From 5c10f8663e5bdb177c519b9632236f10ad06a13b Mon Sep 17 00:00:00 2001 From: tiagohm Date: Mon, 25 Mar 2024 13:40:34 -0300 Subject: [PATCH 01/15] [api]: Implement XISF read/write --- .gitattributes | 3 +- .gitignore | 3 - api/build.gradle.kts | 2 +- .../api/alignment/polar/tppa/TPPAStep.kt | 2 +- .../beans/configurations/BeanConfiguration.kt | 2 +- .../calibration/CalibrationFrameService.kt | 11 +- .../nebulosa/api/framing/FramingService.kt | 2 +- .../kotlin/nebulosa/api/image/ImageBucket.kt | 2 +- .../nebulosa/api/image/ImageController.kt | 4 +- .../kotlin/nebulosa/api/image/ImageInfo.kt | 2 +- .../kotlin/nebulosa/api/image/ImageService.kt | 10 +- .../api/wizard/flat/FlatWizardStep.kt | 4 +- data/.gitignore | 1 + data/fits/.gitignore | 5 - data/fits/NGC3344.Color.16.fits | 375 ------ data/fits/NGC3344.Color.32.fits | 375 ------ data/fits/NGC3344.Color.8.fits | 1 - data/fits/NGC3344.Color.F32.fits | Bin 1054080 -> 0 bytes data/fits/NGC3344.Color.F64.fits | 1 - data/fits/NGC3344.Mono.16.fits | Bin 135360 -> 0 bytes data/fits/NGC3344.Mono.32.fits | 221 ---- data/fits/NGC3344.Mono.8.fits | 12 - data/fits/NGC3344.Mono.F32.fits | Bin 267840 -> 0 bytes data/fits/NGC3344.Mono.F64.fits | 1 - data/fits/STAR_FOCUS_1.fits | Bin 14400 -> 0 bytes data/fits/STAR_FOCUS_10.fits | 1 - data/fits/STAR_FOCUS_11.fits | 1 - data/fits/STAR_FOCUS_12.fits | Bin 14400 -> 0 bytes data/fits/STAR_FOCUS_13.fits | 1 - data/fits/STAR_FOCUS_14.fits | Bin 14400 -> 0 bytes data/fits/STAR_FOCUS_15.fits | 4 - data/fits/STAR_FOCUS_16.fits | 4 - data/fits/STAR_FOCUS_17.fits | Bin 14400 -> 0 bytes data/fits/STAR_FOCUS_2.fits | Bin 14400 -> 0 bytes data/fits/STAR_FOCUS_3.fits | Bin 14400 -> 0 bytes data/fits/STAR_FOCUS_4.fits | 2 - data/fits/STAR_FOCUS_5.fits | 4 - data/fits/STAR_FOCUS_6.fits | Bin 14400 -> 0 bytes data/fits/STAR_FOCUS_7.fits | 3 - data/fits/STAR_FOCUS_8.fits | Bin 14400 -> 0 bytes data/fits/STAR_FOCUS_9.fits | Bin 14400 -> 0 bytes .../point/three/ThreePointPolarAlignment.kt | 2 +- .../alpaca/indi/device/cameras/ASCOMCamera.kt | 62 +- .../astap/plate/solving/AstapPlateSolver.kt | 37 +- .../solving/LibAstrometryNetPlateSolver.kt | 2 +- .../nova/NovaAstrometryNetService.kt | 2 +- .../solving/LocalAstrometryNetPlateSolver.kt | 2 +- .../solving/NovaAstrometryNetPlateSolver.kt | 6 +- nebulosa-fits/build.gradle.kts | 1 + .../src/main/kotlin/nebulosa/fits/Bitpix.kt | 7 +- .../src/main/kotlin/nebulosa/fits/Checksum.kt | 4 +- .../main/kotlin/nebulosa/fits/Compression.kt | 26 +- .../src/main/kotlin/nebulosa/fits/Fits.kt | 12 +- .../main/kotlin/nebulosa/fits/FitsElement.kt | 11 +- .../main/kotlin/nebulosa/fits/FitsHeader.kt | 215 ++- .../kotlin/nebulosa/fits/FitsHeaderCard.kt | 242 ++++ ...ormatter.kt => FitsHeaderCardFormatter.kt} | 38 +- ...rCardParser.kt => FitsHeaderCardParser.kt} | 90 +- .../nebulosa/fits/FitsHeaderCardType.kt | 16 + .../main/kotlin/nebulosa/fits/FitsHelper.kt | 85 +- .../src/main/kotlin/nebulosa/fits/FitsIO.kt | 2 +- .../main/kotlin/nebulosa/fits/FitsKeyword.kt | 15 + .../{NOAOExt.kt => FitsKeywordDictionary.kt} | 1162 ++++++++++++++++- .../{FitsHeaderImpl.kt => FitsKeywordItem.kt} | 8 +- .../src/main/kotlin/nebulosa/fits/FitsPath.kt | 2 +- .../src/main/kotlin/nebulosa/fits/Hdu.kt | 3 +- .../src/main/kotlin/nebulosa/fits/Header.kt | 199 --- .../main/kotlin/nebulosa/fits/HeaderCard.kt | 242 ---- .../src/main/kotlin/nebulosa/fits/ImageHdu.kt | 8 +- .../main/kotlin/nebulosa/fits/MaxImDLExt.kt | 242 ---- .../main/kotlin/nebulosa/fits/NonStandard.kt | 46 - .../kotlin/nebulosa/fits/ReadOnlyHeader.kt | 31 - .../main/kotlin/nebulosa/fits/SBFitsExt.kt | 195 --- .../src/main/kotlin/nebulosa/fits/Standard.kt | 770 ----------- .../kotlin/nebulosa/fits/WritableHeader.kt | 26 - nebulosa-fits/src/test/kotlin/FitsReadTest.kt | 20 +- .../src/test/kotlin/FitsWriteTest.kt | 2 +- nebulosa-guiding-internal/build.gradle.kts | 2 +- .../guiding/internal/GuiderListener.kt | 2 +- .../guiding/internal/InternalGuider.kt | 2 +- .../guiding/internal/MultiStarGuider.kt | 4 +- .../kotlin/nebulosa/guiding/internal/Star.kt | 4 +- nebulosa-hips2fits/build.gradle.kts | 2 +- nebulosa-image-format/build.gradle.kts | 18 + .../nebulosa/image/format/AbstractHeader.kt | 39 + .../main/kotlin/nebulosa/image/format/Hdu.kt | 8 + .../kotlin/nebulosa/image/format/Header.kt | 44 + .../nebulosa/image/format/HeaderCard.kt | 28 + .../kotlin/nebulosa/image/format/HeaderKey.kt | 8 + .../nebulosa/image/format/HeaderValue.kt | 10 + .../nebulosa/image/format/ImageChannel.kt | 8 + .../kotlin/nebulosa/image/format/ImageData.kt | 16 + .../nebulosa/image/format/ImageFormat.kt | 11 + .../kotlin/nebulosa/image/format/ImageHdu.kt | 13 + .../kotlin/nebulosa/image/format/ImageSink.kt | 8 + .../nebulosa/image/format/ImageSource.kt | 8 + .../nebulosa/image/format}/ReadableHeader.kt | 108 +- .../nebulosa/image/format/WritableHeader.kt | 26 + .../build.gradle.kts | 0 .../nebulosa/image}/Float8bitsDataBuffer.kt | 2 +- .../src/main/kotlin/nebulosa/image}/Image.kt | 47 +- .../kotlin/nebulosa/image}/ImageChannel.kt | 2 +- .../image}/algorithms/AlgorithmHelper.kt | 4 +- .../image}/algorithms/ComputationAlgorithm.kt | 4 +- .../image}/algorithms/TransformAlgorithm.kt | 4 +- .../algorithms/computation/Histogram.kt | 10 +- .../image}/algorithms/computation/Median.kt | 10 +- .../computation/MedianAbsoluteDeviation.kt | 10 +- .../algorithms/computation/Statistics.kt | 10 +- .../algorithms/computation/fwhm/FWHM.kt | 6 +- .../image}/algorithms/computation/hfd/HFD.kt | 6 +- .../image}/algorithms/computation/hfd/HFR.kt | 2 +- .../AutoScreenTransformFunction.kt | 12 +- .../algorithms/transformation/Binarize.kt | 6 +- .../algorithms/transformation/CfaPattern.kt | 8 +- .../algorithms/transformation/Debayer.kt | 6 +- .../image}/algorithms/transformation/Draw.kt | 6 +- .../algorithms/transformation/Grayscale.kt | 13 +- .../transformation/HorizontalFlip.kt | 6 +- .../algorithms/transformation/Invert.kt | 6 +- .../transformation/ProtectionMethod.kt | 2 +- .../transformation/SaltAndPepperNoise.kt | 6 +- .../transformation/ScreenTransformFunction.kt | 6 +- .../algorithms/transformation/SigmaClip.kt | 12 +- .../algorithms/transformation/SubFrame.kt | 13 +- .../SubtractiveChromaticNoiseReduction.kt | 8 +- .../algorithms/transformation/VerticalFlip.kt | 6 +- .../transformation/convolution/Blur.kt | 2 +- .../transformation/convolution/Convolution.kt | 6 +- .../convolution/ConvolutionKernel.kt | 2 +- .../transformation/convolution/Edges.kt | 2 +- .../transformation/convolution/Emboss.kt | 2 +- .../convolution/GaussianBlur.kt | 2 +- .../convolution/MatrixConvolutionKernel.kt | 2 +- .../transformation/convolution/Mean.kt | 2 +- .../transformation/convolution/Sharpen.kt | 2 +- .../correction/BiasSubtraction.kt | 8 +- .../correction/DarkSubtraction.kt | 8 +- .../correction/FlatCorrection.kt | 10 +- .../test/kotlin/ComputationAlgorithmTest.kt | 16 +- .../src/test/kotlin/HFDTest.kt | 4 +- .../src/test/kotlin/TransformAlgorithmTest.kt | 108 +- .../src/test/resources/Debayer.fits | Bin 138240 -> 0 bytes nebulosa-indi-client/build.gradle.kts | 2 +- .../indi/client/device/cameras/INDICamera.kt | 2 +- nebulosa-indi-device/build.gradle.kts | 2 +- .../nebulosa/indi/device/camera/Camera.kt | 2 +- nebulosa-indi-protocol/build.gradle.kts | 2 +- .../protocol/parser/INDIXmlInputStream.kt | 17 +- nebulosa-math/src/test/kotlin/Vector3DTest.kt | 2 +- nebulosa-plate-solving/build.gradle.kts | 2 +- .../nebulosa/plate/solving/PlateSolution.kt | 26 +- .../nebulosa/plate/solving/PlateSolver.kt | 2 +- .../src/test/kotlin/PlateSolutionTest.kt | 4 +- .../SmallBodyCloseApprochServiceTest.kt | 2 +- nebulosa-test/build.gradle.kts | 1 + .../kotlin/nebulosa/test/FitsStringSpec.kt | 182 ++- .../test/{ => matchers}/MathMatchers.kt | 6 +- nebulosa-watney/build.gradle.kts | 2 +- .../plate/solving/ComputedPlateSolution.kt | 5 +- .../watney/plate/solving/WatneyPlateSolver.kt | 33 +- .../detection/DefaultStarDetectionFilter.kt | 2 +- .../star/detection/StarDetectionFilter.kt | 2 +- .../star/detection/WatneyStarDetector.kt | 6 +- .../src/test/kotlin/WatnetPlateSolverTest.kt | 2 +- .../src/test/kotlin/WatneyStarDetectorTest.kt | 8 +- .../src/main/kotlin/nebulosa/wcs/WCS.kt | 6 +- .../src/main/kotlin/nebulosa/wcs/WCSUtil.kt | 20 +- nebulosa-wcs/src/test/kotlin/LibWCSTest.kt | 4 +- nebulosa-xisf/build.gradle.kts | 20 + .../nebulosa/xisf/CompressionByteShuffler.kt | 56 + .../main/kotlin/nebulosa/xisf/XisfFormat.kt | 49 + .../main/kotlin/nebulosa/xisf/XisfHeader.kt | 46 + .../nebulosa/xisf/XisfHeaderInputStream.kt | 103 ++ .../main/kotlin/nebulosa/xisf/XisfHelper.kt | 12 + .../nebulosa/xisf/XisfMonolithicFileHeader.kt | 74 ++ .../xisf/XisfMonolithicFileHeaderImageData.kt | 173 +++ .../xisf/XisfMonolithicFileHeaderImageHdu.kt | 23 + .../src/main/kotlin/nebulosa/xisf/XisfPath.kt | 25 + .../kotlin/CompressionByteShufflerTest.kt | 30 + .../src/test/kotlin/XisfFormatTest.kt | 255 ++++ .../test/kotlin/XisfHeaderInputStreamTest.kt | 230 ++++ nebulosa-xml/build.gradle.kts | 17 + .../src/main/kotlin/nebulosa/xml/XmlHelper.kt | 13 + settings.gradle.kts | 5 +- 185 files changed, 3694 insertions(+), 3451 deletions(-) delete mode 100644 data/fits/.gitignore delete mode 100644 data/fits/NGC3344.Color.16.fits delete mode 100644 data/fits/NGC3344.Color.32.fits delete mode 100644 data/fits/NGC3344.Color.8.fits delete mode 100644 data/fits/NGC3344.Color.F32.fits delete mode 100644 data/fits/NGC3344.Color.F64.fits delete mode 100644 data/fits/NGC3344.Mono.16.fits delete mode 100644 data/fits/NGC3344.Mono.32.fits delete mode 100644 data/fits/NGC3344.Mono.8.fits delete mode 100644 data/fits/NGC3344.Mono.F32.fits delete mode 100644 data/fits/NGC3344.Mono.F64.fits delete mode 100644 data/fits/STAR_FOCUS_1.fits delete mode 100644 data/fits/STAR_FOCUS_10.fits delete mode 100644 data/fits/STAR_FOCUS_11.fits delete mode 100644 data/fits/STAR_FOCUS_12.fits delete mode 100644 data/fits/STAR_FOCUS_13.fits delete mode 100644 data/fits/STAR_FOCUS_14.fits delete mode 100644 data/fits/STAR_FOCUS_15.fits delete mode 100644 data/fits/STAR_FOCUS_16.fits delete mode 100644 data/fits/STAR_FOCUS_17.fits delete mode 100644 data/fits/STAR_FOCUS_2.fits delete mode 100644 data/fits/STAR_FOCUS_3.fits delete mode 100644 data/fits/STAR_FOCUS_4.fits delete mode 100644 data/fits/STAR_FOCUS_5.fits delete mode 100644 data/fits/STAR_FOCUS_6.fits delete mode 100644 data/fits/STAR_FOCUS_7.fits delete mode 100644 data/fits/STAR_FOCUS_8.fits delete mode 100644 data/fits/STAR_FOCUS_9.fits create mode 100644 nebulosa-fits/src/main/kotlin/nebulosa/fits/FitsHeaderCard.kt rename nebulosa-fits/src/main/kotlin/nebulosa/fits/{HeaderCardFormatter.kt => FitsHeaderCardFormatter.kt} (86%) rename nebulosa-fits/src/main/kotlin/nebulosa/fits/{HeaderCardParser.kt => FitsHeaderCardParser.kt} (75%) create mode 100644 nebulosa-fits/src/main/kotlin/nebulosa/fits/FitsHeaderCardType.kt create mode 100644 nebulosa-fits/src/main/kotlin/nebulosa/fits/FitsKeyword.kt rename nebulosa-fits/src/main/kotlin/nebulosa/fits/{NOAOExt.kt => FitsKeywordDictionary.kt} (65%) rename nebulosa-fits/src/main/kotlin/nebulosa/fits/{FitsHeaderImpl.kt => FitsKeywordItem.kt} (70%) delete mode 100644 nebulosa-fits/src/main/kotlin/nebulosa/fits/Header.kt delete mode 100644 nebulosa-fits/src/main/kotlin/nebulosa/fits/HeaderCard.kt delete mode 100644 nebulosa-fits/src/main/kotlin/nebulosa/fits/MaxImDLExt.kt delete mode 100644 nebulosa-fits/src/main/kotlin/nebulosa/fits/NonStandard.kt delete mode 100644 nebulosa-fits/src/main/kotlin/nebulosa/fits/ReadOnlyHeader.kt delete mode 100644 nebulosa-fits/src/main/kotlin/nebulosa/fits/SBFitsExt.kt delete mode 100644 nebulosa-fits/src/main/kotlin/nebulosa/fits/Standard.kt delete mode 100644 nebulosa-fits/src/main/kotlin/nebulosa/fits/WritableHeader.kt create mode 100644 nebulosa-image-format/build.gradle.kts create mode 100644 nebulosa-image-format/src/main/kotlin/nebulosa/image/format/AbstractHeader.kt create mode 100644 nebulosa-image-format/src/main/kotlin/nebulosa/image/format/Hdu.kt create mode 100644 nebulosa-image-format/src/main/kotlin/nebulosa/image/format/Header.kt create mode 100644 nebulosa-image-format/src/main/kotlin/nebulosa/image/format/HeaderCard.kt create mode 100644 nebulosa-image-format/src/main/kotlin/nebulosa/image/format/HeaderKey.kt create mode 100644 nebulosa-image-format/src/main/kotlin/nebulosa/image/format/HeaderValue.kt create mode 100644 nebulosa-image-format/src/main/kotlin/nebulosa/image/format/ImageChannel.kt create mode 100644 nebulosa-image-format/src/main/kotlin/nebulosa/image/format/ImageData.kt create mode 100644 nebulosa-image-format/src/main/kotlin/nebulosa/image/format/ImageFormat.kt create mode 100644 nebulosa-image-format/src/main/kotlin/nebulosa/image/format/ImageHdu.kt create mode 100644 nebulosa-image-format/src/main/kotlin/nebulosa/image/format/ImageSink.kt create mode 100644 nebulosa-image-format/src/main/kotlin/nebulosa/image/format/ImageSource.kt rename {nebulosa-fits/src/main/kotlin/nebulosa/fits => nebulosa-image-format/src/main/kotlin/nebulosa/image/format}/ReadableHeader.kt (56%) create mode 100644 nebulosa-image-format/src/main/kotlin/nebulosa/image/format/WritableHeader.kt rename {nebulosa-imaging => nebulosa-image}/build.gradle.kts (100%) rename {nebulosa-imaging/src/main/kotlin/nebulosa/imaging => nebulosa-image/src/main/kotlin/nebulosa/image}/Float8bitsDataBuffer.kt (98%) rename {nebulosa-imaging/src/main/kotlin/nebulosa/imaging => nebulosa-image/src/main/kotlin/nebulosa/image}/Image.kt (90%) rename {nebulosa-imaging/src/main/kotlin/nebulosa/imaging => nebulosa-image/src/main/kotlin/nebulosa/image}/ImageChannel.kt (88%) rename {nebulosa-imaging/src/main/kotlin/nebulosa/imaging => nebulosa-image/src/main/kotlin/nebulosa/image}/algorithms/AlgorithmHelper.kt (87%) rename {nebulosa-imaging/src/main/kotlin/nebulosa/imaging => nebulosa-image/src/main/kotlin/nebulosa/image}/algorithms/ComputationAlgorithm.kt (55%) rename {nebulosa-imaging/src/main/kotlin/nebulosa/imaging => nebulosa-image/src/main/kotlin/nebulosa/image}/algorithms/TransformAlgorithm.kt (84%) rename {nebulosa-imaging/src/main/kotlin/nebulosa/imaging => nebulosa-image/src/main/kotlin/nebulosa/image}/algorithms/computation/Histogram.kt (73%) rename {nebulosa-imaging/src/main/kotlin/nebulosa/imaging => nebulosa-image/src/main/kotlin/nebulosa/image}/algorithms/computation/Median.kt (85%) rename {nebulosa-imaging/src/main/kotlin/nebulosa/imaging => nebulosa-image/src/main/kotlin/nebulosa/image}/algorithms/computation/MedianAbsoluteDeviation.kt (82%) rename {nebulosa-imaging/src/main/kotlin/nebulosa/imaging => nebulosa-image/src/main/kotlin/nebulosa/image}/algorithms/computation/Statistics.kt (93%) rename {nebulosa-imaging/src/main/kotlin/nebulosa/imaging => nebulosa-image/src/main/kotlin/nebulosa/image}/algorithms/computation/fwhm/FWHM.kt (93%) rename {nebulosa-imaging/src/main/kotlin/nebulosa/imaging => nebulosa-image/src/main/kotlin/nebulosa/image}/algorithms/computation/hfd/HFD.kt (98%) rename {nebulosa-imaging/src/main/kotlin/nebulosa/imaging => nebulosa-image/src/main/kotlin/nebulosa/image}/algorithms/computation/hfd/HFR.kt (95%) rename {nebulosa-imaging/src/main/kotlin/nebulosa/imaging => nebulosa-image/src/main/kotlin/nebulosa/image}/algorithms/transformation/AutoScreenTransformFunction.kt (82%) rename {nebulosa-imaging/src/main/kotlin/nebulosa/imaging => nebulosa-image/src/main/kotlin/nebulosa/image}/algorithms/transformation/Binarize.kt (70%) rename {nebulosa-imaging/src/main/kotlin/nebulosa/imaging => nebulosa-image/src/main/kotlin/nebulosa/image}/algorithms/transformation/CfaPattern.kt (86%) rename {nebulosa-imaging/src/main/kotlin/nebulosa/imaging => nebulosa-image/src/main/kotlin/nebulosa/image}/algorithms/transformation/Debayer.kt (96%) rename {nebulosa-imaging/src/main/kotlin/nebulosa/imaging => nebulosa-image/src/main/kotlin/nebulosa/image}/algorithms/transformation/Draw.kt (77%) rename {nebulosa-imaging/src/main/kotlin/nebulosa/imaging => nebulosa-image/src/main/kotlin/nebulosa/image}/algorithms/transformation/Grayscale.kt (78%) rename {nebulosa-imaging/src/main/kotlin/nebulosa/imaging => nebulosa-image/src/main/kotlin/nebulosa/image}/algorithms/transformation/HorizontalFlip.kt (82%) rename {nebulosa-imaging/src/main/kotlin/nebulosa/imaging => nebulosa-image/src/main/kotlin/nebulosa/image}/algorithms/transformation/Invert.kt (73%) rename {nebulosa-imaging/src/main/kotlin/nebulosa/imaging => nebulosa-image/src/main/kotlin/nebulosa/image}/algorithms/transformation/ProtectionMethod.kt (95%) rename {nebulosa-imaging/src/main/kotlin/nebulosa/imaging => nebulosa-image/src/main/kotlin/nebulosa/image}/algorithms/transformation/SaltAndPepperNoise.kt (85%) rename {nebulosa-imaging/src/main/kotlin/nebulosa/imaging => nebulosa-image/src/main/kotlin/nebulosa/image}/algorithms/transformation/ScreenTransformFunction.kt (93%) rename {nebulosa-imaging/src/main/kotlin/nebulosa/imaging => nebulosa-image/src/main/kotlin/nebulosa/image}/algorithms/transformation/SigmaClip.kt (89%) rename {nebulosa-imaging/src/main/kotlin/nebulosa/imaging => nebulosa-image/src/main/kotlin/nebulosa/image}/algorithms/transformation/SubFrame.kt (83%) rename {nebulosa-imaging/src/main/kotlin/nebulosa/imaging => nebulosa-image/src/main/kotlin/nebulosa/image}/algorithms/transformation/SubtractiveChromaticNoiseReduction.kt (89%) rename {nebulosa-imaging/src/main/kotlin/nebulosa/imaging => nebulosa-image/src/main/kotlin/nebulosa/image}/algorithms/transformation/VerticalFlip.kt (82%) rename {nebulosa-imaging/src/main/kotlin/nebulosa/imaging => nebulosa-image/src/main/kotlin/nebulosa/image}/algorithms/transformation/convolution/Blur.kt (75%) rename {nebulosa-imaging/src/main/kotlin/nebulosa/imaging => nebulosa-image/src/main/kotlin/nebulosa/image}/algorithms/transformation/convolution/Convolution.kt (95%) rename {nebulosa-imaging/src/main/kotlin/nebulosa/imaging => nebulosa-image/src/main/kotlin/nebulosa/image}/algorithms/transformation/convolution/ConvolutionKernel.kt (69%) rename {nebulosa-imaging/src/main/kotlin/nebulosa/imaging => nebulosa-image/src/main/kotlin/nebulosa/image}/algorithms/transformation/convolution/Edges.kt (66%) rename {nebulosa-imaging/src/main/kotlin/nebulosa/imaging => nebulosa-image/src/main/kotlin/nebulosa/image}/algorithms/transformation/convolution/Emboss.kt (65%) rename {nebulosa-imaging/src/main/kotlin/nebulosa/imaging => nebulosa-image/src/main/kotlin/nebulosa/image}/algorithms/transformation/convolution/GaussianBlur.kt (94%) rename {nebulosa-imaging/src/main/kotlin/nebulosa/imaging => nebulosa-image/src/main/kotlin/nebulosa/image}/algorithms/transformation/convolution/MatrixConvolutionKernel.kt (84%) rename {nebulosa-imaging/src/main/kotlin/nebulosa/imaging => nebulosa-image/src/main/kotlin/nebulosa/image}/algorithms/transformation/convolution/Mean.kt (65%) rename {nebulosa-imaging/src/main/kotlin/nebulosa/imaging => nebulosa-image/src/main/kotlin/nebulosa/image}/algorithms/transformation/convolution/Sharpen.kt (66%) rename {nebulosa-imaging/src/main/kotlin/nebulosa/imaging => nebulosa-image/src/main/kotlin/nebulosa/image}/algorithms/transformation/correction/BiasSubtraction.kt (80%) rename {nebulosa-imaging/src/main/kotlin/nebulosa/imaging => nebulosa-image/src/main/kotlin/nebulosa/image}/algorithms/transformation/correction/DarkSubtraction.kt (80%) rename {nebulosa-imaging/src/main/kotlin/nebulosa/imaging => nebulosa-image/src/main/kotlin/nebulosa/image}/algorithms/transformation/correction/FlatCorrection.kt (78%) rename {nebulosa-imaging => nebulosa-image}/src/test/kotlin/ComputationAlgorithmTest.kt (90%) rename {nebulosa-imaging => nebulosa-image}/src/test/kotlin/HFDTest.kt (95%) rename {nebulosa-imaging => nebulosa-image}/src/test/kotlin/TransformAlgorithmTest.kt (79%) delete mode 100644 nebulosa-imaging/src/test/resources/Debayer.fits rename nebulosa-test/src/main/kotlin/nebulosa/test/{ => matchers}/MathMatchers.kt (98%) create mode 100644 nebulosa-xisf/build.gradle.kts create mode 100644 nebulosa-xisf/src/main/kotlin/nebulosa/xisf/CompressionByteShuffler.kt create mode 100644 nebulosa-xisf/src/main/kotlin/nebulosa/xisf/XisfFormat.kt create mode 100644 nebulosa-xisf/src/main/kotlin/nebulosa/xisf/XisfHeader.kt create mode 100644 nebulosa-xisf/src/main/kotlin/nebulosa/xisf/XisfHeaderInputStream.kt create mode 100644 nebulosa-xisf/src/main/kotlin/nebulosa/xisf/XisfHelper.kt create mode 100644 nebulosa-xisf/src/main/kotlin/nebulosa/xisf/XisfMonolithicFileHeader.kt create mode 100644 nebulosa-xisf/src/main/kotlin/nebulosa/xisf/XisfMonolithicFileHeaderImageData.kt create mode 100644 nebulosa-xisf/src/main/kotlin/nebulosa/xisf/XisfMonolithicFileHeaderImageHdu.kt create mode 100644 nebulosa-xisf/src/main/kotlin/nebulosa/xisf/XisfPath.kt create mode 100644 nebulosa-xisf/src/test/kotlin/CompressionByteShufflerTest.kt create mode 100644 nebulosa-xisf/src/test/kotlin/XisfFormatTest.kt create mode 100644 nebulosa-xisf/src/test/kotlin/XisfHeaderInputStreamTest.kt create mode 100644 nebulosa-xml/build.gradle.kts create mode 100644 nebulosa-xml/src/main/kotlin/nebulosa/xml/XmlHelper.kt diff --git a/.gitattributes b/.gitattributes index 2451a3c40..709fc3af8 100644 --- a/.gitattributes +++ b/.gitattributes @@ -12,6 +12,7 @@ *.jar binary *.fit binary *.fits binary +*.xisf binary *.ttf binary *.xcf binary *.png binary @@ -19,4 +20,4 @@ *.gz binary *.dll binary *.so binary -*.zip binary \ No newline at end of file +*.zip binary diff --git a/.gitignore b/.gitignore index 479db9a3a..4a81c1a94 100644 --- a/.gitignore +++ b/.gitignore @@ -191,6 +191,3 @@ libobjectbox*.dylib .kotlin # End of https://www.toptal.com/developers/gitignore/api/intellij,kotlin,java,gradle - -**/saved/*.png -**/saved/*.jpg diff --git a/api/build.gradle.kts b/api/build.gradle.kts index b6a6881ed..9fe08451f 100644 --- a/api/build.gradle.kts +++ b/api/build.gradle.kts @@ -19,7 +19,7 @@ dependencies { implementation(project(":nebulosa-guiding-phd2")) implementation(project(":nebulosa-hips2fits")) implementation(project(":nebulosa-horizons")) - implementation(project(":nebulosa-imaging")) + implementation(project(":nebulosa-image")) implementation(project(":nebulosa-indi-client")) implementation(project(":nebulosa-log")) implementation(project(":nebulosa-lx200-protocol")) diff --git a/api/src/main/kotlin/nebulosa/api/alignment/polar/tppa/TPPAStep.kt b/api/src/main/kotlin/nebulosa/api/alignment/polar/tppa/TPPAStep.kt index 02dd5ead7..b2d43157c 100644 --- a/api/src/main/kotlin/nebulosa/api/alignment/polar/tppa/TPPAStep.kt +++ b/api/src/main/kotlin/nebulosa/api/alignment/polar/tppa/TPPAStep.kt @@ -13,7 +13,7 @@ import nebulosa.batch.processing.StepResult import nebulosa.common.concurrency.latch.Pauseable import nebulosa.common.time.Stopwatch import nebulosa.fits.fits -import nebulosa.imaging.Image +import nebulosa.image.Image import nebulosa.indi.device.camera.Camera import nebulosa.indi.device.mount.Mount import nebulosa.log.debug diff --git a/api/src/main/kotlin/nebulosa/api/beans/configurations/BeanConfiguration.kt b/api/src/main/kotlin/nebulosa/api/beans/configurations/BeanConfiguration.kt index f04275e1d..ff01cda52 100644 --- a/api/src/main/kotlin/nebulosa/api/beans/configurations/BeanConfiguration.kt +++ b/api/src/main/kotlin/nebulosa/api/beans/configurations/BeanConfiguration.kt @@ -18,7 +18,7 @@ import nebulosa.guiding.Guider import nebulosa.guiding.phd2.PHD2Guider import nebulosa.hips2fits.Hips2FitsService import nebulosa.horizons.HorizonsService -import nebulosa.imaging.Image +import nebulosa.image.Image import nebulosa.log.loggerFor import nebulosa.phd2.client.PHD2Client import nebulosa.sbd.SmallBodyDatabaseService diff --git a/api/src/main/kotlin/nebulosa/api/calibration/CalibrationFrameService.kt b/api/src/main/kotlin/nebulosa/api/calibration/CalibrationFrameService.kt index a217cac8e..43e45e5ac 100644 --- a/api/src/main/kotlin/nebulosa/api/calibration/CalibrationFrameService.kt +++ b/api/src/main/kotlin/nebulosa/api/calibration/CalibrationFrameService.kt @@ -1,10 +1,11 @@ package nebulosa.api.calibration import nebulosa.fits.* -import nebulosa.imaging.Image -import nebulosa.imaging.algorithms.transformation.correction.BiasSubtraction -import nebulosa.imaging.algorithms.transformation.correction.DarkSubtraction -import nebulosa.imaging.algorithms.transformation.correction.FlatCorrection +import nebulosa.image.Image +import nebulosa.image.algorithms.transformation.correction.BiasSubtraction +import nebulosa.image.algorithms.transformation.correction.DarkSubtraction +import nebulosa.image.algorithms.transformation.correction.FlatCorrection +import nebulosa.image.format.Header import nebulosa.indi.device.camera.FrameType import nebulosa.log.loggerFor import org.springframework.stereotype.Service @@ -31,7 +32,7 @@ class CalibrationFrameService( return if (darkFrame != null || biasFrame != null || flatFrame != null) { var transformedImage = if (createNew) image.clone() else image - var calibrationImage = Image(transformedImage.width, transformedImage.height, Header.EMPTY, transformedImage.mono) + var calibrationImage = Image(transformedImage.width, transformedImage.height, Header.Empty, transformedImage.mono) if (biasFrame != null) { calibrationImage = biasFrame.path!!.fits().use(calibrationImage::load)!! diff --git a/api/src/main/kotlin/nebulosa/api/framing/FramingService.kt b/api/src/main/kotlin/nebulosa/api/framing/FramingService.kt index 3c78ca249..6a31eb37a 100644 --- a/api/src/main/kotlin/nebulosa/api/framing/FramingService.kt +++ b/api/src/main/kotlin/nebulosa/api/framing/FramingService.kt @@ -3,7 +3,7 @@ package nebulosa.api.framing import nebulosa.fits.fits import nebulosa.hips2fits.FormatOutputType import nebulosa.hips2fits.Hips2FitsService -import nebulosa.imaging.Image +import nebulosa.image.Image import nebulosa.io.transferAndCloseOutput import nebulosa.log.loggerFor import nebulosa.math.Angle diff --git a/api/src/main/kotlin/nebulosa/api/image/ImageBucket.kt b/api/src/main/kotlin/nebulosa/api/image/ImageBucket.kt index cc73e3e7f..eed799ebd 100644 --- a/api/src/main/kotlin/nebulosa/api/image/ImageBucket.kt +++ b/api/src/main/kotlin/nebulosa/api/image/ImageBucket.kt @@ -1,7 +1,7 @@ package nebulosa.api.image import nebulosa.fits.fits -import nebulosa.imaging.Image +import nebulosa.image.Image import nebulosa.plate.solving.PlateSolution import org.springframework.stereotype.Component import java.nio.file.Path diff --git a/api/src/main/kotlin/nebulosa/api/image/ImageController.kt b/api/src/main/kotlin/nebulosa/api/image/ImageController.kt index 49e12d6e0..a8d99bfa9 100644 --- a/api/src/main/kotlin/nebulosa/api/image/ImageController.kt +++ b/api/src/main/kotlin/nebulosa/api/image/ImageController.kt @@ -5,8 +5,8 @@ import jakarta.validation.Valid import nebulosa.api.atlas.Location import nebulosa.api.beans.converters.device.DeviceOrEntityParam import nebulosa.api.beans.converters.location.LocationParam -import nebulosa.imaging.ImageChannel -import nebulosa.imaging.algorithms.transformation.ProtectionMethod +import nebulosa.image.ImageChannel +import nebulosa.image.algorithms.transformation.ProtectionMethod import nebulosa.indi.device.camera.Camera import nebulosa.star.detection.ImageStar import org.hibernate.validator.constraints.Range diff --git a/api/src/main/kotlin/nebulosa/api/image/ImageInfo.kt b/api/src/main/kotlin/nebulosa/api/image/ImageInfo.kt index 83a6aa217..25d2d8807 100644 --- a/api/src/main/kotlin/nebulosa/api/image/ImageInfo.kt +++ b/api/src/main/kotlin/nebulosa/api/image/ImageInfo.kt @@ -4,7 +4,7 @@ import com.fasterxml.jackson.annotation.JsonIgnoreProperties import com.fasterxml.jackson.databind.annotation.JsonSerialize import nebulosa.api.beans.converters.angle.DeclinationSerializer import nebulosa.api.beans.converters.angle.RightAscensionSerializer -import nebulosa.imaging.algorithms.computation.Statistics +import nebulosa.image.algorithms.computation.Statistics import nebulosa.indi.device.camera.Camera import java.nio.file.Path diff --git a/api/src/main/kotlin/nebulosa/api/image/ImageService.kt b/api/src/main/kotlin/nebulosa/api/image/ImageService.kt index 0e65de7c4..245b7cddc 100644 --- a/api/src/main/kotlin/nebulosa/api/image/ImageService.kt +++ b/api/src/main/kotlin/nebulosa/api/image/ImageService.kt @@ -8,11 +8,11 @@ import nebulosa.api.calibration.CalibrationFrameService import nebulosa.api.connection.ConnectionService import nebulosa.api.framing.FramingService import nebulosa.fits.* -import nebulosa.imaging.Image -import nebulosa.imaging.ImageChannel -import nebulosa.imaging.algorithms.computation.Histogram -import nebulosa.imaging.algorithms.computation.Statistics -import nebulosa.imaging.algorithms.transformation.* +import nebulosa.image.Image +import nebulosa.image.ImageChannel +import nebulosa.image.algorithms.computation.Histogram +import nebulosa.image.algorithms.computation.Statistics +import nebulosa.image.algorithms.transformation.* import nebulosa.indi.device.camera.Camera import nebulosa.io.transferAndClose import nebulosa.log.debug diff --git a/api/src/main/kotlin/nebulosa/api/wizard/flat/FlatWizardStep.kt b/api/src/main/kotlin/nebulosa/api/wizard/flat/FlatWizardStep.kt index c57d04d34..4afa5f8b3 100644 --- a/api/src/main/kotlin/nebulosa/api/wizard/flat/FlatWizardStep.kt +++ b/api/src/main/kotlin/nebulosa/api/wizard/flat/FlatWizardStep.kt @@ -8,8 +8,8 @@ import nebulosa.batch.processing.Step import nebulosa.batch.processing.StepExecution import nebulosa.batch.processing.StepResult import nebulosa.fits.fits -import nebulosa.imaging.Image -import nebulosa.imaging.algorithms.computation.Statistics +import nebulosa.image.Image +import nebulosa.image.algorithms.computation.Statistics import nebulosa.indi.device.camera.Camera import nebulosa.io.transferAndClose import org.slf4j.LoggerFactory diff --git a/data/.gitignore b/data/.gitignore index f58680a40..6642278fe 100644 --- a/data/.gitignore +++ b/data/.gitignore @@ -1,2 +1,3 @@ simbad/ astrobin/ +test/ diff --git a/data/fits/.gitignore b/data/fits/.gitignore deleted file mode 100644 index 525457074..000000000 --- a/data/fits/.gitignore +++ /dev/null @@ -1,5 +0,0 @@ -!*.zip -BIAS.fits -DARK.fits -FLAT.fits -UNCALIBRATED.fits diff --git a/data/fits/NGC3344.Color.16.fits b/data/fits/NGC3344.Color.16.fits deleted file mode 100644 index 77f456842..000000000 --- a/data/fits/NGC3344.Color.16.fits +++ /dev/null @@ -1,375 +0,0 @@ -SIMPLE = T / file does conform to FITS standard BITPIX = 16 / number of bits per data pixel NAXIS = 3 / number of data axes NAXIS1 = 256 / length of data axis 1 NAXIS2 = 256 / length of data axis 2 NAXIS3 = 4 / length of data axis 3 EXTEND = T / FITS dataset may contain extensions COMMENT FITS (Flexible Image Transport System) format is defined in 'AstronomyCOMMENT and Astrophysics', volume 376, page 359; bibcode: 2001A&A...376..359H BZERO = 32768 / offset data range to that of unsigned short BSCALE = 1 / default scaling factor PROGRAM = 'PixInsight 1.8.9-2' / Software that created this HDU COMMENT PixInsight Class Library: PCL 2.6.1 COMMENT FITS module version 1.2.0 ROWORDER= 'TOP-DOWN' / Order of pixel rows stored in the image array END (! !!#%*...!! ! !#!(& !!# & #)%$"(##!$(-'6,-&)42,*.0/,-L_3.355]}[HYZL>P-:^9'.,1-1-4.5/60)EK140315800,1133...36:4238:>;8>999737?C<=;9a6<>9794?6<3:>8:2D500.67ASC9?FCB=7;=7537244836>.6=7471*0)'(0,!')$#!%    /"!&# #!!' "%+ 5$$,!) %)!"(& )&%*0*21.#+A+)&(,&.6,)8247T%ZMnHG500%/23/0162./0-*.1.01/*454339;6558688<65A43654374/:3044.1?>1:=C:5D5HMG8>;9;C<6C72@1+*15&*((,%#&'*%#! ""'%"!")&!#!""$% $!&'", "''&((5(+/*.Q*35%$)/+.,6AR@<:65+BD<1.+-///0+-.0-.,*,.+-2.[E/-.5.32,50/472*441:@97899A?:9<=?B;4::88:@<4://1:4306463<41.;602-?;6DB>4=>7?@48G8463-*--21),-&/'%(#)+' (% #&41 %$%"&'"!7.)'$" !!$'!$0+),)&,0.2*0)*+<7(,4%'+-107LO516?;-=1../116+/-.(**')**-/56120/1++0&-0543224@?7267789775:98?<:;;D@@<>48468664594678:<735=E?4467224;RLEFKL<8V89-4./-/,+A')(-$./()&""!")'%88 !#%0! !1$$#$+%1#!"  )6&+-#(&(.)0?2:9L20B/1'+(21+0-7E;67=:IQ,.*+-)+,**,.,/+)+.590/004100./,44.8,26422FE;8;6>@9<:979=@7?DCOIF6AC8<069?0,.-2&)+/'$1*+0!!#'$!# 1(+)%.)"#/) !'("%(!&$#&"($'9/ -()**+6:GeoB;C0)$&08.1/1+:7226319<3020,,0--*-0141+6201.>W4--/..,31,..2489P9;=69:?<@84469?A;9<>\AY??AAKA>9=?9?2BQBRI?cA:?@99<FA59=?XQ^kfHXIFM``aZocVSLZDDG<0/.42+4/())$#$&+)%) ! " +"9%.;C" ,'!# !&1!#-#;),:,*L'+&,*$);'*.2Ba W4V3/+(**,-.-2/05.*))38A;:R030.*)//%'-+-.*.348S,0...+(/0,.365114266;7:;:8:LBD>E?:8<=B@EAJ?H@;;>A9:BHB<[zNLNhC6;B;DM@HP[`uv[bEUS;C?HM2375./2%'(%#)36'!!("!! $#" %.'>) $)%#'" '*!!%((BA$)(41*(&%$+9(0C+<0.P sz=3-1.-+)/.3.+:1-380025C?q11.+*,/;/++,C/,+*-78/+(+,3*,-/0036453504356?;>8]=?==?8>DJ@6=CPHU<<@Q:A=XcJKACB?84>RNVUW*ie]EHO<::5286C01-1(+,***'$%%%(!*!(!G"!#"(Q4K%%!'" !# %,)-3'-$#)).4&,)-(+&&85/1,=325<3OaS44(+-+.G)-2+1-,/+-/-34FW^9008/.+.5,)-1;-//0-,+'++1<*+-0/+3020.252538=>?88?B@?A=Asm=G>=A@9HC?<=<@>:CCDCK98E[FA>Ml::;B>HZLF@EBEAC:=718:5342212+*)&))*%!!&*$ "!"% !**!&$- !# #,%#'5#'$$/-4/5:*RHQOLA2/*)/Ec'")%,(##+(.?J)%))++-)*/&+*&&*,*'+0+--+,:,/.(%189-/-00;-,-*;/*//*((,,-.0441/123668875==F?<>?@<9<>?A9??I?>>.*('*.+&$&-.&((&+"(-)'8'+/9),(1,))**+70*,0010/;)*0,+-274--.8+6-.0+-4/,0)/93,,135/314273435568P7MBFC9<<9::>===;B@8=EBCKCC>>@;:@<9><:73692+.287-,)*,)-.)&)##'#&"##  #%3 /'I &5,##%,).)#-2.0-/012=;;=6<=;8AC@=A>;DEGo?::HDJ:@?:;==<@2-,++%%&-'$$$$/,*+*-+&+,-)*(2'+/?***,;+/1/*0-/)-*(+2400.+135-93/0-010225554122:2<693=455257>65B:;==BD=ABAAJGDD>F>XDJB:<7ABB=E<4204=62///588-**&'('.&&&"%! # "$%,"'!%)"* "*0,@7'# 0.*C''--06-?6BE;B=:CFE@@?B=C922:7.221)1-A3/-&,,/&&1?*+$$&%&!  !*3$!"  ! "#-9""&"*'K$&"#*%#&')%$-:21H;1>EZrkaJB5-+-+'-(+0&%(-,'$##*)'((.'-*&&+*%)+-105+*++,/-13+*2--+,/05-331.-54..@;41.37828<95:<7578;9553=54<2/,0-.13E2.+)'(+)%-3-/-"$$$# "'(A!$!!m%.(=!$ &%#!!%%$$(),'+,9A?989?F0twLC2)/#.(+/%(&'))0.+%)*+,(P(&&+*(-)()-6:8;0,(+,-,-.-..,,-,2289/43,2557/127165/25108/7::;=68>>C<:6:::899?DD>GA>B<:>@O@CJD@AG<<;^fbjUORDB@A9>78:376;34?-.-')***1.-,+$#)+(( #,*"!!$ !##!*&$,%"#! %#!&%(! )*'&$-329=SpM* aA:2()/4))'%*()*),.+)')()+)*&$))+**.-/+.20/(**,.+.11/0,-/--7212032038B@902547F?92087::?E69<;7496>>=<<>;8E<>E=>@H=@@?FA?GD=EF=>DD?AACMOFE?<>99@NciUMGQMEKHAEO;6>>C\?AK@EFB>>=KDRLUN@DDCFDC;<<9;8AQT_TLSIcI@Q?>>:>76;6;D2*.'01.*-<7=8>F?@B6;H3:?>5<:389>?>C?EIBGEX99<:9=:78;;CDPD@@?=>KGP:=@@GBA=9=?@ABC99>LOZYMGGIGJO;@B;:<7;6621401:4*0/0+-+2*&(&$$!#*,! ,(% &$& (2@"!  $!("! !$ !#/ $&$""#(+'2Ku tLWaED@2.3*.-2/+,-*(-,-.$+-+-*-,.*&*.0+-/-221631313021-/-234452537453479;H:9557=87<=68;6;@>N=:CKB99?=@8778:=;99F@?FA8>CEF@=CB8A<>:7633101+1/.87>/402()4,,39!"% L.%& ') 4D!%$4(!!-&'!#!#"$"$%)$ ""&'(1;DI@VotO>D920-*'-4.;+),)()+2,/,.40-+.=--00447/1/8.000..02-/336055438<;9253:826:@438E933455;=987?QK;87;95=;;8?<;?@7=9:=@>BBEAK=CBE@>@CEA???BAEAAHEC>:@@B:I=FI`KE=J@LFE>:<;95362(-P=8DB5,.,40)(&)% #19"$!#  #!)'' "1 # ! $,"! "'" #3#%#'# %($&&+/0,I[pf`hQC:>997/*1/2,*,,*-).)*.0/-1,03,,1/1*-,,0*1-=21/-0-.20351126302-/07466:<_:;9?9753,6666C889=:>:94838@?:A>:8<@=:;GA?AIGD>?BADEFHOC=@@@GA@:FTWI]K?E?FG=AD6581213-04:?ZZM9-)&#)%,)* &*&"*. #"? '&%XR3 B$'$ %"$&() #$$!&%'(')%#'&),6XeifydCCG?-+'().+,,0+0:1,/0=,-/-6>:,/-+0555465116/.677148452456H34:8=;?JN6:38374799<>BH;799=749<9L@?=@D;:A:@GQ@?=<==?FB@BHEFB@B>A?:)=/.'&2!!")"B;3!!=,!8!#"" $'"% $'#+*%$&'((+)*@PbX -pAKIjP4).-,4/1,1),)0@A.0.25B90.572*/544621>664D:7;45C<757:8:;433:;9F@9<8:@OH;972<5646:?:A=@99C<=36H=E?F=:==?><<9?BBAEACEBBDBDLGH@>>B@?BHGFA>DFPABDBGUQOJIHG:;@713/1/4/5wC|L;3)+,('##)&&+)$ %(*"#&,$%11'/4p#&#""(/' #!"%&"2(#" "()$%'(-22FU!ZFWWJ8GC=..,0--*0-**239;1--428A1109793A403376@<<9<@@:C73565154869?HA@F979F341879<9><<8?D:?9D<BCJ=>=><>9:;A@@>EFHLJFKCFIGJA@D?FD?CERF@C?DWJHMIHGO^hgMFC=9<566,//22:}MF1)-(+))%#".'$.#"% "!,%"')!! "&&/&1.*  "#%$"$ *""($"$#,%'$%'%((9=M|<9}ca:C>=615.31+.5E112.231431..+322=:85759464:8:76Q@5887<>=;:@@AKGJ?YDAAB?ABHDDCPUCKCD?JQKTcDHS^~jLEE@;7;=:6/18/GYI(-)&$-''"&'$5  !#%#""##2)''%0>%& ### !'(%# ("!#.8("$(,9/R\No,#"^bUF<499:23.0390+-3/288:8242/065.471989:66;88KE48?=::<<<8?>_?<@?@=96B5569A78::=C6:RH:?:?7>OWCE>=:@=?@ADID?>B<1.399J=>39/.3//-)25.3016.399765P8;::888;98=59<==;79<=:BND?6;:77::6875::IFDN>::93888>AEKL;?97:===;?C>;?Q?@@NSMYNeF?E@=AGFCCABKEQ?DA@;ASJZ_Gu`EFLC@B975533+0.66)-4/+#'&)&%/+''###---'-+1E6!""## !  $!#$.$%'!"%)!" !"%2!./786@6/22/,-462.2210-8653115A8?;>3:=78=8?=2368<;9:;::<;<93<88?;A;IvJ96A28849<=?Rg@9;==L=@AAEH8?;==9:<;=F=9\VRYKPVCEEAB=BEEEE@GNGIFE<<=FEGd_oJJ;CH<9=8=3/..))-,,.0,+.$#&(&,'$'$#%** (:40*!$(""! ' !! .,#((23)'$$! #"%-0+-0>0D9<;5;@@?<==@=AFE=?;979@><;<<;959=:=B<8C<><>@48:BC7;>DaHF;>@=9;:?E[>[DB^JCEEFDB@A>EEEHEKFK]MQ@<6<==elNdZKD<@>8764,72+,2*+/1/(-&+&(&&)($(&(*0%@-4,)(!)& ((")$/%$'$(" %4+"%(+!#!)%$/(!&*).0,7@PgQD65Q8=C34722:5845259;68:==8H?7;9966;9;>>D@8?A7A>@C@?@>GB?A;=>@C;8F:=8:<<>==<:BE?EB;>;?K@B89=`K?=;><;?>A;@<>@@89:=98@AD=@D>FBHJB?=GJD?AB=A;B>G>N8A7==<>ABDDJ<7::6K:B@>=>AAJEACA@VFCAECHADDEIMEF@=F^[FZBIMFGYAD=:74B956/-.,F(&(()+%)&,+'./$*)'%'-Q E'& "( "# %!$'& !%+S%!%511,%'0%*%%'%$&+"$+',,565.;99448/1D74;A6/2597@;36DA@<;?>@8=THA=BEBE=;;;?GGDDIDDDJJCMECF@@<;<:8:8>?9=>LWC@;=IBED<8E?CL=;>?A85;GA9<:B>@@@A>@CDEA?FFGPJF@GCE?DKE>BI:CB?>KIafUEHECDA;JBCFJJEJLD@BD;Hf=>E?<;;=:A>?<@AGB=<@LHBA<=8A@=?=@KAEB?DH@E?MAVECDJEBM@A;3??GHROJR>A:=<3045//02.*.+2*1(,+'(03)(Nf))&")39`2+& !$4+=9%!&$'#!$&%1-K)(:#!))+$#$'.?))/%.-.,/2/60==E711/8225:G=995=;<>@H<HGA?AA@?@F>A;?DGBA><=HAB6>CABPPkCB@ACGD>9;A>A;=@;>CE=B=E@CCCC@>>DEJFGHGIKA><;?B?DIKIJGA?:8985546-3/0,'-0**)##(*.+)$*+)0.*)(/-$( ##'4),-('&#&&$!'"+Z<)'"&()*03&&#((,1*(,*464M:]KL?3:5244558<;>;8:?8=:;@BB@>BQKEhb{ZHEHBB?IIJJHKADCCGILKHJNHEIEEBDBD@B@AIGCDBA?>GNVKDBDAC>??@FHDBEGEA>IAFGETcAAH@@JSC?DC>EHDGB>EE>CJFEGMICBG>?96181291-.-,-**')$)*%!+((=+e=$#%26)*$>!$!( &&&  $!!##%!&*$0!)(.'%3)($&%"#3*/,33.704;:@88=>29AB8938>M=8J9>9A@BCE?DIINQ N@??JCEFHNFIWDLIE@BIFFCJPTLHDDGC?CAPGDGKGKGF@?GJPHJKKDGAADCHFJLOLF@;??>CEB@@=GAAEaGSC@@@JFDDMKEFDGHHMOQGLEFJHIFHGE6=AA@CGGIFC:?<:448B1143/,')0(%%$%'$"('.3.5*&%$%*,'"A #%8 "$ #%>.+#$"#&23&)-'%))*&1-.>7035@@<4ICJ@6CJBBCDFTRHEHN?@>@HJICFGBJNMLIWHHJDPIJIN61DHHDCIGCA<@:>818762:/./?')*(*')'&)('(4M'*-%+&$#%()) !#!(/%' #0 ( "$-(  ('*.D#!'0'$&*+*'054J0015-=CAPGFIWMSBAEGEGLLGFRJHFHHJKB>K^hKHNPXUSIMHMLMGKIFNLODIGDIMFJIMPPJPHNHPFNXHJVKIM?=GCCD?JF?CAKFJIH@>AEDBGARNNEFKIRTOFDLGFHJIHII?:9?KFA?ECHQ575973>-*),%*/),(&)/&#(/*)&/(/)%('' " #%&4!#"$/%!!"" )#'&=*(("(*,+)1+')2250/5/5KHL8D=988:6:7899KAA@KLVZGGHHDKPX[YOGGXLEwONPPGFHGIMQPKQVZmrhbpuhVYUPTTOJJIGLOJPNFJFJQLNNSPQTPOOIJLKPQKLOTMLIHELIMLE@@A?GEHJBMJFD]KHIPIJMN^SLGDFLFFIKEGEA@58AD@EECKFDAF:;72:9B0..-)+('*,(-*#%(-&0)*'(#"$#"!(!  *# $)!#'"!#% #(2&!)(()$*(+1&)032.13?=?76BI7:;885=A87G?4;98>C?CSUjxjk^SWPNKS`TLCGJNVKXVEJIOP[S_NPZZh3 c c^X_ORWQOPMJJNSLNIJIIOJTQRQPSNOQLPLQOG>87=48454-.6(+-.-*)&$(')++**+%$"$!"&% !!'#!*!$!##$)')#$$$"(%$&+$$'-'BC-+538993;88>=CI:445>8>?=<>:E?F?FHLFB`l,{dQ^UVWXPIPYMNLTMJQJLIESQUZYQWVUoowJ,'wcVVUQVQMLPMMUPOMJKJJNI[SKSYXOKRNMNPIGECHRUPLNHPVOLICEACGAFGFCCIDCGNEFOPKDIHJJGERIKPqDHNHH>;FD?IFBEED=825>56G4/-1'-**'4(*%#)A%'(00%)+&&$(&+$&$(< #!!!"'", !("#!!$'$'($#!#))-,1*133-33A?00565C9;??6CH[CCECR:SeGEL#!# '!")#&(&&"(#<- #%0$'&%--1/5-?)+0/./1-23/339<=;6:39:=A:7>=<=@@<>>:=C@7660-13-(,+)+*3((*&.&&)''*($&%)'$$.''%Gs!*&+03DKC>,'-%!##$-481,+0.--.+-+/903163;88<;58@B@A;<:FBU{oDBGKROU\\XZ^O]^RRQNMUOOMOTJRKOVTUQ]WgWXhk_Z]jk[\\c`Z`hgwaelc_ZZX[[UYU^Y]e^_]XXRVVX\ZZYbghfq#xVRSQKKKJMKFOPFLK\fIFcPNRLDBIFBGOPMQMMNLRZs<@HNGFFSKEBB?B2636.*2/)*()%.(**,*%'2)'&%))($(+$!"$.(#&/6446jxO1+)%#!7G,(-@/01-27(9;8754=@?747<:;A=E:7=8;98EBASJQkLQ[aj[O^MLSOSTSZO[TMRWV\UNRZUWQX]XXb[YU^\`\^aa]X\a_dh\sildaZ\ZYW_l_]^e]c`c]]dZ`XZW]~^a^\bUa]iVRVQSNJMIJRPNMDLJHSamN_D>E=EHIRLKPSMONHGDG>JIDHFA@B=FB?:7X?=2-**,+*)'1)->-,()%%#+*%')')7"%(''%+*'C4251(&83*&/%&8.0),636.643<=D2D<787CC468=QDE>:7>?:995;>>4=@I?BNQEGNQX^VUUORVOQVRRTdiOOXkPRSWU^QQWUX[Y[Z``Yd]`[Z_[Y_bhhfeke_`^\[[bb]b\^b w_bXXXZ[X]cd_a[ZZ`pXUVRSRUOMLLMIKKLCEDJWp]GFITFFAHKKNNTRUSW[M?C>DMOHAEKDBCL@<<:;500-((*8&*-+)-'&$%'/(*')+.$$#")'*<*($):4*'2)%**')1;,)((+)-+&*246:;=A@47?>B;664QkJ=9?9;:38JW=F>4<=AGJEGAJb]RSMPS[QNUHOSUQYRNOSSQW[OOYZOWXeXcRWXX[[X]bYY_d]_acnigkqk`adgf^Z`d]_ajnd\]Y`[\^\^]bXZ\ZXVZSTPVTYURQMPLLIIFIFNTKXMIDLICBJJMJMMQOLLvjYO`IQHPNIACGL@<=>:6921.,)**-.+,<(#($&%)+)%$++')'#&&$')(#)-$(&.1+(.,*')).-00-1--.+(06?IH==B@;;<69598=<:@B<>458ER?GMOLCDEJDENQIQWVYLUTL^UOTSVRONKNMST_rQVj[O\\ZZ`ZTVXi]\fb_]]_^f^_Za~nshefad^^^\[^]_fh^VY__a[]_\Yb`XWXTXXXUNORWSQQPPQROSLHHJGFIKNCBBEDIJIINOKMLLeeTHWG@HPQDGDED<<;9:BCQ2/72+*-)-,,-+-8'/'$((1/70''&-'%))&(*(#!*+,.+#)2(')3.(42)++-*/887@E9<6789<8665<7@;?=977=9=BBC>@70/5./50*,*.,.),/(/%(&$K/##+%&+,,%$'&#$#*(;/+)()(*+*)A...02658=0368C47>=:7:I8;61;@987;@49FP>?PPOAJCA@FJMndVOSGRTKPHQLF\MKH`MNTSLJOPW\Y\[[[^[W\\]`[\]Y`da]be_cjhiepkiogidbabh_a^d`[a_`Z\V\ga[_ab]b\\ZY[UVOXRMLNNKOUUPMJMG?DFLSEKQDCMWWPKKNRbcZNNZEMHMLUEFAEEBA;;960.3.+.2.%&())&30(*%*1*'+&%'++,+&&$.1)>(& ,,*)'*)/B,,149?C:5D6<7DIREA=H>=A;9;7=9>968:96AAEQcQQQ]TRUONMWKNUPHQOROQeVOMNT[]WTY[\^X[[X\V[dng`_h^_bebeemlpnjljdfied_`]_`^dea`X\_]_a`_b_`]]W[VTW]SWSUSPNIJINHGKX@DEUHEHGIDDFSJNQQV_`SJXRLFIKHJFFEBDG93775332+/,*+.(+)/++(8,)&(--,,+&21)('%)*'$%('%%$3,'+2&4*-3++1=26>28ISZ[dBB9=<8:589:9:8<>@?SFGIAMNFLDGHIQUVRNPfUQUWPTKMMOIKNRSTQU[QSTVTZX[]_b[Z]X\Z^d`dabgaccdlyokugqhjjpmmmjdcdigbbab_ce`c^`b]Z_^_YXZVU\[VVUZWWSKRONMKNGLGHJFGFD>GILQQSWWRRQJFIMQLDNIDMYDA=@;7?230H44-**/+(**)(&)*)%%('*./2>%*&%!0(13$%((&&)-(,/***-1/7869@<=8;@bP:F@=7CFS>>588OH3<6569:>EHDH@EB>JJ=BGKMLEQQO_TZ_cLKM[PKNINPNSST[TXS\Z[Vf^VcbZadZXjhc`ecgmelp|yiknpmosmkkqkicedfb]^`begba^_\^ZZWXWZ[WSMWZYYYPTMPOMLKGLGMFCBDCHLLNNRPUPNLTSUqqUMGGAMHG?85533623713+*&,)&'$'.(+('&**,//*0&"$%$%*+$!#&',#((<*'*((-,?97@7:Q?;94@8BOE>779;957755856=DTHAGIDEFVRHJYQHKUMOPOZTWTTSUOMOX`WTVXUVYVXV]`UWcl_jV^lX]`ic``badbmp7:}ttmnmnkhfozvmikhkhe`cide^bc^e^]_c^bYXVRTVWYSW]RUXPKMKKPILNIAADHKJLNUWSOOTS\QZ~RaFDDCDCF@>4456@5434.)4.(---/43+*'*%))./14('+C&&##"($%&4$+*+/)'(%+9<734123=?98Q73G6?675?;F><:3749:FFC@?{I:31<9EKB;?=<48<8<7:D9?;<>>;820.10.37/*/+..1(,,0,(++0/-.:,*.0%,(&#%!%'(-,.''**10/63437=D@?>ICXRA=?8A6QG<>9;54=:=BI9FC;?@FQLIDFJX]FJMRLPQNMKLJOXPTUPMONVQOTQ_[UX`bgfV^daqtto~#j^Za_]cl{ t{wv|v}ps~zxwpywxpnnimygjcihihnmoeck^XVcYV^V`ZT]YUXOPJKOSRQTKHLPKPOKORRGHPRQUls^YRIDPQJMD?C8B=3.-24///+//0,-)/*'.(**,)*(/,&/1*%*&$*!,./,&('.,+2,48697HKNSNC\C@D9>B8>CEZE<;:89BD@>:FJ@CDETLfCEHS`QMGWVKLGLSRLLMMNMMKTRXUTQWVY\[^b]dajdeghny -e\[\jjpky,|vyur~ - {uxwsppnim rgbflrp aha\\^\VZ]_YY\XUPRRQNMXPQHh]TKMJPMQNKGJVVQ_ycWVMJPzODLLGA<;631740-.1,.5+++.:[75+*''/,(+/;EB510*8.-),2-/480-'-*--.)0'.*+''*/>*-&('&1(+*+;38;<=CEVUGLC:<;9<@:?V`S=>@LNE?B@EKGFHNLJKP`qHGKU[IIGGPOIHMEIBKOLRQLQSVWYWVSYZZn[pcl]dY^`ienjnjiogppu| ?' -|w ~z(}utltrx qnklrlnpnlmlfba]Z`USf_\UZWX_SPLZ_`^khTSNOQ^RONIIE[]cuiagYWOIBIEOBH=?B:7462/-578-,2')+.-5ZG72-$*O3,/4'/*)+5.4J0/+))+.).65>?DITI@;5343284/-/,*)(/-+.08B60*++AA7,,+*%'+-*/)-./+-*'+088DDKGW_al5LsTI>:@=;E=;HFQNjxu}sQOOTXUWVUPjvLLL]ZPPHFLPIIPG>HHMGKJORXZV[cZ\``a]XZd[eguoohjehmqqpvr ~~y{  9cP$}  zuqxpxwsxnpnnwlkijshehxhhfd`XJMaa`aXYV^]Xa_le^]NIJGJMLMKVQW`_UXRUSTSPLC@JQB@I<::;6hEOABLH9?>?:CBbqk} p\[Y[`bWWb_MRMNJEJLMLLJRLHDMMNPMLRXZX^`abUWcbd`]j^fllr{ttoeovons q~ C2 'N;) wqpq~|y|tsppskmhkltsinlmkghUMNTZW^]YWW_Vacw[WWSODGNMPJNQP_gWPJONSTKJHEHFNCAB:>>?740--),8))/.G7=/,2/>.*0>,(,0,*-(,-65533,+6*028JMM]ZuQS[^vgVBCAB@CH=AIJ<@=;84/.,010/.0*,8136.F9**Z2)/-7),2:-1.3*/,).6.67JA9^TIUZ`SZ\e?I><=>L<<@?;Fg9! 3 v{ gTQS[SRLDGINORNQjrSLKQXSSSWRZ[W\`]\bfecmjkwr~ vsu|& - ! v # -  |tt{wy}pyvtryrro|s{nksmkoik_Z_]f_]\bSW[S^n tfXGMJSRQSNWVRfXUTSF@HMOTPYRKO?A@EPJAA:82,/,/-30./,0C15F*,*).*1*'.1.+0-2'++,*-**/+CI9CDNVbWJLL_RB?RGA::>C@>AFCKuAA05.$D|]RTRFHKGOQOLPd_w]`QMKQUPMTZNSbc^``wykflg|szyI53#w #   {|      -wmzzx{~wvuqzzulrrlju{kc__^]`WWZWVXVdt^VOSMLMPWUPXQVVlg^pwJPOTKKLKGEJBSp\<8876.-0221+/.12P5/8-*),0/2,02'30*-**/.++-0./16F:9N?BOMI5?@MHL=@>?<>;=@DACGgNOA0/++:Km^a\QNKHKGFGMLRaaOGGKIRPHPW^Y]Zebe`ryvszn{q2#(+H0  -  }~}zu~}}|zv|vwonmho|pc^]Y__^[S[oeW[e^SLJDLJJTUXQZ^\ZZU^ -rRNNRKSEGIEC<>D7386;D;4,40,.2,6>;>=5)6367979:.55//0,0--.,3C/25@<77:\H<9?>=?9<==;@=9=A?AEJLk*T?>5-:=><7648J=5=+-114:IED>2,+4D74/62030-++./0.0..029@=@GG@>U6::F@9CBD9>:9FD@B?EHKPs'99\^WLYF=x\UONLLFIILTOQYSTQTQVSZ\[Z`V_dailzwmhonpr{    #A575.,0-0<=?BHNQi4BgoMDK/ wdYSVOJDKKGFEcOTS`VUd\^Yc^d^\eb_bm|onntsw}}y~ }~  ~ ~vuyy    -" ~  ~}t{~z|tqv~ ymkk]aeaa`a][Ulg\QVPPNSKKNNPOXTXY[`][huXPKGD[JPC??;;E6846<8380/9/>5>@Z[9*/18832+5++*)-.,+/35+,26/=MIACC<:@CF;;JB:9A9=>>;9@?EITe-DCgz|mJNC+x__[SOLKKJIbbXV]Z\Z_ZXaig`engknwlqn|~  }  {rx u{}  -  x  -~t   t|ywrqkinl^cag]^WXZWVSSSLSPNNOTUm\aRSVTX]rcOOQIbUF@CFE;7::9507=>>533=;J:a@D3,086<2/8'+()((),)-+2/-;:N]6B:A7?IA=65594>7<=9;;?:@ ~ ~ wtvu~   -}  o}{  sliti`^eeafWTWWYU][LIPLOKRV[RTUVZb\V`_[RMJGTJIA>F?>AY7718;875@Q849T=:;==BJSQfUOF\x{fC2ZYUSKKLNROMPP]RV_YXdkgc^d""vixmgoxqv; A"z{x |uqy -~   x|  { -"}mm}h\gg_a^ZVWXWpRQZHOQOOOUUSUYXc[ZS_OBILKOFGEJI=X:577:32020:S;78F@3?A8;53666,(%%(%%/-(-00/424<56/<8887@9883M<3/8@8;499A=FMe>5/8KrvOR'a_WKILNNN^QTRTV\_obbydbZh  wusmgpohu   -xeoz|wzzx   }  -ww %' {ripjckkffl]Y\[^TSWR[OOONLNOSSWZUlgaccHBHDEMCBJMGDA@959CG).$%)$'' (,+2,2356568;H46103310:3+346365<EWJKHuy "- ~]VPJPVTZ[b_`egitlgkmquizoqsleemix -{|y    -"tq xz}wq|riqphhlccbcd[Y]VYXXUXOMLGMTZPLVX]eXajbnsi[PMI?BNF?DFFDCK:24+0<:8759E]{\TaMH?80-05$$($)%''-+),*-00/43:660143<036B83264a=778?JJDDEgu\amgslcd\YSLJNMR[f\]eoffkkjklf\ltkiisakm{~|}}||~xy"zt  -  -% - u } -z{zt~|sutpkki\efg`e`ZZbcYVVZPCGSXTXPNTV^hli\le\JAGD:?LJWEF>;C;:=144297:7ATn}QrnJ@=6<@@#$*-'&*'./(,331.628694?3//..62700/3;/:7:7Q_?D?X^NORY\YXY[a^gNLLWQVYek_a`f`ljgdigpgrflmhgkhzv}y}{{{ - - -       % pnzurtoosrbf^[nddfc^emml]fTSXNXUVVVMYYUXn__cquUWRIEPC>>A?H;@8??6:=6427@=ITah[]zPA7;7;3!""".'*+/./05>50324626/7/10,41/1345<8495Wg??@GHGMJKUWS`inombyWT[^Uh_gk_eZekhhigcgilklnegjxrvz||}z{ - -  -   - - q $  -kpqtqlzndiidelhdihc]_]_Y^WTZY^o^SuMQS[^ibhvwfjTHGGGBDB@C=???<;97;>4AAIH cI``RGVNEB;*$&&$-+)(*JeO=5=53<358/26/41/.4/..3639=Z^?>AECEGGJKWTZfmx i]vid_c`btyoejkmdokefdkmia^^jcl|y|rqzyx{x}~z y -      - - )qlnupnslckfbkfde__Z^`\Z[S\as bYS[X_tb_c"YUQIHHGDB;>H@=@@>8:2@5:T65;ESobmhcNPJ=7%!!#%).(./UiD><961.,.1//51.*20500.7:49RL<DTZWTgxx>ucgfszp{|ihjlhmjof}fada]tju vtzx}y}}ry~xw -# "!#" $",   vt|{pnlwkgnldhimdbfggeZ_b]pk .#y_X^^fad[aogJRQLBJCLR?>@?>FO:=8696>8AN\[_X`o pubcil~ 0- -xjoinmdejhmswiqu|wtozuy}xwru{ -{} -~{w   !$$"&%()& "#%$ | - xmvyqmsuiipziiepdmjgpW`lhci~gx[_bYaluc^]KJ^PNPGGGBCA9BJ:?;::9;7A:119IQb;>@IAJTOHSZ@2'!#"&+-+5306;94:0/.328J:-.)-0/12966:F@:7?IA;:CEJV\dl} xgiupq6U H@riqhmiep ospuuu{xvzzoy}{~|~x~q|   - %%(++*)'%$*'%!%$   |vkrusmkfhnw{mfkmjrm_]TZaekjrrvh`XUO[UR^`f];ObYPLFGCA;=;?F=LN. (')-^'=3B>^5/,871-/.1+*++,0,3344>7>=FLX^_px2)]lkk t$,}Wgnfeds({mn}ymuzrx{{xrtqx}y %&)**+,+**))&%#$  opmqxxlrflr|qnilqrurp[fcaeegjlzme\OGOZmkedNIRWTWPIGCD@B=<9>9>:A@E@4;3CDD99NV=:?;8>69A81")'%*/4_f7>J/-/530-4/.11.1+0+-'/.17203<>:=DBKAGMTWgtsn5Repm{ulxsimhhffmz~*C<ljvx2wut}~ -xy~{ - ~{z - - "'*++,-...-,**'#$$ -  qvrwplruqjuulpozpqu^k\cV]c`cjjg`[HMTR`V[WRZPJMQNEIF@?A<<>?=?A>EF@AD@D:@OD8J755=1414*1:#+&(18DI?;G50J37J83)026)1..+0.+/281/09<99;>DHDWLXW_sFSzfylfahxigisumhbgm6N.qirz us,' - mvvy~{z -  "%%*+-1001210//,(%"$" }xtqpwyxwjsmqi|-"{qtkkY`XX^^\lfQBFLQMPT^YXlRKONND=E>:=9?C?=>B>>AB>D<@DK9=B\HBCMI;7<447=0/,-()''3;,16714,1C170.,G=501.1-3-+0815.24/3:=:5B>LGEEJXOayi_P`udiikndbc`ksccm^USfguwonhhyxsszt -~2v{pvwx~y~!#%(*--/3557675432/,('# !v~ yz~}utztvslknsm|tojjd`aZ_dqTRUNGFFBFMRVZZQPZZICCG?IIJMG?BICB;ACF6;;DZ=:?79356<701,+(3*+C*835.&,,),/270+82,G0+Y-;.33,/:.1/152-5<;;:898@D@6;O2-5303.0.*)+),]835+.(0+0,5*-32Eg6611;/26635/.-/2:4/5>8:<@HAJNKNJVTY\Uaquyvlme_eY_]sfb^gxzhdiskciutmgjqtqlursujx||yzw|~ - %'*--/5768:9:;:986652.,)("  -|}|{lw|tlwspmnfhjufjilbbc^]W[kZSPLSMQWYUXVWbXPPPLNIJOJE@BB@AKBH?@<:C2O=@>;57,462//0*=*,,'*T1%$(-.6//,7;..8>0283A5D318,-.*.://5580><@CBHKLSPZTU[QLhkwg[\\W[`bf`nlvpnjqtudginhgnnqehfyix{u{xtxzvy""*+./259:>>==<<>;6884.-,*& -  - w|vjuoshyr|yifhlccorxdcb]VUW`ZTQKNLMPQVZbWWO?>>]V:A44./726/-+,0)%62E-$%./01-5-9E58K94@4E7+/;:--12,,-,75;5CBD>JCGIJPXSQUUL_^\vpfc_`_XVa]]jiejselircmfrnrrlogckks{{s|zvptr "%'-0259<>>B@??@AA>;9342-,'&! -  ~}{z|stksosonqhgmkamjklnda\VXWUZPOPMRT`QOUX_ePHKWFILIHJIDEIATFDF?B@7;J>P>717<73=953/,(&!   v|xwxzux~qrnkeamggmig`UUWVVQeJVLQMRUTWP[ -_QLHNEIMLSCEFG>GWD^CD@8B9M:W<=6053082,+,.,/(+#"$#8:2((5-1,2>89<4FME4:52002-1+.20=5587C@@CHIGJMMOQXSRSLQ^d]_e^gXQYfVX[f]c]`sbcemkgqnho`cmoy{u}ts}~svx}~ ~ -  %(/457<>DFHJKKLLKIFECB?<74/,' |{{~~y}t~{ pqq{ysopomnnkac_oMBFHONLO_OLKMKLQRPL>FOXWOJG@KGGLAILH?<8:?BC@4DA956,+''.++,,+)(+)!')J;%-/3@2224659ZJ3:5.*,/-022657?@C@ADFBFELW_ZUX[:Bemmdh_Y\i_]_f[}dW_ad`_^_eiijhjkfhpsss}utw -vtwz{| -%,138>>CEIKMOOOOPNLIGED@=741+&$&   ||~~~vsu~{rww~vnjksh`_ZPKRJEHKMUPULGOPQOOMH6GSZRONLIJPWG?E;AC?=N@FU75744@210,1*)')*&%,*$'*-4C3,;EJ:;5I.23B./-+++0633;;IMD=G=ABCINRWTSZ^gxxrtgw\[Za\k]y_Zf[laa]Y`ammoneinwrsqsooxyx}rwrx} -z!$*0127BCGKKOPSSTVTROMJHF@>:41.'&   -z{wrzz suxznjgnixli\UTSVRLRPLSKNFKMXNKNF=EPMPT]RMJHJaHCVXH=DCKAPB;9A411/001/)&.)$'+,&"#'6/2Q878LdLAB=?541?175-+-,16APE=7<:EGKNQSUXXZZWUSROMJB?:63-.,!! } -|z~{yvy} t -mckhsmqdb^VUWQULNLLMFEJRQQLTQLDWSUOTSLHHGHGLFOVA@FG@[F>:817/10,+/.-,+$*>+- !(%,.-FMB2ZWjoN5;561/,5=3--+25^I;8;:;EDFKHKLTX]\``bpkothkabq`TVgjfoago^\a_ccdafoqiyvitlltyz.|{xz}  !(-058=CGKNRVXZ]^]][ZXTROJEB=840.-"  ~y}zvyu - -rzxrtlfjjllicg^ZVVRVSJJKKJUOQNOSTUSTUZW^TIIICA;=BFEAA?LY@LOFD9.132,.,-17+*-)('7.!#')0&-Ff74DPFH<95510,1,8-0/,SKCHHVVttBA  -jhjY[YYSOPZWVWUVVW_\\Vd_W\cwjsusciqloquvz{jpbl|}   %+04;AFLPTZ^aegijjihfc^YTQLGA;72-)%! }|twxxx|zqyxqshkj}7/mi`][\VTPRSTPHKMHKIKUSVPPL[W_SPJHLNGH??B>>=RCOJHNEH>@613.88,2*+)##'-%2')(-4,1NB3BDE<8=>29431,+)7//,-5>CINSX\`ehkmmnnliea\WRMHB=53-)! - -zz}youz|xn~y}lfkelvogadZYYUTT[VNIKYLKLKIOUTQG]RU[PTKJGFAEHH@A?CC>QKXcNA9:/,+4:83*4+)&+,&%+*(*3/=;PIA9I9=A9.20-/-+(/+1/259>KD;;FEHN[TYh .z}tkc\XTUPQNZW_]jyV[Z\\YU_Wbkjumhhlrqknzonr|}}s{uz} - - %*-2:?DINTZ_cgknppponieb]XSNHB<72-*#  u~zvypr{mpwvtghomwljgddd^bW[SONILRNLLHHNONTJJ_TTOWQJGEE@FC@B@;CU5BJf@ O882.132?74.(#! w|t~yu{{}}vpuhhsxtjiafgth`_WLQQSTONJB>JPOONPPVUWRMQLJHBA@NNYEAAGB6OX E@-608/-21*'(((&(4:+2-121F_UH94,>A63./-+*/.-C+*33469;A>=JAPNYk Yd{y]Y]Taj[ZXXUgW]X^Wg[c\ZZWY`bX`lr~elprmpqrq|rvwzzz|  "'+.6;AGKQV[bfjnsy{uqomhc^ZSLHD@:4,(#  -~xvwxvsx~|xxtrihyvgbihvl[^\QJL]MLOI;732/900,-,,(66C7:7@=ECCDQz#eqy{YPm\Za`YYXZ\VX^XhSUi_Vbdbc_\suycRkgrojls{{psvyxw  %(+07<@GLQW\aekosx{vqolgb^YSMHD?:3,)# }zwtwyrzwz -|uvxsq}rkljhhobXY\MJGQELMNHMONQTNHKVTRYJLHKJFFDAFCDYoCDHKGHA;34602-/,(*-+%"$&#+%+577@=9O=36E42<2);J4.(*'++-2C>;:<]QEH@D]9lohl\]Y_[T_a]SYXTcX^`bS\ZX[`jgweeknxmrlfgisnmhoxv{lmt{{z - - $(+6=6B8R_YUAPIVgivh]PP_][_mX]Z_ps_W[][Z`[[^cdehgg\fsmjjf`klnlopyz|{knu{}} - -!!'-19=BGMRX[beimpqrrnkic^ZVPKD@:70'%! y{ux}zw| ~ '>ynmowrjaa[^ZWKNQOXKFHW\mkTKS^DOKTenMIINNSFAFMIJEGD@I>DFMA:510./)+,-+##$"!"%%:3kTce>YD:97351(1C5>B+(&(,5HRM@FB93/($! }uz}to{ v~ - GH7rsdjie_W[VUXOLNTRQOKST[QINUzSQUSYYLMWQHNFFCEFCFLO]JbXPe;8/19/,()+(($# %'%1.7g%{PD;13>;0./3,27+3,().07JAGdxLOQBGJVSY^Xg-R b\b]piaQS]lrptZSURU`aV_ifg^bpwnkvjiolqpoinmrlo~   "(*27=>DKPUY^adgillkgeb^YTPMHA:62.(! - wxwzvuz|zz <(}umlj__^V]QULSONKJJOKPLUSRLXRTXY[_NLIFJGJACJQJ]fJKJH_m81.0+,/.'*$,&"%('"'<<8KpH46825480..9-0//,-):5/,%" |~{vs{~ -zywmmw~~hl`a[WOLMIEFNFFIIHGIOURRLOVSWSWSIDLSE?CBKs_uPiIIP_kbH2,**'&-&)&%##% %!F;>K>527,,.7/5208239300(56/D JNKJNIFNLTSddmymfZZS^df\`_q[WWYSVXQSZ]bU_Ydltxwy~{tovpsmsjp|xb -  !(/5;?DHMQTX[]bbacb^_\WROJD@;72-*# { znwwz{|~|nkow{twsqpickX\PLKJKDLGJJFEDIQVTUXTRbUXgRJILEEBCKT}nZMAM{OhZVB2+%&(#)/*%&(%$#('%!=A<;3,2,-+-3.37=7/31<6:-,.4CFJORVXY\^^_\ZZWSOKGB<84-+#!   "(sxyv~zxvmkpw~ mb_d\Z[YXO\NEJCEHEEONOMRM\\ZYUU\KMLICDHFNJEMMGDPv;<;J832+'+.*)*%")$(7(&,&O73074/2,+.-(27A=2:5541/,*-6839JFHT?@TYMQ^`Z\^^WUVUShLZdft!(#piqVSQYPR[Ta`_nu1yseizxrrnksft}w}}|  $%/06GGNF?<:8@47B25.8,,-*(!'#&,#&& P[3970+/0/.*-57.61/0,)30-76;27;EA9LEVEIOPNWbYf^\WTjSPXhcfo,dgic\URWZWV\]xeij`ohihaoqnkhosovov{~}|z~  ")0/3:>DFIKOQTTSSTURPMJGC?=85-)'# -y{{~~~zwzstknsiuwnqlda`V]VOFIHMIIBEYMDPVZWXbXWPSYUXNDFGAB;KEABDIYFB=?2<>>81++'+1+(3"#"# %%:;@:1-101,6/1/2.154(%0/829AhDD?=LG@EN[lJ?4bH068051((,''**%!% &!%"15AD9430B/14,',./-(&*.56=6PeD=?<:>@>BDCFTUOMIKOXdSYRWkYgaGISS[_]^ZbPQ][\`[k[bZ_`fb{rsonlghqokt}vvy - - "%)//7;?@CEHHIJLLKJHDEB?<84/)(&  - }v|ow}}}z|uopmt{pjhh__[W`UMPKMPUILLRVUXQYZ[^a][XXSlsICCBE@CP;@7>XFC2552.1*+,,*****%& #$0(" 7;K102,020220+176$)(,./9>j)!D<:6957:BCKHSIVPQ^rciXRWZcblfkvV]\bYWSWTUSPOO[d_X]Y_bjzyojkiztpy{yv}  %*0237=>ACDFGHHFFEEBA?<:4/,,'# uurzzy~~~{w vkwnoviih`\Y\WZuRKGGLNTTTRPUVTWXV[WYOABK]_UHEE?AC<:751,)&! zzyxvxyyy xuqlwyphfgg]_f`pUIJIJO^QNOTWX^[Z_ZY`SJNPKPQKHAFEEBB:=<=923620/,/20,()%*'.-*$&$##%pP43>?*(*Z=,.;&&'88)--01Bk~G<35349:;=IKLFKKQYRPSTXQa`afi^bWUYUMQ\RPS^Y_ZcZ\XUg_^evoinrmf|u{{{~| &$**-156:<=??@?>>A>=:7430-)(%" -y~zzurx -urwusqnslgfia_q`YZQPJHKU\QXQUc[]bTUSWUSOPMPPDLC>=UP@8==423421,()***-(&#&'.9/+-$#%!;714,.))+Q90,0,'80(.-2:76BIE;15866:<=EBJGJS\[MROJRTS^[]Y_WKNVWLNZPVaROPRV_ZZVQ[e_`ivqo -ld~pw|}| -  &*-.246:;====<<<:752/0-*(#"  wyz|{w} v|~ zusuvqmmij^mtl`_^SOIDEQPSUXYZ[VXWR^WONSTMLNNHGSOFF>>4220116-,),*-(,+2&$$#$$%0K.''.#9040.3+/&(%(**501-**'72;4;6;451859=M?ERJAOOYOHNKITTYXURZa^\ds\LPNPTPQU_ZVWU[sZZ_cfkw -x||{w ~yz    !&+-04478::9:977641/-,+&#   ~y}~z y~rtqsw{~upoghkkk[Y[\PLKLHMLZJdVSQORYUUWQRMNLQLJFJDSA=744<:-++.+($,*21542++1-()0214-097A:8?>QFW\LICIMEIVQUOWZ][X`YUqpTSRTLMSWQ\N\Xqg]]\`]^mvz w~   $)*03367888765431.+**(!    - ~|~{~} xrnrtqn{}jfoyfa_ekafTMOQMMVWQRRRTSSYWVfQgTTMQNJSOKJD:;9732.2*-1+..,$(+'*#3%()("1(('"+2402,-0**&),-2)-543B0-+(),2.,66N35BEHZOWpVWDJSMTPLSUPOWTa`cf`VVSSLXLRY_VRRiY_^^]aclpz/$}   "&*-0243565357410))&$"  } vvz~sxzmlnpuvqlnnwkfY_a_YSUSSSUWXSMVSWWTQTKZZYWPNMNLFKIDEC>?62261+0./(*&%&(+'&*,*,&%.&'#D"524//4*/)-(1/+-402CR6()%),2,//-046:FKEQWSXORRMPQRPIT[RKTUa]h^PaQHRIHRVYQZ_P]ae^[Xaaplw%,() ~z~   !#(-,.122211331,+'&"  vy }z{|pssurpryzostqheg^W]b^SPQSZVo|NQZVUUWS_U[ZiXTSPLKDDJNH<;=.0>67+*-+&%*'&)(')#,++')(*=0*&)+**);*7/,,846==).PQ4+"'.*-69//27?CKPpjMYhS^kkUXTQJ[bRPYKTL]L[MKGJNMTXSX]WU_`T`^Yddno|9EQ<&  }~x { -!"&))+../0.-/0/**-&"  -|~ - ~yx{usplmxq}lotsjai\RXLXMSMSiTTUTWTY]VV]UXPMWZ]QMbDGCEC<5K77;:.+(-*)*2*(+&(#0+-'))()&)." !1,*-/+?6-=u:-491).4,2$.1.-/60570QBINqfUtuc_bcXd^GMPJcZQTLOPNFCHIONZaTU\aW^hd]Z]_cpimy ;s{X# }~x| ~ !"$%')+-0/,+()%%"# #  {yu{xxrnms}vt{~caaYQLNPQSVU\TRdZ`Vp^RX]WT^P^{e]^LCTDE;E=WC<37/&)(+.0((('2*4:*)./.83,&-#)D0+,/))--.13,-75)(-$*3,,66*C-,,=;??HONIVrY]S^ajxOTIJND_KRNTHFNKMIMs\YZMSRVY[_aY\]filr0mwU"y|  !#$(**0-*)&'!" %$ -}| -~~vuyxrksx yp{f^c[MWJPW\WXVSU]P\XSTQW\]_PQWhs`VYdUDJLG=<88C26,+.+-*'**)081<03139PM:00)*3-,,*0-=016,+%&,+#.(-72)-.170*07JFDY^XQk{udWY][TaUFPLSXJOPHEGDGQMDOYTVNOPY\W_fmcetkls -:?OC -{ yz !"!%%(,*)'''&%  -}}v{voynq|{wptw\ZROPSYSMLOXYRRSZ\WQV_c^X\^ fXj^QFAE=96;740.,-$*-0314/%,+*10@A+8>75(4260(*/5-(/00.4#%&')*1.-1+.0./>131<<164.74'*-./.+*,.,,-(I373/9LH86>921-*-'+)(/,2%''*)()+0.2/,+.//:67B=7BRbn3h3\PU[VHFKKHPKJDFFMEEFDDH>GPP^SOPRRRUY]hfkigk, -y{yvx}}  - - ! #%&!"!   - ~ yhmmtltru -.)~ned_^OJOV^KTOSQJPRSNZ_e_W\RT^Z\_IFSDA?OcWVPPTK\G@KCEIJ@HNUOLHGHSEDGGHPURLLTXOUY^aSgxx|qz| tm|mjy~     }|}vr|omqptntru(+ d_^dMUMNNVXPFOJQTLNI\`doXUcXTWTLKKF>BA@:99;320.2./2-'Z -52--0,+)%4+,.*+*Y45,)5/*+).--1%&22"'33'*'(++/*..328::=JIPSkr ]MXUTLGJCIRFBJBH][HIGDMKEDHHGOVOTIQ_MLd\Vglqjqro]rqyqzvjotzv~  -  ~~z vwywqxplrnnyx| ~wZ[ZSFELJQNaSUSYSUKPOTdaXZW^P[Q\XLFKMG=;;=;=812.1,+.+.-Q3/--.,0&-6-/020=we/,'4/-*2(+)*&(*0%#%F+2-+%'2)3/B?GFF:863:=20/-)(*(,(&(*.+',(,1&6(+*0,--,)-/-'(''(&+*(+((' ##(%'.,M.-01872@>E@7=<;8:6471,6'(+))(-+'/)')8&/1*)-.(&*&&+-0)&),(0+02%,#'""&$%/6?/-4/'/128:E>?@:IDHTRLOHFHIHINJHO?>LOF>EYALIOMIIEOTJV` &~dad`jvo]g }wy~r~jrpvlrozz    - y{|z||uoxwuyupmwxsnbi^]ZWXVPKMYQOQROQSVVXUY[TWYVUWVVTZWJEAE?B?G?AJLOJ`GGFPIT\cb\ebhhntwjqmsr -|suqppy ~| -  -  - -z -%|wwypnqwnyt{owqhpqopma[XWh\QR]QQNYTVSSUYZ^cXYXXT]WWTPNN[XG;;<6987:=GCJ6.0*+*(.)*%%)*+.+&--,0+-=),0%+2*@*$%C.*+-@c3_)''%())'47>9/6?1337GFELDHJ\r\[^ZdYr!mmjgjmu~|ntok}ssz2 yyxy -~   }|}}}||trqqmllktsukhejf iaV\YYS^PRSTTRZVZTUYf_YVUXOQQWQPTOGFDC?CCLB@<2G/0)'.>;,4M98@QGPQ]^c[]a\fJHCQLK@GR?A?JDBHHA>DAF@HGFHDEIHGGN\Ydhmwujmlglsrux.zhntlpz| - ~{~~~~~~}wztwvzpqqgojfljfg_]hb[\UQNQPO[[UZthZVTSQMNVPW__^XVSOOIFL@CA=HEDC??@D5SH=5:28-+0+)((3)*-29/*541*&(("%02%!")(% !6'%%'$" )/>N|~EE?T/-11205BCDFFIDFBJCDCACFNVZ`dkgjiipqfz|vojdksemw  -}}| -  -~~}}}~}|zvwytsqr}lqcegddcddg_[UYLMPUWW[b`VSORV[XWYXYaZYVUPJKHL_KDDHFJ\RA>L>JQX<648++-;+****',(.(15,2)0%%#"&.+'#*(6"%('#$".&'&7HN8'C=;601.2?2=EB<=4-+)-.3((,+,*1)),22C.*-2-"0*#""!"" "#7,8'407@U6D7+)'(+15A\:DFEHHEPU[]Ujxnlot@? -y >/qo{'=w}x}$ ~xzv~yz~|  " } - -|{|}{{|}p{tlkpqpphbbnn^ZVZYUQPTNYWZVf[_]]mTWWZUSVWXQUuTNGFEAFDI^`YeJUd<8CG8.,.).2)*)-++*)+/%0/8+%*'%$!$"#)#!"(")')"#&,27EA;@94*()('+9J54:9E?DBABCL?GBEJDKRLV[felarzMgy~ p}(mmuww{"zpsoutx~}{} }  y |y~v~yqkm {o|ah`{dYYV^\R_WRObV\OXahk_V[n^^[XVYUagwoZFIDGGWQSMEGWx~sMXB=:1.-)./('&4W0('),-+-.%%,6',,! "/ !$%%<6&$&1BEB0(+E4.(%)$*F262472AEXYIN]^dTOOQIOCEALECE;AADUCECHFGH>FA@FJRPbamvnlw"E xtwwpruxrss|zvso}wz|~}{~ - {!{v{ztkusnund_^`oW]^\\WXUMRQSeZTZ_g^ea]\WX`][WSSa*bHGME[@M\NLI@YB<:<2588;/,/-2),*')+2)+,,*,;3(*+$0((*-,*7##/&#"%'*195C;D5<5*)&'./,1245;5HGUxKGX[jLJCLKHGFE@EBF@AAKM?KAAF?F?MEE?=8<:9>3,+-)3))'-4.''+&)',))'0+"%'#13'),$%#$.93#2-NB_qB/8-.(#((*03/31:9@Mbb[TSWKLNLJCHNFHB;=CIDCCE?DVCAFDJ>B>@D@IDDRRgf/xrkn`jkaecqZcmr -rllquqxxps{yy~uq~yz~~  |x||xuntuw toroesqklgtkfbcg]ZbR[YXZX[PY\WWWTY]_[a[RTjXXVQMLHYVKEDCIVFIJVb_DC:=P:25?4+,.&1+-('.)*%'**-'=+T/(-#A0(*4''(2& $#5$#&5-_) {@,,,("=$@:4652;9A>FF>9LBBEMhYPKNRTdSAKLQIILKBCFBAE@8?BBF?DAAKKHI=CCCEN`m dbrnahzg\^deZRXbhmnnpjjmuvynttyxu~{ }{|}vqy|uwxrronw|wwmxlvinncf_ba[be`^^Z^WST]^TUVT[RZ\WTSQUUXaYUXURQNYTQRLFHC>JFEDMIDE==A=?@BE9=>EC@>ATKPW_]cdd`|~cjkgpiiZg\a\`s~vvgf\pxqs{wtswrvy -~wqs|wpminnqrjmvmiuqlpdafc^Z_`ggX\WXUVUWXRPTUZa^YZ]XVZZV_`VSUOQQNWIOOEHMBBFCD\TFG@IkU?99>E;0-1/-/20'*01%(+'(&0('.TP0*.+126$,2 #!P%! !'%( ($! !"$%##&2%+.:9F?CJCNHFIKUMZ\PNPVSK;8=BFG<7:ABBA?GEA?@?=<;>AILLLRWwiddog]sqi^R`b_ad^pupsjf\gfrun{rxuupqt|| |~yz -xgljlqqktlhmdanqf`gY_Ya]^]bWPTWWWUZTUTUWY|]lSd_\WWZXaaZV`TPNLIPRD>;B?>EF_ONP<>AC@A9/>5@/3?+.(',1''+,'*((&4$1))(*#*1&%(25/#(+#$!!!$"&"2 ! "(!%-()+,043;DXFPDHMKNQX`heWceJ86>;?@@@EG>@?DD@?GDCDEELO[,gpadc_jucRRlghbinpebq_Yfdxprvxxqtuqw}  ~xtqstvkgnqrm{smrru|m`^gq_ZYcZ^[\SW\SV]XZ^`h^WPWVRY^Yf[QVZ\]ZRSSYKKHCD@CB>=CKQNA?G<8883852+-.,.0+2A20'5(,-%)&$#!+%2)%'$#')&*0-3(,"!")3 !)$+!!" (%)*+)&(,C+;<6458:CEMBKVXYveqxY:7K87BP@;@@=B?;CIC@?D?C??A>AFKXddh[Za_ede[^k -mrptiuyqoe[`__ep -npoqtqwt ppnm}nqjlbf_gjryxe{whdo^kc_f`_zc\e[U[\b\X][\]XT^ZUYZ\YYYYVZT_TOLJMA@N;6FFBBAA7;2:9./0,322/---,.-.A2-("$--%&1(! &)&''+%#)+/(&$"/ %!"#$$U~% !#"$%#',.28FA1/7>CBCGIPqibgniD7563;IFA>;;A?:DD=87BA?EL@HDFPPQ_RVb_`hodfeegykhfaqrqdip_Z[cmolm#xmu{ozxrupvifkmjja`he`chf^T`ia__]ahtbbcmfkg^\\]WXY]\]QRMTn]^de^\[aYWTRMJGB@<<=?EaCHLGebdjaS^qJB99/;F@A@:9@;?<<>>9;CCER;=DBFRNTPWcd\fpiefcXSgppbhZgig`ddwjcmefkvmpgrnyssmbemgj~n`f^idbUgaX_Wg`Z^S[Y[`qdVXW^a_ZZ]YYZZ\\\YRTWVY\[ah\W[]\OMFHIG9>7;7;:;_a>27;68662111-2.*+.'/*3.(6(#+20+&&$$'#$$'+),:A/-(-7'$.!*#!")F$ # %%.'$,27565=?B:8<<=@>5>>EEC@AAEKWSTY" ]fnbadt_\beshg qgpZpkhnhpff^dnnmi\ailhihlfrbgkc]^YUX\faf[XXSTXcaabWWVVXW\aW`]UUMSRSOVTWUVaY]la]WTRMKDEI_>B;=;=B6F?J:9;85/06401+*+*...*%&(.F(%(-+*&(()'($(;*(IP#((J47%'!'&($$*$#(!%%$($(4326A9?J9CESJRNPW\XVNQSD956;8EcD@4:<<>6@@>@FCA?E=C?CIMQ\SjbWX[cbhad^edikir3lagqliqliiZ`df{Z^f^lfdczjdbmhjlc_gd`_Z]TV\Y]RUWW[_aZXTY]YaYcs^]\YXX\_]YTV\\^d\\YUUNHEDBBFL<<;:==K?:8FA@EEMPJUlULQGJLFQDE;67;Q@=;;:>878RA4?AC<747.)(.%-/**--*)$!$+*,,0()(')$').010*($%'/((+&9%$%& '!'! "  % #%-51-/3@I=>O>ADAAG><579;?B@D9CHJIONGJOYxb[\`ag``[chervokqglln|QW`a__[`]c^^f_fjsmivntbXYZXUae`YUS[X^plqeca_baY[][YW_mi^ja[\c`c_UUWPMSLMNNNE=<DEaEAQUKNJO[\W^Z_fhfVa`mjdohnmhnjgi__[WftfTWh\^dkehfvp}yfeaV[Y\Uq^iVXXdYapuzhlfei\dd`nZbki` h^a[`[e`YVTOHLTONVJCBDC<=E?89>A@?6B66271/**,,+.1--++'*&)+)&.-$$,'1+*(&(,;75(1"1+%&%  & 010! #%"$&'(0--71?^9@MB@?O>?I`j^HBHHGAKNODK_:45>>7?7884>:8:=CL65A=B>:;A=94;<7:7761./1.5)0+($''%%-2-)()'%#"#%.(*+N3,+(,'#&$,.=H!%!#*' ! ()''227;:7>@@GEOM\MQHWTWY[VbZ^ZZ[LeeekdhrpZdkhj^\eWT\a___Q[Z[[]aZkbWY]ZTV`[bg`]`e^^`\\[[]`a`djdc`d\ndaa^a^eXYVVNLMURLVLQE?CDAD:<<;47<:ED6325332/26-1-)(012+,$$()+*%'"&)37*'*4.$)-(*$*'QC"#(!P !  #&"((-177CEBF=??DAKM:2693469=<=?;<;:=@IBFCHHDE;7Clb62A488;5858:CR==D>ACIISHAH@GCCLKKRW^q]]y`m]fbfb[U[T^aaa]Zc``PPTYmxul`nc_[Z^_ef]ddd`deb_c_aZggaa][[jf^\\]`a^ZYUV]fxWQNMOdwVYbFGJF?A>E=>>8<;<<<9<@=;??A_SIPFCDSCCHEJKUVTT]ai_b\fb\__feiaYPQZ][_btps~uujfbj{kcd]__e`^cbkegfe_]fb[iggj\Y\X^VYaWVcZUWMRLJLGKPVQST=JGPT`GLEJJB<>CB;BIHEKACa@EBDBPNNTX\`W_]^c^^e]^pmja]^_Ya\Vioet x -}uiccagfb_d_^bh{mbe^bablakZZ`U]]WVYWUQPJPHJMJIHKJKAGEbZWarPdnB=?<<;;A,1.*363//-+0&-02+)$&)&'($+,(,(.(,'+%'$" ')&!+" ##+-/  %! "%,/+.595:A=CEEJG@ATAB=B>:9<:<:;895-,.58842299:=:<7HI85:FA=@M>FKICECKbXMXZVZZaXZ__XXkf]\`h^hjdfci}$zvlc|uohf__\_fkce^la`]bmhf^YT[TTPPLNKKJHKGJJBFKJCE@ALDNf-?fRD=;7<697?5212163.71=0*,-)''$&#$(++,&/*0,)-)6#') *%*$$ %/!"0 ,)!!"%*+,3145E?A>JC?CABACG>>:;<96=9;:=U;3+743157:I8;<599@98@>I:EC>FD@@GFft^VVURZU[W^XZZYUi_\_W\aX`ebfsuv:@)2znlm`_`]]Vbd`aZdXjmka^aMZSQNTRcLGJIHHIGKDOJADNB;BKHS dRFC:8;::926?3:3,48F-,1&,+'*!'$$ ))/'/9/5*%*(*$('"'&$&% &2 !  #$#+1,0AE?F>A=:I;DAGD@C@?EC:=@88F87APD48/7>:<@;:?979D;FDEC=GC>LMHNBl`SOTKOPSRRUSS\Z]_ZWa_VZXZ^Yffo -~h}wvvr fUaWXXbdUYWW[TOW`^smYXUNSKINGIFKODGDCCGLMJEHMIJ>DFKD^_QCG>?8:?:@f1>64M>532,)+%*408"&&#$()+P2.),+-')+*$&&!#%('!" $# & $*/2-59:9GFA><@;AGCGI=;FA=<;:;=X4CK9<2358;8576=>6=ID<:@??AB@BGINK[FMDHEJFJIYVPPPk]VWUXYVTVVXX\fc_uncmco|johl`SV[^RZY\VRP`XYXXXU_VSTJIFLPPJEDHFPG@GNFVWJ]NDCB>CADFPGCEC@=B>6BI>=5>A9D>EEA;;69;5?3:-9142/388458=;8;::98>FJ=ABG?EJ_jUCJABMLPKHVS`SQYPXMSZVXWUS^^beXYYW^cnci`\]bXXZTZQPWTgZTVSRNNNUTPPIIIGOJGEMHWFGEDCJcgigRZC@KCDB:8LJAON71.-3/54/)>8;8-3,)-12**13-*'*2,%0&'?T$"%()""!4 # "&&($)$)-/826;C=7;>EEFMB?>C9F@;99==E7=9;<1:07:82678>><@;C=E<:E?<9:=9<96BU<69C0+535'*1*/E-)3*),(*.,,0(*'*%/-%&$&.,%##"("+: # *'''!'*).86@7?>B>E>AAIJB_oA@87298;:41534146;61:83;>>AFGG><@>ECGA;EIPiC?FB;=:96:QI64;6A5390-1B3%(13-.&*3**)#,*--.-+5-%,+24)+':"#!$< 5''#!1$$#$.#+)%C<=>;>M?C=?@?=FC@@@<=:768492545559?9/>==BEJU?9;?=BKSUENKF@BEIC4;8:<588>9@31996K2.60-%))+1.'*1-0,-1-./-1+,((3--21577" 9,1!# '#!( $ !+*)#%(*./<1@<7BC9;G?FEOB@Bc<3:957CCFReXNSEB=C>DG?NhBPI>??>=CCAHDFEJZKLPFKCETm#XaROKFOYUQbZUOYSWNPPMI@CCDFJLFEI\QLC=?FG@><><9@?FEWAG;;_@<:;8;388950332260@5N71,+)./0,*,08,E:2(-50)((,.6)"%11-,'" 3G*"#"$. ) "*7*&#*((=15736;7;787FEFM9<79DN@7569569><6;=<15;EIFL|P::FF@@BJYPOE@J@56<@BNFDCFMNMTMON@Lw#y[GEKFMGJOMQXZQSJHDKGFDDECIEJEELEBCG@>A?B;?99;A?>GDCEA5.8@H=CBCRBD?KB:=BE@:??RL75A?ADDAAIIIFJ_HGJKPcQUFHGIKLLPINNYNODEB?CDG@?AB@ADGGGB@CA@AG?@?@:7;98;HBI;:B;DCI?]TX?8HK@:78BE>789:?:324.39C8?B4.2.+);-$)(.CN@0,.20&'*);5()KK11L092%)$!".281!:#/,$"&!,'+5&.1H=5F7<9?=9A;@BBIIC>8@GU;;;::AEF00:<=>C>97K=?9EM=PIMGB47=@COC=CEJGDFBEXVTQ_JHSNFB<>@=@F@ADC>GJKFKDCAGJB9@787963BA>4^?66337241S7;;1+-)))(3/+/-64120+>./9)-()-'L*,/7,#"1(%0$#%#(  #")'#")%&$"%+,1127J493>979<;B@A;AB>>NEKNMGIUjFK;8@FJDCAGGIAD=>U?OEABE?D?T]h WN?MFBAH@BCDE@D>DBDFCF??B=;9?<9<>9A===TEILcE>B99?778;95;52337T823107@><4()00.2F330/93159:P62@*1()#3F%-##%#%#)"1%'#* # $$7-'/-+*12@6<@@=7=9CJn_n=GA7B95ABBD647<>J?653>47;<>BEHI@IVCI;===BRF>>D?A@Gab}~ZRCBFCA<:BB>=?>>B?5<:>:?H99<@7448?B?;==5BEE;=>E639;6;?5;57243=;2957,+1-1K:,+157X9E33414795E60,*28->84-$ "#"&((&5$+!$1%"$73,..058594;7?9>OkhjC:6A9=>?@>=E=@<8=5;7:9=;=B67;?>?=>@F=6:9KE=>DH;91765455S@93:/.-J4+5.5244@4EB8/ZB9:8;;>?;?>OD5=P=89444228<;:<=KOAB?9?>>J=K??;C@?LJ?B@CGPG>E<9?:==<==:A@Q}wZ>=B@>?88<95:>D<:8430>?96888;<9;548;15HO318M9A-&&2-'*.0362038823I=A;@BA@99<9:SPC8507;??;><46<9?;>@CED@8?B<>94D?=>BQL@TB@@GKAA>@D;86H=78>?>D\[HG77>9@J:>;:=E:N89<=;C@>KABC=??::?=17666:9<6>9<:;815;4=C63>?:C=@=866:;<C:@=HNDE?XL?7:<8CMZK>IUVD@>bAC<68AAB???7B?@;E=:8:>>@9:??C<7>BMCAA@?G>=<:?GC;7565839??C:92;A37/87THAO:M6KBG=FE=?<>?H@ArJP79B>FW[==Q:8@99;E>=>CC@EB@>U@C?=:689A>;;AAB8B>EBLDB9F?LHG>C=C8=J:47<.98>;C4;F:548<:71XA?>G;; qC;<83OI6hc8=942-3308-.429@612_*)-2-,.-*+"41)$(">?//2F#,$6& ! 2#%" #%(&',).1*237-.>bYBAB:>;:9;B7:@8>B<28=O>A:C97DJGEL<;67;9B=;DA@NJ9>FB>=4:O@?E9C9=6858>P?9>KC9<:762-=M7/66]UI>5973:D.<=@00/+.-+/7;/0.4./.-8*/1..3:23(+'"#"#++.';7')!.' &# <$%!!#+ %.0.;/=2/0<:<5?@=<9;=A6?:5<:7aC91><DDE>B<8HC?KB?KA:D]EF;MHTEC9PMJ>97@A>7798?:9:E:<C?>?8=>@@HDH>:?A<;::<D^ZFFA<98=87:9AA@W?=:?7=2N9-JZ3275NF;A66:368+10461:+131,>@3/.0..0)*/-23.3<8;#&'3&$(.*%*4.*A1" # '$'$$5)1161.&0>2-1/*+18>98A`C;:9419;D7A<::K=<99955>A>O>@HABPNKNF=ROE@:<7>CE??7<:=9AB8699<>986AB?9@=C?L@F;JG>98;9;D9A>=9:FJGHLI;9;?;;KhV[eK@7;8@6567785/4-,.0:219>872-.24@853=7308/2/0(-1+//-61-/>,+?(*-"#&.8)4+&90%% -*!0*(%')G;6/*60.+.33/>3>>7>=>H;5A60@;<98;;_HNVPDBDPDGS?5@:A=98:5<8==E;7>=969;D<;N;=BDGE@A??@;@?>CMXN=DD:;5@E>C?A6>>>=?M[BJ6::?BUNNZb^HB9@38<;72080/3-'./36)041<0,*=31+67.>77+5-**.->:02/+=.*34,0)' (+)8+)(:,"-!$,>&@0$(+/7L;315+.13-05155:;;:CEV?8DBL9AADE8F:ALqdTU;:86;=;IYNSRDA=KEBEC4::E<@8J1463:::554<8C;8:@=987=ESVjTB;;;>;ACALgf?=F96/53252/.251.1021.//>+591?24-.+-././/*+5/,*(-31(1(%%5-')$$8FS)&')-,!%$ %!%'))'.3*-?8.16/.738>A=>AF>:<IFOA56>Nrh?>?:5D@GP_k`G<6968;>?598\F6:>P<;?:@C6647?1=488@>?>C?97=?:997:6CEAB?>=;=8=?97;D@@9@CG?_YQC8:854.27+/-387,60695+/2,-.*01=0-+8.'1).,)-*,&&&'7),.))&'&&+"*/)5-%$+!+#!) ##% %.,',!-+;+2529/-23676B9Q=TI\DJA>_n[<36CdkRD:5;BA@>HLY)!ZRN?979FJ;9C7A?<7;;<9EG<6C?=<7:>TNS]H6ETB=C611?;8;4?7535:8:8816=>?5<@@>=:>:77FJ=898/57:76::8DGIMK@?A6K:=7<68417;<:/:63497;732:=:7465DN3?:8>FR@V}C?F6?99;:83==XWOLCDB=73@3>.,.-0/*.823*'')56-)+*,.3%%'('(,&&-++-@38JmfD;90YI0)+*'#!'4)"#&2:3*%$%$,2$*-/(./)5-.3-:/==A@9F2>?@GCI?==?<228;=B8:?QZfo8TCk_LB9?=659241;>;?9;?3BFJ5I94N<>5569><79::;7<>C4366308;989943666>CAA\#E=>:IH7BM50:DSsJ;83C8,0.,,2;:/,(.61*&'8E94,+020*+((("()05*8/*-:DIi;C-jVP23>/('>)-&'&#%#   2C025'*" %')-57771,.80..11K==7?GQ6;BHRA=<;6@8=8;=3<=GX -uF:@yUKl9A;045-,0@DS>:964=}H8A2594247:M579759849>B9:<95667:38;;89425:@F<<[hN@>@:46;8@9UqA922824-,0-1-/34-',4.)0;482*22-(-.-,)$+-6.--;523;FwK[^U;DC21.) !(()@0$*"$+$H,&&*(&*)$&%-G2B?03655/4689<2=;8@;@=ICA469FaUG>ABNBHHXCM<9;@9308969;338:6?;B8@KO>D<>>?KH:76-748:21821/,**762+/L3:(1.,/.:265)./D3*&)*0'%&%*()*.3*/+J LTD4i]2=40%%)&,#0*)!#%+"&&:*'CR6%)++)/.04313A1588>;9;=D<7CO=9ECBeD=CSI`KpTUOHJ53239;88371<6<55A9==DoI2552635564358378C758::4??<;;79621784814:/,*+6-/3*)+15;51-.-3/)@62@.;3)&(&,,+)'G)#(/7;)%)O_9I2328/@=+4A$1?$*$'4")".(,3+!#,,*)&*A.,*?037684E:69DC:64846G=823652<9>?16HEE;:9350/685=4865:68/6;<68@A32A653=471240./+3<4202-240I3,2.((.4.(.74'6&"&'6*,3),'(148..(5(--743.,31(&;,12?+#&)($ !"!)103K-!#.(,&/8>.-+0-/27;9c61;NB>\D7LP;==:66:C974a<@:>@734697D<4486552097?:4678<756:P75CE;;5D1,675A.8@2454/6018,48717.,.,(/--,01+'&&,&&(()'$))(*.,277;0!653020/07.5-'*+//6D$"#&G,B2 !"%& $>65++(.;7/474>163I;;?<7;MR?FA<<?06;?581313963266566746;]<52797:97>C=D79~_>=:5:@CB94.14<-))@02;BA0C..56E/-32+&&0)2+&)$'/')/0+,)(3Q)23D,'/8:XSW9LX.**)0'!"!2$#-'++!-$%&$#,4)%,,+(5/2;54053?D8_;B;=>M@ARTFcy-9MaiwREINaR169:579CL56`>;0,44B:Py;BB>>E6;45=5/3<<59542/5526=?HGD542?15736:<49D6M7;MQ:6:684X7>=51.-/1)4%)./.0/*.;3:4/579+&)*.2$-$2H-(075.68'(,8*' (+,EbM::6B-/)+('   #(##"&"!$%*%&.1A&'',2234@9L/;;5869BD@?E=<9;;Ab ]dYynRUc\R\NL?9:<658;258;bC77-48<@%W6>U=2/5:B<9<;8=9577;7:5578=R]D505?>604<57:9;O597:C-:4;;64UB\O403)12.92+2//+5.-85,.H6=7/+3.";1*(*)155KA5R31+&!+%.(181+,13A1'&+9' &6 )#0-$$,)#&')I,)($*!&0,*12057599389=>C96I9<58?>8DLPOQVUKYXSMXT3=:3<8@jTS8?;BA:?725>\=6996EF555=C<:CH]O<-'3/0/2,01'$''+*,)1K=VUD5+46Q1'$#84++")J++-$)!(P"$"!)&(.'%&$('"$$$("%),(6?J8.252=8620:@9@<8D4FF>=G?dIHJZUQYtYP_?FP8;9J;730L1035;4@/ABJ769ZGA=5032969=8/7E475,%)88<4?-74.-.0130*,,-(13c-1;5/28:16:726*2'$*/,,6;ZLPeF7.=>.,H*:*()*"#K!,<**$ -:$"&#%; .($#*%$*/$%*%$+*39.3-.46.4+9@24;B?85C??>=CTG;>CBGMTsmTMK;437=AB7,81,.=?3;57:>:D79;OG05?95696=MDA;977<588@=444727.1/047;i35:34470701/72112,,52>:22/-2.39J\kD;3/7*%')$'&1./:Z:?rUWRg%&+1+M,*LB><%(-.%#!'!#(!#"!+$(+%"%&%*8&++,1,+33.350/094/0:693;289?AG]ESE@?E@E[\J226494@]55;5532;42263332<>@7<7<<<5:13>>88?SOVUPl;F>>733<;28570:41516A?Q54?11;80O.-+52-/13.5>?GA0+2@@GK.eKA41+0'+)#+A11Q Q92OA:;/<0-+0*=+68+.,)$S ,! 8#"-7.-14%$#" #$"'2(*+-()',0.2,622:7..4124831;;BGY^O@JL9BNLN`VL<07:;9BF8F-12;968747207765959;59644:C9<99FSPbl_JCCA<642066524/30*1206A8P//42.0.+),)-F,&:6658<9S;.*,=jvD&^S:,1(-;5'&#;3C9D<0)2+4)(-()'A*4'+.2;25!! 0"  #"&( #97,5-%!$$*,.5,&,1-2.1)-.//74.123/3:3:9:BVKHWGOF:;8BD^AZ=352:68M<=40.<35?C;42538415/9HD703:FjD?A@?CZzwpLLA6765303O2763242:73>249685:-86/),3,+-3.1;,8:;=.(-QKzskfYG>*-#'8$%>./1:E;:)-31*%+&"+-8%,O.><:0' ""'!+$>$+ $(?, #$$)I*(6-+*.-($&+,3>C,13409,1:;37I;HklGJK:88BG5F8079<7306:/6=67584?24?:Oc;vkLA4774628,481475>;A7511A=C3611.(.8)*31())6:Ug418.+>@LOOW]J>') "%$ &*)5.bP*E'1*)(%#D0'$?7I,/J/5%  2/"K%4!*!%'''#*A%,1+(052'*(*,-/a6114.8026934C6=IXOoGEB6.#)-::5500526:7F;2BA/3A47=>T=>5555>?1;=?6548@_<261H8;352:)20/1*(2DH,D3'/-9M_aRI@9-&"%%.)+''(%1^),F/1"$)&9*%<"5=#20*$$$!""%3-#*&#!"###&%(%+(-,E8,+*-//344+,6/C/,436-19:XEUIMOI::'$.092/5)/3;18:8903532:0878?;78;?5OA<5L=3:-B*3D=./,./-:,@>++3-+/*--C>J=261*)&&$ * #(" '&%/#%. #('%&(("%0%*$#& &*'!.#/38!!!" $ )(.&',(%5,**-/3(61:/,27/01340C5:LT@7?25489855=96;967755=B;66IMKMPh94.\BG6<9;11.45A:2/=4.823092/=-/101-52285<3900;33724,04/0,26*%$+%$ '!!1&'.$""'%*&(&++'D/&/)&" $2!&#=F89!,  '"%! , )M*'(&)+.+00*,).+3.54*?0773669A4954:=786A97.=,<5C336840)../1+*+,)()$+%$$&,!8!!(""& (%,!%>7%+.3("# $$B3" 8#!,'#*"-"#% )%$ $8+)&(0:B+04+4/514.2//59;12356;=BM=7D>@7F7DNL7-/..44/,-520*89@49EU<<1886643D51<@B>63040624,*B0G/*2/*.->OO>:H984275D636,0128@G?1-/1462,194921,n?\abc:4-02.-++3-)*%$*))'(($"*&5!& &  ((#$&,"! &$% ! 5G[5+(!!!", #).1'0.(2+.-(.2K@-*+)51621<8HM>9;>6>AE867?Zx?845667,9/2T732-7-40694>I<8>77554GKg0-3;>>E75;]@>>81Jz89P=C9CA75261**8BO?00314.,+,329K646:5~eF32<9=C2789DNUM@?;C310481713454/5/2;92/0344>H.4+19BV 3Y810%(2,(/0-4.:5#V*"#""$ '-"$"'$ !08'*$(*''!'#$'%"')3/)$##%+)&07-!#'V84*+'")07*&8,'9 """[e)'$,#+.:]/+5*A7,**(8,1..3,.-"-.6,=G86EFcc18AOG5528-.)<8+&T<3041+**.++,27?80;I=<-5+0F9:92>7604+-'*/M0.ZkJ45j9--)+%%2<%//!+'!0')!F%)&B3MeVd?9.)+ ))BET*#""",.ei--?*7?5),33.(-1-0--'/83-4.-3;5<@5NqO9-/&0+/0+1+-5/E3*02-+-.+6<236>vggF43006,56,4199//821/127/3368<7:;68C=;3768<56F-124A2',,B8Z311*-6);!&$#'D5'hZW52F8'0$#,5a(!#(!5! !, '(!+".*?1%%0.B%_01  $?5eE$ %*$"$2110^,0<0,4;rM7+,40/.&(59/7@*8;=/:,?7,543%(*3:6(2-+*-#).9*,(.13-556JmaKSC50,,;6153,..**-3*14.4,04176845@88668;2755?3.-5=2.)45/*.(--%#*A&)81()&4&.>N?BS,*%)&(%#"'3- +! ,!%31.<$&=bc>\[S-)" !%/.V*!!#,+"&!+,+D-'8>I>O48068+-+"&16*-42CG)+=-(5+#)(04,--)!**).$$)(+4('6/@199.AUeNGK>,*(*2-&*,*-3/4.,/-./-0./646/726L5>/V33431/*0;;,8'4*,3/$"',!&,5%'%'%%+ %&3<-%D-$"&$!""1&#*! ((263:@7ICWHnlq-H)!$ %%'"#".*"%%**()9-8Hop_M8($((%'&%%+,)-(*&6+=D+3:.+,((,*/))+$((%$-&%--3+,)%)(2:?IGIA*-)'*(+0,02*+/0+*-6:0-1.--2/324671>874445-H207510?01-%&;#$08$&%*%$$%$ ! M,3+/J$%!!7,(C*K(#9(()IQMKht*5( 83%%72!,I%Y4)%+-8@<./6?gi`GW9A-4.&/)%+)))+./,/4-+*(%23)+!"-'-/.*$%'/(%+*R&1**+1>A*029.0(,&$(4$(E.0.00*1')',1-0/O1545CB:2:."& -M1%$5<>?A,7D&&&'D)'3+%%#*,&(# '*6C,&#&$%%!$%'),+,(+)2,150;+-3$'"/(#-+>TN1,,%.I)).13B1163003592=9M>B>3?71>?>/(+./##&+%0 +6")"&'(.H'A"-"56Nd.%63C &A!'#4/CV`K35M/*>'%$$!;!&#%$+R6+ )OvG:xyV vU:1A+G*#$+&(,(##$%#"*%$$##'),*$%&+,I1)-$(%!(!#" '#()+&&($!#+%(&($"#.%+"%4_'0F.20..1/3\33bER18K9JHD?C45=294#'('$%+*'((*&5"2#)(#4 4E"")"''$#P(-XK9+E87>5IL"' "([Q'&%%)G]C:EAZbEM,:-C)("&$&!#)%% "$(.'&!'$&("'$$"&22&'**&"! ! ! ./2% &)/#!#&%2!%%,% %&$7*-;4-'0/7=0?54((&-"" !! !"&#%&V-(5#2! $$2+V 0-*38 !#G""2Z*'#),.- ,$%(M; -%#$$#/SH=<33!5gG4,+!*!%"$*%#/%( $+##$ #"%# ")(')9Q&'/*$&!$!!$*%5'$" !$'%#$( &($%%$!)0?;,';5:?2;]YdY]?71&.8..;2.-6*')"""+)*) #!$!9/$"1)*1 # :;8')/'$*;%3-%",%:c=)/"%*WOM3/4q#V7( %$,(!)#&!)+"'*&)$%!#'#"""'%5#=o!$(("$") $"!!%"!!!+!&-+.($%#)"#$223iG003?F=88f N^VF/.,(7-)( (.'(,"'')+#' $$..G/)7F&"" +#,+"#&B)*!2+P;7)2(F8VFA/52:4-/%"'6*'0%!%)%++$#,( $"# %#)#&$)2' "(-&#""?5/$ )$!> %#+  -! &!2:-&""%]Z9)0',c"0 -K*-&!5%"##C-"7",2/+0&*!#!##'&!!$"#" !%-#'#$#"%(*%397D7,IWbF9-+ )?9C#!4,!# , $ "(/$# (+& .uf=&%&$,)G'=EG',&+ ")$"$'!!#)-A404*#'!'& #"#"&131##" $'!$  " +"!!* 3#'&%)-21ZH("+""$#7#?!#E& -+E 4J3*"'"#;.-,# )$&#!7#!!#*^1#X#!$&"!(#!!.1D1,' %&"%## "#!&#$ ( ( ,(,&'$!=+)W$7%*$")% 1, " %',C,9!"$$7,/-*$ "$ !$%&%'&:4()M(" !"%(!"$!!#*$"#$ $(% !%#)$"! ! "!%@$%$$""% )&$ 2 +% !!"# $"  !! ""$ , "#%&4(*'$-0''-1)%'>_-(+.-ARGNpZ<;G3?j:)/,.)0-/+)'2&">F'+)&(&*,'$3+*+)2%,-,++((.7,,110.-02490312J/253.0/808/8>38+1*)" %+J89-AYEA0*(.-,/('',+,(%&&%)*);>'%+,+(+(1,+-.('.,,7=301100524455>3066544;?29,,3<61*./.250#$5,,0+L?;EGA:FB@DH==@723014019-&(46B/36:457I]PEMJM?9Y?M49,.),*)F$#&)'.-$$# ('79 !"1%#3###)"7"!"  +9'*-%*('-*,;-3+1(&/&2#&#%-(-+.52/0>7?S01)')%$&&&)+*,$&&+15))(&*)''((%%(',%&,,),?@237/52,-,.+//427A:;>D8<>786;;7B52-2C487,$9?A?3878IEM_QMAGF;>06>@2,+*, %+(!"1*+.  # 4 -&#%%+ +'!(( "$ $#!%#*'):1"+(&'&!-.,7<.,/%# "+5*-)/*3/)+042;@0*+.)&%(*'+.-/0&2/$"%-G(&(%$%%''((&)+01F455212:/2-)+-/362159U=Z<:9>HC<3AHUN6../+/%-*%(*$&#$" !A"&!!( "$#$ # /$5))&+(A>==IE5/32HVJCN<1/=5009OFAONLYGJDHMYeKG@8/+*1'(/)$&'$"""%&"' -#9 0:M "!. $% #: ") #'?.4=0,P*(&--(,>&))-&/>dx,,(&#%&)+4)+,06,))*,2>FA_51/*)&(+%$*))'"*%3+=#&()($$&*')++)),-+0./+-*,./9134=814513,24F>SG=@9<9=A>A2:n==Fe=++8/7H?BBGKYr>I;ebCB=FK/-3,,-/"$$!!%,+& " ! , ;&+'&!%)0$! ()$=A%*/:1(&'')/7)5C.>/',476('&.*/*(-,/-+;.&(,'(-3PN;/,&&&(6('&)D,#%%)(*)#"&%(&&((**(+),,+'+,/-/--+=,.62519=A7-/4<@M6;75IK8L@D?8+(3]VHHE|zJTJC',5,,+(#""+,?bh?+-3*'%'/(%)-4*+-&'$%##$'5$&*)(#)*))(+,++*+3/3/.1*+2249::53-2CQ@QC?PF=K@?57479jGD:;8?64ED>DEFOJD=bISSRQ>A?<-,5@50'&&)(%8 !!"!" ) '"!,0%J.0$ ,   "! +)#%"*5H#$%:-1+.'+,**<+.03**E64').+,)'&$*,.',..,))'"+7-4i:',*%+."6?)).6-0)%'0+&%%))'(&%(+,'&'',')***-0Yb1It3,-277644/788=7>=KJGFF\_R[A754.33.32('(:9<-!"!"$  !,%*+# 9 !%"!"%!"$('=I1@N3,4L;8%..()4O($&('.'(&,=2-+%#%#()6+)+**)()##"')(%>R&#"#%&)--).)/5(($*'))'%%&$%)('%&('*',*'+,103555?20-74636328598>=?@I>A:BC?34?`7bmBzC665567//11/=?><>:=FDFj532ADF8;945::9700LZQTj|VRHE?70782/2,21/*+1/'$&#%"!# " !!"$!"'@"!# (!#. !!## "#9'3)./-,.132-%.H0/*4+'&#$!"%"!"!,-*((,(%++/)*&8&%"E&#$%>&&%$$%%%#*$%'+),)*)238(4,&*)*.-,++,).,,.6.5-010+''()010)-A^57798345.03;@A9?LA;EB>:767]LRE9;36;<59).GGPSJHRG:7487--,1<-*),*995&#%##$ %!!"" ! #&!, %%!"' . -"&D7%" %(%/"$+'+3.<93>2@,/.-+-)(.*/$"&,-"# $'%'"$('$#')$&&''')%$$%/#$'%'(*(')P'0)'=,*$$%%.k3(*-)-*/A+-5+++/16113.--:-..-043..,15102751681.335<8J;AE==H<988:8>;?:446883*#DLIdIKIQ;=@8>4,,81+*81)((4-((#%'$%8$)$"%""*37"(  =6 $#"#H#$!!'##%#)'&+:/272'$*MW6560+)+-&!()+-&%'+)%!"('%((('+(#$'&"%*-&&-%$&%%'&,/'$*'*$#(&,+..,(,.+,-23.,'.0..262255/-.,/32/,1.-=3232549440.410=FLA@;=:F?@9<56G:]E5655767-)-CKEROKNJBIE7H5<-*(+*)-,6*)&%&$'&'"%-"#!!! $#5'$'%))w .'\'%$#$! *#"$((0',+7?;.-.(BwQ-.D+)*!)$%/)(&(++5%!%('(&[('#%'%&$$$'),,,(%"(&'&($('''%$&*,01,/.**),1+*+3+/1,-1.,4+24554.07<<72319211+7<@7:546.16:K:?Q>78?A=;89I8?=558777822.7\hsXSPNHCB;20543323--:)('"&%%%$""!" "#()  **! !# &!##&"(,&# $!#%'#" "%/-(&/1-2,K;-SOE'#*.%&)0'*'(*&(*)'+"&#'&%%'&%#"&(#%%$$ #'%%$'&')%('()(&'('&7-)),+*))*11/+.1.1:4//,0/11>:?6764--+-88DLMRLhKAQ867571.0,1>*'*'.-$%#-=+%(" "&$'&$# 6 2!l!" &7/$"!! ')!$6$&##'%b1$$!#%>5UPQ6#&#&5/%)(('+),**&&$(&!%&$&*2'()&)+%-(*+)(*'&()))*$(''&)))->2.*4383/03/9775613C.334041,00796B9?E:>;A437325104<35;:79<8C48><8=I:7:6588741()/;KLcTHLIEDT3:>5470.++%,/*(-3)'&-",%*# #" %')()%$"#. *+# &%+# %!$ *##!$%!# "/#""$$&%$%)!(007.#,3*)+(%.'.-1+/.,'##%&'(&+)&(,,($(,,&*,,)(),,+-**(',)*())+20,,*/*,0./03801/57:308;2.1+,25K79;N=20799454445434J88B?88:<846;=7@DF==A=;?:788;@;314.38KA=G`JWA93;99540*+(',*++/<5/).''&#-%(*:!#;&#$%( *%&$# "-*(**/-*)+D-*,*228*(,/,+*)&,)*,--+,-0/++,3/.,.*11-.29443?7012,162,25:WH9114308864<537676116<<;::4<3:899=AD>?:;;;:=:9AB85347:5C.*+1+&)30/1/4:<5<44314211>?=;>40207<9=JK<=<;;=>>?C:;>;:;::5@XWKbI:-,1(+--),)))29>,) %!)$'###'#",* $$5 #$"XV5 %=%-&!&! "!" ! $#$%!&&%($$%.762I^667*$)..(+)74?.+%%$(&)),**/.*,.7,---3;8+.++.391012.46-+25/+1/-1//0.D.-7406=DK5806140.12;:;D6664E30434K882=>42323ES:851..6775=?DB<:97:97>@:===:8>=ED@EEBMB;DBV=I3020-1..+*8-'2+0,%!###" #$KF*C/*#$+ ($CA4!"B%&B$!"&"#&#*%%"$%(')'$+35VsC5.0*<2&'-.+6,2**&(%,71*(*.4>20-04/+.1/1211=353B94@;4<:4/033..-.+414?9494/?MK510-700-/12175701<:9/2=4@;?426683312886590223399CDBG996;;;C=>?@D?48=HQ;<@>CRF=DHHC35550/),*,-&3l5+-'"%('% !%%*$ #'+& $-! ; 3%,"2^$(! %)" "!%"!1%##$$$*"$&()1-10;cLNW789,403/,.+-+'*))(0010-+,//4@0.-8695C/.2371>:<7=<;@06:<658:4=/./0-.002676F97@1113*,,1,,01:/324B9=G578<66843=:86338575A?=@AG<9@<>@9>;IA998>RCCE=A@ET^TJIA41/41/.+(,)(6a@(("($*##! !,&$.$#("#!4$ #$!"$  $ 4 /.)  ##!% )""("#&)/$%$$(& !/-4:_*JJ./3/6314./))*0;-,1,/,211.*,+/00==:554225085:96S7583048510.600..02..0/14//-8<60UC:20,.-1+0/34<654A<6;DWK;7?67=<67\>66642288B@;:;?D9/.)/('ML3;####$'"$"% ."!#"#"%&%"2#  %#*(:!""" ""#!"$"##/C+%!$&%7*FW=9HKKH122.,,7<=41,-/82+*.)*634306330221650987602764JG329601212-1.b723530.0C.0,-5*,179910C829:6A52375-4469A=?C@?<>;48AA@>:88323H9;IbyceN91/32.1'+***&$%$'$%'$$&%#%$%%!!'!%'"8,-*. $+"$  !"($#$ % $.*$#"$&-?580WD9:42,-1)*07?SC?11-,2++*&/412..0,.6<455O8986564;27;30354/P2201281657;1422010--+*/3KJ63,,..)0+,.04>;&&+/58A?;>:3/734379..0L4-.2@=JBQLH;A:8<><:=99A?K3740$':;FOVrKJJ<8B30.+****$'($'/'& %## !%" &!!"((*#'%/,1!!! &$ ("!"#$ # "$$"#!*'2*5:IC53BA2*,.5@32/1410.7%*+-,)(473.021;8;=?4;=76;6:;22376632347;=9634364>768333/31/.,,32B6:b3*.>+,--26325A(*.34H7=<8><8958=<<;7=DAA<;0+(()7[k -YPACA623.;/*'&%#&&%*'%&'# $%%'# ""$&($/B%&! $&$  (*! #1 -'&1&'%"! !$#&((&%-7)1-=E08@747Q984677599::<:5067957;948640496314420023/255:941334./0:G176:?L56/4<6/557?X43/F=P7)*1502J.3[>><>?<=;>8899?<:>E^FU5(&)')Wx_saM@6C3.///'2''&,"$*'*"*&'&&$#$""$&-,)M3$!"%  +(!'#$3-9#!$#( 5"!#(+# -&&0($&&#',%)2=~P4042U;:P33521333010547277<=9NA;@=86:=9969<86@?:A<::;:89:;=<747552/L17132171272;A:P>342340-0/13925,48=466516>9;032VA2+(/34302,0D@>=<>;>=:<9:@>@AACE>4.'J5(:IINLEEI29/,051*)%'")1##&&0&&*'%$$!#$(! "#$0':*/($* !!!''!(D6""$$#)#"",+'""  #%.'"$)'"&$'29:@V5446=5F40:?/.10/:2258<=;>?:?@A9:779:=F<9=:686450.32002546573>@G3?4465>.213//2704>+.281G18871769?<0-.2342610@?;;;9K?;:?9?.0.'',(F(&('()##$+*&'&&%###""-Ll2%$ "###!!$! $$+) ""#?!$93((&'2!$&!"!$$&,"*&%'-,)0;5479>1/8539C:,.362:738?@<;<>@A8>Q;@::??I;;;;>GHCJJ?<@DJ8IA;B?9543211005146163/84LPD=46?A>?51124E1(,00,/7D9.0/:36;5667F<434056-38;=;:>9?D;??B;Am*!)"" (!,&5#8#( ## "!%3:1..("" %'$,$)'('$&&()'+++,00AVR5?74722.6385;E68<;Yi?;<4=9>@44.55SI:05408D24-9-04435349=787899B30B9;;7;@;?6E?\D=?B>9;10(#+/>BNPKS=82670*..+.-+)%)&/*+$&&!"*)%&Lg%'&$&(;'! 3(>7!"$ !!!#/6;''A#$%%!! #);!"1!'()),0-5/9???@L@`JBECLIFIDLILCNHNPB;<=??9?;>9:;7777788912006?;;755;;=36277EMy56546965119590361586636=SE?5194<9:<=<;87=?B>=A<>841)%,11=BHJHH<;3341.3//',)(($,+#&%#%&$$")&+.+$&!)(" " 1!(.0"*&%% "" #%7o?)(!$"%%(3#%$"$%+!#',277M5\EK>29736668:BB:8:@99>:;@>DC?DQGAMHdXHFOAIBHMIILK?AB@BJGC=ADDA>:;;;9;8979>9><5743<@UG>==8;:854>?>A659144G3:1975>7FD>Sd<;?:?EJ618<3;?6;=7==8=C???A>939/*031LF>KNI<48705-4**4)'')-(&&"### %&'9*u=" !,0###)"!"',(% !!!"!//)/$*'-$"*%$"!# ##,+13/8:=IDA86<>8=>@E@EDELCLzO=<@K::8AHLED@AA>:<;??<@969;>?E<@;742423559377?=<9X?N;889A945BB;=96@>IGP@DBCD??9754")11.1>@D?:5645.+,7.1+*&''&+%  ##-/.8&" $,+# B##(5!!"$$ #J+2'('$$%:=''*%"$'($&)+:703:>EF;ZWH@8:A<:<854<<>=<>A?B=A@@?CAB?>ACDBG><:=@B6849432<;6:;88=IG<<@L852/>D>=::8:CFC@K@AC=@:79>"/;716A=:>987:/,120/;&&(0&&%#$"##%$$)7N($)!"" (!#(' >&&(3#&!  $2!!)'&+M('&+$"#&'&#/7:S224=:J>ES>=37:>:CD799:?=>KJH=;;?NE>ETDIAHGHCINOKMWNKEHFKG64BSZ=?INTQKIICMKLF@B>FEG?C?@DCABAFGMFJBF@H@@I;5KA:DIE>C8;;;@5==<;<9;99>B6234?>>6>>A@?B;=B?>>D@AB>>KB@N=>=6./0./(,-+#*#&%%$!""$#"'((($$"" " &' !3$!%$%###)(" !%" $ $,&;:+(334<=;A=<@AOZ9479<;A:=?A9@9/17E?79B<=@A789=89;68;97773;=NB=GCB798????KCCJo?;F=/%&18@VDDB>=83:;FC@>=CAC99:=<9@::=D=7:2D8DD<73:579;=>EACGDCCH:@,)1=8@FIHMA<2*-.0074[5&1('&"&+'"#$$#%5*%&&#")"0/!!  *'$'" "*!'#%!#&"""*'"$/.%$*91)/.,-+3;@48/214;?KH<6:J>?I]F@P>JAEMADGQEV4%kgy qf|urWPW_b^YLXaaeUUUMJhhlZLc`no]WTX__[WPKONXPMP[RLKILIKCEPB=11=B@FDCA;:6;B469<>=BBCB=>?>4'6F=?B?GBJH;-0;73./3,*#()%'&$+# #"!!$''&!)%!"$&$ !"% '*!#$,;(&"+$$&" )(+2.$&-2*+*,06).6S54024/,-.0/346==SpECNBAEBDBCDFQZ `eZa6vYd~cb`MMXLNQ`Ob|fwa[UDI[_{aUWWofcocj{a[XXT^TRPQTVUXVRKKLIGLG70.;DIPMHIAj_E:32<:@AZFCAB=<7@<>??0+/6CHC=>7;:65<9>HBEI>DF?/*1A<9AAGFJJ7D9=98/,)**,&&(%%($$$&"'#"')*$= """)! <%#$'$#1#&#""#/) ##*!&*$+'6+*+6'-11.--+/1*.097::85.522:>;??=9=B@>C>BED@GTP`\ac\WaunZ_xfX[VRLYWQPHRTSZVLRVc\bvoj[Xc\fgfndd`oeTZbcbfYTUTQNKKKQNK<:>AEKLLFMMOD?A9IY3@POFBGD?9469>?ACJGGAA1()1/K?A@EAD4<754.-+)+**%')(###$$%/"'%& %#"#%(($!&$",0H" )("%#"!%$(#$,.'+'$%./@E3-2.-,/7246515468D5:Q=597=@?>9GA@8GFIDREFM__uin\__bUYUNISCIIPHKSOTi`db^pqsa[Sd][_a_bzr`fXJKU\XYSXWNMLOUTPMH@FFHHIIN`WOT8=:D;=HLQJEEC:;@C@H<5364AADH?><;:;=@DLEHFBFAA>@./2:=DC>>98:9>;3/.-,*-,%"&&&$'('#%#,$!##!""""&$!#*!!';S# %(13628$#*%" #"$"/*+(+)'&(/*()2,0.45;50@94589?K?>;;A746;5BOW>?CDLJGFFIGWQoqSNTT[`XUNJQINLNRPRJ[[m[^heZY]ie[[\c^Z`e^l]_mhXUQPWTVTSTPYTV[WZTNNCDJKRTQO^MJJHiA;@GIECA7ADBEA;;4EI2:QEAGD<9=<8@@FEDCFKFCBd&(1768;HA<:99@885?011,0%#,(#$%%%((&'(&"!3 "#&$#$($"##"'2245ihJ('(%#38I#)=*).%*3$,0.322:9J;23958A:D946:>49923324>B?EIE27F3/?>BEEDDD<@6+('%%6=BD>;9>5;7<7F9-3'(*!& #$$)+/''*(#!!!!" #%4'#1&#!$*! ,C0(3X@%#% #'/V$(/1)1.7&0-,=-11?8GF?8;?634330.3-*EDJ[IGNFcTDTIJRZW\^dQVOMTZ\ZWLOVQTPVZTRaYUS]aea_fe`W][^c`Rjc_a[VUUSPXfTWW`W]Z^WSYNUQTT^wSSSQUIEKNLJJIC<>DADNHC@736:ARVNp>::5<@8;;8>8867_:2)$&#$%%&$&$)7+*&(#"!$!#$#%3 ##",%('#L7/;6'$&&%"'""<(-),4-2-3/+/1>2K6257IK8:;;EHGA;8:763663;7-66<55FRGS]SNKINPKOROU_VUSTVINVnNLIPQ\LOTSXW]\]`dcxld_^\_a\`eba]`]VYURSSSXUWQTVnbWWNPQSURU]]QVORR[RHIJKHGIB?BCBDBAL86681.)''$#%5#$ )%,&%$#")##"#$' " $#%C+%!&B7*$.)$""#&.=),%'-*-.*,2/.207D=26EDF>846IOO;<=86425@O9>5388>BB@JJ_jPJ@HPUKJ_KOSTPWNKIKMPPP@DOTKT[j_]V\YY\c^fma^`g]abjxeaba^WVYb]RORYRRSWUWXVUYUUYZUTQLPPURJKGFHKILJAFCBDB<<;:;9ECOCEAD@;8?A@DEFIBFCLH<+0&9@@C><=>D<9784391-'(%$#+(+%9%$$"#""#$# #&"#$ !!"%$!%(!(&,-*%&'%%),-(./)/***(%++9AF;8??:8;57683145>?76,/3AH4A@EG?BFE@ESTKWPQMBLMEWRUURTOPKGJMNJON><8:<<GH9>><;68677:9T/*.,$$'&&)''*)2!(##$-4<."")" $&!%% $)))+")6)&*/*)-4()(''*028<@8:26786658474B;9513254608:AU??CCCBDKWGHMVQCBAFOHLFfMIKVFHKHDHDBIQSPa]Z[\TSWXa][^^\\]Y]]bfimcttmga^^ZZTVQQOUSTSYXYVQVX[WSYTUWSRPIRLKIFGH@EFB@CIFEBA=?979=FB@6339CMEICGD=G?76>7%HQTCCFQsYTTWBKIKNKRLATFF=HDEIIA;B>ERY\][\ZSPZc]n[]cbbg`Z^d_bhijdpkklde\WY[_STSWVW]WUORQUaZXWZZTSROMNNJFFHGA@BA@JYGECDA:35>?N8;<57>DF@FCDCNFA93?%5?<=<6625./)'*'&'*+!%!$$&,)! %/"""(&&$#%#"(.)=#!%#B''))&+%(;'&**+,052<4:8CPUC?=H?;;=;<8>6<7065419ABTNEIIUI?BAEShURPXTSISLPXQDME;6:@=AJB@=DKU^[WX[]\X^^XZZ^ixmgcm[\]acebklmtmhg`acbaZZPSUUUXWWRRUV][WU_TURSMTNLLPKHBCA?BBDCDGFLV855D;<86348441+;=9=:>;<:<3155*)(,&)&)&%#'%(+)$0-&!&$%$"%"'(# "&$(&&%"$&%8)'(:**##('$(.0.651:BGWpOA48;?G;@=8946<8.218>B:PHKMEOXIJCGGHMMK@IS`TW`ZJEIIA8269>AA>CIJMNWVYWZ]a[ZZ[V^^bhdedee][Y\checmfkfhlkjljc]\X\[VVWWSVYYZ[^ZWTTVWRRSPOQMKGEGEKIDGGDGCGA66<=:710*7=EFHFKIFE@8-,1<51>?;GS<:8832:))'6+*%##'# $$#"!%&# "$((*),EFJIGAKLQ]^aqLEHVH>:7>>85Q[CF9E;GSF>796578431+00/5>VGDSE@DH]YHNNODFUENNGV[PHIKHFAISKMIFMRGEFCEA9>;1+)19>CCBJUGC@@EM=7/*,/+3*-,(# +#%%%)92$!#("$"#-/-%&'H !&#"+$#$1#)()+%" " *1--/0225<=:>A@[J?M=@;97?8>964.1.35GC@=@=@DBGFAD>NLGDA@3;;^_QJNPHEHGE@HKKQUXRXSUXYVT[Wsusf`_]_bigc]Z_`cpsy* rkl`bgimuptnlqsxfb]^`aYYd`]\bf^gVVQY\YUQQB;EMLKHHIMJHF??@A@?4*%38BGDDDGF>?@CFD3*2:87:@A<:=>GIHKIHFFBGKJJORUVSTTZWRVYbaee kfa[_db_ZY^[antqgzt~ntqgjnos|||tmrst`_\_]Yb\Y[cbgdk`WXYcW_UJDIJLMIPKKMIJDAFFFE8>-28CEGG@EIEF;?QV69NEE8?;9:668./20)%%)&%),&%))..1%('*&%(''&&26&$&*#.&(%#"$%%()+%"#'**,/02..587B9??lV@AD7?=S::66432=89?BV\CGHJDJIFFKMKHUKOKE@GHWPKQQ`XRU_bhn\`ccqlc\oqidQIRPR\amdia\[arm}{uk`k{ywhqzylffl]WZjV_Y]_eeuql_c^TMKVKEKHQOKPNPULI=@FCA>3'3@GBFFBCH=15@DBD;CEICB>FC??;47197)%'),)()%,-*,(()$$'''$'&'&*'"-0((((%+#(&+('&&)(*1)1624.@=BaI;O=AI>?G@@GBN<37756@?<44CMADFAMBW8>AJeVNIY[QNHHYSGGIHH@?=HMWNNLRSWYUY`___h`chkhpyyo]IFM^ihkszuibkikqtutpusq|rymr|qlfha\XihmaZY]`tqyt_a]UOQQEIVPNPTQMLLIH@BI<:.?B<CHI=;71++*,+%(&$),*('(*E;>'&%$+&&'&9L%&"%%(,+#'%#%!&&)-*2G199N@HtS>C;6:B;66::HEE96D?3>;:8;>?BBBIIGOBFI\QaNPMLQPBHIMVC?99@JALOMGKNP]XTOLhtdXmTTYTVZdbbbaSV^hkx{ { umbejt{{x||zr{ ~{pifdbas_X[^[cp~udba\RRMOGGNZOLMONMHJ@@A>@>oLA?DBIDBFM<23;5644:TNI;FALLE<>=<>TBG;9>40:-,*'-,/+(*&(+-,8^@.+(#)M0''0%.''&)(3K.)$%%%(&(/+16=T6_Sz*lRFSB<:7;76155YEEVrulR?DGLQHGKOOL\W?GFOIACDBKFVGC945<>CBBPACGNUUUQT[UOV]QUh\\]^bfemstprxo{slr~yh{yqzwrztyu}xsoqtkfnnij`aabggmofhfh]\SOC7@HR@62/0..,51))+)&%(/++,+66+(%'+I@1$'$&$&&%&2))'&&'# %,12<7;>Tf[l},zgGC98=;9=21=:m]ry|lQONV_RXVUPidKHPYZJNEBFGADG;737?=?@FINMMU]XUXUUYVWaTZab]`^c^`bjtuqoxysx - -~# - ~o|zpkjqkrplpjkkhmb`fhukgi~rd_ULD9@QPOWQQKFAGK_cFDIHDD?=@B@KLRQSX\]XV^VWYam^`oeejgde\bijnh{erwz  -1"$|| -  kdfjzxywropnrkbehjytisupc_XB69?GKTSOKEC@JXFCCEHE73??B=DIIRUPK=GBFB@GCCDAH74533<:11-*))+1((,*@37++0/@1,0:.%&'$&+)*)-*/.,%'6%,-0GADi_fbZNa!oYBB?<<=F229=Ku,+nttgpgk~\RRYIBMIIJGB@9?239AG?FKKKLUUb^[UYbUW_|enjhinnqjoghijpumht} }|xt}!$ *$|~}ifiqwtrt{mqskfiqpqipk} deRB>ELKQW[LC57GGYC<>@87>?ACAACFQKRKC6)1>99P;;::;Hp)2" -|zz\UWULPIFGIIEDEG6G?FCGCEIJMPYSS^\YZ^aa`plqoqonsrvboux}$ gh\)". - ~~hbhjpuiv~wqryoodwqymiqrplgl[HMLXMQTRLIG:GHfNGB9>;DB@B@UMN`LMB=)#7@JMNTMCH6;9DRM:80/+))),+/-+--/;.2E**+'+1*&&)+*),-2&((+'))&-'EI?JHQ]ugaZYZ_HE_FL=8=DHGV65%2.%&  (yeWYXMGHIJHFFJT]g7J?FCFBFFKNRO[_aagkmcdnqvzpu: }{  krn r ~j`kvrwvonst~vsitqkegqZQUUPIOLLFD6@:>@FGKXOPJROAHY?FMSGB=B?>K;Qwf5.-/*)(,1//)+*..e605)'&'*/0)+/*)))+,(-(+*,/*.01LD;S>Fpe\BP@MNRBCAA==8:=DFPXwBCA@BI=9GsdbaWOJDFGGCKIH_P68;>BFC;KZVY\U]\bUhwnuzr|gs% )  {{uz|x| -ujtt|{~wy vo}oklgcjnx_SQKJEJRODELJ;BK@B<96<9:FGTTWUTQD;?@HVbq%WZ\a_]]1sfUVLIGEJB=FIBkL@DCFEIHMQTW__Z[W_bhzx~tlnnrx#!5R5 ~z ur  p{nx} ~ztywyu{tpocedd`_jfdSVIYRSZR9KS=9AAD@4353>9>EIU]SRNLU]JIEFLGB@<EJXdnCJLVRNN[`dY?LFCJA:9>?<<:44912.2524/&',*26G?Nb0'$(V2+/-.,/40()-.0))),;0+22??AA<@>F?;HNQLOm<68T97:>>IU]t?cnzztnaC/vbYUPKD<;;8;,*3GHGNMPQXV[\UWT^be_nnniqy~uqy -tnpznkiziktefinq~|}  v -ms t}r~ u{kkilabcmnk]WPMOTUSMJNDPaJUKF@66665BCFKPLNSYjmdMCnDC98:BG><4449K07-659=.0(*35@[qE,$%*,+/*.%(,.,*3+,*+(/4<-7,-::FU<6?JDDCDVBAC516:839>?HT[pCdr~tnbK/ {fWSUJC:;971*M>JNXRVbfecgZb^_cb\Ybqhpx {~ - zvsvupxwzma^cci`wwv -{wwbxmyvy -xjxvyzy}moea\dorf]YTRTTRPQKVIMQOQOHH;><;=@BEJQOS_^`Y\ZWB@<8;WFO?9653E00.3;4,2(.?3712CWI+#*'.,,.'-#'&(/-)((+/+.11*3=B@BB87>>A?EO?78G311246=5BpQUUbdgbiiaeje`ijhjftknr"|~ |{oeitzvl^afnqsqoqlso~y{gc{zz -qmz z_gdcrh`a]X]XPXXVPTOLOOPLJHA>@=?D=CrMXRT[WVGHjA74;;`L@;?AA612280)279J37.11>1G-=++*/-867<63011143:9@AKT\iz3dmnuqfT6ieaXPB:BDC>9DCISUX_oxpwffmb[ggdtzxvnr #"& rxtfa]_jttrogfouvx{yqp}ouvzxre|| }W }wxwrbh ooic[Y^`RTU\R\QMNKURNPA>A?A>BIPKPSY_eXORDF9666F>B<o76.26517.?533J91-),:7=>2/;##'#'&"&'+.,+-).05:07>;NNETdB:;6691.1>844::BIPO\rAMY`xxgL4|]YVLE?DLTEDIJHJQY[`luria[ |{prjswpy  "(~mvoia^kru{urvpjnxxz}yz{pzuzvx sr~  -xgv vxnij&#rm{jY[l[LVVOQTTQPNUkNMF7CCDDCLLJQZ^ma\TP4*39>95::D??@>8;H?697B+,)0823068DAEMS"!'AQnsPP# p_[OF@BJKIRMONQRUV`mf}hfZZl~zyngnmcu~ lX[fmohproy{||~xzx{}}xsc||{obfv}|()~illm' iupdY^YOLQVYhUOVT[RQPMU>FCB@FIILR][mk`_O0(/35<73EL641--2/.<.)(+82307;GCELoeo4LMTH2jb^SWKICHMKKJKQNTj{xuqjnm{|v{|wslmgv |zyuonnemlpstwz |~ -~~{ ~}i~wh[jbu-Jxhntynkplg\U\n|RT^`\RRTVSQ]Lf>;:@AEHFXQdkaekfTO<4088771/)/**,-,-))46020O>>470-.?$'& !#%&'*-/..068640::833/1+*),/0/1+1;4559EBQxNKV --(-3%&~iZFIEHENLKKWS^_aj~rukzvuyz yn}x| - - |zurrrt}z|}vy{~ - -  z -   p -|zc[^'+ vktiijllxejkZL^G[Y\XSTSONNLMNA57PPEDMQOfv{dYUrlu;57;77:>=<=>2245/*,*+-.'+/2?[484F=N49-,AX# &""($&(*/-,/3=47524AA30/0-)01000122/4/2==ZMI>`tt}|aUPI?GOKRdbchjZhslmou{r~vzzjbeefy y -khtw  ~zzy}}~|  - -  ot v_Qpt{ -ytmnng\bgjka]VCIV^eLGRRTWUPO@;<8CPGGCKW_fb[XVbwXM57;03;96;=89hJ9-.+.8"#'#*%&))+,,)(+038585922316.1WNNRej^[S_`lkpr}p|qyflohhkgnw {|ujryysjpz  }}|~yyx} -    -~rflx|}|kXq|n^eqibhgk|mZ\HE]hfkeSZUgjYUKCG:DGIML@OWSTd^\UXT;@C66?5401AD=gM6*-.0.#"!&,&)()*/*.81-02573607/10./))+,3/42.2,;J679DA>BECLNKTYX`WQqMJPZQZajf\h[efmt{tppnhgikajpqo~|} {z~}kxorzun|~}}||}~|~wws}   -rnsv}nSg -~ucTdklkgvk`]\POXchkgYSXPXSTLDEFIb:HtAGLZ_jbb^LAY@446>686289;<8620+*-27522:=:o~1$EOM:E4795#"&'&%')$%6DH9371/;0;=4446+-((+)**.,+.2DD68:B?9BDBEOLOOZ\]U^Zli`VS_antsociuuxvqksd^SQS`fdqzvu}|{vswxysg}x}{|{tot{|y   -ztuyu}ojm1| i{nijlkhid[]VUagdb\^W\[SQLBFKLa[8EGHI`yi[cl_UA?@:9C<::38C989:4+0(0&-I3.3:Uc}DF:>I:X[961!!"$&&*(+(;685;MUQNQaujc[_[]o^_`jgjxhtkkpvqxyyjz\VMUVeenz~{x{zopglv}q^ryx}u{wvvssprtr{}   |ow}|vu} -  klsy{lfhua[dZW_ch\c_f[\OSOMKKWycGO?HNYga^WUFC0DID;76;=02376:F.-**))531<5BO^F<,2K?>CG7+(!###'$))#.-03@9M7//,0,<.-12/,*)++(,/*F@0.08256.5CPTRPMI^\WbhY_ce^yyxyoxmuwpdhfprr{a[cxvxxzwwslipsj{qs_`err{  wmyu}y~{|   pb_l{yfbhmZ]\d[b]jX^[cdMCY[OMiy[7B9IVMTVf[[O:2SOKI?;;648/4;3710--2-40,+:@EW<*&-33;<567.*)$&$%&)('.+1BN:9349349R8,***)'#(/+/-?;.-08.-/26;HQSRVVHaSbZopeni-"% uwaslrmgfrnx{zyrhmz}~ -soiimv|t~ydgrr{{szy~!"" ! ~uyyiq}}~ qcYdiyd\UZW\fkd\abgjiVTCKOLLXoyiSQ8;?BA=QahP-Aa[HE?>75/363=;/3..,.014,3:>SA4(*&//27.2E8%"!!'$$$9zE1CLn;50>=0.111***+((%('++90..-5/-/337IJJQW[\ -z[W\]WdhiwmfdRdrme[_u! xuo`jvuvxy}rynuckx v{vsw}}}ywnept "#$#  {}yjm~|~}uu[^^ckl[Z\_gfaY\ntoszNWVSVHBRYyZ_;1-6DCSd`>9FKEOB?@523683/503,(/5<,30AFG?6KN615-)0++.+%$(($)''GP:JW>77><865//21,/).(&%&)-0+)'//.454816=CB;:4576641410/.30.8F>H=CK=4E-0,+(*+*&'+#()$.(*.,@E8=V=>W>@,//4)0)+'*-)(,5**)-:1..1631B:FFUPXiIKUMVWcu|ixp`frtrqj_ayx &rumpypp_Xn -~nxamou}}}xstyvv|y{{} ##('''()''%" -wxphu~y{ge]^mdlxmhghk]jl|ysqhfSWLICVSO8:7*)0:99GQKLUF:=@FNU**+'),,)+)+(9"+-&(&-20/-76@CL878>.-.*-(*()$&-3,,*(,,.*)),)475=KOHQZYBAH>T[dfggbfd_dkxzmWBWu~rsnnnu}n`Tg|p`_hn]j xxzptwux| yx - #%$')**+,,*+)&$~wuikrx~{vrk`Zlnywgzkooo^vxpjck^VZQ^gdIC&)+'++06YGPGCVA230(2;484073=96<752E245cB>MJ7(2:*,-7)&''%)##)4&)0062/3K=?766S9410..(.,)'05.),*)'-0*%&+.677?G@FMQO=CVTcevordaZ\avimjVJEXZhhuoow -ymg]gngijh`kabrtxmrtxw{  &#$)+-0//..-,)&   rmfYlyy|~pyjfd`en{|rxzlddc_gleakhcZUPRYM?E=510*/8?ELLKLQI1++49879=988@;92685(*3=Z66912*-/-/*,%"!&'%4#12.-),+),.5?62@=5M82R+<.-.*(0()))++%).*++7I<=KC?HUNUYvN^xejurkc\Y\ffg_ThjdU\tvovkrs{w}rlfcuobdqnjd\_rynirxyxz - -  !$&&*-/022110/--'$   tmpdqyy{|~ypni^Uhorq|lmfe^__bfg`ajbWPURTN?><@87:CQZYaY[eXtntnqib]Z^\jb^Vlr__gqmmpznolljigdmeff^eilokhspapuv}y~wi  !#$'().0234653110.*'# |uply -}qv|yrcTewri_vpld\_^buclhpm]][SPQPE=:7V:6;:E6A0,0$#'')9+(',%,826:=AGDEF^]\fYMf`rktf^_\YYZY\Xeavkkmup{kmmfgehf]UZVq`kumqnojkegtzuxyxlgz!"%%((.24666776311/-)%! - yv{}ylw~wrl[g[\iawmtu\^bbgfrwmY\QMLOOK>;9=?GGCIQ[TQ;'0>BA@D@F:6=C7:CEH;U9H?H;bS0615*-3))($(',#$;#+H)%'.3/10:4DD:BX@:B;P>+&.1$$)'')'%)&,.;<>7GECDFQXZ[[WEVMSlhfba_]VT[WTdhbhufic|jkjjfng_]XVagluorti^_Vmvz{zxlv~#''(.2569898::9641,.+&$ yusvhqzpjqvvo\jVU`bronl``fZaqps{kVXUNIMI>;79BFJWCCGO_dF56I@?E@A@228>=dEAN>AE;;?=UB41611294/)%&($()&#)0D),1.,0/:5>BN97;7;:903,+'$''&((&(++.64>?A@GDCKMO]XQGEH`]`lb[WQUKOZRWXcc\undcfikkhhfeaQ[[fmlu{~wqj|ihiux~{xkls{  &'++37:<=?>=>=<<;9520-)% ~wpkv|t\nptkqpoqqkuxytoc\^`huobZNKKII8>8=9I@DPNLFQiOE=9C@;B@B312;9LiJjHDC=<:N4*,830,3<=EG<;ON620.,,.,*&&**;2//2@>@BDHJKJIJGKGDG:>]mfdf[gQKSbVV\aQYW]|deernfwfgcVQ]_lpgqwyzojsts{||wlaht| -#*+/5;=@ACCCBBA?>>;863.+'  |rh|~skatbqorvsux|zojzw^kiirjolaqRGE;3029<48;CYIA828@=knLE??@=6B8>>:53.+?,*(&&%$%(&#%#$#%62,-+,21.5=<;961.*% -zqqvmkurnvr|r~ysoivnukjghqpig[Ra:01/6;9;L@?ACACAFI>)2?NOGB<5A=ULCMRG>?;;>>A@1D<2/2(($&$#&(&$$%&&"(*<9)*24I17868;82.,#  vrqozxsystomz -qlhsu~pgjmwidZOD;A7//48CHF@:?BEB>=8!3BPGDG=DBL^GAK>?@<8C@AL30637<,+*)&'#%$##"(&"%'.1@..X677?//,()(./94;BGFBCGBBE8+1:?BAG@;B>InA;CIB572950,$%"ymvnzwofjpt &|{bafgj{rsd[ONCGBB:59==::ACCDDKH@2D>NJMA;;?=AGHNGA?GS\]XQUdai|gg_`fnTS^S[Wavpoce`cgfcgplffi]j^c]nwwvu} oujkjmv{|}x "&+/27=BHKNPSUWXXWVTROMIE@=82.(&% - ~vm~ztwmhokkvz  -|vbddgikupicZPIDEC?A39?:AKCGIFIJSD=HLO`LD6;98101489;:<@5BB>=8*-'(%&*()1%#&#%$'-!"&*2)1NnAFRGCNC<5:./-2-6+(),2G::5:40*$ -|wv|{zwrkcbdt u`bccljvzmf`WGCAO?A76;A<;DATIGHHB?BGJSWNK6?8;J-)/4;BdaDA?H:2=,+*B'*0,((&$))" *$)+86>/3RK:AB@_I?72/-@))/*)''+c776>@;>JVKNQO]^d`Rc`srxmYVUSTSWWUWXUUgu_a^dbikhxbihi`\]gc~dhl|qnovcmvu}}} x &(+/6=EIMRUX[^_aa_\XVTOLIE@;4.+& |{nz}xqumhehn}~pjifftvzhqd`VOIHGB<6>889;?E@DJJG>5FLS\OF<@@:9:,+79D5342/*-*)'$!#%#  '()1-2E\8/+5,)(%*&)**&)9I5@=GHIKHWWyYgj -npfdTTMMKNRRWRUUYkc^\ea][d mukX]f`ffrmvlY^NZmqz}~z~ %()/:@GJOUY\_bcddb_][VSNLFA;51+&! -|ytxtvlpymlhij~z|spqgheh if][SOKGECFMA58=:>@AMIQG9*?JZSK=?AB57/32377]DTKU`CA/4/1,'2,&'$%% #!$"1&()0:6>_Z97A?=B?@FON?-FJOfLGA>?62687;>;?G?PHMgE3-;/%#*,++'0&%" &$"+++,66EJgTPEH>@A;/1**)%""((..,300O@BBLGHTaU\Tl_zj]jurgaXXVMFRSXXm\`[Z_^^_W_kujknih_ejrrospsbhjtyzy||yzz{ $'+16<<>M4F@E7h8/4-)((,<0(%#$ 4#'*)/2BTcsAEI9<:GB2++.'#!(),-*+,::sA=EFHIPXOWScmne]KXmspaZUUUNRT^a~ba`pTi`q`]^c{ohhjXelikwricxfmztfs|~}|} !$%.3:@DKPTX_ciotrplhb^ZUQLFB=71,&  -yxvz}{ughhzjhny{yqqmx]`euzdc\]TZbQTLFDDHGC6/.)7BDC>>9BDJGFMM=:89;EDJJEI@A4E9Nb79)/,0%(1)$!#$"!"4A+=./4<^rabM69G@931+('%!$%5((1/209?D=BPHRIKH[=Qp NBNO`o_ZYWVs\\U^_pced^^\_hc^^szzP[mimfdit{gfmfjrwyd`pqz{xz - "&)16;BFLQTX_diqy{uoid_ZVRLFB;70*%  -{vx|zvrhjnqhkqx|uy}qc`cxwgd`V]ulUSSD;>R=95.*.8@DE=I6>DKNITGT=466B]QE]X?97:;;;4/,*3*F0)&"!(2"$"(2,<4/BA]RECC17F?=47+%<+(#())(11@/56>9FGHCDVgo:4210/2:0*,'$$$%# ! % '58;NVEZ<35B95=3+0:0+%&%'+,0O6466STADB@AxaYUKEINM\ZT]abY^X]k]]T_Y_dd__oetbir}ss^ZWXddf_lukuedivoujygtvt $'078>DHMSWZ^chlsvtmgb]YTPJE@93/'"  -~wsutyuqphhvpljlwym|'zivn -d|xtbbUTRQTDHC>=881<:73:<=9.0GOXNAFGB@=9FSIDFGmE:O@1U:6+-8()@(&&& "!$!##._SFJKHO5464684>21`B'$'&:/7865<:KLHE@KDPTXYiOB?HSa`]o\c_ek~`MVZSR_[X]`bigooivyrlc_OUcdbhknnyfR\eplozsxzls "',39?CHMSVY]`dflolgc`\XRNHD=83.'! }x{vx{unljhlsskpg{ ypwhhru|yk[XPMKJ@<:=D74016B=67;7.DBNclFCCFBD=8AKEJKJIKVBAAE-,&()#% $&# !"  2+bIl>TA764.01+4812?(+'*-7OA86FC5?aK@GQUcY\hjOLQNb_h`naSWaTQF@KYh^V`dj|gp{qnef^I\ggdelqstXTb vcsxwx|um -"&+19>BIMPUX\_adghfb`_ZVQLGA<71,'# ywzy{{rhcispkhp|ts|w~4znficef_UPVQMMC>=?>64141:5;CFSGFYX\YWev 7pVZa\i_JLVhpfqTJQMObaN]al}hg oohpWQbjjknmlrgUbovowx{|qxxy| - %-17;BHMPSVY\_`ccb^\ZVSNIE@:4/*'! ~}~z|yvpk_ghifn|ytxoounttocdeZURVILKJ?K9@/285/4=JMH@KINSWUSCA>;A?E9=DOPjsTW?>QA%%$($"# !#*' &&68*.P2.5?9636-11B/22,..'8W?5AJB9=:=`ScgOR`\o>$$!  !&%%"68-0*.-6211@164/2/2=..1(58.1rF?<:AMHEJIX\b_hvrm[`XWTXjmhffgJJIMMLPNVV\hQWRajhibnkc`_ijpsoqefi`Omxzvx}vz~{ $*/5:@CFLNQTVXZ[[[TTSPLHD@;51,'$ |}~turka`fu}|t}ra[ZbnknjjaaVdOMF>;9816/1392/>DJIIMDF[W^dND=@>=989?mVPWSZQ^OC*"! %$#$'#""!35,-,+/030.1/35802236/9**0118:528:IJGNJQLYm\TbqdgXOWVY_^shz\\FUI@AFILORTTVVWTPPOMJEA=93.'% {{{}qwfh }{tg\XZcuozcZ]^RINSI>B915,588-:EIGGD]SLRRSWGDF;4DQVWHQx55-C&$%"#%"$&$"'#$-# 4,05?/-5/+-+&+4<5/346/)+'*,3-25C@CR@@WePLT\YceXWUSZXpW]jjozWS\hDIKUOR`Wac_]_s(d`LRcm\hheorV{tjvwzv{vzz}~ -')/7;72*$ -|}~}|uflstfl (|~}rzk_ibr{#xfcfZLGXZGA8O8469-+1;GHJPPDQHLRRJFC<;<<78412'#'"!(,&'*&%!'"!! ?V5<40,+.,+,(,0+./.,/(,,+324*07M=;HFYFQNNP^c`hkdUSo_]fjhff bNSTSTIJTZXY_bm^VGRU^W^d]][Yfhfjtkqvywx}sw{| ))-7;?AEHJLMMLLMNJIIEA=972/'  ~}vecikomw|xum`bcdldcqtkld[XQKKGB;88?8706L@9HQRRO\TNHUUOQ;78999:G?;;JMM>I70#'-+)('$$$%$$4!!6A?=-/**-,72.-0+-2-%&0+5-11S::8?N@:74/*% |kccdflt|}wtch_mifqoskf^pTYheGD;GN>664<>FB>GSWZx [VMQKDB;538><@@:;:;5@=GTNTTTV[by]ZVN@FP=579;;=J81)(C88-*'$$&&$$'#"##! &# 5;D4.2//22-/3.0>7%&%&+-12Fbm023066?EOLPIPPYXZj|i^U_afpqfU>?>FLYQPR[WUSFFM\c`LRSWX`gfuyre^sk\pwu|{{v} $*+.17:>?@BCEDCCB@<;874.)%&"~|yrbYTYiru}~xjfhpikpehtofbXMMWG?F;46347AHCNPQU\X_\Y]cPXYYg`f|LC0:NqePW`YTYYZZQXa]ZgW[Xcg}ovwun`j|vzwyy~~| !'),037;=>@@BA?>=;97431,&#  xse_dd[hsrtwrjxqsqnnx}gx{pd\]SPVQHH@963=;@C@GPTX`c\YSQVE;@J450457=??@XTUQRR_]WZTY`S__ipkSXC414))(*'''####'#! ! %&! :>21,***+5-.*0,'/)'+*+3))37:5026::=@FRMSTU\dfRQMLSY]d`d^OI@=HSDN[TZdUQQQSOPRUFMXRUcigk tcZqi{|yxy{yz "%(,.1779999887630/*(%$" }yvtpl]Zdjimgl~nqut|uthee[jsbUKI>@7;4DCBKPVbVSUQJULFAGIEGLQG?D;<>66/++(((,'&&'$%"$)6 "#<% )721--1()&$(+')8<6)&$#:)*)3.975187=@RIM^UO[SVUMKGKUVZ^XTUPWSjvZHPRRWUSV^XPHKOvRQSQYcilw{~jyuw{{wttx~}qz| #%*.03357675421/,*'%" |xsktpma]imjjrwmniz~sliecffWDCDG<::C?HESIkUUQNPTNJKHJIIHTIAA@BN=421.)+F()*'$+3%&#""%!  #!! (=A/,,+-&&"-,1,:54&&*($"%4//-5?4??;@@ULih^P<@LIJ\WOS\ae[`VPZ TOZVSOZ[W_PQH_VYTTWNK^dj  {t~s{|qonz~qn{~ !")-.0124442/--,*&%$ wlkmvzzskiljprw{ypppmq~zreem~d[NQ_FMD>ABHLKSRUTTQRRQB:AJ`KILNJFNKHG>6741*)))%%''++#!##"%!'!" ,%$!&,.0+0*,.('$(--,--**)4&##$%/1.1;5O99AHOdXh^H>GXUYULX]WVYWT\_slTNOVPnVZ_aTFB[M][XTR\jgm'-" hxjzuqjnu~k{"%)+-./0100.,*+%$!  -slmtwttwwr{z}ln}uy~mmkmvwokhhxaPX``NGDDIFRVVNKVSWZSJA;HFJH?GKJHBCF@A=:?500-*')(-#(# """#!% "!!' "'O -.3/21))(-(+*)+1/+,?&$%"$+7,010368=FFU[[OSdYVQga}\ZRS[NrXHGMH436@@DycZ[RYOOOOUmXY\elmpx4KnxX7&nnwvhevw{zuu|  #""%!"   - -zwtqpnrsty}vv~splmqiamr~zq !lTZZLBA99=AHWNOPSPW]ONQRTQNNKIVZTYYg]EONTA<60C(2&$&&## !$!*1$1"$$0JP:+'1$)3+*&))(E'+)$&%!''".&(04)+-/3,*/9GFEUraR^aZRM\ef]fgQQQaZHJIE<:37BHBMVRWRRIILJHV]a]c`jpr,RU]Q2sjw|{hZmr{xyw} ! ! !yrpmxvw{{{ux}znualdnvios~}sc^IBB@@CBGJEFVSPRQUVSSSZWXMVZ]ZocTCDA;8/7/,%$&$!"$&'#(&#'&&')-^1,/-+*059/+'(&*)&3$%$%',)''&,2..2>411C9?U]|Ox`QHRec`RLMSVMKHFEE;847<@DOJLTYNM@>HDH\dVK_jo~/+2;4:oepmpsnZcwz}|z}  !!  ~|ysrsxyyyxzw oqmfafkmonnw j`o -XPI=<@HCGMHKIIROL\UffVTolWVXWQiWDA=>;810/**(!$$((&""%%&%&%^))3'81F45EE80'%'&'# &%7$'&($$('(/.3,/-.,7:6B>;>TXJ0^BCX``TLQOGNJJCC?B695:=>BFMObTLGCEJIN\_UMekip _ins|jlwfqwuzzruyw|{yx{}}~v{tpdffldmoolunZXSZLGB<>EQCMFQNHOPOKUY[_W[WY__jbH?TB?=;::G/,,0-%&%%*?D'&$$&',$'#(*'(*M,JI,0,+('('((/&""$&*,$%-"/2/0+.,0C22S?=DJHOCkIFMT^`hIFLFFII>D>>=@;?>NBBEGIMPL?FQHEMRUUQcYmcsr~{~k_g}cZrhium{~~  tetqx|z|~}||}vlirfafjmitmyaglh[MOHGBHD<>HOGEIEJPNNIT]blXS\^XWdXNH>===;853510-*&%&)%#V3+'*0%$#!($""!!#,,0-+0)&%$*(#$!#'6&((&#&##1-0*,,52<7AFJGKMHA7MO6@cVQcf[Xitj\hktjUcpcVrqgon|  }   zpoq{x}~zz }y{v}xzzyslkthlrihrqgkprXaPJFB>96??@D\GQJQMOKQLQTZY[WX[ZX`eRBG[C66542540.*%#$&'')Q3%%*%%'#$&'#')&+=1''#.%$'(%'$&"#%-%# =#+3*'*2,/,@9-)-3151D=E<62AUYha]kfTTRLCEEEC=;6;FBOGHGLG;--5FI\[XDPhypkvn`mfc\FV]ANkspdj}  } |qt{|oj}~z{zxx|z||~zuv|xushkkkgkmnvpptcaYcE?:6:<==>G=@DLHHHG@:4.9_c_WXZ`yxYipc|sUTSTLK`cjbcz - - -zxtr||zyvzxx{|~uxx{~|yy}zzxy{{qjqvnjlgnpnlvgb^^^RDFFIEEFIKJK[PLLLLQLJHLPX\`_^XSRPOKN;@7933333149/&*"$!%))'!+.'+11#$(%%6+&%$(#/1$(,*+*$.,*&'$!! "&*)-))'$$*)->86>G;9JNUhl`_SMOODDFHAO81;>@;?k=ICMLTFB?N97C=OiWVZfrxhZ_ljvjgejhRbQU[oc_s  }u{z}|yww{~x|z{{ty{}||~z}{v|vrqljozrlvrsnts{pm`^VJPIKHLHFQLLMMIGJHLSOSOORUX[Z]^VYRJD=9?<747E-2/4A,*%+$(%""%-()+*)%'.C0(&'#&&#(##(/-'2+',&')!!! , %$++/'&*-./446<=NLG^aUehjfbRNFFDFBCN7379@@=LAA??F@CA>A<4/>6FWWWdteSTY_liprnuo[ingflmck - w  -  xmwyzvzyz}|{| xxplqklkqmrwqommltogZJLRVJJGMJHJSOPIPMPYHALRTWUWX\[YXa~tH<;<@;3548A/,2+-)&'#''!""#$"%)9)45+:%()%'%%0)$#&1*/+'#"$/#$!"!! )$"**.*+03+//01@7=QJKLQYZb`[^_IJXBFB<;<56;;;ADBDI@@FC@HN621<,CTX\`qaWZclxpmhqig kpkmedo - }y{u - }pn|ww{z{'~vz xuvqejijgvrzplmiloeWYRObSFFUKGFSNOIKPRTKHIOSXX_V\[WSO`^C78764543/;::+)*''$###$"#%&))'%'*+4+0Q(*(""00&''''I*($"7i*k%"#" !#/),&).;,/01596=JNGKTSfke`WVJAA<>@FD:9:@<9CMF@<9;8:AOQS\]f^hnontxkkknt)&vfmmhkmx~ux}|u~yw}   -~ v|z~|muttuv urnieihnnwqgehpjeXXRRSRUJFKMRMQOQQLPpXnWSVRUe^gUW\NKDAA@>N142.31>m;*-))'("$%&&*+-4&4(-.O@.)37.(#>#!%%!0"&&$4?9'#"#(4'$)&2&-/).476D6B?<<659EjLPWYfZfxjlqjj_fy !uaohlor{{ -|qrssvv~r |wuz~zstquyzxy{|xmijifqpsq}i_`ecX\P\TPJUJKMMOLQMRLMLWRKIKPNSYVURSNGC@::=:F755418R`h0+'(%&$)-##+*'&(5/-.5C&)&5C%""$"$$#!%*1#$"&"!&#&! (")3.48013;GDRGMcn~j\Z[P[Q;@G>ID=>9:>>=>AK<@AB>B:;89;<<=HSYZY[\VTOHB>;=648:9:8:8GJ<:4-*/(+#!$'##%(,8.3*/43$)*$ &! )((!" "$ " &"'##(G'##!#02+-S05@NCMNZYonrn\ODG7EJH>CN?:;<<:AH?AB?>8:9:56I_T^ow{kpokmorm\ddaighix~y~{ -}~} qtnxxxw{~|y||vs|rsqsilnlpluneab\^c^YYULMOGFOSOZlRFFDFBHRMT]`_\[ZRULIC;9959@::8<7E8E4.241.$$$$!#%8(&+0?1*8=,(%"#!,*#!(##+%! $$)"0,#%)6!$%#'(0A:8EB9;AOji-yLHA0>^C>EFR:D<<ACE;@79==HDE>9DD[LG2*-:)%%,$#"%%&')1.57.1&,##"!#+&%!('1$""$!"&"$#%AF#5'(,"(?+5>=8;76@@D6d!wPG?5>YQIJMF=;:@;A=EB@GA<=<:9??9@<;EOHMovhnuu]i|kaW^ni]fjp  zy }qt} {wtyv|}z yrnmmllkxmjc^]as]\ZYN_LCLLKKMWYSHCKWVQGTSWTbab\VQ]PGE<>>F@>^Wup\Je[=2,4.)&!#&*%&*)-3*.-10+G+(%)/#!)+'#' " !#"4+; '! $))`""" %& &1:`89;64P@EGDM jnl\H;6=LLJ?=?B:>A>??:DJMTNj|bfpv  [`snx~}ywzvy   ~  }y||x}yzywyrlkqppocf`er_XQSYTNGHIRMMMcKIRTkQRPYWRW\ZYTvONCB?7:@EO?WtYalH55.-&%$"&''%'*)**(0+&4,8'$+'&&$%!%)%!$% #& "$"##%'$!$""$" *2O8288I>>3??LQr``UML;?D?AO=>AJF><<>MA<:>Lg -VN7-+(''$'($#$0]3''+)('31",<(++%$)1""%%$5K'###3$#!!&"082713;6C@;@7@DK\PCGC=C?=9EA>;8<;9:75<;KNYV]grfa|r~~ -lOnsnrrggqy zxjlrurvolox  ~  {ztntpq$ pc_^\mWYYRUQPKHHGDPNJNRZTZXYYX[e``fXSPthEA>E5BIG]8@HDCHE@4=8=9:7OS=O;=C9<;LEC=9A;?<9PFOWZd]in~{sfqg``Mdkso -vrx|}ob`vnpuzt|y~     }~qykplmmrr i{mg^^]TPROMKJHFKGIMGLSPjk\Y`\XVVcSPNJUeC?BK:=>FWAL7M\<7;:-/+%*'$'()+&&(+4&&'+%'&*$&'0/%$&$,3#%."$"(8;3"/#),M.' !"#)./.4348BGZIrVTNR?FKJDDHMEA1/3=A<<<:==F<9>>GCD=:@8A;7GF[Q`ksztyqdifUITqNScmz -wpspp}}mrogn}zy|y }|   z|{zux|yqspmloutfkwfegg[ZRVJPNLJNSLRNIJMHOY]_\aZ^pYYZUNOIPCA=@>?NDKKEC>?;/5W?(&+%$#'(/&((%+'''(&()$4%>*&",R9'+H/##/#!%&<&#5$,{%B  .#3A1613>9=VSHTzXWYJQKLES[HEMV;;>69?C=89:E><9C[FJ>9B:979=EGYu~u{igmr~hHMSZQEK^ |[aemmtx~svo~|}}z {}}~uvwmnpqu{~pqm vjwhphnhqqznf]fWXNLULLGFMRNmUSPJHKUS]_a\\\^^c_U`VJLAB=97:;8@S>:989>89?DRD=9;@Nh$xvzbXrlSV\\K?IXgh~]gjiciu|rnxw -{|{}}zw|uyrplgjv}{lpwmmlcf_c\W[\[__YYJDAOOODJMKNVTOMLIORY`[[W\XXVTZUTKGG@8@79<<@?83=DJk2+(*.'(&#'&+*').(((4$%&&&%"$7>'"$7-*-'#5* $1('!! !#/$$*6-.R:=:AEHINDJFVRT_FA=;@B6-38B?DUB67;7<7:=:=JDAHN`toqVgtqvvpnc\Na[[YXeqmp^`Pdwu|oo}rty|{{  ~{yvy}rkkhigkohgpm{tksc`a^ZWXXURWc^RNIDILC@BHL\ROURPUX[Y\__Z`[WUThPILFEK?;<=6:=<655:8::=DHL?@Nd^QZxnl{pWANOZZ[WhlbndSGT^qqrvys{||s|{ w|~nmqghjcjmkskdkablnf]dSZT[W]YaSONOTLMOJFDEP[UZPa_YY]c[da_biXRPOKGE?=8?;:=9g??B126,)0-*=-<,/2)++')&*"'&&&(%$7'(%!"$$(0%&)1-/&'."$" !; !"#&)+),32ACVAICGOIIPQTNPZEI6,-1:47:D7779;@D995:8;:@>>=9;;A>=9?DAG54711..*,,.+)+)(-(3.)'&7(*&'$' $/&1"!$##)'#('.;%2 !!!)34!&!$")(=*6675438@AI>DWQKi`y~F),C/05F=389869=DE:89;7:<=<:4@@IgJXt[anptkkWP_idc`ll[HFHR[i gdkmutyuytbhgm}kc_faf^`bh -z`jl}b`kYoZWQSSoYQUMKTT^VTTORLPNbSP]Z]a_`]^a]]VVTVQB@F75=>:>>;../,02*)&)*,,)-))/'*5*)&$(&.$#0$!"( "$!$*%('%!2$% (M  !$(-0FC5.16?CBDGTp~m^sV3&).-68=;63769:<>730654AG;C4;EGG^QT]dfrzmmb^^}zhffdwgwo^ZIBM^_jZ[yklyqz|mehmfiifg][p_YXb^UPTcb\YVVVXYTShie`UR[ZZTTSOUMJJNQm^`ki^_^da]UTTOI@>:::8?:::99/,/1131,11/+5'+*,*,.nC*($"%#%"%  $" #&(D7Q4(-"##'$  'E"#(*9?487.8>D;866:=@MQQSh\`ppjiltXU_[oe^zZ_jOilgj^YRTOSrfknh]akmofjjj1jckcZVRLNQghyYOONMIZRXTOUWUUTW`X`[SSMPIJEPRTSY_\\ia]ZWVNFAB@[7:6:34??@CD7741/+.415-&')))))%$'$$F&$#''&%$"""!+'*LN)(%6-5)+ "  #+0+1:?HYOGGTXfYVHYP9-*)-+0W5;*(0793:6>748::A787>CJVUTHIZ[hjwta\WaY`hf^kR[V^bck\]dIWWV{W]f]bdfksogjyuqabc^YWQXTUXT]NLSLT[YZZXXe]e[^f]YWSUVV`YQOT^_betjc[SQLCBA?9A=6766:@O9>;gE553+./..+)(-3,(&("'(&'%)$'#$#""! "")&+*&&+(%)='' ##'+*43@;IJGHLQEDQfOGPBBIBD>:5//,>82/32<:645556A>83:=?CILOGLGL_aeelgS]_a]dcaf`^_mnhWXULFXTLVV]cYaZe`]_ozoy}ck[[[XULTYTRQQMN^UVWRTZ[W__cbk[[\`gUV_ha\RXi[ZZg^aQOIK@A=;:M=68225\A6FDD<436-)'*)'-(&*)((%#$#$&#*$(%$#""$#..-+*%'0+++)H)! $.#")!*((+-6F;>TAORIGJNQW[OADHAA=9<3Q34673446:760136;;:=6ABAIJOILGTqicdfbc[^Y`^Ym{gfe_}_Jm_u;JKU[Z\g^Y^_a_di}qs{lb]NQTVIWfhVQJORZb`]Xd^_\a[bc_]Ygrh[__gil[eeZ\ZTNKKHIHB:23538@74421;4>>9A[34./-*)+&%&)(('&&$$!"%%&&'(-* #&$+91?(*,1064&" $)!'!/* !')!&(.A.N9DHJNVCDVgtZTMJHJAF:@G>%(111/6/6.41746696:JG\FBVSFD?Jbl_cdepf[KNQXdmkinj^U]_iSLM@XnYMWiZW^ebfbrnyobfVHRSXN}WcTUSWSYfe{cegg^f\ibd|_lpf\qepce_ca]VQIGDHKRND6765/2=:648<8:4=8704/0*'))')1**)&&#"#%!"')$%(%)#"&A;6+7'<5'&!'% #"364$ !,+%',3A_3>GIH?VFBDJ[VMHWOFLN?>;@7*$(/5.0..-/513307845BNBIHSLQ@HS`bYidkr_ZOUMmimkszgjUSQZ\\YgIFXbTRSSRN^]aj}~bYUYUXXTSOW_^^Y[gs tcgbdaffghabkbseoefingidgTEHHGHURNEC5414DGB42469<721323.-+()'&'&'&'))&-&&$/"&%"#%!"$#-$&&'#-#b+$ &'!!(N ,%(+/0?B=?D?GHCFzJDCJRSGYP<>9B53(&)(,-/6/2617;3386<37;DFLMI>GDQOU[gif\UUB;Vdde0_`UY]`VGHGFRZZXWYPKMSZU_efcWSYZ]U_WTY\Y[[^\``d^\^gb`ee^hospkiiokmtihbWYLMTMFGV[JC663::3<;56-;;97307-*+-*6+,$$%&($%&''$)(''""# !"""8&%(&)."*)2%:>!# $')%&$',068<:CDEENOLXRAGSNKFLB?8;9M1/*&*10-03485566355365:BAKK^=<>MO^eYWWSJTRH6P_hr{v|\abfZRNNFMX]UWOGOOPSU[TcfYXYXXTYW`bb^`e]\Z`_XZ]ab_ajdhhljrnqohfjrd]aYOKKHKFMHG<45>;@46852169::5011/22,-1).)($*8.''# '*%*#%$$$2) %-1",+&$''!N?  0 &$&,88;@@GANUKMOCaJCOIFRJ@;9;;@65B*&'))03748467446432@B?@E8E78ACTYRPJS]VWPFVne`bpgbYosgZXWTQIH?PNUaYb_YPN`ZR_]\^]]Y]Zbdd[XYY[Z^d\[afeZ_eebdrfjplk`[f{plWTQRPLJFLV@;6>9SA35:943C99A7504CVo67J+.'*%&)*"%($(."'&$($(%&1&'40#&$#/".0" '!  !$"#**5=B9DBMOPFHKJIIEOFHEA>??:89bH)%0),04/5338BM8:=96:=APE9:0;88C>IIKVjYWjIYQ[X\YVILN[][[WWWV`F@HSelr^Pa[ZZSSdljZcdcb`a]\_[^Ucc_`_^\qqgb_hrqja``bca}`^VOLWwLRi?::@;=>?6;92958@@F;5950,0.,,*+.(%&1('%%%)j#&'&%"$%'1&)%"$#% %-./ 3! !$#))(1S82H>GCIDGRQOIER=;A@E=618B[21'%(0//1/@5257::283>@D==9GHNG<=BO>9=>B@=EA87<8:>N=F:,/1.0.3*-'$''&&'% " " %)5+$&('$%&'#" %" $"!! # "')/47A;4337EIJFJEGAA@=?A:>JJLLOXeZZZR\XVe]Xrsod[[YNQKMZNe r ffXahe^Z`cddcgkj_`Z]fgmfva]e[``\]_^VORNJLGPJKEEFIDEDljZ[_hH_w9;>=:99C01-)22..+-,1&)(*%!!#!!!#%&(,%&()&0'&#!!""#$ +"!!"  3!54 $#%,+08504:;@ECMME?QAF>?>=8;9=4012.$#((*+)),/0262-/CG2,4A<5;J7;RPJU]Z]]YRSWRZSwqb[`e]d`m_\`tx |sXZ_bq]midhhe``cjziZdvhbd`wup^]S_VXTWONLPLJOGKDCDBDB@?>FDM[-\IB:<69375C;20/03..<-:-($##$ !%))*0)5)**(:(&'!*$&"#!(9" $2#!&!%'()0082J?==KIFHHCC@I@>=@A97>53:;S-)('#)(+-/@/34*02<308:C8I>76:?/71+/4I)(,!#$!#"$,,*2.:*&&'('#(!&$#"# !(9  !##+-&2D@AIFOERX`RSPLGQT]`b\`[QVSUbU^^ajslbU\r}~jNWQE[NOU[`^\Z]^VVVb_ZdbZYYOQIGJGHJHPHJECC<=ADEIUNJAD@D:NVJ?F<<:<=;>i6A52WI8++(%%#&0%)!$)X/*(-))$&(*)# %%#% $ $* *,&/29=>OLFDDHAEQHJG?CEC?:98:;g3?H2?/-0*)(*).43,2:>79>>:>FA@>D489IFGJLFWWHGFXUSWSVUTNNRUQU`_WkfV\dy -tqYIPDNQXLUTXXUVi\YV^aSUROOHHBIJHDABEFSHAEJ7GMSp`NFLAF>BAOBEDD@9@?:7?r[H9480-,/+$'"#" ;+ !"!)G+1()'$$##.7''-.[($)*("& !-!'&)1!!%&$:=8GOG@9DKAIFB?GAGHF>9>:7/@/5)0-0,&('%"*,32,/2654=AA;;CDA@AXxY:H=CHESJISQ\PP_ERORUSVWQPVX]^_[YPRdmko_ZW[OUZOVKI[\j\]`\UUNNNLLKHEACLDEBBES=FED>:MWpjbLJF<>@BACCH6@D8=E25PI:GE.,))-'*(͓-!,(!')-%&*-'((,0'%/'+Mj(%$*' &: !%&$ "!',.17T=:AD=>E>:7OsimoaGXD;9:@@IFCEGIPRFlI=8=7?:/2-*--...)'# %('0./2?>98;>@94<<@HGHGJLMNRNQZRReGAIQKHMSQU[YMRNRPKICMMSPR]KDDB>E=E;:<@=D=F@<9CL=@PAJDCEDBELKCF;?@;43/3,/45721,((.0/5C:C;<>>?7@B?I>:79;FFC340/++/291H2,30-?+(/$"#"$(# ")%'$%$%"&%&")(09.+(68A<'($ 6%.!""$ $'"&((#%*(5LIC;73035;Ii8+)(%%-27OQ@JO>:8@9;93R}HMK?=5,4?BCHDLFOdD>C8>DA@DG@>ESGC?9??@;78;::>:G=T>H=<=;=HHXDK:==o=74847.100/*-++)<,D1>1&&$"&"&$ "%&#(&!$&2)*''+2@.))4.//,%(%FS)! !3 ' "+"$"*()A87B<9CKPO=41222=@:3001&&.:O?:QeJ58CA4'.4DIF=FUqbG4.:@B?AH@9CJG@@9>CAC?BE@HDABH>9=;D99877?:=JJ??;<=@;CAR_TLYM<:88;=3.('.)$$+"! $!!-! $"" !*+2M44@C@77B>B=B@BB?>B?FT\=:G649A93=895)#+BAA>JD),99DHFE@HSD>9\ETOP?IDD;558@?>?@>@L@<::89<::8;=B:::AABAA?<;<<=89:75788:I@L>;C;F?C+ ''#" :6@((!*# !!!-+26*06WI:H2:=@<:@>@KIX>?E@;:9899654858;88=;?=;E@C@:9:9<663A>;588;C`LP@8@>D@?=;JKF=@<7<9319;8/R9-2.0-,+&J/12+'&#""!%&%'((&.,*)4,,3+0,)2.W70*;-&*52'-!$)% '&!""#%##'0369:>c28;C==;9CUF_JNML;D8FVa7410311-%7-557898419=77M>Qg?C>=>XCBCH@;A8:@79289370.+*/H/,*&((0,31)&')'%;-/)+7*.21=N614/3*,,;O.3*)&()".%/( &%!"! #7,%36:/59G89;:89=8BN|HKB=H<6C@EJ734;6:2)(&/116B=;=?7;<=BG9;JKe>4/.04::23:Crg=@4566564::7956<:8<<9:8:=536666;I48:;4386?EE<<<5:<=-2:A53894364:24/-+01*/**))+)-R='',43`JV1354324/:-+,04;/?<=1.'$"*"" ($ !3". #-4(')8?1357<<251;4?8@VvpvJ;8B;??@CBE>B;73=3(,(+45899AB8:;C?3763;BE4@4/41=<@:CHMCI@42/87<6468:75;CJ@;8<8<:582555516@7>=7:>5;7465204263792585<;?H8:>9<;7?DSG6>X613()$%*27=967GM>:<6;=:J2D6735..C??::A@ME;95298;55985::@^[H74:7332/200298278:9:6574A6;4724146:RF:9131?A:847877674267/7?I.01S55996@24>_;,2/2=>2>33;1K:_78C/-15=<./10+)0YS1.*&$ %&&#'$# "J#.#)7>==*%0)*2.879/223004RGPBAIGJ=:<99VQF71*.474/+,(472726=B@?=79>3444>:012?B7M;;;F[B<7694719923636:F9DU32404I43153=4C9=3247;8996876727=78?>55486:>=5=6=984/0956BS4026:T<E6<7@H?>4JC5./29>EV?43501252536748999639DO@:665455456IE98764639=7=6625>/0-115S651F85?c5;/-3zT0AX80LB77258264620GO4/+%('/15),*3,(-*&,)&9*,?: & )#%:'  2B+.*$$$)))+.*-/00.3//2@BBII_?Aa@?AyT=8>.053?;51,(-0642869NBL?AC79898?66g?C+15=?MI36Q83A679G7;2:98:AA>5A9G;=9E8;N8328*9495;1<=77,1862/N>74>66`K=7215770x|98876/43/901357=32.j#').0)4)0.&?7+'**94-+$/+:4K+ $2"!$!$#$,'(,,10+015*(/>A>?A>?<<@DE:AE:88;.:4B:750+.2;2F47H@FA<=A;M998899489:9?@A3974;54:77A:A:12124;[G7<>:868/23-170E7A0;784F7),A-/419-.3/2;/21(24074G//1.)E83+(*'%%'%(&0+*,06;)((@%&(.,%,14-dG# 4%&"!2'/0-++,/4/.,)),/6F:9CgI?A:56=>I=M:03F642--''145H=;>:@FMDE>8NC>=.+*-9B4:4?890:?:;;;?B=;@BB?E;>N:85;=S;:=57<799679A7;4644>A@:2`S99:;53M^M=3A3:276>2545420,0(((%,4/<=;4/,.+3CA95C?4,--/)+%')&*,(/).,:-/D+&,''%)3)2**6C4"$3 $!#$(?*(.25./.-1/.?5A=;@FEKB[BEDurKBE,05665+*󼗎X:;CD<75G=@H1,4/47-.616966A=9G68999F9:UC>>>F?;<A=9;B?@8?G:;CD;94>@<:4@245768AC8U373;9WLS>C=8?88.96952-3+*/*$'+-4*14/:*+)G00+970;<5.2+(&*,E>*,))<1+64-5/*$+((5-'%9)!<$#:!,!$&((8(229+/11*,0188:A:F4@57AL@570//4678DTL]Z@<4<;656/63=41*5+-2145658279>E>?@@B8;B@E:77>?>4:;HKSY<=89?D98<898J6/8GDAA<575<.24847EgG75:23111/23-+-.-----0+016&-5->0.-0./10.2-(+:0,)()))&1*%$9'*&)':VX&*&&!!!"!#$$$#!&-,.>6,/2,*426;DDFJQE<=CI\D=?D@P=-/25aFJk77;,,;;AGaxq?513--6>743;P5,48=49998=3/987367T[K<17221+07+,*/31/1.7/2),,*+))./80,+6-(3*+)(4/+%##$*")-)%&/'%,#*0.9-&"-(#  .*%+.+=+24280,-/237NDWLqNsKLDT@JM`bI4*-1ODB607>E51/G@X`8699552683@CYA//0541,*0++&--**-85D5+)6&(&.*,./+4+()+*(/+*)-&$)#%#+-$+'&)&%$#)(%%*'"" %$!& !#)'($/+*.,1.15E-+/2:HK]GGQCB<7WCFnRVM>37?54B=?>?^W@26ARWpL>5622.0O99E<;;>5..9;44.372.0476464364:37:D=?<4<:A>B43=4L4;--'2),)1.1,4/R/=+))1-1,,.-,59,%%+((-(((%*.$)))"##,&*&8"")%%#/*#!!!3#%%)&&$/9./)4..708/125NSAB>D=7;:SJGSH>2R4414B?EB=7lL7.02.455746;<<89-,12005343/552131668100.JK6A;>:5-..,022031.0+*4B`>?XxY4>F6845730175VRBB6=A:0*;/7*),--*)-2)5-+*055141/..4*&'$#$(&&($(%/$'5,S,*(-+WA,&+4('$+4*%#!11*$#$&32#-.(*+,0@.-2.<5GFIA:O5E4525456624516699TE:BH0.54JSs7.:2?*$**..*/@+'')<-'%,>N:3-1450(-%%'%((12':.)&)/54WvA+:U+.9,')M,1'''$'#"89/2%(!"$'(-8814.--4/0/6:ZLD?@>X?AMOT@8594=759?>7@DJOII712TF7T544.04+*.CGVC/2/.-A+(8*071.069K1472343/4;?5550,.1,-,,3+3.1,-,3<41=J;:8DBF@B;1.421.?P0.,..&+%).+*,4.1+'*.+)9B;<5*43-(),*(&'*&*((+?-'%&)1j7L//1?>(-**#$(*%F,)'"##M)$&&%#(%"#(,J->5,.136/38@B@7A;@JCFAHB=,34>DF>>DHZQGD],2.4(*,,22;/11-36@LZ=.+2:1+%"+-/2<752I3051-4705?74565816/,*..+.5-024.53:1@VC9BFD?AE@60/(/002-,.*)'#$'2/*)2Q-8&-'-09I:64-+.@-&%('.'#&!$"&)(%$+$+Pg05*,jR(D61$'+%' //* $$%&A/&?T3(%*))*+,13.1726?>@A>DDU?>LS>5GBBWL@?G\NkDrB=;6."##-/45115/:5;V1-0,,*)-,,+.03-,/91+.754?8<;803/-.0,.2,.0)%"%-'+,'+)2-52/+-+1.,742;)?4%"#$+'&$"8$!&):' &L`/.-/%.,@;03T(+2#*(1:!##:(+:5'(0)+(%)C&(,K221382O>5;SIAH:@FWI:DOKg<>H8BB4K^VrA6B&#'1465492697>>=23601,:_:1*+434/327G81,-,.-447;0125B53-*+))))-8.2/./3--37918B@3370/)1..*.*&&(&+*-++/.40-:/*0+((.3/*-62'7$!#%$#%'""!%%'%&(;,(*2-+,.02((?4/.*&$''&"#!$"&010I-$#/%/(-5M)((310126:y80BYDH^KBFGB==HHk9;6:>@Dsn`eN@>-).01<447=51;F8221042-@:5>&'.11-2C560]15..0-,0021C51+-0.,)(**01-..(+,-05L1+BN9929,(/,-?+3F-,./(+.*0+49923*)+**/,,+,5+'$!')%&&$!!# "&$(1762+=6:+.4..4-5%#"((*AQ#""Q:=2$#%'(%&;6D*'$*?:0,441./,,+5%)*-(*6));621/+-:-'('-0(0%"'%%#-8(/-K3*(#-.66E=02'& )"$$% &$)1!#&+"&#&&%(0@#&$+0/24A:O.7+).+/,+$NP4((5000:584//33752200+***))+.U/&+('-,(('.+-00.<,0-0.&-)2575[Pcf48;,*,+02)-)/*1.(/,$*K/B0,*4.&:)'&#%)-+.-*D70:)#2/62@E3,.60G*! 5&(#-,$!%)($$&'P2,$$$#7++*746348:8=;IJM@>QEC;?@;,*4E59BL?WF=T639&//-56?<071>)+*,-40-0,+++5;95<9676D525/2MF/-)64.0112,-051)+'++/0<4104,*)%!"-/12@I=7;;-0,++**'.0+-?+*:,6((-*/02*/,&$&$'')(.-*QJL4+4GU4+)":I4-")F/)*"0 !)'() &$#') !##")*)*JP=-4:6F:;7:DGA><:J=I:?890K*9?LSDHFI>J*/?'.0I830/D*+*/278++.:+&0ZI?MA:4;B:1-1.OP681>158866655:7.(*+0-12011C1-$$2371C6@5552238-'((**1-o//9/+(*-'/19/70-***.'',5IGP{X4,GC,*;)/%&.-,$J$*B$!&  $"%J *%)('$&"%&$$"&*'*G372.36113?:D=7A@DPB/265@CAJq_:@.0,.-4..+,/..C".410/24H523?058/)/,)6-+,'+,--,.6..-+04,'%%&,&.+*46>P dHly""&'(>%$GWU:"%)+#!!& #$ $&-/""#$'*7'/(('(073-27124<:23<6A;;1<4@BTiWa=849,:Hm;2'('+6+2V/)5121191./0,**$.553651B?10*-::64@R?=@OvCW;:4125?50.-+20-0-1<3c@,.405682h3,6:722+4,,2760)()11-=E2-,+/+:)**'-910DkK=?S299-6*1'+)@11S,-/2.1-+0-*8T.+@25093/L1&&%-ZL@H05&'1'0>/#&'.2C2472,,&.(*,%(*S46+7G::.(* " !""=C.+! #!$ "$'(.*%)/-303,/121:8102226?6>B>IhZUkPQ8,1/44>+L1+*(2?9R8722.;37?C4100/3,0419?C<4273f:7;>CLQd^Vm+*$+H-6%%*#$+#$%(>F(4]AT@:#+ #8)*"0- #$!'J#$3*))0,*&(,-5CE+/282:.4<>7F9032G=9/:..,*/:.-63-..+1:C*'2$#4+35*18)+!#!")&'1FG# R!$#($@-)-SLM?Qc:2 ,* J") % $#"%""B!$+&%)-0,.)(-43b4004.929796)C<(! "$!50"%*!"#""#"%#,(&&H7,/).11543,,3.O50/2915;CgP\RME617 "*-,*3)+-849AAB87341423446749A@SA;69@jC91L41GG32.--/;/AF28A201(*)9,;,(0-+$)# ##" -+ ($&/-&)%)5-)#&& #%0,*9 !""$( & *(/$%$/(*+/17*7141,07552531F5Bd$eF745;76776>:768=38/-(0(,..+)$'"#"',"#) '!&%#+.-*G4+1"  - (!!;N5= 1 &"$"!!*!/$"'%(*+-01.-*.+0*37,M>6556??L>CF5B9101239=/-+.-240-85630P5>7=^9765::521<@;6=L82545DE<9ODxI72=3265<0368AIH;<5:857.6/2851-1O;69O4A078;938=9.31,/--*.+)'("""' $*% #"%)$"41'/('! %(S?#8 !)&#(%$"+&'1! #(/9B,052G1-/.(*-0AE>35589@BIR@7L;:4B8?JY-&.,*13//*7/1.:7;6>JD68OD<@4788880E,(23U@>4;-C467D5<85=8?A4=306/32)C.--4$'*%(!!!%+!,1,!$$$% ! !"&&)'")#5" 0 E" %$*)13A)1ZD1+.,)((-11384WBB9C@?99=<7:;>@??-)2-4/3,'2(:0*0./.,BW\87U?815<6D605%,.-18>629049:=96MX-/1462?DA88M28@33-.;E6/2:8;650rAEG[MA8,/5..'(?4)0$$(#$"!##%''J%$)!!*!3(B4 #"  -#!%'!(*+?:64'06WQ)'*$*,/6:I;RB?96>8GIF=?5B]}H70-/32-:/3A-,,'7-+,1:;BF:B<30557INT@,+,3;476.0-=GT7:3I?*(/3:B::A?316M762779JGVE=6@542Z@FdkV<@119+,'&.+@<(%$##'' )$B"!'":%*  "%#@T-"!!$ " &! !#'"%(@M?M;/23()),%%+*225>=GT71525fAITES==<42-56.,5>I4-(,,:/.--559J;;85661572MBA0/459>030.2:?727=C*+).45823113154384.41=92:?*60/7=K{H;13,-.,$))*8(@8*g( !!#$!$#&""# 2+#"$#!! #,Y+"'$#%# '$8Q:,ZV;O,3,*+.+>9(#6##42W7Gm5;<5Y9/53FD68/,42O1, !$81"2,5##!%D*%'(#" & " 9GK')3&6\(&.0P80++,A.20.4#%$"3.7+682/AGmFK\hd6435.-,E:,+@99561.)*.,-/.?K822@A253,)1023,+-1)061,,.+.920*.,133@1/22/=<<262D?33?OD?12,0J6;:3;,5(3*-&)+R327@C/0p=+($("%BW!&.) !%0%&%+'F #%D-<)&,#'$ ) ('=1&&#bj&'2%1=/&+/0.,02,/"'!*10-4+++;;98I/377?3*-)93U1523(1'="""%E1'TI?1>fI)( '6m+'%+!>!!$,%$&!''B=/)$&&4P7DB%#!",(O &&&)&:'0.%%+>`D9.1,-'#),,>>.:EC1?3VPB=2'#&)6>8,;()+/'*+=+*+117,..03iC<*$&$%D6166,*,'&+1)1204+.00355/3?14878F897:?5.01;,.*7-()-*3.%#'<&(6+%')3&+@@6Dc0&"($'''(9';*##1& 1#",-+J,+DN6R!d7(' #%/:!  "'H$&68A3A(q6998)$%()*0)>F,/H207.'&#.-(1..%)&).())&/6+-/.H+0,),?oK1.'%'%)45))(&+1,9/.0,/1/0-,015,5;4U:C5f564773*1@0/4--$!24'&')%)>(%#'&"%"&!(>58)4.)!$!'%$ "/(!)#1"*+"28B==AR9J}5T/'H1H&!% '$ &%""3(2?CILA1*&"& !##)%*%(&91IN/1<2++)())3/,(%"$'(-(&./3),+&))-,35&'&$'%$()-/++-*))*..068/20,,-0+75=884AD@:7214Y70553:@21''$:#".;%'(*&%!""!""$Y-$6).O$(&"'!!*+"#(?$S&&;.28``ROPI k7RP$ #.J#S3!!$**,"&+3R~VJIe4A)2*!&$&%&').*)193+))'.9'&!"-*.,)'"&'+($+)Z*/+/).02"% "$('%&+;$'C*-)&,+2'(&*1+.-H1018N<4;5T6/SR>O=21,Ia?/,-%)+-.6C(%'*,2#%#!"$!$0'"%%(2AP*%+48/-! '3!%#!%o.Ej rGM'&%&%$$"#*,+)(.'(&,$%3)'#)*!)$)#$+'&11&*+%*J'$014:-/72:1075799SOV>4<0/:8A3-.R0&,/DE6% #+V%%%$%#*&,+( #%6X-*.""4AT'/--# #'%G+]CCM/fhX:,M&<;=## %#$%#%%$##&"!%$)''&#.&'$%/,""**(#"#!,+'!"!$,!& %&&#&)+A+%2,*&%*1;7TDRodE0))-*5F^BH0C20(%'/!"##!" $"!"#'"%"F"*>19$;)##+& `#9/,(:"$$"@$%-2%)3$ -}] !#!%>,(%#%z5>&-+* "!$,"!,$(#,!%"%$#'&"&+')&1L"##/'"""# !  !<$!$   ! #%%'&-7>:('5(*124cnvg[/-.$)5&+/)0/8%&&#%$,**'#! 65)#3% .$!)"#"(.#'#$&('$$!#!$#!)%=&3^"#+'! ( " $* /$ +%! "$3<;mM*.,2/1..uaeD3*))%6)"!"'2%,6%+'&&&$# "!$.!6J85@I* &!!!(!".'))(%&"&).,#"1#2*;0/ !#* $2(%0$$',(&%! ,(!&"" '%(%%#)& $!&*%!!"!A""# "!"!<'5&)#,0%&'3/WIW.%$$&.'6&'%01-O@3& %"("" )#.&%$#M-,*!4! )!!"!,#-s0YC '+$-T~q?$ "!%###)'#+*#'(""( !%&"#8#$! 2 ""  #"$-"$!$!"!;$!.>A2NDo'&#%&)',# #+/-87e" ,#"-,)%7#8%&3E"'%&*""2*!1i155+!'/F.QH5*&%# #%)*$"$,("#/)%!&#$&&*% !%!% !!$'!! -!!E&)%*).J0PNQ7"""01=&".($E%&'4 )!'5$"#(""$3-#!"/?'($&j&2G+" :!'%!"$80-C169.$)#&" $ $ '% "%#!!!'#%!& #)% &-:,6#".CZWV#. 6H18+ ,8.!!1 $  %#* )#  ."#&    NC*#!)(Y(27="'"2!$ +$%")*%$1@N?B+! "#%%!*!$2!$""#!%!! ,  )!2"$#! x;"#* "% *8&"L "+#5$!0   Q 4?)!#& 6)!#<$%/ !#" 3#$$#/U?2H !$!"%!#!)/// '# %!!"% !!,#!"2 " 8%*_(0 $$!&,!$ /&!(" ((;F0;#",)+'$!! %! #&'%$"&@2,-F## #""%!# ("#!!'!  ( ""*E!'!&%(!/  &#"!$""*! # $%!"!&%##%%&"$&%%! $#!!-!#$$#('8(#*$-.')./+(/1T(%,1-;ADUy\;9>3FoA+++-(-,/((%2 6=))&'&$#((&/+*(',"'(*($$%,/&)'&+&()/15/21-<&-.1/.)0/4.8A74),$%"#';L/17C=9<2:>2496'.020:=*,23/1*'/'''34%'" !!$+#")%! "$" ! &!% 0%#%&# #"$- #,"!!#("%#$&"&)+)5-0"(?,)'++#-))#/)4-1,1.-824,)0+*)5+./501.,)/(&*$!+32&23N84I4MNI=I?>;;/74*,/574.#$5,*.-UDAIIE=GGELSBD?CP9@4+.-11*,1'/)*,(&%! " " *E""(%!! %#!"!*&$$&!! $'&)!!'&&2.)'%#$((%+*%/-(-.(57/3/5-+%>?,,0*"'(,.4L[408UlJM20//-74(++,'*&$#$"+%+-+'$&0$(*%+'++''(+350-3/+0)(%$+,-78737A988:2:8395C:31./,,15)%#17C038=69C2;IF8.,*.!%&("#1).3 !#4  5+'-  1%! '% "! #! #*-!$) ''')%.,/@- -*''&!/2/<@,'1#" +?-,33+62(,/04?D0*+1*'#%*(+-,-,#/.# "*E&"#!"#"$'%!#'*+>0000,,5(,#"'(+,.(,38Q:[:77>E?<29E59+6[?K9,@-*(/,?>MRQRIELZJSBDU=DR`43.(+(-$+$*%% "!! -  !#%%!%'"&!"" "*!)-!(.'%/"+%+)*-94*&%-2*)%&@?EgL-$!!$!&2>&-(-)0(/+-350,-).-,,')*--+A2.%#$" !!$*"!$$$&)"&&&$,*$(,)(*+0'!,.4,10*(-0PFEHF?I;=<:F@+(+GI=6G[2"(50)06,-4JFFSQSZJNKJR`k[R@:0.+-&'1*#&(%##%$$#&!/+%;# 0;M%%&) 1!$$& ()!#  "!$$$>#$',"#)B3:B3-R1.(.103B*++0'3>/-)$!$&(/4*++28-*,-/4HSMf<1.+)(()$&)()% )!7*: #"$%" $&"'+%#&&**(&*&%$$#&8,-097*03++#*+HBWK@B?@8:?>A.3|B=@22FFAIHL\RFDjJXY[NA@CC/.7K:1*$#(',B  ! $"#'"$+)'! 5:,Q4%# ?1 "!9-%#%!&"'"$-/'*'.;M()'B5:+0+13+/B.138.1G95),/0/+('#&/1+./.0,*$ ,=/9zF(+*"++ >J')*6.5%#%0)$$&'%#%$"%()%"$#,#$$%$&*Wf*L{0**/431-0*378<7?>TP@CLQ8T3/1VJH;L{6.@JRFh\ZVJEKJNflbiG<77.68098)#'95@/ #!!!!%. $"$!"" !!%-65#&##*"8!$'&-)%# !$$'#%)+*CN?O=A;DDA2/>f9@P^6*,D?;h{J E?DFRdY|rC9I>@>46@9,+,0-0%#"!"" $$$%"!!"#)" "!!7+1%',3,/'(&)*"-'# *#"0*%,&$8,1,;D-B9:>TE/&##&2u1((0(')'(6O(#&('*6*+*((."" !#! !&?&"&$%0//05#0.?'&%#1()*%$%%&'$)%&(&&'(%$!!$+'.-3-17/8/110/-(/0J:;=9G9?BCA>75698:PNM>-43=@JeSeHABVU`~qL>22<=L:88/-8033,&# #'%< !"&,%"   "$ ) &# !$%, " "$%&&*($ "# ##(%*.D'(7#!('+*+3..719ONY(F(&"!''&,$&' *!$'(%D(,3C*-(;4(*) )&%$$%#!!; !+'1*...,,&7*=()&!%.+((")0-%%&)'"(&*'+%#" ($)G1LEH123401..+,+)474:B<>QNH;:3/49BAE@7804:88LJYpLV[\MTMJC44::=712-((.07/"%#$)",+"%%!#%#%#"$$%%!*2 %$) &*%# "!!$&)'(4,$/+(0-*.357/028GT*74.(-'$  !$$#"$!$%(+',-(*/@X()-E'%$(#!+#$%%'&"%$((3'()9.%,<('""&*&+0'-&)(&&'')1*0,+.(&"$)-,(/55A654212(+***:>=::7?GDDf30.>KG5<74.8:62+.D^Zew a[MIA:2992.2,/--)+34($%"&$##$"$! #!&! #%"*.G(#""'# " $&9%$$""&"$#&!:.<,47/254730$-O47.60*'%#!"##""!#-/0)+2&%,-0**.E)"$A!"$%B!%" #$ '#'#(*(+*'876$3)&*&+-,,*++',-/.5,3*),+%!#"",+*$%;a20054/0. (.:C@7ATA9BA96217^KVG78029;03%'NNX\ SMUL97387,,*39,&(,*?=6$!###$ ##%(!!!"!!$0/%2$$,'#!!' *#$$9#!2$(I;(( "),);',**375@=6J4@)87--/*+0-1$!(,-"%"()'(#&*'%%),%)(,()*$"!%2""&&%#(&%(O&0)%@*' "'%0m2*+-+0(.?()8*+*-.3..1+"(:%*)&,2,*(%/2))+31-1-*'--095N;@C9:C961466=:?710355-"FKRhPSPX<>>6?3*+>1/(=2,%&/,&&$"'!(<&+'#'"# $5$<>/-&"#  !# $%$%#>2.#$)*)$Q((!$$!$*'*-(,*+2@8482'$-el6553-//2(!)+,0'%.+($"!")''+,****%$(% %04%$*'"&""%&&1(")*'$#'$,*+--(*--**/++))-10/110+//**,)',--)-('>',*+342-.+(,)-;GH>@=97E>?34-2J6^E211121.%#*CPMXTQVMEKG:H7>0+*,**0-/)($$&%'!("",%%"!" "&&41(.-3:!  %! !$!$$4.n32"(""%&$"#"$*!'&)/,4,228?=--0+Ja3-J0--!*&-1+*(*,*>%#$+'()d))&$'"#"#"#&-)%$)$%$#%#"&%()%"")(.2+1+)'((*(')4*-/**/-/3(15.12,+3:@4,/+:1+)%37<43/.0&*/5M:@S915@?7555L4?;6.33445,,+4pwwbYQVMGE;30556038..@+%%$'&$#$ ""#!%#',&% ..&#.#" '"!#+(*).*,>.$##)"$'#!(&,%$''%&(,00.)12/63N<2a`9],#,2'&*1),,..+**+(,$%#.+%''(%$#&($$%##!!$($$%#!#&((''%#%3+&(*()*'&,2.*.0.030)0--,00:K.255543.3385./-20727817=332.27<<41=?8478345:C:89621.)01`{_RP][VUMC;N52<4CjH.4_*-*2.)#""+F,%",!$#("$'%)%# !(%# "%*W$:5%$,,W01'"%&"&$"#6-&N&)#((,3,55-*,&8E.[m>p9&$/*&#'0*,.84*+)''%-%#*6(&#&'&%&!%$%&&#$#-' "'&,% "")+%,5*)7**+&(,(&-7041/4.,6/..*-.,*153=317067744/021-0512;1;=6346/8:9436B2>/02./20.16.1776780?/2;:69H=L8;66?643115440)"#)6KPq_MQSPJ\8;B:76/-*(#-0++04,&&,%*(+$#$# #),0$$'+0!$#'>$.3($&.+,*'+!$"%",,)&()%'%'3(&')*+*'&+ &1/6/',6(),**0+31209//*$"&#*%%+*')*/+''-/&(**)&'+'(*%($&-''&''+1,.-),'(,+-//4/0176=2-5E4/-((/3H6::U@0/2600414-/./3L43B@2568/+58:3DE@=<=;3:97646<9.,/&.8LC?JfKcE@/98=;2.*)(&()),/<7/)-'))'-'*)>$#% 9&&) !! .-! ?](.&&-0(/"''$ /)*!$'&$ "&)(&,+.'$$'%$#'''.*4F:1(3,+/.0*031B-$)$!!-((*+1/*,0E.,))238,'-.-.*%$&++*++)*-,-*++0++)*'0.)+,9633A8/01,/40*/2:SG=3-/1-6675?103313,/2;6843*3+4248=9F><96875888?@501-4=6D=I\[N@7B8GCB;43>+(+4,&-C1$A@,*)(-,&%#%&!#.4#&!$&"3 !!/92'')(51+!'"''!&2''%"%" '##&4)(&*%"(,)'$)*%"32:W>8D4%37//.-027.()+"'$)'&*+(+0+25-)-,1-/01,.)&6,-,(*-+.)(('+,,,&+&)(2+,003d=65@A4.0,4/))@:22<9B3+../39<7;343.-,-0??97:-'+(1488,-,(,/.)-+,(4CH/.#%"*'(""(,*(01#&,/ "!$"'($SR8%*<-)0/&")" !$#'#& "!'(&%&$,(&)''%2463Yt839+$-0+',,86A/*%&$($)).)*-.(-/7/10/4=;.2+,/4@5/21/06,*11,*,**.1/-)@*+=314@CM:6.402--+,9=:A4315E1/502G860<>/+/-.GX530-''/203:?F@7<93686==8:;=53:?FG>KICNC>DD_BO202,,2//*,6+#3.4-&#$$%#! #%ID0H:0'+.%#"!!" !*&JMA'+H,/T," !!!!&)"&#&,)+&$)&(**.*&/45^1 L5/3.C3#%,1-=-3),&)$)50)*(,/A330010-.323453>735G<4E>8;94002.*(*.)0.2:75:1-B[M80+-9..-*-3/:240.;46.39/@8<1164402.0:3113'*+),33?B=B792889C?>/1,>q*0% "&)## #"")%$2*$&*)'-&(*+-4.44Bw_]l?=<3613./2-3,&(.((100.+,+2/3E-//;;;5C0/1651?>B:?<=D27:963371=-+,+**//1666F1;B0./1(*(.*&*,9,0.CF375<0<5;F367@356408544+*/+--<88*%'(($&#"'-&#C#42(.#$% *% '%"+%%'%$*19*+%'+'##1.6?mI1`W00<2646<3.+))1;++3,212/-/+)*001@C<487426265<=4X84930252.+*2.-*(-.-,-,-/+*(364-SA7..()(*$,),7F=32A937EWP75C82><32\=32.+('01<7Y778::;;>8638::D886QB6=N2:@f&hVK3208;7/.0+$(SS>A%(&%&$"'#! 0*)%*"(&+..#! !$$*(0,=%#()$$#" %'"$&# "%&'((9Z.)&'''=+HW=:Q_WJ9201..=B@97,.0B2**-&*720106211332894:<:516976KI7.20+,0/-+--]1/.10**1D/+(*1$$1=@9,,88*,%.&+OE8>H*%301329FA:393/233A2-0-/%---4=9:E99:6::95,4::>9534/.0E88If&wwS<4023.1%,*&((#)&*%&(&&'$''#'&&"'$+"%+2*6).""",.$'.(!%"( ###'# %% $!#"('(&$)'/8,**&*+3L8<6jT=?43..0+/4?C[NE251.8++*%/303-/3.-5;869S;:67788:69>3-/0.,N-//-15/1514.001...(''&*4YQ32&')*#*&&(,3;4!!&+57?8:B7/)400.16*'+E+#%)>%*).1)$9830234;77=45:4<;421653.,,367876///2262350..-0.,)&%15@:/3180($&%*3$%94CI<@E=:94613856638>8?;8,%$3`~$jYBCC6-509.&#&&!'('+("%(#!%(%(!"%)*)+3I*'&!!'*&#!!$&(7'(&&%9$- #3(1&+*'#!&(%)(+,*'%4;*63CK/A/C;AHB<0.3401()),'5+*0034:;UA89669S86469:5;<=<>91*39833352510--320.11.-.2.)/0.6=462//)++6J2578@H97-2:41424>Y1*-K9I/ "-0+/B'.W<>:;8598<5/47:769C\AX/"#!%\tgNA8B3./-/'3&'&-$%+()"+&(((#"#"!%)1-3]=&#$$%##"4)""#!)')98I-'*'-!$# G$!%*1%#"1()7.&(("%*$'2CV:375UG?]75;3471220,216339=;K>WA11/-2-,..,+711%08=145710854+10O6,#!(,/.(+&)C@:99=777555878;>?B@;-'O1!9KSUSJGJ2<0*/32-)%*#*2$#)'0')*(&&" $%*$'&%*/%3-1-%'-!"!!$#%'-+%1OD%!((#!&!($+%%.1+%#!!!'+4.+'*$ %%)8HJL\98;;F>R94=A0-010:323<=>;;CACF=DBC96=:87<>BBPH?D<=C:259C9376130.0+).*+,.001154BCF4F/..4;*./--)/2*6?'+47-F/43-.042:6'$&+0-..*':;3683D747=4<:9=@?D92+'2PI3T6AVPH]=7/-.*=01-&)-)H((,*++&#(+,&)%$&&'&$$-Qx7+)$&"!&!)'&).)%)+;8 "%'#1 "&G?0..+7$'%!"")+./&"-'&(..-9C?:==E614:39E9,,292;90:???<@CDE:@M>C;;=@ALIGRL=9;@E7I?:A;401.+.**+//11.1/+20OOHA22:?;=1-*-/F-$%/-)-5E4+)*>-25022.=2..0+00&)16972628=587A9@<<@2%,1$56:XB?NfJM@7267*1/+K((0*)'('+)'''0('(23-%&&%$%D|+',&# % #0&11?0@*0((!!!"'"#''9F:13+(##(&%.(-,.+%**,-(-/0178HPQ9B<8524.2269;I36B:`d?),'4'&(401/-2:345655<*(=57537>380A:::926)*"&,=@RSRT=:0351&.0-2+*((+(/(*"''#%,*&*Nh)*)!'(,@)%## ! -.%#KE&%%)#%#"%%%!"$&=@:.0L&!%$%"&'$%5""0#(),.15163=;D:98<<9;C>AEBE@>HGNKPIMADI>aS@LHNSJMDOJMGPHOP@57;>=4<7957811111220),&)2=55.-3858.2111B\831.35/1,,4,/-01+/40504=RG8,)2/60479;423=>>88:761.)"',+9GLQLF9;123+,4/.'+%(($*+#&%#%&$%$.-/0,'((,*$%#! 3"&048&.*.*$!!#&#%"'(AJ,,*)%((+=)'($%#,!#(,588R9`ANA5?=7?88:9?C:8C=>CEJJCHUG?PJhaJHPIPJKNNJRM>CF@@IC@:E425)20A+7*:/0=5CJ6Qd85<6;DD.+37.47/363<74:@<79;:/+2'").+WI=KTD;38415-1&+4*&&%,(%%"#$#%&)>,|>#!&/5&%%# $! $+=&%#"#$.)%&&%&$$$##'?L+;*/,1'%.,'&%&#!'#-+3:67@CWNG=9@B:>Z@>J783??AACBHHHMAN -^B>@OJMHQNGJ_@@GB99M932;LIE?>;;:679B943?@:03.-7;99887593/37:966014:KBL==570*./"*,),9:36<FB>@=63<;>=dQiFO?EGGJFGIJUSNQQPPIMA;27E@J7?MORUDYF=F;<;6:=<@F864869999=<=89;:=?J<;67<>11-0,,(48/681/7BA=87658.,1/..7&%(3'''## " %$%1:R,'*!$##0"% )(!"&&!A-(#!,;*)$&%" '?%#!)2/*.X0+).&##'*&!2;Be34;>SJEJWCHEKKIDNRQROfVRFIJMD31?Pd>KJQE=<8FB@7=>;>>9=872658GC86>?;::9341")27./21@I6D9+(.41,;" !%$&(!#"&1#%#/40*3&*&#!#'  %#-#&$$7($).8$%$$%##!! #!$*.4,.0-.(*)(5(%,79D@=<8EL]YEG>38697<8>=?YLBACNny?=9?BEFLVmbLOaOJe__XZNKLHMRHDOWMZUQONZ`Q[VJZSKICA:BC@N?;B7;G?>>D?EFECA:D34SB15=D9/043333512430104208652K766<>;A:JM>4-08<;??70+0' ,//98796.*++7/<*'%''&!!%"&-"%'.)0''%%" #$$!!$## (--+'/&%&&(#%%(!#$6)##$%)&3.&,&(/26085:<:;>:9NMg@ALCDQLMZ_dVMJW_ZbW_\PNJPOYPoKQZ_\{}Rfc`WUU^QLSHAHA=@ELDE638AG9=@47:88:@=>=;46?*#%3.8KCBS=9;3++.+.)*-,#&$#(%%!!#&'$))))''"$"" !!! "'(%&(C.(!*($)'')*) ## ('"$$ (2,?5,+52:AEAGFEGKadB8>@A89B<:;;>;?1/!&0?6,1:58;3-.17345.5240-/*28P?5A>=-0368:;F>@Fq:5D5!)3;KFE=;4-$)*--/N--#%%&$%#&%*'"&A&,-)-!*(""#,#%!"(5#&/,,%&,$,$'0'%%#!"$!$%'&"&$(-87.3/2-59QL>9;<>Lsa=9630:9<20235384:7>202-?4FC4-(0++347;=;HCFTmLD\ACFMZHIJQJaD>|ywt ZT^dmc`P_gf(qTVVMIjrv`Jaiy{_WUV`][RMLLLWKKLXNJGCBCD89E4(#&078=5790?KA:62,88<;:67;23497:4479@68<:3-38%/2586?>\JJRCBKJKFGEMVk%ovhpIdunliONaOSUh[drd_U@D\djXXUokeuhg}a]UUT^QLLOQRPSQLFAC@:B<)" 25&"2*8?YF:8965.89::8*#*2FHAIVOjhqtccneb -r_`YUQZYTTHRZW][KQUa_g|xr^S_Zlpend`_ocNU`g_kWQPOKGDCDGCA,+/6:BAE=DHMA67'9S'4Q SA<>>85A<<<5-)$3G@D9?2,62,-358==G@B>:) (*A5;?AA=/6623-/1**'("''(&"&$$+"(&& &""$'*'&"$$*0&7&8O%"#')#%#''%.#)$'.2//(#'42KO3+000/2767:736697?8D]G9@7?>@B7FF>G=?7:(')09A>9;9357@;4/4*)(/)&"&$#$))%$'$-"!##!$! !#" %/#'D[%#'-6/;5;))/*&&(%&$1.+0.+'&+20,+4)1287>:5G634<;AMCB?=C:/481DT_=>@ELFDFFDIaYYXYYbea\PHTLQMLSQSG[]o\^li[W_icXS[c[V`f^mZ]pmSNGHRPSQPOISFOSOVL??9:=ALMLK[F:ACc9/7CEB?:301*HC)1DB:?A7157497B>=>AHC?9f$/-37EB9446@866@0/0/1'$)'"$'&'((')-(#3!"!#%*)!', $** (&8<=DxrU0,/)%>CF%,?.+0%+=&-5+211:9\J8482=??EFPA@LSdWSWU^a\WKO]WTSPMOTDV\VRW_q`J[\bk^]b_^S^\VXO\a[[QJONTPNTNQNTTTXKMFB?BEJM_NJMdB@?>::@D==5,6<7EC=(0K($3:JN?LH/.5769:>;>>B?79, /7@E98594:8;9I7,0%%'% "#(,*.&(.)$$$" " "#%8*&3'%%')""4M9/=oM-($ &12Z(.2-+519'6/.L,.1A:KQM8=EDGM?L6B@;742011*.&"@BFQQGPFpYHRHKPaZcbfSWOMW]_]UJMVLLLUXPP`[UN[df_ahf`RYW]``Pf]Y[WPSPNFM[HLO[OWU_QJQGIGPS^rJNRLK>>>?CB?A<63:9?LB?>,*-08r6=Py@34/4:7@@AA@B74# "#07<;3663<;379c=3(#$#%&$%)&$*6*+'%$%"$$ #&#%5! $$2')%#O;2H@-'*+)%%''?.1148+2163*+,>2P5148JQ??>?OOWJC?=874561A:.64:13FYL`kYROQROLOORXeVUVXZFP[m}HFDLLWILTRVV[ZZ^ei|me`_[`fY^b]\X[WPSOKKJIKLMHHM_WLMJGJKMIOYUIMKOM[N;@BDBAC686<;@?5B4/*/9Ln>AC@:4569:;9?E?D;69% 03639A89=K88:;6-)'(%"$1$%!+(1'&'"#'$%!!$) ! !&$&J-(!'G:0)2-%%$#(0@.0))0/11/072-/.9EC56NLIC=78LYTD@B:9805AQ8C6.48=417121:4B>@60;<8:<=A;<7C8- (.6:<8889A?<959491-'&%)$.(.(;'$!!%!" %$ #$&#$#" %&&$%)#..11-*++((/14+13,2.*)+)--8AI>:BA;:@798963:FEQIADGHAFTXPfTRHAHKD\Ta]PROPMHEIGFJJ1BECF\[VZUUSUVnYetuf_Z\]lZ]eckjZTNSVTRMDEB@ABEFGJHGOKNUOPPKGGNKI@H=>.+23(,-8,))()+057>B;;37;=677;;<7A@=73303484>EMKNEaHEFR@AGAAB;7?ROH^^XXXNRUV[_\`_^^ZY]Xa`hjexul^_]\USJLHDDFCHHPPPMHKPVOLSKTRNKH?LC??=<>5<<;:>DDA<:471-25A>:.(*5=J5D;8759:5630($$%)-(&)&&$,,"!"+" !%C% "''"$'+ "("#'$2(--.*)-*+$H.1).*+549578:G69E967IKVRNB?BBGUw`WXVDH?NRNYLD:3744+/79G223+.6?@:>641-106<>O:;8772433,+)")($#.,"%$#$'*(!$!#, "!%'-&$$ !")/';"!)(O'*+-*/();'*1+'+253?8?;OSUGI?JA<9@>@=>9=809512>EBXTAPL\J?@BF[pZRKY[PLWQR[RAIB2.03/7E=34;CM_]WVZ`[V[\QWW^jpmgjWWY\_daflpuhdfW\`[XQNFHJHILOKFJNQUUQQZMLIJCHFCBG@?57729;=:<@AIR0+,;63.-*)12H>?@??B<47%)!,68:4788:70,44($&,%)()$&%&$&-+$.3&#" "%#"',&$##&&0&&&')*)G+,.?-0%$)+((/0/895BMToxfG:>?BK>@C;=7<<8/116=DATMQRFTcQJGJJKYQKAL\dZWm^OBGG;0*,+27759BCHIST[VZ`c\UYVR[_blfeac`VSRU\g`]ogjadijihf^SSOTQLJNRJKNNOTVROOMOMJNKJGJGD99;9@C>BABD?C>/*160.,#!15?C@@CC?;6.&!#1,-:96AO:;36108&&$+()$!$($!%$&$ $&#!!#*.-*/A!#&"1'?4#'*+-*1+2+8.)"$'(**/7H866;;koM_GAGLUbmr~LFFRC5/,4649:CNJMKYPPTefdo]\eg`hqoogicc`[TVbnrpejlcdjlowwk`[aYVPQORQLMOMUXRQRQKKMLOKJRQG8-9IIGGCG?DG?>8-.55)' ('5;<;;AFG3203-1=/+0776E=;42.+)))$&)&+" $! "# &#$"&!'%%&,))%"*#!&0&#*++)$+2G'%+$%#!,/+HFA=72?L>;ABGTWLSV[[QTdrdrZdw]afojead__XXXh9 qkceeaelmihlilqa[NUQWQNQROKRVZiQMLRNVNLF<0/:JDHF?FIA@B>=9282("'08;<=DQA>;6>E21;5$F55:765:1*')*(.(.&$! &"!#'(>3""&)##"$-2-&(&I#'*#.(()8)+,.*%#  ,3../449:?EBJJLf]KQ>=+37ccWOLJB=?B@9CFENSPNVPQSTRPXX{~uh^b]]agge[VY\_nq}Bnef`^_ejpkqhgkptdXRQWTMNYTQUZ`WbNOHQVROHG7-6ADD>?AHFB@7799:<-!).9>>>=?@997?@DCEKKQSPRR]UNRU]`cr lc_Z^_]XQNVSWlrmhxto}onddgnpyxwngfsoTRPPPNYONSZabZf\RQR\V^LB69?@D>GCGJED<;??AF4:%)-=M=BN}cNHM=BAQ=<47:63>86=I=DA@C@@SLB;AA^ZCKENBHH@>GIGFSJKD@>BCSMENM]VOTaafl\bgbtxfXm{ocKDIGJS\fah\UV\ojxzrjVfq|xsagtve_YfQKM^MQMTY_`xsh]_YMF>M=8?8&+8G=??;>@5-,7>;78>?J=A;BB9:8-3.65'"%'+)+*$)/,,'+)%&+)+%,)(&+($01*+-,)-)0(.--&'++-2)2A993KFNlXBPHKPGCOEAOBN967>54>?<36HUIED@NEY8<@F_\UG\aWQEJ^SDCDCF<97FJSJEDLPVWPWc\]`f__jhmu| w]@;CVdehqxta[`\fkspoejmqnrfl~~hd_aYSFd`dPRPY^usztY]XLGEE:>LBJIMJFFGBC7:B00(4>728:?<>=50+9A9CKNINN=;IL:?CB:83/)&())%'%$'.-&)(+F>D**)(,'%(&9J(+&(',31&,'''#'&+//6P7?=`IVaHKD?BHC;8>@KFG97K@4>:86:=?CCAFIHTACFTYgPULI^TCGGOS=857:D;GMLBIOJTVRNLptgWhTOTSSXajb^ZLNYde~z- p`Y^ejuxqwuzypx -v{kc\WUTkz|TLQVQarx\b`VLGAE@9AWHDGFHFEB63719;sN86?=B=<@B-&(-@GB4RMJA=5269?B=<6F?4/<2)'$#+%&-.1/./P5)&.+,+*#%),*$(''3:2*$"!'$'(,@/1976CFT pTIN@EA:6478PID>GAMKF<<@:=@BDNFKSRKPsX^XcTVGNVa\cb]\^icpm|(utcspfl|}wqlp~ys{wqgcXc_cZe`WUW[__failgXPLGAH16aNHHOLNWF6/A8TI]:><;@BL>>,*'#CRRN7JZOJ?95995:()($,-,((,(*//5@cA/+&#)M6)(0%5))(',=R2)%%)%'%'2,48@f;afOcU_G@A?:86152VFEVolcJDEPE;BBAGBXGB7,+06<:9L9=;;62/+JlTCHGQSE>>5<4=IQ>42//.-+2,+,-&$%,4//10;3()')0SM2&0&)(('+.;0,&&',$"$+45=:AH^fp -#H|VK?8?>>@20=:eYnvw{iNRPW^WUSTO`^IDPZYKOD@E@;B@7*)-48=9ABFFFO]VRSQNWVT^SZ\^Z\Xa[Y]kwrqgrupr  ~) evwvsob`lhmhbhbhcafWW^frhdn}paXNG=,6JDGMHLCA<=Cgj=8@A?A654:88FBCZNKIAOQL=>=9+$e\KEGG:;/380&3692AHILPJE9B?C>=B@?BBF1.311>>42-),-.0(,2/I:6-.53M>39B/*(&#+*---,*/,)#(6(.,4HJHzvsw`x5? -lKEC><>I90>?Ev $&osscrgmwbXR[KAMMHFC<868').@GGFJTR`^ZRYfPT_}eskfmllqhnecfjpqifq{y{vp}/.7   z~ x]^]dqohlv|hmoa`enmphjkbdG70:CBHOLC7+->EaC247.+248=<>@BMFLF>1!,58AAI>C?60.AK-2/0/-+,.,,,321+08/380FP0&[1-+#+"(5E--)1*+"%-/*/3FDHdgtu SRED:=P<;8AFBRFGOI@?>.>AeH?8,43:688D>=GPGU) $&$"'~n\\XMGIHIDGDGPa}.K6>EBF?=.52Fu=78<4/54<@FWLLHFQ<FPVa|+119FC641qfgdYQIDHGEAHDBjX-449;B<6CVQTYR]\dPk|sx~we<"$!/   -||~{qs nox}~xyovkcikuuxy -vrl ldke]dk\IF?<<@JG=C0)+)+?5.)3,((-&2GCD6/(11587+1T322-2726//..+=-37HI@@HsZOJFODKRUODJB====@LZp|FT\dbST(vjUZPJEDI<;CIDuN;@BDHYePLJJVYGM=>FA@=74?24677:,*,(F9.2**++.5CCAC1$!.D;40,-06341.466/./-,/1?>HROL` -YQGHIFVP_WOD>K@99=DLZn{'PklliqU2 -zeTPOKGG@59;GI;E^GIGLLTMQ`YWZTV[^gex}{upxrq} m#-,#A8!|uxerxphiqzxn tkq Wxyvnhuovxycghna]cZ]VXUFDFEILLF<@0#/@C9:.**%+06AJLXRII]hbZ=E==E@62:@<9754=-2/09731*+.-97QNUw:$#'X4,11//295.-462*,-0=.,26GKIKGHGTJATa]Z]C<=W85:7*--,-6462@I8;12/5L4;-98:;15*.6>HV`t 7bq~uk]># xeWRVLD3441+!H=JN[UWhkmgn]da_gd]Ybtft|!~  un}moohfkn_OLMOQIggi pitlWjelhpzsbnzrwvvyhlZXW\np`VPKEIGGFH@SALPQSK>?/4224;6>FFIPVUG?AZ330048?@CIXl1^s{|seW4 u^[NI=77750=wQVVfmvkrsfljg`kpknizqqx-" - -|tsvc[arlm\MORY^c_Z\\rx}zf_n{khXTpln}zgf{x{~ tUWcbki[WRNQLCJLOIPKHFFHCA==6815A5>lKSRTa^UGQpA@4011A)(4;9S;90/2A1E.C)/-4-?1))"%&+.,/(/2+0003;=`8E>EAFL>C>=9?860/1/46<;BAKW]fq]ilrpaK& jdfUK<6?@>60=DHRW[e|wkmrg_mpcw~{tt 0,. -~jon]QIM_gga]TSaefegc^^qtwy\acotcadVsqq qK}~| {t}xtlZahjbWLLQTCHLOFXSFECSOIL@056843E156J9:+)-;7;C:1@&%(',.*,)17/+.+35;A48>@1.1E7689=FQOOYi1@R_txaE) z^[ZLC>>PSB?EJBHQ\`gtwjc` vvpwwqz$  52$~nu} y]XSMZdejedc[W]iijuonjnlnbilbf_avjet~|~qWl}{ wtfbg5,nfnYJRbQ:OKAGJLHJHShGHA,9<6AC]=40-6.+52/4P5213*'1>9@B59?='+)(+,)(9...0.;:@A596FHEACME9<>N,**5<33167DBHMOy|6NjlFBf]^KF?@IKFOIMMRUUVeskol^\u ~}olqndv  ~kRPYafZgcckloruhjdklx{oqqytllukttvnfjssfTjpw|kk^QXkwv#;7$x^cgi>dnhYLRNB>FNN^OJNQWNKMJL7<>46>EFKR__pngdG(#(/5--7AEP@AC@C&'#(.&(,*/117,4<@=E9611414G*)*)763,3:HDFPhZc{#EHL>&^^YTYLH@AKEIELPKWo}vntu{{{ pnixztlbi`Yfbgigklomnqqwwoq}zssmjdw|sskoUqyqfqSLYSn|:\qcin|zlejjaTGS^sDITY\LKTVRT_J`75558>DAVShpimojOK3'(596-,;K@:8569-.$0+**./+.*190)/U=@:8421K()(!#&(').15402<>865A>>6436,++040+,+:C2207FDO -P?Np!#%jmYEFEABIJNK[V`a_n 2yyq~} -ztx} }rlgimjy{rprw{ sefiqxtrruvw{z|qneruzyvw`|owxjSKR,4pcncededwcgjR=O=PORSJKPMIIIFH=//HK>?GONim]Wrn4./31-.7:9:<.122,(,+*02'')1Hf541NFV9=0-@c*$%$'-()-242.06B;9764DF5047/,40/0-//0,3+.<>XOL8Nkj}{h\jl hVMC<>MKRijkmnZmput{ u |nfbab~ -v gb|il~zw~|qkjelqqlppoclvtxx{zzyzw{uvZiy}tGAcj|vkhphaU[flh^RH1DOZaEAMMRXSMD922.>OA@oj7>}WA3,,2>)&(*0**--620,+-05;6:3=6843<23@\/+,1/\2../8OlB?>8GHR^YPKDYTzdMH?9G:2./24/3,.,).,4///EY;96@;ACEMLHIJCPLkS:;9YRMQjk\YWc`qtvx|xijphijcl{ zzkaivmbfqx|}{{qmnlnljfa]^bfpsooowx|wxz|wlhn[PWhmn}~mYDg}wmNYk`U`ahxhOQ86ZidibOOHglUQA>>/;A@EE;OUOSc_]PWa7;>-.5*-)2AH;=474/+-+(',-.;O`Mn>Cw&^9)++07$%'21,+,+.5./61.248=596>3532,**+/3/1,)0+@N164@B;;BAHIFS\VaSOmJHMdW\gqpdl\giv|zzurnhhbkooo{ -}zyzbrhkskcstrv{soqpmiifjf`\gglkfmx{tosuxyz{|}vfYW\`n|ypq_?\zsRFXaegcwdTVPCCP^iniTKRITOMF;89B]4Ao:9ABDDMJKOZag[^ZkmeYUdnx|thlwyuqyeZMKO^beu{swzyrpuvu -pX~soyw{qiomeW]wdjii_jtrvvt{~zyy|ww|{xe^YYa^vytm`[ey4~{ \rhcehebd]QRJM^bdbW\RUULKJ49AIb\2>>II`zn\dp\S;7621:558/4@6432/*.$$",D/+3?^o H2:EO:9;762$$**,)-/.0@NB@?67761?<8462+),+&*,*,-(*@:10+:6/62;NTSQSbzu_TX^_w^dcrlot}pms{q|ZUHOQd^o~}qyxlgcfpwoTfqwexiqibfa_ZYZY\frvpuy}}}|}xz~{wokcVckhttqgdqx iajuve`aoZQ[PPZ^gU\`aURBLGAB>TyeBT8@JXig^XW<=(>F<10..1*.0413?)+'&%&;:1<:I[iK9+/U?<.68-+*),*-).,$4169I?Z<77681F3056-.,)),&)/)E<.*,2---)2@RYRQME`fYhf^adad~(' qstjnkzys_Xctvyzzvvpgal%lcnz{ahwLLP]]qmfqjkljpnl| - }{{xt~|{rrwrmcYkeenkpotu fUParsaR`bQVPZU^\_LVT`^A7XWGHo~_4>4?RCKNn\[P0,NJIC840,+3*,4,0,*(*1+2.),>@IZ>)$.218?)--)+2*)((),+)717N^KD?GGGVynLO496:44R`hL&8d`F@76./(//0:6-.)+),000*5=G]E3%&'-+/7('2)**'&*'%)DK>O^~H?7EF401160,--((&'(+*8.+-)3&&)-.3FIFUU^\}c_ZWYgmn -,ujg[etsh^d. {s qYhxvvvy}zq}gmY]r{nwiehomqgdeZR\`inpmml{|   -~}zmngmunehcT]lpwtw}ikROPY_fLMOS_aYUXktssvHNNHO=7QWRa0) *7=Je]/->HAO=87+)+142.2-.&%,1=,0.FJOH;LK8./+(+&&'%*+-3&3*,]\B_kMBCED?A8//37/1-1++(&(00)&#.,(0-/1+07@EQQR`P2a]hSP[iryi^ccinioxjj %N%tu{QSQsvz~'}koqvjx{jbhjlkoogpl[Zflntywy}  }}}skaemioh]WUdk|ewyytxvuZURhXTUX[dhvc]QegssyTaPR?D@:NCKSB8A10-(''%&#)0),&&2+-05KOGN_JG\DG1044/1+.*.,+(+1-+-*8-+(,1,';3?IRPZpNKQMTVgo}diuzxtl_`z~6zxpu|mjUOn gvUjimyz|ysfhlfhjospcbgdgnqv{  -}yulhhjvl_`WQfufw|z|~w`UNNaTdqgaehjUgizrofePRA=\::;33+-0,.+-$#!&()'(=?5100-+.5@I?=JFCZA1S/>3..)&0*,+(,*#''!%$/D:?MC5BOSU^Ldcsyni]Z^hdf^QgjdRXvxu{otu|oh_ZjeW\hjxeZNRajaY`dihltyxvz||~ - {wo}{qt~`XUL`mmossoc]YMD_`ngzgg_\UU``ab\ao`UKMQOF31/2,,.3B:@HCDG@4""41319/,152/28@=4-)1CJFB6;M4,,,"(%)"%&&)(=3/5-31:22/<6<=@YPFL=SEC:>M:U@B9<8<(1/%$%*$G*''"(A6/-.766035AK=?PkL=C@N>F9--""&%&:,#!)$&6-/8?AABAAb_cn`Logtp~n``_[WTVXTcdomryvqood`ad\TISLhS`qddcaXZSPbkbhhcROgipsr{   }wtprnnxe`fkupl`hvj`[JZKK]Tqjw|UW\[`cr~nRSLBEJKC21067BB=FLQPL5&2;8:>:@403A49@CK=b>QEU?iT5819*/7))&%)%,'&9&2J1-+57466E:LKFUjMAKG_B1*-/"#*(%+'%'"''86;6LGDDDP\bhf\BWHToljbbacVSYUOaicl4#kjholli`j^UQPE\bgsfjg\NNC]emhgdT\eoso|  - #"""!"" -}zwwuoqmd_\aYagaXfgedL\IETRmnhn\[bT]pt{gQNRCDF>61+/:CJQ>1((#&+%),'(.5E.2;11;8B:DF_FEF?FFB35+,&"%'')(&()(&10:?C>GADILOh^X>:D^_jvg_XQYJNYMUXbiYtdcgfjhgf^]VCOTajhoy|pi`sa_WgjsqkTXZ_equ~ !$'(('%%&$%$"  -}yxwuqnnf`Z`hqi`H^bd]dbgiebzuv{k\RV[jzp`UH@C=@08-/*E<>EDF?LXGI7.<<1><@-*)68NqSoLIIC=9XDX>6.-1..2,'&&,07&-#-<+=;6,0@>45=GDSNE@WYA45.+,/+*$(+)>2/.,?>ADEEFKJHJJND?D9?iuokk_kSHSaVV^fRX\iiefonezd`WIFPVgkdlqv uf`klcnslgXJN\bdnu~ - %),,-,+***)('$$! wwvqnnomg\YmqgWThS`bijptrvsll~uZkagqjpm]nO:=2,#%2,*328>=@EH?EL6(56=SC<4)2>@zQDBGDH7@=EE=42-)?**)&()*')($)-**(:34206?88ABLDNK]QA3B.1+*+/45+-9727:RKJIMNPOKXRF;>@9FFpqwy^^YLRbZY\]YXdcdukaf^rrfIFIOQW]tiyxswlg_`lol]hZNO[kpuy !%(...00021/,*)''$! wuppqlote\[aaWe`_gcsh}|snboghfcdnpeiWF]0)"",/.4F78>A;:9=C6(9IHC=6/;>WVFRRJFHH>CVAGEJNPVLKeSXKG8g~Wfxqkjbft`_`njab_flc`^Xa[pi`TMPG_\ZaohmwhZf[\_akl\_KINduu}~ - &+,0245545530-+)(%# ~wrnouq|e``]okfoiicfz oj`lslfinxgdRG<3:)"#*,9>A:4:;::68/&;.((*&%$%&$#&+*%%)18A12CPX=D:DHPFDAPDGEKILPTTVRBEgnnz|kuc\^]__`n\ ipjl][\_cd]^TOL_Z[X`Zcqrsre\TY_`a]caTILRjuv %).0156888::730,*)%#}{xqovo eYepj_fnmdbev{ nnj^hubgpl{joKC<>=4*+1.;:;45:<8:<0 )+6@?C96>QN5;G4.)),,0#%'+%$ --)&"$4-7L;?BK\QGOBSJM?F6>8-/**125[aI?HDEFLlPAJEERVMT[efj{}^esY[hii\omefhjobgtbh_^OFY]]XPdototysd`V\^hhekaVSfksw~ !),12479==>?=:74/,+'$ {{spqoqpeZsplbkhbXbj~s3 z[[a_l|ts_TFE:=50*)/3544989?;CA7'98GHE:24@;GD:38B;;87:cN@9;/1'%+,+,*('" )P4*'$+(-:4KQH>YjhjE?E:@834=L2.))0/FbN??ABGLMRMB@IT_^YS[iiq okb`qrWX\P^Ups|gfaflecgsffbaR^V]R`wysuidYXUcgmllwiutw| -"(+0357:>@BCDA<9850+(%!~}uwonmnpc[{rmjf_Z\__mz {_\\bimvqh^TG>79<44(0516D<>=>BBSA4;@PbI@.142/.+/278=B89MC>?<*,(&$()+(/&&'$$'#1#%-3807SvNUjPP]PH;?49571:-(&-9YA>@DHE?QRQONXS^blY?avkqnr]hdf^cXMWbUbudcubjkeqnfa\i_YY]UM[p{w7p`ebfogiouow{v|yw|~#*.167;?ADIHGEA>;81.*("~yvu{uojhdfkjj|gh_NTYl} - rYZ\]pi|~laZP:64G73()/641<9O@ADE;79ABX\P@/6986&!)1=H85252/(.-($#"&'!! "-/0528BIGCOemKIPe@608.,&"*&+/+*'8O;L?EIMPM___in{}upSXKMHPRRVTTW]ugd`fcb^f q sePT]Y`\prseRWCM`eotrzpejw~{|~ "(-26CKGHJWbrcgI  wtyqlR]KIHURWe]aY`Zao^g`Xc -}pf]SUU\g{pgfZJPXdkmmqslkZbyz{}|").4;?FNSTWWWUSOID@;51.*# }ywurlxkcca^bf[`ZrgP_oq}jZY`Y^sida]XGGIA>=?50,*984966AHE5"AHPgGA8;;3..40=@@ETIQQd~Q;2B2%$--*(%0)*%&$)4220>DY\yb^RRGJD@23.-+&#$)*32-385WHFHYNN_o\h_uh/ix{tgZ\XJETQXVubc\\dcfcVak~nimfbR[`nrhogwfU\_kliimljggdsvz "(/5;AIQV\___[VQKF@:510)" -|yqmosebeglncW]UkdN\z`adspZ[_hua_WSJJVZDCA7<38A0.8(49=?@-'AFRKF;;<;26559>;BCL8OIMIv@04-'%&-@.%%&'6)-1,6@QfqPSQ@>CRI4-.5+%!+*5/-,,BHzKFLSSOW_R]XktyqiM^p|{i]X[YQQT]ighgyVqeyh\ae tcfdS`gbdumaVnXbuiZflpmknimoty -!%)049AKT\elkibZRMH@9630)# {xuopqedbipjeVVZr]ZcuwuigfwXZbr{c_SVISfLNHB;?A=<,$# ,9<<71-9@ACBML;7648A?FQTNCE9T;cbA7(1,-"&/'#"%) #9K.@47@Ktx{ZKOduf_\YYz_\Vafyipjceacpe^^~ ' {JRe]k`^`ow_]f\_dchTO]cfkgcnrx} -#(+159ALU^jvyrh]TNHA;63.(# xtpomnhbejkgbV[bi\^epwstvm]W^r{f_VMZ|vYOR@35J11,"#,7;=4?-7@GNGVBT>127A`TNi]F87;<>6=0*06+E0*&!"*6#&".>/@?7RRgYUS9@WHD9=-)>++"-+0)73D5>;@?G`y]nH<>E@=B:/2803,&%,216V<9<;PeJO@ACjbWPFEMM`[Uaigdf]cpbZR]`fkmdbwixgtw |v`MLKaV_WgsenWY`pafYnvRcqaappx -"!&,/27>FMRZaotndYQKF?:52,$ zuqnmkb_begda^W[jf`]fnsi|+|`oic}yv]^NKMLN?A:45/*#3-,(-22/%'?LVL=C>B;43?ZRLKQM?WC6H;1(,:,-A*&(%#!%!!&(0neW_cU[><;:9F7=42^C()*+>4?@C?A;\OQ@AIHR\]boSF>HRfecveibljcNS_NRa_\_cjnq{tzj^SCMZ[[acl_vaDR_`\^}natjmS]jsw{ $'*.49?GLOUZbgcZTPJD>92-&# -{yrtrkdgfhlbb[][]hi^gxcy}nvjenxgZTLKBD61259-%"%(80)/2(#7;IcoE=>C=<66BNFMNRTQcPMKP-*%',%( "%$"$# 8/{QPhWB>624919446A)4*/4=SI;DQGT_a\aiosqJATeThmjoj`Zqrzyy&(+159?EHMQTY]\SPLHC=72-%! zuuwshdjimqbWLYgeb`dno|zxAytcfZhbZQLTLHF;8654)&$&#-+,=BP4>FJWUH>FA6M;B;1-9,3+(+24=L;CgSVDLJ`aga_n:?xZ^_aqdLNZoznuSFPKNcbQ`kz rnymglQEWbeeilku^HQ_h_kopqegfghmtxx{ #%+059:50)$  -yuvvjijjijlaVJV[XT`|t{rwejsjusm\c_TRORC@AB9J-4$+*!*5DHB4BBHRXSM?:96A;H78:054L/45046,>YH>7D6M>CK=;Wa`hl{1&5wck\fflt{cc`TgOPPPWa`S[Rdpu=vbc^WQmolouwjU_\Rdtmo`fbhdqy{} !&,048:46CLU\XD<5;G=6839kdurehsd+  !$(+$" $?J,7/24<677M3950553@/06*=E7/cH%L=BEVNJOIghfhw~ehZ[W`nxmommEFDLJJJJTX^qUVP`zkmciiYTWaemxoo]`aYC_lqpp|qagnrejvx~ %+.1479?ADGIKH@AA=951,)# -~wvnonkhkpnghcXOLSdxypvhVMNWgkggf\]P[IH82.,,%' $',%#3AJC@K9>TWbfJ<4:64248:aXh`eao`8.#%"&+$!$%"6A.3./37:619045828556->./:@6@C;7=CQTKRNRRdyg]h{pk`V^[_cg}ubRDUL=9BHQ[RSTL_dgxpedAHQ[Pcusa[idObgrppfVakoo}yry|$),/269:=>BEE?<;:951.*&  }vuijmgglto`e}VW{maQNR[mpx]UXYE;JJB33+&*$*-1"/?@AFH5088120)-4:1/.492+1,18:247NKJZCDaiYV]b`jmca^]a^z[cutw IPdnBBEXRT_Yh^f]\5^WCEUcRfaejsIxl]llqlypdhmqpv{{").-1478::<@?;78642-)(# -wsghgijnviRZflVa -yeseVcZn{vc\bTB?SP?7)L+'-0#")2DGGNMBLAGQPIB=:5276G<5+-1126-//+),'.4+-0/<7;/5:[I@SM`SVYVSdjgsvn_\xfeqsolllFRQOPGHU_V[ag r\UCRNXNPZVVTQ`g``qgflqkmsweilhpzww !(--014678669:4230,(%$  ~}wqmoljkreRNX^_`oyuqdTUT[g_`qujnaRPHBF=90,.4-+")C50AOQKMYOGESRIM332/6;=LA?AR[UBX>2#')-'*) +"'&"4#%"?MFH14,-24=:3/1-13/-(2-8106J<@>K[DFOZMIVWgqj_igk_[okgshhkALQ;IMVMOOOYUa^^pw`NHN[ORnTM^\dWZ\dWVkxorujknowvz{swy %*,//148640251,.-*&#! -ytljrsrl|UPOWX_k{|vulYaTgbaqjrneZlITe^B?2>J1+('.5>98DSSY_PKPG@=97,0@>BE:C@:647832;/.1,-+)$+.15;+)8F6;BGINKSUMJV[g]Ybadb\mqo|ns`)*79HMUPW]JRf^cf]jYOBNTYPlO\pleY\g[Diu|rqqmnosxxsuy|z~"'*+,.16340./,(*+(%  |xqmlnrknlUBMGZcl -~tpastU^ecepsk_VNIHJM?++00//)63COHQVSP]gd[QI7JN7//48?BP7/&'D:A,+,'$#" #'" !! &$"FXgiv}|sx_Wdkdhjbesma]SH@NA8:/,*$&*2:?DGKMQZ^RecTD0.-9>@8:;9<86=G-$--/.+0(#%&$("#!")  VM68H6106G@:9/2/72*38601o - A96::GIPLXY[\j^gg`jkW__`rkoH@&4KzePUa]WZXYYNZa[[hRQM[egr -nrj[b{qwkszxzpwlz|qqrpw| $'()--.,*)(&#"  -~zrlurl`^LBKM?Xffioj`lhidafu{dw{o`WYEFPJ=@2,+)..496FOQT\b]WRKQA585:AB==99146?:;./*&*,*+$ 0*"!#" "  !$#nXG@L>2-,?561A-++10)-;5+8GT=;59:=EFEKbb_Y\\gi`_\chXidqwoPU<6IVSMN\[XWaX\[oY[QWTMGLeebotphxLedqru|zyyjis|||~{xrooz}  %&'')))((&$"  -{srorpe^[ROIDBY`a[RU~zprkbjymerpme^WPSPkOA;831247<8MNRXUY`JBAEFA?9ABH=D:376BG576*&&(')$!!")&%  #%!BL?:6---*A69252(2-'(,0;/-6><425=;BBEM]V\`amllTTMQ[[hljkbOC86GVCLZW]kXRVORNMQS>IQJPab`jiVNh`t~xvuikrxx{ylkmgly} #$&%&&%%$" ~|wrqlohedZYRCAMVX^U\|~}klqq{tqfcc[ny]TDB76-2)<<5GLY^VPRLENF?9@BD::638//'#%%*%%$'!$'%,7!! ;$) ;8:114,-&'/5..HC=.'!$B+(.71=8728CE?ED]Vu{lY=?NMQd]QXgdjaaYTe$ZO`[WYacWdMNG_VWRPQEAT[cuwph{|zmus`b`lqyyv[Ugfn{|  !!  ~|{{tkqvn_ZZV_ej`VTXWcet%#}wnkiiq -~q_cpbZGNaBI=7;AGIFOMTQUVNLI?/2BYBDHOLFRPJG;4:4,)(''&$%#*+ "$##'" *&'%.15504.270,#+13/394.'<+#'*&8545@5Q>=GOZhh| bM>FWX`]Obf`]`[]_eZNOZUw^gadS>BWEYXQLESeaht,|q\qcrj`Z`esy{upTakuv{  -~z|xsrqqj[WX^aaefealju_ezqw|gfekrzrlefZITelJ>=?GBNX[MFSOUYPC;/;=E@:CIMLCEI>A;=H@DDNMJKNKKBBGFC/:)$$%!!%!! !#$ !#%KA3'/88846.3/0/128@ELMNZ`cZb\GRYDJKE\^qjo#@QDGC|ppqqibVVbqvkyTWki}}   zxxuvwyzxphgaVbf\\fluzsmov{yscffeamvlqkni~li`fBQE/;85;@nLIdVTSYUICJHKJ?:NNJQ`>DCB?L;i?@:6,%)%")#-**' "%! ##&';*)(@7:<<2<22At@-A>,).A(,"/1,>884A\Jh\dl~rsx`f{|{zd\XTqghREGQG.?>68::BD?DQRQRMOURRSRVUIXX hbzl]JNB>>3=1( "((*-$%$$2%")),2-/G;<1-69EN70%=2+**.,*8&/)(63+-++6;59:A<93HBKdq \+iFKUutl`YXXZTSKJIF64,41=DZHMX]RL:9@>>[aOG\ahm &/71,{aUehig`KVfjnq{zxikvz}prx  ~{|}{vonig^`[VYjmfin~y|zrmg]e_Zagirkoe[|\V929:F=>KBGGFQQKWOffURku_Z[[ SyoNF9A=<61/))+$&+/-& +*''.'e,3J1:6O>>W[P9+(0--(")-E(()-2//)*22:2933.:<>QIAOdaT?aA@_op_Q`VGRRK@EBB3206bKFBI<>P80.-/'(&)0FI()$*(-6*.)1-+-5]4XZDMCCFHMTUH7DTC?H?:C==5662-.)()+)X<21/8)))(($%,*)/;9=<:2,(*&5+(&#$'<),31)(,/?8:01.;=GADGS[HIWKJNL_dgaSMEHUEO[DC<>0697<;:BHKJMOJ96IK.8[RHceOYaqiUbekeEZnXJbbW]^quzw}ynrw}pnwwx~ |xz}yrqaZWWdaknijtv{qnulmntvib`oZipbcpmdgotS[HC:@922;7=DaIRFRCIHOHPV\ZcY_c]`gkWGL^C984503>54+! #(-+)Q61)/'&*'*#+#'1)5J32...*&(,)0""!'&3&' C.>+))5/31GBCPQL~_BX?BK_svjaUTfJMPZbA=WaA/3442+-K00.=2:]VEHD=68E`ejdhXRRHLNUJBGH946178<:=@FFHLKA5$.3J?NMACa|xfVHQWkL`R?DZkcPju{ vmqx|f^^gqv}{}qoqpqtnrmms|qfggkkmlujxkf'xg^`TZba}|othnTWGB<=636UHCAFFPRPLKC??OJOQWk[Z`]]_iUc??50://5.24,-'%!$#(%"#'//)/*//#5"#%.%&#)(.21($&#&!%-+-%)$ $"!''&60(.2285F@E<1,DZcpgmzpY[UMEGECD;:168C48B:H?KFECHD4$"(7>QVO9Em|rhwmYhaYP;EK/9]c\O\t}qsx~{wlY]crvntwuyyqqifZXkmij{sxodmprrsyrmovxrle[`cd^gemzuvu_[S]917@@:>eW\IKKDGNG>EDHJMOU\c[]a]ZXUGH@:2/3505-0--+) 5#!$$#''%4*(+:#*2(((((%+).(-0&&*%(3,<9'"# %#!"*/<%3.'%&**29>8523FPudsecSQRLFAAC=?2-186309432000546))& &*+')0+.42$$+&(6))&(%':;$-/)0/-1/.+&$#"!$(0*1,')) %&-472MIKON@@CEGJFLMORUW\``aWVRKF>:>:76780-&1);MPPd|cIHT[ihmnjrfRhdZY\bP]x |v{qjvs~tvvxrulndW`bedihjmsnnz{rr}~~fagchcngqxmmmnitmbQFIIUE>:EHDHXKKHJHGYC2BJVUTRYcb`\b{kC<98<<2436<.+4/.)'%$''! #"$$%)>+88,D)1(%*'(;4+ )7.1,*%("8&%$&#!!($"+..,&,6/2212A8A]VOSWeirnhjfSJ\CFA=;:2668:?GHEP@?=;@C<+)&4$8WQXat_KT_hvmognig ce`cVZfyyvz|r{sixyv|xyysnpqsb]kffmlurs'xos}rmnc__^a]p} uzmloflqgVYMIeN@?NEF>SNKFEHLRH@AHPUT\Ya_c\S_UA976846330<5<-*,+)%!"!$!$&).+)'(-.947U0.,&%35&(**&O-+'"?s.x)%'! %/,) %-;//.1668=GZGR^ct{ugb\P??9?BEA658?9::@KBBA@CI>7300.3=MSQZYd]hutkt{lnjly-5xaedbmbmztrsrx}gwmksuqs}wvw{lrp{uv~orqwfknrkj pjiaXabmq{rfanqneTRQNNMTC?CHOLNJIHEJdKnPPRNVjeiW]fTN?=E?=L.24066Dy<(.-)))"'&(*-$-&4+16^D8)3:4-# C#)'#1%(&(?UG+&$!"'3&&&$3)*.-+367@9;DTOTcmd\][PMAPOG:D7497776>C==?64:841,-3AuPOURe\m }itvjeYa|5oWicfihxutmekgjkwtfwwyy}trpjzzwvshlflsq{wwtx|se_bd`nnss|i^^laTVO]RJFRBEFIOJLGKEGDSHFCHNMSX\XSTUOI;88=:F78736ATpu.,**)($*,#%)(%0%7412=I-)):L'#""#%$('("&19"#!)# #"$"&'',5+5<3/1=JATJSr~~ldcY`X<>M9EC=>78<988BL;:<@9:33003539;CUYaoxpkp qh]gg q]d^oso{k vqrzyjuvzfv} - ytolkmjhefhdpjlo}}ox|tli_okrlulhzoba\`TMSSLWpH?FISSXTJCA?7DQYZZb^YXVO@;7:328:9:A@?SO>>:-,7()'$%'#$)&2A49/3=?'--($#& &$(),%%!$'!#! "!)#+""(U( "#'1-/0],2BUEOS^_}6haJM3DYG;AU9;6575>K;5<6B:9<9921.2--D^Rav |ilongkjgW_^Wa\`cu~z -~t -{xtxrw|{ )fjelqxoryrspxr{~wluurokkcfklnpxnb]\[Z^TUVPLLI@=GNL[pI><=@;=8:ADD4;7?80*/-,CKG[|ylwqsRssqhxaLPaeT_o}-ryw -zwt|~(}p{jn~xw}xuuywqotxnmngekmnmsqj]W]b^Y`cURWFADDHGM_dSE9;BNKU]WYdgh][YV[VKN8258?KGGGCJQvbI5-.E)%")(#!%$&+057?;24(1$*$%#0*(%.*3'%$%## )")%$,0"2+'.#'C)4=>:@58@<7S@CGFZ)"{eI3.8kWIGYFB;:?B@>;OPL<88=57?<5608FEMJnhos~+TXjlktzw{~qst{q{  ~ ~x}  |p{}v{rx{yuklvssrcc`iufSKMUQLCDGLEIGiA@JMeNPNZYRV^_bZ\NA>:58@IP=Z;5orz[<700#$%$&&*&'+,*.-25,8-9)&.*)),/&*1&$)%%%)"&& &#'(! #"&"!-4Z?4=OXunp`UM79<=BZ;OB?>67911B@FQbi#}Pew >Fbpzknt[ntzoa}wmmokio}~ -|~{   n| sw|nmzotcaZdSPSPQIYJDGPLOAJVUPJJRZ_ie[d]\maw`K:N><=>QD16AT|+\M<'.&&&$'*(&%.`4,,-0,.;0$#8A*.1+-.=$$&)*#,b- '""3($ !%!861=78@6FBBC3AJPdUHEA9B<<6D>;959;A]KNQTjB>FGDDIL@097<767VX=U8=H9>7TIE:5>1781LBIOTeakwvhkeVXD]mttwrw{~j[Zvgiqqm| } -  ~ ! | -}o~gooqpwy nnkWWYOKKGEAAB?EC?A=EKOemXZb^\YYdWTQPWoA:?H7@>KcCP7Wj?@B8*-)%&$#%')*,(+.7')),&()+&')45,'*.58$&-#'%/C<7(3%;b72!"%63/0747DOLCIKPE@2,19A2=99;9A;7=?NFE<6:1<30@FUOVmx~|ykjcN=NnEK^h -{pmot~ufsndf|{w~ { - - }u| ~uxt{ysrqnmsyppkkiiRSLNFHFECFJGNHADEDIRW_[a^`t\[^WOUIOFA>AC=]LSTIA?A=29YH%%)#$ #+1*))(/,,(**--&.(8.((2\D03Q=("-+%*/C+%!5"0FR '!0R7616B;?@9JGG:>AAHTRIJFCJLWa[_\cY\WY`ZYJEI@:B68?@BB:4?TPu1)&)+(&%$%#+*+-4+&)6'&&)%%#%38%'70-1.)<. "+=-) ##"#%:& ,=//X?;=EJMOYEHE^UXeHC46:A3%08@?PhD6283=29=87595=87R?;CQf|om[l}u{~vl[R=VRZTV[ohoVVH^zv~kl~r{{v{} -}~{z{ogefe_c -wggtn}vhte_bcXUUUSNU_YNIC:@B828@H]JLMRPQT^Y\Zh^gb[RVkUKMFFM?/)23A;;?=53;=D7;:23293;>7CHQ:=M i_T[}utsS6FFUVUSdd]n^E=FRtpjqzv|~s{ zpihdfh]chhsnafa\ind]bNWQVUWRbTQKGPFCFB=8+&# "%',3*101280-$;)%%""E#$#! " �--((45KI_@DEKTGHUXXQTcMO8((.<43;N6347>@?6316565B@;:368?NsrUpanusznF7k_lVPdyjfI2DKnffxs}x~{w} uljkqheh\gckaddrx xmoq[Wbt_POOUSYKDGJIFHFHNMTB=HUQIKQYec^ffcha^^YiQQDD;:@>A8?A=H52?031*&*-/,),)).):**((;)''+)*!"'5'/"$('&.-,-.5?1:"'%$"+7"<&!!%!$#-,='4995158@ELAB\VLphK))A.0.J=345544>IG9657487=761:9H^EZ{^huvzmkREZ'jdbaknSF8?7+.,136),%**-*(-).0(-6)(&$*&2'%3%"%% $%"%1-.)(%:*'"!"$ ,[" $ %&(/,KK7/15AFEHH\ vu -\7'&*)1:<@1-335;>?=./710BH7>.7<@CcSZ`jhvppbUV -oiecvnuWTA4ASVdRTij{t~riemehkffXTs[UX^YTKO^\ZYSSQMWHJkee\RNXXTNKOIMFGFGMhZ^qj`bagfaVSURL?=88::J;8=;5-,.343/.32/-:(*+.*+)sH('$%&&,#'" $!#%''B=X=+1'%,*$ #!(Y% #&':C2668?zSMOY~oprvi<,*/(!30243-647<ILRLYiuddphWaY22+.&&.1/0468;E95C)2;B:51.6:=GVUSjYcwtpoptVN_Xkb\~[XdIhjpe^YLJFKiejmfY_pssinkm =qil_YUIFHNfgVJDCB=VKOOIOPRUNTZT[YQPKKCB:JRPPX]]_qe\Y\XKAB>A[4:7:22CDLGL;843-(+3480()*-)++'&'&'O)$"'&&%%#! "**/QQ/1(05B+2"# $&## '0'.@@EMFCJ\QHLXguh^QdX9&$"***V4:'&.17185A51368?244:>CVZX?JX`pnybYUaS\gg[nKQK]afe\Yf@LKLsX[aY\belrpoq ~{]b[[SRJQKQTQZGEIDMZUXZTTc]b\Xd_XUOOVV`WNJQ\bdhwrnbWSI@>=:8A818638AU>B02##"!#(,*.0C@LOJPS^DFVsTNUDEGHNPHJFN]dfjngPZY`W_b_d_]VmrhVWOJ?TK?MRW_RVYcdaao -hlZPPSPFOSMMMQEDVNORPSYYU]`ccj[]Y^eRVdnd]PRi`]amdiVSFI;=945O6/8308]I@PND:508-))..,.&#)(','#$!!$ )%)&%%"$&#./11-)*63135[0$!!%!1##+),+(+1J@CZGTXQKNOWfhSCGK??86?5Q(-4206/19032*-0:>5:3CA>KHNGIDPmlbfigcTWVYWXi|iecd~^Frk/@@TWYXk`R_^b`dlttn`ZELOSBPmlSLBFKV^[WRg\a[`[ce_YWjzlY^emytVjg\\aWRIJEEE?4--,+4>24533>5FB7@]55/1.-+/'$%'&')%'$$"&$''+'-*#'&/F8C.2699=>0&$$$),%' &1)# $%)$))0?1XBKLUU^F?`kWTQNOEQAFMC"#.0,*0)/)/,3.03929KLdCBTSGC>Ldm]egjo`P@BBPbppkrq[U\YrYAE8XhJEUi]TXi]ddvp}sioSCMPWH}SfXTQTPTjjwdihiTm\mdebvyj^vqjidiigVPCEAIJMQD22.1..7:739>793=9;1610***.&*3()'&$ ##$!#'+()&$&$!#*N@92@-O@..''3-# &$:9=!+ $:8%&-3B^2F?I[YU\VIGKNXRdijdSPRT_Q\TQXWUVWWW`^b]XZe``hfco}xvrs|qtusmcdKMTIIH_fTE3124727:54,9;9:0190,.-*;.*"#+)-)#%%(%'*)+&%" #""!>(),*,4&-,=-=K"%!'+ ))*&),28;=;ILLJTSP[VFM\QTOSD@=::I11(!&/+,-42620210311529ACKI]449FO^lZZRK/K[guY\b_UMH@ =FS[UYQ?JIOOQSQ^gYXRVSOSS^^`]\b^\Y^^ZZ[`cadmgjouuzyyqns}rkn]PLJKLHPJD914A7B55423479=73243.25,03)+$&&%=,&')#)+*/%%##'3&" '02&.-)%,/"N@" "$# 8&(%)=>>AGMGUVNPSHiKHTOVdT=:;;;G77H&#!$".063222212123,9F;=[C558714C;>=8934Cc{::J*,$+(")("&&#(/%)'$('+,(<)*82'*'&,%04'"%(+ ##"!$"!"#%$)9=D;GFSTWKMTRPPITLLJD=;G=;BwU*#.$(,2.5434>K55>539;=NC43*953;7>GFPiVTh@NGUUVQPCEGTXXVPSNM`>9>Kbp|'\HdYWVOSdunXcddgccb\a__Uaa_`d`\uukeesreddjhgkf]QMaPTkC88E=?I>595/7:5HEI;9=5405/-0)',*+'2+(&%$)j%)+(($)')?*.*%')'&(',3 %8&$#!  *#($%0X@3K@IAMHM]VXNKVA@@@D=33JgV9:7533@42BCFHA@F/.-22,+&"%)%,)$"#$$#(/(#$''&&'+-*,')2$!#'#!+$ $% ,%(*'+(->EBR6=0;IXFNPPDHBCLC=;<8?P=#'($%,K/)%-.121.+-1843vP=HE9EB:9>===bAE<431+//=,/&$*+%)(#!  '+>0$)''&'*-+##(&#"!(()"!!""! ! $" "%)*08:E=4525EINHNJVCB>ECE:@=GJ3,(#%.,%.&')-*)32)%-83,2I?CJ8;d;:126GGIJKVgXWYSPQN_][qtud[VTEDDHUOl " {ckU^o`]Ybfgmhgq m^^Z]hipm}ecmaeaf_fcYPVRHNLRNQFFFIDGGxwhb_[E\z@@<><:;J5//-54/.-4,2(%$'"!!"!",**4&(%.-7*,*$&$&&&#$0($%!&%# $5&@9"'#'-/1=71499@JISRJHZBIAC?C:>9=3.-/, &!#'#$'*)/6.''AAAECMW~UEE<>697<;ID411151/;/;,$! ! &,125-<,*),?-('#0&*$%$%.?("&7$& #($&'*,.4?5L@=:OOKMMKDCNGC>JI98A5177`.+%#$#$%(:)/.#)+4F>9?;:8;,DRINGUV_Y_NX[MWZXba\_LU^T`icagsXbirj\ndwylb[KRYh`hmt\[nlkksngTZQLUSVgKJSLNNKIF@XGBFEF>DXD=ctOG@?9==>IAID=1:8/24E**+"("&%(/3+22G-),)*+&+%)')$$!)1>#% ! #!$#-1)8F@DNFFEFXEPMaZICFHDC<>L85F2.26>&'#))#%/,41)$(G7?@=95DA7?HOB9ID9@KAR[gTOMH?IQ^^^[_]LSNTaR]Tbmyg^KVrpMVJBVFJNW_]`^adWWVkgcic`b`QQJGGEEKJPLMIFC:>FJOP^VOFFFE5@ID@G<=9AAGEt=A76_[D)*+'$ +5%*"(,b1-)/-,)'-.. &#(1(&#(!"&!'!" %* ,.)43E3<,'*$%#+1.'+0?66<=7<@;>DD<=D/56HEDFIGT[ED=LPNOORORIHNRJR``QmaOXc~~sXEJ?NLVGQQZZX[qc[Z_dWVQNRJHCIJFBBAFETNDFN4ER_~mXOXJL?DBO@EEF@8AL>?GnT;6=2*..*&& # !<&!*J.5+(('('$0A('42c1+,-,'-"%&3#+!-12!#&%$9>:NYSD:LTIOIHJPFQNMD>B>9/D/4%/,/*!"%.,'),435<@;7:ADBA;^Z9G>BGEUKGSPZKMU=IJKPPSUNJTSZZ][SJNdurvbZRXGU[OTEAabm^_hd[WRTQKJEFB=@JBCBA?S=CJE>4Pc'nWNH>BCF?BEK8CG;DQ:9cQBHC0/*+.&&!# 0892*($).'&&-')*-7+-2)6Wo3,%.+%'! !!# >, (**"!!*++36DOOF?FPNPPXQILYGMCCJ;84.(3)19*-$ &.')/566:@:5:8>=@=EQ]929CE@MHKNUFIA9/9AIIMQKKPfUGhSGEKE=Nie\gdYRPWUOLHHRRU\g]]\PJID??QT6<@=:;?A73X1*0E-(,&("(I-)')& #((&&+&((,&5/,((0640+($%$ %!$$ '#"#$(1,09AA@MFMKHHMM[ZPw PA:>:C>/0*&/.,++" -**0B778;;82/;?9@IJk=)*5EC@KDGVJ@9327A?DEMNMMPLN[OQjD7@OFFJQQO[UJPKQNDD=LQVSSfM?B?8C7?97489A;C;:=?:;2GM`HW_J?=E@4V@00253;IOGIXHNIMOLBGUQKE>FF?82/1,16;;1.&$!(),?;E767<;6U/:EMCVIa?0%0OSKFHIFMZ?2-1@HNA9@PVCJI?FJUG?=563EDFPW>A>BAAGEGN`PPZ\E=>==>8?71794>A:N@4:><@OC.0*#212 "#"*(""')&''$'+.=HICHC?LOLLP@FWeLDBSPH>;933.AOm:*% #.1MR@KU?5:>7@-,TOMG?>/&.9CFMFUIVhB46:A>=8Lm3W<9=8@@EC;C<=?A?N@E>9:07D<=CF>:6<==723978>:I8UAI?>?=BMM`KMAAH{@9975=-1230,--,,C,K4?5$## "'!""'$(+#!#4.+)(.7B3/4B7265+-,V[.&$#!"  $=$$*"%"$#,,/FB..+,)9Q@@]iV/4BA><7H^\eI@A4 (1=CZHJ`]WH;8<798I:9686@7;:@EU30/*.3,H633/9:H=.8$)"!""0""<\%%#/0+'+44:D>:iW@=6.,31()/') '"%!&$/" %#""&%/.4P;8BJB;:GBFDDFCLC?I@GbsD@N93:C;0A57, $:G9=97O36:H=:6:CFCB=EC%'6NINEAF@JBF?Z[aFGYLS?958E610+08863..-1@7331&&# #"#&;72&//1(,04KM8?oi7?P>;F1*-.&)" )C9E'"!"!*%"!%$2.6638>^M=N6;AD@9;823-.#.6788128213W=:8SSBYSI72$%7DEF:CUMfH=9=EKA42=>430,0J:/4.05.,'S1570**$!!'((%')(----1(48370-;<`B8/K1,0;A--&( ##$#,'#'(,"!&%)'&(9??>?Ei58>D<<=P39/76207GU==0:)./'2*1%,#&$"!"( ')#$ $8/(5@K68BP;799;>B:BQWINIQ>:KDFM745:28,$#%*-14@:5A=597=D;89OUzC1**'3:I[S>SqKL913//<;19B5;/)5@ }B=-,/6,105626117538;59;<=263256OC<8>7Ic~WB>GACDAFFNFF?:2;.$'#'/79;8AD8::C=.11/7CL0?.*+-;AI9=U`HR@/3-308545397188917929//11/-5=3;:48:3;7361.064739:45:2:AES>?@@9<<=D@;987C;9FOH87.-,-+,)87339/40P<08097:Db,88:?8=987>261322@LX -\FDFD@=;4BKYJ8Gb5-0%$&/2E924HM<884?=:O4C63,+'*@CF78>BSH<:3278:40845;=@ilS<592.-.0/,.122,2695<4341=450112406=^R;<,.121/5XYcIGQQRC:><>bSJ:5*.352*$(%13.1.3=GD=<87=0761>3,*,AC9B:;:JpN;359272:;-0534:EDKV/25-2F21-33/.B5:5-16==7634033/5=8=EC;:2;:?CCD|=7/1+7=&***6*#.%)"%]#! #K42>>$<??B7<82935./+9yCJQXJBEMNA?olWO6+3-3:0.+'.11,-0=@M?BDAF5;6BK>@3GI5*.060B30,/,4031053668001=LXE=54/1285>8MM>=><8;59>:@9947F.-+57?R374Q;:@a;=578g7F^@7ZOCA=<99D?=54OU<50*(&849.5283.1.180+<.0OH#3, )$/@+ ">U5:/)((3++57/.300/3/+1DIHJTkFI_ILH]C:2*,,2?92)('+.0//65D@O>BX@598+7388>5A:;9*,?=82N?>8>7@kWD@=A?><46;4;87870750L@2-/3=920*4=LHd0('0!$(8&%#"&&)0*+0,34.124*)/FIBBC@EBGBJNBGF?91>/B3I:51()(+4/C26H@FB;>G>J=PNK:9LR81'.=E;G@9?:::9=8?MA3959\K=><68/8>9645;637<2-22:@IRK:?6062-2<640),)'1=?(.02./?J89@=2+,-80-'A,AW;;#'% !!"]*'$)(,#&--2H1?24-=2@*4>>?9<<69@>BL>@?_=>:8>=699:6:B?3>62722:40-156>nK8GD;9>=027026/@6D37<;3H6).G-4928.22/2:14=,793<;M4396-D;:/&(')))()-10-09@F110I-*/6/'5<>>~\+("!!"&=.&$$0&03/-10./23**(-6=M=BNAP805N632('#"+/3F=9<:@9C:C=>=AFGBAOGJ@F=?M955:@66=89967>@8:2416BDJ76nc>5>?65QqQ>3C29369K2955212.2(%&'/A6BAFROZJkQMIXID.15641$*%!.+02564N59CE@9;J=BM.&0,02.)511453=D9N:>:<@J=>XFDDEKA>@D<;;KDD==Q:@8C@:68,'(,-IB)/*.<6/>B4870)-1,:0+->2/G""$"D%$"%&&*:*45B.200*,37<:?F@GUYhXK[UsOF@@K2<85;SE480,.2467EYXpnG=6;<341)83:2/(-()1.0188;4::?J>?DEE>8:@F;<>897P4/?KGBED583?037::;SyK=;<3452202:5-2/.12-32,477(+51F34.208:7250,-C8//,,*'/:1-,C,3./,<^d00*##% ($ # &&%""(1.0>:.//()748@NKKS]PEFOO[SGGFI_@*-./pKT}<9F'*8:CJo H941(-6<3989]1(.7Y25810J;87;?471?:A6?ERF>:>NB8><>7I&FFSB:=:949=777D6FAC7@@89<50E:545;_vP;05374-09-1-5:2272D9;,.../,)35=0-/=2.6./-+>51*&$%+'.0/-,3-,3)0<:A)()>$, %  "7.%* 00@,3649/)/104:ZQfZTvTPIPGU\maM5(*.QKD71@?Q72.821JB==A7555/1.<79241>A124>9657<467QD91;?>4417'&-;@G4>AODF25@6T5>/.&4,0)6/82;3Z6>.2-=160/111>A/%(*,-2-..)*6++&1%+(...-F(/,)((30)#+"/*('.*)%0=17.4/-80C/14CTPKfNF9W8625;DKC>HVrMY}DD6mR:011,369529;?=::+'*/.-0/45.6451137442/,)KM8TEC@6.**'/22/,,+,&%/Fn?A` -f6BO9;;7743367^ZIF6HFB2,>0;,(+51*(74-:1)418=77=9638-**"#),-+-(-+1)-61T-'440\E/,/D0-*47/+""!$;64+%&)58(01,,,/2I1-30@W7J?NIVRK3D?;501;HA6;WqfT583`~B9.5645702/>C9L8/-#$@$8(K40965846254331079@CO-25/*+/-1204''.('/3G=E}~oSBDA[B@JGL>O93.441,H[30./1()%(-).0836/00100@N@E80783-2.-)-++*,+(-B1(((*1vIZ06:HA01/.)./0,D5.-#$%Z0&*,,','&%0.L0A333475.6=EHE>I@DPILGNIB(55ADJ?AKUn`UNr+304%')*13<.3/+86CThH.'/6/+ (+..:520J5283,85-2E64638=.4(&&,)(+1&/0728,5.CbB:DIKCCFB501*-..0/.-*&% #%3-+-7Z3?/3*/5D\F<8.,0B2%'//7+&(%#"&+,*&/*3[t9>07kM,J>;,.2)&'635$%(+3I0'6V6--0++**+25/2547AAEIFKR[EGTWD9LGF^XGAJdW}QyG@=6-!+1551/;/?6>uJO4-*')5*'*'),24/7H7001,'91;;Di0**)('&+*)'/.50.+9/+0;43B=C>;1102,.,-0.4,*" !%'*+*0-;0453.01434951;,E:&#$*3,*($-"!')1B/(._yA817.-1MA;>m0//*..>:!!&(N63<7,)5,/*%)E%',P652594XA7D[OGMAFI[U?MVRm<@G=HE>_q[D5I '40231775;9CD9/03-/*74995/.-,10+G94@"#)*-*/E553c-7*)%'-.+1.G3)')**,&#)&+)*-)$$')-4K/*KV?:37/'2+*A.2R-+-0'+.+1+2;=<1)+0,.1,./5<0++&++&'($" "##$()-;DI2?>;;=4?($$',.DV+$"%TCD4)'&-+'(1;S*(%-B?5/7HO:;9@BDIKLI\ULHLFKF@:87Hj0AgkOaOB=58..02/074;2''9'),5//3+5=P#"=)2BH/1?2#(422//,)#?.$%))*-*)(+*h/(#'$$(//9>2G56[E22)-C?PF=75.0G'%*S537@@1H-1>>H*&11+,.1,;/&&%$"#"&&"%(*F^:PDV81GCQ\T`>8L($'.3,5*"8$*=553(*)()'$+9( .,.*0.:@85.8A=FIN[MGE`LPg_?/C7 bSdw;1*+*0-'9+*?O/:7I=@KYdOFbKOIIA3*c-8)JLDR\C8>KD+234//3910(&@%#%+-'*!RV,$$2+33:7;6.,227411/*+&(&$%!&[4%+&$+*$%"/)+//,>*/)+,#,)/68;adpv?=B..0/1;,-.2*41+1*)(]1J91,62)=+*-)()/041&\?O/%#%G% )%/-*%-/-)%'-S:3""$ $?,+.;::14:565E0.603QI./(42(-//23*-42'%"&*//54103()'$!),.0AQD.5F>R>F@BOOGEE;PFR6B1,*@%'&*,17.++8)!)_KDM>>3@F;2102UT5:3=469816635>B-%&&,.70/5/C.,% 0272G>F7=B879<2+)&+-85q2/<2-%(-,5:C679.00+/+,.>VOi@5WJ2/>.5))>=9+T-2M'$ "&%(%J$,*22+*/$#%&$%"%)',T>7424;<28>F8<<<93&0,%,/8/73/*0&+3@;E96>;YY23;63-539A;?95<46/84IG31(..4-.*)-/1H!*510066Q=8:L=9A304--7..,)-,+0//:2302590,'$(/,212@-513@;:0m?3AE?693@1/7=6+&("*;-F K13-021B-+.)1=::PNDWp>JJ29.5/4.D;W_<4.'&C$" .%! (#)4:AF7.''&!(#!"$/+*0)*&.4B671:32W`>787;A?:>ECElubLN>&3CPdP>6+%),-:5C6=)0342221-2/(***-43:539>9+&1253;QsYJ_\ZC@A>65.2022,,,33223.5H4Y16.45:0.134B]7/C646D74R1%*$(aZP3O/:'+4*4H5%((28M<><59?*:2.0(,2Z;;;H_HH80#%$ .%&#"&!&KU3,&&&"$$(*5-(//3526/1543;=:15857G;AHCTziXx`]<.0-06A+J+'&%.B@R=7261<56;;13-312,.606?I@7586h6;;@LYYxlbyCH<8325306R,243048@<275>D=14@.57431A620618746125$%&/;I[M/4**)/"%4%%B*,'-S78,)4,)5*)+,HP3LnWqTJ3"#" #),/-2$'1! $$!'N%&7.))11/(-108CE*05;2?35=?:@_O^}}VME+-%$%#+#$)-1.3479D23-7?5<.047?=@463772353/4.65094>GBL927:TD7/A420-2C85<4246,7BiT148;BNt]fVVI:/7 &)*(0(*,769MJL=:65152162:873<\O68247-*-)/623/BB`HC>2C3-16.),'$"% !+#""!2#-+*-:1/117<88*,/$') (!"" " 3".0D!$!"&,%'"/(-!"%%#2)-.2=<.=55603=6::<73J=Jm/uTBC?J.-1++.+0.*+%.026rIC;7G634;F82;=:8:::D>86;BA33;962+IyCMNEB4N7/*,-537?A8BH6?9>A=93G9=9253;<<@>R=E>6BHA{A;:<<=956EG=:EU91778IH<>KK}Q62;5993E3/59EOZ>C=?;8C7:07;8817WC=EY57<8>LPT]F;UCB4G;DPX+ 2-+/3..(713.:4:C3:;9<<4J-(57^A@5C?<[26==F62383H8@QOE=<=@I;<<+XBB2K3=AL=DB?HDPP?H<;@8:8,L642C)+,*,"$#"(/%$# !155((()"#%##! '#16%$$7!) "&5!4$#."  !G% "!%%15E>O@>DA;=CEHD>,*5-4-4*&3)5/,5243/I^i;@[B?69>8F83:%/1-09=64:07;=@51KS+01596MNMABT;=I<820AR=67@AC><9sJOMeRR>25=95-1J;/2+()*,%$$'(.,(S", )##0''%&1 !!% !!!!!61N7%&"$##/%!"'' &-4QSA=-5=__1(*$(,5>COASH?:8B@TKLCF7JcI;1.050.8/7B-**.9/)15>AMJ?KA:387:IOZC*+/3C659,1.GOf99,A9((43>F:=?C639T@>788?QUbJ@=I9:B1:84;F^L89A3440*/,,=3GJ4j/%%# #*&%%(,-&$##"7-*!! "#(! &"# !" #%#1_1*/'#)%#""(&?\C.WhB]4@3..52=A*&>$(:8`98M/6@EvoKs}t@@85/20-X0*7.++9@5A9=/217)+23$26D@52189-5,0327>99IG;kA29;LK>@44:9O4Hb9B75>92+)+3*,-2,/5GL5&#" $*G:+A1A&$$%%;-(0,%"#&-$# "#; " """RS+#+&=(>l-,-6_?;1.4K34148'$&#<7>-6:--MU}Z\q|y=86<3//ME//96;:=75*,0//10GP<77OL.43*%1232-/-0(,7.+*-*.3-2*/0434B2/863HHC;;:PE07FRIF<734M.% %"jo,./"5B4),.00/08..%)!*7507/+-LDOSY|(^8(%--10,8/.F:C7,080-05/<@=974_\0('%(,%-/);.:0(+6-/3242.144362:549==A;11+89X;F=?.9/?"('('J;0b^=9O -_70&%,Bw6530$J&'-6)%&#"!,1SUC6-('EX5BA#%!!&3,Z #$'-.)%35)*/?S:B860.$ #,0DR4@PL8H>pdTI8&")-?I;1?+,/1(*-<,,.637--704}0P?+## #L7484+*3&#.1*3326224364?09E4;B>>S>B@IF=216@511=.(.5-;9-&(D%.9+%'-=%/L?:[w?/),'-5-4H.@+'$,+9.'";%'689b==Z[A^9+f3.(#& & %2 ;# <"%"!#(V''7@F2?a6GD8,"$$$1,1HO44K74;0)&$0-+504+1)*2)**(/6-/41I/-,*+I_4,)"$%+8<*,.*00);323/3;21435643>D8]DJ?l@A>B=>/3K66:32(%69,5-.!%/H.+'+-($%,'3IFL0391%+%2+(#%&14)7+;!&0/(;F^PKU^Lc&"1@'(,0-)$&&$&*&*e=-<27T-1-((3&(00&-1F! +V*1>>>P~{hk]_#?|>MM&'!'1'!#")G%eC! "#(+2%)-7\ dJGh>O+4%!& &#%&(1/&2>741.*29&'#$/,.+-(%()*'$-(d45,8/0/.%# ()+('/>'&F-0(),.6+-),3-20J886/C9&!%5),'% ,;3%&$*.(./4&H3:8%"$G/0O;@#/  #8;4*#%!YD+#$RNJ2W,CGA%*#(''&('$#!#&!!('*+,+%4('&(18%"(-+%%!$$ -,$ #!&- #%%$&$&%+3>L.,2/,(,,4E?gRaO4.06.@TgMX7J34++)4'(+)""$&&)* " ""%&"0#&,):/7J<>)?-*"$-$!c&*A483>#&(($@/1(9;-?9*"&"3 b!"%" #G2+!"$8O.56$3%%"&2%%0()#)"*'&%$+,'--(-*2W&$%5'##$&" " <%"!&$$"$#( #'(/04?JC--7.-2<;{ -ug?24+0C*03197>#$('*(/+-.""" #%"! '.$8 ##(1.G:;A.*$ # ,./#)*N@,)&./))70 ")"-%+6V9+9%! M/%GN78%"!! 1.#,%%'/6%)%$%%((($&)+%#+%A(9m!&-( #,%"$ +!$ 2,"!/&#$)>GG\1:0236387)xnR3.-.(8.(&%.6,2<,2('% +$! %"$)#! %*(#*.+ARA?RS-%+'$"$%(%(*)2+++1#'!-3;8*'3";0@/5!'( %2%,2&).4**'#$.)&$%#&&+(*(*$((!')(##"! > % #!!%" !"$$%&A0@)6(3/'*.A>oci<*$%(3/<$,)141UF>,%"+% ! #"$#'+/(#7&,*.X:=7)$<* !($ !%2+%&",)!1 *   '\z -O$!&%'$.(&.2))*%&0$" $%&$(=(*"! 9%"!  "  "#%#'!% #$(%$<&##!-FPA_M~,'$'')-6)"'.85A?k($%-&' )!"%#<$ #..#!"#;(9.,;O)%#((""#41&%&5),$!"#!""A BBD2)0-U4`bA4$ ! #% $*-/*()0,((8.("&""'*+'$$&##!%# !"%&#!!" ! .%'L/#$/'+/9S8[Tb8& $2>D&*!! $5+)K..-&9#$  "4*$$&)-$ &%5(*,(!! )&$("&30'%'"":M*#+!#.1~0B9V6!  <*$ #$255K:A@7&'&)#"!'!%!"))!#&($ !!#" % & +$&" (+%+4A2=&$%Gdpo.0#(FX0-1"0:1$"!! )7!!"(###".'/!(/*(##!';-# &( %Z>3")*2/o/6LK')$7$'$ #,'*)0-&+9S`LZ1 #$#'#!+# $6&('$#"!"!$ $$0"! !, %7')" %)H#'+ "2'2I((Y$%!-$*"('&%''#4!'%"#''&W!#(+";O3)0*%&D9&-S*"&9 &$# $ $"#8'++%9PV?A !"!$$!'#%!(87<%%## " "  )!"#&!.&))=#!!9'"4^/5(%%&""# #"! ""!+7####$ !!+'" 3$ $("%  %+(#34L[;?0(77 $,$##$# % )!""((*+$)$D556J$$"!###"$%$'%""!!'!!$ !)" !"%.I #%(# ("(&.*$ %&-"(&" ! #%&&  "(!.'"%"&#&"+"$ \ No newline at end of file diff --git a/data/fits/NGC3344.Color.32.fits b/data/fits/NGC3344.Color.32.fits deleted file mode 100644 index b0b26921c..000000000 --- a/data/fits/NGC3344.Color.32.fits +++ /dev/null @@ -1,375 +0,0 @@ -SIMPLE = T / file does conform to FITS standard BITPIX = 32 / number of bits per data pixel NAXIS = 3 / number of data axes NAXIS1 = 256 / length of data axis 1 NAXIS2 = 256 / length of data axis 2 NAXIS3 = 4 / length of data axis 3 EXTEND = T / FITS dataset may contain extensions COMMENT FITS (Flexible Image Transport System) format is defined in 'AstronomyCOMMENT and Astrophysics', volume 376, page 359; bibcode: 2001A&A...376..359H PROGRAM = 'PixInsight 1.8.9-2' / Software that created this HDU COMMENT PixInsight Class Library: PCL 2.6.1 COMMENT FITS module version 1.2.0 BZERO = 0. / PCL: Default signed data offset BSCALE = 1. / PCL: Default data scaling ratio ROWORDER= 'TOP-DOWN' / Order of pixel rows stored in the image array END (((!!! !!!!!!###%%%***.........!!!!!! !!! !!!###!!!(((&&& !!!!!!### &&& ###)))%%%$$$"""(((######!!!$$$(((---'''666,,,---&&&)))444222,,,***...000///,,,---LLL___333...333555555]]]}}}[[[HHHYYYZZZLLL>>>PPP---:::^^^999'''...,,,111---111---444...555///666000)))EEEKKK111444000333111555888000000,,,111111333333.........333666:::444222333888:::>>>;;;888>>>999999999777333777???CCC<<<===;;;999aaa666<<<>>>999777999444???666<<<333:::>>>888:::222DDD555000000...666777AAASSSCCC999???FFFCCCBBB===777;;;===777555333777222444444888333666>>>...666===777444777111***000)))'''(((000,,,!!!''')))$$$###!!!%%%    ///"""!!!&&&### ###!!!!!!''' """%%%+++ 555$$$$$$,,,!!!))) %%%)))!!!"""(((&&& )))&&&%%%***000***222111...###+++AAA+++)))&&&(((,,,&&&...666,,,)))888222444777TTT%ZZZMMMnnnHHHGGG555<<>>000000%%%///222333///000111666222...///000---***...111...000111///***444555444333333999;;;666555555888666888888<<>><<<666555AAA444333666555444333777444///:::333000444444...111???>>>111:::===CCC:::555DDD555HHHMMMGGG888>>>;;;999;;;CCC<<<666CCC777222@@@111+++***111555&&&***((((((,,,%%%###&&&'''***%%%###!!! """"""'''%%%"""!!!""")))&&&!!!###!!!""""""$$$%%% $$$!!!&&&'''""",,, """''''''&&&((((((555(((+++///***...QQQ***333555%%%$$$)))///+++...,,,666AAARRR@@@<<<:::666555+++BBBDDD<<<111...+++---/////////000+++---...000---...,,,***,,,...+++---222...[[[EEE///---...555...333222,,,555000///444777222***444444111:::@@@999777888999999AAA???:::999<<<===???BBB;;;444::::::888888:::@@@<<<444::://////111:::444333000666444666333<<<444111...;;;666000222---???;;;666DDDBBB>>>444===>>>777???@@@444888GGG888444666333---***------222111))),,,---&&&///'''%%%(((###)))+++''' (((%%% ###&&&444111 %%%$$$%%%"""&&&'''"""!!!777...)))'''$$$""" !!!!!!$$$'''!!!$$$000+++))),,,)))&&&,,,000...222***000)))***+++<<<777(((,,,444%%%'''+++---111000777LLLOOO555111666???;;;---===111......///111111666+++///---...(((******''')))******---///555666111222000///111++++++000&&&---000555444333222222444@@@???777222666777777888999777777555:::999888???<<<:::;;;;;;DDD@@@@@@<<<>>>444888444666888666666444555999444666777888:::<<<777333555===EEE???444444666777222222444;;;RRRLLLEEEFFFKKKLLL<<<888VVV888999---444...///---///,,,+++AAA''')))(((---$$$...///((()))&&&""""""!!!""")))'''%%%888888 !!!###%%%000!!! !!!111$$$$$$###$$$+++%%%111###!!!"""  )))666&&&+++---###(((&&&(((...)))000???222:::999LLL222000BBB///111'''+++(((222111+++000---777EEE;;;666777===:::IIIQQQ,,,...***+++---)))+++,,,******,,,...,,,///+++)))+++...555999000///000000444111000000...///,,,444444...888,,,222666444222222FFFEEE;;;888;;;666>>>@@@999<<<:::999777999===@@@777???DDD<<>>CCCOOOIIIFFF666AAACCC888<<<000666999???000,,,...---222&&&)))+++///'''$$$111***+++000!!!!!!###'''$$$!!!### 111(((+++)))%%%...)))"""###///))) !!!'''((("""%%%(((!!!&&&$$$###&&&"""((($$$'''999/// ---((()))******+++666:::GGGeeeoooBBB;;;CCC000)))$$$&&&000888...111///111+++:::777222222666333111999<<<333000222000,,,,,,000------***---000111444111+++666222000111...>>>WWW444------///......,,,333111,,,......222444888999PPP999;;;===666999:::???<<<@@@888444444666999???AAA;;;999<<<>>>\\\AAAYYY??????AAAAAAKKKAAA>>>999===???999???222BBBQQQBBBRRRIII???cccAAA:::???@@@<<>>999999<<<<<>>FFFAAA555999===???XXXQQQ^^^kkkfffHHH<<>>XXXIIIFFFMMM``````aaaZZZooocccVVVSSSLLLZZZDDDDDDGGG<<<000///...444222+++444///((())))))$$$###$$$&&&+++)))%%%))) !!! """ +++"""999%%%...;;;CCC""" ,,,'''!!!### !!!&&&111!!!###---###;;;))),,,:::,,,***LLL'''+++&&&,,,***$$$)));;;'''***...222BBBaaa WWW4VVV333///+++(((******,,,---...---222///000555...***))))))333888AAA;;;:::RRR000333000...***)))//////%%%'''---+++---...***...333444888SSS,,,000.........+++(((///000,,,...333666555111111444222666666;;;777:::;;;:::888:::LLLBBBDDD>>>EEE???:::888<<<===BBB@@@EEEAAAJJJ???HHH@@@;;;;;;>>>AAA999:::BBBHHHBBB<<<[[[zzzNNNLLLNNNhhhCCC666;;;BBB;;;DDDMMM@@@HHHPPP[[[```uuuvvv[[[bbbEEEUUUSSS;;;CCC???HHHMMM222333777555...///222%%%'''(((%%%###)))333666'''!!!!!!((("""!!!!!! $$$###""" %%%...'''>>>))) $$$)))%%%###'''""" '''***!!!!!!%%%((((((BBBAAA$$$)))(((444111***(((&&&%%%$$$+++999(((000CCC+++<<<000...PPP ssszzz===333---111...---+++)))///...333...+++:::111---333888000000222555CCC???qqq111111...+++***,,,///;;;///++++++,,,CCC///,,,+++***---777888///+++(((+++,,,333***,,,---///000000333666444555333555000444333555666???;;;>>>888]]]===???======???888>>>DDDJJJ@@@666===CCCPPPHHHUUU<<<<<>><<<@@@QQQ:::AAA===XXXcccJJJKKKAAACCCBBB???888444>>>RRRNNNVVVUUUWWW*iiieee]]]EEEHHHOOO<<<::::::555222888666CCC000111---111(((+++,,,*********'''$$$%%%%%%%%%(((!!!***!!!(((!!!GGG"""!!!###"""(((QQQ444KKK%%%%%%!!!'''""" !!!### %%%,,,)))---333'''---$$$###))))))...444&&&,,,)))---(((+++&&&&&&888555///111,,,===333222555<<<333OOOaaaSSS444444(((+++---+++...GGG)))---222+++111---,,,///+++---///---333444FFFWWW^^^999000000888///...+++...555,,,)))---111;;;---//////000---,,,+++'''++++++111<<<***+++---000///+++333000222000...222555222555333888===>>>???<<>>888888???BBB@@@???AAA===AAAsssmmm===GGG>>>===AAA@@@999HHHCCC???<<<===<<>><<<@@@>>>:::CCCCCCDDDCCCKKK999888EEE[[[FFFAAA>>>MMMlll:::<<>><<>>:::;;;BBB>>>HHHZZZLLLFFF<<>>@@@EEEBBBEEEAAACCC<<>>:::===777111888:::555333444222222111222+++***)))&&&))))))***%%%!!!!!!&&&***$$$ """!!!"""%%% !!!******!!!&&&$$$--- !!!### ###,,,%%%###'''555###'''$$$$$$///---444///555:::***RRRHHHQQQOOOLLLAAA222///***)))///EEEccc'''""")))%%%,,,(((######+++(((...???JJJ)))%%%))))))++++++---)))***///&&&+++***&&&&&&***,,,***'''+++000+++------+++,,,:::,,,///...(((%%%111888999---///---000000;;;---,,,---***;;;///***//////***((((((,,,,,,---...000444444111///111222333666666888888777555======FFF???<<<>>>???@@@<<<999<<<>>>???AAA999??????III???>>>>>><<>>...***((('''***...+++&&&$$$&&&---...&&&((((((&&&+++"""(((---)))'''888'''+++///999))),,,(((111,,,))))))******+++777000***,,,000000111000///;;;)))***000,,,+++---222777444------...888+++666---...000+++---444///,,,000)))///999333,,,,,,111333555///333111444222777333444333555555666888PPP777MMMBBBFFFCCC999<<<<<<999::::::>>>=========;;;BBB@@@888===EEEBBBCCCKKKCCCCCC<<>>>>>>>>@@@;;;:::<<>>@@@<<<999>>><<<:::777333666999222+++...222888777---,,,)))***,,,)))---...)))&&&)))######'''###&&&"""######  ###%%%333 ///'''III &&&555,,,######%%%,,,)))...)))###---222...000---///000111222<<>>===;;;;;;===666<<<===;;;888AAACCC@@@===AAA>>>;;;DDDEEEGGGooo???::::::HHHDDDJJJ:::@@@???:::;;;======<<<@@@<<>>222---,,,++++++%%%%%%&&&---'''$$$$$$$$$$$$///,,,***+++***---+++&&&+++,,,---)))***(((222'''+++///???*********,,,;;;+++///111///***000---///)))---***(((+++222444000000...+++111333555---999333///000---000111000222222555555555444111222222:::222<<<666999333===444555555222555777>>>666555<<>>BBB:::;;;======BBBDDD===AAABBBAAAAAAJJJGGGDDDDDD>>>FFF>>>XXXDDDJJJBBB:::<<<777AAABBBBBB===EEE<<>><<<444222000444===666222/////////555888888---******&&&'''((('''...&&&&&&&&&"""%%%!!! ### """$$$%%%,,,"""'''!!!%%%)))"""*** """***000,,,@@@777'''### 000...***CCC''''''------000666---???666BBBEEE<<>>;;;BBB===:::<<>>CCCFFFEEE@@@@@@<<>>???BBB===CCC999222222:::777...222222111)))111---AAA333///---&&&,,,,,,///&&&&&&111???***+++$$$$$$&&&%%%&&&!!!  !!!***333$$$!!!"""  !!! """###---999""""""&&&"""***'''KKK$$$&&&"""###***%%%###&&&''')))%%%$$$---:::222111HHH;;;111>>>EEEZZZrrrkkkaaaJJJBBB555---+++---+++'''---(((+++000&&&%%%(((---,,,'''$$$######***)))'''((((((...'''---***&&&&&&+++***%%%)))+++---111000555+++***++++++,,,///---111333+++***222------+++,,,///000555---333333111...---555444......@@@;;;444111...333777888222888<<<999555:::<<<777555777888;;;999555555333===555444<<>><<<222///,,,000---...111333EEE222...+++)))'''(((+++)))%%%---333---///---"""$$$$$$$$$### """'''(((AAA!!!$$$!!!!!!mmm%%%...(((===!!!$$$ &&&%%%###!!!!!!%%%%%%$$$$$$((())),,,'''+++,,,999AAA???999888999???F0tttwwwLLLCCC222)))///###...(((+++///%%%(((&&&'''))))))000...+++%%%)))***+++,,,(((PPP(((&&&&&&+++***(((---)))((()))---666:::888;;;000,,,(((+++,,,---,,,---...---......,,,,,,---,,,222222888999///444333,,,222555555777///111222777111666555///222555111000888///777::::::;;;===666888>>>>>>CCC<<<:::666:::::::::888999999???DDDDDD>>>GGGAAA>>>BBB<<<:::>>>@@@OOO@@@CCCJJJDDD@@@AAAGGG<<>><<<<<<;;;^^^fffbbbjjjUUUOOORRRDDDBBB@@@AAA999>>>777888:::333777666;;;333444???---...---''')))*********111...---,,,+++$$$###)))+++(((((( ###,,,***"""!!!!!!$$$ !!!######!!!***&&&$$$,,,%%%"""###!!! %%%###!!!&&&%%%(((!!! )))***'''&&&$$$---333222999===SSSpppM* aaaAAA:::222((()))///444))))))'''%%%***((()))***))),,,...+++)))''')))((()))+++)))***&&&$$$))))))+++******...---///+++...222000///(((******,,,...+++...111111///000,,,---///------777222111222000333222000333888BBB@@@999000222555444777FFF???999222000888777::::::???EEE666999<<<;;;777444999666>>>>>>===<<<<<<>>>;;;888EEE<<<>>>EEE===>>>@@@HHH===@@@@@@???FFFAAA???GGGDDD===EEEFFF===>>>DDDDDD???AAAAAACCCMMMOOOFFFEEE???<<<>>>999999@@@NNNccciiiUUUMMMGGGQQQMMMEEEKKKHHHAAAEEEOOO;;;666>>>>>>CCC\\\???<<>>AAAKKK@@@EEEFFFBBB>>>>>>===KKKDDDRRRLLLUUUNNN@@@DDDDDDCCCFFFDDDCCC;;;<<<<<<999;;;888AAAQQQTTT___TTTLLLSSSIIIcccIII@@@QQQ???>>>>>>:::>>>777666;;;666;;;DDD222***...'''000111...***---<<>><<<777===888>>>FFF???@@@BBB666;;;HHH333:::???>>>555<<<:::333888999>>>???>>>CCC???EEEIIIBBBGGGEEEXXX999999<<<:::999===:::777888;;;;;;<<>>CCCDDDPPPDDD@@@@@@???===>>>KKKGGGPPP:::===@@@@@@GGGBBBAAA===999===???@@@AAABBBCCC999999>>>LLLOOOZZZYYYMMMGGGGGGIIIGGGJJJOOO;;;@@@BBB;;;:::<<<777;;;666666222111444000111:::444***000///000+++---+++222***&&&(((&&&$$$$$$!!!###***,,,!!! ,,,(((%%% &&&$$$&&& (((222@@@"""!!!  $$$!!!((("""!!! !!!$$$ !!!###/// $$$&&&$$$""""""###(((+++'''222KKKuuu tttLLLWWWaaaEEEDDD@@@222...333***...---222///+++,,,---***(((---,,,---...$$$+++---+++---***---,,,...***&&&***...000+++---///---222222111666333111333111333000222111---///---222333444444555222555333777444555333444777999;;;HHH:::999555555777===888777<<<===666888;;;666;;;@@@>>>NNN===:::CCCKKKBBB999999???===@@@888777777888:::===;;;999999FFF@@@???FFFAAA<<>>888>>>CCCEEEFFF@@@===CCCBBB888<<>>AAA<<<>>>:::777666333333111000111+++111///...888777>>>///444000222((()))444,,,,,,333999!!!"""%%% LLL...%%%&&& '''))) 444DDD!!!%%%$$$444(((!!!!!!---&&&'''!!!###!!!###"""$$$"""$$$%%%)))$$$ """"""&&&'''(((111;;;DDDIII@@@VVVoootttOOO>>>DDD999222000---***'''---444...;;;+++))),,,)))((()))+++222,,,///,,,...444000---+++...===------000000444444777///111///888...000000000......000222---///333333666000555555444333888<<<;;;999222555333:::888222666:::@@@444333888EEE999333333444555555;;;===999888777???QQQKKK;;;888777;;;999555===;;;;;;888???<<<;;;???@@@777===999:::===@@@>>>BBBBBBEEEAAAKKK===CCCBBBEEE@@@>>>@@@CCCEEEAAA?????????BBBAAAEEEAAAAAAHHHEEECCC>>>:::@@@@@@BBB:::III===FFFIII```KKKEEE===JJJ@@@LLLFFFEEE>>>:::<<<;;;999555333666222(((---PPP===888DDDBBB555,,,...,,,444000)))(((&&&)))%%% ###111999"""$$$!!!###  ###!!!)))'''''' """111 ### !!! $$$,,,"""!!! """'''""" ###333###%%%###'''### %%%((($$$&&&&&&+++///000,,,III[[[pppfff```hhhQQQCCC:::>>>999999777///***111///222,,,***,,,,,,***---)))...)))***...000///---111,,,000333,,,,,,111///111***---,,,,,,000***111---===222111///---000---...222000333555111111222666333000222---///000777444666666:::<<<___:::;;;999???999777555333,,,666666666666CCC888888999===:::>>>:::999444888333888@@@???:::AAA>>>:::888<<<@@@===:::<<>>;;;GGGAAA???AAAIIIGGGDDD>>>???BBBAAADDDEEEFFFHHHOOOCCC===@@@@@@@@@GGGAAA@@@:::FFFTTTWWWIII]]]KKK???EEE???FFFGGG===AAADDD666555888111222111333---000444:::???ZZZZZZMMM999---)))&&&###)))%%%,,,)))*** &&&***&&&"""***... ###"""??? '''&&&%%%XXXRRR333 BBB$$$'''$$$ %%%"""$$$&&&((())) ###$$$$$$!!!&&&%%%'''(((''')))%%%###'''&&&))),,,666XXXeeeiiifffyyydddCCCCCCGGG???<<>>---+++'''((()))...+++,,,,,,000+++000:::111,,,///000===,,,---///---666>>>:::,,,///---+++000555555555444666555111111666///...666777777111444888444555222444555666HHH333444:::888===;;;???JJJNNN666:::333888333777444777999999<<<>>>BBBHHH;;;777999999===777444999<<<999LLL@@@???===@@@DDD;;;:::AAA:::@@@GGGQQQ@@@???===<<<======???FFFBBB@@@BBBHHHEEEFFFBBB@@@BBB>>>AAA???<<>>:::)))===///...'''&&&222!!!!!!""")))"""BBB;;;333!!!!!!===,,,!!!888!!!###"""""" $$$'''"""%%% $$$'''###+++***%%%$$$&&&'''((((((+++)))***@@@PPPbbbX -pppAAAKKKIIIjjjPPP444)))...---,,,444///111,,,111))),,,)))000@@@AAA...000...222555BBB999000...555777222***///555444444666222111>>>666666444DDD:::777;;;444555CCC<<<777555777:::888:::;;;444333333:::;;;999FFF@@@999<<<888:::@@@OOOHHH;;;999777222<<<555666444666:::???:::AAA===@@@999999CCC<<<===333666HHH===EEE???FFF===:::======???>>><<<<<<999???BBBBBBAAAEEEAAACCCEEEBBBBBBDDDBBBDDDLLLGGGHHH<<>>@@@>>>>>>BBB@@@???BBBHHHGGGFFFAAA>>>DDDFFFPPPAAABBBDDDBBBGGGUUUQQQOOOJJJIIIHHHGGG:::;;;@@@777111333///111///444///555wwwC|||LLL;;;333)))+++,,,((('''######)))&&&&&&+++)))$$$ %%%(((***"""###&&&,,,$$$%%%111111'''///444ppp###&&&###""""""(((///''' ###!!!"""%%%&&&"""222(((###""" """((()))$$$%%%'''(((---222222FFFUUU!ZFWWWWWWJJJ888GGGCCC===......,,,000------***000---******222333999;;;111------444222888AAA111111000999777999333AAA444000333333777666@@@<<<<<<999<<>><<<@@@@@@:::CCC777333555666555111555444888666999???HHHAAA@@@FFF999777999FFF333444111888777999<<<999>>><<<<<<888???DDD:::???999DDD<<<BBBCCCJJJ===>>>===>>><<<>>>999:::;;;AAA@@@@@@>>>EEEFFFHHHLLLJJJFFFKKKCCCFFFIIIGGGJJJAAA@@@DDD???FFFDDD???CCCEEERRRFFF@@@CCC???DDDWWWJJJHHHMMMIIIHHHGGGOOO^^^hhhgggMMMFFFCCC===999<<<555666666,,,//////222222:::}}}MFFF111)))---(((+++))))))%%%###"""...'''$$$...###"""%%% """!!!,,,%%%"""''')))!!!!!! """&&&&&&///&&&111...***  """###%%%$$$"""$$$ ***""""""((($$$"""$$$###,,,%%%'''$$$%%%'''%%%((((((999===MMM|||<9}}}cccaaa:::CCC>>>===666111555...333111+++...555EEE111111222...222333111444333111......+++333222222===:::888555777555999444666444:::888:::777666QQQ@@@555888888777<<<>>>===;;;:::<<>>@@@@@@AAAKKKGGGJJJ???YYYDDDAAAAAABBB???AAABBBHHHDDDDDDCCCPPPUUUCCCKKKCCCDDD???JJJQQQKKKTTTcccDDDHHHSSS^^^~~~jjjLLLEEEEEE@@@;;;777;;;===:::666///111888///GGGYYYIII(((---)))&&&$$$---''''''"""&&&'''$$$555  !!!###%%%###""""""######222)))''''''%%%000>>>%%%&&& ######### !!!'''(((%%%### ((("""!!!###...888((("""$$$(((,,,999///RRR\\\NNNooo,#"^^^bbbUUUFFF<<<444999999:::222333...000333999000+++---333///222888888:::888222444222///000666555...444777111999888999:::666666;;;888888KKKEEE444888???===::::::<<<<<<<<<888???>>>___???<<<@@@???@@@===999666BBB555555666999AAA777888::::::===CCC666:::RRRHHH:::???:::???777>>>OOOWWWCCCEEE>>>===:::@@@===???@@@AAADDDIIIDDD???>>>BBB<<<<<>>111...333999999JJJ===>>>333999///...333//////---)))222555...333000111666...333999999777666555PPP888;;;::::::888888888;;;999888===555999<<<======<<>>;;;777999<<<===:::BBBNNNDDD???666;;;:::777777::::::666888777555::::::IIIFFFDDDNNN>>>::::::999333888888888>>>AAAEEEKKKLLL;;;???999777<<>>:::=========;;;???CCC>>>;;;???QQQ???@@@@@@NNNSSSMMMYYYNNNeeeFFF???EEE@@@===AAAGGGFFFCCCCCCAAABBBKKKEEEQQQ???DDDAAA@@@;;;AAASSSJJJZZZ___GGGuuu```EEEFFFLLLCCC@@@BBB999777555555333333+++000...666666)))---444///+++###'''&&&)))&&&%%%///+++''''''#########---------'''---+++111EEE666!!!""""""###### !!!  $$$!!!###$$$...$$$%%%'''!!!"""%%%)))!!!""" !!!"""%%%222!!!...///777<<>>888666@@@666///222222///,,,---444666222...222222111000---888666555333111111555AAA888???;;;>>>333:::===777888===888???===222333666888<<<;;;999:::;;;<<>>::::::<<<;;;<<<999333<<<888888???;;;AAA;;;IIIvvvJJJ999666AAA222888888444999<<<===???RRRggg@@@999;;;======LLL===@@@AAAAAAEEEHHH888???;;;======999:::<<<;;;===FFF===999\\\VVVRRRYYYKKKPPPVVVCCCEEEEEEAAABBB===BBBEEEEEEEEEEEE@@@GGGNNNGGGIIIFFFEEE<<<<<<===FFFEEEGGGddd___oooJJJJJJ;;;CCCHHH<<<999===888===333///......))))))---,,,,,,...000,,,+++...$$$###&&&(((&&&,,,'''$$$'''$$$###%%%****** (((:::444000***!!!$$$(((""""""!!! ''' !!!!!! ...,,,###((((((222333)))'''$$$$$$!!! ###"""%%%---000+++---000>>>000DDD<<>>999<<<;;;555;;;@@@@@@???<<<======@@@===AAAFFFEEE===???;;;999777999@@@>>><<<;;;<<<<<<;;;999555999===:::===BBB<<<888CCC<<<>>><<<>>>@@@444888:::BBBCCC777;;;>>>DDDaaaHHHFFF;;;>>>@@@===999;;;:::???EEE[[[<<>>>>>[[[DDDBBB^^^JJJCCCEEEEEEFFFDDDBBB@@@AAA>>>EEEEEEEEEHHHEEEKKKFFFKKK]]]MMMQQQ@@@<<<666<<<======eeelllNNNdddZZZKKKDDD<<<@@@>>>888777666444,,,777222+++,,,222***+++///111///(((---&&&+++&&&(((&&&&&&)))((($$$(((&&&(((***000%%%@@@---444,,,)))(((!!!)))&&& ((((((""")))$$$///%%%$$$'''$$$(((""" %%%444+++"""%%%(((+++!!!###!!!)))%%%$$$///(((!!!&&&***)))...000,,,777@@@PPPgggQQQDDD666555QQQ888===CCC333444777222222:::555888444555222555999;;;666888:::======888HHH???777;;;999999666666;;;999;;;>>>>>>DDD@@@888???AAA777AAA>>>@@@CCC@@@???@@@>>>GGGBBB???AAA;;;===>>>@@@CCC;;;888FFF:::===888:::<<<<<<>>>======<<<:::BBBEEE???EEEBBB<<>>;;;>>>;;;???KKK@@@BBB888999===```KKK???===;;;>>><<<;;;???>>>AAA;;;<<>>@@@<<<<<>>>>>@@@@@@888999:::===999888@@@AAADDD===@@@DDD>>>FFFBBBHHHJJJBBB???===GGGJJJDDD???AAABBB===AAA<<>>;;;BBB>>>GGG>>>NNN888AAA777======<<>><<<>>>AAABBBDDDDDDJJJ<<<777::::::666KKK:::BBB@@@>>><<>>===>>>AAAAAAJJJEEEAAACCCAAA@@@VVVFFFCCCAAAEEECCCHHHAAADDDDDDEEEIIIMMMEEEFFF@@@===FFF^^^[[[FFFZZZBBBIIIMMMFFFGGGYYYAAADDD===:::777444BBB999555666///---...,,,FFF(((&&&(((((()))+++%%%)))&&&,,,+++'''...///$$$***)))'''%%%'''---QQQ EEE'''&&& """((( """### %%%!!!$$$'''&&& !!!%%%+++SSS%%%!!!%%%555111111,,,%%%'''000%%%***%%%%%%'''%%%$$$&&&+++"""$$$+++''',,,,,,555666555...;;;999999444444888///111DDD777444;;;AAA666///222555999777@@@;;;333666DDDAAA@@@<<<;;;???>>>@@@888===TTTHHHAAA===BBBEEEBBBEEE===;;;;;;;;;???GGGGGGDDDDDDIIIDDDDDDDDDJJJJJJCCCMMMEEECCCFFF@@@@@@<<<;;;<<<:::888:::888>>>???999===>>><<>>LLLWWWCCC@@@;;;===IIIBBBEEEDDD<<<888EEE???CCCLLL===;;;>>>???AAA888555;;;GGGAAA999<<<:::BBB>>>@@@@@@<<>>@@@AAA>>>@@@CCCDDDEEEAAA???FFFFFFGGGPPPJJJFFF@@@GGGCCCEEE???DDDKKKEEE>>>BBBIII<<>>:::CCCBBB???>>>KKKIIIaaafffUUUEEEHHHEEECCCDDDAAA;;;JJJBBBCCCFFFJJJJJJEEEJJJLLLDDD@@@BBBDDD;;;HHHfff===<<>>>>>EEE???<<<;;;;;;===:::AAA>>>???<<<@@@AAAGGGBBB===<<<@@@LLLHHHBBBAAA<<<===888<<>>AAA@@@===???===<<>>@@@KKKAAAEEEBBB???DDDHHH@@@EEE???MMMAAAVVVEEECCCDDDJJJEEEBBBMMM@@@AAA;;;333??????GGGHHHRRROOOJJJRRR>>>AAA:::===<<<333000444555//////000222...***...+++222***111(((,,,+++'''(((000333)))(((NNNfff))))))&&&""")))333999```222+++&&& !!!$$$444+++===999%%%!!!&&&$$$'''###!!!$$$&&&%%%111---KKK)))(((:::###!!!))))))+++$$$###$$$'''...???))))))///%%%...---...,,,///222///666000======EEE777111111///888222222555:::GGG===999999555===;;;<<<>>>@@@HHH<<<<<>>HHHGGGAAA???AAAAAA@@@???@@@FFF>>>AAA;;;???DDDGGGBBBAAA>>><<<===HHHAAABBB666>>>CCCAAABBBPPPPPPkkkCCCBBB@@@AAACCCGGGDDD>>>999;;;AAA>>>AAA;;;===@@@;;;>>>CCCEEE===<<>>BBB===EEE@@@CCCCCCCCCCCC@@@>>>>>>DDDEEEJJJFFFGGGHHHGGGIIIKKKAAA>>><<<;;;???BBB???DDDIIIKKKIIIJJJGGGAAA???:::888999888555555444666---333///000,,,'''---000******)))######(((***...+++)))$$$***+++)))000...***)))(((///---$$$((( ######'''444))),,,---((('''&&&###&&&&&&$$$!!!'''"""+++ZZZ<<<)))'''"""&&&((()))***000333&&&&&&###((((((,,,111***(((,,,***444666444MMM:::]]]KKKLLL???333:::555222444444555555888<<<;;;>>>;;;888:::???888===:::;;;@@@BBBBBB@@@>>>BBBQQQKKKEEEhhhbbb{{{ZZZHHHEEEHHHBBBBBB???IIIIIIJJJJJJHHHKKKAAADDDCCCCCCGGGIIILLLKKKHHHJJJNNNHHHEEEIIIEEEEEEBBBDDDBBBDDD@@@BBB@@@AAAIIIGGGCCCDDDBBBAAA???>>>GGGNNNVVVKKKDDDBBBDDDAAACCC>>>??????@@@FFFHHHDDDBBBEEEGGGEEEAAA>>><<>>IIIAAAFFFGGGEEETTTcccAAAAAAHHH@@@@@@JJJSSSCCC???DDDCCC>>>EEEHHHDDDGGGBBB>>>EEEEEE>>>CCCJJJFFFEEEGGGMMMIIICCCBBBGGG>>><<>>???999666111888111222999111---...---,,,---******''')))$$$)))***%%%!!!+++((((((===+++eee===$$$###%%%222666)))***$$$>>>!!!$$$!!!((( &&&&&&&&&  $$$!!!!!!######%%%!!!&&&***$$$000!!!)))(((...'''%%%333)))((($$$&&&%%%"""###333***///,,,333333...777000444;;;:::@@@888888===>>>222999AAABBB888999333888>>>MMM===888JJJ999>>>999AAA@@@BBBCCCEEE???DDDIIIIIINNNQQQ NNN@@@??????JJJCCCEEEFFFHHHNNNFFFIIIWWWDDDLLLIIIEEE@@@BBBIIIFFFFFFCCCJJJPPPTTTLLLHHHDDDDDDGGGCCC???CCCAAAPPPGGGDDDGGGKKKGGGKKKGGGFFF@@@???GGGJJJPPPHHHJJJKKKKKKDDDGGGAAAAAADDDCCCHHHFFFJJJLLLOOOLLLFFF@@@;;;??????>>>CCCEEEBBB@@@@@@===GGGAAAAAAEEEaaaGGGSSSCCC@@@@@@@@@JJJFFFDDDDDDMMMKKKEEEFFFDDDGGGHHHHHHMMMOOOQQQGGGLLLEEEFFFJJJHHHIIIFFFHHHGGGEEE666===AAAAAA@@@CCCGGGGGGIIIFFFCCC:::???<<<:::444444888BBB111111444333///,,,''')))000(((%%%%%%$$$%%%'''$$$"""((('''...333...555***&&&%%%$$$%%%***,,,'''"""AAA ###%%%888 """$$$ ###%%%>>>...+++###$$$"""###&&&222333&&&)))---'''%%%))))))***&&&111---...>>>777000333555@@@@@@<<<444IIICCCJJJ@@@666<<>>CCCJJJ<<>><<>>BBBBBBCCCDDDFFFTTTRRRHHHEEEHHHNNN???@@@>>>@@@HHHJJJIIICCCFFFGGGBBBJJJNNNMMMLLLIIIWWWHHHHHHJJJDDDPPPIIIJJJIIINNN666111DDDHHHHHHDDDCCCIIIGGGCCCAAA<<<@@@:::>>>888111888777666222:::///...///???''')))***(((***''')))'''&&&)))((('''(((444MMM'''***---%%%+++&&&$$$###%%%((()))))) !!!###!!!(((///%%%''' ###000 ((( """$$$---(((  ((('''***...DDD###!!!'''000'''$$$&&&***+++***'''000555444JJJ000000111555---===<<>>CCCAAAPPPGGGFFFIIIWWWMMMSSSBBBAAAEEEGGGEEEGGGLLLLLLGGGFFFRRRJJJHHHFFFHHHHHHJJJKKKBBB>>>KKK^^^hhhKKKHHHNNNPPPXXXUUUSSSIIIMMMHHHMMMLLLMMMGGGKKKIIIFFFNNNLLLOOODDDIIIGGGDDDIIIMMMFFFJJJIIIMMMPPPPPPJJJPPPHHHNNNHHHPPPFFFNNNXXXHHHJJJVVVKKKIIIMMM???===GGGCCCCCCDDD???JJJFFF???CCCAAAKKKFFFJJJIIIHHH@@@>>>AAAEEEDDDBBBGGGAAARRRNNNNNNEEEFFFKKKIIIRRRTTTOOOFFFDDDLLLGGGFFFHHHJJJIIIHHHIIIIII???:::999???KKKFFFAAA???EEECCCHHHQQQ<<>>555777555999777333>>>---***))),,,%%%***///))),,,(((&&&)))///&&&###(((///***)))&&&///(((///)))%%%((('''''' """ ###%%%&&&444!!!###"""$$$///%%%!!!!!!"""""" )))###'''&&&===***(((((("""(((***,,,+++)))111+++''')))222222555000///555///555KKKHHHLLL888DDD===999888888:::666:::777888999999KKKAAAAAA@@@KKKLLLVVVZZZGGGGGGHHHHHHDDDKKKPPPXXX[[[YYYOOOGGGGGGXXXLLLEEEwwwOOONNNPPPPPPGGGFFFHHHGGGIIIMMMQQQPPPKKKQQQVVVZZZmmmrrrhhhbbbpppuuuhhhVVVYYYUUUPPPTTTTTTOOOJJJJJJIIIGGGLLLOOOJJJPPPNNNFFFJJJFFFJJJQQQLLLNNNNNNSSSPPPQQQTTTPPPOOOOOOIIIJJJLLLKKKPPPQQQKKKLLLOOOTTTMMMLLLIIIHHHEEELLLIIIMMMLLLEEE@@@@@@AAA???GGGEEEHHHJJJBBBMMMJJJFFFDDD]]]KKKHHHIIIPPPIIIJJJMMMNNN^^^SSSLLLGGGDDDFFFLLLFFFFFFIIIKKKEEEGGGEEEAAA@@@555888AAADDD@@@EEEEEECCCKKKFFFDDDAAAFFF:::;;;777222:::999BBB000......---)))+++((('''***,,,(((---***###%%%(((---&&&000)))***'''(((###"""$$$###"""!!!(((!!!  ***### $$$)))!!!###'''"""!!!###%%% ###(((222&&&!!!)))(((((()))$$$***(((+++111&&&)))000333222...111333???===???777666BBBIII777:::;;;888888555===AAA888777GGG???444;;;999888>>>CCC???CCCSSSUUUjjjxxxjjjkkk^^^SSSWWWPPPNNNKKKSSS```TTTLLLCCCGGGJJJNNNVVVKKKXXXVVVEEEJJJIIIOOOPPP[[[SSS___NNNPPPZZZZZZhhh3 ccc ccc^^^XXX___OOORRRWWWQQQOOOPPPMMMJJJJJJNNNSSSLLLNNNIIIJJJIIIIIIOOOJJJTTTQQQRRRQQQPPPSSSNNNOOOQQQLLLPPPLLLQQQOOOGGG<<>>>>>888777===444888444555444---...666(((+++---...---***)))&&&$$$(((''')))++++++******+++%%%$$$"""$$$!!!"""&&&%%% !!!!!!'''###!!!***!!!$$$!!!######$$$)))''')))###$$$$$$$$$"""(((%%%$$$&&&+++$$$$$$'''---'''BBBCCC---+++555333888999999333;;;888888>>>===CCCIII:::444444555>>>888>>>???===<<<>>>:::EEE???FFF???FFFHHHLLLFFFBBB```lll,{{{dddQQQ^^^UUUVVVWWWXXXPPPIIIPPPYYYMMMNNNLLLTTTMMMJJJQQQJJJLLLIIIEEESSSQQQUUUZZZYYYQQQWWWVVVUUUoooooowwwJ,'wwwcccVVVVVVUUUQQQVVVQQQMMMLLLPPPMMMMMMUUUPPPOOOMMMJJJKKKJJJJJJNNNIII[[[SSSKKKSSSYYYXXXOOOKKKRRRNNNMMMNNNPPPIIIGGGEEECCCHHHRRRUUUPPPLLLNNNHHHPPPVVVOOOLLLIIICCCEEEAAACCCGGGAAAFFFGGGFFFCCCCCCIIIDDDCCCGGGNNNEEEFFFOOOPPPKKKDDDIIIHHHJJJJJJGGGEEERRRIIIKKKPPPqqqDDDHHHNNNHHHHHH>>>;;;FFFDDD???IIIFFFBBBEEEEEEDDD===888222555>>>555666GGG444///---111'''---******'''444(((***%%%###)))AAA%%%'''(((000000%%%)))+++&&&&&&$$$(((&&&+++$$$&&&$$$(((<<< ###!!!!!!!!!"""'''""",,, !!!((("""###!!!!!!$$$'''$$$'''((($$$###!!!###))))))---,,,111***111333333---333333AAA???000000555666555<<>>CCC999;;;??????666<<>>CCCHHH[[[CCCCCCEEECCCRRR:::<<>>SSSeeeGGGEEELLL<<>>###!!!### '''!!!""")))###&&&(((&&&&&&"""(((###<<<--- ###%%%000$$$'''&&&%%%------111///555---???)))+++000///...///111---222333///333333999<<<===;;;666:::333999:::===AAA:::777>>>===<<<===@@@@@@<<<>>>>>>:::<<>>===CCC@@@777666666000---111333---(((,,,+++)))+++***333((((((***&&&...&&&&&&)))''''''***((($$$&&&%%%)))'''$$$$$$...''''''%%%GGGsss!!!***&&&+++000333DDDKKKCCC>>>,,,'''---%%%!!!######$$$---444888111,,,+++000...------...+++---+++///999000333111666333;;;888888<<<;;;555888<<>>@@@BBB@@@AAA;;;<<<:::FFFBBBUUU{{{oooDDDBBBGGGKKKRRROOOUUU\\\\\\XXXZZZ^^^OOO]]]^^^RRRRRRQQQNNNMMMUUUOOOOOOMMMOOOTTTJJJRRRKKKOOOVVVTTTUUUQQQ]]]WWWgggWWWXXXhhhkkk___ZZZ]]]jjjkkk[[[\\\\\\ccc```ZZZ```hhhgggwwwaaaeeelllccc___ZZZZZZXXX[[[[[[UUUYYYUUU^^^YYY]]]eee^^^___]]]XXXXXXRRRVVVVVVXXX\\\ZZZZZZYYYbbbggghhhfffqqq#xxxVVVRRRSSSQQQKKKKKKKKKJJJMMMKKKFFFOOOPPPFFFLLLKKK\\\fffIIIFFFcccPPPNNNRRRLLLDDDBBBIIIFFFBBBGGGOOOPPPMMMQQQMMMMMMNNNLLLRRRZZZsss<<<@@@HHHNNNGGGFFFFFFSSSKKKEEEBBBBBB???BBB<<>>222666333666...***222///)))***((()))%%%...(((******,,,***%%%'''222)))'''&&&%%%))))))((($$$(((+++$$$!!!"""$$$...(((###&&&///666444444666jjjxxxOOO111+++)))%%%###!!!777GGG,,,(((---@@@///000111---222777(((999;;;888777555444===@@@???777444777<<<:::;;;AAA<<>>===<<>>EEE:::777===888;;;999888EEEBBBAAASSSJJJQQQkkkLLLQQQ[[[aaajjj[[[OOO^^^MMMLLLSSSOOOSSSTTTSSSZZZOOO[[[TTTMMMRRRWWWVVV\\\UUUNNNRRRZZZUUUWWWQQQXXX]]]XXXXXXbbb[[[YYYUUU^^^\\\```\\\^^^aaaaaa]]]XXX\\\aaa___dddhhh\\\sssiiillldddaaaZZZ\\\ZZZYYYWWW___lll___]]]^^^eee]]]ccc```ccc]]]]]]dddZZZ```XXXZZZWWW]]]~~~^^^aaa^^^\\\bbbUUUaaa]]]iiiVVVRRRVVVQQQSSSNNNJJJMMMIIIJJJRRRPPPNNNMMMDDDLLLJJJHHHSSSammmNNN___DDD>>>EEE===EEEHHHIIIRRRLLLKKKPPPSSSMMMOOONNNHHHGGGDDDGGG>>>JJJIIIDDDHHHFFFAAA@@@BBB===FFFBBB???:::777XXX???===222---******,,,+++***)))'''111)))--->>>---,,,((()))%%%%%%###+++***%%%''')))''')))777"""%%%(((''''''%%%+++***'''CCC444222555111(((&&&888333***&&&///%%%&&&888...000))),,,666333666...666444333<<<===DDD222DDD<<<777888777CCCCCC444666888===QQQDDDEEE>>>:::777>>>???:::999999555;;;>>>>>>444===@@@III???BBBNNNQQQEEEGGGNNNQQQXXX^^^VVVUUUUUUOOORRRVVVOOOQQQVVVRRRRRRTTTdddiiiOOOOOOXXXkkkPPPRRRSSSWWWUUU^^^QQQQQQWWWUUUXXX[[[YYY[[[ZZZ``````YYYddd]]]```[[[ZZZ___[[[YYY___bbbhhhhhhfffeeekkkeee___```^^^\\\[[[[[[bbbbbb]]]bbb\\\^^^bbb www___bbbXXXXXXXXXZZZ[[[XXX]]]cccddd___aaa[[[ZZZZZZ```pppXXXUUUVVVRRRSSSRRRUUUOOOMMMLLLLLLMMMIIIKKKKKKLLLCCCEEEDDDJJJWWWppp]]]GGGFFFIIITTTFFFFFFAAAHHHKKKKKKNNNNNNTTTRRRUUUSSSWWW[[[MMM???CCC>>>DDDMMMOOOHHHAAAEEEKKKDDDBBBCCCLLL@@@<<<<<<:::;;;555000000---((((((***888&&&***---+++)))---'''&&&$$$%%%'''///(((***''')))+++...$$$$$$###""")))'''***<<<***((($$$))):::444***'''222)))%%%******''')))111;;;,,,)))((((((+++)))---+++&&&***222444666:::;;;===AAA@@@444777???>>>BBB;;;666666444QQQkkkJJJ===999???999;;;:::333888JJJWWW===FFF>>>444<<<===AAAGGGJJJEEEGGGAAAJJJbbb]]]RRRSSSMMMPPPSSS[[[QQQNNNUUUHHHOOOSSSUUUQQQYYYRRRNNNOOOSSSSSSQQQWWW[[[OOOOOOYYYZZZOOOWWWXXXeeeXXXcccRRRWWWXXXXXX[[[[[[XXX]]]bbbYYYYYY___ddd]]]___aaacccnnniiigggkkkqqqkkk```aaadddgggfff^^^ZZZ```ddd]]]___aaajjjnnnddd\\\]]]YYY```[[[\\\^^^\\\^^^]]]bbbXXXZZZ\\\ZZZXXXVVVZZZSSSTTTPPPVVVTTTYYYUUURRRQQQMMMPPPLLLLLLIIIIIIFFFIIIFFFNNNTTTKKKXXXMMMIIIDDDLLLIIICCCBBBJJJJJJMMMJJJMMMMMMQQQOOOLLLLLLvvvjjjYYYOOO```IIIQQQHHHPPPNNNIIIAAACCCGGGLLL@@@<<<===>>>:::666999222111...,,,)))******---...+++,,,<<<(((###((($$$&&&%%%)))+++)))%%%$$$++++++''')))'''###&&&&&&$$$''')))(((###)))---$$$(((&&&...111+++(((...,,,***'''))))))...---000000---111------...+++(((000666???IIIHHH======BBB@@@;;;;;;<<<666999555999888===<<<:::@@@BBB<<<>>>444555888EEERRR???GGGMMMOOOLLLCCCDDDEEEJJJDDDEEENNNQQQIIIQQQWWWVVVYYYLLLUUUTTTLLL^^^UUUOOOTTTSSSVVVRRROOONNNKKKNNNMMMSSSTTT___rrrQQQVVVjjj[[[OOO\\\\\\ZZZZZZ```ZZZTTTVVVXXXiii]]]\\\fffbbb___]]]]]]___^^^fff^^^___ZZZaaa~~~nnnssshhheeefffaaaddd^^^^^^^^^\\\[[[^^^]]]___fffhhh^^^VVVYYY______aaa[[[]]]___\\\YYYbbb```XXXWWWXXXTTTXXXXXXXXXUUUNNNOOORRRWWWSSSQQQQQQPPPPPPQQQRRROOOSSSLLLHHHHHHJJJGGGFFFIIIKKKNNNCCCBBBBBBEEEDDDIIIJJJIIIIIINNNOOOKKKMMMLLLLLLeeeeeeTTTHHHWWWGGG@@@HHHPPPQQQDDDGGGDDDEEEDDD<<<<<<;;;999:::BBBCCCQQQ222///777222+++***---)))---,,,,,,---+++---888'''///'''$$$((((((111///777000''''''&&&---'''%%%))))))&&&(((***(((###!!!***+++,,,...+++###)))222(((''')))333...(((444222)))++++++---***///888888777@@@EEE999<<<666777888999<<<888666666555<<<777@@@;;;???===999777777===999===<<>>BBBBBBCCC>>>@@@777000///555...///555000***,,,***...,,,...))),,,///(((///%%%(((&&&$$$KKK///######+++%%%&&&+++,,,,,,%%%$$$'''&&&###$$$###***(((;;;///+++)))((()))(((***+++***)))AAA.........000222666555888===000333666888CCC444777>>>===:::777:::III888;;;666111;;;@@@999888777;;;@@@444999FFFPPP>>>???PPPPPPOOOAAAJJJCCCAAA@@@FFFJJJMMMnnndddVVVOOOSSSGGGRRRTTTKKKPPPHHHQQQLLLFFF\\\MMMKKKHHH```MMMNNNTTTSSSLLLJJJOOOPPPWWW\\\YYY\\\[[[[[[[[[^^^[[[WWW\\\\\\]]]```[[[\\\]]]YYY```dddaaa]]]bbbeee___cccjjjhhhiiieeepppkkkiiiooogggiiidddbbbaaabbbhhh___aaa^^^ddd```[[[aaa___```ZZZ\\\VVV\\\gggaaa[[[___aaabbb]]]bbb\\\\\\ZZZYYY[[[UUUVVVOOOXXXRRRMMMLLLNNNNNNKKKOOOUUUUUUPPPMMMJJJMMMGGG???DDDFFFLLLSSSEEEKKKQQQDDDCCCMMMWWWWWWPPPKKKKKKNNNRRRbbbcccZZZNNNNNNZZZEEEMMMHHHMMMLLLUUUEEEFFFAAAEEEEEEBBBAAA;;;;;;999666000...333...+++...222...%%%&&&((())))))&&&333000(((***%%%***111***'''+++&&&%%%'''++++++,,,+++&&&&&&$$$...111)))>>>(((&&&&&&###999,,,,,,***)))'''***)))///BBB,,,,,,111444999???CCC:::555DDD666<<<777DDDIIIRRREEEAAA===HHH>>>===AAA;;;999;;;777===999>>>999666888:::999666<<>>AAAAAAEEEQQQcccQQQQQQQQQ]]]TTTRRRUUUOOONNNMMMWWWKKKNNNUUUPPPHHHQQQOOORRROOOQQQeeeVVVOOOMMMNNNTTT[[[]]]WWWTTTYYY[[[\\\^^^XXX[[[[[[XXX\\\VVV[[[dddnnnggg```___hhh^^^___bbbeeebbbeeeeeemmmlllpppnnnjjjllljjjdddfffiiieeeddd___```]]]___```^^^dddeeeaaa```XXX\\\___]]]___aaa```___bbb___```]]]]]]WWW[[[VVVTTTWWW]]]SSSWWWSSSUUUSSSPPPNNNIIIJJJIIINNNHHHGGGKKKXXX@@@DDDEEEUUUHHHEEEHHHGGGIIIDDDDDDFFFSSSJJJNNNQQQQQQVVV___```SSSJJJXXXRRRLLLFFFIIIKKKHHHJJJFFFFFFEEEBBBDDDGGG999333777777555333333222+++///,,,***+++...(((+++)))///++++++(((888,,,)))&&&(((------,,,,,,+++&&&222111)))((('''%%%)))***'''$$$%%%((('''%%%%%%$$$333,,,'''+++222&&&444***---333++++++111===222666>>>222888IIISSSZZZ[[[dddBBBBBB999===<<<<<>>888:::555888999:::999:::888<<<>>>@@@???SSSFFFGGGIIIAAAMMMNNNFFFLLLDDDGGGHHHIIIQQQUUUVVVRRRNNNPPPfffUUUQQQUUUWWWPPPTTTKKKMMMMMMOOOIIIKKKNNNRRRSSSTTTQQQUUU[[[QQQSSSTTTVVVTTTZZZXXX[[[]]]___bbb[[[ZZZ]]]XXX\\\ZZZ^^^ddd```dddaaabbbgggaaaccccccdddlllyyyoookkkuuugggqqqhhhjjjjjjpppmmmmmmmmmjjjdddcccdddiiigggbbbbbbaaabbb___ccceee```ccc^^^```bbb]]]ZZZ___^^^___YYYXXXZZZVVVUUU\\\[[[VVVVVVUUUZZZWWWWWWSSSKKKRRROOONNNMMMKKKNNNGGGLLLGGGHHHJJJFFFGGGFFFDDD>>>GGGIIILLLQQQQQQSSSWWWWWWRRRRRRQQQJJJFFFIIIMMMQQQLLLDDDNNNIIIDDDMMMYYYDDDAAA===@@@;;;777???222333000HHH444444---******///+++(((******)))(((&&&)))***)))%%%%%%((('''***...///222>>>%%%***&&&%%%!!!000(((111333$$$%%%((((((&&&&&&)))---(((,,,///*********---111///777888666999@@@<<<===888;;;@@@bbbPPP:::FFF@@@===777CCCFFFSSS>>>>>>555888888OOOHHH333<<<666555666999:::>>>EEEHHHDDDHHH@@@EEEBBB>>>JJJJJJ===BBBGGGKKKMMMLLLEEEQQQQQQOOO___TTTZZZ___cccLLLKKKMMM[[[PPPKKKNNNIIINNNPPPNNNSSSSSSTTT[[[TTTXXXSSS\\\ZZZ[[[VVVfff^^^VVVcccbbbZZZaaadddZZZXXXjjjhhhccc```eeecccgggmmmeeelllppp|||yyyiiikkknnnpppmmmooosssmmmkkkkkkqqqkkkiiiccceeedddfffbbb]]]^^^```bbbeeegggbbbaaa^^^___\\\^^^ZZZZZZWWWXXXWWWZZZ[[[WWWSSSMMMWWWZZZYYYYYYYYYPPPTTTMMMPPPOOOMMMLLLKKKGGGLLLGGGMMMFFFCCCBBBDDDCCCHHHLLLLLLNNNNNNRRRPPPUUUPPPNNNLLLTTTSSSUUUqqqqqqUUUMMMGGGGGGAAAMMMHHHGGG???888555555333333666222333777111333+++***&&&,,,)))&&&'''$$$'''...(((+++((('''&&&******,,,//////***000&&&"""$$$%%%$$$%%%***+++$$$!!!###&&&''',,,###((((((<<<***'''***((((((---,,,???999777<<>>@@@777:::QQQ???;;;999444@@@888BBBOOOEEE>>>777777999;;;999555777777555555888555666===DDDTTTHHHAAAGGGIIIDDDEEEFFFVVVRRRHHHJJJYYYQQQHHHKKKUUUMMMOOOPPPOOOZZZTTTWWWTTTTTTSSSUUUOOOMMMOOOXXX```WWWTTTVVVXXXUUUVVVYYYVVVXXXVVV]]]```UUUWWWccclll___jjjVVV^^^lllXXX]]]```iiiccc``````bbbaaadddbbbmmmppp7:}}}ttttttmmmnnnmmmnnnkkkhhhfffooozzzvvvmmmiiikkkhhhkkkhhheee```ccciiidddeee^^^bbbccc^^^eee^^^]]]___ccc^^^bbbYYYXXXVVVRRRTTTVVVWWWYYYSSSWWW]]]RRRUUUXXXPPPKKKMMMKKKKKKPPPIIILLLNNNIIIAAAAAADDDHHHKKKJJJLLLNNNUUUWWWSSSOOOOOOTTTSSS\\\QQQZZZ~~~RRRaaaFFFDDDDDDCCCDDDCCCFFF@@@>>>444444555666@@@555444333444...)))444...(((---------///444333+++***'''***%%%))))))...///111444((('''+++CCC&&&&&&######"""((($$$%%%&&&444$$$+++***+++///)))'''(((%%%+++999<<<777333444111222333<<>>===???999888QQQ777333GGG666???666777555???;;;FFF>>><<<:::333777444999:::FFFFFFCCC@@@???<<>>{{{III:::333111<<<999EEEKKKBBB;;;???===<<<444888<<<888<<<777:::DDD999???;;;<<<<<>>>>>>>>;;;888222000...111000...333777///***///+++......111(((,,,,,,000,,,(((++++++000///---...:::,,,***...000%%%,,,(((&&&###%%%!!!%%%'''(((---,,,...''''''******111000///666333444333777===DDD@@@???>>>IIICCCXXXRRRAAA===???888AAA666QQQGGG<<<>>>999;;;555444===:::===BBBIII999FFFCCC;;;???@@@FFFQQQLLLIIIDDDFFFJJJXXX]]]FFFJJJMMMRRRLLLPPPQQQNNNMMMKKKLLLJJJOOOXXXPPPTTTUUUPPPMMMOOONNNVVVQQQOOOTTTQQQ___[[[UUUXXX```bbbgggfffVVV^^^dddaaaqqqttttttooo~~~#jjj^^^ZZZaaa___]]]ccclll{{{ ttt{{{wwwvvv|||vvv}}}pppsss~~~zzzxxxwwwpppyyywwwxxxpppnnnnnniiimmmyyygggjjjccciiihhhiiihhhnnnmmmoooeeeccckkk^^^XXXVVVcccYYYVVV^^^VVV```ZZZTTT]]]YYYUUUXXXOOOPPPJJJKKKOOOSSSRRRQQQTTTKKKHHHLLLPPPKKKPPPOOOKKKOOORRRRRRGGGHHHPPPRRRQQQUUUlllsss^^^YYYRRRIIIDDDPPPQQQJJJMMMDDD???CCC888BBB===333...---222444/////////+++//////000,,,---)))///***'''...(((******,,,)))***(((///,,,&&&///111***%%%***&&&$$$***!!!,,,...///,,,&&&((('''...,,,+++222,,,444888666999777HHHKKKNNNSSSNNNCCC\\\CCC@@@DDD999>>>BBB888>>>CCCEEEZZZEEE<<<;;;:::888999BBBDDD@@@>>>:::FFFJJJ@@@CCCDDDEEETTTLLLfffCCCEEEHHHSSS```QQQMMMGGGWWWVVVKKKLLLGGGLLLSSSRRRLLLLLLMMMMMMNNNMMMMMMKKKTTTRRRXXXUUUTTTQQQWWWVVVYYY\\\[[[^^^bbb]]]dddaaajjjdddeeeggghhhnnnyyy -eee\\\[[[\\\jjjjjjpppkkkyyy,|||vvvyyyuuurrr~~~ - {{{uuuxxxwwwsssppppppnnniiimmm rrrgggbbbffflllrrrppp aaahhhaaa\\\\\\^^^\\\VVVZZZ]]]___YYYYYY\\\XXXUUUPPPRRRRRRQQQNNNMMMXXXPPPQQQHHHhhh]]]TTTKKKMMMJJJPPPMMMQQQNNNKKKGGGJJJVVVVVVQQQ___yyycccWWWVVVMMMJJJPPPzzzOOODDDLLLLLLGGGAAA<<<;;;666333111777444000---...111,,,...555+++++++++...:::[[[777555+++***''''''///,,,(((+++///<<>><<>>;;;EEEBBB<<>>555111000***888...---))),,,222---///444888000---'''---***------...)))000'''...***+++''''''***///>>>***---&&&((('''&&&111(((+++***+++;;;333888;;;<<<===CCCEEEVVVUUUGGGLLLCCC:::<<<;;;999<<<@@@:::???VVV```SSS===>>>@@@LLLNNNEEE???BBB@@@EEEKKKGGGFFFHHHNNNLLLJJJKKKPPP```qqqHHHGGGKKKUUU[[[IIIIIIGGGGGGPPPOOOIIIHHHMMMEEEIIIBBBKKKOOOLLLRRRQQQLLLQQQSSSVVVWWWYYYWWWVVVSSSYYYZZZZZZnnn[[[pppccclll]]]dddYYY^^^```iiieeennnjjjnnnjjjiiiooogggppppppuuu||| ?' -|||www ~~~zzz(}}}uuutttllltttrrrxxx qqqnnnkkklllrrrlllnnnpppnnnlllmmmlllfffbbbaaa]]]ZZZ```UUUSSSfff___\\\UUUZZZWWWXXX___SSSPPPLLLZZZ___```^^^kkkhhhTTTSSSNNNOOOQQQ^^^RRROOONNNIIIIIIEEE[[[]]]cccuuuiiiaaagggYYYWWWOOOIIIBBBIIIEEEOOOBBBHHH===???BBB:::777444666222///---555777888---,,,222''')))+++...---555ZZZGGG777222---$$$***OOO333,,,///444'''///***)))+++555...444JJJ000///+++))))))+++...)))...666555<<>>>>>???<<>>DDDIIITTTIII@@@;;;555333444333222888444///---///,,,***)))(((///---+++...000888BBB666000***++++++AAAAAA777,,,,,,+++***%%%'''+++---***///)))---...///+++---***'''+++000888888DDDDDDKKKGGGWWW___aaalll5LsssTTTIII>>>:::@@@===;;;EEE===;;;HHHFFFQQQNNNjjjxxxuuu}}}sssQQQOOOOOOTTTXXXUUUWWWVVVUUUPPPjjjvvvLLLLLLLLL]]]ZZZPPPPPPHHHFFFLLLPPPIIIIIIPPPGGG>>>HHHHHHMMMGGGKKKJJJOOORRRXXXZZZVVV[[[cccZZZ\\\``````aaa]]]XXXZZZddd[[[eeeggguuuoooooohhhjjjeeehhhmmmqqqqqqpppvvvrrr ~~~~~~yyy{{{  9cP$}}}  zzzuuuqqqxxxpppxxxwwwsssxxxnnnpppnnnnnnwwwlllkkkiiijjjssshhheeehhhxxxhhhhhhfffddd```XXXJJJMMMaaaaaa```aaaXXXYYYVVV^^^]]]XXXaaa___llleee^^^]]]NNNIIIJJJGGGJJJMMMLLLMMMKKKVVVQQQWWW```___UUUXXXRRRUUUSSSTTTSSSPPPLLLCCC@@@JJJQQQBBB@@@III<<<::::::;;;666<<hhhEEEOOOAAABBBLLLHHH999???>>>???:::CCCBBBbbbqqqkkk}}} ppp\\\[[[YYY[[[```bbbWWWWWWbbb___MMMRRRMMMNNNJJJEEEJJJLLLMMMLLLLLLJJJRRRLLLHHHDDDMMMMMMNNNPPPMMMLLLRRRXXXZZZXXX^^^```aaabbbUUUWWWcccbbbddd```]]]jjj^^^fffllllllrrr{{{ttttttoooeeeooovvvooonnnsss qqq~~~ C2 'N;) wwwqqqpppqqq~~~|||yyy|||tttsssppppppssskkkmmmhhhkkkllltttsssiiinnnlllmmmkkkggghhhUUUMMMNNNTTTZZZWWW^^^]]]YYYWWWWWW___VVVaaacccwww[[[WWWWWWSSSOOODDDGGGNNNMMMPPPJJJNNNQQQPPP___gggWWWPPPJJJOOONNNSSSTTTKKKJJJHHHEEEHHHFFFNNNCCCAAABBB:::>>>>>>???777444000------))),,,888))))))///...GGG777===///,,,222///>>>...***000>>>,,,(((,,,000,,,***---(((,,,---666555555333333,,,+++666***000222888JJJMMMMMM]]]ZZZuuuQQQSSS[[[^^^vvvgggVVVBBBCCCAAABBB@@@CCCHHH===AAA<<>>IIIJJJ<<<@@@===;;;888444///...,,,000111000///...000***,,,888111333666...FFF999******ZZZ222)))///---777))),,,222:::---111...333***///,,,)))...666...666777JJJAAA999^^^TTTIIIUUUZZZ```SSSZZZ\\\eee???III>>><<<===>>>LLL<<<<<<@@@???;;;FFFggg9! 3 vvv{{{ gggTTTQQQSSS[[[SSSRRRLLLDDDGGGIIINNNOOORRRNNNQQQjjjrrrSSSLLLKKKQQQXXXSSSSSSSSSWWWRRRZZZ[[[WWW\\\```]]]\\\bbbfffeeecccmmmjjjkkkwwwrrr~~~ vvvsssuuu|||& - ! vvv # -  |||tttttt{{{wwwyyy}}}pppyyyvvvtttrrryyyrrrrrrooo|||sss{{{nnnkkksssmmmkkkoooiiikkk___ZZZ___]]]fff___]]]\\\bbbSSSWWW[[[SSS^^^nnn tttfffXXXGGGMMMJJJSSSRRRQQQSSSNNNWWWVVVRRRfffXXXUUUTTTSSSFFF@@@HHHMMMOOOTTTPPPYYYRRRKKKOOO???AAA@@@EEEPPPJJJAAAAAA:::888222,,,///,,,///---333000...///,,,000CCC111555FFF***,,,***)))...***111***'''...111...+++000---222'''++++++,,,***---******///+++CCCIII999CCCDDDNNNVVVbbbWWWJJJLLLLLL___RRRBBB???RRRGGGAAA::::::>>>CCC@@@>>>AAAFFFCCCKKKuuuAA05.$D|||]]]RRRTTTRRRFFFHHHKKKGGGOOOQQQOOOLLLPPPddd___www]]]```QQQMMMKKKQQQUUUPPPMMMTTTZZZNNNSSSbbbccc^^^``````wwwyyykkkffflllggg|||ssszzzyyyI53#www #   {{{|||      -wwwmmmzzzzzzxxx{{{~~~wwwvvvuuuqqqzzzzzzuuulllrrrrrrllljjjuuu{{{kkkccc______^^^]]]```WWWWWWZZZWWWVVVXXXVVVdddttt^^^VVVOOOSSSMMMLLLMMMPPPWWWUUUPPPXXXQQQVVVVVVlllggg^^^pppwwwJJJPPPOOOTTTKKKKKKLLLKKKGGGEEEJJJBBBSSSppp\\\<<<888888777666...---000222222111+++///...111222PPP555///888---***))),,,000///222,,,000222'''333000***---******///...++++++---000...///111666FFF:::999NNN???BBBOOOMMMIII555???@@@MMMHHHLLL===@@@>>>???<<<>>>;;;===@@@DDDAAACCCGGGgggNOA0/++:Kmmm^^^aaa\\\QQQNNNKKKHHHKKKGGGFFFGGGMMMLLLRRRaaaaaaOOOGGGGGGKKKIIIRRRPPPHHHPPPWWW^^^YYY]]]ZZZeeebbbeee```rrryyyvvvssszzznnn{{{qqq2#(+H0  -  }}}~~~}}}zzzuuu~~~}}}}}}|||zzzvvv|||vvvwwwooonnnmmmhhhooo|||pppccc^^^]]]YYY______^^^[[[SSS[[[oooeeeWWW[[[eee^^^SSSLLLJJJDDDLLLJJJJJJTTTUUUXXXQQQZZZ^^^\\\ZZZZZZUUU^^^ -rrrRRRNNNNNNRRRKKKSSSEEEGGGIIIEEECCC<<<>>>DDD777333888666;;;DDD;;;444,,,444000,,,...222,,,666>>>;;;>>>===555)))666333666777999777999:::...555555//////000,,,000------...,,,333CCC///222555@@@<<<777777:::\\\HHH<<<999???>>>===???999<<<======;;;@@@===999===AAA???AAAEEEJJJLLLkkk*T?>5->>:::===>>><<<777666444888JJJ===555===+++---111111444:::IIIEEEDDD>>>222,,,+++444DDD777444///666222000333000---++++++...///000...000......000222999@@@===@@@GGGGGG@@@>>>UUU666::::::FFF@@@999CCCBBBDDD999>>>:::999FFFDDD@@@BBB???EEEHHHKKKPPPsss'99\^WLYF=xxx\\\UUUOOONNNLLLLLLFFFIIIIIILLLTTTOOOQQQYYYSSSTTTQQQTTTQQQVVVSSSZZZ\\\[[[ZZZ```VVV___dddaaaiiilllzzzwwwmmmhhhooonnnppprrr{{{    #>>AAA555777555...,,,000---000<<>><<<===???BBBHHHNNNQQQiii4BgoMDK/ wwwdddYYYSSSVVVOOOJJJDDDKKKKKKGGGFFFEEEcccOOOTTTSSS```VVVUUUddd\\\^^^YYYccc^^^ddd^^^\\\eeebbb___bbbmmm|||ooonnnnnntttssswww}}}}}}yyy~~~ }}}~~~  ~~~ ~~~vvvuuuyyyyyy    -" ~~~  ~~~}}}ttt{{{~~~zzz|||tttqqqvvv~~~ yyymmmkkkkkk]]]aaaeeeaaaaaa```aaa]]][[[UUUlllggg\\\QQQVVVPPPPPPNNNSSSKKKKKKNNNNNNPPPOOOXXXTTTXXXYYY[[[```]]][[[hhhuuuXXXPPPKKKGGGDDD[[[JJJPPPCCC??????;;;;;;EEE666888444666<<<888333888000///999///>>>555>>>@@@ZZZ[[[999***///111888888333222+++555++++++***)))---...,,,+++///333555+++,,,222666///===MMMIIIAAACCCCCC<<<:::@@@CCCFFF;;;;;;JJJBBB:::999AAA999===>>>>>>;;;999@@@???EEEIIITTTeee-DCgz|mJNC+xxx______[[[SSSOOOLLLKKKKKKJJJIIIbbbbbbXXXVVV]]]ZZZ\\\ZZZ___ZZZXXXaaaiiiggg```eeennngggkkknnnwwwlllqqqnnn|||~~~  }}}  {{{rrrxxx uuu{{{}}}  -  xxx  -~~~ttt   ttt|||yyywwwrrrqqqkkkiiinnnlll^^^cccaaaggg]]]^^^WWWXXXZZZWWWVVVSSSSSSSSSLLLSSSPPPNNNNNNOOOTTTUUUmmm\\\aaaRRRSSSVVVTTTXXX]]]rrrcccOOOOOOQQQIIIbbbUUUFFF@@@CCCFFFEEE;;;777::::::999555000777===>>>>>>555333333===;;;JJJ:::aaa@@@DDD333,,,000888666<<<222///888'''+++((()))(((((())),,,)))---+++222///---;;;:::NNN]]]666BBB:::AAA777???IIIAAA===666555555999444>>>777<<<===999;;;;;;???:::@@@<< ~~~ ~~~ wwwtttvvvuuu~~~   -}}}  ooo}}}{{{  sssllliiitttiii```^^^eeeeeeaaafffWWWTTTWWWWWWYYYUUU]]][[[LLLIIIPPPLLLOOOKKKRRRVVV[[[RRRTTTUUUVVVZZZbbb\\\VVV```___[[[RRRMMMJJJGGGTTTJJJIIIAAA>>>FFF???>>>AAAYYY777777111888;;;<<>>888777555@@@QQQ888444999TTT===:::;;;======BBBJJJSSSQQQfffUOF\x{fC2ZZZYYYUUUSSSKKKKKKLLLNNNRRROOOMMMPPPPPP]]]RRRVVV___YYYXXXdddkkkgggccc^^^ddd""vvviiixxxmmmgggoooxxxqqqvvv; A"zzz{{{xxx |||uuuqqqyyy -~~~   xxx|||  {{{ -"}}}mmmmmm}}}hhh\\\gggggg___aaa^^^ZZZVVVWWWXXXWWWpppRRRQQQZZZHHHOOOQQQOOOOOOOOOUUUUUUSSSUUUYYYXXXccc[[[ZZZSSS___OOOBBBIIILLLKKKOOOFFFGGGEEEJJJIII<<>>===XXX:::555777777:::333222000222000:::SSS;;;777888FFF@@@333???AAA888;;;555333666666666,,,(((%%%%%%(((%%%%%%///---(((---000000///444222444<<<555666///<<<888888888777@@@999888888333MMM<<<333///888@@@888;;;444999999AAA===FFFMMMeee>5/8KrvOR'aaa___WWWKKKIIILLLNNNNNNNNN^^^QQQTTTRRRTTTVVV\\\___ooobbbbbbyyydddbbbZZZhhh  wwwuuusssmmmgggpppooohhhuuu   -xxxeeeooozzz|||wwwzzzzzzxxx   }}}  -wwwwww %' {{{rrriiipppjjjccckkkkkkfffffflll]]]YYY\\\[[[^^^TTTSSSWWWRRR[[[OOOOOOOOONNNLLLNNNOOOSSSSSSWWWZZZUUUlllgggaaaccccccHHHBBBHHHDDDEEEMMMCCCBBBJJJMMMGGGDDD<<>>AAA@@@999555999CCCGGG)))...$$$%%%)))$$$'''''' (((,,,+++222,,,222333555666555666888;;;HHH444666111000333333111000:::333+++333444666333666555<<<<<>>EEEWWWJJJKKKHHHuuuyyy "- ~~~]]]VVVPPPJJJPPPVVVTTTZZZ[[[bbb___```eeegggiiitttlllgggkkkmmmqqquuuiiizzzoooqqqsssllleeeeeemmmiiixxx -{{{|||yyy    -"tttqqq xxxzzz}}}wwwqqq|||rrriiiqqqppphhhhhhlllccccccbbbcccddd[[[YYY]]]VVVYYYXXXXXXUUUXXXOOOMMMLLLGGGMMMTTTZZZPPPLLLVVVXXX]]]eeeXXXaaajjjbbbnnnsssiii[[[PPPMMMIII???BBBNNNFFF???DDDFFFFFFDDDCCCKKK:::222444+++000<<<:::888777555999EEE]]]{{{\\\TTTaaaMMMHHH???888000---000555$$$$$$((($$$)))%%%''''''---+++))),,,***---000000///444333:::666666000111444333<<<000333666BBB888333222666444aaa===777777888???JJJJJJDDDDDDEEEggguuu\\\aaammmgggssslllcccddd\\\YYYSSSLLLJJJNNNMMMRRR[[[fff\\\]]]eeeoooffffffkkkkkkjjjkkklllfff\\\llltttkkkiiiiiisssaaakkkmmm{{{~~~|||}}}}}}||||||~~~xxxyyy"zzzttt  -  -% - uuu }}} -zzz{{{zzzttt~~~|||sssuuutttpppkkkkkkiii\\\eeefffggg```eee```ZZZZZZbbbcccYYYVVVVVVZZZPPPCCCGGGSSSXXXTTTXXXPPPNNNTTTVVV^^^hhhllliii\\\llleee\\\JJJAAAGGGDDD:::???LLLJJJWWWEEEFFF>>>;;;CCC;;;:::===111444444222999777:::777AAATTTnnn}}}QQQrrrnnnJJJ@@@===666<<<@@@@@@###$$$***---'''&&&***'''...///(((,,,333333111...666222888666999444???333//////......666222777000000///333;;;///:::777:::777QQQ___???DDD???XXX^^^NNNOOORRRYYY\\\YYYXXXYYY[[[aaa^^^gggNNNLLLLLLWWWQQQVVVYYYeeekkk___aaa```fff```llljjjgggdddiiigggpppgggrrrffflllmmmhhhgggkkkhhhzzzvvv}}}yyy}}}{{{{{{{{{ - - -       % pppnnnzzzuuurrrtttoooooosssrrrbbbfff^^^[[[nnnddddddfffccc^^^eeemmmmmmlll]]]fffTTTSSSXXXNNNXXXUUUVVVVVVVVVMMMYYYYYYUUUXXXnnn______cccqqquuuUUUWWWRRRIIIEEEPPPCCC>>>>>>AAA???HHH;;;@@@888??????666:::===666444222777@@@===IIITTTaaahhh[[[]]]zzzPPPAAA777;;;777;;;333!!!"""""""""...'''***+++///...///000555>>>555000333222444666222666///777///111000,,,444111///111333444555<<<888444999555WWWggg??????@@@GGGHHHGGGMMMJJJKKKUUUWWWSSS```iiinnnooommmbbbyyyWWWTTT[[[^^^UUUhhh___gggkkk___eeeZZZeeekkkhhhhhhiiigggcccgggiiilllkkklllnnneeegggjjjxxxrrrvvvzzz||||||}}}zzz{{{ - -  -   - - qqq $  -kkkpppqqqtttqqqlllzzznnndddiiiiiidddeeelllhhhdddiiihhhccc]]]___]]]___YYY^^^WWWTTTZZZYYY^^^ooo^^^SSSuuuMMMQQQSSS[[[^^^iiibbbhhhvvvwwwfffjjjTTTHHHGGGGGGGGGBBBDDDBBB@@@CCC===?????????<<<;;;999777;;;<<>>>>>444AAAAAAIIIHHH cccIII``````RRRGGGVVVNNNEEEBBB;;;***$$$&&&&&&$$$---+++)))(((***JJJeeeOOO===555===555333<<<333555888///222666///444111///...444///......333666333999===ZZZ^^^???>>>AAAEEECCCEEEGGGGGGJJJKKKWWWTTTZZZfffmmmxxx iii]]]vvviiiddd___ccc```bbbtttyyyoooeeejjjkkkmmmdddoookkkeeefffdddkkkmmmiiiaaa^^^^^^jjjccclll|||yyy|||rrrqqqzzzyyyxxx{{{xxx}}}~~~zzz yyy -      - - )qqqlllnnnuuupppnnnssslllccckkkfffbbbkkkfffdddeee______ZZZ^^^```\\\ZZZ[[[SSS\\\aaasss bbbYYYSSS[[[XXX___tttbbb___ccc"YYYUUUQQQIIIHHHHHHGGGDDDBBB;;;>>>HHH@@@===@@@@@@>>>888:::222@@@555:::TTT666555;;;EEESSSooobbbmmmhhhcccNNNPPPJJJ===777%%%!!!!!!###%%%)))...(((...///UUUiiiDDD>>><<<999666111...,,,...111//////555111...***222000555000000...777:::444999RRRLLL<<<<<>>DDDTTTZZZWWWTTTgggxxxxxx>uuucccgggfffssszzzppp{{{|||iiihhhjjjlllhhhmmmjjjooofff}}}fffaaadddaaa]]]tttjjjuuu vvvtttzzzxxx}}}yyy}}}}}}rrryyy~~~xxxwww -# "!#" $",   vvvttt|||{{{pppnnnlllwwwkkkgggnnnllldddhhhiiimmmdddbbbfffggggggeeeZZZ___bbb]]]pppkkk .#yyy___XXX^^^^^^fffaaaddd[[[aaaooogggJJJRRRQQQLLLBBBJJJCCCLLLRRR???>>>@@@???>>>FFFOOO:::===888666999666>>>888<<>>AAANNN\\\[[[___XXX```ooo pppuuubbbccciiilll~~~ 0- -xxxjjjoooiiinnnmmmdddeeejjjhhhmmmssswwwiiiqqquuu|||wwwtttooozzzuuuyyy}}}xxxwwwrrruuu{{{ -{{{}}} -~~~{{{www   !$$"&%()& "#%$ ||| - xxxmmmvvvyyyqqqmmmsssuuuiiiiiipppzzziiiiiieeepppdddmmmjjjgggpppWWW```lllhhhccciii~~~gggxxx[[[___bbbYYYaaallluuuccc^^^]]]KKKJJJ^^^PPPNNNPPPGGGGGGGGGBBBCCCAAA999BBBJJJ:::???;;;::::::999;;;777AAA:::111111999IIIQQQbbb;;;>>>@@@IIIAAAJJJTTTOOOHHHSSSZZZ@@@222'''!!!###"""&&&+++---+++555333000666;;;999444:::000///...333222888JJJ:::---...)))---000///111222999666666:::FFF@@@:::777???IIIAAA;;;:::CCCEEEJJJVVV\\\dddlll}}} xxxgggiiiuuupppqqq6U H@rrriiiqqqhhhmmmiiieeeppp ooossspppuuuuuuuuu{{{xxxvvvzzzzzzoooyyy}}}{{{~~~|||~~~xxx~~~qqq|||   - %%(++*)'%$*'%!%$   |||vvvkkkrrruuusssmmmkkkfffhhhnnnwww{{{mmmfffkkkmmmjjjrrrmmm___]]]TTTZZZaaaeeekkkjjjrrrrrrvvvhhh```XXXUUUOOO[[[UUURRR^^^```fff]]];;;OOObbbYYYPPPLLLFFFGGGCCCAAA;;;===;;;<<>>???FFF===LLLNNN... (((''')))---^^^'===333BBB>>>^^^555///,,,888777111---///...111+++***++++++,,,000,,,333333444444>>>777>>>===<<>>FFFLLLXXX^^^___pppxxx2)]]]lllkkkkkk ttt$,}}}WWWgggnnnfffeeedddsss({{{mmmnnn}}}yyymmmuuuzzzrrrxxx{{{{{{xxxrrrtttqqqxxx}}}yyy %&)**+,+**))&%#$  ooopppmmmqqqxxxxxxlllrrrffflllrrr|||qqqnnniiilllqqqrrruuurrrppp[[[fffcccaaaeeeeeegggjjjlllzzzmmmeee\\\OOOGGGOOOZZZmmmkkkeeedddNNNIIIRRRWWWTTTWWWPPPIIIGGGCCCDDD@@@BBB===<<<999>>>999>>>:::AAA@@@EEE@@@444;;;333CCCDDDDDD999999NNNVVV===:::???;;;888>>>666999AAA888111""")))'''%%%***///444___fff777>>>JJJ///---///555333000---444///...111111...111+++000+++---'''///...111777222000333<<<>>>:::===DDDBBBKKKAAAGGGMMMTTTWWWgggtttsssnnn5Reeepppmmm{{{uuulllxxxsssiiimmmhhhhhhffffffmmmzzz~~~*C<llljjjvvvxxx2wwwuuuttt}}}~~~ -xxxyyy~~~{{{ - ~~~{{{zzz - - "'*++,-...-,**'#$$ -  qqqvvvrrrwwwppplllrrruuuqqqjjjuuuuuulllpppooozzzpppqqquuu^^^kkk\\\cccVVV]]]ccc```cccjjjjjjggg```[[[HHHMMMTTTRRR```VVV[[[WWWRRRZZZPPPJJJMMMQQQNNNEEEIIIFFF@@@???AAA<<<<<<>>>???===???AAA>>>EEEFFF@@@AAADDD@@@DDD:::@@@OOODDD888JJJ777555555===111444111444***111:::###+++&&&(((111888DDDIII???;;;GGG555000JJJ333777JJJ888333)))000222666)))111......+++000...+++///222888111///000999<<<999999;;;>>>DDDHHHDDDWWWLLLXXXWWW___sssFSzzzfffyyylllfffaaahhhxxxiiigggiiisssuuummmhhhbbbgggmmm6N.qqqiiirrrzzz uuusss,' - mmmvvvvvvyyy~~~{{{zzz -  "%%*+-1001210//,(%"$" }}}xxxtttqqqpppwwwyyyxxxwwwjjjsssmmmqqqiii|||-"{{{qqqtttkkkkkkYYY```XXXXXX^^^^^^\\\lllfffQQQBBBFFFLLLQQQMMMPPPTTT^^^YYYXXXlllRRRKKKOOONNNNNNDDD===EEE>>>:::===999???CCC???===>>>BBB<<>>>>>>>>AAABBB>>>DDD<<<@@@DDDKKK999===BBB\\\HHHBBBCCCMMMIII;;;777<<<444444777===000///,,,---((()))''''''333;;;,,,111666777111444,,,111CCC111777000...,,,GGG===555000111...111---333---+++000888111555...222444///333:::===:::555BBB>>>LLLGGGEEEEEEJJJXXXOOOaaayyyiii___PPP```uuudddiiiiiikkknnndddbbbccc```kkksssccccccmmm^^^UUUSSSfffggguuuwwwooonnnhhhhhhyyyxxxsssssszzzttt -~~~2vvv{{{pppvvvwwwxxx~~~yyy~~~!#%(*--/3557675432/,('# !vvv~~~ yyyzzz~~~}}}uuutttzzztttvvvssslllkkknnnsssmmm|||tttooojjjjjjddd```aaaZZZ___dddqqqTTTRRRUUUNNNGGGFFFFFFBBBFFFMMMRRRVVVZZZZZZQQQPPPZZZZZZIIICCCCCCGGG???IIIIIIJJJMMMGGG???BBBIIICCCBBB;;;AAACCCFFF666;;;;;;DDDZZZ===:::???777999333555666<<<777000111,,,+++(((333***+++CCC***888333555...&&&,,,,,,))),,,///222777000+++888222,,,GGG000+++YYY---;;;...333333,,,///:::...111///111555222---555<<<;;;;;;<<>>:::888999888@@@DDD@@@666;;;OOO222---555333000333...000...***)))+++))),,,]]]888333555+++...(((000+++000,,,555***---333222EEEggg666666111111;;;///222666666333555///...---///222:::444///555>>>888:::<<<@@@HHHAAAJJJNNNKKKNNNJJJVVVTTTYYY\\\UUUaaaqqquuuyyyvvvlllmmmeee___eeeYYY___]]]sssfffbbb^^^gggxxxzzzhhhdddiiissskkkccciiiuuutttmmmgggjjjqqqtttqqqllluuurrrsssuuujjjxxx||||||yyyzzzwww|||~~~ - %'*--/5768:9:;:986652.,)("  -|||}}}|||{{{lllwww|||tttlllwwwssspppmmmnnnfffhhhjjjuuufffjjjiiilllbbbbbbccc^^^]]]WWW[[[kkkZZZSSSPPPLLLSSSMMMQQQWWWYYYUUUXXXVVVWWWbbbXXXPPPPPPPPPLLLNNNIIIJJJOOOJJJEEE@@@BBBBBB@@@AAAKKKBBBHHH???@@@<<<:::CCC222OOO===@@@>>>;;;555777,,,444666222//////000***===***,,,,,,'''***TTT111%%%$$$(((---...666//////,,,777;;;......888>>>000222888333AAA555DDD333111888,,,---...***...::://////555555888000>>><<<@@@CCCBBBHHHKKKLLLSSSPPPZZZTTTUUU[[[QQQLLLhhhkkkwwwggg[[[\\\\\\WWW[[[```bbbfff```nnnlllvvvpppnnnjjjqqqtttuuudddgggiiinnnhhhgggnnnnnnqqqeeehhhfffyyyiiixxx{{{uuu{{{xxxtttxxxzzzvvvyyy""*+./259:>>==<<>;6884.-,*& -  - www|||vvvjjjuuuooossshhhyyyrrr|||yyyiiifffhhhlllccccccooorrrxxxdddcccbbb]]]VVVUUUWWW```ZZZTTTQQQKKKNNNLLLMMMPPPQQQVVVZZZbbbWWWWWWOOO<<>>???>>>>>>]]]VVV:::AAA444444...///777222666///---+++,,,000)))%%%666222EEE---$$$%%%...///000111---555---999EEE555888KKK999444@@@444EEE777+++///;;;:::------111222,,,,,,---,,,777555;;;555CCCBBBDDD>>>JJJCCCGGGIIIJJJPPPXXXSSSQQQUUUUUULLL___^^^\\\vvvpppfffccc___```___XXXVVVaaa]]]]]]jjjiiieeejjjssseeellliiirrrcccmmmfffrrrnnnrrrrrrlllooogggccckkkkkksss{{{{{{sss|||zzzvvvppptttrrr "%'-0259<>>B@??@AA>;9342-,'&! -  ~~~}}}{{{zzz|||ssstttkkksssooosssooonnnqqqhhhgggmmmkkkaaammmjjjkkklllnnndddaaa\\\VVVXXXWWWUUUZZZPPPOOOPPPMMMRRRTTT```QQQOOOUUUXXX___eeePPPHHHKKKWWWFFFIIILLLIIIHHHJJJIIIDDDEEEIIIAAATTTFFFDDDFFF???BBB@@@777;;;JJJ>>>PPP>>>777111777<<<777333<<=953/,(&!   vvv|||xxxwwwxxxzzzuuuxxx~~~qqqrrrnnnkkkeeeaaammmggggggmmmiiiggg```UUUUUUWWWVVVVVVQQQeeeJJJVVVLLLQQQMMMRRRUUUTTTWWWPPP[[[ -___QQQLLLHHHNNNEEEIIIMMMLLLSSSCCCEEEFFFGGG>>>GGGWWWDDD^^^CCCDDD@@@888BBB999MMM:::WWW<<<===666000555333000888222,,,+++,,,...,,,///(((+++###"""$$$###888:::222((((((555---111,,,222>>>888999<<<444FFFMMMEEE444:::555222000000222---111+++...222000===555555888777CCC@@@@@@CCCHHHIIIGGGJJJMMMMMMOOOQQQXXXSSSRRRSSSLLLQQQ^^^ddd]]]___eee^^^gggXXXQQQYYYfffVVVXXX[[[fff]]]ccc]]]```sssbbbccceeemmmkkkgggqqqnnnhhhooo```cccmmmoooyyy{{{uuu}}}tttsss}}}~~~sssvvvxxx}}}~~~ ~~~ -  %(/457<>DFHJKKLLKIFECB?<74/,' |||{{{{{{~~~~~~yyy}}}ttt~~~{{{ pppqqqqqq{{{yyysssooopppooommmnnnnnnkkkaaaccc___oooMMMBBBFFFHHHOOONNNLLLOOO___OOOLLLKKKMMMKKKLLLQQQRRRPPPLLL>>>FFFOOOXXXWWWOOOJJJGGG@@@KKKGGGGGGLLLAAAIIILLLHHH???<<<888:::???BBBCCC@@@444DDDAAA999555666,,,+++''''''...++++++,,,,,,+++)))(((+++)))!!!''')))JJJ;;;%%%---///333@@@222222222444666555999ZZZJJJ333:::555...***,,,///---000222222666555777???@@@CCC@@@AAADDDFFFBBBFFFEEELLLWWW___ZZZUUUXXX[[[:Beeemmmmmmdddhhh___YYY\\\iii___]]]___fff[[[}}}dddWWW___aaaddd```___^^^___eeeiiiiiijjjhhhjjjkkkfffhhhpppsssssssss}}}uuutttwww -vvvtttwwwzzz{{{||| -%,138>>CEIKMOOOOPNLIGED@=741+&$&   ||||||~~~~~~~~~vvvsssuuu~~~{{{rrrwwwwww~~~vvvnnnjjjkkkssshhh```___ZZZPPPKKKRRRJJJEEEHHHKKKMMMUUUPPPUUULLLGGGOOOPPPQQQOOOOOOMMMHHH666GGGSSSZZZRRROOONNNLLLIIIJJJPPPWWWGGG???EEE;;;AAACCC???===NNN@@@FFFUUU777555777444444@@@222111000,,,111***)))''')))***&&&%%%,,,***$$$'''***---444CCC333,,,;;;<<>>EEEJJJ:::;;;555III...222333BBB...///---+++++++++000666333333;;;;;;IIIMMMDDD===GGG===AAABBBCCCIIINNNRRRWWWTTTSSSZZZ^^^gggxxxxxxrrrtttgggwww\\\[[[ZZZaaa\\\kkk]]]yyy___ZZZfff[[[lllaaaaaa]]]YYY```aaammmmmmooonnneeeiiinnnwwwrrrsssqqqsssooooooxxxyyyxxx}}}rrrwwwrrrxxx}}} -zzz!$*0127BCGKKOPSSTVTROMJHF@>:41.'&   -zzz{{{wwwrrrzzzzzz sssuuuxxxzzznnnjjjgggnnniiixxxllliii\\\UUUTTTSSSVVVRRRLLLRRRPPPLLLSSSKKKNNNFFFKKKMMMXXXNNNKKKNNNFFF===EEEPPPMMMPPPTTT]]]RRRMMMJJJHHHJJJaaaHHHCCCVVVXXXHHH===DDDCCCKKKAAAPPPBBB;;;999AAA444111111///000000111///)))&&&...)))$$$'''+++,,,&&&"""###'''666///222QQQ888777888LLLdddLLLAAABBB===???555444111???111777555---+++---,,,111666AAAPPPEEE===777<<<:::<<EGKNQSUXXZZWUSROMJB?:63-.,!! }}} -|||zzz~~~{{{yyyvvvyyy}}} ttt -mmmccckkkhhhsssmmmqqqdddbbb^^^VVVUUUWWWQQQUUULLLNNNLLLLLLMMMFFFEEEJJJRRRQQQQQQLLLTTTQQQLLLDDDWWWSSSUUUOOOTTTSSSLLLHHHHHHGGGHHHGGGLLLFFFOOOVVVAAA@@@FFFGGG@@@[[[FFF>>>:::888111777///111000,,,+++///...---,,,+++$$$***>>>+++--- !!!(((%%%,,,...---FFFMMMBBB222ZZZWWWjjjoooNNN555;;;555666111///,,,555===333------+++222555^^^III;;;888;;;:::;;;EEEDDDFFFKKKHHHKKKLLLTTTXXX]]]\\\``````bbbpppkkkooottthhhkkkaaabbbqqq```TTTVVVgggjjjfffoooaaagggooo^^^\\\aaa___ccccccdddaaafffoooqqqiiiyyyvvviiitttlllllltttyyyzzz.|||{{{xxxzzz}}}  !(-058=CGKNRVXZ]^]][ZXTROJEB=840.-"  ~~~yyy}}}zzzvvvyyyuuu - -rrrzzzxxxrrrtttlllfffjjjjjjlllllliiicccggg^^^ZZZVVVVVVRRRVVVSSSJJJJJJKKKKKKJJJUUUOOOQQQNNNOOOSSSTTTUUUSSSTTTUUUZZZWWW^^^TTTIIIIIIIIICCCAAA;;;===BBBFFFEEEAAAAAA???LLLYYY@@@LLLOOOFFFDDD999...111333222,,,...,,,---111777+++***---)))((('''777...!!!###''')))000&&&---FFFfff777444DDDPPPFFFHHH<<<999555555111000,,,111,,,888---000///,,,<<>>SSSKKKCCCHHHHHHVVVVVVttttttBA  -jjjhhhjjjYYY[[[YYYYYYSSSOOOPPPZZZWWWVVVWWWUUUVVVVVVWWW___\\\\\\VVVddd___WWW\\\cccwwwjjjsssuuusssccciiiqqqllloooqqquuuvvvzzz{{{jjjpppbbblll|||}}}   %+04;AFLPTZ^aegijjihfc^YTQLGA;72-)%! }}}|||tttwwwxxxxxxxxx|||zzzqqqyyyxxxqqqssshhhkkkjjj}}}7/mmmiii```]]][[[\\\VVVTTTPPPRRRSSSTTTPPPHHHKKKMMMHHHKKKIIIKKKUUUSSSVVVPPPPPPLLL[[[WWW___SSSPPPJJJHHHLLLNNNGGGHHH??????BBB>>>>>>===RRRCCCOOOJJJHHHNNNEEEHHH>>>@@@666111333...888888,,,222***+++)))######'''---%%%222''')))(((---444,,,111NNNBBB333BBBDDDEEE<<<888===>>>222999444333111,,,+++)))777//////,,,---555>>><<CINSX\`ehkmmnnliea\WRMHB=53-)! - -zzzzzz}}}yyyooouuuzzz|||xxxnnn~~~yyy}}}lllfffkkkeeelllvvvooogggaaadddZZZYYYYYYUUUTTTTTT[[[VVVNNNIIIKKKYYYLLLKKKLLLKKKIIIOOOUUUTTTQQQGGG]]]RRRUUU[[[PPPTTTKKKJJJGGGFFFAAAEEEHHHHHH@@@AAA???CCCCCC>>>QQQKKKXXXcccNNNAAA999:::///,,,+++444:::888333***444+++)))&&&+++,,,&&&%%%+++***(((***333///===;;;PPPIIIAAA999III999===AAA999...222000---///---+++(((///+++111///222555999>>>KKKDDD;;;;;;FFFEEEHHHNNN[[[TTTYYYhhh .zzz}}}tttkkkccc\\\XXXTTTUUUPPPQQQNNNZZZWWW___]]]jjjyyyVVV[[[ZZZ\\\\\\YYYUUU___WWWbbbkkkjjjuuummmhhhhhhlllrrrqqqkkknnnzzzooonnnrrr|||}}}}}}sss{{{uuuzzz}}} - - %*-2:?DINTZ_cgknppponieb]XSNHB<72-*#  uuu~~~zzzvvvyyyppprrr{{{mmmpppwwwvvvtttggghhhooommmwwwllljjjgggddddddddd^^^bbbWWW[[[SSSOOONNNIIILLLRRRNNNLLLLLLHHHHHHNNNOOONNNTTTJJJJJJ___TTTTTTOOOWWWQQQJJJGGGEEEEEE@@@FFFCCC@@@BBB@@@;;;CCCUUU555BBBJJJfff@ OOO888888222...111333222<<>>???<<74.(#! www|||ttt~~~yyyuuu{{{{{{}}}}}}vvvpppuuuhhhhhhsssxxxtttjjjiiiaaafffgggttthhh```___WWWLLLQQQQQQSSSTTTOOONNNJJJBBB>>>JJJPPPOOOOOONNNPPPPPPVVVUUUWWWRRRMMMQQQLLLJJJHHHBBBAAA@@@NNNNNNYYYEEEAAAAAAGGGBBB666OOOXXX EEE@@@---666000888///---222111***'''(((((((((&&&(((444:::+++222---111222111FFF___UUUHHH999444,,,>>>AAA666333...///---+++***///...---CCC+++***333333444666999;;;AAA>>>===JJJAAAPPPNNNYYYkkk YYYddd{{{yyy]]]YYY]]]TTTaaajjj[[[ZZZXXXXXXUUUgggWWW]]]XXX^^^WWWggg[[[ccc\\\ZZZZZZWWWYYY```bbbXXX```lllrrr~~~eeelllppprrrmmmpppqqqrrrqqq|||rrrvvvwwwzzzzzzzzz|||  "'+.6;AGKQV[bfjnsy{uqomhc^ZSLHD@:4,(#  -~~~xxxvvvwwwxxxvvvsssxxx~~~|||xxxxxxtttrrriiihhhyyyvvvgggbbbiiihhhvvvlll[[[^^^\\\QQQJJJLLL]]]MMMLLLOOOIII<<>>;;;777333222///999000000,,,---,,,,,,(((666666CCC777:::777@@@===EEECCCCCCDDDQQQzzz#eeeqqqyyy{{{YYYPPPmmm\\\ZZZaaa```YYYYYYXXXZZZ\\\VVVXXX^^^XXXhhhSSSUUUiii___VVVbbbdddbbbccc___\\\sssuuuyyycccRRRkkkgggrrrooojjjlllsss{{{{{{pppsssvvvyyyxxxwww  %(+07<@GLQW\aekosx{vqolgb^YSMHD?:3,)# }}}zzzwwwtttwwwyyyrrrzzzwwwzzz -|||uuuvvvxxxsssqqq}}}rrrkkkllljjjhhhhhhooobbbXXXYYY\\\MMMJJJGGGQQQEEELLLMMMNNNHHHMMMOOONNNQQQTTTNNNHHHKKKVVVTTTRRRYYYJJJLLLHHHKKKJJJFFFFFFDDDAAAFFFCCCDDDYYYoooCCCDDDHHHKKKGGGHHHAAA;;;333444666000222---///,,,(((***---+++%%%"""$$$&&&###+++%%%+++555777777@@@===999OOO===333666EEE444222<<<222)));;;JJJ444...(((***'''++++++---222CCC>>>;;;:::<<<]]]QQQEEEHHH@@@DDD]]]9lllooohhhlll\\\]]]YYY___[[[TTT___aaa]]]SSSYYYXXXTTTcccXXX^^^```bbbSSS\\\ZZZXXX[[[```jjjgggwwweeeeeekkknnnxxxmmmrrrlllfffgggiiisssnnnmmmhhhoooxxxvvv{{{lllmmmttt{{{{{{zzz - - $(+6=>>666BBB888RRR___YYYUUUAAAPPPIIIVVVgggiiivvvhhh]]]PPPPPP___]]][[[___mmmXXX]]]ZZZ___pppsss___WWW[[[]]][[[ZZZ```[[[[[[^^^cccdddeeehhhgggggg\\\fffsssmmmjjjjjjfff```kkklllnnnlllooopppyyyzzz|||{{{kkknnnuuu{{{}}}}}} - -!!'-19=BGMRX[beimpqrrnkic^ZVPKD@:70'%! yyy{{{uuuxxx}}}zzzwww||| ~~~ '>yyynnnmmmooowwwrrrjjjaaaaaa[[[^^^ZZZWWWKKKNNNQQQOOOXXXKKKFFFHHHWWW\\\mmmkkkTTTKKKSSS^^^DDDOOOKKKTTTeeennnMMMIIIIIINNNNNNSSSFFFAAAFFFMMMIIIJJJEEEGGGDDD@@@III>>>DDDFFFMMMAAA:::555111000...///)))+++,,,---+++######$$$"""!!!"""%%%%%%:::333kkkTTTccceee>>>YYYDDD:::999777333555111(((111CCC555>>>BBB+++(((&&&(((,,,555HHHRRRMMM@@@FFFBBB<<93/($! }}}uuuzzz}}}tttooo{{{ vvv~~~ - GH7rrrsssdddjjjiiieee___WWW[[[VVVUUUXXXOOOLLLNNNTTTRRRQQQOOOKKKSSSTTT[[[QQQIIINNNUUUzzzSSSQQQUUUSSSYYYYYYLLLMMMWWWQQQHHHNNNFFFFFFCCCEEEFFFCCCFFFLLLOOO]]]JJJbbbXXXPPPeee;;;888///111999///,,,((()))+++(((((($$$### %%%'''%%%111...777ggg%{{{PPPDDD;;;111333>>>;;;000...///333,,,222777+++333,,,((()))...000777JJJAAAGGGdddxxxLLLOOOQQQBBBGGGJJJVVVSSSYYY^^^XXXggg-R bbb\\\bbb]]]pppiiiaaaQQQSSS]]]lllrrrppptttZZZSSSUUURRRUUU```aaaVVV___iiifffggg^^^bbbpppwwwnnnkkkvvvjjjiiiooolllqqqpppoooiiinnnmmmrrrlllooo~~~   "(*27=>DKPUY^adgillkgeb^YTPMHA:62.(! - wwwxxxwwwzzzvvvuuuzzz|||zzzzzz <(}}}uuummmllljjj______^^^VVV]]]QQQUUULLLSSSOOONNNKKKJJJJJJOOOKKKPPPLLLUUUSSSRRRLLLXXXRRRTTTXXXYYY[[[___NNNLLLIIIFFFJJJGGGJJJAAACCCJJJQQQJJJ]]]fffJJJKKKJJJHHH___mmm888111...000+++,,,///...'''***$$$,,,&&&"""%%%((('''"""'''<<<<<<888KKKpppHHH444666888222555444888000......999---000//////,,,---)))<<:5/,%" |||~~~{{{vvvsss{{{~~~ -zzzyyywwwmmmmmmwww~~~~~~hhhlll```aaa[[[WWWOOOLLLMMMIIIEEEFFFNNNFFFFFFIIIIIIHHHGGGIIIOOOUUURRRRRRLLLOOOVVVSSSWWWSSSWWWSSSIIIDDDLLLSSSEEE???CCCBBBKKKsss___uuuPPPiiiIIIIIIPPP___kkkbbbHHH222,,,******'''&&&---&&&)))&&&%%%######%%% %%%!!!FFF;;;>>>KKK>>>555222777,,,,,,...777///555222000888222333999333000000(((555666///DDD JJJNNNKKKJJJNNNIIIFFFNNNLLLTTTSSSddddddmmmyyymmmfffZZZZZZSSS^^^dddfff\\\```___qqq[[[WWWWWWYYYSSSVVVXXXQQQSSSZZZ]]]bbbUUU___YYYdddllltttxxxwwwyyy~~~{{{tttooovvvpppsssmmmsssjjjppp|||xxxbbb -  !(/5;?DHMQTX[]bbacb^_\WROJD@;72-*# {{{ zzznnnwwwwwwzzz{{{|||~~~|||nnnkkkooowww{{{tttwwwsssqqqpppiiiccckkkXXX\\\PPPLLLKKKJJJKKKDDDLLLGGGJJJJJJFFFEEEDDDIIIQQQVVVTTTUUUXXXTTTRRRbbbUUUXXXgggRRRJJJIIILLLEEEEEEBBBCCCKKKTTT}}}nnnZZZMMMAAAMMM{{{OOOhhhZZZVVVBBB222+++%%%&&&(((###)))///***%%%&&&(((%%%$$$###((('''%%%!!!===AAA<<<;;;333,,,222,,,---+++---333...333777===777///333111<<<666:::---,,,...444<<CFJORVXY\^^_\ZZWSOKGB<84-+#!   "(sssxxxyyyvvv~~~zzzxxxvvvmmmkkkpppwww~~~ mmmbbb___ddd\\\ZZZ[[[YYYXXXOOO\\\NNNEEEJJJCCCEEEHHHEEEEEEOOONNNOOOMMMRRRMMM\\\\\\ZZZYYYUUUUUU\\\KKKMMMLLLIIICCCDDDHHHFFFNNNJJJEEEMMMMMMGGGDDDPPPvvv;;;<<<;;;JJJ888333222+++'''+++...***)))***%%%""")))$$$(((777(((&&&,,,&&&OOO777333000777444///222,,,+++...---(((222777AAA===222:::555555444111///,,,***---666888333999JJJFFFHHHTTT???@@@TTTYYYMMMQQQ^^^```ZZZ\\\^^^^^^WWWUUUVVVUUUSSShhhLLLZZZdddfffttt!(#pppiiiqqqVVVSSSQQQYYYPPPRRR[[[TTTaaa```___nnnuuu1yyyssseeeiiizzzxxxrrrrrrnnnkkksssfffttt}}}www}}}}}}|||  $%/06>>GGGGGGNNNFFF???<<<:::888@@@444777BBB222555...888,,,,,,---***(((!!!'''###&&&,,,###&&&&&& PPP[[[333999777000+++///000///...***---555777...666111///000,,,)))333000---777666;;;222777;;;EEEAAA999LLLEEEVVVEEEIIIOOOPPPNNNWWWbbbYYYfff^^^\\\WWWTTTjjjSSSPPPXXXhhhcccfffooo,dddgggiiiccc\\\UUURRRWWWZZZWWWVVV\\\]]]xxxeeeiiijjj```ooohhhiiihhhaaaoooqqqnnnkkkhhhooosssooovvvooovvv{{{~~~}}}|||zzz~~~  ")0/3:>DFIKOQTTSSTURPMJGC?=85-)'# -yyy{{{{{{~~~~~~~~~zzzwwwzzzssstttkkknnnsssiiiuuuwwwnnnqqqllldddaaa```VVV]]]VVVOOOFFFIIIHHHMMMIIIIIIBBBEEEYYYMMMDDDPPPVVVZZZWWWXXXbbbXXXWWWPPPSSSYYYUUUXXXNNNDDDFFFGGGAAABBB;;;KKKEEEAAABBBDDDIIIYYYFFFBBB===???222<<<>>>>>>888111++++++'''+++111+++(((333"""###"""### %%%%%%:::;;;@@@:::111---111000111,,,666///111///222...111555444(((%%%000///888222999AAAhhhDDDDDD???===LLL<<>>GGG@@@EEENNN[[[lllJJJ???444bbbHHH000666888000555111((((((,,,''''''******%%%!!!%%% &&&!!!%%%"""111555AAADDD999444333000BBB///111444,,,''',,,...///---(((&&&***...555666===666PPPeeeDDD===???<<<:::>>>@@@>>>BBBDDDCCCFFFTTTUUUOOOMMMIIIKKKOOOXXXdddSSSYYYRRRWWWkkkYYYgggaaaGGGIIISSSSSS[[[___]]]^^^ZZZbbbPPPQQQ]]][[[\\\```[[[kkk[[[bbbZZZ___```fffbbb{{{rrrsssooonnnlllggghhhqqqoookkkttt}}}vvvvvvyyy - - "%)//7;?@CEHHIJLLKJHDEB?<84/)(&  - }}}vvv|||ooowww}}}}}}}}}zzz|||uuuooopppmmmttt{{{pppjjjhhhhhh______[[[WWW```UUUMMMPPPKKKMMMPPPUUUIIILLLLLLRRRVVVUUUXXXQQQYYYZZZ[[[^^^aaa]]][[[XXXXXXSSSlllsssIIICCCCCCBBBEEE@@@CCCPPP;;;@@@777>>>XXXFFFCCC222555555222...111***+++,,,,,,***************%%%&&& ###$$$000(((""" 777;;;KKK111000222,,,000222000222222000+++111777666$$$)))(((,,,...///999>>>jjj)!DDD<<<:::666999555777:::BBBCCCKKKHHHSSSIIIVVVPPPQQQ^^^rrrccciiiXXXRRRWWWZZZcccbbblllfffkkkvvvVVV]]]\\\bbbYYYWWWSSSWWWTTTUUUSSSPPPOOOOOO[[[ddd___XXX]]]YYY___bbbjjjzzzyyyooojjjkkkiiizzztttpppyyy{{{yyyvvv}}}  %*0237=>ACDFGHHFFEEBA?<:4/,,'# uuuuuurrrzzzzzzyyy~~~~~~~~~{{{www vvvkkkwwwnnnooovvviiiiiihhh```\\\YYY\\\WWWZZZuuuRRRKKKGGGGGGLLLNNNTTTTTTTTTRRRPPPUUUVVVTTTWWWXXXVVV[[[WWWYYYOOOAAABBBKKK]]]___UUUHHHEEEEEE???AAACCC<<<:751,)&! zzzzzzyyyxxxvvvxxxyyyyyyyyy xxxuuuqqqlllwwwyyyppphhhfffgggggg]]]___fff```pppUUUIIIJJJIIIJJJOOO^^^QQQNNNOOOTTTWWWXXX^^^[[[ZZZ___ZZZYYY```SSSJJJNNNPPPKKKPPPQQQKKKHHHAAAFFFEEEEEEBBBBBB:::===<<<===999222333666222000///,,,///222000,,,((()))%%%***'''...---***$$$&&&$$$######%%%pppPPP444333>>>???***(((***ZZZ===,,,...;;;&&&&&&'''888888)))------000111BBBkkk~~~GGG<<<333555333444999:::;;;===IIIKKKLLLFFFKKKKKKQQQYYYRRRPPPSSSTTTXXXQQQaaa```aaafffiii^^^bbbWWWUUUYYYUUUMMMQQQ\\\RRRPPPSSS^^^YYY___ZZZcccZZZ\\\XXXUUUggg___^^^eeevvvoooiiinnnrrrmmmfff|||uuu{{{{{{{{{~~~||| &$**-156:<=??@?>>A>=:7430-)(%" -yyy~~~zzzzzzuuurrrxxx -uuurrrwwwuuusssqqqnnnssslllgggfffiiiaaa___qqq```YYYZZZQQQPPPJJJHHHKKKUUU\\\QQQXXXQQQUUUccc[[[]]]bbbTTTUUUSSSWWWUUUSSSOOOPPPMMMPPPPPPDDDLLLCCC>>>===UUUPPP@@@888======444222333444222111,,,((()))*********---(((&&&###&&&'''...999///+++---$$$###%%%!!!;;;777111444,,,...))))))+++QQQ999000,,,000,,,'''888000(((...---222:::777666BBBIIIEEE;;;111555888666666:::<<<===EEEBBBJJJGGGJJJSSS\\\[[[MMMRRROOOJJJRRRTTTSSS^^^[[[]]]YYY___WWWKKKNNNVVVWWWLLLNNNZZZPPPVVVaaaRRROOOPPPRRRVVV___ZZZZZZVVVQQQ[[[eee___```iiivvvqqqooo -lllddd~~~pppwww|||}}}||| -  &*-.246:;====<<<:752/0-*(#"  wwwyyyzzz|||{{{www}}} vvv|||~~~ zzzuuusssuuuvvvqqqmmmmmmiiijjj^^^mmmtttlll```___^^^SSSOOOIIIDDDEEEQQQPPPSSSUUUXXXYYYZZZ[[[VVVXXXWWWRRR^^^WWWOOONNNSSSTTTMMMLLLNNNNNNHHHGGGSSSOOOFFFFFF>>>>>>444222222000111111666---,,,))),,,***---(((,,,+++222&&&$$$$$$###$$$$$$%%%000KKK...''''''...###999000444000...333+++///&&&(((%%%(((******555000111---******'''777222;;;444;;;666;;;444555111888555999===MMM???EEERRRJJJAAAOOOOOOYYYOOOHHHNNNKKKIIITTTTTTYYYXXXUUURRRZZZaaa^^^\\\dddsss\\\LLLPPPNNNPPPTTTPPPQQQUUU___ZZZVVVWWWUUU[[[sssZZZZZZ___cccfffkkkwww -xxx||||||{{{www ~~~yyyzzz    !&+-04478::9:977641/-,+&#   ~~~yyy}}}~~~zzz yyy~~~rrrtttqqqssswww{{{~~~uuupppoooggghhhkkkkkkkkk[[[YYY[[[\\\PPPLLLKKKLLLHHHMMMLLLZZZJJJdddVVVSSSQQQOOORRRYYYUUUUUUWWWQQQRRRMMMNNNLLLQQQLLLJJJFFFJJJDDDSSSAAA===777444444<<<<<>>:::---++++++...+++((($$$,,,***222111555444222++++++111---((()))000222111444---000999777AAA:::888???>>>QQQFFFWWW\\\LLLIIICCCIIIMMMEEEIIIVVVQQQUUUOOOWWWZZZ]]][[[XXX```YYYUUUqqqpppTTTSSSRRRTTTLLLMMMSSSWWWQQQ\\\NNN\\\XXXqqqggg]]]]]]\\\```]]]^^^mmmvvvzzz www~~~   $)*03367888765431.+**(!    - ~~~|||~~~{{{~~~}}} xxxrrrnnnrrrtttqqqnnn{{{}}}jjjfffoooyyyfffaaa___eeekkkaaafffTTTMMMOOOQQQMMMMMMVVVWWWQQQRRRRRRRRRTTTSSSSSSYYYWWWVVVfffQQQgggTTTTTTMMMQQQNNNJJJSSSOOOKKKJJJDDD:::;;;999777333222...222***---111+++......,,,$$$(((+++'''***###333%%%((()))((("""111(((((('''"""+++222444000222,,,---000******&&&))),,,---222)))---555444333BBB000---+++((())),,,222...,,,666666NNN333555BBBEEEHHHZZZOOOWWWpppVVVWWWDDDJJJSSSMMMTTTPPPLLLSSSUUUPPPOOOWWWTTTaaa```cccfff```VVVVVVSSSSSSLLLXXXLLLRRRYYY___VVVRRRRRRiiiYYY___^^^^^^]]]aaaccclllpppzzz/$}}}   "&*-0243565357410))&$"  }}} vvvvvvzzz~~~sssxxxzzzmmmlllnnnpppuuuvvvqqqlllnnnnnnwwwkkkfffYYY___aaa___YYYSSSUUUSSSSSSSSSUUUWWWXXXSSSMMMVVVSSSWWWWWWTTTQQQTTTKKKZZZZZZYYYWWWPPPNNNMMMNNNLLLFFFKKKIIIDDDEEECCC>>>???666222222666111+++000...///(((***&&&%%%&&&(((+++'''&&&***,,,***,,,&&&%%%...&&&'''###DDD"""555222444//////444***///)))---(((111///+++---444000222CCCRRR666((()))%%%))),,,222,,,//////---000444666:::FFFKKKEEEQQQWWWSSSXXXOOORRRRRRMMMPPPQQQRRRPPPIIITTT[[[RRRKKKTTTUUUaaa]]]hhh^^^PPPaaaQQQHHHRRRIIIHHHRRRVVVYYYQQQZZZ___PPP]]]aaaeee^^^[[[XXXaaaaaappplllwww%,() ~~~zzz~~~   !#(-,.122211331,+'&"  vvvyyy }}}zzz{{{|||pppssssssuuurrrppprrryyyzzzooossstttqqqhhheeeggg^^^WWW]]]bbb^^^SSSPPPQQQSSSZZZVVVooo|||NNNQQQZZZVVVUUUUUUWWWSSS___UUU[[[ZZZiiiXXXTTTSSSPPPLLLKKKDDDDDDJJJNNNHHH<<<;;;===...000>>>666777+++***---+++&&&%%%***'''&&&)))(((''')))###,,,++++++''')))(((***===000***&&&)))+++******)));;;***777///,,,,,,888444666======)))...PPPQQQ444+++"""'''...***---666999//////222777???CCCKKKPPPpppjjjMMMYYYhhhSSS^^^kkkkkkUUUXXXTTTQQQJJJ[[[bbbRRRPPPYYYKKKTTTLLL]]]LLL[[[MMMKKKGGGJJJNNNMMMTTTXXXSSSXXX]]]WWWUUU___```TTT```^^^YYYddddddnnnooo|||9EQ<&  }}}~~~xxx {{{ -!"&))+../0.-/0/**-&"  -|||~~~ - ~~~yyyxxx{{{uuusssppplllmmmxxxqqq}}}llloootttsssjjjaaaiii\\\RRRXXXLLLXXXMMMSSSMMMSSSiiiTTTTTTUUUTTTWWWTTTYYY]]]VVVVVV]]]UUUXXXPPPMMMWWWZZZ]]]QQQMMMbbbDDDGGGCCCEEECCC<<<555KKK777777;;;:::...+++(((---***)))***222***(((+++&&&(((###000+++---'''))))))((()))&&&)))...""" !!!111,,,***---///+++???666---===uuu:::---444999111)))...444,,,222$$$...111...---///666000555777000QQQBBBIIINNNqqqfffUUUtttuuuccc___bbbcccXXXddd^^^GGGMMMPPPJJJcccZZZQQQTTTLLLOOOPPPNNNFFFCCCHHHIIIOOONNNZZZaaaTTTUUU\\\aaaWWW^^^hhhddd]]]ZZZ]]]___cccpppiiimmmyyy ;s{X# }}}~~~xxx||| ~~~ !"$%')+-0/,+()%%"# #  {{{yyyuuu{{{xxxxxxrrrnnnmmmsss}}}vvvttt{{{~~~cccaaaaaaYYYQQQLLLNNNPPPQQQSSSVVVUUU\\\TTTRRRdddZZZ```VVVppp^^^RRRXXX]]]WWWTTT^^^PPP^^^{{{eee]]]^^^LLLCCCTTTDDDEEE;;;EEE===WWWCCC<<<333777///&&&)))(((+++...000((((((((('''222***444:::***)))...///...888333,,,&&&---###)))DDD000+++,,,///))))))------...111333,,,---777555)))(((---$$$***333,,,,,,666666***CCC---,,,,,,===;;;??????HHHOOONNNIIIVVVrrrYYY]]]SSS^^^aaajjjxxxOOOTTTIIIJJJNNNDDD___KKKRRRNNNTTTHHHFFFNNNKKKMMMIIIMMMsss\\\YYYZZZMMMSSSRRRVVVYYY[[[___aaaYYY\\\]]]fffiiilllrrr0mwU"yyy|||  !#$(**0-*)&'!" %$ -}}}||| -~~~~~~vvvuuuyyyxxxrrrkkksssxxx yyyppp{{{fff^^^ccc[[[MMMWWWJJJPPPWWW\\\WWWXXXVVVSSSUUU]]]PPP\\\XXXSSSTTTQQQWWW\\\]]]___PPPQQQWWWhhhsss```VVVYYYdddUUUDDDJJJLLLGGG===<<<888888CCC222666,,,+++...+++---***'''******)))000888111<<<000333111333999PPPMMM:::000000)))***333---,,,,,,***000---===000111666,,,+++%%%&&&,,,+++###...(((---777222)))---...111777000***000777JJJFFFDDDYYY^^^XXXQQQkkk{{{uuudddWWWYYY]]][[[TTTaaaUUUFFFPPPLLLSSSXXXJJJOOOPPPHHHEEEGGGDDDGGGQQQMMMDDDOOOYYYTTTVVVNNNOOOPPPYYY\\\WWW___fffmmmccceeetttkkklllsss -:?OC -{{{ yyyzzz !"!%%(,*)'''&%  -}}}}}}vvv{{{vvvoooyyynnnqqq|||{{{wwwppptttwww\\\ZZZRRROOOPPPSSSYYYSSSMMMLLLOOOXXXYYYRRRRRRSSSZZZ\\\WWWQQQVVV___ccc^^^XXX\\\^^^ fffXXXjjj^^^QQQFFFAAAEEE===999666;;;777444000...,,,---$$$***---000333111444///%%%,,,+++***111000@@@AAA+++888>>>777555(((444222666000(((***///555---(((///000000...444###%%%&&&''')))***111...---111+++...000...///>>>111333111<<<<<>><<<111666444...777444'''***---...///...+++***,,,...,,,,,,---(((III333777333///999LLLHHH888666>>>999222111---***---'''+++)))(((///,,,222%%%''''''***)))((()))+++000...222///,,,+++...//////:::666777BBB===777BBBRRRbbbnnn3h3\\\PPPUUU[[[VVVHHHFFFKKKKKKHHHPPPKKKJJJDDDFFFFFFMMMEEEEEEFFFDDDDDDHHH>>>GGGPPPPPP^^^SSSOOOPPPRRRRRRRRRUUUYYY]]]hhhfffkkkiiigggkkk, -yyy{{{yyyvvvxxx}}}}}}  - - ! #%&!"!   - ~~~ yyyhhhmmmmmmtttllltttrrruuu -.)~~~nnneeeddd___^^^OOOJJJOOOVVV^^^KKKTTTOOOSSSQQQJJJPPPRRRSSSNNNZZZ___eee___WWW\\\RRRTTT^^^ZZZ\\\___IIIFFFSSSDDDAAA???<<>>OOOcccWVVVPPPPPPTTTKKK\\\GGG@@@KKKCCCEEEIIIJJJ@@@HHHNNNUUUOOOLLLHHHGGGHHHSSSEEEDDDGGGGGGHHHPPPUUURRRLLLLLLTTTXXXOOOUUUYYY^^^aaaSSSgggxxxxxx|||qqqzzz||| tttmmm|||mmmjjjyyy~~~     }}}|||}}}vvvrrr|||ooommmqqqppptttnnntttrrruuu(+ ddd___^^^dddMMMUUUMMMNNNNNNVVVXXXPPPFFFOOOJJJQQQTTTLLLNNNIII\\\```dddoooXXXUUUcccXXXTTTWWWTTTLLLKKKKKKFFF>>>BBBAAA@@@:::999999;;;333222000...222...///222---'''ZZZ -555222------000,,,+++)))%%%444+++,,,...***+++***YYY444555,,,)))555///***+++)))...------111%%%&&&222222"""'''333333'''***'''(((++++++///***......333222888::::::===JJJIIIPPPSSSkkkrrr ]]]MMMXXXUUUTTTLLLGGGJJJCCCIIIRRRFFFBBBJJJBBBHHH]]][[[HHHIIIGGGDDDMMMKKKEEEDDDHHHHHHGGGOOOVVVOOOTTTIIIQQQ___MMMLLLddd\\\VVVggglllqqqjjjqqqrrrooo]]]rrrqqqyyyqqqzzzvvvjjjoootttzzzvvv~~~  -  ~~~~~~zzz vvvwwwyyywwwqqqxxxppplllrrrnnnnnnyyyxxx||| ~~~wwwZZZ[[[ZZZSSSFFFEEELLLJJJQQQNNNaaaSSSUUUSSSYYYSSSUUUKKKPPPOOOTTTdddaaaXXXZZZWWW^^^PPP[[[QQQ\\\XXXLLLFFFKKKMMMGGG===;;;;;;===;;;===888111222...111,,,+++...+++...---QQQ333///------...,,,000&&&---666---///000222000===wwweee///,,,'''444///---***222(((+++)))***&&&(((***000%%%###%%%FFF+++222---+++%%%'''222)))333///BBB???GGGFFFFFF<<>>:::888666333:::===222000///---)))(((***(((,,,(((&&&(((***...+++''',,,(((,,,111&&&666(((+++***000,,,------,,,)))---///---'''(((''''''(((&&&+++***(((+++((((((''' ######(((%%%'''...,,,MMM...---000111888777222@@@>>>EEE@@@<<>>777===<<<;;;888:::666444777111,,,666'''(((+++))))))(((---+++'''///)))''')))888&&&///111***)))---...(((&&&***&&&&&&+++---000)))&&&))),,,(((000+++000222%%%,,,###'''""""""&&&$$$%%%///666???///---444///'''///111222888:::EEE>>>???@@@:::<<>>IIIDDDHHHTTTRRRLLLOOOHHHFFFHHHIIIHHHIIINNNJJJHHHOOO???>>>LLLOOOFFF>>>EEEYYYAAALLLIIIOOOMMMIIIIIIEEEOOOTTTJJJVVV``` &~~~dddaaaddd```jjjvvvooo]]]ggg }}}wwwyyy~~~rrr~~~jjjrrrpppvvvlllrrrooozzzzzz    - yyy{{{|||zzz||||||uuuoooxxxwwwuuuyyyuuupppmmmwwwxxxsssnnnbbbiii^^^]]]ZZZWWWXXXVVVPPPKKKMMMYYYQQQOOOQQQRRROOOQQQSSSVVVVVVXXXUUUYYY[[[TTTWWWYYYVVVUUUWWWVVVVVVTTTZZZWWWJJJEEEAAA<<>>EEE???BBB???GGG???AAAJJJLLLOOOJJJ```GGGGGGFFFPPPIIITTT\\\cccbbb\\\eeebbbhhhhhhnnntttwwwjjjqqqmmmsssrrr -|||sssuuuqqqppppppyyy ~~~||| -  -  - -zzz -%|||wwwwwwyyypppnnnqqqwwwnnnyyyttt{{{ooowwwqqqhhhpppqqqooopppmmmaaa[[[XXXWWWhhh\\\QQQRRR]]]QQQQQQNNNYYYTTTVVVSSSSSSUUUYYYZZZ^^^cccXXXYYYXXXXXXTTT]]]WWWWWWTTTPPPNNNNNN[[[XXXGGG;;;;;;<<<666999888777:::===GGGCCCJJJ666...000***+++***(((...)))***%%%%%%)))***+++...+++&&&------,,,000+++---===))),,,000%%%+++222***@@@***$$$%%%CCC...***+++---@@@ccc333___)))''''''%%%((())))))'''444777>>>999///666???111333333777<<>>GGGFFFEEELLLDDDHHHJJJ\\\rrr\\\[[[^^^ZZZdddYYYrrr!mmmmmmjjjgggjjjmmmuuu~~~|||nnntttoookkk}}}sssssszzz2 yyyyyyxxxyyy -~~~   }}}|||}}}}}}}}}||||||tttrrrqqqqqqmmmllllllkkktttsssuuukkkhhheeejjjfff iiiaaaVVV\\\YYYYYYSSS^^^PPPRRRSSSTTTTTTRRRZZZVVVZZZTTTUUUYYYfff___YYYVVVUUUXXXOOOQQQQQQWWWQQQPPPTTTOOOGGGFFFDDDCCC???CCCCCCLLLBBB@@@<<<222<<>>GGG///000)))'''...>>>;;;,,,444MMM999888@@@QQQGGGPPPQQQ]]]^^^ccc[[[]]]aaa\\\fffJJJHHHCCCQQQLLLKKK@@@GGGRRR???AAA???JJJDDDBBBHHHHHHAAA>>>DDDAAAFFF@@@HHHGGGFFFHHHDDDEEEIIIHHHGGGGGGNNN\\\YYYdddhhhmmmwwwuuujjjmmmlllggglllsssrrruuuxxx.zzzhhhnnntttlllpppzzz||| - ~~~{{{~~~~~~~~~~~~~~~~~~}}}wwwzzztttwwwvvvzzzpppqqqqqqgggooojjjfffllljjjfffggg___]]]hhhbbb[[[\\\UUUQQQNNNQQQPPPOOO[[[[[[UUUZZZttthhhZZZVVVTTTSSSQQQMMMNNNVVVPPPWWW______^^^XXXVVVSSSOOOOOOIIIFFFLLL@@@CCCAAA===HHHEEEDDDCCC??????@@@DDD555SSSHHH===555:::222888---+++000+++)))((((((333)))***---222999///***555444111***&&&(((((("""%%%000222%%%!!!""")))(((%%% !!!666'''%%%%%%'''$$$""" )))///>>>NNN|||~~~EEEEEE???TTT///---111111222000555BBBCCC<<>>DDDFFFFFFIIIDDDFFFBBBJJJCCCDDDCCCAAACCCFFFNNNVVVZZZ```dddkkkgggjjjiiiiiipppqqqfffzzz|||vvvooojjjdddkkkssseeemmmwww  -}}}}}}||| -  -~~~~~~}}}}}}}}}~~~}}}|||zzzvvvwwwyyytttsssqqqrrr}}}lllqqqccceeegggddddddcccddddddggg___[[[UUUYYYLLLMMMPPPUUUWWWWWW[[[bbb```VVVSSSOOORRRVVV[[[XXXWWWYYYXXXYYYaaaZZZYYYVVVUUUPPPJJJKKKHHHLLL___KKKDDDDDDHHHFFFJJJ\\\RRRAAA>>>LLL>>>JJJQQQXXX<<<666444888++++++---;;;+++************''',,,(((...(((111555,,,222)))000%%%%%%###"""&&&...+++'''###***(((666"""%%%((('''###$$$"""...&&&'''&&&777HHHNNN8'CCC===;;;666000111...222???222===EEEBBB<<>><<<===444---+++)))---...333((((((,,,+++,,,***111)))))),,,222222CCC...***---222---"""000***###""""""!!!"""""" """###777,,,888'''444000777@@@UUU6DDD777+++)))'''(((+++111555AAA\\\:::<<>>DDDFFFEEEHHHHHHEEEPPPUUU[[[]]]UUUjjjxxxnnnlllooottt@? -yyy >/qqqooo{{{'=www}}}xxx}}}$ ~~~xxxzzzvvv~~~yyyzzz~~~|||  " }}} - -|||{{{|||}}}{{{{{{|||}}}ppp{{{tttlllkkkpppqqqpppppphhhbbbbbbnnnnnn^^^ZZZVVVZZZYYYUUUQQQPPPTTTNNNYYYWWWZZZVVVfff[[[___]]]]]]mmmTTTWWWWWWZZZUUUSSSVVVWWWXXXQQQUUUuuuTTTNNNGGGFFFEEEAAAFFFDDDIII^^^```YYYeeeJJJUUUddd<<<888CCCGGG888...,,,...)))...222)))***)))---++++++***)))+++///%%%000///888+++%%%***'''%%%$$$!!!$$$"""###)))###!!!"""(((""")))''')))"""###&&&,,,222777EEEAAA;;;@@@999444***((()))((('''+++999JJJ555444:::999<<>>EEE???DDDBBBAAABBBCCCLLL???GGGBBBEEEJJJDDDKKKRRRLLLVVV[[[fffeeelllaaarrrzzzMgyyy~~~ ppp}}}(mmmmmmuuuwwwwww{{{"zzzpppsssooouuutttxxx~~~}}}{{{}}} }}}  yyy |||yyy~~~vvv~~~yyyqqqkkkmmm {{{ooo|||aaahhh```{{{dddYYYYYYVVV^^^\\\RRR___WWWRRROOObbbVVV\\\OOOXXXaaahhhkkk___VVV[[[nnn^^^^^^[[[XXXVVVYYYUUUaaagggwwwoooZZZFFFIIIDDDGGGGGGWWWQQQSSSMMMEEEGGGWWWxxx~~~sssMMMXXXBBB===:::111...---)))...///((('''&&&444WWW000((('''))),,,---+++---...%%%%%%,,,666''',,,,,,!!! """/// !!!$$$%%%%%%<<<666&&&$$$&&&111BBBEEEBBB000(((+++EEE444...(((%%%)))$$$***FFF222666222444777222AAAEEEXXXYYYIIINNN]]]^^^dddTTTOOOOOOQQQIIIOOOCCCEEEAAALLLEEECCCEEE;;;AAAAAADDDUUUCCCEEE<<>>CCCHHHFFFGGGHHH>>>FFFAAA@@@FFFJJJRRRPPPbbbaaammmvvvnnnlllwww"E xxxtttwwwwwwppprrruuuxxxrrrssssss|||zzzvvvsssooo}}}wwwzzz|||~~~}}}{{{~~~ - {{{!{{{vvv{{{zzztttkkkuuusssnnnuuunnnddd___^^^```oooWWW]]]^^^\\\\\\WWWXXXUUUMMMRRRQQQSSSeeeZZZTTTZZZ___ggg^^^eeeaaa]]]\\\WWWXXX```]]][[[WWWSSSSSSaaa*bbbHHHGGGMMMEEE[[[@@@MMM\\\NNNLLLIII@@@YYYBBB<<<:::<<<222555888888;;;///,,,///---222))),,,***''')))+++222)))+++,,,,,,***,,,;;;333(((***+++$$$000((((((***---,,,***777######///&&&###"""%%%'''***111999555CCC;;;DDD555<<<555***)))&&&'''...///,,,111222444555;;;555HHHGGGUUUxxxKKKGGGXXX[[[jjjLLLJJJCCCLLLKKKHHHGGGFFFEEE@@@EEEBBBFFF@@@AAAAAAKKKMMM???KKKAAAAAAFFF???FFF???MMMEEEEEE???<<>>===888<<<:::999>>>333,,,+++---)))333))))))'''---444...''''''+++&&&)))''',,,))))))'''000+++"""%%%'''###111333'''))),,,$$$%%%###$$$...999333###222---NNNBBB___qqqBBB///888---...(((###((((((***000333///333111:::999@@@MMMbbbbbb[[[TTTSSSWWWKKKLLLNNNLLLJJJCCCHHHNNNFFFHHHBBB;;;===CCCIIIDDDCCCCCCEEE???DDDVVVCCCAAAFFFDDDJJJ>>>BBB>>>@@@DDD@@@IIIDDDDDDRRRRRRgggfff/xxxrrrkkknnn```jjjkkkaaaeeecccqqqZZZcccmmmrrr -rrrllllllqqquuuqqqxxxxxxpppsss{{{yyyyyy~~~uuuqqq~~~yyyzzz~~~~~~  |||xxx||||||xxxuuunnntttuuuwww tttooorrroooeeesssqqqkkklllgggtttkkkfffbbbcccggg]]]ZZZbbbRRR[[[YYYXXXZZZXXX[[[PPPYYY\\\WWWWWWWWWTTTYYY]]]___[[[aaa[[[RRRTTTjjjXXXXXXVVVQQQMMMLLLHHHYYYVVVKKKEEEDDDCCCIIIVVVFFFIIIJJJVVVbbb___DDDCCC:::===PPP:::222555???444+++,,,...&&&111+++---((('''...)))***%%%'''******---'''===+++TTT///(((---###AAA000(((***444''''''(((222&&& $$$###555$$$###&&&555---___) {{{@@@,,,,,,,,,((("""===$$$@@@:::444666555222;;;999<<>>AAA>>>FFFFFF>>><<>>999LLLBBBBBBEEEMMMhhhYYYPPPKKKNNNRRRTTTdddSSSAAAKKKLLLQQQIIIIIILLLKKKBBBCCCFFFBBBAAAEEE@@@888???BBBBBBFFF???DDDAAAAAAKKKKKKHHHIII===CCCCCCCCCEEENNN```mmm dddbbbrrrnnnaaahhhzzzggg\\\^^^dddeeeZZZRRRXXXbbbhhhmmmnnnnnnpppjjjjjjmmmuuuvvvyyynnnttttttyyyxxxuuu~~~{{{ }}}{{{|||}}}vvvqqqyyy|||uuuwwwxxxrrrrrrooonnnwww|||wwwwwwmmmxxxlllvvviiinnnnnncccfff___bbbaaa[[[bbbeee```^^^^^^ZZZ^^^WWWSSSTTT]]]^^^TTTUUUVVVTTT[[[RRRZZZ\\\WWWTTTSSSQQQUUUUUUXXXaaaYYYUUUXXXUUURRRQQQNNNYYYTTTQQQRRRLLLFFFHHHCCC>>>JJJFFFEEEDDDMMMIIIDDDEEE<<>>======AAA===???@@@BBBEEE999===>>>EEECCC@@@>>>AAATTTKKKPPPWWW___]]]cccdddddd```|||~~~cccjjjkkkgggpppiiiiiiZZZggg\\\aaa\\\```sss~~~vvvvvvgggfff\\\pppxxxqqqsss{{{wwwtttssswwwrrrvvvyyy -~~~wwwqqqsss|||wwwpppmmmiiinnnnnnqqqrrrjjjmmmvvvmmmiiiuuuqqqlllpppdddaaafffccc^^^ZZZ___```ggggggXXX\\\WWWXXXUUUVVVUUUWWWXXXRRRPPPTTTUUUZZZaaa^^^YYYZZZ]]]XXXVVVZZZZZZVVV___```VVVSSSUUUOOOQQQQQQNNNWWWIIIOOOOOOEEEHHHMMMBBBBBBFFFCCCDDD\\\TTTFFFGGG@@@IIIkkkUUU???999999>>>EEE;;;000---111///---///222000'''***000111%%%(((+++'''(((&&&000((('''...TTTPPP000***...+++111222666$$$,,,222 ###!!!PPP%%%!!! !!!'''%%%((( ((($$$!!! !!!"""$$$%%%######&&&222%%%+++...:::999FFF???CCCJJJCCCNNNHHHFFFIIIKKKUUUMMMZZZ\\\PPPNNNPPPVVVSSSKKK;;;888===BBBFFFGGG<<<777:::AAABBBBBBAAA???GGGEEEAAA???@@@???===<<<;;;>>>AAAIIILLLLLLLLLRRRWWWwwwiiiddddddoooggg]]]sssqqqiii^^^RRR```bbb___aaaddd^^^pppuuupppsssjjjfff\\\gggfffrrruuunnn{{{rrrxxxuuuuuupppqqqttt|||||| |||~~~yyyzzz -xxxgggllljjjlllqqqqqqkkktttlllhhhmmmdddaaannnqqqfff```gggYYY___YYYaaa]]]^^^]]]bbbWWWPPPTTTWWWWWWWWWUUUZZZTTTUUUTTTUUUWWWYYY|||]]]lllSSSddd___\\\WWWWWWZZZXXXaaaaaaZZZVVV```TTTPPPNNNLLLIIIPPPRRRDDD>>>;;;BBB???>>>EEEFFF___OOONNNPPP<<<>>>AAACCC@@@AAA999///>>>555@@@///333???+++...(((''',,,111''''''+++,,,'''***((((((&&&444$$$111))))))(((***###***111&&&%%%(((222555///###(((+++###$$$!!!!!!!!!$$$"""&&&"""222 !!! """(((!!!%%%---((()))+++,,,000444333;;;DDDXXXFFFPPPDDDHHHMMMKKKNNNQQQXXX```hhheeeWWWccceeeJJJ888666<<>>>>>;;;???@@@@@@@@@EEEGGG>>>@@@???DDDDDD@@@???GGGDDDCCCDDDEEEEEELLLOOO[[[,gggpppaaadddccc___jjjuuucccRRRRRRlllggghhhbbbiiinnnpppeeebbbqqq___YYYfffdddxxxppprrrvvvxxxxxxqqqtttuuuqqqwww}}}  ~~~xxxtttqqqssstttvvvkkkgggnnnqqqrrrmmm{{{sssmmmrrrrrruuu|||mmm```^^^gggqqq___ZZZYYYcccZZZ^^^[[[\\\SSSWWW\\\SSSVVV]]]XXXZZZ^^^```hhh^^^WWWPPPWWWVVVRRRYYY^^^YYYfff[[[QQQVVVZZZ\\\]]]ZZZRRRSSSSSSYYYKKKKKKHHHCCCDDD@@@CCCBBB>>>===CCCKKKQQQNNNAAA???GGG<<<888888888333888555222+++---...,,,...000+++222AAA222000'''555(((,,,---%%%)))&&&$$$###!!!+++%%%222)))%%%'''$$$###''')))&&&***000---333(((,,,"""!!!""")))333 !!!)))$$$+++!!!!!!""" (((%%%)))***+++)))&&&(((,,,CCC+++;;;<<<666444555888:::CCCEEEMMMBBBKKKVVVXXXYYYvvveeeqqqxxxYYY:::777KKK888777BBBPPP@@@;;;@@@@@@===BBB???;;;CCCIIICCC@@@???DDD???CCC??????AAA>>>AAAFFFKKKXXXddddddhhh[[[ZZZaaa___eeedddeee[[[^^^kkk -mmmrrrppptttiiiuuuyyyqqqoooeee[[[```______eeeppp -nnnpppoooqqqtttqqqwwwttt ppppppnnnmmm}}}nnnqqqjjjlllbbbfff___gggjjjrrryyyxxxeee{{{wwwhhhdddooo^^^kkkccc___fff```___zzzccc\\\eee[[[UUU[[[\\\bbb\\\XXX]]][[[\\\]]]XXXTTT^^^ZZZUUUYYYZZZ\\\YYYYYYYYYYYYVVVZZZTTT___TTTOOOLLLJJJMMMAAA@@@NNN;;;666FFFFFFBBBBBBAAAAAA777;;;222:::999...///000,,,333222222///---------,,,...---...AAA222---((("""$$$------%%%&&&111(((!!! &&&)))&&&''''''+++%%%###)))+++///(((&&&$$$"""/// %%%!!!"""###$$$$$$UUU~~~%%% !!!###"""$$$%%%###''',,,...222888FFFAAA111///777>>>CCCBBBCCCGGGIIIPPPqqqiiibbbgggnnniiiDDD777555666333;;;IIIFFFAAA>>>;;;;;;AAA???:::DDDDDD===888777BBBAAA???EEELLL@@@HHHDDDFFFPPPPPPQQQ___RRRVVVbbb___```hhhooodddfffeeeeeegggyyykkkhhhfffaaaqqqrrrqqqdddiiippp___ZZZ[[[cccmmmooolllmmm#xxxmmmuuu{{{ooozzzxxxrrruuupppvvviiifffkkkmmmjjjjjjaaa```hhheee```ccchhhfff^^^TTT```iiiaaa______]]]aaahhhtttbbbbbbcccmmmfffkkkggg^^^\\\\\\]]]WWWXXXYYY]]]\\\]]]QQQRRRMMMTTTnnn]]]^^^dddeee^^^\\\[[[aaaYYYWWWTTTRRRMMMJJJGGGBBB@@@<<<<<<===<<>>???EEEaaaCCCHHHLLLGGGeeebbbdddjjjaaaSSS^^^qqqJJJBBB999999///;;;FFF@@@AAA@@@:::999@@@;;;???<<<<<<>>>>>>999;;;CCCCCCEEERRR;;;===DDDBBBFFFRRRNNNTTTPPPWWWcccddd\\\fffpppiiieeefffcccXXXSSSgggppppppbbbhhhZZZgggiiiggg```ddddddwwwjjjcccmmmeeefffkkkvvvmmmpppgggrrrnnnyyyssssssmmmbbbeeemmmgggjjj~~~nnn```fff^^^iiidddbbbUUUgggaaaXXX___WWWggg```ZZZ^^^SSS[[[YYY[[[```qqqdddVVVXXXWWW^^^aaa___ZZZZZZ]]]YYYYYYZZZZZZ\\\\\\\\\YYYRRRTTTWWWVVVYYY\\\[[[aaahhh\\\WWW[[[]]]\\\OOOMMMFFFHHHIIIGGG999>>>777;;;777;;;:::;;;___aaa>>>222777;;;666888666666222111111111---222...***+++...'''///***333...(((666(((###+++222000+++&&&&&&$$$$$$'''###$$$$$$'''+++))),,,:::AAA///---(((---777'''$$$...!!!***###!!!""")))FFF$$$ ### %%%%%%...'''$$$,,,222777555666555===???<<>>BBB:::888<<<<<<===@@@>>>555>>>>>>EEEEEECCC@@@<<>>AAAAAAEEEKKKWWWSSSTTTYYY" ]]]fffnnnbbbaaadddttt___\\\bbbeeessshhhggg qqqgggpppZZZpppkkkhhhnnnhhhpppffffff^^^dddnnnnnnmmmiii\\\aaaiiilllhhhiiihhhlllfffrrrbbbgggkkkccc]]]^^^YYYUUUXXX\\\fffaaafff[[[XXXXXXSSSTTTXXXcccaaaaaabbbWWWWWWVVVVVVXXXWWW\\\aaaWWW```]]]UUUUUUMMMSSSRRRSSSOOOVVVTTTWWWUUUVVVaaaYYY]]]lllaaa]]]WWWTTTRRRMMMKKKDDDEEEIII___>>>BBB;;;===;;;===BBB666FFF???JJJ:::999;;;888555///000666444000111+++***+++***.........***%%%&&&(((...FFF(((%%%(((---+++***&&&(((((()))'''((($$$(((;;;***(((IIIPPP###((((((JJJ444777%%%'''!!!'''&&&((($$$$$$***$$$###(((!!!%%%%%%$$$((($$$(((444333222666AAA999???JJJ999CCCEEESSSJJJRRRNNNPPPWWW\\\XXXVVVNNNQQQSSSDDD999555666;;;888EEEcccDDD@@@444:::<<<<<<>>>666@@@@@@>>>@@@FFFCCCAAA???EEE===CCC???CCCIIIMMMQQQ\\\SSSjjjbbbWWWXXX[[[cccbbbhhhaaaddd^^^eeedddiiikkkiiirrr3lllaaagggqqqllliiiqqqllliiiiiiZZZ```dddfff{{{ZZZ^^^fff^^^lllfffdddccczzzjjjdddbbbmmmhhhjjjlllccc___gggddd```___ZZZ]]]TTTVVV\\\YYY]]]RRRUUUWWWWWW[[[___aaaZZZXXXTTTYYY]]]YYYaaaYYYcccsss^^^]]]\\\YYYXXXXXX\\\___]]]YYYTTTVVV\\\\\\^^^ddd\\\\\\YYYUUUUUUNNNHHHEEEDDDBBBBBBFFFLLL<<<<<<;;;:::======KKK???:::<<>>888FFFAAA@@@EEEEEEMMMPPPJJJUUUlllUUULLLQQQGGGJJJLLLFFFQQQDDDEEE;;;666777;;;QQQ@@@===;;;<<>>;;;:::<<>>>>>888777888RRRAAA444???AAACCC<<<777444777...)))(((...%%%---///******------***)))$$$!!!$$$+++***,,,,,,000((()))(((''')))$$$''')))...000111000***((($$$%%%'''///((((((+++&&&999%%%$$$%%%&&& '''!!!'''!!! """  %%% ###%%%---555111---///333@@@III===>>>OOO<<>>>>>AAADDDAAAAAAGGG>>><<<555777999;;;???BBB@@@DDD999CCCHHHJJJIIIOOONNNGGGJJJOOOYYYxxxbbb[[[\\\```aaaggg``````[[[ccchhheeerrrvvvoookkkqqqgggllllllnnn|||QQQWWW```aaa______[[[```]]]ccc^^^^^^fff___fffjjjsssmmmiiivvvnnntttbbbXXXYYYZZZXXXUUUaaaeee```YYYUUUSSS[[[XXX^^^ppplllqqqeeecccaaa___bbbaaaYYY[[[]]][[[YYYWWW___mmmiii^^^jjjaaa[[[\\\ccc```ccc___UUUUUUWWWPPPMMMSSSLLLMMMNNNNNNNNNEEE===<<<<<>>DDDEEEaaaEEEAAAQQQUUUKKKNNNJJJOOO[[[\\\WWW^^^ZZZ___fffhhhfffVVVaaa```mmmjjjdddooohhhnnnmmmhhhnnnjjjgggiii______[[[WWWffftttfffTTTWWWhhh\\\^^^dddkkkeeehhhfffvvvppp}}}yyyfffeeeaaaVVV[[[YYY\\\UUUqqq^^^iiiVVVXXXXXXdddYYYaaapppuuuzzzhhhlllfffeeeiii\\\dddddd```nnnZZZbbbkkkiii``` hhh^^^aaa[[[```[[[eee```YYYVVVTTTOOOHHHLLLTTTOOONNNVVVJJJCCCBBBDDDCCC<<<===EEE???888999>>>AAA@@@???666BBB666666222777111///******,,,,,,+++...111------++++++'''***&&&)))+++)))&&&...---$$$$$$,,,'''111+++***(((&&&(((,,,;;;777555(((111"""111+++%%%&&&%%%  &&& 000111000!!! ###%%%"""$$$&&&'''(((000------777111???^^^999@@@MMMBBB@@@???OOO>>>???III```jjj^^^HHHBBBHHHHHHGGGAAAKKKNNNOOODDDKKK___:::444555>>>>>>777???777888888444>>>:::888:::===CCCLLL666<<>>555<<>>AAA===BBB>>>:::;;;AAA===999444;;;<<<777:::777777666111...///111...555)))000+++((($$$''''''%%%%%%---222---)))((()))'''%%%###"""###%%%...(((***+++NNN333,,,+++(((,,,'''###&&&$$$,,,...===HHH!!!%%%!!!###***''' !!! ((()))''''''222222777;;;:::<<>>777>>>@@@@@@GGGEEEOOOMMM\\\MMMQQQHHHWWWTTTWWWYYY[[[VVVbbbZZZ^^^ZZZZZZ[[[LLLeeeeeeeeekkkdddhhhrrrpppZZZdddkkkhhhjjj^^^\\\eeeWWWTTT\\\aaa_________QQQ[[[ZZZ[[[[[[]]]aaaZZZkkkbbbWWWYYY]]]ZZZTTTVVV```[[[bbbggg```]]]```eee^^^^^^```\\\\\\[[[[[[]]]```aaa```dddjjjdddccc```ddd\\\nnndddaaaaaa^^^aaa^^^eeeXXXYYYVVVVVVNNNLLLMMMUUURRRLLLVVVLLLQQQEEE???CCCDDDAAADDD:::<<<<<<;;;444777<<<:::EEEDDD666333222555333333222///222666---111---)))(((000111222+++,,,$$$$$$((()))+++***%%%'''"""&&&)))333777***'''***444...$$$)))---(((***$$$***'''QQQCCC"""###(((!!!PPP !!!  ###&&&"""((((((---111777777CCCEEEBBBFFF<<>>===??????DDDAAAKKKMMM:::222666999333444666999===<<<===???;;;<<<;;;:::===@@@<<>>IIIBBBFFFCCCHHHHHHDDDEEE;;;777CCClllbbb666222AAA444888888;;;555888555888:::CCCRRR======DDD>>>AAACCCIIIIIISSSHHHAAAHHH@@@GGGCCCCCCLLLKKKKKKRRRWWW^^^qqq]]]]]]yyy```mmm]]]fffbbbfffbbb[[[UUU[[[TTT^^^aaaaaaaaa]]]ZZZccc``````PPPPPPTTTYYYmmmxxxuuulll```nnnccc___[[[ZZZ^^^___eeefff]]]ddddddddd```dddeeebbb___ccc___aaaZZZggggggaaaaaa]]][[[[[[jjjfff^^^\\\\\\]]]```aaa^^^ZZZYYYUUUVVV]]]fffxxxWWWQQQNNNMMMOOOdddwwwVVVYYYbbbFFFGGGJJJFFF???AAA>>>EEE===>>>>>>888<<<;;;<<<<<<<<>><<<999<<<@@@===;;;<<>>??????AAA___SSSIIIPPPFFFCCCDDDSSSCCCCCCHHHEEEJJJKKKUUUVVVTTTTTT]]]aaaiii___bbb\\\fffbbb\\\______fffeeeiiiaaaYYYPPPQQQZZZ]]][[[___bbbtttpppsss~~~uuuuuujjjfffbbbjjj{{{kkkcccddd]]]______eee```^^^cccbbbkkkeeegggfffeee___]]]fffbbb[[[iiiggggggjjj\\\YYY\\\XXX^^^VVVYYYaaaWWWVVVcccZZZUUUWWWMMMRRRLLLJJJLLLGGGKKKPPPVVVQQQSSSTTT===JJJGGGPPPTTT```GGGLLLEEEJJJJJJBBB<<<>>><<>>CCCBBB;;;BBBIIIHHHEEEKKKAAACCCaaa@@@EEEBBBDDDBBBPPPNNNNNNTTTXXX\\\```WWW___]]]^^^ccc^^^^^^eee]]]^^^pppmmmjjjaaa]]]^^^___YYYaaa\\\VVViiioooeeettt xxx -}}}uuuiiiccccccaaagggfffbbb___ddd___^^^bbbhhh{{{mmmbbbeee^^^bbbaaabbblllaaakkkZZZZZZ```UUU]]]]]]WWWVVVYYYWWWUUUQQQPPPJJJPPPHHHJJJMMMJJJIIIHHHKKKJJJKKKAAAGGGEEEbbbZZZWWWaaarrrPPPdddnnnBBB===???<<<<<<;;;;;;AAA,,,111...***333666333//////---+++000&&&---000222+++)))$$$&&&)))&&&'''((($$$+++,,,(((,,,(((...(((,,,'''+++%%%'''$$$""" ''')))&&&!!!+++""" ######+++---///  %%%!!! """%%%,,,///+++...555999555:::AAA===CCCEEEEEEJJJGGG@@@AAATTTAAABBB===BBB>>>:::999<<<:::<<<:::;;;888999555---,,,...555888888444222222999999:::===:::<<<777HHHIII888555:::FFFAAA===@@@MMM>>>FFFKKKIIICCCEEECCCKKKbbbXXXMMMXXXZZZVVVZZZZZZaaaXXXZZZ______XXXXXXkkkfff]]]\\\```hhh^^^hhhjjjdddfffccciii}}}$zzzvvvlllccc|||uuuooohhhfff______\\\___fffkkkccceee^^^lllaaa```]]]bbbmmmhhhfff^^^YYYTTT[[[TTTTTTPPPPPPLLLNNNKKKKKKJJJHHHKKKGGGJJJJJJBBBFFFKKKJJJCCCEEE@@@AAALLLDDDNNNfff-?fffRRRDDD===;;;777<<<666999777???555222111222111666333...777111===000***,,,---)))''''''$$$&&&###$$$(((++++++,,,&&&///***000,,,)))---)))666###'''))) ***%%%***$$$$$$ %%%///!!!"""000 ,,,)))!!!!!!"""%%%***+++,,,333111444555EEE???AAA>>>JJJCCC???CCCAAABBBAAACCCGGG>>>>>>:::;;;<<<999666===999;;;:::===UUU;;;333+++777444333111555777:::III888;;;<<<555999999@@@999888@@@>>>III:::EEECCC>>>FFFDDD@@@@@@GGGFFFfffttt^^^VVVVVVUUURRRZZZUUU[[[WWW^^^XXXZZZZZZYYYUUUiii___\\\___WWW\\\aaaXXX```eeebbbfffsssuuuvvv:@)2zzznnnlllmmm```___```]]]]]]VVVbbbddd```aaaZZZdddXXXjjjmmmkkkaaa^^^aaaMMMZZZSSSQQQNNNTTTRRRcccLLLGGGJJJIIIHHHHHHIIIGGGKKKDDDOOOJJJAAADDDNNNBBB;;;BBBKKKHHHSSS dddRRRFFFCCC:::888;;;::::::999222666???333:::333,,,444888FFF---,,,111&&&,,,+++'''***!!!'''$$$$$$ ))))))///'''///999///555***%%%***(((***$$$((('''"""'''&&&$$$&&&%%% &&&222 !!!  ###$$$###+++111,,,000AAAEEE???FFF>>>AAA===:::III;;;DDDAAAGGGDDD@@@CCC@@@???EEECCC:::===@@@888888FFF888777AAAPPPDDD444888///777>>>:::<<<@@@;;;:::???999777999DDD;;;FFFDDDEEECCC===GGGCCC>>>LLLMMMHHHNNNBBBlll```SSSOOOTTTKKKOOOPPPSSSRRRRRRUUUSSSSSS\\\ZZZ]]]___ZZZWWWaaa___VVVZZZXXXZZZ^^^YYYffffffooo -~~~hhh}}}wwwvvvvvvrrr fffUUUaaaWWWXXXXXXbbbdddUUUYYYWWWWWW[[[TTTOOOWWW```^^^sssmmmYYYXXXUUUNNNSSSKKKIIINNNGGGIIIFFFKKKOOODDDGGGDDDCCCCCCGGGLLLMMMJJJEEEHHHMMMIIIJJJ>>>DDDFFFKKKDDD^^^___QQQCCCGGG>>>???888:::???:::@@@fff111>>>666444MMM>>>555333222,,,)))+++%%%***444000888"""&&&&&&###$$$((()))+++PPP222...))),,,+++---''')))+++***$$$&&&&&&!!!###%%%((('''!!!""" $$$### &&& $$$***///222---555999:::999GGGFFFAAA>>><<<@@@;;;AAAGGGCCCGGGIII===;;;FFFAAA===<<<;;;:::;;;===XXX444CCCKKK999<<<222333555888;;;888555777666===>>>666===IIIDDD<<<:::@@@??????AAABBB@@@BBBGGGIIINNNKKK[[[FFFMMMDDDHHHEEEJJJFFFJJJIIIYYYVVVPPPPPPPPPkkk]]]VVVWWWUUUXXXYYYVVVTTTVVVVVVXXXXXX\\\fffccc___uuunnncccmmmcccooo|||jjjooohhhlll```SSSVVV[[[^^^RRRZZZYYY\\\VVVRRRPPP```XXXYYYXXXXXXXXXUUU___VVVSSSTTTJJJIIIFFFLLLPPPPPPJJJEEEDDDHHHFFFPPPGGG@@@GGGNNNFFFVVVWWWJJJ]]]NNNDDDCCCBBB>>>CCCAAADDDFFFPPPGGGCCCEEECCC@@@===BBB>>><<>>666BBBIII>>>===555>>>AAA<<>>999DDD>>>EEEEEEAAA;;;;;;666999;;;555???333:::---999111444222///333888888444555888===;;;888;;;::::::999888>>>FFFJJJ===AAABBBGGG???EEEJJJ___jjjUUUCCCJJJAAABBBMMMLLLPPPKKKHHHVVVSSS```SSSQQQYYYPPPXXXMMMSSSZZZVVVXXXWWWUUUSSS^^^^^^bbbeeeXXXYYYYYYWWW^^^cccnnnccciii```\\\]]]bbbXXXXXXZZZTTTZZZQQQPPPWWWTTTgggZZZTTTVVVSSSRRRNNNNNNNNNUUUTTTPPPPPPIIIIIIIIIGGGOOOJJJGGGEEEMMMHHHWWWFFFGGGEEEDDDCCCJJJcccgggiiigggRRRZZZCCC@@@KKKCCCDDD<<>>BBB:::888LLLJJJAAAOOONNN777111...---333///555444///)))>>>888;;;888---333,,,)))---111222******111333---***'''***222,,,%%%000&&&'''???TTT$$$"""%%%((()))""""""!!!444 ### """&&&&&&((($$$)))$$$)))---///888222666;;;CCC===777;;;>>>EEEEEEFFFMMMBBB???>>>CCC999FFF@@@;;;999999======EEE777===999;;;<<<111:::000777:::888222666777888>>>>>><<<@@@;;;CCC===<<>>EEE<<<:::EEE???<<<999:::===999<<<999666BBBUUU<<<666999CCC000+++555333555'''***111***///EEE---)))333***))),,,(((***...,,,,,,000(((***'''***%%%///---%%%&&&$$$&&&...,,,%%%######"""((("""+++::: ### ***'''''''''!!!'''***)))...888666@@@777???>>>BBB>>>EEE>>>AAAAAAIIIJJJBBB___oooAAA@@@888777222999888;;;:::444111555333444111444666;;;666111:::888333;;;>>>>>>AAAFFFGGGGGG>>><<<@@@>>>EEECCCGGGAAA;;;EEEIIIPPPiiiCCC???<<>>FFFBBB;;;===:::999666:::QQQIII666444;;;666AAA555333999000---111BBB333%%%(((111333---...&&&***333******)))###,,,***------...---+++555---%%%,,,+++222444)))+++''':::"""###!!!$$$<<< 555''''''###!!!111$$$$$$###$$$...###+++)))%%%CCC<<<===>>>;;;>>>MMM???CCC===???@@@???===FFFCCC@@@@@@@@@<<<===:::777666888444999222555444555555555999???999///>>>======<<>>BBBEEEJJJUUU???999;;;???===BBBKKKSSSUUUEEENNNKKKFFF@@@BBBEEEIIICCC444;;;888:::<<<555888888>>>999@@@333111999999666KKK222...666000---%%%))))))+++111...'''***111---000,,,---111---...///---111+++,,,((((((333------222111555777777""" 999,,,111!!!### '''###!!!((( $$$ !!!+++***)))###%%%(((***...///<<<111@@@<<<777BBBCCC999;;;GGG???FFFEEEOOOBBB@@@<<>>BBBccc<<<333:::999555777CCCCCCFFFRRReeeXXXNNNSSSEEEBBB===CCC>>>DDDGGG???NNNhhhBBBPPPIII>>>??????>>>===CCCCCCAAAHHHDDDFFFEEEJJJZZZKKKLLLPPPFFFKKKCCCEEETTTmmm#XaaaRRROOOKKKFFFOOOYYYUUUQQQbbbZZZUUUOOOYYYSSSWWWNNNPPPPPPMMMIII@@@CCCCCCDDDFFFJJJLLLFFFEEEIII\\\QQQLLLCCC===???FFFGGG@@@>>><<<>>><<<999@@@???FFFEEEWWWAAAGGG;;;;;;<<>>___@@@<<<:::;;;888;;;333888888999555000333333222222666000@@@555NNN777111,,,+++)))...///000,,,***,,,000888,,,EEE:::222(((---555000)))((((((,,,...666)))"""%%%111111---,,,'''""" 333GGG***"""###"""$$$... ))) """***777***&&&###***((((((===111555777333666;;;777;;;777888777FFFEEEFFFMMM999<<<777999DDDNNN@@@777555666999555666999>>><<<666;;;===<<<111555;;;EEEIIIFFFLLL|||PPP::::::FFFFFF@@@@@@BBBJJJYYYPPPOOOEEE@@@JJJ@@@555666<<<@@@BBBNNNFFFDDDCCCFFFMMMNNNMMMTTTMMMOOONNN@@@LLLwww#yyy[[[GGGEEEKKKFFFMMMGGGJJJOOOMMMQQQXXXZZZQQQSSSJJJHHHDDDKKKGGGFFFDDDDDDEEECCCIIIEEEJJJEEEEEELLLEEEBBBCCCGGG@@@>>>AAA???BBB;;;???999999;;;AAA???>>>GGGDDD<<>>CCCEEEAAA555...888@@@HHH===CCCBBBCCCRRRBBBDDD???KKKBBB:::===BBBEEE@@@:::??????RRRLLL777555AAA???AAADDDDDDAAAAAAIIIIIIIIIFFFJJJ___HHHGGGJJJKKKPPPcccQQQUUUFFFHHHGGGIIIKKKLLLLLLPPPIIINNNNNNYYYNNNOOODDDEEEBBB???CCCDDDGGG@@@???AAABBB@@@AAADDDGGGGGGGGGBBB@@@CCCAAA@@@AAAGGG???@@@???@@@:::777;;;999888;;;HHHBBBIII;;;:::BBB;;;DDDCCCIII???]]]TTTXXX???888HHHKKK@@@:::777888BBBEEE>>>777888999:::???:::333222444...333999CCC888???BBB444...222...+++)));;;---$$$)))(((...CCCNNN@@@000,,,...222000&&&'''***)));;;555((()))KKKKKK111111LLL000999222%%%)))$$$!!!"""...222888111!!!:::###///,,,$$$"""&&&!!!,,,'''+++555&&&...111HHH===555FFF777<<<999???===999AAA;;;@@@BBBBBBIII<<>>IIICCC>>>888@@@GGGUUU;;;;;;;;;::::::AAAEEEFFF000000:::<<<===<<>>>>>CCC>>>999777KKK===???999EEEMMM===PPPIIIMMMGGGBBB444777===@@@CCCOOO<<>>CCC===CCCEEEJJJGGGDDDFFFBBBEEEXXXVVVTTTQQQ___JJJHHHSSSNNNFFFBBB<<<>>>@@@===@@@FFF@@@AAADDDCCC>>>GGGJJJKKKFFFKKKDDD<<>>CCCAAAGGGJJJBBB999@@@777888777999666333BBBAAA>>>444^^^???666666333333777222444111SSS777;;;;;;111+++---)))))))))(((333///+++///---666444111222000+++>>>...///999)))---((()))---'''LLL***,,,///777,,,###"""111(((%%%000$$$###%%%###(((  ###""")))'''###""")))%%%&&&$$$"""%%%+++,,,111111222777JJJ444999<<>>333>>>999777999<<<;;;BBB@@@AAA;;;AAABBB>>>>>>NNNEEEKKKNNNMMMGGGIIIUUUjjjFFFKKK;;;888@@@FFFJJJDDDCCCAAAGGGGGGIIIAAADDD===>>>UUU???OOOEEEAAABBBEEE???DDD???TTT]]]hhh WWWNNN???MMMFFFBBBAAAHHH@@@BBBCCCDDDEEE@@@DDD>>>DDDBBBDDDFFFCCCFFF??????BBB===;;;999???<<<999<<>><<<>>>999<<>>AAA=========TTTEEEIIILLLcccEEE>>>BBB999999???777777888;;;999555;;;555222333333777TTT888222333111000777@@@>>><<<444((()))000000...222FFF333333000///999333111555999:::PPP666222@@@***111((()))###333FFF%%%---######%%%###%%%###)))"""111%%%'''###*** ### $$$$$$777---'''///---+++***111222@@@666<<<@@@@@@===777===999CCCJJJnnn___nnn===GGGAAA777BBB999555AAABBBBBBDDD666444777<<<>>>JJJ???666555333>>>444777<<>>;;;<<<>>>BBBEEEHHHIII@@@IIIVVVCCCIII;;;=========BBBRRRFFF>>>>>>DDD???AAA@@@GGGaaabbb}}}~~~ZZZRRRCCCBBBFFFCCCAAA<<<:::BBBBBB>>>===???<<>>>>>>>>BBB???555<<<:::>>>:::???HHH999999<<<@@@777444444888???BBB???;;;======555BBBEEEEEE;;;===>>>EEE666333999;;;666;;;???555;;;555777222444333===;;;222999555777,,,+++111---111KKK:::,,,+++111555777XXX999EEE333333444111444777999555EEE666000,,,***222888--->>>888444---$$$ """###"""&&&((((((&&&555$$$+++!!!$$$111%%%"""$$$777333,,,......000555888555999444;;;777???999>>>OOOkkkhhhjjjCCC:::666AAA999===>>><<>>???@@@>>>===EEE===@@@<<<<<>>888===555;;;777:::999===;;;===BBB666777;;;???>>>???===>>>@@@FFF===666:::999KKKEEE===>>>DDDHHH;;;999111777666555444555555SSS@@@999333:::///...---JJJ444+++555...555222444444@@@444EEEBBB888///<<>>ZZZBBB999:::888;;;;;;>>>???;;;???>>>OOODDD555===PPP===888999444444444222222888<<<;;;:::<<<===KKKOOOAAABBB???999???>>>>>>JJJ===KKK??????;;;CCC@@@???LLLJJJ???BBB@@@CCCGGGPPPGGG>>>EEE<<<999???:::======<<<======:::AAA@@@QQQ}}}wwwZZZ>>>===BBB@@@>>>???888888<<<999555<<>>:::>>>DDD<<<:::888444333000>>>???999666888888888;;;<<<999;;;555444888;;;111555HHHOOO333111888MMM999AAA<<>>---&&&&&&222---'''***...000333666222000333888888222333III===AAA;;;@@@BBBAAA@@@999999<<<999:::SSSPPPCCC888555000777;;;??????;;;>>><<<444666<<<999???;;;>>>@@@CCCEEEDDD@@@888???BBB<<<>>>999444DDD???===>>>BBBQQQLLL@@@TTTBBB@@@@@@GGGKKKAAAAAA>>>@@@DDD;;;888666HHH===777888>>>???>>>DDD\\\[[[HHHGGG777777>>>999@@@JJJ:::>>>;;;:::===EEE:::NNN<<>>888999<<<===;;;CCC@@@>>>KKKAAABBBCCC===??????::::::???===111777666666666:::999<<<666>>>999<<<:::;;;888111555;;;444===<<>><<>>CCC666333>>>???:::CCC===@@@===888666666:::;;;<<<<<>>CCC:::@@@===HHHNNNDDDEEE???XXXLLL???777:::<<<888CCCMMMZZZKKK>>>IIIUUUVVVDDD@@@>>>bbbAAACCC<<<666888AAAAAABBB?????????777BBB???@@@;;;EEE===:::888:::>>>>>>@@@999:::??????CCC<<<777>>>BBBMMMCCCAAAAAA@@@???GGG>>>===<<<:::???GGGCCC;;;777555666555888333999??????CCC:::999222;;;AAA333777///888777<<>>TTTHHHAAAOOO:::MMM666<<>>KKKBBBGGG===FFFEEE===???<<<>>>???HHH@@@AAArrrJJJPPP777999BBB>>>FFFWWW[[[======QQQ:::888@@@999999;;;EEE>>>===>>>CCCCCC@@@EEEBBB@@@>>>UUU@@@CCC???===:::666888999AAA>>>;;;;;;AAAAAABBB888BBB>>>EEEBBBLLLDDDBBB999FFF???LLLHHHGGG>>>CCC===CCC888===JJJ:::444777<<<...999888>>>;;;CCC444;;;FFF:::555444888<<<:::777111XXXAAA???>>>GGG;;;;;; qqqCCC;;;<<<888333OOOIII666hhhccc888===999444222---333333000888---...444222999@@@666111222___***)))---222---,,,...---***+++"""444111)))$$$(((""">>>???//////222FFF###,,,$$$666&&& !!! 222###%%%""" ###%%%(((&&&''',,,)))...111***222333777---...>>>bbbYYYBBBAAABBB:::>>>;;;:::999;;;BBB777:::@@@888>>>BBB<<<222888===OOO>>>AAA:::CCC999777<<>>DDDJJJGGGEEELLL<<>><<<;;;666777;;;999BBB===;;;DDDAAA@@@NNNJJJ999>>>FFFBBB>>>===444:::<<>><<>>OOO@@@???EEE999CCC999===666888555888>>>PPP???999>>>KKKCCC999<<<:::777666222---===MMM777///666666]]]UUUIII>>>555999777333:::DDD...<<<===@@@000000///+++...---+++///777;;;///000...444...///...---888***///111......333:::222333(((+++'''"""###"""###++++++...''';;;777''')))!!!...''' &&&### <<<$$$%%%!!!!!!###+++ %%%...000...;;;///===222///000<<<:::<<<555???@@@===<<<999;;;===AAA666???:::555<<<:::777aaaCCC999111>>><<<DDDDDD<<>>EEE>>>BBB<<<888HHHCCC???KKKBBB???KKKAAA:::DDD]]]EEEFFF;;;MMMHHHTTTEEECCC999PPPMMMJJJ>>>999777@@@AAA>>>777777999888???:::999:::EEE:::<<<<<>>CCC???>>>???888===>>>@@@@@@HHHDDDHHH>>>:::???AAA<<<;;;::::::<<<<<>>DDD^^^ZZZFFFFFFAAA<<<999888===888777:::999AAAAAA@@@WWW???===:::???777===222NNN999---JJJZZZ333222777555NNNFFF;;;AAA666666:::333666888+++111000444666111:::+++111333111,,,>>>@@@333///...000......000)))***///---222333...333<<<888;;;###&&&'''333&&&$$$(((...***%%%***444...***AAA111""" ### '''$$$'''$$$$$$555)))111111666111...&&&000>>>222---111///***+++111888>>>999888AAA```CCC;;;:::999444111999;;;DDD777AAA<<<::::::KKK===<<<999999999555555>>>AAA>>>OOO>>>@@@HHHAAABBBPPPNNNKKKNNNFFF===RRROOOEEE@@@:::<<<777>>>CCCEEE??????777<<<:::===999AAABBB888666999999<<<>>>999888666AAABBB???999@@@===CCC???LLL@@@<<>>FFF;;;JJJGGG>>><<>>999888;;;999;;;DDD999AAA>>>===999:::FFFJJJGGGHHHLLLIII;;;999;;;???;;;;;;KKKhhhVVV[[[eeeKKK@@@777;;;888@@@666555666777777888555///444---,,,...000:::222111999>>>888777222---...222444@@@888555333===777333000888///222///000(((---111+++//////---666111---///>>>,,,+++???(((***---"""###&&&...888)))444+++&&&999000%%%%%% ---***!!!000***(((%%%''')))GGG;;;666///***666000...+++...333333///>>>333>>>>>>777>>>===>>>HHH<<>>;;;555AAA666000@@@;;;<<<999888;;;;;;___HHHNNNVVVPPPDDDBBBDDDPPPDDDGGGSSS???555@@@:::AAA===999888:::555<<<888======EEE;;;777>>>===999666999;;;DDD<<<;;;NNN;;;===BBBDDDGGGEEE@@@AAA??????@@@;;;@@@???>>>CCCMMMXXXNNN===DDDDDD:::;;;555@@@EEE>>>CCC???AAA666>>>>>>>>>===???MMM[[[BBBJJJ666::::::???BBBUUUNNNNNNZZZbbb^^^HHHBBB999@@@333888<<<;;;777222000888000///333---'''...///333666)))000444111<<<000,,,***===333111+++666777...>>>777777+++555---******...--->>>:::000222///+++===...***333444,,,000)))''' (((+++)))888+++)))(((:::,,,"""---!!!$$$,,,>>>&&&@@@000$$$(((+++///777LLL;;;333111555+++...111333---000555111555555:::;;;;;;:::CCCEEEVVV???888DDDBBBLLL999AAAAAADDDEEE888FFF:::AAALLLqqqdddTTTUUU;;;:::888666;;;===;;;IIIYYYNNNSSSRRRDDDAAA===KKKEEEBBBEEECCC444::::::EEE<<<@@@888JJJ111444666333:::::::::555555444<<<888<<>>CCC;;;888:::@@@===999888777===EEESSSVVVjjjTTTBBB;;;;;;;;;>>>;;;<<>>AAACCCAAALLLgggfff???===FFF999666///555333222555222///...222555111...111000222111...//////>>>+++555999111???222444---...+++---...///...//////***+++555///,,,***(((---333111(((111(((%%%%%%555---''')))$$$$$$888FFFSSS)))&&&''')))---,,,!!!%%%$$$ %%%!!!%%%'''))))))'''...333***---???888...111666///...777333888>>>AAA===>>>AAAFFF>>>:::<<<<<>>IIIFFFOOOAAA555666>>>NNNrrrhhh???>>>???:::555DDD@@@GGGPPP___kkk```GGG<<<666999666888;;;>>>???555999888\\\FFF666:::>>>PPP<<<;;;???:::@@@CCC666666444777???111===444888888@@@>>>???>>>CCC???999777===???:::999999777:::666CCCEEEAAABBB???>>>===;;;===888===???999777;;;DDD@@@@@@<<>>999@@@CCCGGG???___YYYQQQCCC888:::888555444...222777+++///---333888777,,,666000666999555+++///222,,,---...***000111===000---+++888...'''111)))...,,,)))---***,,,&&&&&&&&&'''777))),,,...))))))&&&'''&&&&&&+++"""***///)))555---%%%$$$+++!!!+++###!!!))) ######%%% %%%...,,,''',,,!!!---+++;;;+++222555222999///---222333666777666BBB999QQQ===TTTIII\\\DDDJJJ<<>>AAA>>>___nnn[[[<<<333666CCCdddkkkRRRDDD:::555;;;BBBAAA@@@>>>HHHLLLYYY)!ZZZRRRNNN???999777999FFFJJJ;;;999CCC777AAA???<<<777;;;<<>>;;;<<<999EEEGGG<<<666CCC???===<<<777:::<<>>>>>TTTNNNSSS]]]HHH666EEETTTBBB===CCC<<>>666111111???;;;888;;;444???777555333555:::888:::888888111666===>>>???555<<<@@@@@@>>>===:::>>>:::777777FFFJJJ===888999888///555777:::777666::::::<<>>888DDDGGGIIIMMMKKK@@@???AAA666KKK:::<<>>===777<<<666888444111777;;;<<<:::///:::666333444999777;;;777333222:::===:::777444666555DDDNNN333???<<>>:::888>>>FFFRRR@@@VVV}}}CCC???FFF666???999999;;;:::888333======XXXWWWOOOLLLCCCDDDBBB===777333@@@333>>>...,,,...---000///***...888222333***'''''')))555666---)))+++***,,,...333%%%%%%'''((('''(((,,,&&&&&&---++++++---@@@333888JJJmmmfffDDD;;;999000YYYIII000)))+++***'''###!!!'''444)))"""###&&&222:::333***%%%$$$%%%$$$,,,222$$$***---///(((...///)))555---...333---:::///======AAA@@@999FFF222>>>???@@@GGGCCCIII???======???<<<222222888;;;===BBB888:::???QQQZZZfffooo888TTTCCCkkk___LLLBBB999???===666555999222444111;;;>>>;;;???999;;;???333BBBFFFJJJ555III999444NNN<<<>>>555555666999>>><<<777999::::::;;;777<<<>>>CCC444333666666333000888;;;999888999999444333666666666>>>CCCAAAAAA\\\#EEE===>>>:::IIIHHH777BBBMMM555000:::DDDSSSsssJJJ;;;888333CCC888,,,000...,,,,,,222;;;:::///,,,(((...666111***&&&'''888EEE999444,,,+++000222000***+++((((((((("""((()))000555***888///***---:::DDDIIIiii;C-jjjVVVPPP222333>>>///((('''>>>)))---&&&'''&&&###%%%###   222CCC000222555'''***""" %%%''')))---555777777777111,,,...888000......111111KKK======777???GGGQQQ666;;;BBBHHHRRRAAA===<<<;;;666@@@888===888;;;===333<<<===GGGXXX -uuuFFF:::@@@yyyUUUKKKlll999AAA;;;000444555---,,,000@@@DDDSSS>>>:::999666444===}}}HHH888AAA222555999444222444777:::MMM555777999777555999888444999>>>BBB999:::<<<999555666666777:::333888;;;;;;888999444222555:::@@@FFF<<<<<<[[[hhhNNN@@@>>>@@@<<>>:::444666;;;888@@@999UUUqqqAAA999222222888222444---,,,000---111---///333444---''',,,444...)))000;;;444888222***222222---(((---...---,,,)))$$$+++---666...------;;;555222333;;;FFFwwwK[^^^UUU;;;DDDCCC222111...))) !!!(((((()))@@@000$$$***"""$$$+++$$$HHH,,,&&&&&&***(((&&&***)))$$$&&&%%%---GGG222BBB???000333666555555///444666888999<<<222===;;;888@@@;;;@@@===IIICCCAAA444666999FFFaaaUUUGGG>>>AAABBBNNNBBBHHHHHHXXXCCCMMM<<>><<<999;;;<<>>@@@999333000888999666999;;;333333888:::666???;;;BBB888@@@KKKOOO>>>DDD<<<>>>>>>???KKKHHH:::777666---777444888:::222111888222111///,,,******777666222+++///LLL333:::(((111...,,,///...:::222666555)))...///DDD333***&&&)))***000'''%%%&&&%%%***((()))***...333***///+++JJJ LLLTTTDDD444iii]]]222===444000%%%%%%)))&&&,,,###000***)))!!!###%%%+++"""&&&&&&:::***'''CCCRRR666%%%)))++++++)))///...000444333111333AAA111555888888>>>;;;999;;;===DDD<<<777CCCOOO===999EEECCCBBBeeeDDD===CCCSSSIII```KKKpppTTTUUUOOOHHHJJJ555333222333999;;;888888333777111<<<666<<>><<<555555AAA999======DDDoooIII222555555222666333555555666444333555888333777888CCC777555888::::::444??????<<<;;;;;;777999666222111777888444888111444:::///,,,***+++666---///333***)))+++111555;;;555111---...---333///)))@@@666222@@@...;;;333)))&&&(((&&&,,,,,,+++)))'''GGG)))###(((///777;;;)))%%%)))OOO___999III222333222888///@@@===+++444AAA$$$111???$$$***$$$'''444""")))"""...(((,,,333+++!!!###,,,,,,***)))&&&***AAA...,,,***???000333777666888444EEE:::666999DDDCCC<<>>:::666444888444666GGG===888222333666555222<<<999>>>???111666HHHEEEEEE;;;:::999333555000///666888555===444888666555:::666888///666;;;<<<666888@@@AAA333222AAA666555333===444777111222444000...///+++333<<<444222000222---222444000III333,,,222...((((((...444...(((...777444'''666&&&"""&&&'''666***,,,333))),,,'''(((111444888......(((555(((------777444333...,,,333111(((&&&;;;,,,111222???+++###&&&)))((($$$ !!!"""!!!)))111000333KKK---!!!###...(((,,,&&&///888>>>...---+++000---///222777;;;999ccc666111;;;NNNBBB>>>\\\DDD<<>>777LLLPPP;;;======:::666666:::CCC999777444aaa<<<@@@:::>>>@@@777333444666999777DDD<<<444444888666555555222000999777???:::444666777888<<<777555666:::PPP777555CCCEEE;;;;;;555DDD111,,,666777555AAA...888@@@222444555444///666000111888,,,444888777111777...,,,...,,,(((///------,,,000111+++'''&&&&&&,,,&&&&&&(((((()))'''$$$))))))(((***...,,,222777777;;;000!!!666555333000222000///000777...555---'''***+++//////666DDD$$$"""###&&&GGG,,,BBB222 !!!"""%%%&&& $$$>>>666555++++++(((...;;;777///444777444>>>111666333III;;;;;;???<<<777;;;MMMRRR???FFFAAA<<<<<<<<>>???000666;;;???555888111333111333999666333222666666555666666777444666;;;]]]<<<555222777999777:::999777>>>CCC===DDD777999~~~___>>>===:::555:::@@@CCCBBB999444...111444<<<---))))))@@@000222;;;BBBAAA000CCC......555666EEE///---333222+++&&&&&&000)))222+++&&&)))$$$'''///''')))///000+++,,,)))(((333QQQ)))222333DDD,,,'''///888:::XXXSSSWWW999LLLXXX...******)))000'''!!!"""!!!222$$$###---'''++++++!!!---$$$%%%&&&$$$###,,,444)))%%%,,,,,,+++(((555///222;;;555444000555333???DDD888___;;;BBB;;;===>>>MMM@@@AAARRRTTTFFFcccyyy-9MaaaiiiwwwRRREEEIIINNNaaaRRR111666999:::555777999CCCLLL555666```>>>;;;000,,,444444BBB:::PPPyyy;;;BBBBBB>>>>>>EEE666;;;444555===555///333<<<<<<555999555444222///555555222666===???HHHGGGDDD555444222???111555777333666:::<<<444999DDD666MMM777;;;MMMQQQ:::666:::666888444XXX777>>>===555111...---///111)))444%%%)))...///...000///***...;;;333:::444///555777999+++&&&)))***...222$$$---$$$222HHH---(((000777555...666888'''(((,,,888***''' (((+++,,,EEEbbbMMM::::::666BBB---///)))+++((('''   ###(((######"""&&&"""!!!$$$%%%***%%%&&&...111AAA&&&'''''',,,222222333444@@@999LLL///;;;;;;555888666999BBBDDD@@@???EEE===<<<999;;;;;;AAAbbb ]]]dddYYYyyynnnRRRUUUccc\\\RRR\\\NNNLLL???999:::<<<666555888;;;222555888;;;bbbCCC777777---444888<<<@@@%WWW666>>>UUU===222///555:::BBB<<<999<<<;;;888===999555777777;;;777:::555555777888===RRR]]]DDD555000555???>>>666000444<<<555777:::999;;;OOO555999777:::CCC---:::444;;;;;;666444UUUBBB\\\OOO444000333)))111222...999222+++222//////+++555...---888555,,,...HHH666===777///+++333...""";;;111***(((***)))111555555KKKAAA555RRR333111+++&&&!!!+++%%%...(((111888111+++,,,111333AAA111'''&&&+++999''' &&&666 )))###000---$$$$$$,,,)))###&&&''')))III,,,)))((($$$***!!!&&&000,,,***111222000555777555999999333888999===>>>CCC999666III999<<<555888???>>>888DDDLLLPPPOOOQQQVVVUUUKKKYYYXXXSSSMMMXXXTTT333===:::333<<<<<>>888@@@jjjTTTSSS888???;;;BBBAAA:::???777222555>>>\\\===666999999666EEEFFF555555555===CCC<<<:::CCCHHH]]]OOO<<<<<>>---'''333///000///222,,,000111'''$$$''''''+++***,,,)))111KKK===VVVUUUDDD555+++444666QQQ111'''$$$###888444++++++""")))JJJ++++++---$$$)))!!!(((PPP"""$$$"""!!!)))&&&(((...'''%%%&&&$$$((('''"""$$$$$$$$$((("""%%%))),,,(((666???JJJ888...222555222===888666222000:::@@@999@@@<<<888DDD444FFFFFF>>>===GGG???dddIIIHHHJJJZZZUUUQQQYYYtttYYYPPP___???FFFPPP888;;;999JJJ;;;777333000LLL111000333555;;;444@@@///AAABBBJJJ777666999ZZZGGG<<>>AAA===555000333222999666999===888///777EEE444777555,,,%%%)))888888<<<444???---777444...---...000111333000***,,,,,,---(((111333ccc---111;;;555///222888:::111666:::777222666***222'''$$$***///,,,,,,666;;;ZZZLLLPPPeeeFFF777...===>>>...,,,HHH***:::***((()))***"""###KKK!!!,,,<<<******$$$ ---:::$$$"""&&&###%%%;;; ...((($$$###***%%%$$$***///$$$%%%***%%%$$$+++***333999...333---...444666...444+++999@@@222444;;;BBB???888555CCC??????>>>===CCCTTTGGG;;;>>>CCCBBBGGGMMMTTTsssmmmTTTMMMKKK;;;444333777===AAABBB777,,,888111,,,...===???333;;;555777:::>>>:::DDD<<>>777999;;;OOOGGG000555???999555666999666===MMMDDDAAA;;;999777777<<<555888888@@@===444444444777222777...111///000444777;;;iii333555:::333444444777000777000111///777222111111222,,,,,,555222>>>:::222222///---222...333999JJJ\\\kkkDDD;;;333///777***%%%''')))$$$'''&&&111...///:::ZZZ:::???rrrUUUWWWRRRggg%%%&&&+++111+++MMM,,,***LLLBBB>>><<<%%%(((---...%%%###!!!'''!!!###(((!!!###"""!!!+++$$$(((+++%%%"""%%%&&&%%%***888&&&++++++,,,111,,,+++333333...333555000///000999444///000:::666999333;;;222888999???AAAGGG]]]EEESSSEEE@@@???EEE@@@EEE[[[\\\JJJ222222666444999444@@@]]]555555;;;555555333222;;;444222222666333333333222<<<>>>@@@777<<<777<<<<<<<<<555:::111333>>>>>>888888???SSSOOOVVVUUUPPPlll;;;FFF>>>>>>777333333<<<;;;222888555777000:::444111555111666AAA???QQQ555444???111111;;;888000OOO...---+++555222---///111333...555>>>???GGGAAA000+++222@@@@@@GGGK.eeeKKKAAA444111+++000'''+++)))###+++AAA111111QQQ QQQ999222OOOAAA:::;;;///<<<000---+++000***===+++666888+++...,,,)))$$$SSS ,,,!!! 888###"""---777...---111444%%%$$$###""" ###$$$"""'''222(((***+++---((()))''',,,000...222,,,666222222:::777......444111222444888333111;;;;;;BBBGGGYYY^^^OOO@@@JJJLLL999BBBNNNLLLNNN```VVVLLL<<<000777:::;;;999BBBFFF888FFF---111222;;;999666888777444777222000777777666555999555999;;;555999666444444:::CCC999<<<999999FFFSSSPPPbbblll___JJJCCCCCCAAA<<<666444222000666666555222444///333000***111222000666AAA888PPP//////444222...000...+++))),,,)))---FFF,,,&&&:::666666555888<<<999SSS;;;...***,,,===jjjvvvD&^^^SSS:::,,,111(((---;;;555'''&&&###;;;333CCC999DDD<<<000)))222+++444)))(((---((()))'''AAA***444'''+++...222;;;222555!!!!!! 000"""  ###"""&&&((( ###999777,,,555---%%%!!!$$$$$$***,,,...555,,,&&&,,,111---222...111)))---...//////777444...111222333///333:::333:::999:::BBBVVVKKKHHHWWWGGGOOOFFF:::;;;888BBBDDD^^^AAAZZZ===333555222:::666888MMM<<<===444000...<<<333555???CCC;;;444222555333888444111555///999HHHDDD777000333:::FFFjjjDDD???AAA@@@???CCCZZZzzzwwwpppLLLLLLAAA666777666555333000333OOO222777666333222444222:::777333>>>222444999666888555:::---888666///))),,,333,,,+++---333...111;;;,,,888:::;;;===...(((---QQQKKKzzzssskkkfffYYYGGG>>>***---###'''888$$$%%%>>>...///111:::EEE;;;:::)))---333111***%%%+++&&&"""+++---888%%%,,,OOO...>>><<<:::000''' """"""'''!!!+++$$$>>>$$$+++ $$$(((???,,, ###$$$$$$)))III***(((666---+++***...---((($$$&&&+++,,,333>>>CCC,,,111333444000999,,,111:::;;;333777III;;;HHHkkklllGGGJJJKKK:::888888BBBGGG555FFF888000777999<<<777333000666:::///666===666777555888444???222444???<<>>:::OOOccc;vvvkkkLLLAAA444777777444666222888,,,444888111444777555>>>;;;AAA777555111111AAA===CCC333666111111...(((...888)))***333111((())))))666:::UUUggg444111888...+++>>>@@@LLLOOOOOOWWW]]]JJJ>>>'''))) """%%%$$$ &&&***)))555...bbbPPP***EEE'111***)))(((%%%###DDD000'''$$$???777III,,,///JJJ///555%%%  222///"""KKK%%%444!!!***!!!%%%'''''''''###***AAA%%%,,,111+++(((000555222'''***(((***,,,---///aaa666111111444...888000222666999333444CCC666===IIIXXXOOOoooGGGEEEBBB666...###)))---::::::555555000000555222666:::777FFF;;;222BBBAAA///333AAA444777===>>>TTT===>>>555555555555>>>???111;;;===???666555<<>>444888@@@___<<<222666111HHH888;;;333555222:::)))222000///111***(((222DDDHHH,,,DDD333'''///---999MMM___aaaRRRIII@@@999---&&&"""%%%%%%...)))+++''''''(((%%%111^^^))),,,FFF///111"""$$$)))&&&999***%%%<<<"""555===###222000***$$$$$$$$$!!!""""""%%%333---###***&&&###!!!"""#########&&&%%%(((%%%+++(((---,,,EEE888,,,+++***---//////333444444+++,,,666///CCC///,,,444333666---111999:::XXXEEEUUUIIIMMMOOOIII::::::'''$$$...000999222///555)))///333;;;111888:::888999000333555333222:::000888777888???;;;777888;;;???555OOOAAA<<<555LLL===333<<>>:::---BBB***333DDD===...///,,,...///---:::,,,@@@>>>++++++333---+++///***------CCC>>>JJJ===222666111***)))&&&&&&$$$ *** ###(((""" '''&&&%%%///###%%%... ###((('''%%%&&&(((((("""%%%000%%%***$$$###&&& &&&***'''!!!...###///333888!!!!!!!!!""" $$$ )))(((...&&&''',,,(((%%%555,,,******---///333(((666111:::///,,,222777///000111333444000CCC555:::LLLTTT@@@777???<<>>222555444888999888555555===999666;;;999666777777555555===BBB;;;666666IIIMMMKKKMMMPPPhhh94.\\\BBBGGG666<<<999;;;111111...444555AAA:::222///===444...888222333000999222///===---///111000111---555222222888555<<<333999000000;;;333333777222444,,,000444///000,,,222666***%%%$$$+++%%%$$$ '''!!!!!!111&&&'''...$$$""""""'''%%%***&&&(((&&&++++++'''DDD///&&&///)))&&&""" $$$222!!!&&&###===FFF888999!!!,,,  '''"""%%%!!! ,,, )))MMM***'''(((&&&)))+++...+++000000***,,,)))...+++333...555444***???000777777333666666999AAA444<<>>999555444:::===777888666AAA999777<<>>...===,,,<<<555CCC333333666888444000)))......///111+++***+++,,,)))((()))$$$+++%%%$$$$$$&&&,,,!!!888!!!!!!(((""""""&&& (((%%%,,,!!!%%%>>>777%%%+++...333((("""### $$$$$$BBB333""" 888###!!!,,,'''###***"""---"""###%%% )))%%%$$$ $$$888+++)))&&&(((000:::BBB+++000444+++444///555111444...222//////555999;;;111222333555666;;;===BBBMMM===777DDD>>>@@@777FFF777DDDNNNLLL777---///......444444///,,,---555222000***888999@@@444999EEEUUU<<<<<>><<<111888888666666444333DDD555111<<<<<>>@@@BBB>>>666333000444000666222444,,,***BBB000GGG///***222///***...--->>>OOOOOO>>>:::HHH999888444222777555DDD666333666,,,000111222888@@@GGG???<<>>111---///111444666222,,,111999444999222111,,,nnn???\\\aaabbbccc:::444---000222...---++++++333---)))***%%%$$$***))))))'''(((((($$$"""***&&&555!!!&&& &&&  ((((((###$$$&&&,,,"""!!! &&&$$$%%% !!! 555GGG[[[555+++(((!!!!!!!!!""",,, ###)))...111'''000...(((222+++...---(((...222KKK@@@---***+++)))555111666222111<<<888HHHMMM>>>999;;;>>>666>>>AAAEEE888666777???ZZZxxx???888444555666666777,,,999///222TTT777333222---777---444000666999444>>>III<<<888>>>777777555555444GGGKKKggg000---333;;;>>>>>>EEE777555;;;<<>>]]]@@@>>>>>>888111JJJzzz888999PPP===CCC999CCCAAA777555222666111******888BBBOOO???000000333111444...,,,+++,,,333222999KKK<<>>666444666:::555~~~eeeFFF333222<<<999===CCC222777888999DDDNNNUUUMMM@@@???;;;CCC333111000444888111777111333444555444///555///222;;;999222///000333444444>>>HHH...444+++111999BBBVVV 3YYY888111000%%%(((222,,,(((///000---444...:::555###VVV***"""###""""""$$$ '''---"""$$$"""'''$$$ !!!000888'''***$$$(((***''''''!!!'''###$$$'''%%%"""''')))333<<>>///)))$$$######%%%+++)))&&&000777---!!!###'''VVV888444***+++'''""")))000777***&&&888,,,'''999 """""""""[[[eee)))'''$$$,,,###+++...:::]]]///+++555***AAA777,,,******(((888,,,111......333,,,...---"""---...666,,,===GGG888666EEEFFFcccccc111888AAAOOOGGG555555222888---...)))<<<888+++&&&TTT<<<333000444111+++******...++++++,,,222777???888000;;;<<>>III===<<<---555+++000FFF999:::999222>>>777666000444+++---'''***///MMM000...ZZZkkkJJJ444555jjj999------)))+++%%%%%%222<<<%%%//////!!!+++'''!!!000''')))!!!FFF%%%)))&&&BBB333MMMeeeVVVddd???999...)))+++ ))))))BBBEEETTT***###""""""""",,,...eeeiii------???***777???555))),,,333333...(((---111---000------'''///888333---444...---333;;;555<<<@@@555NNNqqqOOO999---///&&&000+++///000+++111+++---555///EEE333***000222---+++---...+++666<<<222333666>>>vvvggggggFFF444333000000666,,,555666,,,444111999999//////888222111///111222777///333333666888<<<777:::;;;666888CCC===;;;333777666888<<<555666FFF---111222444AAA222''',,,,,,BBB888ZZZ333111111***---666)));;;!!!&&&$$$###'''DDD555'''hhhZZZWWW555222FFF888'''000$$$###,,,555aaa(((!!!###(((!!!555!!! !!!,,, '''(((!!!+++"""...***???111%%%%%%000...BBB%___000111  $$$???555eeeEEE$$$ %%%***$$$"""$$$222111111000^^^,,,000<<<000,,,444;;;rrrMMM777+++,,,444000///...&&&(((555999///777@@@***888;;;===///:::,,,???777,,,555444333%%%(((***333:::666(((222---+++***---###)))...999***,,,(((...111333---555555666JJJmmmaaaKKKSSSCCC555000,,,,,,;;;666111555333,,,......******---333***111444...444,,,000444111777666888444555@@@888888666666888;;;222777555555???333...---555===222...)))444555///***...(((------%%%###***AAA&&&)))888111((()))&&&444&&&...>>>NNN???BBBSSS,,,***%%%)))&&&(((%%%###"""'''333--- +++!!! ,,,!!!%%%333111...<<<$$$&&&===bbbccc>\[[[SSS---)))""" !!!%%%///...VVV***!!!!!!###,,,+++"""&&&!!!+++,,,+++DDD---'''888>>>III>>>OOO4888000666888+++---+++"""&&&111666***---444222CCCGGG)))+++===---(((555+++###)))(((000444,,,------)))!!!******)))...$$$$$$)))(((+++444((('''666///@@@111999999...AAAUUUeeeNNNGGGKKK>>>,,,***(((***222---&&&***,,,***---333///444...,,,///---...///---000...///666444666///777222666LLL555>>>///VVV333333444333111///***000;;;;;;,,,888'''444***,,,333///$$$"""''',,,!!!&&&,,,555%%%'''%%%'''%%%%%%+++ %%%&&&333<<<---%%%DDD---$$$"""&&&$$$!!!""""""111&&&###***!!! ((((((222666333:::@@@777IIICCCWWWHnnnlllqqq---HHH)))!!!$$$ %%%%%%'''"""###"""...***"""%%%%%%******((()))999---888HHHoooppp___MMM888((($$$((((((%%%'''&&&%%%%%%+++,,,)))---(((***&&&666+++===DDD+++333:::...+++,,,((((((,,,***///))))))+++$$$((((((%%%$$$---&&&%%%------333+++,,,)))%%%)))(((222:::???IIIGGGIIIAAA***---)))'''***(((+++000,,,000222***+++///000+++***---666:::000---111...------222///333222444666777111>>>888777444444444555---HHH222000777555111000???000111---%%%&&&;;;###$$$000888$$$&&&%%%***%%%$$$$$$%%%$$$ !!! MMM,,,333+++///JJJ$$$%%%!!!!!!777,,,(((CCC***KKK(((###999(((((()))IIIQQQMMMKKKhhhttt*5( 8333%%%%%%777222!!!,,,III%%%YYY444)))%%%+++---888@@@<<<...///666???gggiii```GGGWWW999AAA---444...&&&///)))%%%+++)))))))))+++...///,,,///444---+++***(((%%%222333)))+++!!!"""---'''---///...***$$$%%%'''///(((%%%+++***RRR&&&111******+++111>>>AAA***000222999...000(((,,,&&&$$$(((444$$$(((EEE...000...000000***111''')))''',,,111---000///OOO111555444555CCCBBB:::222<<>>:::..."""&&& ---MMM111%%%$$$555<<<>>>???AAA,,,777DDD<<>>&&&&&&&&&'''DDD)))'''333+++%%%%%%###***,,,&&&(((### '''***666CCC,,,&&&###&&&$$$%%%%%%!!!$$$%%%'''))),,,+++,,,(((+++)))222,,,111555000;;;+++---333$$$'''"""///(((###---+++>>>TTTNNN111,,,,,,%%%...III))))))...111333BBB111111666333000000333555999222===999MMM<<>>>>>BBB>>>333???777111>>>???>>>///(((+++...///######&&&+++%%%000 +++666""")))"""&&&'''(((...HHH'''AAA"""---"""555666NNNddd...%%%666333CCC &&&AAA!!!'''###444///CCCVVV```KKK333555MMM///***>>>'''%%%$$$$$$!!!;;;!!!&&&###%%%$$$+++RRR666+++ )))OOOvvvGGG:::xxxyyyVVV vvvUUU:::111AAA+++GGG***###$$$+++&&&(((,,,(((######$$$%%%###"""***%%%$$$$$$######'''))),,,***$$$%%%&&&+++,,,III111)))---$$$(((%%%!!!(((!!!###""" '''###((()))+++&&&&&&((($$$!!!###+++%%%(((&&&((($$$"""###...%%%+++"""%%%444___'''000FFF...222000......111///333\\\333333bbbEEERRR111888KKK999JJJHHHDDD???CCC444555===222999444###'''((('''$$$%%%+++***'''((((((***&&&555"""222###)))(((###444 444EEE"""""")))"""''''''$$$###PPP(((---XXXKKK999+++EEE888777>>>555IIILLL"""''' """((([[[QQQ'''&&&%%%%%%)))GGG]]]CCC:::EEEAAAZZZbbbEEEMMM,,,:::---CCC)))((("""&&&$$$&&&!!!###)))%%%%%% """$$$(((...'''&&&!!!'''$$$&&&((("""'''$$$$$$"""&&&222222&&&'''******&&&"""!!! !!! !!! ...///222%%% &&&)))///###!!!###&&&%%%222!!!%%%%%%,,,%%% %%%&&&$$$777***---;;;444---'''000///777===<<>>000???555444((((((&&&---"""""" !!!!!! !!!"""&&&###%%%&&&VVV---(((555###222!!! $$$$$$222+++VVV 000---***333888 !!!###GGG""""""222ZZZ***'''###))),,,...--- ,,,$$$%%%(((MMM; -%%%###$$$$$$###///SSSHHH===<<<333333!5gggGGG444,,,+++!!!***!!!%%%"""$$$***%%%###///%%%((( $$$+++######$$$ ###"""%%%### """)))(((''')))999QQQ&&&'''///***$$$&&&!!!$$$!!!!!!$$$***%%%555'''$$$""" !!!$$$'''%%%###$$$((( &&&((($$$%%%%%%$$$!!!)))000???;;;,,,''';;;555:::???222;;;]]]YYYdddYYY]]]???777111&&&...888......;;;222...---666***''')))"""""""""+++)))***))) ###!!!$$$!!!999///$$$"""111)))***111 ### :::;;;888''')))///'''$$$***;;;%%%333---%%%""",,,%%%:::ccc===)))///"""%%%***WWWOOOMMM333///444qqq#VVV777((( %%%$$$,,,(((!!!)))###&&&!!!)))+++"""'''***&&&)))$$$%%%!!!###'''###"""""""""'''%%%555###===ooo!!!$$$(((((("""$$$"""))) $$$"""!!!!!!%%%"""!!!!!!!!!+++!!!&&&---+++...((($$$%%%###)))"""###$$$222222333iiiGGG000000333???FFF===888888fff NNN^^^VVVFFF///...,,,(((777---)))((( (((...'''(((,,,"""'''''')))+++###''' $$$$$$......GGG///)))777FFF&&&"""""" +++###,,,+++"""###&&&BBB)))***!!!222+++PPP;;;777)))222(((FFF888VVVFFFAAA///555222:::444---///%%%"""'''666***'''000%%%!!!%%%)))%%%++++++$$$###,,,((( $$$"""### %%%###)))###&&&$$$)))222''' """(((---&&&###""""""<<>>???555///$$$ )))$$$!!!>>> %%%###+++  ---!!! &&&!!!222:::---&&&""""""%%%]]]ZZZ999)))000''',,,ccc"""000 -KKK***---&&&!!!555%%%"""######CCC---"""777""",,,222///+++000&&&***!!!###!!!######'''&&&!!!!!!$$$"""###""" !!!%%%---###'''###$$$###"""%%%(((***%%%333999777DDD777,,,IIIWWWbbbFFF999---+++ )))???999CCC###!!!444,,,!!!### ,,, $$$ """(((///$$$### (((+++&&& ...uuufff===&&&%%%&&&$$$,,,)))GGG'''===EEEGGG''',,,&&&+++ """)))$$$"""$$$'''!!!!!!###)))---AAA444000444***###'''!!!'''&&& ###"""###"""&&&111333111######""" $$$'''!!!$$$  """ +++"""!!!!!!*** 333###'''&&&%%%)))---222111ZZZHHH((("""+++""""""$$$###777###???!!!###EEE&&& ---+++EEE 444JJJ333***"""'''"""###;;;...---,,,### )))$$$&&&###!!!777###!!!!!!###***^^^111###XXX###!!!$$$&&&"""!!!(((###!!!!!!...111DDD111,,,''' %%%&&&"""%%%###### """###!!!&&&###$$$ ((( ((( ,,,(((,,,&&&'''$$$!!!===+++)))WWW$$$777%%%***$$$""")))%%% 111,,, """ %%%''',,,CCC,,,999!!!"""$$$$$$777,,,///---***$$$ """$$$ !!!$$$%%%&&&%%%'''&&&:::444((()))MMM(((""" !!!"""%%%(((!!!"""$$$!!!!!!###***$$$"""###$$$ $$$(((%%% !!!%%%###)))$$$"""!!! !!! """!!!%%%@@@$$$%%%$$$$$$""""""%%% )))&&&$$$ 222 +++%%% !!!!!!"""### $$$"""  !!!!!! """"""$$$ ,,, """###%%%&&&444(((***'''$$$---000''''''---111)))%%%'''>>>___---(((+++...---AAARRRGGGNNNpppZZZ<<<;;;GGG333???jjj:::)))///,,,...)))000---///+++)))'''222&&&""">>>FFF'''+++)))&&&(((&&&***,,,'''$$$333+++***+++)))222%%%,,,---,,,++++++((((((...777,,,,,,111111000...---000222444999000333111222JJJ///222555333...000///888000888///888>>>333888+++111***)))""" %%%+++<<>>JJJ888999---AAAYYYEEEAAA000***(((...---,,,///((('''''',,,+++,,,(((%%%&&&&&&%%%)))***)));;;>>>'''%%%+++,,,+++(((+++(((111,,,+++---...((('''...,,,,,,777===333000111111000000555222444444555555>>>333000666666555444444;;;???222999,,,,,,333<<<666111***...///...222555000###$$$555,,,,,,000+++LLL???;;;EEEGGGAAA:::FFFBBB@@@DDDHHH======@@@<<>>777222333000111444000111999---&&&(((444666BBB///333666:::444555777III]]]PPPEEEMMMJJJMMM???999YYY???MMM444999,,,...))),,,***)))FFF$$$###&&&)))'''...---$$$$$$### ((('''777999 !!!"""111%%%###333#########)))"""777"""!!!"""  +++999'''***---%%%***((('''---***,,,;;;---333+++111(((&&&///&&&222###&&&###%%%---(((---+++...555222///000>>>777???SSS000111)))''')))%%%$$$&&&&&&&&&)))+++***,,,$$$&&&&&&+++111555))))))(((&&&***)))''''''((((((%%%%%%(((''',,,%%%&&&,,,,,,))),,,???@@@222333777///555222,,,---,,,...+++//////444222777AAA:::;;;>>>DDD888<<<>>>777888666;;;;;;777BBB555222---222CCC444888777,,,$$$999???AAA???333888777888IIIEEEMMM___QQQMMMAAAGGGFFF;;;>>>000666>>>@@@222,,,+++***,,, %%%+++(((!!!"""111***+++...  ### 444 ---&&&###%%%%%%+++ +++'''!!!(((((( """$$$ $$$###!!!%%%###***'''))):::111"""+++(((&&&'''&&&!!!---...,,,777<<<...,,,///%%%### """+++555***---)))///***333///)))+++000444222;;;@@@000***+++...)))&&&%%%(((***'''+++...---///000&&&222///$$$"""%%%---GGG(((&&&(((%%%$$$%%%%%%''''''((((((&&&)))+++000111FFF444555555222111222:::///222---)))+++---///333666222111555999UUU===ZZZ<<<:::999>>>HHHCCC<<<333<<>>AAAHHHUUUNNN666......///+++///%%%---***%%%(((***$$$&&&###$$$""" !!!AAA"""&&&!!!!!!((( """$$$###$$$ ### ///$$$555))))))&&&+++(((<<>>AAA>>>======IIIEEE555///333222HHHVVVJJJCCCNNN<<<111///===555000000999OOOFFFAAAOOONNNLLLYYYGGGJJJDDDHHHMMMYYYeeeKKKGGG@@@888///+++***111'''(((///)))$$$&&&'''$$$"""""""""%%%&&&"""''' ---###999 000:::MMM """!!!... $$$%%% ###::: """))) ###'''???...444===000,,,PPP***(((&&&------(((,,,>>>&&&))))))---&&&///>>>dddxxx,,,,,,(((&&&###%%%&&&)))+++444)))+++,,,000666,,,))))))***,,,222>>>FFFAAA___555111///***)))&&&(((+++%%%$$$***))))))'''"""***%%%333+++===###&&&((()))((($$$$$$&&&***''')))++++++)))))),,,---+++000...///+++---***,,,...///999111333444===888111444555111333,,,222444FFF>>>SSSGGG===@@@999<<<999===AAA>>>AAA222:::nnn======FFFeee===++++++888///777HHH???BBBBBBGGGKKKYYYrrr>>>III;;;eeebbbCCCBBB===FFFKKK///---333,,,,,,---///"""$$$$$$!!!!!!%%%,,,+++&&& """ !!! ,,, ;;;&&&+++'''&&&!!!%%%)))000$$$!!! ((()))$$$===AAA%%%***///:::111(((&&&'''''')))///777)))555CCC...>>>///''',,,444777666((('''&&&...***///***(((---,,,///---+++;;;...&&&(((,,,'''(((---333PPPNNN;;;///,,,&&&&&&&&&(((666((('''&&&)))DDD,,,###%%%%%%)))(((***)))###"""&&&%%%(((&&&&&&((((((******(((+++))),,,,,,+++'''+++,,,///---///------+++===,,,...666222555111999===AAA777---///444<<>><<<@@@MMM666;;;777555IIIKKK888LLL@@@DDD???888+++(((333]]]VVVHHHHHHEEE|||zzzJJJTTTJJJCCC<<>>''',,,555,,,,,,+++(((###""""""+++,,,???bbbhhh???+++---333***'''%%%'''///(((%%%)))---444***+++---&&&'''$$$%%%######$$$'''555$$$&&&***)))(((###)))***))))))(((+++,,,++++++***+++333///333///...111***+++222222444999::::::555333---222CCCQQQ@@@QQQCCC???PPPFFF===KKK@@@???555777444777999jjjGGGDDD:::;;;888???666444EEEDDD>>>DDDEEEFFFOOOJJJDDD===bbbIIISSSSSSRRRQQQ>>>AAA???<<<---,,,555@@@555000'''&&&&&&)))(((%%%888 !!!!!!"""!!!""" ))) '''"""!!!,,,000%%%JJJ...000$$$ ,,,   """!!! +++)))###%%%"""***555HHH###$$$%%%:::---111+++...'''+++,,,******<<<+++...000333******EEE666444''')))...+++,,,)))'''&&&$$$***,,,...''',,,......,,,))))))'''"""+++777---444iii:::''',,,***%%%+++..."""666???))))))...666---000)))%%%'''000+++&&&%%%%%%))))))'''(((&&&%%%(((+++,,,'''&&&'''''',,,''')))*********---000YYYbbb111IIIttt333,,,---222777777666444444///777888888===777>>>===KKKJJJ<<>>GGGFFFFFF\\\___RRR[[[AAA777555444...333333...333222((('''(((:::999<<<---!!!"""!!!"""$$$  !!!,,,%%%***+++### 999 !!!%%%"""!!!"""%%%!!!"""$$$((('''===III111@@@NNN333,,,444LLL;;;888%%%......((()))444OOO((($$$&&&((('''...'''(((&&&,,,===222---+++%%%###%%%###((()))666+++)))+++******)))((()))######"""''')))(((%%%>>>RRR&&&###"""###%%%&&&)))------)))...)))///555(((((($$$***'''))))))'''%%%%%%&&&$$$%%%)))((('''%%%&&&((('''***''',,,***'''+++,,,111000333555555555???222000---777444666333666333222888555999888>>>===???@@@III>>>AAA:::BBBCCC???333444???```777<<>>bbbmmmBBBzzzCCC<<>>666666555555666777//////111111///===???>>><<<>>>:::===FFFDDDFFFjjj555333222AAADDDFFF888;;;999444555::::::999777000000LLLZZZQQQTTTjjj|||VVVRRRHHHEEE???777000777888222///222,,,222111///***+++111///'''$$$&&&###%%%"""!!!### """ !!!!!!"""$$$!!!"""'''@@@"""!!!### (((!!!###... !!!!!!###### """###999'''333)))...///---,,,...111333222---%%%...HHH000///***444+++'''&&&###$$$!!!"""%%%"""!!!"""!!!,,,---***((((((,,,(((%%%++++++///)))***&&&888&&&%%%"""EEE&&&###$$$%%%>>>&&&&&&%%%$$$$$$%%%%%%%%%###***$$$%%%'''+++))),,,)))***)))222333888(((444,,,&&&***)))***...---,,,++++++,,,)))...,,,,,,...666...555---000111000+++''''''((()))000111000)))---AAA^^^555777777999888333444555...000333;;;@@@AAA999???LLLAAA;;;EEEBBB>>>:::777666777]]]LLLRRREEE999;;;333666;;;<<<555999)))...GGGGGGPPPSSSJJJHHHRRRGGG:::777444888777------,,,111<<<---***))),,,***999999555&&&###%%%######$$$ %%%!!!!!!"""""" !!! ###&&&!!!,,, %%%%%%!!!"""''' ... ---"""&&&DDD777%%%""" %%%(((%%%///"""$$$+++'''+++333...<<<999333>>>222@@@,,,///...---+++---)))(((...***///$$$"""&&&,,,---"""### $$$'''%%%'''"""$$$((('''$$$###''')))$$$&&&&&&''''''''')))%%%$$$$$$%%%///###$$$'''%%%'''(((***(((''')))PPP'''000)))'''===,,,***$$$$$$%%%%%%...kkk333(((***---)))---***///AAA+++---555+++++++++///111666111111333...------:::---......---000444333......,,,111555111000222777555111666888111...333333555<<<888JJJ;;;AAAEEE======HHH<<<999888888:::888>>>;;;???:::444444666888888333***###DDDLLLIIIdddIIIKKKIIIQQQ;;;===@@@888>>>444,,,,,,888111+++***888111)))((((((444---((((((###%%%'''$$$%%%888$$$)))$$$"""%%%""""""***333777"""(((  ===666 $$$###"""###HHH###$$$!!!!!!'''######%%%###)))'''&&&+++:::///222777222'''$$$***MMMWWW666555666000+++)))+++---&&&!!!((()))+++---&&&%%%'''+++)))%%%!!!"""((('''%%%((((((((('''+++(((###$$$'''&&&"""%%%***---&&&&&&---%%%$$$&&&%%%%%%'''&&&,,,///'''$$$***'''***$$$###(((&&&,,,+++......,,,(((,,,...+++,,,---222333...,,,'''...000......222666222222555555///---...,,,///333222///,,,111...---===333222333222555444999444444000...444111000===FFFLLLAAA@@@;;;===:::FFF???@@@999<<<555666GGG:::]]]EEE555666555555777666777---)))---CCCKKKEEERRROOOKKKNNNJJJBBBIIIEEE777HHH555<<<---***(((+++***)))---,,,666***)))&&&%%%&&&$$$'''&&&'''"""%%%---"""###!!!!!!!!! $$$###555'''$$$'''%%%))))))www ...'''\\\'''%%%$$$###$$$!!! ***###"""$$$((((((000''',,,+++777???;;;...---...(((BBBwwwQQQ---...DDD+++)))***!!!)))$$$%%%///)))(((&&&(((++++++555%%%!!!%%%((('''(((&&&[[[((('''###%%%'''%%%&&&$$$$$$$$$'''))),,,,,,,,,(((%%%"""(((&&&'''&&&((($$$((('''''''''%%%$$$&&&***,,,000111,,,///...******))),,,111+++***+++333+++///111,,,---111...,,,444+++222444555555444...000777<<<<<<777222333111999222111111+++777<<<@@@777:::555444666...111666:::KKK:::???QQQ>>>777888???AAA===;;;888999III888???===555555888777777777888222222...777\\\hhhsssXXXSSSPPPNNNHHHCCCBBB;;;222000555444333333222333------:::)))((('''"""&&&%%%%%%%%%$$$""""""!!!""" """###((()))  ******!!! !!!### &&&!!!######&&&"""(((,,,&&&### $$$!!!###%%%'''###""" """%%%///---(((&&&///111---222,,,KKK;;;---SSSOEEE'''###***...%%%&&&)))000'''***'''(((***&&&(((***)))'''+++"""&&&###'''&&&%%%%%%'''&&&%%%###"""&&&(((###%%%%%%$$$$$$ ###'''%%%%%%$$$'''&&&''')))%%%((('''((()))(((&&&'''((('''&&&777---)))))),,,+++***))))))***111111///+++...111...111:::444//////,,,000///111111<<>>>>>:::???666777666444------+++---888888DDDLLLMMMRRRLLLhhhKKKAAAQQQ888666777555777111...000,,,111>>>***'''***'''...---$$$%%%###---===+++%%%(((""" """&&&$$$'''&&&$$$### 666 222!!!lll!!!""" &&&777///$$$"""!!!!!! ''')))!!!$$$666$$$&&&######'''%%%bbb111$$$$$$!!!###%%%>>>555UUUPPPQQQ666###&&&###&&&555///%%%)))(((((('''+++))),,,******&&&&&&$$$(((&&&!!!%%%&&&$$$&&&***222'''((()))&&&)))+++%%%---(((***+++)))(((***'''&&&((()))))))))***$$$(((''''''&&&)))))))))--->>>222...***444333888333///000333///999777777555666111333CCC...333333444000444111,,,000000777999666BBB999???EEE:::>>>;;;AAA444333777333222555111000444<<<333555;;;:::777999<<<888CCC444888>>><<<888===III<<>>:::777:::666555888888777444111((()))///;;;KKKLLLcccTTTHHHLLLIIIEEEDDDTTT333:::>>>555444777000...++++++%%%,,,///***(((---333)))'''&&&---""",,,%%%***### ###""" %%%''')))((()))%%%$$$"""###... ***+++### &&&%%%+++### %%%!!!$$$ ***######!!!$$$%%%!!!### """///###""""""$$$$$$&&&%%%$$$%%%)))!!!(((000000777...###,,,333***)))+++(((%%%...'''...---111+++///...,,,'''######%%%&&&'''(((&&&+++)))&&&(((,,,,,,((($$$(((,,,,,,&&&***,,,,,,)))((())),,,,,,+++---******(((''',,,)))***((())))))+++222000,,,,,,***///***,,,000...///000333888000111///555777:::333000888;;;222...111+++,,,222555KKK777999;;;NNN===222000777999999444555444444444555444333444JJJ888888BBB???888888:::<<<888444666;;;===777@@@DDDFFF======AAA===;;;???:::777888888;;;@@@;;;333111444...333888KKKAAA===GGG```JJJWWWAAA999333;;;999999555444000***+++(((''',,,***++++++///<<<555///)))...''''''&&&###---%%%(((***:::!!!###;;;&&&###$$$%%%((( <<>>***%%%&&&$$$### """---***(((******///---***)))+++DDD---***,,,***222222888***(((,,,///,,,+++***)))&&&,,,)))***,,,------+++,,,---000///++++++,,,333///...,,,...***111111---...222999444444333???777000111222,,,111666222,,,222555:::WWWHHH999111111444333000888888666444<<<555333777666777666111111666<<<<<<;;;::::::444<<<333:::888999999===AAADDD>>>???:::;;;;;;;;;:::===:::999AAABBB888555333444777:::555CCC<<>>...***+++111+++&&&)))<<>>333000///111///444:::<<<555<<<444444333111444222111111>>>???===;;;>>>444000222000777<<<999===JJJKKK<<<===<<<;;;;;;===>>>>>>???CCC:::;;;>>>;;;:::;;;::::::555@@@XXXWWWKKKbbbIII<<>>:::---,,,111(((+++------))),,,)))))))))222999>>>,,,))) %%%!!!)))$$$'''#########'''###""",,,*** $$$$$$555 ###$$$"""XXXVVV555 %%%===%%%---&&&!!!&&&!!! """!!!""" !!! $$$###$$$%%%!!!&&&&&&%%%((($$$$$$%%%...777666222III^^^666666777***$$$)))......(((+++)))777444???...+++%%%%%%$$$(((&&&)))))),,,******///...***,,,...777,,,---------333;;;888+++...++++++...333999111000111222...444666---+++222555///+++111///---111//////000...DDD...---777444000666===DDDKKK555888000666111444000...111222;;;:::;;;DDD666666666444EEE333000444333444KKK888888222===>>>444222333222333EEESSS:::888555111......666777777555===???DDDBBB<<<:::999777:::999777>>>@@@:::=========:::888>>>===EEEDDD@@@EEEEEEBBBMMMBBB;;;DDDBBBVVV===III333000222000---111......+++***888---'''222+++000,,,%%%!!!#########""" ###$$$KKKFFF***CCC///***###$$$+++ ((($$$CCCAAA444!!!"""BBB%%%&&&BBB$$$!!!"""&&&"""###&&&###***%%%%%%"""$$$%%%(((''')))'''$$$+++333555VVVsssCCC555...000***<<<222&&&'''---...+++666,,,222******&&&(((%%%,,,777111***(((***...444>>>222000---000444///+++...111///111222111111===333555333BBB999444@@@;;;444<<<:::444///000333333......---...+++444111444???999444999444///???MMMKKK555111000---777000000---///111222111777555777000111<<<:::999///222===444@@@;;;???444222666666888333333111222888888666555999000222222333333999999CCCDDDBBBGGG999999666;;;;;;;;;CCC===>>>???@@@DDD???444888===HHHQQQ;;;<<<@@@>>>CCCRRRFFF===DDDHHHHHHCCC333555555555000///))),,,***,,,---&&&333lll555+++---'''"""%%%((('''%%% !!!%%%%%%***$$$ ###'''+++&&& $$$---!!! ;;; 333%%%,,,"""222^^^$$$(((!!! %%%)))""" """!!!%%%"""!!!111%%%######$$$$$$$$$***"""$$$&&&((()))111---111000;;;cccLNWWW777888999,,,444000333///,,,...+++---+++'''***))))))(((000000111000---+++,,,//////444@@@000...---888666999555CCC///...222333777111>>>:::<<<777===<<<;;;@@@000666:::<<<666555888:::444===///...///000---...000000222666777666FFF999777@@@111111111333***,,,,,,111,,,,,,000111:::///333222<<>>444BBB999===GGG555777888<<<666666888444333===:::888666333333888555777555AAA???===@@@AAAGGG<<<999@@@<<<>>>@@@999>>>;;;IIIAAA999999888>>>RRRCCCCCCEEE===AAA@@@EEETTT^^^TTTJJJIIIAAA444111///444111///...+++(((,,,)))(((666aaa@@@(((((("""((($$$***######!!! !!!,,,&&&$$$...$$$###((("""###!!!444$$$ ###$$$!!!"""$$$  $$$ 444 ///...)))  ######!!!%%% )))""""""((("""###&&&)))///$$$%%%$$$$$$(((&&& !!!///---444:::___*JJJJJJ...///333///666333111444...///))))))***000;;;---,,,111,,,///,,,222111111...***,,,+++///000000======:::555555444222222555000888555:::999666SSS777555888333000444888555111000...666000000......000222......000///111444//////---888<<<666000UUUCCC:::222000,,,...---111+++000///333444<<<666555444AAA<<<666;;;DDDWWWKKK;;;777???666777===<<<666777\\\>>>666666666444222222888888BBB<<>>@@@;;;:::;;;???DDD<<>>999///...)))///((('''MMMLLL333;;;############$$$'''"""$$$"""%%% ..."""!!!###"""###"""%%%&&&%%%"""222###  %%%###***(((:::!!!""""""""" """"""###!!!"""$$$"""######///CCC+++%%%!!!$$$&&&%%%777***FFFWWW===999HHHKKKKKKHHH111222222...,,,,,,777<<<===444111,,,---///888222+++***...)))***666333444333000666333333000222222111666555000999888777666000222777666444JJJGGG333222999666000111222111222---111...bbb777222333555333000...000CCC...000,,,---555***,,,111777999999111000CCC<<>>888222999:::666AAA555222333777555---444444666999AAA===???CCC@@@???<<<<<>>>>>;;;444888AAAAAA@@@>>>:::888888333222333HHH999;;;IIIbbbyyyccceeeNNN999111///333222...111'''+++*********&&&$$$%%%$$$'''$$$%%%'''$$$$$$&&&%%%###%%%$$$%%%%%%!!!!!!'''!!!%%%'''"""888,,,---***... $$$+++"""$$$  !!!"""((($$$###$$$ %%% $$$...***$$$###"""$$$&&&---???555888000WWWDDD999:::444222,,,---111)))***000777???SSSCCC???111111---,,,222++++++***&&&///444111222......000,,,...666<<<444555555OOO888999888666555666444;;;222777;;;333000333555444///PPP222222000111222888111666555777;;;111444222222000111000------+++***///333KKKJJJ666333,,,,,,......)))000+++,,,...000444>>>;;;&&&&&&+++///555888AAA???;;;>>>:::333///777333444333777999......000LLL444---...222@@@===JJJBBBQQQLLLHHH;;;AAA:::888<<<>>><<<:::===999999AAA???KKK333777444000$$$''':::;;;FFFOOOVVVrrrKKKJJJJJJ<<<888BBB333000...+++************$$$'''((($$$'''///'''&&& %%%###### !!!%%%""" &&&!!!!!!"""((((((***###'''%%%///,,,111!!!!!!!!! &&&$$$ ((("""!!!"""###$$$ ### """$$$$$$"""###!!!***'''222***555:::IIICCC555333BBBAAA222***,,,...555@@@333222///111444111000...777%%%***+++---,,,)))(((444777333...000222111;;;888;;;===???444;;;===777666;;;666:::;;;222222333777666666333222333444777;;;===999666333444333666444>>>777666888333333333///333111///...,,,,,,333222BBB666:::bbb333***...>>>+++,,,------222666333222555AAA(((***...333444HHH777===<<<888<<>>>>><<<888999555888===<<<<<<;;;777===DDDAAAAAA<<<;;;000+++(((((()))777[[[kkk -YYYPPPAAACCCAAA666222333...;;;///***'''&&&%%%###&&&&&&%%%***'''%%%&&&'''### $$$%%%%%%'''### """"""$$$&&&((($$$///BBB%%%&&&!!! $$$&&&$$$  (((***!!! ###111 ---'''&&&111&&&'''%%%"""!!! !!!$$$###&&&((((((&&&%%%---777)))111---===EEE000<<>>888@@@777444777QQQ999888444666777777555999999::::::<<<:::555000666777999555777;;;999444888666444000444999666333111444444222000000222333///222555555:::999444111333333444...///000:::GGG111777666:::???LLL555666///444<<<666///555555777???XXX444333///FFF===PPP777)))***111555000222JJJ...333[[[>>>>>><<<>>>???<<<===;;;>>>888888999999???<<<:::>>>EEE^^^FFFUUU555(((&&&)))''')))WWWxxx___sssaaaMMM@@@666CCC333.../////////'''222''''''&&&,,,"""$$$***'''***"""***&&&'''&&&&&&$$$###$$$""""""$$$&&&---,,,)))MMM333$$$!!!"""%%%  +++(((!!!'''###$$$333---999###!!!$$$###((( 555"""!!!###(((+++### ---&&&&&&000((($$$&&&&&&###''',,,%%%)))222===~~~PPP444000444222UUU;;;:::PPP333333555222111333333333000111000555444777222777777<<<===999NNNAAA;;;@@@===888666:::===999999666999<<<888666@@@???:::AAA<<<::::::;;;:::888999:::;;;===<<<777444777555555222///LLL111777111333222111777111222777222;;;AAA:::PPP>>>333444222333444000---000///111333999222555,,,444888===444666666555111666>>>999;;;000333222VVVAAA222+++(((///333444333000222,,,000DDD@@@>>>===<<<>>>;;;>>>===:::<<<999:::@@@>>>@@@AAAAAACCCEEE>>>444...'''JJJ555(((:::IIIIIINNNLLLEEEEEEIII222999///,,,000555111***)))%%%'''""")))111######&&&&&&000&&&&&&***'''%%%$$$$$$!!!###$$$(((!!! """###$$$000''':::***///((($$$*** !!!!!!!!!''''''!!!(((DDD666""""""$$$$$$###)))###"""""",,,+++'''""""""  ###%%%...'''"""$$$)))'''"""&&&$$$'''222999:::@@@VVV555444444666===555FFF444000:::???///...111000///:::222222555888<<<===;;;>>>???:::???@@@<<>>AAA999:::777777999:::===<<>>FFF<<<999===:::666888666444555000...333222000000222555444666555777333>>>@@@GGG333???444444666555>>>...222111333//////222777000444>>>+++...222888111GGG111888888777111777666999???<<<000---...222333444222666111000@@@???;;;;;;;;;999KKK???;;;:::???999???<<>>...000...'''''',,,(((FFF(((&&&((('''((()))######$$$+++***&&&'''&&&&&&%%%#########""""""---LLLlll222%%%$$$ """#########!!!!!!$$$!!! $$$$$$+++))) """"""###???!!!$$$999333((((((&&&'''222!!!$$$&&&!!!"""!!!$$$$$$&&&,,,"""***&&&%%%'''---,,,)))000;;;555444777999>>>111///888555333999CCC:::,,,...333666222:::777333888???@@@<<<;;;<<<>>>@@@AAA888>>>QQQ;;;@@@::::::??????III;;;;;;;;;;;;>>>GGGHHHCCCJJJJJJ???<<<@@@DDDJJJ888IIIAAA;;;BBB???999555444333222111111000000555111444666111666333///888444LLLPPPDDD===444666???AAA>>>???555111111222444EEE111(((,,,000000,,,///777DDD999...000///:::333666;;;555666666777FFF<<<444333444000555666---333888;;;===;;;:::>>>999???DDD;;;??????BBB;;;AAA<<>>mmm***!!!)))"""""" (((!!!,,,&&&555###888###((( ###### """!!!%%%333:::111......((("""""" %%%'''$$$,,,$$$)))'''((('''$$$&&&&&&((()))'''+++++++++,,,000000AAAVVVRRR555???777444777222222...666333888555;;;EEE666888<<<;;;YYYiii???;;;<<<<<>>444===999<<>>>>>@@@444444...555555SSSIII:::000555444000888DDD222444---999---000444444333555333444999===777888777888999999BBB333000BBB999;;;;;;777;;;@@@;;;???666EEE???\\\DDD===???BBB>>>999;;;111000(((###+++///>>>BBBNNNPPPKKKSSS===888222666777000***......+++...---+++)))%%%)))&&&///***+++$$$&&&&&&!!!"""***)))%%%&&&LLLggg%%%'''&&&$$$&&&(((;;;'''!!! 333(((>>>777!!!"""$$$ !!!!!!!!!###///666;;;''''''AAA###$$$%%%%%%!!!!!! ###)));;;!!!"""111!!!'''((()))))),,,000---555///999<<>>?????????@@@<<>>LLL@@@```JJJBBBEEECCCLLLIIIFFFIIIDDDLLLIIILLLCCCNNNHHHNNNPPPBBB;;;<<<===??????999???;;;>>>999:::;;;777777777777777888888999111222000000666???;;;;;;777555555;;;;;;===333666222777777EEEMMMyyy555666555444666999666555111111999555999000333666111555888666666333666===SSSEEE???555111999444<<<999:::<<<===<<<;;;888777===???BBB>>>===AAA<<<>>>888444111)))%%%,,,111111===BBBHHHJJJHHHHHH<<<;;;333333444111...333//////''',,,)))(((((($$$,,,+++###&&&%%%###%%%&&&$$$$$$""")))&&&+++...+++$$$&&&!!!)))(((""" """ 111!!!(((...000"""***&&&%%%%%% """""" ###%%%777ooo???)))(((!!!$$$"""%%%%%%(((333###%%%$$$"""$$$%%%+++!!!###''',,,222777777MMM555\\\EEEKKK>>>222999777333666666666888:::BBBBBB:::888:::@@@999999>>>:::;;;@@@>>>DDDCCC???DDDQQQGGGAAAMMMHHHdddXXXHHHFFFOOOAAAIIIBBBHHHMMMIIIIIILLLKKK???AAABBB@@@BBBJJJGGGCCC===AAADDDDDDAAA>>>:::;;;;;;;;;999;;;888999777999>>>999>>><<<555777444333<<<@@@UUUGGG>>>======888;;;:::888555444>>>???>>>AAA666555999111444444GGG333:::111999777555>>>777FFFDDD>>>SSSddd<<<;;;???:::???EEEJJJ666111888<<<333;;;???666;;;===777======888===CCC?????????AAA>>>999333999///***000333111LLLFFF>>>KKKNNNIII<<<444888777000555---444******444)))'''''')))---(((&&&&&&"""######### %%%&&&'''999***uuu===""" !!!,,,000#########)))"""!!!"""''',,,(((%%% !!!!!!!!!"""!!!//////)))///$$$***'''---$$$"""***%%%$$$"""!!!### ######,,,+++111333///888:::===IIIDDDAAA888666<<<>>>888<<>>===>>>@@@EEE@@@EEEDDDEEELLLCCCLLLzzzOOO===<<<<<>>@@@KKK::::::888AAAHHHLLLEEEDDD@@@AAAAAA>>>:::<<<<<>>;;;<<>>??????<<<@@@999666999;;;>>>???EEE<<<@@@;;;777444222444222333555555999333777777???===<<<999XXX???NNN;;;888888999AAA999444555BBBBBB;;;===999666@@@>>>IIIGGGPPP@@@DDDBBBCCCDDD??????999777555444""")))111111...111>>>@@@DDD???:::555666444555...+++,,,777...111+++***&&&''''''&&&+++%%%  ######---///...888&&&""" $$$,,,+++### BBB######(((555!!!!!!"""$$$$$$ ###JJJ+++222'''((('''$$$$$$%%%:::===''''''***%%%"""$$$'''((($$$&&&)))+++:::777000333:::>>>EEEFFF;;;ZZZWWWHHH@@@888:::AAA<<<:::<<<888555444<<<<<<>>><<>>===<<<>>><<>>AAA???<<>>BBB===AAA@@@@@@???CCCAAABBB???>>>AAACCCDDDBBBGGG>>><<<:::===@@@BBB666888444999444333222<<<;;;666:::;;;888888===IIIGGG<<<<<<@@@LLL888555222///>>>DDD>>>===::::::888:::CCCFFFCCC@@@KKK@@@AAACCC===@@@:::777999>>>"""///;;;777111666AAA===:::>>>999888777:::///,,,111222000///;;;&&&&&&(((000&&&&&&%%%###$$$"""######%%%$$$$$$)))777NNN((($$$)))!!!"""""" (((!!!###(((''' >>>&&&&&&(((333###&&&!!!  $$$222!!!!!!)))'''&&&+++MMM((('''&&&+++$$$"""###&&&'''&&&###///777:::SSS222222444===:::JJJ>>>EEESSS>>>===333777:::>>>:::CCCDDD777999999:::???===>>>KKKJJJHHH===;;;;;;???NNNEEE>>>EEETTTDDDIIIAAAHHHGGGHHHCCCIIINNNOOOKKKMMMWWWNNNKKKEEEHHHFFFKKKGGG666444BBBSSSZZZ===???IIINNNTTTQQQKKKIIIIIICCCMMMKKKLLLFFF@@@BBB>>>FFFEEEGGG???CCC???@@@DDDCCCAAABBBAAAFFFGGGMMMFFFJJJBBBFFF@@@HHH@@@@@@III;;;555KKKAAA<<>>:::DDDIIIEEE>>><<>>CCC888;;;;;;;;;@@@555======<<<;;;<<<999;;;999999>>>BBB666222333444???>>>>>>666>>>>>>AAA@@@???BBB;;;===BBB???>>>>>>DDD@@@AAABBB>>>>>><<>>KKKBBB@@@NNN===>>>===666...///000...///(((,,,---+++###***###&&&%%%%%%$$$!!!""""""$$$###"""'''((((((((($$$$$$"""""" """ &&&''' !!!333$$$!!!%%%$$$%%%#########)))(((""" !!!%%%""" $$$ $$$,,,&&&;;;:::+++(((333333444<<<===;;;AAA===<<<@@@AAAOOOZZZ999444777999<<<;;;AAA:::===???AAA999@@@<<>>999///111777EEE???777999BBB<<<===@@@AAA777888999===888999;;;666888;;;999777777777333;;;===NNNBBB===GGGCCCBBB777999888????????????KKKCCCCCCJJJooo???;;;FFF===///%%%&&&111888<<>>@@@VVVDDDDDDBBB>>>===888333:::;;;FFFCCC@@@>>>===CCCAAACCC999999:::===<<<999@@@::::::===DDD===777:::222DDD888DDDDDD<<<777333:::555777999;;;===>>>EEEAAACCCGGGDDDCCCCCCHHH:::@@@,,,)))111===888@@@FFFIIIHHHMMMAAA<<<222***---...000000777444[[[555&&&111((('''&&&"""&&&+++'''"""###$$$$$$###%%%555***%%%&&&&&&###""")))"""000///!!!!!!  ***'''$$$'''""" """***!!!'''###%%%!!!###&&&"""""""""***'''"""$$$///...%%%$$$***999111)))///...,,,---+++333;;;@@@444888///222111444;;;???KKKHHH<<<666:::JJJ>>>???III]]]FFF@@@PPP>>>JJJAAAEEEMMMAAADDDGGGQQQEEEVVV4%kkkgggyyy qqqfff|||uuurrrWWWPPPWWW___bbb^^^YYYLLLXXXaaaaaaeeeUUUUUUUUUMMMJJJhhhhhhlllZZZLLLccc```nnnooo]]]WWWTTTXXX______[[[WWWPPPKKKOOONNNXXXPPPMMMPPP[[[RRRLLLKKKIIILLLIIIKKKCCCEEEPPPBBB===111111===BBB@@@FFFDDDCCCAAA<<>>;;;<<>>:::666;;;BBB444666999<<<>>>===BBBBBBCCCBBB===>>>???>>>444'''666FFF===???BBB???GGGBBBJJJHHH;;;---000;;;777333...///333,,,***###((()))%%%'''&&&$$$+++### ###"""!!!!!!$$$''''''&&&!!!)))%%%!!!"""$$$&&&$$$ !!!"""%%% '''***!!!###$$$,,,;;;(((&&&"""+++$$$$$$&&&""" )))(((+++222...$$$&&&---222***+++***,,,000666)))...666SSS555444000222444///,,,---...000///333444666======SSSpppEEECCCNNNBBBAAAEEEBBBDDDBBBCCCDDDFFFQQQZZZ ```eeeZZZaaa6vvvYYYddd~~~cccbbb```MMMMMMXXXLLLNNNQQQ```OOObbb|||fffwwwaaa[[[UUUDDDIII[[[___{{{aaaUUUWWWWWWooofffcccooocccjjj{{{aaa[[[XXXXXXTTT^^^TTTRRRPPPQQQTTTVVVUUUXXXVVVRRRKKKKKKLLLIIIGGGLLLGGG777000...;;;DDDIIIPPPMMMHHHIIIAAAjjj___EEE:::333222<<<:::@@@AAAZZZFFFCCCAAABBB===<<<777@@@<<<>>>??????000+++///666CCCHHHCCC===>>>777;;;:::666555<<<999>>>HHHBBBEEEIII>>>DDDFFF???///***111AAA<<<999AAAAAAGGGFFFJJJJJJ777DDD999===999888///,,,)))******,,,&&&&&&(((%%%%%%((($$$$$$$$$&&&"""'''###"""''')))***$$$=== """"""""")))!!! <<<%%%###$$$'''$$$###111###&&&###""""""###///))) ######***!!!&&&***$$$+++'''666+++***+++666'''---111111...------+++///111***...000999777::::::888555...555222222:::>>>;;;??????===999===BBB@@@>>>CCC>>>BBBEEEDDD@@@GGGTTTPPP```\\\aaaccc\\\WWWaaauuunnnZZZ___xxxfffXXX[[[VVVRRRLLLYYYWWWQQQPPPHHHRRRTTTSSSZZZVVVLLLRRRVVVccc\\\bbbvvvooojjj[[[XXXccc\\\fffgggfffnnndddddd```oooeeeTTTZZZbbbcccbbbfffYYYTTTUUUTTTQQQNNNKKKKKKKKKQQQNNNKKK<<<:::>>>AAAEEEKKKLLLLLLFFFMMMMMMOOODDD???AAA999IIIYYY333@@@PPPOOOFFFBBBGGGDDD???<<>>999444666999>>>???AAACCCJJJGGGGGGAAAAAA111((()))111///KKK???AAA@@@EEEAAADDD444<<<777555444...---+++)))+++******%%%''')))(((#########$$$$$$%%%///"""'''%%%&&& %%%###"""###%%%(((((($$$!!!&&&$$$""",,,000HHH""" )))((("""%%%###"""!!!%%%$$$(((###$$$,,,...'''+++'''$$$%%%...///@@@EEE333---222...---,,,///777222444666555111555444666888DDD555:::QQQ===555999777===@@@???>>>999GGGAAA@@@888GGGFFFIIIDDDRRREEEFFFMMM______uuuiiinnn\\\______bbbUUUYYYUUUNNNIIISSSCCCIIIIIIPPPHHHKKKSSSOOOTTTiii```dddbbb^^^pppqqqsssaaa[[[SSSddd]]][[[___aaa___bbbzzzrrr```fffXXXJJJKKKUUU\\\XXXYYYSSSXXXWWWNNNMMMLLLOOOUUUTTTPPPMMMHHH@@@FFFFFFHHHHHHIIIIIINNN```WWWOOOTTT888===:::DDD;;;===HHHLLLQQQJJJEEEEEECCC:::;;;@@@CCC@@@HHH<<<555333666444AAAAAADDDHHH???>>><<<;;;:::;;;===@@@DDDLLLEEEHHHFFFBBBFFFAAAAAA>>>@@@...///222:::===DDDCCC>>>>>>999888:::999>>>;;;333///...---,,,***---,,,%%%"""&&&&&&&&&$$$'''((('''###%%%###,,,$$$!!!######!!!""""""""""""&&&$$$!!!###***!!!!!!''';;;SSS### %%%(((111333666222888$$$###***%%%""" ###"""$$$"""///***+++(((+++)))'''&&&(((///***((()))222,,,000...444555;;;555000@@@999444555888999???KKK???>>>;;;;;;AAA777444666;;;555BBBOOOWWW>>>???CCCDDDLLLJJJGGGFFFFFFIIIGGGWWWQQQoooqqqSSSNNNTTTTTT[[[```XXXUUUNNNJJJQQQIIINNNLLLNNNRRRPPPRRRJJJ[[[[[[mmm[[[^^^hhheeeZZZYYY]]]iiieee[[[[[[\\\ccc^^^ZZZ```eee^^^lll]]]___mmmhhhXXXUUUQQQPPPWWWTTTVVVTTTSSSTTTPPPYYYTTTVVV[[[WWWZZZTTTNNNNNNCCCDDDJJJKKKRRRTTTQQQOOO^^^MMMJJJJJJHHHiiiAAA;;;@@@GGGIIIEEECCCAAA777AAADDDBBBEEEAAA;;;;;;444EEEIII222:::QQQEEEAAAGGGDDD<<<999===<<<888@@@@@@FFFEEEDDDCCCFFFKKKFFFCCCBBBddd&&&(((111777666888;;;HHHAAA<<<:::999999@@@888888555???000111111,,,000%%%###,,,(((###$$$%%%%%%%%%((((((&&&'''(((&&&"""!!!333 """###&&&$$$###$$$((($$$"""######"""'''222222444555iiihhhJJJ((('''(((%%%###333888III###)))===***)))...%%%***333$$$,,,000...333222222:::999JJJ;;;222333999555888AAA:::DDD999444666:::>>>444999999222333333222<<>>444>>>BBB???EEEIIIEEE222777FFF333///<<>>???>>>BBBEEEEEEDDDDDDDDD<<<@@@666+++((('''%%%%%%666===BBBDDD>>>;;;999>>>555;;;777<<<777FFF999---333'''(((***!!!&&& ###$$$$$$)))+++///''''''***(((###!!!!!!!!!!!!""" ###%%%444'''###111&&&###!!!$$$***!!! ,,,CCC000(((333XXX@@@%%%###%%% ###'''///VVV$$$(((///111)))111...777&&&000---,,,===---111111???888GGGFFF???888<<>>;;;???666333444333333000...333---***EEEDDDJJJ[[[IIIGGGNNNFFFcccTTTDDDTTTIIIJJJRRRZZZWWW\\\^^^dddQQQVVVOOOMMMTTTZZZ\\\ZZZWWWLLLOOOVVVQQQTTTPPPVVVZZZTTTRRRaaaYYYUUUSSS]]]aaaeeeaaa___fffeee```WWW]]][[[^^^ccc```RRRjjjccc___aaa[[[VVVUUUUUUSSSPPPXXXfffTTTWWWWWW```WWW]]]ZZZ^^^WWWSSSYYYNNNUUUQQQTTTTTT^^^wwwSSSSSSSSSQQQUUUIIIEEEKKKNNNLLLJJJJJJIIICCC<<<>>>DDDAAADDDNNNHHHCCC@@@777333666:::AAARVVVNNNppp>>>::::::555<<<@@@<<>><<>>888;;;;;;888>>>888888666777___:::222)))$$$&&&###$$$%%%%%%&&&$$$&&&$$$)))777+++***&&&(((###"""!!!$$$!!!###$$$###%%%333 ######""",,,%%%((('''###LLL777///;;;666'''$$$&&&&&&%%%"""'''""""""<<<(((---))),,,444---222---333///+++///111>>>222KKK666222555777IIIKKK888:::;;;;;;EEEHHHGGGAAA;;;888:::777666333666666333;;;777---666666<<<555555FFFRRRGGGSSS]]]SSSNNNKKKIIINNNPPPKKKOOORRROOOUUU___VVVUUUSSSTTTVVVIIINNNVVVnnnNNNLLLIIIPPPQQQ\\\LLLOOOTTTSSSXXXWWW]]]\\\]]]```dddcccxxxlllddd___^^^\\\___aaa\\\```eeebbbaaa]]]```]]]VVVYYYUUURRRSSSSSSSSSXXXUUUWWWQQQTTTVVVnnnbbbWWWWWWNNNPPPQQQSSSUUURRRUUU]]]]]]QQQVVVOOORRRRRR[[[RRRHHHIIIJJJKKKHHHGGGIIIBBB???BBBCCCBBBDDDBBB<<>>AAALLL888666666888111...)))''''''$$$###%%%555###$$$ )))%%%,,,&&&%%%$$$###""")))######"""###$$$''' """ $$$###%%%CCC+++%%%!!!&&&BBB777***$$$...)))$$$""""""###&&&...===))),,,%%%'''---***---...***,,,222///...222000777DDD===222666EEEDDDFFF>>>888444666IIIOOOOOO;;;<<<===888666444222555@@@OOO999>>>555333888888>>>BBBBBB@@@JJJJJJ___jjjPPPJJJ@@@HHHPPPUUUKKKJJJ___KKKOOOSSSTTTPPPWWWNNNKKKIIIKKKMMMPPPPPPPPP@@@DDDOOOTTTKKKTTT[[[jjj___]]]VVV\\\YYYYYY\\\ccc^^^fffmmmaaa^^^```ggg]]]aaabbbjjjxxxeeeaaabbbaaa^^^WWWVVVYYYbbb]]]RRROOORRRYYYRRRRRRSSSWWWUUUWWWXXXVVVUUUYYYUUUUUUYYYZZZUUUTTTQQQLLLPPPPPPUUURRRJJJKKKGGGFFFHHHKKKIIILLLJJJAAAFFFCCCBBBDDDBBB<<<<<<;;;:::;;;999EEECCCOOOCCCEEEAAADDD@@@;;;888???AAA@@@DDDEEEFFFIIIBBBFFFCCCLLLHHH<<<+++000&&&999@@@@@@CCC>>><<<===>>>DDD<<<999777888444333999111---'''(((%%%$$$###+++(((+++%%%999%%%$$$$$$"""###""""""###$$$### ###&&&"""###$$$ !!!!!!"""%%%$$$!!!%%%(((!!!(((&&&,,,---***%%%&&&'''%%%%%%))),,,---(((...///)))///*********(((%%%++++++999AAAFFF;;;888??????:::888;;;555777666888333111444555>>>???777666,,,///333AAAHHH444AAA@@@EEEGGG???BBBFFFEEE@@@EEESSSTTTKKKWWWPPPQQQMMMBBBLLLMMMEEEWWWRRRUUUUUURRRTTTOOOPPPKKKGGGJJJMMMNNNJJJOOONNN<<>>>>><<<888:::<<<<<<<<>>GGGHHH999>>>>>><<<;;;666888666777777:::999TTT///***...,,,$$$$$$'''&&&&&&)))''''''***)))222!!!(((######$$$---444<<<..."""""")))""" $$$&&&!!!%%%%%% $$$)))))))))+++""")))666)))&&&***///***)))---444((()))(((''''''***000222888<<<@@@888:::222666777888666666555888444777444BBB;;;999555111333222555444666000888:::AAAUUU??????CCCCCCCCCBBBDDDKKKWWWGGGHHHMMMVVVQQQCCCBBBAAAFFFOOOHHHLLLFFFfffMMMIIIKKKVVVFFFHHHKKKHHHDDDHHHDDDBBBIIIQQQSSSPPPaaa]]]ZZZ[[[\\\TTTSSSWWWXXXaaa]]][[[^^^^^^\\\\\\]]]YYY]]]]]]bbbfffiiimmmcccttttttmmmgggaaa^^^^^^ZZZZZZTTTVVVQQQQQQOOOUUUSSSTTTSSSYYYXXXYYYVVVQQQVVVXXX[[[WWWSSSYYYTTTUUUWWWSSSRRRPPPIIIRRRLLLKKKIIIFFFGGGHHH@@@EEEFFFBBB@@@CCCIIIFFFEEEBBBAAA===???999777999===FFFBBB@@@666333333999CCCMMMEEEIIICCCGGGDDD===GGG???777666>>>777%%%HHHQQQTTTCCC<<>>CCCFFFQQQsssYYYTTTTTTWWWBBBKKKIIIKKKNNNKKKRRRLLLAAATTTFFFFFF===HHHDDDEEEIIIIIIAAA;;;BBB>>>EEERRRYYY\\\]]][[[\\\ZZZSSSPPPZZZccc]]]nnn[[[]]]cccbbbbbbggg```ZZZ^^^ddd___bbbhhhiiijjjdddpppkkkkkkllldddeee\\\WWWYYY[[[___SSSTTTSSSWWWVVVWWW]]]WWWUUUOOORRRQQQUUUaaaZZZXXXWWWZZZZZZTTTSSSRRROOOMMMNNNNNNJJJFFFFFFHHHGGGAAA@@@BBBAAA@@@JJJYYYGGGEEECCCDDDAAA:::333555>>>???NNN888;;;<<<555777>>>DDDFFF@@@FFFCCCDDDCCCNNNFFFAAA999333???%%%555<<>>???<<<===<<<666666222555...///)))'''***'''&&&'''***+++!!!%%%!!!$$$$$$&&&,,,)))!!! %%%///"""""""""(((&&&&&&$$$###%%%###"""(((...)))===###!!!%%%###BBB''''''))))))&&&+++%%%(((;;;'''&&&******+++,,,000555222<<<444:::888CCCPPPUUUCCC???===HHH???;;;;;;===;;;<<<888>>>666<<<777000666555444111999AAABBBTTTNNNEEEIIIIIIUUUIII???BBBAAAEEESSShhhUUURRRPPPXXXTTTSSSIIISSSLLLPPPXXXQQQDDDMMMEEE;;;666:::@@@===AAAJJJBBB@@@===DDDKKKUUU^^^[[[WWWXXX[[[]]]\\\XXX^^^^^^XXXZZZZZZ^^^iiixxxmmmgggcccmmm[[[\\\]]]aaaccceeebbbkkklllmmmtttmmmhhhggg```aaacccbbbaaaZZZZZZPPPSSSUUUUUUUUUXXXWWWWWWRRRRRRUUUVVV]]][[[WWWUUU___TTTUUURRRSSSMMMTTTNNNLLLLLLPPPKKKHHHBBBCCCAAA???BBBBBBDDDCCCDDDGGGFFFLLLVVV888555555DDD;;;<<<888666333444888<<>>444444111+++;;;===999===:::>>>;;;<<<:::<<<333111555555***)))(((,,,&&&)))&&&)))&&&%%%###'''%%%(((+++)))$$$000---&&&!!!&&&$$$%%%$$$"""%%%"""'''(((### """&&&$$$(((&&&&&&%%%"""$$$&&&%%%888)))'''(((:::******######((('''$$$(((...000...666555111:::BBBGGGWWWpppOOOAAA444888;;;???GGG;;;@@@===888999444666<<<888...222111888>>>BBB:::PPPHHHKKKMMMEEEOOOXXXIIIJJJCCCGGGGGGHHHMMMMMMKKK@@@IIISSS```TTTWWW```ZZZJJJEEEIIIIIIAAA888222666999>>>AAAAAA>>>CCCIIIJJJMMMNNNWWWVVVYYYWWWZZZ]]]aaa[[[ZZZZZZ[[[VVV^^^^^^bbbhhhdddeeedddeeeeee]]][[[YYY\\\ccchhheeecccmmmfffkkkfffhhhlllkkkjjjllljjjccc]]]\\\XXX\\\[[[VVVVVVWWWWWWSSSVVVYYYYYYZZZ[[[^^^ZZZWWWTTTTTTVVVWWWRRRRRRSSSPPPOOOQQQMMMKKKGGGEEEGGGEEEKKKIIIDDDGGGGGGDDDGGGCCCGGGAAA666666<<<===:::777111000***777===EEEFFFHHHFFFKKKIIIFFFEEE@@@888---,,,111<<<555111>>>???;;;GGGSSS<<<:::888888333222:::))))))'''666+++***%%%######'''### $$$$$$###"""!!!%%%&&&### """$$$((((((***))),,,<<>>EEEFFFJJJIIIGGGAAAKKKLLLQQQ]]]^^^aaaqqqLLLEEEHHHVVVHHH>>>:::777>>>>>><<>>888555QQQ[[[CCCFFF999EEE;;;GGGSSSFFF>>>777999666555777888444333111+++000000///555>>>VVVGGGDDDSSSEEE@@@DDDHHH]]]YYYHHHNNNNNNOOODDDFFFUUUEEENNNNNNGGGVVV[[[PPPHHHIIIKKKHHHFFFAAA<<>>IIISSSKKKMMMIIIFFFMMMRRRGGGEEEFFFCCCEEEAAA999>>>;;;111+++)))111999>>>CCCCCCBBBJJJUUUGGGCCC@@@@@@EEEMMM===<<>>777///***,,,///+++333***---,,,(((### +++###%%%%%%%%%)))999222$$$!!!###((("""$$$"""###---///---%%%&&&'''HHH !!!&&&###"""+++$$$###$$$111###)))((()))+++%%%""" """ ***111------///000222222555<<<===:::>>>AAA@@@[[[JJJ???MMM===@@@;;;999777???888>>>999666444...111...333555GGGCCC@@@===@@@===@@@DDDBBBGGGFFFAAADDD>>>NNNLLLGGGDDDAAA@@@333;;;;;;^^^___QQQJJJNNNPPPHHHEEEHHHGGGEEE@@@HHHKKKKKKQQQUUUXXXRRRXXXSSSUUUXXXYYYVVVTTT[[[WWWsssuuusssfff```___]]]___bbbiiigggccc]]]ZZZ___```cccpppsssyyy* rrrkkklll```bbbgggiiimmmuuuppptttnnnlllqqqsssxxxfffbbb]]]^^^```aaaYYYYYYddd```]]]\\\bbbfff^^^gggVVVVVVQQQYYY\\\YYYUUUQQQQQQBBB;;;EEEMMMLLLKKKHHHHHHIIIMMMJJJHHHFFF??????@@@AAA@@@???444***%%%333888BBBGGGDDDDDDDDDGGGFFF>>>???@@@CCCFFFDDD333***222:::888777:::@@@<<>>AAA<<<:::===>>>GGGIIIHHHKKKIIIHHHFFFFFFBBBGGGKKKJJJJJJOOORRRUUUVVVSSSTTTTTTZZZWWWRRRVVVYYYbbbaaaeeeeee kkkfffaaa[[[___dddbbb___ZZZYYY^^^[[[aaannntttqqqgggzzzttt~~~nnntttqqqgggjjjnnnooosss|||||||||tttmmmrrrsssttt```___\\\___]]]YYYbbb\\\YYY[[[cccbbbgggdddkkk```WWWXXXYYYcccWWW___UUUJJJDDDIIIJJJLLLMMMIIIPPPKKKKKKMMMIIIJJJDDDAAAFFFFFFFFFEEE888>>>---222888CCCEEEGGGGGG@@@EEEIIIEEEFFF;;;???QQQVVV666999NNNEEEEEE888???;;;999:::666666888...///222000)))%%%%%%)))&&&%%%))),,,&&&%%%))))))......111%%%((('''***&&&%%%(((''''''&&&&&&222666&&&$$$&&&***###...&&&(((%%%###"""$$$%%%%%%((()))+++%%%"""###'''******,,,///000222......555888777BBB999??????lllVVV@@@AAADDD777???===SSS::::::666666444333222===888999<<>>???BBBVVV\\\CCCGGGHHHJJJDDDJJJIIIFFFFFFKKKMMMKKKHHHUUUKKKOOOKKKEEE@@@GGGHHHWWWPPPKKKQQQQQQ```XXXRRRUUU___bbbhhhnnn\\\```ccccccqqqlllccc\\\oooqqqiiidddQQQIIIRRRPPPRRR\\\aaammmdddiiiaaa\\\[[[aaarrrmmm}}}{{{uuukkk```kkk{{{yyywwwhhhqqqzzzyyylllfffffflll]]]WWWZZZjjjVVV___YYY]]]___eeeeeeuuuqqqlll___ccc^^^TTTMMMKKKVVVKKKEEEKKKHHHQQQOOOKKKPPPNNNPPPUUULLLIII===@@@FFFCCCAAA>>>333'''333@@@GGGBBBFFFFFFBBBCCCHHH===111555@@@DDDBBBDDD;;;CCCEEEIIICCCBBB>>>FFFCCC??????;;;444777111999777)))%%%'''))),,,)))((()))%%%,,,---***,,,(((((()))$$$$$$'''''''''$$$'''&&&'''&&&***'''"""---000((((((((((((%%%+++###(((&&&+++((('''&&&&&&)))(((***111)))111666222444...@@@===BBBaaaIII;;;OOO===AAAIII>>>???GGG@@@@@@GGGBBBNNN<<<333777777555666@@@???<<<444444CCCMMMAAADDDFFFAAAMMMBBBWWW888>>>AAAJJJeeeVVVNNNIIIYYY[[[QQQNNNHHHHHHYYYSSSGGGGGGIIIHHHHHH@@@???===HHHMMMWWWNNNNNNLLLRRRSSSWWWYYYUUUYYY```_________hhh```ccchhhkkkhhhpppyyyyyyooo]]]IIIFFFMMM^^^iiihhhkkkssszzzuuuiiibbbkkkiiikkkqqqtttuuutttpppuuusssqqq|||rrryyymmmrrr|||qqqlllfffhhhaaa\\\XXXiiihhhmmmaaaZZZYYY]]]```tttqqqyyyttt___aaa]]]UUUOOOQQQQQQEEEIIIVVVPPPNNNPPPTTTQQQMMMLLLLLLIIIHHH@@@BBBIII<<<:::...???BBB<<<<<>>CCCHHHIII===;;;777111++++++***,,,+++%%%(((&&&$$$))),,,***((('''(((***EEE;;;>>>'''&&&%%%$$$+++&&&&&&'''&&&999LLL%%%&&&"""%%%%%%(((,,,+++###'''%%%###%%%!!!&&&&&&)))---***222GGG111999999NNN@@@HHHtttSSS>>>CCC;;;666:::BBB;;;666666::::::HHHEEEEEE999666DDD???333>>>;;;:::888;;;>>>???BBBBBBBBBIIIIIIGGGOOOBBBFFFIII\\\QQQaaaNNNPPPMMMLLLQQQPPPBBBHHHIIIMMMVVVCCC???999999@@@JJJAAALLLOOOMMMGGGKKKNNNPPP]]]XXXTTTOOOLLLhhhtttdddXXXmmmTTTTTTYYYTTTVVVZZZdddbbbbbbbbbaaaSSSVVV^^^hhhkkkxxx{{{ {{{ uuummmbbbeeejjjttt{{{{{{xxx||||||zzzrrr{{{ ~~~{{{pppiiifffdddbbbaaasss___XXX[[[^^^[[[cccppp~~~uuudddbbbaaa\\\RRRRRRMMMOOOGGGGGGNNNZZZOOOLLLMMMOOONNNMMMHHHJJJ@@@@@@AAA>>>@@@>>>oooLLLAAA???DDDBBBIIIDDDBBBFFFMMM<<<222333<<>>;;;555666444444:::TTTNNNIII;;;FFFAAALLLLLLEEE<<<>>><<>>===<<<>>>TTTBBBGGG;;;999>>>444000:::---,,,***'''---,,,///+++(((***&&&(((+++---,,,888^^^@@@...+++(((###)))MMM000''''''000%%%...''''''&&&)))(((333KKK...)))$$$%%%%%%%%%(((&&&(((///+++111666===TTT666___SSSzzz*lllRRRFFFSSSBBB<<<:::777;;;777666111555555YYYEEEEEEVVVrrruuulllRRR???DDDGGGLLLQQQHHHGGGKKKOOOOOOLLL\\\WWW???GGGFFFOOOIIIAAACCCDDDBBBKKKFFFVVVGGGCCC999444555<<<>>>CCCBBBBBBPPPAAACCCGGGNNNUUUUUUUUUQQQTTT[[[UUUOOOVVV]]]QQQUUUhhh\\\\\\]]]^^^bbbfffeeemmmssstttppprrrxxxooo{{{ssslllrrr~~~yyyhhh{{{yyyqqqzzzwwwrrrzzztttyyyuuu}}}xxxsssoooqqqtttkkkfffnnnnnniiijjj```aaaaaabbbggggggmmmooofffhhhfffhhh]]]\\\SSSOOOCCC<<>>777@@@HHHRRR@@@666222///000......,,,555111))))))+++)))&&&%%%(((///++++++,,,+++666666+++(((%%%'''+++III@@@111$$$'''$$$&&&$$$&&&&&&%%%&&&222))))))'''&&&&&&'''### %%%,,,111222<<<777;;;>>>TTTfff[[[lll}}},zzzgggGGGCCC999888===;;;999===222111===:::mmm]]]rrryyy|||lllQQQOOONNNVVV___RRRXXXVVVUUUPPPiiidddKKKHHHPPPYYYZZZJJJNNNEEEBBBFFFGGGAAADDDGGG;;;777333777???===???@@@FFFIIINNNMMMMMMUUU]]]XXXUUUXXXUUUUUUYYYVVVWWWaaaTTTZZZaaabbb]]]```^^^ccc^^^```bbbjjjtttuuuqqqoooxxxyyysssxxx - -~~~# - ~~~ooo|||zzzpppkkkjjjqqqkkkrrrppplllpppjjjkkkkkkhhhmmmbbb```fffhhhuuukkkgggiii~~~rrrddd___UUULLLDDD999@@@QQQPPPOOOWWWQQQQQQKKKFFFAAAGGGKKK___cccFFFDDDIIIHHHDDDDDD???===<<>>@@@BBB@@@KKKLLLRRRQQQSSSXXX\\\]]]XXXVVV^^^VVVWWWYYYaaammm^^^```oooeeeeeejjjgggdddeee\\\bbbiiijjjnnnhhh{{{eeerrrwwwzzz  -1"$|||||| -  kkkdddfffjjjzzzxxxyyywwwrrrooopppnnnrrrkkkbbbeeehhhjjjyyytttiiisssuuupppccc___XXXBBB666999???GGGKKKTTTSSSOOOKKKEEECCC@@@JJJXXXFFFCCCCCCEEEHHHEEE777333??????BBB===DDDIIIIIIRRRUUUPPPKKK===GGGBBBFFFBBB@@@GGGCCCCCCDDDAAAHHH777444555333333<<<:::111111---***))))))+++111((((((,,,***@@@333777++++++000///@@@111,,,000:::...%%%&&&'''$$$&&&+++)))***)))---***///...,,,%%%'''666%%%,,,---000GGGAAADDDiii___fffbbbZZZNNNaaa!oooYYYBBBBBB???<<<<<<===FFF222222999===KKKuuu,+nnnttttttgggpppgggkkk~~~\\\RRRRRRYYYIIIBBBMMMIIIIIIJJJGGGBBB@@@999???222333999AAAGGG???FFFKKKKKKKKKLLLUUUUUUbbb^^^[[[UUUYYYbbbUUUWWW___|||eeennnjjjhhhiiinnnnnnqqqjjjoooggghhhiiijjjpppuuummmhhhttt}}} }}}|||xxxttt}}}!$ *$|||~~~}}}iiifffiiiqqqwwwtttrrrttt{{{mmmqqqssskkkfffiiiqqqpppqqqiiipppkkk}}} dddeeeRRRBBB>>>EEELLLKKKQQQWWW[[[LLLCCC555777GGGGGGYYYCCC<<<>>>@@@888777>>>???AAACCCAAAAAACCCFFFQQQKKKRRRKKKCCC666)))111<<>>>>>999999PPP;;;;;;::::::;;;HHHppp)2" -|||zzzzzz\\\UUUWWWUUULLLPPPIIIFFFGGGIIIIIIEEEDDDEEEGGG666GGG???FFFCCCGGGCCCEEEIIIJJJMMMPPPYYYSSSSSS^^^\\\YYYZZZ^^^aaaaaa```ppplllqqqoooqqqooonnnsssrrrvvvbbbooouuuxxx}}}$ ggghhh\\\)". - ~~~~~~hhhbbbhhhjjjpppuuuiiivvv~~~wwwqqqrrryyyoooooodddwwwqqqyyymmmiiiqqqrrrppplllggglll[[[HHHMMMLLLXXXMMMQQQTTTRRRLLLIIIGGG:::GGGHHHfffNNNGGGBBB999>>>;;;DDDBBB@@@BBB@@@UUUMMMNNN```LLLMMMBBB===)))###777@@@JJJMMMNNNTTTMMMCCCHHH666;;;999DDDRRRMMM:::888000///+++))))))))),,,+++///---+++------///;;;...222EEE******+++'''+++111***&&&&&&)))+++***))),,,---222&&&((((((+++'''))))))&&&---'''EEEIII???JJJHHHQQQ]]]uuugggaaaZZZYYYZZZ___HHHEEE___FFFLLL===888<<>>===DDDHHHGGGVVV65%2.%&  (yyyeeeWWWYYYXXXMMMGGGHHHIIIJJJHHHFFFFFFJJJTTT]]]ggg777JJJ???FFFCCCFFFBBBFFFFFFKKKNNNRRROOO[[[___aaaaaagggkkkmmmcccdddnnnqqqvvvzzzpppuuu: }}}{{{  kkkrrrnnn rrr ~~~jjj```kkkvvvrrrwwwvvvooonnnsssttt~~~vvvsssiiitttqqqkkkeeegggqqqZZZQQQUUUUUUPPPIIIOOOLLLLLLFFFDDD666@@@<<>>:::>>>@@@FFFGGGKKKXXXOOOPPPJJJRRROOOAAAHHHYYY???FFFMMMSSSGGGBBB===BBB???>>>KKK;;;QQQwwwfff555...---///***)))(((,,,111//////)))+++***......eee666000555)))'''&&&'''***///000)))+++///***)))))))))+++,,,(((---(((+++***,,,///***...000111LLLDDD;;;SSS>>>FFFpppeee\\\BBBPPP@@@MMMNNNRRRBBBCCCAAAAAA======888:::===DDDFFFPPPXXXwwwBCA@BI=9GsssdddbbbaaaWWWOOOJJJDDDFFFGGGGGGCCCKKKIIIHHH___PPP666888;;;>>>BBBFFFCCC;;;KKKZZZVVVYYY\\\UUU]]]\\\bbbUUUhhhwwwnnnuuuzzzrrr|||gggsss% )  {{{{{{uuuzzz|||xxx||| -uuujjjtttttt|||{{{~~~wwwyyy vvvooo}}}oookkklllgggcccjjjnnnxxx___SSSQQQKKKJJJEEEJJJRRROOODDDEEELLLJJJ;;;BBBKKK@@@BBB<<<999666<<<999:::FFFGGGTTTTTTWWWUUUTTTQQQDDD;;;<<>>???@@@HHHVVVbbbqqq%WZ\a_]]1sssfffUUUVVVLLLIIIGGGEEEJJJBBB===FFFIIIBBBkkkLLL@@@DDDCCCFFFEEEIIIHHHMMMQQQTTTWWW______ZZZ[[[WWW___bbbhhhzzzxxx~~~tttlllnnnnnnrrrxxx#!5R5 ~~~zzz uuurrr  ppp{{{nnnxxx}}} ~~~zzztttyyywwwyyyuuu{{{tttpppoooccceeedddddd```___jjjfffdddSSSVVVIIIYYYRRRSSSZZZRRR999KKKSSS===999AAAAAADDD@@@444333555333>>>999>>>EEEIIIUUU]]]SSSRRRNNNLLLUUU]]]JJJIIIEEEFFFLLLGGGBBB@@@<<<<<>>EEEJJJXXXdddnnn>>CCCJJJLLLVVVRRRNNNNNN[[[```dddYYY???LLLFFFCCCJJJAAA:::999>>>???<<<<<<:::444444999111222...222555222444///&&&''',,,***222666GGG???NNNbbb000'''$$$(((VVV222+++///---...,,,///444000((()))---...000))))))))),,,;;;000+++222222??????AAAAAA<<<@@@>>>FFF???;;;HHHNNNQQQLLLOOOmmm<<<666888TTT999777:::>>>>>>IIIUUU]]]ttt?cnzztnaC/vvvbbbYYYUUUPPPKKKDDD<<<;;;;;;888;;;,,,***333GGGHHHGGGNNNMMMPPPQQQXXXVVV[[[\\\UUUWWWTTT^^^bbbeee___nnnnnnnnniiiqqqyyy~~~uuuqqqyyy -tttnnnpppzzznnnkkkiiizzziiikkkttteeefffiiinnnqqq~~~|||}}}  vvv -mmmsss ttt}}}rrr~~~ uuu{{{kkkkkkiiilllaaabbbcccmmmnnnkkk]]]WWWPPPMMMOOOTTTUUUSSSMMMJJJNNNDDDPPPaaaJJJUUUKKKFFF@@@666666666666555BBBCCCFFFKKKPPPLLLNNNSSSYYYjjjmmmdddMMMCCCnnnDDDCCC999888:::BBBGGG>>><<<444444444999KKK000777---666555999===...000(((***333555@@@[[[qqqEEE,,,$$$%%%***,,,+++///***...%%%(((,,,...,,,***333+++,,,***+++(((///444<<<---777,,,---::::::FFFUUU<<<666???JJJDDDDDDCCCDDDVVVBBBAAACCC555111666:::888333999>>>???HHHTTT[[[pppCdr~tnbK/ {{{fffWWWSSSUUUJJJCCC:::;;;999777111***MMM>>>JJJNNNXXXRRRVVVbbbfffeeecccgggZZZbbb^^^___cccbbb\\\YYYbbbqqqhhhpppxxx {{{~~~ - zzzvvvsssvvvuuupppxxxwwwzzzmmmaaa^^^cccccciii```wwwwwwvvv -{{{wwwwwwbbbxxxmmmyyyvvvyyy -xxxjjjxxxvvvyyyzzzyyy}}}mmmoooeeeaaa\\\dddooorrrfff]]]YYYTTTRRRTTTTTTRRRPPPQQQKKKVVVIIIMMMQQQOOOQQQOOOHHHHHH;;;>>><<<;;;===@@@BBBEEEJJJQQQOOOSSS___^^^```YYY\\\ZZZWWWBBB@@@<<<888;;;WWWFFFOOO???999666555333EEE000000...333;;;444,,,222(((...???333777111222CCCWWWIII+++###***'''...,,,,,,...'''---###'''&&&(((///---)))((((((+++///+++...111111***333===BBB@@@BBBBBB888777>>>>>>AAA???EEEOOO???777888GGG333111111222444666<<>>===555BBBpppQQQUUUUUUbbbdddgggbbbiiiiiiaaaeeejjjeee```iiijjjhhhjjjffftttkkknnnrrr"|||~~~ |||{{{oooeeeiiitttzzzvvvlll^^^aaafffnnnqqqsssqqqoooqqqlllsssooo~~~yyy{{{gggccc{{{zzzzzz -qqqmmmzzz zzz___gggdddcccrrrhhh```aaa]]]XXX]]]XXXPPPXXXXXXVVVPPPTTTOOOLLLOOOOOOPPPLLLJJJHHHAAA>>>@@@===???DDD===CCCrrrMMMXXXRRRTTT[[[WWWVVVGGGHHHjjjAAA777444;;;;;;```LLL@@@;;;???AAAAAA666111222222888000)))222777999JJJ333777...111111>>>111GGG---===++++++***///---<<>>888666777<<<666333000111111111444333:::999@@@AAAKKKTTT\\\iiizzz3dmnuqfT6iiieeeaaaXXXPPPBBB:::BBBDDDCCC>>>999DDDCCCIIISSSUUUXXX___oooxxxpppwwwffffffmmmbbb[[[ggggggdddtttzzzxxxvvvnnnrrr #"& rrrxxxtttfffaaa]]]___jjjttttttrrrooogggfffooouuuvvvxxx{{{yyyqqqppp}}}ooouuuvvvzzzxxxrrreee|||||| }}}WWW }}}wwwxxxwwwrrrbbbhhh ooooooiiiccc[[[YYY^^^```RRRTTTUUU\\\RRR\\\QQQMMMNNNKKKUUURRRNNNPPPAAA>>>AAA???AAA>>>BBBIIIPPPKKKPPPSSSYYY___eeeXXXOOORRRDDDFFF999666666666FFF>>>BBB<<<<<>>ooo777666...222666555111777...???555333333JJJ999111---))),,,:::777===>>>222///;;;######'''###'''&&&"""&&&'''+++...,,,+++---)))...000555:::000777>>>;;;NNNNNNEEETTTdddBBB:::;;;666666999111...111>>>888444444::::::BBBIIIPPPOOO\\\rrrAMY`xxgL4|||]]]YYYVVVLLLEEE???DDDLLLTTTEEEDDDIIIJJJHHHJJJQQQYYY[[[```llluuurrriiiaaa[[[ |||{{{ppprrrjjjssswwwpppyyy  "(~~~mmmvvvoooiiiaaa^^^kkkrrruuu{{{uuurrrvvvpppjjjnnnxxxxxxzzz}}}yyyzzz{{{pppzzzuuuzzzvvvxxx sssrrr~~~  -xxxgggvvv vvvxxxnnniiijjj&#rrrmmm{{{jjjYYY[[[lll[[[LLLVVVVVVOOOQQQTTTTTTQQQPPPNNNUUUkkkNNNMMMFFF777CCCCCCDDDDDDCCCLLLLLLJJJQQQZZZ^^^mmmaaa\\\TTTPPP444***333999>>>999555::::::DDD??????@@@>>><<>>888;;;HHH???666999777BBB+++,,,)))000888222333000666888DDDAAAEEEMMMSSS"!'AQnsPP# ppp___[[[OOOFFF@@@BBBJJJKKKIIIRRRMMMOOONNNQQQRRRUUUVVV```mmmfff}}}hhhfffZZZZZZlll~~~zzzyyynnngggnnnmmmcccuuu~~~ lllXXX[[[fffmmmooohhhppprrroooyyy{{{||||||~~~xxxzzzxxx{{{}}}}}}xxxsssccc||||||{{{ooobbbfffvvv}}}|||()~~~iiillllllmmm' iiiuuupppdddYYY^^^YYYOOOLLLQQQVVVYYYhhhUUUOOOVVVTTT[[[RRRQQQPPPMMMUUU>>>FFFCCCBBB@@@FFFIIIIIILLLRRR]]][[[mmmkkk```___OOO000(((///333555<<<777333<<>>EEELLL666444111------222///...<<<...)))(((+++888222333000777;;;GGGCCCEEELLLoooeeeooo4LMTH2jjjbbb^^^SSSWWWKKKIIICCCHHHMMMKKKKKKJJJKKKQQQNNNTTTjjj{{{xxxuuuqqqjjjnnnmmm{{{|||vvv{{{|||wwwssslllmmmgggvvv |||zzzyyyuuuooonnnnnneeemmmlllpppssstttwwwzzz |||~~~ -~~~~~~{{{ ~~~}}}iii~~~wwwhhh[[[jjjbbbuuu-Jxxxhhhnnntttyyynnnkkkppplllggg\\\UUU\\\nnn|||RRRTTT^^^```\\\RRRRRRTTTVVVSSSQQQ]]]LLLfff>>>;;;:::@@@AAAEEEHHHFFFXXXQQQdddkkkaaaeeekkkfffTTTOOO<<<444000<<>>888888777777111///)))///******,,,---,,,---))))))444666000222000OOO>>>>>>444777000---...???$$$'''&&& !!!###%%%&&&'''***---///......000666888666444000::::::888333333///111+++***))),,,///000///111+++111;;;444555555999EEEBBBQQQxxxNNNKKKVVV --(-3%&~~~iiiZZZFFFIIIEEEHHHEEENNNLLLKKKKKKWWWSSS^^^___aaajjj~~~rrruuukkkzzzvvvuuuyyyzzz yyynnn}}}xxx||| - - |||zzzuuurrrrrrrrrttt}}}zzz|||}}}vvvyyy{{{~~~ - -  zzz -   ppp -|||zzzccc[[[^^^'+ vvvkkktttiiiiiijjjllllllxxxeeejjjkkkZZZLLL^^^GGG[[[YYY\\\XXXSSSTTTSSSOOONNNNNNLLLMMMNNNAAA555777PPPPPPEEEDDDMMMQQQOOOfffvvv{{{dddYYYUUUrrrllluuu;;;555777;;;777777:::>>>===<<<===>>>222222444555///***,,,***+++---...'''+++///222???[[[444888444FFF===NNN444999---,,,AAAXXX### &&&""""""((($$$&&&(((***///---,,,///333===444777555222444AAAAAA333000///000---)))000111000000000111222222///444///222======ZZZMMMIII>>>```tttttt}}}|||aaaUUUPPPIII???GGGOOOKKKRRRdddbbbccchhhjjjZZZhhhssslllmmmooouuu{{{rrr~~~vvvzzzzzzjjjbbbeeeeeefffyyy yyy -kkkhhhtttwww  ~~~zzzzzzyyy}}}}}}~~~|||  - -  ooottt vvv___QQQpppttt{{{ -yyytttmmmnnnnnnggg\\\bbbgggjjjkkkaaa]]]VVVCCCIIIVVV^^^eeeLLLGGGRRRRRRTTTWWWUUUPPPOOO@@@;;;<<<888CCCPPPGGGGGGCCCKKKWWW___fffbbb[[[XXXVVVbbbwwwXXXMMM555777;;;000333;;;999666;;;===888999<<>>hhhJJJ999---...+++...888"""###'''###***%%%&&&))))))+++,,,,,,)))(((+++000333888555888555999222222333111666...111<<>>WWWNNNNNNRRReeejjj^^^[[[SSS___```lllkkkppprrr}}}ppp|||qqqyyyffflllooohhhhhhkkkgggnnnwww {{{|||uuujjjrrryyyyyysssjjjpppzzz  }}}}}}|||~~~yyyyyyxxx}}} -    -~~~rrrffflllxxx|||}}}|||kkkXXXqqq|||nnn^^^eeeqqqiiibbbhhhgggkkk|||mmmZZZ\\\HHHEEE]]]hhhfffkkkeeeSSSZZZUUUgggjjjYYYUUUKKKCCCGGG:::DDDGGGIIIMMMLLL@@@OOOWWWSSSTTTddd^^^\\\UUUXXXTTT;;;@@@CCC666666???555444000111AAADDD<<>>===gggMMM666***---...000...###"""!!!&&&,,,&&&)))((()))***///***...888111---000222555777333666000777///111000...///))))))+++,,,333///444222...222,,,;;;JJJ666777999DDDAAA>>>BBBEEECCCLLLNNNKKKTTTYYYXXX```WWWQQQqqqMMMJJJPPPZZZQQQZZZaaajjjfff\\\hhh[[[eeefffmmmttt{{{tttppppppnnnhhhgggiiikkkaaajjjpppqqqooo~~~|||}}} {{{zzz~~~}}}kkkxxxooorrrzzzuuunnn|||~~~}}}}}}||||||}}}~~~|||~~~wwwwwwsss}}}   -rrrnnnsssvvv}}}nnnSSSggg -~~~uuucccTTTdddkkklllkkkgggvvvkkk```]]]\\\PPPOOOXXXccchhhkkkgggYYYSSSXXXPPPXXXSSSTTTLLLDDDEEEFFFIIIbbb:::HHHtttAAAGGGLLLZZZ___jjjbbbbbb^^^LLLAAAYYY@@@444444666>>>666888666222888999;;;<<<888666222000+++***---222777555222222:::===:::ooo~~~111$$$EEEOOOMMM:::EEE444777999555###"""&&&'''&&&%%%''')))$$$%%%666DDDHHH999333777111///;;;000;;;===444444444666+++---((((((+++)))******...,,,+++...222DDDDDD666888:::BBB???999BBBDDDBBBEEEOOOLLLOOOOOOZZZ\\\]]]UUU^^^ZZZllliii```VVVSSS___aaannntttsssoooccciiiuuuuuuxxxvvvqqqkkksssddd^^^SSSQQQSSS```fffdddqqqzzzvvvuuu}}}|||{{{vvvssswwwxxxyyysssggg}}}xxx}}}{{{|||{{{tttooottt{{{|||yyy   -zzztttuuuyyyuuu}}}ooojjjmmm1||| iii{{{nnniiijjjlllkkkhhhiiiddd[[[]]]VVVUUUaaagggdddbbb\\\^^^WWW\\\[[[SSSQQQLLLBBBFFFKKKLLLaaa[[[888EEEGGGHHHIII```yyyiii[[[ccclll___UUUAAA???@@@:::999CCC<<<::::::333888CCC999888999:::444+++000(((000&&&---III333...333:::UUUccc}}}DDDFFF:::>>>III:::XXX[[[999666111!!!!!!"""$$$&&&&&&***(((+++(((<<>>;;;666888555;;;MMMUUUQQQNNNQQQaaauuujjjccc[[[___[[[]]]ooo^^^___```jjjgggjjjxxxhhhtttkkkkkkpppvvvqqqxxxyyyyyyjjjzzz\\\VVVMMMUUUVVVeeeeeennnzzz~~~{{{xxx{{{zzzooopppggglllvvv}}}qqq^^^rrryyyxxx}}}uuu{{{wwwvvvvvvssssssppprrrtttrrr{{{}}}   |||ooowww}}}|||vvvuuu}}} -  kkklllsssyyy{{{lllfffhhhuuuaaa[[[dddZZZWWW___ccchhh\\\ccc___fff[[[\\\OOOSSSOOOMMMKKKKKKWWWyyycccGGGOOO???HHHNNNYYYgggaaa^^^WWWUUUFFFCCC000DDDIIIDDD;;;777666;;;===000222333777666:::FFF...---******))))))555333111<<<555BBBOOO^^^FFF<<<,,,222KKK???>>>CCCGGG777+++(((!!!#########'''$$$))))))###...---000333@@@999MMM777//////,,,000,,,<<<...---111222///,,,***)))++++++(((,,,///***FFF@@@000...000888222555666...555CCCPPPTTTRRRPPPMMMIII^^^\\\WWWbbbhhhYYY___ccceee^^^yyyyyyxxxyyyoooxxxmmmuuuwwwpppdddhhhfffppprrrrrr{{{aaa[[[cccxxxvvvxxxxxxzzzwwwwwwsssllliiipppsssjjj{{{qqqsss___```eeerrrrrr{{{  wwwmmmyyyuuu}}}yyy~~~{{{|||   pppbbb___lll{{{yyyfffbbbhhhmmmZZZ]]]\\\ddd[[[bbb]]]jjjXXX^^^[[[cccdddMMMCCCYYY[[[OOOMMMiiiyyy[[[777BBB999IIIVVVMMMTTTVVVfff[[[[[[OOO:::222SSSOOOKKKIII???;;;;;;666444888///444;;;333777111000------222---444000,,,+++:::@@@EEEWWW<<<***&&&---333333;;;<<<555666777...***)))$$$&&&$$$%%%&&&)))((('''...+++111BBBNNN:::999333444999333444999RRR888,,,*********)))'''###(((///+++///---???;;;...---000888...---///222666;;;HHHQQQSSSRRRVVVVVVHHHaaaSSSbbbZZZooopppeeennniii-"% uuuwwwaaassslllrrrmmmgggfffrrrnnnxxx{{{zzzyyyrrrhhhmmmzzz}}}~~~ -sssoooiiiiiimmmvvv|||ttt~~~yyydddgggrrrrrr{{{{{{ssszzzyyy~~~!"" ! ~~~uuuyyyyyyiiiqqq}}}}}}~~~ qqqcccYYYdddiiiyyyddd\\\UUUZZZWWW\\\fffkkkddd\\\aaabbbgggjjjiiiVVVTTTCCCKKKOOOLLLLLLXXXoooyyyiiiSSSQQQ888;;;???BBBAAA===QQQaaahhhPPP---AAAaaa[[[HHHEEE???>>>777555///333666333===;;;///333......,,,...000111444,,,333:::>>>SSSAAA444(((***&&&//////222777...222EEE888%%%"""!!!!!!'''$$$$$$$$$999zzzEEE111CCCLLLnnn;;;555000>>>===000...111111111*********+++((((((%%%((('''++++++999000......---555///---///333333777IIIJJJJJJQQQWWW[[[\\\ -zzz[[[WWW\\\]]]WWWdddhhhiiiwwwmmmfffdddRRRdddrrrmmmeee[[[___uuu! xxxuuuooo```jjjvvvuuuvvvxxxyyy}}}rrryyynnnuuuccckkkxxx vvv{{{vvvssswww}}}}}}}}}yyywwwnnneeepppttt "#$#  {{{}}}yyyjjjmmm~~~|||~~~}}}uuuuuu[[[^^^^^^ccckkklll[[[ZZZ\\\___gggfffaaaYYY\\\nnntttooossszzzNNNWWWVVVSSSVVVHHHBBBRRRYYYyyyZZZ___;;;111---666DDDCCCSSSddd```>>>999FFFKKKEEEOOOBBB???@@@555222333666888333///555000333,,,(((///555<<<,,,333000AAAFFFGGG???666KKKNNN666111555---)))000++++++...+++%%%$$$(((((($$$)))''''''GGGPPP:::JJJWWW>>>777777>>><<<888666555//////222111,,,///)))...(((&&&%%%&&&)))---000+++)))'''//////...444555444888111666<<>>===CCCBBB;;;:::444555777666666444111444111000///...333000...888FFF>>>HHH===CCCKKK===444EEE---000,,,+++(((***+++***&&&'''+++###((()))$$$...(((***...,,,@@@EEE888===VVV===>>>WWW>>>@@@,,,//////444)))000)))+++'''***---)))(((,,,555******)))---:::111......111666333111BBB:::FFFFFFUUUPPPXXXiiiIIIKKKUUUMMMVVVWWWcccuuu|||iiixxxppp```fffrrrtttrrrqqqjjj___aaayyyxxx &rrruuummmpppyyypppppp___XXXnnn -~~~nnnxxxaaammmooouuu}}}}}}}}}xxxssstttyyyvvvvvv|||yyy{{{{{{}}} ##('''()''%" -wwwxxxppphhhuuu~~~yyy{{{gggeee]]]^^^mmmdddlllxxxmmmhhhggghhhkkk]]]jjjlll|||yyysssqqqhhhfffSSSWWWLLLIIICCCVVVSSSOOO888:::777***)))000:::999999GGGQQQKKKLLLUUUFFF:::<<>>===@@@FFFNNNUUU******+++'''))),,,,,,)))+++)))+++(((999"""+++---&&&(((&&&---222000///---777666@@@CCCLLL888777888>>>...---...***---(((***((()))$$$&&&---333,,,,,,***(((,,,,,,...***)))))),,,)))444777555===KKKOOOHHHQQQZZZYYYBBBAAAHHH>>>TTT[[[dddfffggggggbbbfffddd___dddkkkxxxzzzmmmWWWBBBWWWuuu~~~rrrsssnnnnnnnnnuuu}}}nnn```TTTggg|||ppp```___hhhnnn]]]jjj xxxxxxzzzppptttwwwuuuxxx||| yyyxxx - #%$')**+,,*+)&$~~~wwwuuuiiikkkrrrxxx~~~{{{vvvrrrkkk```ZZZlllnnnyyywwwgggzzzkkkooooooooo^^^vvvxxxpppjjjccckkk^^^VVVZZZQQQ^^^gggdddIIICCC&&&)))+++'''++++++000666YYYGGGPPPGGGCCCVVVAAA222333000(((222;;;444888444000777333===999666<<<777555222EEE222444555cccBBB>>>MMMJJJ777(((222:::***,,,---777)))&&&''''''%%%)))######)))444&&&)))000000666222///333KKK===???777666666SSS999444111000......(((...,,,)))'''000555...))),,,***)))'''---000***%%%&&&+++...666777777???GGG@@@FFFMMMQQQOOO===CCCVVVTTTccceeevvvooorrrdddaaaZZZ\\\aaavvviiimmmjjjVVVJJJEEEXXXZZZhhhhhhuuuoooooowww -yyymmmggg]]]gggnnngggiiijjjhhh```kkkaaabbbrrrtttxxxmmmrrrtttxxxwww{{{  &#$)+-0//..-,)&   rrrmmmfffYYYlllyyyyyy|||~~~pppyyyjjjfffddd```eeennn{{{|||rrrxxxzzzlllddddddccc___gggllleeeaaakkkhhhcccZZZUUUPPPRRRYYYMMM???EEE===555111000***///888???EEELLLLLLKKKLLLQQQIII111++++++444999888777999===999888888@@@;;;999222666888555(((***333===ZZZ666666999111222***---///---///***,,,%%%"""!!!&&&'''%%%444###111222...---))),,,+++))),,,...555???666222@@@===555MMM888222RRR+++<<<...---...***(((000((()))))))))++++++%%%)))...***++++++777III<<<===KKKCCC???HHHUUUNNNUUUYYYvvvNNN^^^xxxeeejjjuuurrrkkkccc\\\YYY\\\ffffffggg___TTThhhjjjdddUUU\\\tttvvvooovvvkkkrrrsss{{{www}}}rrrlllfffcccuuuooobbbdddqqqnnnjjjddd\\\___rrryyynnniiirrrxxxyyyxxxzzz - -  !$&&*-/022110/--'$   tttmmmpppdddqqqyyyyyy{{{|||~~~yyypppnnniii^^^UUUhhhooorrrqqq|||lllmmmfffeee^^^______bbbfffggg```aaajjjbbbWWWPPPUUURRRTTTNNN???>>><<<@@@888777:::<<>>CCCQQQZZZYYYaaaYYY[[[eeeXXXtttnnntttnnnqqqiiibbb]]]ZZZ^^^\\\jjjbbb^^^VVVlllrrr______gggqqqmmmmmmpppzzznnnooolllllljjjiiigggdddmmmeeeffffff^^^eeeiiillloookkkhhhssspppaaapppuuuvvv}}}yyy~~~wwwiii  !#$'().0234653110.*'# |||uuuppplllyyy -}}}qqqvvv|||yyyrrrcccTTTeeewwwrrriii___vvvppplllddd\\\___^^^bbbuuuccclllhhhpppmmm]]]]]][[[SSSPPPQQQPPPEEE===:::777<<>>VVV:::666;;;:::EEE666AAA000,,,000$$$###'''''')))999+++(((''',,,%%%,,,888222666:::===AAAGGGDDDEEEFFF^^^]]]\\\fffYYYMMMfff```rrrkkktttfff^^^___\\\YYYYYYZZZYYY\\\XXXeeeaaavvvkkkkkkmmmuuuppp{{{kkkmmmmmmfffgggeeehhhfff]]]UUUZZZVVVqqq```kkkuuummmqqqnnnooojjjkkkeeegggtttzzzuuuxxxyyyxxxlllgggzzz!"%%((.24666776311/-)%! - yyyvvv{{{}}}yyylllwww~~~wwwrrrlll[[[ggg[[[\\\iiiaaawwwmmmtttuuu\\\^^^bbbbbbgggfffrrrwwwmmmYYY\\\QQQMMMLLLOOOOOOKKK>>>;;;999===???GGGGGGCCCIIIQQQ[[[TTTQQQ;;;'''000>>>BBBAAA@@@DDD@@@FFF:::666===CCC777:::CCCEEEHHH;;;UUU999HHH???HHH;;;bbbSSS000666111555***---333))))))((($$$(((''',,,###$$$;;;###+++HHH)))%%%'''...333///111000:::444DDDDDD:::BBBXXX@@@:::BBB;;;PPP>>>+++&&&...111$$$$$$)))'''''')))'''%%%)))&&&,,,...;;;<<<>>>777GGGEEECCCDDDFFFQQQXXXZZZ[[[[[[WWWEEEVVVMMMSSSlllhhhfffbbbaaa___]]]VVVTTT[[[WWWTTTdddhhhbbbhhhuuufffiiiccc|||jjjkkkjjjjjjfffnnnggg___]]]XXXVVVaaagggllluuuooorrrtttiii^^^___VVVmmmvvvzzz{{{zzzxxxlllvvv~~~#''(.2569898::9641,.+&$ yyyuuusssvvvhhhqqqzzzpppjjjqqqvvvvvvooo\\\jjjVVVUUU```bbbrrrooonnnlll``````fffZZZaaaqqqpppsss{{{kkkVVVXXXUUUNNNIIIMMMIII>>>;;;777999BBBFFFJJJWWWCCCCCCGGGOOO___dddFFF555666III@@@???EEE@@@AAA@@@222222888>>>===dddEEEAAANNN>>>AAAEEE;;;;;;???===UUUBBB444111666111111222999444///)))%%%&&&((($$$((()))&&&###)))000DDD))),,,111...,,,000///:::555>>>BBBNNN999777;;;777;;;:::999000333,,,+++'''$$$''''''&&&((((((&&&(((++++++...666444>>>???AAA@@@GGGDDDCCCKKKMMMOOO]]]XXXQQQGGGEEEHHH```]]]```lllbbb[[[WWWQQQUUUKKKOOOZZZRRRWWWXXXcccccc\\\uuunnndddcccfffiiikkkkkkhhhhhhfffeeeaaaQQQ[[[[[[fffmmmllluuu{{{~~~wwwqqqjjj|||iiihhhiiiuuuxxx~~~{{{xxxkkklllsss{{{  &'++37:<=?>=>=<<;9520-)% ~~~wwwpppkkkvvv|||ttt\\\nnnppptttkkkqqqpppoooqqqqqqkkkuuuxxxyyytttoooccc\\\^^^```hhhuuuooobbbZZZNNNKKKKKKIIIIII888>>>888===999III@@@DDDPPPNNNLLLFFFQQQiiiOOOEEE===999CCC@@@;;;BBB@@@BBB333111222;;;999LLLiiiJJJjjjHHHDDDCCC===<<<:::NNN<<>>444***,,,888333000,,,333<<<===EEEGGG<<<;;;OOONNN666222000...,,,,,,...,,,***&&&&&&******;;;222//////222@@@>>>@@@BBBDDDHHHJJJKKKJJJIIIJJJGGGKKKGGGDDDGGG:::>>>]]]mmmfffdddfff[[[gggQQQKKKSSSbbbVVVVVV\\\aaaQQQYYYWWW]]]|||dddeeeeeerrrnnnfffwwwfffgggcccVVVQQQ]]]___lllpppgggqqqwwwyyyzzzooojjjssstttsss{{{||||||wwwlllaaahhhttt||| -#*+/5;=@ACCCBBA?>>;863.+'  |||rrrhhh|||~~~ssskkkaaatttbbbqqqooorrrvvvsssuuuxxx|||zzzooojjjzzzwww^^^kkkiiiiiirrrjjjooolllaaaqqqRRRGGGEEE;;;333000222999<<<444888<<>>;;;CCCYYYIIIAAA888222888@@@===kkknnnLLLEEE??????@@@===666BBB888>>>>>>:::555333...+++???,,,***(((&&&&&&%%%$$$%%%(((&&&###%%%###$$$###%%%666222,,,---+++,,,222111...555===<<<<<;961.*% -zzzqqqqqqvvvmmmkkkuuurrrnnnvvvrrr|||rrr~~~yyysssoooiiivvvnnnuuukkkjjjggghhhqqqpppiiiggg[[[RRRaaa:::000111///666;;;999;;;LLL@@@???AAACCCAAACCCAAAFFFIII>>>)))222???NNNOOOGGGBBB<<<555AAA===UUULLLCCCMMMRRRGGG>>>???;;;;;;>>>>>>AAA@@@111DDD<<<222///222(((((($$$&&&$$$###&&&(((&&&$$$$$$%%%&&&&&&"""(((***<<<999)))***222444III111777888666888<<;82.,#  vvvrrrqqqooozzzxxxsssyyyssstttooommmzzz -qqqlllhhhsssuuu~~~pppgggjjjmmmwwwiiidddZZZOOODDD;;;AAA777//////444888CCCHHHFFF@@@:::???BBBEEEBBB>>>===888!!!333BBBPPPGGGDDDGGG===DDDBBBLLL^^^GGGAAAKKK>>>???@@@<<<888CCC@@@AAALLL333000666333777<<<,,,+++***)))&&&'''###%%%$$$######"""(((&&&"""%%%'''...111@@@......<<>>XXX666777777???//////,,,((()))(((...///999444;;;BBBGGGFFFBBB<<>>CCCGGGBBBBBBEEE888+++111:::???BBBAAAGGG@@@;;;BBB>>>IIInnnAAA;;;CCCIIIBBB555777222<<950,$%"yyymmmvvvnnnzzzwwwooofffjjjpppttt &|||{{{bbbaaafffgggjjj{{{rrrsssddd[[[OOONNNCCCGGGBBBBBB:::555999======::::::AAACCCCCCDDDDDDKKKHHH@@@222DDD>>>NNNJJJMMMAAA;;;;;;???<<>>===AAAGGGHHHNNNGGGAAA???GGGSSS\\\]]]XXXQQQUUUdddaaaiii|||gggggg___```fffnnnTTTSSS^^^SSS[[[WWWaaavvvpppoooccceee```cccgggfffcccgggppplllffffffiii]]]jjj^^^ccc]]]nnnwwwwwwvvvuuu}}} ooouuujjjkkkjjjmmmvvv{{{|||}}}xxx "&+/27=BHKNPSUWXXWVTROMIE@=82.(&% - ~~~vvvmmm~~~zzztttwwwmmmhhhoookkkkkkvvvzzz  -|||vvvbbbddddddgggiiikkkuuupppiiicccZZZPPPIIIDDDEEECCC???AAA333999???:::AAAKKKCCCGGGIIIFFFIIIJJJSSSDDD===HHHLLLOOO```LLLDDD666;;;999888111000111444888999;;;:::<<<@@@555BBBBBB>>>===888***---'''(((%%%&&&***((()))111%%%###&&&###%%%$$$'''---!!!"""&&&***222)))111NNNnnnAAAFFFRRRGGGCCCNNNCCC<<<555:::...///---222---666+++((())),,,222GGG::::::555<<:40*$ -|||wwwvvv|||{{{zzzwwwrrrkkkcccbbbdddttt uuu```bbbccccccllljjjvvvzzzmmmfff```WWWGGGCCCAAAOOO???AAA777666;;;AAA<<<;;;DDDAAATTTIIIGGGHHHHHHBBB???BBBGGGJJJSSSWWWNNNKKK666???888;;;JJJ---)))///444;;;BBBdddaaaDDDAAA???HHH:::222===,,,+++***BBB'''***000,,,((((((&&&$$$))))))""" ***$$$)))+++888666>>>///333RRRKKK:::AAABBB@@@___III???777222///---@@@))))))///***)))''''''+++ccc777777666>>>@@@;;;>>>JJJVVVKKKNNNQQQOOO]]]^^^ddd```RRRccc```sssrrrxxxmmmYYYVVVUUUSSSTTTSSSWWWWWWUUUWWWXXXUUUUUUggguuu___aaa^^^dddbbbiiikkkhhhxxxbbbiiihhhiii```\\\]]]gggccc~~~dddhhhlll|||qqqnnnooovvvcccmmmvvvuuu}}}}}}}}} xxx &(+/6=EIMRUX[^_aa_\XVTOLIE@;4.+& |||{{{nnnzzz}}}xxxqqquuummmhhheeehhhnnn}}}~~~pppjjjiiifffffftttvvvzzzhhhqqqddd```VVVOOOIIIHHHGGGBBB<<<666>>>888888999;;;???EEE@@@DDDJJJJJJGGG>>>555FFFLLLSSS\\\OOOFFF<<<@@@@@@:::999:::,,,+++777999DDD<<>>555333444222///***---***)))'''$$$!!!###%%%###  '''((()))111---222<<>>EEE\\\888///+++555,,,)))(((%%%***&&&)))******&&&)))999III555@@@===GGGHHHIIIKKKHHHWWWWWWyyyYYYgggjjj -nnnpppfffdddTTTTTTMMMMMMKKKNNNRRRRRRWWWRRRUUUUUUYYYkkkccc^^^\\\eeeaaa]]][[[ddd mmmuuukkkXXX]]]fff```ffffffrrrmmmvvvlllYYY^^^NNNZZZmmmqqqzzz}}}~~~zzz~~~ %()/:@GJOUY\_bcddb_][VSNLFA;51+&! -|||yyytttxxxtttvvvlllpppyyymmmlllhhhiiijjj~~~zzz|||ssspppqqqggghhheeehhh iiifff]]][[[SSSOOOKKKGGGEEECCCFFFMMMAAA555888===:::>>>@@@AAAMMMIIIQQQGGG999***???JJJZZZSSSKKK===???AAABBB555777///333222333777777]]]DDDTTTKKKUUU```CCCAAA///444///111,,,'''222,,,&&&'''$$$%%%%%% ###!!!$$$"""111&&&((()))000:::666>>>___ZZZ<<>>999777AAA???===BBB???@@@FFFOOONNN???---FFFJJJOOOfffLLLGGGAAA>>>???666222666888777;;;>>>;;;???GGG???PPPHHHMMMgggEEE333---;;;///%%%###***,,,++++++'''000&&&%%%""" &&&$$$"""+++++++++,,,666666EEEJJJgggTTTPPPEEEHHH>>>@@@AAA;;;///111******)))%%%""""""((((((......,,,333000000OOO@@@BBBBBBLLLGGGHHHTTTaaaUUU\\\TTTlll___zzzjjj]]]jjjuuurrrgggaaaXXXXXXVVVMMMFFFRRRSSSXXXXXXmmm\\\```[[[ZZZ___^^^^^^___WWW___kkkuuujjjkkknnniiihhh___eeejjjrrrrrrooossspppsssbbbhhhjjjtttyyyzzzyyy||||||yyyzzzzzz{{{ $'+16>><<<<<<>>>MMM444FFF@@@EEE7hhh888///444---)))((((((,,,<<<000(((%%%###$$$ 444###'''***)))///222BBBTTTcccsssAAAEEEIII999<<<:::GGGBBB222++++++...'''###!!!((())),,,---***+++,,,::::::sssAAA===EEEFFFHHHIIIPPPXXXOOOWWWSSScccmmmnnneee]]]KKKXXXmmmssspppaaaZZZUUUUUUUUUNNNRRRTTT^^^aaa~~~bbbaaa```pppTTTiii```qqq```]]]^^^ccc{{{ooohhhhhhjjjXXXeeellliiikkkwwwrrriiicccxxxfffmmmzzztttfffsss|||~~~}}}|||}}} !$%.3:@DKPTX_ciotrplhb^ZUQLFB=71,&  -yyyxxxvvvzzz}}}{{{uuuggghhhhhhzzzjjjhhhnnnyyy{{{yyyqqqqqqmmmxxx]]]```eeeuuuzzzdddccc\\\]]]TTTZZZbbbQQQTTTLLLFFFDDDDDDHHHGGGCCC666///...)))777BBBDDDCCC>>>>>>999BBBDDDJJJGGGFFFMMMMMM===:::888999;;;EEEDDDJJJJJJEEEIII@@@AAA444EEE999NNNbbb777999)))///,,,000%%%(((111)))$$$!!!###$$$"""!!!"""444AAA+++===...///444<<<^^^rrraaabbbMMM666999GGG@@@999333111+++((('''%%%!!!$$$%%%555((((((111///222000999???DDD===BBBPPPHHHRRRIIIKKKHHH[[[===QQQppp NNNBBBNNNOOO```ooo___ZZZYYYWWWVVVsss\\\\\\UUU^^^___pppccceeeddd^^^^^^\\\___hhhccc^^^^^^ssszzzzzzPPP[[[mmmiiimmmfffdddiiittt{{{gggfffmmmfffjjjrrrwwwyyyddd```pppqqqzzz{{{xxxzzz - "&)16;BFLQTX_diqy{uoid_ZVRLFB;70*%  -{{{vvvxxx|||zzzvvvrrrhhhjjjnnnqqqhhhkkkqqqxxx|||uuuyyy}}}qqqccc```cccxxxwwwgggddd```VVV]]]uuulllUUUSSSSSSDDD;;;>>>RRR===999555...***...888@@@DDDEEE===III666>>>DDDKKKNNNIIITTTGGGTTT===444666666BBB]]]QQQEEE]]]XXX???999777:::;;;;;;;;;444///,,,***333***FFF000)))&&&"""!!!(((222"""$$$"""(((222,,,<<<444///BBBAAA]]]RRREEECCCCCC111777FFF???===444777+++%%%<<<+++(((###((())))))(((111111@@@///555666>>>999FFFGGGHHHCCCDDDVVVgggooo<<>>:::444222111000///222:::000***,,,'''$$$$$$$$$%%%### !!! %%% '''555888;;;NNNVVVEEEZZZ<<<333555BBB999555===333+++000:::000+++%%%&&&%%%'''+++,,,000OOO666444666666SSSTTTAAADDDBBB@@@AAAxxxaaaYYYUUUKKKEEEIIINNNMMM\\\ZZZTTT]]]aaabbbYYY^^^XXX]]]kkk]]]]]]TTT___YYY___dddddd______oooeeetttbbbiiirrr}}}ssssss^^^ZZZWWWXXXddddddfff___llluuukkkuuueeedddiiivvvooouuujjjyyygggtttvvvttt $'078>DHMSWZ^chlsvtmgb]YTPJE@93/'"  -~~~wwwsssuuutttyyyuuuqqqppphhhhhhvvvpppllljjjlllwwwyyymmm|||'zzziiivvvnnn -ddd|||xxxtttbbbbbbUUUTTTRRRQQQTTTDDDHHHCCC>>>===888888111<<<:::777333:::<<<===999...000GGGOOOXXXNNNAAAFFFGGGBBB@@@===999FFFSSSIIIDDDFFFGGGmmmEEE:::OOO@@@111UUU:::666+++---888((()))@@@(((&&&&&&&&& """!!!$$$!!!######...___SSSFFFJJJKKKHHHOOO555444666444666888444>>>222111```BBB'''$$$'''&&&:::///777888666555<<<:::KKKLLLHHHEEE@@@KKKDDDPPPTTTXXXYYYiiiOOOBBB???HHHSSSaaa```]]]ooo\\\ccc___eeekkk~~~```MMMVVVZZZSSSRRR___[[[XXX]]]```bbbiiigggooooooiiivvvyyyrrrlllccc___OOOUUUcccdddbbbhhhkkknnnnnnyyyfffRRR\\\eeeppplllooozzzsssxxxzzzlllsss "',39?CHMSVY]`dflolgc`\XRNHD=83.'! }}}xxx{{{vvvxxx{{{uuunnnllljjjhhhlllsssssskkkpppggg{{{ yyypppwwwhhhhhhrrruuu|||yyykkk[[[XXXPPPMMMKKKJJJ@@@<<<:::===DDD777444000111666BBB===666777;;;777...DDDBBBNNNccclllFFFCCCCCCFFFBBBDDD===888AAAKKKEEEJJJKKKJJJIIIKKKVVVBBBAAAAAAEEE---,,,&&&((()))###%%% $$$&&&### !!!"""  222+++bbbIIIlll>>>TTTAAA777666444...000111+++444888111222???(((+++'''***---777OOOAAA888666FFFCCC555???aaaKKK@@@GGGQQQUUUcccYYY\\\hhhjjjOOOLLLQQQNNNbbb___hhh```nnnaaaSSSWWWaaaTTTQQQFFF@@@KKKYYYhhh^^^VVV```dddjjj|||gggppp{{{qqqnnneeefff^^^III\\\ggggggdddeeelllqqqssstttXXXTTTbbb vvvcccsssxxxwwwxxx|||uuummm -"&+19>BIMPUX\_adghfb`_ZVQLGA<71,'# yyywwwzzzyyy{{{{{{rrrhhhccciiissspppkkkhhhppp|||tttsss|||www~~~4zzznnnfffiiiccceeefff___UUUPPPVVVQQQMMMMMMCCC>>>===???>>>666444111444111:::555;;;CCCFFFSSS<<>>GGGFFFYYYXXX\\\YYYWWWeeevvv 7pppVVVZZZaaa\\\iii___JJJLLLVVVhhhpppfffqqqTTTJJJQQQMMMOOObbbaaaNNN]]]aaalll}}}hhhggg oooooohhhpppWWWQQQbbbjjjjjjkkknnnmmmlllrrrgggUUUbbbooovvvooowwwxxx{{{|||qqqxxxxxxyyy||| - %-17;BHMPSVY\_`ccb^\ZVSNIE@:4/*'! ~~~}}}~~~zzz|||yyyvvvpppkkk___ggghhhiiifffnnn|||yyytttxxxoooooouuunnnttttttooocccdddeeeZZZUUURRRVVVIIILLLKKKJJJ???KKK999@@@///222888555///444===JJJMMMHHH@@@KKKIIINNNSSSWWWUUUSSSCCCAAA>>>;;;AAA???EEE999===DDDOOOPPPjjjsssTTTWWW???>>>QQQAAA%%%%%%$$$((($$$"""### !!!###***''' &&&&&&666888***...PPP222...555???999666333666---111111BBB///222222,,,......'''888WWW???555<<>>AAAJJJBBB999===:::===```SSScccgggOOORRR```\\\ooo>>>$$$$$$!!!  !!!&&&%%%%%%"""666888---000***...---666222111111@@@111666444///222///222===......111(((555888...111rrrFFF???<<<:::AAAMMMHHHEEEJJJIIIXXX\\\bbb___hhhvvvrrrmmm[[[```XXXWWWTTTXXXjjjmmmhhhffffffgggJJJJJJIIIMMMMMMLLLPPPNNNVVVVVV\\\hhhQQQWWWRRRaaajjjhhhiiibbbnnnkkkccc```___iiijjjpppsssoooqqqeeefffiii```OOOmmmxxxzzzvvvxxx}}}vvvzzz~~~{{{ $*/5:@CFLNQTVXZ[[[TTSPLHD@;51,'$ |||}}}~~~tttuuurrrkkkaaa```fffuuu}}}|||ttt}}}rrraaa[[[ZZZbbbnnnkkknnnjjjjjjaaaaaaVVVdddOOOMMMFFF>>>;;;999888111666///111333999222///>>>DDDJJJIIIIIIMMMDDDFFF[[[WWW^^^dddNNNDDD===@@@>>>===999888999???mmmVVVPPPWWWSSSZZZQQQ^^^OOOCCC***"""!!! %%%$$$###$$$'''###""""""!!!333555,,,---,,,+++///000333000...111///333555888000222222333666///999******000111111888:::555222888:::IIIJJJGGGNNNJJJQQQLLLYYYmmm\\\TTTbbbqqqdddgggXXXOOOWWWVVVYYY___^^^ssshhhzzz\\\\\\FFFUUUIII@@@<<AFILORTTVVWTPPOMJEA=93.'% {{{{{{{{{}}}qqqwwwfffhhh }}}{{{tttggg\\\XXXZZZcccuuuooozzzcccZZZ]]]^^^RRRIIINNNSSSIII>>>BBB999111555,,,555888888---:::EEEIIIGGGGGGDDD]]]SSSLLLRRRRRRSSSWWWGGGDDDFFF;;;444<<>>DDDQQQVVVWWWHHHQQQxxx555555---CCC&&&$$$%%%"""###%%%"""$$$&&&$$$"""'''###$$$---### 444,,,000555???///---555///+++---+++&&&+++444<<<555///333444666///)))+++'''***,,,333---222555CCC@@@CCCRRR@@@@@@WWWeeePPPLLLTTT\\\YYYccceeeXXXWWWUUUSSSZZZXXXpppWWW]]]jjjjjjooozzzWWWSSS\\\hhhDDDIIIKKKUUUOOORRR```WWWaaaccc___]]]___sss(ddd```LLLRRRcccmmm\\\hhhhhheeeooorrrVVV{{{tttjjjvvvwwwzzzvvv{{{vvvzzzzzz}}}~~~ -')/7;72*$ -|||}}}~~~}}}|||uuuffflllssstttffflll (|||~~~}}}rrrzzzkkk___iiibbbrrr{{{#xxxfffcccfffZZZLLLGGGXXXZZZGGGAAA888OOO888444666999---+++111;;;GGGHHHJJJPPPPPPDDDQQQHHHLLLRRRRRRJJJFFFCCC<<<;;;<<<<<<777<<>>888444111222'''###'''"""!!!(((,,,&&&'''***&&&%%%!!!'''"""!!!!!! ???VVV555<<<444000,,,+++...,,,+++,,,(((,,,000+++...///...,,,///(((,,,,,,+++333222444***000777MMM===;;;HHHFFFYYYFFFQQQNNNNNNPPP^^^ccc```hhhkkkdddUUUSSSooo___]]]fffjjjhhhffffff bbbNNNSSSTTTSSSTTTIIIJJJTTTZZZXXXYYY___bbbmmm^^^VVVGGGRRRUUU^^^WWW^^^ddd]]]]]][[[YYYfffhhhfffjjjtttkkkqqqvvvyyywwwxxx}}}ssswww{{{||| ))-7;?AEHJLMMLLMNJIIEA=972/'  ~~~}}}vvveeeccciiikkkooommmwww|||xxxuuummm```bbbcccdddllldddcccqqqtttkkklllddd[[[XXXQQQKKKKKKGGGBBB;;;888888???888777000666LLL@@@999HHHQQQRRRRRROOO\\\TTTNNNHHHUUUUUUOOOQQQ;;;777888999999999:::GGG???;;;;;;JJJMMMMMM>>>III777000###'''---+++)))((('''$$$$$$$$$%%%$$$$$$444!!!!!!666AAA???===---///******---,,,777222...---000+++---222---%%%&&&000+++555---111111SSS::::::888???NNN@@@<<:74/*% |||kkkccccccdddffflllttt|||}}}wwwtttccchhh___mmmiiifffqqqooossskkkfff^^^pppTTTYYYhhheeeGGGDDD;;;GGGNNN>>>666666444<<<>>>FFFBBB>>>GGGSSSWWWZZZxxx [[[VVVMMMQQQKKKDDDBBB;;;555333888>>><<<@@@@@@:::<<>>;;;:::;;;555@@@===GGGTTTNNNTTTTTTTTTVVV[[[bbbyyy]]]ZZZVVVNNN@@@FFFPPP===555777999;;;;;;===JJJ888111)))(((CCC888888---***'''$$$$$$&&&&&&$$$$$$'''###"""######!!! &&&### 555;;;DDD444...222//////222222---///333...000>>>777%%%&&&%%%&&&+++---111222FFFbbbmmm000222333000666666???EEEOOOLLLPPPIIIPPPPPPYYYXXXZZZjjj|||iii^^^UUU___aaafffpppqqqfffUUU>>>???>>>FFFLLLYYYQQQPPPRRR[[[WWWUUUSSSFFFFFFMMM\\\ccc```LLLRRRSSSWWWXXX```gggfffuuuyyyrrreee^^^ssskkk\\\pppwwwuuu|||{{{{{{vvv}}} $*+.17:>?@BCEDCCB@<;874.)%&"~~~|||yyyrrrbbbYYYTTTYYYiiirrruuu}}}~~~xxxjjjfffhhhpppiiikkkpppeeehhhtttooofffbbbXXXMMMMMMWWWGGG???FFF;;;444666333444777<<>>AAAHHHCCCNNNPPPQQQUUU\\\XXX___\\\YYY]]]cccPPPXXXYYYYYYggg```fff|||LLLCCC000:::NNNqqqeeePPPWWW```YYYTTTYYYYYYZZZZZZQQQXXXaaa]]]ZZZgggWWW[[[XXXcccggg}}}ooovvvwwwuuunnn```jjj|||vvvzzzwwwyyyyyy~~~~~~||| !'),037;=>@@BA?>=;97431,&#  xxxssseee___dddddd[[[hhhsssrrrtttwwwrrrjjjxxxqqqsssqqqnnnnnnxxx}}}gggxxx{{{pppddd\\\]]]SSSPPPVVVQQQHHHHHH@@@999666333===;;;@@@CCC@@@GGGPPPTTTXXX```ccc\\\YYYSSSQQQVVVEEE;;;@@@<<>>JJJ444555000444555777===??????@@@XXXTTTUUUQQQRRRRRR___]]]WWWZZZTTTYYY```SSS______iiipppkkkSSSXXXCCC<<>>444111444))))))(((***'''''''''############'''###!!! !!! %%%&&&!!! :::>>>222111,,,*********+++555---...***000,,,'''///)))'''+++***+++333))))))333777:::555000222666::::::===@@@FFFRRRMMMSSSTTTUUU\\\dddfffRRRQQQMMMLLLSSSYYY]]]ddd```ddd^^^OOOIII@@@===HHHSSSDDDNNN[[[TTTZZZdddUUUQQQQQQQQQSSSOOOPPPRRRUUUFFFMMMXXXRRRUUUccciiigggkkk tttcccZZZqqqiii{{{|||yyyxxxyyy{{{yyyzzz "%(,.1779999887630/*(%$" }}}yyyvvvtttppplll]]]ZZZdddjjjiiimmmggglll~~~nnnqqquuuttt|||uuuttthhheeeeee[[[jjjsssbbbUUUKKKIII>>>@@@777;;;444DDDCCCBBBKKKPPPVVVbbbVVVSSSUUUQQQJJJUUULLLFFFAAAGGGIIIEEEGGGLLLQQQGGG???DDD;;;<<<>>>666666///++++++(((((((((,,,'''&&&&&&'''$$$%%%"""$$$)))666 """###<<<%%% )))777222111------111((()))&&&$$$(((+++''')))888<<<666)))&&&$$$###:::)))***)))333...999777555111888777===@@@RRRIIIMMM^^^UUUOOO[[[SSSVVVUUUMMMKKKGGGKKKUUUVVVZZZ^^^XXXTTTUUUPPPWWWSSSjjjvvvZZZHHHPPPRRRRRRWWWUUUSSSVVV^^^XXXPPPHHHKKKOOOvvvRRRQQQSSSQQQYYYccciiilllwww{{{~~~jjjyyyuuuwww{{{{{{wwwttttttxxx~~~}}}qqqzzz||| #%*.03357675421/,*'%" |||xxxssskkktttpppmmmaaa]]]iiimmmjjjjjjrrrwwwmmmnnniiizzz~~~sssllliiieeecccffffffWWWDDDCCCDDDGGG<<<::::::CCC???HHHEEESSSIIIkkkUUUUUUQQQNNNPPPTTTNNNJJJKKKHHHJJJIIIIIIHHHTTTIIIAAAAAA@@@BBBNNN===444222111...)))+++FFF((()))***'''$$$+++333%%%&&&###""""""%%%!!!  ###!!!!!! (((===AAA///,,,,,,+++---&&&&&&"""---,,,111,,,:::555444&&&&&&***((($$$"""%%%444//////---555???444??????;;;@@@@@@UUULLLiiihhh^^^PPP<<<@@@LLLIIIJJJ\\\WWWOOOSSS\\\aaaeee[[[```VVVPPPZZZ TTTOOOZZZVVVSSSOOOZZZ[[[WWW___PPPQQQHHH___VVVYYYTTTTTTWWWNNNKKK^^^dddjjj  {{{ttt~~~sss{{{|||qqqooonnnzzz~~~qqqnnn{{{~~~ !")-.0124442/--,*&%$ wwwlllkkkmmmvvvzzzzzzssskkkiiillljjjppprrrwww{{{yyypppppppppmmmqqq~~~zzzrrreeeeeemmm~~~ddd[[[NNNQQQ___FFFMMMDDD>>>AAABBBHHHLLLKKKSSSRRRUUUTTTTTTQQQRRRRRRQQQBBB:::AAAJJJ```KKKIIILLLNNNJJJFFFNNNKKKHHHGGG>>>666777444111***)))))))))%%%%%%''''''++++++###!!!######"""%%%!!!'''!!!""" ,,,%%%$$$!!!&&&,,,...000+++000***,,,...((('''$$$(((------,,,------******)))444&&&######$$$%%%///111...111;;;555OOO999999AAAHHHOOOdddXXXhhh^^^HHH>>>GGGXXXUUUYYYUUULLLXXX]]]WWWVVVYYYWWWTTT\\\___ssslllTTTNNNOOOVVVPPPnnnVVVZZZ___aaaTTTFFFBBB[[[MMM]]][[[XXXTTTRRR\\\jjjgggmmm'-" hhhxxxjjjzzzuuuqqqjjjnnnuuu~~~kkk{{{"%)+-./0100.,*+%$!  -ssslllmmmtttwwwttttttwwwwwwrrr{{{zzz}}}lllnnn}}}uuuyyy~~~mmmmmmkkkmmmvvvwwwoookkkhhhhhhxxxaaaPPPXXX``````NNNGGGDDDDDDIIIFFFRRRVVVVVVNNNKKKVVVSSSWWWZZZSSSJJJAAA;;;HHHFFFJJJHHH???GGGKKKJJJHHHBBBCCCFFF@@@AAA===:::???555000000---***''')))(((---###(((### """""""""###!!!%%% """!!!!!!''' """'''OOO ---...333///222111))))))(((---(((+++***)))+++111///+++,,,???&&&$$$%%%"""$$$+++777,,,000111000333666888<<>>===FFFFFFUUU[[[[[[OOOSSSdddYYYVVVQQQgggaaa}}}\\\ZZZRRRSSS[[[NNNrrrXXXHHHGGGMMMHHH444333666@@@@@@DDDyyycccZZZ[[[RRRYYYOOOOOOOOOOOOUUUmmmXXXYYY\\\eeelllmmmpppxxx4KnxX7&nnnnnnwwwvvvhhheeevvvwww{{{zzzuuuuuu|||  #""%!"   - -zzzwwwtttqqqpppnnnrrrssstttyyy}}}vvvvvv~~~sssppplllmmmqqqiiiaaammmrrr~~~zzzqqq !lllTTTZZZZZZLLLBBBAAA999999===AAAHHHWWWNNNOOOPPPSSSPPPWWW]]]OOONNNQQQRRRTTTQQQNNNNNNKKKIIIVVVZZZTTTYYYYYYggg]]]EEEOOONNNTTTAAA<<<666000CCC(((222&&&$$$&&&&&&###### !!!$$$!!!***111$$$111"""$$$$$$000JJJPPP:::+++'''111$$$)))333+++***&&&))))))(((EEE'''+++)))$$$&&&%%%!!!''''''"""...&&&(((000444)))+++---///333,,,***///999GGGFFFEEEUUUrrraaaRRR^^^aaaZZZRRRMMM\\\eeefff]]]fffgggQQQQQQQQQaaaZZZHHHJJJIIIEEE<<<:::333777BBBHHHBBBMMMVVVRRRWWWRRRRRRIIIIIILLLJJJHHHVVV]]]aaa]]]ccc```jjjppprrr,RU]Q2sssjjjwww|||{{{hhhZZZmmmrrr{{{xxxyyywww}}} ! ! !yyyrrrpppmmmxxxvvvwww{{{{{{{{{uuuxxx}}}zzznnnuuuaaallldddnnnvvviiiooosss~~~}}}sssccc^^^IIIBBBBBB@@@@@@CCCBBBGGGJJJEEEFFFVVVSSSPPPRRRQQQUUUVVVSSSSSSSSSZZZWWWXXXMMMVVVZZZ]]]ZZZooocccTTTCCCDDDAAA;;;888///777///,,,%%%$$$&&&$$$!!!"""$$$&&&'''###(((&&&###'''&&&&&&''')))---^^^111,,,///---+++***000555999///&&&###444+++'''(((&&&***)))&&&333$$$%%%$$$%%%''',,,)))''''''&&&,,,222......222>>>444111111CCC999???UUU]]]|||OOOxxx```QQQHHHRRReeeccc```RRRLLLMMMSSSVVVMMMKKKHHHFFFEEEEEE;;;888444777<<<@@@DDDOOOJJJLLLTTTYYYNNNMMM@@@>>>HHHDDDHHH\\\dddVVVKKK___jjjooo~~~/+2;4:oooeeepppmmmpppsssnnnZZZcccwwwzzz}}}|||zzz}}}  !!  ~~~|||yyysssrrrsssxxxyyyyyyyyyxxxzzzwww oooqqqmmmfffaaafffkkkmmmooonnnnnnwww jjj```ooo -XXXPPPIII===<<<@@@HHHCCCGGGMMMHHHKKKIIIIIIRRROOOLLL\\\UUUffffffVVVTTTooolllWWWVVVXXXWWWQQQiiiWWWDDDAAA===>>>;;;888111000///******(((!!!$$$$$$((((((&&&""""""%%%%%%&&&%%%&&&%%%^^^))))))333'''888111FFF444555EEEEEE888000'''%%%'''&&&'''### &&&%%%777$$$'''&&&((($$$$$$((('''(((///...333,,,///---...,,,777:::666BBB>>>;;;>>>TTTXXXJJJ0^^^BBBCCCXXX``````TTTLLLQQQOOOGGGNNNJJJJJJCCCCCC???BBB666999555:::===>>>BBBFFFMMMOOObbbTTTLLLGGGCCCEEEJJJIIINNN\\\___UUUMMMeeekkkiiippp ___iiinnnsss|||jjjlllwwwfffqqqwwwuuuzzzzzzrrruuuyyywww|||{{{yyyxxx{{{}}}}}}~~~vvv{{{tttpppdddffffffllldddmmmoooooollluuunnnZZZXXXSSSZZZLLLGGGBBB<<<>>>EEEQQQCCCMMMFFFQQQNNNHHHOOOPPPOOOKKKUUUYYY[[[___WWW[[[WWWYYY______jjjbbbHHH???TTTBBB???===;;;::::::GGG///,,,,,,000---%%%&&&%%%%%%***???DDD'''&&&$$$$$$&&&''',,,$$$'''###(((***'''(((***MMM,,,JJJIII,,,000,,,+++((('''((('''((((((///&&&""""""$$$&&&***,,,$$$%%%---"""///222///000+++...,,,000CCC222222SSS???===DDDJJJHHHOOOCCCkkkIIIFFFMMMTTT^^^```hhhIIIFFFLLLFFFFFFIIIIII>>>DDD>>>>>>===@@@;;;???>>>NNNBBBBBBEEEGGGIIIMMMPPPLLL???FFFQQQHHHEEEMMMRRRUUUUUUQQQcccYYYmmmcccsssrrr~~~{{{~~~kkk___ggg}}}cccZZZrrrhhhiiiuuummm{{{~~~~~~  ttteeetttqqqxxx|||zzz|||~~~}}}||||||}}}vvvllliiirrrfffaaafffjjjmmmiiitttmmmyyyaaaggglllhhh[[[MMMOOOHHHGGGBBBHHHDDD<<<>>>HHHOOOGGGEEEIIIEEEJJJPPPNNNNNNIIITTT]]]bbblllXXXSSS\\\^^^XXXWWWdddXXXNNNHHH>>>=========;;;888555333555111000---***&&&%%%&&&)))%%%###VVV333+++'''***000%%%$$$###!!!((($$$""""""!!!!!!###,,,,,,000---+++000)))&&&%%%$$$***(((###$$$!!!###'''666&&&((((((&&&###&&&######111---000***,,,,,,555222<<<777<<>>AAAFFFJJJGGGKKKMMMHHHAAA777MMMOOO666@@@cccVVVQQQcccfff[[[XXXiiitttjjj\\\hhhkkktttjjjUUUcccpppcccVVVrrrqqqgggooonnn|||  }}}   zzzpppoooqqq{{{xxx}}}~~~zzzzzz }}}yyy{{{vvv}}}xxxzzzzzzyyyssslllkkkttthhhlllrrriiihhhrrrqqqgggkkkppprrrXXXaaaPPPJJJFFFBBB>>>999666??????@@@DDD\\\GGGQQQJJJQQQMMMOOOKKKQQQLLLQQQTTTZZZYYY[[[WWWXXX[[[ZZZXXX```eeeRRRBBBGGG[[[CCC666666555444222555444000...***%%%###$$$&&&'''''')))QQQ333%%%%%%***%%%%%%'''###$$$&&&'''###''')))&&&+++===111''''''###...%%%$$$'''(((%%%'''$$$&&&"""###%%%---%%%### ===###+++333***'''***222,,,///,,,@@@999<<>><<>>---)))---333111555111DDD===EEE<<<666222AAAUUUYYYhhhaaa]]]kkkfffTTTTTTRRRLLLCCCEEEEEEEEECCC===;;;666;;;<<>>FFFBBBOOOGGGHHHGGGLLLGGG;;;------555FFFIII\\\[[[XXXDDDPPPhhhyyypppkkkvvvnnn```mmmfffccc\\\FFFVVV]]]AAANNNkkkssspppdddjjj}}}  }}} |||qqqttt{{{|||ooojjj}}}~~~zzz{{{zzzxxxxxx|||zzz||||||~~~zzzuuuvvv|||xxxuuussshhhkkkkkkkkkgggkkkmmmnnnvvvpppppptttcccaaaYYYcccEEE<<>>???:::666:::<<<======>>>GGG===@@@DDDLLLHHHHHHHHHGGG@@@:::444...999___ccc___WWWXXXZZZ```yyyxxxYYYiiipppccc|||sssUUUTTTSSSTTTLLLKKK```cccjjjbbbccczzz - - -zzzxxxtttrrr||||||zzzyyyvvvzzzxxxxxx{{{|||~~~uuuxxxxxx{{{~~~|||yyyyyy}}}zzzzzzxxxyyy{{{{{{qqqjjjqqqvvvnnnjjjlllgggnnnpppnnnlllvvvgggbbb^^^^^^^^^RRRDDDFFFFFFIIIEEEEEEFFFIIIKKKJJJKKK[[[PPPLLLLLLLLLLLLQQQLLLJJJHHHLLLPPPXXX\\\```___^^^XXXSSSRRRPPPOOOKKKNNN;;;@@@777999333333333333333111444999///&&&***"""$$$!!!%%%))))))'''!!!+++...'''+++111111###$$$(((%%%%%%666+++&&&%%%$$$(((###///111$$$(((,,,***+++***$$$...,,,***&&&'''$$$!!!!!! """&&&***)))---))))))'''$$$$$$***)))--->>>888666>>>GGG;;;999JJJNNNUUUhhhlll```___SSSMMMOOOOOODDDDDDFFFHHHAAAOOO888111;;;>>>@@@;;;???kkk===IIICCCMMMLLLTTTFFFBBB???NNN999777CCC===OOOiiiWWWVVVZZZfffrrrxxxhhhZZZ___llljjjvvvjjjgggeeejjjhhhRRRbbbQQQUUU[[[oooccc___sss  }}}uuu{{{zzz}}}|||yyywwwwww{{{~~~xxx|||zzz{{{{{{tttyyy{{{}}}||||||~~~zzz}}}{{{vvv|||vvvrrrqqqllljjjooozzzrrrlllvvvrrrsssnnntttsss{{{pppmmm```^^^VVVJJJPPPIIIKKKHHHLLLHHHFFFQQQLLLLLLMMMMMMIIIGGGJJJHHHLLLSSSOOOSSSOOOOOORRRUUUXXX[[[ZZZ]]]^^^VVVYYYRRRJJJDDD===999???<<<777444777EEE---222///444AAA,,,***%%%+++$$$(((%%%""""""%%%---((()))+++***)))%%%'''...CCC000(((&&&'''###&&&&&&###(((######(((///---'''222+++''',,,&&&''')))!!!!!!!!! ,,, %%%$$$++++++///'''&&&***---...///444444666<<<===NNNLLLGGG^^^aaaUUUeeehhhjjjfffbbbRRRNNNFFFFFFDDDFFFBBBCCCNNN777333777999@@@@@@===LLLAAAAAA??????FFF@@@CCCAAA>>>AAA<<<444///>>>666FFFWWWWWWWWWdddttteeeSSSTTTYYY___llliiippprrrnnnuuuooo[[[iiinnngggffflllmmmccckkk - www  -  xxxmmmwwwyyyzzzvvvzzzyyyzzz}}}|||{{{||| xxxxxxppplllqqqkkklllkkkqqqmmmrrrwwwqqqooommmmmmllltttooogggZZZJJJLLLRRRVVVJJJJJJGGGMMMJJJHHHJJJSSSOOOPPPIIIPPPMMMPPPYYYHHHAAALLLRRRTTTWWWUUUWWWXXX\\\[[[YYYXXXaaa~~~tttHHH<<<;;;<<<@@@;;;333555444888AAA///,,,222+++---)))&&&'''###''''''!!!""""""###$$$"""%%%)))999)))444555+++:::%%%((()))%%%'''%%%%%%000)))$$$###&&&111***///+++'''###"""$$$///###$$$!!!"""!!!!!! )))$$$"""******...***+++000333+++//////000111@@@777===QQQJJJKKKLLLQQQYYYZZZbbb```[[[^^^___IIIJJJXXXBBBFFFBBB<<<;;;<<<555666;;;;;;;;;AAADDDBBBDDDIII@@@@@@FFFCCC@@@HHHNNN666222111<<<,,,CCCTTTXXX\\\```qqqaaaWWWZZZccclllxxxpppmmmhhhqqqiiiggg kkkpppkkkmmmeeedddooo - }}}yyy{{{uuu - }}}pppnnn|||wwwwww{{{zzz{{{'~~~vvvzzz xxxuuuvvvqqqeeejjjiiijjjgggvvvrrrzzzppplllmmmiiillloooeeeWWWYYYRRROOObbbSSSFFFFFFUUUKKKGGGFFFSSSNNNOOOIIIKKKPPPRRRTTTKKKHHHIIIOOOSSSXXXXXX___VVV\\\[[[WWWSSSOOO```^^^CCC777888777666444555444333///;;;::::::+++)))***''''''$$$#########$$$"""###%%%&&&))))))'''%%%'''***+++444+++000QQQ(((***(((""""""000000&&&''''''''''''III***((($$$"""777iii***kkk%%%"""###""" !!!###///))),,,&&&)))...;;;,,,///000111555999666===JJJNNNGGGKKKTTTSSSfffkkkeee```WWWVVVJJJAAAAAA<<<>>>@@@FFFDDD:::999:::@@@<<<999<<>>CCCMMMFFF@@@<<<999;;;888:::AAAOOOQQQSSS\\\]]]fff^^^hhhnnnooonnntttxxxkkkkkkkkknnnttt)&vvvfffmmmmmmhhhkkkmmmxxx~~~uuuxxx}}}|||uuu~~~yyywww}}}   -~~~ vvv|||zzz~~~|||mmmuuuttttttuuuvvv uuurrrnnniiieeeiiihhhnnnnnnwwwqqqgggeeehhhpppjjjeeeXXXXXXRRRRRRSSSRRRUUUJJJFFFKKKMMMRRRMMMQQQOOOQQQQQQLLLPPPpppXXXnnnWWWSSSVVVRRRUUUeee^^^gggUUUWWW\\\NNNKKKDDDAAAAAA@@@>>>NNN111444222...333111>>>mmm;;;***---))))))'''((("""$$$%%%&&&&&&***+++---444&&&444(((---...OOO@@@...)))333777...(((###>>>###!!!%%%%%%!!!000"""&&&&&&$$$444???999'''###"""###(((444'''$$$)))&&&222&&&---///)))...444777666DDD666<<>>BBB???<<<<<<666555999EEEjjjLLLPPPWWWYYYfffZZZfffxxxjjjlllqqqjjjjjj___fffyyy !uuuaaaooohhhlllooorrr{{{{{{ -|||qqqrrrssssssvvvvvv~~~rrr |||wwwuuuzzz~~~zzzssstttqqquuuyyyzzzxxxyyy{{{|||xxxmmmiiijjjiiifffqqqpppsssqqq}}}iii___```eeecccXXX\\\PPP\\\TTTPPPJJJUUUJJJKKKMMMMMMOOOLLLQQQMMMRRRLLLMMMLLLWWWRRRKKKIIIKKKPPPNNNSSSYYYVVVUUURRRSSSNNNGGGCCC@@@::::::===:::FFF777555555444111888RRR```hhh000+++'''(((%%%&&&$$$)))---######+++***'''&&&(((555///---...555CCC&&&)))&&&555CCC%%%""""""$$$"""$$$$$$###!!!%%%***111###$$$"""&&&"""!!!&&&###&&&!!! (((""")))333...444888000111333;;;GGGDDDRRRGGGMMMcccnnn~~~jjj\\\ZZZ[[[PPP[[[QQQ;;;@@@GGG>>>IIIDDD===>>>999:::>>>>>>===>>>AAAKKK<<<@@@AAABBB>>>BBB:::;;;888999;;;<<<<<<===<<>>HHHSSSYYYZZZYYY[[[\\\VVVTTTOOOHHHBBB>>>;;;===666444888:::999:::888:::888GGGJJJ<<<:::444---***///(((+++###!!!$$$'''######%%%(((,,,888...333***///444333$$$)))***$$$ &&&!!! )))((((((!!!""" """$$$ """ &&&"""'''######(((GGG'''######!!!###000222+++---SSS000555@@@NNNCCCMMMNNNZZZYYYooonnnrrrnnn\\\OOODDDGGG777EEEJJJHHH>>>CCCNNN???:::;;;<<<<<<:::AAAHHH???<<>>AAABBB???>>>888:::999:::555666III___TTT^^^ooowww{{{kkkpppoookkkmmmooorrrmmm\\\ddddddaaaiiiggghhhiiixxx~~~yyy~~~{{{ -}}}~~~}}} qqqtttnnnxxxxxxxxxwww{{{~~~|||yyy||||||vvvsss|||rrrsssqqqsssiiilllnnnlllpppllluuunnneeeaaabbb\\\^^^ccc^^^YYYYYYUUULLLMMMOOOGGGFFFOOOSSSOOOZZZlllRRRFFFFFFDDDFFFBBBHHHRRRMMMTTT]]]```___\\\[[[ZZZRRRUUULLLIIICCC;;;999999555999@@@::::::888<<<777EEE888EEE444...222444111...$$$$$$$$$$$$!!!###%%%888(((&&&+++000???111***888===,,,(((%%%"""###!!!,,,***###!!!(((######+++%%%!!! $$$$$$)))"""000,,,###%%%)))666!!!$$$%%%###'''(((000AAA:::888EEEBBB999;;;AAAOOOjjjiii-yyyLLLHHHAAA000>>>^^^CCC>>>EEEFFFRRR:::DDD<<<<<<<<>>AAACCCEEE;;;@@@<<>>777999======HHHDDDEEE>>>999DDDDDD[[[LLLGGG222***---:::)))%%%%%%,,,$$$###"""%%%%%%&&&''')))111...555777...111&&&,,,######"""!!!###+++&&&%%%!!!((('''111$$$""""""$$$!!!"""&&&"""$$$###%%%AAAFFF###555'''(((,,,"""(((???+++555>>>===888;;;777666@@@@@@DDD666ddd!wwwPPPGGG???555>>>YYYQQQIIIJJJMMMFFF===;;;:::@@@;;;AAA===EEEBBB@@@GGGAAA<<<===<<<:::999??????999@@@<<<;;;EEEOOOHHHMMMooovvvhhhnnnuuuuuu]]]iii|||kkkaaaWWW^^^nnniii]]]fffjjjppp  zzzyyy }}}qqqttt}}} {{{wwwtttyyyvvv|||}}}zzz yyyrrrnnnmmmmmmllllllkkkxxxmmmjjjccc^^^]]]aaasss]]]\\\ZZZYYYNNN___LLLCCCLLLLLLKKKKKKMMMWWWYYYSSSHHHCCCKKKWWWVVVQQQGGGTTTSSSWWWTTTbbbaaabbb\\\VVVQQQ]]]PPPGGGEEE<<<>>>>>>FFF@@@>>>^^^WWWuuuppp\\\JJJeee[[[===222,,,444...)))&&&!!!###&&&***%%%&&&***)))---333***...---111000+++GGG+++(((%%%)))///###!!!)))+++'''###''' """ !!!###"""444+++;;; '''!!! $$$))))))```""""""""" %%%&&& &&&111:::```888999;;;666444PPP@@@EEEGGGDDDMMM jjjnnnlll\\\HHH;;;666<<>>===LLLLLLJJJ???===???BBB:::>>>AAA>>>??????:::DDDJJJMMMTTTNNNjjj|||bbbfffpppvvv  [[[```sssnnnxxx~~~}}}yyywwwzzzvvvyyy   ~~~  }}}yyy||||||xxx}}}yyyzzzyyywwwyyyrrrlllkkkqqqppppppooocccfff```eeerrr___XXXQQQSSSYYYTTTNNNGGGHHHIIIRRRMMMMMMMMMcccKKKIIIRRRTTTkkkQQQRRRPPPYYYWWWRRRWWW\\\ZZZYYYTTTvvvOOONNNCCCBBB???777:::@@@EEEOOO???WWWtttYYYaaalllHHH555555...---&&&%%%$$$"""&&&''''''%%%'''***)))******(((000+++&&&444,,,888'''$$$+++'''&&&&&&$$$%%%!!!%%%)))%%%!!!$$$%%% ###&&& """$$$"""######%%%'''$$$!!!$$$""""""$$$""" ***222OOO888222888888III>>>>>>333??????LLLQQQrrr``````UUUMMMLLL;;;???DDD???AAAOOO<<>>===>>>AAAJJJFFF>>><<>><<<<<<>>>MMMAAA<<<:::>>>LLLggg -VVVNNN777---+++(((''''''$$$'''((($$$###$$$000]]]333''''''+++)))((('''333111""",,,<<<(((++++++%%%$$$)))111""""""%%%%%%$$$555KKK'''#########333$$$###!!!!!!&&&"""000888222777111333;;;666CCC@@@;;;@@@777@@@DDDKKK\\\PPPCCCGGGCCC===CCC???===999EEEAAA>>>;;;888<<<<<>>;;;999:::777555<<<;;;KKKNNNYYYVVV]]]gggrrrfffaaa|||rrr~~~~~~ -lllOOOnnnsssnnnrrrrrrggggggqqqyyy zzzxxxjjjlllrrruuurrrvvvooollloooxxx  ~~~  {{{zzztttnnntttpppqqq$ pppccc___^^^\\\mmmWWWYYYYYYRRRUUUQQQPPPKKKHHHHHHGGGDDDPPPNNNJJJNNNRRRZZZTTTZZZXXXYYYYYYXXX[[[eee``````fffXXXSSSPPPttthhhEEEAAA>>>EEE<<>>555BBBIIIGGG]]]888<<>>@@@HHHDDDCCCHHHEEE@@@444===888===999:::777OOOSSS===OOO;;;===CCC999<<<;;;LLLEEECCC===999AAA;;;???<<<999PPPFFFOOOWWWZZZddd]]]iiinnn~~~{{{sssfffqqqggg``````MMMdddkkksssooo -vvvrrrxxx|||}}}ooobbb```vvvnnnpppuuuzzzttt|||yyy~~~     }}}~~~qqqyyykkkppplllmmmmmmrrrrrr iii{{{mmmggg^^^^^^]]]TTTPPPRRROOOMMMKKKJJJHHHFFFKKKGGGIIIMMMGGGLLLSSSPPPjjjkkk\\\YYY```\\\XXXVVVVVVcccSSSPPPNNNJJJUUUeeeCCC???BBBKKK:::===>>>FFFWWWAAALLL777MMM\\\<<<777;;;:::---///+++%%%***'''$$$'''((()))+++&&&&&&(((+++444&&&&&&'''+++%%%'''&&&***$$$&&&'''000///%%%$$$&&&$$$,,,333###%%%..."""$$$"""(((888;;;333"""///###))),,,MMM...''' !!!"""###)))...///...444333444888BBBGGGZZZIIIrrrVVVTTTNNNRRR???FFFKKKJJJDDDDDDHHHMMMEEEAAA111///333===AAA<<<<<<<<<:::======FFF<<<999>>>>>>GGGCCCDDD===:::@@@888AAA;;;777GGGFFF[[[QQQ```kkkssszzztttyyyqqqdddiiifffUUUIIITTTqqqNNNSSScccmmmzzz -wwwpppssspppppp}}}}}}mmmrrrooogggnnn}}}zzzyyy|||yyy }}}|||   zzz|||{{{zzzuuuxxx|||yyyqqqssspppmmmlllooouuutttfffkkkwwwfffeeegggggg[[[ZZZRRRVVVJJJPPPNNNLLLJJJNNNSSSLLLRRRNNNIIIJJJMMMHHHOOOYYY]]]___\\\aaaZZZ^^^pppYYYYYYZZZUUUNNNOOOIIIPPPCCCAAA===@@@>>>???NNNDDDKKKKKKEEECCC>>>???;;;///555WWW???(((&&&+++%%%$$$###'''(((///&&&((((((%%%+++'''''''''(((&&&((()))$$$444%%%>>>***&&&""",,,RRR999'''+++HHH///######///###!!!%%%&&&<<<&&&###555$$$,,,{{{%BBB  ...###333AAA111666111333>>>999===VVVSSSHHHTTTzzzXXXWWWYYYJJJQQQKKKLLLEEESSS[[[HHHEEEMMMVVV;;;;;;>>>666999???CCC===888999:::EEE>>><<<999CCC[[[FFFJJJ>>>999BBB:::999777999===EEEGGGYYYuuu~~~uuu{{{iiigggmmmrrr~~~hhhHHHMMMSSSZZZQQQEEEKKK^^^ |||[[[aaaeeemmmmmmtttxxx~~~sssvvvooo~~~|||}}}}}}zzz {{{}}}}}}~~~uuuvvvwwwmmmnnnpppqqquuu{{{~~~pppqqqmmm vvvjjjwwwhhhppphhhnnnhhhqqqqqqzzznnnfff]]]fffWWWXXXNNNLLLUUULLLLLLGGGFFFMMMRRRNNNmmmUUUSSSPPPJJJHHHKKKUUUSSS]]]___aaa\\\\\\\\\^^^^^^ccc___UUU```VVVJJJLLLAAABBB===999777:::;;;888<<>>@@@SSS>>>:::999888999>>>888999???DDDRRRDDD<<>>===999;;;@@@NNNhhh$xxxvvvzzzbbbXXXrrrlllSSSVVV\\\\\\KKK???IIIXXXggghhh~~~]]]gggjjjiiiccciiiuuu|||rrrnnnxxxwww -{{{|||{{{}}}}}}zzzwww|||uuuyyyrrrppplllgggjjjvvv}}}{{{lllpppwwwmmmmmmlllcccfff___ccc\\\WWW[[[\\\[[[______YYYYYYJJJDDDAAAOOOOOOOOODDDJJJMMMKKKNNNVVVTTTOOOMMMLLLIIIOOORRRYYY```[[[[[[WWW\\\XXXXXXVVVTTTZZZUUUTTTKKKGGGGGG@@@888@@@777999<<<<<<@@@???888333===DDDJJJkkk222+++(((***...'''(((&&&###'''&&&+++***''')))...(((((((((444$$$%%%&&&&&&&&&%%%"""$$$777>>>'''"""$$$777---***---'''###555*** $$$111((('''!!!!!! !!!###///$$$$$$***666---...RRR:::===:::AAAEEEHHHIIINNNDDDJJJFFFVVVRRRTTT___FFFAAA===;;;@@@BBB666---333888BBB???DDDUUUBBB666777;;;777<<<777<<>>:::===:::===JJJDDDAAAHHHNNN```tttoooqqqVVVgggtttqqqvvvvvvpppnnnccc\\\NNNaaa[[[[[[YYYXXXeeeqqqmmmppp^^^```PPPdddwwwuuu|||oooooo}}}rrrtttyyy|||{{{{{{  ~~~{{{yyyvvvyyy}}}rrrkkkkkkhhhiiigggkkkooohhhgggpppmmm{{{tttkkksssccc```aaa^^^ZZZWWWXXXXXXUUURRRWWWccc^^^RRRNNNIIIDDDIIILLLCCC@@@BBBHHHLLL\\\RRROOOUUURRRPPPUUUXXX[[[YYY\\\______ZZZ```[[[WWWUUUTTThhhPPPIIILLLFFFEEEKKK???<<>>;;;<<<===666:::===<<>><<<666555555:::888::::::===DDDHHHLLL???@@@NNNddd^^^QQQZZZxxxnnnlll{{{pppWWWAAANNNOOOZZZZZZ[[[WWWhhhlllbbbnnndddSSSGGGTTT^^^qqqqqqrrrvvvyyysss{{{||||||sss|||{{{ www|||~~~nnnmmmqqqggghhhjjjcccjjjmmmkkkssskkkdddkkkaaabbblllnnnfff]]]dddSSSZZZTTT[[[WWW]]]YYYaaaSSSOOONNNOOOTTTLLLMMMOOOJJJFFFDDDEEEPPP[[[UUUZZZPPPaaa___YYYYYY]]]ccc[[[dddaaa___bbbiiiXXXRRRPPPOOOKKKGGGEEE???===888???;;;:::===999ggg??????BBB111222666,,,)))000---***===---<<<,,,///222)))++++++''')))&&&***"""'''&&&&&&&&&(((%%%$$$777'''(((%%%!!!"""$$$$$$(((000%%%&&&)))111---///&&&'''..."""$$$""" !!!;;; !!!"""###&&&)))+++))),,,333222AAACCCVVVAAAIIICCCGGGOOOIIIIIIPPPQQQTTTNNNPPPZZZEEEIII666,,,---111:::444777:::DDD777777777999;;;@@@DDD999999555:::888;;;:::@@@>>>>>>===999;;;<<>>;;;AAA>>>===999???DDDAAAGGG555444777111111......***,,,,,,...+++)))+++)))(((---(((333...)))'''&&&777(((***&&&'''$$$''' $$$///&&&111"""!!!$$$######)))'''###((('''...;;;%%%222 !!!!!!!!!)))333444!!!&&&!!!$$$""")))(((===***666666777555444333888@@@AAAIII>>>DDDWWWQQQKKKiii```yyy~~~FFF))),,,CCC///000555FFF===333888999888666999===DDDEEE:::888999;;;777:::<<<===<<<:::444@@@@@@IIIgggJJJXXXttt[[[aaannnppptttkkkkkkWWWPPP___iiidddccc```llllll[[[HHHFFFHHHRRR[[[iii gggdddkkkmmmuuutttyyyuuuyyytttbbbhhhgggmmm}}}kkkccc___fffaaafff^^^```bbbhhh -zzz```jjjlll}}}bbb```kkkYYYoooZZZWWWQQQSSSSSSoooYYYQQQUUUMMMKKKTTTTTT^^^VVVTTTTTTOOORRRLLLPPPNNNbbbSSSPPP]]]ZZZ]]]aaa___```]]]^^^aaa]]]]]]VVVVVVTTTVVVQQQBBB@@@FFF777555===>>>:::>>>>>>;;;......///,,,000222***)))&&&)))***,,,,,,)))---))))))///'''***555***)))&&&$$$(((&&&...$$$###000$$$!!!"""((( """$$$!!!$$$***%%%((('''%%%!!!222$$$%%% (((MMM  !!!$$$(((---000FFFCCC555...111666???CCCBBBDDDGGGTTTppp~~~mmm^^^sssVVV333&&&)))...---666888===;;;666333777666999:::<<<>>>777333000666555444AAAGGG;;;CCC444;;;EEEGGGGGG^^^QQQTTT]]]dddfffrrrzzzmmmmmmbbb^^^^^^}}}zzzhhhffffffdddwwwgggwwwooo^^^ZZZIIIBBBMMM^^^___jjjZZZ[[[yyykkklllyyyqqqzzz|||mmmeeehhhmmmfffiiiiiifffggg]]][[[ppp___YYYXXXbbb^^^UUUPPPTTTcccbbb\\\YYYVVVVVVVVVXXXYYYTTTSSShhhiiieee```UUURRR[[[ZZZZZZTTTTTTSSSOOOUUUMMMJJJJJJNNNQQQmmm^^^```kkkiii^^^___^^^dddaaa]]]UUUTTTTTTOOOIII@@@>>>:::::::::888???:::::::::999999///,,,///111111333111,,,111111///+++555'''+++***,,,***,,,...nnnCCC***((($$$"""%%%###%%%"""%%%  $$$""" ###&&&(((DDD777QQQ444(((---"""######'''$$$  '''EEE"""###(((***999???444888777<<>>...888>>>DDD;;;888666666:::===@@@MMMQQQQQQSSShhh\\\```ppppppjjjiiillltttXXXUUU___[[[oooeee^^^zzzZZZ___jjjOOOiiilllgggjjj^^^YYYRRRTTTOOOSSSrrrfffkkknnnhhh]]]aaakkkmmmooofffjjjjjjjjj1jjjccckkkcccZZZVVVRRRLLLNNNQQQggghhhyyyYYYOOOOOONNNMMMIIIZZZRRRXXXTTTOOOUUUWWWUUUUUUTTTWWW```XXX```[[[SSSSSSMMMPPPIIIJJJEEEPPPRRRTTTSSSYYY___\\\\\\iiiaaa]]]ZZZWWWVVVNNNFFFAAABBB@@@[[[777:::666:::333444??????@@@CCCDDD777777444111///+++...444111555---&&&''')))))))))))))))%%%$$$'''$$$$$$FFF&&&$$$###''''''&&&%%%$$$"""""""""!!!+++'''***LLLNNN)))(((%%%666---555)))+++ """  ###+++000+++111:::<<>>???HHHYYYOOOGGGGGGTTTXXXfffYYYVVVHHHYYYPPP999---***)))---+++000WWW555;;;***(((000777999333:::666>>>777444888::::::AAA777888777>>>CCCJJJVVVUUUTTTHHHIIIZZZ[[[hhhjjjwwwtttaaa\\\WWWaaaYYY```hhhfff^^^kkkRRR[[[VVV^^^bbbccckkk\\\]]]dddIIIWWWWWWVVV{{{WWW]]]fff]]]bbbdddfffkkksssooogggjjjyyyuuuqqqaaabbbccc^^^YYYWWWQQQXXXTTTUUUXXXTTT]]]NNNLLLSSSLLLTTT[[[YYYZZZZZZXXXXXXeee]]]eee[[[^^^fff]]]YYYWWWSSSUUUVVVVVV```YYYQQQOOOTTT^^^___bbbeeetttjjjccc[[[SSSQQQLLLCCCBBBAAA???999AAA===666777666666:::@@@OOO999>>>;;;gggEEE555555333+++...///......+++)))(((---333,,,(((&&&((("""'''(((&&&'''%%%)))$$$'''###$$$###""""""!!! """""")))&&&+++***&&&&&&+++(((%%%)))==='''''' ######'''+++***444333@@@;;;IIIJJJGGGHHHLLLQQQEEEDDDQQQfffOOOGGGPPPBBBBBBIIIBBBDDD>>>:::555//////,,,>>>888222///333222<<<:::666444555555555666AAA>>>888333:::===???CCCIIILLLOOOGGGLLLGGGLLL___aaaeeeeeelllgggSSS]]]___aaa]]]dddcccaaafff```^^^___mmmnnnhhhWWWXXXUUULLLFFFXXXTTTLLLVVVVVV]]]cccYYYaaaZZZeee```]]]___ooozzzoooyyy}}}ccckkk[[[[[[[[[XXXUUULLLTTTYYYTTTRRRQQQQQQMMMNNN^^^UUUVVVWWWRRRTTTZZZ[[[WWW______cccbbbkkk[[[[[[\\\```gggUUUVVV___hhhaaa\\\RRRXXXiii[[[ZZZZZZggg^^^aaaQQQOOOIIIKKK@@@AAA===;;;:::MMM===666888222222555\\\AAA666FFFDDDDDD<<<444333666---)))'''***)))'''---(((&&&***)))((((((%%%###$$$###$$$&&&###***$$$(((%%%$$$###""""""$$$###......---+++***%%%'''000+++++++++)))HHH)))!!! $$$...###""")))!!!***((((((+++---666FFF;;;>>>TTTAAAOOORRRIIIGGGJJJNNNQQQWWW[[[OOOAAADDDHHHAAAAAA===999<<<333QQQ333444666777333444444666:::777666000111333666;;;;;;:::===666AAABBBAAAIIIJJJOOOIIILLLGGGTTTqqqiiicccdddfffbbbccc[[[^^^YYY```^^^YYYmmm{{{gggfffeee___}}}___JJJmmm___uuu;;;JJJKKKUUU[[[ZZZ\\\ggg^^^YYY^^^___aaa___dddiii}}}qqqsss{{{lllbbb]]]NNNQQQTTTVVVIIIWWWfffhhhVVVQQQJJJOOORRRZZZbbb```]]]XXXddd^^^___\\\aaa[[[bbbccc___]]]YYYgggrrrhhh[[[______gggiiilll[[[eeeeeeZZZ\\\ZZZTTTNNNKKKKKKHHHIIIHHHBBB:::222333555333888@@@777444444222111;;;444>>>>>>999AAA[[[333444...///---***)))+++&&&%%%&&&)))(((((('''&&&&&&$$$$$$!!!"""%%%%%%&&&&&&'''(((---*** ###&&&$$$+++999111???(((***,,,111000666444&&&""" $$$)))!!!'''!!!///*** !!!''')))!!!&&&(((...AAA...NNN999DDDHHHJJJNNNVVVCCCDDDVVVgggtttZZZTTTMMMJJJHHHJJJAAAFFF:::@@@GGG>>>%%%(((111111111///666///666...444111777444666666999666:::JJJGGG\\\FFFBBBVVVSSSFFFDDD???JJJbbblll___cccdddeeepppfff[[[KKKNNNQQQXXXdddmmmkkkiiinnnjjj^^^UUU]]]___iiiSSSLLLMMM@@@XXXnnnYYYMMMWWWiiiZZZWWW^^^eeebbbfffbbbrrrnnnyyyooobbbfffVVVHHHRRRSSSXXXNNN}}}WWWcccTTTUUUSSSWWWSSSYYYfffeee{{{ccceeegggggg^^^fff\\\iiibbbddd|||___lllpppfff\\\qqqeeepppccceee___cccaaa]]]VVVQQQIIIGGGDDDHHHKKKRRRNNNDDD666777666555///222===:::666444888<<<888:::444===888777000444///000***'''))))))''')))111******)))&&&&&&###"""###%%%!!!"""''')))$$$%%%(((%%%)))###"""&&&AAA;;;666+++777'''<<<555'''&&&!!!'''%%% ###"""333666444$$$ !!!,,,+++%%%''',,,333AAA___333>>>GGGIIIHHH???VVVFFFBBBDDDJJJ[[[VVVMMMHHHWWWOOOFFFLLLNNN???>>>;;;@@@777***$$$(((///555...000......---///555111333333000777888444555BBBNNNBBBIIIHHHSSSLLLQQQ@@@HHHSSS```bbbYYYiiidddkkkrrr___ZZZOOOUUUMMMmmmiiimmmkkkssszzzgggjjjUUUSSSQQQZZZ\\\\\\YYYgggIIIFFFXXXbbbTTTRRRSSSSSSRRRNNN^^^]]]aaajjj}}}~~~bbbYYYUUUYYYUUUXXXXXXTTTSSSOOOWWW___^^^^^^YYY[[[gggsss tttcccgggbbbdddaaaffffffggghhhaaabbbkkkbbbssseeeoooeeefffiiinnngggiiidddgggTTTEEEHHHHHHGGGHHHUUURRRNNNEEECCC555444111444DDDGGGBBB444222444666999<<<777222111333222333...---+++((()))'''&&&'''&&&'''&&&'''))))))&&&---&&&&&&$$$///"""&&&%%%"""###%%%!!!"""$$$###---$$$&&&&&&'''###---###bbb+++$$$ &&&'''!!!!!!(((NNN ,,,%%%(((+++///000???BBB===???DDD???GGGHHHCCCFFFzzzJJJDDDCCCJJJRRRSSSGGGYYYPPP<<<>>>999BBB555333(((&&&)))(((,,,---///666///222666111777;;;333333888666<<<333777;;;DDDFFFLLLMMMIII>>>GGGDDDQQQOOOUUU[[[gggiiifff\\\UUUUUUBBB;;;VVVddddddeee0___```UUUYYY]]]```VVVGGGHHHGGGFFFRRRZZZZZZXXXWWWYYYPPPKKKMMMSSSZZZUUU___eeefffcccWWWSSSYYYZZZ]]]UUU___WWWTTTYYY\\\YYY[[[[[[^^^\\\``````ddd^^^\\\^^^gggbbb```eeeeee^^^hhhooossspppkkkiiiiiioookkkmmmtttiiihhhbbbWWWYYYLLLMMMTTTMMMFFFGGGVVV[[[JJJCCC666666333::::::333<<<;;;555666---;;;;;;999777333000777---***+++---***666+++,,,$$$$$$%%%&&&((($$$%%%&&&''''''$$$)))(((''''''""""""### !!!"""""""""888&&&%%%(((&&&)))..."""***)))222%%%:::>>>!!!### $$$''')))%%%&&&$$$''',,,000666888<<<:::CCCDDDEEEEEENNNOOOLLLXXXRRRAAAGGGSSSNNNKKKFFFLLLBBB???888;;;999MMM111///***&&&***111000---000333444888555555666666333555555333666555:::BBBAAAKKKKKK^^^===<<<>>>MMMOOO^^^eeeYYYWWWWWWSSSJJJTTTRRRHHH666PPP___hhhrrr{{{vvv|||\\\aaabbbfffZZZRRRNNNNNNFFFMMMXXX]]]UUUWWWOOOGGGOOOOOOPPPSSSUUU[[[TTTcccfffYYYXXXYYYXXXXXXTTTYYYWWW```bbbbbb^^^```eee]]]\\\ZZZ```___XXXZZZ]]]aaabbb___aaajjjdddhhhhhhllljjjrrrnnnqqqooohhhfffjjjrrrddd]]]aaaYYYOOOKKKKKKHHHKKKFFFMMMHHHGGG<<<444555>>>;;;@@@444666888555222111666999::::::555000111111///222222,,,---111)))...)))((($$$***888...''''''### '''***%%%***###%%%$$$$$$$$$222))) %%%---111""",,,+++&&&$$$''''''!!!NNN???  000 &&&$$$&&&,,,888888;;;@@@@@@GGGAAANNNUUUKKKMMMOOOCCCaaaJJJCCCOOOIIIFFFRRRJJJ@@@;;;999;;;;;;@@@666555BBB***&&&'''))))))000333777444888444666777444444666444333222@@@BBB???@@@EEE888EEE777888AAACCCTTTYYYRRRPPPJJJSSS]]]VVVWWWPPPFFFVVVnnneee```bbbpppgggbbbYYYooosssgggZZZXXXWWWTTTQQQIIIHHH???PPPNNNUUUaaaYYYbbb___YYYPPPNNN```ZZZRRR___]]]\\\^^^]]]]]]YYY]]]ZZZbbbdddddd[[[XXXYYYYYY[[[ZZZ^^^ddd\\\[[[aaafffeeeZZZ___eeeeeebbbdddrrrfffjjjppplllkkk```[[[fff{{{ppplllWWWTTTQQQRRRPPPLLLJJJFFFLLLVVV@@@;;;666>>>999SSSAAA333555:::999444333CCC999999AAA777555000444CCCVVVooo666777JJJ+++...'''***%%%&&&)))***"""%%%((($$$(((..."""'''&&&$$$((($$$(((%%%&&&111&&&'''444000###&&&$$$###///"""...000""" '''!!!  !!!$$$"""###******555===BBB999DDDBBBMMMOOOPPPFFFHHHKKKJJJIIIIIIEEEOOOFFFHHHEEEAAA>>>??????:::888999bbbHHH)))%%%000))),,,000444///555333333888BBBMMM888:::===999666:::===AAAPPPEEE999:::000;;;888888CCC>>>IIIIIIKKKVVVjjjYYYWWWjjjIIIYYYQQQ[[[XXX\\\YYYVVVIIILLLNNN[[[]]][[[[[[WWWWWWWWWVVV```FFF@@@HHHSSSeeelllrrr^^^PPPaaa[[[ZZZZZZSSSSSSdddllljjjZZZcccdddcccbbb```aaa]]]\\\___[[[^^^UUUcccccc___```___^^^\\\qqqqqqgggbbb___hhhrrrqqqjjjaaa``````bbbcccaaa}}}```^^^VVVOOOLLLWWWwwwLLLRRRiii???::::::@@@;;;===>>>???666;;;999222999555888@@@@@@FFF;;;555999555000,,,000...,,,,,,***+++...(((%%%&&&111((('''%%%%%%%%%)))jjj###&&&'''&&&%%%"""$$$%%%'''111&&&)))%%%"""$$$###%%% %%%---.../// 333!!! !!!$$$###))))))(((111SSS888222HHH>>>GGGCCCIIIDDDGGGRRRQQQOOOIIIEEERRR===;;;AAA@@@EEE===666111888BBB[[[222111'''%%%(((000//////111///@@@555222555777::::::222888333>>>@@@DDD======999GGGHHHNNNGGG<<<===<<>>BBBOOO>>>999===>>>BBB<<>>@@@===EEEAAA888777<<<888:::>>>NNN===FFF:::,,,///111...000...333***---'''$$$''''''&&&&&&'''%%% """ """ %%%)))555+++$$$&&&((('''$$$%%%&&&'''###""" %%%""" $$$"""!!!!!! ### """''')))///444777AAA;;;444333333777EEEIIIJJJFFFJJJEEEGGGAAAAAA@@@===???AAA:::>>><<>>JJJJJJLLLLLLOOOXXXeeeZZZZZZZZZRRR\\\XXXVVVeee]]]XXXrrrsssoooddd[[[[[[YYYNNNQQQKKKMMMZZZNNNeee rrr ffffffXXXaaahhheee^^^ZZZ```cccddddddcccgggkkkjjj___```ZZZ]]]fffgggmmmfffvvvaaa]]]eee[[[``````\\\]]]___^^^VVVOOORRRNNNJJJLLLGGGPPPJJJKKKEEEEEEFFFIIIDDDEEEDDDllljjjZZZ[[[___hhhHHH___www999;;;>>>===:::999999CCC000111---)))222222......+++---,,,111&&&)))(((***%%%!!!!!!###!!!!!!!!!###%%%&&&(((,,,%%%&&&((()))&&&000'''&&&###!!!!!!""""""###$$$ +++"""!!!!!!"""  333!!!555444 $$$###%%%,,,+++000888555000444:::;;;@@@EEECCCMMMMMMEEE???QQQAAAFFF>>>???>>>===888;;;999===444000111222...$$$###((((((***+++)))))),,,///000222666222---///CCCGGG222,,,444AAA<<<555;;;JJJ<<>>777;;;RRRPPPJJJUUU]]]ZZZ]]]]]]YYYRRRSSSWWWRRRZZZSSSwwwqqqbbb[[[```eee]]]ddd```mmm___\\\```tttxxx |||sssXXXZZZ___bbbqqq]]]mmmiiidddhhhhhheee``````cccjjjzzziiiZZZdddvvvhhhbbbddd```wwwuuuppp^^^]]]SSS___VVVXXXTTTWWWOOONNNLLLPPPLLLJJJOOOGGGKKKDDDCCCDDDBBBDDDBBB@@@???>>>FFFDDDMMM[[[-\\\IIIBBB:::<<<666999333777555CCC;;;222000///000333......<<<---:::---((($$$######$$$ !!!%%%))))))***000)))555)))******(((:::(((&&&'''!!!***$$$&&&"""###!!!(((999""" $$$222###!!!&&&!!!%%%'''((()))000000888222JJJ???======KKKIIIFFFHHHHHHCCCCCC@@@III@@@>>>===@@@AAA999777>>>555333:::;;;SSS---)))((('''###)))(((+++---///@@@///333444***000222<<<333000888:::CCC888III>>><<>>777666:::???///777111+++///444III)))(((,,,!!!###$$$!!!###"""$$$,,,,,,***222...:::***&&&&&&'''((('''###(((!!!&&&$$$###"""### !!!(((999  !!!######+++---&&&222DDD@@@AAAIII<<>>FFFOOOEEERRRXXX```RRRSSSPPPLLLGGGQQQTTT]]]```bbb\\\```[[[QQQVVVSSSUUUbbbUUU^^^^^^aaajjjssslllbbbUUU\\\rrr}}}~~~jjjNNNWWWQQQEEE[[[NNNOOOUUU[[[```^^^\\\ZZZ]]]^^^VVVVVVVVVbbb___ZZZdddbbbZZZYYYYYYOOOQQQIIIGGGJJJGGGHHHJJJHHHPPPHHHJJJEEECCCCCC<<<===AAADDDEEEIIIUUUNNNJJJAAADDD@@@DDD:::NNNVVVJJJ???FFF<<<<<<:::<<<===;;;>>>iii666AAA555222WWWIII888++++++(((%%%%%%###&&&000%%%)))!!!$$$)))XXX///***(((---))))))$$$&&&(((***)))### %%%%%%###%%% $$$ $$$*** ***,,,&&&///222999===>>>OOOLLLFFFDDDDDDHHHAAAEEEQQQHHHJJJGGG???CCCEEECCC???:::999888:::;;;ggg333???HHH222???///---000***)))(((***)))...444333,,,222:::>>>777999>>>>>>:::<<>>>>>FFFAAA@@@>>>DDD444888999IIIFFFGGGJJJLLLFFFWWWWWWHHHGGGFFFXXXUUUSSSWWWSSSVVVUUUTTTNNNNNNRRRUUUQQQUUU```___WWWkkkfffVVV\\\dddyyy -tttqqqYYYIIIPPPDDDNNNQQQXXXLLLUUUTTTXXXXXXUUUVVViii\\\YYYVVV^^^aaaSSSUUURRROOOOOOHHHHHHBBBIIIJJJHHHDDDAAABBBEEEFFFSSSHHHAAAEEEJJJ777GGGMMMSSSppp```NNNFFFLLLAAAFFF>>>BBBAAAOOOBBBEEEDDDDDD@@@999@@@???:::777???rrr[[[HHH999444888000---,,,///+++$$$'''"""###""" ;;;+++ !!!"""!!!)))GGG+++111((()))'''$$$$$$######...777''''''---...[[[((($$$)))***((("""&&& !!!---!!!'''&&&)))111!!!!!!%%%&&&$$$:::===888GGGOOOGGG@@@999DDDKKKAAAIIIFFFBBB???GGGAAAGGGHHHFFF>>>999>>>:::777///@@@///555)))000---000,,,&&&((('''%%%"""***,,,333222,,,///222666555444===AAAAAA;;;;;;CCCDDDAAA@@@AAAXXXxxxYYY:::HHH===CCCHHHEEESSSJJJIIISSSQQQ\\\PPPPPP___EEERRROOORRRUUUSSSVVVWWWQQQPPPVVVXXX]]]^^^___[[[YYYPPPRRRdddmmmkkkooo___ZZZWWW[[[OOOUUUZZZOOOVVVKKKIII[[[\\\jjj\\\]]]```\\\UUUUUUNNNNNNNNNLLLLLLKKKHHHEEEAAACCCLLLDDDEEEBBBBBBEEESSS===FFFEEEDDD>>>:::MMMWWWpppjjjbbbLLLJJJFFF<<<>>>@@@BBBAAACCCCCCHHH666@@@DDD888===EEE222555PPPIII:::GGGEEE...,,,))))))---'''***(((&&&###888555111---!!!,,,(((!!!''')))---%%%&&&***---'''((((((,,,000'''%%%///'''+++MMMjjj(((%%%$$$***''' &&&::: !!!%%%&&&$$$ """!!!''',,,...111777<<>>TTT===:::AAADDD===>>>EEE>>>:::777OOOsssiiimmmoooaaaGGGXXXDDD;;;999<<>>:::@@@@@@IIIFFFCCCEEEGGGIIIPPPRRRFFFlllIII===888===777???:::///222---***------.........)))'''### %%%((('''000...///222???>>>999888;;;>>>@@@999444<<>><<<<<<@@@HHHGGGHHHGGGJJJLLLMMMNNNRRRNNNQQQZZZRRRRRReeeGGGAAAIIIQQQKKKHHHMMMSSSQQQUUU[[[YYYMMMRRRNNNRRRPPPKKKIIICCCMMMMMMSSSPPPRRR]]]KKKDDDDDDBBB>>>EEE===EEE;;;:::<<<@@@===DDD===FFF@@@<<<<<>>999CCCLLL===@@@PPPAAAJJJDDDCCCEEEDDDBBBEEELLLKKKCCCFFF;;;???@@@;;;444333///333,,,///444555777222111,,,((((((...000///555CCC:::CCC;;;<<<>>>>>>???<<>>777@@@BBB???III>>>:::777999;;;<<>>FFFFFFCCC333444000///++++++///222999111HHH222,,,333000---???+++(((///$$$"""###"""$$$(((### """)))%%%'''$$$%%%$$$%%%"""&&&%%%&&&""")))(((000999...+++(((666888AAA<<<'''((($$$ 666%%%...!!!""""""$$$ $$$'''"""&&&((((((###%%%***(((555<<>>LLLIIICCC;;;777333000333555;;;IIIiii888+++)))(((%%%%%%---222777OOOQQQ@@@JJJOOO>>>:::888@@@999;;;999333RRR}}}HHHMMMKKK???===555,,,444???BBBCCCHHHDDDLLLFFFOOOdddDDD>>>CCC<<>>888>>>DDDAAA@@@DDDGGG@@@>>>EEESSSGGGCCC???999??????@@@;;;777888;;;::::::>>>:::GGG===TTT>>>HHH===<<<===;;;===HHHHHHXXXDDDKKK:::======ooo===777444888444777...111000000///***---++++++)))<<<,,,DDD111>>>111&&&&&&$$$"""&&&"""&&&$$$ """%%%&&&###(((&&&!!!$$$&&&222)))***''''''+++222@@@...))))))444...//////,,,%%%(((%%%FFFSSS)))!!! !!!333 ''' """+++"""$$$"""***((()))AAA888777BBB<<<<<>>999CCCKKKPPPOOO===444111222222222===@@@:::333000000111&&&&&&...:::OOO???:::QQQeeeJJJ555888CCCAAA<<>>444'''...444<<>>DDDIIIFFF===FFFUUUqqqbbbGGG444...:::@@@BBB???AAAHHH@@@999CCCJJJGGG@@@@@@<<>>999>>>CCCAAACCC???BBBEEE@@@HHHDDDAAABBBHHH>>>999===;;;DDD999999888777777???:::===JJJJJJ??????;;;<<<===@@@;;;CCCAAARRR___TTTLLLYYYMMM<<<:::888888;;;<<>>===333...((('''...)))$$$$$$+++"""!!! $$$!!!!!!---!!! $$$"""""" !!!***+++222MMM444444@@@CCC@@@777777BBB>>>BBB===BBB@@@BBBBBB???>>>BBB???FFFTTT\\\===:::GGG666444999AAA999333===888999555)))###+++<<>>BBBAAAAAA>>>JJJDDD))),,,999999DDDHHHFFFEEE@@@HHHSSSDDD>>>999\\\EEETTTOOOPPP???IIIDDDDDD;;;555555888@@@???>>>???@@@>>>@@@LLL@@@<<<::::::888999<<<::::::888;;;===BBB:::::::::AAAAAABBBAAAAAA???<<<;;;<<<<<<===888999:::777555777888888:::III@@@LLL>>>;;;CCC;;;FFF???CCC<<>>+++ ''''''###""" :::666@@@((((((!!!***### !!!!!!!!!---+++222666***000666WWWIII:::HHH222:::===@@@<<<:::@@@>>>@@@KKKIIIXXX<<>>>>>???EEE@@@;;;<<>>:::999888999999666555444888555888;;;888888===;;;???===;;;EEE@@@CCC@@@:::999:::999<<<666666333AAA>>>;;;555888888;;;CCC```LLLPPP@@@888@@@>>>DDD@@@???===;;;JJJKKKFFF===@@@<<<777<<<999333111999;;;888///RRR999---222...000---,,,+++&&&JJJ///111222+++'''&&&###""""""!!!%%%&&&%%%'''((((((&&&...,,,***)))444,,,,,,333+++000,,,)))222...WWW777000***;;;---&&&***555222'''---!!!$$$)))%%% '''&&&!!!""""""###%%%######'''000333666999:::>>>ccc222888;;;CCC======;;;999CCCUUUFFF___JJJNNNMMMLLL;;;DDD888FFFVVVaaa777444111000333111111---%%%777---555555777888999888444111999===777777MMM>>><<>>QQQggg???CCC>>>===>>>XXXCCCBBBCCCHHH@@@;;;AAA888:::@@@777999222888999333777000...+++***///HHH///,,,***&&&((((((000,,,333111)))&&&''')))'''%%%;;;---///)))+++777***...222111===NNN666111444///333***,,,,,,;;;OOO...333***)))&&&((()))"""...%%%///((( &&&%%%!!!"""!!! ###777,,,%%%333666:::///555999GGG888999;;;:::888999===888BBBNNN|||HHHKKKBBB===HHH<<<666CCC@@@EEEJJJ777333444;;;666:::222)))(((&&&///111111666BBB===;;;===???777;;;<<<===BBBGGG999;;;JJJKKKeee>>>444///...000444<<>>::::::222333:::CCCrrrggg===@@@444555666666555666444::::::777999555666<<<:::888<<<<<<999:::888:::===555333666666666666;;;III444888:::;;;444333888666???EEEEEE<<<<<<<<<555:::<<<===---222:::AAA555333888999444333666444:::222444///---+++000111***///******))))))+++)))---RRR==='''''',,,444333```JJJVVV111333555444333222444///:::---+++,,,000444;;;///???<<<===111...'''$$$"""***"""""" ((($$$ !!!333"""... ###---444(((''')))888???111333555777<<<<<<222555111;;;444???888@@@VVVvvvpppvvvJJJ;;;888BBB;;;??????@@@CCCBBBEEE>>>BBB;;;777333===333(((,,,(((+++444555888999999AAABBB888:::;;;CCC???333777666333;;;BBBEEE444@@@444///444111===<<<@@@:::CCCHHHMMMCCCIII@@@444222///888777<<<666444666888:::777555;;;CCCJJJ@@@;;;888<<<888<<<:::555888222555555555555111666@@@777>>>===777:::>>>555;;;777444666555222000444222666333777999222555888555<<<;;;???HHH888:::<<>>>>>999<<<;;;777???DDDSSSGGG666>>>XXX666111333((()))$$$%%%***222777===999666777GGGMMM>>>:::<<<666;;;===:::JJJ222DDD666777333555......CCC??????::::::AAA@@@MMMEEE;;;999555222999888;;;555555999888555::::::@@@^^^[[[HHH777444:::777333333222///222000000222999888222777888:::999:::666555777444AAA666;;;444777222444111444666:::RRRFFF:::999111333111???AAA:::888444777888777777666777444222666777///777???III...000111SSS555555999999666@@@222444>>>___;;;,,,222///222===>>>222>>>333333;;;111KKK:::___777888CCC///---111555===<<<...///111000+++)))000YYYSSS111...***&&&$$$ %%%&&&&&&###'''$$$### """JJJ###...###)))777>>>======***%%%000)))***222...888777999///222222333000000444RRRGGGPPPBBBAAAIIIGGGJJJ===:::<<<999999VVVQQQFFF777111***...444777444///+++,,,(((444777222777222666===BBB@@@???===777999>>>333444444444>>>:::000111222???BBB777MMM;;;;;;;;;FFF[[[BBB<<<777666999444777111999999222333666333666:::FFF999DDDUUU333222444000444III444333111555333===444CCC999===333222444777;;;888999999666888777666777222777===777888???>>>555555444888666:::>>>===555===666===999888444///000999555666BBBSSS444000222666:::TTT<<<<<>>EEE666<<<777@@@HHH???>>>444JJJCCC555...///222999>>>EEEVVV???444<<>>333555000111222555222555333666777444888999999999666333999DDDOOO@@@:::666666555444555555444555666IIIEEE999888777666444666333999===777===666666222555>>>///000---111111555SSS666555111FFF888555???ccc555;;;///---333zzzTTT000AAAXXX888000LLLBBB777777222555888222666444666222000GGGOOO444///+++%%%((('''///111555))),,,***333,,,(((---***&&&,,,)))&&&999***,,,???::: &&& )))###%%%:::'''  222BBB+++...***$$$$$$$$$)))))))))+++...***---///000000...333//////222@@@BBBBBBIIIIII___???AAAaaa@@@???AAAyyyTTT===888>>>...000555333???;;;555111,,,(((---000666444222888666999NNNBBBLLL???AAACCC777999888999888???666666ggg???CCC+++111555===???MMMIII333666QQQ888333AAA666777999GGG777;;;222:::999888:::AAAAAA<<>>>>>555AAA999GGG;;;===999EEE888;;;NNN888333222888***999444999555;;;111<<<===777777,,,111888666222///NNN>>>777444>>>666666```KKK===777222111555777777000xxx|||999888888777666///444333///999000111333555777===333222...jjj###''')))...000)))444)))000...&&&???777+++'''******999444---+++$$$///+++:::444KKK+++ $$$222"""!!!$$$!!!$$$###$$$,,,'''(((,,,,,,111000+++000111555***(((///>>>AAA>>>???AAA>>>???<<<<<<@@@DDDEEE:::AAAEEE:::888888;;;...:::444BBB:::777555000+++...222;;;222FFF444777HHH@@@FFFAAA<<<===AAA<<>>;;;MMM999999888888999999444888999:::999???@@@AAA333999777444;;;555444:::777777AAA:::AAA:::111222111222444;;;[[[GGG777<<<>>>:::888666888///222333---111777000EEE777AAA000;;;777888444FFF777))),,,AAA---///444111999---...333///222;;;///222111(((222444000777444GGG//////111...)))EEE888333+++(((***'''%%%%%%'''%%%(((&&&000+++***,,,000666;;;)))((((((@@@%%%&&&(((...,,,%%%,,,111444---dddGGG### 444%%%&&&"""!!!222'''///000---++++++,,,///444///...,,,)))))),,,///666FFF:::999CCCgggIII???AAA:::555666===>>>III===MMM:::000333FFF666444222------''''''111444555HHH===;;;>>>:::@@@FFFMMMDDDEEE>>>888NNNCCC>>>===...+++***---999BBB444:::444???888999000<<>>:::???:::;;;;;;;;;???BBB===;;;@@@BBBBBB???EEE;;;>>>NNN:::888555;;;===SSS;;;:::===555777<<<777999999666777999AAA777;;;444666444444>>>AAA@@@:::222```SSS999999:::;;;555333MMM^^^MMM===333AAA333:::222777666>>>222555444555444222000,,,000(((((((((%%%,,,444///<<<===;;;444///,,,...+++333CCCAAA999555CCC???444,,,------///)))+++%%%''')))&&&***,,,(((///)))...,,,:::---///DDD+++&&&,,,''''''%%%)))333)))222******666CCC444"""$$$333 $$$!!!###$$$(((???***(((...222555...///...---111///...???555AAA===;;;@@@FFFEEEKKKBBB[[[BBBEEEDDDuuurrrKKKBBBEEE,,,000555666666555+++***&&&###111000333333666777888XXX:::;;;CCCDDD<<<777555GGG===@@@HHH111,,,444///444777---...666111666999666666AAA===999GGG666888999999999FFF999:::UUUCCC>>>>>>>>>FFF???;;;<<<AAA===999;;;BBB???@@@888???GGG:::;;;CCCDDD;;;999444>>>@@@<<<:::444@@@222444555777666888AAACCC888UUU333777333;;;999WWWLLLSSS>>>CCC===888???888888...999666999555222---333+++***///***$$$'''+++---444***111444///:::***+++)))GGG000000+++999777000;;;<<<555...222+++(((&&&***,,,EEE>>>***,,,))))))<<<111+++666444---555///***$$$+++((((((555---'''%%%999)))!!!<<<$$$###:::!!!,,,!!!$$$&&&((((((888(((222222999+++///111111***,,,000111888888:::AAA<<>>:::FFF444@@@555777AAALLL@@@555777000//////444666777888DDDTTTLLL]]]ZZZ@@@<<<444<<<;;;666555666///666333===444111***555+++---222111444555666555888222777999>>>EEE>>>???@@@@@@BBB888;;;BBB@@@EEE:::777777>>>???>>>444:::;;;HHHKKKSSSYYY<<<===888999???DDD999888<<<888999888JJJ666///888GGGDDDAAAAAA<<<555777555<<<...222444888444777EEEgggGGG777555:::222333111111111///222333---+++---...---------------000+++000111666&&&---555--->>>000...---000...///111000...222---(((+++:::000,,,)))((()))))))))&&&111***%%%$$$999'''***&&&)))''':::VVVXXX&&&***&&&&&&!!!!!!!!!"""!!!###$$$$$$$$$###!!!&&&---,,,...>>>666,,,///222,,,***444222666;;;DDDDDDFFFJJJQQQEEE<<<===CCCIII\\\DDD===???DDD@@@PPP===---///222555aaaFFFJJJkkk777777;;;,,,,,,;;;;;;AAAGGGaaaxxxqqq???555111333------666>>>777444333;;;PPP555,,,444<<>>888===444999999999888===333///999888777333666777TTT[[[KKK<<<111777222222111+++000777+++,,,***///333111///111...777///222))),,,,,,***+++))))))...///888000,,,+++666---(((333***+++)))(((444///+++%%%######$$$***""")))---)))%%%&&&///'''%%%,,,###***000...999---&&&"""---(((###  ...***%%%+++...+++===+++222444222888000,,,---///222333777NNNDDDWWWLLLqqqNNNsssKKKLLLDDDTTT@@@JJJMMM```bbbIII444***---111OOODDDBBB666000777>>>EEE555111///<<>>GGG@@@XXX```888666999999555555222666888<<>>333@@@CCCYYYAAA//////000555444111,,,***000++++++&&&------******---888555DDD555+++)))666&&&(((&&&...***,,,...///+++444+++((()))+++***(((///+++***)))---&&&$$$)))###%%%###+++---$$$+++'''&&&)))&&&%%%$$$###)))(((%%%%%%***'''"""""" %%%$$$!!!&&& !!!###)))'''((($$$///+++***...,,,111...111555EEE---+++///222:::HHHKKK]]]GGGGGGQQQCCCBBB<<<777WWWCCCFFFnnnRRRVVVMMM>>>333777???555444BBB===???>>>???^^^WWW@@@222666AAARRRWWWpppLLL>>>555666222222...000OOO999999EEE<<<;;;;;;>>>555......999;;;444444...333777222...000444777666444666444333666444:::333777:::DDD===???<<>><<<444<<<:::AAA>>>BBB444333===444LLL444;;;------'''222))),,,)))111...111,,,444///RRR///===+++))))))111---111,,,,,,...---,,,555999,,,%%%%%%+++((((((---(((((((((%%%***...$$$)))))))))"""######,,,&&&***&&&888"""""")))%%%%%%###///***###!!!!!!!!!333###%%%%%%)))&&&&&&$$$///999...///)))444......777000888///111222555NNNSSSAAABBB>>>DDD===777;;;:::SSSJJJGGGSSSHHH>>>222RRR444444111444BBB???EEEBBB<<>>===777lllLLL777...000222...444555555777444666;;;<<<<<<888999---,,,111222000000555333444333///555555222111333111666666888111000000...JJJKKK666AAA;;;>>>:::555---......,,,000222222000333111...000+++***444BBB```>>>???XXXxxxYYY444>>>FFF666888444555777333000111777555VVVRRRBBBBBB666===AAA:::000***;;;///777***))),,,------***)))---222)))555---+++***000555555111444111///......444***&&&'''$$$###$$$(((&&&&&&((($$$(((%%%///$$$'''555,,,SSS,,,***(((---+++WWWAAA,,,&&&+++444((('''$$$+++444***%%%###!!!111111***$$$###$$$&&&333222###---...(((***+++,,,000@@@...---222...<<<555GGGFFFIIIAAA:::OOO555EEE<<>>444555222555444555666666222444555111666666999<<>>999TTTEEE:::BBBHHH000...555444JJJSSSsss777...:::222???***$$$******......***///@@@+++'''''')))<<<---'''%%%,,,>>>NNN:::333---111444555000(((---%%%%%%'''%%%((((((111222''':::...)))&&&)))///555444WWWvvvAAA+++:::UUU+++...999,,,''')))MMM,,,111'''''''''$$$'''###"""888999///222%%%(((!!!"""$$$'''(((---888888111444...------444///000///666:::ZZZLLLDDD???@@@>>>XXX???AAAMMMOOOTTT@@@888555999444===777555999???>>>777@@@DDDJJJOOOIIIIII777111222TTTFFF777TTT555444444...000444+++***...CCCGGGVVVCCC///222///...---AAA+++(((888***000777111...000666999KKK111444777222333444333///444;;;???555555555000,,,...111,,,---,,,,,,333+++333...111,,,---,,,333<<<444111===JJJ;;;:::888DDDBBBFFF@@@BBB;;;111...444222111...???PPP000...,,,......&&&+++%%%)))...+++***,,,444...111+++'''***...+++)))999BBB;;;<<<555***444333---((())),,,***(((&&&'''***&&&***((((((+++???---'''%%%&&&)))111jjj7LLL//////111???>>>(((---******###$$$(((***%%%FFF,,,)))'''"""######MMM)))$$$&&&&&&%%%###(((%%%"""###(((,,,JJJ--->>>555,,,...111333666///333888@@@BBB@@@777AAA;;;@@@JJJCCCFFFAAAHHHBBB===,,,333444>>>DDDFFF>>>>>>DDDHHHZZZQQQGGGDDD]]],,,222...444(((***,,,,,,222222;;;///111111---333666@@@LLLZZZ===...+++222:::111+++%%%"""+++---///222<<<777555222III333000555111---444777000555???777444555666555888111666///,,,***......+++...555---000222444...555333:::111@@@VVVCCC999BBBFFFDDD???AAAEEE@@@666000///(((///000000222---,,,...***)))'''###$$$'''222///***)))222QQQ---888&&&---'''---000999III:::666444---+++...@@@---&&&%%%((('''...'''###&&&!!!$$$"""&&&)))(((%%%$$$+++$$$+++PPPggg000555***,,,jjjRRR(((DDD666111$$$'''+++%%%''' //////*** $$$$$$%%%&&&AAA///&&&???TTT333(((%%%***))))))***+++,,,111333...111777222666???>>>@@@AAA>>>DDDDDDUUU???>>>LLLSSS>>>555GGGBBBBBBWWWLLL@@@???GGG\\\NNNkkkDDDrrrBBB===;;;666..."""######---///444555111111555///:::555<<>>;;;VVV111---000,,,,,,***)))---,,,,,,+++...000333---,,,///999111+++...777555444???888<<<;;;888000333///---...000,,,...222,,,...000)))%%%"""%%%---'''+++,,,'''+++)))222---555222///+++---+++111...,,,777444222;;;)))???444%%%"""###$$$+++'''&&&$$$"""888$$$!!!&&&))):::''' &&&LLL```///...---///%%%...,,,@@@;;;000333TTT(((+++222###***(((111:::!!!######:::(((+++:::555'''(((000)))+++(((%%%)))CCC&&&(((,,,KKK222222111333888222OOO>>>555;;;SSSIIIAAAHHH:::@@@FFFWWWIII:::DDDOOOKKKggg<<<>>>HHH888BBBBBB444KKK^^^VVVrrrAAA666BBB&&&###'''111444666555444999222666999777>>>>>>===222333666000111,,,:::___:::111***+++444333444///333222777GGG888111,,,---,,,...---444444777;;;000111222555BBB555333---***+++))))))))))))---888...222///...///333------333777999111888BBB@@@333333777000///)))111......***...***&&&&&&(((&&&+++***---++++++///...444000---:::///***000+++((((((...333///***---666222'''777$$$!!!###%%%$$$###%%%'''""""""!!!%%%%%%'''%%%&&&(((;;;,,,(((***222---+++,,,...000222((((((???444///...***&&&$$$''''''&&&"""###!!!$$$"""&&&000111000III---$$$###///%%%///(((---555MMM)))((((((333111000111222666:::yyy888000BBBYYYDDDHHH^^^KKKBBBFFFGGGBBB======HHHHHHkkk999;;;666:::>>>@@@DDDsssnnn```eeeNNN@@@>>>---)))...000111<<<444444777===555111;;;FFF888222222111000444222---@@@:::555>>>&&&'''...111111---222CCC555666000]]]111555......000---,,,000000222111CCC555111+++---000...,,,)))(((******000111---......(((+++,,,---000555LLL111+++BBBNNN999999222999,,,(((///,,,---???+++333FFF---,,,...///(((+++...***000+++444999999222333***)))+++******///,,,,,,+++,,,555+++'''$$$!!!''')))%%%&&&&&&$$$!!!!!!### """&&&$$$(((111777666222+++===666:::+++...444......444---555%%%###"""((((((***AAAQQQ###""""""QQQ:::===222$$$###%%%'''(((%%%&&&;;;666DDD***'''$$$***???:::000,,,444<<>>444111...///,,,,,,+++555%%%)))***---(((***666))))));;;666222111///+++---:::---'''((('''---000(((&&&###444888%%%"""'''%%%%%%###---888(((///---KKK333***(((###---...666666EEE===000222'''&&& )))"""$$$$$$%%% &&&$$$)))111!!!###&&&+++"""&&&###&&&&&&%%%(((000@@@###&&&$$$+++000///222444AAA:::OOO...777<<>>+++)))...+++///,,,+++$$$NNNPPP444((((((555000000000:::555888444//////333333777555222222000000+++*********))))))+++...UUU///&&&+++((('''---,,,(((((('''...+++---000000...<<<,,,000---000...&&&---)))222555777555[[[PPPcccfff444888;;;,,,***,,,+++000222)))---)))///***111...(((///,,,$$$***KKK///BBB000,,,***444...&&&:::)))'''&&&###%%%)))---+++...---***DDD777000:::)))###222///666222@@@EEE333,,,...666000GGG***!!! 555&&&(((###---,,,$$$!!!%%%)))((($$$$$$&&&'''PPP222,,,$$$$$$$$$###777++++++***777444666333444888:::888===;;;IIIJJJMMM@@@>>>QQQEEECCC;;;???@@@;;;,,,***444EEE555999BBBLLL???WWWFFF===TTT666333999&&&//////---555666???<<<000777111>>>)))+++***,,,---444000---000,,,+++++++++555;;;999555<<<999666777666DDD555222555///222MMMFFF///---)))666444...000111111222,,,---000555111)))+++'''++++++///000<<<444111000444,,,***)))%%%!!!"""---///111222@@@III===777;;;;;;---000,,,++++++******'''...000+++---???+++***:::,,,666((((((---***///000222***///,,,&&&$$$&&&$$$'''''')))(((...---***QQQJJJLLL444+++444GGGUUU444+++)))""":::III444---""")))FFF///)))***"""000 !!!)))'''((())) &&&$$$###'''))) !!!######""")))***)))***JJJPPP===---444:::666FFF:::;;;777:::DDDGGGAAA>>><<<:::JJJ===III:::???888999000KKK***999???LLLSSSDDDHHHFFFIII>>>JJJ***///???'''...000III888333000///DDD***+++***///222777888++++++...:::+++&&&000ZZZIII???MMMAAA:::444;;;BBB:::111---111...OOOPPP666888111>>>111555888888666666666555555:::777...(((***+++000---111222000111111CCC111---$$$$$$222333777111CCC666@@@555555555222222333888---'''((((((******111---ooo//////999///+++(((***---'''///111999///777000---*********...'''''',,,555IIIGGGPPP{{{XXX444,,,GGGCCC,,,***;;;)))///%%%&&&...---,,,$$$JJJ$$$***BBB$$$!!!&&&  $$$"""%%%JJJ ***%%%)))((('''$$$&&&"""%%%&&&$$$$$$"""&&&***'''***GGG333777222...333666111111333<<>>???:::DDD===777AAA@@@DDDPPPBBB///222666555@@@CCCAAAJJJqqq___:::<<>>@@@...000,,,...---444......+++,,,///......CCC"""...444111000///222444HHH555222333???000555888///)))///,,,)))666---+++,,,'''+++,,,------,,,...666......---+++000444,,,'''%%%%%%&&&,,,&&&...+++***444666>>>PPP dddHHHlllyyy""""""&&&'''(((>>>%%%$$$GGGWWWUUU:::"""%%%)))+++###!!!!!!&&& ###$$$ $$$&&&---///""""""###$$$'''***777'''///(((((('''(((000777333---222777111222444<<<:::222333<<<666AAA;;;;;;111<<<444@@@BBBTTTiiiWWWaaa===888444999,,,:::HHHmmm;;;222'''((('''+++666+++222VVV///)))555111222111111999111...///000,,,******$$$...555555333666555111BBB???111000***---::::::666444@@@RRR???===@@@OOOvvvCCCWWW;;;:::444111222555???555000...---+++222000---000---111<<<333ccc@@@,,,...444000555666888222hhh333,,,666:::777222222+++444,,,,,,222777666000)))((()))111111---===EEE222---,,,+++///+++:::)))******'''---999111000DDDkkkKKK===???SSS222999999---666***111'''+++)))@@@111<<>>111SSS,,,---///222...111---+++000---***888TTT...+++@@@222555000999333///LLL111&&&&&&%%%---ZZZLLL@@@HHH000555&&&'''111'''000>>>///###&&&'''...222CCC222444777222,,,,,,&&&...(((***,,,%%%(((***SSS444666+++777GGG::::::...(((*** """ !!!""""""===CCC...+++!!! ###!!!$$$ """$$$'''(((...***%%%)))///---333000333,,,///111222111:::888111000222222222666???666>>>BBB>>>IIIhhhZZZUUUkkkPPPQQQ888,,,111///444444>>>+++LLL111+++***(((222???999RRR888777222222...;;;333777???CCC444111000000///333,,,000444111999???CCC<<<444222777333fff:::777;;;>>>CCCLLLQQQddd^^^VVVmmm<<>>+++***$$$+++HHH---666%%%%%%***###$$$+++###$$$%%%(((>>>FFF(((444]]]AAATTT@@@:::###+++ ###888)))***"""000--- ###$$$!!!'''JJJ###$$$333***))))))000,,,***&&&(((,,,---555CCCEEE+++///222888222:::...444<<<>>>777<<>>FFF999000333222GGG===999///:::......,,,***///:::...---666333---......+++111:::CCC***'''222$$$###444+++333555***111888)))+++!!!###!!!""")))&&&'''111FFFGGG### RRR!!!$$$###((($$$@@@---)))---SSSLLLMMM???QQQccc:::222 ,,,*** JJJ"""))) %%% $$$###"""%%%""""""BBB!!!$$$+++&&&%%%)))---000,,,...)))(((---444333bbb444000000444...999222999777999666<<>>)))CCC<<<(((!!! """$$$!!!555000"""%%%***!!!"""###""""""###"""%%%###,,,(((&&&&&&HHH777,,,///)))...111111555444333,,,,,,333...OOO555000///222999111555;;;CCCgggPPP\\\RRRMMMEEE666111777 """***---,,,***333)))+++---888444999AAAAAABBB888777333444111444222333444444666777444999AAA@@@<<>>SSSAAA;;;666999@@@jjjCCC999111LLL444111GGGGGG333222...------///;;;///AAAFFF222888AAA222000111(((***)))999,,,;;;,,,(((000---+++$$$)))### ######""" ---+++ ((($$$&&&///---&&&)))%%%)))555---)))###&&&&&& ###%%%000,,,***999 !!!""""""$$$((( &&& ***(((///$$$%%%$$$///(((***+++///111777***777111444111,,,000777555555222555333111FFF555BBBddd$eeeFFF<<>>777444555;;;777666777777666>>>:::777666<<>>888===333888///---(((000(((,,,......+++)))$$$'''"""###"""''',,,"""###))) '''!!!&&&%%%###+++...---***GGG444+++111"""  --- (((!!!!!!;;;NNN555=== 111 &&&"""$$$"""!!!!!!***!!!///$$$"""'''%%%(((***+++---000111...---***...+++000***333777,,,MMM>>>666555555666??????LLL>>>CCCFFF555BBB999111000111222333999===///---+++...---222444000---888555666333000PPP555>>>777===^^^999777666555::::::555222111<<<@@@;;;666===LLL888222555444555DDDEEE<<<999OOODDDxxxIII777222===333222666555<<<000333666888AAAIIIHHH;;;<<<555:::888555777...666///222888555111---111OOO;;;666999OOO444AAA000777888;;;999333888===999...333111,,,///------***...+++)))'''((("""""""""''' $$$***%%% ###"""%%%)))$$$"""444111'''///((('''!!! %%%(((SSS???###888 !!!)))&&&###(((%%%$$$"""+++&&&'''111!!! ###(((///999BBB,,,000555222GGG111---///...(((***---000AAAEEE>>>333555555888999@@@BBBIIIRRR@@@777LLL;;;:::444BBB888???JJJYYY---&&&...,,,***111333//////***777///111...:::777;;;666>>>JJJDDD666888OOODDD<<<@@@444777888888888888000EEE,,,(((222333UUU@@@>>>444;;;<<>>---CCC444666777DDD555<<<888555===888???AAA444===333000666///333222)))CCC...------444$$$'''***%%%(((!!!!!!!!!%%%+++!!!,,,111,,,!!!$$$$$$$$$%%% !!! !!!"""&&&&&&)))'''""")))###555""" 000 EEE""" %%%$$$***)))111333AAA)))111ZZZDDD111+++...,,,)))((((((---111111333888444WWWBBBBBB999CCC@@@???999999===<<<777:::;;;>>>@@@??????---)))222---444///333,,,'''222(((:::000***000...///...,,,BBBWWW\\\888777UUU???888111555<<<666DDD666000555%%%,,,...---111888>>>666222999000444999:::===999666MMMXXX---///111444666222???DDDAAA888888MMM222888@@@333333---...;;;EEE666///222:::888;;;666555000rrrAAAEEEGGG[[[MMMAAA888,,,///555......'''(((???444)))000$$$$$$(((###$$$"""!!!######%%%''''''JJJ%%%$$$)))!!!!!!***!!!333(((BBB444 ###"""  ---###!!!%%%'''!!!(((***+++???:::666444'''000666WWWQQQ)))'''***$$$***,,,///666:::III;;;RRRBBB???999666>>>888GGGIIIFFF===???555BBB]]]}}}HHH777000---///333222---:::///333AAA---,,,,,,'''777---+++,,,111:::;;;BBBFFF:::BBB<<<333000555555777IIINNNTTT@@@,,,+++,,,333;;;444777666...000---===GGGTTT777:::333III???***(((///333:::BBB::::::AAA???333111666MMM777666222777777999JJJGGGVVVEEE===666@@@555444222ZZZ@@@FFFdddkkkVVV<<<@@@111111999+++,,,'''&&&...+++@@@<<<(((%%%$$$######'''''' )))$$$BBB"""!!!'''""":::%%%***  """%%%###@@@TTT---"""!!!!!!$$$ """ &&&!!! !!!###'''"""%%%(((@@@MMM???MMM;;;///222333((()))))),,,%%%%%%+++***222222555>>>===GGGTTT777111555222555fffAAAIIITTTEEESSS======<<<444222---555666...,,,555>>>III444---(((,,,,,,:::///...------555555999JJJ;;;;;;888555666666111555777222MMMBBBAAA000///444555999>>>000333000...222:::???777222777===CCC***+++)))...444555888222333111111333111555444333888444...444111===999222:::???***666000///777===KKK{{{HHH;;;111333,,,---...,,,$$$))))))***888(((@@@888***ggg((( !!!!!!###$$$!!!$$$###&&&""""""### 222+++###"""$$$###!!!!!! ###,,,YYY+++"""'''$$$###%%%### '''$$$888QQQ:::,,,ZZZVVV;;;OOO,,,333,,,***+++...+++>>>999(((###666######444222WWW777GGGmmm555;;;<<<<<>>555YYY999///555333FFFDDD666888///,,,444222OOO111<<>>,,, !!!$$$888111"""222,,,555######!!!%%%DDD***%%%'''(((###""" &&& """ 999GGGKKK''')))333&&&666\\\(((&&&...000PPP888000++++++,,,AAA...222000...444###%%%$$$"""333...777+++666888222///AAAGGGmmmFFFKKK\\\hhhddd666444333555...---,,,EEE:::,,,+++@@@999999555666111...)))***...,,,---///...???KKK888222222@@@AAA222555333,,,)))111000222333,,,+++---111)))000666111,,,,,,...+++...999222000***...,,,111333333@@@111///222222///===<<<<<<222666222DDD???333333???OOODDD???111222,,,000JJJ666;;;:::333;;;,,,555(((333***---&&&)))+++RRR333222777@@@CCC///000ppp===+++((($$$((("""%%%BBBWWW!!!&&&...))) !!!%%%000%%%&&&%%%+++'''FFF ###%%%DDD---<<<)))&&&,,,###'''$$$ ))) ((('''===111&&&&&&###bbbjjj&&&'''222%%%111===///&&&+++///000...,,,000222,,,///"""'''!!!***111000---444+++++++++<<>>;;;;;;999888III///333777777???333***---)))999333UUU111555222333(((111'''==="""""""""%%%EEE111'''TTTIII???111>>>fffIII)))((( '''666mmm+++'''%%%+++!!!>>>!!!!!!$$$,,,%%%$$$&&&!!!''''''BBB===///)))$$$&&&&&&444PPP777DDDBBB%%%###!!!""",,,(((OOO &&&&&&&&&)))&&&:::'''000...%%%%%%+++>>>```DDD999...111,,,---'''###))),,,,,,>>>>>>...:::EEECCC111???333VVVPPPBBB===222'''###&&&)))666>>>888,,,;;;((()))+++///'''***+++===+++***+++111111777,,,......000333iiiCCC<<<***$$$&&&$$$%%%DDD666111666666,,,***,,,'''&&&+++111)))111222000444+++...000000333555555///333???111444888777888FFF888999777:::???555...000111;;;,,,...***777---((()))---***333...%%%###'''<<<&&&(((666+++%%%''')))333&&&+++@@@@@@666DDDccc000&&&"""((($$$'''''''''(((999''';;;***######111&&& 111###""",,,---+++JJJ,,,+++DDDNNN666RRR!ddd777(((''' ###%%%///:::!!!  """'''HHH$$$&&&666888AAA333AAA(qqq666999999888)))$$$%%%((()))***000)))>>>FFF,,,///HHH222000777...'''&&&###...---(((111......%%%)))&&&)))...((())))))&&&///666+++---///...HHH+++000,,,))),,,???oooKKK111...'''%%%'''%%%)))444555))))))(((&&&+++111,,,999///...000,,,///111///000---,,,000111555,,,555;;;444UUU:::CCC555fff555666444777777333***111@@@000///444------$$$!!!222444'''&&&''')))%%%)))>>>(((%%%###'''&&&"""%%%"""&&&!!!(((>>>555888)))444...)))!!!$$$!!!'''%%%$$$ """///(((!!!)))###111"""***+++"""222888BBB======AAARRR999JJJ}}}5TTT///'''HHH111HHH&&&!!!%%% '''$$$ &&&%%%""""""333(((222???CCCIIILLLAAA111***&&&"""&&& !!!######)))%%%***%%%(((&&&999111IIINNN///111<<<222++++++)))((())))))333///,,,(((%%%"""$$$'''(((---(((&&&...///333))),,,+++&&&))))))---,,,333555&&&'''&&&$$$'''%%%$$$((()))---///++++++---***))))))***......000666888///222000,,,,,,---000+++777555===888888444AAADDD@@@:::777222111444YYY777000555555333:::@@@222111''''''$$$:::###"""...;;;%%%'''(((***&&&%%%!!!""""""!!!""""""$$$YYY---$$$666)))...OOO$$$(((&&&"""'''!!!!!!***+++"""###(((???$$$SSS&&&&&&;;;...222888``````RRROOOPPPIII kkk777RRRPPP$$$ ###...JJJ###SSS333!!!!!!$$$******,,,"""&&&+++333RRR~~~VVVJJJIIIeee444AAA)))222***!!!&&&$$$&&&%%%&&&''')))...***)))111999333+++))))))'''...999'''&&&!!!"""---***...,,,)))'''"""&&&'''+++((($$$+++)))ZZZ***///+++///)))...000222"""%%% """$$$((('''%%%&&&+++;;;$$$'''CCC***---)))&&&,,,+++222'''(((&&&***111+++...---HHH111000111888NNN<<<444;;;555TTT666///SSSRRR>>>OOO===222111,,,IIIaaa???///,,,---%%%)))+++---...666CCC(((%%%'''***,,,222###%%%###!!!"""$$$!!!$$$000'''"""%%%%%%(((222AAAPPP***%%%+++444888///---!!! '''333!!!%%%###!!!%%%ooo...EEEjjj rrrGGGMMM<<>>'''&&&%%%&&&%%%$$$$$$"""###***,,,+++)))(((...'''(((&&&,,,$$$%%%333)))'''###)))***!!!)))$$$)))###$$$+++'''&&&111111&&&***+++%%%***JJJ'''$$$000111444:::---///777222:::111000777555777999999SSSOOOVVV>>>444<<<000///:::888AAA333---...RRR000&&&,,,///DDDEEE666%%% ###+++VVV%%%%%%%%%$$$%%%###***&&&,,,+++((( ###%%%666XXX---***...""""""444AAATTT'''///------### ###'''%%%GGG+++]]]CCCCCCMMM///fffhhhXXX<<>>:::,,,MMM&&&<<<;;;===###### %%%###$$$%%%###%%%%%%$$$######&&&"""!!!%%%$$$)))''''''&&&###...&&&'''$$$%%%///,,,""""""******(((###"""###!!!,,,+++'''!!!"""!!!$$$,,,!!!&&& %%%&&&&&&###&&&)))+++AAA+++%%%222,,,***&&&%%%***111;;;777TTTDDDRRRooodddEEE000))))))---***555FFF^^^BBBHHH000CCC222000(((%%%'''///!!!"""######!!!""" $$$"""!!!"""###'''"""%%%"""FFF"""***>>>111999$$$;;;)))######+++&&& ```###999///,,,(((:::"""$$$$$$"""@@@$$$%%%---222%%%)))333$$$ ---}}}]]] !!!###!!!%%%>>>,,,(((%%%###%%%zzz555>>>&&&---+++*** """!!!$$$,,,"""!!!,,,$$$(((###,,,!!!%%%"""%%%$$$###'''&&&"""&&&+++''')))&&&111LLL"""######///'''"""""""""### !!!  !!!<<<$$$!!!$$$   !!! ###%%%%%%'''&&&---777>>>:::((('''555(((***111222444cccnnnvvvggg[[[///---...$$$)))555&&&+++///)))000///888%%%&&&&&&###%%%$$$,,,******'''###!!! 666555)))###<<>>333%%% ...$$$!!!)))"""###"""(((...###'''###$$$&&&((('''$$$$$$!!!###!!!$$$###!!!)))%%%===&&&333^^^"""###+++'''!!! ((( """ $$$*** ///$$$ +++%%%!!! """$$$333<<<;;;mmmMMM***...,,,222///111......uuuaaaeeeDDD333***))))))%%%666)))"""!!!"""'''222%%%,,,666%%%+++'''&&&&&&&&&$$$### """!!!$$$...!!!666JJJ888555@@@III*** &&&!!!!!!!!!(((!!!"""...'''))))))(((%%%&&&"""&&&)))...,,,###"""111###222***;;;000/// !!!###*** $$$222(((%%%000$$$$$$''',,,(((&&&%%%!!! ,,,(((!!!&&&"""""" '''%%%(((%%%%%%###)))&&& $$$!!!&&&***%%%!!!!!!"""!!!AAA""""""### """!!!"""!!!<<<'''555&&&)))###,,,000%%%&&&'''333///WWWIIIWWW...%%%$$$$$$&&&...'''666&&&'''%%%000111---OOO@@@333&&& %%%"""((("""""" )))###...&&&%%%$$$###MMM---,,,***!!!444!!! )))!!!!!!"""!!!,,,###---sss000YYYCCC '''+++$$$---TTT~~~qqq???$$$ """!!!%%%#########)))'''###+++***###'''(((""""""((( !!!%%%&&&"""###888###$$$!!! 222 """"""  ###"""$$$---"""$$$!!!$$$!!!"""!!!;;;$$$!!!...>>>AAA222NNNDDDooo'''&&&###%%%&&&)))''',,,### ###+++///---888777eee""" ,,,###"""---,,,)))%%%777###888%%%&&&333EEE"""'''%%%&&&***""""""222***!!!111iii111555555+++!!!'''///FFF...QQQHHH555***&&&%%%### ###%%%)))***$$$"""$$$,,,((("""###///)))%%%!!!&&&###$$$&&&&&&***%%% !!!%%%!!!%%% !!!!!!$$$'''!!!!!! ---!!!!!!EEE&&&)))%%%***)))...JJJ000PPPNNNQQQ777"""""""""000111===&&&"""...((($$$EEE%%%&&&'''444 )))!!!'''555$$$"""###(((""""""$$$333---###!!!"""///???'''((($$$&&&jjj&&&222GGG+++""" :::!!!'''%%%!!!"""$$$888000---CCC111666999...$$$)))###&&&""" $$$ $$$ '''%%% """%%%###!!!!!!!!!'''###%%%!!!&&& ###)))%%% &&&---:::,,,666###"""...CCCZZZWWWVVV###... 666HHH111888+++ ,,,888...!!!!!!111 $$$  %%%###*** )))###  ..."""###&&&    NNNCCC***###!!!)))(((YYY(((222777==="""'''"""222!!!$$$ +++$$$%%%""")))***%%%$$$111@@@NNN???BBB+++!!! """###%%%%%%!!!***!!!$$$222!!!$$$""""""###!!!%%%!!!!!! ,,,  )))!!!222"""$$$###!!! xxx;;;"""###*** """%%% ***888&&&"""LLL """+++###555$$$!!!000   QQQ 444???)))!!!###&&& 666)))!!!###<<<$$$%%%/// !!!###""" 333###$$$$$$###///UUU???222HHH !!!$$$!!!"""%%%!!!###!!!)))///////// '''### %%%!!!!!!"""%%% !!!!!!,,,###!!!"""222 """ 888%%%***___(((000 $$$$$$!!!&&&,,,!!!$$$ ///&&&!!!(((""" ((((((;;;FFF000;;;###""",,,)))+++'''$$$!!!!!! %%%!!! ###&&&'''%%%$$$"""&&&@@@222,,,---FFF###### ###""""""%%%!!!### ((("""###!!!!!!'''!!!  ((( """"""***EEE!!!'''!!!&&&%%%(((!!!///  &&&###"""!!!$$$""""""***!!! ### $$$%%%!!!"""!!!&&&%%%######%%%%%%&&&"""$$$&&&%%%%%%!!! $$$###!!!!!!---!!!###$$$$$$###((('''888(((###***$$$---...''')))...///+++(((///111TTT(((%%%,,,111---;;;AAADDDUUUyyy\\\;;;999>>>333FFFoooAAA+++++++++---(((---,,,///((((((%%%222 666===))))))&&&'''&&&$$$###((((((&&&///+++***(((''',,,"""'''(((***((($$$$$$%%%,,,///&&&)))'''&&&+++&&&((()))///111555///222111---<<<&&&---...111///...)))000///444...888AAA777444))),,,$$$%%%"""###''';;;LLL///111777CCC===999<<<222:::>>>222444999666'''...000222000:::===***,,,222333///111***'''///'''''''''333444%%%'''""" !!!!!!$$$+++###""")))%%%!!! """$$$""" !!! &&&!!!%%% 000%%%###%%%&&&### ###"""$$$--- ###,,,"""!!!!!!###((("""%%%###$$$&&&"""&&&)))+++)))555---000"""(((???,,,)))'''++++++###---))))))###///)))444---<<>>111,,,111...---888222444,,,)))000+++***)))555+++...///555000111...,,,)))///(((&&&***$$$!!!+++333222&&&222333NNN888444III444MMMNNNIII===III???>>>;;;;;;///<<>>777444***,,,///555777444...###$$$555,,,***...---UUUDDDAAAIIIIIIEEE===GGGGGGEEELLLSSSBBBDDD???CCCPPP999@@@444+++...---111111***,,,111'''///)))***,,,(((&&&%%%!!! """ """ ***EEE""""""(((%%%!!!!!! %%%###!!!"""!!!***&&&$$$$$$&&&!!!!!! $$$'''&&&)))!!!!!!'''&&&&&&222...)))'''%%%###$$$((((((%%%+++***%%%///---(((---...(((555777///333///555---+++%%%>>>???,,,,,,000***"""'''(((,,,...444LLL[[[444000888UUUlllJJJMMM222000//////---777444(((++++++,,,'''***&&&$$$###$$$"""+++%%%+++---+++'''$$$&&&000$$$(((***%%%+++'''++++++''''''(((+++333555000---333///+++000)))(((%%%$$$+++,,,---777888777333777AAA999888888:::222:::888333999555CCC:::333111...///,,,,,,111555)))%%%###111777CCC000333888===666999<<>>CCC222;;;IIIFFF888...,,,***...!!!%%%&&&((("""###111)))...333 !!!###444  555+++'''---  111%%%!!! '''%%% """!!! ###!!! ###***---!!!$$$))) ''''''''')))%%%...,,,///@@@--- ---***''''''&&&!!!///222///<<<@@@,,,'''111###""" +++???---,,,333333+++666222(((,,,///000444???DDD000***+++111***'''###%%%***(((+++---,,,---,,,###///...### """***EEE&&&"""###!!!"""###"""$$$'''%%%!!!###'''***+++>>>000000000000,,,,,,555(((,,,###"""'''(((+++,,,...(((,,,333888QQQ:::[[[:::777777>>>EEE???<<<222999EEE555999+++666[[[???KKK999,,,@@@---***(((///,,,???>>>MMMRRRQQQRRRIIIEEELLLZZZJJJSSSBBBDDDUUU===DDDRRR```444333...(((+++(((---$$$+++$$$***%%%%%% """!!!!!! ---  !!!###%%%%%%!!!%%%'''"""&&&!!!"""""" """***!!!)))---!!!(((...'''%%%///"""+++%%%+++)))***---999444***&&&%%%---222***)))%%%&&&@@@???EEEgggLLL---$$$!!!!!!$$$!!!&&&222>>>&&&---(((---)))000(((///+++---333555000,,,---)))...---,,,,,,''')))***------+++AAA222...%%%###$$$""" !!!!!!$$$***"""!!!$$$$$$$$$&&&)))"""&&&&&&&&&$$$,,,***$$$(((,,,)))(((***+++000'''!!!,,,...444,,,111000***(((---000PPPFFFEEEHHHFFF???III;;;===<<<:::FFF@@@+++(((+++GGGIII===666GGG[[[222"""(((555000)))000<<>>666,,,---444JJJFFFFFFSSSQQQSSSZZZJJJNNNKKKJJJRRR```kkk[[[RRR@@@:::000...+++---&&&'''111***###&&&(((%%%######%%%$$$$$$###&&&!!!///+++%%%;;;### 000;;;MMM%%%%%%&&&))) 111!!!$$$$$$&&& ((()))!!!###  """!!!$$$$$$$$$>>>###$$$''',,,"""###)))BBB333:::BBB333---RRR111...(((...111000333BBB***++++++000'''333>>>///---)))$$$!!!$$$&&&(((///444***++++++222888---***,,,---///444HHHSSSMMMfff<<<111...+++)))(((((()))$$$&&&)))((()))%%% )))!!!777***::: ###"""$$$%%%""" $$$&&&"""'''+++%%%###&&&&&&******(((&&&***&&&%%%$$$$$$###&&&888,,,---000999777***000333++++++###***+++HHHBBBWWWKKK@@@BBB???@@@888:::???>>>AAA...333|||BBB<<>>===@@@222222FFFFFFAAAIIIHHHLLL\\\RRRFFFDDDjjjJJJXXXYYY[[[NNNAAA@@@CCCCCC///...777KKK:::111***$$$###(((''',,,BBB  !!! $$$"""###'''"""$$$+++)))'''!!! 555:::,,,QQQ444%%%### ???111 """!!!999---%%%###%%%!!!&&&"""'''"""$$$---///'''***'''...;;;MMM((()))'''BBB555:::+++000+++111333+++///BBB...111333888...111GGG999555))),,,///000///+++((('''###&&&///111+++...///...000,,,***$$$ ,,,===///999zzzFFF(((+++***"""++++++ >>>JJJ''')))***666...555%%%###%%%000)))$$$$$$&&&'''%%%###%%%$$$"""%%%((()))%%%"""$$$###,,,###$$$$$$%%%$$$&&&***WWWfff***LLL{{{000******///444333111---000***333777888<<<777???>>>TTTPPP@@@CCCLLLQQQ888TTT333///111VVVJJJHHH;;;LLL{{{666...@@@JJJRRRFFFhhh\\\ZZZVVVJJJEEEKKKJJJNNNffflllbbbiiiGGG<<<777777...666888000999888)))###'''999555@@@/// ###!!!!!!!!!!!!%%%... $$$"""$$$!!!"""""" !!!!!!%%%---666555###&&&######***"""888!!!$$$'''&&&---)))%%%### !!!$$$$$$'''###%%%)))+++***CCCNNN<<>>???OOO===AAA;;;DDDDDDAAA222///>>>fff999@@@PPP^^^666***,,,DDD???;;;hhh{{{JJJ EEE???DDDFFFRRRdddYYY|||rrrCCC999III>>>@@@>>>444666@@@999,,,+++,,,000---000%%%###"""!!!"""""" $$$$$$$$$%%%"""!!!!!!"""###)))""" """!!!!!!777+++111%%%''',,,333,,,///'''(((&&&)))***"""---'''### ***###"""000***%%%,,,&&&$$$888,,,111,,,;;;DDD---BBB999:::>>>TTTEEE///&&&######&&&222uuu111((((((000(((''')))'''(((666OOO(((###&&&((('''***666***+++***((((((..."""""" !!!###!!! !!!&&&???&&&"""&&&$$$%%%000//////000555###000...???'''&&&%%%###111((()))***%%%$$$%%%%%%&&&'''$$$)))%%%&&&(((&&&&&&'''(((%%%$$$!!!!!!$$$+++'''...---333---111777///888///111111000///---(((///000JJJ:::;;;===999GGG999???BBBCCCAAA>>>777555666999888:::PPPNNNMMM>>>---444333===@@@JJJeeeSSSeeeHHHAAABBBVVVUUU```~~~qqqLLL>>>222222<<<===LLL:::888888///---888000333333,,,&&&### ###'''%%%<<< !!!"""&&&,,,%%%"""   """$$$ ))) &&&### !!!$$$%%%,,, """ """$$$%%%&&&&&&***((($$$ """### ######(((%%%***...DDD'''(((777###!!!((('''+++***+++333......777111999OOONNNYYY(((FFF(((&&&"""!!!''''''&&&,,,$$$&&&''' ***!!!$$$'''(((%%%DDD(((,,,333CCC***---(((;;;444(((***))) )))&&&%%%$$$$$$%%%###!!!!!!;;; !!!+++'''111***.........,,,,,,&&&777***===((()))&&&!!!%%%...+++((((((""")))000---%%%%%%&&&)))'''"""(((&&&***'''+++%%%###""" ((($$$)))GGG111LLLEEEHHH111222333444000111......+++,,,+++)))444777444:::BBB<<<>>>QQQNNNHHH;;;:::333///444999BBBAAAEEE@@@777888000444:::888888LLLJJJYYYpppLLLVVV[[[\\\MMMTTTMMMJJJCCC444444::::::===777111222---((((((...000777///"""%%%###$$$)))""",,,+++"""%%%%%%!!!###%%%###%%%###"""$$$$$$%%%%%%!!!***222 %%%$$$))) &&&***%%%### """!!!!!!$$$&&&)))'''(((444,,,$$$///+++(((000---***...333555777///000222888GGGTTT***777444...(((---'''$$$  !!!$$$$$$###"""$$$!!!$$$%%%(((+++''',,,---(((***///@@@XXX((()))---EEE'''%%%$$$(((###!!!+++###$$$%%%%%%'''&&&"""%%%$$$((((((333'''((()))999...%%%,,,<<<((('''""""""&&&***&&&+++000'''---&&&)))(((&&&&&&'''''')))111***000,,,+++...(((&&&"""$$$)))---,,,(((///555555AAA666555444222111222(((+++*********:::>>>===::::::777???GGGDDDDDDfff333000...>>>KKKGGG555<<<777444...888:::666222+++...DDD^^^ZZZeeewww aaa[[[MMMIIIAAA:::222999999222...222,,,///------)))+++333444((($$$%%%"""&&&$$$######$$$"""$$$!!! ###!!!&&&!!! ###%%%"""***...GGG(((###""""""'''### """ $$$&&&999%%%$$$$$$""""""&&&"""$$$###&&&!!!:::...<<<,,,444777///222555444777333000$$$---OOO444777...666000***'''%%%###!!!"""######""""""!!!###---///000)))+++222&&&%%%,,,---000******...EEE)))"""$$$AAA!!!"""$$$%%%BBB!!!%%%""" ###$$$ '''###'''###(((***(((+++***'''888777666$$$333)))&&&***&&&+++---,,,,,,***++++++''',,,---///...555,,,333***))),,,+++%%%!!!###"""""",,,+++***$$$%%%;;;aaa222000000555444///000... (((...:::CCC@@@777AAATTTAAA999BBBAAA999666222111777^^^KKKVVVGGG777888000222999;;;000333%%%'''NNNNNNXXX\\\ SSSMMMUUULLL999777333888777,,,,,,***333999,,,&&&(((,,,***???===666$$$!!!#########$$$ ######%%%(((!!!!!!!!!"""!!!!!!$$$000///%%%222$$$$$$,,,'''###!!!!!!''' ***###$$$$$$999###!!!222$$$(((III;;;(((((( """))),,,)));;;''',,,******333777555@@@===666JJJ444@@@)))888777------///***+++000---111$$$!!!(((,,,---"""%%%"""((()))'''(((###&&&***'''%%%%%%))),,,%%%)))(((,,,((()))***$$$"""!!!%%%222""""""&&&&&&%%%###(((&&&%%%(((OOO&&&000)))%%%@@@***''' """'''%%%000mmm222***+++---+++000(((...???((()))888***+++***---...333......111+++"""(((:::%%%***)))&&&,,,222,,,***(((%%%///222))))))+++333111---111---***'''------000999555NNN;;;@@@CCC999:::CCC999666111444666666===:::???777111000333555555---"""FFFKKKRRRhhhPPPSSSPPPXXX<<<>>>>>>666???333***+++>>>111///(((===222,,,%%%&&&///,,,&&&&&&$$$"""'''!!!(((<<<&&&+++'''###'''"""### $$$555$$$<<<>>>///---&&&"""###  !!!### $$$%%%$$$%%%###>>>222...###$$$)))***)))$$$QQQ((((((!!!$$$$$$!!!$$$***'''***---(((,,,***+++222@@@888444888222'''$$$---eeelll666555555333---//////222(((!!!)))+++,,,000'''%%%...+++((($$$"""!!!""")))''''''+++,,,************%%%$$$(((%%% %%%000444%%%$$$***'''"""&&&""""""%%%&&&&&&111(((""")))***'''$$$###'''$$$,,,***+++------(((***------******///++++++))))))---111000///111111000+++//////******,,,)))''',,,------)))---((('''>>>''',,,***+++333444222---...+++(((,,,)))---;;;GGGHHH>>>@@@===999777EEE>>>???333444---222JJJ666^^^EEE222111111111222111...%%%###***CCCPPPMMMXXXTTTQQQVVVMMMEEEKKKGGG:::HHH777>>>000+++***,,,******000---///)))((($$$$$$&&&%%%'''!!!((("""""",,,%%%%%%"""!!!""" """&&&&&&444111(((...---333:::!!!  %%%!!! !!!$$$!!!$$$$$$444...nnn333222"""(((""""""%%%&&&$$$"""###"""$$$***!!!'''&&&)))///,,,444,,,222222888???===------000+++JJJaaa333---JJJ000------!!!***&&&---111+++***(((***,,,***>>>%%%###$$$+++'''((()))ddd))))))&&&$$$'''"""###"""###"""###&&&---)))%%%$$$)))$$$%%%$$$###%%%###"""&&&%%%((()))%%%"""""")))(((...222+++111+++)))'''((((((***(((''')))444***---///******///---///333(((111555...111222,,,+++333:::@@@444,,,///+++:::111+++)))%%%333777<<<444333///...000&&&***///555MMM:::@@@SSS999111555@@@???777555555555LLL444???;;;666...333333444444555,,,,,,+++444pppwwwwwwbbbYYYQQQVVVMMMGGGEEE;;;333000555555666000333888......@@@+++%%%%%%$$$'''&&&$$$###$$$ """"""###!!!%%%###''',,,&&&%%% ......&&&###...###""" '''"""!!!###+++(((***)))...***,,,>>>...$$$######)))"""$$$'''###!!!(((&&&,,,%%%$$$''''''%%%&&&(((,,,000000...)))111222///666333NNN<<<222aaa`9]]],,,###,,,222'''&&&***111))),,,,,,......+++******+++(((,,,$$$%%%###...+++%%%''''''(((%%%$$$###&&&((($$$$$$%%%######!!!!!!$$$((($$$$$$%%%###!!!###&&&((((((''''''%%%###%%%333+++&&&(((***((()))***'''&&&,,,222...***...000...000333000)))000------,,,000000:::KKK...222555555555444333...333333888555...///---222000777222777888111777===333333222...222777<<<<<<444111===???888444777888333444555:::CCC:::888999666222111...)))000111```{{{___RRRPPP]]][[[VVVUUUMMMCCC;;;NNN555222<<<444CCCjjjHHH...444___***---***222...)))###""""""+++FFF,,,%%%""",,,!!!$$$###((("""$$$'''%%%)))%%%### !!!(((%%%### """%%%***WWW$$$:::555%%%$$$,,,,,,WWW000111'''"""%%%&&&"""&&&$$$"""###666---&&&NNN&&&)))###((((((,,,333,,,555555---***,,,&&&888EEE...[[[mmm>ppp999&&&$$$///***&&&###'''000***,,,...888444***+++)))''''''%%%---%%%###***666(((&&&###&&&'''&&&%%%&&&!!!%%%$$$%%%&&&&&&###$$$###---''' """'''&&&,,,%%% """""")))+++%%%,,,555***)))777******+++&&&(((,,,(((&&&---777000444111///444...,,,666///......***---...,,,***111555333===333111777000666777777444444///000222111---000555111222;;;111;;;===666333444666///888:::999444333666BBB<<>>222>>>///000222...///222000...111666...111777777666777888000???///222;;;:::666999HHH===LLL888;;;666666???666444333111111555444444000)))"""###)))666KKKPPPqqq___MMMQQQSSSPPPJJJ\\\888;;;BBB:::777666///---***(((###---000++++++000444,,,&&&&&&,,,%%%***(((+++$$$###$$$### ###))),,,000$$$$$$'''+++000!!!$$$###'''>>>$$$...333((($$$&&&...+++,,,***'''+++!!!$$$"""%%%""",,,,,,)))&&&((()))%%%'''%%%'''333(((&&&''')))***+++***'''&&&+++ &&&111///666///''',,,666((())),,,******000+++333111222000999//////***$$$"""&&&###***%%%%%%+++***''')))***///+++''''''---///&&&(((******)))&&&'''+++'''(((***%%%((($$$&&&---''''''&&&''''''+++111,,,...---))),,,'''(((,,,+++---//////444///000111777666===222---555EEE444///---((((((///333HHH666::::::UUU@@@000///222666000000444111444---///...///333LLL444333BBB@@@222555666888///+++555888:::333DDDEEE@@@===<<<===;;;333:::999777666444666<<<999...,,,///&&&...888LLLCCC???JJJfffKKKcccEEE@@@///999888===;;;222...***)))(((&&&((()))))),,,///<<<777///)))---'''))))))'''---'''***)))>>>$$$###%%% 999&&&&&&))) !!!!!! ...---!!! ???]]](((...&&&&&&---000(((///"""''''''$$$ ///)))***!!!$$$'''&&&$$$ """&&&)))(((&&&,,,+++...'''$$$$$$'''%%%$$$###'''''''''...***444FFF:::111(((333,,,+++///...000***000333111BBB---$$$)))$$$!!!!!!---((((((***+++111///***,,,000EEE...,,,))))))222333888,,,'''---...---...***%%%$$$&&&++++++***++++++)))***---,,,---***++++++000++++++)))***'''000...)))+++,,,999666333333AAA888///000111,,,///444000***///222:::SSSGGG===333---///111---666666777555???111000333333111333,,,///222;;;666888444333***333+++444222444888===999FFF>>><<<999666888777555888888888???@@@555000111---444===666DDD===III\\\[[[NNN@@@777BBB888GGGCCCBBB;;;444333>>>+++(((+++444,,,&&&---CCC111$$$AAA@@@,,,***)))(((---,,,&&&%%%###%%%&&&!!!###...444###&&&!!!$$$&&&"""333 !!!!!!///999222'''''')))(((555111+++!!!'''"""''''''!!!&&&222''''''%%%"""%%%""" '''######&&&444)))(((&&&***%%%"""(((,,,)))'''$$$)))***%%%"""333222:::WWW>>>888DDD444%%%333777//////...---000222777...((()))+++"""'''$$$)))'''&&&***+++(((+++000+++222555---)))---,,,111---///000111,,,...)))&&&666,,,---,,,(((***---+++...)))(((((('''+++,,,,,,,,,&&&+++&&&)))(((222+++,,,000000333ddd===666555@@@AAA444...000,,,444///))))))@@@:::222222<<<999BBB333+++......///333999<<<777;;;333444333...---,,,---000??????999777:::---'''+++(((111444888<<>>888,,,---,,,(((,,,///...)))---+++,,,(((444CCCHHH///...###%%%"""***'''(((""""""(((,,,***(((000111###&&&,,,/// """!!!$$$"""'''((($$$SSSRRR888%%%***<<<---)))000///&&&""")))""" !!!$$$###'''###&&& """!!!'''(((&&&%%%&&&$$$,,,(((&&&)))''''''%%%222444666333YYYttt888333999+++$$$---000+++''',,,,,,888666AAA///***%%%&&&$$$((($$$))))))...)))***---...(((---///777///111000///444===;;;...222+++,,,///444@@@555///222111///000666,,,***111111,,,***,,,******...111///---)))@@@***+++===333111444@@@CCCMMM:::666...444000222------+++,,,999===:::AAA444333111555EEE111///555000222GGG888666000<<<>>>///+++///---...GGGXXX555333000---''''''///222000333:::???FFF@@@777<<<999333666888666======888:::;;;===555333:::???FFFGGG>>>KKKIIICCCNNNCCC>>>DDDDDD___BBBOOO222000222,,,,,,222//////***,,,666+++###333...444---&&&###$$$$$$%%%###!!! ###%%%IIIDDD000HHH:::000'''+++...%%%###"""!!!!!!""" !!!***&&&JJJMMMAAA'''+++HHH,,,///TTT,,,""" !!!!!!!!!!!!&&&)))"""&&&###&&&,,,)))+++&&&$$$)))&&&(((******...***&&&///444555^^^1 LLL555///333...CCC333###%%%,,,111---===---333))),,,&&&)))$$$)))555000)))***(((,,,///AAA333333000000111000---...333222333444555333>>>777333555GGG<<<444EEE>>>888;;;999444000000222...***(((***...)))000...222:::777555:::111---BBB[[[MMM888000+++---999......---***---333///:::222444000...;;;444666...333999///@@@888<<<111111666444444000222...000:::333111111333'''***+++))),,,333333???BBB===BBB777999222888888999CCC???>>><<>>///111,,,>>>qqq***000%%% """&&&)))###### ###"""""")))%%%$$$222***$$$&&&***)))'''---&&&(((***+++---444...444444BBBwww_]lll???===<<<333666111333...///222---333,,,&&&(((...((((((111000000...+++,,,+++222///333EEE---//////;;;;;;;;;555CCC000///111666555111???>>>BBB:::???<<<===DDD222777:::999666333333777111===---+++,,,+++******//////111666666666FFF111;;;BBB000...///111(((***(((...***&&&***,,,999,,,000...CCCFFF333777555<<<000<<<555;;;FFF333666777@@@333555666444000888555444444+++***///+++------<<<888888<<>>***%%%'''(((((($$$&&&###"""'''---&&&###CCC###444222(((...###$$$%%% ***%%% '''%%%"""+++%%%%%%'''%%%$$$***111999***+++%%%'''+++'''######111...666???mmmI1```WWW000000<<<222666444666<<<333...+++))))))111;;;++++++333,,,222111222///---///+++)))***000000111@@@CCC<<<444888777444222666222666555<<<===444XXX888444999333000222555222...+++***222...---***(((---...---,,,---,,,---///+++***(((333666444---SSSAAA777......((()))(((***$$$,,,))),,,777FFF===333222AAA999333777EEEWWWPPP777555CCC888222>>><<<333222\\\===333222...+++((('''000111<<<777YYY777777888::::::;;;;;;>>>888666333888::::::DDD888888666QQQBBB666===NNN222:::@@@fff&hhhVVVKKK333222000888;;;777///...000+++$$$(((SSSSSS>>>AAA%%%(((&&&%%%&&&$$$"""'''###!!! 000***)))%%%***"""(((&&&+++......&&&###444###!!! !!!$$$$$$***(((000,,,===%%%###((()))$$$$$$###""" %%%'''"""$$$&&&### """%%%&&&'''((((((999ZZZ...)))&&&'''''''''===+++HHHWWW===:::QQQ___WWWJJJ999222000111......===BBB@@@999777,,,...000BBB222******---&&&***777222000111000666222111111333333222888999444:::<<<:::555111666999777666KKKIII777...222000+++,,,000///---+++------]]]111///...111000******111DDD///+++(((***111$$$$$$111===@@@999,,,,,,888888***,,,%%%...&&&+++OOOEEE888>>>HHH***%%%333000111333222999FFFAAA:::333999333///222333333AAA222---000---///%%%---------444===999:::EEE999999:::666::::::999555,,,444::::::>>>999555333444///...000EEE888888IIIfff&wwwwwwSSS<<<444000222333...111%%%,,,***&&&((((((###)))&&&***%%%&&&(((&&&&&&'''$$$''''''###'''&&&&&&"""'''$$$+++"""%%%+++222***666)))...""""""""",,,...$$$'''...(((!!!%%%"""((( #########'''### %%%%%% $$$!!!###"""((('''(((&&&$$$)))'''///888,,,******&&&***+++333LLL888<<<666jjjTTT===???444333......000+++///444???CCC[[[NNNEEE222555111...888++++++***%%%///333000333---///333...---555;;;888666999SSS;;;:::666777777888888:::666999>>>333---///000...,,,NNN---//////---111555///111555111444...000000111.........(((''''''&&&***444YYYQQQ333222&&&''')))***###***&&&&&&(((,,,333;;;444!!!!!!&&&+++555777???888:::BBB777///)))444000000...111666***'''+++EEE+++###%%%)))>>><<>>%%%***)))...111)))$$$999888333000222333444;;;777777<<>>===444555:::444<<<;;;444222111666555333...,,,,,,333666777888777666/////////222222666222333555000......---000...,,,)))&&&%%%111555@@@:::<<>>///333111888000((($$$&&&%%%***333$$$%%%999444CCCIII<<<@@@EEE===:::999444666111333888555666666333888>>>888???;;;888,,,%%%$$$333```~~~$jjjYYYBBBCCCCCC666---555000999...&&&###&&&&&&!!!'''((('''+++((("""%%%(((###!!!%%%(((%%%(((!!!"""%%%)))***)))+++333III***'''&&&!!!!!!'''***&&&###!!!!!!$$$&&&(((777'''(((&&&&&&%%%999$$$--- ###333(((111&&&+++***'''###!!!&&&(((%%%)))(((+++,,,***'''%%%444;;;***666333CCCKKK///AAA///CCC;;;AAAHHHBBB<<<000...333444000111((()))))),,,'''555+++***000000333444:::;;;UUUAAA888999666666999SSS888666444666999:::555;;;<<<===<<<>>>999111***333999888333333333555222555111000------333222000...111111...---...222...)))///000...666===444666222//////)))++++++666JJJ222555777888@@@HHH999777---222:::444111444222444>>>YYY111***---KKK999III/// """---000+++///BBB'''...WWW<<<>>>:::;;;888555999888<<<555///444777:::777666999CCC\\\AAAXXX///"""###!!!%%%\\\tttgggNNNAAA888BBB333...///---///'''333&&&'''&&&---$$$%%%+++((()))"""+++&&&(((((((((###"""###"""!!!%%%)))111---333]]]===&&&###$$$$$$%%%######"""444)))""""""###!!!)))''')))999888III---'''***'''---!!!$$$### GGG$$$!!!%%%***111%%%###"""111((()))777...&&&(((((("""%%%***$$$'''222CCCVVV:::333777555UUUGGG???]]]777555;;;333444777111222222000,,,222111666333333999===;;;<<>>KKK>>>WWWAAA111111///---222---,,,......,,,+++777111111%%%000888===111444555777111000888555444+++111000OOO666,,,###!!!(((,,,///...(((+++&&&)))CCC@@@:::999999===777777777555555555888777888;;;>>>???BBB@@@;;;---'''OOO111!!!999KKKSSSUUUSSSJJJGGGJJJ222<<<000***///333222---)))%%%***###***222$$$###)))'''000''')))***(((&&&&&&""" $$$%%%***$$$'''&&&%%%***///%%%333---111---%%%'''---!!!"""!!!!!!$$$###%%%'''---+++%%%111OOODDD%%%!!!((((((###!!!&&&!!!((($$$+++%%%%%%...111+++%%%###!!!!!!!!!'''+++444...+++'''***$$$ %%%%%%)))888HHHJJJLLL\\\999888;;;;;;FFF>>>RRR999444===AAA000---000111000:::333222333<<<===>>>;;;;;;CCCAAACCCFFF===DDDBBBCCC999666===:::888777<<<>>>BBBBBBPPPHHH???DDD<<<===CCC:::222555999CCC999333777666111333000...000+++)))...***+++,,,...000000111111555444BBBCCCFFF444FFF///......444;;;***...///------)))///222***666???'''+++444777---FFF///444333---...000444222:::666'''$$$&&&+++000---......***''':::;;;333666888333DDD777444777===444<<<:::999===@@@???DDD999222+++'''222PPPIII333TTT666AAAVVVPPPHHH]]]===777///---...***===000111---&&&)))---)))HHH((((((,,,***++++++&&&###(((+++,,,&&&)))%%%$$$&&&&&&'''&&&$$$$$$---QQQxxx777+++)))$$$&&&"""!!!&&&!!!)))'''&&&)))...)))%%%)))+++;;;888 """%%%'''###111 """&&&GGG???000......+++777$$$'''%%%!!!"""""")))+++...///&&&"""---'''&&&(((......---999CCC???:::======EEE666111444:::333999EEE999,,,,,,222999222;;;999000:::?????????<<<@@@CCCDDDEEE:::@@@MMM>>>CCC;;;;;;===<<>>@@@AAALLLIIIGGGRRRLLL===999;;;@@@EEE777III???:::AAA;;;444000111...+++...******+++//////111111...111///+++222000OOOOOOHHHAAA222222:::???;;;===111---***---///FFF---$$$%%%///---)))---555EEE444+++)))***>>>---222555000222222...===222......000+++000000&&&)))111666999777222666222888===555888777AAA999@@@<<<<<<@@@222%%%,,,111$$$555666:::XXXBBB???NNNfffJJJMMM@@@777222666777***111///+++KKK((((((000***)))'''((('''+++)))'''''''''000((('''(((222333---%%%&&&&&&%%%$$$%%%DDD|||+++''',,,&&&### %%% ###000&&&111111???000@@@***000((((((!!!!!!!!!"""'''"""###''''''999FFF:::111333+++(((######(((&&&%%%...(((---,,,...+++%%%******,,,---(((---///000111777888HHHPPPQQQ999BBB<<<888555222444...222222666999;;;III333666BBB:::```ddd???<<>>))),,,'''444'''&&&(((444000111///---222:::333444555666555555<<<***(((===555777555333777>>>333888000AAA<<>>:::::::::999222666)))***"""&&&,,,===@@@RRRSSSRRRTTT===:::000333555111&&&...000---222+++***((((((+++(((///(((***"""''''''###%%%,,,***&&&***NNNhhh)))***)))!!!'''(((,,,@@@)))%%%###### !!! ---...%%%###KKKEEE&&&%%%%%%)))###%%%###"""%%%%%%%%%!!!"""$$$&&&===@@@:::...000LLL&&&!!!%%%$$$%%%"""&&&'''$$$%%%555""""""000###((())),,,...111555111666333===;;;DDD:::999888<<>><<<<<<999;;;CCC>>>AAAEEEBBBEEE@@@>>>HHHGGGNNNKKKPPPIIIMMMAAADDDIII>>>aaaSSS@@@LLLHHHNNNSSSJJJMMMDDDOOOJJJMMMGGGPPPHHHOOOPPP@@@555777;;;>>>===444<<<777999555777888111111111111111222222000))),,,&&&)))222===555555...---333888555888...222111111111BBB\\\888333111...333555///111,,,,,,444,,,///---000111+++///444000555000444===RRRGGG888,,,)))222///666000444777999;;;444222333===>>>>>>888888:::777666111...)))"""''',,,+++999GGGLLLQQQLLLFFF999;;;111222333+++,,,444///...'''+++%%%(((((($$$***+++###&&&%%%###%%%&&&$$$%%%$$$...---///000,,,'''((((((,,,***$$$%%%###!!! 333"""&&&000444888&&&...***...***$$$!!!!!!###&&&###%%%"""'''(((AAAJJJ,,,,,,***)))%%%((((((+++===)))'''((($$$%%%###,,,!!!###(((,,,555888888RRR999```AAANNNAAA555???===777???888888:::<<>>999???CCC:::888CCC===>>>CCCEEEJJJJJJCCCHHHUUUGGG???PPPJJJhhhaaaJJJHHHPPPIIIPPPJJJKKKNNNNNNJJJRRRMMM>>>CCCFFF@@@@@@IIICCC@@@:::<<>>EEE444222555)))222000AAA+++777***:::///000===555CCCJJJ666QQQddd888555<<<666;;;DDDDDD...+++333777...444777///333666333<<<777444:::@@@<<<777999;;;:::///+++222'''""")))...+++WWWIII===KKKTTTDDD;;;333888444111555---111&&&+++444***&&&&&&%%%,,,(((%%%%%%"""###$$$###%%%&&&)))>>>,,,|||>>>###!!!&&&///555&&&%%%%%%### $$$!!! $$$+++===&&&%%%###"""###$$$...)))%%%&&&&&&%%%&&&$$$$$$$$$######'''???LLL+++;;;***///,,,111'''%%%...,,,'''&&&%%%&&&###!!!'''###---+++333:::666777@@@CCCWWWNNNGGG===999@@@BBB<<>>:::>>>ZZZ@@@>>>JJJ777888333??????AAAAAACCCBBBHHHHHHHHHMMMAAANNN -^^^BBB>>>@@@OOOJJJMMMHHHQQQNNNGGGJJJ___@@@@@@GGGBBB999999MMM999333222;;;LLLIIIEEE???>>>;;;;;;:::666777999BBB999444333???@@@:::000333...---777;;;999999888888777555999333///333777:::<<>>999666666000111444:::KKKBBBLLL<<>>======555777000***...///"""***,,,))),,,999<<>>:::333666<<<<<>>FFFBBB>>>@@@===666333<<<<<>>;;;>>>===dddQQQiiiFFFOOO???EEEGGGGGGJJJFFFGGGIIIJJJUUUSSSNNNQQQQQQPPPPPPIIIMMMAAA;;;222777EEE@@@JJJ777???MMMOOORRRUUUDDDYYYFFF===FFF;;;<<<;;;666:::===<<<@@@FFF888666444888666999999999999===<<<===888999;;;:::===???JJJ<<<;;;666777<<<>>>111111---000,,,,,,(((444888///666888111///777BBBAAA===888<<>>777666555888...,,,111///......777&&&%%%(((333'''''''''###### """ %%%$$$%%%111:::RRR,,,'''***!!!$$$######000"""%%% )))(((!!!"""&&&&&&!!!AAA---(((###!!!,,,;;;***)))$$$&&&%%%""" '''???%%%###!!!)))222///***...XXX000+++)))...&&&######'''***&&&!!!222;;;BBBeee333444<<>>;;;>>>SSSJJJEEEJJJWWWCCCHHHEEEKKKKKKIIIDDDNNNRRRQQQRRROOOfffVVVRRRFFFIIIJJJMMMDDD333111???PPPddd>>><<>>KKKJJJQQQEEE===<<<888FFFBBB@@@777===>>>;;;>>>>>>999===<<>>888777222666555888GGGCCC888666>>>???;;;::::::999333444111""")))222777...///222111@@@III666DDD999+++(((...444111,,,;;;""" !!!%%%$$$&&&(((!!!###"""&&&111###%%%###///444000***333&&&***&&&###!!!###'''  %%%###---###&&&$$$$$$777((($$$)))...888$$$%%%$$$$$$%%%######!!!!!! ###!!!$$$***...444,,,...000---...(((***)))(((555(((%%%,,,777999DDD@@@===<<<888EEELLL]]]YYYEEEGGG>>>333888666999777<<<888>>>===???YYYLLLBBBAAACCCNNNnnnyyy???===999???BBBEEEFFFLLLVVVmmmbbbLLLOOOaaaOOOJJJeee______XXXZZZNNNKKKLLLHHHMMMRRRHHHDDDOOOWWWMMMZZZUUUQQQOOONNNZZZ```QQQ[[[VVVJJJZZZSSSKKKIIICCCAAA:::BBBCCC@@@NNN???;;;BBB777;;;GGG???>>>>>>DDD???EEEFFFEEECCCAAA:::DDD333444SSSBBB111555===DDD999///000444333333333333555111222444333000111000444222000888666555222KKK777666666<<<>>>;;;AAA:::JJJMMM>>>444---000888<<<;;;??????777000+++000''' ,,,//////999888<<>>777999666...***++++++777///<<<***'''%%%''''''&&&!!!!!!%%%"""&&&---"""%%%'''...)))000''''''%%%%%%""" ###$$$$$$!!!!!!$$$###### (((------+++'''///&&&%%%&&&&&&(((###%%%%%%(((!!!###$$$666)))######$$$%%%)))&&&333...&&&,,,&&&(((///222666000888<<>>555:::<<<:::;;;>>>:::999NNNMMMggg@@@AAALLLCCCDDDQQQLLLMMMZZZ___dddVVVMMMJJJWWW___ZZZbbbWWW___\\\PPPNNNJJJPPPOOOYYYPPPoooKKKQQQZZZ___\\\{{{}}}RRRfffccc```WWWUUUUUU^^^QQQLLLSSSHHHAAAHHHAAA===@@@EEELLLDDDEEE666333888AAAGGG<<>>999===@@@444777:::888888:::@@@===>>>===;;;444666???***###%%%333...888KKKCCCBBBSSS===999;;;333++++++...+++...)))***---,,,###&&&$$$###(((%%%%%%!!!!!!###&&&'''$$$))))))))))))''''''"""$$$"""""" !!!!!!!!! """'''(((%%%&&&(((CCC...(((!!!***((($$$)))'''''')))***))) ###### ((('''"""$$$$$$ (((222,,,???555,,,+++555222:::AAAEEEAAAGGGFFFEEEGGGKKKaaadddBBB888>>>@@@AAA<<>>888999BBB<<<:::;;;;;;>>>;;;???111///!!!&&&000???666,,,111:::555888;;;333---...111777333444555...555222444000---///***222888PPP???555AAA>>>===---000333666888:::;;;FFF>>>@@@FFFqqq:::555DDD555!!!)))333;;;KKKFFFEEE===;;;444---$$$)))***------///NNN------###%%%%%%&&&$$$%%%###&&&%%%***'''"""&&&AAA&&&,,,---)))---!!!***(((""""""###,,,###%%%!!!"""(((555###&&&///,,,,,,%%%&&&,,,$$$,,,$$$'''000'''%%%%%%###!!!"""$$$!!!$$$%%%'''&&&"""&&&$$$(((---888777...333///222---555999QQQLLL>>>999;;;<<<>>>LLLsssaaa===<<>>999666333000:::999<<<222000222333555333888444:::777>>>222000222---???444FFFCCC444---(((000++++++333444777;;;===;;;<<>>HHHCCCFFFTTTmmmLLLDDD\\\AAACCCFFFMMMZZZHHHIIIJJJQQQJJJaaaD>|||yyywwwttt ZZZTTT^^^dddmmmccc```PPP___gggfff(qqqTTTVVVVVVMMMIIIjjjrrrvvv```JJJaaaiiiyyy{{{___WWWUUUVVV```]]][[[RRRMMMLLLLLLLLLWWWKKKKKKLLLXXXNNNJJJGGGCCCBBBCCCDDD888999EEE444(((###&&&000777888===555777999000???KKKAAA:::666222,,,888888<<<;;;:::666777;;;222333444999777:::444444777999@@@666888<<<:::333---333888%%%///222555888666???<<>>>>>\\\JJJJJJRRRCCCBBBKKKJJJKKKFFFGGGEEEMMMVVVkkk%ooovvvhhhpppIddduuunnnllliiiOOONNNaaaOOOSSSUUUhhh[[[dddrrrddd___UUU@@@DDD\\\dddjjjXXXXXXUUUoookkkeeeuuuhhhggg}}}aaa]]]UUUUUUTTT^^^QQQLLLLLLOOOQQQRRRPPPSSSQQQLLLFFFAAACCC@@@:::BBB<<<)))""" 222<<>>555&&&"""222***888???YYYFFF:::888999666555...888999::::::888***###***222<<>>FFFHHHAAA<<>>IIIVVVOOOjjjhhhqqqtttccccccnnneeebbb -rrr___```YYYUUUQQQZZZYYYTTTTTTHHHRRRZZZWWW]]][[[KKKQQQUUUaaa___ggg|||xxxrrr^^^SSS___ZZZlllpppeeennnddd```___ooocccNNNUUU```ggg___kkkWWWQQQPPPOOOKKKGGGDDDCCCDDDGGGCCCAAA,,,+++///666:::BBBAAAEEE===DDDHHHMMMAAA666777'''999SSS'''444QQQ SSSAAA<<<>>>>>>888555AAA<<<<<<<<<555---)))$$$333GGG@@@DDD999???222,,,666222,,,---333555888======GGG@@@BBB>>>:::))) (((***AAA555;;;???AAAAAA===///666666222333---///111******'''((("""''''''(((&&&"""&&&$$$$$$+++"""(((&&&&&& &&&""""""$$$'''***'''&&&"""$$$$$$***000&&&777&&&888OOO%%%"""###''')))###%%%###''''''%%%...###)))$$$'''...222//////(((###'''444222KKKOOO333+++000000000///222777666777:::777333666666999777???888DDD]]]GGG999@@@777???>>>@@@BBB777FFFFFF>>><<>>GGG===???777:::(((''')))000999AAA>>>999;;;999333555777@@@;;;444///444***)))(((///)))&&&"""&&&$$$###$$$))))))%%%$$$'''$$$---"""!!!######!!!$$$!!! !!!###""" %%%///###'''DDD[[[%%%###'''---666///;;;555;;;))))))///***&&&&&&(((%%%&&&$$$111...+++000...+++'''&&&+++222000,,,+++444)))111222888777>>>:::555GGG666333444<<<;;;AAAMMMCCCBBB???===CCC:::///444888111DDDTTT___===>>>@@@EEELLLFFFDDDFFFFFFDDDIIIaaaYYYYYYXXXYYYYYYbbbeeeaaa\\\PPPHHHTTTLLLQQQMMMLLLSSSQQQSSSGGG[[[]]]ooo\\\^^^llliii[[[WWW___iiicccXXXSSS[[[ccc[[[VVV```fff^^^mmmZZZ]]]pppmmmSSSNNNGGGHHHRRRPPPSSSQQQPPPOOOIIISSSFFFOOOSSSOOOVVVLLL??????999:::===AAALLLMMMLLLKKK[[[FFF:::AAACCCccc999///777CCCEEEBBB???:::333<<>>000111***HHHCCC)))111DDDBBB:::???AAA777111555777444999777BBB>>>===>>>AAAHHHCCC???999fff$$$///---333777EEEBBB999444444666@@@888666666@@@000///000///111'''$$$)))'''"""$$$'''&&&'''((((((''')))---(((###333!!!"""!!!###%%%***)))!!!''',,, $$$****** (((&&&888<<<===DDDxxxrrrUUU000,,,///)))%%%>>>CCCFFF%%%,,,???...+++000%%%+++===&&&---555+++222111111:::999\\\JJJ888444888222<<>>===??????EEEFFFPPPAAA@@@LLLSSSdddWWWSSSWWWUUU^^^aaa\\\WWWKKKOOO]]]WWWTTTSSSPPPMMMOOOTTTDDDVVV\\\VVVRRRWWW___qqq```JJJ[[[\\\bbbkkk^^^]]]bbb___^^^SSS^^^\\\VVVXXXOOO\\\aaa[[[[[[QQQJJJOOONNNTTTPPPNNNTTTNNNQQQNNNTTTTTTTTTXXXKKKMMMFFFBBB???BBBEEEJJJMMM___NNNJJJMMMdddBBB@@@???>>>::::::@@@DDD======555,,,666<<<777EEECCC===(((000KKK((($$$333:::JJJNNN???LLLHHH///...555777666999:::>>>;;;>>>>>>BBB???777999,,, ///777@@@EEE999888555999444:::888;;;999III777,,,000%%%%%%'''%%% """###(((,,,***...&&&(((...)))$$$$$$$$$""" """ """###%%%888***&&&333'''%%%%%%''')))""""""444MMM999///===oooMMM---((($$$ &&&111222ZZZ(((...222---+++555111999'''666///...LLL,,,...111AAA:::KKKQQQMMM888===EEEDDDGGGMMM???LLL666BBB@@@;;;777444222000111111***...&&&"""@@@BBBFFFQQQQQQGGGPPPFFFpppYYYHHHRRRHHHKKKPPPaaaZZZcccbbbfffSSSWWWOOOMMMWWW]]]___]]]UUUJJJMMMVVVLLLLLLLLLUUUXXXPPPPPP```[[[UUUNNN[[[dddfff___aaahhhfff```RRRYYYWWW]]]``````PPPfff]]]YYY[[[WWWPPPSSSPPPNNNFFFMMM[[[HHHLLLOOO[[[OOOWWWUUU___QQQJJJQQQGGGIIIGGGPPPSSS^^^rrrJJJNNNRRRLLLKKK>>>>>>>>>???CCCBBB???AAA<<<666333:::999???LLLBBB???>>>,,,***---000888rrr6===PPPyyy@@@333444///444:::777@@@@@@AAAAAA@@@BBB777444### """###000777<<<;;;333666666333<<<;;;333777999ccc===333(((###$$$###%%%&&&$$$%%%)))&&&$$$***666***+++'''%%%$$$%%%"""$$$$$$ ###&&&###%%%555!!! $$$$$$222''')))%%%###OOO;;;222HHH@@@---'''***+++)))%%%%%%''''''???...111111444888+++222111666333***+++,,,>>>222PPP555111444888JJJQQQ??????>>>???OOOOOOWWWJJJCCC???===888777444555666111AAA:::...666444:::111333FFFYYYLLL```kkkYYYRRROOOQQQRRROOOLLLOOOOOORRRXXXeeeVVVUUUVVVXXXZZZFFFPPP[[[mmm}}}HHHFFFDDDLLLLLLWWWIIILLLTTTRRRVVVVVV[[[ZZZZZZ^^^eeeiii|||mmmeee```___[[[```fffYYY^^^bbb]]]\\\XXX[[[WWWPPPSSSOOOKKKKKKJJJIIIKKKLLLMMMHHHHHHMMM___WWWLLLMMMJJJGGGJJJKKKMMMIIIOOOYYYUUUIIIMMMKKKOOOMMM[[[NNN;;;@@@BBBDDDBBBAAACCC666888666<<<;;;@@@???555BBB444///***///999LLLnnn>>>AAACCC@@@:::444555666999:::;;;999???EEE???DDD;;;666999%%% 000333666333999AAA888999===KKK888888:::;;;666---)))'''(((%%%"""$$$111$$$%%%!!!+++(((111'''&&&'''"""###'''$$$%%%!!!!!!$$$))) !!! !!!&&&$$$&&&JJJ---(((!!!'''GGG:::000)))222---%%%%%%$$$###(((000@@@...000))))))000///111111///000777222---///...999EEECCC555666NNNLLLIIICCC===777888LLLYYYTTTDDD@@@BBB:::999888000555AAAQQQ888CCC666...444888<<>>===444111777111222111:::444BBB<<>>>>>@@@666000;;;<<<888:::<<<===AAA;;;<<<777CCC888--- (((...666:::<<<888888888999AAA???<<<999555999444999111---'''&&&%%%)))$$$...(((...(((;;;'''$$$!!!!!!%%%!!!""" %%%$$$ ###$$$&&&###$$$###""" %%%&&&&&&$$$%%%)))###......111111---***++++++((((((///111444+++111333,,,222...***)))+++)))------888AAAIII>>>:::BBBAAA;;;:::@@@777999888999666333:::<<>>FFFEEEQQQIIIAAADDDGGGHHHAAAFFFTTTXXXPPPfffTTTRRRHHHAAAHHHKKKDDD\\\TTTaaa]]]PPPRRROOOPPPMMMHHHEEEIIIGGGFFFJJJJJJ111BBBEEECCCFFF\\\[[[VVVZZZUUUUUUSSSUUUVVVnnnYYYeeetttuuufff___ZZZ\\\]]]lllZZZ]]]eeeccckkkjjjZZZTTTNNNSSSVVVTTTRRRMMMDDDEEEBBB@@@AAABBBEEEFFFGGGJJJHHHGGGOOOKKKNNNUUUOOOPPPPPPKKKGGGGGGNNNKKKIII@@@HHH===<<>>>>><<>>...+++222333(((,,,---888,,,))))))((()))+++000555777>>>BBB;;;;;;333777;;;===666777777;;;;;;<<<777AAA@@@===777333333000333444888444>>><<>>EEEMMMKKKNNNEEEaaaHHHEEEFFFRRR@@@AAAGGGAAAAAABBB;;;777???RRROOOHHH^^^^^^XXXXXXXXXNNNRRRUUUVVV[[[___\\\```___^^^^^^ZZZYYY]]]XXXaaa```hhhjjjeeexxxuuulll^^^___]]]\\\UUUSSSJJJLLLHHHDDDDDDFFFCCCHHHHHHPPPPPPPPPMMMHHHKKKPPPVVVOOOLLLSSSKKKTTTRRRNNNKKKHHH???LLLCCC??????===<<<>>>555<<<<<<;;;:::>>>DDDDDDAAA<<<:::444777111---222555AAA>>>:::...(((***555===JJJ<<>>555DDD;;;888777555999:::555666333000((($$$$$$%%%)))---(((&&&)))&&&&&&$$$,,,,,,"""!!!"""+++""" !!!%%%CCC%%% """''''''"""$$$'''+++ """((("""###'''$$$222(((------...***)))---***+++$$$HHH...111)))...***+++555444999555777888:::GGG666999EEE999666777<<>>IIIKKKVVVRRRNNNBBB???BBBBBBGGGUUUwww```WWWXXXVVVDDDHHH???NNNRRRNNNYYYLLL<<>>DDD:::333777444<<>>444+++///777999GGG222222333+++...666<<>>???@@@:::>>>666444111---111000666<<<>>>OOO:::;;;888777777222444333333,,,+++)))""")))((($$$###...,,,"""%%%$$$###$$$'''***(((!!!$$$!!!###,,, """!!!%%%'''---&&&$$$$$$ !!!""")))///''';;;"""!!!)))(((OOO'''***+++---***///((()));;;'''***111+++'''+++222555333???888???;;;OOOSSSUUUGGGIII???JJJAAA<<<999@@@>>>@@@===>>>999===888000999555111222>>>EEEBBBXXXTTTAAAPPPLLL\\\JJJ???@@@BBBFFF[[[pppZZZRRRKKKYYY[[[PPPLLLWWWQQQRRR[[[RRRAAAIIIBBB222...000333///777EEE===333444;;;CCCMMM___]]]WWWVVVZZZ```[[[VVV[[[\\\QQQWWWWWW^^^jjjpppmmmgggjjjWWWWWWYYY\\\___dddaaaffflllpppuuuhhhdddfffWWW\\\```[[[XXXQQQNNNFFFHHHJJJHHHIIILLLOOOKKKFFFJJJNNNQQQUUUUUUQQQQQQZZZMMMLLLIIIJJJCCCHHHFFFCCCBBBGGG@@@???555777777222999;;;===:::<<<@@@AAAIIIRRR000+++,,,;;;666333...---***)))111222HHH>>>???@@@??????BBB<<<444777%%%)))!!!,,,666888:::444777888888:::777000,,,444444((($$$&&&,,,%%%)))((()))$$$&&&%%%&&&$$$&&&---+++$$$...333&&&###""" """%%%###"""''',,,&&&$$$######&&&&&&000&&&&&&&&&''')))***)))GGG+++,,,...???---000%%%$$$)))+++((((((///000///888999555BBBMMMTTToooxxxfffGGG:::>>>???BBBKKK>>>@@@CCC;;;===777<<<<<<888///111111666===DDDAAATTTMMMQQQRRRFFFTTTcccQQQJJJGGGJJJJJJKKKYYYQQQKKKAAALLL\\\dddZZZWWWmmm^^^OOOBBBGGGGGG;;;000***,,,+++222777777555999BBBCCCHHHIIISSSTTT[[[VVVZZZ```ccc\\\UUUYYYVVVRRR[[[___bbblllfffeeeaaaccc```VVVSSSRRRUUU\\\ggg```]]]ooogggjjjaaadddiiijjjiiihhhfff^^^SSSSSSOOOTTTQQQLLLJJJNNNRRRJJJKKKNNNNNNOOOTTTVVVRRROOOOOOMMMOOOMMMJJJNNNKKKJJJGGGJJJGGGDDD999999;;;999@@@CCC>>>BBBAAABBBDDD???CCC>>>///***111666000...,,,###!!!111555???CCC@@@@@@CCCCCC???;;;666...&&&!!!###111,,,---:::999666AAAOOO:::;;;333666111000888&&&&&&$$$+++((()))$$$!!!$$$((($$$!!!%%%$$$&&&$$$ $$$&&&###!!!!!!###***...---***///AAA!!!###&&&"""111'''???444###'''***+++---***111+++222+++888...)))"""$$$'''(((******///777HHH888666666;;;;;;kkkoooMMM___GGGAAA<<>>GGGLLLUUUbbbmmmrrr~~~LLLFFFFFFRRRCCC555///,,,444666444999:::CCCNNNJJJMMMKKKYYYPPPPPPTTTeeefffdddooo]]]\\\eeeggg```hhhqqqoooooogggiiicccccc```[[[TTTVVVbbbnnnrrrpppeeejjjlllcccdddjjjlllooowwwwwwkkk```[[[aaaYYYVVVPPPQQQOOORRRQQQLLLMMMOOOMMMUUUXXXRRRQQQRRRQQQKKKKKKMMMLLLOOOKKKJJJRRRQQQGGG888---999IIIIIIGGGGGGCCCGGG???DDDGGG???>>>888---...555555)))''' ((('''555;;;<<<;;;;;;AAAFFFGGG333222000333---111===///+++000777777666EEE===;;;444222...+++)))))))))$$$&&&)))&&&+++""" $$$!!! """### &&&###$$$"""&&&!!!'''%%%%%%&&&,,,))))))%%%"""***###!!!&&&000&&&###***++++++)))$$$+++222GGG'''%%%+++$$$%%%###!!!,,,///+++<<>>HHHFFFAAA===777222???LLL>>>;;;AAABBBGGGTTTWWWLLLSSSVVV[[[[[[QQQTTTdddrrrdddrrrZZZdddwww]]]aaafffooojjjeeeaaaddd______XXXXXXXXXhhh9 qqqkkkccceeeeeeaaaeeelllmmmiiihhhllliiilllqqqaaa[[[NNNUUUQQQWWWQQQNNNQQQRRROOOKKKRRRVVVZZZiiiQQQMMMLLLRRRNNNVVVNNNLLLFFF<<<000///:::JJJDDDHHHFFF???FFFIIIAAA@@@BBB>>>===999222888222((("""'''000888;;;<<<===DDDQQQAAA>>>;;;666>>>EEE222111;;;555$$$FFF555555:::777666555:::111***''')))***(((...(((...&&&$$$!!! &&&"""!!!###'''(((>>>333""""""&&&)))######"""$$$---222---&&&(((&&&III###'''***###...(((((()))888)))+++,,,...***%%%###  ,,,333......///444444999:::???EEEBBBJJJJJJLLLfff]]]KKKQQQ>>><<>>===+++333777ccccccWWWOOOLLLJJJBBB===???BBB@@@999CCCFFFEEENNNSSSPPPNNNVVVPPPQQQSSSTTTRRRPPPXXXXXX{{{~~~uuuhhh^^^bbb]]]]]]aaaggggggeee[[[VVVYYY\\\___nnnqqq}}}Bnnneeefff```^^^___eeejjjpppkkkqqqhhhgggkkkppptttdddXXXRRRQQQWWWTTTMMMNNNYYYTTTQQQUUUZZZ```WWWbbbNNNOOOHHHQQQVVVRRROOOHHHGGG777---666AAADDDDDD>>>???AAAHHHFFFBBB@@@777777999999:::<<<---!!!)))...999>>>>>>>>>===???@@@999999777<<>>???<<>>@@@DDDCCCEEEKKKKKKQQQSSSPPPRRRRRR]]]UUUNNNRRRUUU]]]```cccrrr lllccc___ZZZ^^^___]]]XXXQQQNNNVVVSSSWWWlllrrrmmmhhhxxxtttooo}}}ooonnnddddddgggnnnpppyyyxxxwwwnnngggfffsssoooTTTRRRPPPPPPPPPNNNYYYOOONNNSSSZZZaaabbbZZZfff\\\RRRQQQRRR\\\VVV^^^LLLBBB666999???@@@DDD>>>GGGCCCGGGJJJEEEDDD<<<;;;??????AAAFFF444:::%%%)))---<<>>===MMM===BBBNNN}}}cccNNNHHHMMM===BBBAAAQQQ===<<<444777:::666333>>>888666===III===DDDAAA@@@CCC@@@@@@SSSLLLBBB;;;AAAAAA^^^ZZZCCCKKKEEENNNBBBHHHHHH@@@>>>GGGIIIGGGFFFSSSJJJKKKDDD@@@>>>BBBCCCSSSMMMEEENNNMMM]]]VVVOOOTTTaaaaaaffflll\\\bbbgggbbbtttxxxfffXXXmmm{{{ooocccKKKDDDIIIGGGJJJSSS\\\fffaaahhh\\\UUUVVV\\\ooojjjxxxzzzrrrjjjVVVfffqqq|||xxxsssaaagggtttvvveee___YYYfffQQQKKKMMM^^^MMMQQQMMMTTTYYY___```xxxssshhh]]]___YYYMMMFFF>>>MMM===888???<<>>888&&&+++888GGG===??????;;;>>>@@@555---,,,777>>>;;;777888>>>???JJJ===AAA;;;BBBBBB999:::888---333...666555'''"""%%%'''+++)))+++***$$$)))///,,,,,,'''+++)))%%%&&&+++)))+++%%%,,,)))(((&&&+++((($$$000111***+++---,,,)))---)))000(((...------&&&'''++++++---222)))222AAA999999333KKKFFFNNNlllXXXBBBPPPHHHKKKPPPGGGCCCOOOEEEAAAOOOBBBNNN999666777>>>555444>>>???<<<333666HHHUUUIIIEEEDDD@@@NNNEEEYYY888<<<@@@FFF___\\\UUUGGG\\\aaaWWWQQQEEEJJJ^^^SSSDDDCCCDDDCCCFFF<<<999777FFFJJJSSSJJJEEEDDDLLLPPPVVVWWWPPPWWWccc\\\]]]```fff______jjjhhhmmmuuu||| www]]]@@@;;;CCCVVVdddeeehhhqqqxxxtttaaa[[[```\\\fffkkkssspppoooeeejjjmmmqqqnnnrrrffflll~~~~~~hhhddd___aaaYYYSSSFFFddd```dddPPPRRRPPPYYY^^^uuussszzztttYYY]]]XXXLLLGGGEEEEEE:::>>>LLLBBBJJJIIIMMMJJJFFFFFFGGGBBBCCC777:::BBB000000(((444>>>777222888:::???<<<>>>===555000+++999AAA999CCCKKKNNNIIINNNNNN===;;;IIILLL:::???CCCBBB:::888333///)))&&&((())))))%%%'''%%%$$$'''...---&&&)))(((+++FFF>>>DDD******)))(((,,,'''%%%(((&&&999JJJ(((+++&&&(((''',,,333111&&&,,,'''''''''###'''&&&+++//////666PPP777???===```IIIVVVaaaHHHKKKDDD???BBBHHHCCC;;;888>>>@@@KKKFFFGGG999777KKK@@@444>>>:::888666:::===???CCCCCCAAAFFFIIIHHHTTTAAACCCFFFTTTYYYgggPPPUUULLLIII^^^TTTCCCGGGGGGOOOSSS===888555777:::DDD;;;GGGMMMLLLBBBIIIOOOJJJTTTVVVRRRNNNLLLppptttgggWWWhhhTTTOOOTTTSSSSSSXXXaaajjjbbb^^^ZZZLLLNNNYYYdddeee~~~zzz- ppp```YYY^^^eeejjjuuuxxxqqqwwwuuuzzzyyypppxxx -vvv{{{kkkccc\\\WWWUUUTTTkkkzzz|||TTTLLLQQQVVVQQQaaarrrxxx\\\bbb```VVVLLLGGGAAAEEE@@@999AAAWWWHHHDDDGGGFFFHHHFFFEEEBBB666333777111999;;;sssNNN888666???===BBB===<<<@@@BBB---&&&(((---@@@GGGBBB444RRRMMMJJJAAA===555222666999???BBB===<<<666FFF???444///<<<222)))'''$$$###+++%%%&&&---...111///...///PPP555)))&&&...+++,,,+++***###%%%))),,,***$$$(((''''''333:::222***$$$"""!!!'''$$$'''(((,,,@@@///111999777666CCCFFFTTT pppTTTIIINNN@@@EEEAAA:::666444777888PPPIIIDDD>>>GGGAAAMMMKKKFFF<<<<<<<<>>@@@:::===@@@BBBDDDNNNFFFKKKSSSRRRKKKPPPsssXXX^^^XXXcccTTTVVVGGGNNNVVVaaa\\\cccbbb]]]\\\^^^iiicccpppmmm|||(uuutttcccssspppffflll|||}}}wwwqqqlllppp~~~yyysss{{{wwwqqqgggcccXXXccc___cccZZZeee```WWWUUUWWW[[[______fffaaaiiilllgggXXXPPPLLLGGGAAAHHH111666aaaNNNHHHHHHOOOLLLNNNWWWFFF666///AAA888TTTIII]]]:::>>><<<;;;@@@BBBLLL>>>>>>,,,***'''###CCCRRRRRRNNN777JJJZZZOOOJJJ???999555999<<>>999555:::((()))((($$$,,,---,,,((((((,,,(((***//////555@@@cccAAA///+++&&&###)))MMM666)))(((000%%%555))))))(((''',,,===RRR222)))%%%%%%)))%%%'''%%%'''222,,,444888@@@fff;;;aaafffOcccUUU___GGG@@@AAA???:::888666111555222VVVFFFEEEVVVooolllcccJJJ<<>>DDDEEEPPPEEE;;;BBBBBBAAAGGGBBBXXXGGGBBB777,,,+++000666<<<:::999LLL999<<>>===;;;;;;666222///+++JJJlllTTTCCCHHHGGGQQQSSSEEE>>>>>>555<<<444===IIIQQQ>>>444222//////...---+++222,,,+++,,,---&&&$$$%%%,,,444//////111000;;;333((()))''')))000SSSMMM222&&&000&&&)))(((((('''+++...;;;000,,,&&&&&&''',,,$$$"""$$$+++444555===:::AAAHHH^^^fffppp -#H|||VVVKKK???888???>>>>>>@@@222000===:::eeeYYYnnnvvvwww{{{iiiNNNRRRPPPWWW^^^WWWUUUSSSTTTOOO```^^^IIIDDDPPPZZZYYYKKKOOODDD@@@EEE@@@;;;BBB@@@777***)))---444888===999AAABBBFFFFFFFFFOOO]]]VVVRRRSSSQQQNNNWWWVVVTTT^^^SSSZZZ\\\^^^ZZZ\\\XXXaaa[[[YYY]]]kkkwwwrrrqqqgggrrruuuppprrr  ~~~) eeevvvwwwvvvsssooobbb```lllhhhmmmhhhbbbhhhbbbhhhcccaaafffWWWWWW^^^fffrrrhhhdddnnn}}}pppaaaXXXNNNGGG===,,,666JJJDDDGGGMMMHHHLLLCCCAAA<<<===CCCgggjjj===888@@@AAA???AAA666555444:::888888FFFBBBCCCZZZNNNKKKIIIAAAOOOQQQLLL===>>>===999<<+$eee\\\KKKEEEGGGGGG:::;;;///333888<<>>000&&&333666999222AAAHHHIIILLLPPPJJJEEE999BBB???CCC>>>===BBB@@@???BBBBBBFFF111...333111111>>>>>>444222---))),,,---...000(((,,,222///III:::666---...555333MMM>>>333999BBB///***(((&&&###+++***---------,,,***///,,,)))###(((666(((...,,,444HHHJJJHHHzzzvvvssswww```xxx5? -lllKKKEEECCC>>><<<>>>III999000>>>???EEEvvv $&ooosssssscccrrrgggmmmwwwbbbXXXRRR[[[KKKAAAMMMMMMHHHFFFCCC<<<888666888''')))...<<>>@@@GGGGGGFFFJJJTTTRRR```^^^ZZZRRRYYYfffPPPTTT___}}}eeessskkkfffmmmllllllqqqhhhnnneeecccfffjjjpppqqqiiifffqqq{{{yyy{{{vvvppp}}}/.7   zzz~~~ xxx]]]^^^]]]dddqqqooohhhlllvvv|||hhhmmmoooaaa```eeennnmmmppphhhjjjkkkbbbdddGGG777000:::CCCBBBHHHOOOLLLCCC777+++--->>>EEEaaaCCC222444777...+++222444888===<<<>>>@@@BBBMMMFFFLLLFFF>>>111!!!,,,555888AAAAAAIII>>>CCC???666000...AAAKKK---222///000///---+++,,,...,,,,,,,,,333222111+++000888///333888000FFFPPP000&&&[[[111---+++###+++"""(((555EEE------)))111***+++"""%%%---///***///333FFFDDDHHHdddgggtttuuu SSSRRREEEDDD:::===PPP<<<;;;888AAA<<>>FFFBBBRRRFFFGGGOOOIII@@@???>>>...>>>AAAeeeHHH???888,,,444333:::666888888<<>>DDD>>>===GGGPPPGGGUUU) $&$"'~~~nnn\\\\\\XXXMMMGGGIIIHHHIIIDDDGGGDDDGGGPPPaaa}}}...KKK666>>><<>>EEEBBBFFF???===...555222FFFuuu===777888<<<444///555444<<<@@@FFFWWWLLLLLLHHHFFFQQQ<<<<<>>FFFPPPVVVaaa|||+119FC641qqqfffgggdddYYYQQQIIIDDDHHHGGGEEEAAAHHHDDDBBBjjjXXX---444444999;;;BBB<<<666CCCVVVQQQTTTYYYRRR]]]\\\dddPPPkkk|||sssxxx~~~wwweee<"$!/   -||||||~~~{{{qqqsss nnnoooxxx}}}~~~xxxyyyooovvvkkkccciiikkkuuuuuuxxxyyy -vvvrrrlll llldddkkkeee]]]dddkkk\\\IIIFFF???<<<<<<@@@JJJGGG===<<>>CCC000)))+++)))+++???555...)))333,,,((((((---&&&222GGGCCCDDD666///(((111111555888777+++111TTT333222222---222777222666//////......+++===---333777HHHIII@@@@@@HHHsssZZZOOOJJJFFFOOODDDKKKRRRUUUOOODDDJJJBBB============@@@LLLZZZppp|||FT\dbST(vvvjjjUUUZZZPPPJJJEEEDDDIII<<<;;;CCCIIIDDDuuuNNN;;;@@@BBBDDD<<>>HHHYYYeeePPPLLLJJJJJJVVVYYYGGGMMM===>>>FFFAAA@@@===777444???222444666777777:::,,,***,,,(((FFF999...222******++++++...555CCCCCCAAACCC111$$$!!!...DDD;;;444000,,,---000666333444111...444666666///...///---,,,///111???>>>HHHRRROOOLLL``` -YYYQQQGGGHHHIIIFFFVVVPPP___WWWOOODDD>>>KKK@@@999999===DDDLLLZZZnnn{{{'PklliqU2 -zzzeeeTTTPPPOOOKKKGGGGGG@@@555999;;;GGGIII;;;EEE^^^GGGIIIGGGLLLLLLTTTMMMQQQ```YYYWWWZZZTTTVVV[[[^^^gggeeexxx}}}{{{uuupppxxxrrrqqq}}} mmm#-,#A8!|||uuuxxxeeerrrxxxppphhhiiiqqqzzzxxxnnn tttkkkqqq WWWxxxyyyvvvnnnhhhuuuooovvvxxxyyycccggghhhnnnaaa]]]cccZZZ]]]VVVXXXUUUFFFDDDFFFEEEIIILLLLLLFFF<<<@@@000###///@@@CCC999:::...******%%%+++000666AAAJJJLLLXXXRRRIIIIII]]]hhhbbbZZZ===EEE======EEE@@@666222:::@@@<<<999777555444===---222///000999777333111***+++...---999777QQQNNNUUUwww:::$$$###'''XXX444,,,111111//////222999555...---444666222***,,,---000===...,,,222666GGGKKKIIIKKKGGGHHHGGGTTTJJJAAATTTaaa]]]ZZZ]]]CCC<<<===WWW888555:::<<>>777***------,,,---666<<>>444666222@@@III888;;;111222///555LLL444;;;---999888:::;;;111555***...666<<>>>>>HHHVVV```ttt 7bq~uk]># xxxeeeWWWRRRVVVLLLDDD333444444111+++!!!HHH===JJJNNN[[[UUUWWWhhhkkkmmmgggnnn]]]dddaaa___gggddd]]]YYYbbbtttfffttt|||!~~~  uuunnn}}}mmmoooooohhhfffkkknnn___OOOLLLMMMOOOQQQIIIggggggiii pppiiitttlllWWWjjjeeelllhhhpppzzzsssbbbnnnzzzrrrwwwvvvvvvyyyhhhlllZZZXXXWWW\\\nnnppp```VVVPPPKKKEEEIIIGGGGGGFFFHHH@@@SSSAAALLLPPPQQQSSSKKK>>>???///444222222444;;;666<<>>>>>FFFFFFIIIPPPVVVUUUGGG???AAAZZZ333333000000444888???@@@CCCIIIXXXlll1^s{|seW4 uuu^^^[[[NNNIII===777777777555000===wwwQQQVVVVVVfffmmmvvvkkkrrrsssfffllljjjggg```kkkpppkkknnniiizzzqqqqqqxxx-" - -|||tttsssvvvccc[[[aaarrrlllmmm\\\MMMOOORRRYYY^^^ccc___ZZZ\\\\\\rrrxxx}}}zzzfff___nnn{{{kkkhhhXXXTTTppplllnnn}}}zzzgggfff{{{xxx{{{~~~ tttUUUWWWcccbbbkkkiii[[[WWWRRRNNNQQQLLLCCCJJJLLLOOOIIIPPPKKKHHHFFFFFFHHHCCCAAA======666888111555AAA555>>>lllKKKSSSRRRTTTaaa^^^UUUGGGQQQppp<<>>AAA@@@444000111111AAA)))(((444;;;999SSS;;;999000///222AAA111EEE...CCC)))///---444---???111))))))"""%%%&&&+++...,,,///(((///222+++000000000333;;;===```888EEE>>>EEEAAAFFFLLL>>>CCC>>>===999???888666000///111///444666<<<;;;BBBAAAKKKWWW]]]fffqqq]ilrpaK& jjjdddfffUUUKKK<<<666???@@@>>>666000===DDDHHHRRRWWW[[[eee|||wwwkkkmmmrrrggg___mmmpppcccwww~~~{{{tttttt 0,. -~~~jjjooonnn]]]QQQIIIMMM___ggggggaaa]]]TTTSSSaaaeeefffeeegggccc^^^^^^qqqtttwwwyyy\\\aaacccoootttcccaaadddVVVsssqqqqqq qqqKKK}}}~~~||| {{{ttt}}}xxxtttlllZZZaaahhhjjjbbbWWWLLLLLLQQQTTTCCCHHHLLLOOOFFFXXXSSSFFFEEECCCSSSOOOIIILLL@@@000555666888444<<>>333EEE111555666JJJ999:::+++)))---;;;777;;;CCC:::111@@@&&&%%%(((''',,,...***,,,)))111777///+++...+++333555;;;AAA444<<>>888>>>@@@111...111EEE777666888999===FFFQQQOOOOOOYYYiii1@R_txaE) zzz^^^[[[ZZZLLLCCC>>>>>>PPPSSSBBB???EEEJJJBBBHHHQQQ\\\```gggtttwwwjjjccc``` vvvvvvpppwwwwwwqqqzzz$  52$~~~nnnuuu}}} yyy]]]XXXSSSMMMZZZdddeeejjjeeedddccc[[[WWW]]]iiiiiijjjuuuooonnnjjjnnnlllnnnbbbiiilllbbbfff___aaavvvjjjeeettt~~~|||~~~qqqWWWlll}}}{{{ wwwtttfffbbbggg5,nnnfffnnnYYYJJJRRRbbbQQQ:::OOOKKKAAAGGGJJJLLLHHHJJJHHHSSShhhGGGHHHAAA,,,999<<<666<<>>AAACCC]]]===444000---666...+++555222///444PPP555222111333***'''111>>>999@@@BBB555999???==='''+++)))(((+++,,,)))(((999.........000...;;;:::@@@AAA555999666FFFHHHEEEAAACCCMMMEEE999<<<>>>NNN,,,******555<<<333333111666777DDDBBBHHHMMMOOOyyy|||6NjlFBfff]]]^^^KKKFFF???@@@IIIKKKFFFOOOIIIMMMMMMRRRUUUUUUVVVeeessskkkooolll^^^\\\uuu ~~~}}}ooolllqqqnnndddvvv  ~~~kkkRRRPPPYYYaaafffZZZgggcccccckkklllooorrruuuhhhjjjdddkkklllxxx{{{oooqqqqqqyyytttlllllluuukkkttttttvvvnnnfffjjjssssssfffTTTjjjpppwww|||kkkkkk^^^QQQXXXkkkwwwvvv#;7$xxx^^^cccgggiii>dddnnnhhhYYYLLLRRRNNNBBB>>>FFFNNNNNN^^^OOOJJJNNNQQQWWWNNNKKKMMMJJJLLL777<<<>>>444666>>>EEEFFFKKKRRR______pppnnngggdddGGG(((###(((///555------777AAAEEEPPP@@@AAACCC@@@<<>>CCC&&&'''###(((...&&&(((,,,***///111111777,,,444<<<@@@===EEE<<>>999666111111444111444GGG***)))***)))777666333,,,333:::HHHDDDFFFPPPhhhZZZccc{{{#EHL>&^^^^^^YYYTTTYYYLLLHHH@@@AAAKKKEEEIIIEEELLLPPPKKKWWWooo}}}vvvnnntttuuu{{{{{{{{{ pppnnniiixxxzzztttlllbbbiii```YYYfffbbbgggiiigggkkklllooommmnnnqqqqqqwwwwwwoooqqq}}}zzzssssssmmmjjjdddwww|||sssssskkkoooUUUqqqyyyqqqfffqqqSSSLLLYYYSSSnnn|||:\qqqccciiinnn|||zzzllleeejjjjjjaaaTTTGGGSSS^^^sssDDDIIITTTYYY\\\LLLKKKTTTVVVRRRTTT___JJJ```777555555555888>>>DDDAAAVVVSSShhhpppiiimmmooojjjOOOKKK333'''(((555999666---,,,;;;KKK@@@:::888555666999---...$$$000+++******...///+++...***111999000)))///UUU===@@@:::888444222111KKK((()))(((!!!###&&&(((''')))...111555444000222<<<>>>888666555AAA>>>>>>666444333666,,,++++++000444000+++,,,+++:::CCC222222000777FFFDDDOOO -PPP???NNNppp!#%jjjmmmYYYEEEFFFEEEAAABBBIIIJJJNNNKKK[[[VVV```aaa___nnn 2yyyyyyqqq~~~}}} -zzztttxxx}}} }}}rrrlllgggiiimmmjjjyyy{{{rrrppprrrwww{{{ ssseeefffiiiqqqxxxtttrrrrrruuuvvvwww{{{zzz|||qqqnnneeerrruuuzzzyyyvvvwww```|||ooowwwxxxjjjSSSKKKRRR,4pppcccnnnccceeedddeeedddwwwcccgggjjjRRR===OOO===PPPOOORRRSSSJJJKKKPPPMMMIIIIIIIIIFFFHHH===//////HHHKKK>>>???GGGOOONNNiiimmm]]]WWWrrrnnn444...///333111---...777:::999:::<<<...111222222,,,(((,,,+++***000222'''''')))111HHHfff555444111NNNFFFVVV999===000---@@@ccc***$$$%%%$$$'''---((()))---222444222...000666BBB;;;999777666444DDDFFF555000444777///,,,444000///000---//////000,,,333+++...<<<>>>XXXOOOLLL888NNNkkkjjj}}}{{{hhh\\\jjjlll hhhVVVMMMCCC<<<>>>MMMKKKRRRiiijjjkkkmmmnnnZZZmmmpppuuuttt{{{ uuu |||nnnfffbbbaaabbb~~~ -vvv gggbbb|||iiilll~~~zzzwww~~~|||qqqkkkjjjeeelllqqqqqqlllppppppoooccclllvvvtttxxxxxx{{{zzzzzzyyyzzzwww{{{uuuvvvZZZiiiyyy}}}tttGGGAAAcccjjj|||vvvkkkhhhppphhhaaaUUU[[[ffflllhhh^^^RRRHHH111DDDOOOZZZaaaEEEAAAMMMMMMRRRXXXSSSMMMDDD999222222...>>>OOOAAA@@@<<>>ooojjj777>>>}}}WWWAAA333,,,,,,222>>>)))&&&(((***000******------666222000,,,+++---000555;;;666:::333===666888444333<<<222333@@@\\\///+++,,,111///\\\222......///888OOOlllBBB???>>>888GGGHHHRRR^^^YYYPPPKKKDDDYYYTTTzzzdddMMMHHH???999<<>>GGG:::222...///222444///333,,,...,,,)))...,,,444/////////EEEYYY;;;999666@@@;;;AAACCCEEEMMMLLLHHHIIIJJJCCCPPPLLLkkkSSS:::;;;999YYYRRRMMMQQQjjjkkk\\\YYYWWWccc```qqqtttvvvxxx|||xxxiiijjjppphhhiiijjjccclll{{{ zzzzzzkkkaaaiiivvvmmmbbbfffqqqxxx|||}}}{{{{{{qqqmmmnnnlllnnnllljjjfffaaa]]]^^^bbbfffpppsssooooooooowwwxxx|||wwwxxxzzz|||wwwlllhhhnnn[[[PPPWWWhhhmmmnnn}}}~~~mmmYYYDDDggg}}}wwwmmmNNNYYYkkk```UUU```aaahhhxxxhhhOOOQQQ888666ZZZiiidddiiibbbOOOOOOHHHggglllUUUQQQAAA>>>>>>///;;;AAA@@@EEEEEE;;;OOOUUUOOOSSSccc___]]]PPPWWWaaa777;;;>>>---...555***---)))222AAAHHH;;;===444777444///+++---+++(((''',,,---...;;;OOO```MMMnnn>>>CCCwww&^^^999)))++++++000777$$$%%%'''222111,,,+++,,,+++...555...///666111...222444888===555999666>>>333555333222,,,******+++///333///111,,,)))000+++@@@NNN111666444@@@BBB;;;;;;BBBAAAHHHIIIFFFSSS\\\VVVaaaSSSOOOmmmJJJHHHMMMdddWWW\\\gggqqqpppdddlll\\\gggiiivvv|||zzzzzzuuurrrnnnhhhhhhbbbkkkooooooooo{{{ -}}}zzzyyyzzzbbbrrrhhhkkkssskkkcccssstttrrrvvv{{{sssoooqqqpppmmmiiiiiifffjjjfff```\\\gggggglllkkkfffmmmxxx{{{tttooosssuuuxxxyyyzzz{{{|||}}}vvvfffYYYWWW\\\```nnn|||yyypppqqq___???\\\zzzsssRRRFFFXXXaaaeeegggcccwwwdddTTTVVVPPPCCCCCCPPP^^^iiinnniiiTTTKKKRRRIIITTTOOOMMMFFF;;;888999BBB]]]444AAAooo<<>>:::999AAABBBDDDDDDMMMJJJKKKOOOZZZaaaggg[[[^^^ZZZkkkmmmeeeYYYUUUdddnnnxxx|||ttthhhlllwwwyyyuuuqqqyyyeeeZZZMMMKKKOOO^^^bbbeeeuuu{{{ssswwwzzzyyyrrrpppuuuvvvuuu -pppXXX~~~sssoooyyywww{{{qqqiiiooommmeeeWWW]]]wwwdddjjjiiiiii___jjjtttrrrvvvvvvttt{{{~~~zzzyyyyyy|||wwwwww|||{{{xxxeee^^^YYYYYYaaa^^^vvvyyytttmmm```[[[eeeyyy4~~~{{{ \\\rrrhhhccceeehhheeebbbddd]]]QQQRRRJJJMMM^^^bbbdddbbbWWW\\\RRRUUUUUULLLKKKJJJ444999AAAIIIbbb\\\222>>>>>>IIIIII```zzznnn\\\dddppp\\\SSS;;;777666222111:::555555888///444@@@666444333222///***...$$$$$$""",,,DDD///+++333???^^^ooo HHH222:::EEEOOO:::999;;;777666222$$$$$$******,,,)))---///...000@@@NNNBBB@@@???666777777666111???<<<888444666222+++))),,,+++&&&***,,,***,,,---(((***@@@:::111000+++:::666///666222;;;NNNTTTSSSQQQSSSbbbzzzuuu___TTTXXX^^^___www^^^dddcccrrrlllooottt}}}pppmmmsss{{{qqq|||ZZZUUUHHHOOOQQQddd^^^ooo~~~}}}qqqyyyxxxlllgggcccfffpppwwwoooTTTfffqqqwwweeexxxiiiqqqiiibbbfffaaa___ZZZYYYZZZYYY\\\fffrrrvvvpppuuuyyy}}}}}}}}}|||}}}xxxzzz~~~{{{wwwoookkkcccVVVccckkkhhhttttttqqqgggdddqqqxxx iiiaaajjjuuuvvveee```aaaoooZZZQQQ[[[PPPPPPZZZ^^^gggUUU\\\```aaaUUURRRBBBLLLGGGAAABBB>>>TTTyyyeeeBBBTTT888@@@JJJXXXiiiggg^^^XXXWWW<<<===(((>>>FFF<<<111000......111***...000444111333???)))+++'''&&&%%%&&&;;;:::111<<<:::III[[[iiiKKK999+++///UUU???<<<...666888---+++***))),,,***---)))...,,,$$$444111666999III???ZZZ<<<777777666888111FFF333000555666---...,,,)))))),,,&&&)))///)))EEE<<<...***,,,222---------)))222@@@RRRYYYRRRQQQMMMEEE```fffYYYhhhfff^^^aaadddaaaddd~~~(' qqqssstttjjjnnnkkkzzzyyysss___XXXccctttvvvyyyzzzzzzvvvvvvpppgggaaalll%lllcccnnnzzz{{{aaahhhwwwLLLLLLPPP]]]]]]qqqmmmfffqqqjjjkkkllljjjpppnnnlll||| - }}}{{{{{{xxxttt~~~|||{{{rrrrrrwwwrrrmmmcccYYYkkkeeeeeennnkkkpppoootttuuu fffUUUPPPaaarrrsssaaaRRR```bbbQQQVVVPPPZZZUUU^^^\\\___LLLVVVTTT```^^^AAA777XXXWWWGGGHHHooo~~~___444>>>444???RRRCCCKKKNNNnnn\\\[[[PPP000,,,NNNJJJIIICCC888444000,,,+++333***,,,444,,,000,,,***(((***111+++222...))),,,>>>@@@IIIZZZ>>>)))$$$...222111888???)))------)))+++222***)))(((((())),,,+++)))777111777NNN^^^KKKDDD???<<>>GGGGGGGGGVVVyyynnnLLLOOO444999666:::444444RRR```hhhLLL&&&888ddd```FFF@@@777666...///(((//////000:::666---...)))+++))),,,000000000***555===GGG]]]EEE333%%%&&&'''---+++///777((('''222)))******'''&&&***'''%%%)))DDDKKK>>>OOO^^^~~~HHH???777EEEFFF444000111111666000,,,------((((((&&&'''(((+++***888...+++---)))333&&&&&&)))---...333FFFIIIFFFUUUUUU^^^\\\}}}ccc___ZZZWWWYYYgggmmmnnn -,uuujjjggg[[[eeetttssshhh^^^ddd. {{{sss qqqYYYhhhxxxvvvvvvvvvyyy}}}zzzqqq}}}gggmmmYYY]]]rrr{{{nnnwwwiiieeehhhooommmqqqgggdddeeeZZZRRR\\\```iiinnnpppmmmmmmlll{{{|||   -~~~}}}zzzmmmnnngggmmmuuunnneeehhhcccTTT]]]lllpppwwwtttwww}}}iiikkkRRROOOPPPYYY___fffLLLMMMOOOSSS___aaaYYYUUUXXXkkktttssssssvvvHHHNNNNNNHHHOOO===777QQQWWWRRRaaa000))) ***777===JJJeee]]]///--->>>HHHAAAOOO===888777+++)))+++111444222...222---...&&&%%%,,,111===,,,000...FFFJJJOOOHHH;;;LLLKKK888...///+++(((+++&&&&&&'''%%%***+++---333&&&333***,,,]]]\\\BBB___kkkMMMBBBCCCEEEDDD???AAA888//////333777///111---111++++++(((&&&(((000000)))&&&###...,,,(((000---///111+++000777@@@EEEQQQQQQRRR```P2aaa]]]hhhSSSPPP[[[iiirrryyyiii^^^cccccciiinnniiioooxxxjjjjjj %N%tttuuu{{{QQQSSSQQQsssvvvzzz~~~'}}}kkkoooqqqvvvjjjxxx{{{jjjbbbhhhjjjlllkkkoooooogggppplll[[[ZZZffflllnnntttyyywwwyyy}}}  }}}}}}}}}ssskkkaaaeeemmmiiiooohhh]]]WWWUUUdddkkk|||eeewwwyyyyyytttxxxvvvuuuZZZUUURRRhhhXXXTTTUUUXXX[[[dddhhhvvvccc]]]QQQeeegggssssssyyyTTTaaaPPPRRR???DDD@@@:::<<>>NNNCCCKKKSSSBBB888AAA111000---(((''''''%%%&&&###)))000))),,,&&&&&&222+++---000555KKKOOOGGGNNN___JJJGGG\\\DDDGGG111000444444///111+++...***...,,,+++(((+++111---+++---***888---+++(((,,,111,,,''';;;333???IIIRRRPPPZZZpppNNNKKKQQQMMMTTTVVVgggooo}}}dddiiiuuuzzzxxxtttlll___```zzz~~~6zzzxxxpppuuu|||mmmjjjUUUOOOnnn gggvvvUUUjjjiiimmmyyyzzz|||yyysssfffhhhlllfffhhhjjjooossspppcccbbbgggdddgggnnnqqqvvv{{{  -}}}yyyuuulllhhhhhhjjjvvvlll___```WWWQQQfffuuufffwww|||zzz|||~~~www```UUUNNNNNNaaaTTTdddqqqgggaaaeeehhhjjjUUUgggiiizzzrrrooofffeeePPPRRRAAA===<<>>\\\::::::;;;333333+++---000,,,...+++---$$$###!!!&&&((()))'''(((===???555111000000---+++...555@@@III???===JJJFFFCCCZZZAAA111SSS///>>>333......)))&&&000***,,,+++(((,,,***###''''''!!!%%%$$$///DDD:::???MMMCCC555BBBOOOSSSUUU^^^LLLdddcccsssyyynnniii]]]ZZZ^^^hhhdddfff^^^QQQgggjjjdddRRRXXXvvvxxxuuu{{{oootttuuu|||ooohhh___ZZZjjjeeeWWW\\\hhhjjjxxxeeeZZZNNNRRRaaajjjaaaYYY```dddiiihhhllltttyyyxxxvvvzzz||||||~~~ - {{{wwwooo}}}{{{qqqttt~~~```XXXUUULLL```mmmmmmooossssssoooccc]]]YYYMMMDDD___```nnngggzzzgggggg___\\\UUUUUU``````aaabbb\\\aaaooo```UUUKKKMMMQQQOOOFFF333111///222,,,,,,...333BBB:::@@@HHHCCCDDDGGG@@@444""""""444111333111999///,,,111555222///222888@@@===444---)))111CCCJJJFFFBBB666;;;MMM444,,,,,,,,,"""(((%%%)))"""%%%&&&&&&)))(((===333///555---333111:::222222///<<<666<<<===@@@YYYPPPFFFLLL<<>>===SSSEEECCC:::>>>MMM:::UUU@@@BBB999<<<888<<<(((111///%%%$$$%%%***$$$GGG***''''''"""(((AAA666///---...777666666000333555AAAKKK===???PPPkkkLLL===CCC@@@NNN>>>FFF999------""""""&&&%%%&&&:::,,,###!!!)))$$$&&&666---///888???AAAAAABBBAAAAAAbbb___cccnnn```LLLooogggtttppp~~~nnn``````___[[[WWWTTTVVVXXXTTTcccdddooommmrrryyyvvvqqqooooooddd```aaaddd\\\TTTIIISSSLLLhhhSSS```qqqddddddcccaaaXXXZZZSSSPPPbbbkkkbbbhhhhhhcccRRROOOgggiiipppsssrrr{{{   }}}wwwtttppprrrnnnnnnxxxeee```fffkkkuuuppplll```hhhvvvjjj```[[[JJJZZZKKKKKK]]]TTTqqqjjjwww|||UUUWWW\\\[[[```cccrrr~~~nnnRRRSSSLLLBBBEEEJJJKKKCCC222111000666777BBBBBB===FFFLLLQQQPPPLLL555&&&222;;;888:::>>>:::@@@444000333AAA444999@@@CCCKKK===bbb>>>QQQEEEUUU???iiiTTT555888111999***///777))))))&&&%%%)))%%%,,,'''&&&999&&&222JJJ111---+++555777444666666EEE:::LLLKKKFFFUUUjjjMMMAAAKKKGGG___BBB111***---///"""###***(((%%%+++'''%%%'''"""''''''888666;;;666LLLGGGDDDDDDDDDPPP\\\bbbhhhfff\\\BBBWWWHHHTTTooollljjjbbbbbbaaacccVVVSSSYYYUUUOOOaaaiiiccclll4#kkkjjjhhhooolllllliii```jjj^^^UUUQQQPPPEEE\\\bbbgggsssfffjjjggg\\\NNNNNNCCC]]]eeemmmhhhgggdddTTT\\\eeeooosssooo|||  - #"""!"" -}}}zzzwwwwwwuuuoooqqqmmmddd___\\\aaaYYYaaagggaaaXXXfffgggeeedddLLL\\\IIIEEETTTRRRmmmnnnhhhnnn\\\[[[bbbTTT]]]pppttt{{{gggQQQNNNRRRCCCDDDFFF>>>666111+++///:::CCCJJJQQQ>>><<>>111((((((###&&&+++%%%))),,,'''(((...555EEE...222;;;111111;;;888BBB:::DDDFFF___FFFEEEFFF???FFFFFFBBB333555+++,,,&&&"""%%%'''''')))(((&&&((()))(((&&&111000:::???CCC>>>GGGAAADDDIIILLLOOOhhh^^^XXX>>>:::DDD^^^___jjjvvvggg___XXXQQQYYYJJJNNNYYYMMMUUUXXXbbbiiiYYYtttdddcccgggfffjjjhhhgggfff^^^]]]VVVCCCOOOTTTaaajjjhhhoooyyy|||pppiii```sssaaa___WWWgggjjjsssqqqkkkTTTXXXZZZ___eeeqqquuu~~~ !$'(('%%&$%$"  -}}}yyyxxxwwwuuuqqqnnnnnnfff```ZZZ```hhhqqqiii```HHH^^^bbbddd]]]dddbbbgggiiieeebbbzzzuuuvvv{{{kkk\\\RRRVVV[[[jjjzzzppp```UUUHHH@@@CCC===@@@000888---///***EEE<<<>>>EEEDDDFFF???LLLXXXGGGIII777...<<<<<<111>>><<<@@@---***)))666888NNNqqqSSSoooLLLIIIIIICCC===999XXXDDDXXX>>>666...---111......222,,,'''&&&&&&,,,000777&&&---###---<<<+++===;;;666,,,000@@@>>>444555===GGGDDDSSSNNNEEE@@@WWWYYYAAA444555...+++,,,///+++***$$$(((+++)))>>>222///...,,,???>>>AAADDDEEEEEEFFFKKKJJJHHHJJJJJJNNNDDD???DDD999???iiiuuuoookkkkkk___kkkSSSHHHSSSaaaVVVVVV^^^fffRRRXXX\\\iiiiiieeefffooonnneeezzzddd```WWWIIIFFFPPPVVVgggkkkdddlllqqqvvv uuufff```kkklllcccnnnssslllgggXXXJJJNNN\\\bbbdddnnnuuu~~~ - %),,-,+***)('$$! wwwwwwvvvqqqnnnnnnooommmggg\\\YYYmmmqqqgggWWWTTThhhSSS```bbbiiijjjppptttrrrvvvsssllllll~~~uuuZZZkkkaaagggqqqjjjpppmmm]]]nnnOOO:::===222,,,###%%%222,,,***333222888>>>===@@@EEEHHH???EEELLL666(((555666===SSSCCC<<<444)))222>>>@@@zzzQQQDDDBBBGGGDDDHHH777@@@===EEEEEE===444222---)))???******)))&&&((()))***''')))((($$$)))---******(((:::333444222000666???888888AAABBBLLLDDDNNNKKK]]]QQQAAA333BBB...111+++***+++///444555+++---999777222777:::RRRKKKJJJIIIMMMNNNPPPOOOKKKXXXRRRFFF;;;>>>@@@999FFFFFFpppqqqwwwyyy^^^^^^YYYLLLRRRbbbZZZYYY\\\]]]YYYXXXdddcccddduuukkkaaafff^^^rrrrrrfffIIIFFFIIIOOOQQQWWW]]]tttiiiyyyxxxssswwwlllggg___```lllooolll]]]hhhZZZNNNOOO[[[kkkpppuuuyyy !%(...00021/,*)''$! wwwuuuppppppqqqlllooottteee\\\[[[aaaaaaWWWeee```___gggcccssshhh}}}|||sssnnnbbboooggghhhfffcccdddnnnpppeeeiiiWWWFFF]]]000)))"""""",,,///...444FFF777888>>>AAA;;;:::999===CCC666(((999IIIHHHCCC===666///;;;>>>WWWVVVFFFRRRRRRJJJFFFHHHHHH>>><<>>CCCVVVAAAGGGEEEJJJNNNPPPVVVLLLKKKeeeSSSXXXKKKGGG888ggg~~~WWWfffxxxqqqkkkjjjbbbfffttt```___```nnnjjjaaabbb___ffflllccc```^^^XXXaaa[[[pppiii```TTTMMMPPPGGG___\\\ZZZaaaooohhhmmmwwwhhhZZZfff[[[\\\___aaakkklll\\\___KKKIIINNNddduuuuuu}}}~~~ - &+,0245545530-+)(%# ~~~wwwrrrnnnooouuuqqq|||eee``````]]]oookkkfffoooiiiiiicccfffzzz ooojjj```lllssslllfffiiinnnxxxgggdddRRRGGG<<<333:::)))"""###***,,,999>>>AAA:::444:::;;;::::::666888///&&&<<>>;;;...((((((***&&&%%%$$$%%%&&&$$$###&&&+++***%%%%%%)))111888AAA111222CCCPPPXXX===DDD<<>>:::DDDHHHPPPFFFDDDAAAPPPDDDGGGEEEKKKIIILLLPPPTTTTTTVVVRRRBBBEEEgggnnnnnnzzz|||kkkuuuccc\\\^^^]]]______```nnn\\\ iiipppjjjlll]]][[[\\\___cccddd]]]^^^TTTOOOLLL___ZZZ[[[XXX```ZZZcccqqqrrrsssrrreee\\\TTTYYY___```aaa]]]cccaaaTTTIIILLLRRRjjjuuuvvv %).0156888::730,*)%#}}}{{{xxxqqqooovvvooo eeeYYYeeepppjjj___fffnnnmmmdddbbbeeevvv{{{ nnnnnnjjj^^^hhhuuubbbgggppplll{{{jjjoooKKKCCC<<<>>>===444***+++111...;;;:::;;;444555:::<<<888:::<<<000 )))+++666@@@???CCC999666>>><<>>QQQNNN555;;;GGG444...)))))),,,,,,000###%%%'''+++%%%$$$ ------)))&&&"""$$$444---777LLL;;;???BBBKKK\\\QQQGGGOOOBBBSSSJJJMMM???FFF666>>>888---///******111222555[[[aaaIII???HHHDDDEEEFFFLLLlllPPPAAAJJJEEEEEERRRVVVMMMTTT[[[eeefffjjj{{{}}}^^^eeesssYYY[[[hhhiiiiii\\\ooommmeeefffhhhjjjooobbbgggtttbbbhhh___^^^OOOFFFYYY]]]]]]XXXPPPdddoootttoootttyyysssddd```VVV\\\^^^hhhhhheeekkkaaaVVVSSSfffkkkssswww~~~ !),12479==>?=:74/,+'$ {{{{{{ssspppqqqoooqqqpppeeeZZZsssppplllbbbkkkhhhbbbXXXbbbjjj~~~sss3 zzz[[[[[[aaa___lll|||tttsss___TTTFFFEEE:::===555000***)))///333555444444999888999???;;;CCCAAA777'''999888GGGHHHEEE:::222444@@@;;;GGGDDD:::333888BBB;;;;;;888777:::cccNNN@@@999;;;///111'''%%%+++,,,+++,,,***((('''""" )))PPP444***'''$$$+++(((---:::444KKKQQQHHH>>>YYYjjjhhhjjjEEE???EEE:::@@@888333444===LLL222...))))))000///FFFbbbNNN??????AAABBBGGGLLLMMMRRRMMMBBB@@@IIITTT___^^^YYYSSS[[[iiiiiiqqq oookkkbbb```qqqrrrWWWXXX\\\PPP^^^UUUpppsss|||gggfffaaafffllleeecccgggsssffffffbbbaaaRRR^^^VVV]]]RRR```wwwyyysssuuuiiidddYYYXXXUUUcccgggmmmllllllwwwiiiuuutttwww||| -"(+0357:>@BCDA<9850+(%!~~~}}}uuuwwwooonnnmmmnnnpppccc[[[{{{rrrmmmjjjfff___ZZZ\\\______mmmzzz {{{___\\\\\\bbbiiimmmvvvqqqhhh^^^TTTGGG>>>777999<<<444444(((000555111666DDD<<<>>>===>>>BBBBBBSSSAAA444;;;@@@PPPbbbIII@@@...111444222///...+++///222777888===BBB888999MMMCCC>>>???<<<***,,,(((&&&$$$((()))+++(((///&&&&&&'''$$$$$$'''###111###%%%---333888000777SSSvvvNNNUUUjjjPPPPPP]]]PPPHHH;;;???444999555777111:::---(((&&&---999YYYAAA>>>@@@DDDHHHEEE???QQQRRRQQQOOONNNXXXSSS^^^bbblllYYY???aaavvvkkkqqqnnnrrr]]]hhhdddfff^^^cccXXXMMMWWWbbbUUUbbbuuudddcccuuubbbjjjkkkeeeqqqnnnfffaaa\\\iii___YYYYYY]]]UUUMMM[[[ppp{{{www7ppp```eeebbbfffooogggiiiooouuuooowww{{{vvv|||yyywww|||~~~#*.167;?ADIHGEA>;81.*("~~~yyyvvvuuu{{{uuuooojjjhhhdddfffkkkjjjjjj|||ggghhh___NNNTTTYYYlll}}} - rrrYYYZZZ\\\]]]pppiii|||~~~lllaaaZZZPPP:::666444GGG777333((()))///666444111<<<999OOO@@@AAADDDEEE;;;777999AAABBBXXX\\\PPP@@@///666999888666&&&!!!)))111<<>>===HHH888<<>>555222555222///(((...---((($$$###"""&&&'''!!!!!! """---///000555222888BBBIIIGGGCCCOOOeeemmmKKKIIIPPPeee@@@666000888...,,,&&&"""***&&&+++///+++***'''888OOO;;;LLL???EEEIIIMMMPPPMMM_________iiinnn{{{}}}uuupppSSSXXXKKKMMMHHHPPPRRRRRRVVVTTTTTTWWW]]]uuugggddd```fffcccbbb^^^fff qqq ssseeePPPTTT]]]YYY```\\\ppprrrssseeeRRRWWWCCCMMM```eeeoootttrrrzzzpppeeejjjwww~~~{{{|||~~~ "(-26>>CCCKKKGGGHHHJJJWWWbbbrrrcccgggI  wwwtttyyyqqqlllRRR]]]KKKIIIHHHUUURRRWWWeee]]]aaaYYY```ZZZaaaooo^^^ggg```XXXccc -}}}pppfff]]]SSSUUUUUU\\\ggg{{{pppgggfffZZZJJJPPPXXXdddkkkmmmmmmqqqssslllkkkZZZbbbyyyzzz{{{}}}|||").4;?FNSTWWWUSOID@;51.*# }}}yyywwwuuurrrlllxxxkkkccccccaaa^^^bbbfff[[[```ZZZrrrgggPPP___oooqqq}}}jjjZZZYYY```YYY^^^sssiiidddaaa]]]XXXGGGGGGIIIAAA>>>===???555000,,,***999888444999666666AAAHHHEEE555"""AAAHHHPPPgggGGGAAA888;;;;;;333......444000===@@@@@@EEETTTIIIQQQQQQddd~~~QQQ;;;222BBB222%%%$$$------***(((%%%000)))***%%%&&&$$$)))444222222000>>>DDDYYY\\\yyybbb^^^RRRRRRGGGJJJDDD@@@222333...---+++&&&###$$$)))***333222---333888555WWWHHHFFFHHHYYYNNNNNN___ooo\\\hhh___uuuhhh/iiixxx{{{tttgggZZZ\\\XXXJJJEEETTTQQQXXXVVVuuubbbccc\\\\\\dddcccfffcccVVVaaakkk~~~nnniiimmmfffbbbRRR[[[```nnnrrrhhhooogggwwwfffUUU\\\___kkkllliiiiiimmmllljjjggggggdddsssvvvzzz "(/5;AIQV\___[VQKF@:510)" -|||yyyqqqmmmooossseeebbbeeeggglllnnncccWWW]]]UUUkkkdddNNN\\\zzz```aaadddssspppZZZ[[[___hhhuuuaaa___WWWSSSJJJJJJVVVZZZDDDCCCAAA777<<<333888AAA000...888(((444999===???@@@---'''AAAFFFRRRKKKFFF;;;;;;<<<;;;222666555555999>>>;;;BBBCCCLLL888OOOIIIMMMIvvv@@@000444---'''%%%&&&---@@@...%%%%%%&&&'''666)))---111,,,666@@@QQQfffqqqPPPSSSQQQ@@@>>>CCCRRRIII444---...555+++%%%!!!+++***555///---,,,,,,BBBHHHzzzKKKFFFLLLSSSSSSOOOWWW___RRR]]]XXXkkktttyyyqqqiiiMMM^^^ppp|||{{{iii]]]XXX[[[YYYQQQQQQTTT]]]iiiggghhhgggyyyVVVqqqeeeyyyhhh\\\aaaeee tttcccfffdddSSS```gggbbbddduuummmaaaVVVnnnXXXbbbuuuiiiZZZffflllpppmmmkkknnniiimmmoootttyyy -!%)049AKT\elkibZRMH@9630)# {{{xxxuuuooopppqqqeeedddbbbiiipppjjjeeeVVVVVVZZZrrr]]]ZZZcccuuuwwwuuuiiigggfffwwwXXXZZZbbbrrr{{{ccc___SSSVVVIIISSSfffLLLNNNHHHBBB;;;???AAA===<<<,,,$$$### ,,,999<<<<<<777111---999@@@AAACCCBBBMMMLLL;;;777666444888AAA???FFFQQQTTTNNNCCCEEE999TTT;;;cccbbbAAA777(((111,,,---"""&&&///'''###"""%%%))) ###999KKK...@@@444777@@@KKKtttxxx{{{ZZZ<<>>KKKOOOddduuufff___\\\YYYYYYzzz___\\\VVVaaafffyyyiiipppjjjccceeeaaacccpppeee^^^^^^~~~ ' {{{JJJRRReee]]]kkk```^^^```ooowww___]]]fff\\\___dddccchhhTTTOOO]]]cccfffkkkgggcccnnnrrrxxx}}} -#(+159ALU^jvyrh]TNHA;63.(# xxxtttpppooommmnnnhhhbbbeeejjjkkkgggbbbVVV[[[bbbiii\\\^^^eeepppwwwssstttvvvmmm]]]WWW^^^rrr{{{fff___VVVMMMZZZ|||vvvYYYOOORRR@@@333555JJJ111111,,,"""###,,,777;;;===444???---777@@@GGGNNNGGGVVVBBBTTT>>>111222777AAA```TTTNNNiii]]]FFF888777;;;<<<>>>666===000***000666+++EEE000***&&&!!!"""***666###&&&"""...>>>///@@@???777RRRRRRgggYYYUUUSSS999@@@WWWHHHDDD999===---)))>>>++++++"""---+++000)))777333DDD555>>>;;;@@@<<>>???GGG```yyy]]]nnnHHH<<<>>>EEE@@@===BBB:::///222888000333,,,&&&%%%,,,222111666VVV<<<999<<<;;;PPPeeeJJJOOO@@@AAACCCjjjbbbWWWPPPFFFEEEMMMMMM```[[[UUUaaaiiigggdddfff]]]cccpppbbbZZZRRR]]]```fffkkkmmmdddbbbwwwiiixxxgggtttwww |||vvv```MMMLLLKKKaaaVVV___WWWgggssseeennnWWWYYY```pppaaafffYYYnnnvvvRRRcccqqqaaaaaappppppxxx -"!&,/27>FMRZaotndYQKF?:52,$ zzzuuuqqqnnnmmmkkkbbb___bbbeeegggdddaaa^^^WWW[[[jjjfff```]]]fffnnnsssiii|||+|||```oooiiiccc}}}yyyvvv]]]^^^NNNKKKMMMLLLNNN???AAA:::444555///***###333---,,,(((---222222///%%%'''???LLLVVVLLL===CCC>>>BBB;;;444333???ZZZRRRLLLKKKQQQMMM???WWWCCC666HHH;;;111(((,,,:::,,,---AAA***&&&(((%%%###!!!%%%!!!!!!&&&(((000nnneeeWWW___cccUUU[[[>>><<<;;;:::999FFF777===444222^^^CCC((()))***+++>>>444???@@@CCC???AAA;;;\\\OOOQQQ@@@AAAIIIHHHRRR\\\]]]bbboooSSSFFF>>>HHHRRRfffeeecccvvveeeiiibbbllljjjcccNNNSSS___NNNRRRaaa___\\\___cccjjjnnnqqq{{{tttzzzjjj^^^SSSCCCMMMZZZ[[[[[[aaaccclll___vvvaaaDDDRRR___```\\\^^^}}}nnnaaatttjjjmmmSSS]]]jjjssswww{{{ $'*.49?GLOUZbgcZTPJD>92-&# -{{{yyyrrrtttrrrkkkdddgggfffhhhlllbbbbbb[[[]]][[[]]]hhhiii^^^gggxxxcccyyy}}}nnnvvvjjjeeennnxxxgggZZZTTTLLLKKKBBBDDD666111222555999---%%%"""%%%(((888000)))///222(((###777;;;IIIcccoooEEE===>>>CCC===<<<666666BBBNNNFFFMMMNNNRRRTTTQQQcccPPPMMMKKKPPP---***%%%''',,,%%%((( """%%%$$$"""$$$### 888///{{{QQQPPPhhhWWWBBB>>>666222444999111999444444666AAA)))444***///444===SSSIII;;;DDDQQQGGG<<>>TTT___aaa\\\aaaiiiooosssqqqJJJAAATTTeeeTTThhhmmmjjjooojjj```ZZZqqqrrrzzzyyyyyy&(+159?EHMQTY]\SPLHC=72-%! zzzuuuuuuwwwssshhhdddjjjiiimmmqqqbbbWWWLLLYYYgggeeebbb```dddnnnooo|||zzzxxxAyyytttcccfffZZZhhhbbbZZZQQQLLLTTTLLLHHHFFF;;;888666555444)))&&&$$$&&&###---+++,,,===BBBPPP444>>>FFFJJJWWWUUUHHH>>>FFFAAA666MMM;;;BBB<<>>;;;111---999,,,333+++(((+++222444===LLL;;;CCCgggSSSVVVDDDLLLJJJ```aaagggaaa___nnn:?xxxZZZ^^^___aaaqqqdddLLLNNNZZZooozzznnnuuuSSSFFFPPPKKKNNNcccbbbQQQ```kkkzzz rrrnnnyyymmmggglllQQQEEEWWWbbbeeeeeeiiilllkkkuuu^^^HHHQQQ___hhh___kkkooopppqqqeeegggfffggghhhmmmtttxxxxxx{{{ #%+059:50)$  -yyyuuuvvvvvvjjjiiijjjjjjiiijjjlllaaaVVVJJJVVV[[[XXXTTT```|||ttt{{{rrrwwweeejjjsssjjjuuusssmmm\\\ccc___TTTRRROOORRRCCC@@@AAABBB999JJJ---444$$$+++***!!!***555DDDHHHBBB444BBBBBBHHHRRRXXXSSSMMM???:::999666AAA;;;HHH777<<>>888:::000555444LLL///444555000444666,,,>>>YYYHHH>>>777DDD6MMM>>>CCCKKK===;;;WWWaaa```hhhlll{{{1&5wwwccckkk\\\fffffflllttt{{{cccccc```TTTgggOOOPPPPPPPPPWWWaaa```SSS[[[RRRdddpppuuu=vvvbbbccc^^^WWWQQQmmmooolllooouuuwwwjjjUUU___\\\RRRdddtttmmmooo```fffbbbhhhdddqqqyyy{{{}}} !&,048:>>444666CCCLLLUUU\\\XXXDDD<<<555;;;GGG===666888333999kkkddduuurrreeehhhsssddd+++  !!!$$$(((+++$$$""" $$$???JJJ,,,777///222444<<<666777777MMM333999555000555555333@@@///000666***===EEE777///cccHHH%LLL===BBBEEEVVVNNNJJJOOOIIIggghhhfffhhhwww~~~eeehhhZZZ[[[WWW```nnnxxxmmmooommmmmmEEEFFFDDDLLLJJJJJJJJJJJJTTTXXX^^^qqqUUUVVVPPP```zzzkkkmmmccciiiiiiYYYTTTWWWaaaeeemmmxxxoooooo]]]```aaaYYYCCC___lllqqqpppppp|||qqqaaagggnnnrrreeejjjvvvxxx~~~ %+.1479?ADGIKH@AA=951,)# -~~~wwwvvvnnnooonnnkkkhhhkkkpppnnnggghhhcccXXXOOOLLLSSSdddxxxyyypppvvvhhhVVVMMMNNNWWWgggkkkggggggfff\\\]]]PPP[[[IIIHHH888222...,,,,,,%%%''' $$$''',,,%%%###333AAAJJJCCC@@@KKK999>>>TTTWWWbbbfffJJJ<<<444:::666444222444888:::aaaXXXhhh```eeeaaaooo```888...###%%%"""&&&+++$$$!!!$$$%%%"""666AAA...333...///333777:::666111999000444555888222888555555666--->>>...///:::@@@666@@@CCC;;;777===CCCQQQTTTKKKRRRNNNRRRRRRdddyyyggg]]]hhh{{{pppkkk```VVV^^^[[[___cccggg}}}uuubbbRRRDDDUUULLL===999BBBHHHQQQ[[[RRRSSSTTTLLL___dddgggxxxpppeeedddAAAHHHQQQ[[[PPPcccuuusssaaa[[[iiidddOOObbbgggrrrppppppfffVVVaaakkkoooooo}}}yyyrrryyy|||$),/269:=>BEE?<;:951.*&  }}}vvvuuuiiijjjmmmggggggllltttooo```eee}}}VVVWWW{{{mmmaaaQQQNNNRRR[[[mmmpppxxx]]]UUUXXXYYYEEE;;;JJJJJJBBB333333+++&&&***$$$***---111"""///???@@@AAAFFF<<>>HHH555000888888111222000)))---444:::111///...444999222+++111,,,111888:::222444777NNNKKKJJJZZZCCCDDDaaaiiiYYYVVV]]]bbb```jjjmmmcccaaa^^^]]]aaa^^^zzz[[[cccuuutttwww IIIPPPdddnnnBBBBBBEEEXXXRRRTTT___YYYhhh^^^fff]]]\\\5^^^WWWCCCEEEUUUcccRRRfffaaaeeejjjsssIIIxxxlll]]]llllllqqqlllyyypppdddhhhmmmqqqpppvvv{{{{{{").-1478::<@?;78642-)(# -wwwsssggghhhgggiiijjjnnnvvviiiRRRZZZffflllVVVaaa -yyyeeessseeeVVVcccZZZnnn{{{vvvccc\\\bbbTTTBBB???SSSPPP???777)))LLL+++'''---000###""")))222DDDGGGGGGNNNMMMBBBLLLAAAGGGQQQPPPIIIBBB===:::555222777666<<>>GGG<<<555+++---111111222666---//////+++))),,,'''...444+++---000///<<<777;;;///555:::[[[III@@@SSSMMM```SSSVVVYYYVVVSSSdddjjjgggsssvvvnnn___\\\xxxfffeeeqqqsssooolllllllllFFFRRRQQQOOOPPPGGGHHHUUU___VVV[[[aaaggg rrr\\\UUUCCCRRRNNNXXXNNNPPPZZZVVVVVVTTTQQQ```ggg``````qqqgggffflllqqqkkkmmmssswwweeeiiilllhhhpppzzzwwwwww !(--014678669:4230,(%$  ~~~}}}wwwqqqmmmooollljjjkkkrrreeeRRRNNNXXX^^^___```oooyyyuuuqqqdddTTTUUUTTT[[[ggg___```qqquuujjjnnnaaaRRRPPPHHHBBBFFF===999000,,,...444---+++""")))CCC555000AAAOOOQQQKKKMMMYYYOOOGGGEEESSSRRRIIIMMM333333222///666;;;===LLLAAA???AAARRR[[[UUUBBBXXX>>>222###''')))---'''***))) +++"""'''&&&"""444###%%%"""???MMMFFFHHH111444,,,---222444===:::333///111---111333///---(((222---888111000666JJJ<<<@@@>>>KKK[[[DDDFFFOOOZZZMMMIIIVVVWWWgggqqqjjj___iiigggkkk___[[[oookkkgggssshhhhhhkkkAAALLLQQQ;;;IIIMMMVVVMMMOOOOOOOOOYYYUUUaaa^^^^^^pppwww```NNNHHHNNN[[[OOORRRnnnTTTMMM^^^\\\dddWWWZZZ\\\dddWWWVVVkkkxxxooorrruuujjjkkknnnooowwwvvvzzz{{{ssswwwyyy %*,//148640251,.-*&#! -yyytttllljjjrrrsssrrrlll|||UUUPPPOOOWWWXXX___kkk{{{|||vvvuuulllYYYaaaTTTgggbbbaaaqqqjjjrrrnnneeeZZZlllIIITTTeee^^^BBB???222>>>JJJ111+++((('''...555>>>999888DDDSSSSSSYYY___PPPKKKPPPGGG@@@===999777,,,000@@@>>>BBBEEE:::<<>>CCC@@@:::666444777888333222;;;///...111,,,---+++)))$$$+++...111555;;;+++)))888FFF666;;;BBBGGGIIINNNKKKSSSUUUMMMJJJVVV[[[ggg]]]YYYbbbaaadddbbb\\\mmmqqqooo|||nnnsss```)))***777999HHHMMMUUUPPPWWW]]]JJJRRRfff^^^cccfff]]]jjjYYYOOOBBBNNNTTTYYYPPPlllOOO\\\pppllleeeYYY\\\ggg[[[DDDiiiuuu|||rrrqqqqqqmmmnnnooosssxxxxxxsssuuuyyy|||zzz~~~"'*+,.16340./,(*+(%  |||xxxqqqmmmlllnnnrrrkkknnnlllUUUBBBMMMGGGZZZccclll -~~~tttpppaaassstttUUU^^^eeeccceeepppssskkk___VVVNNNIIIHHHJJJMMM???++++++000000//////)))666333CCCOOOHHHQQQVVVSSSPPP]]]gggddd[[[QQQIII777JJJNNN777//////444888???BBBPPP777///&&&'''DDD:::AAA,,,+++,,,'''$$$###""" ###'''""" !!!!!! &&&$$$"""<<>>FFFXXXgggiiivvv}}}|||sssxxx___WWWdddkkkdddhhhjjjbbbeeesssmmmaaa]]]SSSHHH@@@NNNAAA888:::///,,,***$$$&&&***222:::???DDDGGGKKKMMMQQQZZZ^^^RRReeecccTTTDDD000...---999>>>@@@888:::;;;999<<<888666===GGG---$$$------///...+++000(((###%%%&&&$$$((("""###!!!""")))  VVVMMM666888HHH666111000666GGG@@@:::999///222///777222***333888666000111ooo - AAA999666::::::GGGIIIPPPLLLXXXYYY[[[\\\jjj^^^gggggg```jjjkkkWWW______```rrrkkkoooHHH@@@&&&444KKKzzzeeePPPUUUaaa]]]WWWZZZXXXYYYYYYNNNZZZaaa[[[[[[hhhRRRQQQMMM[[[eeegggrrr -nnnrrrjjj[[[bbb{{{qqqwwwkkkssszzzxxxzzzpppwwwlllzzz|||qqqqqqrrrpppwww||| $'()--.,*)(&#"  -~~~zzzrrrllluuurrrlll```^^^LLLBBBKKKMMM???XXXffffffiiiooojjj```lllhhhiiidddaaafffuuu{{{dddwww{{{ooo```WWWYYYEEEFFFPPPJJJ===@@@222,,,+++)))......444999666FFFOOOQQQTTT\\\bbb]]]WWWRRRKKKQQQAAA555888555:::AAABBB======999999111444666???:::;;;...///***&&&***,,,***+++$$$ 000***"""!!!###""" """  !!!$$$###nnnXXXGGG@@@LLL>>>222---,,,???555666111AAA---++++++111000)))---;;;555+++888GGGTTT===;;;555999:::===EEEFFFEEEKKKbbbbbb___YYY\\\\\\gggiii```___\\\ccchhhXXXiiidddqqqwwwoooPPPUUU<<<666IIIVVVSSSMMMNNN\\\[[[XXXWWWaaaXXX\\\[[[oooYYY[[[QQQWWWTTTMMMGGGLLLeeeeeebbboootttppphhhxxxLLLeeedddqqqrrruuu|||zzzyyyyyyjjjiiisss|||||||||~~~{{{xxxrrroooooozzz}}}  %&'')))((&$"  -{{{sssrrrooorrrpppeee^^^[[[RRROOOIIIDDDBBBYYY```aaa[[[RRRUUU~~~zzzppprrrkkkbbbjjjyyymmmeeerrrpppmmmeee^^^WWWPPPSSSPPPkkkOOOAAA;;;888333111222444777<<<888MMMNNNRRRXXXUUUYYY```JJJBBBAAAEEEFFFAAA???999AAABBBHHH===DDD:::333777666BBBGGG555777666***&&&&&&(((''')))$$$!!!!!!""")))&&&%%%  ###%%%!!!BBBLLL???:::666---------***AAA666999222555222(((222---'''(((,,,000;;;///---666>>><<<444222555===;;;BBBBBBEEEMMM]]]VVV\\\```aaammmllllllTTTTTTMMMQQQ[[[[[[hhhllljjjkkkbbbOOOCCC888666GGGVVVCCCLLLZZZWWW]]]kkkXXXRRRVVVOOORRRNNNMMMQQQSSS>>>IIIQQQJJJPPPaaabbb```jjjiiiVVVNNNhhh```ttt~~~xxxvvvuuuiiikkkrrrxxxxxx{{{yyylllkkkmmmggglllyyy}}} #$&%&&%%$" ~~~|||wwwrrrqqqlllooohhheeedddZZZYYYRRRCCCAAAMMMVVVXXX^^^UUU\\\|||~~~}}}kkklllqqqqqq{{{tttqqqfffcccccc[[[nnnyyy]]]TTTDDDBBB777666---222)))<<<<<<555GGGLLLYYY^^^VVVPPPRRRLLLEEENNNFFF???999@@@BBB<<>>DDD::::::666333888//////'''###%%%%%%***%%%%%%$$$'''!!!$$$'''%%%,,,777!!!!!! ;;;$$$))) ;;;888:::111111444,,,---&&&'''///555......HHHCCC===...'''!!!$$$BBB+++(((...777111===888777222888<<>>CCCEEE???EEEDDD]]]VVVuuu{{{lllYYY===???NNNMMMQQQddd]]]QQQXXXgggdddjjjaaaaaaYYYTTTeee$ZZZOOO```[[[WWWYYYaaacccWWWdddMMMNNNGGG___VVVWWWRRRPPPQQQEEEAAATTT[[[cccuuuwwwppphhh{{{|||zzzmmmuuusss```bbb```lllqqqyyyyyyvvv[[[UUUgggfffnnn{{{|||  !!  ~~~|||{{{{{{tttkkkqqqvvvnnn___ZZZZZZVVV___eeejjj```VVVTTTXXXWWWccceeettt%#}}}wwwnnnkkkiiiiiiqqq -~~~qqq___cccpppbbbZZZGGGNNNaaaBBBIII===777;;;AAAGGGIIIFFFOOOMMMTTTQQQUUUVVVNNNLLLIII???///222BBBYYYBBBDDDHHHOOOLLLFFFRRRPPPJJJGGG;;;444:::444,,,)))(((''''''&&&$$$%%%###***+++ """$$$######'''""" ***&&&'''%%%...111555555000444...222777000,,,###+++111333///333999444...'''<<<+++###'''***&&&888555444555@@@555QQQ>>>===GGGOOOZZZhhhhhh||| bbbMMM>>>FFFWWWXXX```]]]OOObbbfff```]]]```[[[]]]___eeeZZZNNNOOOZZZUUUwww^^^gggaaadddSSS>>>BBBWWWEEEYYYXXXQQQLLLEEESSSeeeaaahhhttt,|||qqq\\\qqqcccrrrjjj```ZZZ```eeesssyyy{{{uuupppTTTaaakkkuuuvvv{{{  -~~~zzz|||xxxsssrrrqqqqqqjjj[[[WWWXXX^^^aaaaaaeeefffeeeaaallljjjuuu___eeezzzqqqwww|||gggfffeeekkkrrrzzzrrrllleeefffZZZIIITTTeeelllJJJ>>>===???GGGBBBNNNXXX[[[MMMFFFSSSOOOUUUYYYPPPCCC;;;///;;;===EEE@@@:::CCCIIIMMMLLLCCCEEEIII>>>AAA;;;<<>>===HHH@@@DDDDDDNNNMMMJJJKKKNNNKKKKKKBBBBBBGGGFFFCCC<<>>///:::)))$$$$$$%%%!!!!!!%%%!!!!!! !!!###$$$ !!!###%%%KKKAAA333'''///888888888444666...333///000///111222<<>>888@@@EEELLLMMMNNNZZZ```cccZZZbbb\\\GGGRRRYYYDDDJJJKKKEEE\\\^^^qqqjjjooo#@QDGC|||ppppppqqqqqqiiibbbVVVVVVbbbqqqvvvkkkyyyTTTWWWkkkiii}}}}}}   zzzxxxxxxuuuvvvwwwyyyzzzxxxppphhhgggaaaVVVbbbfff\\\\\\fffllluuuzzzsssmmmooovvv{{{yyyssscccffffffeeeaaammmvvvlllqqqkkknnniii~~~llliii```fffBBBQQQEEE///;;;888555;;;@@@nnnLLLIIIdddVVVTTTSSSYYYUUUIIICCCJJJHHHKKKJJJ???:::NNNNNNJJJQQQ```>>>DDDCCCBBB???LLL;;;iii???@@@:::666,,,%%%)))%%%""")))###---******''' """%%%!!! ######&&&''';;;***)))(((@@@777:::<<<<<<222<<<222222AAAttt@@@---AAA>>>,,,)))...AAA(((,,,"""///111,,,>>>888888444AAA\\\JJJhhh\\\dddlll~~~rrrsssxxx```fff{{{|||{{{zzzddd\\\XXXTTTqqqggghhhRRREEEGGGQQQGGG...???<<>>>>>666888::::::BBBDDD???DDDQQQRRRQQQRRRMMMOOOUUURRRRRRSSSRRRVVVUUUIIIXXXXXX hhhbbbzzzlll]]]JJJNNNBBB>>>>>>333===111((( """((((((***---$$$%%%$$$$$$222%%%""")))))),,,222---///GGG;;;<<<111---666999EEENNN777000%%%===222+++******...,,,***888&&&///)))(((666333+++---++++++666;;;555999:::AAA<<<999333HHHBBBKKKdddqqq \\\+iiiFFFKKKUUUuuutttlll```YYYXXXXXXZZZTTTSSSKKKJJJIIIFFF666444,,,444111===DDDZZZHHHMMMXXX]]]RRRLLL:::999@@@>>>>>>[[[aaaOOOGGG\\\aaahhhmmm &/71,{{{aaaUUUeeehhhiiiggg```KKKVVVfffjjjnnnqqq{{{zzzxxxiiikkkvvvzzz}}}ppprrrxxx  ~~~{{{|||}}}{{{vvvooonnniiiggg^^^```[[[VVVYYYjjjmmmfffiiinnn~~~yyy|||zzzrrrmmmggg]]]eee___ZZZaaagggiiirrrkkkoooeee[[[|||\\\VVV999222999:::FFF===>>>KKKBBBGGGGGGFFFQQQQQQKKKWWWOOOffffffUUURRRkkkuuu___ZZZ[[[[[[ SSSyyyoooNNNFFF999AAA===<<<666111///))))))+++$$$&&&+++///---&&& +++***''''''...'''eee,,,333JJJ111:::666OOO>>>>>>WWW[[[PPP999+++(((000------(((""")))---EEE(((((()))---222//////)))***222222:::222999333333...:::<<<>>>QQQIIIAAAOOOdddaaaTTT?aaaAAA@@@___oooppp___QQQ```VVVGGGRRRRRRKKK@@@EEEBBBBBB333222000666<<>>bbbKKKFFFBBBIII<<<>>>PPP888000...---///'''(((&&&)))000FFFIII((()))$$$***(((---666***...)))111---+++---555]]]444XXXZZZ<<>>DDDMMMCCCCCCFFFHHHMMMTTTUUUHHH777DDDTTTCCC<<>>???HHH???:::CCC======555666666222---...)))((()))+++)))XXX<<<222111///888)))))))))(((((($$$%%%,,,***)))///;;;999===<<<:::222,,,(((***&&&555+++(((&&&###$$$'''<<<))),,,333111)))(((,,,///???888:::000111...;;;===GGGAAADDDGGGSSS[[[HHHIIIWWWKKKJJJNNNLLL___dddgggaaaSSSMMMEEEHHHUUUEEEOOO[[[DDDCCC<<<>>>000666999777<<<;;;:::BBBHHHKKKJJJMMMOOOJJJ999666IIIKKK...888[[[RRRHHHccceeeOOOYYYaaaqqqiiiUUUbbbeeekkkeeeEEEZZZnnnXXXJJJbbbbbbWWW]]]^^^qqquuuzzzwww}}}yyynnnrrrwww}}}pppnnnwwwwwwxxx~~~ |||xxxzzz}}}yyyrrrqqqaaaZZZWWWWWWdddaaakkknnniiijjjtttvvv{{{qqqnnnuuulllmmmnnntttvvviiibbb```oooZZZiiipppbbbcccpppmmmdddgggoootttSSS[[[HHHCCC:::@@@999222222;;;777===DDDaaaIIIRRRFFFRRRCCCIIIHHHOOOHHHPPPVVV\\\ZZZcccYYY___ccc]]]```gggkkkWWWGGGLLL^^^CCC999888444555000333>>>555444+++!!! ###(((---+++)))QQQ666111)))///'''&&&***'''***###+++###'''111)))555JJJ333222.........***&&&(((,,,)))000""""""!!!'''&&&333&&&''' CCC...>>>+++))))))555///333111GGGBBBCCCPPPQQQLLL~~~___BBBXXX???BBBKKK___sssvvvjjjaaaUUUTTTfffJJJMMMPPPZZZbbbAAA===WWWaaaAAA///333444444<<>>222+++---KKK000000...===222:::]]]VVVEEEHHHDDD===666888EEE```eeejjjdddhhhXXXRRRRRRHHHLLLNNNUUUJJJBBBGGGHHH999444666111777888<<<:::===@@@FFFFFFHHHLLLKKKAAA555$$$...333JJJ???NNNMMMAAACCCaaa|||xxxfffVVVHHHQQQWWWkkkLLL```RRR???DDDZZZkkkcccPPPjjjuuu{{{ vvvmmmqqqxxx|||fff^^^^^^gggqqqvvv}}}{{{}}}qqqoooqqqpppqqqtttnnnrrrmmmmmmsss|||qqqfffggggggkkkkkkmmmllluuujjjxxxkkkfff'xxxggg^^^```TTTZZZbbbaaa}}}|||ooottthhhnnnTTTWWWGGGBBB<<<===666333666UUUHHHCCCAAAFFFFFFPPPRRRPPPLLLKKKCCC??????OOOJJJOOOQQQWWWkkk[[[ZZZ```]]]]]]___iiiUUUccc??????555000::://////555...222444,,,---'''%%%!!!$$$###(((%%%"""###'''//////)))///***//////###555"""###%%%...%%%&&&###)))(((...222111((($$$&&&###&&&!!!%%%---+++---%%%)))$$$ $$$"""!!!''''''&&&666000(((...222222888555FFF@@@EEE<<<111,,,DDDZZZcccpppgggmmmzzzpppYYY[[[UUUMMMEEEGGGEEECCCDDD;;;:::111666888CCC444888BBB:::HHH???KKKFFFEEECCCHHHDDD444$$$"""(((777>>>QQQVVVOOO999EEEmmm|||rrrhhhwwwmmmYYYhhhaaaYYYPPP;;;EEEKKK///999]]]ccc\\\OOO\\\ttt}}}qqqsssxxx~~~{{{wwwlllYYY]]]cccrrrvvvnnntttwwwuuuyyyyyyqqqqqqiiifffZZZXXXkkkmmmiiijjj{{{sssxxxooodddmmmppprrrrrrsssyyyrrrmmmooovvvxxxrrrllleee[[[```cccddd^^^gggeeemmmzzzuuuvvvuuu___[[[SSS]]]999111777@@@@@@:::>>>eeeWWW\\\IIIKKKKKKDDDGGGNNNGGG>>>EEEDDDHHHJJJMMMOOOUUU\\\ccc[[[]]]aaa]]]ZZZXXXUUUGGGHHH@@@:::222///333555000555---000------+++))) 555###!!!$$$$$$###''''''%%%444***(((+++:::###***222(((((((((((((((%%%+++)))...(((---000&&&&&&***%%%(((333,,,<<<999'''"""### %%%###!!!"""***///<<<%%%333...'''%%%&&&******222999>>>888555222333FFFPPPuuudddssseeecccSSSQQQRRRLLLFFFAAAAAACCC===???222---111888666333<<>>000999444333222000000000555444666))))))&&& &&&***+++''')))000+++...444222$$$$$$+++&&&(((666))))))&&&(((%%%''':::;;;$$$---///)))000///---111///...+++&&&$$$###"""!!!$$$(((000***111,,,''')))))) %%%&&&---444777222<<>>MMMIIIKKKOOONNN@@@@@@CCCEEEGGGJJJFFFLLLMMMOOORRRUUUWWW\\\``````aaaWWWVVVRRRKKKFFF>>>:::>>>:::777666<<>>777888000---&&&111)));;;MMMPPPPPPddd|||cccIIIHHHTTT[[[iiihhhmmmnnnjjjrrrfffRRRhhhdddZZZYYY\\\bbbPPP]]]xxx |||vvv{{{qqqjjjvvvsss~~~tttvvvvvvxxxrrruuulllnnndddWWW```bbbeeedddiiihhhjjjmmmsssnnnnnnzzz{{{rrrrrr}}}~~~~~~fffaaagggccchhhcccnnngggqqqxxxmmmmmmmmmnnniiitttmmmbbbQQQFFFIIIIIIUUUEEE>>>:::EEEHHHDDDHHHXXXKKKKKKHHHJJJHHHGGGYYYCCC222BBBJJJVVVUUUTTTRRRYYYcccbbb```\\\bbb{{{kkkCCC<<<999888<<<<<<222444333666<<<...+++444///...)))'''%%%$$$''''''!!! ###"""$$$$$$%%%)))>>>+++888888,,,DDD)))111(((%%%***'''(((;;;444+++ )))777...111,,,***%%%((("""888&&&%%%$$$&&&###!!!!!!((($$$"""+++......,,,&&&,,,666///222222111222AAA888AAA]]]VVVOOOSSSWWWeeeiiirrrnnnhhhjjjfffSSSJJJ\\\CCCFFFAAA===;;;:::222666666888:::???GGGHHHEEEPPP@@@???===;;;@@@CCC<<<+++)))&&&444$$$888WWWQQQXXXaaattt___KKKTTT___hhhvvvmmmooogggnnniiiggg ccceee```cccVVVZZZfffyyyyyyvvvzzz|||rrr{{{sssiiixxxyyyvvv|||xxxyyyyyysssnnnpppqqqsssbbb]]]kkkffffffmmmllluuurrrsss'xxxooosss}}}rrrmmmnnnccc______^^^aaa]]]ppp}}} uuuzzzmmmllloooffflllqqqgggVVVYYYMMMIIIeeeNNN@@@???NNNEEEFFF>>>SSSNNNKKKFFFEEEHHHLLLRRRHHH@@@AAAHHHPPPUUUTTT\\\YYYaaa___ccc\\\SSS___UUUAAA999777666888444666333333000<<<555<<<---***,,,+++)))%%%!!!"""!!!$$$!!!$$$&&&)))...+++)))'''(((---...999444777UUU000...,,,&&&%%%333555&&&(((******&&&OOO---+++'''"""???sss...xxx)))%%%'''!!! %%%///,,,))) %%%---;;;//////...111666666888===GGGZZZGGGRRR^^^cccttt{{{uuugggbbb\\\PPP??????999???BBBEEEAAA666555888???999::::::@@@KKKBBBBBBAAA@@@CCCIII>>>777333000000...333===MMMSSSQQQZZZYYYddd]]]hhhuuutttkkkttt{{{lllnnnjjjlllyyy-5xxxaaaeeedddbbbmmmbbbmmmzzztttrrrsssrrrxxx}}}gggwwwmmmkkksssuuuqqqsss}}}wwwvvvwww{{{lllrrrppp{{{uuuvvv~~~ooorrrqqqwwwfffkkknnnrrrkkkjjj pppjjjiiiaaaXXXaaabbbmmmqqq{{{rrrfffaaannnqqqnnneeeTTTRRRQQQNNNNNNMMMTTTCCC???CCCHHHOOOLLLNNNJJJIIIHHHEEEJJJdddKKKnnnPPPPPPRRRNNNVVVjjjeeeiiiWWW]]]fffTTTNNN???===EEE???===LLL...222444000666666DDDyyy<<<(((...---)))))))))"""'''&&&(((***---$$$---&&&444+++111666^^^DDD888)))333:::444---### CCC###)))'''###111%%%(((&&&(((???UUUGGG+++&&&$$$!!!"""'''333&&&&&&&&&$$$333)))***...---+++333666777@@@999;;;DDDTTTOOOTTTcccmmmddd\\\]]][[[PPPMMMAAAPPPOOOGGG:::DDD777444999777777777666>>>CCC======???666444:::888444111,,,---333AAAuuuPPPOOOUUURRReee\\\mmm }}}iiitttvvvjjjeeeYYYaaa|||5oooWWWiiicccfffiiihhhxxxuuutttmmmeeekkkgggjjjkkkwwwtttfffwwwwwwyyyyyy}}}tttrrrpppjjjzzzzzzwwwvvvssshhhlllffflllsssqqq{{{wwwwwwtttxxx|||ssseee___bbbddd```nnnnnnssssss|||iii^^^^^^lllaaaTTTVVVOOO]]]RRRJJJFFFRRRBBBEEEFFFIIIOOOJJJLLLGGGKKKEEEGGGDDDSSSHHHFFFCCCHHHNNNMMMSSSXXX\\\XXXSSSTTTUUUOOOIII;;;888888===:::FFF777888777333666AAATTTpppuuu...,,,******)))((($$$***,,,###%%%)))(((%%%000%%%777444111222===III---)))))):::LLL'''###""""""###%%%$$$((('''((("""&&&111999"""###!!!)))### ###"""$$$"""&&&'''''',,,555+++555<<<333///111===JJJAAATTTJJJSSSrrr~~~~~~llldddcccYYY```XXX<<<>>>MMM999EEECCC===>>>777888<<<999888888BBBLLL;;;:::<<<@@@999:::333333000000333555333999;;;CCCUUUYYYaaaoooxxxpppkkkppp qqqhhh]]]gggggg qqq]]]ddd^^^ooosssooo{{{kkk vvvqqqrrrzzzyyyjjjuuuvvvzzzfffvvv}}} - yyytttooolllkkkmmmjjjhhheeefffhhhdddpppjjjlllooo}}}}}}oooxxx|||tttllliii___oookkkrrrllluuulllhhhzzzooobbbaaa\\\```TTTMMMSSSSSSLLLWWWpppHHH???FFFIIISSSSSSXXXTTTJJJCCCAAA???<<>>777DDDQQQYYYZZZZZZbbb^^^YYYXXXVVVOOO@@@;;;777:::333222888:::999:::AAA@@@???SSSOOO>>>>>>:::---,,,777((()))'''$$$%%%'''###$$$)))&&&222AAA444999///333===???'''------((($$$###&&& &&&$$$((())),,,%%%%%%!!!$$$'''!!!###!!! """!!!)))###+++""""""(((UUU((( """###'''111---///000]]],,,222BBBUUUEEEOOOSSS^^^___}}}6hhhaaaJJJMMM333DDDYYYGGG;;;AAAUUU999;;;666555777555>>>KKK;;;555<<<666BBB:::999<<<999999222111...222------DDD^^^RRRaaavvv |||iiilllooonnngggkkkjjjgggWWW___^^^WWWaaa\\\```cccuuu~~~zzz -~~~ttt -{{{xxxtttxxxrrrwww|||{{{ )fffjjjeeelllqqqxxxooorrryyyrrrssspppxxxrrr{{{~~~wwwllluuuuuurrroookkkkkkcccfffkkklllnnnpppxxxnnnbbb]]]\\\[[[ZZZ^^^TTTUUUVVVPPPLLLLLLIII@@@===GGGNNNLLL[[[pppIII>>><<<===@@@;;;<<>>===888:::AAADDDDDD444;;;777???888000***///---,,,CCCKKKGGG[[[|||yyylllwwwqqqsssRRRssssssqqqhhhxxxaaaLLLPPPaaaeeeTTT___ooo}}}-rrryyywww -zzzwwwttt|||~~~(}}}ppp{{{jjjnnn~~~xxxwww}}}xxxuuuuuuyyywwwqqqoootttxxxnnnmmmnnngggeeekkkmmmnnnmmmsssqqqjjj]]]WWW]]]bbb^^^YYY```cccUUURRRWWWFFFAAADDDDDDHHHGGGMMM___dddSSSEEE999;;;BBBNNNKKKUUU]]]WWWYYYdddggghhh]]][[[YYYVVV[[[VVVKKKNNN888222555888???KKKGGGGGGGGGCCCJJJQQQvvvbbbIII555---...EEE)))%%%""")))(((###!!!%%%$$$&&&+++000555777???;;;222444(((111$$$***$$$%%%###000***(((%%%...***333'''%%%$$$%%%###### )))""")))%%%$$$,,,000"""222+++'''...###'''CCC)))444===>>>:::@@@555888@@@<<>><<<777SSS@@@CCCGGGFFFZZZ)"{{{eeeIII333...888kkkWWWIIIGGGYYYFFFBBB;;;:::???BBB@@@>>>;;;OOOPPPLLL<<<888888===555777???<<<555666000888FFFEEEMMMJJJnnnhhhooosss~~~+TTTXXXjjjlllkkktttzzzwww{{{~~~qqqsssttt{{{qqq{{{  ~~~ ~~~xxx}}}  |||ppp{{{}}}vvv{{{rrrxxx{{{yyyuuukkklllvvvssssssrrrcccccc```iiiuuufffSSSKKKMMMUUUQQQLLLCCCDDDGGGLLLEEEIIIGGGiiiAAA@@@JJJMMMeeeNNNPPPNNNZZZYYYRRRVVV^^^___bbbZZZ\\\NNNAAA>>>:::555888@@@IIIPPP===ZZZ;5ooorrrzzz[[[<<<777000000###$$$%%%$$$&&&&&&***&&&'''+++,,,***...---222555,,,888---999)))&&&...***)))))),,,///&&&***111&&&$$$)))%%%%%%%%%)))"""&&&&&& &&&###'''(((!!! ###"""&&&"""!!!---444ZZZ???444===<<>>OOOXXXuuunnnppp```UUUMMM777999<<<===BBBZZZ;;;OOOBBB???>>><<>>666777999111111BBB@@@FFFQQQbbbiii#}}}PPPeeewww >Fbbbpppzzzkkknnnttt[[[nnntttzzzoooaaa}}}wwwmmmmmmoookkkiiiooo}}}~~~ -|||~~~{{{   nnn||| ssswww|||nnnmmmzzzoootttcccaaaZZZdddSSSPPPSSSPPPQQQIIIYYYJJJDDDGGGPPPLLLOOOAAAJJJVVVUUUPPPJJJJJJRRRZZZ___iiieee[[[ddd]]]\\\mmmaaawww```KKK:::NNN>>><<<===>>>QQQDDD111666AAATTT|||+\\\MMM<<<'''...&&&&&&&&&$$$'''***(((&&&%%%...```444,,,,,,---000,,,...;;;000$$$###888AAA***...111+++---...===$$$$$$&&&)))***###,,,bbb--- '''""""""333((($$$ !!!%%%!!!888666111===777888@@@666FFFBBBBBBCCC333AAAJJJPPPdddUUUHHHEEEAAA999BBB<<<<<<666DDD>>>;;;999555999;;;AAA]]]KKKNNN<<>>QQQTTTjjjBBB>>>FFFGGGDDDDDDIIILLL@@@000999777<<<777666777VVVXXX===UUU888===HHH999>>>777TTTIIIEEE:::555>>>111777888111LLLBBBIIIOOOTTTeeeaaakkkwwwvvvhhhkkkeeeVVVXXXDDD]]]mmmttttttwwwrrrwww{{{~~~jjj[[[ZZZvvvgggiiiqqqqqqmmm||| }}} -  ~~~ ! ||| -}}}ooo~~~gggooooooqqqpppwwwyyy nnnnnnkkkWWWWWWYYYOOOKKKKKKGGGEEEAAAAAABBB???EEECCC???AAA===EEEKKKOOOeeemmmXXXZZZbbb^^^\\\YYYYYYdddWWWTTTQQQPPPWWWoooAAA:::???HHH777@@@>>>KKKcccCCCPPP777WWWjjj???@@@BBB888***---)))%%%&&&$$$###%%%''')))***,,,(((+++...777''')))))),,,&&&((()))+++&&&''')))444555,,,'''***...555888$$$&&&---###'''%%%///CCC<<<777(((333%%%;;;bbb777222!!!"""%%%666333///000777444777<<>>DDDOOOLLLCCCIIIKKKPPPEEE@@@222,,,111999AAA222===999999;;;999AAA;;;777===???NNNFFFEEE<<<666:::111<<<333000@@@FFFUUUOOOVVVmmmxxx~~~|||yyykkkjjjcccNNN===NNNnnnEEEKKK^^^hhh -{{{pppmmmooottt~~~uuufffsssnnndddfff|||{{{www~~~ {{{ - - }}}uuu||| ~~~uuuxxxttt{{{yyysssrrrqqqnnnmmmsssyyyppppppkkkkkkiiiiiiRRRSSSLLLNNNFFFHHHFFFEEECCCFFFJJJGGGNNNHHHAAADDDEEEDDDIIIRRRWWW___[[[aaa^^^```ttt\\\[[[^^^WWWOOOUUUIIIOOOFFFAAA>>>AAACCC===]]]LLLSSSTTTIIIAAA???AAA===222999YYYHHH%%%%%%)))###$$$ ###+++111***))))))(((///,,,,,,(((******------&&&...(((888...((((((222\\\DDD000333QQQ===((("""---+++%%%***///CCC+++%%%!!!555"""000FRRR '''!!!000RRR777666111666BBB<<>>;;;???@@@<<>>999JJJGGGGGG:::>>>AAAAAAHHHTTTRRRIIIJJJFFFCCCJJJLLLWWWaaa[[[___\\\cccYYY\\\WWWYYY```ZZZYYYJJJEEEIII@@@:::BBB666888???@@@BBBBBB:::444???TTTPPPuuu111)))&&&)))+++(((&&&%%%$$$%%%###+++***+++---444+++&&&)))666'''&&&&&&)))%%%%%%###%%%333888%%%'''777000---111...)))<<<... """+++===---))) ######"""###%%%:::&&& ,,,===//////XXX???;;;===EEEJJJMMMOOOYYYEEEHHHEEE^^^UUUXXXeeeHHHCCC444666:::AAA333%%%000888@@@???PPPhhhDDD666222888333===222999===888777555999555===888777RRR???;;;CCCQQQfff|||ooommm[[[lll}}}uuu{{{~~~vvvlll[[[RRR===VVVRRRZZZTTTVVV[[[ooohhhoooVVVVVVHHH^^^zzzvvv~~~kkklll~~~rrr{{{{{{vvv{{{}}} -}}}~~~{{{zzz{{{ooogggeeefffeee___ccc -wwwggggggtttnnn}}}vvvhhhttteee___bbbcccXXXUUUUUUUUUSSSNNNUUU___YYYNNNIIICCC:::@@@BBB888222888@@@HHH]]]JJJLLLMMMRRRPPPQQQTTT^^^YYY\\\ZZZhhh^^^gggbbb[[[RRRVVVkkkUUUKKKMMMFFFFFFMMM???<<>>///)))222333AAA;;;;;;???===555333;;;===DDD777;;;:::222333222999333;;;>>>777CCCHHHQQQ:::===MMM iii___TTT[[[}}}uuutttsssSSS666FFFFFFUUUVVVUUUSSSdddddd]]]nnn^^^EEE===FFFRRRtttpppjjjqqqzzzvvv|||~~~sss{{{ zzzpppiiihhhdddfffhhh]]]ccchhhhhhsssnnnaaafffaaa\\\iiinnnddd]]]bbbNNNWWWQQQVVVUUUWWWRRRbbbTTTQQQKKKGGGPPPFFFCCCFFFBBB===888<<>>+++&&&### """%%%''',,,333***111000111222888000---$$$;;;)))%%%%%%""""""EEE###$$$###!!! """ &&&###000------((((((444555KKKIII___@@@DDDEEEKKKTTTGGGHHHUUUXXXXXXQQQTTTcccMMMOOO888((((((...<<<444333;;;NNN666333444777>>>@@@???666333111666555666555BBB@@@;;;:::333666888???NNNsssrrrUUUpppaaannnuuussszzznnnFFF777kkk___lllVVVPPPdddyyyjjjfffIII222DDDKKKnnnffffffxxxsss}}}xxx~~~{{{www}}} uuullljjjkkkqqqhhheeehhh\\\gggccckkkaaaddddddrrrxxx xxxmmmoooqqq[[[WWWbbbttt___PPPOOOOOOUUUSSSYYYKKKDDDGGGJJJIIIFFFHHHFFFHHHNNNMMMTTTBBB===HHHUUUQQQIIIKKKQQQYYYeeeccc^^^ffffffccchhhaaa^^^^^^YYYiiiQQQQQQDDDDDD;;;:::@@@>>>AAA888???AAA===HHH555222???000333111***&&&***---///,,,))),,,))))))...))):::******((((((;;;)))''''''+++)))***!!!"""'''555'''///"""$$$((('''&&&...---,,,---...555???111:::"""'''%%%$$$"""+++777"""<<<&&&!!!!!!%%%!!!$$$###---,,,==='''444999999555111555888@@@EEELLLAAABBB\\\VVVLLLppphhhKKK))))))AAA...000...JJJ===333444555555444444>>>IIIGGG999666555777444888777===777666111:::999HHH^^^EEEZZZ{{{^^^hhhuuuvvvzzzmmmkkkRRREEEZZZ'jjjdddbbbaaakkknnnSSSFFF888<<>>???777+++...,,,111333666))),,,%%%******---***(((---)))...000(((---666)))(((&&&$$$***&&&222'''%%%333%%%"""%%%%%% $$$%%%"""%%%111---...)))(((%%%:::***'''"""!!!"""$$$ ,,,[[[""" $$$ %%%&&&(((///,,,KKKKKK777///111555AAAFFFEEEHHHHHH\\\ vvvuuu -\\\777'''&&&***)))111:::<<<@@@111---333333555;;;>>>???===...///777111000BBBHHH777>>>...777<<<@@@CCCcccSSSZZZ```jjjhhhvvvppppppbbbUUUVVV -oooiiieeecccvvvnnnuuuWWWTTTAAA444AAASSSVVVdddRRRTTTiiijjj{{{ttt~~~rrriiieeemmmeeehhhkkkffffffXXXTTTsss[[[UUUXXX^^^YYYTTTKKKOOO^^^\\\ZZZYYYSSSSSSQQQMMMWWWHHHJJJkkkeeeeee\\\RRRNNNXXXXXXTTTNNNKKKOOOIIIMMMFFFGGGFFFGGGMMMhhhZZZ^^^qqqjjj```bbbaaagggfffaaaVVVSSSUUURRRLLL???===888888::::::JJJ;;;888===;;;555---,,,...333444333///...333222///---:::(((***+++...***+++)))sssHHH((('''$$$%%%&&&&&&,,,###'''""" $$$!!!###%%%''''''BBB===XXX===+++111'''%%%,,,***$$$ ###!!!(((YYY%%% ###&&&''':::CCC222666666888???zzzSSSMMMOOOYYY~~~oooppprrrvvviii<<<,,,***///(((!!!333000222444333---666444777<<<<<>>IIILLLRRRLLLYYYiiiuuuddddddppphhhWWWaaaYYY222222+++...&&&&&&...111///000444666888;;;EEE999555CCC)))222;;;BBB:::555111...666:::===GGGVVVUUUSSSjjjYYYcccwwwtttpppoooppptttVVVNNN___XXXkkkbbb\\\~~~[[[XXXdddIIIhhhjjjpppeee^^^YYYLLLJJJFFFKKKiiieeejjjmmmfffYYY___pppssssssiiinnnkkkmmm =qqqiiilll___YYYUUUIIIFFFHHHNNNfffgggVVVJJJDDDCCCBBB===VVVKKKOOOOOOIIIOOOPPPRRRUUUNNNTTTZZZTTT[[[YYYQQQPPPKKKKKKCCCBBB:::JJJRRRPPPPPPXXX]]]]]]___qqqeee\\\YYY\\\XXXKKKAAABBB>>>AAA[[[444:::777:::222222CCCDDDLLLGGGLLL;;;888444333---(((+++333444888000((()))***---)))++++++'''&&&'''&&&'''OOO)))$$$"""'''&&&&&&%%%%%%###!!! """******///QQQQQQ///111(((000555BBB+++222"""### $$$&&&###### '''000'''...@@@@@@EEEMMMFFFCCCJJJ\\\QQQHHHLLLXXXggguuuhhh^^^QQQdddXXX999&&&$$$"""*********VVV444:::'''&&&...111777111888555AAA555111333666888???222444444:::>>>CCCVVVZZZXXX???JJJXXX```pppnnnyyybbbYYYUUUaaaSSS\\\gggggg[[[nnnKKKQQQKKK]]]aaafffeee\\\YYYfff@@@LLLKKKLLLsssXXX[[[aaaYYY\\\bbbeeelllrrrpppoooqqq ~~~{{{]]]bbb[[[[[[SSSRRRJJJQQQKKKQQQTTTQQQZZZGGGEEEIIIDDDMMMZZZUUUXXXZZZTTTTTTccc]]]bbb\\\XXXddd___XXXUUUOOOOOOVVVVVV```WWWNNNJJJQQQ\\\bbbdddhhhwwwrrrnnnbbbWWWSSSIII@@@>>>===:::888AAA888111888666333888AAAUUU>>>BBB<<>>000222######"""!!!###(((,,,***...000CCC@@@LLLOOOJJJPPPSSS^^^DDDFFFVVVsssTTTNNNUUUDDDEEEGGG<<>>HHHNNNPPPHHHJJJFFFNNN]]]dddfffjjjnnngggPPPZZZYYY```WWW___bbb___ddd___]]]VVVmmmrrrhhhVVVWWWOOOJJJ???TTTKKK???MMMRRRWWW___RRRVVVYYYcccdddaaaaaaooo -hhhlllZZZPPPPPPSSSPPPFFFOOOSSSMMMMMMMMMQQQEEEDDDVVVNNNOOORRRPPPSSSYYYYYYUUU]]]```ccccccjjj[[[]]]YYY^^^eeeRRRVVVdddnnnddd]]]PPPRRRiii```]]]aaammmdddiiiVVVSSSFFFIII;;;===999444555OOO666///888333000888]]]III@@@PPPNNNDDD:::555000888---))))))......,,,...&&&###)))(((''',,,'''###$$$!!!!!!$$$ )))%%%)))&&&%%%%%%"""$$$&&&###...///111111---)))***666333111333555[[[000$$$!!!!!!%%%!!!111######+++))),,,+++(((+++111JJJ@@@CCCZZZGGGTTTXXXQQQKKKNNNOOOWWWfffhhhSSSCCCGGGKKK??????888666???555QQQ(((---444222000666///111999000333222***---000:::>>>555:::333CCCAAA>>>KKKHHHNNNGGGIIIDDDPPPmmmlllbbbfffiiigggcccTTTWWWVVVYYYWWWXXXiii|||iiieeecccddd~~~^^^FFFrrrkkk///@@@@@@TTTWWWYYYXXXkkk```RRR___^^^bbb```dddlllttttttnnn```ZZZEEELLLOOOSSSBBBPPPmmmlllSSSLLLBBBFFFKKKVVV^^^[[[WWWRRRggg\\\aaa[[[```[[[ccceee___YYYWWWjjjzzzlllYYY^^^eeemmmyyytttVVVjjjggg\\\\\\aaaWWWRRRIIIJJJEEEEEEEEE???444------,,,+++444>>>222444555333333>>>555FFFBBB777@@@]]]555555///111...---+++///'''$$$%%%'''&&&''')))%%%'''$$$$$$"""&&&$$$''''''+++'''---***###'''&&&///FFF888CCC...222666999999===>>>000&&&$$$$$$$$$))),,,%%%''' &&&111)))### $$$%%%)))$$$))))))000???111XXXBBBKKKLLLUUUUUU^^^FFF???```kkkWWWTTTQQQNNNOOOEEEQQQAAAFFFMMMCCC"""###...000,,,***000)))///)))///,,,333...000333999222999KKKLLLdddCCCBBBTTTSSSGGGCCC>>>LLLdddmmm]]]eeegggjjjooo```PPP@@@BBBBBBPPPbbbppppppkkkrrrqqq[[[UUU\\\YYYrrrYYYAAAEEE888XXXhhhJJJEEEUUUiii]]]TTTXXXiii]]]ddddddvvvppp}}}sssiiioooSSSCCCMMMPPPWWWHHH}}}SSSfffXXXTTTQQQTTTPPPTTTjjjjjjwwwdddiiihhhiiiTTTmmm\\\mmmdddeeebbbvvvyyyjjj^^^vvvqqqjjjiiidddiiiiiigggVVVPPPCCCEEEAAAIIIJJJMMMQQQDDD222222...111......777:::777333999>>>777999333===999;;;111666111000*********...&&&***333((()))'''&&&$$$ ######$$$!!!###'''+++((()))&&&$$$&&&$$$!!!###***NNN@@@999222@@@---OOO@@@......''''''333---### &&&$$$:::999===!!!+++ $$$:::888%%%&&&---333BBB^^^222<<>>FFF???III[[[YYYUUU\\\VVVIIIGGGKKKNNNXXXRRRdddiiijjjdddSSSPPPRRRTTT___QQQ\\\TTTQQQXXXWWWUUUVVVWWWWWWWWW```^^^bbb]]]XXXZZZeee``````hhhfffcccooo}}}xxxvvvrrrsss|||qqqtttuuusssmmmcccdddKKKMMMTTTIIIIIIHHH___fffTTTEEE333111222444777222777:::555444,,,999;;;999:::000111999000,,,...---***;;;...***"""###+++)))---)))###%%%%%%(((%%%'''***)))+++&&&%%%""" ###""""""!!!>>>((())),,,***,,,444&&&---,,,===---===KKK"""%%%!!!'''+++ ))))))***&&&))),,,222888;;;===;;;IIILLLLLLJJJTTTSSSPPP[[[VVVFFFMMM\\\QQQTTTOOOSSSDDD@@@===::::::III111111(((!!!&&&///+++,,,---444222666222000222111000333111111555222999AAACCCKKKIII]]]444444999FFFOOO^^^lllZZZZZZRRRKKK<<>>///KKK[[[ggguuuYYY\\\bbb___UUUMMMHHH@@@ ===FFFSSS[[[UUUYYYQQQ???JJJIIIOOOOOOQQQSSSQQQ^^^gggYYYXXXRRRVVVSSSOOOSSSSSS^^^^^^```]]]\\\bbb^^^\\\YYY^^^^^^ZZZZZZ[[[```cccaaadddmmmgggjjjooouuuuuuzzzyyyyyyqqqnnnsss}}}rrrkkknnn]]]PPPLLLJJJKKKLLLHHHPPPJJJDDD999111444AAA777BBB555555444222333444777999===777333222444333...222555,,,000333)))+++$$$&&&&&&%%%===,,,&&&''')))###)))+++***///%%%%%%######'''333&&&""" '''000222&&&...---)))%%%,,,///"""NNN@@@""" """$$$### 888&&&(((%%%)))===>>>>>>AAAGGGMMMGGGUUUVVVNNNPPPSSSHHHiiiKKKHHHTTTOOOVVVdddTTT===:::;;;;;;;;;GGG777777HHH&&&###!!!$$$"""...000666333222222222222111222111222333,,,999FFF;;;<<>>===[[[CCC555555888777111444CCC;;;>>>===888999333444CCCccc{{{::::::JJJ***,,,$$$+++(((""")))((("""&&&&&&###(((///%%%)))'''$$$((('''+++,,,(((<<<)))***888222'''***'''&&&,,,%%%000444'''"""%%%(((+++ ######"""!!!$$$"""!!!"""###%%%$$$)))999===DDD;;;GGGFFFSSSTTTWWWKKKMMMTTTRRRPPPPPPIIITTTLLLLLLJJJDDD===;;;GGG===;;;BBBwwwUUU***###...$$$(((,,,222...555444333444>>>KKK555555>>>555333999;;;===NNNCCC444333***999555333;;;777>>>GGGFFFPPPiiiVVVTTThhh@@@NNNGGGUUUUUUVVVQQQPPPCCCEEEGGGTTTXXXXXXVVVPPPSSSNNNMMM```>>>999>>>KKKbbbppp|||'\\\HHHdddYYYWWWVVVOOOSSSddduuunnnXXXcccddddddgggccccccbbb\\\aaa______UUUaaaaaa___```ddd```\\\uuuuuukkkeeeeeesssrrreeeddddddjjjhhhgggkkkfff]]]QQQMMMaaaPPPTTTkkkCCC888888EEE===???III>>>555999555///777:::555HHHEEEIII;;;999===555444000555///---000)))''',,,***+++'''222+++(((&&&%%%$$$)))jjj%%%)))+++(((((($$$)))''')))???***...***%%%''')))'''&&&(((''',,,333 %%%888&&&$$$###!!!  ***###((($$$%%%000XXX@@@333KKK@@@IIIAAAMMMHHHMMM]]]VVVXXXNNNKKKVVVAAA@@@@@@@@@DDD===333333<<>>JJJgggVVV999:::777555333333@@@444222BBBCCCFFFHHHAAA@@@FFF///...---222222,,,+++&&&"""%%%)))%%%,,,)))$$$"""###$$$$$$###(((///(((###$$$''''''&&&&&&'''+++---***,,,''')))222$$$!!!###'''###!!!+++$$$ $$$%%% ,,,%%%(((***'''+++(((--->>>EEEBBBRRR666===000;;;IIIXXXFFFNNNPPPPPPDDDHHHBBBCCCLLLCCC===;;;<<<888???PPP===###'''((($$$%%%,,,KKK///)))%%%---...111222111...+++---111888444333vvvPPP===HHHEEE<<>>999EEEBBB:::999>>>=========bbbAAAEEE<<<444333111+++//////===,,,///&&&$$$***+++%%%)))(((###!!!  '''+++>>>000$$$)))''''''&&&'''***---+++######(((&&&###"""!!!(((((()))"""!!!!!!""""""!!! !!! $$$""" """%%%)))***000888:::EEE===444555222555EEEIIINNNHHHNNNJJJVVVCCCBBB>>>EEECCCEEE:::@@@===GGGJJJ333,,,(((###%%%...,,,%%%...&&&''')))---***)))333222)))%%%---888333,,,222III???CCCJJJ888;;;ddd;;;:::111222666GGGGGGIIIJJJKKKVVVgggXXXWWWYYYSSSPPPQQQNNN___]]][[[qqqtttuuuddd[[[VVVTTTEEEDDDDDDHHHUUUOOOlll " {{{ccckkkUUU^^^ooo```]]]YYYbbbfffgggmmmhhhgggqqq mmm^^^^^^ZZZ]]]hhhiiipppmmm}}}eeecccmmmaaaeeeaaafff___fffcccYYYPPPVVVRRRHHHNNNLLLRRRNNNQQQFFFFFFFFFIIIDDDGGGGGGxxxwwwhhhbbb___[[[EEE\\\zzz@@@@@@<<<>>><<<:::;;;JJJ555//////---555444///...---444,,,222(((%%%$$$'''"""!!!!!!"""!!!""",,,******444&&&(((%%%...---777***,,,***$$$&&&$$$&&&&&&&&&###$$$000((($$$%%%!!!&&&%%%### $$$555&&&@@@999"""'''###'''---///111===777111444999999@@@JJJIIISSSRRRJJJHHHZZZBBBIIIAAACCC???CCC:::>>>999===333...---///,,, &&&!!!###'''###$$$'''***)))///666...''''''<<>>AAAAAAAAAEEECCCMMMWWW~~~UUUEEEEEE<<<>>>666999777<<<;;;IIIDDD444111111111555111///;;;///;;;,,,$$$!!! !!! &&&,,,111222555---<<<,,,***))),,,???---((('''###000&&&***$$$%%%$$$%%%...???((("""&&&777$$$&&& ###((($$$&&&'''***,,,...444???555LLL@@@===:::OOOOOOKKKMMMMMMKKKDDDCCCNNNGGGCCC>>>JJJIII999888AAA555111777777```...+++%%%###$$$###$$$%%%(((:::)))///...###)))+++<<>>444FFF>>>999???;;;:::888;;;,,,DDDRRRIIINNNGGGUUUVVV___YYY___NNNXXX[[[MMMWWWZZZXXXbbbaaa\\\___LLLUUU^^^TTT```iiicccaaagggsssXXXbbbiiirrrjjj\\\nnndddwwwyyylllbbb[[[KKKRRRYYYhhh```hhhmmmttt\\\[[[nnnlllkkkkkksssnnngggTTTZZZQQQLLLUUUSSSVVVgggKKKJJJSSSLLLNNNNNNKKKIIIFFF@@@XXXGGGBBBFFFEEEFFF>>>DDDXXXDDD===ccctttOOOGGG@@@???999======>>>IIIAAAIIIDDD===111:::888///222444EEE******+++"""((("""&&&%%%(((///333+++222222GGG---))),,,)))***+++&&&+++%%%)))''')))$$$$$$!!!)))111>>>###%%% !!! ###!!!$$$###---111)))888FFF@@@DDDNNNFFFFFFEEEFFFXXXEEEPPPMMMaaaZZZIIICCCFFFHHHDDDCCC<<<>>>LLL888555FFF222...222666>>>&&&'''###))))))###%%%///,,,444111)))$$$(((GGG777???@@@===999555DDDAAA777???HHHOOOBBB999IIIDDD999@@@KKKAAARRR[[[gggTTTOOOMMMHHH???IIIQQQ^^^^^^^^^[[[___]]]LLLSSSNNNTTTaaaRRR]]]TTTbbbmmmyyyggg^^^KKKVVVrrrpppMMMVVVJJJBBBVVVFFFJJJNNNWWW___]]]```^^^aaadddWWWWWWVVVkkkgggccciiiccc```bbb```QQQQQQJJJGGGGGGEEEEEEKKKJJJPPPLLLMMMIIIFFFCCC:::>>>FFFJJJOOOPPP^^^VVVOOOFFFFFFFFFEEE555@@@IIIDDD@@@GGG<<<===999AAAAAAGGGEEEttt===AAA777666___[[[DDD)))***+++'''$$$ +++555%%%***"""(((,,,bbb111---)))///---,,,)))'''---...... &&&###(((111(((&&&###(((!!!"""&&&!!!'''!!!""" %%%*** ,,,...)))444333<<>>EEE333<<<,,,'''***$$$%%%###+++111...'''+++000???666666<<<===777<<<@@@;;;>>>DDDDDD<<<===DDD///555666HHHEEEDDDFFFIIIGGGTTT[[[EEEDDD===LLLPPPNNNOOOOOORRROOORRRIIIHHHNNNRRRJJJRRR``````QQQmmmaaaOOOXXXccc~~~~~~sssXXXEEEJJJ???NNNLLLVVVGGGQQQQQQZZZZZZXXX[[[qqqccc[[[ZZZ___dddWWWVVVQQQNNNRRRJJJHHHCCCIIIJJJFFFBBBBBBAAAFFFEEETTTNNNDDDFFFNNN444EEERRR___~~~mmmXXXOOOXXXJJJLLL???DDDBBBOOO@@@EEEEEEFFF@@@888AAALLL>>>???GGGnnnTTT;;;666===222***......***&&&&&& ### !!!<<<&&&!!!***JJJ...555+++(((((('''((('''$$$000AAA((('''444222ccc111+++,,,---,,,'''---"""%%%&&&333###+++!!!---111222!!!###&&&%%%$$$999>>>:::NNNYYYSSSDDD:::LLLTTTIIIOOOIIIHHHJJJPPPFFFQQQNNNMMMDDD>>>BBB>>>999///DDD///444%%%///,,,///***!!!"""%%%...,,,'''))),,,444333555<<<@@@;;;777:::AAADDDBBBAAA;;;^^^ZZZ999GGG>>>BBBGGGEEEUUUKKKGGGSSSPPPZZZKKKMMMUUU===IIIJJJKKKPPPPPPSSSUUUNNNJJJTTTSSSZZZZZZ]]][[[SSSJJJNNNddduuurrrvvvbbbZZZRRRXXXGGGUUU[[[OOOTTTEEEAAAaaabbbmmm^^^___hhhddd[[[WWWRRRTTTQQQKKKJJJEEEFFFBBB===@@@JJJBBBCCCBBBAAA???SSS===CCCJJJEEE>>>444PPPccc'nnnWWWNNNHHH>>>BBBCCCFFF???BBBEEEKKK888CCCGGG;;;DDDQQQ:::999cccQQQBBBHHHCCC000///***+++...&&&&&&!!!### 000888999222***((($$$)))...'''&&&&&&---''')))***---777+++---222)))666WWWooo333,,,%%%...+++%%%'''!!! !!!!!!### >>>,,, (((******"""!!!!!!***++++++333666DDDOOOOOOFFF???FFFPPPNNNPPPPPPXXXQQQIIILLLYYYGGGMMMCCCCCCJJJ;;;888444...(((333)))111999***---$$$ &&&...''')))///555666666:::@@@:::555:::888>>>===@@@===EEEQQQ]]]999222999CCCEEE@@@MMMHHHKKKNNNUUUFFFIIIAAA999///999AAAIIIIIIMMMQQQKKKKKKPPPfffUUUGGGhhhSSSGGGEEEKKKEEE===NNNiiieee\\\gggdddYYYRRRPPPWWWUUUOOOLLLHHHHHHRRRRRRUUU\\\ggg]]]]]]\\\PPPJJJIIIDDD??????QQQTTT666<<<@@@<<>>===:::;;;<<>>???AAA777333XXX111***000EEE---(((,,,&&&((("""(((III---)))''')))&&& ###((((((&&&&&&+++&&&((((((,,,&&&555///,,,((((((000666444000+++((($$$%%%$$$ %%%!!!$$$$$$ '''###"""###$$$(((111,,,000999AAAAAA@@@MMMFFFMMMKKKHHHHHHMMMMMM[[[ZZZPPPwww PPPAAA:::>>>:::CCC>>>///000***&&&///...,,,++++++""" ---******000BBB777777888;;;;;;888222///;;;???999@@@IIIJJJkkk===)))***555EEECCC@@@KKKDDDGGGVVVJJJ@@@999333222777AAA???DDDEEEMMMNNNMMMMMMPPPLLLNNN[[[OOOQQQjjjDDD777@@@OOOFFFFFFJJJQQQQQQOOO[[[UUUJJJPPPKKKQQQNNNDDDDDD===LLLQQQVVVSSSSSSfffMMM???BBB???888CCC777???999777444888999AAA;;;CCC;;;:::===???:::;;;222GGGMMM```HHHWWW___JJJ???===EEE@@@444VVV@@@000000222555333<<>>;;;IIIOOOGGGIIIXXXHHHNNNIIIMMMOOOLLLBBBGGGUUUQQQKKKEEE>>>FFFFFF???888222///111,,,111666;;;;;;111...&&&$$$!!!((())),,,???;;;EEE777666777<<<;;;666UUU///:::EEEMMMCCCVVVIIIaaa???000%%%000OOOSSSKKKFFFHHHIIIFFFMMMZZZ???222---111@@@HHHNNNAAA999@@@PPPVVVCCCJJJIII???FFFJJJUUUGGG???===555666333EEEDDDFFFPPPWWW>>>AAA>>>BBBAAAAAAGGGEEEGGGNNN```PPPPPPZZZ\\\EEE===>>>======>>>888???777111777999444>>>AAA:::NNN@@@444:::>>><<<<<>>@@@OOOCCC...000***###222111222 """###"""***(((""""""''')))&&&''''''$$$'''+++...===HHHIIICCCHHHCCC???LLLOOOLLLLLLPPP@@@FFFWWWeeeLLLDDDBBBSSSPPPHHH>>>;;;999333333...AAAOOOmmm:::***%%% ###...111MMMRRR@@@KKKUUU???555:::>>>777@@@---,,,TTTOOOMMMGGG???>>>///&&&...999CCCFFFMMMFFFUUUIIIVVVhhhBBB444666:::AAA>>>===888LLLmmm3WWW<<<999===888@@@@@@EEECCC;;;CCC<<<===???AAA???NNN@@@EEE>>>999:::000777DDD<<<===CCCFFF>>><<>>:::666<<<======777222333999777888>>>:::III888UUUAAAIII???>>>???===BBBMMMMMM```KKKMMMAAAAAAHHH{{{@@@999999777555===---111222333000,,,------,,,,,,CCC,,,KKK444???555$$$###### """'''!!!""""""'''$$$(((+++###!!!###444...+++)))(((...777BBB333///444BBB777222666555+++---,,,VVV[[[...&&&$$$###!!!"""  $$$===$$$$$$***"""%%%"""$$$###,,,,,,///FFFBBB<<>>......+++,,,)))999QQQ@@@@@@]]]iiiVVV///444BBBAAA>>><<<777HHH^^^\\\eeeIII@@@AAA444 (((111===CCCZZZHHHJJJ```]]]WWWHHH;;;888<<>><<<<<>><<>>777999888III:::999666888666@@@777<<>>;;;:::@@@EEEUUU333000///***...333,,,HHH666333333///999:::HHH===...888$$$)))"""!!!""""""000""""""<<<\\\%%%%%%###///000+++'''+++444444:::DDD>>>:::iiiWWW@@@===666...,,,333111((()))///'''))) '''"""%%%!!!&&&$$$///""" %%%###""""""&&&%%%///...444PPP;;;888BBBJJJBBB;;;:::GGGBBBFFFDDDDDDFFFCCCLLLCCC???III@@@GGGbbbsssDDD@@@NNN999333:::CCC;;;000AAA555777,,, $$$:::GGG999===999777OOO333666:::HHH===:::666:::CCCFFFCCCBBB===EEECCC%%%'''666<<>>NNNIIINNNEEEAAAFFF@@@JJJBBBFFF???ZZZ[[[aaaFFFGGGYYYLLLSSS???999555888EEE666111000+++000888888666333......---111@@@777333333111&&&&&&### ###"""###&&&;;;777222&&&//////111(((,,,000444KKKMMM888???oooiii777???PPP>>>;;;FFF111***---...&&&)))""" )))CCC999EEE'''"""!!!"""!!!***%%%"""!!!%%%$$$222...666666333888>>>^^^MMM===NNN666;;;AAADDD@@@<<>>999;;;888222333---...###...666777888888111222888222111333WWW===:::888SSSSSSBBBYYYSSSIII777222$$$%%%777DDDEEEFFF:::CCCUUUMMMfffHHH===999===EEEKKKAAA444222===>>>444333000,,,<<>>000JJJ:::///444...000555...,,,'''SSS111555777000******$$$!!!!!!'''((((((%%%''')))(((------------111(((444888333777000---;;;<<<```BBB888///KKK111,,,000;;;AAA------&&&((( ######$$$###,,,'''###'''(((,,,"""!!!&&&%%%)))'''&&&(((999??????>>>???EEEiii555888>>>DDD<<<<<<===<<>>PPP333999///777666222000777GGGUUU======000:::)))...///'''222***111%%%,,,###&&&$$$"""!!!"""((( ''')))###$$$ $$$888///(((555@@@KKK666888BBBPPP;;;777999999;;;>>>BBB:::BBBQQQWWWIIINNNIIIQQQ>>>:::KKKDDDFFFMMM777444555:::222888,,,$$$###%%%***---111444@@@:::555AAA===555999777===DDD;;;888999OOOUUUzzzCCC111******'''333:::III[[[SSS>>>SSSqqqKKKLLL999111333//////<<<;;;111999BBB555;;;///)))555@@@ }}}BBB===---,,,///666,,,111000555666222666111111777555333888;;;555999;;;<<<===222666333222555666<<>>OOOCCC<<<<<>>888>>>777IIIccc~~~WWWBBB>>>GGGAAACCCDDDAAAFFFFFFNNNFFFFFF???:::222;;;...$$$'''###'''///777999;;;888AAADDD888::::::CCC===...111111///777CCCLLL000???...***+++---;;;AAAIII999===UUU```HHHRRR@@@///333---333000888555444555333999777111888<<>>888999111777999222999//////111111///---555===333;;;:::444888:::333;;;777333666111...000666444777333999:::444555:::222:::AAAEEESSS>>>???@@@@@@999<<<<<<===DDD@@@;;;999888777CCC;;;999FFFOOOHHH888777...---,,,---+++,,,)))888777333333999///444000PPP<<<000888000999777:::DDDbbb<<>>,,,888888:::???888===999888777>>>222666111333222222@@@LLLXXX -\\\FFFDDDFFFDDD@@@===;;;444BBBKKKYYYJJJ888GGGbbb555---000%%%$$$&&&///222EEE999222444HHHMMM<<<888888444???===:::OOO444CCC666333,,,+++'''***@@@CCCFFF777888>>>BBBSSSHHH<<<:::333222777888:::444000888444555;;;===@@@iiilllSSS<<<555999222...---...000///,,,...111222222,,,222666999555<<<444333444111===444555000111111222444000666===^^^RRR;;;<<>><<<,,,...111222111///555XXXYYYcccIIIGGGQQQQQQRRRCCC:::>>><<<>>>bbbSSSJJJ:::555***...333555222***$$$(((%%%111333...111...333===GGGDDD===<<<888777===000777666111>>>333,,,***,,,AAACCC999BBB:::;;;:::JJJpppNNN;;;333555999222777222:::;;;---000555333444:::EEEDDDKKKVVV///222555---222FFF222111---333333///...BBB555:::555---111666======777666333444000333333///555===888===EEECCC;;;:::222;;;:::???CCCCCC<<>>DDD|||===777///111+++777===&&&*********666***###...%%%)))"""%%%]]]###!!! ###KKK444222>>>>>>$$$<<<<<>>??????BBB777<<<888222999333555...///+++999yyyCCCJJJQQQXXXJJJBBBEEEMMMNNNAAA???ooolllWWWOOO666+++333---333:::000...+++'''...111111,,,---000===@@@MMM???BBBDDDAAAFFF555;;;666BBBKKK>>>@@@333GGGIII555***...000666<<>>000BBB333000,,,///,,,444000333111000555333666666888000000111===LLLXXXEEE===555444///111222888555>>>888MMMMMM>>>===>>><<<888;;;555999>>>:::@@@999999444777FFF...---+++555777???RRR333777444QQQ;;;:::@@@aaa;;;===555777888ggg777FFF^^^@@@777ZZZOOOCCCAAA===<<<999999DDD???===555444OOOUUU<<<555000***(((&&&888444999...555222888333...111...111888000+++<<<...000OOOHHH###333,,, )))$$$///@@@+++ """>>>UUU555:::///)))((((((333++++++555777///...333000000///333///+++111DDDIIIHHHJJJTTTkkkFFFIII___IIILLLHHH]]]CCC:::222***,,,,,,222???999222)))((('''+++...000//////666555<<>>DDD@@@OOO>>>BBBXXX@@@555999888+++777333888888>>>555AAA:::;;;999***,,,???===888222NNN???>>>888>>>777@@@kkkWWWDDD@@@===<<>>AAA???>>><<<444666;;;444;;;888777888777<<>>000777555000LLL@@@222---///333===999222000***444===LLLHHHddd000((('''000!!!$$$(((888&&&%%%###"""&&&&&&)))000***+++000,,,333444...111222444***)))///FFFIIIBBBBBBCCC@@@EEEBBBGGGBBBJJJNNNBBBGGGFFF???999111>>>///BBB333III:::555111((()))(((+++444///CCC222666HHH@@@FFFBBB;;;>>>GGG>>>JJJ===PPPNNNKKK:::999LLLRRR888111'''...===EEE;;;GGG@@@999???:::::::::999===888???MMMAAA333999555999\\\KKK===>>><<<666888///888>>>999666444555;;;666333777<<<222---222222:::@@@<<>>IIIRRRKKK:::???666000666222---222<<<666444000))),,,)))'''111===???(((...000222...///???JJJ888999@@@===222+++,,,---888000---'''AAA,,,AAAWWW;;;;;;###'''%%% !!!!!!"""]]]***'''$$$)))(((,,,###&&&------222HHH111???222444---===222@@@***444>>>>>>???<<>>999<<<<<<666999@@@>>>BBBLLL>>>@@@???___===>>>:::888>>>===666999999:::666:::BBB???333>>>666222777222222:::444<<>>000---111555666>>>nnnKKK888GGGDDD;;;999>>>===000222777000222666///@@@666DDD333777<<<;;;333HHH666)))...GGG---444999222888...222222///222:::111444===,,,777999333<<<;;;MMM444333999666---DDD;;;:::///&&&(((''')))))))))((()))---111000---000999@@@FFF111111000III---***///666///'''555<<<>>>>>>~~~\\\+++((("""!!!!!!"""&&&===...&&&$$$$$$000&&&000333///---111000...///222333******(((---666===MMM===<<>>BBBNNNAAAPPP888000555NNN666333222((('''###"""+++///333FFF===999<<<:::<<>>@@@999CCC:::CCC===>>>===AAAFFFGGGBBBAAAOOOGGGJJJ@@@FFF===???MMM999555555<<>>:::@@@666666===888999999666777>>>@@@888:::222444111666BBBDDDJJJ777666nnnccc>>>555>>>???666555QQQqqqQQQ>>>333CCC222999333666999KKK222999555555222111222...222(((%%%&&&'''///AAA666BBBAAA<<>>FFFRRROOOZZZJJJkkkQQQMMMIIIXXXIIIDDD...111555666444111$$$***%%%!!!...+++000222555666444NNN555999CCCEEE@@@999;;;JJJ===BBBMMM...&&&000,,,000222...)))555111111444555333===DDD999NNN:::>>>:::<<<@@@JJJ===>>>XXXFFFDDDDDDEEEKKKAAA>>>@@@DDD<<<;;;;;;KKKDDDDDD======QQQ:::<<>>@@@888CCC@@@:::666888,,,'''(((,,,---IIIBBB)))///***...<<<666///>>>BBB444888777000)))---111,,,:::000+++--->>>222///GGG""""""$$$"""DDD%%%$$$"""%%%&&&&&&***:::***444555BBB...222000000***,,,333777<<<:::???FFF@@@GGGUUUYYYhhhXXXKKK[[[UUUsssOOOFFF@@@@@@KKK222<<<888555;;;SSSEEE444888000,,,...222444666777EEEYYYXXXpppnnnGGG===666;;;<<<333444111)))888333:::222///(((---((()))111...000111888888;;;444::::::???JJJ>>>???DDDEEEEEE<<>>>>>888:::@@@FFF;;;<<<>>>888999777PPP444///???KKKGGGBBBEEEDDD555888333???000333777::::::;;;SSSyyyKKK===;;;<<<333444555222222000222:::555---222///...111222---333222,,,444777777(((+++555111FFF333444...222000888:::777222555000,,,---CCC888//////,,,,,,***'''///:::111---,,,CCC,,,333...///,,,<<<^^^ddd000000***######%%% ((($$$ ### &&&&&&%%%""""""(((111...000>>>:::...//////((()))777444888@@@NNNKKKKKKSSS]]]PPPEEEFFFOOOOOO[[[SSSGGGGGGFFFIII___@@@***---...///pppKKKTTT}}}<<<999FFF'''***888:::CCCJJJooo HHH999444111(((---666<<<333999888999]]]111(((...777YYY222555888111000JJJ;;;888777;;;???444777111???:::AAA666???EEERRRFFF>>>:::>>>NNNBBB888>>><<<>>>777III&FFFFFFSSSBBB:::===:::999444999===777777777DDD666FFFAAACCC777@@@@@@888999<<<555000EEE:::555444555;;;___vvvPPP;;;000555333777444---000999---111---555:::222222777222DDD999;;;,,,.........///,,,)))333555===000---///===222...666...///---+++>>>555111***&&&$$$%%%+++'''...000///---,,,333---,,,333)))000<<<:::AAA)))((()))>>>$$$,,, %%%  """777...%%%*** 000000@@@,,,333666444999///)))///111000444:::ZZZQQQfffZZZTTTvvvTTTPPPIIIPPPGGGUUU\\\mmmaaaMMM555(((***...QQQKKKDDD777111@@@???QQQ777222...<<>>888222111JJJBBB======AAA777555555555///111...<<<777999222444111>>>AAA111222444>>>999666555777<<<444666777QQQDDD999<<>>111;;;???>>>444444111777'''&&&---;;;@@@GGG<<>>444>>>AAAOOODDDFFF222555@@@666TTT555>>>///...&&&444,,,000)))666///888222;;;333ZZZ666>>>...222---===111666000///111111111>>>AAA///%%%(((***,,,---222---......)))***666++++++&&&111%%%+++(((.........---FFF(((///,,,)))((((((333000)))###+++"""///***((('''...***)))%%%000===111777...444///---888000CCC///111444<<>>CCCTTTPPPKKKfffNNNFFF999WWW888666222555;;;DDDKKKCCC>>>HHHVVVrrrMMMYYY}}}DDDDDD666mmmRRR:::000111111,,,333666999555222999;;;???===::::::+++'''***///...---000///444555...666444555111111333777444444222///,,,)))KKKMMM888TTTEEECCC@@@666...******'''///222222///,,,,,,+++,,,&&&%%%///FFFnnn???AAA``` -fff666BBBOOO999;;;;;;777777444333333666777^^^ZZZIIIFFF666HHHFFFBBB222,,,>>>000;;;,,,(((+++555111***(((777444---:::111)))444111888===777777===999666333888---******"""###))),,,---+++---(((---+++111)))---666111TTT---'''444444000\\\EEE///,,,///DDD000---***444777///+++""""""!!!$$$;;;666444+++%%%&&&)))555888(((000111,,,,,,,,,///222III111---333000@@@<<>>WWW777JJJ???NNNIIIVVVRRRKKK333DDD???;;;555000111;;;HHHAAA666;;;WWWqqqfffTTT555888333```~~~BBB999...555666444555777000222///>>>CCC999LLL888///---###$$$@@@$$$888(((KKK444000999666555888444666222555444333333111000777999@@@CCCOOO---222555///***+++///---111222000444''''''...((('''///333GGG===EEE}}}~~~oooSSSBBBDDDAAA[[[BBB<<>>@@@JJJGGGLLL>>>OOO999333...444444111,,,HHH[[[333000...///111((()))%%%(((---)))...000888333666///000000111000000@@@NNN@@@EEE888000777888333---222...---)))---++++++***,,,+++(((---BBB111(((((((((***111vvvIZZZ000666:::HHHAAA000111///...)))...///000,,,DDD555...---###$$$%%%ZZZ000&&&***,,,,,,''',,,'''&&&%%%000...LLL000AAA333333333444777555...666===EEEHHHEEE>>>III@@@DDDPPPIIILLLGGGNNNIIIBBB(((555555AAADDDJJJ???AAAKKKUUUnnn```UUUNNNrrr+++333000444%%%''')))***111333<<<...333///+++888666CCCTTThhhHHH...'''///666///+++ (((+++......:::555222000JJJ555222888333,,,888555---222EEE666444666333888===...444(((&&&&&&,,,)))(((+++111&&&///000777222888,,,555...CCCbbbBBB:::DDDIIIKKKCCCCCCFFFBBB555000111***---......000///...---***&&&%%% ###%%%333---+++---777ZZZ333???///333***///555DDD\\\FFF<<<888...,,,000BBB222%%%'''//////777+++&&&(((%%%###"""&&&+++,,,***&&&///***333[[[ttt999>>>000777kkkMMM,,,JJJ>>>;;;,,,...222)))&&&'''666333555$$$%%%(((+++333III000'''666VVV666------000++++++******+++222555///222555444777AAAAAAEEEIIIFFFKKKRRR[[[EEEGGGTTTWWWDDD999LLLGGGFFF^^^XXXGGGAAAJJJdddWWW}}}QQQyyyGGG@@@===666---!!!+++111555555111///;;;///???666>>>uuuJJJOOO444---***''')))555***'''***'''))),,,222444///777HHH777000000111,,,'''999<<>>111;;;;;;DDDiii000******)))((('''&&&+++***)))'''///...555000...+++999///+++000;;;444333BBB===CCC>>>;;;111111000222,,,...,,,---000...444,,,***""" !!!%%%'''***+++***000---;;;000444555333...000111444333444999555111;;;,,,EEE:::&&&###$$$***333,,,***((($$$---"""!!!''')))111BBB///(((...___yyyAAA888111777...---111MMMAAA;;;>>>mmm000//////***......>>>:::!!!!!!&&&(((NNN666333<<<777,,,)))555,,,///***%%%)))EEE%%%''',,,PPP666555222555999444XXXAAA777DDD[[[OOOGGGMMMAAAFFFIII[[[UUU???MMMVVVRRRmmm<<<@@@GGG===HHHEEE>>>___qqq[[[DDD555III '''444000222333111777777555;;;999CCCDDD999///000333---///***<<>>777444999999555///...---,,,111000+++GGG999444@@@"""###)))***---***///EEE555555333ccc---777***)))%%%'''---...+++111...GGG333)))''')))******,,,&&&###)))&&&+++)))***---)))$$$$$$''')))---444KKK///***KKKVVV???:::333777///'''222+++***AAA...222RRR---+++---000'''+++...+++111+++222;;;===<<<111)))+++000,,,...111,,,...///555<<<000++++++&&&++++++&&&'''((($$$""" """######$$$((()))---;;;DDD<<>>III222???>>>;;;;;;===444???((($$$$$$''',,,...DDDVVV+++$$$"""%%%TTTCCCDDD444)))'''&&&---+++'''(((111;;;SSS***(((%%%---BBB???555///777HHHOOO:::;;;999@@@BBBDDDIIIKKKLLLIII\\\UUULLLHHHLLLFFFKKKFFF@@@:::888777HHHjjj0AgggkkkOOOaaaOOOBBB===555888......000222///000777444;;;222''''''999'''))),,,555//////333+++555===PPP###"""===)))222BBBHHH///111???222###(((444222222//////,,,)))###???...$$$%%%))))))***---***)))(((+++***hhh///(((###'''$$$$$$(((//////999>>>222GGG555666[[[EEE222222)))---CCC???PPPFFF===777555...000GGG'''%%%***SSS555333777@@@@@@111HHH---111>>>>>>HHH***&&&111111+++,,,...111,,,;;;///&&&&&&%%%$$$"""###"""&&&&&&"""%%%(((***FFF^^^:::PPPDDDVVV888111GGGCCCQQQ\\\TTT```>>>888LLL((($$$'''...333,,,555***"""888$$$***===555555333(((***)))((()))'''$$$+++999((( ...,,,...***000...:::@@@888555...888AAA===FFFIIINNN[[[MMMGGGEEE```LLLPPPggg___???///CCC777 bbbSSSdddwww;;;111<<>>***+++***000---'''999+++***???<<>>OOO///:::777III===@@@KKKYYYdddOOOFFFbbbKKKOOOIIIIIIAAA333***ccc---888)))JJJLLLDDDRRR\\\CCC888>>>KKKDDD+++222333444//////333999111000(((&&&@@@%%%###%%%+++---'''***!!!RRRVVV,,,$$$$$$222+++333333:::777;;;666...,,,222222777444111111///***+++&&&(((&&&$$$%%%!!!&&&[[[444%%%+++&&&$$$+++***$$$%%%"""///)))+++//////,,,>>>***///)))+++,,,###,,,)))///666888;;;aaadddpppvvv???===BBB......000///111;;;,,,---...222***444111+++111***)))(((]]]111JJJ999111,,,666222)))===+++***---)))((()))///000444111&&&\\\???<<>>OOO///%%%###%%%GGG%%% )))%%%///---***%%%---///---)))%%%'''---SSS:::333""""""$$$ $$$???,,,+++...;;;::::::111444<<>>:::555666555EEE000...666000333QQQIII...///(((444222(((---//////222333***---444222'''%%%"""&&&***//////555444111000333((()))'''$$$!!!))),,,...000AAAQQQDDD<<>>...555FFF>>>RRR>>>FFF@@@BBBOOOOOOGGGEEEEEE;;;PPPFFFRRR666BBB<<>>111,,,***@@@%%%'''&&&***,,,111777...++++++888)))!!!)))___KKKDDDMMM>>>>>>333@@@FFF;;;222111000222UUUTTT555:::333===444666999888111666666333555>>>BBB---%%%&&&&&&,,,...777000///555///CCC...,,,%%% 000222777222GGG>>>FFF777===BBB888777999<<<222+++)))&&&+++---888555qqq222///<<<222---%%%(((---,,,555:::CCC666777999...000000+++///+++,,,...>>>VVVOOOiii@@@555WWWJJJ222///>>>...555))))))>>>===999+++TTT---222MMM'''$$$ """&&&%%%(((%%%JJJ$$$,,,***222222+++***///$$$###%%%&&&$$$%%%"""%%%)))''',,,TTT>>>777444222444;;;<<<222888>>>FFF888<<<<<<<<>><<<999333&&&000,,,%%%,,,///888///777333///***000&&&+++333@@@;;;EEE999666>>>;;;YYYYYY222333;;;666333---555333999AAA;;;???999555<<<444666///888444IIIGGG333111(((......444---...***)))---///111HHH!!!***555111000000666666QQQ===888:::LLL===999AAA333000444------777......,,,)))---,,,+++000//////:::222333000222555999000,,,'''$$$(((///,,,222111222@@@<<>>---555111333@@@;;;:::000mmm???333AAAEEE???666999333@@@111///777===666+++&&&((("""***;;;---FFF KKK111333---000222111BBB---+++...)))111===::::::PPPNNNDDDWWWppp>>>JJJJJJ222999...555///444...DDD;;;WWW___<<<444...'''&&&CCC$$$""" ...%%%!!! (((###)))444:::AAAFFF777...''''''&&&!!!(((###!!!"""$$$///+++***000)))***&&&...444BBB666777111:::333222WWW```>>>777888777;;;AAA???:::>>>EEECCCEEEllluuubbbLLLNNN>>>&&&333CCCPPPdddPPP>>>666+++%%%))),,,---:::555CCC666===)))000333444222222222111---222///(((*********---444333:::555333999>>>999+++&&&111222555333;;;QQQsssYYYJJJ___\\\ZZZCCC@@@AAA>>>666555...222000222222,,,,,,,,,333333222222333...555HHH444YYY111666...444555:::000...111333444BBB]]]777///CCC666444666DDD777444RRR111%%%***$$$(((aaaZZZPPP3OOO///:::'''+++444***444HHH555%%%((((((222888MMM<<<>>><<<555999???***:::222...000(((,,,222ZZZ;;;;;;;;;HHH___HHHHHH888000###%%%$$$ ...%%%&&&###"""&&&!!!&&&KKKUUU333,,,&&&&&&&&&"""$$$$$$(((***555---(((//////333555222666///111555444333;;;===:::111555888555777GGG;;;AAAHHHCCCTTTzzziiiXXXxxx```]]]<<<...000---000666AAA+++JJJ+++'''&&&%%%...BBB@@@RRR===777222666111<<<555666;;;;;;111333---333111222,,,...666000666???III@@@777555888666hhh666;;;;;;@@@LLLYYYYYYxxxlllbbbyyyCCCHHH<<<888333222555333000666RRR,,,222444333000444888@@@<<<222777555>>>DDD===111444@@@...555777444333111AAA666222000666111888777444666111222555$$$%%%&&&///;;;III[[[MMM///444******)))///"""%%%444%%%%%%BBB***,,,'''---SSS777888,,,)))444,,,)))555***)))+++,,,HHHPPP333LLLnnnWWWqqqTTTJJJ333"""###""" ###))),,,///---222$$$'''111!!! $$$$$$!!!'''NNN%%%&&&777...))))))111111///(((---111000888CCCEEE***000555;;;222???333555===???:::@@@___OOO^^^}}}}}}VVVMMMEEE+++---%%%$$$%%%###+++###$$$)))---111...333444777999DDD<<>>222333---777???555<<<...000444777???===@@@444666333<<>>777777222333555333///444...666555000999444>>>GGGBBBLLL999222777:::TTTDDD777///AAA444222000---222CCC888555<<<444222444666,,,777<<>>BBBiiiTTT111444<<>>888;;;BBBNNNttt]]]fffVVVVVVIII:::///777 &&&)))***(((000(((***,,,777666999MMMJJJLLL===:::666555111555222111666222:::888777<<>>333<<<\OOO666888222444777---***---)))///666222333///BBBBBB```HHHCCC>>><<>>222CCC333---111666...))),,,'''$$$"""%%% !!!+++###""""""!!!222###---+++***---:::111///111111777<<<888888***,,,///$$$'''))) (((!!!"""""" """ 333"""...000DDD!!!$$$!!!"""&&&,,,%%%'''"""///(((---!!!"""%%%%%%###222)))---...222===<<<...===555555666000333===666::::::<<<777333JJJ===JJJmmm/uuuTTTBBBCCC???JJJ...---111++++++...+++000...***+++%%%...000222666rrrIIICCC;;;777GGG666333444;;;FFF888222;;;===:::888:::::::::DDD>>>888666;;;BBBAAA333333;;;999666222+++IIIyyyCMMMNNNEEEBBB444NNN777///***,,,---555333777???AAA888BBBHHH666???999>>>AAA===999333GGG999===999222555333;;;<<<<<<@@@>>>RRR===EEE>>>666BBBHHH<<>>AAA{{{AAA;;;:::<<<<<<===999555666EEEGGG===:::EEEUUU999111777777888IIIHHH<<<>>>KKKKKK}}}QQQ666222;;;555999999333EEE333///555999EEEOOOZZZ>>>CCC===???;;;888CCC777:::000777;;;888888111777WWWCCC===EEEYYY<<>>555777<<<888>>>LLLPPPTTT]]]FFF;;;UUUCCCBBB444GGG;;;DDDPPPXXX+++ 222---+++///333......(((777111333...:::444:::<<>>CCC333:::;;;999<<<<<<444JJJ---(((555777^^^AAA@@@555CCC???<<<[[[222666======FFF666222333888333HHH888@@@QQQOOOEEE===<<<===@@@III;;;<<<<<<+++XXXBBBBBB222KKK333===AAALLL===DDDBBB???HHHDDDPPPPPP???HHH<<<;;;@@@888:::888,,,LLL666444222CCC)))+++,,,***,,,"""$$$###"""(((///%%%$$$### !!!111555555((((((((()))"""###%%%######!!! '''###111666%%%$$$$$$777!!!))) """&&&555!!!444$$$###..."""  !!!GGG%%% """!!!%%%%%%111555<<>>EEE>>>OOO@@@>>>DDDAAA;;;===CCCEEEHHHDDD>>>,,,***555---444---444***&&&333)))555///,,,555222444333///III^^^iii;;;@@@[[[BBB???666999>>>888FFF888333:::%%%///111---000999===666444:::000777;;;===@@@555111KKKSSS+++000111555999666MMMNNNMMMAAABBBTTT;;;===III<<<888222000AAARRR===666777@@@AAACCC>>><<<999sssJJJOOOMMMeeeRRRRRR>>>222555===999555---111JJJ;;;///222+++((()))***,,,%%%$$$$$$'''(((...,,,(((SSS""",,, )))######000''''''%%%&&&111 !!!!!!%%% !!!!!!!!!!!!!!!666111NNN777%%%&&&"""$$$######///%%%!!!"""'''''' &&&---444QQQSSSAAA===---555===______111(((***$$$(((,,,555>>>CCCOOOAAASSSHHH???:::888BBB@@@TTTKKKLLLCCCFFF777JJJcccIII;;;111...000555000...888///777BBB---******...999///)))111555>>>AAAMMMJJJ???KKKAAA:::333888777:::IIIOOOZZZCCC***+++///333CCC666555999,,,111...GGGOOOfff999999,,,AAA999((((((444333>>>FFF:::===???CCC666333999TTT@@@>>>777888888???QQQUUUbbbJJJ@@@===III999:::<<>>BBB111:::888444;;;FFF^^^LLL888999AAA333444444000***///,,,,,,===333GGGJJJ444jjj///%%%%%%### ###***&&&%%%%%%(((,,,---&&&$$$######"""777---***!!!!!! """###(((!!! &&&"""### !!!""" ###%%%###111___111***///'''###)))%%%###""""""(((&&&???\\\CCC...WWWhhhBBB]]]444@@@333......555222===AAA***&&&>>>$$$(((:::888```999888MMM///666@@@EEEvvvoooKKKsss}}}ttt@@@@@@888555///222000---XXX<<>>000***777...++++++999@@@555AAA999===///222111777)))+++222333$$$222666DDD@@@555222111888999---555,,,000333222777>>>999999IIIGGG;;;kkkAAA222999;;;LLLKKK>>>@@@444444:::999OOO444HHHbbb999BBB777555>>>999222+++)))+++333***,,,---222,,,///555GGGLLL555&&&###""" $$$***GGG:::+++AAA111AAA&&&$$$$$$%%%%%%;;;---(((000,,,%%%"""###&&&---$$$### """###;;; """ """""""""RRRSSS+++###+++&&&===(((>>>lll---,,,---666___???;;;111...444KKK333444111444888'''$$$&&&###<<<777>>>---666:::------MMMUUU}}}ZZZ\\\qqq|||yyy===888666<<<333//////MMMEEE//////999666;;;:::===777555***,,,000//////111000GGGPPP<<<777777OOOLLL...444333***%%%111222333222---///---000(((,,,777...+++***---***...333---222***///000444333444BBB222///888666333HHHHHHCCC;;;;;;:::PPPEEE000777FFFRRRIIIFFF<<<777333444MMM<<>>...%%% %%%"""jjjooo,,,...///"""555BBB444))),,,...000000///000888......%%%)))!!!***777555000777///+++---LLLDDDOOOSSSYYY|||(^^^888(((%%%------111000,,,888///...FFF:::CCC777,,,000888000---000555///<<<@@@===999777444___\\\000((('''%%%(((,,,%%%---///)));;;...:::000(((+++666---///333222444222...111444444333666222:::555444999======AAA<<>>;;;111111+++888999XXX;;;FFF===???...999///???"""((('''((('''JJJ;;;000bbb^^^===999OOO -___777000&&&%%%,,,BBBwww666555333000$$$JJJ&&&'''---666)))%%%&&&###"""!!!,,,111SSSUUUCCC666---((('''EEEXXX555BBBAAA###%%%!!!!!!&&&333,,,ZZZ ###$$$'''---...)))%%%333555)))***///???SSS:::BBB888666000...$$$ ###,,,000DDDRRR444@@@PPPLLL888HHH>>>pppdddTTTIII888&&&""")))---???III;;;111???+++,,,///111(((***---<<<,,,,,,...666333777------777000444}}}0PPP???+++###### ###LLL777444888444+++***333&&&###...111***333333222666222222444333666444???000999EEE444;;;BBB>>>>>>SSS>>>BBB@@@IIIFFF===222111666@@@555111111===...(((...555---;;;999---&&&(((DDD%%%...999+++%%%'''---===%%%///LLL???:::[[[www???///))),,,'''---555---444HHH...@@@+++'''$$$,,,+++999...'''""";;;%%%'''666888999bbb======ZZZ[[[AAA^^^9+fff333...(((###&&& &&& %%%222 ;;;### <<<"""%%%"""!!!###(((VVV''''''777@@@FFF222???aaa666GGGDDD888,,,"""$$$$$$$$$111,,,111HHHOOO444444KKK777444;;;000)))&&&$$$000---+++555000444+++111)))***222)))******(((///666---///444111III///---,,,***+++III___444,,,)))"""$$$%%%+++888<<<***,,,...***000000)));;;333222333///333;;;222111444333555666444333>>>DDD888]]]DDDJJJ???lll@@@AAA>>>BBB===>>>///333KKK666666:::333222(((%%%666999,,,555---...!!!%%%///HHH...+++'''+++---((($$$%%%,,,'''333IIIFFFLLL000333999111%%%+++%%%222+++(((###%%%&&&111444)))777+++;;;!!!&&&000///(((;;;FFF^^^PPPKKKUUU^^^LLLccc>>&&&"""111@@@'''(((,,,000---)))$$$&&&&&&$$$&&&***&&&***eee===---<<<222777TTT---111---((((((333&&&(((000000&&&---111FFF!!! +++VVV***111>>>>>>>>>PPP~~~{{{hhhkkk]]]___#?|||>>>MMMMMM&&&'''!!!'''111'''!!!###""")))GGG%%%eeeCCC!!! """###(((+++222%%%)))---777\\\ dddJJJGGGhhh>>>OOO+++444%%%!!!&&& &&&###%%%&&&(((111///&&&222>>>777444111...***222999&&&'''###$$$///,,,...+++---(((%%%((()))***'''$$$---(((ddd444555,,,888///000///...%%%### ((()))+++((('''///>>>'''&&&FFF---000((())),,,...666+++---))),,,333---222000JJJ888888666<<>>///CCC999&&&!!!%%%555))),,,'''%%% ,,,;;;333%%%&&&$$$***...(((...///444&&&HHH333:::888%%%"""$$$GGG///000OOO;;;@@@###///  ###888;;;444***###%%%!!!YYYDDD+++###$$$RRRNNNJJJ222WWW,,,CCCGGGAAA%%%***###(((''''''&&&((('''$$$###!!!###&&&!!!!!!((('''***+++,,,+++%%%444((('''&&&(((111888%%%"""(((---+++%%%%%%!!!$$$$$$ ---,,,$$$ ###!!!&&&--- ###%%%%%%$$$&&&$$$&&&%%%+++333>>>LLL...,,,222///,,,(((,,,,,,444EEE???gggRRRaaaOOO444...000666...@@@TTTgggMMMXXX777JJJ333444++++++)))444'''(((+++)))""""""$$$&&&&&&)))*** """ """"""%%%&&&"""000###&&&,,,))):::///777JJJ<<<>>>)))???---***"""$$$---$$$!!!ccc&&&***AAA444888333>>>###&&&(((((($$$@@@///111(((999;;;---???999***"""&&&"""333 bbb!!!"""%%%""" ###GGG222+++!!!"""$$$888OOO...555666$$$333%%%%%%"""&&&222%%%%%%000((()))###)))"""***'''&&&%%%$$$+++,,,'''------(((---***222WWW&&&$$$%%%555'''######$$$&&&""" """ <<<%%%"""!!!&&&$$$$$$"""$$$###((( ###'''(((///000444???JJJCCC------777...---222<<<;;;{{{ -uuuggg???222444+++000CCC***000333111999777>>>###$$$((('''***(((///+++---...""""""""" ###%%%"""!!! '''...$$$888 ######(((111...GGG:::;;;AAA...***$$$ ### ,,,...///###)))***NNN@@@,,,)))&&&...///))))))777000 """)))"""---%%%+++666VVV999+++999%%%!!! MMM///%%%GGGNNN777888%%%"""!!!!!! 111...###,,,%%%%%%'''///666%%%)))%%%$$$%%%%%%((((((((($$$&&&)))+++%%%###+++%%%AAA(((999mmm!!!&&&---((( ###,,,%%%"""$$$ +++!!!$$$ 222,,,"""!!!///&&&###$$$)))>>>GGGGGG\\\111:::0002223336663338887)xxxnnnRRR333...---...(((888...(((&&&%%%...666,,,222<<<,,,222((('''%%% +++$$$!!! %%%"""$$$)))###!!! %%%***(((###***...+++AAARRRAAA???RRRSSS---%%%+++'''$$$"""$$$%%%(((%%%(((***)))222+++++++++111###'''!!!---333;;;888***'''333""";;;000@@@///555!!!'''((( %%%222%%%,,,222&&&)))...444******'''###$$$...)))&&&$$$%%%###&&&&&&+++(((***(((***$$$((((((!!!''')))(((######"""!!! >>> %%% ###!!!!!!%%%""" !!!"""$$$$$$%%%&&&AAA000@@@)))666(((333///'''***...AAA>>>oooccciii<<<***$$$%%%(((333///<<<$$$,,,)))111444111UUUFFF>>>,,,%%%"""+++%%% !!! ###"""$$$###'''+++///(((###777&&&,,,***...XXX:::===777)))$$$<<<*** !!!((($$$ !!!%%%222+++%%%&&&""",,,)))!!!111 ***   '''<<>>\\\zzz -OOO$$$!!!&&&%%%'''$$$...(((&&&...222))))))***%%%&&&000$$$""" $$$%%%&&&$$$(((===(((***"""!!! 999%%%"""!!!  """  """###%%%###'''!!!%%% ###$$$(((%%%$$$<<<&&&######!!!---FFFPPPAAA___MMM~~~,,,'''$$$'''''')))---666)))"""'''...888555AAA???kkk((($$$%%%---&&&''' )))!!!"""%%%###<<<$$$ ###......###!!!"""###;;;(((999...,,,;;;OOO)))%%%###((((((""""""###444111&&&%%%&&&555))),,,$$$!!!"""###!!!""""""AAA BBBBBBDDD222)))000---UUU444```bbbAAA444$$$ !!! ###%%% $$$***---///***((()))000,,,((((((888...((("""&&&""""""'''***+++'''$$$$$$&&&######!!!%%%### !!!"""%%%&&&###!!!!!!""" !!! ...%%%'''LLL///###$$$///'''+++///999SSS888[[[TTTbbb888&&& $$$222>>>DDD&&&***!!!!!! $$$555+++)))KKK......---&&&999###$$$  """444***$$$$$$&&&)))---$$$ &&&%%%555(((***,,,(((!!!!!! )))&&&$$$((("""&&&333000'''%%%'''"""""":::MMM***###+++!!!###...111~~~000BBB9VVV666!!!  <<<***$$$ ###$$$222555555KKK:::AAA@@@777&&&'''&&&)))###"""!!!'''!!!%%%!!!"""))))))!!!###&&&((($$$ !!!!!!###""" %%% &&& +++$$$&&&""" (((+++%%%+++444AAA222===&&&$$$%%%GGGdddpppooo...000###(((FFFXXX000---111"""000:::111$$$"""!!!!!! )))777!!!!!!"""(((#########"""...'''///!!!(((///***(((######!!!''';;;---### &&&((( %%%ZZZ>>>333""")))***222///ooo///666LLLKKK''')))$$$777$$$'''$$$ ###,,,'''***)))000---&&&+++999SSS```LLLZZZ111 ###$$$###'''###!!!+++### $$$666&&&((('''$$$###"""!!!"""!!!$$$ $$$$$$000"""!!! !!!,,, %%%777''')))""" %%%)))HHH###'''+++ """222'''222III((((((YYY$$$%%%!!!---$$$***"""((('''&&&%%%''''''###444!!!'''%%%"""###''''''&&&WWW!!!###(((+++""";;;OOO333)))000***%%%&&&DDD999&&&---SSS***"""&&&999 &&&$$$### $$$ $$$"""###888'''++++++%%%999PPPVVV???AAA !!!"""!!!$$$$$$!!!'''###%%%!!!(((888777<<<%%%%%%###### """ """  )))!!!"""###&&&!!!...&&&))))))===###!!!!!!999'''"""444^^^///555(((%%%%%%&&&""""""### ###"""!!! """"""!!!+++777############$$$ !!!!!!+++'''""" 333$$$ $$$((("""%%%  %%%+++(((###333444LLL[[[;;;???000(((777777 $$$,,,$$$######$$$### %%% )))!!!""""""((((((***+++$$$)))$$$DDD555555666JJJ$$$$$$"""!!!#########"""$$$%%%$$$'''%%%""""""!!!!!!'''!!!!!!$$$ !!!)))""" !!!"""%%%...III ###%%%(((### ((("""(((&&&...***$$$ %%%&&&---"""(((&&&""" !!! ###%%%&&&&&&  """(((!!!...'''"""%%%"""&&&###&&&"""+++"""$$$ \ No newline at end of file diff --git a/data/fits/NGC3344.Color.8.fits b/data/fits/NGC3344.Color.8.fits deleted file mode 100644 index b553a37c8..000000000 --- a/data/fits/NGC3344.Color.8.fits +++ /dev/null @@ -1 +0,0 @@ -SIMPLE = T / file does conform to FITS standard BITPIX = 8 / number of bits per data pixel NAXIS = 3 / number of data axes NAXIS1 = 256 / length of data axis 1 NAXIS2 = 256 / length of data axis 2 NAXIS3 = 4 / length of data axis 3 EXTEND = T / FITS dataset may contain extensions COMMENT FITS (Flexible Image Transport System) format is defined in 'AstronomyCOMMENT and Astrophysics', volume 376, page 359; bibcode: 2001A&A...376..359H PROGRAM = 'PixInsight 1.8.9-2' / Software that created this HDU COMMENT PixInsight Class Library: PCL 2.6.1 COMMENT FITS module version 1.2.0 ROWORDER= 'TOP-DOWN' / Order of pixel rows stored in the image array END (! !!#%*...!! ! !#!(& !!# & #)%$"(##!$(-'6,-&)42,*.0/,-L_3.355]}[HYZL>P-:^9'.,1-1-4.5/60)EK140315800,1133...36:4238:>;8>999737?C<=;9a6<>9794?6<3:>8:2D500.67ASC9?FCB=7;=7537244836>.6=7471*0)'(0,!')$#!%    /"!&# #!!' "%+ 5$$,!) %)!"(& )&%*0*21.#+A+)&(,&.6,)8247TZMnHG500%/23/0162./0-*.1.01/*454339;6558688<65A43654374/:3044.1?>1:=C:5D5HMG8>;9;C<6C72@1+*15&*((,%#&'*%#! ""'%"!")&!#!""$% $!&'", "''&((5(+/*.Q*35%$)/+.,6AR@<:65+BD<1.+-///0+-.0-.,*,.+-2.[E/-.5.32,50/472*441:@97899A?:9<=?B;4::88:@<4://1:4306463<41.;602-?;6DB>4=>7?@48G8463-*--21),-&/'%(#)+' (% #&41 %$%"&'"!7.)'$" !!$'!$0+),)&,0.2*0)*+<7(,4%'+-107LO516?;-=1../116+/-.(**')**-/56120/1++0&-0543224@?7267789775:98?<:;;D@@<>48468664594678:<735=E?4467224;RLEFKL<8V89-4./-/,+A')(-$./()&""!")'%88 !#%0! !1$$#$+%1#!"  )6&+-#(&(.)0?2:9L20B/1'+(21+0-7E;67=:IQ,.*+-)+,**,.,/+)+.590/004100./,44.8,26422FE;8;6>@9<:979=@7?DCOIF6AC8<069?0,.-2&)+/'$1*+0!!#'$!# 1(+)%.)"#/) !'("%(!&$#&"($'9/ -()**+6:GeoB;C0)$&08.1/1+:7226319<3020,,0--*-0141+6201.>W4--/..,31,..2489P9;=69:?<@84469?A;9<>\AY??AAKA>9=?9?2BQBRI?cA:?@99<FA59=?XQ^kfHXIFM``aZocVSLZDDG<0/.42+4/())$#$&+)%) ! " +"9%.;C" ,'!# !&1!#-#;),:,*L'+&,*$);'*.2BaWV3/+(**,-.-2/05.*))38A;:R030.*)//%'-+-.*.348S,0...+(/0,.365114266;7:;:8:LBD>E?:8<=B@EAJ?H@;;>A9:BHB<[zNLNhC6;B;DM@HP[`uv[bEUS;C?HM2375./2%'(%#)36'!!("!! $#" %.'>) $)%#'" '*!!%((BA$)(41*(&%$+9(0C+<0.Psz=3-1.-+)/.3.+:1-380025C?q11.+*,/;/++,C/,+*-78/+(+,3*,-/0036453504356?;>8]=?==?8>DJ@6=CPHU<<@Q:A=XcJKACB?84>RNVUWie]EHO<::5286C01-1(+,***'$%%%(!*!(!G"!#"(Q4K%%!'" !# %,)-3'-$#)).4&,)-(+&&85/1,=325<3OaS44(+-+.G)-2+1-,/+-/-34FW^9008/.+.5,)-1;-//0-,+'++1<*+-0/+3020.252538=>?88?B@?A=Asm=G>=A@9HC?<=<@>:CCDCK98E[FA>Ml::;B>HZLF@EBEAC:=718:5342212+*)&))*%!!&*$ "!"% !**!&$- !# #,%#'5#'$$/-4/5:*RHQOLA2/*)/Ec'")%,(##+(.?J)%))++-)*/&+*&&*,*'+0+--+,:,/.(%189-/-00;-,-*;/*//*((,,-.0441/123668875==F?<>?@<9<>?A9??I?>>.*('*.+&$&-.&((&+"(-)'8'+/9),(1,))**+70*,0010/;)*0,+-274--.8+6-.0+-4/,0)/93,,135/314273435568P7MBFC9<<9::>===;B@8=EBCKCC>>@;:@<9><:73692+.287-,)*,)-.)&)##'#&"##  #%3 /'I &5,##%,).)#-2.0-/012=;;=6<=;8AC@=A>;DEGo?::HDJ:@?:;==<@2-,++%%&-'$$$$/,*+*-+&+,-)*(2'+/?***,;+/1/*0-/)-*(+2400.+135-93/0-010225554122:2<693=455257>65B:;==BD=ABAAJGDD>F>XDJB:<7ABB=E<4204=62///588-**&'('.&&&"%! # "$%,"'!%)"* "*0,@7'# 0.*C''--06-?6BE;B=:CFE@@?B=C922:7.221)1-A3/-&,,/&&1?*+$$&%&!  !*3$!"  ! "#-9""&"*'K$&"#*%#&')%$-:21H;1>EZrkaJB5-+-+'-(+0&%(-,'$##*)'((.'-*&&+*%)+-105+*++,/-13+*2--+,/05-331.-54..@;41.37828<95:<7578;9553=54<2/,0-.13E2.+)'(+)%-3-/-"$$$# "'(A!$!!m%.(=!$ &%#!!%%$$(),'+,9A?989?ưtwLC2)/#.(+/%(&'))0.+%)*+,(P(&&+*(-)()-6:8;0,(+,-,-.-..,,-,2289/43,2557/127165/25108/7::;=68>>C<:6:::899?DD>GA>B<:>@O@CJD@AG<<;^fbjUORDB@A9>78:376;34?-.-')***1.-,+$#)+(( #,*"!!$ !##!*&$,%"#! %#!&%(! )*'&$-329=SpͪaA:2()/4))'%*()*),.+)')()+)*&$))+**.-/+.20/(**,.+.11/0,-/--7212032038B@902547F?92087::?E69<;7496>>=<<>;8E<>E=>@H=@@?FA?GD=EF=>DD?AACMOFE?<>99@NciUMGQMEKHAEO;6>>C\?AK@EFB>>=KDRLUN@DDCFDC;<<9;8AQT_TLSIcI@Q?>>:>76;6;D2*.'01.*-<7=8>F?@B6;H3:?>5<:389>?>C?EIBGEX99<:9=:78;;CDPD@@?=>KGP:=@@GBA=9=?@ABC99>LOZYMGGIGJO;@B;:<7;6621401:4*0/0+-+2*&(&$$!#*,! ,(% &$& (2@"!  $!("! !$ !#/ $&$""#(+'2KutLWaED@2.3*.-2/+,-*(-,-.$+-+-*-,.*&*.0+-/-221631313021-/-234452537453479;H:9557=87<=68;6;@>N=:CKB99?=@8778:=;99F@?FA8>CEF@=CB8A<>:7633101+1/.87>/402()4,,39!"% L.%& ') 4D!%$4(!!-&'!#!#"$"$%)$ ""&'(1;DI@VotO>D920-*'-4.;+),)()+2,/,.40-+.=--00447/1/8.000..02-/336055438<;9253:826:@438E933455;=987?QK;87;95=;;8?<;?@7=9:=@>BBEAK=CBE@>@CEA???BAEAAHEC>:@@B:I=FI`KE=J@LFE>:<;95362(-P=8DB5,.,40)(&)% #19"$!#  #!)'' "1 # ! $,"! "'" #3#%#'# %($&&+/0,I[pf`hQC:>997/*1/2,*,,*-).)*.0/-1,03,,1/1*-,,0*1-=21/-0-.20351126302-/07466:<_:;9?9753,6666C889=:>:94838@?:A>:8<@=:;GA?AIGD>?BADEFHOC=@@@GA@:FTWI]K?E?FG=AD6581213-04:?ZZM9-)&#)%,)* &*&"*. #"? '&%XR3 B$'$ %"$&() #$$!&%'(')%#'&),6XeifydCCG?-+'().+,,0+0:1,/0=,-/-6>:,/-+0555465116/.677148452456H34:8=;?JN6:38374799<>BH;799=749<9L@?=@D;:A:@GQ@?=<==?FB@BHEFB@B>A?:)=/.'&2!!")"B;3!!=,!8!#"" $'"% $'#+*%$&'((+)*@Pb؏pAKIjP4).-,4/1,1),)0@A.0.25B90.572*/544621>664D:7;45C<757:8:;433:;9F@9<8:@OH;972<5646:?:A=@99C<=36H=E?F=:==?><<9?BBAEACEBBDBDLGH@>>B@?BHGFA>DFPABDBGUQOJIHG:;@713/1/4/5w|L;3)+,('##)&&+)$ %(*"#&,$%11'/4p#&#""(/' #!"%&"2(#" "()$%'(-22FUƄWWJ8GC=..,0--*0-**239;1--428A1109793A403376@<<9<@@:C73565154869?HA@F979F341879<9><<8?D:?9D=><>9:;A@@>EFHLJFKCFIGJA@D?FD?CERF@C?DWJHMIHGO^hgMFC=9<566,//22:}͂F1)-(+))%#".'$.#"% "!,%"')!! "&&/&1.*  "#%$"$ *""($"$#,%'$%'%((9=M|}ca:C>=615.31+.5E112.231431..+322=:85759464:8:76Q@5887<>=;:@@AKGJ?YDAAB?ABHDDCPUCKCD?JQKTcDHS^~jLEE@;7;=:6/18/GYI(-)&$-''"&'$5  !#%#""##2)''%0>%& ### !'(%# ("!#.8("$(,9/R\No^bUF<499:23.0390+-3/288:8242/065.471989:66;88KE48?=::<<<8?>_?<@?@=96B5569A78::=C6:RH:?:?7>OWCE>=:@=?@ADID?>B<1.399J=>39/.3//-)25.3016.399765P8;::888;98=59<==;79<=:BND?6;:77::6875::IFDN>::93888>AEKL;?97:===;?C>;?Q?@@NSMYNeF?E@=AGFCCABKEQ?DA@;ASJZ_Gu`EFLC@B975533+0.66)-4/+#'&)&%/+''###---'-+1E6!""## !  $!#$.$%'!"%)!" !"%2!./786@6/22/,-462.2210-8653115A8?;>3:=78=8?=2368<;9:;::<;<93<88?;A;IvJ96A28849<=?Rg@9;==L=@AAEH8?;==9:<;=F=9\VRYKPVCEEAB=BEEEE@GNGIFE<<=FEGd_oJJ;CH<9=8=3/..))-,,.0,+.$#&(&,'$'$#%** (:40*!$(""! ' !! .,#((23)'$$! #"%-0+-0>0D9<;5;@@?<==@=AFE=?;979@><;<<;959=:=B<8C<><>@48:BC7;>DaHF;>@=9;:?E[>[DB^JCEEFDB@A>EEEHEKFK]MQ@<6<==elNdZKD<@>8764,72+,2*+/1/(-&+&(&&)($(&(*0%@-4,)(!)& ((")$/%$'$(" %4+"%(+!#!)%$/(!&*).0,7@PgQD65Q8=C34722:5845259;68:==8H?7;9966;9;>>D@8?A7A>@C@?@>GB?A;=>@C;8F:=8:<<>==<:BE?EB;>;?K@B89=`K?=;><;?>A;@<>@@89:=98@AD=@D>FBHJB?=GJD?AB=A;B>G>N8A7==<>ABDDJ<7::6K:B@>=>AAJEACA@VFCAECHADDEIMEF@=F^[FZBIMFGYAD=:74B956/-.,F(&(()+%)&,+'./$*)'%'-QE'& "( "# %!$'& !%+S%!%511,%'0%*%%'%$&+"$+',,565.;99448/1D74;A6/2597@;36DA@<;?>@8=THA=BEBE=;;;?GGDDIDDDJJCMECF@@<;<:8:8>?9=>LWC@;=IBED<8E?CL=;>?A85;GA9<:B>@@@A>@CDEA?FFGPJF@GCE?DKE>BI:CB?>KIafUEHECDA;JBCFJJEJLD@BD;Hf=>E?<;;=:A>?<@AGB=<@LHBA<=8A@=?=@KAEB?DH@E?MAVECDJEBM@A;3??GHROJR>A:=<3045//02.*.+2*1(,+'(03)(Nf))&")39`2+& !$4+=9%!&$'#!$&%1-K)(:#!))+$#$'.?))/%.-.,/2/60==E711/8225:G=995=;<>@H<HGA?AA@?@F>A;?DGBA><=HAB6>CABPPkCB@ACGD>9;A>A;=@;>CE=B=E@CCCC@>>DEJFGHGIKA><;?B?DIKIJGA?:8985546-3/0,'-0**)##(*.+)$*+)0.*)(/-$( ##'4),-('&#&&$!'"+Z<)'"&()*03&&#((,1*(,*464M:]KL?3:5244558<;>;8:?8=:;@BB@>BQKEhb{ZHEHBB?IIJJHKADCCGILKHJNHEIEEBDBD@B@AIGCDBA?>GNVKDBDAC>??@FHDBEGEA>IAFGETcAAH@@JSC?DC>EHDGB>EE>CJFEGMICBG>?96181291-.-,-**')$)*%!+((=+e=$#%26)*$>!$!( &&&  $!!##%!&*$0!)(.'%3)($&%"#3*/,33.704;:@88=>29AB8938>M=8J9>9A@BCE?DIINQN@??JCEFHNFIWDLIE@BIFFCJPTLHDDGC?CAPGDGKGKGF@?GJPHJKKDGAADCHFJLOLF@;??>CEB@@=GAAEaGSC@@@JFDDMKEFDGHHMOQGLEFJHIFHGE6=AA@CGGIFC:?<:448B1143/,')0(%%$%'$"('.3.5*&%$%*,'"A #%8 "$ #%>.+#$"#&23&)-'%))*&1-.>7035@@<4ICJ@6CJBBCDFTRHEHN?@>@HJICFGBJNMLIWHHJDPIJIN61DHHDCIGCA<@:>818762:/./?')*(*')'&)('(4M'*-%+&$#%()) !#!(/%' #0 ( "$-(  ('*.D#!'0'$&*+*'054J0015-=CAPGFIWMSBAEGEGLLGFRJHFHHJKB>K^hKHNPXUSIMHMLMGKIFNLODIGDIMFJIMPPJPHNHPFNXHJVKIM?=GCCD?JF?CAKFJIH@>AEDBGARNNEFKIRTOFDLGFHJIHII?:9?KFA?ECHQ575973>-*),%*/),(&)/&#(/*)&/(/)%('' " #%&4!#"$/%!!"" )#'&=*(("(*,+)1+')2250/5/5KHL8D=988:6:7899KAA@KLVZGGHHDKPX[YOGGXLEwONPPGFHGIMQPKQVZmrhbpuhVYUPTTOJJIGLOJPNFJFJQLNNSPQTPOOIJLKPQKLOTMLIHELIMLE@@A?GEHJBMJFD]KHIPIJMN^SLGDFLFFIKEGEA@58AD@EECKFDAF:;72:9B0..-)+('*,(-*#%(-&0)*'(#"$#"!(!  *# $)!#'"!#% #(2&!)(()$*(+1&)032.13?=?76BI7:;885=A87G?4;98>C?CSUjxjk^SWPNKS`TLCGJNVKXVEJIOP[S_NPZZhcc^X_ORWQOPMJJNSLNIJIIOJTQRQPSNOQLPLQOG>87=48454-.6(+-.-*)&$(')++**+%$"$!"&% !!'#!*!$!##$)')#$$$"(%$&+$$'-'BC-+538993;88>=CI:445>8>?=<>:E?F?FHLFB`l{dQ^UVWXPIPYMNLTMJQJLIESQUZYQWVUoowʬwcVVUQVQMLPMMUPOMJKJJNI[SKSYXOKRNMNPIGECHRUPLNHPVOLICEACGAFGFCCIDCGNEFOPKDIHJJGERIKPqDHNHH>;FD?IFBEED=825>56G4/-1'-**'4(*%#)A%'(00%)+&&$(&+$&$(< #!!!"'", !("#!!$'$'($#!#))-,1*133-33A?00565C9;??6CH[CCECR:SeGEL#!# '!")#&(&&"(#<- #%0$'&%--1/5-?)+0/./1-23/339<=;6:39:=A:7>=<=@@<>>:=C@7660-13-(,+)+*3((*&.&&)''*($&%)'$$.''%Gs!*&+03DKC>,'-%!##$-481,+0.--.+-+/903163;88<;58@B@A;<:FBU{oDBGKROU\\XZ^O]^RRQNMUOOMOTJRKOVTUQ]WgWXhk_Z]jk[\\c`Z`hgwaelc_ZZX[[UYU^Y]e^_]XXRVVX\ZZYbghfqxVRSQKKKJMKFOPFLK\fIFcPNRLDBIFBGOPMQMMNLRZs<@HNGFFSKEBB?B2636.*2/)*()%.(**,*%'2)'&%))($(+$!"$.(#&/6446jxO1+)%#!7G,(-@/01-27(9;8754=@?747<:;A=E:7=8;98EBASJQkLQ[aj[O^MLSOSTSZO[TMRWV\UNRZUWQX]XXb[YU^\`\^aa]X\a_dh\sildaZ\ZYW_l_]^e]c`c]]dZ`XZW]~^a^\bUa]iVRVQSNJMIJRPNMDLJHSmN_D>E=EHIRLKPSMONHGDG>JIDHFA@B=FB?:7X?=2-**,+*)'1)->-,()%%#+*%')')7"%(''%+*'C4251(&83*&/%&8.0),636.643<=D2D<787CC468=QDE>:7>?:995;>>4=@I?BNQEGNQX^VUUORVOQVRRTdiOOXkPRSWU^QQWUX[Y[Z``Yd]`[Z_[Y_bhhfeke_`^\[[bb]b\^bw_bXXXZ[X]cd_a[ZZ`pXUVRSRUOMLLMIKKLCEDJWp]GFITFFAHKKNNTRUSW[M?C>DMOHAEKDBCL@<<:;500-((*8&*-+)-'&$%'/(*')+.$$#")'*<*($):4*'2)%**')1;,)((+)-+&*246:;=A@47?>B;664QkJ=9?9;:38JW=F>4<=AGJEGAJb]RSMPS[QNUHOSUQYRNOSSQW[OOYZOWXeXcRWXX[[X]bYY_d]_acnigkqk`adgf^Z`d]_ajnd\]Y`[\^\^]bXZ\ZXVZSTPVTYURQMPLLIIFIFNTKXMIDLICBJJMJMMQOLLvjYO`IQHPNIACGL@<=>:6921.,)**-.+,<(#($&%)+)%$++')'#&&$')(#)-$(&.1+(.,*')).-00-1--.+(06?IH==B@;;<69598=<:@B<>458ER?GMOLCDEJDENQIQWVYLUTL^UOTSVRONKNMST_rQVj[O\\ZZ`ZTVXi]\fb_]]_^f^_Za~nshefad^^^\[^]_fh^VY__a[]_\Yb`XWXTXXXUNORWSQQPPQROSLHHJGFIKNCBBEDIJIINOKMLLeeTHWG@HPQDGDED<<;9:BCQ2/72+*-)-,,-+-8'/'$((1/70''&-'%))&(*(#!*+,.+#)2(')3.(42)++-*/887@E9<6789<8665<7@;?=977=9=BBC>@70/5./50*,*.,.),/(/%(&$K/##+%&+,,%$'&#$#*(;/+)()(*+*)A...02658=0368C47>=:7:I8;61;@987;@49FP>?PPOAJCA@FJMndVOSGRTKPHQLF\MKH`MNTSLJOPW\Y\[[[^[W\\]`[\]Y`da]be_cjhiepkiogidbabh_a^d`[a_`Z\V\ga[_ab]b\\ZY[UVOXRMLNNKOUUPMJMG?DFLSEKQDCMWWPKKNRbcZNNZEMHMLUEFAEEBA;;960.3.+.2.%&())&30(*%*1*'+&%'++,+&&$.1)>(& ,,*)'*)/B,,149?C:5D6<7DIREA=H>=A;9;7=9>968:96AAEQcQQQ]TRUONMWKNUPHQOROQeVOMNT[]WTY[\^X[[X\V[dng`_h^_bebeemlpnjljdfied_`]_`^dea`X\_]_a`_b_`]]W[VTW]SWSUSPNIJINHGKX@DEUHEHGIDDFSJNQQV_`SJXRLFIKHJFFEBDG93775332+/,*+.(+)/++(8,)&(--,,+&21)('%)*'$%('%%$3,'+2&4*-3++1=26>28ISZ[dBB9=<8:589:9:8<>@?SFGIAMNFLDGHIQUVRNPfUQUWPTKMMOIKNRSTQU[QSTVTZX[]_b[Z]X\Z^d`dabgaccdlyokugqhjjpmmmjdcdigbbab_ce`c^`b]Z_^_YXZVU\[VVUZWWSKRONMKNGLGHJFGFD>GILQQSWWRRQJFIMQLDNIDMYDA=@;7?230H44-**/+(**)(&)*)%%('*./2>%*&%!0(13$%((&&)-(,/***-1/7869@<=8;@bP:F@=7CFS>>588OH3<6569:>EHDH@EB>JJ=BGKMLEQQO_TZ_cLKM[PKNINPNSST[TXS\Z[Vf^VcbZadZXjhc`ecgmelp|yiknpmosmkkqkicedfb]^`begba^_\^ZZWXWZ[WSMWZYYYPTMPOMLKGLGMFCBDCHLLNNRPUPNLTSUqqUMGGAMHG?85533623713+*&,)&'$'.(+('&**,//*0&"$%$%*+$!#&',#((<*'*((-,?97@7:Q?;94@8BOE>779;957755856=DTHAGIDEFVRHJYQHKUMOPOZTWTTSUOMOX`WTVXUVYVXV]`UWcl_jV^lX]`ic``badbmp}ttmnmnkhfozvmikhkhe`cide^bc^e^]_c^bYXVRTVWYSW]RUXPKMKKPILNIAADHKJLNUWSOOTS\QZ~RaFDDCDCF@>4456@5434.)4.(---/43+*'*%))./14('+C&&##"($%&4$+*+/)'(%+9<734123=?98Q73G6?675?;F><:3749:FFC@?{I:31<9EKB;?=<48<8<7:D9?;<>>;820.10.37/*/+..1(,,0,(++0/-.:,*.0%,(&#%!%'(-,.''**10/63437=D@?>ICXRA=?8A6QG<>9;54=:=BI9FC;?@FQLIDFJX]FJMRLPQNMKLJOXPTUPMONVQOTQ_[UX`bgfV^daqtto~j^Za_]cl{t{wv|v}ps~zxwpywxpnnimygjcihihnmoeck^XVcYV^V`ZT]YUXOPJKOSRQTKHLPKPOKORRGHPRQUls^YRIDPQJMD?C8B=3.-24///+//0,-)/*'.(**,)*(/,&/1*%*&$*!,./,&('.,+2,48697HKNSNC\C@D9>B8>CEZE<;:89BD@>:FJ@CDETLfCEHS`QMGWVKLGLSRLLMMNMMKTRXUTQWVY\[^b]dajdeghnye\[\jjpky|vyur~{uxwsppnimrgbflrpaha\\^\VZ]_YY\XUPRRQNMXPQHh]TKMJPMQNKGJVVQ_ycWVMJPzODLLGA<;631740-.1,.5+++.:[75+*''/,(+/;EB510*8.-),2-/480-'-*--.)0'.*+''*/>*-&('&1(+*+;38;<=CEVUGLC:<;9<@:?V`S=>@LNE?B@EKGFHNLJKP`qHGKU[IIGGPOIHMEIBKOLRQLQSVWYWVSYZZn[pcl]dY^`ienjnjiogppu||w~z}utltrxqnklrlnpnlmlfba]Z`USf_\UZWX_SPLZ_`^khTSNOQ^RONIIE[]cuiagYWOIBIEOBH=?B:7462/-578-,2')+.-5ZG72-$*O3,/4'/*)+5.4J0/+))+.).65>?DITI@;5343284/-/,*)(/-+.08B60*++AA7,,+*%'+-*/)-./+-*'+088DDKGW_al̞sTI>:@=;E=;HFQNjxu}sQOOTXUWVUPjvLLL]ZPPHFLPIIPG>HHMGKJORXZV[cZ\``a]XZd[eguoohjehmqqpvr~~y{Ф}zuqxpxwsxnpnnwlkijshehxhhfd`XJMaa`aXYV^]Xa_le^]NIJGJMLMKVQW`_UXRUSTSPLC@JQB@I<::;6?:CBbqk}p\[Y[`bWWb_MRMNJEJLMLLJRLHDMMNPMLRXZX^`abUWcbd`]j^fllr{ttoeovonsq~òλwqpq~|y|tsppskmhkltsinlmkghUMNTZW^]YWW_Vacw[WWSODGNMPJNQP_gWPJONSTKJHEHFNCAB:>>?740--),8))/.G7=/,2/>.*0>,(,0,*-(,-65533,+6*028JMM]ZuQS[^vgVBCAB@CH=AIJ<@=;84/.,010/.0*,8136.F9**Z2)/-7),2:-1.3*/,).6.67JA9^TIUZ`SZ\e?I><=>L<<@?;Fgv{gTQS[SRLDGINORNQjrSLKQXSSSWRZ[W\`]\bfecmjkwr~vsu|v|tt{wy}pyvtryrro|s{nksmkoik_Z_]f_]\bSW[S^ntfXGMJSRQSNWVRfXUTSF@HMOTPYRKO?A@EPJAA:82,/,/-30./,0C15F*,*).*1*'.1.+0-2'++,*-**/+CI9CDNVbWJLL_RB?RGA::>C@>AFCKu|]RTRFHKGOQOLPd_w]`QMKQUPMTZNSbc^``wykflg|szyɵw{|wmzzx{~wvuqzzulrrlju{kc__^]`WWZWVXVdt^VOSMLMPWUPXQVVlg^pwJPOTKKLKGEJBSp\<8876.-0221+/.12P5/8-*),0/2,02'30*-**/.++-0./16F:9N?BOMI5?@MHL=@>?<>;=@DACGg˒m^a\QNKHKGFGMLRaaOGGKIRPHPW^Y]Zebe`ryvszn{qȰ}~}zu~}}|zv|vwonmho|pc^]Y__^[S[oeW[e^SLJDLJJTUXQZ^\ZZU^rRNNRKSEGIEC<>D7386;D;4,40,.2,6>;>=5)6367979:.55//0,0--.,3C/25@<77:\H<9?>=?9<==;@=9=A?AEJLkԿڷ}reRSQKJJMKHNgtr]POTQIQQP[YY`a[d]ijkuzwoqov|ĕ}~|{~w}{zyuvhllkdfwzy\`Xhcbe^N_h`]\aZVGEFFSMLQLT^^XXVXaY\QOTMIEEELB>:=><7648J=5=+-114:IED>2,+4D74/62030-++./0.0..029@=@GG@>U6::F@9CBD9>:9FD@B?EHKPsƽx\UONLLFIILTOQYSTQTQVSZ\[Z`V_dailzwmhonpr{㹙}}t~yu|ywrnrpivzzuj^_bdfb_`W]WQ_m_URJIHEKOOISPVVWV\VcgP]UNQDDDHEBCB:99943>A575.,0-0<=?BHNQi˯wdYSVOJDKKGFEcOTS`VUd\^Yc^d^\eb_bm|onntsw}}y~}~~~vuyy~~}t{~z|tqv~ymkk]aeaa`a][Ulg\QVPPNSKKNNPOXTXY[`][huXPKGD[JPC??;;E6846<8380/9/>5>@Z[9*/18832+5++*)-.,+/35+,26/=MIACC<:@CF;;JB:9A9=>>;9@?EITeëx__[SOLKKJIbbXV]Z\Z_ZXaig`engknwlqn|~}{rxu{}x~tt|ywrqkinl^cag]^WXZWVSSSLSPNNOTUm\aRSVTX]rcOOQIbUF@CFE;7::9507=>>533=;J:a@D3,086<2/8'+()((),)-+2/-;:N]6B:A7?IA=65594>7<=9;;?:@F?>AY7718;875@Q849T=:;==BJSQfòZYUSKKLNROMPP]RV_YXdkgc^dvixmgoxqvz{x|uqy~x|{}mm}h\gg_a^ZVWXWpRQZHOQOOOUUSUYXc[ZS_OBILKOFGEJI=X:577:32020:S;78F@3?A8;53666,(%%(%%/-(-00/424<56/<8887@9883M<3/8@8;499A=FMeҧa_WKILNNN^QTRTV\_obbydbZhwusmgpohuxeoz|wzzx}ww{ripjckkffl]Y\[^TSWR[OOONLNOSSWZUlgaccHBHDEMCBJMGDA@959CG).$%)$'' (,+2,2356568;H46103310:3+346365<EWJKHuy~]VPJPVTZ[b_`egitlgkmquizoqsleemix{|ytqxz}wq|riqphhlccbcd[Y]VYXXUXOMLGMTZPLVX]eXajbnsi[PMI?BNF?DFFDCK:24+0<:8759E]{\TaMH?80-05$$($)%''-+),*-00/43:660143<036B83264a=778?JJDDEgu\amgslcd\YSLJNMR[f\]eoffkkjklf\ltkiisakm{~|}}||~xyztu}z{zt~|sutpkki\efg`e`ZZbcYVVZPCGSXTXPNTV^hli\le\JAGD:?LJWEF>;C;:=144297:7ATn}QrnJ@=6<@@#$*-'&*'./(,331.628694?3//..62700/3;/:7:7Q_?D?X^NORY\YXY[a^gNLLWQVYek_a`f`ljgdigpgrflmhgkhzv}y}{{{pnzurtoosrbf^[nddfc^emml]fTSXNXUVVVMYYUXn__cquUWRIEPC>>A?H;@8??6:=6427@=ITah[]zPA7;7;3!""".'*+/./05>50324626/7/10,41/1345<8495Wg??@GHGMJKUWS`inombyWT[^Uh_gk_eZekhhigcgilklnegjxrvz||}z{qkpqtqlzndiidelhdihc]_]_Y^WTZY^o^SuMQS[^ibhvwfjTHGGGBDB@C=???<;97;>4AAIHcI``RGVNEB;*$&&$-+)(*JeO=5=53<358/26/41/.4/..3639=Z^?>AECEGGJKWTZfmxi]vid_c`btyoejkmdokefdkmia^^jcl|y|rqzyx{x}~zyqlnupnslckfbkfde__Z^`\Z[S\asbYS[X_tb_cYUQIHHGDB;>H@=@@>8:2@5:T65;ESobmhcNPJ=7%!!#%).(./UiD><961.,.1//51.*20500.7:49RL<DTZWTgxxucgfszp{|ihjlhmjof}fada]tjuvtzx}y}}ry~xwvt|{pnlwkgnldhimdbfggeZ_b]pky_X^^fad[aogJRQLBJCLR?>@?>FO:=8696>8AN\[_X`opubcil~xjoinmdejhmswiqu|wtozuy}xwru{{}~{w|xmvyqmsuiipziiepdmjgpW`lhci~gx[_bYaluc^]KJ^PNPGGGBCA9BJ:?;::9;7A:119IQb;>@IAJTOHSZ@2'!#"&+-+5306;94:0/.328J:-.)-0/12966:F@:7?IA;:CEJV\dl}xgiupq՘riqhmiepospuuu{xvzzoy}{~|~x~q||vkrusmkfhnw{mfkmjrm_]TZaekjrrvh`XUO[UR^`f];ObYPLFGCA;=;?F=LN. (')-^=3B>^5/,871-/.1+*++,0,3344>7>=FLX^_px]lkkt}Wgnfeds{mn}ymuzrx{{xrtqx}yopmqxxlrflr|qnilqrurp[fcaeegjlzme\OGOZmkedNIRWTWPIGCD@B=<9>9>:A@E@4;3CDD99NV=:?;8>69A81")'%*/4_f7>J/-/530-4/.11.1+0+-'/.17203<>:=DBKAGMTWgtsn҇epm{ulxsimhhffmz~üljvxwut}~xy~{~{zqvrwplruqjuulpozpqu^k\cV]c`cjjg`[HMTR`V[WRZPJMQNEIF@?A<<>?=?A>EF@AD@D:@OD8J755=1414*1:#+&(18DI?;G50J37J83)026)1..+0.+/281/09<99;>DHDWLXW_szfylfahxigisumhbgmήqirzusmvvy~{z}xtqpwyxwjsmqi|{qtkkY`XX^^\lfQBFLQMPT^YXlRKONND=E>:=9?C?=>B>>AB>D<@DK9=B\HBCMI;7<447=0/,-()''3;,16714,1C170.,G=501.1-3-+0815.24/3:=:5B>LGEEJXOayi_P`udiikndbc`ksccm^USfguwonhhyxsszt~v{pvwx~y~v~yz~}utztvslknsm|tojjd`aZ_dqTRUNGFFBFMRVZZQPZZICCG?IIJMG?BICB;ACF6;;DZ=:?79356<701,+(3*+C*835.&,,),/270+82,G0+Y-;.33,/:.1/152-5<;;:898@D@6;O2-5303.0.*)+),]835+.(0+0,5*-32Eg6611;/26635/.-/2:4/5>8:<@HAJNKNJVTY\Uaquyvlme_eY_]sfb^gxzhdiskciutmgjqtqlursujx||yzw|~|}|{lw|tlwspmnfhjufjilbbc^]W[kZSPLSMQWYUXVWbXPPPLNIJOJE@BB@AKBH?@<:C2O=@>;57,462//0*=*,,'*T1%$(-.6//,7;..8>0283A5D318,-.*.://5580><@CBHKLSPZTU[QLhkwg[\\W[`bf`nlvpnjqtudginhgnnqehfyix{u{xtxzvyw|vjuoshyr|yifhlccorxdcb]VUW`ZTQKNLMPQVZbWWO?>>]V:A44./726/-+,0)%62E-$%./01-5-9E58K94@4E7+/;:--12,,-,75;5CBD>JCGIJPXSQUUL_^\vpfc_`_XVa]]jiejselircmfrnrrlogckks{{s|zvptr~}{z|stksosonqhgmkamjklnda\VXWUZPOPMRT`QOUX_ePHKWFILIHJIDEIATFDF?B@7;J>P>717<73GWD^CD@8B9M:W<=6053082,+,.,/(+#"$#8:2((5-1,2>89<4FME4:52002-1+.20=5587C@@CHIGJMMOQXSRSLQ^d]_e^gXQYfVX[f]c]`sbcemkgqnho`cmoy{u}ts}~svx}~~|{yv{ywx{~zljlqahoiumnjcp[VUSIKNROIINRUPRNV`WSJCLIPdPJG?KN?_XGD??=95E=:BB784,C/*)+('%',)$&&'%%42+*--61,75539;Z7-5A./..,+/32469;FOXWOJG@KGGLAILH?<8:?BC@4DA956,+''.++,,+)(+)!')J;%-/3@2224659ZJ3:5.*,/-022657?@C@ADFBFELW_ZUX[emmdh_Y\i_]_f[}dW_ad`_^_eiijhjkfhpsss}utwvtwz{|||~~~vsu~{rww~vnjksh`_ZPKRJEHKMUPULGOPQOOMH6GSZRONLIJPWG?E;AC?=N@FU75744@210,1*)')*&%,*$'*-4C3,;EJ:;5I.23B./-+++0633;;IMD=G=ABCINRWTSZ^gxxrtgw\[Za\k]y_Zf[laa]Y`ammoneinwrsqsooxyx}rwrx}zz{wrzzsuxznjgnixli\UTSVRLRPLSKNFKMXNKNF=EPMPT]RMJHJaHCVXH=DCKAPB;9A411/001/)&.)$'+,&"#'6/2Q878LdLAB=?541?175-+-,16APE=7<::817/10,+/.-,+$*>+- !(%,.-FMB2ZWjoN5;561/,5=3--+25^I;8;:;EDFKHKLTX]\``bpkothkabq`TVgjfoago^\a_ccdafoqiyvitlltyz|{xz}½~y}zvyurzxrtlfjjllicg^ZVVRVSJJKKJUOQNOSTUSTUZW^TIIICA;=BFEAA?LY@LOFD9.132,.,-17+*-)('7.!#')0&-Ff74DPFH<95510,1,8-0/,SKCHHVVttjhjY[YYSOPZWVWUVVW_\\Vd_W\cwjsusciqloquvz{jpbl|}}|twxxx|zqyxqshkj}mi`][\VTPRSTPHKMHKIKUSVPPL[W_SPJHLNGH??B>>=RCOJHNEH>@613.88,2*+)##'-%2')(-4,1NB3BDE<8=>29431,+)7//,-5>QKXcNA9:/,+4:83*4+)&+,&%+*(*3/=;PIA9I9=A9.20-/-+(/+1/259>KD;;FEHN[TYhz}tkc\XTUPQNZW_]jyV[Z\\YU_Wbkjumhhlrqknzonr|}}s{uz}¼u~zvypr{mpwvtghomwljgddd^bW[SONILRNLLHHNONTJJ_TTOWQJGEE@FC@B@;CU5BJfO882.132?JPOONPPVUWRMQLJHBA@NNYEAAGB6OXE@-608/-21*'(((&(4:+2-121F_UH94,>A63./-+*/.-C+*33469;A>=JAPNYkYd{y]Y]Taj[ZXXUgW]X^Wg[c\ZZWY`bX`lr~elprmpqrq|rvwzzz|~xvwxvsx~|xxtrihyvgbihvl[^\QJL]MLOI;732/900,-,,(66C7:7@=ECCDQzeqy{YPm\Za`YYXZ\VX^XhSUi_Vbdbc_\suycRkgrojls{{psvyxwĿ}zwtwyrzwz|uvxsq}rkljhhobXY\MJGQELMNHMONQTNHKVTRYJLHKJFFDAFCDYoCDHKGHA;34602-/,(*-+%"$&#+%+577@=9O=36E42<2);J4.(*'++-2C>;:<]QEH@D]lohl\]Y_[T_a]SYXTcX^`bS\ZX[`jgweeknxmrlfgisnmhoxv{lmt{{z~{|vvx{styr~~ybkqpig^a_g^PXUNJKFKcYYTNNJXEIT[VuQHIILIGGGQD?GC\DBGE=}SE576.-E0-12&%#(%"%(+2\A7B6B8R_YUAPIVgivh]PP_][_mX]Z_ps_W[][Z`[[^cdehgg\fsmjjf`klnlopyz|{knu{}}y{ux}zw|~ynmowrjaa[^ZWKNQOXKFHW\mkTKS^DOKTenMIINNSFAFMIJEGD@I>DFMA:510./)+,-+##$"!"%%:3kTce>YD:97351(1C5>B+(&(,5HRM@FB;0./3,27+3,().07JAGdxLOQBGJVSY^Xgҍb\b]piaQS]lrptZSURU`aV_ifg^bpwnkvjiolqpoinmrlo~wxwzvuz|zz}umlj__^V]QULSONKJJOKPLUSRLXRTXY[_NLIFJGJACJQJ]fJKJH_m81.0+,/.'*$,&"%('"'<<8KpH46825480..9-0//,-)K>527,,.7/5208239300(56/DJNKJNIFNLTSddmymfZZS^df\`_q[WWYSVXQSZ]bU_Ydltxwy~{tovpsmsjp|xb{znwwz{|~|nkow{twsqpickX\PLKJKDLGJJFEDIQVTUXTRbUXgRJILEEBCKT}nZMAM{OhZVB2+%&(#)/*%&(%$#('%!=A<;3,2,-+-3.37=7/31<6:-,.4GGNF?<:8@47B25.8,,-*(!'#&,#&& P[3970+/0/.*-57.61/0,)30-76;27;EA9LEVEIOPNWbYf^\WTjSPXhcfodgic\URWZWV\]xeij`ohihaoqnkhosovov{~}|z~ÿy{{~~~zwzstknsiuwnqlda`V]VOFIHMIIBEYMDPVZWXbXWPSYUXNDFGAB;KEABDIYFB=?2<>>81++'+1+(3"#"# %%:;@:1-101,6/1/2.154(%0/829AhDD?=LG@EN[lJ?4bH068051((,''**%!% &!%"15AD9430B/14,',./-(&*.56=6PeD=?<:>@>BDCFTUOMIKOXdSYRWkYgaGISS[_]^ZbPQ][\`[k[bZ_`fb{rsonlghqokt}vvy¿}v|ow}}}z|uopmt{pjhh__[W`UMPKMPUILLRVUXQYZ[^a][XXSlsICCBE@CP;@7>XFC2552.1*+,,*****%& #$0(" 7;K102,020220+176$)(,./9>jD<:6957:BCKHSIVPQ^rciXRWZcblfkvV]\bYWSWTUSPOO[d_X]Y_bjzyojkiztpy{yv}uurzzy~~~{wvkwnoviih`\Y\WZuRKGGLNTTTRPUVTWXV[WYOABK]_UHEE?AC?*(*Z=,.;&&'88)--01Bk~G<35349:;=IKLFKKQYRPSTXQa`afi^bWUYUMQ\RPS^Y_ZcZ\XUg_^evoinrmf|u{{{~|y~zzurxurwusqnslgfia_q`YZQPJHKU\QXQUc[]bTUSWUSOPMPPDLC>=UP@8==423421,()***-(&#&'.9/+-$#%!;714,.))+Q90,0,'80(.-2:76BIE;15866:<=EBJGJS\[MROJRTS^[]Y_WKNVWLNZPVaROPRV_ZZVQ[e_`ivqold~pw|}|wyz|{w}v|~zusuvqmmij^mtl`_^SOIDEQPSUXYZ[VXWR^WONSTMLNNHGSOFF>>4220116-,),*-(,+2&$$#$$%0K.''.#9040.3+/&(%(**501-**'72;4;6;451859=M?ERJAOOYOHNKITTYXURZa^\ds\LPNPTPQU_ZVWU[sZZ_cfkwx||{w~yz~y}~zy~rtqsw{~upoghkkk[Y[\PLKLHMLZJdVSQORYUUWQRMNLQLJFJDSA=744<:-++.+($,*21542++1-()0214-097A:8?>QFW\LICIMEIVQUOWZ][X`YUqpTSRTLMSWQ\N\Xqg]]\`]^mvzw~~|~{~}xrnrtqn{}jfoyfa_ekafTMOQMMVWQRRRTSSYWVfQgTTMQNJSOKJD:;9732.2*-1+..,$(+'*#3%()("1(('"+2402,-0**&),-2)-543B0-+(),2.,66N35BEHZOWpVWDJSMTPLSUPOWTa`cf`VVSSLXLRY_VRRiY_^^]aclpz}}vvz~sxzmlnpuvqlnnwkfY_a_YSUSSSUWXSMVSWWTQTKZZYWPNMNLFKIDEC>?62261+0./(*&%&(+'&*,*,&%.&'#D"524//4*/)-(1/+-402CR6()%),2,//-046:FKEQWSXORRMPQRPIT[RKTUa]h^PaQHRIHRVYQZ_P]ae^[Xaaplw~z~vy}z{|pssurpryzostqheg^W]b^SPQSZVo|NQZVUUWS_U[ZiXTSPLKDDJNH<;=.0>67+*-+&%*'&)(')#,++')(*=0*&)+**);*7/,,846==).PQ4+"'.*-69//27?CKPpjMYhS^kkUXTQJ[bRPYKTL]L[MKGJNMTXSX]WU_`T`^Yddno|Ѽ}~x{|~~yx{usplmxq}lotsjai\RXLXMSMSiTTUTWTY]VV]UXPMWZ]QMbDGCEC<5K77;:.+(-*)*2*(+&(#0+-'))()&)." !1,*-/+?6-=u:-491).4,2$.1.-/60570QBINqfUtuc_bcXd^GMPJcZQTLOPNFCHIONZaTU\aW^hd]Z]_cpimyأ}~x|~{yu{xxrnms}vt{~caaYQLNPQSVU\TRdZ`Vp^RX]WT^P^{e]^LCTDE;E=WC<37/&)(+.0((('2*4:*)./.83,&-#)D0+,/))--.13,-75)(-$*3,,66*C-,,=;??HONIVrY]S^ajxOTIJND_KRNTHFNKMIMs\YZMSRVY[_aY\]filrբy|}|~~vuyxrksxyp{f^c[MWJPW\WXVSU]P\XSTQW\]_PQWhs`VYdUDJLG=<88C26,+.+-*'**)081<03139PM:00)*3-,,*0-=016,+%&,+#.(-72)-.170*07JFDY^XQk{udWY][TaUFPLSXJOPHEGDGQMDOYTVNOPY\W_fmcetklsÚ{yz}}v{voynq|{wptw\ZROPSYSMLOXYRRSZ\WQV_c^X\^fXj^QFAE=96;740.,-$*-0314/%,+*10@A+8>75(4260(*/5-(/00.4#%&')*1.-1+.0./>131<<164.74'*-./.+*,.,,-(I373/9LH86>921-*-'+)(/,2%''*)()+0.2/,+.//:67B=7BRbn\PU[VHFKKHPKJDFFMEEFDDH>GPP^SOPRRRUY]hfkigky{yvx}}~yhmmtltru~ned_^OJOV^KTOSQJPRSNZ_e_W\RT^Z\_IFSDA?OcיVPPTK\G@KCEIJ@HNUOLHGHSEDGGHPURLLTXOUY^aSgxx|qz|tm|mjy~}|}vr|omqptntrud_^dMUMNNVXPFOJQTLNI\`doXUcXTWTLKKF>BA@:99;320.2./2-'Z52--0,+)%4+,.*+*Y45,)5/*+).--1%&22"'33'*'(++/*..328::=JIPSkr]MXUTLGJCIRFBJBH][HIGDMKEDHHGOVOTIQ_MLd\Vglqjqro]rqyqzvjotzv~~~zvwywqxplrnnyx|~wZ[ZSFELJQNaSUSYSUKPOTdaXZW^P[Q\XLFKMG=;;=;=812.1,+.+.-Q3/--.,0&-6-/020=we/,'4/-*2(+)*&(*0%#%F+2-+%'2)3/B?GFF:863:=20/-)(*(,(&(*.+',(,1&6(+*0,--,)-/-'(''(&+*(+((' ##(%'.,M.-01872@>E@7=<;8:6471,6'(+))(-+'/)')8&/1*)-.(&*&&+-0)&),(0+02%,#'""&$%/6?/-4/'/128:E>?@:IDHTRLOHFHIHINJHO?>LOF>EYALIOMIIEOTJV`~dad`jvo]g}wy~r~jrpvlrozzy{|z||uoxwuyupmwxsnbi^]ZWXVPKMYQOQROQSVVXUY[TWYVUWVVTZWJEAE?B?G?AJLOJ`GGFPIT\cb\ebhhntwjqmsr|suqppy~|z|wwypnqwnyt{owqhpqopma[XWh\QR]QQNYTVSSUYZ^cXYXXT]WWTPNN[XG;;<6987:=GCJ6.0*+*(.)*%%)*+.+&--,0+-=),0%+2*@*$%C.*+-@c3_)''%())'47>9/6?1337GFELDHJ\r\[^ZdYrmmjgjmu~|ntok}sszyyxy~}|}}}||trqqmllktsukhejfiaV\YYS^PRSTTRZVZTUYf_YVUXOQQWQPTOGFDC?CCLB@<2G/0)'.>;,4M98@QGPQ]^c[]a\fJHCQLK@GR?A?JDBHHA>DAF@HGFHDEIHGGN\Ydhmwujmlglsruxzhntlpz|~{~~~~~~}wztwvzpqqgojfljfg_]hb[\UQNQPO[[UZthZVTSQMNVPW__^XVSOOIFL@CA=HEDC??@D5SH=5:28-+0+)((3)*-29/*541*&(("%02%!")(% !6'%%'$" )/>N|~EE?T/-11205BCDFFIDFBJCDCACFNVZ`dkgjiipqfz|vojdksemw}}|~~}}}~}|zvwytsqr}lqcegddcddg_[UYLMPUWW[b`VSORV[XWYXYaZYVUPJKHL_KDDHFJ\RA>L>JQX<648++-;+****',(.(15,2)0%%#"&.+'#*(6"%('#$".&'&7HNC=;601.2?2=EB<=4-+)-.3((,+,*1)),22C.*-2-"0*#""!"" "#7,8'407@UD7+)'(+15A\:DFEHHEPU[]Ujxnlotyqo{w}x}~xzv~yz~|}|{|}{{|}p{tlkpqpphbbnn^ZVZYUQPTNYWZVf[_]]mTWWZUSVWXQUuTNGFEAFDI^`YeJUd<8CG8.,.).2)*)-++*)+/%0/8+%*'%$!$"#)#!"(")')"#&,27EA;@94*()('+9J54:9E?DBABCL?GBEJDKRLV[felarzy~p}mmuww{zpsoutx~}{}}y|y~v~yqkm{o|ah`{dYYV^\R_WRObV\OXahk_V[n^^[XVYUagwoZFIDGGWQSMEGWx~sMXB=:1.-)./('&4W0('),-+-.%%,6',,! "/ !$%%<6&$&1BEB0(+E4.(%)$*F262472AEXYIN]^dTOOQIOCEALECE;AADUCECHFGH>FA@FJRPbamvnlwœxtwwpruxrss|zvso}wz|~}{~{{v{ztkusnund_^`oW]^\\WXUMRQSeZTZ_g^ea]\WX`][WSSabHGME[@M\NLI@YB<:<2588;/,/-2),*')+2)+,,*,;3(*+$0((*-,*7##/&#"%'*195C;D5<5*)&'./,1245;5HGUxKGX[jLJCLKHGFE@EBF@AAKM?KAAF?F?MEE?=8<:9>3,+-)3))'-4.''+&)',))'0+"%'#13'),$%#$.93#2-NB_qB/8-.(#((*03/31:9@Mbb[TSWKLNLJCHNFHB;=CIDCCE?DVCAFDJ>B>@D@IDDRRgfxrkn`jkaecqZcmrrllquqxxps{yy~uq~yz~~|x||xuntuwtoroesqklgtkfbcg]ZbR[YXZX[PY\WWWTY]_[a[RTjXXVQMLHYVKEDCIVFIJVb_DC:=P:25?4+,.&1+-('.)*%'**-'=+T/(-#A0(*4''(2& $#5$#&5-_{@,,,("=$@:4652;9A>FF>9LBBEMhYPKNRTdSAKLQIILKBCFBAE@8?BBF?DAAKKHI=CCCEN`mdbrnahzg\^deZRXbhmnnpjjmuvynttyxu~{}{|}vqy|uwxrronw|wwmxlvinncf_ba[be`^^Z^WST]^TUVT[RZ\WTSQUUXaYUXURQNYTQRLFHC>JFEDMIDE==A=?@BE9=>EC@>ATKPW_]cdd`|~cjkgpiiZg\a\`s~vvgf\pxqs{wtswrvy~wqs|wpminnqrjmvmiuqlpdafc^Z_`ggX\WXUVUWXRPTUZa^YZ]XVZZV_`VSUOQQNWIOOEHMBBFCD\TFG@IkU?99>E;0-1/-/20'*01%(+'(&0('.TP0*.+126$,2 #!P%! !'%( ($! !"$%##&2%+.:9F?CJCNHFIKUMZ\PNPVSK;8=BFG<7:ABBA?GEA?@?=<;>AILLLRWwiddog]sqi^R`b_ad^pupsjf\gfrun{rxuupqt|||~yzxgljlqqktlhmdanqf`gY_Ya]^]bWPTWWWUZTUTUWY|]lSd_\WWZXaaZV`TPNLIPRD>;B?>EF_ONP<>AC@A9/>5@/3?+.(',1''+,'*((&4$1))(*#*1&%(25/#(+#$!!!$"&"2 ! "(!%-()+,043;DXFPDHMKNQX`heWceJ86>;?@@@EG>@?DD@?GDCDEELO[gpadc_jucRRlghbinpebq_Yfdxprvxxqtuqw}~xtqstvkgnqrm{smrru|m`^gq_ZYcZ^[\SW\SV]XZ^`h^WPWVRY^Yf[QVZ\]ZRSSYKKHCD@CB>=CKQNA?G<8883852+-.,.0+2A20'5(,-%)&$#!+%2)%'$#')&*0-3(,"!")3 !)$+!!" (%)*+)&(,C+;<6458:CEMBKVXYveqxY:7K87BP@;@@=B?;CIC@?D?C??A>AFKXddh[Za_ede[^kmrptiuyqoe[`__epnpoqtqwtppnm}nqjlbf_gjryxe{whdo^kc_f`_zc\e[U[\b\X][\]XT^ZUYZ\YYYYVZT_TOLJMA@N;6FFBBAA7;2:9./0,322/---,.-.A2-("$--%&1(! &)&''+%#)+/(&$"/ %!"#$$U~% !#"$%#',.28FA1/7>CBCGIPqibgniD7563;IFA>;;A?:DD=87BA?EL@HDFPPQ_RVb_`hodfeegykhfaqrqdip_Z[cmolmxmu{ozxrupvifkmjja`he`chf^T`ia__]ahtbbcmfkg^\\]WXY]\]QRMTn]^de^\[aYWTRMJGB@<<=?EaCHLGebdjaS^qJB99/;F@A@:9@;?<<>>9;CCER;=DBFRNTPWcd\fpiefcXSgppbhZgig`ddwjcmefkvmpgrnyssmbemgj~n`f^idbUgaX_Wg`Z^S[Y[`qdVXW^a_ZZ]YYZZ\\\YRTWVY\[ah\W[]\OMFHIG9>7;7;:;_a>27;68662111-2.*+.'/*3.(6(#+20+&&$$'#$$'+),:A/-(-7'$.!*#!")F$ # %%.'$,27565=?B:8<<=@>5>>EEC@AAEKWSTY]fnbadt_\beshgqgpZpkhnhpff^dnnmi\ailhihlfrbgkc]^YUX\faf[XXSTXcaabWWVVXW\aW`]UUMSRSOVTWUVaY]la]WTRMKDEI_>B;=;=B6F?J:9;85/06401+*+*...*%&(.F(%(-+*&(()'($(;*(IP#((J47%'!'&($$*$#(!%%$($(4326A9?J9CESJRNPW\XVNQSD956;8EcD@4:<<>6@@>@FCA?E=C?CIMQ\SjbWX[cbhad^edikirlagqliqliiZ`df{Z^f^lfdczjdbmhjlc_gd`_Z]TV\Y]RUWW[_aZXTY]YaYcs^]\YXX\_]YTV\\^d\\YUUNHEDBBFL<<;:==K?:8FA@EEMPJUlULQGJLFQDE;67;Q@=;;:>878RA4?AC<747.)(.%-/**--*)$!$+*,,0()(')$').010*($%'/((+&9%$%& '!'! "  % #%-51-/3@I=>O>ADAAG><579;?B@D9CHJIONGJOYxb[\`ag``[chervokqglln|QW`a__[`]c^^f_fjsmivntbXYZXUae`YUS[X^plqeca_baY[][YW_mi^ja[\c`c_UUWPMSLMNNNE=<DEaEAQUKNJO[\W^Z_fhfVa`mjdohnmhnjgi__[WftfTWh\^dkehfvp}yfeaV[Y\Uq^iVXXdYapuzhlfei\dd`nZbki`h^a[`[e`YVTOHLTONVJCBDC<=E?89>A@?6B66271/**,,+.1--++'*&)+)&.-$$,'1+*(&(,;75(1"1+%&%  & 010! #%"$&'(0--71?^9@MB@?O>?I`j^HBHHGAKNODK_:45>>7?7884>:8:=CL65A=B>:;A=94;<7:7761./1.5)0+($''%%-2-)()'%#"#%.(*+N3,+(,'#&$,.=H!%!#*' ! ()''227;:7>@@GEOM\MQHWTWY[VbZ^ZZ[LeeekdhrpZdkhj^\eWT\a___Q[Z[[]aZkbWY]ZTV`[bg`]`e^^`\\[[]`a`djdc`d\ndaa^a^eXYVVNLMURLVLQE?CDAD:<<;47<:ED6325332/26-1-)(012+,$$()+*%'"&)37*'*4.$)-(*$*'QC"#(!P !  #&"((-177CEBF=??DAKM:2693469=<=?;<;:=@IBFCHHDE;7Clb62A488;5858:CR==D>ACIISHAH@GCCLKKRW^q]]y`m]fbfb[U[T^aaa]Zc``PPTYmxul`nc_[Z^_ef]ddd`deb_c_aZggaa][[jf^\\]`a^ZYUV]fxWQNMOdwVYbFGJF?A>E=>>8<;<<<9<@=;??A_SIPFCDSCCHEJKUVTT]ai_b\fb\__feiaYPQZ][_btps~uujfbj{kcd]__e`^cbkegfe_]fb[iggj\Y\X^VYaWVcZUWMRLJLGKPVQST=JGPT`GLEJJB<>CB;BIHEKACa@EBDBPNNTX\`W_]^c^^e]^pmja]^_Ya\Vioetx}uiccagfb_d_^bh{mbe^bablakZZ`U]]WVYWUQPJPHJMJIHKJKAGEbZWarPdnB=?<<;;A,1.*363//-+0&-02+)$&)&'($+,(,(.(,'+%'$" ')&!+" ##+-/  %! "%,/+.595:A=CEEJG@ATAB=B>:9<:<:;895-,.58842299:=:<7HI85:FA=@M>FKICECKbXMXZVZZaXZ__XXkf]\`h^hjdfci}zvlc|uohf__\_fkce^la`]bmhf^YT[TTPPLNKKJHKGJJBFKJCE@ALDNffRD=;7<697?5212163.71=0*,-)''$&#$(++,&/*0,)-)6#') *%*$$ %/!"0 ,)!!"%*+,3145E?A>JC?CABACG>>:;<96=9;:=U;3+743157:I8;<599@98@>I:EC>FD@@GFft^VVURZU[W^XZZYUi_\_W\aX`ebfsuvznlm`_`]]Vbd`aZdXjmka^aMZSQNTRcLGJIHHIGKDOJADNB;BKHSdRFC:8;::926?3:3,48F-,1&,+'*!'$$ ))/'/9/5*%*(*$('"'&$&% &2 !  #$#+1,0AE?F>A=:I;DAGD@C@?EC:=@88F87APD48/7>:<@;:?979D;FDEC=GC>LMHNBl`SOTKOPSRRUSS\Z]_ZWa_VZXZ^Yffo~h}wvvrfUaWXXbdUYWW[TOW`^smYXUNSKINGIFKODGDCCGLMJEHMIJ>DFKD^_QCG>?8:?:@f1>64M>532,)+%*408"&&#$()+P2.),+-')+*$&&!#%('!" $# & $*/2-59:9GFA><@;AGCGI=;FA=<;:;=X4CK9<2358;8576=>6=ID<:@??AB@BGINK[FMDHEJFJIYVPPPk]VWUXYVTVVXX\fc_uncmco|johl`SV[^RZY\VRP`XYXXXU_VSTJIFLPPJEDHFPG@GNFVWJ]NDCB>CADFPGCEC@=B>6BI>=5>A9D>EEA;;69;5?3:-9142/388458=;8;::98>FJ=ABG?EJ_jUCJABMLPKHVS`SQYPXMSZVXWUS^^beXYYW^cnci`\]bXXZTZQPWTgZTVSRNNNUTPPIIIGOJGEMHWFGEDCJcgigRZC@KCDB:8LJAON71.-3/54/)>8;8-3,)-12**13-*'*2,%0&'?T$"%()""!4 # "&&($)$)-/826;C=7;>EEFMB?>C9F@;99==E7=9;<1:07:82678>><@;C=E<:E?<9:=9<96BU<69C0+535'*1*/E-)3*),(*.,,0(*'*%/-%&$&.,%##"("+: # *'''!'*).86@7?>B>E>AAIJB_oA@87298;:41534146;61:83;>>AFGG><@>ECGA;EIPiC?FB;=:96:QI64;6A5390-1B3%(13-.&*3**)#,*--.-+5-%,+24)+':"#!$< 5''#!1$$#$.#+)%C<=>;>M?C=?@?=FC@@@<=:768492545559?9/>==BEJU?9;?=BKSUENKF@BEIC4;8:<588>9@31996K2.60-%))+1.'*1-0,-1-./-1+,((3--21577" 9,1!# '#!( $ !+*)#%(*./<1@<7BC9;G?FEOB@Bc<3:957CCFReXNSEB=C>DG?NhBPI>??>=CCAHDFEJZKLPFKCETmؐaROKFOYUQbZUOYSWNPPMI@CCDFJLFEI\QLC=?FG@><><9@?FEWAG;;_@<:;8;388950332260@5N71,+)./0,*,08,E:2(-50)((,.6)"%11-,'" 3G*"#"$. ) "*7*&#*((=15736;7;787FEFM9<79DN@7569569><6;=<15;EIFL|P::FF@@BJYPOE@J@56<@BNFDCFMNMTMON@Lwy[GEKFMGJOMQXZQSJHDKGFDDECIEJEELEBCG@>A?B;?99;A?>GDCEA5.8@H=CBCRBD?KB:=BE@:??RL75A?ADDAAIIIFJ_HGJKPcQUFHGIKLLPINNYNODEB?CDG@?AB@ADGGGB@CA@AG?@?@:7;98;HBI;:B;DCI?]TX?8HK@:78BE>789:?:324.39C8?B4.2.+);-$)(.CN@0,.20&'*);5()KK11L092%)$!".281!:#/,$"&!,'+5&.1H=5F7<9?=9A;@BBIIC>8@GU;;;::AEF00:<=>C>97K=?9EM=PIMGB47=@COC=CEJGDFBEXVTQ_JHSNFB<>@=@F@ADC>GJKFKDCAGJB9@787963BA>4^?66337241S7;;1+-)))(3/+/-64120+>./9)-()-'L*,/7,#"1(%0$#%#(  #")'#")%&$"%+,1127J493>979<;B@A;AB>>NEKNMGIUjFK;8@FJDCAGGIAD=>U?OEABE?D?T]hWN?MFBAH@BCDE@D>DBDFCF??B=;9?<9<>9A===TEILcE>B99?778;95;52337T823107@><4()00.2F330/93159:P62@*1()#3F%-##%#%#)"1%'#* # $$7-'/-+*12@6<@@=7=9CJn_n=GA7B95ABBD647<>J?653>47;<>BEHI@IVCI;===BRF>>D?A@Gab}~ZRCBFCA<:BB>=?>>B?5<:>:?H99<@7448?B?;==5BEE;=>E639;6;?5;57243=;2957,+1-1K:,+157X9E33414795E60,*28->84-$ "#"&((&5$+!$1%"$73,..058594;7?9>OkhjC:6A9=>?@>=E=@<8=5;7:9=;=B67;?>?=>@F=6:9KE=>DH;91765455S@93:/.-J4+5.5244@4EB8/ZB9:8;;>?;?>OD5=P=89444228<;:<=KOAB?9?>>J=K??;C@?LJ?B@CGPG>E<9?:==<==:A@Q}wZ>=B@>?88<95:>D<:8430>?96888;<9;548;15HO318M9A-&&2-'*.0362038823I=A;@BA@99<9:SPC8507;??;><46<9?;>@CED@8?B<>94D?=>BQL@TB@@GKAA>@D;86H=78>?>D\[HG77>9@J:>;:=E:N89<=;C@>KABC=??::?=17666:9<6>9<:;815;4=C63>?:C=@=866:;<C:@=HNDE?XL?7:<8CMZK>IUVD@>bAC<68AAB???7B?@;E=:8:>>@9:??C<7>BMCAA@?G>=<:?GC;7565839??C:92;A37/87THAO:M6KBG=FE=?<>?H@ArJP79B>FW[==Q:8@99;E>=>CC@EB@>U@C?=:689A>;;AAB8B>EBLDB9F?LHG>C=C8=J:47<.98>;C4;F:548<:71XA?>G;;qC;<83OI6hc8=942-3308-.429@612_*)-2-,.-*+"41)$(">?//2F#,$6& ! 2#%" #%(&',).1*237-.>bYBAB:>;:9;B7:@8>B<28=O>A:C97DJGEL<;67;9B=;DA@NJ9>FB>=4:O@?E9C9=6858>P?9>KC9<:762-=M7/66]UI>5973:D.<=@00/+.-+/7;/0.4./.-8*/1..3:23(+'"#"#++.';7')!.' &# <$%!!#+ %.0.;/=2/0<:<5?@=<9;=A6?:5<:7aC91>E>B<8HC?KB?KA:D]EF;MHTEC9PMJ>97@A>7798?:9:E:<C?>?8=>@@HDH>:?A<;::<D^ZFFA<98=87:9AA@W?=:?7=2N9-JZ3275NF;A66:368+10461:+131,>@3/.0..0)*/-23.3<8;#&'3&$(.*%*4.*A1" # '$'$$5)1161.&0>2-1/*+18>98A`C;:9419;D7A<::K=<99955>A>O>@HABPNKNF=ROE@:<7>CE??7<:=9AB8699<>986AB?9@=C?L@F;JG>98;9;D9A>=9:FJGHLI;9;?;;KhV[eK@7;8@6567785/4-,.0:219>872-.24@853=7308/2/0(-1+//-61-/>,+?(*-"#&.8)4+&90%% -*!0*(%')G;6/*60.+.33/>3>>7>=>H;5A60@;<98;;_HNVPDBDPDGS?5@:A=98:5<8==E;7>=969;D<;N;=BDGE@A??@;@?>CMXN=DD:;5@E>C?A6>>>=?M[BJ6::?BUNNZb^HB9@38<;72080/3-'./36)041<0,*=31+67.>77+5-**.->:02/+=.*34,0)' (+)8+)(:,"-!$,>&@0$(+/7L;315+.13-05155:;;:CEV?8DBL9AADE8F:ALqdTU;:86;=;IYNSRDA=KEBEC4::E<@8J1463:::554<8C;8:@=987=ESVjTB;;;>;ACALgf?=F96/53252/.251.1021.//>+591?24-.+-././/*+5/,*(-31(1(%%5-')$$8FS)&')-,!%$ %!%'))'.3*-?8.16/.738>A=>AF>:<IFOA56>Nrh?>?:5D@GP_k`G<6968;>?598\F6:>P<;?:@C6647?1=488@>?>C?97=?:997:6CEAB?>=;=8=?97;D@@9@CG?_YQC8:854.27+/-387,60695+/2,-.*01=0-+8.'1).,)-*,&&&'7),.))&'&&+"*/)5-%$+!+#!) ##% %.,',!-+;+2529/-23676B9Q=TI\DJA>_n[<36CdkRD:5;BA@>HLYZRN?979FJ;9C7A?<7;;<9EG<6C?=<7:>TNS]H6ETB=C611?;8;4?7535:8:8816=>?5<@@>=:>:77FJ=898/57:76::8DGIMK@?A6K:=7<68417;<:/:63497;732:=:7465DN3?:8>FR@V}C?F6?99;:83==XWOLCDB=73@3>.,.-0/*.823*'')56-)+*,.3%%'('(,&&-++-@38JmfD;90YI0)+*'#!'4)"#&2:3*%$%$,2$*-/(./)5-.3-:/==A@9F2>?@GCI?==?<228;=B8:?QZfo8TCk_LB9?=659241;>;?9;?3BFJ5I94N<>5569><79::;7<>C4366308;989943666>CAA\E=>:IH7BM50:DSsJ;83C8,0.,,2;:/,(.61*&'8E94,+020*+((("()05*8/*-:DIiíjVP23>/('>)-&'&#%#   2C025'*" %')-57771,.80..11K==7?GQ6;BHRA=<;6@8=8;=3<=GXuF:@yUKl9A;045-,0@DS>:964=}H8A2594247:M579759849>B9:<95667:38;;89425:@F<<[hN@>@:46;8@9UqA922824-,0-1-/34-',4.)0;482*22-(-.-,)$+-6.--;523;Fwە^U;DC21.) !(()@0$*"$+$H,&&*(&*)$&%-G2B?03655/4689<2=;8@;@=ICA469FaUG>ABNBHHXCM<9;@9308969;338:6?;B8@KO>D<>>?KH:76-748:21821/,**762+/L3:(1.,/.:265)./D3*&)*0'%&%*()*.3*/+JLTD4i]2=40%%)&,#0*)!#%+"&&:*'CR6%)++)/.04313A1588>;9;=D<7CO=9ECBeD=CSI`KpTUOHJ53239;88371<6<55A9==DoI2552635564358378C758::4??<;;79621784814:/,*+6-/3*)+15;51-.-3/)@62@.;3)&(&,,+)'G)#(/7;)%)O_9I2328/@=+4A$1?$*$'4")".(,3+!#,,*)&*A.,*?037684E:69DC:64846G=823652<9>?16HEE;:9350/685=4865:68/6;<68@A32A653=471240./+3<4202-240I3,2.((.4.(.74'6&"&'6*,3),'(148..(5(--743.,31(&;,12?+#&)($ !"!)103K-!#.(,&/8>.-+0-/27;9c61;NB>\D7LP;==:66:C974a<@:>@734697D<4486552097?:4678<756:P75CE;;5D1,675A.8@2454/6018,48717.,.,(/--,01+'&&,&&(()'$))(*.,277;0!653020/07.5-'*+//6D$"#&G,B2 !"%& $>65++(.;7/474>163I;;?<7;MR?FA<<?06;?581313963266566746;]<52797:97>C=D79~_>=:5:@CB94.14<-))@02;BA0C..56E/-32+&&0)2+&)$'/')/0+,)(3Q)23D,'/8:XSW9LX.**)0'!"!2$#-'++!-$%&$#,4)%,,+(5/2;54053?D8_;B;=>M@ARTFcy͓aiwREINaR169:579CL56`>;0,44B:Py;BB>>E6;45=5/3<<59542/5526=?HGD542?15736:<49D6M7;MQ:6:684X7>=51.-/1)4%)./.0/*.;3:4/579+&)*.2$-$2H-(075.68'(,8*' (+,EbM::6B-/)+('   #(##"&"!$%*%&.1A&'',2234@9L/;;5869BD@?E=<9;;Ab]dYynRUc\R\NL?9:<658;258;bC77-48<@W6>U=2/5:B<9<;8=9577;7:5578=R]D505?>604<57:9;O597:C-:4;;64UB\O403)12.92+2//+5.-85,.H6=7/+3.";1*(*)155KA5R31+&!+%.(181+,13A1'&+9' &6 )#0-$$,)#&')I,)($*!&0,*12057599389=>C96I9<58?>8DLPOQVUKYXSMXT3=:3<8@jTS8?;BA:?725>\=6996EF555=C<:CH]O<-'3/0/2,01'$''+*,)1K=VUD5+46Q1'$#84++")J++-$)!(P"$"!)&(.'%&$('"$$$("%),(6?J8.252=8620:@9@<8D4FF>=G?dIHJZUQYtYP_?FP8;9J;730L1035;4@/ABJ769ZGA=5032969=8/7E475,%)88<4?-74.-.0130*,,-(13c-1;5/28:16:726*2'$*/,,6;ZLPeF7.=>.,H*:*()*"#K!,<**$ -:$"&#%; .($#*%$*/$%*%$+*39.3-.46.4+9@24;B?85C??>=CTG;>CBGMTsmTMK;437=AB7,81,.=?3;57:>:D79;OG05?95696=MDA;977<588@=444727.1/047;i35:34470701/72112,,52>:22/-2.39J\kD;3/7*%')$'&1./:Z:?rUWRg%&+1+M,*LB><%(-.%#!'!#(!#"!+$(+%"%&%*8&++,1,+33.350/094/0:693;289?AG]ESE@?E@E[\J226494@]55;5532;42263332<>@7<7<<<5:13>>88?SOVUPl;F>>733<;28570:41516A?Q54?11;80O.-+52-/13.5>?GA0+2@@GˮeKA41+0'+)#+A11QQ92OA:;/<0-+0*=+68+.,)$S ,! 8#"-7.-14%$#" #$"'2(*+-()',0.2,622:7..4124831;;BGY^O@JL9BNLN`VL<07:;9BF8F-12;968747207765959;59644:C9<99FSPbl_JCCA<642066524/30*1206A8P//42.0.+),)-F,&:6658<9S;.*,=jvĦ^S:,1(-;5'&#;3C9D<0)2+4)(-()'A*4'+.2;25!! 0"  #"&( #97,5-%!$$*,.5,&,1-2.1)-.//74.123/3:3:9:BVKHWGOF:;8BD^AZ=352:68M<=40.<35?C;42538415/9HD703:FjD?A@?CZzwpLLA6765303O2763242:73>249685:-86/),3,+-3.1;,8:;=.(-QKzskfYG>*-#'8$%>./1:E;:)-31*%+&"+-8%,O.><:0' ""'!+$>$+ $(?, #$$)I*(6-+*.-($&+,3>C,13409,1:;37I;HklGJK:88BG5F8079<7306:/6=67584?24?:OcvkLA4774628,481475>;A7511A=C3611.(.8)*31())6:Ug418.+>@LOOW]J>') "%$ &*)5.bP*E1*)(%#D0'$?7I,/J/5%  2/"K%4!*!%'''#*A%,1+(052'*(*,-/a6114.8026934C6=IXOoGEB6.#)-::5500526:7F;2BA/3A47=>T=>5555>?1;=?6548@_<261H8;352:)20/1*(2DH,D3'/-9M_aRI@9-&"%%.)+''(%1^),F/1"$)&9*%<"5=#20*$$$!""%3-#*&#!"###&%(%+(-,E8,+*-//344+,6/C/,436-19:XEUIMOI::'$.092/5)/3;18:8903532:0878?;78;?5OA<5L=3:-B*3D=./,./-:,@>++3-+/*--C>J=261*)&&$ * #(" '&%/#%. #('%&(("%0%*$#& &*'!.#/38!!!" $ )(.&',(%5,**-/3(61:/,27/01340C5:LT@7?25489855=96;967755=B;66IMKMPh\BG6<9;11.45A:2/=4.823092/=-/101-52285<3900;33724,04/0,26*%$+%$ '!!1&'.$""'%*&(&++'D/&/)&" $2!&#=F89!,  '"%! , )M*'(&)+.+00*,).+3.54*?0773669A4954:=786A97.=,<5C336840)../1+*+,)()$+%$$&,!8!!(""& (%,!%>7%+.3("# $$B3" 8#!,'#*"-"#% )%$ $8+)&(0:B+04+4/514.2//59;12356;=BM=7D>@7F7DNL7-/..44/,-520*89@49EU<<1886643D51<@B>63040624,*B0G/*2/*.->OO>:H984275D636,0128@G?1-/1462,194921,n?\abc:4-02.-++3-)*%$*))'(($"*&5!& &  ((#$&,"! &$% ! 5G[5+(!!!", #).1'0.(2+.-(.2K@-*+)51621<8HM>9;>6>AE867?Zx?845667,9/2T732-7-40694>I<8>77554GKg0-3;>>E75;]@>>81Jz89P=C9CA75261**8BO?00314.,+,329K646:5~eF32<9=C2789DNUM@?;C310481713454/5/2;92/0344>H.4+19BVY810%(2,(/0-4.:5#V*"#""$ '-"$"'$ !08'*$(*''!'#$'%"')3/)$##%+)&07-!#'V84*+'")07*&8,'9 """[e)'$,#+.:]/+5*A7,**(8,1..3,.-"-.6,=G86EFcc18AOG5528-.)<8+&T<3041+**.++,27?80;I=<-5+0F9:92>7604+-'*/M0.ZkJ45j9--)+%%2<%//!+'!0')!F%)&B3MeVd?9.)+ ))BET*#""",.ei--?*7?5),33.(-1-0--'/83-4.-3;5<@5NqO9-/&0+/0+1+-5/E3*02-+-.+6<236>vggF43006,56,4199//821/127/3368<7:;68C=;3768<56F-124A2',,B8Z311*-6);!&$#'D5'hZW52F8'0$#,5a(!#(!5! !, '(!+".*?1%%0.B_01  $?5eE$ %*$"$2110^,0<0,4;rM7+,40/.&(59/7@*8;=/:,?7,543%(*3:6(2-+*-#).9*,(.13-556JmaKSC50,,;6153,..**-3*14.4,04176845@88668;2755?3.-5=2.)45/*.(--%#*A&)81()&4&.>N?BS,*%)&(%#"'3- +! ,!%31.<$&=bcܝ[S-)" !%/.V*!!#,+"&!+,+D-'8>I>O8068+-+"&16*-42CG)+=-(5+#)(04,--)!**).$$)(+4('6/@199.AUeNGK>,*(*2-&*,*-3/4.,/-./-0./646/726L5>/V33431/*0;;,8'4*,3/$"',!&,5%'%'%%+ %&3<-%D-$"&$!""1&#*! ((263:@7ICWȇnlq-H)!$ %%'"#".*"%%**()9-8Hop_M8($((%'&%%+,)-(*&6+=D+3:.+,((,*/))+$((%$-&%--3+,)%)(2:?IGIA*-)'*(+0,02*+/0+*-6:0-1.--2/324671>874445-H207510?01-%&;#$08$&%*%$$%$ ! M,3+/J$%!!7,(C*K(#9(()IQMKht3%%72!,I%Y4)%+-8@<./6?gi`GW9A-4.&/)%+)))+./,/4-+*(%23)+!"-'-/.*$%'/(%+*R&1**+1>A*029.0(,&$(4$(E.0.00*1')',1-0/O1545CB:2:."& -M1%$5<>?A,7D&&&'D)'3+%%#*,&(# '*6C,&#&$%%!$%'),+,(+)2,150;+-3$'"/(#-+>TN1,,%.I)).13B1163003592=9M>B>3?71>?>/(+./##&+%0 +6")"&'(.H'A"-"56Nd.%63C &A!'#4/CV`K35M/*>'%$$!;!&#%$+R6+ )OvG:xyVvU:1A+G*#$+&(,(##$%#"*%$$##'),*$%&+,I1)-$(%!(!#" '#()+&&($!#+%(&($"#.%+"%4_'0F.20..1/3\33bER18K9JHD?C45=294#'('$%+*'((*&5"2#)(#4 4E"")"''$#P(-XK9+E87>5IL"' "([Q'&%%)G]C:EAZbEM,:-C)("&$&!#)%% "$(.'&!'$&("'$$"&22&'**&"! ! ! ./2% &)/#!#&%2!%%,% %&$7*-;4-'0/7=0?54((&-"" !! !"&#%&V-(5#2! $$2+V 0-*38 !#G""2Z*'#),.- ,$%(M%#$$#/SH=<33gG4,+!*!%"$*%#/%( $+##$ #"%# ")(')9Q&'/*$&!$!!$*%5'$" !$'%#$( &($%%$!)0?;,';5:?2;]YdY]?71&.8..;2.-6*')"""+)*) #!$!9/$"1)*1 # :;8')/'$*;%3-%",%:c=)/"%*WOM3/4qV7( %$,(!)#&!)+"'*&)$%!#'#"""'%5#=o!$(("$") $"!!%"!!!+!&-+.($%#)"#$223iG003?F=88fN^VF/.,(7-)( (.'(,"'')+#' $$..G/)7F&"" +#,+"#&B)*!2+P;7)2(F8VFA/52:4-/%"'6*'0%!%)%++$#,( $"# %#)#&$)2' "(-&#""?5/$ )$!> %#+  -! &!2:-&""%]Z9)0',c"0K*-&!5%"##C-"7",2/+0&*!#!##'&!!$"#" !%-#'#$#"%(*%397D7,IWbF9-+ )?9C#!4,!# , $ "(/$# (+& .uf=&%&$,)G'=EG',&+ ")$"$'!!#)-A404*#'!'& #"#"&131##" $'!$  " +"!!* 3#'&%)-21ZH("+""$#7#?!#E& -+E 4J3*"'"#;.-,# )$&#!7#!!#*^1#X#!$&"!(#!!.1D1,' %&"%## "#!&#$ ( ( ,(,&'$!=+)W$7%*$")% 1, " %',C,9!"$$7,/-*$ "$ !$%&%'&:4()M(" !"%(!"$!!#*$"#$ $(% !%#)$"! ! "!%@$%$$""% )&$ 2 +% !!"# $"  !! ""$ , "#%&4(*'$-0''-1)%'>_-(+.-ARGNpZ<;G3?j:)/,.)0-/+)'2&">F'+)&(&*,'$3+*+)2%,-,++((.7,,110.-02490312J/253.0/808/8>38+1*)" %+J89-AYEA0*(.-,/('',+,(%&&%)*);>'%+,+(+(1,+-.('.,,7=301100524455>3066544;?29,,3<61*./.250#$5,,0+L?;EGA:FB@DH==@723014019-&(46B/36:457I]PEMJM?9Y?M49,.),*)F$#&)'.-$$# ('79 !"1%#3###)"7"!"  +9'*-%*('-*,;-3+1(&/&2#&#%-(-+.52/0>7?S01)')%$&&&)+*,$&&+15))(&*)''((%%(',%&,,),?@237/52,-,.+//427A:;>D8<>786;;7B52-2C487,$9?A?3878IEM_QMAGF;>06>@2,+*, %+(!"1*+.  # 4 -&#%%+ +'!(( "$ $#!%#*'):1"+(&'&!-.,7<.,/%# "+5*-)/*3/)+042;@0*+.)&%(*'+.-/0&2/$"%-G(&(%$%%''((&)+01F455212:/2-)+-/362159U=Z<:9>HC<3AHUN6../+/%-*%(*$&#$" !A"&!!( "$#$ # /$5))&+(A>==IE5/32HVJCN<1/=5009OFAONLYGJDHMYeKG@8/+*1'(/)$&'$"""%&"' -#9 0:M "!. $% #: ") #'?.4=0,P*(&--(,>&))-&/>dx,,(&#%&)+4)+,06,))*,2>FA_51/*)&(+%$*))'"*%3+=#&()($$&*')++)),-+0./+-*,./9134=814513,24F>SG=@9<9=A>A2:n==Fe=++8/7H?BBGKYr>I;ebCB=FK/-3,,-/"$$!!%,+& " ! , ;&+'&!%)0$! ()$=A%*/:1(&'')/7)5C.>/',476('&.*/*(-,/-+;.&(,'(-3PN;/,&&&(6('&)D,#%%)(*)#"&%(&&((**(+),,+'+,/-/--+=,.62519=A7-/4<@M6;75IK8L@D?8+(3]VHHE|zJTJC',5,,+(#""+,?bh?+-3*'%'/(%)-4*+-&'$%##$'5$&*)(#)*))(+,++*+3/3/.1*+2249::53-2CQ@QC?PF=K@?57479jGD:;8?64ED>DEFOJD=bISSRQ>A?<-,5@50'&&)(%8 !!"!" ) '"!,0%J.0$ ,   "! +)#%"*5H#$%:-1+.'+,**<+.03**E64').+,)'&$*,.',..,))'"+7-4i:',*%+."6?)).6-0)%'0+&%%))'(&%(+,'&'',')***-0Yb1It3,-277644/788=7>=KJGFF\_R[A754.33.32('(:9<-!"!"$  !,%*+# 9 !%"!"%!"$('=I1@N3,4L;8%..()4O($&('.'(&,=2-+%#%#()6+)+**)()##"')(%>R&#"#%&)--).)/5(($*'))'%%&$%)('%&('*',*'+,103555?20-74636328598>=?@I>A:BC?34?`7bmBzC665567//11/=?><>:=FDFj532ADF8;945::9700LZQTj|VRHE?70782/2,21/*+1/'$&#%"!# " !!"$!"'@"!# (!#. !!## "#9'3)./-,.132-%.H0/*4+'&#$!"%"!"!,-*((,(%++/)*&8&%"E&#$%>&&%$$%%%#*$%'+),)*)238(4,&*)*.-,++,).,,.6.5-010+''()010)-A^57798345.03;@A9?LA;EB>:767]LRE9;36;<59).GGPSJHRG:7487--,1<-*),*995&#%##$ %!!"" ! #&!, %%!"' . -"&D7%" %(%/"$+'+3.<93>2@,/.-+-)(.*/$"&,-"# $'%'"$('$#')$&&''')%$$%/#$'%'(*(')P'0)'=,*$$%%.k3(*-)-*/A+-5+++/16113.--:-..-043..,15102751681.335<8J;AE==H<988:8>;?:446883*#DLIdIKIQ;=@8>4,,81+*81)((4-((#%'$%8$)$"%""*37"(  =6 $#"#H#$!!'##%#)'&+:/272'$*MW6560+)+-&!()+-&%'+)%!"('%((('+(#$'&"%*-&&-%$&%%'&,/'$*'*$#(&,+..,(,.+,-23.,'.0..262255/-.,/32/,1.-=3232549440.410=FLA@;=:F?@9<56G:]E5655767-)-CKEROKNJBIE7H5<-*(+*)-,6*)&%&$'&'"%-"#!!! $#5'$'%))w .'\'%$#$! *#"$((0',+7?;.-.(BwQ-.D+)*!)$%/)(&(++5%!%('(&[('#%'%&$$$'),,,(%"(&'&($('''%$&*,01,/.**),1+*+3+/1,-1.,4+24554.07<<72319211+7<@7:546.16:K:?Q>78?A=;89I8?=558777822.7\hsXSPNHCB;20543323--:)('"&%%%$""!" "#()  **! !# &!##&"(,&# $!#%'#" "%/-(&/1-2,K;-SϗE'#*.%&)0'*'(*&(*)'+"&#'&%%'&%#"&(#%%$$ #'%%$'&')%('()(&'('&7-)),+*))*11/+.1.1:4//,0/11>:?6764--+-88DLMRLhKAQ867571.0,1>*'*'.-$%#-=+%(" "&$'&$# 6 2!l!" &7/$"!! ')!$6$&##'%b1$$!#%>5UPQ6#&#&5/%)(('+),**&&$(&!%&$&*2'()&)+%-(*+)(*'&()))*$(''&)))->2.*4383/03/9775613C.334041,00796B9?E:>;A437325104<35;:79<8C48><8=I:7:6588741()/;KLcTHLIEDT3:>5470.++%,/*(-3)'&-",%*# #" %')()%$"#. *+# &%+# %!$ *##!$%!# "/#""$$&%$%)!(007.#,3*)+(%.'.-1+/.,'##%&'(&+)&(,,($(,,&*,,)(),,+-**(',)*())+20,,*/*,0./03801/57:308;2.1+,25K79;N=20799454445434J88B?88:<846;=7@DF==A=;?:788;@;314.38KA=G`JWA93;99540*+(',*++/<5/).''&#-%(*:!#;&#$%( *%&$# "-*(**/-*)+D-*,*228*(,/,+*)&,)*,--+,-0/++,3/.,.*11-.29443?7012,162,25:WH9114308864<537676116<<;::4<3:899=AD>?:;;;:=:9AB85347:5C.*+1+&)30/1/4:<5<44314211>?=;>40207<9=JK<=<;;=>>?C:;>;:;::5@XWKbI:-,1(+--),)))29>,) %!)$'###'#",* $$5 #$"XV5 %=%-&!&! "!" ! $#$%!&&%($$%.762I^667*$)..(+)74?.+%%$(&)),**/.*,.7,---3;8+.++.391012.46-+25/+1/-1//0.D.-7406=DK5806140.12;:;D6664E30434K882=>42323ES:851..6775=?DB<:97:97>@:===:8>=ED@EEBMB;DBV=I3020-1..+*8-'2+0,%!###" #$KF*C/*#$+ ($CA4!"B%&B$!"&"#&#*%%"$%(')'$+35VsC5.0*<2&'-.+6,2**&(%,71*(*.4>20-04/+.1/1211=353B94@;4<:4/033..-.+414?9494/?MK510-700-/12175701<:9/2=4@;?426683312886590223399CDBG996;;;C=>?@D?48=HQ;<@>CRF=DHHC35550/),*,-&3l5+-'"%('% !%%*$ #'+& $-! ; 3%,"2^$(! %)" "!%"!1%##$$$*"$&()1-10;cW789,403/,.+-+'*))(0010-+,//4@0.-8695C/.2371>:<7=<;@06:<658:4=/./0-.002676F97@1113*,,1,,01:/324B9=G578<66843=:86338575A?=@AG<9@<>@9>;IA998>RCCE=A@ET^TJIA41/41/.+(,)(6a@(("($*##! !,&$.$#("#!4$ #$!"$  $ 4 /.)  ##!% )""("#&)/$%$$(& !/-4:_JJ./3/6314./))*0;-,1,/,211.*,+/00==:554225085:96S7583048510.600..02..0/14//-8<60UC:20,.-1+0/34<654A<6;DWK;7?67=<67\>66642288B@;:;?D9/.)/('ML3;####$'"$"% ."!#"#"%&%"2#  %#*(:!""" ""#!"$"##/C+%!$&%7*FW=9HKKH122.,,7<=41,-/82+*.)*634306330221650987602764JG329601212-1.b723530.0C.0,-5*,179910C829:6A52375-4469A=?C@?<>;48AA@>:88323H9;IbyceN91/32.1'+***&$%$'$%'$$&%#%$%%!!'!%'"8,-*. $+"$  !"($#$ % $.*$#"$&-?580WD9:42,-1)*07?SC?11-,2++*&/412..0,.6<455O8986564;27;30354/P2201281657;1422010--+*/3KJ63,,..)0+,.04>;&&+/58A?;>:3/734379..0L4-.2@=JBQLH;A:8<><:=99A?K3740$':;FOVrKJJ<8B30.+****$'($'/'& %## !%" &!!"((*#'%/,1!!! &$ ("!"#$ # "$$"#!*'2*5:IC53BA2*,.5@32/1410.7%*+-,)(473.021;8;=?4;=76;6:;22376632347;=9634364>768333/31/.,,32B6:b3*.>+,--26325A(*.34H7=<8><8958=<<;7=DAA<;0+(()7[kYPACA623.;/*'&%#&&%*'%&'# $%%'# ""$&($/B%&! $&$  (*! #1 -'&1&'%"! !$#&((&%-7)1-=E08@747Q984677599::<:5067957;948640496314420023/255:941334./0:G176:?L56/4<6/557?X43/F=P7)*1502J.3[>><>?<=;>8899?<:>E^FU5(&)')Wx_saM@6C3.///'2''&,"$*'*"*&'&&$#$""$&-,)M3$!"%  +(!'#$3-9#!$#( 5"!#(+# -&&0($&&#',%)2=~P4042U;:P33521333010547277<=9NA;@=86:=9969<86@?:A<::;:89:;=<747552/L17132171272;A:P>342340-0/13925,48=466516>9;032VA2+(/34302,0D@>=<>;>=:<9:@>@AACE>4.'J5(:IINLEEI29/,051*)%'")1##&&0&&*'%$$!#$(! "#$0':*/($* !!!''!(D6""$$#)#"",+'""  #%.'"$)'"&$'29:@V5446=5F40:?/.10/:2258<=;>?:?@A9:779:=F<9=:686450.32002546573>@G3?4465>.213//2704>+.281G18871769?<0-.2342610@?;;;9K?;:?9?.0.'',(F(&('()##$+*&'&&%###""-Ll2%$ "###!!$! $$+) ""#?!$93((&'2!$&!"!$$&,"*&%'-,)0;5479>1/8539C:,.362:738?@<;<>@A8>Q;@::??I;;;;>GHCJJ?<@DJ8IA;B?9543211005146163/84LPD=46?A>?51124E1(,00,/7D9.0/:36;5667F<434056-38;=;:>9?D;??B;Am*!)"" (!,&5#8#( ## "!%3:1..("" %'$,$)'('$&&()'+++,00AVR5?74722.6385;E68<;Yi?;<4=9>@44.55SI:05408D24-9-04435349=787899B30B9;;7;@;?6E?\D=?B>9;10(#+/>BNPKS=82670*..+.-+)%)&/*+$&&!"*)%&Lg%'&$&(;'! 3(>7!"$ !!!#/6;''A#$%%!! #);!"1!'()),0-5/9???@L@`JBECLIFIDLILCNHNPB;<=??9?;>9:;7777788912006?;;755;;=36277EMy56546965119590361586636=SE?5194<9:<=<;87=?B>=A<>841)%,11=BHJHH<;3341.3//',)(($,+#&%#%&$$")&+.+$&!)(" " 1!(.0"*&%% "" #%7o?)(!$"%%(3#%$"$%+!#',277M5\EK>29736668:BB:8:@99>:;@>DC?DQGAMHdXHFOAIBHMIILK?AB@BJGC=ADDA>:;;;9;8979>9><5743<@UG>==8;:854>?>A659144G3:1975>7FD>Sd<;?:?EJ618<3;?6;=7==8=C???A>939/*031LF>KNI<48705-4**4)'')-(&&"### %&'9*u=" !,0###)"!"',(% !!!"!//)/$*'-$"*%$"!# ##,+13/8:=IDA86<>8=>@E@EDELCLzO=<@K::8AHLED@AA>:<;??<@969;>?E<@;742423559377?=<9X?N;889A945BB;=96@>IGP@DBCD??9754")11.1>@D?:5645.+,7.1+*&''&+%  ##-/.8&" $,+# B##(5!!"$$ #J+2'('$$%:=''*%"$'($&)+:703:>EF;ZWH@8:A<:<854<<>=<>A?B=A@@?CAB?>ACDBG><:=@B6849432<;6:;88=IG<<@L852/>D>=::8:CFC@K@AC=@:79>"/;716A=:>987:/,120/;&&(0&&%#$"##%$$)7N($)!"" (!#(' >&&(3#&!  $2!!)'&+M('&+$"#&'&#/7:S224=:J>ES>=37:>:CD799:?=>KJH=;;?NE>ETDIAHGHCINOKMWNKEHFKG64BSZ=?INTQKIICMKLF@B>FEG?C?@DCABAFGMFJBF@H@@I;5KA:DIE>C8;;;@5==<;<9;99>B6234?>>6>>A@?B;=B?>>D@AB>>KB@N=>=6./0./(,-+#*#&%%$!""$#"'((($$"" " &' !3$!%$%###)(" !%" $ $,&;:+(334<=;A=<@AOZ9479<;A:=?A9@9/17E?79B<=@A789=89;68;97773;=NB=GCB798????KCCJo?;F=/%&18@VDDB>=83:;FC@>=CAC99:=<9@::=D=7:2D8DD<73:579;=>EACGDCCH:@,)1=8@FIHMA<2*-.0074[5&1('&"&+'"#$$#%5*%&&#")"0/!!  *'$'" "*!'#%!#&"""*'"$/.%$*91)/.,-+3;@48/214;?KH<6:J>?I]F@P>JAEMADGQEVkgyqf|urWPW_b^YLXaaeUUUMJhhlZLc`no]WTX__[WPKONXPMP[RLKILIKCEPB=11=B@FDCA;:6;B469<>=BBCB=>?>4'6F=?B?GBJH;-0;73./3,*#()%'&$+# #"!!$''&!)%!"$&$ !"% '*!#$,;(&"+$$&" )(+2.$&-2*+*,06).6S54024/,-.0/346==SpECNBAEBDBCDFQZ`eZavYd~cb`MMXLNQ`Ob|fwa[UDI[_{aUWWofcocj{a[XXT^TRPQTVUXVRKKLIGLG70.;DIPMHIAj_E:32<:@AZFCAB=<7@<>??0+/6CHC=>7;:65<9>HBEI>DF?/*1A<9AAGFJJ7D9=98/,)**,&&(%%($$$&"'#"')*$= """)! <%#$'$#1#&#""#/) ##*!&*$+'6+*+6'-11.--+/1*.097::85.522:>;??=9=B@>C>BED@GTP`\ac\WaunZ_xfX[VRLYWQPHRTSZVLRVc\bvoj[Xc\fgfndd`oeTZbcbfYTUTQNKKKQNK<:>AEKLLFMMOD?A9IY3@POFBGD?9469>?ACJGGAA1()1/K?A@EAD4<754.-+)+**%')(###$$%/"'%& %#"#%(($!&$",0H" )("%#"!%$(#$,.'+'$%./@E3-2.-,/7246515468D5:Q=597=@?>9GA@8GFIDREFM__uin\__bUYUNISCIIPHKSOTi`db^pqsa[Sd][_a_bzr`fXJKU\XYSXWNMLOUTPMH@FFHHIIN`WOT8=:D;=HLQJEEC:;@C@H<5364AADH?><;:;=@DLEHFBFAA>@./2:=DC>>98:9>;3/.-,*-,%"&&&$'('#%#,$!##!""""&$!#*!!';S# %(13628$#*%" #"$"/*+(+)'&(/*()2,0.45;50@94589?K?>;;A746;5BOW>?CDLJGFFIGWQoqSNTT[`XUNJQINLNRPRJ[[m[^heZY]ie[[\c^Z`e^l]_mhXUQPWTVTSTPYTV[WZTNNCDJKRTQO^MJJHiA;@GIECA7ADBEA;;4EI2:QEAGD<9=<8@@FEDCFKFCBd&(1768;HA<:99@885?011,0%#,(#$%%%((&'(&"!3 "#&$#$($"##"'2245ihJ('(%#38I#)=*).%*3$,0.322:9J;23958A:D946:>49923324>B?EIE27F3/?>BEEDDD<@6+('%%6=BD>;9>5;7<7F9-3'(*!& #$$)+/''*(#!!!!" #%4'#1&#!$*! ,C0(3X@%#% #'/V$(/1)1.7&0-,=-11?8GF?8;?634330.3-*EDJ[IGNFcTDTIJRZW\^dQVOMTZ\ZWLOVQTPVZTRaYUS]aea_fe`W][^c`Rjc_a[VUUSPXfTWW`W]Z^WSYNUQTT^wSSSQUIEKNLJJIC<>DADNHC@736:AVNp>::5<@8;;8>8867_:2)$&#$%%&$&$)7+*&(#"!$!#$#%3 ##",%('#L7/;6'$&&%"'""<(-),4-2-3/+/1>2K6257IK8:;;EHGA;8:763663;7-66<55FRGS]SNKINPKOROU_VUSTVINVnNLIPQ\LOTSXW]\]`dcxld_^\_a\`eba]`]VYURSSSXUWQTVnbWWNPQSURU]]QVORR[RHIJKHGIB?BCBDBAL86681.)''$#%5#$ )%,&%$#")##"#$' " $#%C+%!&B7*$.)$""#&.=),%'-*-.*,2/.207D=26EDF>846IOO;<=86425@O9>5388>BB@JJ_jPJ@HPUKJ_KOSTPWNKIKMPPP@DOTKT[j_]V\YY\c^fma^`g]abjxeaba^WVYb]RORYRRSWUWXVUYUUYZUTQLPPURJKGFHKILJAFCBDB<<;:;9ECOCEAD@;8?A@DEFIBFCLH<+0&9@@C><=>D<9784391-'(%$#+(+%9%$$"#""#$# #&"#$ !!"%$!%(!(&,-*%&'%%),-(./)/***(%++9AF;8??:8;57683145>?76,/3AH4A@EG?BFE@ESTKWPQMBLMEWRUURTOPKGJMNJON><8:<<GH9>><;68677:9T/*.,$$'&&)''*)2!(##$-4<."")" $&!%% $)))+")6)&*/*)-4()(''*028<@8:26786658474B;9513254608:AU??CCCBDKWGHMVQCBAFOHLFfMIKVFHKHDHDBIQSPa]Z[\TSWXa][^^\\]Y]]bfimcttmga^^ZZTVQQOUSTSYXYVQVX[WSYTUWSRPIRLKIFGH@EFB@CIFEBA=?979=FB@6339CMEICGD=G?76>7%HQTCCFQsYTTWBKIKNKRLATFF=HDEIIA;B>ERY\][\ZSPZc]n[]cbbg`Z^d_bhijdpkklde\WY[_STSWVW]WUORQUaZXWZZTSROMNNJFFHGA@BA@JYGECDA:35>?N8;<57>DF@FCDCNFA93?%5?<=<6625./)'*'&'*+!%!$$&,)! %/"""(&&$#%#"(.)=#!%#B''))&+%(;'&**+,052<4:8CPUC?=H?;;=;<8>6<7065419ABTNEIIUI?BAEShURPXTSISLPXQDME;6:@=AJB@=DKU^[WX[]\X^^XZZ^ixmgcm[\]acebklmtmhg`acbaZZPSUUUXWWRRUV][WU_TURSMTNLLPKHBCA?BBDCDGFLV855D;<86348441+;=9=:>;<:<3155*)(,&)&)&%#'%(+)$0-&!&$%$"%"'(# "&$(&&%"$&%8)'(:**##('$(.0.651:BGWpOA48;?G;@=8946<8.218>B:PHKMEOXIJCGGHMMK@IS`TW`ZJEIIA8269>AA>CIJMNWVYWZ]a[ZZ[V^^bhdedee][Y\checmfkfhlkjljc]\X\[VVWWSVYYZ[^ZWTTVWRRSPOQMKGEGEKIDGGDGCGA66<=:710*7=EFHFKIFE@8-,1<51>?;GS<:8832:))'6+*%##'# $$#"!%&# "$((*),EFJIGAKLQ]^aqLEHVH>:7>>85Q[CF9E;GSF>796578431+00/5>VGDSE@DH]YHNNODFUENNGV[PHIKHFAISKMIFMRGEFCEA9>;1+)19>CCBJUGC@@EM=7/*,/+3*-,(# +#%%%)92$!#("$"#-/-%&'H !&#"+$#$1#)()+%" " *1--/0225<=:>A@[J?M=@;97?8>964.1.35GC@=@=@DBGFAD>NLGDA@3;;^_QJNPHEHGE@HKKQUXRXSUXYVT[Wsusf`_]_bigc]Z_`cpsyrkl`bgimuptnlqsxfb]^`aYYd`]\bf^gVVQY\YUQQB;EMLKHHIMJHF??@A@?4*%38BGDDDGF>?@CFD3*2:87:@A<:=>GIHKIHFFBGKJJORUVSTTZWRVYbaeekfa[_db_ZY^[antqgzt~ntqgjnos|||tmrst`_\_]Yb\Y[cbgdk`WXYcW_UJDIJLMIPKKMIJDAFFFE8>-28CEGG@EIEF;?QV69NEE8?;9:668./20)%%)&%),&%))..1%('*&%(''&&26&$&*#.&(%#"$%%()+%"#'**,/02..587B9??lV@AD7?=S::66432=89?BV\CGHJDJIFFKMKHUKOKE@GHWPKQQ`XRU_bhn\`ccqlc\oqidQIRPR\amdia\[arm}{uk`k{ywhqzylffl]WZjV_Y]_eeuql_c^TMKVKEKHQOKPNPULI=@FCA>3'3@GBFFBCH=15@DBD;CEICB>FC??;47197)%'),)()%,-*,(()$$'''$'&'&*'"-0((((%+#(&+('&&)(*1)1624.@=BaI;O=AI>?G@@GBN<37756@?<44CMADFAMBW8>AJeVNIY[QNHHYSGGIHH@?=HMWNNLRSWYUY`___h`chkhpyyo]IFM^ihkszuibkikqtutpusq|rymr|qlfha\XihmaZY]`tqyt_a]UOQQEIVPNPTQMLLIH@BI<:.?B<CHI=;71++*,+%(&$),*('(*E;>'&%$+&&'&9L%&"%%(,+#'%#%!&&)-*2G199N@HtS>C;6:B;66::HEE96D?3>;:8;>?BBBIIGOBFI\QaNPMLQPBHIMVC?99@JALOMGKNP]XTOLhtdXmTTYTVZdbbbaSV^hkx{{umbejt{{x||zr{~{pifdbas_X[^[cp~udba\RRMOGGNZOLMONMHJ@@A>@>oLA?DBIDBFM<23;5644:TNI;FALLE<>=<>TBG;9>40:-,*'-,/+(*&(+-,8^@.+(#)M0''0%.''&)(3K.)$%%%(&(/+16=T6_SzlRFSB<:7;76155YEEVrulR?DGLQHGKOOL\W?GFOIACDBKFVGC945<>CBBPACGNUUUQT[UOV]QUh\\]^bfemstprxo{slr~yh{yqzwrztyu}xsoqtkfnnij`aabggmofhfh]\SOC7@HR@62/0..,51))+)&%(/++,+66+(%'+I@1$'$&$&&%&2))'&&'# %,12<7;>Tf[l}zgGC98=;9=21=:m]ry|lQONV_RXVUPidKHPYZJNEBFGADG;737?=?@FINMMU]XUXUUYVWaTZab]`^c^`bjtuqoxysx~~o|zpkjqkrplpjkkhmb`fhukgi~rd_ULD9@QPOWQQKFAGK_cFDIHDD?=@B@KLRQSX\]XV^VWYam^`oeejgde\bijnh{erwz||kdfjzxywropnrkbehjytisupc_XB69?GKTSOKEC@JXFCCEHE73??B=DIIRUPK=GBFB@GCCDAH74533<:11-*))+1((,*@37++0/@1,0:.%&'$&+)*)-*/.,%'6%,-0GADi_fbZNaoYBB?<<=F229=Kunttgpgk~\RRYIBMIIJGB@9?239AG?FKKKLUUb^[UYbUW_|enjhinnqjoghijpumht}}|xt}|~}ifiqwtrt{mqskfiqpqipk}deRB>ELKQW[LC57GGYC<>@87>?ACAACFQKRKC6)1>99P;;::;Hp|zz\UWULPIFGIIEDEG6G?FCGCEIJMPYSS^\YZ^aa`plqoqonsrvboux}gh\~~hbhjpuiv~wqryoodwqymiqrplgl[HMLXMQTRLIG:GHfNGB9>;DB@B@UMN`LMB=)#7@JMNTMCH6;9DRM:80/+))),+/-+--/;.2E**+'+1*&&)+*),-2&((+'))&-'EI?JHQ]ugaZYZ_HE_FL=8=DHGVyeWYXMGHIJHFFJT]g7J?FCFBFFKNRO[_aagkmcdnqvzpu}{krnr~j`kvrwvonst~vsitqkegqZQUUPIOLLFD6@:>@FGKXOPJROAHY?FMSGB=B?>K;Qwf5.-/*)(,1//)+*..e605)'&'*/0)+/*)))+,(-(+*,/*.01LD;S>Fpe\BP@MNRBCAA==8:=DFPXwɽǑsdbaWOJDFGGCKIH_P68;>BFC;KZVY\U]\bUhwnuzr|gs{{uz|x|ujtt|{~wyvo}oklgcjnx_SQKJEJRODELJ;BK@B<96<9:FGTTWUTQD;?@HVbqݱsfUVLIGEJB=FIBkL@DCFEIHMQTW__Z[W_bhzx~tlnnrxҵ~zurp{nx}~ztywyu{tpocedd`_jfdSVIYRSZR9KS=9AAD@4353>9>EIU]SRNLU]JIEFLGB@<EJXdnٺzaUMKKGHB;=@AECJLVRNN[`dY?LFCJA:9>?<<:44912.2524/&',*26G?Nb0'$(V2+/-.,/40()-.0))),;0+22??AA<@>F?;HNQLOm<68T97:>>IU]tïvbYUPKD<;;8;,*3GHGNMPQXV[\UWT^be_nnniqy~uqytnpznkiziktefinq~|}vmst}r~u{kkilabcmnk]WPMOTUSMJNDPaJUKF@66665BCFKPLNSYjmdMCnDC98:BG><4449K07-659=.0(*35@[qE,$%*,+/*.%(,.,*3+,*+(/4<-7,-::FU<6?JDDCDVBAC516:839>?HT[p˯{fWSUJC:;971*M>JNXRVbfecgZb^_cb\Ybqhpx{~zvsvupxwzma^cci`wwv{wwbxmyvyxjxvyzy}moea\dorf]YTRTTRPQKVIMQOQOHH;><;=@BEJQOS_^`Y\ZWB@<8;WFO?9653E00.3;4,2(.?3712CWI+#*'.,,.'-#'&(/-)((+/+.11*3=B@BB87>>A?EO?78G311246=5BpQUUbdgbiiaeje`ijhjftknr|~|{oeitzvl^afnqsqoqlso~y{gc{zzqmzz_gdcrh`a]X]XPXXVPTOLOOPLJHA>@=?D=CrMXRT[WVGHjA74;;`L@;?AA612280)279J37.11>1G-=++*/-867<63011143:9@AKT\izԶieaXPB:BDC>9DCISUX_oxpwffmb[ggdtzxvnrrxtfa]_jttrogfouvx{yqp}ouvzxre||}W}wxwrbhooic[Y^`RTU\R\QMNKURNPA>A?A>BIPKPSY_eXORDF9666F>B<o76.26517.?533J91-),:7=>2/;##'#'&"&'+.,+-).05:07>;NNETdB:;6691.1>844::BIPO\r̴|]YVLE?DLTEDIJHJQY[`luria[|{prjswpy~mvoia^kru{urvpjnxxz}yz{pzuzvxsr~xgvvxnijrm{jY[l[LVVOQTTQPNUkNMF7CCDDCLLJQZ^ma\TP4*39>95::D??@>8;H?697B+,)0823068DAEMSУp_[OF@BJKIRMONQRUV`mf}hfZZl~zyngnmcu~lX[fmohproy{||~xzx{}}xsc||{obfv}|~illmiupdY^YOLQVYhUOVT[RQPMU>FCB@FIILR][mk`_O0(/35<73EL641--2/.<.)(+82307;GCELoeoȲjb^SWKICHMKKJKQNTj{xuqjnm{|v{|wslmgv|zyuonnemlpstwz|~~~{~}i~wh[jbuʓxhntynkplg\U\n|RT^`\RRTVSQ]Lf>;:@AEHFXQdkaekfTO<4088771/)/**,-,-))46020O>>470-.?$'& !#%&'*-/..068640::833/1+*),/0/1+1;4559EBQxNKV~iZFIEHENLKKWS^_aj~rukzvuyzyn}x||zurrrt}z|}vy{~zp|zc[^vktiijllxejkZL^G[Y\XSTSONNLMNA57PPEDMQOfv{dYUrlu;57;77:>=<=>2245/*,*+-.'+/2?[484F=N49-,AX# &""($&(*/-,/3=47524AA30/0-)01000122/4/2==ZMI>`tt}|aUPI?GOKRdbchjZhslmou{r~vzzjbeefyykhtw~zzy}}~|otv_Qpt{ytmnng\bgjka]VCIV^eLGRRTWUPO@;<8CPGGCKW_fb[XVbwXM57;03;96;=89hJ9-.+.8"#'#*%&))+,,)(+038585922316.1WNNRej^[S_`lkpr}p|qyflohhkgnw{|ujryysjpz}}|~yyx}~rflx|}|kXq|n^eqibhgk|mZ\HE]hfkeSZUgjYUKCG:DGIML@OWSTd^\UXT;@C66?5401AD=gM6*-.0.#"!&,&)()*/*.81-02573607/10./))+,3/42.2,;J679DA>BECLNKTYX`WQqMJPZQZajf\h[efmt{tppnhgikajpqo~|}{z~}kxorzun|~}}||}~|~wws}rnsv}nSg~ucTdklkgvk`]\POXchkgYSXPXSTLDEFIb:HtAGLZ_jbb^LAY@446>686289;<8620+*-27522:=:o~1$EOM:E4795#"&'&%')$%6DH9371/;0;=4446+-((+)**.,+.2DD68:B?9BDBEOLOOZ\]U^Zli`VS_antsociuuxvqksd^SQS`fdqzvu}|{vswxysg}x}{|{tot{|yztuyu}ojm|i{nijlkhid[]VUagdb\^W\[SQLBFKLa[8EGHI`yi[cl_UA?@:9C<::38C989:4+0(0&-I3.3:Uc}DF:>I:X[961!!"$&&*(+(;685;MUQNQaujc[_[]o^_`jgjxhtkkpvqxyyjz\VMUVeenz~{x{zopglv}q^ryx}u{wvvssprtr{}|ow}|vu}klsy{lfhua[dZW_ch\c_f[\OSOMKKWycGO?HNYga^WUFC0DID;76;=02376:F.-**))531<5BO^F<,2K?>CG7+(!###'$))#.-03@9M7//,0,<.-12/,*)++(,/*F@0.08256.5CPTRPMI^\WbhY_ce^yyxyoxmuwpdhfprr{a[cxvxxzwwslipsj{qs_`err{wmyu}y~{|pb_l{yfbhmZ]\d[b]jX^[cdMCY[OMiy[7B9IVMTVf[[O:2SOKI?;;648/4;3710--2-40,+:@EW<*&-33;<567.*)$&$%&)('.+1BN:9349349R8,***)'#(/+/-?;.-08.-/26;HQSRVVHaSbZopeniuwaslrmgfrnx{zyrhmz}~soiimv|t~ydgrr{{szy~~uyyiq}}~qcYdiyd\UZW\fkd\abgjiVTCKOLLXoyiSQ8;?BA=QahP-Aa[HE?>75/363=;/3..,.014,3:>SA4(*&//27.2E8%"!!'$$$9zE1CLn;50>=0.111***+((%('++90..-5/-/337IJJQW[\z[W\]WdhiwmfdRdrme[_uxuo`jvuvxy}rynuckxv{vsw}}}ywnept{}yjm~|~}uu[^^ckl[Z\_gfaY\ntoszNWVSVHBRYyZ_;1-6DCSd`>9FKEOB?@523683/503,(/5<,30AFG?6KN615-)0++.+%$(($)''GP:JW>77><865//21,/).(&%&)-0+)'//.454816=CB;:4576641410/.30.8F>H=CK=4E-0,+(*+*&'+#()$.(*.,@E8=V=>W>@,//4)0)+'*-)(,5**)-:1..1631B:FFUPXiIKUMVWcu|ixp`frtrqj_ayxrumpypp_Xn~nxamou}}}xstyvv|y{{}wxphu~y{ge]^mdlxmhghk]jl|ysqhfSWLICVSO8:7*)0:99GQKLUF:=@FNU**+'),,)+)+(9"+-&(&-20/-76@CL878>.-.*-(*()$&-3,,*(,,.*)),)475=KOHQZYBAH>T[dfggbfd_dkxzmWBWu~rsnnnu}n`Tg|p`_hn]jxxzptwux|yx~wuikrx~{vrk`Zlnywgzkooo^vxpjck^VZQ^gdIC&)+'++06YGPGCVA230(2;484073=96<752E245cB>MJ7(2:*,-7)&''%)##)4&)0062/3K=?766S9410..(.,)'05.),*)'-0*%&+.677?G@FMQO=CVTcevordaZ\avimjVJEXZhhuoowymg]gngijh`kabrtxmrtxw{rmfYlyy|~pyjfd`en{|rxzlddc_gleakhcZUPRYM?E=510*/8?ELLKLQI1++49879=988@;92685(*3=Z66912*-/-/*,%"!&'%4#12.-),+),.5?62@=5M82R+<.-.*(0()))++%).*++7I<=KC?HUNUYvN^xejurkc\Y\ffg_ThjdU\tvovkrs{w}rlfcuobdqnjd\_rynirxyxztmpdqyy{|~ypni^Uhorq|lmfe^__bfg`ajbWPURTN?><@87:CQZYaY[eXtntnqib]Z^\jb^Vlr__gqmmpznolljigdmeff^eilokhspapuv}y~wi|uply}qv|yrcTewri_vpld\_^buclhpm]][SPQPE=:7V:6;:E6A0,0$#'')9+(',%,826:=AGDEF^]\fYMf`rktf^_\YYZY\Xeavkkmup{kmmfgehf]UZVq`kumqnojkegtzuxyxlgzyv{}ylw~wrl[g[\iawmtu\^bbgfrwmY\QMLOOK>;9=?GGCIQ[TQ;'0>BA@D@F:6=C7:CEH;U9H?H;bS0615*-3))($(',#$;#+H)%'.3/10:4DD:BX@:B;P>+&.1$$)'')'%)&,.;<>7GECDFQXZ[[WEVMSlhfba_]VT[WTdhbhufic|jkjjfng_]XVagluorti^_Vmvz{zxlv~yusvhqzpjqvvo\jVU`bronl``fZaqps{kVXUNIMI>;79BFJWCCGO_dF56I@?E@A@228>=dEAN>AE;;?=UB41611294/)%&($()&#)0D),1.,0/:5>BN97;7;:903,+'$''&((&(++.64>?A@GDCKMO]XQGEH`]`lb[WQUKOZRWXcc\undcfikkhhfeaQ[[fmlu{~wqj|ihiux~{xkls{~wpkv|t\nptkqpoqqkuxytoc\^`huobZNKKII8>8=9I@DPNLFQiOE=9C@;B@B312;9LiJjHDC=<:N4*,830,3<=EG<;ON620.,,.,*&&**;2//2@>@BDHJKJIJGKGDG:>]mfdf[gQKSbVV\aQYW]|deernfwfgcVQ]_lpgqwyzojsts{||wlaht||rh|~skatbqorvsux|zojzw^kiirjolaqRGE;3029<48;CYIA828@=knLE??@=6B8>>:53.+?,*(&&%$%(&#%#$#%62,-+,21.5=<)2?NOGB<5A=ULCMRG>?;;>>A@1D<2/2(($&$#&(&$$%&&"(*<9)*24I17868=8!3BPGDG=DBL^GAK>?@<8C@AL30637<,+*)&'#%$##"(&"%'.1@..X677?//,()(./94;BGFBCGBBE8+1:?BAG@;B>InA;CIB572NJMA;;?=AGHNGA?GS\]XQUdai|gg_`fnTS^S[Wavpoce`cgfcgplffi]j^c]nwwvu}oujkjmv{|}x~vm~ztwmhokkvz|vbddgikupicZPIDEC?A39?:AKCGIFIJSD=HLO`LD6;98101489;:<@5BB>=8*-'(%&*()1%#&#%$'-!"&*2)1NnAFRGCNC<5:./-2-6+(),2G::5/3RK:AB@_I?72/-@))/*)''+c776>@;>JVKNQO]^d`Rc`srxmYVUSTSWWUWXUUgu_a^dbikhxbihi`\]gc~dhl|qnovcmvu}}}x|{nz}xqumhehn}~pjifftvzhqd`VOIHGB<6>889;?E@DJJG>5FLS\OF<@@:9:,+79D5342/*-*)'$!#%#  '()1-2E\8/+5,)(%*&)**&)9I5@=GHIKHWWyYgjnpfdTTMMKNRRWRUUYkc^\ea][dmukX]f`ffrmvlY^NZmqz}~z~|ytxtvlpymlhij~z|spqghehif][SOKGECFMA58=:>@AMIQG9*?JZSK=?AB57/32377]DTKU`CA/4/1,'2,&'$%% #!$"1&()0:6>_Z97A?=B?@FON?-FJOfLGA>?62687;>;?G?PHMgE3-;/%#*,++'0&%" &$"+++,66EJgTPEH>@A;/1**)%""((..,300O@BBLGHTaU\Tl_zj]jurgaXXVMFRSXXm\`[Z_^^_W_kujknih_ejrrospsbhjtyzy||yzz{xxyx|ytgogtp_gzhjkvr`achtdd^[VTXZIJIA?=AH;<<4=@CEG61HJSMIDB<<7:78<><<>M4F@Eh8/4-)((,<0(%#$ 4#'*)/2BTcsAEI9<:GB2++.'#!(),-*+,::sA=EFHIPXOWScmne]KXmspaZUUUNRT^a~ba`pTi`q`]^c{ohhjXelikwricxfmztfs|~}|}½yxvz}{ughhzjhny{yqqmx]`euzdc\]TZbQTLFDDHGC6/.)7BDC>>9BDJGFMM=:89;EDJJEI@A4E9Nb79)/,0%(1)$!#$"!"4A+=./4<^rabM69G@931+('%!$%5((1/209?D=BPHRIKH[=QpNBNO`o_ZYWVs\\U^_pced^^\_hc^^szzP[mimfdit{gfmfjrwyd`pqz{xz»{vx|zvrhjnqhkqx|uy}qc`cxwgd`V]ulUSSD;>R=95.*.8@DE=I6>DKNITGT=466B]QE]X?97:;;;4/,*3*F0)&"!(2"$"(2,<4/BA]RECC17F?=47+%<+(#())(11@/56>9FGHCDVgo:4210/2:0*,'$$$%# ! % '58;NVEZ<35B95=3+0:0+%&%'+,0O6466STADB@AxaYUKEINM\ZT]abY^X]k]]T_Y_dd__oetbir}ss^ZWXddf_lukuedivoujygtvt~wsutyuqphhvpljlwym|zivnd|xtbbUTRQTDHC>=881<:73:<=9.0GOXNAFGB@=9FSIDFGmE:O@1U:6+-8()@(&&& "!$!##._SFJKHO5464684>21`B'$'&:/7865<:KLHE@KDPTXYiOB?HSa`]o\c_ek~`MVZSR_[X]`bigooivyrlc_OUcdbhknnyfR\eplozsxzlsĽ}x{vx{unljhlsskpg{ypwhhru|yk[XPMKJ@<:=D74016B=67;7.DBNclFCCFBD=8AKEJKJIKVBAAE-,&()#% $&# !"  2+bIl>TA764.01+4812?(+'*-7OA86FC5?aK@GQUcY\hjOLQNb_h`naSWaTQF@KYh^V`dj|gp{qnef^I\ggdelqstXTbvcsxwx|umywzy{{rhcispkhp|ts|w~znficef_UPVQMMC>=?>64141:5;CFSGFYX\YWevpVZa\i_JLVhpfqTJQMObaN]al}hgoohpWQbjjknmlrgUbovowx{|qxxy|~}~z|yvpk_ghifn|ytxoounttocdeZURVILKJ?K9@/285/4=JMH@KINSWUSCA>;A?E9=DOPjsTW?>QA%%$($"# !#*' &&68*.P2.5?9636-11B/22,..'8W?5AJB9=:=`ScgOR`\o>$$!  !&%%"68-0*.-6211@164/2/2=..1(58.1rF?<:AMHEJIX\b_hvrm[`XWTXjmhffgJJIMMLPNVV\hQWRajhibnkc`_ijpsoqefi`Omxzvx}vz~{|}~turka`fu}|t}ra[ZbnknjjaaVdOMF>;9816/1392/>DJIIMDF[W^dND=@>=989?mVPWSZQ^OC*"! %$#$'#""!35,-,+/030.1/35802236/9**0118:528:IJGNJQLYm\TbqdgXOWVY_^shz\\FUI@B915,588-:EIGGD]SLRRSWGDF;4DQVWHQx55-C&$%"#%"$&$"'#$-# 4,05?/-5/+-+&+4<5/346/)+'*,3-25C@CR@@WePLT\YceXWUSZXpW]jjozWS\hDIKUOR`Wac_]_sd`LRcm\hheorV{tjvwzv{vzz}~¾|}~}|uflstfl|~}rzk_ibr{xfcfZLGXZGA8O8469-+1;GHJPPDQHLRRJFC<;<<78412'#'"!(,&'*&%!'"!! ?V5<40,+.,+,(,0+./.,/(,,+324*07M=;HFYFQNNP^c`hkdUSo_]fjhffbNSTSTIJTZXY_bm^VGRU^W^d]][Yfhfjtkqvywx}sw{|~}vecikomw|xum`bcdldcqtkld[XQKKGB;88?8706L@9HQRRO\TNHUUOQ;78999:G?;;JMM>I70#'-+)('$$$%$$4!!6A?=-/**-,72.-0+-2-%&0+5-11S::8?N@664<>FB>GSWZx[VMQKDB;538><@@:;:;5@=GTNTTTV[by]ZVN@FP=579;;=J81)(C88-*'$$&&$$'#"##! &# 5;D4.2//22-/3.0>7%&%&+-12Fbm023066?EOLPIPPYXZj|i^U_afpqfU>?>FLYQPR[WUSFFM\c`LRSWX`gfuyre^sk\pwu|{{v}~|yrbYTYiru}~xjfhpikpehtofbXMMWG?F;46347AHCNPQU\X_\Y]cPXYYg`f|LC0:NqePW`YTYYZZQXa]ZgW[Xcg}ovwun`j|vzwyy~~|xse_dd[hsrtwrjxqsqnnx}gx{pd\]SPVQHH@963=;@C@GPTX`c\YSQVE;@J450457=??@XTUQRR_]WZTY`S__ipkSXC414))(*'''####'#! ! %&! :>21,***+5-.*0,'/)'+*+3))37:5026::=@FRMSTU\dfRQMLSY]d`d^OI@=HSDN[TZdUQQQSOPRUFMXRUcigktcZqi{|yxy{yz}yvtpl]Zdjimgl~nqut|uthee[jsbUKI>@7;4DCBKPVbVSUQJULFAGIEGLQG?D;<>66/++(((,'&&'$%"$)6 "#<% )721--1()&$(+')8<6)&$#:)*)3.975187=@RIM^UO[SVUMKGKUVZ^XTUPWSjvZHPRRWUSV^XPHKOvRQSQYcilw{~jyuw{{wttx~}qz||xsktpma]imjjrwmniz~sliecffWDCDG<::C?HESIkUUQNPTNJKHJIIHTIAA@BN=421.)+F()*'$+3%&#""%!  #!! (=A/,,+-&&"-,1,:54&&*($"%4//-5?4??;@@ULih^P<@LIJ\WOS\ae[`VPZTOZVSOZ[W_PQH_VYTTWNK^dj{t~s{|qonz~qn{~wlkmvzzskiljprw{ypppmq~zreem~d[NQ_FMD>ABHLKSRUTTQRRQB:AJ`KILNJFNKHG>6741*)))%%''++#!##"%!'!" ,%$!&,.0+0*,.('$(--,--**)4&##$%/1.1;5O99AHOdXh^H>GXUYULX]WVYWT\_slTNOVPnVZ_aTFB[M][XTR\jgmhxjzuqjnu~k{slmtwttwwr{z}ln}uy~mmkmvwokhhxaPX``NGDDIFRVVNKVSWZSJA;HFJH?GKJHBCF@A=:?500-*')(-#(# """#!% "!!' "'O -.3/21))(-(+*)+1/+,?&$%"$+7,010368=FFU[[OSdYVQga}\ZRS[NrXHGMH436@@DycZ[RYOOOOUmXY\elmpxطnnwvhevw{zuu|zwtqpnrsty}vv~splmqiamr~zqlTZZLBA99=AHWNOPSPW]ONQRTQNNKIVZTYYg]EONTA<60C(2&$&&## !$!*1$1"$$0JP:+'1$)3+*&))(E'+)$&%!''".&(04)+-/3,*/9GFEUraR^aZRM\ef]fgQQQaZHJIE<:37BHBMVRWRRIILJHV]a]c`jprѲsjw|{hZmr{xyw}yrpmxvw{{{ux}znualdnvios~}sc^IBB@@CBGJEFVSPRQUVSSSZWXMVZ]ZocTCDA;8/7/,%$&$!"$&'#(&#'&&')-^1,/-+*059/+'(&*)&3$%$%',)''&,2..2>411C9?U]|Ox`QHRec`RLMSVMKHFEE;847<@DOJLTYNM@>HDH\dVK_jo~oepmpsnZcwz}|z}~|ysrsxyyyxzwoqmfafkmonnwj`oXPI=<@HCGMHKIIROL\UffVTolWVXWQiWDA=>;810/**(!$$((&""%%&%&%^))3'81F45EE80'%'&'# &%7$'&($$('(/.3,/-.,7:6B>;>TXJ^BCX``TLQOGNJJCC?B695:=>BFMObTLGCEJIN\_UMekip_ins|jlwfqwuzzruyw|{yx{}}~v{tpdffldmoolunZXSZLGB<>EQCMFQNHOPOKUY[_W[WY__jbH?TB?=;::G/,,0-%&%%*?D'&$$&',$'#(*'(*M,JI,0,+('('((/&""$&*,$%-"/2/0+.,0C22S?=DJHOCkIFMT^`hIFLFFII>D>>=@;?>NBBEGIMPL?FQHEMRUUQcYmcsr~{~k_g}cZrhium{~~tetqx|z|~}||}vlirfafjmitmyaglh[MOHGBHD<>HOGEIEJPNNIT]blXS\^XWdXNH>===;853510-*&%&)%#V3+'*0%$#!($""!!#,,0-+0)&%$*(#$!#'6&((&#&##1-0*,,52<7AFJGKMHA7MO6@cVQcf[Xitj\hktjUcpcVrqgon|}zpoq{x}~zz}y{v}xzzyslkthlrihrqgkprXaPJFB>96??@D\GQJQMOKQLQTZY[WX[ZX`eRBG[C66542540.*%#$&'')Q3%%*%%'#$&'#')&+=1''#.%$'(%'$&"#%-%# =#+3*'*2,/,@9-)-3151D=E<62AUYha]kfTTRLCEEEC=;6;FBOGHGLG;--5FI\[XDPhypkvn`mfc\FV]ANkspdj}}|qt{|oj}~z{zxx|z||~zuv|xushkkkgkmnvpptcaYcE?:6:<==>G=@DLHHHG@:4.9_c_WXZ`yxYipc|sUTSTLK`cjbczzxtr||zyvzxx{|~uxx{~|yy}zzxy{{qjqvnjlgnpnlvgb^^^RDFFIEEFIKJK[PLLLLQLJHLPX\`_^XSRPOKN;@7933333149/&*"$!%))'!+.'+11#$(%%6+&%$(#/1$(,*+*$.,*&'$!! "&*)-))'$$*)->86>G;9JNUhl`_SMOODDFHAO81;>@;?k=ICMLTFB?N97C=OiWVZfrxhZ_ljvjgejhRbQU[oc_s}u{z}|yww{~x|z{{ty{}||~z}{v|vrqljozrlvrsnts{pm`^VJPIKHLHFQLLMMIGJHLSOSOORUX[Z]^VYRJD=9?<747E-2/4A,*%+$(%""%-()+*)%'.C0(&'#&&#(##(/-'2+',&')!!! , %$++/'&*-./446<=NLG^aUehjfbRNFFDFBCN7379@@=LAA??F@CA>A<4/>6FWWWdteSTY_liprnuo[ingflmckwxmwyzvzyz}|{|xxplqklkqmrwqommltogZJLRVJJGMJHJSOPIPMPYHALRTWUWX\[YXa~tH<;<@;3548A/,2+-)&'#''!""#$"%)9)45+:%()%'%%0)$#&1*/+'#"$/#$!"!! )$"**.*+03+//01@7=QJKLQYZb`[^_IJXBFB<;<56;;;ADBDI@@FC@HN621<,CTX\`qaWZclxpmhqigkpkmedo}y{u}pn|ww{z{~vzxuvqejijgvrzplmiloeWYRObSFFUKGFSNOIKPRTKHIOSXX_V\[WSO`^C78764543/;::+)*''$###$"#%&))'%'*+4+0Q(*(""00&''''I*($"7i*k%"#" !#/),&).;,/01596=JNGKTSfke`WVJAA<>@FD:9:@<9CMF@<9;8:AOQS\]f^hnontxkkkntvfmmhkmx~ux}|u~yw}~v|z~|muttuvurnieihnnwqgehpjeXXRRSRUJFKMRMQOQQLPpXnWSVRUe^gUW\NKDAA@>N142.31>m;*-))'("$%&&*+-4&4(-.O@.)37.(#>#!%%!0"&&$4?9'#"#(4'$)&2&-/).476D6B?<<659EjLPWYfZfxjlqjj_fyuaohlor{{|qrssvv~r|wuz~zstquyzxy{|xmijifqpsq}i_`ecX\P\TPJUJKMMOLQMRLMLWRKIKPNSYVURSNGC@::=:F755418R`h0+'(%&$)-##+*'&(5/-.5C&)&5C%""$"$$#!%*1#$"&"!&#&! (")3.48013;GDRGMcn~j\Z[P[Q;@G>ID=>9:>>=>AK<@AB>B:;89;<<=HSYZY[\VTOHB>;=648:9:8:8GJ<:4-*/(+#!$'##%(,8.3*/43$)*$ &! )((!" "$ " &"'##(G'##!#02+-S05@NCMNZYonrn\ODG7EJH>CN?:;<<:AH?AB?>8:9:56I_T^ow{kpokmorm\ddaighix~y~{}~}qtnxxxw{~|y||vs|rsqsilnlpluneab\^c^YYULMOGFOSOZlRFFDFBHRMT]`_\[ZRULIC;9959@::8<7E8E4.241.$$$$!#%8(&+0?1*8=,(%"#!,*#!(##+%! $$)"0,#%)6!$%#'(0A:8EB9;AOjiyLHA0>^C>EFR:D<<ACE;@79==HDE>9DD[LG2*-:)%%,$#"%%&')1.57.1&,##"!#+&%!('1$""$!"&"$#%AF#5'(,"(?+5>=8;76@@D6dwPG?5>YQIJMF=;:@;A=EB@GA<=<:9??9@<;EOHMovhnuu]i|kaW^ni]fjpzy}qt}{wtyv|}zyrnmmllkxmjc^]as]\ZYN_LCLLKKMWYSHCKWVQGTSWTbab\VQ]PGE<>>F@>^Wup\Je[=2,4.)&!#&*%&*)-3*.-10+G+(%)/#!)+'#' " !#"4+; '! $))`""" %& &1:`89;64P@EGDMjnl\H;6=LLJ?=?B:>A>??:DJMTNj|bfpv[`snx~}ywzvy~}y||x}yzywyrlkqppocf`er_XQSYTNGHIRMMMcKIRTkQRPYWRW\ZYTvONCB?7:@EO?WtYalH55.-&%$"&''%'*)**(0+&4,8'$+'&&$%!%)%!$% #& "$"##%'$!$""$" *2O8288I>>3??LQr``UML;?D?AO=>AJF><<>MA<:>LgVN7-+(''$'($#$0]3''+)('31",<(++%$)1""%%$5K'###3$#!!&"082713;6C@;@7@DK\PCGC=C?=9EA>;8<;9:75<;KNYV]grfa|r~~lOnsnrrggqyzxjlrurvolox~{ztntpqpc_^\mWYYRUQPKHHGDPNJNRZTZXYYX[e``fXSPthEA>E5BIG]8@HDCHE@4=8=9:7OS=O;=C9<;LEC=9A;?<9PFOWZd]in~{sfqg``Mdksovrx|}ob`vnpuzt|y~}~qykplmmrri{mg^^]TPROMKJHFKGIMGLSPjk\Y`\XVVcSPNJUeC?BK:=>FWAL7M\<7;:-/+%*'$'()+&&(+4&&'+%'&*$&'0/%$&$,3#%."$"(8;3"/#),M.' !"#)./.4348BGZIrVTNR?FKJDDHMEA1/3=A<<<:==F<9>>GCD=:@8A;7GF[Q`ksztyqdifUITqNScmzwpspp}}mrogn}zy|y}|z|{zux|yqspmloutfkwfegg[ZRVJPNLJNSLRNIJMHOY]_\aZ^pYYZUNOIPCA=@>?NDKKEC>?;/5W?(&+%$#'(/&((%+'''(&()$4%>*&",R9'+H/##/#!%&<&#5$,{B  .#3A1613>9=VSHTzXWYJQKLES[HEMV;;>69?C=89:E><9C[FJ>9B:979=EGYu~u{igmr~hHMSZQEK^|[aemmtx~svo~|}}z{}}~uvwmnpqu{~pqmvjwhphnhqqznf]fWXNLULLGFMRNmUSPJHKUS]_a\\\^^c_U`VJLAB=97:;8@S>:989>89?DRD=9;@NhxvzbXrlSV\\K?IXgh~]gjiciu|rnxw{|{}}zw|uyrplgjv}{lpwmmlcf_c\W[\[__YYJDAOOODJMKNVTOMLIORY`[[W\XXVTZUTKGG@8@79<<@?83=DJk2+(*.'(&#'&+*').(((4$%&&&%"$7>'"$7-*-'#5* $1('!! !#/$$*6-.R:=:AEHINDJFVRT_FA=;@B6-38B?DUB67;7<7:=:=JDAHN`toqVgtqvvpnc\Na[[YXeqmp^`Pdwu|oo}rty|{{~{yvy}rkkhigkohgpm{tksc`a^ZWXXURWc^RNIDILC@BHL\ROURPUX[Y\__Z`[WUThPILFEK?;<=6:=<655:8::=DHL?@Nd^QZxnl{pWANOZZ[WhlbndSGT^qqrvys{||s|{w|~nmqghjcjmkskdkablnf]dSZT[W]YaSONOTLMOJFDEP[UZPa_YY]c[da_biXRPOKGE?=8?;:=9g??B126,)0-*=-<,/2)++')&*"'&&&(%$7'(%!"$$(0%&)1-/&'."$" !; !"#&)+),32ACVAICGOIIPQTNPZEI6,-1:47:D7779;@D995:8;:@>>=9;;A>=9?DAG54711..*,,.+)+)(-(3.)'&7(*&'$' $/&1"!$##)'#('.;%2 !!!)34!&!$")(=*6675438@AI>DWQKi`y~F),C/05F=389869=DE:89;7:<=<:4@@IgJXt[anptkkWP_idc`ll[HFHR[igdkmutyuytbhgm}kc_faf^`bhz`jl}b`kYoZWQSSoYQUMKTT^VTTORLPNbSP]Z]a_`]^a]]VVTVQB@F75=>:>>;../,02*)&)*,,)-))/'*5*)&$(&.$#0$!"( "$!$*%('%!2$% (M  !$(-0FC5.16?CBDGTp~m^sV3&).-68=;63769:<>730654AG;C4;EGG^QT]dfrzmmb^^}zhffdwgwo^ZIBM^_jZ[yklyqz|mehmfiifg][p_YXb^UPTcb\YVVVXYTShie`UR[ZZTTSOUMJJNQm^`ki^_^da]UTTOI@>:::8?:::99/,/1131,11/+5'+*,*,.nC*($"%#%"%  $" #&(D7Q4(-"##'$  'E"#(*9?487.8>D;866:=@MQQSh\`ppjiltXU_[oe^zZ_jOilgj^YRTOSrfknh]akmofjjjjckcZVRLNQghyYOONMIZRXTOUWUUTW`X`[SSMPIJEPRTSY_\\ia]ZWVNFAB@[7:6:34??@CD7741/+.415-&')))))%$'$$F&$#''&%$"""!+'*LN)(%6-5)+ "  #+0+1:?HYOGGTXfYVHYP9-*)-+0W5;*(0793:6>748::A787>CJVUTHIZ[hjwta\WaY`hf^kR[V^bck\]dIWWV{W]f]bdfksogjyuqabc^YWQXTUXT]NLSLT[YZZXXe]e[^f]YWSUVV`YQOT^_betjc[SQLCBA?9A=6766:@O9>;gE553+./..+)(-3,(&("'(&'%)$'#$#""! "")&+*&&+(%)='' ##'+*43@;IJGHLQEDQfOGPBBIBD>:5//,>82/32<:645556A>83:=?CILOGLGL_aeelgS]_a]dcaf`^_mnhWXULFXTLVV]cYaZe`]_ozoy}ck[[[XULTYTRQQMN^UVWRTZ[W__cbk[[\`gUV_ha\RXi[ZZg^aQOIK@A=;:M=68225\A6FDD<436-)'*)'-(&*)((%#$#$&#*$(%$#""$#..-+*%'0+++)H)! $.#")!*((+-6F;>TAORIGJNQW[OADHAA=9<3Q34673446:760136;;:=6ABAIJOILGTqicdfbc[^Y`^Ym{gfe_}_Jm_u;JKU[Z\g^Y^_a_di}qs{lb]NQTVIWfhVQJORZb`]Xd^_\a[bc_]Ygrh[__gil[eeZ\ZTNKKHIHB:23538@74421;4>>9A[34./-*)+&%&)(('&&$$!"%%&&'(-* #&$+91?(*,1064&" $)!'!/* !')!&(.A.N9DHJNVCDVgtZTMJHJAF:@G>%(111/6/6.41746696:JG\FBVSFD?Jbl_cdepf[KNQXdmkinj^U]_iSLM@XnYMWiZW^ebfbrnyobfVHRSXN}WcTUSWSYfe{cegg^f\ibd|_lpf\qepce_ca]VQIGDHKRND6765/2=:648<8:4=8704/0*'))')1**)&&#"#%!"')$%(%)#"&A;6+7'<5'&!'% #"364$ !,+%',3A_3>GIH?VFBDJ[VMHWOFLN?>;@7*$(/5.0..-/513307845BNBIHSLQ@HS`bYidkr_ZOUMmimkszgjUSQZ\\YgIFXbTRSSRN^]aj}~bYUYUXXTSOW_^^Y[gstcgbdaffghabkbseoefingidgTEHHGHURNEC5414DGB42469<721323.-+()'&'&'&'))&-&&$/"&%"#%!"$#-$&&'#-#b+$ &'!!(N ,%(+/0?B=?D?GHCFzJDCJRSGYP<>9B53(&)(,-/6/2617;3386<37;DFLMI>GDQOU[gif\UUB;Vdde_`UY]`VGHGFRZZXWYPKMSZU_efcWSYZ]U_WTY\Y[[^\``d^\^gb`ee^hospkiiokmtihbWYLMTMFGV[JC663::3<;56-;;97307-*+-*6+,$$%&($%&''$)(''""# !"""8&%(&)."*)2%:>!# $')%&$',068<:CDEENOLXRAGSNKFLB?8;9M1/*&*10-03485566355365:BAKK^=<>MO^eYWWSJTRH6P_hr{v|\abfZRNNFMX]UWOGOOPSU[TcfYXYXXTYW`bb^`e]\Z`_XZ]ab_ajdhhljrnqohfjrd]aYOKKHKFMHG<45>;@46852169::5011/22,-1).)($*8.''# '*%*#%$$$2) %-1",+&$''!N?  0 &$&,88;@@GANUKMOCaJCOIFRJ@;9;;@65B*&'))03748467446432@B?@E8E78ACTYRPJS]VWPFVne`bpgbYosgZXWTQIH?PNUaYb_YPN`ZR_]\^]]Y]Zbdd[XYY[Z^d\[afeZ_eebdrfjplk`[f{plWTQRPLJFLV@;6>9SA35:943C99A7504CVo67J+.'*%&)*"%($(."'&$($(%&1&'40#&$#/".0" '!  !$"#**5=B9DBMOPFHKJIIEOFHEA>??:89bH)%0),04/5338BM8:=96:=APE9:0;88C>IIKVjYWjIYQ[X\YVILN[][[WWWV`F@HSelr^Pa[ZZSSdljZcdcb`a]\_[^Ucc_`_^\qqgb_hrqja``bca}`^VOLWwLRi?::@;=>?6;92958@@F;5950,0.,,*+.(%&1('%%%)j#&'&%"$%'1&)%"$#% %-./ 3! !$#))(1S82H>GCIDGRQOIER=;A@E=618B[21'%(0//1/@5257::283>@D==9GHNG<=BO>9=>B@=EA87<8:>N=F:,/1.0.3*-'$''&&'% " " %)5+$&('$%&'#" %" $"!! # "')/47A;4337EIJFJEGAA@=?A:>JJLLOXeZZZR\XVe]Xrsod[[YNQKMZNerffXahe^Z`cddcgkj_`Z]fgmfva]e[``\]_^VORNJLGPJKEEFIDEDljZ[_hH_w9;>=:99C01-)22..+-,1&)(*%!!#!!!#%&(,%&()&0'&#!!""#$ +"!!"  3!54 $#%,+08504:;@ECMME?QAF>?>=8;9=4012.$#((*+)),/0262-/CG2,4A<5;J7;RPJU]Z]]YRSWRZSwqb[`e]d`m_\`tx|sXZ_bq]midhhe``cjziZdvhbd`wup^]S_VXTWONLPLJOGKDCDBDB@?>FDM[\IB:<69375C;20/03..<-:-($##$ !%))*0)5)**(:(&'!*$&"#!(9" $2#!&!%'()0082J?==KIFHHCC@I@>=@A97>53:;S-)('#)(+-/@/34*02<308:C8I>76:?/71+/4I)(,!#$!#"$,,*2.:*&&'('#(!&$#"# !(9  !##+-&2D@AIFOERX`RSPLGQT]`b\`[QVSUbU^^ajslbU\r}~jNWQE[NOU[`^\Z]^VVVb_ZdbZYYOQIGJGHJHPHJECC<=ADEIUNJAD@D:NVJ?F<<:<=;>i6A52WI8++(%%#&0%)!$)X/*(-))$&(*)# %%#% $ $* *,&/29=>OLFDDHAEQHJG?CEC?:98:;g3?H2?/-0*)(*).43,2:>79>>:>FA@>D489IFGJLFWWHGFXUSWSVUTNNRUQU`_WkfV\dytqYIPDNQXLUTXXUVi\YV^aSUROOHHBIJHDABEFSHAEJ7GMSp`NFLAF>BAOBEDD@9@?:7?r[H9480-,/+$'"#" ;+ !"!)G+1()'$$##.7''-.[($)*("& !-!'&)1!!%&$:=8GOG@9DKAIFB?GAGHF>9>:7/@/5)0-0,&('%"*,32,/2654=AA;;CDA@AXxY:H=CHESJISQ\PP_ERORUSVWQPVX]^_[YPRdmko_ZW[OUZOVKI[\j\]`\UUNNNLLKHEACLDEBBES=FED>:MWpjbLJF<>@BACCH6@D8=E25PI:GE.,))-'*(͓-!,(!')-%&*-'((,0'%/'+Mj(%$*' &: !%&$ "!',.17T=:AD=>E>:7OsimoaGXD;9:@@IFCEGIPRFlI=8=7?:/2-*--...)'# %('0./2?>98;>@94<<@HGHGJLMNRNQZRReGAIQKHMSQU[YMRNRPKICMMSPR]KDDB>E=E;:<@=D=F@<9CL=@PAJDCEDBELKCF;?@;43/3,/45721,((.0/5C:C;<>>?7@B?I>:79;FFC340/++/291H2,30-?+(/$"#"$(# ")%'$%$%"&%&")(09.+(68A<'($ 6%.!""$ $'"&((#%*(5LIC;73035;Ii8+)(%%-27OQ@JO>:8@9;93R}HMK?=5,4?BCHDLFOdD>C8>DA@DG@>ESGC?9??@;78;::>:G=T>H=<=;=HHXDK:==o=74847.100/*-++)<,D1>1&&$"&"&$ "%&#(&!$&2)*''+2@.))4.//,%(%FS)! !3 ' "+"$"*()A87B<9CKPO=41222=@:3001&&.:O?:QeJ58CA4'.4DIF=FUqbG4.:@B?AH@9CJG@@9>CAC?BE@HDABH>9=;D99877?:=JJ??;<=@;CAR_TLYM<:88;=3.('.)$$+"! $!!-! $"" !*+2M44@C@77B>B=B@BB?>B?FT\=:G649A93=895)#+BAA>JD),99DHFE@HSD>9\ETOP?IDD;558@?>?@>@L@<::89<::8;=B:::AABAA?<;<<=89:75788:I@L>;C;F?C+ ''#" :6@((!*# !!!-+26*06WI:H2:=@<:@>@KIX>?E@;:9899654858;88=;?=;E@C@:9:9<663A>;588;C`LP@8@>D@?=;JKF=@<7<9319;8/R9-2.0-,+&J/12+'&#""!%&%'((&.,*)4,,3+0,)2.W70*;-&*52'-!$)% '&!""#%##'0369:>c28;C==;9CUF_JNML;D8FVa7410311-%7-557898419=77M>Qg?C>=>XCBCH@;A8:@79289370.+*/H/,*&((0,31)&')'%;-/)+7*.21=N614/3*,,;O.3*)&()".%/( &%!"! #7,%36:/59G89;:89=8BN|HKB=H<6C@EJ734;6:2)(&/116B=;=?7;<=BG9;JKe>4/.04::23:Crg=@4566564::7956<:8<<9:8:=536666;I48:;4386?EE<<<5:<=-2:A53894364:24/-+01*/**))+)-R='',43`JV1354324/:-+,04;/?<=1.'$"*"" ($ !3". #-4(')8?1357<<251;4?8@VvpvJ;8B;??@CBE>B;73=3(,(+45899AB8:;C?3763;BE4@4/41=<@:CHMCI@42/87<6468:75;CJ@;8<8<:582555516@7>=7:>5;7465204263792585<;?H8:>9<;7?DSG6>X613()$%*27=967GM>:<6;=:J2D6735..C??::A@ME;95298;55985::@^[H74:7332/200298278:9:6574A6;4724146:RF:9131?A:847877674267/7?I.01S55996@24>_;,2/2=>2>33;1K:_78C/-15=<./10+)0YS1.*&$ %&&#'$# "J#.#)7>==*%0)*2.879/223004RGPBAIGJ=:<99VQF71*.474/+,(472726=B@?=79>3444>:012?B7M;;;F[B<7694719923636:F9DU32404I43153=4C9=3247;8996876727=78?>55486:>=5=6=984/0956BS4026:T<E6<7@H?>4JC5./29>EV?43501252536748999639DO@:665455456IE98764639=7=6625>/0-115S651F85?c5;/-3zT0AX80LB77258264620GO4/+%('/15),*3,(-*&,)&9*,?: & )#%:'  2B+.*$$$)))+.*-/00.3//2@BBII_?Aa@?AyT=8>.053?;51,(-0642869NBL?AC79898?66g?C+15=?MI36Q83A679G7;2:98:AA>5A9G;=9E8;N8328*9495;1<=77,1862/N>74>66`K=7215770x|98876/43/901357=32.j#').0)4)0.&?7+'**94-+$/+:4K+ $2"!$!$#$,'(,,10+015*(/>A>?A>?<<@DE:AE:88;.:4B:750+.2;2F47H@FA<=A;M998899489:9?@A3974;54:77A:A:12124;[G7<>:868/23-170E7A0;784F7),A-/419-.3/2;/21(24074G//1.)E83+(*'%%'%(&0+*,06;)((@%&(.,%,14-dG# 4%&"!2'/0-++,/4/.,)),/6F:9CgI?A:56=>I=M:03F642--''145H=;>:@FMDE>8NC>=.+*-9B4:4?890:?:;;;?B=;@BB?E;>N:85;=S;:=57<799679A7;4644>A@:2`S99:;53M^M=3A3:276>2545420,0(((%,4/<=;4/,.+3CA95C?4,--/)+%')&*,(/).,:-/D+&,''%)3)2**6C4"$3 $!#$(?*(.25./.-1/.?5A=;@FEKB[BEDurKBE,05665+*󼗎X:;CD<75G=@H1,4/47-.616966A=9G68999F9:UC>>>F?;@<:4@245768AC8U373;9WLS>C=8?88.96952-3+*/*$'+-4*14/:*+)G00+970;<5.2+(&*,E>*,))<1+64-5/*$+((5-'%9)!<$#:!,!$&((8(229+/11*,0188:A:F4@57AL@570//4678DTL]Z@<4<;656/63=41*5+-2145658279>E>?@@B8;B@E:77>?>4:;HKSY<=89?D98<898J6/8GDAA<575<.24847EgG75:23111/23-+-.-----0+016&-5->0.-0./10.2-(+:0,)()))&1*%$9'*&)':VX&*&&!!!"!#$$$#!&-,.>6,/2,*426;DDFJQE<=CI\D=?D@P=-/25aFJk77;,,;;AGaxq?513--6>743;P5,48=49998=3/987367T[K<17221+07+,*/31/1.7/2),,*+))./80,+6-(3*+)(4/+%##$*")-)%&/'%,#*0.9-&"-(#  .*%+.+=+24280,-/237NDWLqNsKLDT@JM`bI4*-1ODB607>E51/G@X`8699552683@CYA//0541,*0++&--**-85D5+)6&(&.*,./+4+()+*(/+*)-&$)#%#+-$+'&)&%$#)(%%*'"" %$!& !#)'($/+*.,1.15E-+/2:HK]GGQCB<7WCFnRVM>37?54B=?>?^W@26ARWpL>5622.0O99E<;;>5..9;44.372.0476464364:37:D=?<4<:A>B43=4L4;--'2),)1.1,4/R/=+))1-1,,.-,59,%%+((-(((%*.$)))"##,&*&8"")%%#/*#!!!3#%%)&&$/9./)4..708/125NSAB>D=7;:SJGSH>2R4414B?EB=7lL7.02.455746;<<89-,12005343/552131668100.JK6A;>:5-..,022031.0+*4B`>?XxY4>F6845730175VRBB6=A:0*;/7*),--*)-2)5-+*055141/..4*&'$#$(&&($(%/$'5,S,*(-+WA,&+4('$+4*%#!11*$#$&32#-.(*+,0@.-2.<5GFIA:O5E4525456624516699TE:BH0.54JSs7.:2?*$**..*/@+'')<-'%,>N:3-1450(-%%'%((12':.)&)/54WvA+:U+.9,')M,1'''$'#"89/2%(!"$'(-8814.--4/0/6:ZLD?@>X?AMOT@8594=759?>7@DJOII712TF7T544.04+*.CGVC/2/.-A+(8*071.069K1472343/4;?5550,.1,-,,3+3.1,-,3<41=J;:8DBF@B;1.421.?P0.,..&+%).+*,4.1+'*.+)9B;<5*43-(),*(&'*&*((+?-'%&)1jL//1?>(-**#$(*%F,)'"##M)$&&%#(%"#(,J->5,.136/38@B@7A;@JCFAHB=,34>DF>>DHZQGD],2.4(*,,22;/11-36@LZ=.+2:1+%"+-/2<752I3051-4705?74565816/,*..+.5-024.53:1@VC9BFD?AE@60/(/002-,.*)'#$'2/*)2Q-8&-'-09I:64-+.@-&%('.'#&!$"&)(%$+$+Pg05*,jR(D61$'+%' //* $$%&A/&?T3(%*))*+,13.1726?>@A>DDU?>LS>5GBBWL@?G\NkDrB=;6."##-/45115/:5;V1-0,,*)-,,+.03-,/91+.754?8<;803/-.0,.2,.0)%"%-'+,'+)2-52/+-+1.,742;)?4%"#$+'&$"8$!&):' &L`/.-/%.,@;03T(+2#*(1:!##:(+:5'(0)+(%)C&(,K221382O>5;SIAH:@FWI:DOKg<>H8BB4K^VrA6B&#'1465492697>>=23601,:_:1*+434/327G81,-,.-447;0125B53-*+))))-8.2/./3--37918B@3370/)1..*.*&&(&+*-++/.40-:/*0+((.3/*-62'7$!#%$#%'""!%%'%&(;,(*2-+,.02((?4/.*&$''&"#!$"&010I-$#/%/(-5M)((310126:y80BYDH^KBFGB==HHk9;6:>@Dsn`eN@>-).01<447=51;F8221042-@:5>&'.11-2C560]15..0-,0021C51+-0.,)(**01-..(+,-05L1+BN9929,(/,-?+3F-,./(+.*0+49923*)+**/,,+,5+'$!')%&&$!!# "&$(1762+=6:+.4..4-5%#"((*AQ#""Q:=2$#%'(%&;6D*'$*?:0,441./,,+5%)*-(*6));621/+-:-'('-0(0%"'%%#-8(/-K3*(#-.66E=02'& )"$$% &$)1!#&+"&#&&%(0@#&$+0/24A:O.7+).+/,+$NP4((5000:584//33752200+***))+.U/&+('-,(('.+-00.<,0-0.&-)2575[Pcf48;,*,+02)-)/*1.(/,$*K/B0,*4.&:)'&#%)-+.-*D70:)#2/62@E3,.60G*! 5&(#-,$!%)($$&'P2,$$$#7++*746348:8=;IJM@>QEC;?@;,*4E59BL?WF=T639&//-56?<071>)+*,-40-0,+++5;95<9676D525/2MF/-)64.0112,-051)+'++/0<4104,*)%!"-/12@I=7;;-0,++**'.0+-?+*:,6((-*/02*/,&$&$'')(.-*QJL4+4GU4+)":I4-")F/)*"0 !)'() &$#') !##")*)*JP=-4:6F:;7:DGA><:J=I:?890K*9?LSDHFI>J*/?'.0I830/D*+*/278++.:+&0ZI?MA:4;B:1-1.OP681>158866655:7.(*+0-12011C1-$$2371C6@5552238-'((**1-o//9/+(*-'/19/70-***.'',5IGP{X4,GC,*;)/%&.-,$J$*B$!&  $"%J *%)('$&"%&$$"&*'*G372.36113?:D=7A@DPB/265@CAJq_:@.0,.-4..+,/..C".410/24H523?058/)/,)6-+,'+,--,.6..-+04,'%%&,&.+*46>PdHly""&'(>%$GWU:"%)+#!!& #$ $&-/""#$'*7'/(('(073-27124<:23<6A;;1<4@BTiWa=849,:Hm;2'('+6+2V/)5121191./0,**$.553651B?10*-::64@R?=@OvCW;:4125?50.-+20-0-1<3c@,.405682h3,6:722+4,,2760)()11-=E2-,+/+:)**'-910DkK=?S299-6*1'+)@11S,-/2.1-+0-*8T.+@25093/L1&&%-ZL@H05&'1'0>/#&'.2C2472,,&.(*,%(*S46+7G::.(* " !""=C.+! #!$ "$'(.*%)/-303,/121:8102226?6>B>IhZUkPQ8,1/44>+L1+*(2?9R8722.;37?C4100/3,0419?C<4273f:7;>CLQd^Vm+*$+H-6%%*#$+#$%(>F(4]AT@:#+ #8)*"0- #$!'J#$3*))0,*&(,-5CE+/282:.4<>7F9032G=9/:..,*/:.-63-..+1:C*'2$#4+35*18)+!#!")&'1FG# R!$#($@-)-SLM?Qc:2 ,* J") % $#"%""B!$+&%)-0,.)(-43b4004.929796)C<(! "$!50"%*!"#""#"%#,(&&H7,/).11543,,3.O50/2915;CgP\RME617 "*-,*3)+-849AAB87341423446749A@SA;69@jC91L41GG32.--/;/AF28A201(*)9,;,(0-+$)# ##" -+ ($&/-&)%)5-)#&& #%0,*9 !""$( & *(/$%$/(*+/17*7141,07552531F5BdeF745;76776>:768=38/-(0(,..+)$'"#"',"#) '!&%#+.-*G4+1"  - (!!;N5= 1 &"$"!!*!/$"'%(*+-01.-*.+0*37,M>6556??L>CF5B9101239=/-+.-240-85630P5>7=^9765::521<@;6=L82545DE<9ODxI72=3265<0368AIH;<5:857.6/2851-1O;69O4A078;938=9.31,/--*.+)'("""' $*% #"%)$"41'/('! %(S?#8 !)&#(%$"+&'1! #(/9B,052G1-/.(*-0AE>35589@BIR@7L;:4B8?JY-&.,*13//*7/1.:7;6>JD68OD<@4788880E,(23U@>4;-C467D5<85=8?A4=306/32)C.--4$'*%(!!!%+!,1,!$$$% ! !"&&)'")#5" 0 E" %$*)13A)1ZD1+.,)((-11384WBB9C@?99=<7:;>@??-)2-4/3,'2(:0*0./.,BW\87U?815<6D605%,.-18>629049:=96MX-/1462?DA88M28@33-.;E6/2:8;650rAEG[MA8,/5..'(?4)0$$(#$"!##%''J%$)!!*!3(B4 #"  -#!%'!(*+?:64'06WQ)'*$*,/6:I;RB?96>8GIF=?5B]}H70-/32-:/3A-,,'7-+,1:;BF:B<30557INT@,+,3;476.0-=GT7:3I?*(/3:B::A?316M762779JGVE=6@542Z@FdkV<@119+,'&.+@<(%$##'' )$B"!'":%*  "%#@T-"!!$ " &! !#'"%(@M?M;/23()),%%+*225>=GT71525fAITES==<42-56.,5>I4-(,,:/.--559J;;85661572MBA0/459>030.2:?727=C*+).45823113154384.41=92:?*60/7=K{H;13,-.,$))*8(@8*g( !!#$!$#&""# 2+#"$#!! #,Y+"'$#%# '$8Q:,ZV;O,3,*+.+>9(#6##42W7Gm5;<5Y9/53FD68/,42O1, !$81"2,5##!%D*%'(#" & " 9GK')3&6\(&.0P80++,A.20.4#%$"3.7+682/AGmFK\hd6435.-,E:,+@99561.)*.,-/.?K822@A253,)1023,+-1)061,,.+.920*.,133@1/22/=<<262D?33?OD?12,0J6;:3;,5(3*-&)+R327@C/0p=+($("%BW!&.) !%0%&%+'F #%D-<)&,#'$ ) ('=1&&#bj&'2%1=/&+/0.,02,/"'!*10-4+++;;98I/377?3*-)93U1523(1'="""%E1'TI?1>fI)( '6m+'%+!>!!$,%$&!''B=/)$&&4P7DB%#!",(O &&&)&:'0.%%+>`D9.1,-'#),,>>.:EC1?3VPB=2'#&)6>8,;()+/'*+=+*+117,..03iC<*$&$%D6166,*,'&+1)1204+.00355/3?14878F897:?5.01;,.*7-()-*3.%#'<&(6+%')3&+@@6Dc0&"($'''(9';*##1& 1#",-+J,+DN6Rd7(' #%/:!  "'H$&68A3Aq6998)$%()*0)>F,/H207.'&#.-(1..%)&).())&/6+-/.H+0,),?oK1.'%'%)45))(&+1,9/.0,/1/0-,015,5;4U:C5f564773*1@0/4--$!24'&')%)>(%#'&"%"&!(>58)4.)!$!'%$ "/(!)#1"*+"28B==AR9J}T/'H1H&!% '$ &%""3(2?CILA1*&"& !##)%*%(&91IN/1<2++)())3/,(%"$'(-(&./3),+&))-,35&'&$'%$()-/++-*))*..068/20,,-0+75=884AD@:7214Y70553:@21''$:#".;%'(*&%!""!""$Y-$6).O$(&"'!!*+"#(?$S&&;.28``ROPIk7RP$ #.J#S3!!$**,"&+3R~VJIe4A)2*!&$&%&').*)193+))'.9'&!"-*.,)'"&'+($+)Z*/+/).02"% "$('%&+;$'C*-)&,+2'(&*1+.-H1018N<4;5T6/SR>O=21,Ia?/,-%)+-.6C(%'*,2#%#!"$!$0'"%%(2AP*%+48/-! '3!%#!%o.EjrGM'&%&%$$"#*,+)(.'(&,$%3)'#)*!)$)#$+'&11&*+%*J'$014:-/72:1075799SOV>4<0/:8A3-.R0&,/DE6% #+V%%%$%#*&,+( #%6X-*.""4AT'/--# #'%G+]CCM/fhX:,M&<;=## %#$%#%%$##&"!%$)''&#.&'$%/,""**(#"#!,+'!"!$,!& %&&#&)+A+%2,*&%*1;7TDRodE0))-*5F^BH0C20(%'/!"##!" $"!"#'"%"F"*>19$;)##+& `#9/,(:"$$"@$%-2%)3$ -}] !#!%>,(%#%z5>&-+* "!$,"!,$(#,!%"%$#'&"&+')&1L"##/'"""# !  !<$!$   ! #%%'&-7>:('5(*124cnvg[/-.$)5&+/)0/8%&&#%$,**'#! 65)#3% .$!)"#"(.#'#$&('$$!#!$#!)%=&3^"#+'! ( " $* /$ +%! "$3<;mM*.,2/1..uaeD3*))%6)"!"'2%,6%+'&&&$# "!$.!6J85@I* &!!!(!".'))(%&"&).,#"1#2*;0/ !#* $2(%0$$',(&%! ,(!&"" '%(%%#)& $!&*%!!"!A""# "!"!<'5&)#,0%&'3/WIW.%$$&.'6&'%01-O@3& %"("" )#.&%$#M-,*!4! )!!"!,#-s0YC '+$-T~q?$ "!%###)'#+*#'(""( !%&"#8#$! 2 ""  #"$-"$!$!"!;$!.>A2NDo'&#%&)',# #+/-87e" ,#"-,)%7#8%&3E"'%&*""2*!1i155+!'/F.QH5*&%# #%)*$"$,("#/)%!&#$&&*% !%!% !!$'!! -!!E&)%*).J0PNQ7"""01=&".($E%&'4 )!'5$"#(""$3-#!"/?'($&j&2G+" :!'%!"$80-C169.$)#&" $ $ '% "%#!!!'#%!& #)% &-:,6#".CZWV#. 6H18+ ,8.!!1 $  %#* )#  ."#&    NC*#!)(Y(27="'"2!$ +$%")*%$1@N?B+! "#%%!*!$2!$""#!%!! ,  )!2"$#! x;"#* "% *8&"L "+#5$!0   Q 4?)!#& 6)!#<$%/ !#" 3#$$#/U?2H !$!"%!#!)/// '# %!!"% !!,#!"2 " 8%*_(0 $$!&,!$ /&!(" ((;F0;#",)+'$!! %! #&'%$"&@2,-F## #""%!# ("#!!'!  ( ""*E!'!&%(!/  &#"!$""*! # $%!"!&%##%%&"$&%%! $#!!-!#$$#('8(#*$-.')./+(/1T(%,1-;ADUy\;9>3FoA+++-(-,/((%2 6=))&'&$#((&/+*(',"'(*($$%,/&)'&+&()/15/21-<&-.1/.)0/4.8A74),$%"#';L/17C=9<2:>2496'.020:=*,23/1*'/'''34%'" !!$+#")%! "$" ! &!% 0%#%&# #"$- #,"!!#("%#$&"&)+)5-0"(?,)'++#-))#/)4-1,1.-824,)0+*)5+./501.,)/(&*$!+32&23N84I4MNI=I?>;;/74*,/574.#$5,*.-UDAIIE=GGELSBD?CP9@4+.-11*,1'/)*,(&%! " " *E""(%!! %#!"!*&$$&!! $'&)!!'&&2.)'%#$((%+*%/-(-.(57/3/5-+%>?,,0*"'(,.4L[408UlJM20//-74(++,'*&$#$"+%+-+'$&0$(*%+'++''(+350-3/+0)(%$+,-78737A988:2:8395C:31./,,15)%#17C038=69C2;IF8.,*.!%&("#1).3 !#4  5+'-  1%! '% "! #! #*-!$) ''')%.,/@- -*''&!/2/<@,'1#" +?-,33+62(,/04?D0*+1*'#%*(+-,-,#/.# "*E&"#!"#"$'%!#'*+>0000,,5(,#"'(+,.(,38Q:[:77>E?<29E59+6[?K9,@-*(/,?>MRQRIELZJSBDU=DR`43.(+(-$+$*%% "!! -  !#%%!%'"&!"" "*!)-!(.'%/"+%+)*-94*&%-2*)%&@?EgL-$!!$!&2>&-(-)0(/+-350,-).-,,')*--+A2.%#$" !!$*"!$$$&)"&&&$,*$(,)(*+0'!,.4,10*(-0PFEHF?I;=<:F@+(+GI=6G[2"(50)06,-4JFFSQSZJNKJR`k[R@:0.+-&'1*#&(%##%$$#&!/+%;# 0;M%%&) 1!$$& ()!#  "!$$$>#$',"#)B3:B3-R1.(.103B*++0'3>/-)$!$&(/4*++28-*,-/4HSMf<1.+)(()$&)()% )!7*: #"$%" $&"'+%#&&**(&*&%$$#&8,-097*03++#*+HBWK@B?@8:?>A.3|B=@22FFAIHL\RFDjJXY[NA@CC/.7K:1*$#(',B  ! $"#'"$+)'! 5:,Q4%# ?1 "!9-%#%!&"'"$-/'*'.;M()'B5:+0+13+/B.138.1G95),/0/+('#&/1+./.0,*$ ,=/9zF(+*"++ >J')*6.5%#%0)$$&'%#%$"%()%"$#,#$$%$&*Wf*L{0**/431-0*378<7?>TP@CLQ8T3/1VJH;L{6.@JRFh\ZVJEKJNflbiG<77.68098)#'95@/ #!!!!%. $"$!"" !!%-65#&##*"8!$'&-)%# !$$'#%)+*CN?O=A;DDA2/>f9@P^6*,D?;h{JE?DFRdY|rC9I>@>46@9,+,0-0%#"!"" $$$%"!!"#)" "!!7+1%',3,/'(&)*"-'# *#"0*%,&$8,1,;D-B9:>TE/&##&2u1((0(')'(6O(#&('*6*+*((."" !#! !&?&"&$%0//05#0.?'&%#1()*%$%%&'$)%&(&&'(%$!!$+'.-3-17/8/110/-(/0J:;=9G9?BCA>75698:PNM>-43=@JeSeHABVU`~qL>22<=L:88/-8033,&# #'%< !"&,%"   "$ ) &# !$%, " "$%&&*($ "# ##(%*.D'(7#!('+*+3..719ONY(F(&"!''&,$&' *!$'(%D(,3C*-(;4(*) )&%$$%#!!; !+'1*...,,&7*=()&!%.+((")0-%%&)'"(&*'+%#" ($)G1LEH123401..+,+)474:B<>QNH;:3/49BAE@7804:88LJYpLV[\MTMJC44::=712-((.07/"%#$)",+"%%!#%#%#"$$%%!*2 %$) &*%# "!!$&)'(4,$/+(0-*.357/028GT*74.(-'$  !$$#"$!$%(+',-(*/@X()-E'%$(#!+#$%%'&"%$((3'()9.%,<('""&*&+0'-&)(&&'')1*0,+.(&"$)-,(/55A654212(+***:>=::7?GDDf30.>KG5<74.8:62+.D^Zewa[MIA:2992.2,/--)+34($%"&$##$"$! #!&! #%"*.G(#""'# " $&9%$$""&"$#&!:.<,47/254730$-O47.60*'%#!"##""!#-/0)+2&%,-0**.E)"$A!"$%B!%" #$ '#'#(*(+*'876$3)&*&+-,,*++',-/.5,3*),+%!#"",+*$%;a20054/0. (.:C@7ATA9BA96217^KVG78029;03%'NNX\SMUL97387,,*39,&(,*?=6$!###$ ##%(!!!"!!$0/%2$$,'#!!' *#$$9#!2$(I;(( "),);',**375@=6J4@)87--/*+0-1$!(,-"%"()'(#&*'%%),%)(,()*$"!%2""&&%#(&%(O&0)%@*' "'%0m2*+-+0(.?()8*+*-.3..1+"(:%*)&,2,*(%/2))+31-1-*'--095N;@C9:C961466=:?710355-"FKRhPSPX<>>6?3*+>1/(=2,%&/,&&$"'!(<&+'#'"# $5$<>/-&"#  !# $%$%#>2.#$)*)$Q((!$$!$*'*-(,*+2@8482'$-el6553-//2(!)+,0'%.+($"!")''+,****%$(% %04%$*'"&""%&&1(")*'$#'$,*+--(*--**/++))-10/110+//**,)',--)-('>',*+342-.+(,)-;GH>@=97E>?34-2J6^E211121.%#*CPMXTQVMEKG:H7>0+*,**0-/)($$&%'!("",%%"!" "&&41(.-3:!  %! !$!$$4.n32"(""%&$"#"$*!'&)/,4,228?=--0+Ja3-J0--!*&-1+*(*,*>%#$+'()d))&$'"#"#"#&-)%$)$%$#%#"&%()%"")(.2+1+)'((*(')4*-/**/-/3(15.12,+3:@4,/+:1+)%37<43/.0&*/5M:@S915@?7555L4?;6.33445,,+4pwwbYQVMGE;30556038..@+%%$'&$#$ ""#!%#',&% ..&#.#" '"!#+(*).*,>.$##)"$'#!(&,%$''%&(,00.)12/63N<2a],#,2'&*1),,..+**+(,$%#.+%''(%$#&($$%##!!$($$%#!#&((''%#%3+&(*()*'&,2.*.0.030)0--,00:K.255543.3385./-20727817=332.27<<41=?8478345:C:89621.)01`{_RP][VUMC;N52<4CjH.4_*-*2.)#""+F,%",!$#("$'%)%# !(%# "%*W$:5%$,,W01'"%&"&$"#6-&N&)#((,3,55-*,&8E.[mp9&$/*&#'0*,.84*+)''%-%#*6(&#&'&%&!%$%&&#$#-' "'&,% "")+%,5*)7**+&(,(&-7041/4.,6/..*-.,*153=317067744/021-0512;1;=6346/8:9436B2>/02./20.16.1776780?/2;:69H=L8;66?643115440)"#)6KPq_MQSPJ\8;B:76/-*(#-0++04,&&,%*(+$#$# #),0$$'+0!$#'>$.3($&.+,*'+!$"%",,)&()%'%'3(&')*+*'&+ &1/6/',6(),**0+31209//*$"&#*%%+*')*/+''-/&(**)&'+'(*%($&-''&''+1,.-),'(,+-//4/0176=2-5E4/-((/3H6::U@0/2600414-/./3L43B@2568/+58:3DE@=<=;3:97646<9.,/&.8LC?JfKcE@/98=;2.*)(&()),/<7/)-'))'-'*)>$#% 9&&) !! .-! ?](.&&-0(/"''$ /)*!$'&$ "&)(&,+.'$$'%$#'''.*4F:1(3,+/.0*031B-$)$!!-((*+1/*,0E.,))238,'-.-.*%$&++*++)*-,-*++0++)*'0.)+,9633A8/01,/40*/2:SG=3-/1-6675?103313,/2;6843*3+4248=9F><96875888?@501-4=6D=I\[N@7B8GCB;43>+(+4,&-C1$A@,*)(-,&%#%&!#.4#&!$&"3 !!/92'')(51+!'"''!&2''%"%" '##&4)(&*%"(,)'$)*%"32:W>8D4%37//.-027.()+"'$)'&*+(+0+25-)-,1-/01,.)&6,-,(*-+.)(('+,,,&+&)(2+,003d=65@A4.0,4/))@:22<9B3+../39<7;343.-,-0??97:-'+(1488,-,(,/.)-+,(4CH/.#%"*'(""(,*(01#&,/ "!$"'($SR8%*<-)0/&")" !$#'#& "!'(&%&$,(&)''%2463Yt839+$-0+',,86A/*%&$($)).)*-.(-/7/10/4=;.2+,/4@5/21/06,*11,*,**.1/-)@*+=314@CM:6.402--+,9=:A4315E1/502G860<>/+/-.GX530-''/203:?F@7<93686==8:;=53:?FG>KICNC>DD_BO202,,2//*,6+#3.4-&#$$%#! #%ID0H:0'+.%#"!!" !*&JMA'+H,/T," !!!!&)"&#&,)+&$)&(**.*&/45^L5/3.C3#%,1-=-3),&)$)50)*(,/A330010-.323453>735G<4E>8;94002.*(*.)0.2:75:1-B[M80+-9..-*-3/:240.;46.39/@8<1164402.0:3113'*+),33?B=B792889C?>/1,>q*0% "&)## #"")%$2*$&*)'-&(*+-4.44Bwl?=<3613./2-3,&(.((100.+,+2/3E-//;;;5C0/1651?>B:?<=D27:963371=-+,+**//1666F1;B0./1(*(.*&*,9,0.CF375<0<5;F367@356408544+*/+--<88*%'(($&#"'-&#C#42(.#$% *% '%"+%%'%$*19*+%'+'##1.6?mɱ`W00<2646<3.+))1;++3,212/-/+)*001@C<487426265<=4X84930252.+*2.-*(-.-,-,-/+*(364-SA7..()(*$,),7F=32A937EWP75C82><32\=32.+('01<7Y778::;;>8638::D886QB6=N2:@fhVK3208;7/.0+$(SS>A%(&%&$"'#! 0*)%*"(&+..#! !$$*(0,=%#()$$#" %'"$&# "%&'((9Z.)&'''=+HW=:Q_WJ9201..=B@97,.0B2**-&*720106211332894:<:516976KI7.20+,0/-+--]1/.10**1D/+(*1$$1=@9,,88*,%.&+OE8>H*%301329FA:393/233A2-0-/%---4=9:E99:6::95,4::>9534/.0E88IfwwS<4023.1%,*&((#)&*%&(&&'$''#'&&"'$+"%+2*6).""",.$'.(!%"( ###'# %% $!#"('(&$)'/8,**&*+3L8<6jT=?43..0+/4?C[NE251.8++*%/303-/3.-5;869S;:67788:69>3-/0.,N-//-15/1514.001...(''&*4YQ32&')*#*&&(,3;4!!&+57?8:B7/)400.16*'+E+#%)>%*).1)$9830234;77=45:4<;421653.,,367876///2262350..-0.,)&%15@:/3180($&%*3$%94CI<@E=:94613856638>8?;8,%$3`~jYBCC6-509.&#&&!'('+("%(#!%(%(!"%)*)+3I*'&!!'*&#!!$&(7'(&&%9$- #3(1&+*'#!&(%)(+,*'%4;*63CK/A/C;AHB<0.3401()),'5+*0034:;UA89669S86469:5;<=<>91*39833352510--320.11.-.2.)/0.6=462//)++6J2578@H97-2:41424>Y1*-K9I/ "-0+/B'.W<>:;8598<5/47:769C\AX/"#!%\tgNA8B3./-/'3&'&-$%+()"+&(((#"#"!%)1-3]=&#$$%##"4)""#!)')98I-'*'-!$# G$!%*1%#"1()7.&(("%*$'2CV:375UG?]75;3471220,216339=;K>WA11/-2-,..,+711%08=145710854+10O6,#!(,/.(+&)C@:99=777555878;>?B@;-'O1!9KSUSJGJ2<0*/32-)%*#*2$#)'0')*(&&" $%*$'&%*/%3-1-%'-!"!!$#%'-+%1OD%!((#!&!($+%%.1+%#!!!'+4.+'*$ %%)8HJL\98;;F>R94=A0-010:323<=>;;CACF=DBC96=:87<>BBPH?D<=C:259C9376130.0+).*+,.001154BCF4F/..4;*./--)/2*6?'+47-F/43-.042:6'$&+0-..*':;3683D747=4<:9=@?D92+'2PI3T6AVPH]=7/-.*=01-&)-)H((,*++&#(+,&)%$&&'&$$-Qx7+)$&"!&!)'&).)%)+;8 "%'#1 "&G?0..+7$'%!"")+./&"-'&(..-9C?:==E614:39E9,,292;90:???<@CDE:@M>C;;=@ALIGRL=9;@E7I?:A;401.+.**+//11.1/+20OOHA22:?;=1-*-/F-$%/-)-5E4+)*>-25022.=2..0+00&)16972628=587A9@<<@2%,1$56:XB?NfJM@7267*1/+K((0*)'('+)'''0('(23-%&&%$%D|+',&# % #0&11?0@*0((!!!"'"#''9F:13+(##(&%.(-,.+%**,-(-/0178HPQ9B<8524.2269;I36B:`d?),'4'&(401/-2:345655<*(=57537>380A:::926)*"&,=@RSRT=:0351&.0-2+*((+(/(*"''#%,*&*Nh)*)!'(,@)%## ! -.%#KE&%%)#%#"%%%!"$&=@:.0L&!%$%"&'$%5""0#(),.15163=;D:98<<9;C>AEBE@>HGNKPIMADI>aS@LHNSJMDOJMGPHOP@57;>=4<7957811111220),&)2=55.-3858.2111B\831.35/1,,4,/-01+/40504=RG8,)2/60479;423=>>88:761.)"',+9GLQLF9;123+,4/.'+%(($*+#&%#%&$%$.-/0,'((,*$%#! 3"&048&.*.*$!!#&#%"'(AJ,,*)%((+=)'($%#,!#(,588R9`ANA5?=7?88:9?C:8C=>CEJJCHUG?PJhaJHPIPJKNNJRM>CF@@IC@:E425)20A+7*:/0=5CJ6Qd85<6;DD.+37.47/363<74:@<79;:/+2'").+WI=KTD;38415-1&+4*&&%,(%%"#$#%&)>,|>#!&/5&%%# $! $+=&%#"#$.)%&&%&$$$##'?L+;*/,1'%.,'&%&#!'#-+3:67@CWNG=9@B:>Z@>J783??AACBHHHMAN^B>@OJMHQNGJ_@@GB99M932;LIE?>;;:679B943?@:03.-7;99887593/37:966014:KBL==570*./"*,),9:36<FB>@=63<;>=dQiFO?EGGJFGIJUSNQQPPIMA;27E@J7?MORUDYF=F;<;6:=<@F864869999=<=89;:=?J<;67<>11-0,,(48/681/7BA=87658.,1/..7&%(3'''## " %$%1:R,'*!$##0"% )(!"&&!A-(#!,;*)$&%" '?%#!)2/*.X0+).&##'*&!2;Be34;>SJEJWCHEKKIDNRQROfVRFIJMD31?Pd>KJQE=<8FB@7=>;>>9=872658GC86>?;::9341")27./21@I6D9+(.41,;" !%$&(!#"&1#%#/40*3&*&#!#'  %#-#&$$7($).8$%$$%##!! #!$*.4,.0-.(*)(5(%,79D@=<8EL]YEG>38697<8>=?YLBACNny?=9?BEFLVmbLOaOJe__XZNKLHMRHDOWMZUQONZ`Q[VJZSKICA:BC@N?;B7;G?>>D?EFECA:D34SB15=D9/043333512430104208652K766<>;A:JM>4-08<;??70+0' ,//98796.*++7/<*'%''&!!%"&-"%'.)0''%%" #$$!!$## (--+'/&%&&(#%%(!#$6)##$%)&3.&,&(/26085:<:;>:9NMg@ALCDQLMZ_dVMJW_ZbW_\PNJPOYPoKQZ_\{}Rfc`WUU^QLSHAHA=@ELDE638AG9=@47:88:@=>=;46?*#%3.8KCBS=9;3++.+.)*-,#&$#(%%!!#&'$))))''"$"" !!! "'(%&(C.(!*($)'')*) ## ('"$$ (2,?5,+52:AEAGFEGKadB8>@A89B<:;;>;?1/!&0?6,1:58;3-.17345.5240-/*28P?5A>=-0368:;F>@Fq:5D5!)3;KFE=;4-$)*--/N--#%%&$%#&%*'"&A&,-)-!*(""#,#%!"(5#&/,,%&,$,$'0'%%#!"$!$%'&"&$(-87.3/2-59QL>9;<>Lsa=9630:9<20235384:7>202-?4FC4-(0++347;=;HCFTmLD\ACFMZHIJQJaľ|ywtZT^dmc`P_gfqTVVMIjrv`Jaiy{_WUV`][RMLLLWKKLXNJGCBCD89E4(#&078=5790?KA:62,88<;:67;23497:4479@68<:3-38%/2586?>\JJRCBKJKFGEMVkovhpɁdunliONaOSUh[drd_U@D\djXXUokeuhg}a]UUT^QLLOQRPSQLFAC@:B<)" 25&"2*8?YF:8965.89::8*#*2FHAIVOjhqtccnebr_`YUQZYTTHRZW][KQUa_g|xr^S_Zlpend`_ocNU`g_kWQPOKGDCDGCA,+/6:BAE=DHMA67'9S'4QSA<>>85A<<<5-)$3G@D9?2,62,-358==G@B>:) (*A5;?AA=/6623-/1**'("''(&"&$$+"(&& &""$'*'&"$$*0&7&8O%"#')#%#''%.#)$'.2//(#'42KO3+000/2767:736697?8D]G9@7?>@B7FF>G=?7:(')09A>9;9357@;4/4*)(/)&"&$#$))%$'$-"!##!$! !#" %/#'D[%#'-6/;5;))/*&&(%&$1.+0.+'&+20,+4)1287>:5G634<;AMCB?=C:/481DT_=>@ELFDFFDIaYYXYYbea\PHTLQMLSQSG[]o\^li[W_icXS[c[V`f^mZ]pmSNGHRPSQPOISFOSOVL??9:=ALMLK[F:ACc9/7CEB?:301*HC)1DB:?A7157497B>=>AHC?9f$/-37EB9446@866@0/0/1'$)'"$'&'((')-(#3!"!#%*)!', $** (&8<=DxrU0,/)%>CF%,?.+0%+=&-5+211:9\J8482=??EFPA@LSdWSWU^a\WKO]WTSPMOTDV\VRW_q`J[\bk^]b_^S^\VXO\a[[QJONTPNTNQNTTTXKMFB?BEJM_NJMdB@?>::@D==5,6<7EC=(0K($3:JN?LH/.5769:>;>>B?79, /7@E98594:8;9I7,0%%'% "#(,*.&(.)$$$" " "#%8*&3'%%')""4M9/=oM-($ &12Z(.2-+519'6/.L,.1A:KQM8=EDGM?L6B@;742011*.&"@BFQQGPFpYHRHKPaZcbfSWOMW]_]UJMVLLLUXPP`[UN[df_ahf`RYW]``Pf]Y[WPSPNFM[HLO[OWU_QJQGIGPS^rJNRLK>>>?CB?A<63:9?LB?>,*-08r=Py@34/4:7@@AA@B74# "#07<;3663<;379c=3(#$#%&$%)&$*6*+'%$%"$$ #&#%5! $$2')%#O;2H@-'*+)%%''?.1148+2163*+,>2P5148JQ??>?OOWJC?=874561A:.64:13FYL`kYROQROLOORXeVUVXZFP[m}HFDLLWILTRVV[ZZ^ei|me`_[`fY^b]\X[WPSOKKJIKLMHHM_WLMJGJKMIOYUIMKOM[N;@BDBAC686<;@?5B4/*/9Ln>AC@:4569:;9?E?D;69% 03639A89=K88:;6-)'(%"$1$%!+(1'&'"#'$%!!$) ! !&$&J-(!'G:0)2-%%$#(0@.0))0/11/072-/.9EC56NLIC=78LYTD@B:9805AQ8C6.48=417121:4B>@60;<8:<=A;<7C8- (.6:<8889A?<959491-'&%)$.(.(;'$!!%!" %$ #$&#$#" %&&$%)#..11-*++((/14+13,2.*)+)--8AI>:BA;:@798963:FEQIADGHAFTXPfTRHAHKD\Ta]PROPMHEIGFJJ1BECF\[VZUUSUVnYetuf_Z\]lZ]eckjZTNSVTRMDEB@ABEFGJHGOKNUOPPKGGNKI@H=>.+23(,-8,))()+057>B;;37;=677;;<7A@=73303484>EMKNEaHEFR@AGAAB;7?ROH^^XXXNRUV[_\`_^^ZY]Xa`hjexul^_]\USJLHDDFCHHPPPMHKPVOLSKTRNKH?LC??=<>5<<;:>DDA<:471-25A>:.(*5=J5D;8759:5630($$%)-(&)&&$,,"!"+" !%C% "''"$'+ "("#'$2(--.*)-*+$H.1).*+549578:G69E967IKVRNB?BBGUw`WXVDH?NRNYLD:3744+/79G223+.6?@:>641-106<>O:;8772433,+)")($#.,"%$#$'*(!$!#, "!%'-&$$ !")/';"!)(O'*+-*/();'*1+'+253?8?;OSUGI?JA<9@>@=>9=809512>EBXTAPL\J?@BF[pZRKY[PLWQR[RAIB2.03/7E=34;CM_]WVZ`[V[\QWW^jpmgjWWY\_daflpuhdfW\`[XQNFHJHILOKFJNQUUQQZMLIJCHFCBG@?57729;=:<@AIR0+,;63.-*)12H>?@??B<47%)!,68:4788:70,44($&,%)()$&%&$&-+$.3&#" "%#"',&$##&&0&&&')*)G+,.?-0%$)+((/0/895BMToxfG:>?BK>@C;=7<<8/116=DATMQRFTcQJGJJKYQKAL\dZWm^OBGG;0*,+27759BCHIST[VZ`c\UYVR[_blfeac`VSRU\g`]ogjadijihf^SSOTQLJNRJKNNOTVROOMOMJNKJGJGD99;9@C>BABD?C>/*160.,#!15?C@@CC?;6.&!#1,-:96AO:;36108&&$+()$!$($!%$&$ $&#!!#*.-*/A!#&"1'?4#'*+-*1+2+8.)"$'(**/7H866;;koM_GAGLUbmr~LFFRC5/,4649:CNJMKYPPTefdo]\eg`hqoogicc`[TVbnrpejlcdjlowwk`[aYVPQORQLMOMUXRQRQKKMLOKJRQG8-9IIGGCG?DG?>8-.55)' ('5;<;;AFG3203-1=/+0776E=;42.+)))$&)&+" $! "# &#$"&!'%%&,))%"*#!&0&#*++)$+2G'%+$%#!,/+HFA=72?L>;ABGTWLSV[[QTdrdrZdw]afojead__XXXhqkceeaelmihlilqa[NUQWQNQROKRVZiQMLRNVNLF<0/:JDHF?FIA@B>=9282("'08;<=DQA>;6>E21;5$F55:765:1*')*(.(.&$! &"!#'(>3""&)##"$-2-&(&I#'*#.(()8)+,.*%#  ,3../449:?EBJJLf]KQ>=+37ccWOLJB=?B@9CFENSPNVPQSTRPXX{~uh^b]]agge[VY\_nq}”nef`^_ejpkqhgkptdXRQWTMNYTQUZ`WbNOHQVROHG7-6ADD>?AHFB@7799:<-!).9>>>=?@997?@DCEKKQSPRR]UNRU]`crlc_Z^_]XQNVSWlrmhxto}onddgnpyxwngfsoTRPPPNYONSZabZf\RQR\V^LB69?@D>GCGJED<;??AF4:%)-=M=BN}cNHM=BAQ=<47:63>86=I=DA@C@@SLB;AA^ZCKENBHH@>GIGFSJKD@>BCSMENM]VOTaafl\bgbtxfXm{ocKDIGJS\fah\UV\ojxzrjVfq|xsagtve_YfQKM^MQMTY_`xsh]_YMF>M=8?8&+8G=??;>@5-,7>;78>?J=A;BB9:8-3.65'"%'+)+*$)/,,'+)%&+)+%,)(&+($01*+-,)-)0(.--&'++-2)2A993KFNlXBPHKPGCOEAOBN967>54>?<36HUIED@NEY8<@F_\UG\aWQEJ^SDCDCF<97FJSJEDLPVWPWc\]`f__jhmu|w]@;CVdehqxta[`\fkspoejmqnrfl~~hd_aYSFd`dPRPY^usztY]XLGEE:>LBJIMJFFGBC7:B00(4>728:?<>=50+9A9CKNINN=;IL:?CB:83/)&())%'%$'.-&)(+F>D**)(,'%(&9J(+&(',31&,'''#'&+//6P7?=`IVaHKD?BHC;8>@KFG97K@4>:86:=?CCAFIHTACFTYgPULI^TCGGOS=857:D;GMLBIOJTVRNLptgWhTOTSSXajb^ZLNYde~zp`Y^ejuxqwuzypxv{kc\WUTkz|TLQVQarx\b`VLGAE@9AWHDGFHFEB63719;sN86?=B=<@B-&(-@GB4RMJA=5269?B=<6F?4/<2)'$#+%&-.1/./P5)&.+,+*#%),*$(''3:2*$"!'$'(,@/1976CFTpTIN@EA:6478PID>GAMKF<<@:=@BDNFKSRKPsX^XcTVGNVa\cb]\^icpm|utcspfl|}wqlp~ys{wqgcXc_cZe`WUW[__failgXPLGAH16aNHHOLNWF6/A8TI]:><;@BL>>,*'#CRRN7JZOJ?95995:()($,-,((,(*//5@cA/+&#)M6)(0%5))(',=R2)%%)%'%'2,48@f;afχcU_G@A?:86152VFEVolcJDEPE;BBAGBXGB7,+06<:9L9=;;62/+JlTCHGQSE>>5<4=IQ>42//.-+2,+,-&$%,4//10;3()')0SM2&0&)(('+.;0,&&',$"$+45=:AH^fpȐ|VK?8?>>@20=:eYnvw{iNRPW^WUSTO`^IDPZYKOD@E@;B@7*)-48=9ABFFFO]VRSQNWVT^SZ\^Z\Xa[Y]kwrqgrupr~evwvsob`lhmhbhbhcafWW^frhdn}paXNG=,6JDGMHLCA<=Cgj=8@A?A654:88FBCZNKIAOQL=>=90&3692AHILPJE9B?C>=B@?BBF1.311>>42-),-.0(,2/I:6-.53M>39B/*(&#+*---,*/,)#(6(.,4HJHzvsw`xlKEC><>I90>?EvosscrgmwbXR[KAMMHFC<868').@GGFJTR`^ZRYfPT_}eskfmllqhnecfjpqifq{y{vp}z~x]^]dqohlv|hmoa`enmphjkbdG70:CBHOLC7+->EaC247.+248=<>@BMFLF>1!,58AAI>C?60.AK-2/0/-+,.,,,321+08/380FP0&[1-+#+"(5E--)1*+"%-/*/3FDHdgtuSRED:=P<;8AFBRFGOI@?>.>AeH?8,43:688D>=GPGU~n\\XMGIHIDGDGPa}.K6>EBF?=.52Fu=78<4/54<@FWLLHFQ<FPVa|öqfgdYQIDHGEAHDBjX-449;B<6CVQTYR]\dPk|sx~we||~{qsnox}~xyovkcikuuxyvrlldke]dk\IF?<<@JG=C0)+)+?5.)3,((-&2GCD6/(11587+1T322-2726//..+=-37HI@@HsZOJFODKRUODJB====@LZp|ԨvjUZPJEDI<;CIDuN;@BDHYePLJJVYGM=>FA@=74?24677:,*,(F9.2**++.5CCAC1$!.D;40,-06341.466/./-,/1?>HROL`YQGHIFVP_WOD>K@99=DLZn{ղzeTPOKGG@59;GI;E^GIGLLTMQ`YWZTV[^gex}{upxrq}m|uxerxphiqzxntkqWxyvnhuovxycghna]cZ]VXUFDFEILLF<@0#/@C9:.**%+06AJLXRII]hbZ=E==E@62:@<9754=-2/09731*+.-97QNUw:$#'X4,11//295.-462*,-0=.,26GKIKGHGTJATa]Z]C<=W85:7*--,-6462@I8;12/5L4;-98:;15*.6>HV`tݾxeWRVLD3441+!H=JN[UWhkmgn]da_gd]Ybtft|~un}moohfkn_OLMOQIggipitlWjelhpzsbnzrwvvyhlZXW\np`VPKEIGGFH@SALPQSK>?/4224;6>FFIPVUG?AZ330048?@CIXl״u^[NI=77750=wQVVfmvkrsfljg`kpknizqqx|tsvc[arlm\MORY^c_Z\\rx}zf_n{khXTpln}zgf{x{~tUWcbki[WRNQLCJLOIPKHFFHCA==6815A5>lKSRTa^UGQpA@4011A)(4;9S;90/2A1E.C)/-4-?1))"%&+.,/(/2+0003;=`8E>EAFL>C>=9?860/1/46<;BAKW]fq˦jdfUK<6?@>60=DHRW[e|wkmrg_mpcw~{tt~jon]QIM_gga]TSaefegc^^qtwy\acotcadVsqqqK}~|{t}xtlZahjbWLLQTCHLOFXSFECSOIL@056843E156J9:+)-;7;C:1@&%(',.*,)17/+.+35;A48>@1.1E7689=FQOOYiũz^[ZLC>>PSB?EJBHQ\`gtwjc`vvpwwqz~nu}y]XSMZdejedc[W]iijuonjnlnbilbf_avjet~|~qWl}{wtfbgnfnYJRbQ:OKAGJLHJHShGHA,9<6AC]=40-6.+52/4P5213*'1>9@B59?='+)(+,)(9...0.;:@A596FHEACME9<>N,**5<33167DBHMOy|“f]^KF?@IKFOIMMRUUVeskol^\u~}olqndv~kRPYafZgcckloruhjdklx{oqqytllukttvnfjssfTjpw|kk^QXkwvx^cgidnhYLRNB>FNN^OJNQWNKMJL7<>46>EFKR__pngdG(#(/5--7AEP@AC@C&'#(.&(,*/117,4<@=E9611414G*)*)763,3:HDFPhZc{̾^^YTYLH@AKEIELPKWo}vntu{{{pnixztlbi`Yfbgigklomnqqwwoq}zssmjdw|sskoUqyqfqSLYSn|ܚqcin|zlejjaTGS^sDITY\LKTVRT_J`75558>DAVShpimojOK3'(596-,;K@:8569-.$0+**./+.*190)/U=@:8421K()(!#&(').15402<>865A>>6436,++040+,+:C2207FDOP?NpjmYEFEABIJNK[V`a_nyyq~}ztx}}rlgimjy{rprw{sefiqxtrruvw{z|qneruzyvw`|owxjSKRpcncededwcgjR=O=PORSJKPMIIIFH=//HK>?GONim]Wrn4./31-.7:9:<.122,(,+*02'')1Hf541NFV9=0-@c*$%$'-()-242.06B;9764DF5047/,40/0-//0,3+.<>XOL8Nkj}{h\jlhVMC<>MKRijkmnZmput{u|nfbab~vgb|il~zw~|qkjelqqlppoclvtxx{zzyzw{uvZiy}tGAcj|vkhphaU[flh^RH1DOZaEAMMRXSMD922.>OA@oj7>}WA3,,2>)&(*0**--620,+-05;6:3=6843<23@\/+,1/\2../8OlB?>8GHR^YPKDYTzdMH?9G:2./24/3,.,).,4///EY;96@;ACEMLHIJCPLkS:;9YRMQjk\YWc`qtvx|xijphijcl{zzkaivmbfqx|}{{qmnlnljfa]^bfpsooowx|wxz|wlhn[PWhmn}~mYDg}wmNYk`U`ahxhOQ86ZidibOOHglUQA>>/;A@EE;OUOSc_]PWa7;>-.5*-)2AH;=474/+-+(',-.;O`Mn>Cw^9)++07$%'21,+,+.5./61.248=596>3532,**+/3/1,)0+@N164@B;;BAHIFS\VaSOmJHMdW\gqpdl\giv|zzurnhhbkooo{}zyzbrhkskcstrv{soqpmiifjf`\gglkfmx{tosuxyz{|}vfYW\`n|ypq_?\zsRFXaegcwdTVPCCP^iniTKRITOMF;89B]4Ao:9ABDDMJKOZag[^ZkmeYUdnx|thlwyuqyeZMKO^beu{swzyrpuvupX~soyw{qiomeW]wdjii_jtrvvt{~zyy|ww|{xe^YYa^vytm`[ey~{\rhcehebd]QRJM^bdbW\RUULKJ49AIb\2>>II`zn\dp\S;7621:558/4@6432/*.$$",D/+3?^oH2:EO:9;762$$**,)-/.0@NB@?67761?<8462+),+&*,*,-(*@:10+:6/62;NTSQSbzu_TX^_w^dcrlot}pms{q|ZUHOQd^o~}qyxlgcfpwoTfqwexiqibfa_ZYZY\frvpuy}}}|}xz~{wokcVckhttqgdqxiajuve`aoZQ[PPZ^gU\`aURBLGAB>TyeBT8@JXig^XW<=(>F<10..1*.0413?)+'&%&;:1<:I[iK9+/U?<.68-+*),*-).,$4169I?Z<77681F3056-.,)),&)/)E<.*,2---)2@RYRQME`fYhf^adad~qstjnkzys_Xctvyzzvvpgallcnz{ahwLLP]]qmfqjkljpnl|}{{xt~|{rrwrmcYkeenkpotufUParsaR`bQVPZU^\_LVT`^A7XWGHo~_4>4?RCKNn\[P0,NJIC840,+3*,4,0,*(*1+2.),>@IZ>)$.218?)--)+2*)((),+)717N^KD?GGGVynLO496:44R`hL&8d`F@76./(//0:6-.)+),000*5=G]E3%&'-+/7('2)**'&*'%)DK>O^~H?7EF401160,--((&'(+*8.+-)3&&)-.3FIFUU^\}c_ZWYgmnujg[etsh^d{sqYhxvvvy}zq}gmY]r{nwiehomqgdeZR\`inpmml{|~}zmngmunehcT]lpwtw}ikROPY_fLMOS_aYUXktssvHNNHO=7QWRa0) *7=Je]/->HAO=87+)+142.2-.&%,1=,0.FJOH;LK8./+(+&&'%*+-3&3*,]\B_kMBCED?A8//37/1-1++(&(00)&#.,(0-/1+07@EQQR`вa]hSP[iryi^ccinioxjjΥtu{QSQsvz~}koqvjx{jbhjlkoogpl[Zflntywy}}}}skaemioh]WUdk|ewyytxvuZURhXTUX[dhvc]QegssyTaPR?D@:NCKSB8A10-(''%&#)0),&&2+-05KOGN_JG\DG1044/1+.*.,+(+1-+-*8-+(,1,';3?IRPZpNKQMTVgo}diuzxtl_`z~zxpu|mjUOngvUjimyz|ysfhlfhjospcbgdgnqv{}yulhhjvl_`WQfufw|z|~w`UNNaTdqgaehjUgizrofePRA=\::;33+-0,.+-$#!&()'(=?5100-+.5@I?=JFCZA1S/>3..)&0*,+(,*#''!%$/D:?MC5BOSU^Ldcsyni]Z^hdf^QgjdRXvxu{otu|oh_ZjeW\hjxeZNRajaY`dihltyxvz||~{wo}{qt~`XUL`mmossoc]YMD_`ngzgg_\UU``ab\ao`UKMQOF31/2,,.3B:@HCDG@4""41319/,152/28@=4-)1CJFB6;M4,,,"(%)"%&&)(=3/5-31:22/<6<=@YPFL=SEC:>M:U@B9<8<(1/%$%*$G*''"(A6/-.766035AK=?PkL=C@N>F9--""&%&:,#!)$&6-/8?AABAAb_cn`Logtp~n``_[WTVXTcdomryvqood`ad\TISLhS`qddcaXZSPbkbhhcROgipsr{}wtprnnxe`fkupl`hvj`[JZKK]Tqjw|UW\[`cr~nRSLBEJKC21067BB=FLQPL5&2;8:>:@403A49@CK=b>QEU?iT5819*/7))&%)%,'&9&2J1-+57466E:LKFUjMAKG_B1*-/"#*(%+'%'"''86;6LGDDDP\bhf\BWHToljbbacVSYUOaiclkjholli`j^UQPE\bgsfjg\NNC]emhgdT\eoso|}zwwuoqmd_\aYagaXfgedL\IETRmnhn\[bT]pt{gQNRCDF>61+/:CJQ>1((#&+%),'(.5E.2;11;8B:DF_FEF?FFB35+,&"%'')(&()(&10:?C>GADILOh^X>:D^_jvg_XQYJNYMUXbiYtdcgfjhgf^]VCOTajhoy|pi`sa_WgjsqkTXZ_equ~}yxwuqnnf`Z`hqi`H^bd]dbgiebzuv{k\RV[jzp`UH@C=@08-/*E<>EDF?LXGI7.<<1><@-*)68NqSoLIIC=9XDX>6.-1..2,'&&,07&-#-<+=;6,0@>45=GDSNE@WYA45.+,/+*$(+)>2/.,?>ADEEFKJHJJND?D9?iuokk_kSHSaVV^fRX\iiefonezd`WIFPVgkdlqvuf`klcnslgXJN\bdnu~wwvqnnomg\YmqgWThS`bijptrvsll~uZkagqjpm]nO:=2,#%2,*328>=@EH?EL6(56=SC<4)2>@zQDBGDH7@=EE=42-)?**)&()*')($)-**(:34206?88ABLDNK]QA3B.1+*+/45+-9727:RKJIMNPOKXRF;>@9FFpqwy^^YLRbZY\]YXdcdukaf^rrfIFIOQW]tiyxswlg_`lol]hZNO[kpuywuppqlote\[aaWe`_gcsh}|snboghfcdnpeiWF]0)"",/.4F78>A;:9=C6(9IHC=6/;>WVFRRJFHH>CVAGEJNPVLKeSXKG8g~Wfxqkjbft`_`njab_flc`^Xa[pi`TMPG_\ZaohmwhZf[\_akl\_KINduu}~~wrnouq|e``]okfoiicfzoj`lslfinxgdRG<3:)"#*,9>A:4:;::68/&;.((*&%$%&$#&+*%%)18A12CPX=D:DHPFDAPDGEKILPTTVRBEgnnz|kuc\^]__`n\ipjl][\_cd]^TOL_Z[X`Zcqrsre\TY_`a]caTILRjuv}{xqovoeYepj_fnmdbev{nnj^hubgpl{joKC<>=4*+1.;:;45:<8:<0 )+6@?C96>QN5;G4.)),,0#%'+%$ --)&"$4-7L;?BK\QGOBSJM?F6>8-/**125[aI?HDEFLlPAJEERVMT[efj{}^esY[hii\omefhjobgtbh_^OFY]]XPdototysd`V\^hhekaVSfksw~{{spqoqpeZsplbkhbXbj~sz[[a_l|ts_TFE:=50*)/3544989?;CA7'98GHE:24@;GD:38B;;87:cN@9;/1'%+,+,*('" )P4*'$+(-:4KQH>YjhjE?E:@834=L2.))0/FbN??ABGLMRMB@IT_^YS[iiqokb`qrWX\P^Ups|gfaflecgsffbaR^V]R`wysuidYXUcgmllwiutw|~}uwonmnpc[{rmjf_Z\__mz{_\\bimvqh^TG>79<44(0516D<>=>BBSA4;@PbI@.142/.+/278=B89MC>?<*,(&$()+(/&&'$$'#1#%-3807SvNUjPP]PH;?49571:-(&-9YA>@DHE?QRQONXS^blY?avkqnr]hdf^cXMWbUbudcubjkeqnfa\i_YY]UM[p{wp`ebfogiouow{v|yw|~~yvu{uojhdfkjj|gh_NTYl}rYZ\]pi|~laZP:64G73()/641<9O@ADE;79ABX\P@/6986&!)1=H85252/(.-($#"&'!! "-/0528BIGCOemKIPe@608.,&"*&+/+*'8O;L?EIMPM___in{}upSXKMHPRRVTTW]ugd`fcb^fqsePT]Y`\prseRWCM`eotrzpejw~{|~yywpsqgd_ece]\k``XYb|}~posdb`dfaW[NE===7AM:+16178;JCI=/!9HVXJ66<=02'-(177gKhSjlJK3343-'6,%&!#'#$%#2+222=?MmhP`W[OFJ]8=70,)&()*/,+.50B>CKGHJWbrcgɞwtyqlR]KIHURWe]aY`Zao^g`Xc}pf]SUU\g{pgfZJPXdkmmqslkZbyz{}|}ywurlxkcca^bf[`ZrgP_oq}jZY`Y^sida]XGGIA>=?50,*984966AHE5"AHPgGA8;;3..40=@@ETIQQd~Q;2B2%$--*(%0)*%&$)4220>DY\yb^RRGJD@23.-+&#$)*32-385WHFHYNN_o\h_uhix{tgZ\XJETQXVubc\\dcfcVak~nimfbR[`nrhogwfU\_kliimljggdsvz|yqmosebeglncW]UkdN\z`adspZ[_hua_WSJJVZDCA7<38A0.8(49=?@-'AFRKF;;<;26559>;BCL8OIMv@04-'%&-@.%%&'6)-1,6@QfqPSQ@>CRI4-.5+%!+*5/-,,BHzKFLSSOW_R]XktyqiM^p|{i]X[YQQT]ighgyVqeyh\aetcfdS`gbdumaVnXbuiZflpmknimoty{xuopqedbipjeVVZr]ZcuwuigfwXZbr{c_SVISfLNHB;?A=<,$# ,9<<71-9@ACBML;7648A?FQTNCE9T;cbA7(1,-"&/'#"%) #9K.@47@Ktx{ZKOduf_\YYz_\Vafyipjceacpe^^~{JRe]k`^`ow_]f\_dchTO]cfkgcnrx}xtpomnhbejkgbV[bi\^epwstvm]W^r{f_VMZ|vYOR@35J11,"#,7;=4?-7@GNGVBT>127A`TNi]F87;<>6=0*06+E0*&!"*6#&".>/@?7RRgYUS9@WHD9=-)>++"-+0)73D5>;@?G`y]nH<>E@=B:/2803,&%,216V<9<;PeJO@ACjbWPFEMM`[Uaigdf]cpbZR]`fkmdbwixgtw|v`MLKaV_WgsenWY`pafYnvRcqaappxƿzuqnmkb_begda^W[jf`]fnsi||`oic}yv]^NKMLN?A:45/*#3-,(-22/%'?LVL=C>B;43?ZRLKQM?WC6H;1(,:,-A*&(%#!%!!&(0neW_cU[><;:9F7=42^C()*+>4?@C?A;\OQ@AIHR\]boSF>HRfecveibljcNS_NRa_\_cjnq{tzj^SCMZ[[acl_vaDR_`\^}natjmS]jsw{ľ{yrtrkdgfhlbb[][]hi^gxcy}nvjenxgZTLKBD61259-%"%(80)/2(#7;IcoE=>C=<66BNFMNRTQcPMKP-*%',%( "%$"$# 8/{QPhWB>624919446A)4*/4=SI;DQGT_a\aiosqJATeThmjoj`ZqrzyyýzuuwshdjimqbWLYgeb`dno|zxytcfZhbZQLTLHF;8654)&$&#-+,=BP4>FJWUH>FA6M;B;1-9,3+(+24=L;CgSVDLJ`aga_nxZ^_aqdLNZoznuSFPKNcbQ`kzrnymglQEWbeeilku^HQ_h_kopqegfghmtxx{þyuvvjijjijlaVJV[XT`|t{rwejsjusm\c_TRORC@AB9J-4$+*!*5DHB4BBHRXSM?:96A;H78:054L/45046,>YH>7DM>CK=;Wa`hl{wck\fflt{cc`TgOPPPWa`S[Rdpuvbc^WQmolouwjU_\Rdtmo`fbhdqy{}zxvopmnohqjUMRTFDRyxsyuf_ZT[bfnrpX^SXKJ==60+$-$ ,)"/AEB>46CLU\XD<5;G=6839kdurehsd+  !$(+$" $?J,7/24<677M3950553@/06*=E7/cHL=BEVNJOIghfhw~ehZ[W`nxmommEFDLJJJJTX^qUVP`zkmciiYTWaemxoo]`aYC_lqpp|qagnrejvx~~wvnonkhkpnghcXOLSdxypvhVMNWgkggf\]P[IH82.,,%' $',%#3AJC@K9>TWbfJ<4:64248:aXh`eao`8.#%"&+$!$%"6A.3./37:619045828556->./:@6@C;7=CQTKRNRRdyg]h{pk`V^[_cg}ubRDUL=9BHQ[RSTL_dgxpedAHQ[Pcusa[idObgrppfVakoo}yry|ſ}vuijmgglto`e}VW{maQNR[mpx]UXYE;JJB33+&*$*-1"/?@AFH5088120)-4:1/.492+1,18:247NKJZCDaiYV]b`jmca^]a^z[cutwIPdnBBEXRT_Yh^f]\^WCEUcRfaejsIxl]llqlypdhmqpv{{wsghgijnviRZflVayeseVcZn{vc\bTB?SP?7)L+'-0#")2DGGNMBLAGQPIB=:5276G<5+-1126-//+),'.4+-0/<7;/5:[I@SM`SVYVSdjgsvn_\xfeqsolllFRQOPGHU_V[agr\UCRNXNPZVVTQ`g``qgflqkmsweilhpzww~}wqmoljkreRNX^_`oyuqdTUT[g_`qujnaRPHBF=90,.4-+")C50AOQKMYOGESRIM332/6;=LA?AR[UBX>2#')-'*) +"'&"4#%"?MFH14,-24=:3/1-13/-(2-8106J<@>K[DFOZMIVWgqj_igk_[okgshhkALQ;IMVMOOOYUa^^pw`NHN[ORnTM^\dWZ\dWVkxorujknowvz{swyytljrsrl|UPOWX_k{|vulYaTgbaqjrneZlITe^B?2>J1+('.5>98DSSY_PKPG@=97,0@>BE:C@:647832;/.1,-+)$+.15;+)8F6;BGINKSUMJV[g]Ybadb\mqo|ns`)*79HMUPW]JRf^cf]jYOBNTYPlO\pleY\g[Diu|rqqmnosxxsuy|z~|xqmlnrknlUBMGZcl~tpastU^ecepsk_VNIHJM?++00//)63COHQVSP]gd[QI7JN7//48?BP7/&'D:A,+,'$#" #'" !! &$"FXgiv}|sx_Wdkdhjbesma]SH@NA8:/,*$&*2:?DGKMQZ^RecTD0.-9>@8:;9<86=G-$--/.+0(#%&$("#!")  VM68H6106G@:9/2/72*38601oA96::GIPLXY[\j^gg`jkW__`rkoH@&4KzePUa]WZXYYNZa[[hRQM[egrnrj[b{qwkszxzpwlz|qqrpw|~zrlurl`^LBKM?Xffioj`lhidafu{dw{o`WYEFPJ=@2,+)..496FOQT\b]WRKQA585:AB==99146?:;./*&*,*+$ 0*"!#" "  !$#nXG@L>2-,?561A-++10)-;5+8GT=;59:=EFEKbb_Y\\gi`_\chXidqwoPU<6IVSMN\[XWaX\[oY[QWTMGLeebotphxLedqru|zyyjis|||~{xrooz}{srorpe^[ROIDBY`a[RU~zprkbjymerpme^WPSPkOA;831247<8MNRXUY`JBAEFA?9ABH=D:376BG576*&&(')$!!")&%  #%!BL?:6---*A69252(2-'(,0;/-6><425=;BBEM]V\`amllTTMQ[[hljkbOC86GVCLZW]kXRVORNMQS>IQJPab`jiVNh`t~xvuikrxx{ylkmgly}~|wrqlohedZYRCAMVX^U\|~}klqq{tqfcc[ny]TDB76-2)<<5GLY^VPRLENF?9@BD::638//'#%%*%%$'!$'%,7!! ;$) ;8:114,-&'/5..HC=.'!$B+(.71=8728CE?ED]Vu{lY=?NMQd]QXgdjaaYTeZO`[WYacWdMNG_VWRPQEAT[cuwph{|zmus`b`lqyyv[Ugfn{|~|{{tkqvn_ZZV_ej`VTXWcet}wnkiiq~q_cpbZGNaBI=7;AGIFOMTQUVNLI?/2BYBDHOLFRPJG;4:4,)(''&$%#*+ "$##'" *&'%.15504.270,#+13/394.'<+#'*&8545@5Q>=GOZhh|bM>FWX`]Obf`]`[]_eZNOZUw^gadS>BWEYXQLESeaht|q\qcrj`Z`esy{upTakuv{~z|xsrqqj[WX^aaefealju_ezqw|gfekrzrlefZITelJ>=?GBNX[MFSOUYPC;/;=E@:CIMLCEI>A;=H@DDNMJKNKKBBGFC/:)$$%!!%!! !#$ !#%KA3'/88846.3/0/128@ELMNZ`cZb\GRYDJKE\^qjoÔ|ppqqibVVbqvkyTWki}}zxxuvwyzxphgaVbf\\fluzsmov{yscffeamvlqkni~li`fBQE/;85;@nLIdVTSYUICJHKJ?:NNJQ`>DCB?L;i?@:6,%)%")#-**' "%! ##&';*)(@7:<<2<22At@-A>,).A(,"/1,>884A\Jh\dl~rsx`f{|{zd\XTqghREGQG.?>68::BD?DQRQRMOURRSRVUIXXhbzl]JNB>>3=1( "((*-$%$$2%")),2-/G;<1-69EN70%=2+**.,*8&/)(63+-++6;59:A<93HBKdq\iFKUutl`YXXZTSKJIF64,41=DZHMX]RL:9@>>[aOG\ahm{aUehig`KVfjnq{zxikvz}prx~{|}{vonig^`[VYjmfin~y|zrmg]e_Zagirkoe[|\V929:F=>KBGGFQQKWOffURku_Z[[SyoNF9A=<61/))+$&+/-& +*''.'e,3J1:6O>>W[P9+(0--(")-E(()-2//)*22:2933.:<>QIAOdaTaA@_op_Q`VGRRK@EBB3206bKFBI<>P80.-/'(&)0FI()$*(-6*.)1-+-5]4XZDMCCFHMTUH7DTC?H?:C==5662-.)()+)X<21/8)))(($%,*)/;9=<:2,(*&5+(&#$'<),31)(,/?8:01.;=GADGS[HIWKJNL_dgaSMEHUEO[DC<>0697<;:BHKJMOJ96IK.8[RHceOYaqiUbekeEZnXJbbW]^quzw}ynrw}pnwwx~|xz}yrqaZWWdaknijtv{qnulmntvib`oZipbcpmdgotS[HC:@922;7=DaIRFRCIHOHPV\ZcY_c]`gkWGL^C984503>54+! #(-+)Q61)/'&*'*#+#'1)5J32...*&(,)0""!'&3&' C.>+))5/31GBCPQL~_BX?BK_svjaUTfJMPZbA=WaA/3442+-K00.=2:]VEHD=68E`ejdhXRRHLNUJBGH946178<:=@FFHLKA5$.3J?NMACa|xfVHQWkL`R?DZkcPju{vmqx|f^^gqv}{}qoqpqtnrmms|qfggkkmlujxkfxg^`TZba}|othnTWGB<=636UHCAFFPRPLKC??OJOQWk[Z`]]_iUc??50://5.24,-'%!$#(%"#'//)/*//#5"#%.%&#)(.21($&#&!%-+-%)$ $"!''&60(.2285F@E<1,DZcpgmzpY[UMEGECD;:168C48B:H?KFECHD4$"(7>QVO9Em|rhwmYhaYP;EK/9]c\O\t}qsx~{wlY]crvntwuyyqqifZXkmij{sxodmprrsyrmovxrle[`cd^gemzuvu_[S]917@@:>eW\IKKDGNG>EDHJMOU\c[]a]ZXUGH@:2/3505-0--+) 5#!$$#''%4*(+:#*2(((((%+).(-0&&*%(3,<9'"# %#!"*/<%3.'%&**29>8523FPudsecSQRLFAAC=?2-186309432000546))& &*+')0+.42$$+&(6))&(%':;$-/)0/-1/.+&$#"!$(0*1,')) %&-472MIKON@@CEGJFLMORUW\``aWVRKF>:>:76780-&1);MPPd|cIHT[ihmnjrfRhdZY\bP]x|v{qjvs~tvvxrulndW`bedihjmsnnz{rr}~~fagchcngqxmmmnitmbQFIIUE>:EHDHXKKHJHGYC2BJVUTRYcb`\b{kC<98<<2436<.+4/.)'%$''! #"$$%)>+88,D)1(%*'(;4+ )7.1,*%("8&%$&#!!($"+..,&,6/2212A8A]VOSWeirnhjfSJ\CFA=;:2668:?GHEP@?=;@C<+)&4$8WQXat_KT_hvmognigce`cVZfyyvz|r{sixyv|xyysnpqsb]kffmlursxos}rmnc__^a]p}uzmloflqgVYMIeN@?NEF>SNKFEHLRH@AHPUT\Ya_c\S_UA976846330<5<-*,+)%!"!$!$&).+)'(-.947U0.,&%35&(**&O-+'"?s.x)%'! %/,) %-;//.1668=GZGR^ct{ugb\P??9?BEA658?9::@KBBA@CI>7300.3=MSQZYd]hutkt{lnjlyxaedbmbmztrsrx}gwmksuqs}wvw{lrp{uv~orqwfknrkjpjiaXabmq{rfanqneTRQNNMTC?CHOLNJIHEJdKnPPRNVjeiW]fTN?=E?=L.24066Dy<(.-)))"'&(*-$-&4+16^D8)3:4-# C#)'#1%(&(?UG+&$!"'3&&&$3)*.-+367@9;DTOTcmd\][PMAPOG:D7497776>C==?64:841,-3AuPOURe\m}itvjeYa|oWicfihxutmekgjkwtfwwyy}trpjzzwvshlflsq{wwtx|se_bd`nnss|i^^laTVO]RJFRBEFIOJLGKEGDSHFCHNMSX\XSTUOI;88=:F78736ATpu.,**)($*,#%)(%0%7412=I-)):L'#""#%$('("&19"#!)# #"$"&'',5+5<3/1=JATJSr~~ldcY`X<>M9EC=>78<988BL;:<@9:33003539;CUYaoxpkpqh]ggq]d^oso{kvqrzyjuvzfv}ytolkmjhefhdpjlo}}ox|tli_okrlulhzoba\`TMSSLWpH?FISSXTJCA?7DQYZZb^YXVO@;7:328:9:A@?SO>>:-,7()'$%'#$)&2A49/3=?'--($#& &$(),%%!$'!#! "!)#+""(U( "#'1-/0],2BUEOS^_}haJM3DYG;AU9;6575>K;5<6B:9<9921.2--D^Rav|ilongkjgW_^Wa\`cu~z~t{xtxrw|{fjelqxoryrspxr{~wluurokkcfklnpxnb]\[Z^TUVPLLI@=GNL[pI><=@;=8:ADD4;7?80*/-,CKG[|ylwqsRssqhxaLPaeT_o}rywzwt|~}p{jn~xw}xuuywqotxnmngekmnmsqj]W]b^Y`cURWFADDHGM_dSE9;BNKU]WYdgh][YV[VKN8258?KGGGCJQvbI5-.E)%")(#!%$&+057?;24(1$*$%#0*(%.*3'%$%## )")%$,0"2+'.#'C)4=>:@58@<7S@CGFZ{eI3.8kWIGYFB;:?B@>;OPL<88=57?<5608FEMJnhos~TXjlktzw{~qst{q{~~x}|p{}v{rx{yuklvssrcc`iufSKMUQLCDGLEIGiA@JMeNPNZYRV^_bZ\NA>:58@IP=Zorz[<700#$%$&&*&'+,*.-25,8-9)&.*)),/&*1&$)%%%)"&& &#'(! #"&"!-4Z?4=OXunp`UM79<=BZ;OB?>67911B@FQbi}PewƇbpzknt[ntzoa}wmmokio}~|~{n|sw|nmzotcaZdSPSPQIYJDGPLOAJVUPJJRZ_ie[d]\maw`K:N><=>QD16AT|\M<'.&&&$'*(&%.`4,,-0,.;0$#8A*.1+-.=$$&)*#,b- '""3($ !%!861=78@6FBBC3AJPdUHEA9B<<6D>;959;A]KNQTjB>FGDDIL@097<767VX=U8=H9>7TIE:5>1781LBIOTeakwvhkeVXD]mttwrw{~j[Zvgiqqm|}~|}o~gooqpwynnkWWYOKKGEAAB?EC?A=EKOemXZb^\YYdWTQPWoA:?H7@>KcCP7Wj?@B8*-)%&$#%')*,(+.7')),&()+&')45,'*.58$&-#'%/C<7(3%;b72!"%63/0747DOLCIKPE@2,19A2=99;9A;7=?NFE<6:1<30@FUOVmx~|ykjcN=NnEK^h{pmot~ufsndf|{w~{}u|~uxt{ysrqnmsyppkkiiRSLNFHFECFJGNHADEDIRW_[a^`t\[^WOUIOFA>AC=]LSTIA?A=29YH%%)#$ #+1*))(/,,(**--&.(8.((2\D03Q=("-+%*/C+%!5"0R '!0R7616B;?@9JGG:>AAHTRIJFCJLWa[_\cY\WY`ZYJEI@:B68?@BB:4?TPu1)&)+(&%$%#+*+-4+&)6'&&)%%#%38%'70-1.)<. "+=-) ##"#%:& ,=//X?;=EJMOYEHE^UXeHC46:A3%08@?PhD6283=29=87595=87R?;CQf|om[l}u{~vl[R=VRZTV[ohoVVH^zv~kl~r{{v{}}~{z{ogefe_cwggtn}vhte_bcXUUUSNU_YNIC:@B828@H]JLMRPQT^Y\Zh^gb[RVkUKMFFM?/)23A;;?=53;=D7;:23293;>7CHQ:=Mi_T[}utsS6FFUVUSdd]n^E=FRtpjqzv|~s{zpihdfh]chhsnafa\ind]bNWQVUWRbTQKGPFCFB=8+&# "%',3*101280-$;)%%""E#$#! " �--((45KI_@DEKTGHUXXQTcMO8((.<43;N6347>@?6316565B@;:368?NsrUpanusznF7k_lVPdyjfI2DKnffxs}x~{w}uljkqheh\gckaddrxxmoq[Wbt_POOUSYKDGJIFHFHNMTB=HUQIKQYec^ffcha^^YiQQDD;:@>A8?A=H52?031*&*-/,),)).):**((;)''+)*!"'5'/"$('&.-,-.5?1:"'%$"+7"<&!!%!$#-,='4995158@ELAB\VLphK))A.0.J=345544>IG9657487=761:9H^EZ{^huvzmkREZjdbaknSF8?7+.,136),%**-*(-).0(-6)(&$*&2'%3%"%% $%"%1-.)(%:*'"!"$ ,[" $ %&(/,KK7/15AFEHH\vu\7'&*)1:<@1-335;>?=./710BH7>.7<@CcSZ`jhvppbUVoiecvnuWTA4ASVdRTij{t~riemehkffXTs[UX^YTKO^\ZYSSQMWHJkee\RNXXTNKOIMFGFGMhZ^qj`bagfaVSURL?=88::J;8=;5-,.343/.32/-:(*+.*+)sH('$%&&,#'" $!#%''B=X=+1'%,*$ #!(Y% #&':C2668?zSMOY~oprvi<,*/(!30243-647<ILRLYiuddphWaY22+.&&.1/0468;E95C)2;B:51.6:=GVUSjYcwtpoptVN_Xkb\~[XdIhjpe^YLJFKiejmfY_pssinkmqil_YUIFHNfgVJDCB=VKOOIOPRUNTZT[YQPKKCB:JRPPX]]_qe\Y\XKAB>A[4:7:22CDLGL;843-(+3480()*-)++'&'&'O)$"'&&%%#! "**/QQ/1(05B+2"# $&## '0'.@@EMFCJ\QHLXguh^QdX9&$"***V4:'&.17185A51368?244:>CVZX?JX`pnybYUaS\gg[nKQK]afe\Yf@LKLsX[aY\belrpoq~{]b[[SRJQKQTQZGEIDMZUXZTTc]b\Xd_XUOOVV`WNJQ\bdhwrnbWSI@>=:8A818638AU>B02##"!#(,*.0C@LOJPS^DFVsTNUDEGHNPHJFN]dfjngPZY`W_b_d_]VmrhVWOJ?TK?MRW_RVYcdaaohlZPPSPFOSMMMQEDVNORPSYYU]`ccj[]Y^eRVdnd]PRi`]amdiVSFI;=945O6/8308]I@PND:508-))..,.&#)(','#$!!$ )%)&%%"$&#./11-)*63135[0$!!%!1##+),+(+1J@CZGTXQKNOWfhSCGK??86?5Q(-4206/19032*-0:>5:3CA>KHNGIDPmlbfigcTWVYWXi|iecd~^Frk/@@TWYXk`R_^b`dlttn`ZELOSBPmlSLBFKV^[WRg\a[`[ce_YWjzlY^emytVjg\\aWRIJEEE?4--,+4>24533>5FB7@]55/1.-+/'$%'&')%'$$"&$''+'-*#'&/F8C.2699=>0&$$$),%' &1)# $%)$))0?1XBKLUU^F?`kWTQNOEQAFMC"#.0,*0)/)/,3.03929KLdCBTSGC>Ldm]egjo`P@BBPbppkrq[U\YrYAE8XhJEUi]TXi]ddvp}sioSCMPWH}SfXTQTPTjjwdihiTm\mdebvyj^vqjidiigVPCEAIJMQD22.1..7:739>793=9;1610***.&*3()'&$ ##$!#'+()&$&$!#*N@92@-O@..''3-# &$:9=!+ $:8%&-3B^2F?I[YU\VIGKNXRdijdSPRT_Q\TQXWUVWWW`^b]XZe``hfco}xvrs|qtusmcdKMTIIH_fTE3124727:54,9;9:0190,.-*;.*"#+)-)#%%(%'*)+&%" #""!>(),*,4&-,=-=K"%!'+ ))*&),28;=;ILLJTSP[VFM\QTOSD@=::I11(!&/+,-42620210311529ACKI]449FO^lZZRK/K[guY\b_UMH@=FS[UYQ?JIOOQSQ^gYXRVSOSS^^`]\b^\Y^^ZZ[`cadmgjouuzyyqns}rkn]PLJKLHPJD914A7B55423479=73243.25,03)+$&&%=,&')#)+*/%%##'3&" '02&.-)%,/"N@" "$# 8&(%)=>>AGMGUVNPSHiKHTOVdT=:;;;G77H&#!$".063222212123,9F;=[C558714C;>=8934Cc{::J*,$+(")("&&#(/%)'$('+,(<)*82'*'&,%04'"%(+ ##"!$"!"#%$)9=D;GFSTWKMTRPPITLLJD=;G=;BwU*#.$(,2.5434>K55>539;=NC43*953;7>GFPiVTh@NGUUVQPCEGTXXVPSNM`>9>Kbp|\HdYWVOSdunXcddgccb\a__Uaa_`d`\uukeesreddjhgkf]QMaPTkC88E=?I>595/7:5HEI;9=5405/-0)',*+'2+(&%$)j%)+(($)')?*.*%')'&(',3 %8&$#!  *#($%0X@3K@IAMHM]VXNKVA@@@D=33JgV9:7533@42BCFHA@F/.-22,+&"%)%,)$"#$$#(/(#$''&&'+-*,')2$!#'#!+$ $% ,%(*'+(->EBR6=0;IXFNPPDHBCLC=;<8?P=#'($%,K/)%-.121.+-1843vP=HE9EB:9>===bAE<431+//=,/&$*+%)(#!  '+>0$)''&'*-+##(&#"!(()"!!""! ! $" "%)*08:E=4525EINHNJVCB>ECE:@=GJ3,(#%.,%.&')-*)32)%-83,2I?CJ8;d;:126GGIJKVgXWYSPQN_][qtud[VTEDDHUOl{ckU^o`]Ybfgmhgqm^^Z]hipm}ecmaeaf_fcYPVRHNLRNQFFFIDGGxwhb_[E\z@@<><:;J5//-54/.-4,2(%$'"!!"!",**4&(%.-7*,*$&$&&&#$0($%!&%# $5&@9"'#'-/1=71499@JISRJHZBIAC?C:>9=3.-/, &!#'#$'*)/6.''AAAECMW~UEE<>697<;ID411151/;/;,$! ! &,125-<,*),?-('#0&*$%$%.?("&7$& #($&'*,.4?5L@=:OOKMMKDCNGC>JI98A5177`.+%#$#$%(:)/.#)+4F>9?;:8;,DRINGUV_Y_NX[MWZXba\_LU^T`icagsXbirj\ndwylb[KRYh`hmt\[nlkksngTZQLUSVgKJSLNNKIF@XGBFEF>DXD=ctOG@?9==>IAID=1:8/24E**+"("&%(/3+22G-),)*+&+%)')$$!)1>#% ! #!$#-1)8F@DNFFEFXEPMaZICFHDC<>L85F2.26>&'#))#%/,41)$(G7?@=95DA7?HOB9ID9@KAR[gTOMH?IQ^^^[_]LSNTaR]Tbmyg^KVrpMVJBVFJNW_]`^adWWVkgcic`b`QQJGGEEKJPLMIFC:>FJOP^VOFFFE5@ID@G<=9AAGEt=A76_[D)*+'$ +5%*"(,b1-)/-,)'-.. &#(1(&#(!"&!'!" %* ,.)43E3<,'*$%#+1.'+0?66<=7<@;>DD<=D/56HEDFIGT[ED=LPNOORORIHNRJR``QmaOXc~~sXEJ?NLVGQQZZX[qc[Z_dWVQNRJHCIJFBBAFETNDFN4ER_~mXOXJL?DBO@EEF@8AL>?GnT;6=2*..*&& # !<&!*J.5+(('('$0A('42c1+,-,'-"%&3#+!-12!#&%$9>:NYSD:LTIOIHJPFQNMD>B>9/D/4%/,/*!"%.,'),435<@;7:ADBA;^Z9G>BGEUKGSPZKMU=IJKPPSUNJTSZZ][SJNdurvbZRXGU[OTEAabm^_hd[WRTQKJEFB=@JBCBA?S=CJE>4PcnWNH>BCF?BEK8CG;DQ:9cQBHC0/*+.&&!# 0892*($).'&&-')*-7+-2)6Wo3,%.+%'! !!# >, (**"!!*++36DOOF?FPNPPXQILYGMCCJ;84.(3)19*-$ &.')/566:@:5:8>=@=EQ]929CE@MHKNUFIA9/9AIIMQKKPfUGhSGEKE=Nie\gdYRPWUOLHHRRU\g]]\PJID??QT6<@=:;?A73X1*0E-(,&("(I-)')& #((&&+&((,&5/,((0640+($%$ %!$$ '#"#$(1,09AA@MFMKHHMM[ZPwPA:>:C>/0*&/.,++" -**0B778;;82/;?9@IJk=)*5EC@KDGVJ@9327A?DEMNMMPLN[OQjD7@OFFJQQO[UJPKQNDD=LQVSSfM?B?8C7?97489A;C;:=?:;2GM`HW_J?=E@4V@00253;IOGIXHNIMOLBGUQKE>FF?82/1,16;;1.&$!(),?;E767<;6U/:EMCVIa?0%0OSKFHIFMZ?2-1@HNA9@PVCJI?FJUG?=563EDFPW>A>BAAGEGN`PPZ\E=>==>8?71794>A:N@4:><@OC.0*#212 "#"*(""')&''$'+.=HICHC?LOLLP@FWeLDBSPH>;933.AOm:*% #.1MR@KU?5:>7@-,TOMG?>/&.9CFMFUIVhB46:A>=8LmW<9=8@@EC;C<=?A?N@E>9:07D<=CF>:6<==723978>:I8UAI?>?=BMM`KMAAH{@9975=-1230,--,,C,K4?5$## "'!""'$(+#!#4.+)(.7B3/4B7265+-,V[.&$#!"  $=$$*"%"$#,,/FB..+,)9Q@@]iV/4BA><7H^\eI@A4 (1=CZHJ`]WH;8<798I:9686@7;:@EU30/*.3,H633/9:H=.8$)"!""0""<\%%#/0+'+44:D>:iW@=6.,31()/') '"%!&$/" %#""&%/.4P;8BJB;:GBFDDFCLC?I@GbsD@N93:C;0A57, $:G9=97O36:H=:6:CFCB=EC%'6NINEAF@JBF?Z[aFGYLS?958E610+08863..-1@7331&&# #"#&;72&//1(,04KM8?oi7?P>;F1*-.&)" )C9E'"!"!*%"!%$2.6638>^M=N6;AD@9;823-.#.6788128213W=:8SSBYSI72$%7DEF:CUMfH=9=EKA42=>430,0J:/4.05.,'S1570**$!!'((%')(----1(48370-;<`B8/K1,0;A--&( ##$#,'#'(,"!&%)'&(9??>?Ei58>D<<=P39/76207GU==0:)./'2*1%,#&$"!"( ')#$ $8/(5@K68BP;799;>B:BQWINIQ>:KDFM745:28,$#%*-14@:5A=597=D;89OUzC1**'3:I[S>SqKL913//<;19B5;/)5@}B=-,/6,105626117538;59;<=263256OC<8>7Ic~WB>GACDAFFNFF?:2;.$'#'/79;8AD8::C=.11/7CL0?.*+-;AI9=U`HR@/3-308545397188917929//11/-5=3;:48:3;7361.064739:45:2:AES>?@@9<<=D@;987C;9FOH87.-,-+,)87339/40P<08097:Db,88:?8=987>261322@LX\FDFD@=;4BKYJ8Gb5-0%$&/2E924HM<884?=:O4C63,+'*@CF78>BSH<:3278:40845;=@ilS<592.-.0/,.122,2695<4341=450112406=^R;<,.121/5XYcIGQQRC:><>bSJ:5*.352*$(%13.1.3=GD=<87=0761>3,*,AC9B:;:JpN;359272:;-0534:EDKV/25-2F21-33/.B5:5-16==7634033/5=8=EC;:2;:?CCD|=7/1+7=&***6*#.%)"%]#! #K42>>$<??B7<82935./+9yCJQXJBEMNA?olWO6+3-3:0.+'.11,-0=@M?BDAF5;6BK>@3GI5*.060B30,/,4031053668001=LXE=54/1285>8MM>=><8;59>:@9947F.-+57?R374Q;:@a;=578g7F^@7ZOCA=<99D?=54OU<50*(&849.5283.1.180+<.0OH#3, )$/@+ ">U5:/)((3++57/.300/3/+1DIHJTkFI_ILH]C:2*,,2?92)('+.0//65D@O>BX@598+7388>5A:;9*,?=82N?>8>7@kWD@=A?><46;4;87870750L@2-/3=920*4=LHd0('0!$(8&%#"&&)0*+0,34.124*)/FIBBC@EBGBJNBGF?91>/B3I:51()(+4/C26H@FB;>G>J=PNK:9LR81'.=E;G@9?:::9=8?MA3959\K=><68/8>9645;637<2-22:@IRK:?6062-2<640),)'1=?(.02./?J89@=2+,-80-'A,AW;;#'% !!"]*'$)(,#&--2H1?24-=2@*4>>?9<<69@>BL>@?_=>:8>=699:6:B?3>62722:40-156>nK8GD;9>=027026/@6D37<;3H6).G-4928.22/2:14=,793<;M4396-D;:/&(')))()-10-09@F110I-*/6/'5<>>~\+("!!"&=.&$$0&03/-10./23**(-6=M=BNAP805N632('#"+/3F=9<:@9C:C=>=AFGBAOGJ@F=?M955:@66=89967>@8:2416BDJ76nc>5>?65QqQ>3C29369K2955212.2(%&'/A6BAFROZJkQMIXID.15641$*%!.+02564N59CE@9;J=BM.&0,02.)511453=D9N:>:<@J=>XFDDEKA>@D<;;KDD==Q:@8C@:68,'(,-IB)/*.<6/>B4870)-1,:0+->2/G""$"D%$"%&&*:*45B.200*,37<:?F@GUYhXK[UsOF@@K2<85;SE480,.2467EYXpnG=6;<341)83:2/(-()1.0188;4::?J>?DEE>8:@F;<>897P4/?KGBED583?037::;SyK=;<3452202:5-2/.12-32,477(+51F34.208:7250,-C8//,,*'/:1-,C,3./,<^d00*##% ($ # &&%""(1.0>:.//()748@NKKS]PEFOO[SGGFI_@*-./pKT}<9F'*8:CJoH941(-6<3989]1(.7Y25810J;87;?471?:A6?ERF>:>NB8><>7IFFSB:=:949=777D6FAC7@@89<50E:545;_vP;05374-09-1-5:2272D9;,.../,)35=0-/=2.6./-+>51*&$%+'.0/-,3-,3)0<:A)()>$, %  "7.%* 00@,3649/)/104:ZQfZTvTPIPGU\maM5(*.QKD71@?Q72.821JB==A7555/1.<79241>A124>9657<467QD91;?>4417'&-;@G4>AODF25@6T5>/.&4,0)6/82;3Z6>.2-=160/111>A/%(*,-2-..)*6++&1%+(...-F(/,)((30)#+"/*('.*)%0=17.4/-80C/14CTPKfNF9W8625;DKC>HVrMY}DD6mR:011,369529;?=::+'*/.-0/45.6451137442/,)KM8TEC@6.**'/22/,,+,&%/Fn?A`f6BO9;;7743367^ZIF6HFB2,>0;,(+51*(74-:1)418=77=9638-**"#),-+-(-+1)-61T-'440\E/,/D0-*47/+""!$;64+%&)58(01,,,/2I1-30@W7J?NIVRK3D?;501;HA6;WqfT583`~B9.5645702/>C9L8/-#$@$8(K40965846254331079@CO-25/*+/-1204''.('/3G=E}~oSBDA[B@JGL>O93.441,H[30./1()%(-).0836/00100@N@E80783-2.-)-++*,+(-B1(((*1vZ06:HA01/.)./0,D5.-#$%Z0&*,,','&%0.L0A333475.6=EHE>I@DPILGNIB(55ADJ?AKUn`UNr+304%')*13<.3/+86CThH.'/6/+ (+..:520J5283,85-2E64638=.4(&&,)(+1&/0728,5.CbB:DIKCCFB501*-..0/.-*&% #%3-+-7Z3?/3*/5D\F<8.,0B2%'//7+&(%#"&+,*&/*3[t9>07kM,J>;,.2)&'635$%(+3I0'6V6--0++**+25/2547AAEIFKR[EGTWD9LGF^XGAJdW}QyG@=6-!+1551/;/?6>uJO4-*')5*'*'),24/7H7001,'91;;Di0**)('&+*)'/.50.+9/+0;43B=C>;1102,.,-0.4,*" !%'*+*0-;0453.01434951;,E:&#$*3,*($-"!')1B/(._yA817.-1MA;>m0//*..>:!!&(N63<7,)5,/*%)E%',P652594XA7D[OGMAFI[U?MVRm<@G=HE>_q[D5I '40231775;9CD9/03-/*74995/.-,10+G94@"#)*-*/E553c-7*)%'-.+1.G3)')**,&#)&+)*-)$$')-4K/*KV?:37/'2+*A.2R-+-0'+.+1+2;=<1)+0,.1,./5<0++&++&'($" "##$()-;DI2?>;;=4?($$',.DV+$"%TCD4)'&-+'(1;S*(%-B?5/7HO:;9@BDIKLI\ULHLFKF@:87HjgkOaOB=58..02/074;2''9'),5//3+5=P#"=)2BH/1?2#(422//,)#?.$%))*-*)(+*h/(#'$$(//9>2G56[E22)-C?PF=75.0G'%*S537@@1H-1>>H*&11+,.1,;/&&%$"#"&&"%(*F^:PDV81GCQ\T`>8L($'.3,5*"8$*=553(*)()'$+9( .,.*0.:@85.8A=FIN[MGE`LPg_?/C7bSdw;1*+*0-'9+*?O/:7I=@KYdOFbKOIIA3*c-8)JLDR\C8>KD+234//3910(&@%#%+-'*!RV,$$2+33:7;6.,227411/*+&(&$%!&[4%+&$+*$%"/)+//,>*/)+,#,)/68;adpv?=B..0/1;,-.2*41+1*)(]1J91,62)=+*-)()/041&\?O/%#%G% )%/-*%-/-)%'-S:3""$ $?,+.;::14:565E0.603QI./(42(-//23*-42'%"&*//54103()'$!),.0AQD.5F>R>F@BOOGEE;PFR6B1,*@%'&*,17.++8)!)_KDM>>3@F;2102UT5:3=469816635>B-%&&,.70/5/C.,% 0272G>F7=B879<2+)&+-85q2/<2-%(-,5:C679.00+/+,.>VOi@5WJ2/>.5))>=9+T-2M'$ "&%(%J$,*22+*/$#%&$%"%)',T>7424;<28>F8<<<93&0,%,/8/73/*0&+3@;E96>;YY23;63-539A;?95<46/84IG31(..4-.*)-/1H!*510066Q=8:L=9A304--7..,)-,+0//:2302590,'$(/,212@-513@;:0m?3AE?693@1/7=6+&("*;-FK13-021B-+.)1=::PNDWp>JJ29.5/4.D;W_<4.'&C$" .%! (#)4:AF7.''&!(#!"$/+*0)*&.4B671:32W`>787;A?:>ECElubLN>&3CPdP>6+%),-:5C6=)0342221-2/(***-43:539>9+&1253;QsYJ_\ZC@A>65.2022,,,33223.5H4Y16.45:0.134B]7/C646D74R1%*$(aZPO/:'+4*4H5%((28M<><59?*:2.0(,2Z;;;H_HH80#%$ .%&#"&!&KU3,&&&"$$(*5-(//3526/1543;=:15857G;AHCTziXx`]<.0-06A+J+'&%.B@R=7261<56;;13-312,.606?I@7586h6;;@LYYxlbyCH<8325306R,243048@<275>D=14@.57431A620618746125$%&/;I[M/4**)/"%4%%B*,'-S78,)4,)5*)+,HP3LnWqTJ3"#" #),/-2$'1! $$!'N%&7.))11/(-108CE*05;2?35=?:@_O^}}VME+-%$%#+#$)-1.3479D23-7?5<.047?=@463772353/4.65094>GBL927:TD7/A420-2C85<4246,7BiT148;BNt]fVVI:/7 &)*(0(*,769MJL=:65152162:873<ܑO68247-*-)/623/BB`HC>2C3-16.),'$"% !+#""!2#-+*-:1/117<88*,/$') (!"" " 3".0D!$!"&,%'"/(-!"%%#2)-.2=<.=55603=6::<73J=JmuTBC?J.-1++.+0.*+%.026rIC;7G634;F82;=:8:::D>86;BA33;962+IyÛMNEB4N7/*,-537?A8BH6?9>A=93G9=9253;<<@>R=E>6BHA{A;:<<=956EG=:EU91778IH<>KK}Q62;5993E3/59EOZ>C=?;8C7:07;8817WC=EY57<8>LPT]F;UCB4G;DPX+ 2-+/3..(713.:4:C3:;9<<4J-(57^A@5C?<[26==F62383H8@QOE=<=@I;<<+XBB2K3=AL=DB?HDPP?H<;@8:8,L642C)+,*,"$#"(/%$# !155((()"#%##! '#16%$$7!) "&5!4$#."  !G% "!%%15E>O@>DA;=CEHD>,*5-4-4*&3)5/,5243/I^i;@[B?69>8F83:%/1-09=64:07;=@51KS+01596MNMABT;=I<820AR=67@AC><9sJOMeRR>25=95-1J;/2+()*,%$$'(.,(S", )##0''%&1 !!% !!!!!61N7%&"$##/%!"'' &-4QSA=-5=__1(*$(,5>COASH?:8B@TKLCF7JcI;1.050.8/7B-**.9/)15>AMJ?KA:387:IOZC*+/3C659,1.GOf99,A9((43>F:=?C639T@>788?QUbJ@=I9:B1:84;F^L89A3440*/,,=3GJ4j/%%# #*&%%(,-&$##"7-*!! "#(! &"# !" #%#1_1*/'#)%#""(&?\C.WhB]4@3..52=A*&>$(:8`98M/6@EvoKs}t@@85/20-X0*7.++9@5A9=/217)+23$26D@52189-5,0327>99IG;kA29;LK>@44:9O4Hb9B75>92+)+3*,-2,/5GL5&#" $*G:+A1A&$$%%;-(0,%"#&-$# "#; " """RS+#+&=(>l-,-6_?;1.4K34148'$&#<7>-6:--MU}Z\q|y=86<3//ME//96;:=75*,0//10GP<77OL.43*%1232-/-0(,7.+*-*.3-2*/0434B2/863HHC;;:PE07FRIF<734M.% %"jo,./"5B4),.00/08..%)!*7507/+-LDOSY|^8(%--10,8/.F:C7,080-05/<@=974_\0('%(,%-/);.:0(+6-/3242.144362:549==A;11+89X;F=?.9/?"('('J;0b^=9O_70&%,Bw6530$J&'-6)%&#"!,1SUC6-('EX5BA#%!!&3,Z #$'-.)%35)*/?S:B860.$ #,0DR4@PL8H>pdTI8&")-?I;1?+,/1(*-<,,.637--704}P?+## #L7484+*3&#.1*3326224364?09E4;B>>S>B@IF=216@511=.(.5-;9-&(D%.9+%'-=%/L?:[w?/),'-5-4H.@+'$,+9.'";%'689b==Z[A^f3.(#& & %2 ;# <"%"!#(V''7@F2?a6GD8,"$$$1,1HO44K74;0)&$0-+504+1)*2)**(/6-/41I/-,*+I_4,)"$%+8<*,.*00);323/3;21435643>D8]DJ?l@A>B=>/3K66:32(%69,5-.!%/H.+'+-($%,'3IFL0391%+%2+(#%&14)7+;!&0/(;F^PKU^Lcb9,L;O# ,&#$!!#.,"$'')6*6J?@;3-/*#' $!-()%''?5TP47C4.+)'--5.1''#&)(-+(024,10(+0.'7;+'# ('&),50(1/-)((3139:44/60260A=FDG@FOHCB:3@`@9;<&"1@'(,0-)$&&$&*&*e=-<27T-1-((3&(00&-1F! +V*1>>>P~{hk]_|>MM&'!'1'!#")G%eC! "#(+2%)-7\dJGh>O+4%!& &#%&(1/&2>741.*29&'#$/,.+-(%()*'$-(d45,8/0/.%# ()+('/>'&F-0(),.6+-),3-20J886/C9&!%5),'% ,;3%&$*.(./4&H3:8%"$G/0O;@#/  #8;4*#%!YD+#$RNJ2W,CGA%*#(''&('$#!#&!!('*+,+%4('&(18%"(-+%%!$$ -,$ #!&- #%%$&$&%+3>L.,2/,(,,4E?gRaO4.06.@TgMX7J34++)4'(+)""$&&)* " ""%&"0#&,):/7J<>)?-*"$-$!c&*A483>#&(($@/1(9;-?9*"&"3b!"%" #G2+!"$8O.56$3%%"&2%%0()#)"*'&%$+,'--(-*2W&$%5'##$&" " <%"!&$$"$#( #'(/04?JC--7.-2<;{ug?24+0C*03197>#$('*(/+-.""" #%"! '.$8 ##(1.G:;A.*$ # ,./#)*N@,)&./))70 ")"-%+6V9+9%! M/%GN78%"!! 1.#,%%'/6%)%$%%((($&)+%#+%A(9m!&-( #,%"$ +!$ 2,"!/&#$)>GG\1:023638xnR3.-.(8.(&%.6,2<,2('% +$! %"$)#! %*(#*.+ARA?RS-%+'$"$%(%(*)2+++1#'!-3;8*'3";0@/5!'( %2%,2&).4**'#$.)&$%#&&+(*(*$((!')(##"! > % #!!%" !"$$%&A0@)6(3/'*.A>oci<*$%(3/<$,)141UF>,%"+% ! #"$#'+/(#7&,*.X:=7)$<* !($ !%2+%&",)!1 *   '\zO$!&%'$.(&.2))*%&0$" $%&$(=(*"! 9%"!  "  "#%#'!% #$(%$<&##!-FPA_M~,'$'')-6)"'.85A?k($%-&' )!"%#<$ #..#!"#;(9.,;O)%#((""#41&%&5),$!"#!""ABBD2)0-U4`bA4$ ! #% $*-/*()0,((8.("&""'*+'$$&##!%# !"%&#!!" ! .%'L/#$/'+/9S8[Tb8& $2>D&*!! $5+)K..-&9#$  "4*$$&)-$ &%5(*,(!! )&$("&30'%'"":M*#+!#.1~0BV6!  <*$ #$255K:A@7&'&)#"!'!%!"))!#&($ !!#" % & +$&" (+%+4A2=&$%Gdpo.0#(FX0-1"0:1$"!! )7!!"(###".'/!(/*(##!';-# &( %Z>3")*2/o/6LK')$7$'$ #,'*)0-&+9S`LZ1 #$#'#!+# $6&('$#"!"!$ $$0"! !, %7')" %)H#'+ "2'2I((Y$%!-$*"('&%''#4!'%"#''&W!#(+";O3)0*%&D9&-S*"&9 &$# $ $"#8'++%9PV?A !"!$$!'#%!(87<%%## " "  )!"#&!.&))=#!!9'"4^/5(%%&""# #"! ""!+7####$ !!+'" 3$ $("%  %+(#34L[;?0(77 $,$##$# % )!""((*+$)$D556J$$"!###"$%$'%""!!'!!$ !)" !"%.I #%(# ("(&.*$ %&-"(&" ! #%&&  "(!.'"%"&#&"+"$ \ No newline at end of file diff --git a/data/fits/NGC3344.Color.F32.fits b/data/fits/NGC3344.Color.F32.fits deleted file mode 100644 index 53200d029b17a7a5e2b7c014342b3df6d244294b..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 1054080 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?~~~~~~?>>>>>>???]]]]]]??||||||?뻻?;;;;;;?zzzzzz?陙??xxxxxx???斖???tttttt?444444?333333?⒒?rrrrrr?⒒??ᑑ?????ర??PPPPPP????ߟ?^^^^^^?]]]]]]???______?______?ݝ?㳳???]]]]]]??????ښ?ZZZZZZ?XXXXXX?ٙ????????TTTTTT?TTTTTT????ӓ?Ғ?А??Ғ????ӓ???Օ?UUUUUU??Ԕ?SSSSSS?TTTTTT??Ғ??А?PPPPPP??ӓ?ӓ?VVVVVV?QQQQQQ?PPPPPP?PPPPPP??А????111111??QQQQQQ??Ɩ????Ǘ?Ɩ??Ș??Ó????????ŕ??Ɩ?Ș??Ș?ё??UUUUUU??̜????PPPPPP??ə??Ǘ?Ɩ?ŕ??Ǘ??Ɩ??ŕ??ə?ə???̜?͝?PPPPPP??Ξ?Ғ?PPPPPP??ӓ?VVVVVV???VVVVVV???^^^^^^?WWWWWW?VVVVVV?WWWWWW??XXXXXX?ښ??֖???UUUUUU???WWWWWW??ח??????֖?֖??VVVVVV??ؘ????ܜ??ߟ?000000?YYYYYY???ܜ?[[[[[[??\\\\\\?ܜ?\\\\\\??ܜ?ݝ???ޞ?ޞ?ޞ?pppppp???pppppp?qqqqqq?ర?ర???ᑑ?RRRRRR?222222?⒒??333333?TTTTTT??uuuuuu???wwwwww?888888??yyyyyy?::::::??{{{{{{?\\\\\\??]]]]]]??~~~~~~??????????>>>>>>????||||||??[[[[[[?zzzzzz?陙??蘘??WWWWWW?斖?啕??tttttt???⒒?rrrrrr?rrrrrr?ᱱ?ᱱ??ర?ᑑ?QQQQQQ???ߟ??ݝ???ݝ???ߟ?????PPPPPP???ܜ?ZZZZZZ??^^^^^^?ݝ??ؘ?ZZZZZZ??ݝ????ח??TTTTTT?Ғ??WWWWWW?SSSSSS???RRRRRR???????Ғ???ӓ??SSSSSS?SSSSSS??TTTTTT?Ғ?UUUUUU?RRRRRR?ϟ?Ξ?͝?ё???SSSSSS?RRRRRR????А???XXXXXX?RRRRRR???Ɩ???Ș?PPPPPP?????Ĕ??ə??ŕ?’?Ĕ????ə???ə?͝?А?̜?̜???Ș???͝?˛?ə??Ǘ?̜????Ɩ???????˛??˛??Ξ?QQQQQQ????TTTTTT?ޞ?⒒?tttttt?YYYYYY?\\\\\\?^^^^^^??VVVVVV??[[[[[[??֖?XXXXXX??VVVVVV?VVVVVV??֖??Օ??ח????UUUUUU?ZZZZZZ???Օ?ؘ??ؘ??????]]]]]]?^^^^^^??Ԕ???ܜ??ښ?????000000???ݝ?^^^^^^???????ᑑ??ర?PPPPPP?111111????⒒??㳳?䴴??uuuuuu???痗???陙?::::::??뛛?<<<<<>>>>>??흝??\\\\\\??;;;;;;?zzzzzz?鹹??蘘??WWWWWW?vvvvvv?啕?555555?tttttt?㓓??Ⲳ?222222?ᱱ???000000??ర??ర?______?ޞ????^^^^^^?ܜ?ర?ޞ??ޞ?QQQQQQ?pppppp?Ⲳ??]]]]]]?ݝ???\\\\\\?______?ܜ???ښ????ؘ??VVVVVV??SSSSSS?Ғ??TTTTTT?QQQQQQ??SSSSSS?ӓ??SSSSSS??ӓ?TTTTTT??ӓ???Օ??Ԕ?VVVVVV?Ғ????Ғ?ё?ё??PPPPPP?ё???VVVVVV????????PPPPPP?͝?ə?????Ɩ?Ǘ????Ɩ?ŕ?’?????ŕ?’?ŕ?ʚ?˛?˛??Ξ?̜??Ξ?ə??QQQQQQ?????Ĕ?͝?Ғ?????Ó?ŕ?ŕ?Ɩ????͝???WWWWWW?TTTTTT?QQQQQQ????WWWWWW?777777???????WWWWWW?VVVVVV?????XXXXXX?WWWWWW??VVVVVV?????ח??ؘ???֖????ښ???YYYYYY?YYYYYY??ۛ??[[[[[[?ܜ??ٙ??ZZZZZZ??ۛ?[[[[[[????ݝ???[[[[[[????PPPPPP??ర??ޞ?PPPPPP??QQQQQQ??QQQQQQ??ᑑ?222222?333333?SSSSSS??䔔??uuuuuu??緷?痗?888888??鹹?ZZZZZZ??뛛?<<<<<>>>>>????>>>>>>??}}}}}}?켼?<<<<<>>>>>?^^^^^^?^^^^^^??}}}}}}?======?||||||??[[[[[[???yyyyyy?蘘??WWWWWW????䴴?444444?SSSSSS?RRRRRR?222222?rrrrrr??qqqqqq???000000?PPPPPP??pppppp??^^^^^^??]]]]]]??______?ޞ???qqqqqq?ߟ?ర?ᑑ?RRRRRR???ssssss?^^^^^^?ۛ?[[[[[[???ܜ?ښ?XXXXXX?XXXXXX??ח?֖???ӓ?TTTTTT????ё????[[[[[[?????ח?????YYYYYY?ۛ?SSSSSS?RRRRRR?RRRRRR?ӓ?ӓ??ё?PPPPPP?ё?SSSSSS?RRRRRR?Ғ?QQQQQQ????RRRRRR???ё?SSSSSS?PPPPPP??ʚ?Ș???Ǘ?Ĕ?ŕ??Ɩ?ŕ???????’?’??ə????YYYYYY??VVVVVV???̜?˛?ə?ʚ?Ș??Ș??ʚ??А?ŕ?????ʚ??Ԕ?SSSSSS??ё?А???ؘ??PPPPPP??UUUUUU?VVVVVV??YYYYYY????ۛ?XXXXXX?UUUUUU?TTTTTT?Օ?WWWWWW?WWWWWW???????ᑑ?YYYYYY?Օ???Ғ?UUUUUU?VVVVVV??YYYYYY?ח?YYYYYY????[[[[[[?WWWWWW????[[[[[[??ۛ?ښ??ۛ???ۛ??ۛ?\\\\\\?ݝ?????㓓?ర??______???000000?111111?111111????ᑑ?222222?rrrrrr?⒒?SSSSSS??tttttt?UUUUUU?嵵?VVVVVV???888888?蘘?陙?::::::??[[[[[[??윜??]]]]]]?????}}}}}}?======?켼??뻻?;;;;;;?ZZZZZZ?鹹?999999?xxxxxx??777777?vvvvvv???䔔?444444?SSSSSS?rrrrrr?222222?222222??qqqqqq??ర??ర??PPPPPP?______?]]]]]]?ޞ?______?????ᑑ?000000?ݝ?ߟ?QQQQQQ?qqqqqq????000000?ܜ???ښ?ZZZZZZ?YYYYYY????Օ?UUUUUU????ӓ??Ԕ?TTTTTT??????TTTTTT?RRRRRR?ӓ?UUUUUU?ޞ??TTTTTT?UUUUUU??VVVVVV?VVVVVV??SSSSSS??TTTTTT??ӓ?ё?ё??QQQQQQ?ё??ё???WWWWWW?Ғ?ؘ???YYYYYY?͝??Ǘ?Ș?̜?Ǘ???Ĕ?ŕ???????’?Ó?’?Ș??˛??䴴????͝?Ș?ə??͝???Ǘ?ə???˛?ŕ?ə???Ĕ???˛?Ғ?PPPPPP??????TTTTTT?А??Ғ?Օ??VVVVVV?ח????嵵?ZZZZZZ?ᱱ?ؘ??ؘ?WWWWWW??ZZZZZZ?XXXXXX?TTTTTT??WWWWWW??ܜ???֖??UUUUUU?Ԕ?UUUUUU??XXXXXX?Օ??ZZZZZZ?ٙ??ח?ؘ???ۛ???ݝ?ښ?ZZZZZZ???\\\\\\???ZZZZZZ?ۛ?[[[[[[?ܜ???ߟ?000000???PPPPPP?pppppp?ᑑ?111111??111111?111111??ᑑ??????㳳?TTTTTT??UUUUUU?VVVVVV??緷??蘘?yyyyyy??꺺?;;;;;;??<<<<<>>>>>??Ꚛ???ర?ZZZZZZ?YYYYYY?XXXXXX???А??А????̜???RRRRRR??UUUUUU???????ٙ?ٙ?[[[[[[?ؘ??????ޞ??ݝ?ۛ?ܜ??Ⲳ???qqqqqq?qqqqqq???tttttt?TTTTTT??RRRRRR?RRRRRR?PPPPPP?000000?111111??000000?ܜ???ٙ?XXXXXX?WWWWWW??ښ???ܜ???ٙ??]]]]]]?ݝ???^^^^^^?\\\\\\??______?000000??ర??]]]]]]?ݝ??pppppp?ޞ??ܜ?YYYYYY??????qqqqqq??______????PPPPPP?pppppp?ᑑ?______?????ܜ?ؘ??qqqqqq?ర???ZZZZZZ???VVVVVV?ח??Ԕ??UUUUUU??Ԕ??TTTTTT?SSSSSS?ӓ??UUUUUU?Ԕ?ӓ??PPPPPP??PPPPPP?ϟ?PPPPPP??А?RRRRRR?????VVVVVV??YYYYYY???Ԕ??ё?̜????ё??А???ё?͝????˛?????ʚ?Ș?˛??ϟ?ʚ?ə?ə?Ғ?̜?Ș?Ɩ?Ĕ???˛?Ξ???Ǘ?͝???Ó??Ó????Ó?ŕ???ŕ?Ɩ?Ĕ???ʚ???˛??͝?ӓ?ӓ?QQQQQQ???А??͝???̜?Ș??Ș???????А?RRRRRR????ܜ?888888?鹹?;;;;;;?????陙?斖???WWWWWW?VVVVVV?Օ??QQQQQQ?ϟ????QQQQQQ??RRRRRR?Ғ??Ғ?TTTTTT?VVVVVV????]]]]]]?ܜ?ZZZZZZ?XXXXXX??pppppp?qqqqqq?????ܜ?ښ????^^^^^^?000000?qqqqqq??222222???RRRRRR?qqqqqq?TTTTTT????ߟ?[[[[[[?ݝ?000000?????ZZZZZZ?XXXXXX?ח??ܜ?]]]]]]??]]]]]]?ܜ?ݝ??ښ?ۛ???ޞ???______?^^^^^^?ޞ????ޞ?PPPPPP?]]]]]]?ޞ?ݝ???ᱱ??ܜ?ߟ?111111?ర?QQQQQQ?????ݝ???pppppp?qqqqqq????ݝ??ۛ?ZZZZZZ?ښ??tttttt?ܜ?[[[[[[??ښ?VVVVVV?????Օ?Օ??TTTTTT???TTTTTT??ӓ?UUUUUU??ӓ?SSSSSS?ё?˛????????Ғ?TTTTTT?֖?ח?[[[[[[?XXXXXX??????ə?̜??̜?ʚ????ϟ?ϟ????֖?͝??Ș??Ș?Ɩ??Ș????ӓ?ə?Ɩ????Ĕ?Ș????͝?Ǘ??˛???Ó????’?’??Ș?ŕ?ŕ?ŕ??ŕ??˛??Ξ???ʚ?PPPPPP?PPPPPP???͝??ϟ??̜?˛?А?ŕ??Ĕ????ə?????PPPPPP?QQQQQQ?SSSSSS??TTTTTT?444444??888888?::::::??~~~~~~???tttttt?111111?????ё??А?Ғ??RRRRRR?Ԕ?SSSSSS??ӓ?TTTTTT?Ԕ?UUUUUU?Օ??[[[[[[?ٙ?______??ٙ?֖?֖???pppppp?ߟ?ޞ?^^^^^^?ۛ??ۛ?[[[[[[??]]]]]]?ߟ??222222???PPPPPP?ర???ᑑ?111111?????ٙ?[[[[[[?????ܜ??^^^^^^????ߟ??ޞ???______???000000?PPPPPP?000000?ర??______??ర???ర??????pppppp?????000000?????ؘ?ٙ?ݝ?______??㳳??555555?333333?ߟ?ZZZZZZ???[[[[[[??qqqqqq?ZZZZZZ?]]]]]]???VVVVVV?ח?VVVVVV???TTTTTT?Օ?VVVVVV??UUUUUU??Օ???Ԕ?TTTTTT??SSSSSS?UUUUUU??ё??А??ё?RRRRRR?RRRRRR??Ԕ?WWWWWW??[[[[[[???????Ǘ?ə?ʚ??˛?ə??ё?ё?Ғ??ϟ??͝??Ǘ?Ǘ??Ș????Ǘ??ʚ?˛?Ș??ʚ?Ɩ?Ó???Ξ???ʚ?ə?Ξ????Ó????’??????ŕ??Ĕ?Ș?˛?̜??Ξ???QQQQQQ????Ș?Ɩ?Ɩ??Ǘ????Ĕ??ŕ???ə??˛?͝???QQQQQQ???YYYYYY???斖?陙?鹹?Ꚛ??VVVVVV??ښ?ؘ?ח????RRRRRR???SSSSSS???Ғ??TTTTTT?ӓ??ښ???]]]]]]?\\\\\\?ښ?ۛ?[[[[[[???ݝ?????000000??[[[[[[??ݝ???222222?ᑑ??⒒?RRRRRR???PPPPPP??ర?ޞ?^^^^^^?]]]]]]??ۛ?ۛ?YYYYYY?[[[[[[??????ޞ?ర?ర?111111?qqqqqq????ߟ?000000?ర?PPPPPP??pppppp??111111?QQQQQQ?ర?ర?ߟ?ߟ??ర?ᱱ?000000?pppppp??ssssss?ߟ?______?ZZZZZZ?ర?222222??ߟ??PPPPPP???ښ?ؘ?]]]]]]?PPPPPP?Ⲳ?嵵?YYYYYY?rrrrrr???ۛ???^^^^^^?ۛ??????UUUUUU??ۛ??Ԕ??ח???Ԕ?Ԕ??Օ??TTTTTT?WWWWWW??ٙ??͝???PPPPPP?QQQQQQ??ё??TTTTTT???XXXXXX?YYYYYY??ٙ???????ϟ?͝?ə?ə???А????˛?˛?Ș?Ǘ?Ĕ?Ǘ????Ɩ??Ɩ?Ĕ?Ĕ??????????˛??Ɩ??ϟ??Ó?????’??Ó??Ɩ?Ǘ????????????ə?ə?Ǘ?Ș?ŕ??Ĕ??Ǘ??Ǘ?Ș?ŕ?Ș?͝??ʚ?ʚ?̜?QQQQQQ?А?TTTTTT??ӓ??Օ?QQQQQQ?嵵??嵵?vvvvvv?䴴??ߟ??ZZZZZZ?֖?ё?RRRRRR?QQQQQQ??QQQQQQ?ӓ??????ח??XXXXXX?ښ?000000??ߟ?ܜ?]]]]]]??ޞ?ݝ?]]]]]]?^^^^^^?ޞ?pppppp?ᱱ??^^^^^^?ۛ?______???PPPPPP?ᱱ?QQQQQQ?QQQQQQ?rrrrrr?222222??ᑑ???ర??ޞ?000000?]]]]]]?ܜ?ܜ?ܜ???000000?______?ޞ??PPPPPP?ర????______?ݝ?^^^^^^??ߟ???PPPPPP?000000??QQQQQQ?QQQQQQ?qqqqqq??111111?PPPPPP??ޞ?ర?QQQQQQ?ᑑ??111111?222222?ᑑ?ర?PPPPPP??ర?QQQQQQ??pppppp?rrrrrr??ޞ???ח?000000?Ⲳ??uuuuuu?qqqqqq?ݝ???ZZZZZZ??ZZZZZZ?ښ????YYYYYY?ښ??֖??ח???VVVVVV???????ӓ?ӓ??SSSSSS?ӓ?PPPPPP?ʚ?˛???QQQQQQ??SSSSSS?TTTTTT??ٙ?ݝ???VVVVVV?UUUUUU?ܜ??]]]]]]?͝?ʚ?˛?͝?˛?˛???Ξ??Ξ?????ʚ?Ǘ????ŕ?Ɩ??Ó?ŕ?Ǘ??ϟ?????ё?Ξ?ӓ??̜?Ɩ??PPPPPP????????????Ǘ?Ɩ??Ǘ?ə?Ξ??˛?ʚ???PPPPPP?PPPPPP?ə??Ǘ??Ɩ?Ĕ??Ș????Ș???Ǘ??Ǘ??Ξ?Ξ?֖??SSSSSS?RRRRRR???pppppp???pppppp?PPPPPP??______?pppppp???XXXXXX?UUUUUU??RRRRRR?ϟ????Ԕ??ؘ???ښ?֖???ర??[[[[[[??]]]]]]????ܜ??ߟ?ݝ?ޞ?ޞ?ښ?ؘ?YYYYYY?YYYYYY?ٙ?^^^^^^???ᑑ?qqqqqq?????PPPPPP?^^^^^^?QQQQQQ?RRRRRR???PPPPPP????111111?pppppp??ర?000000??111111??ߟ?ޞ?ޞ?^^^^^^?______?______??ߟ??PPPPPP?PPPPPP??000000?111111??QQQQQQ?QQQQQQ?ᑑ?ᑑ?rrrrrr????ᱱ???000000????qqqqqq????RRRRRR?333333?ݝ??TTTTTT????QQQQQQ??^^^^^^???[[[[[[?ۛ?ۛ???ؘ??ښ??XXXXXX?WWWWWW?Օ??RRRRRR?Օ?ח?YYYYYY???Ԕ?Ԕ???UUUUUU????͝???????????ٙ?ؘ???Օ?ؘ???SSSSSS?ʚ?˛?͝??ə?͝?̜??͝?Ξ??̜?????Ș??Ĕ?˛????Ĕ?Ǘ??Ξ?ZZZZZZ?ZZZZZZ?̜????Ғ?̜?Ɩ??ŕ?????Ó???’??Ĕ?Ĕ?ŕ???Ĕ??ŕ??ə??ʚ??ʚ?̜???ə?Ș???Ș??TTTTTT?ə??Ɩ??ə???Ș??ə??ӓ?^^^^^^??А?????VVVVVV??ؘ??Օ??YYYYYY??ݝ?YYYYYY???А?Ξ?PPPPPP?QQQQQQ??VVVVVV?UUUUUU?\\\\\\?WWWWWW?WWWWWW?֖???ZZZZZZ?ښ?ښ?ܜ?]]]]]]??]]]]]]?ۛ????????\\\\\\?ۛ?????PPPPPP?PPPPPP????pppppp?000000?______?ݝ?ٙ?ᑑ???ٙ?ٙ??ߟ???000000?PPPPPP??111111?111111??ߟ?ߟ???ߟ?PPPPPP???]]]]]]??______?ޞ?ݝ?000000?pppppp???ᑑ??㓓????qqqqqq?QQQQQQ??]]]]]]???????PPPPPP???????ח????ర?ర?ݝ??ZZZZZZ?ݝ?ܜ??[[[[[[??]]]]]]??ZZZZZZ?ח?֖??PPPPPP??WWWWWW????WWWWWW????ZZZZZZ?VVVVVV????PPPPPP??ʚ?PPPPPP?ӓ??ӓ?ё???UUUUUU??\\\\\\?[[[[[[???YYYYYY?ܜ?Ғ??ʚ??̜??Ɩ???̜?YYYYYY?ϟ?PPPPPP??ϟ??˛?ʚ?̜??Ɩ?Ǘ?Ɩ??ŕ?Ɩ?Ǘ?˛????ϟ???涶?????Ǘ?̜?Ξ?’??’???Ĕ??Ĕ???ŕ?Ɩ???Ĕ??ə???ʚ?˛??PPPPPP??Ș??Ɩ??????Ɩ?Ĕ???Ɩ?˛??Ǘ????ϟ?͝??QQQQQQ??QQQQQQ???TTTTTT?TTTTTT?SSSSSS?TTTTTT??RRRRRR?VVVVVV?ӓ??UUUUUU??ϟ???ӓ?ӓ?Ԕ?YYYYYY?ښ?ח????????ܜ?______???\\\\\\?^^^^^^?ٙ???????ۛ???PPPPPP?ᑑ??????PPPPPP?PPPPPP?]]]]]]?ښ?ܜ?^^^^^^?^^^^^^??ښ??ޞ?000000?PPPPPP??pppppp?ᑑ?ర??111111??______??000000?PPPPPP?______??ߟ?^^^^^^?^^^^^^??______?pppppp??ᑑ?QQQQQQ?111111??ᑑ??RRRRRR?ᱱ?qqqqqq??ᑑ?ᱱ?QQQQQQ?000000?ߟ??ܜ?ٙ????______??????\\\\\\?333333?????ۛ?ח?YYYYYY?\\\\\\?ZZZZZZ?ؘ?????[[[[[[?֖???QQQQQQ?WWWWWW??ٙ??YYYYYY??֖?UUUUUU??ښ?VVVVVV?UUUUUU???????RRRRRR?SSSSSS????????ח??UUUUUU???͝?????ϟ?ʚ???Ș?PPPPPP???ϟ?˛??ʚ?Ǘ???Ɩ?ŕ?ŕ??ə?Ș??ӓ??QQQQQQ?ZZZZZZ??Ξ???SSSSSS???Ɩ??????????Ĕ??Ĕ??Ǘ????Ș?Ɩ???ʚ?˛?ə???˛?Ǘ?Ș???Ǘ?Ĕ?Ĕ?ŕ??ə?Ǘ??????͝?Ғ??˛?̜??PPPPPP??А?QQQQQQ???ӓ???VVVVVV????TTTTTT?\\\\\\?SSSSSS?Ғ??֖?TTTTTT?֖?XXXXXX?ښ?ٙ????YYYYYY?ٙ?[[[[[[??????ۛ???ZZZZZZ??XXXXXX?ښ??000000?\\\\\\??ߟ??______??111111?pppppp???ޞ?ߟ?______????ܜ?ޞ?]]]]]]?ۛ??000000???pppppp?ߟ?______?______???______?ߟ??ߟ????______?000000??pppppp?PPPPPP??ᱱ?Ⲳ?222222?ᱱ?111111?????⒒???RRRRRR???QQQQQQ?000000?ܜ?ۛ??ݝ????______??ۛ???333333?QQQQQQ?pppppp??ߟ?]]]]]]????????ݝ???WWWWWW?????????VVVVVV?????????QQQQQQ?ё?RRRRRR?ؘ????PPPPPP???֖??ښ?ؘ?ؘ?ח??PPPPPP?VVVVVV???????????̜?͝??????ŕ??Ɩ??˛?ʚ????Ξ???ߟ?Ș??QQQQQQ??SSSSSS??QQQQQQ??˛?̜?ʚ????Ó??’?Ó?Ĕ??’????̜?ə?˛?Ș?Ǘ?͝??͝?Ξ?????ŕ?Ɩ???ŕ?Ĕ?????ŕ????????А?ϟ?̜?А??А?QQQQQQ?????֖??WWWWWW?UUUUUU?ח?֖??ZZZZZZ??Օ???XXXXXX?ۛ?????ZZZZZZ?]]]]]]?]]]]]]?000000??ݝ?\\\\\\????ח??TTTTTT???ٙ??\\\\\\?ޞ?ర?ݝ?]]]]]]?______?ర???ݝ?????^^^^^^?????______??000000??ర?______???????rrrrrr?????^^^^^^?000000?111111?111111?ᑑ??ᱱ?222222?⒒??Ⲳ??RRRRRR?222222?rrrrrr???RRRRRR???Ⲳ?rrrrrr?QQQQQQ?PPPPPP?ޞ??]]]]]]?^^^^^^?]]]]]]?ర?pppppp??______??ښ?[[[[[[?ర?666666???PPPPPP??ᱱ?ZZZZZZ??ۛ?ZZZZZZ?ښ????ZZZZZZ???WWWWWW?Օ?UUUUUU?XXXXXX???ؘ??ח?????TTTTTT??А?ё???XXXXXX???QQQQQQ???RRRRRR??^^^^^^?ZZZZZZ?????UUUUUU?PPPPPP?ϟ???̜?????ə???̜??̜???ŕ?????Ɩ?RRRRRR?ə??ə??UUUUUU??______??ё???RRRRRR????̜??Ș?????????ŕ???RRRRRR?ϟ??̜?Ș?ə?Ș???ʚ?ʚ?Ș???Ǘ?Ɩ??Ǘ?Ĕ?Ó?Ĕ?ŕ??Ǘ?Ș???ё?А?????͝???ʚ?͝?SSSSSS?UUUUUU?TTTTTT?ӓ?TTTTTT?XXXXXX?]]]]]]?ښ?????WWWWWW??ח???ښ??ښ???????ݝ?\\\\\\??^^^^^^?^^^^^^?ښ?ޞ??Օ?SSSSSS?UUUUUU?Օ?YYYYYY?YYYYYY?ۛ??ޞ?ߟ????pppppp?ޞ?????ݝ?______??\\\\\\?ח?ܜ?^^^^^^?PPPPPP??______?]]]]]]???ݝ?ݝ????ܜ??ܜ??______??111111?ర?111111??rrrrrr?Ⲳ?⒒??ssssss?SSSSSS?SSSSSS??⒒?Ⲳ?SSSSSS?Ⲳ?rrrrrr?222222??222222?222222??qqqqqq??PPPPPP????______??PPPPPP?000000?000000?ݝ?]]]]]]?______?pppppp?QQQQQQ??RRRRRR?ᑑ?PPPPPP?qqqqqq????^^^^^^???ٙ??]]]]]]?XXXXXX???֖????????ٙ??????SSSSSS????^^^^^^????ϟ??ӓ?VVVVVV??XXXXXX?ח??UUUUUU?ё????RRRRRR??͝?˛??͝?Ξ???ə?˛???ё??Ɩ???Ĕ?Ĕ?ʚ?ə?Ș??ʚ?А??ח?ё?????ϟ????˛?ŕ??????Ó??Ĕ?Ĕ???Ɩ??ə??̜?SSSSSS?˛?Ǘ?Ǘ??????Ɩ?Ș??Ǘ???Ĕ?ŕ?ŕ???Ǘ??ё???????ʚ???ʚ????Ԕ??SSSSSS?RRRRRR?ח???ؘ??VVVVVV???YYYYYY?ח?^^^^^^?^^^^^^??^^^^^^???000000????[[[[[[?]]]]]]?????ٙ??ܜ?ܜ??XXXXXX????ݝ????ޞ?????ZZZZZZ????㓓???ښ??ర?pppppp?\\\\\\?????YYYYYY?ܜ?ܜ?000000????PPPPPP?000000?000000?PPPPPP??ర?pppppp?⒒???333333?㳳?㳳???㓓???Ⲳ?Ⲳ?⒒??⒒?222222????ᱱ?qqqqqq?pppppp??[[[[[[??^^^^^^?]]]]]]?______?^^^^^^?ߟ????111111?ర?111111??qqqqqq??ؘ????^^^^^^?ٙ?ؘ??[[[[[[?֖?WWWWWW????ؘ?WWWWWW?ښ??ח????SSSSSS??VVVVVV???SSSSSS?ZZZZZZ?^^^^^^??˛?А?̜?RRRRRR?Օ?SSSSSS??Օ?ٙ?????????RRRRRR?ϟ?͝?͝????Ǘ??͝?ə?˛?Ș??Ɩ?Ɩ??Ɩ????ŕ???QQQQQQ?????Ɩ?ə?ə?͝??ʚ??˛???Ĕ????’??Ĕ??Ó??ŕ?Ș?А?ӓ??̜?ə??̜?ə??̜?Ԕ??????Ĕ?Ó???Ǘ?ŕ?Ǘ?Ɩ?ϟ?͝??Ɩ????Ɩ?Ǘ???͝??TTTTTT??Ԕ?Օ?Օ??XXXXXX??ؘ?֖???YYYYYY?ۛ?ZZZZZZ?pppppp?嵵?TTTTTT???䴴?111111?]]]]]]??XXXXXX???ܜ?[[[[[[??ٙ?ܜ?ۛ????ޞ?^^^^^^?ܜ??[[[[[[?ޞ?______?ߟ??QQQQQQ????ZZZZZZ?ZZZZZZ?[[[[[[?ݝ????ర???ߟ?^^^^^^???ܜ?ܜ????ޞ???^^^^^^?ߟ????000000?????333333?ssssss?㳳?444444?TTTTTT?TTTTTT???㳳??333333?333333?333333?⒒?⒒?444444??????111111?ߟ?]]]]]]?^^^^^^?^^^^^^?ZZZZZZ?\\\\\\?______?______??ߟ?000000?ర?ర?111111?ర??\\\\\\??VVVVVV??ZZZZZZ?^^^^^^???UUUUUU?֖???ٙ????XXXXXX?ؘ??ښ?ZZZZZZ?Օ?????????^^^^^^?ZZZZZZ??TTTTTT??͝?ϟ?А?PPPPPP?Ξ?TTTTTT?XXXXXX???Ɩ?PPPPPP?XXXXXX???QQQQQQ?ϟ??˛?ʚ?Ǘ?ə??ə?Ξ?͝?Ǘ?ə??????Ș???ə????PPPPPP?????Ǘ?Ǘ??˛???QQQQQQ??’????Ó????̜?ޞ?QQQQQQ?Ș???ۛ?͝?ʚ???Ξ???Ș?Ș?Ș????ŕ???’??Ó?ŕ?ŕ?̜????Ɩ?ʚ?Ǘ?Ɩ?Ǘ?ə?ə?˛?RRRRRR?Ғ?Ғ?TTTTTT????QQQQQQ?ޞ????WWWWWW????ZZZZZZ??????[[[[[[?ٙ??Ԕ??ܜ?[[[[[[?YYYYYY???]]]]]]??444444?111111???]]]]]]?pppppp???ښ?ݝ?]]]]]]?ݝ??^^^^^^??______?ܜ?^^^^^^?ۛ?]]]]]]????000000?qqqqqq??ݝ??ݝ???______?______?PPPPPP?______?^^^^^^??ۛ?YYYYYY????ర???ర?pppppp?rrrrrr???㳳???TTTTTT?tttttt?䔔?tttttt??㳳?㓓?ssssss?SSSSSS?333333???rrrrrr?qqqqqq?ర?PPPPPP?ర????______?^^^^^^?ښ?[[[[[[?ߟ??ߟ?______???ర???]]]]]]?]]]]]]??ח?ח?????֖????000000?ٙ?XXXXXX?VVVVVV??ۛ????ޞ?ӓ??Օ??Օ??А?Ԕ?VVVVVV?^^^^^^?֖??͝?Ș?Ɩ????????̜?ё??QQQQQQ??А?ϟ??ʚ??ə???ə?Ǘ?ʚ??ə???Ǘ?ʚ???ə??PPPPPP?ё??ϟ???ӓ??Ș?ʚ?Ɩ?Ĕ??ŕ?ŕ??ŕ?’?????Ĕ?Ó?Ó????Ғ???˛?˛?????ʚ?Ǘ?Ǘ??Ș??Ǘ?Ĕ????’??Ĕ?Ɩ??ŕ?Ĕ?Ó?Ǘ?Ǘ???ʚ???Ș????QQQQQQ?ӓ???֖?wwwwww?555555?????Ԕ?֖????????WWWWWW??ؘ??ZZZZZZ???ۛ?????777777????????֖???????ߟ?\\\\\\???ޞ??000000??pppppp?111111???ۛ?ޞ?^^^^^^???ߟ?ߟ?^^^^^^?ߟ????ߟ?ర??ᱱ??ᱱ??rrrrrr??㓓??444444?tttttt?444444?tttttt?䔔?䴴?䴴?tttttt?444444?444444?㳳??㓓??????______?ߟ??PPPPPP?ర???\\\\\\????PPPPPP?^^^^^^????______?ర??????[[[[[[??ח??XXXXXX??ښ?[[[[[[?]]]]]]?ٙ??VVVVVV?ܜ???\\\\\\??UUUUUU??UUUUUU??Ғ??RRRRRR?А??????ϟ?Ĕ?Ǘ?˛?ϟ????SSSSSS?ϟ?А?ё??Ξ??А?͝???ʚ?˛????Ș??Ș??Ǘ??ə????ё???Ξ???Ξ??QQQQQQ?Ɩ???ŕ???ŕ???Ó?ŕ???Ĕ????????QQQQQQ??Ξ?Օ?Ξ??????Ǘ?Ǘ??Ĕ??Ĕ?ŕ?Ó??Ɩ?Ĕ???ʚ???Ĕ?Ɩ??Ș???Ș??ə?Ș?А??ё?ё?UUUUUU???ZZZZZZ?pppppp??RRRRRR??UUUUUU?SSSSSS?Օ???]]]]]]??ZZZZZZ????ٙ?ܜ??ܜ?\\\\\\?ښ??XXXXXX?^^^^^^??qqqqqq???ܜ?]]]]]]?[[[[[[??^^^^^^?????ۛ?000000??QQQQQQ?ߟ?ۛ??XXXXXX?[[[[[[??]]]]]]?______?______?PPPPPP?______????^^^^^^?ݝ?ݝ??000000?PPPPPP?PPPPPP?^^^^^^???______??ర????Ⲳ???ssssss?㳳??tttttt?tttttt??????555555???䴴?TTTTTT??SSSSSS???RRRRRR???PPPPPP?PPPPPP?000000?QQQQQQ?pppppp?????]]]]]]?ߟ?^^^^^^???000000?PPPPPP??PPPPPP???YYYYYY?WWWWWW?ח?[[[[[[????[[[[[[?????WWWWWW?ښ???^^^^^^??\\\\\\??ٙ????RRRRRR??Օ?????˛??Ĕ???̜?̜??TTTTTT???UUUUUU?ё???ϟ?PPPPPP?ʚ??Ș??Ș?ʚ??ʚ??ʚ?ə??͝?Ș????͝???Ξ??ё?ӓ?UUUUUU???ŕ?Ó?Ĕ???Ĕ?ŕ?Ĕ?ŕ??̜??ŕ?Ɩ????Ɩ???Ǘ?Ɩ?˛??????˛????Ɩ???Ɩ????Ĕ???Ɩ?ə?????????Ĕ?Ĕ??Ĕ??˛?ʚ?Ξ????TTTTTT?֖?VVVVVV?А?PPPPPP??????ٙ???ؘ?ٙ??????ޞ?[[[[[[??А??]]]]]]?ߟ?ܜ????ۛ?ۛ?ۛ?]]]]]]??______?ۛ????ర??????ۛ?WWWWWW?ښ?ᑑ????ޞ????]]]]]]???111111??000000?^^^^^^????000000?QQQQQQ?ᑑ????ssssss???tttttt?䴴?䔔??555555?UUUUUU?UUUUUU?uuuuuu?啕?啕?UUUUUU?uuuuuu?555555??䔔??SSSSSS??Ⲳ???ߟ??pppppp?????]]]]]]?ZZZZZZ??ܜ???ߟ?????ݝ?ܜ???֖??ۛ?^^^^^^???ޞ?????ח?ݝ???ښ???ח?Օ?֖?TTTTTT?ח???RRRRRR???Ĕ?ŕ?Ó?ŕ?ŕ???VVVVVV?????Օ?PPPPPP??ə????͝?????˛?ə?Ξ?̜???˛?ʚ??QQQQQQ???ʚ??А??SSSSSS?Ғ?˛??????Ɩ?˛?Ĕ??Ó?Ó?’?Ĕ???Ĕ???Ĕ?????Ǘ?ə??Ξ?ϟ?˛????̜??Ș???????Ĕ?Ó??ʚ??Ĕ???Ĕ?Ó?Ɩ???’??ŕ???˛?˛?ϟ???ё?SSSSSS?TTTTTT??Ξ??Օ???YYYYYY?ݝ??ܜ??XXXXXX?֖??XXXXXX?ݝ?ZZZZZZ?[[[[[[?ښ?Օ?Ғ?QQQQQQ??֖?????]]]]]]????QQQQQQ??^^^^^^?[[[[[[??WWWWWW??ۛ??ZZZZZZ?ښ??000000???XXXXXX?ؘ?ܜ???[[[[[[?ܜ?????000000?RRRRRR?rrrrrr??pppppp?????ᑑ?222222?RRRRRR?Ⲳ?ssssss?㓓????tttttt?䔔?555555?uuuuuu?嵵??????嵵?啕?555555???㳳?333333??RRRRRR?ᑑ???qqqqqq????ܜ?[[[[[[?ٙ?VVVVVV??^^^^^^?^^^^^^??ߟ???^^^^^^?ښ?ٙ???YYYYYY?ۛ???ܜ??ޞ????????YYYYYY?XXXXXX????֖?UUUUUU??Ԕ?VVVVVV?SSSSSS?ϟ?QQQQQQ?Ξ?ʚ?Ș???Ǘ??ϟ?QQQQQQ?????TTTTTT?RRRRRR?Ș?ŕ?ŕ??̜??˛?̜?Ξ?̜????͝?̜????ʚ???ə?Ξ?֖???̜?Ș???Ɩ?Ǘ?Ɩ?Ǘ???’????Ó?’???Ș???Ɩ?Ĕ??ŕ?Ĕ???ʚ?ϟ????Ξ?ʚ?SSSSSS???Ԕ?ŕ???Ɩ??????Ĕ?Ĕ?Ĕ?ŕ?ŕ?’?Ĕ???ŕ?ŕ?˛?RRRRRR??Ξ???ϟ??UUUUUU?ӓ?UUUUUU?VVVVVV?ݝ?ӓ?ח??YYYYYY?ښ?]]]]]]?ܜ????VVVVVV??ٙ?ٙ?????ښ??UUUUUU???ݝ??ݝ??ܜ????______?ܜ??ٙ??]]]]]]??ؘ??\\\\\\?ۛ??ښ????ܜ?^^^^^^?ۛ?ZZZZZZ?ܜ??^^^^^^??ޞ?pppppp??QQQQQQ??222222?QQQQQQ?111111?ᑑ?222222?RRRRRR?Ⲳ?SSSSSS?SSSSSS???444444?䔔???UUUUUU?嵵???VVVVVV?VVVVVV?666666?666666???嵵?嵵??䔔???333333?⒒??111111?RRRRRR????ᱱ??[[[[[[???\\\\\\?^^^^^^?^^^^^^???ߟ?^^^^^^??ۛ?ZZZZZZ?ח?UUUUUU???ܜ?\\\\\\???[[[[[[?ٙ?YYYYYY?ח???ؘ?ٙ???XXXXXX?ښ?ؘ???UUUUUU?Ԕ??ӓ?ϟ?????˛????ϟ???SSSSSS?SSSSSS????ŕ?Ǘ?ϟ???̜??Ș?ə?Ξ?˛?˛?ə??͝?̜????ŕ?Ș??ϟ???ə?˛?Ғ?ə?ŕ??Ɩ?’???ŕ??’?????А???ə?ŕ?Ɩ???Ɩ?Ǘ??ə?Ǘ??ʚ?˛??000000?А???˛?Ξ?????Ɩ???Ó?Ĕ?????Ĕ?Ɩ?Ĕ??????Ξ??ё?QQQQQQ???TTTTTT?֖?VVVVVV?XXXXXX?VVVVVV??YYYYYY???ۛ??ۛ?\\\\\\?ZZZZZZ?ؘ?WWWWWW?֖?ח??ښ?ؘ?ח?Օ??ܜ?????\\\\\\?[[[[[[?[[[[[[??ޞ?ۛ????ښ?ZZZZZZ???[[[[[[?YYYYYY?ٙ?ٙ?ח?YYYYYY?ZZZZZZ???????XXXXXX??]]]]]]?ݝ?______?^^^^^^?ߟ??ZZZZZZ??111111???ᑑ?ᱱ?⒒?Ⲳ?333333?㓓?㳳?444444?tttttt?䔔???555555???VVVVVV?vvvvvv?斖??涶?vvvvvv?666666?666666???UUUUUU??tttttt??㓓??222222????111111?pppppp?000000??]]]]]]???^^^^^^?QQQQQQ?pppppp?______?\\\\\\?ݝ??^^^^^^?ܜ???YYYYYY??ܜ?ZZZZZZ??ݝ??????ח?ؘ?]]]]]]?????[[[[[[?WWWWWW?WWWWWW????TTTTTT??QQQQQQ?Ξ??˛??ϟ????RRRRRR??RRRRRR?TTTTTT?֖??Ǘ??˛????ϟ??Ξ?˛??͝?͝?͝??PPPPPP??Ғ?Ξ???˛??ə?TTTTTT?Ξ?ϟ??˛?ə??ŕ??Ǘ??’?????Ó??’???QQQQQQ?Ș?Ĕ??ŕ??ə?ə??Ǘ??̜?А?ə???Օ???͝??QQQQQQ??PPPPPP??????Ó?Ó?Ĕ?̜?ŕ??Ó??’??????Ξ?PPPPPP???QQQQQQ?ё?ח?WWWWWW??ٙ?VVVVVV?SSSSSS?ٙ??000000?ܜ???ٙ?ח???VVVVVV?VVVVVV?֖?VVVVVV???YYYYYY?XXXXXX?ݝ????[[[[[[?]]]]]]????[[[[[[?[[[[[[?ٙ??YYYYYY??ٙ?WWWWWW?UUUUUU?֖?Օ?\\\\\\???]]]]]]?[[[[[[?\\\\\\?ۛ??ښ??YYYYYY???ޞ?]]]]]]??^^^^^^????ޞ????????SSSSSS?333333?444444?TTTTTT?䴴?䴴????VVVVVV?斖???????vvvvvv?666666?666666??嵵?555555?䴴?444444??SSSSSS?Ⲳ??QQQQQQ??pppppp???ᑑ?^^^^^^?ݝ??______?000000??^^^^^^???ߟ??ܜ??????ZZZZZZ?XXXXXX??[[[[[[??]]]]]]??ח?ؘ?ؘ??ٙ?ܜ??000000?[[[[[[?VVVVVV??TTTTTT?SSSSSS??????͝?̜?Ξ?ϟ????RRRRRR?TTTTTT???TTTTTT?͝?Ó???А?PPPPPP????ё???Ξ??˛???QQQQQQ??͝?UUUUUU?̜??ϟ??͝?ؘ????Ș?ʚ??Ɩ?ə?Ĕ?Ĕ????Ó????͝??ŕ??Ĕ?’?Ó??ə?Ǘ?Ș???????А????А?͝???ŕ???Ș???Ĕ?Ó?Ó?Ĕ?Ó?’?Ĕ????͝???˛??QQQQQQ???ё?TTTTTT??֖????QQQQQQ?Օ?SSSSSS????ٙ?ؘ?XXXXXX??WWWWWW?Օ???????ؘ???ssssss?]]]]]]?ٙ?ZZZZZZ???ښ??ښ?ښ?ٙ?ۛ???WWWWWW??Օ?XXXXXX???]]]]]]???ܜ??ZZZZZZ?ח??Օ?[[[[[[?ݝ?ޞ?rrrrrr??ޞ???ݝ?ߟ?ర??pppppp??rrrrrr?333333?㓓?㓓?㳳?tttttt?????VVVVVV?涶??777777??777777??WWWWWW?WWWWWW?777777??斖?666666?啕??uuuuuu??䔔?㳳?㓓???ᑑ????000000?PPPPPP?^^^^^^?]]]]]]??ݝ??\\\\\\?ޞ??ښ?\\\\\\?ݝ?ݝ???ښ?Օ?UUUUUU??ؘ?ܜ??ۛ????ٙ?֖?XXXXXX?\\\\\\?????Օ??UUUUUU?ӓ?RRRRRR?SSSSSS?RRRRRR??͝?˛?̜?А?ё?Ғ????????ё?ʚ??RRRRRR??ϟ?QQQQQQ??PPPPPP??????Ξ??QQQQQQ?PPPPPP?ӓ??PPPPPP?QQQQQQ?͝?͝?ϟ?Ξ?UUUUUU?А??Ș??Ș?Ș??̜??Ǘ?Ĕ?’?????Ĕ???Ĕ???Ĕ??Ș????Ǘ??ʚ??А?ӓ?̜?˛?͝?˛?͝??̜??ə??ŕ?Ó??Ó?Ó??????ŕ?ŕ?????ϟ?PPPPPP??????SSSSSS??WWWWWW??TTTTTT??QQQQQQ???WWWWWW???ؘ???TTTTTT?UUUUUU???֖?Ԕ??????ర?]]]]]]?ۛ???ٙ?ZZZZZZ?????ٙ?YYYYYY?XXXXXX?TTTTTT???ٙ?[[[[[[??]]]]]]??ߟ??\\\\\\?ښ??ZZZZZZ??ZZZZZZ?]]]]]]??ߟ???????000000??qqqqqq?RRRRRR??SSSSSS?SSSSSS?㓓????uuuuuu?uuuuuu?vvvvvv??WWWWWW?痗?緷???緷??緷?痗?痗?wwwwww?777777?涶?VVVVVV??嵵?555555?䴴??㳳??222222??ᱱ?111111??000000?ర?ߟ????ݝ?????ۛ????\\\\\\???\\\\\\?\\\\\\??]]]]]]??^^^^^^?????ח???]]]]]]???ؘ?֖?ӓ???RRRRRR?RRRRRR????Ξ?̜?RRRRRR????ӓ??ё?TTTTTT?ZZZZZZ??QQQQQQ?Ξ?̜???͝?А??А?ə?Ș??͝?̜??ZZZZZZ?Ғ?ښ????Ξ???ӓ???͝??Ș????Ɩ???’?’?Ó?????Ĕ??Ó?ŕ??͝??????ə???ə??Ξ?QQQQQQ???͝??ӓ??????????????͝??Ǘ?Ǘ?????А???Ғ??Ғ?RRRRRR?Ғ????????WWWWWW?[[[[[[?ٙ??ٙ???TTTTTT???ؘ?Օ?Օ??XXXXXX?TTTTTT?VVVVVV??WWWWWW???YYYYYY?YYYYYY?ܜ?ۛ?ٙ??ٙ???Օ?TTTTTT?WWWWWW?????\\\\\\??^^^^^^??ޞ??ښ?RRRRRR?????????XXXXXX?????ర?QQQQQQ?222222?SSSSSS?SSSSSS???tttttt?UUUUUU?uuuuuu??涶?wwwwww?緷??888888?xxxxxx?xxxxxx?xxxxxx?XXXXXX?XXXXXX?888888????wwwwww???vvvvvv??uuuuuu???㓓???ᱱ?qqqqqq??pppppp??PPPPPP?pppppp??ܜ???ߟ???XXXXXX??ؘ?\\\\\\??ܜ?ݝ??]]]]]]???ޞ??ښ?ޞ??ח??ZZZZZZ?ZZZZZZ?ܜ?ښ???XXXXXX?\\\\\\?Ԕ??QQQQQQ?͝?ə???̜??????ё?ё?Ғ??ӓ?RRRRRR???Ξ???͝??VVVVVV?RRRRRR?PPPPPP?????Ξ??ۛ??QQQQQQ?ϟ?ϟ??Ξ??А?????ʚ?ə??ŕ?ϟ??????’??’????’????’????Ɩ?ŕ???Ș??ʚ?Ξ???А?ϟ??PPPPPP?˛??ϟ?????Ĕ???????˛????SSSSSS?QQQQQQ???ё???Ғ??Օ??Ғ??????ё???ۛ??֖??Օ??UUUUUU?XXXXXX?֖??VVVVVV??Օ?UUUUUU?ؘ?ؘ???YYYYYY?XXXXXX?YYYYYY?XXXXXX?ۛ????TTTTTT?????ٙ??pppppp?^^^^^^?ۛ?ޞ???]]]]]]?ޞ?]]]]]]???ܜ??______??\\\\\\???YYYYYY?ښ??000000??qqqqqq?ᑑ?rrrrrr?333333?㓓??䔔??UUUUUU???痗??XXXXXX?xxxxxx?踸???????xxxxxx?XXXXXX?888888??wwwwww?777777??666666??UUUUUU?䴴?㳳??rrrrrr??QQQQQQ?ర?pppppp?????ޞ?\\\\\\?\\\\\\?ݝ?[[[[[[??]]]]]]?ܜ?ۛ?ݝ?ܜ??ܜ?ߟ?^^^^^^?pppppp?????ZZZZZZ?ݝ?ۛ?]]]]]]??ښ???\\\\\\??ZZZZZZ???Ԕ?XXXXXX???Ș?Ǘ??͝?̜?͝???ϟ?PPPPPP??PPPPPP??PPPPPP?ё?RRRRRR??Ĕ??ϟ?ӓ???А??ʚ?PPPPPP?Ξ?UUUUUU???SSSSSS?Ԕ???ϟ?͝?͝???PPPPPP??Ș????Ǘ?????????????’???????̜?Ĕ????RRRRRR?Ș?˛?????QQQQQQ??WWWWWW?̜?ϟ????????Ɩ?Ǘ?Ș?Ș?͝????ϟ?А??QQQQQQ?Ғ?RRRRRR?ӓ?Ғ??֖?ӓ?UUUUUU?ӓ???ZZZZZZ????ۛ????ח?ؘ????ח???111111???ח?XXXXXX??XXXXXX???֖???ښ??????UUUUUU?YYYYYY?ٙ?YYYYYY?????^^^^^^?rrrrrr?????ښ??ۛ?ܜ??^^^^^^???YYYYYY??ZZZZZZ???qqqqqq?222222?RRRRRR??SSSSSS??䔔??555555?嵵??緷?888888?xxxxxx?踸??999999?陙?陙?陙?YYYYYY?YYYYYY?YYYYYY??踸?xxxxxx???wwwwww??VVVVVV??啕?tttttt??SSSSSS?ssssss?⒒?ᱱ??000000?000000??pppppp?ᑑ??ݝ?ܜ?\\\\\\??ޞ???^^^^^^????[[[[[[?ޞ?QQQQQQ?ssssss??PPPPPP??\\\\\\????]]]]]]?ߟ???ښ?[[[[[[??ZZZZZZ??֖???͝?PPPPPP?˛?Ǘ?Ǘ?????ё???ϟ?А?QQQQQQ?А??Ξ???ə?А?????Ξ??А??ח??PPPPPP???ϟ??????PPPPPP??ə???ə?˛???ŕ??Ĕ??Ó??’????????’?Ó??Ș??????ӓ??ϟ?ϟ??͝????˛?˛?ϟ?Ǘ?Ǘ???Ĕ???Ǘ?̜??͝?А??ё?А???ϟ?????????Ԕ?TTTTTT?Ғ?Ғ??ܜ?ښ?]]]]]]?ܜ?000000?ؘ?ZZZZZZ??VVVVVV??֖????111111?ٙ????ښ?ٙ??WWWWWW??XXXXXX??ZZZZZZ???ؘ?֖????YYYYYY?YYYYYY?ؘ?ښ?YYYYYY?????^^^^^^?[[[[[[??ؘ?ZZZZZZ?ۛ?????ܜ?ۛ??ٙ??000000??ᑑ?⒒?Ⲳ?SSSSSS??tttttt?555555?UUUUUU?555555?嵵?痗??蘘???陙?鹹???????yyyyyy??蘘?888888??緷??斖??uuuuuu?䴴??㓓??222222??ᑑ?ర???PPPPPP???ޞ????ޞ?[[[[[[?]]]]]]???ۛ?ښ??ޞ?ߟ?ᑑ?ᑑ?000000??\\\\\\???ؘ??????[[[[[[??ۛ?ۛ??RRRRRR??QQQQQQ????˛?Ξ?͝?ё?ϟ??????А?А?QQQQQQ??ŕ?Ș??ϟ?А?PPPPPP???͝?А??RRRRRR?ۛ?PPPPPP?͝??RRRRRR?А?ʚ?˛???PPPPPP?RRRRRR???ʚ?QQQQQQ??Ɩ?ŕ?Ĕ??ŕ??????’????Ĕ????’???ə?QQQQQQ???͝????͝?QQQQQQ???Ξ?PPPPPP??????ŕ?Ĕ?Ĕ??Ș?Ș?ə?Ԕ?Ԕ?А?͝?PPPPPP?Ξ?ϟ?PPPPPP?RRRRRR?ښ??PPPPPP?QQQQQQ?QQQQQQ?QQQQQQ???SSSSSS?Ԕ?UUUUUU??XXXXXX?ZZZZZZ??^^^^^^???WWWWWW?ח?\\\\\\?֖?Օ?ؘ?YYYYYY???ZZZZZZ??]]]]]]?ᱱ?XXXXXX???????]]]]]]?ٙ???YYYYYY???ٙ?YYYYYY?YYYYYY?????ݝ???ޞ?ߟ???YYYYYY???????]]]]]]????PPPPPP??ᑑ?rrrrrr??333333?TTTTTT?䔔??啕??vvvvvv?777777?888888?蘘??yyyyyy?陙?::::::?ZZZZZZ?Ꚛ?꺺?Ꚛ?zzzzzz?::::::???鹹?999999?踸?xxxxxx??777777?涶??啕?䔔?䴴?TTTTTT???rrrrrr???ర?ర?000000?pppppp??^^^^^^?[[[[[[???ݝ?ۛ?ޞ???ٙ?ښ?????qqqqqq?333333?????ؘ?XXXXXX?ٙ??ښ??ܜ?????ӓ???А?А??ʚ?̜?Ξ?Ξ???PPPPPP???????????ӓ?Ғ?SSSSSS?PPPPPP?͝?͝?ϟ???QQQQQQ?ϟ?˛?ϟ???̜?̜??ʚ?֖???ʚ?˛??Ǘ?Ó?Ĕ??Ó???ŕ?Ó????’?ё??’???Ó??Ĕ???QQQQQQ??QQQQQQ??SSSSSS?֖?VVVVVV?ח?А?ʚ???̜???Ǘ?˛?PPPPPP??ŕ?ŕ??Ǘ??RRRRRR?UUUUUU?А????Ξ?PPPPPP???ӓ??PPPPPP?ϟ????WWWWWW??TTTTTT?UUUUUU??XXXXXX?ZZZZZZ??????ٙ?ۛ???ח????XXXXXX?ݝ????YYYYYY????ٙ?????ٙ?ٙ?ZZZZZZ?WWWWWW?ښ?ח??WWWWWW?ۛ???ݝ?]]]]]]?______?111111??]]]]]]?ښ??ښ?[[[[[[?ݝ???______??000000????111111??rrrrrr??ssssss?TTTTTT??uuuuuu??VVVVVV??緷?XXXXXX??yyyyyy???zzzzzz?꺺??????Ꚛ?ZZZZZZ??鹹?999999?踸??緷??VVVVVV????䴴??RRRRRR?rrrrrr?QQQQQQ?qqqqqq?ర?000000???ߟ?ݝ?[[[[[[?PPPPPP?ߟ?ޞ???[[[[[[?????ݝ?ޞ?111111?Ⲳ?QQQQQQ??000000?ݝ?ؘ????ZZZZZZ??]]]]]]??ZZZZZZ??֖??RRRRRR??QQQQQQ??ϟ?PPPPPP?ə?̜?ϟ??PPPPPP????RRRRRR?ё?RRRRRR?Ғ???Ξ????????͝?̜??Ș??Ș???̜?͝????ʚ?А?А??Ξ???Ɩ?Ó??’????Ĕ?Ș?’????’??Ó?Ɩ??????Ĕ?Ș?ӓ?ۛ?PPPPPP?ё?Ԕ???ӓ???ʚ???Ǘ?Ɩ??Ɩ??ŕ??Ĕ??????ʚ?????RRRRRR?SSSSSS??Ғ?ӓ????WWWWWW?ٙ??ϟ?????111111?ZZZZZZ?ښ?VVVVVV?ٙ???????VVVVVV??VVVVVV?֖????[[[[[[?XXXXXX?ZZZZZZ??YYYYYY?[[[[[[?ZZZZZZ??XXXXXX??ZZZZZZ??XXXXXX???ח?VVVVVV??\\\\\\?______??555555?ݝ???\\\\\\?ݝ???ݝ??ߟ?______?pppppp?qqqqqq??ర?111111?qqqqqq?111111??rrrrrr??㓓?tttttt??啕??涶?wwwwww??蘘?YYYYYY??zzzzzz?Ꚛ?꺺??{{{{{{?뛛?뛛?뛛?;;;;;;??zzzzzz?ZZZZZZ??yyyyyy??XXXXXX??WWWWWW?斖??UUUUUU?䔔??SSSSSS?⒒?ᱱ?QQQQQQ????pppppp????ݝ???ޞ???ܜ???ؘ???qqqqqq?000000???pppppp?]]]]]]??ؘ????ښ?ݝ?ޞ?[[[[[[?ٙ?????PPPPPP??ϟ?PPPPPP?˛??͝?PPPPPP??͝??PPPPPP??RRRRRR????А?ϟ?А??Ғ???ӓ???ϟ??͝?Ғ?Ɩ?Ĕ?Ǘ??͝?А??XXXXXX??PPPPPP?ϟ????Ξ??ŕ??А?Ó????????Ĕ?Ĕ??????Ĕ?ŕ????Ǘ?ə?Ԕ???PPPPPP?А???RRRRRR?ϟ?˛??Ǘ?Ɩ??Ĕ?Ĕ?Ǘ??Ĕ?Ó?Ó?ŕ??˛?˛????͝??Ғ?Օ??ӓ?TTTTTT??WWWWWW?ח???Ԕ????ܜ??[[[[[[?VVVVVV?Օ?UUUUUU??????UUUUUU???UUUUUU?UUUUUU??]]]]]]??XXXXXX?ח??ؘ?ZZZZZZ????ؘ?ZZZZZZ??ZZZZZZ???WWWWWW???ߟ?????\\\\\\?ۛ??ݝ??[[[[[[?ݝ?]]]]]]?______?______?______?qqqqqq?000000?000000????qqqqqq?ᱱ??rrrrrr??㳳???uuuuuu???緷?踸?999999?鹹?ZZZZZZ?꺺??{{{{{{???<<<<<>>>>>???????????======?윜??[[[[[[??ZZZZZZ?陙??XXXXXX?wwwwww???UUUUUU?䴴??SSSSSS??ᱱ?QQQQQQ???000000???ݝ???ޞ?ݝ?ܜ??ښ?ۛ?\\\\\\???\\\\\\???]]]]]]?^^^^^^??000000?______?\\\\\\?????????Օ?WWWWWW?]]]]]]??UUUUUU????͝??Ԕ?Ξ?̜?ʚ???????QQQQQQ?Ξ?RRRRRR?????ӓ?RRRRRR????Ξ????А?WWWWWW?TTTTTT?QQQQQQ?WWWWWW??ϟ?̜?˛??͝?͝?͝??Ǘ???ə??ё??Ĕ??????????????Ǘ?А?PPPPPP?WWWWWW?Ԕ?QQQQQQ???Ș?˛?ё?ϟ?Ξ??˛?ŕ?’??ŕ????Ĕ?Ĕ??Ș?Ș??Ǘ?ʚ???̜?ё?????Օ????Ԕ??\\\\\\?ё??XXXXXX?֖?֖?WWWWWW??WWWWWW?֖?UUUUUU??ܜ??VVVVVV???ٙ??????VVVVVV?YYYYYY??ؘ??XXXXXX?XXXXXX??PPPPPP?______????VVVVVV??ٙ?ښ?YYYYYY?XXXXXX?ښ??______???ZZZZZZ?ښ?[[[[[[??]]]]]]?^^^^^^??^^^^^^?YYYYYY?ۛ?111111??ݝ?^^^^^^?PPPPPP??qqqqqq?ᱱ?ᱱ?Ⲳ??tttttt?䴴?UUUUUU?VVVVVV??緷?xxxxxx??鹹?ZZZZZZ??;;;;;;??윜???????======?윜??[[[[[[??ZZZZZZ?yyyyyy??888888?WWWWWW?涶??UUUUUU?䔔?444444?ssssss?⒒??qqqqqq??pppppp?000000????]]]]]]???????ۛ???______?]]]]]]?\\\\\\???ߟ?RRRRRR??[[[[[[?ٙ?ښ?YYYYYY??pppppp???YYYYYY????֖?֖?SSSSSS??Ғ?Ξ?͝?̜???ə?ə??Ș?ə?Ξ?А??А?PPPPPP?ə???Ғ?Օ?Օ??SSSSSS?ё?ё?ϟ??͝?PPPPPP?????ؘ?]]]]]]???????Ș??Ǘ??????Ó????’???????’??Ó?ʚ??͝?ӓ?Օ?QQQQQQ?֖??ə?ʚ?А?̜?ʚ?Ξ?ə?ŕ????ŕ?’??’?Ó?ŕ??????????PPPPPP??А??PPPPPP??XXXXXX?VVVVVV?UUUUUU??QQQQQQ?RRRRRR?ӓ?SSSSSS??֖??WWWWWW?XXXXXX?ؘ?VVVVVV?ח??WWWWWW??WWWWWW?WWWWWW???VVVVVV???????YYYYYY??ؘ?ZZZZZZ?ܜ?______?222222???ח?֖?????ٙ???]]]]]]??]]]]]]?YYYYYY??ZZZZZZ?ݝ??]]]]]]?ښ?^^^^^^????ర?000000?ݝ??000000?pppppp?ᑑ?rrrrrr?rrrrrr?Ⲳ?㳳?䔔??????蘘??鹹?zzzzzz??[[[[[[??||||||??흝?~~~~~~?????\\\\\\?뻻?;;;;;;?Ꚛ??YYYYYY?踸??777777?vvvvvv???TTTTTT??ssssss?222222?qqqqqq?QQQQQQ???ߟ???]]]]]]??^^^^^^?]]]]]]?\\\\\\????ݝ???ښ???^^^^^^?[[[[[[???ޞ?ZZZZZZ?ݝ?ۛ?QQQQQQ?????ؘ?ؘ?UUUUUU??Ԕ?TTTTTT??????Ξ???Ș???˛?ə???Ξ?̜???????ӓ?PPPPPP?ё??А??Ξ?̜?ё??RRRRRR??ё??[[[[[[?QQQQQQ????Ș?UUUUUU???ŕ?Ɩ???Ĕ??????????????????ё?Ғ????ʚ?????????Ș??А?Ó??Ó???Ǘ?˛???ʚ??????QQQQQQ???????VVVVVV?ZZZZZZ??А?ϟ???XXXXXX??WWWWWW?????YYYYYY??ߟ??SSSSSS?Օ?֖??Ԕ????WWWWWW??ؘ?ZZZZZZ????ZZZZZZ?ݝ?^^^^^^?ܜ?????UUUUUU???ؘ???ۛ?ۛ?^^^^^^?ٙ?Ԕ??YYYYYY?????ޞ??PPPPPP??ޞ???000000??ᑑ?222222?⒒?333333?㓓?TTTTTT??啕?vvvvvv?777777??xxxxxx??鹹?zzzzzz??;;;;;;?뻻??윜??흝??흝??||||||??뛛??ZZZZZZ???蘘?緷??vvvvvv???444444?㳳?333333?RRRRRR?111111?111111?111111??______???ݝ???]]]]]]?ۛ??ښ??????????ᑑ?^^^^^^??????ܜ?]]]]]]??^^^^^^?????SSSSSS??Ғ????Ξ??˛???Ș??А?Ξ??˛?͝?˛???А?ӓ???ё???ё?А??Ξ??PPPPPP??QQQQQQ?Ғ??Ғ?RRRRRR??Օ?А?PPPPPP?PPPPPP?QQQQQQ?Ɩ????Ĕ??’???????????????ŕ?ؘ?RRRRRR?000000????PPPPPP?˛?????Ș?ŕ???Ș??ϟ??ŕ?Ó??Ɩ?˛??PPPPPP???ё??ʚ?ϟ?XXXXXX????TTTTTT?UUUUUU??VVVVVV???ښ???TTTTTT?ӓ?ؘ????ۛ?XXXXXX?????XXXXXX??TTTTTT?ё???VVVVVV??ח?Օ???ښ??pppppp????\\\\\\?ۛ?YYYYYY?ٙ?ח?RRRRRR?????YYYYYY??\\\\\\?????ؘ?ᑑ?ݝ??????ర??]]]]]]?[[[[[[??pppppp?QQQQQQ???rrrrrr?Ⲳ?ssssss?TTTTTT??uuuuuu?666666?777777??XXXXXX?999999?鹹??꺺??뛛??<<<<<>>>>>????????;;;;;;?999999???ᑑ???ݝ?______??ښ??ܜ??______???pppppp????ర?111111?qqqqqq?ᱱ?Ⲳ?⒒??333333?ssssss?ssssss?㓓??TTTTTT?tttttt?䔔?䔔?tttttt?tttttt?TTTTTT??㓓?㓓?㓓?SSSSSS?ssssss???222222??222222??ర??ᑑ?qqqqqq?ర?PPPPPP???]]]]]]?[[[[[[??ݝ??ۛ?]]]]]]?ߟ?ߟ??QQQQQQ???QQQQQQ??ߟ??ݝ?]]]]]]??\\\\\\??ZZZZZZ????ߟ?ᑑ??ܜ??????А?А?А?ʚ??Ș?А??ӓ?XXXXXX??TTTTTT?ؘ?WWWWWW?֖??ݝ??RRRRRR?Ԕ?Օ?TTTTTT????????TTTTTT??А?TTTTTT?PPPPPP?PPPPPP??Ғ?ё?Ғ?А?????????’??’????Ɩ???Ǘ???????????’????Ɩ?Ɩ?Ǘ??ŕ??Ó????Ĕ???Ĕ???????Ĕ???Ș?ə?͝?Ɩ????Ξ?ё?ё?UUUUUU??????VVVVVV?Օ?TTTTTT??XXXXXX?______???֖?Ԕ???ӓ?ܜ????SSSSSS???ə?????^^^^^^??֖??Ԕ?VVVVVV?????UUUUUU?[[[[[[??VVVVVV??YYYYYY??[[[[[[???rrrrrr?斖?yyyyyy??????rrrrrr??ۛ?ۛ??ݝ??YYYYYY?ݝ????ޞ??PPPPPP?]]]]]]?]]]]]]???SSSSSS??111111??⒒?Ⲳ??㓓?㳳???tttttt?TTTTTT?TTTTTT?䴴?444444?TTTTTT???㳳?ssssss????RRRRRR??RRRRRR?⒒??ᑑ??QQQQQQ?QQQQQQ??ޞ???\\\\\\??ۛ?ܜ???^^^^^^?______??000000?ݝ?ݝ???PPPPPP?ߟ????[[[[[[?\\\\\\?ZZZZZZ?XXXXXX?[[[[[[?ܜ?ߟ?㓓?rrrrrr?ޞ?\\\\\\?111111?444444???֖?֖??А?PPPPPP?̜?̜?Ξ?PPPPPP???ӓ??????WWWWWW??ӓ?TTTTTT?Ԕ??TTTTTT?ӓ?ӓ??RRRRRR?Օ?֖??VVVVVV?VVVVVV??WWWWWW?QQQQQQ??ӓ??PPPPPP??????????????????Ș??Ș?????Ғ???ŕ?Ó?Ș??Ĕ?ə?ŕ???Ĕ?Ĕ??QQQQQQ?Ó?ŕ?Ĕ???’??Ó?Ó???????Ĕ?ŕ?Ɩ?Ǘ?ə???Ǘ?̜??ё?QQQQQQ?UUUUUU?ܜ?XXXXXX?Ԕ?ח?XXXXXX?֖?Ԕ?SSSSSS??YYYYYY?ٙ?WWWWWW?ٙ??TTTTTT?TTTTTT?TTTTTT?XXXXXX?֖??Ғ?RRRRRR?QQQQQQ???ə?˛?А??А?SSSSSS?Օ?Ԕ??Ԕ?Ԕ?RRRRRR?RRRRRR??Ғ??Օ?WWWWWW?XXXXXX?WWWWWW???ښ??ܜ??啕?ZZZZZZ?꺺?뻻?::::::?VVVVVV?RRRRRR???ښ?????֖?[[[[[[?ܜ???^^^^^^?000000?ర???______??222222?222222?PPPPPP?ᑑ?RRRRRR?rrrrrr?rrrrrr??ssssss?㳳??444444???444444?㳳????444444??㓓????222222??222222??ర?????^^^^^^?ܜ??[[[[[[???ݝ????000000????]]]]]]??PPPPPP?㓓??______?ޞ?ۛ?]]]]]]?XXXXXX???ۛ?ݝ??222222?000000?ZZZZZZ???ߟ?______???ח?RRRRRR?А?А????А??Ғ?QQQQQQ?ё?Օ???Ԕ?TTTTTT?UUUUUU?Օ????֖???SSSSSS?Օ?֖??WWWWWW?֖??????PPPPPP?͝??Ǘ?˛?Ǘ??’????????Ó?????Ó???Ó?Ĕ?Ɩ?ח?Ș??Ǘ?Ɩ?ŕ???ʚ?̜?Ǘ????ŕ?Ó????Ĕ??ə??’??’?Ó??Ĕ?Ó?Ó?????????Ș?Ș??̜?ϟ?UUUUUU?WWWWWW????ssssss??TTTTTT??Ԕ?YYYYYY???Ԕ??SSSSSS??Օ?SSSSSS???ё?QQQQQQ?QQQQQQ?͝???˛?????Ғ???VVVVVV?ӓ?SSSSSS????????Օ???ښ?pppppp??ߟ??uuuuuu?VVVVVV?wwwwww?斖?WWWWWW???YYYYYY??[[[[[[???ۛ?֖???ޞ?______??000000?ర?pppppp?ޞ?______???qqqqqq??ర??RRRRRR?rrrrrr?RRRRRR?333333?ssssss?㳳???444444?444444??????ssssss???Ⲳ?222222?RRRRRR?222222??ᑑ???PPPPPP?ߟ??^^^^^^??ܜ???^^^^^^?^^^^^^?^^^^^^???pppppp????ޞ??000000?RRRRRR?ᑑ?PPPPPP??\\\\\\?[[[[[[?ٙ?XXXXXX?ٙ??[[[[[[??ۛ?ۛ??ᱱ?ښ???ర?QQQQQQ???RRRRRR?Ξ??????SSSSSS???RRRRRR?RRRRRR?Ԕ????UUUUUU?ٙ?ٙ?Օ?????Օ???PPPPPP?TTTTTT?ZZZZZZ???PPPPPP?Ξ??͝??Ș??Ǘ????????????’?’??’??’?ח?Ĕ?Ĕ?ə?Ó??Ș?ё??ʚ?QQQQQQ?QQQQQQ???Ó?’?Ó??Ó????’?˛??Ó??????Ó??Ǘ??ə??Ǘ?Ɩ???˛???А??͝????Ғ?ర??ח?А???????TTTTTT???ӓ?Ғ?Ғ???ϟ?А??̜?ʚ??Ξ??А?ё?SSSSSS??ؘ?????QQQQQQ?Ғ?RRRRRR?ӓ???UUUUUU?SSSSSS?YYYYYY??ZZZZZZ??222222?ర?ᱱ?RRRRRR?333333?RRRRRR?rrrrrr???ZZZZZZ?ۛ???ښ???ٙ?\\\\\\??000000??000000???]]]]]]?ޞ??PPPPPP?PPPPPP?pppppp??ޞ??222222?RRRRRR??㓓?㳳?㳳???ssssss?SSSSSS?㓓?ssssss?ssssss?333333???⒒?Ⲳ?rrrrrr?222222???000000???ܜ?]]]]]]?^^^^^^????000000??^^^^^^???______?PPPPPP?ర??ర?______?ߟ?ݝ???????ٙ?ٙ???[[[[[[????]]]]]]???ۛ?֖???֖???А???QQQQQQ?TTTTTT??SSSSSS?ё?TTTTTT?ӓ??????UUUUUU?VVVVVV??????VVVVVV???ښ?ؘ??ϟ??А?ϟ?Ξ?͝????Ǘ????Ɩ?’??’?’??ϟ??Ó?????Ó???Ó????Ó???SSSSSS??Ғ?RRRRRR????ŕ??Ó??Ó???Ǘ?????????’?Ɩ??Ǘ??Ǘ??ŕ????????ϟ?Ξ??Ғ?????RRRRRR?ё?SSSSSS??ח???RRRRRR?ё??ё?ё?RRRRRR?RRRRRR?????Ξ??͝?ϟ??ӓ?А?А?QQQQQQ??RRRRRR?SSSSSS???ϟ?ё?TTTTTT??QQQQQQ?SSSSSS?Ԕ?UUUUUU?UUUUUU?TTTTTT??VVVVVV?[[[[[[????ܜ?ߟ???ߟ????______??֖?ܜ??ZZZZZZ?]]]]]]?[[[[[[??ߟ?pppppp?ߟ?ర?pppppp?ర????111111???PPPPPP?ᑑ??RRRRRR?Ⲳ???SSSSSS?333333??SSSSSS??333333??Ⲳ?⒒?rrrrrr??222222?RRRRRR???PPPPPP??PPPPPP??YYYYYY??\\\\\\?000000??????ޞ????ߟ??______???______?ݝ??ZZZZZZ?ܜ?ٙ?XXXXXX?ٙ?ښ?[[[[[[?ZZZZZZ??[[[[[[?^^^^^^?XXXXXX?????SSSSSS????А????????QQQQQQ?RRRRRR?QQQQQQ?Ғ??ӓ?ӓ?RRRRRR??WWWWWW?ؘ?????ח?????ӓ???Ξ?Ξ?Ξ?͝??ʚ?ə?ʚ?Ș??Ɩ???’??Ĕ?’??Օ??ə?ŕ?Ó???’??????????????Ɩ?ŕ??Ĕ??’????????Ó??????????Ș?Ɩ?????ʚ???˛??ϟ??????RRRRRR??Ғ???֖?ח?UUUUUU?ӓ?Ғ?PPPPPP??Ԕ??Ғ???PPPPPP?ϟ?ё???Ξ?͝??PPPPPP??PPPPPP?ё?Ғ???SSSSSS??PPPPPP?˛?SSSSSS?????Օ?TTTTTT??ٙ???ZZZZZZ??ښ?????ښ?UUUUUU???222222??Օ?ܜ?\\\\\\???ۛ??????pppppp?111111??PPPPPP?ర?ర?ᑑ?RRRRRR?______?PPPPPP?qqqqqq??ᱱ?222222?Ⲳ???rrrrrr?⒒?RRRRRR??⒒?222222??????ᑑ???ޞ???\\\\\\???______?ߟ?ޞ?ޞ?000000?ᑑ?______?^^^^^^??ݝ?______??ޞ?ޞ??^^^^^^???????ܜ?ZZZZZZ??ܜ?\\\\\\????ܜ??XXXXXX??Ғ?ё?А??̜??ϟ?ϟ?????TTTTTT?Ғ?TTTTTT?SSSSSS???TTTTTT??TTTTTT??֖?VVVVVV?????֖???YYYYYY?Ԕ?А??????ʚ???ʚ?????’????Ó?Ó?Ĕ?TTTTTT?ə?’?’??’?’?Ó????Ó??Ó?Ĕ??ŕ?Ξ?Ș?Ó?Ó???’??Ó??’?Ó?????’?Ɩ?’???Ξ??ŕ?ə??Ó????Ǘ???̜???RRRRRR??]]]]]]?UUUUUU?ϟ?Ԕ?ϟ???UUUUUU???ؘ?֖?TTTTTT???RRRRRR?RRRRRR?Ԕ?ӓ?????XXXXXX?ϟ?ʚ???͝?PPPPPP?RRRRRR?А?SSSSSS??????QQQQQQ??Ǘ?Ɩ?Ș?ϟ??UUUUUU???Օ???ZZZZZZ???]]]]]]??֖?VVVVVV?????ZZZZZZ?????ۛ?ۛ?ښ?\\\\\\??______???ర?ర?QQQQQQ?ర?000000?ߟ?______?ర??]]]]]]??111111?ᑑ?qqqqqq???rrrrrr?SSSSSS??⒒?rrrrrr?RRRRRR?RRRRRR??ᱱ??ᑑ?ᑑ??QQQQQQ??ߟ?______????PPPPPP??______??]]]]]]???______??^^^^^^?????ర??????ٙ???\\\\\\?ښ?[[[[[[?]]]]]]??ݝ?[[[[[[?ZZZZZZ?ܜ????Օ??QQQQQQ??͝?ϟ?????ё?TTTTTT?Օ?Ԕ?ӓ?ӓ?Ғ??ё?Ғ?Ԕ?Ԕ?ӓ?Ԕ???UUUUUU??WWWWWW?֖??ٙ?ٙ??Ξ???А??˛??Ș?Ș?ə?Ǘ?ŕ?ŕ??????Ó?’????????Ɩ???ŕ?Ó???Ó?Ĕ?’???Ĕ?ə?????Ĕ?????’???Ĕ????????Ǘ?ʚ?Ș?Ĕ??PPPPPP??Ǘ?Ĕ?̜???VVVVVV?Ԕ??ё??А?͝?˛??֖????֖?WWWWWW???ӓ?RRRRRR??Ғ?TTTTTT?Ғ?А???˛?˛?˛??ϟ??PPPPPP?????RRRRRR??????Ɩ????UUUUUU??UUUUUU??Ғ??YYYYYY?^^^^^^?pppppp??PPPPPP?????XXXXXX?ۛ???WWWWWW?ӓ????\\\\\\??ޞ?000000??QQQQQQ??QQQQQQ?ᑑ??ర????ర?111111????______??QQQQQQ?ᑑ?ᱱ?⒒?444444?⒒?222222?222222?⒒?????PPPPPP?PPPPPP??ߟ??______?ޞ?ޞ??000000???ݝ?ޞ??ߟ?^^^^^^?ߟ?]]]]]]?????RRRRRR?ssssss???ZZZZZZ??YYYYYY?YYYYYY???^^^^^^?ޞ??[[[[[[???[[[[[[??ח?UUUUUU?ӓ??ё?А???VVVVVV???ё??SSSSSS??Օ?TTTTTT?????ё?TTTTTT?TTTTTT??Ԕ??ښ?֖?VVVVVV?WWWWWW?VVVVVV?֖?????Ξ????̜???ə??ə?ʚ??Ɩ??ŕ?’?????????ŕ??Ó?Ǘ??ŕ??????’?Ɩ??????Ĕ?Ș?ŕ???’??’??’?’?Ó?ŕ??Ó????????Ó?Ĕ??Ɩ?Ĕ?Ɩ?ə?Ș?ʚ?Ș??Ξ?QQQQQQ????PPPPPP?UUUUUU?VVVVVV??XXXXXX?WWWWWW??ٙ???Ԕ???QQQQQQ?QQQQQQ?QQQQQQ??Ξ?͝??͝???Ξ??ϟ??ё?А???????͝?Ɩ?Ɩ?ʚ?ё?RRRRRR???????^^^^^^???ݝ?ۛ??[[[[[[?ٙ???ё?Օ?WWWWWW?PPPPPP?ӓ?????ښ?______????qqqqqq??111111??______?000000??111111??ర??\\\\\\???ర??pppppp??????pppppp??????ښ?______?ߟ?ޞ???pppppp???ޞ????ޞ???ߟ?ޞ?]]]]]]?ݝ????]]]]]]????????[[[[[[?ۛ?ݝ?????XXXXXX?VVVVVV??QQQQQQ??PPPPPP??ё??QQQQQQ??Ԕ?UUUUUU?Ғ?SSSSSS????TTTTTT?RRRRRR??Ғ???ӓ?TTTTTT?Ԕ??֖????WWWWWW??UUUUUU?Օ???А?PPPPPP?Ξ?ʚ?ə?Ș?ʚ?Ș??Ǘ?Ș?Ǘ?Ĕ????ʚ???????Ĕ???Ǘ??Ĕ????Ɩ?Ǘ?Ó??Ó?Ó?????Ó?Ó?Ĕ?Ɩ?’??Ó?’?Ó??????Ó????????Ĕ??͝?Ó?Ǘ??’????Ĕ???PPPPPP?̜?̜??˛???[[[[[[???֖?????RRRRRR??ё?А???ϟ?????Ξ?Ξ???Ξ????????????̜??????֖??^^^^^^???VVVVVV?ZZZZZZ??????UUUUUU????????ښ?ؘ??ޞ?ᱱ?QQQQQQ?QQQQQQ?RRRRRR?QQQQQQ?pppppp?000000?ޞ??pppppp?pppppp?ర?pppppp???ܜ???000000??ޞ?^^^^^^?ݝ?ޞ??????ߟ?]]]]]]????ߟ??????000000?^^^^^^?^^^^^^??______?ޞ??ޞ??000000?^^^^^^???\\\\\\?ښ?\\\\\\?ݝ?ۛ?ښ???ۛ??ۛ??ݝ??ؘ?ח?ח?ח?Ԕ??ё?ё?RRRRRR?QQQQQQ?QQQQQQ?ё?RRRRRR??Ғ????????TTTTTT??Ғ????????ח???Ԕ????ӓ?͝??˛?̜?ə?ə?ə?ə?ə?Ș??̜?Ǘ??????’?Ĕ?Ĕ?Ó??ŕ??Ó?ŕ?Ș?Ș????’?’??ŕ??’????Ǘ?Ș?????ŕ???????Ó???????????Ĕ?Ɩ?Ĕ?Ĕ?Ó????Ĕ?Ɩ??????͝?̜?Ғ?ӓ?UUUUUU??????SSSSSS?????ё??PPPPPP???Ș?͝???͝?ϟ??Ξ?RRRRRR??SSSSSS???ё?А?ϟ?ӓ?̜?˛??Ξ??ZZZZZZ??Օ?֖?ٙ?ܜ???֖???ښ?ݝ?ښ??YYYYYY?ښ??Ԕ?ؘ?TTTTTT?UUUUUU??????ర?111111?RRRRRR?qqqqqq?qqqqqq??______?]]]]]]????ޞ?______??000000?PPPPPP?pppppp???^^^^^^??ర??pppppp????ߟ???ޞ????^^^^^^??______???ߟ??ޞ?pppppp?______??ݝ??000000?ర?000000?ݝ?ܜ?\\\\\\??ښ??ޞ?ܜ??ݝ?ܜ??ۛ?????[[[[[[??ח?Օ?Ғ??RRRRRR?????ё?TTTTTT???SSSSSS?SSSSSS?RRRRRR??Ғ????????Ԕ?UUUUUU???֖?WWWWWW?ח?Օ?VVVVVV?Ԕ?Ғ??Ξ?̜?ϟ??˛??˛?QQQQQQ?Ɩ??Ǘ??PPPPPP???’?ŕ???’???’?Ɩ??Ĕ?ŕ??Ĕ?’?Ó??????Ó?????????Ǘ?Ɩ?Ó??ŕ?Ó???Ó?Ĕ??????????’??ŕ?ŕ?Ǘ?Ó???Ɩ??Ǘ?????Ξ?ӓ???ח?XXXXXX?UUUUUU?YYYYYY??ښ?ٙ?ؘ?Ԕ?ӓ?ё?ё??ё?А??ӓ?˛?ə?˛?̜???Ξ??PPPPPP?PPPPPP?ϟ?ϟ?ё???PPPPPP??PPPPPP???Ǘ???ё??????YYYYYY???VVVVVV???ZZZZZZ??ܜ?ۛ?]]]]]]???ZZZZZZ?ۛ??ٙ??[[[[[[???PPPPPP?QQQQQQ??ᱱ?ᑑ??ర??PPPPPP?????000000?111111?000000?QQQQQQ?111111??pppppp?PPPPPP?ᱱ??PPPPPP?ర????[[[[[[??^^^^^^?ޞ?ݝ?ޞ?^^^^^^?ޞ?______????pppppp???111111???PPPPPP?ర?000000?000000???\\\\\\????\\\\\\?[[[[[[?ܜ??\\\\\\??[[[[[[?[[[[[[?????֖?Ғ??Ԕ?Օ?Ғ?Ғ??SSSSSS?Ғ??Ғ????RRRRRR??SSSSSS??VVVVVV??PPPPPP??Ԕ???UUUUUU?????VVVVVV??XXXXXX?ߟ????͝???͝?ə?ʚ???PPPPPP?Ǘ???ŕ?Ɩ?Ĕ??Ó??Ó?Ó???????’?Ĕ?̜?Ĕ??ʚ?ŕ??’??Ĕ?’?Ó?’?’??Ĕ????Ș??Ǘ?ŕ?Ó????Ǘ????????Ĕ???????ŕ??ə?ŕ?Ǘ?Ǘ??Ș??˛?Ξ?TTTTTT?Ғ???TTTTTT?VVVVVV?֖?ؘ???ח??RRRRRR?Ғ??А?ё?А??͝??ʚ??͝?͝?͝?PPPPPP??А??RRRRRR???ё????ӓ???Ș????????\\\\\\?XXXXXX??֖?????[[[[[[??\\\\\\?ZZZZZZ???ᱱ?????[[[[[[?YYYYYY???QQQQQQ?111111?______?000000?????^^^^^^?000000??]]]]]]?pppppp?pppppp?pppppp?ᱱ?QQQQQQ?pppppp?111111?000000?PPPPPP?pppppp?000000?______?000000????ۛ?????ޞ?000000???????ߟ?ݝ?ޞ?qqqqqq?PPPPPP??]]]]]]?ݝ?\\\\\\?YYYYYY?ښ?ZZZZZZ?ښ??ݝ???ܜ?ޞ???[[[[[[?ZZZZZZ???YYYYYY??VVVVVV?Ԕ??ؘ??ё?ё?UUUUUU???ё??ӓ??RRRRRR???Ԕ????RRRRRR??????Օ???????ח??˛??˛???ʚ??ə?Ǘ?͝???ŕ?Ĕ??Ó?Ó????????’??Ĕ?Ĕ?Ó?’?Ó??ŕ??ŕ??TTTTTT?????????Ó?Ó?Ó?Ó?RRRRRR?????˛?ZZZZZZ???’????????Ǘ?Ĕ???Ĕ??͝??Ǘ??Ș?ʚ?̜??Ξ?Ғ?ӓ?????ٙ??YYYYYY???Օ?Ғ?PPPPPP?PPPPPP????ё???̜????̜??ϟ???ϟ????SSSSSS?ё???̜?͝???PPPPPP??TTTTTT???WWWWWW?ٙ?ח??ۛ??ۛ??????ۛ??555555??ݝ?ٙ?[[[[[[?[[[[[[???[[[[[[??ߟ?]]]]]]??______??000000?000000?ర?]]]]]]?ߟ?^^^^^^?????______?ᱱ??ᑑ??pppppp?qqqqqq?QQQQQQ??ߟ??ᱱ?pppppp?ݝ???????pppppp?ޞ?pppppp?ߟ???[[[[[[?]]]]]]???]]]]]]?ݝ?ᑑ?]]]]]]?ܜ?ۛ?ZZZZZZ?YYYYYY?ZZZZZZ??ۛ?ۛ????\\\\\\??YYYYYY???ښ?YYYYYY???Ԕ?Ԕ??Ԕ?UUUUUU?Ғ?ё??SSSSSS?Ԕ?SSSSSS?TTTTTT??TTTTTT?TTTTTT?????ۛ???Օ?Ԕ?UUUUUU?YYYYYY?ח??UUUUUU???ӓ???PPPPPP?PPPPPP???ӓ?Ș????ə?Ș??[[[[[[?͝??Ɩ?Ĕ?Ĕ?Ó????’????ŕ?Ɩ?????Ɩ?????Ĕ?ə?˛????????’?’????????ϟ?̜?Ó????????Ó??Ĕ????Ɩ?Ǘ?Ĕ???˛????????SSSSSS????ܜ?????Օ??Ғ?PPPPPP?ӓ??RRRRRR?Ξ?А???͝?͝?Ξ??͝?PPPPPP????Ξ???А?ϟ????ʚ?̜?QQQQQQ?ښ????VVVVVV?ٙ?֖?ٙ???ښ??\\\\\\?ښ?ښ??ٙ?^^^^^^?111111?444444?]]]]]]?XXXXXX????pppppp??ܜ?PPPPPP??ర??QQQQQQ?rrrrrr??\\\\\\?ܜ???ݝ?ݝ??ߟ?ܜ?000000?111111?Ⲳ??RRRRRR???000000?000000??pppppp???]]]]]]?ޞ???000000?ߟ?ޞ????\\\\\\?]]]]]]?^^^^^^?ޞ????^^^^^^????[[[[[[?ZZZZZZ?ښ?ZZZZZZ?ٙ?\\\\\\???\\\\\\?______?ZZZZZZ???YYYYYY??000000???????Ғ?UUUUUU?Ғ??SSSSSS?SSSSSS???TTTTTT?SSSSSS?Ԕ??SSSSSS???Ԕ??RRRRRR???ӓ??VVVVVV?Օ?UUUUUU?Ԕ??ӓ??????Ξ??ё?˛?ʚ?ʚ??Ș??Ԕ????ŕ?Ó??’???Ĕ?Ɩ???ŕ??Ó???ʚ?Ǘ?Ɩ??ʚ???Ĕ??ʚ??’????????????’??Ș?????????????????Ĕ?ə?????Ș?ə?͝???Ԕ??SSSSSS??ۛ?ߟ?ښ??֖????TTTTTT?͝????RRRRRR??Ξ??̜????Ξ??PPPPPP????PPPPPP?А??А??͝??̜?͝???Ξ???VVVVVV??XXXXXX?ښ???[[[[[[?ښ????ZZZZZZ???ZZZZZZ?ߟ?000000?ܜ??ᑑ??ZZZZZZ?ܜ??ݝ??????qqqqqq?______??^^^^^^?pppppp??ܜ??______?pppppp??ߟ?PPPPPP?ర?ᑑ???㓓???000000?______???ݝ?^^^^^^??ܜ?[[[[[[?ۛ??\\\\\\?^^^^^^??ݝ?^^^^^^?PPPPPP?SSSSSS??^^^^^^?????\\\\\\????ۛ??[[[[[[?????ۛ?YYYYYY???XXXXXX???Օ??TTTTTT???SSSSSS???TTTTTT?VVVVVV?UUUUUU?UUUUUU?Օ????????QQQQQQ????VVVVVV?֖?VVVVVV???Օ????А??͝?Ξ?????̜??????Ғ????Ɩ??Ǘ??ŕ????Ó???’?????ə??Ǘ??ə??Ĕ??????????Ĕ????????????????Ó?????Ó???????ŕ?Ɩ???ʚ??ӓ??SSSSSS?ӓ?֖?VVVVVV???ۛ?ܜ?ۛ?????˛?QQQQQQ?Ғ????ӓ?ϟ??͝????PPPPPP??ϟ??ϟ??QQQQQQ??PPPPPP?А?ϟ????̜??ʚ??RRRRRR???ח?????????[[[[[[??ܜ?[[[[[[?????XXXXXX?ZZZZZZ???ZZZZZZ??ߟ?pppppp?^^^^^^??ߟ?000000???QQQQQQ???000000??______?000000?ߟ?______???000000?ర???qqqqqq???\\\\\\??ۛ???????ߟ???^^^^^^?PPPPPP??000000?pppppp??ݝ???ܜ??\\\\\\??ZZZZZZ??ۛ????]]]]]]?ۛ?YYYYYY?XXXXXX?ؘ??ח??ח?VVVVVV?VVVVVV?UUUUUU??SSSSSS???ё????֖???Ԕ?ё?ё??ё?А??Ԕ?SSSSSS??WWWWWW?????֖?Ԕ?UUUUUU??RRRRRR??͝?̜?̜?ʚ?̜??????˛?QQQQQQ??QQQQQQ?????Ș????????’????ŕ??ϟ?Ș???Ξ???’???????????????ŕ?’?????????Ĕ?????’?Ĕ????’??Ó???PPPPPP???QQQQQQ?А?̜?͝?PPPPPP??ښ?ZZZZZZ??嵵?333333??^^^^^^???PPPPPP???ח???QQQQQQ?ё?Ԕ??????PPPPPP??PPPPPP???PPPPPP??QQQQQQ?͝???А?ϟ??ʚ?ʚ??????ח??______?ܜ?ZZZZZZ?ܜ??ۛ?ܜ??ݝ?]]]]]]??ۛ?000000??Օ?֖?ZZZZZZ??WWWWWW??\\\\\\??ᱱ?ᑑ?䴴?ᱱ?PPPPPP?ݝ????ᑑ?ᑑ?PPPPPP?????000000?000000?PPPPPP?111111?ᱱ???ssssss?ᑑ???______????111111?______?______????ߟ?ߟ??ߟ?______????^^^^^^???ܜ??ښ?[[[[[[?\\\\\\?ݝ?[[[[[[??ۛ?????ח?WWWWWW???YYYYYY?Օ?Ԕ????ӓ?SSSSSS??ӓ?TTTTTT?ח??TTTTTT?SSSSSS??QQQQQQ?Ғ?UUUUUU?ӓ?UUUUUU?VVVVVV?Օ?VVVVVV?ח?ؘ?ٙ??VVVVVV??????TTTTTT??˛?̜?Ξ?Ξ???QQQQQQ??̜????????Ɩ??Ĕ?’?’?????’?’??Ó?Ĕ?Ș??ʚ?˛??Ș????????ŕ??’???Ó?Ș???????????????’?PPPPPP?ё???ʚ?Ó?????ϟ?ŕ?ʚ??Ξ??͝?˛???????㳳?444444?㓓?222222????ϟ?ʚ??VVVVVV?TTTTTT?RRRRRR?Ғ?SSSSSS?ё?Ξ?͝???͝?PPPPPP?Ξ?QQQQQQ?А???PPPPPP??Ξ???̜?ϟ?ϟ?̜???͝?QQQQQQ???SSSSSS???ݝ??ۛ??]]]]]]?]]]]]]?WWWWWW?ZZZZZZ?????XXXXXX??ח?ۛ?ZZZZZZ?WWWWWW?ٙ?ښ??ᑑ?pppppp?pppppp?333333?ᱱ?PPPPPP??ޞ?^^^^^^?pppppp??000000??PPPPPP?qqqqqq??PPPPPP?????rrrrrr?333333???______?pppppp?000000??\\\\\\??______?000000??111111?qqqqqq??????^^^^^^?ݝ??______?ޞ?111111?^^^^^^?ܜ?ۛ?[[[[[[?[[[[[[?????[[[[[[?ښ??ח?WWWWWW?XXXXXX??WWWWWW??֖?VVVVVV?ӓ????????SSSSSS??VVVVVV??????Օ?TTTTTT??????ؘ?XXXXXX?ؘ??Օ?TTTTTT?WWWWWW???QQQQQQ????ё???ח??]]]]]]???Ғ?YYYYYY??Ξ?????Ĕ??????’???Ĕ?Ɩ?ə???Ɩ?Ș??ŕ??ŕ??’?Ĕ?Ǘ????Ĕ?ŕ?Ó??Ó????????ŕ?͝??Ó????Ĕ?Ĕ??????’????Ș????̜?͝?????QQQQQQ???SSSSSS??qqqqqq?ښ?ۛ????͝???????Ԕ?PPPPPP????????Ξ???Ғ?ϟ?Ξ?ϟ?А???PPPPPP??ϟ?ϟ???Ғ?SSSSSS??ӓ?ښ???ؘ?ٙ??ݝ?㓓?ᱱ?000000??111111?rrrrrr?333333?????ర?RRRRRR?ۛ???ߟ?______?^^^^^^?000000?PPPPPP?000000??ޞ?ݝ??^^^^^^?000000?ᑑ???????ర?ᑑ???ర?qqqqqq?qqqqqq?111111?000000?⒒??ߟ?ర?pppppp?111111???ᱱ??000000?______?^^^^^^?????______?^^^^^^?ޞ?^^^^^^??^^^^^^?ܜ???\\\\\\?????ٙ??YYYYYY?ܜ???TTTTTT??VVVVVV??ӓ???RRRRRR?Ԕ?SSSSSS?SSSSSS?SSSSSS???RRRRRR?Ԕ???TTTTTT?Ԕ??VVVVVV??Ԕ???֖?VVVVVV??ݝ??ӓ??А?ϟ?˛???QQQQQQ??ϟ???333333?SSSSSS?VVVVVV?XXXXXX???ʚ?ʚ??Ɩ??’????Ó?Ó?’?Ó??Ĕ?????ŕ?????Ó??ŕ?Ó????’??’?Ĕ?’???’???????????’?Ó??????????????????RRRRRR???ə?ϟ?ϟ??TTTTTT?ܜ???UUUUUU?SSSSSS??͝?ϟ??ϟ?PPPPPP??????Ξ??PPPPPP?Ғ?ё???PPPPPP?А?А?А??ϟ?ϟ??˛?PPPPPP??͝?А??͝???RRRRRR??YYYYYY??Ⲳ?]]]]]]?Օ?ښ?]]]]]]??tttttt?666666??QQQQQQ?ᑑ?______????ۛ???\\\\\\????ޞ???111111?PPPPPP????ܜ?ܜ??]]]]]]?pppppp???QQQQQQ??ర?QQQQQQ?RRRRRR?ߟ?ర?000000??QQQQQQ??QQQQQQ?pppppp?ᑑ?pppppp?pppppp?pppppp?⒒?ర??RRRRRR?rrrrrr??pppppp?qqqqqq?????ߟ??]]]]]]??ޞ??ߟ?ښ??RRRRRR?ᱱ???______????ర?YYYYYY?Օ?????????Ғ?UUUUUU?ӓ??RRRRRR??VVVVVV?WWWWWW????UUUUUU????YYYYYY??WWWWWW??VVVVVV???[[[[[[??ӓ??ؘ?????SSSSSS?PPPPPP??????QQQQQQ?333333??Օ?ӓ?˛?Ɩ?ŕ??Ó?Ó??Ó??????WWWWWW?ə?Ó?Ó?ŕ?Ĕ??Ó?ə?Ș??????ŕ?ŕ?’??Ĕ?Ș????’?’??ʚ??Ó?????ə????????????????˛?Ș?ə?͝????͝??˛?????????Ξ??ϟ?Ξ?̜?QQQQQQ?PPPPPP??͝????ϟ??ӓ??͝??UUUUUU?????͝??͝?̜??˛?ʚ??͝??ӓ?VVVVVV?Օ?WWWWWW??ܜ?ٙ?XXXXXX??ܜ??ߟ?ߟ??QQQQQQ????ۛ??ۛ?ܜ?ܜ???\\\\\\?^^^^^^?111111?ޞ??ښ???ܜ?]]]]]]?ܜ?ݝ????????PPPPPP?000000?PPPPPP?111111??rrrrrr?ᑑ?ߟ?PPPPPP??pppppp???ᱱ?pppppp????111111?ᱱ??PPPPPP???pppppp?PPPPPP???pppppp?ޞ??ۛ????\\\\\\?䔔??ᱱ????ח??[[[[[[??VVVVVV?VVVVVV?Ԕ?UUUUUU?TTTTTT????????ӓ?Ғ?ӓ?Ԕ?֖??֖??VVVVVV?VVVVVV???YYYYYY???ٙ??????QQQQQQ?PPPPPP??QQQQQQ??????˛??˛?QQQQQQ?ٙ?????ŕ??’????’??Ó?Ǘ???Ĕ?ŕ??Ɩ?Ó??Ó?????ʚ?ŕ??ŕ???ʚ??’???ŕ?????????ŕ?’???Ĕ???’?????ʚ???????Ɩ????ʚ??ʚ?А?RRRRRR??WWWWWW?????ؘ????????QQQQQQ???Ξ??Ξ?̜??˛???Ξ??͝?Ξ??̜??͝??QQQQQQ??Ξ?̜?PPPPPP?͝?ϟ??̜??ё???֖??WWWWWW?ZZZZZZ?ۛ?ߟ????ٙ?\\\\\\????SSSSSS?????QQQQQQ??ݝ?ܜ???______???ؘ??ݝ?ۛ??]]]]]]?ޞ???^^^^^^?????pppppp?ߟ?ᑑ?Ⲳ?Ⲳ?ᱱ??qqqqqq????111111??⒒??ᱱ????PPPPPP???______?Ⲳ??ߟ??\\\\\\?^^^^^^????[[[[[[?[[[[[[?ܜ??ܜ?ᱱ?ZZZZZZ??[[[[[[??ח?ח?WWWWWW???Ԕ??SSSSSS??Ғ??ё???RRRRRR?SSSSSS?????ښ???VVVVVV????Օ?Օ????ӓ?Ғ?UUUUUU?YYYYYY??ϟ?А???Ξ??ё??PPPPPP??˛?SSSSSS???˛?͝??Ɩ?Ǘ?ŕ?’??Ó??Ó??Ĕ?ŕ????ŕ????Ó?ŕ?’?Ó?????Ó??Ǘ?’?????ə??’???????͝?ə??Ǘ??Ĕ??SSSSSS??Ó?????????Ĕ??Ǘ???ə???А??֖?RRRRRR?ܜ?Օ??ӓ?Ԕ?ϟ?ё??Ғ????SSSSSS?QQQQQQ?PPPPPP?Ș?Ǘ?ə?Ξ?PPPPPP?????Ξ?Ξ?ё??̜??????Ξ????PPPPPP?͝?˛??ё??TTTTTT????ޞ??^^^^^^?\\\\\\??ZZZZZZ?ٙ?UUUUUU?RRRRRR??\\\\\\?ӓ???[[[[[[??ޞ?QQQQQQ??????______?______?[[[[[[?ܜ???ۛ?______??ޞ?^^^^^^??^^^^^^?111111?______???000000?PPPPPP?qqqqqq?ᱱ??111111?⒒?111111???000000?ޞ????pppppp???ޞ??]]]]]]???^^^^^^?PPPPPP?\\\\\\???[[[[[[????]]]]]]??ٙ???ٙ?YYYYYY????֖?Ԕ?Օ?Ғ??ӓ??Ғ?ӓ???Ԕ?ӓ?RRRRRR?Ғ?SSSSSS???VVVVVV?WWWWWW???XXXXXX?֖?ח??VVVVVV?VVVVVV?֖?UUUUUU?ӓ??RRRRRR???PPPPPP?Ξ???ϟ?ӓ????QQQQQQ???ϟ?͝?Ǘ?ʚ??ϟ???ŕ?’???Ó??Ǘ????’?ŕ?Ó?Ó?Ó????Ĕ???’??????Ԕ?̜?Ó?ŕ??Ǘ???Ǘ???’??????ʚ????䴴?А?????????ə?PPPPPP?Ș??Ș?ə??̜?Ξ?Օ????ޞ???VVVVVV?Ғ?TTTTTT???QQQQQQ????QQQQQQ?SSSSSS?Օ?͝?͝???̜?ϟ??Ξ??̜??QQQQQQ???̜???ё?Ғ??̜?А??̜?˛?̜?Ξ?QQQQQQ??VVVVVV?]]]]]]?ߟ?]]]]]]??ZZZZZZ??[[[[[[?ܜ?ߟ???SSSSSS??֖?TTTTTT?QQQQQQ??ח?ᑑ????XXXXXX?YYYYYY?[[[[[[?[[[[[[????ߟ??ݝ??ߟ??______?______??ޞ??000000?111111?????000000?pppppp??______?______?ߟ?]]]]]]?ݝ??[[[[[[?ۛ??\\\\\\?]]]]]]??ߟ??\\\\\\?[[[[[[?111111?ర?ݝ?ښ?????ۛ??\\\\\\?\\\\\\?ޞ?ۛ?ٙ?WWWWWW?ٙ???ӓ??UUUUUU????ё?SSSSSS?Ԕ?ӓ?[[[[[[?UUUUUU???Ғ???UUUUUU??WWWWWW??XXXXXX????ח?ח???UUUUUU??Օ?Ғ??PPPPPP?А?Ξ?̜?˛??͝???ϟ?????ϟ?˛?Ǘ?Ǘ??Ɩ?????’??Ɩ???Ó?Ĕ?Ĕ??Ĕ?Ó????’?’?Ĕ????Ĕ?’?Ĕ????Ɩ?Ǘ??ŕ?̜?ŕ??????Ĕ?Ó???Ó?????ё???????????͝?Ǘ?Ǘ?Ǘ???͝?SSSSSS?QQQQQQ?RRRRRR??Ғ?^^^^^^?֖??RRRRRR?RRRRRR?ӓ?TTTTTT?֖?֖??Ԕ?QQQQQQ????Ξ?̜??˛???????̜??̜???̜?ϟ??Ԕ???ϟ?PPPPPP??Ξ?̜?͝??ӓ???䔔??ݝ?ޞ?ؘ??ܜ????Օ????ϟ?RRRRRR????ߟ?WWWWWW??ښ?ZZZZZZ??ZZZZZZ?]]]]]]??222222?ܜ?ۛ???QQQQQQ????Ⲳ???222222??______??PPPPPP?______??ޞ????]]]]]]?^^^^^^?ܜ????ښ?ݝ?______??????ర?[[[[[[?[[[[[[???ٙ??????????VVVVVV?VVVVVV?Ғ??PPPPPP?????Ғ?SSSSSS??ӓ?Օ???SSSSSS??RRRRRR??Ԕ?VVVVVV????????Օ??֖?UUUUUU????????˛?̜????ϟ??ə?Ξ??Ғ???ŕ????Ó????Ó??ŕ??Ó?Ĕ???????’????’???˛??Ó???˛?Ɩ??Ɩ?Ó??ʚ?????Ș??Ó??????????????????Ǘ?????Ɩ??Ԕ??Ξ??PPPPPP?QQQQQQ??RRRRRR?ӓ??Ғ?ё?Օ?Ԕ???ё?PPPPPP?Ξ?͝??А??Ɩ?ə??А?ϟ??UUUUUU?А??˛?͝?˛??˛??ϟ?̜?͝????Ξ??Ξ?Ғ??PPPPPP??ӓ????\\\\\\?Օ???\\\\\\?ݝ?ݝ??ۛ???ӓ?XXXXXX???VVVVVV??YYYYYY?\\\\\\?[[[[[[??ח?????]]]]]]????______??ܜ??^^^^^^????111111???PPPPPP?ᱱ?ߟ??^^^^^^?ݝ?^^^^^^?______?ܜ????ZZZZZZ????????[[[[[[???????XXXXXX?ח?֖????UUUUUU?Ԕ???ח?Ԕ?ӓ?RRRRRR??RRRRRR????А????Ԕ??UUUUUU?Ԕ??UUUUUU???VVVVVV????֖????UUUUUU????RRRRRR??ё?QQQQQQ??ϟ????˛???Ξ?͝???YYYYYY?̜?ؘ?Ĕ?ŕ?ŕ????ŕ??Ó?????Ĕ?’?ŕ?ŕ?Ĕ????’?Ó??ŕ????ϟ???Ó??’?˛?ə?ə??’?Ș????????????????????????????͝?ŕ?Ɩ?Ɩ?˛???͝?А??А??Ғ??Ғ?RRRRRR?UUUUUU?SSSSSS??Օ?RRRRRR???RRRRRR?А??Ș??ʚ??PPPPPP??͝??Ξ???Ξ??ϟ?????ʚ?ʚ?????Ξ????ϟ??ӓ?ర??ח?TTTTTT?֖??ۛ??????PPPPPP?ӓ??֖?֖?????ؘ?ۛ?????ח?\\\\\\?\\\\\\?ܜ?ݝ?^^^^^^?000000??ర??000000????????ᑑ???ߟ?ۛ?[[[[[[?\\\\\\???ښ??ښ?[[[[[[??????XXXXXX?ؘ??ۛ?ٙ?WWWWWW???֖????WWWWWW?VVVVVV?XXXXXX???ӓ????SSSSSS??Ғ?ё??QQQQQQ????UUUUUU?֖??XXXXXX??VVVVVV?VVVVVV?WWWWWW????XXXXXX??ؘ?ZZZZZZ??Ԕ?????QQQQQQ?ϟ?Ξ??ϟ?͝??Ξ?̜??ϟ?ϟ?А?Ș????Ĕ??Ɩ??Ξ?Ɩ???Ǘ??Ĕ?ŕ?ŕ?Ó?Ĕ????Ó?????’??˛?Ó??’???????’??Ĕ?Ș?Ɩ?Ǘ??Ó??????????????͝?????????????Ĕ?ŕ?Ĕ??ə??PPPPPP??Օ?PPPPPP?RRRRRR????RRRRRR?RRRRRR??TTTTTT??ӓ??֖?QQQQQQ?RRRRRR???Ɩ?Ș???˛???˛?˛?˛?̜?͝???̜?̜?ʚ???͝?????Ξ?̜?͝???SSSSSS?[[[[[[?YYYYYY?Օ????[[[[[[?[[[[[[?ܜ?PPPPPP?[[[[[[?RRRRRR?PPPPPP?ݝ?ؘ?ښ?WWWWWW??YYYYYY?]]]]]]???YYYYYY???ϟ?Ԕ?Օ??ZZZZZZ???]]]]]]??ݝ?______???ޞ?ݝ???ర??\\\\\\????ښ?ښ???ZZZZZZ?YYYYYY?[[[[[[??ښ??[[[[[[?]]]]]]????ۛ??ۛ?WWWWWW??YYYYYY?ܜ???TTTTTT?Օ??????SSSSSS??ӓ?Ԕ??SSSSSS?TTTTTT??Օ??SSSSSS?RRRRRR?ӓ??Ԕ?ӓ????ؘ???????WWWWWW?֖?֖?Օ?YYYYYY??ӓ?PPPPPP???͝?PPPPPP??Ξ?̜?ϟ??PPPPPP??ʚ??˛?Ș?Ș???????ŕ?Ĕ?ŕ?Ĕ??Ɩ??ə??Ĕ?Ó??˛????Ó??Ó????Ǘ??Ș??????Ĕ?Ó???Ó??͝?’???????Ĕ?ə????????????????????Ĕ??Ξ????˛?ʚ??ə???PPPPPP?RRRRRR????TTTTTT??ZZZZZZ??^^^^^^?ߟ?000000?ё?Ĕ???Ǘ??ʚ?ё?Ξ?ə??̜???̜?Ξ??QQQQQQ???̜?͝?˛???Ξ??????RRRRRR??Ғ????XXXXXX?ۛ??????????ZZZZZZ????000000??????ё??Ԕ??ZZZZZZ?qqqqqq????[[[[[[?]]]]]]??^^^^^^?]]]]]]?^^^^^^????ؘ???[[[[[[?______????ٙ?XXXXXX?ٙ?ח??ؘ???QQQQQQ?ޞ??ښ??______?ؘ???VVVVVV??֖??TTTTTT????VVVVVV?TTTTTT?UUUUUU?SSSSSS????ח?Օ????Ԕ???ӓ?ؘ???WWWWWW?֖?WWWWWW?XXXXXX???WWWWWW?ח?XXXXXX?WWWWWW?WWWWWW?Օ?Օ??Օ?TTTTTT?А??ё?˛?ʚ?Ξ?????͝???Ǘ?????Ĕ??Ĕ????Ĕ?Ɩ?Ĕ?Ĕ?Ǘ?Ó??ʚ??Ĕ?????????????????????’??Ó?’?????’????????????SSSSSS?????????????????Ɩ??ё??ʚ??Ș??ϟ??А??????ߟ?[[[[[[?ח???Օ?ə??Ĕ??Ɩ???Ξ?͝??ə?˛??̜????˛?ə???ʚ??PPPPPP??͝???͝?QQQQQQ???ח?TTTTTT??WWWWWW??ٙ?ܜ?ޞ?[[[[[[?[[[[[[?ؘ?ח?ח?______?ޞ??ٙ?ٙ??????ח?֖?RRRRRR?А?SSSSSS?ח??ښ?֖??^^^^^^???^^^^^^??\\\\\\?ޞ???[[[[[[?YYYYYY??000000?[[[[[[?ٙ?ZZZZZZ?ZZZZZZ?ٙ??WWWWWW????VVVVVV??pppppp?ؘ?ח?UUUUUU????ؘ??VVVVVV?Օ?Օ?Օ??VVVVVV????ZZZZZZ?YYYYYY??UUUUUU?Ԕ??֖?֖?????UUUUUU?SSSSSS?Ғ?Ғ?ӓ?TTTTTT?[[[[[[?ח???ZZZZZZ?ח??ח??XXXXXX?WWWWWW?UUUUUU????RRRRRR???????ϟ????̜?̜?Ǘ??Ǘ?Ș?Ș?ə?Ș??Ș?Ș?Ǘ?ŕ?ʚ?Ó?ŕ??????ۛ??????’??’??’????????????˛?TTTTTT???Ɩ????Ó????????????Ó?QQQQQQ???????????????????̜?ϟ???˛??ϟ?ܜ?????ߟ?ޞ??XXXXXX?XXXXXX?XXXXXX?ؘ???Ș?Ɩ??Ó??̜????˛?????Ξ??͝?˛???ʚ?˛???ʚ?????RRRRRR???ӓ?Ғ??WWWWWW?ח????ۛ?ZZZZZZ?VVVVVV?Ԕ??TTTTTT?[[[[[[?????YYYYYY??XXXXXX??֖?֖???WWWWWW??VVVVVV?UUUUUU??ܜ??ٙ??ZZZZZZ??ۛ??^^^^^^?ۛ?ښ?ٙ??[[[[[[?ZZZZZZ?\\\\\\??ܜ???Օ??????TTTTTT?SSSSSS??WWWWWW?ٙ?Օ??֖?SSSSSS?ӓ??Ԕ??Ԕ?TTTTTT??TTTTTT???XXXXXX?VVVVVV?VVVVVV?VVVVVV?֖?UUUUUU?UUUUUU?????Ԕ??SSSSSS?TTTTTT???֖?WWWWWW??YYYYYY?ښ?WWWWWW???ؘ???RRRRRR??QQQQQQ??RRRRRR?ʚ?ə?˛?ʚ?ə???Ξ???ϟ??ə?ə????ə????ŕ???Ĕ?Ó??ŕ???ŕ?Ɩ???̜?ŕ???Ĕ??’????????????Ĕ?ϟ??Ĕ??Ó??Ș??Ó???????????????????????????????Ș?Ș??ʚ???̜?Ξ????Ғ?TTTTTT????Օ?ؘ??????ʚ??Ɩ?????ʚ???˛??̜??????????͝?????Ξ??SSSSSS?TTTTTT?TTTTTT???????ښ?ZZZZZZ????UUUUUU????YYYYYY?ח?ޞ?֖??ښ??ZZZZZZ???ښ?ח?VVVVVV?Ԕ????ܜ?ٙ??ۛ??WWWWWW?XXXXXX??[[[[[[??ٙ?ښ?ښ?ښ?pppppp?666666?ښ????֖?Օ?Ԕ??ӓ?TTTTTT???^^^^^^?VVVVVV???ӓ?SSSSSS?RRRRRR?֖?Ԕ????UUUUUU??UUUUUU?UUUUUU?????????SSSSSS??RRRRRR?Ғ?QQQQQQ??Ԕ???VVVVVV????ZZZZZZ?XXXXXX?WWWWWW?֖??Օ?ӓ?ё?PPPPPP?А???˛????ə??ϟ?ϟ????˛?˛??Ș?Ǘ?ŕ???Ș?ʚ?Ɩ??Ó?Ĕ?Ĕ?Ĕ?Ĕ?Ĕ?’??Ó???ё????Ó?Ó??’????????ŕ?Ó???ӓ?Ĕ??’??Ɩ?ʚ?Ĕ?ŕ??????????????????????????????ŕ??ŕ?Ș???ϟ?Ғ??ϟ??VVVVVV??????ٙ?VVVVVV?Օ??VVVVVV??̜?Ɩ??Ĕ?Ɩ?ŕ???ʚ?͝????˛?̜?ə????˛?????PPPPPP?˛??˛???Ғ?Օ?UUUUUU???RRRRRR?֖???ښ???XXXXXX???XXXXXX?VVVVVV???ٙ?ח??Ԕ??Օ?ח?ؘ????WWWWWW??RRRRRR???Օ???WWWWWW?ٙ?WWWWWW?ؘ??ٙ?????ښ?^^^^^^?PPPPPP?]]]]]]?\\\\\\?XXXXXX?ؘ??ח?VVVVVV??TTTTTT???UUUUUU???WWWWWW?ӓ??????VVVVVV?֖?֖???YYYYYY?WWWWWW?YYYYYY??ח?ٙ?WWWWWW?VVVVVV???UUUUUU?Օ?Օ??VVVVVV?TTTTTT???ח??ؘ?YYYYYY??ښ????TTTTTT???А?PPPPPP?ϟ?̜?PPPPPP?Ξ??˛??????̜??͝??QQQQQQ?ʚ?ʚ?ə?ŕ??Ǘ???ŕ?Ĕ??Ɩ?ə??????Ó???Ó?’?Ĕ??Ó??????????Ĕ??ŕ????ŕ??’?Ĕ?Ξ?Ó?Ó???????????????????????????????Ó?ŕ???ə??͝?RRRRRR?Ғ????TTTTTT?QQQQQQ??TTTTTT?ٙ????А?А?RRRRRR?А????ʚ?Ǘ?Ǘ?????Ǘ?ə??????ʚ?ʚ?ʚ??PPPPPP???ə??Ξ?ϟ??RRRRRR????????XXXXXX?YYYYYY?YYYYYY????WWWWWW??XXXXXX?WWWWWW???XXXXXX?ٙ??ח??[[[[[[?ۛ????UUUUUU??ё????Օ?Օ?WWWWWW??VVVVVV?XXXXXX?֖?YYYYYY??WWWWWW???ޞ??^^^^^^?______???????UUUUUU???VVVVVV??Ԕ?TTTTTT?TTTTTT?SSSSSS?ӓ?ח?UUUUUU?Օ??Ԕ??֖??????ؘ???????UUUUUU?Օ???XXXXXX??Ԕ??ZZZZZZ??֖?֖??ח?XXXXXX?TTTTTT??RRRRRR???PPPPPP?Ξ?͝??SSSSSS?Ξ?????ʚ??PPPPPP??ё?????ə??Ɩ?Ĕ?Ó??Ĕ?Ó?Ɩ????Ĕ???’??????????’??????????Ɩ?ŕ??’?Ó??ŕ?ŕ?ŕ?Ĕ??Ĕ???????????????????????Ĕ??????????ŕ?Ɩ??ё?͝???PPPPPP??Ԕ?RRRRRR??Ғ?ӓ?TTTTTT????PPPPPP???PPPPPP?PPPPPP?Ξ?̜??ə?TTTTTT?ə???˛?ə?????˛???Ș?ə??͝?͝??Ξ??PPPPPP?А?PPPPPP?RRRRRR?Ғ??RRRRRR????\\\\\\?ZZZZZZ???ٙ?ؘ???ח?VVVVVV??ח?VVVVVV?[[[[[[???ٙ?YYYYYY??______??Ғ?[[[[[[??]]]]]]?͝?Ғ??UUUUUU??֖???ח?VVVVVV?ח??XXXXXX???ZZZZZZ?______?\\\\\\????ؘ?WWWWWW?ӓ?TTTTTT??Օ?RRRRRR??ٙ??Օ?TTTTTT?Ғ??Ԕ?֖?ؘ??WWWWWW???ח???XXXXXX??ؘ???WWWWWW?VVVVVV??ܜ??????ZZZZZZ???YYYYYY?YYYYYY?֖??֖??ӓ????RRRRRR??А???ə?ʚ?ə???˛????Ș?͝????̜?PPPPPP??ə???Ǘ?Ɩ??Ĕ?ŕ??’??Ĕ???Ó???????’?’???Ó??Ɩ???????ŕ?̜?Ș?ϟ????Ș??????????Ĕ??Ó???Ǘ???????????????????Ó?Ĕ?????PPPPPP??ӓ?̜???Ғ?ӓ?Օ???Օ???֖??SSSSSS?Ғ??Ғ?PPPPPP?ё?????’??Ș?Ș?Ș?Ǘ??Ǘ????Ș?˛????̜???Ғ???ё?А?Օ??ё??ϟ?Ғ?ؘ?????YYYYYY??ٙ???ӓ?TTTTTT???[[[[[[??ZZZZZZ?ۛ?ښ?ח?UUUUUU?WWWWWW??ZZZZZZ???SSSSSS???ۛ?VVVVVV?SSSSSS??ZZZZZZ?֖??ח?YYYYYY?ؘ?ٙ?ؘ?ܜ?ۛ?^^^^^^??ؘ?ٙ?Օ??Ԕ???ӓ?______????UUUUUU????VVVVVV?ٙ?YYYYYY???YYYYYY???ח?ٙ??ZZZZZZ?ؘ??????ٙ???\\\\\\?YYYYYY???YYYYYY???XXXXXX?WWWWWW?Օ?TTTTTT?RRRRRR?????Ԕ?ӓ???˛??ʚ?Ǘ??Ξ?????????Ξ??˛???Ǘ???Ó?Ĕ?Ĕ?Ó?Ĕ?Ș???Ĕ??????’???Ó?Ĕ??’??’?Ĕ???????PPPPPP?͝??ŕ?˛?Ó??ʚ?Ó????Ó?’?????ə??????????????????????ŕ?’?Ó??ə?PPPPPP??ə???RRRRRR??ϟ?Օ?ё?А??Ғ??Օ?SSSSSS????ё??ӓ?ϟ??͝??˛????Ǘ?ʚ?????Ɩ?Ǘ?ʚ?Ș?ə?ə??˛???ʚ?А?ӓ?А?RRRRRR????TTTTTT?????ؘ?VVVVVV?ZZZZZZ???ܜ??֖??UUUUUU?SSSSSS?[[[[[[?ZZZZZZ?[[[[[[???ޞ?000000??ښ?UUUUUU??TTTTTT?֖???VVVVVV??RRRRRR?ё??ؘ??Ԕ???Ԕ?ӓ?ח?WWWWWW?XXXXXX?ښ?______?ߟ?ؘ?VVVVVV?UUUUUU?VVVVVV?UUUUUU????????ח?ח?VVVVVV????qqqqqq????ؘ??XXXXXX?ٙ?ٙ???XXXXXX?ؘ???ؘ??YYYYYY??YYYYYY?ٙ?ZZZZZZ?ۛ??ZZZZZZ????QQQQQQ?????UUUUUU?Ԕ?ӓ?QQQQQQ??ʚ??Ș????А?????̜??˛??Ș?ə??ə??Ɩ?ŕ??Ĕ?Ó??Ó??Ó??Ó?Ĕ?Ĕ??Ɩ????Ǘ???’???’???????Ɩ????Ó??Ɩ??ؘ?ŕ????Ó??????ӓ????????????????????????’??ŕ?Ǘ??ϟ?А?Ξ?ϟ??ϟ????ё?ޞ?Ғ???Ғ?Ԕ???VVVVVV????̜?А?ʚ?ə???Ĕ???Ɩ?Ǘ??Ǘ???Ș?˛?͝?ə?ə????ə?˛?͝??ё??SSSSSS?RRRRRR????TTTTTT??UUUUUU???ZZZZZZ?ٙ??UUUUUU?UUUUUU?А?͝?Օ???YYYYYY?PPPPPP??????UUUUUU?VVVVVV?WWWWWW??Օ????ё?Ԕ?֖?֖???VVVVVV???SSSSSS??֖?UUUUUU??YYYYYY?ٙ????VVVVVV?֖?WWWWWW?UUUUUU????VVVVVV??VVVVVV???ח?????ח??ח??ؘ??YYYYYY?YYYYYY?ח??????ZZZZZZ?ZZZZZZ???[[[[[[??ZZZZZZ??ؘ??VVVVVV??SSSSSS??SSSSSS?ё??Օ??Ғ????ə???ə??͝?ʚ??Ɩ?͝?͝?̜?˛?ə??˛?Ɩ??ŕ?Ɩ???ŕ????’????’??Ó?Ó??Ĕ??Ó?Ó???????????’???Ĕ????Ĕ??’??????????Ó???Ĕ???????????????????’???Ó?????????QQQQQQ?QQQQQQ?ӓ????Ԕ?PPPPPP???ӓ??ё??А?ϟ??͝?̜?SSSSSS?Ș?Ǘ????Ș??Ɩ??ə???ʚ?ʚ???ə?ʚ?ʚ?ə??ʚ??А?PPPPPP???ח?Ξ???SSSSSS??ח?YYYYYY?VVVVVV????Ғ??Ԕ??????ܜ??ݝ??PPPPPP??XXXXXX?ؘ?ٙ?֖?Ԕ?ӓ?ӓ?pppppp?ё?SSSSSS??WWWWWW?UUUUUU????????UUUUUU????ٙ?VVVVVV??VVVVVV????VVVVVV???ؘ?ؘ?ח??YYYYYY?WWWWWW??֖????֖?WWWWWW?XXXXXX?ؘ??XXXXXX?ښ?????ښ?ܜ?ۛ?\\\\\\???ٙ?ښ?ܜ??WWWWWW?XXXXXX?VVVVVV??????ё?SSSSSS?????ʚ??͝?????ʚ??Ș??̜???ʚ??Ș?Ș?Ǘ????Ɩ?Ș?Ĕ??Ĕ??????Ó?Ó???Ó??’???’?????Ĕ???’?Ɩ?Ș???ŕ???Ó?Ó??ӓ?ϟ?????????????????????????????????????͝????PPPPPP?ӓ?UUUUUU??SSSSSS???XXXXXX?Ғ???RRRRRR?ё?Ԕ?Ғ??͝?̜?͝?͝???ʚ?А???Ó?Ĕ?Ĕ??ə?˛?????˛?????ə???А?ϟ??QQQQQQ??QQQQQQ?˛??PPPPPP???VVVVVV?Ԕ??Ғ??WWWWWW?Օ???ё?Օ?ۛ?YYYYYY??ؘ???ؘ?VVVVVV????֖????TTTTTT?RRRRRR??ϟ??ӓ?UUUUUU?XXXXXX?VVVVVV?ؘ??VVVVVV??ӓ??֖?Ԕ??WWWWWW??ח?WWWWWW?WWWWWW?VVVVVV?WWWWWW?֖?ؘ?????VVVVVV?VVVVVV??֖?ח????XXXXXX?ٙ?YYYYYY?֖??YYYYYY?YYYYYY?ؘ??ܜ?ٙ?ښ??????ٙ??????TTTTTT?Ԕ???Ғ?ё??Օ??͝???̜??PPPPPP?ə?ʚ??̜??ə??̜?̜?PPPPPP?˛?ʚ????Օ???˛?Ғ?ŕ??Ó??’??Ĕ???’??????Ó??????’??Ș??Ó???????Ǘ??????????Ó???????????????????????????????ʚ?Ξ?А?̜??А?SSSSSS???ё???Ғ?RRRRRR?RRRRRR?QQQQQQ??ё??QQQQQQ?PPPPPP??ϟ?ϟ???̜?ؘ??Ĕ?’??Ĕ????Ǘ?ʚ?ə?ə??А?SSSSSS???Ξ?̜???Ξ?PPPPPP??QQQQQQ?̜???͝?????RRRRRR?RRRRRR??Օ?ښ?VVVVVV??ښ?RRRRRR?VVVVVV?TTTTTT????VVVVVV?Օ?RRRRRR??ӓ??WWWWWW??????Օ??ё????YYYYYY??ܜ?⒒??ח??XXXXXX??֖?֖?????ښ?֖????ؘ??XXXXXX?WWWWWW????ח?UUUUUU??????ח??\\\\\\?\\\\\\??ؘ???ܜ?\\\\\\?ښ?XXXXXX???ؘ??XXXXXX?______??ח?Օ??????Ԕ?ZZZZZZ?ϟ????͝?Ξ??ϟ??͝?̜??̜?ʚ????ё?͝?ʚ?̜?ʚ????????ŕ???’??Ș??Ó?’?’?’?Ĕ?ښ???Ó??’???’?Ó?Ș??Ĕ?’????’??’?Ɩ??Ǘ????ə???????????????????????????????Ĕ?Ĕ??Ș????????RRRRRR???Ԕ?TTTTTT??RRRRRR?QQQQQQ?Ԕ?Ξ?͝?PPPPPP??QQQQQQ?Ξ??Ș??А???Ș?Ó?’???Ǘ?Ǘ?Ș?Ǘ??ʚ??ʚ?˛?????ə????Ξ?Ξ?̜???ӓ???Ξ??ϟ??QQQQQQ????Ԕ?ޞ?Օ?YYYYYY?֖???WWWWWW??ؘ?Ԕ?SSSSSS?SSSSSS?TTTTTT??ח?Օ?Ԕ??VVVVVV??VVVVVV?֖???UUUUUU?WWWWWW?ݝ??ݝ????VVVVVV???ؘ??UUUUUU???????ٙ??ښ?[[[[[[?ؘ???ח??ZZZZZZ???ZZZZZZ?YYYYYY????[[[[[[??ښ?YYYYYY?^^^^^^?????ؘ??VVVVVV??ؘ?VVVVVV????\\\\\\?UUUUUU????Օ?UUUUUU?Ғ????XXXXXX??͝?̜?͝???????͝?Ξ?ё???Ξ?͝?Ɩ?ŕ??Ș?Ș?ŕ?Ɩ????????????’?’??Ó?Ĕ?’???’?????Ó???ŕ?’?’??????????????????????ŕ??????????????????Ĕ???Ĕ??̜???SSSSSS???Ș??RRRRRR???Ғ??Ғ?ϟ???PPPPPP???Ξ?͝?Ξ??͝?SSSSSS??ŕ?ŕ?ŕ??ŕ????????ʚ??̜???Ș??̜???[[[[[[???Ғ???А???̜?Ξ??А????Ԕ?ӓ??VVVVVV???WWWWWW???VVVVVV???ח???ښ??Օ??SSSSSS??ӓ??Օ??XXXXXX?ښ?Ⲳ??PPPPPP?^^^^^^??????YYYYYY??XXXXXX?WWWWWW???ؘ????XXXXXX?ٙ???ښ?YYYYYY?ؘ?XXXXXX?Օ?ؘ??ח??[[[[[[?ZZZZZZ??ؘ?ח?WWWWWW???ח?ؘ???????WWWWWW?֖?֖?ӓ??ӓ??ӓ?RRRRRR?Ԕ?SSSSSS?Օ?ӓ???QQQQQQ???ٙ???Ξ?QQQQQQ?PPPPPP??˛?????ӓ?Ξ?ё???Ǘ?Ș????ə??Ɩ?Ó??Ó?Ó???Ó?’??????’?Ĕ?ʚ?ŕ????Ó??’??Ó????’??????????????????????????????????????????Ó?Ĕ?Ǘ??˛?PPPPPP?͝??ə?ə?˛?QQQQQQ?RRRRRR?Ғ?ё?Ғ?QQQQQQ??PPPPPP?PPPPPP??Ξ?ϟ?PPPPPP?????RRRRRR???Ɩ?Ĕ?Ĕ?Ɩ?ŕ???Ɩ??Ɩ???????ŕ?ʚ?Ξ?ʚ??ʚ???ё?ӓ?͝???ϟ?Ξ?͝?͝??Ғ?Ғ?????YYYYYY?֖?֖?֖?Ԕ???Օ?YYYYYY?WWWWWW??ܜ??????VVVVVV?ӓ?TTTTTT??SSSSSS?֖?ӓ?YYYYYY?pppppp?⒒?111111??ܜ?ᱱ??ٙ?ٙ??XXXXXX??YYYYYY?ח?֖??????????ښ???֖?WWWWWW?ٙ??[[[[[[?ٙ?ݝ?XXXXXX?WWWWWW?YYYYYY?????WWWWWW??ח?Օ??Ԕ?ӓ?Ғ????Ғ??QQQQQQ?QQQQQQ?ё?RRRRRR??QQQQQQ???ښ?֖???????̜?͝??Ξ??̜?̜???Ș?Ɩ?Ĕ?????ŕ?Ɩ??Ș??Ĕ???’?????????’????’???Ĕ???Ó???????????ŕ??????????ə?????ʚ?????????????????????’??ŕ???ʚ????͝??QQQQQQ??SSSSSS?SSSSSS?QQQQQQ?ϟ?TTTTTT?PPPPPP?ё??ϟ??Ξ??͝?̜?Ξ???Ș????????ŕ?Ĕ?Ĕ??Ǘ?????Ɩ?Ǘ??????PPPPPP??ʚ?͝?Ғ??QQQQQQ?QQQQQQ?Ξ???˛?͝?Ԕ??Ғ?UUUUUU?WWWWWW?֖?WWWWWW?WWWWWW?VVVVVV?Ԕ???Ԕ?֖???pppppp?\\\\\\?ؘ???YYYYYY?WWWWWW???[[[[[[??????111111???ర???֖??ؘ?\\\\\\?WWWWWW?[[[[[[?ZZZZZZ????YYYYYY????ښ?ޞ?ZZZZZZ?֖??ݝ??ؘ????]]]]]]??ח?WWWWWW???Օ?????ӓ????Ғ???????А??А??ϟ??ё??SSSSSS???嵵??RRRRRR?А????̜?ə?˛?ʚ??͝???Ǘ??ə????Ɩ??Ɩ????????????’?Ĕ?Ĕ???Ĕ?ʚ?Ĕ???????Ó??????????̜??????????????????????????????????’?Ó??Ĕ?????Ғ?ϟ?Ξ?Ξ??RRRRRR?ё??????RRRRRR???Ξ??PPPPPP?̜?˛??ʚ?ə??͝??Ɩ?Ĕ??Ó??Ĕ??ŕ?Ɩ?Ǘ??Ǘ?ə??????ə??????RRRRRR????PPPPPP??Ξ?А?ʚ?QQQQQQ?Ԕ?SSSSSS?TTTTTT?SSSSSS?Օ?UUUUUU?ח??ؘ?TTTTTT????VVVVVV?????ח?ח?TTTTTT?VVVVVV??Օ?ח???YYYYYY???WWWWWW?YYYYYY?ٙ?]]]]]]?ښ?ٙ??ZZZZZZ?ᑑ?ښ?ߟ?ޞ??ښ?ؘ?֖???֖?????YYYYYY??֖???ޞ??ٙ?ߟ????TTTTTT???SSSSSS?Ԕ??UUUUUU???ё?Ԕ??RRRRRR??Ғ??QQQQQQ??TTTTTT?ё??QQQQQQ?ё??͝????QQQQQQ?ޞ?ᱱ?Օ?RRRRRR?PPPPPP?ϟ??̜?̜???˛???ϟ?Ǘ?˛?Ș?ŕ?Ǘ??RRRRRR?Ĕ????????????????????????Ó??Ó????????????̜????????????????????????????????????ŕ?Ɩ?????PPPPPP?RRRRRR???ϟ???А??QQQQQQ????PPPPPP?PPPPPP??А???Ξ?ё???ё?ə?Ǘ?ʚ?А??Ó?ŕ???Ɩ??Ɩ?ə??Ș???ŕ????PPPPPP??А?Ξ????͝?ё????А?Ғ?QQQQQQ??ё??QQQQQQ?Ԕ???Ԕ?????TTTTTT??WWWWWW??ؘ????TTTTTT?Օ??UUUUUU?ؘ?UUUUUU?ח?ח?XXXXXX?ښ???ؘ?UUUUUU??ܜ?______?ߟ?ښ?ӓ??TTTTTT?QQQQQQ??ӓ??UUUUUU???ח??֖?WWWWWW?ח?Օ?Օ?Օ?ؘ??֖??ؘ?֖?VVVVVV?VVVVVV??TTTTTT?RRRRRR??Ғ???Ғ????Ғ?QQQQQQ????Ξ?PPPPPP??QQQQQQ?RRRRRR?UUUUUU?ӓ?Ғ?PPPPPP?????ӓ?Օ?Ғ?ϟ?ё?????Ξ?͝??ZZZZZZ??PPPPPP?ʚ???RRRRRR??ŕ?ŕ??’?’????’?Ĕ????????Ĕ??Ǘ???Ɩ?Ĕ?Ĕ?????Ĕ????’?’??’???????????????????????????????????????????Ǘ??̜?Ξ????ё????PPPPPP?QQQQQQ?TTTTTT??Ғ??ϟ??QQQQQQ??ϟ??̜???͝??ə?ϟ???ϟ?Ǘ?Ɩ???Ĕ???Ĕ???ə?????˛?̜?????PPPPPP???ё?PPPPPP??????̜?RRRRRR?ё??Ғ??ё?????ё??UUUUUU????Օ?UUUUUU??ӓ?ӓ?Ԕ?UUUUUU?TTTTTT?UUUUUU?????ٙ?Օ???^^^^^^?QQQQQQ??\\\\\\?VVVVVV?RRRRRR???ӓ?TTTTTT???UUUUUU????UUUUUU?Օ?ZZZZZZ??VVVVVV?Օ?ח?XXXXXX??UUUUUU?Ԕ?????А?RRRRRR?Ғ???PPPPPP?А?QQQQQQ?ё???PPPPPP?QQQQQQ?Ғ?˛??SSSSSS????ӓ?ё??PPPPPP?ё??А?PPPPPP??А?QQQQQQ????̜??ϟ??˛?ϟ?ܜ???̜????Ɩ??Ǘ?ŕ??Ó?????͝?ŕ??????Ĕ??ŕ?Ș??Ĕ?Ó??????˛?Ó?Ó?Ɩ?????Ĕ????????Ɩ?????Ó????????????????????????Ĕ?Ș???’????Ξ??????̜???PPPPPP?RRRRRR?ё?А?ϟ??PPPPPP???ё??̜???˛?Ǘ??Ǘ?ʚ?Ĕ??Ɩ?????Ó?’????ə???Ǘ???ʚ??Ξ?PPPPPP?PPPPPP?͝?͝???PPPPPP??PPPPPP???VVVVVV???Ξ???QQQQQQ??Ғ?RRRRRR??TTTTTT?????QQQQQQ?Ԕ??Ԕ?UUUUUU??Օ??TTTTTT??Օ??WWWWWW?ח???VVVVVV??Ԕ??[[[[[[????֖????UUUUUU?֖??Օ??RRRRRR???ښ??WWWWWW???UUUUUU?UUUUUU?ӓ?ӓ?ӓ?????QQQQQQ?PPPPPP????QQQQQQ?А?А?QQQQQQ??Ξ?ё?QQQQQQ????SSSSSS????ښ?ؘ??Ғ?ё????А?PPPPPP????????Ξ?QQQQQQ??ʚ??RRRRRR???QQQQQQ???Ĕ?Ĕ?Ɩ?Ó??????ʚ?Ș?Ɩ?????Ó?Ĕ?Ɩ?’???Ɩ?Ó?????Ó?’?Ǘ?Ó?ŕ?SSSSSS?ښ??’???Ó??????????????????????????????????’??????Ó???Ș?˛??QQQQQQ?ё?ϟ?˛?А?RRRRRR???Ғ????QQQQQQ??А???͝?QQQQQQ??ʚ??????ə???ʚ??Ó?????Ĕ??Ș??Ǘ??̜??˛?͝??͝?˛?ϟ?????ϟ??SSSSSS???˛????RRRRRR?ӓ?ё?SSSSSS?SSSSSS?UUUUUU???А?Ξ?̜?А???Ғ?ӓ???SSSSSS????ӓ??UUUUUU?RRRRRR????ё?UUUUUU?ZZZZZZ??VVVVVV?XXXXXX?ؘ?֖??Ԕ???Ԕ?TTTTTT?Ғ??Ԕ???Օ??XXXXXX???SSSSSS?Ғ?ӓ??ё?PPPPPP??Օ?͝??PPPPPP???Ξ??PPPPPP??Ξ??QQQQQQ???˛???ZZZZZZ?[[[[[[??XXXXXX????͝?̜???˛?ʚ???̜?̜?˛?ϟ??̜?˛?Ș????Ǘ?????Ɩ???????Ó??’???Ó??????’?’?Ɩ?’??’?Ĕ??Ș?Ĕ????ŕ?Ș???’????????????????????????????????????????????ŕ?Ĕ??̜??????RRRRRR?ё??QQQQQQ??RRRRRR??Ԕ?ё???RRRRRR?Ξ??Ξ?˛?ϟ??Ǘ??Ɩ??Ɩ?Ɩ????Ĕ?Ó???’??Ó???Ǘ??ϟ??̜??͝???̜???ϟ?͝?PPPPPP?QQQQQQ?SSSSSS???ə??̜??А?А?SSSSSS???SSSSSS?SSSSSS?ё?????????Ғ??SSSSSS?ӓ?Ԕ?ӓ?TTTTTT?֖?Ԕ?Ԕ?YYYYYY??PPPPPP?RRRRRR?TTTTTT???SSSSSS??TTTTTT?UUUUUU??VVVVVV?SSSSSS?Ԕ?ӓ?Ԕ???RRRRRR??SSSSSS?SSSSSS???Ԕ?WWWWWW????А??QQQQQQ?Ξ?QQQQQQ?͝????Ξ??Ξ?ё????ϟ???ə?А??ܜ??ϟ?Ғ??Ξ??Ξ????ӓ?ϟ?Ǘ???ʚ?ə???SSSSSS?˛??ə?ŕ??Ǘ??ə?Ĕ?’??Ξ???????Ó?’??’?????Ĕ??’??’?ŕ?Ɩ?ʚ?Ɩ?’??Ó???????????͝???Ɩ????????????????????????????˛????????????ŕ??̜???Ξ???PPPPPP?Ғ???QQQQQQ??А?QQQQQQ????ё?͝?ϟ??͝??ə?Ǘ?ə??Ǘ??ʚ?˛??Ș???????Ǘ?ʚ????͝????ϟ??UUUUUU?Ǘ?͝??ӓ?PPPPPP???VVVVVV?Ξ??Ɩ?˛?ӓ??QQQQQQ?ё?QQQQQQ?RRRRRR?А?SSSSSS??QQQQQQ?͝??̜?????PPPPPP?????Ғ???Ғ??TTTTTT?Ғ??QQQQQQ?ϟ?ϟ?Ξ??????ё??PPPPPP???QQQQQQ??ё?RRRRRR??WWWWWW?SSSSSS?SSSSSS??????ϟ?Ξ??Ξ??͝?͝?̜??˛??А?ϟ?RRRRRR???˛?̜?͝??ϟ???ё?Ԕ?????ё?ё??ə???Ǘ?ŕ?ŕ?Ǘ??̜?Ș????ə??Ɩ?ϟ?ŕ??Ǘ???????????Ĕ?’?Ó??’??’???’???Ĕ???̜??ŕ????PPPPPP??Ó?????’?????????????????????????????????Ó??????????’???ʚ????ё????Ғ??????ӓ?VVVVVV?QQQQQQ?PPPPPP???RRRRRR??͝?˛?ə??ə?ʚ?͝?RRRRRR?ZZZZZZ??ŕ?Ĕ??’?’?Ɩ??˛??TTTTTT??Ғ??????̜?͝?̜?ə?Ԕ?______??SSSSSS??ϟ?Ξ?ʚ???ϟ?А?????ё????????А??А???TTTTTT?UUUUUU?ϟ?Ξ??А??QQQQQQ?QQQQQQ?RRRRRR?QQQQQQ?RRRRRR?QQQQQQ???ϟ?PPPPPP?Ғ?PPPPPP??А?PPPPPP?????PPPPPP??????QQQQQQ????ϟ?̜?ϟ?ϟ??͝?˛??͝??????Ξ????Ξ??Ξ?͝?Ξ???????Ξ?Ξ??Ξ?˛????˛??Ș???Ǘ??Ɩ?ŕ?ŕ?Ĕ????Ș??Ș???????????’?????????Ĕ??Ó?Ó?ŕ????Ĕ?Ĕ???Ǘ?Ǘ??’??’?ё??Ĕ?????????????ə???????????????????Ó??????ŕ??????Ĕ?PPPPPP??˛?А???ϟ??А?PPPPPP?А?Ξ?Ғ?ё?????̜?????Ξ??Ș????Ξ???ə???Ș??????ϟ??TTTTTT?YYYYYY?Ғ?ʚ???PPPPPP??PPPPPP??RRRRRR?UUUUUU????Ξ???Ó????А???????Ғ?PPPPPP???RRRRRR?ё?Ξ?ё?UUUUUU?\\\\\\?ؘ??????А?ϟ?PPPPPP???̜??Ғ?????ϟ?ϟ?̜???̜???PPPPPP??ϟ?А?QQQQQQ????PPPPPP?А???̜?Ξ?͝??̜?̜??˛?˛?ϟ??Ξ?Ғ?Ғ?ϟ?ϟ?͝??Ξ??͝??PPPPPP?Ԕ????VVVVVV?SSSSSS?????͝??ӓ???Ș??Ǘ????Ș??Ș?Ɩ?ʚ????ŕ??Ó??’?Ó????Ǘ?’????UUUUUU???Ó?Ɩ????Ĕ?Ș??Ș?˛?Ș?Ɩ???Ξ?ə???Ó??Ĕ???ŕ????????????Ɩ??????????????????????????????ŕ??SSSSSS??????˛?˛?А??А?Ξ?А??А?А?ϟ??А?ϟ?ё???Ξ?????̜?PPPPPP?̜?ə?Ξ??̜?ʚ?Ĕ??ŕ?????̜?̜?Ғ???Ξ?ё?ϟ??̜???А?PPPPPP?PPPPPP??Ғ??Ĕ??̜?̜???ё?QQQQQQ??????̜??QQQQQQ????ϟ?RRRRRR???͝?ʚ?ʚ???ϟ??ϟ??????????̜?????͝?Ξ?А????PPPPPP?PPPPPP?А?PPPPPP?PPPPPP?ϟ??͝???Ξ??̜??˛?ʚ?˛????RRRRRR????͝??͝?ё?ϟ????Օ?WWWWWW??PPPPPP?ӓ?ё?ё??˛?ʚ???˛???Ǘ??˛?????ŕ??Ǘ?˛??ə???’??Ó????????’?’???Ɩ?Ó?ŕ??Ǘ??Ó?ŕ?Ɩ??QQQQQQ??Ș?ؘ?WWWWWW???ӓ??Ǘ??ŕ??Ó?Ó????????????????????????????????????????Ɩ?ŕ???????RRRRRR?????Ξ????????RRRRRR??????А???ё?Ғ?Ԕ???????ʚ?ə?????˛?̜??ʚ?ʚ??ʚ?ə???????????ё????ŕ?˛?ϟ??RRRRRR?Ξ??RRRRRR?RRRRRR??QQQQQQ?Ξ???ϟ?QQQQQQ??͝??ϟ?Ξ??˛?ʚ?ʚ????̜???̜??̜?̜??ʚ???ʚ??͝???Ξ?͝?ϟ?Ξ?͝?QQQQQQ?????̜??̜????ə?PPPPPP??͝?ʚ???͝???????????ϟ?Ξ?͝?Ғ??ё?Ξ???˛??̜?ə?Ș?̜?͝??Ǘ?Ԕ?̜?Ɩ????Ɩ??ŕ??Ғ?Ǘ?Ș??ŕ?Ó??????’??’?Ó???????Ĕ????ə?ŕ???Ĕ????˛???͝?Ɩ???ʚ??Ó?Ɩ?????????Ĕ?’????????????????????????Ó??????’???Ó??ə??̜??????͝??Ξ?Ξ?͝?̜??UUUUUU?ё??Ғ?ӓ?SSSSSS??͝???ё?Օ?XXXXXX?˛??Ș??ə?Ș?Ș?Ɩ?’?˛?Ɩ?ʚ?ʚ?˛??̜???Ș?̜?Ξ?˛?˛?SSSSSS???ё??QQQQQQ???ٙ???Ǘ?Ș??ϟ?А??Ғ?А?ё??TTTTTT??˛?ʚ????ӓ?̜??͝??˛?????ё????ə?ʚ?PPPPPP?А???͝??͝???ϟ?͝?PPPPPP???Ξ??͝?Ξ?͝?͝?͝?Ξ??̜??˛?ʚ?ə?˛?PPPPPP?????͝?͝??TTTTTT??ϟ???Ξ????А????͝?PPPPPP????˛?̜???̜?ə?˛???ŕ??Ǘ??Ǘ????????ə?Ș?Ĕ??Ó?Ĕ?Ó?’?͝?Ɩ?Ǘ?Ĕ?ŕ?˛????Ș?Ξ?ӓ??Ș??Ǘ?ə????͝???ə??Ĕ???Ĕ???’?Ǘ?????????????????????????????????’???????˛??’?ə???Ǘ?ʚ?̜???̜?͝???̜?Ξ??А?ӓ???ర???А?Ξ??????QQQQQQ?Ғ?˛?ə??͝????Ĕ???Ǘ?Ș?Ș??А?Ξ?͝?Ξ?ϟ?˛?͝??Ξ?А??̜?͝?Ғ??YYYYYY???Ǘ?????QQQQQQ??QQQQQQ?ϟ??ؘ???͝????˛???˛??????ə???ܜ??Ξ???ʚ???ʚ?????˛?̜?ʚ???????̜????Ξ?ʚ?ə?????͝?RRRRRR????͝??ə???ϟ?QQQQQQ?QQQQQQ????ʚ???Ξ?Ɩ???PPPPPP?ʚ?ə??̜??ə??????Ǘ?Ɩ?ŕ??Ș??Ǘ???Ĕ?Ĕ?ŕ?Ĕ?Ɩ?Ԕ?Ξ?Ó?Ó???ə??Ғ?Օ?Ș?ə?ʚ??ə???Ǘ??Ɩ?ŕ????͝?Ǘ?ϟ??Ξ?Ș??Ó???????????????????????????????????ə???????????Ɩ???Ó?Ĕ??ϟ?Ș?ə?ʚ?˛????ʚ?Ș?͝??ϟ???Օ?ݝ??ݝ?Ғ?͝??А?͝?ϟ?ϟ???А?QQQQQQ??А?͝?˛?ə?Ξ?ə????ŕ??ʚ??̜?̜?PPPPPP?А???͝??ϟ?ə?˛??ə?͝?А?QQQQQQ????Ǘ??Ș?Ξ??????SSSSSS??RRRRRR????Ǘ??˛???????˛?ʚ?͝??Ғ??͝??????ʚ???ʚ?ʚ?ʚ?ʚ?Ș???˛??Ξ?˛???ʚ?͝?˛???ʚ??????ə?˛?̜??ʚ??ʚ??͝?ϟ?????ϟ??Ξ??̜?ϟ??̜??˛?ʚ?PPPPPP??̜?PPPPPP???̜?˛?Ɩ????Ĕ??????Ǘ????Ɩ?ӓ?͝????ʚ???̜?TTTTTT??RRRRRR?ё??ŕ?ʚ?Ԕ??ŕ?Ó?????Ó?Ɩ?????Ǘ????????????????’???????????????????????????????UUUUUU?ə??Ǘ??Ǘ?Ǘ???Ǘ?ə?̜?????ə??Ș?˛??RRRRRR??Ԕ?????̜??͝?˛?ϟ????????Ș?ə??Ĕ??’???˛?Ξ?̜??˛??SSSSSS?????͝?Ξ??Ғ????˛?ə?ʚ????ϟ?ϟ???PPPPPP??SSSSSS?QQQQQQ?͝?̜?ʚ??̜??͝?ʚ?ʚ?̜??ʚ????ח???˛???˛?ə?ə??Ǘ?????̜???˛???̜???ʚ?˛??PPPPPP??͝??˛???Ș????Ԕ?ё??̜?Ș?ə?Ș?ϟ?PPPPPP????˛??˛?˛??˛????˛?Ǘ?˛?ϟ?RRRRRR???Ș??ʚ?ʚ?̜?̜???????͝???Ǘ??Ξ????ə?ə?͝?Ș????˛???Ǘ?Ɩ?Ș?ʚ?Ξ???Ǘ?Ș??ŕ?Ĕ??VVVVVV??Ș??????’????Ó????????Ғ?????????????????????????????Ĕ?˛??Ξ?Ξ??’??Ĕ?????˛?̜?Ǘ???ə????Ԕ???А?PPPPPP?RRRRRR??Ғ?Ξ???̜?̜?Օ?TTTTTT?ё?˛?Ș????˛??Ǘ?ŕ????˛??˛???Ξ?А??ϟ?Ξ?˛?̜??ə???????Ș??ϟ?А?˛?SSSSSS?͝?͝?͝?ё??А??˛??̜??˛?Ș?̜?̜??ə??ə???ё?̜??UUUUUU?ə?????RRRRRR??ə?Ș?ʚ?ə?Ξ???̜?Ξ?ə???˛?͝??̜?̜???˛??˛??˛?Ξ?˛??ϟ??ʚ?ʚ??????Ξ?ʚ?Ξ??Ξ?̜???Ǘ??̜?ʚ??А??????????UUUUUU????˛?Ș?̜?TTTTTT?ʚ?˛??ŕ?ə?????͝?Ԕ??ʚ??͝?ϟ?????Ǘ??????Ɩ??ŕ?Ĕ??????Ĕ????Ɩ??Ó?’???????????Օ???????????????????????????А????Ș?????Ǘ?Ĕ??Ɩ?Ǘ?ə?Ș?ə?????Ǘ?Ǘ??ٙ??PPPPPP???ё?ϟ?PPPPPP?ё??̜?̜?UUUUUU??????ə???͝?ʚ??Ș??Ǘ?Ș??Ș?ə??????ϟ?PPPPPP??QQQQQQ???˛???ϟ???Ғ??ʚ??Ǘ??̜??QQQQQQ?Օ?ϟ???TTTTTT?Ԕ?ϟ?А??YYYYYY??̜?????˛??ə???ʚ??ə?ʚ??Ș??ʚ??ʚ?ə??˛???̜?̜?̜??ə?̜???????ʚ??ʚ?ʚ??ʚ??RRRRRR?QQQQQQ?̜??˛????ə?̜?Ξ?˛?Ξ????ʚ??Ǘ??Ɩ?Ș?Ș?ʚ???ʚ?Ș?ё??ʚ?ϟ??ʚ?͝?Ǘ?Ɩ?ə?ޞ???PPPPPP?????А?˛?˛??ʚ???????????Ǘ?ŕ?’??Ó?Ǘ?Ș?ʚ?Ĕ???ə???Ɩ????Ĕ??̜???ϟ??????Ĕ??’???Ó??????????????????????????А?ŕ??????Ĕ?Ĕ?Ĕ?ŕ???Ɩ?Ǘ????ə?Ǘ?Ǘ????А?А?RRRRRR?RRRRRR??ϟ?PPPPPP?XXXXXX??ϟ?PPPPPP?^^^^^^??Ξ?????ʚ?ə?ϟ?͝?ʚ?Ș???Ɩ???????̜?ӓ?А??ϟ?PPPPPP??˛?̜??̜??ϟ????ϟ??ŕ?Ș?ʚ?Ξ?ϟ?SSSSSS?RRRRRR?ə??TTTTTT??ə?PPPPPP??˛?̜??˛?͝???̜???PPPPPP?PPPPPP??TTTTTT?˛?????ʚ?ə??ə??˛???̜?Ξ??̜??ϟ?А?SSSSSS?QQQQQQ????ʚ?PPPPPP?̜??͝?Ξ?̜?QQQQQQ??͝?ӓ??ə????̜??̜?ʚ?͝?Ș??Ξ?˛?˛??Ș????Ǘ?ӓ??˛???????Ξ?˛??Ș?ʚ?˛?˛????̜???˛??Ǘ??ə?Ǘ?̜??Ș?ə?ʚ?˛?Ξ?ə???ښ??Ó?Ĕ???Ĕ??Ĕ????ϟ?˛?ŕ?Ó???̜??Ɩ?ŕ??Ǘ?ŕ????ŕ???????????????????????????????????????Ó????Ș??ŕ??Ș?ʚ???Ǘ??PPPPPP??ϟ?PPPPPP??ϟ?????QQQQQQ??PPPPPP?QQQQQQ????͝????А??˛?ʚ??ŕ???͝??ё??˛???ё?PPPPPP??Ξ?PPPPPP????SSSSSS??RRRRRR?͝?˛???˛???ʚ?Ξ?QQQQQQ?ϟ?А??Ξ??????̜??͝???ə??̜?˛????Ξ?А???????͝??ə?˛?˛??ʚ???ə??ʚ??͝??̜??˛?˛???Ș?֖?̜?SSSSSS?QQQQQQ?SSSSSS?̜??А??А??˛?Ș?Ș?Ș??Ș?ϟ??ə???͝??˛????Ǘ?ŕ?Ǘ?ϟ?Ǘ????Ǘ?ʚ??ʚ??????˛????А??ʚ??Ɩ?Ș???Ɩ?̜?ʚ??????Ó??˛?͝?’?Ɩ???ŕ?Ɩ?˛???Ǘ??Ș????Ó?Ɩ??ŕ????Ǘ?͝?Ĕ????Ĕ?????????????????????????????ӓ?’?’????ŕ??’??Ĕ?Ș?ё????????Ξ??ʚ??Ξ?Ξ??Ξ???͝?QQQQQQ?????̜?ٙ???ə?˛?̜?000000??̜??ʚ???Ɩ??ʚ?ʚ?͝?͝?˛??ϟ??QQQQQQ?ϟ???Ξ??ϟ????Ș?Ξ???̜?Ξ??QQQQQQ?ё???Ș??ϟ??Ξ??̜?̜?ʚ??Ξ?Ξ?PPPPPP????͝?SSSSSS?̜?̜???̜?̜???̜??̜?ϟ??PPPPPP?ə?̜?˛??͝?ʚ???˛?˛?PPPPPP??PPPPPP??Ș??Ș???͝???˛???????Ǘ??ə?Ɩ?Ș?˛??QQQQQQ?˛?PPPPPP??͝?˛???ё?˛?Ĕ??PPPPPP?Ɩ?Ǘ??Ș?̜?Ɩ??ə?Ǘ??͝?Ǘ??Ș?????˛???Ǘ?Ǘ?Ș??Ĕ?QQQQQQ??ə?ŕ???Ó?’?’?Ó?’????ŕ?????͝?Ĕ????’?????’??Ș??Ɩ?????????????????????????????????????’?????Ó?Ǘ??Ɩ?ŕ?ŕ??Ǘ??Ǘ???Ĕ?Ĕ??Ǘ??ё??̜???RRRRRR?ϟ?PPPPPP??ʚ??Ξ??RRRRRR?Ξ?SSSSSS???ə?ё????Ɩ?Ɩ?Ó?Ó?Ș??ʚ??Ξ?͝????ё?SSSSSS??QQQQQQ???ӓ???Ξ??ŕ??Ɩ?̜?А????ϟ??̜???PPPPPP?͝?̜???ϟ??͝?͝?͝?ϟ?А?Ξ?͝??А?А?ϟ?QQQQQQ?͝??ӓ???ʚ?͝?Ξ??͝??Ξ?ʚ?˛??˛?̜?̜??˛?̜?PPPPPP?˛?͝??????PPPPPP??????̜?̜??͝?ʚ?ə?SSSSSS?ח?SSSSSS?Ξ?ə?PPPPPP?ə???˛????ʚ??ʚ?????????’???Ǘ??Ξ?͝??Ǘ???ŕ?ə??PPPPPP?̜?ʚ??ϟ???Ɩ?Ɩ?Ǘ?Ĕ?ŕ?’?Ó?Ĕ?????Ǘ?Ĕ????Ɩ?Ǘ??ŕ???Ó?Ó?’?Ĕ?ə?Ĕ????????????????????????????????????????ə????????ϟ?????ʚ??Ǘ??Ɩ?Ș?Ǘ??ϟ?ʚ?PPPPPP?Ξ?͝??ё?QQQQQQ??А??А?QQQQQQ??]]]]]]?ܜ??А?QQQQQQ???ʚ???ʚ?ŕ????Ș??ə?ə??˛????͝????˛?ʚ??Ξ???Ș???Ǘ??˛?Ɩ???Ș??̜???PPPPPP?Ξ?̜????̜?̜?̜?ё?̜??UUUUUU?????ё?ϟ?͝???PPPPPP?Ξ?̜?͝?А?ϟ???ϟ???͝???͝?̜??????????ʚ?˛???PPPPPP???UUUUUU?ə?˛?ə?͝?̜??????Ξ??ϟ????̜??̜?ʚ??Ɩ?ə?ŕ??Ǘ???Ó?ŕ?Ɩ???Ș??Ǘ???ŕ?Ĕ????ŕ?̜?˛??͝??ʚ???ŕ?????QQQQQQ????Ĕ?Ĕ??Ș?ŕ???Ɩ?ʚ?Ǘ???ŕ???ʚ?Ɩ?Ó?’?̜?Ĕ??????????????????????????????????????????????????̜?ŕ?Ǘ?Ș?Ș????Ș????PPPPPP??PPPPPP??Ғ??????XXXXXX?????ё???ʚ?˛?PPPPPP???ʚ?˛??Ǘ?Ǘ???˛?????WWWWWW?֖?????͝??ʚ??Ǘ??ə?Ξ??Ș??ʚ?ŕ?Ɩ??Ș??ʚ??ʚ???˛?̜??QQQQQQ??ϟ???А??͝?А??QQQQQQ??˛?˛??ϟ????͝????VVVVVV??Ξ??̜?ϟ??̜????̜??Ғ??Ǘ????PPPPPP?PPPPPP??ʚ?˛?ʚ???????˛?QQQQQQ???˛?ʚ???ə?Ș?Ș?Ș?Ǘ??ə?Ɩ?ŕ?Ɩ??Ɩ?Ɩ?Ɩ?Ɩ?Ɩ??ŕ??Ș???Ɩ?ʚ?Ɩ????Ɩ???Ǘ?Ș????Ɩ??ŕ????Ĕ??Ĕ?Ĕ?Ĕ??Ș??’??̜?Ó???Ĕ?Ó??Օ??????????????????????????????????????????????????????Ɩ??????Ǘ???????͝???ё?Ғ?TTTTTT?QQQQQQ??Ξ??RRRRRR???Ξ?ϟ????Ξ?Ɩ?Ǘ??ʚ?XXXXXX?ё?Ғ??˛?˛?͝???͝?͝?PPPPPP??XXXXXX??\\\\\\?ϟ?ʚ?Ș?ə?Ɩ?Ɩ???˛??ə?͝??ʚ????????ə?˛?QQQQQQ??ʚ?ə?̜?͝?ə?̜???̜?Ξ?ʚ?̜?ϟ?RRRRRR?А?͝?˛??А??˛?͝??ϟ??А?rrrrrr?QQQQQQ??ӓ?ϟ?˛??̜??ə?̜?Ξ?ʚ????˛???Ξ??̜?̜?̜??Ξ?ə?Ǘ?̜??˛?ə??˛?????Ș?˛???Ș?ŕ??˛?ŕ???Ǘ?ə?Ș?Ǘ?Ș??˛?Ǘ??Ĕ????ŕ?Ĕ?Ĕ??Ǘ????ŕ??Ɩ??ə??ŕ?Ĕ???Ǘ?ŕ?’??????Ĕ?Ɩ?Ĕ?’??Ǘ?Ó?’??????̜?Ɩ???Ɩ????????????????????????????????????????????’?ŕ???ŕ?Ξ?ŕ???????Ɩ?Ǘ??ə?˛?ӓ????\\\\\\?ӓ???????Ғ?SSSSSS??ؘ?RRRRRR???Ɩ?Ș???А???˛??QQQQQQ?ʚ?Ș?Ǘ??Ғ?QQQQQQ?222222???PPPPPP??͝??ə???А??̜?ϟ?˛?????ʚ?ʚ???̜?ʚ?˛????Ș?Ș????ʚ??˛?Ξ?˛?ʚ??RRRRRR??˛?˛?SSSSSS??ϟ?Ξ??????????̜?̜?ʚ?ʚ?????А?͝?????А?Ξ????ʚ???PPPPPP?А??QQQQQQ?̜??ə???VVVVVV?PPPPPP?Ǘ?Ǘ??ʚ??Ș????ŕ?ŕ??Ɩ?Ɩ???Ɩ??ʚ??ʚ?ŕ?Ĕ?????????Ǘ?ŕ??ŕ??Ĕ?ŕ???Ǘ?ŕ??Ĕ?Ɩ???Ĕ??’??ŕ?Ɩ??ŕ?Ó??Ĕ??’???Ĕ??’?’??Ó??????????????????????’??????????????????????Ĕ?Ó???Ǘ?ŕ????Ș??Ș?ʚ?QQQQQQ?Ɩ?ŕ?Ǘ?????WWWWWW???TTTTTT??А??˛???ё?ۛ?Ԕ?Օ?SSSSSS??ə?˛?ϟ?ʚ??А?Ξ?ϟ??ϟ?ח?????PPPPPP?Ԕ?????ʚ???????̜?̜?QQQQQQ??͝?͝??ʚ???̜?͝????ə?˛?????˛?????ə????ə?˛???Ξ?ϟ???????А????????˛?Ɩ?Ĕ?Ș?ʚ???̜?Ξ?А?Օ?PPPPPP???ə?ə???ə?ϟ?Ș??????PPPPPP??А??ə?Ξ????͝?Ɩ?Ɩ?Ó??Ĕ??Ĕ?Ș??Ș???Ǘ?Ԕ?Ǘ?Ξ?ŕ?Ĕ?Ĕ?Ș?Ɩ?Ș????Ɩ??ʚ?̜??’?’?ŕ???Ɩ????’????Ĕ?Ĕ?Ĕ???????????Ĕ?’?’??Ǘ???????????????????????ə????????????????????’?’?Ĕ????Ǘ?̜??Ǘ?Ĕ????˛???Ǘ?Ș??ʚ?ӓ??PPPPPP?А???Ξ?˛?͝???Ғ??????Ԕ???Ș??А?ϟ?QQQQQQ?А??PPPPPP??ؘ??SSSSSS???Ξ?˛???˛??????ʚ?ʚ?˛???͝????̜?Ɩ??Ș????ʚ?ə??ə?Ǘ?ʚ?ʚ??Ș?ə?Ș????Ș????Ғ???PPPPPP?͝???ʚ?Ɩ????????ə?Ș???ŕ???А???ϟ???VVVVVV???ё????ʚ?˛?ə??Ș?˛?ʚ?Օ?Ԕ?А?А??Ξ?PPPPPP????͝?Ǘ?˛??Ĕ??Ɩ?Ɩ??Ĕ?Ɩ??Ĕ?ʚ?Ɩ?ŕ???ʚ?ʚ?Ș??Ș?Ǘ??????Ó??????????’?Ǘ??Ó?ʚ??????Ɩ?ŕ??PPPPPP???ŕ???Ó??ŕ???’????????????????????????????????????????Ș?Ș??????ə???Ɩ????ŕ?????Ɩ????ʚ??ё?RRRRRR?PPPPPP???ʚ?QQQQQQ???А??Ғ????͝?̜??Ǘ???А?PPPPPP???QQQQQQ?WWWWWW?WWWWWW?SSSSSS?ٙ?ə??ə?Օ?ܜ?ϟ?ʚ?Ș?ʚ??ə?ʚ?͝?ə?ʚ?Ǘ??ϟ??QQQQQQ?̜??̜??Ɩ???͝?Ș?Ғ?ə?Ș???ʚ??ʚ??ʚ?????ʚ?Ș???̜???Ǘ?Ǘ??Ǘ??Ɩ?ə?ə?ə??????Ɩ?Ɩ??Ș?ʚ???QQQQQQ?ٙ?ښ??RRRRRR?ϟ??̜??QQQQQQ??А????ʚ??Ғ???˛????ϟ????????Ǘ??ŕ?Ó?Ó?Ĕ??Ɩ?Ó?’???ӓ??ə?Ɩ?Ș??ʚ???Ɩ?’?’?Ó?’???Ș??Ó???Ĕ??Ĕ?Ǘ?ʚ???ݝ?PPPPPP?ŕ??UUUUUU?ŕ??̜??Ó?Ĕ?SSSSSS??Ș?Ó?Ó?Ó??Ó?????????????????????????????????????????̜?Ǘ??’?????Ó??Ɩ???Ș???Ɩ?Ɩ??Ǘ??Ǘ???֖???ϟ????ϟ?PPPPPP?SSSSSS?????ʚ?̜??Ξ?˛?ʚ?̜?ϟ??˛???Ғ??RRRRRR?RRRRRR?˛?Ș???ё?˛??ʚ??????ŕ?????Օ??Ǘ??Ǘ??Ɩ?PPPPPP?ŕ?????˛?Ș????̜??Ș??˛??ə??ə?Ǘ??͝?ϟ?ʚ?ʚ?ʚ????Ș??Ɩ???ə?ŕ?ə??Ș??Ɩ??ə???Ș?Ξ?Ғ?͝????А?ё??А?͝?Ș????Ș??ϟ????????ŕ?’?Ĕ??ŕ?????Ș?ŕ?Ó???ŕ?Ĕ?̜?А?͝??ʚ???ə?Ɩ??Ĕ?????Ó??????ŕ?ϟ?Ɩ?Ó?’??Ĕ?Ș?ښ???Ǘ?Ǘ?Ș?ϟ???Ɩ???????’?ё??Ĕ?Ó???????????????????????????????????????SSSSSS?Ĕ????’???’?????Ғ?Ɩ??ʚ???Ș?ə??Ǘ?ə???А??˛?PPPPPP?͝??Ғ??ё?PPPPPP??А?Ξ??ə????ё?????֖?TTTTTT???WWWWWW???????????͝?Ǘ?Ș?Ș?Ɩ?ə????֖?Ξ??ŕ???Ș?ŕ?’??ŕ?Ɩ?Ǘ???˛?ʚ??RRRRRR?ə??ʚ?Ș?Ɩ??˛??ʚ?ϟ?˛??ʚ??ʚ??Ș??Ǘ?????ŕ??ʚ?Ɩ?????ʚ?ə??Ș??Օ??̜?А?ё??ϟ?PPPPPP?QQQQQQ????Ǘ??Ǘ????Ɩ????Ĕ?Ó???Ó??Ǘ??Ĕ??TTTTTT?Ɩ???Ɩ?Ó?Ɩ??̜?RRRRRR????Ɩ?ŕ???Ɩ??’??Ó??Ó???????Ĕ??’??ŕ??ŕ????ʚ???ښ?Ԕ????Ș??Ó?ŕ?’?Ó??Ǘ?Ǘ???????????????????????????????????????????’??PPPPPP?Ǘ??ϟ??ə??’??Ĕ?Ĕ??ŕ??Ș?ə??Ș?˛???ϟ???PPPPPP????UUUUUU?ϟ?????ʚ??А?А????ϟ???ӓ???ܜ?А?Ξ?͝??????Ɩ?Ǘ??ʚ?Ș?Ș?ʚ?Ǘ??ʚ??ؘ???ʚ?Ș??Ĕ???????Ɩ??ʚ??Ș?˛??ə??Ɩ????͝?ϟ??ə???̜??͝?Օ?Ș?Ɩ?????Ĕ?Ɩ???ŕ???ə?Ɩ??Ǘ?̜?Ș?ŕ??˛?ʚ??ϟ???͝???ə?Ǘ?Ɩ?????????Ĕ?’??’?Ɩ?Ó?ŕ??Ó?ŕ?Ĕ??Ɩ?ʚ??Ǘ?ŕ?Ɩ?ŕ?Ș???˛???͝?Ĕ?ϟ??’????ŕ?Ó?????????Ĕ??Ó?????Ǘ??Ɩ?Ǘ?’????͝??ə???ŕ?????Ș???????????????????????????????????????????ŕ??ʚ?Ó???Ĕ?ŕ??’?Ĕ????????Ș?ə?????ʚ?͝??RRRRRR?PPPPPP????ё??RRRRRR??????????А?А???ח?Օ?ܜ?PPPPPP??А???Ó?Ș???ʚ??̜???̜?˛???Ξ??ə???Ș?????Ș??ŕ??ə??Ǘ?ə??˛???Ș??Ɩ???Ɩ???˛?͝??Ș??ʚ?А?ʚ?ə?Ɩ??ŕ?Ĕ?Ĕ?Ĕ?Ĕ?Ɩ????Ǘ??Ǘ?ə?Ɩ?Ɩ?ə?˛?̜?Ș??А??ə?ə?˛??Ǘ?Ĕ?Ș??????????ŕ??Ɩ?ŕ?ŕ?Ǘ????Ɩ??Ǘ???ŕ????ə?Ǘ??Ɩ???Ó?˛????’???’?Ó?????’?’?Ó?’???͝?????Ɩ?ŕ???????ϟ??Ǘ?????Ó?Ó??????????????????????????????????????????Ș??RRRRRR?Ɩ???Ǘ?’?Ǘ??Ɩ?ʚ?SSSSSS?Ĕ???ə?Ș??Ș????^^^^^^???А?VVVVVV???ח??А?ё??А?Ξ?Ξ????̜?͝???????ۛ??YYYYYY?ӓ???Ɩ?Ĕ???Ș????˛?Ξ?ʚ?Ș?͝?ё????Ș????Ɩ???ʚ???Ó??Ș?Ș?Ɩ???ʚ???WWWWWW?Ș?ʚ????Ɩ?????Ș??ʚ?Ș?ŕ?Ɩ????Ĕ?????Ș?Ɩ????ŕ??Ɩ??ʚ??Ș?ŕ?А?ӓ?̜?̜??̜???Ǘ??Ɩ?ϟ?ŕ?ə?ё?Ɩ???Ǘ??ŕ????ŕ??̜?̜??ə??Ĕ?ŕ???Ǘ???ŕ??ʚ?ŕ?Ó???Ó?Ĕ?’?????????????Ș?˛???ŕ?Ξ???ŕ??????Ɩ?ʚ?’??????PPPPPP?TTTTTT??????????????????????????????????????????TTTTTT??Ξ????’?Ó??’??͝????Ó???ϟ??????Ғ??̜??А??ϟ???А??Օ?TTTTTT?ё?PPPPPP??PPPPPP??PPPPPP?̜?˛?͝?ʚ?QQQQQQ?֖??????XXXXXX??ё?Ξ?ʚ?͝??Ǘ????Ș?ə?ə?̜????PPPPPP?Ɩ?Ɩ????Ɩ???ʚ?А?ӓ?Ó??̜??ə?PPPPPP?ϟ????Ǘ?’?ŕ???Ș??Ș?ŕ??Ó?͝?Ɩ?????ŕ??ŕ??ŕ??Ǘ??ə????ŕ?ŕ?????ϟ???ə???А?ə??ŕ???̜?RRRRRR?А???Ǘ???QQQQQQ???Ó??Ș??˛?ϟ?Ξ?Ɩ?QQQQQQ?ŕ?Ɩ???????Ɩ?Ĕ?Ó?Ĕ?Ɩ?Ó?ʚ?ŕ??’??????’?????’?ə??ŕ???ӓ?Ș???̜?Ξ????Օ?̜??ϟ???’??Ǘ??Ĕ???????????????????????????????????????????’???Ǘ?ŕ????’?’????ə?’?????Ó????ϟ???????QQQQQQ?Ξ?ܜ?QQQQQQ?Ғ?ё???Օ??ё???Ξ?˛?ё????ᱱ?Ԕ??ח??˛?ə?͝?PPPPPP?UUUUUU?ё??Ș???Ǘ???PPPPPP?ё?ŕ?????Ó???Ɩ???Ĕ??TTTTTT?????Ǘ?͝?ʚ?˛?Ǘ???Ș??Ǘ???ə???’??ŕ??ŕ??Ĕ????Ĕ?ə?Ĕ??Ɩ?ə?Ĕ???Ĕ?Ĕ?ŕ?Ǘ?ŕ??PPPPPP?Ș??Ș??PPPPPP???Ǘ?ŕ?Ǘ?Ǘ???\\\\\\?ϟ????Ș??Ǘ???ŕ?ʚ?’?Ĕ??Ɩ????Ĕ?Ĕ?͝???Ș?Ǘ?ŕ?Ɩ??Ɩ?Ó??Ó?Ɩ???????’??Ó?’?’??Ɩ???Ǘ?Ɩ??ə????Ɩ????QQQQQQ?Ξ???Ó???Ĕ????’????????????????????????????????????????????Ĕ?Ș????ŕ??????’???????ŕ??Ǘ???PPPPPP????˛??ϟ?Ξ?͝?PPPPPP??TTTTTT?QQQQQQ?PPPPPP??А?ё?PPPPPP??͝?????˛??QQQQQQ?QQQQQQ?А?ӓ???͝?̜??PPPPPP?Ǘ?Ș?Ș?ə?Ǘ?Ǘ?????Ɩ???ŕ?Ĕ??ŕ?Ǘ??ŕ??ӓ?????ʚ?????ʚ???Ǘ?Ǘ?ə?ə?˛?ʚ?????ŕ????Ĕ?Ĕ?ŕ??UUUUUU?Ǘ??ŕ??Ó?Ɩ????Ó??ŕ?Ɩ???????Ɩ????Ɩ?Ĕ??ʚ?˛?ʚ????ٙ???͝????ŕ???Ĕ?Ɩ?Ĕ?Ǘ??Ș???Ǘ?????Ǘ?А????????Ĕ?Ó???’?Ĕ?Ɩ?ŕ??Ɩ???˛???Ĕ???Ǘ????QQQQQQ?ə???????????ʚ?????????????????????????????????????????????Ɩ????’?Ĕ?????Ó?????????˛?ŕ?ŕ??˛???ə?????Ξ?͝?RRRRRR?Ғ?SSSSSS???TTTTTT?QQQQQQ??͝?ϟ??͝????QQQQQQ?ʚ?̜?А??ϟ??ё?Ξ???ə?̜??Ǘ?Ǘ?Ɩ?ʚ??ϟ???˛?Ș??Ĕ?ŕ???Ɩ???Ɩ???ŕ?ŕ?ŕ?ʚ?͝?̜?ʚ??̜??˛???ʚ??ʚ?Ǘ??SSSSSS?ё?Ǘ?Ɩ?Ĕ?????Ș?Ș???Ɩ??ʚ?Ș?Ĕ?ŕ?Ó?ŕ?ŕ?Ǘ????Ș?????Ĕ?’???Ɩ?Ǘ?Ș???RRRRRR?Ξ?˛?͝?͝?Ɩ???ŕ?ŕ???Ó???ŕ?Ɩ?ϟ?ŕ???????Ɩ??Ǘ????Ǘ??????Ó?Ó?Ĕ???Ɩ??TTTTTT?Ғ???ŕ???UUUUUU??ŕ?Ĕ???RRRRRR??Ɩ??Ĕ?ё?Ǘ?Ĕ?????????????????????????????????????????????????????Ĕ?Ó??Ĕ?????Ó?Ĕ????????Ĕ??Ĕ??Ғ??Ξ?Ɩ????ё??͝?˛????PPPPPP????Ғ?Ξ?RRRRRR??ϟ??̜????̜?ϟ?????ё?RRRRRR??Ғ??Ǘ?ϟ?Ó???RRRRRR??ə??Ǘ???ŕ??Ǘ??˛??ŕ?ŕ???ŕ???֖?RRRRRR?ϟ?SSSSSS?PPPPPP???͝?А??Ș?Ɩ?Ș??????Ș??Ș?ʚ??????ʚ?ʚ??˛????ŕ??Ɩ?Ș???Ș?Ș??Ș?Ɩ??????ə?˛?Ș????ʚ?ʚ?ʚ???ə??Ɩ?Ó?????Ș?Ɩ??Ǘ?Ǘ?̜?Ǘ?ŕ???Ɩ?Ó?Ǘ?Ș?̜?Ǘ?˛??Ɩ?????Ó?Ó??ʚ?RRRRRR???????????͝?Ĕ?Ǘ?’???Ɩ???Ғ???А???????????????????????????????????????????????????’??Ғ???’?Ĕ??Ó?????’???????Ó???ə?˛???ə??Ș?Ș?ə??QQQQQQ???̜???ϟ???Ξ?˛?PPPPPP????А?Ǘ???ʚ???PPPPPP?Ғ?\\\\\\????PPPPPP?????͝?̜??ə??Ș??Ĕ??Ș?̜???ə??Ɩ?Ș?ŕ????QQQQQQ???Ξ???˛?Ԕ????͝?ə?ə?Ǘ??ʚ??ϟ???˛?̜??ə?ʚ?Ǘ?ə?Ș???????Ɩ????ŕ??Ǘ???????Ș??Ǘ????ʚ??ə?ϟ??ʚ??Ǘ?Ĕ?Ǘ??Ĕ??Ɩ?ŕ??Ó?ŕ??Ɩ?Ɩ??????Ɩ?ŕ????Ó?’?’?????ŕ??????ᱱ????^^^^^^????Ó???’????UUUUUU???’?Ĕ?ŕ???????????????????????????????????????????????????????????Ɩ?Ǘ?????Ó??˛?Ó?Ǘ???Ó???˛?ə?Ɩ??˛?Ș??????ə???PPPPPP?͝?͝?Ș????А??ZZZZZZ??XXXXXX?Ξ???̜?????[[[[[[?͝??Ó??Ó?ŕ??ŕ??Օ?Ǘ?Ĕ?ʚ?Ș??Ș?Ș?̜?Ș??Ǘ???????ʚ?ʚ?ə??ʚ?Ș?А?ϟ?Ș???Ɩ??????Ԕ?ϟ?Ξ???ݝ???͝???Ș??ʚ?ϟ?ʚ???Ɩ?ŕ???Ɩ??Ɩ?Ș??ə???????ʚ?????ə????˛???ŕ?????˛???Ĕ??Ĕ?Ș?Ș?Ɩ?Ξ?PPPPPP?QQQQQQ??Ɩ??ŕ?Ǘ?ŕ??Ĕ???Ó?Ɩ?̜?Ș?????Ξ?ϟ???̜?̜?Ɩ???Ș?Ó?ŕ?Ĕ??Ș??RRRRRR?Ɩ??’???????????????????????????????????????????????????????ʚ??˛?Ǘ?ŕ??????????????Ó???ŕ??˛??ə?Ǘ?˛?????ʚ?Ș?ʚ??˛??̜?ʚ??ϟ?Ξ??VVVVVV???????’?ʚ?PPPPPP????Ξ??Ǘ?Ĕ?Ɩ?Ǘ?Ș?˛?Ǘ???ϟ??Ǘ?Ș?ʚ?????Ǘ?ə???Ɩ??Ɩ??ʚ??͝?˛?????Ɩ??ʚ?ə??ə???WWWWWW?Ғ?????ϟ?Ξ?Ξ?͝?Ș?ə?Ǘ?Ɩ????Ɩ?Ɩ?ŕ?Ɩ?Ș?Ɩ????ə??Ș???Ɩ?Ǘ???Ș?Ɩ?ŕ??Ɩ?????ŕ???ʚ??̜?ə?Ǘ??Ș???’?Ɩ?֖???333333???ʚ??Ó?Ș?Ó???Ǘ???Ó??????˛?????????’??????ŕ?˛????????????????????????????????????????????????????????????Ξ???ŕ??????????Ó????’?Ĕ?Ǘ?Ɩ?ə??ə??Ǘ?Ș??Ș???Ș??????ϟ???А??RRRRRR??֖?UUUUUU???TTTTTT???Ș?Ǘ????ŕ??Ș?ŕ????ϟ?̜?Ԕ??˛????͝?ə?˛?ϟ???Ș???Ǘ?ə????Ș?̜?ϟ?????˛?ə?ٙ??˛?͝????TTTTTT??ח?Օ?[[[[[[????ʚ?Ș?Ș?Ș??Ǘ?Ș???????ə?ə?͝?˛???Ș??͝?˛??ʚ?Ξ?Ĕ?ə?ə?Ș?Ɩ??͝?Ǘ?Ɩ???Ɩ??ʚ??Ș?Ǘ?Ș??’??’?͝??ϟ????Ș??ŕ??ŕ??’?ə????ŕ???ŕ??Ɩ??’?’?????ŕ???’???ё???WWWWWW?PPPPPP??????????????????ŕ?????????????????????????????????????????Ĕ???????Ɩ??????Ó?Ғ???ə??Ĕ?Ĕ???????Ɩ?ʚ??QQQQQQ?ŕ?Ǘ?????????˛???А??\\\\\\??Ғ?RRRRRR?PPPPPP?Ɩ?ŕ?Ó??Ó?Ĕ?ŕ?Ĕ?????Ș?Ș???ʚ?˛??А??Ξ???Ș?ʚ???ϟ?˛??ŕ???ʚ?˛?˛?ϟ?Ș?ʚ??˛??ə?Ǘ???А?Ξ??ښ?000000??UUUUUU?Ғ?UUUUUU?Ξ?̜??Ș?ə?Ǘ????ŕ?Ș?ə???????ё?̜??ə???Ξ?̜?Ǘ??????Ǘ???Ɩ??ə?Ɩ???ŕ?Ș????Ó?????ŕ?ə?ʚ??Ș??Ĕ?ŕ?????????Ĕ???Ó?Ș?ё????Ԕ????????Ɩ?Ĕ?Ɩ???SSSSSS?ϟ?TTTTTT???????????????????????????????????????????????????????????Ғ??Ĕ??’??????’???А???ŕ??’?Ĕ?Ɩ????Ĕ??Ɩ??ə?ؘ??????̜??̜?˛?̜????Ξ??ӓ????PPPPPP?̜?ə?’?????Ɩ??Ǘ??Ǘ??Ǘ?Ǘ?ə?ʚ?ϟ?Ғ?????ʚ??А?ə??ə????͝?ə??ə?ʚ?PPPPPP????PPPPPP???Ɩ??Ғ???Ԕ???ߟ?ZZZZZZ?????ə?????ŕ?Ɩ????Ɩ??ʚ???PPPPPP?˛????Ξ???Ǘ?ə???˛??Ǘ?ʚ??PPPPPP????????Ǘ???????Ó???????˛?ŕ?Ĕ??????ŕ????’????Ó?Օ????????Ó??Ș?????PPPPPP??Ĕ????????????????????????????????????????????????????????????ʚ???’???????????’???????˛??Ǘ?Ĕ??Ș?Ș?ʚ??ə???ə???ʚ??Ǘ??̜?Ș?ʚ?͝?????Ԕ?SSSSSS?QQQQQQ??Ș?˛?????Ɩ???ə?Ĕ?ŕ?Ɩ???̜?PPPPPP?PPPPPP?А??˛?ə??Ș???ə????˛??̜?PPPPPP????ӓ?ϟ???͝?ə?̜?UUUUUU??Ғ????͝???]]]]]]?Ғ?̜?ə?ə?ə?ʚ?Ǘ????Ǘ?ə?Ș??Ǘ?Ξ???PPPPPP?͝??̜??ښ??̜?Ș???Ș???ə???Ɩ?Ɩ?Ǘ?͝?Ǘ?PPPPPP?ё???PPPPPP???Ș???Ĕ?̜??͝????Ɩ?ŕ??Ĕ?????????????Ɩ????ŕ??????Ǘ?Ɩ??Ĕ?’?Ĕ?ʚ?Ɩ?Ĕ????????’??????????????????????????????????????????????????̜???????????????Ǘ????’??Ǘ???ŕ?Ǘ?Ș?˛??˛?Ș??Ș???˛?ʚ?ʚ??ʚ?ə?Ș?ё?ʚ?А??䔔?YYYYYY?ё??А??А?ə?Ș???Ǘ????Ș??Ɩ??Ɩ??Ș?ʚ?ٙ?PPPPPP?Ξ?̜??QQQQQQ??Ǘ?ə???˛??ʚ?͝?˛??˛?˛????˛???PPPPPP?͝??Ǘ?????ə?QQQQQQ??tttttt?qqqqqq?Ғ?QQQQQQ??PPPPPP?Ș???ə?Ɩ??Ɩ?ə??????Ξ?Ξ?ə?????ʚ?ʚ????ʚ?ə????????Ξ?QQQQQQ??͝?ʚ??͝???Ξ?ə??Ǘ?Ɩ???????ŕ?Ĕ??Ó?????Ó??????Ĕ??????Ó???’??ŕ??Ɩ????ŕ?Ș???????Ɩ?????????????????????????????????????????????????͝?ӓ?ʚ?Ξ??Ș???????????????Ǘ???Ó?’???ŕ?Ɩ??Ș??Ɩ???ŕ???ə?˛??SSSSSS???ʚ?ʚ??ϟ?ϟ????ё?ʚ?А?̜?Ș??Ș??ə?̜?Ξ?Ǘ?Ɩ?ŕ??Ɩ????Ɩ??ʚ??ə???ʚ??˛?Ξ?ח?̜?˛??ʚ???ʚ??Ș???͝??Ξ????ʚ??ʚ??QQQQQQ??̜????RRRRRR?˛??Ξ?ə???ʚ???ə???PPPPPP?RRRRRR??͝??ʚ???ʚ?˛???Ǘ???ʚ?Ș?Ɩ?Ș??͝??̜???PPPPPP??˛??͝?̜?ə??Ξ?̜??ə?Ș??Ǘ?Ɩ?Ɩ???ŕ?Ĕ?Ó????????Ó????????’??????’?Ĕ????Ș?Ó?Ǘ??Ó???????’???ϟ??????????????????????????????????????????????????Ĕ????????’???ŕ??Ó???Ș?????Ǘ?̜?А???ʚ???Ș?Ɩ?Ǘ????Ɩ??PPPPPP?QQQQQQ??ə?ʚ?ʚ??̜??А?RRRRRR?Ԕ??˛??͝???А??ϟ?Ғ?VVVVVV?Ɩ?????Ș?ə?Ǘ?Ǘ??˛?Ǘ?Ș???˛?͝???Ғ?????????˛??????QQQQQQ????ə?UUUUUU????͝????ʚ?ʚ???А?˛???ʚ?ə?Ғ????QQQQQQ?Ξ?Ξ?ʚ?ə?˛???ə?ʚ?ŕ??Ξ??Ɩ????˛??ʚ???ʚ?Ξ??ϟ?PPPPPP??Ξ?ə???Ǘ?ə??Ĕ???Ɩ?Ɩ???Ó??’??????’?ŕ???????????????Ș??????’????????????????Ĕ???????????????????????????????????????Ó????????Ĕ??ʚ?????????QQQQQQ?????’????Ĕ?Ș?ə?PPPPPP?Ĕ?Ș?֖??Ș?ŕ???Ĕ???Ɩ?Ș?Ș?ə????А?А?̜???ϟ?̜?̜?Ξ??˛??͝???ϟ?ϟ?Ɩ?Ĕ??Ɩ??Ǘ?ə??Ó????????Ǘ???А????˛?UUUUUU?ϟ??Ș?ʚ??????ʚ?’???Ɩ?Ș?????̜???̜??Ξ?̜??SSSSSS??Ɩ?Ǘ?Ș????ϟ??PPPPPP???SSSSSS????ə?ə?Ɩ??͝?QQQQQQ??Ǘ????͝??ʚ??ܜ?PPPPPP?QQQQQQ???SSSSSS?PPPPPP???Ǘ?ʚ???Ó??ϟ??Ĕ???????????’?Ó?Ó??Ғ??’??????????Ĕ??????????????????????????????????????????????????????????????????ə??А???????????Ɩ?????’?Ó????ŕ?ϟ????Ó????TTTTTT?Ĕ?Ó?????Ǘ???RRRRRR?͝?Ԕ?А?ϟ?̜?????RRRRRR?ё?Ξ?ϟ?ʚ?А?WWWWWW?______??˛??Ɩ?Ǘ?ə??Ɩ??Ǘ?ə?PPPPPP?Ɩ???Ó?˛?Ɩ?ŕ??Ș??͝?А?ё??А??ə??ʚ?ʚ?˛?RRRRRR?ӓ????ŕ??ə?͝??˛????Ɩ?Ξ???˛??ə?RRRRRR?ϟ???Ǘ?ə??А???PPPPPP?ϟ?ə?Ș??SSSSSS?˛???˛?˛?̜?Ғ??Օ?QQQQQQ?Ξ???ʚ???֖??ё???Օ???Ș?Ș?̜?ŕ??Ó???ŕ????’????Ó?Ó???Ĕ??А????Ó???’?????????????????????????????’???????????????????????????????????????????????Ɩ????????????????Ó??’???SSSSSS?ϟ?SSSSSS?͝?Ǘ??ə??Ĕ?Ĕ??’?’?ŕ????ʚ??Ξ???˛?Ș?ʚ??ʚ?ٙ??PPPPPP?RRRRRR??QQQQQQ??Ξ?Ξ????Ɩ?ʚ????ʚ??RRRRRR??Ɩ?????Ǘ??Ɩ?Ɩ?ʚ?ʚ?̜?Ғ?͝?͝??ʚ???Ș?ʚ?˛??SSSSSS?А?PPPPPP??Ǘ??ʚ?̜???ə?????ϟ?˛??˛?Ξ???ŕ?Ĕ???ʚ???ə?Ș?Ș?ə?Ș?ʚ??ə?????Ș?Ξ?̜???ϟ????Ǘ?˛?Ξ?????͝?Ș?ə??Ɩ????Ĕ?Ĕ????????????????????????????????ŕ??????????????????????????????????????????????????????????????????VVVVVV?ŕ??Ó??????’????Ó???TTTTTT???֖?Օ?͝???ə???ŕ??ŕ??̜?????????˛??[[[[[[?ʚ?͝????VVVVVV??PPPPPP?XXXXXX??XXXXXX?̜?˛?ə?Ǘ??Ǘ??Ǘ???ё????????Ĕ?Ș?ŕ?ŕ?ŕ?????????˛??ŕ??Ǘ???˛?̜?ə??ə????Ș??Ĕ?????ʚ??ё???Ǘ????Ǘ?ʚ?ŕ???Ɩ???ʚ?ʚ???ʚ?VVVVVV?̜?Ǘ?ʚ?ə?ё????Ǘ?????Ș???̜??Ș???Ș?????ŕ?’?’?Ó?ŕ?’???͝??????????Ș????ʚ?????’???????’?Ó????????????̜??????????????????????????????????????????????????????????????Ó??Ĕ??ə???????????ŕ?ŕ??PPPPPP???????’???ə??˛?ŕ????Ǘ?PPPPPP??[[[[[[??ё???????ə?ʚ??Ɩ??QQQQQQ???ŕ??̜?̜?ʚ??Ș??Ĕ????Ɩ?Ǘ??ϟ??????PPPPPP??ʚ?ə??Ĕ?Ș???ə??ŕ?Ɩ?Ș?Ĕ???Ș????ŕ??̜??????Ș?ə?ə??Ș?Ǘ???Ǘ?Ξ???????ϟ?ə?ə?ϟ???ϟ?Ș????Ғ??͝??ə?͝??ʚ??ə??Ɩ??Ĕ?ŕ?Ԕ?ə??˛???Ǘ???Ξ?ŕ?????’?А?????Ĕ????’??’?????’?ŕ?Ó?ё???’??Ɩ??Ĕ????Ó???Ĕ?????????????????????????????????????????????????????Ó?Ξ?Ș???????????ؘ?ښ??Ó??’?Ș?Ξ?Ǘ??ŕ?Ǘ???????Ǘ??Ó???Ș??Ɩ??ŕ?ŕ?ŕ??ϟ??Ғ?А??Ⲳ?ݝ?ӓ???’??Ǘ?Ș???ə?Ɩ??А?˛?ё?̜?ŕ???Ɩ????Ǘ??ϟ?̜??ə???^^^^^^?Ғ?ʚ??Ó??ŕ?Ǘ?’???ŕ?˛???ə?ŕ?Ɩ?˛?Ǘ??Ǘ??ə??Ɩ?Ǘ?Ǘ?ə???Ǘ????̜?˛??͝??ϟ??͝?͝?̜??RRRRRR?Ǘ?ə?˛?˛?ϟ?ə??Ɩ?Ĕ?̜?ə?UUUUUU?Ș?ʚ??ə??Ș?Ó?Ξ?????’?QQQQQQ?Ș?Ó??RRRRRR?ϟ?Ș??ٙ?RRRRRR?Ĕ????Ó??[[[[[[?ŕ?Ó?’?ŕ???????’??????Ó?Ó?А?Ξ?Ǘ?Ĕ??????˛??А?’??????????????????????????????????????????????????????????????????????Ĕ???Ó???’?’?ŕ????̜??Ș??Ɩ?Ó????Ĕ???????QQQQQQ??Ș?ϟ?ə?Օ??А?Ξ??Ó???Ĕ?????͝??Ĕ?ŕ?Ǘ?Ó??ŕ?Ξ?ŕ??ŕ?Ș?Ș?˛?????ə?ZZZZZZ????????’???Ș??????Ó??ŕ?Ș?Ĕ?Ș????ŕ????ə?ʚ?ʚ?Ǘ?ə?ϟ?Ș???˛??ё??̜?˛??ϟ?ʚ???Ș?͝????˛?Ɩ??Ĕ?Ɩ??ə??’??Ó?????ŕ?’?Ó?Ĕ?ə??ŕ???????????Ó?Ó?Ó??̜?Ó?͝??????Ș????Ș????Ɩ?ŕ?Ғ??ŕ??ӓ??Ԕ?㓓?444444??˛??Ó????????????????????????????????????????????’??????????Ǘ????????????????Ó??????PPPPPP?ə?PPPPPP??\\\\\\??̜?̜??Ĕ?????’??Ĕ???Ĕ??ё??Ǘ????˛??Ó????Ɩ??Ș???’?Ĕ??Ĕ???Ĕ?Ĕ??Ǘ??ŕ?Ɩ?Ǘ???ŕ???Ĕ??ϟ???Ș??Ó?’?Ó?’?Ĕ??ʚ?Ĕ?Ĕ???ŕ?Ș??̜?Ǘ????Ǘ?Ș?Ǘ??Ɩ???Ș?ʚ??ʚ?͝??UUUUUU???ʚ?ٙ?ʚ???˛?˛?ə??Ș???Ǘ??Ɩ?Ɩ?????Ó??Ó?Ĕ??’?Ĕ???’??Ó???’??????ʚ??Ĕ???Ĕ????Ó?’?????Ǘ???Ĕ??Ș????ŕ????А?Ξ?Ξ?PPPPPP?Ԕ?̜?Ғ?______?Ⲳ?涶??Ǘ?Ó??Ș???????????????????????????????????????????????’???????????????Ó???????’???ə???ϟ??RRRRRR??PPPPPP?Ș???????????Ĕ?’??’???̜?Ș?RRRRRR?ӓ?Ǘ?Ș???ŕ?ŕ?Ĕ??Ĕ?Ĕ?ə?Ǘ???’???Ó??Ɩ????Ǘ?ə?Ĕ??ŕ??Ĕ?Ĕ?Ɩ??ə?ʚ??Ó???Ó?’???Ĕ?Ɩ?Ǘ?ŕ?ŕ?Ɩ??Ĕ?Ĕ???????Ǘ?????Ɩ??ŕ?˛?ʚ?Ξ????PPPPPP????˛??Ș??VVVVVV?˛??ʚ?ʚ?ə????Ș?Ó?Ó??????͝?’?Ó????’?????????VVVVVV?Ɩ???Ĕ????????Ó????ŕ????ϟ???????͝??????Ԕ???RRRRRR?qqqqqq?㳳??˛?Ԕ??????????????????????????????????????????????????????????????Ғ???ə??????????ŕ?ə?Ԕ?ߟ?Օ?Ғ?RRRRRR?YYYYYY??PPPPPP?Ĕ????????’??Ó?Ĕ???Ĕ?Ș?̜?ə?ŕ?Ĕ?Ĕ?Ó??̜?Ó????Ɩ????Ĕ?Ó???Ó?ŕ???ŕ?Ĕ?֖??Ǘ?ŕ?Ǘ?Ĕ??????’?????Ó?’??ŕ?͝??Ó???Ɩ?Ĕ???ŕ??Ó????Ș?ŕ??Ɩ??Ș??Ș??ӓ???͝?ʚ???Ǘ??Ԕ???Ξ??Ș??RRRRRR?XXXXXX?ϟ?Ǘ??Ɩ?’?Ĕ?ŕ?Ɩ?????’?Ó?????’????????Ó???’?’???PPPPPP???’?ŕ???Ǘ?Ɩ????Ó?ə????’???’???QQQQQQ?ښ??ᱱ?ܜ??SSSSSS??ؘ??ə?RRRRRR??ŕ???’?ӓ????????????????????????????????????Ɩ????????????????????????Ĕ????Ĕ?Ó?????˛?ə??XXXXXX?]]]]]]?Ғ????ŕ?????’???˛?PPPPPP???’??А?Ĕ?ŕ?̜?Ɩ?Ĕ?ŕ?????’???????Ó??’??’???????ŕ?Ĕ???Ó?????’?ə?Ĕ?Ó??Ĕ???Ĕ??Ĕ???ŕ?Ó??Ș?Ș???ŕ?’??Ғ?Ó???Ș???Ɩ?Ǘ?˛???Ș??˛?ʚ?˛?̜?̜???Օ?????Ǘ???PPPPPP?ə?Ɩ??Ԕ????Ǘ??QQQQQQ??’???ŕ?Օ?’?’?’??’?????ŕ????’???Ɩ??????PPPPPP??Ó?Ǘ?Ɩ?????Ɩ????Ó?’??ŕ?WWWWWW???SSSSSS?Ǘ?ٙ?????ə???ӓ?Ĕ??ŕ?VVVVVV????????????????????????????????????˛????????????????????QQQQQQ????ŕ??Ɩ?Ǘ??Ó?’????UUUUUU?ŕ?PPPPPP??????Ξ?????ŕ??Ĕ?????Ó??????Ĕ?˛??Ǘ??????’??Ɩ??????????????’??’??’??Ó?Ĕ?????ŕ?ə???????????Ĕ?̜?Ξ?Ɩ?Ɩ?????Ó???Ɩ??Ɩ??ʚ?TTTTTT??Ș???ŕ??Ǘ??????PPPPPP???RRRRRR??Ɩ?RRRRRR???Ĕ??Ɩ?Ǘ??’???’?’??Ǘ????????Ɩ??Ɩ??’??ŕ??Ǘ??’??ӓ???Ó?ŕ?’??͝?????Ó??????̜?????Ó?ӓ?Ó?̜???Ɩ?˛?ŕ?͝?’??Ǘ?’???Ó??????????????????????Ó?????????’?????????˛????????????????????WWWWWW?????’??UUUUUU?Ó???͝??PPPPPP?Ξ?????PPPPPP?Ɩ???Ǘ???????????’????Ó??Ĕ??Ɩ?ŕ??Ó???Ǘ??Ǘ??Ó??Ó??????????Ó???Ó?ŕ?????????’????????????ё???ŕ??Ĕ?ə?Ɩ?Ó????Ǘ????Օ???ʚ??QQQQQQ??͝?pppppp????˛???Ș?͝???Ǘ????Ó??????Ó??Ó?????????????Ǘ??????Ɩ???????ʚ?’???Ĕ??’?????Ș?Ó???????????ё???Ș?????˛??Ĕ?А?ŕ?????????????????????????????????????˛?????????????????????˛??Ó???????’?Ó?Ó?????SSSSSS???͝?Ξ????’???’??’?’????????’??Ĕ?Ó?Ó?????Ó??’?Ǘ????????????????ŕ?Ó?????????????????’?????Ĕ?ŕ?PPPPPP?ŕ?’?????’??Ș?͝?˛???Ԕ???QQQQQQ??Ĕ?Ĕ?Ɩ??ʚ?ё?ח?А???????’?Ó?Ǘ???????????????????????Ó???’??ё????Ș?̜??͝?Ĕ????ŕ??????̜?Ǘ?????????????’??Ɩ????????’?Ĕ?ə????????????????????????????????????????????????????????Ɩ?______?WWWWWW??????’????’??’?ޞ?PPPPPP?ʚ???Ɩ?ŕ??????????????????’??’???Ó????ŕ?Ó?Ĕ??Ș?????Ǘ?Ó???????????????????????????????’?’?Ó??Ɩ?˛????Ó?ʚ???Ș????ۛ?ݝ???Ǘ?Ɩ???Ĕ?ʚ??ŕ?Ǘ?Ĕ??Ǘ??’????’?????Ó????????????????ʚ???????Ĕ???Ǘ??̜?Ó???????’?Ó??????͝???’?Ɩ?ŕ?Ó???˛???????????Ĕ????????????????????????????????????????????????????????????Ĕ?’?Ғ???ʚ?????Ξ??????͝?Օ??ə?’????????Ĕ???????Ó?????Ó?????????Ĕ?’?Ξ??ə?ח????ŕ?Ó???????????????????Ǘ????ŕ?’??????????ə??͝?[[[[[[?SSSSSS?????Ǘ?Ș???]]]]]]???XXXXXX?YYYYYY??ə??Ĕ?Ĕ?’??Ĕ????Ó??’???’?ŕ?Ó???????????????????????????????Ғ??ʚ??RRRRRR??????????????????Ó?Ĕ?Ĕ???????’??????????????????????????????????????????????????????????????????Ĕ?????Ș????͝??Ǘ????????????????’????Ó????’??????????Ó?’??’?’??Ĕ?????????’???????PPPPPP??????????????????????????Ó?ʚ??Ĕ????’??Ó?ə?Ǘ??RRRRRR??Ⲳ??’?????Ó???Ó?’??Ș?Ɩ???ə???????’????????????????????Ĕ?????’???SSSSSS?Ɩ???????????????Ĕ??????????????????????????????????????????????????????????????????????????????Ɩ???VVVVVV???Ó?ŕ??Ɩ??ߟ?\\\\\\?ϟ??????????????’????Ĕ?Ó??ŕ???Ó?????????’???????????????????????????????????????Ɩ??????????????͝???????PPPPPP??ӓ???Ó???’??Ĕ?Ó?????ŕ?Ǘ?Ɩ??˛?YYYYYY??????????Ɩ?????????????????Ĕ?’?????˛???’??ə?QQQQQQ????Ó?’?????????????????????????????????????????????????????????????????????????????????????Ș?ZZZZZZ?Ș?ʚ?ʚ?ŕ??Ó?Ǘ?ё??TTTTTT??ʚ?????????????’?????’?Ĕ?????????Ǘ?Ĕ?’????????’???’??????’?????????Ó????????????????????????Ɩ???QQQQQQ????Ĕ?’??Ĕ??Ғ???ӓ?TTTTTT?˛?????Ș?Ξ??????????QQQQQQ?’??Ó?????????????????????Ĕ???????Ó?????ʚ?????????????????????ə?Ɩ????????????????????????????????????????????????????????????????????????Ǘ?ϟ?Ó???????ښ???SSSSSS??ŕ?????????????Ó?’??????Ɩ??Ș??̜???Ĕ?????????????Ó?’?????’????????????????????????Ó???????’???????????Ĕ?’???Ɩ????????֖??Օ???????????Ș??ŕ??????????????????????Ș??????????’?????Ĕ??????????????????????????????????????????????????????????????????????????????????????????ӓ???????Ĕ??VVVVVV???˛?Ξ??Ó????????????ŕ??’??Ĕ??’??Ș??ӓ?ϟ?А?ŕ?????’?’??????????????????’???????????????????????????????????????Ĕ?????????????͝???????’????????????????????????ŕ?????ʚ???????????????????????????TTTTTT??????????????????????????????????????????????????????????????????????????????ϟ?Ĕ???????Ĕ??????’????Ǘ????????????ə?????Ǘ?UUUUUU?ϟ?????????????’????Ĕ?Ǘ?Ǘ?Ǘ??Ó????’?????????????????????????????’????????????????????????????’?????????????????????????????????????????????????????Ǘ????????????????????????????????????????????????????????????????????????????????????͝?ё??͝????Ĕ??ŕ?Ó????????????’???????Ó?’???????Ɩ?ё???????????’?????????????Ó?????????????????????????????????????????QQQQQQ????????????????Ó????’???????Ǘ??????????????????????????????????????????????????????????????????????????????????????????????????????’?????’???’?’?????’?’????????Ɩ???????Ó??????Ɩ??Ó?Ĕ??Ǘ?ŕ??Ǘ?Ș???’??Ș?Ɩ?͝?PPPPPP??UUUUUU?^^^^^^??͝?̜??ə?ё??PPPPPP?ŕ?ŕ?ŕ?Ɩ??Ɩ??Ǘ???’?????Ξ?Ĕ?Ĕ??Ó???????Ǘ?ŕ???Ó???Ó??????’??Ǘ??Ĕ?Ó??ŕ???Ĕ?Ǘ?Ș?ʚ?Ǘ??Ș?Ɩ???Ɩ??Ș?Ǘ??Ĕ??Ǘ????PPPPPP?˛??Ĕ???’????Ó?͝??Ǘ?Ș?˛??Ξ?̜???????̜??Ó??????Ξ????ə?Ǘ?Ș??Ó?Ǘ?Ó?Ó?Ó?ə??’?Ó???????????????????????ŕ???????????????????????Ĕ??’???????????????????????’???’??’???????Ɩ???????????’???????Ĕ?ŕ?Ĕ?ʚ?Ɩ????ϟ??Ĕ?Ó?ŕ?ŕ??Ɩ?Ĕ?Ĕ??Ǘ?Ĕ??Ɩ????WWWWWW?ᑑ??А?????Ғ?̜?ə?ŕ?Ǘ??Ș?Ĕ?????Ĕ??????ŕ????????Ó???Ĕ?ŕ?Ó?’????Ĕ??’?Ó?Ĕ?Ó???’?’???Ó?ŕ?ŕ??Ș??Ș??Ɩ?????Ĕ??ŕ??Ĕ?ʚ?ŕ??Ǘ?ʚ??Ș???Ĕ?Ǘ??????ŕ?ə????ə?ӓ???RRRRRR??SSSSSS?ӓ?RRRRRR?Ξ?RRRRRR?ϟ??͝?͝?Ǘ??ӓ?˛??Ș??Ĕ?Ĕ????????Ĕ?Ĕ?Ó?’??Ĕ??????????????????????????????????????????????????????????????????????????????’?Ɩ????’??’????Ó???????Ș?Ĕ?Ɩ?Ɩ?Ó?Ĕ???А?Ĕ???????ʚ??Ó????Ó??Ó???RRRRRR??ӓ????Ǘ?????Ș????Ɩ?Ɩ?Ǘ?Ĕ?Ĕ?Ĕ?ŕ??Ɩ?Ó?Ĕ?Ó??’???Ó??ə?????Ĕ???’?Ș??Ó?Ɩ???’??Ĕ????Ǘ?Ɩ?ŕ?ŕ?ŕ?Ĕ?Ǘ??ə???ə?͝?Ș???̜?ə??Ș?͝??ʚ?͝??Ɩ???˛????Ǘ?ʚ?˛?????ʚ????Ɩ?UUUUUU??PPPPPP?RRRRRR?RRRRRR?QQQQQQ?Ξ???QQQQQQ???А??ϟ???̜???ŕ??Ɩ?Ș?Ș???Ș?Ó?Ǘ?Ĕ?????’???????????????????????????QQQQQQ?????????????????????’??????????????’???????????????Ó??Ĕ???Ó?????Ĕ?Ó?’?????’?ŕ??’?Ǘ?Ɩ??Ɩ???ʚ?˛?Ǘ?ə?Ǘ?ʚ?Ɩ?ŕ?’??ϟ??????Ó??????????UUUUUU??Ғ?SSSSSS???Ǘ?Ǘ?Ɩ?˛???ŕ?ŕ??Ó???????ŕ?’?ŕ?Ɩ?ŕ?Ó???????’?ŕ?Ó?ŕ?ŕ?Ó?Ó??ŕ?ə?ʚ??Ɩ?ə?Ǘ?ŕ??Ĕ??’??ŕ??Ɩ?˛??˛?ə?˛?PPPPPP?̜???????ə?̜?ʚ???ə?Ș??Ǘ???Ș?ʚ?Ĕ?’??Ș?˛???ə??Ξ??̜???XXXXXX???TTTTTT?ё?TTTTTT????PPPPPP??ϟ??Ǘ?ə??Ɩ?Ɩ???’?’?Ó??Ĕ??ə?’?Ó????????ŕ??????????????????Ɩ??’?˛????????????????????????????????Ó???’????Ó??’???????Ó????Ó????????Ó????????ŕ????Ó??Ǘ?ŕ??????Ș???ə?Ĕ?˛??’?Ó??Ĕ?Ó???ə?̜??Ș??ϟ??Ξ??ʚ?ə?ŕ?Ĕ????’??Ó????Ɩ???’??Ǘ??Ó?Ó????’??’??Ĕ????’?????Ó??Ĕ?ё???ʚ???Ǘ?Ɩ?Ó?Ó?Ó?ŕ??Ó??ŕ?ŕ??ϟ??ʚ?PPPPPP???̜???ʚ??Ξ??˛?PPPPPP?̜?̜?ŕ??̜?ə??ə????͝?????ʚ?˛??SSSSSS?Ԕ?XXXXXX???QQQQQQ??????͝?RRRRRR?ё???????’?????Ș?Ĕ??ə???????????????????????????ʚ?ŕ?Ó?Ɩ???????????????????????????Ș?????’????????Ó?’???????????????Ɩ???Ĕ??Ó?Ó?Ó?Ĕ?’???Ǘ??Ɩ??Ɩ??Ó?Ó???Ǘ??Ǘ????Ó?Ș?????ŕ?ϟ?Ɩ??ə?ə?ŕ?????Ǘ???ϟ????ŕ?Ș??Ó??’???ŕ?Ɩ??Ɩ???Ǘ??????QQQQQQ?????????Ó?’????Ó??ŕ????????ʚ?????Ó??ŕ?????ə??TTTTTT????˛?˛??QQQQQQ?ϟ???̜?QQQQQQ?ʚ?̜?ŕ???ϟ??̜???Ɩ???Ǘ??ϟ??SSSSSS?Ԕ?TTTTTT?Ԕ?RRRRRR?QQQQQQ??֖?Ғ??А??UUUUUU?Ξ??Ԕ???ə???ŕ??Ɩ??ŕ????’?’???????????????????????????Ɩ??????????????????????’??’?????’???Ó???????????????????????Ĕ?Ɩ????Ó?’?Ǘ??ŕ?’?ŕ?Ĕ??Ɩ?̜????’?Ɩ???Ĕ?’???ϟ?QQQQQQ?pppppp???Ɩ??????????Ɩ??Ɩ?Ĕ???Ǘ?ŕ?Ɩ?ə?ʚ???Ɩ?Ĕ??Ɩ???Ó?Ĕ??Ɩ?Ɩ?ŕ?PPPPPP???’????????????????Ĕ???????????Ĕ???ŕ??Ó??????Ș????Ɩ???ё?QQQQQQ??ё?ϟ?RRRRRR?͝?Ξ???ё??ŕ??ŕ??RRRRRR?Ξ???????ʚ??Ĕ??????UUUUUU?VVVVVV??SSSSSS?ё???PPPPPP??ё??Ғ?????Ǘ???Ǘ????Ó????Ĕ??’???????????????????????????????PPPPPP???????????????????’????????Ó???????????????????Ĕ??Ó??Ó???Ó????Ĕ?͝?Ɩ?????PPPPPP?YYYYYY???Ĕ???ŕ?Ǘ?ə?ŕ?Ĕ?Ξ???555555?VVVVVV?Ĕ?’???????Ș?ŕ??ŕ?ŕ??Ɩ?’?ʚ?Ĕ??ŕ?Ș??ʚ?ϟ?ӓ?ə?Ǘ??Ɩ??Ɩ???Ó????Ó?????????Ó?Ǘ????’??’?Ĕ????Ĕ?Ó??Ó????????ŕ??????ʚ?Ǘ??Ǘ??ŕ??ʚ?ϟ???ZZZZZZ?ӓ?А?QQQQQQ?PPPPPP??̜??Ғ?˛?Ǘ??Ǘ?QQQQQQ???RRRRRR?UUUUUU???Ɩ????Ɩ??Ғ?ё?ё??TTTTTT??֖?Ғ?ӓ??Ғ?Ԕ????Ԕ?????ŕ?Ɩ??Ó?Ș?????’???’???????????????????Ǘ?ŕ???????’?͝??????????????͝?SSSSSS?’??’????Ĕ????Ș????????Ĕ????????????????????Ó????Ĕ?А?ə??А?ə?Ɩ?Ԕ?Ș????Ș??ə?А??ŕ?ŕ??Ó?ə????Ǘ?Ɩ?Ĕ??????Ǘ???ŕ?ŕ???Ɩ???Ɩ?Ǘ????SSSSSS?ٙ??Ș??ŕ?Ĕ???Ĕ???Ĕ??Ĕ?’??Ĕ??˛???????’??????Ó?ŕ?’??????????’???????Ɩ??̜?˛???ə?ŕ?ŕ???ŕ??А????А?ϟ????ϟ??PPPPPP??ə?⒒??А????͝?Ó??ʚ?Ɩ??RRRRRR?PPPPPP?QQQQQQ?QQQQQQ??QQQQQQ??ZZZZZZ?______?ё??͝?]]]]]]???ё?А??Ғ??Ǘ??ŕ??Ǘ?Ș??????’????????????????????????????????????????????????????’??ə?ŕ?Ĕ????????????Ĕ??????’?????ʚ?????Ǘ?ŕ??А??Ĕ??ə?ё?ʚ?Ɩ?ŕ???Ș?????Ғ?Ɩ??ə?Ĕ????˛?Ĕ?Ó?Ó?Ɩ?ŕ???ŕ?ŕ?ŕ??Ǘ???Ș?Ó?Ó?Ĕ?Ó??Ɩ?ə?ۛ?XXXXXX???Ǘ?ŕ??Ĕ?Ó???Ĕ?????Ș???????????????’??’??Ó?Ĕ??Ó??Ĕ??’??ŕ?’?Ó??Ó?’?Ξ?????ʚ?ŕ?˛??????Ǘ?Ξ??YYYYYY??PPPPPP?TTTTTT?PPPPPP?PPPPPP??PPPPPP?ӓ??????TTTTTT?ϟ??А?QQQQQQ?PPPPPP?ʚ?Ó?’?ə?XXXXXX?????222222?????SSSSSS??ϟ?????ϟ??̜?Ξ?Ș??ŕ??Ɩ??’????Ó?Ó?????????’??????Ғ???????????????????????????’????Ǘ?????Ɩ?’????????????Ó???????’??????ŕ??Ǘ?˛?ё?ŕ?ʚ??Ó?Ɩ???ʚ???Ș?Ξ?Ș?????ʚ???ʚ?ӓ?PPPPPP??Ǘ??Ĕ?ŕ????Ǘ?’??Ĕ?Ǘ???Ó?ŕ?˛??Ɩ?Ĕ?Ó???????Ɩ?А?????Ș?˛?Ɩ???’?Ɩ???Ó???Ó?Ó?Ĕ??’???????Ǘ???Ĕ?Ĕ?’???’??’??Ó?Ĕ?Ó??Ó???????Ĕ??’????̜????ŕ?Ó??ё????QQQQQQ?QQQQQQ??Ғ?ϟ??ϟ?Ξ?ʚ??ə?˛?͝?______??Ғ?Ξ??Ξ????ё?ё?PPPPPP?RRRRRR????Ԕ?ё??ښ?Ғ??VVVVVV??ӓ?PPPPPP????Ǘ??˛???Ș?????Ó??А???????????????Ó?????????????ŕ?Ĕ?Ó????????????ʚ?????TTTTTT??’???ϟ?Ș??????????̜?Ɩ?’??’??????Ó???Ɩ?Ǘ?Ó??Ó??͝?SSSSSS??Ĕ?Ó?А?ʚ??ŕ??ŕ?Ș?ə?ŕ?Ǘ?А??Ș?ə???Ș??̜?ʚ?Ĕ??Ǘ??Ǘ?ŕ??Ó???Ǘ?Ș?ŕ??Ǘ????????????Ξ?Ǘ?̜?ޞ?ё??ŕ???ŕ?ŕ???Ғ?Ó?Ĕ????ʚ?’??’??Ĕ????Ó?’??’???’??Ĕ?’????????’?????ٙ???????Ǘ??ə?Ș?Ɩ???ə?˛???˛?ϟ???????TTTTTT???ə?Ǘ?Ș?Օ?Ғ??͝??????Ғ?Ԕ?ё???֖?Օ?Ғ?QQQQQQ??Ғ?ӓ?ٙ??ؘ?ZZZZZZ???˛?˛?????̜??Ĕ??Ó?̜?ʚ??Ǘ????????????’??????????????????????????????????’?Ɩ??ʚ?????????????Ó??Ɩ?Ĕ?’????????Ó??’?Ĕ?ŕ???ӓ???Օ??????????Ĕ?ə???Ĕ?Ó???ŕ???ŕ?Ó??ё?ʚ?Ɩ??????’??ʚ??ŕ????Ǘ?Ó?Ó?????????Ĕ??RRRRRR?ؘ?????????ŕ??????’?????Ó???????’??Ó????Ó??’?’??’????ŕ??Ǘ??Ș?ʚ?А?Ǘ?Ĕ???Ǘ??Ɩ??ŕ??Ș?Ǘ?ə??͝???ϟ??Ξ?PPPPPP?͝???PPPPPP??Ǘ???ٙ?̜???ח?????ϟ?͝???Ғ?qqqqqq?QQQQQQ?ϟ??ё?Ԕ??VVVVVV??ܜ??̜?RRRRRR???????̜??ŕ???Ɩ??’???????????????’??????????????Ĕ???????????????????˛?ŕ?Ș???’?Ó??ə??Ǘ?Ó???Ĕ???Ɩ?Ó????????’??????Ș??͝??Ɩ?А?̜????QQQQQQ?Ǘ??????]]]]]]?Ș???????Ó??Ĕ?Ó????????Ó????ŕ??????????????????ϟ?????’??Ǘ?Ǘ??ʚ????ϟ?Ó??’??Ș??Ĕ??’??’?’??Ó??Ĕ?’?????Ó??’?????ŕ?Ó??Ɩ?ə?Ɩ?Ș?˛?Ǘ??Ǘ?Ș?Ș??Ǘ?Ɩ??Ǘ??Ғ??͝?Ξ?̜??̜?ϟ?А??PPPPPP??˛?ʚ??̜????ӓ?SSSSSS??Ɩ??ə?Ξ??Ғ?YYYYYY??YYYYYY??PPPPPP?А?Օ?UUUUUU??ߟ?\\\\\\??????Ξ?????Ǘ?Ɩ???ə?ə??????Ó?’????????’????????????Ĕ??????????’??????????????????’?????????????’????Ó??˛????Ó?ŕ??ŕ?ə???˛?Ș?̜??ӓ?VVVVVV??ё?????Ó?Ó?????????Ó?????Ó??’????ə???Ɩ??͝????Ĕ???Ĕ??’???’????͝???ŕ?Ó?Ș????????˛??Ξ??Ĕ???’??ŕ????Ĕ??Ɩ?’?’??Ĕ?Ó?????Ó?ŕ?’??????Ĕ??Ș??QQQQQQ??Ș??ə???Ș???ŕ??ŕ?Ĕ??˛???А???TTTTTT?ӓ??͝??ə?Ǘ??̜?А?PPPPPP?QQQQQQ??˛????????Ғ?VVVVVV???Օ???SSSSSS??SSSSSS?Ғ??????Ξ?˛?Ș??Ɩ?????˛?Ǘ??’???Ĕ???ŕ???’?’???’??’???????????’??’???????????????????’??Ĕ???????’??????????Ĕ?Ó?????Ǘ?ŕ???Ɩ???ə?ʚ?˛?Ǘ???????˛????Ɩ?Ó?????????????’??ŕ?Ó??Ɩ???Ǘ????Ĕ?Ɩ?QQQQQQ?Ó?’??????ŕ???’?’???Ó???’????ə?Ó??Ĕ?̜??’????Ó??????ŕ??Ó?Ɩ??Ĕ????Ó?Ó?Ĕ?Ș????ŕ???????Ĕ?Ɩ???Ǘ?ʚ?ʚ?PPPPPP??ʚ???Ș???ŕ??????Ξ???˛?ϟ????ٙ?ə??????ʚ??˛???????ŕ???ח?֖?YYYYYY??qqqqqq?XXXXXX??SSSSSS?RRRRRR?PPPPPP???̜?̜?????Ǘ?Ɩ?Ɩ?Ĕ?ŕ?ə????’?????????????????????????’????????????????????Ó?????????̜??????’?????????????????˛?Ǘ??ʚ??˛?ə???Ɩ???˛?????Ó?’???????????Ɩ?Ǘ??Ĕ?ŕ???’??Ɩ?????QQQQQQ?Ĕ???PPPPPP????’?А??’????????Ó??Ó?????ŕ??Ó??˛???ə?Ĕ????ŕ?Ɩ????ŕ?ŕ?Ó??Ɩ?Ǘ??ʚ??ə??Ĕ??ŕ?’??????ŕ???’?͝?XXXXXX????ʚ??Ǘ?????????˛?PPPPPP??PPPPPP?̜?А?PPPPPP?̜???Ș?˛?ח??Օ??˛????̜?͝??ə?’?Ó?ӓ?ӓ???ᑑ??SSSSSS?UUUUUU??̜?˛?ə??˛????ə?̜??????ϟ?Ξ?????????????’????????????????Ǘ?’?????????????Ó?????Ó???????̜???????RRRRRR?͝???????Ĕ??Ĕ?͝?Ó????ə?˛?ʚ??Ξ??Ғ???Ĕ??˛?Ɩ?Ɩ?Ǘ??ŕ??Ɩ?Ș?????Ɩ??’???Ĕ?Ó?????Ó?’?’?Ĕ??’?Ĕ????Ĕ?????’??????’????’?????Ĕ?’???Ó???Ó?’??[[[[[[???ŕ?Ɩ?ŕ????ϟ??Ĕ???ŕ??Ɩ??ə???Ș?ŕ????’??Ĕ???????’?Ǘ??Ĕ?Ĕ?ŕ?ə?Ș?Ɩ?Ș?Ɩ??Ó?Ɩ?Ɩ??̜?ʚ?ӓ?͝???̜???̜??Ș????Ξ??ϟ?˛?Ș??ə?ʚ?ʚ?Ɩ????ё??Ԕ??????????ϟ?ə??ŕ??Ș?Ǘ??Ξ???’??Ǘ??????Ó???????ŕ?Ó??Ó????????ʚ????Ǘ?Ɩ???????????????????’??’???????Ĕ??Ĕ??TTTTTT??????????Ó??Ɩ????ŕ???????Ó??Ɩ?YYYYYY???ʚ?ʚ?ə?Ɩ?Ǘ?Ǘ????Ĕ?ŕ???Ó?’??ŕ??????Ĕ?Ó?Ó?ŕ??????’???’??’???’???Ó?????’???Ș???Ĕ??Ó???Ó????ŕ?Ɩ?Ɩ???Ɩ?Ɩ???Ǘ?ŕ?ŕ?Ĕ?Ĕ?Ɩ?Ș??Ǘ?Ș?Ș??ŕ?Ǘ?Ǘ????Ĕ?Ó??Ɩ?Ɩ?Ĕ?Ɩ??Ó??Ó???ŕ?ə???Ɩ??ŕ???Ĕ?Ɩ?͝?????Ξ?̜?˛?QQQQQQ??ϟ?ə??Ɩ??Ғ??ח?QQQQQQ??Ș?Ș?Ș??Ș??’?????SSSSSS???TTTTTT?Օ?SSSSSS?QQQQQQ?????˛???ŕ??????Ɩ?Ǘ?Ĕ?????’?Ó????????’?’?????????Ș???Ɩ?ə???????????’?????????????ۛ?ə???????’??????????Ó??Ĕ?Ǘ???????ϟ?Ξ?Ɩ?Ɩ??ŕ?Ғ???XXXXXX?ə?Ɩ?Ғ??Ɩ?Ɩ????Ɩ?Ș?ŕ???????’????ŕ?Ó??Ĕ??Ĕ?Ĕ???Ó????????Ɩ?Ĕ?’??Ĕ??’???’????’??Ĕ?’???Ĕ????ŕ?Ș?ŕ?Ĕ?Ó?????Ó?Ĕ???Ɩ?Ǘ???Ǘ?Ɩ?Ǘ?ə??Ș?ʚ??Ș???ŕ?ə?????Ǘ?ŕ??Ș?ŕ?Ĕ?’?ə?˛???ə?Ǘ?????Ǘ?ʚ?SSSSSS????̜?Ș?ʚ??ϟ?˛?ʚ?ʚ?ʚ???ϟ?͝???ə?ə???ʚ???ŕ?????ؘ?VVVVVV?TTTTTT?Օ?SSSSSS??QQQQQQ?͝?ə??ʚ?ʚ???ə?????ŕ?’?’??Ó???????????’??Ó???’???????????Ó???????????????ŕ???Ĕ?????????Ĕ???Ó??????’??Ó?Ó?’???????Ĕ?Ș??Ǘ??ə?ӓ???XXXXXX??777777?WWWWWW?????Ó???Ș?Ĕ?????ŕ???ŕ????’???ŕ?’?Ó?Ó??’???????’????????????’???????Ó?Ó?’??’?ə?ŕ?????Ĕ??Ó??????????ə??Ĕ??Ɩ?Ɩ????????ʚ?ʚ?ʚ??ə??ə?ə??ʚ??Ǘ?Ɩ???˛??˛??Ș?˛?Ξ?ə?ə????˛????Ș?Ξ?ϟ???˛??ə??ʚ?????̜???Ș??Ĕ??Ș????Ԕ??WWWWWW??Օ?UUUUUU?SSSSSS??͝?ӓ?ʚ?????ښ??????Ɩ????Ĕ????ŕ?ё??’?????????Ó?’?Ĕ?’????????’??????????’?????ʚ?’??????Ș?Ó??’????????Ɩ??ӓ??Ĕ?????ə??ʚ?ʚ?Ɩ?????QQQQQQ???[[[[[[???̜???Ǘ????Ó????????ŕ?Ĕ?Ó?Ó?’?Ɩ?’????????Ó??’???’??’??????Ɩ?Ó???Ó???’????Ĕ?ŕ?’??ʚ??Ĕ?˛???ŕ??????Ɩ?˛???Ș?Ǘ?????Ǘ????Ɩ????Ș?ʚ?ə?Ξ?ə?Ș?˛???˛?˛???Ǘ???Ș?Ɩ??ʚ?Ș??͝?Ș?͝?Ξ??ə???Ǘ???̜??ə??А??Ԕ?А????ʚ?͝???̜?ə?Ș??Ș?????˛?˛?????Ԕ??ӓ?Ғ?UUUUUU?ᱱ?Ξ???̜???ə?Ǘ??Ɩ?ӓ?ŕ?Ó?ŕ??Ș?????Ǘ?PPPPPP???????’?Ĕ????????͝????ϟ???????????’?????ܜ?Ĕ?Ĕ??’?’??͝?̜?Ĕ??????’?????????Ó??Ĕ?’??ŕ?ښ?ə???’???Ξ??ח?Օ???Ó??????Ó?Ĕ?Ĕ?????????Ó?’?Ɩ????’?????Ĕ???????Ɩ??Ĕ?Ĕ???????Ó?Ó?Ó???’??’??Ó??Ó?Ș???Ɩ?ŕ??Ǘ??Ǘ?Ɩ?Ɩ?Ș?ə??ʚ????????ə???Ǘ??ŕ?’??ŕ?ʚ?ʚ????Ξ?ё?̜????Ǘ????Ǘ????Ș???Ș?˛?˛??˛???ϟ?Ǘ??͝???̜??Ξ???͝???ϟ???ə?Ș?Ș?ʚ????Ĕ???Ĕ????\\\\\\??SSSSSS?TTTTTT???Ғ???͝?А??˛??Ǘ?Ɩ????Ɩ??ŕ?ŕ???????’???ŕ????????Ĕ?????Ó???ŕ?????????????Ó????ə?????ŕ???Ó?ŕ????’????Ĕ???Ĕ?’?Ó?’?Ó?ə???Ó?Ĕ??ŕ??Ó??ŕ???Ș?Ǘ??Ǘ?Ó????Ĕ?????ŕ?ə?Ș???̜?Ǘ?Ǘ????????’?’?ŕ??Ó?Ĕ??Ǘ?ŕ?Ó?Ó?Ɩ?Ǘ?????Ĕ??Ó?ŕ?Ó???’????Ɩ?Ó?Ó??Ó?Ó?ŕ?Ș???Ɩ?Ĕ??Ó???ŕ?Ɩ?Ǘ?Ǘ??Ǘ??Ș?˛??Ξ??Ɩ?ʚ?QQQQQQ??Ǘ?Ɩ???Ǘ?ə?????UUUUUU???Ǘ??????Ș??Ɩ?Ǘ??Ǘ?ə???ə?А???ʚ???Ǘ?ŕ?ʚ???ə??QQQQQQ??Ξ??Ξ?͝?ə??̜?˛?????̜???Ǘ??????ϟ?Ғ?ٙ???QQQQQQ??Ǘ?̜??Ξ?͝????Ĕ????Ĕ?Ĕ??Ǘ??˛?Ǘ?Ĕ?Ɩ?Ó?Ĕ?Ĕ?Ó?Ɩ?Ó??Ĕ????’??̜???Ĕ??????Ɩ???????????ϟ?WWWWWW?????Ɩ???Ǘ???Ó?Ó???Ǘ?Ĕ????Ó??????Ĕ????ŕ??Ó???Ó?’???Ó?Ó?Ó?????ё??Ș??ə??ŕ?Ǘ?????ə?Ș?А?Ɩ??Ĕ?????Ɩ????ŕ?Ș?Ǘ????QQQQQQ???Ĕ?Ĕ??ə???Ó?Ɩ??Ɩ???’???ŕ?ŕ??ŕ?ŕ?Ĕ??Ɩ??Ɩ??ŕ?ŕ??ŕ?ŕ?Ĕ??Ó???Ĕ?ŕ??̜??ə?ə?PPPPPP??Ǘ??Ș??Ǘ????Ǘ?????Ξ?ə?Ɩ?Ǘ?Ș?Ɩ???˛?ʚ?ϟ?Ș??ə?ə?Ș?ə??Ǘ??͝????ə??ə?ŕ?????Ξ?̜?ё???̜???˛?ʚ????ϟ??ʚ??Ș?Ɩ??Ξ???Ξ?RRRRRR???ӓ??˛?А????А?͝??ə??ŕ??ŕ????Ɩ??Ș??PPPPPP????Ĕ??Ɩ???’??’??????????????????ə?????Ǘ?̜??Ó?Ó?Ĕ??ʚ?Ș?ŕ??Ó??Ó?Ó????Ó?Ó?’??’???Ó?????Ĕ????’????Ĕ?Ó??Ĕ??’??ə????????’?ə?˛?Ǘ?Ǘ??Ɩ???˛???Ĕ?ŕ??Ó??Ĕ?Ó???ŕ??ŕ??ŕ??ʚ?Ɩ?Ĕ?Ɩ??Ș?Ɩ?Ǘ??Ș???Ĕ????Ɩ????Ɩ?ŕ??Ĕ???Ó?ŕ?????ŕ??Ĕ???ŕ????ə??Ξ??ʚ??PPPPPP??????Ǘ?Ĕ?Ĕ??????̜?А?ə?ŕ???Ǘ?ə?̜??˛?͝?ə??ə??Ɩ??Ɩ??ϟ?ϟ?̜?˛??Ɩ?Ó?ŕ??Ș???????͝?͝?˛?̜???˛??͝?˛?˛?͝?̜????̜????ח?Ԕ?ZZZZZZ???ϟ????Ξ????Ɩ????Ǘ??Ĕ?Ɩ?ŕ??????Ǘ???’???Ó??????????Ș????Ǘ???????????Ó????Ԕ??’???Ɩ?Ĕ??Ǘ???Ĕ??????????Ó??????Ó???’??????Ĕ?Ó?Ó?’????ə?VVVVVV???ə?̜?ŕ??Ɩ??ŕ?Ó?????PPPPPP?Ǘ??’?????Ĕ?Ĕ??Ĕ??Ɩ???Ɩ?Ǘ?˛?Ǘ?Ș??Ǘ??Ξ?͝???ŕ??Ǘ???ʚ?Ǘ??Ș?Ǘ?????Ș?Ș???????Ș?Ǘ?Ɩ?Ĕ???ŕ?Ξ?ə?Ș????SSSSSS???????Ɩ?Ɩ?ŕ??̜?Ξ??PPPPPP??ə?Ș?ʚ?QQQQQQ?Ș?Ǘ?ʚ?????????Ǘ?ŕ?Ǘ?Ɩ????ʚ?ə??Ɩ?Ó?Ó?Ǘ???ə??ϟ?ё??˛??̜?ə????Ξ?Ξ???͝?Ξ?ʚ?ə??ϟ?ё????RRRRRR??ӓ??????А????????Ǘ?Ǘ????ŕ??ə???Ɩ?????’??????’?RRRRRR??????Ó?ŕ??’?????????????Ғ?SSSSSS?PPPPPP?Ó?ŕ???Ǘ???????????????Ĕ???????Ĕ?ŕ???Ĕ????????Ǘ??ʚ?ח?666666?ᑑ??ʚ?Ǘ?ə???ə??’??Ș?Ɩ?Ξ?Ɩ?ə?Ĕ???Ĕ??Ĕ?ʚ??Ĕ????Ǘ?PPPPPP?ə?ə???Ș??Ɩ??ə??ə??ʚ?ə??˛?ə?ʚ????QQQQQQ???͝?̜??????????Ĕ?????˛?ʚ??Ș?Ɩ?А??SSSSSS???ŕ?Ɩ?̜???Ɩ??Ɩ?ə?Ǘ??????͝????ə?̜?Ǘ????Ș?Ș?????????ə?Ș?Ș?ə?Ó??ŕ?Ĕ??ə?ə?ϟ?А?Ξ?А?˛?̜????̜??ϟ???ϟ?А?͝??ə?????̜?ϟ?ϟ??TTTTTT??PPPPPP?QQQQQQ???QQQQQQ??ə?ʚ?ə????Ĕ?Ĕ???Ó?Ɩ?ZZZZZZ?Ǘ??Ɩ?Ó??’?Ó?Ó?????’?’????Ó?Ɩ????’??Ó?Ǘ??????????͝???Ǘ?Ș???\\\\\\???’???????Ĕ???????Ĕ?’???????Ĕ?Ó?Ɩ????ŕ?Ɩ?????А???뻻??ϟ?Ξ??ə??Ș?ə??Ǘ??Ɩ?ə???????Ș????ŕ??ŕ??Ǘ?ə?QQQQQQ?Ɩ?Ǘ?Ǘ?͝?͝?͝?ʚ???Ǘ?Ș??ʚ?Ș?ϟ??А??ϟ??Ξ???˛??̜??ə?ə?˛?Ș?Ξ?Ɩ?ŕ??ŕ???Ǘ?Ǘ?Ș????ё?Ș?͝?А???Ǘ?Ș?????????̜?????ё?ə?˛?ʚ????ʚ?͝?ё?ə??˛??ə?ʚ?????ʚ???ŕ??Ǘ?ŕ?Ɩ?Ɩ???????͝??ϟ?˛???˛???А?Ξ??ʚ?ʚ??Ԕ???А??Ξ?ϟ?ё??????RRRRRR?ə?Ș??ə?ə?Ș?ŕ??????̜??А????ŕ?Ó???????Ɩ?’?Ó??Ĕ?Ó?Ó?Ó?Ĕ????’?Ó???????????Ó?Ɩ?????????????’????’??Ó?’??ŕ?’?’?Ó?’???Ș?̜??ŕ?’?Ó?ŕ?Ó???Ș???ϟ?[[[[[[?999999?666666???????????ə??ŕ?Ĕ?Ĕ?Ș?͝?ŕ?ŕ?ə???Ș??Ǘ?Ɩ?Ǘ?ŕ?Ĕ????Ș??????˛??????ʚ??Ξ?????̜?ə???ʚ???ŕ????Ɩ???Ɩ??Ɩ??Ɩ??Ɩ?Ǘ?ŕ???ə???Ɩ??PPPPPP?˛????Ĕ?????Ĕ??˛?ё?Ξ?ə??PPPPPP?̜?ə?˛?QQQQQQ???˛?ʚ??????ə???Ξ?ə???ŕ??Ó??Ș??˛?VVVVVV?˛?˛????͝?͝????ə????????TTTTTT?А??Ξ?ӓ????ٙ??㓓??Օ??ə????͝?˛?Ǘ???ŕ??????PPPPPP?’???’????Ó???????Ĕ?’?????ŕ????????????????????Ξ?’????Ĕ??????’?Ó???????’??Ó???̜?֖??Ĕ??Ó?Ó?Ó?Ξ?ŕ???Ξ??TTTTTT???Ғ?̜???Ș???Ξ?А??̜?˛????А????Ɩ???˛???Ș????Ș?Ș?ə?ə???̜?????ʚ?Ș??̜?˛???RRRRRR?˛????ŕ???Ǘ?Ɩ?ŕ?Ɩ?Ɩ?WWWWWW?Ș?Ǘ??Ș????Ș??Ǘ?ŕ???Ș???Ș?Ξ??̜???????’???ŕ??QQQQQQ?????’?ə??Ș?ə??̜?ё?PPPPPP??ə?̜?ə?Ǘ??ə?ə?PPPPPP??Ɩ??Ɩ?Ǘ?’?Ɩ?Ɩ?Ɩ??Ξ?̜??QQQQQQ?̜?̜?????̜?ʚ??????̜?ʚ?ə??Ǘ???QQQQQQ???RRRRRR?ٙ??????????ə??Ș?’???????Ĕ???’?????Ó??Ó?Ó??Ó????Ó??ŕ??’?ŕ????Ĕ??????????Ó????’?????????Ó???’?’???????Ó????Ĕ?Ó?Ǘ???????ŕ?ə?????ښ??Ξ?ϟ??ə????ŕ?Ǘ??ϟ???ӓ?QQQQQQ??ʚ?Ș???ŕ?ŕ??’?Ǘ?ə??ə?Ɩ?Ǘ?ə??Ɩ?ʚ?͝???̜??͝???˛?˛?????̜??ə?Ɩ?Ǘ????ӓ?Ɩ?Ǘ?Ǘ?Ɩ?Ș?ʚ?Ǘ?Ș?ʚ?Ș?????Ș?????Ó?Ó????VVVVVV?TTTTTT?ə???Ó?Ĕ????????ə?͝?????ŕ?ʚ?˛?ϟ???А?˛?Ǘ?Ĕ?????Ș???Ó?ŕ?QQQQQQ?ŕ??’?Ĕ???ё?̜?SSSSSS?ё?Ғ??Ξ?ʚ?Ș??̜??ə??ə???̜?Ғ?Ǘ??Ș????˛?˛??Օ?YYYYYY?Ⲳ?ర???SSSSSS?Ξ???ʚ????Ĕ???????Ó??Ǘ?Ó?????????????’?Ó?ŕ?ŕ?Ɩ?Ó?ŕ?Ó?ʚ?˛?̜??Ó?????????????????????Ɩ??????Ó?????ŕ??????Ĕ??Ĕ?Ó?ŕ?ŕ?˛??Ξ?QQQQQQ?ӓ?ӓ??̜?ӓ??ʚ?ŕ?Ǘ??͝??̜???ʚ??????’??Ĕ??Ș?Ĕ??̜??ə???ə??͝?˛?˛??PPPPPP???Ξ??ʚ????͝???Ș??ʚ?ə????ə??˛??˛??Ǘ?Ǘ?Ǘ?????ə?ʚ????Ɩ????Ĕ??’?Ș?ʚ????ZZZZZZ?Ɩ????Ó?Ĕ?’??ə?Ș??????Ĕ?Ɩ??ə?QQQQQQ??͝?Ξ?ʚ?˛??Ǘ?ə?Ș??????’??ə??’?̜???RRRRRR???QQQQQQ?Ξ??̜???Ș?ə??ʚ???ə????ϟ?͝???’????ə??ߟ?䔔?ښ?VVVVVV?А????Ɩ?ʚ??̜???????Ó??Ó?ŕ???’????’??’??????’?Ĕ??Ĕ?ŕ?ə?RRRRRR??Ó????Ó???????????????˛?Ó????’?̜??Ɩ????ə??Ș??ŕ??Ó?????’?Ĕ??ŕ???Ó?’??͝???ə???Ǘ?PPPPPP?Ǘ??͝?PPPPPP??А????ə???Ș??Ĕ?Ĕ??Ó?ʚ?ŕ????ə???͝?UUUUUU?PPPPPP??̜???̜??????̜??ʚ?͝??Ξ???̜?Ș??ə?̜??ə?ə?ə?ʚ??ʚ?Ș??Ɩ?Ɩ?ə????Ș?Ș??Ɩ????Ĕ?Ǘ????Ξ????Ǘ?Ǘ?Ĕ?ŕ?ŕ??Ғ??ʚ?˛????̜?˛?Ɩ????Ș?????VVVVVV?Ș??Ɩ??̜?RRRRRR?Ǘ???Ɩ??ŕ?Ǘ?А?Ó??????͝??ʚ?̜???ʚ?Ǘ??˛??˛??̜???PPPPPP??Ǘ?????’??ర????ӓ?PPPPPP??А?ə??Ǘ?Ɩ?Ǘ?Ó?ə??Ó??Ɩ??’?ŕ??Ĕ??ŕ???????????’?Ĕ?Ș?Ɩ?ə?WWWWWW?Ξ?????’?????Ĕ??????Ĕ?Ó?Ĕ?̜??RRRRRR?Ɩ?Ó??Ó?Ɩ??????????’??Ș?’????Ș??Ĕ?˛??????’???Ó????Օ??ə?˛?ʚ?UUUUUU??ϟ?WWWWWW?˛?ʚ?͝?ə??˛?Ș??????Ș??ə?ə?̜?Ξ?͝???ё?͝??ϟ?͝??͝??͝?͝???Ξ??ə????А?̜?ʚ??̜?͝?ʚ????̜?ϟ???ə??Ɩ?ŕ?ŕ?RRRRRR??ʚ?ŕ?Ǘ?Ǘ?????ə??????PPPPPP?Ș?Ș?Ǘ?Ɩ??Ɩ?????ŕ?˛?Ș?Ș?’???Ξ?Ș??ʚ?˛?Ș???ʚ??ŕ?Ș?????????Ǘ???ŕ??Ĕ????̜?̜?Ξ?˛?˛?˛?ʚ?ʚ?ʚ??˛??͝??ϟ?А??͝?Ɩ?Ó???Ș??̜???UUUUUU??Ғ??Ғ?????Ǘ?ə??Ɩ?Ĕ?’???????Ĕ?Ó??Ó?Ĕ????????’???Ó??’??Ǘ?’?ə?Ɩ?Ș?Ɩ?’?Ó?Ɩ???????’?Ó?Ɩ?ŕ?’?Ș???’???????????ŕ?’?’??Ș?ŕ?’?????Ó?ŕ???ŕ?Ó????’?’?Ĕ???Ғ???̜??͝?͝?ё??Ԕ?̜??Ξ?PPPPPP??Ɩ??Ș???ə??ə??Ξ??͝?͝??PPPPPP??ё?Ξ??А??̜??Ξ???˛???А?А???ϟ???Ξ????ʚ?̜??̜?ə?˛??Ș?ə????ŕ?Ĕ???ŕ?????Ș?Ș?ʚ??А??ё??ё?Ǘ????͝???Ǘ?Ɩ?Ɩ?Ĕ?Ǘ????ϟ?Ó?ŕ??˛?Ɩ?ё?Ǘ??ə?Ɩ???????Ó???ŕ??Ɩ????Ó??͝?ə???ə??˛??˛?Ξ????̜?Ξ??ϟ??̜??ŕ?Ó???RRRRRR?ə???PPPPPP?Օ???WWWWWW?Ξ?˛?Ǘ?Ɩ???Ξ??Ș?Ɩ??Ĕ?Ɩ?Ĕ??????ŕ?ŕ????ŕ???Ĕ?’????Ó????Ɩ?TTTTTT??˛?ŕ?Ĕ???????Ĕ?Ó??Ĕ??Ĕ?’?Ĕ?ŕ?͝????’?Ó??Ș?????ϟ????ŕ?˛??Ó?’????Ĕ?ŕ??Ǘ???Ɩ?Ó?????Ɩ?̜??ϟ??Ξ?Ξ?QQQQQQ??Ș???ə?̜?QQQQQQ?̜????̜??͝?̜???ϟ?ϟ?ϟ?????QQQQQQ???SSSSSS???͝?͝?Ξ??ӓ??͝???PPPPPP??RRRRRR??Ԕ??Ξ?̜?͝??QQQQQQ?˛?RRRRRR?ϟ??PPPPPP?͝???Ș??ŕ????ŕ?Ǘ?Ǘ?Ș?Ș??Ș?Ǘ?ŕ??????PPPPPP????ϟ?͝?Ξ?Ș?Ɩ??Ɩ?Ǘ?ё?Ɩ??’?Ǘ?Ɩ?Ĕ?Ɩ?ʚ?QQQQQQ??ŕ?Ĕ???Ɩ??ʚ?????Ξ?????ŕ????Ĕ?Ș??̜?˛?????Ξ?ʚ??˛?PPPPPP?̜??????’??Ș??ʚ????А?ϟ?ӓ?ٙ?Ғ?SSSSSS??˛???˛??Ș?Ǘ?ŕ??????Ĕ?Ó??Ó?ŕ?Ĕ?Ó?Ó?Ó???Ó???ə?Ɩ?’???’??’???ŕ?Ó?????’?????Ș?Ș?ϟ???????????Ó???Ó?Ó?̜?ё??Ș?ə?ŕ??????’???Ɩ???ŕ?’????Ɩ??Ɩ?Ǘ??Ș?˛????TTTTTT?̜?А???ʚ???????̜?͝?RRRRRR?ə??А????ϟ??QQQQQQ???RRRRRR??ё???ё?Ԕ?RRRRRR??QQQQQQ??ё??QQQQQQ??ϟ?Ғ????ӓ??А???˛??˛?????̜?˛???Ǘ?ə?Ǘ?Ǘ?ŕ??ŕ??????Ĕ??ŕ?ə?ё?ə?Ș??˛??????Ș??Ɩ??SSSSSS??̜????ŕ?Ș??Ĕ??Ó??Ó?????Ș?Ǘ?Ɩ???ə??ʚ??ʚ?ʚ????Ξ?ʚ?˛?ʚ?ə?˛??ə???PPPPPP??XXXXXX?????̜???Ĕ??????Ξ??Ԕ??Ԕ??Ξ???ə?ʚ?Ș????Ɩ??ŕ????ŕ??Ǘ????Ó?Ó??’?????ӓ??Ĕ??Ĕ??Ó????Ĕ?’???????Ɩ??’???QQQQQQ??’?’?Ĕ??’???’?’?’?????Ξ????????’??’???Ó??’?ʚ??????Ĕ???Ș?ʚ?Ș??ə?Ξ?͝???̜???PPPPPP???ə?ə????̜?͝???PPPPPP?QQQQQQ?А?QQQQQQ?????ӓ???RRRRRR?SSSSSS?PPPPPP??RRRRRR??XXXXXX?????ӓ??Ғ?SSSSSS???Ғ?SSSSSS???????ʚ?˛?͝??Ξ???˛?̜?ʚ?˛??Ș?Ș?Ș?Ș?Ș????Ĕ???Ĕ??Ξ?ʚ?ʚ??Ɩ?ə??ʚ????Ș?Ș?Ș?А????ə?Ș??ə?ʚ?Ǘ?Ș?????Ǘ?Ɩ??Ș?ŕ?Ǘ???ʚ???Ξ?Ԕ????Ĕ??Ǘ????˛?̜?͝???ə?Ξ??????˛??Ș??Ĕ???Ó??ŕ?̜???TTTTTT??ё?̜?͝?Ș??ə?ŕ???Ǘ??Ó?ŕ?’?????ŕ???’????’???’???Ɩ?Ǘ???Ó??????’??????ə??????????????????’??Ó??PPPPPP??Ғ????Ĕ?’???ŕ?Ξ?Ĕ?Ó???’???????ʚ???Ԕ?̜??PPPPPP?ӓ?PPPPPP?ʚ?ϟ?Ξ?˛?ϟ?????ё???̜?ϟ?????Ξ???QQQQQQ?Ғ?Ғ???UUUUUU??ϟ??Ғ??XXXXXX?Ғ???RRRRRR??Ғ??ӓ?ӓ?Ғ?Ԕ?SSSSSS???ё???RRRRRR?????ϟ???͝??˛?ʚ?ʚ???Ș?ə??ə?????Ǘ?Ɩ???ə?˛??????ə?˛????Ǘ?͝?͝??QQQQQQ???ʚ?Ĕ???PPPPPP?ŕ?˛???Ǘ??Ξ?ʚ??Ғ??TTTTTT???ʚ???͝????ŕ?ə?˛???˛?Ǘ?ə??ə??˛?????˛?̜?͝??Ǘ?ŕ??Ó??Ĕ??ŕ??RRRRRR?Ξ????͝?ə???Ș?ʚ?Ɩ?Ș??ŕ?????’???’?’????????’??Ĕ????????Ǘ?ʚ??’?’???????ŕ?Ξ??’??????Ĕ?’???’???????Ó?ϟ??ŕ?͝??Ǘ??Ș?Ó?’???Ó??’????Ó??Ɩ?ŕ?ə???˛????ӓ??Ξ?̜??А??PPPPPP?RRRRRR??Ξ?????֖???Ғ?˛??ə?ϟ?ϟ?PPPPPP?PPPPPP??А????SSSSSS?PPPPPP?ӓ?QQQQQQ?ח?А????Ғ?SSSSSS??TTTTTT?ӓ??Ғ?????А?̜?̜?SSSSSS?̜?ə??͝??RRRRRR?QQQQQQ?ϟ??͝?͝???˛?̜?А?̜??ə?ϟ????ə??Ɩ?˛?͝?̜?̜???˛?ʚ?̜?ə?Ǘ?ə?˛?????А???Ș?Ǘ?????Ɩ?Ǘ?ŕ?Ǘ????ə?ə?ӓ?˛???ə??˛??ə??Ș??̜????Ș????А???А??Ξ?Ξ?ʚ?˛????Ǘ?????Ĕ??̜??QQQQQQ??˛??????ŕ?Ĕ?ə??Ǘ??Ĕ?Ó??Ɩ??Ɩ????????????Ș???Ɩ?’???Ĕ???’???А?????ŕ?ə?ʚ?’???Ó?Ĕ???’?ŕ?????????˛??Ĕ?ə??Ɩ???PPPPPP?А???Ĕ?’???Ĕ????ŕ????ə?????TTTTTT??[[[[[[??SSSSSS??Ξ??ё?А???Ξ??ə???PPPPPP?ϟ????Ξ?PPPPPP??͝??Ξ??TTTTTT?ZZZZZZ?ё??ϟ?QQQQQQ???Ғ?ё??RRRRRR?Ғ?UUUUUU??ӓ?TTTTTT?TTTTTT???RRRRRR?SSSSSS?PPPPPP?͝??˛?QQQQQQ??Ғ?˛?ϟ?SSSSSS??Ԕ?UUUUUU??VVVVVV?ё?Ξ?ё?͝??͝???Ξ???ё??????̜?̜?̜?̜?Ξ??Ξ??̜?͝??Ξ?ϟ?Ғ??͝??˛???Ș?Ș?Ɩ???????Ǘ???Ș?Ǘ?˛?А?PPPPPP?Ξ???ё?ʚ?????PPPPPP??ʚ?ə??ə?Ǘ?А??ϟ?Ξ?А?̜?Ξ?Ξ???ə??Ɩ?˛?????Ș??Ǘ?͝??ʚ??˛??ʚ????Ș?Ǘ???˛??’??ə?Ó?Ó?Ó???????’??’?Ș??Ԕ??Ó????????’??Ĕ?????????PPPPPP?Ɩ?????͝??Ĕ???’???Ó?ϟ?’???Ĕ??Ǘ?????ŕ?Ĕ?????Ó?????͝?А?YYYYYY?ə??????QQQQQQ?ӓ??ё?PPPPPP??̜?ϟ???А?SSSSSS????Ξ?QQQQQQ?Ξ??SSSSSS?Օ????͝???Ғ?QQQQQQ?Ғ????QQQQQQ???RRRRRR??ӓ?Ԕ?TTTTTT?Ԕ??ٙ?Օ?Ԕ?ё?RRRRRR?Ғ?SSSSSS??ə?Ș?ϟ?????QQQQQQ??֖?UUUUUU?SSSSSS?????Ғ?TTTTTT?QQQQQQ?Ξ???ё?А??˛?Ξ??͝???̜?Ξ??ϟ??RRRRRR?А?ё?PPPPPP??̜?PPPPPP?Ξ?????QQQQQQ??????Ĕ?Ɩ?ə?Ș??PPPPPP???˛?ə?ə?ŕ?ə??ə?˛?˛?????Ș?Ǘ?RRRRRR???˛???ʚ???????ϟ?͝???̜?ə??Ș????Ĕ??˛??Ǘ??Ș??RRRRRR???̜?ŕ????Ș??͝????’?????????Ș??’??Ǘ????ə???????Ó??????’??Ɩ?????˛???Ĕ????’???’???????????????Ɩ????Ĕ??ʚ??’??˛?̜???Ξ???QQQQQQ??WWWWWW?VVVVVV?QQQQQQ???ə???̜?˛????Ξ?ϟ?VVVVVV??А?PPPPPP??ӓ?ۛ?^^^^^^?ϟ?Ξ?̜?ϟ?А?QQQQQQ?ё??Օ?[[[[[[?ؘ???XXXXXX??Ғ??YYYYYY????֖?ӓ????SSSSSS?Ԕ?????SSSSSS?֖?UUUUUU?TTTTTT??ӓ?֖??TTTTTT??Օ?Ғ?֖???RRRRRR??PPPPPP??А???ӓ?ϟ?͝?А?˛?͝??ϟ????ϟ?QQQQQQ?ё?QQQQQQ??PPPPPP???ə???А?Ș?ʚ?Ξ??̜?Ǘ???ə?ə?ə?ə?ʚ?Ș???ə??Ș???????ʚ???˛?????͝?PPPPPP??Ғ?SSSSSS???Ɩ????͝?ϟ?ϟ?˛??ŕ??Ó????Ǘ?Ǘ?̜?????˛?̜????ŕ?ŕ?˛?Ǘ???Ó?’?Ó?Ó?????’???Ɩ??’?Ó??Ĕ??Ó?Ó?’?’?????????????????Ɩ?Ɩ?ŕ?Ó?Ǘ??’?????’?’???????Ĕ????’?Ĕ??ə??????Ǘ???????ӓ??PPPPPP?ϟ????͝?͝???̜?Ғ?͝?Ξ?PPPPPP???ʚ????͝???̜?ӓ?SSSSSS???PPPPPP????TTTTTT??SSSSSS?֖???Օ?SSSSSS?Ғ???֖?ؘ?????ӓ?Ғ???VVVVVV????TTTTTT?֖????______?Ԕ?ٙ????UUUUUU?UUUUUU?ח?TTTTTT????PPPPPP??PPPPPP?Ξ??QQQQQQ???QQQQQQ??ə??PPPPPP???QQQQQQ???PPPPPP??PPPPPP?ϟ???˛?Ξ????????˛?̜?Ș??Ș?Ș?Ξ?Ș?͝??ʚ?ʚ?̜??ʚ?ə????Ǘ??ŕ?Ɩ?̜??˛?ə?͝?˛??̜?Ξ???˛??????Ξ??Ξ?͝???ϟ???’?ə?????А??Ξ?̜?͝?ə?ŕ?ŕ??ŕ??Ĕ??Ɩ???????’?’?????Ó??Ĕ?Ĕ?Ĕ?Ĕ?Ó?Ó??????????????Ó??’??????????Ĕ?Ó?Ó?Ĕ??Ĕ???????Ó?????????ϟ?ʚ??ŕ?ʚ???PPPPPP?QQQQQQ?PPPPPP??ё?QQQQQQ???XXXXXX??А????PPPPPP??ё??PPPPPP?PPPPPP???ϟ??RRRRRR??PPPPPP???PPPPPP?˛?А?ӓ???SSSSSS?XXXXXX?ݝ???֖??ٙ???YYYYYY??YYYYYY?֖???ӓ?TTTTTT?RRRRRR?Ғ?SSSSSS?SSSSSS?TTTTTT??UUUUUU???VVVVVV????ᱱ?ؘ?WWWWWW?YYYYYY??嵵??ؘ?UUUUUU???TTTTTT????QQQQQQ?͝?ϟ???RRRRRR?ё?UUUUUU????˛?Ξ?QQQQQQ???А???̜?А???͝?͝??͝?ϟ?Ș?Ǘ????ϟ???Ș??ʚ??͝?ə?Ɩ??Ș?˛?ə??ʚ??ʚ????Ɩ?Ǘ?????ϟ?ʚ?PPPPPP??Ξ?Ɩ??ə????͝?ё???ё?\\\\\\??ʚ??ʚ????Ĕ?ə?͝??ё?QQQQQQ?Ξ?͝??Ɩ??Ĕ??Ɩ?Ɩ?Ǘ?ӓ?Ɩ?Ɩ??’?’???’???’??Ó???PPPPPP???Ɩ?Ĕ?Ɩ?????????’?????ʚ???Ǘ???’??????Ó??Ó?’?’???????’?Ó??????Ɩ??˛??ə?Ǘ??Ɩ?ʚ?̜?TTTTTT???̜?͝?????XXXXXX?Ξ??PPPPPP?RRRRRR?QQQQQQ?͝?ϟ?ё??А???Ғ?А?RRRRRR?ё???Օ?RRRRRR??Ғ??______??ܜ?????ܜ?????ܜ??ؘ?֖?YYYYYY??UUUUUU??ZZZZZZ???ח?VVVVVV??Օ?Ԕ?Օ?ٙ???ؘ?????PPPPPP?uuuuuu???UUUUUU??ӓ????UUUUUU?QQQQQQ?̜??QQQQQQ??ӓ?Ғ?Ғ?SSSSSS?Ғ???PPPPPP????͝??Ș??˛?Ș?ʚ??Ԕ?̜??˛???Ɩ?Ĕ?Ș?ə??̜??ə???̜?????ə?ʚ?ə????˛?????Ɩ?ϟ??ё???Ɩ???ŕ?ŕ?ə??˛?͝?Ξ?͝??А?А?Ξ???ə?̜???Ĕ?͝??͝?????͝?˛?ŕ??Ɩ?Ǘ??Ǘ????ʚ?’??Ĕ?’????Ș?ŕ????’?’????’??’?’?’????ʚ?????????Ɩ?ŕ???’?’???’???Ǘ?’?Ó??Ó????Ɩ???ŕ?ə?Ș??????Ɩ???Ǘ?Ǘ?????ϟ?͝??ə?ə?̜?ϟ??֖?А?Ξ?????ё??[[[[[[????PPPPPP??ё?SSSSSS?֖??RRRRRR?Ғ?TTTTTT?Ғ?XXXXXX?蘘??SSSSSS??^^^^^^??333333?SSSSSS???qqqqqq?㳳??000000?֖??ח??[[[[[[??????ٙ??\\\\\\??Օ?Օ?SSSSSS?RRRRRR?ښ?ܜ?ݝ??Ғ?XXXXXX?ZZZZZZ?^^^^^^????UUUUUU?Օ??WWWWWW??Ԕ?SSSSSS?????????ӓ?Ғ???А????̜?QQQQQQ??????˛??Ξ?ʚ?˛?̜??ϟ??PPPPPP????????͝???˛?͝??ə??̜?˛????˛?̜??????ə?Ɩ?ə??’?Ǘ??ʚ???ϟ??ϟ?ϟ?˛?˛??˛?ŕ???????Ξ??ϟ??А?˛?Ĕ?Ɩ??ʚ?Ș?ŕ????ŕ??Ĕ?ŕ??’???Ǘ??????????Ó???Ó?????Ó???????Ó????Ɩ?’???’??Ɩ?˛?ŕ?Ș?Ĕ???Ó??’??????ʚ??Ó???ʚ?Ĕ?Ș?Ǘ????Ĕ???Օ??ʚ?ə?Ș??Ș??Ɩ??????˛?????Ғ?Ғ?Ԕ??А??Ғ??ё??QQQQQQ?SSSSSS?Օ??䴴???ݝ???333333?999999?000000??]]]]]]?222222?ۛ??ZZZZZZ??ӓ?XXXXXX???UUUUUU????ర?ܜ????UUUUUU?????pppppp?ښ???UUUUUU???YYYYYY?]]]]]]???______?XXXXXX?WWWWWW?UUUUUU?UUUUUU??ח?TTTTTT????TTTTTT?Ԕ???TTTTTT??ё?PPPPPP????А??Ĕ?????PPPPPP?QQQQQQ?QQQQQQ?ϟ??ϟ?]]]]]]???ʚ??????ϟ?VVVVVV?ё???̜??ʚ???̜??????????QQQQQQ??ʚ??Ș????ə?ə???ϟ???˛?ϟ??̜?Ó????˛???Ξ???RRRRRR?ё?ʚ??????Ș??Ĕ?Ĕ?ŕ??’?’?????’?????Ó????Ĕ??’??????????Ξ?’??????Ó?Ξ??’?????Ĕ???????ŕ??Ĕ???Ș??˛?Ɩ?ŕ????Ș?ʚ???Ǘ???Ș???Ș?Ș??ϟ?А??˛??Ș?˛??Ș?˛?А??ё??PPPPPP???ё?QQQQQQ?PPPPPP?QQQQQQ?ё???PPPPPP??RRRRRR?Օ??ښ??\\\\\\????ۛ??pppppp?YYYYYY?ؘ?QQQQQQ?ܜ???VVVVVV?UUUUUU?TTTTTT?֖?VVVVVV????Ԕ?֖??WWWWWW???TTTTTT?UUUUUU?XXXXXX?????ܜ?ח???֖???YYYYYY?ۛ???????ӓ?UUUUUU??????TTTTTT??????????PPPPPP??ŕ?Ǘ???А?PPPPPP?QQQQQQ?Ξ???SSSSSS?PPPPPP??˛?Ó?̜??Ó??TTTTTT?ᱱ??PPPPPP?????ʚ?PPPPPP????ʚ?Ɩ?Ĕ??ə????̜?ϟ??????Ɩ?ə?ʚ??Ξ?Ξ???А???Ĕ?????PPPPPP?ʚ?͝?ϟ?PPPPPP?PPPPPP?Ξ?Ǘ????ə?Ɩ?Ǘ?Ș???Ó???Ó?Ó????????ŕ???????????????Ó??Ó????????˛????’???Ó?Ĕ??’??Ó?Ó?’???Ĕ??Ó???Ǘ?Ǘ???Ó?????ə?ŕ????Ǘ??˛??˛??˛?ə???̜?˛?ϟ???WWWWWW??̜??˛?ϟ???А?˛?ё?ё???Ғ??QQQQQQ??Օ?Ғ??Օ?ۛ?[[[[[[??SSSSSS?ܜ???ؘ?[[[[[[?ۛ??XXXXXX?֖??QQQQQQ?Ԕ?????RRRRRR?SSSSSS??SSSSSS??ښ?ؘ?ٙ?ٙ??ߟ?^^^^^^??ח??ӓ???֖?֖??YYYYYY???ޞ?ؘ??Ԕ?PPPPPP???֖?֖?????SSSSSS?RRRRRR?PPPPPP??Ғ?Ғ?ё?QQQQQQ?̜?ə????Ξ?PPPPPP?ϟ??VVVVVV??RRRRRR???Ǘ?Ó????ʚ?PPPPPP?ӓ???Ξ?ϟ?????Ξ??ϟ?ə?Ǘ???Ɩ??͝?А?RRRRRR??˛??Ș????????????Ξ?ϟ?˛???Ó?Ĕ??̜?PPPPPP??̜?͝?̜?ə?ʚ?˛??͝??Ǘ???Ĕ??Ǘ?Ĕ???????Ĕ?Ĕ?’??Ó??Ɩ??????????????’?Ǘ???Ó????’??Ó?Ɩ??Ǘ?͝?ʚ?͝?Ĕ?Ĕ?Ǘ?????’???Ș??ŕ???ŕ?Ó??ŕ????ŕ??Ĕ?Ș???˛???ʚ???ə???͝?PPPPPP?SSSSSS??А?ϟ?Ξ???Ǘ???Ș????Ξ???QQQQQQ??ё??ё?ё??RRRRRR?XXXXXX?VVVVVV???VVVVVV??VVVVVV?VVVVVV?ؘ?YYYYYY?XXXXXX??????TTTTTT?SSSSSS???TTTTTT????WWWWWW???ח??ZZZZZZ????ZZZZZZ???????Օ??ٙ?ח?[[[[[[?֖?WWWWWW??[[[[[[??ӓ???Ԕ???TTTTTT???RRRRRR??ё????Օ??ϟ?ϟ?̜??Ξ?PPPPPP??SSSSSS????ё??PPPPPP???̜?Ǘ?˛??QQQQQQ?А?ϟ??ə??ϟ?˛????Ș????Ĕ?Ș??А??ϟ?PPPPPP?˛?Ș?ʚ?˛??̜?˛?А??Ξ??PPPPPP???ϟ?̜?ٙ????Ǘ?Ɩ?ə?˛?QQQQQQ?А?̜??????????Ǘ??Ǘ?Ș?Ó??Ĕ?Ó???Ó??Ó???Ó?Ĕ?Ɩ????ə?????’??Ĕ??Ó?????????????Ξ???ܜ?UUUUUU???Ǘ?Ĕ?’????ё??’??ϟ??ŕ??’?ŕ?Ξ??Ɩ?ʚ?ŕ??Ș?Ș??̜??Ғ????????PPPPPP?̜???ʚ???˛???Ș??Ǘ??Օ?PPPPPP????Ξ?ϟ?ϟ?QQQQQQ?ё??PPPPPP????????UUUUUU?ח?XXXXXX?????WWWWWW?????SSSSSS????Օ??Օ?Ԕ???\\\\\\??Ғ???ؘ??ח?WWWWWW?ؘ??ח??ח??Օ????XXXXXX???TTTTTT?Ғ??ӓ???ӓ??ӓ?TTTTTT?ӓ??????SSSSSS?ё?А?ϟ?А?QQQQQQ?Ғ?SSSSSS??ӓ?Ғ?SSSSSS??А??ϟ??????Ξ?Ξ?ʚ????˛?QQQQQQ??Ξ??????ə??Ғ?ӓ?ϟ???Ǘ??ʚ?˛??̜???͝???А?ϟ?˛?̜???????Ǘ?˛??QQQQQQ?̜??ʚ?̜????͝?̜?RRRRRR?˛???’?’?Ó??’???????????Ĕ??????????’????ə?Ó?’?’?Ó?Ĕ?????SSSSSS?̜?Ǘ?Ξ??SSSSSS?Ɩ??????Ș??֖????Ɩ?ŕ?ʚ?Ș?̜?Ó??Ǘ?????Ș?PPPPPP???TTTTTT?SSSSSS??Ξ?QQQQQQ???SSSSSS?ϟ???А??͝?˛????Ș?Ș??????А?ё?TTTTTT?TTTTTT???ё??VVVVVV??Ԕ????XXXXXX?֖??ؘ?ٙ????SSSSSS??WWWWWW??WWWWWW?UUUUUU?Ғ?SSSSSS?Օ????UUUUUU??????UUUUUU?ӓ???ٙ??XXXXXX??ٙ??Ԕ?VVVVVV??WWWWWW????ٙ?WWWWWW?VVVVVV??????ӓ?ё?SSSSSS????????UUUUUU??TTTTTT?Ғ?TTTTTT??RRRRRR????ח?ܜ?Ғ?ӓ?Ԕ??????ϟ??А?ϟ?PPPPPP???ə??̜?ϟ??А?ϟ????Ɩ???ܜ??Ξ??^^^^^^??ə??Ǘ???˛???PPPPPP?PPPPPP??А?˛?????????˛??͝?ə???ə??͝?ə?˛?̜??Ξ?ə?????’???’?Ĕ??????ŕ?Ó?’??’????????’?ʚ??????Ó?Ĕ?’???͝????Ɩ?Ó??ŕ?Ĕ?’?’?Ó?Ó?ϟ??Ș?Ș???ŕ??Ș??ə??ŕ?????ʚ?Ș???Ғ?TTTTTT?ϟ?ϟ??ϟ????Ғ??ϟ?Ξ??˛??ʚ??Ș?PPPPPP??????Ș?ə?ё?VVVVVV????VVVVVV?Ԕ??TTTTTT?Ԕ?????Ԕ??YYYYYY?Օ?UUUUUU?Օ??֖?ё???[[[[[[?______??ё?????RRRRRR???Ԕ?Օ?Օ??֖?֖?ח?YYYYYY?ZZZZZZ??[[[[[[?YYYYYY?????ٙ?VVVVVV?ח?ؘ?WWWWWW??????????Ғ?RRRRRR???SSSSSS???SSSSSS????SSSSSS?Ғ??Ғ??SSSSSS?RRRRRR??VVVVVV?UUUUUU?RRRRRR?SSSSSS???SSSSSS??ӓ?͝??А??А?PPPPPP??????͝??ϟ?ʚ?А??Ǘ??Ǘ?̜??ۛ??PPPPPP?????ʚ??̜??͝?̜?ϟ?QQQQQQ?ϟ??͝??̜?’??????ə??ə?̜?PPPPPP??̜?Ξ?????͝??Ɩ?Ĕ?Ó??’???Ș??’??ŕ??Ș?Ó??Ó???Ó??’????Ĕ????????Ғ?Ɩ???Ó????Ĕ??Ɩ?’?’????????Ĕ?Ĕ??Ǘ?Ș?Ș?Ǘ??˛??Ɩ?Ǘ??̜?QQQQQQ??ʚ??ӓ??RRRRRR??Ξ?˛???VVVVVV????А??̜???ʚ?PPPPPP?TTTTTT????????А??PPPPPP??ӓ??䔔?ޞ???Ξ??ӓ?Օ????SSSSSS??TTTTTT?????????RRRRRR?Ғ??˛?Ξ?Ғ??RRRRRR????ח???VVVVVV??Օ????ZZZZZZ?ܜ?ؘ???ٙ?VVVVVV?ח?ؘ??000000???ח?ח?VVVVVV?SSSSSS?SSSSSS?TTTTTT?????RRRRRR??RRRRRR?QQQQQQ????ӓ????TTTTTT?SSSSSS???Ԕ?ӓ???ё?RRRRRR?RRRRRR?Ԕ???ϟ?ϟ?ϟ??????̜???̜??Ξ??Ș?˛?Ș??Ș???А??А??????͝?????Ξ?PPPPPP?͝??˛???Ɩ???????????̜?PPPPPP?ϟ??̜?ʚ?̜??̜?Ș?Ɩ?Ó??’?Ĕ??????͝?Ó????’????’????????????’????’?Ĕ????Ș?Ș?Ɩ??ŕ?ŕ???Ǘ?Ș??ŕ?Ș?ə?????Ĕ?ŕ?Ĕ?Ɩ?Ɩ??PPPPPP?RRRRRR???А?PPPPPP?͝???˛?̜??̜??ə?????˛????ə?Ғ???ё?QQQQQQ?TTTTTT?RRRRRR?PPPPPP????PPPPPP?ё????ٙ??Ԕ??PPPPPP??????XXXXXX?WWWWWW??Ԕ???SSSSSS??QQQQQQ?RRRRRR??ё?Ғ?Ғ?Ș?А?QQQQQQ??ё???Օ?֖?UUUUUU?UUUUUU??UUUUUU?Օ?ۛ?VVVVVV?YYYYYY??]]]]]]?ٙ??֖??WWWWWW??֖?WWWWWW?YYYYYY????ښ?֖??ӓ??Օ??Ԕ?SSSSSS??QQQQQQ?А??PPPPPP?А?QQQQQQ?ё??Ғ?????ӓ?UUUUUU???????ӓ??RRRRRR???Ξ??QQQQQQ?QQQQQQ?PPPPPP?͝?????Ξ?ϟ?ϟ?͝??ə???Ɩ??Ș???̜?͝??ə??ʚ?˛??̜????PPPPPP?ϟ??????????QQQQQQ?QQQQQQ?ə?̜?͝??˛???ʚ?˛?ʚ??͝?UUUUUU???ŕ???????ŕ??Ĕ??Ĕ???Ó??????˛?Ξ?Ɩ????Ĕ????Ó???????ŕ?ŕ?ŕ??ə?????ŕ??ə???Ɩ???Ĕ?Ĕ??Ĕ?ŕ??ʚ?˛??А?͝?͝?ə?˛?͝?Ξ??˛?˛?͝?͝??˛?PPPPPP??Ξ?˛?ə?ə??ə???????YYYYYY?PPPPPP?PPPPPP??А??QQQQQQ?PPPPPP???QQQQQQ?Ғ??WWWWWW?TTTTTT??ϟ??QQQQQQ?SSSSSS??ӓ?QQQQQQ?XXXXXX??QQQQQQ?ё?Ԕ??PPPPPP??PPPPPP?PPPPPP?А?͝?˛?ϟ?Ԕ???ח?ח????ӓ?Ԕ?UUUUUU?Օ??????ח?ח?֖?VVVVVV?WWWWWW??XXXXXX???ښ?YYYYYY??]]]]]]??ח??WWWWWW??UUUUUU??Ғ?????ё???????SSSSSS????Օ??????Ԕ?ӓ???ϟ???ϟ?ϟ?Ξ???ʚ???͝?????PPPPPP????˛?Ș?Ɩ??ʚ?PPPPPP??????ʚ?Ξ?Ғ??PPPPPP?Ξ??ϟ?ʚ?˛?Ș????Ș???Ԕ?TTTTTT??ʚ??͝??˛?ʚ?̜??ʚ??ə?????’?Ĕ?Ɩ???Ĕ?????????ŕ????’??’???Ó?Ó???Ó?ŕ????????Ó????Ɩ?Ɩ???Ĕ?Ɩ??ŕ????Ș?Ĕ???ŕ?ʚ??̜?ʚ?˛?????̜?QQQQQQ?̜??˛????А?͝?ʚ??Ξ?˛?̜??ʚ?˛???ё??Ξ??RRRRRR??Օ?Ԕ?ӓ?А?ϟ?А?А??UUUUUU?????Օ???ϟ?ӓ?Ԕ?ӓ?VVVVVV???Ԕ?А?ϟ??˛?͝?͝????ə?˛???RRRRRR??֖??֖??Ԕ?ӓ?ӓ?VVVVVV????֖???YYYYYY??ٙ???VVVVVV??֖??ٙ?ٙ?ZZZZZZ???ښ??ښ?XXXXXX???ӓ?TTTTTT??UUUUUU?ё??QQQQQQ??ӓ?SSSSSS?TTTTTT??SSSSSS??ё?RRRRRR?ӓ?֖?UUUUUU??TTTTTT???SSSSSS?RRRRRR??ё????PPPPPP?Ξ??PPPPPP?ϟ?ʚ?ʚ??ʚ?????Ξ?ϟ?ϟ???ŕ?Ǘ?˛?̜????ə?ŕ????ϟ???ϟ??????Ș?Ɩ?Ș????????͝??˛?˛???ə?ə??ŕ?Ĕ??Ĕ???????’????Ó????????????’?Ó?Ɩ???????Ĕ?Ǘ?Ó?͝???Ĕ???Ó??ŕ?Ɩ??Ǘ??Ĕ?͝?Ó??Ș?ŕ?Ó?ŕ??ʚ?ə?ϟ??ϟ?͝???UUUUUU??RRRRRR?ϟ?Ғ?PPPPPP??̜????Ξ??̜?Ξ???̜?ʚ?Ș???QQQQQQ?А???PPPPPP????Ғ?ϟ??А?ё???֖?Ԕ??VVVVVV?????TTTTTT?Ԕ??Ԕ?PPPPPP?RRRRRR?А????ə?Ǘ?˛?QQQQQQ?Ξ?ə??͝??SSSSSS??WWWWWW??Օ?֖???Օ???TTTTTT???ח?ښ?000000??[[[[[[??ښ???VVVVVV????XXXXXX?ٙ???]]]]]]???ٙ??????TTTTTT?ӓ?ё??Ғ??RRRRRR????ё?Ғ?ӓ?TTTTTT?UUUUUU?UUUUUU?TTTTTT?TTTTTT?֖?SSSSSS??RRRRRR?Ғ???ё??А???ϟ?ʚ?˛?˛??̜?͝?Ξ????PPPPPP?RRRRRR?Ԕ??ŕ??͝??ə??Ɩ??Ĕ?Ș????ϟ??ϟ?ϟ?А???˛?’?Ĕ????????˛????˛?????????’?Ĕ??Ĕ???’????Ɩ?ŕ???ə??????’???Ó?????????????Ó?Ĕ??Ĕ??ŕ???ϟ?Ɩ??’??Ĕ?ŕ???Ǘ??Ǘ??̜?ʚ?А?SSSSSS????ٙ????ϟ?А?????͝?Ξ?˛????Ǘ?Ș?Ș??Ξ??PPPPPP??SSSSSS?TTTTTT?Ԕ?ё???TTTTTT?Ғ??Ғ?Ғ??VVVVVV?TTTTTT??PPPPPP????֖??[[[[[[?ח??А???͝????ŕ??˛?˛?ʚ?̜?А???RRRRRR????Օ?֖????UUUUUU?VVVVVV?Օ?Ԕ???ؘ??ٙ?YYYYYY?XXXXXX???Օ??Ԕ?UUUUUU????WWWWWW???ښ?XXXXXX??ZZZZZZ?ښ?ZZZZZZ??ٙ?ח?????TTTTTT??Ғ?ӓ?Ԕ?Ғ??ӓ?ӓ???Օ?Ԕ???SSSSSS??SSSSSS?Ғ?ӓ??Ғ??Ғ???̜?̜?͝?̜????А?PPPPPP?А??ϟ???Ǘ??Ș???????Ș?ʚ?ϟ??????ϟ?͝??????Ș??Ɩ??̜??PPPPPP???͝?ə??Ș??????ŕ??Ĕ???????’?????????????Ɩ??Ǘ?PPPPPP??????Ș?Ó?ϟ???Ó??ŕ?Ɩ??Ș?ŕ??ŕ???Ĕ???Ó????Ǘ?˛?????͝?͝???SSSSSS???PPPPPP????ח????˛???UUUUUU?˛????Ș?Ș?̜?Ξ?????Ғ?ё????ӓ?А??ё?RRRRRR?QQQQQQ?QQQQQQ????UUUUUU?ؘ?[[[[[[?ܜ?ߟ?ssssss??ё?ё?Ԕ??ʚ?Ǘ?????̜???ӓ?Ғ?SSSSSS??VVVVVV????YYYYYY?ٙ???WWWWWW??YYYYYY????\\\\\\????ZZZZZZ??????Օ?ؘ?ۛ?ܜ??YYYYYY?ښ????ښ????????XXXXXX?VVVVVV?Օ??TTTTTT??Ԕ?TTTTTT??SSSSSS??SSSSSS?UUUUUU??Ԕ?TTTTTT?Ԕ?TTTTTT???SSSSSS????Ғ?Ԕ?TTTTTT???Ɩ?̜?RRRRRR?RRRRRR?????ϟ???ϟ???Ɩ??ʚ?ʚ?Ĕ?Ó???Ó?ʚ?͝??͝?͝?PPPPPP?ё??ə???ə?Ɩ?Ș?Ξ?Ǘ?ŕ??˛?˛??QQQQQQ?Ξ?͝????ŕ?Ĕ?Ĕ?Ĕ???Ĕ??ŕ????????????????Ó?’?’???Ĕ?Ĕ?’???????????ŕ?ŕ?Ĕ??ŕ???Ó?’?ŕ??’????Ǘ?ŕ??Օ?RRRRRR???ϟ?Ξ?????Ԕ?А??ϟ???ӓ??͝?ϟ?Ξ??͝??ə????Ǘ?ŕ???ϟ?????ё??ё?Ғ??WWWWWW???Ғ??ϟ??UUUUUU???Ғ??֖?????ё?PPPPPP?Ξ?˛??ϟ???͝?PPPPPP?А??????Օ???TTTTTT???ܜ??ܜ?֖???WWWWWW?XXXXXX?ٙ??ښ?YYYYYY?XXXXXX????????PPPPPP?777777?111111?\\\\\\???YYYYYY?YYYYYY?XXXXXX?YYYYYY??[[[[[[?ZZZZZZ???ZZZZZZ??\\\\\\?XXXXXX??ӓ?UUUUUU?TTTTTT??TTTTTT?ӓ?TTTTTT?Ԕ???Ԕ?Օ?֖?ZZZZZZ?TTTTTT?SSSSSS??Ԕ?ӓ?Օ?ӓ??ё???Ǘ??Ғ???ё?ϟ?ё?RRRRRR?PPPPPP??А??Ξ?̜???????Ó???͝??Ξ??TTTTTT?PPPPPP??͝???QQQQQQ??Ș?͝?ʚ??ё?ʚ?ʚ??˛??ʚ??Ș??Ó?Ĕ???????????????Ó???ə????Ĕ?????Ɩ??Ɩ????RRRRRR???Ó??????Ĕ??Ĕ?ŕ????’??????ə???Ǘ???̜??ϟ?QQQQQQ?А?Ғ?Ғ??ٙ?WWWWWW??TTTTTT???PPPPPP?ϟ?˛???͝????Ɩ?????ё???ϟ?ё?ϟ?PPPPPP??ϟ?RRRRRR??А?QQQQQQ?ϟ?Ғ?????Ξ?ŕ?ə?˛??????Ғ?А?Ξ?ϟ?А??̜??ё?QQQQQQ?ӓ???ӓ?Օ??TTTTTT???Ԕ?????ߟ?]]]]]]??ח?ؘ?WWWWWW?WWWWWW?XXXXXX???YYYYYY??Օ?VVVVVV???ۛ?\\\\\\?______?㓓?XXXXXX?⒒?ۛ?YYYYYY?ٙ??ח??YYYYYY?ښ???\\\\\\????????Ԕ?TTTTTT???SSSSSS?ӓ?VVVVVV??TTTTTT?UUUUUU?֖???ؘ?ӓ???TTTTTT?Օ?Ԕ????˛?Ɩ??PPPPPP????ϟ?PPPPPP??ё?А??˛?˛?̜?̜???Ɩ???Ĕ??̜????Ξ?ϟ??̜?̜?˛???̜????ŕ?ŕ?ŕ??͝????˛?͝?Ó?Ĕ?Ș??’???Ǘ?’?Ó????Ɩ???Ó?ŕ??̜?Ɩ?Ɩ??Ĕ?????’??Ș?˛?Ǘ?Ɩ?Ǘ?Ɩ??Ĕ????Ĕ?Ĕ??Ɩ?Ĕ?Ɩ??Ĕ?ŕ??Ó??Ó????Ș??ʚ?̜?ə?˛????А?ӓ???֖?SSSSSS?А??PPPPPP??RRRRRR?QQQQQQ?А?˛?????ə??Ș??ʚ?А?Ξ???PPPPPP?͝?А???А?͝?͝????ӓ???ϟ??ϟ???˛?̜?QQQQQQ?А?Ғ??RRRRRR???А?????QQQQQQ???TTTTTT???Ԕ?Ԕ?WWWWWW?UUUUUU?ӓ?Ԕ?UUUUUU?WWWWWW???ܜ??111111????֖?ח??WWWWWW??TTTTTT?ӓ?Օ????ܜ?[[[[[[????ర??______??ۛ????ۛ??^^^^^^?000000???ۛ??ٙ????Ԕ????ӓ?VVVVVV??ӓ??֖?XXXXXX?ؘ?֖?ٙ??Ԕ?TTTTTT?Ԕ??Օ?ח??А??̜?ϟ???????Ғ?QQQQQQ???͝?ϟ?ϟ?PPPPPP?ё???’?Ĕ?Ɩ??ϟ??????ϟ?QQQQQQ?Ș????????PPPPPP?Ș??˛??˛?ʚ?Ș??Ó??Ɩ??’???????Ɩ?Ó??Ĕ???Ǘ????Ɩ???Ó?Ó?Ĕ???Ĕ?ə?̜????Ɩ?’?ə???Ĕ?????’???ŕ?Ó??Ɩ???ŕ?ŕ?ʚ?ʚ?ʚ?ʚ??̜??Ξ?SSSSSS?Ξ?А?ӓ?______??ӓ??SSSSSS?Ξ?А?PPPPPP?TTTTTT?Ξ???˛???ə????Ξ?RRRRRR?Ξ??PPPPPP???????А?͝?PPPPPP?PPPPPP?ח?֖???QQQQQQ?ӓ?А??????RRRRRR??ё??Ғ?????А???SSSSSS?QQQQQQ?ӓ?SSSSSS?WWWWWW?Օ???XXXXXX?XXXXXX?ٙ???ؘ??ؘ???ٙ??[[[[[[??????RRRRRR??Ғ???ٙ?XXXXXX???UUUUUU?Օ???ښ??ޞ??ܜ?ښ?Օ?ٙ?\\\\\\??000000???XXXXXX???ݝ?YYYYYY??VVVVVV?ٙ?TTTTTT??SSSSSS?ח?SSSSSS?TTTTTT?SSSSSS??VVVVVV??????WWWWWW??VVVVVV?SSSSSS?ё??SSSSSS?Ξ??ϟ?????Ғ?SSSSSS?SSSSSS?Ԕ?ё??˛??ϟ?ϟ?????ŕ???Ξ?ϟ?ϟ?͝???ʚ?Ɩ??˛??͝?˛???ϟ?Ғ?Ξ?PPPPPP?͝?А?А?̜???Ɩ?ə???ʚ?Ó??’?Ó?ŕ?Ĕ?ŕ???Ĕ?Ǘ???Ó?ŕ?Ĕ?’??ŕ?Ĕ?ŕ?’??Ĕ???ŕ????Ș??ŕ?Ɩ??Ĕ?Ɩ?Ĕ????Ɩ?Ɩ??Ó?ŕ?ŕ?Ɩ??Ĕ??PPPPPP?̜?̜?ə??ё?ӓ???А????????QQQQQQ?PPPPPP??А?ӓ?̜??˛??ʚ???ϟ??ə???UUUUUU?RRRRRR?QQQQQQ???ӓ?QQQQQQ?VVVVVV????ё???UUUUUU???XXXXXX??TTTTTT?QQQQQQ?Ғ?ח??????ё??̜?˛?ё?Ғ??Ғ?QQQQQQ????Օ??????WWWWWW??ٙ???ښ??[[[[[[?]]]]]]??ᱱ???WWWWWW??͝??Օ??YYYYYY??\\\\\\??RRRRRR??XXXXXX????ٙ???ర???YYYYYY?ښ?[[[[[[?\\\\\\?PPPPPP?ۛ?ܜ?ٙ??ߟ?ߟ????XXXXXX?VVVVVV??ё?????Ԕ??VVVVVV?ח?]]]]]]??ޞ??VVVVVV?WWWWWW????QQQQQQ?QQQQQQ????А?Ғ?RRRRRR?SSSSSS?Ғ?ё?ё??А??˛??А??????˛????ϟ???Ξ?ʚ??ŕ?̜?PPPPPP?̜???ӓ?RRRRRR?ӓ?ӓ?Ξ?͝?RRRRRR????ϟ??А???ə?Ǘ?Ĕ???Ĕ?Ĕ?’?Ó?’??Ó??Ɩ??Ĕ??ŕ?ё?????Ĕ???Ó?’???̜?Ғ??ŕ???Ó??ə?Ș???Ó?Ó?Ó??Ó??ŕ?Ǘ?Ǘ???˛?ϟ?Ξ??RRRRRR?Օ?PPPPPP?XXXXXX????ϟ?А???͝?????ё??̜?˛?????????Ξ?ϟ???PPPPPP?ё?RRRRRR???PPPPPP??ё??VVVVVV???UUUUUU??RRRRRR?ח???????Ξ??ʚ?˛???͝??SSSSSS??А?RRRRRR??Ғ??Օ?Ԕ?ӓ?????????????XXXXXX?ښ?ؘ?ח?֖??ӓ?VVVVVV??YYYYYY?ߟ???ޞ?嵵?⒒?ᱱ???VVVVVV?ח?YYYYYY?ښ?]]]]]]??\\\\\\??]]]]]]?ޞ?^^^^^^???QQQQQQ?000000???ݝ??????UUUUUU???ޞ????TTTTTT?Օ?TTTTTT?XXXXXX?ܜ????ؘ??Օ???PPPPPP?QQQQQQ??̜?PPPPPP?????ё??ё?QQQQQQ?А??ə?˛?Ș?̜?͝??ӓ???ϟ?Ξ?А?Ξ???А?Ɩ???Ɩ???А??Ԕ?SSSSSS?Ғ?PPPPPP?Ξ?ʚ???̜?ϟ?А?Ξ???ё?ϟ??Ǘ???Ĕ?Ó???ŕ?’??Ɩ??Ș?Ǘ??Ǘ??ʚ?Ĕ???ŕ??ŕ???’??Ĕ?????Ó?Ó?ə???????Ó??Ó????Ǘ?Ș?̜?˛???ё??ᱱ?⒒???RRRRRR?ӓ??QQQQQQ?PPPPPP????˛???RRRRRR????PPPPPP?SSSSSS??ё????А????ё??Ғ???SSSSSS??UUUUUU?ϟ??SSSSSS??VVVVVV??PPPPPP?PPPPPP??Ғ???ӓ?ё?????˛?̜????Ξ??А??ӓ?ё???Ԕ?????ח????Օ??ӓ?Օ?XXXXXX???ؘ?WWWWWW??ח?ZZZZZZ???[[[[[[?????SSSSSS??]]]]]]?????ٙ?????______??\\\\\\???ߟ?^^^^^^????rrrrrr?\\\\\\???????֖?YYYYYY???UUUUUU?????ٙ?XXXXXX?ZZZZZZ???????PPPPPP??Ș??XXXXXX?ӓ?????ӓ??ё??Ǘ?PPPPPP???RRRRRR?WWWWWW????͝??А??????Ó???Ԕ?Ԕ?ӓ?˛?Ғ?֖??Ғ?ϟ?̜?ʚ?̜??UUUUUU?ϟ?????̜?ʚ???Ĕ????Ɩ???????Ǘ?Ǘ?ʚ???PPPPPP?Ǘ?ŕ???Ĕ?SSSSSS??Ĕ???’?ʚ?Ĕ?Ĕ??Ó??Ξ?Ԕ??Ĕ?’?’?Ĕ?’?Ó?’?Ó??????ٙ?͝?XXXXXX?ٙ?????UUUUUU????PPPPPP?ϟ????Ș?ʚ??Օ?ё?QQQQQQ?Օ????Ғ??QQQQQQ???Ғ???RRRRRR???SSSSSS?ח????QQQQQQ??QQQQQQ?͝?А?А?PPPPPP??А???А?˛??ŕ?????̜??̜??А??ӓ???ӓ??VVVVVV??RRRRRR????????VVVVVV?Օ?ח?YYYYYY?ؘ???ܜ???]]]]]]?[[[[[[??\\\\\\???000000?111111?______?pppppp??ٙ????ݝ??pppppp?SSSSSS?ᑑ?PPPPPP????]]]]]]???ښ?PPPPPP????ZZZZZZ??ZZZZZZ?ښ????ٙ???Օ??Օ????ۛ???ٙ???UUUUUU?UUUUUU??PPPPPP?̜?Ǘ?ё?SSSSSS?????ӓ?ӓ??Ξ????ݝ?[[[[[[??˛?Ξ??Ғ?Ξ??Ξ?͝?͝???Ǘ?ŕ?Ғ??????TTTTTT??QQQQQQ???ʚ???Ξ?RRRRRR?TTTTTT????Ǘ?Ǘ??Ɩ?ŕ???ŕ??Ɩ???’???Ǘ?Ǘ?Ș??͝?ə??Ĕ?Ó?Ĕ???SSSSSS?????Ĕ???Ó?ŕ??͝?????Ó?????ŕ??ʚ?Ξ??PPPPPP??ח?ٙ??QQQQQQ?tttttt????Օ??ϟ??ϟ??????Ξ??YYYYYY?VVVVVV?ۛ?ݝ???ZZZZZZ?ӓ?Ԕ???ח??UUUUUU?????ח?RRRRRR???֖?VVVVVV?????QQQQQQ??͝?А??˛??Ĕ?Ɩ???Ξ?̜?PPPPPP?А?ё?ё?ё??WWWWWW?Օ?Ԕ??TTTTTT?ӓ??Օ??ח??֖??ח?֖???XXXXXX??VVVVVV?WWWWWW???ܜ?pppppp?\\\\\\??ܜ?]]]]]]??ܜ??????pppppp??ᑑ???111111?ߟ?555555?ర?ᱱ???YYYYYY?ݝ??ݝ???pppppp???ؘ????[[[[[[??ؘ??ؘ???XXXXXX?ٙ???ח?ٙ?ܜ???ۛ?______??XXXXXX??ӓ??Ξ???Ғ???SSSSSS????PPPPPP??Ξ???ښ?Ξ???PPPPPP?ϟ?PPPPPP??ʚ?????ё?А??֖?ӓ??RRRRRR?PPPPPP??TTTTTT??Ξ??Ξ?̜?????ə?ə?ŕ??ʚ?˛?Ǘ??ښ????ŕ?ŕ????Ș???ʚ?Ɩ?Ǘ??ϟ?????ə?Ǘ?Ǘ??????Ó?Ɩ??????Ĕ?????Ó?Ɩ???Ξ?ё??֖???QQQQQQ??\\\\\\???uuuuuu?䔔?YYYYYY???QQQQQQ????͝?Ǘ?ə???RRRRRR??^^^^^^?]]]]]]?PPPPPP?ᑑ?qqqqqq?ۛ?ؘ??WWWWWW?XXXXXX?ٙ???VVVVVV?ޞ?ZZZZZZ?UUUUUU??ӓ???А??QQQQQQ??PPPPPP?А?Ξ?ϟ?̜?ʚ???ə?˛?Ξ?Ξ?Ξ??Ғ?ӓ???UUUUUU??֖?????Ԕ?Օ????????ٙ?XXXXXX?ؘ?ؘ??????ZZZZZZ?^^^^^^??ۛ?ޞ???RRRRRR?Ⲳ??ᑑ??痗?㓓??䴴??SSSSSS?ᱱ????uuuuuu?Ⲳ?QQQQQQ?]]]]]]???QQQQQQ???qqqqqq??XXXXXX?WWWWWW?WWWWWW???]]]]]]?]]]]]]??ښ?ZZZZZZ?ښ?ښ?[[[[[[??֖?XXXXXX???ݝ?ܜ????rrrrrr???VVVVVV?Ԕ?̜??Ǘ???А??????͝?????PPPPPP????????ə??̜??PPPPPP??RRRRRR???Ғ?QQQQQQ?̜?А?ϟ???Ξ?А??ϟ?А?А?ё?Ș??ə?Ș?Ș?????Ɩ?Ĕ??Ɩ??????Ǘ?RRRRRR???Ɩ??ʚ?ə?SSSSSS??ə?̜?А?Ǘ?????ŕ??Ɩ?Ɩ?Ɩ???Ǘ??Ĕ?????????Ғ??ޞ?ݝ??????涶??QQQQQQ???QQQQQQ?????RRRRRR?̜???ϟ?QQQQQQ?ݝ??ᱱ?Ⲳ?䔔???????ܜ??[[[[[[?RRRRRR??ؘ??Ԕ???PPPPPP?SSSSSS?SSSSSS??ё??????Ó?Ĕ???А?????ё?Ғ??Ԕ??ח?֖?Ԕ?VVVVVV?ٙ????______?YYYYYY???ٙ?[[[[[[???\\\\\\??ۛ?YYYYYY??ٙ?ښ??\\\\\\?ZZZZZZ?ٙ?\\\\\\??PPPPPP?^^^^^^??ݝ??______???????㓓??111111?RRRRRR?RRRRRR?⒒?Ⲳ?ᱱ?ᑑ?PPPPPP??ᑑ?PPPPPP?ޞ?ߟ?ᱱ??WWWWWW?ח?WWWWWW??\\\\\\????ݝ???[[[[[[??XXXXXX??YYYYYY?ۛ?[[[[[[???ښ???222222??ؘ???˛????А?????˛?ŕ?Ɩ??QQQQQQ?XXXXXX????˛??ŕ????Ξ????А?SSSSSS?ё??ё??Ș???ʚ??PPPPPP?PPPPPP?RRRRRR???ϟ????PPPPPP??Ɩ??Ǘ??Ǘ?Ɩ?ŕ??????ə??Ș?ŕ???Ǘ?ə???ё?????Ș?Ɩ?ŕ??ŕ???ʚ?QQQQQQ?Ɩ?Ɩ?Ĕ?Ș??ŕ??’?Ɩ?Ǘ??Ǘ?ə?ё????????]]]]]]?000000???rrrrrr??Ԕ?QQQQQQ???Ξ???͝??PPPPPP???\\\\\\??444444???UUUUUU?333333???QQQQQQ?111111???㓓?ర???֖??SSSSSS?TTTTTT?RRRRRR?QQQQQQ?RRRRRR???PPPPPP??͝?RRRRRR?Ș???ϟ???А??ё?????TTTTTT??ח??Օ???ؘ?XXXXXX?ؘ?\\\\\\?ۛ?ݝ????\\\\\\???ܜ?ܜ???ݝ??ޞ?pppppp?ర?222222?uuuuuu?rrrrrr?ᑑ??PPPPPP??pppppp??ᱱ?ర?ח?XXXXXX??⒒????rrrrrr?vvvvvv??Ⲳ?QQQQQQ???111111?ssssss?qqqqqq?????WWWWWW?UUUUUU?ח?????[[[[[[?______??ښ?ۛ?]]]]]]?YYYYYY???\\\\\\??ޞ???ښ????????ё?А?Ԕ?ё???RRRRRR??ϟ????PPPPPP?YYYYYY??ϟ????ə???????ӓ??WWWWWW???ϟ????Ș??PPPPPP?Ғ?SSSSSS?TTTTTT??ϟ?А??̜?̜?PPPPPP?SSSSSS?????Ɩ???ŕ??Ǘ?Ș?Ș?Ǘ???Ǘ?ə?̜??˛?????ŕ?Ĕ?˛??ŕ??Ĕ?Ĕ?Ĕ?Ĕ?Ș?˛???Ĕ?Ɩ??Ĕ?Ó?Ó?Ó??Ĕ?SSSSSS?ӓ???VVVVVV?ؘ??ᑑ?ޞ?ݝ???ؘ?]]]]]]?????VVVVVV??????Ξ????UUUUUU??555555???䔔??䔔?TTTTTT?ssssss?ssssss?㓓??ߟ?ۛ????SSSSSS??RRRRRR??RRRRRR??????XXXXXX?______??????PPPPPP??PPPPPP?ϟ?RRRRRR??SSSSSS?SSSSSS??ח?ؘ??ZZZZZZ??[[[[[[?ٙ???]]]]]]?000000?______??ۛ??鹹?tttttt?rrrrrr??TTTTTT??______??ᱱ?Ⲳ?ᑑ?qqqqqq?444444?SSSSSS???rrrrrr?ᑑ??qqqqqq??????YYYYYY??Ⲳ?ᱱ?PPPPPP??⒒?444444??222222?ᱱ?[[[[[[???000000???pppppp???ؘ?UUUUUU??[[[[[[?ښ?\\\\\\??ߟ?000000?ߟ??ߟ?^^^^^^?ZZZZZZ?ZZZZZZ?ښ??ޞ?ݝ????ܜ??֖?ښ?[[[[[[???Ғ??ё??QQQQQQ?А?ё?ϟ?Ξ??ʚ??ё?]]]]]]?Ξ?˛????Ǘ?ʚ????ё?????ё?TTTTTT???֖?͝?А??TTTTTT?А?͝???˛???ʚ?SSSSSS??ZZZZZZ?ʚ??ŕ?Ɩ?ŕ???Ɩ?Ș?Ɩ?????????ʚ?˛?ŕ??Ó?Ĕ?Ɩ?ʚ??Ĕ?ŕ??Ó???Ǘ?ə?Ș?ŕ?Ș???ŕ??˛??Ș?ə???ӓ???ё?VVVVVV??000000??ӓ??SSSSSS?Օ?WWWWWW??ӓ????PPPPPP?ϟ?̜???ё??Օ?XXXXXX??222222?uuuuuu?666666?666666?777777??xxxxxx??斖?666666??\\\\\\?ٙ???VVVVVV?TTTTTT?RRRRRR????QQQQQQ?PPPPPP???А?ښ??Ɩ???̜?͝?А????Օ?TTTTTT??VVVVVV?Ԕ?WWWWWW????????ssssss?ߟ????YYYYYY?000000?痗?TTTTTT??PPPPPP???ssssss?䔔???SSSSSS??444444???㳳?SSSSSS?111111???111111?000000??QQQQQQ????ߟ??\\\\\\??ᱱ?rrrrrr??Ⲳ?ర?ۛ???______?ߟ??^^^^^^??ݝ?pppppp???ZZZZZZ??]]]]]]?]]]]]]??^^^^^^?QQQQQQ?ݝ?ర?rrrrrr?ܜ???qqqqqq??????YYYYYY?WWWWWW?????RRRRRR?ё?ϟ????Ғ??Ξ??А???ϟ?UUUUUU???ʚ?Ș??Ș??ŕ???????TTTTTT??PPPPPP??ə??UUUUUU?SSSSSS????͝?ё???Ξ?͝??????Ĕ?ŕ?Ĕ?ŕ?ϟ?ʚ??Ĕ?ə????Ɩ???????Ǘ??Ș?Ș?ʚ??˛?ŕ?Ș??ə???Ɩ??˛???Ǘ?Ǘ???ŕ?Ξ?Ɩ?ə?˛??RRRRRR??????֖??Ғ?ё????Ԕ?UUUUUU???Ғ?А?Ξ?Ξ?Ξ?Ξ???֖???PPPPPP?222222??Ꚛ?뛛?윜?\\\\\\?zzzzzz?Ꚛ??222222?000000?ݝ?ښ?UUUUUU?֖??Ғ?QQQQQQ??RRRRRR??͝??RRRRRR??]]]]]]?ӓ?͝??А???QQQQQQ?PPPPPP?SSSSSS?ӓ????ח?VVVVVV??VVVVVV?ؘ??ښ???PPPPPP?ᑑ??ޞ??????RRRRRR?333333?????444444??䔔?䴴?啕???緷???111111??PPPPPP??______??ߟ??ర??ݝ?^^^^^^?]]]]]]?ZZZZZZ???RRRRRR??PPPPPP????ݝ????[[[[[[????ۛ?[[[[[[?^^^^^^????ܜ?000000?ర?PPPPPP?qqqqqq?]]]]]]????ZZZZZZ?]]]]]]???ח??VVVVVV?֖??YYYYYY??Ғ??Ξ?SSSSSS?ё??Ԕ?RRRRRR?Ǘ??ё?ʚ??̜?̜?????Ĕ?Ó?ə?Ɩ????VVVVVV?YYYYYY???Ғ?Ғ?Օ?VVVVVV??SSSSSS?Ξ??ё?PPPPPP??Ξ?˛??ϟ????˛?˛??????ё?̜?????ŕ?ŕ??ʚ???PPPPPP??Ș?????͝????Ɩ???ə??Ș?????Ǘ??Ǘ?Ɩ??Ǘ?Ș?ϟ???Ԕ????QQQQQQ?VVVVVV?TTTTTT???RRRRRR?ё?Օ?????????̜?̜?Ξ???֖?ۛ??000000???}}}}}}?흝?흝?======?>>>>>>?꺺?VVVVVV?㳳?QQQQQQ?ޞ?YYYYYY????????ʚ?̜?͝??RRRRRR?͝?QQQQQQ?ח??RRRRRR?????SSSSSS?TTTTTT??VVVVVV??֖??Օ??ח??YYYYYY??______??]]]]]]???ܜ?\\\\\\?______???ᑑ??222222?[[[[[[??RRRRRR?tttttt?嵵?啕?tttttt??888888??ర?444444?333333??]]]]]]??pppppp?YYYYYY?ܜ????ZZZZZZ?\\\\\\?ޞ??ۛ??ᑑ??ర?ర?pppppp???\\\\\\??ᱱ????^^^^^^?ݝ?ۛ??000000??]]]]]]??ݝ???RRRRRR?ర???^^^^^^????ۛ?XXXXXX?WWWWWW??֖?WWWWWW?Օ??UUUUUU?ё??ё?QQQQQQ?RRRRRR???ё?????Ǘ???̜?????’?ŕ???PPPPPP?Ғ???Ԕ?RRRRRR?RRRRRR?WWWWWW??ؘ?֖?Ξ?QQQQQQ?Ξ?Ξ?QQQQQQ???????̜?˛?ʚ??Ξ?Ɩ??Ǘ??̜?˛?ə?Ș??ŕ??Ɩ?̜?˛?TTTTTT?ӓ?UUUUUU?????Ó????Ș?Ș?Ǘ?Ǘ??̜?ʚ??Ɩ??????Ɩ??Ξ???????RRRRRR??????Ғ?PPPPPP??XXXXXX?WWWWWW?֖?WWWWWW?000000???Ξ???ʚ???ϟ?????RRRRRR?wwwwww????______??}}}}}}?뛛?wwwwww?444444????VVVVVV?Օ?ӓ??QQQQQQ?̜???ʚ?Ξ???Ĕ?PPPPPP???SSSSSS?SSSSSS?TTTTTT???Օ??????ח??ؘ?ח?[[[[[[?ܜ?[[[[[[?ښ??????pppppp??qqqqqq?ర?]]]]]]?ޞ?ᑑ?QQQQQQ???⒒?⒒?RRRRRR?RRRRRR?______?ޞ???111111?]]]]]]??XXXXXX??ܜ?XXXXXX???UUUUUU??VVVVVV???]]]]]]?ܜ???111111??000000??]]]]]]?ޞ??Ⲳ?ర??YYYYYY??pppppp?______?ۛ??000000?PPPPPP?^^^^^^?[[[[[[?ݝ?______??tttttt?______?000000?^^^^^^??^^^^^^??ٙ???֖??ח???ۛ?UUUUUU??QQQQQQ??А??Ғ?ё?PPPPPP?ϟ??ϟ?SSSSSS?ח?????˛??Ɩ?Ɩ??Ɩ???А??SSSSSS???VVVVVV?֖???XXXXXX??͝??ϟ??????RRRRRR??͝?Ș??Ǘ?ʚ???͝?Ɩ?̜???͝?Ș?ʚ?????RRRRRR?]]]]]]???Ș?????Ɩ?????????Ș??Ǘ?Ș????˛?̜?ϟ?????ϟ?PPPPPP?SSSSSS????Ғ?UUUUUU??Ғ?ӓ??????˛?Ș??˛?˛??????Օ???ᑑ??\\\\\\?>>>>>>????}}}}}}?뻻??tttttt?qqqqqq??YYYYYY??Ԕ?Օ???ə???Ș?ŕ???Ξ?Ғ?ӓ??UUUUUU????[[[[[[??ۛ?WWWWWW??XXXXXX????WWWWWW?VVVVVV?ؘ??ٙ??????444444?ర?000000???ߟ???222222?111111?㓓??ᑑ?111111?111111??]]]]]]?ۛ?______?[[[[[[????ٙ??ۛ????SSSSSS??TTTTTT?RRRRRR???ZZZZZZ??111111?ᑑ?PPPPPP??ZZZZZZ????ښ?YYYYYY????????ޞ??ؘ?ۛ?000000?ర?ޞ?ܜ???ݝ?ݝ?^^^^^^???֖????ۛ???Օ???QQQQQQ?RRRRRR???ё????PPPPPP???TTTTTT????ϟ?Ǘ?????͝????UUUUUU?ё????ٙ??WWWWWW?ښ?TTTTTT?͝??˛????PPPPPP?TTTTTT?˛?˛?Ǘ?Ǘ?????Ș??˛??Ɩ?ə?ŕ????PPPPPP?͝?ʚ?ӓ??SSSSSS???ŕ?ŕ?ə?Ǘ?Ș?Ș???’?Ĕ?Ó???ə?Ɩ??Ɩ??ʚ??ə???Ɩ?ʚ??QQQQQQ??????ё?ё?RRRRRR??Օ?UUUUUU??ϟ?PPPPPP?֖?ə?ə?????ϟ???RRRRRR???PPPPPP?Ⲳ?666666??~~~~~~???~~~~~~?켼??斖??qqqqqq?000000?]]]]]]?ח??ӓ?RRRRRR?Ξ?˛?˛?˛?ʚ??Ξ??TTTTTT?Օ?Օ?ٙ?[[[[[[?ݝ??ܜ??ٙ??ښ??????ۛ?ZZZZZZ?ޞ?\\\\\\?\\\\\\??SSSSSS?嵵???TTTTTT?222222?000000???????QQQQQQ??Ⲳ?ᑑ?QQQQQQ?????ݝ???XXXXXX?ܜ??[[[[[[??SSSSSS??Ԕ?VVVVVV?ח???֖???ܜ??______?ޞ?ٙ??ۛ????????ۛ?______?⒒??pppppp?ޞ??ٙ???pppppp????ߟ???111111??UUUUUU???ؘ??ZZZZZZ???Ԕ?ӓ?TTTTTT???Ғ???RRRRRR????ё?ё???PPPPPP?Ξ?Ξ???Ș?ʚ?PPPPPP?ʚ?????Ԕ??XXXXXX?ח?UUUUUU??TTTTTT???Ǘ?ŕ?????ё???PPPPPP????Ș?Ș?PPPPPP?Ĕ???͝?̜??͝?̜??Ǘ??PPPPPP?Ș?QQQQQQ???Ĕ?Ǘ?Ɩ??Ɩ?ϟ?Ș?Ĕ?Ĕ??’??ŕ???Ǘ??Ǘ??ŕ????ə?͝?Ξ???QQQQQQ??QQQQQQ?PPPPPP?ё?????Ξ?̜?ϟ????Ǘ?Ș?Ǘ????͝?А?PPPPPP???WWWWWW?ٙ?\\\\\\??뻻?======?흝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

XA)*_4+h^{5r7*|N3ag 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 J{vkr(?*jyIvNiw! diff --git a/data/fits/NGC3344.Mono.F64.fits b/data/fits/NGC3344.Mono.F64.fits deleted file mode 100644 index 9097f201a..000000000 --- a/data/fits/NGC3344.Mono.F64.fits +++ /dev/null @@ -1 +0,0 @@ -SIMPLE = T / file does conform to FITS standard BITPIX = -64 / number of bits per data pixel NAXIS = 2 / number of data axes NAXIS1 = 256 / length of data axis 1 NAXIS2 = 256 / length of data axis 2 EXTEND = T / FITS dataset may contain extensions COMMENT FITS (Flexible Image Transport System) format is defined in 'AstronomyCOMMENT and Astrophysics', volume 376, page 359; bibcode: 2001A&A...376..359H PROGRAM = 'PixInsight 1.8.9-2' / Software that created this HDU COMMENT PixInsight Class Library: PCL 2.6.1 COMMENT FITS module version 1.2.0 ROWORDER= 'TOP-DOWN' / Order of pixel rows stored in the image array END ?????’??????????????????’???????????????????????????????Ɩ???????Ó??????Ș?ə?Ĕ?Ĕ?Ǘ?ə????ё?ٙ??ŕ?Ǘ??Ș?ӓ?YYYYYY?Ԕ???ؘ?QQQQQQ???ʚ???ϟ??Ș??Ș?ŕ?ə?Ǘ?ə?Ɩ????Ĕ???SSSSSS?ŕ?Ǘ??ŕ??ŕ?Ǘ?Ǘ?ŕ?Ó?ʚ???Ǘ?????Ș??Ǘ???????Ș?˛?ʚ?ʚ?ə??ə?????̜?˛?˛?Օ?ə??͝??ə?ʚ??Ξ??Ξ??????Ǘ?̜?????ŕ??А?Օ?̜??PPPPPP?Ғ????˛??ё?˛???̜?ə?ə?ʚ?˛?ə?ϟ???ə?͝???ʚ?Ɩ?Ĕ?Ș??Ó?Ó??ə??’?’?????????????????????????????????????????????ŕ???????????????????????????ʚ??????????Ɩ????ŕ?????Ó???’???Ĕ???Ó?ŕ?ŕ??????ё?Ɩ?Ĕ?Ó?Ĕ?Ɩ??ŕ?Ș????Ǘ????ᑑ?????Ғ?̜?Ξ?VVVVVV?ӓ?RRRRRR?͝?˛?ŕ??????PPPPPP?Ĕ???Ɩ???Ĕ???Ǘ???Ș????Ǘ?ŕ??Ɩ???Ǘ?ŕ???????Ǘ?Ș??Ǘ???????????̜?ə??А???˛?Ș?̜?˛??ə??Ș?ə??͝????ə??ʚ??ŕ??Ɩ??Ǘ??Ξ???͝??͝?????Օ??Ξ?RRRRRR??PPPPPP??ё?͝?А?Ԕ??Ξ????ŕ?Ș??Ó??’?’??’??’????????????????????????????????????????????????????????????????????????Ó??????????ŕ???????????????Ó?’?Ǘ??’?????Ó???Ɩ?ə?Ɩ?Ș?ؘ??ʚ????’??ŕ??Ĕ??̜??А??ӓ???Ǘ??ח?Ғ????ŕ?Ș??Ǘ?????Ǘ?Ɩ?Ǘ??Ó??Ĕ?Ó?ŕ???RRRRRR????Ɩ??Ɩ??Ǘ??ʚ?Ǘ??Ș???Ĕ???Ǘ??А???ʚ??ʚ?˛?͝?˛?̜?̜?͝?͝????͝?͝?̜??̜?PPPPPP????Ǘ?Ǘ???̜?ʚ?Ɩ??ə?ə????Ó?Ó??Ș?Ǘ?ə?Ɩ???ϟ???ё?Ξ?Ғ???RRRRRR?SSSSSS??PPPPPP??????Ș???Ɩ?Ǘ?Ș?Ĕ??Ǘ???’???’????????????????????????????Ó?????????????????????????????????????????????’????????????????Ó????????Ó????Ɩ??Ɩ???Ǘ??Ǘ?ə?ŕ??ŕ??’???Ó?ŕ?ə?’??ŕ?ŕ?Ǘ?Ǘ????ə??̜??UUUUUU?Ξ?RRRRRR?????Ǘ??˛??ŕ????ŕ???’??Ó??ŕ?ə?Ș?Ǘ?Ɩ?ŕ?ŕ?ʚ??Ĕ?Ɩ?Ó?ŕ????Ɩ?Ǘ?Ǘ?Ǘ??̜?ʚ??ʚ?˛??˛???????ə??Ξ?Ξ??Ξ??PPPPPP?ϟ??А??͝??̜?͝??PPPPPP?????ʚ??ʚ????ŕ?Ɩ????ə????˛?????Օ??Ԕ????Ξ??А??˛?Ξ?Ǘ?Ș??Ǘ??ŕ??’?’?Ó??Ó?Ș??’???????????????????????͝?Ξ???????????????????????????????????????????????????????????ŕ?????????????Ξ???Ǘ?’?ŕ????ŕ?Ǘ?PPPPPP?Ș??Ș??????ʚ???’?Ĕ????Ɩ?ə?Ξ???ʚ????֖??ə?ŕ?Ĕ?ŕ?Ó?????ŕ???Ǘ??Ó??Ɩ?ʚ????ŕ?Ĕ?????ŕ?ŕ?Ó????Ș?Ó??Ș??Ɩ?Ǘ?ё?ё?˛???ə?͝?̜?Ș?ə??ə???ʚ???Ξ??ϟ?PPPPPP???Ξ?PPPPPP???Ξ????͝?????˛?SSSSSS?͝?ϟ?Ξ???ϟ?QQQQQQ??QQQQQQ??Ξ?͝??ӓ?Ғ?Ԕ???????ϟ??ə??А?QQQQQQ?ʚ??????Ó??ŕ????ŕ?Ɩ?Ș??????????????????˛???????????’????????????????????????????Ɩ????????????????????????????Ĕ?Ĕ?????’?????ŕ?Ó???ə??Ɩ?Ĕ??Ĕ?????˛?Ғ?Ԕ????Ĕ?’?????Ɩ??Ɩ?????Ɩ?Ǘ??˛?ʚ?ϟ??ə?Ɩ?Ǘ?Ș?ŕ??Ĕ???Ĕ?Ɩ?Ș??ə?ə????????TTTTTT?Ɩ????Ó??Ó?ŕ?ŕ???Ĕ?Ɩ?Ǘ?ʚ??ӓ??????˛?ϟ?ʚ?̜??Ɩ?Ǘ?Ș??̜??˛????ח??XXXXXX?PPPPPP?ϟ?ϟ????PPPPPP??PPPPPP?Ғ???Ǘ?Ξ??А?UUUUUU???ӓ?͝?ʚ?ʚ?͝?˛?QQQQQQ??Ғ?TTTTTT?ӓ?TTTTTT?SSSSSS??SSSSSS???SSSSSS??????Ԕ?ؘ??????ŕ?Ș????Ĕ??’?’???????????????????????????????????????????????????????????????????????????????????Ɩ???Ó???Ș?????’??Ĕ?ʚ?Ș???Ĕ??Ș????Ĕ?ё??[[[[[[???Օ?ʚ???’???Ó?Ș???ʚ???ŕ??Ǘ??Ǘ??̜?˛??Ș??ə????̜?Ɩ?Ɩ?ŕ?Ș?Ș?Ș??ʚ?ʚ?ŕ?Ó???Ó??ŕ?Ó??Ș??Ó??Ĕ??ŕ???Ǘ?Ǘ????ə?Ɩ??˛?ə???ʚ?͝????̜?ϟ?ʚ?̜???ʚ??̜?Օ?ӓ?Ғ??SSSSSS??SSSSSS?А?PPPPPP?PPPPPP????ə??ə??ё???TTTTTT?WWWWWW??Ɩ?ə???ə???ؘ?Օ?SSSSSS??????TTTTTT????А?QQQQQQ?SSSSSS??Ԕ???Ș?Ș?Ǘ?ə????Ó??ŕ??Ó??Ó???????????????????????????????ё??????????????????????????????????????????????Ĕ????’??’??????????Ɩ????͝?ʚ?Ó?Ǘ?Ĕ?Ĕ?Ǘ??Ɩ?ə??ܜ?999999?䴴??Ǘ??Ó?’???Ó?Ș????Ɩ??Ș??Ĕ?Ǘ?Ĕ?Ǘ??̜???А??ʚ?Ș?ŕ?ʚ?Ǘ?Ǘ??Ĕ?????ŕ?Ĕ???Ó?Ĕ?Ó?’?’?Ɩ?ʚ?Ó?Ó????ŕ?Ǘ?Ɩ???Ș??ə??Ș???ə???ʚ?????˛?̜?ϟ?̜?ё?̜??ʚ?ə?ϟ?SSSSSS?QQQQQQ???Ԕ?А?QQQQQQ??PPPPPP?А??Ғ?̜??̜?̜?Ԕ?WWWWWW?Օ?UUUUUU???˛??SSSSSS?PPPPPP?ʚ????SSSSSS??UUUUUU?֖??ؘ?Ԕ???Ԕ?UUUUUU?ח??TTTTTT?SSSSSS??Ξ???Ɩ??ŕ??ə??’?Ó?Ĕ?????Ó?Ó?????????????????Ǘ?????????Ξ??????????????ϟ?TTTTTT???????????????????????????????????????????Ó??Ǘ??PPPPPP??Ɩ?Օ?ŕ??Ó?Ǘ?Ǘ?Ĕ??А?Ó?ŕ??Ș????[[[[[[?RRRRRR?Ξ??ŕ???Ó??ŕ???ŕ?Ǘ?Ǘ?ə??Ǘ?ŕ?ŕ?ŕ??˛??Ғ?QQQQQQ?????Ɩ?ŕ??ŕ??’?’??ŕ?ŕ???Ɩ??˛?Ș??’?Ĕ??ŕ?ŕ??’?Ĕ?Ɩ?Ĕ??Ǘ????Ǘ?Ș?Ǘ???ʚ????????̜?͝???????˛????͝?SSSSSS????PPPPPP??ϟ?А?Ξ?PPPPPP?ё?ё?ё???ᱱ?ޞ??ё?ӓ?ۛ???Ș?ϟ?ʚ?ϟ???RRRRRR???RRRRRR??ZZZZZZ???Օ?А???????Ԕ?ə?Ș?˛??Ǘ????’?’???Ó???Ó????????????????????????????????????????Ǘ???????????Ɩ????????????????????????ŕ??????Ĕ?????’????????Ó??Ș???˛?RRRRRR?Ǘ?????֖??Ԕ??ŕ?Ĕ?Ș?Ɩ?Ș?????ə??Ɩ?ϟ?Ș?Ĕ??Ș?ŕ?ŕ??˛?Օ??qqqqqq???????ŕ?͝?ŕ?Ĕ??ŕ?Ғ?Ǘ??Ó??ŕ??Ǘ??’???Ó??Ó???ŕ?Ɩ?Ɩ???Ɩ???Ǘ??Ǘ??ə?Ș??ə????ə?ʚ?͝??͝?ʚ????Ξ?Ș?ʚ?͝?ё?SSSSSS???А????PPPPPP?QQQQQQ?UUUUUU?͝?PPPPPP?????А??QQQQQQ?RRRRRR?QQQQQQ????̜???Ԕ?Ԕ??ᑑ??VVVVVV??㓓?????ښ?QQQQQQ??PPPPPP??˛???PPPPPP?Ș?ə?Ǘ???Ĕ?Ĕ??Ó?’?????????Ĕ???’??????????????????????????????????ŕ??Ș?????????????????????????????’????Ξ?Ó????ŕ?Ɩ?Ș?ʚ?Ó?Ǘ??˛??Ɩ?Ó?ŕ?ё???ʚ?Ș??ϟ?˛???Ɩ??PPPPPP?˛??ə???ŕ?Ɩ??QQQQQQ?????Ǘ?Ɩ??????’?Ǘ??ё?ZZZZZZ??????Ɩ??Ó??ə???ŕ??̜???Ǘ??Ĕ??Ó??’??ŕ??????ŕ?’?Ɩ?Ɩ?Ɩ??ŕ????Ǘ????ʚ?̜?ʚ?ʚ?͝?Ș?˛??˛??ϟ??ϟ?͝???̜????Օ???UUUUUU??PPPPPP?TTTTTT?ё???Ξ?̜??QQQQQQ?\\\\\\?SSSSSS?RRRRRR?ϟ??Ξ?ё?͝???Ғ??SSSSSS???ؘ?UUUUUU?Ғ??ۛ??VVVVVV?VVVVVV??????PPPPPP??Ǘ??QQQQQQ??ə??Ĕ?????????????????????????????????Ó??????????????????Ó?Ԕ????????????????Ɩ?????????????Ɩ??????˛?SSSSSS??’??Ξ?Ǘ?ʚ??Ș????Ɩ??А?Ɩ??ə??ŕ?ŕ?Ғ?̜?̜??ŕ??Ș?ə??ŕ???Ɩ?Ǘ???Ǘ??Ǘ?Ǘ??ŕ?Ĕ??????Ș?Ξ???????Ɩ??Ș?Ș??͝???Ɩ?Ș?͝???Ɩ?Ĕ?Ĕ?ʚ?Ǘ??Ó?Ó?ŕ????Ĕ?Ó?ŕ??Ǘ??Ĕ?ŕ?ŕ?????Ǘ???˛??ZZZZZZ?˛??000000??˛?ə?˛?Ξ?Ξ?Ξ?͝?????ϟ????А??ӓ?????PPPPPP???˛??VVVVVV?RRRRRR??ϟ?Ԕ?ݝ???RRRRRR??Ԕ?ӓ?ZZZZZZ?WWWWWW?UUUUUU??Ғ??????ٙ??XXXXXX??Ξ?͝??Ș?̜??Ș?˛??ŕ???ϟ?????????’?????????????????????????????????????????’?????????????????’??????????????Ĕ?Ĕ??TTTTTT?ʚ???˛???TTTTTT??Ξ?Ó??ə?ŕ??????????Ĕ????PPPPPP???Ǘ?Ó??Ó?????????Ɩ?ŕ??Ɩ?’???????Ɩ?ŕ??ё?????’?Ĕ?Ĕ?Ɩ?Ș???Ș??Ș?˛??ŕ??Ɩ?Ĕ??ŕ?Ĕ?????Ó?ŕ??ŕ??Ĕ?ŕ?ŕ?????ŕ???˛?ʚ???͝???Ξ?̜?ə???͝???̜?̜?ϟ?????PPPPPP??ё???ё?ϟ????˛??RRRRRR?rrrrrr?ۛ?Ξ?А?TTTTTT?WWWWWW???ə?Ғ???ZZZZZZ???000000??А?ё???ؘ??]]]]]]??PPPPPP?͝?ё??????ϟ??Ǘ?Ș?Ș?ə???Ó??’??????????????????????????????????????????????Ș??Ɩ?????’???’??????????????ŕ???Ó???ʚ??ʚ?ŕ???ŕ???PPPPPP?А?ӓ?ϟ??Ĕ?’????000000?Ғ????’?????ŕ???͝?TTTTTT?Ĕ??Ó?Ó??????Ǘ?Ó??Ĕ????’?????’??’?’????Ĕ???’??˛??????Ș??ŕ?Ĕ??Ó?˛???Ɩ??Ĕ?Ó?Ó??????Ǘ?Ɩ??Ɩ??Ǘ??Ǘ????ə?ə??̜??̜???Ξ?PPPPPP?͝?ʚ??͝??͝??Ξ???А?PPPPPP?PPPPPP?ϟ?RRRRRR?ϟ?QQQQQQ?????ϟ??ϟ?PPPPPP?Ξ??SSSSSS???PPPPPP?ə??Ξ?А??RRRRRR????Ғ??RRRRRR?UUUUUU??WWWWWW??ۛ??А?̜??PPPPPP?А?RRRRRR?Ξ???????????’?’????Ξ???????Ó????????????Ĕ??????????’???????????????????’??’?????????????̜??’?̜?????Ɩ????ŕ?Ɩ???͝?֖??ٙ??ϟ??’???Ĕ???????Ɩ???Ó?????Ĕ??’?PPPPPP???Ș??Ĕ?Ǘ?Ĕ?̜????Ĕ???ə??’?Ó??ŕ???Ó???’?Ɩ??Ǘ??Ș?ʚ?ə?Ɩ??ŕ?̜?ŕ?̜?ŕ?Ɩ?ŕ?’?Ĕ?ə?Ǘ??ŕ??Ɩ???Ĕ????Ǘ????Ș???Ǘ???Ɩ??Ǘ??Ԕ??TTTTTT?Ғ??͝?????̜??͝?ʚ???˛?ϟ???PPPPPP??QQQQQQ????SSSSSS??QQQQQQ??˛?͝?А???RRRRRR?RRRRRR???͝?ϟ?ϟ??͝?????Ԕ????TTTTTT???RRRRRR?????Ξ????ʚ???Ɩ??ə??Ș?’?Ó?Ó?Ĕ?ŕ???Ɩ????????????????????????????ʚ?????????????Ó???????Ǘ?Ĕ???????????????ŕ????????Ɩ?Ǘ?Ș??Ǘ??ʚ????˛?̜???Ɩ?Ɩ?ŕ?’?????’?ŕ??????’?Ó????????ё?֖?Ĕ?ŕ?Ĕ?ϟ????????Ǘ??Ó??Ɩ?Ó??Ó???Ó??Ĕ?ŕ???Ǘ??͝??Ĕ???Ɩ?Ɩ?Ó??ŕ??ŕ????????ŕ?ŕ??ŕ??˛?Ǘ??ʚ???Ș?Ș?????˛?ə?Ș???Ξ????͝??͝??ə?ʚ?˛????QQQQQQ??PPPPPP??ϟ?PPPPPP??Ғ???͝??˛??Ғ?SSSSSS??PPPPPP?ϟ?̜??ϟ?ϟ??Ξ??̜?Օ??VVVVVV???PPPPPP?WWWWWW??ӓ??ё?Ξ?ʚ??Ξ????Ǘ?˛?˛?ʚ?Ɩ??ə???’?Ĕ?’?Ó??????????????????????????Ó????????????????????Ǘ????????????????????????Ξ??˛????Ș?Ǘ????˛??Ș?˛?Ԕ??˛?Ș??Ǘ???’???????????Ǘ?Ǘ????Ǘ???Ɩ?Ɩ?Ș?????Ó?Ó??RRRRRR?Ó?’??Ó?А??Ĕ?Ĕ?Ó?????’????Ĕ???Ǘ??Ɩ?ŕ?ʚ??͝??̜??Ĕ?Ɩ?ŕ?Ɩ?Ș???Ǘ?????Ǘ??Ș?͝?Ș??Ș?ʚ???Ǘ????Ɩ??˛???ə?UUUUUU???Ξ?Ξ??????ə?ʚ?̜??ё???QQQQQQ?TTTTTT?ё?PPPPPP??RRRRRR??PPPPPP???Ξ????Ғ?Ξ?ϟ?˛??PPPPPP?А???????Օ?VVVVVV??TTTTTT?SSSSSS??SSSSSS??Ξ????Ș??Ǘ?ʚ?PPPPPP????Ǘ?Ɩ?Ξ?Ξ?̜?Ĕ?’?Ó???’??????????????????????Ó???????????’???????????Ĕ????????Ǘ??Ĕ?RRRRRR?͝???????Ĕ?ŕ?Ó????Ɩ??Ǘ?˛?Ș?А?Ξ?͝?ё????͝?ϟ????Ǘ?ŕ?Ș?ŕ?????Ǘ???????Ó?Ĕ??’??Ĕ?’??Ó??’?Ó??Ĕ??Ĕ????Ó?Ó???????ŕ?Ɩ??Ĕ?Ɩ??Ĕ?ə??Ĕ?PPPPPP?Ș?Ɩ?Ó?Ó?Ĕ?Ó?Ș?ܜ??Ɩ????Ș?Ɩ???Ǘ??̜????ə??̜?ʚ??˛?Ș??ə??Ș?ʚ?ʚ?Ș?ə?̜?̜??ə?ə?Ξ???ʚ?˛?Ξ?͝??Ξ?Ξ????̜?͝?PPPPPP?ϟ??ϟ????QQQQQQ?SSSSSS???ϟ?Ξ???QQQQQQ?PPPPPP??ϟ???͝?Ξ?Ξ??Ș?Ó???TTTTTT????Ԕ??VVVVVV??А?QQQQQQ?Ξ??̜?Ǘ??Ξ?ʚ???͝??ŕ???͝?Ș?ŕ???Ó?Ĕ?Ó???Ĕ???ŕ?????????????ʚ???????????????????????????????’??’????’???????Ĕ????’?ŕ??Ó??ϟ?ə?ʚ???ŕ?Ɩ?ʚ?VVVVVV????????Ɩ?Ǘ???ŕ??Ɩ??Ó?’?Ĕ?Ɩ?ŕ????????Ĕ?Ĕ?ŕ??Ɩ???’?Ĕ???Ó?????Ș?Ó???Ó?Ó??Ĕ?Ǘ?ə?Ĕ???????ŕ???Ɩ?Ș??Ǘ?ŕ???Ǘ??Ǘ?̜???Ǘ???ʚ?ə?Ș?˛?͝?˛?ʚ?̜??ə?Ș?ə?Ș??˛?ʚ?ə??˛??Ș?А??˛??˛????̜?̜?ʚ?ʚ????????ё??А??SSSSSS?QQQQQQ?QQQQQQ?ϟ?А?͝????ٙ???͝????͝?ϟ?ə?Ǘ?ə???SSSSSS?֖?Օ?Ԕ??Ԕ????Ξ??͝?PPPPPP?Ș?Ɩ????????????Ó?’?Ĕ?Ó????’??Ǘ????????’?’??Ó?’??’?Ĕ??????????????????????Ș?Ĕ??Ó????’????’???????????’???????͝??PPPPPP?ə???Ș?WWWWWW??333333????Ғ?Ǘ?ŕ?Ɩ???’???Ĕ?Ĕ?Ó?Ĕ?????????Ĕ??Ó?XXXXXX?Ĕ???Ó?Ĕ????’??Ĕ???Ș??ŕ?????Ĕ???Ó????Ĕ?Ó?Ó???Ǘ?ʚ??Ǘ?ə?Ș?????ʚ??Ɩ?Ǘ?˛??ə?ʚ?Ǘ??ʚ?Ș?Ǘ????̜?̜????ʚ??PPPPPP???˛?˛??Ξ?˛?ʚ??Ș?Ξ?А?ё?Ξ?PPPPPP???Ξ???͝??Ԕ??QQQQQQ?Օ??Ξ??ё?QQQQQQ?А?PPPPPP??ϟ?Ԕ??ё??͝???Ξ???Ξ?˛?˛?????ޞ??VVVVVV???SSSSSS???ϟ??ʚ?̜?̜??˛??̜?Ș?Ș???ŕ?Ĕ???Ó?Ó?Ó??’?’??’????’?Ĕ????????????????????????????????????Ǘ?Ó???????’?????Ĕ????????Ó???Ĕ??Ș??Ș?˛????RRRRRR??꺺???ϟ?Ɩ?Ș???Ó???Ĕ?ŕ??Ĕ??????Ĕ??’?Ó??Ĕ??Ó?Ó??????Ó??’?Ó??Ó?Ó???ŕ???’?Ĕ??Ĕ?ŕ?Ó??ŕ???ŕ???ŕ?Ĕ?Ĕ?͝???Ɩ?Ǘ?Ǘ???Ɩ?Ǘ?̜????Ș?ʚ??ʚ?PPPPPP????Ǘ?ʚ????PPPPPP??ʚ?̜?͝??̜?˛?̜??Ξ???͝???˛?˛???͝?QQQQQQ?Ξ???RRRRRR?͝????ϟ?PPPPPP???PPPPPP??QQQQQQ?RRRRRR??Ξ?А?А?Ξ??ϟ?А??Ғ??PPPPPP???Ξ??ə???ח???????Ԕ?Օ?ӓ?ё??Օ?͝???Ξ?ё??QQQQQQ??͝?UUUUUU?Ǘ??ŕ???Ĕ??’?????’??Ĕ?????????????????Ó????????????’???Ǘ?ŕ???Ó??VVVVVV?ŕ?Ĕ????Ó??????˛?????????Ĕ??Ó?Ș?ə?Ĕ??Ĕ???QQQQQQ?Ғ?000000?ۛ??ᑑ??̜????Ĕ?’????????Ɩ??Ĕ????ʚ?Ĕ??’??Ĕ?Ó?’?Ó??Ó?Ó?Ó????Ó??ŕ???ŕ??Ɩ?’??Ɩ??Ǘ???’??Ɩ?Ɩ?Ĕ?Ɩ?˛?????Ș?Ș?Ɩ??ə??Ǘ?ə?͝?????̜???ϟ??ə??ə?ʚ??ʚ?Ș?˛????͝???˛?ϟ?Ξ??????Ξ??ʚ??Ξ??͝??Ξ??QQQQQQ??????QQQQQQ?QQQQQQ?А????ӓ??֖????ϟ?PPPPPP???PPPPPP?QQQQQQ?Ξ?͝?͝?̜??ə??ʚ???Ԕ?UUUUUU??֖?Ԕ??TTTTTT??????Ξ??Ξ?ʚ?ə??Ș??ё??Ĕ?Ɩ??Ș??Ó?Ó???Ғ?Ɩ??Ĕ?????Ó?????’???̜???????????????????????????̜?Ș???????????Ó?ŕ????’?Ó????Ó??ʚ????’??Ғ?SSSSSS?______?^^^^^^???ə?????ʚ??Ɩ???Ĕ?Ɩ?????Ó???Ĕ?Ó??????Ɩ??Ĕ??ŕ??ŕ??Ó??ŕ?Ɩ??Ɩ???ŕ?????Ɩ??Ó?ŕ?Ĕ?Ĕ???????˛???̜??ϟ?̜?ʚ??̜??ϟ?ϟ?Ξ??Ξ?ʚ?????̜?????Ǘ?ʚ?ʚ?Ξ????ϟ?QQQQQQ???QQQQQQ?А?SSSSSS?????˛?͝???????????А?ϟ?????PPPPPP?Ξ?А????ϟ????QQQQQQ??Ξ?ϟ?????Ξ?͝?̜??Ǘ???Ԕ?Օ?ښ?֖?ӓ?Ԕ????֖?̜????̜??ʚ????Ĕ?Ǘ?ə?Ɩ??ə?˛?ŕ??Ĕ??’??Ó??’???????’?Ĕ????????’??????????????????????ə???’??????ŕ?????’?????????’?’??’???ŕ???͝?SSSSSS????Ξ?ё??ə?ə????Ĕ?Ș?Ǘ???Ș???Ĕ????????Ĕ?Ɩ?ŕ??ŕ??Ǘ??’??Ǘ?Ǘ???Ǘ??Ɩ???Ș???Ș?Ɩ??ŕ?ŕ?Ǘ?ŕ?Ɩ??Ɩ?Ɩ?Ǘ?ʚ???Ș?????ə???ʚ???ʚ??ə?̜?͝?ϟ?˛??Ξ?PPPPPP??ə????̜?͝?Ԕ??Ξ?PPPPPP???˛?ʚ?Ξ????̜???̜??̜??̜?????QQQQQQ?Ξ?????͝?Ξ?А??Ξ??RRRRRR???А?ё??PPPPPP?QQQQQQ?ϟ?͝?Ξ?ϟ?А?ё?PPPPPP?̜?̜?͝?ə??ϟ?TTTTTT???ӓ???ח???̜?PPPPPP??ϟ?????Ǘ???Ǘ????Ș??̜????ŕ?ŕ?Ó?’?Ș??????????Ĕ??’?????Ó????????????ϟ???Ó???Ĕ?’??????????’?Ó?????????????Ó?ŕ????????’???Ǘ?ʚ????ӓ??Ǘ?̜?Ș??Ǘ?Ɩ??Ó??ə?Ǘ?А???Ĕ???????ŕ??Ɩ?ə???ŕ???Ǘ??Ǘ?Ɩ????Ɩ??Ǘ??Ǘ??Ɩ??Ĕ??????Ș?Ǘ?Ș???ə?Ǘ?Ǘ?Ș??ʚ?ə?Ǘ???????˛?ϟ?˛?˛??ё?͝?ə??ʚ??ʚ?͝????̜??WWWWWW????ʚ?̜???Ξ?Ξ?͝??А???Ξ???͝???͝?А?PPPPPP?PPPPPP??PPPPPP???????ϟ?А?QQQQQQ?RRRRRR?QQQQQQ?????PPPPPP????ϟ???ϟ?͝???Ξ?PPPPPP??Ғ?PPPPPP???ؘ??ё?Ξ??Ξ?Ғ?RRRRRR?????А?ə?Ǘ?Ǘ?ʚ?Ǘ?Ó????ŕ???????Ǘ?Ɩ??’???’????˛?????????????Ǘ?????Ǘ?Ș?Ĕ?’??????’????????Ǘ????????Ó????ʚ??’??Ó????Ĕ????Ó?ŕ???̜?PPPPPP?ӓ?Օ?Ғ?RRRRRR?ё?͝??̜???ə?Ǘ???Ǘ?˛??Ĕ?Ɩ?ŕ??Ĕ?Ó?Ɩ???Ɩ?Ɩ??Ɩ??Ɩ?ʚ?̜????Ǘ?ə?Ɩ?Ǘ????ŕ?Ɩ??͝?Ǘ?Ș??ŕ?Ɩ???Ș?Ɩ??Ǘ?Ɩ?????Ǘ?ə??Ǘ??˛?Ș??ə??̜?ښ???̜?А?Ξ????Ɩ?̜??Ș?Ș?ё?????Ξ???ʚ?ə??ə???PPPPPP??А??̜??˛????˛????PPPPPP?QQQQQQ????ʚ?ϟ?PPPPPP?ϟ?????А?PPPPPP?PPPPPP?PPPPPP???QQQQQQ?ё??PPPPPP???PPPPPP??А?????ח??TTTTTT?ZZZZZZ??PPPPPP?ё???RRRRRR?PPPPPP??PPPPPP??Ș?ʚ??Ǘ??Ș?ŕ?Ǘ???Ș?А?????????’?Ĕ?’?’???Ĕ????Ɩ????͝????????????’???????????Ó???Ó?????????????????’??’????Ó?’?Ĕ?’??Ó?ə?QQQQQQ?RRRRRR?RRRRRR???Ғ?Ԕ?Ғ??Ǘ?ʚ???ŕ???̜?˛???Ɩ????ŕ??ŕ?ŕ?Ǘ??Ɩ?ʚ?Ș??Ǘ?Ș???Ǘ??Ǘ?˛??Ξ?Ɩ?Ș?Ɩ?Ɩ?Ș?˛?Ξ?ʚ??ʚ??Ș????Ɩ??̜?????Ș?ʚ??ə???Ғ?Ș?Ș????͝?А??Ԕ?̜??ə?????ə??˛???PPPPPP?Ғ?͝???̜?RRRRRR?˛??̜??̜?TTTTTT????А??̜?˛??˛???֖????˛????ϟ?Ξ?͝??ё?Ғ??А?????ϟ???ё????А??????Ғ?QQQQQQ??????А?SSSSSS?Ғ??А?ӓ?˛?ʚ???Ș?ʚ?Ș??Ɩ?Ɩ??ə?ʚ??͝?̜?ə?Ĕ???????????ӓ?RRRRRR????Ɩ??’?Ǘ??????????????RRRRRR?ё???????ё??????????????Ó??????Ó???Ó?’??’??Ĕ??ŕ?Ĕ???ϟ??ښ?斖??XXXXXX?SSSSSS??͝???ϟ?ŕ??Ǘ??Ɩ??Ǘ?ʚ???Ó???Ǘ?Ξ??Ɩ???Ș?˛??˛?ə?????Ɩ?Ș?ʚ?ə?ʚ????А?˛?̜?˛???????А?ϟ??ə?ʚ??˛???Ș??Ǘ?̜??̜?QQQQQQ?ϟ?̜???ʚ??UUUUUU?TTTTTT????????Ș?ə??̜???͝?Ξ?ʚ??А???????ё??ё??˛??͝??̜?̜?˛?˛???Ξ???˛??????ϟ????SSSSSS??ϟ??PPPPPP??????QQQQQQ??Ғ?ё?͝?Ξ??ӓ??PPPPPP?А?ё??Ғ?֖?????ӓ?Ғ????̜?ə?ə??Ǘ?Ɩ???ŕ???Ԕ??ə?ŕ??Ó???????????????????’?Ǘ??????????Ξ??˛?Ó?Ǘ?????Ĕ???????????????????Ó??????ŕ??’?Ó?Ĕ???Ș??ϟ??ߟ?꺺?ZZZZZZ?[[[[[[?QQQQQQ?ё?А??Ξ??̜?Ș?Ǘ????Ɩ?Ĕ?Ɩ??ŕ??ə?ə????Ɩ??ə???ё?ə?Ș????Ξ???ə?Ș?ʚ??͝?ʚ??ϟ?PPPPPP??А?А??QQQQQQ???ϟ?А?????̜???Ș?ə??Ș?Ș???˛??͝???ϟ????ʚ?????Ǘ??Ș?Ș???ϟ?ʚ???А??????̜??ϟ??ӓ?͝?Ξ?Ξ?PPPPPP?͝???̜??А????͝?͝??ϟ??Ξ?RRRRRR?QQQQQQ????ӓ?А?ϟ?ё?PPPPPP?QQQQQQ?ё?ϟ??А?TTTTTT??ϟ????֖?Ғ?Ғ?SSSSSS?QQQQQQ???SSSSSS?ח?ZZZZZZ?XXXXXX?TTTTTT?????ʚ??ʚ????ŕ??Ɩ?Ǘ??ᑑ??ə???ŕ???’?’????Ǘ?Ó??Ș????????’?????????????????˛???Ș?ŕ????????????’???ŕ???Ĕ????Ĕ??’???’?Ĕ??????ϟ?Օ???555555?XXXXXX???ʚ?͝???˛???Ș??Ɩ?ŕ?Ɩ??А??Ǘ???ə??ʚ?ʚ??Ș?Ɩ??Ɩ?ə?ə?ə?А?PPPPPP???̜??˛??̜???̜??Ξ??֖?Ξ????ʚ?̜?Ξ?͝??ʚ???ʚ?ʚ??ə???ə??ə?ə??̜??ʚ??ϟ?А?͝??WWWWWW?Ғ?PPPPPP?˛?ʚ???ə??Ǘ?ʚ??˛??А??͝??ё?А??А???UUUUUU?PPPPPP??ё?͝???PPPPPP?Ξ?Ξ??QQQQQQ?Ξ?͝?͝???̜?PPPPPP??RRRRRR?PPPPPP?ח?PPPPPP?ϟ???А????А?PPPPPP?PPPPPP??ӓ?А??PPPPPP?PPPPPP?ϟ??ӓ?PPPPPP?Ғ??Ξ??Ғ???111111????͝??ʚ?Ξ?А?Ξ?ə?Ș?Ɩ??ŕ?ə?[[[[[[????’??’???Ĕ??’?????????????’??’???ʚ????????????’?ŕ?????????????????’?????’???????’???Ó???Ɩ???ё??ܜ???ٙ??ё???ə????PPPPPP?˛?ʚ???ə?Ξ??Ɩ??????˛?̜?˛?ə?̜??ʚ?ə???ə?̜?̜?ə?Ξ???͝?????̜?TTTTTT?SSSSSS?˛???͝?ʚ???˛????ʚ?ZZZZZZ?Ξ???͝???ə?????Ș???Ǘ?Ș???ϟ??ʚ?ʚ?????ə?͝?Ș???Ԕ??PPPPPP?QQQQQQ???͝?̜????ϟ?Ғ?QQQQQQ??̜??Ξ??ϟ?PPPPPP????˛?̜?Ξ??ʚ?Ξ???А?Ғ?QQQQQQ?QQQQQQ?Ғ???А?PPPPPP??QQQQQQ?QQQQQQ?А?͝?PPPPPP??????ϟ???̜??Ԕ?PPPPPP?А?UUUUUU?[[[[[[?????Ԕ???ə?˛???ʚ?Ĕ??Ɩ?Ɩ??Ș?Ɩ?????Ó?Ĕ?’?’?Ĕ??’?Ó???????????Ó?Ĕ???ʚ????????ə?????????????????????????ŕ?????’???Ș?Ɩ?’???’?Ó??QQQQQQ???˛??֖??Ԕ??ё?Ξ???Ɩ?Ɩ????VVVVVV??????Ǘ?????Ó???ə?ʚ?Ș?Ș?ʚ?Ǘ?????̜?̜?Օ????͝?̜??̜?ϟ?˛?͝??˛?ʚ???̜?ʚ???˛?ʚ???Ξ??Ξ????ʚ?̜?˛????ʚ?Ș??????Ԕ??Ξ?ϟ?ə??ə?ə?Ɩ?ʚ??Ș?ʚ?˛??ё??Ɩ?Ǘ?Ș?ə???RRRRRR?ё?PPPPPP??А?̜???̜???Ξ??ʚ??˛????ʚ?Ξ?Ғ?ё??Ғ?WWWWWW?ؘ?ӓ????Ξ?А?QQQQQQ????ϟ?ϟ?RRRRRR?QQQQQQ??̜??͝?˛???ё??TTTTTT?֖??111111??TTTTTT?TTTTTT?TTTTTT?А????ʚ??Ǘ????Ɩ?Ó?????ə??????’????’??Ó????ŕ?ŕ?Ɩ???Ó??˛????????????????????????Ó??????ŕ???????’?????????Ó??Ɩ?????͝??Օ?TTTTTT?PPPPPP?ə??ə?̜?ё?˛?ʚ?ə??˛?ə???͝?Ĕ?Ɩ?Ǘ?Ș????̜?͝?˛??ə?ʚ?ʚ?PPPPPP???PPPPPP??˛?ϟ?А?͝??????ʚ?ʚ?˛?͝?͝?͝?˛?˛??̜??А?????̜???̜?А?Ξ?͝?Ξ????ʚ?????Ș?Ș?̜???͝???Ξ?????Ș??Ș?˛?͝?̜??PPPPPP?Ԕ?Ș???̜????А?А?????Ξ??ϟ????Ș?Ș?̜?А?ə?Ș??Ғ??????????ϟ??????А?Ξ??????А???Ǘ?ə?ə?ϟ?YYYYYY?ܜ??ח?Օ?QQQQQQ???͝?˛?̜?ə???Ɩ??Ĕ?Ó?’?Ĕ?Ĕ??Ɩ?ŕ?Ó?????’?Ó??Ĕ??????’?????ё????????????????????Ĕ?????????Ǘ????Ĕ???Ó???????????Ó?ŕ?????Ξ???????TTTTTT???ϟ?ϟ?QQQQQQ??̜?ə??ʚ?ʚ????Ș?ŕ???ə??Ǘ?ə?ə?ʚ?ʚ?͝??VVVVVV????͝?˛?͝??Ξ?????Ξ????Ξ?ϟ?А??͝??͝?Ξ?ϟ?͝?Ξ?А????͝????ϟ????̜?̜?˛?ʚ??˛?̜?????????̜?̜????ʚ??????PPPPPP?ӓ?ؘ???ʚ??PPPPPP?͝????Ξ?QQQQQQ??̜?̜?ə???VVVVVV?ϟ??Ș??͝????˛???ё????QQQQQQ?А??PPPPPP??Ξ?ϟ???ё???QQQQQQ??YYYYYY?SSSSSS??͝?Ǘ?ŕ??Ǘ??ؘ??YYYYYY?^^^^^^???ё?͝??̜?ə??ə?ə?Ĕ??ŕ?Ĕ?????Ɩ?ŕ?Ɩ???Ó?Ĕ?Ó?Ó?’??????’?Ó?Ǘ?Ǘ??Ԕ??Ĕ????????Ɩ?Ĕ???????’?????????Ĕ????????’???Ĕ?Ɩ??????Ó??ə???Ó??’??Ǘ?Ó??̜??QQQQQQ?WWWWWW?PPPPPP?̜?????ϟ?UUUUUU??˛?̜?ʚ???˛?˛??ʚ?ə?????͝??PPPPPP?А?Ξ??ё???PPPPPP???Ξ?А?Ξ???????QQQQQQ???ё?PPPPPP???PPPPPP????А?PPPPPP?А?А????͝??˛??TTTTTT???ʚ???˛?Ξ?˛???˛?PPPPPP???UUUUUU??̜?͝??˛?͝?????ʚ?͝??͝?PPPPPP?ʚ?͝?Ξ??̜??͝?͝?˛??ё?ϟ?PPPPPP?ʚ???????Ǘ?ʚ??̜?̜??̜????ё???А??А?QQQQQQ?????PPPPPP??QQQQQQ?ё???Ғ??QQQQQQ?Ξ????ϟ???Ԕ???Ԕ????˛???Ș?ʚ????Ɩ?Ó???ŕ????Ĕ??ə????Ĕ??’?’????????’??ʚ?͝??ə??Ĕ???ŕ?????????Ó????RRRRRR?????’????????????Ɩ?Ĕ???????????’?ŕ?Ĕ??Ĕ???˛?ϟ?ϟ????˛?˛??А?̜???????Ș?ʚ??ə???ʚ?̜?Ξ?PPPPPP???А?????PPPPPP???ё?Ξ???Ξ?Ξ??А?А???ӓ??А??А???А?Ξ??QQQQQQ?SSSSSS???А??͝??͝??͝??ə?˛?˛?ʚ?ʚ?˛??????̜?ё?QQQQQQ???QQQQQQ??̜?͝??ё?ə?˛??̜?ʚ??̜????ё??ə?˛??ʚ?ӓ?????˛?Ξ??ϟ?ё?PPPPPP?ʚ?ə?ʚ?̜?̜???͝??˛??QQQQQQ?PPPPPP?PPPPPP?PPPPPP?ϟ??QQQQQQ?PPPPPP??QQQQQQ??ё?А?QQQQQQ???RRRRRR?ӓ???̜??Ξ?VVVVVV?Ԕ???͝????Ғ??А?PPPPPP??ʚ?ə?Ș???????Ǘ???Ĕ?Ó?Ĕ???ŕ??’?’?Ɩ??Ó??Ĕ??Ó?’????’?͝?ښ?ߟ?͝??’???????????’????’?Ɩ?ŕ?????’?RRRRRR???’?Ξ?˛??ŕ?Ó??ʚ??’?????’?’?Ó?????Ó??Ĕ?Ș?Ș??ə???̜?͝??А???ϟ?̜????Ξ?Ǘ?Ș?˛?͝??????QQQQQQ?QQQQQQ?А??PPPPPP??QQQQQQ?ё?????ё?ϟ??QQQQQQ?QQQQQQ???ϟ????SSSSSS?ӓ?RRRRRR???QQQQQQ??ё???ϟ???PPPPPP???ϟ??̜??˛???ʚ??͝????˛?Ξ?̜??????Ғ??̜?͝?ё?ё??QQQQQQ???̜??͝?SSSSSS?˛?Ǘ?ə?˛??Ș?ə??Ғ?ϟ?ə???PPPPPP?̜???????ӓ???˛???͝???̜?ϟ?А??PPPPPP?ϟ???ё???QQQQQQ??RRRRRR?PPPPPP??PPPPPP??SSSSSS???̜??Ș?ϟ?ϟ?QQQQQQ?XXXXXX??ё?????ё?PPPPPP???͝?ə??Ș?ŕ??Ș?????Ó?Ĕ??Ĕ?Ɩ???’?Ș?’?Ó??ə???’??’??Ó?Ó??ߟ?˛??ŕ????’?????Ɩ?Ó?̜??̜?????????????Ó?˛????Ș?????Ó?Ĕ??Ǘ?’??Ó???’???ŕ?ŕ?Ĕ?Ǘ??Ǘ?Ǘ?ə?ə?????QQQQQQ?͝?̜????Ș??˛?Ξ?̜?????PPPPPP?ϟ?XXXXXX?\\\\\\???А?А??Ғ?Ғ???Ԕ??WWWWWW??VVVVVV??Օ?Ғ??RRRRRR?ё?PPPPPP????TTTTTT??Ԕ???Օ??????????Ξ?Ξ?͝?Ξ????˛?˛???˛???˛?ʚ?̜?Ξ??Ξ??͝?ϟ?RRRRRR?QQQQQQ??QQQQQQ?̜??ə??͝??TTTTTT?А?˛?Ξ?͝??ϟ?Ғ?̜?̜???ə???͝?̜?͝?̜?̜?ϟ????Ξ????RRRRRR?̜?˛?RRRRRR?ϟ?А?PPPPPP?Ξ?А???QQQQQQ??SSSSSS???RRRRRR??QQQQQQ?RRRRRR??ϟ???˛?Ǘ??ə??QQQQQQ?RRRRRR?Օ??Ԕ?֖?А?ϟ?˛?͝???Ɩ????Ș??Ǘ??Ó????ŕ??’?????Ɩ?Ɩ?Ó????Ó?Ĕ?Ó???ŕ?Ǘ??ŕ?????????????????’????????????ə???Ĕ?Ĕ?QQQQQQ?????Ó?????ŕ????ə???ŕ???Ǘ???̜???PPPPPP?RRRRRR?͝?˛???ϟ?ə??ʚ?͝???Ξ??͝?QQQQQQ?PPPPPP??????PPPPPP???SSSSSS???Ғ?Ԕ?Ғ?RRRRRR???ZZZZZZ?????TTTTTT?ӓ??ӓ?Ғ???TTTTTT?RRRRRR?UUUUUU??UUUUUU??RRRRRR?PPPPPP?А??ё?QQQQQQ???PPPPPP???А??Ξ?Ξ?Ξ?Ξ?Ξ?Ξ???˛?̜?ʚ?˛?Ξ?ё?PPPPPP?PPPPPP???͝??PPPPPP??˛???Ξ??SSSSSS?UUUUUU??Ξ?Ξ?͝?͝?Ξ?PPPPPP?Ξ?͝???ϟ??ϟ??̜???͝?ϟ??????VVVVVV??ё?Ξ?˛?ϟ?????А??А??Ξ???QQQQQQ?RRRRRR?QQQQQQ????QQQQQQ?PPPPPP?͝?˛???ə?̜???Ғ????ӓ?А???˛?̜?ʚ??˛?ə?ə????ŕ??’???’??Ó????Ó?Ĕ????ŕ?Ĕ??Ș??????ŕ????????ʚ??????ə??ŕ?Ó??’??????????’?̜???ŕ?Ĕ??’??Ó?Ó??˛?????’?Ó????Ĕ?Ɩ??͝??????Ԕ??ʚ??͝???̜??͝??ё?ё??Ξ???ϟ?Ξ????QQQQQQ??Ғ???RRRRRR??ӓ???UUUUUU?ܜ??ӓ????ӓ??ӓ????Ԕ?TTTTTT????ё???ӓ?Ғ??????ё?PPPPPP?А?PPPPPP?PPPPPP?ϟ?А??ϟ?Ξ?ϟ?QQQQQQ?PPPPPP????Ξ??̜????ӓ?????PPPPPP?ϟ?Ξ?͝??QQQQQQ?ё????????̜?TTTTTT?͝?????͝?ё?Ξ????֖??А?PPPPPP?ё????Ԕ?Ξ??ϟ?А?̜?А?ё?Ξ?А?????Ξ??Ғ?ё?QQQQQQ?ё?RRRRRR?ё?ϟ??PPPPPP?ʚ?Ș??͝?????Ԕ?Օ?????Ξ?ʚ?̜???Ɩ??̜?Ɩ???ŕ?Ǘ?ŕ????’??’?’???Ó?Ó??ϟ???А?????ʚ?’?’??Ș??????????????Ĕ?????????????Ș?ə?Ĕ?ə???Ĕ??’???Ó????????’?Ǘ?Ɩ?ʚ?˛?????SSSSSS??ё???PPPPPP??͝????ϟ???ϟ?ϟ?WWWWWW??ϟ?ӓ?˛?Ξ?̜????ё??QQQQQQ??????????PPPPPP?А?TTTTTT??ӓ?SSSSSS?Օ?TTTTTT??ӓ???????QQQQQQ?TTTTTT?А?PPPPPP?ϟ?????Ғ?ё????ϟ?А?А??QQQQQQ?PPPPPP??Ғ???PPPPPP?А???????ё???А?ё?ϟ???PPPPPP?QQQQQQ?ё??QQQQQQ?RRRRRR??ϟ?͝?˛???̜??Ξ?ϟ?̜?Ξ??ё??PPPPPP??XXXXXX?ё?Օ?PPPPPP???ϟ?RRRRRR???Ξ?Ғ?RRRRRR?А????ё?QQQQQQ???????RRRRRR??ё?ё??ϟ?Ξ??????ʚ?̜?QQQQQQ???ё?PPPPPP???̜???Ǘ?Ș??Ș??Ǘ??Ĕ?Ĕ??Ó???????????’??ə?Ș??????’??Ɩ??????????Ĕ?̜?????????’?????????Ǘ???Ĕ?????Ξ???Ĕ?????Ĕ??’?????͝?ə??Ξ??Ғ?Ғ?????QQQQQQ??ϟ??PPPPPP??PPPPPP?Ξ?̜?̜?PPPPPP???PPPPPP???ϟ??QQQQQQ??PPPPPP??PPPPPP???ښ?ӓ?WWWWWW?ӓ???Ғ?SSSSSS???SSSSSS??VVVVVV?????ӓ???Ԕ?Ғ?А?ϟ??????Ғ?TTTTTT?Օ?TTTTTT??Ғ???Ғ??QQQQQQ??ё???RRRRRR???Ԕ?RRRRRR??QQQQQQ??А??ё???RRRRRR??Ғ?ё?QQQQQQ??RRRRRR??RRRRRR?SSSSSS?QQQQQQ??PPPPPP?ё??Ғ?Ξ??͝????̜??А?͝??PPPPPP?ϟ?ϟ??Ԕ???????͝???QQQQQQ??ё??PPPPPP?PPPPPP??А??SSSSSS??????Ғ??RRRRRR?А??PPPPPP??????ϟ?̜?Ξ???????͝?ϟ??Ǘ?????ϟ?Ĕ?Ĕ?ŕ?˛?Ó??Ó????’???Ó?’?’?ŕ??UUUUUU?Ĕ??ŕ??’?????’??Ĕ?Ĕ?????????Ó?Ó??????Ó???????ʚ?????ŕ?Ĕ???Ԕ??Ó?Ó??’????Ĕ????͝?Ξ?VVVVVV?ʚ?ʚ?˛???ӓ????ё?PPPPPP?˛?͝?????RRRRRR??Ξ?Ξ?ϟ??А??Ԕ?Ԕ????А??UUUUUU??QQQQQQ????Ԕ??SSSSSS?SSSSSS?ӓ?RRRRRR???UUUUUU?TTTTTT?Ԕ?ח??TTTTTT??ӓ?SSSSSS?TTTTTT?ӓ?Ξ??Ғ?WWWWWW?ٙ?ё?ё??UUUUUU??VVVVVV????RRRRRR??TTTTTT????RRRRRR?QQQQQQ?ӓ???QQQQQQ?Ғ?ё?ё?Ғ???RRRRRR??SSSSSS???SSSSSS?TTTTTT?RRRRRR?SSSSSS???ё????ϟ????Ғ?͝?̜???ϟ?PPPPPP?͝??QQQQQQ?Ξ?PPPPPP?Ξ????А?PPPPPP????ϟ?ϟ?Ξ?ϟ??????А?ё?А?SSSSSS?Ԕ?SSSSSS?QQQQQQ?А???ё?ё??ё????Ș???˛???͝?͝?PPPPPP?͝?ё??ϟ??PPPPPP?????ʚ?????’?????’?????Ș???Ó??Ǘ??’?ə???????????????Ó?????Ɩ????Ĕ??????????????’??Ó?͝?ŕ??ŕ?’?Ĕ?Ĕ?ŕ??Ĕ?ʚ?Ó???ʚ???̜??͝??ϟ???֖?QQQQQQ?RRRRRR?А??̜?̜?Ξ?̜?Ξ??ϟ???VVVVVV?SSSSSS?QQQQQQ???SSSSSS?????PPPPPP??QQQQQQ??????WWWWWW?SSSSSS?ӓ???Ғ??ٙ?֖?֖??UUUUUU????ӓ?Օ??TTTTTT?SSSSSS?UUUUUU???YYYYYY?XXXXXX??????֖???UUUUUU??֖???Ғ??ё?????????Ғ?Ԕ?????ӓ?Ԕ???ӓ???SSSSSS?QQQQQQ??Օ?Ԕ??QQQQQQ??Ԕ?RRRRRR????А??А?????ϟ??Ξ?PPPPPP????Ξ???PPPPPP???QQQQQQ?А??????RRRRRR???Ғ?А??PPPPPP?RRRRRR?ё?ё?RRRRRR?Ғ??А?Ξ?????˛??͝?QQQQQQ??ё???PPPPPP??А?˛??ə????????Ĕ??Ó????Ó??Ĕ????Ó???Ș??Ĕ??’????????????????ŕ?????Ĕ?????’?????????ʚ?’????Ó?Ĕ??Ɩ?Ĕ?Ó?Ɩ?????˛?Ș?˛??Ғ?RRRRRR?VVVVVV???RRRRRR??????͝???ϟ?Ξ???А?˛?Ξ?Ξ??PPPPPP??ϟ?PPPPPP?TTTTTT????Ԕ?VVVVVV???VVVVVV?TTTTTT?TTTTTT??ח?ٙ?֖??RRRRRR?Ԕ?֖?VVVVVV???ؘ??Ԕ?Ԕ?ӓ??UUUUUU??Օ?[[[[[[?Ԕ?Օ??WWWWWW??ᱱ?qqqqqq????ݝ??????UUUUUU?WWWWWW?Ԕ??Ԕ?SSSSSS?Ғ??TTTTTT?Օ???QQQQQQ?QQQQQQ???TTTTTT??TTTTTT??SSSSSS?ӓ???????SSSSSS?RRRRRR?SSSSSS??Ξ???PPPPPP?QQQQQQ??ϟ??А?А????QQQQQQ??PPPPPP?А?ϟ?А?PPPPPP?ϟ?ё?Ғ?Ξ?̜???QQQQQQ?ё?ё??ё?QQQQQQ?RRRRRR?????QQQQQQ?Ғ?ё?QQQQQQ?QQQQQQ??ё??RRRRRR?QQQQQQ?QQQQQQ????ʚ?Ǘ?͝?͝?ё?Ԕ?RRRRRR???А??А??ə?ə????Ɩ??Ș?Ɩ??Ǘ?????Ó?????’??Ĕ???????????????????Ó?Ó????ʚ???????’???’??Ĕ??????Ó???????’?Ǘ?Ó?А??Ɩ??˛??̜??PPPPPP??QQQQQQ?PPPPPP??QQQQQQ?ё?????͝?Ξ?PPPPPP?ϟ?ё??А??ё?Ξ?ё?PPPPPP????QQQQQQ??ё??Ԕ?֖?ߟ????ښ?VVVVVV???YYYYYY??֖???VVVVVV?XXXXXX???Ԕ???SSSSSS?SSSSSS??ӓ?Օ???ؘ??֖?WWWWWW???pppppp?ZZZZZZ?ZZZZZZ?ۛ?䴴???[[[[[[??????ח?Օ??Ғ??ӓ??UUUUUU????SSSSSS?????Ғ?ח?TTTTTT????Ԕ?Ғ???RRRRRR??Ғ?ӓ?QQQQQQ???̜?ϟ?ӓ?Ғ?А?А?Ғ????RRRRRR???ϟ????А???А?????͝?PPPPPP??UUUUUU?????RRRRRR??PPPPPP??ё?ё?ё?QQQQQQ??Ғ?Ғ?TTTTTT??QQQQQQ??ӓ??̜?Ɩ?Ɩ??ϟ?PPPPPP?TTTTTT??RRRRRR?ё???̜?Ș??Ș??Ș?ə??????’??’??’?Ɩ??????ё???Ĕ?ŕ?Ɩ??????????????PPPPPP???Ó?????Ó??Ĕ?????????????????????Ș?ʚ?ŕ?Ș?ə???ʚ?ʚ???͝??̜??Ξ??ؘ?Օ?А?Ξ?PPPPPP??ё??А?RRRRRR?QQQQQQ??А????RRRRRR???UUUUUU??Ғ?QQQQQQ?Օ?ర??111111???]]]]]]?ۛ?PPPPPP?^^^^^^?[[[[[[???YYYYYY?ZZZZZZ??ח?֖?XXXXXX??֖?????ח??ܜ??֖?WWWWWW????ZZZZZZ?^^^^^^?pppppp?ݝ?ߟ?rrrrrr?555555???????֖??֖?TTTTTT????Ԕ???Օ?????SSSSSS?RRRRRR??ӓ??Ԕ??????RRRRRR????RRRRRR?QQQQQQ?QQQQQQ?А????ӓ??Ғ??ё?ӓ??SSSSSS?А?PPPPPP?А?QQQQQQ?А???А?А?????А?̜???RRRRRR??А?ϟ?͝?PPPPPP??ϟ?А?А??ё???Ғ?ӓ?Ғ?RRRRRR?RRRRRR??А???Ș?̜?ё?ϟ?ё???ӓ?Օ?ё?А?˛??ə???ʚ??????ʚ?ŕ?Ĕ???Ó??Ĕ????’??’??Ɩ??Ĕ???’??????????ŕ???Ó??????ŕ???????’?Ó?????Ɩ???’?ə???’???ə?ŕ??Ș?Ǘ???ʚ?ϟ???͝?Ș??ʚ?̜?PPPPPP??TTTTTT???̜??TTTTTT??QQQQQQ??YYYYYY??ё?UUUUUU??Ԕ?QQQQQQ?RRRRRR?Ԕ??Ғ?SSSSSS??UUUUUU??xxxxxx??RRRRRR?]]]]]]???ᑑ?㳳?ޞ?[[[[[[?pppppp?ᑑ?ޞ???Օ?WWWWWW?YYYYYY?ZZZZZZ?YYYYYY??TTTTTT??ZZZZZZ?ZZZZZZ????ח?ח?Օ?Ԕ????YYYYYY?WWWWWW?PPPPPP?ߟ?000000???ٙ???ٙ????VVVVVV?UUUUUU?Օ?UUUUUU?XXXXXX??UUUUUU???VVVVVV??Ԕ?Ԕ????????Ғ?͝??ё??RRRRRR?ӓ?Ғ?Ғ?RRRRRR?QQQQQQ?SSSSSS??ӓ?RRRRRR?ё??ё???Ғ??ё??RRRRRR???А??А?PPPPPP?ё??А?QQQQQQ?Օ?Ғ??А?ё?QQQQQQ?А?Ξ???Ξ?ϟ???QQQQQQ??RRRRRR?Ғ?RRRRRR?RRRRRR?QQQQQQ?ё??ё????ӓ?QQQQQQ??RRRRRR?QQQQQQ?ӓ?RRRRRR?Ԕ??PPPPPP???А?Ξ???ə?˛??Ɩ?’??Ɩ??Ĕ??’?Ɩ???’????’?????????’?Ó?’???????’????ŕ?????’?Ǘ?PPPPPP?Ĕ?Ó??Ɩ???Ó???????ʚ?Ș????????Ɩ?ə???Ș??֖??˛?ə?ʚ??ə??Ș?ə?ʚ?ə?˛?˛?̜?А?А????RRRRRR??ё?ё?RRRRRR?ё?RRRRRR??RRRRRR??ӓ??ZZZZZZ?㓓?ᑑ?[[[[[[????Ⲳ??ర?XXXXXX??000000????UUUUUU????UUUUUU??ٙ?Օ?ښ??\\\\\\??ښ?YYYYYY?????ٙ?000000?ښ???ؘ??^^^^^^??ޞ?ۛ?ܜ?pppppp?ښ?YYYYYY?XXXXXX?XXXXXX?ח?YYYYYY??֖??֖??WWWWWW???ח?֖??Ԕ??Ԕ????ϟ??˛?ё?ӓ?Ԕ?VVVVVV?Օ??TTTTTT??]]]]]]?ZZZZZZ??QQQQQQ???????XXXXXX?ӓ?Ғ?????Ξ???QQQQQQ?ё?ё???˛????Ғ??ё?ϟ???Ξ??А???ӓ?RRRRRR???QQQQQQ??ӓ?RRRRRR???????Ғ??ӓ?ӓ?Ԕ?TTTTTT?Ξ???А??Ξ?ə?Ǘ???Ɩ?Ǘ?Ó??ŕ?Ó??ŕ??????????ŕ?Ɩ?Ó??????????PPPPPP?’???????ə?????????ʚ?ŕ????Ɩ??Ó?ŕ?’???̜??Ǘ???Ĕ?Ǘ??????Ɩ???Ɩ???Ξ?Ξ??ϟ?͝????˛???А?ϟ???А???????А?ё?????ٙ??ߟ??\\\\\\??YYYYYY????ޞ?ؘ??______??WWWWWW?ؘ?WWWWWW?VVVVVV??XXXXXX??VVVVVV???֖?WWWWWW??ؘ????WWWWWW???ZZZZZZ?______??ܜ???[[[[[[?ٙ??ۛ?ۛ?ݝ??ۛ??ۛ????XXXXXX?ZZZZZZ??ZZZZZZ??XXXXXX??WWWWWW??VVVVVV?Օ????VVVVVV?Օ??QQQQQQ?ё?RRRRRR?SSSSSS?ӓ???UUUUUU?ӓ?UUUUUU?Օ?VVVVVV?SSSSSS?RRRRRR???ښ??UUUUUU?Ԕ??ᱱ?Օ?SSSSSS?RRRRRR?ӓ??ё??TTTTTT?RRRRRR??RRRRRR?А??Ξ?Ș?PPPPPP?֖?ё??QQQQQQ??ϟ??ё?PPPPPP?͝??А??QQQQQQ??Ғ?Ԕ?ӓ?ӓ?RRRRRR??͝???͝?????????͝?PPPPPP?ϟ?̜?̜?ə?Ș??Ɩ?Ǘ?Ɩ?Ɩ?Ó???ŕ?’??’??????Ĕ??Ĕ?????????????Ĕ?’???????Ɩ???ӓ?????ŕ??Ó?????Ó????’?Ǘ??ŕ?Ș??’????????˛?ə?Ș?Ǘ??͝?˛?̜?̜?̜?ʚ??̜??Ξ?Ғ??ϟ??PPPPPP?͝?????ё?QQQQQQ?PPPPPP???ё???TTTTTT??Օ?ZZZZZZ????ZZZZZZ??ޞ????ؘ?YYYYYY?ٙ?????UUUUUU??WWWWWW???TTTTTT???Ԕ????ۛ???ZZZZZZ?YYYYYY?^^^^^^??ޞ???֖?[[[[[[????ZZZZZZ?ZZZZZZ?ۛ?ᱱ?ర?ۛ???UUUUUU?UUUUUU?ח?ٙ?XXXXXX?XXXXXX????Օ?UUUUUU???ח?WWWWWW?VVVVVV??Ԕ?Ғ?TTTTTT??Ԕ?TTTTTT?Ԕ?TTTTTT??ZZZZZZ???WWWWWW????ZZZZZZ??ח?Ԕ?Ԕ???TTTTTT???Ғ??PPPPPP??Ғ??TTTTTT?QQQQQQ?Ξ????Ғ?RRRRRR??ӓ?ё?QQQQQQ??А?PPPPPP?А?????SSSSSS?Ԕ?SSSSSS?RRRRRR?SSSSSS??Ғ?RRRRRR??͝???QQQQQQ?ё??RRRRRR??QQQQQQ?ϟ??ϟ???А???ə?Ș?Ǘ????????Ó??Ĕ????Ó??Ǘ?’??’????????Ó?’???Ɩ???Ó????’??Ó??ʚ?͝????Ó?’?Ɩ??????Ó????Ɩ?ŕ????Ĕ?ŕ?Ș?Ɩ???˛?Ǘ??Ș?????ʚ?QQQQQQ?Ξ??̜?Ξ??QQQQQQ?TTTTTT???А?PPPPPP?ё??̜?͝?А??SSSSSS??YYYYYY??QQQQQQ?RRRRRR???TTTTTT??Ԕ?Ԕ??Ԕ?XXXXXX??]]]]]]??֖?Օ??֖??ٙ?ח???TTTTTT?VVVVVV??Օ?Ԕ?UUUUUU?֖??֖?Ԕ??ؘ??ؘ?????XXXXXX?YYYYYY?\\\\\\?ۛ?ؘ?ؘ???ٙ?XXXXXX??ۛ???YYYYYY???????VVVVVV???ח?WWWWWW?֖???XXXXXX???YYYYYY??ؘ?WWWWWW?Օ?Օ??ӓ?????֖???֖???֖?000000???Ғ??TTTTTT??Ғ???RRRRRR???SSSSSS?Ғ?А???TTTTTT???PPPPPP??SSSSSS?RRRRRR???А?ϟ????ё?RRRRRR?ӓ??SSSSSS??SSSSSS?Ԕ?SSSSSS??ӓ??Ɩ???PPPPPP???А?TTTTTT?RRRRRR???ϟ?ϟ?ё?Ξ?ϟ??QQQQQQ?˛??ʚ????’?Ǘ?ŕ?’???Ó??ŕ?Ĕ??Ĕ?ŕ?????????’??????????Ó?????˛?????]]]]]]?Ԕ??Ĕ??????PPPPPP???’???Ɩ??Ș????’???ə?˛??ʚ?ϟ?ϟ????˛???Ξ??ϟ?RRRRRR?Ξ???PPPPPP??̜?ϟ??̜???ϟ???TTTTTT??TTTTTT?SSSSSS????Ԕ??VVVVVV?SSSSSS??UUUUUU?VVVVVV???VVVVVV???XXXXXX???WWWWWW??Օ???Օ?Օ?UUUUUU??UUUUUU????YYYYYY?XXXXXX?WWWWWW?XXXXXX??ݝ??UUUUUU??YYYYYY??]]]]]]?YYYYYY?ٙ?ښ??ٙ?ח?ZZZZZZ???ؘ??ښ?ZZZZZZ??YYYYYY?WWWWWW?֖??֖??????WWWWWW???ؘ????????Օ??֖?????WWWWWW???Օ??Օ??TTTTTT?TTTTTT?Ԕ?SSSSSS????QQQQQQ?RRRRRR?ё?ӓ??SSSSSS?̜??TTTTTT??˛???ח?ܜ???UUUUUU?Ξ??А?PPPPPP??ё?ё?RRRRRR?SSSSSS?SSSSSS????QQQQQQ??PPPPPP?ʚ?Ǘ?Ǘ?Ɩ?Ɩ???RRRRRR??QQQQQQ?А?ϟ???PPPPPP?Ξ?PPPPPP?͝???Ș???ŕ?Ɩ?????’????ə??Ĕ??Ĕ??????????Ó????ʚ????’?Ɩ????Ǘ???ŕ?˛??Ғ????Ĕ??’?Ɩ?Ξ??Ó?ŕ??ʚ????Ξ??ə???ё?Ș?ʚ?ʚ?QQQQQQ?????͝?PPPPPP?SSSSSS?RRRRRR?RRRRRR?Ғ?ϟ???А?PPPPPP?QQQQQQ?͝?˛??˛??ʚ?ə?͝?ʚ??ӓ??Ԕ?ٙ?????ۛ?WWWWWW?SSSSSS?WWWWWW??TTTTTT?VVVVVV??ח?ؘ??ښ??????XXXXXX?ؘ?ؘ?ח??Օ?ח?VVVVVV???ח?ؘ??֖?ZZZZZZ?XXXXXX?WWWWWW?֖?YYYYYY?????[[[[[[???ח???ٙ??ښ????ښ?ZZZZZZ??ח?ח?WWWWWW?????WWWWWW???ZZZZZZ??ٙ???????ח?VVVVVV???ٙ?000000??WWWWWW?WWWWWW?֖??Ԕ?Ԕ?UUUUUU???Ԕ??TTTTTT??QQQQQQ?QQQQQQ????UUUUUU?????Ξ?ϟ?А????ؘ?UUUUUU?]]]]]]?QQQQQQ?ϟ?PPPPPP??А???ӓ???SSSSSS?ӓ???QQQQQQ?̜???????А??QQQQQQ???PPPPPP?Ξ?QQQQQQ?ϟ??͝?͝?YYYYYY???Ɩ?Ó??’?Ó?Ó?Ó?Ó?’???ŕ?Ξ?Ɩ??Ó?Ĕ??????????Ó?˛?????Ɩ???Ĕ??TTTTTT??ə?ϟ?̜?Ĕ?’?Ɩ?ŕ?Ó??????ŕ??ŕ?Ǘ??Ș???˛?ə?Ǘ?ʚ?˛??ʚ??͝??̜?͝?ӓ????ϟ???ӓ?ӓ?ё????Ξ?͝???̜??PPPPPP?Ξ?Ș????͝??ӓ?VVVVVV?SSSSSS??ؘ?֖??????Ԕ?Օ?֖?Օ??YYYYYY???֖??ؘ??UUUUUU?ח?ݝ?QQQQQQ?UUUUUU??TTTTTT??VVVVVV???Օ??֖????????ZZZZZZ?______?\\\\\\??ٙ?YYYYYY??ٙ????ۛ??ښ?ٙ?ښ?ٙ??ؘ?ח????WWWWWW?XXXXXX?ח??֖?WWWWWW????????VVVVVV??WWWWWW?֖?ח?ٙ?ٙ???VVVVVV????XXXXXX?Ԕ?Ԕ???TTTTTT??Ԕ?Ғ??RRRRRR?Ғ?Ғ??Ғ??Ғ???Ξ?PPPPPP?SSSSSS??QQQQQQ??RRRRRR??Ғ???А?ϟ???RRRRRR?RRRRRR?SSSSSS?Ԕ???ӓ?Ғ??????ʚ????ϟ?QQQQQQ??А??ё?Ԕ??͝??Ξ?˛???ŕ??’??Ó?̜????ŕ?Ó?Ǘ?Ó???????’??’?????????Ó??Ɩ?Ó???ё???’??ŕ?’?????Ș?PPPPPP??Ɩ?Ó??Ǘ??Ǘ??ŕ??ʚ?ə??˛??Ξ?RRRRRR????Ғ?RRRRRR??А???̜?TTTTTT?ח?UUUUUU?PPPPPP????͝?̜?ʚ?̜????QQQQQQ?͝??Ξ?Ξ??RRRRRR?RRRRRR?ё??ӓ??QQQQQQ?\\\\\\??????ח??TTTTTT?YYYYYY?TTTTTT?Օ?֖????Օ?Ԕ???UUUUUU???VVVVVV?RRRRRR????Ԕ??ؘ?\\\\\\?YYYYYY???ؘ????ښ?YYYYYY????YYYYYY??ۛ???ښ?\\\\\\??ۛ?ښ??[[[[[[?ZZZZZZ????????????WWWWWW?ؘ?ؘ?XXXXXX???WWWWWW?ؘ?WWWWWW?WWWWWW?XXXXXX?ؘ?ח?WWWWWW??UUUUUU?VVVVVV?VVVVVV?WWWWWW?֖??UUUUUU?????TTTTTT?Օ?Ԕ?Ғ?ӓ????Ғ???А?А?А??ӓ?Ғ???????PPPPPP???????SSSSSS?TTTTTT?Ғ?SSSSSS?Ғ?ח??RRRRRR??????RRRRRR??QQQQQQ?А??QQQQQQ??А??Ξ?Ξ?̜?˛?Ξ?????Ó??’?Ɩ?ŕ?Ɩ?????’?????’????’???’?’??????Ó?’??Ó?ŕ???Ó?Ǘ???Ó?Ĕ??Ó??ŕ???ŕ?Ș????Ɩ??Ɩ??Ó???ϟ??SSSSSS??Ξ?QQQQQQ??ϟ?Ξ??̜?͝????˛????QQQQQQ????ə???TTTTTT?͝??RRRRRR?ӓ?ӓ?QQQQQQ????ё??VVVVVV??TTTTTT?ח?VVVVVV?VVVVVV?Օ?Ғ??UUUUUU???֖???VVVVVV??Օ??Ԕ?ӓ?TTTTTT??UUUUUU??֖??ё????TTTTTT????ؘ???WWWWWW???]]]]]]?YYYYYY??]]]]]]??????YYYYYY?ܜ?ٙ?ZZZZZZ???ర???ZZZZZZ?YYYYYY??ؘ?YYYYYY?XXXXXX???֖?VVVVVV?֖??֖?֖?ח??VVVVVV?֖??VVVVVV?XXXXXX??ח?ؘ??ח?ח?ח???֖????VVVVVV??SSSSSS??Օ?Ԕ?ӓ??SSSSSS?SSSSSS????ӓ?SSSSSS????PPPPPP???А?Ғ?SSSSSS???А?ϟ?????RRRRRR?SSSSSS?ӓ?Ғ??????ϟ???ʚ??QQQQQQ????QQQQQQ???А?͝?Ξ?͝?͝?͝?PPPPPP??֖??Ɩ?ə?Ǘ????Ó?Ĕ?ŕ?Ĕ???ŕ?˛??ŕ????’?Ș??ϟ?Ș????ŕ??????Ó?Ó?????ŕ?ŕ??Ɩ??ŕ?̜??Ó??ə???Ș?˛??ŕ???Ĕ?Ɩ?ʚ?˛??А???ϟ???͝?Ξ?͝??̜???Ξ????ϟ?͝??˛??͝?̜???ϟ?PPPPPP?Ғ?WWWWWW??QQQQQQ???RRRRRR????ח?SSSSSS???WWWWWW??Ғ?Ғ??SSSSSS?Օ????ۛ??TTTTTT?TTTTTT?ח?SSSSSS??Ԕ???TTTTTT?SSSSSS?Ғ?Ԕ?ښ?ؘ??ZZZZZZ??ؘ?ؘ?YYYYYY?ח????ښ?YYYYYY???ٙ???ٙ?XXXXXX?ٙ?YYYYYY??ۛ???ۛ?______??ݝ??ZZZZZZ?????WWWWWW??֖??VVVVVV???WWWWWW?ח?ؘ?XXXXXX?ؘ??֖?ח?XXXXXX????ؘ?WWWWWW?ח?ח??֖??TTTTTT????Ԕ????RRRRRR?SSSSSS?ӓ??????ӓ?RRRRRR?RRRRRR???PPPPPP??ϟ??SSSSSS?RRRRRR??Ξ???PPPPPP??UUUUUU?SSSSSS?TTTTTT?Ғ???QQQQQQ??????А?Ǘ??֖??Ғ?????А?Ξ??Ξ?PPPPPP?Ξ?Ξ??ŕ?Ĕ??Ĕ??ʚ?Ǘ?????Ó?ŕ???Ó?????’??Ғ?Ó??????Ó?Ĕ????Ĕ??????’???Ɩ??Ĕ?Ĕ?Ĕ???ŕ???ŕ?Ș?ŕ?Ș?Ɩ?Ǘ??̜?Ξ?ʚ??̜??RRRRRR?˛?̜?QQQQQQ?ϟ??????А?͝?ʚ??А?͝??˛???ə?̜??Ԕ??PPPPPP???????ё??RRRRRR?SSSSSS?????֖?WWWWWW?RRRRRR??TTTTTT?Ԕ?UUUUUU?TTTTTT?VVVVVV?Ԕ??WWWWWW?SSSSSS?SSSSSS?????TTTTTT?TTTTTT?RRRRRR??Ғ?????????ؘ???ؘ?ښ????YYYYYY?ښ??ښ?ۛ??ؘ?ٙ???ښ?\\\\\\?\\\\\\?ܜ?????]]]]]]?[[[[[[?ۛ?YYYYYY?XXXXXX?ؘ????ח??XXXXXX???YYYYYY??ח???VVVVVV?WWWWWW?ښ??????WWWWWW?WWWWWW??VVVVVV?Օ?????ӓ?Ԕ??RRRRRR??Ғ?RRRRRR??TTTTTT???SSSSSS???RRRRRR?А?̜??QQQQQQ??UUUUUU?ϟ??ё????ӓ??RRRRRR?SSSSSS?Ғ???VVVVVV??SSSSSS?????ϟ??RRRRRR?Ғ???ё?А???Ξ?Ξ???ə?ə??????????????Ó??????Ó???????Ó?Ĕ???Ó????ŕ?Ș??А?????ё?Ĕ??ŕ?ŕ?Ó?Ɩ?Ó?ŕ?PPPPPP?Ĕ?Ĕ???Ș??̜?????ϟ??Ғ?UUUUUU??RRRRRR?QQQQQQ?А?ӓ???PPPPPP?PPPPPP?ϟ?PPPPPP???͝?PPPPPP?͝?????ʚ??????Ғ?ӓ???ӓ???ё??֖???VVVVVV??XXXXXX??֖?Ԕ?VVVVVV??Օ????UUUUUU?SSSSSS?А?PPPPPP??RRRRRR?ё?Ғ??SSSSSS??ё???WWWWWW?ٙ?ؘ?ח???YYYYYY???YYYYYY?YYYYYY??ؘ??YYYYYY????ۛ?ښ????ٙ?ښ??[[[[[[????ݝ???\\\\\\???ښ??ښ?ZZZZZZ?ؘ?ؘ?֖??ח?ח??ؘ???֖??ח??YYYYYY???ח??WWWWWW?ח???UUUUUU??Օ??UUUUUU?֖??TTTTTT??SSSSSS???Ғ?RRRRRR??RRRRRR??SSSSSS??Ԕ?WWWWWW???Ξ?ӓ??А????͝?ϟ???Ғ?SSSSSS?ӓ?ӓ?TTTTTT????ё?А???ʚ?А?QQQQQQ?PPPPPP?QQQQQQ?PPPPPP?QQQQQQ?А?А?PPPPPP????̜?̜?Ǘ?Ɩ?????Ĕ?ŕ???’?Ĕ??ŕ?Ɩ?ŕ?’?ʚ?Ǘ?Ó??Ó?Ó??Ó?’?Ó????’????Ó??Ĕ?????’?Ó?’??ŕ???Ξ?ŕ?Ǘ?’???Ĕ?Ó??ʚ?ə?ə?????SSSSSS??XXXXXX?ݝ?UUUUUU??̜????SSSSSS?PPPPPP?QQQQQQ?А????͝????˛??Ξ?????ӓ?TTTTTT??Ғ?Օ?ח??TTTTTT?RRRRRR?SSSSSS?SSSSSS?ӓ?UUUUUU?Օ??Ғ?TTTTTT?֖?ښ??WWWWWW?ٙ?XXXXXX?Ԕ????RRRRRR?А??ϟ??????SSSSSS??Ԕ?UUUUUU?Օ?ח?WWWWWW?XXXXXX?ח?ؘ?YYYYYY?ZZZZZZ??XXXXXX?XXXXXX??WWWWWW?YYYYYY?YYYYYY?ZZZZZZ???[[[[[[???[[[[[[?YYYYYY???YYYYYY?[[[[[[???[[[[[[??ۛ?]]]]]]?ۛ????????ٙ?YYYYYY?ؘ?ٙ?YYYYYY????XXXXXX?WWWWWW???ؘ???ٙ????WWWWWW???֖?֖????֖????ӓ?TTTTTT???TTTTTT?????ӓ?Ғ?ӓ?????QQQQQQ?PPPPPP?ϟ???Ș?ϟ???????Ԕ??ӓ?RRRRRR?PPPPPP?˛?˛??ё?ϟ?̜??ё?А?ӓ????Ξ????ϟ?Ɩ?Ɩ???Ǘ???’?’??’????’?????’???’?Ĕ??Ɩ???PPPPPP??’?’???Ș???ʚ??????????ŕ???Ó??Ó?Ĕ??????ё?͝?̜?ʚ????XXXXXX?QQQQQQ?֖?ё??͝?RRRRRR????ё?͝?͝??ח?Օ?̜?͝?ʚ????͝?PPPPPP?Ғ?TTTTTT??Ԕ?RRRRRR?RRRRRR???UUUUUU?TTTTTT??Ғ????ӓ?????ٙ?YYYYYY?ZZZZZZ???Ԕ???ח??ё??ϟ???QQQQQQ??SSSSSS?Ԕ?WWWWWW??VVVVVV?Օ???????ٙ??YYYYYY?ؘ?ښ?ۛ?ٙ?ٙ?ݝ???[[[[[[??[[[[[[??[[[[[[??ZZZZZZ?ZZZZZZ???pppppp?______?ݝ?______????????????\\\\\\????ٙ??ٙ????XXXXXX?XXXXXX?YYYYYY????XXXXXX?XXXXXX?WWWWWW?WWWWWW????֖??ח?WWWWWW?Օ?ӓ?QQQQQQ?TTTTTT??֖?Օ?Օ?TTTTTT??ӓ?TTTTTT?TTTTTT??Ғ??Ξ?ϟ?А?QQQQQQ?͝??ə?̜?˛??Ғ?Ғ?Ғ???TTTTTT?UUUUUU??QQQQQQ?А??ё???ӓ??QQQQQQ???ϟ?SSSSSS??ё???ə??Ǘ?Ǘ?Ș?ŕ?Ɩ??ŕ?Ș?’???????????????Ó?Ó?Ĕ??Ɩ?Ĕ???????????????Ĕ???Ɩ??Ĕ?’???’???Ǘ?????ё?̜?????VVVVVV???Ғ?Ξ?Ғ?ϟ??VVVVVV???͝?Ξ?͝???͝??˛?ʚ??ʚ??ə?͝??WWWWWW?ӓ?RRRRRR???ё?Ғ?ӓ???ӓ???Օ?Ғ?SSSSSS??SSSSSS?UUUUUU?UUUUUU??ח?XXXXXX?VVVVVV?TTTTTT?Ԕ??TTTTTT?ӓ?RRRRRR?QQQQQQ?Ԕ?ח???Ԕ??????ח???YYYYYY??WWWWWW?ZZZZZZ?]]]]]]?ZZZZZZ??XXXXXX?ښ???ٙ??]]]]]]?\\\\\\??ZZZZZZ???ښ????ߟ?Ⲳ?WWWWWW??ߟ??\\\\\\???ܜ?ܜ?ݝ?ݝ??ܜ??^^^^^^??^^^^^^????ZZZZZZ?ٙ???ؘ????XXXXXX?ؘ?YYYYYY?YYYYYY?\\\\\\??ח?ח????֖????RRRRRR?RRRRRR?Ԕ???Օ???UUUUUU?֖???SSSSSS?Ғ??Ғ?PPPPPP?ё??͝?ə??̜?PPPPPP?ё?Ғ?Ғ?Ғ?????RRRRRR?Ғ?ӓ???RRRRRR??֖?ϟ?VVVVVV?PPPPPP?PPPPPP??А??PPPPPP?QQQQQQ?Ξ????ə???Ǘ?Ș?Ǘ????Ǘ????????ʚ???????????Ș??Ó?Ĕ?SSSSSS???????’??’?ʚ??ŕ??ŕ??Ó??????˛??Ș?ə?ə?ʚ??͝?А????QQQQQQ??XXXXXX?ӓ?А?Ԕ??QQQQQQ?ϟ?Ξ???Ξ?QQQQQQ??͝?̜??ʚ????SSSSSS?RRRRRR?ё??QQQQQQ?А??Ғ??ӓ?ӓ??Ғ?ё?Օ?UUUUUU??????А?А?YYYYYY??VVVVVV?Ԕ?Օ??TTTTTT?SSSSSS?TTTTTT?Ԕ??RRRRRR?TTTTTT?Ԕ??֖?WWWWWW?XXXXXX?֖???WWWWWW??XXXXXX?WWWWWW??????______?ۛ??ٙ???ښ?\\\\\\???YYYYYY???ZZZZZZ??ޞ??????000000???ښ?[[[[[[?\\\\\\?ܜ?]]]]]]?______????ݝ?ޞ?______??????ښ?????ښ??ٙ??ۛ?YYYYYY?ۛ?ח???ؘ?ٙ?ؘ?WWWWWW?VVVVVV?֖??QQQQQQ??Օ?UUUUUU??TTTTTT???UUUUUU?TTTTTT??SSSSSS?ё?QQQQQQ???RRRRRR??Ξ?ʚ??͝??RRRRRR?ӓ?????ӓ?QQQQQQ?????SSSSSS?PPPPPP?Ξ???PPPPPP?ϟ?PPPPPP?ё?PPPPPP??А?PPPPPP????͝?ə???Ĕ?ʚ?Ɩ?Ɩ??Ș??Ș????Ĕ?PPPPPP?Ξ?Ǘ?ŕ??Ó???’?Ó???Ș?˛?Ǘ??Ǘ?ŕ??’????’?’?Ĕ?Ɩ???Ǘ?Ĕ?Ó?Ó?Ó??ŕ?????ə?˛?ʚ?ə?̜?????Ғ?rrrrrr?UUUUUU??А??QQQQQQ?ϟ?TTTTTT?TTTTTT?QQQQQQ?PPPPPP?ϟ?Ξ?Ξ?˛?˛?͝??͝?̜?͝?ё?Ξ?ё?ϟ?PPPPPP?ϟ?RRRRRR?Ғ?ё??QQQQQQ??Ғ?ח?RRRRRR?Օ???Ғ?QQQQQQ????QQQQQQ??????TTTTTT??SSSSSS?SSSSSS?Ғ??Ԕ?Ԕ?TTTTTT??VVVVVV??WWWWWW??WWWWWW??ؘ??VVVVVV?WWWWWW??ZZZZZZ?ZZZZZZ?[[[[[[???RRRRRR??ۛ????[[[[[[???????[[[[[[?______?000000?ߟ?ޞ?qqqqqq?????______??ܜ??????111111??ర?______??______?ߟ???ZZZZZZ?ٙ?ښ????ٙ??ٙ?[[[[[[?ۛ?ܜ?[[[[[[????ؘ?ؘ?ۛ???ח??ӓ???UUUUUU?Օ?TTTTTT???UUUUUU?UUUUUU?TTTTTT?TTTTTT??RRRRRR?ӓ??ӓ?SSSSSS??????Ғ?ӓ????SSSSSS?Ԕ?SSSSSS???RRRRRR?֖??ё?Օ????????А??Ξ?Ξ?ʚ??˛?ʚ?Ɩ???Ɩ???Ɩ?Ș?Ĕ?Ó??ŕ????Ó???Ɩ?Ĕ???Ĕ?ŕ?Ĕ?Ĕ??͝?Ĕ??Ĕ?Ɩ????Ĕ?’???’???ŕ??????Ĕ??Ɩ?Ǘ?????ə?͝????ϟ??ё?\\\\\\?WWWWWW?ё?ё?RRRRRR??QQQQQQ??VVVVVV?А?ϟ??͝??˛??А???А?SSSSSS?Ξ????ё?QQQQQQ??????ё?RRRRRR?ח??RRRRRR?ӓ????Ԕ?TTTTTT?SSSSSS?SSSSSS?TTTTTT??TTTTTT??WWWWWW????SSSSSS????ח??Ԕ?????VVVVVV?WWWWWW??ښ??]]]]]]?ؘ???ښ?ޞ???????[[[[[[????֖??YYYYYY???ݝ??[[[[[[??ښ?ۛ?______????QQQQQQ?PPPPPP?ޞ??]]]]]]?ర???000000??ܜ???pppppp??ܜ????ؘ?ٙ?]]]]]]?XXXXXX?ZZZZZZ?ؘ??ZZZZZZ?ۛ?[[[[[[??^^^^^^?]]]]]]???ZZZZZZ?WWWWWW?Օ?????Օ?TTTTTT????֖???WWWWWW??TTTTTT?QQQQQQ??ӓ?SSSSSS????????RRRRRR?ӓ?ӓ?RRRRRR??????RRRRRR?SSSSSS??SSSSSS???TTTTTT???RRRRRR??ӓ????А????ϟ??Ɩ??Ĕ?Ɩ???ŕ??Ó?Ǘ??Ɩ??????’???Ĕ????Ĕ?Ó?Ɩ?Ĕ???ə??Ĕ??Ĕ?’?Ɩ??ŕ?Ĕ??ŕ??Ó?Ó?????ŕ?ʚ?͝?˛?̜?ə??ё???TTTTTT?А?VVVVVV???ӓ?А????QQQQQQ?SSSSSS????̜???̜??QQQQQQ?QQQQQQ?А??̜?Ғ???RRRRRR???UUUUUU?Ғ?ؘ?ϟ?QQQQQQ??Ԕ???UUUUUU?ӓ??ؘ???ӓ???֖?ӓ?ӓ??????QQQQQQ?TTTTTT?UUUUUU?ח?Օ?Օ??֖???XXXXXX?WWWWWW?ؘ?ZZZZZZ?ٙ???\\\\\\?ZZZZZZ???ܜ?ܜ????QQQQQQ????TTTTTT???\\\\\\?ܜ??______????ݝ??^^^^^^?ݝ?ݝ?ޞ??qqqqqq??PPPPPP?______?pppppp???ర??pppppp????111111?^^^^^^?]]]]]]??\\\\\\?ښ??ZZZZZZ???______???ؘ????^^^^^^??000000??ښ?YYYYYY?WWWWWW?VVVVVV??֖???ח?֖??VVVVVV?WWWWWW?VVVVVV?UUUUUU???TTTTTT???Ғ??ё???????Ғ?RRRRRR??????PPPPPP??ӓ?TTTTTT???XXXXXX???VVVVVV?VVVVVV?Ғ???pppppp?UUUUUU????ӓ??ϟ??ʚ?Ǘ??Ǘ????ŕ??Ó??Ș???Ĕ?ŕ??TTTTTT?ϟ?PPPPPP?Ĕ???’???Ó?Ĕ?Ĕ??Ԕ??Ó????ŕ??Ɩ??Ĕ?Ó??Ó????ŕ?Ǘ?Ɩ?ʚ???ϟ???Ғ?TTTTTT?______?WWWWWW??????RRRRRR??͝??ϟ?PPPPPP??Ԕ?UUUUUU?ϟ?͝?RRRRRR?QQQQQQ?˛?А?PPPPPP?????QQQQQQ????????RRRRRR?SSSSSS?Ԕ?YYYYYY????Օ??Ԕ?VVVVVV?Օ??????RRRRRR?QQQQQQ??А?RRRRRR??RRRRRR?UUUUUU?Օ????Օ??ٙ????UUUUUU?ܜ?______??XXXXXX??WWWWWW??????ۛ?ۛ??[[[[[[?ښ?ח??????pppppp?rrrrrr??VVVVVV?????ۛ?\\\\\\?]]]]]]?????ᑑ?QQQQQQ?ᑑ??pppppp?ర??qqqqqq?QQQQQQ?111111??ᑑ????ۛ?ۛ??pppppp?SSSSSS?㓓??ؘ?YYYYYY???ۛ?ޞ?111111?000000???ښ?YYYYYY???Օ??TTTTTT?????UUUUUU?UUUUUU??Օ????RRRRRR??Ғ?RRRRRR?SSSSSS??PPPPPP?????RRRRRR???Ғ?ӓ?UUUUUU???ϟ?RRRRRR??VVVVVV?WWWWWW?Ԕ??VVVVVV?Օ?ӓ?RRRRRR?А??ϟ?????ϟ??RRRRRR??̜?͝?Ғ??ə??Ĕ????Ĕ???ə?????Ș??’?ŕ????ŕ?????ŕ??’??????Ǘ?????Ĕ?’?Ó?ŕ???ə?Ș??Ξ??PPPPPP????qqqqqq???RRRRRR??????͝?͝?̜?ϟ??VVVVVV?TTTTTT??Ғ?ё?Ԕ???PPPPPP??А??ӓ?????TTTTTT???UUUUUU?????TTTTTT??ח?Ғ?Ғ?Ғ?Ғ?Ԕ?Ԕ??Ԕ?ӓ??PPPPPP???RRRRRR?RRRRRR?TTTTTT???SSSSSS??TTTTTT??֖?Օ??֖?WWWWWW??֖???ۛ?ٙ???ٙ?VVVVVV?WWWWWW??ۛ?ZZZZZZ?\\\\\\?\\\\\\?ښ?????ޞ?^^^^^^????啕?444444?RRRRRR?000000?pppppp??pppppp????Ⲳ??⒒??ᑑ??000000??ᑑ??PPPPPP???SSSSSS?000000?ޞ??[[[[[[??ܜ?]]]]]]?ޞ???????[[[[[[??\\\\\\?\\\\\\??]]]]]]?ܜ??XXXXXX????ח?Ғ?SSSSSS??WWWWWW?֖???VVVVVV???Ԕ?Ғ???TTTTTT?WWWWWW???TTTTTT?SSSSSS?????ח??SSSSSS?А???ʚ????WWWWWW??֖????SSSSSS?QQQQQQ???QQQQQQ?֖??SSSSSS??ϟ??̜?ʚ?Ξ?Ș?Ǘ?Ɩ?Ĕ?Ș?Ș??Ɩ???Ó??Ɩ??Ǘ??YYYYYY??ə?Ǘ???ŕ???Ĕ????Ș?Ĕ?Ĕ???ŕ?˛?Ԕ?Ș???Ó?Ó?Ó?ŕ?Ó?ŕ???˛?Ξ???Ξ?ZZZZZZ?ח?111111???WWWWWW?UUUUUU??Ғ?А??Ξ????˛?Ξ????Ғ?WWWWWW?^^^^^^????QQQQQQ?Ғ?ӓ?????TTTTTT?UUUUUU????ٙ?Ғ??ӓ?Օ?Ԕ??Ғ??RRRRRR?Ԕ?SSSSSS?ח?ӓ?Ғ???ϟ??QQQQQQ?Ғ?Ғ?Ғ?֖?Ғ???Օ?WWWWWW?ח??VVVVVV???ח??ח?ٙ??WWWWWW??ٙ??????[[[[[[?ݝ?______?______?^^^^^^?ޞ?000000?^^^^^^??ߟ?ݝ???ᑑ??QQQQQQ???ర?ssssss?ᑑ?qqqqqq??㳳?vvvvvv?333333?222222??pppppp??ర?ߟ?pppppp?pppppp???pppppp?qqqqqq??^^^^^^????\\\\\\?ޞ???ܜ?ZZZZZZ????\\\\\\??]]]]]]??ۛ??ۛ?\\\\\\?ٙ?ٙ?WWWWWW??????ח???VVVVVV?ח?ח??????[[[[[[?????[[[[[[??RRRRRR??Ғ?TTTTTT??QQQQQQ??ϟ??Ԕ?]]]]]]??Ԕ?UUUUUU????SSSSSS???А?ё?Ξ?ё?ӓ?VVVVVV????ə?ə????̜?????ŕ??Ó?Ĕ???Ɩ?Ǘ??͝?Ξ??ŕ?Ó?Ĕ?Ɩ?ӓ?ё??Ó????’?Ó????ʚ?ŕ???Ĕ???’??Ó?Ǘ??˛??ϟ??ё?WWWWWW?[[[[[[?ٙ???痗?ᱱ??TTTTTT??ϟ???????˛?QQQQQQ?А??XXXXXX?^^^^^^?000000?pppppp??ݝ??Օ?UUUUUU?WWWWWW?YYYYYY?֖??WWWWWW???\\\\\\??TTTTTT??Օ?XXXXXX?XXXXXX?Ԕ?UUUUUU???SSSSSS?????А???ϟ?????ӓ?TTTTTT??Օ?UUUUUU?WWWWWW?ٙ??ח?XXXXXX???XXXXXX?ח??ZZZZZZ?WWWWWW??ښ??ZZZZZZ???[[[[[[??ZZZZZZ?????QQQQQQ???ర?pppppp?ߟ?????333333?TTTTTT?ᱱ??⒒??Ⲳ???wwwwww?䴴??⒒?111111?ޞ??qqqqqq?111111?ర?????]]]]]]?????ޞ?]]]]]]?ޞ????\\\\\\???ښ?ۛ?\\\\\\?______?ܜ??\\\\\\?ర??[[[[[[?????PPPPPP????֖??VVVVVV?֖??Ԕ?ӓ?TTTTTT???ۛ???????ё?QQQQQQ?QQQQQQ?Ғ???Ԕ??Ԕ?YYYYYY??Օ??????ӓ??RRRRRR?????????̜??Ξ????Ș?Ɩ???Ɩ?ŕ??Ĕ??ŕ??Ǘ?Ș?Ș??ʚ???Ĕ?Ǘ?Ɩ????Ó?ŕ????Ɩ???Ɩ?Ĕ???Ș?Ɩ??Ó?Ó??ŕ??PPPPPP??UUUUUU??ښ???ޞ?ښ?pppppp?嵵??111111?UUUUUU??ё????Ξ????????PPPPPP?ߟ?qqqqqq???^^^^^^?ٙ?ؘ?????XXXXXX?XXXXXX??????Օ?Ԕ?Ғ??ӓ????Ғ????͝?А?QQQQQQ??RRRRRR?Ғ???UUUUUU??VVVVVV?WWWWWW?XXXXXX?YYYYYY?ٙ??ח???XXXXXX?ؘ??]]]]]]?ٙ?ZZZZZZ????ݝ?ܜ???YYYYYY?[[[[[[???ݝ????ߟ?ᑑ?PPPPPP??222222?⒒?222222?222222?TTTTTT?緷?TTTTTT????ssssss??RRRRRR?tttttt?䔔?嵵?SSSSSS?RRRRRR??ర??rrrrrr?rrrrrr??Ⲳ?444444?ݝ????pppppp?000000?000000??ޞ????ޞ???ۛ?\\\\\\????\\\\\\?????[[[[[[??????RRRRRR?TTTTTT??WWWWWW???????Օ?ؘ?ᱱ???ӓ??TTTTTT?SSSSSS??͝????QQQQQQ??TTTTTT?TTTTTT??XXXXXX??Ԕ?QQQQQQ??Ғ????SSSSSS?Ғ?RRRRRR?Ғ????͝???̜?PPPPPP???ʚ????ŕ?Ɩ??Ĕ??Ǘ?Ɩ?????Ɩ???ё???ə???Ó?Ĕ??Ó??Ɩ?????Ǘ?ə???Ó?Ĕ??Ó?Ǘ??ʚ?ӓ?Ғ?????ZZZZZZ?ؘ?VVVVVV?ښ?SSSSSS?䴴??XXXXXX???QQQQQQ?А?А??SSSSSS?̜?̜??А?TTTTTT?ޞ?㳳??䔔?VVVVVV?VVVVVV?ᑑ?ݝ??ޞ?ۛ??ۛ?ܜ??ߟ?ؘ?VVVVVV?֖????????ӓ?Ғ???ӓ?͝?Ξ?ё?Ғ???SSSSSS????UUUUUU?ח??ZZZZZZ?YYYYYY??ח??ښ?WWWWWW???ర?[[[[[[?]]]]]]?ܜ??]]]]]]??ޞ?ߟ??^^^^^^?\\\\\\?ܜ?ܜ??^^^^^^??ޞ?]]]]]]?ߟ?111111?222222???000000?ߟ?111111?㳳?涶???????333333?tttttt???ssssss????555555????????\\\\\\??ޞ??______??ߟ????^^^^^^????ܜ?ޞ?^^^^^^?ޞ?ܜ??ܜ??⒒???ۛ????Ԕ?UUUUUU???ؘ??UUUUUU???QQQQQQ??֖??UUUUUU???Ғ??ϟ?ё??RRRRRR??RRRRRR?RRRRRR??SSSSSS???WWWWWW??SSSSSS???̜?QQQQQQ??Ғ?ӓ?TTTTTT??SSSSSS??PPPPPP??˛?RRRRRR??̜??̜?˛??Ș??Ɩ?Ɩ?Ɩ?Ɩ???Ǘ??Ó?Ɩ??Ș???Ɩ?????ؘ??Ĕ?ŕ??Ș?’??̜??Ǘ?Ǘ???Ĕ?ŕ?Ó?Ó?Ǘ?Ș?ŕ????PPPPPP???ۛ????ZZZZZZ?[[[[[[?PPPPPP????TTTTTT????ϟ?Օ?????ϟ?ӓ???斖???777777??222222?Ⲳ?RRRRRR?RRRRRR??pppppp???ؘ??ח?ח?????SSSSSS???SSSSSS?SSSSSS????֖?RRRRRR?SSSSSS?Ғ??ӓ?ӓ?Ԕ?Ԕ?Օ??XXXXXX???YYYYYY?YYYYYY?XXXXXX?ؘ??ښ?ښ?ZZZZZZ??????ߟ???000000?000000???^^^^^^?______??ర?ᑑ??333333?嵵?㳳?RRRRRR??qqqqqq?QQQQQQ??RRRRRR??⒒?^^^^^^??ښ?SSSSSS?啕??SSSSSS??vvvvvv?TTTTTT?㓓?222222??rrrrrr??444444??333333??111111???ۛ??]]]]]]?ޞ??????ޞ?ޞ?000000???ۛ??ޞ?PPPPPP?]]]]]]?ܜ?ޞ?^^^^^^??]]]]]]????Ԕ??Օ???֖?WWWWWW?WWWWWW??Ԕ?Ԕ?QQQQQQ??VVVVVV?^^^^^^??UUUUUU?SSSSSS??ё??SSSSSS??RRRRRR??RRRRRR?WWWWWW?Օ?UUUUUU?ZZZZZZ?UUUUUU?UUUUUU????Ɩ?ϟ??TTTTTT?UUUUUU?UUUUUU???Ғ???PPPPPP?ϟ?Ғ?????ʚ??Ǘ?ŕ??ŕ?Ǘ??ə????Ǘ??PPPPPP?Ș?????Ɩ?Ĕ?Ɩ?ə???Ó???Ɩ?ŕ?Ǘ??ʚ?Ó???Ɩ?Ĕ?ŕ????Ĕ?????ӓ??YYYYYY??[[[[[[?ٙ????ٙ?ӓ?Ғ?YYYYYY?SSSSSS?TTTTTT?PPPPPP?Ξ?PPPPPP?RRRRRR??А?RRRRRR?ӓ?????緷??777777?涶?uuuuuu?嵵??tttttt???pppppp??WWWWWW??ח?Ԕ?SSSSSS???TTTTTT??ӓ?SSSSSS?Ԕ??YYYYYY?]]]]]]??Օ??SSSSSS?Ғ?ӓ?SSSSSS?ӓ?SSSSSS????????ZZZZZZ?ۛ?ݝ??[[[[[[?[[[[[[?ݝ???ߟ?pppppp?ޞ?ర?踸???ssssss?啕???111111??????????⒒??Ⲳ????????㓓?????䴴?䔔??333333?ߟ??ᱱ?ᑑ?RRRRRR?111111???ᱱ?]]]]]]?ښ?ݝ?000000?ߟ?????ᑑ??qqqqqq?111111?^^^^^^???????ܜ??ޞ??ۛ???YYYYYY??ח?ח?֖??֖?UUUUUU?UUUUUU?TTTTTT?ӓ??????TTTTTT?SSSSSS?RRRRRR?SSSSSS?ё??ё?RRRRRR???Ԕ??Օ?????ӓ?VVVVVV?ZZZZZZ??ӓ??֖?ӓ?RRRRRR?ё?RRRRRR?ё??TTTTTT?PPPPPP??ߟ???ə???Ǘ??ŕ?Ǘ????ŕ?????ZZZZZZ??ə?̜??Ĕ??Ĕ?Ɩ??ə?ŕ??ə?ŕ?Ɩ??ŕ?????ŕ?Ɩ??Ǘ??Ɩ?Ș?ə??Ԕ???VVVVVV???]]]]]]?ښ?XXXXXX?QQQQQQ??ё??????ё?ё?А?А?Ξ?ϟ??Ғ????______?ssssss?999999?yyyyyy??xxxxxx?踸????陙?333333?ޞ??ښ??WWWWWW?Օ???SSSSSS?SSSSSS?SSSSSS?RRRRRR?Ԕ?????PPPPPP??А?ё?RRRRRR????Ԕ?XXXXXX????WWWWWW??YYYYYY????pppppp?^^^^^^?ߟ??000000??ޞ?ర?\\\\\\?pppppp?666666?tttttt?⒒?111111?tttttt???㳳?⒒?222222?㳳?㓓???444444?㳳?㓓?222222??222222?⒒?qqqqqq?ᑑ??ᱱ???QQQQQQ?qqqqqq?ర?ర?ssssss?㓓?tttttt?SSSSSS?⒒?000000???ᑑ?ᱱ?ర??000000?ర?RRRRRR?ߟ?]]]]]]?ߟ?????PPPPPP?⒒?PPPPPP??㳳??^^^^^^??QQQQQQ?111111?㓓?^^^^^^??]]]]]]????ޞ?pppppp??ח??UUUUUU??Ԕ?UUUUUU???SSSSSS?????ӓ?VVVVVV?ӓ??QQQQQQ?А?Ξ??PPPPPP?А??????ח?WWWWWW?֖????ۛ?XXXXXX?Ԕ?Ԕ?TTTTTT??RRRRRR?Ԕ??ё???PPPPPP?͝??ё?ə??Ș???PPPPPP?̜?Ș?Ĕ???Ĕ??Ǘ???QQQQQQ?ϟ?PPPPPP????ʚ??ə??͝?ə?ʚ??ʚ?ʚ?ə??Ș???ə?Ɩ?Ɩ?Ǘ???А????ё????QQQQQQ?ښ??Ғ?QQQQQQ?ё??Ғ?А?ё??ӓ?Ғ?А??А?Ξ?ϟ???QQQQQQ?ӓ??ٙ?^^^^^^??嵵?[[[[[[?;;;;;;?[[[[[[?뻻?[[[[[[?[[[[[[??777777??QQQQQQ??ۛ??WWWWWW???ӓ??TTTTTT?RRRRRR?QQQQQQ?ӓ???ݝ??RRRRRR??SSSSSS???TTTTTT???֖?????ؘ?YYYYYY??ZZZZZZ??\\\\\\????ᱱ?______?ݝ??ݝ??PPPPPP?RRRRRR?RRRRRR?SSSSSS?SSSSSS?RRRRRR?䔔??ssssss?333333??䴴?啕?xxxxxx???ssssss???111111?ᱱ?ᱱ??pppppp?ᱱ?222222?rrrrrr??QQQQQQ?ᑑ?111111?______?Ⲳ?rrrrrr???RRRRRR?qqqqqq?ᱱ?????^^^^^^?PPPPPP??Ⲳ??ర?ߟ?ᑑ??111111?000000?000000?QQQQQQ?qqqqqq?ᑑ??PPPPPP?ߟ?ర?ߟ?^^^^^^?^^^^^^??ۛ?ۛ?[[[[[[???]]]]]]??\\\\\\???Ԕ??WWWWWW?WWWWWW????Օ????ӓ?????͝?Ξ?͝??А?ё?SSSSSS???YYYYYY?WWWWWW?֖??UUUUUU?WWWWWW?YYYYYY??UUUUUU?SSSSSS?ӓ??ӓ?RRRRRR?ё??А?Ғ?ϟ????Ξ???Ș?Ș??QQQQQQ????ŕ?ŕ?Ɩ?Ǘ???QQQQQQ?ё?PPPPPP??Ɩ??’?Ș?ё?̜???Ș???????Ɩ?????Ǘ?Ǘ?????А??ё?ӓ??Ғ???Ғ??PPPPPP?RRRRRR?????UUUUUU?SSSSSS???Ξ???ϟ?PPPPPP????WWWWWW?ZZZZZZ???888888?::::::?}}}}}}??}}}}}}???;;;;;;?888888?555555??PPPPPP????Ԕ?Ԕ?ӓ?SSSSSS?RRRRRR??ё?Ғ?WWWWWW?ח?ё??XXXXXX?Ԕ??TTTTTT??UUUUUU???????YYYYYY???ٙ????ߟ?ర?pppppp??ܜ???^^^^^^?ߟ??ᱱ?RRRRRR????ssssss???555555?䴴?tttttt???888888?㳳???qqqqqq?ర?ర?rrrrrr????pppppp?______?______??ᑑ?qqqqqq?pppppp????222222?RRRRRR?rrrrrr??pppppp??㳳?㳳?\\\\\\?Ⲳ?QQQQQQ?111111??pppppp?______?RRRRRR?qqqqqq?PPPPPP???ᱱ??SSSSSS?ᱱ?QQQQQQ?ర?000000??ݝ?]]]]]]??]]]]]]??]]]]]]??ݝ??ۛ?ZZZZZZ???ח?WWWWWW????֖?TTTTTT?UUUUUU??Ξ??VVVVVV?????ϟ?Ξ??ϟ???Ғ???WWWWWW?֖??Օ??ٙ???RRRRRR????Ԕ??PPPPPP??QQQQQQ?ё?А?А??̜?̜?Ξ????????ə?Ĕ??Ǘ?Ɩ?ʚ?͝??QQQQQQ??ښ???Ĕ??WWWWWW?ʚ?Ǘ??Ș?Ș?Ǘ?Ș??ə??ŕ??Ș?ə?ŕ?ŕ?ŕ??ϟ????˛?QQQQQQ??ё?QQQQQQ?PPPPPP?ё????PPPPPP?ӓ???Ԕ?UUUUUU?\\\\\\????֖??Ξ?????֖?ؘ?ޞ?ssssss?蘘?<<<<<>>>>>????]]]]]]????Ⲳ?pppppp?ۛ??֖??Ԕ?Ғ?PPPPPP??А?ϟ???VVVVVV???Օ?ؘ?֖?WWWWWW????ZZZZZZ????ٙ?ٙ??ښ???[[[[[[??ܜ????ᑑ?RRRRRR??QQQQQQ??pppppp??QQQQQQ?QQQQQQ?222222???㓓?⒒???rrrrrr?ᑑ??PPPPPP?QQQQQQ?ߟ?000000??______????^^^^^^?[[[[[[????______?ܜ?000000?PPPPPP?000000??SSSSSS?333333?rrrrrr??PPPPPP?ᑑ?ర?ޞ?qqqqqq??ర??pppppp?222222?⒒?Ⲳ?rrrrrr?111111?000000??000000?ᑑ??QQQQQQ?000000?pppppp???pppppp???ޞ???ښ?ܜ?ߟ????YYYYYY?WWWWWW???ח??֖??Օ?ח?Ԕ??ח?VVVVVV?????????ё?RRRRRR?Ғ?SSSSSS??VVVVVV???ٙ???XXXXXX??[[[[[[?ٙ?SSSSSS?RRRRRR???PPPPPP???Օ??ϟ??????ʚ??˛?ϟ???˛??Ș??ʚ?Ξ??̜?RRRRRR?XXXXXX??Ș?’?Ɩ?ŕ?????Ĕ?Ș?’?Ĕ???Ș??ŕ??ŕ?Ǘ??Ɩ??ʚ??Ɩ?̜??RRRRRR?ё???Ξ???QQQQQQ???Ғ?UUUUUU?QQQQQQ??Ξ?SSSSSS??˛???̜?͝?А??Ғ????111111???<<<<<>>>>>??Ꚛ?꺺?uuuuuu?⒒?????SSSSSS??Ғ?TTTTTT?Ԕ?????Օ?VVVVVV?֖?ח????ۛ?ర??ۛ?ؘ?YYYYYY?______?rrrrrr??ర?PPPPPP?000000?ݝ???ݝ??ߟ?111111?????QQQQQQ???⒒?Ⲳ?RRRRRR???ؘ?????ޞ??ޞ??^^^^^^?pppppp?ర????PPPPPP?ర?PPPPPP????222222?QQQQQQ?ᑑ?qqqqqq????111111??ᑑ???222222?QQQQQQ??ᱱ?ᱱ???\\\\\\???QQQQQQ???ర??ۛ?ܜ???QQQQQQ??嵵?嵵?444444?QQQQQQ???ߟ?ర????PPPPPP????ښ??֖?֖?ח?XXXXXX??\\\\\\?ח??ח?WWWWWW??VVVVVV???UUUUUU?WWWWWW??ӓ??Ғ??SSSSSS??Ԕ??֖??XXXXXX?]]]]]]??ZZZZZZ????Ș?̜?͝?Ξ?QQQQQQ????SSSSSS????ё?А?А?ϟ?ə?ə?Ǘ?ʚ??ʚ?Ș?ə?̜??Ξ?????Ǘ?Ɩ??А?RRRRRR?RRRRRR??˛?PPPPPP?PPPPPP??’?????’?Ó?Ó??ŕ??Ɩ??ŕ???Ξ????А?RRRRRR?Ԕ?????Ș?ʚ??Ș?PPPPPP?Ș?ŕ?Ɩ?Ǘ?͝??˛?????????ݝ??rrrrrr?777777??::::::??鹹???^^^^^^?[[[[[[??WWWWWW???TTTTTT???UUUUUU???TTTTTT?Ԕ?VVVVVV?Օ?ח?ݝ????ޞ?ܜ?ݝ?]]]]]]?pppppp???pppppp?ర?ߟ?ޞ?qqqqqq?]]]]]]?]]]]]]??ߟ???㳳?⒒??ssssss??⒒??qqqqqq???ర??000000?ޞ?^^^^^^??\\\\\\?^^^^^^??ޞ?______?ߟ??pppppp?ᱱ?ᱱ??rrrrrr?QQQQQQ??111111??QQQQQQ??qqqqqq??ᱱ?RRRRRR?RRRRRR?rrrrrr???111111?QQQQQQ?ర???qqqqqq?ᱱ?333333?䴴?111111????ssssss?ᱱ??PPPPPP?ᱱ?]]]]]]?ZZZZZZ???000000?ᑑ??666666?陙???]]]]]]????ᑑ?______?^^^^^^?______?ݝ?\\\\\\?ٙ?XXXXXX??ߟ??ZZZZZZ?ח??????WWWWWW?ח??VVVVVV????????RRRRRR?ӓ??????\\\\\\?ZZZZZZ?[[[[[[????????QQQQQQ??????TTTTTT?RRRRRR????͝??ʚ?ə??ə????????Ǘ???̜?????????Ș??????????Ó???Ǘ?Ș??Ș?ə?̜???˛?ə??Ξ?͝??˛?ə?ʚ???ŕ??ə?ə?ə??Ǘ??ϟ??̜?????Օ?????Ⲳ?斖??斖?777777?嵵???RRRRRR?]]]]]]???TTTTTT???SSSSSS?Օ???Ԕ??֖?YYYYYY??ښ?ܜ??嵵?RRRRRR????000000????PPPPPP?111111?rrrrrr?Ⲳ?????pppppp?ᑑ???RRRRRR?SSSSSS???RRRRRR?ᱱ?pppppp?ᱱ???ᱱ?000000??______?______?000000?qqqqqq?QQQQQQ?ర???ᑑ???????pppppp?ర???ᱱ?qqqqqq?QQQQQQ?222222?⒒?rrrrrr?⒒?222222?rrrrrr?ᑑ?qqqqqq???rrrrrr?Ⲳ??RRRRRR?㓓???RRRRRR?pppppp?rrrrrr?RRRRRR?ర?ᱱ?㳳???ܜ??ښ?qqqqqq??????]]]]]]?ߟ??qqqqqq??ݝ?ޞ?^^^^^^???????ర?VVVVVV?YYYYYY??ٙ??????Օ?Օ??UUUUUU?Օ?RRRRRR???VVVVVV??ӓ?ӓ?UUUUUU??Օ?????YYYYYY??ߟ?^^^^^^?000000??PPPPPP?PPPPPP???ϟ??ё??А??QQQQQQ?̜??̜?̜??Ɩ??Ɩ???Ș??Ǘ?͝?????TTTTTT?А?SSSSSS????ϟ????ח???Ó???Ĕ?’?Ó?Ĕ??Ș?Ǘ????PPPPPP??͝???˛?QQQQQQ?QQQQQQ??ə?ə???Ɩ???????˛?˛????˛??А?WWWWWW????QQQQQQ???______????PPPPPP?qqqqqq?RRRRRR?333333?111111?\\\\\\?ח??TTTTTT??????ښ?ښ???\\\\\\?YYYYYY?\\\\\\?______?⒒?ߟ?ݝ?ݝ??000000???^^^^^^???ߟ?000000??\\\\\\???ۛ?ܜ????RRRRRR?RRRRRR???111111??QQQQQQ???㳳?^^^^^^??ᑑ??000000???ᑑ???qqqqqq?????pppppp??pppppp??????ᱱ???ᑑ?⒒?222222?⒒?⒒?Ⲳ??㳳???333333????ᑑ??ߟ?000000?RRRRRR?222222?111111?RRRRRR?㓓?tttttt??????qqqqqq??222222?pppppp?______???ޞ??\\\\\\??ۛ????ښ??ؘ?TTTTTT?Օ???[[[[[[?Օ?TTTTTT??֖???WWWWWW???RRRRRR??????Ԕ??Ғ????ۛ?????[[[[[[?????PPPPPP??˛?????А????А???ʚ?ʚ?’???̜?ʚ?Ș???͝??ݝ???RRRRRR???TTTTTT?ϟ?ə?Ș?Ɩ?Ș????????Ó??????ŕ?ŕ??ə?ʚ?͝??Ξ?̜?Ξ?ʚ?ʚ?˛?ʚ??Ș?ʚ?ϟ?UUUUUU?˛?Ș?????͝?ʚ??˛??????RRRRRR???VVVVVV?ؘ?\\\\\\??ZZZZZZ?ؘ?WWWWWW??]]]]]]???Օ??Ғ?QQQQQQ?RRRRRR?SSSSSS??XXXXXX?嵵??YYYYYY?YYYYYY??\\\\\\??\\\\\\???^^^^^^??ߟ????______???????ݝ?ߟ?PPPPPP?PPPPPP??qqqqqq?QQQQQQ?ᑑ??qqqqqq?QQQQQQ?111111??????ߟ??\\\\\\???ᱱ??111111?QQQQQQ??222222?RRRRRR????ర?111111??ᑑ?QQQQQQ??000000??111111??PPPPPP?ᱱ??RRRRRR?222222???䴴??SSSSSS?333333?⒒?rrrrrr??ర??RRRRRR???pppppp?ᱱ?ᑑ?______?qqqqqq?RRRRRR????[[[[[[??????PPPPPP?ޞ???______??^^^^^^?ܜ?______???ZZZZZZ?YYYYYY??SSSSSS?ח?ٙ???YYYYYY?YYYYYY?Օ???????VVVVVV?Ғ?̜?Ξ???TTTTTT??ӓ?RRRRRR??WWWWWW???]]]]]]?ٙ???ߟ??Ԕ??˛?PPPPPP?Ξ???QQQQQQ?А?ښ?ё??PPPPPP??RRRRRR?????Ș?ə????ə??????RRRRRR?ݝ?PPPPPP????˛??ʚ???’??Ó?ʚ?Ǘ????ŕ?Ɩ??Ǘ???Ɩ??˛?˛??̜?͝?͝?ё?̜?ə?Ș??Ǘ??Ș?ʚ?Ș??????͝?ʚ?ʚ???ٙ??А?ϟ???SSSSSS???֖?֖?Օ?VVVVVV?VVVVVV???֖??XXXXXX?RRRRRR??ё?ח?Օ???[[[[[[??ٙ??ח?ZZZZZZ??]]]]]]????PPPPPP??PPPPPP??000000?ۛ???????^^^^^^???QQQQQQ?rrrrrr???pppppp?ర??111111?QQQQQQ??ݝ???111111??ݝ?______??QQQQQQ?QQQQQQ?111111?qqqqqq?rrrrrr??ᑑ?222222?111111??111111?QQQQQQ?ᱱ?111111??QQQQQQ??ర??111111??RRRRRR??⒒?⒒?RRRRRR???ssssss???333333???⒒?ᑑ?QQQQQQ??ߟ?]]]]]]?^^^^^^????ᱱ?222222?ర????䔔?RRRRRR?QQQQQQ?222222???ZZZZZZ????[[[[[[??\\\\\\??PPPPPP?ݝ??YYYYYY???ZZZZZZ??ۛ?ܜ??WWWWWW??ؘ?\\\\\\??XXXXXX???SSSSSS?TTTTTT????Ԕ?UUUUUU?UUUUUU????֖??ۛ?ٙ???ٙ?YYYYYY????ϟ?Ξ?????̜?ё????͝??͝?ə?ʚ?ʚ??Ǘ??ə??˛??Օ??Օ????^^^^^^?Ⲳ?UUUUUU?Ξ?Ǘ?ə?ə??????Ó?Ǘ?Ó?ŕ???Ɩ??Ɩ??Ξ?ʚ???ʚ??͝???ə?͝???ə??ə?Ɩ?????ə?̜???˛???VVVVVV??Ξ?ϟ?Ғ??QQQQQQ?Ғ??Ғ????ח?YYYYYY?YYYYYY?????Օ??VVVVVV??VVVVVV?YYYYYY?ZZZZZZ?ܜ??YYYYYY??ؘ?[[[[[[??]]]]]]??000000?ޞ?ݝ??ݝ?ܜ?\\\\\\?ܜ??ښ?ܜ???ޞ?^^^^^^??ర????QQQQQQ???pppppp????ర??ߟ???ޞ?qqqqqq?qqqqqq?ర??ᑑ???????111111??111111?pppppp?PPPPPP??QQQQQQ?ᱱ?RRRRRR??ᱱ?RRRRRR???SSSSSS??⒒??333333?333333?SSSSSS????ssssss??333333?Ⲳ?ᑑ????pppppp?111111?222222?ᱱ??QQQQQQ??XXXXXX??䔔?⒒?ᑑ???pppppp???ۛ??ݝ???????ٙ??????????XXXXXX?֖?XXXXXX??WWWWWW?UUUUUU?SSSSSS????[[[[[[?RRRRRR???RRRRRR???ؘ???ښ????TTTTTT?YYYYYY?Ғ?Ξ???QQQQQQ?Ξ?ϟ?Ξ?̜?ϟ???PPPPPP??͝?˛?ʚ??Ș?ə???͝?ʚ?̜??QQQQQQ??000000?111111?QQQQQQ????Օ?А??ϟ?ϟ???’??Ó??Ó??Ĕ?ŕ?’?Ó?????˛?Ξ?ʚ?ə???ϟ?PPPPPP??˛??̜?Ǘ??ŕ?ŕ?Ǘ??Ɩ?Ɩ?Ș?Ș?Ǘ?ə???TTTTTT??Ξ???QQQQQQ??RRRRRR?Ғ?Ғ??????ٙ???[[[[[[??ؘ??ܜ?ZZZZZZ??ח??ښ??ߟ??ݝ?[[[[[[?ܜ??ޞ??ߟ???ܜ?ޞ?ۛ??WWWWWW??WWWWWW?ښ?[[[[[[?ۛ??PPPPPP?ᑑ?ߟ?______?ర?qqqqqq????ߟ?pppppp?PPPPPP?rrrrrr?PPPPPP?RRRRRR??????ᱱ?QQQQQQ?ᱱ????ర???000000?㓓??QQQQQQ??qqqqqq?ర?ᱱ?⒒?⒒??SSSSSS??ssssss?㳳???SSSSSS?㓓?SSSSSS?㓓?333333?333333?㓓??444444??㓓?⒒?ᱱ??pppppp?000000??PPPPPP??ᑑ?111111?????????qqqqqq?QQQQQQ?333333??ర??ܜ??ݝ??\\\\\\??ۛ???XXXXXX???????ٙ?????֖?Օ??TTTTTT??ח??]]]]]]?RRRRRR??????000000??????ښ?SSSSSS?Ғ?RRRRRR?А?PPPPPP?RRRRRR??PPPPPP???Ξ?Ғ?ϟ?Ξ?ϟ?ϟ??Ș?ʚ??˛?ŕ?ə?Ԕ?˛???А???ᑑ???SSSSSS??TTTTTT?QQQQQQ??ܜ?А???????Ó??Ɩ?????VVVVVV?QQQQQQ????˛??ə?????Ș???Ǘ?ŕ??????Ɩ????ə??Ғ?̜??̜?ё?А???͝?А?UUUUUU?WWWWWW?VVVVVV?Օ?ח??000000?ݝ?ޞ?pppppp??YYYYYY??______???[[[[[[??ܜ??111111??????______?????ܜ?pppppp?ٙ??֖???\\\\\\?ۛ??222222?PPPPPP?ర?ర?000000?pppppp?QQQQQQ?PPPPPP???ܜ?????????ᱱ?pppppp????PPPPPP?PPPPPP?PPPPPP????ߟ?????222222?⒒?222222?⒒?SSSSSS????444444?䔔?tttttt?tttttt?444444???tttttt??㓓?ssssss??SSSSSS?SSSSSS?SSSSSS?Ⲳ??ᱱ??ߟ?ᱱ?111111??qqqqqq?qqqqqq?qqqqqq?000000???qqqqqq?rrrrrr???⒒?ᱱ??______?ݝ??PPPPPP?pppppp?]]]]]]??\\\\\\?ߟ??YYYYYY?ۛ?ٙ?XXXXXX?ZZZZZZ??\\\\\\?YYYYYY?ښ?ZZZZZZ?ۛ?YYYYYY?YYYYYY??WWWWWW?֖???֖?ۛ??ߟ??ؘ?SSSSSS?Ԕ?VVVVVV?ؘ??ZZZZZZ???????SSSSSS?TTTTTT??PPPPPP??Ξ???˛???Ξ??PPPPPP?ӓ?ə???Ǘ?Ǘ??͝??˛????Օ??UUUUUU??̜?͝???RRRRRR??Օ?PPPPPP?Ș?Ɩ?????Ĕ?’???’?Ș?Ș??˛?QQQQQQ????Ș??Ǘ?ə??ϟ?Ș???ʚ????????Ǘ?ʚ????ʚ???ϟ?˛?͝??ʚ???֖?WWWWWW??VVVVVV?VVVVVV?֖?ܜ?ZZZZZZ??ޞ????[[[[[[????ర??222222?uuuuuu??ᑑ??ݝ??]]]]]]?______?ߟ?ݝ?[[[[[[?\\\\\\?????ర????000000?????PPPPPP??000000?______???^^^^^^???444444?Ⲳ?______??ర??ᱱ???ᑑ?[[[[[[?[[[[[[???ߟ?ᑑ?QQQQQQ???ᱱ?qqqqqq?ᑑ?ᱱ?RRRRRR?222222????TTTTTT?TTTTTT???555555??䴴??????333333?㳳?SSSSSS?333333?rrrrrr?RRRRRR??Ⲳ????QQQQQQ?pppppp????????RRRRRR?ᱱ???Ⲳ?ߟ??ZZZZZZ?ݝ?ర?000000?\\\\\\??ܜ??YYYYYY???\\\\\\?ٙ????ؘ?ZZZZZZ?ٙ???UUUUUU??YYYYYY?ٙ???????VVVVVV??UUUUUU??Օ?ח??ܜ?YYYYYY??VVVVVV???WWWWWW?Օ?Ԕ?TTTTTT?ё?А?А??͝???͝???Ξ??ʚ?ə??˛??͝?ʚ?Ǘ????ӓ?XXXXXX???Ǘ???Ξ??ё?Ξ?А?QQQQQQ?ʚ??ŕ??????????Ǘ???TTTTTT????˛?͝?˛?˛?Ξ??Ξ??Ɩ?ŕ????Ó????ə?ə?ё?PPPPPP?ə??˛?PPPPPP??ə???Ξ??Ԕ??ח??????YYYYYY??YYYYYY?ߟ?ޞ????SSSSSS??555555??嵵?斖???????ޞ?]]]]]]??\\\\\\?000000????pppppp?ర?????pppppp?ర?ర??222222?111111?ߟ?ޞ??]]]]]]?^^^^^^???qqqqqq??ᱱ?ర?______??PPPPPP?ۛ??????ߟ?ర?QQQQQQ?ᑑ????qqqqqq?RRRRRR?ᱱ??qqqqqq?RRRRRR?333333?tttttt?䔔??UUUUUU?uuuuuu?UUUUUU?555555???TTTTTT?䔔?tttttt?tttttt???555555?444444?rrrrrr??RRRRRR?RRRRRR?rrrrrr?QQQQQQ?PPPPPP??ర?ݝ?______???ᑑ??QQQQQQ?ᱱ?ᱱ?222222????????pppppp???XXXXXX??ؘ??ܜ??ۛ?ٙ?????ܜ??WWWWWW??UUUUUU?֖?VVVVVV???^^^^^^?000000?]]]]]]???ё???ӓ????ZZZZZZ??֖?ə?RRRRRR?ZZZZZZ?ؘ???QQQQQQ?QQQQQQ???ʚ?̜?͝???PPPPPP???ə?????˛??Ǘ?̜?????̜?ŕ?Ǘ??ʚ??̜?ϟ??Ξ?WWWWWW?А??????’??Ó?Ғ??RRRRRR?ʚ?RRRRRR?TTTTTT??ϟ???А?PPPPPP?ə??ə?ə?????Ɩ??ŕ????Ǘ?Ǘ???ʚ?ʚ?ə??ʚ?ə?ʚ?̜??PPPPPP??Օ?Օ?XXXXXX??[[[[[[??㳳??[[[[[[?????ۛ?^^^^^^??RRRRRR?????PPPPPP????[[[[[[?ޞ??[[[[[[?YYYYYY??????ర???ᱱ?ޞ??]]]]]]??______??000000?PPPPPP????PPPPPP??______?ۛ?ݝ?000000?QQQQQQ?RRRRRR???ర??ߟ?PPPPPP???qqqqqq??pppppp?pppppp????PPPPPP?qqqqqq?????ᱱ?㓓?????555555?UUUUUU?uuuuuu?啕?uuuuuu?555555???䴴?䔔?tttttt?444444???????RRRRRR???111111????????ᱱ??ᱱ?111111?222222?000000???ښ?ZZZZZZ?ۛ?ݝ??ٙ??YYYYYY?ZZZZZZ?\\\\\\?111111?\\\\\\??????^^^^^^????ؘ??WWWWWW?XXXXXX?Օ?Ԕ??YYYYYY?PPPPPP?ٙ??RRRRRR?Ξ?˛?PPPPPP??UUUUUU???ZZZZZZ?ё?PPPPPP?ӓ??ӓ???ё?ё???̜?Ξ?Ξ?̜??͝?ʚ?̜??Ș??Ξ?А???ə???SSSSSS??͝?Ԕ?Օ???͝?ə?Ǘ???Ș???Ĕ????’?ŕ???UUUUUU?WWWWWW???WWWWWW?PPPPPP?̜??PPPPPP?ϟ?͝???Ș?Ș?ʚ??Ǘ??ŕ?Ș??Ĕ??Ĕ???ʚ?Ǘ??ŕ?ʚ??ə???͝?PPPPPP???QQQQQQ?????XXXXXX??XXXXXX?wwwwww?[[[[[[?ؘ??ښ???????????[[[[[[??[[[[[[?\\\\\\??]]]]]]?ޞ?]]]]]]?]]]]]]??UUUUUU?XXXXXX????ޞ?______????ZZZZZZ?pppppp?pppppp??ర?㳳?111111?ߟ??ߟ?pppppp?______?qqqqqq??ᑑ???ߟ?^^^^^^?ర??pppppp?????111111?qqqqqq?______??QQQQQQ??RRRRRR?????㳳?444444?䔔??UUUUUU?uuuuuu?UUUUUU?啕?嵵???啕?UUUUUU?UUUUUU???䴴?444444?444444??333333?⒒?qqqqqq?qqqqqq?RRRRRR?ᱱ??qqqqqq?000000?______?ޞ?pppppp?000000?ᑑ?pppppp?111111?????111111?ర?????ۛ?ZZZZZZ?ۛ?ۛ??ܜ??ߟ???ٙ?ߟ???ޞ??ח?[[[[[[?ח?XXXXXX??VVVVVV?Օ??Ԕ?֖??????͝??RRRRRR??TTTTTT?WWWWWW?Օ?RRRRRR?ӓ?ӓ?ё?ё??Ғ?А?А??͝?Ξ?Ξ?͝?̜?˛??˛?˛?˛?ʚ?͝?̜??ϟ???SSSSSS?PPPPPP????̜????Ș???????ŕ????Ĕ?’?Ș???̜??QQQQQQ??????А??А????ə??ŕ?ə???Ĕ?Ɩ?Ǘ?ŕ?ŕ??̜??Ɩ?Ɩ??ϟ??ə??˛?Ξ??̜?SSSSSS???TTTTTT??XXXXXX??ߟ???ח?VVVVVV?ٙ??XXXXXX?XXXXXX????ܜ??______?ښ???______?ޞ??\\\\\\?ZZZZZZ???QQQQQQ???333333??______?]]]]]]?^^^^^^?PPPPPP?000000?ߟ??ٙ??rrrrrr??rrrrrr?111111??ర???^^^^^^?ߟ??ర?qqqqqq??000000?ߟ?ߟ???000000??qqqqqq?qqqqqq?ᑑ?ర??ర??QQQQQQ??RRRRRR??SSSSSS???444444?䔔?䴴?555555?uuuuuu?啕?????666666?666666????uuuuuu??tttttt??TTTTTT?㳳??⒒???ᑑ?⒒?ᱱ????ݝ???pppppp?111111?ᑑ?111111?QQQQQQ?111111?qqqqqq????ZZZZZZ?ZZZZZZ??\\\\\\??PPPPPP???ܜ?\\\\\\?]]]]]]?????pppppp??ޞ?\\\\\\????UUUUUU?Ԕ????ח?Օ??А?ə??͝??А????UUUUUU?UUUUUU?ؘ???QQQQQQ??RRRRRR???̜????˛?͝?͝?͝?̜??PPPPPP?˛?͝?Ғ??А??QQQQQQ?А?ё??UUUUUU?ח??Ɩ?Ǘ??Ɩ?????ŕ?Ǘ?ŕ?Ξ???ə??ŕ??ə?͝????͝??А??TTTTTT?͝?͝?͝?А??Ș?Ș?ŕ??ŕ?????Ĕ?Ș?̜????????Ǘ??????ϟ?ϟ?QQQQQQ?????[[[[[[?ܜ?֖????XXXXXX?YYYYYY??ۛ??\\\\\\?????[[[[[[?ܜ??000000???RRRRRR?XXXXXX????RRRRRR?RRRRRR??ݝ?ݝ?ݝ?______?ᑑ??ޞ?ۛ??______?222222?ᑑ??[[[[[[?ۛ???ٙ??Ⲳ??000000?????PPPPPP?ߟ???RRRRRR?222222?qqqqqq??rrrrrr?222222?ర?ᑑ?⒒?Ⲳ?333333?333333??䔔???uuuuuu?嵵?嵵??666666?VVVVVV?VVVVVV?vvvvvv?斖?斖?VVVVVV?VVVVVV?666666??啕??䔔?444444??333333?⒒?qqqqqq?qqqqqq??RRRRRR?222222???PPPPPP????pppppp?111111?????222222??______?ݝ??ٙ???pppppp???000000?]]]]]]?^^^^^^????⒒?qqqqqq?????ٙ?ח?ؘ?֖?ښ??ۛ??ӓ?Ș?ʚ????ə??ϟ???VVVVVV??TTTTTT??RRRRRR?̜?͝??Ǘ?͝??Ξ?ϟ?͝???̜?А?ϟ??????SSSSSS?˛???ZZZZZZ?RRRRRR??Ԕ?TTTTTT??Ǘ??ϟ??????Ĕ?Ĕ???ŕ?????Ĕ?Ɩ?ʚ?ʚ?̜??Ș?˛?????̜???ϟ???ə?Ș?Ș?ŕ???ŕ?ŕ?ʚ???????ŕ?ə?????????ϟ??TTTTTT?RRRRRR???ח?֖??TTTTTT???????ޞ??ZZZZZZ??YYYYYY??ߟ??????ӓ??YYYYYY???ᑑ????ݝ?______??ᑑ????ښ??000000?]]]]]]?????[[[[[[???ۛ??______?000000??______?ߟ?PPPPPP?000000?ర?QQQQQQ?SSSSSS?ssssss??222222?SSSSSS?qqqqqq?222222?222222??SSSSSS?ssssss??䔔?䴴??555555??啕?嵵?666666?vvvvvv?涶?????涶?涶?斖?666666??555555??TTTTTT??㓓???SSSSSS??222222?rrrrrr?ssssss??ޞ??????ర???ޞ??]]]]]]??ܜ???^^^^^^???ޞ??000000??[[[[[[?ۛ??ښ??ݝ?????ښ??WWWWWW?֖?WWWWWW?ٙ?UUUUUU?RRRRRR??ё?Ξ??̜?ə??PPPPPP?RRRRRR??UUUUUU?Օ?Ԕ??֖??͝???????А?ё??Ξ???PPPPPP?ϟ??Ξ?ϟ??Ɩ?Ș???ؘ??͝?ϟ??˛??Ș?ə???Ɩ?Ǘ?Ó?’??ŕ?Ĕ?Ó?͝?’?˛??ə????Ɩ???Ș?̜??̜??????͝?ə????Ș?Ș???ŕ?ʚ?ŕ?Ɩ??Ɩ??Ǘ?????Ș?Ș??TTTTTT??QQQQQQ???ё????ח?XXXXXX?______?֖?ܜ?111111?[[[[[[?ܜ??ޞ???YYYYYY?XXXXXX??????WWWWWW?ܜ??ۛ??YYYYYY???^^^^^^??ܜ?^^^^^^?ޞ?PPPPPP?ߟ?ర?ޞ?ݝ?\\\\\\?ۛ??ߟ??????ݝ???ۛ??pppppp?^^^^^^?]]]]]]?______?PPPPPP?pppppp?000000??ᑑ??⒒??ssssss?⒒?rrrrrr??SSSSSS?SSSSSS??TTTTTT?tttttt??555555?UUUUUU?嵵???VVVVVV?涶???777777?777777?????涶?斖??啕?555555??TTTTTT??SSSSSS?Ⲳ?㓓??222222?222222??PPPPPP?ޞ?ߟ?ܜ?______???ర?ర??PPPPPP??^^^^^^????ܜ??______???]]]]]]?]]]]]]??\\\\\\??ZZZZZZ???ܜ??ښ?ZZZZZZ??ZZZZZZ???WWWWWW????Ғ??QQQQQQ?Ғ?PPPPPP?PPPPPP?QQQQQQ???RRRRRR??UUUUUU???UUUUUU?Ԕ?RRRRRR??˛?RRRRRR??PPPPPP????̜??Ξ?͝??ϟ????̜?????QQQQQQ?Ғ?QQQQQQ?˛??Ԕ??Ɩ??Ș?Ĕ??Ĕ???Ó??????ʚ??˛?Ɩ??Ɩ?˛?Ǘ???˛?Ș?ʚ?̜???ర?ё?Ξ?ϟ??А?Ș?ə???Ș??ŕ??ŕ?ŕ?Ǘ?Ș???Ș?Ș?Ș???˛?А???ӓ???Ғ?VVVVVV??XXXXXX?ZZZZZZ?????ర?ޞ?ߟ??^^^^^^?\\\\\\?ZZZZZZ??XXXXXX?ٙ??]]]]]]??ٙ???______??ZZZZZZ???ޞ?]]]]]]???000000???????\\\\\\?[[[[[[???\\\\\\?ܜ??\\\\\\?ݝ??^^^^^^?ݝ??ߟ?????000000???111111?PPPPPP??RRRRRR?Ⲳ??RRRRRR???㳳?㳳?TTTTTT?䴴??UUUUUU?啕?嵵??666666?VVVVVV???WWWWWW?WWWWWW?wwwwww?緷?痗?WWWWWW?777777????VVVVVV??啕????ssssss?SSSSSS??rrrrrr?⒒?ᱱ?ᑑ??PPPPPP?______?^^^^^^?ర?rrrrrr?ᑑ????ర???\\\\\\?XXXXXX?\\\\\\?PPPPPP?______??ZZZZZZ??^^^^^^?]]]]]]?ۛ?????______??????YYYYYY?ٙ????֖?ח????????Ԕ?Ԕ?Ԕ??Ԕ?VVVVVV??TTTTTT??ϟ?А???А???QQQQQQ?ϟ??PPPPPP?PPPPPP??Ξ?RRRRRR?QQQQQQ???А?Ξ??RRRRRR???А????˛??Ɩ??ə???Ĕ?Ɩ??А?Ĕ?????ӓ???Ó???ʚ?˛?Ǘ???Ξ?ё??˛??֖?Ξ?̜?ϟ?Ξ?Ғ????Ǘ?ʚ????Ĕ??Ξ??ŕ???ŕ?Ǘ?Ξ???PPPPPP???ӓ??ӓ?ӓ?YYYYYY????????222222?????YYYYYY?ٙ???XXXXXX??ؘ?ٙ?XXXXXX?????]]]]]]??]]]]]]?______?ޞ?pppppp?ܜ??]]]]]]???[[[[[[?\\\\\\??ZZZZZZ??YYYYYY?XXXXXX??ZZZZZZ?ݝ??????]]]]]]?ݝ??ܜ??ర??pppppp??PPPPPP?ޞ?ݝ??qqqqqq?RRRRRR?RRRRRR?????tttttt?TTTTTT?UUUUUU?UUUUUU?嵵???666666??777777?痗?緷?緷?緷???緷?wwwwww??777777??涶??嵵?UUUUUU??䔔??333333?Ⲳ?222222??QQQQQQ?qqqqqq??ర???111111?qqqqqq?111111?PPPPPP?ݝ?000000??PPPPPP??ݝ?YYYYYY?ݝ?ZZZZZZ???ښ??ݝ???ٙ????ۛ?[[[[[[?ޞ?????YYYYYY??UUUUUU???֖?UUUUUU??QQQQQQ?А?ё??ӓ???Ԕ?֖???VVVVVV?QQQQQQ???RRRRRR?Ғ????RRRRRR?SSSSSS??ϟ???ϟ??Ғ??ӓ?ϟ?֖?Ξ???SSSSSS??ZZZZZZ???Ξ?ʚ?̜?Ɩ???Ɩ??ŕ?Ó??Ĕ?Ǘ?’?’???Ǘ?SSSSSS????Ș?ʚ???????Ғ???ח??Ξ??ϟ?UUUUUU?PPPPPP?Ɩ????Ó?Ó?Ɩ?ŕ?Ĕ?ŕ??Ó??ŕ???PPPPPP?А??Ξ?ӓ?Ғ?Ғ??SSSSSS????XXXXXX?ؘ?ח??????ܜ?ۛ?ښ?ZZZZZZ??ٙ?ח????WWWWWW?[[[[[[?\\\\\\??\\\\\\?䴴?444444?ߟ?ۛ?ܜ?[[[[[[?pppppp?\\\\\\??ܜ????\\\\\\?ZZZZZZ?ZZZZZZ?????ݝ?????______??ZZZZZZ???^^^^^^?000000??㓓????ޞ??QQQQQQ??RRRRRR???㓓?444444?䔔?䴴??啕???666666??WWWWWW?緷?緷?????888888?888888??緷?wwwwww?777777?斖?涶?vvvvvv??啕??䴴??SSSSSS???RRRRRR?QQQQQQ?ᱱ?ᱱ?ర?000000??000000?]]]]]]?______?pppppp??ݝ??000000??ޞ?ZZZZZZ??YYYYYY?XXXXXX???ޞ??ݝ?ݝ?ښ?ZZZZZZ??ٙ?ZZZZZZ?^^^^^^??ޞ?000000??XXXXXX?XXXXXX?ח?Օ??Օ?Ԕ??QQQQQQ?PPPPPP??Ғ????????ٙ????ϟ?Ԕ?ё?ё???????ϟ?ё??ښ??????Ғ?ϟ?????????˛????ϟ??Ɩ?Ó?Ó??’???Ĕ??ŕ?ə?RRRRRR?????Ǘ?ə???????Ξ??ϟ?̜?PPPPPP?ϟ??ʚ??Ș?Ș?ŕ?Ó?ŕ??Ĕ?ŕ?ŕ?Ĕ?Ɩ??Ǘ??͝?̜??QQQQQQ??ё?ӓ?Ғ?Ғ?TTTTTT?UUUUUU???????Օ???ZZZZZZ?]]]]]]?ښ????WWWWWW??Օ?ؘ?֖??ؘ???ٙ?ᱱ?ߟ?ݝ????\\\\\\???\\\\\\?\\\\\\?\\\\\\??ښ????\\\\\\??ݝ?______??ర??ޞ??ర??]]]]]]?ݝ??pppppp??ర?pppppp??ޞ???ᑑ?222222?Ⲳ?ssssss??TTTTTT?TTTTTT?䔔?555555???vvvvvv?vvvvvv?WWWWWW???XXXXXX?蘘?踸?蘘?蘘?蘘?蘘?xxxxxx?xxxxxx?XXXXXX??痗?777777??斖?666666?嵵????ssssss?333333??⒒??qqqqqq??QQQQQQ??______??000000?QQQQQQ???ZZZZZZ????ݝ?______?^^^^^^?^^^^^^??ޞ?ݝ?????ݝ???ZZZZZZ?ZZZZZZ???Ⲳ?ݝ???Օ???Ԕ?Ԕ???PPPPPP??А?TTTTTT??SSSSSS??Օ?UUUUUU?ӓ?֖?^^^^^^?VVVVVV?ӓ?ё?PPPPPP??ё??Ғ????̜?͝?А??TTTTTT?ۛ???SSSSSS?Ғ??PPPPPP?А??UUUUUU?PPPPPP????ʚ?Ǘ????ʚ???Ó?Ĕ?Ɩ??Ș?’?ŕ??Ó?Ɩ??ϟ?А?˛?ŕ?Ɩ???ə?Ǘ?˛?А?PPPPPP?RRRRRR??ϟ??Օ???˛??Ș?Ǘ?Ǘ?Ș????Ĕ??Ɩ???ə???ё??QQQQQQ???ӓ??TTTTTT?TTTTTT??TTTTTT??UUUUUU??SSSSSS????ٙ??[[[[[[??ۛ???֖????WWWWWW?ח??ښ????ٙ?pppppp??[[[[[[?[[[[[[?^^^^^^?ݝ?ۛ?ߟ???[[[[[[????ښ???ܜ?????pppppp??]]]]]]?333333??ߟ?ߟ????000000?^^^^^^??ݝ?000000??QQQQQQ??rrrrrr?SSSSSS?TTTTTT?TTTTTT???啕?VVVVVV?vvvvvv??痗?888888?xxxxxx???999999?999999?999999?????踸?蘘?XXXXXX??緷?WWWWWW??vvvvvv??555555?䴴??333333???222222??qqqqqq?ᑑ???______????ߟ?ݝ?ۛ??ۛ??ޞ?ߟ???ߟ?000000?ర?PPPPPP??ܜ??ߟ?ٙ??ܜ?\\\\\\?????ZZZZZZ?^^^^^^????ё??͝?Ξ??QQQQQQ?Ξ?PPPPPP?QQQQQQ???ӓ?Ԕ?Ԕ?Օ?UUUUUU?UUUUUU??QQQQQQ?̜?ё????TTTTTT????PPPPPP?RRRRRR?А?ܜ??Ԕ?Ғ??QQQQQQ?QQQQQQ?А?̜???А??PPPPPP?̜?˛??Ɩ?QQQQQQ?Ǘ??Ĕ??Ó??’??????’????̜?ʚ??Ǘ??Ǘ?˛??Ș????ϟ?ё???QQQQQQ?̜?ə?QQQQQQ???Ɩ?Ĕ?ŕ??ə?????͝??Ξ?PPPPPP?Ԕ?Ғ???SSSSSS?ӓ?Ԕ?TTTTTT?UUUUUU???Ԕ?Ғ?VVVVVV??Ғ?UUUUUU??????XXXXXX??ח?Օ?WWWWWW??ؘ?ח????ח??ښ???[[[[[[?ZZZZZZ?ۛ??ݝ??[[[[[[?WWWWWW?֖?WWWWWW??YYYYYY?[[[[[[?\\\\\\??ᱱ?PPPPPP??PPPPPP??pppppp???ߟ?ߟ???PPPPPP??pppppp?______?pppppp????000000?ᑑ?222222?⒒?Ⲳ?㓓?444444?䴴??嵵??VVVVVV??緷?XXXXXX?蘘???YYYYYY?陙?鹹?鹹?鹹?鹹?陙?999999???蘘?XXXXXX??緷??涶?666666?嵵???㳳?333333?Ⲳ???ᑑ?111111?qqqqqq????______?000000??ݝ?ߟ?______?^^^^^^????ޞ??PPPPPP?ᑑ??111111?????^^^^^^?ߟ???\\\\\\?\\\\\\?^^^^^^??\\\\\\?ۛ??????̜?̜?PPPPPP??А?QQQQQQ??RRRRRR??RRRRRR??RRRRRR?Ғ?Ғ?ӓ?TTTTTT?ё???????RRRRRR??͝?RRRRRR??VVVVVV?????SSSSSS????ϟ????ё?ʚ?Ғ?А?˛?ə????’?Ó?Ó?’???Ĕ???Ó????Ĕ?????Ɩ?ʚ??ӓ?ʚ??͝????RRRRRR?\\\\\\?ؘ?Ξ???Ș??ŕ?Ɩ?ŕ?Ș?Ș?ə?ʚ?ʚ?ϟ??QQQQQQ?TTTTTT???ё?????TTTTTT??????UUUUUU?WWWWWW?111111???ۛ?????YYYYYY?ZZZZZZ????ٙ??ښ??ZZZZZZ?YYYYYY?ٙ?ZZZZZZ??ZZZZZZ????ZZZZZZ?ZZZZZZ?ܜ?\\\\\\??ZZZZZZ??YYYYYY???\\\\\\??]]]]]]?ߟ?ݝ?^^^^^^?000000?333333??^^^^^^?ܜ?ޞ?]]]]]]??^^^^^^???pppppp??PPPPPP??\\\\\\?^^^^^^??222222?⒒?SSSSSS?ssssss??TTTTTT??啕??666666?涶??XXXXXX???yyyyyy?鹹??::::::?::::::?::::::????陙?YYYYYY?999999??蘘?888888??777777?涶?vvvvvv?uuuuuu??tttttt?䴴???222222?ᑑ?ᑑ??ᑑ?⒒?333333?pppppp?ߟ??ޞ??000000?______?PPPPPP?ߟ??????tttttt??qqqqqq?111111?ޞ???ߟ???ޞ?\\\\\\?ܜ?]]]]]]??\\\\\\??ؘ???????̜??PPPPPP?SSSSSS????А???SSSSSS?Ғ??ё??Ó?͝??VVVVVV???ӓ?ё??RRRRRR??YYYYYY?SSSSSS?ё??А?QQQQQQ?ё?А???QQQQQQ??UUUUUU?˛???˛?͝?А???Ɩ?ŕ??Ĕ?’???’???????Ĕ??ʚ?ё???PPPPPP??UUUUUU?͝?ё??ϟ??PPPPPP?WWWWWW?̜?͝??QQQQQQ?????ŕ??Ș?????ё?ӓ?ӓ??PPPPPP?ӓ????Ғ?ӓ???VVVVVV??VVVVVV?֖?UUUUUU??]]]]]]??ݝ?????]]]]]]??XXXXXX????ښ???[[[[[[??000000?[[[[[[??[[[[[[??YYYYYY?ؘ???ܜ?ۛ?ۛ?[[[[[[??YYYYYY?YYYYYY????[[[[[[???ܜ?______???PPPPPP?ݝ?]]]]]]?[[[[[[??ޞ????ߟ??^^^^^^?ۛ?]]]]]]??ᱱ?RRRRRR?Ⲳ?㳳??tttttt??uuuuuu?666666?VVVVVV?666666?涶?xxxxxx??999999?陙?鹹?::::::?ZZZZZZ?Ꚛ?Ꚛ?Ꚛ?꺺?Ꚛ?zzzzzz??鹹?YYYYYY???xxxxxx??wwwwww??vvvvvv???䴴?444444?ssssss?SSSSSS????RRRRRR?ᑑ???ర?^^^^^^??111111?pppppp??ߟ??PPPPPP???^^^^^^?PPPPPP??333333?333333?QQQQQQ??ޞ?ޞ??????????ݝ?]]]]]]?WWWWWW?Ԕ?SSSSSS?ӓ?TTTTTT??PPPPPP?А?ё????RRRRRR?PPPPPP?ё??TTTTTT?Ғ?RRRRRR??ϟ??̜??????Ғ??RRRRRR?QQQQQQ????А?SSSSSS??RRRRRR?͝???QQQQQQ?ё?TTTTTT????Ғ?????Ǘ??ʚ??’??ŕ?Ó????ŕ?’?????Ɩ??ӓ?̜??ϟ????А????PPPPPP??͝?QQQQQQ?˛???Ɩ?ŕ?ŕ???ʚ??VVVVVV???ϟ?ё?PPPPPP???ӓ??Ԕ??SSSSSS???VVVVVV???WWWWWW???[[[[[[?ܜ??000000?^^^^^^?000000?YYYYYY???ؘ?ח??[[[[[[??ZZZZZZ??ZZZZZZ??RRRRRR??ZZZZZZ?ۛ????ܜ?______??\\\\\\?ۛ????\\\\\\?\\\\\\??ۛ??ݝ?______???ర???______??\\\\\\???ర?PPPPPP?PPPPPP??000000??ݝ??qqqqqq?RRRRRR?Ⲳ?㓓??TTTTTT?UUUUUU?啕??斖??WWWWWW???999999?鹹??::::::?꺺???;;;;;;?;;;;;;???꺺?zzzzzz?ZZZZZZ??yyyyyy?999999?蘘??痗??斖?嵵?嵵?uuuuuu??333333??SSSSSS?RRRRRR???qqqqqq?ᱱ?111111?pppppp??QQQQQQ???^^^^^^?pppppp?000000?ޞ?ܜ?]]]]]]?ޞ??qqqqqq?000000?rrrrrr??啕?pppppp??qqqqqq?]]]]]]??[[[[[[??ܜ?PPPPPP?ޞ????VVVVVV?Օ?SSSSSS?TTTTTT????ϟ?А?QQQQQQ?ё?PPPPPP?PPPPPP????SSSSSS??????ӓ??Օ?TTTTTT?UUUUUU????ё??SSSSSS???ϟ??TTTTTT?А?ϟ?PPPPPP???ؘ????͝?Ș????Ɩ???Ɩ?Ɩ??Ó?’??Ó????????ŕ????Օ?Ғ???ؘ?ٙ???̜?ϟ??Ξ?˛?ə?Ș?͝?ё??Ɩ?Ɩ????UUUUUU?֖???PPPPPP?А?А??SSSSSS?ӓ??ӓ?RRRRRR?????YYYYYY?XXXXXX???????????ܜ??????ٙ?YYYYYY?ښ???]]]]]]?ښ?????ۛ????]]]]]]??????ZZZZZZ?[[[[[[?ښ???PPPPPP??ᱱ?ᱱ?⒒?ޞ??ݝ?]]]]]]?]]]]]]?^^^^^^??ర???RRRRRR?ᑑ?pppppp???RRRRRR??㓓??䔔?UUUUUU??VVVVVV??777777??蘘??鹹??zzzzzz?꺺??;;;;;;?{{{{{{?뛛?뛛?뛛?[[[[[[?;;;;;;??Ꚛ?ZZZZZZ??YYYYYY??xxxxxx??777777?涶???嵵?444444?㓓?㳳?⒒???qqqqqq?111111?111111????QQQQQQ????????ݝ?]]]]]]???RRRRRR?ssssss?222222?pppppp???ۛ??ۛ??\\\\\\????\\\\\\???֖??ӓ???Ғ?Ғ?Ξ?PPPPPP????????ӓ?TTTTTT?Ԕ??SSSSSS??TTTTTT?UUUUUU?????ϟ????˛??̜??ϟ?ϟ?PPPPPP??QQQQQQ?????QQQQQQ??Ξ?Ɩ????Ó?Ĕ??ŕ?Ɩ?ʚ?Ó?’?Ĕ?’??’?Ɩ????Ó??ʚ??ə??]]]]]]?QQQQQQ?RRRRRR???Ғ???PPPPPP?̜?Ξ??ə?Ǘ?ʚ?Ǘ??Ɩ?ŕ?????ϟ?Ξ??PPPPPP??QQQQQQ?PPPPPP???Ԕ?Ԕ??WWWWWW?VVVVVV??ٙ???Ғ?ZZZZZZ?????ܜ??XXXXXX???????VVVVVV?ؘ???XXXXXX?ܜ?YYYYYY????\\\\\\????\\\\\\?\\\\\\??ZZZZZZ?ܜ???ۛ??ښ?YYYYYY??ޞ??QQQQQQ?wwwwww???ޞ?______?PPPPPP?ర??????ᱱ?Ⲳ???RRRRRR?⒒?RRRRRR??ssssss??䔔?uuuuuu??vvvvvv??痗?XXXXXX??YYYYYY??zzzzzz???[[[[[[?뛛?????뻻?{{{{{{???Ꚛ??陙??蘘??wwwwww??VVVVVV?啕??tttttt?㳳??Ⲳ?RRRRRR?RRRRRR??ᱱ?111111??PPPPPP???ర???000000??ݝ?ۛ?ۛ?ۛ??rrrrrr??Ⲳ?qqqqqq?qqqqqq?______?ZZZZZZ??[[[[[[?ۛ????????ؘ??SSSSSS?Ғ????ϟ?ϟ????А?SSSSSS??WWWWWW?TTTTTT??????????ח?Օ?Ԕ?ϟ??ϟ?А??ʚ?Ǘ?ʚ?͝?PPPPPP???ZZZZZZ?TTTTTT?Ғ??Ԕ???А?Ǘ???Ғ?ŕ?Ɩ?ə????Ó?’?ŕ?ŕ?????’?ŕ???̜?А?Ș??????RRRRRR?QQQQQQ?ٙ?ӓ?QQQQQQ?Ξ??ə????ŕ?????Ĕ???Ξ?͝?͝?А?QQQQQQ?ϟ??TTTTTT??Ԕ?UUUUUU?֖???[[[[[[?]]]]]]?ۛ?ח?\\\\\\??^^^^^^??000000?]]]]]]???ח??????WWWWWW?ח??WWWWWW?ח???YYYYYY??YYYYYY??ZZZZZZ??ܜ?\\\\\\???\\\\\\??ܜ?ZZZZZZ?ٙ?ZZZZZZ?ܜ?ۛ??????000000???PPPPPP????????⒒?qqqqqq?ᑑ????⒒??333333?ssssss?444444?䴴???vvvvvv??緷?xxxxxx?YYYYYY??ZZZZZZ??;;;;;;?뛛??<<<<<>>>>>??~~~~~~?^^^^^^??}}}}}}??||||||??[[[[[[??ZZZZZZ?陙??蘘???斖??555555?TTTTTT??333333?⒒?222222?RRRRRR??ᱱ?pppppp?PPPPPP?000000???ర??ܜ??ܜ?pppppp?]]]]]]??^^^^^^?PPPPPP??PPPPPP?ޞ?TTTTTT??ݝ???ZZZZZZ??ߟ?000000?[[[[[[???ٙ?????ח?UUUUUU?SSSSSS?SSSSSS?SSSSSS?????̜???????????ӓ???SSSSSS?UUUUUU??QQQQQQ?А?ϟ?ϟ?PPPPPP?SSSSSS?????ӓ????ӓ????ϟ?ϟ?ŕ??Ǘ?ʚ???????’??????QQQQQQ?Ɩ?ϟ??ə??ϟ???????͝??QQQQQQ?Ξ?˛?ə??ŕ?Ĕ?Ó?’?Ó???ŕ??ʚ?ə??ʚ???RRRRRR????SSSSSS?VVVVVV??UUUUUU???Ғ?WWWWWW???VVVVVV?ӓ?????ٙ?ؘ???WWWWWW?^^^^^^???WWWWWW?ٙ?YYYYYY??ښ?[[[[[[??YYYYYY?YYYYYY??ٙ????ٙ??PPPPPP?ssssss?ᱱ???ٙ?ݝ??]]]]]]??????\\\\\\?ܜ?ޞ?ܜ?ݝ???pppppp??ۛ????ర?pppppp??QQQQQQ??rrrrrr???ssssss?䴴?UUUUUU??666666??緷?XXXXXX??yyyyyy?::::::?꺺?;;;;;;?뻻?||||||??흝?~~~~~~?______???>>>>>>?흝??||||||??{{{{{{??ZZZZZZ?陙??XXXXXX???vvvvvv?嵵?555555?tttttt???⒒?RRRRRR?222222?qqqqqq?qqqqqq??000000????????????ޞ?PPPPPP??ߟ?pppppp??QQQQQQ??ޞ?ۛ?ښ??????ZZZZZZ?XXXXXX??PPPPPP?]]]]]]?ח?WWWWWW??SSSSSS??ё??QQQQQQ?А????̜?PPPPPP??SSSSSS?ӓ?QQQQQQ?Ԕ????Ԕ????SSSSSS??QQQQQQ??͝?͝??YYYYYY??SSSSSS?XXXXXX?XXXXXX??ϟ???Ғ???̜?ə???˛????????ŕ???????Ǘ?ϟ???QQQQQQ??XXXXXX??Ғ?????Ғ??А?̜??Ǘ?Ĕ?????ŕ?ŕ??Ĕ??ʚ?ё??͝?????SSSSSS?SSSSSS?RRRRRR?SSSSSS????ӓ?ؘ?]]]]]]?______?TTTTTT???ؘ?ؘ?ٙ???XXXXXX?WWWWWW?ٙ??ؘ?????XXXXXX?ؘ?\\\\\\????[[[[[[??ښ??ZZZZZZ????ర??YYYYYY?ё??YYYYYY?\\\\\\??ۛ????ర?PPPPPP???]]]]]]??ߟ???[[[[[[?pppppp?\\\\\\?______?RRRRRR????ᑑ??⒒?????uuuuuu?嵵?VVVVVV?777777??xxxxxx??鹹?ZZZZZZ??[[[[[[??||||||??}}}}}}?>>>>>>????>>>>>>?흝??||||||??{{{{{{??::::::?陙??XXXXXX?緷??VVVVVV?啕?UUUUUU?䔔?㳳??Ⲳ?222222?ᱱ?ᑑ???PPPPPP??ర??ߟ?ݝ?ܜ?ܜ??^^^^^^?]]]]]]??ߟ?ޞ????ssssss???ܜ?]]]]]]??]]]]]]?QQQQQQ?ݝ?[[[[[[???ٙ????Օ??UUUUUU?ё??PPPPPP?RRRRRR?Ξ?Ξ??Ξ???ё?Ғ???RRRRRR??ϟ?TTTTTT???ח?TTTTTT???SSSSSS???А?ё?QQQQQQ?UUUUUU?SSSSSS?ё?ZZZZZZ?______?PPPPPP?ϟ?ё??Ξ??̜?????ə????Ó?’?????????Ó???̜??ϟ???Ғ?XXXXXX?А?˛?̜????А???????Ó???Ĕ?Ɩ?Ǘ?????͝???????ё??rrrrrr?ܜ?ٙ??֖?????YYYYYY?ؘ??YYYYYY?ZZZZZZ?ZZZZZZ??YYYYYY???ܜ??YYYYYY?ח????ښ?ښ?ٙ???ۛ?______??\\\\\\?^^^^^^??Ⲳ???ZZZZZZ??ؘ???ۛ??ZZZZZZ?]]]]]]?ߟ?ݝ??ۛ?ۛ???ޞ????111111????qqqqqq?000000?000000?ᑑ?ᱱ?Ⲳ?㓓?㓓???啕?????蘘?999999?鹹?ZZZZZZ??{{{{{{??\\\\\\??}}}}}}??????]]]]]]??<<<<<>>>>>??]]]]]]??윜??뛛??Ꚛ??YYYYYY?蘘??WWWWWW???555555??TTTTTT?ssssss?rrrrrr?RRRRRR?rrrrrr???pppppp?ర??PPPPPP?ర??ޞ??ݝ??ݝ?______?______?]]]]]]??QQQQQQ?]]]]]]??⒒???rrrrrr?RRRRRR?]]]]]]?\\\\\\?^^^^^^???000000???XXXXXX?VVVVVV??UUUUUU???QQQQQQ?QQQQQQ?ё????̜??QQQQQQ???А??ё??˛??RRRRRR?Օ??]]]]]]?ӓ?Ғ?Ғ?ӓ?Ғ?SSSSSS????Ԕ???????????ӓ?ʚ??ŕ??Ɩ??Ĕ????Ĕ?’??????????Ǘ?ۛ??ర???ח?RRRRRR??͝??????˛?ϟ?ʚ?̜?QQQQQQ??Ɩ??ŕ?Ǘ?͝???А?Ξ?SSSSSS??͝?RRRRRR?ښ?UUUUUU?QQQQQQ??VVVVVV?WWWWWW?ۛ??ښ??ޞ???VVVVVV?Օ???ۛ?ZZZZZZ?]]]]]]?ZZZZZZ?֖??222222??ښ??֖?ӓ???XXXXXX????ZZZZZZ?ۛ??000000??ۛ?ݝ?PPPPPP?^^^^^^?ݝ?ۛ???UUUUUU??\\\\\\?\\\\\\?ۛ?ۛ?]]]]]]?^^^^^^??ߟ?ٙ??[[[[[[??000000?ۛ?______?PPPPPP?000000?PPPPPP????ޞ??ᱱ?rrrrrr???㓓??䔔?uuuuuu??vvvvvv???蘘???ZZZZZZ?꺺?;;;;;;?뻻??||||||?켼??}}}}}}?흝?]]]]]]??윜?||||||??{{{{{{??::::::?鹹??xxxxxx??777777?斖??uuuuuu?䴴??333333?222222?RRRRRR?RRRRRR??ర?PPPPPP??pppppp?ర?ర?ߟ?]]]]]]?ۛ?]]]]]]?______??]]]]]]?\\\\\\?ޞ?111111???ర??ర?ssssss??rrrrrr??\\\\\\???ۛ???ח??ח?VVVVVV?UUUUUU?Օ??ё?ё?RRRRRR??PPPPPP?ϟ?͝??ϟ??PPPPPP?А???YYYYYY??ӓ?UUUUUU????TTTTTT??Օ???UUUUUU?ё??QQQQQQ???SSSSSS?ӓ????VVVVVV?Օ??ё?Ғ????ŕ?Ǘ???????????????Ɩ????ߟ?000000??PPPPPP?ϟ?????Ș???̜?Ɩ??͝?Ɩ?ʚ?Ɩ?Ĕ?ŕ?Ǘ???SSSSSS?Ξ?QQQQQQ????Ԕ?Ԕ??SSSSSS?SSSSSS????ؘ??ۛ??啕?蘘??XXXXXX?ؘ?ZZZZZZ???ܜ??Ԕ???ܜ?ޞ?\\\\\\?ޞ?WWWWWW?Ԕ?VVVVVV?UUUUUU??ښ?ZZZZZZ??YYYYYY???PPPPPP???qqqqqq?222222???\\\\\\?ޞ??ח?[[[[[[?ܜ???ݝ??]]]]]]?ޞ?\\\\\\?ؘ??ޞ??ޞ?000000?PPPPPP?ర???ర????QQQQQQ??rrrrrr???ssssss??TTTTTT??嵵?斖???888888??鹹?ZZZZZZ?꺺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 diff --git a/data/fits/STAR_FOCUS_10.fits b/data/fits/STAR_FOCUS_10.fits deleted file mode 100644 index 8c3dc0d75..000000000 --- a/data/fits/STAR_FOCUS_10.fits +++ /dev/null @@ -1 +0,0 @@ -SIMPLE = T / Created by ImageJ FITS_Writer BITPIX = 16 / number of bits per data pixel NAXIS = 2 / number of data axes NAXIS1 = 65 / length of data axis 1 NAXIS2 = 85 / length of data axis 2 BZERO = 32768 / data range offset BSCALE = 1 / default scaling factor DATAMIN = 0.000000 DATAMAX = 65535.000000 INSTRUME= 'ATIK-383L: fw rev 3.27' FILTER = 'Position 3' EXPTIME = 3.000 DATE-OBS= '2014-01-17T20:33:26' XPIXSZ = 5.400 YPIXSZ = 5.400 XBINNING= 1 YBINNING= 1 XORGSUBF= 1127 YORGSUBF= 915 XPOSSUBF= 1127 YPOSSUBF= 915 CBLACK = 324 CWHITE = 15106 CCD-TEMP= -10.0 SWCREATE= 'Artemis Capture' END ypƁ|mskt}mjupׁzZā{i~mwu{ljrrvzҁŁNh߁~΁Yy~}qkxAq{`|}h~kd|w}y쁇ǁ_|{{o}t|{́uXȁt}|p{Nxtgs_|luD܁rymh~~EźVÁ>yeswqxq|hkȁ`uctVj}āǁ]{zvxyzl=dmŁ^z|q^āҁ|rf_qnŁn|~|txhwyv~k~xkف\s􁢁Ɓ܁r}{с[q{Áx|ցƁzz{zɁzi~bn]{ǁՁ}ʁ\poTxx}ju~g{ukkv|[\|zxׁz}lp|{xj`sX~|q~܁mm~Ɓ{|xЁzāS^oǁxp~xszʁc^tz]ӁugyvṕzruibzvЁRӁz|dq}y~hhu{hye၌}{pmӁptrKks}ȁt́s~΁~xbKlx~abut{݁rReQȁqցoā{lxv^_zƁ{nqˁijzkqpˁW}āwb^Zl[bjwɁhvs{z{rnm|fywākm}EX\ҁyd~iw΁Ýneiysnvrynvtvāqiсpm~Á{\by||Ɓ~́axivll|{i}rzƁˁȁƁuycq}}z|v|فˁwsrԁ}^jhr||lj]jvЁk}yz|}jtjԁp~ʁ~tŁȁ~nsRTʁuzte{d́}ú{}sdkԁvSсy~q́Łw|{ˁnt́ÁŁjd|b؁p{jut}ḱāk灵pujuvwǁہƁŁ|w|q~{gnˁʁŁqw|{tuhq|lɁlف~}ρ(ւ"ʁet\Ё~^|΁ʁPnwŚs߁tÁ\x\p|}{jk|Ă$G J,P끞\zxnaVFǁji^ʁ.Ҏț+_ꉵK{􁚁ākNyb|j~Ё~}}_ׄxɍS/́ljh}Ásā݁kwzuN!σB݁΁u~n|~fṕimρB00ڂ5ف́oSLyqwƁw~ȁɁʁЁŁtrjxw|r|{qŁ聼́́t|oɁzxxtādhvh{luށásp]}d~rՁՁЁׁǁˁʁ]ok`MʁhŁށ{āy~ĺ|сcesha~LoŁvfǁmtmفˁvρǁ{сzH|e{ˁ|́xցunxʁzӁRz~cf~pjÁkҁkpuˁrlrwt[z{w[xw~Á́hʁo~zqZf~䁧uk{qȁ}]΁dk~tvfeсzŁ}[isxYg|kyrxv|ˁpāx}v~|Ło|bo~|\ofpdl}ҁi~ǁwāvƁpmvllȁeˁYs;a򁤁qā}xa|ufat|rcȁ{}ρuK{Ձ́py|݁wsx|ejFƁ~mź́s~|[}{pGÁq|wÁӁwvƁ}~jqŹrrwk}āہyÁ}eɁcb|΁{Łtρ`mہslr{jVyʁЁ[}]kv}}gWvxoɁ{ȁzƁ|{ravāPˁrx}giźȁ́qt~qw|v́~ybp{y{MցՁ~z}Ákzvq~|]ZzrYPY[ҁuxWiẃŁyeb|]gwǁkjpҁˁpÁct{g \ No newline at end of file diff --git a/data/fits/STAR_FOCUS_11.fits b/data/fits/STAR_FOCUS_11.fits deleted file mode 100644 index 935196f76..000000000 --- a/data/fits/STAR_FOCUS_11.fits +++ /dev/null @@ -1 +0,0 @@ -SIMPLE = T / Created by ImageJ FITS_Writer BITPIX = 16 / number of bits per data pixel NAXIS = 2 / number of data axes NAXIS1 = 65 / length of data axis 1 NAXIS2 = 85 / length of data axis 2 BZERO = 32768 / data range offset BSCALE = 1 / default scaling factor DATAMIN = 0.000000 DATAMAX = 65535.000000 INSTRUME= 'ATIK-383L: fw rev 3.27' FILTER = 'Position 3' EXPTIME = 3.000 DATE-OBS= '2014-01-17T20:33:32' XPIXSZ = 5.400 YPIXSZ = 5.400 XBINNING= 1 YBINNING= 1 XORGSUBF= 1127 YORGSUBF= 915 XPOSSUBF= 1127 YPOSSUBF= 915 CBLACK = 311 CWHITE = 15701 CCD-TEMP= -10.0 SWCREATE= 'Artemis Capture' END uwmg݁torzY~mipxRtgU{ydTzvVy{uc}rt`|jf|mibq}F^wqv}otyrxd|km`\oЁiogryvouux~~zTqgHlycfggdQWjky\t|cjpz`zrnwhpZv́{~Ol{^|zzpwfvrRopmbtxszpx|szāx;oppr\bsUnolg`sd{r䁱fsw|Y}oqqxmk^rg~ztgp{gzy}\q?~f|{rsorao[}hy|joixQxwo}yh|Xs}tZ|fyuyr`{g}{~sh{d]Sxkrzkiollpcyj{ρt~jmex]oOkIytlu~|ātrzy{lRgalbkxmyvxwx́wq;dxqz]~}|v{~nyx|}vujjzrz][^ws~kz[jc[|[Nj{^{q}s{u}؁{pbKV^MˁUx|ewse}]ejnMtPy{~xYkqzl|_qcYnzz~miuq}Ulu|or\d~\svOjy}́zd}k{tpt6Chsry{g[d`ssmpz|ŁyJe`l~dvukŁ}l[}kryrjl]vSbs{ncc}bxIvā}Lxd_^mlY䁆rx]΁uy~yegkȁ{}|́wwno|Du^kw{T^hӁZgxmwtsvlbyYLnyXo{ymzyzoin~~y\uwdz~{tVyup}esq}yȁmrxv|istq}nW:oyuuslʁ}]b|u{erldj}wpjexvj}iY}hTgp|ց}iKuoi|e|\rx`Ӂs|āqnk\fcdWvhoj|ywjyrb|fri\FM{{vgzt|Ázi~yx}ny}Oxx|{Rov]@hkhhttwzn||{΁cցw{nt\us~ndquywk}zwkz{[eo|mritlrnrkk^yzjȁuxf_el`i|~tρ^dskɁs؁}sjjmzopH`lirltāx܁Ձ݂||cqVz\tLp~j́asmȁ,x5끧r~txzm\y|bkxdsWhjj0Pp!فҁ́z[c|y[x{fJׁutta|bɁłփC߄|H"ɁVsxuebvTЁ\jvkI{fZ|h́eτdފ#ԃvN΁xoYmrsptzl}vƃYn󋅇-G,܁ہso{e}iwW|rˁ~wy~́Ă_pL*_te؄~$恐ԁ}r|{pknW~aje{uXā~J~BU:Z_Uxā}zw}|}`kw}aȁsށ@GͰ::m5Ą悕.߁}z_swg}\Ӂktxtysjvqn{pẃoKՌ]N+W[u āÁj}pku{tNU}drŁcÁÁ̂yIϓX~5{^nslap}lv}Z]gvzف͈H1b΃5~gYm}h~iuyXvhVt}yzɂÄI E䈥yԂźԁfg؁fwpr:yxlkywe9\_ၘwȁvx{lvl|qq|zlxiˁ@.esxffxV|yMslq^sRizށAف{~nyifjttCovs{|kkeӁjȁЁ߁Ɓāl~nvxj\vx[r~nb|tqZu`lḿށnrw}mYx^|fgbpt|x|x1pwywzyouuabŁgxiyx{sdy~|;ljd`VxXtl]hu}i^taXslbwiym|Łsonnsg~||zrwoWk}^j}jv}LaŁ~u~kszɁUywY{nh~skc|cm]j>iVtl[|wǁ}{ρwphzfbmā|n_}pghԁc^}ev`w`i{~f|lpdxS}Jtwzuf~|nx{n^`ˁ{v}~n}yWerZy{phjdb^y|ȁZrmgbtzgk#ց^ludɁs^}qw}unƁ}ydrosOB]vwg{lX|wrXvodco|jRtrx||jxry]bibgi{vȁr|i{xxtZtViycdlāebluEwQlr}}u^n[zxg^~~g_~tdHpyʁ~NgVy{prymt|sCemzlxbivyunFs~Ár{yn~hxtynuzd7epЁvuvjv~]x[RsxXslky~bcwx}|kuzNrvy~hslg\m~́kplǁsyumlp}nfafrfkml{tu`XuztwutybplpYncklt_tu~vdtkqwt^bvkd~onmnlaamqyeZl{veeTŁj2Zd\txȁ{rk|Ɂh`ckWJ`h[]QsTryjh|vyVpux{xu}pmhjc_{roȁp[ryb[qwgq`pdcvu^}l=ve\y~z^d|~pn`wtqughingTyyƁml{IdepzzeIptdh߁s{eegsw}~k~apYptxn~|z`Kq́wwmnknO \ No newline at end of file diff --git a/data/fits/STAR_FOCUS_12.fits b/data/fits/STAR_FOCUS_12.fits deleted file mode 100644 index 43e429cee6d7c9448278c96616073f779e9359ea..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 14400 zcmeI2X>6R=b%xUv0o*i2iZt$@1O`zQb&6JwCED_W7L7K?Oe|RuX`51HS(HRdl(=)a z&kT9L*@wd+XE-xlW;h(~i%5#1NXnut$+9HJw&X0fvos4@2ie>>Y5S*Wfu!j3elk!i zmb0k&RfvOGzI*RE=RNN^cV}V2_MMMy%gg)wyqo+L<$XGDOI>M+qx4YTftI|2%96vS zpUZosps4Vfr|QZbrFHL>*<4Vxv!M9q`qpnmUsXfp0R*ed@(z?c>ho&&eW=7yl2=pS zTw3v7eLFT47Zg%_Q+yk4&}XYDX)djQua^HUvGuLLnZAwp)9TZC6{S^&9Y=)k9ew5X zd9;7OKU?31o9TP-{q@oQ{r)!Z*|zI(D&OO8{)PuOJ_tS=Rb5Hd;ZiV`)t5TnPt*1C z&4pVwy>EQiOJ8YONkfGrul`_3MS0cXyt0ymj_R8P_8l`@Hx+H#Ua;d=@ZEdQz4qU) z$8xh;Ti>SQ8}x0w|Ni{@Z&72xj>4i{Pi)`zZvO7xR8;W!b@>nGKlX55SyNtJX=7gg zJsTdl`(}84wd|3C$BMS?x-lMi@2svbca&FG<>miYI^L~wTk+1Kg6-RG@Hbz+zPr)y z@EiWNt$TcP;SK(7xOe@1>+W5@Zv6vA8}5BLKmXzU2Y*|j#q{37JvaJ$|2_BJGQQov zXMM$+3wG=%*zwtS`}=FU=Wk?k_wQL>@#DKbTlmE0M{dBke!~O55y<;A*nJay53SeG za%+FZJ0CCnz2duxzW)opEt?)H>$`hXoujmpd1p&WjiaHi^tbK1!mw?} z)?0;gTkbXkw;A{y88GeUpjkDorp8Q~3Nvo9CSW3Fp9z{iV@%5Ir)0>qm;vKAZx6k4Oi3))fbaskoTd(40rRAp<+Ir= zVec$0t8F_@GliW58UlDSL~D!ZE8uMa(?QxCFg<1%To!g}%{9DjHY?`5c@;KVcpGF6 zn-Hx=uyY#C=lInH<}ULTo-LTi!TLPjcA-B;yJkLHj2FKwa|~TCfUKLRC{~|=A0KsF z;qN%UByC(C>Nl7IBwHy-@YIZCfTwHHS_^Z5=j!AZWvS4>nS0c9Umg*s(x*7M&sV`R&Md6GuO6^q6Pu zSR}#a<#~ix8TKt+URqD`+(_=UQ+5XZF64&DlLWOsn|(J??xem6OesFqGv4I8ndehv zd=&^5;Iaulme~u2D2N8I*NMkxkTm3ZrTGa=PN21(l2Lv)(WW0AeY_g5nL{p$#VDFz zAY-F&)@i;7t|c<93?72`J4l@|PoOsjLpfOSlaXDv?kFtg?Dko7>uD0bjWFtlpC0sl z9r+HkhRif&Vet8FFS8&~*6bqY3Gn%e-ZixP&=#XrukjFt46>utIbkV^g(@;|f>I~C zAcVtch~WJbXp4bx0sI*xy|z~&G_}F# zq@CmPWQaWTA(a9_haIh#@Y_e}EZ@awZ|BubEC$gf)Jx>$Fxjsh={27vU+O^Wgy~Uq zJcA!iSUCr4y&zu$ixVrOrUdP2aLyCIIJvynMm9(L{a{jza@pCokn_6dXOU)`++2 zE8SomMnj1DQQLPnh%MSgVYZH6$Eow8zlHo+#>yDn3{tPGzl^pq&`E0wwCzOsIcnP} zje??$(gd3OiBF8V#{$n4H@cw5BgFdi*X8U$6+W_yL0t$=lbylDYbEj>*AwH=$9Lt0>E7v5<$$Y9M4 zx*&7iyxBp!G?G5P=lOJEs}iO=u#pD$4AI(8o#v%1j4UI&!n+GJ=WP@hk*NoVM*9hV ztq}1bY*t|@hGaEdDxZQx!J<_qZx^3^)H~6>2@QpD>ibHcagV=o?S?UaPuDYyyo>O<}& zEFHD|>_U3lyhf>Jm;rKaH{OnuDGONFJX}go(28anti5ni1M)cbn`qIA)i%oev1&l1 zQjM+^{O%z}9kg&#+F|$4(|l_Ub%+`VzN~`C%X^6!$woIVEv%k_tsE`9SnEe)JGdff zngd-wdLPA_danBUNy;)rX_y-2RtSA=yo>NW38PMQoa9$KzgOX6g&DF1D^c3bfI~f? z2Ak)ok)9mbXF!sHuQqhYh+z$KaWch&ToYy8_85ACNX~++8Cx%7F^h!3&jdIuo4Fo( zO%AK-Y0K2BUx>vyBuYUw2J4#j{Vhv6hb~rU9r#|uXdNbton)^LJw#?6lwRWF!9NQQs%Vvi{ZrW1Ts8-)cB0!!c_+xkiavHq} zveyqoUEr_6UJV&_eZ2J1qLLmt333-wnxDn)QKU8U&Qf1Otd7EejPK|1TeGwqCKrjo zagZ&8#ErMdU`svrFuZI=N7jx^8&-SqENt)LYH1rsqgHNOM_hw-H+q#HA*?T>H-Xg| z;-Zz!b9|11ZkBmN=-TMln&-Tr^x>7pUCVCcLLvt@0Y)wh7WRUtjIsM55kG;|82T;r zX@BWweDB4Q4|Z$uLwk_ZWS>@WU7(p^ZSX9ZFXGiV;PnDAOv0aXbc9x;Ak%s@#e0@4 z8-!IS9%>G+rbQpU!v}(Wu-c36YJAL4s!@G{R}_?5C3)<;(mvsv=wIdO6s$C3+XFA! z*$y$IeGML8fw5Y6(7K@wKLc9CB*&hUH5dhnwop&xg?ghhF ztPkPA+erSH^No2*GHCradbIj01KBZfXlw|h|2){6$)8H%I>;_heP9p2w6f4{)ra3n zvTv1VFR~rfYCjRiw@Ivfu^B*0V{RHY#QQ5)pR)eY`lxx$`b+Z_^EzA(*&~GJ)LME( zow-U6PQql8-|9hG>R+T6hFDjeCky&vEJN#lEc?OXCSv8_*Q#%bI3@7y-4ZX)(5P+tyb%k*56onTIk z!vDk8fBHTad_DA?@N3~CL6>i%=P_%m`6seLE2bcJ4`5YiKI%Ck_F?VxixK4Ki1QHW znyD>j9;gDv6jEA$E#qxJ`J~ei4>8c%J&8wZp;L$!GDK^%A6Xx^?((ej`@4rz^L=+G zJ`wqpzs~cP)op#y{0lvJ0!vLuMA6cKb&WV$t10^0K}2|djy&x~e;X|_c-O&q3j0$q zHA%}}q_v{duCaq&HiXtXvEI|xV2(k zMrR!nw6LdN*GGUSsA+>GonI#5WfTdGOhb6>Cx5kWaubmx^(kHnbY5aj@pJ2=mfQRD z$m-M`ul@A&j(^|IvluW3`7sD<^C$baZ7zBgXoI0HtgM$V7m-aRXv19PR6OJmdaRIi~W22zg zuIdP_j+^bE=tI*nu*?w634H1||6#siJ?a?`{8{%$`jf+N4eyD)9{7-F%=$YxcmqxI zpw~I#EU{16-f6G42|LZ$bTXEfV(T!L9OPg(kzR(~Uh3S~+sC^X3_2T%p+TpC+7D^x zEw9!nf0Hcae}VMpt(IdG2gYn-+^|Cm76nstZu5v#*zW)O@@Tt|vg- zNGoM#)O-oFej-0W{URJlr^EJcgzqbiQ@;Sioz^C6ul281BjfQm;AfI|1bBxE>mLEv1Z`&VLwh$LGL@8Q)XtDiA$V9KCr)Ae1vt}8s@7t7 zfP7H=4})Qa`1_DLLUbco(%60yPs_-$X6$NTD+ZEynS;GJ(XPjmcAIl}qnM3RJC8*N zqmAb5UD%ukkLHjOVn0d*7KrJSaQ9U^!zO6&rq?y{*#N$cpw?d5Pm4Ynn1qoDvjt5q zxYw>ktB4C|>qlxUYm084!;EXYK%jHA0KQewBY#MLh?7|_V=)Ns33xw+&N(zKlB@mT z>Swm;N5V^43>J3cZy0?ov<>2A3*(e_DiQQ){(K&UZpNolG-xc-OrllV02Yt(q`itx zE5?as7aDX+pp*4UJ6;3G{*0##b3uept)rWeOd;o@ya8-}e26nj4eJEEN(2MUmq_h(2!lp(Fo!_>Sb?xx!p#3F~B+#onnsMge7wjI|i}ftbyhuqe z@zeO-M*h{o!vfEp%*`ph*6Fa5)vHczwN`8;Cw1bP0fSavK{7${Ng$KJw-8#3iGXf> zq%jU_m2fzKbc{^MfMFURwUVeHceEBALQ3O|_5&euP93azPPxn1W|HJ`W-x)k(N^#!1S$h=v0ma!B^TcL45=5rxMQn`UCDo5~n|U0+@3l(m~UX%BW3X)hKWc%}JTr%V}})mAK(gG2X4X)Nok zI7$vq(MqSBomj5NUK7ZbElKjmN9!g|Kb&~1Ge6x=G*F{`+kV(t!%l!Rp2y#BlVYDI@`_9A$v^KjWZ~!>I2X}9g3UE-&(T(Qe=iWt7V4ttwaB7Nj0s(+O>m&H@z%$)WPtz;M@gqRqG~$;|YHPuv zn*yCz>JD!a-=pxZ{kz8cc6yEO9f$B$r$zf=@Ep1o`8eNW@bm<1`asf1eB_0E%HgfX z#AW!&pvzC$2qh!ns{&~hCL_#}x{LIY5zA;x@!X9qoo)HiquoS^xhTwggqQMH=d+!# z(8tq@#5{r289ud}o+q~Ic{)wW&?<>{+MNqYg5D9KcWCdqpAo5zo1PGUkCO*&NYBv& zb-uiY^fcH?nDY+eg-*3~lH|5CDTqehcV4D6O)r{t@()oJ|6nlx1_RojVK7{4xsb2xrZakkuS~HphRN8Zg zvDr@?)5yy2RdV1ejA%a6ZFCaJ-IPBA>QSOoL%ElzhiOyFJ3;@~nXMvUO9of+%Zo%1 zUd2k3I^8a0DbXm{L%B`}eIO~Lx8=a2)2>c3SZ8&ok@`Mu^nV1}(|E9;(JuppKkzH9ZS@jXO4?Yp#sUnNhX<}+B&!qxqh*O4htf>#1D+$I z8RX{K0l4u&CxyDR=%OZ#u0?P}$nP3_SO$aUGM$Mf;IfYU#Tq=(DWnH28u3GX9za79 z{&kb5)s}kE34Hbt?OAe8cScTX`e5@*@MnST`W^HoO0I$3MV9M70)+592(^w4^PWMY z?$u&g(Q0P~o$_NpJRGK6=W<8TK8Rc=sC?v!W}|sV2Az|C1q6p+O8*g}Xf#n91!;mh z18bG!WjFps(7K1(FxqybrJOns(dmanoz6glacBJ$l2o2cD66qWs2f;dmL@VsXsa?jhW{P?^n#0pce)*7|K|-e|+SR$R zdX4WKeJo9_`t){u)cXDcrFF~*x^vYD$pNG^vs|`)xB^$YFIPTjCzu7_0iJcYrA(-0 zHqbq@PG!Z6X0Sa->ooffP$#jK1?yGYQk?88q|Hg9puQ0zXS8y2@g1ja1)ni|TB1z1 ztD3(;Jf9^BI&*6T;W+lfu%I#0N38ZS>UpSB-#Q4&6KLxpvRY3$z^HuL3x-9swUHfS zT4TEIv*uxI5dFFb)_<-DscsQ;9yDp^lm1)eDmtU~fBig()E=18Jg$?J8v20ldXwPS zDq84u<~sofjUTgks{23XMgT-#29f@s$&05cQ0x3%``XYQ)9w zN5G{sLai)Q#A}6`Ao-<8Cb$Xv47CA98jWa0U~Hvcw?!dpGnAd+NvDysM0x-Q>h1aj zwrY8Wu|ABvFla>4iIDD`9P}C|-nP@La^#?9gD{%3Z_v(6_xo#F<%y$RupMgn5`7AR`lHF!I8YB4JWj@pKf!nX!4BTemHUrlg_`vPI|A!3x4}I>O ACjbBd diff --git a/data/fits/STAR_FOCUS_13.fits b/data/fits/STAR_FOCUS_13.fits deleted file mode 100644 index 165c31b7c..000000000 --- a/data/fits/STAR_FOCUS_13.fits +++ /dev/null @@ -1 +0,0 @@ -SIMPLE = T / Created by ImageJ FITS_Writer BITPIX = 16 / number of bits per data pixel NAXIS = 2 / number of data axes NAXIS1 = 65 / length of data axis 1 NAXIS2 = 85 / length of data axis 2 BZERO = 32768 / data range offset BSCALE = 1 / default scaling factor DATAMIN = 0.000000 DATAMAX = 65535.000000 INSTRUME= 'ATIK-383L: fw rev 3.27' FILTER = 'Position 3' EXPTIME = 3.000 DATE-OBS= '2014-01-17T20:34:09' XPIXSZ = 5.400 YPIXSZ = 5.400 XBINNING= 1 YBINNING= 1 XORGSUBF= 1127 YORGSUBF= 915 XPOSSUBF= 1127 YPOSSUBF= 915 CBLACK = 326 CWHITE = 13119 CCD-TEMP= -10.0 SWCREATE= 'Artemis Capture' END o|xˁ{݁^nexnv|yLd~z~deyhbs}}TЁvyKmlsrwYL}ʁ^yrԁyсŁp`xyuxmenY^wex~|~lbāׁlzofe{{]qɁkkvȁznɁxs~ԁxxv}bm}teu|~yj|~ȁu}atLkaсɁ|pjxtsiyzrbbǁeypvks_bzhy{e}crkہ\iˁNwlVсpozၛa{zsmX\seo|wuρ~vkn؁Ł|сu΁zlw~n}āqḱj{DsxzhrȁxZŁgdnzubρājvywMwuv́kqxo|zÁ~[jt`vxҁMkxjMlXkārqzhk܁ʁuy{΁k؁juflǁЁZdlgƁtYppŁwсi~lyuЁԁuҁ{eÁ{plˁl{Ձd~|kuńƁ~ɁvzyutŁpŁˁˁ|ukaȁyźha΁{sh^y{nVrbmdn]ws~eie΁{qxfȁsyts~||h́V^xtxpˁh{x́uxq́onykk{|ȁtr{xcӁwxszvǁLˁy~t⁔K~ƁiЁvɁt>v聤zx{nxzcylŁS~恐pā|pvytNml}~oρ~{vہyɁrx~Ál||}Qmvҁ}xсhԁ{bp쁋ŁǁsvjoyhnefvdЁhxik~m}}x`nՁЁ}hbsǁxwvfT|ilY_ˁkÁЁxyρuā~ҁwy`ҁrxrbn2Ɂ~Ɂ́ЁՁӁubtbqwlu{hˁҁρၳŁǁsāimirz{΁q˂܁ցȁYzt{xwonxƁہǁс쁼D]@)ȂЁ}{́t܁yqxЁۂv0؃؂؁ЁÁftxeryc}{\ŁhxŁ ;䃽1 N ԁŁrw{zorw{xrŁ~{Ł؁&DŽ\B􁸁ށ~zgāOPzāvlˁ_MvƩHރ2 ؁΁yЁ{wk;^{zˁD΅ʌ›-cH܂ ʁ恗x|Ɓ|rx{6X:y0se~eāÁeځlq^sՁρʂ.1RqO?dh>Rxupflmȁax|}wWzӁ3< ׁȁÁwrǁc_d\ ւ(遇vԁ|nyXrɁqaut Gh9e򁵁Ձˁsq~䁈udqtcƁxÁ߁x8<&ԁzȁb|lr}ҁd_Ɓ߁тӁЁtԁqxh|bsl恋t}f}ЁׁсՁnāfkāqK}{~vŁÁÁځíf|ρсÁЁԁց{́́wgvykh́h|tȁāājpwρd{wxpjvsańÁɁwxkҁxdptxwԁЁ{ˁ{Ł~vsicȁXP~~FvyrjiÁF]΁spr~{DRxˁZqzt\x}pxtW}v_yɁqƁ}zdtdn{^~ՁouyiŁpitr~Whglv~fɁ{qځ恾yfhlQw`[^||v}v<cr|xpg|}wuqqU~|n΁~vboxynd݁|yvzhpVfy偋။xw_TupxynǁOxpzˁ}rqxqoānwsupgl[zwqāف{ḱrŁuicUŁj{Ёupmsсljdisd`[~i|`\tv䁲}yˁmՁr~lzzpxvk|Sczx݁ځpxÁ{Łk~z||~xgfln~f}oxƁsuyn}izwjzz|Á΁h{vƁāށzm_pq|]nlz~x{ttz \ No newline at end of file diff --git a/data/fits/STAR_FOCUS_14.fits b/data/fits/STAR_FOCUS_14.fits deleted file mode 100644 index 8e91733fa77ed50d7e885594a507cdf0410c7910..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 14400 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 diff --git a/data/fits/STAR_FOCUS_15.fits b/data/fits/STAR_FOCUS_15.fits deleted file mode 100644 index 16b5b6440..000000000 --- a/data/fits/STAR_FOCUS_15.fits +++ /dev/null @@ -1,4 +0,0 @@ -SIMPLE = T / Created by ImageJ FITS_Writer BITPIX = 16 / number of bits per data pixel NAXIS = 2 / number of data axes NAXIS1 = 65 / length of data axis 1 NAXIS2 = 85 / length of data axis 2 BZERO = 32768 / data range offset BSCALE = 1 / default scaling factor DATAMIN = 0.000000 DATAMAX = 65535.000000 INSTRUME= 'ATIK-383L: fw rev 3.27' FILTER = 'Position 3' EXPTIME = 3.000 DATE-OBS= '2014-01-17T20:35:09' XPIXSZ = 5.400 YPIXSZ = 5.400 XBINNING= 1 YBINNING= 1 XORGSUBF= 1127 YORGSUBF= 915 XPOSSUBF= 1127 YPOSSUBF= 915 CBLACK = 321 CWHITE = 3866 CCD-TEMP= -10.0 SWCREATE= 'Artemis Capture' END ~itll||}wQaelL^_ujTu{~cǁviqqm}z_s~fl~twZ{nhv|S{lx|y^~j~tÁcupuwyÁemkiuZwrub^fd~zhpphmqtyw[}Vdrt}xρw{Yhtp\}yaprhk|p^`~|tf`khzq\~rx|Jr{vri|qy\}~Heo~|uueN~\~l}m[|]|t{MvSqpnyu~vx||ulɁX~}x~ki}Xaps\[zwʁwf{uxgVwq}c|hdp}zEZxnn\|zxgtz]Ӂ{v|wnP~|powoltgNn~zvz~yuiuwvuwsrcjxtsR~r=msO{zu^m|bqewpЁɁȁtthmnw}ej}|spwwjy[|P\ryv~v`reqpdVlh`v{Moe[y}k~mhlx}SbHjj{b~с|zmkpƁsx|kȁsl|[WfmznTdw]vltiq}Fiph~|xrxwvVrj~g_btI\k~~hk}g|uŁxpbgeu{N]bl}ryos|ntktju|ziblpxeʁlvry`gtv~xix~|]fgp}b~xtZi|x_r]fmƁtpÁwp|iqzh|ldxwa~{nu|edxznxV}jfqr}un~^}vgnrxdYqV`q~K|kp{spt}{B}ZƁ~\~~doekfdnmtYao`yXord~{z|~j́v]s}xepkbe|ipe{eecstkr~U{zvƁʁz{mUrfX]zl{}Łqv~|x|tjρb}etlzxp`twkuaȁnvf^`kpyvpvVoik`izfyr{~yriy΁zeh}~Zn^}f{ρS~~tbxxfvh\|jɁbhmzȁ~́xyolpj~ZskcbuakdpT}Okxā؁Ӂ灲uǁ⁾tLpxxL={sǁK~|Ɂ遴΁%zl|glew؁ye{ˁȁԁ΁ˁӁV#R͂pف}_zj}qwXʁzȁƁ4(4ȁerGxsk\fpтK5 -ЉU o'шp"9uspсx{xVjr9y~~zqp#JI[}ĂԂK:!{Áv́wwM~w9yS~Xrkj},݌-ʼnك傌eł -_Hd؁hoy|[PiQ|xpg$sɂ܂΂I sÁ{merzdxrm`z~vڊK40Nކi0؃ցЁtgR^p|UĺynyhX،WۅuVy􅄈\+\Շuۊ K - ~Xszlkttwj\uおЁ84+؍f*ۉ{hWӁɁi^~duq~o`T~nw{vȁ8ΐN2U끠ǁu\trc{p^}|遞􂱃 S~%mق7ӁPŁq||irxLkwggepǁ˂9<ڃ^灳|Ł}buk\Ё{Ábpd~y~pxЁMρT^lC*큹\np~\j{zx6ZbՁȁӁ΁Ӂolynsv|g~sh}ȁǁˁ{AhRu|ztjl~t~xu~dǁ}u}mtoutZ[vā|i`kuu|fryl]ǁ`ɁUr=U|zYhq}gɁၠcḰz}óv{|MPԁځ{|phs_w[V|rwp}jxVrqoqbnvLh}m|xekmYx⁈r|^nJv{W|kslNqrkzojvUxlpVpe|nẂwv܁ׁyjpl}zo[vww|us}fo~sinzw{|~\ryqia}Po^Rwmturjm}ivVhzoX}dj|zdρxfmphjgsilxu[|vwq}r^kzÁo[x~UjwbaVwTphk~^[tsyk{kllZkہuzka|{gt\VgʁIUtdyrpwŁSaqqsyyiStPXs][Pe`ryRv|hrk"ysKknqwgl \ No newline at end of file diff --git a/data/fits/STAR_FOCUS_16.fits b/data/fits/STAR_FOCUS_16.fits deleted file mode 100644 index 407bcc4a5..000000000 --- a/data/fits/STAR_FOCUS_16.fits +++ /dev/null @@ -1,4 +0,0 @@ -SIMPLE = T / Created by ImageJ FITS_Writer BITPIX = 16 / number of bits per data pixel NAXIS = 2 / number of data axes NAXIS1 = 65 / length of data axis 1 NAXIS2 = 85 / length of data axis 2 BZERO = 32768 / data range offset BSCALE = 1 / default scaling factor DATAMIN = 0.000000 DATAMAX = 65535.000000 INSTRUME= 'ATIK-383L: fw rev 3.27' FILTER = 'Position 3' EXPTIME = 3.000 DATE-OBS= '2014-01-17T20:35:54' XPIXSZ = 5.400 YPIXSZ = 5.400 XBINNING= 1 YBINNING= 1 XORGSUBF= 1127 YORGSUBF= 915 XPOSSUBF= 1127 YPOSSUBF= 915 CBLACK = 324 CWHITE = 2489 CCD-TEMP= -10.0 SWCREATE= 'Artemis Capture' END mtkhoRЁt`kƁrh灸ցÁρ}Ё{uxˁii|v́d[xz||с́t{nvuut}inmxd~{āX}~ypxOz|ztz^ǁg}gV~{X́{~~nxQ́ʁtqvnx[~ds|fځezpj]|ouqkJ}myzʁV|~knrǁU|wÁxsŁz{ysyafszwvufoce}qnwsgyllijgmyyjn{vt~thWwsvrsms}Nn΁z܁Ё|Ɂ{||}^}ρ؁v{zypq|ń|}ptsbzu}zŁXonSNqƁs{rȁdvȁlgpx|ˁ}lvρvurx~āDj{bp|||zksyuqɁ\}k|KɁqae`zknv{~|_|XmkցZzwk|ckm`RpЁtxxÁ~vwqkr|ezoLӁzsՁpsρuhuqSUVg`}xńv{uvvҁt|inubā||hd}lXenz^uióȁ^Ӂˁś́hācjЁЁāo~ur~rlzfՁlYZjqwʁpxzȁ΁vhӁul΁r{s||sivŁŁ}ȁosʁgq||]ȁʁyz쁄~ՁŁrƁāgf|xՁźԁ́jށm쁼ԁvĺtw}g{`xmyفˁ聱遞ӁɁсY}v`[izjŁЁŁ遱-ށ҂5Jԁ{؁elznɁrǁww끭 =_qƂt"S -ǁ၆n{LZ}yMt݁́Łց|􃃃݄.-MHׂӂȂTցŁuvkRvnہ~Ȃ -.̈́] yv&rՁpсjml~遈Ă:ᄬ煽cRFK>V{;%܁Łātiz\my؂iCr؆%!僊#K.炂ށށx́r=Ձف܁܂{ۃ]z`烲)@$ہrÁvŁcpt~N|{ԁyŁxā(To|~iOȁŁz~~ȁtxM{yʁЁ>%EƃS<ς+ׄw.ʂ}rp|}сā ؅RӅ_ނ|#uSZk.XX]āցyn^}|uȁā;'h'1xփo>H0"肈ԁÁہƁ[{ko񁚁؂""11lMVC ҁ́ҁ?˃)i煫%с́dCɁҁ9ˇ;QЅ=3(ׁ́ւBGS`5遪ɁƁuh́upƁ!<077؃ɁԁہKЇɅ ćāriŁ>ŁaقVuℙZ]т EăUن醤l݁Ɂā~y{ox8K{ eւĂȂ -сق1IO*僥ǁ}fwсw_H}΁́󁪁!/jG<ȁ+L?rۅotru<ȁ[́́~zтJ9|JNĂ 0΂h(+ֆŃ܁ȁwā~Łzr{΁sg͂~pćxÆcM6i8& bx ք~@Äm_C{x~wsrro5V/9"m򂎂z͂o,7\ nȁ~|r\bv^id́ՁLt{Kd^ -ˆM{ouf{M`hzÁЁ͂c='DV\B օRтρfer܁szpɁyڂXۆ݊t܈drׇ҆V׈=g 䁍Ł}yZqrvoG̈e ;lbŁсspnx܁ǁ݁Zy$넮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 diff --git a/data/fits/STAR_FOCUS_2.fits b/data/fits/STAR_FOCUS_2.fits deleted file mode 100644 index ee43051d3ffe1f2301b025d3595a721597ebfd21..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 14400 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 X9l8V5r&Jc(g*2yF!Aq-@h-+kts!NDdOhQH=m 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 v5?okr(7%hiX7tNhi<=dcoL&zj#e-KlIjyrtso݁}eӁ|zwԁzRȁ{ā؁́~́jX|tRasvɁiҁ\xRʁfmlnǁcsomсŁRЁjŁcԁ́v{ҁ}\h3sՁɁ|}yʁȁցmsn}[Ł~uzi䁎}[|huib|YŁfyrY}{sn|ˁŁstpa}f́q}p聵}܁{Ձ_kEm݁́vxvSyyuk聰ρÁguȁhŁzhˁ܁Ɂg؁gieρāЁpzc}pjoxpVgs~ցu{rɁ||māVぞqgrśفၫwju^xykҁx|uҁ~v|zr=}ʁ}ȁ~lptYwzρu~ShzwÁjnԁʁ΁{oāāЁ|d偊}j}ms`^vāxӁÁففɁ񁬁΁ρ߁jweucxӁwʁځiŁqf܁Áǁс_ȁy|voĺeuӁ}{́~w؁ÁÁցjksЁ}b|~ށeJf܁ǁɁƂʁkknс́m[Ёvvz{فǂ؂_,rρ|uY\́~ʁjׂ44m'=aȂ6 opvdzonśl{xj<σ(y(xu}c|~woс݁Ё 5Ƀ}nAԄbЂeƁ{}~ÁcāɁ}unkŁmāyh҂#Ђb|BSX*̆tʄ@63́Áԁz}elÁn}ʁӁׂ"ŃȆVU* wslńnʁ|၎jȁ݁ل.zc⁡灸́y~x|efāubshxq^́m΁iHŁցOǁjchw|ہ{syúx|Ái|pp|~e~~pāӁցsy|slv{qe|~kˁЁ{|]~pt΁`\`Zāiszm[tetB]}Vǁow~y{wMŁ\_|Ɓpl|dcQxz_΁y{\~nyxyf}}[xbuǁ{uta~en|ɁLmqjwnyqqiÁ_m~||n݁|ف[s}xzoсnl΁mf~b{mhź|p|l{lzb~mxoviyZgȁw~~tbb`ysZyff􁱁xzywyulyǁ]zyfCg{́Ffyirmtx[yevhzHvy]rЁKr~sTt^fʁ|qsre}pā\kybf́u~}ցi|tÁ{wszlxŁey|vmx́nuyTz|r~tptՁz{āTɁj}zqq΁hzxxc|{eUejāmzʁp[a݁|o_nǁ}ʁ|qluρz}xgQāՁ}lŁdz~nȁo{VguovkykdƁ~lyleaҁz{ǵԁyuayeln~k{ÁXs|~QSlXy]ickejmw{xuevlkvցd[zdu~xo~L|\ \ No newline at end of file diff --git a/data/fits/STAR_FOCUS_6.fits b/data/fits/STAR_FOCUS_6.fits deleted file mode 100644 index 259ba37545a5e9c4933a62264455136ca1452ad4..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 14400 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ˉUʐВ׎78 \lǁځgrz}mc~ls45ܜޜŔځrokyepFtaPāc`wŬLEE%~Ȃd -؁ԁȁwhnZSk}tÁс=DŽWaϬrԈp؁^~rTqpmtú~Ӂ肬k Un֛wp΄ڃ%,災m~y~bY`ni|{ < jNPSqmG넋/ぎrhȁv{vy>}}Łwޅ('̉Pہs^zpe`~woxocy[!̅M`Q<灔p||tk~gf]]oyoyhwu{{ˁނHltx́yszeyV`w~{bށÁtЁЂ -W9Lewwwq9bphātyz|āry~}`{%3\u)ׁād΁zZoF|zrЁށ ^cn}q|uu|b~n&dUO{ON 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 diff --git a/data/fits/STAR_FOCUS_9.fits b/data/fits/STAR_FOCUS_9.fits deleted file mode 100644 index afcccbfd9d1198e92845d2e4df9e9f511cf4c0e8..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 14400 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, val code: Int, val description: String) { @@ -10,15 +11,15 @@ enum class Bitpix(val type: Class, val code: Int, val description: S FLOAT(Float::class.javaPrimitiveType!!, -32, "32-bit floating point"), DOUBLE(Double::class.javaPrimitiveType!!, -64, "64-bit floating point"); - val card = HeaderCard.create(Standard.BITPIX, code) + val card = FitsHeaderCard.create(FitsKeywordDictionary.BITPIX, code) val byteSize = abs(code) / 8 companion object { @JvmStatic - fun from(header: Header): Bitpix { - return of(header.getInt(Standard.BITPIX, 0)) + fun from(header: ReadableHeader): Bitpix { + return of(header.getInt(FitsKeywordDictionary.BITPIX, 0)) } @JvmStatic diff --git a/nebulosa-fits/src/main/kotlin/nebulosa/fits/Checksum.kt b/nebulosa-fits/src/main/kotlin/nebulosa/fits/Checksum.kt index a2784903f..929dd73db 100644 --- a/nebulosa-fits/src/main/kotlin/nebulosa/fits/Checksum.kt +++ b/nebulosa-fits/src/main/kotlin/nebulosa/fits/Checksum.kt @@ -1,6 +1,6 @@ package nebulosa.fits -enum class Checksum(hduType: HduType, valueType: ValueType, comment: String) : FitsHeader { +enum class Checksum(hduType: HduType, valueType: ValueType, comment: String) : FitsKeyword { /** * The value field of the CHECKSUM keyword shall contain a 16 character string, left justified starting in column * 12, containing the ASCII encoded complement of the checksum of the FITS HDU (Header and Data Unit). The algorithm @@ -28,7 +28,7 @@ enum class Checksum(hduType: HduType, valueType: ValueType, comment: String) : F */ DATASUM(HduType.ANY, ValueType.STRING, "checksum of the data records"); - private val header = FitsHeaderImpl(name, hduType, valueType, comment) + private val header = FitsKeywordItem(name, hduType, valueType, comment) override val key get() = header.key diff --git a/nebulosa-fits/src/main/kotlin/nebulosa/fits/Compression.kt b/nebulosa-fits/src/main/kotlin/nebulosa/fits/Compression.kt index 6a5674f20..f092ee24c 100644 --- a/nebulosa-fits/src/main/kotlin/nebulosa/fits/Compression.kt +++ b/nebulosa-fits/src/main/kotlin/nebulosa/fits/Compression.kt @@ -2,8 +2,8 @@ package nebulosa.fits enum class Compression( hduType: HduType, valueType: ValueType, comment: String, - val uncompressedKey: FitsHeader? = null, -) : FitsHeader { + val keyword: FitsKeyword? = null, +) : FitsKeyword { /** * (required keyword) This keyword must have the logical value T. The value field of this keyword shall be ’T’ to * indicate that the FITS binary table extension contains a compressed BINTABLE, and that logically this extension @@ -30,19 +30,19 @@ enum class Compression( * (required keyword) The value field of this keyword shall contain an integer that gives the value of the BITPIX * keyword in the uncompressed FITS image. 1 */ - ZBITPIX(HduType.ANY, ValueType.INTEGER, "", Standard.BITPIX), + ZBITPIX(HduType.ANY, ValueType.INTEGER, "", FitsKeywordDictionary.BITPIX), /** * (required keyword) The value field of this keyword shall contain an integer that gives the value of the NAXIS * keyword in the uncompressed FITS image. */ - ZNAXIS(HduType.ANY, ValueType.INTEGER, "", Standard.NAXIS), + ZNAXIS(HduType.ANY, ValueType.INTEGER, "", FitsKeywordDictionary.NAXIS), /** * (required keywords) The value field of these keywords shall contain a positive integer that gives the value of * the NAXISn keywords in the uncompressed FITS image. */ - ZNAXISn(HduType.ANY, ValueType.INTEGER, "", Standard.NAXISn), + ZNAXISn(HduType.ANY, ValueType.INTEGER, "", FitsKeywordDictionary.NAXISn), /** * (optional keywords) The value of these indexed keywords (where n ranges from 1 to ZNAXIS ) shall contain a @@ -89,7 +89,7 @@ enum class Compression( * identical copy of the original FITS file when the image is uncompressed.preserves the original SIMPLE keyword.may * only be used if the original uncompressed image was contained in the primary array of the FITS file. */ - ZSIMPLE(HduType.PRIMARY, ValueType.LOGICAL, "", Standard.SIMPLE), + ZSIMPLE(HduType.PRIMARY, ValueType.LOGICAL, "", FitsKeywordDictionary.SIMPLE), /** * The following optional keyword is defined to store a verbatim copy of the value and comment field of the @@ -98,7 +98,7 @@ enum class Compression( * keyword.may only be used if the original uncompressed image was contained in in IMAGE extension. */ - ZTENSION(HduType.ANY, ValueType.STRING, "", Standard.XTENSION), + ZTENSION(HduType.ANY, ValueType.STRING, "", FitsKeywordDictionary.XTENSION), /** * The following optional keyword is defined to store a verbatim copy of the value and comment field of the @@ -106,7 +106,7 @@ enum class Compression( * identical copy of the original FITS file when the image is uncompressed.preserves the original EXTEND keyword.may * only be used if the original uncompressed image was contained in the primary array of the FITS file. */ - ZEXTEND(HduType.PRIMARY, ValueType.LOGICAL, "", Standard.EXTEND), + ZEXTEND(HduType.PRIMARY, ValueType.LOGICAL, "", FitsKeywordDictionary.EXTEND), /** * The following optional keyword is defined to store a verbatim copy of the value and comment field of the @@ -115,7 +115,7 @@ enum class Compression( * keyword.may only be used if the original uncompressed image was contained in the primary array of the FITS file, */ @Deprecated("no blocksize other that 2880 may be used") - ZBLOCKED(HduType.PRIMARY, ValueType.LOGICAL, "", Standard.BLOCKED), + ZBLOCKED(HduType.PRIMARY, ValueType.LOGICAL, "", FitsKeywordDictionary.BLOCKED), /** * The following optional keyword is defined to store a verbatim copy of the value and comment field of the @@ -123,7 +123,7 @@ enum class Compression( * identical copy o f the original FITS file when the image is uncompressed.preserves the original PCOUNT * keyword.may only be used if the original uncompressed image was contained in in IMAGE extension. */ - ZPCOUNT(HduType.EXTENSION, ValueType.INTEGER, "", Standard.PCOUNT), + ZPCOUNT(HduType.EXTENSION, ValueType.INTEGER, "", FitsKeywordDictionary.PCOUNT), /** * The following optional keyword is defined to store a verbatim copy of the value and comment field of the @@ -131,7 +131,7 @@ enum class Compression( * identical copy o f the original FITS file when the image is uncompressed.preserves the original GCOUNT * keyword.may only be used if the original uncompressed image was contained in in IMAGE extension. */ - ZGCOUNT(HduType.EXTENSION, ValueType.INTEGER, "", Standard.GCOUNT), + ZGCOUNT(HduType.EXTENSION, ValueType.INTEGER, "", FitsKeywordDictionary.GCOUNT), /** * The following optional keyword is defined to store a verbatim copy of the value and comment field of the @@ -181,7 +181,7 @@ enum class Compression( * The value field of these keywords shall contain the character string values of the corresponding TFORMn keywords * that defines the data type of column n in the original uncompressed FITS table. */ - ZFORMn(HduType.ANY, ValueType.STRING, "", Standard.TFORMn), + ZFORMn(HduType.ANY, ValueType.STRING, "", FitsKeywordDictionary.TFORMn), /** * The value field of these keywords shall contain a charac- ter string giving the mnemonic name of the algorithm @@ -190,7 +190,7 @@ enum class Compression( */ ZCTYPn(HduType.ANY, ValueType.STRING, ""); - private val header = FitsHeaderImpl(name, hduType, valueType, comment) + private val header = FitsKeywordItem(name, hduType, valueType, comment) override val key get() = header.key diff --git a/nebulosa-fits/src/main/kotlin/nebulosa/fits/Fits.kt b/nebulosa-fits/src/main/kotlin/nebulosa/fits/Fits.kt index 4ecdfc0f3..49fbb08ef 100644 --- a/nebulosa-fits/src/main/kotlin/nebulosa/fits/Fits.kt +++ b/nebulosa-fits/src/main/kotlin/nebulosa/fits/Fits.kt @@ -11,7 +11,7 @@ open class Fits : LinkedList> { constructor(hdus: Collection>) : super(hdus) - fun readHdu(source: SeekableSource): Hdu<*>? { + open fun readHdu(source: SeekableSource): Hdu<*>? { return try { return FitsIO.read(source).also(::add) } catch (ignored: EOFException) { @@ -19,13 +19,17 @@ open class Fits : LinkedList> { } } - fun read(source: SeekableSource) { + open fun read(source: SeekableSource) { while (true) { readHdu(source) ?: break } } - fun writeTo(sink: Sink) { - forEach { FitsIO.write(sink, it) } + open fun writeTo(sink: Sink) { + writeTo(sink, FitsIO) + } + + open fun writeTo(sink: Sink, writer: FitsWriter) { + forEach { writer.write(sink, it) } } } diff --git a/nebulosa-fits/src/main/kotlin/nebulosa/fits/FitsElement.kt b/nebulosa-fits/src/main/kotlin/nebulosa/fits/FitsElement.kt index 258b8b2bb..e09d6b651 100644 --- a/nebulosa-fits/src/main/kotlin/nebulosa/fits/FitsElement.kt +++ b/nebulosa-fits/src/main/kotlin/nebulosa/fits/FitsElement.kt @@ -1,11 +1,6 @@ package nebulosa.fits -import nebulosa.io.SeekableSource -import okio.Sink +import nebulosa.image.format.ImageSink +import nebulosa.image.format.ImageSource -interface FitsElement { - - fun read(source: SeekableSource) - - fun write(sink: Sink) -} +interface FitsElement : ImageSource, ImageSink diff --git a/nebulosa-fits/src/main/kotlin/nebulosa/fits/FitsHeader.kt b/nebulosa-fits/src/main/kotlin/nebulosa/fits/FitsHeader.kt index ceca4437f..47b75110d 100644 --- a/nebulosa-fits/src/main/kotlin/nebulosa/fits/FitsHeader.kt +++ b/nebulosa-fits/src/main/kotlin/nebulosa/fits/FitsHeader.kt @@ -1,17 +1,216 @@ package nebulosa.fits -interface FitsHeader { +import nebulosa.image.format.AbstractHeader +import nebulosa.image.format.HeaderCard +import nebulosa.image.format.HeaderKey +import nebulosa.io.SeekableSource +import nebulosa.io.source +import nebulosa.log.loggerFor +import okio.Buffer +import okio.Sink +import java.io.EOFException +import java.util.* - val key: String +open class FitsHeader : AbstractHeader, FitsElement { - val comment: String + constructor() : super() - val hduType: HduType + constructor(cards: Collection) : super(cards) - val valueType: ValueType + override fun readOnly(): FitsHeader = ReadOnly(this) - fun n(vararg numbers: Int): FitsHeader + override fun clone() = FitsHeader(this) - val isCommentStyle - get() = valueType == ValueType.NONE || key.isBlank() + override fun read(source: SeekableSource) { + clear() + + var count = 0 + val buffer = Buffer() + + while (true) { + buffer.clear() + + if (source.read(buffer, 80L) != 80L) throw EOFException() + + val card = FitsHeaderCard.from(buffer) + count++ + + if (cards.isEmpty()) { + require(isFirstCard(card.key)) { "Not a proper FITS header: ${card.key}" } + } else if (card.isBlank) { + continue + } else if (card.key == FitsKeywordDictionary.END.key) { + break + } + + add(card) + } + + val skipBytes = Hdu.computeRemainingBytesToSkip(count * 80L) + if (skipBytes > 0L) source.skip(skipBytes) + + buffer.clear() + } + + override fun write(sink: Sink) { + val buffer = Buffer() + + for (card in cards) { + buffer.writeString(card.formattedValue(), Charsets.US_ASCII) + } + + if (cards.last.key != "END") { + buffer.writeString(FitsHeaderCard.END.formattedValue(), Charsets.US_ASCII) + } + + var remainingBytes = Hdu.computeRemainingBytesToSkip(buffer.size) + + while (remainingBytes-- > 0) { + buffer.writeByte(0) + } + + buffer.readAll(sink) + } + + override fun add(key: HeaderKey, value: Boolean) { + checkType(key, ValueType.LOGICAL) + FitsHeaderCard.create(key, value).also(::add) + } + + override fun add(key: String, value: Boolean, comment: String) { + FitsHeaderCard.create(key, value, comment).also(::add) + } + + override fun add(key: HeaderKey, value: Int) { + checkType(key, ValueType.INTEGER) + FitsHeaderCard.create(key, value).also(::add) + } + + override fun add(key: String, value: Int, comment: String) { + FitsHeaderCard.create(key, value, comment).also(::add) + } + + override fun add(key: HeaderKey, value: Double) { + checkType(key, ValueType.REAL) + FitsHeaderCard.create(key, value).also(::add) + } + + override fun add(key: String, value: Double, comment: String) { + FitsHeaderCard.create(key, value, comment).also(::add) + } + + override fun add(key: HeaderKey, value: String) { + checkType(key, ValueType.STRING) + FitsHeaderCard.create(key, value).also(::add) + } + + override fun add(key: String, value: String, comment: String) { + FitsHeaderCard.create(key, value, comment).also(::add) + } + + open fun add(card: FitsHeaderCard) { + if (!card.isKeyValuePair) cards.add(card) + else { + val index = cards.indexOfFirst { it.key == card.key } + if (index >= 0) cards[index] = card + else cards.add(card) + } + } + + open class ReadOnly : FitsHeader { + + constructor() : super(LinkedList()) + + constructor(cards: Collection) : super(cards) + + final override fun read(source: SeekableSource) = Unit + + final override fun clear() = Unit + + final override fun add(key: HeaderKey, value: Boolean) = Unit + + final override fun add(key: HeaderKey, value: Int) = Unit + + final override fun add(key: HeaderKey, value: Double) = Unit + + final override fun add(key: HeaderKey, value: String) = Unit + + final override fun write(sink: Sink) = Unit + + final override fun add(key: String, value: Boolean, comment: String) = Unit + + final override fun add(key: String, value: Int, comment: String) = Unit + + final override fun add(key: String, value: Double, comment: String) = Unit + + final override fun add(key: String, value: String, comment: String) = Unit + + final override fun add(card: FitsHeaderCard) = Unit + + final override fun delete(key: HeaderKey) = false + + final override fun delete(key: String) = false + + override fun readOnly() = this + } + + companion object { + + const val DEFAULT_COMMENT_ALIGN = 30 + const val MIN_COMMENT_ALIGN = 20 + const val MAX_COMMENT_ALIGN = 70 + + @JvmStatic private val LOG = loggerFor() + + var commentAlignPosition = DEFAULT_COMMENT_ALIGN + set(value) { + require(value in MIN_COMMENT_ALIGN..MAX_COMMENT_ALIGN) + field = value + } + + @JvmStatic + fun from(source: SeekableSource): FitsHeader { + val header = FitsHeader() + header.read(source) + return header + } + + @JvmStatic + fun from(source: String): FitsHeader { + return from(source.toByteArray()) + } + + @JvmStatic + fun from(source: ByteArray): FitsHeader { + return from(source.source()) + } + + @JvmStatic + fun checkType(key: HeaderKey, type: ValueType): Boolean { + if (key is FitsKeyword) { + if (key.valueType == type || key.valueType == ValueType.ANY) { + return true + } + + if (key.valueType == ValueType.COMPLEX && (type == ValueType.REAL || type == ValueType.INTEGER)) { + return true + } + + if (key.valueType == ValueType.REAL && type == ValueType.INTEGER) { + return true + } + + LOG.warn("[${key.key}] with unexpected value type. Expected $type, got ${key.valueType}") + + return false + } + + return true + } + + @JvmStatic + fun isFirstCard(key: String): Boolean { + return FitsKeywordDictionary.SIMPLE.key == key || FitsKeywordDictionary.XTENSION.key == key + } + } } diff --git a/nebulosa-fits/src/main/kotlin/nebulosa/fits/FitsHeaderCard.kt b/nebulosa-fits/src/main/kotlin/nebulosa/fits/FitsHeaderCard.kt new file mode 100644 index 000000000..863979efe --- /dev/null +++ b/nebulosa-fits/src/main/kotlin/nebulosa/fits/FitsHeaderCard.kt @@ -0,0 +1,242 @@ +package nebulosa.fits + +import nebulosa.image.format.HeaderCard +import nebulosa.image.format.HeaderKey +import nebulosa.log.loggerFor +import okio.Buffer +import org.apache.commons.numbers.complex.Complex +import java.io.Serializable +import java.math.BigDecimal +import java.math.BigInteger +import kotlin.math.max + +data class FitsHeaderCard( + override val key: String, override val value: String, + override val comment: String, val type: FitsHeaderCardType, +) : HeaderCard, Serializable { + + internal constructor(parsed: FitsHeaderCardParser) : this( + parsed.key, parsed.value, parsed.comment, parsed.type + ) + + override val isCommentStyle + get() = type == FitsHeaderCardType.NONE + + override val isKeyValuePair + get() = !isCommentStyle && key.isNotEmpty() + + override val isBooleanType + get() = type == FitsHeaderCardType.BOOLEAN + + override val isStringType + get() = type == FitsHeaderCardType.TEXT + + override val isDecimalType + get() = type == FitsHeaderCardType.DECIMAL || type == FitsHeaderCardType.BIG_DECIMAL + + override val isIntegerType + get() = type == FitsHeaderCardType.INTEGER || type == FitsHeaderCardType.BIG_INTEGER + + override val isBlank + get() = if (!isCommentStyle || key.isNotBlank()) false else comment.isBlank() + + val hasHierarchKey + get() = isHierarchKey(key) + + private fun getBooleanValue(defaultValue: Boolean): Boolean { + return if (value == "T") true else if (value == "F") false else defaultValue + } + + private fun getNumericValue(asType: Class, defaultValue: T): T { + return try { + val decimal = BigDecimal(value.uppercase().replace('D', 'E')) + + if (Byte::class.javaObjectType.isAssignableFrom(asType)) { + asType.cast(decimal.toByte()) + } else if (Short::class.javaObjectType.isAssignableFrom(asType)) { + asType.cast(decimal.toShort()) + } else if (Int::class.javaObjectType.isAssignableFrom(asType)) { + asType.cast(decimal.toInt()) + } else if (Long::class.javaObjectType.isAssignableFrom(asType)) { + asType.cast(decimal.toLong()) + } else if (Float::class.javaObjectType.isAssignableFrom(asType)) { + asType.cast(decimal.toFloat()) + } else if (Double::class.javaObjectType.isAssignableFrom(asType)) { + asType.cast(decimal.toDouble()) + } else if (BigInteger::class.javaObjectType.isAssignableFrom(asType)) { + asType.cast(decimal.toBigInteger()) + } else if (BigDecimal::class.javaObjectType.isAssignableFrom(asType)) { + asType.cast(decimal) + } else { + throw IllegalArgumentException("unsupported class $asType") + } + } catch (e: NumberFormatException) { + LOG.error("failed to parse numeric value", e) + defaultValue + } + } + + override fun getValue(asType: Class, defaultValue: T): T { + return if (Boolean::class.javaObjectType.isAssignableFrom(asType)) { + asType.cast(getBooleanValue(defaultValue as Boolean)) + } else if (Number::class.javaObjectType.isAssignableFrom(asType)) { + getNumericValue(asType, defaultValue) + } else if (String::class.javaObjectType.isAssignableFrom(asType)) { + asType.cast(value) + } else if (Complex::class.java.isAssignableFrom(asType)) { + asType.cast(Complex.parse(value.trim().uppercase().replace('D', 'E'))) + } else if (value.isBlank()) { + defaultValue + } else { + throw IllegalArgumentException("unsupported class $asType") + } + } + + override fun formattedValue(): String { + return FitsHeaderCardFormatter.format(this) + } + + companion object { + + @JvmStatic private val LOG = loggerFor() + + const val FITS_HEADER_CARD_SIZE = 80 + const val MAX_KEYWORD_LENGTH = 8 + const val STRING_QUOTES_LENGTH = 2 + const val MAX_VALUE_LENGTH = 70 + const val MAX_COMMENT_CARD_COMMENT_LENGTH = MAX_VALUE_LENGTH + 1 + const val MAX_STRING_VALUE_LENGTH = MAX_VALUE_LENGTH - 2 + const val MAX_LONG_STRING_VALUE_LENGTH = MAX_STRING_VALUE_LENGTH - 1 + const val MAX_LONG_STRING_VALUE_WITH_COMMENT_LENGTH = MAX_LONG_STRING_VALUE_LENGTH - 2 + const val MAX_HIERARCH_KEYWORD_LENGTH = FITS_HEADER_CARD_SIZE - 6 + const val MAX_LONG_STRING_CONTINUE_OVERHEAD = 3 + const val MIN_VALID_CHAR = 0x20.toChar() + const val MAX_VALID_CHAR = 0x7e.toChar() + const val HIERARCH_WITH_DOT = "HIERARCH." + + @JvmStatic val END = FitsHeaderCard("END", "", "", FitsHeaderCardType.NONE) + + @JvmStatic + fun from(source: Buffer): FitsHeaderCard { + return from(source.readString(80L, Charsets.US_ASCII)) + } + + @JvmStatic + fun from(source: CharSequence): FitsHeaderCard { + return FitsHeaderCard(FitsHeaderCardParser(source)) + } + + @JvmStatic + fun create(header: HeaderKey, value: Boolean): FitsHeaderCard { + return create(header.key, value, header.comment) + } + + @JvmStatic + fun create(header: HeaderKey, value: Int): FitsHeaderCard { + return create(header.key, "$value", header.comment) + } + + @JvmStatic + fun create(header: HeaderKey, value: Long): FitsHeaderCard { + return create(header.key, "$value", header.comment) + } + + @JvmStatic + fun create(header: HeaderKey, value: BigInteger): FitsHeaderCard { + return create(header.key, "$value", header.comment) + } + + @JvmStatic + fun create(header: HeaderKey, value: Float): FitsHeaderCard { + return create(header.key, "$value", header.comment) + } + + @JvmStatic + fun create(header: HeaderKey, value: Double): FitsHeaderCard { + return create(header.key, "$value", header.comment) + } + + @JvmStatic + fun create(key: HeaderKey, value: BigDecimal, comment: String = ""): FitsHeaderCard { + return create(key.key, "$value", comment) + } + + @JvmStatic + fun create(header: HeaderKey, value: String): FitsHeaderCard { + return create(header.key, value, header.comment) + } + + @JvmStatic + fun create(key: String, value: Boolean, comment: String = ""): FitsHeaderCard { + return FitsHeaderCard(key, if (value) "T" else "F", comment, FitsHeaderCardType.BOOLEAN) + } + + @JvmStatic + fun create(key: String, value: Int, comment: String = ""): FitsHeaderCard { + return FitsHeaderCard(key, "$value", comment, FitsHeaderCardType.INTEGER) + } + + @JvmStatic + fun create(key: String, value: Long, comment: String = ""): FitsHeaderCard { + return FitsHeaderCard(key, "$value", comment, FitsHeaderCardType.INTEGER) + } + + @JvmStatic + fun create(key: String, value: BigInteger, comment: String = ""): FitsHeaderCard { + return FitsHeaderCard(key, "$value", comment, FitsHeaderCardType.BIG_INTEGER) + } + + @JvmStatic + fun create(key: String, value: Float, comment: String = ""): FitsHeaderCard { + return FitsHeaderCard(key, "$value", comment, FitsHeaderCardType.DECIMAL) + } + + @JvmStatic + fun create(key: String, value: Double, comment: String = ""): FitsHeaderCard { + return FitsHeaderCard(key, "$value", comment, FitsHeaderCardType.DECIMAL) + } + + @JvmStatic + fun create(key: String, value: BigDecimal, comment: String = ""): FitsHeaderCard { + return FitsHeaderCard(key, "$value", comment, FitsHeaderCardType.BIG_DECIMAL) + } + + @JvmStatic + fun create(key: String, value: String, comment: String = ""): FitsHeaderCard { + return FitsHeaderCard(key, value, comment, FitsHeaderCardType.TEXT) + } + + @JvmStatic + internal fun isHierarchKey(key: String): Boolean { + return key.uppercase().startsWith(HIERARCH_WITH_DOT) + } + + @JvmStatic + fun isValidChar(c: Char): Boolean { + return c in MIN_VALID_CHAR..MAX_VALID_CHAR + } + + @JvmStatic + fun sanitize(input: CharSequence): String { + val data = CharArray(input.length) + + for (i in input.indices) { + val char = input[i] + data[i] = if (isValidChar(char)) char else '?' + } + + return data.concatToString() + } + + @JvmStatic + private fun spaceForValue(key: String): Int { + return if (key.length > MAX_KEYWORD_LENGTH) { + // HierarchFormater.extraSpaceRequired = 1 + FITS_HEADER_CARD_SIZE - (max(key.length, MAX_KEYWORD_LENGTH) + 1) + } else { + // DEFAULT_SKIP_BLANK_AFTER_ASSIGN = false, so AssignLength = 2. + FITS_HEADER_CARD_SIZE - (max(key.length, MAX_KEYWORD_LENGTH) + 2) + } + } + } +} diff --git a/nebulosa-fits/src/main/kotlin/nebulosa/fits/HeaderCardFormatter.kt b/nebulosa-fits/src/main/kotlin/nebulosa/fits/FitsHeaderCardFormatter.kt similarity index 86% rename from nebulosa-fits/src/main/kotlin/nebulosa/fits/HeaderCardFormatter.kt rename to nebulosa-fits/src/main/kotlin/nebulosa/fits/FitsHeaderCardFormatter.kt index e5ee5b51a..d172d7f41 100644 --- a/nebulosa-fits/src/main/kotlin/nebulosa/fits/HeaderCardFormatter.kt +++ b/nebulosa-fits/src/main/kotlin/nebulosa/fits/FitsHeaderCardFormatter.kt @@ -3,10 +3,10 @@ package nebulosa.fits import java.util.* import kotlin.math.min -object HeaderCardFormatter { +object FitsHeaderCardFormatter { - fun format(card: HeaderCard): String { - return with(StringBuilder(HeaderCard.FITS_HEADER_CARD_SIZE)) { + fun format(card: FitsHeaderCard): String { + return with(StringBuilder(FitsHeaderCard.FITS_HEADER_CARD_SIZE)) { appendKey(card) val valueStart = appendValue(card) @@ -21,18 +21,18 @@ object HeaderCardFormatter { pad() - HeaderCard.sanitize(this) + FitsHeaderCard.sanitize(this) } } @JvmStatic - private fun StringBuilder.appendKey(card: HeaderCard) { + private fun StringBuilder.appendKey(card: FitsHeaderCard) { var key = card.key if (card.hasHierarchKey) { key = HierarchKeyFormatter.INSTANCE.format(key) - if (key.length > HeaderCard.MAX_HIERARCH_KEYWORD_LENGTH) { + if (key.length > FitsHeaderCard.MAX_HIERARCH_KEYWORD_LENGTH) { // Truncate HIERARCH keywords as necessary to fit. // This is really just a second parachute here. Normally, HeaderCards // won't allow creation or setting longer keywords... @@ -46,11 +46,11 @@ object HeaderCardFormatter { append(key) - padTo(HeaderCard.MAX_KEYWORD_LENGTH) + padTo(FitsHeaderCard.MAX_KEYWORD_LENGTH) } @JvmStatic - private fun StringBuilder.appendValue(card: HeaderCard): Int { + private fun StringBuilder.appendValue(card: FitsHeaderCard): Int { val value = card.value if (card.isCommentStyle) { @@ -73,7 +73,7 @@ object HeaderCardFormatter { while (from < value.length) { pad() - append(Standard.CONTINUE.key + " ") + append(FitsKeywordDictionary.CONTINUE.key + " ") from += appendQuotedValue(card, from) } } else { @@ -84,7 +84,7 @@ object HeaderCardFormatter { } @JvmStatic - private fun StringBuilder.appendQuotedValue(card: HeaderCard, from: Int): Int { + private fun StringBuilder.appendQuotedValue(card: FitsHeaderCard, from: Int): Int { // Always leave room for an extra & character at the end... var available = availableCharCount() - QUOTES_LENGTH @@ -158,7 +158,7 @@ object HeaderCardFormatter { } @JvmStatic - private fun StringBuilder.appendLongStringComment(card: HeaderCard) { + private fun StringBuilder.appendLongStringComment(card: FitsHeaderCard) { // We can wrap the comment to our delight, with CONTINUE! val iLast = length - 1 val comment = card.comment @@ -182,7 +182,7 @@ object HeaderCardFormatter { if (available < COMMENT_PREFIX.length) { // Add a CONTINUE card with an empty string and try again... pad() - append(Standard.CONTINUE.key + " ''") + append(FitsKeywordDictionary.CONTINUE.key + " ''") appendComment(card) return } @@ -193,7 +193,7 @@ object HeaderCardFormatter { // Now add records as needed to write the comment fully... while (from < comment.length) { pad() - append(Standard.CONTINUE.key + " ") + append(FitsKeywordDictionary.CONTINUE.key + " ") append(if (comment.length >= from + MAX_LONG_END_COMMENT) "'&'" else "''") append(LONG_COMMENT_PREFIX) from += append(comment, from) @@ -202,16 +202,16 @@ object HeaderCardFormatter { @JvmStatic private fun StringBuilder.realign(at: Int, from: Int): Boolean { - return if (length >= HeaderCard.FITS_HEADER_CARD_SIZE || from >= Header.commentAlignPosition) { + return if (length >= FitsHeaderCard.FITS_HEADER_CARD_SIZE || from >= FitsHeader.commentAlignPosition) { // We are beyond the alignment point already... false } else { - realign(at, from, Header.commentAlignPosition) + realign(at, from, FitsHeader.commentAlignPosition) } } @JvmStatic - private fun StringBuilder.appendComment(card: HeaderCard): Boolean { + private fun StringBuilder.appendComment(card: FitsHeaderCard): Boolean { val comment = card.comment if (comment.isEmpty()) { @@ -307,18 +307,18 @@ object HeaderCardFormatter { @JvmStatic private fun StringBuilder.padTo(to: Int) { - for (pos in length % HeaderCard.FITS_HEADER_CARD_SIZE until to) { + for (pos in length % FitsHeaderCard.FITS_HEADER_CARD_SIZE until to) { append(' ') } } @JvmStatic private fun StringBuilder.availableCharCount(): Int { - return (HeaderCard.FITS_HEADER_CARD_SIZE - length % HeaderCard.FITS_HEADER_CARD_SIZE) % HeaderCard.FITS_HEADER_CARD_SIZE + return (FitsHeaderCard.FITS_HEADER_CARD_SIZE - length % FitsHeaderCard.FITS_HEADER_CARD_SIZE) % FitsHeaderCard.FITS_HEADER_CARD_SIZE } @JvmStatic - private fun HeaderCard.minTruncatedCommentSize(): Int { + private fun FitsHeaderCard.minTruncatedCommentSize(): Int { var firstWordLength = comment.indexOf(' ') if (firstWordLength < 0) { diff --git a/nebulosa-fits/src/main/kotlin/nebulosa/fits/HeaderCardParser.kt b/nebulosa-fits/src/main/kotlin/nebulosa/fits/FitsHeaderCardParser.kt similarity index 75% rename from nebulosa-fits/src/main/kotlin/nebulosa/fits/HeaderCardParser.kt rename to nebulosa-fits/src/main/kotlin/nebulosa/fits/FitsHeaderCardParser.kt index e3b6c2bba..9d40dd6c6 100644 --- a/nebulosa-fits/src/main/kotlin/nebulosa/fits/HeaderCardParser.kt +++ b/nebulosa-fits/src/main/kotlin/nebulosa/fits/FitsHeaderCardParser.kt @@ -1,27 +1,19 @@ package nebulosa.fits import nebulosa.log.loggerFor -import org.apache.commons.numbers.complex.Complex import java.math.BigDecimal import java.math.BigInteger import java.util.* import kotlin.math.min -internal class HeaderCardParser(private val line: CharSequence) { +internal data class FitsHeaderCardParser(private val line: CharSequence) { private var parsePos = 0 - var key = "" - private set - - var value = "" - private set - - var comment = "" - private set - - var type: Class<*> = Nothing::class.java - private set + @JvmField internal var key = "" + @JvmField internal var value = "" + @JvmField internal var comment = "" + @JvmField internal var type = FitsHeaderCardType.NONE init { parseKey() @@ -35,7 +27,7 @@ internal class HeaderCardParser(private val line: CharSequence) { // The stem is in the first 8 characters or what precedes an '=' character // before that. - var endStem = if (iEq >= 0 && iEq <= HeaderCard.MAX_KEYWORD_LENGTH) iEq else HeaderCard.MAX_KEYWORD_LENGTH + var endStem = if (iEq >= 0 && iEq <= FitsHeaderCard.MAX_KEYWORD_LENGTH) iEq else FitsHeaderCard.MAX_KEYWORD_LENGTH endStem = min(line.length.toDouble(), endStem.toDouble()).toInt() val rawStem = line.substring(0, endStem).trim { it <= ' ' } @@ -60,7 +52,7 @@ internal class HeaderCardParser(private val line: CharSequence) { // If the line does not have an '=', can only be a simple key // If it's not a HIERARCH keyword, then return the simple key. - if (iEq < 0 || stem != NonStandard.HIERARCH.key) { + if (iEq < 0 || stem != FitsKeywordDictionary.HIERARCH.key) { return } @@ -78,7 +70,7 @@ internal class HeaderCardParser(private val line: CharSequence) { } key = builder.toString() - if (NonStandard.HIERARCH.key == key) { + if (FitsKeywordDictionary.HIERARCH.key == key) { // The key is only HIERARCH, without a hierarchical keyword after it... LOG.warn("HIERARCH base keyword without HIERARCH-style long key after it.") return @@ -128,11 +120,11 @@ internal class HeaderCardParser(private val line: CharSequence) { return } - if (Standard.CONTINUE.key == key) { + if (FitsKeywordDictionary.CONTINUE.key == key) { parseValueBody() } else if (line[parsePos] == '=') { - if (parsePos < HeaderCard.MAX_KEYWORD_LENGTH) { - LOG.warn("[$key] assigmment before byte ${HeaderCard.MAX_KEYWORD_LENGTH + 1} for key '$key'.") + if (parsePos < FitsHeaderCard.MAX_KEYWORD_LENGTH) { + LOG.warn("[$key] assigmment before byte ${FitsHeaderCard.MAX_KEYWORD_LENGTH + 1} for key '$key'.") } if (parsePos + 1 >= line.length) { @@ -141,9 +133,9 @@ internal class HeaderCardParser(private val line: CharSequence) { LOG.warn("[$key] missing required standard space after '='.") } - if (parsePos > HeaderCard.MAX_KEYWORD_LENGTH) { + if (parsePos > FitsHeaderCard.MAX_KEYWORD_LENGTH) { // equal sign = after the 9th char -- only supported with hierarch keys... - if (!key.startsWith(NonStandard.HIERARCH.key + ".")) { + if (!key.startsWith(FitsKeywordDictionary.HIERARCH.key + ".")) { LOG.warn("[$key] possibly misplaced '=' (after byte 9).") // It's not a HIERARCH key return @@ -198,9 +190,9 @@ internal class HeaderCardParser(private val line: CharSequence) { } private fun parseStringValue() { - type = String::class.java + type = FitsHeaderCardType.TEXT - val buf = StringBuilder(HeaderCard.MAX_VALUE_LENGTH) + val buf = StringBuilder(FitsHeaderCard.MAX_VALUE_LENGTH) // Build the string value, up to the end quote and paying attention to double // quotes inside the string, which are translated to single quotes within @@ -226,16 +218,16 @@ internal class HeaderCardParser(private val line: CharSequence) { value = getNoTrailingSpaceString(buf) } - private fun getInferredValueType(key: String, value: String): Class<*> { + private fun getInferredValueType(key: String, value: String): FitsHeaderCardType { if (value.isEmpty()) { - LOG.warn("[$key] null non-string value (defaulted to Boolean.class).") - return Boolean::class.javaPrimitiveType!! + LOG.warn("[$key] null non-string value (defaulted to Boolean).") + return FitsHeaderCardType.BOOLEAN } val trimmedValue = value.trim().uppercase() if ("T" == trimmedValue || "F" == trimmedValue) { - return Boolean::class.javaPrimitiveType!! + return FitsHeaderCardType.BOOLEAN } if (INT_REGEX.matches(trimmedValue)) { return getIntegerType(trimmedValue) @@ -244,63 +236,55 @@ internal class HeaderCardParser(private val line: CharSequence) { return getDecimalType(trimmedValue) } if (COMPLEX_REGEX.matches(trimmedValue)) { - return Complex::class.java + return FitsHeaderCardType.COMPLEX } LOG.warn("[$key] unrecognised non-string value type '$trimmedValue'.") - return Nothing::class.java + return FitsHeaderCardType.NONE } - private fun getDecimalType(value: String): Class { - var transformedValue = value.uppercase() - val hasD = (transformedValue.indexOf('D') >= 0) - - if (hasD) { + private fun getDecimalType(value: String): FitsHeaderCardType { + val transformedValue = if ('D' in value) { // Convert the Double Scientific Notation specified by FITS to pure IEEE. - transformedValue = transformedValue.replace('D', 'E') + value.uppercase().replace('D', 'E') + } else { + value } val big = BigDecimal(transformedValue) // Check for zero, and deal with it separately... - if (big.stripTrailingZeros() == BigDecimal.ZERO) { + if (big.stripTrailingZeros().compareTo(BigDecimal.ZERO) == 0) { val decimals = big.scale() - if (decimals <= 7) { - return if (hasD) Double::class.javaPrimitiveType!! - else Float::class.javaPrimitiveType!! - } - - return if (decimals <= 16) Double::class.javaPrimitiveType!! - else BigDecimal::class.javaPrimitiveType!! + return if (decimals <= 16) FitsHeaderCardType.DECIMAL + else FitsHeaderCardType.BIG_DECIMAL } // Now non-zero values... val decimals = big.precision() - 1 val f = big.toFloat() - if ((decimals <= 7) && f != 0.0f && f.isFinite()) { - return if (hasD) Double::class.javaPrimitiveType!! - else Float::class.javaPrimitiveType!! + if (decimals <= 7 && f != 0.0f && f.isFinite()) { + return FitsHeaderCardType.DECIMAL } val d = big.toDouble() - return if ((decimals <= 16) && d != 0.0 && d.isFinite()) Double::class.javaPrimitiveType!! - else BigDecimal::class.java + return if (decimals <= 16 && d != 0.0 && d.isFinite()) FitsHeaderCardType.DECIMAL + else FitsHeaderCardType.BIG_DECIMAL } - private fun getIntegerType(value: String): Class { + private fun getIntegerType(value: String): FitsHeaderCardType { val bits = BigInteger(value).bitLength() - return if (bits < 32) Int::class.javaPrimitiveType!! - else return if (bits < 64) Long::class.javaPrimitiveType!! - else BigInteger::class.java + return if (bits < 64) FitsHeaderCardType.INTEGER + else FitsHeaderCardType.BIG_INTEGER } companion object { - @JvmStatic private val LOG = loggerFor() + @JvmStatic private val LOG = loggerFor() @JvmStatic private val DECIMAL_REGEX = Regex("[+-]?\\d+(\\.\\d*)?([dDeE][+-]?\\d+)?") @JvmStatic private val COMPLEX_REGEX = Regex("\\(\\s*$DECIMAL_REGEX\\s*,\\s*$DECIMAL_REGEX\\s*\\)") diff --git a/nebulosa-fits/src/main/kotlin/nebulosa/fits/FitsHeaderCardType.kt b/nebulosa-fits/src/main/kotlin/nebulosa/fits/FitsHeaderCardType.kt new file mode 100644 index 000000000..a5f320ac0 --- /dev/null +++ b/nebulosa-fits/src/main/kotlin/nebulosa/fits/FitsHeaderCardType.kt @@ -0,0 +1,16 @@ +package nebulosa.fits + +import org.apache.commons.numbers.complex.Complex +import java.math.BigDecimal +import java.math.BigInteger + +enum class FitsHeaderCardType(@JvmField val type: Class<*>) { + NONE(Nothing::class.javaObjectType), + TEXT(String::class.javaObjectType), + BOOLEAN(Boolean::class.javaObjectType), + INTEGER(Long::class.javaObjectType), + BIG_INTEGER(BigInteger::class.java), + DECIMAL(Double::class.java), + BIG_DECIMAL(BigDecimal::class.java), + COMPLEX(Complex::class.java), +} diff --git a/nebulosa-fits/src/main/kotlin/nebulosa/fits/FitsHelper.kt b/nebulosa-fits/src/main/kotlin/nebulosa/fits/FitsHelper.kt index d7b8b660d..307886eb8 100644 --- a/nebulosa-fits/src/main/kotlin/nebulosa/fits/FitsHelper.kt +++ b/nebulosa-fits/src/main/kotlin/nebulosa/fits/FitsHelper.kt @@ -2,6 +2,7 @@ package nebulosa.fits +import nebulosa.image.format.ReadableHeader import nebulosa.io.SeekableSource import nebulosa.math.Angle import nebulosa.math.deg @@ -10,72 +11,70 @@ import java.nio.file.Path import java.time.Duration import java.time.LocalDateTime -inline fun Header.clone() = Header(this) +inline val ReadableHeader.naxis + get() = getInt(FitsKeywordDictionary.NAXIS, -1) -inline val Header.naxis - get() = getInt(Standard.NAXIS, -1) +inline fun ReadableHeader.naxis(n: Int) = getInt(FitsKeywordDictionary.NAXISn.n(n), 0) -inline fun Header.naxis(n: Int) = getInt(Standard.NAXISn.n(n), 0) +inline val ReadableHeader.width + get() = getInt(FitsKeywordDictionary.NAXIS1, 0) -inline val Header.width - get() = getInt(Standard.NAXIS1, 0) +inline val ReadableHeader.height + get() = getInt(FitsKeywordDictionary.NAXIS2, 0) -inline val Header.height - get() = getInt(Standard.NAXIS2, 0) +val ReadableHeader.rightAscension + get() = Angle(getStringOrNull(FitsKeywordDictionary.RA), isHours = true, decimalIsHours = false).takeIf { it.isFinite() } + ?: Angle(getStringOrNull(FitsKeywordDictionary.OBJCTRA), true).takeIf { it.isFinite() } + ?: getDouble(FitsKeywordDictionary.CRVAL1, Double.NaN).deg -val Header.rightAscension - get() = Angle(getStringOrNull(Standard.RA), isHours = true, decimalIsHours = false).takeIf { it.isFinite() } - ?: Angle(getStringOrNull(SBFitsExt.OBJCTRA), true).takeIf { it.isFinite() } - ?: getDouble(NOAOExt.CRVAL1, Double.NaN).deg +val ReadableHeader.declination + get() = Angle(getStringOrNull(FitsKeywordDictionary.DEC)).takeIf { it.isFinite() } + ?: Angle(getStringOrNull(FitsKeywordDictionary.OBJCTDEC)).takeIf { it.isFinite() } + ?: getDouble(FitsKeywordDictionary.CRVAL2, Double.NaN).deg -val Header.declination - get() = Angle(getStringOrNull(Standard.DEC)).takeIf { it.isFinite() } - ?: Angle(getStringOrNull(SBFitsExt.OBJCTDEC)).takeIf { it.isFinite() } - ?: getDouble(NOAOExt.CRVAL2, Double.NaN).deg +inline val ReadableHeader.binX + get() = getInt(FitsKeywordDictionary.XBINNING, 1) -inline val Header.binX - get() = getInt(SBFitsExt.XBINNING, 1) +inline val ReadableHeader.binY + get() = getIntOrNull(FitsKeywordDictionary.YBINNING) ?: binX -inline val Header.binY - get() = getIntOrNull(SBFitsExt.YBINNING) ?: binX +inline val ReadableHeader.exposureTimeInSeconds + get() = getDoubleOrNull(FitsKeywordDictionary.EXPTIME) ?: getDouble(FitsKeywordDictionary.EXPOSURE, 0.0) -inline val Header.exposureTimeInSeconds - get() = getDoubleOrNull(Standard.EXPTIME) ?: getDouble(Standard.EXPOSURE, 0.0) - -inline val Header.exposureTime: Duration +inline val ReadableHeader.exposureTime: Duration get() = Duration.ofNanos((exposureTimeInSeconds * 1000000000.0).toLong()) -inline val Header.exposureTimeInMicroseconds +inline val ReadableHeader.exposureTimeInMicroseconds get() = (exposureTimeInSeconds * 1000000.0).toLong() const val INVALID_TEMPERATURE = 999.0 -inline val Header.temperature - get() = getDoubleOrNull(NOAOExt.CCDTEM) ?: getDouble(SBFitsExt.CCD_TEMP, INVALID_TEMPERATURE) +inline val ReadableHeader.temperature + get() = getDoubleOrNull(FitsKeywordDictionary.CCDTEM) ?: getDouble(FitsKeywordDictionary.CCD_TEMP, INVALID_TEMPERATURE) -inline val Header.gain - get() = getDouble(NOAOExt.GAIN, 0.0) +inline val ReadableHeader.gain + get() = getDouble(FitsKeywordDictionary.GAIN, 0.0) -inline val Header.latitude - get() = (getDoubleOrNull(SBFitsExt.SITELAT)?.deg ?: getDoubleOrNull("LAT-OBS"))?.deg +inline val ReadableHeader.latitude + get() = (getDoubleOrNull(FitsKeywordDictionary.SITELAT)?.deg ?: getDoubleOrNull("LAT-OBS"))?.deg -inline val Header.longitude - get() = (getDoubleOrNull(SBFitsExt.SITELONG)?.deg ?: getDoubleOrNull("LONG-OBS"))?.deg +inline val ReadableHeader.longitude + get() = (getDoubleOrNull(FitsKeywordDictionary.SITELONG)?.deg ?: getDoubleOrNull("LONG-OBS"))?.deg -inline val Header.observationDate - get() = getStringOrNull(Standard.DATE_OBS)?.let(LocalDateTime::parse) +inline val ReadableHeader.observationDate + get() = getStringOrNull(FitsKeywordDictionary.DATE_OBS)?.let(LocalDateTime::parse) -inline val Header.cfaPattern - get() = getStringOrNull(MaxImDLExt.BAYERPAT)?.ifBlank { null }?.trim() +inline val ReadableHeader.cfaPattern + get() = getStringOrNull(FitsKeywordDictionary.BAYERPAT)?.ifBlank { null }?.trim() -inline val Header.filter - get() = getStringOrNull(Standard.FILTER)?.ifBlank { null }?.trim() +inline val ReadableHeader.filter + get() = getStringOrNull(FitsKeywordDictionary.FILTER)?.ifBlank { null }?.trim() -inline val Header.frame - get() = (getStringOrNull("FRAME") ?: getStringOrNull(SBFitsExt.IMAGETYP))?.ifBlank { null }?.trim() +inline val ReadableHeader.frame + get() = (getStringOrNull("FRAME") ?: getStringOrNull(FitsKeywordDictionary.IMAGETYP))?.ifBlank { null }?.trim() -inline val Header.instrument - get() = getStringOrNull(Standard.INSTRUME)?.ifBlank { null }?.trim() +inline val ReadableHeader.instrument + get() = getStringOrNull(FitsKeywordDictionary.INSTRUME)?.ifBlank { null }?.trim() inline fun SeekableSource.fits() = Fits().also { it.read(this) } diff --git a/nebulosa-fits/src/main/kotlin/nebulosa/fits/FitsIO.kt b/nebulosa-fits/src/main/kotlin/nebulosa/fits/FitsIO.kt index d0c951efe..010eb4bdc 100644 --- a/nebulosa-fits/src/main/kotlin/nebulosa/fits/FitsIO.kt +++ b/nebulosa-fits/src/main/kotlin/nebulosa/fits/FitsIO.kt @@ -7,7 +7,7 @@ import java.io.IOException object FitsIO : FitsReader, FitsWriter { override fun read(source: SeekableSource): Hdu<*> { - val header = Header.from(source) + val header = FitsHeader.from(source) val hdu = when { ImageHdu.isValid(header) -> ImageHdu(header) diff --git a/nebulosa-fits/src/main/kotlin/nebulosa/fits/FitsKeyword.kt b/nebulosa-fits/src/main/kotlin/nebulosa/fits/FitsKeyword.kt new file mode 100644 index 000000000..b43a99c2a --- /dev/null +++ b/nebulosa-fits/src/main/kotlin/nebulosa/fits/FitsKeyword.kt @@ -0,0 +1,15 @@ +package nebulosa.fits + +import nebulosa.image.format.HeaderKey + +interface FitsKeyword : HeaderKey { + + val hduType: HduType + + val valueType: ValueType + + fun n(vararg numbers: Int): FitsKeyword + + val isCommentStyle + get() = valueType == ValueType.NONE || key.isBlank() +} diff --git a/nebulosa-fits/src/main/kotlin/nebulosa/fits/NOAOExt.kt b/nebulosa-fits/src/main/kotlin/nebulosa/fits/FitsKeywordDictionary.kt similarity index 65% rename from nebulosa-fits/src/main/kotlin/nebulosa/fits/NOAOExt.kt rename to nebulosa-fits/src/main/kotlin/nebulosa/fits/FitsKeywordDictionary.kt index 37b18604a..caa1055eb 100644 --- a/nebulosa-fits/src/main/kotlin/nebulosa/fits/NOAOExt.kt +++ b/nebulosa-fits/src/main/kotlin/nebulosa/fits/FitsKeywordDictionary.kt @@ -1,13 +1,951 @@ package nebulosa.fits -/** - * This keyword dictionary defines keywords which may be used in image data recorded by the data acquisition system. It - * currently does not consider keywords for data processing. Most of the keywords defined here will not be used. New - * parameters must be added to the logical class heirarchy and then a keyword defined in this dictionary before use in - * image data. - */ @Suppress("EnumEntryName") -enum class NOAOExt : FitsHeader { +enum class FitsKeywordDictionary : FitsKeyword { + + // Standard. + // https://github.com/nom-tam-fits/nom-tam-fits/blob/master/src/main/java/nom/tam/fits/header/Standard.java + // https://github.com/nom-tam-fits/nom-tam-fits/blob/master/src/main/java/nom/tam/fits/header/ObservationDescription.java + // https://github.com/nom-tam-fits/nom-tam-fits/blob/master/src/main/java/nom/tam/fits/header/ObservationDurationDescription.java + + /** + * The value field shall contain a character string identifying who compiled the information in the data associated + * with the key. This keyword is appropriate when the data originate in a published paper or are compiled from many + * sources. + */ + AUTHOR(HduType.ANY, ValueType.STRING, "author of the data"), + + /** + * The value field shall contain an integer. The absolute value is used in computing the sizes of data structures. + * It shall specify the number of bits that represent a data value. RANGE: -64,-32,8,16,32 + */ + BITPIX(HduType.ANY, ValueType.INTEGER, "bits per data value"), + + /** + * This keyword shall be used only in primary array headers or IMAGE extension headers with positive values of + * BITPIX (i.e., in arrays with integer data). Columns 1-8 contain the string, `BLANK ' (ASCII blanks in columns + * 6-8). The value field shall contain an integer that specifies the representation of array values whose physical + * values are undefined. + */ + BLANK(HduType.IMAGE, ValueType.INTEGER, "value used for undefined array elements"), + + /** + * Columns 1-8 contain ASCII blanks. This keyword has no associated value. Columns 9-80 may contain any ASCII text. + * Any number of card images with blank keyword fields may appear in a key. + */ + BLANKS(" ", HduType.ANY, ValueType.NONE, ""), + + /** + * This keyword may be used only in the primary key. It shall appear within the first 36 card images of the FITS + * file. (Note: This keyword thus cannot appear if NAXIS is greater than 31, or if NAXIS is greater than 30 and the + * EXTEND keyword is present.) Its presence with the required logical value of T advises that the physical block + * size of the FITS file on which it appears may be an integral multiple of the logical record length, and not + * necessarily equal to it. Physical block size and logical record length may be equal even if this keyword is + * present or unequal if it is absent. It is reserved primarily to prevent its use with other meanings. Since the + * issuance of version 1 of the standard, the BLOCKED keyword has been deprecated. + */ + @Deprecated("no blocksize other that 2880 may be used") + BLOCKED(HduType.PRIMARY, ValueType.LOGICAL, "is physical blocksize a multiple of 2880?"), + + /** + * This keyword shall be used, along with the BZERO keyword, when the array pixel values are not the true physical + * values, to transform the primary data array values to the true physical values they represent, using the + * equation: physical_value = BZERO + BSCALE * array_value. The value field shall contain a floating point number + * representing the coefficient of the linear term in the scaling equation, the ratio of physical value to array + * value at zero offset. The default value for this keyword is 1.0. + */ + BSCALE(HduType.IMAGE, ValueType.REAL, "linear factor in scaling equation"), + + /** + * The value field shall contain a character string, describing the physical units in which the quantities in the + * array, after application of BSCALE and BZERO, are expressed. The units of all FITS key keyword values, with the + * exception of measurements of angles, should conform with the recommendations in the IAU Style Manual. For angular + * measurements given as floating point values and specified with reserved keywords, degrees are the recommended + * units (with the units, if specified, given as 'deg'). + */ + BUNIT(HduType.IMAGE, ValueType.STRING, "physical units of the array values"), + + /** + * This keyword shall be used, along with the BSCALE keyword, when the array pixel values are not the true physical + * values, to transform the primary data array values to the true values using the equation: physical_value = BZERO + * + BSCALE * array_value. The value field shall contain a floating point number representing the physical value + * corresponding to an array value of zero. The default value for this keyword is 0.0. + */ + BZERO(HduType.IMAGE, ValueType.REAL, "zero point in scaling equation"), + + /** + * The value field shall contain a floating point number giving the partial derivative of the coordinate specified + * by the CTYPEn keywords with respect to the pixel index, evaluated at the reference point CRPIXn, in units of the + * coordinate specified by the CTYPEn keyword. These units must follow the prescriptions of section 5.3 of the FITS + * Standard. + */ + CDELTn(HduType.IMAGE, ValueType.REAL, "coordinate increment along axis"), + + /** + * This keyword shall have no associated value; columns 9-80 may contain any ASCII text. Any number of COMMENT card + * images may appear in a key. + */ + COMMENT(HduType.ANY, ValueType.NONE, ""), + + /** + * The CONTINUE keyword, when followed by spaces in columns 9 and 10 of the card image and a character string + * enclosed in single quotes starting in column 11 or higher, indicates that the quoted string should be treated as + * a continuation of the character string value in the previous key keyword. To conform to this convention, the + * character string value on the previous keyword must end with the ampersand character ('&'), but the ampersand + * is not part of the value string and should be deleted before concatenating the strings together. The character + * string value may be continued on any number of consecutive CONTINUE keywords, thus effectively allowing + * arbitrarily long strings to be written as keyword values. + */ + CONTINUE(HduType.ANY, ValueType.NONE, "denotes the CONTINUE long string keyword convention"), + + /** + * This keyword is used to indicate a rotation from a standard coordinate system described by the CTYPEn to a + * different coordinate system in which the values in the array are actually expressed. Rules for such rotations are + * not further specified in the Standard; the rotation should be explained in comments. The value field shall + * contain a floating point number giving the rotation angle in degrees between axis n and the direction implied by + * the coordinate system defined by CTYPEn. In unit degrees. + */ + CROTAn(HduType.IMAGE, ValueType.REAL, "coordinate system rotation angle"), + + /** + * The value field shall contain a floating point number, identifying the location of a reference point along axis + * n, in units of the axis index. This value is based upon a counter that runs from 1 to NAXISn with an increment of + * 1 per pixel. The reference point value need not be that for the center of a pixel nor lie within the actual data + * array. Use comments to indicate the location of the index point relative to the pixel. + */ + CRPIXn(HduType.IMAGE, ValueType.REAL, "coordinate system reference pixel"), + + /** + * The value field shall contain a floating point number, giving the value of the coordinate specified by the CTYPEn + * keyword at the reference point CRPIXn. Units must follow the prescriptions of section 5.3 of the FITS Standard. + */ + CRVALn(HduType.IMAGE, ValueType.REAL, "coordinate system value at reference pixel"), + + /** + * The value field shall contain a character string, giving the name of the coordinate represented by axis n. + */ + CTYPEn(HduType.IMAGE, ValueType.STRING, "name of the coordinate axis"), + + /** + * The value field shall always contain a floating point number, regardless of the value of BITPIX. This number + * shall give the maximum valid physical value represented by the array, exclusive of any special values. + */ + DATAMAX(HduType.IMAGE, ValueType.REAL, "maximum data value"), + + /** + * The value field shall always contain a floating point number, regardless of the value of BITPIX. This number + * shall give the minimum valid physical value represented by the array, exclusive of any special values. + */ + DATAMIN(HduType.IMAGE, ValueType.REAL, "minimum data value"), + + /** + * The date on which the HDU was created, in the format specified in the FITS Standard. The old date format was + * 'yy/mm/dd' and may be used only for dates from 1900 through 1999. the new Y2K compliant date format is + * 'yyyy-mm-dd' or 'yyyy-mm-ddTHH:MM:SS[.sss]'. + */ + DATE(HduType.ANY, ValueType.STRING, "date of file creation"), + + /** + * The date of the observation, in the format specified in the FITS Standard. The old date format was 'yy/mm/dd' and + * may be used only for dates from 1900 through 1999. The new Y2K compliant date format is 'yyyy-mm-dd' or + * 'yyyy-mm-ddTHH:MM:SS[.sss]'. + */ + DATE_OBS("DATE-OBS", HduType.ANY, ValueType.STRING, "date of the observation"), + + /** + * This keyword has no associated value. Columns 9-80 shall be filled with ASCII blanks. + */ + END(HduType.ANY, ValueType.NONE, ""), + + /** + * The value field shall contain a floating point number giving the equinox in years for the celestial coordinate + * system in which positions are expressed. Starting with Version 1, the Standard has deprecated the use of the + * EPOCH keyword and thus it shall not be used in FITS files created after the adoption of the standard; rather, the + * EQUINOX keyword shall be used. + */ + @Deprecated("use EQUINOX instead") + EPOCH(HduType.ANY, ValueType.REAL, "equinox of celestial coordinate system"), + + /** + * The value field shall contain a floating point number giving the equinox in years for the celestial coordinate + * system in which positions are expressed. + */ + EQUINOX(HduType.ANY, ValueType.REAL, "equinox of celestial coordinate system"), + + /** + * If the FITS file may contain extensions, a card image with the keyword EXTEND and the value field containing the + * logical value T must appear in the primary key immediately after the last NAXISn card image, or, if NAXIS=0, the + * NAXIS card image. The presence of this keyword with the value T in the primary key does not require that + * extensions be present. + */ + EXTEND(HduType.PRIMARY, ValueType.LOGICAL, "may the FITS file contain extensions?"), + + /** + * The value field shall contain an integer, specifying the level in a hierarchy of extension levels of the + * extension key containing it. The value shall be 1 for the highest level; levels with a higher value of this + * keyword shall be subordinate to levels with a lower value. If the EXTLEVEL keyword is absent, the file should be + * treated as if the value were 1. This keyword is used to describe an extension and should not appear in the + * primary key.RANGE: [1:] DEFAULT: 1 + */ + EXTLEVEL(HduType.EXTENSION, ValueType.INTEGER, "hierarchical level of the extension"), + + /** + * The value field shall contain a character string, to be used to distinguish among different extensions of the + * same type, i.e., with the same value of XTENSION, in a FITS file. This keyword is used to describe an extension + * and should not appear in the primary key. + */ + EXTNAME(HduType.EXTENSION, ValueType.STRING, "name of the extension"), + + /** + * The value field shall contain an integer, to be used to distinguish among different extensions in a FITS file + * with the same type and name, i.e., the same values for XTENSION and EXTNAME. The values need not start with 1 for + * the first extension with a particular value of EXTNAME and need not be in sequence for subsequent values. If the + * EXTVER keyword is absent, the file should be treated as if the value were 1. This keyword is used to describe an + * extension and should not appear in the primary key.RANGE: [1:] DEFAULT: 1 + */ + EXTVER(HduType.EXTENSION, ValueType.INTEGER, "version of the extension"), + + /** + * The value field shall contain an integer that shall be used in any way appropriate to define the data structure, + * consistent with Eq. 5.2 in the FITS Standard. This keyword originated for use in FITS Random Groups where it + * specifies the number of random groups present. In most other cases this keyword will have the value 1. + */ + GCOUNT(HduType.EXTENSION, ValueType.INTEGER, "group count"), + + /** + * The value field shall contain the logical constant T. The value T associated with this keyword implies that + * random groups records are present. + */ + GROUPS(HduType.GROUPS, ValueType.LOGICAL, "indicates random groups structure"), + + /** + * This keyword shall have no associated value; columns 9-80 may contain any ASCII text. The text should contain a + * history of steps and procedures associated with the processing of the associated data. Any number of HISTORY card + * images may appear in a key. + */ + HISTORY(HduType.ANY, ValueType.NONE, "processing history of the data"), + + /** + * The value field shall contain a character string identifying the instrument used to acquire the data associated + * with the key. + */ + INSTRUME(HduType.ANY, ValueType.STRING, "name of instrument"), + + /** + * The value field shall contain a non-negative integer no greater than 999, representing the number of axes in the + * associated data array. A value of zero signifies that no data follow the key in the HduType. In the context of FITS + * 'TABLE' or 'BINTABLE' extensions, the value of NAXIS is always 2.RANGE: [0:999] + */ + NAXIS(HduType.ANY, ValueType.INTEGER, "number of axes"), + + /** + * The value field of this indexed keyword shall contain a non-negative integer, representing the number of elements + * along axis n of a data array. The NAXISn must be present for all values n = 1,...,NAXIS, and for no other values + * of n. A value of zero for any of the NAXISn signifies that no data follow the key in the HduType. If NAXIS is equal + * to 0, there should not be any NAXISn keywords.RANGE: [0:] + */ + NAXISn(HduType.ANY, ValueType.INTEGER, "size of the n'th axis"), + + /** + * The value field shall contain a character string giving a name for the object observed. + */ + OBJECT(HduType.ANY, ValueType.STRING, "name of observed object"), + + /** + * The value field shall contain a character string identifying who acquired the data associated with the key. + */ + OBSERVER(HduType.ANY, ValueType.STRING, "observer who acquired the data"), + + /** + * The value field shall contain a character string identifying the organization or institution responsible for + * creating the FITS file. + */ + ORIGIN(HduType.ANY, ValueType.STRING, "organization responsible for the data"), + + /** + * The value field shall contain an integer that shall be used in any way appropriate to define the data structure, + * consistent with Eq. 5.2 in the FITS Standard. This keyword was originated for use with FITS Random Groups and + * represented the number of parameters preceding each group. It has since been used in 'BINTABLE' extensions to + * represent the size of the data heap following the main data table. In most other cases its value will be zero. + */ + PCOUNT(HduType.EXTENSION, ValueType.INTEGER, "parameter count"), + + /** + * This keyword is reserved for use within the FITS Random Groups structure. This keyword shall be used, along with + * the PZEROn keyword, when the nth FITS group parameter value is not the true physical value, to transform the + * group parameter value to the true physical values it represents, using the equation, physical_value = PZEROn + + * PSCALn * group_parameter_value. The value field shall contain a floating point number representing the + * coefficient of the linear term, the scaling factor between true values and group parameter values at zero offset. + * The default value for this keyword is 1.0. + */ + PSCALn(HduType.GROUPS, ValueType.REAL, "parameter scaling factor"), + + /** + * This keyword is reserved for use within the FITS Random Groups structure. The value field shall contain a + * character string giving the name of parameter n. If the PTYPEn keywords for more than one value of n have the + * same associated name in the value field, then the data value for the parameter of that name is to be obtained by + * adding the derived data values of the corresponding parameters. This rule provides a mechanism by which a random + * parameter may have more precision than the accompanying data array elements; for example, by summing two 16-bit + * values with the first scaled relative to the other such that the sum forms a number of up to 32-bit precision. + */ + PTYPEn(HduType.GROUPS, ValueType.STRING, "name of random groups parameter"), + + /** + * This keyword is reserved for use within the FITS Random Groups structure. This keyword shall be used, along with + * the PSCALn keyword, when the nth FITS group parameter value is not the true physical value, to transform the + * group parameter value to the physical value. The value field shall contain a floating point number, representing + * the true value corresponding to a group parameter value of zero. The default value for this keyword is 0.0. The + * transformation equation is as follows: physical_value = PZEROn + PSCALn * group_parameter_value.DEFAULT: 0.0 + */ + PZEROn(HduType.GROUPS, ValueType.REAL, "parameter scaling zero point"), + + /** + * Coordinate reference frame of major/minor axes.If absent the default value is 'FK5'. + */ + RADESYS(HduType.ANY, ValueType.STRING, "Coordinate reference frame of major/minor axes."), + + /** + * Coordinate reference frame of major/minor axes. use RADESYS instead. + */ + @Deprecated("use RADESYS instead.") + RADECSYS(HduType.ANY, ValueType.STRING, "Coordinate reference frame of major/minor axes."), + + /** + * The value field shall contain a character string citing a reference where the data associated with the key are + * published. + */ + REFERENC(HduType.ANY, ValueType.STRING, "bibliographic reference"), + + /** + * The SIMPLE keyword is required to be the first keyword in the primary key of all FITS files. The value field + * shall contain a logical constant with the value T if the file conforms to the standard. This keyword is mandatory + * for the primary key and is not permitted in extension headers. A value of F signifies that the file does not + * conform to this standard. + */ + SIMPLE(HduType.PRIMARY, ValueType.LOGICAL, "does file conform to the Standard?"), + + /** + * The value field of this indexed keyword shall contain an integer specifying the column in which field n starts in + * an ASCII TABLE extension. The first column of a row is numbered 1.RANGE: [1:] + */ + TBCOLn(HduType.ASCII_TABLE, ValueType.INTEGER, "begining column number"), + + /** + * The value field of this indexed keyword shall contain a character string describing how to interpret the contents + * of field n as a multidimensional array, providing the number of dimensions and the length along each axis. The + * form of the value is not further specified by the Standard. A proposed convention is described in Appendix B.2 of + * the FITS Standard in which the value string has the format '(l,m,n...)' where l, m, n,... are the dimensions of + * the array. + */ + TDIMn(HduType.BINTABLE, ValueType.STRING, "dimensionality of the array "), + + /** + * The value field of this indexed keyword shall contain a character string describing the format recommended for + * the display of the contents of field n. If the table value has been scaled, the physical value shall be + * displayed. All elements in a field shall be displayed with a single, repeated format. For purposes of display, + * each byte of bit (type X) and byte (type B) arrays is treated as an unsigned integer. Arrays of type A may be + * terminated with a zero byte. Only the format codes in Table 8.6, discussed in section 8.3.4 of the FITS Standard, + * are permitted for encoding. The format codes must be specified in upper case. If the Bw.m, Ow.m, and Zw.m formats + * are not readily available to the reader, the Iw.m display format may be used instead, and if the ENw.d and ESw.d + * formats are not available, Ew.d may be used. The meaning of this keyword is not defined for fields of type P in + * the Standard but may be defined in conventions using such fields. + */ + TDISPn(HduType.TABLE, ValueType.STRING, "display format"), + + /** + * The value field shall contain a character string identifying the telescope used to acquire the data associated + * with the key. + */ + TELESCOP(HduType.ANY, ValueType.STRING, "name of telescope"), + + /** + * The value field shall contain a non-negative integer representing the number of fields in each row of a 'TABLE' + * or 'BINTABLE' extension. The maximum permissible value is 999. RANGE: [0:999] + */ + TFIELDS(HduType.TABLE, ValueType.INTEGER, "number of columns in the table"), + + /** + * The value field of this indexed keyword shall contain a character string describing the format in which field n + * is encoded in a 'TABLE' or 'BINTABLE' extension. + */ + TFORMn(HduType.TABLE, ValueType.STRING, "column data format"), + + /** + * The value field of this keyword shall contain an integer providing the separation, in bytes, between the start of + * the main data table and the start of a supplemental data area called the heap. The default value shall be the + * product of the values of NAXIS1 and NAXIS2. This keyword shall not be used if the value of PCOUNT is zero. A + * proposed application of this keyword is presented in Appendix B.1 of the FITS Standard. + */ + THEAP(HduType.BINTABLE, ValueType.INTEGER, "offset to starting data heap address"), + + /** + * In ASCII 'TABLE' extensions, the value field for this indexed keyword shall contain the character string that + * represents an undefined value for field n. The string is implicitly blank filled to the width of the field. In + * binary 'BINTABLE' table extensions, the value field for this indexed keyword shall contain the integer that + * represents an undefined value for field n of data type B, I, or J. The keyword may not be used in 'BINTABLE' + * extensions if field n is of any other data type. + */ + TNULLn(HduType.TABLE, ValueType.STRING, "value used to indicate undefined table element"), + + /** + * This indexed keyword shall be used, along with the TZEROn keyword, when the quantity in field n does not + * represent a true physical quantity. The value field shall contain a floating point number representing the + * coefficient of the linear term in the equation, physical_value = TZEROn + TSCALn * field_value, which must be + * used to compute the true physical value of the field, or, in the case of the complex data types C and M, of the + * real part of the field with the imaginary part of the scaling factor set to zero. The default value for this + * keyword is 1.0. This keyword may not be used if the format of field n is A, L, or X.DEFAULT: 1.0 + */ + TSCALn(HduType.TABLE, ValueType.REAL, "linear data scaling factor"), + + /** + * The value field for this indexed keyword shall contain a character string, giving the name of field n. It is + * recommended that only letters, digits, and underscore (hexadecimal code 5F, ('_') be used in the name. String + * comparisons with the values of TTYPEn keywords should not be case sensitive. The use of identical names for + * different fields should be avoided. + */ + TTYPEn(HduType.TABLE, ValueType.STRING, "column name"), + + /** + * The value field shall contain a character string describing the physical units in which the quantity in field n, + * after any application of TSCALn and TZEROn, is expressed. The units of all FITS key keyword values, with the + * exception of measurements of angles, should conform with the recommendations in the IAU Style Manual. For angular + * measurements given as floating point values and specified with reserved keywords, degrees are the recommended + * units (with the units, if specified, given as 'deg'). + */ + TUNITn(HduType.TABLE, ValueType.STRING, "column units"), + + /** + * This indexed keyword shall be used, along with the TSCALn keyword, when the quantity in field n does not + * represent a true physical quantity. The value field shall contain a floating point number representing the true + * physical value corresponding to a value of zero in field n of the FITS file, or, in the case of the complex data + * types C and M, in the real part of the field, with the imaginary part set to zero. The default value for this + * keyword is 0.0. This keyword may not be used if the format of field n is A, L, or X.DEFAULT: 0.0 + */ + TZEROn(HduType.TABLE, ValueType.REAL, "column scaling zero point"), + + /** + * The value field shall contain a character string giving the name of the extension type. This keyword is mandatory + * for an extension key and must not appear in the primary key. For an extension that is not a standard extension, + * the type name must not be the same as that of a standard extension. + */ + XTENSION(HduType.EXTENSION, ValueType.STRING, "marks beginning of new HDU"), + + // FITS keywords that have been widely used within the astronomical community. + // These are the Keywords that describe the observation. + + /** + * The value field shall contain a floating point number giving the air mass during the observation by a ground + * based telescope. The value of the airmass is often approximated by the secant of the elevation angle and has a + * value of 1.0 at the zenith and increases towards the horizon. This value is assumed to correspond to the start of + * the observation unless another interpretation is clearly explained in the comment field. + */ + AIRMASS(HduType.ANY, ValueType.REAL, "air mass"), + + /** + * The value field gives the declination of the observation. It may be expressed either as a floating point number + * in units of decimal degrees, or as a character string in 'dd:mm:ss.sss' format where the decimal point and number + * of fractional digits are optional. The coordinate reference frame is given by the RADECSYS keyword, and the + * coordinate epoch is given by the EQUINOX keyword. Example: -47.25944 or '-47:15:34.00'. + */ + DEC(HduType.ANY, ValueType.STRING, "declination of the observed object"), + + /** + * The value field shall contain a floating point number giving the nominal declination of the pointing direction in + * units of decimal degrees. The coordinate reference frame is given by the RADECSYS keyword, and the coordinate + * epoch is given by the EQUINOX keyword. The precise definition of this keyword is instrument-specific, but + * typically the nominal direction corresponds to the direction to which the instrument was requested to point. The + * DEC_PNT keyword should be used to give the actual pointed direction. + */ + DEC_NOM(HduType.ANY, ValueType.REAL, "nominal declination of the observation"), + + /** + * The value field shall contain a floating point number giving the declination of the observed object in units of + * decimal degrees. The coordinate reference frame is given by the RADECSYS keyword, and the coordinate epoch is + * given by the EQUINOX keyword. + */ + DEC_OBJ(HduType.ANY, ValueType.REAL, "declination of the observed object"), + + /** + * The value field shall contain a floating point number giving the declination of the pointing direction in units + * of decimal degrees. The coordinate reference frame is given by the RADECSYS keyword, and the coordinate epoch is + * given by the EQUINOX keyword. The precise definition of this keyword is instrument-specific, but typically the + * pointed direction corresponds to the optical axis of the instrument. This keyword gives a mean value in cases + * where the pointing axis was not fixed during the entire observation. + */ + DEC_PNT(HduType.ANY, ValueType.REAL, "declination of the pointed direction of the instrument"), + + /** + * The value field shall contain a floating point number giving the declination of the space craft (or telescope + * platform) X axis during the observation in decimal degrees. The coordinate reference frame is given by the + * RADECSYS keyword, and the coordinate epoch is given by the EQUINOX keyword. This keyword gives a mean value in + * cases where the axis was not fixed during the entire observation. + */ + DEC_SCX(HduType.ANY, ValueType.REAL, "declination of the X spacecraft axis"), + + /** + * The value field shall contain a floating point number giving the declination of the space craft (or telescope + * platform) Z axis during the observation in decimal degrees. The coordinate reference frame is given by the + * RADECSYS keyword, and the coordinate epoch is given by the EQUINOX keyword. This keyword gives a mean value in + * cases where the axis was not fixed during the entire observation. + */ + DEC_SCZ(HduType.ANY, ValueType.REAL, "declination of the Z spacecraft axis"), + + /** + * The value field shall contain a floating point number giving the geographic latitude from which the observation + * was made in units of degrees. + */ + LATITUDE(HduType.ANY, ValueType.REAL, "geographic latitude of the observation"), + + /** + * The value field shall contain a floating point number giving the angle between the direction of the observation + * (e.g., the optical axis of the telescope or the position of the target) and the moon, measured in degrees. + */ + MOONANGL(HduType.ANY, ValueType.REAL, "angle between the observation and the moon"), + + /** + * The value field shall contain a character string giving a name for the observed object that conforms to the IAU + * astronomical object naming conventions. The value of this keyword is more strictly constrained than for the + * standard OBJECT keyword which in practice has often been used to record other ancillary information about the + * observation (e.g. filter, exposure time, weather conditions, etc.). + */ + OBJNAME(HduType.ANY, ValueType.STRING, "AU name of observed object"), + + /** + * The value field shall contain a character string which uniquely identifies the dataset contained in the FITS + * file. This is typically a sequence number that can contain a mixture of numerical and character values. Example: + * '10315-01-01-30A' + */ + OBS_ID(HduType.ANY, ValueType.STRING, "unique observation ID"), + + /** + * The value field shall contain a floating point number giving the position angle of the y axis of the detector + * projected on the sky, in degrees east of north. This keyword is synonymous with the CROTA2 WCS keyword. + */ + ORIENTAT(HduType.IMAGE, ValueType.REAL, "position angle of image y axis (deg. E of N)"), + + /** + * The value field shall contain a floating point number giving the position angle of the relevant aspect of + * telescope pointing axis and/or instrument on the sky in units of degrees east of north. It commonly applies to + * the orientation of a slit mask. + */ + PA_PNT(HduType.ANY, ValueType.REAL, "position angle of the pointing"), + + /** + * The value field gives the Right Ascension of the observation. It may be expressed either as a floating point + * number in units of decimal degrees, or as a character string in 'HH:MM:SS.sss' format where the decimal point and + * number of fractional digits are optional. The coordinate reference frame is given by the RADECSYS keyword, and + * the coordinate epoch is given by the EQUINOX keyword. Example: 180.6904 or '12:02:45.7'. + */ + RA(HduType.ANY, ValueType.STRING, "R.A. of the observation"), + + /** + * The value field shall contain a floating point number giving the nominal Right Ascension of the pointing + * direction in units of decimal degrees. The coordinate reference frame is given by the RADECSYS keyword, and the + * coordinate epoch is given by the EQUINOX keyword. The precise definition of this keyword is instrument-specific, + * but typically the nominal direction corresponds to the direction to which the instrument was requested to point. + * The RA_PNT keyword should be used to give the actual pointed direction. + */ + RA_NOM(HduType.ANY, ValueType.REAL, "nominal R.A. of the observation"), + + /** + * The value field shall contain a floating point number giving the Right Ascension of the observed object in units + * of decimal degrees. The coordinate reference frame is given by the RADECSYS keyword, and the coordinate epoch is + * given by the EQUINOX keyword. + */ + RA_OBJ(HduType.ANY, ValueType.REAL, "R.A. of the observed object"), + + /** + * The value field shall contain a floating point number giving the Right Ascension of the pointing direction in + * units of decimal degrees. The coordinate reference frame is given by the RADECSYS keyword, and the coordinate + * epoch is given by the EQUINOX keyword. The precise definition of this keyword is instrument-specific, but + * typically the pointed direction corresponds to the optical axis of the instrument. This keyword gives a mean + * value in cases where the pointing axis was not fixed during the entire observation. + */ + RA_PNT(HduType.ANY, ValueType.REAL, "R.A. of the pointed direction of the instrument"), + + /** + * The value field shall contain a floating point number giving the Right Ascension of the space craft (or telescope + * platform) X axis during the observation in decimal degrees. The coordinate reference frame is given by the + * RADECSYS keyword, and the coordinate epoch is given by the EQUINOX keyword. This keyword gives a mean value in + * cases where the axis was not fixed during the entire observation. + */ + RA_SCX(HduType.ANY, ValueType.REAL, "R.A. of the X spacecraft axis"), + + /** + * The value field shall contain a floating point number giving the Right Ascension of the space craft (or telescope + * platform) Y axis during the observation in decimal degrees. The coordinate reference frame is given by the + * RADECSYS keyword, and the coordinate epoch is given by the EQUINOX keyword. This keyword gives a mean value in + * cases where the axis was not fixed during the entire observation. + */ + RA_SCY(HduType.ANY, ValueType.REAL, "R.A. of the Y spacecraft axis"), + + /** + * The value field shall contain a floating point number giving the Right Ascension of the space craft (or telescope + * platform) Z axis during the observation in decimal degrees. The coordinate reference frame is given by the + * RADECSYS keyword, and the coordinate epoch is given by the EQUINOX keyword. This keyword gives a mean value in + * cases where the axis was not fixed during the entire observation. + */ + RA_SCZ(HduType.ANY, ValueType.REAL, "R.A. of the Z spacecraft axis"), + + /** + * The value field shall contain a floating point number giving the angle between the direction of the observation + * (e.g., the optical axis of the telescope or the position of the target) and the sun, measured in degrees. + */ + SUNANGLE(HduType.ANY, ValueType.REAL, "angle between the observation and the sun"), + + // FITS keywords that have been widely used within the astronomical community. + // These are the Keywords that describe the instrument that took the data. + + /** + * The value field shall contain a character string which gives the name of the instrumental aperture though which + * the observation was made. This keyword is typically used in instruments which have a selection of apertures which + * restrict the field of view of the detector. + */ + APERTURE(HduType.ANY, ValueType.STRING, "name of field of view aperture"), + + /** + * The value field shall contain a character string which identifies the configuration or mode of the pre-processing + * software that operated on the raw instrumental data to generate the data that is recorded in the FITS file. + * Example: some X-ray satellite data may be recorded in 'BRIGHT', 'FAINT', or 'FAST' data mode. + */ + DATAMODE(HduType.ANY, ValueType.STRING, "pre-processor data mode"), + + /** + * The value field shall contain a character string giving the name of the detector within the instrument that was + * used to make the observation. Example: 'CCD1' + */ + DETNAM(HduType.ANY, ValueType.STRING, "name of the detector used to make the observation"), + + /** + * The value field shall contain a character string which gives the name of the filter that was used during the + * observation to select or modify the radiation that was transmitted to the detector. More than 1 filter may be + * listed by using the FILTERn indexed keyword. The value 'none' or 'NONE' indicates that no filter was used. + */ + FILTER(HduType.ANY, ValueType.STRING, "name of filter used during the observation"), + + /** + * The value field of this indexed keyword shall contain a character string which gives the name of one of multiple + * filters that were used during the observation to select or modify the radiation that was transmitted to the + * detector. The value 'none' or 'NONE' indicates that no filter was used. + */ + FILTERn(HduType.ANY, ValueType.STRING, "name of filters used during the observation"), + + /** + * The value field shall contain a character string which gives the name of the defraction grating that was used + * during the observation. More than 1 grating may be listed by using the GRATINGn indexed keyword. The value 'none' + * or 'NONE' indicates that no grating was used. + */ + GRATING(HduType.ANY, ValueType.STRING, "name of the grating used during the observation."), + + /** + * The value field of this indexed keyword shall contain a character string which gives the name of one of multiple + * defraction gratings that were used during the observation. The value 'none' or 'NONE' indicates that no grating + * was used. + */ + GRATINGn(HduType.ANY, ValueType.STRING, "name of gratings used during the observation."), + + /** + * The value field shall contain a character string which gives the observing mode of the observation. This is used + * in cases where the instrument or detector can be configured to operate in different modes which significantly + * affect the resulting data. Examples: 'SLEW', 'RASTER', or 'POINTING' + */ + OBS_MODE(HduType.ANY, ValueType.STRING, "instrumental mode of the observation"), + + /** + * The value field shall contain an integer giving the data value at which the detector becomes saturated. This + * keyword value may differ from the maximum value implied by the BITPIX in that more bits may be allocated in the + * FITS pixel values than the detector can accommodate. + */ + SATURATE(HduType.ANY, ValueType.INTEGER, "Data value at which saturation occurs"), + + // FITS keywords that have been widely used within the astronomical community. + // These are the Keywords that describe the observation. + + /** + * The value field shall contain a character string that gives the date on which the observation ended. This keyword + * has the same format, and is used in conjunction with, the standard DATA-OBS keyword that gives the starting date + * of the observation. These 2 keywords may give either the calendar date using the 'yyyy-mm-dd' format, or may give + * the full date and time using the 'yyyy-mm-ddThh:mm:ss.sss' format. + */ + DATE_END("DATE-END", HduType.ANY, ValueType.STRING, "date of the end of observation"), + + /** + * The value field shall contain a floating point number giving the difference between the stop and start times of + * the observation in units of seconds. This keyword is synonymous with the TELAPSE keyword. + */ + ELAPTIME(HduType.ANY, ValueType.REAL, "elapsed time of the observation"), + + /** + * The value field shall contain a floating point number giving the exposure time of the observation in units of + * seconds. The exact definition of 'exposure time' is mission dependent and may, for example, include corrections + * for shutter open and close duration, detector dead time, vignetting, or other effects. This keyword is synonymous + * with the EXPTIME keyword. + */ + EXPOSURE(HduType.ANY, ValueType.REAL, "exposure time"), + + /** + * The value field shall contain a floating point number giving the exposure time of the observation in units of + * seconds. The exact definition of 'exposure time' is mission dependent and may, for example, include corrections + * for shutter open and close duration, detector dead time, vignetting, or other effects. This keyword is synonymous + * with the EXPOSURE keyword. + */ + EXPTIME(HduType.ANY, ValueType.REAL, "exposure time"), + + /** + * The value field shall contain a floating point number giving the total integrated exposure time in units of + * seconds corrected for detector 'dead time' effects which reduce the net efficiency of the detector. The ratio of + * LIVETIME/ONTIME gives the mean dead time correction during the observation, which lies in the range 0.0 to 1.0. + */ + LIVETIME(HduType.ANY, ValueType.REAL, "exposure time after deadtime correction"), + + /** + * The value field shall contain a floating point number giving the total integrated exposure time of the + * observation in units of seconds. ONTIME may be less than TELAPSE if there were intevals during the observation in + * which the target was not observed (e.g., the shutter was closed, or the detector power was turned off). + */ + ONTIME(HduType.ANY, ValueType.REAL, "integration time during the observation"), + + /** + * The value field shall contain a floating point number giving the difference between the stop and start times of + * the observation in units of seconds. This keyword is synonymous with the ELAPTIME keyword. + */ + TELAPSE(HduType.ANY, ValueType.REAL, "elapsed time of the observation"), + + /** + * The value field shall contain a character string that gives the time at which the observation ended. This keyword + * is used in conjunction with the DATE-END keyword to give the ending time of the observation; the DATE-END keyword + * gives the ending calendar date, with format 'yyyy-mm-dd', and TIME-END gives the time within that day using the + * format 'hh:mm:ss.sss...'. This keyword should not be used if the time is included directly as part of the + * DATE-END keyword value with the format 'yyyy-mm-ddThh:mm:ss.sss'. + */ + TIME_END("TIME-END", HduType.ANY, ValueType.STRING, "time at the end of the observation"), + + /** + * The value field shall contain a character string that gives the time at which the observation started. This + * keyword is used in conjunction with the standard DATE-OBS keyword to give the starting time of the observation; + * the DATE-OBS keyword gives the starting calendar date, with format 'yyyy-mm-dd', and TIME-OBS gives the time + * within that day using the format 'hh:mm:ss.sss...'. This keyword should not be used if the time is included + * directly as part of the DATE-OBS keyword value with the format 'yyyy-mm-ddThh:mm:ss.sss'. + */ + TIME_OBS("TIME-OBS", HduType.ANY, ValueType.STRING, "time at the start of the observation"), + + // Maxim DL.Extension keywords that may be added or read by MaxIm DL. + // https://github.com/nom-tam-fits/nom-tam-fits/blob/master/src/main/java/nom/tam/fits/header/extra/MaxImDLExt.java + + /** + * if present the image has a valid Bayer color pattern. + */ + BAYERPAT(HduType.IMAGE, ValueType.REAL, "image Bayer color pattern"), + + /** + * Boltwood Cloud Sensor ambient temperature in degrees C. + */ + BOLTAMBT(HduType.IMAGE, ValueType.REAL, "ambient temperature in degrees C"), + + /** + * Boltwood Cloud Sensor cloud condition. + */ + BOLTCLOU(HduType.IMAGE, ValueType.REAL, "Boltwood Cloud Sensor cloud condition."), + + /** + * Boltwood Cloud Sensor daylight level. + */ + BOLTDAY(HduType.IMAGE, ValueType.REAL, "Boltwood Cloud Sensor daylight level."), + + /** + * Boltwood Cloud Sensor dewpoint in degrees C. + */ + BOLTDEW(HduType.IMAGE, ValueType.REAL, "Boltwood Cloud Sensor dewpoint in degrees C."), + + /** + * Boltwood Cloud Sensor humidity in percent. + */ + BOLTHUM(HduType.IMAGE, ValueType.REAL, "Boltwood Cloud Sensor humidity in percent."), + + /** + * Boltwood Cloud Sensor rain condition. + */ + BOLTRAIN(HduType.IMAGE, ValueType.REAL, "Boltwood Cloud Sensor rain condition."), + + /** + * Boltwood Cloud Sensor sky minus ambient temperature in degrees C. + */ + BOLTSKYT(HduType.IMAGE, ValueType.REAL, "Boltwood Cloud Sensor sky minus ambient temperature in degrees C."), + + /** + * Boltwood Cloud Sensor wind speed in km/h. + */ + BOLTWIND(HduType.IMAGE, ValueType.REAL, "Boltwood Cloud Sensor wind speed in km/h."), + + /** + * indicates calibration state of the image; B indicates bias corrected, D indicates dark corrected, F indicates + * flat corrected. + */ + CALSTAT(HduType.IMAGE, ValueType.REAL, "calibration state of the image"), + + /** + * type of color sensor Bayer array or zero for monochrome. + */ + COLORTYP(HduType.IMAGE, ValueType.REAL, "type of color sensor"), + + /** + * initial display screen stretch mode. + */ + CSTRETCH(HduType.IMAGE, ValueType.REAL, "initial display screen stretch mode"), + + /** + * Total dark time of the observation. This is the total time during which dark current is collected by the + * detector. If the times in the extension are different the primary HDU gives one of the extension times. + */ + DARKTIME(HduType.IMAGE, ValueType.REAL, "dark current integration time"), + + /** + * Davis Instruments Weather Station ambient temperature in deg C + */ + DAVAMBT(HduType.IMAGE, ValueType.REAL, "ambient temperature"), + + /** + * Davis Instruments Weather Station barometric pressure in hPa + */ + DAVBAROM(HduType.IMAGE, ValueType.REAL, "barometric pressure"), + + /** + * Davis Instruments Weather Station dewpoint in deg C + */ + DAVDEW(HduType.IMAGE, ValueType.REAL, "dewpoint in deg C"), + + /** + * Davis Instruments Weather Station humidity in percent + */ + DAVHUM(HduType.IMAGE, ValueType.REAL, "humidity in percent"), + + /** + * Davis Instruments Weather Station solar radiation in W/m^2 + */ + DAVRAD(HduType.IMAGE, ValueType.REAL, "solar radiation"), + + /** + * Davis Instruments Weather Station accumulated rainfall in mm/day + */ + DAVRAIN(HduType.IMAGE, ValueType.REAL, "accumulated rainfall"), + + /** + * Davis Instruments Weather Station wind speed in km/h + */ + DAVWIND(HduType.IMAGE, ValueType.REAL, "wind speed"), + + /** + * Davis Instruments Weather Station wind direction in deg + */ + DAVWINDD(HduType.IMAGE, ValueType.REAL, "wind direction"), + + /** + * status of pier flip for German Equatorial mounts. + */ + FLIPSTAT(HduType.IMAGE, ValueType.REAL, "status of pier flip"), + + /** + * Focuser position in steps, if focuser is connected. + */ + FOCUSPOS(HduType.IMAGE, ValueType.REAL, "Focuser position in steps"), + + /** + * Focuser step size in microns, if available. + */ + FOCUSSZ(HduType.IMAGE, ValueType.REAL, "Focuser step size in microns"), + + /** + * Focuser temperature readout in degrees C, if available. + */ + FOCUSTEM(HduType.IMAGE, ValueType.REAL, "Focuser temperature readout"), + + /** + * format of file from which image was read. + */ + INPUTFMT(HduType.IMAGE, ValueType.REAL, "format of file"), + + /** + * ISO camera setting, if camera uses ISO speeds. + */ + ISOSPEED(HduType.IMAGE, ValueType.REAL, "ISO camera setting"), + + /** + * records the geocentric Julian Day of the start of exposure. + */ + JD(HduType.IMAGE, ValueType.REAL, "geocentric Julian Day"), + + /** + * records the geocentric Julian Day of the start of exposure. + */ + JD_GEO(HduType.IMAGE, ValueType.REAL, "geocentric Julian Da"), + + /** + * records the Heliocentric Julian Date at the exposure midpoint. + */ + JD_HELIO(HduType.IMAGE, ValueType.REAL, "Heliocentric Julian Date"), + + /** + * records the Heliocentric Julian Date at the exposure midpoint. + */ + JD_HELIO2("JD-HELIO", HduType.IMAGE, ValueType.REAL, "Heliocentric Julian Date"), + + /** + * UT of midpoint of exposure. + */ + MIDPOINT(HduType.IMAGE, ValueType.REAL, "midpoint of exposure"), + + /** + * user-entered information; free-form notes. + */ + NOTES(HduType.IMAGE, ValueType.REAL, "free-form note"), + + /** + * nominal altitude of center of image + */ + OBJCTALT(HduType.IMAGE, ValueType.REAL, "altitude of center of image"), + + /** + * nominal azimuth of center of image + */ + OBJCTAZ(HduType.IMAGE, ValueType.REAL, "nominal azimuth of center of image"), + + /** + * nominal hour angle of center of image + */ + OBJCTHA(HduType.IMAGE, ValueType.REAL, "nominal hour angle of center of image"), + + /** + * indicates side-of-pier status when connected to a German Equatorial mount. + */ + PIERSIDE(HduType.IMAGE, ValueType.REAL, "side-of-pier status"), + + /** + * records the selected Readout Mode (if any) for the camera. + */ + READOUTM(HduType.IMAGE, ValueType.REAL, "Readout Mode for the camera"), + + /** + * Rotator angle in degrees, if focal plane rotator is connected. + */ + ROTATANG(HduType.IMAGE, ValueType.REAL, "Rotator angle in degrees"), + + /** + * indicates tile position within a mosaic. + */ + TILEXY(HduType.IMAGE, ValueType.REAL, "tile position within a mosaic"), + + /** + * X offset of Bayer array on imaging sensor. + */ + XBAYROFF(HduType.IMAGE, ValueType.REAL, "X offset of Bayer array"), + + /** + * Y offset of Bayer array on imaging sensor. + */ + YBAYROFF(HduType.IMAGE, ValueType.REAL, "Y offset of Bayer array"), + + // NOAO. https://github.com/nom-tam-fits/nom-tam-fits/blob/master/src/main/java/nom/tam/fits/header/extra/NOAOExt.java + ACTFREQ(HduType.PRIMARY, ValueType.NONE, ""), ACTHWV(HduType.PRIMARY, ValueType.STRING, ""), @@ -1240,12 +2178,6 @@ enum class NOAOExt : FitsHeader { */ CUNIT2(HduType.EXTENSION, ValueType.STRING, "Coordinate reference unit"), - /** - * Total dark time of the observation. This is the total time during which dark current is collected by the - * detector. If the times in the extension are different the primary HDU gives one of the extension times. - */ - DARKTIME(HduType.PRIMARY_EXTENSION, ValueType.REAL, "Dark time"), - /** * Mapping of the CCD section to image coordinates. */ @@ -3467,16 +4399,197 @@ enum class NOAOExt : FitsHeader { * Modified Julian date at the start of the exposure. The fractional part of the date is given to better than a * second of time. */ - MJD_OBS("MJD-OBS", HduType.PRIMARY_EXTENSION, ValueType.REAL, "MJD of exposure start"); + MJD_OBS("MJD-OBS", HduType.PRIMARY_EXTENSION, ValueType.REAL, "MJD of exposure start"), + + // SBIG. https://github.com/nom-tam-fits/nom-tam-fits/blob/master/src/main/java/nom/tam/fits/header/extra/SBFitsExt.java + + /** + * Aperture Area of the Telescope used in square millimeters. Note that we are specifying the area as well as the + * diameter because we want to be able to correct for any central obstruction. + */ + APTAREA(HduType.IMAGE, ValueType.REAL, "Aperture Area of the Telescope"), + + /** + * Aperture Diameter of the Telescope used in millimeters. + */ + APTDIA(HduType.IMAGE, ValueType.REAL, "Aperture Diameter of the Telescope"), + + /** + * Upon initial display of this image use this ADU level for the Black level. + */ + CBLACK(HduType.IMAGE, ValueType.INTEGER, "use this ADU level for the Black"), + + /** + * Temperature of CCD when exposure taken. + */ + CCD_TEMP("CCD-TEMP", HduType.IMAGE, ValueType.REAL, "Temperature of CCD"), + + /** + * Altitude in degrees of the center of the image in degrees. Format is the same as the OBJCTDEC keyword. + */ + CENTALT(HduType.IMAGE, ValueType.STRING, "Altitude of the center of the image"), + + /** + * Azimuth in degrees of the center of the image in degrees. Format is the same as the OBJCTDEC keyword. + */ + CENTAZ(HduType.IMAGE, ValueType.STRING, "Azimuth of the center of the image"), + + /** + * Upon initial display of this image use this ADU level as the White level. For the SBIG method of displaying + * images using Background and Range the following conversions would be used: Background = CBLACK Range = CWHITE - + * CBLACK. + */ + CWHITE(HduType.IMAGE, ValueType.INTEGER, "use this ADU level for the White"), + + /** + * Electronic gain in e-/ADU. + */ + EGAIN(HduType.IMAGE, ValueType.REAL, "Electronic gain in e-/ADU"), + /* + * Optional Keywords

The following Keywords are not defined in the FITS Standard but are defined in this + * Standard. They may or may not be included by AIP Software Packages adhering to this Standard. Any of these + * keywords read by an AIP Package must be preserved in files written.

+ */ + /** + * Focal Length of the Telescope used in millimeters. + */ + FOCALLEN(HduType.IMAGE, ValueType.REAL, "Focal Length of the Telescope"), + + /** + * This indicates the type of image and should be one of the following: Light Frame Dark Frame Bias Frame Flat + * Field. + */ + IMAGETYP(HduType.IMAGE, ValueType.STRING, "type of image"), + + /** + * This is the Declination of the center of the image in degrees. The format for this is ‘+25 12 34.111’ (SDD MM + * SS.SSS) using a space as the separator. For the sign, North is + and South is -. + */ + OBJCTDEC(HduType.IMAGE, ValueType.STRING, "Declination of the center of the image"), + + /** + * This is the Right Ascension of the center of the image in hours, minutes and secon ds. The format for this is ’12 + * 24 23.123’ (HH MM SS.SSS) using a space as the separator. + */ + OBJCTRA(HduType.IMAGE, ValueType.STRING, "Right Ascension of the center of the image"), + + /** + * Add this ADU count to each pixel value to get to a zero - based ADU. For example in SBIG images we add 100 ADU to + * each pixel to stop underflow at Zero ADU from noise. We would set PEDESTAL to - 100 in this case. + */ + PEDESTAL(HduType.IMAGE, ValueType.INTEGER, "ADU count to each pixel value to get to a zero"), + + /** + * This string indicates the version of this standard that the image was created to ie ‘SBFITSEXT Version 1.0’. + */ + SBSTDVER(HduType.IMAGE, ValueType.STRING, "version of this standard"), + + /** + * This is the setpoint of the cooling in degrees C. If it is not specified the setpoint is assumed to be the + */ + SET_TEMP("SET-TEMP", HduType.IMAGE, ValueType.REAL, "setpoint of the cooling in degrees C"), + + /** + * Latitude of the imaging location in degrees. Format is the same as the OBJCTDEC key word. + */ + SITELAT(HduType.IMAGE, ValueType.STRING, "Latitude of the imaging location"), + + /** + * Longitude of the imaging location in degrees. Format is the same as the OBJCTDEC keyword. + */ + SITELONG(HduType.IMAGE, ValueType.STRING, "Longitude of the imaging location"), + + /** + * Number of images combined to make this image as in Track and Accumulate or Co - Added images. + */ + SNAPSHOT(HduType.IMAGE, ValueType.INTEGER, "Number of images combined"), + + /** + * This indicates the name and version of the Software that initially created this file ie ‘SBIGs CCDOps Version + * 5.10’. + */ + SWCREATE(HduType.IMAGE, ValueType.STRING, "created version of the Software"), + + /** + * This indicates the name and version of the Software that modified this file ie ‘SBIGs CCDOps Version 5.10’ and + * the re can be multiple copies of this keyword. Only add this keyword if you actually modified the image and we + * suggest placing this above the HISTORY keywords corresponding to the modifications made to the image. + */ + SWMODIFY(HduType.IMAGE, ValueType.STRING, "modified version of the Software"), + + /** + * If the image was auto-guided this is the exposure time in seconds of the tracker used to acquire this image. If + * this keyword is not present then the image was unguided or hand guided. + */ + TRAKTIME(HduType.IMAGE, ValueType.REAL, "exposure time in seconds of the tracker"), + + /** + * Binning factor in width. + */ + XBINNING(HduType.IMAGE, ValueType.INTEGER, "Binning factor in width"), + + /** + * Sub frame X position of upper left pixel relative to whole frame in binned pixel units. + */ + XORGSUBF(HduType.IMAGE, ValueType.INTEGER, "Sub frame X position"), + + /** + * Pixel width in microns (after binning). + */ + XPIXSZ(HduType.IMAGE, ValueType.REAL, "Pixel width in microns"), + + /** + * Binning factor in height. + */ + YBINNING(HduType.IMAGE, ValueType.INTEGER, "Binning factor in height"), + + /** + * Sub frame Y position of upper left pixel relative to whole frame in binned pixel units. + */ + YORGSUBF(HduType.IMAGE, ValueType.INTEGER, "Sub frame Y position"), + + /** + * Pixel height in microns (after binning). + */ + YPIXSZ(HduType.IMAGE, ValueType.REAL, "Pixel height in microns"), + + // Non-Standard. https://github.com/nom-tam-fits/nom-tam-fits/blob/master/src/main/java/nom/tam/fits/header/NonStandard.java + + /** + * The HIERARCH keyword, when followed by spaces in columns 9 and 10 of the FITS card image, indicates that the ESO + * HIERARCH keyword convention should be used to interpret the name and value of the keyword. The HIERARCH keyword + * formally has no value because it is not followed by an equals sign in column 9. Under the HIERARCH convention the + * actual name of the keyword begins in column 11 of the card image and is terminated by the equal sign ('=') + * character. The name can contain any number of characters as long as it fits within columns 11 and 80 of the card + * image and also leaves enough space for the equal sign separator and the value field. The name can contain any + * printable ASCII text character, including spaces and lower-case characters, except for the equal sign character + * which serves as the terminator of the name field. Leading and trailing spaces in the name field are not + * significant, but embedded spaces within the name are significant. The value field follows the equals sign and + * must conform to the syntax for a free-format value field as defined in the FITS Standard. The value field may be + * null, in which case it contains only space characters, otherwise it may contain either a character string + * enclosed in single quotes, the logical constant T or F, an integer number, a floating point number, a complex + * integer number, or a complex floating point number. The value field may be followed by an optional comment + * string. The comment field must be separated from the value field by a slash character ('/'). It is recommended + * that the slash character be preceeded and followed by a space character. Example: "HIERARCH Filter Wheel = 12 / + * filter position". In this example the logical name of the keyword is 'Filter Wheel' and the value is 12. + */ + HIERARCH(HduType.ANY, ValueType.NONE, "denotes the HIERARCH keyword convention"), - private val header: FitsHeaderImpl + /** + * The presence of this keyword with a value = T in an extension key indicates that the keywords contained in the + * primary key (except the FITS Mandatory keywords, and any COMMENT, HISTORY or 'blank' keywords) are to be + * inherited, or logically included in that extension key. + */ + INHERIT(HduType.EXTENSION, ValueType.LOGICAL, "denotes the INHERIT keyword convention"); - constructor(key: String, hduType: HduType, valueType: ValueType, comment: String) { - header = FitsHeaderImpl(key, hduType, valueType, comment) + private val header: FitsKeyword + + constructor(name: String, hduType: HduType, valueType: ValueType, comment: String) { + header = FitsKeywordItem(name, hduType, valueType, comment) } constructor(hduType: HduType, valueType: ValueType, comment: String) { - header = FitsHeaderImpl(name, hduType, valueType, comment) + header = FitsKeywordItem(name, hduType, valueType, comment) } override val key @@ -3492,4 +4605,17 @@ enum class NOAOExt : FitsHeader { get() = header.valueType override fun n(vararg numbers: Int) = header.n(*numbers) + + companion object { + + @JvmStatic val NAXIS1 = NAXISn.n(1) + @JvmStatic val NAXIS2 = NAXISn.n(2) + @JvmStatic val NAXIS3 = NAXISn.n(3) + + @JvmStatic val CDELT1 = CDELTn.n(1) + @JvmStatic val CDELT2 = CDELTn.n(2) + + @JvmStatic val CROTA1 = CROTAn.n(1) + @JvmStatic val CROTA2 = CROTAn.n(2) + } } diff --git a/nebulosa-fits/src/main/kotlin/nebulosa/fits/FitsHeaderImpl.kt b/nebulosa-fits/src/main/kotlin/nebulosa/fits/FitsKeywordItem.kt similarity index 70% rename from nebulosa-fits/src/main/kotlin/nebulosa/fits/FitsHeaderImpl.kt rename to nebulosa-fits/src/main/kotlin/nebulosa/fits/FitsKeywordItem.kt index 494149080..dc2c1d91d 100644 --- a/nebulosa-fits/src/main/kotlin/nebulosa/fits/FitsHeaderImpl.kt +++ b/nebulosa-fits/src/main/kotlin/nebulosa/fits/FitsKeywordItem.kt @@ -1,13 +1,13 @@ package nebulosa.fits -data class FitsHeaderImpl( +data class FitsKeywordItem( override val key: String, override val hduType: HduType, override val valueType: ValueType, override val comment: String = "", -) : FitsHeader { +) : FitsKeyword { - override fun n(vararg numbers: Int): FitsHeader { + override fun n(vararg numbers: Int): FitsKeyword { if (numbers.isEmpty() || "n" !in key) return this val key = StringBuffer(key) @@ -17,6 +17,6 @@ data class FitsHeaderImpl( key.replace(idx, idx + 1, "$number") } - return FitsHeaderImpl("$key", hduType, valueType, comment) + return FitsKeywordItem("$key", hduType, valueType, comment) } } diff --git a/nebulosa-fits/src/main/kotlin/nebulosa/fits/FitsPath.kt b/nebulosa-fits/src/main/kotlin/nebulosa/fits/FitsPath.kt index 84d4d5704..e76bfa878 100644 --- a/nebulosa-fits/src/main/kotlin/nebulosa/fits/FitsPath.kt +++ b/nebulosa-fits/src/main/kotlin/nebulosa/fits/FitsPath.kt @@ -6,7 +6,7 @@ import java.io.Closeable import java.io.File import java.nio.file.Path -class FitsPath(path: Path) : Fits(), Closeable { +class FitsPath(val path: Path) : Fits(), Closeable { private val source = path.seekableSource() private val sink = path.seekableSink() diff --git a/nebulosa-fits/src/main/kotlin/nebulosa/fits/Hdu.kt b/nebulosa-fits/src/main/kotlin/nebulosa/fits/Hdu.kt index d5daeb787..23b14c2b5 100644 --- a/nebulosa-fits/src/main/kotlin/nebulosa/fits/Hdu.kt +++ b/nebulosa-fits/src/main/kotlin/nebulosa/fits/Hdu.kt @@ -1,10 +1,11 @@ package nebulosa.fits +import nebulosa.image.format.ReadableHeader import kotlin.math.max interface Hdu : FitsElement, Collection { - val header: Header + val header: ReadableHeader val data: Array diff --git a/nebulosa-fits/src/main/kotlin/nebulosa/fits/Header.kt b/nebulosa-fits/src/main/kotlin/nebulosa/fits/Header.kt deleted file mode 100644 index 0f5132f13..000000000 --- a/nebulosa-fits/src/main/kotlin/nebulosa/fits/Header.kt +++ /dev/null @@ -1,199 +0,0 @@ -package nebulosa.fits - -import nebulosa.io.SeekableSource -import nebulosa.io.source -import nebulosa.log.loggerFor -import okio.Buffer -import okio.Sink -import java.io.EOFException -import java.io.Serializable -import java.util.* - -open class Header internal constructor(@JvmField internal val cards: LinkedList) : - FitsElement, WritableHeader, ReadableHeader, Collection by cards, Serializable { - - constructor() : this(LinkedList()) - - constructor(cards: Collection) : this(LinkedList(cards)) - - constructor(header: Header) : this(LinkedList(header.cards)) - - open fun readOnly(): Header = ReadOnlyHeader(this) - - override fun clear() { - cards.clear() - } - - override fun read(source: SeekableSource) { - clear() - - var count = 0 - val buffer = Buffer() - - while (true) { - buffer.clear() - - if (source.read(buffer, 80L) != 80L) throw EOFException() - - val card = HeaderCard.from(buffer) - count++ - - if (cards.isEmpty()) { - require(isFirstCard(card.key)) { "Not a proper FITS header: ${card.key} at ${source.position - 80L} offset" } - } else if (card.isBlank) { - continue - } else if (card.key == Standard.END.key) { - break - } - - add(card) - } - - val skipBytes = Hdu.computeRemainingBytesToSkip(count * 80L) - if (skipBytes > 0L) source.skip(skipBytes) - - buffer.clear() - } - - override fun write(sink: Sink) { - val buffer = Buffer() - - for (card in cards) { - buffer.writeString(card.format().also { println(it) }, Charsets.US_ASCII) - } - - if (cards.last.key != "END") { - buffer.writeString(HeaderCard.END.format(), Charsets.US_ASCII) - } - - var remainingBytes = Hdu.computeRemainingBytesToSkip(buffer.size) - - while (remainingBytes-- > 0) { - buffer.writeByte(0) - } - - buffer.readAll(sink) - } - - override fun add(key: FitsHeader, value: Boolean): HeaderCard { - checkType(key, ValueType.LOGICAL) - return HeaderCard.create(key, value).also(::add) - } - - override fun add(key: String, value: Boolean, comment: String): HeaderCard { - return HeaderCard.create(key, value, comment).also(::add) - } - - override fun add(key: FitsHeader, value: Int): HeaderCard { - checkType(key, ValueType.INTEGER) - return HeaderCard.create(key, value).also(::add) - } - - override fun add(key: String, value: Int, comment: String): HeaderCard { - return HeaderCard.create(key, value, comment).also(::add) - } - - override fun add(key: FitsHeader, value: Double): HeaderCard { - checkType(key, ValueType.REAL) - return HeaderCard.create(key, value).also(::add) - } - - override fun add(key: String, value: Double, comment: String): HeaderCard { - return HeaderCard.create(key, value, comment).also(::add) - } - - override fun add(key: FitsHeader, value: String): HeaderCard { - checkType(key, ValueType.STRING) - return HeaderCard.create(key, value).also(::add) - } - - override fun add(key: String, value: String, comment: String): HeaderCard { - return HeaderCard.create(key, value, comment).also(::add) - } - - override fun add(card: HeaderCard) { - if (!card.isKeyValuePair) cards.add(card) - else { - val index = cards.indexOfFirst { it.key == card.key } - if (index >= 0) cards[index] = card - else cards.add(card) - } - } - - override fun delete(key: FitsHeader): Boolean { - return cards.removeIf { it.key == key.key } - } - - override fun equals(other: Any?): Boolean { - if (this === other) return true - if (other !is Header) return false - - if (cards != other.cards) return false - - return true - } - - override fun hashCode(): Int { - return cards.hashCode() - } - - override fun toString(): String { - return "Header(cards=$cards)" - } - - companion object { - - @JvmStatic val EMPTY: Header = ReadOnlyHeader() - - const val DEFAULT_COMMENT_ALIGN = 30 - const val MIN_COMMENT_ALIGN = 20 - const val MAX_COMMENT_ALIGN = 70 - - @JvmStatic private val LOG = loggerFor
() - - var commentAlignPosition = DEFAULT_COMMENT_ALIGN - set(value) { - require(value in MIN_COMMENT_ALIGN..MAX_COMMENT_ALIGN) - field = value - } - - @JvmStatic - fun from(source: SeekableSource): Header { - val header = Header() - header.read(source) - return header - } - - @JvmStatic - fun from(source: String): Header { - return from(source.toByteArray()) - } - - @JvmStatic - fun from(source: ByteArray): Header { - return from(source.source()) - } - - @JvmStatic - fun checkType(key: FitsHeader, type: ValueType): Boolean { - if (key.valueType == type || key.valueType == ValueType.ANY) { - return true - } - if (key.valueType == ValueType.COMPLEX && (type == ValueType.REAL || type == ValueType.INTEGER)) { - return true - } - if (key.valueType == ValueType.REAL && type == ValueType.INTEGER) { - return true - } - - LOG.warn("[${key.key}] with unexpected value type. Expected $type, got ${key.valueType}") - - return false - } - - @JvmStatic - fun isFirstCard(key: String): Boolean { - return Standard.SIMPLE.key == key || Standard.XTENSION.key == key - } - } -} diff --git a/nebulosa-fits/src/main/kotlin/nebulosa/fits/HeaderCard.kt b/nebulosa-fits/src/main/kotlin/nebulosa/fits/HeaderCard.kt deleted file mode 100644 index 27d5e392f..000000000 --- a/nebulosa-fits/src/main/kotlin/nebulosa/fits/HeaderCard.kt +++ /dev/null @@ -1,242 +0,0 @@ -package nebulosa.fits - -import nebulosa.log.loggerFor -import okio.Buffer -import org.apache.commons.numbers.complex.Complex -import java.io.Serializable -import java.math.BigDecimal -import java.math.BigInteger -import kotlin.math.max - -data class HeaderCard( - override val key: String, override val value: String, - val comment: String, val type: Class<*>, -) : Serializable, Map.Entry { - - internal constructor(parsed: HeaderCardParser) : this( - parsed.key, parsed.value, parsed.comment, parsed.type - ) - - val isCommentStyle - get() = type === Nothing::class.java - - val isKeyValuePair - get() = !isCommentStyle && key.isNotEmpty() - - val isBooleanType - get() = BOOLEAN_TYPES.any { it === type } - - val isStringType - get() = type === String::class.javaObjectType - - val isDecimalType - get() = DECIMAL_TYPES.any { it === type } - || BigDecimal::class.java.isAssignableFrom(type) - - val isIntegerType - get() = INTEGET_TYPES.any { it === type } - - val isNumericType - get() = isDecimalType || isIntegerType - - val isBlank - get() = if (!isCommentStyle || key.isNotBlank()) false else comment.isBlank() - - val hasHierarchKey - get() = isHierarchKey(key) - - private fun getBooleanValue(defaultValue: Boolean): Boolean { - return if (value == "T") true else if (value == "F") false else defaultValue - } - - inline fun getValue(defaultValue: T): T { - return getValue(T::class.java, defaultValue) - } - - fun getValue(asType: Class, defaultValue: T): T { - return if (isStringType) { - asType.cast(value) - } else if (value.isBlank()) { - defaultValue - } else if (isBooleanType) { - asType.cast(getBooleanValue(defaultValue as Boolean)) - } else if (Complex::class.java.isAssignableFrom(asType)) { - asType.cast(Complex.parse(value.trim().uppercase().replace('D', 'E'))) - } else if (isNumericType) { - try { - val decimal = BigDecimal(value.uppercase().replace('D', 'E')) - - if (Byte::class.javaObjectType.isAssignableFrom(asType)) { - asType.cast(decimal.toByte()) - } else if (Short::class.javaObjectType.isAssignableFrom(asType)) { - asType.cast(decimal.toShort()) - } else if (Int::class.javaObjectType.isAssignableFrom(asType)) { - asType.cast(decimal.toInt()) - } else if (Long::class.javaObjectType.isAssignableFrom(asType)) { - asType.cast(decimal.toLong()) - } else if (Float::class.javaObjectType.isAssignableFrom(asType)) { - asType.cast(decimal.toFloat()) - } else if (Double::class.javaObjectType.isAssignableFrom(asType)) { - asType.cast(decimal.toDouble()) - } else if (BigInteger::class.javaObjectType.isAssignableFrom(asType)) { - asType.cast(decimal.toBigInteger()) - } else if (String::class.javaObjectType.isAssignableFrom(asType)) { - asType.cast(decimal.toString()) - } else if (Boolean::class.javaObjectType.isAssignableFrom(asType)) { - asType.cast(decimal.toBigInteger().compareTo(BigInteger.ZERO) != 0) - } else { - asType.cast(decimal) - } - } catch (e: NumberFormatException) { - LOG.error("failed to parse numeric value", e) - defaultValue - } - } else { - throw IllegalArgumentException("unsupported class $asType") - } - } - - fun format(): String { - return HeaderCardFormatter.format(this) - } - - companion object { - - @JvmStatic private val LOG = loggerFor() - - const val FITS_HEADER_CARD_SIZE = 80 - const val MAX_KEYWORD_LENGTH = 8 - const val STRING_QUOTES_LENGTH = 2 - const val MAX_VALUE_LENGTH = 70 - const val MAX_COMMENT_CARD_COMMENT_LENGTH = MAX_VALUE_LENGTH + 1 - const val MAX_STRING_VALUE_LENGTH = MAX_VALUE_LENGTH - 2 - const val MAX_LONG_STRING_VALUE_LENGTH = MAX_STRING_VALUE_LENGTH - 1 - const val MAX_LONG_STRING_VALUE_WITH_COMMENT_LENGTH = MAX_LONG_STRING_VALUE_LENGTH - 2 - const val MAX_HIERARCH_KEYWORD_LENGTH = FITS_HEADER_CARD_SIZE - 6 - const val MAX_LONG_STRING_CONTINUE_OVERHEAD = 3 - const val MIN_VALID_CHAR = 0x20.toChar() - const val MAX_VALID_CHAR = 0x7e.toChar() - const val HIERARCH_WITH_DOT = "HIERARCH." - - @JvmStatic val END = HeaderCard("END", "", "", Any::class.java) - - @JvmStatic private val BOOLEAN_TYPES = arrayOf( - Boolean::class.javaPrimitiveType!!, Boolean::class.javaObjectType, - ) - - @JvmStatic private val DECIMAL_TYPES = arrayOf( - Float::class.javaPrimitiveType!!, Double::class.javaPrimitiveType!!, - Float::class.javaObjectType, Double::class.javaObjectType, - ) - - @JvmStatic private val INTEGET_TYPES = arrayOf( - Byte::class.javaPrimitiveType!!, Short::class.javaPrimitiveType!!, - Int::class.javaPrimitiveType!!, Long::class.javaPrimitiveType!!, - Byte::class.javaObjectType, Short::class.javaObjectType, - Int::class.javaObjectType, Long::class.javaObjectType, - ) - - @JvmStatic - fun from(source: Buffer): HeaderCard { - return from(source.readString(80L, Charsets.US_ASCII)) - } - - @JvmStatic - fun from(source: CharSequence): HeaderCard { - return HeaderCard(HeaderCardParser(source)) - } - - @JvmStatic - fun create(header: FitsHeader, value: Boolean): HeaderCard { - return HeaderCard(header.key, if (value) "T" else "F", header.comment, Boolean::class.javaPrimitiveType!!) - } - - @JvmStatic - fun create(header: FitsHeader, value: Int): HeaderCard { - return HeaderCard(header.key, "$value", header.comment, Int::class.javaPrimitiveType!!) - } - - @JvmStatic - fun create(header: FitsHeader, value: Long): HeaderCard { - return HeaderCard(header.key, "$value", header.comment, Long::class.javaPrimitiveType!!) - } - - @JvmStatic - fun create(header: FitsHeader, value: Float): HeaderCard { - return HeaderCard(header.key, "$value", header.comment, Float::class.javaPrimitiveType!!) - } - - @JvmStatic - fun create(header: FitsHeader, value: Double): HeaderCard { - return HeaderCard(header.key, "$value", header.comment, Double::class.javaPrimitiveType!!) - } - - @JvmStatic - fun create(header: FitsHeader, value: String): HeaderCard { - return HeaderCard(header.key, value, header.comment, String::class.javaObjectType) - } - - @JvmStatic - fun create(key: String, value: Boolean, comment: String = ""): HeaderCard { - return HeaderCard(key, if (value) "T" else "F", comment, Boolean::class.javaPrimitiveType!!) - } - - @JvmStatic - fun create(key: String, value: Int, comment: String = ""): HeaderCard { - return HeaderCard(key, "$value", comment, Int::class.javaPrimitiveType!!) - } - - @JvmStatic - fun create(key: String, value: Long, comment: String = ""): HeaderCard { - return HeaderCard(key, "$value", comment, Long::class.javaPrimitiveType!!) - } - - @JvmStatic - fun create(key: String, value: Float, comment: String = ""): HeaderCard { - return HeaderCard(key, "$value", comment, Float::class.javaPrimitiveType!!) - } - - @JvmStatic - fun create(key: String, value: Double, comment: String = ""): HeaderCard { - return HeaderCard(key, "$value", comment, Double::class.javaPrimitiveType!!) - } - - @JvmStatic - fun create(key: String, value: String, comment: String = ""): HeaderCard { - return HeaderCard(key, value, comment, String::class.javaObjectType) - } - - @JvmStatic - internal fun isHierarchKey(key: String): Boolean { - return key.uppercase().startsWith(HIERARCH_WITH_DOT) - } - - @JvmStatic - fun isValidChar(c: Char): Boolean { - return c in MIN_VALID_CHAR..MAX_VALID_CHAR - } - - @JvmStatic - fun sanitize(input: CharSequence): String { - val data = CharArray(input.length) - - for (i in input.indices) { - val char = input[i] - data[i] = if (isValidChar(char)) char else '?' - } - - return data.concatToString() - } - - @JvmStatic - private fun spaceForValue(key: String): Int { - return if (key.length > MAX_KEYWORD_LENGTH) { - // HierarchFormater.extraSpaceRequired = 1 - FITS_HEADER_CARD_SIZE - (max(key.length, MAX_KEYWORD_LENGTH) + 1) - } else { - // DEFAULT_SKIP_BLANK_AFTER_ASSIGN = false, so AssignLength = 2. - FITS_HEADER_CARD_SIZE - (max(key.length, MAX_KEYWORD_LENGTH) + 2) - } - } - } -} diff --git a/nebulosa-fits/src/main/kotlin/nebulosa/fits/ImageHdu.kt b/nebulosa-fits/src/main/kotlin/nebulosa/fits/ImageHdu.kt index 43fd30a06..f6ba70399 100644 --- a/nebulosa-fits/src/main/kotlin/nebulosa/fits/ImageHdu.kt +++ b/nebulosa-fits/src/main/kotlin/nebulosa/fits/ImageHdu.kt @@ -1,5 +1,7 @@ package nebulosa.fits +import nebulosa.image.format.Header +import nebulosa.image.format.ReadableHeader import nebulosa.io.SeekableSource import okio.Buffer import okio.Sink @@ -16,8 +18,7 @@ data class ImageHdu( override fun read(source: SeekableSource) { val imageSize = (width * height * bitpix.byteSize).toLong() var position = source.position - - val n = header.getInt(Standard.NAXIS3, 1) + val n = header.getInt(FitsKeywordDictionary.NAXIS3, 1) data = Array(n) { SeekableSourceImageData(source, position, width, height, bitpix).also { position += imageSize } } val skipBytes = Hdu.computeRemainingBytesToSkip(imageSize * size) @@ -58,6 +59,7 @@ data class ImageHdu( companion object { @JvmStatic - fun isValid(header: Header) = header.getBoolean(Standard.SIMPLE) || header.getStringOrNull(Standard.XTENSION) == "IMAGE" + fun isValid(header: ReadableHeader) = + header.getBoolean(FitsKeywordDictionary.SIMPLE) || header.getStringOrNull(FitsKeywordDictionary.XTENSION) == "IMAGE" } } diff --git a/nebulosa-fits/src/main/kotlin/nebulosa/fits/MaxImDLExt.kt b/nebulosa-fits/src/main/kotlin/nebulosa/fits/MaxImDLExt.kt deleted file mode 100644 index 073e439cc..000000000 --- a/nebulosa-fits/src/main/kotlin/nebulosa/fits/MaxImDLExt.kt +++ /dev/null @@ -1,242 +0,0 @@ -package nebulosa.fits - -/** - * The Fits extension as defined by Maxim DL.Extension keywords that may be added or read by MaxIm DL, depending on the - * current equipment and software configuration. - */ -enum class MaxImDLExt : FitsHeader { - /** - * if present the image has a valid Bayer color pattern. - */ - BAYERPAT(ValueType.REAL, "image Bayer color pattern"), - - /** - * Boltwood Cloud Sensor ambient temperature in degrees C. - */ - BOLTAMBT(ValueType.REAL, "ambient temperature in degrees C"), - - /** - * Boltwood Cloud Sensor cloud condition. - */ - BOLTCLOU(ValueType.REAL, "Boltwood Cloud Sensor cloud condition."), - - /** - * Boltwood Cloud Sensor daylight level. - */ - BOLTDAY(ValueType.REAL, "Boltwood Cloud Sensor daylight level."), - - /** - * Boltwood Cloud Sensor dewpoint in degrees C. - */ - BOLTDEW(ValueType.REAL, "Boltwood Cloud Sensor dewpoint in degrees C."), - - /** - * Boltwood Cloud Sensor humidity in percent. - */ - BOLTHUM(ValueType.REAL, "Boltwood Cloud Sensor humidity in percent."), - - /** - * Boltwood Cloud Sensor rain condition. - */ - BOLTRAIN(ValueType.REAL, "Boltwood Cloud Sensor rain condition."), - - /** - * Boltwood Cloud Sensor sky minus ambient temperature in degrees C. - */ - BOLTSKYT(ValueType.REAL, "Boltwood Cloud Sensor sky minus ambient temperature in degrees C."), - - /** - * Boltwood Cloud Sensor wind speed in km/h. - */ - BOLTWIND(ValueType.REAL, "Boltwood Cloud Sensor wind speed in km/h."), - - /** - * indicates calibration state of the image; B indicates bias corrected, D indicates dark corrected, F indicates - * flat corrected. - */ - CALSTAT(ValueType.REAL, "calibration state of the image"), - - /** - * type of color sensor Bayer array or zero for monochrome. - */ - COLORTYP(ValueType.REAL, "type of color sensor"), - - /** - * initial display screen stretch mode. - */ - CSTRETCH(ValueType.REAL, "initial display screen stretch mode"), - - /** - * dark current integration time, if recorded. May be longer than exposure time. - */ - DARKTIME(ValueType.REAL, "dark current integration time"), - - /** - * Davis Instruments Weather Station ambient temperature in deg C - */ - DAVAMBT(ValueType.REAL, "ambient temperature"), - - /** - * Davis Instruments Weather Station barometric pressure in hPa - */ - DAVBAROM(ValueType.REAL, "barometric pressure"), - - /** - * Davis Instruments Weather Station dewpoint in deg C - */ - DAVDEW(ValueType.REAL, "dewpoint in deg C"), - - /** - * Davis Instruments Weather Station humidity in percent - */ - DAVHUM(ValueType.REAL, "humidity in percent"), - - /** - * Davis Instruments Weather Station solar radiation in W/m^2 - */ - DAVRAD(ValueType.REAL, "solar radiation"), - - /** - * Davis Instruments Weather Station accumulated rainfall in mm/day - */ - DAVRAIN(ValueType.REAL, "accumulated rainfall"), - - /** - * Davis Instruments Weather Station wind speed in km/h - */ - DAVWIND(ValueType.REAL, "wind speed"), - - /** - * Davis Instruments Weather Station wind direction in deg - */ - DAVWINDD(ValueType.REAL, "wind direction"), - - /** - * status of pier flip for German Equatorial mounts. - */ - FLIPSTAT(ValueType.REAL, "status of pier flip"), - - /** - * Focuser position in steps, if focuser is connected. - */ - FOCUSPOS(ValueType.REAL, "Focuser position in steps"), - - /** - * Focuser step size in microns, if available. - */ - FOCUSSZ(ValueType.REAL, "Focuser step size in microns"), - - /** - * Focuser temperature readout in degrees C, if available. - */ - FOCUSTEM(ValueType.REAL, "Focuser temperature readout"), - - /** - * format of file from which image was read. - */ - INPUTFMT(ValueType.REAL, "format of file"), - - /** - * ISO camera setting, if camera uses ISO speeds. - */ - ISOSPEED(ValueType.REAL, "ISO camera setting"), - - /** - * records the geocentric Julian Day of the start of exposure. - */ - JD(ValueType.REAL, "geocentric Julian Day"), - - /** - * records the geocentric Julian Day of the start of exposure. - */ - JD_GEO(ValueType.REAL, "geocentric Julian Da"), - - /** - * records the Heliocentric Julian Date at the exposure midpoint. - */ - JD_HELIO(ValueType.REAL, "Heliocentric Julian Date"), - - /** - * records the Heliocentric Julian Date at the exposure midpoint. - */ - JD_HELIO2("JD-HELIO", ValueType.REAL, "Heliocentric Julian Date"), - - /** - * UT of midpoint of exposure. - */ - MIDPOINT(ValueType.REAL, "midpoint of exposure"), - - /** - * user-entered information; free-form notes. - */ - NOTES(ValueType.REAL, "free-form note"), - - /** - * nominal altitude of center of image - */ - OBJCTALT(ValueType.REAL, "altitude of center of image"), - - /** - * nominal azimuth of center of image - */ - OBJCTAZ(ValueType.REAL, "nominal azimuth of center of image"), - - /** - * nominal hour angle of center of image - */ - OBJCTHA(ValueType.REAL, "nominal hour angle of center of image"), - - /** - * indicates side-of-pier status when connected to a German Equatorial mount. - */ - PIERSIDE(ValueType.REAL, "side-of-pier status"), - - /** - * records the selected Readout Mode (if any) for the camera. - */ - READOUTM(ValueType.REAL, "Readout Mode for the camera"), - - /** - * Rotator angle in degrees, if focal plane rotator is connected. - */ - ROTATANG(ValueType.REAL, "Rotator angle in degrees"), - - /** - * indicates tile position within a mosaic. - */ - TILEXY(ValueType.REAL, "tile position within a mosaic"), - - /** - * X offset of Bayer array on imaging sensor. - */ - XBAYROFF(ValueType.REAL, "X offset of Bayer array"), - - /** - * Y offset of Bayer array on imaging sensor. - */ - YBAYROFF(ValueType.REAL, "Y offset of Bayer array"); - - private val header: FitsHeaderImpl - - constructor(key: String, valueType: ValueType, comment: String) { - header = FitsHeaderImpl(key, hduType, valueType, comment) - } - - constructor(valueType: ValueType, comment: String) { - header = FitsHeaderImpl(name, hduType, valueType, comment) - } - - override val key - get() = header.key - - override val comment - get() = header.comment - - override val hduType - get() = HduType.IMAGE - - override val valueType - get() = header.valueType - - override fun n(vararg numbers: Int) = header.n(*numbers) -} diff --git a/nebulosa-fits/src/main/kotlin/nebulosa/fits/NonStandard.kt b/nebulosa-fits/src/main/kotlin/nebulosa/fits/NonStandard.kt deleted file mode 100644 index bf3310be3..000000000 --- a/nebulosa-fits/src/main/kotlin/nebulosa/fits/NonStandard.kt +++ /dev/null @@ -1,46 +0,0 @@ -package nebulosa.fits - -enum class NonStandard(hduType: HduType, valueType: ValueType, comment: String) : FitsHeader { - /** - * The HIERARCH keyword, when followed by spaces in columns 9 and 10 of the FITS card image, indicates that the ESO - * HIERARCH keyword convention should be used to interpret the name and value of the keyword. The HIERARCH keyword - * formally has no value because it is not followed by an equals sign in column 9. Under the HIERARCH convention the - * actual name of the keyword begins in column 11 of the card image and is terminated by the equal sign ('=') - * character. The name can contain any number of characters as long as it fits within columns 11 and 80 of the card - * image and also leaves enough space for the equal sign separator and the value field. The name can contain any - * printable ASCII text character, including spaces and lower-case characters, except for the equal sign character - * which serves as the terminator of the name field. Leading and trailing spaces in the name field are not - * significant, but embedded spaces within the name are significant. The value field follows the equals sign and - * must conform to the syntax for a free-format value field as defined in the FITS Standard. The value field may be - * null, in which case it contains only space characters, otherwise it may contain either a character string - * enclosed in single quotes, the logical constant T or F, an integer number, a floating point number, a complex - * integer number, or a complex floating point number. The value field may be followed by an optional comment - * string. The comment field must be separated from the value field by a slash character ('/'). It is recommended - * that the slash character be preceeded and followed by a space character. Example: "HIERARCH Filter Wheel = 12 / - * filter position". In this example the logical name of the keyword is 'Filter Wheel' and the value is 12. - */ - HIERARCH(HduType.ANY, ValueType.NONE, "denotes the HIERARCH keyword convention"), - - /** - * The presence of this keyword with a value = T in an extension key indicates that the keywords contained in the - * primary key (except the FITS Mandatory keywords, and any COMMENT, HISTORY or 'blank' keywords) are to be - * inherited, or logically included in that extension key. - */ - INHERIT(HduType.EXTENSION, ValueType.LOGICAL, "denotes the INHERIT keyword convention"); - - private val header = FitsHeaderImpl(name, hduType, valueType, comment) - - override val key - get() = header.key - - override val comment - get() = header.comment - - override val hduType - get() = header.hduType - - override val valueType - get() = header.valueType - - override fun n(vararg numbers: Int) = this -} diff --git a/nebulosa-fits/src/main/kotlin/nebulosa/fits/ReadOnlyHeader.kt b/nebulosa-fits/src/main/kotlin/nebulosa/fits/ReadOnlyHeader.kt deleted file mode 100644 index 522b2e17e..000000000 --- a/nebulosa-fits/src/main/kotlin/nebulosa/fits/ReadOnlyHeader.kt +++ /dev/null @@ -1,31 +0,0 @@ -package nebulosa.fits - -import nebulosa.io.SeekableSource -import java.util.* - -open class ReadOnlyHeader : Header { - - constructor() : super(LinkedList()) - - constructor(cards: Collection) : super(LinkedList(cards)) - - constructor(header: Header) : super(LinkedList(header.cards)) - - override fun read(source: SeekableSource) = throw UnsupportedOperationException("Header is read-only") - - override fun clear() = throw UnsupportedOperationException("Header is read-only") - - override fun add(key: FitsHeader, value: Boolean) = throw UnsupportedOperationException("Header is read-only") - - override fun add(key: FitsHeader, value: Int) = throw UnsupportedOperationException("Header is read-only") - - override fun add(key: FitsHeader, value: Double) = throw UnsupportedOperationException("Header is read-only") - - override fun add(key: FitsHeader, value: String) = throw UnsupportedOperationException("Header is read-only") - - override fun add(card: HeaderCard) = throw UnsupportedOperationException("Header is read-only") - - override fun delete(key: FitsHeader) = throw UnsupportedOperationException("Header is read-only") - - override fun readOnly() = this -} diff --git a/nebulosa-fits/src/main/kotlin/nebulosa/fits/SBFitsExt.kt b/nebulosa-fits/src/main/kotlin/nebulosa/fits/SBFitsExt.kt deleted file mode 100644 index 77efeee74..000000000 --- a/nebulosa-fits/src/main/kotlin/nebulosa/fits/SBFitsExt.kt +++ /dev/null @@ -1,195 +0,0 @@ -package nebulosa.fits - -/** - * A Set of FITS Standard Extensions for Amateur Astronomical Processing Software Packages published by SBIG. - */ -enum class SBFitsExt : FitsHeader { - /** - * Aperture Area of the Telescope used in square millimeters. Note that we are specifying the area as well as the - * diameter because we want to be able to correct for any central obstruction. - */ - APTAREA(ValueType.REAL, "Aperture Area of the Telescope"), - - /** - * Aperture Diameter of the Telescope used in millimeters. - */ - APTDIA(ValueType.REAL, "Aperture Diameter of the Telescope"), - - /** - * Upon initial display of this image use this ADU level for the Black level. - */ - CBLACK(ValueType.INTEGER, "use this ADU level for the Black"), - - /** - * Temperature of CCD when exposure taken. - */ - CCD_TEMP("CCD-TEMP", ValueType.REAL, "Temperature of CCD"), - - /** - * Altitude in degrees of the center of the image in degrees. Format is the same as the OBJCTDEC keyword. - */ - CENTALT(ValueType.STRING, "Altitude of the center of the image"), - - /** - * Azimuth in degrees of the center of the image in degrees. Format is the same as the OBJCTDEC keyword. - */ - CENTAZ(ValueType.STRING, "Azimuth of the center of the image"), - - /** - * Upon initial display of this image use this ADU level as the White level. For the SBIG method of displaying - * images using Background and Range the following conversions would be used: Background = CBLACK Range = CWHITE - - * CBLACK. - */ - CWHITE(ValueType.INTEGER, "use this ADU level for the White"), - - /** - * Total dark time of the observation. This is the total time during which dark current is collected by the - * detector. If the times in the extension are different the primary HDU gives one of the extension times. - *

- * units = UNITTIME - *

- *

- * default value = EXPTIME - *

- *

- * index = none - *

- */ - DARKTIME(ValueType.REAL, "Dark time"), - - /** - * Electronic gain in e-/ADU. - */ - EGAIN(ValueType.REAL, "Electronic gain in e-/ADU"), - /* - * Optional Keywords

The following Keywords are not defined in the FITS Standard but are defined in this - * Standard. They may or may not be included by AIP Software Packages adhering to this Standard. Any of these - * keywords read by an AIP Package must be preserved in files written.

- */ - /** - * Focal Length of the Telescope used in millimeters. - */ - FOCALLEN(ValueType.REAL, "Focal Length of the Telescope"), - - /** - * This indicates the type of image and should be one of the following: Light Frame Dark Frame Bias Frame Flat - * Field. - */ - IMAGETYP(ValueType.STRING, "type of image"), - - /** - * This is the Declination of the center of the image in degrees. The format for this is ‘+25 12 34.111’ (SDD MM - * SS.SSS) using a space as the separator. For the sign, North is + and South is -. - */ - OBJCTDEC(ValueType.STRING, "Declination of the center of the image"), - - /** - * This is the Right Ascension of the center of the image in hours, minutes and secon ds. The format for this is ’12 - * 24 23.123’ (HH MM SS.SSS) using a space as the separator. - */ - OBJCTRA(ValueType.STRING, "Right Ascension of the center of the image"), - - /** - * Add this ADU count to each pixel value to get to a zero - based ADU. For example in SBIG images we add 100 ADU to - * each pixel to stop underflow at Zero ADU from noise. We would set PEDESTAL to - 100 in this case. - */ - PEDESTAL(ValueType.INTEGER, "ADU count to each pixel value to get to a zero"), - - /** - * This string indicates the version of this standard that the image was created to ie ‘SBFITSEXT Version 1.0’. - */ - SBSTDVER(ValueType.STRING, "version of this standard"), - - /** - * This is the setpoint of the cooling in degrees C. If it is not specified the setpoint is assumed to be the - */ - SET_TEMP("SET-TEMP", ValueType.REAL, "setpoint of the cooling in degrees C"), - - /** - * Latitude of the imaging location in degrees. Format is the same as the OBJCTDEC key word. - */ - SITELAT(ValueType.STRING, "Latitude of the imaging location"), - - /** - * Longitude of the imaging location in degrees. Format is the same as the OBJCTDEC keyword. - */ - SITELONG(ValueType.STRING, "Longitude of the imaging location"), - - /** - * Number of images combined to make this image as in Track and Accumulate or Co - Added images. - */ - SNAPSHOT(ValueType.INTEGER, "Number of images combined"), - - /** - * This indicates the name and version of the Software that initially created this file ie ‘SBIGs CCDOps Version - * 5.10’. - */ - SWCREATE(ValueType.STRING, "created version of the Software"), - - /** - * This indicates the name and version of the Software that modified this file ie ‘SBIGs CCDOps Version 5.10’ and - * the re can be multiple copies of this keyword. Only add this keyword if you actually modified the image and we - * suggest placing this above the HISTORY keywords corresponding to the modifications made to the image. - */ - SWMODIFY(ValueType.STRING, "modified version of the Software"), - - /** - * If the image was auto-guided this is the exposure time in seconds of the tracker used to acquire this image. If - * this keyword is not present then the image was unguided or hand guided. - */ - TRAKTIME(ValueType.REAL, "exposure time in seconds of the tracker"), - - /** - * Binning factor in width. - */ - XBINNING(ValueType.INTEGER, "Binning factor in width"), - - /** - * Sub frame X position of upper left pixel relative to whole frame in binned pixel units. - */ - XORGSUBF(ValueType.INTEGER, "Sub frame X position"), - - /** - * Pixel width in microns (after binning). - */ - XPIXSZ(ValueType.REAL, "Pixel width in microns"), - - /** - * Binning factor in height. - */ - YBINNING(ValueType.INTEGER, "Binning factor in height"), - - /** - * Sub frame Y position of upper left pixel relative to whole frame in binned pixel units. - */ - YORGSUBF(ValueType.INTEGER, "Sub frame Y position"), - - /** - * Pixel height in microns (after binning). - */ - YPIXSZ(ValueType.REAL, "Pixel height in microns"); - - private val header: FitsHeaderImpl - - constructor(key: String, valueType: ValueType, comment: String) { - header = FitsHeaderImpl(key, hduType, valueType, comment) - } - - constructor(valueType: ValueType, comment: String) { - header = FitsHeaderImpl(name, hduType, valueType, comment) - } - - override val key - get() = header.key - - override val comment - get() = header.comment - - override val hduType - get() = HduType.IMAGE - - override val valueType - get() = header.valueType - - override fun n(vararg numbers: Int) = header.n(*numbers) -} diff --git a/nebulosa-fits/src/main/kotlin/nebulosa/fits/Standard.kt b/nebulosa-fits/src/main/kotlin/nebulosa/fits/Standard.kt deleted file mode 100644 index 2e64ab09b..000000000 --- a/nebulosa-fits/src/main/kotlin/nebulosa/fits/Standard.kt +++ /dev/null @@ -1,770 +0,0 @@ -package nebulosa.fits - -enum class Standard : FitsHeader { - /** - * The value field shall contain a character string identifying who compiled the information in the data associated - * with the key. This keyword is appropriate when the data originate in a published paper or are compiled from many - * sources. - */ - AUTHOR(HduType.ANY, ValueType.STRING, "author of the data"), - - /** - * The value field shall contain an integer. The absolute value is used in computing the sizes of data structures. - * It shall specify the number of bits that represent a data value. RANGE: -64,-32,8,16,32 - */ - BITPIX(HduType.ANY, ValueType.INTEGER, "bits per data value"), - - /** - * This keyword shall be used only in primary array headers or IMAGE extension headers with positive values of - * BITPIX (i.e., in arrays with integer data). Columns 1-8 contain the string, `BLANK ' (ASCII blanks in columns - * 6-8). The value field shall contain an integer that specifies the representation of array values whose physical - * values are undefined. - */ - BLANK(HduType.IMAGE, ValueType.INTEGER, "value used for undefined array elements"), - - /** - * Columns 1-8 contain ASCII blanks. This keyword has no associated value. Columns 9-80 may contain any ASCII text. - * Any number of card images with blank keyword fields may appear in a key. - */ - BLANKS(" ", HduType.ANY, ValueType.NONE, ""), - - /** - * This keyword may be used only in the primary key. It shall appear within the first 36 card images of the FITS - * file. (Note: This keyword thus cannot appear if NAXIS is greater than 31, or if NAXIS is greater than 30 and the - * EXTEND keyword is present.) Its presence with the required logical value of T advises that the physical block - * size of the FITS file on which it appears may be an integral multiple of the logical record length, and not - * necessarily equal to it. Physical block size and logical record length may be equal even if this keyword is - * present or unequal if it is absent. It is reserved primarily to prevent its use with other meanings. Since the - * issuance of version 1 of the standard, the BLOCKED keyword has been deprecated. - */ - @Deprecated("no blocksize other that 2880 may be used") - BLOCKED(HduType.PRIMARY, ValueType.LOGICAL, "is physical blocksize a multiple of 2880?"), - - /** - * This keyword shall be used, along with the BZERO keyword, when the array pixel values are not the true physical - * values, to transform the primary data array values to the true physical values they represent, using the - * equation: physical_value = BZERO + BSCALE * array_value. The value field shall contain a floating point number - * representing the coefficient of the linear term in the scaling equation, the ratio of physical value to array - * value at zero offset. The default value for this keyword is 1.0. - */ - BSCALE(HduType.IMAGE, ValueType.REAL, "linear factor in scaling equation"), - - /** - * The value field shall contain a character string, describing the physical units in which the quantities in the - * array, after application of BSCALE and BZERO, are expressed. The units of all FITS key keyword values, with the - * exception of measurements of angles, should conform with the recommendations in the IAU Style Manual. For angular - * measurements given as floating point values and specified with reserved keywords, degrees are the recommended - * units (with the units, if specified, given as 'deg'). - */ - BUNIT(HduType.IMAGE, ValueType.STRING, "physical units of the array values"), - - /** - * This keyword shall be used, along with the BSCALE keyword, when the array pixel values are not the true physical - * values, to transform the primary data array values to the true values using the equation: physical_value = BZERO - * + BSCALE * array_value. The value field shall contain a floating point number representing the physical value - * corresponding to an array value of zero. The default value for this keyword is 0.0. - */ - BZERO(HduType.IMAGE, ValueType.REAL, "zero point in scaling equation"), - - /** - * The value field shall contain a floating point number giving the partial derivative of the coordinate specified - * by the CTYPEn keywords with respect to the pixel index, evaluated at the reference point CRPIXn, in units of the - * coordinate specified by the CTYPEn keyword. These units must follow the prescriptions of section 5.3 of the FITS - * Standard. - */ - CDELTn(HduType.IMAGE, ValueType.REAL, "coordinate increment along axis"), - - /** - * This keyword shall have no associated value; columns 9-80 may contain any ASCII text. Any number of COMMENT card - * images may appear in a key. - */ - COMMENT(HduType.ANY, ValueType.NONE, ""), - - /** - * The CONTINUE keyword, when followed by spaces in columns 9 and 10 of the card image and a character string - * enclosed in single quotes starting in column 11 or higher, indicates that the quoted string should be treated as - * a continuation of the character string value in the previous key keyword. To conform to this convention, the - * character string value on the previous keyword must end with the ampersand character ('&'), but the ampersand - * is not part of the value string and should be deleted before concatenating the strings together. The character - * string value may be continued on any number of consecutive CONTINUE keywords, thus effectively allowing - * arbitrarily long strings to be written as keyword values. - */ - CONTINUE(HduType.ANY, ValueType.NONE, "denotes the CONTINUE long string keyword convention"), - - /** - * This keyword is used to indicate a rotation from a standard coordinate system described by the CTYPEn to a - * different coordinate system in which the values in the array are actually expressed. Rules for such rotations are - * not further specified in the Standard; the rotation should be explained in comments. The value field shall - * contain a floating point number giving the rotation angle in degrees between axis n and the direction implied by - * the coordinate system defined by CTYPEn. In unit degrees. - */ - CROTAn(HduType.IMAGE, ValueType.REAL, "coordinate system rotation angle"), - - /** - * The value field shall contain a floating point number, identifying the location of a reference point along axis - * n, in units of the axis index. This value is based upon a counter that runs from 1 to NAXISn with an increment of - * 1 per pixel. The reference point value need not be that for the center of a pixel nor lie within the actual data - * array. Use comments to indicate the location of the index point relative to the pixel. - */ - CRPIXn(HduType.IMAGE, ValueType.REAL, "coordinate system reference pixel"), - - /** - * The value field shall contain a floating point number, giving the value of the coordinate specified by the CTYPEn - * keyword at the reference point CRPIXn. Units must follow the prescriptions of section 5.3 of the FITS Standard. - */ - CRVALn(HduType.IMAGE, ValueType.REAL, "coordinate system value at reference pixel"), - - /** - * The value field shall contain a character string, giving the name of the coordinate represented by axis n. - */ - CTYPEn(HduType.IMAGE, ValueType.STRING, "name of the coordinate axis"), - - /** - * The value field shall always contain a floating point number, regardless of the value of BITPIX. This number - * shall give the maximum valid physical value represented by the array, exclusive of any special values. - */ - DATAMAX(HduType.IMAGE, ValueType.REAL, "maximum data value"), - - /** - * The value field shall always contain a floating point number, regardless of the value of BITPIX. This number - * shall give the minimum valid physical value represented by the array, exclusive of any special values. - */ - DATAMIN(HduType.IMAGE, ValueType.REAL, "minimum data value"), - - /** - * The date on which the HDU was created, in the format specified in the FITS Standard. The old date format was - * 'yy/mm/dd' and may be used only for dates from 1900 through 1999. the new Y2K compliant date format is - * 'yyyy-mm-dd' or 'yyyy-mm-ddTHH:MM:SS[.sss]'. - */ - DATE(HduType.ANY, ValueType.STRING, "date of file creation"), - - /** - * The date of the observation, in the format specified in the FITS Standard. The old date format was 'yy/mm/dd' and - * may be used only for dates from 1900 through 1999. The new Y2K compliant date format is 'yyyy-mm-dd' or - * 'yyyy-mm-ddTHH:MM:SS[.sss]'. - */ - DATE_OBS("DATE-OBS", HduType.ANY, ValueType.STRING, "date of the observation"), - - /** - * This keyword has no associated value. Columns 9-80 shall be filled with ASCII blanks. - */ - END(HduType.ANY, ValueType.NONE, ""), - - /** - * The value field shall contain a floating point number giving the equinox in years for the celestial coordinate - * system in which positions are expressed. Starting with Version 1, the Standard has deprecated the use of the - * EPOCH keyword and thus it shall not be used in FITS files created after the adoption of the standard; rather, the - * EQUINOX keyword shall be used. - */ - @Deprecated("use EQUINOX instead") - EPOCH(HduType.ANY, ValueType.REAL, "equinox of celestial coordinate system"), - - /** - * The value field shall contain a floating point number giving the equinox in years for the celestial coordinate - * system in which positions are expressed. - */ - EQUINOX(HduType.ANY, ValueType.REAL, "equinox of celestial coordinate system"), - - /** - * If the FITS file may contain extensions, a card image with the keyword EXTEND and the value field containing the - * logical value T must appear in the primary key immediately after the last NAXISn card image, or, if NAXIS=0, the - * NAXIS card image. The presence of this keyword with the value T in the primary key does not require that - * extensions be present. - */ - EXTEND(HduType.PRIMARY, ValueType.LOGICAL, "may the FITS file contain extensions?"), - - /** - * The value field shall contain an integer, specifying the level in a hierarchy of extension levels of the - * extension key containing it. The value shall be 1 for the highest level; levels with a higher value of this - * keyword shall be subordinate to levels with a lower value. If the EXTLEVEL keyword is absent, the file should be - * treated as if the value were 1. This keyword is used to describe an extension and should not appear in the - * primary key.RANGE: [1:] DEFAULT: 1 - */ - EXTLEVEL(HduType.EXTENSION, ValueType.INTEGER, "hierarchical level of the extension"), - - /** - * The value field shall contain a character string, to be used to distinguish among different extensions of the - * same type, i.e., with the same value of XTENSION, in a FITS file. This keyword is used to describe an extension - * and should not appear in the primary key. - */ - EXTNAME(HduType.EXTENSION, ValueType.STRING, "name of the extension"), - - /** - * The value field shall contain an integer, to be used to distinguish among different extensions in a FITS file - * with the same type and name, i.e., the same values for XTENSION and EXTNAME. The values need not start with 1 for - * the first extension with a particular value of EXTNAME and need not be in sequence for subsequent values. If the - * EXTVER keyword is absent, the file should be treated as if the value were 1. This keyword is used to describe an - * extension and should not appear in the primary key.RANGE: [1:] DEFAULT: 1 - */ - EXTVER(HduType.EXTENSION, ValueType.INTEGER, "version of the extension"), - - /** - * The value field shall contain an integer that shall be used in any way appropriate to define the data structure, - * consistent with Eq. 5.2 in the FITS Standard. This keyword originated for use in FITS Random Groups where it - * specifies the number of random groups present. In most other cases this keyword will have the value 1. - */ - GCOUNT(HduType.EXTENSION, ValueType.INTEGER, "group count"), - - /** - * The value field shall contain the logical constant T. The value T associated with this keyword implies that - * random groups records are present. - */ - GROUPS(HduType.GROUPS, ValueType.LOGICAL, "indicates random groups structure"), - - /** - * This keyword shall have no associated value; columns 9-80 may contain any ASCII text. The text should contain a - * history of steps and procedures associated with the processing of the associated data. Any number of HISTORY card - * images may appear in a key. - */ - HISTORY(HduType.ANY, ValueType.NONE, "processing history of the data"), - - /** - * The value field shall contain a character string identifying the instrument used to acquire the data associated - * with the key. - */ - INSTRUME(HduType.ANY, ValueType.STRING, "name of instrument"), - - /** - * The value field shall contain a non-negative integer no greater than 999, representing the number of axes in the - * associated data array. A value of zero signifies that no data follow the key in the HduType. In the context of FITS - * 'TABLE' or 'BINTABLE' extensions, the value of NAXIS is always 2.RANGE: [0:999] - */ - NAXIS(HduType.ANY, ValueType.INTEGER, "number of axes"), - - /** - * The value field of this indexed keyword shall contain a non-negative integer, representing the number of elements - * along axis n of a data array. The NAXISn must be present for all values n = 1,...,NAXIS, and for no other values - * of n. A value of zero for any of the NAXISn signifies that no data follow the key in the HduType. If NAXIS is equal - * to 0, there should not be any NAXISn keywords.RANGE: [0:] - */ - NAXISn(HduType.ANY, ValueType.INTEGER, "size of the n'th axis"), - - /** - * The value field shall contain a character string giving a name for the object observed. - */ - OBJECT(HduType.ANY, ValueType.STRING, "name of observed object"), - - /** - * The value field shall contain a character string identifying who acquired the data associated with the key. - */ - OBSERVER(HduType.ANY, ValueType.STRING, "observer who acquired the data"), - - /** - * The value field shall contain a character string identifying the organization or institution responsible for - * creating the FITS file. - */ - ORIGIN(HduType.ANY, ValueType.STRING, "organization responsible for the data"), - - /** - * The value field shall contain an integer that shall be used in any way appropriate to define the data structure, - * consistent with Eq. 5.2 in the FITS Standard. This keyword was originated for use with FITS Random Groups and - * represented the number of parameters preceding each group. It has since been used in 'BINTABLE' extensions to - * represent the size of the data heap following the main data table. In most other cases its value will be zero. - */ - PCOUNT(HduType.EXTENSION, ValueType.INTEGER, "parameter count"), - - /** - * This keyword is reserved for use within the FITS Random Groups structure. This keyword shall be used, along with - * the PZEROn keyword, when the nth FITS group parameter value is not the true physical value, to transform the - * group parameter value to the true physical values it represents, using the equation, physical_value = PZEROn + - * PSCALn * group_parameter_value. The value field shall contain a floating point number representing the - * coefficient of the linear term, the scaling factor between true values and group parameter values at zero offset. - * The default value for this keyword is 1.0. - */ - PSCALn(HduType.GROUPS, ValueType.REAL, "parameter scaling factor"), - - /** - * This keyword is reserved for use within the FITS Random Groups structure. The value field shall contain a - * character string giving the name of parameter n. If the PTYPEn keywords for more than one value of n have the - * same associated name in the value field, then the data value for the parameter of that name is to be obtained by - * adding the derived data values of the corresponding parameters. This rule provides a mechanism by which a random - * parameter may have more precision than the accompanying data array elements; for example, by summing two 16-bit - * values with the first scaled relative to the other such that the sum forms a number of up to 32-bit precision. - */ - PTYPEn(HduType.GROUPS, ValueType.STRING, "name of random groups parameter"), - - /** - * This keyword is reserved for use within the FITS Random Groups structure. This keyword shall be used, along with - * the PSCALn keyword, when the nth FITS group parameter value is not the true physical value, to transform the - * group parameter value to the physical value. The value field shall contain a floating point number, representing - * the true value corresponding to a group parameter value of zero. The default value for this keyword is 0.0. The - * transformation equation is as follows: physical_value = PZEROn + PSCALn * group_parameter_value.DEFAULT: 0.0 - */ - PZEROn(HduType.GROUPS, ValueType.REAL, "parameter scaling zero point"), - - /** - * Coordinate reference frame of major/minor axes.If absent the default value is 'FK5'. - */ - RADESYS(HduType.ANY, ValueType.STRING, "Coordinate reference frame of major/minor axes."), - - /** - * Coordinate reference frame of major/minor axes. use RADESYS instead. - */ - @Deprecated("use RADESYS instead.") - RADECSYS(HduType.ANY, ValueType.STRING, "Coordinate reference frame of major/minor axes."), - - /** - * The value field shall contain a character string citing a reference where the data associated with the key are - * published. - */ - REFERENC(HduType.ANY, ValueType.STRING, "bibliographic reference"), - - /** - * The SIMPLE keyword is required to be the first keyword in the primary key of all FITS files. The value field - * shall contain a logical constant with the value T if the file conforms to the standard. This keyword is mandatory - * for the primary key and is not permitted in extension headers. A value of F signifies that the file does not - * conform to this standard. - */ - SIMPLE(HduType.PRIMARY, ValueType.LOGICAL, "does file conform to the Standard?"), - - /** - * The value field of this indexed keyword shall contain an integer specifying the column in which field n starts in - * an ASCII TABLE extension. The first column of a row is numbered 1.RANGE: [1:] - */ - TBCOLn(HduType.ASCII_TABLE, ValueType.INTEGER, "begining column number"), - - /** - * The value field of this indexed keyword shall contain a character string describing how to interpret the contents - * of field n as a multidimensional array, providing the number of dimensions and the length along each axis. The - * form of the value is not further specified by the Standard. A proposed convention is described in Appendix B.2 of - * the FITS Standard in which the value string has the format '(l,m,n...)' where l, m, n,... are the dimensions of - * the array. - */ - TDIMn(HduType.BINTABLE, ValueType.STRING, "dimensionality of the array "), - - /** - * The value field of this indexed keyword shall contain a character string describing the format recommended for - * the display of the contents of field n. If the table value has been scaled, the physical value shall be - * displayed. All elements in a field shall be displayed with a single, repeated format. For purposes of display, - * each byte of bit (type X) and byte (type B) arrays is treated as an unsigned integer. Arrays of type A may be - * terminated with a zero byte. Only the format codes in Table 8.6, discussed in section 8.3.4 of the FITS Standard, - * are permitted for encoding. The format codes must be specified in upper case. If the Bw.m, Ow.m, and Zw.m formats - * are not readily available to the reader, the Iw.m display format may be used instead, and if the ENw.d and ESw.d - * formats are not available, Ew.d may be used. The meaning of this keyword is not defined for fields of type P in - * the Standard but may be defined in conventions using such fields. - */ - TDISPn(HduType.TABLE, ValueType.STRING, "display format"), - - /** - * The value field shall contain a character string identifying the telescope used to acquire the data associated - * with the key. - */ - TELESCOP(HduType.ANY, ValueType.STRING, "name of telescope"), - - /** - * The value field shall contain a non-negative integer representing the number of fields in each row of a 'TABLE' - * or 'BINTABLE' extension. The maximum permissible value is 999. RANGE: [0:999] - */ - TFIELDS(HduType.TABLE, ValueType.INTEGER, "number of columns in the table"), - - /** - * The value field of this indexed keyword shall contain a character string describing the format in which field n - * is encoded in a 'TABLE' or 'BINTABLE' extension. - */ - TFORMn(HduType.TABLE, ValueType.STRING, "column data format"), - - /** - * The value field of this keyword shall contain an integer providing the separation, in bytes, between the start of - * the main data table and the start of a supplemental data area called the heap. The default value shall be the - * product of the values of NAXIS1 and NAXIS2. This keyword shall not be used if the value of PCOUNT is zero. A - * proposed application of this keyword is presented in Appendix B.1 of the FITS Standard. - */ - THEAP(HduType.BINTABLE, ValueType.INTEGER, "offset to starting data heap address"), - - /** - * In ASCII 'TABLE' extensions, the value field for this indexed keyword shall contain the character string that - * represents an undefined value for field n. The string is implicitly blank filled to the width of the field. In - * binary 'BINTABLE' table extensions, the value field for this indexed keyword shall contain the integer that - * represents an undefined value for field n of data type B, I, or J. The keyword may not be used in 'BINTABLE' - * extensions if field n is of any other data type. - */ - TNULLn(HduType.TABLE, ValueType.STRING, "value used to indicate undefined table element"), - - /** - * This indexed keyword shall be used, along with the TZEROn keyword, when the quantity in field n does not - * represent a true physical quantity. The value field shall contain a floating point number representing the - * coefficient of the linear term in the equation, physical_value = TZEROn + TSCALn * field_value, which must be - * used to compute the true physical value of the field, or, in the case of the complex data types C and M, of the - * real part of the field with the imaginary part of the scaling factor set to zero. The default value for this - * keyword is 1.0. This keyword may not be used if the format of field n is A, L, or X.DEFAULT: 1.0 - */ - TSCALn(HduType.TABLE, ValueType.REAL, "linear data scaling factor"), - - /** - * The value field for this indexed keyword shall contain a character string, giving the name of field n. It is - * recommended that only letters, digits, and underscore (hexadecimal code 5F, ('_') be used in the name. String - * comparisons with the values of TTYPEn keywords should not be case sensitive. The use of identical names for - * different fields should be avoided. - */ - TTYPEn(HduType.TABLE, ValueType.STRING, "column name"), - - /** - * The value field shall contain a character string describing the physical units in which the quantity in field n, - * after any application of TSCALn and TZEROn, is expressed. The units of all FITS key keyword values, with the - * exception of measurements of angles, should conform with the recommendations in the IAU Style Manual. For angular - * measurements given as floating point values and specified with reserved keywords, degrees are the recommended - * units (with the units, if specified, given as 'deg'). - */ - TUNITn(HduType.TABLE, ValueType.STRING, "column units"), - - /** - * This indexed keyword shall be used, along with the TSCALn keyword, when the quantity in field n does not - * represent a true physical quantity. The value field shall contain a floating point number representing the true - * physical value corresponding to a value of zero in field n of the FITS file, or, in the case of the complex data - * types C and M, in the real part of the field, with the imaginary part set to zero. The default value for this - * keyword is 0.0. This keyword may not be used if the format of field n is A, L, or X.DEFAULT: 0.0 - */ - TZEROn(HduType.TABLE, ValueType.REAL, "column scaling zero point"), - - /** - * The value field shall contain a character string giving the name of the extension type. This keyword is mandatory - * for an extension key and must not appear in the primary key. For an extension that is not a standard extension, - * the type name must not be the same as that of a standard extension. - */ - XTENSION(HduType.EXTENSION, ValueType.STRING, "marks beginning of new HDU"), - - // FITS keywords that have been widely used within the astronomical community. - // These are the Keywords that describe the observation. - - /** - * The value field shall contain a floating point number giving the air mass during the observation by a ground - * based telescope. The value of the airmass is often approximated by the secant of the elevation angle and has a - * value of 1.0 at the zenith and increases towards the horizon. This value is assumed to correspond to the start of - * the observation unless another interpretation is clearly explained in the comment field. - */ - AIRMASS(HduType.ANY, ValueType.REAL, "air mass"), - - /** - * The value field gives the declination of the observation. It may be expressed either as a floating point number - * in units of decimal degrees, or as a character string in 'dd:mm:ss.sss' format where the decimal point and number - * of fractional digits are optional. The coordinate reference frame is given by the RADECSYS keyword, and the - * coordinate epoch is given by the EQUINOX keyword. Example: -47.25944 or '-47:15:34.00'. - */ - DEC(HduType.ANY, ValueType.STRING, "declination of the observed object"), - - /** - * The value field shall contain a floating point number giving the nominal declination of the pointing direction in - * units of decimal degrees. The coordinate reference frame is given by the RADECSYS keyword, and the coordinate - * epoch is given by the EQUINOX keyword. The precise definition of this keyword is instrument-specific, but - * typically the nominal direction corresponds to the direction to which the instrument was requested to point. The - * DEC_PNT keyword should be used to give the actual pointed direction. - */ - DEC_NOM(HduType.ANY, ValueType.REAL, "nominal declination of the observation"), - - /** - * The value field shall contain a floating point number giving the declination of the observed object in units of - * decimal degrees. The coordinate reference frame is given by the RADECSYS keyword, and the coordinate epoch is - * given by the EQUINOX keyword. - */ - DEC_OBJ(HduType.ANY, ValueType.REAL, "declination of the observed object"), - - /** - * The value field shall contain a floating point number giving the declination of the pointing direction in units - * of decimal degrees. The coordinate reference frame is given by the RADECSYS keyword, and the coordinate epoch is - * given by the EQUINOX keyword. The precise definition of this keyword is instrument-specific, but typically the - * pointed direction corresponds to the optical axis of the instrument. This keyword gives a mean value in cases - * where the pointing axis was not fixed during the entire observation. - */ - DEC_PNT(HduType.ANY, ValueType.REAL, "declination of the pointed direction of the instrument"), - - /** - * The value field shall contain a floating point number giving the declination of the space craft (or telescope - * platform) X axis during the observation in decimal degrees. The coordinate reference frame is given by the - * RADECSYS keyword, and the coordinate epoch is given by the EQUINOX keyword. This keyword gives a mean value in - * cases where the axis was not fixed during the entire observation. - */ - DEC_SCX(HduType.ANY, ValueType.REAL, "declination of the X spacecraft axis"), - - /** - * The value field shall contain a floating point number giving the declination of the space craft (or telescope - * platform) Z axis during the observation in decimal degrees. The coordinate reference frame is given by the - * RADECSYS keyword, and the coordinate epoch is given by the EQUINOX keyword. This keyword gives a mean value in - * cases where the axis was not fixed during the entire observation. - */ - DEC_SCZ(HduType.ANY, ValueType.REAL, "declination of the Z spacecraft axis"), - - /** - * The value field shall contain a floating point number giving the geographic latitude from which the observation - * was made in units of degrees. - */ - LATITUDE(HduType.ANY, ValueType.REAL, "geographic latitude of the observation"), - - /** - * The value field shall contain a floating point number giving the angle between the direction of the observation - * (e.g., the optical axis of the telescope or the position of the target) and the moon, measured in degrees. - */ - MOONANGL(HduType.ANY, ValueType.REAL, "angle between the observation and the moon"), - - /** - * The value field shall contain a character string giving a name for the observed object that conforms to the IAU - * astronomical object naming conventions. The value of this keyword is more strictly constrained than for the - * standard OBJECT keyword which in practice has often been used to record other ancillary information about the - * observation (e.g. filter, exposure time, weather conditions, etc.). - */ - OBJNAME(HduType.ANY, ValueType.STRING, "AU name of observed object"), - - /** - * The value field shall contain a character string which uniquely identifies the dataset contained in the FITS - * file. This is typically a sequence number that can contain a mixture of numerical and character values. Example: - * '10315-01-01-30A' - */ - OBS_ID(HduType.ANY, ValueType.STRING, "unique observation ID"), - - /** - * The value field shall contain a floating point number giving the position angle of the y axis of the detector - * projected on the sky, in degrees east of north. This keyword is synonymous with the CROTA2 WCS keyword. - */ - ORIENTAT(HduType.IMAGE, ValueType.REAL, "position angle of image y axis (deg. E of N)"), - - /** - * The value field shall contain a floating point number giving the position angle of the relevant aspect of - * telescope pointing axis and/or instrument on the sky in units of degrees east of north. It commonly applies to - * the orientation of a slit mask. - */ - PA_PNT(HduType.ANY, ValueType.REAL, "position angle of the pointing"), - - /** - * The value field gives the Right Ascension of the observation. It may be expressed either as a floating point - * number in units of decimal degrees, or as a character string in 'HH:MM:SS.sss' format where the decimal point and - * number of fractional digits are optional. The coordinate reference frame is given by the RADECSYS keyword, and - * the coordinate epoch is given by the EQUINOX keyword. Example: 180.6904 or '12:02:45.7'. - */ - RA(HduType.ANY, ValueType.STRING, "R.A. of the observation"), - - /** - * The value field shall contain a floating point number giving the nominal Right Ascension of the pointing - * direction in units of decimal degrees. The coordinate reference frame is given by the RADECSYS keyword, and the - * coordinate epoch is given by the EQUINOX keyword. The precise definition of this keyword is instrument-specific, - * but typically the nominal direction corresponds to the direction to which the instrument was requested to point. - * The RA_PNT keyword should be used to give the actual pointed direction. - */ - RA_NOM(HduType.ANY, ValueType.REAL, "nominal R.A. of the observation"), - - /** - * The value field shall contain a floating point number giving the Right Ascension of the observed object in units - * of decimal degrees. The coordinate reference frame is given by the RADECSYS keyword, and the coordinate epoch is - * given by the EQUINOX keyword. - */ - RA_OBJ(HduType.ANY, ValueType.REAL, "R.A. of the observed object"), - - /** - * The value field shall contain a floating point number giving the Right Ascension of the pointing direction in - * units of decimal degrees. The coordinate reference frame is given by the RADECSYS keyword, and the coordinate - * epoch is given by the EQUINOX keyword. The precise definition of this keyword is instrument-specific, but - * typically the pointed direction corresponds to the optical axis of the instrument. This keyword gives a mean - * value in cases where the pointing axis was not fixed during the entire observation. - */ - RA_PNT(HduType.ANY, ValueType.REAL, "R.A. of the pointed direction of the instrument"), - - /** - * The value field shall contain a floating point number giving the Right Ascension of the space craft (or telescope - * platform) X axis during the observation in decimal degrees. The coordinate reference frame is given by the - * RADECSYS keyword, and the coordinate epoch is given by the EQUINOX keyword. This keyword gives a mean value in - * cases where the axis was not fixed during the entire observation. - */ - RA_SCX(HduType.ANY, ValueType.REAL, "R.A. of the X spacecraft axis"), - - /** - * The value field shall contain a floating point number giving the Right Ascension of the space craft (or telescope - * platform) Y axis during the observation in decimal degrees. The coordinate reference frame is given by the - * RADECSYS keyword, and the coordinate epoch is given by the EQUINOX keyword. This keyword gives a mean value in - * cases where the axis was not fixed during the entire observation. - */ - RA_SCY(HduType.ANY, ValueType.REAL, "R.A. of the Y spacecraft axis"), - - /** - * The value field shall contain a floating point number giving the Right Ascension of the space craft (or telescope - * platform) Z axis during the observation in decimal degrees. The coordinate reference frame is given by the - * RADECSYS keyword, and the coordinate epoch is given by the EQUINOX keyword. This keyword gives a mean value in - * cases where the axis was not fixed during the entire observation. - */ - RA_SCZ(HduType.ANY, ValueType.REAL, "R.A. of the Z spacecraft axis"), - - /** - * The value field shall contain a floating point number giving the angle between the direction of the observation - * (e.g., the optical axis of the telescope or the position of the target) and the sun, measured in degrees. - */ - SUNANGLE(HduType.ANY, ValueType.REAL, "angle between the observation and the sun"), - - // FITS keywords that have been widely used within the astronomical community. - // These are the Keywords that describe the instrument that took the data. - - /** - * The value field shall contain a character string which gives the name of the instrumental aperture though which - * the observation was made. This keyword is typically used in instruments which have a selection of apertures which - * restrict the field of view of the detector. - */ - APERTURE(HduType.ANY, ValueType.STRING, "name of field of view aperture"), - - /** - * The value field shall contain a character string which identifies the configuration or mode of the pre-processing - * software that operated on the raw instrumental data to generate the data that is recorded in the FITS file. - * Example: some X-ray satellite data may be recorded in 'BRIGHT', 'FAINT', or 'FAST' data mode. - */ - DATAMODE(HduType.ANY, ValueType.STRING, "pre-processor data mode"), - - /** - * The value field shall contain a character string giving the name of the detector within the instrument that was - * used to make the observation. Example: 'CCD1' - */ - DETNAM(HduType.ANY, ValueType.STRING, "name of the detector used to make the observation"), - - /** - * The value field shall contain a character string which gives the name of the filter that was used during the - * observation to select or modify the radiation that was transmitted to the detector. More than 1 filter may be - * listed by using the FILTERn indexed keyword. The value 'none' or 'NONE' indicates that no filter was used. - */ - FILTER(HduType.ANY, ValueType.STRING, "name of filter used during the observation"), - - /** - * The value field of this indexed keyword shall contain a character string which gives the name of one of multiple - * filters that were used during the observation to select or modify the radiation that was transmitted to the - * detector. The value 'none' or 'NONE' indicates that no filter was used. - */ - FILTERn(HduType.ANY, ValueType.STRING, "name of filters used during the observation"), - - /** - * The value field shall contain a character string which gives the name of the defraction grating that was used - * during the observation. More than 1 grating may be listed by using the GRATINGn indexed keyword. The value 'none' - * or 'NONE' indicates that no grating was used. - */ - GRATING(HduType.ANY, ValueType.STRING, "name of the grating used during the observation."), - - /** - * The value field of this indexed keyword shall contain a character string which gives the name of one of multiple - * defraction gratings that were used during the observation. The value 'none' or 'NONE' indicates that no grating - * was used. - */ - GRATINGn(HduType.ANY, ValueType.STRING, "name of gratings used during the observation."), - - /** - * The value field shall contain a character string which gives the observing mode of the observation. This is used - * in cases where the instrument or detector can be configured to operate in different modes which significantly - * affect the resulting data. Examples: 'SLEW', 'RASTER', or 'POINTING' - */ - OBS_MODE(HduType.ANY, ValueType.STRING, "instrumental mode of the observation"), - - /** - * The value field shall contain an integer giving the data value at which the detector becomes saturated. This - * keyword value may differ from the maximum value implied by the BITPIX in that more bits may be allocated in the - * FITS pixel values than the detector can accommodate. - */ - SATURATE(HduType.ANY, ValueType.INTEGER, "Data value at which saturation occurs"), - - // FITS keywords that have been widely used within the astronomical community. - // These are the Keywords that describe the observation. - - /** - * The value field shall contain a character string that gives the date on which the observation ended. This keyword - * has the same format, and is used in conjunction with, the standard DATA-OBS keyword that gives the starting date - * of the observation. These 2 keywords may give either the calendar date using the 'yyyy-mm-dd' format, or may give - * the full date and time using the 'yyyy-mm-ddThh:mm:ss.sss' format. - */ - DATE_END("DATE-END", HduType.ANY, ValueType.STRING, "date of the end of observation"), - - /** - * The value field shall contain a floating point number giving the difference between the stop and start times of - * the observation in units of seconds. This keyword is synonymous with the TELAPSE keyword. - */ - ELAPTIME(HduType.ANY, ValueType.REAL, "elapsed time of the observation"), - - /** - * The value field shall contain a floating point number giving the exposure time of the observation in units of - * seconds. The exact definition of 'exposure time' is mission dependent and may, for example, include corrections - * for shutter open and close duration, detector dead time, vignetting, or other effects. This keyword is synonymous - * with the EXPTIME keyword. - */ - EXPOSURE(HduType.ANY, ValueType.REAL, "exposure time"), - - /** - * The value field shall contain a floating point number giving the exposure time of the observation in units of - * seconds. The exact definition of 'exposure time' is mission dependent and may, for example, include corrections - * for shutter open and close duration, detector dead time, vignetting, or other effects. This keyword is synonymous - * with the EXPOSURE keyword. - */ - EXPTIME(HduType.ANY, ValueType.REAL, "exposure time"), - - /** - * The value field shall contain a floating point number giving the total integrated exposure time in units of - * seconds corrected for detector 'dead time' effects which reduce the net efficiency of the detector. The ratio of - * LIVETIME/ONTIME gives the mean dead time correction during the observation, which lies in the range 0.0 to 1.0. - */ - LIVETIME(HduType.ANY, ValueType.REAL, "exposure time after deadtime correction"), - - /** - * The value field shall contain a floating point number giving the total integrated exposure time of the - * observation in units of seconds. ONTIME may be less than TELAPSE if there were intevals during the observation in - * which the target was not observed (e.g., the shutter was closed, or the detector power was turned off). - */ - ONTIME(HduType.ANY, ValueType.REAL, "integration time during the observation"), - - /** - * The value field shall contain a floating point number giving the difference between the stop and start times of - * the observation in units of seconds. This keyword is synonymous with the ELAPTIME keyword. - */ - TELAPSE(HduType.ANY, ValueType.REAL, "elapsed time of the observation"), - - /** - * The value field shall contain a character string that gives the time at which the observation ended. This keyword - * is used in conjunction with the DATE-END keyword to give the ending time of the observation; the DATE-END keyword - * gives the ending calendar date, with format 'yyyy-mm-dd', and TIME-END gives the time within that day using the - * format 'hh:mm:ss.sss...'. This keyword should not be used if the time is included directly as part of the - * DATE-END keyword value with the format 'yyyy-mm-ddThh:mm:ss.sss'. - */ - TIME_END("TIME-END", HduType.ANY, ValueType.STRING, "time at the end of the observation"), - - /** - * The value field shall contain a character string that gives the time at which the observation started. This - * keyword is used in conjunction with the standard DATE-OBS keyword to give the starting time of the observation; - * the DATE-OBS keyword gives the starting calendar date, with format 'yyyy-mm-dd', and TIME-OBS gives the time - * within that day using the format 'hh:mm:ss.sss...'. This keyword should not be used if the time is included - * directly as part of the DATE-OBS keyword value with the format 'yyyy-mm-ddThh:mm:ss.sss'. - */ - TIME_OBS("TIME-OBS", HduType.ANY, ValueType.STRING, "time at the start of the observation"); - - private val header: FitsHeader - - constructor(name: String, hduType: HduType, valueType: ValueType, comment: String) { - header = FitsHeaderImpl(name, hduType, valueType, comment) - } - - constructor(hduType: HduType, valueType: ValueType, comment: String) { - header = FitsHeaderImpl(name, hduType, valueType, comment) - } - - override val key - get() = header.key - - override val comment - get() = header.comment - - override val hduType - get() = header.hduType - - override val valueType - get() = header.valueType - - override fun n(vararg numbers: Int) = header.n(*numbers) - - companion object { - - @JvmStatic val NAXIS1 = NAXISn.n(1) - @JvmStatic val NAXIS2 = NAXISn.n(2) - @JvmStatic val NAXIS3 = NAXISn.n(3) - - @JvmStatic val CTYPE1 = CTYPEn.n(1) - @JvmStatic val CTYPE2 = CTYPEn.n(2) - - @JvmStatic val CRPIX1 = CRPIXn.n(1) - @JvmStatic val CRPIX2 = CRPIXn.n(2) - - @JvmStatic val CRVAL1 = CRVALn.n(1) - @JvmStatic val CRVAL2 = CRVALn.n(2) - - @JvmStatic val CDELT1 = CDELTn.n(1) - @JvmStatic val CDELT2 = CDELTn.n(2) - - @JvmStatic val CROTA1 = CROTAn.n(1) - @JvmStatic val CROTA2 = CROTAn.n(2) - } -} diff --git a/nebulosa-fits/src/main/kotlin/nebulosa/fits/WritableHeader.kt b/nebulosa-fits/src/main/kotlin/nebulosa/fits/WritableHeader.kt deleted file mode 100644 index 288459691..000000000 --- a/nebulosa-fits/src/main/kotlin/nebulosa/fits/WritableHeader.kt +++ /dev/null @@ -1,26 +0,0 @@ -package nebulosa.fits - -interface WritableHeader { - - fun clear() - - fun add(key: FitsHeader, value: Boolean): HeaderCard - - fun add(key: FitsHeader, value: Int): HeaderCard - - fun add(key: FitsHeader, value: Double): HeaderCard - - fun add(key: FitsHeader, value: String): HeaderCard - - fun add(key: String, value: Boolean, comment: String = ""): HeaderCard - - fun add(key: String, value: Int, comment: String = ""): HeaderCard - - fun add(key: String, value: Double, comment: String = ""): HeaderCard - - fun add(key: String, value: String, comment: String = ""): HeaderCard - - fun add(card: HeaderCard) - - fun delete(key: FitsHeader): Boolean -} diff --git a/nebulosa-fits/src/test/kotlin/FitsReadTest.kt b/nebulosa-fits/src/test/kotlin/FitsReadTest.kt index 09e27bf95..981768217 100644 --- a/nebulosa-fits/src/test/kotlin/FitsReadTest.kt +++ b/nebulosa-fits/src/test/kotlin/FitsReadTest.kt @@ -8,70 +8,70 @@ class FitsReadTest : FitsStringSpec() { init { "mono:8-bit" { - val hdu = NGC3344_MONO_8.filterIsInstance().first() + val hdu = NGC3344_MONO_8_FITS.filterIsInstance().first() hdu.width shouldBeExactly 256 hdu.height shouldBeExactly 256 hdu.size shouldBeExactly 1 hdu.bitpix shouldBe Bitpix.BYTE } "mono:16-bit" { - val hdu = NGC3344_MONO_16.filterIsInstance().first() + val hdu = NGC3344_MONO_16_FITS.filterIsInstance().first() hdu.width shouldBeExactly 256 hdu.height shouldBeExactly 256 hdu.size shouldBeExactly 1 hdu.bitpix shouldBe Bitpix.SHORT } "mono:32-bit" { - val hdu = NGC3344_MONO_32.filterIsInstance().first() + val hdu = NGC3344_MONO_32_FITS.filterIsInstance().first() hdu.width shouldBeExactly 256 hdu.height shouldBeExactly 256 hdu.size shouldBeExactly 1 hdu.bitpix shouldBe Bitpix.INTEGER } "mono:32-bit floating-point" { - val hdu = NGC3344_MONO_F32.filterIsInstance().first() + val hdu = NGC3344_MONO_F32_FITS.filterIsInstance().first() hdu.width shouldBeExactly 256 hdu.height shouldBeExactly 256 hdu.size shouldBeExactly 1 hdu.bitpix shouldBe Bitpix.FLOAT } "mono:64-bit floating-point" { - val hdu = NGC3344_MONO_F64.filterIsInstance().first() + val hdu = NGC3344_MONO_F64_FITS.filterIsInstance().first() hdu.width shouldBeExactly 256 hdu.height shouldBeExactly 256 hdu.size shouldBeExactly 1 hdu.bitpix shouldBe Bitpix.DOUBLE } "color:8-bit" { - val hdu = NGC3344_COLOR_8.filterIsInstance().first() + val hdu = NGC3344_COLOR_8_FITS.filterIsInstance().first() hdu.width shouldBeExactly 256 hdu.height shouldBeExactly 256 hdu.size shouldBeExactly 4 hdu.bitpix shouldBe Bitpix.BYTE } "color:16-bit" { - val hdu = NGC3344_COLOR_16.filterIsInstance().first() + val hdu = NGC3344_COLOR_16_FITS.filterIsInstance().first() hdu.width shouldBeExactly 256 hdu.height shouldBeExactly 256 hdu.size shouldBeExactly 4 hdu.bitpix shouldBe Bitpix.SHORT } "color:32-bit" { - val hdu = NGC3344_COLOR_32.filterIsInstance().first() + val hdu = NGC3344_COLOR_32_FITS.filterIsInstance().first() hdu.width shouldBeExactly 256 hdu.height shouldBeExactly 256 hdu.size shouldBeExactly 4 hdu.bitpix shouldBe Bitpix.INTEGER } "color:32-bit floating-point" { - val hdu = NGC3344_COLOR_F32.filterIsInstance().first() + val hdu = NGC3344_COLOR_F32_FITS.filterIsInstance().first() hdu.width shouldBeExactly 256 hdu.height shouldBeExactly 256 hdu.size shouldBeExactly 4 hdu.bitpix shouldBe Bitpix.FLOAT } "color:64-bit floating-point" { - val hdu = NGC3344_COLOR_F64.filterIsInstance().first() + val hdu = NGC3344_COLOR_F64_FITS.filterIsInstance().first() hdu.width shouldBeExactly 256 hdu.height shouldBeExactly 256 hdu.size shouldBeExactly 4 diff --git a/nebulosa-fits/src/test/kotlin/FitsWriteTest.kt b/nebulosa-fits/src/test/kotlin/FitsWriteTest.kt index 95b084b0c..42597f91d 100644 --- a/nebulosa-fits/src/test/kotlin/FitsWriteTest.kt +++ b/nebulosa-fits/src/test/kotlin/FitsWriteTest.kt @@ -10,7 +10,7 @@ class FitsWriteTest : FitsStringSpec() { init { "mono" { - val hdu0 = NGC3344_MONO_8.filterIsInstance().first() + val hdu0 = NGC3344_MONO_8_FITS.filterIsInstance().first() val data = ByteArray(69120) hdu0.write(data.sink()) data.toByteString(2880, 66240).md5().hex() shouldBe "e1735e21c94dc49885fabc429406e573" diff --git a/nebulosa-guiding-internal/build.gradle.kts b/nebulosa-guiding-internal/build.gradle.kts index 903eaf776..e2464b95d 100644 --- a/nebulosa-guiding-internal/build.gradle.kts +++ b/nebulosa-guiding-internal/build.gradle.kts @@ -6,7 +6,7 @@ plugins { dependencies { api(project(":nebulosa-common")) api(project(":nebulosa-math")) - api(project(":nebulosa-imaging")) + api(project(":nebulosa-image")) api(project(":nebulosa-guiding")) implementation(project(":nebulosa-log")) testImplementation(project(":nebulosa-test")) diff --git a/nebulosa-guiding-internal/src/main/kotlin/nebulosa/guiding/internal/GuiderListener.kt b/nebulosa-guiding-internal/src/main/kotlin/nebulosa/guiding/internal/GuiderListener.kt index 2e57db51b..2a15333fa 100644 --- a/nebulosa-guiding-internal/src/main/kotlin/nebulosa/guiding/internal/GuiderListener.kt +++ b/nebulosa-guiding-internal/src/main/kotlin/nebulosa/guiding/internal/GuiderListener.kt @@ -1,7 +1,7 @@ package nebulosa.guiding.internal import nebulosa.guiding.GuideDirection -import nebulosa.imaging.Image +import nebulosa.image.Image interface GuiderListener { diff --git a/nebulosa-guiding-internal/src/main/kotlin/nebulosa/guiding/internal/InternalGuider.kt b/nebulosa-guiding-internal/src/main/kotlin/nebulosa/guiding/internal/InternalGuider.kt index 0c6316e79..6328418e1 100644 --- a/nebulosa-guiding-internal/src/main/kotlin/nebulosa/guiding/internal/InternalGuider.kt +++ b/nebulosa-guiding-internal/src/main/kotlin/nebulosa/guiding/internal/InternalGuider.kt @@ -1,6 +1,6 @@ package nebulosa.guiding.internal -import nebulosa.imaging.Image +import nebulosa.image.Image interface InternalGuider : Iterable { diff --git a/nebulosa-guiding-internal/src/main/kotlin/nebulosa/guiding/internal/MultiStarGuider.kt b/nebulosa-guiding-internal/src/main/kotlin/nebulosa/guiding/internal/MultiStarGuider.kt index 9ce1a0ecc..6462014ae 100644 --- a/nebulosa-guiding-internal/src/main/kotlin/nebulosa/guiding/internal/MultiStarGuider.kt +++ b/nebulosa-guiding-internal/src/main/kotlin/nebulosa/guiding/internal/MultiStarGuider.kt @@ -2,8 +2,8 @@ package nebulosa.guiding.internal import nebulosa.constants.PIOVERTWO import nebulosa.guiding.GuideDirection -import nebulosa.imaging.Image -import nebulosa.imaging.algorithms.transformation.convolution.Mean +import nebulosa.image.Image +import nebulosa.image.algorithms.transformation.convolution.Mean import nebulosa.log.loggerFor import nebulosa.math.cos import nebulosa.math.sin diff --git a/nebulosa-guiding-internal/src/main/kotlin/nebulosa/guiding/internal/Star.kt b/nebulosa-guiding-internal/src/main/kotlin/nebulosa/guiding/internal/Star.kt index a0f736c52..e24f0b2f6 100644 --- a/nebulosa-guiding-internal/src/main/kotlin/nebulosa/guiding/internal/Star.kt +++ b/nebulosa-guiding-internal/src/main/kotlin/nebulosa/guiding/internal/Star.kt @@ -1,7 +1,7 @@ package nebulosa.guiding.internal -import nebulosa.imaging.Image -import nebulosa.imaging.algorithms.computation.hfd.HFD +import nebulosa.image.Image +import nebulosa.image.algorithms.computation.hfd.HFD import kotlin.math.roundToInt /** diff --git a/nebulosa-hips2fits/build.gradle.kts b/nebulosa-hips2fits/build.gradle.kts index b4d5f2298..47b29a48e 100644 --- a/nebulosa-hips2fits/build.gradle.kts +++ b/nebulosa-hips2fits/build.gradle.kts @@ -6,7 +6,7 @@ plugins { dependencies { api(project(":nebulosa-math")) api(project(":nebulosa-retrofit")) - testImplementation(project(":nebulosa-imaging")) + testImplementation(project(":nebulosa-image")) testImplementation(project(":nebulosa-test")) } diff --git a/nebulosa-image-format/build.gradle.kts b/nebulosa-image-format/build.gradle.kts new file mode 100644 index 000000000..bc8cae46b --- /dev/null +++ b/nebulosa-image-format/build.gradle.kts @@ -0,0 +1,18 @@ +plugins { + kotlin("jvm") + id("maven-publish") +} + +dependencies { + api(project(":nebulosa-io")) + implementation(project(":nebulosa-log")) + testImplementation(project(":nebulosa-test")) +} + +publishing { + publications { + create("pluginMaven") { + from(components["java"]) + } + } +} diff --git a/nebulosa-image-format/src/main/kotlin/nebulosa/image/format/AbstractHeader.kt b/nebulosa-image-format/src/main/kotlin/nebulosa/image/format/AbstractHeader.kt new file mode 100644 index 000000000..7862fb539 --- /dev/null +++ b/nebulosa-image-format/src/main/kotlin/nebulosa/image/format/AbstractHeader.kt @@ -0,0 +1,39 @@ +package nebulosa.image.format + +import java.io.Serializable +import java.util.* + +abstract class AbstractHeader protected constructor(@JvmField protected val cards: LinkedList) : + Header, Collection by cards, Serializable { + + constructor() : this(LinkedList()) + + constructor(cards: Collection) : this(LinkedList(cards)) + + abstract fun readOnly(): Header + + override fun clear() { + cards.clear() + } + + override fun delete(key: String): Boolean { + return cards.removeIf { it.key == key } + } + + override fun equals(other: Any?): Boolean { + if (this === other) return true + if (other !is AbstractHeader) return false + + if (cards != other.cards) return false + + return true + } + + override fun hashCode(): Int { + return cards.hashCode() + } + + override fun toString(): String { + return "Header(cards=$cards)" + } +} diff --git a/nebulosa-image-format/src/main/kotlin/nebulosa/image/format/Hdu.kt b/nebulosa-image-format/src/main/kotlin/nebulosa/image/format/Hdu.kt new file mode 100644 index 000000000..462ba4cea --- /dev/null +++ b/nebulosa-image-format/src/main/kotlin/nebulosa/image/format/Hdu.kt @@ -0,0 +1,8 @@ +package nebulosa.image.format + +interface Hdu { + + val header: ReadableHeader + + val data: T +} diff --git a/nebulosa-image-format/src/main/kotlin/nebulosa/image/format/Header.kt b/nebulosa-image-format/src/main/kotlin/nebulosa/image/format/Header.kt new file mode 100644 index 000000000..bccb00803 --- /dev/null +++ b/nebulosa-image-format/src/main/kotlin/nebulosa/image/format/Header.kt @@ -0,0 +1,44 @@ +package nebulosa.image.format + +import nebulosa.io.SeekableSource +import okio.Sink + +interface Header : ReadableHeader, WritableHeader, Cloneable { + + public override fun clone(): Header + + data object Empty : Header, Iterator { + + override fun clone() = this + + override fun contains(element: HeaderCard) = false + + override val size = 0 + + override fun containsAll(elements: Collection) = false + + override fun isEmpty() = true + + override fun iterator() = this + + override fun write(sink: Sink) = Unit + + override fun clear() = Unit + + override fun add(key: String, value: Boolean, comment: String) = Unit + + override fun add(key: String, value: Int, comment: String) = Unit + + override fun add(key: String, value: Double, comment: String) = Unit + + override fun add(key: String, value: String, comment: String) = Unit + + override fun delete(key: String) = false + + override fun read(source: SeekableSource) = Unit + + override fun hasNext() = false + + override fun next() = TODO("Unsupported operation") + } +} diff --git a/nebulosa-image-format/src/main/kotlin/nebulosa/image/format/HeaderCard.kt b/nebulosa-image-format/src/main/kotlin/nebulosa/image/format/HeaderCard.kt new file mode 100644 index 000000000..86c8687d5 --- /dev/null +++ b/nebulosa-image-format/src/main/kotlin/nebulosa/image/format/HeaderCard.kt @@ -0,0 +1,28 @@ +package nebulosa.image.format + +interface HeaderCard : HeaderKey, HeaderValue, Map.Entry { + + val isCommentStyle: Boolean + + val isKeyValuePair: Boolean + + val isBooleanType: Boolean + + val isStringType: Boolean + + val isDecimalType: Boolean + + val isIntegerType: Boolean + + val isNumericType + get() = isDecimalType || isIntegerType + + val isBlank: Boolean + + companion object { + + inline fun HeaderCard.getValue(defaultValue: T): T { + return getValue(T::class.java, defaultValue) + } + } +} diff --git a/nebulosa-image-format/src/main/kotlin/nebulosa/image/format/HeaderKey.kt b/nebulosa-image-format/src/main/kotlin/nebulosa/image/format/HeaderKey.kt new file mode 100644 index 000000000..842555ffe --- /dev/null +++ b/nebulosa-image-format/src/main/kotlin/nebulosa/image/format/HeaderKey.kt @@ -0,0 +1,8 @@ +package nebulosa.image.format + +interface HeaderKey { + + val key: String + + val comment: String +} diff --git a/nebulosa-image-format/src/main/kotlin/nebulosa/image/format/HeaderValue.kt b/nebulosa-image-format/src/main/kotlin/nebulosa/image/format/HeaderValue.kt new file mode 100644 index 000000000..4b0edb4ae --- /dev/null +++ b/nebulosa-image-format/src/main/kotlin/nebulosa/image/format/HeaderValue.kt @@ -0,0 +1,10 @@ +package nebulosa.image.format + +interface HeaderValue { + + val value: String + + fun getValue(asType: Class, defaultValue: T): T + + fun formattedValue(): String +} diff --git a/nebulosa-image-format/src/main/kotlin/nebulosa/image/format/ImageChannel.kt b/nebulosa-image-format/src/main/kotlin/nebulosa/image/format/ImageChannel.kt new file mode 100644 index 000000000..d09c27d4b --- /dev/null +++ b/nebulosa-image-format/src/main/kotlin/nebulosa/image/format/ImageChannel.kt @@ -0,0 +1,8 @@ +package nebulosa.image.format + +enum class ImageChannel(val index: Int) { + GRAY(0), + RED(0), + GREEN(1), + BLUE(2), +} diff --git a/nebulosa-image-format/src/main/kotlin/nebulosa/image/format/ImageData.kt b/nebulosa-image-format/src/main/kotlin/nebulosa/image/format/ImageData.kt new file mode 100644 index 000000000..feb827090 --- /dev/null +++ b/nebulosa-image-format/src/main/kotlin/nebulosa/image/format/ImageData.kt @@ -0,0 +1,16 @@ +package nebulosa.image.format + +interface ImageData { + + val width: Int + + val height: Int + + val numberOfChannels: Int + + val red: FloatArray + + val green: FloatArray + + val blue: FloatArray +} diff --git a/nebulosa-image-format/src/main/kotlin/nebulosa/image/format/ImageFormat.kt b/nebulosa-image-format/src/main/kotlin/nebulosa/image/format/ImageFormat.kt new file mode 100644 index 000000000..d24b6db98 --- /dev/null +++ b/nebulosa-image-format/src/main/kotlin/nebulosa/image/format/ImageFormat.kt @@ -0,0 +1,11 @@ +package nebulosa.image.format + +import nebulosa.io.SeekableSource +import okio.Sink + +interface ImageFormat { + + fun read(source: SeekableSource): List> + + fun write(sink: Sink, hdus: Iterable>) +} diff --git a/nebulosa-image-format/src/main/kotlin/nebulosa/image/format/ImageHdu.kt b/nebulosa-image-format/src/main/kotlin/nebulosa/image/format/ImageHdu.kt new file mode 100644 index 000000000..140125c46 --- /dev/null +++ b/nebulosa-image-format/src/main/kotlin/nebulosa/image/format/ImageHdu.kt @@ -0,0 +1,13 @@ +package nebulosa.image.format + +interface ImageHdu : Hdu { + + val width: Int + + val height: Int + + val numberOfChannels: Int + + val isMono + get() = numberOfChannels == 1 +} diff --git a/nebulosa-image-format/src/main/kotlin/nebulosa/image/format/ImageSink.kt b/nebulosa-image-format/src/main/kotlin/nebulosa/image/format/ImageSink.kt new file mode 100644 index 000000000..a4c66941d --- /dev/null +++ b/nebulosa-image-format/src/main/kotlin/nebulosa/image/format/ImageSink.kt @@ -0,0 +1,8 @@ +package nebulosa.image.format + +import okio.Sink + +interface ImageSink { + + fun write(sink: Sink) +} diff --git a/nebulosa-image-format/src/main/kotlin/nebulosa/image/format/ImageSource.kt b/nebulosa-image-format/src/main/kotlin/nebulosa/image/format/ImageSource.kt new file mode 100644 index 000000000..d2639348c --- /dev/null +++ b/nebulosa-image-format/src/main/kotlin/nebulosa/image/format/ImageSource.kt @@ -0,0 +1,8 @@ +package nebulosa.image.format + +import nebulosa.io.SeekableSource + +interface ImageSource { + + fun read(source: SeekableSource) +} diff --git a/nebulosa-fits/src/main/kotlin/nebulosa/fits/ReadableHeader.kt b/nebulosa-image-format/src/main/kotlin/nebulosa/image/format/ReadableHeader.kt similarity index 56% rename from nebulosa-fits/src/main/kotlin/nebulosa/fits/ReadableHeader.kt rename to nebulosa-image-format/src/main/kotlin/nebulosa/image/format/ReadableHeader.kt index 39c9774f1..6eb0f0d0a 100644 --- a/nebulosa-fits/src/main/kotlin/nebulosa/fits/ReadableHeader.kt +++ b/nebulosa-image-format/src/main/kotlin/nebulosa/image/format/ReadableHeader.kt @@ -1,120 +1,120 @@ -package nebulosa.fits +package nebulosa.image.format -interface ReadableHeader : Collection { +interface ReadableHeader : Collection, ImageSink { operator fun contains(key: String): Boolean { return any { it.key == key } } - operator fun contains(key: FitsHeader): Boolean { + operator fun contains(key: HeaderKey): Boolean { return key.key in this } - fun getBoolean(key: String, defaultValue: Boolean = false): Boolean { + fun getBoolean(key: String, defaultValue: Boolean): Boolean { val card = firstOrNull { it.key == key } ?: return defaultValue - return card.getValue(defaultValue) + return card.getValue(Boolean::class.javaObjectType, defaultValue) } fun getBooleanOrNull(key: String): Boolean? { val card = firstOrNull { it.key == key } ?: return null - return card.getValue(null) - } - - fun getBoolean(key: FitsHeader, defaultValue: Boolean = false): Boolean { - return getBoolean(key.key, defaultValue) - } - - fun getBooleanOrNull(key: FitsHeader): Boolean? { - return getBooleanOrNull(key.key) + return card.getValue(Boolean::class.javaObjectType, null) } fun getInt(key: String, defaultValue: Int): Int { val card = firstOrNull { it.key == key } ?: return defaultValue - return card.getValue(defaultValue) + return card.getValue(Int::class.javaObjectType, defaultValue) } fun getIntOrNull(key: String): Int? { val card = firstOrNull { it.key == key } ?: return null - return card.getValue(null) + return card.getValue(Int::class.javaObjectType, null) } - fun getInt(key: FitsHeader, defaultValue: Int): Int { - return getInt(key.key, defaultValue) + fun getLong(key: String, defaultValue: Long): Long { + val card = firstOrNull { it.key == key } ?: return defaultValue + return card.getValue(Long::class.javaObjectType, defaultValue) } - fun getIntOrNull(key: FitsHeader): Int? { - return getIntOrNull(key.key) + fun getLongOrNull(key: String): Long? { + val card = firstOrNull { it.key == key } ?: return null + return card.getValue(Long::class.javaObjectType, null) } - fun getLong(key: String, defaultValue: Long): Long { + fun getFloat(key: String, defaultValue: Float): Float { val card = firstOrNull { it.key == key } ?: return defaultValue - return card.getValue(defaultValue) + return card.getValue(Float::class.javaObjectType, defaultValue) } - fun getLongOrNull(key: String): Long? { + fun getFloatOrNull(key: String): Float? { val card = firstOrNull { it.key == key } ?: return null - return card.getValue(null) + return card.getValue(Float::class.javaObjectType, null) } - fun getLong(key: FitsHeader, defaultValue: Long): Long { - return getLong(key.key, defaultValue) + fun getDouble(key: String, defaultValue: Double): Double { + val card = firstOrNull { it.key == key } ?: return defaultValue + return card.getValue(Double::class.javaObjectType, defaultValue) } - fun getLongOrNull(key: FitsHeader): Long? { - return getLongOrNull(key.key) + fun getDoubleOrNull(key: String): Double? { + val card = firstOrNull { it.key == key } ?: return null + return card.getValue(Double::class.javaObjectType, null) } - fun getFloat(key: String, defaultValue: Float): Float { + fun getString(key: String, defaultValue: String): String { val card = firstOrNull { it.key == key } ?: return defaultValue - return card.getValue(defaultValue) + return card.getValue(String::class.javaObjectType, defaultValue) } - fun getFloatOrNull(key: String): Float? { + fun getStringOrNull(key: String): String? { val card = firstOrNull { it.key == key } ?: return null - return card.getValue(null) + return card.getValue(String::class.javaObjectType, null) } - fun getFloat(key: FitsHeader, defaultValue: Float): Float { - return getFloat(key.key, defaultValue) + fun getBoolean(key: HeaderKey, defaultValue: Boolean = false): Boolean { + return getBoolean(key.key, defaultValue) } - fun getFloatOrNull(key: FitsHeader): Float? { - return getFloatOrNull(key.key) + fun getBooleanOrNull(key: HeaderKey): Boolean? { + return getBooleanOrNull(key.key) } - fun getDouble(key: String, defaultValue: Double): Double { - val card = firstOrNull { it.key == key } ?: return defaultValue - return card.getValue(defaultValue) + fun getInt(key: HeaderKey, defaultValue: Int): Int { + return getInt(key.key, defaultValue) } - fun getDoubleOrNull(key: String): Double? { - val card = firstOrNull { it.key == key } ?: return null - return card.getValue(null) + fun getIntOrNull(key: HeaderKey): Int? { + return getIntOrNull(key.key) } - fun getDouble(key: FitsHeader, defaultValue: Double): Double { - return getDouble(key.key, defaultValue) + fun getLong(key: HeaderKey, defaultValue: Long): Long { + return getLong(key.key, defaultValue) } - fun getDoubleOrNull(key: FitsHeader): Double? { - return getDoubleOrNull(key.key) + fun getLongOrNull(key: HeaderKey): Long? { + return getLongOrNull(key.key) } - fun getString(key: String, defaultValue: String): String { - val card = firstOrNull { it.key == key } ?: return defaultValue - return card.getValue(defaultValue) + fun getFloat(key: HeaderKey, defaultValue: Float): Float { + return getFloat(key.key, defaultValue) } - fun getStringOrNull(key: String): String? { - val card = firstOrNull { it.key == key } ?: return null - return card.getValue(null) + fun getFloatOrNull(key: HeaderKey): Float? { + return getFloatOrNull(key.key) + } + + fun getDouble(key: HeaderKey, defaultValue: Double): Double { + return getDouble(key.key, defaultValue) + } + + fun getDoubleOrNull(key: HeaderKey): Double? { + return getDoubleOrNull(key.key) } - fun getString(key: FitsHeader, defaultValue: String): String { + fun getString(key: HeaderKey, defaultValue: String): String { return getString(key.key, defaultValue) } - fun getStringOrNull(key: FitsHeader): String? { + fun getStringOrNull(key: HeaderKey): String? { return getStringOrNull(key.key) } } diff --git a/nebulosa-image-format/src/main/kotlin/nebulosa/image/format/WritableHeader.kt b/nebulosa-image-format/src/main/kotlin/nebulosa/image/format/WritableHeader.kt new file mode 100644 index 000000000..07d105f77 --- /dev/null +++ b/nebulosa-image-format/src/main/kotlin/nebulosa/image/format/WritableHeader.kt @@ -0,0 +1,26 @@ +package nebulosa.image.format + +interface WritableHeader : ImageSource { + + fun clear() + + fun add(key: HeaderKey, value: Boolean) = add(key.key, value, key.comment) + + fun add(key: HeaderKey, value: Int) = add(key.key, value, key.comment) + + fun add(key: HeaderKey, value: Double) = add(key.key, value, key.comment) + + fun add(key: HeaderKey, value: String) = add(key.key, value, key.comment) + + fun add(key: String, value: Boolean, comment: String = "") + + fun add(key: String, value: Int, comment: String = "") + + fun add(key: String, value: Double, comment: String = "") + + fun add(key: String, value: String, comment: String = "") + + fun delete(key: HeaderKey) = delete(key.key) + + fun delete(key: String): Boolean +} diff --git a/nebulosa-imaging/build.gradle.kts b/nebulosa-image/build.gradle.kts similarity index 100% rename from nebulosa-imaging/build.gradle.kts rename to nebulosa-image/build.gradle.kts diff --git a/nebulosa-imaging/src/main/kotlin/nebulosa/imaging/Float8bitsDataBuffer.kt b/nebulosa-image/src/main/kotlin/nebulosa/image/Float8bitsDataBuffer.kt similarity index 98% rename from nebulosa-imaging/src/main/kotlin/nebulosa/imaging/Float8bitsDataBuffer.kt rename to nebulosa-image/src/main/kotlin/nebulosa/image/Float8bitsDataBuffer.kt index 3b3cb3a53..6a965a92b 100644 --- a/nebulosa-imaging/src/main/kotlin/nebulosa/imaging/Float8bitsDataBuffer.kt +++ b/nebulosa-image/src/main/kotlin/nebulosa/image/Float8bitsDataBuffer.kt @@ -1,4 +1,4 @@ -package nebulosa.imaging +package nebulosa.image import java.awt.image.DataBuffer diff --git a/nebulosa-imaging/src/main/kotlin/nebulosa/imaging/Image.kt b/nebulosa-image/src/main/kotlin/nebulosa/image/Image.kt similarity index 90% rename from nebulosa-imaging/src/main/kotlin/nebulosa/imaging/Image.kt rename to nebulosa-image/src/main/kotlin/nebulosa/image/Image.kt index 405896762..154fe3501 100644 --- a/nebulosa-imaging/src/main/kotlin/nebulosa/imaging/Image.kt +++ b/nebulosa-image/src/main/kotlin/nebulosa/image/Image.kt @@ -1,12 +1,13 @@ -package nebulosa.imaging +package nebulosa.image import nebulosa.fits.* -import nebulosa.imaging.algorithms.ComputationAlgorithm -import nebulosa.imaging.algorithms.TransformAlgorithm -import nebulosa.imaging.algorithms.transform -import nebulosa.imaging.algorithms.transformation.CfaPattern -import nebulosa.imaging.algorithms.transformation.Debayer -import nebulosa.imaging.algorithms.transformation.Grayscale +import nebulosa.image.algorithms.ComputationAlgorithm +import nebulosa.image.algorithms.TransformAlgorithm +import nebulosa.image.algorithms.transform +import nebulosa.image.algorithms.transformation.CfaPattern +import nebulosa.image.algorithms.transformation.Debayer +import nebulosa.image.algorithms.transformation.Grayscale +import nebulosa.image.format.Header import okio.Sink import java.awt.color.ColorSpace import java.awt.image.* @@ -240,10 +241,10 @@ class Image( } with(image.header) { - add(Standard.NAXIS, 3) - add(Standard.NAXIS1, width) - add(Standard.NAXIS2, height) - add(Standard.NAXIS3, 3) + add(FitsKeywordDictionary.NAXIS, 3) + add(FitsKeywordDictionary.NAXIS1, width) + add(FitsKeywordDictionary.NAXIS2, height) + add(FitsKeywordDictionary.NAXIS3, 3) } return image @@ -359,21 +360,21 @@ class Image( @JvmStatic fun open(bufferedImage: BufferedImage): Image { - val header = Header() + val header = FitsHeader() val width = bufferedImage.width val height = bufferedImage.height val mono = bufferedImage.type == TYPE_BYTE_GRAY - || bufferedImage.type == TYPE_USHORT_GRAY - - header.add(Standard.SIMPLE, true) - header.add(Standard.BITPIX, Bitpix.FLOAT.code) - header.add(Standard.NAXIS, if (mono) 2 else 3) - header.add(Standard.NAXISn.n(1), width) - header.add(Standard.NAXISn.n(2), height) - if (!mono) header.add(Standard.NAXISn.n(3), 3) - header.add(Standard.BSCALE, 1.0) - header.add(Standard.BZERO, 0.0) - header.add(Standard.EXTEND, true) + || bufferedImage.type == TYPE_USHORT_GRAY + + header.add(FitsKeywordDictionary.SIMPLE, true) + header.add(FitsKeywordDictionary.BITPIX, Bitpix.FLOAT.code) + header.add(FitsKeywordDictionary.NAXIS, if (mono) 2 else 3) + header.add(FitsKeywordDictionary.NAXISn.n(1), width) + header.add(FitsKeywordDictionary.NAXISn.n(2), height) + if (!mono) header.add(FitsKeywordDictionary.NAXISn.n(3), 3) + header.add(FitsKeywordDictionary.BSCALE, 1.0) + header.add(FitsKeywordDictionary.BZERO, 0.0) + header.add(FitsKeywordDictionary.EXTEND, true) val image = Image(width, height, header, mono) diff --git a/nebulosa-imaging/src/main/kotlin/nebulosa/imaging/ImageChannel.kt b/nebulosa-image/src/main/kotlin/nebulosa/image/ImageChannel.kt similarity index 88% rename from nebulosa-imaging/src/main/kotlin/nebulosa/imaging/ImageChannel.kt rename to nebulosa-image/src/main/kotlin/nebulosa/image/ImageChannel.kt index 1343276fe..e16b4a0c0 100644 --- a/nebulosa-imaging/src/main/kotlin/nebulosa/imaging/ImageChannel.kt +++ b/nebulosa-image/src/main/kotlin/nebulosa/image/ImageChannel.kt @@ -1,4 +1,4 @@ -package nebulosa.imaging +package nebulosa.image enum class ImageChannel(@JvmField val offset: Int) { RED(0), diff --git a/nebulosa-imaging/src/main/kotlin/nebulosa/imaging/algorithms/AlgorithmHelper.kt b/nebulosa-image/src/main/kotlin/nebulosa/image/algorithms/AlgorithmHelper.kt similarity index 87% rename from nebulosa-imaging/src/main/kotlin/nebulosa/imaging/algorithms/AlgorithmHelper.kt rename to nebulosa-image/src/main/kotlin/nebulosa/image/algorithms/AlgorithmHelper.kt index d5d890e05..be556492d 100644 --- a/nebulosa-imaging/src/main/kotlin/nebulosa/imaging/algorithms/AlgorithmHelper.kt +++ b/nebulosa-image/src/main/kotlin/nebulosa/image/algorithms/AlgorithmHelper.kt @@ -1,6 +1,6 @@ -package nebulosa.imaging.algorithms +package nebulosa.image.algorithms -import nebulosa.imaging.Image +import nebulosa.image.Image @JvmName("apply") @Suppress("NOTHING_TO_INLINE") diff --git a/nebulosa-imaging/src/main/kotlin/nebulosa/imaging/algorithms/ComputationAlgorithm.kt b/nebulosa-image/src/main/kotlin/nebulosa/image/algorithms/ComputationAlgorithm.kt similarity index 55% rename from nebulosa-imaging/src/main/kotlin/nebulosa/imaging/algorithms/ComputationAlgorithm.kt rename to nebulosa-image/src/main/kotlin/nebulosa/image/algorithms/ComputationAlgorithm.kt index 4d8d03ec4..3872b862c 100644 --- a/nebulosa-imaging/src/main/kotlin/nebulosa/imaging/algorithms/ComputationAlgorithm.kt +++ b/nebulosa-image/src/main/kotlin/nebulosa/image/algorithms/ComputationAlgorithm.kt @@ -1,6 +1,6 @@ -package nebulosa.imaging.algorithms +package nebulosa.image.algorithms -import nebulosa.imaging.Image +import nebulosa.image.Image fun interface ComputationAlgorithm { diff --git a/nebulosa-imaging/src/main/kotlin/nebulosa/imaging/algorithms/TransformAlgorithm.kt b/nebulosa-image/src/main/kotlin/nebulosa/image/algorithms/TransformAlgorithm.kt similarity index 84% rename from nebulosa-imaging/src/main/kotlin/nebulosa/imaging/algorithms/TransformAlgorithm.kt rename to nebulosa-image/src/main/kotlin/nebulosa/image/algorithms/TransformAlgorithm.kt index b861062b9..53230446a 100644 --- a/nebulosa-imaging/src/main/kotlin/nebulosa/imaging/algorithms/TransformAlgorithm.kt +++ b/nebulosa-image/src/main/kotlin/nebulosa/image/algorithms/TransformAlgorithm.kt @@ -1,6 +1,6 @@ -package nebulosa.imaging.algorithms +package nebulosa.image.algorithms -import nebulosa.imaging.Image +import nebulosa.image.Image fun interface TransformAlgorithm { diff --git a/nebulosa-imaging/src/main/kotlin/nebulosa/imaging/algorithms/computation/Histogram.kt b/nebulosa-image/src/main/kotlin/nebulosa/image/algorithms/computation/Histogram.kt similarity index 73% rename from nebulosa-imaging/src/main/kotlin/nebulosa/imaging/algorithms/computation/Histogram.kt rename to nebulosa-image/src/main/kotlin/nebulosa/image/algorithms/computation/Histogram.kt index 18307233b..65e7948ba 100644 --- a/nebulosa-imaging/src/main/kotlin/nebulosa/imaging/algorithms/computation/Histogram.kt +++ b/nebulosa-image/src/main/kotlin/nebulosa/image/algorithms/computation/Histogram.kt @@ -1,9 +1,9 @@ -package nebulosa.imaging.algorithms.computation +package nebulosa.image.algorithms.computation -import nebulosa.imaging.Image -import nebulosa.imaging.Image.Companion.forEach -import nebulosa.imaging.ImageChannel -import nebulosa.imaging.algorithms.ComputationAlgorithm +import nebulosa.image.Image +import nebulosa.image.Image.Companion.forEach +import nebulosa.image.ImageChannel +import nebulosa.image.algorithms.ComputationAlgorithm import kotlin.math.max import kotlin.math.min diff --git a/nebulosa-imaging/src/main/kotlin/nebulosa/imaging/algorithms/computation/Median.kt b/nebulosa-image/src/main/kotlin/nebulosa/image/algorithms/computation/Median.kt similarity index 85% rename from nebulosa-imaging/src/main/kotlin/nebulosa/imaging/algorithms/computation/Median.kt rename to nebulosa-image/src/main/kotlin/nebulosa/image/algorithms/computation/Median.kt index d5b846ad1..0357ad1ec 100644 --- a/nebulosa-imaging/src/main/kotlin/nebulosa/imaging/algorithms/computation/Median.kt +++ b/nebulosa-image/src/main/kotlin/nebulosa/image/algorithms/computation/Median.kt @@ -1,9 +1,9 @@ -package nebulosa.imaging.algorithms.computation +package nebulosa.image.algorithms.computation -import nebulosa.imaging.Image -import nebulosa.imaging.Image.Companion.forEach -import nebulosa.imaging.ImageChannel -import nebulosa.imaging.algorithms.ComputationAlgorithm +import nebulosa.image.Image +import nebulosa.image.Image.Companion.forEach +import nebulosa.image.ImageChannel +import nebulosa.image.algorithms.ComputationAlgorithm import kotlin.math.max import kotlin.math.min diff --git a/nebulosa-imaging/src/main/kotlin/nebulosa/imaging/algorithms/computation/MedianAbsoluteDeviation.kt b/nebulosa-image/src/main/kotlin/nebulosa/image/algorithms/computation/MedianAbsoluteDeviation.kt similarity index 82% rename from nebulosa-imaging/src/main/kotlin/nebulosa/imaging/algorithms/computation/MedianAbsoluteDeviation.kt rename to nebulosa-image/src/main/kotlin/nebulosa/image/algorithms/computation/MedianAbsoluteDeviation.kt index 49cb2a56c..0f7984da4 100644 --- a/nebulosa-imaging/src/main/kotlin/nebulosa/imaging/algorithms/computation/MedianAbsoluteDeviation.kt +++ b/nebulosa-image/src/main/kotlin/nebulosa/image/algorithms/computation/MedianAbsoluteDeviation.kt @@ -1,9 +1,9 @@ -package nebulosa.imaging.algorithms.computation +package nebulosa.image.algorithms.computation -import nebulosa.imaging.Image -import nebulosa.imaging.Image.Companion.forEach -import nebulosa.imaging.ImageChannel -import nebulosa.imaging.algorithms.ComputationAlgorithm +import nebulosa.image.Image +import nebulosa.image.Image.Companion.forEach +import nebulosa.image.ImageChannel +import nebulosa.image.algorithms.ComputationAlgorithm import kotlin.math.abs import kotlin.math.min diff --git a/nebulosa-imaging/src/main/kotlin/nebulosa/imaging/algorithms/computation/Statistics.kt b/nebulosa-image/src/main/kotlin/nebulosa/image/algorithms/computation/Statistics.kt similarity index 93% rename from nebulosa-imaging/src/main/kotlin/nebulosa/imaging/algorithms/computation/Statistics.kt rename to nebulosa-image/src/main/kotlin/nebulosa/image/algorithms/computation/Statistics.kt index 1b0114b26..2d4b0dbd5 100644 --- a/nebulosa-imaging/src/main/kotlin/nebulosa/imaging/algorithms/computation/Statistics.kt +++ b/nebulosa-image/src/main/kotlin/nebulosa/image/algorithms/computation/Statistics.kt @@ -1,9 +1,9 @@ -package nebulosa.imaging.algorithms.computation +package nebulosa.image.algorithms.computation -import nebulosa.imaging.Image -import nebulosa.imaging.Image.Companion.forEach -import nebulosa.imaging.ImageChannel -import nebulosa.imaging.algorithms.ComputationAlgorithm +import nebulosa.image.Image +import nebulosa.image.Image.Companion.forEach +import nebulosa.image.ImageChannel +import nebulosa.image.algorithms.ComputationAlgorithm import kotlin.math.abs import kotlin.math.max import kotlin.math.min diff --git a/nebulosa-imaging/src/main/kotlin/nebulosa/imaging/algorithms/computation/fwhm/FWHM.kt b/nebulosa-image/src/main/kotlin/nebulosa/image/algorithms/computation/fwhm/FWHM.kt similarity index 93% rename from nebulosa-imaging/src/main/kotlin/nebulosa/imaging/algorithms/computation/fwhm/FWHM.kt rename to nebulosa-image/src/main/kotlin/nebulosa/image/algorithms/computation/fwhm/FWHM.kt index ee52e1524..c13b43c90 100644 --- a/nebulosa-imaging/src/main/kotlin/nebulosa/imaging/algorithms/computation/fwhm/FWHM.kt +++ b/nebulosa-image/src/main/kotlin/nebulosa/image/algorithms/computation/fwhm/FWHM.kt @@ -1,7 +1,7 @@ -package nebulosa.imaging.algorithms.computation.fwhm +package nebulosa.image.algorithms.computation.fwhm -import nebulosa.imaging.Image -import nebulosa.imaging.algorithms.ComputationAlgorithm +import nebulosa.image.Image +import nebulosa.image.algorithms.ComputationAlgorithm import kotlin.math.max import kotlin.math.min diff --git a/nebulosa-imaging/src/main/kotlin/nebulosa/imaging/algorithms/computation/hfd/HFD.kt b/nebulosa-image/src/main/kotlin/nebulosa/image/algorithms/computation/hfd/HFD.kt similarity index 98% rename from nebulosa-imaging/src/main/kotlin/nebulosa/imaging/algorithms/computation/hfd/HFD.kt rename to nebulosa-image/src/main/kotlin/nebulosa/image/algorithms/computation/hfd/HFD.kt index 1c93e5369..73dfa555e 100644 --- a/nebulosa-imaging/src/main/kotlin/nebulosa/imaging/algorithms/computation/hfd/HFD.kt +++ b/nebulosa-image/src/main/kotlin/nebulosa/image/algorithms/computation/hfd/HFD.kt @@ -1,7 +1,7 @@ -package nebulosa.imaging.algorithms.computation.hfd +package nebulosa.image.algorithms.computation.hfd -import nebulosa.imaging.Image -import nebulosa.imaging.algorithms.ComputationAlgorithm +import nebulosa.image.Image +import nebulosa.image.algorithms.ComputationAlgorithm import kotlin.math.* /** diff --git a/nebulosa-imaging/src/main/kotlin/nebulosa/imaging/algorithms/computation/hfd/HFR.kt b/nebulosa-image/src/main/kotlin/nebulosa/image/algorithms/computation/hfd/HFR.kt similarity index 95% rename from nebulosa-imaging/src/main/kotlin/nebulosa/imaging/algorithms/computation/hfd/HFR.kt rename to nebulosa-image/src/main/kotlin/nebulosa/image/algorithms/computation/hfd/HFR.kt index 5bb0d87ba..4df771850 100644 --- a/nebulosa-imaging/src/main/kotlin/nebulosa/imaging/algorithms/computation/hfd/HFR.kt +++ b/nebulosa-image/src/main/kotlin/nebulosa/image/algorithms/computation/hfd/HFR.kt @@ -1,4 +1,4 @@ -package nebulosa.imaging.algorithms.computation.hfd +package nebulosa.image.algorithms.computation.hfd import kotlin.math.sqrt diff --git a/nebulosa-imaging/src/main/kotlin/nebulosa/imaging/algorithms/transformation/AutoScreenTransformFunction.kt b/nebulosa-image/src/main/kotlin/nebulosa/image/algorithms/transformation/AutoScreenTransformFunction.kt similarity index 82% rename from nebulosa-imaging/src/main/kotlin/nebulosa/imaging/algorithms/transformation/AutoScreenTransformFunction.kt rename to nebulosa-image/src/main/kotlin/nebulosa/image/algorithms/transformation/AutoScreenTransformFunction.kt index b40346143..ddd031f63 100644 --- a/nebulosa-imaging/src/main/kotlin/nebulosa/imaging/algorithms/transformation/AutoScreenTransformFunction.kt +++ b/nebulosa-image/src/main/kotlin/nebulosa/image/algorithms/transformation/AutoScreenTransformFunction.kt @@ -1,10 +1,10 @@ -package nebulosa.imaging.algorithms.transformation +package nebulosa.image.algorithms.transformation -import nebulosa.imaging.Image -import nebulosa.imaging.algorithms.ComputationAlgorithm -import nebulosa.imaging.algorithms.TransformAlgorithm -import nebulosa.imaging.algorithms.computation.Median -import nebulosa.imaging.algorithms.computation.MedianAbsoluteDeviation +import nebulosa.image.Image +import nebulosa.image.algorithms.ComputationAlgorithm +import nebulosa.image.algorithms.TransformAlgorithm +import nebulosa.image.algorithms.computation.Median +import nebulosa.image.algorithms.computation.MedianAbsoluteDeviation import nebulosa.log.loggerFor import kotlin.math.max import kotlin.math.min diff --git a/nebulosa-imaging/src/main/kotlin/nebulosa/imaging/algorithms/transformation/Binarize.kt b/nebulosa-image/src/main/kotlin/nebulosa/image/algorithms/transformation/Binarize.kt similarity index 70% rename from nebulosa-imaging/src/main/kotlin/nebulosa/imaging/algorithms/transformation/Binarize.kt rename to nebulosa-image/src/main/kotlin/nebulosa/image/algorithms/transformation/Binarize.kt index 7debce20b..9de147801 100644 --- a/nebulosa-imaging/src/main/kotlin/nebulosa/imaging/algorithms/transformation/Binarize.kt +++ b/nebulosa-image/src/main/kotlin/nebulosa/image/algorithms/transformation/Binarize.kt @@ -1,7 +1,7 @@ -package nebulosa.imaging.algorithms.transformation +package nebulosa.image.algorithms.transformation -import nebulosa.imaging.Image -import nebulosa.imaging.algorithms.TransformAlgorithm +import nebulosa.image.Image +import nebulosa.image.algorithms.TransformAlgorithm data class Binarize(private val threshold: Float = 0.5f) : TransformAlgorithm { diff --git a/nebulosa-imaging/src/main/kotlin/nebulosa/imaging/algorithms/transformation/CfaPattern.kt b/nebulosa-image/src/main/kotlin/nebulosa/image/algorithms/transformation/CfaPattern.kt similarity index 86% rename from nebulosa-imaging/src/main/kotlin/nebulosa/imaging/algorithms/transformation/CfaPattern.kt rename to nebulosa-image/src/main/kotlin/nebulosa/image/algorithms/transformation/CfaPattern.kt index bfaeeb053..e4015aa68 100644 --- a/nebulosa-imaging/src/main/kotlin/nebulosa/imaging/algorithms/transformation/CfaPattern.kt +++ b/nebulosa-image/src/main/kotlin/nebulosa/image/algorithms/transformation/CfaPattern.kt @@ -1,8 +1,8 @@ -package nebulosa.imaging.algorithms.transformation +package nebulosa.image.algorithms.transformation -import nebulosa.fits.Header import nebulosa.fits.cfaPattern -import nebulosa.imaging.ImageChannel +import nebulosa.image.ImageChannel +import nebulosa.image.format.ReadableHeader enum class CfaPattern(private val pattern: Array>) { RGGB(arrayOf(arrayOf(ImageChannel.RED, ImageChannel.GREEN), arrayOf(ImageChannel.GREEN, ImageChannel.BLUE))), @@ -19,7 +19,7 @@ enum class CfaPattern(private val pattern: Array>) { companion object { @JvmStatic - fun from(header: Header): CfaPattern? { + fun from(header: ReadableHeader): CfaPattern? { return header.cfaPattern?.let(CfaPattern::valueOf) } } diff --git a/nebulosa-imaging/src/main/kotlin/nebulosa/imaging/algorithms/transformation/Debayer.kt b/nebulosa-image/src/main/kotlin/nebulosa/image/algorithms/transformation/Debayer.kt similarity index 96% rename from nebulosa-imaging/src/main/kotlin/nebulosa/imaging/algorithms/transformation/Debayer.kt rename to nebulosa-image/src/main/kotlin/nebulosa/image/algorithms/transformation/Debayer.kt index e5fd85ee3..7c34532d1 100644 --- a/nebulosa-imaging/src/main/kotlin/nebulosa/imaging/algorithms/transformation/Debayer.kt +++ b/nebulosa-image/src/main/kotlin/nebulosa/image/algorithms/transformation/Debayer.kt @@ -1,7 +1,7 @@ -package nebulosa.imaging.algorithms.transformation +package nebulosa.image.algorithms.transformation -import nebulosa.imaging.Image -import nebulosa.imaging.algorithms.TransformAlgorithm +import nebulosa.image.Image +import nebulosa.image.algorithms.TransformAlgorithm data class Debayer(private val pattern: CfaPattern? = null) : TransformAlgorithm { diff --git a/nebulosa-imaging/src/main/kotlin/nebulosa/imaging/algorithms/transformation/Draw.kt b/nebulosa-image/src/main/kotlin/nebulosa/image/algorithms/transformation/Draw.kt similarity index 77% rename from nebulosa-imaging/src/main/kotlin/nebulosa/imaging/algorithms/transformation/Draw.kt rename to nebulosa-image/src/main/kotlin/nebulosa/image/algorithms/transformation/Draw.kt index f39a7c9bf..578790f3d 100644 --- a/nebulosa-imaging/src/main/kotlin/nebulosa/imaging/algorithms/transformation/Draw.kt +++ b/nebulosa-image/src/main/kotlin/nebulosa/image/algorithms/transformation/Draw.kt @@ -1,7 +1,7 @@ -package nebulosa.imaging.algorithms.transformation +package nebulosa.image.algorithms.transformation -import nebulosa.imaging.Image -import nebulosa.imaging.algorithms.TransformAlgorithm +import nebulosa.image.Image +import nebulosa.image.algorithms.TransformAlgorithm import java.awt.Graphics2D import java.awt.RenderingHints diff --git a/nebulosa-imaging/src/main/kotlin/nebulosa/imaging/algorithms/transformation/Grayscale.kt b/nebulosa-image/src/main/kotlin/nebulosa/image/algorithms/transformation/Grayscale.kt similarity index 78% rename from nebulosa-imaging/src/main/kotlin/nebulosa/imaging/algorithms/transformation/Grayscale.kt rename to nebulosa-image/src/main/kotlin/nebulosa/image/algorithms/transformation/Grayscale.kt index b31002c43..50cb8ba7c 100644 --- a/nebulosa-imaging/src/main/kotlin/nebulosa/imaging/algorithms/transformation/Grayscale.kt +++ b/nebulosa-image/src/main/kotlin/nebulosa/image/algorithms/transformation/Grayscale.kt @@ -1,9 +1,8 @@ -package nebulosa.imaging.algorithms.transformation +package nebulosa.image.algorithms.transformation -import nebulosa.fits.Standard -import nebulosa.fits.clone -import nebulosa.imaging.Image -import nebulosa.imaging.algorithms.TransformAlgorithm +import nebulosa.fits.FitsKeywordDictionary +import nebulosa.image.Image +import nebulosa.image.algorithms.TransformAlgorithm import kotlin.math.max import kotlin.math.min @@ -17,8 +16,8 @@ data class Grayscale( if (source.mono) return source val header = source.header.clone() - header.add(Standard.NAXIS, 2) - header.delete(Standard.NAXIS3) + header.add(FitsKeywordDictionary.NAXIS, 2) + header.delete(FitsKeywordDictionary.NAXIS3) val result = Image(source.width, source.height, header, true) for (i in source.r.indices) { diff --git a/nebulosa-imaging/src/main/kotlin/nebulosa/imaging/algorithms/transformation/HorizontalFlip.kt b/nebulosa-image/src/main/kotlin/nebulosa/image/algorithms/transformation/HorizontalFlip.kt similarity index 82% rename from nebulosa-imaging/src/main/kotlin/nebulosa/imaging/algorithms/transformation/HorizontalFlip.kt rename to nebulosa-image/src/main/kotlin/nebulosa/image/algorithms/transformation/HorizontalFlip.kt index 15dc72492..ca7e1b45f 100644 --- a/nebulosa-imaging/src/main/kotlin/nebulosa/imaging/algorithms/transformation/HorizontalFlip.kt +++ b/nebulosa-image/src/main/kotlin/nebulosa/image/algorithms/transformation/HorizontalFlip.kt @@ -1,7 +1,7 @@ -package nebulosa.imaging.algorithms.transformation +package nebulosa.image.algorithms.transformation -import nebulosa.imaging.Image -import nebulosa.imaging.algorithms.TransformAlgorithm +import nebulosa.image.Image +import nebulosa.image.algorithms.TransformAlgorithm data object HorizontalFlip : TransformAlgorithm { diff --git a/nebulosa-imaging/src/main/kotlin/nebulosa/imaging/algorithms/transformation/Invert.kt b/nebulosa-image/src/main/kotlin/nebulosa/image/algorithms/transformation/Invert.kt similarity index 73% rename from nebulosa-imaging/src/main/kotlin/nebulosa/imaging/algorithms/transformation/Invert.kt rename to nebulosa-image/src/main/kotlin/nebulosa/image/algorithms/transformation/Invert.kt index 403595497..daf96a810 100644 --- a/nebulosa-imaging/src/main/kotlin/nebulosa/imaging/algorithms/transformation/Invert.kt +++ b/nebulosa-image/src/main/kotlin/nebulosa/image/algorithms/transformation/Invert.kt @@ -1,7 +1,7 @@ -package nebulosa.imaging.algorithms.transformation +package nebulosa.image.algorithms.transformation -import nebulosa.imaging.Image -import nebulosa.imaging.algorithms.TransformAlgorithm +import nebulosa.image.Image +import nebulosa.image.algorithms.TransformAlgorithm data object Invert : TransformAlgorithm { diff --git a/nebulosa-imaging/src/main/kotlin/nebulosa/imaging/algorithms/transformation/ProtectionMethod.kt b/nebulosa-image/src/main/kotlin/nebulosa/image/algorithms/transformation/ProtectionMethod.kt similarity index 95% rename from nebulosa-imaging/src/main/kotlin/nebulosa/imaging/algorithms/transformation/ProtectionMethod.kt rename to nebulosa-image/src/main/kotlin/nebulosa/image/algorithms/transformation/ProtectionMethod.kt index 31405461a..72d2d60ef 100644 --- a/nebulosa-imaging/src/main/kotlin/nebulosa/imaging/algorithms/transformation/ProtectionMethod.kt +++ b/nebulosa-image/src/main/kotlin/nebulosa/image/algorithms/transformation/ProtectionMethod.kt @@ -1,4 +1,4 @@ -package nebulosa.imaging.algorithms.transformation +package nebulosa.image.algorithms.transformation import kotlin.math.max import kotlin.math.min diff --git a/nebulosa-imaging/src/main/kotlin/nebulosa/imaging/algorithms/transformation/SaltAndPepperNoise.kt b/nebulosa-image/src/main/kotlin/nebulosa/image/algorithms/transformation/SaltAndPepperNoise.kt similarity index 85% rename from nebulosa-imaging/src/main/kotlin/nebulosa/imaging/algorithms/transformation/SaltAndPepperNoise.kt rename to nebulosa-image/src/main/kotlin/nebulosa/image/algorithms/transformation/SaltAndPepperNoise.kt index fda8f9ff8..0f7882ce9 100644 --- a/nebulosa-imaging/src/main/kotlin/nebulosa/imaging/algorithms/transformation/SaltAndPepperNoise.kt +++ b/nebulosa-image/src/main/kotlin/nebulosa/image/algorithms/transformation/SaltAndPepperNoise.kt @@ -1,7 +1,7 @@ -package nebulosa.imaging.algorithms.transformation +package nebulosa.image.algorithms.transformation -import nebulosa.imaging.Image -import nebulosa.imaging.algorithms.TransformAlgorithm +import nebulosa.image.Image +import nebulosa.image.algorithms.TransformAlgorithm import java.util.* data class SaltAndPepperNoise( diff --git a/nebulosa-imaging/src/main/kotlin/nebulosa/imaging/algorithms/transformation/ScreenTransformFunction.kt b/nebulosa-image/src/main/kotlin/nebulosa/image/algorithms/transformation/ScreenTransformFunction.kt similarity index 93% rename from nebulosa-imaging/src/main/kotlin/nebulosa/imaging/algorithms/transformation/ScreenTransformFunction.kt rename to nebulosa-image/src/main/kotlin/nebulosa/image/algorithms/transformation/ScreenTransformFunction.kt index 3510220ea..668eedb17 100644 --- a/nebulosa-imaging/src/main/kotlin/nebulosa/imaging/algorithms/transformation/ScreenTransformFunction.kt +++ b/nebulosa-image/src/main/kotlin/nebulosa/image/algorithms/transformation/ScreenTransformFunction.kt @@ -1,7 +1,7 @@ -package nebulosa.imaging.algorithms.transformation +package nebulosa.image.algorithms.transformation -import nebulosa.imaging.Image -import nebulosa.imaging.algorithms.TransformAlgorithm +import nebulosa.image.Image +import nebulosa.image.algorithms.TransformAlgorithm import kotlin.math.max import kotlin.math.min diff --git a/nebulosa-imaging/src/main/kotlin/nebulosa/imaging/algorithms/transformation/SigmaClip.kt b/nebulosa-image/src/main/kotlin/nebulosa/image/algorithms/transformation/SigmaClip.kt similarity index 89% rename from nebulosa-imaging/src/main/kotlin/nebulosa/imaging/algorithms/transformation/SigmaClip.kt rename to nebulosa-image/src/main/kotlin/nebulosa/image/algorithms/transformation/SigmaClip.kt index 65982ff5a..4c34d2880 100644 --- a/nebulosa-imaging/src/main/kotlin/nebulosa/imaging/algorithms/transformation/SigmaClip.kt +++ b/nebulosa-image/src/main/kotlin/nebulosa/image/algorithms/transformation/SigmaClip.kt @@ -1,10 +1,10 @@ -package nebulosa.imaging.algorithms.transformation +package nebulosa.image.algorithms.transformation -import nebulosa.imaging.Image -import nebulosa.imaging.ImageChannel -import nebulosa.imaging.algorithms.ComputationAlgorithm -import nebulosa.imaging.algorithms.TransformAlgorithm -import nebulosa.imaging.algorithms.computation.Statistics +import nebulosa.image.Image +import nebulosa.image.ImageChannel +import nebulosa.image.algorithms.ComputationAlgorithm +import nebulosa.image.algorithms.TransformAlgorithm +import nebulosa.image.algorithms.computation.Statistics import kotlin.math.max import kotlin.math.min diff --git a/nebulosa-imaging/src/main/kotlin/nebulosa/imaging/algorithms/transformation/SubFrame.kt b/nebulosa-image/src/main/kotlin/nebulosa/image/algorithms/transformation/SubFrame.kt similarity index 83% rename from nebulosa-imaging/src/main/kotlin/nebulosa/imaging/algorithms/transformation/SubFrame.kt rename to nebulosa-image/src/main/kotlin/nebulosa/image/algorithms/transformation/SubFrame.kt index 115bad15c..5f931f097 100644 --- a/nebulosa-imaging/src/main/kotlin/nebulosa/imaging/algorithms/transformation/SubFrame.kt +++ b/nebulosa-image/src/main/kotlin/nebulosa/image/algorithms/transformation/SubFrame.kt @@ -1,9 +1,8 @@ -package nebulosa.imaging.algorithms.transformation +package nebulosa.image.algorithms.transformation -import nebulosa.fits.Standard -import nebulosa.fits.clone -import nebulosa.imaging.Image -import nebulosa.imaging.algorithms.TransformAlgorithm +import nebulosa.fits.FitsKeywordDictionary +import nebulosa.image.Image +import nebulosa.image.algorithms.TransformAlgorithm data class SubFrame( private val x: Int, private val y: Int, @@ -22,8 +21,8 @@ data class SubFrame( require(y + height <= source.height) { "subframe.height < source.height: ${y + height} > ${source.height}" } val header = source.header.clone() - header.add(Standard.NAXIS1, width) - header.add(Standard.NAXIS2, height) + header.add(FitsKeywordDictionary.NAXIS1, width) + header.add(FitsKeywordDictionary.NAXIS2, height) val subframe = Image(width, height, header, source.mono) var index = 0 diff --git a/nebulosa-imaging/src/main/kotlin/nebulosa/imaging/algorithms/transformation/SubtractiveChromaticNoiseReduction.kt b/nebulosa-image/src/main/kotlin/nebulosa/image/algorithms/transformation/SubtractiveChromaticNoiseReduction.kt similarity index 89% rename from nebulosa-imaging/src/main/kotlin/nebulosa/imaging/algorithms/transformation/SubtractiveChromaticNoiseReduction.kt rename to nebulosa-image/src/main/kotlin/nebulosa/image/algorithms/transformation/SubtractiveChromaticNoiseReduction.kt index d0c68aced..6568418ca 100644 --- a/nebulosa-imaging/src/main/kotlin/nebulosa/imaging/algorithms/transformation/SubtractiveChromaticNoiseReduction.kt +++ b/nebulosa-image/src/main/kotlin/nebulosa/image/algorithms/transformation/SubtractiveChromaticNoiseReduction.kt @@ -1,8 +1,8 @@ -package nebulosa.imaging.algorithms.transformation +package nebulosa.image.algorithms.transformation -import nebulosa.imaging.Image -import nebulosa.imaging.ImageChannel -import nebulosa.imaging.algorithms.TransformAlgorithm +import nebulosa.image.Image +import nebulosa.image.ImageChannel +import nebulosa.image.algorithms.TransformAlgorithm /** * The Subtractive Chromatic Noise Reduction (SCNR) technique diff --git a/nebulosa-imaging/src/main/kotlin/nebulosa/imaging/algorithms/transformation/VerticalFlip.kt b/nebulosa-image/src/main/kotlin/nebulosa/image/algorithms/transformation/VerticalFlip.kt similarity index 82% rename from nebulosa-imaging/src/main/kotlin/nebulosa/imaging/algorithms/transformation/VerticalFlip.kt rename to nebulosa-image/src/main/kotlin/nebulosa/image/algorithms/transformation/VerticalFlip.kt index a7448fd16..cb0261b17 100644 --- a/nebulosa-imaging/src/main/kotlin/nebulosa/imaging/algorithms/transformation/VerticalFlip.kt +++ b/nebulosa-image/src/main/kotlin/nebulosa/image/algorithms/transformation/VerticalFlip.kt @@ -1,7 +1,7 @@ -package nebulosa.imaging.algorithms.transformation +package nebulosa.image.algorithms.transformation -import nebulosa.imaging.Image -import nebulosa.imaging.algorithms.TransformAlgorithm +import nebulosa.image.Image +import nebulosa.image.algorithms.TransformAlgorithm data object VerticalFlip : TransformAlgorithm { diff --git a/nebulosa-imaging/src/main/kotlin/nebulosa/imaging/algorithms/transformation/convolution/Blur.kt b/nebulosa-image/src/main/kotlin/nebulosa/image/algorithms/transformation/convolution/Blur.kt similarity index 75% rename from nebulosa-imaging/src/main/kotlin/nebulosa/imaging/algorithms/transformation/convolution/Blur.kt rename to nebulosa-image/src/main/kotlin/nebulosa/image/algorithms/transformation/convolution/Blur.kt index d65160672..cd5ec4d22 100644 --- a/nebulosa-imaging/src/main/kotlin/nebulosa/imaging/algorithms/transformation/convolution/Blur.kt +++ b/nebulosa-image/src/main/kotlin/nebulosa/image/algorithms/transformation/convolution/Blur.kt @@ -1,4 +1,4 @@ -package nebulosa.imaging.algorithms.transformation.convolution +package nebulosa.image.algorithms.transformation.convolution data object Blur : Convolution( floatArrayOf( diff --git a/nebulosa-imaging/src/main/kotlin/nebulosa/imaging/algorithms/transformation/convolution/Convolution.kt b/nebulosa-image/src/main/kotlin/nebulosa/image/algorithms/transformation/convolution/Convolution.kt similarity index 95% rename from nebulosa-imaging/src/main/kotlin/nebulosa/imaging/algorithms/transformation/convolution/Convolution.kt rename to nebulosa-image/src/main/kotlin/nebulosa/image/algorithms/transformation/convolution/Convolution.kt index 019fa2bba..a9022c0ee 100644 --- a/nebulosa-imaging/src/main/kotlin/nebulosa/imaging/algorithms/transformation/convolution/Convolution.kt +++ b/nebulosa-image/src/main/kotlin/nebulosa/image/algorithms/transformation/convolution/Convolution.kt @@ -1,7 +1,7 @@ -package nebulosa.imaging.algorithms.transformation.convolution +package nebulosa.image.algorithms.transformation.convolution -import nebulosa.imaging.Image -import nebulosa.imaging.algorithms.TransformAlgorithm +import nebulosa.image.Image +import nebulosa.image.algorithms.TransformAlgorithm import kotlin.math.max import kotlin.math.min diff --git a/nebulosa-imaging/src/main/kotlin/nebulosa/imaging/algorithms/transformation/convolution/ConvolutionKernel.kt b/nebulosa-image/src/main/kotlin/nebulosa/image/algorithms/transformation/convolution/ConvolutionKernel.kt similarity index 69% rename from nebulosa-imaging/src/main/kotlin/nebulosa/imaging/algorithms/transformation/convolution/ConvolutionKernel.kt rename to nebulosa-image/src/main/kotlin/nebulosa/image/algorithms/transformation/convolution/ConvolutionKernel.kt index 46c5c2e00..c0979fb2f 100644 --- a/nebulosa-imaging/src/main/kotlin/nebulosa/imaging/algorithms/transformation/convolution/ConvolutionKernel.kt +++ b/nebulosa-image/src/main/kotlin/nebulosa/image/algorithms/transformation/convolution/ConvolutionKernel.kt @@ -1,4 +1,4 @@ -package nebulosa.imaging.algorithms.transformation.convolution +package nebulosa.image.algorithms.transformation.convolution interface ConvolutionKernel { diff --git a/nebulosa-imaging/src/main/kotlin/nebulosa/imaging/algorithms/transformation/convolution/Edges.kt b/nebulosa-image/src/main/kotlin/nebulosa/image/algorithms/transformation/convolution/Edges.kt similarity index 66% rename from nebulosa-imaging/src/main/kotlin/nebulosa/imaging/algorithms/transformation/convolution/Edges.kt rename to nebulosa-image/src/main/kotlin/nebulosa/image/algorithms/transformation/convolution/Edges.kt index 938ad6acd..abc2f56c0 100644 --- a/nebulosa-imaging/src/main/kotlin/nebulosa/imaging/algorithms/transformation/convolution/Edges.kt +++ b/nebulosa-image/src/main/kotlin/nebulosa/image/algorithms/transformation/convolution/Edges.kt @@ -1,4 +1,4 @@ -package nebulosa.imaging.algorithms.transformation.convolution +package nebulosa.image.algorithms.transformation.convolution data object Edges : Convolution( floatArrayOf( diff --git a/nebulosa-imaging/src/main/kotlin/nebulosa/imaging/algorithms/transformation/convolution/Emboss.kt b/nebulosa-image/src/main/kotlin/nebulosa/image/algorithms/transformation/convolution/Emboss.kt similarity index 65% rename from nebulosa-imaging/src/main/kotlin/nebulosa/imaging/algorithms/transformation/convolution/Emboss.kt rename to nebulosa-image/src/main/kotlin/nebulosa/image/algorithms/transformation/convolution/Emboss.kt index 942016324..553b8c9a0 100644 --- a/nebulosa-imaging/src/main/kotlin/nebulosa/imaging/algorithms/transformation/convolution/Emboss.kt +++ b/nebulosa-image/src/main/kotlin/nebulosa/image/algorithms/transformation/convolution/Emboss.kt @@ -1,4 +1,4 @@ -package nebulosa.imaging.algorithms.transformation.convolution +package nebulosa.image.algorithms.transformation.convolution data object Emboss : Convolution( floatArrayOf( diff --git a/nebulosa-imaging/src/main/kotlin/nebulosa/imaging/algorithms/transformation/convolution/GaussianBlur.kt b/nebulosa-image/src/main/kotlin/nebulosa/image/algorithms/transformation/convolution/GaussianBlur.kt similarity index 94% rename from nebulosa-imaging/src/main/kotlin/nebulosa/imaging/algorithms/transformation/convolution/GaussianBlur.kt rename to nebulosa-image/src/main/kotlin/nebulosa/image/algorithms/transformation/convolution/GaussianBlur.kt index e2eb4af0b..0601d084d 100644 --- a/nebulosa-imaging/src/main/kotlin/nebulosa/imaging/algorithms/transformation/convolution/GaussianBlur.kt +++ b/nebulosa-image/src/main/kotlin/nebulosa/image/algorithms/transformation/convolution/GaussianBlur.kt @@ -1,4 +1,4 @@ -package nebulosa.imaging.algorithms.transformation.convolution +package nebulosa.image.algorithms.transformation.convolution import kotlin.math.exp diff --git a/nebulosa-imaging/src/main/kotlin/nebulosa/imaging/algorithms/transformation/convolution/MatrixConvolutionKernel.kt b/nebulosa-image/src/main/kotlin/nebulosa/image/algorithms/transformation/convolution/MatrixConvolutionKernel.kt similarity index 84% rename from nebulosa-imaging/src/main/kotlin/nebulosa/imaging/algorithms/transformation/convolution/MatrixConvolutionKernel.kt rename to nebulosa-image/src/main/kotlin/nebulosa/image/algorithms/transformation/convolution/MatrixConvolutionKernel.kt index 927eda989..2d7022d32 100644 --- a/nebulosa-imaging/src/main/kotlin/nebulosa/imaging/algorithms/transformation/convolution/MatrixConvolutionKernel.kt +++ b/nebulosa-image/src/main/kotlin/nebulosa/image/algorithms/transformation/convolution/MatrixConvolutionKernel.kt @@ -1,4 +1,4 @@ -package nebulosa.imaging.algorithms.transformation.convolution +package nebulosa.image.algorithms.transformation.convolution import kotlin.math.sqrt diff --git a/nebulosa-imaging/src/main/kotlin/nebulosa/imaging/algorithms/transformation/convolution/Mean.kt b/nebulosa-image/src/main/kotlin/nebulosa/image/algorithms/transformation/convolution/Mean.kt similarity index 65% rename from nebulosa-imaging/src/main/kotlin/nebulosa/imaging/algorithms/transformation/convolution/Mean.kt rename to nebulosa-image/src/main/kotlin/nebulosa/image/algorithms/transformation/convolution/Mean.kt index 47605e0e6..cbb07ac9a 100644 --- a/nebulosa-imaging/src/main/kotlin/nebulosa/imaging/algorithms/transformation/convolution/Mean.kt +++ b/nebulosa-image/src/main/kotlin/nebulosa/image/algorithms/transformation/convolution/Mean.kt @@ -1,4 +1,4 @@ -package nebulosa.imaging.algorithms.transformation.convolution +package nebulosa.image.algorithms.transformation.convolution data object Mean : Convolution( floatArrayOf( diff --git a/nebulosa-imaging/src/main/kotlin/nebulosa/imaging/algorithms/transformation/convolution/Sharpen.kt b/nebulosa-image/src/main/kotlin/nebulosa/image/algorithms/transformation/convolution/Sharpen.kt similarity index 66% rename from nebulosa-imaging/src/main/kotlin/nebulosa/imaging/algorithms/transformation/convolution/Sharpen.kt rename to nebulosa-image/src/main/kotlin/nebulosa/image/algorithms/transformation/convolution/Sharpen.kt index 07f08d63a..70260b2c2 100644 --- a/nebulosa-imaging/src/main/kotlin/nebulosa/imaging/algorithms/transformation/convolution/Sharpen.kt +++ b/nebulosa-image/src/main/kotlin/nebulosa/image/algorithms/transformation/convolution/Sharpen.kt @@ -1,4 +1,4 @@ -package nebulosa.imaging.algorithms.transformation.convolution +package nebulosa.image.algorithms.transformation.convolution data object Sharpen : Convolution( floatArrayOf( diff --git a/nebulosa-imaging/src/main/kotlin/nebulosa/imaging/algorithms/transformation/correction/BiasSubtraction.kt b/nebulosa-image/src/main/kotlin/nebulosa/image/algorithms/transformation/correction/BiasSubtraction.kt similarity index 80% rename from nebulosa-imaging/src/main/kotlin/nebulosa/imaging/algorithms/transformation/correction/BiasSubtraction.kt rename to nebulosa-image/src/main/kotlin/nebulosa/image/algorithms/transformation/correction/BiasSubtraction.kt index a0d686aaa..56b197d0d 100644 --- a/nebulosa-imaging/src/main/kotlin/nebulosa/imaging/algorithms/transformation/correction/BiasSubtraction.kt +++ b/nebulosa-image/src/main/kotlin/nebulosa/image/algorithms/transformation/correction/BiasSubtraction.kt @@ -1,8 +1,8 @@ -package nebulosa.imaging.algorithms.transformation.correction +package nebulosa.image.algorithms.transformation.correction -import nebulosa.imaging.Image -import nebulosa.imaging.ImageChannel -import nebulosa.imaging.algorithms.TransformAlgorithm +import nebulosa.image.Image +import nebulosa.image.ImageChannel +import nebulosa.image.algorithms.TransformAlgorithm import kotlin.math.max data class BiasSubtraction(private val biasFrame: Image) : TransformAlgorithm { diff --git a/nebulosa-imaging/src/main/kotlin/nebulosa/imaging/algorithms/transformation/correction/DarkSubtraction.kt b/nebulosa-image/src/main/kotlin/nebulosa/image/algorithms/transformation/correction/DarkSubtraction.kt similarity index 80% rename from nebulosa-imaging/src/main/kotlin/nebulosa/imaging/algorithms/transformation/correction/DarkSubtraction.kt rename to nebulosa-image/src/main/kotlin/nebulosa/image/algorithms/transformation/correction/DarkSubtraction.kt index 91832d845..62fb5ca3e 100644 --- a/nebulosa-imaging/src/main/kotlin/nebulosa/imaging/algorithms/transformation/correction/DarkSubtraction.kt +++ b/nebulosa-image/src/main/kotlin/nebulosa/image/algorithms/transformation/correction/DarkSubtraction.kt @@ -1,8 +1,8 @@ -package nebulosa.imaging.algorithms.transformation.correction +package nebulosa.image.algorithms.transformation.correction -import nebulosa.imaging.Image -import nebulosa.imaging.ImageChannel -import nebulosa.imaging.algorithms.TransformAlgorithm +import nebulosa.image.Image +import nebulosa.image.ImageChannel +import nebulosa.image.algorithms.TransformAlgorithm import kotlin.math.max data class DarkSubtraction(private val darkFrame: Image) : TransformAlgorithm { diff --git a/nebulosa-imaging/src/main/kotlin/nebulosa/imaging/algorithms/transformation/correction/FlatCorrection.kt b/nebulosa-image/src/main/kotlin/nebulosa/image/algorithms/transformation/correction/FlatCorrection.kt similarity index 78% rename from nebulosa-imaging/src/main/kotlin/nebulosa/imaging/algorithms/transformation/correction/FlatCorrection.kt rename to nebulosa-image/src/main/kotlin/nebulosa/image/algorithms/transformation/correction/FlatCorrection.kt index 7eae74606..3225ff04c 100644 --- a/nebulosa-imaging/src/main/kotlin/nebulosa/imaging/algorithms/transformation/correction/FlatCorrection.kt +++ b/nebulosa-image/src/main/kotlin/nebulosa/image/algorithms/transformation/correction/FlatCorrection.kt @@ -1,9 +1,9 @@ -package nebulosa.imaging.algorithms.transformation.correction +package nebulosa.image.algorithms.transformation.correction -import nebulosa.imaging.Image -import nebulosa.imaging.ImageChannel -import nebulosa.imaging.algorithms.TransformAlgorithm -import nebulosa.imaging.algorithms.computation.Statistics +import nebulosa.image.Image +import nebulosa.image.ImageChannel +import nebulosa.image.algorithms.TransformAlgorithm +import nebulosa.image.algorithms.computation.Statistics data class FlatCorrection(private val flatFrame: Image) : TransformAlgorithm { diff --git a/nebulosa-imaging/src/test/kotlin/ComputationAlgorithmTest.kt b/nebulosa-image/src/test/kotlin/ComputationAlgorithmTest.kt similarity index 90% rename from nebulosa-imaging/src/test/kotlin/ComputationAlgorithmTest.kt rename to nebulosa-image/src/test/kotlin/ComputationAlgorithmTest.kt index 45dea772d..00cc89ca9 100644 --- a/nebulosa-imaging/src/test/kotlin/ComputationAlgorithmTest.kt +++ b/nebulosa-image/src/test/kotlin/ComputationAlgorithmTest.kt @@ -2,21 +2,21 @@ import io.kotest.matchers.floats.plusOrMinus import io.kotest.matchers.floats.shouldBeExactly import io.kotest.matchers.ints.shouldBeExactly import io.kotest.matchers.shouldBe -import nebulosa.imaging.Image -import nebulosa.imaging.ImageChannel -import nebulosa.imaging.algorithms.computation.MedianAbsoluteDeviation -import nebulosa.imaging.algorithms.computation.Statistics +import nebulosa.image.Image +import nebulosa.image.ImageChannel +import nebulosa.image.algorithms.computation.MedianAbsoluteDeviation +import nebulosa.image.algorithms.computation.Statistics import nebulosa.test.FitsStringSpec class ComputationAlgorithmTest : FitsStringSpec() { init { "mono:median absolute deviation" { - val mImage = Image.open(NGC3344_MONO_F32) + val mImage = Image.open(NGC3344_MONO_F32_FITS) mImage.compute(MedianAbsoluteDeviation()) shouldBe (0.0862f plusOrMinus 1e-4f) } "mono:statistics" { - val mImage = Image.open(NGC3344_MONO_F32) + val mImage = Image.open(NGC3344_MONO_F32_FITS) val statistics = mImage.compute(Statistics.GRAY) statistics.count shouldBeExactly 65536 @@ -31,13 +31,13 @@ class ComputationAlgorithmTest : FitsStringSpec() { statistics.maximum shouldBeExactly 1f } "color:median absolute deviation" { - val cImage = Image.open(NGC3344_COLOR_F32) + val cImage = Image.open(NGC3344_COLOR_F32_FITS) cImage.compute(MedianAbsoluteDeviation(channel = ImageChannel.RED)) shouldBe (0.0823f plusOrMinus 1e-4f) cImage.compute(MedianAbsoluteDeviation(channel = ImageChannel.GREEN)) shouldBe (0.0745f plusOrMinus 1e-4f) cImage.compute(MedianAbsoluteDeviation(channel = ImageChannel.BLUE)) shouldBe (0.0705f plusOrMinus 1e-4f) } "color:statistics" { - val cImage = Image.open(NGC3344_COLOR_F32) + val cImage = Image.open(NGC3344_COLOR_F32_FITS) run { val statistics = cImage.compute(Statistics.RED) diff --git a/nebulosa-imaging/src/test/kotlin/HFDTest.kt b/nebulosa-image/src/test/kotlin/HFDTest.kt similarity index 95% rename from nebulosa-imaging/src/test/kotlin/HFDTest.kt rename to nebulosa-image/src/test/kotlin/HFDTest.kt index 5d80bc958..8cffda51d 100644 --- a/nebulosa-imaging/src/test/kotlin/HFDTest.kt +++ b/nebulosa-image/src/test/kotlin/HFDTest.kt @@ -1,7 +1,7 @@ import io.kotest.matchers.floats.plusOrMinus import io.kotest.matchers.shouldBe -import nebulosa.imaging.Image -import nebulosa.imaging.algorithms.computation.hfd.HFD +import nebulosa.image.Image +import nebulosa.image.algorithms.computation.hfd.HFD import nebulosa.test.FitsStringSpec class HFDTest : FitsStringSpec() { diff --git a/nebulosa-imaging/src/test/kotlin/TransformAlgorithmTest.kt b/nebulosa-image/src/test/kotlin/TransformAlgorithmTest.kt similarity index 79% rename from nebulosa-imaging/src/test/kotlin/TransformAlgorithmTest.kt rename to nebulosa-image/src/test/kotlin/TransformAlgorithmTest.kt index 954045d31..775b2770a 100644 --- a/nebulosa-imaging/src/test/kotlin/TransformAlgorithmTest.kt +++ b/nebulosa-image/src/test/kotlin/TransformAlgorithmTest.kt @@ -3,10 +3,10 @@ import io.kotest.matchers.booleans.shouldBeTrue import io.kotest.matchers.ints.shouldBeExactly import io.kotest.matchers.shouldBe import nebulosa.fits.fits -import nebulosa.imaging.Image -import nebulosa.imaging.ImageChannel -import nebulosa.imaging.algorithms.transformation.* -import nebulosa.imaging.algorithms.transformation.convolution.* +import nebulosa.image.Image +import nebulosa.image.ImageChannel +import nebulosa.image.algorithms.transformation.* +import nebulosa.image.algorithms.transformation.convolution.* import nebulosa.test.FitsStringSpec import java.io.File @@ -14,26 +14,26 @@ class TransformAlgorithmTest : FitsStringSpec() { init { "mono:raw" { - val mImage = Image.open(NGC3344_MONO_8) + val mImage = Image.open(NGC3344_MONO_8_FITS) mImage.save("mono-raw").second shouldBe "e17cfc29c3b343409cd8617b6913330e" } "mono:vertical flip" { - val mImage = Image.open(NGC3344_MONO_8) + val mImage = Image.open(NGC3344_MONO_8_FITS) mImage.transform(VerticalFlip) mImage.save("mono-vertical-flip").second shouldBe "262260dfe719726c0e7829a088279a21" } "mono:horizontal flip" { - val mImage = Image.open(NGC3344_MONO_8) + val mImage = Image.open(NGC3344_MONO_8_FITS) mImage.transform(HorizontalFlip) mImage.save("mono-horizontal-flip").second shouldBe "daf0f05db5de3750962f338527564b27" } "mono:vertical & horizontal flip" { - val mImage = Image.open(NGC3344_MONO_8) + val mImage = Image.open(NGC3344_MONO_8_FITS) mImage.transform(VerticalFlip, HorizontalFlip) mImage.save("mono-vertical-horizontal-flip").second shouldBe "3bc81f579a0e34ce9312c3b242209166" } "mono:subframe" { - val mImage = Image.open(NGC3344_MONO_8) + val mImage = Image.open(NGC3344_MONO_8_FITS) val nImage = mImage.transform(SubFrame(45, 70, 16, 16)) nImage.width shouldBeExactly 16 nImage.height shouldBeExactly 16 @@ -41,106 +41,106 @@ class TransformAlgorithmTest : FitsStringSpec() { nImage.save("mono-subframe").second shouldBe "4d9984e778f82dde10b9aeeee7a29fe0" } "mono:sharpen" { - val mImage = Image.open(NGC3344_MONO_8) + val mImage = Image.open(NGC3344_MONO_8_FITS) mImage.transform(Sharpen) mImage.save("mono-sharpen").second shouldBe "0b162242a4e673f6480b5206cf49ca50" } "mono:mean" { - val mImage = Image.open(NGC3344_MONO_8) + val mImage = Image.open(NGC3344_MONO_8_FITS) mImage.transform(Mean) mImage.save("mono-mean").second shouldBe "cf866292f657c379ae3965931dd8eeea" } "mono:invert" { - val mImage = Image.open(NGC3344_MONO_8) + val mImage = Image.open(NGC3344_MONO_8_FITS) mImage.transform(Invert) mImage.save("mono-invert").second shouldBe "6e94463bb5b9561de1f0ee0a154db53e" } "mono:emboss" { - val mImage = Image.open(NGC3344_MONO_8) + val mImage = Image.open(NGC3344_MONO_8_FITS) mImage.transform(Emboss) mImage.save("mono-emboss").second shouldBe "94a8ef5e4573e392d087cf10c905ba12" } "mono:edges" { - val mImage = Image.open(NGC3344_MONO_8) + val mImage = Image.open(NGC3344_MONO_8_FITS) mImage.transform(Edges) mImage.save("mono-edges").second shouldBe "27ccd5f5e6098d0cae27e7495e18dd72" } "mono:blur" { - val mImage = Image.open(NGC3344_MONO_8) + val mImage = Image.open(NGC3344_MONO_8_FITS) mImage.transform(Blur) mImage.save("mono-blur").second shouldBe "f2c5466dccf71b5c4bee86c5fbbb95fc" } "mono:gaussian blur" { - val mImage = Image.open(NGC3344_MONO_8) + val mImage = Image.open(NGC3344_MONO_8_FITS) mImage.transform(GaussianBlur(sigma = 5.0, size = 9)) mImage.save("mono-gaussian-blur").second shouldBe "69057b0c4461fb0d55b779da9e72fd69" } "mono:STF:midtone = 0.1, shadow = 0.0, highlight = 1.0" { - val mImage = Image.open(NGC3344_MONO_8) + val mImage = Image.open(NGC3344_MONO_8_FITS) mImage.transform(ScreenTransformFunction(0.1f)) mImage.save("mono-stf-01-00-10").second shouldBe "22c0bd985e70a01330722d912869d6ee" } "mono:STF:midtone = 0.9, shadow = 0.0, highlight = 1.0" { - val mImage = Image.open(NGC3344_MONO_8) + val mImage = Image.open(NGC3344_MONO_8_FITS) mImage.transform(ScreenTransformFunction(0.9f)) mImage.save("mono-stf-09-00-10").second shouldBe "553ccb7546dce3a8f742d5e8f7c58a3f" } "mono:STF:midtone = 0.1, shadow = 0.5, highlight = 1.0" { - val mImage = Image.open(NGC3344_MONO_8) + val mImage = Image.open(NGC3344_MONO_8_FITS) mImage.transform(ScreenTransformFunction(0.1f, shadow = 0.5f)) mImage.save("mono-stf-01-05-10").second shouldBe "f31db854fab72033dce2f8c572ec6783" } "mono:STF:midtone = 0.9, shadow = 0.5, highlight = 1.0" { - val mImage = Image.open(NGC3344_MONO_8) + val mImage = Image.open(NGC3344_MONO_8_FITS) mImage.transform(ScreenTransformFunction(0.9f, shadow = 0.5f)) mImage.save("mono-stf-09-05-10").second shouldBe "633b49c4a1dbb5ad8e6a9d74f330636d" } "mono:STF:midtone = 0.1, shadow = 0.0, highlight = 0.5" { - val mImage = Image.open(NGC3344_MONO_8) + val mImage = Image.open(NGC3344_MONO_8_FITS) mImage.transform(ScreenTransformFunction(0.1f, highlight = 0.5f)) mImage.save("mono-stf-01-00-05").second shouldBe "26036937eb3e5f99cd6129f709ce4b31" } "mono:STF:midtone = 0.9, shadow = 0.0, highlight = 0.5" { - val mImage = Image.open(NGC3344_MONO_8) + val mImage = Image.open(NGC3344_MONO_8_FITS) mImage.transform(ScreenTransformFunction(0.9f, highlight = 0.5f)) mImage.save("mono-stf-09-00-05").second shouldBe "e8f694dae666ac15ce2f8a169eb84024" } "mono:STF:midtone = 0.1, shadow = 0.4, highlight = 0.6" { - val mImage = Image.open(NGC3344_MONO_8) + val mImage = Image.open(NGC3344_MONO_8_FITS) mImage.transform(ScreenTransformFunction(0.1f, 0.4f, 0.6f)) mImage.save("mono-stf-01-04-06").second shouldBe "5226aba21669a24f985703b3e7220568" } "mono:STF:midtone = 0.9, shadow = 0.4, highlight = 0.6" { - val mImage = Image.open(NGC3344_MONO_8) + val mImage = Image.open(NGC3344_MONO_8_FITS) mImage.transform(ScreenTransformFunction(0.9f, 0.4f, 0.6f)) mImage.save("mono-stf-09-04-06").second shouldBe "c2acb25ef7be92a51f63e673ec9a850f" } "mono:auto STF" { - val mImage = Image.open(NGC3344_MONO_8) + val mImage = Image.open(NGC3344_MONO_8_FITS) mImage.transform(AutoScreenTransformFunction) mImage.save("mono-auto-stf").second shouldBe "e17cfc29c3b343409cd8617b6913330e" } "color:raw" { - val mImage = Image.open(NGC3344_COLOR_32) + val mImage = Image.open(NGC3344_COLOR_32_FITS) mImage.save("color-raw").second shouldBe "18fb83e240bc7a4cbafbc1aba2741db6" } "color:vertical flip" { - val mImage = Image.open(NGC3344_COLOR_32) + val mImage = Image.open(NGC3344_COLOR_32_FITS) mImage.transform(VerticalFlip) mImage.save("color-vertical-flip").second shouldBe "b717ecda5c5bba50cfa06304ef2bca88" } "color:horizontal flip" { - val mImage = Image.open(NGC3344_COLOR_32) + val mImage = Image.open(NGC3344_COLOR_32_FITS) mImage.transform(HorizontalFlip) mImage.save("color-horizontal-flip").second shouldBe "f70228600c77551473008ed4b9986439" } "color:vertical & horizontal flip" { - val mImage = Image.open(NGC3344_COLOR_32) + val mImage = Image.open(NGC3344_COLOR_32_FITS) mImage.transform(VerticalFlip, HorizontalFlip) mImage.save("color-vertical-horizontal-flip").second shouldBe "1237314044f20307b76203148af855e3" } "color:subframe" { - val mImage = Image.open(NGC3344_COLOR_32) + val mImage = Image.open(NGC3344_COLOR_32_FITS) val nImage = mImage.transform(SubFrame(45, 70, 16, 16)) nImage.width shouldBeExactly 16 nImage.height shouldBeExactly 16 @@ -148,122 +148,122 @@ class TransformAlgorithmTest : FitsStringSpec() { nImage.save("color-subframe").second shouldBe "282fc4fdf9142fcb4b18e1df1eef4caa" } "color:sharpen" { - val mImage = Image.open(NGC3344_COLOR_32) + val mImage = Image.open(NGC3344_COLOR_32_FITS) mImage.transform(Sharpen) mImage.save("color-sharpen").second shouldBe "e562282bdafdeba6ce88981bb9c3ba61" } "color:mean" { - val mImage = Image.open(NGC3344_COLOR_32) + val mImage = Image.open(NGC3344_COLOR_32_FITS) mImage.transform(Mean) mImage.save("color-mean").second shouldBe "a8380d928aaa756e202ba43bd3a2f207" } "color:invert" { - val mImage = Image.open(NGC3344_COLOR_32) + val mImage = Image.open(NGC3344_COLOR_32_FITS) mImage.transform(Invert) mImage.save("color-invert").second shouldBe "decad269ec26450aebeaf7546867b5f8" } "color:emboss" { - val mImage = Image.open(NGC3344_COLOR_32) + val mImage = Image.open(NGC3344_COLOR_32_FITS) mImage.transform(Emboss) mImage.save("color-emboss").second shouldBe "58d69250f1233055aa33f9ec7ca40af1" } "color:edges" { - val mImage = Image.open(NGC3344_COLOR_32) + val mImage = Image.open(NGC3344_COLOR_32_FITS) mImage.transform(Edges) mImage.save("color-edges").second shouldBe "091f2955740a8edcd2401dc416d19d51" } "color:blur" { - val mImage = Image.open(NGC3344_COLOR_32) + val mImage = Image.open(NGC3344_COLOR_32_FITS) mImage.transform(Blur) mImage.save("color-blur").second shouldBe "0fca440b763de5380fa29de736f3c792" } "color:gaussian blur" { - val mImage = Image.open(NGC3344_COLOR_32) + val mImage = Image.open(NGC3344_COLOR_32_FITS) mImage.transform(GaussianBlur(sigma = 5.0, size = 9)) mImage.save("color-gaussian-blur").second shouldBe "394d1a4f136f15c802dd73004c421d64" } "color:STF:midtone = 0.1, shadow = 0.0, highlight = 1.0" { - val mImage = Image.open(NGC3344_COLOR_32) + val mImage = Image.open(NGC3344_COLOR_32_FITS) mImage.transform(ScreenTransformFunction(0.1f)) mImage.save("color-stf-01-00-10").second shouldBe "e952bd263df6fd275b9a80aca554cb4b" } "color:STF:midtone = 0.9, shadow = 0.0, highlight = 1.0" { - val mImage = Image.open(NGC3344_COLOR_32) + val mImage = Image.open(NGC3344_COLOR_32_FITS) mImage.transform(ScreenTransformFunction(0.9f)) mImage.save("color-stf-09-00-10").second shouldBe "038809d7612018e2e5c19d5e1f551abd" } "color:STF:midtone = 0.1, shadow = 0.5, highlight = 1.0" { - val mImage = Image.open(NGC3344_COLOR_32) + val mImage = Image.open(NGC3344_COLOR_32_FITS) mImage.transform(ScreenTransformFunction(0.1f, shadow = 0.5f)) mImage.save("color-stf-01-05-10").second shouldBe "70e812260f56f8621002327575611f31" } "color:STF:midtone = 0.9, shadow = 0.5, highlight = 1.0" { - val mImage = Image.open(NGC3344_COLOR_32) + val mImage = Image.open(NGC3344_COLOR_32_FITS) mImage.transform(ScreenTransformFunction(0.9f, shadow = 0.5f)) mImage.save("color-stf-09-05-10").second shouldBe "6ca400f617f466a9eb02a3a6f2985d99" } "color:STF:midtone = 0.1, shadow = 0.0, highlight = 0.5" { - val mImage = Image.open(NGC3344_COLOR_32) + val mImage = Image.open(NGC3344_COLOR_32_FITS) mImage.transform(ScreenTransformFunction(0.1f, highlight = 0.5f)) mImage.save("color-stf-01-00-05").second shouldBe "3cd98ee9a8949d5100295acccd77010b" } "color:STF:midtone = 0.9, shadow = 0.0, highlight = 0.5" { - val mImage = Image.open(NGC3344_COLOR_32) + val mImage = Image.open(NGC3344_COLOR_32_FITS) mImage.transform(ScreenTransformFunction(0.9f, highlight = 0.5f)) mImage.save("color-stf-09-00-05").second shouldBe "2cfeffc88c893cc5883d8a2221f29b91" } "color:STF:midtone = 0.1, shadow = 0.4, highlight = 0.6" { - val mImage = Image.open(NGC3344_COLOR_32) + val mImage = Image.open(NGC3344_COLOR_32_FITS) mImage.transform(ScreenTransformFunction(0.1f, 0.4f, 0.6f)) mImage.save("color-stf-01-04-06").second shouldBe "532a07a1a166eb007c2e40651aec2097" } "color:STF:midtone = 0.9, shadow = 0.4, highlight = 0.6" { - val mImage = Image.open(NGC3344_COLOR_32) + val mImage = Image.open(NGC3344_COLOR_32_FITS) mImage.transform(ScreenTransformFunction(0.9f, 0.4f, 0.6f)) mImage.save("color-stf-09-04-06").second shouldBe "eb3d940d9fd2c8814e930715e89897c4" } "color:auto STF" { - val mImage = Image.open(NGC3344_COLOR_32) + val mImage = Image.open(NGC3344_COLOR_32_FITS) mImage.transform(AutoScreenTransformFunction) mImage.save("color-auto-stf").second shouldBe "a9c3657d8597b927607eb438e666d3a0" } "color:SCNR Maximum Mask" { - val mImage = Image.open(NGC3344_COLOR_32) + val mImage = Image.open(NGC3344_COLOR_32_FITS) mImage.transform(SubtractiveChromaticNoiseReduction(ImageChannel.RED, 1f, ProtectionMethod.MAXIMUM_MASK)) mImage.save("color-scnr-maximum-mask").second shouldBe "e7d2155e18ff1e3172f4e849ae983145" } "color:SCNR Additive Mask" { - val mImage = Image.open(NGC3344_COLOR_32) + val mImage = Image.open(NGC3344_COLOR_32_FITS) mImage.transform(SubtractiveChromaticNoiseReduction(ImageChannel.RED, 1f, ProtectionMethod.ADDITIVE_MASK)) mImage.save("color-scnr-additive-mask").second shouldBe "a458c44cedcda704de16d80053fd87eb" } "color:SCNR Average Neutral" { - val mImage = Image.open(NGC3344_COLOR_32) + val mImage = Image.open(NGC3344_COLOR_32_FITS) mImage.transform(SubtractiveChromaticNoiseReduction(ImageChannel.RED, 1f, ProtectionMethod.AVERAGE_NEUTRAL)) mImage.save("color-scnr-average-neutral").second shouldBe "e07345ffc4982a62301c95c76d3efb35" } "color:SCNR Maximum Neutral" { - val mImage = Image.open(NGC3344_COLOR_32) + val mImage = Image.open(NGC3344_COLOR_32_FITS) mImage.transform(SubtractiveChromaticNoiseReduction(ImageChannel.RED, 1f, ProtectionMethod.MAXIMUM_NEUTRAL)) mImage.save("color-scnr-maximum-neutral").second shouldBe "a1d4b04f57b001ba4a996bab0407fd7e" } "color:SCNR Minimum Neutral" { - val mImage = Image.open(NGC3344_COLOR_32) + val mImage = Image.open(NGC3344_COLOR_32_FITS) mImage.transform(SubtractiveChromaticNoiseReduction(ImageChannel.RED, 1f, ProtectionMethod.MINIMUM_NEUTRAL)) mImage.save("color-scnr-minimum-neutral").second shouldBe "8b7be57ff38da9c97b35d7888047c0f9" } "color:grayscale BT-709" { - val mImage = Image.open(NGC3344_COLOR_32) + val mImage = Image.open(NGC3344_COLOR_32_FITS) val nImage = mImage.transform(Grayscale.BT709) nImage.save("color-grayscale-bt709").second shouldBe "cab675aa35390a2d58cd48555d91054f" } "color:grayscale RMY" { - val mImage = Image.open(NGC3344_COLOR_32) + val mImage = Image.open(NGC3344_COLOR_32_FITS) val nImage = mImage.transform(Grayscale.RMY) nImage.save("color-grayscale-rmy").second shouldBe "e113627002a4178d1010a2f6246e325f" } "color:grayscale Y" { - val mImage = Image.open(NGC3344_COLOR_32) + val mImage = Image.open(NGC3344_COLOR_32_FITS) val nImage = mImage.transform(Grayscale.Y) nImage.save("color-grayscale-y").second shouldBe "24dd4a7e0fa9e4be34c53c924a78a940" } diff --git a/nebulosa-imaging/src/test/resources/Debayer.fits b/nebulosa-imaging/src/test/resources/Debayer.fits deleted file mode 100644 index 03ada23d6d414096312cf0fe7dc7744366a75fe6..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 138240 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 = emptyList(), -) : ReadOnlyHeader(header) { +) : FitsHeader.ReadOnly(header) { override fun readOnly() = this @@ -34,16 +34,16 @@ data class PlateSolution( @JvmStatic private val LOG = loggerFor() @JvmStatic - fun from(header: Header): PlateSolution? { + fun from(header: ReadableHeader): PlateSolution? { val (cd11, cd12, _, cd22) = header.computeCdMatrix() - val crota2 = header.getDoubleOrNull(Standard.CROTA2)?.deg ?: atan2(cd12, cd11).rad + val crota2 = header.getDoubleOrNull(FitsKeywordDictionary.CROTA2)?.deg ?: atan2(cd12, cd11).rad // https://danmoser.github.io/notes/gai_fits-imgs.html - val cdelt1 = header.getDoubleOrNull(Standard.CDELT1)?.deg ?: (cd11 / cos(crota2)).deg - val cdelt2 = header.getDoubleOrNull(Standard.CDELT2)?.deg ?: (cd22 / cos(crota2)).deg - val crval1 = header.getDoubleOrNull(Standard.CRVAL1)?.deg ?: return null - val crval2 = header.getDoubleOrNull(Standard.CRVAL2)?.deg ?: return null - val width = header.getIntOrNull(Standard.NAXIS1) ?: header.getInt("IMAGEW", 0) - val height = header.getIntOrNull(Standard.NAXIS2) ?: header.getInt("IMAGEH", 0) + val cdelt1 = header.getDoubleOrNull(FitsKeywordDictionary.CDELT1)?.deg ?: (cd11 / cos(crota2)).deg + val cdelt2 = header.getDoubleOrNull(FitsKeywordDictionary.CDELT2)?.deg ?: (cd22 / cos(crota2)).deg + val crval1 = header.getDoubleOrNull(FitsKeywordDictionary.CRVAL1)?.deg ?: return null + val crval2 = header.getDoubleOrNull(FitsKeywordDictionary.CRVAL2)?.deg ?: return null + val width = header.getIntOrNull(FitsKeywordDictionary.NAXIS1) ?: header.getInt("IMAGEW", 0) + val height = header.getIntOrNull(FitsKeywordDictionary.NAXIS2) ?: header.getInt("IMAGEH", 0) LOG.info( "solution from {}: ORIE={}, SCALE={}, RA={}, DEC={}", diff --git a/nebulosa-plate-solving/src/main/kotlin/nebulosa/plate/solving/PlateSolver.kt b/nebulosa-plate-solving/src/main/kotlin/nebulosa/plate/solving/PlateSolver.kt index 13efcc880..27ef2dadb 100644 --- a/nebulosa-plate-solving/src/main/kotlin/nebulosa/plate/solving/PlateSolver.kt +++ b/nebulosa-plate-solving/src/main/kotlin/nebulosa/plate/solving/PlateSolver.kt @@ -1,7 +1,7 @@ package nebulosa.plate.solving import nebulosa.common.concurrency.cancel.CancellationToken -import nebulosa.imaging.Image +import nebulosa.image.Image import nebulosa.math.Angle import java.nio.file.Path import java.time.Duration diff --git a/nebulosa-plate-solving/src/test/kotlin/PlateSolutionTest.kt b/nebulosa-plate-solving/src/test/kotlin/PlateSolutionTest.kt index 635c3341c..90afd4273 100644 --- a/nebulosa-plate-solving/src/test/kotlin/PlateSolutionTest.kt +++ b/nebulosa-plate-solving/src/test/kotlin/PlateSolutionTest.kt @@ -2,7 +2,7 @@ import io.kotest.core.spec.style.StringSpec import io.kotest.matchers.doubles.plusOrMinus import io.kotest.matchers.nulls.shouldNotBeNull import io.kotest.matchers.shouldBe -import nebulosa.fits.Header +import nebulosa.fits.FitsHeader import nebulosa.math.formatHMS import nebulosa.math.formatSignedDMS import nebulosa.math.toArcsec @@ -38,7 +38,7 @@ class PlateSolutionTest : StringSpec() { "END " "astrometry.net" { - val header = Header.from(astrometryNet) + val header = FitsHeader.from(astrometryNet) val solution = PlateSolution.from(header).shouldNotBeNull() solution.rightAscension.formatHMS() shouldBe "03h19m07.7s" diff --git a/nebulosa-sbd/src/test/kotlin/SmallBodyCloseApprochServiceTest.kt b/nebulosa-sbd/src/test/kotlin/SmallBodyCloseApprochServiceTest.kt index 267d7c7b0..7fb3a2f17 100644 --- a/nebulosa-sbd/src/test/kotlin/SmallBodyCloseApprochServiceTest.kt +++ b/nebulosa-sbd/src/test/kotlin/SmallBodyCloseApprochServiceTest.kt @@ -15,7 +15,7 @@ class SmallBodyCloseApprochServiceTest : StringSpec() { val service = SmallBodyDatabaseService() "search" { - val data = service.closeApproaches(distance = 10, date = LocalDate.of(2024, 3, 13)).execute().body() + val data = service.closeApproaches(distance = 10.0, date = LocalDate.of(2024, 3, 13)).execute().body() data.shouldNotBeNull() data.count shouldBeGreaterThanOrEqual 1 diff --git a/nebulosa-test/build.gradle.kts b/nebulosa-test/build.gradle.kts index 42421be4f..6ab8f1936 100644 --- a/nebulosa-test/build.gradle.kts +++ b/nebulosa-test/build.gradle.kts @@ -7,6 +7,7 @@ dependencies { api(project(":nebulosa-io")) api(project(":nebulosa-hips2fits")) api(project(":nebulosa-fits")) + api(project(":nebulosa-xisf")) api(libs.okhttp) api(libs.bundles.kotest) } diff --git a/nebulosa-test/src/main/kotlin/nebulosa/test/FitsStringSpec.kt b/nebulosa-test/src/main/kotlin/nebulosa/test/FitsStringSpec.kt index 151665d1d..d0de7282b 100644 --- a/nebulosa-test/src/main/kotlin/nebulosa/test/FitsStringSpec.kt +++ b/nebulosa-test/src/main/kotlin/nebulosa/test/FitsStringSpec.kt @@ -1,112 +1,170 @@ package nebulosa.test +import io.kotest.core.listeners.TestListener import io.kotest.core.spec.style.StringSpec +import io.kotest.core.test.TestCase +import io.kotest.core.test.TestResult +import io.kotest.core.test.TestScope +import nebulosa.fits.FitsPath import nebulosa.fits.fits import nebulosa.io.transferAndCloseOutput +import nebulosa.xisf.XisfPath +import nebulosa.xisf.xisf import okhttp3.OkHttpClient import okhttp3.Request +import okhttp3.logging.HttpLoggingInterceptor import okio.ByteString.Companion.toByteString import java.awt.image.BufferedImage +import java.io.Closeable import java.nio.file.Path +import java.util.concurrent.ConcurrentHashMap import java.util.concurrent.TimeUnit -import java.util.zip.ZipInputStream import javax.imageio.ImageIO import kotlin.io.path.* @Suppress("PropertyName") abstract class FitsStringSpec : StringSpec() { - protected val FITS_DIR = "../data/fits" - - protected val NGC3344_COLOR_8 by lazy { "$FITS_DIR/NGC3344.Color.8.fits".fits() } - protected val NGC3344_COLOR_16 by lazy { "$FITS_DIR/NGC3344.Color.16.fits".fits() } - protected val NGC3344_COLOR_32 by lazy { "$FITS_DIR/NGC3344.Color.32.fits".fits() } - protected val NGC3344_COLOR_F32 by lazy { "$FITS_DIR/NGC3344.Color.F32.fits".fits() } - protected val NGC3344_COLOR_F64 by lazy { "$FITS_DIR/NGC3344.Color.F64.fits".fits() } - protected val NGC3344_MONO_8 by lazy { "$FITS_DIR/NGC3344.Mono.8.fits".fits() } - protected val NGC3344_MONO_16 by lazy { "$FITS_DIR/NGC3344.Mono.16.fits".fits() } - protected val NGC3344_MONO_32 by lazy { "$FITS_DIR/NGC3344.Mono.32.fits".fits() } - protected val NGC3344_MONO_F32 by lazy { "$FITS_DIR/NGC3344.Mono.F32.fits".fits() } - protected val NGC3344_MONO_F64 by lazy { "$FITS_DIR/NGC3344.Mono.F64.fits".fits() } - protected val M6707HH by lazy { download("M6707HH.fits", ASTROPY_PHOTOMETRY_URL).fits() } - protected val STAR_FOCUS_1 by lazy { "$FITS_DIR/STAR_FOCUS_1.fits".fits() } - protected val STAR_FOCUS_2 by lazy { "$FITS_DIR/STAR_FOCUS_2.fits".fits() } - protected val STAR_FOCUS_3 by lazy { "$FITS_DIR/STAR_FOCUS_3.fits".fits() } - protected val STAR_FOCUS_4 by lazy { "$FITS_DIR/STAR_FOCUS_4.fits".fits() } - protected val STAR_FOCUS_5 by lazy { "$FITS_DIR/STAR_FOCUS_5.fits".fits() } - protected val STAR_FOCUS_6 by lazy { "$FITS_DIR/STAR_FOCUS_6.fits".fits() } - protected val STAR_FOCUS_7 by lazy { "$FITS_DIR/STAR_FOCUS_7.fits".fits() } - protected val STAR_FOCUS_8 by lazy { "$FITS_DIR/STAR_FOCUS_8.fits".fits() } - protected val STAR_FOCUS_9 by lazy { "$FITS_DIR/STAR_FOCUS_9.fits".fits() } - protected val STAR_FOCUS_10 by lazy { "$FITS_DIR/STAR_FOCUS_10.fits".fits() } - protected val STAR_FOCUS_11 by lazy { "$FITS_DIR/STAR_FOCUS_11.fits".fits() } - protected val STAR_FOCUS_12 by lazy { "$FITS_DIR/STAR_FOCUS_12.fits".fits() } - protected val STAR_FOCUS_13 by lazy { "$FITS_DIR/STAR_FOCUS_13.fits".fits() } - protected val STAR_FOCUS_14 by lazy { "$FITS_DIR/STAR_FOCUS_14.fits".fits() } - protected val STAR_FOCUS_15 by lazy { "$FITS_DIR/STAR_FOCUS_15.fits".fits() } - protected val STAR_FOCUS_16 by lazy { "$FITS_DIR/STAR_FOCUS_16.fits".fits() } - protected val STAR_FOCUS_17 by lazy { "$FITS_DIR/STAR_FOCUS_17.fits".fits() } - protected val UNCALIBRATED by lazy { "$FITS_DIR/UNCALIBRATED.fits".fits() } - protected val DARK by lazy { "$FITS_DIR/DARK.fits".fits() } - protected val FLAT by lazy { "$FITS_DIR/FLAT.fits".fits() } - protected val BIAS by lazy { "$FITS_DIR/BIAS.fits".fits() } + protected val M82_MONO_8_LZ4_XISF by lazy { download("M82.Mono.8.LZ4.xisf", GITHUB_XISF_URL) } + protected val M82_MONO_8_LZ4_HC_XISF by lazy { download("M82.Mono.8.LZ4-HC.xisf", GITHUB_XISF_URL) } + protected val M82_MONO_8_XISF by lazy { download("M82.Mono.8.xisf", GITHUB_XISF_URL) } + protected val M82_MONO_8_ZLIB_XISF by lazy { download("M82.Mono.8.ZLib.xisf", GITHUB_XISF_URL) } + protected val M82_MONO_8_ZSTANDARD_XISF by lazy { download("M82.Mono.8.ZStandard.xisf", GITHUB_XISF_URL) } + protected val M82_MONO_16_XISF by lazy { download("M82.Mono.16.xisf", GITHUB_XISF_URL) } + protected val M82_MONO_32_XISF by lazy { download("M82.Mono.32.xisf", GITHUB_XISF_URL) } + protected val M82_MONO_F32_XISF by lazy { download("M82.Mono.F32.xisf", GITHUB_XISF_URL) } + protected val M82_MONO_F64_XISF by lazy { download("M82.Mono.F64.xisf", GITHUB_XISF_URL) } + + protected val M82_COLOR_8_LZ4_XISF by lazy { download("M82.Color.8.LZ4.xisf", GITHUB_XISF_URL) } + protected val M82_COLOR_8_LZ4_HC_XISF by lazy { download("M82.Color.8.LZ4-HC.xisf", GITHUB_XISF_URL) } + protected val M82_COLOR_8_XISF by lazy { download("M82.Color.8.xisf", GITHUB_XISF_URL) } + protected val M82_COLOR_8_ZLIB_XISF by lazy { download("M82.Color.8.ZLib.xisf", GITHUB_XISF_URL) } + protected val M82_COLOR_8_ZSTANDARD_XISF by lazy { download("M82.Color.8.ZStandard.xisf", GITHUB_XISF_URL) } + protected val M82_COLOR_16_XISF by lazy { download("M82.Color.16.xisf", GITHUB_XISF_URL) } + protected val M82_COLOR_32_XISF by lazy { download("M82.Color.32.xisf", GITHUB_XISF_URL) } + protected val M82_COLOR_F32_XISF by lazy { download("M82.Color.F32.xisf", GITHUB_XISF_URL) } + protected val M82_COLOR_F64_XISF by lazy { download("M82.Color.F64.xisf", GITHUB_XISF_URL) } + + protected val NGC3344_COLOR_8_FITS_PATH by lazy { download("NGC3344.Color.8.fits", GITHUB_FITS_URL) } + protected val NGC3344_COLOR_16_FITS_PATH by lazy { download("NGC3344.Color.16.fits", GITHUB_FITS_URL) } + protected val NGC3344_COLOR_32_FITS_PATH by lazy { download("NGC3344.Color.32.fits", GITHUB_FITS_URL) } + protected val NGC3344_COLOR_F32_FITS_PATH by lazy { download("NGC3344.Color.F32.fits", GITHUB_FITS_URL) } + protected val NGC3344_COLOR_F64_FITS_PATH by lazy { download("NGC3344.Color.F64.fits", GITHUB_FITS_URL) } + protected val NGC3344_MONO_8_FITS_PATH by lazy { download("NGC3344.Mono.8.fits", GITHUB_FITS_URL) } + protected val NGC3344_MONO_16_FITS_PATH by lazy { download("NGC3344.Mono.16.fits", GITHUB_FITS_URL) } + protected val NGC3344_MONO_32_FITS_PATH by lazy { download("NGC3344.Mono.32.fits", GITHUB_FITS_URL) } + protected val NGC3344_MONO_F32_FITS_PATH by lazy { download("NGC3344.Mono.F32.fits", GITHUB_FITS_URL) } + protected val NGC3344_MONO_F64_FITS_PATH by lazy { download("NGC3344.Mono.F64.fits", GITHUB_FITS_URL) } + + protected val NGC3344_COLOR_8_FITS by lazy { NGC3344_COLOR_8_FITS_PATH.fits() } + protected val NGC3344_COLOR_16_FITS by lazy { NGC3344_COLOR_16_FITS_PATH.fits() } + protected val NGC3344_COLOR_32_FITS by lazy { NGC3344_COLOR_32_FITS_PATH.fits() } + protected val NGC3344_COLOR_F32_FITS by lazy { NGC3344_COLOR_F32_FITS_PATH.fits() } + protected val NGC3344_COLOR_F64_FITS by lazy { NGC3344_COLOR_F64_FITS_PATH.fits() } + protected val NGC3344_MONO_8_FITS by lazy { NGC3344_MONO_8_FITS_PATH.fits() } + protected val NGC3344_MONO_16_FITS by lazy { NGC3344_MONO_16_FITS_PATH.fits() } + protected val NGC3344_MONO_32_FITS by lazy { NGC3344_MONO_32_FITS_PATH.fits() } + protected val NGC3344_MONO_F32_FITS by lazy { NGC3344_MONO_F32_FITS_PATH.fits() } + protected val NGC3344_MONO_F64_FITS by lazy { NGC3344_MONO_F64_FITS_PATH.fits() } + + protected val M6707HH by lazyFITS("M6707HH.fits", ASTROPY_PHOTOMETRY_URL) + + protected val STAR_FOCUS_1 by lazyFITS("STAR.FOCUS.1.fits") + protected val STAR_FOCUS_2 by lazyFITS("STAR.FOCUS.2.fits") + protected val STAR_FOCUS_3 by lazyFITS("STAR.FOCUS.3.fits") + protected val STAR_FOCUS_4 by lazyFITS("STAR.FOCUS.4.fits") + protected val STAR_FOCUS_5 by lazyFITS("STAR.FOCUS.5.fits") + protected val STAR_FOCUS_6 by lazyFITS("STAR.FOCUS.6.fits") + protected val STAR_FOCUS_7 by lazyFITS("STAR.FOCUS.7.fits") + protected val STAR_FOCUS_8 by lazyFITS("STAR.FOCUS.8.fits") + protected val STAR_FOCUS_9 by lazyFITS("STAR.FOCUS.9.fits") + protected val STAR_FOCUS_10 by lazyFITS("STAR.FOCUS.10.fits") + protected val STAR_FOCUS_11 by lazyFITS("STAR.FOCUS.11.fits") + protected val STAR_FOCUS_12 by lazyFITS("STAR.FOCUS.12.fits") + protected val STAR_FOCUS_13 by lazyFITS("STAR.FOCUS.13.fits") + protected val STAR_FOCUS_14 by lazyFITS("STAR.FOCUS.14.fits") + protected val STAR_FOCUS_15 by lazyFITS("STAR.FOCUS.15.fits") + protected val STAR_FOCUS_16 by lazyFITS("STAR.FOCUS.16.fits") + protected val STAR_FOCUS_17 by lazyFITS("STAR.FOCUS.17.fits") + + private val afterEach = AfterEach() + + init { + prependExtension(afterEach) + } + + protected fun TestScope.closeAfterEach(closeable: T) = closeable.apply { + afterEach[testCase] = this + } protected fun BufferedImage.save(name: String): Pair { - val path = Path.of("src", "test", "resources", "saved", "$name.png").createParentDirectories() + val path = Path.of("..", "data", "test", "$name.png").createParentDirectories() ImageIO.write(this, "PNG", path.toFile()) - return path to path.md5() + val md5 = path.md5() + println("$name: $md5") + return path to md5 } protected fun Path.md5(): String { return readBytes().toByteString().md5().hex() } + protected fun lazyFITS(name: String, baseUrl: String = GITHUB_FITS_URL): Lazy { + return lazy { download(name, baseUrl).fits() } + } + + protected fun lazyXISF(name: String, baseUrl: String = GITHUB_XISF_URL): Lazy { + return lazy { download(name, baseUrl).xisf() } + } + protected fun download(name: String, baseUrl: String): Path { - val path = Path.of(System.getProperty("java.io.tmpdir"), name) + return synchronize(name) { + val path = Path.of(System.getProperty("java.io.tmpdir"), name) - if (path.exists() && path.fileSize() > 0L) { - return path - } + if (!path.exists() || path.fileSize() <= 0L) { + val request = Request.Builder() + .get() + .url("$baseUrl/$name") + .build() - val request = Request.Builder() - .get() - .url("$baseUrl/$name") - .build() + val call = HTTP_CLIENT.newCall(request) - val call = HTTP_CLIENT.newCall(request) + call.execute().use { + it.body?.byteStream()?.transferAndCloseOutput(path.outputStream()) + } + } - call.execute().use { - it.body?.byteStream()?.transferAndCloseOutput(path.outputStream()) + path } - - return path } - protected fun unzip(name: String) { - val path = Path.of(FITS_DIR, "$name.zip") - - with(ZipInputStream(path.inputStream())) { - var zipEntry = getNextEntry() - - while (zipEntry != null) { - transferAndCloseOutput(Path.of(FITS_DIR, zipEntry.name).outputStream()) - zipEntry = getNextEntry() - } + @Suppress("BlockingMethodInNonBlockingContext") + private class AfterEach : ConcurrentHashMap(), TestListener { - closeEntry() - close() + override suspend fun afterEach(testCase: TestCase, result: TestResult) { + remove(testCase)?.close() } } companion object { const val ASTROPY_PHOTOMETRY_URL = "https://www.astropy.org/astropy-data/photometry" + const val GITHUB_FITS_URL = "https://github.com/tiagohm/nebulosa.data/raw/main/test/fits" + const val GITHUB_XISF_URL = "https://github.com/tiagohm/nebulosa.data/raw/main/test/xisf" @JvmStatic val HTTP_CLIENT = OkHttpClient.Builder() .readTimeout(60L, TimeUnit.SECONDS) .writeTimeout(60L, TimeUnit.SECONDS) .connectTimeout(60L, TimeUnit.SECONDS) .callTimeout(60L, TimeUnit.SECONDS) + .addInterceptor(HttpLoggingInterceptor().setLevel(HttpLoggingInterceptor.Level.BASIC)) .build() + + @JvmStatic @PublishedApi internal val SYNC_KEYS = ConcurrentHashMap() + + inline fun synchronize(key: String, block: () -> R): R { + val lock = synchronized(SYNC_KEYS) { SYNC_KEYS.getOrPut(key) { Any() } } + return synchronized(lock, block) + } } } diff --git a/nebulosa-test/src/main/kotlin/nebulosa/test/MathMatchers.kt b/nebulosa-test/src/main/kotlin/nebulosa/test/matchers/MathMatchers.kt similarity index 98% rename from nebulosa-test/src/main/kotlin/nebulosa/test/MathMatchers.kt rename to nebulosa-test/src/main/kotlin/nebulosa/test/matchers/MathMatchers.kt index f49e4ad40..e884006eb 100644 --- a/nebulosa-test/src/main/kotlin/nebulosa/test/MathMatchers.kt +++ b/nebulosa-test/src/main/kotlin/nebulosa/test/matchers/MathMatchers.kt @@ -1,6 +1,6 @@ @file:Suppress("NOTHING_TO_INLINE") -package nebulosa.test +package nebulosa.test.matchers import io.kotest.matchers.Matcher import io.kotest.matchers.MatcherResult @@ -10,6 +10,8 @@ import nebulosa.math.Vector3D inline infix fun Vector3D.plusOrMinus(tolerance: Double) = Vector3DMatcher(this, tolerance) +inline infix fun Matrix3D.plusOrMinus(tolerance: Double) = Matrix3DMatcher(this, tolerance) + class Vector3DMatcher(expected: Vector3D, tolerance: Double) : Matcher { private val xMatcher = ToleranceMatcher(expected.x, tolerance) @@ -23,8 +25,6 @@ class Vector3DMatcher(expected: Vector3D, tolerance: Double) : Matcher } } -inline infix fun Matrix3D.plusOrMinus(tolerance: Double) = Matrix3DMatcher(this, tolerance) - class Matrix3DMatcher(expected: Matrix3D, tolerance: Double) : Matcher { private val a11Matcher = ToleranceMatcher(expected.a11, tolerance) diff --git a/nebulosa-watney/build.gradle.kts b/nebulosa-watney/build.gradle.kts index 7b107551b..fd34d8f83 100644 --- a/nebulosa-watney/build.gradle.kts +++ b/nebulosa-watney/build.gradle.kts @@ -5,7 +5,7 @@ plugins { dependencies { api(project(":nebulosa-erfa")) - api(project(":nebulosa-imaging")) + api(project(":nebulosa-image")) api(project(":nebulosa-star-detection")) api(project(":nebulosa-plate-solving")) api(libs.apache.collections) diff --git a/nebulosa-watney/src/main/kotlin/nebulosa/watney/plate/solving/ComputedPlateSolution.kt b/nebulosa-watney/src/main/kotlin/nebulosa/watney/plate/solving/ComputedPlateSolution.kt index cf011c837..ebb7a4ac9 100644 --- a/nebulosa-watney/src/main/kotlin/nebulosa/watney/plate/solving/ComputedPlateSolution.kt +++ b/nebulosa-watney/src/main/kotlin/nebulosa/watney/plate/solving/ComputedPlateSolution.kt @@ -1,11 +1,12 @@ package nebulosa.watney.plate.solving -import nebulosa.fits.Header +import nebulosa.image.format.Header +import nebulosa.image.format.ReadableHeader import nebulosa.math.Angle import nebulosa.plate.solving.Parity internal data class ComputedPlateSolution( - @JvmField val header: Header = Header(), + @JvmField val header: ReadableHeader = Header.Empty, @JvmField val orientation: Angle = 0.0, @JvmField val pixelScale: Double = 0.0, // arcsec/px @JvmField val centerRA: Angle = 0.0, diff --git a/nebulosa-watney/src/main/kotlin/nebulosa/watney/plate/solving/WatneyPlateSolver.kt b/nebulosa-watney/src/main/kotlin/nebulosa/watney/plate/solving/WatneyPlateSolver.kt index 9df007b95..474d14f1e 100644 --- a/nebulosa-watney/src/main/kotlin/nebulosa/watney/plate/solving/WatneyPlateSolver.kt +++ b/nebulosa-watney/src/main/kotlin/nebulosa/watney/plate/solving/WatneyPlateSolver.kt @@ -2,11 +2,10 @@ package nebulosa.watney.plate.solving import nebulosa.common.concurrency.cancel.CancellationToken import nebulosa.erfa.SphericalCoordinate -import nebulosa.fits.Header -import nebulosa.fits.NOAOExt -import nebulosa.fits.Standard +import nebulosa.fits.FitsHeader +import nebulosa.fits.FitsKeywordDictionary import nebulosa.fits.fits -import nebulosa.imaging.Image +import nebulosa.image.Image import nebulosa.log.debug import nebulosa.log.loggerFor import nebulosa.math.Angle @@ -391,19 +390,19 @@ data class WatneyPlateSolver( val scopePxX = (-pc.b * scopePxY + (-pc.c)) / pc.a val parity = if (sign < 0) Parity.NORMAL else Parity.FLIPPED - val header = Header() - header.add(Standard.CDELT1, cdelt1) - header.add(Standard.CDELT2, cdelt2) - header.add(Standard.CROTA1, crota1.toDegrees) - header.add(Standard.CROTA2, crota2.toDegrees) - header.add(Standard.CRVAL1, scopeCoordsRA.toDegrees) - header.add(Standard.CRVAL2, scopeCoordsDEC.toDegrees) - header.add(Standard.CRPIX1, scopePxX) - header.add(Standard.CRPIX2, scopePxY) - header.add(NOAOExt.CD1_1, cd11) - header.add(NOAOExt.CD1_2, cd12) - header.add(NOAOExt.CD1_1, cd11) - header.add(NOAOExt.CD2_2, cd22) + val header = FitsHeader() + header.add(FitsKeywordDictionary.CDELT1, cdelt1) + header.add(FitsKeywordDictionary.CDELT2, cdelt2) + header.add(FitsKeywordDictionary.CROTA1, crota1.toDegrees) + header.add(FitsKeywordDictionary.CROTA2, crota2.toDegrees) + header.add(FitsKeywordDictionary.CRVAL1, scopeCoordsRA.toDegrees) + header.add(FitsKeywordDictionary.CRVAL2, scopeCoordsDEC.toDegrees) + header.add(FitsKeywordDictionary.CRPIX1, scopePxX) + header.add(FitsKeywordDictionary.CRPIX2, scopePxY) + header.add(FitsKeywordDictionary.CD1_1, cd11) + header.add(FitsKeywordDictionary.CD1_2, cd12) + header.add(FitsKeywordDictionary.CD1_1, cd11) + header.add(FitsKeywordDictionary.CD2_2, cd22) return ComputedPlateSolution( header, crota1, pixScale, scopeCoordsRA, scopeCoordsDEC, diff --git a/nebulosa-watney/src/main/kotlin/nebulosa/watney/star/detection/DefaultStarDetectionFilter.kt b/nebulosa-watney/src/main/kotlin/nebulosa/watney/star/detection/DefaultStarDetectionFilter.kt index 69ee3764c..cd3a4468e 100644 --- a/nebulosa-watney/src/main/kotlin/nebulosa/watney/star/detection/DefaultStarDetectionFilter.kt +++ b/nebulosa-watney/src/main/kotlin/nebulosa/watney/star/detection/DefaultStarDetectionFilter.kt @@ -2,7 +2,7 @@ package nebulosa.watney.star.detection import nebulosa.constants.PI import nebulosa.constants.TAU -import nebulosa.imaging.Image +import nebulosa.image.Image import kotlin.math.max object DefaultStarDetectionFilter : StarDetectionFilter { diff --git a/nebulosa-watney/src/main/kotlin/nebulosa/watney/star/detection/StarDetectionFilter.kt b/nebulosa-watney/src/main/kotlin/nebulosa/watney/star/detection/StarDetectionFilter.kt index a9991fe50..b972d6967 100644 --- a/nebulosa-watney/src/main/kotlin/nebulosa/watney/star/detection/StarDetectionFilter.kt +++ b/nebulosa-watney/src/main/kotlin/nebulosa/watney/star/detection/StarDetectionFilter.kt @@ -1,6 +1,6 @@ package nebulosa.watney.star.detection -import nebulosa.imaging.Image +import nebulosa.image.Image /** * Interface for filtering stars after initial star detection. diff --git a/nebulosa-watney/src/main/kotlin/nebulosa/watney/star/detection/WatneyStarDetector.kt b/nebulosa-watney/src/main/kotlin/nebulosa/watney/star/detection/WatneyStarDetector.kt index f556e5469..0786eb5ad 100644 --- a/nebulosa-watney/src/main/kotlin/nebulosa/watney/star/detection/WatneyStarDetector.kt +++ b/nebulosa-watney/src/main/kotlin/nebulosa/watney/star/detection/WatneyStarDetector.kt @@ -1,8 +1,8 @@ package nebulosa.watney.star.detection -import nebulosa.imaging.Image -import nebulosa.imaging.algorithms.computation.Statistics -import nebulosa.imaging.algorithms.computation.hfd.HFD +import nebulosa.image.Image +import nebulosa.image.algorithms.computation.Statistics +import nebulosa.image.algorithms.computation.hfd.HFD import nebulosa.star.detection.StarDetector import kotlin.math.roundToInt diff --git a/nebulosa-watney/src/test/kotlin/WatnetPlateSolverTest.kt b/nebulosa-watney/src/test/kotlin/WatnetPlateSolverTest.kt index 05c2a974d..c669eaa33 100644 --- a/nebulosa-watney/src/test/kotlin/WatnetPlateSolverTest.kt +++ b/nebulosa-watney/src/test/kotlin/WatnetPlateSolverTest.kt @@ -3,7 +3,7 @@ import io.kotest.matchers.collections.shouldHaveSize import io.kotest.matchers.doubles.plusOrMinus import io.kotest.matchers.ints.shouldBeExactly import io.kotest.matchers.shouldBe -import nebulosa.imaging.Image +import nebulosa.image.Image import nebulosa.math.deg import nebulosa.test.Hips2FitsStringSpec import nebulosa.test.NonGitHubOnlyCondition diff --git a/nebulosa-watney/src/test/kotlin/WatneyStarDetectorTest.kt b/nebulosa-watney/src/test/kotlin/WatneyStarDetectorTest.kt index 0d8734dea..619473ceb 100644 --- a/nebulosa-watney/src/test/kotlin/WatneyStarDetectorTest.kt +++ b/nebulosa-watney/src/test/kotlin/WatneyStarDetectorTest.kt @@ -1,8 +1,8 @@ import io.kotest.matchers.collections.shouldHaveSize import io.kotest.matchers.shouldBe -import nebulosa.imaging.Image -import nebulosa.imaging.algorithms.transformation.Draw -import nebulosa.imaging.algorithms.transformation.convolution.Mean +import nebulosa.image.Image +import nebulosa.image.algorithms.transformation.Draw +import nebulosa.image.algorithms.transformation.convolution.Mean import nebulosa.star.detection.ImageStar import nebulosa.test.FitsStringSpec import nebulosa.watney.star.detection.WatneyStarDetector @@ -16,7 +16,7 @@ class WatneyStarDetectorTest : FitsStringSpec() { val detector = WatneyStarDetector(computeHFD = true) "detect stars" { - var image = Image.open(NGC3344_COLOR_32) + var image = Image.open(NGC3344_COLOR_32_FITS) var stars = detector.detect(image.transform(Mean)) stars shouldHaveSize 1 image.transform(ImageStarsDraw(stars)).save("color-detected-stars-1") diff --git a/nebulosa-wcs/src/main/kotlin/nebulosa/wcs/WCS.kt b/nebulosa-wcs/src/main/kotlin/nebulosa/wcs/WCS.kt index fc69d0516..542d56297 100644 --- a/nebulosa-wcs/src/main/kotlin/nebulosa/wcs/WCS.kt +++ b/nebulosa-wcs/src/main/kotlin/nebulosa/wcs/WCS.kt @@ -4,13 +4,13 @@ import com.sun.jna.Pointer import com.sun.jna.ptr.DoubleByReference import com.sun.jna.ptr.IntByReference import com.sun.jna.ptr.PointerByReference -import nebulosa.fits.Header +import nebulosa.image.format.ReadableHeader import nebulosa.math.Angle import nebulosa.math.deg import nebulosa.math.toDegrees import java.io.Closeable -class WCS(header: Header) : Closeable { +class WCS(header: ReadableHeader) : Closeable { private val wcs: Pointer @@ -23,7 +23,7 @@ class WCS(header: Header) : Closeable { val card = headerIter.next() if (isKeywordValid(card.key)) { - headerText.append(card.format()) + headerText.append(card.formattedValue()) keyCount++ } } diff --git a/nebulosa-wcs/src/main/kotlin/nebulosa/wcs/WCSUtil.kt b/nebulosa-wcs/src/main/kotlin/nebulosa/wcs/WCSUtil.kt index beb5905e8..0aa01de3f 100644 --- a/nebulosa-wcs/src/main/kotlin/nebulosa/wcs/WCSUtil.kt +++ b/nebulosa-wcs/src/main/kotlin/nebulosa/wcs/WCSUtil.kt @@ -1,7 +1,7 @@ package nebulosa.wcs -import nebulosa.fits.Header -import nebulosa.fits.Standard +import nebulosa.fits.FitsKeywordDictionary +import nebulosa.image.format.ReadableHeader import nebulosa.math.Angle import nebulosa.math.cos import nebulosa.math.deg @@ -9,23 +9,23 @@ import nebulosa.math.sin import kotlin.math.abs import kotlin.math.sign -val Header.hasCd +val ReadableHeader.hasCd get() = "CD1_1" in this || - "CDELT1" in this && "CROTA2" in this || - "CDELT1" in this && "PC1_1" in this + "CDELT1" in this && "CROTA2" in this || + "CDELT1" in this && "PC1_1" in this -fun Header.computeCdMatrix(): DoubleArray { +fun ReadableHeader.computeCdMatrix(): DoubleArray { return if (hasCd) { doubleArrayOf(cd(1, 1), cd(1, 2), cd(2, 1), cd(2, 2)) } else { - val a = getDouble(Standard.CDELT1, 0.0) - val b = getDouble(Standard.CDELT2, 0.0) - val c = getDouble(Standard.CROTA2, 0.0).deg + val a = getDouble(FitsKeywordDictionary.CDELT1, 0.0) + val b = getDouble(FitsKeywordDictionary.CDELT2, 0.0) + val c = getDouble(FitsKeywordDictionary.CROTA2, 0.0).deg computeCdFromCdelt(a, b, c) } } -fun Header.cd(i: Int, j: Int): Double { +fun ReadableHeader.cd(i: Int, j: Int): Double { return if ("CD1_1" in this) { getDouble("CD${i}_$j", 0.0) } else if ("CROTA2" in this) { diff --git a/nebulosa-wcs/src/test/kotlin/LibWCSTest.kt b/nebulosa-wcs/src/test/kotlin/LibWCSTest.kt index ef6b7db4e..28fdd9383 100644 --- a/nebulosa-wcs/src/test/kotlin/LibWCSTest.kt +++ b/nebulosa-wcs/src/test/kotlin/LibWCSTest.kt @@ -2,8 +2,8 @@ import io.kotest.core.annotation.EnabledIf import io.kotest.core.spec.style.StringSpec import io.kotest.matchers.doubles.plusOrMinus import io.kotest.matchers.shouldBe -import nebulosa.fits.Header import nebulosa.fits.fits +import nebulosa.image.format.ReadableHeader import nebulosa.math.formatHMS import nebulosa.math.formatSignedDMS import nebulosa.test.NonGitHubOnlyCondition @@ -52,7 +52,7 @@ class LibWCSTest : StringSpec() { } } - private fun readHeaderFromFits(name: String): Header { + private fun readHeaderFromFits(name: String): ReadableHeader { return "src/test/resources/$name.fits".fits().use { it.first!!.header } } diff --git a/nebulosa-xisf/build.gradle.kts b/nebulosa-xisf/build.gradle.kts new file mode 100644 index 000000000..300c43409 --- /dev/null +++ b/nebulosa-xisf/build.gradle.kts @@ -0,0 +1,20 @@ +plugins { + kotlin("jvm") + id("maven-publish") +} + +dependencies { + api(project(":nebulosa-image-format")) + api(project(":nebulosa-fits")) + api(project(":nebulosa-xml")) + implementation(project(":nebulosa-log")) + testImplementation(project(":nebulosa-test")) +} + +publishing { + publications { + create("pluginMaven") { + from(components["java"]) + } + } +} diff --git a/nebulosa-xisf/src/main/kotlin/nebulosa/xisf/CompressionByteShuffler.kt b/nebulosa-xisf/src/main/kotlin/nebulosa/xisf/CompressionByteShuffler.kt new file mode 100644 index 000000000..d0bc53e7b --- /dev/null +++ b/nebulosa-xisf/src/main/kotlin/nebulosa/xisf/CompressionByteShuffler.kt @@ -0,0 +1,56 @@ +package nebulosa.xisf + +/** + * For data blocks structured as contiguous sequences of 16-bit or larger integer + * or floating point numbers, a reversible byte shuffling routine can greatly improve + * compression ratios by increasing data locality, i.e. by redistributing the + * sequence such that similar byte values tend to be placed close together. + */ +object CompressionByteShuffler { + + fun shuffle(input: ByteArray, output: ByteArray, itemSize: Int) { + val size = input.size + val numberOfItems = size / itemSize + val copyLength = size % itemSize + + var s = 0 + + for (j in 0 until itemSize) { + var u = j + + repeat(numberOfItems) { + output[s++] = input[u] + u += itemSize + } + + if (copyLength > 0) { + val destinationOffset = s + val startIndex = numberOfItems * itemSize + input.copyInto(output, destinationOffset, startIndex, startIndex + copyLength) + } + } + } + + fun unshuffle(input: ByteArray, output: ByteArray, itemSize: Int) { + val size = input.size + val numberOfItems = size / itemSize + val copyLength = size % itemSize + + var s = 0 + + for (j in 0 until itemSize) { + var u = j + + repeat(numberOfItems) { + output[u] = input[s++] + u += itemSize + } + + if (copyLength > 0) { + val destinationOffset = numberOfItems * itemSize + val startIndex = s + input.copyInto(output, destinationOffset, startIndex, startIndex + copyLength) + } + } + } +} diff --git a/nebulosa-xisf/src/main/kotlin/nebulosa/xisf/XisfFormat.kt b/nebulosa-xisf/src/main/kotlin/nebulosa/xisf/XisfFormat.kt new file mode 100644 index 000000000..6955d73d4 --- /dev/null +++ b/nebulosa-xisf/src/main/kotlin/nebulosa/xisf/XisfFormat.kt @@ -0,0 +1,49 @@ +package nebulosa.xisf + +import nebulosa.image.format.Hdu +import nebulosa.image.format.ImageFormat +import nebulosa.image.format.ImageHdu +import nebulosa.io.SeekableSource +import okio.Buffer +import okio.Sink + +/** + * Extensible Image Serialization Format (XISF) is the native file format of PixInsight. + * It is a free, open format for storage, management and interchange of digital images + * and associated data. + * + * @see XISF Version 1.0 Specification + */ +data object XisfFormat : ImageFormat { + + override fun read(source: SeekableSource): List { + val buffer = Buffer() + + source.read(buffer, 8) // XISF0100 + buffer.readString(Charsets.US_ASCII) + + // Header length (4) + reserved (4) + source.read(buffer, 4 + 4) + val headerLength = buffer.readIntLe().toLong() + buffer.skip(4) // reserved + + // XISF Header. + source.read(buffer, headerLength) + val stream = XisfHeaderInputStream(buffer.inputStream()) + val hdus = ArrayList(2) + + while (true) { + val header = stream.read() ?: break + + when (header) { + is XisfMonolithicFileHeader.Image -> hdus.add(XisfMonolithicFileHeaderImageHdu(header, source)) + } + } + + return hdus + } + + override fun write(sink: Sink, hdus: Iterable>) { + TODO("Not implemented yet") + } +} diff --git a/nebulosa-xisf/src/main/kotlin/nebulosa/xisf/XisfHeader.kt b/nebulosa-xisf/src/main/kotlin/nebulosa/xisf/XisfHeader.kt new file mode 100644 index 000000000..0b4dbc26c --- /dev/null +++ b/nebulosa-xisf/src/main/kotlin/nebulosa/xisf/XisfHeader.kt @@ -0,0 +1,46 @@ +package nebulosa.xisf + +import nebulosa.image.format.AbstractHeader +import nebulosa.image.format.Header +import nebulosa.image.format.HeaderCard +import nebulosa.io.SeekableSource +import okio.Sink + +open class XisfHeader : AbstractHeader { + + constructor() : super() + + constructor(cards: Collection) : super(cards) + + override fun readOnly(): Header { + TODO("Not yet implemented") + } + + override fun clone(): Header { + TODO("Not yet implemented") + } + + override fun write(sink: Sink) { + TODO("Not yet implemented") + } + + override fun add(key: String, value: Boolean, comment: String) { + TODO("Not yet implemented") + } + + override fun add(key: String, value: Int, comment: String) { + TODO("Not yet implemented") + } + + override fun add(key: String, value: Double, comment: String) { + TODO("Not yet implemented") + } + + override fun add(key: String, value: String, comment: String) { + TODO("Not yet implemented") + } + + override fun read(source: SeekableSource) { + TODO("Not yet implemented") + } +} diff --git a/nebulosa-xisf/src/main/kotlin/nebulosa/xisf/XisfHeaderInputStream.kt b/nebulosa-xisf/src/main/kotlin/nebulosa/xisf/XisfHeaderInputStream.kt new file mode 100644 index 000000000..38955627f --- /dev/null +++ b/nebulosa-xisf/src/main/kotlin/nebulosa/xisf/XisfHeaderInputStream.kt @@ -0,0 +1,103 @@ +package nebulosa.xisf + +import com.fasterxml.aalto.stax.InputFactoryImpl +import nebulosa.fits.FitsHeaderCard +import nebulosa.fits.FitsHeaderCardType +import nebulosa.io.ByteOrder +import nebulosa.xisf.XisfMonolithicFileHeader.* +import nebulosa.xml.attribute +import java.io.Closeable +import java.io.InputStream +import javax.xml.stream.XMLStreamConstants + +class XisfHeaderInputStream(source: InputStream) : Closeable { + + private val reader = XML_INPUT_FACTORY.createXMLStreamReader(source) + + fun read(): XisfMonolithicFileHeader? { + while (reader.hasNext()) { + when (reader.next()) { + XMLStreamConstants.START_ELEMENT -> { + return parseStartElement() ?: continue + } + } + } + + return null + } + + private fun parseStartElement(): XisfMonolithicFileHeader? { + return when (reader.localName) { + "Image" -> parseImage() + else -> null + } + } + + private fun parseImage(): Image { + val (width, height, numberOfChannels) = reader.attribute("geometry")!!.split(":") + + val location = reader.attribute("location")!! + check(location.startsWith("attachment")) + val (_, position, size) = location.split(":") + + val sampleFormat = SampleFormat.valueOf(reader.attribute("sampleFormat")!!.uppercase()) + val colorSpace = reader.attribute("colorSpace")?.uppercase()?.let(ColorSpace::valueOf) + val pixelStorage = reader.attribute("pixelStorage")?.uppercase()?.let(PixelStorageModel::valueOf) + val byteOrder = reader.attribute("byteOrder")?.uppercase()?.let(ByteOrder::valueOf) + val compression = reader.attribute("compression")?.let { CompressionFormat.parse(it) } + val (keywords, thumbnail) = parseKeywords() + // TODO: bounds (Representable Range) + // TODO: Convert metadata into FITS keywords? + + return Image( + width.toInt(), height.toInt(), numberOfChannels.toInt(), + position.toLong(), size.toLong(), + sampleFormat, colorSpace ?: ColorSpace.GRAY, + pixelStorage ?: PixelStorageModel.PLANAR, + byteOrder ?: ByteOrder.LITTLE, + compression, keywords, thumbnail, + ) + } + + private fun parseKeywords(): Pair, Image?> { + val name = reader.localName + + val keywords = ArrayList() + var thumbnail: Image? = null + + while (reader.hasNext()) { + val type = reader.next() + + if (type == XMLStreamConstants.END_ELEMENT && reader.localName == name) { + break + } else if (type == XMLStreamConstants.START_ELEMENT) { + when (reader.localName) { + "FITSKeyword" -> keywords.add(parseFITSKeyword()) + "Thumbnail" -> thumbnail = parseImage() + } + } + } + + return keywords to thumbnail + } + + private fun parseFITSKeyword(): FitsHeaderCard { + val name = reader.attribute("name") ?: "" + val value = reader.attribute("value")?.trim() ?: "" + val trimmedValue = value.trim('\'') + val comment = reader.attribute("comment") ?: "" + val isStringType = value.startsWith('\'') && value.endsWith('\'') + // TODO: Identify other types + val type = if (isStringType) FitsHeaderCardType.TEXT else FitsHeaderCardType.NONE + return FitsHeaderCard(name, trimmedValue, comment, type) + } + + override fun close() { + reader.close() + } + + companion object { + + @JvmStatic private val XML_INPUT_FACTORY = InputFactoryImpl() + } +} diff --git a/nebulosa-xisf/src/main/kotlin/nebulosa/xisf/XisfHelper.kt b/nebulosa-xisf/src/main/kotlin/nebulosa/xisf/XisfHelper.kt new file mode 100644 index 000000000..d48ad55b1 --- /dev/null +++ b/nebulosa-xisf/src/main/kotlin/nebulosa/xisf/XisfHelper.kt @@ -0,0 +1,12 @@ +@file:Suppress("NOTHING_TO_INLINE") + +package nebulosa.xisf + +import java.io.File +import java.nio.file.Path + +inline fun String.xisf() = XisfPath(this).also(XisfPath::read) + +inline fun Path.xisf() = XisfPath(this).also(XisfPath::read) + +inline fun File.xisf() = XisfPath(this).also(XisfPath::read) diff --git a/nebulosa-xisf/src/main/kotlin/nebulosa/xisf/XisfMonolithicFileHeader.kt b/nebulosa-xisf/src/main/kotlin/nebulosa/xisf/XisfMonolithicFileHeader.kt new file mode 100644 index 000000000..fd70065d6 --- /dev/null +++ b/nebulosa-xisf/src/main/kotlin/nebulosa/xisf/XisfMonolithicFileHeader.kt @@ -0,0 +1,74 @@ +package nebulosa.xisf + +import nebulosa.fits.FitsHeaderCard +import nebulosa.io.ByteOrder + +sealed interface XisfMonolithicFileHeader { + + enum class SampleFormat(val byteLength: Long) { + UINT8(1L), + UINT16(2L), + UINT32(4L), + UINT64(8L), + FLOAT32(4L), + FLOAT64(8L), + } + + enum class ColorSpace { + GRAY, + RGB, + CIELAB, + } + + enum class PixelStorageModel { + PLANAR, + NORMAL, + } + + enum class CompressionType { + ZLIB, + LZ4, + LZ4_HC, + ZSTD, + } + + data class CompressionFormat( + @JvmField val type: CompressionType, + @JvmField val shuffled: Boolean, + @JvmField val uncompressedSize: Long, + @JvmField val itemSize: Int = 0, + ) { + + companion object { + + @JvmStatic + fun parse(text: String): CompressionFormat { + val parts = text.split(":") + + val type = when (parts[0]) { + "zlib", "zlib+sh" -> CompressionType.ZLIB + "lz4", "lz4+sh" -> CompressionType.LZ4 + "lz4hc", "lz4hc+sh" -> CompressionType.LZ4_HC + "zstd", "zstd+sh" -> CompressionType.ZSTD + else -> throw IllegalArgumentException("Invalid compression type: ${parts[0]}") + } + + val uncompressedSize = parts[1].toLong() + val shuffled = parts[0].endsWith("+sh") + val itemSize = if (shuffled && parts.size >= 3) parts[2].toInt() else 0 + + return CompressionFormat(type, shuffled, uncompressedSize, itemSize) + } + } + } + + data class Image( + @JvmField val width: Int, @JvmField val height: Int, @JvmField val numberOfChannels: Int, + @JvmField val position: Long, @JvmField val size: Long, + @JvmField val sampleFormat: SampleFormat, @JvmField val colorSpace: ColorSpace, + @JvmField val pixelStorage: PixelStorageModel, @JvmField val byteOrder: ByteOrder, + @JvmField val compressionFormat: CompressionFormat? = null, + @JvmField val keywords: List = emptyList(), + @JvmField val thumbnail: Image? = null, + ) : XisfMonolithicFileHeader +} diff --git a/nebulosa-xisf/src/main/kotlin/nebulosa/xisf/XisfMonolithicFileHeaderImageData.kt b/nebulosa-xisf/src/main/kotlin/nebulosa/xisf/XisfMonolithicFileHeaderImageData.kt new file mode 100644 index 000000000..f3aa1e649 --- /dev/null +++ b/nebulosa-xisf/src/main/kotlin/nebulosa/xisf/XisfMonolithicFileHeaderImageData.kt @@ -0,0 +1,173 @@ +package nebulosa.xisf + +import nebulosa.image.format.ImageChannel +import nebulosa.image.format.ImageData +import nebulosa.io.* +import nebulosa.xisf.XisfMonolithicFileHeader.* +import okio.Buffer +import okio.InflaterSource +import java.util.zip.Inflater +import kotlin.math.min + +@Suppress("NOTHING_TO_INLINE") +internal data class XisfMonolithicFileHeaderImageData( + private val image: Image, + private val source: SeekableSource, +) : ImageData { + + override val width + get() = image.width + + override val height + get() = image.height + + override val numberOfChannels + get() = image.numberOfChannels + + private val numberOfPixels = width * height + + init { + val uncompressedSize = image.compressionFormat?.uncompressedSize ?: image.size + val expectedSize = numberOfChannels * numberOfPixels * image.sampleFormat.byteLength + check(uncompressedSize == expectedSize) { "invalid size. $uncompressedSize != $expectedSize" } + } + + override val red by lazy { readImage(ImageChannel.RED) } + + override val green by lazy { readImage(ImageChannel.GREEN) } + + override val blue by lazy { readImage(ImageChannel.BLUE) } + + private fun readImage(channel: ImageChannel): FloatArray { + return if (numberOfChannels == 1) { + if (channel.index == 0) readGray() else red + } else { + when (channel) { + ImageChannel.GREEN -> readGreen() + ImageChannel.BLUE -> readBlue() + else -> readRed() + } + } + } + + private inline fun readGray(): FloatArray { + return readChannel(ImageChannel.GRAY) + } + + private inline fun readRed(): FloatArray { + return readChannel(ImageChannel.RED) + } + + private inline fun readGreen(): FloatArray { + return readChannel(ImageChannel.GREEN) + } + + private inline fun readBlue(): FloatArray { + return readChannel(ImageChannel.BLUE) + } + + private fun readChannel(channel: ImageChannel): FloatArray { + return if (image.pixelStorage == PixelStorageModel.NORMAL) readNormal(channel) + else readPlanar(channel) + } + + /** + * In the planar storage model, each channel of an image shall be stored as + * a contiguous sequence of pixel samples (each channel is stored in a separate block). + */ + private fun readPlanar(channel: ImageChannel): FloatArray { + val startIndex = numberOfPixels * image.sampleFormat.byteLength * channel.index + + source.seek(image.position + startIndex) + + val data = FloatArray(numberOfPixels) + var remainingPixels = data.size + var pos = 0 + + var closeable: (() -> Unit)? = null + + val compressedSource = when (image.compressionFormat?.type) { + CompressionType.ZLIB -> InflaterSource(source, Inflater(false).also { closeable = it::end }) + CompressionType.LZ4 -> TODO("Not implemented yet") + CompressionType.LZ4_HC -> TODO("Not implemented yet") + CompressionType.ZSTD -> TODO("Not implemented yet") + null -> source + } + + try { + Buffer().use { buffer -> + while (remainingPixels > 0) { + var n = min(PIXEL_COUNT, remainingPixels) + val byteCount = n * image.sampleFormat.byteLength + + val size = compressedSource.read(buffer, byteCount) + + if (size == 0L) break + + // require(size % image.sampleFormat.byteLength == 0L) + n = (size / image.sampleFormat.byteLength).toInt() + + repeat(n) { + data[pos++] = buffer.readPixel(image.sampleFormat, image.byteOrder) + } + + remainingPixels -= n + } + } + } finally { + closeable?.invoke() + } + + return data + } + + /** + * In the normal storage model, all pixel samples of an image shall be stored as + * a contiguous sequence (all pixel samples are stored in a single block). + */ + private fun readNormal(channel: ImageChannel): FloatArray { + source.seek(image.position) + + val pixelBlockSizeInBytes = numberOfChannels * image.sampleFormat.byteLength + val bytesToSkipBefore = channel.index * image.sampleFormat.byteLength + val bytesToSkipAfter = pixelBlockSizeInBytes - bytesToSkipBefore - image.sampleFormat.byteLength + val data = FloatArray(numberOfPixels) + var remainingPixels = data.size + var pos = 0 + + Buffer().use { buffer -> + while (remainingPixels > 0) { + val n = min(PIXEL_COUNT, remainingPixels) + val byteCount = n * pixelBlockSizeInBytes + + check(source.read(buffer, byteCount) == byteCount) + + repeat(n) { + if (bytesToSkipBefore > 0) buffer.skip(bytesToSkipBefore) + data[pos++] = buffer.readPixel(image.sampleFormat, image.byteOrder) + if (bytesToSkipAfter > 0) buffer.skip(bytesToSkipAfter) + } + + remainingPixels -= n + } + } + + return data + } + + private fun Buffer.readPixel(format: SampleFormat, byteOrder: ByteOrder): Float { + return when (format) { + SampleFormat.UINT8 -> (buffer.readByte().toInt() and 0xFF) / 255f + SampleFormat.UINT16 -> (buffer.readShort(byteOrder).toInt() and 0xFFFF) / 65535f + SampleFormat.UINT32 -> ((buffer.readInt(byteOrder).toLong() and 0xFFFFFFFF) / 4294967295.0).toFloat() + SampleFormat.UINT64 -> TODO("Unsupported UInt64 sample format") + SampleFormat.FLOAT32 -> buffer.readFloat(byteOrder) + SampleFormat.FLOAT64 -> buffer.readDouble(byteOrder).toFloat() + } + } + + companion object { + + const val PIXEL_COUNT = 64 + } +} diff --git a/nebulosa-xisf/src/main/kotlin/nebulosa/xisf/XisfMonolithicFileHeaderImageHdu.kt b/nebulosa-xisf/src/main/kotlin/nebulosa/xisf/XisfMonolithicFileHeaderImageHdu.kt new file mode 100644 index 000000000..a3e802402 --- /dev/null +++ b/nebulosa-xisf/src/main/kotlin/nebulosa/xisf/XisfMonolithicFileHeaderImageHdu.kt @@ -0,0 +1,23 @@ +package nebulosa.xisf + +import nebulosa.image.format.ImageHdu +import nebulosa.io.SeekableSource + +internal data class XisfMonolithicFileHeaderImageHdu( + private val image: XisfMonolithicFileHeader.Image, + private val source: SeekableSource, +) : ImageHdu { + + override val width + get() = image.width + + override val height + get() = image.height + + override val numberOfChannels + get() = image.numberOfChannels + + override val header = XisfHeader(image.keywords) + + override val data = XisfMonolithicFileHeaderImageData(image, source) +} diff --git a/nebulosa-xisf/src/main/kotlin/nebulosa/xisf/XisfPath.kt b/nebulosa-xisf/src/main/kotlin/nebulosa/xisf/XisfPath.kt new file mode 100644 index 000000000..e34789821 --- /dev/null +++ b/nebulosa-xisf/src/main/kotlin/nebulosa/xisf/XisfPath.kt @@ -0,0 +1,25 @@ +package nebulosa.xisf + +import nebulosa.io.seekableSink +import nebulosa.io.seekableSource +import java.io.Closeable +import java.io.File +import java.nio.file.Path + +class XisfPath(val path: Path) : Closeable { + + private val source = path.seekableSource() + private val sink = path.seekableSink() + + constructor(file: File) : this(file.toPath()) + + constructor(path: String) : this(Path.of(path)) + + fun read() { + } + + override fun close() { + source.close() + sink.close() + } +} diff --git a/nebulosa-xisf/src/test/kotlin/CompressionByteShufflerTest.kt b/nebulosa-xisf/src/test/kotlin/CompressionByteShufflerTest.kt new file mode 100644 index 000000000..66556a1ad --- /dev/null +++ b/nebulosa-xisf/src/test/kotlin/CompressionByteShufflerTest.kt @@ -0,0 +1,30 @@ +import io.kotest.core.spec.style.StringSpec +import io.kotest.matchers.ints.shouldBeExactly +import nebulosa.xisf.CompressionByteShuffler +import kotlin.random.Random + +class CompressionByteShufflerTest : StringSpec() { + + init { + "shuffle & unshuffle" { + val original = ByteArray(256) { (it / 32).toByte() } + val buffer = ByteArray(256) + val unshuffled = ByteArray(256) + + CompressionByteShuffler.shuffle(original, buffer, 8) + CompressionByteShuffler.unshuffle(buffer, unshuffled, 8) + + repeat(original.size) { unshuffled[it].toInt() shouldBeExactly original[it].toInt() } + } + "random shuffle & unshuffle" { + val original = Random.nextBytes(256) + val buffer = ByteArray(256) + val unshuffled = ByteArray(256) + + CompressionByteShuffler.shuffle(original, buffer, 8) + CompressionByteShuffler.unshuffle(buffer, unshuffled, 8) + + repeat(original.size) { unshuffled[it].toInt() shouldBeExactly original[it].toInt() } + } + } +} diff --git a/nebulosa-xisf/src/test/kotlin/XisfFormatTest.kt b/nebulosa-xisf/src/test/kotlin/XisfFormatTest.kt new file mode 100644 index 000000000..b7ade6e09 --- /dev/null +++ b/nebulosa-xisf/src/test/kotlin/XisfFormatTest.kt @@ -0,0 +1,255 @@ +import io.kotest.matchers.collections.shouldHaveSize +import io.kotest.matchers.ints.shouldBeExactly +import io.kotest.matchers.shouldBe +import io.kotest.matchers.types.shouldBeSameInstanceAs +import io.kotest.matchers.types.shouldNotBeSameInstanceAs +import nebulosa.image.format.ImageHdu +import nebulosa.io.seekableSource +import nebulosa.test.FitsStringSpec +import nebulosa.xisf.XisfFormat +import java.awt.image.BufferedImage +import java.awt.image.DataBufferByte +import java.awt.image.DataBufferInt + +class XisfFormatTest : FitsStringSpec() { + + init { + "mono:planar:8" { + val source = closeAfterEach(M82_MONO_8_XISF.seekableSource()) + val hdus = XisfFormat.read(source) + + hdus shouldHaveSize 1 + + with(hdus[0]) { + width shouldBeExactly 512 + height shouldBeExactly 512 + numberOfChannels shouldBeExactly 1 + header shouldHaveSize 22 + data.red.size shouldBeExactly 512 * 512 + data.green shouldBeSameInstanceAs data.red + data.blue shouldBeSameInstanceAs data.green + + val image = makeImage() + image.save("xisf-mono-planar-8").second shouldBe "0dca7efedef5b3525f8037f401518b0b" + } + } + "mono:planar:16" { + val source = closeAfterEach(M82_MONO_16_XISF.seekableSource()) + val hdus = XisfFormat.read(source) + + hdus shouldHaveSize 1 + + with(hdus[0]) { + width shouldBeExactly 512 + height shouldBeExactly 512 + numberOfChannels shouldBeExactly 1 + header shouldHaveSize 22 + data.red.size shouldBeExactly 512 * 512 + data.green shouldBeSameInstanceAs data.red + data.blue shouldBeSameInstanceAs data.green + + val image = makeImage() + image.save("xisf-mono-planar-16").second shouldBe "0dca7efedef5b3525f8037f401518b0b" + } + } + "mono:planar:32" { + val source = closeAfterEach(M82_MONO_32_XISF.seekableSource()) + val hdus = XisfFormat.read(source) + + hdus shouldHaveSize 1 + + with(hdus[0]) { + width shouldBeExactly 512 + height shouldBeExactly 512 + numberOfChannels shouldBeExactly 1 + header shouldHaveSize 22 + data.red.size shouldBeExactly 512 * 512 + data.green shouldBeSameInstanceAs data.red + data.blue shouldBeSameInstanceAs data.green + + val image = makeImage() + image.save("xisf-mono-planar-32").second shouldBe "0dca7efedef5b3525f8037f401518b0b" + } + } + "mono:planar:F32" { + val source = closeAfterEach(M82_MONO_F32_XISF.seekableSource()) + val hdus = XisfFormat.read(source) + + hdus shouldHaveSize 1 + + with(hdus[0]) { + width shouldBeExactly 512 + height shouldBeExactly 512 + numberOfChannels shouldBeExactly 1 + header shouldHaveSize 22 + data.red.size shouldBeExactly 512 * 512 + data.green shouldBeSameInstanceAs data.red + data.blue shouldBeSameInstanceAs data.green + + val image = makeImage() + image.save("xisf-mono-planar-F32").second shouldBe "0dca7efedef5b3525f8037f401518b0b" + } + } + "mono:planar:F64" { + val source = closeAfterEach(M82_MONO_F64_XISF.seekableSource()) + val hdus = XisfFormat.read(source) + + hdus shouldHaveSize 1 + + with(hdus[0]) { + width shouldBeExactly 512 + height shouldBeExactly 512 + numberOfChannels shouldBeExactly 1 + header shouldHaveSize 22 + data.red.size shouldBeExactly 512 * 512 + data.green shouldBeSameInstanceAs data.red + data.blue shouldBeSameInstanceAs data.green + + val image = makeImage() + image.save("xisf-mono-planar-F64").second shouldBe "0dca7efedef5b3525f8037f401518b0b" + } + } + "color:planar:8" { + val source = closeAfterEach(M82_COLOR_8_XISF.seekableSource()) + val hdus = XisfFormat.read(source) + + hdus shouldHaveSize 1 + + with(hdus[0]) { + width shouldBeExactly 512 + height shouldBeExactly 512 + numberOfChannels shouldBeExactly 3 + header shouldHaveSize 22 + data.red.size shouldBeExactly 512 * 512 + data.green shouldNotBeSameInstanceAs data.red + data.blue shouldNotBeSameInstanceAs data.green + + val image = makeImage() + image.save("xisf-color-planar-8").second shouldBe "89beed384ee9e97ce033ba447a377937" + } + } + "color:planar:16" { + val source = closeAfterEach(M82_COLOR_16_XISF.seekableSource()) + val hdus = XisfFormat.read(source) + + hdus shouldHaveSize 1 + + with(hdus[0]) { + width shouldBeExactly 512 + height shouldBeExactly 512 + numberOfChannels shouldBeExactly 3 + header shouldHaveSize 22 + data.red.size shouldBeExactly 512 * 512 + data.green shouldNotBeSameInstanceAs data.red + data.blue shouldNotBeSameInstanceAs data.green + + val image = makeImage() + image.save("xisf-color-planar-16").second shouldBe "89beed384ee9e97ce033ba447a377937" + } + } + "color:planar:32" { + val source = closeAfterEach(M82_COLOR_32_XISF.seekableSource()) + val hdus = XisfFormat.read(source) + + hdus shouldHaveSize 1 + + with(hdus[0]) { + width shouldBeExactly 512 + height shouldBeExactly 512 + numberOfChannels shouldBeExactly 3 + header shouldHaveSize 22 + data.red.size shouldBeExactly 512 * 512 + data.green shouldNotBeSameInstanceAs data.red + data.blue shouldNotBeSameInstanceAs data.green + + val image = makeImage() + image.save("xisf-color-planar-32").second shouldBe "89beed384ee9e97ce033ba447a377937" + } + } + "color:planar:F32" { + val source = closeAfterEach(M82_COLOR_F32_XISF.seekableSource()) + val hdus = XisfFormat.read(source) + + hdus shouldHaveSize 1 + + with(hdus[0]) { + width shouldBeExactly 512 + height shouldBeExactly 512 + numberOfChannels shouldBeExactly 3 + header shouldHaveSize 22 + data.red.size shouldBeExactly 512 * 512 + data.green shouldNotBeSameInstanceAs data.red + data.blue shouldNotBeSameInstanceAs data.green + + val image = makeImage() + image.save("xisf-color-planar-F32").second shouldBe "89beed384ee9e97ce033ba447a377937" + } + } + "color:planar:F64" { + val source = closeAfterEach(M82_COLOR_F64_XISF.seekableSource()) + val hdus = XisfFormat.read(source) + + hdus shouldHaveSize 1 + + with(hdus[0]) { + width shouldBeExactly 512 + height shouldBeExactly 512 + numberOfChannels shouldBeExactly 3 + header shouldHaveSize 22 + data.red.size shouldBeExactly 512 * 512 + data.green shouldNotBeSameInstanceAs data.red + data.blue shouldNotBeSameInstanceAs data.green + + val image = makeImage() + image.save("xisf-color-planar-F64").second shouldBe "89beed384ee9e97ce033ba447a377937" + } + } + "mono:planar:8:zlib" { + val source = closeAfterEach(M82_MONO_8_ZLIB_XISF.seekableSource()) + val hdus = XisfFormat.read(source) + + hdus shouldHaveSize 1 + + with(hdus[0]) { + width shouldBeExactly 512 + height shouldBeExactly 512 + numberOfChannels shouldBeExactly 1 + header shouldHaveSize 22 + data.red.size shouldBeExactly 512 * 512 + data.green shouldBeSameInstanceAs data.red + data.blue shouldBeSameInstanceAs data.green + + val image = makeImage() + image.save("xisf-mono-planar-8-zlib").second shouldBe "0dca7efedef5b3525f8037f401518b0b" + } + } + } + + companion object { + + @JvmStatic + private fun ImageHdu.makeImage(): BufferedImage { + val type = if (numberOfChannels == 1) BufferedImage.TYPE_BYTE_GRAY else BufferedImage.TYPE_INT_RGB + val image = BufferedImage(width, height, type) + + if (numberOfChannels == 1) { + val buffer = (image.raster.dataBuffer as DataBufferByte) + + repeat(width * height) { + buffer.data[it] = (data.red[it] * 255f).toInt().toByte() + } + } else { + val buffer = (image.raster.dataBuffer as DataBufferInt) + + repeat(width * height) { + val red = (data.red[it] * 255f).toInt() and 0xFF + val green = (data.green[it] * 255f).toInt() and 0xFF + val blue = (data.blue[it] * 255f).toInt() and 0xFF + buffer.data[it] = red or (green shl 8) or (blue shl 16) + } + } + + return image + } + } +} diff --git a/nebulosa-xisf/src/test/kotlin/XisfHeaderInputStreamTest.kt b/nebulosa-xisf/src/test/kotlin/XisfHeaderInputStreamTest.kt new file mode 100644 index 000000000..04ba2c042 --- /dev/null +++ b/nebulosa-xisf/src/test/kotlin/XisfHeaderInputStreamTest.kt @@ -0,0 +1,230 @@ +import io.kotest.matchers.collections.shouldHaveSize +import io.kotest.matchers.ints.shouldBeExactly +import io.kotest.matchers.nulls.shouldNotBeNull +import io.kotest.matchers.shouldBe +import io.kotest.matchers.types.shouldBeInstanceOf +import nebulosa.io.ByteOrder +import nebulosa.test.FitsStringSpec +import nebulosa.xisf.XisfHeaderInputStream +import nebulosa.xisf.XisfMonolithicFileHeader +import kotlin.io.path.inputStream + +class XisfHeaderInputStreamTest : FitsStringSpec() { + + init { + "read:8:gray" { + val stream = closeAfterEach(M82_MONO_8_XISF.inputStream().also { it.skip(16) }) + val headerStream = XisfHeaderInputStream(stream) + val image = headerStream.read().shouldNotBeNull().shouldBeInstanceOf() + + with(image) { + width shouldBeExactly 512 + height shouldBeExactly 512 + numberOfChannels shouldBeExactly 1 + sampleFormat shouldBe XisfMonolithicFileHeader.SampleFormat.UINT8 + colorSpace shouldBe XisfMonolithicFileHeader.ColorSpace.GRAY + byteOrder shouldBe ByteOrder.LITTLE + keywords shouldHaveSize 22 + } + } + "read:8:gray:zlib" { + val stream = closeAfterEach(M82_MONO_8_ZLIB_XISF.inputStream().also { it.skip(16) }) + val headerStream = XisfHeaderInputStream(stream) + val image = headerStream.read().shouldNotBeNull().shouldBeInstanceOf() + + with(image) { + width shouldBeExactly 512 + height shouldBeExactly 512 + numberOfChannels shouldBeExactly 1 + sampleFormat shouldBe XisfMonolithicFileHeader.SampleFormat.UINT8 + colorSpace shouldBe XisfMonolithicFileHeader.ColorSpace.GRAY + byteOrder shouldBe ByteOrder.LITTLE + compressionFormat.shouldNotBeNull().type shouldBe XisfMonolithicFileHeader.CompressionType.ZLIB + keywords shouldHaveSize 22 + } + } + "read:8:gray:lz4" { + val stream = closeAfterEach(M82_MONO_8_LZ4_XISF.inputStream().also { it.skip(16) }) + val headerStream = XisfHeaderInputStream(stream) + val image = headerStream.read().shouldNotBeNull().shouldBeInstanceOf() + + with(image) { + width shouldBeExactly 512 + height shouldBeExactly 512 + numberOfChannels shouldBeExactly 1 + sampleFormat shouldBe XisfMonolithicFileHeader.SampleFormat.UINT8 + colorSpace shouldBe XisfMonolithicFileHeader.ColorSpace.GRAY + byteOrder shouldBe ByteOrder.LITTLE + compressionFormat.shouldNotBeNull().type shouldBe XisfMonolithicFileHeader.CompressionType.LZ4 + keywords shouldHaveSize 22 + } + } + "read:8:gray:lz4-hc" { + val stream = closeAfterEach(M82_MONO_8_LZ4_HC_XISF.inputStream().also { it.skip(16) }) + val headerStream = XisfHeaderInputStream(stream) + val image = headerStream.read().shouldNotBeNull().shouldBeInstanceOf() + + with(image) { + width shouldBeExactly 512 + height shouldBeExactly 512 + numberOfChannels shouldBeExactly 1 + sampleFormat shouldBe XisfMonolithicFileHeader.SampleFormat.UINT8 + colorSpace shouldBe XisfMonolithicFileHeader.ColorSpace.GRAY + byteOrder shouldBe ByteOrder.LITTLE + compressionFormat.shouldNotBeNull().type shouldBe XisfMonolithicFileHeader.CompressionType.LZ4_HC + keywords shouldHaveSize 22 + } + } + "read:8:gray:zstd" { + val stream = closeAfterEach(M82_MONO_8_ZSTANDARD_XISF.inputStream().also { it.skip(16) }) + val headerStream = XisfHeaderInputStream(stream) + val image = headerStream.read().shouldNotBeNull().shouldBeInstanceOf() + + with(image) { + width shouldBeExactly 512 + height shouldBeExactly 512 + numberOfChannels shouldBeExactly 1 + sampleFormat shouldBe XisfMonolithicFileHeader.SampleFormat.UINT8 + colorSpace shouldBe XisfMonolithicFileHeader.ColorSpace.GRAY + byteOrder shouldBe ByteOrder.LITTLE + compressionFormat.shouldNotBeNull().type shouldBe XisfMonolithicFileHeader.CompressionType.ZSTD + keywords shouldHaveSize 22 + } + } + "read:16:gray" { + val stream = closeAfterEach(M82_MONO_16_XISF.inputStream().also { it.skip(16) }) + val headerStream = XisfHeaderInputStream(stream) + val image = headerStream.read().shouldNotBeNull().shouldBeInstanceOf() + + with(image) { + width shouldBeExactly 512 + height shouldBeExactly 512 + numberOfChannels shouldBeExactly 1 + sampleFormat shouldBe XisfMonolithicFileHeader.SampleFormat.UINT16 + colorSpace shouldBe XisfMonolithicFileHeader.ColorSpace.GRAY + byteOrder shouldBe ByteOrder.LITTLE + keywords shouldHaveSize 22 + } + } + "read:32:gray" { + val stream = closeAfterEach(M82_MONO_32_XISF.inputStream().also { it.skip(16) }) + val headerStream = XisfHeaderInputStream(stream) + val image = headerStream.read().shouldNotBeNull().shouldBeInstanceOf() + + with(image) { + width shouldBeExactly 512 + height shouldBeExactly 512 + numberOfChannels shouldBeExactly 1 + sampleFormat shouldBe XisfMonolithicFileHeader.SampleFormat.UINT32 + colorSpace shouldBe XisfMonolithicFileHeader.ColorSpace.GRAY + byteOrder shouldBe ByteOrder.LITTLE + keywords shouldHaveSize 22 + } + } + "read:F32:gray" { + val stream = closeAfterEach(M82_MONO_F32_XISF.inputStream().also { it.skip(16) }) + val headerStream = XisfHeaderInputStream(stream) + val image = headerStream.read().shouldNotBeNull().shouldBeInstanceOf() + + with(image) { + width shouldBeExactly 512 + height shouldBeExactly 512 + numberOfChannels shouldBeExactly 1 + sampleFormat shouldBe XisfMonolithicFileHeader.SampleFormat.FLOAT32 + colorSpace shouldBe XisfMonolithicFileHeader.ColorSpace.GRAY + byteOrder shouldBe ByteOrder.LITTLE + keywords shouldHaveSize 22 + } + } + "read:F64:gray" { + val stream = closeAfterEach(M82_MONO_F64_XISF.inputStream().also { it.skip(16) }) + val headerStream = XisfHeaderInputStream(stream) + val image = headerStream.read().shouldNotBeNull().shouldBeInstanceOf() + + with(image) { + width shouldBeExactly 512 + height shouldBeExactly 512 + numberOfChannels shouldBeExactly 1 + sampleFormat shouldBe XisfMonolithicFileHeader.SampleFormat.FLOAT64 + colorSpace shouldBe XisfMonolithicFileHeader.ColorSpace.GRAY + byteOrder shouldBe ByteOrder.LITTLE + keywords shouldHaveSize 22 + } + } + "read:8:rgb" { + val stream = closeAfterEach(M82_COLOR_8_XISF.inputStream().also { it.skip(16) }) + val headerStream = XisfHeaderInputStream(stream) + val image = headerStream.read().shouldNotBeNull().shouldBeInstanceOf() + + with(image) { + width shouldBeExactly 512 + height shouldBeExactly 512 + numberOfChannels shouldBeExactly 3 + sampleFormat shouldBe XisfMonolithicFileHeader.SampleFormat.UINT8 + colorSpace shouldBe XisfMonolithicFileHeader.ColorSpace.RGB + byteOrder shouldBe ByteOrder.LITTLE + keywords shouldHaveSize 22 + } + } + "read:16:rgb" { + val stream = closeAfterEach(M82_COLOR_16_XISF.inputStream().also { it.skip(16) }) + val headerStream = XisfHeaderInputStream(stream) + val image = headerStream.read().shouldNotBeNull().shouldBeInstanceOf() + + with(image) { + width shouldBeExactly 512 + height shouldBeExactly 512 + numberOfChannels shouldBeExactly 3 + sampleFormat shouldBe XisfMonolithicFileHeader.SampleFormat.UINT16 + colorSpace shouldBe XisfMonolithicFileHeader.ColorSpace.RGB + byteOrder shouldBe ByteOrder.LITTLE + keywords shouldHaveSize 22 + } + } + "read:32:rgb" { + val stream = closeAfterEach(M82_COLOR_32_XISF.inputStream().also { it.skip(16) }) + val headerStream = XisfHeaderInputStream(stream) + val image = headerStream.read().shouldNotBeNull().shouldBeInstanceOf() + + with(image) { + width shouldBeExactly 512 + height shouldBeExactly 512 + numberOfChannels shouldBeExactly 3 + sampleFormat shouldBe XisfMonolithicFileHeader.SampleFormat.UINT32 + colorSpace shouldBe XisfMonolithicFileHeader.ColorSpace.RGB + byteOrder shouldBe ByteOrder.LITTLE + keywords shouldHaveSize 22 + } + } + "read:F32:rgb" { + val stream = closeAfterEach(M82_COLOR_F32_XISF.inputStream().also { it.skip(16) }) + val headerStream = XisfHeaderInputStream(stream) + val image = headerStream.read().shouldNotBeNull().shouldBeInstanceOf() + + with(image) { + width shouldBeExactly 512 + height shouldBeExactly 512 + numberOfChannels shouldBeExactly 3 + sampleFormat shouldBe XisfMonolithicFileHeader.SampleFormat.FLOAT32 + colorSpace shouldBe XisfMonolithicFileHeader.ColorSpace.RGB + byteOrder shouldBe ByteOrder.LITTLE + keywords shouldHaveSize 22 + } + } + "read:F64:rgb" { + val stream = closeAfterEach(M82_COLOR_F64_XISF.inputStream().also { it.skip(16) }) + val headerStream = XisfHeaderInputStream(stream) + val image = headerStream.read().shouldNotBeNull().shouldBeInstanceOf() + + with(image) { + width shouldBeExactly 512 + height shouldBeExactly 512 + numberOfChannels shouldBeExactly 3 + sampleFormat shouldBe XisfMonolithicFileHeader.SampleFormat.FLOAT64 + colorSpace shouldBe XisfMonolithicFileHeader.ColorSpace.RGB + byteOrder shouldBe ByteOrder.LITTLE + keywords shouldHaveSize 22 + } + } + } +} diff --git a/nebulosa-xml/build.gradle.kts b/nebulosa-xml/build.gradle.kts new file mode 100644 index 000000000..8d82b0108 --- /dev/null +++ b/nebulosa-xml/build.gradle.kts @@ -0,0 +1,17 @@ +plugins { + kotlin("jvm") + id("maven-publish") +} + +dependencies { + api(libs.xml) + testImplementation(project(":nebulosa-test")) +} + +publishing { + publications { + create("pluginMaven") { + from(components["java"]) + } + } +} diff --git a/nebulosa-xml/src/main/kotlin/nebulosa/xml/XmlHelper.kt b/nebulosa-xml/src/main/kotlin/nebulosa/xml/XmlHelper.kt new file mode 100644 index 000000000..a3e9eb174 --- /dev/null +++ b/nebulosa-xml/src/main/kotlin/nebulosa/xml/XmlHelper.kt @@ -0,0 +1,13 @@ +package nebulosa.xml + +import javax.xml.stream.XMLStreamReader + +fun XMLStreamReader.attribute(name: String): String? { + for (i in 0 until attributeCount) { + if (getAttributeLocalName(i) == name) { + return getAttributeValue(i) + } + } + + return null +} diff --git a/settings.gradle.kts b/settings.gradle.kts index 0b00ef413..fab773656 100644 --- a/settings.gradle.kts +++ b/settings.gradle.kts @@ -62,7 +62,8 @@ include(":nebulosa-guiding-internal") include(":nebulosa-guiding-phd2") include(":nebulosa-hips2fits") include(":nebulosa-horizons") -include(":nebulosa-imaging") +include(":nebulosa-image") +include(":nebulosa-image-format") include(":nebulosa-indi-client") include(":nebulosa-indi-device") include(":nebulosa-indi-protocol") @@ -89,3 +90,5 @@ include(":nebulosa-time") include(":nebulosa-vizier") include(":nebulosa-watney") include(":nebulosa-wcs") +include(":nebulosa-xisf") +include(":nebulosa-xml") From f9e9a5c03842f7708d0e053ecde1a46b96bf10fa Mon Sep 17 00:00:00 2001 From: tiagohm Date: Mon, 25 Mar 2024 23:17:44 -0300 Subject: [PATCH 02/15] [api]: Implement XISF read/write --- .../calibration/CalibrationFrameService.kt | 7 +- .../api/cameras/CameraExposureStep.kt | 2 +- .../alpaca/indi/device/cameras/ASCOMCamera.kt | 27 ++- .../nova/NovaAstrometryNetService.kt | 4 +- .../src/main/kotlin/nebulosa/fits/Bitpix.kt | 5 +- .../src/main/kotlin/nebulosa/fits/Fits.kt | 27 +-- .../main/kotlin/nebulosa/fits/FitsFormat.kt | 165 ++++++++++++++ .../main/kotlin/nebulosa/fits/FitsHeader.kt | 64 +----- .../kotlin/nebulosa/fits/FitsHeaderCard.kt | 2 +- .../main/kotlin/nebulosa/fits/FitsHelper.kt | 6 + .../src/main/kotlin/nebulosa/fits/FitsIO.kt | 25 --- .../src/main/kotlin/nebulosa/fits/FitsPath.kt | 10 +- .../main/kotlin/nebulosa/fits/FitsReader.kt | 8 - .../main/kotlin/nebulosa/fits/FitsWriter.kt | 8 - .../kotlin/nebulosa/fits/FloatImageData.kt | 43 ---- .../src/main/kotlin/nebulosa/fits/Hdu.kt | 42 ---- .../main/kotlin/nebulosa/fits/ImageData.kt | 17 -- .../src/main/kotlin/nebulosa/fits/ImageHdu.kt | 65 ------ .../nebulosa/fits/SeekableSourceImageData.kt | 119 +++++++--- .../nebulosa/fits/SeekableSourceImageHdu.kt | 15 ++ nebulosa-fits/src/test/kotlin/FitsReadTest.kt | 43 ++-- .../src/test/kotlin/FitsWriteTest.kt | 5 +- .../src/test/kotlin/ImageDataTest.kt | 63 ------ .../src/test/kotlin/Hips2FitsServiceTest.kt | 1 + .../nebulosa/image/format/AbstractHeader.kt | 8 +- .../kotlin/nebulosa/image/format/BasicHdu.kt | 3 + .../nebulosa/image/format/BasicImageHdu.kt | 9 + .../nebulosa/image/format/FloatImageData.kt | 11 + .../main/kotlin/nebulosa/image/format/Hdu.kt | 2 +- .../kotlin/nebulosa/image/format/Header.kt | 7 - .../nebulosa/image/format/HeaderValue.kt | 2 +- .../kotlin/nebulosa/image/format/ImageData.kt | 3 + .../image/format/ImageRepresentation.kt | 12 ++ .../nebulosa/image/format/ReadableHeader.kt | 2 +- .../nebulosa/image/format/WritableHeader.kt | 2 +- .../nebulosa/image/Float8bitsDataBuffer.kt | 10 +- .../src/main/kotlin/nebulosa/image/Image.kt | 204 +++++++++--------- .../algorithms/transformation/Debayer.kt | 6 +- .../algorithms/transformation/Grayscale.kt | 14 +- .../image/algorithms/transformation/Invert.kt | 6 +- .../transformation/ScreenTransformFunction.kt | 8 +- .../algorithms/transformation/SubFrame.kt | 9 +- .../SubtractiveChromaticNoiseReduction.kt | 2 +- .../src/main/kotlin/nebulosa/wcs/WCS.kt | 2 +- .../src/main/kotlin/nebulosa/xisf/Xisf.kt | 25 +++ .../main/kotlin/nebulosa/xisf/XisfFormat.kt | 44 ++-- .../main/kotlin/nebulosa/xisf/XisfHeader.kt | 46 ---- .../xisf/XisfMonolithicFileHeaderImageData.kt | 2 - .../xisf/XisfMonolithicFileHeaderImageHdu.kt | 3 +- .../src/main/kotlin/nebulosa/xisf/XisfPath.kt | 7 +- 50 files changed, 572 insertions(+), 650 deletions(-) create mode 100644 nebulosa-fits/src/main/kotlin/nebulosa/fits/FitsFormat.kt delete mode 100644 nebulosa-fits/src/main/kotlin/nebulosa/fits/FitsIO.kt delete mode 100644 nebulosa-fits/src/main/kotlin/nebulosa/fits/FitsReader.kt delete mode 100644 nebulosa-fits/src/main/kotlin/nebulosa/fits/FitsWriter.kt delete mode 100644 nebulosa-fits/src/main/kotlin/nebulosa/fits/FloatImageData.kt delete mode 100644 nebulosa-fits/src/main/kotlin/nebulosa/fits/Hdu.kt delete mode 100644 nebulosa-fits/src/main/kotlin/nebulosa/fits/ImageData.kt delete mode 100644 nebulosa-fits/src/main/kotlin/nebulosa/fits/ImageHdu.kt create mode 100644 nebulosa-fits/src/main/kotlin/nebulosa/fits/SeekableSourceImageHdu.kt delete mode 100644 nebulosa-fits/src/test/kotlin/ImageDataTest.kt create mode 100644 nebulosa-image-format/src/main/kotlin/nebulosa/image/format/BasicHdu.kt create mode 100644 nebulosa-image-format/src/main/kotlin/nebulosa/image/format/BasicImageHdu.kt create mode 100644 nebulosa-image-format/src/main/kotlin/nebulosa/image/format/FloatImageData.kt create mode 100644 nebulosa-image-format/src/main/kotlin/nebulosa/image/format/ImageRepresentation.kt create mode 100644 nebulosa-xisf/src/main/kotlin/nebulosa/xisf/Xisf.kt delete mode 100644 nebulosa-xisf/src/main/kotlin/nebulosa/xisf/XisfHeader.kt diff --git a/api/src/main/kotlin/nebulosa/api/calibration/CalibrationFrameService.kt b/api/src/main/kotlin/nebulosa/api/calibration/CalibrationFrameService.kt index 43e45e5ac..f2def0291 100644 --- a/api/src/main/kotlin/nebulosa/api/calibration/CalibrationFrameService.kt +++ b/api/src/main/kotlin/nebulosa/api/calibration/CalibrationFrameService.kt @@ -6,6 +6,8 @@ import nebulosa.image.algorithms.transformation.correction.BiasSubtraction import nebulosa.image.algorithms.transformation.correction.DarkSubtraction import nebulosa.image.algorithms.transformation.correction.FlatCorrection import nebulosa.image.format.Header +import nebulosa.image.format.ImageHdu +import nebulosa.image.format.ReadableHeader import nebulosa.indi.device.camera.FrameType import nebulosa.log.loggerFor import org.springframework.stereotype.Service @@ -99,7 +101,8 @@ class CalibrationFrameService( try { file.fits().use { fits -> - val (header) = fits.filterIsInstance().firstOrNull() ?: return@use + val hdu = fits.filterIsInstance().firstOrNull() ?: return@use + val header = hdu.header val frameType = header.frameType?.takeIf { it != FrameType.LIGHT } ?: return@use val exposureTime = if (frameType == FrameType.DARK) header.exposureTimeInMicroseconds else 0L @@ -175,7 +178,7 @@ class CalibrationFrameService( @JvmStatic private val LOG = loggerFor() - @JvmStatic val Header.frameType + @JvmStatic val ReadableHeader.frameType get() = frame?.uppercase()?.let { if ("LIGHT" in it) FrameType.LIGHT else if ("DARK" in it) FrameType.DARK diff --git a/api/src/main/kotlin/nebulosa/api/cameras/CameraExposureStep.kt b/api/src/main/kotlin/nebulosa/api/cameras/CameraExposureStep.kt index b55358c11..d84b801b5 100644 --- a/api/src/main/kotlin/nebulosa/api/cameras/CameraExposureStep.kt +++ b/api/src/main/kotlin/nebulosa/api/cameras/CameraExposureStep.kt @@ -179,7 +179,7 @@ data class CameraExposureStep( if (stream != null) { stream.transferAndClose(savedPath!!.outputStream()) } else if (fits != null) { - savedPath!!.outputStream().use { fits.writeTo(it.sink()) } + savedPath!!.outputStream().use { fits.write(it.sink()) } } else { return } diff --git a/nebulosa-alpaca-indi/src/main/kotlin/nebulosa/alpaca/indi/device/cameras/ASCOMCamera.kt b/nebulosa-alpaca-indi/src/main/kotlin/nebulosa/alpaca/indi/device/cameras/ASCOMCamera.kt index 08707736e..7716812b9 100644 --- a/nebulosa-alpaca-indi/src/main/kotlin/nebulosa/alpaca/indi/device/cameras/ASCOMCamera.kt +++ b/nebulosa-alpaca-indi/src/main/kotlin/nebulosa/alpaca/indi/device/cameras/ASCOMCamera.kt @@ -7,8 +7,13 @@ import nebulosa.alpaca.api.PulseGuideDirection import nebulosa.alpaca.indi.client.AlpacaClient import nebulosa.alpaca.indi.device.ASCOMDevice import nebulosa.common.concurrency.latch.CountUpDownLatch -import nebulosa.fits.* +import nebulosa.fits.Bitpix +import nebulosa.fits.Fits +import nebulosa.fits.FitsHeader +import nebulosa.fits.FitsKeywordDictionary import nebulosa.image.algorithms.transformation.CfaPattern +import nebulosa.image.format.BasicImageHdu +import nebulosa.image.format.FloatImageData import nebulosa.indi.device.Device import nebulosa.indi.device.camera.* import nebulosa.indi.device.camera.Camera.Companion.NANO_SECONDS @@ -614,15 +619,15 @@ data class ASCOMCamera( val width = metadata.dimension1 val height = metadata.dimension2 - val planes = max(1, metadata.dimension3) + val numberOfChannels = max(1, metadata.dimension3) val source = stream.source().buffer() - val data = Array(planes) { FloatImageData(width, height) } + val data = FloatImageData(width, height, numberOfChannels) for (x in 0 until width) { for (y in 0 until height) { val idx = y * width + x - for (p in 0 until planes) { + for (p in 0 until numberOfChannels) { val pixel = when (metadata.imageElementType.bitpix) { Bitpix.BYTE -> (source.readByte().toInt() and 0xFF) / 255f Bitpix.SHORT -> (source.readShortLe().toInt() + 32768) / 65535f @@ -632,7 +637,13 @@ data class ASCOMCamera( Bitpix.LONG -> return } - data[p].data[idx] = pixel + val channel = when (p) { + 0 -> data.red + 1 -> data.green + else -> data.blue + } + + channel[idx] = pixel } } } @@ -642,10 +653,10 @@ data class ASCOMCamera( val header = FitsHeader() header.add(FitsKeywordDictionary.SIMPLE, true) header.add(FitsKeywordDictionary.BITPIX, -32) - header.add(FitsKeywordDictionary.NAXIS, if (planes == 3) 3 else 2) + header.add(FitsKeywordDictionary.NAXIS, if (numberOfChannels == 3) 3 else 2) header.add(FitsKeywordDictionary.NAXIS1, width) header.add(FitsKeywordDictionary.NAXIS2, height) - if (planes == 3) header.add(FitsKeywordDictionary.NAXIS3, planes) + if (numberOfChannels == 3) header.add(FitsKeywordDictionary.NAXIS3, numberOfChannels) header.add(FitsKeywordDictionary.EXTEND, true) header.add(FitsKeywordDictionary.INSTRUME, name) header.add(FitsKeywordDictionary.EXPTIME, 0.0) // TODO @@ -678,7 +689,7 @@ data class ASCOMCamera( header.add("OFFSET", offset, "Offset") } - val hdu = ImageHdu(header, data) + val hdu = BasicImageHdu(width, height, numberOfChannels, header, data) val fits = Fits() fits.add(hdu) diff --git a/nebulosa-astrometrynet/src/main/kotlin/nebulosa/astrometrynet/nova/NovaAstrometryNetService.kt b/nebulosa-astrometrynet/src/main/kotlin/nebulosa/astrometrynet/nova/NovaAstrometryNetService.kt index 49792edd3..4574bbf5d 100644 --- a/nebulosa-astrometrynet/src/main/kotlin/nebulosa/astrometrynet/nova/NovaAstrometryNetService.kt +++ b/nebulosa-astrometrynet/src/main/kotlin/nebulosa/astrometrynet/nova/NovaAstrometryNetService.kt @@ -1,6 +1,6 @@ package nebulosa.astrometrynet.nova -import nebulosa.fits.FitsIO +import nebulosa.fits.FitsFormat import nebulosa.image.Image import nebulosa.retrofit.RetrofitService import okhttp3.FormBody @@ -62,7 +62,7 @@ class NovaAstrometryNetService( override fun contentType() = OCTET_STREAM_MEDIA_TYPE override fun writeTo(sink: BufferedSink) { - FitsIO.write(sink, image.hdu()) + image.writeTo(sink, FitsFormat) } } diff --git a/nebulosa-fits/src/main/kotlin/nebulosa/fits/Bitpix.kt b/nebulosa-fits/src/main/kotlin/nebulosa/fits/Bitpix.kt index 779b552af..acf90c181 100644 --- a/nebulosa-fits/src/main/kotlin/nebulosa/fits/Bitpix.kt +++ b/nebulosa-fits/src/main/kotlin/nebulosa/fits/Bitpix.kt @@ -1,5 +1,6 @@ package nebulosa.fits +import nebulosa.image.format.HeaderCard import nebulosa.image.format.ReadableHeader import kotlin.math.abs @@ -11,9 +12,9 @@ enum class Bitpix(val type: Class, val code: Int, val description: S FLOAT(Float::class.javaPrimitiveType!!, -32, "32-bit floating point"), DOUBLE(Double::class.javaPrimitiveType!!, -64, "64-bit floating point"); - val card = FitsHeaderCard.create(FitsKeywordDictionary.BITPIX, code) + val card: HeaderCard = FitsHeaderCard.create(FitsKeywordDictionary.BITPIX, code) - val byteSize = abs(code) / 8 + @JvmField internal val byteLength = abs(code) / 8 companion object { diff --git a/nebulosa-fits/src/main/kotlin/nebulosa/fits/Fits.kt b/nebulosa-fits/src/main/kotlin/nebulosa/fits/Fits.kt index 49fbb08ef..67c96b6b2 100644 --- a/nebulosa-fits/src/main/kotlin/nebulosa/fits/Fits.kt +++ b/nebulosa-fits/src/main/kotlin/nebulosa/fits/Fits.kt @@ -1,35 +1,22 @@ package nebulosa.fits +import nebulosa.image.format.Hdu +import nebulosa.image.format.ImageRepresentation import nebulosa.io.SeekableSource import okio.Sink -import java.io.EOFException import java.util.* -open class Fits : LinkedList> { +open class Fits : LinkedList>, ImageRepresentation { constructor() : super() constructor(hdus: Collection>) : super(hdus) - open fun readHdu(source: SeekableSource): Hdu<*>? { - return try { - return FitsIO.read(source).also(::add) - } catch (ignored: EOFException) { - null - } + override fun read(source: SeekableSource) { + addAll(FitsFormat.read(source)) } - open fun read(source: SeekableSource) { - while (true) { - readHdu(source) ?: break - } - } - - open fun writeTo(sink: Sink) { - writeTo(sink, FitsIO) - } - - open fun writeTo(sink: Sink, writer: FitsWriter) { - forEach { writer.write(sink, it) } + override fun write(sink: Sink) { + FitsFormat.write(sink, this) } } diff --git a/nebulosa-fits/src/main/kotlin/nebulosa/fits/FitsFormat.kt b/nebulosa-fits/src/main/kotlin/nebulosa/fits/FitsFormat.kt new file mode 100644 index 000000000..fa59bc81a --- /dev/null +++ b/nebulosa-fits/src/main/kotlin/nebulosa/fits/FitsFormat.kt @@ -0,0 +1,165 @@ +package nebulosa.fits + +import nebulosa.fits.FitsHeader.Companion.isFirstCard +import nebulosa.image.format.* +import nebulosa.io.* +import nebulosa.log.loggerFor +import okio.Buffer +import okio.Sink +import java.io.EOFException +import kotlin.math.max + +object FitsFormat : ImageFormat { + + const val BLOCK_SIZE = 2880 + + @JvmStatic + fun computeRemainingBytesToSkip(sizeInBytes: Long): Long { + val numberOfBlocks = (sizeInBytes / BLOCK_SIZE) + 1 + val remainingByteCount = (numberOfBlocks * BLOCK_SIZE) - sizeInBytes + return max(0L, remainingByteCount) + } + + fun isImageHdu(header: ReadableHeader) = + header.getBoolean(FitsKeywordDictionary.SIMPLE) || header.getStringOrNull(FitsKeywordDictionary.XTENSION) == "IMAGE" + + fun readHeader(source: SeekableSource): FitsHeader { + val header = FitsHeader() + + var count = 0 + + Buffer().use { buffer -> + while (true) { + buffer.clear() + + if (source.read(buffer, 80L) != 80L) throw EOFException() + + val card = FitsHeaderCard.from(buffer) + + count++ + + if (header.isEmpty()) { + require(isFirstCard(card.key)) { "Not a proper FITS header: ${card.key}" } + } else if (card.isBlank) { + continue + } else if (card.key == FitsKeywordDictionary.END.key) { + break + } + + header.add(card) + } + + val skipBytes = computeRemainingBytesToSkip(count * 80L) + if (skipBytes > 0L) source.skip(skipBytes) + } + + return header + } + + fun readImageData(header: ReadableHeader, source: SeekableSource): ImageData { + val width = header.width + val height = header.height + val numberOfChannels = header.numberOfChannels + val bitpix = header.bitpix + val position = source.position + + val data = SeekableSourceImageData(source, position, width, height, numberOfChannels, bitpix) + val skipBytes = computeRemainingBytesToSkip(data.channelBlockSize * numberOfChannels) + if (skipBytes > 0L) source.seek(position + skipBytes) + + return data + } + + override fun read(source: SeekableSource): List> { + val header = readHeader(source) + val hdus = ArrayList(2) + + while (!source.exhausted) { + val hdu = when { + isImageHdu(header) -> SeekableSourceImageHdu(header, readImageData(header, source)) + else -> { + LOG.warn("unsupported FITS header: {}", header) + continue + } + } + + hdus.add(hdu) + } + + return hdus + } + + fun writeHeader(header: ReadableHeader, sink: Sink) { + Buffer().use { buffer -> + for (card in header) { + buffer.writeString(card.formatted(), Charsets.US_ASCII) + } + + if (header.last().key != FitsHeaderCard.END.key) { + buffer.writeString(FitsHeaderCard.END.formatted(), Charsets.US_ASCII) + } + + val remainingBytes = computeRemainingBytesToSkip(buffer.size) + repeat(remainingBytes.toInt()) { buffer.writeByte(0) } + buffer.readAll(sink) + } + } + + fun writeImageData(data: ImageData, header: ReadableHeader, sink: Sink) { + val bitpix = header.bitpix + val channels = arrayOf(data.red, data.green, data.blue) + var byteCount = 0L + + Buffer().use { buffer -> + for (channel in 0 until data.numberOfChannels) { + for (i in 0 until data.numberOfPixels) { + buffer.writePixel(channels[0][i], bitpix) + + if (buffer.size >= 1024L) { + byteCount += buffer.readAll(sink) + } + } + } + + val remainingBytes = computeRemainingBytesToSkip(byteCount) + + if (remainingBytes > 0) { + repeat(remainingBytes.toInt()) { buffer.writeByte(0) } + buffer.readAll(sink) + } + } + } + + override fun write(sink: Sink, hdus: Iterable>) { + for (hdu in hdus) { + if (hdu is ImageHdu) { + writeHeader(hdu.header, sink) + writeImageData(hdu.data, hdu.header, sink) + } + } + } + + internal fun Buffer.readPixel(bitpix: Bitpix): Float { + return when (bitpix) { + Bitpix.BYTE -> (buffer.readByte().toInt() and 0xFF) / 255f + Bitpix.SHORT -> (buffer.readShort().toInt() and 0xFFFF) / 65535f + Bitpix.INTEGER -> ((buffer.readInt().toLong() and 0xFFFFFFFF) / 4294967295.0).toFloat() + Bitpix.LONG -> TODO("Unsupported UInt64 sample format") + Bitpix.FLOAT -> buffer.readFloat() + Bitpix.DOUBLE -> buffer.readDouble().toFloat() + } + } + + internal fun Buffer.writePixel(pixel: Float, bitpix: Bitpix) { + when (bitpix) { + Bitpix.BYTE -> buffer.writeByte((pixel * 255f).toInt()) + Bitpix.SHORT -> buffer.writeShort((pixel * 65535f).toInt()) + Bitpix.INTEGER -> buffer.writeInt((pixel * 4294967295.0).toInt()) + Bitpix.LONG -> TODO("Unsupported UInt64 sample format") + Bitpix.FLOAT -> buffer.writeFloat(pixel) + Bitpix.DOUBLE -> buffer.writeDouble(pixel.toDouble()) + } + } + + @JvmStatic private val LOG = loggerFor() +} diff --git a/nebulosa-fits/src/main/kotlin/nebulosa/fits/FitsHeader.kt b/nebulosa-fits/src/main/kotlin/nebulosa/fits/FitsHeader.kt index 47b75110d..82c6f3e1c 100644 --- a/nebulosa-fits/src/main/kotlin/nebulosa/fits/FitsHeader.kt +++ b/nebulosa-fits/src/main/kotlin/nebulosa/fits/FitsHeader.kt @@ -6,12 +6,9 @@ import nebulosa.image.format.HeaderKey import nebulosa.io.SeekableSource import nebulosa.io.source import nebulosa.log.loggerFor -import okio.Buffer -import okio.Sink -import java.io.EOFException import java.util.* -open class FitsHeader : AbstractHeader, FitsElement { +open class FitsHeader : AbstractHeader { constructor() : super() @@ -21,57 +18,6 @@ open class FitsHeader : AbstractHeader, FitsElement { override fun clone() = FitsHeader(this) - override fun read(source: SeekableSource) { - clear() - - var count = 0 - val buffer = Buffer() - - while (true) { - buffer.clear() - - if (source.read(buffer, 80L) != 80L) throw EOFException() - - val card = FitsHeaderCard.from(buffer) - count++ - - if (cards.isEmpty()) { - require(isFirstCard(card.key)) { "Not a proper FITS header: ${card.key}" } - } else if (card.isBlank) { - continue - } else if (card.key == FitsKeywordDictionary.END.key) { - break - } - - add(card) - } - - val skipBytes = Hdu.computeRemainingBytesToSkip(count * 80L) - if (skipBytes > 0L) source.skip(skipBytes) - - buffer.clear() - } - - override fun write(sink: Sink) { - val buffer = Buffer() - - for (card in cards) { - buffer.writeString(card.formattedValue(), Charsets.US_ASCII) - } - - if (cards.last.key != "END") { - buffer.writeString(FitsHeaderCard.END.formattedValue(), Charsets.US_ASCII) - } - - var remainingBytes = Hdu.computeRemainingBytesToSkip(buffer.size) - - while (remainingBytes-- > 0) { - buffer.writeByte(0) - } - - buffer.readAll(sink) - } - override fun add(key: HeaderKey, value: Boolean) { checkType(key, ValueType.LOGICAL) FitsHeaderCard.create(key, value).also(::add) @@ -123,8 +69,6 @@ open class FitsHeader : AbstractHeader, FitsElement { constructor(cards: Collection) : super(cards) - final override fun read(source: SeekableSource) = Unit - final override fun clear() = Unit final override fun add(key: HeaderKey, value: Boolean) = Unit @@ -135,8 +79,6 @@ open class FitsHeader : AbstractHeader, FitsElement { final override fun add(key: HeaderKey, value: String) = Unit - final override fun write(sink: Sink) = Unit - final override fun add(key: String, value: Boolean, comment: String) = Unit final override fun add(key: String, value: Int, comment: String) = Unit @@ -170,9 +112,7 @@ open class FitsHeader : AbstractHeader, FitsElement { @JvmStatic fun from(source: SeekableSource): FitsHeader { - val header = FitsHeader() - header.read(source) - return header + return FitsFormat.readHeader(source) } @JvmStatic diff --git a/nebulosa-fits/src/main/kotlin/nebulosa/fits/FitsHeaderCard.kt b/nebulosa-fits/src/main/kotlin/nebulosa/fits/FitsHeaderCard.kt index 863979efe..9b5862b50 100644 --- a/nebulosa-fits/src/main/kotlin/nebulosa/fits/FitsHeaderCard.kt +++ b/nebulosa-fits/src/main/kotlin/nebulosa/fits/FitsHeaderCard.kt @@ -92,7 +92,7 @@ data class FitsHeaderCard( } } - override fun formattedValue(): String { + override fun formatted(): String { return FitsHeaderCardFormatter.format(this) } diff --git a/nebulosa-fits/src/main/kotlin/nebulosa/fits/FitsHelper.kt b/nebulosa-fits/src/main/kotlin/nebulosa/fits/FitsHelper.kt index 307886eb8..105c79e26 100644 --- a/nebulosa-fits/src/main/kotlin/nebulosa/fits/FitsHelper.kt +++ b/nebulosa-fits/src/main/kotlin/nebulosa/fits/FitsHelper.kt @@ -22,6 +22,12 @@ inline val ReadableHeader.width inline val ReadableHeader.height get() = getInt(FitsKeywordDictionary.NAXIS2, 0) +inline val ReadableHeader.numberOfChannels + get() = getInt(FitsKeywordDictionary.NAXIS3, 1) + +inline val ReadableHeader.bitpix + get() = Bitpix.from(this) + val ReadableHeader.rightAscension get() = Angle(getStringOrNull(FitsKeywordDictionary.RA), isHours = true, decimalIsHours = false).takeIf { it.isFinite() } ?: Angle(getStringOrNull(FitsKeywordDictionary.OBJCTRA), true).takeIf { it.isFinite() } diff --git a/nebulosa-fits/src/main/kotlin/nebulosa/fits/FitsIO.kt b/nebulosa-fits/src/main/kotlin/nebulosa/fits/FitsIO.kt deleted file mode 100644 index 010eb4bdc..000000000 --- a/nebulosa-fits/src/main/kotlin/nebulosa/fits/FitsIO.kt +++ /dev/null @@ -1,25 +0,0 @@ -package nebulosa.fits - -import nebulosa.io.SeekableSource -import okio.Sink -import java.io.IOException - -object FitsIO : FitsReader, FitsWriter { - - override fun read(source: SeekableSource): Hdu<*> { - val header = FitsHeader.from(source) - - val hdu = when { - ImageHdu.isValid(header) -> ImageHdu(header) - else -> throw IOException("unsupported FITS header") - } - - hdu.read(source) - - return hdu - } - - override fun write(sink: Sink, hdu: Hdu<*>) { - hdu.write(sink) - } -} diff --git a/nebulosa-fits/src/main/kotlin/nebulosa/fits/FitsPath.kt b/nebulosa-fits/src/main/kotlin/nebulosa/fits/FitsPath.kt index e76bfa878..6a7ca33fd 100644 --- a/nebulosa-fits/src/main/kotlin/nebulosa/fits/FitsPath.kt +++ b/nebulosa-fits/src/main/kotlin/nebulosa/fits/FitsPath.kt @@ -16,15 +16,11 @@ class FitsPath(val path: Path) : Fits(), Closeable { constructor(path: String) : this(Path.of(path)) fun read() { - return read(source) + read(source) } - fun readHdu(): Hdu<*>? { - return readHdu(source) - } - - fun writeTo() { - writeTo(sink) + fun write() { + write(sink) } override fun close() { diff --git a/nebulosa-fits/src/main/kotlin/nebulosa/fits/FitsReader.kt b/nebulosa-fits/src/main/kotlin/nebulosa/fits/FitsReader.kt deleted file mode 100644 index 558d92df7..000000000 --- a/nebulosa-fits/src/main/kotlin/nebulosa/fits/FitsReader.kt +++ /dev/null @@ -1,8 +0,0 @@ -package nebulosa.fits - -import nebulosa.io.SeekableSource - -interface FitsReader { - - fun read(source: SeekableSource): Hdu<*>? -} diff --git a/nebulosa-fits/src/main/kotlin/nebulosa/fits/FitsWriter.kt b/nebulosa-fits/src/main/kotlin/nebulosa/fits/FitsWriter.kt deleted file mode 100644 index 347f10112..000000000 --- a/nebulosa-fits/src/main/kotlin/nebulosa/fits/FitsWriter.kt +++ /dev/null @@ -1,8 +0,0 @@ -package nebulosa.fits - -import okio.Sink - -interface FitsWriter { - - fun write(sink: Sink, hdu: Hdu<*>) -} diff --git a/nebulosa-fits/src/main/kotlin/nebulosa/fits/FloatImageData.kt b/nebulosa-fits/src/main/kotlin/nebulosa/fits/FloatImageData.kt deleted file mode 100644 index 0c62de7fc..000000000 --- a/nebulosa-fits/src/main/kotlin/nebulosa/fits/FloatImageData.kt +++ /dev/null @@ -1,43 +0,0 @@ -package nebulosa.fits - -import nebulosa.io.writeFloat -import okio.Buffer -import okio.Sink -import java.nio.ByteBuffer - -@Suppress("ArrayInDataClass") -data class FloatImageData( - override val width: Int, - override val height: Int, - @JvmField val data: FloatArray = FloatArray(width * height), -) : ImageData { - - override val bitpix = Bitpix.FLOAT - - override fun read(block: (ByteBuffer) -> Unit) { - val strideSizeInBytes = width * bitpix.byteSize - val stride = ByteBuffer.allocate(strideSizeInBytes) - - repeat(height) { - var offset = it * width - stride.clear() - repeat(width) { stride.putFloat(data[offset++]) } - stride.flip() - block(stride) - } - } - - override fun writeTo(sink: Sink): Long { - return Buffer().use { b -> - var byteCount = 0L - - repeat(height) { - var offset = it * width - repeat(width) { b.writeFloat(data[offset++]) } - byteCount += b.readAll(sink) - } - - byteCount - } - } -} diff --git a/nebulosa-fits/src/main/kotlin/nebulosa/fits/Hdu.kt b/nebulosa-fits/src/main/kotlin/nebulosa/fits/Hdu.kt deleted file mode 100644 index 23b14c2b5..000000000 --- a/nebulosa-fits/src/main/kotlin/nebulosa/fits/Hdu.kt +++ /dev/null @@ -1,42 +0,0 @@ -package nebulosa.fits - -import nebulosa.image.format.ReadableHeader -import kotlin.math.max - -interface Hdu : FitsElement, Collection { - - val header: ReadableHeader - - val data: Array - - override val size - get() = data.size - - override fun contains(element: T): Boolean { - return data.any { it === element } - } - - override fun containsAll(elements: Collection): Boolean { - return elements.all { it in this } - } - - override fun isEmpty(): Boolean { - return data.isEmpty() - } - - override fun iterator(): Iterator { - return data.iterator() - } - - companion object { - - const val BLOCK_SIZE = 2880 - - @JvmStatic - fun computeRemainingBytesToSkip(sizeInBytes: Long): Long { - val numberOfBlocks = (sizeInBytes / BLOCK_SIZE) + 1 - val remainingByteCount = (numberOfBlocks * BLOCK_SIZE) - sizeInBytes - return max(0L, remainingByteCount) - } - } -} diff --git a/nebulosa-fits/src/main/kotlin/nebulosa/fits/ImageData.kt b/nebulosa-fits/src/main/kotlin/nebulosa/fits/ImageData.kt deleted file mode 100644 index 6e1aae545..000000000 --- a/nebulosa-fits/src/main/kotlin/nebulosa/fits/ImageData.kt +++ /dev/null @@ -1,17 +0,0 @@ -package nebulosa.fits - -import okio.Sink -import java.nio.ByteBuffer - -interface ImageData { - - val width: Int - - val height: Int - - val bitpix: Bitpix - - fun read(block: (ByteBuffer) -> Unit) - - fun writeTo(sink: Sink): Long -} diff --git a/nebulosa-fits/src/main/kotlin/nebulosa/fits/ImageHdu.kt b/nebulosa-fits/src/main/kotlin/nebulosa/fits/ImageHdu.kt deleted file mode 100644 index f6ba70399..000000000 --- a/nebulosa-fits/src/main/kotlin/nebulosa/fits/ImageHdu.kt +++ /dev/null @@ -1,65 +0,0 @@ -package nebulosa.fits - -import nebulosa.image.format.Header -import nebulosa.image.format.ReadableHeader -import nebulosa.io.SeekableSource -import okio.Buffer -import okio.Sink - -data class ImageHdu( - override var header: Header, - override var data: Array = emptyArray(), -) : Hdu { - - val width = header.width - val height = header.height - val bitpix = Bitpix.from(header) - - override fun read(source: SeekableSource) { - val imageSize = (width * height * bitpix.byteSize).toLong() - var position = source.position - val n = header.getInt(FitsKeywordDictionary.NAXIS3, 1) - data = Array(n) { SeekableSourceImageData(source, position, width, height, bitpix).also { position += imageSize } } - - val skipBytes = Hdu.computeRemainingBytesToSkip(imageSize * size) - if (skipBytes > 0L) source.seek(position + skipBytes) - } - - override fun write(sink: Sink) { - header.write(sink) - - val byteCount = data.sumOf { it.writeTo(sink) } - var remainingBytes = Hdu.computeRemainingBytesToSkip(byteCount) - - if (remainingBytes > 0) { - Buffer().use { - while (remainingBytes-- > 0) it.writeByte(0) - it.readAll(sink) - it.close() - } - } - } - - override fun equals(other: Any?): Boolean { - if (this === other) return true - if (other !is ImageHdu) return false - - if (header != other.header) return false - if (!data.contentDeepEquals(other.data)) return false - - return true - } - - override fun hashCode(): Int { - var result = header.hashCode() - result = 31 * result + data.contentDeepHashCode() - return result - } - - companion object { - - @JvmStatic - fun isValid(header: ReadableHeader) = - header.getBoolean(FitsKeywordDictionary.SIMPLE) || header.getStringOrNull(FitsKeywordDictionary.XTENSION) == "IMAGE" - } -} diff --git a/nebulosa-fits/src/main/kotlin/nebulosa/fits/SeekableSourceImageData.kt b/nebulosa-fits/src/main/kotlin/nebulosa/fits/SeekableSourceImageData.kt index 85f0ca77e..2f2e8dd42 100644 --- a/nebulosa-fits/src/main/kotlin/nebulosa/fits/SeekableSourceImageData.kt +++ b/nebulosa-fits/src/main/kotlin/nebulosa/fits/SeekableSourceImageData.kt @@ -1,56 +1,121 @@ package nebulosa.fits +import nebulosa.fits.FitsFormat.readPixel +import nebulosa.image.format.ImageChannel +import nebulosa.image.format.ImageData import nebulosa.io.SeekableSource -import nebulosa.io.sink -import nebulosa.io.transferFully import okio.Buffer import okio.Sink -import java.nio.ByteBuffer +import kotlin.math.min -data class SeekableSourceImageData( +@Suppress("NOTHING_TO_INLINE") +internal data class SeekableSourceImageData( private val source: SeekableSource, private val position: Long, override val width: Int, override val height: Int, - override val bitpix: Bitpix, + override val numberOfChannels: Int, + private val bitpix: Bitpix, ) : ImageData { - private val strideSizeInBytes = (width * bitpix.byteSize).toLong() + @JvmField internal val channelBlockSize = (numberOfPixels * bitpix.byteLength).toLong() - override fun read(block: (ByteBuffer) -> Unit) { - val data = ByteArray(strideSizeInBytes.toInt()) - val sink = data.sink() + override val red by lazy { readImage(ImageChannel.RED) } - synchronized(source) { - source.seek(position) + override val green by lazy { readImage(ImageChannel.GREEN) } - Buffer().use { b -> - repeat(height) { - sink.seek(0L) + override val blue by lazy { readImage(ImageChannel.BLUE) } - b.transferFully(source, sink, strideSizeInBytes) - block(ByteBuffer.wrap(data)) - b.clear() + @Synchronized + private fun readImage(channel: ImageChannel): FloatArray { + return if (numberOfChannels == 1) { + if (channel.index == 0) readGray() else red + } else { + when (channel) { + ImageChannel.GREEN -> readGreen() + ImageChannel.BLUE -> readBlue() + else -> readRed() + } + } + } + + private inline fun readGray(): FloatArray { + return readChannel(ImageChannel.GRAY) + } + + private inline fun readRed(): FloatArray { + return readChannel(ImageChannel.RED) + } + + private inline fun readGreen(): FloatArray { + return readChannel(ImageChannel.GREEN) + } + + private inline fun readBlue(): FloatArray { + return readChannel(ImageChannel.BLUE) + } + + private fun readChannel(channel: ImageChannel): FloatArray { + val startIndex = channelBlockSize * channel.index + source.seek(position + startIndex) + + val data = FloatArray(numberOfPixels) + var remainingPixels = data.size + var pos = 0 + + Buffer().use { buffer -> + while (remainingPixels > 0) { + var n = min(PIXEL_COUNT, remainingPixels) + val byteCount = n * bitpix.byteLength.toLong() + + val size = source.read(buffer, byteCount) + + if (size == 0L) break + + // require(size % bitpix.byteLength == 0L) + n = (size / bitpix.byteLength).toInt() + + repeat(n) { + data[pos++] = buffer.readPixel(bitpix) } + + remainingPixels -= n } } + + return data } - override fun writeTo(sink: Sink): Long { + internal fun writeTo(sink: Sink): Long { var byteCount = 0L - return synchronized(source) { - source.seek(position) + Buffer().use { buffer -> + for (i in 0 until numberOfChannels) { + val startIndex = channelBlockSize * i + var bytesToWrite = channelBlockSize + + source.seek(position + startIndex) + + while (bytesToWrite > 0L) { + val length = source.read(buffer, min(bytesToWrite, 1024L)) - Buffer().use { b -> - repeat(height) { - b.transferFully(source, sink, strideSizeInBytes) - b.clear() - byteCount += strideSizeInBytes + if (length > 0L) { + sink.write(buffer, length) + + buffer.clear() + + byteCount += length + bytesToWrite -= length + } } } - - byteCount } + + return byteCount + } + + companion object { + + const val PIXEL_COUNT = 64 } } diff --git a/nebulosa-fits/src/main/kotlin/nebulosa/fits/SeekableSourceImageHdu.kt b/nebulosa-fits/src/main/kotlin/nebulosa/fits/SeekableSourceImageHdu.kt new file mode 100644 index 000000000..20df3b51c --- /dev/null +++ b/nebulosa-fits/src/main/kotlin/nebulosa/fits/SeekableSourceImageHdu.kt @@ -0,0 +1,15 @@ +package nebulosa.fits + +import nebulosa.image.format.ImageData +import nebulosa.image.format.ImageHdu +import nebulosa.image.format.ReadableHeader + +internal data class SeekableSourceImageHdu( + override val header: ReadableHeader, + override val data: ImageData, +) : ImageHdu { + + override val width = header.width + override val height = header.height + override val numberOfChannels = header.numberOfChannels +} diff --git a/nebulosa-fits/src/test/kotlin/FitsReadTest.kt b/nebulosa-fits/src/test/kotlin/FitsReadTest.kt index 981768217..e82dd6143 100644 --- a/nebulosa-fits/src/test/kotlin/FitsReadTest.kt +++ b/nebulosa-fits/src/test/kotlin/FitsReadTest.kt @@ -1,7 +1,8 @@ import io.kotest.matchers.ints.shouldBeExactly import io.kotest.matchers.shouldBe import nebulosa.fits.Bitpix -import nebulosa.fits.ImageHdu +import nebulosa.fits.bitpix +import nebulosa.image.format.ImageHdu import nebulosa.test.FitsStringSpec class FitsReadTest : FitsStringSpec() { @@ -11,71 +12,71 @@ class FitsReadTest : FitsStringSpec() { val hdu = NGC3344_MONO_8_FITS.filterIsInstance().first() hdu.width shouldBeExactly 256 hdu.height shouldBeExactly 256 - hdu.size shouldBeExactly 1 - hdu.bitpix shouldBe Bitpix.BYTE + hdu.numberOfChannels shouldBeExactly 1 + hdu.header.bitpix shouldBe Bitpix.BYTE } "mono:16-bit" { val hdu = NGC3344_MONO_16_FITS.filterIsInstance().first() hdu.width shouldBeExactly 256 hdu.height shouldBeExactly 256 - hdu.size shouldBeExactly 1 - hdu.bitpix shouldBe Bitpix.SHORT + hdu.numberOfChannels shouldBeExactly 1 + hdu.header.bitpix shouldBe Bitpix.SHORT } "mono:32-bit" { val hdu = NGC3344_MONO_32_FITS.filterIsInstance().first() hdu.width shouldBeExactly 256 hdu.height shouldBeExactly 256 - hdu.size shouldBeExactly 1 - hdu.bitpix shouldBe Bitpix.INTEGER + hdu.numberOfChannels shouldBeExactly 1 + hdu.header.bitpix shouldBe Bitpix.INTEGER } "mono:32-bit floating-point" { val hdu = NGC3344_MONO_F32_FITS.filterIsInstance().first() hdu.width shouldBeExactly 256 hdu.height shouldBeExactly 256 - hdu.size shouldBeExactly 1 - hdu.bitpix shouldBe Bitpix.FLOAT + hdu.numberOfChannels shouldBeExactly 1 + hdu.header.bitpix shouldBe Bitpix.FLOAT } "mono:64-bit floating-point" { val hdu = NGC3344_MONO_F64_FITS.filterIsInstance().first() hdu.width shouldBeExactly 256 hdu.height shouldBeExactly 256 - hdu.size shouldBeExactly 1 - hdu.bitpix shouldBe Bitpix.DOUBLE + hdu.numberOfChannels shouldBeExactly 1 + hdu.header.bitpix shouldBe Bitpix.DOUBLE } "color:8-bit" { val hdu = NGC3344_COLOR_8_FITS.filterIsInstance().first() hdu.width shouldBeExactly 256 hdu.height shouldBeExactly 256 - hdu.size shouldBeExactly 4 - hdu.bitpix shouldBe Bitpix.BYTE + hdu.numberOfChannels shouldBeExactly 4 + hdu.header.bitpix shouldBe Bitpix.BYTE } "color:16-bit" { val hdu = NGC3344_COLOR_16_FITS.filterIsInstance().first() hdu.width shouldBeExactly 256 hdu.height shouldBeExactly 256 - hdu.size shouldBeExactly 4 - hdu.bitpix shouldBe Bitpix.SHORT + hdu.numberOfChannels shouldBeExactly 4 + hdu.header.bitpix shouldBe Bitpix.SHORT } "color:32-bit" { val hdu = NGC3344_COLOR_32_FITS.filterIsInstance().first() hdu.width shouldBeExactly 256 hdu.height shouldBeExactly 256 - hdu.size shouldBeExactly 4 - hdu.bitpix shouldBe Bitpix.INTEGER + hdu.numberOfChannels shouldBeExactly 4 + hdu.header.bitpix shouldBe Bitpix.INTEGER } "color:32-bit floating-point" { val hdu = NGC3344_COLOR_F32_FITS.filterIsInstance().first() hdu.width shouldBeExactly 256 hdu.height shouldBeExactly 256 - hdu.size shouldBeExactly 4 - hdu.bitpix shouldBe Bitpix.FLOAT + hdu.numberOfChannels shouldBeExactly 4 + hdu.header.bitpix shouldBe Bitpix.FLOAT } "color:64-bit floating-point" { val hdu = NGC3344_COLOR_F64_FITS.filterIsInstance().first() hdu.width shouldBeExactly 256 hdu.height shouldBeExactly 256 - hdu.size shouldBeExactly 4 - hdu.bitpix shouldBe Bitpix.DOUBLE + hdu.numberOfChannels shouldBeExactly 4 + hdu.header.bitpix shouldBe Bitpix.DOUBLE } } } diff --git a/nebulosa-fits/src/test/kotlin/FitsWriteTest.kt b/nebulosa-fits/src/test/kotlin/FitsWriteTest.kt index 42597f91d..d555bcee8 100644 --- a/nebulosa-fits/src/test/kotlin/FitsWriteTest.kt +++ b/nebulosa-fits/src/test/kotlin/FitsWriteTest.kt @@ -1,6 +1,7 @@ import io.kotest.matchers.shouldBe -import nebulosa.fits.ImageHdu +import nebulosa.fits.FitsFormat import nebulosa.fits.fits +import nebulosa.image.format.ImageHdu import nebulosa.io.sink import nebulosa.io.source import nebulosa.test.FitsStringSpec @@ -12,7 +13,7 @@ class FitsWriteTest : FitsStringSpec() { "mono" { val hdu0 = NGC3344_MONO_8_FITS.filterIsInstance().first() val data = ByteArray(69120) - hdu0.write(data.sink()) + FitsFormat.write(data.sink(), listOf(hdu0)) data.toByteString(2880, 66240).md5().hex() shouldBe "e1735e21c94dc49885fabc429406e573" val fits = data.source().use { it.fits() } diff --git a/nebulosa-fits/src/test/kotlin/ImageDataTest.kt b/nebulosa-fits/src/test/kotlin/ImageDataTest.kt deleted file mode 100644 index 77e75b901..000000000 --- a/nebulosa-fits/src/test/kotlin/ImageDataTest.kt +++ /dev/null @@ -1,63 +0,0 @@ -import io.kotest.core.spec.style.StringSpec -import io.kotest.matchers.floats.shouldBeExactly -import io.kotest.matchers.ints.shouldBeExactly -import nebulosa.fits.Bitpix -import nebulosa.fits.FloatImageData -import nebulosa.fits.SeekableSourceImageData -import nebulosa.io.sink -import nebulosa.io.source -import java.nio.ByteBuffer - -class ImageDataTest : StringSpec() { - - init { - "float:read" { - val input = FloatArray(100) { it.toFloat() } - val data = FloatImageData(10, 10, input) - - var i = 0 - - data.read { b -> - repeat(10) { b.getFloat() shouldBeExactly input[i++] } - } - - i shouldBeExactly 100 - } - "float:write" { - val input = FloatArray(100) { it.toFloat() } - val data = FloatImageData(10, 10, input) - val output = ByteArray(100 * 4) - - data.writeTo(output.sink()) - - val buffer = ByteBuffer.wrap(output) - - repeat(100) { - buffer.getFloat() shouldBeExactly input[it] - } - } - "seekable source:read" { - val input = ByteArray(100) { it.toByte() } - val data = SeekableSourceImageData(input.source(), 0L, 10, 10, Bitpix.BYTE) - - var i = 0 - - data.read { b -> - repeat(10) { b.get().toInt() shouldBeExactly input[i++].toInt() } - } - - i shouldBeExactly 100 - } - "seekable source:write" { - val input = ByteArray(100) { it.toByte() } - val data = SeekableSourceImageData(input.source(), 0L, 10, 10, Bitpix.BYTE) - val output = ByteArray(input.size) - - data.writeTo(output.sink()) - - repeat(output.size) { - output[it].toInt() shouldBeExactly input[it].toInt() - } - } - } -} diff --git a/nebulosa-hips2fits/src/test/kotlin/Hips2FitsServiceTest.kt b/nebulosa-hips2fits/src/test/kotlin/Hips2FitsServiceTest.kt index 1f5adf9dc..2853c8809 100644 --- a/nebulosa-hips2fits/src/test/kotlin/Hips2FitsServiceTest.kt +++ b/nebulosa-hips2fits/src/test/kotlin/Hips2FitsServiceTest.kt @@ -6,6 +6,7 @@ import io.kotest.matchers.ints.shouldBeExactly import io.kotest.matchers.nulls.shouldNotBeNull import nebulosa.fits.* import nebulosa.hips2fits.Hips2FitsService +import nebulosa.image.format.ImageHdu import nebulosa.io.source import nebulosa.math.deg import nebulosa.math.toDegrees diff --git a/nebulosa-image-format/src/main/kotlin/nebulosa/image/format/AbstractHeader.kt b/nebulosa-image-format/src/main/kotlin/nebulosa/image/format/AbstractHeader.kt index 7862fb539..3bf66aa24 100644 --- a/nebulosa-image-format/src/main/kotlin/nebulosa/image/format/AbstractHeader.kt +++ b/nebulosa-image-format/src/main/kotlin/nebulosa/image/format/AbstractHeader.kt @@ -29,11 +29,7 @@ abstract class AbstractHeader protected constructor(@JvmField protected val card return true } - override fun hashCode(): Int { - return cards.hashCode() - } + override fun hashCode() = cards.hashCode() - override fun toString(): String { - return "Header(cards=$cards)" - } + override fun toString() = "${javaClass.simpleName}(cards=$cards)" } diff --git a/nebulosa-image-format/src/main/kotlin/nebulosa/image/format/BasicHdu.kt b/nebulosa-image-format/src/main/kotlin/nebulosa/image/format/BasicHdu.kt new file mode 100644 index 000000000..c7031e544 --- /dev/null +++ b/nebulosa-image-format/src/main/kotlin/nebulosa/image/format/BasicHdu.kt @@ -0,0 +1,3 @@ +package nebulosa.image.format + +data class BasicHdu(override val header: ReadableHeader, override val data: T) : Hdu diff --git a/nebulosa-image-format/src/main/kotlin/nebulosa/image/format/BasicImageHdu.kt b/nebulosa-image-format/src/main/kotlin/nebulosa/image/format/BasicImageHdu.kt new file mode 100644 index 000000000..995f641fd --- /dev/null +++ b/nebulosa-image-format/src/main/kotlin/nebulosa/image/format/BasicImageHdu.kt @@ -0,0 +1,9 @@ +package nebulosa.image.format + +data class BasicImageHdu( + override val width: Int, + override val height: Int, + override val numberOfChannels: Int, + override val header: ReadableHeader, + override val data: ImageData, +) : ImageHdu diff --git a/nebulosa-image-format/src/main/kotlin/nebulosa/image/format/FloatImageData.kt b/nebulosa-image-format/src/main/kotlin/nebulosa/image/format/FloatImageData.kt new file mode 100644 index 000000000..64bddc643 --- /dev/null +++ b/nebulosa-image-format/src/main/kotlin/nebulosa/image/format/FloatImageData.kt @@ -0,0 +1,11 @@ +package nebulosa.image.format + +@Suppress("ArrayInDataClass") +data class FloatImageData( + override val width: Int, + override val height: Int, + override val numberOfChannels: Int = 1, + override val red: FloatArray = FloatArray(width * height), + override val green: FloatArray = if (numberOfChannels == 1) red else FloatArray(width * height), + override val blue: FloatArray = if (numberOfChannels == 1) red else FloatArray(width * height), +) : ImageData diff --git a/nebulosa-image-format/src/main/kotlin/nebulosa/image/format/Hdu.kt b/nebulosa-image-format/src/main/kotlin/nebulosa/image/format/Hdu.kt index 462ba4cea..4507dd62b 100644 --- a/nebulosa-image-format/src/main/kotlin/nebulosa/image/format/Hdu.kt +++ b/nebulosa-image-format/src/main/kotlin/nebulosa/image/format/Hdu.kt @@ -1,6 +1,6 @@ package nebulosa.image.format -interface Hdu { +sealed interface Hdu { val header: ReadableHeader diff --git a/nebulosa-image-format/src/main/kotlin/nebulosa/image/format/Header.kt b/nebulosa-image-format/src/main/kotlin/nebulosa/image/format/Header.kt index bccb00803..637b5633f 100644 --- a/nebulosa-image-format/src/main/kotlin/nebulosa/image/format/Header.kt +++ b/nebulosa-image-format/src/main/kotlin/nebulosa/image/format/Header.kt @@ -1,8 +1,5 @@ package nebulosa.image.format -import nebulosa.io.SeekableSource -import okio.Sink - interface Header : ReadableHeader, WritableHeader, Cloneable { public override fun clone(): Header @@ -21,8 +18,6 @@ interface Header : ReadableHeader, WritableHeader, Cloneable { override fun iterator() = this - override fun write(sink: Sink) = Unit - override fun clear() = Unit override fun add(key: String, value: Boolean, comment: String) = Unit @@ -35,8 +30,6 @@ interface Header : ReadableHeader, WritableHeader, Cloneable { override fun delete(key: String) = false - override fun read(source: SeekableSource) = Unit - override fun hasNext() = false override fun next() = TODO("Unsupported operation") diff --git a/nebulosa-image-format/src/main/kotlin/nebulosa/image/format/HeaderValue.kt b/nebulosa-image-format/src/main/kotlin/nebulosa/image/format/HeaderValue.kt index 4b0edb4ae..2f0d528e4 100644 --- a/nebulosa-image-format/src/main/kotlin/nebulosa/image/format/HeaderValue.kt +++ b/nebulosa-image-format/src/main/kotlin/nebulosa/image/format/HeaderValue.kt @@ -6,5 +6,5 @@ interface HeaderValue { fun getValue(asType: Class, defaultValue: T): T - fun formattedValue(): String + fun formatted(): String } diff --git a/nebulosa-image-format/src/main/kotlin/nebulosa/image/format/ImageData.kt b/nebulosa-image-format/src/main/kotlin/nebulosa/image/format/ImageData.kt index feb827090..82fcaef1d 100644 --- a/nebulosa-image-format/src/main/kotlin/nebulosa/image/format/ImageData.kt +++ b/nebulosa-image-format/src/main/kotlin/nebulosa/image/format/ImageData.kt @@ -8,6 +8,9 @@ interface ImageData { val numberOfChannels: Int + val numberOfPixels + get() = width * height + val red: FloatArray val green: FloatArray diff --git a/nebulosa-image-format/src/main/kotlin/nebulosa/image/format/ImageRepresentation.kt b/nebulosa-image-format/src/main/kotlin/nebulosa/image/format/ImageRepresentation.kt new file mode 100644 index 000000000..67f8a0177 --- /dev/null +++ b/nebulosa-image-format/src/main/kotlin/nebulosa/image/format/ImageRepresentation.kt @@ -0,0 +1,12 @@ +package nebulosa.image.format + +interface ImageRepresentation : MutableList>, ImageSource, ImageSink { + + fun addFirst(hdu: Hdu<*>) + + fun addLast(hdu: Hdu<*>) + + fun removeFirst(): Hdu<*> + + fun removeLast(): Hdu<*> +} diff --git a/nebulosa-image-format/src/main/kotlin/nebulosa/image/format/ReadableHeader.kt b/nebulosa-image-format/src/main/kotlin/nebulosa/image/format/ReadableHeader.kt index 6eb0f0d0a..19f9a19eb 100644 --- a/nebulosa-image-format/src/main/kotlin/nebulosa/image/format/ReadableHeader.kt +++ b/nebulosa-image-format/src/main/kotlin/nebulosa/image/format/ReadableHeader.kt @@ -1,6 +1,6 @@ package nebulosa.image.format -interface ReadableHeader : Collection, ImageSink { +interface ReadableHeader : Collection { operator fun contains(key: String): Boolean { return any { it.key == key } diff --git a/nebulosa-image-format/src/main/kotlin/nebulosa/image/format/WritableHeader.kt b/nebulosa-image-format/src/main/kotlin/nebulosa/image/format/WritableHeader.kt index 07d105f77..72e18ca79 100644 --- a/nebulosa-image-format/src/main/kotlin/nebulosa/image/format/WritableHeader.kt +++ b/nebulosa-image-format/src/main/kotlin/nebulosa/image/format/WritableHeader.kt @@ -1,6 +1,6 @@ package nebulosa.image.format -interface WritableHeader : ImageSource { +interface WritableHeader { fun clear() diff --git a/nebulosa-image/src/main/kotlin/nebulosa/image/Float8bitsDataBuffer.kt b/nebulosa-image/src/main/kotlin/nebulosa/image/Float8bitsDataBuffer.kt index 6a965a92b..067469071 100644 --- a/nebulosa-image/src/main/kotlin/nebulosa/image/Float8bitsDataBuffer.kt +++ b/nebulosa-image/src/main/kotlin/nebulosa/image/Float8bitsDataBuffer.kt @@ -5,12 +5,12 @@ import java.awt.image.DataBuffer @Suppress("ArrayInDataClass") data class Float8bitsDataBuffer( @JvmField val mono: Boolean, - @JvmField val r: FloatArray, // or gray. - @JvmField val g: FloatArray = r, - @JvmField val b: FloatArray = r, -) : DataBuffer(TYPE_FLOAT, if (mono) r.size else r.size + g.size + b.size) { + @JvmField val red: FloatArray, // or gray. + @JvmField val green: FloatArray = red, + @JvmField val blue: FloatArray = red, +) : DataBuffer(TYPE_FLOAT, if (mono) red.size else red.size + green.size + blue.size) { - @JvmField val data = arrayOf(r, g, b) + @JvmField val data = arrayOf(red, green, blue) @Suppress("NOTHING_TO_INLINE") private inline operator fun get(i: Int): Float { diff --git a/nebulosa-image/src/main/kotlin/nebulosa/image/Image.kt b/nebulosa-image/src/main/kotlin/nebulosa/image/Image.kt index 154fe3501..4f1ab7b0b 100644 --- a/nebulosa-image/src/main/kotlin/nebulosa/image/Image.kt +++ b/nebulosa-image/src/main/kotlin/nebulosa/image/Image.kt @@ -7,7 +7,7 @@ import nebulosa.image.algorithms.transform import nebulosa.image.algorithms.transformation.CfaPattern import nebulosa.image.algorithms.transformation.Debayer import nebulosa.image.algorithms.transformation.Grayscale -import nebulosa.image.format.Header +import nebulosa.image.format.* import okio.Sink import java.awt.color.ColorSpace import java.awt.image.* @@ -15,11 +15,21 @@ import kotlin.math.max import kotlin.math.min @Suppress("NOTHING_TO_INLINE") -class Image( - width: Int, height: Int, - val header: Header, val mono: Boolean, -) : BufferedImage(colorModel(mono), raster(width, height, mono), false, null) { +class Image internal constructor( + width: Int, height: Int, val mono: Boolean, + @JvmField val hdu: ImageHdu, +) : BufferedImage(colorModel(mono), raster(hdu, mono), false, null) { + constructor(width: Int, height: Int, header: ReadableHeader, mono: Boolean) + : this(width, height, mono, BasicImageHdu(width, height, if (mono) 1 else 3, header, FloatImageData(width, height, if (mono) 1 else 3))) + + constructor(width: Int, height: Int, header: ReadableHeader, red: FloatArray) + : this(width, height, true, BasicImageHdu(width, height, 1, header, FloatImageData(width, height, 1, red))) + + constructor(width: Int, height: Int, header: ReadableHeader, red: FloatArray, green: FloatArray, blue: FloatArray) + : this(width, height, false, BasicImageHdu(width, height, 3, header, FloatImageData(width, height, 3, red, green, blue))) + + @JvmField val header = hdu.header @JvmField val numberOfChannels = if (mono) 1 else 3 @JvmField val stride = width @JvmField val buffer = raster.dataBuffer as Float8bitsDataBuffer @@ -28,14 +38,14 @@ class Image( inline val data get() = buffer.data - inline val r - get() = buffer.r + inline val red + get() = buffer.red - inline val g - get() = buffer.g + inline val green + get() = buffer.green - inline val b - get() = buffer.b + inline val blue + get() = buffer.blue inline fun indexAt(x: Int, y: Int): Int { return y * stride + x @@ -58,7 +68,7 @@ class Image( } inline fun writeRed(index: Int, color: Float) { - r[index] = color + red[index] = color } inline fun writeRed(x: Int, y: Int, color: Float) { @@ -66,7 +76,7 @@ class Image( } inline fun writeGreen(index: Int, color: Float) { - g[index] = color + green[index] = color } inline fun writeGreen(x: Int, y: Int, color: Float) { @@ -74,7 +84,7 @@ class Image( } inline fun writeBlue(index: Int, color: Float) { - b[index] = color + blue[index] = color } inline fun writeBlue(x: Int, y: Int, color: Float) { @@ -82,11 +92,11 @@ class Image( } inline fun writeGray(index: Int, color: Float) { - r[index] = color + red[index] = color if (!mono) { - g[index] = color - b[index] = color + green[index] = color + blue[index] = color } } @@ -111,7 +121,7 @@ class Image( } inline fun readRed(index: Int): Float { - return r[index] + return red[index] } inline fun readRed(x: Int, y: Int): Float { @@ -119,7 +129,7 @@ class Image( } inline fun readGreen(index: Int): Float { - return g[index] + return green[index] } inline fun readGreen(x: Int, y: Int): Float { @@ -127,7 +137,7 @@ class Image( } inline fun readBlue(index: Int): Float { - return b[index] + return blue[index] } inline fun readBlue(x: Int, y: Int): Float { @@ -135,52 +145,17 @@ class Image( } inline fun readGray(index: Int): Float { - return if (mono) r[index] else (r[index] + g[index] + b[index]) / 3f + return if (mono) red[index] else (red[index] + green[index] + blue[index]) / 3f } inline fun readGrayBT709(index: Int): Float { - return if (mono) r[index] else (r[index] * 0.2125f + g[index] * 0.7154f + b[index] * 0.0721f) + return if (mono) red[index] else (red[index] * 0.2125f + green[index] * 0.7154f + blue[index] * 0.0721f) } inline fun readGray(x: Int, y: Int): Float { return readGray(indexAt(x, y)) } - fun writeImageData(channel: ImageChannel, data: ImageData) { - var idx = 0 - - when (data.bitpix) { - Bitpix.BYTE -> data.read { - while (it.hasRemaining()) { - write(idx++, channel, (it.get().toInt() and 0xFF) / 255f) - } - } - Bitpix.SHORT -> data.read { - while (it.hasRemaining()) { - write(idx++, channel, (it.getShort().toInt() + 32768) / 65535f) - } - } - Bitpix.INTEGER -> data.read { - while (it.hasRemaining()) { - write(idx++, channel, ((it.getInt().toLong() + 2147483648) / 4294967295.0).toFloat()) - } - } - Bitpix.FLOAT -> data.read { - while (it.hasRemaining()) { - write(idx++, channel, it.getFloat()) - } - } - Bitpix.DOUBLE -> data.read { - while (it.hasRemaining()) { - write(idx++, channel, it.getDouble().toFloat()) - } - } - Bitpix.LONG -> { - throw UnsupportedOperationException("BITPIX 64-bit integer is not supported") - } - } - } - fun writeTo(output: IntArray) { var idx = 0 @@ -189,13 +164,13 @@ class Image( val index = indexAt(x, y) if (mono) { - val c = (r[index] * 255f).toInt() + val c = (red[index] * 255f).toInt() val p = 0xFF000000.toInt() or (c shl 16) or (c shl 8) or c output[idx++] = p } else { - val ri = (r[index] * 255f).toInt() - val gi = (g[index] * 255f).toInt() - val bi = (b[index] * 255f).toInt() + val ri = (red[index] * 255f).toInt() + val gi = (green[index] * 255f).toInt() + val bi = (blue[index] * 255f).toInt() val p = 0xFF000000.toInt() or (ri shl 16) or (gi shl 8) or bi output[idx++] = p } @@ -203,44 +178,34 @@ class Image( } } - fun writeTo(sink: Sink) { - hdu().write(sink) - } - - fun hdu(): Hdu { - return ImageHdu(header, Array(numberOfChannels) { FloatImageData(width, height, data[it]) }) + fun writeTo(sink: Sink, format: ImageFormat) { + format.write(sink, listOf(hdu)) } /** * Creates a new [Image] and returns a mono version of this image. */ fun mono(grayscale: Grayscale = Grayscale.BT709): Image { - val image = Image(width, height, header.clone(), true) - - if (mono) { - r.copyInto(image.r) + return if (mono) { + Image(width, height, FitsHeader(header), red.clone()) + } else { + grayscale.transform(this) } - - return grayscale.transform(image) } /** * Creates a new [Image] and returns a RGB version of this image. */ fun color(): Image { - val image = Image(width, height, header.clone(), false) + val newHeader = FitsHeader(header) - if (mono) { - r.copyInto(image.r) - r.copyInto(image.g) - r.copyInto(image.b) + val image = if (mono) { + Image(width, height, newHeader, red.clone(), red.clone(), red.clone()) } else { - r.copyInto(image.r) - g.copyInto(image.g) - b.copyInto(image.b) + Image(width, height, newHeader, red.clone(), green.clone(), blue.clone()) } - with(image.header) { + with(newHeader) { add(FitsKeywordDictionary.NAXIS, 3) add(FitsKeywordDictionary.NAXIS1, width) add(FitsKeywordDictionary.NAXIS2, height) @@ -254,12 +219,12 @@ class Image( return hdu.width == width && hdu.height == height && (isMono(hdu) || !debayer) == this.mono } - fun canLoad(fits: Fits, debayer: Boolean = true): Boolean { - return canLoad(fits.filterIsInstance().first(), debayer) + fun canLoad(image: ImageRepresentation, debayer: Boolean = true): Boolean { + return canLoad(image.filterIsInstance().first(), debayer) } - fun load(fits: Fits, debayer: Boolean = true): Image? { - return load(fits.filterIsInstance().first(), debayer) + fun load(image: ImageRepresentation, debayer: Boolean = true): Image? { + return load(image.filterIsInstance().first(), debayer) } fun load(hdu: ImageHdu, debayer: Boolean = true): Image? { @@ -296,16 +261,26 @@ class Image( } @JvmStatic - fun open( - fits: Fits, - debayer: Boolean = true, - ) = open(fits.filterIsInstance().first(), debayer) + internal fun raster(width: Int, height: Int, mono: Boolean, red: FloatArray, green: FloatArray, blue: FloatArray): WritableRaster { + val pixelStride = if (mono) 1 else 3 + val bandOffsets = if (mono) intArrayOf(0) else intArrayOf(0, 1, 2) + val sampleModel = PixelInterleavedSampleModel(DataBuffer.TYPE_BYTE, width, height, pixelStride, width * pixelStride, bandOffsets) + val buffer = Float8bitsDataBuffer(mono, red, green, blue) + return Raster.createWritableRaster(sampleModel, buffer, null) + } + + @JvmStatic + internal fun raster(hdu: ImageHdu, mono: Boolean): WritableRaster { + return raster(hdu.width, hdu.height, hdu.isMono || mono, hdu.data.red, hdu.data.green, hdu.data.blue) + } + + @JvmStatic + fun open(image: ImageRepresentation, debayer: Boolean = true): Image { + return open(image.filterIsInstance().first(), debayer) + } @JvmStatic - fun open( - hdu: ImageHdu, - debayer: Boolean = true, - ): Image { + fun open(hdu: ImageHdu, debayer: Boolean = true): Image { val mono = isMono(hdu) || !debayer val image = Image(hdu.width, hdu.height, hdu.header, mono) load(image, hdu, debayer) @@ -314,8 +289,26 @@ class Image( @JvmStatic private fun load(image: Image, hdu: ImageHdu, debayer: Boolean) { - val pixels = hdu.data + require(image.width == hdu.width) + require(image.height == hdu.height) + + if (image.mono || !debayer) { + hdu.data.red.copyInto(image.red) + } else { + hdu.data.red.copyInto(image.red) + hdu.data.green.copyInto(image.green) + hdu.data.blue.copyInto(image.blue) + + val bayer = CfaPattern.from(image.header) + + if (bayer != null) { + Debayer(bayer).transform(image) + } + } + } + @JvmStatic + private fun load(image: Image, debayer: Boolean) { fun rescaling() { for (p in 0 until image.numberOfChannels) { val minMax = floatArrayOf(Float.MAX_VALUE, Float.MIN_VALUE) @@ -340,19 +333,14 @@ class Image( // TODO: DATA[i] = BZERO + BSCALE * DATA[i] // Mono. - if (hdu.size == 1) { - val bayer = CfaPattern.from(hdu.header) - image.writeImageData(ImageChannel.GRAY, pixels[0]) - + if (image.mono) { rescaling() + } else { + val bayer = CfaPattern.from(image.header) if (debayer && bayer != null) { Debayer(bayer).transform(image) } - } else { - for (channel in ImageChannel.RGB) { - image.writeImageData(channel, pixels[channel.offset]) - } rescaling() } @@ -386,11 +374,11 @@ class Image( val rgb = bufferedImage.getRGB(x, y) if (mono) { - image.r[idx++] = (rgb and 0xff) / 255f + image.red[idx++] = (rgb and 0xff) / 255f } else { - image.r[idx] = (rgb ushr 16 and 0xff) / 255f - image.g[idx] = (rgb ushr 8 and 0xff) / 255f - image.b[idx++] = (rgb and 0xff) / 255f + image.red[idx] = (rgb ushr 16 and 0xff) / 255f + image.green[idx] = (rgb ushr 8 and 0xff) / 255f + image.blue[idx++] = (rgb and 0xff) / 255f } } } @@ -405,7 +393,7 @@ class Image( @JvmStatic fun isMono(hdu: ImageHdu): Boolean { - return hdu.size == 1 && !canDebayer(hdu) + return hdu.isMono && !canDebayer(hdu) } inline fun Image.forEach( diff --git a/nebulosa-image/src/main/kotlin/nebulosa/image/algorithms/transformation/Debayer.kt b/nebulosa-image/src/main/kotlin/nebulosa/image/algorithms/transformation/Debayer.kt index 7c34532d1..75d036ee9 100644 --- a/nebulosa-image/src/main/kotlin/nebulosa/image/algorithms/transformation/Debayer.kt +++ b/nebulosa-image/src/main/kotlin/nebulosa/image/algorithms/transformation/Debayer.kt @@ -31,7 +31,7 @@ data class Debayer(private val pattern: CfaPattern? = null) : TransformAlgorithm val startIndex = rowIndex - width for (x in 0 until width) { - source.r[startIndex + x] = cache[cacheIndex][x] + source.red[startIndex + x] = cache[cacheIndex][x] } } } @@ -98,8 +98,8 @@ data class Debayer(private val pattern: CfaPattern? = null) : TransformAlgorithm } cache[y and 1][x] = rgbValues[0] / rgbCounters[0] - source.g[index] = rgbValues[1] / rgbCounters[1] - source.b[index] = rgbValues[2] / rgbCounters[2] + source.green[index] = rgbValues[1] / rgbCounters[1] + source.blue[index] = rgbValues[2] / rgbCounters[2] } copyCacheToRedChannel(rowIndex, y) diff --git a/nebulosa-image/src/main/kotlin/nebulosa/image/algorithms/transformation/Grayscale.kt b/nebulosa-image/src/main/kotlin/nebulosa/image/algorithms/transformation/Grayscale.kt index 50cb8ba7c..37615d79b 100644 --- a/nebulosa-image/src/main/kotlin/nebulosa/image/algorithms/transformation/Grayscale.kt +++ b/nebulosa-image/src/main/kotlin/nebulosa/image/algorithms/transformation/Grayscale.kt @@ -1,5 +1,6 @@ package nebulosa.image.algorithms.transformation +import nebulosa.fits.FitsHeader import nebulosa.fits.FitsKeywordDictionary import nebulosa.image.Image import nebulosa.image.algorithms.TransformAlgorithm @@ -15,13 +16,14 @@ data class Grayscale( override fun transform(source: Image): Image { if (source.mono) return source - val header = source.header.clone() - header.add(FitsKeywordDictionary.NAXIS, 2) - header.delete(FitsKeywordDictionary.NAXIS3) - val result = Image(source.width, source.height, header, true) + val newHeader = FitsHeader(source.header) + newHeader.add(FitsKeywordDictionary.NAXIS, 2) + newHeader.delete(FitsKeywordDictionary.NAXIS3) - for (i in source.r.indices) { - result.r[i] = max(0f, min(red * source.r[i] + green * source.g[i] + blue * source.b[i], 1f)) + val result = Image(source.width, source.height, newHeader, true) + + for (i in source.red.indices) { + result.red[i] = max(0f, min(red * source.red[i] + green * source.green[i] + blue * source.blue[i], 1f)) } return result diff --git a/nebulosa-image/src/main/kotlin/nebulosa/image/algorithms/transformation/Invert.kt b/nebulosa-image/src/main/kotlin/nebulosa/image/algorithms/transformation/Invert.kt index daf96a810..327840db6 100644 --- a/nebulosa-image/src/main/kotlin/nebulosa/image/algorithms/transformation/Invert.kt +++ b/nebulosa-image/src/main/kotlin/nebulosa/image/algorithms/transformation/Invert.kt @@ -6,11 +6,11 @@ import nebulosa.image.algorithms.TransformAlgorithm data object Invert : TransformAlgorithm { override fun transform(source: Image): Image { - for (i in source.r.indices) source.r[i] = 1f - source.r[i] + for (i in source.red.indices) source.red[i] = 1f - source.red[i] if (!source.mono) { - for (i in source.g.indices) source.g[i] = 1f - source.g[i] - for (i in source.b.indices) source.b[i] = 1f - source.b[i] + for (i in source.green.indices) source.green[i] = 1f - source.green[i] + for (i in source.blue.indices) source.blue[i] = 1f - source.blue[i] } return source diff --git a/nebulosa-image/src/main/kotlin/nebulosa/image/algorithms/transformation/ScreenTransformFunction.kt b/nebulosa-image/src/main/kotlin/nebulosa/image/algorithms/transformation/ScreenTransformFunction.kt index 668eedb17..8a09f240b 100644 --- a/nebulosa-image/src/main/kotlin/nebulosa/image/algorithms/transformation/ScreenTransformFunction.kt +++ b/nebulosa-image/src/main/kotlin/nebulosa/image/algorithms/transformation/ScreenTransformFunction.kt @@ -40,12 +40,12 @@ data class ScreenTransformFunction( lut.fill(Float.NaN) - for (i in source.r.indices) { - source.r[i] = source.r[i].df(midtone, shadow, highlight, k1, k2) + for (i in source.red.indices) { + source.red[i] = source.red[i].df(midtone, shadow, highlight, k1, k2) if (!source.mono) { - source.g[i] = source.g[i].df(midtone, shadow, highlight, k1, k2) - source.b[i] = source.b[i].df(midtone, shadow, highlight, k1, k2) + source.green[i] = source.green[i].df(midtone, shadow, highlight, k1, k2) + source.blue[i] = source.blue[i].df(midtone, shadow, highlight, k1, k2) } } diff --git a/nebulosa-image/src/main/kotlin/nebulosa/image/algorithms/transformation/SubFrame.kt b/nebulosa-image/src/main/kotlin/nebulosa/image/algorithms/transformation/SubFrame.kt index 5f931f097..4a9e147b0 100644 --- a/nebulosa-image/src/main/kotlin/nebulosa/image/algorithms/transformation/SubFrame.kt +++ b/nebulosa-image/src/main/kotlin/nebulosa/image/algorithms/transformation/SubFrame.kt @@ -1,5 +1,6 @@ package nebulosa.image.algorithms.transformation +import nebulosa.fits.FitsHeader import nebulosa.fits.FitsKeywordDictionary import nebulosa.image.Image import nebulosa.image.algorithms.TransformAlgorithm @@ -20,10 +21,10 @@ data class SubFrame( require(x + width <= source.width) { "subframe.width < source.width: ${x + width} > ${source.width}" } require(y + height <= source.height) { "subframe.height < source.height: ${y + height} > ${source.height}" } - val header = source.header.clone() - header.add(FitsKeywordDictionary.NAXIS1, width) - header.add(FitsKeywordDictionary.NAXIS2, height) - val subframe = Image(width, height, header, source.mono) + val newHeader = FitsHeader(source.header) + newHeader.add(FitsKeywordDictionary.NAXIS1, width) + newHeader.add(FitsKeywordDictionary.NAXIS2, height) + val subframe = Image(width, height, newHeader, source.mono) var index = 0 diff --git a/nebulosa-image/src/main/kotlin/nebulosa/image/algorithms/transformation/SubtractiveChromaticNoiseReduction.kt b/nebulosa-image/src/main/kotlin/nebulosa/image/algorithms/transformation/SubtractiveChromaticNoiseReduction.kt index 6568418ca..06619c2c4 100644 --- a/nebulosa-image/src/main/kotlin/nebulosa/image/algorithms/transformation/SubtractiveChromaticNoiseReduction.kt +++ b/nebulosa-image/src/main/kotlin/nebulosa/image/algorithms/transformation/SubtractiveChromaticNoiseReduction.kt @@ -34,7 +34,7 @@ data class SubtractiveChromaticNoiseReduction( val p0 = (channel.offset + 2) % 3 val p1 = (channel.offset + 1) % 3 - for (i in source.r.indices) { + for (i in source.red.indices) { source.data[channel.offset][i] = protectionMethod .compute(source.data[p0][i], source.data[p1][i], source.data[channel.offset][i], amount) } diff --git a/nebulosa-wcs/src/main/kotlin/nebulosa/wcs/WCS.kt b/nebulosa-wcs/src/main/kotlin/nebulosa/wcs/WCS.kt index 542d56297..d2b977380 100644 --- a/nebulosa-wcs/src/main/kotlin/nebulosa/wcs/WCS.kt +++ b/nebulosa-wcs/src/main/kotlin/nebulosa/wcs/WCS.kt @@ -23,7 +23,7 @@ class WCS(header: ReadableHeader) : Closeable { val card = headerIter.next() if (isKeywordValid(card.key)) { - headerText.append(card.formattedValue()) + headerText.append(card.formatted()) keyCount++ } } diff --git a/nebulosa-xisf/src/main/kotlin/nebulosa/xisf/Xisf.kt b/nebulosa-xisf/src/main/kotlin/nebulosa/xisf/Xisf.kt new file mode 100644 index 000000000..30f2159d8 --- /dev/null +++ b/nebulosa-xisf/src/main/kotlin/nebulosa/xisf/Xisf.kt @@ -0,0 +1,25 @@ +package nebulosa.xisf + +import nebulosa.image.format.Hdu +import nebulosa.image.format.ImageRepresentation +import nebulosa.io.SeekableSource +import okio.Sink +import java.util.* + +/** + * Represents a XISF image. + */ +open class Xisf : LinkedList>, ImageRepresentation { + + constructor() : super() + + constructor(hdus: Collection>) : super(hdus) + + final override fun read(source: SeekableSource) { + addAll(XisfFormat.read(source)) + } + + final override fun write(sink: Sink) { + XisfFormat.write(sink, this) + } +} diff --git a/nebulosa-xisf/src/main/kotlin/nebulosa/xisf/XisfFormat.kt b/nebulosa-xisf/src/main/kotlin/nebulosa/xisf/XisfFormat.kt index 6955d73d4..5806bf3c2 100644 --- a/nebulosa-xisf/src/main/kotlin/nebulosa/xisf/XisfFormat.kt +++ b/nebulosa-xisf/src/main/kotlin/nebulosa/xisf/XisfFormat.kt @@ -17,30 +17,30 @@ import okio.Sink data object XisfFormat : ImageFormat { override fun read(source: SeekableSource): List { - val buffer = Buffer() - - source.read(buffer, 8) // XISF0100 - buffer.readString(Charsets.US_ASCII) - - // Header length (4) + reserved (4) - source.read(buffer, 4 + 4) - val headerLength = buffer.readIntLe().toLong() - buffer.skip(4) // reserved - - // XISF Header. - source.read(buffer, headerLength) - val stream = XisfHeaderInputStream(buffer.inputStream()) - val hdus = ArrayList(2) - - while (true) { - val header = stream.read() ?: break - - when (header) { - is XisfMonolithicFileHeader.Image -> hdus.add(XisfMonolithicFileHeaderImageHdu(header, source)) + return Buffer().use { buffer -> + source.read(buffer, 8) // XISF0100 + buffer.readString(Charsets.US_ASCII) + + // Header length (4) + reserved (4) + source.read(buffer, 4 + 4) + val headerLength = buffer.readIntLe().toLong() + buffer.skip(4) // reserved + + // XISF Header. + source.read(buffer, headerLength) + val stream = XisfHeaderInputStream(buffer.inputStream()) + val hdus = ArrayList(2) + + while (true) { + val header = stream.read() ?: break + + when (header) { + is XisfMonolithicFileHeader.Image -> hdus.add(XisfMonolithicFileHeaderImageHdu(header, source)) + } } - } - return hdus + hdus + } } override fun write(sink: Sink, hdus: Iterable>) { diff --git a/nebulosa-xisf/src/main/kotlin/nebulosa/xisf/XisfHeader.kt b/nebulosa-xisf/src/main/kotlin/nebulosa/xisf/XisfHeader.kt deleted file mode 100644 index 0b4dbc26c..000000000 --- a/nebulosa-xisf/src/main/kotlin/nebulosa/xisf/XisfHeader.kt +++ /dev/null @@ -1,46 +0,0 @@ -package nebulosa.xisf - -import nebulosa.image.format.AbstractHeader -import nebulosa.image.format.Header -import nebulosa.image.format.HeaderCard -import nebulosa.io.SeekableSource -import okio.Sink - -open class XisfHeader : AbstractHeader { - - constructor() : super() - - constructor(cards: Collection) : super(cards) - - override fun readOnly(): Header { - TODO("Not yet implemented") - } - - override fun clone(): Header { - TODO("Not yet implemented") - } - - override fun write(sink: Sink) { - TODO("Not yet implemented") - } - - override fun add(key: String, value: Boolean, comment: String) { - TODO("Not yet implemented") - } - - override fun add(key: String, value: Int, comment: String) { - TODO("Not yet implemented") - } - - override fun add(key: String, value: Double, comment: String) { - TODO("Not yet implemented") - } - - override fun add(key: String, value: String, comment: String) { - TODO("Not yet implemented") - } - - override fun read(source: SeekableSource) { - TODO("Not yet implemented") - } -} diff --git a/nebulosa-xisf/src/main/kotlin/nebulosa/xisf/XisfMonolithicFileHeaderImageData.kt b/nebulosa-xisf/src/main/kotlin/nebulosa/xisf/XisfMonolithicFileHeaderImageData.kt index f3aa1e649..6128dfe3c 100644 --- a/nebulosa-xisf/src/main/kotlin/nebulosa/xisf/XisfMonolithicFileHeaderImageData.kt +++ b/nebulosa-xisf/src/main/kotlin/nebulosa/xisf/XisfMonolithicFileHeaderImageData.kt @@ -24,8 +24,6 @@ internal data class XisfMonolithicFileHeaderImageData( override val numberOfChannels get() = image.numberOfChannels - private val numberOfPixels = width * height - init { val uncompressedSize = image.compressionFormat?.uncompressedSize ?: image.size val expectedSize = numberOfChannels * numberOfPixels * image.sampleFormat.byteLength diff --git a/nebulosa-xisf/src/main/kotlin/nebulosa/xisf/XisfMonolithicFileHeaderImageHdu.kt b/nebulosa-xisf/src/main/kotlin/nebulosa/xisf/XisfMonolithicFileHeaderImageHdu.kt index a3e802402..f238183bc 100644 --- a/nebulosa-xisf/src/main/kotlin/nebulosa/xisf/XisfMonolithicFileHeaderImageHdu.kt +++ b/nebulosa-xisf/src/main/kotlin/nebulosa/xisf/XisfMonolithicFileHeaderImageHdu.kt @@ -1,5 +1,6 @@ package nebulosa.xisf +import nebulosa.fits.FitsHeader import nebulosa.image.format.ImageHdu import nebulosa.io.SeekableSource @@ -17,7 +18,7 @@ internal data class XisfMonolithicFileHeaderImageHdu( override val numberOfChannels get() = image.numberOfChannels - override val header = XisfHeader(image.keywords) + override val header = FitsHeader(image.keywords) override val data = XisfMonolithicFileHeaderImageData(image, source) } diff --git a/nebulosa-xisf/src/main/kotlin/nebulosa/xisf/XisfPath.kt b/nebulosa-xisf/src/main/kotlin/nebulosa/xisf/XisfPath.kt index e34789821..1ec8dadfa 100644 --- a/nebulosa-xisf/src/main/kotlin/nebulosa/xisf/XisfPath.kt +++ b/nebulosa-xisf/src/main/kotlin/nebulosa/xisf/XisfPath.kt @@ -6,7 +6,7 @@ import java.io.Closeable import java.io.File import java.nio.file.Path -class XisfPath(val path: Path) : Closeable { +class XisfPath(val path: Path) : Xisf(), Closeable { private val source = path.seekableSource() private val sink = path.seekableSink() @@ -16,6 +16,11 @@ class XisfPath(val path: Path) : Closeable { constructor(path: String) : this(Path.of(path)) fun read() { + read(source) + } + + fun write() { + write(sink) } override fun close() { From e67b8b8cc4449874d0acf85c9d52e4bb52b1de8e Mon Sep 17 00:00:00 2001 From: tiagohm Date: Mon, 25 Mar 2024 23:51:14 -0300 Subject: [PATCH 03/15] [api]: Fix position of seekable Sink and Source --- nebulosa-io/src/main/kotlin/nebulosa/io/ByteArraySink.kt | 4 +++- nebulosa-io/src/main/kotlin/nebulosa/io/ByteArraySource.kt | 4 +++- nebulosa-io/src/main/kotlin/nebulosa/io/ByteBufferSink.kt | 4 +++- nebulosa-io/src/main/kotlin/nebulosa/io/ByteBufferSource.kt | 4 +++- .../src/main/kotlin/nebulosa/io/RandomAccessFileSink.kt | 3 ++- .../src/main/kotlin/nebulosa/io/RandomAccessFileSource.kt | 3 ++- 6 files changed, 16 insertions(+), 6 deletions(-) diff --git a/nebulosa-io/src/main/kotlin/nebulosa/io/ByteArraySink.kt b/nebulosa-io/src/main/kotlin/nebulosa/io/ByteArraySink.kt index 8857d28cd..3f21402a8 100644 --- a/nebulosa-io/src/main/kotlin/nebulosa/io/ByteArraySink.kt +++ b/nebulosa-io/src/main/kotlin/nebulosa/io/ByteArraySink.kt @@ -29,13 +29,15 @@ internal class ByteArraySink( @Synchronized override fun seek(position: Long) { val newPos = if (position < 0) byteCount + position else position - this.position = max(0L, min(newPos, byteCount - 1L)) + this.position = max(0L, min(newPos, byteCount.toLong())) } @Synchronized override fun write(source: Buffer, byteCount: Long) { if (byteCount == 0L) return + if (exhausted) throw IllegalStateException("exhausted") + var remaining = byteCount while (remaining > 0) { diff --git a/nebulosa-io/src/main/kotlin/nebulosa/io/ByteArraySource.kt b/nebulosa-io/src/main/kotlin/nebulosa/io/ByteArraySource.kt index 38abe68f4..6c25cfe1b 100644 --- a/nebulosa-io/src/main/kotlin/nebulosa/io/ByteArraySource.kt +++ b/nebulosa-io/src/main/kotlin/nebulosa/io/ByteArraySource.kt @@ -28,11 +28,13 @@ internal class ByteArraySource( @Synchronized override fun seek(position: Long) { val newPos = if (position < 0) byteCount + position else position - this.position = max(0L, min(newPos, byteCount - 1L)) + this.position = max(0L, min(newPos, byteCount.toLong())) } @Synchronized override fun read(sink: Buffer, byteCount: Long): Long { + if (exhausted) throw IllegalStateException("exhausted") + return sink.readAndWriteUnsafe(cursor).use { timeout.throwIfReached() diff --git a/nebulosa-io/src/main/kotlin/nebulosa/io/ByteBufferSink.kt b/nebulosa-io/src/main/kotlin/nebulosa/io/ByteBufferSink.kt index 409717873..f94ccdd58 100644 --- a/nebulosa-io/src/main/kotlin/nebulosa/io/ByteBufferSink.kt +++ b/nebulosa-io/src/main/kotlin/nebulosa/io/ByteBufferSink.kt @@ -33,13 +33,15 @@ internal class ByteBufferSink( @Synchronized override fun seek(position: Long) { val newPos = if (position < 0) byteCount + position else position - this.position = max(0L, min(newPos, byteCount - 1L)) + this.position = max(0L, min(newPos, byteCount.toLong())) } @Synchronized override fun write(source: Buffer, byteCount: Long) { if (byteCount == 0L) return + if (exhausted) throw IllegalStateException("exhausted") + var remaining = byteCount while (remaining > 0) { diff --git a/nebulosa-io/src/main/kotlin/nebulosa/io/ByteBufferSource.kt b/nebulosa-io/src/main/kotlin/nebulosa/io/ByteBufferSource.kt index 5c54ccca1..00bd45f8e 100644 --- a/nebulosa-io/src/main/kotlin/nebulosa/io/ByteBufferSource.kt +++ b/nebulosa-io/src/main/kotlin/nebulosa/io/ByteBufferSource.kt @@ -32,11 +32,13 @@ internal class ByteBufferSource( @Synchronized override fun seek(position: Long) { val newPos = if (position < 0) byteCount + position else position - this.position = max(0L, min(newPos, byteCount - 1L)) + this.position = max(0L, min(newPos, byteCount.toLong())) } @Synchronized override fun read(sink: Buffer, byteCount: Long): Long { + if (exhausted) throw IllegalStateException("exhausted") + return sink.readAndWriteUnsafe(cursor).use { timeout.throwIfReached() diff --git a/nebulosa-io/src/main/kotlin/nebulosa/io/RandomAccessFileSink.kt b/nebulosa-io/src/main/kotlin/nebulosa/io/RandomAccessFileSink.kt index 726de9fdd..cc30fa679 100644 --- a/nebulosa-io/src/main/kotlin/nebulosa/io/RandomAccessFileSink.kt +++ b/nebulosa-io/src/main/kotlin/nebulosa/io/RandomAccessFileSink.kt @@ -24,12 +24,13 @@ internal class RandomAccessFileSink( val size = file.length() if (size <= 0) return val newPos = if (position < 0) size + position else position - file.seek(max(0L, min(newPos, size - 1L))) + file.seek(max(0L, min(newPos, size))) } @Synchronized override fun write(source: Buffer, byteCount: Long) { if (!file.channel.isOpen) throw IllegalStateException("closed") + if (exhausted) throw IllegalStateException("exhausted") if (byteCount == 0L) return diff --git a/nebulosa-io/src/main/kotlin/nebulosa/io/RandomAccessFileSource.kt b/nebulosa-io/src/main/kotlin/nebulosa/io/RandomAccessFileSource.kt index 4c1d11f88..40f54ce37 100644 --- a/nebulosa-io/src/main/kotlin/nebulosa/io/RandomAccessFileSource.kt +++ b/nebulosa-io/src/main/kotlin/nebulosa/io/RandomAccessFileSource.kt @@ -25,12 +25,13 @@ internal class RandomAccessFileSource( val size = file.length() if (size <= 0) return val newPos = if (position < 0) size + position else position - file.seek(max(0L, min(newPos, size - 1L))) + file.seek(max(0L, min(newPos, size))) } @Synchronized override fun read(sink: Buffer, byteCount: Long): Long { if (!file.channel.isOpen) throw IllegalStateException("closed") + if (exhausted) throw IllegalStateException("exhausted") return sink.readAndWriteUnsafe(cursor).use { timeout.throwIfReached() From 7178f417bc0b1086dba12d1caa2f4a6fc201aa0d Mon Sep 17 00:00:00 2001 From: tiagohm Date: Tue, 26 Mar 2024 19:03:14 -0300 Subject: [PATCH 04/15] [api]: Fix FITS read --- .../alpaca/indi/device/cameras/ASCOMCamera.kt | 60 +- .../astap/plate/solving/AstapPlateSolver.kt | 30 +- .../src/main/kotlin/nebulosa/fits/Bitpix.kt | 66 +- .../src/main/kotlin/nebulosa/fits/Checksum.kt | 4 +- .../main/kotlin/nebulosa/fits/Compression.kt | 26 +- .../main/kotlin/nebulosa/fits/FitsElement.kt | 6 - .../main/kotlin/nebulosa/fits/FitsFormat.kt | 34 +- .../main/kotlin/nebulosa/fits/FitsHeader.kt | 4 +- .../kotlin/nebulosa/fits/FitsHeaderCard.kt | 9 +- .../nebulosa/fits/FitsHeaderCardFormatter.kt | 8 +- .../nebulosa/fits/FitsHeaderCardParser.kt | 24 +- .../nebulosa/fits/FitsHeaderCardType.kt | 2 +- .../kotlin/nebulosa/fits/FitsHeaderKey.kt | 15 + ...itsKeywordItem.kt => FitsHeaderKeyItem.kt} | 12 +- .../main/kotlin/nebulosa/fits/FitsHelper.kt | 46 +- .../main/kotlin/nebulosa/fits/FitsKeyword.kt | 4614 +++++++++++++++- .../nebulosa/fits/FitsKeywordDictionary.kt | 4621 ----------------- .../src/main/kotlin/nebulosa/fits/FitsPath.kt | 2 +- .../nebulosa/fits/HierarchKeyFormatter.kt | 5 +- .../nebulosa/fits/SeekableSourceImageData.kt | 9 +- .../nebulosa/fits/SeekableSourceImageHdu.kt | 15 - .../fits/StandardHierarchKeyFormatter.kt | 2 +- .../kotlin/FitsHeaderCardFormatterTest.kt | 30 + .../test/kotlin/FitsHeaderCardParserTest.kt | 50 + .../src/main/kotlin/nebulosa/image/Image.kt | 72 +- .../algorithms/transformation/Grayscale.kt | 6 +- .../algorithms/transformation/SubFrame.kt | 6 +- .../test/kotlin/ComputationAlgorithmTest.kt | 9 +- .../src/test/kotlin/TransformAlgorithmTest.kt | 100 +- .../nebulosa/plate/solving/PlateSolution.kt | 16 +- .../kotlin/nebulosa/test/FitsStringSpec.kt | 11 - .../watney/plate/solving/WatneyPlateSolver.kt | 26 +- .../src/main/kotlin/nebulosa/wcs/WCSUtil.kt | 8 +- .../xisf/XisfMonolithicFileHeaderImageData.kt | 17 +- .../xisf/XisfMonolithicFileHeaderImageHdu.kt | 13 +- .../src/main/kotlin/nebulosa/xisf/XisfPath.kt | 2 +- 36 files changed, 5003 insertions(+), 4977 deletions(-) delete mode 100644 nebulosa-fits/src/main/kotlin/nebulosa/fits/FitsElement.kt create mode 100644 nebulosa-fits/src/main/kotlin/nebulosa/fits/FitsHeaderKey.kt rename nebulosa-fits/src/main/kotlin/nebulosa/fits/{FitsKeywordItem.kt => FitsHeaderKeyItem.kt} (57%) delete mode 100644 nebulosa-fits/src/main/kotlin/nebulosa/fits/FitsKeywordDictionary.kt delete mode 100644 nebulosa-fits/src/main/kotlin/nebulosa/fits/SeekableSourceImageHdu.kt create mode 100644 nebulosa-fits/src/test/kotlin/FitsHeaderCardFormatterTest.kt create mode 100644 nebulosa-fits/src/test/kotlin/FitsHeaderCardParserTest.kt diff --git a/nebulosa-alpaca-indi/src/main/kotlin/nebulosa/alpaca/indi/device/cameras/ASCOMCamera.kt b/nebulosa-alpaca-indi/src/main/kotlin/nebulosa/alpaca/indi/device/cameras/ASCOMCamera.kt index 7716812b9..6e6236a38 100644 --- a/nebulosa-alpaca-indi/src/main/kotlin/nebulosa/alpaca/indi/device/cameras/ASCOMCamera.kt +++ b/nebulosa-alpaca-indi/src/main/kotlin/nebulosa/alpaca/indi/device/cameras/ASCOMCamera.kt @@ -10,7 +10,7 @@ import nebulosa.common.concurrency.latch.CountUpDownLatch import nebulosa.fits.Bitpix import nebulosa.fits.Fits import nebulosa.fits.FitsHeader -import nebulosa.fits.FitsKeywordDictionary +import nebulosa.fits.FitsKeyword import nebulosa.image.algorithms.transformation.CfaPattern import nebulosa.image.format.BasicImageHdu import nebulosa.image.format.FloatImageData @@ -651,41 +651,41 @@ data class ASCOMCamera( source.close() val header = FitsHeader() - header.add(FitsKeywordDictionary.SIMPLE, true) - header.add(FitsKeywordDictionary.BITPIX, -32) - header.add(FitsKeywordDictionary.NAXIS, if (numberOfChannels == 3) 3 else 2) - header.add(FitsKeywordDictionary.NAXIS1, width) - header.add(FitsKeywordDictionary.NAXIS2, height) - if (numberOfChannels == 3) header.add(FitsKeywordDictionary.NAXIS3, numberOfChannels) - header.add(FitsKeywordDictionary.EXTEND, true) - header.add(FitsKeywordDictionary.INSTRUME, name) - header.add(FitsKeywordDictionary.EXPTIME, 0.0) // TODO - header.add(FitsKeywordDictionary.CCD_TEMP, temperature) - header.add(FitsKeywordDictionary.PIXSIZEn.n(1), pixelSizeX) - header.add(FitsKeywordDictionary.PIXSIZEn.n(2), pixelSizeY) - header.add(FitsKeywordDictionary.XBINNING, binX) - header.add(FitsKeywordDictionary.YBINNING, binY) - header.add(FitsKeywordDictionary.XPIXSZ, pixelSizeX * binX) - header.add(FitsKeywordDictionary.YPIXSZ, pixelSizeY * binY) + header.add(FitsKeyword.SIMPLE, true) + header.add(FitsKeyword.BITPIX, -32) + header.add(FitsKeyword.NAXIS, if (numberOfChannels == 3) 3 else 2) + header.add(FitsKeyword.NAXIS1, width) + header.add(FitsKeyword.NAXIS2, height) + if (numberOfChannels == 3) header.add(FitsKeyword.NAXIS3, numberOfChannels) + header.add(FitsKeyword.EXTEND, true) + header.add(FitsKeyword.INSTRUME, name) + header.add(FitsKeyword.EXPTIME, 0.0) // TODO + header.add(FitsKeyword.CCD_TEMP, temperature) + header.add(FitsKeyword.PIXSIZEn.n(1), pixelSizeX) + header.add(FitsKeyword.PIXSIZEn.n(2), pixelSizeY) + header.add(FitsKeyword.XBINNING, binX) + header.add(FitsKeyword.YBINNING, binY) + header.add(FitsKeyword.XPIXSZ, pixelSizeX * binX) + header.add(FitsKeyword.YPIXSZ, pixelSizeY * binY) header.add("FRAME", frameType.description, "Frame Type") - header.add(FitsKeywordDictionary.IMAGETYP, "${frameType.description} Frame") + header.add(FitsKeyword.IMAGETYP, "${frameType.description} Frame") mount?.also { - header.add(FitsKeywordDictionary.TELESCOP, it.name) - header.add(FitsKeywordDictionary.SITELAT, it.latitude.toDegrees) - header.add(FitsKeywordDictionary.SITELONG, it.longitude.toDegrees) + header.add(FitsKeyword.TELESCOP, it.name) + header.add(FitsKeyword.SITELAT, it.latitude.toDegrees) + header.add(FitsKeyword.SITELONG, it.longitude.toDegrees) val center = Geoid.IERS2010.lonLat(it.longitude, it.latitude, it.elevation) val icrf = ICRF.equatorial(it.rightAscension, it.declination, epoch = CurrentTime, center = center) val raDec = icrf.equatorial() - header.add(FitsKeywordDictionary.OBJCTRA, raDec.longitude.normalized.formatHMS()) - header.add(FitsKeywordDictionary.OBJCTDEC, raDec.longitude.formatSignedDMS()) - header.add(FitsKeywordDictionary.RA, raDec.longitude.normalized.toDegrees) - header.add(FitsKeywordDictionary.DEC, raDec.longitude.toDegrees) - header.add(FitsKeywordDictionary.PIERSIDE, it.pierSide.name) - header.add(FitsKeywordDictionary.EQUINOX, 2000) - header.add(FitsKeywordDictionary.DATE_OBS, LocalDate.now().format(DateTimeFormatter.ISO_LOCAL_DATE_TIME)) - header.add(FitsKeywordDictionary.COMMENT, "Generated by Nebulosa via ASCOM") - header.add(FitsKeywordDictionary.GAIN, gain) + header.add(FitsKeyword.OBJCTRA, raDec.longitude.normalized.formatHMS()) + header.add(FitsKeyword.OBJCTDEC, raDec.longitude.formatSignedDMS()) + header.add(FitsKeyword.RA, raDec.longitude.normalized.toDegrees) + header.add(FitsKeyword.DEC, raDec.longitude.toDegrees) + header.add(FitsKeyword.PIERSIDE, it.pierSide.name) + header.add(FitsKeyword.EQUINOX, 2000) + header.add(FitsKeyword.DATE_OBS, LocalDate.now().format(DateTimeFormatter.ISO_LOCAL_DATE_TIME)) + header.add(FitsKeyword.COMMENT, "Generated by Nebulosa via ASCOM") + header.add(FitsKeyword.GAIN, gain) header.add("OFFSET", offset, "Offset") } diff --git a/nebulosa-astap/src/main/kotlin/nebulosa/astap/plate/solving/AstapPlateSolver.kt b/nebulosa-astap/src/main/kotlin/nebulosa/astap/plate/solving/AstapPlateSolver.kt index d9c6de13f..4edb44f8a 100644 --- a/nebulosa-astap/src/main/kotlin/nebulosa/astap/plate/solving/AstapPlateSolver.kt +++ b/nebulosa-astap/src/main/kotlin/nebulosa/astap/plate/solving/AstapPlateSolver.kt @@ -3,7 +3,7 @@ package nebulosa.astap.plate.solving import nebulosa.common.concurrency.cancel.CancellationToken import nebulosa.common.process.ProcessExecutor import nebulosa.fits.FitsHeader -import nebulosa.fits.FitsKeywordDictionary +import nebulosa.fits.FitsKeyword import nebulosa.image.Image import nebulosa.log.loggerFor import nebulosa.math.Angle @@ -94,20 +94,20 @@ class AstapPlateSolver(path: Path) : PlateSolver { val height = cdelt2 * dimensions[1].trim().toDouble() val header = FitsHeader() - header.add(FitsKeywordDictionary.CTYPE1, ctype1) - header.add(FitsKeywordDictionary.CTYPE2, ctype2) - header.add(FitsKeywordDictionary.CRPIX1, crpix1) - header.add(FitsKeywordDictionary.CRPIX2, crpix2) - header.add(FitsKeywordDictionary.CRVAL1, crval1) - header.add(FitsKeywordDictionary.CRVAL2, crval2) - header.add(FitsKeywordDictionary.CDELT1, cdelt1) - header.add(FitsKeywordDictionary.CDELT2, cdelt2) - header.add(FitsKeywordDictionary.CROTA1, crota1) - header.add(FitsKeywordDictionary.CROTA2, crota2) - header.add(FitsKeywordDictionary.CD1_1, cd11) - header.add(FitsKeywordDictionary.CD1_2, cd12) - header.add(FitsKeywordDictionary.CD2_1, cd21) - header.add(FitsKeywordDictionary.CD2_2, cd22) + header.add(FitsKeyword.CTYPE1, ctype1) + header.add(FitsKeyword.CTYPE2, ctype2) + header.add(FitsKeyword.CRPIX1, crpix1) + header.add(FitsKeyword.CRPIX2, crpix2) + header.add(FitsKeyword.CRVAL1, crval1) + header.add(FitsKeyword.CRVAL2, crval2) + header.add(FitsKeyword.CDELT1, cdelt1) + header.add(FitsKeyword.CDELT2, cdelt2) + header.add(FitsKeyword.CROTA1, crota1) + header.add(FitsKeyword.CROTA2, crota2) + header.add(FitsKeyword.CD1_1, cd11) + header.add(FitsKeyword.CD1_2, cd12) + header.add(FitsKeyword.CD2_1, cd21) + header.add(FitsKeyword.CD2_2, cd22) val solution = PlateSolution(true, crota2.deg, cdelt2.deg, crval1.deg, crval2.deg, width.deg, height.deg, header = header) diff --git a/nebulosa-fits/src/main/kotlin/nebulosa/fits/Bitpix.kt b/nebulosa-fits/src/main/kotlin/nebulosa/fits/Bitpix.kt index acf90c181..d5bc2e127 100644 --- a/nebulosa-fits/src/main/kotlin/nebulosa/fits/Bitpix.kt +++ b/nebulosa-fits/src/main/kotlin/nebulosa/fits/Bitpix.kt @@ -4,15 +4,13 @@ import nebulosa.image.format.HeaderCard import nebulosa.image.format.ReadableHeader import kotlin.math.abs -enum class Bitpix(val type: Class, val code: Int, val description: String) { - BYTE(Byte::class.javaPrimitiveType!!, 8, "bytes"), - SHORT(Short::class.javaPrimitiveType!!, 16, "16-bit integers"), - INTEGER(Int::class.javaPrimitiveType!!, 32, "32-bit integers"), - LONG(Long::class.javaPrimitiveType!!, 64, "64-bit integers"), - FLOAT(Float::class.javaPrimitiveType!!, -32, "32-bit floating point"), - DOUBLE(Double::class.javaPrimitiveType!!, -64, "64-bit floating point"); - - val card: HeaderCard = FitsHeaderCard.create(FitsKeywordDictionary.BITPIX, code) +enum class Bitpix(val type: Class, val code: Int) : HeaderCard by FitsHeaderCard.create(FitsKeyword.BITPIX, code) { + BYTE(Byte::class.javaPrimitiveType!!, 8), + SHORT(Short::class.javaPrimitiveType!!, 16), + INTEGER(Int::class.javaPrimitiveType!!, 32), + LONG(Long::class.javaPrimitiveType!!, 64), + FLOAT(Float::class.javaPrimitiveType!!, -32), + DOUBLE(Double::class.javaPrimitiveType!!, -64); @JvmField internal val byteLength = abs(code) / 8 @@ -20,39 +18,35 @@ enum class Bitpix(val type: Class, val code: Int, val description: S @JvmStatic fun from(header: ReadableHeader): Bitpix { - return of(header.getInt(FitsKeywordDictionary.BITPIX, 0)) + return of(header.getInt(FitsKeyword.BITPIX, 0)) } @JvmStatic - fun of(code: Int): Bitpix { - return when (code) { - 8 -> BYTE - 16 -> SHORT - 32 -> INTEGER - 64 -> LONG - -32 -> FLOAT - -64 -> DOUBLE - else -> throw IllegalArgumentException("invalid BITPIX code: $code") - } + fun of(code: Int) = when (code) { + 8 -> BYTE + 16 -> SHORT + 32 -> INTEGER + 64 -> LONG + -32 -> FLOAT + -64 -> DOUBLE + else -> throw IllegalArgumentException("invalid BITPIX code: $code") } @JvmStatic - fun of(type: Class<*>): Bitpix { - return when (type) { - Byte::class.javaPrimitiveType, - Byte::class.javaObjectType -> BYTE - Short::class.javaPrimitiveType, - Short::class.javaObjectType -> SHORT - Int::class.javaPrimitiveType, - Int::class.javaObjectType -> INTEGER - Long::class.javaPrimitiveType, - Long::class.javaObjectType -> LONG - Float::class.javaPrimitiveType, - Float::class.javaObjectType -> FLOAT - Double::class.javaPrimitiveType, - Double::class.javaObjectType -> DOUBLE - else -> throw IllegalArgumentException("no BITPIX for type: $type") - } + fun of(type: Class<*>) = when (type) { + Byte::class.javaPrimitiveType, + Byte::class.javaObjectType -> BYTE + Short::class.javaPrimitiveType, + Short::class.javaObjectType -> SHORT + Int::class.javaPrimitiveType, + Int::class.javaObjectType -> INTEGER + Long::class.javaPrimitiveType, + Long::class.javaObjectType -> LONG + Float::class.javaPrimitiveType, + Float::class.javaObjectType -> FLOAT + Double::class.javaPrimitiveType, + Double::class.javaObjectType -> DOUBLE + else -> throw IllegalArgumentException("no BITPIX for type: $type") } } } diff --git a/nebulosa-fits/src/main/kotlin/nebulosa/fits/Checksum.kt b/nebulosa-fits/src/main/kotlin/nebulosa/fits/Checksum.kt index 929dd73db..63de84647 100644 --- a/nebulosa-fits/src/main/kotlin/nebulosa/fits/Checksum.kt +++ b/nebulosa-fits/src/main/kotlin/nebulosa/fits/Checksum.kt @@ -1,6 +1,6 @@ package nebulosa.fits -enum class Checksum(hduType: HduType, valueType: ValueType, comment: String) : FitsKeyword { +enum class Checksum(hduType: HduType, valueType: ValueType, comment: String) : FitsHeaderKey { /** * The value field of the CHECKSUM keyword shall contain a 16 character string, left justified starting in column * 12, containing the ASCII encoded complement of the checksum of the FITS HDU (Header and Data Unit). The algorithm @@ -28,7 +28,7 @@ enum class Checksum(hduType: HduType, valueType: ValueType, comment: String) : F */ DATASUM(HduType.ANY, ValueType.STRING, "checksum of the data records"); - private val header = FitsKeywordItem(name, hduType, valueType, comment) + private val header = FitsHeaderKeyItem(name, hduType, valueType, comment) override val key get() = header.key diff --git a/nebulosa-fits/src/main/kotlin/nebulosa/fits/Compression.kt b/nebulosa-fits/src/main/kotlin/nebulosa/fits/Compression.kt index f092ee24c..c4beafe02 100644 --- a/nebulosa-fits/src/main/kotlin/nebulosa/fits/Compression.kt +++ b/nebulosa-fits/src/main/kotlin/nebulosa/fits/Compression.kt @@ -2,8 +2,8 @@ package nebulosa.fits enum class Compression( hduType: HduType, valueType: ValueType, comment: String, - val keyword: FitsKeyword? = null, -) : FitsKeyword { + val keyword: FitsHeaderKey? = null, +) : FitsHeaderKey { /** * (required keyword) This keyword must have the logical value T. The value field of this keyword shall be ’T’ to * indicate that the FITS binary table extension contains a compressed BINTABLE, and that logically this extension @@ -30,19 +30,19 @@ enum class Compression( * (required keyword) The value field of this keyword shall contain an integer that gives the value of the BITPIX * keyword in the uncompressed FITS image. 1 */ - ZBITPIX(HduType.ANY, ValueType.INTEGER, "", FitsKeywordDictionary.BITPIX), + ZBITPIX(HduType.ANY, ValueType.INTEGER, "", FitsKeyword.BITPIX), /** * (required keyword) The value field of this keyword shall contain an integer that gives the value of the NAXIS * keyword in the uncompressed FITS image. */ - ZNAXIS(HduType.ANY, ValueType.INTEGER, "", FitsKeywordDictionary.NAXIS), + ZNAXIS(HduType.ANY, ValueType.INTEGER, "", FitsKeyword.NAXIS), /** * (required keywords) The value field of these keywords shall contain a positive integer that gives the value of * the NAXISn keywords in the uncompressed FITS image. */ - ZNAXISn(HduType.ANY, ValueType.INTEGER, "", FitsKeywordDictionary.NAXISn), + ZNAXISn(HduType.ANY, ValueType.INTEGER, "", FitsKeyword.NAXISn), /** * (optional keywords) The value of these indexed keywords (where n ranges from 1 to ZNAXIS ) shall contain a @@ -89,7 +89,7 @@ enum class Compression( * identical copy of the original FITS file when the image is uncompressed.preserves the original SIMPLE keyword.may * only be used if the original uncompressed image was contained in the primary array of the FITS file. */ - ZSIMPLE(HduType.PRIMARY, ValueType.LOGICAL, "", FitsKeywordDictionary.SIMPLE), + ZSIMPLE(HduType.PRIMARY, ValueType.LOGICAL, "", FitsKeyword.SIMPLE), /** * The following optional keyword is defined to store a verbatim copy of the value and comment field of the @@ -98,7 +98,7 @@ enum class Compression( * keyword.may only be used if the original uncompressed image was contained in in IMAGE extension. */ - ZTENSION(HduType.ANY, ValueType.STRING, "", FitsKeywordDictionary.XTENSION), + ZTENSION(HduType.ANY, ValueType.STRING, "", FitsKeyword.XTENSION), /** * The following optional keyword is defined to store a verbatim copy of the value and comment field of the @@ -106,7 +106,7 @@ enum class Compression( * identical copy of the original FITS file when the image is uncompressed.preserves the original EXTEND keyword.may * only be used if the original uncompressed image was contained in the primary array of the FITS file. */ - ZEXTEND(HduType.PRIMARY, ValueType.LOGICAL, "", FitsKeywordDictionary.EXTEND), + ZEXTEND(HduType.PRIMARY, ValueType.LOGICAL, "", FitsKeyword.EXTEND), /** * The following optional keyword is defined to store a verbatim copy of the value and comment field of the @@ -115,7 +115,7 @@ enum class Compression( * keyword.may only be used if the original uncompressed image was contained in the primary array of the FITS file, */ @Deprecated("no blocksize other that 2880 may be used") - ZBLOCKED(HduType.PRIMARY, ValueType.LOGICAL, "", FitsKeywordDictionary.BLOCKED), + ZBLOCKED(HduType.PRIMARY, ValueType.LOGICAL, "", FitsKeyword.BLOCKED), /** * The following optional keyword is defined to store a verbatim copy of the value and comment field of the @@ -123,7 +123,7 @@ enum class Compression( * identical copy o f the original FITS file when the image is uncompressed.preserves the original PCOUNT * keyword.may only be used if the original uncompressed image was contained in in IMAGE extension. */ - ZPCOUNT(HduType.EXTENSION, ValueType.INTEGER, "", FitsKeywordDictionary.PCOUNT), + ZPCOUNT(HduType.EXTENSION, ValueType.INTEGER, "", FitsKeyword.PCOUNT), /** * The following optional keyword is defined to store a verbatim copy of the value and comment field of the @@ -131,7 +131,7 @@ enum class Compression( * identical copy o f the original FITS file when the image is uncompressed.preserves the original GCOUNT * keyword.may only be used if the original uncompressed image was contained in in IMAGE extension. */ - ZGCOUNT(HduType.EXTENSION, ValueType.INTEGER, "", FitsKeywordDictionary.GCOUNT), + ZGCOUNT(HduType.EXTENSION, ValueType.INTEGER, "", FitsKeyword.GCOUNT), /** * The following optional keyword is defined to store a verbatim copy of the value and comment field of the @@ -181,7 +181,7 @@ enum class Compression( * The value field of these keywords shall contain the character string values of the corresponding TFORMn keywords * that defines the data type of column n in the original uncompressed FITS table. */ - ZFORMn(HduType.ANY, ValueType.STRING, "", FitsKeywordDictionary.TFORMn), + ZFORMn(HduType.ANY, ValueType.STRING, "", FitsKeyword.TFORMn), /** * The value field of these keywords shall contain a charac- ter string giving the mnemonic name of the algorithm @@ -190,7 +190,7 @@ enum class Compression( */ ZCTYPn(HduType.ANY, ValueType.STRING, ""); - private val header = FitsKeywordItem(name, hduType, valueType, comment) + private val header = FitsHeaderKeyItem(name, hduType, valueType, comment) override val key get() = header.key diff --git a/nebulosa-fits/src/main/kotlin/nebulosa/fits/FitsElement.kt b/nebulosa-fits/src/main/kotlin/nebulosa/fits/FitsElement.kt deleted file mode 100644 index e09d6b651..000000000 --- a/nebulosa-fits/src/main/kotlin/nebulosa/fits/FitsElement.kt +++ /dev/null @@ -1,6 +0,0 @@ -package nebulosa.fits - -import nebulosa.image.format.ImageSink -import nebulosa.image.format.ImageSource - -interface FitsElement : ImageSource, ImageSink diff --git a/nebulosa-fits/src/main/kotlin/nebulosa/fits/FitsFormat.kt b/nebulosa-fits/src/main/kotlin/nebulosa/fits/FitsFormat.kt index fa59bc81a..f10ca0cf3 100644 --- a/nebulosa-fits/src/main/kotlin/nebulosa/fits/FitsFormat.kt +++ b/nebulosa-fits/src/main/kotlin/nebulosa/fits/FitsFormat.kt @@ -9,7 +9,7 @@ import okio.Sink import java.io.EOFException import kotlin.math.max -object FitsFormat : ImageFormat { +data object FitsFormat : ImageFormat { const val BLOCK_SIZE = 2880 @@ -21,7 +21,7 @@ object FitsFormat : ImageFormat { } fun isImageHdu(header: ReadableHeader) = - header.getBoolean(FitsKeywordDictionary.SIMPLE) || header.getStringOrNull(FitsKeywordDictionary.XTENSION) == "IMAGE" + header.getBoolean(FitsKeyword.SIMPLE) || header.getStringOrNull(FitsKeyword.XTENSION) == "IMAGE" fun readHeader(source: SeekableSource): FitsHeader { val header = FitsHeader() @@ -34,15 +34,19 @@ object FitsFormat : ImageFormat { if (source.read(buffer, 80L) != 80L) throw EOFException() - val card = FitsHeaderCard.from(buffer) - count++ + val card = try { + FitsHeaderCard.from(buffer) + } catch (e: IllegalArgumentException) { + break + } + if (header.isEmpty()) { require(isFirstCard(card.key)) { "Not a proper FITS header: ${card.key}" } } else if (card.isBlank) { continue - } else if (card.key == FitsKeywordDictionary.END.key) { + } else if (card.key == FitsKeyword.END.key) { break } @@ -64,19 +68,25 @@ object FitsFormat : ImageFormat { val position = source.position val data = SeekableSourceImageData(source, position, width, height, numberOfChannels, bitpix) - val skipBytes = computeRemainingBytesToSkip(data.channelBlockSize * numberOfChannels) - if (skipBytes > 0L) source.seek(position + skipBytes) + val skipBytes = computeRemainingBytesToSkip(data.totalSizeInBytes) + if (skipBytes > 0L) source.seek(position + data.totalSizeInBytes + skipBytes) return data } override fun read(source: SeekableSource): List> { - val header = readHeader(source) - val hdus = ArrayList(2) + val hdus = ArrayList(1) while (!source.exhausted) { + val header = try { + readHeader(source) + } catch (e: Throwable) { + LOG.error("failed to read FITS header", e) + break + } + val hdu = when { - isImageHdu(header) -> SeekableSourceImageHdu(header, readImageData(header, source)) + isImageHdu(header) -> BasicImageHdu(header.width, header.height, header.numberOfChannels, header, readImageData(header, source)) else -> { LOG.warn("unsupported FITS header: {}", header) continue @@ -142,8 +152,8 @@ object FitsFormat : ImageFormat { internal fun Buffer.readPixel(bitpix: Bitpix): Float { return when (bitpix) { Bitpix.BYTE -> (buffer.readByte().toInt() and 0xFF) / 255f - Bitpix.SHORT -> (buffer.readShort().toInt() and 0xFFFF) / 65535f - Bitpix.INTEGER -> ((buffer.readInt().toLong() and 0xFFFFFFFF) / 4294967295.0).toFloat() + Bitpix.SHORT -> (buffer.readShort().toInt() + 32768) / 65535f + Bitpix.INTEGER -> ((buffer.readInt().toLong() + 2147483648L) / 4294967295.0).toFloat() Bitpix.LONG -> TODO("Unsupported UInt64 sample format") Bitpix.FLOAT -> buffer.readFloat() Bitpix.DOUBLE -> buffer.readDouble().toFloat() diff --git a/nebulosa-fits/src/main/kotlin/nebulosa/fits/FitsHeader.kt b/nebulosa-fits/src/main/kotlin/nebulosa/fits/FitsHeader.kt index 82c6f3e1c..c91302739 100644 --- a/nebulosa-fits/src/main/kotlin/nebulosa/fits/FitsHeader.kt +++ b/nebulosa-fits/src/main/kotlin/nebulosa/fits/FitsHeader.kt @@ -127,7 +127,7 @@ open class FitsHeader : AbstractHeader { @JvmStatic fun checkType(key: HeaderKey, type: ValueType): Boolean { - if (key is FitsKeyword) { + if (key is FitsHeaderKey) { if (key.valueType == type || key.valueType == ValueType.ANY) { return true } @@ -150,7 +150,7 @@ open class FitsHeader : AbstractHeader { @JvmStatic fun isFirstCard(key: String): Boolean { - return FitsKeywordDictionary.SIMPLE.key == key || FitsKeywordDictionary.XTENSION.key == key + return FitsKeyword.SIMPLE.key == key || FitsKeyword.XTENSION.key == key } } } diff --git a/nebulosa-fits/src/main/kotlin/nebulosa/fits/FitsHeaderCard.kt b/nebulosa-fits/src/main/kotlin/nebulosa/fits/FitsHeaderCard.kt index 9b5862b50..752b63add 100644 --- a/nebulosa-fits/src/main/kotlin/nebulosa/fits/FitsHeaderCard.kt +++ b/nebulosa-fits/src/main/kotlin/nebulosa/fits/FitsHeaderCard.kt @@ -110,8 +110,6 @@ data class FitsHeaderCard( const val MAX_LONG_STRING_VALUE_WITH_COMMENT_LENGTH = MAX_LONG_STRING_VALUE_LENGTH - 2 const val MAX_HIERARCH_KEYWORD_LENGTH = FITS_HEADER_CARD_SIZE - 6 const val MAX_LONG_STRING_CONTINUE_OVERHEAD = 3 - const val MIN_VALID_CHAR = 0x20.toChar() - const val MAX_VALID_CHAR = 0x7e.toChar() const val HIERARCH_WITH_DOT = "HIERARCH." @JvmStatic val END = FitsHeaderCard("END", "", "", FitsHeaderCardType.NONE) @@ -211,18 +209,13 @@ data class FitsHeaderCard( return key.uppercase().startsWith(HIERARCH_WITH_DOT) } - @JvmStatic - fun isValidChar(c: Char): Boolean { - return c in MIN_VALID_CHAR..MAX_VALID_CHAR - } - @JvmStatic fun sanitize(input: CharSequence): String { val data = CharArray(input.length) for (i in input.indices) { val char = input[i] - data[i] = if (isValidChar(char)) char else '?' + data[i] = if (FitsHeaderCardParser.isValidChar(char)) char else '?' } return data.concatToString() diff --git a/nebulosa-fits/src/main/kotlin/nebulosa/fits/FitsHeaderCardFormatter.kt b/nebulosa-fits/src/main/kotlin/nebulosa/fits/FitsHeaderCardFormatter.kt index d172d7f41..088474020 100644 --- a/nebulosa-fits/src/main/kotlin/nebulosa/fits/FitsHeaderCardFormatter.kt +++ b/nebulosa-fits/src/main/kotlin/nebulosa/fits/FitsHeaderCardFormatter.kt @@ -30,7 +30,7 @@ object FitsHeaderCardFormatter { var key = card.key if (card.hasHierarchKey) { - key = HierarchKeyFormatter.INSTANCE.format(key) + key = HierarchKeyFormatter.format(key) if (key.length > FitsHeaderCard.MAX_HIERARCH_KEYWORD_LENGTH) { // Truncate HIERARCH keywords as necessary to fit. @@ -73,7 +73,7 @@ object FitsHeaderCardFormatter { while (from < value.length) { pad() - append(FitsKeywordDictionary.CONTINUE.key + " ") + append(FitsKeyword.CONTINUE.key + " ") from += appendQuotedValue(card, from) } } else { @@ -182,7 +182,7 @@ object FitsHeaderCardFormatter { if (available < COMMENT_PREFIX.length) { // Add a CONTINUE card with an empty string and try again... pad() - append(FitsKeywordDictionary.CONTINUE.key + " ''") + append(FitsKeyword.CONTINUE.key + " ''") appendComment(card) return } @@ -193,7 +193,7 @@ object FitsHeaderCardFormatter { // Now add records as needed to write the comment fully... while (from < comment.length) { pad() - append(FitsKeywordDictionary.CONTINUE.key + " ") + append(FitsKeyword.CONTINUE.key + " ") append(if (comment.length >= from + MAX_LONG_END_COMMENT) "'&'" else "''") append(LONG_COMMENT_PREFIX) from += append(comment, from) diff --git a/nebulosa-fits/src/main/kotlin/nebulosa/fits/FitsHeaderCardParser.kt b/nebulosa-fits/src/main/kotlin/nebulosa/fits/FitsHeaderCardParser.kt index 9d40dd6c6..6ff467a1b 100644 --- a/nebulosa-fits/src/main/kotlin/nebulosa/fits/FitsHeaderCardParser.kt +++ b/nebulosa-fits/src/main/kotlin/nebulosa/fits/FitsHeaderCardParser.kt @@ -23,12 +23,12 @@ internal data class FitsHeaderCardParser(private val line: CharSequence) { private fun parseKey() { // Find the '=' in the line, if any... - val iEq: Int = line.indexOf('=') + val iEq = line.indexOf('=') // The stem is in the first 8 characters or what precedes an '=' character // before that. - var endStem = if (iEq >= 0 && iEq <= FitsHeaderCard.MAX_KEYWORD_LENGTH) iEq else FitsHeaderCard.MAX_KEYWORD_LENGTH - endStem = min(line.length.toDouble(), endStem.toDouble()).toInt() + var endStem = if (iEq in 0..FitsHeaderCard.MAX_KEYWORD_LENGTH) iEq else FitsHeaderCard.MAX_KEYWORD_LENGTH + endStem = min(line.length, endStem) val rawStem = line.substring(0, endStem).trim { it <= ' ' } // Check for space at the start of the keyword... @@ -52,7 +52,7 @@ internal data class FitsHeaderCardParser(private val line: CharSequence) { // If the line does not have an '=', can only be a simple key // If it's not a HIERARCH keyword, then return the simple key. - if (iEq < 0 || stem != FitsKeywordDictionary.HIERARCH.key) { + if (iEq < 0 || stem != FitsKeyword.HIERARCH.key) { return } @@ -68,9 +68,10 @@ internal data class FitsHeaderCardParser(private val line: CharSequence) { builder.append('.') builder.append(token) } + key = builder.toString() - if (FitsKeywordDictionary.HIERARCH.key == key) { + if (FitsKeyword.HIERARCH.key == key) { // The key is only HIERARCH, without a hierarchical keyword after it... LOG.warn("HIERARCH base keyword without HIERARCH-style long key after it.") return @@ -110,7 +111,7 @@ internal data class FitsHeaderCardParser(private val line: CharSequence) { } } - comment = line.substring(parsePos) + comment = line.substring(parsePos).trim() parsePos = line.length } @@ -120,7 +121,7 @@ internal data class FitsHeaderCardParser(private val line: CharSequence) { return } - if (FitsKeywordDictionary.CONTINUE.key == key) { + if (FitsKeyword.CONTINUE.key == key) { parseValueBody() } else if (line[parsePos] == '=') { if (parsePos < FitsHeaderCard.MAX_KEYWORD_LENGTH) { @@ -135,7 +136,7 @@ internal data class FitsHeaderCardParser(private val line: CharSequence) { if (parsePos > FitsHeaderCard.MAX_KEYWORD_LENGTH) { // equal sign = after the 9th char -- only supported with hierarch keys... - if (!key.startsWith(FitsKeywordDictionary.HIERARCH.key + ".")) { + if (!key.startsWith(FitsKeyword.HIERARCH.key + ".")) { LOG.warn("[$key] possibly misplaced '=' (after byte 9).") // It's not a HIERARCH key return @@ -284,11 +285,18 @@ internal data class FitsHeaderCardParser(private val line: CharSequence) { companion object { + const val MIN_VALID_CHAR = 0x20.toChar() + const val MAX_VALID_CHAR = 0x7e.toChar() + @JvmStatic private val LOG = loggerFor() @JvmStatic private val DECIMAL_REGEX = Regex("[+-]?\\d+(\\.\\d*)?([dDeE][+-]?\\d+)?") @JvmStatic private val COMPLEX_REGEX = Regex("\\(\\s*$DECIMAL_REGEX\\s*,\\s*$DECIMAL_REGEX\\s*\\)") @JvmStatic private val INT_REGEX = Regex("[+-]?\\d+") + @JvmStatic + fun isValidChar(c: Char): Boolean { + return c in MIN_VALID_CHAR..MAX_VALID_CHAR + } } } diff --git a/nebulosa-fits/src/main/kotlin/nebulosa/fits/FitsHeaderCardType.kt b/nebulosa-fits/src/main/kotlin/nebulosa/fits/FitsHeaderCardType.kt index a5f320ac0..fbadf7fc8 100644 --- a/nebulosa-fits/src/main/kotlin/nebulosa/fits/FitsHeaderCardType.kt +++ b/nebulosa-fits/src/main/kotlin/nebulosa/fits/FitsHeaderCardType.kt @@ -4,7 +4,7 @@ import org.apache.commons.numbers.complex.Complex import java.math.BigDecimal import java.math.BigInteger -enum class FitsHeaderCardType(@JvmField val type: Class<*>) { +enum class FitsHeaderCardType(@JvmField internal val type: Class<*>) { NONE(Nothing::class.javaObjectType), TEXT(String::class.javaObjectType), BOOLEAN(Boolean::class.javaObjectType), diff --git a/nebulosa-fits/src/main/kotlin/nebulosa/fits/FitsHeaderKey.kt b/nebulosa-fits/src/main/kotlin/nebulosa/fits/FitsHeaderKey.kt new file mode 100644 index 000000000..8a816818c --- /dev/null +++ b/nebulosa-fits/src/main/kotlin/nebulosa/fits/FitsHeaderKey.kt @@ -0,0 +1,15 @@ +package nebulosa.fits + +import nebulosa.image.format.HeaderKey + +sealed interface FitsHeaderKey : HeaderKey { + + val hduType: HduType + + val valueType: ValueType + + fun n(vararg numbers: Int): FitsHeaderKey + + val isCommentStyle + get() = valueType == ValueType.NONE || key.isBlank() +} diff --git a/nebulosa-fits/src/main/kotlin/nebulosa/fits/FitsKeywordItem.kt b/nebulosa-fits/src/main/kotlin/nebulosa/fits/FitsHeaderKeyItem.kt similarity index 57% rename from nebulosa-fits/src/main/kotlin/nebulosa/fits/FitsKeywordItem.kt rename to nebulosa-fits/src/main/kotlin/nebulosa/fits/FitsHeaderKeyItem.kt index dc2c1d91d..d6f77252a 100644 --- a/nebulosa-fits/src/main/kotlin/nebulosa/fits/FitsKeywordItem.kt +++ b/nebulosa-fits/src/main/kotlin/nebulosa/fits/FitsHeaderKeyItem.kt @@ -1,22 +1,24 @@ package nebulosa.fits -data class FitsKeywordItem( +data class FitsHeaderKeyItem( override val key: String, override val hduType: HduType, override val valueType: ValueType, override val comment: String = "", -) : FitsKeyword { +) : FitsHeaderKey { - override fun n(vararg numbers: Int): FitsKeyword { + override fun n(vararg numbers: Int): FitsHeaderKey { if (numbers.isEmpty() || "n" !in key) return this val key = StringBuffer(key) + var idx = 0 for (number in numbers) { - val idx = key.indexOf("n") + idx = key.indexOf("n", idx) + if (idx < 0) break key.replace(idx, idx + 1, "$number") } - return FitsKeywordItem("$key", hduType, valueType, comment) + return FitsHeaderKeyItem("$key", hduType, valueType, comment) } } diff --git a/nebulosa-fits/src/main/kotlin/nebulosa/fits/FitsHelper.kt b/nebulosa-fits/src/main/kotlin/nebulosa/fits/FitsHelper.kt index 105c79e26..0f3f45d16 100644 --- a/nebulosa-fits/src/main/kotlin/nebulosa/fits/FitsHelper.kt +++ b/nebulosa-fits/src/main/kotlin/nebulosa/fits/FitsHelper.kt @@ -12,40 +12,40 @@ import java.time.Duration import java.time.LocalDateTime inline val ReadableHeader.naxis - get() = getInt(FitsKeywordDictionary.NAXIS, -1) + get() = getInt(FitsKeyword.NAXIS, -1) -inline fun ReadableHeader.naxis(n: Int) = getInt(FitsKeywordDictionary.NAXISn.n(n), 0) +inline fun ReadableHeader.naxis(n: Int) = getInt(FitsKeyword.NAXISn.n(n), 0) inline val ReadableHeader.width - get() = getInt(FitsKeywordDictionary.NAXIS1, 0) + get() = getInt(FitsKeyword.NAXIS1, 0) inline val ReadableHeader.height - get() = getInt(FitsKeywordDictionary.NAXIS2, 0) + get() = getInt(FitsKeyword.NAXIS2, 0) inline val ReadableHeader.numberOfChannels - get() = getInt(FitsKeywordDictionary.NAXIS3, 1) + get() = getInt(FitsKeyword.NAXIS3, 1) inline val ReadableHeader.bitpix get() = Bitpix.from(this) val ReadableHeader.rightAscension - get() = Angle(getStringOrNull(FitsKeywordDictionary.RA), isHours = true, decimalIsHours = false).takeIf { it.isFinite() } - ?: Angle(getStringOrNull(FitsKeywordDictionary.OBJCTRA), true).takeIf { it.isFinite() } - ?: getDouble(FitsKeywordDictionary.CRVAL1, Double.NaN).deg + get() = Angle(getStringOrNull(FitsKeyword.RA), isHours = true, decimalIsHours = false).takeIf { it.isFinite() } + ?: Angle(getStringOrNull(FitsKeyword.OBJCTRA), true).takeIf { it.isFinite() } + ?: getDouble(FitsKeyword.CRVAL1, Double.NaN).deg val ReadableHeader.declination - get() = Angle(getStringOrNull(FitsKeywordDictionary.DEC)).takeIf { it.isFinite() } - ?: Angle(getStringOrNull(FitsKeywordDictionary.OBJCTDEC)).takeIf { it.isFinite() } - ?: getDouble(FitsKeywordDictionary.CRVAL2, Double.NaN).deg + get() = Angle(getStringOrNull(FitsKeyword.DEC)).takeIf { it.isFinite() } + ?: Angle(getStringOrNull(FitsKeyword.OBJCTDEC)).takeIf { it.isFinite() } + ?: getDouble(FitsKeyword.CRVAL2, Double.NaN).deg inline val ReadableHeader.binX - get() = getInt(FitsKeywordDictionary.XBINNING, 1) + get() = getInt(FitsKeyword.XBINNING, 1) inline val ReadableHeader.binY - get() = getIntOrNull(FitsKeywordDictionary.YBINNING) ?: binX + get() = getIntOrNull(FitsKeyword.YBINNING) ?: binX inline val ReadableHeader.exposureTimeInSeconds - get() = getDoubleOrNull(FitsKeywordDictionary.EXPTIME) ?: getDouble(FitsKeywordDictionary.EXPOSURE, 0.0) + get() = getDoubleOrNull(FitsKeyword.EXPTIME) ?: getDouble(FitsKeyword.EXPOSURE, 0.0) inline val ReadableHeader.exposureTime: Duration get() = Duration.ofNanos((exposureTimeInSeconds * 1000000000.0).toLong()) @@ -56,31 +56,31 @@ inline val ReadableHeader.exposureTimeInMicroseconds const val INVALID_TEMPERATURE = 999.0 inline val ReadableHeader.temperature - get() = getDoubleOrNull(FitsKeywordDictionary.CCDTEM) ?: getDouble(FitsKeywordDictionary.CCD_TEMP, INVALID_TEMPERATURE) + get() = getDoubleOrNull(FitsKeyword.CCDTEM) ?: getDouble(FitsKeyword.CCD_TEMP, INVALID_TEMPERATURE) inline val ReadableHeader.gain - get() = getDouble(FitsKeywordDictionary.GAIN, 0.0) + get() = getDouble(FitsKeyword.GAIN, 0.0) inline val ReadableHeader.latitude - get() = (getDoubleOrNull(FitsKeywordDictionary.SITELAT)?.deg ?: getDoubleOrNull("LAT-OBS"))?.deg + get() = (getDoubleOrNull(FitsKeyword.SITELAT)?.deg ?: getDoubleOrNull("LAT-OBS"))?.deg inline val ReadableHeader.longitude - get() = (getDoubleOrNull(FitsKeywordDictionary.SITELONG)?.deg ?: getDoubleOrNull("LONG-OBS"))?.deg + get() = (getDoubleOrNull(FitsKeyword.SITELONG)?.deg ?: getDoubleOrNull("LONG-OBS"))?.deg inline val ReadableHeader.observationDate - get() = getStringOrNull(FitsKeywordDictionary.DATE_OBS)?.let(LocalDateTime::parse) + get() = getStringOrNull(FitsKeyword.DATE_OBS)?.let(LocalDateTime::parse) inline val ReadableHeader.cfaPattern - get() = getStringOrNull(FitsKeywordDictionary.BAYERPAT)?.ifBlank { null }?.trim() + get() = getStringOrNull(FitsKeyword.BAYERPAT)?.ifBlank { null }?.trim() inline val ReadableHeader.filter - get() = getStringOrNull(FitsKeywordDictionary.FILTER)?.ifBlank { null }?.trim() + get() = getStringOrNull(FitsKeyword.FILTER)?.ifBlank { null }?.trim() inline val ReadableHeader.frame - get() = (getStringOrNull("FRAME") ?: getStringOrNull(FitsKeywordDictionary.IMAGETYP))?.ifBlank { null }?.trim() + get() = (getStringOrNull("FRAME") ?: getStringOrNull(FitsKeyword.IMAGETYP))?.ifBlank { null }?.trim() inline val ReadableHeader.instrument - get() = getStringOrNull(FitsKeywordDictionary.INSTRUME)?.ifBlank { null }?.trim() + get() = getStringOrNull(FitsKeyword.INSTRUME)?.ifBlank { null }?.trim() inline fun SeekableSource.fits() = Fits().also { it.read(this) } diff --git a/nebulosa-fits/src/main/kotlin/nebulosa/fits/FitsKeyword.kt b/nebulosa-fits/src/main/kotlin/nebulosa/fits/FitsKeyword.kt index b43a99c2a..055d8c0ba 100644 --- a/nebulosa-fits/src/main/kotlin/nebulosa/fits/FitsKeyword.kt +++ b/nebulosa-fits/src/main/kotlin/nebulosa/fits/FitsKeyword.kt @@ -1,15 +1,4615 @@ package nebulosa.fits -import nebulosa.image.format.HeaderKey +@Suppress("EnumEntryName") +enum class FitsKeyword : FitsHeaderKey { -interface FitsKeyword : HeaderKey { + // Standard. + // https://github.com/nom-tam-fits/nom-tam-fits/blob/master/src/main/java/nom/tam/fits/header/Standard.java + // https://github.com/nom-tam-fits/nom-tam-fits/blob/master/src/main/java/nom/tam/fits/header/ObservationDescription.java + // https://github.com/nom-tam-fits/nom-tam-fits/blob/master/src/main/java/nom/tam/fits/header/ObservationDurationDescription.java - val hduType: HduType + /** + * The value field shall contain a character string identifying who compiled the information in the data associated + * with the key. This keyword is appropriate when the data originate in a published paper or are compiled from many + * sources. + */ + AUTHOR(HduType.ANY, ValueType.STRING, "author of the data"), - val valueType: ValueType + /** + * The value field shall contain an integer. The absolute value is used in computing the sizes of data structures. + * It shall specify the number of bits that represent a data value. RANGE: -64,-32,8,16,32 + */ + BITPIX(HduType.ANY, ValueType.INTEGER, "bits per data value"), - fun n(vararg numbers: Int): FitsKeyword + /** + * This keyword shall be used only in primary array headers or IMAGE extension headers with positive values of + * BITPIX (i.e., in arrays with integer data). Columns 1-8 contain the string, `BLANK ' (ASCII blanks in columns + * 6-8). The value field shall contain an integer that specifies the representation of array values whose physical + * values are undefined. + */ + BLANK(HduType.IMAGE, ValueType.INTEGER, "value used for undefined array elements"), - val isCommentStyle - get() = valueType == ValueType.NONE || key.isBlank() + /** + * Columns 1-8 contain ASCII blanks. This keyword has no associated value. Columns 9-80 may contain any ASCII text. + * Any number of card images with blank keyword fields may appear in a key. + */ + BLANKS(" ", HduType.ANY, ValueType.NONE, ""), + + /** + * This keyword may be used only in the primary key. It shall appear within the first 36 card images of the FITS + * file. (Note: This keyword thus cannot appear if NAXIS is greater than 31, or if NAXIS is greater than 30 and the + * EXTEND keyword is present.) Its presence with the required logical value of T advises that the physical block + * size of the FITS file on which it appears may be an integral multiple of the logical record length, and not + * necessarily equal to it. Physical block size and logical record length may be equal even if this keyword is + * present or unequal if it is absent. It is reserved primarily to prevent its use with other meanings. Since the + * issuance of version 1 of the standard, the BLOCKED keyword has been deprecated. + */ + @Deprecated("no blocksize other that 2880 may be used") + BLOCKED(HduType.PRIMARY, ValueType.LOGICAL, "is physical blocksize a multiple of 2880?"), + + /** + * This keyword shall be used, along with the BZERO keyword, when the array pixel values are not the true physical + * values, to transform the primary data array values to the true physical values they represent, using the + * equation: physical_value = BZERO + BSCALE * array_value. The value field shall contain a floating point number + * representing the coefficient of the linear term in the scaling equation, the ratio of physical value to array + * value at zero offset. The default value for this keyword is 1.0. + */ + BSCALE(HduType.IMAGE, ValueType.REAL, "linear factor in scaling equation"), + + /** + * The value field shall contain a character string, describing the physical units in which the quantities in the + * array, after application of BSCALE and BZERO, are expressed. The units of all FITS key keyword values, with the + * exception of measurements of angles, should conform with the recommendations in the IAU Style Manual. For angular + * measurements given as floating point values and specified with reserved keywords, degrees are the recommended + * units (with the units, if specified, given as 'deg'). + */ + BUNIT(HduType.IMAGE, ValueType.STRING, "physical units of the array values"), + + /** + * This keyword shall be used, along with the BSCALE keyword, when the array pixel values are not the true physical + * values, to transform the primary data array values to the true values using the equation: physical_value = BZERO + * + BSCALE * array_value. The value field shall contain a floating point number representing the physical value + * corresponding to an array value of zero. The default value for this keyword is 0.0. + */ + BZERO(HduType.IMAGE, ValueType.REAL, "zero point in scaling equation"), + + /** + * The value field shall contain a floating point number giving the partial derivative of the coordinate specified + * by the CTYPEn keywords with respect to the pixel index, evaluated at the reference point CRPIXn, in units of the + * coordinate specified by the CTYPEn keyword. These units must follow the prescriptions of section 5.3 of the FITS + * Standard. + */ + CDELTn(HduType.IMAGE, ValueType.REAL, "coordinate increment along axis"), + + /** + * This keyword shall have no associated value; columns 9-80 may contain any ASCII text. Any number of COMMENT card + * images may appear in a key. + */ + COMMENT(HduType.ANY, ValueType.NONE, ""), + + /** + * The CONTINUE keyword, when followed by spaces in columns 9 and 10 of the card image and a character string + * enclosed in single quotes starting in column 11 or higher, indicates that the quoted string should be treated as + * a continuation of the character string value in the previous key keyword. To conform to this convention, the + * character string value on the previous keyword must end with the ampersand character ('&'), but the ampersand + * is not part of the value string and should be deleted before concatenating the strings together. The character + * string value may be continued on any number of consecutive CONTINUE keywords, thus effectively allowing + * arbitrarily long strings to be written as keyword values. + */ + CONTINUE(HduType.ANY, ValueType.NONE, "denotes the CONTINUE long string keyword convention"), + + /** + * This keyword is used to indicate a rotation from a standard coordinate system described by the CTYPEn to a + * different coordinate system in which the values in the array are actually expressed. Rules for such rotations are + * not further specified in the Standard; the rotation should be explained in comments. The value field shall + * contain a floating point number giving the rotation angle in degrees between axis n and the direction implied by + * the coordinate system defined by CTYPEn. In unit degrees. + */ + CROTAn(HduType.IMAGE, ValueType.REAL, "coordinate system rotation angle"), + + /** + * The value field shall contain a floating point number, identifying the location of a reference point along axis + * n, in units of the axis index. This value is based upon a counter that runs from 1 to NAXISn with an increment of + * 1 per pixel. The reference point value need not be that for the center of a pixel nor lie within the actual data + * array. Use comments to indicate the location of the index point relative to the pixel. + */ + CRPIXn(HduType.IMAGE, ValueType.REAL, "coordinate system reference pixel"), + + /** + * The value field shall contain a floating point number, giving the value of the coordinate specified by the CTYPEn + * keyword at the reference point CRPIXn. Units must follow the prescriptions of section 5.3 of the FITS Standard. + */ + CRVALn(HduType.IMAGE, ValueType.REAL, "coordinate system value at reference pixel"), + + /** + * The value field shall contain a character string, giving the name of the coordinate represented by axis n. + */ + CTYPEn(HduType.IMAGE, ValueType.STRING, "name of the coordinate axis"), + + /** + * The value field shall always contain a floating point number, regardless of the value of BITPIX. This number + * shall give the maximum valid physical value represented by the array, exclusive of any special values. + */ + DATAMAX(HduType.IMAGE, ValueType.REAL, "maximum data value"), + + /** + * The value field shall always contain a floating point number, regardless of the value of BITPIX. This number + * shall give the minimum valid physical value represented by the array, exclusive of any special values. + */ + DATAMIN(HduType.IMAGE, ValueType.REAL, "minimum data value"), + + /** + * The date on which the HDU was created, in the format specified in the FITS Standard. The old date format was + * 'yy/mm/dd' and may be used only for dates from 1900 through 1999. the new Y2K compliant date format is + * 'yyyy-mm-dd' or 'yyyy-mm-ddTHH:MM:SS[.sss]'. + */ + DATE(HduType.ANY, ValueType.STRING, "date of file creation"), + + /** + * The date of the observation, in the format specified in the FITS Standard. The old date format was 'yy/mm/dd' and + * may be used only for dates from 1900 through 1999. The new Y2K compliant date format is 'yyyy-mm-dd' or + * 'yyyy-mm-ddTHH:MM:SS[.sss]'. + */ + DATE_OBS("DATE-OBS", HduType.ANY, ValueType.STRING, "date of the observation"), + + /** + * This keyword has no associated value. Columns 9-80 shall be filled with ASCII blanks. + */ + END(HduType.ANY, ValueType.NONE, ""), + + /** + * The value field shall contain a floating point number giving the equinox in years for the celestial coordinate + * system in which positions are expressed. Starting with Version 1, the Standard has deprecated the use of the + * EPOCH keyword and thus it shall not be used in FITS files created after the adoption of the standard; rather, the + * EQUINOX keyword shall be used. + */ + @Deprecated("use EQUINOX instead") + EPOCH(HduType.ANY, ValueType.REAL, "equinox of celestial coordinate system"), + + /** + * The value field shall contain a floating point number giving the equinox in years for the celestial coordinate + * system in which positions are expressed. + */ + EQUINOX(HduType.ANY, ValueType.REAL, "equinox of celestial coordinate system"), + + /** + * If the FITS file may contain extensions, a card image with the keyword EXTEND and the value field containing the + * logical value T must appear in the primary key immediately after the last NAXISn card image, or, if NAXIS=0, the + * NAXIS card image. The presence of this keyword with the value T in the primary key does not require that + * extensions be present. + */ + EXTEND(HduType.PRIMARY, ValueType.LOGICAL, "may the FITS file contain extensions?"), + + /** + * The value field shall contain an integer, specifying the level in a hierarchy of extension levels of the + * extension key containing it. The value shall be 1 for the highest level; levels with a higher value of this + * keyword shall be subordinate to levels with a lower value. If the EXTLEVEL keyword is absent, the file should be + * treated as if the value were 1. This keyword is used to describe an extension and should not appear in the + * primary key.RANGE: [1:] DEFAULT: 1 + */ + EXTLEVEL(HduType.EXTENSION, ValueType.INTEGER, "hierarchical level of the extension"), + + /** + * The value field shall contain a character string, to be used to distinguish among different extensions of the + * same type, i.e., with the same value of XTENSION, in a FITS file. This keyword is used to describe an extension + * and should not appear in the primary key. + */ + EXTNAME(HduType.EXTENSION, ValueType.STRING, "name of the extension"), + + /** + * The value field shall contain an integer, to be used to distinguish among different extensions in a FITS file + * with the same type and name, i.e., the same values for XTENSION and EXTNAME. The values need not start with 1 for + * the first extension with a particular value of EXTNAME and need not be in sequence for subsequent values. If the + * EXTVER keyword is absent, the file should be treated as if the value were 1. This keyword is used to describe an + * extension and should not appear in the primary key.RANGE: [1:] DEFAULT: 1 + */ + EXTVER(HduType.EXTENSION, ValueType.INTEGER, "version of the extension"), + + /** + * The value field shall contain an integer that shall be used in any way appropriate to define the data structure, + * consistent with Eq. 5.2 in the FITS Standard. This keyword originated for use in FITS Random Groups where it + * specifies the number of random groups present. In most other cases this keyword will have the value 1. + */ + GCOUNT(HduType.EXTENSION, ValueType.INTEGER, "group count"), + + /** + * The value field shall contain the logical constant T. The value T associated with this keyword implies that + * random groups records are present. + */ + GROUPS(HduType.GROUPS, ValueType.LOGICAL, "indicates random groups structure"), + + /** + * This keyword shall have no associated value; columns 9-80 may contain any ASCII text. The text should contain a + * history of steps and procedures associated with the processing of the associated data. Any number of HISTORY card + * images may appear in a key. + */ + HISTORY(HduType.ANY, ValueType.NONE, "processing history of the data"), + + /** + * The value field shall contain a character string identifying the instrument used to acquire the data associated + * with the key. + */ + INSTRUME(HduType.ANY, ValueType.STRING, "name of instrument"), + + /** + * The value field shall contain a non-negative integer no greater than 999, representing the number of axes in the + * associated data array. A value of zero signifies that no data follow the key in the HduType. In the context of FITS + * 'TABLE' or 'BINTABLE' extensions, the value of NAXIS is always 2.RANGE: [0:999] + */ + NAXIS(HduType.ANY, ValueType.INTEGER, "number of axes"), + + /** + * The value field of this indexed keyword shall contain a non-negative integer, representing the number of elements + * along axis n of a data array. The NAXISn must be present for all values n = 1,...,NAXIS, and for no other values + * of n. A value of zero for any of the NAXISn signifies that no data follow the key in the HduType. If NAXIS is equal + * to 0, there should not be any NAXISn keywords.RANGE: [0:] + */ + NAXISn(HduType.ANY, ValueType.INTEGER, "size of the n'th axis"), + + /** + * The value field shall contain a character string giving a name for the object observed. + */ + OBJECT(HduType.ANY, ValueType.STRING, "name of observed object"), + + /** + * The value field shall contain a character string identifying who acquired the data associated with the key. + */ + OBSERVER(HduType.ANY, ValueType.STRING, "observer who acquired the data"), + + /** + * The value field shall contain a character string identifying the organization or institution responsible for + * creating the FITS file. + */ + ORIGIN(HduType.ANY, ValueType.STRING, "organization responsible for the data"), + + /** + * The value field shall contain an integer that shall be used in any way appropriate to define the data structure, + * consistent with Eq. 5.2 in the FITS Standard. This keyword was originated for use with FITS Random Groups and + * represented the number of parameters preceding each group. It has since been used in 'BINTABLE' extensions to + * represent the size of the data heap following the main data table. In most other cases its value will be zero. + */ + PCOUNT(HduType.EXTENSION, ValueType.INTEGER, "parameter count"), + + /** + * This keyword is reserved for use within the FITS Random Groups structure. This keyword shall be used, along with + * the PZEROn keyword, when the nth FITS group parameter value is not the true physical value, to transform the + * group parameter value to the true physical values it represents, using the equation, physical_value = PZEROn + + * PSCALn * group_parameter_value. The value field shall contain a floating point number representing the + * coefficient of the linear term, the scaling factor between true values and group parameter values at zero offset. + * The default value for this keyword is 1.0. + */ + PSCALn(HduType.GROUPS, ValueType.REAL, "parameter scaling factor"), + + /** + * This keyword is reserved for use within the FITS Random Groups structure. The value field shall contain a + * character string giving the name of parameter n. If the PTYPEn keywords for more than one value of n have the + * same associated name in the value field, then the data value for the parameter of that name is to be obtained by + * adding the derived data values of the corresponding parameters. This rule provides a mechanism by which a random + * parameter may have more precision than the accompanying data array elements; for example, by summing two 16-bit + * values with the first scaled relative to the other such that the sum forms a number of up to 32-bit precision. + */ + PTYPEn(HduType.GROUPS, ValueType.STRING, "name of random groups parameter"), + + /** + * This keyword is reserved for use within the FITS Random Groups structure. This keyword shall be used, along with + * the PSCALn keyword, when the nth FITS group parameter value is not the true physical value, to transform the + * group parameter value to the physical value. The value field shall contain a floating point number, representing + * the true value corresponding to a group parameter value of zero. The default value for this keyword is 0.0. The + * transformation equation is as follows: physical_value = PZEROn + PSCALn * group_parameter_value.DEFAULT: 0.0 + */ + PZEROn(HduType.GROUPS, ValueType.REAL, "parameter scaling zero point"), + + /** + * Coordinate reference frame of major/minor axes.If absent the default value is 'FK5'. + */ + RADESYS(HduType.ANY, ValueType.STRING, "Coordinate reference frame of major/minor axes."), + + /** + * The value field shall contain a character string citing a reference where the data associated with the key are + * published. + */ + REFERENC(HduType.ANY, ValueType.STRING, "bibliographic reference"), + + /** + * The SIMPLE keyword is required to be the first keyword in the primary key of all FITS files. The value field + * shall contain a logical constant with the value T if the file conforms to the standard. This keyword is mandatory + * for the primary key and is not permitted in extension headers. A value of F signifies that the file does not + * conform to this standard. + */ + SIMPLE(HduType.PRIMARY, ValueType.LOGICAL, "does file conform to the Standard?"), + + /** + * The value field of this indexed keyword shall contain an integer specifying the column in which field n starts in + * an ASCII TABLE extension. The first column of a row is numbered 1.RANGE: [1:] + */ + TBCOLn(HduType.ASCII_TABLE, ValueType.INTEGER, "begining column number"), + + /** + * The value field of this indexed keyword shall contain a character string describing how to interpret the contents + * of field n as a multidimensional array, providing the number of dimensions and the length along each axis. The + * form of the value is not further specified by the Standard. A proposed convention is described in Appendix B.2 of + * the FITS Standard in which the value string has the format '(l,m,n...)' where l, m, n,... are the dimensions of + * the array. + */ + TDIMn(HduType.BINTABLE, ValueType.STRING, "dimensionality of the array "), + + /** + * The value field of this indexed keyword shall contain a character string describing the format recommended for + * the display of the contents of field n. If the table value has been scaled, the physical value shall be + * displayed. All elements in a field shall be displayed with a single, repeated format. For purposes of display, + * each byte of bit (type X) and byte (type B) arrays is treated as an unsigned integer. Arrays of type A may be + * terminated with a zero byte. Only the format codes in Table 8.6, discussed in section 8.3.4 of the FITS Standard, + * are permitted for encoding. The format codes must be specified in upper case. If the Bw.m, Ow.m, and Zw.m formats + * are not readily available to the reader, the Iw.m display format may be used instead, and if the ENw.d and ESw.d + * formats are not available, Ew.d may be used. The meaning of this keyword is not defined for fields of type P in + * the Standard but may be defined in conventions using such fields. + */ + TDISPn(HduType.TABLE, ValueType.STRING, "display format"), + + /** + * The value field shall contain a character string identifying the telescope used to acquire the data associated + * with the key. + */ + TELESCOP(HduType.ANY, ValueType.STRING, "name of telescope"), + + /** + * The value field shall contain a non-negative integer representing the number of fields in each row of a 'TABLE' + * or 'BINTABLE' extension. The maximum permissible value is 999. RANGE: [0:999] + */ + TFIELDS(HduType.TABLE, ValueType.INTEGER, "number of columns in the table"), + + /** + * The value field of this indexed keyword shall contain a character string describing the format in which field n + * is encoded in a 'TABLE' or 'BINTABLE' extension. + */ + TFORMn(HduType.TABLE, ValueType.STRING, "column data format"), + + /** + * The value field of this keyword shall contain an integer providing the separation, in bytes, between the start of + * the main data table and the start of a supplemental data area called the heap. The default value shall be the + * product of the values of NAXIS1 and NAXIS2. This keyword shall not be used if the value of PCOUNT is zero. A + * proposed application of this keyword is presented in Appendix B.1 of the FITS Standard. + */ + THEAP(HduType.BINTABLE, ValueType.INTEGER, "offset to starting data heap address"), + + /** + * In ASCII 'TABLE' extensions, the value field for this indexed keyword shall contain the character string that + * represents an undefined value for field n. The string is implicitly blank filled to the width of the field. In + * binary 'BINTABLE' table extensions, the value field for this indexed keyword shall contain the integer that + * represents an undefined value for field n of data type B, I, or J. The keyword may not be used in 'BINTABLE' + * extensions if field n is of any other data type. + */ + TNULLn(HduType.TABLE, ValueType.STRING, "value used to indicate undefined table element"), + + /** + * This indexed keyword shall be used, along with the TZEROn keyword, when the quantity in field n does not + * represent a true physical quantity. The value field shall contain a floating point number representing the + * coefficient of the linear term in the equation, physical_value = TZEROn + TSCALn * field_value, which must be + * used to compute the true physical value of the field, or, in the case of the complex data types C and M, of the + * real part of the field with the imaginary part of the scaling factor set to zero. The default value for this + * keyword is 1.0. This keyword may not be used if the format of field n is A, L, or X.DEFAULT: 1.0 + */ + TSCALn(HduType.TABLE, ValueType.REAL, "linear data scaling factor"), + + /** + * The value field for this indexed keyword shall contain a character string, giving the name of field n. It is + * recommended that only letters, digits, and underscore (hexadecimal code 5F, ('_') be used in the name. String + * comparisons with the values of TTYPEn keywords should not be case sensitive. The use of identical names for + * different fields should be avoided. + */ + TTYPEn(HduType.TABLE, ValueType.STRING, "column name"), + + /** + * The value field shall contain a character string describing the physical units in which the quantity in field n, + * after any application of TSCALn and TZEROn, is expressed. The units of all FITS key keyword values, with the + * exception of measurements of angles, should conform with the recommendations in the IAU Style Manual. For angular + * measurements given as floating point values and specified with reserved keywords, degrees are the recommended + * units (with the units, if specified, given as 'deg'). + */ + TUNITn(HduType.TABLE, ValueType.STRING, "column units"), + + /** + * This indexed keyword shall be used, along with the TSCALn keyword, when the quantity in field n does not + * represent a true physical quantity. The value field shall contain a floating point number representing the true + * physical value corresponding to a value of zero in field n of the FITS file, or, in the case of the complex data + * types C and M, in the real part of the field, with the imaginary part set to zero. The default value for this + * keyword is 0.0. This keyword may not be used if the format of field n is A, L, or X.DEFAULT: 0.0 + */ + TZEROn(HduType.TABLE, ValueType.REAL, "column scaling zero point"), + + /** + * The value field shall contain a character string giving the name of the extension type. This keyword is mandatory + * for an extension key and must not appear in the primary key. For an extension that is not a standard extension, + * the type name must not be the same as that of a standard extension. + */ + XTENSION(HduType.EXTENSION, ValueType.STRING, "marks beginning of new HDU"), + + // FITS keywords that have been widely used within the astronomical community. + // These are the Keywords that describe the observation. + + /** + * The value field shall contain a floating point number giving the air mass during the observation by a ground + * based telescope. The value of the airmass is often approximated by the secant of the elevation angle and has a + * value of 1.0 at the zenith and increases towards the horizon. This value is assumed to correspond to the start of + * the observation unless another interpretation is clearly explained in the comment field. + */ + AIRMASS(HduType.ANY, ValueType.REAL, "air mass"), + + /** + * The value field gives the declination of the observation. It may be expressed either as a floating point number + * in units of decimal degrees, or as a character string in 'dd:mm:ss.sss' format where the decimal point and number + * of fractional digits are optional. The coordinate reference frame is given by the RADECSYS keyword, and the + * coordinate epoch is given by the EQUINOX keyword. Example: -47.25944 or '-47:15:34.00'. + */ + DEC(HduType.ANY, ValueType.STRING, "declination of the observed object"), + + /** + * The value field shall contain a floating point number giving the nominal declination of the pointing direction in + * units of decimal degrees. The coordinate reference frame is given by the RADECSYS keyword, and the coordinate + * epoch is given by the EQUINOX keyword. The precise definition of this keyword is instrument-specific, but + * typically the nominal direction corresponds to the direction to which the instrument was requested to point. The + * DEC_PNT keyword should be used to give the actual pointed direction. + */ + DEC_NOM(HduType.ANY, ValueType.REAL, "nominal declination of the observation"), + + /** + * The value field shall contain a floating point number giving the declination of the observed object in units of + * decimal degrees. The coordinate reference frame is given by the RADECSYS keyword, and the coordinate epoch is + * given by the EQUINOX keyword. + */ + DEC_OBJ(HduType.ANY, ValueType.REAL, "declination of the observed object"), + + /** + * The value field shall contain a floating point number giving the declination of the pointing direction in units + * of decimal degrees. The coordinate reference frame is given by the RADECSYS keyword, and the coordinate epoch is + * given by the EQUINOX keyword. The precise definition of this keyword is instrument-specific, but typically the + * pointed direction corresponds to the optical axis of the instrument. This keyword gives a mean value in cases + * where the pointing axis was not fixed during the entire observation. + */ + DEC_PNT(HduType.ANY, ValueType.REAL, "declination of the pointed direction of the instrument"), + + /** + * The value field shall contain a floating point number giving the declination of the space craft (or telescope + * platform) X axis during the observation in decimal degrees. The coordinate reference frame is given by the + * RADECSYS keyword, and the coordinate epoch is given by the EQUINOX keyword. This keyword gives a mean value in + * cases where the axis was not fixed during the entire observation. + */ + DEC_SCX(HduType.ANY, ValueType.REAL, "declination of the X spacecraft axis"), + + /** + * The value field shall contain a floating point number giving the declination of the space craft (or telescope + * platform) Z axis during the observation in decimal degrees. The coordinate reference frame is given by the + * RADECSYS keyword, and the coordinate epoch is given by the EQUINOX keyword. This keyword gives a mean value in + * cases where the axis was not fixed during the entire observation. + */ + DEC_SCZ(HduType.ANY, ValueType.REAL, "declination of the Z spacecraft axis"), + + /** + * The value field shall contain a floating point number giving the geographic latitude from which the observation + * was made in units of degrees. + */ + LATITUDE(HduType.ANY, ValueType.REAL, "geographic latitude of the observation"), + + /** + * The value field shall contain a floating point number giving the angle between the direction of the observation + * (e.g., the optical axis of the telescope or the position of the target) and the moon, measured in degrees. + */ + MOONANGL(HduType.ANY, ValueType.REAL, "angle between the observation and the moon"), + + /** + * The value field shall contain a character string giving a name for the observed object that conforms to the IAU + * astronomical object naming conventions. The value of this keyword is more strictly constrained than for the + * standard OBJECT keyword which in practice has often been used to record other ancillary information about the + * observation (e.g. filter, exposure time, weather conditions, etc.). + */ + OBJNAME(HduType.ANY, ValueType.STRING, "AU name of observed object"), + + /** + * The value field shall contain a character string which uniquely identifies the dataset contained in the FITS + * file. This is typically a sequence number that can contain a mixture of numerical and character values. Example: + * '10315-01-01-30A' + */ + OBS_ID(HduType.ANY, ValueType.STRING, "unique observation ID"), + + /** + * The value field shall contain a floating point number giving the position angle of the y axis of the detector + * projected on the sky, in degrees east of north. This keyword is synonymous with the CROTA2 WCS keyword. + */ + ORIENTAT(HduType.IMAGE, ValueType.REAL, "position angle of image y axis (deg. E of N)"), + + /** + * The value field shall contain a floating point number giving the position angle of the relevant aspect of + * telescope pointing axis and/or instrument on the sky in units of degrees east of north. It commonly applies to + * the orientation of a slit mask. + */ + PA_PNT(HduType.ANY, ValueType.REAL, "position angle of the pointing"), + + /** + * The value field gives the Right Ascension of the observation. It may be expressed either as a floating point + * number in units of decimal degrees, or as a character string in 'HH:MM:SS.sss' format where the decimal point and + * number of fractional digits are optional. The coordinate reference frame is given by the RADECSYS keyword, and + * the coordinate epoch is given by the EQUINOX keyword. Example: 180.6904 or '12:02:45.7'. + */ + RA(HduType.ANY, ValueType.STRING, "R.A. of the observation"), + + /** + * The value field shall contain a floating point number giving the nominal Right Ascension of the pointing + * direction in units of decimal degrees. The coordinate reference frame is given by the RADECSYS keyword, and the + * coordinate epoch is given by the EQUINOX keyword. The precise definition of this keyword is instrument-specific, + * but typically the nominal direction corresponds to the direction to which the instrument was requested to point. + * The RA_PNT keyword should be used to give the actual pointed direction. + */ + RA_NOM(HduType.ANY, ValueType.REAL, "nominal R.A. of the observation"), + + /** + * The value field shall contain a floating point number giving the Right Ascension of the observed object in units + * of decimal degrees. The coordinate reference frame is given by the RADECSYS keyword, and the coordinate epoch is + * given by the EQUINOX keyword. + */ + RA_OBJ(HduType.ANY, ValueType.REAL, "R.A. of the observed object"), + + /** + * The value field shall contain a floating point number giving the Right Ascension of the pointing direction in + * units of decimal degrees. The coordinate reference frame is given by the RADECSYS keyword, and the coordinate + * epoch is given by the EQUINOX keyword. The precise definition of this keyword is instrument-specific, but + * typically the pointed direction corresponds to the optical axis of the instrument. This keyword gives a mean + * value in cases where the pointing axis was not fixed during the entire observation. + */ + RA_PNT(HduType.ANY, ValueType.REAL, "R.A. of the pointed direction of the instrument"), + + /** + * The value field shall contain a floating point number giving the Right Ascension of the space craft (or telescope + * platform) X axis during the observation in decimal degrees. The coordinate reference frame is given by the + * RADECSYS keyword, and the coordinate epoch is given by the EQUINOX keyword. This keyword gives a mean value in + * cases where the axis was not fixed during the entire observation. + */ + RA_SCX(HduType.ANY, ValueType.REAL, "R.A. of the X spacecraft axis"), + + /** + * The value field shall contain a floating point number giving the Right Ascension of the space craft (or telescope + * platform) Y axis during the observation in decimal degrees. The coordinate reference frame is given by the + * RADECSYS keyword, and the coordinate epoch is given by the EQUINOX keyword. This keyword gives a mean value in + * cases where the axis was not fixed during the entire observation. + */ + RA_SCY(HduType.ANY, ValueType.REAL, "R.A. of the Y spacecraft axis"), + + /** + * The value field shall contain a floating point number giving the Right Ascension of the space craft (or telescope + * platform) Z axis during the observation in decimal degrees. The coordinate reference frame is given by the + * RADECSYS keyword, and the coordinate epoch is given by the EQUINOX keyword. This keyword gives a mean value in + * cases where the axis was not fixed during the entire observation. + */ + RA_SCZ(HduType.ANY, ValueType.REAL, "R.A. of the Z spacecraft axis"), + + /** + * The value field shall contain a floating point number giving the angle between the direction of the observation + * (e.g., the optical axis of the telescope or the position of the target) and the sun, measured in degrees. + */ + SUNANGLE(HduType.ANY, ValueType.REAL, "angle between the observation and the sun"), + + // FITS keywords that have been widely used within the astronomical community. + // These are the Keywords that describe the instrument that took the data. + + /** + * The value field shall contain a character string which gives the name of the instrumental aperture though which + * the observation was made. This keyword is typically used in instruments which have a selection of apertures which + * restrict the field of view of the detector. + */ + APERTURE(HduType.ANY, ValueType.STRING, "name of field of view aperture"), + + /** + * The value field shall contain a character string which identifies the configuration or mode of the pre-processing + * software that operated on the raw instrumental data to generate the data that is recorded in the FITS file. + * Example: some X-ray satellite data may be recorded in 'BRIGHT', 'FAINT', or 'FAST' data mode. + */ + DATAMODE(HduType.ANY, ValueType.STRING, "pre-processor data mode"), + + /** + * The value field shall contain a character string giving the name of the detector within the instrument that was + * used to make the observation. Example: 'CCD1' + */ + DETNAM(HduType.ANY, ValueType.STRING, "name of the detector used to make the observation"), + + /** + * The value field shall contain a character string which gives the name of the filter that was used during the + * observation to select or modify the radiation that was transmitted to the detector. More than 1 filter may be + * listed by using the FILTERn indexed keyword. The value 'none' or 'NONE' indicates that no filter was used. + */ + FILTER(HduType.ANY, ValueType.STRING, "name of filter used during the observation"), + + /** + * The value field of this indexed keyword shall contain a character string which gives the name of one of multiple + * filters that were used during the observation to select or modify the radiation that was transmitted to the + * detector. The value 'none' or 'NONE' indicates that no filter was used. + */ + FILTERn(HduType.ANY, ValueType.STRING, "name of filters used during the observation"), + + /** + * The value field shall contain a character string which gives the name of the defraction grating that was used + * during the observation. More than 1 grating may be listed by using the GRATINGn indexed keyword. The value 'none' + * or 'NONE' indicates that no grating was used. + */ + GRATING(HduType.ANY, ValueType.STRING, "name of the grating used during the observation."), + + /** + * The value field of this indexed keyword shall contain a character string which gives the name of one of multiple + * defraction gratings that were used during the observation. The value 'none' or 'NONE' indicates that no grating + * was used. + */ + GRATINGn(HduType.ANY, ValueType.STRING, "name of gratings used during the observation."), + + /** + * The value field shall contain a character string which gives the observing mode of the observation. This is used + * in cases where the instrument or detector can be configured to operate in different modes which significantly + * affect the resulting data. Examples: 'SLEW', 'RASTER', or 'POINTING' + */ + OBS_MODE(HduType.ANY, ValueType.STRING, "instrumental mode of the observation"), + + /** + * The value field shall contain an integer giving the data value at which the detector becomes saturated. This + * keyword value may differ from the maximum value implied by the BITPIX in that more bits may be allocated in the + * FITS pixel values than the detector can accommodate. + */ + SATURATE(HduType.ANY, ValueType.INTEGER, "Data value at which saturation occurs"), + + // FITS keywords that have been widely used within the astronomical community. + // These are the Keywords that describe the observation. + + /** + * The value field shall contain a character string that gives the date on which the observation ended. This keyword + * has the same format, and is used in conjunction with, the standard DATA-OBS keyword that gives the starting date + * of the observation. These 2 keywords may give either the calendar date using the 'yyyy-mm-dd' format, or may give + * the full date and time using the 'yyyy-mm-ddThh:mm:ss.sss' format. + */ + DATE_END("DATE-END", HduType.ANY, ValueType.STRING, "date of the end of observation"), + + /** + * The value field shall contain a floating point number giving the difference between the stop and start times of + * the observation in units of seconds. This keyword is synonymous with the TELAPSE keyword. + */ + ELAPTIME(HduType.ANY, ValueType.REAL, "elapsed time of the observation"), + + /** + * The value field shall contain a floating point number giving the exposure time of the observation in units of + * seconds. The exact definition of 'exposure time' is mission dependent and may, for example, include corrections + * for shutter open and close duration, detector dead time, vignetting, or other effects. This keyword is synonymous + * with the EXPTIME keyword. + */ + EXPOSURE(HduType.ANY, ValueType.REAL, "exposure time"), + + /** + * The value field shall contain a floating point number giving the exposure time of the observation in units of + * seconds. The exact definition of 'exposure time' is mission dependent and may, for example, include corrections + * for shutter open and close duration, detector dead time, vignetting, or other effects. This keyword is synonymous + * with the EXPOSURE keyword. + */ + EXPTIME(HduType.ANY, ValueType.REAL, "exposure time"), + + /** + * The value field shall contain a floating point number giving the total integrated exposure time in units of + * seconds corrected for detector 'dead time' effects which reduce the net efficiency of the detector. The ratio of + * LIVETIME/ONTIME gives the mean dead time correction during the observation, which lies in the range 0.0 to 1.0. + */ + LIVETIME(HduType.ANY, ValueType.REAL, "exposure time after deadtime correction"), + + /** + * The value field shall contain a floating point number giving the total integrated exposure time of the + * observation in units of seconds. ONTIME may be less than TELAPSE if there were intevals during the observation in + * which the target was not observed (e.g., the shutter was closed, or the detector power was turned off). + */ + ONTIME(HduType.ANY, ValueType.REAL, "integration time during the observation"), + + /** + * The value field shall contain a floating point number giving the difference between the stop and start times of + * the observation in units of seconds. This keyword is synonymous with the ELAPTIME keyword. + */ + TELAPSE(HduType.ANY, ValueType.REAL, "elapsed time of the observation"), + + /** + * The value field shall contain a character string that gives the time at which the observation ended. This keyword + * is used in conjunction with the DATE-END keyword to give the ending time of the observation; the DATE-END keyword + * gives the ending calendar date, with format 'yyyy-mm-dd', and TIME-END gives the time within that day using the + * format 'hh:mm:ss.sss...'. This keyword should not be used if the time is included directly as part of the + * DATE-END keyword value with the format 'yyyy-mm-ddThh:mm:ss.sss'. + */ + TIME_END("TIME-END", HduType.ANY, ValueType.STRING, "time at the end of the observation"), + + /** + * The value field shall contain a character string that gives the time at which the observation started. This + * keyword is used in conjunction with the standard DATE-OBS keyword to give the starting time of the observation; + * the DATE-OBS keyword gives the starting calendar date, with format 'yyyy-mm-dd', and TIME-OBS gives the time + * within that day using the format 'hh:mm:ss.sss...'. This keyword should not be used if the time is included + * directly as part of the DATE-OBS keyword value with the format 'yyyy-mm-ddThh:mm:ss.sss'. + */ + TIME_OBS("TIME-OBS", HduType.ANY, ValueType.STRING, "time at the start of the observation"), + + // Maxim DL.Extension keywords that may be added or read by MaxIm DL. + // https://github.com/nom-tam-fits/nom-tam-fits/blob/master/src/main/java/nom/tam/fits/header/extra/MaxImDLExt.java + + /** + * if present the image has a valid Bayer color pattern. + */ + BAYERPAT(HduType.IMAGE, ValueType.REAL, "image Bayer color pattern"), + + /** + * Boltwood Cloud Sensor ambient temperature in degrees C. + */ + BOLTAMBT(HduType.IMAGE, ValueType.REAL, "ambient temperature in degrees C"), + + /** + * Boltwood Cloud Sensor cloud condition. + */ + BOLTCLOU(HduType.IMAGE, ValueType.REAL, "Boltwood Cloud Sensor cloud condition."), + + /** + * Boltwood Cloud Sensor daylight level. + */ + BOLTDAY(HduType.IMAGE, ValueType.REAL, "Boltwood Cloud Sensor daylight level."), + + /** + * Boltwood Cloud Sensor dewpoint in degrees C. + */ + BOLTDEW(HduType.IMAGE, ValueType.REAL, "Boltwood Cloud Sensor dewpoint in degrees C."), + + /** + * Boltwood Cloud Sensor humidity in percent. + */ + BOLTHUM(HduType.IMAGE, ValueType.REAL, "Boltwood Cloud Sensor humidity in percent."), + + /** + * Boltwood Cloud Sensor rain condition. + */ + BOLTRAIN(HduType.IMAGE, ValueType.REAL, "Boltwood Cloud Sensor rain condition."), + + /** + * Boltwood Cloud Sensor sky minus ambient temperature in degrees C. + */ + BOLTSKYT(HduType.IMAGE, ValueType.REAL, "Boltwood Cloud Sensor sky minus ambient temperature in degrees C."), + + /** + * Boltwood Cloud Sensor wind speed in km/h. + */ + BOLTWIND(HduType.IMAGE, ValueType.REAL, "Boltwood Cloud Sensor wind speed in km/h."), + + /** + * indicates calibration state of the image; B indicates bias corrected, D indicates dark corrected, F indicates + * flat corrected. + */ + CALSTAT(HduType.IMAGE, ValueType.REAL, "calibration state of the image"), + + /** + * type of color sensor Bayer array or zero for monochrome. + */ + COLORTYP(HduType.IMAGE, ValueType.REAL, "type of color sensor"), + + /** + * initial display screen stretch mode. + */ + CSTRETCH(HduType.IMAGE, ValueType.REAL, "initial display screen stretch mode"), + + /** + * Total dark time of the observation. This is the total time during which dark current is collected by the + * detector. If the times in the extension are different the primary HDU gives one of the extension times. + */ + DARKTIME(HduType.IMAGE, ValueType.REAL, "dark current integration time"), + + /** + * Davis Instruments Weather Station ambient temperature in deg C + */ + DAVAMBT(HduType.IMAGE, ValueType.REAL, "ambient temperature"), + + /** + * Davis Instruments Weather Station barometric pressure in hPa + */ + DAVBAROM(HduType.IMAGE, ValueType.REAL, "barometric pressure"), + + /** + * Davis Instruments Weather Station dewpoint in deg C + */ + DAVDEW(HduType.IMAGE, ValueType.REAL, "dewpoint in deg C"), + + /** + * Davis Instruments Weather Station humidity in percent + */ + DAVHUM(HduType.IMAGE, ValueType.REAL, "humidity in percent"), + + /** + * Davis Instruments Weather Station solar radiation in W/m^2 + */ + DAVRAD(HduType.IMAGE, ValueType.REAL, "solar radiation"), + + /** + * Davis Instruments Weather Station accumulated rainfall in mm/day + */ + DAVRAIN(HduType.IMAGE, ValueType.REAL, "accumulated rainfall"), + + /** + * Davis Instruments Weather Station wind speed in km/h + */ + DAVWIND(HduType.IMAGE, ValueType.REAL, "wind speed"), + + /** + * Davis Instruments Weather Station wind direction in deg + */ + DAVWINDD(HduType.IMAGE, ValueType.REAL, "wind direction"), + + /** + * status of pier flip for German Equatorial mounts. + */ + FLIPSTAT(HduType.IMAGE, ValueType.REAL, "status of pier flip"), + + /** + * Focuser position in steps, if focuser is connected. + */ + FOCUSPOS(HduType.IMAGE, ValueType.REAL, "Focuser position in steps"), + + /** + * Focuser step size in microns, if available. + */ + FOCUSSZ(HduType.IMAGE, ValueType.REAL, "Focuser step size in microns"), + + /** + * Focuser temperature readout in degrees C, if available. + */ + FOCUSTEM(HduType.IMAGE, ValueType.REAL, "Focuser temperature readout"), + + /** + * format of file from which image was read. + */ + INPUTFMT(HduType.IMAGE, ValueType.REAL, "format of file"), + + /** + * ISO camera setting, if camera uses ISO speeds. + */ + ISOSPEED(HduType.IMAGE, ValueType.REAL, "ISO camera setting"), + + /** + * records the geocentric Julian Day of the start of exposure. + */ + JD(HduType.IMAGE, ValueType.REAL, "geocentric Julian Day"), + + /** + * records the geocentric Julian Day of the start of exposure. + */ + JD_GEO(HduType.IMAGE, ValueType.REAL, "geocentric Julian Da"), + + /** + * records the Heliocentric Julian Date at the exposure midpoint. + */ + JD_HELIO(HduType.IMAGE, ValueType.REAL, "Heliocentric Julian Date"), + + /** + * records the Heliocentric Julian Date at the exposure midpoint. + */ + JD_HELIO2("JD-HELIO", HduType.IMAGE, ValueType.REAL, "Heliocentric Julian Date"), + + /** + * UT of midpoint of exposure. + */ + MIDPOINT(HduType.IMAGE, ValueType.REAL, "midpoint of exposure"), + + /** + * user-entered information; free-form notes. + */ + NOTES(HduType.IMAGE, ValueType.REAL, "free-form note"), + + /** + * nominal altitude of center of image + */ + OBJCTALT(HduType.IMAGE, ValueType.REAL, "altitude of center of image"), + + /** + * nominal azimuth of center of image + */ + OBJCTAZ(HduType.IMAGE, ValueType.REAL, "nominal azimuth of center of image"), + + /** + * nominal hour angle of center of image + */ + OBJCTHA(HduType.IMAGE, ValueType.REAL, "nominal hour angle of center of image"), + + /** + * indicates side-of-pier status when connected to a German Equatorial mount. + */ + PIERSIDE(HduType.IMAGE, ValueType.REAL, "side-of-pier status"), + + /** + * records the selected Readout Mode (if any) for the camera. + */ + READOUTM(HduType.IMAGE, ValueType.REAL, "Readout Mode for the camera"), + + /** + * Rotator angle in degrees, if focal plane rotator is connected. + */ + ROTATANG(HduType.IMAGE, ValueType.REAL, "Rotator angle in degrees"), + + /** + * indicates tile position within a mosaic. + */ + TILEXY(HduType.IMAGE, ValueType.REAL, "tile position within a mosaic"), + + /** + * X offset of Bayer array on imaging sensor. + */ + XBAYROFF(HduType.IMAGE, ValueType.REAL, "X offset of Bayer array"), + + /** + * Y offset of Bayer array on imaging sensor. + */ + YBAYROFF(HduType.IMAGE, ValueType.REAL, "Y offset of Bayer array"), + + // NOAO. https://github.com/nom-tam-fits/nom-tam-fits/blob/master/src/main/java/nom/tam/fits/header/extra/NOAOExt.java + + ACTFREQ(HduType.PRIMARY, ValueType.NONE, ""), + ACTHWV(HduType.PRIMARY, ValueType.STRING, ""), + + /** + * Times for the active optics sensor measurements given as modified Julian dates. + */ + ACTMJD(HduType.PRIMARY, ValueType.REAL, ""), + + /** + * Times for the active optics sensor measurements given as modified Julian dates. + */ + ACTMJDn(HduType.PRIMARY, ValueType.REAL, ""), + + /** + * Active optics system position angle measurements in appropriate units. + */ + ACTPAN(HduType.PRIMARY, ValueType.REAL, ""), + + /** + * Active optics system position angle measurements in appropriate units. + */ + ACTPANn(HduType.PRIMARY, ValueType.REAL, ""), + + /** + * Active optics system linear position sensor measurements in appropriate units. + */ + ACTPOS(HduType.PRIMARY, ValueType.REAL, ""), + + /** + * Active optics system linear position sensor measurements in appropriate units. + */ + ACTPOSn(HduType.PRIMARY, ValueType.REAL, ""), + + /** + * Active optics system pressure sensor measurements in appropriate units. + */ + ACTPRE(HduType.PRIMARY, ValueType.REAL, ""), + + /** + * Active optics system pressure sensor measurements in appropriate units. + */ + ACTPREn(HduType.PRIMARY, ValueType.REAL, ""), + + ACTSTAT(HduType.PRIMARY, ValueType.NONE, ""), + + ACTSWV(HduType.PRIMARY, ValueType.NONE, ""), + + /** + * Active optics system temperature sensor measurements in degrees Celsius. + */ + ACTTEM(HduType.PRIMARY, ValueType.REAL, ""), + + /** + * Active optics system temperature sensor measurements in degrees Celsius. + */ + ACTTEMn(HduType.PRIMARY, ValueType.REAL, ""), + + /** + * Active optics voltage sensor measurements in volts. + */ + ACTVOL(HduType.PRIMARY, ValueType.REAL, ""), + + /** + * Active optics voltage sensor measurements in volts. + */ + ACTVOLn(HduType.PRIMARY, ValueType.REAL, ""), + + /** + * Times for the adapter sensor measurements given as modified Julian dates. + */ + ADAMJD(HduType.PRIMARY, ValueType.REAL, ""), + + /** + * Times for the adapter sensor measurements given as modified Julian dates. + */ + ADAMJDn(HduType.PRIMARY, ValueType.REAL, ""), + + /** + * Adapter position angle measurements in appropriate units. + */ + ADAPAN(HduType.PRIMARY, ValueType.REAL, ""), + + /** + * Adapter position angle measurements in appropriate units. + */ + ADAPANn(HduType.PRIMARY, ValueType.REAL, ""), + + /** + * Adapter linear position sensor measurements in appropriate units. + */ + ADAPOS(HduType.PRIMARY, ValueType.REAL, ""), + + /** + * Adapter linear position sensor measurements in appropriate units. + */ + ADAPOSn(HduType.PRIMARY, ValueType.REAL, ""), + + /** + * Adapter pressure sensor measurements in appropriate units. + */ + ADAPRE(HduType.PRIMARY, ValueType.REAL, ""), + + /** + * Adapter pressure sensor measurements in appropriate units. + */ + ADAPREn(HduType.PRIMARY, ValueType.REAL, ""), + + ADAPSWV(HduType.PRIMARY, ValueType.NONE, ""), + + ADAPTER(HduType.PRIMARY, ValueType.NONE, ""), + + ADASTAT(HduType.PRIMARY, ValueType.NONE, ""), + + /** + * Adapter temperature sensor measurements in degrees Celsius. + */ + ADATEM(HduType.PRIMARY, ValueType.REAL, ""), + + /** + * Adapter temperature sensor measurements in degrees Celsius. + */ + ADATEMn(HduType.PRIMARY, ValueType.REAL, ""), + + /** + * Adapter voltage sensor measurements in volts. + */ + ADAVOL(HduType.PRIMARY, ValueType.REAL, ""), + + /** + * Adapter voltage sensor measurements in volts. + */ + ADAVOLn(HduType.PRIMARY, ValueType.REAL, ""), + + /** + * Atmospheric dispersion compensator hardware identification. + */ + ADC(HduType.PRIMARY, ValueType.STRING, "ADC Identification"), + + /** + * Times for the ADC sensor measurements given as modified Julian dates. + */ + ADCMJD(HduType.PRIMARY, ValueType.REAL, ""), + + /** + * Times for the ADC sensor measurements given as modified Julian dates. + */ + ADCMJDn(HduType.PRIMARY, ValueType.REAL, ""), + + /** + * ADC position angle measurements in appropriate units. + */ + ADCPAN(HduType.PRIMARY, ValueType.REAL, ""), + + /** + * ADC position angle measurements in appropriate units. + */ + ADCPANn(HduType.PRIMARY, ValueType.REAL, ""), + + /** + * ADC linear position sensor measurements in appropriate units. + */ + ADCPOS(HduType.PRIMARY, ValueType.REAL, ""), + + /** + * ADC linear position sensor measurements in appropriate units. + */ + ADCPOSn(HduType.PRIMARY, ValueType.REAL, ""), + + /** + * ADC pressure sensor measurements in appropriate units. + */ + ADCPRE(HduType.PRIMARY, ValueType.REAL, ""), + + /** + * ADC pressure sensor measurements in appropriate units. + */ + ADCPREn(HduType.PRIMARY, ValueType.REAL, ""), + + /** + * ADC status. + */ + ADCSTAT(HduType.PRIMARY, ValueType.STRING, ""), + + /** + * Atmospheric dispersion compensator software identification. + */ + ADCSWV(HduType.PRIMARY, ValueType.STRING, "ADC software version"), + + /** + * ADC temperature sensor measurements in degrees Celsius. + */ + ADCTEM(HduType.PRIMARY, ValueType.REAL, ""), + + /** + * ADC temperature sensor measurements in degrees Celsius. + */ + ADCTEMn(HduType.PRIMARY, ValueType.REAL, ""), + + /** + * ADC voltage sensor measurements in volts. + */ + ADCVOL(HduType.PRIMARY, ValueType.REAL, ""), + + /** + * ADC voltage sensor measurements in volts. + */ + ADCVOLn(HduType.PRIMARY, ValueType.REAL, ""), + + /** + * Declination of the aperture(s). + */ + ADECnnn(HduType.PRIMARY, ValueType.STRING, "Aperture declination"), + + /** + * Declination unit. + */ + ADEUnnn(HduType.PRIMARY, ValueType.STRING, "Declination unit"), + + /** + * Object declination for wavefront sensing. + */ + ADODEC(HduType.PRIMARY, ValueType.STRING, "Adaptive optics object declination"), + + /** + * Declination unit. + */ + ADODECU(HduType.PRIMARY, ValueType.STRING, "Declination unit"), + + /** + * Object coordinate epoch for wavefront sensing. + */ + ADOEPOCH(HduType.PRIMARY, ValueType.NONE, ""), + + /** + * Object coordinate system equinox for wavefront sensing. A value before 1984 is Besselian otherwise it is Julian. + */ + ADOEQUIN(HduType.PRIMARY, ValueType.REAL, ""), + + ADOFREQ(HduType.PRIMARY, ValueType.NONE, ""), + + ADOHWV(HduType.PRIMARY, ValueType.NONE, ""), + + /** + * Times for the adaptive optics sensor measurements given as modified Julian dates. + */ + ADOMJD(HduType.PRIMARY, ValueType.REAL, ""), + + /** + * Times for the adaptive optics sensor measurements given as modified Julian dates. + */ + ADOMJDn(HduType.PRIMARY, ValueType.REAL, ""), + + /** + * Adaptive optics system position angle measurements in appropriate units. + */ + ADOPAN(HduType.PRIMARY, ValueType.REAL, ""), + + /** + * Adaptive optics system position angle measurements in appropriate units. + */ + ADOPANn(HduType.PRIMARY, ValueType.REAL, ""), + + /** + * Adaptive optics system linear position sensor measurements in appropriate units. + */ + ADOPOS(HduType.PRIMARY, ValueType.REAL, ""), + + /** + * Adaptive optics system linear position sensor measurements in appropriate units. + */ + ADOPOSn(HduType.PRIMARY, ValueType.REAL, ""), + + /** + * Adaptive optics system pressure sensor measurements in appropriate units. + */ + ADOPRE(HduType.PRIMARY, ValueType.REAL, ""), + + /** + * Adaptive optics system pressure sensor measurements in appropriate units. + */ + ADOPREn(HduType.PRIMARY, ValueType.REAL, ""), + + /** + * Object right ascension for wavefront sensing. + */ + ADORA(HduType.PRIMARY, ValueType.STRING, "Adaptive optics object right ascension"), + + /** + * Object coordinate system type for wavefront sensing. + */ + ADORADEC(HduType.PRIMARY, ValueType.STRING, ""), + + /** + * Right ascension unit. + */ + ADORAU(HduType.PRIMARY, ValueType.STRING, "Right ascension unit"), + + ADOSTAT(HduType.PRIMARY, ValueType.NONE, ""), + ADOSWV(HduType.PRIMARY, ValueType.NONE, ""), + + /** + * Adaptive optics system temperature sensor measurements in degrees Celsius. + */ + ADOTEM(HduType.PRIMARY, ValueType.REAL, ""), + + /** + * Adaptive optics system temperature sensor measurements in degrees Celsius. + */ + ADOTEMn(HduType.PRIMARY, ValueType.REAL, ""), + + /** + * Type of object used for wavefront sensing. + */ + ADOTYPE(HduType.PRIMARY, ValueType.STRING, "Adaptive optics object type"), + + /** + * Adaptive optics system voltage sensor measurements in volts. + */ + ADOVOL(HduType.PRIMARY, ValueType.REAL, ""), + + /** + * Adaptive optics system voltage sensor measurements in volts. + */ + ADOVOLn(HduType.PRIMARY, ValueType.REAL, ""), + + /** + * Epoch of the coordinates for the aperture(s). + */ + AEPOnnn(HduType.PRIMARY, ValueType.REAL, "Aperture coordinate epoch"), + + /** + * Coordinate system equinox for the aperture(s). A value before 1984 is Besselian otherwise it is Julian. + */ + AEQUnnn(HduType.PRIMARY, ValueType.REAL, "Aperture coordinate equinox"), + + /** + * The computed airmass(es) at the time(s) given by the AMMJDn keywords. + */ + AIRMASSn(HduType.PRIMARY, ValueType.REAL, "Airmass"), + + /** + * Times for the airmass calculation given as modified Julian dates. The MJDHDR keyword may be used for the time at + * which the image header is created or the MJD-OBS keyword may be used for the time of observation. + */ + AMMJD(HduType.PRIMARY, ValueType.REAL, "MJD of airmass"), + + /** + * Times for the airmass calculation given as modified Julian dates. The MJDHDR keyword may be used for the time at + * which the image header is created or the MJD-OBS keyword may be used for the time of observation. + */ + AMMJDn(HduType.PRIMARY, ValueType.REAL, "MJD of airmass"), + + /** + * Amplifier integration or sample time. + */ + AMPINTEG(HduType.PRIMARY_EXTENSION, ValueType.REAL, "Amplifier integration/sample time"), + + /** + * Times for the amplifier sensor measurements given as modified Julian dates. The MJDHDR keyword may be used for + * the time at which the image header is created or the MJD-OBS keyword may be used for the time of observation. + */ + AMPMJD(HduType.PRIMARY_EXTENSION, ValueType.REAL, ""), + + /** + * Times for the amplifier sensor measurements given as modified Julian dates. The MJDHDR keyword may be used for + * the time at which the image header is created or the MJD-OBS keyword may be used for the time of observation. + */ + AMPMJDn(HduType.PRIMARY_EXTENSION, ValueType.REAL, ""), + + /** + * Amplifier name. + */ + AMPNAME(HduType.EXTENSION, ValueType.STRING, "Amplifier name"), + + /** + * CCD amplifier position angle measurements in appropriate units. + */ + AMPPAN(HduType.PRIMARY_EXTENSION, ValueType.REAL, ""), + + /** + * CCD amplifier position angle measurements in appropriate units. + */ + AMPPANn(HduType.PRIMARY_EXTENSION, ValueType.REAL, ""), + + /** + * CCD amplifier linear position sensor measurements in appropriate units. + */ + AMPPOS(HduType.PRIMARY_EXTENSION, ValueType.REAL, ""), + + /** + * CCD amplifier linear position sensor measurements in appropriate units. + */ + AMPPOSn(HduType.PRIMARY_EXTENSION, ValueType.REAL, ""), + + /** + * CCD amplifier pressure sensor measurements in appropriate units. + */ + AMPPRE(HduType.PRIMARY_EXTENSION, ValueType.REAL, ""), + + /** + * CCD amplifier pressure sensor measurements in appropriate units. + */ + AMPPREn(HduType.PRIMARY_EXTENSION, ValueType.REAL, ""), + + /** + * Amplifier unbinned pixel read time. + */ + AMPREAD(HduType.PRIMARY_EXTENSION, ValueType.REAL, "Unbinned pixel read time"), + + /** + * CCD amplifier sampling method used. This may also include any integration times. + */ + AMPSAMPL(HduType.PRIMARY_EXTENSION, ValueType.STRING, "Amplifier sampling method"), + + /** + * Mapping of the CCD section to amplifier coordinates. + */ + AMPSEC(HduType.EXTENSION, ValueType.STRING, "Amplifier section"), + + /** + * The logical unbinned size of the amplifier readout in section notation. This includes drift scanning if + * applicable. + */ + AMPSIZE(HduType.EXTENSION, ValueType.STRING, "Amplifier readout size"), + + /** + * CCD amplifier temperature sensor measurements in degrees Celsius. + */ + AMPTEM(HduType.PRIMARY_EXTENSION, ValueType.REAL, ""), + + /** + * CCD amplifier temperature sensor measurements in degrees Celsius. + */ + AMPTEMn(HduType.PRIMARY_EXTENSION, ValueType.REAL, ""), + + /** + * CCD amplifier voltage sensor measurements in volts. } + */ + AMPVOL(HduType.PRIMARY_EXTENSION, ValueType.REAL, ""), + + /** + * CCD amplifier voltage sensor measurements in volts. } + */ + AMPVOLn(HduType.PRIMARY_EXTENSION, ValueType.REAL, ""), + + /** + * Aperture position angle unit. + */ + APAUnnn(HduType.PRIMARY, ValueType.STRING, "Aperture position angle unit"), + + /** + * Declination of the aperture(s). + */ + APDEC(HduType.PRIMARY, ValueType.STRING, "Aperture declination"), + + /** + * Declination unit. + */ + APDECU(HduType.PRIMARY, ValueType.STRING, "Declination unit"), + + /** + * Aperture diameter of the aperture(s) for circular apertures and fibers. This is also used as an approximation to + * the size of hexagonal lenses. + */ + APDInnn(HduType.PRIMARY, ValueType.REAL, "Aperture diameter"), + + /** + * Epoch of the coordinates for the aperture(s). + */ + APEPOCH(HduType.PRIMARY, ValueType.REAL, "Aperture coordinate epoch"), + + /** + * Coordinate system equinox for the aperture(s). A value before 1984 is Besselian otherwise it is Julian. + */ + APEQUIN(HduType.PRIMARY, ValueType.REAL, "Aperture coordinate equinox"), + + /** + * Aperture diameter of the aperture(s) for circular apertures and fibers. This is also used as an approximation to + * the size of hexagonal lenses. + */ + APERDIA(HduType.PRIMARY, ValueType.REAL, "Aperture diameter"), + + /** + * Aperture length of the aperture(s) for slit apertures. + */ + APERLEN(HduType.PRIMARY, ValueType.REAL, "Slit length"), + + /** + * Aperture identification. This can be a physical aperture identification, the name of a mask, a fiber + * configuration, etc. When there are many apertures the keyword APERTURE may be used to specify a configuration or + * mask identification and the APER%4d keywords can be used to identify some information about the aperture such as + * a fiber number. + */ + APERnnn(HduType.PRIMARY, ValueType.STRING, "Aperture identification"), + + /** + * Aperture position angle of the aperture(s) on the sky. This is measured using the longest dimension from north to + * east for slits. For hexagonal lenslets it gives the position angle for one of the sides. + */ + APERPA(HduType.PRIMARY, ValueType.REAL, "Aperture position angle"), + + /** + * Aperture identification. This can be a physical aperture identification, the name of a mask, a fiber + * configuration, etc. When there are many apertures the keyword APERTURE may be used to specify a configuration or + * mask identification and the APER%4d keywords can be used to identify some information about the aperture such as + * a fiber number. + */ + APERWID(HduType.PRIMARY, ValueType.REAL, "Slit width"), + + /** + * Aperture length of the aperture(s) for slit apertures. + */ + APLEnnn(HduType.PRIMARY, ValueType.REAL, "Slit length"), + + /** + * Aperture position angle of the aperture(s) on the sky. This is measured using the longest dimension from north to + * east for slits. For hexagonal lenslets it gives the position angle for one of the sides. + */ + APPAnnn(HduType.PRIMARY, ValueType.REAL, "Aperture position angle"), + + /** + * Aperture position angle unit. + */ + APPAUNIT(HduType.PRIMARY, ValueType.STRING, "Aperture position angle unit"), + + /** + * Right ascension of the aperture(s). + */ + APRA(HduType.PRIMARY, ValueType.STRING, "Aperture right ascension"), + + /** + * Aperture coordinate system type for the aperture(s). + */ + APRADEC(HduType.PRIMARY, ValueType.STRING, "Aperture coordinate system"), + + /** + * Right ascension unit. + */ + APRAU(HduType.PRIMARY, ValueType.STRING, "Right ascension unit"), + + /** + * Aperture type. This is an from a dictionary. The common types are "slit", "hole", "fiber", "hexlens", + * "hexlens+fiber" and "none". The last type is for aperture-less spectroscopy such as with objective prisms. + * Typically for multiobject spectroscopy all the aperture types will be the same and the keyword will be APTYPE. + */ + APTYnnn(HduType.PRIMARY, ValueType.STRING, "Aperture type"), + + /** + * Aperture type. This is an from a dictionary. The common types are "slit", "hole", "fiber", "hexlens", + * "hexlens+fiber" and "none". The last type is for aperture-less spectroscopy such as with objective prisms. + * Typically for multiobject spectroscopy all the aperture types will be the same and the keyword will be APTYPE. + */ + APTYPE(HduType.PRIMARY, ValueType.STRING, "Aperture type"), + + /** + * Units of aperture dimensions. This applies to slit widths and lengths, fiber diameters, lenslet diameters, etc. + * It may be a physical dimension or a projected angle on the sky. + */ + APUNIT(HduType.PRIMARY, ValueType.STRING, "Aperture dimension unit"), + + /** + * Units of aperture dimensions. This applies to slit widths and lengths, fiber diameters, lenslet diameters, etc. + * It may be a physical dimension or a projected angle on the sky. + */ + APUNnnn(HduType.PRIMARY, ValueType.STRING, "Aperture dimension unit"), + + /** + * Aperture width of the aperture(s) for slit apertures. + */ + APWInnn(HduType.PRIMARY, ValueType.REAL, "Slit width"), + + /** + * Right ascension of the aperture(s). + */ + ARAnnn(HduType.PRIMARY, ValueType.STRING, "Aperture right ascension"), + + /** + * Right ascension unit. + */ + ARAUnnn(HduType.PRIMARY, ValueType.STRING, "Right ascension unit"), + + /** + * Archive hardware version. + */ + ARCHHWV(HduType.PRIMARY, ValueType.STRING, "Archive hardware"), + + /** + * Archive identification. This may be the same as the observation identification. + */ + ARCHID(HduType.PRIMARY, ValueType.STRING, "Archive identification"), + + /** + * The archive name in which the observation is archived. + */ + ARCHIVE(HduType.PRIMARY, ValueType.STRING, "Archive"), + + /** + * Archive status of data. + */ + ARCHSTAT(HduType.PRIMARY, ValueType.STRING, "Archive status"), + + /** + * Archive software version. + */ + ARCHSWV(HduType.PRIMARY, ValueType.STRING, "Archive software version"), + + /** + * Arcon predicted gain. This is the gain measured in the laboratory. The GAIN keyword may also have this value + * initially but it is updated to the most recent estimate of the gain. + */ + ARCONG(HduType.EXTENSION, ValueType.REAL, "Predicted gain"), + + /** + * Arcon gain index ValueType. + */ + ARCONGI(HduType.EXTENSION, ValueType.INTEGER, "Gain selection"), + + /** + * Arcon predicted RMS readout noise. This is the value measured in the laboratory. The RDNOISE keyword may also + * have this value initially but it is updated to the most current estimate. + */ + ARCONRN(HduType.EXTENSION, ValueType.REAL, "Predicted readout noise"), + + /** + * Arcon waveform complilation date. + */ + ARCONWD(HduType.PRIMARY_EXTENSION, ValueType.STRING, "Date CCD waveforms last compiled"), + + /** + * Arcon waveform options enabled. + */ + ARCONWM(HduType.PRIMARY_EXTENSION, ValueType.STRING, "Arcon waveform options enabled"), + + /** + * Aperture coordinate system type for the aperture(s). + */ + ARDSnnn(HduType.PRIMARY, ValueType.STRING, "Aperture coordinate system"), + + /** + * Transformation matrix between CCD and amplifier coordinates. Normally only two values will be non-zero and will + * have values of 1 or -1. If missing the default is an identify matrix. + */ + ATMn_n(HduType.EXTENSION, ValueType.REAL, "Amplifier transformation matrix"), + + /** + * Transformation origin vector between CCD and amplifier coordinates. + */ + ATVn(HduType.EXTENSION, ValueType.REAL, "Amplifier transformation vector"), + + /** + * Section of the recorded image containing overscan or prescan data. This will be in binned pixels if binning is + * done. Multiple regions may be recorded and specified, such as both prescan and overscan, but the first section + * given by this parameter is likely to be the one used during calibration. + */ + BIASnnn(HduType.EXTENSION, ValueType.STRING, "Bias section"), + + /** + * Section of the recorded image containing overscan or prescan data. This will be in binned pixels if binning is + * done. Multiple regions may be recorded and specified, such as both prescan and overscan, but the first section + * given by this parameter is likely to be the one used during calibration. + */ + BIASSEC(HduType.EXTENSION, ValueType.STRING, "Bias section"), + + /** + * Description of bad pixels. The value is an IRAF bad pixel mask name. + */ + BPM(HduType.PRIMARY_EXTENSION, ValueType.STRING, "Bad pixels"), + + /** + * Camera configuration. + */ + CAMCONF(HduType.PRIMARY, ValueType.STRING, "Camera Configuration"), + + /** + * Camera name. + */ + CAMERA(HduType.PRIMARY, ValueType.STRING, "Camera name"), + + /** + * Camera focus. + */ + CAMFOCUS(HduType.PRIMARY, ValueType.REAL, "Camera focus"), + + /** + * Camera hardware version. + */ + CAMHWV(HduType.PRIMARY, ValueType.STRING, "Camera version"), + + /** + * Times for the instrument sensor measurements given as modified Julian dates. + */ + CAMMJD(HduType.PRIMARY, ValueType.REAL, ""), + + /** + * Times for the instrument sensor measurements given as modified Julian dates. + */ + CAMMJDn(HduType.PRIMARY, ValueType.REAL, ""), + + /** + * Camera position angle measurements in appropriate units. + */ + CAMPAN(HduType.PRIMARY, ValueType.REAL, "Camera position angle"), + + /** + * Camera position angle measurements in appropriate units. + */ + CAMPANn(HduType.PRIMARY, ValueType.REAL, "Camera position angle"), + + /** + * Camera linear position sensor measurements in appropriate units. + */ + CAMPOS(HduType.PRIMARY, ValueType.REAL, ""), + + /** + * Camera linear position sensor measurements in appropriate units. + */ + CAMPOSn(HduType.PRIMARY, ValueType.REAL, ""), + + /** + * Camera pressure sensor measurements in appropriate units. + */ + CAMPRE(HduType.PRIMARY, ValueType.REAL, ""), + + /** + * Camera pressure sensor measurements in appropriate units. + */ + CAMPREn(HduType.PRIMARY, ValueType.REAL, ""), + + /** + * Camera status. + */ + CAMSTAT(HduType.PRIMARY, ValueType.STRING, "Camera status"), + + /** + * Camera software version. + */ + CAMSWV(HduType.PRIMARY, ValueType.STRING, "Camera software version"), + + /** + * Camera temperature sensor measurements in degrees Celsius. + */ + CAMTEM(HduType.PRIMARY, ValueType.REAL, ""), + + /** + * Camera temperature sensor measurements in degrees Celsius. + */ + CAMTEMn(HduType.PRIMARY, ValueType.REAL, ""), + + /** + * Camera voltage sensor measurements in volts. + */ + CAMVOL(HduType.PRIMARY, ValueType.REAL, ""), + + /** + * Camera voltage sensor measurements in volts. + */ + CAMVOLn(HduType.PRIMARY, ValueType.REAL, ""), + + /** + * Declination of the CCD center. + */ + CCDDEC(HduType.PRIMARY_EXTENSION, ValueType.STRING, "CCD declination"), + + /** + * Declination unit. + */ + CCDDECU(HduType.PRIMARY_EXTENSION, ValueType.STRING, "Declination unit"), + + /** + * Epoch of the CCD center coordinates. + */ + CCDEPOCH(HduType.PRIMARY_EXTENSION, ValueType.REAL, "CCD coordinate epoch"), + + /** + * CCD coordinate system equinox. A value before 1984 is Besselian otherwise it is Julian. + */ + CCDEQUIN(HduType.PRIMARY_EXTENSION, ValueType.REAL, "CCD coordinate equinox"), + + /** + * CCD hardware version + */ + CCDHWV(HduType.PRIMARY_EXTENSION, ValueType.STRING, "CCD version"), + + /** + * Times for the CCD sensor measurements given as modified Julian dates. The MJDHDR keyword may be used for the time + * at which the image header is created or the MJD-OBS keyword may be used for the time of observation. + */ + CCDMJD(HduType.PRIMARY_EXTENSION, ValueType.REAL, ""), + + /** + * Times for the CCD sensor measurements given as modified Julian dates. The MJDHDR keyword may be used for the time + * at which the image header is created or the MJD-OBS keyword may be used for the time of observation. + */ + CCDMJDn(HduType.PRIMARY_EXTENSION, ValueType.REAL, ""), + + /** + * CCD identification. + */ + CCDNAME(HduType.PRIMARY_EXTENSION, ValueType.STRING, "CCD identification"), + + /** + * Number of amplifiers used to readout the CCD. This keyword may be absent if only one amplifier is used. + */ + CCDNAMPS(HduType.PRIMARY_EXTENSION, ValueType.INTEGER, "Number of amplifiers used"), + + /** + * CCD position angle measurements in appropriate units. + */ + CCDPAN(HduType.PRIMARY_EXTENSION, ValueType.REAL, ""), + + /** + * CCD position angle measurements in appropriate units. + */ + CCDPANn(HduType.PRIMARY_EXTENSION, ValueType.REAL, ""), + + /** + * CCD linear position sensor measurements in appropriate units. + */ + CCDPOS(HduType.PRIMARY_EXTENSION, ValueType.REAL, ""), + + /** + * CCD linear position sensor measurements in appropriate units. + */ + CCDPOSn(HduType.PRIMARY_EXTENSION, ValueType.REAL, ""), + + /** + * CCD pressure sensor measurements in appropriate units. + */ + CCDPRE(HduType.PRIMARY_EXTENSION, ValueType.REAL, ""), + + /** + * CCD pressure sensor measurements in appropriate units. + */ + CCDPREn(HduType.PRIMARY_EXTENSION, ValueType.REAL, ""), + + /** + * The actual format size of the CCD. This is the same as the CCDSIZE keyword except in the case of drift scanning. + */ + CCDPSIZE(HduType.PRIMARY_EXTENSION, ValueType.STRING, "CCD size"), + + /** + * Right ascension of the CCD center. + */ + CCDRA(HduType.PRIMARY_EXTENSION, ValueType.STRING, "CCD right ascension"), + + /** + * CCD coordinate system type. + */ + CCDRADEC(HduType.PRIMARY_EXTENSION, ValueType.STRING, "CCD coordinate system"), + + /** + * Right ascension unit. + */ + CCDRAU(HduType.PRIMARY_EXTENSION, ValueType.STRING, "Right ascension unit"), + + /** + * The unbinned section of the logical CCD pixel raster covered by the amplifier readout in section notation. The + * section must map directly to the specified data section through the binning and CCD to image coordiante + * transformation. The image data section (DATASEC) is specified with the starting pixel less than the ending pixel. + * Thus the order of this section may be flipped depending on the coordinate transformation (which depends on how + * the CCD coordinate system is defined). + */ + CCDSEC(HduType.EXTENSION, ValueType.STRING, "Region of CCD read"), + + /** + * The logical unbinned size of the CCD in section notation. Normally this would be the physical size of the CCD + * unless drift scanning is done. This is the full size even when subraster readouts are done. + */ + CCDSIZE(HduType.PRIMARY_EXTENSION, ValueType.STRING, "CCD size"), + + /** + * CCD on-chip summing given as two or four integer numbers. These define the summing of CCD pixels in the amplifier + * readout order. The first two numbers give the number of pixels summed in the serial and parallel directions + * respectively. If the first pixel read out consists of fewer unbinned pixels along either direction the next two + * numbers give the number of pixels summed for the first serial and parallel pixels. From this it is implicit how + * many pixels are summed for the last pixels given the size of the CCD section (CCDSEC). It is highly recommended + * that controllers read out all pixels with the same summing in which case the size of the CCD section will be the + * summing factors times the size of the data section. + */ + CCDSUM(HduType.EXTENSION, ValueType.STRING, "CCD on-chip summing"), + + /** + * CCD software version + */ + CCDSWV(HduType.PRIMARY_EXTENSION, ValueType.STRING, "CCD software version"), + + /** + * CCD temperature sensor measurements in degrees Celsius. + */ + CCDTEM(HduType.PRIMARY_EXTENSION, ValueType.REAL, "CCD temperature"), + + /** + * CCD temperature sensor measurements in degrees Celsius. + */ + CCDTEMn(HduType.PRIMARY_EXTENSION, ValueType.REAL, "CCD temperature"), + + /** + * CCD voltage sensor measurements in volts. + */ + CCDVOL(HduType.PRIMARY_EXTENSION, ValueType.REAL, ""), + + /** + * CCD voltage sensor measurements in volts. + */ + CCDVOLn(HduType.PRIMARY_EXTENSION, ValueType.REAL, ""), + + /** + * Spectrum coordinate matrix. World coordinate axis 1 is defined to be the dispersion and the other axes are + * spatial. The matrix implies a dispersion axis in the image coordinates. + */ + CD1_1(HduType.EXTENSION, ValueType.REAL, "Coordinate scale matrix"), + + /** + * Spectrum coordinate matrix. World coordinate axis 1 is defined to be the dispersion and the other axes are + * spatial. The matrix implies a dispersion axis in the image coordinates. + */ + CD1_2(HduType.EXTENSION, ValueType.REAL, "Coordinate scale matrix"), + + /** + * Spectrum coordinate matrix. World coordinate axis 1 is defined to be the dispersion and the other axes are + * spatial. The matrix implies a dispersion axis in the image coordinates. + */ + CD11nnn(HduType.EXTENSION, ValueType.REAL, "Coordinate scale matrix"), + + /** + * Spectrum coordinate matrix. World coordinate axis 1 is defined to be the dispersion and the other axes are + * spatial. The matrix implies a dispersion axis in the image coordinates. + */ + CD12nnn(HduType.EXTENSION, ValueType.REAL, "Coordinate scale matrix"), + + /** + * Spectrum coordinate matrix. World coordinate axis 1 is defined to be the dispersion and the other axes are + * spatial. The matrix implies a dispersion axis in the image coordinates. + */ + CD2_1(HduType.EXTENSION, ValueType.REAL, "Coordinate scale matrix"), + + /** + * Spectrum coordinate matrix. World coordinate axis 1 is defined to be the dispersion and the other axes are + * spatial. The matrix implies a dispersion axis in the image coordinates. + */ + CD2_2(HduType.EXTENSION, ValueType.REAL, "Coordinate scale matrix"), + + /** + * Spectrum coordinate matrix. World coordinate axis 1 is defined to be the dispersion and the other axes are + * spatial. The matrix implies a dispersion axis in the image coordinates. + */ + CD21nnn(HduType.EXTENSION, ValueType.REAL, "Coordinate scale matrix"), + + /** + * Spectrum coordinate matrix. World coordinate axis 1 is defined to be the dispersion and the other axes are + * spatial. The matrix implies a dispersion axis in the image coordinates. + */ + CD22nnn(HduType.EXTENSION, ValueType.REAL, "Spec coord matrix"), + + /** + * Coordinate scale matrix for image world coordinates. This describes the scales and rotations of the coordinate + * axes. + */ + CHPANGLE(HduType.PRIMARY, ValueType.NONE, ""), + + CHPDIST(HduType.PRIMARY, ValueType.NONE, ""), + + CHPFREQ(HduType.PRIMARY, ValueType.NONE, ""), + + CHPHWV(HduType.PRIMARY, ValueType.NONE, ""), + + /** + * Times for the chopping system sensor measurements given as modified Julian dates. + */ + CHPMJD(HduType.PRIMARY, ValueType.REAL, ""), + + /** + * Times for the chopping system sensor measurements given as modified Julian dates. + */ + CHPMJDn(HduType.PRIMARY, ValueType.REAL, ""), + + CHPNCHOP(HduType.PRIMARY, ValueType.NONE, ""), + + /** + * Chopping system position angle measurements in appropriate units. Note that CHPANGLE should be used for the + * chopping angle and these keywords are for other system position angle measurements. + */ + CHPPAN(HduType.PRIMARY, ValueType.REAL, ""), + + /** + * Chopping system position angle measurements in appropriate units. Note that CHPANGLE should be used for the + * chopping angle and these keywords are for other system position angle measurements. + */ + CHPPANn(HduType.PRIMARY, ValueType.REAL, ""), + + /** + * Chopping system linear position sensor measurements in appropriate units. + */ + CHPPOS(HduType.PRIMARY, ValueType.REAL, ""), + + /** + * Chopping system linear position sensor measurements in appropriate units. + */ + CHPPOSn(HduType.PRIMARY, ValueType.REAL, ""), + + /** + * Chopping system pressure sensor measurements in appropriate units. + */ + CHPPRE(HduType.PRIMARY, ValueType.REAL, ""), + + /** + * Chopping system pressure sensor measurements in appropriate units. + */ + CHPPREn(HduType.PRIMARY, ValueType.REAL, ""), + + CHPSTAT(HduType.PRIMARY, ValueType.NONE, ""), + + CHPSWV(HduType.PRIMARY, ValueType.NONE, ""), + + /** + * Chopping system temperature sensor measurements in degrees Celsius. + */ + CHPTEM(HduType.PRIMARY, ValueType.REAL, ""), + + /** + * Chopping system temperature sensor measurements in degrees Celsius. + */ + CHPTEMn(HduType.PRIMARY, ValueType.REAL, ""), + + /** + * Chopping system voltage sensor measurements in volts. + */ + CHPVOL(HduType.PRIMARY, ValueType.REAL, ""), + + /** + * Chopping system voltage sensor measurements in volts. + */ + CHPVOLn(HduType.PRIMARY, ValueType.REAL, ""), + + /** + * Dispersion limit for the region occupied by the spectrum. + */ + CMAX1(HduType.EXTENSION, ValueType.REAL, "Spectrum dispersion limit"), + + /** + * Cross-dispersion limit for the region occupied by the spectrum. + */ + CMAX2(HduType.EXTENSION, ValueType.REAL, "Spectrum cross-dispersion limit"), + + /** + * Dispersion limit for the region occupied by the spectrum. + */ + CMIN1(HduType.EXTENSION, ValueType.REAL, "Spectrum dispersion limit"), + + /** + * Cross-dispersion limit for the region occupied by the spectrum. + */ + CMIN2(HduType.EXTENSION, ValueType.REAL, "Spectrum cross-dispersion limit"), + + /** + * Observer comments. + */ + CMMTnnn(HduType.PRIMARY, ValueType.STRING, ""), + + /** + * Dispersion limit for the region occupied by the spectrum. + */ + CMN1nnn(HduType.EXTENSION, ValueType.REAL, "Spectrum dispersion limit"), + + /** + * Cross-dispersion limit for the region occupied by the spectrum. + */ + CMN2nnn(HduType.EXTENSION, ValueType.REAL, "Spectrum cross-dispersion limit"), + + /** + * Dispersion limit for the region occupied by the spectrum. + */ + CMX1nnn(HduType.EXTENSION, ValueType.REAL, "Spectrum dispersion limit"), + + /** + * Cross-dispersion limit for the region occupied by the spectrum. + */ + CMX2nnn(HduType.EXTENSION, ValueType.REAL, "Spectrum cross-dispersion limit"), + + /** + * Controller hardware version. + */ + CONHWV(HduType.PRIMARY_EXTENSION, ValueType.STRING, "Controller hardware version"), + + /** + * Controller status. + */ + CONSTAT(HduType.PRIMARY_EXTENSION, ValueType.STRING, "Controller status"), + + /** + * Controller software version. + */ + CONSWV(HduType.PRIMARY_EXTENSION, ValueType.STRING, "Controller software version"), + + /** + * Detector controller name. + */ + CONTROLR(HduType.PRIMARY_EXTENSION, ValueType.STRING, "Detector controller"), + + /** + * Correctors in the optical path. + */ + CORRCT(HduType.PRIMARY, ValueType.STRING, "Corrector"), + + /** + * Correctors in the optical path. + */ + CORRCTn(HduType.PRIMARY, ValueType.STRING, "Corrector"), + + /** + * Correctors in the optical path. + */ + CORRCTOR(HduType.PRIMARY, ValueType.STRING, "Corrector Identification"), + + /** + * Default cross dispersion unit. + */ + CROSUNIT(HduType.PRIMARY_EXTENSION, ValueType.STRING, "Declination unit"), + + /** + * Default cross dispersion coordinate ValueType. + */ + CROSVAL(HduType.PRIMARY_EXTENSION, ValueType.REAL, "Cross dispersion coordinate"), + + /** + * Reference spectrum pixel coordinate. Generally this should be the at the center of the spectrum. In raw data the + * spectrum position(s) may be predicted apart from an offset that will be determined during data reduction. + */ + CRP1nnn(HduType.EXTENSION, ValueType.REAL, "Coordinate reference pixel"), + + /** + * Reference spectrum pixel coordinate. Generally this should be the at the center of the spectrum. In raw data the + * spectrum position(s) may be predicted apart from an offset that will be determined during data reduction. + */ + CRP2nnn(HduType.EXTENSION, ValueType.REAL, "Coordinate reference pixel"), + + /** + * Reference spectrum pixel coordinate. Generally this should be the at the center of the spectrum. In raw data the + * spectrum position(s) may be predicted apart from an offset that will be determined during data reduction. + */ + CRPIX1(HduType.EXTENSION, ValueType.REAL, "Coordinate reference pixel"), + + /** + * Reference spectrum pixel coordinate. Generally this should be the at the center of the spectrum. In raw data the + * spectrum position(s) may be predicted apart from an offset that will be determined during data reduction. + */ + CRPIX2(HduType.EXTENSION, ValueType.REAL, "Coordinate reference pixel"), + + /** + * Spectrum reference dispersion coordinate corresponding to the spectrum reference pixel coordinate. Note that by + * definition WCS axis 1 is always the dispersion axis. The mapping of this WCS axis to the dispersion direction in + * the image is given by the coordinate transformation matrix keywords. In raw data the reference dispersion + * coordinate may be approximately predicted. This will be refined during data reductions. + */ + CRV1nnn(HduType.EXTENSION, ValueType.REAL, "Coordinate reference value"), + + /** + * Spectrum reference dispersion coordinate corresponding to the spectrum reference pixel coordinate. Note that by + * definition WCS axis 1 is always the dispersion axis. The mapping of this WCS axis to the dispersion direction in + * the image is given by the coordinate transformation matrix keywords. In raw data the reference dispersion + * coordinate may be approximately predicted. This will be refined during data reductions. + */ + CRV2nnn(HduType.EXTENSION, ValueType.REAL, "Coordinate reference value"), + + /** + * Spectrum reference dispersion coordinate corresponding to the spectrum reference pixel coordinate. Note that by + * definition WCS axis 1 is always the dispersion axis. The mapping of this WCS axis to the dispersion direction in + * the image is given by the coordinate transformation matrix keywords. In raw data the reference dispersion + * coordinate may be approximately predicted. This will be refined during data reductions. + */ + CRVAL1(HduType.EXTENSION, ValueType.REAL, "Spectrum dispersion center"), + + /** + * Reference right ascension coordinate corresponding to the image reference pixel coordinate. Note that by + * definition WCS axis 1 is always the right ascension axis. The mapping of this WCS axis to the right ascension + * direction in the image is given by the coordinate transformation matrix keywords. In raw data the reference right + * ascension coordinate may be only approximate. This will be refined during data reductions. + */ + CRVAL2(HduType.EXTENSION, ValueType.REAL, "Spectrum cross-dispersion center"), + + /** + * Reference declination coordinate corresponding to the image reference pixel coordinate. Note that by definition + * WCS axis 1 is always the declination axis. The mapping of this WCS axis to the declination direction in the image + * is given by the coordinate transformation matrix keywords. In raw data the reference right ascension coordinate + * may be only approximate. This will be refined during data reductions. + */ + CTY1nnn(HduType.EXTENSION, ValueType.STRING, "Spectrum coordinate type"), + + /** + * Coordinate type for image world coordinates. The IRAF WCS standards are used (which is generally the FITS + * standard). + */ + CTY2nnn(HduType.EXTENSION, ValueType.STRING, "Spectrum coordinate type"), + + /** + * Coordinate type for image world coordinates. The IRAF WCS standards are used (which is generally the FITS + * standard). + */ + CTYP2nnn(HduType.EXTENSION, ValueType.STRING, "Coordinate type"), + + /** + * Spectrum dispersion coordinate type. These are the FITS defined types. + */ + CTYPE1(HduType.EXTENSION, ValueType.STRING, "Spectrum coordinate type"), + + /** + * Coordinate type for image world coordinates. The IRAF WCS standards are used (which is generally the FITS + * standard). + */ + CTYPE2(HduType.EXTENSION, ValueType.STRING, "Spectrum coordinate type"), + + /** + * Coordinate type for image world coordinates. The IRAF WCS standards are used (which is generally the FITS + * standard). + */ + CUN1nnn(HduType.EXTENSION, ValueType.STRING, "Spectrum coordinate unit"), + + /** + * Coordinate reference unit for direct imaging world coordinates. + */ + CUN2nnn(HduType.EXTENSION, ValueType.STRING, "Spectrum coordinate unit"), + + /** + * Coordinate reference unit for direct imaging world coordinates. + */ + CUNIT1(HduType.EXTENSION, ValueType.STRING, "Spectrum coordinate unit"), + + /** + * Coordinate reference unit for direct imaging world coordinates. + */ + CUNIT2(HduType.EXTENSION, ValueType.STRING, "Coordinate reference unit"), + + /** + * Mapping of the CCD section to image coordinates. + */ + DATASEC(HduType.EXTENSION, ValueType.STRING, "Image data section"), + + /** + * Date at the end of the exposure. The format follows the FITS standard. + */ + DATEEND(HduType.PRIMARY_EXTENSION, ValueType.STRING, "Date at end of exposure"), + + /** + * Date header creation. The format follows the FITS 'date' standard. + */ + DATEHDR(HduType.PRIMARY_EXTENSION, ValueType.STRING, "Date of header creation"), + + /** + * Default date for the observation. This keyword is generally not used and is DATE-OBS keyword for the start of the + * exposure on the detector is used. + */ + DATEOBS(HduType.PRIMARY_EXTENSION, ValueType.STRING, "Date of observation"), + + /** + * Projected position angle of the positive declination axis on the detector. The position angle is measured + * clockwise from the image y axis. + */ + DECPANGL(HduType.PRIMARY, ValueType.REAL, "Position angle of Dec axis"), + + /** + * Default declination units. + */ + DECUNIT(HduType.PRIMARY_EXTENSION, ValueType.STRING, "Declination unit"), + + /** + * Detector configuration. + */ + DETCONF(HduType.PRIMARY, ValueType.STRING, "Detector Configuration"), + + /** + * Declination of the detector center. + */ + DETDEC(HduType.PRIMARY, ValueType.STRING, "Detector delination"), + + /** + * Declination unit. + */ + DETDECU(HduType.PRIMARY, ValueType.STRING, "Delination unit"), + + /** + * Detector name. + */ + DETECTOR(HduType.PRIMARY, ValueType.STRING, "Detector name"), + + /** + * Epoch of the detector center coordinates. + */ + DETEPOCH(HduType.PRIMARY, ValueType.REAL, "Detector coordinate epoch"), + + /** + * Detector coordinate system equinox. A value before 1984 is Besselian otherwise it is Julian. + */ + DETEQUIN(HduType.PRIMARY, ValueType.REAL, "Detector coordinate equinox"), + + /** + * Detector hardware version. + */ + DETHWV(HduType.PRIMARY, ValueType.STRING, "Detector version"), + + /** + * Times for the detector sensor measurements given as modified Julian dates. The MJDHDR keyword may be used for the + * time at which the image header is created or the MJD-OBS keyword may be used for the time of observation. + */ + DETMJD(HduType.PRIMARY, ValueType.REAL, ""), + + /** + * Times for the detector sensor measurements given as modified Julian dates. The MJDHDR keyword may be used for the + * time at which the image header is created or the MJD-OBS keyword may be used for the time of observation. + */ + DETMJDn(HduType.PRIMARY, ValueType.REAL, ""), + + /** + * Detector position angle measurements in appropriate units. + */ + DETPAN(HduType.PRIMARY, ValueType.REAL, ""), + + /** + * Detector position angle measurements in appropriate units. + */ + DETPANn(HduType.PRIMARY, ValueType.REAL, ""), + + /** + * Detector linear position sensor measurements in appropriate units. + */ + DETPOS(HduType.PRIMARY, ValueType.REAL, ""), + + /** + * Detector linear position sensor measurements in appropriate units. + */ + DETPOSn(HduType.PRIMARY, ValueType.REAL, ""), + + /** + * Detector pressure sensor measurements in appropriate units. + */ + DETPRE(HduType.PRIMARY, ValueType.REAL, ""), + + /** + * Detector pressure sensor measurements in appropriate units. + */ + DETPREn(HduType.PRIMARY, ValueType.REAL, ""), + + /** + * Right ascension of the detector center. + */ + DETRA(HduType.PRIMARY_EXTENSION, ValueType.STRING, "Detector right ascension"), + + /** + * Detector coordinate system type. + */ + DETRADEC(HduType.PRIMARY, ValueType.STRING, "Detector coordinate system"), + + /** + * Right ascension unit. + */ + DETRAU(HduType.PRIMARY_EXTENSION, ValueType.STRING, "Right ascension unit"), + + /** + * Mapping of the CCD section to detector coordinates. + */ + DETSEC(HduType.EXTENSION, ValueType.STRING, "Detector data section"), + + /** + * The logical unbinned size of the detector in section notation. This is the full pixel raster size including, if + * applicable, drift scanning or a mosaic format. This is the full size even when subraster readouts are done. + */ + DETSIZE(HduType.PRIMARY, ValueType.STRING, "Detector size"), + + /** + * Detector status. + */ + DETSTAT(HduType.PRIMARY, ValueType.STRING, "Detector status"), + + /** + * Detector software version. This will not generally be used and the controller software version will apply. + */ + DETSWV(HduType.PRIMARY, ValueType.STRING, "Detector software version"), + + /** + * Detector temperature sensor measurements in degrees Celsius. + */ + DETTEM(HduType.PRIMARY, ValueType.REAL, ""), + + /** + * Detector temperature sensor measurements in degrees Celsius. + */ + DETTEMn(HduType.PRIMARY, ValueType.REAL, ""), + + /** + * Detector voltage sensor measurements in volts. + */ + DETVOL(HduType.PRIMARY, ValueType.REAL, ""), + + /** + * Detector voltage sensor measurements in volts. + */ + DETVOLn(HduType.PRIMARY, ValueType.REAL, ""), + + /** + * Dewar identification. + */ + DEWAR(HduType.PRIMARY, ValueType.STRING, "Dewar"), + + /** + * Dewar hardware version. + */ + DEWHWV(HduType.PRIMARY_EXTENSION, ValueType.STRING, "Dewar hardware"), + + /** + * Times for the dewar sensor measurements given as modified Julian dates. The MJDHDR keyword may be used for the + * time at which the image header is created or the MJD-OBS keyword may be used for the time of observation. + */ + DEWMJD(HduType.PRIMARY_EXTENSION, ValueType.REAL, ""), + + /** + * Times for the dewar sensor measurements given as modified Julian dates. The MJDHDR keyword may be used for the + * time at which the image header is created or the MJD-OBS keyword may be used for the time of observation. + */ + DEWMJDn(HduType.PRIMARY_EXTENSION, ValueType.REAL, ""), + + /** + * Dewar position angle measurements in appropriate units. + */ + DEWPAN(HduType.PRIMARY_EXTENSION, ValueType.REAL, ""), + + /** + * Dewar position angle measurements in appropriate units. + */ + DEWPANn(HduType.PRIMARY_EXTENSION, ValueType.REAL, ""), + + /** + * Dewar linear position sensor measurements in appropriate units. + */ + DEWPOS(HduType.PRIMARY_EXTENSION, ValueType.REAL, ""), + + /** + * Dewar linear position sensor measurements in appropriate units. + */ + DEWPOSn(HduType.PRIMARY_EXTENSION, ValueType.REAL, ""), + + /** + * Dewar pressure sensor measurements in appropriate units. + */ + DEWPRE(HduType.PRIMARY_EXTENSION, ValueType.REAL, ""), + + /** + * Dewar pressure sensor measurements in appropriate units. + */ + DEWPREn(HduType.PRIMARY_EXTENSION, ValueType.REAL, ""), + + /** + * Dewar status. + */ + DEWSTAT(HduType.PRIMARY_EXTENSION, ValueType.STRING, "Dewar status"), + + /** + * Dewar software version. + */ + DEWSWV(HduType.PRIMARY_EXTENSION, ValueType.STRING, "Dewar software version"), + + /** + * Dewar temperature sensor measurements in degrees Celsius. + */ + DEWTEM(HduType.PRIMARY_EXTENSION, ValueType.REAL, "Dewar temperature"), + + /** + * Dewar temperature sensor measurements in degrees Celsius. + */ + DEWTEMn(HduType.PRIMARY_EXTENSION, ValueType.REAL, "Dewar temperature"), + + /** + * Dewar voltage sensor measurements in volts. + */ + DEWVOL(HduType.PRIMARY_EXTENSION, ValueType.REAL, ""), + + /** + * Dewar voltage sensor measurements in volts. + */ + DEWVOLn(HduType.PRIMARY_EXTENSION, ValueType.REAL, ""), + + /** + * Times for the disperser sensor measurements given as modified Julian dates. + */ + DISMJD(HduType.PRIMARY, ValueType.REAL, ""), + + /** + * Times for the disperser sensor measurements given as modified Julian dates. + */ + DISMJDn(HduType.PRIMARY, ValueType.REAL, ""), + + /** + * Disperser position angle measurements in appropriate units. + */ + DISPAN(HduType.PRIMARY, ValueType.REAL, ""), + + /** + * Disperser position angle measurements in appropriate units. + */ + DISPANn(HduType.PRIMARY, ValueType.REAL, ""), + + /** + * The detector axis along which the dispersion is most closely aligned. + */ + DISPAXIS(HduType.PRIMARY, ValueType.INTEGER, "Dispersion axis"), + + /** + * Approximate central dispersion/pixel on the detector. + */ + DISPDW(HduType.PRIMARY, ValueType.REAL, "Dispersion"), + + /** + * Disperser identification names. + */ + DISPER(HduType.PRIMARY, ValueType.STRING, "Disperser"), + + /** + * Disperser identification names. + */ + DISPERn(HduType.PRIMARY, ValueType.STRING, "Disperser"), + + /** + * Disperser linear position sensor measurements in appropriate units. + */ + DISPOS(HduType.PRIMARY, ValueType.REAL, ""), + + /** + * Disperser linear position sensor measurements in appropriate units. + */ + DISPOSn(HduType.PRIMARY, ValueType.REAL, ""), + + /** + * Disperser pressure sensor measurements in appropriate units. + */ + DISPRE(HduType.PRIMARY, ValueType.REAL, ""), + + /** + * Disperser pressure sensor measurements in appropriate units. + */ + DISPREn(HduType.PRIMARY, ValueType.REAL, ""), + + /** + * Default dispersion coordinate unit. + */ + DISPUNIT(HduType.PRIMARY_EXTENSION, ValueType.STRING, "Dispersion coordinate unit"), + + /** + * Default dispersion coordinate ValueType. + */ + DISPVAL(HduType.PRIMARY_EXTENSION, ValueType.REAL, "Dispersion coordinate"), + + /** + * Approximate central dispersion coordinate on the detector. + */ + DISPWC(HduType.PRIMARY, ValueType.REAL, "Central dispersion coordinate"), + + /** + * Disperser temperature sensor measurements in degrees Celsius. + */ + DISTEM(HduType.PRIMARY, ValueType.REAL, ""), + + /** + * Disperser temperature sensor measurements in degrees Celsius. + */ + DISTEMn(HduType.PRIMARY, ValueType.REAL, ""), + + /** + * Disperser voltage sensor measurements in volts. + */ + DISVOL(HduType.PRIMARY, ValueType.REAL, ""), + + /** + * Disperser voltage sensor measurements in volts. + */ + DISVOLn(HduType.PRIMARY, ValueType.REAL, ""), + + /** + * Average wind direction measurements measured east of north over the sampling period inside the dome. + */ + DMEDIR(HduType.PRIMARY, ValueType.REAL, "Average wind direction"), + + /** + * Average wind direction measurements measured east of north over the sampling period inside the dome. + */ + DMEDIRn(HduType.PRIMARY, ValueType.REAL, "Average wind direction"), + + /** + * Maximum wind speed over the sampling period inside the dome. + */ + DMEGUS(HduType.PRIMARY, ValueType.REAL, "Maximum dome wind speed"), + + /** + * Maximum wind speed over the sampling period inside the dome. + */ + DMEGUSn(HduType.PRIMARY, ValueType.REAL, "Maximum dome wind speed"), + + /** + * Times for the dome environment measurements given as modified Julian. For the wind measurements this is the start + * of the sampling period. + */ + DMEMJD(HduType.PRIMARY, ValueType.REAL, ""), + + /** + * Times for the dome environment measurements given as modified Julian. For the wind measurements this is the start + * of the sampling period. + */ + DMEMJDn(HduType.PRIMARY, ValueType.REAL, ""), + + /** + * Wind sampling period for the wind measurements inside the dome. If no value is given then the measurements are + * assumed to be 'instantaneous'. + */ + DMEPER(HduType.PRIMARY, ValueType.REAL, "Dome wind sampling"), + + /** + * Wind sampling period for the wind measurements inside the dome. If no value is given then the measurements are + * assumed to be 'instantaneous'. + */ + DMEPERn(HduType.PRIMARY, ValueType.REAL, "Dome wind sampling"), + + /** + * Temperatures Celsius inside the dome. + */ + DMETEM(HduType.PRIMARY, ValueType.REAL, "Dome temperature"), + + /** + * Temperatures Celsius inside the dome. + */ + DMETEMn(HduType.PRIMARY, ValueType.REAL, "Dome temperature"), + + /** + * Average wind speeds over the sampling period inside the dome. + */ + DMEWIN(HduType.PRIMARY, ValueType.REAL, "Average dome wind speed"), + + /** + * Average wind speeds over the sampling period inside the dome. + */ + DMEWINn(HduType.PRIMARY, ValueType.REAL, "Average dome wind speed"), + + /** + * Times for the dome sensor measurements given as modified Julian dates. + */ + DOMMJD(HduType.PRIMARY, ValueType.REAL, ""), + + /** + * Times for the dome sensor measurements given as modified Julian dates. + */ + DOMMJDn(HduType.PRIMARY, ValueType.REAL, ""), + + /** + * Dome position angle sensor measurements. This should be in degrees east of north for the center of the dome slit. + */ + DOMPAN(HduType.PRIMARY, ValueType.REAL, ""), + + /** + * Dome position angle sensor measurements. This should be in degrees east of north for the center of the dome slit. + */ + DOMPANn(HduType.PRIMARY, ValueType.REAL, ""), + + /** + * Dome linear position sensor measurements in appropriate units. + */ + DOMPOS(HduType.PRIMARY, ValueType.REAL, ""), + + /** + * Dome linear position sensor measurements in appropriate units. + */ + DOMPOSn(HduType.PRIMARY, ValueType.REAL, ""), + + /** + * Dome pressure sensor measurements in appropriate units. + */ + DOMPRE(HduType.PRIMARY, ValueType.REAL, ""), + + /** + * Dome pressure sensor measurements in appropriate units. + */ + DOMPREn(HduType.PRIMARY, ValueType.REAL, ""), + + /** + * Dome status. + */ + DOMSTAT(HduType.PRIMARY, ValueType.STRING, "Dome status"), + + /** + * Dome temperature sensor measurements in degrees Celsius. + */ + DOMTEM(HduType.PRIMARY, ValueType.REAL, "Dome temperature"), + + /** + * Dome temperature sensor measurements in degrees Celsius. + */ + DOMTEMn(HduType.PRIMARY, ValueType.REAL, "Dome temperature"), + + /** + * Dome voltage sensor measurements in volts. + */ + DOMVOL(HduType.PRIMARY, ValueType.REAL, ""), + + /** + * Dome voltage sensor measurements in volts. + */ + DOMVOLn(HduType.PRIMARY, ValueType.REAL, ""), + + /** + * Transformation matrix between CCD and detector coordinates. If missing the default is an identify matrix. + */ + DTMn_n(HduType.EXTENSION, ValueType.REAL, "Detector transformation matrix"), + + /** + * Transformation origin vector between CCD and detector coordinates. + */ + DTVn(HduType.EXTENSION, ValueType.REAL, "Detector transformation vector"), + + /** + * Average wind direction measurements measured east of north over the sampling period outside the dome at times + * given by ENVMJDn keywords. + */ + ENVDIR(HduType.PRIMARY, ValueType.REAL, "Average wind direction"), + + /** + * Average wind direction measurements measured east of north over the sampling period outside the dome at times + * given by ENVMJDn keywords. + */ + ENVDIRn(HduType.PRIMARY, ValueType.REAL, "Average wind direction"), + + /** + * Maximum wind speed in km/s over the sampling period outside the dome at times given by ENVMJDn keywords. + */ + ENVGUS(HduType.PRIMARY, ValueType.REAL, "Maximum gust speed"), + + /** + * Maximum wind speed in km/s over the sampling period outside the dome at times given by ENVMJDn keywords. + */ + ENVGUSn(HduType.PRIMARY, ValueType.REAL, "Maximum gust speed"), + + /** + * Relative humidity measurements at times given by ENVMJDn keywords. + */ + ENVHUM(HduType.PRIMARY, ValueType.REAL, "Relative humidity"), + + /** + * Relative humidity measurements at times given by ENVMJDn keywords. + */ + ENVHUMn(HduType.PRIMARY, ValueType.REAL, "Relative humidity"), + + /** + * Times for the site environment measurements given as modified Julian. For the wind measurements this is the start + * of the sampling period. + */ + ENVMJD(HduType.PRIMARY, ValueType.REAL, "Environment measurement time"), + + /** + * Times for the site environment measurements given as modified Julian. For the wind measurements this is the start + * of the sampling period. + */ + ENVMJDn(HduType.PRIMARY, ValueType.REAL, "Environment measurement time"), + + /** + * Wind sampling period for the wind measurements outside the dome at times given by ENVMJDn keywords. If no value + * is given then the measurements are assumed to be 'instantaneous'. + */ + ENVPER(HduType.PRIMARY, ValueType.REAL, "Wind sampling period"), + + /** + * Wind sampling period for the wind measurements outside the dome at times given by ENVMJDn keywords. If no value + * is given then the measurements are assumed to be 'instantaneous'. + */ + ENVPERn(HduType.PRIMARY, ValueType.REAL, "Wind sampling period"), + + /** + * Atmospheric pressure measurements at times given by ENVMJDn keywords. + */ + ENVPRE(HduType.PRIMARY, ValueType.REAL, "Air pressure"), + + /** + * Atmospheric pressure measurements at times given by ENVMJDn keywords. + */ + ENVPREn(HduType.PRIMARY, ValueType.REAL, "Air pressure"), + + /** + * Temperatures outside the dome at times given by ENVMJDn keywords. + */ + ENVTEM(HduType.PRIMARY, ValueType.REAL, "Site temperature"), + + /** + * Temperatures outside the dome at times given by ENVMJDn keywords. + */ + ENVTEMn(HduType.PRIMARY, ValueType.REAL, "Site temperature"), + + /** + * Precipitable water vapor measurements at times given by ENVMJDn keywords. + */ + ENVWAT(HduType.PRIMARY, ValueType.REAL, "Precipitable water vapor"), + + /** + * Precipitable water vapor measurements at times given by ENVMJDn keywords. + */ + ENVWATn(HduType.PRIMARY, ValueType.REAL, "Precipitable water vapor"), + + /** + * Average wind speeds over the sampling period outside the dome at times given by ENVMJDn keywords. + */ + ENVWIN(HduType.PRIMARY, ValueType.REAL, "Average wind speed"), + + /** + * Average wind speeds over the sampling period outside the dome at times given by ENVMJDn keywords. + */ + ENVWINn(HduType.PRIMARY, ValueType.REAL, "Average wind speed"), + + /** + * Error information. The sequence numbers are used to order the information. + */ + ERRORnnn(HduType.PRIMARY, ValueType.STRING, ""), + + /** + * Requested exposure time of the observation. + */ + EXPREQ(HduType.PRIMARY_EXTENSION, ValueType.REAL, "Requested exposure time"), + + /** + * Fiber identification for the fiber(s). The string consists of a fiber number, an object type number (0=sky, + * 1=object, etc.), the right ascension and declination, and the object name or title. This can replace OBJNAME, + * APRA/OBJRA, and APDEC/OBJDEC. + */ + FIBER(HduType.PRIMARY, ValueType.STRING, ""), + + /** + * Fiber identification for the fiber(s). The string consists of a fiber number, an object type number (0=sky, + * 1=object, etc.), the right ascension and declination, and the object name or title. This can replace OBJNAME, + * APRA/OBJRA, and APDEC/OBJDEC. + */ + FIBnnn(HduType.PRIMARY, ValueType.STRING, ""), + + /** + * Filter position given as filter wheel number or other filter system position measurement. + */ + FILPOS(HduType.PRIMARY, ValueType.REAL, "Filter system position"), + + /** + * Filter position given as filter wheel number or other filter system position measurement. + */ + FILPOSn(HduType.PRIMARY, ValueType.REAL, "Filter system position"), + + /** + * Filter type. This is the technical specification or observatory identification name. + */ + FILTYP(HduType.PRIMARY, ValueType.STRING, "Filter type"), + + /** + * Filter type. This is the technical specification or observatory identification name. + */ + FILTYPn(HduType.PRIMARY, ValueType.STRING, "Filter type"), + + /** + * Number of focus exposures in a focus sequence. + */ + FOCNEXPO(HduType.PRIMARY, ValueType.INTEGER, "Number of focus exposures"), + + /** + * Pixel shift on the detector between exposures in a focus sequence. + */ + FOCSHIFT(HduType.PRIMARY, ValueType.REAL, "Shift between focus exposures"), + + /** + * Starting focus value in focus sequence. + */ + FOCSTART(HduType.PRIMARY, ValueType.REAL, "Starting focus"), + + /** + * Focus increment step in focus sequence. + */ + FOCSTEP(HduType.PRIMARY, ValueType.REAL, "Focus step"), + + /** + * Amplifier gain in electrons per analog unit. This is the most current estimate of the gain. + */ + GAIN(HduType.EXTENSION, ValueType.REAL, "Amplifier gain"), + + /** + * Guider TV name. + */ + GTV(HduType.PRIMARY, ValueType.STRING, "Guider TV"), + + /** + * Guider TV filter names. This name is the astronomical standard name if applicable; i.e. U, B, Gunn I, etc. The + * filter type and filter device position are given by other keywords. + */ + GTVFIL(HduType.PRIMARY, ValueType.STRING, "Filter name"), + + /** + * Guider TV filter names. This name is the astronomical standard name if applicable; i.e. U, B, Gunn I, etc. The + * filter type and filter device position are given by other keywords. + */ + GTVFILn(HduType.PRIMARY, ValueType.STRING, "Filter name"), + + /** + * Guider TV filter position given as filter wheel number or other filter system position measurement. + */ + GTVFPO(HduType.PRIMARY, ValueType.REAL, "Filter system position"), + + /** + * Guider TV filter position given as filter wheel number or other filter system position measurement. + */ + GTVFPOn(HduType.PRIMARY, ValueType.REAL, "Filter system position"), + + /** + * Guider TV filter type. This is the technical specification or observatory identification name. + */ + GTVFTY(HduType.PRIMARY, ValueType.STRING, "Filter type"), + + /** + * Guider TV filter type. This is the technical specification or observatory identification name. + */ + GTVFTYn(HduType.PRIMARY, ValueType.STRING, "Filter type"), + + /** + * Guider TV identification and hardware version. + */ + GTVHWV(HduType.PRIMARY, ValueType.STRING, ""), + + /** + * Times for the guider television sensor measurements given as modified Julian dates. + */ + GTVMJD(HduType.PRIMARY, ValueType.REAL, ""), + + /** + * Times for the guider television sensor measurements given as modified Julian dates. + */ + GTVMJDn(HduType.PRIMARY, ValueType.REAL, ""), + + /** + * Guider television position angle measurements in appropriate units. + */ + GTVPAN(HduType.PRIMARY, ValueType.REAL, ""), + + /** + * Guider television position angle measurements in appropriate units. + */ + GTVPANn(HduType.PRIMARY, ValueType.REAL, ""), + + /** + * Guider television linear position sensor measurements in appropriate units. + */ + GTVPOS(HduType.PRIMARY, ValueType.REAL, "Television position ()"), + + /** + * Guider television linear position sensor measurements in appropriate units. + */ + GTVPOSn(HduType.PRIMARY, ValueType.REAL, "Television position ()"), + + /** + * Guider television pressure sensor measurements in appropriate units. + */ + GTVPRE(HduType.PRIMARY, ValueType.REAL, ""), + + /** + * Guider television pressure sensor measurements in appropriate units. + */ + GTVPREn(HduType.PRIMARY, ValueType.REAL, ""), + + /** + * Guider TV status. + */ + GTVSTAT(HduType.PRIMARY, ValueType.STRING, ""), + + /** + * Guider TV software version. + */ + GTVSWV(HduType.PRIMARY, ValueType.NONE, ""), + + /** + * Guider television temperature sensor measurements in degrees Celsius. + */ + GTVTEM(HduType.PRIMARY, ValueType.REAL, ""), + + /** + * Guider television temperature sensor measurements in degrees Celsius. + */ + GTVTEMn(HduType.PRIMARY, ValueType.REAL, ""), + + /** + * Guider television voltage sensor measurements in volts. + */ + GTVVOL(HduType.PRIMARY, ValueType.REAL, ""), + + /** + * Guider television voltage sensor measurements in volts. + */ + GTVVOLn(HduType.PRIMARY, ValueType.REAL, ""), + + /** + * Guide object declination. + */ + GUIDEC(HduType.PRIMARY, ValueType.STRING, "Guider declination"), + + /** + * Declination unit. + */ + GUIDECU(HduType.PRIMARY, ValueType.STRING, "Declination unit"), + + /** + * Guider identification and hardware version. + */ + GUIDEHWV(HduType.PRIMARY, ValueType.NONE, ""), + + /** + * Guider name. Two of the names are 'manual' and 'none' for manual guiding or no guider, respectively. + */ + GUIDER(HduType.PRIMARY, ValueType.STRING, "Guider name"), + + /** + * Guider software version. + */ + GUIDESWV(HduType.PRIMARY, ValueType.NONE, ""), + + /** + * Epoch of the guide object coordinates. + */ + GUIEPOCH(HduType.PRIMARY, ValueType.NONE, ""), + + /** + * Guide object coordinate system equinox. A value before 1984 is Besselian otherwise it is Julian. + */ + GUIEQUIN(HduType.PRIMARY, ValueType.REAL, ""), + + /** + * Times for the guider sensor measurements given as modified Julian dates. + */ + GUIMJD(HduType.PRIMARY, ValueType.REAL, ""), + + /** + * Times for the guider sensor measurements given as modified Julian dates. + */ + GUIMJDn(HduType.PRIMARY, ValueType.REAL, ""), + + /** + * Guider position angle measurements in appropriate units. + */ + GUIPAN(HduType.PRIMARY, ValueType.REAL, ""), + + /** + * Guider position angle measurements in appropriate units. + */ + GUIPANn(HduType.PRIMARY, ValueType.REAL, ""), + + /** + * Guider linear position sensor measurements in appropriate units. This might be used for guide probe positions. + */ + GUIPOS(HduType.PRIMARY, ValueType.REAL, "Guider position ()"), + + /** + * Guider linear position sensor measurements in appropriate units. This might be used for guide probe positions. + */ + GUIPOSn(HduType.PRIMARY, ValueType.REAL, "Guider position ()"), + + /** + * Guider pressure sensor measurements in appropriate units. + */ + GUIPRE(HduType.PRIMARY, ValueType.REAL, ""), + + /** + * Guider pressure sensor measurements in appropriate units. + */ + GUIPREn(HduType.PRIMARY, ValueType.REAL, ""), + + /** + * Guide object right ascension. + */ + GUIRA(HduType.PRIMARY, ValueType.STRING, "Guider right ascension"), + + /** + * Guide object coordinate system type. + */ + GUIRADEC(HduType.PRIMARY, ValueType.STRING, ""), + + /** + * Guider correction rate. + */ + GUIRATE(HduType.PRIMARY, ValueType.REAL, "Guider rate"), + + /** + * Right ascension unit. + */ + GUIRAU(HduType.PRIMARY, ValueType.STRING, "Right ascension unit"), + + /** + * Guider status. + */ + GUISTAT(HduType.PRIMARY, ValueType.STRING, ""), + + /** + * Guider temperature sensor measurements in degrees Celsius. + */ + GUITEM(HduType.PRIMARY, ValueType.REAL, ""), + + /** + * Guider temperature sensor measurements in degrees Celsius. + */ + GUITEMn(HduType.PRIMARY, ValueType.REAL, ""), + + /** + * Guider voltage sensor measurements in volts. + */ + GUIVOL(HduType.PRIMARY, ValueType.REAL, ""), + + /** + * Guider voltage sensor measurements in volts. + */ + GUIVOLn(HduType.PRIMARY, ValueType.REAL, ""), + + /** + * Hour angle at TELMJD. + */ + HA(HduType.PRIMARY, ValueType.STRING, "Hour angle"), + + /** + * Image creation system hardware version. + */ + IMAGEHWV(HduType.PRIMARY, ValueType.STRING, "Image creation hardware version"), + + /** + * The image identification when there are multiple images within an observation. For detectors with CCDs this would + * be a unique number assigned to each amplifier in the detector. + */ + IMAGEID(HduType.EXTENSION, ValueType.INTEGER, "Image identification"), + + /** + * Image creation system software version. + */ + IMAGESWV(HduType.PRIMARY, ValueType.STRING, "Image creation software version"), + + /** + * Instrument focus. + */ + INSFOCUS(HduType.PRIMARY, ValueType.REAL, "Instrument focus"), + + /** + * Times for the instrument sensor measurements given as modified Julian dates. + */ + INSMJD(HduType.PRIMARY, ValueType.REAL, ""), + + /** + * Times for the instrument sensor measurements given as modified Julian dates. + */ + INSMJDn(HduType.PRIMARY, ValueType.REAL, ""), + + /** + * Instrument position angle measurements in appropriate units. + */ + INSPAN(HduType.PRIMARY, ValueType.REAL, ""), + + /** + * Instrument position angle measurements in appropriate units. + */ + INSPANn(HduType.PRIMARY, ValueType.REAL, ""), + + /** + * Instrument linear position sensor measurements in appropriate units. + */ + INSPOS(HduType.PRIMARY, ValueType.REAL, ""), + + /** + * Instrument linear position sensor measurements in appropriate units. + */ + INSPOSn(HduType.PRIMARY, ValueType.REAL, ""), + + /** + * Instrument pressure sensor measurements in appropriate units. + */ + INSPRE(HduType.PRIMARY, ValueType.REAL, ""), + + /** + * Instrument pressure sensor measurements in appropriate units. + */ + INSPREn(HduType.PRIMARY, ValueType.REAL, ""), + + /** + * Instrument status. + */ + INSSTAT(HduType.PRIMARY, ValueType.STRING, "Instrument status"), + + /** + * Instrument configuration. + */ + INSTCONF(HduType.PRIMARY, ValueType.STRING, "Instrument configuration"), + + /** + * Instrument temperature sensor measurements in degrees Celsius. + */ + INSTEM(HduType.PRIMARY, ValueType.REAL, ""), + + /** + * Instrument temperature sensor measurements in degrees Celsius. + */ + INSTEMn(HduType.PRIMARY, ValueType.REAL, ""), + + /** + * Instrument hardware version. + */ + INSTHWV(HduType.PRIMARY, ValueType.STRING, "Instrument hardware version"), + + /** + * Instrument software version. ------------------------------------------------------------------ + */ + INSTSWV(HduType.PRIMARY, ValueType.STRING, "Instrument software version"), + + /** + * Instrument voltage sensor measurements in volts. + */ + INSVOL(HduType.PRIMARY, ValueType.REAL, ""), + + /** + * Instrument voltage sensor measurements in volts. + */ + INSVOLn(HduType.PRIMARY, ValueType.REAL, ""), + + /** + * The keyword dictionary defining the keywords. This dictionary should be archived with the data. + */ + KWDICT(HduType.PRIMARY, ValueType.STRING, "Keyword dictionary"), + + /** + * Calibration lamp name + */ + LAMP(HduType.PRIMARY, ValueType.STRING, "Calibration lamp"), + + /** + * Calibration lamp type. + */ + LAMPTYPE(HduType.PRIMARY, ValueType.STRING, "Lamp type"), + + /** + * Times for the lamp sensor measurements given as modified Julian dates. The MJDHDR keyword may be used for the + * time at which the image header is created or the MJD-OBS keyword may be used for the time of observation. + */ + LMPMJD(HduType.PRIMARY, ValueType.REAL, ""), + + /** + * Times for the lamp sensor measurements given as modified Julian dates. The MJDHDR keyword may be used for the + * time at which the image header is created or the MJD-OBS keyword may be used for the time of observation. + */ + LMPMJDn(HduType.PRIMARY, ValueType.REAL, ""), + + /** + * Calibration lamp position angle measurements in appropriate units. + */ + LMPPAN(HduType.PRIMARY, ValueType.REAL, ""), + + /** + * Calibration lamp position angle measurements in appropriate units. + */ + LMPPANn(HduType.PRIMARY, ValueType.REAL, ""), + + /** + * Calibration lamp linear position sensor measurements in appropriate units. + */ + LMPPOS(HduType.PRIMARY, ValueType.REAL, ""), + + /** + * Calibration lamp linear position sensor measurements in appropriate units. + */ + LMPPOSn(HduType.PRIMARY, ValueType.REAL, ""), + + /** + * Calibration lamp pressure sensor measurements in appropriate units. + */ + LMPPRE(HduType.PRIMARY, ValueType.REAL, ""), + + /** + * Calibration lamp pressure sensor measurements in appropriate units. + */ + LMPPREn(HduType.PRIMARY, ValueType.REAL, ""), + + /** + * Calibration lamp temperature sensor measurements in degrees Celsius. + */ + LMPTEM(HduType.PRIMARY, ValueType.REAL, ""), + + /** + * Calibration lamp temperature sensor measurements in degrees Celsius. + */ + LMPTEMn(HduType.PRIMARY, ValueType.REAL, ""), + + /** + * Calibration lamp voltage sensor measurements in volts. + */ + LMPVOL(HduType.PRIMARY, ValueType.REAL, ""), + + /** + * Calibration lamp voltage sensor measurements in volts. + */ + LMPVOLn(HduType.PRIMARY, ValueType.REAL, ""), + + /** + * Local siderial time at the start of the exposure. + */ + LST_OBS("LST-OBS", HduType.PRIMARY_EXTENSION, ValueType.STRING, "LST of exposure start"), + + /** + * Local siderial time at the end of the exposure. + */ + LSTEND(HduType.PRIMARY_EXTENSION, ValueType.STRING, "LST at end of exposure"), + + /** + * Local siderial time of the header creation. + */ + LSTHDR(HduType.PRIMARY_EXTENSION, ValueType.STRING, "LST of header creation"), + + /** + * Default local siderial time for the observation. This keyword is generally not used and is LST-OBS keyword for + * the start of the exposure on the detector is used. + */ + LSTOBS(HduType.PRIMARY_EXTENSION, ValueType.STRING, "LST of observation"), + + /** + * Transformation matrix between CCD and image coordinates. If missing the default is an identify matrix. + */ + LTMn_n(HduType.EXTENSION, ValueType.REAL, "Image transformation matrix"), + + /** + * Transformation origin vector between CCD and image coordinates. + */ + LTVn(HduType.EXTENSION, ValueType.REAL, "Image transformation vector"), + + /** + * The maximum number of scanned (unbinned) lines used to form an output line. This is used with drift scanning or a + * scan table. For long drift scans this will be the number of lines in the CCD. + */ + MAXNSCAN(HduType.EXTENSION, ValueType.INTEGER, "Maximum number of scanned lines"), + + /** + * The minimum number of scanned (unbinned) lines used to form an output line. This is used with drift scanning or a + * scan table. This will only differ from MAXNSCAN if the initial lines in the output image are from the initial + * ramp-up. + */ + MINNSCAN(HduType.EXTENSION, ValueType.INTEGER, "Minimum number of scanned lines"), + + /** + * Modified Julian date when the image header was created by the software. The fractional part of the date is given + * to better than a second of time. Many header keywords may be sampled or computed at this time and this keyword is + * the default for these. + */ + MJDHDR(HduType.PRIMARY_EXTENSION, ValueType.REAL, "MJD of header creation"), + + /** + * Default modified Julian date for the observation. The fractional part of the date is given to better than a + * second of time. This keyword is generally not used and is MJD-OBS keyword for the start of the exposure on the + * detector is used. + */ + MJDOBS(HduType.PRIMARY_EXTENSION, ValueType.REAL, "MJD of observation"), + + /** + * The number of amplifiers in the detector. When there is only a single amplifier used it may be absent since the + * default value is 1. + */ + NAMPS(HduType.PRIMARY, ValueType.INTEGER, "Number of Amplifiers"), + + /** + * The number of CCDs in the detector. This is used with mosaics of CCD detectors. For a single CCD it may be absent + * since the default value is 1. + */ + NCCDS(HduType.PRIMARY, ValueType.INTEGER, "Number of CCDs"), + + NODANGLE(HduType.PRIMARY, ValueType.NONE, ""), + + NODDIST(HduType.PRIMARY, ValueType.NONE, ""), + + NODFREQ(HduType.PRIMARY, ValueType.NONE, ""), + + NODHWV(HduType.PRIMARY, ValueType.NONE, ""), + + /** + * Times for the nodding system sensor measurements given as modified Julian dates. + */ + NODMJD(HduType.PRIMARY, ValueType.REAL, ""), + + /** + * Times for the nodding system sensor measurements given as modified Julian dates. + */ + NODMJDn(HduType.PRIMARY, ValueType.REAL, ""), + + NODNCHOP(HduType.PRIMARY, ValueType.NONE, ""), + + /** + * Nodding position angle measurements in appropriate units. Note that NODANGLE should be used for the nodding angle + * and these keywords are for other system position angle measurements. + */ + NODPAN(HduType.PRIMARY, ValueType.REAL, ""), + + /** + * Nodding position angle measurements in appropriate units. Note that NODANGLE should be used for the nodding angle + * and these keywords are for other system position angle measurements. + */ + NODPANn(HduType.PRIMARY, ValueType.REAL, ""), + + /** + * Nodding system linear position sensor measurements in appropriate units. + */ + NODPOS(HduType.PRIMARY, ValueType.REAL, ""), + + /** + * Nodding system linear position sensor measurements in appropriate units. + */ + NODPOSn(HduType.PRIMARY, ValueType.REAL, ""), + + /** + * Nodding system pressure sensor measurements in appropriate units. + */ + NODPRE(HduType.PRIMARY, ValueType.REAL, ""), + + /** + * Nodding system pressure sensor measurements in appropriate units. + */ + NODPREn(HduType.PRIMARY, ValueType.REAL, ""), + + NODSTAT(HduType.PRIMARY, ValueType.NONE, ""), + + NODSWV(HduType.PRIMARY, ValueType.NONE, ""), + + /** + * Nodding system temperature sensor measurements in degrees Celsius. + */ + NODTEM(HduType.PRIMARY, ValueType.REAL, ""), + + /** + * Nodding system temperature sensor measurements in degrees Celsius. + */ + NODTEMn(HduType.PRIMARY, ValueType.REAL, ""), + + /** + * Nodding system voltage sensor measurements in volts. + */ + NODVOL(HduType.PRIMARY, ValueType.REAL, ""), + + /** + * Nodding system voltage sensor measurements in volts. + */ + NODVOLn(HduType.PRIMARY, ValueType.REAL, ""), + + /** + * Number of coadded subexposures. When charge shuffling this gives the number of charge shuffled exposures. + */ + NSUBEXPS(HduType.PRIMARY_EXTENSION, ValueType.INTEGER, "Number of subexposures"), + + /** + * Declination of the target astronomical object(s). + */ + OBJDEC(HduType.PRIMARY, ValueType.STRING, "Declination of object"), + + /** + * Declination unit. + */ + OBJDECU(HduType.PRIMARY, ValueType.STRING, "Declination unit"), + + /** + * Epoch of the target astronomical object coordinate(s). This is given in years. + */ + OBJEPOCH(HduType.PRIMARY, ValueType.REAL, "Epoch of object coordinates"), + + /** + * Coordinate system equinox for the target astronomical object(s). A value before 1984 is Besselian otherwise it is + * Julian. + */ + OBJEQUIN(HduType.PRIMARY, ValueType.REAL, "Object coordinate equinox"), + + /** + * Standard reference or catalog name for the target astronomical object(s). The name should follow IAU standards. + * These keywords differ from the OBJECT keyword which is used to identify the observation. + */ + OBJnnn(HduType.PRIMARY, ValueType.STRING, "Target object"), + + /** + * Right ascension of the target astronomical object(s). + */ + OBJRA(HduType.PRIMARY, ValueType.STRING, "Right ascension of object"), + + /** + * Coordinate system type for the target astronomical object(s). + */ + OBJRADEC(HduType.PRIMARY, ValueType.STRING, "Object coordinate system"), + + /** + * Right ascension unit. + */ + OBJRAU(HduType.PRIMARY, ValueType.STRING, "Right ascension unit"), + + /** + * Type of target astronomical object(s). This is taken from a dictionary of names yet to be defined. Some common + * types are 'galaxy', 'star', and 'sky'. If not particular object is targeted the type 'field' may be used. + */ + OBJTnnn(HduType.PRIMARY, ValueType.STRING, "Type of object"), + + /** + * Type of target astronomical object(s). This is taken from a dictionary of names yet to be defined. Some common + * types are 'galaxy', 'star', and 'sky'. If not particular object is targeted the type 'field' may be used. + */ + OBJTYPE(HduType.PRIMARY, ValueType.STRING, "Type of object"), + + /** + * Declination of the observation. This may be distinct from the object coordinates and the telescope coordinates. + * It may be used to indicate the requested observation coordinates. + */ + OBSDEC(HduType.PRIMARY, ValueType.STRING, "Observation declination"), + + /** + * Declination unit. + */ + OBSDECU(HduType.PRIMARY, ValueType.STRING, "Declination unit"), + + /** + * Epoch of the coordinates used in observation coordinates. + */ + OBSEPOCH(HduType.PRIMARY, ValueType.REAL, "Observation coordinate epoch"), + + /** + * Equinox of coordinates used in observation coordinates. A value before 1984 is Besselian otherwise it is Julian. + */ + OBSEQUIN(HduType.PRIMARY, ValueType.REAL, "Observation coordinate equinox"), + + /** + * Observatory identification for the site of the observation. + */ + OBSERVAT(HduType.PRIMARY, ValueType.STRING, "Observatory"), + + /** + * The unique observatory observation identification. This serves to identify all data from the same observation. + */ + OBSID(HduType.PRIMARY_EXTENSION, ValueType.STRING, "Observation identification"), + + /** + * Right ascension of the observation. This may be distinct from the object coordinates and the telescope + * coordinates. It may be used to indicate the requested observation coordinates. + */ + OBSRA(HduType.PRIMARY, ValueType.STRING, "Observation right ascension"), + + /** + * Coordinate system used in observation coordinates. + */ + OBSRADEC(HduType.PRIMARY, ValueType.STRING, "Observation coordinate system"), + + /** + * Right ascension unit. + */ + OBSRAU(HduType.PRIMARY, ValueType.STRING, "Right ascension unit"), + + /** + * Name(s) of the observers. + */ + OBSRVRnn(HduType.PRIMARY, ValueType.STRING, "Observer(s)"), + + /** + * Status of the observation. ----------------------------------------------------------------- + */ + OBSSTAT(HduType.PRIMARY, ValueType.STRING, "Observation status"), + + /** + * The type of observation such as an astronomical exposure or a particular type of calibration exposure. + */ + OBSTYPE(HduType.PRIMARY_EXTENSION, ValueType.STRING, "Observation type"), + + /** + * Declination of the target astronomical object(s). + */ + ODECnnn(HduType.PRIMARY, ValueType.STRING, "Declination of object"), + + /** + * Declination unit. + */ + ODEUnnn(HduType.PRIMARY, ValueType.STRING, "Declination unit"), + + /** + * Epoch of the target astronomical object coordinate(s). This is given in years. + */ + OEPOnnn(HduType.PRIMARY, ValueType.REAL, "Epoch of object coordinates"), + + /** + * Coordinate system equinox for the target astronomical object(s). A value before 1984 is Besselian otherwise it is + * Julian. + */ + OEQUnnn(HduType.PRIMARY, ValueType.REAL, "Object coordinate equinox"), + + /** + * Right ascension of the target astronomical object(s). + */ + ORAnnn(HduType.PRIMARY, ValueType.STRING, "Right ascension of object"), + + /** + * Right ascension unit. + */ + ORAUnnn(HduType.PRIMARY, ValueType.STRING, "Right ascension unit"), + + /** + * Coordinate system type for the target astronomical object(s). + */ + ORDSnnn(HduType.PRIMARY, ValueType.STRING, "Object coordinate system"), + + /** + * Status of calibration to data proportional to photons. For CCD data this means bias section correction, zero + * level calibration, dark count calibration, and flat field calibration. + */ + PHOTCAL(HduType.PRIMARY_EXTENSION, ValueType.LOGICAL, "Data proportional to photons?"), + + /** + * Photometric conditions during the observation. + */ + PHOTOMET(HduType.PRIMARY, ValueType.STRING, "Photometric conditions"), + + /** + * Processing hardware used. + */ + PIPEHW(HduType.PRIMARY_EXTENSION, ValueType.STRING, "Processing hardware"), + + /** + * Processing hardware used. + */ + PIPEHWn(HduType.PRIMARY_EXTENSION, ValueType.STRING, "Processing hardware"), + + /** + * Name of processing pipeline applied. + */ + PIPELINE(HduType.PRIMARY_EXTENSION, ValueType.STRING, "Pipeline used"), + + /** + * Processing software version. + */ + PIPESW(HduType.PRIMARY_EXTENSION, ValueType.STRING, "Processing software"), + + /** + * Processing software version. + */ + PIPESWn(HduType.PRIMARY_EXTENSION, ValueType.STRING, "Processing software"), + + /** + * Projected pixel scale along axis n. + */ + PIXSCALn(HduType.PRIMARY, ValueType.REAL, "Pixel scale"), + + /** + * Unbinned pixel size along each dimension given in appropriate units. The units should be indicated in the + * comment. The projected pixel size in arc seconds or wavelength are given by other parameters. + */ + PIXSIZEn(HduType.PRIMARY_EXTENSION, ValueType.REAL, "Pixel size"), + + /** + * Pixel limit for region occupied by the spectrum. + */ + PMAX1(HduType.EXTENSION, ValueType.REAL, "Spectrum pixel limit"), + + /** + * Pixel limit for region occupied by the spectrum. + */ + PMAX2(HduType.EXTENSION, ValueType.REAL, "Spectrum pixel limit"), + + /** + * Pixel limit for region occupied by the spectrum. + */ + PMIN1(HduType.EXTENSION, ValueType.REAL, "Spectrum pixel limit"), + + /** + * Pixel limit for region occupied by the spectrum. + */ + PMIN2(HduType.EXTENSION, ValueType.REAL, "Spectrum pixel limit"), + + /** + * Pixel limit for region occupied by the spectrum. + */ + PMN1nnn(HduType.EXTENSION, ValueType.REAL, "Spectrum pixel limit"), + + /** + * Pixel limit for region occupied by the spectrum. + */ + PMN2n(HduType.EXTENSION, ValueType.REAL, "Spectrum pixel limit"), + + /** + * Pixel limit for region occupied by the spectrum. + */ + PMX1n(HduType.EXTENSION, ValueType.REAL, "Spectrum pixel limit"), + + /** + * Pixel limit for region occupied by the spectrum. + */ + PMX2n(HduType.EXTENSION, ValueType.REAL, "Spectrum pixel limit"), + + /** + * CCD preflash time. If the times in the extension are different the primary HDU gives one of the extension times. + */ + PREFLASH(HduType.PRIMARY_EXTENSION, ValueType.REAL, "Preflash time"), + + /** + * Processing log information formatted as FITS comments. + */ + PROCnnn(HduType.PRIMARY_EXTENSION, ValueType.STRING, ""), + + /** + * Processing status. + */ + PROCSTAT(HduType.PRIMARY_EXTENSION, ValueType.STRING, "Processing status"), + + /** + * The unique observatory proposal identification. + */ + PROPID(HduType.PRIMARY, ValueType.STRING, "Proposal identification"), + + /** + * The name or title of the proposal. + */ + PROPOSAL(HduType.PRIMARY, ValueType.STRING, "Proposal title"), + + /** + * Name(s) of the proposers. + */ + PROPOSER(HduType.PRIMARY, ValueType.STRING, "Proposer(s)"), + + /** + * Name(s) of the proposers. + */ + PROPSRnn(HduType.PRIMARY, ValueType.STRING, "Proposer(s)"), + + /** + * Default coordinate system equinox. A value before 1984 is Besselian otherwise it is Julian. If absent the default + * is J2000. + */ + RADECEQ(HduType.PRIMARY_EXTENSION, ValueType.REAL, "Default coordinate equinox"), + + /** + * Projected position angle of the positive right ascension axis on the detector. The position angle is measured + * clockwise from the image y axis. + */ + RAPANGL(HduType.PRIMARY, ValueType.REAL, "Position angle of RA axis"), + + /** + * Default right ascension units. + */ + RAUNIT(HduType.PRIMARY_EXTENSION, ValueType.STRING, "Right ascension unit"), + + /** + * CCD readout noise in rms electrons. This is the most current estimate. + */ + RDNOISE(HduType.EXTENSION, ValueType.REAL, "Readout noise"), + + /** + * Amplifier unbinned pixel read time. + */ + READTIME(HduType.PRIMARY_EXTENSION, ValueType.REAL, "Unbinned pixel read time"), + + /** + * Archive identification. This may be the same as the observation identification. + */ + RECNO(HduType.PRIMARY, ValueType.STRING, "Archive identification"), + + /** + * Seeing estimates specified as the stellar full-width at half-maximum in arc seconds. There may be more than one + * estimate. The times of the estimates are given by the SEEMJDn keyword. + */ + SEEING(HduType.PRIMARY, ValueType.REAL, "FWHM"), + + /** + * Seeing estimates specified as the stellar full-width at half-maximum in arc seconds. There may be more than one + * estimate. The times of the estimates are given by the SEEMJDn keyword. + */ + SEEINGn(HduType.PRIMARY, ValueType.REAL, "FWHM"), + + /** + * Times for the seeing estimates given as modified Julian dates. + */ + SEEMJD(HduType.PRIMARY, ValueType.REAL, "MJD for seeing estimate"), + + /** + * Times for the seeing estimates given as modified Julian dates. + */ + SEEMJDn(HduType.PRIMARY, ValueType.REAL, "MJD for seeing estimate"), + + /** + * Exposure time of the nth subexposure. If all subexposures are the same length then only the first keyword, SEXP, + * is needed. For charge shuffling the subexposure time is the total time for each charge shuffled exposure. There + * is no finer division of the exposure times. Comments would be used to describe the subexposures of each charge + * shuffled subexposure. + */ + SEXP(HduType.PRIMARY_EXTENSION, ValueType.REAL, "Subexposure time"), + + /** + * Exposure time of the nth subexposure. If all subexposures are the same length then only the first keyword, SEXP, + * is needed. For charge shuffling the subexposure time is the total time for each charge shuffled exposure. There + * is no finer division of the exposure times. Comments would be used to describe the subexposures of each charge + * shuffled subexposure. + */ + SEXPnnn(HduType.PRIMARY_EXTENSION, ValueType.REAL, "Subexposure time"), + + /** + * Time for the shutter to close fully. + */ + SHUTCLOS(HduType.PRIMARY, ValueType.REAL, "Shutter close time"), + + /** + * Shutter identification and hardware version. + */ + SHUTHWV(HduType.PRIMARY, ValueType.STRING, "Shutter hardware version"), + + /** + * Time for the shutter to open fully. + */ + SHUTOPEN(HduType.PRIMARY, ValueType.REAL, "Shutter open time"), + + /** + * Shutter status. + */ + SHUTSTAT(HduType.PRIMARY, ValueType.STRING, "Shutter status"), + + /** + * Shutter software version. + */ + SHUTSWV(HduType.PRIMARY, ValueType.STRING, "Shutter software version"), + + /** + * Slit or mask hole identification for the aperture(s). The string consists of a number, an object type number + * (0=sky, 1=object, etc.), the right ascension and declination, and the object name or title. declination, and the + * object name or title. This can replace OBJNAME, APRA/OBJRA, and APDEC/OBJDEC. + */ + SLIT(HduType.PRIMARY, ValueType.STRING, ""), + + /** + * Slit or mask hole identification for the aperture(s). The string consists of a number, an object type number + * (0=sky, 1=object, etc.), the right ascension and declination, and the object name or title. declination, and the + * object name or title. This can replace OBJNAME, APRA/OBJRA, and APDEC/OBJDEC. + */ + SLITnnn(HduType.PRIMARY, ValueType.STRING, ""), + + /** + * FWHM of the object spectrum profile on the detector. The width is in the units of the spatial world coordinate + * system. This may be approximate. It is particularly useful for specifying the profile width of fiber fed spectra. + */ + SPECFWHM(HduType.EXTENSION, ValueType.REAL, "FWHM of spectrum"), + + /** + * UTC of the start of each subexposure. + */ + SUT(HduType.PRIMARY_EXTENSION, ValueType.STRING, "UTC of subexposure start"), + + /** + * UTC of the start of each subexposure. + */ + SUTn(HduType.PRIMARY_EXTENSION, ValueType.STRING, "UTC of subexposure start"), + + /** + * FWHM of the object spectrum profile on the detector. The width is in the units of the spatial world coordinate + * system. This may be approximate. It is particularly useful for specifying the profile width of fiber fed spectra. + */ + SWIDnnn(HduType.EXTENSION, ValueType.REAL, "FWHM of spectrum"), + + /** + * Modified Julian date at the time of the altitude/azimuth keywords. + */ + TELAAMJD(HduType.PRIMARY, ValueType.REAL, "MJD at for alt/az"), + + /** + * Telescope pointing altitude at the time given by TELAAMJD. + */ + TELALT(HduType.PRIMARY, ValueType.STRING, "Telescope altitude"), + + /** + * Telescope pointing azimuth at the time given by TELAAMJD. + */ + TELAZ(HduType.PRIMARY, ValueType.STRING, "Telescope azimuth"), + + /** + * Telescope configuration. The configuration defines the mirrors, correctors, light paths, etc. + */ + TELCONF(HduType.PRIMARY, ValueType.STRING, "Telescope configuration"), + + /** + * Telescope pointing declination. + */ + TELDEC(HduType.PRIMARY, ValueType.STRING, "Telescope declination"), + + /** + * Declination unit. + */ + TELDECU(HduType.PRIMARY, ValueType.STRING, "Declination unit"), + + /** + * Telescope pointing coordinate epoch. + */ + TELEPOCH(HduType.PRIMARY, ValueType.REAL, "Telescope coordinate epoch"), + + /** + * Telescope pointing coordinate system equinox. A value before 1984 is Besselian otherwise it is Julian. + */ + TELEQUIN(HduType.PRIMARY, ValueType.REAL, "Telescope coordinate equinox"), + + /** + * Telescope focus value in available units. + */ + TELFOCUS(HduType.PRIMARY, ValueType.REAL, "Telescope focus"), + + /** + * Time of zenith distance and hour angle + */ + TELMJD(HduType.PRIMARY, ValueType.REAL, "Time of zenith distance and hour angle"), + + /** + * Times for the telescope sensor measurements given as modified Julian dates. + */ + TELMJDn(HduType.PRIMARY, ValueType.REAL, ""), + + /** + * Telescope position angle measurements in appropriate units. This could include altitude and azimuth measurements. + */ + TELPAN(HduType.PRIMARY, ValueType.REAL, ""), + + /** + * Telescope position angle measurements in appropriate units. This could include altitude and azimuth measurements. + */ + TELPANn(HduType.PRIMARY, ValueType.REAL, ""), + + /** + * Telescope linear position sensor measurements in appropriate units. + */ + TELPOS(HduType.PRIMARY, ValueType.REAL, ""), + + /** + * Telescope linear position sensor measurements in appropriate units. + */ + TELPOSn(HduType.PRIMARY, ValueType.REAL, ""), + + /** + * Telescope pressure sensor measurements in appropriate units. + */ + TELPRE(HduType.PRIMARY, ValueType.REAL, ""), + + /** + * Telescope pressure sensor measurements in appropriate units. + */ + TELPREn(HduType.PRIMARY, ValueType.REAL, ""), + + /** + * Telescope pointing right ascension. + */ + TELRA(HduType.PRIMARY, ValueType.STRING, "Telescope right ascension"), + + /** + * Telescope pointing coordinate system type. + */ + TELRADEC(HduType.PRIMARY, ValueType.STRING, "Telescope coordinate system"), + + /** + * Right ascension unit. + */ + TELRAU(HduType.PRIMARY, ValueType.STRING, "Right ascension unit"), + + /** + * Telescope status. + */ + TELSTAT(HduType.PRIMARY, ValueType.STRING, "Telescope status"), + + /** + * Telescope control system software version. + */ + TELTCS(HduType.PRIMARY, ValueType.STRING, "Telescope control system"), + + /** + * Telescope temperature sensor measurements in degrees Celsius. The comment string may be modified to indicate the + * location of the measurement. + */ + TELTEM(HduType.PRIMARY, ValueType.REAL, "Telescope temperature"), + + /** + * Telescope temperature sensor measurements in degrees Celsius. The comment string may be modified to indicate the + * location of the measurement. + */ + TELTEMn(HduType.PRIMARY, ValueType.REAL, "Telescope temperature"), + + /** + * Declination telescope tracking rate in arc seconds per second. + */ + TELTKDEC(HduType.PRIMARY, ValueType.REAL, "Tracking rate from siderial"), + + /** + * Right ascension telescope tracking rate from siderial in arc seconds per second. + */ + TELTKRA(HduType.PRIMARY, ValueType.REAL, "Tracking rate from siderial"), + + /** + * Telescope hardware version. + */ + TELVER(HduType.PRIMARY, ValueType.STRING, "Telescope version"), + + /** + * Telescope voltage sensor measurements in volts. + */ + TELVOL(HduType.PRIMARY, ValueType.REAL, ""), + + /** + * Telescope voltage sensor measurements in volts. + */ + TELVOLn(HduType.PRIMARY, ValueType.REAL, ""), + + /** + * Time of exposure end in the TSYSEND system. + */ + TIMEEND(HduType.PRIMARY_EXTENSION, ValueType.STRING, "Time of exposure end"), + + /** + * Time of header creation. + */ + TIMEHDR(HduType.PRIMARY_EXTENSION, ValueType.STRING, "Time of header creation"), + + /** + * Default time system. All times which do not have a "timesys" element associated with them in this dictionary + * default to this keyword. . + */ + TIMESYS(HduType.PRIMARY, ValueType.STRING, "Default time system"), + + /** + * Section of the recorded image to be kept after calibration processing. This is generally the part of the data + * section containing useful data. The section is in in binned pixels if binning is done. + */ + TRIMSEC(HduType.EXTENSION, ValueType.STRING, "Section of useful data"), + + /** + * Time system for the TIMEEND keyword. + */ + TSYSEND(HduType.PRIMARY_EXTENSION, ValueType.STRING, "Time system for TIMEEND"), + + /** + * Time system for the header creation keywords. + */ + TSYSHDR(HduType.PRIMARY_EXTENSION, ValueType.STRING, "Time system for header creation"), + + /** + * Time system for the TIME-OBS keyword. + */ + TSYSOBS(HduType.PRIMARY_EXTENSION, ValueType.STRING, "Time system for TIME-OBS"), + + /** + * TV name. + */ + TV(HduType.PRIMARY, ValueType.STRING, "TV"), + + /** + * TV filter names. This name is the astronomical standard name if applicable; i.e. U, B, Gunn I, etc. The filter + * type and filter device position are given by other keywords. + */ + TVFILTn(HduType.PRIMARY, ValueType.STRING, "Filter name"), + + /** + * Television focus value in available units. + */ + TVFOCn(HduType.PRIMARY, ValueType.REAL, "Television focus"), + + /** + * TV filter position given as filter wheel number or other filter system position measurement. + */ + TVFPOSn(HduType.PRIMARY, ValueType.REAL, "Filter system position"), + + /** + * TV filter type. This is the technical specification or observatory identification name. + */ + TVFTYPn(HduType.PRIMARY, ValueType.STRING, "Filter type"), + + /** + * TV identification and hardware version. + */ + TVHWV(HduType.PRIMARY, ValueType.STRING, "TV Hardware"), + + /** + * Times for the guider television sensor measurements given as modified Julian dates. + */ + TVMJDn(HduType.PRIMARY, ValueType.REAL, ""), + + /** + * TV name. + */ + TVn(HduType.PRIMARY, ValueType.STRING, "TV"), + + /** + * TV filter names. This name is the astronomical standard name if applicable; i.e. U, B, Gunn I, etc. The filter + * type and filter device position are given by other keywords. + */ + TVnFILTn(HduType.PRIMARY, ValueType.STRING, "Filter name"), + + /** + * Television focus value in available units. + */ + TVnFOCn(HduType.PRIMARY, ValueType.REAL, "Television focus"), + + /** + * TV filter position given as filter wheel number or other filter system position measurement. + */ + TVnFPOSn(HduType.PRIMARY, ValueType.REAL, "Filter system position"), + + /** + * TV filter type. This is the technical specification or observatory identification name. + */ + TVnFTYPn(HduType.PRIMARY, ValueType.STRING, "Filter type"), + + /** + * TV identification and hardware version. + */ + TVnHWV(HduType.PRIMARY, ValueType.STRING, "TV Hardware"), + + /** + * Times for the guider television sensor measurements given as modified Julian dates. + */ + TVnMJDn(HduType.PRIMARY, ValueType.REAL, ""), + + /** + * Television position angle measurements in appropriate units. + */ + TVnPANn(HduType.PRIMARY, ValueType.REAL, ""), + + /** + * Television linear position sensor measurements in appropriate units. + */ + TVnPOSn(HduType.PRIMARY, ValueType.REAL, "Television position ()"), + + /** + * Television pressure sensor measurements in appropriate units. + */ + TVnPREn(HduType.PRIMARY, ValueType.REAL, ""), + + /** + * TV status. + */ + TVnSTAT(HduType.PRIMARY, ValueType.STRING, ""), + + /** + * TV software version. + */ + TVnSWV(HduType.PRIMARY, ValueType.NONE, ""), + + /** + * Television temperature sensor measurements in degrees Celsius. + */ + TVnTEMn(HduType.PRIMARY, ValueType.REAL, ""), + + /** + * Television voltage sensor measurements in volts. + */ + TVnVOLn(HduType.PRIMARY, ValueType.REAL, ""), + + /** + * Television position angle measurements in appropriate units. + */ + TVPANn(HduType.PRIMARY, ValueType.REAL, ""), + + /** + * Television linear position sensor measurements in appropriate units. + */ + TVPOSn(HduType.PRIMARY, ValueType.REAL, "Television position ()"), + + /** + * Television pressure sensor measurements in appropriate units. + */ + TVPREn(HduType.PRIMARY, ValueType.REAL, ""), + + /** + * TV status. + */ + TVSTAT(HduType.PRIMARY, ValueType.STRING, ""), + + /** + * TV software version. + */ + TVSWV(HduType.PRIMARY, ValueType.NONE, ""), + + /** + * Television temperature sensor measurements in degrees Celsius. + */ + TVTEMn(HduType.PRIMARY, ValueType.REAL, ""), + + /** + * Television voltage sensor measurements in volts. + */ + TVVOLn(HduType.PRIMARY, ValueType.REAL, ""), + + /** + * Altitude unit. + */ + UNITALT(HduType.PRIMARY, ValueType.STRING, "Altitude unit"), + + /** + * Plane angle unit. + */ + UNITANG(HduType.PRIMARY, ValueType.STRING, "Plane angle unit"), + + /** + * Focal plane aperture size unit. + */ + UNITAP(HduType.PRIMARY, ValueType.STRING, "Aperture size unit"), + + /** + * Area unit. + */ + UNITAREA(HduType.PRIMARY, ValueType.STRING, "Area unit"), + + /** + * Azimuth unit. + */ + UNITAZ(HduType.PRIMARY, ValueType.STRING, "Azimuth unit"), + + /** + * Capacitance unit. + */ + UNITCAP(HduType.PRIMARY, ValueType.STRING, "Capacitance unit"), + + /** + * Charge unit. + */ + UNITCHAR(HduType.PRIMARY, ValueType.STRING, "Charge unit"), + + /** + * Conductance unit. + */ + UNITCOND(HduType.PRIMARY, ValueType.STRING, "Conductance unit"), + + /** + * Current unit. + */ + UNITCUR(HduType.PRIMARY, ValueType.STRING, "Current unit"), + + /** + * Delination unit. + */ + UNITDEC(HduType.PRIMARY, ValueType.STRING, "Declination unit"), + + /** + * Energy unit. + */ + UNITENER(HduType.PRIMARY, ValueType.STRING, "Energy unit"), + + /** + * Event unit. + */ + UNITEVNT(HduType.PRIMARY, ValueType.STRING, "Event unit"), + + /** + * Flux unit. + */ + UNITFLUX(HduType.PRIMARY, ValueType.STRING, "Flux unit"), + + /** + * Force unit. + */ + UNITFORC(HduType.PRIMARY, ValueType.STRING, "Force unit"), + + /** + * Frequency unit. + */ + UNITFREQ(HduType.PRIMARY, ValueType.STRING, "Frequency unit"), + + /** + * Time of day unit. + */ + UNITHOUR(HduType.PRIMARY, ValueType.STRING, "Time of day unit"), + + /** + * Illuminance unit. + */ + UNITILLU(HduType.PRIMARY, ValueType.STRING, "Illuminance unit"), + + /** + * Inductance unit. + */ + UNITINDU(HduType.PRIMARY, ValueType.STRING, "Inductance unit"), + + /** + * Latitude unit. + */ + UNITLAT(HduType.PRIMARY, ValueType.STRING, "Latitude unit"), + + /** + * Length unit. A wavelength unit is also provided so this unit is primarily used to instrumental descriptions. + */ + UNITLEN(HduType.PRIMARY, ValueType.STRING, "Length unit"), + + /** + * Luminous flux unit. + */ + UNITLFLX(HduType.PRIMARY, ValueType.STRING, "Luminous flux unit"), + + /** + * Luminous intensity unit. + */ + UNITLINT(HduType.PRIMARY, ValueType.STRING, "Luminous intensity unit"), + + /** + * Longitude unit. + */ + UNITLONG(HduType.PRIMARY, ValueType.STRING, "Longitude unit"), + + /** + * Mass unit. + */ + UNITMASS(HduType.PRIMARY, ValueType.STRING, "Mass unit"), + + /** + * Magnetic density unit. + */ + UNITMDEN(HduType.PRIMARY, ValueType.STRING, "Magnetic density unit"), + + /** + * Magnetic field unit. + */ + UNITMFLD(HduType.PRIMARY, ValueType.STRING, "Magnetic field unit"), + + /** + * Magnetic flux unit. + */ + UNITMFLX(HduType.PRIMARY, ValueType.STRING, "Magnetic flux unit"), + + /** + * Position angle unit. + */ + UNITPA(HduType.PRIMARY, ValueType.STRING, "Position angle unit"), + + /** + * Power unit. + */ + UNITPOW(HduType.PRIMARY, ValueType.STRING, "Wavelength unit"), + + /** + * Pressure unit. + */ + UNITPRES(HduType.PRIMARY, ValueType.STRING, "Pressure unit"), + + /** + * Right ascension unit. + */ + UNITRA(HduType.PRIMARY, ValueType.STRING, "Right ascension unit"), + + /** + * Celestial rate of motion. + */ + UNITRATE(HduType.PRIMARY, ValueType.STRING, "Celestial rate of motion"), + + /** + * Resistance unit. + */ + UNITRES(HduType.PRIMARY, ValueType.STRING, "Resistance unit"), + + /** + * Solid angle unit. + */ + UNITSANG(HduType.PRIMARY, ValueType.STRING, "Solid angle unit"), + + /** + * Celestial separation unit. + */ + UNITSEP(HduType.PRIMARY, ValueType.STRING, "Separation unit"), + + /** + * Temperature unit. + */ + UNITTEMP(HduType.PRIMARY, ValueType.STRING, "Temperature unit"), + + /** + * Time unit. + */ + UNITTIME(HduType.PRIMARY, ValueType.STRING, "Time unit"), + + /** + * Velocity unit. + */ + UNITVEL(HduType.PRIMARY, ValueType.STRING, "Velocity unit"), + + /** + * Voltage unit. + */ + UNITVOLT(HduType.PRIMARY, ValueType.STRING, "Voltage unit"), + + /** + * UTC time at the start of the exposure. + */ + UTC_OBS("UTC-OBS", HduType.PRIMARY_EXTENSION, ValueType.STRING, "UTC of exposure start"), + + /** + * UTC at the end of the exposure. + */ + UTCEND(HduType.PRIMARY_EXTENSION, ValueType.STRING, "UTC at end of exposure"), + + /** + * UTC of header creation. + */ + UTCHDR(HduType.PRIMARY_EXTENSION, ValueType.STRING, "UTC of header creation"), + + /** + * Default UTC time for the observation. This keyword is generally not used and is UTC-OBS keyword for the start of + * the exposure on the detector is used. + */ + UTCOBS(HduType.PRIMARY_EXTENSION, ValueType.STRING, "UTC of observation"), + + /** + * IRAF WCS attribute strings for all axes. These are defined by the IRAF WCS system. + */ + WAT_nnn(HduType.PRIMARY_EXTENSION, ValueType.STRING, ""), + + /** + * IRAF WCS attribute strings. These are defined by the IRAF WCS system. + */ + WATn_nnn(HduType.PRIMARY_EXTENSION, ValueType.STRING, ""), + + /** + * Descriptive string identifying the source of the astrometry used to derive the WCS. One example is the exposure + * used to derive a WCS apart from the reference coordinate. + */ + WCSAnnn(HduType.PRIMARY_EXTENSION, ValueType.STRING, "WCS Source"), + + /** + * Descriptive string identifying the source of the astrometry used to derive the WCS. One example is the exposure + * used to derive a WCS apart from the reference coordinate. + */ + WCSASTRM(HduType.PRIMARY_EXTENSION, ValueType.STRING, "WCS Source"), + + /** + * Dimensionality of the WCS physical system. In IRAF a WCS can have a higher dimensionality than the image. + */ + WCSDIM(HduType.PRIMARY_EXTENSION, ValueType.INTEGER, "WCS dimensionality"), + + /** + * Epoch of the coordinates used in the world coordinate system. + */ + WCSEnnn(HduType.PRIMARY_EXTENSION, ValueType.REAL, "WCS coordinate epoch"), + + /** + * Equinox when equatorial coordinates are used in the world coordinate system. A value before 1984 is Besselian + * otherwise it is Julian. + */ + WCSEPOCH(HduType.PRIMARY_EXTENSION, ValueType.REAL, "WCS coordinate epoch"), + + /** + * Coordinate system type when equatorial coordinates are used in the world coordinate system. + */ + WCSRADEC(HduType.PRIMARY_EXTENSION, ValueType.STRING, "WCS coordinate system"), + + /** + * Coordinate system type when equatorial coordinates are used in the world coordinate system. + */ + WCSRnnn(HduType.PRIMARY_EXTENSION, ValueType.STRING, "WCS coordinate system"), + + /** + * Weather condition description. Generally this would be either 'clear' or 'partly cloudy'. + */ + WEATHER(HduType.PRIMARY, ValueType.STRING, "Weather conditions"), + + /** + * Zenith distance of telescope pointing at TELMJD. + */ + ZD(HduType.PRIMARY, ValueType.REAL, "Zenith distance"), + + /** + * Modified Julian date at the start of the exposure. The fractional part of the date is given to better than a + * second of time. + */ + MJD_OBS("MJD-OBS", HduType.PRIMARY_EXTENSION, ValueType.REAL, "MJD of exposure start"), + + // SBIG. https://github.com/nom-tam-fits/nom-tam-fits/blob/master/src/main/java/nom/tam/fits/header/extra/SBFitsExt.java + + /** + * Aperture Area of the Telescope used in square millimeters. Note that we are specifying the area as well as the + * diameter because we want to be able to correct for any central obstruction. + */ + APTAREA(HduType.IMAGE, ValueType.REAL, "Aperture Area of the Telescope"), + + /** + * Aperture Diameter of the Telescope used in millimeters. + */ + APTDIA(HduType.IMAGE, ValueType.REAL, "Aperture Diameter of the Telescope"), + + /** + * Upon initial display of this image use this ADU level for the Black level. + */ + CBLACK(HduType.IMAGE, ValueType.INTEGER, "use this ADU level for the Black"), + + /** + * Temperature of CCD when exposure taken. + */ + CCD_TEMP("CCD-TEMP", HduType.IMAGE, ValueType.REAL, "Temperature of CCD"), + + /** + * Altitude in degrees of the center of the image in degrees. Format is the same as the OBJCTDEC keyword. + */ + CENTALT(HduType.IMAGE, ValueType.STRING, "Altitude of the center of the image"), + + /** + * Azimuth in degrees of the center of the image in degrees. Format is the same as the OBJCTDEC keyword. + */ + CENTAZ(HduType.IMAGE, ValueType.STRING, "Azimuth of the center of the image"), + + /** + * Upon initial display of this image use this ADU level as the White level. For the SBIG method of displaying + * images using Background and Range the following conversions would be used: Background = CBLACK Range = CWHITE - + * CBLACK. + */ + CWHITE(HduType.IMAGE, ValueType.INTEGER, "use this ADU level for the White"), + + /** + * Electronic gain in e-/ADU. + */ + EGAIN(HduType.IMAGE, ValueType.REAL, "Electronic gain in e-/ADU"), + /* + * Optional Keywords

The following Keywords are not defined in the FITS Standard but are defined in this + * Standard. They may or may not be included by AIP Software Packages adhering to this Standard. Any of these + * keywords read by an AIP Package must be preserved in files written.

+ */ + /** + * Focal Length of the Telescope used in millimeters. + */ + FOCALLEN(HduType.IMAGE, ValueType.REAL, "Focal Length of the Telescope"), + + /** + * This indicates the type of image and should be one of the following: Light Frame Dark Frame Bias Frame Flat + * Field. + */ + IMAGETYP(HduType.IMAGE, ValueType.STRING, "type of image"), + + /** + * This is the Declination of the center of the image in degrees. The format for this is ‘+25 12 34.111’ (SDD MM + * SS.SSS) using a space as the separator. For the sign, North is + and South is -. + */ + OBJCTDEC(HduType.IMAGE, ValueType.STRING, "Declination of the center of the image"), + + /** + * This is the Right Ascension of the center of the image in hours, minutes and secon ds. The format for this is ’12 + * 24 23.123’ (HH MM SS.SSS) using a space as the separator. + */ + OBJCTRA(HduType.IMAGE, ValueType.STRING, "Right Ascension of the center of the image"), + + /** + * Add this ADU count to each pixel value to get to a zero - based ADU. For example in SBIG images we add 100 ADU to + * each pixel to stop underflow at Zero ADU from noise. We would set PEDESTAL to - 100 in this case. + */ + PEDESTAL(HduType.IMAGE, ValueType.INTEGER, "ADU count to each pixel value to get to a zero"), + + /** + * This string indicates the version of this standard that the image was created to ie ‘SBFITSEXT Version 1.0’. + */ + SBSTDVER(HduType.IMAGE, ValueType.STRING, "version of this standard"), + + /** + * This is the setpoint of the cooling in degrees C. If it is not specified the setpoint is assumed to be the + */ + SET_TEMP("SET-TEMP", HduType.IMAGE, ValueType.REAL, "setpoint of the cooling in degrees C"), + + /** + * Latitude of the imaging location in degrees. Format is the same as the OBJCTDEC key word. + */ + SITELAT(HduType.IMAGE, ValueType.STRING, "Latitude of the imaging location"), + + /** + * Longitude of the imaging location in degrees. Format is the same as the OBJCTDEC keyword. + */ + SITELONG(HduType.IMAGE, ValueType.STRING, "Longitude of the imaging location"), + + /** + * Number of images combined to make this image as in Track and Accumulate or Co - Added images. + */ + SNAPSHOT(HduType.IMAGE, ValueType.INTEGER, "Number of images combined"), + + /** + * This indicates the name and version of the Software that initially created this file ie ‘SBIGs CCDOps Version + * 5.10’. + */ + SWCREATE(HduType.IMAGE, ValueType.STRING, "created version of the Software"), + + /** + * This indicates the name and version of the Software that modified this file ie ‘SBIGs CCDOps Version 5.10’ and + * the re can be multiple copies of this keyword. Only add this keyword if you actually modified the image and we + * suggest placing this above the HISTORY keywords corresponding to the modifications made to the image. + */ + SWMODIFY(HduType.IMAGE, ValueType.STRING, "modified version of the Software"), + + /** + * If the image was auto-guided this is the exposure time in seconds of the tracker used to acquire this image. If + * this keyword is not present then the image was unguided or hand guided. + */ + TRAKTIME(HduType.IMAGE, ValueType.REAL, "exposure time in seconds of the tracker"), + + /** + * Binning factor in width. + */ + XBINNING(HduType.IMAGE, ValueType.INTEGER, "Binning factor in width"), + + /** + * Sub frame X position of upper left pixel relative to whole frame in binned pixel units. + */ + XORGSUBF(HduType.IMAGE, ValueType.INTEGER, "Sub frame X position"), + + /** + * Pixel width in microns (after binning). + */ + XPIXSZ(HduType.IMAGE, ValueType.REAL, "Pixel width in microns"), + + /** + * Binning factor in height. + */ + YBINNING(HduType.IMAGE, ValueType.INTEGER, "Binning factor in height"), + + /** + * Sub frame Y position of upper left pixel relative to whole frame in binned pixel units. + */ + YORGSUBF(HduType.IMAGE, ValueType.INTEGER, "Sub frame Y position"), + + /** + * Pixel height in microns (after binning). + */ + YPIXSZ(HduType.IMAGE, ValueType.REAL, "Pixel height in microns"), + + // Non-Standard. https://github.com/nom-tam-fits/nom-tam-fits/blob/master/src/main/java/nom/tam/fits/header/NonStandard.java + + /** + * The HIERARCH keyword, when followed by spaces in columns 9 and 10 of the FITS card image, indicates that the ESO + * HIERARCH keyword convention should be used to interpret the name and value of the keyword. The HIERARCH keyword + * formally has no value because it is not followed by an equals sign in column 9. Under the HIERARCH convention the + * actual name of the keyword begins in column 11 of the card image and is terminated by the equal sign ('=') + * character. The name can contain any number of characters as long as it fits within columns 11 and 80 of the card + * image and also leaves enough space for the equal sign separator and the value field. The name can contain any + * printable ASCII text character, including spaces and lower-case characters, except for the equal sign character + * which serves as the terminator of the name field. Leading and trailing spaces in the name field are not + * significant, but embedded spaces within the name are significant. The value field follows the equals sign and + * must conform to the syntax for a free-format value field as defined in the FITS Standard. The value field may be + * null, in which case it contains only space characters, otherwise it may contain either a character string + * enclosed in single quotes, the logical constant T or F, an integer number, a floating point number, a complex + * integer number, or a complex floating point number. The value field may be followed by an optional comment + * string. The comment field must be separated from the value field by a slash character ('/'). It is recommended + * that the slash character be preceeded and followed by a space character. Example: "HIERARCH Filter Wheel = 12 / + * filter position". In this example the logical name of the keyword is 'Filter Wheel' and the value is 12. + */ + HIERARCH(HduType.ANY, ValueType.NONE, "denotes the HIERARCH keyword convention"), + + /** + * The presence of this keyword with a value = T in an extension key indicates that the keywords contained in the + * primary key (except the FITS Mandatory keywords, and any COMMENT, HISTORY or 'blank' keywords) are to be + * inherited, or logically included in that extension key. + */ + INHERIT(HduType.EXTENSION, ValueType.LOGICAL, "denotes the INHERIT keyword convention"); + + private val header: FitsHeaderKey + + constructor(name: String, hduType: HduType, valueType: ValueType, comment: String) { + header = FitsHeaderKeyItem(name, hduType, valueType, comment) + } + + constructor(hduType: HduType, valueType: ValueType, comment: String) { + header = FitsHeaderKeyItem(name, hduType, valueType, comment) + } + + override val key + get() = header.key + + override val comment + get() = header.comment + + override val hduType + get() = header.hduType + + override val valueType + get() = header.valueType + + override fun n(vararg numbers: Int) = header.n(*numbers) + + companion object { + + @JvmStatic val NAXIS1 = NAXISn.n(1) + @JvmStatic val NAXIS2 = NAXISn.n(2) + @JvmStatic val NAXIS3 = NAXISn.n(3) + + @JvmStatic val CDELT1 = CDELTn.n(1) + @JvmStatic val CDELT2 = CDELTn.n(2) + + @JvmStatic val CROTA1 = CROTAn.n(1) + @JvmStatic val CROTA2 = CROTAn.n(2) + } } diff --git a/nebulosa-fits/src/main/kotlin/nebulosa/fits/FitsKeywordDictionary.kt b/nebulosa-fits/src/main/kotlin/nebulosa/fits/FitsKeywordDictionary.kt deleted file mode 100644 index caa1055eb..000000000 --- a/nebulosa-fits/src/main/kotlin/nebulosa/fits/FitsKeywordDictionary.kt +++ /dev/null @@ -1,4621 +0,0 @@ -package nebulosa.fits - -@Suppress("EnumEntryName") -enum class FitsKeywordDictionary : FitsKeyword { - - // Standard. - // https://github.com/nom-tam-fits/nom-tam-fits/blob/master/src/main/java/nom/tam/fits/header/Standard.java - // https://github.com/nom-tam-fits/nom-tam-fits/blob/master/src/main/java/nom/tam/fits/header/ObservationDescription.java - // https://github.com/nom-tam-fits/nom-tam-fits/blob/master/src/main/java/nom/tam/fits/header/ObservationDurationDescription.java - - /** - * The value field shall contain a character string identifying who compiled the information in the data associated - * with the key. This keyword is appropriate when the data originate in a published paper or are compiled from many - * sources. - */ - AUTHOR(HduType.ANY, ValueType.STRING, "author of the data"), - - /** - * The value field shall contain an integer. The absolute value is used in computing the sizes of data structures. - * It shall specify the number of bits that represent a data value. RANGE: -64,-32,8,16,32 - */ - BITPIX(HduType.ANY, ValueType.INTEGER, "bits per data value"), - - /** - * This keyword shall be used only in primary array headers or IMAGE extension headers with positive values of - * BITPIX (i.e., in arrays with integer data). Columns 1-8 contain the string, `BLANK ' (ASCII blanks in columns - * 6-8). The value field shall contain an integer that specifies the representation of array values whose physical - * values are undefined. - */ - BLANK(HduType.IMAGE, ValueType.INTEGER, "value used for undefined array elements"), - - /** - * Columns 1-8 contain ASCII blanks. This keyword has no associated value. Columns 9-80 may contain any ASCII text. - * Any number of card images with blank keyword fields may appear in a key. - */ - BLANKS(" ", HduType.ANY, ValueType.NONE, ""), - - /** - * This keyword may be used only in the primary key. It shall appear within the first 36 card images of the FITS - * file. (Note: This keyword thus cannot appear if NAXIS is greater than 31, or if NAXIS is greater than 30 and the - * EXTEND keyword is present.) Its presence with the required logical value of T advises that the physical block - * size of the FITS file on which it appears may be an integral multiple of the logical record length, and not - * necessarily equal to it. Physical block size and logical record length may be equal even if this keyword is - * present or unequal if it is absent. It is reserved primarily to prevent its use with other meanings. Since the - * issuance of version 1 of the standard, the BLOCKED keyword has been deprecated. - */ - @Deprecated("no blocksize other that 2880 may be used") - BLOCKED(HduType.PRIMARY, ValueType.LOGICAL, "is physical blocksize a multiple of 2880?"), - - /** - * This keyword shall be used, along with the BZERO keyword, when the array pixel values are not the true physical - * values, to transform the primary data array values to the true physical values they represent, using the - * equation: physical_value = BZERO + BSCALE * array_value. The value field shall contain a floating point number - * representing the coefficient of the linear term in the scaling equation, the ratio of physical value to array - * value at zero offset. The default value for this keyword is 1.0. - */ - BSCALE(HduType.IMAGE, ValueType.REAL, "linear factor in scaling equation"), - - /** - * The value field shall contain a character string, describing the physical units in which the quantities in the - * array, after application of BSCALE and BZERO, are expressed. The units of all FITS key keyword values, with the - * exception of measurements of angles, should conform with the recommendations in the IAU Style Manual. For angular - * measurements given as floating point values and specified with reserved keywords, degrees are the recommended - * units (with the units, if specified, given as 'deg'). - */ - BUNIT(HduType.IMAGE, ValueType.STRING, "physical units of the array values"), - - /** - * This keyword shall be used, along with the BSCALE keyword, when the array pixel values are not the true physical - * values, to transform the primary data array values to the true values using the equation: physical_value = BZERO - * + BSCALE * array_value. The value field shall contain a floating point number representing the physical value - * corresponding to an array value of zero. The default value for this keyword is 0.0. - */ - BZERO(HduType.IMAGE, ValueType.REAL, "zero point in scaling equation"), - - /** - * The value field shall contain a floating point number giving the partial derivative of the coordinate specified - * by the CTYPEn keywords with respect to the pixel index, evaluated at the reference point CRPIXn, in units of the - * coordinate specified by the CTYPEn keyword. These units must follow the prescriptions of section 5.3 of the FITS - * Standard. - */ - CDELTn(HduType.IMAGE, ValueType.REAL, "coordinate increment along axis"), - - /** - * This keyword shall have no associated value; columns 9-80 may contain any ASCII text. Any number of COMMENT card - * images may appear in a key. - */ - COMMENT(HduType.ANY, ValueType.NONE, ""), - - /** - * The CONTINUE keyword, when followed by spaces in columns 9 and 10 of the card image and a character string - * enclosed in single quotes starting in column 11 or higher, indicates that the quoted string should be treated as - * a continuation of the character string value in the previous key keyword. To conform to this convention, the - * character string value on the previous keyword must end with the ampersand character ('&'), but the ampersand - * is not part of the value string and should be deleted before concatenating the strings together. The character - * string value may be continued on any number of consecutive CONTINUE keywords, thus effectively allowing - * arbitrarily long strings to be written as keyword values. - */ - CONTINUE(HduType.ANY, ValueType.NONE, "denotes the CONTINUE long string keyword convention"), - - /** - * This keyword is used to indicate a rotation from a standard coordinate system described by the CTYPEn to a - * different coordinate system in which the values in the array are actually expressed. Rules for such rotations are - * not further specified in the Standard; the rotation should be explained in comments. The value field shall - * contain a floating point number giving the rotation angle in degrees between axis n and the direction implied by - * the coordinate system defined by CTYPEn. In unit degrees. - */ - CROTAn(HduType.IMAGE, ValueType.REAL, "coordinate system rotation angle"), - - /** - * The value field shall contain a floating point number, identifying the location of a reference point along axis - * n, in units of the axis index. This value is based upon a counter that runs from 1 to NAXISn with an increment of - * 1 per pixel. The reference point value need not be that for the center of a pixel nor lie within the actual data - * array. Use comments to indicate the location of the index point relative to the pixel. - */ - CRPIXn(HduType.IMAGE, ValueType.REAL, "coordinate system reference pixel"), - - /** - * The value field shall contain a floating point number, giving the value of the coordinate specified by the CTYPEn - * keyword at the reference point CRPIXn. Units must follow the prescriptions of section 5.3 of the FITS Standard. - */ - CRVALn(HduType.IMAGE, ValueType.REAL, "coordinate system value at reference pixel"), - - /** - * The value field shall contain a character string, giving the name of the coordinate represented by axis n. - */ - CTYPEn(HduType.IMAGE, ValueType.STRING, "name of the coordinate axis"), - - /** - * The value field shall always contain a floating point number, regardless of the value of BITPIX. This number - * shall give the maximum valid physical value represented by the array, exclusive of any special values. - */ - DATAMAX(HduType.IMAGE, ValueType.REAL, "maximum data value"), - - /** - * The value field shall always contain a floating point number, regardless of the value of BITPIX. This number - * shall give the minimum valid physical value represented by the array, exclusive of any special values. - */ - DATAMIN(HduType.IMAGE, ValueType.REAL, "minimum data value"), - - /** - * The date on which the HDU was created, in the format specified in the FITS Standard. The old date format was - * 'yy/mm/dd' and may be used only for dates from 1900 through 1999. the new Y2K compliant date format is - * 'yyyy-mm-dd' or 'yyyy-mm-ddTHH:MM:SS[.sss]'. - */ - DATE(HduType.ANY, ValueType.STRING, "date of file creation"), - - /** - * The date of the observation, in the format specified in the FITS Standard. The old date format was 'yy/mm/dd' and - * may be used only for dates from 1900 through 1999. The new Y2K compliant date format is 'yyyy-mm-dd' or - * 'yyyy-mm-ddTHH:MM:SS[.sss]'. - */ - DATE_OBS("DATE-OBS", HduType.ANY, ValueType.STRING, "date of the observation"), - - /** - * This keyword has no associated value. Columns 9-80 shall be filled with ASCII blanks. - */ - END(HduType.ANY, ValueType.NONE, ""), - - /** - * The value field shall contain a floating point number giving the equinox in years for the celestial coordinate - * system in which positions are expressed. Starting with Version 1, the Standard has deprecated the use of the - * EPOCH keyword and thus it shall not be used in FITS files created after the adoption of the standard; rather, the - * EQUINOX keyword shall be used. - */ - @Deprecated("use EQUINOX instead") - EPOCH(HduType.ANY, ValueType.REAL, "equinox of celestial coordinate system"), - - /** - * The value field shall contain a floating point number giving the equinox in years for the celestial coordinate - * system in which positions are expressed. - */ - EQUINOX(HduType.ANY, ValueType.REAL, "equinox of celestial coordinate system"), - - /** - * If the FITS file may contain extensions, a card image with the keyword EXTEND and the value field containing the - * logical value T must appear in the primary key immediately after the last NAXISn card image, or, if NAXIS=0, the - * NAXIS card image. The presence of this keyword with the value T in the primary key does not require that - * extensions be present. - */ - EXTEND(HduType.PRIMARY, ValueType.LOGICAL, "may the FITS file contain extensions?"), - - /** - * The value field shall contain an integer, specifying the level in a hierarchy of extension levels of the - * extension key containing it. The value shall be 1 for the highest level; levels with a higher value of this - * keyword shall be subordinate to levels with a lower value. If the EXTLEVEL keyword is absent, the file should be - * treated as if the value were 1. This keyword is used to describe an extension and should not appear in the - * primary key.RANGE: [1:] DEFAULT: 1 - */ - EXTLEVEL(HduType.EXTENSION, ValueType.INTEGER, "hierarchical level of the extension"), - - /** - * The value field shall contain a character string, to be used to distinguish among different extensions of the - * same type, i.e., with the same value of XTENSION, in a FITS file. This keyword is used to describe an extension - * and should not appear in the primary key. - */ - EXTNAME(HduType.EXTENSION, ValueType.STRING, "name of the extension"), - - /** - * The value field shall contain an integer, to be used to distinguish among different extensions in a FITS file - * with the same type and name, i.e., the same values for XTENSION and EXTNAME. The values need not start with 1 for - * the first extension with a particular value of EXTNAME and need not be in sequence for subsequent values. If the - * EXTVER keyword is absent, the file should be treated as if the value were 1. This keyword is used to describe an - * extension and should not appear in the primary key.RANGE: [1:] DEFAULT: 1 - */ - EXTVER(HduType.EXTENSION, ValueType.INTEGER, "version of the extension"), - - /** - * The value field shall contain an integer that shall be used in any way appropriate to define the data structure, - * consistent with Eq. 5.2 in the FITS Standard. This keyword originated for use in FITS Random Groups where it - * specifies the number of random groups present. In most other cases this keyword will have the value 1. - */ - GCOUNT(HduType.EXTENSION, ValueType.INTEGER, "group count"), - - /** - * The value field shall contain the logical constant T. The value T associated with this keyword implies that - * random groups records are present. - */ - GROUPS(HduType.GROUPS, ValueType.LOGICAL, "indicates random groups structure"), - - /** - * This keyword shall have no associated value; columns 9-80 may contain any ASCII text. The text should contain a - * history of steps and procedures associated with the processing of the associated data. Any number of HISTORY card - * images may appear in a key. - */ - HISTORY(HduType.ANY, ValueType.NONE, "processing history of the data"), - - /** - * The value field shall contain a character string identifying the instrument used to acquire the data associated - * with the key. - */ - INSTRUME(HduType.ANY, ValueType.STRING, "name of instrument"), - - /** - * The value field shall contain a non-negative integer no greater than 999, representing the number of axes in the - * associated data array. A value of zero signifies that no data follow the key in the HduType. In the context of FITS - * 'TABLE' or 'BINTABLE' extensions, the value of NAXIS is always 2.RANGE: [0:999] - */ - NAXIS(HduType.ANY, ValueType.INTEGER, "number of axes"), - - /** - * The value field of this indexed keyword shall contain a non-negative integer, representing the number of elements - * along axis n of a data array. The NAXISn must be present for all values n = 1,...,NAXIS, and for no other values - * of n. A value of zero for any of the NAXISn signifies that no data follow the key in the HduType. If NAXIS is equal - * to 0, there should not be any NAXISn keywords.RANGE: [0:] - */ - NAXISn(HduType.ANY, ValueType.INTEGER, "size of the n'th axis"), - - /** - * The value field shall contain a character string giving a name for the object observed. - */ - OBJECT(HduType.ANY, ValueType.STRING, "name of observed object"), - - /** - * The value field shall contain a character string identifying who acquired the data associated with the key. - */ - OBSERVER(HduType.ANY, ValueType.STRING, "observer who acquired the data"), - - /** - * The value field shall contain a character string identifying the organization or institution responsible for - * creating the FITS file. - */ - ORIGIN(HduType.ANY, ValueType.STRING, "organization responsible for the data"), - - /** - * The value field shall contain an integer that shall be used in any way appropriate to define the data structure, - * consistent with Eq. 5.2 in the FITS Standard. This keyword was originated for use with FITS Random Groups and - * represented the number of parameters preceding each group. It has since been used in 'BINTABLE' extensions to - * represent the size of the data heap following the main data table. In most other cases its value will be zero. - */ - PCOUNT(HduType.EXTENSION, ValueType.INTEGER, "parameter count"), - - /** - * This keyword is reserved for use within the FITS Random Groups structure. This keyword shall be used, along with - * the PZEROn keyword, when the nth FITS group parameter value is not the true physical value, to transform the - * group parameter value to the true physical values it represents, using the equation, physical_value = PZEROn + - * PSCALn * group_parameter_value. The value field shall contain a floating point number representing the - * coefficient of the linear term, the scaling factor between true values and group parameter values at zero offset. - * The default value for this keyword is 1.0. - */ - PSCALn(HduType.GROUPS, ValueType.REAL, "parameter scaling factor"), - - /** - * This keyword is reserved for use within the FITS Random Groups structure. The value field shall contain a - * character string giving the name of parameter n. If the PTYPEn keywords for more than one value of n have the - * same associated name in the value field, then the data value for the parameter of that name is to be obtained by - * adding the derived data values of the corresponding parameters. This rule provides a mechanism by which a random - * parameter may have more precision than the accompanying data array elements; for example, by summing two 16-bit - * values with the first scaled relative to the other such that the sum forms a number of up to 32-bit precision. - */ - PTYPEn(HduType.GROUPS, ValueType.STRING, "name of random groups parameter"), - - /** - * This keyword is reserved for use within the FITS Random Groups structure. This keyword shall be used, along with - * the PSCALn keyword, when the nth FITS group parameter value is not the true physical value, to transform the - * group parameter value to the physical value. The value field shall contain a floating point number, representing - * the true value corresponding to a group parameter value of zero. The default value for this keyword is 0.0. The - * transformation equation is as follows: physical_value = PZEROn + PSCALn * group_parameter_value.DEFAULT: 0.0 - */ - PZEROn(HduType.GROUPS, ValueType.REAL, "parameter scaling zero point"), - - /** - * Coordinate reference frame of major/minor axes.If absent the default value is 'FK5'. - */ - RADESYS(HduType.ANY, ValueType.STRING, "Coordinate reference frame of major/minor axes."), - - /** - * Coordinate reference frame of major/minor axes. use RADESYS instead. - */ - @Deprecated("use RADESYS instead.") - RADECSYS(HduType.ANY, ValueType.STRING, "Coordinate reference frame of major/minor axes."), - - /** - * The value field shall contain a character string citing a reference where the data associated with the key are - * published. - */ - REFERENC(HduType.ANY, ValueType.STRING, "bibliographic reference"), - - /** - * The SIMPLE keyword is required to be the first keyword in the primary key of all FITS files. The value field - * shall contain a logical constant with the value T if the file conforms to the standard. This keyword is mandatory - * for the primary key and is not permitted in extension headers. A value of F signifies that the file does not - * conform to this standard. - */ - SIMPLE(HduType.PRIMARY, ValueType.LOGICAL, "does file conform to the Standard?"), - - /** - * The value field of this indexed keyword shall contain an integer specifying the column in which field n starts in - * an ASCII TABLE extension. The first column of a row is numbered 1.RANGE: [1:] - */ - TBCOLn(HduType.ASCII_TABLE, ValueType.INTEGER, "begining column number"), - - /** - * The value field of this indexed keyword shall contain a character string describing how to interpret the contents - * of field n as a multidimensional array, providing the number of dimensions and the length along each axis. The - * form of the value is not further specified by the Standard. A proposed convention is described in Appendix B.2 of - * the FITS Standard in which the value string has the format '(l,m,n...)' where l, m, n,... are the dimensions of - * the array. - */ - TDIMn(HduType.BINTABLE, ValueType.STRING, "dimensionality of the array "), - - /** - * The value field of this indexed keyword shall contain a character string describing the format recommended for - * the display of the contents of field n. If the table value has been scaled, the physical value shall be - * displayed. All elements in a field shall be displayed with a single, repeated format. For purposes of display, - * each byte of bit (type X) and byte (type B) arrays is treated as an unsigned integer. Arrays of type A may be - * terminated with a zero byte. Only the format codes in Table 8.6, discussed in section 8.3.4 of the FITS Standard, - * are permitted for encoding. The format codes must be specified in upper case. If the Bw.m, Ow.m, and Zw.m formats - * are not readily available to the reader, the Iw.m display format may be used instead, and if the ENw.d and ESw.d - * formats are not available, Ew.d may be used. The meaning of this keyword is not defined for fields of type P in - * the Standard but may be defined in conventions using such fields. - */ - TDISPn(HduType.TABLE, ValueType.STRING, "display format"), - - /** - * The value field shall contain a character string identifying the telescope used to acquire the data associated - * with the key. - */ - TELESCOP(HduType.ANY, ValueType.STRING, "name of telescope"), - - /** - * The value field shall contain a non-negative integer representing the number of fields in each row of a 'TABLE' - * or 'BINTABLE' extension. The maximum permissible value is 999. RANGE: [0:999] - */ - TFIELDS(HduType.TABLE, ValueType.INTEGER, "number of columns in the table"), - - /** - * The value field of this indexed keyword shall contain a character string describing the format in which field n - * is encoded in a 'TABLE' or 'BINTABLE' extension. - */ - TFORMn(HduType.TABLE, ValueType.STRING, "column data format"), - - /** - * The value field of this keyword shall contain an integer providing the separation, in bytes, between the start of - * the main data table and the start of a supplemental data area called the heap. The default value shall be the - * product of the values of NAXIS1 and NAXIS2. This keyword shall not be used if the value of PCOUNT is zero. A - * proposed application of this keyword is presented in Appendix B.1 of the FITS Standard. - */ - THEAP(HduType.BINTABLE, ValueType.INTEGER, "offset to starting data heap address"), - - /** - * In ASCII 'TABLE' extensions, the value field for this indexed keyword shall contain the character string that - * represents an undefined value for field n. The string is implicitly blank filled to the width of the field. In - * binary 'BINTABLE' table extensions, the value field for this indexed keyword shall contain the integer that - * represents an undefined value for field n of data type B, I, or J. The keyword may not be used in 'BINTABLE' - * extensions if field n is of any other data type. - */ - TNULLn(HduType.TABLE, ValueType.STRING, "value used to indicate undefined table element"), - - /** - * This indexed keyword shall be used, along with the TZEROn keyword, when the quantity in field n does not - * represent a true physical quantity. The value field shall contain a floating point number representing the - * coefficient of the linear term in the equation, physical_value = TZEROn + TSCALn * field_value, which must be - * used to compute the true physical value of the field, or, in the case of the complex data types C and M, of the - * real part of the field with the imaginary part of the scaling factor set to zero. The default value for this - * keyword is 1.0. This keyword may not be used if the format of field n is A, L, or X.DEFAULT: 1.0 - */ - TSCALn(HduType.TABLE, ValueType.REAL, "linear data scaling factor"), - - /** - * The value field for this indexed keyword shall contain a character string, giving the name of field n. It is - * recommended that only letters, digits, and underscore (hexadecimal code 5F, ('_') be used in the name. String - * comparisons with the values of TTYPEn keywords should not be case sensitive. The use of identical names for - * different fields should be avoided. - */ - TTYPEn(HduType.TABLE, ValueType.STRING, "column name"), - - /** - * The value field shall contain a character string describing the physical units in which the quantity in field n, - * after any application of TSCALn and TZEROn, is expressed. The units of all FITS key keyword values, with the - * exception of measurements of angles, should conform with the recommendations in the IAU Style Manual. For angular - * measurements given as floating point values and specified with reserved keywords, degrees are the recommended - * units (with the units, if specified, given as 'deg'). - */ - TUNITn(HduType.TABLE, ValueType.STRING, "column units"), - - /** - * This indexed keyword shall be used, along with the TSCALn keyword, when the quantity in field n does not - * represent a true physical quantity. The value field shall contain a floating point number representing the true - * physical value corresponding to a value of zero in field n of the FITS file, or, in the case of the complex data - * types C and M, in the real part of the field, with the imaginary part set to zero. The default value for this - * keyword is 0.0. This keyword may not be used if the format of field n is A, L, or X.DEFAULT: 0.0 - */ - TZEROn(HduType.TABLE, ValueType.REAL, "column scaling zero point"), - - /** - * The value field shall contain a character string giving the name of the extension type. This keyword is mandatory - * for an extension key and must not appear in the primary key. For an extension that is not a standard extension, - * the type name must not be the same as that of a standard extension. - */ - XTENSION(HduType.EXTENSION, ValueType.STRING, "marks beginning of new HDU"), - - // FITS keywords that have been widely used within the astronomical community. - // These are the Keywords that describe the observation. - - /** - * The value field shall contain a floating point number giving the air mass during the observation by a ground - * based telescope. The value of the airmass is often approximated by the secant of the elevation angle and has a - * value of 1.0 at the zenith and increases towards the horizon. This value is assumed to correspond to the start of - * the observation unless another interpretation is clearly explained in the comment field. - */ - AIRMASS(HduType.ANY, ValueType.REAL, "air mass"), - - /** - * The value field gives the declination of the observation. It may be expressed either as a floating point number - * in units of decimal degrees, or as a character string in 'dd:mm:ss.sss' format where the decimal point and number - * of fractional digits are optional. The coordinate reference frame is given by the RADECSYS keyword, and the - * coordinate epoch is given by the EQUINOX keyword. Example: -47.25944 or '-47:15:34.00'. - */ - DEC(HduType.ANY, ValueType.STRING, "declination of the observed object"), - - /** - * The value field shall contain a floating point number giving the nominal declination of the pointing direction in - * units of decimal degrees. The coordinate reference frame is given by the RADECSYS keyword, and the coordinate - * epoch is given by the EQUINOX keyword. The precise definition of this keyword is instrument-specific, but - * typically the nominal direction corresponds to the direction to which the instrument was requested to point. The - * DEC_PNT keyword should be used to give the actual pointed direction. - */ - DEC_NOM(HduType.ANY, ValueType.REAL, "nominal declination of the observation"), - - /** - * The value field shall contain a floating point number giving the declination of the observed object in units of - * decimal degrees. The coordinate reference frame is given by the RADECSYS keyword, and the coordinate epoch is - * given by the EQUINOX keyword. - */ - DEC_OBJ(HduType.ANY, ValueType.REAL, "declination of the observed object"), - - /** - * The value field shall contain a floating point number giving the declination of the pointing direction in units - * of decimal degrees. The coordinate reference frame is given by the RADECSYS keyword, and the coordinate epoch is - * given by the EQUINOX keyword. The precise definition of this keyword is instrument-specific, but typically the - * pointed direction corresponds to the optical axis of the instrument. This keyword gives a mean value in cases - * where the pointing axis was not fixed during the entire observation. - */ - DEC_PNT(HduType.ANY, ValueType.REAL, "declination of the pointed direction of the instrument"), - - /** - * The value field shall contain a floating point number giving the declination of the space craft (or telescope - * platform) X axis during the observation in decimal degrees. The coordinate reference frame is given by the - * RADECSYS keyword, and the coordinate epoch is given by the EQUINOX keyword. This keyword gives a mean value in - * cases where the axis was not fixed during the entire observation. - */ - DEC_SCX(HduType.ANY, ValueType.REAL, "declination of the X spacecraft axis"), - - /** - * The value field shall contain a floating point number giving the declination of the space craft (or telescope - * platform) Z axis during the observation in decimal degrees. The coordinate reference frame is given by the - * RADECSYS keyword, and the coordinate epoch is given by the EQUINOX keyword. This keyword gives a mean value in - * cases where the axis was not fixed during the entire observation. - */ - DEC_SCZ(HduType.ANY, ValueType.REAL, "declination of the Z spacecraft axis"), - - /** - * The value field shall contain a floating point number giving the geographic latitude from which the observation - * was made in units of degrees. - */ - LATITUDE(HduType.ANY, ValueType.REAL, "geographic latitude of the observation"), - - /** - * The value field shall contain a floating point number giving the angle between the direction of the observation - * (e.g., the optical axis of the telescope or the position of the target) and the moon, measured in degrees. - */ - MOONANGL(HduType.ANY, ValueType.REAL, "angle between the observation and the moon"), - - /** - * The value field shall contain a character string giving a name for the observed object that conforms to the IAU - * astronomical object naming conventions. The value of this keyword is more strictly constrained than for the - * standard OBJECT keyword which in practice has often been used to record other ancillary information about the - * observation (e.g. filter, exposure time, weather conditions, etc.). - */ - OBJNAME(HduType.ANY, ValueType.STRING, "AU name of observed object"), - - /** - * The value field shall contain a character string which uniquely identifies the dataset contained in the FITS - * file. This is typically a sequence number that can contain a mixture of numerical and character values. Example: - * '10315-01-01-30A' - */ - OBS_ID(HduType.ANY, ValueType.STRING, "unique observation ID"), - - /** - * The value field shall contain a floating point number giving the position angle of the y axis of the detector - * projected on the sky, in degrees east of north. This keyword is synonymous with the CROTA2 WCS keyword. - */ - ORIENTAT(HduType.IMAGE, ValueType.REAL, "position angle of image y axis (deg. E of N)"), - - /** - * The value field shall contain a floating point number giving the position angle of the relevant aspect of - * telescope pointing axis and/or instrument on the sky in units of degrees east of north. It commonly applies to - * the orientation of a slit mask. - */ - PA_PNT(HduType.ANY, ValueType.REAL, "position angle of the pointing"), - - /** - * The value field gives the Right Ascension of the observation. It may be expressed either as a floating point - * number in units of decimal degrees, or as a character string in 'HH:MM:SS.sss' format where the decimal point and - * number of fractional digits are optional. The coordinate reference frame is given by the RADECSYS keyword, and - * the coordinate epoch is given by the EQUINOX keyword. Example: 180.6904 or '12:02:45.7'. - */ - RA(HduType.ANY, ValueType.STRING, "R.A. of the observation"), - - /** - * The value field shall contain a floating point number giving the nominal Right Ascension of the pointing - * direction in units of decimal degrees. The coordinate reference frame is given by the RADECSYS keyword, and the - * coordinate epoch is given by the EQUINOX keyword. The precise definition of this keyword is instrument-specific, - * but typically the nominal direction corresponds to the direction to which the instrument was requested to point. - * The RA_PNT keyword should be used to give the actual pointed direction. - */ - RA_NOM(HduType.ANY, ValueType.REAL, "nominal R.A. of the observation"), - - /** - * The value field shall contain a floating point number giving the Right Ascension of the observed object in units - * of decimal degrees. The coordinate reference frame is given by the RADECSYS keyword, and the coordinate epoch is - * given by the EQUINOX keyword. - */ - RA_OBJ(HduType.ANY, ValueType.REAL, "R.A. of the observed object"), - - /** - * The value field shall contain a floating point number giving the Right Ascension of the pointing direction in - * units of decimal degrees. The coordinate reference frame is given by the RADECSYS keyword, and the coordinate - * epoch is given by the EQUINOX keyword. The precise definition of this keyword is instrument-specific, but - * typically the pointed direction corresponds to the optical axis of the instrument. This keyword gives a mean - * value in cases where the pointing axis was not fixed during the entire observation. - */ - RA_PNT(HduType.ANY, ValueType.REAL, "R.A. of the pointed direction of the instrument"), - - /** - * The value field shall contain a floating point number giving the Right Ascension of the space craft (or telescope - * platform) X axis during the observation in decimal degrees. The coordinate reference frame is given by the - * RADECSYS keyword, and the coordinate epoch is given by the EQUINOX keyword. This keyword gives a mean value in - * cases where the axis was not fixed during the entire observation. - */ - RA_SCX(HduType.ANY, ValueType.REAL, "R.A. of the X spacecraft axis"), - - /** - * The value field shall contain a floating point number giving the Right Ascension of the space craft (or telescope - * platform) Y axis during the observation in decimal degrees. The coordinate reference frame is given by the - * RADECSYS keyword, and the coordinate epoch is given by the EQUINOX keyword. This keyword gives a mean value in - * cases where the axis was not fixed during the entire observation. - */ - RA_SCY(HduType.ANY, ValueType.REAL, "R.A. of the Y spacecraft axis"), - - /** - * The value field shall contain a floating point number giving the Right Ascension of the space craft (or telescope - * platform) Z axis during the observation in decimal degrees. The coordinate reference frame is given by the - * RADECSYS keyword, and the coordinate epoch is given by the EQUINOX keyword. This keyword gives a mean value in - * cases where the axis was not fixed during the entire observation. - */ - RA_SCZ(HduType.ANY, ValueType.REAL, "R.A. of the Z spacecraft axis"), - - /** - * The value field shall contain a floating point number giving the angle between the direction of the observation - * (e.g., the optical axis of the telescope or the position of the target) and the sun, measured in degrees. - */ - SUNANGLE(HduType.ANY, ValueType.REAL, "angle between the observation and the sun"), - - // FITS keywords that have been widely used within the astronomical community. - // These are the Keywords that describe the instrument that took the data. - - /** - * The value field shall contain a character string which gives the name of the instrumental aperture though which - * the observation was made. This keyword is typically used in instruments which have a selection of apertures which - * restrict the field of view of the detector. - */ - APERTURE(HduType.ANY, ValueType.STRING, "name of field of view aperture"), - - /** - * The value field shall contain a character string which identifies the configuration or mode of the pre-processing - * software that operated on the raw instrumental data to generate the data that is recorded in the FITS file. - * Example: some X-ray satellite data may be recorded in 'BRIGHT', 'FAINT', or 'FAST' data mode. - */ - DATAMODE(HduType.ANY, ValueType.STRING, "pre-processor data mode"), - - /** - * The value field shall contain a character string giving the name of the detector within the instrument that was - * used to make the observation. Example: 'CCD1' - */ - DETNAM(HduType.ANY, ValueType.STRING, "name of the detector used to make the observation"), - - /** - * The value field shall contain a character string which gives the name of the filter that was used during the - * observation to select or modify the radiation that was transmitted to the detector. More than 1 filter may be - * listed by using the FILTERn indexed keyword. The value 'none' or 'NONE' indicates that no filter was used. - */ - FILTER(HduType.ANY, ValueType.STRING, "name of filter used during the observation"), - - /** - * The value field of this indexed keyword shall contain a character string which gives the name of one of multiple - * filters that were used during the observation to select or modify the radiation that was transmitted to the - * detector. The value 'none' or 'NONE' indicates that no filter was used. - */ - FILTERn(HduType.ANY, ValueType.STRING, "name of filters used during the observation"), - - /** - * The value field shall contain a character string which gives the name of the defraction grating that was used - * during the observation. More than 1 grating may be listed by using the GRATINGn indexed keyword. The value 'none' - * or 'NONE' indicates that no grating was used. - */ - GRATING(HduType.ANY, ValueType.STRING, "name of the grating used during the observation."), - - /** - * The value field of this indexed keyword shall contain a character string which gives the name of one of multiple - * defraction gratings that were used during the observation. The value 'none' or 'NONE' indicates that no grating - * was used. - */ - GRATINGn(HduType.ANY, ValueType.STRING, "name of gratings used during the observation."), - - /** - * The value field shall contain a character string which gives the observing mode of the observation. This is used - * in cases where the instrument or detector can be configured to operate in different modes which significantly - * affect the resulting data. Examples: 'SLEW', 'RASTER', or 'POINTING' - */ - OBS_MODE(HduType.ANY, ValueType.STRING, "instrumental mode of the observation"), - - /** - * The value field shall contain an integer giving the data value at which the detector becomes saturated. This - * keyword value may differ from the maximum value implied by the BITPIX in that more bits may be allocated in the - * FITS pixel values than the detector can accommodate. - */ - SATURATE(HduType.ANY, ValueType.INTEGER, "Data value at which saturation occurs"), - - // FITS keywords that have been widely used within the astronomical community. - // These are the Keywords that describe the observation. - - /** - * The value field shall contain a character string that gives the date on which the observation ended. This keyword - * has the same format, and is used in conjunction with, the standard DATA-OBS keyword that gives the starting date - * of the observation. These 2 keywords may give either the calendar date using the 'yyyy-mm-dd' format, or may give - * the full date and time using the 'yyyy-mm-ddThh:mm:ss.sss' format. - */ - DATE_END("DATE-END", HduType.ANY, ValueType.STRING, "date of the end of observation"), - - /** - * The value field shall contain a floating point number giving the difference between the stop and start times of - * the observation in units of seconds. This keyword is synonymous with the TELAPSE keyword. - */ - ELAPTIME(HduType.ANY, ValueType.REAL, "elapsed time of the observation"), - - /** - * The value field shall contain a floating point number giving the exposure time of the observation in units of - * seconds. The exact definition of 'exposure time' is mission dependent and may, for example, include corrections - * for shutter open and close duration, detector dead time, vignetting, or other effects. This keyword is synonymous - * with the EXPTIME keyword. - */ - EXPOSURE(HduType.ANY, ValueType.REAL, "exposure time"), - - /** - * The value field shall contain a floating point number giving the exposure time of the observation in units of - * seconds. The exact definition of 'exposure time' is mission dependent and may, for example, include corrections - * for shutter open and close duration, detector dead time, vignetting, or other effects. This keyword is synonymous - * with the EXPOSURE keyword. - */ - EXPTIME(HduType.ANY, ValueType.REAL, "exposure time"), - - /** - * The value field shall contain a floating point number giving the total integrated exposure time in units of - * seconds corrected for detector 'dead time' effects which reduce the net efficiency of the detector. The ratio of - * LIVETIME/ONTIME gives the mean dead time correction during the observation, which lies in the range 0.0 to 1.0. - */ - LIVETIME(HduType.ANY, ValueType.REAL, "exposure time after deadtime correction"), - - /** - * The value field shall contain a floating point number giving the total integrated exposure time of the - * observation in units of seconds. ONTIME may be less than TELAPSE if there were intevals during the observation in - * which the target was not observed (e.g., the shutter was closed, or the detector power was turned off). - */ - ONTIME(HduType.ANY, ValueType.REAL, "integration time during the observation"), - - /** - * The value field shall contain a floating point number giving the difference between the stop and start times of - * the observation in units of seconds. This keyword is synonymous with the ELAPTIME keyword. - */ - TELAPSE(HduType.ANY, ValueType.REAL, "elapsed time of the observation"), - - /** - * The value field shall contain a character string that gives the time at which the observation ended. This keyword - * is used in conjunction with the DATE-END keyword to give the ending time of the observation; the DATE-END keyword - * gives the ending calendar date, with format 'yyyy-mm-dd', and TIME-END gives the time within that day using the - * format 'hh:mm:ss.sss...'. This keyword should not be used if the time is included directly as part of the - * DATE-END keyword value with the format 'yyyy-mm-ddThh:mm:ss.sss'. - */ - TIME_END("TIME-END", HduType.ANY, ValueType.STRING, "time at the end of the observation"), - - /** - * The value field shall contain a character string that gives the time at which the observation started. This - * keyword is used in conjunction with the standard DATE-OBS keyword to give the starting time of the observation; - * the DATE-OBS keyword gives the starting calendar date, with format 'yyyy-mm-dd', and TIME-OBS gives the time - * within that day using the format 'hh:mm:ss.sss...'. This keyword should not be used if the time is included - * directly as part of the DATE-OBS keyword value with the format 'yyyy-mm-ddThh:mm:ss.sss'. - */ - TIME_OBS("TIME-OBS", HduType.ANY, ValueType.STRING, "time at the start of the observation"), - - // Maxim DL.Extension keywords that may be added or read by MaxIm DL. - // https://github.com/nom-tam-fits/nom-tam-fits/blob/master/src/main/java/nom/tam/fits/header/extra/MaxImDLExt.java - - /** - * if present the image has a valid Bayer color pattern. - */ - BAYERPAT(HduType.IMAGE, ValueType.REAL, "image Bayer color pattern"), - - /** - * Boltwood Cloud Sensor ambient temperature in degrees C. - */ - BOLTAMBT(HduType.IMAGE, ValueType.REAL, "ambient temperature in degrees C"), - - /** - * Boltwood Cloud Sensor cloud condition. - */ - BOLTCLOU(HduType.IMAGE, ValueType.REAL, "Boltwood Cloud Sensor cloud condition."), - - /** - * Boltwood Cloud Sensor daylight level. - */ - BOLTDAY(HduType.IMAGE, ValueType.REAL, "Boltwood Cloud Sensor daylight level."), - - /** - * Boltwood Cloud Sensor dewpoint in degrees C. - */ - BOLTDEW(HduType.IMAGE, ValueType.REAL, "Boltwood Cloud Sensor dewpoint in degrees C."), - - /** - * Boltwood Cloud Sensor humidity in percent. - */ - BOLTHUM(HduType.IMAGE, ValueType.REAL, "Boltwood Cloud Sensor humidity in percent."), - - /** - * Boltwood Cloud Sensor rain condition. - */ - BOLTRAIN(HduType.IMAGE, ValueType.REAL, "Boltwood Cloud Sensor rain condition."), - - /** - * Boltwood Cloud Sensor sky minus ambient temperature in degrees C. - */ - BOLTSKYT(HduType.IMAGE, ValueType.REAL, "Boltwood Cloud Sensor sky minus ambient temperature in degrees C."), - - /** - * Boltwood Cloud Sensor wind speed in km/h. - */ - BOLTWIND(HduType.IMAGE, ValueType.REAL, "Boltwood Cloud Sensor wind speed in km/h."), - - /** - * indicates calibration state of the image; B indicates bias corrected, D indicates dark corrected, F indicates - * flat corrected. - */ - CALSTAT(HduType.IMAGE, ValueType.REAL, "calibration state of the image"), - - /** - * type of color sensor Bayer array or zero for monochrome. - */ - COLORTYP(HduType.IMAGE, ValueType.REAL, "type of color sensor"), - - /** - * initial display screen stretch mode. - */ - CSTRETCH(HduType.IMAGE, ValueType.REAL, "initial display screen stretch mode"), - - /** - * Total dark time of the observation. This is the total time during which dark current is collected by the - * detector. If the times in the extension are different the primary HDU gives one of the extension times. - */ - DARKTIME(HduType.IMAGE, ValueType.REAL, "dark current integration time"), - - /** - * Davis Instruments Weather Station ambient temperature in deg C - */ - DAVAMBT(HduType.IMAGE, ValueType.REAL, "ambient temperature"), - - /** - * Davis Instruments Weather Station barometric pressure in hPa - */ - DAVBAROM(HduType.IMAGE, ValueType.REAL, "barometric pressure"), - - /** - * Davis Instruments Weather Station dewpoint in deg C - */ - DAVDEW(HduType.IMAGE, ValueType.REAL, "dewpoint in deg C"), - - /** - * Davis Instruments Weather Station humidity in percent - */ - DAVHUM(HduType.IMAGE, ValueType.REAL, "humidity in percent"), - - /** - * Davis Instruments Weather Station solar radiation in W/m^2 - */ - DAVRAD(HduType.IMAGE, ValueType.REAL, "solar radiation"), - - /** - * Davis Instruments Weather Station accumulated rainfall in mm/day - */ - DAVRAIN(HduType.IMAGE, ValueType.REAL, "accumulated rainfall"), - - /** - * Davis Instruments Weather Station wind speed in km/h - */ - DAVWIND(HduType.IMAGE, ValueType.REAL, "wind speed"), - - /** - * Davis Instruments Weather Station wind direction in deg - */ - DAVWINDD(HduType.IMAGE, ValueType.REAL, "wind direction"), - - /** - * status of pier flip for German Equatorial mounts. - */ - FLIPSTAT(HduType.IMAGE, ValueType.REAL, "status of pier flip"), - - /** - * Focuser position in steps, if focuser is connected. - */ - FOCUSPOS(HduType.IMAGE, ValueType.REAL, "Focuser position in steps"), - - /** - * Focuser step size in microns, if available. - */ - FOCUSSZ(HduType.IMAGE, ValueType.REAL, "Focuser step size in microns"), - - /** - * Focuser temperature readout in degrees C, if available. - */ - FOCUSTEM(HduType.IMAGE, ValueType.REAL, "Focuser temperature readout"), - - /** - * format of file from which image was read. - */ - INPUTFMT(HduType.IMAGE, ValueType.REAL, "format of file"), - - /** - * ISO camera setting, if camera uses ISO speeds. - */ - ISOSPEED(HduType.IMAGE, ValueType.REAL, "ISO camera setting"), - - /** - * records the geocentric Julian Day of the start of exposure. - */ - JD(HduType.IMAGE, ValueType.REAL, "geocentric Julian Day"), - - /** - * records the geocentric Julian Day of the start of exposure. - */ - JD_GEO(HduType.IMAGE, ValueType.REAL, "geocentric Julian Da"), - - /** - * records the Heliocentric Julian Date at the exposure midpoint. - */ - JD_HELIO(HduType.IMAGE, ValueType.REAL, "Heliocentric Julian Date"), - - /** - * records the Heliocentric Julian Date at the exposure midpoint. - */ - JD_HELIO2("JD-HELIO", HduType.IMAGE, ValueType.REAL, "Heliocentric Julian Date"), - - /** - * UT of midpoint of exposure. - */ - MIDPOINT(HduType.IMAGE, ValueType.REAL, "midpoint of exposure"), - - /** - * user-entered information; free-form notes. - */ - NOTES(HduType.IMAGE, ValueType.REAL, "free-form note"), - - /** - * nominal altitude of center of image - */ - OBJCTALT(HduType.IMAGE, ValueType.REAL, "altitude of center of image"), - - /** - * nominal azimuth of center of image - */ - OBJCTAZ(HduType.IMAGE, ValueType.REAL, "nominal azimuth of center of image"), - - /** - * nominal hour angle of center of image - */ - OBJCTHA(HduType.IMAGE, ValueType.REAL, "nominal hour angle of center of image"), - - /** - * indicates side-of-pier status when connected to a German Equatorial mount. - */ - PIERSIDE(HduType.IMAGE, ValueType.REAL, "side-of-pier status"), - - /** - * records the selected Readout Mode (if any) for the camera. - */ - READOUTM(HduType.IMAGE, ValueType.REAL, "Readout Mode for the camera"), - - /** - * Rotator angle in degrees, if focal plane rotator is connected. - */ - ROTATANG(HduType.IMAGE, ValueType.REAL, "Rotator angle in degrees"), - - /** - * indicates tile position within a mosaic. - */ - TILEXY(HduType.IMAGE, ValueType.REAL, "tile position within a mosaic"), - - /** - * X offset of Bayer array on imaging sensor. - */ - XBAYROFF(HduType.IMAGE, ValueType.REAL, "X offset of Bayer array"), - - /** - * Y offset of Bayer array on imaging sensor. - */ - YBAYROFF(HduType.IMAGE, ValueType.REAL, "Y offset of Bayer array"), - - // NOAO. https://github.com/nom-tam-fits/nom-tam-fits/blob/master/src/main/java/nom/tam/fits/header/extra/NOAOExt.java - - ACTFREQ(HduType.PRIMARY, ValueType.NONE, ""), - ACTHWV(HduType.PRIMARY, ValueType.STRING, ""), - - /** - * Times for the active optics sensor measurements given as modified Julian dates. - */ - ACTMJD(HduType.PRIMARY, ValueType.REAL, ""), - - /** - * Times for the active optics sensor measurements given as modified Julian dates. - */ - ACTMJDn(HduType.PRIMARY, ValueType.REAL, ""), - - /** - * Active optics system position angle measurements in appropriate units. - */ - ACTPAN(HduType.PRIMARY, ValueType.REAL, ""), - - /** - * Active optics system position angle measurements in appropriate units. - */ - ACTPANn(HduType.PRIMARY, ValueType.REAL, ""), - - /** - * Active optics system linear position sensor measurements in appropriate units. - */ - ACTPOS(HduType.PRIMARY, ValueType.REAL, ""), - - /** - * Active optics system linear position sensor measurements in appropriate units. - */ - ACTPOSn(HduType.PRIMARY, ValueType.REAL, ""), - - /** - * Active optics system pressure sensor measurements in appropriate units. - */ - ACTPRE(HduType.PRIMARY, ValueType.REAL, ""), - - /** - * Active optics system pressure sensor measurements in appropriate units. - */ - ACTPREn(HduType.PRIMARY, ValueType.REAL, ""), - - ACTSTAT(HduType.PRIMARY, ValueType.NONE, ""), - - ACTSWV(HduType.PRIMARY, ValueType.NONE, ""), - - /** - * Active optics system temperature sensor measurements in degrees Celsius. - */ - ACTTEM(HduType.PRIMARY, ValueType.REAL, ""), - - /** - * Active optics system temperature sensor measurements in degrees Celsius. - */ - ACTTEMn(HduType.PRIMARY, ValueType.REAL, ""), - - /** - * Active optics voltage sensor measurements in volts. - */ - ACTVOL(HduType.PRIMARY, ValueType.REAL, ""), - - /** - * Active optics voltage sensor measurements in volts. - */ - ACTVOLn(HduType.PRIMARY, ValueType.REAL, ""), - - /** - * Times for the adapter sensor measurements given as modified Julian dates. - */ - ADAMJD(HduType.PRIMARY, ValueType.REAL, ""), - - /** - * Times for the adapter sensor measurements given as modified Julian dates. - */ - ADAMJDn(HduType.PRIMARY, ValueType.REAL, ""), - - /** - * Adapter position angle measurements in appropriate units. - */ - ADAPAN(HduType.PRIMARY, ValueType.REAL, ""), - - /** - * Adapter position angle measurements in appropriate units. - */ - ADAPANn(HduType.PRIMARY, ValueType.REAL, ""), - - /** - * Adapter linear position sensor measurements in appropriate units. - */ - ADAPOS(HduType.PRIMARY, ValueType.REAL, ""), - - /** - * Adapter linear position sensor measurements in appropriate units. - */ - ADAPOSn(HduType.PRIMARY, ValueType.REAL, ""), - - /** - * Adapter pressure sensor measurements in appropriate units. - */ - ADAPRE(HduType.PRIMARY, ValueType.REAL, ""), - - /** - * Adapter pressure sensor measurements in appropriate units. - */ - ADAPREn(HduType.PRIMARY, ValueType.REAL, ""), - - ADAPSWV(HduType.PRIMARY, ValueType.NONE, ""), - - ADAPTER(HduType.PRIMARY, ValueType.NONE, ""), - - ADASTAT(HduType.PRIMARY, ValueType.NONE, ""), - - /** - * Adapter temperature sensor measurements in degrees Celsius. - */ - ADATEM(HduType.PRIMARY, ValueType.REAL, ""), - - /** - * Adapter temperature sensor measurements in degrees Celsius. - */ - ADATEMn(HduType.PRIMARY, ValueType.REAL, ""), - - /** - * Adapter voltage sensor measurements in volts. - */ - ADAVOL(HduType.PRIMARY, ValueType.REAL, ""), - - /** - * Adapter voltage sensor measurements in volts. - */ - ADAVOLn(HduType.PRIMARY, ValueType.REAL, ""), - - /** - * Atmospheric dispersion compensator hardware identification. - */ - ADC(HduType.PRIMARY, ValueType.STRING, "ADC Identification"), - - /** - * Times for the ADC sensor measurements given as modified Julian dates. - */ - ADCMJD(HduType.PRIMARY, ValueType.REAL, ""), - - /** - * Times for the ADC sensor measurements given as modified Julian dates. - */ - ADCMJDn(HduType.PRIMARY, ValueType.REAL, ""), - - /** - * ADC position angle measurements in appropriate units. - */ - ADCPAN(HduType.PRIMARY, ValueType.REAL, ""), - - /** - * ADC position angle measurements in appropriate units. - */ - ADCPANn(HduType.PRIMARY, ValueType.REAL, ""), - - /** - * ADC linear position sensor measurements in appropriate units. - */ - ADCPOS(HduType.PRIMARY, ValueType.REAL, ""), - - /** - * ADC linear position sensor measurements in appropriate units. - */ - ADCPOSn(HduType.PRIMARY, ValueType.REAL, ""), - - /** - * ADC pressure sensor measurements in appropriate units. - */ - ADCPRE(HduType.PRIMARY, ValueType.REAL, ""), - - /** - * ADC pressure sensor measurements in appropriate units. - */ - ADCPREn(HduType.PRIMARY, ValueType.REAL, ""), - - /** - * ADC status. - */ - ADCSTAT(HduType.PRIMARY, ValueType.STRING, ""), - - /** - * Atmospheric dispersion compensator software identification. - */ - ADCSWV(HduType.PRIMARY, ValueType.STRING, "ADC software version"), - - /** - * ADC temperature sensor measurements in degrees Celsius. - */ - ADCTEM(HduType.PRIMARY, ValueType.REAL, ""), - - /** - * ADC temperature sensor measurements in degrees Celsius. - */ - ADCTEMn(HduType.PRIMARY, ValueType.REAL, ""), - - /** - * ADC voltage sensor measurements in volts. - */ - ADCVOL(HduType.PRIMARY, ValueType.REAL, ""), - - /** - * ADC voltage sensor measurements in volts. - */ - ADCVOLn(HduType.PRIMARY, ValueType.REAL, ""), - - /** - * Declination of the aperture(s). - */ - ADECnnn(HduType.PRIMARY, ValueType.STRING, "Aperture declination"), - - /** - * Declination unit. - */ - ADEUnnn(HduType.PRIMARY, ValueType.STRING, "Declination unit"), - - /** - * Object declination for wavefront sensing. - */ - ADODEC(HduType.PRIMARY, ValueType.STRING, "Adaptive optics object declination"), - - /** - * Declination unit. - */ - ADODECU(HduType.PRIMARY, ValueType.STRING, "Declination unit"), - - /** - * Object coordinate epoch for wavefront sensing. - */ - ADOEPOCH(HduType.PRIMARY, ValueType.NONE, ""), - - /** - * Object coordinate system equinox for wavefront sensing. A value before 1984 is Besselian otherwise it is Julian. - */ - ADOEQUIN(HduType.PRIMARY, ValueType.REAL, ""), - - ADOFREQ(HduType.PRIMARY, ValueType.NONE, ""), - - ADOHWV(HduType.PRIMARY, ValueType.NONE, ""), - - /** - * Times for the adaptive optics sensor measurements given as modified Julian dates. - */ - ADOMJD(HduType.PRIMARY, ValueType.REAL, ""), - - /** - * Times for the adaptive optics sensor measurements given as modified Julian dates. - */ - ADOMJDn(HduType.PRIMARY, ValueType.REAL, ""), - - /** - * Adaptive optics system position angle measurements in appropriate units. - */ - ADOPAN(HduType.PRIMARY, ValueType.REAL, ""), - - /** - * Adaptive optics system position angle measurements in appropriate units. - */ - ADOPANn(HduType.PRIMARY, ValueType.REAL, ""), - - /** - * Adaptive optics system linear position sensor measurements in appropriate units. - */ - ADOPOS(HduType.PRIMARY, ValueType.REAL, ""), - - /** - * Adaptive optics system linear position sensor measurements in appropriate units. - */ - ADOPOSn(HduType.PRIMARY, ValueType.REAL, ""), - - /** - * Adaptive optics system pressure sensor measurements in appropriate units. - */ - ADOPRE(HduType.PRIMARY, ValueType.REAL, ""), - - /** - * Adaptive optics system pressure sensor measurements in appropriate units. - */ - ADOPREn(HduType.PRIMARY, ValueType.REAL, ""), - - /** - * Object right ascension for wavefront sensing. - */ - ADORA(HduType.PRIMARY, ValueType.STRING, "Adaptive optics object right ascension"), - - /** - * Object coordinate system type for wavefront sensing. - */ - ADORADEC(HduType.PRIMARY, ValueType.STRING, ""), - - /** - * Right ascension unit. - */ - ADORAU(HduType.PRIMARY, ValueType.STRING, "Right ascension unit"), - - ADOSTAT(HduType.PRIMARY, ValueType.NONE, ""), - ADOSWV(HduType.PRIMARY, ValueType.NONE, ""), - - /** - * Adaptive optics system temperature sensor measurements in degrees Celsius. - */ - ADOTEM(HduType.PRIMARY, ValueType.REAL, ""), - - /** - * Adaptive optics system temperature sensor measurements in degrees Celsius. - */ - ADOTEMn(HduType.PRIMARY, ValueType.REAL, ""), - - /** - * Type of object used for wavefront sensing. - */ - ADOTYPE(HduType.PRIMARY, ValueType.STRING, "Adaptive optics object type"), - - /** - * Adaptive optics system voltage sensor measurements in volts. - */ - ADOVOL(HduType.PRIMARY, ValueType.REAL, ""), - - /** - * Adaptive optics system voltage sensor measurements in volts. - */ - ADOVOLn(HduType.PRIMARY, ValueType.REAL, ""), - - /** - * Epoch of the coordinates for the aperture(s). - */ - AEPOnnn(HduType.PRIMARY, ValueType.REAL, "Aperture coordinate epoch"), - - /** - * Coordinate system equinox for the aperture(s). A value before 1984 is Besselian otherwise it is Julian. - */ - AEQUnnn(HduType.PRIMARY, ValueType.REAL, "Aperture coordinate equinox"), - - /** - * The computed airmass(es) at the time(s) given by the AMMJDn keywords. - */ - AIRMASSn(HduType.PRIMARY, ValueType.REAL, "Airmass"), - - /** - * Times for the airmass calculation given as modified Julian dates. The MJDHDR keyword may be used for the time at - * which the image header is created or the MJD-OBS keyword may be used for the time of observation. - */ - AMMJD(HduType.PRIMARY, ValueType.REAL, "MJD of airmass"), - - /** - * Times for the airmass calculation given as modified Julian dates. The MJDHDR keyword may be used for the time at - * which the image header is created or the MJD-OBS keyword may be used for the time of observation. - */ - AMMJDn(HduType.PRIMARY, ValueType.REAL, "MJD of airmass"), - - /** - * Amplifier integration or sample time. - */ - AMPINTEG(HduType.PRIMARY_EXTENSION, ValueType.REAL, "Amplifier integration/sample time"), - - /** - * Times for the amplifier sensor measurements given as modified Julian dates. The MJDHDR keyword may be used for - * the time at which the image header is created or the MJD-OBS keyword may be used for the time of observation. - */ - AMPMJD(HduType.PRIMARY_EXTENSION, ValueType.REAL, ""), - - /** - * Times for the amplifier sensor measurements given as modified Julian dates. The MJDHDR keyword may be used for - * the time at which the image header is created or the MJD-OBS keyword may be used for the time of observation. - */ - AMPMJDn(HduType.PRIMARY_EXTENSION, ValueType.REAL, ""), - - /** - * Amplifier name. - */ - AMPNAME(HduType.EXTENSION, ValueType.STRING, "Amplifier name"), - - /** - * CCD amplifier position angle measurements in appropriate units. - */ - AMPPAN(HduType.PRIMARY_EXTENSION, ValueType.REAL, ""), - - /** - * CCD amplifier position angle measurements in appropriate units. - */ - AMPPANn(HduType.PRIMARY_EXTENSION, ValueType.REAL, ""), - - /** - * CCD amplifier linear position sensor measurements in appropriate units. - */ - AMPPOS(HduType.PRIMARY_EXTENSION, ValueType.REAL, ""), - - /** - * CCD amplifier linear position sensor measurements in appropriate units. - */ - AMPPOSn(HduType.PRIMARY_EXTENSION, ValueType.REAL, ""), - - /** - * CCD amplifier pressure sensor measurements in appropriate units. - */ - AMPPRE(HduType.PRIMARY_EXTENSION, ValueType.REAL, ""), - - /** - * CCD amplifier pressure sensor measurements in appropriate units. - */ - AMPPREn(HduType.PRIMARY_EXTENSION, ValueType.REAL, ""), - - /** - * Amplifier unbinned pixel read time. - */ - AMPREAD(HduType.PRIMARY_EXTENSION, ValueType.REAL, "Unbinned pixel read time"), - - /** - * CCD amplifier sampling method used. This may also include any integration times. - */ - AMPSAMPL(HduType.PRIMARY_EXTENSION, ValueType.STRING, "Amplifier sampling method"), - - /** - * Mapping of the CCD section to amplifier coordinates. - */ - AMPSEC(HduType.EXTENSION, ValueType.STRING, "Amplifier section"), - - /** - * The logical unbinned size of the amplifier readout in section notation. This includes drift scanning if - * applicable. - */ - AMPSIZE(HduType.EXTENSION, ValueType.STRING, "Amplifier readout size"), - - /** - * CCD amplifier temperature sensor measurements in degrees Celsius. - */ - AMPTEM(HduType.PRIMARY_EXTENSION, ValueType.REAL, ""), - - /** - * CCD amplifier temperature sensor measurements in degrees Celsius. - */ - AMPTEMn(HduType.PRIMARY_EXTENSION, ValueType.REAL, ""), - - /** - * CCD amplifier voltage sensor measurements in volts. } - */ - AMPVOL(HduType.PRIMARY_EXTENSION, ValueType.REAL, ""), - - /** - * CCD amplifier voltage sensor measurements in volts. } - */ - AMPVOLn(HduType.PRIMARY_EXTENSION, ValueType.REAL, ""), - - /** - * Aperture position angle unit. - */ - APAUnnn(HduType.PRIMARY, ValueType.STRING, "Aperture position angle unit"), - - /** - * Declination of the aperture(s). - */ - APDEC(HduType.PRIMARY, ValueType.STRING, "Aperture declination"), - - /** - * Declination unit. - */ - APDECU(HduType.PRIMARY, ValueType.STRING, "Declination unit"), - - /** - * Aperture diameter of the aperture(s) for circular apertures and fibers. This is also used as an approximation to - * the size of hexagonal lenses. - */ - APDInnn(HduType.PRIMARY, ValueType.REAL, "Aperture diameter"), - - /** - * Epoch of the coordinates for the aperture(s). - */ - APEPOCH(HduType.PRIMARY, ValueType.REAL, "Aperture coordinate epoch"), - - /** - * Coordinate system equinox for the aperture(s). A value before 1984 is Besselian otherwise it is Julian. - */ - APEQUIN(HduType.PRIMARY, ValueType.REAL, "Aperture coordinate equinox"), - - /** - * Aperture diameter of the aperture(s) for circular apertures and fibers. This is also used as an approximation to - * the size of hexagonal lenses. - */ - APERDIA(HduType.PRIMARY, ValueType.REAL, "Aperture diameter"), - - /** - * Aperture length of the aperture(s) for slit apertures. - */ - APERLEN(HduType.PRIMARY, ValueType.REAL, "Slit length"), - - /** - * Aperture identification. This can be a physical aperture identification, the name of a mask, a fiber - * configuration, etc. When there are many apertures the keyword APERTURE may be used to specify a configuration or - * mask identification and the APER%4d keywords can be used to identify some information about the aperture such as - * a fiber number. - */ - APERnnn(HduType.PRIMARY, ValueType.STRING, "Aperture identification"), - - /** - * Aperture position angle of the aperture(s) on the sky. This is measured using the longest dimension from north to - * east for slits. For hexagonal lenslets it gives the position angle for one of the sides. - */ - APERPA(HduType.PRIMARY, ValueType.REAL, "Aperture position angle"), - - /** - * Aperture identification. This can be a physical aperture identification, the name of a mask, a fiber - * configuration, etc. When there are many apertures the keyword APERTURE may be used to specify a configuration or - * mask identification and the APER%4d keywords can be used to identify some information about the aperture such as - * a fiber number. - */ - APERWID(HduType.PRIMARY, ValueType.REAL, "Slit width"), - - /** - * Aperture length of the aperture(s) for slit apertures. - */ - APLEnnn(HduType.PRIMARY, ValueType.REAL, "Slit length"), - - /** - * Aperture position angle of the aperture(s) on the sky. This is measured using the longest dimension from north to - * east for slits. For hexagonal lenslets it gives the position angle for one of the sides. - */ - APPAnnn(HduType.PRIMARY, ValueType.REAL, "Aperture position angle"), - - /** - * Aperture position angle unit. - */ - APPAUNIT(HduType.PRIMARY, ValueType.STRING, "Aperture position angle unit"), - - /** - * Right ascension of the aperture(s). - */ - APRA(HduType.PRIMARY, ValueType.STRING, "Aperture right ascension"), - - /** - * Aperture coordinate system type for the aperture(s). - */ - APRADEC(HduType.PRIMARY, ValueType.STRING, "Aperture coordinate system"), - - /** - * Right ascension unit. - */ - APRAU(HduType.PRIMARY, ValueType.STRING, "Right ascension unit"), - - /** - * Aperture type. This is an from a dictionary. The common types are "slit", "hole", "fiber", "hexlens", - * "hexlens+fiber" and "none". The last type is for aperture-less spectroscopy such as with objective prisms. - * Typically for multiobject spectroscopy all the aperture types will be the same and the keyword will be APTYPE. - */ - APTYnnn(HduType.PRIMARY, ValueType.STRING, "Aperture type"), - - /** - * Aperture type. This is an from a dictionary. The common types are "slit", "hole", "fiber", "hexlens", - * "hexlens+fiber" and "none". The last type is for aperture-less spectroscopy such as with objective prisms. - * Typically for multiobject spectroscopy all the aperture types will be the same and the keyword will be APTYPE. - */ - APTYPE(HduType.PRIMARY, ValueType.STRING, "Aperture type"), - - /** - * Units of aperture dimensions. This applies to slit widths and lengths, fiber diameters, lenslet diameters, etc. - * It may be a physical dimension or a projected angle on the sky. - */ - APUNIT(HduType.PRIMARY, ValueType.STRING, "Aperture dimension unit"), - - /** - * Units of aperture dimensions. This applies to slit widths and lengths, fiber diameters, lenslet diameters, etc. - * It may be a physical dimension or a projected angle on the sky. - */ - APUNnnn(HduType.PRIMARY, ValueType.STRING, "Aperture dimension unit"), - - /** - * Aperture width of the aperture(s) for slit apertures. - */ - APWInnn(HduType.PRIMARY, ValueType.REAL, "Slit width"), - - /** - * Right ascension of the aperture(s). - */ - ARAnnn(HduType.PRIMARY, ValueType.STRING, "Aperture right ascension"), - - /** - * Right ascension unit. - */ - ARAUnnn(HduType.PRIMARY, ValueType.STRING, "Right ascension unit"), - - /** - * Archive hardware version. - */ - ARCHHWV(HduType.PRIMARY, ValueType.STRING, "Archive hardware"), - - /** - * Archive identification. This may be the same as the observation identification. - */ - ARCHID(HduType.PRIMARY, ValueType.STRING, "Archive identification"), - - /** - * The archive name in which the observation is archived. - */ - ARCHIVE(HduType.PRIMARY, ValueType.STRING, "Archive"), - - /** - * Archive status of data. - */ - ARCHSTAT(HduType.PRIMARY, ValueType.STRING, "Archive status"), - - /** - * Archive software version. - */ - ARCHSWV(HduType.PRIMARY, ValueType.STRING, "Archive software version"), - - /** - * Arcon predicted gain. This is the gain measured in the laboratory. The GAIN keyword may also have this value - * initially but it is updated to the most recent estimate of the gain. - */ - ARCONG(HduType.EXTENSION, ValueType.REAL, "Predicted gain"), - - /** - * Arcon gain index ValueType. - */ - ARCONGI(HduType.EXTENSION, ValueType.INTEGER, "Gain selection"), - - /** - * Arcon predicted RMS readout noise. This is the value measured in the laboratory. The RDNOISE keyword may also - * have this value initially but it is updated to the most current estimate. - */ - ARCONRN(HduType.EXTENSION, ValueType.REAL, "Predicted readout noise"), - - /** - * Arcon waveform complilation date. - */ - ARCONWD(HduType.PRIMARY_EXTENSION, ValueType.STRING, "Date CCD waveforms last compiled"), - - /** - * Arcon waveform options enabled. - */ - ARCONWM(HduType.PRIMARY_EXTENSION, ValueType.STRING, "Arcon waveform options enabled"), - - /** - * Aperture coordinate system type for the aperture(s). - */ - ARDSnnn(HduType.PRIMARY, ValueType.STRING, "Aperture coordinate system"), - - /** - * Transformation matrix between CCD and amplifier coordinates. Normally only two values will be non-zero and will - * have values of 1 or -1. If missing the default is an identify matrix. - */ - ATMn_n(HduType.EXTENSION, ValueType.REAL, "Amplifier transformation matrix"), - - /** - * Transformation origin vector between CCD and amplifier coordinates. - */ - ATVn(HduType.EXTENSION, ValueType.REAL, "Amplifier transformation vector"), - - /** - * Section of the recorded image containing overscan or prescan data. This will be in binned pixels if binning is - * done. Multiple regions may be recorded and specified, such as both prescan and overscan, but the first section - * given by this parameter is likely to be the one used during calibration. - */ - BIASnnn(HduType.EXTENSION, ValueType.STRING, "Bias section"), - - /** - * Section of the recorded image containing overscan or prescan data. This will be in binned pixels if binning is - * done. Multiple regions may be recorded and specified, such as both prescan and overscan, but the first section - * given by this parameter is likely to be the one used during calibration. - */ - BIASSEC(HduType.EXTENSION, ValueType.STRING, "Bias section"), - - /** - * Description of bad pixels. The value is an IRAF bad pixel mask name. - */ - BPM(HduType.PRIMARY_EXTENSION, ValueType.STRING, "Bad pixels"), - - /** - * Camera configuration. - */ - CAMCONF(HduType.PRIMARY, ValueType.STRING, "Camera Configuration"), - - /** - * Camera name. - */ - CAMERA(HduType.PRIMARY, ValueType.STRING, "Camera name"), - - /** - * Camera focus. - */ - CAMFOCUS(HduType.PRIMARY, ValueType.REAL, "Camera focus"), - - /** - * Camera hardware version. - */ - CAMHWV(HduType.PRIMARY, ValueType.STRING, "Camera version"), - - /** - * Times for the instrument sensor measurements given as modified Julian dates. - */ - CAMMJD(HduType.PRIMARY, ValueType.REAL, ""), - - /** - * Times for the instrument sensor measurements given as modified Julian dates. - */ - CAMMJDn(HduType.PRIMARY, ValueType.REAL, ""), - - /** - * Camera position angle measurements in appropriate units. - */ - CAMPAN(HduType.PRIMARY, ValueType.REAL, "Camera position angle"), - - /** - * Camera position angle measurements in appropriate units. - */ - CAMPANn(HduType.PRIMARY, ValueType.REAL, "Camera position angle"), - - /** - * Camera linear position sensor measurements in appropriate units. - */ - CAMPOS(HduType.PRIMARY, ValueType.REAL, ""), - - /** - * Camera linear position sensor measurements in appropriate units. - */ - CAMPOSn(HduType.PRIMARY, ValueType.REAL, ""), - - /** - * Camera pressure sensor measurements in appropriate units. - */ - CAMPRE(HduType.PRIMARY, ValueType.REAL, ""), - - /** - * Camera pressure sensor measurements in appropriate units. - */ - CAMPREn(HduType.PRIMARY, ValueType.REAL, ""), - - /** - * Camera status. - */ - CAMSTAT(HduType.PRIMARY, ValueType.STRING, "Camera status"), - - /** - * Camera software version. - */ - CAMSWV(HduType.PRIMARY, ValueType.STRING, "Camera software version"), - - /** - * Camera temperature sensor measurements in degrees Celsius. - */ - CAMTEM(HduType.PRIMARY, ValueType.REAL, ""), - - /** - * Camera temperature sensor measurements in degrees Celsius. - */ - CAMTEMn(HduType.PRIMARY, ValueType.REAL, ""), - - /** - * Camera voltage sensor measurements in volts. - */ - CAMVOL(HduType.PRIMARY, ValueType.REAL, ""), - - /** - * Camera voltage sensor measurements in volts. - */ - CAMVOLn(HduType.PRIMARY, ValueType.REAL, ""), - - /** - * Declination of the CCD center. - */ - CCDDEC(HduType.PRIMARY_EXTENSION, ValueType.STRING, "CCD declination"), - - /** - * Declination unit. - */ - CCDDECU(HduType.PRIMARY_EXTENSION, ValueType.STRING, "Declination unit"), - - /** - * Epoch of the CCD center coordinates. - */ - CCDEPOCH(HduType.PRIMARY_EXTENSION, ValueType.REAL, "CCD coordinate epoch"), - - /** - * CCD coordinate system equinox. A value before 1984 is Besselian otherwise it is Julian. - */ - CCDEQUIN(HduType.PRIMARY_EXTENSION, ValueType.REAL, "CCD coordinate equinox"), - - /** - * CCD hardware version - */ - CCDHWV(HduType.PRIMARY_EXTENSION, ValueType.STRING, "CCD version"), - - /** - * Times for the CCD sensor measurements given as modified Julian dates. The MJDHDR keyword may be used for the time - * at which the image header is created or the MJD-OBS keyword may be used for the time of observation. - */ - CCDMJD(HduType.PRIMARY_EXTENSION, ValueType.REAL, ""), - - /** - * Times for the CCD sensor measurements given as modified Julian dates. The MJDHDR keyword may be used for the time - * at which the image header is created or the MJD-OBS keyword may be used for the time of observation. - */ - CCDMJDn(HduType.PRIMARY_EXTENSION, ValueType.REAL, ""), - - /** - * CCD identification. - */ - CCDNAME(HduType.PRIMARY_EXTENSION, ValueType.STRING, "CCD identification"), - - /** - * Number of amplifiers used to readout the CCD. This keyword may be absent if only one amplifier is used. - */ - CCDNAMPS(HduType.PRIMARY_EXTENSION, ValueType.INTEGER, "Number of amplifiers used"), - - /** - * CCD position angle measurements in appropriate units. - */ - CCDPAN(HduType.PRIMARY_EXTENSION, ValueType.REAL, ""), - - /** - * CCD position angle measurements in appropriate units. - */ - CCDPANn(HduType.PRIMARY_EXTENSION, ValueType.REAL, ""), - - /** - * CCD linear position sensor measurements in appropriate units. - */ - CCDPOS(HduType.PRIMARY_EXTENSION, ValueType.REAL, ""), - - /** - * CCD linear position sensor measurements in appropriate units. - */ - CCDPOSn(HduType.PRIMARY_EXTENSION, ValueType.REAL, ""), - - /** - * CCD pressure sensor measurements in appropriate units. - */ - CCDPRE(HduType.PRIMARY_EXTENSION, ValueType.REAL, ""), - - /** - * CCD pressure sensor measurements in appropriate units. - */ - CCDPREn(HduType.PRIMARY_EXTENSION, ValueType.REAL, ""), - - /** - * The actual format size of the CCD. This is the same as the CCDSIZE keyword except in the case of drift scanning. - */ - CCDPSIZE(HduType.PRIMARY_EXTENSION, ValueType.STRING, "CCD size"), - - /** - * Right ascension of the CCD center. - */ - CCDRA(HduType.PRIMARY_EXTENSION, ValueType.STRING, "CCD right ascension"), - - /** - * CCD coordinate system type. - */ - CCDRADEC(HduType.PRIMARY_EXTENSION, ValueType.STRING, "CCD coordinate system"), - - /** - * Right ascension unit. - */ - CCDRAU(HduType.PRIMARY_EXTENSION, ValueType.STRING, "Right ascension unit"), - - /** - * The unbinned section of the logical CCD pixel raster covered by the amplifier readout in section notation. The - * section must map directly to the specified data section through the binning and CCD to image coordiante - * transformation. The image data section (DATASEC) is specified with the starting pixel less than the ending pixel. - * Thus the order of this section may be flipped depending on the coordinate transformation (which depends on how - * the CCD coordinate system is defined). - */ - CCDSEC(HduType.EXTENSION, ValueType.STRING, "Region of CCD read"), - - /** - * The logical unbinned size of the CCD in section notation. Normally this would be the physical size of the CCD - * unless drift scanning is done. This is the full size even when subraster readouts are done. - */ - CCDSIZE(HduType.PRIMARY_EXTENSION, ValueType.STRING, "CCD size"), - - /** - * CCD on-chip summing given as two or four integer numbers. These define the summing of CCD pixels in the amplifier - * readout order. The first two numbers give the number of pixels summed in the serial and parallel directions - * respectively. If the first pixel read out consists of fewer unbinned pixels along either direction the next two - * numbers give the number of pixels summed for the first serial and parallel pixels. From this it is implicit how - * many pixels are summed for the last pixels given the size of the CCD section (CCDSEC). It is highly recommended - * that controllers read out all pixels with the same summing in which case the size of the CCD section will be the - * summing factors times the size of the data section. - */ - CCDSUM(HduType.EXTENSION, ValueType.STRING, "CCD on-chip summing"), - - /** - * CCD software version - */ - CCDSWV(HduType.PRIMARY_EXTENSION, ValueType.STRING, "CCD software version"), - - /** - * CCD temperature sensor measurements in degrees Celsius. - */ - CCDTEM(HduType.PRIMARY_EXTENSION, ValueType.REAL, "CCD temperature"), - - /** - * CCD temperature sensor measurements in degrees Celsius. - */ - CCDTEMn(HduType.PRIMARY_EXTENSION, ValueType.REAL, "CCD temperature"), - - /** - * CCD voltage sensor measurements in volts. - */ - CCDVOL(HduType.PRIMARY_EXTENSION, ValueType.REAL, ""), - - /** - * CCD voltage sensor measurements in volts. - */ - CCDVOLn(HduType.PRIMARY_EXTENSION, ValueType.REAL, ""), - - /** - * Spectrum coordinate matrix. World coordinate axis 1 is defined to be the dispersion and the other axes are - * spatial. The matrix implies a dispersion axis in the image coordinates. - */ - CD1_1(HduType.EXTENSION, ValueType.REAL, "Coordinate scale matrix"), - - /** - * Spectrum coordinate matrix. World coordinate axis 1 is defined to be the dispersion and the other axes are - * spatial. The matrix implies a dispersion axis in the image coordinates. - */ - CD1_2(HduType.EXTENSION, ValueType.REAL, "Coordinate scale matrix"), - - /** - * Spectrum coordinate matrix. World coordinate axis 1 is defined to be the dispersion and the other axes are - * spatial. The matrix implies a dispersion axis in the image coordinates. - */ - CD11nnn(HduType.EXTENSION, ValueType.REAL, "Coordinate scale matrix"), - - /** - * Spectrum coordinate matrix. World coordinate axis 1 is defined to be the dispersion and the other axes are - * spatial. The matrix implies a dispersion axis in the image coordinates. - */ - CD12nnn(HduType.EXTENSION, ValueType.REAL, "Coordinate scale matrix"), - - /** - * Spectrum coordinate matrix. World coordinate axis 1 is defined to be the dispersion and the other axes are - * spatial. The matrix implies a dispersion axis in the image coordinates. - */ - CD2_1(HduType.EXTENSION, ValueType.REAL, "Coordinate scale matrix"), - - /** - * Spectrum coordinate matrix. World coordinate axis 1 is defined to be the dispersion and the other axes are - * spatial. The matrix implies a dispersion axis in the image coordinates. - */ - CD2_2(HduType.EXTENSION, ValueType.REAL, "Coordinate scale matrix"), - - /** - * Spectrum coordinate matrix. World coordinate axis 1 is defined to be the dispersion and the other axes are - * spatial. The matrix implies a dispersion axis in the image coordinates. - */ - CD21nnn(HduType.EXTENSION, ValueType.REAL, "Coordinate scale matrix"), - - /** - * Spectrum coordinate matrix. World coordinate axis 1 is defined to be the dispersion and the other axes are - * spatial. The matrix implies a dispersion axis in the image coordinates. - */ - CD22nnn(HduType.EXTENSION, ValueType.REAL, "Spec coord matrix"), - - /** - * Coordinate scale matrix for image world coordinates. This describes the scales and rotations of the coordinate - * axes. - */ - CHPANGLE(HduType.PRIMARY, ValueType.NONE, ""), - - CHPDIST(HduType.PRIMARY, ValueType.NONE, ""), - - CHPFREQ(HduType.PRIMARY, ValueType.NONE, ""), - - CHPHWV(HduType.PRIMARY, ValueType.NONE, ""), - - /** - * Times for the chopping system sensor measurements given as modified Julian dates. - */ - CHPMJD(HduType.PRIMARY, ValueType.REAL, ""), - - /** - * Times for the chopping system sensor measurements given as modified Julian dates. - */ - CHPMJDn(HduType.PRIMARY, ValueType.REAL, ""), - - CHPNCHOP(HduType.PRIMARY, ValueType.NONE, ""), - - /** - * Chopping system position angle measurements in appropriate units. Note that CHPANGLE should be used for the - * chopping angle and these keywords are for other system position angle measurements. - */ - CHPPAN(HduType.PRIMARY, ValueType.REAL, ""), - - /** - * Chopping system position angle measurements in appropriate units. Note that CHPANGLE should be used for the - * chopping angle and these keywords are for other system position angle measurements. - */ - CHPPANn(HduType.PRIMARY, ValueType.REAL, ""), - - /** - * Chopping system linear position sensor measurements in appropriate units. - */ - CHPPOS(HduType.PRIMARY, ValueType.REAL, ""), - - /** - * Chopping system linear position sensor measurements in appropriate units. - */ - CHPPOSn(HduType.PRIMARY, ValueType.REAL, ""), - - /** - * Chopping system pressure sensor measurements in appropriate units. - */ - CHPPRE(HduType.PRIMARY, ValueType.REAL, ""), - - /** - * Chopping system pressure sensor measurements in appropriate units. - */ - CHPPREn(HduType.PRIMARY, ValueType.REAL, ""), - - CHPSTAT(HduType.PRIMARY, ValueType.NONE, ""), - - CHPSWV(HduType.PRIMARY, ValueType.NONE, ""), - - /** - * Chopping system temperature sensor measurements in degrees Celsius. - */ - CHPTEM(HduType.PRIMARY, ValueType.REAL, ""), - - /** - * Chopping system temperature sensor measurements in degrees Celsius. - */ - CHPTEMn(HduType.PRIMARY, ValueType.REAL, ""), - - /** - * Chopping system voltage sensor measurements in volts. - */ - CHPVOL(HduType.PRIMARY, ValueType.REAL, ""), - - /** - * Chopping system voltage sensor measurements in volts. - */ - CHPVOLn(HduType.PRIMARY, ValueType.REAL, ""), - - /** - * Dispersion limit for the region occupied by the spectrum. - */ - CMAX1(HduType.EXTENSION, ValueType.REAL, "Spectrum dispersion limit"), - - /** - * Cross-dispersion limit for the region occupied by the spectrum. - */ - CMAX2(HduType.EXTENSION, ValueType.REAL, "Spectrum cross-dispersion limit"), - - /** - * Dispersion limit for the region occupied by the spectrum. - */ - CMIN1(HduType.EXTENSION, ValueType.REAL, "Spectrum dispersion limit"), - - /** - * Cross-dispersion limit for the region occupied by the spectrum. - */ - CMIN2(HduType.EXTENSION, ValueType.REAL, "Spectrum cross-dispersion limit"), - - /** - * Observer comments. - */ - CMMTnnn(HduType.PRIMARY, ValueType.STRING, ""), - - /** - * Dispersion limit for the region occupied by the spectrum. - */ - CMN1nnn(HduType.EXTENSION, ValueType.REAL, "Spectrum dispersion limit"), - - /** - * Cross-dispersion limit for the region occupied by the spectrum. - */ - CMN2nnn(HduType.EXTENSION, ValueType.REAL, "Spectrum cross-dispersion limit"), - - /** - * Dispersion limit for the region occupied by the spectrum. - */ - CMX1nnn(HduType.EXTENSION, ValueType.REAL, "Spectrum dispersion limit"), - - /** - * Cross-dispersion limit for the region occupied by the spectrum. - */ - CMX2nnn(HduType.EXTENSION, ValueType.REAL, "Spectrum cross-dispersion limit"), - - /** - * Controller hardware version. - */ - CONHWV(HduType.PRIMARY_EXTENSION, ValueType.STRING, "Controller hardware version"), - - /** - * Controller status. - */ - CONSTAT(HduType.PRIMARY_EXTENSION, ValueType.STRING, "Controller status"), - - /** - * Controller software version. - */ - CONSWV(HduType.PRIMARY_EXTENSION, ValueType.STRING, "Controller software version"), - - /** - * Detector controller name. - */ - CONTROLR(HduType.PRIMARY_EXTENSION, ValueType.STRING, "Detector controller"), - - /** - * Correctors in the optical path. - */ - CORRCT(HduType.PRIMARY, ValueType.STRING, "Corrector"), - - /** - * Correctors in the optical path. - */ - CORRCTn(HduType.PRIMARY, ValueType.STRING, "Corrector"), - - /** - * Correctors in the optical path. - */ - CORRCTOR(HduType.PRIMARY, ValueType.STRING, "Corrector Identification"), - - /** - * Default cross dispersion unit. - */ - CROSUNIT(HduType.PRIMARY_EXTENSION, ValueType.STRING, "Declination unit"), - - /** - * Default cross dispersion coordinate ValueType. - */ - CROSVAL(HduType.PRIMARY_EXTENSION, ValueType.REAL, "Cross dispersion coordinate"), - - /** - * Reference spectrum pixel coordinate. Generally this should be the at the center of the spectrum. In raw data the - * spectrum position(s) may be predicted apart from an offset that will be determined during data reduction. - */ - CRP1nnn(HduType.EXTENSION, ValueType.REAL, "Coordinate reference pixel"), - - /** - * Reference spectrum pixel coordinate. Generally this should be the at the center of the spectrum. In raw data the - * spectrum position(s) may be predicted apart from an offset that will be determined during data reduction. - */ - CRP2nnn(HduType.EXTENSION, ValueType.REAL, "Coordinate reference pixel"), - - /** - * Reference spectrum pixel coordinate. Generally this should be the at the center of the spectrum. In raw data the - * spectrum position(s) may be predicted apart from an offset that will be determined during data reduction. - */ - CRPIX1(HduType.EXTENSION, ValueType.REAL, "Coordinate reference pixel"), - - /** - * Reference spectrum pixel coordinate. Generally this should be the at the center of the spectrum. In raw data the - * spectrum position(s) may be predicted apart from an offset that will be determined during data reduction. - */ - CRPIX2(HduType.EXTENSION, ValueType.REAL, "Coordinate reference pixel"), - - /** - * Spectrum reference dispersion coordinate corresponding to the spectrum reference pixel coordinate. Note that by - * definition WCS axis 1 is always the dispersion axis. The mapping of this WCS axis to the dispersion direction in - * the image is given by the coordinate transformation matrix keywords. In raw data the reference dispersion - * coordinate may be approximately predicted. This will be refined during data reductions. - */ - CRV1nnn(HduType.EXTENSION, ValueType.REAL, "Coordinate reference value"), - - /** - * Spectrum reference dispersion coordinate corresponding to the spectrum reference pixel coordinate. Note that by - * definition WCS axis 1 is always the dispersion axis. The mapping of this WCS axis to the dispersion direction in - * the image is given by the coordinate transformation matrix keywords. In raw data the reference dispersion - * coordinate may be approximately predicted. This will be refined during data reductions. - */ - CRV2nnn(HduType.EXTENSION, ValueType.REAL, "Coordinate reference value"), - - /** - * Spectrum reference dispersion coordinate corresponding to the spectrum reference pixel coordinate. Note that by - * definition WCS axis 1 is always the dispersion axis. The mapping of this WCS axis to the dispersion direction in - * the image is given by the coordinate transformation matrix keywords. In raw data the reference dispersion - * coordinate may be approximately predicted. This will be refined during data reductions. - */ - CRVAL1(HduType.EXTENSION, ValueType.REAL, "Spectrum dispersion center"), - - /** - * Reference right ascension coordinate corresponding to the image reference pixel coordinate. Note that by - * definition WCS axis 1 is always the right ascension axis. The mapping of this WCS axis to the right ascension - * direction in the image is given by the coordinate transformation matrix keywords. In raw data the reference right - * ascension coordinate may be only approximate. This will be refined during data reductions. - */ - CRVAL2(HduType.EXTENSION, ValueType.REAL, "Spectrum cross-dispersion center"), - - /** - * Reference declination coordinate corresponding to the image reference pixel coordinate. Note that by definition - * WCS axis 1 is always the declination axis. The mapping of this WCS axis to the declination direction in the image - * is given by the coordinate transformation matrix keywords. In raw data the reference right ascension coordinate - * may be only approximate. This will be refined during data reductions. - */ - CTY1nnn(HduType.EXTENSION, ValueType.STRING, "Spectrum coordinate type"), - - /** - * Coordinate type for image world coordinates. The IRAF WCS standards are used (which is generally the FITS - * standard). - */ - CTY2nnn(HduType.EXTENSION, ValueType.STRING, "Spectrum coordinate type"), - - /** - * Coordinate type for image world coordinates. The IRAF WCS standards are used (which is generally the FITS - * standard). - */ - CTYP2nnn(HduType.EXTENSION, ValueType.STRING, "Coordinate type"), - - /** - * Spectrum dispersion coordinate type. These are the FITS defined types. - */ - CTYPE1(HduType.EXTENSION, ValueType.STRING, "Spectrum coordinate type"), - - /** - * Coordinate type for image world coordinates. The IRAF WCS standards are used (which is generally the FITS - * standard). - */ - CTYPE2(HduType.EXTENSION, ValueType.STRING, "Spectrum coordinate type"), - - /** - * Coordinate type for image world coordinates. The IRAF WCS standards are used (which is generally the FITS - * standard). - */ - CUN1nnn(HduType.EXTENSION, ValueType.STRING, "Spectrum coordinate unit"), - - /** - * Coordinate reference unit for direct imaging world coordinates. - */ - CUN2nnn(HduType.EXTENSION, ValueType.STRING, "Spectrum coordinate unit"), - - /** - * Coordinate reference unit for direct imaging world coordinates. - */ - CUNIT1(HduType.EXTENSION, ValueType.STRING, "Spectrum coordinate unit"), - - /** - * Coordinate reference unit for direct imaging world coordinates. - */ - CUNIT2(HduType.EXTENSION, ValueType.STRING, "Coordinate reference unit"), - - /** - * Mapping of the CCD section to image coordinates. - */ - DATASEC(HduType.EXTENSION, ValueType.STRING, "Image data section"), - - /** - * Date at the end of the exposure. The format follows the FITS standard. - */ - DATEEND(HduType.PRIMARY_EXTENSION, ValueType.STRING, "Date at end of exposure"), - - /** - * Date header creation. The format follows the FITS 'date' standard. - */ - DATEHDR(HduType.PRIMARY_EXTENSION, ValueType.STRING, "Date of header creation"), - - /** - * Default date for the observation. This keyword is generally not used and is DATE-OBS keyword for the start of the - * exposure on the detector is used. - */ - DATEOBS(HduType.PRIMARY_EXTENSION, ValueType.STRING, "Date of observation"), - - /** - * Projected position angle of the positive declination axis on the detector. The position angle is measured - * clockwise from the image y axis. - */ - DECPANGL(HduType.PRIMARY, ValueType.REAL, "Position angle of Dec axis"), - - /** - * Default declination units. - */ - DECUNIT(HduType.PRIMARY_EXTENSION, ValueType.STRING, "Declination unit"), - - /** - * Detector configuration. - */ - DETCONF(HduType.PRIMARY, ValueType.STRING, "Detector Configuration"), - - /** - * Declination of the detector center. - */ - DETDEC(HduType.PRIMARY, ValueType.STRING, "Detector delination"), - - /** - * Declination unit. - */ - DETDECU(HduType.PRIMARY, ValueType.STRING, "Delination unit"), - - /** - * Detector name. - */ - DETECTOR(HduType.PRIMARY, ValueType.STRING, "Detector name"), - - /** - * Epoch of the detector center coordinates. - */ - DETEPOCH(HduType.PRIMARY, ValueType.REAL, "Detector coordinate epoch"), - - /** - * Detector coordinate system equinox. A value before 1984 is Besselian otherwise it is Julian. - */ - DETEQUIN(HduType.PRIMARY, ValueType.REAL, "Detector coordinate equinox"), - - /** - * Detector hardware version. - */ - DETHWV(HduType.PRIMARY, ValueType.STRING, "Detector version"), - - /** - * Times for the detector sensor measurements given as modified Julian dates. The MJDHDR keyword may be used for the - * time at which the image header is created or the MJD-OBS keyword may be used for the time of observation. - */ - DETMJD(HduType.PRIMARY, ValueType.REAL, ""), - - /** - * Times for the detector sensor measurements given as modified Julian dates. The MJDHDR keyword may be used for the - * time at which the image header is created or the MJD-OBS keyword may be used for the time of observation. - */ - DETMJDn(HduType.PRIMARY, ValueType.REAL, ""), - - /** - * Detector position angle measurements in appropriate units. - */ - DETPAN(HduType.PRIMARY, ValueType.REAL, ""), - - /** - * Detector position angle measurements in appropriate units. - */ - DETPANn(HduType.PRIMARY, ValueType.REAL, ""), - - /** - * Detector linear position sensor measurements in appropriate units. - */ - DETPOS(HduType.PRIMARY, ValueType.REAL, ""), - - /** - * Detector linear position sensor measurements in appropriate units. - */ - DETPOSn(HduType.PRIMARY, ValueType.REAL, ""), - - /** - * Detector pressure sensor measurements in appropriate units. - */ - DETPRE(HduType.PRIMARY, ValueType.REAL, ""), - - /** - * Detector pressure sensor measurements in appropriate units. - */ - DETPREn(HduType.PRIMARY, ValueType.REAL, ""), - - /** - * Right ascension of the detector center. - */ - DETRA(HduType.PRIMARY_EXTENSION, ValueType.STRING, "Detector right ascension"), - - /** - * Detector coordinate system type. - */ - DETRADEC(HduType.PRIMARY, ValueType.STRING, "Detector coordinate system"), - - /** - * Right ascension unit. - */ - DETRAU(HduType.PRIMARY_EXTENSION, ValueType.STRING, "Right ascension unit"), - - /** - * Mapping of the CCD section to detector coordinates. - */ - DETSEC(HduType.EXTENSION, ValueType.STRING, "Detector data section"), - - /** - * The logical unbinned size of the detector in section notation. This is the full pixel raster size including, if - * applicable, drift scanning or a mosaic format. This is the full size even when subraster readouts are done. - */ - DETSIZE(HduType.PRIMARY, ValueType.STRING, "Detector size"), - - /** - * Detector status. - */ - DETSTAT(HduType.PRIMARY, ValueType.STRING, "Detector status"), - - /** - * Detector software version. This will not generally be used and the controller software version will apply. - */ - DETSWV(HduType.PRIMARY, ValueType.STRING, "Detector software version"), - - /** - * Detector temperature sensor measurements in degrees Celsius. - */ - DETTEM(HduType.PRIMARY, ValueType.REAL, ""), - - /** - * Detector temperature sensor measurements in degrees Celsius. - */ - DETTEMn(HduType.PRIMARY, ValueType.REAL, ""), - - /** - * Detector voltage sensor measurements in volts. - */ - DETVOL(HduType.PRIMARY, ValueType.REAL, ""), - - /** - * Detector voltage sensor measurements in volts. - */ - DETVOLn(HduType.PRIMARY, ValueType.REAL, ""), - - /** - * Dewar identification. - */ - DEWAR(HduType.PRIMARY, ValueType.STRING, "Dewar"), - - /** - * Dewar hardware version. - */ - DEWHWV(HduType.PRIMARY_EXTENSION, ValueType.STRING, "Dewar hardware"), - - /** - * Times for the dewar sensor measurements given as modified Julian dates. The MJDHDR keyword may be used for the - * time at which the image header is created or the MJD-OBS keyword may be used for the time of observation. - */ - DEWMJD(HduType.PRIMARY_EXTENSION, ValueType.REAL, ""), - - /** - * Times for the dewar sensor measurements given as modified Julian dates. The MJDHDR keyword may be used for the - * time at which the image header is created or the MJD-OBS keyword may be used for the time of observation. - */ - DEWMJDn(HduType.PRIMARY_EXTENSION, ValueType.REAL, ""), - - /** - * Dewar position angle measurements in appropriate units. - */ - DEWPAN(HduType.PRIMARY_EXTENSION, ValueType.REAL, ""), - - /** - * Dewar position angle measurements in appropriate units. - */ - DEWPANn(HduType.PRIMARY_EXTENSION, ValueType.REAL, ""), - - /** - * Dewar linear position sensor measurements in appropriate units. - */ - DEWPOS(HduType.PRIMARY_EXTENSION, ValueType.REAL, ""), - - /** - * Dewar linear position sensor measurements in appropriate units. - */ - DEWPOSn(HduType.PRIMARY_EXTENSION, ValueType.REAL, ""), - - /** - * Dewar pressure sensor measurements in appropriate units. - */ - DEWPRE(HduType.PRIMARY_EXTENSION, ValueType.REAL, ""), - - /** - * Dewar pressure sensor measurements in appropriate units. - */ - DEWPREn(HduType.PRIMARY_EXTENSION, ValueType.REAL, ""), - - /** - * Dewar status. - */ - DEWSTAT(HduType.PRIMARY_EXTENSION, ValueType.STRING, "Dewar status"), - - /** - * Dewar software version. - */ - DEWSWV(HduType.PRIMARY_EXTENSION, ValueType.STRING, "Dewar software version"), - - /** - * Dewar temperature sensor measurements in degrees Celsius. - */ - DEWTEM(HduType.PRIMARY_EXTENSION, ValueType.REAL, "Dewar temperature"), - - /** - * Dewar temperature sensor measurements in degrees Celsius. - */ - DEWTEMn(HduType.PRIMARY_EXTENSION, ValueType.REAL, "Dewar temperature"), - - /** - * Dewar voltage sensor measurements in volts. - */ - DEWVOL(HduType.PRIMARY_EXTENSION, ValueType.REAL, ""), - - /** - * Dewar voltage sensor measurements in volts. - */ - DEWVOLn(HduType.PRIMARY_EXTENSION, ValueType.REAL, ""), - - /** - * Times for the disperser sensor measurements given as modified Julian dates. - */ - DISMJD(HduType.PRIMARY, ValueType.REAL, ""), - - /** - * Times for the disperser sensor measurements given as modified Julian dates. - */ - DISMJDn(HduType.PRIMARY, ValueType.REAL, ""), - - /** - * Disperser position angle measurements in appropriate units. - */ - DISPAN(HduType.PRIMARY, ValueType.REAL, ""), - - /** - * Disperser position angle measurements in appropriate units. - */ - DISPANn(HduType.PRIMARY, ValueType.REAL, ""), - - /** - * The detector axis along which the dispersion is most closely aligned. - */ - DISPAXIS(HduType.PRIMARY, ValueType.INTEGER, "Dispersion axis"), - - /** - * Approximate central dispersion/pixel on the detector. - */ - DISPDW(HduType.PRIMARY, ValueType.REAL, "Dispersion"), - - /** - * Disperser identification names. - */ - DISPER(HduType.PRIMARY, ValueType.STRING, "Disperser"), - - /** - * Disperser identification names. - */ - DISPERn(HduType.PRIMARY, ValueType.STRING, "Disperser"), - - /** - * Disperser linear position sensor measurements in appropriate units. - */ - DISPOS(HduType.PRIMARY, ValueType.REAL, ""), - - /** - * Disperser linear position sensor measurements in appropriate units. - */ - DISPOSn(HduType.PRIMARY, ValueType.REAL, ""), - - /** - * Disperser pressure sensor measurements in appropriate units. - */ - DISPRE(HduType.PRIMARY, ValueType.REAL, ""), - - /** - * Disperser pressure sensor measurements in appropriate units. - */ - DISPREn(HduType.PRIMARY, ValueType.REAL, ""), - - /** - * Default dispersion coordinate unit. - */ - DISPUNIT(HduType.PRIMARY_EXTENSION, ValueType.STRING, "Dispersion coordinate unit"), - - /** - * Default dispersion coordinate ValueType. - */ - DISPVAL(HduType.PRIMARY_EXTENSION, ValueType.REAL, "Dispersion coordinate"), - - /** - * Approximate central dispersion coordinate on the detector. - */ - DISPWC(HduType.PRIMARY, ValueType.REAL, "Central dispersion coordinate"), - - /** - * Disperser temperature sensor measurements in degrees Celsius. - */ - DISTEM(HduType.PRIMARY, ValueType.REAL, ""), - - /** - * Disperser temperature sensor measurements in degrees Celsius. - */ - DISTEMn(HduType.PRIMARY, ValueType.REAL, ""), - - /** - * Disperser voltage sensor measurements in volts. - */ - DISVOL(HduType.PRIMARY, ValueType.REAL, ""), - - /** - * Disperser voltage sensor measurements in volts. - */ - DISVOLn(HduType.PRIMARY, ValueType.REAL, ""), - - /** - * Average wind direction measurements measured east of north over the sampling period inside the dome. - */ - DMEDIR(HduType.PRIMARY, ValueType.REAL, "Average wind direction"), - - /** - * Average wind direction measurements measured east of north over the sampling period inside the dome. - */ - DMEDIRn(HduType.PRIMARY, ValueType.REAL, "Average wind direction"), - - /** - * Maximum wind speed over the sampling period inside the dome. - */ - DMEGUS(HduType.PRIMARY, ValueType.REAL, "Maximum dome wind speed"), - - /** - * Maximum wind speed over the sampling period inside the dome. - */ - DMEGUSn(HduType.PRIMARY, ValueType.REAL, "Maximum dome wind speed"), - - /** - * Times for the dome environment measurements given as modified Julian. For the wind measurements this is the start - * of the sampling period. - */ - DMEMJD(HduType.PRIMARY, ValueType.REAL, ""), - - /** - * Times for the dome environment measurements given as modified Julian. For the wind measurements this is the start - * of the sampling period. - */ - DMEMJDn(HduType.PRIMARY, ValueType.REAL, ""), - - /** - * Wind sampling period for the wind measurements inside the dome. If no value is given then the measurements are - * assumed to be 'instantaneous'. - */ - DMEPER(HduType.PRIMARY, ValueType.REAL, "Dome wind sampling"), - - /** - * Wind sampling period for the wind measurements inside the dome. If no value is given then the measurements are - * assumed to be 'instantaneous'. - */ - DMEPERn(HduType.PRIMARY, ValueType.REAL, "Dome wind sampling"), - - /** - * Temperatures Celsius inside the dome. - */ - DMETEM(HduType.PRIMARY, ValueType.REAL, "Dome temperature"), - - /** - * Temperatures Celsius inside the dome. - */ - DMETEMn(HduType.PRIMARY, ValueType.REAL, "Dome temperature"), - - /** - * Average wind speeds over the sampling period inside the dome. - */ - DMEWIN(HduType.PRIMARY, ValueType.REAL, "Average dome wind speed"), - - /** - * Average wind speeds over the sampling period inside the dome. - */ - DMEWINn(HduType.PRIMARY, ValueType.REAL, "Average dome wind speed"), - - /** - * Times for the dome sensor measurements given as modified Julian dates. - */ - DOMMJD(HduType.PRIMARY, ValueType.REAL, ""), - - /** - * Times for the dome sensor measurements given as modified Julian dates. - */ - DOMMJDn(HduType.PRIMARY, ValueType.REAL, ""), - - /** - * Dome position angle sensor measurements. This should be in degrees east of north for the center of the dome slit. - */ - DOMPAN(HduType.PRIMARY, ValueType.REAL, ""), - - /** - * Dome position angle sensor measurements. This should be in degrees east of north for the center of the dome slit. - */ - DOMPANn(HduType.PRIMARY, ValueType.REAL, ""), - - /** - * Dome linear position sensor measurements in appropriate units. - */ - DOMPOS(HduType.PRIMARY, ValueType.REAL, ""), - - /** - * Dome linear position sensor measurements in appropriate units. - */ - DOMPOSn(HduType.PRIMARY, ValueType.REAL, ""), - - /** - * Dome pressure sensor measurements in appropriate units. - */ - DOMPRE(HduType.PRIMARY, ValueType.REAL, ""), - - /** - * Dome pressure sensor measurements in appropriate units. - */ - DOMPREn(HduType.PRIMARY, ValueType.REAL, ""), - - /** - * Dome status. - */ - DOMSTAT(HduType.PRIMARY, ValueType.STRING, "Dome status"), - - /** - * Dome temperature sensor measurements in degrees Celsius. - */ - DOMTEM(HduType.PRIMARY, ValueType.REAL, "Dome temperature"), - - /** - * Dome temperature sensor measurements in degrees Celsius. - */ - DOMTEMn(HduType.PRIMARY, ValueType.REAL, "Dome temperature"), - - /** - * Dome voltage sensor measurements in volts. - */ - DOMVOL(HduType.PRIMARY, ValueType.REAL, ""), - - /** - * Dome voltage sensor measurements in volts. - */ - DOMVOLn(HduType.PRIMARY, ValueType.REAL, ""), - - /** - * Transformation matrix between CCD and detector coordinates. If missing the default is an identify matrix. - */ - DTMn_n(HduType.EXTENSION, ValueType.REAL, "Detector transformation matrix"), - - /** - * Transformation origin vector between CCD and detector coordinates. - */ - DTVn(HduType.EXTENSION, ValueType.REAL, "Detector transformation vector"), - - /** - * Average wind direction measurements measured east of north over the sampling period outside the dome at times - * given by ENVMJDn keywords. - */ - ENVDIR(HduType.PRIMARY, ValueType.REAL, "Average wind direction"), - - /** - * Average wind direction measurements measured east of north over the sampling period outside the dome at times - * given by ENVMJDn keywords. - */ - ENVDIRn(HduType.PRIMARY, ValueType.REAL, "Average wind direction"), - - /** - * Maximum wind speed in km/s over the sampling period outside the dome at times given by ENVMJDn keywords. - */ - ENVGUS(HduType.PRIMARY, ValueType.REAL, "Maximum gust speed"), - - /** - * Maximum wind speed in km/s over the sampling period outside the dome at times given by ENVMJDn keywords. - */ - ENVGUSn(HduType.PRIMARY, ValueType.REAL, "Maximum gust speed"), - - /** - * Relative humidity measurements at times given by ENVMJDn keywords. - */ - ENVHUM(HduType.PRIMARY, ValueType.REAL, "Relative humidity"), - - /** - * Relative humidity measurements at times given by ENVMJDn keywords. - */ - ENVHUMn(HduType.PRIMARY, ValueType.REAL, "Relative humidity"), - - /** - * Times for the site environment measurements given as modified Julian. For the wind measurements this is the start - * of the sampling period. - */ - ENVMJD(HduType.PRIMARY, ValueType.REAL, "Environment measurement time"), - - /** - * Times for the site environment measurements given as modified Julian. For the wind measurements this is the start - * of the sampling period. - */ - ENVMJDn(HduType.PRIMARY, ValueType.REAL, "Environment measurement time"), - - /** - * Wind sampling period for the wind measurements outside the dome at times given by ENVMJDn keywords. If no value - * is given then the measurements are assumed to be 'instantaneous'. - */ - ENVPER(HduType.PRIMARY, ValueType.REAL, "Wind sampling period"), - - /** - * Wind sampling period for the wind measurements outside the dome at times given by ENVMJDn keywords. If no value - * is given then the measurements are assumed to be 'instantaneous'. - */ - ENVPERn(HduType.PRIMARY, ValueType.REAL, "Wind sampling period"), - - /** - * Atmospheric pressure measurements at times given by ENVMJDn keywords. - */ - ENVPRE(HduType.PRIMARY, ValueType.REAL, "Air pressure"), - - /** - * Atmospheric pressure measurements at times given by ENVMJDn keywords. - */ - ENVPREn(HduType.PRIMARY, ValueType.REAL, "Air pressure"), - - /** - * Temperatures outside the dome at times given by ENVMJDn keywords. - */ - ENVTEM(HduType.PRIMARY, ValueType.REAL, "Site temperature"), - - /** - * Temperatures outside the dome at times given by ENVMJDn keywords. - */ - ENVTEMn(HduType.PRIMARY, ValueType.REAL, "Site temperature"), - - /** - * Precipitable water vapor measurements at times given by ENVMJDn keywords. - */ - ENVWAT(HduType.PRIMARY, ValueType.REAL, "Precipitable water vapor"), - - /** - * Precipitable water vapor measurements at times given by ENVMJDn keywords. - */ - ENVWATn(HduType.PRIMARY, ValueType.REAL, "Precipitable water vapor"), - - /** - * Average wind speeds over the sampling period outside the dome at times given by ENVMJDn keywords. - */ - ENVWIN(HduType.PRIMARY, ValueType.REAL, "Average wind speed"), - - /** - * Average wind speeds over the sampling period outside the dome at times given by ENVMJDn keywords. - */ - ENVWINn(HduType.PRIMARY, ValueType.REAL, "Average wind speed"), - - /** - * Error information. The sequence numbers are used to order the information. - */ - ERRORnnn(HduType.PRIMARY, ValueType.STRING, ""), - - /** - * Requested exposure time of the observation. - */ - EXPREQ(HduType.PRIMARY_EXTENSION, ValueType.REAL, "Requested exposure time"), - - /** - * Fiber identification for the fiber(s). The string consists of a fiber number, an object type number (0=sky, - * 1=object, etc.), the right ascension and declination, and the object name or title. This can replace OBJNAME, - * APRA/OBJRA, and APDEC/OBJDEC. - */ - FIBER(HduType.PRIMARY, ValueType.STRING, ""), - - /** - * Fiber identification for the fiber(s). The string consists of a fiber number, an object type number (0=sky, - * 1=object, etc.), the right ascension and declination, and the object name or title. This can replace OBJNAME, - * APRA/OBJRA, and APDEC/OBJDEC. - */ - FIBnnn(HduType.PRIMARY, ValueType.STRING, ""), - - /** - * Filter position given as filter wheel number or other filter system position measurement. - */ - FILPOS(HduType.PRIMARY, ValueType.REAL, "Filter system position"), - - /** - * Filter position given as filter wheel number or other filter system position measurement. - */ - FILPOSn(HduType.PRIMARY, ValueType.REAL, "Filter system position"), - - /** - * Filter type. This is the technical specification or observatory identification name. - */ - FILTYP(HduType.PRIMARY, ValueType.STRING, "Filter type"), - - /** - * Filter type. This is the technical specification or observatory identification name. - */ - FILTYPn(HduType.PRIMARY, ValueType.STRING, "Filter type"), - - /** - * Number of focus exposures in a focus sequence. - */ - FOCNEXPO(HduType.PRIMARY, ValueType.INTEGER, "Number of focus exposures"), - - /** - * Pixel shift on the detector between exposures in a focus sequence. - */ - FOCSHIFT(HduType.PRIMARY, ValueType.REAL, "Shift between focus exposures"), - - /** - * Starting focus value in focus sequence. - */ - FOCSTART(HduType.PRIMARY, ValueType.REAL, "Starting focus"), - - /** - * Focus increment step in focus sequence. - */ - FOCSTEP(HduType.PRIMARY, ValueType.REAL, "Focus step"), - - /** - * Amplifier gain in electrons per analog unit. This is the most current estimate of the gain. - */ - GAIN(HduType.EXTENSION, ValueType.REAL, "Amplifier gain"), - - /** - * Guider TV name. - */ - GTV(HduType.PRIMARY, ValueType.STRING, "Guider TV"), - - /** - * Guider TV filter names. This name is the astronomical standard name if applicable; i.e. U, B, Gunn I, etc. The - * filter type and filter device position are given by other keywords. - */ - GTVFIL(HduType.PRIMARY, ValueType.STRING, "Filter name"), - - /** - * Guider TV filter names. This name is the astronomical standard name if applicable; i.e. U, B, Gunn I, etc. The - * filter type and filter device position are given by other keywords. - */ - GTVFILn(HduType.PRIMARY, ValueType.STRING, "Filter name"), - - /** - * Guider TV filter position given as filter wheel number or other filter system position measurement. - */ - GTVFPO(HduType.PRIMARY, ValueType.REAL, "Filter system position"), - - /** - * Guider TV filter position given as filter wheel number or other filter system position measurement. - */ - GTVFPOn(HduType.PRIMARY, ValueType.REAL, "Filter system position"), - - /** - * Guider TV filter type. This is the technical specification or observatory identification name. - */ - GTVFTY(HduType.PRIMARY, ValueType.STRING, "Filter type"), - - /** - * Guider TV filter type. This is the technical specification or observatory identification name. - */ - GTVFTYn(HduType.PRIMARY, ValueType.STRING, "Filter type"), - - /** - * Guider TV identification and hardware version. - */ - GTVHWV(HduType.PRIMARY, ValueType.STRING, ""), - - /** - * Times for the guider television sensor measurements given as modified Julian dates. - */ - GTVMJD(HduType.PRIMARY, ValueType.REAL, ""), - - /** - * Times for the guider television sensor measurements given as modified Julian dates. - */ - GTVMJDn(HduType.PRIMARY, ValueType.REAL, ""), - - /** - * Guider television position angle measurements in appropriate units. - */ - GTVPAN(HduType.PRIMARY, ValueType.REAL, ""), - - /** - * Guider television position angle measurements in appropriate units. - */ - GTVPANn(HduType.PRIMARY, ValueType.REAL, ""), - - /** - * Guider television linear position sensor measurements in appropriate units. - */ - GTVPOS(HduType.PRIMARY, ValueType.REAL, "Television position ()"), - - /** - * Guider television linear position sensor measurements in appropriate units. - */ - GTVPOSn(HduType.PRIMARY, ValueType.REAL, "Television position ()"), - - /** - * Guider television pressure sensor measurements in appropriate units. - */ - GTVPRE(HduType.PRIMARY, ValueType.REAL, ""), - - /** - * Guider television pressure sensor measurements in appropriate units. - */ - GTVPREn(HduType.PRIMARY, ValueType.REAL, ""), - - /** - * Guider TV status. - */ - GTVSTAT(HduType.PRIMARY, ValueType.STRING, ""), - - /** - * Guider TV software version. - */ - GTVSWV(HduType.PRIMARY, ValueType.NONE, ""), - - /** - * Guider television temperature sensor measurements in degrees Celsius. - */ - GTVTEM(HduType.PRIMARY, ValueType.REAL, ""), - - /** - * Guider television temperature sensor measurements in degrees Celsius. - */ - GTVTEMn(HduType.PRIMARY, ValueType.REAL, ""), - - /** - * Guider television voltage sensor measurements in volts. - */ - GTVVOL(HduType.PRIMARY, ValueType.REAL, ""), - - /** - * Guider television voltage sensor measurements in volts. - */ - GTVVOLn(HduType.PRIMARY, ValueType.REAL, ""), - - /** - * Guide object declination. - */ - GUIDEC(HduType.PRIMARY, ValueType.STRING, "Guider declination"), - - /** - * Declination unit. - */ - GUIDECU(HduType.PRIMARY, ValueType.STRING, "Declination unit"), - - /** - * Guider identification and hardware version. - */ - GUIDEHWV(HduType.PRIMARY, ValueType.NONE, ""), - - /** - * Guider name. Two of the names are 'manual' and 'none' for manual guiding or no guider, respectively. - */ - GUIDER(HduType.PRIMARY, ValueType.STRING, "Guider name"), - - /** - * Guider software version. - */ - GUIDESWV(HduType.PRIMARY, ValueType.NONE, ""), - - /** - * Epoch of the guide object coordinates. - */ - GUIEPOCH(HduType.PRIMARY, ValueType.NONE, ""), - - /** - * Guide object coordinate system equinox. A value before 1984 is Besselian otherwise it is Julian. - */ - GUIEQUIN(HduType.PRIMARY, ValueType.REAL, ""), - - /** - * Times for the guider sensor measurements given as modified Julian dates. - */ - GUIMJD(HduType.PRIMARY, ValueType.REAL, ""), - - /** - * Times for the guider sensor measurements given as modified Julian dates. - */ - GUIMJDn(HduType.PRIMARY, ValueType.REAL, ""), - - /** - * Guider position angle measurements in appropriate units. - */ - GUIPAN(HduType.PRIMARY, ValueType.REAL, ""), - - /** - * Guider position angle measurements in appropriate units. - */ - GUIPANn(HduType.PRIMARY, ValueType.REAL, ""), - - /** - * Guider linear position sensor measurements in appropriate units. This might be used for guide probe positions. - */ - GUIPOS(HduType.PRIMARY, ValueType.REAL, "Guider position ()"), - - /** - * Guider linear position sensor measurements in appropriate units. This might be used for guide probe positions. - */ - GUIPOSn(HduType.PRIMARY, ValueType.REAL, "Guider position ()"), - - /** - * Guider pressure sensor measurements in appropriate units. - */ - GUIPRE(HduType.PRIMARY, ValueType.REAL, ""), - - /** - * Guider pressure sensor measurements in appropriate units. - */ - GUIPREn(HduType.PRIMARY, ValueType.REAL, ""), - - /** - * Guide object right ascension. - */ - GUIRA(HduType.PRIMARY, ValueType.STRING, "Guider right ascension"), - - /** - * Guide object coordinate system type. - */ - GUIRADEC(HduType.PRIMARY, ValueType.STRING, ""), - - /** - * Guider correction rate. - */ - GUIRATE(HduType.PRIMARY, ValueType.REAL, "Guider rate"), - - /** - * Right ascension unit. - */ - GUIRAU(HduType.PRIMARY, ValueType.STRING, "Right ascension unit"), - - /** - * Guider status. - */ - GUISTAT(HduType.PRIMARY, ValueType.STRING, ""), - - /** - * Guider temperature sensor measurements in degrees Celsius. - */ - GUITEM(HduType.PRIMARY, ValueType.REAL, ""), - - /** - * Guider temperature sensor measurements in degrees Celsius. - */ - GUITEMn(HduType.PRIMARY, ValueType.REAL, ""), - - /** - * Guider voltage sensor measurements in volts. - */ - GUIVOL(HduType.PRIMARY, ValueType.REAL, ""), - - /** - * Guider voltage sensor measurements in volts. - */ - GUIVOLn(HduType.PRIMARY, ValueType.REAL, ""), - - /** - * Hour angle at TELMJD. - */ - HA(HduType.PRIMARY, ValueType.STRING, "Hour angle"), - - /** - * Image creation system hardware version. - */ - IMAGEHWV(HduType.PRIMARY, ValueType.STRING, "Image creation hardware version"), - - /** - * The image identification when there are multiple images within an observation. For detectors with CCDs this would - * be a unique number assigned to each amplifier in the detector. - */ - IMAGEID(HduType.EXTENSION, ValueType.INTEGER, "Image identification"), - - /** - * Image creation system software version. - */ - IMAGESWV(HduType.PRIMARY, ValueType.STRING, "Image creation software version"), - - /** - * Instrument focus. - */ - INSFOCUS(HduType.PRIMARY, ValueType.REAL, "Instrument focus"), - - /** - * Times for the instrument sensor measurements given as modified Julian dates. - */ - INSMJD(HduType.PRIMARY, ValueType.REAL, ""), - - /** - * Times for the instrument sensor measurements given as modified Julian dates. - */ - INSMJDn(HduType.PRIMARY, ValueType.REAL, ""), - - /** - * Instrument position angle measurements in appropriate units. - */ - INSPAN(HduType.PRIMARY, ValueType.REAL, ""), - - /** - * Instrument position angle measurements in appropriate units. - */ - INSPANn(HduType.PRIMARY, ValueType.REAL, ""), - - /** - * Instrument linear position sensor measurements in appropriate units. - */ - INSPOS(HduType.PRIMARY, ValueType.REAL, ""), - - /** - * Instrument linear position sensor measurements in appropriate units. - */ - INSPOSn(HduType.PRIMARY, ValueType.REAL, ""), - - /** - * Instrument pressure sensor measurements in appropriate units. - */ - INSPRE(HduType.PRIMARY, ValueType.REAL, ""), - - /** - * Instrument pressure sensor measurements in appropriate units. - */ - INSPREn(HduType.PRIMARY, ValueType.REAL, ""), - - /** - * Instrument status. - */ - INSSTAT(HduType.PRIMARY, ValueType.STRING, "Instrument status"), - - /** - * Instrument configuration. - */ - INSTCONF(HduType.PRIMARY, ValueType.STRING, "Instrument configuration"), - - /** - * Instrument temperature sensor measurements in degrees Celsius. - */ - INSTEM(HduType.PRIMARY, ValueType.REAL, ""), - - /** - * Instrument temperature sensor measurements in degrees Celsius. - */ - INSTEMn(HduType.PRIMARY, ValueType.REAL, ""), - - /** - * Instrument hardware version. - */ - INSTHWV(HduType.PRIMARY, ValueType.STRING, "Instrument hardware version"), - - /** - * Instrument software version. ------------------------------------------------------------------ - */ - INSTSWV(HduType.PRIMARY, ValueType.STRING, "Instrument software version"), - - /** - * Instrument voltage sensor measurements in volts. - */ - INSVOL(HduType.PRIMARY, ValueType.REAL, ""), - - /** - * Instrument voltage sensor measurements in volts. - */ - INSVOLn(HduType.PRIMARY, ValueType.REAL, ""), - - /** - * The keyword dictionary defining the keywords. This dictionary should be archived with the data. - */ - KWDICT(HduType.PRIMARY, ValueType.STRING, "Keyword dictionary"), - - /** - * Calibration lamp name - */ - LAMP(HduType.PRIMARY, ValueType.STRING, "Calibration lamp"), - - /** - * Calibration lamp type. - */ - LAMPTYPE(HduType.PRIMARY, ValueType.STRING, "Lamp type"), - - /** - * Times for the lamp sensor measurements given as modified Julian dates. The MJDHDR keyword may be used for the - * time at which the image header is created or the MJD-OBS keyword may be used for the time of observation. - */ - LMPMJD(HduType.PRIMARY, ValueType.REAL, ""), - - /** - * Times for the lamp sensor measurements given as modified Julian dates. The MJDHDR keyword may be used for the - * time at which the image header is created or the MJD-OBS keyword may be used for the time of observation. - */ - LMPMJDn(HduType.PRIMARY, ValueType.REAL, ""), - - /** - * Calibration lamp position angle measurements in appropriate units. - */ - LMPPAN(HduType.PRIMARY, ValueType.REAL, ""), - - /** - * Calibration lamp position angle measurements in appropriate units. - */ - LMPPANn(HduType.PRIMARY, ValueType.REAL, ""), - - /** - * Calibration lamp linear position sensor measurements in appropriate units. - */ - LMPPOS(HduType.PRIMARY, ValueType.REAL, ""), - - /** - * Calibration lamp linear position sensor measurements in appropriate units. - */ - LMPPOSn(HduType.PRIMARY, ValueType.REAL, ""), - - /** - * Calibration lamp pressure sensor measurements in appropriate units. - */ - LMPPRE(HduType.PRIMARY, ValueType.REAL, ""), - - /** - * Calibration lamp pressure sensor measurements in appropriate units. - */ - LMPPREn(HduType.PRIMARY, ValueType.REAL, ""), - - /** - * Calibration lamp temperature sensor measurements in degrees Celsius. - */ - LMPTEM(HduType.PRIMARY, ValueType.REAL, ""), - - /** - * Calibration lamp temperature sensor measurements in degrees Celsius. - */ - LMPTEMn(HduType.PRIMARY, ValueType.REAL, ""), - - /** - * Calibration lamp voltage sensor measurements in volts. - */ - LMPVOL(HduType.PRIMARY, ValueType.REAL, ""), - - /** - * Calibration lamp voltage sensor measurements in volts. - */ - LMPVOLn(HduType.PRIMARY, ValueType.REAL, ""), - - /** - * Local siderial time at the start of the exposure. - */ - LST_OBS("LST-OBS", HduType.PRIMARY_EXTENSION, ValueType.STRING, "LST of exposure start"), - - /** - * Local siderial time at the end of the exposure. - */ - LSTEND(HduType.PRIMARY_EXTENSION, ValueType.STRING, "LST at end of exposure"), - - /** - * Local siderial time of the header creation. - */ - LSTHDR(HduType.PRIMARY_EXTENSION, ValueType.STRING, "LST of header creation"), - - /** - * Default local siderial time for the observation. This keyword is generally not used and is LST-OBS keyword for - * the start of the exposure on the detector is used. - */ - LSTOBS(HduType.PRIMARY_EXTENSION, ValueType.STRING, "LST of observation"), - - /** - * Transformation matrix between CCD and image coordinates. If missing the default is an identify matrix. - */ - LTMn_n(HduType.EXTENSION, ValueType.REAL, "Image transformation matrix"), - - /** - * Transformation origin vector between CCD and image coordinates. - */ - LTVn(HduType.EXTENSION, ValueType.REAL, "Image transformation vector"), - - /** - * The maximum number of scanned (unbinned) lines used to form an output line. This is used with drift scanning or a - * scan table. For long drift scans this will be the number of lines in the CCD. - */ - MAXNSCAN(HduType.EXTENSION, ValueType.INTEGER, "Maximum number of scanned lines"), - - /** - * The minimum number of scanned (unbinned) lines used to form an output line. This is used with drift scanning or a - * scan table. This will only differ from MAXNSCAN if the initial lines in the output image are from the initial - * ramp-up. - */ - MINNSCAN(HduType.EXTENSION, ValueType.INTEGER, "Minimum number of scanned lines"), - - /** - * Modified Julian date when the image header was created by the software. The fractional part of the date is given - * to better than a second of time. Many header keywords may be sampled or computed at this time and this keyword is - * the default for these. - */ - MJDHDR(HduType.PRIMARY_EXTENSION, ValueType.REAL, "MJD of header creation"), - - /** - * Default modified Julian date for the observation. The fractional part of the date is given to better than a - * second of time. This keyword is generally not used and is MJD-OBS keyword for the start of the exposure on the - * detector is used. - */ - MJDOBS(HduType.PRIMARY_EXTENSION, ValueType.REAL, "MJD of observation"), - - /** - * The number of amplifiers in the detector. When there is only a single amplifier used it may be absent since the - * default value is 1. - */ - NAMPS(HduType.PRIMARY, ValueType.INTEGER, "Number of Amplifiers"), - - /** - * The number of CCDs in the detector. This is used with mosaics of CCD detectors. For a single CCD it may be absent - * since the default value is 1. - */ - NCCDS(HduType.PRIMARY, ValueType.INTEGER, "Number of CCDs"), - - NODANGLE(HduType.PRIMARY, ValueType.NONE, ""), - - NODDIST(HduType.PRIMARY, ValueType.NONE, ""), - - NODFREQ(HduType.PRIMARY, ValueType.NONE, ""), - - NODHWV(HduType.PRIMARY, ValueType.NONE, ""), - - /** - * Times for the nodding system sensor measurements given as modified Julian dates. - */ - NODMJD(HduType.PRIMARY, ValueType.REAL, ""), - - /** - * Times for the nodding system sensor measurements given as modified Julian dates. - */ - NODMJDn(HduType.PRIMARY, ValueType.REAL, ""), - - NODNCHOP(HduType.PRIMARY, ValueType.NONE, ""), - - /** - * Nodding position angle measurements in appropriate units. Note that NODANGLE should be used for the nodding angle - * and these keywords are for other system position angle measurements. - */ - NODPAN(HduType.PRIMARY, ValueType.REAL, ""), - - /** - * Nodding position angle measurements in appropriate units. Note that NODANGLE should be used for the nodding angle - * and these keywords are for other system position angle measurements. - */ - NODPANn(HduType.PRIMARY, ValueType.REAL, ""), - - /** - * Nodding system linear position sensor measurements in appropriate units. - */ - NODPOS(HduType.PRIMARY, ValueType.REAL, ""), - - /** - * Nodding system linear position sensor measurements in appropriate units. - */ - NODPOSn(HduType.PRIMARY, ValueType.REAL, ""), - - /** - * Nodding system pressure sensor measurements in appropriate units. - */ - NODPRE(HduType.PRIMARY, ValueType.REAL, ""), - - /** - * Nodding system pressure sensor measurements in appropriate units. - */ - NODPREn(HduType.PRIMARY, ValueType.REAL, ""), - - NODSTAT(HduType.PRIMARY, ValueType.NONE, ""), - - NODSWV(HduType.PRIMARY, ValueType.NONE, ""), - - /** - * Nodding system temperature sensor measurements in degrees Celsius. - */ - NODTEM(HduType.PRIMARY, ValueType.REAL, ""), - - /** - * Nodding system temperature sensor measurements in degrees Celsius. - */ - NODTEMn(HduType.PRIMARY, ValueType.REAL, ""), - - /** - * Nodding system voltage sensor measurements in volts. - */ - NODVOL(HduType.PRIMARY, ValueType.REAL, ""), - - /** - * Nodding system voltage sensor measurements in volts. - */ - NODVOLn(HduType.PRIMARY, ValueType.REAL, ""), - - /** - * Number of coadded subexposures. When charge shuffling this gives the number of charge shuffled exposures. - */ - NSUBEXPS(HduType.PRIMARY_EXTENSION, ValueType.INTEGER, "Number of subexposures"), - - /** - * Declination of the target astronomical object(s). - */ - OBJDEC(HduType.PRIMARY, ValueType.STRING, "Declination of object"), - - /** - * Declination unit. - */ - OBJDECU(HduType.PRIMARY, ValueType.STRING, "Declination unit"), - - /** - * Epoch of the target astronomical object coordinate(s). This is given in years. - */ - OBJEPOCH(HduType.PRIMARY, ValueType.REAL, "Epoch of object coordinates"), - - /** - * Coordinate system equinox for the target astronomical object(s). A value before 1984 is Besselian otherwise it is - * Julian. - */ - OBJEQUIN(HduType.PRIMARY, ValueType.REAL, "Object coordinate equinox"), - - /** - * Standard reference or catalog name for the target astronomical object(s). The name should follow IAU standards. - * These keywords differ from the OBJECT keyword which is used to identify the observation. - */ - OBJnnn(HduType.PRIMARY, ValueType.STRING, "Target object"), - - /** - * Right ascension of the target astronomical object(s). - */ - OBJRA(HduType.PRIMARY, ValueType.STRING, "Right ascension of object"), - - /** - * Coordinate system type for the target astronomical object(s). - */ - OBJRADEC(HduType.PRIMARY, ValueType.STRING, "Object coordinate system"), - - /** - * Right ascension unit. - */ - OBJRAU(HduType.PRIMARY, ValueType.STRING, "Right ascension unit"), - - /** - * Type of target astronomical object(s). This is taken from a dictionary of names yet to be defined. Some common - * types are 'galaxy', 'star', and 'sky'. If not particular object is targeted the type 'field' may be used. - */ - OBJTnnn(HduType.PRIMARY, ValueType.STRING, "Type of object"), - - /** - * Type of target astronomical object(s). This is taken from a dictionary of names yet to be defined. Some common - * types are 'galaxy', 'star', and 'sky'. If not particular object is targeted the type 'field' may be used. - */ - OBJTYPE(HduType.PRIMARY, ValueType.STRING, "Type of object"), - - /** - * Declination of the observation. This may be distinct from the object coordinates and the telescope coordinates. - * It may be used to indicate the requested observation coordinates. - */ - OBSDEC(HduType.PRIMARY, ValueType.STRING, "Observation declination"), - - /** - * Declination unit. - */ - OBSDECU(HduType.PRIMARY, ValueType.STRING, "Declination unit"), - - /** - * Epoch of the coordinates used in observation coordinates. - */ - OBSEPOCH(HduType.PRIMARY, ValueType.REAL, "Observation coordinate epoch"), - - /** - * Equinox of coordinates used in observation coordinates. A value before 1984 is Besselian otherwise it is Julian. - */ - OBSEQUIN(HduType.PRIMARY, ValueType.REAL, "Observation coordinate equinox"), - - /** - * Observatory identification for the site of the observation. - */ - OBSERVAT(HduType.PRIMARY, ValueType.STRING, "Observatory"), - - /** - * The unique observatory observation identification. This serves to identify all data from the same observation. - */ - OBSID(HduType.PRIMARY_EXTENSION, ValueType.STRING, "Observation identification"), - - /** - * Right ascension of the observation. This may be distinct from the object coordinates and the telescope - * coordinates. It may be used to indicate the requested observation coordinates. - */ - OBSRA(HduType.PRIMARY, ValueType.STRING, "Observation right ascension"), - - /** - * Coordinate system used in observation coordinates. - */ - OBSRADEC(HduType.PRIMARY, ValueType.STRING, "Observation coordinate system"), - - /** - * Right ascension unit. - */ - OBSRAU(HduType.PRIMARY, ValueType.STRING, "Right ascension unit"), - - /** - * Name(s) of the observers. - */ - OBSRVRnn(HduType.PRIMARY, ValueType.STRING, "Observer(s)"), - - /** - * Status of the observation. ----------------------------------------------------------------- - */ - OBSSTAT(HduType.PRIMARY, ValueType.STRING, "Observation status"), - - /** - * The type of observation such as an astronomical exposure or a particular type of calibration exposure. - */ - OBSTYPE(HduType.PRIMARY_EXTENSION, ValueType.STRING, "Observation type"), - - /** - * Declination of the target astronomical object(s). - */ - ODECnnn(HduType.PRIMARY, ValueType.STRING, "Declination of object"), - - /** - * Declination unit. - */ - ODEUnnn(HduType.PRIMARY, ValueType.STRING, "Declination unit"), - - /** - * Epoch of the target astronomical object coordinate(s). This is given in years. - */ - OEPOnnn(HduType.PRIMARY, ValueType.REAL, "Epoch of object coordinates"), - - /** - * Coordinate system equinox for the target astronomical object(s). A value before 1984 is Besselian otherwise it is - * Julian. - */ - OEQUnnn(HduType.PRIMARY, ValueType.REAL, "Object coordinate equinox"), - - /** - * Right ascension of the target astronomical object(s). - */ - ORAnnn(HduType.PRIMARY, ValueType.STRING, "Right ascension of object"), - - /** - * Right ascension unit. - */ - ORAUnnn(HduType.PRIMARY, ValueType.STRING, "Right ascension unit"), - - /** - * Coordinate system type for the target astronomical object(s). - */ - ORDSnnn(HduType.PRIMARY, ValueType.STRING, "Object coordinate system"), - - /** - * Status of calibration to data proportional to photons. For CCD data this means bias section correction, zero - * level calibration, dark count calibration, and flat field calibration. - */ - PHOTCAL(HduType.PRIMARY_EXTENSION, ValueType.LOGICAL, "Data proportional to photons?"), - - /** - * Photometric conditions during the observation. - */ - PHOTOMET(HduType.PRIMARY, ValueType.STRING, "Photometric conditions"), - - /** - * Processing hardware used. - */ - PIPEHW(HduType.PRIMARY_EXTENSION, ValueType.STRING, "Processing hardware"), - - /** - * Processing hardware used. - */ - PIPEHWn(HduType.PRIMARY_EXTENSION, ValueType.STRING, "Processing hardware"), - - /** - * Name of processing pipeline applied. - */ - PIPELINE(HduType.PRIMARY_EXTENSION, ValueType.STRING, "Pipeline used"), - - /** - * Processing software version. - */ - PIPESW(HduType.PRIMARY_EXTENSION, ValueType.STRING, "Processing software"), - - /** - * Processing software version. - */ - PIPESWn(HduType.PRIMARY_EXTENSION, ValueType.STRING, "Processing software"), - - /** - * Projected pixel scale along axis n. - */ - PIXSCALn(HduType.PRIMARY, ValueType.REAL, "Pixel scale"), - - /** - * Unbinned pixel size along each dimension given in appropriate units. The units should be indicated in the - * comment. The projected pixel size in arc seconds or wavelength are given by other parameters. - */ - PIXSIZEn(HduType.PRIMARY_EXTENSION, ValueType.REAL, "Pixel size"), - - /** - * Pixel limit for region occupied by the spectrum. - */ - PMAX1(HduType.EXTENSION, ValueType.REAL, "Spectrum pixel limit"), - - /** - * Pixel limit for region occupied by the spectrum. - */ - PMAX2(HduType.EXTENSION, ValueType.REAL, "Spectrum pixel limit"), - - /** - * Pixel limit for region occupied by the spectrum. - */ - PMIN1(HduType.EXTENSION, ValueType.REAL, "Spectrum pixel limit"), - - /** - * Pixel limit for region occupied by the spectrum. - */ - PMIN2(HduType.EXTENSION, ValueType.REAL, "Spectrum pixel limit"), - - /** - * Pixel limit for region occupied by the spectrum. - */ - PMN1nnn(HduType.EXTENSION, ValueType.REAL, "Spectrum pixel limit"), - - /** - * Pixel limit for region occupied by the spectrum. - */ - PMN2n(HduType.EXTENSION, ValueType.REAL, "Spectrum pixel limit"), - - /** - * Pixel limit for region occupied by the spectrum. - */ - PMX1n(HduType.EXTENSION, ValueType.REAL, "Spectrum pixel limit"), - - /** - * Pixel limit for region occupied by the spectrum. - */ - PMX2n(HduType.EXTENSION, ValueType.REAL, "Spectrum pixel limit"), - - /** - * CCD preflash time. If the times in the extension are different the primary HDU gives one of the extension times. - */ - PREFLASH(HduType.PRIMARY_EXTENSION, ValueType.REAL, "Preflash time"), - - /** - * Processing log information formatted as FITS comments. - */ - PROCnnn(HduType.PRIMARY_EXTENSION, ValueType.STRING, ""), - - /** - * Processing status. - */ - PROCSTAT(HduType.PRIMARY_EXTENSION, ValueType.STRING, "Processing status"), - - /** - * The unique observatory proposal identification. - */ - PROPID(HduType.PRIMARY, ValueType.STRING, "Proposal identification"), - - /** - * The name or title of the proposal. - */ - PROPOSAL(HduType.PRIMARY, ValueType.STRING, "Proposal title"), - - /** - * Name(s) of the proposers. - */ - PROPOSER(HduType.PRIMARY, ValueType.STRING, "Proposer(s)"), - - /** - * Name(s) of the proposers. - */ - PROPSRnn(HduType.PRIMARY, ValueType.STRING, "Proposer(s)"), - - /** - * Default coordinate system equinox. A value before 1984 is Besselian otherwise it is Julian. If absent the default - * is J2000. - */ - RADECEQ(HduType.PRIMARY_EXTENSION, ValueType.REAL, "Default coordinate equinox"), - - /** - * Projected position angle of the positive right ascension axis on the detector. The position angle is measured - * clockwise from the image y axis. - */ - RAPANGL(HduType.PRIMARY, ValueType.REAL, "Position angle of RA axis"), - - /** - * Default right ascension units. - */ - RAUNIT(HduType.PRIMARY_EXTENSION, ValueType.STRING, "Right ascension unit"), - - /** - * CCD readout noise in rms electrons. This is the most current estimate. - */ - RDNOISE(HduType.EXTENSION, ValueType.REAL, "Readout noise"), - - /** - * Amplifier unbinned pixel read time. - */ - READTIME(HduType.PRIMARY_EXTENSION, ValueType.REAL, "Unbinned pixel read time"), - - /** - * Archive identification. This may be the same as the observation identification. - */ - RECNO(HduType.PRIMARY, ValueType.STRING, "Archive identification"), - - /** - * Seeing estimates specified as the stellar full-width at half-maximum in arc seconds. There may be more than one - * estimate. The times of the estimates are given by the SEEMJDn keyword. - */ - SEEING(HduType.PRIMARY, ValueType.REAL, "FWHM"), - - /** - * Seeing estimates specified as the stellar full-width at half-maximum in arc seconds. There may be more than one - * estimate. The times of the estimates are given by the SEEMJDn keyword. - */ - SEEINGn(HduType.PRIMARY, ValueType.REAL, "FWHM"), - - /** - * Times for the seeing estimates given as modified Julian dates. - */ - SEEMJD(HduType.PRIMARY, ValueType.REAL, "MJD for seeing estimate"), - - /** - * Times for the seeing estimates given as modified Julian dates. - */ - SEEMJDn(HduType.PRIMARY, ValueType.REAL, "MJD for seeing estimate"), - - /** - * Exposure time of the nth subexposure. If all subexposures are the same length then only the first keyword, SEXP, - * is needed. For charge shuffling the subexposure time is the total time for each charge shuffled exposure. There - * is no finer division of the exposure times. Comments would be used to describe the subexposures of each charge - * shuffled subexposure. - */ - SEXP(HduType.PRIMARY_EXTENSION, ValueType.REAL, "Subexposure time"), - - /** - * Exposure time of the nth subexposure. If all subexposures are the same length then only the first keyword, SEXP, - * is needed. For charge shuffling the subexposure time is the total time for each charge shuffled exposure. There - * is no finer division of the exposure times. Comments would be used to describe the subexposures of each charge - * shuffled subexposure. - */ - SEXPnnn(HduType.PRIMARY_EXTENSION, ValueType.REAL, "Subexposure time"), - - /** - * Time for the shutter to close fully. - */ - SHUTCLOS(HduType.PRIMARY, ValueType.REAL, "Shutter close time"), - - /** - * Shutter identification and hardware version. - */ - SHUTHWV(HduType.PRIMARY, ValueType.STRING, "Shutter hardware version"), - - /** - * Time for the shutter to open fully. - */ - SHUTOPEN(HduType.PRIMARY, ValueType.REAL, "Shutter open time"), - - /** - * Shutter status. - */ - SHUTSTAT(HduType.PRIMARY, ValueType.STRING, "Shutter status"), - - /** - * Shutter software version. - */ - SHUTSWV(HduType.PRIMARY, ValueType.STRING, "Shutter software version"), - - /** - * Slit or mask hole identification for the aperture(s). The string consists of a number, an object type number - * (0=sky, 1=object, etc.), the right ascension and declination, and the object name or title. declination, and the - * object name or title. This can replace OBJNAME, APRA/OBJRA, and APDEC/OBJDEC. - */ - SLIT(HduType.PRIMARY, ValueType.STRING, ""), - - /** - * Slit or mask hole identification for the aperture(s). The string consists of a number, an object type number - * (0=sky, 1=object, etc.), the right ascension and declination, and the object name or title. declination, and the - * object name or title. This can replace OBJNAME, APRA/OBJRA, and APDEC/OBJDEC. - */ - SLITnnn(HduType.PRIMARY, ValueType.STRING, ""), - - /** - * FWHM of the object spectrum profile on the detector. The width is in the units of the spatial world coordinate - * system. This may be approximate. It is particularly useful for specifying the profile width of fiber fed spectra. - */ - SPECFWHM(HduType.EXTENSION, ValueType.REAL, "FWHM of spectrum"), - - /** - * UTC of the start of each subexposure. - */ - SUT(HduType.PRIMARY_EXTENSION, ValueType.STRING, "UTC of subexposure start"), - - /** - * UTC of the start of each subexposure. - */ - SUTn(HduType.PRIMARY_EXTENSION, ValueType.STRING, "UTC of subexposure start"), - - /** - * FWHM of the object spectrum profile on the detector. The width is in the units of the spatial world coordinate - * system. This may be approximate. It is particularly useful for specifying the profile width of fiber fed spectra. - */ - SWIDnnn(HduType.EXTENSION, ValueType.REAL, "FWHM of spectrum"), - - /** - * Modified Julian date at the time of the altitude/azimuth keywords. - */ - TELAAMJD(HduType.PRIMARY, ValueType.REAL, "MJD at for alt/az"), - - /** - * Telescope pointing altitude at the time given by TELAAMJD. - */ - TELALT(HduType.PRIMARY, ValueType.STRING, "Telescope altitude"), - - /** - * Telescope pointing azimuth at the time given by TELAAMJD. - */ - TELAZ(HduType.PRIMARY, ValueType.STRING, "Telescope azimuth"), - - /** - * Telescope configuration. The configuration defines the mirrors, correctors, light paths, etc. - */ - TELCONF(HduType.PRIMARY, ValueType.STRING, "Telescope configuration"), - - /** - * Telescope pointing declination. - */ - TELDEC(HduType.PRIMARY, ValueType.STRING, "Telescope declination"), - - /** - * Declination unit. - */ - TELDECU(HduType.PRIMARY, ValueType.STRING, "Declination unit"), - - /** - * Telescope pointing coordinate epoch. - */ - TELEPOCH(HduType.PRIMARY, ValueType.REAL, "Telescope coordinate epoch"), - - /** - * Telescope pointing coordinate system equinox. A value before 1984 is Besselian otherwise it is Julian. - */ - TELEQUIN(HduType.PRIMARY, ValueType.REAL, "Telescope coordinate equinox"), - - /** - * Telescope focus value in available units. - */ - TELFOCUS(HduType.PRIMARY, ValueType.REAL, "Telescope focus"), - - /** - * Time of zenith distance and hour angle - */ - TELMJD(HduType.PRIMARY, ValueType.REAL, "Time of zenith distance and hour angle"), - - /** - * Times for the telescope sensor measurements given as modified Julian dates. - */ - TELMJDn(HduType.PRIMARY, ValueType.REAL, ""), - - /** - * Telescope position angle measurements in appropriate units. This could include altitude and azimuth measurements. - */ - TELPAN(HduType.PRIMARY, ValueType.REAL, ""), - - /** - * Telescope position angle measurements in appropriate units. This could include altitude and azimuth measurements. - */ - TELPANn(HduType.PRIMARY, ValueType.REAL, ""), - - /** - * Telescope linear position sensor measurements in appropriate units. - */ - TELPOS(HduType.PRIMARY, ValueType.REAL, ""), - - /** - * Telescope linear position sensor measurements in appropriate units. - */ - TELPOSn(HduType.PRIMARY, ValueType.REAL, ""), - - /** - * Telescope pressure sensor measurements in appropriate units. - */ - TELPRE(HduType.PRIMARY, ValueType.REAL, ""), - - /** - * Telescope pressure sensor measurements in appropriate units. - */ - TELPREn(HduType.PRIMARY, ValueType.REAL, ""), - - /** - * Telescope pointing right ascension. - */ - TELRA(HduType.PRIMARY, ValueType.STRING, "Telescope right ascension"), - - /** - * Telescope pointing coordinate system type. - */ - TELRADEC(HduType.PRIMARY, ValueType.STRING, "Telescope coordinate system"), - - /** - * Right ascension unit. - */ - TELRAU(HduType.PRIMARY, ValueType.STRING, "Right ascension unit"), - - /** - * Telescope status. - */ - TELSTAT(HduType.PRIMARY, ValueType.STRING, "Telescope status"), - - /** - * Telescope control system software version. - */ - TELTCS(HduType.PRIMARY, ValueType.STRING, "Telescope control system"), - - /** - * Telescope temperature sensor measurements in degrees Celsius. The comment string may be modified to indicate the - * location of the measurement. - */ - TELTEM(HduType.PRIMARY, ValueType.REAL, "Telescope temperature"), - - /** - * Telescope temperature sensor measurements in degrees Celsius. The comment string may be modified to indicate the - * location of the measurement. - */ - TELTEMn(HduType.PRIMARY, ValueType.REAL, "Telescope temperature"), - - /** - * Declination telescope tracking rate in arc seconds per second. - */ - TELTKDEC(HduType.PRIMARY, ValueType.REAL, "Tracking rate from siderial"), - - /** - * Right ascension telescope tracking rate from siderial in arc seconds per second. - */ - TELTKRA(HduType.PRIMARY, ValueType.REAL, "Tracking rate from siderial"), - - /** - * Telescope hardware version. - */ - TELVER(HduType.PRIMARY, ValueType.STRING, "Telescope version"), - - /** - * Telescope voltage sensor measurements in volts. - */ - TELVOL(HduType.PRIMARY, ValueType.REAL, ""), - - /** - * Telescope voltage sensor measurements in volts. - */ - TELVOLn(HduType.PRIMARY, ValueType.REAL, ""), - - /** - * Time of exposure end in the TSYSEND system. - */ - TIMEEND(HduType.PRIMARY_EXTENSION, ValueType.STRING, "Time of exposure end"), - - /** - * Time of header creation. - */ - TIMEHDR(HduType.PRIMARY_EXTENSION, ValueType.STRING, "Time of header creation"), - - /** - * Default time system. All times which do not have a "timesys" element associated with them in this dictionary - * default to this keyword. . - */ - TIMESYS(HduType.PRIMARY, ValueType.STRING, "Default time system"), - - /** - * Section of the recorded image to be kept after calibration processing. This is generally the part of the data - * section containing useful data. The section is in in binned pixels if binning is done. - */ - TRIMSEC(HduType.EXTENSION, ValueType.STRING, "Section of useful data"), - - /** - * Time system for the TIMEEND keyword. - */ - TSYSEND(HduType.PRIMARY_EXTENSION, ValueType.STRING, "Time system for TIMEEND"), - - /** - * Time system for the header creation keywords. - */ - TSYSHDR(HduType.PRIMARY_EXTENSION, ValueType.STRING, "Time system for header creation"), - - /** - * Time system for the TIME-OBS keyword. - */ - TSYSOBS(HduType.PRIMARY_EXTENSION, ValueType.STRING, "Time system for TIME-OBS"), - - /** - * TV name. - */ - TV(HduType.PRIMARY, ValueType.STRING, "TV"), - - /** - * TV filter names. This name is the astronomical standard name if applicable; i.e. U, B, Gunn I, etc. The filter - * type and filter device position are given by other keywords. - */ - TVFILTn(HduType.PRIMARY, ValueType.STRING, "Filter name"), - - /** - * Television focus value in available units. - */ - TVFOCn(HduType.PRIMARY, ValueType.REAL, "Television focus"), - - /** - * TV filter position given as filter wheel number or other filter system position measurement. - */ - TVFPOSn(HduType.PRIMARY, ValueType.REAL, "Filter system position"), - - /** - * TV filter type. This is the technical specification or observatory identification name. - */ - TVFTYPn(HduType.PRIMARY, ValueType.STRING, "Filter type"), - - /** - * TV identification and hardware version. - */ - TVHWV(HduType.PRIMARY, ValueType.STRING, "TV Hardware"), - - /** - * Times for the guider television sensor measurements given as modified Julian dates. - */ - TVMJDn(HduType.PRIMARY, ValueType.REAL, ""), - - /** - * TV name. - */ - TVn(HduType.PRIMARY, ValueType.STRING, "TV"), - - /** - * TV filter names. This name is the astronomical standard name if applicable; i.e. U, B, Gunn I, etc. The filter - * type and filter device position are given by other keywords. - */ - TVnFILTn(HduType.PRIMARY, ValueType.STRING, "Filter name"), - - /** - * Television focus value in available units. - */ - TVnFOCn(HduType.PRIMARY, ValueType.REAL, "Television focus"), - - /** - * TV filter position given as filter wheel number or other filter system position measurement. - */ - TVnFPOSn(HduType.PRIMARY, ValueType.REAL, "Filter system position"), - - /** - * TV filter type. This is the technical specification or observatory identification name. - */ - TVnFTYPn(HduType.PRIMARY, ValueType.STRING, "Filter type"), - - /** - * TV identification and hardware version. - */ - TVnHWV(HduType.PRIMARY, ValueType.STRING, "TV Hardware"), - - /** - * Times for the guider television sensor measurements given as modified Julian dates. - */ - TVnMJDn(HduType.PRIMARY, ValueType.REAL, ""), - - /** - * Television position angle measurements in appropriate units. - */ - TVnPANn(HduType.PRIMARY, ValueType.REAL, ""), - - /** - * Television linear position sensor measurements in appropriate units. - */ - TVnPOSn(HduType.PRIMARY, ValueType.REAL, "Television position ()"), - - /** - * Television pressure sensor measurements in appropriate units. - */ - TVnPREn(HduType.PRIMARY, ValueType.REAL, ""), - - /** - * TV status. - */ - TVnSTAT(HduType.PRIMARY, ValueType.STRING, ""), - - /** - * TV software version. - */ - TVnSWV(HduType.PRIMARY, ValueType.NONE, ""), - - /** - * Television temperature sensor measurements in degrees Celsius. - */ - TVnTEMn(HduType.PRIMARY, ValueType.REAL, ""), - - /** - * Television voltage sensor measurements in volts. - */ - TVnVOLn(HduType.PRIMARY, ValueType.REAL, ""), - - /** - * Television position angle measurements in appropriate units. - */ - TVPANn(HduType.PRIMARY, ValueType.REAL, ""), - - /** - * Television linear position sensor measurements in appropriate units. - */ - TVPOSn(HduType.PRIMARY, ValueType.REAL, "Television position ()"), - - /** - * Television pressure sensor measurements in appropriate units. - */ - TVPREn(HduType.PRIMARY, ValueType.REAL, ""), - - /** - * TV status. - */ - TVSTAT(HduType.PRIMARY, ValueType.STRING, ""), - - /** - * TV software version. - */ - TVSWV(HduType.PRIMARY, ValueType.NONE, ""), - - /** - * Television temperature sensor measurements in degrees Celsius. - */ - TVTEMn(HduType.PRIMARY, ValueType.REAL, ""), - - /** - * Television voltage sensor measurements in volts. - */ - TVVOLn(HduType.PRIMARY, ValueType.REAL, ""), - - /** - * Altitude unit. - */ - UNITALT(HduType.PRIMARY, ValueType.STRING, "Altitude unit"), - - /** - * Plane angle unit. - */ - UNITANG(HduType.PRIMARY, ValueType.STRING, "Plane angle unit"), - - /** - * Focal plane aperture size unit. - */ - UNITAP(HduType.PRIMARY, ValueType.STRING, "Aperture size unit"), - - /** - * Area unit. - */ - UNITAREA(HduType.PRIMARY, ValueType.STRING, "Area unit"), - - /** - * Azimuth unit. - */ - UNITAZ(HduType.PRIMARY, ValueType.STRING, "Azimuth unit"), - - /** - * Capacitance unit. - */ - UNITCAP(HduType.PRIMARY, ValueType.STRING, "Capacitance unit"), - - /** - * Charge unit. - */ - UNITCHAR(HduType.PRIMARY, ValueType.STRING, "Charge unit"), - - /** - * Conductance unit. - */ - UNITCOND(HduType.PRIMARY, ValueType.STRING, "Conductance unit"), - - /** - * Current unit. - */ - UNITCUR(HduType.PRIMARY, ValueType.STRING, "Current unit"), - - /** - * Delination unit. - */ - UNITDEC(HduType.PRIMARY, ValueType.STRING, "Declination unit"), - - /** - * Energy unit. - */ - UNITENER(HduType.PRIMARY, ValueType.STRING, "Energy unit"), - - /** - * Event unit. - */ - UNITEVNT(HduType.PRIMARY, ValueType.STRING, "Event unit"), - - /** - * Flux unit. - */ - UNITFLUX(HduType.PRIMARY, ValueType.STRING, "Flux unit"), - - /** - * Force unit. - */ - UNITFORC(HduType.PRIMARY, ValueType.STRING, "Force unit"), - - /** - * Frequency unit. - */ - UNITFREQ(HduType.PRIMARY, ValueType.STRING, "Frequency unit"), - - /** - * Time of day unit. - */ - UNITHOUR(HduType.PRIMARY, ValueType.STRING, "Time of day unit"), - - /** - * Illuminance unit. - */ - UNITILLU(HduType.PRIMARY, ValueType.STRING, "Illuminance unit"), - - /** - * Inductance unit. - */ - UNITINDU(HduType.PRIMARY, ValueType.STRING, "Inductance unit"), - - /** - * Latitude unit. - */ - UNITLAT(HduType.PRIMARY, ValueType.STRING, "Latitude unit"), - - /** - * Length unit. A wavelength unit is also provided so this unit is primarily used to instrumental descriptions. - */ - UNITLEN(HduType.PRIMARY, ValueType.STRING, "Length unit"), - - /** - * Luminous flux unit. - */ - UNITLFLX(HduType.PRIMARY, ValueType.STRING, "Luminous flux unit"), - - /** - * Luminous intensity unit. - */ - UNITLINT(HduType.PRIMARY, ValueType.STRING, "Luminous intensity unit"), - - /** - * Longitude unit. - */ - UNITLONG(HduType.PRIMARY, ValueType.STRING, "Longitude unit"), - - /** - * Mass unit. - */ - UNITMASS(HduType.PRIMARY, ValueType.STRING, "Mass unit"), - - /** - * Magnetic density unit. - */ - UNITMDEN(HduType.PRIMARY, ValueType.STRING, "Magnetic density unit"), - - /** - * Magnetic field unit. - */ - UNITMFLD(HduType.PRIMARY, ValueType.STRING, "Magnetic field unit"), - - /** - * Magnetic flux unit. - */ - UNITMFLX(HduType.PRIMARY, ValueType.STRING, "Magnetic flux unit"), - - /** - * Position angle unit. - */ - UNITPA(HduType.PRIMARY, ValueType.STRING, "Position angle unit"), - - /** - * Power unit. - */ - UNITPOW(HduType.PRIMARY, ValueType.STRING, "Wavelength unit"), - - /** - * Pressure unit. - */ - UNITPRES(HduType.PRIMARY, ValueType.STRING, "Pressure unit"), - - /** - * Right ascension unit. - */ - UNITRA(HduType.PRIMARY, ValueType.STRING, "Right ascension unit"), - - /** - * Celestial rate of motion. - */ - UNITRATE(HduType.PRIMARY, ValueType.STRING, "Celestial rate of motion"), - - /** - * Resistance unit. - */ - UNITRES(HduType.PRIMARY, ValueType.STRING, "Resistance unit"), - - /** - * Solid angle unit. - */ - UNITSANG(HduType.PRIMARY, ValueType.STRING, "Solid angle unit"), - - /** - * Celestial separation unit. - */ - UNITSEP(HduType.PRIMARY, ValueType.STRING, "Separation unit"), - - /** - * Temperature unit. - */ - UNITTEMP(HduType.PRIMARY, ValueType.STRING, "Temperature unit"), - - /** - * Time unit. - */ - UNITTIME(HduType.PRIMARY, ValueType.STRING, "Time unit"), - - /** - * Velocity unit. - */ - UNITVEL(HduType.PRIMARY, ValueType.STRING, "Velocity unit"), - - /** - * Voltage unit. - */ - UNITVOLT(HduType.PRIMARY, ValueType.STRING, "Voltage unit"), - - /** - * UTC time at the start of the exposure. - */ - UTC_OBS("UTC-OBS", HduType.PRIMARY_EXTENSION, ValueType.STRING, "UTC of exposure start"), - - /** - * UTC at the end of the exposure. - */ - UTCEND(HduType.PRIMARY_EXTENSION, ValueType.STRING, "UTC at end of exposure"), - - /** - * UTC of header creation. - */ - UTCHDR(HduType.PRIMARY_EXTENSION, ValueType.STRING, "UTC of header creation"), - - /** - * Default UTC time for the observation. This keyword is generally not used and is UTC-OBS keyword for the start of - * the exposure on the detector is used. - */ - UTCOBS(HduType.PRIMARY_EXTENSION, ValueType.STRING, "UTC of observation"), - - /** - * IRAF WCS attribute strings for all axes. These are defined by the IRAF WCS system. - */ - WAT_nnn(HduType.PRIMARY_EXTENSION, ValueType.STRING, ""), - - /** - * IRAF WCS attribute strings. These are defined by the IRAF WCS system. - */ - WATn_nnn(HduType.PRIMARY_EXTENSION, ValueType.STRING, ""), - - /** - * Descriptive string identifying the source of the astrometry used to derive the WCS. One example is the exposure - * used to derive a WCS apart from the reference coordinate. - */ - WCSAnnn(HduType.PRIMARY_EXTENSION, ValueType.STRING, "WCS Source"), - - /** - * Descriptive string identifying the source of the astrometry used to derive the WCS. One example is the exposure - * used to derive a WCS apart from the reference coordinate. - */ - WCSASTRM(HduType.PRIMARY_EXTENSION, ValueType.STRING, "WCS Source"), - - /** - * Dimensionality of the WCS physical system. In IRAF a WCS can have a higher dimensionality than the image. - */ - WCSDIM(HduType.PRIMARY_EXTENSION, ValueType.INTEGER, "WCS dimensionality"), - - /** - * Epoch of the coordinates used in the world coordinate system. - */ - WCSEnnn(HduType.PRIMARY_EXTENSION, ValueType.REAL, "WCS coordinate epoch"), - - /** - * Equinox when equatorial coordinates are used in the world coordinate system. A value before 1984 is Besselian - * otherwise it is Julian. - */ - WCSEPOCH(HduType.PRIMARY_EXTENSION, ValueType.REAL, "WCS coordinate epoch"), - - /** - * Coordinate system type when equatorial coordinates are used in the world coordinate system. - */ - WCSRADEC(HduType.PRIMARY_EXTENSION, ValueType.STRING, "WCS coordinate system"), - - /** - * Coordinate system type when equatorial coordinates are used in the world coordinate system. - */ - WCSRnnn(HduType.PRIMARY_EXTENSION, ValueType.STRING, "WCS coordinate system"), - - /** - * Weather condition description. Generally this would be either 'clear' or 'partly cloudy'. - */ - WEATHER(HduType.PRIMARY, ValueType.STRING, "Weather conditions"), - - /** - * Zenith distance of telescope pointing at TELMJD. - */ - ZD(HduType.PRIMARY, ValueType.REAL, "Zenith distance"), - - /** - * Modified Julian date at the start of the exposure. The fractional part of the date is given to better than a - * second of time. - */ - MJD_OBS("MJD-OBS", HduType.PRIMARY_EXTENSION, ValueType.REAL, "MJD of exposure start"), - - // SBIG. https://github.com/nom-tam-fits/nom-tam-fits/blob/master/src/main/java/nom/tam/fits/header/extra/SBFitsExt.java - - /** - * Aperture Area of the Telescope used in square millimeters. Note that we are specifying the area as well as the - * diameter because we want to be able to correct for any central obstruction. - */ - APTAREA(HduType.IMAGE, ValueType.REAL, "Aperture Area of the Telescope"), - - /** - * Aperture Diameter of the Telescope used in millimeters. - */ - APTDIA(HduType.IMAGE, ValueType.REAL, "Aperture Diameter of the Telescope"), - - /** - * Upon initial display of this image use this ADU level for the Black level. - */ - CBLACK(HduType.IMAGE, ValueType.INTEGER, "use this ADU level for the Black"), - - /** - * Temperature of CCD when exposure taken. - */ - CCD_TEMP("CCD-TEMP", HduType.IMAGE, ValueType.REAL, "Temperature of CCD"), - - /** - * Altitude in degrees of the center of the image in degrees. Format is the same as the OBJCTDEC keyword. - */ - CENTALT(HduType.IMAGE, ValueType.STRING, "Altitude of the center of the image"), - - /** - * Azimuth in degrees of the center of the image in degrees. Format is the same as the OBJCTDEC keyword. - */ - CENTAZ(HduType.IMAGE, ValueType.STRING, "Azimuth of the center of the image"), - - /** - * Upon initial display of this image use this ADU level as the White level. For the SBIG method of displaying - * images using Background and Range the following conversions would be used: Background = CBLACK Range = CWHITE - - * CBLACK. - */ - CWHITE(HduType.IMAGE, ValueType.INTEGER, "use this ADU level for the White"), - - /** - * Electronic gain in e-/ADU. - */ - EGAIN(HduType.IMAGE, ValueType.REAL, "Electronic gain in e-/ADU"), - /* - * Optional Keywords

The following Keywords are not defined in the FITS Standard but are defined in this - * Standard. They may or may not be included by AIP Software Packages adhering to this Standard. Any of these - * keywords read by an AIP Package must be preserved in files written.

- */ - /** - * Focal Length of the Telescope used in millimeters. - */ - FOCALLEN(HduType.IMAGE, ValueType.REAL, "Focal Length of the Telescope"), - - /** - * This indicates the type of image and should be one of the following: Light Frame Dark Frame Bias Frame Flat - * Field. - */ - IMAGETYP(HduType.IMAGE, ValueType.STRING, "type of image"), - - /** - * This is the Declination of the center of the image in degrees. The format for this is ‘+25 12 34.111’ (SDD MM - * SS.SSS) using a space as the separator. For the sign, North is + and South is -. - */ - OBJCTDEC(HduType.IMAGE, ValueType.STRING, "Declination of the center of the image"), - - /** - * This is the Right Ascension of the center of the image in hours, minutes and secon ds. The format for this is ’12 - * 24 23.123’ (HH MM SS.SSS) using a space as the separator. - */ - OBJCTRA(HduType.IMAGE, ValueType.STRING, "Right Ascension of the center of the image"), - - /** - * Add this ADU count to each pixel value to get to a zero - based ADU. For example in SBIG images we add 100 ADU to - * each pixel to stop underflow at Zero ADU from noise. We would set PEDESTAL to - 100 in this case. - */ - PEDESTAL(HduType.IMAGE, ValueType.INTEGER, "ADU count to each pixel value to get to a zero"), - - /** - * This string indicates the version of this standard that the image was created to ie ‘SBFITSEXT Version 1.0’. - */ - SBSTDVER(HduType.IMAGE, ValueType.STRING, "version of this standard"), - - /** - * This is the setpoint of the cooling in degrees C. If it is not specified the setpoint is assumed to be the - */ - SET_TEMP("SET-TEMP", HduType.IMAGE, ValueType.REAL, "setpoint of the cooling in degrees C"), - - /** - * Latitude of the imaging location in degrees. Format is the same as the OBJCTDEC key word. - */ - SITELAT(HduType.IMAGE, ValueType.STRING, "Latitude of the imaging location"), - - /** - * Longitude of the imaging location in degrees. Format is the same as the OBJCTDEC keyword. - */ - SITELONG(HduType.IMAGE, ValueType.STRING, "Longitude of the imaging location"), - - /** - * Number of images combined to make this image as in Track and Accumulate or Co - Added images. - */ - SNAPSHOT(HduType.IMAGE, ValueType.INTEGER, "Number of images combined"), - - /** - * This indicates the name and version of the Software that initially created this file ie ‘SBIGs CCDOps Version - * 5.10’. - */ - SWCREATE(HduType.IMAGE, ValueType.STRING, "created version of the Software"), - - /** - * This indicates the name and version of the Software that modified this file ie ‘SBIGs CCDOps Version 5.10’ and - * the re can be multiple copies of this keyword. Only add this keyword if you actually modified the image and we - * suggest placing this above the HISTORY keywords corresponding to the modifications made to the image. - */ - SWMODIFY(HduType.IMAGE, ValueType.STRING, "modified version of the Software"), - - /** - * If the image was auto-guided this is the exposure time in seconds of the tracker used to acquire this image. If - * this keyword is not present then the image was unguided or hand guided. - */ - TRAKTIME(HduType.IMAGE, ValueType.REAL, "exposure time in seconds of the tracker"), - - /** - * Binning factor in width. - */ - XBINNING(HduType.IMAGE, ValueType.INTEGER, "Binning factor in width"), - - /** - * Sub frame X position of upper left pixel relative to whole frame in binned pixel units. - */ - XORGSUBF(HduType.IMAGE, ValueType.INTEGER, "Sub frame X position"), - - /** - * Pixel width in microns (after binning). - */ - XPIXSZ(HduType.IMAGE, ValueType.REAL, "Pixel width in microns"), - - /** - * Binning factor in height. - */ - YBINNING(HduType.IMAGE, ValueType.INTEGER, "Binning factor in height"), - - /** - * Sub frame Y position of upper left pixel relative to whole frame in binned pixel units. - */ - YORGSUBF(HduType.IMAGE, ValueType.INTEGER, "Sub frame Y position"), - - /** - * Pixel height in microns (after binning). - */ - YPIXSZ(HduType.IMAGE, ValueType.REAL, "Pixel height in microns"), - - // Non-Standard. https://github.com/nom-tam-fits/nom-tam-fits/blob/master/src/main/java/nom/tam/fits/header/NonStandard.java - - /** - * The HIERARCH keyword, when followed by spaces in columns 9 and 10 of the FITS card image, indicates that the ESO - * HIERARCH keyword convention should be used to interpret the name and value of the keyword. The HIERARCH keyword - * formally has no value because it is not followed by an equals sign in column 9. Under the HIERARCH convention the - * actual name of the keyword begins in column 11 of the card image and is terminated by the equal sign ('=') - * character. The name can contain any number of characters as long as it fits within columns 11 and 80 of the card - * image and also leaves enough space for the equal sign separator and the value field. The name can contain any - * printable ASCII text character, including spaces and lower-case characters, except for the equal sign character - * which serves as the terminator of the name field. Leading and trailing spaces in the name field are not - * significant, but embedded spaces within the name are significant. The value field follows the equals sign and - * must conform to the syntax for a free-format value field as defined in the FITS Standard. The value field may be - * null, in which case it contains only space characters, otherwise it may contain either a character string - * enclosed in single quotes, the logical constant T or F, an integer number, a floating point number, a complex - * integer number, or a complex floating point number. The value field may be followed by an optional comment - * string. The comment field must be separated from the value field by a slash character ('/'). It is recommended - * that the slash character be preceeded and followed by a space character. Example: "HIERARCH Filter Wheel = 12 / - * filter position". In this example the logical name of the keyword is 'Filter Wheel' and the value is 12. - */ - HIERARCH(HduType.ANY, ValueType.NONE, "denotes the HIERARCH keyword convention"), - - /** - * The presence of this keyword with a value = T in an extension key indicates that the keywords contained in the - * primary key (except the FITS Mandatory keywords, and any COMMENT, HISTORY or 'blank' keywords) are to be - * inherited, or logically included in that extension key. - */ - INHERIT(HduType.EXTENSION, ValueType.LOGICAL, "denotes the INHERIT keyword convention"); - - private val header: FitsKeyword - - constructor(name: String, hduType: HduType, valueType: ValueType, comment: String) { - header = FitsKeywordItem(name, hduType, valueType, comment) - } - - constructor(hduType: HduType, valueType: ValueType, comment: String) { - header = FitsKeywordItem(name, hduType, valueType, comment) - } - - override val key - get() = header.key - - override val comment - get() = header.comment - - override val hduType - get() = header.hduType - - override val valueType - get() = header.valueType - - override fun n(vararg numbers: Int) = header.n(*numbers) - - companion object { - - @JvmStatic val NAXIS1 = NAXISn.n(1) - @JvmStatic val NAXIS2 = NAXISn.n(2) - @JvmStatic val NAXIS3 = NAXISn.n(3) - - @JvmStatic val CDELT1 = CDELTn.n(1) - @JvmStatic val CDELT2 = CDELTn.n(2) - - @JvmStatic val CROTA1 = CROTAn.n(1) - @JvmStatic val CROTA2 = CROTAn.n(2) - } -} diff --git a/nebulosa-fits/src/main/kotlin/nebulosa/fits/FitsPath.kt b/nebulosa-fits/src/main/kotlin/nebulosa/fits/FitsPath.kt index 6a7ca33fd..765b4dedc 100644 --- a/nebulosa-fits/src/main/kotlin/nebulosa/fits/FitsPath.kt +++ b/nebulosa-fits/src/main/kotlin/nebulosa/fits/FitsPath.kt @@ -6,7 +6,7 @@ import java.io.Closeable import java.io.File import java.nio.file.Path -class FitsPath(val path: Path) : Fits(), Closeable { +data class FitsPath(val path: Path) : Fits(), Closeable { private val source = path.seekableSource() private val sink = path.seekableSink() diff --git a/nebulosa-fits/src/main/kotlin/nebulosa/fits/HierarchKeyFormatter.kt b/nebulosa-fits/src/main/kotlin/nebulosa/fits/HierarchKeyFormatter.kt index a74dee47f..76941adef 100644 --- a/nebulosa-fits/src/main/kotlin/nebulosa/fits/HierarchKeyFormatter.kt +++ b/nebulosa-fits/src/main/kotlin/nebulosa/fits/HierarchKeyFormatter.kt @@ -8,8 +8,5 @@ interface HierarchKeyFormatter { val isCaseSensitive: Boolean - companion object { - - @JvmStatic var INSTANCE: HierarchKeyFormatter = StandardHierarchKeyFormatter.DEFAULT - } + companion object : HierarchKeyFormatter by StandardHierarchKeyFormatter.DEFAULT } diff --git a/nebulosa-fits/src/main/kotlin/nebulosa/fits/SeekableSourceImageData.kt b/nebulosa-fits/src/main/kotlin/nebulosa/fits/SeekableSourceImageData.kt index 2f2e8dd42..312f34871 100644 --- a/nebulosa-fits/src/main/kotlin/nebulosa/fits/SeekableSourceImageData.kt +++ b/nebulosa-fits/src/main/kotlin/nebulosa/fits/SeekableSourceImageData.kt @@ -18,7 +18,8 @@ internal data class SeekableSourceImageData( private val bitpix: Bitpix, ) : ImageData { - @JvmField internal val channelBlockSize = (numberOfPixels * bitpix.byteLength).toLong() + @JvmField internal val channelSizeInBytes = (numberOfPixels * bitpix.byteLength).toLong() + @JvmField internal val totalSizeInBytes = channelSizeInBytes * numberOfChannels override val red by lazy { readImage(ImageChannel.RED) } @@ -56,7 +57,7 @@ internal data class SeekableSourceImageData( } private fun readChannel(channel: ImageChannel): FloatArray { - val startIndex = channelBlockSize * channel.index + val startIndex = channelSizeInBytes * channel.index source.seek(position + startIndex) val data = FloatArray(numberOfPixels) @@ -91,8 +92,8 @@ internal data class SeekableSourceImageData( Buffer().use { buffer -> for (i in 0 until numberOfChannels) { - val startIndex = channelBlockSize * i - var bytesToWrite = channelBlockSize + val startIndex = channelSizeInBytes * i + var bytesToWrite = channelSizeInBytes source.seek(position + startIndex) diff --git a/nebulosa-fits/src/main/kotlin/nebulosa/fits/SeekableSourceImageHdu.kt b/nebulosa-fits/src/main/kotlin/nebulosa/fits/SeekableSourceImageHdu.kt deleted file mode 100644 index 20df3b51c..000000000 --- a/nebulosa-fits/src/main/kotlin/nebulosa/fits/SeekableSourceImageHdu.kt +++ /dev/null @@ -1,15 +0,0 @@ -package nebulosa.fits - -import nebulosa.image.format.ImageData -import nebulosa.image.format.ImageHdu -import nebulosa.image.format.ReadableHeader - -internal data class SeekableSourceImageHdu( - override val header: ReadableHeader, - override val data: ImageData, -) : ImageHdu { - - override val width = header.width - override val height = header.height - override val numberOfChannels = header.numberOfChannels -} diff --git a/nebulosa-fits/src/main/kotlin/nebulosa/fits/StandardHierarchKeyFormatter.kt b/nebulosa-fits/src/main/kotlin/nebulosa/fits/StandardHierarchKeyFormatter.kt index c974daffb..6773ca294 100644 --- a/nebulosa-fits/src/main/kotlin/nebulosa/fits/StandardHierarchKeyFormatter.kt +++ b/nebulosa-fits/src/main/kotlin/nebulosa/fits/StandardHierarchKeyFormatter.kt @@ -1,6 +1,6 @@ package nebulosa.fits -class StandardHierarchKeyFormatter(override val isCaseSensitive: Boolean) : HierarchKeyFormatter { +data class StandardHierarchKeyFormatter(override val isCaseSensitive: Boolean) : HierarchKeyFormatter { override fun format(key: String): String { // cfitsio specifies a required space before the '=', so let's play nice with it. diff --git a/nebulosa-fits/src/test/kotlin/FitsHeaderCardFormatterTest.kt b/nebulosa-fits/src/test/kotlin/FitsHeaderCardFormatterTest.kt new file mode 100644 index 000000000..54d099a1c --- /dev/null +++ b/nebulosa-fits/src/test/kotlin/FitsHeaderCardFormatterTest.kt @@ -0,0 +1,30 @@ +import io.kotest.core.spec.style.StringSpec +import io.kotest.matchers.shouldBe +import nebulosa.fits.FitsHeaderCard +import nebulosa.fits.FitsHeaderCardFormatter + +class FitsHeaderCardFormatterTest : StringSpec() { + + init { + "should format boolean value" { + val text = FitsHeaderCardFormatter.format(FitsHeaderCard.create("SIMPLE", true, "Boolean Type")) + text shouldBe "SIMPLE = T / Boolean Type " + } + "should format integer value" { + val text = FitsHeaderCardFormatter.format(FitsHeaderCard.create("NAXIS", 3, "Integer Type")) + text shouldBe "NAXIS = 3 / Integer Type " + } + "should format decimal value" { + val text = FitsHeaderCardFormatter.format(FitsHeaderCard.create("EXPOSURE", 150.0, "Decimal Type")) + text shouldBe "EXPOSURE= 150.0 / Decimal Type " + } + "should format text value" { + val text = FitsHeaderCardFormatter.format(FitsHeaderCard.create("INSTRUME", "Camera", "Text Type")) + text shouldBe "INSTRUME= 'Camera ' / Text Type " + } + "should format end key" { + val text = FitsHeaderCardFormatter.format(FitsHeaderCard.END) + text shouldBe "END " + } + } +} diff --git a/nebulosa-fits/src/test/kotlin/FitsHeaderCardParserTest.kt b/nebulosa-fits/src/test/kotlin/FitsHeaderCardParserTest.kt new file mode 100644 index 000000000..57ac0aabb --- /dev/null +++ b/nebulosa-fits/src/test/kotlin/FitsHeaderCardParserTest.kt @@ -0,0 +1,50 @@ +import io.kotest.core.spec.style.StringSpec +import io.kotest.matchers.shouldBe +import nebulosa.fits.FitsHeaderCardParser +import nebulosa.fits.FitsHeaderCardType + +class FitsHeaderCardParserTest : StringSpec() { + + init { + "should parse boolean value" { + val parsed = FitsHeaderCardParser("SIMPLE = T / Boolean Type ") + + parsed.key shouldBe "SIMPLE" + parsed.value shouldBe "T" + parsed.type shouldBe FitsHeaderCardType.BOOLEAN + parsed.comment shouldBe "Boolean Type" + } + "should parse integer value" { + val parsed = FitsHeaderCardParser("NAXIS = 3 / Integer Type ") + + parsed.key shouldBe "NAXIS" + parsed.value shouldBe "3" + parsed.type shouldBe FitsHeaderCardType.INTEGER + parsed.comment shouldBe "Integer Type" + } + "should parse decimal value" { + val parsed = FitsHeaderCardParser("EXPOSURE= 150.0 / Decimal Type ") + + parsed.key shouldBe "EXPOSURE" + parsed.value shouldBe "150.0" + parsed.type shouldBe FitsHeaderCardType.DECIMAL + parsed.comment shouldBe "Decimal Type" + } + "should parse text value" { + val parsed = FitsHeaderCardParser("INSTRUME= 'Camera ' / Text Type ") + + parsed.key shouldBe "INSTRUME" + parsed.value shouldBe "Camera" + parsed.type shouldBe FitsHeaderCardType.TEXT + parsed.comment shouldBe "Text Type" + } + "should parse end key" { + val parsed = FitsHeaderCardParser("END") + + parsed.key shouldBe "END" + parsed.value shouldBe "" + parsed.type shouldBe FitsHeaderCardType.NONE + parsed.comment shouldBe "" + } + } +} diff --git a/nebulosa-image/src/main/kotlin/nebulosa/image/Image.kt b/nebulosa-image/src/main/kotlin/nebulosa/image/Image.kt index 4f1ab7b0b..ce4d692c1 100644 --- a/nebulosa-image/src/main/kotlin/nebulosa/image/Image.kt +++ b/nebulosa-image/src/main/kotlin/nebulosa/image/Image.kt @@ -206,17 +206,17 @@ class Image internal constructor( } with(newHeader) { - add(FitsKeywordDictionary.NAXIS, 3) - add(FitsKeywordDictionary.NAXIS1, width) - add(FitsKeywordDictionary.NAXIS2, height) - add(FitsKeywordDictionary.NAXIS3, 3) + add(FitsKeyword.NAXIS, 3) + add(FitsKeyword.NAXIS1, width) + add(FitsKeyword.NAXIS2, height) + add(FitsKeyword.NAXIS3, 3) } return image } fun canLoad(hdu: ImageHdu, debayer: Boolean = true): Boolean { - return hdu.width == width && hdu.height == height && (isMono(hdu) || !debayer) == this.mono + return hdu.width == width && hdu.height == height && (isMono(hdu) || !debayer) == mono } fun canLoad(image: ImageRepresentation, debayer: Boolean = true): Boolean { @@ -247,19 +247,6 @@ class Image internal constructor( return ComponentColorModel(space, false, false, OPAQUE, DataBuffer.TYPE_BYTE) } - @JvmStatic - internal fun raster(width: Int, height: Int, mono: Boolean): WritableRaster { - val pixelStride = if (mono) 1 else 3 - val bandOffsets = if (mono) intArrayOf(0) else intArrayOf(0, 1, 2) - val sampleModel = PixelInterleavedSampleModel(DataBuffer.TYPE_BYTE, width, height, pixelStride, width * pixelStride, bandOffsets) - val size = width * height - - val buffer = if (mono) Float8bitsDataBuffer.mono(size) - else Float8bitsDataBuffer.rgb(size) - - return Raster.createWritableRaster(sampleModel, buffer, null) - } - @JvmStatic internal fun raster(width: Int, height: Int, mono: Boolean, red: FloatArray, green: FloatArray, blue: FloatArray): WritableRaster { val pixelStride = if (mono) 1 else 3 @@ -271,7 +258,7 @@ class Image internal constructor( @JvmStatic internal fun raster(hdu: ImageHdu, mono: Boolean): WritableRaster { - return raster(hdu.width, hdu.height, hdu.isMono || mono, hdu.data.red, hdu.data.green, hdu.data.blue) + return raster(hdu.width, hdu.height, isMono(hdu) || mono, hdu.data.red, hdu.data.green, hdu.data.blue) } @JvmStatic @@ -281,28 +268,31 @@ class Image internal constructor( @JvmStatic fun open(hdu: ImageHdu, debayer: Boolean = true): Image { - val mono = isMono(hdu) || !debayer - val image = Image(hdu.width, hdu.height, hdu.header, mono) - load(image, hdu, debayer) + val image = Image(hdu.width, hdu.height, isMono(hdu) || !debayer, hdu) + + if (image.mono && debayer) { + image.debayer() + } + return image } + private inline fun Image.debayer(bayer: CfaPattern? = CfaPattern.from(header)) { + if (bayer != null) { + Debayer(bayer).transform(this) + } + } + @JvmStatic private fun load(image: Image, hdu: ImageHdu, debayer: Boolean) { - require(image.width == hdu.width) - require(image.height == hdu.height) + hdu.data.red.copyInto(image.red) - if (image.mono || !debayer) { - hdu.data.red.copyInto(image.red) - } else { - hdu.data.red.copyInto(image.red) + if (!image.mono) { hdu.data.green.copyInto(image.green) hdu.data.blue.copyInto(image.blue) - val bayer = CfaPattern.from(image.header) - - if (bayer != null) { - Debayer(bayer).transform(image) + if (debayer) { + image.debayer() } } } @@ -354,15 +344,15 @@ class Image internal constructor( val mono = bufferedImage.type == TYPE_BYTE_GRAY || bufferedImage.type == TYPE_USHORT_GRAY - header.add(FitsKeywordDictionary.SIMPLE, true) - header.add(FitsKeywordDictionary.BITPIX, Bitpix.FLOAT.code) - header.add(FitsKeywordDictionary.NAXIS, if (mono) 2 else 3) - header.add(FitsKeywordDictionary.NAXISn.n(1), width) - header.add(FitsKeywordDictionary.NAXISn.n(2), height) - if (!mono) header.add(FitsKeywordDictionary.NAXISn.n(3), 3) - header.add(FitsKeywordDictionary.BSCALE, 1.0) - header.add(FitsKeywordDictionary.BZERO, 0.0) - header.add(FitsKeywordDictionary.EXTEND, true) + header.add(FitsKeyword.SIMPLE, true) + header.add(FitsKeyword.BITPIX, Bitpix.FLOAT.code) + header.add(FitsKeyword.NAXIS, if (mono) 2 else 3) + header.add(FitsKeyword.NAXISn.n(1), width) + header.add(FitsKeyword.NAXISn.n(2), height) + if (!mono) header.add(FitsKeyword.NAXISn.n(3), 3) + header.add(FitsKeyword.BSCALE, 1.0) + header.add(FitsKeyword.BZERO, 0.0) + header.add(FitsKeyword.EXTEND, true) val image = Image(width, height, header, mono) diff --git a/nebulosa-image/src/main/kotlin/nebulosa/image/algorithms/transformation/Grayscale.kt b/nebulosa-image/src/main/kotlin/nebulosa/image/algorithms/transformation/Grayscale.kt index 37615d79b..9d520f03e 100644 --- a/nebulosa-image/src/main/kotlin/nebulosa/image/algorithms/transformation/Grayscale.kt +++ b/nebulosa-image/src/main/kotlin/nebulosa/image/algorithms/transformation/Grayscale.kt @@ -1,7 +1,7 @@ package nebulosa.image.algorithms.transformation import nebulosa.fits.FitsHeader -import nebulosa.fits.FitsKeywordDictionary +import nebulosa.fits.FitsKeyword import nebulosa.image.Image import nebulosa.image.algorithms.TransformAlgorithm import kotlin.math.max @@ -17,8 +17,8 @@ data class Grayscale( if (source.mono) return source val newHeader = FitsHeader(source.header) - newHeader.add(FitsKeywordDictionary.NAXIS, 2) - newHeader.delete(FitsKeywordDictionary.NAXIS3) + newHeader.add(FitsKeyword.NAXIS, 2) + newHeader.delete(FitsKeyword.NAXIS3) val result = Image(source.width, source.height, newHeader, true) diff --git a/nebulosa-image/src/main/kotlin/nebulosa/image/algorithms/transformation/SubFrame.kt b/nebulosa-image/src/main/kotlin/nebulosa/image/algorithms/transformation/SubFrame.kt index 4a9e147b0..aec94be6e 100644 --- a/nebulosa-image/src/main/kotlin/nebulosa/image/algorithms/transformation/SubFrame.kt +++ b/nebulosa-image/src/main/kotlin/nebulosa/image/algorithms/transformation/SubFrame.kt @@ -1,7 +1,7 @@ package nebulosa.image.algorithms.transformation import nebulosa.fits.FitsHeader -import nebulosa.fits.FitsKeywordDictionary +import nebulosa.fits.FitsKeyword import nebulosa.image.Image import nebulosa.image.algorithms.TransformAlgorithm @@ -22,8 +22,8 @@ data class SubFrame( require(y + height <= source.height) { "subframe.height < source.height: ${y + height} > ${source.height}" } val newHeader = FitsHeader(source.header) - newHeader.add(FitsKeywordDictionary.NAXIS1, width) - newHeader.add(FitsKeywordDictionary.NAXIS2, height) + newHeader.add(FitsKeyword.NAXIS1, width) + newHeader.add(FitsKeyword.NAXIS2, height) val subframe = Image(width, height, newHeader, source.mono) var index = 0 diff --git a/nebulosa-image/src/test/kotlin/ComputationAlgorithmTest.kt b/nebulosa-image/src/test/kotlin/ComputationAlgorithmTest.kt index 00cc89ca9..1a1f8a244 100644 --- a/nebulosa-image/src/test/kotlin/ComputationAlgorithmTest.kt +++ b/nebulosa-image/src/test/kotlin/ComputationAlgorithmTest.kt @@ -2,6 +2,7 @@ import io.kotest.matchers.floats.plusOrMinus import io.kotest.matchers.floats.shouldBeExactly import io.kotest.matchers.ints.shouldBeExactly import io.kotest.matchers.shouldBe +import nebulosa.fits.fits import nebulosa.image.Image import nebulosa.image.ImageChannel import nebulosa.image.algorithms.computation.MedianAbsoluteDeviation @@ -12,11 +13,11 @@ class ComputationAlgorithmTest : FitsStringSpec() { init { "mono:median absolute deviation" { - val mImage = Image.open(NGC3344_MONO_F32_FITS) + val mImage = Image.open(NGC3344_MONO_F32_FITS_PATH.fits()) mImage.compute(MedianAbsoluteDeviation()) shouldBe (0.0862f plusOrMinus 1e-4f) } "mono:statistics" { - val mImage = Image.open(NGC3344_MONO_F32_FITS) + val mImage = Image.open(NGC3344_MONO_F32_FITS_PATH.fits()) val statistics = mImage.compute(Statistics.GRAY) statistics.count shouldBeExactly 65536 @@ -31,13 +32,13 @@ class ComputationAlgorithmTest : FitsStringSpec() { statistics.maximum shouldBeExactly 1f } "color:median absolute deviation" { - val cImage = Image.open(NGC3344_COLOR_F32_FITS) + val cImage = Image.open(NGC3344_COLOR_F32_FITS_PATH.fits()) cImage.compute(MedianAbsoluteDeviation(channel = ImageChannel.RED)) shouldBe (0.0823f plusOrMinus 1e-4f) cImage.compute(MedianAbsoluteDeviation(channel = ImageChannel.GREEN)) shouldBe (0.0745f plusOrMinus 1e-4f) cImage.compute(MedianAbsoluteDeviation(channel = ImageChannel.BLUE)) shouldBe (0.0705f plusOrMinus 1e-4f) } "color:statistics" { - val cImage = Image.open(NGC3344_COLOR_F32_FITS) + val cImage = Image.open(NGC3344_COLOR_F32_FITS_PATH.fits()) run { val statistics = cImage.compute(Statistics.RED) diff --git a/nebulosa-image/src/test/kotlin/TransformAlgorithmTest.kt b/nebulosa-image/src/test/kotlin/TransformAlgorithmTest.kt index 775b2770a..7824698a6 100644 --- a/nebulosa-image/src/test/kotlin/TransformAlgorithmTest.kt +++ b/nebulosa-image/src/test/kotlin/TransformAlgorithmTest.kt @@ -14,26 +14,26 @@ class TransformAlgorithmTest : FitsStringSpec() { init { "mono:raw" { - val mImage = Image.open(NGC3344_MONO_8_FITS) + val mImage = Image.open(NGC3344_MONO_8_FITS_PATH.fits()) mImage.save("mono-raw").second shouldBe "e17cfc29c3b343409cd8617b6913330e" } "mono:vertical flip" { - val mImage = Image.open(NGC3344_MONO_8_FITS) + val mImage = Image.open(NGC3344_MONO_8_FITS_PATH.fits()) mImage.transform(VerticalFlip) mImage.save("mono-vertical-flip").second shouldBe "262260dfe719726c0e7829a088279a21" } "mono:horizontal flip" { - val mImage = Image.open(NGC3344_MONO_8_FITS) + val mImage = Image.open(NGC3344_MONO_8_FITS_PATH.fits()) mImage.transform(HorizontalFlip) mImage.save("mono-horizontal-flip").second shouldBe "daf0f05db5de3750962f338527564b27" } "mono:vertical & horizontal flip" { - val mImage = Image.open(NGC3344_MONO_8_FITS) + val mImage = Image.open(NGC3344_MONO_8_FITS_PATH.fits()) mImage.transform(VerticalFlip, HorizontalFlip) mImage.save("mono-vertical-horizontal-flip").second shouldBe "3bc81f579a0e34ce9312c3b242209166" } "mono:subframe" { - val mImage = Image.open(NGC3344_MONO_8_FITS) + val mImage = Image.open(NGC3344_MONO_8_FITS_PATH.fits()) val nImage = mImage.transform(SubFrame(45, 70, 16, 16)) nImage.width shouldBeExactly 16 nImage.height shouldBeExactly 16 @@ -41,106 +41,106 @@ class TransformAlgorithmTest : FitsStringSpec() { nImage.save("mono-subframe").second shouldBe "4d9984e778f82dde10b9aeeee7a29fe0" } "mono:sharpen" { - val mImage = Image.open(NGC3344_MONO_8_FITS) + val mImage = Image.open(NGC3344_MONO_8_FITS_PATH.fits()) mImage.transform(Sharpen) mImage.save("mono-sharpen").second shouldBe "0b162242a4e673f6480b5206cf49ca50" } "mono:mean" { - val mImage = Image.open(NGC3344_MONO_8_FITS) + val mImage = Image.open(NGC3344_MONO_8_FITS_PATH.fits()) mImage.transform(Mean) mImage.save("mono-mean").second shouldBe "cf866292f657c379ae3965931dd8eeea" } "mono:invert" { - val mImage = Image.open(NGC3344_MONO_8_FITS) + val mImage = Image.open(NGC3344_MONO_8_FITS_PATH.fits()) mImage.transform(Invert) mImage.save("mono-invert").second shouldBe "6e94463bb5b9561de1f0ee0a154db53e" } "mono:emboss" { - val mImage = Image.open(NGC3344_MONO_8_FITS) + val mImage = Image.open(NGC3344_MONO_8_FITS_PATH.fits()) mImage.transform(Emboss) mImage.save("mono-emboss").second shouldBe "94a8ef5e4573e392d087cf10c905ba12" } "mono:edges" { - val mImage = Image.open(NGC3344_MONO_8_FITS) + val mImage = Image.open(NGC3344_MONO_8_FITS_PATH.fits()) mImage.transform(Edges) mImage.save("mono-edges").second shouldBe "27ccd5f5e6098d0cae27e7495e18dd72" } "mono:blur" { - val mImage = Image.open(NGC3344_MONO_8_FITS) + val mImage = Image.open(NGC3344_MONO_8_FITS_PATH.fits()) mImage.transform(Blur) mImage.save("mono-blur").second shouldBe "f2c5466dccf71b5c4bee86c5fbbb95fc" } "mono:gaussian blur" { - val mImage = Image.open(NGC3344_MONO_8_FITS) + val mImage = Image.open(NGC3344_MONO_8_FITS_PATH.fits()) mImage.transform(GaussianBlur(sigma = 5.0, size = 9)) mImage.save("mono-gaussian-blur").second shouldBe "69057b0c4461fb0d55b779da9e72fd69" } "mono:STF:midtone = 0.1, shadow = 0.0, highlight = 1.0" { - val mImage = Image.open(NGC3344_MONO_8_FITS) + val mImage = Image.open(NGC3344_MONO_8_FITS_PATH.fits()) mImage.transform(ScreenTransformFunction(0.1f)) mImage.save("mono-stf-01-00-10").second shouldBe "22c0bd985e70a01330722d912869d6ee" } "mono:STF:midtone = 0.9, shadow = 0.0, highlight = 1.0" { - val mImage = Image.open(NGC3344_MONO_8_FITS) + val mImage = Image.open(NGC3344_MONO_8_FITS_PATH.fits()) mImage.transform(ScreenTransformFunction(0.9f)) mImage.save("mono-stf-09-00-10").second shouldBe "553ccb7546dce3a8f742d5e8f7c58a3f" } "mono:STF:midtone = 0.1, shadow = 0.5, highlight = 1.0" { - val mImage = Image.open(NGC3344_MONO_8_FITS) + val mImage = Image.open(NGC3344_MONO_8_FITS_PATH.fits()) mImage.transform(ScreenTransformFunction(0.1f, shadow = 0.5f)) mImage.save("mono-stf-01-05-10").second shouldBe "f31db854fab72033dce2f8c572ec6783" } "mono:STF:midtone = 0.9, shadow = 0.5, highlight = 1.0" { - val mImage = Image.open(NGC3344_MONO_8_FITS) + val mImage = Image.open(NGC3344_MONO_8_FITS_PATH.fits()) mImage.transform(ScreenTransformFunction(0.9f, shadow = 0.5f)) mImage.save("mono-stf-09-05-10").second shouldBe "633b49c4a1dbb5ad8e6a9d74f330636d" } "mono:STF:midtone = 0.1, shadow = 0.0, highlight = 0.5" { - val mImage = Image.open(NGC3344_MONO_8_FITS) + val mImage = Image.open(NGC3344_MONO_8_FITS_PATH.fits()) mImage.transform(ScreenTransformFunction(0.1f, highlight = 0.5f)) mImage.save("mono-stf-01-00-05").second shouldBe "26036937eb3e5f99cd6129f709ce4b31" } "mono:STF:midtone = 0.9, shadow = 0.0, highlight = 0.5" { - val mImage = Image.open(NGC3344_MONO_8_FITS) + val mImage = Image.open(NGC3344_MONO_8_FITS_PATH.fits()) mImage.transform(ScreenTransformFunction(0.9f, highlight = 0.5f)) mImage.save("mono-stf-09-00-05").second shouldBe "e8f694dae666ac15ce2f8a169eb84024" } "mono:STF:midtone = 0.1, shadow = 0.4, highlight = 0.6" { - val mImage = Image.open(NGC3344_MONO_8_FITS) + val mImage = Image.open(NGC3344_MONO_8_FITS_PATH.fits()) mImage.transform(ScreenTransformFunction(0.1f, 0.4f, 0.6f)) mImage.save("mono-stf-01-04-06").second shouldBe "5226aba21669a24f985703b3e7220568" } "mono:STF:midtone = 0.9, shadow = 0.4, highlight = 0.6" { - val mImage = Image.open(NGC3344_MONO_8_FITS) + val mImage = Image.open(NGC3344_MONO_8_FITS_PATH.fits()) mImage.transform(ScreenTransformFunction(0.9f, 0.4f, 0.6f)) mImage.save("mono-stf-09-04-06").second shouldBe "c2acb25ef7be92a51f63e673ec9a850f" } "mono:auto STF" { - val mImage = Image.open(NGC3344_MONO_8_FITS) + val mImage = Image.open(NGC3344_MONO_8_FITS_PATH.fits()) mImage.transform(AutoScreenTransformFunction) mImage.save("mono-auto-stf").second shouldBe "e17cfc29c3b343409cd8617b6913330e" } "color:raw" { - val mImage = Image.open(NGC3344_COLOR_32_FITS) + val mImage = Image.open(NGC3344_COLOR_32_FITS_PATH.fits()) mImage.save("color-raw").second shouldBe "18fb83e240bc7a4cbafbc1aba2741db6" } "color:vertical flip" { - val mImage = Image.open(NGC3344_COLOR_32_FITS) + val mImage = Image.open(NGC3344_COLOR_32_FITS_PATH.fits()) mImage.transform(VerticalFlip) mImage.save("color-vertical-flip").second shouldBe "b717ecda5c5bba50cfa06304ef2bca88" } "color:horizontal flip" { - val mImage = Image.open(NGC3344_COLOR_32_FITS) + val mImage = Image.open(NGC3344_COLOR_32_FITS_PATH.fits()) mImage.transform(HorizontalFlip) mImage.save("color-horizontal-flip").second shouldBe "f70228600c77551473008ed4b9986439" } "color:vertical & horizontal flip" { - val mImage = Image.open(NGC3344_COLOR_32_FITS) + val mImage = Image.open(NGC3344_COLOR_32_FITS_PATH.fits()) mImage.transform(VerticalFlip, HorizontalFlip) mImage.save("color-vertical-horizontal-flip").second shouldBe "1237314044f20307b76203148af855e3" } "color:subframe" { - val mImage = Image.open(NGC3344_COLOR_32_FITS) + val mImage = Image.open(NGC3344_COLOR_32_FITS_PATH.fits()) val nImage = mImage.transform(SubFrame(45, 70, 16, 16)) nImage.width shouldBeExactly 16 nImage.height shouldBeExactly 16 @@ -148,122 +148,122 @@ class TransformAlgorithmTest : FitsStringSpec() { nImage.save("color-subframe").second shouldBe "282fc4fdf9142fcb4b18e1df1eef4caa" } "color:sharpen" { - val mImage = Image.open(NGC3344_COLOR_32_FITS) + val mImage = Image.open(NGC3344_COLOR_32_FITS_PATH.fits()) mImage.transform(Sharpen) mImage.save("color-sharpen").second shouldBe "e562282bdafdeba6ce88981bb9c3ba61" } "color:mean" { - val mImage = Image.open(NGC3344_COLOR_32_FITS) + val mImage = Image.open(NGC3344_COLOR_32_FITS_PATH.fits()) mImage.transform(Mean) mImage.save("color-mean").second shouldBe "a8380d928aaa756e202ba43bd3a2f207" } "color:invert" { - val mImage = Image.open(NGC3344_COLOR_32_FITS) + val mImage = Image.open(NGC3344_COLOR_32_FITS_PATH.fits()) mImage.transform(Invert) mImage.save("color-invert").second shouldBe "decad269ec26450aebeaf7546867b5f8" } "color:emboss" { - val mImage = Image.open(NGC3344_COLOR_32_FITS) + val mImage = Image.open(NGC3344_COLOR_32_FITS_PATH.fits()) mImage.transform(Emboss) mImage.save("color-emboss").second shouldBe "58d69250f1233055aa33f9ec7ca40af1" } "color:edges" { - val mImage = Image.open(NGC3344_COLOR_32_FITS) + val mImage = Image.open(NGC3344_COLOR_32_FITS_PATH.fits()) mImage.transform(Edges) mImage.save("color-edges").second shouldBe "091f2955740a8edcd2401dc416d19d51" } "color:blur" { - val mImage = Image.open(NGC3344_COLOR_32_FITS) + val mImage = Image.open(NGC3344_COLOR_32_FITS_PATH.fits()) mImage.transform(Blur) mImage.save("color-blur").second shouldBe "0fca440b763de5380fa29de736f3c792" } "color:gaussian blur" { - val mImage = Image.open(NGC3344_COLOR_32_FITS) + val mImage = Image.open(NGC3344_COLOR_32_FITS_PATH.fits()) mImage.transform(GaussianBlur(sigma = 5.0, size = 9)) mImage.save("color-gaussian-blur").second shouldBe "394d1a4f136f15c802dd73004c421d64" } "color:STF:midtone = 0.1, shadow = 0.0, highlight = 1.0" { - val mImage = Image.open(NGC3344_COLOR_32_FITS) + val mImage = Image.open(NGC3344_COLOR_32_FITS_PATH.fits()) mImage.transform(ScreenTransformFunction(0.1f)) mImage.save("color-stf-01-00-10").second shouldBe "e952bd263df6fd275b9a80aca554cb4b" } "color:STF:midtone = 0.9, shadow = 0.0, highlight = 1.0" { - val mImage = Image.open(NGC3344_COLOR_32_FITS) + val mImage = Image.open(NGC3344_COLOR_32_FITS_PATH.fits()) mImage.transform(ScreenTransformFunction(0.9f)) mImage.save("color-stf-09-00-10").second shouldBe "038809d7612018e2e5c19d5e1f551abd" } "color:STF:midtone = 0.1, shadow = 0.5, highlight = 1.0" { - val mImage = Image.open(NGC3344_COLOR_32_FITS) + val mImage = Image.open(NGC3344_COLOR_32_FITS_PATH.fits()) mImage.transform(ScreenTransformFunction(0.1f, shadow = 0.5f)) mImage.save("color-stf-01-05-10").second shouldBe "70e812260f56f8621002327575611f31" } "color:STF:midtone = 0.9, shadow = 0.5, highlight = 1.0" { - val mImage = Image.open(NGC3344_COLOR_32_FITS) + val mImage = Image.open(NGC3344_COLOR_32_FITS_PATH.fits()) mImage.transform(ScreenTransformFunction(0.9f, shadow = 0.5f)) mImage.save("color-stf-09-05-10").second shouldBe "6ca400f617f466a9eb02a3a6f2985d99" } "color:STF:midtone = 0.1, shadow = 0.0, highlight = 0.5" { - val mImage = Image.open(NGC3344_COLOR_32_FITS) + val mImage = Image.open(NGC3344_COLOR_32_FITS_PATH.fits()) mImage.transform(ScreenTransformFunction(0.1f, highlight = 0.5f)) mImage.save("color-stf-01-00-05").second shouldBe "3cd98ee9a8949d5100295acccd77010b" } "color:STF:midtone = 0.9, shadow = 0.0, highlight = 0.5" { - val mImage = Image.open(NGC3344_COLOR_32_FITS) + val mImage = Image.open(NGC3344_COLOR_32_FITS_PATH.fits()) mImage.transform(ScreenTransformFunction(0.9f, highlight = 0.5f)) mImage.save("color-stf-09-00-05").second shouldBe "2cfeffc88c893cc5883d8a2221f29b91" } "color:STF:midtone = 0.1, shadow = 0.4, highlight = 0.6" { - val mImage = Image.open(NGC3344_COLOR_32_FITS) + val mImage = Image.open(NGC3344_COLOR_32_FITS_PATH.fits()) mImage.transform(ScreenTransformFunction(0.1f, 0.4f, 0.6f)) mImage.save("color-stf-01-04-06").second shouldBe "532a07a1a166eb007c2e40651aec2097" } "color:STF:midtone = 0.9, shadow = 0.4, highlight = 0.6" { - val mImage = Image.open(NGC3344_COLOR_32_FITS) + val mImage = Image.open(NGC3344_COLOR_32_FITS_PATH.fits()) mImage.transform(ScreenTransformFunction(0.9f, 0.4f, 0.6f)) mImage.save("color-stf-09-04-06").second shouldBe "eb3d940d9fd2c8814e930715e89897c4" } "color:auto STF" { - val mImage = Image.open(NGC3344_COLOR_32_FITS) + val mImage = Image.open(NGC3344_COLOR_32_FITS_PATH.fits()) mImage.transform(AutoScreenTransformFunction) mImage.save("color-auto-stf").second shouldBe "a9c3657d8597b927607eb438e666d3a0" } "color:SCNR Maximum Mask" { - val mImage = Image.open(NGC3344_COLOR_32_FITS) + val mImage = Image.open(NGC3344_COLOR_32_FITS_PATH.fits()) mImage.transform(SubtractiveChromaticNoiseReduction(ImageChannel.RED, 1f, ProtectionMethod.MAXIMUM_MASK)) mImage.save("color-scnr-maximum-mask").second shouldBe "e7d2155e18ff1e3172f4e849ae983145" } "color:SCNR Additive Mask" { - val mImage = Image.open(NGC3344_COLOR_32_FITS) + val mImage = Image.open(NGC3344_COLOR_32_FITS_PATH.fits()) mImage.transform(SubtractiveChromaticNoiseReduction(ImageChannel.RED, 1f, ProtectionMethod.ADDITIVE_MASK)) mImage.save("color-scnr-additive-mask").second shouldBe "a458c44cedcda704de16d80053fd87eb" } "color:SCNR Average Neutral" { - val mImage = Image.open(NGC3344_COLOR_32_FITS) + val mImage = Image.open(NGC3344_COLOR_32_FITS_PATH.fits()) mImage.transform(SubtractiveChromaticNoiseReduction(ImageChannel.RED, 1f, ProtectionMethod.AVERAGE_NEUTRAL)) mImage.save("color-scnr-average-neutral").second shouldBe "e07345ffc4982a62301c95c76d3efb35" } "color:SCNR Maximum Neutral" { - val mImage = Image.open(NGC3344_COLOR_32_FITS) + val mImage = Image.open(NGC3344_COLOR_32_FITS_PATH.fits()) mImage.transform(SubtractiveChromaticNoiseReduction(ImageChannel.RED, 1f, ProtectionMethod.MAXIMUM_NEUTRAL)) mImage.save("color-scnr-maximum-neutral").second shouldBe "a1d4b04f57b001ba4a996bab0407fd7e" } "color:SCNR Minimum Neutral" { - val mImage = Image.open(NGC3344_COLOR_32_FITS) + val mImage = Image.open(NGC3344_COLOR_32_FITS_PATH.fits()) mImage.transform(SubtractiveChromaticNoiseReduction(ImageChannel.RED, 1f, ProtectionMethod.MINIMUM_NEUTRAL)) mImage.save("color-scnr-minimum-neutral").second shouldBe "8b7be57ff38da9c97b35d7888047c0f9" } "color:grayscale BT-709" { - val mImage = Image.open(NGC3344_COLOR_32_FITS) + val mImage = Image.open(NGC3344_COLOR_32_FITS_PATH.fits()) val nImage = mImage.transform(Grayscale.BT709) nImage.save("color-grayscale-bt709").second shouldBe "cab675aa35390a2d58cd48555d91054f" } "color:grayscale RMY" { - val mImage = Image.open(NGC3344_COLOR_32_FITS) + val mImage = Image.open(NGC3344_COLOR_32_FITS_PATH.fits()) val nImage = mImage.transform(Grayscale.RMY) nImage.save("color-grayscale-rmy").second shouldBe "e113627002a4178d1010a2f6246e325f" } "color:grayscale Y" { - val mImage = Image.open(NGC3344_COLOR_32_FITS) + val mImage = Image.open(NGC3344_COLOR_32_FITS_PATH.fits()) val nImage = mImage.transform(Grayscale.Y) nImage.save("color-grayscale-y").second shouldBe "24dd4a7e0fa9e4be34c53c924a78a940" } diff --git a/nebulosa-plate-solving/src/main/kotlin/nebulosa/plate/solving/PlateSolution.kt b/nebulosa-plate-solving/src/main/kotlin/nebulosa/plate/solving/PlateSolution.kt index 4e5c6231d..4c039bc89 100644 --- a/nebulosa-plate-solving/src/main/kotlin/nebulosa/plate/solving/PlateSolution.kt +++ b/nebulosa-plate-solving/src/main/kotlin/nebulosa/plate/solving/PlateSolution.kt @@ -1,7 +1,7 @@ package nebulosa.plate.solving import nebulosa.fits.FitsHeader -import nebulosa.fits.FitsKeywordDictionary +import nebulosa.fits.FitsKeyword import nebulosa.image.format.HeaderCard import nebulosa.image.format.ReadableHeader import nebulosa.log.loggerFor @@ -36,14 +36,14 @@ data class PlateSolution( @JvmStatic fun from(header: ReadableHeader): PlateSolution? { val (cd11, cd12, _, cd22) = header.computeCdMatrix() - val crota2 = header.getDoubleOrNull(FitsKeywordDictionary.CROTA2)?.deg ?: atan2(cd12, cd11).rad + val crota2 = header.getDoubleOrNull(FitsKeyword.CROTA2)?.deg ?: atan2(cd12, cd11).rad // https://danmoser.github.io/notes/gai_fits-imgs.html - val cdelt1 = header.getDoubleOrNull(FitsKeywordDictionary.CDELT1)?.deg ?: (cd11 / cos(crota2)).deg - val cdelt2 = header.getDoubleOrNull(FitsKeywordDictionary.CDELT2)?.deg ?: (cd22 / cos(crota2)).deg - val crval1 = header.getDoubleOrNull(FitsKeywordDictionary.CRVAL1)?.deg ?: return null - val crval2 = header.getDoubleOrNull(FitsKeywordDictionary.CRVAL2)?.deg ?: return null - val width = header.getIntOrNull(FitsKeywordDictionary.NAXIS1) ?: header.getInt("IMAGEW", 0) - val height = header.getIntOrNull(FitsKeywordDictionary.NAXIS2) ?: header.getInt("IMAGEH", 0) + val cdelt1 = header.getDoubleOrNull(FitsKeyword.CDELT1)?.deg ?: (cd11 / cos(crota2)).deg + val cdelt2 = header.getDoubleOrNull(FitsKeyword.CDELT2)?.deg ?: (cd22 / cos(crota2)).deg + val crval1 = header.getDoubleOrNull(FitsKeyword.CRVAL1)?.deg ?: return null + val crval2 = header.getDoubleOrNull(FitsKeyword.CRVAL2)?.deg ?: return null + val width = header.getIntOrNull(FitsKeyword.NAXIS1) ?: header.getInt("IMAGEW", 0) + val height = header.getIntOrNull(FitsKeyword.NAXIS2) ?: header.getInt("IMAGEH", 0) LOG.info( "solution from {}: ORIE={}, SCALE={}, RA={}, DEC={}", diff --git a/nebulosa-test/src/main/kotlin/nebulosa/test/FitsStringSpec.kt b/nebulosa-test/src/main/kotlin/nebulosa/test/FitsStringSpec.kt index d0de7282b..e724c54b0 100644 --- a/nebulosa-test/src/main/kotlin/nebulosa/test/FitsStringSpec.kt +++ b/nebulosa-test/src/main/kotlin/nebulosa/test/FitsStringSpec.kt @@ -56,17 +56,6 @@ abstract class FitsStringSpec : StringSpec() { protected val NGC3344_MONO_F32_FITS_PATH by lazy { download("NGC3344.Mono.F32.fits", GITHUB_FITS_URL) } protected val NGC3344_MONO_F64_FITS_PATH by lazy { download("NGC3344.Mono.F64.fits", GITHUB_FITS_URL) } - protected val NGC3344_COLOR_8_FITS by lazy { NGC3344_COLOR_8_FITS_PATH.fits() } - protected val NGC3344_COLOR_16_FITS by lazy { NGC3344_COLOR_16_FITS_PATH.fits() } - protected val NGC3344_COLOR_32_FITS by lazy { NGC3344_COLOR_32_FITS_PATH.fits() } - protected val NGC3344_COLOR_F32_FITS by lazy { NGC3344_COLOR_F32_FITS_PATH.fits() } - protected val NGC3344_COLOR_F64_FITS by lazy { NGC3344_COLOR_F64_FITS_PATH.fits() } - protected val NGC3344_MONO_8_FITS by lazy { NGC3344_MONO_8_FITS_PATH.fits() } - protected val NGC3344_MONO_16_FITS by lazy { NGC3344_MONO_16_FITS_PATH.fits() } - protected val NGC3344_MONO_32_FITS by lazy { NGC3344_MONO_32_FITS_PATH.fits() } - protected val NGC3344_MONO_F32_FITS by lazy { NGC3344_MONO_F32_FITS_PATH.fits() } - protected val NGC3344_MONO_F64_FITS by lazy { NGC3344_MONO_F64_FITS_PATH.fits() } - protected val M6707HH by lazyFITS("M6707HH.fits", ASTROPY_PHOTOMETRY_URL) protected val STAR_FOCUS_1 by lazyFITS("STAR.FOCUS.1.fits") diff --git a/nebulosa-watney/src/main/kotlin/nebulosa/watney/plate/solving/WatneyPlateSolver.kt b/nebulosa-watney/src/main/kotlin/nebulosa/watney/plate/solving/WatneyPlateSolver.kt index 474d14f1e..46d2c6524 100644 --- a/nebulosa-watney/src/main/kotlin/nebulosa/watney/plate/solving/WatneyPlateSolver.kt +++ b/nebulosa-watney/src/main/kotlin/nebulosa/watney/plate/solving/WatneyPlateSolver.kt @@ -3,7 +3,7 @@ package nebulosa.watney.plate.solving import nebulosa.common.concurrency.cancel.CancellationToken import nebulosa.erfa.SphericalCoordinate import nebulosa.fits.FitsHeader -import nebulosa.fits.FitsKeywordDictionary +import nebulosa.fits.FitsKeyword import nebulosa.fits.fits import nebulosa.image.Image import nebulosa.log.debug @@ -391,18 +391,18 @@ data class WatneyPlateSolver( val parity = if (sign < 0) Parity.NORMAL else Parity.FLIPPED val header = FitsHeader() - header.add(FitsKeywordDictionary.CDELT1, cdelt1) - header.add(FitsKeywordDictionary.CDELT2, cdelt2) - header.add(FitsKeywordDictionary.CROTA1, crota1.toDegrees) - header.add(FitsKeywordDictionary.CROTA2, crota2.toDegrees) - header.add(FitsKeywordDictionary.CRVAL1, scopeCoordsRA.toDegrees) - header.add(FitsKeywordDictionary.CRVAL2, scopeCoordsDEC.toDegrees) - header.add(FitsKeywordDictionary.CRPIX1, scopePxX) - header.add(FitsKeywordDictionary.CRPIX2, scopePxY) - header.add(FitsKeywordDictionary.CD1_1, cd11) - header.add(FitsKeywordDictionary.CD1_2, cd12) - header.add(FitsKeywordDictionary.CD1_1, cd11) - header.add(FitsKeywordDictionary.CD2_2, cd22) + header.add(FitsKeyword.CDELT1, cdelt1) + header.add(FitsKeyword.CDELT2, cdelt2) + header.add(FitsKeyword.CROTA1, crota1.toDegrees) + header.add(FitsKeyword.CROTA2, crota2.toDegrees) + header.add(FitsKeyword.CRVAL1, scopeCoordsRA.toDegrees) + header.add(FitsKeyword.CRVAL2, scopeCoordsDEC.toDegrees) + header.add(FitsKeyword.CRPIX1, scopePxX) + header.add(FitsKeyword.CRPIX2, scopePxY) + header.add(FitsKeyword.CD1_1, cd11) + header.add(FitsKeyword.CD1_2, cd12) + header.add(FitsKeyword.CD1_1, cd11) + header.add(FitsKeyword.CD2_2, cd22) return ComputedPlateSolution( header, crota1, pixScale, scopeCoordsRA, scopeCoordsDEC, diff --git a/nebulosa-wcs/src/main/kotlin/nebulosa/wcs/WCSUtil.kt b/nebulosa-wcs/src/main/kotlin/nebulosa/wcs/WCSUtil.kt index 0aa01de3f..f02dda5ec 100644 --- a/nebulosa-wcs/src/main/kotlin/nebulosa/wcs/WCSUtil.kt +++ b/nebulosa-wcs/src/main/kotlin/nebulosa/wcs/WCSUtil.kt @@ -1,6 +1,6 @@ package nebulosa.wcs -import nebulosa.fits.FitsKeywordDictionary +import nebulosa.fits.FitsKeyword import nebulosa.image.format.ReadableHeader import nebulosa.math.Angle import nebulosa.math.cos @@ -18,9 +18,9 @@ fun ReadableHeader.computeCdMatrix(): DoubleArray { return if (hasCd) { doubleArrayOf(cd(1, 1), cd(1, 2), cd(2, 1), cd(2, 2)) } else { - val a = getDouble(FitsKeywordDictionary.CDELT1, 0.0) - val b = getDouble(FitsKeywordDictionary.CDELT2, 0.0) - val c = getDouble(FitsKeywordDictionary.CROTA2, 0.0).deg + val a = getDouble(FitsKeyword.CDELT1, 0.0) + val b = getDouble(FitsKeyword.CDELT2, 0.0) + val c = getDouble(FitsKeyword.CROTA2, 0.0).deg computeCdFromCdelt(a, b, c) } } diff --git a/nebulosa-xisf/src/main/kotlin/nebulosa/xisf/XisfMonolithicFileHeaderImageData.kt b/nebulosa-xisf/src/main/kotlin/nebulosa/xisf/XisfMonolithicFileHeaderImageData.kt index 6128dfe3c..89203ae55 100644 --- a/nebulosa-xisf/src/main/kotlin/nebulosa/xisf/XisfMonolithicFileHeaderImageData.kt +++ b/nebulosa-xisf/src/main/kotlin/nebulosa/xisf/XisfMonolithicFileHeaderImageData.kt @@ -15,14 +15,9 @@ internal data class XisfMonolithicFileHeaderImageData( private val source: SeekableSource, ) : ImageData { - override val width - get() = image.width - - override val height - get() = image.height - - override val numberOfChannels - get() = image.numberOfChannels + override val width = image.width + override val height = image.height + override val numberOfChannels = image.numberOfChannels init { val uncompressedSize = image.compressionFormat?.uncompressedSize ?: image.size @@ -126,9 +121,9 @@ internal data class XisfMonolithicFileHeaderImageData( private fun readNormal(channel: ImageChannel): FloatArray { source.seek(image.position) - val pixelBlockSizeInBytes = numberOfChannels * image.sampleFormat.byteLength + val blockSizeInBytes = numberOfChannels * image.sampleFormat.byteLength val bytesToSkipBefore = channel.index * image.sampleFormat.byteLength - val bytesToSkipAfter = pixelBlockSizeInBytes - bytesToSkipBefore - image.sampleFormat.byteLength + val bytesToSkipAfter = blockSizeInBytes - bytesToSkipBefore - image.sampleFormat.byteLength val data = FloatArray(numberOfPixels) var remainingPixels = data.size var pos = 0 @@ -136,7 +131,7 @@ internal data class XisfMonolithicFileHeaderImageData( Buffer().use { buffer -> while (remainingPixels > 0) { val n = min(PIXEL_COUNT, remainingPixels) - val byteCount = n * pixelBlockSizeInBytes + val byteCount = n * blockSizeInBytes check(source.read(buffer, byteCount) == byteCount) diff --git a/nebulosa-xisf/src/main/kotlin/nebulosa/xisf/XisfMonolithicFileHeaderImageHdu.kt b/nebulosa-xisf/src/main/kotlin/nebulosa/xisf/XisfMonolithicFileHeaderImageHdu.kt index f238183bc..8f2e910ed 100644 --- a/nebulosa-xisf/src/main/kotlin/nebulosa/xisf/XisfMonolithicFileHeaderImageHdu.kt +++ b/nebulosa-xisf/src/main/kotlin/nebulosa/xisf/XisfMonolithicFileHeaderImageHdu.kt @@ -9,16 +9,9 @@ internal data class XisfMonolithicFileHeaderImageHdu( private val source: SeekableSource, ) : ImageHdu { - override val width - get() = image.width - - override val height - get() = image.height - - override val numberOfChannels - get() = image.numberOfChannels - + override val width = image.width + override val height = image.height + override val numberOfChannels = image.numberOfChannels override val header = FitsHeader(image.keywords) - override val data = XisfMonolithicFileHeaderImageData(image, source) } diff --git a/nebulosa-xisf/src/main/kotlin/nebulosa/xisf/XisfPath.kt b/nebulosa-xisf/src/main/kotlin/nebulosa/xisf/XisfPath.kt index 1ec8dadfa..2581951c1 100644 --- a/nebulosa-xisf/src/main/kotlin/nebulosa/xisf/XisfPath.kt +++ b/nebulosa-xisf/src/main/kotlin/nebulosa/xisf/XisfPath.kt @@ -6,7 +6,7 @@ import java.io.Closeable import java.io.File import java.nio.file.Path -class XisfPath(val path: Path) : Xisf(), Closeable { +data class XisfPath(val path: Path) : Xisf(), Closeable { private val source = path.seekableSource() private val sink = path.seekableSink() From eae5f79dfd3364fcd9b24c6c321c715bc9af954d Mon Sep 17 00:00:00 2001 From: tiagohm Date: Wed, 27 Mar 2024 00:37:51 -0300 Subject: [PATCH 05/15] [api]: Fix unit tests --- GitHub CI.run.xml | 2 +- nebulosa-fits/src/test/kotlin/FitsReadTest.kt | 21 +-- .../src/test/kotlin/FitsWriteTest.kt | 2 +- .../src/main/kotlin/nebulosa/image/Image.kt | 8 +- .../src/test/kotlin/TransformAlgorithmTest.kt | 7 +- .../main/kotlin/nebulosa/io/ByteArraySink.kt | 2 +- .../kotlin/nebulosa/io/ByteArraySource.kt | 2 +- .../main/kotlin/nebulosa/io/ByteBufferSink.kt | 14 +- .../kotlin/nebulosa/io/ByteBufferSource.kt | 14 +- nebulosa-io/src/main/kotlin/nebulosa/io/Io.kt | 8 +- .../nebulosa/io/RandomAccessFileSink.kt | 1 - .../nebulosa/io/RandomAccessFileSource.kt | 3 +- .../src/test/kotlin/BufferedByteArrayTest.kt | 150 +++++++++--------- .../src/test/kotlin/BufferedByteBufferTest.kt | 128 +++++++++++++++ .../kotlin/BufferedRandomAccessFileTest.kt | 130 +++++++-------- .../test/kotlin/BufferedRandomSourceTest.kt | 2 +- .../src/test/kotlin/BufferedStringSpec.kt | 32 ++++ nebulosa-io/src/test/kotlin/Util.kt | 8 - .../src/test/kotlin/FixedStarTest.kt | 2 +- .../SmallBodyCloseApprochServiceTest.kt | 3 +- .../src/test/kotlin/SimbadServiceTest.kt | 3 + .../kotlin/nebulosa/test/FitsStringSpec.kt | 2 + .../src/test/kotlin/WatneyStarDetectorTest.kt | 3 +- 23 files changed, 355 insertions(+), 192 deletions(-) create mode 100644 nebulosa-io/src/test/kotlin/BufferedByteBufferTest.kt create mode 100644 nebulosa-io/src/test/kotlin/BufferedStringSpec.kt delete mode 100644 nebulosa-io/src/test/kotlin/Util.kt diff --git a/GitHub CI.run.xml b/GitHub CI.run.xml index 3442b30e6..d6fb113ef 100644 --- a/GitHub CI.run.xml +++ b/GitHub CI.run.xml @@ -10,7 +10,7 @@ diff --git a/nebulosa-fits/src/test/kotlin/FitsReadTest.kt b/nebulosa-fits/src/test/kotlin/FitsReadTest.kt index e82dd6143..6ae8b3ec1 100644 --- a/nebulosa-fits/src/test/kotlin/FitsReadTest.kt +++ b/nebulosa-fits/src/test/kotlin/FitsReadTest.kt @@ -2,6 +2,7 @@ import io.kotest.matchers.ints.shouldBeExactly import io.kotest.matchers.shouldBe import nebulosa.fits.Bitpix import nebulosa.fits.bitpix +import nebulosa.fits.fits import nebulosa.image.format.ImageHdu import nebulosa.test.FitsStringSpec @@ -9,70 +10,70 @@ class FitsReadTest : FitsStringSpec() { init { "mono:8-bit" { - val hdu = NGC3344_MONO_8_FITS.filterIsInstance().first() + val hdu = NGC3344_MONO_8_FITS_PATH.fits().filterIsInstance().first() hdu.width shouldBeExactly 256 hdu.height shouldBeExactly 256 hdu.numberOfChannels shouldBeExactly 1 hdu.header.bitpix shouldBe Bitpix.BYTE } "mono:16-bit" { - val hdu = NGC3344_MONO_16_FITS.filterIsInstance().first() + val hdu = NGC3344_MONO_16_FITS_PATH.fits().filterIsInstance().first() hdu.width shouldBeExactly 256 hdu.height shouldBeExactly 256 hdu.numberOfChannels shouldBeExactly 1 hdu.header.bitpix shouldBe Bitpix.SHORT } "mono:32-bit" { - val hdu = NGC3344_MONO_32_FITS.filterIsInstance().first() + val hdu = NGC3344_MONO_32_FITS_PATH.fits().filterIsInstance().first() hdu.width shouldBeExactly 256 hdu.height shouldBeExactly 256 hdu.numberOfChannels shouldBeExactly 1 hdu.header.bitpix shouldBe Bitpix.INTEGER } "mono:32-bit floating-point" { - val hdu = NGC3344_MONO_F32_FITS.filterIsInstance().first() + val hdu = NGC3344_MONO_F32_FITS_PATH.fits().filterIsInstance().first() hdu.width shouldBeExactly 256 hdu.height shouldBeExactly 256 hdu.numberOfChannels shouldBeExactly 1 hdu.header.bitpix shouldBe Bitpix.FLOAT } "mono:64-bit floating-point" { - val hdu = NGC3344_MONO_F64_FITS.filterIsInstance().first() + val hdu = NGC3344_MONO_F64_FITS_PATH.fits().filterIsInstance().first() hdu.width shouldBeExactly 256 hdu.height shouldBeExactly 256 hdu.numberOfChannels shouldBeExactly 1 hdu.header.bitpix shouldBe Bitpix.DOUBLE } "color:8-bit" { - val hdu = NGC3344_COLOR_8_FITS.filterIsInstance().first() + val hdu = NGC3344_COLOR_8_FITS_PATH.fits().filterIsInstance().first() hdu.width shouldBeExactly 256 hdu.height shouldBeExactly 256 hdu.numberOfChannels shouldBeExactly 4 hdu.header.bitpix shouldBe Bitpix.BYTE } "color:16-bit" { - val hdu = NGC3344_COLOR_16_FITS.filterIsInstance().first() + val hdu = NGC3344_COLOR_16_FITS_PATH.fits().filterIsInstance().first() hdu.width shouldBeExactly 256 hdu.height shouldBeExactly 256 hdu.numberOfChannels shouldBeExactly 4 hdu.header.bitpix shouldBe Bitpix.SHORT } "color:32-bit" { - val hdu = NGC3344_COLOR_32_FITS.filterIsInstance().first() + val hdu = NGC3344_COLOR_32_FITS_PATH.fits().filterIsInstance().first() hdu.width shouldBeExactly 256 hdu.height shouldBeExactly 256 hdu.numberOfChannels shouldBeExactly 4 hdu.header.bitpix shouldBe Bitpix.INTEGER } "color:32-bit floating-point" { - val hdu = NGC3344_COLOR_F32_FITS.filterIsInstance().first() + val hdu = NGC3344_COLOR_F32_FITS_PATH.fits().filterIsInstance().first() hdu.width shouldBeExactly 256 hdu.height shouldBeExactly 256 hdu.numberOfChannels shouldBeExactly 4 hdu.header.bitpix shouldBe Bitpix.FLOAT } "color:64-bit floating-point" { - val hdu = NGC3344_COLOR_F64_FITS.filterIsInstance().first() + val hdu = NGC3344_COLOR_F64_FITS_PATH.fits().filterIsInstance().first() hdu.width shouldBeExactly 256 hdu.height shouldBeExactly 256 hdu.numberOfChannels shouldBeExactly 4 diff --git a/nebulosa-fits/src/test/kotlin/FitsWriteTest.kt b/nebulosa-fits/src/test/kotlin/FitsWriteTest.kt index d555bcee8..fd975c448 100644 --- a/nebulosa-fits/src/test/kotlin/FitsWriteTest.kt +++ b/nebulosa-fits/src/test/kotlin/FitsWriteTest.kt @@ -11,7 +11,7 @@ class FitsWriteTest : FitsStringSpec() { init { "mono" { - val hdu0 = NGC3344_MONO_8_FITS.filterIsInstance().first() + val hdu0 = NGC3344_MONO_8_FITS_PATH.fits().filterIsInstance().first() val data = ByteArray(69120) FitsFormat.write(data.sink(), listOf(hdu0)) data.toByteString(2880, 66240).md5().hex() shouldBe "e1735e21c94dc49885fabc429406e573" diff --git a/nebulosa-image/src/main/kotlin/nebulosa/image/Image.kt b/nebulosa-image/src/main/kotlin/nebulosa/image/Image.kt index ce4d692c1..cbe6c9027 100644 --- a/nebulosa-image/src/main/kotlin/nebulosa/image/Image.kt +++ b/nebulosa-image/src/main/kotlin/nebulosa/image/Image.kt @@ -258,7 +258,11 @@ class Image internal constructor( @JvmStatic internal fun raster(hdu: ImageHdu, mono: Boolean): WritableRaster { - return raster(hdu.width, hdu.height, isMono(hdu) || mono, hdu.data.red, hdu.data.green, hdu.data.blue) + return if (mono || hdu.data.numberOfChannels >= 3) { + raster(hdu.width, hdu.height, mono, hdu.data.red, hdu.data.green, hdu.data.blue) + } else { + raster(hdu.width, hdu.height, false, hdu.data.red, FloatArray(hdu.data.numberOfPixels), FloatArray(hdu.data.numberOfPixels)) + } } @JvmStatic @@ -270,7 +274,7 @@ class Image internal constructor( fun open(hdu: ImageHdu, debayer: Boolean = true): Image { val image = Image(hdu.width, hdu.height, isMono(hdu) || !debayer, hdu) - if (image.mono && debayer) { + if (!image.mono && debayer) { image.debayer() } diff --git a/nebulosa-image/src/test/kotlin/TransformAlgorithmTest.kt b/nebulosa-image/src/test/kotlin/TransformAlgorithmTest.kt index 7824698a6..6a55cdc25 100644 --- a/nebulosa-image/src/test/kotlin/TransformAlgorithmTest.kt +++ b/nebulosa-image/src/test/kotlin/TransformAlgorithmTest.kt @@ -8,7 +8,6 @@ import nebulosa.image.ImageChannel import nebulosa.image.algorithms.transformation.* import nebulosa.image.algorithms.transformation.convolution.* import nebulosa.test.FitsStringSpec -import java.io.File class TransformAlgorithmTest : FitsStringSpec() { @@ -268,14 +267,12 @@ class TransformAlgorithmTest : FitsStringSpec() { nImage.save("color-grayscale-y").second shouldBe "24dd4a7e0fa9e4be34c53c924a78a940" } "color:debayer" { - val fits = File("src/test/resources/Debayer.fits").fits() - val mImage = Image.open(fits) + val mImage = Image.open(DEBAYER_FITS_PATH.fits()) val nImage = mImage.transform(AutoScreenTransformFunction) nImage.save("color-debayer").second shouldBe "86b5bdd67dfd6bbf5495afae4bf2bc04" } "color:no-debayer" { - val fits = File("src/test/resources/Debayer.fits").fits() - val mImage = Image.open(fits, false) + val mImage = Image.open(DEBAYER_FITS_PATH.fits(), false) val nImage = mImage.transform(AutoScreenTransformFunction) nImage.save("color-no-debayer").second shouldBe "958ccea020deec1f0c075042a9ba37c3" } diff --git a/nebulosa-io/src/main/kotlin/nebulosa/io/ByteArraySink.kt b/nebulosa-io/src/main/kotlin/nebulosa/io/ByteArraySink.kt index 3f21402a8..8419c146c 100644 --- a/nebulosa-io/src/main/kotlin/nebulosa/io/ByteArraySink.kt +++ b/nebulosa-io/src/main/kotlin/nebulosa/io/ByteArraySink.kt @@ -36,7 +36,7 @@ internal class ByteArraySink( override fun write(source: Buffer, byteCount: Long) { if (byteCount == 0L) return - if (exhausted) throw IllegalStateException("exhausted") + if (exhausted) throw EOFException("exhausted") var remaining = byteCount diff --git a/nebulosa-io/src/main/kotlin/nebulosa/io/ByteArraySource.kt b/nebulosa-io/src/main/kotlin/nebulosa/io/ByteArraySource.kt index 6c25cfe1b..cbcd2c4bd 100644 --- a/nebulosa-io/src/main/kotlin/nebulosa/io/ByteArraySource.kt +++ b/nebulosa-io/src/main/kotlin/nebulosa/io/ByteArraySource.kt @@ -33,7 +33,7 @@ internal class ByteArraySource( @Synchronized override fun read(sink: Buffer, byteCount: Long): Long { - if (exhausted) throw IllegalStateException("exhausted") + if (exhausted) return -1L return sink.readAndWriteUnsafe(cursor).use { timeout.throwIfReached() diff --git a/nebulosa-io/src/main/kotlin/nebulosa/io/ByteBufferSink.kt b/nebulosa-io/src/main/kotlin/nebulosa/io/ByteBufferSink.kt index f94ccdd58..308382ade 100644 --- a/nebulosa-io/src/main/kotlin/nebulosa/io/ByteBufferSink.kt +++ b/nebulosa-io/src/main/kotlin/nebulosa/io/ByteBufferSink.kt @@ -16,11 +16,8 @@ internal class ByteBufferSink( private val cursor = Buffer.UnsafeCursor() - override var position - get() = data.position().toLong() - private set(value) { - data.position(value.toInt()) - } + override var position = 0L + private set override val exhausted get() = position >= byteCount @@ -40,7 +37,7 @@ internal class ByteBufferSink( override fun write(source: Buffer, byteCount: Long) { if (byteCount == 0L) return - if (exhausted) throw IllegalStateException("exhausted") + if (exhausted) throw EOFException("exhausted") var remaining = byteCount @@ -52,9 +49,10 @@ internal class ByteBufferSink( val length = min(min(this.byteCount - position, it.remaining.toLong()), remaining) - if (length > 0) { - data.put(it.data!!, it.start, length.toInt()) + if (length > 0L) { + data.put(offset + position.toInt(), it.data!!, it.start, length.toInt()) remaining -= length + position += length source.skip(length) } else { throw EOFException("exhausted") diff --git a/nebulosa-io/src/main/kotlin/nebulosa/io/ByteBufferSource.kt b/nebulosa-io/src/main/kotlin/nebulosa/io/ByteBufferSource.kt index 00bd45f8e..7bea53969 100644 --- a/nebulosa-io/src/main/kotlin/nebulosa/io/ByteBufferSource.kt +++ b/nebulosa-io/src/main/kotlin/nebulosa/io/ByteBufferSource.kt @@ -15,11 +15,8 @@ internal class ByteBufferSource( private val cursor = Buffer.UnsafeCursor() - override var position - get() = data.position().toLong() - private set(value) { - data.position(value.toInt()) - } + override var position = 0L + private set override val exhausted get() = position >= byteCount @@ -37,7 +34,7 @@ internal class ByteBufferSource( @Synchronized override fun read(sink: Buffer, byteCount: Long): Long { - if (exhausted) throw IllegalStateException("exhausted") + if (exhausted) return -1L return sink.readAndWriteUnsafe(cursor).use { timeout.throwIfReached() @@ -45,10 +42,11 @@ internal class ByteBufferSource( val size = sink.size val length = min(min(this.byteCount - position, 8192L), byteCount) - if (length > 0) { + if (length > 0L) { it.expandBuffer(length.toInt()) - data.get(it.data!!, it.start, length.toInt()) + data.get(offset + position.toInt(), it.data!!, it.start, length.toInt()) it.resizeBuffer(size + length) + position += length length } else { it.resizeBuffer(size) diff --git a/nebulosa-io/src/main/kotlin/nebulosa/io/Io.kt b/nebulosa-io/src/main/kotlin/nebulosa/io/Io.kt index 73893ff4a..eb8f1c255 100644 --- a/nebulosa-io/src/main/kotlin/nebulosa/io/Io.kt +++ b/nebulosa-io/src/main/kotlin/nebulosa/io/Io.kt @@ -13,8 +13,6 @@ import java.nio.ByteBuffer import java.nio.file.Path import java.util.* -val EMPTY_BYTE_ARRAY = ByteArray(0) - inline fun BufferedSource.readSignedByte() = readByte().toInt() inline fun BufferedSource.readUnsignedByte() = readSignedByte() and 0xFF @@ -102,6 +100,12 @@ fun ByteArray.sink( timeout: Timeout = Timeout.NONE, ): SeekableSink = ByteArraySink(this, offset, byteCount, timeout) +fun ByteBuffer.sink( + offset: Int = 0, + byteCount: Int = capacity() - offset, + timeout: Timeout = Timeout.NONE, +): SeekableSink = ByteBufferSink(this, offset, byteCount, timeout) + fun ByteBuffer.source( offset: Int = 0, byteCount: Int = capacity() - offset, diff --git a/nebulosa-io/src/main/kotlin/nebulosa/io/RandomAccessFileSink.kt b/nebulosa-io/src/main/kotlin/nebulosa/io/RandomAccessFileSink.kt index cc30fa679..c5b0e018a 100644 --- a/nebulosa-io/src/main/kotlin/nebulosa/io/RandomAccessFileSink.kt +++ b/nebulosa-io/src/main/kotlin/nebulosa/io/RandomAccessFileSink.kt @@ -30,7 +30,6 @@ internal class RandomAccessFileSink( @Synchronized override fun write(source: Buffer, byteCount: Long) { if (!file.channel.isOpen) throw IllegalStateException("closed") - if (exhausted) throw IllegalStateException("exhausted") if (byteCount == 0L) return diff --git a/nebulosa-io/src/main/kotlin/nebulosa/io/RandomAccessFileSource.kt b/nebulosa-io/src/main/kotlin/nebulosa/io/RandomAccessFileSource.kt index 40f54ce37..b48f13913 100644 --- a/nebulosa-io/src/main/kotlin/nebulosa/io/RandomAccessFileSource.kt +++ b/nebulosa-io/src/main/kotlin/nebulosa/io/RandomAccessFileSource.kt @@ -31,7 +31,8 @@ internal class RandomAccessFileSource( @Synchronized override fun read(sink: Buffer, byteCount: Long): Long { if (!file.channel.isOpen) throw IllegalStateException("closed") - if (exhausted) throw IllegalStateException("exhausted") + + if (exhausted) return -1L return sink.readAndWriteUnsafe(cursor).use { timeout.throwIfReached() diff --git a/nebulosa-io/src/test/kotlin/BufferedByteArrayTest.kt b/nebulosa-io/src/test/kotlin/BufferedByteArrayTest.kt index a71ecf63f..ebad8478a 100644 --- a/nebulosa-io/src/test/kotlin/BufferedByteArrayTest.kt +++ b/nebulosa-io/src/test/kotlin/BufferedByteArrayTest.kt @@ -1,6 +1,5 @@ import io.kotest.assertions.throwables.shouldNotThrow import io.kotest.assertions.throwables.shouldThrow -import io.kotest.core.spec.style.StringSpec import io.kotest.matchers.booleans.shouldBeFalse import io.kotest.matchers.booleans.shouldBeTrue import io.kotest.matchers.doubles.shouldBeExactly @@ -13,112 +12,113 @@ import okio.buffer import okio.utf8Size import java.io.EOFException -class BufferedByteArrayTest : StringSpec() { +class BufferedByteArrayTest : BufferedStringSpec() { init { - val data = ByteArray(79) - - "write" { - val sink = data.sink() - - val buffer = sink.buffer() - buffer.writeByte(0xab) - buffer.writeShort(0xabcd) - buffer.writeShortLe(0x2143) - buffer.writeInt(-0x543210ff) - buffer.writeIntLe(-0x789abcdf) - buffer.writeLong(-0x543210fe789abcdfL) - buffer.writeLongLe(-0x350145414f4ea400L) - buffer.writeFloat(3.14f) - buffer.writeFloatLe(3.14f) - buffer.writeDouble(3.14) - buffer.writeDoubleLe(3.14) - buffer.writeUtf8("təˈranəˌsôr") - buffer.writeUtf8CodePoint("µ".codePointAt(0)) - buffer.writeString("c", charset = Charsets.UTF_32BE) - buffer.write(byteArrayOf(1, 2, 3)) - buffer.writeByte(0xf9) - buffer.flush() - } "read" { + val data = ByteArray(79) + data.sink().use { it.initialize() } + val source = data.source() - val buffer = source.buffer() - buffer.readUnsignedByte() shouldBeExactly 0xab - buffer.readShort().toInt() and 0xffff shouldBeExactly 0xabcd - buffer.readShortLe().toInt() and 0xffff shouldBeExactly 0x2143 - buffer.readInt() shouldBeExactly -0x543210ff - buffer.readIntLe() shouldBeExactly -0x789abcdf - buffer.readLong() shouldBeExactly -0x543210fe789abcdfL - buffer.readLongLe() shouldBeExactly -0x350145414f4ea400L - buffer.readFloat() shouldBeExactly 3.14f - buffer.readFloatLe() shouldBeExactly 3.14f - buffer.readDouble() shouldBeExactly 3.14 - buffer.readDoubleLe() shouldBeExactly 3.14 - buffer.readUtf8("təˈranəˌsôr".utf8Size()) shouldBe "təˈranəˌsôr" - buffer.readUtf8CodePoint() shouldBeExactly "µ".codePointAt(0) - buffer.readString(4, Charsets.UTF_32BE) shouldBe "c" - buffer.readByteArray(3) shouldBe byteArrayOf(1, 2, 3) - buffer.exhausted().shouldBeFalse() - buffer.readUnsignedByte() shouldBeExactly 0xf9 - buffer.exhausted().shouldBeTrue() + with(source.buffer()) { + readUnsignedByte() shouldBeExactly 0xAB + readShort().toInt() and 0xFFFF shouldBeExactly 0xABCD + readShortLe().toInt() and 0xFFFF shouldBeExactly 0x2143 + readInt() shouldBeExactly -0x543210FF + readIntLe() shouldBeExactly -0x789ABCDF + readLong() shouldBeExactly -0x543210FE789ABCDFL + readLongLe() shouldBeExactly -0x350145414F4EA400L + readFloat() shouldBeExactly 3.14F + readFloatLe() shouldBeExactly 3.14F + readDouble() shouldBeExactly 3.14 + readDoubleLe() shouldBeExactly 3.14 + readUtf8("təˈranəˌsôr".utf8Size()) shouldBe "təˈranəˌsôr" + readUtf8CodePoint() shouldBeExactly "µ".codePointAt(0) + readString(4, Charsets.UTF_32BE) shouldBe "c" + readByteArray(3) shouldBe byteArrayOf(1, 2, 3) + exhausted().shouldBeFalse() + readUnsignedByte() shouldBeExactly 0xF9 + exhausted().shouldBeTrue() + } } "seek and write" { + val data = ByteArray(79) val sink = data.sink() sink.seek(-1L) - val buffer = sink.buffer() - buffer.writeByte(0x44) - buffer.flush() + with(sink.buffer()) { + writeByte(0x44) + flush() + } } "skip and read" { + val data = ByteArray(79) + data.sink().use { it.initialize() } + val source = data.source() source.skip(78) - val buffer = source.buffer() - buffer.exhausted().shouldBeFalse() - buffer.readSignedByte() shouldBeExactly 0x44 - buffer.exhausted().shouldBeTrue() + with(source.buffer()) { + exhausted().shouldBeFalse() + readSignedByte() shouldBeExactly 0xF9.toByte().toInt() + exhausted().shouldBeTrue() + } } "seek and read" { + val data = ByteArray(79) + data.sink().use { it.initialize() } + val source = data.source() - source.seek(-1L) - val buffer = source.buffer() - buffer.exhausted().shouldBeFalse() - buffer.readSignedByte() shouldBeExactly 0x44 - buffer.exhausted().shouldBeTrue() + with(source.buffer()) { + source.seek(-1L) + exhausted().shouldBeFalse() + readSignedByte() shouldBeExactly 0xF9.toByte().toInt() + exhausted().shouldBeTrue() + + source.seek(37) + exhausted().shouldBeFalse() + readDouble() shouldBeExactly 3.14 + exhausted().shouldBeFalse() + } } "write with offset and byte count" { - val sink = data.sink(2, 8) + val data = ByteArray(79) + data.sink().use { it.initialize() } - val buffer = sink.buffer() - buffer.writeDouble(3.14) - shouldNotThrow { buffer.flush() } + val sink = data.sink(36, 8) - buffer.writeByte(0x10) - shouldThrow { buffer.flush() } + with(sink.buffer()) { + writeDouble(3.14) + shouldNotThrow { flush() } + + writeByte(0x10) + shouldThrow { flush() } + } } "read with offset and byte count" { - val source = data.source(2, 8) + val data = ByteArray(79) + data.sink().use { it.initialize() } - val buffer = source.buffer() - buffer.exhausted().shouldBeFalse() - buffer.readDouble() shouldBeExactly 3.14 - buffer.exhausted().shouldBeTrue() + val source = data.source(37, 8) + + with(source.buffer()) { + exhausted().shouldBeFalse() + readDouble() shouldBeExactly 3.14 + exhausted().shouldBeTrue() + } } "close emits buffered bytes" { - data.fill(0) + val data = ByteArray(79) { 1 } val sink = data.sink() + sink.buffer().use { it.writeByte(0x99) } - sink.buffer().use { - it.writeByte(0x99) + data.source().buffer().use { + it.readUnsignedByte() shouldBeExactly 0x99 + it.readUnsignedByte() shouldBeExactly 1 } - - val source = data.source() - val buffer = source.buffer() - buffer.readUnsignedByte() shouldBeExactly 0x99 } } } diff --git a/nebulosa-io/src/test/kotlin/BufferedByteBufferTest.kt b/nebulosa-io/src/test/kotlin/BufferedByteBufferTest.kt new file mode 100644 index 000000000..4846a8428 --- /dev/null +++ b/nebulosa-io/src/test/kotlin/BufferedByteBufferTest.kt @@ -0,0 +1,128 @@ +import io.kotest.assertions.throwables.shouldNotThrow +import io.kotest.assertions.throwables.shouldThrow +import io.kotest.matchers.booleans.shouldBeFalse +import io.kotest.matchers.booleans.shouldBeTrue +import io.kotest.matchers.doubles.shouldBeExactly +import io.kotest.matchers.floats.shouldBeExactly +import io.kotest.matchers.ints.shouldBeExactly +import io.kotest.matchers.longs.shouldBeExactly +import io.kotest.matchers.shouldBe +import nebulosa.io.* +import okio.buffer +import okio.utf8Size +import java.io.EOFException +import java.nio.ByteBuffer + +class BufferedByteBufferTest : BufferedStringSpec() { + + init { + "read" { + val data = ByteBuffer.allocate(79) + data.sink().use { it.initialize() } + + val source = data.source() + + with(source.buffer()) { + readUnsignedByte() shouldBeExactly 0xAB + readShort().toInt() and 0xFFFF shouldBeExactly 0XABCD + readShortLe().toInt() and 0xFFFF shouldBeExactly 0X2143 + readInt() shouldBeExactly -0x543210FF + readIntLe() shouldBeExactly -0x789ABCDF + readLong() shouldBeExactly -0x543210FE789ABCDFL + readLongLe() shouldBeExactly -0x350145414F4EA400L + readFloat() shouldBeExactly 3.14F + readFloatLe() shouldBeExactly 3.14F + readDouble() shouldBeExactly 3.14 + readDoubleLe() shouldBeExactly 3.14 + readUtf8("təˈranəˌsôr".utf8Size()) shouldBe "təˈranəˌsôr" + readUtf8CodePoint() shouldBeExactly "µ".codePointAt(0) + readString(4, Charsets.UTF_32BE) shouldBe "c" + readByteArray(3) shouldBe byteArrayOf(1, 2, 3) + exhausted().shouldBeFalse() + readUnsignedByte() shouldBeExactly 0xF9 + exhausted().shouldBeTrue() + } + } + "seek and write" { + val data = ByteBuffer.allocate(79) + + val sink = data.sink() + sink.initialize() + sink.seek(-1L) + + with(sink.buffer()) { + writeByte(0x44) + flush() + } + } + "skip and read" { + val data = ByteBuffer.allocate(79) + data.sink().use { it.initialize() } + + val source = data.source() + source.skip(78) + + with(source.buffer()) { + exhausted().shouldBeFalse() + readSignedByte() shouldBeExactly 0xF9.toByte().toInt() + exhausted().shouldBeTrue() + } + } + "seek and read" { + val data = ByteBuffer.allocate(79) + data.sink().use { it.initialize() } + + val source = data.source() + + with(source.buffer()) { + source.seek(-1L) + exhausted().shouldBeFalse() + readSignedByte() shouldBeExactly 0xF9.toByte().toInt() + exhausted().shouldBeTrue() + + source.seek(37) + exhausted().shouldBeFalse() + readDouble() shouldBeExactly 3.14 + exhausted().shouldBeFalse() + } + } + "write with offset and byte count" { + val data = ByteBuffer.allocate(79) + data.sink().use { it.initialize() } + + val sink = data.sink(2, 8) + + with(sink.buffer()) { + writeDouble(3.14) + shouldNotThrow { flush() } + + writeByte(0x10) + shouldThrow { flush() } + } + } + "read with offset and byte count" { + val data = ByteBuffer.allocate(79) + data.sink().use { it.initialize() } + + val source = data.source(37, 8) + + with(source.buffer()) { + exhausted().shouldBeFalse() + readDouble() shouldBeExactly 3.14 + exhausted().shouldBeTrue() + } + } + "close emits buffered bytes" { + val data = ByteBuffer.allocate(79) + repeat(data.capacity()) { data.put(1) } + + val sink = data.sink() + sink.buffer().use { it.writeByte(0x99) } + + data.source().buffer().use { + it.readUnsignedByte() shouldBeExactly 0x99 + it.readUnsignedByte() shouldBeExactly 1 + } + } + } +} diff --git a/nebulosa-io/src/test/kotlin/BufferedRandomAccessFileTest.kt b/nebulosa-io/src/test/kotlin/BufferedRandomAccessFileTest.kt index 8d2d680f9..f76506540 100644 --- a/nebulosa-io/src/test/kotlin/BufferedRandomAccessFileTest.kt +++ b/nebulosa-io/src/test/kotlin/BufferedRandomAccessFileTest.kt @@ -1,4 +1,4 @@ -import io.kotest.core.spec.style.StringSpec +import io.kotest.engine.spec.tempfile import io.kotest.matchers.booleans.shouldBeFalse import io.kotest.matchers.booleans.shouldBeTrue import io.kotest.matchers.doubles.shouldBeExactly @@ -9,95 +9,97 @@ import io.kotest.matchers.shouldBe import nebulosa.io.* import okio.buffer import okio.utf8Size +import java.io.File -class BufferedRandomAccessFileTest : StringSpec() { +class BufferedRandomAccessFileTest : BufferedStringSpec() { init { - val file = createFile() - - "write" { - val sink = file.seekableSink() - - val buffer = sink.buffer() - buffer.writeByte(0xab) - buffer.writeShort(0xabcd) - buffer.writeShortLe(0x2143) - buffer.writeInt(-0x543210ff) - buffer.writeIntLe(-0x789abcdf) - buffer.writeLong(-0x543210fe789abcdfL) - buffer.writeLongLe(-0x350145414f4ea400L) - buffer.writeFloat(3.14f) - buffer.writeFloatLe(3.14f) - buffer.writeDouble(3.14) - buffer.writeDoubleLe(3.14) - buffer.writeUtf8("təˈranəˌsôr") - buffer.writeUtf8CodePoint("µ".codePointAt(0)) - buffer.writeString("c", charset = Charsets.UTF_32BE) - buffer.write(byteArrayOf(1, 2, 3)) - buffer.writeByte(0xf9) - buffer.flush() - } "read" { + val file = makeFile() val source = file.seekableSource() - val buffer = source.buffer() - buffer.readUnsignedByte() shouldBeExactly 0xab - buffer.readShort().toInt() and 0xffff shouldBeExactly 0xabcd - buffer.readShortLe().toInt() and 0xffff shouldBeExactly 0x2143 - buffer.readInt() shouldBeExactly -0x543210ff - buffer.readIntLe() shouldBeExactly -0x789abcdf - buffer.readLong() shouldBeExactly -0x543210fe789abcdfL - buffer.readLongLe() shouldBeExactly -0x350145414f4ea400L - buffer.readFloat() shouldBeExactly 3.14f - buffer.readFloatLe() shouldBeExactly 3.14f - buffer.readDouble() shouldBeExactly 3.14 - buffer.readDoubleLe() shouldBeExactly 3.14 - buffer.readUtf8("təˈranəˌsôr".utf8Size()) shouldBe "təˈranəˌsôr" - buffer.readUtf8CodePoint() shouldBeExactly "µ".codePointAt(0) - buffer.readString(4, Charsets.UTF_32BE) shouldBe "c" - buffer.readByteArray(3) shouldBe byteArrayOf(1, 2, 3) - buffer.exhausted().shouldBeFalse() - buffer.readUnsignedByte() shouldBeExactly 0xf9 - buffer.exhausted().shouldBeTrue() + with(source.buffer()) { + readUnsignedByte() shouldBeExactly 0xab + readShort().toInt() and 0xffff shouldBeExactly 0xabcd + readShortLe().toInt() and 0xffff shouldBeExactly 0x2143 + readInt() shouldBeExactly -0x543210ff + readIntLe() shouldBeExactly -0x789abcdf + readLong() shouldBeExactly -0x543210fe789abcdfL + readLongLe() shouldBeExactly -0x350145414f4ea400L + readFloat() shouldBeExactly 3.14f + readFloatLe() shouldBeExactly 3.14f + readDouble() shouldBeExactly 3.14 + readDoubleLe() shouldBeExactly 3.14 + readUtf8("təˈranəˌsôr".utf8Size()) shouldBe "təˈranəˌsôr" + readUtf8CodePoint() shouldBeExactly "µ".codePointAt(0) + readString(4, Charsets.UTF_32BE) shouldBe "c" + readByteArray(3) shouldBe byteArrayOf(1, 2, 3) + exhausted().shouldBeFalse() + readUnsignedByte() shouldBeExactly 0xf9 + exhausted().shouldBeTrue() + } } "seek and write" { + val file = makeFile() val sink = file.seekableSink() sink.seek(-1L) - val buffer = sink.buffer() - buffer.writeByte(0x44) - buffer.flush() + with(sink.buffer()) { + writeByte(0x44) + flush() + } + + val source = file.seekableSource() + source.seek(-1L) + + with(source.buffer()) { + readByte().toInt() shouldBeExactly 0x44 + } } "skip and read" { + val file = makeFile() val source = file.seekableSource() source.skip(78) - val buffer = source.buffer() - buffer.exhausted().shouldBeFalse() - buffer.readSignedByte() shouldBeExactly 0x44 - buffer.exhausted().shouldBeTrue() + with(source.buffer()) { + exhausted().shouldBeFalse() + readSignedByte() shouldBeExactly 0xF9.toByte().toInt() + exhausted().shouldBeTrue() + } } "seek and read" { + val file = makeFile() val source = file.seekableSource() - source.seek(-1L) - val buffer = source.buffer() - buffer.exhausted().shouldBeFalse() - buffer.readSignedByte() shouldBeExactly 0x44 - buffer.exhausted().shouldBeTrue() + with(source.buffer()) { + source.seek(-1L) + exhausted().shouldBeFalse() + readSignedByte() shouldBeExactly 0xF9.toByte().toInt() + exhausted().shouldBeTrue() + + source.seek(37) + exhausted().shouldBeFalse() + readDouble() shouldBeExactly 3.14 + exhausted().shouldBeFalse() + } } "close emits buffered bytes" { - file.writeBytes(EMPTY_BYTE_ARRAY) + val file = makeFile() + file.writeBytes(ByteArray(79) { 1 }) val sink = file.seekableSink() + sink.buffer().use { it.writeByte(0x99) } - sink.buffer().use { - it.writeByte(0x99) + file.seekableSource().buffer().use { + it.readUnsignedByte() shouldBeExactly 0x99 + it.readUnsignedByte() shouldBeExactly 1 } - - val source = file.seekableSource() - val buffer = source.buffer() - buffer.readUnsignedByte() shouldBeExactly 0x99 } } + + private fun makeFile(): File { + val file = tempfile() + file.seekableSink().use { it.initialize() } + return file + } } diff --git a/nebulosa-io/src/test/kotlin/BufferedRandomSourceTest.kt b/nebulosa-io/src/test/kotlin/BufferedRandomSourceTest.kt index fb5cd4a89..b20e744cc 100644 --- a/nebulosa-io/src/test/kotlin/BufferedRandomSourceTest.kt +++ b/nebulosa-io/src/test/kotlin/BufferedRandomSourceTest.kt @@ -28,7 +28,7 @@ class BufferedRandomSourceTest : StringSpec() { val counter = IntArray(256) for (byte in this) { - counter[byte.toInt() and 0xff]++ + counter[byte.toInt() and 0xFF]++ } val average = counter.average() diff --git a/nebulosa-io/src/test/kotlin/BufferedStringSpec.kt b/nebulosa-io/src/test/kotlin/BufferedStringSpec.kt new file mode 100644 index 000000000..1f051417b --- /dev/null +++ b/nebulosa-io/src/test/kotlin/BufferedStringSpec.kt @@ -0,0 +1,32 @@ +import io.kotest.core.spec.style.StringSpec +import nebulosa.io.writeDouble +import nebulosa.io.writeDoubleLe +import nebulosa.io.writeFloat +import nebulosa.io.writeFloatLe +import okio.Sink +import okio.buffer + +abstract class BufferedStringSpec : StringSpec() { + + protected fun Sink.initialize() { + buffer().use { + it.writeByte(0xAB) + it.writeShort(0xABCD) + it.writeShortLe(0x2143) + it.writeInt(-0x543210FF) + it.writeIntLe(-0x789ABCDF) + it.writeLong(-0x543210FE789ABCDFL) + it.writeLongLe(-0x350145414F4EA400L) + it.writeFloat(3.14F) + it.writeFloatLe(3.14F) + it.writeDouble(3.14) + it.writeDoubleLe(3.14) + it.writeUtf8("təˈranəˌsôr") + it.writeUtf8CodePoint("µ".codePointAt(0)) + it.writeString("c", charset = Charsets.UTF_32BE) + it.write(byteArrayOf(1, 2, 3)) + it.writeByte(0xF9) + it.flush() + } + } +} diff --git a/nebulosa-io/src/test/kotlin/Util.kt b/nebulosa-io/src/test/kotlin/Util.kt deleted file mode 100644 index 9fd8175f5..000000000 --- a/nebulosa-io/src/test/kotlin/Util.kt +++ /dev/null @@ -1,8 +0,0 @@ -import java.io.File -import java.util.* - -internal fun createFile(): File { - val name = UUID.randomUUID().toString() - return File.createTempFile(name, ".dat") - .also { it.deleteOnExit() } -} diff --git a/nebulosa-nova/src/test/kotlin/FixedStarTest.kt b/nebulosa-nova/src/test/kotlin/FixedStarTest.kt index 73331aa14..4796e4084 100644 --- a/nebulosa-nova/src/test/kotlin/FixedStarTest.kt +++ b/nebulosa-nova/src/test/kotlin/FixedStarTest.kt @@ -36,7 +36,7 @@ class FixedStarTest : StringSpec() { with(ra.normalized.hms()) { truncate(this[0]) shouldBeExactly 3.0 truncate(this[1]) shouldBeExactly 2.0 - this[2] shouldBe (3.9 plusOrMinus 15.0) + this[2] shouldBe (3.9 plusOrMinus 20.0) } with(dec.dms()) { diff --git a/nebulosa-sbd/src/test/kotlin/SmallBodyCloseApprochServiceTest.kt b/nebulosa-sbd/src/test/kotlin/SmallBodyCloseApprochServiceTest.kt index 7fb3a2f17..b725a05ac 100644 --- a/nebulosa-sbd/src/test/kotlin/SmallBodyCloseApprochServiceTest.kt +++ b/nebulosa-sbd/src/test/kotlin/SmallBodyCloseApprochServiceTest.kt @@ -1,5 +1,6 @@ import io.kotest.core.spec.style.StringSpec import io.kotest.matchers.collections.shouldContainAll +import io.kotest.matchers.collections.shouldHaveAtLeastSize import io.kotest.matchers.collections.shouldHaveSize import io.kotest.matchers.doubles.plusOrMinus import io.kotest.matchers.ints.shouldBeGreaterThanOrEqual @@ -21,7 +22,7 @@ class SmallBodyCloseApprochServiceTest : StringSpec() { data.count shouldBeGreaterThanOrEqual 1 data.fields shouldHaveSize 14 - data.data shouldHaveSize 10 + data.data shouldHaveAtLeastSize 10 data.data[0][0] shouldBe "2024 EC3" data.data[0][3] shouldBe "2024-Mar-13 07:22" diff --git a/nebulosa-simbad/src/test/kotlin/SimbadServiceTest.kt b/nebulosa-simbad/src/test/kotlin/SimbadServiceTest.kt index 8cc87b702..23bde8e13 100644 --- a/nebulosa-simbad/src/test/kotlin/SimbadServiceTest.kt +++ b/nebulosa-simbad/src/test/kotlin/SimbadServiceTest.kt @@ -1,3 +1,4 @@ +import io.kotest.core.annotation.EnabledIf import io.kotest.core.spec.style.StringSpec import io.kotest.matchers.collections.shouldHaveAtLeastSize import io.kotest.matchers.nulls.shouldNotBeNull @@ -8,10 +9,12 @@ import nebulosa.math.arcmin import nebulosa.math.deg import nebulosa.math.hours import nebulosa.simbad.SimbadService +import nebulosa.test.NonGitHubOnlyCondition import okhttp3.OkHttpClient import okhttp3.logging.HttpLoggingInterceptor import java.util.concurrent.TimeUnit +@EnabledIf(NonGitHubOnlyCondition::class) class SimbadServiceTest : StringSpec() { init { diff --git a/nebulosa-test/src/main/kotlin/nebulosa/test/FitsStringSpec.kt b/nebulosa-test/src/main/kotlin/nebulosa/test/FitsStringSpec.kt index e724c54b0..6870e3335 100644 --- a/nebulosa-test/src/main/kotlin/nebulosa/test/FitsStringSpec.kt +++ b/nebulosa-test/src/main/kotlin/nebulosa/test/FitsStringSpec.kt @@ -44,6 +44,7 @@ abstract class FitsStringSpec : StringSpec() { protected val M82_COLOR_32_XISF by lazy { download("M82.Color.32.xisf", GITHUB_XISF_URL) } protected val M82_COLOR_F32_XISF by lazy { download("M82.Color.F32.xisf", GITHUB_XISF_URL) } protected val M82_COLOR_F64_XISF by lazy { download("M82.Color.F64.xisf", GITHUB_XISF_URL) } + protected val DEBAYER_XISF_PATH by lazy { download("Debayer.xisf", GITHUB_XISF_URL) } protected val NGC3344_COLOR_8_FITS_PATH by lazy { download("NGC3344.Color.8.fits", GITHUB_FITS_URL) } protected val NGC3344_COLOR_16_FITS_PATH by lazy { download("NGC3344.Color.16.fits", GITHUB_FITS_URL) } @@ -55,6 +56,7 @@ abstract class FitsStringSpec : StringSpec() { protected val NGC3344_MONO_32_FITS_PATH by lazy { download("NGC3344.Mono.32.fits", GITHUB_FITS_URL) } protected val NGC3344_MONO_F32_FITS_PATH by lazy { download("NGC3344.Mono.F32.fits", GITHUB_FITS_URL) } protected val NGC3344_MONO_F64_FITS_PATH by lazy { download("NGC3344.Mono.F64.fits", GITHUB_FITS_URL) } + protected val DEBAYER_FITS_PATH by lazy { download("Debayer.fits", GITHUB_FITS_URL) } protected val M6707HH by lazyFITS("M6707HH.fits", ASTROPY_PHOTOMETRY_URL) diff --git a/nebulosa-watney/src/test/kotlin/WatneyStarDetectorTest.kt b/nebulosa-watney/src/test/kotlin/WatneyStarDetectorTest.kt index 619473ceb..429519a39 100644 --- a/nebulosa-watney/src/test/kotlin/WatneyStarDetectorTest.kt +++ b/nebulosa-watney/src/test/kotlin/WatneyStarDetectorTest.kt @@ -1,5 +1,6 @@ import io.kotest.matchers.collections.shouldHaveSize import io.kotest.matchers.shouldBe +import nebulosa.fits.fits import nebulosa.image.Image import nebulosa.image.algorithms.transformation.Draw import nebulosa.image.algorithms.transformation.convolution.Mean @@ -16,7 +17,7 @@ class WatneyStarDetectorTest : FitsStringSpec() { val detector = WatneyStarDetector(computeHFD = true) "detect stars" { - var image = Image.open(NGC3344_COLOR_32_FITS) + var image = Image.open(NGC3344_COLOR_32_FITS_PATH.fits()) var stars = detector.detect(image.transform(Mean)) stars shouldHaveSize 1 image.transform(ImageStarsDraw(stars)).save("color-detected-stars-1") From 433849a7b4b89bacaa3541e2bcbc517c9dffb568 Mon Sep 17 00:00:00 2001 From: tiagohm Date: Wed, 27 Mar 2024 16:49:47 -0300 Subject: [PATCH 06/15] [api][desktop]: Implement XISF read/write --- api/build.gradle.kts | 1 + .../api/alignment/polar/darv/DARVJob.kt | 6 +- .../api/alignment/polar/tppa/TPPAStep.kt | 21 +++--- .../api/cameras/CameraCaptureEventHandler.kt | 10 +-- .../api/cameras/CameraCaptureListener.kt | 4 +- .../api/cameras/CameraExposureStep.kt | 39 +++++------ .../api/cameras/CameraLoopExposureStep.kt | 3 - .../api/cameras/CameraStartCaptureStep.kt | 3 - .../kotlin/nebulosa/api/image/ImageBucket.kt | 16 ++++- .../nebulosa/api/image/ImageController.kt | 2 +- .../kotlin/nebulosa/api/image/ImageService.kt | 2 +- .../api/wizard/flat/FlatWizardExecutor.kt | 4 +- .../nebulosa/api/wizard/flat/FlatWizardJob.kt | 4 +- .../api/wizard/flat/FlatWizardStep.kt | 37 +++++----- .../src/shared/services/electron.service.ts | 7 +- .../point/three/ThreePointPolarAlignment.kt | 15 ++--- .../alpaca/indi/device/cameras/ASCOMCamera.kt | 34 +++++----- .../nebulosa/fits/SeekableSourceImageData.kt | 15 +++-- .../src/test/kotlin/Hips2FitsServiceTest.kt | 3 + .../nebulosa/image/format/FloatImageData.kt | 12 +++- .../nebulosa/image/format/ImageChannel.kt | 9 ++- .../kotlin/nebulosa/image/format/ImageData.kt | 2 + .../src/main/kotlin/nebulosa/image/Image.kt | 42 ++++++------ .../kotlin/nebulosa/image/ImageChannel.kt | 13 ---- .../image/algorithms/computation/Histogram.kt | 2 +- .../image/algorithms/computation/Median.kt | 2 +- .../computation/MedianAbsoluteDeviation.kt | 2 +- .../algorithms/computation/Statistics.kt | 2 +- .../algorithms/transformation/CfaPattern.kt | 2 +- .../algorithms/transformation/Debayer.kt | 36 +++++----- .../algorithms/transformation/SigmaClip.kt | 2 +- .../SubtractiveChromaticNoiseReduction.kt | 10 +-- .../correction/BiasSubtraction.kt | 2 +- .../correction/DarkSubtraction.kt | 2 +- .../correction/FlatCorrection.kt | 2 +- .../test/kotlin/ComputationAlgorithmTest.kt | 2 +- .../src/test/kotlin/TransformAlgorithmTest.kt | 25 ++++++- nebulosa-indi-client/build.gradle.kts | 1 + .../indi/client/device/cameras/INDICamera.kt | 67 +++++++++++++------ .../indi/device/camera/CameraFrameCaptured.kt | 22 ++++-- nebulosa-io/src/main/kotlin/nebulosa/io/Io.kt | 2 +- .../nebulosa/plate/solving/PlateSolution.kt | 4 +- .../main/kotlin/nebulosa/xisf/XisfFormat.kt | 14 ++-- .../xisf/XisfMonolithicFileHeaderImageData.kt | 17 +++-- 44 files changed, 311 insertions(+), 211 deletions(-) delete mode 100644 nebulosa-image/src/main/kotlin/nebulosa/image/ImageChannel.kt diff --git a/api/build.gradle.kts b/api/build.gradle.kts index 9fe08451f..436cd039e 100644 --- a/api/build.gradle.kts +++ b/api/build.gradle.kts @@ -29,6 +29,7 @@ dependencies { implementation(project(":nebulosa-stellarium-protocol")) implementation(project(":nebulosa-watney")) implementation(project(":nebulosa-wcs")) + implementation(project(":nebulosa-xisf")) implementation(libs.apache.codec) implementation(libs.csv) implementation(libs.eventbus) diff --git a/api/src/main/kotlin/nebulosa/api/alignment/polar/darv/DARVJob.kt b/api/src/main/kotlin/nebulosa/api/alignment/polar/darv/DARVJob.kt index 04a268396..e034700f4 100644 --- a/api/src/main/kotlin/nebulosa/api/alignment/polar/darv/DARVJob.kt +++ b/api/src/main/kotlin/nebulosa/api/alignment/polar/darv/DARVJob.kt @@ -14,10 +14,12 @@ import nebulosa.batch.processing.ExecutionContext.Companion.getDouble import nebulosa.batch.processing.ExecutionContext.Companion.getDuration import nebulosa.batch.processing.delay.DelayStep import nebulosa.batch.processing.delay.DelayStepListener +import nebulosa.image.format.ImageRepresentation import nebulosa.indi.device.camera.Camera import nebulosa.indi.device.camera.FrameType import nebulosa.indi.device.guide.GuideOutput import java.nio.file.Files +import java.nio.file.Path import java.time.Duration data class DARVJob( @@ -65,8 +67,8 @@ data class DARVJob( onNext(DARVEvent.Finished(id)) } - override fun onExposureFinished(step: CameraExposureStep, stepExecution: StepExecution) { - onNext(CameraExposureFinished(stepExecution.jobExecution, step.camera, 1, 1, Duration.ZERO, 1.0, Duration.ZERO, step.savedPath!!)) + override fun onExposureFinished(step: CameraExposureStep, stepExecution: StepExecution, image: ImageRepresentation, savedPath: Path) { + onNext(CameraExposureFinished(stepExecution.jobExecution, step.camera, 1, 1, Duration.ZERO, 1.0, Duration.ZERO, savedPath)) } override fun onGuidePulseElapsed(step: GuidePulseStep, stepExecution: StepExecution) { diff --git a/api/src/main/kotlin/nebulosa/api/alignment/polar/tppa/TPPAStep.kt b/api/src/main/kotlin/nebulosa/api/alignment/polar/tppa/TPPAStep.kt index b2d43157c..e22f178be 100644 --- a/api/src/main/kotlin/nebulosa/api/alignment/polar/tppa/TPPAStep.kt +++ b/api/src/main/kotlin/nebulosa/api/alignment/polar/tppa/TPPAStep.kt @@ -12,8 +12,7 @@ import nebulosa.batch.processing.StepExecution import nebulosa.batch.processing.StepResult import nebulosa.common.concurrency.latch.Pauseable import nebulosa.common.time.Stopwatch -import nebulosa.fits.fits -import nebulosa.image.Image +import nebulosa.image.format.ImageRepresentation import nebulosa.indi.device.camera.Camera import nebulosa.indi.device.mount.Mount import nebulosa.log.debug @@ -21,6 +20,7 @@ import nebulosa.log.loggerFor import nebulosa.math.Angle import nebulosa.math.deg import nebulosa.plate.solving.PlateSolver +import java.nio.file.Path data class TPPAStep( @JvmField val camera: Camera, @@ -30,7 +30,7 @@ data class TPPAStep( private val longitude: Angle = mount!!.longitude, private val latitude: Angle = mount!!.latitude, private val cameraRequest: CameraStartCaptureRequest = request.capture, -) : Step, Pauseable { +) : Step, Pauseable, CameraCaptureListener { private val cameraExposureStep = CameraExposureStep(camera, cameraRequest) private val alignment = ThreePointPolarAlignment(solver, longitude, latitude) @@ -38,10 +38,10 @@ data class TPPAStep( private val stopwatch = Stopwatch() private val stepDistances = DoubleArray(2) { if (request.eastDirection) request.stepDistance else -request.stepDistance } - @Volatile private var image: Image? = null @Volatile private var mountSlewStep: MountSlewStep? = null @Volatile private var noSolutionAttempts = 0 @Volatile private var stepExecution: StepExecution? = null + @Volatile private var savedImage: Pair? = null val stepCount get() = alignment.state @@ -65,20 +65,26 @@ data class TPPAStep( return listeners.remove(listener) } + override fun onExposureFinished(step: CameraExposureStep, stepExecution: StepExecution, image: ImageRepresentation, savedPath: Path) { + savedImage = image to savedPath + } + override fun beforeJob(jobExecution: JobExecution) { + cameraExposureStep.registerCameraCaptureListener(this) cameraExposureStep.beforeJob(jobExecution) mount?.tracking(true) } override fun afterJob(jobExecution: JobExecution) { cameraExposureStep.afterJob(jobExecution) + cameraExposureStep.unregisterCameraCaptureListener(this) if (mount != null && request.stopTrackingWhenDone) { mount.tracking(false) } + savedImage = null stopwatch.stop() - listeners.forEach { it.polarAlignmentFinished(this, jobExecution.cancellationToken.isCancelled) } } @@ -119,14 +125,13 @@ data class TPPAStep( cameraExposureStep.execute(stepExecution) if (!cancellationToken.isCancelled) { - val savedPath = cameraExposureStep.savedPath ?: return StepResult.FINISHED - image = savedPath.fits().use { image?.load(it, false) ?: Image.open(it, false) } + val saved = savedImage ?: return StepResult.FINISHED val radius = if (mount == null) 0.0 else ThreePointPolarAlignment.DEFAULT_RADIUS // Polar alignment step. val result = alignment.align( - savedPath, image!!, mount?.rightAscension ?: 0.0, mount?.declination ?: 0.0, radius, + saved.second, mount?.rightAscension ?: 0.0, mount?.declination ?: 0.0, radius, request.compensateRefraction, cancellationToken ) diff --git a/api/src/main/kotlin/nebulosa/api/cameras/CameraCaptureEventHandler.kt b/api/src/main/kotlin/nebulosa/api/cameras/CameraCaptureEventHandler.kt index b594a3320..9e7a7d264 100644 --- a/api/src/main/kotlin/nebulosa/api/cameras/CameraCaptureEventHandler.kt +++ b/api/src/main/kotlin/nebulosa/api/cameras/CameraCaptureEventHandler.kt @@ -11,6 +11,8 @@ import nebulosa.batch.processing.JobExecution import nebulosa.batch.processing.JobStatus import nebulosa.batch.processing.StepExecution import nebulosa.batch.processing.delay.DelayStep +import nebulosa.image.format.ImageRepresentation +import java.nio.file.Path data class CameraCaptureEventHandler(private val observer: Observer) : CameraCaptureListener { @@ -31,8 +33,8 @@ data class CameraCaptureEventHandler(private val observer: Observer return diff --git a/api/src/main/kotlin/nebulosa/api/cameras/CameraCaptureListener.kt b/api/src/main/kotlin/nebulosa/api/cameras/CameraCaptureListener.kt index 3b685d6b4..32f9e647c 100644 --- a/api/src/main/kotlin/nebulosa/api/cameras/CameraCaptureListener.kt +++ b/api/src/main/kotlin/nebulosa/api/cameras/CameraCaptureListener.kt @@ -2,6 +2,8 @@ package nebulosa.api.cameras import nebulosa.batch.processing.JobExecution import nebulosa.batch.processing.StepExecution +import nebulosa.image.format.ImageRepresentation +import java.nio.file.Path interface CameraCaptureListener { @@ -11,7 +13,7 @@ interface CameraCaptureListener { fun onExposureElapsed(step: CameraExposureStep, stepExecution: StepExecution) = Unit - fun onExposureFinished(step: CameraExposureStep, stepExecution: StepExecution) = Unit + fun onExposureFinished(step: CameraExposureStep, stepExecution: StepExecution, image: ImageRepresentation, savedPath: Path) = Unit fun onCaptureFinished(step: CameraExposureStep, jobExecution: JobExecution) = Unit } diff --git a/api/src/main/kotlin/nebulosa/api/cameras/CameraExposureStep.kt b/api/src/main/kotlin/nebulosa/api/cameras/CameraExposureStep.kt index d84b801b5..9299a17c2 100644 --- a/api/src/main/kotlin/nebulosa/api/cameras/CameraExposureStep.kt +++ b/api/src/main/kotlin/nebulosa/api/cameras/CameraExposureStep.kt @@ -11,16 +11,14 @@ import nebulosa.batch.processing.StepResult import nebulosa.batch.processing.delay.DelayStep import nebulosa.batch.processing.delay.DelayStepListener import nebulosa.common.concurrency.latch.CountUpDownLatch -import nebulosa.fits.Fits +import nebulosa.image.format.ImageRepresentation import nebulosa.indi.device.camera.* -import nebulosa.io.transferAndClose import nebulosa.log.debug import nebulosa.log.loggerFor import okio.sink import org.greenrobot.eventbus.EventBus import org.greenrobot.eventbus.Subscribe import org.greenrobot.eventbus.ThreadMode -import java.io.InputStream import java.nio.file.Path import java.time.Duration import java.time.LocalDateTime @@ -50,9 +48,6 @@ data class CameraExposureStep( @Volatile private var stepExecution: StepExecution? = null - @Volatile override var savedPath: Path? = null - private set - override fun registerCameraCaptureListener(listener: CameraCaptureListener): Boolean { return listeners.add(listener) } @@ -66,7 +61,7 @@ data class CameraExposureStep( if (event.device === camera) { when (event) { is CameraFrameCaptured -> { - save(event.stream, event.fits) + save(event.image, event.format) } is CameraExposureAborted, is CameraExposureFailed, @@ -168,25 +163,18 @@ data class CameraExposureStep( } } - private fun save(stream: InputStream?, fits: Fits?) { + private fun save(image: ImageRepresentation, format: CameraFrameCaptured.Format) { try { - savedPath = request.makeSavePath(camera) - - LOG.info("saving FITS. path={}", savedPath) + val savedPath = request.makeSavePath(camera, format) - savedPath!!.createParentDirectories() + LOG.info("saving {} image at {}", format, savedPath) - if (stream != null) { - stream.transferAndClose(savedPath!!.outputStream()) - } else if (fits != null) { - savedPath!!.outputStream().use { fits.write(it.sink()) } - } else { - return - } + savedPath.createParentDirectories() + savedPath.outputStream().use { image.write(it.sink()) } - listeners.forEach { it.onExposureFinished(this, stepExecution!!) } + listeners.forEach { it.onExposureFinished(this, stepExecution!!, image, savedPath) } } catch (e: Throwable) { - LOG.error("failed to save FITS", e) + LOG.error("failed to save $format image", e) aborted = true } finally { latch.countDown() @@ -230,14 +218,17 @@ data class CameraExposureStep( @JvmStatic private val DATE_TIME_FORMAT = DateTimeFormatter.ofPattern("yyyyMMdd.HHmmssSSS") @JvmStatic - fun CameraStartCaptureRequest.makeSavePath(camera: Camera, autoSave: Boolean = this.autoSave): Path { + internal fun CameraStartCaptureRequest.makeSavePath( + camera: Camera, format: CameraFrameCaptured.Format, + autoSave: Boolean = this.autoSave, + ): Path { return if (autoSave) { val now = LocalDateTime.now() val savePath = autoSubFolderMode.pathFor(savePath!!, now) - val fileName = "%s-%s.fits".format(now.format(DATE_TIME_FORMAT), frameType) + val fileName = "%s-%s.%s".format(now.format(DATE_TIME_FORMAT), frameType, format.extension) Path.of("$savePath", fileName) } else { - val fileName = "%s.fits".format(camera.name) + val fileName = "%s.%s".format(camera.name, format.extension) Path.of("$savePath", fileName) } } diff --git a/api/src/main/kotlin/nebulosa/api/cameras/CameraLoopExposureStep.kt b/api/src/main/kotlin/nebulosa/api/cameras/CameraLoopExposureStep.kt index bc6f968cb..5129cff94 100644 --- a/api/src/main/kotlin/nebulosa/api/cameras/CameraLoopExposureStep.kt +++ b/api/src/main/kotlin/nebulosa/api/cameras/CameraLoopExposureStep.kt @@ -14,9 +14,6 @@ data class CameraLoopExposureStep( private val cameraExposureStep = CameraExposureStep(camera, request) private val delayStep = DelayStep(request.exposureDelay) - override val savedPath - get() = cameraExposureStep.savedPath - init { delayStep.registerDelayStepListener(cameraExposureStep) } diff --git a/api/src/main/kotlin/nebulosa/api/cameras/CameraStartCaptureStep.kt b/api/src/main/kotlin/nebulosa/api/cameras/CameraStartCaptureStep.kt index 86c6e67ab..0e70c4241 100644 --- a/api/src/main/kotlin/nebulosa/api/cameras/CameraStartCaptureStep.kt +++ b/api/src/main/kotlin/nebulosa/api/cameras/CameraStartCaptureStep.kt @@ -2,7 +2,6 @@ package nebulosa.api.cameras import nebulosa.batch.processing.Step import nebulosa.indi.device.camera.Camera -import java.nio.file.Path sealed interface CameraStartCaptureStep : Step { @@ -10,8 +9,6 @@ sealed interface CameraStartCaptureStep : Step { val request: CameraStartCaptureRequest - val savedPath: Path? - fun registerCameraCaptureListener(listener: CameraCaptureListener): Boolean fun unregisterCameraCaptureListener(listener: CameraCaptureListener): Boolean diff --git a/api/src/main/kotlin/nebulosa/api/image/ImageBucket.kt b/api/src/main/kotlin/nebulosa/api/image/ImageBucket.kt index eed799ebd..967b709a9 100644 --- a/api/src/main/kotlin/nebulosa/api/image/ImageBucket.kt +++ b/api/src/main/kotlin/nebulosa/api/image/ImageBucket.kt @@ -3,8 +3,10 @@ package nebulosa.api.image import nebulosa.fits.fits import nebulosa.image.Image import nebulosa.plate.solving.PlateSolution +import nebulosa.xisf.xisf import org.springframework.stereotype.Component import java.nio.file.Path +import kotlin.io.path.extension @Component class ImageBucket { @@ -13,7 +15,7 @@ class ImageBucket { @Synchronized fun put(path: Path, image: Image, solution: PlateSolution? = null) { - bucket[path] = image to solution + bucket[path] = image to (solution ?: PlateSolution.from(image.header)) } @Synchronized @@ -26,9 +28,17 @@ class ImageBucket { @Synchronized fun open(path: Path, debayer: Boolean = true, solution: PlateSolution? = null, force: Boolean = false): Image { val openedImage = this[path] + if (openedImage != null && !force) return openedImage.first - val image = path.fits().use { openedImage?.first?.load(it) ?: Image.open(it, debayer) } - put(path, image, solution ?: PlateSolution.from(image.header)) + + val representation = when (path.extension.lowercase()) { + "fit", "fits" -> path.fits() + "xisf" -> path.xisf() + else -> throw IllegalArgumentException("invalid extension: $path") + } + + val image = representation.use { openedImage?.first?.load(it) ?: Image.open(it, debayer) } + put(path, image, solution) return image } diff --git a/api/src/main/kotlin/nebulosa/api/image/ImageController.kt b/api/src/main/kotlin/nebulosa/api/image/ImageController.kt index a8d99bfa9..17ac495d2 100644 --- a/api/src/main/kotlin/nebulosa/api/image/ImageController.kt +++ b/api/src/main/kotlin/nebulosa/api/image/ImageController.kt @@ -5,8 +5,8 @@ import jakarta.validation.Valid import nebulosa.api.atlas.Location import nebulosa.api.beans.converters.device.DeviceOrEntityParam import nebulosa.api.beans.converters.location.LocationParam -import nebulosa.image.ImageChannel import nebulosa.image.algorithms.transformation.ProtectionMethod +import nebulosa.image.format.ImageChannel import nebulosa.indi.device.camera.Camera import nebulosa.star.detection.ImageStar import org.hibernate.validator.constraints.Range diff --git a/api/src/main/kotlin/nebulosa/api/image/ImageService.kt b/api/src/main/kotlin/nebulosa/api/image/ImageService.kt index 245b7cddc..6f610b4be 100644 --- a/api/src/main/kotlin/nebulosa/api/image/ImageService.kt +++ b/api/src/main/kotlin/nebulosa/api/image/ImageService.kt @@ -9,10 +9,10 @@ import nebulosa.api.connection.ConnectionService import nebulosa.api.framing.FramingService import nebulosa.fits.* import nebulosa.image.Image -import nebulosa.image.ImageChannel import nebulosa.image.algorithms.computation.Histogram import nebulosa.image.algorithms.computation.Statistics import nebulosa.image.algorithms.transformation.* +import nebulosa.image.format.ImageChannel import nebulosa.indi.device.camera.Camera import nebulosa.io.transferAndClose import nebulosa.log.debug diff --git a/api/src/main/kotlin/nebulosa/api/wizard/flat/FlatWizardExecutor.kt b/api/src/main/kotlin/nebulosa/api/wizard/flat/FlatWizardExecutor.kt index e79c4038b..23ca02631 100644 --- a/api/src/main/kotlin/nebulosa/api/wizard/flat/FlatWizardExecutor.kt +++ b/api/src/main/kotlin/nebulosa/api/wizard/flat/FlatWizardExecutor.kt @@ -1,5 +1,6 @@ package nebulosa.api.wizard.flat +import nebulosa.api.image.ImageBucket import nebulosa.api.messages.MessageService import nebulosa.batch.processing.JobExecutor import nebulosa.batch.processing.JobLauncher @@ -12,6 +13,7 @@ import org.springframework.stereotype.Component class FlatWizardExecutor( private val messageService: MessageService, override val jobLauncher: JobLauncher, + private val imageBucket: ImageBucket, ) : JobExecutor() { fun execute(camera: Camera, request: FlatWizardRequest): String { @@ -20,7 +22,7 @@ class FlatWizardExecutor( LOG.info { "starting flat wizard capture. camera=$camera, request=$request" } - val flatWizardJob = FlatWizardJob(camera, request) + val flatWizardJob = FlatWizardJob(camera, request, imageBucket = imageBucket) flatWizardJob.subscribe(messageService::sendMessage) register(jobLauncher.launch(flatWizardJob)) return flatWizardJob.id diff --git a/api/src/main/kotlin/nebulosa/api/wizard/flat/FlatWizardJob.kt b/api/src/main/kotlin/nebulosa/api/wizard/flat/FlatWizardJob.kt index 100b6c041..c73a491f1 100644 --- a/api/src/main/kotlin/nebulosa/api/wizard/flat/FlatWizardJob.kt +++ b/api/src/main/kotlin/nebulosa/api/wizard/flat/FlatWizardJob.kt @@ -4,6 +4,7 @@ import io.reactivex.rxjava3.subjects.PublishSubject import nebulosa.api.cameras.CameraCaptureElapsed import nebulosa.api.cameras.CameraCaptureEventHandler import nebulosa.api.cameras.CameraExposureFinished +import nebulosa.api.image.ImageBucket import nebulosa.api.messages.MessageEvent import nebulosa.batch.processing.PublishSubscribe import nebulosa.batch.processing.SimpleJob @@ -16,10 +17,11 @@ data class FlatWizardJob( @JvmField val camera: Camera, @JvmField val request: FlatWizardRequest, @JvmField val wheel: FilterWheel? = null, + @JvmField val imageBucket: ImageBucket? = null, ) : SimpleJob(), PublishSubscribe, FlatWizardExecutionListener { private val cameraCaptureEventHandler = CameraCaptureEventHandler(this) - private val step = FlatWizardStep(camera, request) + private val step = FlatWizardStep(camera, request, imageBucket) override val subject = PublishSubject.create() diff --git a/api/src/main/kotlin/nebulosa/api/wizard/flat/FlatWizardStep.kt b/api/src/main/kotlin/nebulosa/api/wizard/flat/FlatWizardStep.kt index 4afa5f8b3..b172c33e8 100644 --- a/api/src/main/kotlin/nebulosa/api/wizard/flat/FlatWizardStep.kt +++ b/api/src/main/kotlin/nebulosa/api/wizard/flat/FlatWizardStep.kt @@ -3,25 +3,23 @@ package nebulosa.api.wizard.flat import nebulosa.api.cameras.AutoSubFolderMode import nebulosa.api.cameras.CameraCaptureListener import nebulosa.api.cameras.CameraExposureStep -import nebulosa.api.cameras.CameraExposureStep.Companion.makeSavePath +import nebulosa.api.image.ImageBucket import nebulosa.batch.processing.Step import nebulosa.batch.processing.StepExecution import nebulosa.batch.processing.StepResult -import nebulosa.fits.fits import nebulosa.image.Image import nebulosa.image.algorithms.computation.Statistics +import nebulosa.image.format.ImageRepresentation import nebulosa.indi.device.camera.Camera -import nebulosa.io.transferAndClose import org.slf4j.LoggerFactory +import java.nio.file.Path import java.time.Duration import java.util.concurrent.atomic.AtomicReference -import kotlin.io.path.deleteIfExists -import kotlin.io.path.inputStream -import kotlin.io.path.outputStream data class FlatWizardStep( @JvmField val camera: Camera, @JvmField val request: FlatWizardRequest, + @JvmField val imageBucket: ImageBucket? = null, ) : Step { @Volatile var exposureMin = request.exposureMin @@ -72,31 +70,38 @@ data class FlatWizardStep( exposureTime = (exposureMax + exposureMin).dividedBy(2L) val cameraExposureStep = CameraExposureStep( - camera, - request.captureRequest.copy( + camera, request.captureRequest.copy( exposureTime = exposureTime, exposureAmount = 1, autoSave = false, autoSubFolderMode = AutoSubFolderMode.OFF, ) ) + var saved: Pair? = null + + val listener = object : CameraCaptureListener { + + override fun onExposureFinished(step: CameraExposureStep, stepExecution: StepExecution, image: ImageRepresentation, savedPath: Path) { + saved = image to savedPath + } + } + this.cameraExposureStep.set(cameraExposureStep) cameraCaptureListeners.forEach(cameraExposureStep::registerCameraCaptureListener) + cameraExposureStep.registerCameraCaptureListener(listener) cameraExposureStep.executeSingle(stepExecution) - val savedPath = cameraExposureStep.savedPath + if (!stopped && saved != null) { + val (imageRepresentation, savedPath) = saved!! - if (!stopped && savedPath != null) { - image = savedPath.fits().use { image?.load(it, false) ?: Image.open(it, false) } + image = image?.load(imageRepresentation) ?: Image.open(imageRepresentation, false) + imageBucket?.put(savedPath, image!!) val statistics = STATISTICS.compute(image!!) LOG.info("flat frame captured. duration={}, statistics={}", exposureTime, statistics) if (statistics.mean in meanRange) { - val path = request.captureRequest.makeSavePath(camera, true) - savedPath.inputStream().transferAndClose(path.outputStream()) - savedPath.deleteIfExists() - LOG.info("Found an optimal exposure time. exposure={}, path={}", exposureTime, path) - flatWizardExecutionListeners.forEach { it.onFlatCaptured(this, path, exposureTime) } + LOG.info("Found an optimal exposure time. exposure={}, path={}", exposureTime, savedPath) + flatWizardExecutionListeners.forEach { it.onFlatCaptured(this, savedPath, exposureTime) } } else if (statistics.mean < meanRange.start) { exposureMin = cameraExposureStep.exposureTime return StepResult.CONTINUABLE diff --git a/desktop/src/shared/services/electron.service.ts b/desktop/src/shared/services/electron.service.ts index d78aff675..0c7ae92de 100644 --- a/desktop/src/shared/services/electron.service.ts +++ b/desktop/src/shared/services/electron.service.ts @@ -111,7 +111,12 @@ export class ElectronService { } openFits(data?: OpenFile): Promise { - return this.openFile({ ...data, filters: [{ name: 'FITS files', extensions: ['fits', 'fit'] }] }) + return this.openFile({ + ...data, filters: [ + { name: 'FITS files', extensions: ['fits', 'fit'] }, + { name: 'XISF files', extensions: ['xisf'] }, + ] + }) } saveFits(data?: OpenFile) { diff --git a/nebulosa-alignment/src/main/kotlin/nebulosa/alignment/polar/point/three/ThreePointPolarAlignment.kt b/nebulosa-alignment/src/main/kotlin/nebulosa/alignment/polar/point/three/ThreePointPolarAlignment.kt index 086a3c004..91e8a5bb3 100644 --- a/nebulosa-alignment/src/main/kotlin/nebulosa/alignment/polar/point/three/ThreePointPolarAlignment.kt +++ b/nebulosa-alignment/src/main/kotlin/nebulosa/alignment/polar/point/three/ThreePointPolarAlignment.kt @@ -2,15 +2,10 @@ package nebulosa.alignment.polar.point.three import nebulosa.common.concurrency.cancel.CancellationToken import nebulosa.constants.DEG2RAD -import nebulosa.fits.declination -import nebulosa.fits.observationDate -import nebulosa.fits.rightAscension -import nebulosa.image.Image import nebulosa.math.Angle import nebulosa.plate.solving.PlateSolution import nebulosa.plate.solving.PlateSolver import nebulosa.plate.solving.PlateSolvingException -import nebulosa.time.TimeYMDHMS import nebulosa.time.UTC import java.nio.file.Path import kotlin.math.min @@ -34,15 +29,13 @@ data class ThreePointPolarAlignment( private set fun align( - path: Path, image: Image, - rightAscension: Angle = image.header.rightAscension, - declination: Angle = image.header.declination, - radius: Angle = DEFAULT_RADIUS, + path: Path, + rightAscension: Angle, declination: Angle, radius: Angle = DEFAULT_RADIUS, compensateRefraction: Boolean = false, cancellationToken: CancellationToken = CancellationToken.NONE, ): ThreePointPolarAlignmentResult { val solution = try { - solver.solve(path, image, rightAscension, declination, radius, cancellationToken = cancellationToken) + solver.solve(path, null, rightAscension, declination, radius, cancellationToken = cancellationToken) } catch (e: PlateSolvingException) { return ThreePointPolarAlignmentResult.NoPlateSolution(e) } @@ -50,7 +43,7 @@ data class ThreePointPolarAlignment( if (!solution.solved || cancellationToken.isCancelled) { return ThreePointPolarAlignmentResult.NoPlateSolution(null) } else { - val time = image.header.observationDate?.let { UTC(TimeYMDHMS(it)) } ?: UTC.now() + val time = UTC.now() positions[min(state, 2)] = solution.position(time, compensateRefraction) diff --git a/nebulosa-alpaca-indi/src/main/kotlin/nebulosa/alpaca/indi/device/cameras/ASCOMCamera.kt b/nebulosa-alpaca-indi/src/main/kotlin/nebulosa/alpaca/indi/device/cameras/ASCOMCamera.kt index 6e6236a38..12cfa270d 100644 --- a/nebulosa-alpaca-indi/src/main/kotlin/nebulosa/alpaca/indi/device/cameras/ASCOMCamera.kt +++ b/nebulosa-alpaca-indi/src/main/kotlin/nebulosa/alpaca/indi/device/cameras/ASCOMCamera.kt @@ -694,27 +694,27 @@ data class ASCOMCamera( val fits = Fits() fits.add(hdu) - sender.fireOnEventReceived(CameraFrameCaptured(this, null, fits, false)) + sender.fireOnEventReceived(CameraFrameCaptured(this, fits, false, CameraFrameCaptured.Format.FITS)) } ?: LOG.error("image body is null. device={}", name) } override fun toString() = "Camera(name=$name, connected=$connected, exposuring=$exposuring," + - " hasCoolerControl=$hasCoolerControl, cooler=$cooler," + - " hasDewHeater=$hasDewHeater, dewHeater=$dewHeater," + - " frameFormats=$frameFormats, canAbort=$canAbort," + - " cfaOffsetX=$cfaOffsetX, cfaOffsetY=$cfaOffsetY, cfaType=$cfaType," + - " exposureMin=$exposureMin, exposureMax=$exposureMax," + - " exposureState=$exposureState, exposureTime=$exposureTime," + - " hasCooler=$hasCooler, hasThermometer=$hasThermometer, canSetTemperature=$canSetTemperature," + - " temperature=$temperature, canSubFrame=$canSubFrame," + - " x=$x, minX=$minX, maxX=$maxX, y=$y, minY=$minY, maxY=$maxY," + - " width=$width, minWidth=$minWidth, maxWidth=$maxWidth, height=$height," + - " minHeight=$minHeight, maxHeight=$maxHeight," + - " canBin=$canBin, maxBinX=$maxBinX, maxBinY=$maxBinY," + - " binX=$binX, binY=$binY, gain=$gain, gainMin=$gainMin," + - " gainMax=$gainMax, offset=$offset, offsetMin=$offsetMin," + - " offsetMax=$offsetMax, hasGuiderHead=$hasGuiderHead," + - " canPulseGuide=$canPulseGuide, pulseGuiding=$pulseGuiding)" + " hasCoolerControl=$hasCoolerControl, cooler=$cooler," + + " hasDewHeater=$hasDewHeater, dewHeater=$dewHeater," + + " frameFormats=$frameFormats, canAbort=$canAbort," + + " cfaOffsetX=$cfaOffsetX, cfaOffsetY=$cfaOffsetY, cfaType=$cfaType," + + " exposureMin=$exposureMin, exposureMax=$exposureMax," + + " exposureState=$exposureState, exposureTime=$exposureTime," + + " hasCooler=$hasCooler, hasThermometer=$hasThermometer, canSetTemperature=$canSetTemperature," + + " temperature=$temperature, canSubFrame=$canSubFrame," + + " x=$x, minX=$minX, maxX=$maxX, y=$y, minY=$minY, maxY=$maxY," + + " width=$width, minWidth=$minWidth, maxWidth=$maxWidth, height=$height," + + " minHeight=$minHeight, maxHeight=$maxHeight," + + " canBin=$canBin, maxBinX=$maxBinX, maxBinY=$maxBinY," + + " binX=$binX, binY=$binY, gain=$gain, gainMin=$gainMin," + + " gainMax=$gainMax, offset=$offset, offsetMin=$offsetMin," + + " offsetMax=$offsetMax, hasGuiderHead=$hasGuiderHead," + + " canPulseGuide=$canPulseGuide, pulseGuiding=$pulseGuiding)" data class ImageMetadata( @JvmField val metadataVersion: Int, // Bytes 0..3 - Metadata version = 1 diff --git a/nebulosa-fits/src/main/kotlin/nebulosa/fits/SeekableSourceImageData.kt b/nebulosa-fits/src/main/kotlin/nebulosa/fits/SeekableSourceImageData.kt index 312f34871..4a7fc10ae 100644 --- a/nebulosa-fits/src/main/kotlin/nebulosa/fits/SeekableSourceImageData.kt +++ b/nebulosa-fits/src/main/kotlin/nebulosa/fits/SeekableSourceImageData.kt @@ -57,11 +57,18 @@ internal data class SeekableSourceImageData( } private fun readChannel(channel: ImageChannel): FloatArray { + val data = FloatArray(numberOfPixels) + readChannelTo(channel, data) + return data + } + + override fun readChannelTo(channel: ImageChannel, output: FloatArray) { + // TODO: Read channel from source only if not initialized (remove lazy from red, green and blue). + val startIndex = channelSizeInBytes * channel.index source.seek(position + startIndex) - val data = FloatArray(numberOfPixels) - var remainingPixels = data.size + var remainingPixels = output.size var pos = 0 Buffer().use { buffer -> @@ -77,14 +84,12 @@ internal data class SeekableSourceImageData( n = (size / bitpix.byteLength).toInt() repeat(n) { - data[pos++] = buffer.readPixel(bitpix) + output[pos++] = buffer.readPixel(bitpix) } remainingPixels -= n } } - - return data } internal fun writeTo(sink: Sink): Long { diff --git a/nebulosa-hips2fits/src/test/kotlin/Hips2FitsServiceTest.kt b/nebulosa-hips2fits/src/test/kotlin/Hips2FitsServiceTest.kt index 2853c8809..ce093b062 100644 --- a/nebulosa-hips2fits/src/test/kotlin/Hips2FitsServiceTest.kt +++ b/nebulosa-hips2fits/src/test/kotlin/Hips2FitsServiceTest.kt @@ -1,3 +1,4 @@ +import io.kotest.core.annotation.EnabledIf import io.kotest.core.spec.style.StringSpec import io.kotest.matchers.collections.shouldHaveSize import io.kotest.matchers.collections.shouldNotBeEmpty @@ -10,7 +11,9 @@ import nebulosa.image.format.ImageHdu import nebulosa.io.source import nebulosa.math.deg import nebulosa.math.toDegrees +import nebulosa.test.NonGitHubOnlyCondition +@EnabledIf(NonGitHubOnlyCondition::class) class Hips2FitsServiceTest : StringSpec() { init { diff --git a/nebulosa-image-format/src/main/kotlin/nebulosa/image/format/FloatImageData.kt b/nebulosa-image-format/src/main/kotlin/nebulosa/image/format/FloatImageData.kt index 64bddc643..cd30ac4e3 100644 --- a/nebulosa-image-format/src/main/kotlin/nebulosa/image/format/FloatImageData.kt +++ b/nebulosa-image-format/src/main/kotlin/nebulosa/image/format/FloatImageData.kt @@ -8,4 +8,14 @@ data class FloatImageData( override val red: FloatArray = FloatArray(width * height), override val green: FloatArray = if (numberOfChannels == 1) red else FloatArray(width * height), override val blue: FloatArray = if (numberOfChannels == 1) red else FloatArray(width * height), -) : ImageData +) : ImageData { + + override fun readChannelTo(channel: ImageChannel, output: FloatArray) { + when (channel) { + ImageChannel.GRAY, + ImageChannel.RED -> red.copyInto(output) + ImageChannel.GREEN -> green.copyInto(output) + ImageChannel.BLUE -> blue.copyInto(output) + } + } +} diff --git a/nebulosa-image-format/src/main/kotlin/nebulosa/image/format/ImageChannel.kt b/nebulosa-image-format/src/main/kotlin/nebulosa/image/format/ImageChannel.kt index d09c27d4b..c966c3aa2 100644 --- a/nebulosa-image-format/src/main/kotlin/nebulosa/image/format/ImageChannel.kt +++ b/nebulosa-image-format/src/main/kotlin/nebulosa/image/format/ImageChannel.kt @@ -1,8 +1,13 @@ package nebulosa.image.format -enum class ImageChannel(val index: Int) { +enum class ImageChannel(@JvmField val index: Int) { GRAY(0), RED(0), GREEN(1), - BLUE(2), + BLUE(2); + + companion object { + + @JvmStatic val RGB = listOf(RED, GREEN, BLUE) + } } diff --git a/nebulosa-image-format/src/main/kotlin/nebulosa/image/format/ImageData.kt b/nebulosa-image-format/src/main/kotlin/nebulosa/image/format/ImageData.kt index 82fcaef1d..ab83c43ca 100644 --- a/nebulosa-image-format/src/main/kotlin/nebulosa/image/format/ImageData.kt +++ b/nebulosa-image-format/src/main/kotlin/nebulosa/image/format/ImageData.kt @@ -16,4 +16,6 @@ interface ImageData { val green: FloatArray val blue: FloatArray + + fun readChannelTo(channel: ImageChannel, output: FloatArray) } diff --git a/nebulosa-image/src/main/kotlin/nebulosa/image/Image.kt b/nebulosa-image/src/main/kotlin/nebulosa/image/Image.kt index cbe6c9027..4e2a161aa 100644 --- a/nebulosa-image/src/main/kotlin/nebulosa/image/Image.kt +++ b/nebulosa-image/src/main/kotlin/nebulosa/image/Image.kt @@ -18,7 +18,7 @@ import kotlin.math.min class Image internal constructor( width: Int, height: Int, val mono: Boolean, @JvmField val hdu: ImageHdu, -) : BufferedImage(colorModel(mono), raster(hdu, mono), false, null) { +) : BufferedImage(colorModel(mono), raster(hdu, mono), false, null), Cloneable { constructor(width: Int, height: Int, header: ReadableHeader, mono: Boolean) : this(width, height, mono, BasicImageHdu(width, height, if (mono) 1 else 3, header, FloatImageData(width, height, if (mono) 1 else 3))) @@ -52,7 +52,7 @@ class Image internal constructor( } inline fun write(index: Int, channel: ImageChannel, color: Float) { - write(index, channel.offset, color) + write(index, channel.index, color) } inline fun write(index: Int, channel: Int, color: Float) { @@ -60,7 +60,7 @@ class Image internal constructor( } inline fun write(x: Int, y: Int, channel: ImageChannel, color: Float) { - write(x, y, channel.offset, color) + write(x, y, channel.index, color) } inline fun write(x: Int, y: Int, channel: Int, color: Float) { @@ -105,7 +105,7 @@ class Image internal constructor( } inline fun read(index: Int, channel: ImageChannel): Float { - return read(index, channel.offset) + return read(index, channel.index) } inline fun read(index: Int, channel: Int): Float { @@ -113,7 +113,7 @@ class Image internal constructor( } inline fun read(x: Int, y: Int, channel: ImageChannel): Float { - return read(x, y, channel.offset) + return read(x, y, channel.index) } inline fun read(x: Int, y: Int, channel: Int): Float { @@ -215,25 +215,29 @@ class Image internal constructor( return image } - fun canLoad(hdu: ImageHdu, debayer: Boolean = true): Boolean { - return hdu.width == width && hdu.height == height && (isMono(hdu) || !debayer) == mono + fun canLoad(hdu: ImageHdu): Boolean { + return hdu.width == width && hdu.height == height && hdu.isMono == mono } - fun canLoad(image: ImageRepresentation, debayer: Boolean = true): Boolean { - return canLoad(image.filterIsInstance().first(), debayer) + fun canLoad(image: ImageRepresentation): Boolean { + return canLoad(image.filterIsInstance().first()) } - fun load(image: ImageRepresentation, debayer: Boolean = true): Image? { - return load(image.filterIsInstance().first(), debayer) + fun load(image: ImageRepresentation): Image? { + return load(image.filterIsInstance().first()) } - fun load(hdu: ImageHdu, debayer: Boolean = true): Image? { - if (!canLoad(hdu, debayer)) return null - load(this, hdu, debayer) + fun load(image: Image): Image? { + return load(image.hdu) + } + + fun load(hdu: ImageHdu): Image? { + if (!canLoad(hdu)) return null + load(this, hdu, false) return this } - fun clone() = if (mono) mono() else color() + public override fun clone() = if (mono) mono() else color() fun transform(vararg algorithms: TransformAlgorithm) = algorithms.transform(this) @@ -289,14 +293,14 @@ class Image internal constructor( @JvmStatic private fun load(image: Image, hdu: ImageHdu, debayer: Boolean) { - hdu.data.red.copyInto(image.red) + hdu.data.readChannelTo(ImageChannel.RED, image.red) if (!image.mono) { - hdu.data.green.copyInto(image.green) - hdu.data.blue.copyInto(image.blue) - if (debayer) { image.debayer() + } else { + hdu.data.readChannelTo(ImageChannel.GREEN, image.green) + hdu.data.readChannelTo(ImageChannel.BLUE, image.blue) } } } diff --git a/nebulosa-image/src/main/kotlin/nebulosa/image/ImageChannel.kt b/nebulosa-image/src/main/kotlin/nebulosa/image/ImageChannel.kt deleted file mode 100644 index e16b4a0c0..000000000 --- a/nebulosa-image/src/main/kotlin/nebulosa/image/ImageChannel.kt +++ /dev/null @@ -1,13 +0,0 @@ -package nebulosa.image - -enum class ImageChannel(@JvmField val offset: Int) { - RED(0), - GREEN(1), - BLUE(2), - GRAY(0); - - companion object { - - @JvmStatic val RGB = listOf(RED, GREEN, BLUE) - } -} diff --git a/nebulosa-image/src/main/kotlin/nebulosa/image/algorithms/computation/Histogram.kt b/nebulosa-image/src/main/kotlin/nebulosa/image/algorithms/computation/Histogram.kt index 65e7948ba..e439a8a82 100644 --- a/nebulosa-image/src/main/kotlin/nebulosa/image/algorithms/computation/Histogram.kt +++ b/nebulosa-image/src/main/kotlin/nebulosa/image/algorithms/computation/Histogram.kt @@ -2,8 +2,8 @@ package nebulosa.image.algorithms.computation import nebulosa.image.Image import nebulosa.image.Image.Companion.forEach -import nebulosa.image.ImageChannel import nebulosa.image.algorithms.ComputationAlgorithm +import nebulosa.image.format.ImageChannel import kotlin.math.max import kotlin.math.min diff --git a/nebulosa-image/src/main/kotlin/nebulosa/image/algorithms/computation/Median.kt b/nebulosa-image/src/main/kotlin/nebulosa/image/algorithms/computation/Median.kt index 0357ad1ec..77411184b 100644 --- a/nebulosa-image/src/main/kotlin/nebulosa/image/algorithms/computation/Median.kt +++ b/nebulosa-image/src/main/kotlin/nebulosa/image/algorithms/computation/Median.kt @@ -2,8 +2,8 @@ package nebulosa.image.algorithms.computation import nebulosa.image.Image import nebulosa.image.Image.Companion.forEach -import nebulosa.image.ImageChannel import nebulosa.image.algorithms.ComputationAlgorithm +import nebulosa.image.format.ImageChannel import kotlin.math.max import kotlin.math.min diff --git a/nebulosa-image/src/main/kotlin/nebulosa/image/algorithms/computation/MedianAbsoluteDeviation.kt b/nebulosa-image/src/main/kotlin/nebulosa/image/algorithms/computation/MedianAbsoluteDeviation.kt index 0f7984da4..b11c41688 100644 --- a/nebulosa-image/src/main/kotlin/nebulosa/image/algorithms/computation/MedianAbsoluteDeviation.kt +++ b/nebulosa-image/src/main/kotlin/nebulosa/image/algorithms/computation/MedianAbsoluteDeviation.kt @@ -2,8 +2,8 @@ package nebulosa.image.algorithms.computation import nebulosa.image.Image import nebulosa.image.Image.Companion.forEach -import nebulosa.image.ImageChannel import nebulosa.image.algorithms.ComputationAlgorithm +import nebulosa.image.format.ImageChannel import kotlin.math.abs import kotlin.math.min diff --git a/nebulosa-image/src/main/kotlin/nebulosa/image/algorithms/computation/Statistics.kt b/nebulosa-image/src/main/kotlin/nebulosa/image/algorithms/computation/Statistics.kt index 2d4b0dbd5..2a44ef99a 100644 --- a/nebulosa-image/src/main/kotlin/nebulosa/image/algorithms/computation/Statistics.kt +++ b/nebulosa-image/src/main/kotlin/nebulosa/image/algorithms/computation/Statistics.kt @@ -2,8 +2,8 @@ package nebulosa.image.algorithms.computation import nebulosa.image.Image import nebulosa.image.Image.Companion.forEach -import nebulosa.image.ImageChannel import nebulosa.image.algorithms.ComputationAlgorithm +import nebulosa.image.format.ImageChannel import kotlin.math.abs import kotlin.math.max import kotlin.math.min diff --git a/nebulosa-image/src/main/kotlin/nebulosa/image/algorithms/transformation/CfaPattern.kt b/nebulosa-image/src/main/kotlin/nebulosa/image/algorithms/transformation/CfaPattern.kt index e4015aa68..b650c546f 100644 --- a/nebulosa-image/src/main/kotlin/nebulosa/image/algorithms/transformation/CfaPattern.kt +++ b/nebulosa-image/src/main/kotlin/nebulosa/image/algorithms/transformation/CfaPattern.kt @@ -1,7 +1,7 @@ package nebulosa.image.algorithms.transformation import nebulosa.fits.cfaPattern -import nebulosa.image.ImageChannel +import nebulosa.image.format.ImageChannel import nebulosa.image.format.ReadableHeader enum class CfaPattern(private val pattern: Array>) { diff --git a/nebulosa-image/src/main/kotlin/nebulosa/image/algorithms/transformation/Debayer.kt b/nebulosa-image/src/main/kotlin/nebulosa/image/algorithms/transformation/Debayer.kt index 75d036ee9..3f9451efc 100644 --- a/nebulosa-image/src/main/kotlin/nebulosa/image/algorithms/transformation/Debayer.kt +++ b/nebulosa-image/src/main/kotlin/nebulosa/image/algorithms/transformation/Debayer.kt @@ -46,54 +46,54 @@ data class Debayer(private val pattern: CfaPattern? = null) : TransformAlgorithm rgbCounters.fill(0) var bayerIndex = pattern[y and 1, x and 1] - rgbValues[bayerIndex.offset] += source.readRed(index) - rgbCounters[bayerIndex.offset]++ + rgbValues[bayerIndex.index] += source.readRed(index) + rgbCounters[bayerIndex.index]++ if (x != 0) { bayerIndex = pattern[y and 1, x - 1 and 1] - rgbValues[bayerIndex.offset] += source.readRed(index - 1) - rgbCounters[bayerIndex.offset]++ + rgbValues[bayerIndex.index] += source.readRed(index - 1) + rgbCounters[bayerIndex.index]++ } if (x != widthM1) { bayerIndex = pattern[y and 1, x + 1 and 1] - rgbValues[bayerIndex.offset] += source.readRed(index + 1) - rgbCounters[bayerIndex.offset]++ + rgbValues[bayerIndex.index] += source.readRed(index + 1) + rgbCounters[bayerIndex.index]++ } if (y != 0) { bayerIndex = pattern[y - 1 and 1, x and 1] - rgbValues[bayerIndex.offset] += source.readRed(index - source.stride) - rgbCounters[bayerIndex.offset]++ + rgbValues[bayerIndex.index] += source.readRed(index - source.stride) + rgbCounters[bayerIndex.index]++ if (x != 0) { bayerIndex = pattern[y - 1 and 1, x - 1 and 1] - rgbValues[bayerIndex.offset] += source.readRed(index - source.stride - 1) - rgbCounters[bayerIndex.offset]++ + rgbValues[bayerIndex.index] += source.readRed(index - source.stride - 1) + rgbCounters[bayerIndex.index]++ } if (x != widthM1) { bayerIndex = pattern[y - 1 and 1, x + 1 and 1] - rgbValues[bayerIndex.offset] += source.readRed(index - source.stride + 1) - rgbCounters[bayerIndex.offset]++ + rgbValues[bayerIndex.index] += source.readRed(index - source.stride + 1) + rgbCounters[bayerIndex.index]++ } } if (y != heightM1) { bayerIndex = pattern[y + 1 and 1, x and 1] - rgbValues[bayerIndex.offset] += source.readRed(index + source.stride) - rgbCounters[bayerIndex.offset]++ + rgbValues[bayerIndex.index] += source.readRed(index + source.stride) + rgbCounters[bayerIndex.index]++ if (x != 0) { bayerIndex = pattern[y + 1 and 1, x - 1 and 1] - rgbValues[bayerIndex.offset] += source.readRed(index + source.stride - 1) - rgbCounters[bayerIndex.offset]++ + rgbValues[bayerIndex.index] += source.readRed(index + source.stride - 1) + rgbCounters[bayerIndex.index]++ } if (x != widthM1) { bayerIndex = pattern[y + 1 and 1, x + 1 and 1] - rgbValues[bayerIndex.offset] += source.readRed(index + source.stride + 1) - rgbCounters[bayerIndex.offset]++ + rgbValues[bayerIndex.index] += source.readRed(index + source.stride + 1) + rgbCounters[bayerIndex.index]++ } } diff --git a/nebulosa-image/src/main/kotlin/nebulosa/image/algorithms/transformation/SigmaClip.kt b/nebulosa-image/src/main/kotlin/nebulosa/image/algorithms/transformation/SigmaClip.kt index 4c34d2880..197ddbf55 100644 --- a/nebulosa-image/src/main/kotlin/nebulosa/image/algorithms/transformation/SigmaClip.kt +++ b/nebulosa-image/src/main/kotlin/nebulosa/image/algorithms/transformation/SigmaClip.kt @@ -1,10 +1,10 @@ package nebulosa.image.algorithms.transformation import nebulosa.image.Image -import nebulosa.image.ImageChannel import nebulosa.image.algorithms.ComputationAlgorithm import nebulosa.image.algorithms.TransformAlgorithm import nebulosa.image.algorithms.computation.Statistics +import nebulosa.image.format.ImageChannel import kotlin.math.max import kotlin.math.min diff --git a/nebulosa-image/src/main/kotlin/nebulosa/image/algorithms/transformation/SubtractiveChromaticNoiseReduction.kt b/nebulosa-image/src/main/kotlin/nebulosa/image/algorithms/transformation/SubtractiveChromaticNoiseReduction.kt index 06619c2c4..9a2ea4666 100644 --- a/nebulosa-image/src/main/kotlin/nebulosa/image/algorithms/transformation/SubtractiveChromaticNoiseReduction.kt +++ b/nebulosa-image/src/main/kotlin/nebulosa/image/algorithms/transformation/SubtractiveChromaticNoiseReduction.kt @@ -1,8 +1,8 @@ package nebulosa.image.algorithms.transformation import nebulosa.image.Image -import nebulosa.image.ImageChannel import nebulosa.image.algorithms.TransformAlgorithm +import nebulosa.image.format.ImageChannel /** * The Subtractive Chromatic Noise Reduction (SCNR) technique @@ -31,12 +31,12 @@ data class SubtractiveChromaticNoiseReduction( override fun transform(source: Image): Image { if (source.mono || channel == ImageChannel.GRAY) return source - val p0 = (channel.offset + 2) % 3 - val p1 = (channel.offset + 1) % 3 + val p0 = (channel.index + 2) % 3 + val p1 = (channel.index + 1) % 3 for (i in source.red.indices) { - source.data[channel.offset][i] = protectionMethod - .compute(source.data[p0][i], source.data[p1][i], source.data[channel.offset][i], amount) + source.data[channel.index][i] = protectionMethod + .compute(source.data[p0][i], source.data[p1][i], source.data[channel.index][i], amount) } return source diff --git a/nebulosa-image/src/main/kotlin/nebulosa/image/algorithms/transformation/correction/BiasSubtraction.kt b/nebulosa-image/src/main/kotlin/nebulosa/image/algorithms/transformation/correction/BiasSubtraction.kt index 56b197d0d..236c3d2c2 100644 --- a/nebulosa-image/src/main/kotlin/nebulosa/image/algorithms/transformation/correction/BiasSubtraction.kt +++ b/nebulosa-image/src/main/kotlin/nebulosa/image/algorithms/transformation/correction/BiasSubtraction.kt @@ -1,8 +1,8 @@ package nebulosa.image.algorithms.transformation.correction import nebulosa.image.Image -import nebulosa.image.ImageChannel import nebulosa.image.algorithms.TransformAlgorithm +import nebulosa.image.format.ImageChannel import kotlin.math.max data class BiasSubtraction(private val biasFrame: Image) : TransformAlgorithm { diff --git a/nebulosa-image/src/main/kotlin/nebulosa/image/algorithms/transformation/correction/DarkSubtraction.kt b/nebulosa-image/src/main/kotlin/nebulosa/image/algorithms/transformation/correction/DarkSubtraction.kt index 62fb5ca3e..7a092333d 100644 --- a/nebulosa-image/src/main/kotlin/nebulosa/image/algorithms/transformation/correction/DarkSubtraction.kt +++ b/nebulosa-image/src/main/kotlin/nebulosa/image/algorithms/transformation/correction/DarkSubtraction.kt @@ -1,8 +1,8 @@ package nebulosa.image.algorithms.transformation.correction import nebulosa.image.Image -import nebulosa.image.ImageChannel import nebulosa.image.algorithms.TransformAlgorithm +import nebulosa.image.format.ImageChannel import kotlin.math.max data class DarkSubtraction(private val darkFrame: Image) : TransformAlgorithm { diff --git a/nebulosa-image/src/main/kotlin/nebulosa/image/algorithms/transformation/correction/FlatCorrection.kt b/nebulosa-image/src/main/kotlin/nebulosa/image/algorithms/transformation/correction/FlatCorrection.kt index 3225ff04c..785d7029f 100644 --- a/nebulosa-image/src/main/kotlin/nebulosa/image/algorithms/transformation/correction/FlatCorrection.kt +++ b/nebulosa-image/src/main/kotlin/nebulosa/image/algorithms/transformation/correction/FlatCorrection.kt @@ -1,9 +1,9 @@ package nebulosa.image.algorithms.transformation.correction import nebulosa.image.Image -import nebulosa.image.ImageChannel import nebulosa.image.algorithms.TransformAlgorithm import nebulosa.image.algorithms.computation.Statistics +import nebulosa.image.format.ImageChannel data class FlatCorrection(private val flatFrame: Image) : TransformAlgorithm { diff --git a/nebulosa-image/src/test/kotlin/ComputationAlgorithmTest.kt b/nebulosa-image/src/test/kotlin/ComputationAlgorithmTest.kt index 1a1f8a244..016f65b56 100644 --- a/nebulosa-image/src/test/kotlin/ComputationAlgorithmTest.kt +++ b/nebulosa-image/src/test/kotlin/ComputationAlgorithmTest.kt @@ -4,9 +4,9 @@ import io.kotest.matchers.ints.shouldBeExactly import io.kotest.matchers.shouldBe import nebulosa.fits.fits import nebulosa.image.Image -import nebulosa.image.ImageChannel import nebulosa.image.algorithms.computation.MedianAbsoluteDeviation import nebulosa.image.algorithms.computation.Statistics +import nebulosa.image.format.ImageChannel import nebulosa.test.FitsStringSpec class ComputationAlgorithmTest : FitsStringSpec() { diff --git a/nebulosa-image/src/test/kotlin/TransformAlgorithmTest.kt b/nebulosa-image/src/test/kotlin/TransformAlgorithmTest.kt index 6a55cdc25..8e1a0b309 100644 --- a/nebulosa-image/src/test/kotlin/TransformAlgorithmTest.kt +++ b/nebulosa-image/src/test/kotlin/TransformAlgorithmTest.kt @@ -1,12 +1,14 @@ import io.kotest.matchers.booleans.shouldBeFalse import io.kotest.matchers.booleans.shouldBeTrue import io.kotest.matchers.ints.shouldBeExactly +import io.kotest.matchers.nulls.shouldBeNull +import io.kotest.matchers.nulls.shouldNotBeNull import io.kotest.matchers.shouldBe import nebulosa.fits.fits import nebulosa.image.Image -import nebulosa.image.ImageChannel import nebulosa.image.algorithms.transformation.* import nebulosa.image.algorithms.transformation.convolution.* +import nebulosa.image.format.ImageChannel import nebulosa.test.FitsStringSpec class TransformAlgorithmTest : FitsStringSpec() { @@ -119,6 +121,15 @@ class TransformAlgorithmTest : FitsStringSpec() { mImage.transform(AutoScreenTransformFunction) mImage.save("mono-auto-stf").second shouldBe "e17cfc29c3b343409cd8617b6913330e" } + "!mono:reload" { + val mImage0 = Image.open(NGC3344_MONO_8_FITS_PATH.fits()) + + val mImage1 = Image.open(NGC3344_MONO_8_FITS_PATH.fits()) + mImage1.transform(Invert) + + mImage0.load(mImage1.hdu) + mImage0.save("mono-reload").second shouldBe "6e94463bb5b9561de1f0ee0a154db53e" + } "color:raw" { val mImage = Image.open(NGC3344_COLOR_32_FITS_PATH.fits()) mImage.save("color-raw").second shouldBe "18fb83e240bc7a4cbafbc1aba2741db6" @@ -276,5 +287,17 @@ class TransformAlgorithmTest : FitsStringSpec() { val nImage = mImage.transform(AutoScreenTransformFunction) nImage.save("color-no-debayer").second shouldBe "958ccea020deec1f0c075042a9ba37c3" } + "color:reload" { + val mImage0 = Image.open(NGC3344_COLOR_32_FITS_PATH.fits()) + var mImage1 = Image.open(DEBAYER_FITS_PATH.fits()) + + mImage1.load(mImage0.hdu).shouldNotBeNull() + mImage1.save("color-reload").second shouldBe "18fb83e240bc7a4cbafbc1aba2741db6" + + mImage1 = Image.open(DEBAYER_FITS_PATH.fits(), false) + + mImage1.load(mImage0.hdu).shouldBeNull() + mImage0.load(mImage1.hdu).shouldBeNull() + } } } diff --git a/nebulosa-indi-client/build.gradle.kts b/nebulosa-indi-client/build.gradle.kts index df3e33b47..52957c1a7 100644 --- a/nebulosa-indi-client/build.gradle.kts +++ b/nebulosa-indi-client/build.gradle.kts @@ -7,6 +7,7 @@ dependencies { api(project(":nebulosa-io")) api(project(":nebulosa-nova")) api(project(":nebulosa-image")) + api(project(":nebulosa-xisf")) api(project(":nebulosa-indi-device")) implementation(project(":nebulosa-log")) testImplementation(project(":nebulosa-test")) diff --git a/nebulosa-indi-client/src/main/kotlin/nebulosa/indi/client/device/cameras/INDICamera.kt b/nebulosa-indi-client/src/main/kotlin/nebulosa/indi/client/device/cameras/INDICamera.kt index 5503807d1..d796e03f2 100644 --- a/nebulosa-indi-client/src/main/kotlin/nebulosa/indi/client/device/cameras/INDICamera.kt +++ b/nebulosa-indi-client/src/main/kotlin/nebulosa/indi/client/device/cameras/INDICamera.kt @@ -1,5 +1,6 @@ package nebulosa.indi.client.device.cameras +import nebulosa.fits.fits import nebulosa.image.algorithms.transformation.CfaPattern import nebulosa.indi.client.INDIClient import nebulosa.indi.client.device.INDIDevice @@ -8,14 +9,18 @@ import nebulosa.indi.device.camera.Camera.Companion.NANO_SECONDS import nebulosa.indi.device.guide.GuideOutputPulsingChanged import nebulosa.indi.protocol.* import nebulosa.io.Base64InputStream +import nebulosa.io.transferAndClose import nebulosa.log.loggerFor +import nebulosa.xisf.xisf +import java.nio.file.Files import java.time.Duration +import kotlin.io.path.outputStream // https://github.com/indilib/indi/blob/master/libs/indibase/indiccd.cpp internal open class INDICamera( - override val sender: INDIClient, - override val name: String, + final override val sender: INDIClient, + final override val name: String, ) : INDIDevice(), Camera { @Volatile final override var exposuring = false @@ -117,6 +122,8 @@ internal open class INDICamera( @Volatile final override var pulseGuiding = false private set + private val savePath = Files.createTempFile(name, ".camera") + override fun handleMessage(message: INDIProtocol) { when (message) { is SwitchVector<*> -> { @@ -295,9 +302,25 @@ internal open class INDICamera( when (message.name) { "CCD1" -> { val ccd1 = message["CCD1"]!! - val fits = Base64InputStream(ccd1.value) - val compressed = COMPRESSION_FORMATS.any { ccd1.format.endsWith(it, true) } - sender.fireOnEventReceived(CameraFrameCaptured(this, fits, null, compressed)) + + val format = CameraFrameCaptured.Format.from(ccd1.format) + + if (format != CameraFrameCaptured.Format.RAW) { + val stream = Base64InputStream(ccd1.value) + stream.transferAndClose(savePath.outputStream()) + + val compressed = COMPRESSION_FORMATS.any { ccd1.format.endsWith(it, true) } + + val image = when (format) { + CameraFrameCaptured.Format.FITS -> savePath.fits() + CameraFrameCaptured.Format.XISF -> savePath.xisf() + else -> throw IllegalStateException("impossible format") + } + + LOG.info("saved {} file at {}. compressed={}", format, savePath, compressed) + + sender.fireOnEventReceived(CameraFrameCaptured(this, image, compressed, format)) + } } "CCD2" -> { // TODO: Handle Guider Head frame. @@ -427,26 +450,26 @@ internal open class INDICamera( } override fun toString() = "Camera(name=$name, connected=$connected, exposuring=$exposuring," + - " hasCoolerControl=$hasCoolerControl, cooler=$cooler," + - " hasDewHeater=$hasDewHeater, dewHeater=$dewHeater," + - " frameFormats=$frameFormats, canAbort=$canAbort," + - " cfaOffsetX=$cfaOffsetX, cfaOffsetY=$cfaOffsetY, cfaType=$cfaType," + - " exposureMin=$exposureMin, exposureMax=$exposureMax," + - " exposureState=$exposureState, exposureTime=$exposureTime," + - " hasCooler=$hasCooler, hasThermometer=$hasThermometer, canSetTemperature=$canSetTemperature," + - " temperature=$temperature, canSubFrame=$canSubFrame," + - " x=$x, minX=$minX, maxX=$maxX, y=$y, minY=$minY, maxY=$maxY," + - " width=$width, minWidth=$minWidth, maxWidth=$maxWidth, height=$height," + - " minHeight=$minHeight, maxHeight=$maxHeight," + - " canBin=$canBin, maxBinX=$maxBinX, maxBinY=$maxBinY," + - " binX=$binX, binY=$binY, gain=$gain, gainMin=$gainMin," + - " gainMax=$gainMax, offset=$offset, offsetMin=$offsetMin," + - " offsetMax=$offsetMax, hasGuiderHead=$hasGuiderHead," + - " canPulseGuide=$canPulseGuide, pulseGuiding=$pulseGuiding)" + " hasCoolerControl=$hasCoolerControl, cooler=$cooler," + + " hasDewHeater=$hasDewHeater, dewHeater=$dewHeater," + + " frameFormats=$frameFormats, canAbort=$canAbort," + + " cfaOffsetX=$cfaOffsetX, cfaOffsetY=$cfaOffsetY, cfaType=$cfaType," + + " exposureMin=$exposureMin, exposureMax=$exposureMax," + + " exposureState=$exposureState, exposureTime=$exposureTime," + + " hasCooler=$hasCooler, hasThermometer=$hasThermometer, canSetTemperature=$canSetTemperature," + + " temperature=$temperature, canSubFrame=$canSubFrame," + + " x=$x, minX=$minX, maxX=$maxX, y=$y, minY=$minY, maxY=$maxY," + + " width=$width, minWidth=$minWidth, maxWidth=$maxWidth, height=$height," + + " minHeight=$minHeight, maxHeight=$maxHeight," + + " canBin=$canBin, maxBinX=$maxBinX, maxBinY=$maxBinY," + + " binX=$binX, binY=$binY, gain=$gain, gainMin=$gainMin," + + " gainMax=$gainMax, offset=$offset, offsetMin=$offsetMin," + + " offsetMax=$offsetMax, hasGuiderHead=$hasGuiderHead," + + " canPulseGuide=$canPulseGuide, pulseGuiding=$pulseGuiding)" companion object { - @JvmStatic private val COMPRESSION_FORMATS = arrayOf(".fz", ".gz") + @JvmStatic private val COMPRESSION_FORMATS = arrayOf(".fz", ".gz", ".z") @JvmStatic private val LOG = loggerFor() } } diff --git a/nebulosa-indi-device/src/main/kotlin/nebulosa/indi/device/camera/CameraFrameCaptured.kt b/nebulosa-indi-device/src/main/kotlin/nebulosa/indi/device/camera/CameraFrameCaptured.kt index d75cce06d..f39915186 100644 --- a/nebulosa-indi-device/src/main/kotlin/nebulosa/indi/device/camera/CameraFrameCaptured.kt +++ b/nebulosa-indi-device/src/main/kotlin/nebulosa/indi/device/camera/CameraFrameCaptured.kt @@ -1,11 +1,23 @@ package nebulosa.indi.device.camera -import nebulosa.fits.Fits -import java.io.InputStream +import nebulosa.image.format.ImageRepresentation data class CameraFrameCaptured( override val device: Camera, - @JvmField val stream: InputStream?, - @JvmField val fits: Fits?, + @JvmField val image: ImageRepresentation, @JvmField val compressed: Boolean, -) : CameraEvent + @JvmField val format: Format, +) : CameraEvent { + + enum class Format(@JvmField val extension: String) { + FITS("fits"), + XISF("xisf"), + RAW("bin"); + + companion object { + + @JvmStatic + fun from(format: String) = entries.first { format.contains(it.extension, true) } + } + } +} diff --git a/nebulosa-io/src/main/kotlin/nebulosa/io/Io.kt b/nebulosa-io/src/main/kotlin/nebulosa/io/Io.kt index eb8f1c255..30f4c8b26 100644 --- a/nebulosa-io/src/main/kotlin/nebulosa/io/Io.kt +++ b/nebulosa-io/src/main/kotlin/nebulosa/io/Io.kt @@ -183,7 +183,7 @@ fun Buffer.transferFully(source: Source, sink: Sink, byteCount: Long) { while (remainingCount > 0L) { val size = source.read(this, remainingCount) - require(size > 0) { "unexpected end of file" } + if (size < 0L) throw EOFException("unexpected end of file") sink.write(this, size) remainingCount -= size } diff --git a/nebulosa-plate-solving/src/main/kotlin/nebulosa/plate/solving/PlateSolution.kt b/nebulosa-plate-solving/src/main/kotlin/nebulosa/plate/solving/PlateSolution.kt index 4c039bc89..e0ee3c598 100644 --- a/nebulosa-plate-solving/src/main/kotlin/nebulosa/plate/solving/PlateSolution.kt +++ b/nebulosa-plate-solving/src/main/kotlin/nebulosa/plate/solving/PlateSolution.kt @@ -35,13 +35,13 @@ data class PlateSolution( @JvmStatic fun from(header: ReadableHeader): PlateSolution? { + val crval1 = header.getDoubleOrNull(FitsKeyword.CRVAL1)?.deg ?: return null + val crval2 = header.getDoubleOrNull(FitsKeyword.CRVAL2)?.deg ?: return null val (cd11, cd12, _, cd22) = header.computeCdMatrix() val crota2 = header.getDoubleOrNull(FitsKeyword.CROTA2)?.deg ?: atan2(cd12, cd11).rad // https://danmoser.github.io/notes/gai_fits-imgs.html val cdelt1 = header.getDoubleOrNull(FitsKeyword.CDELT1)?.deg ?: (cd11 / cos(crota2)).deg val cdelt2 = header.getDoubleOrNull(FitsKeyword.CDELT2)?.deg ?: (cd22 / cos(crota2)).deg - val crval1 = header.getDoubleOrNull(FitsKeyword.CRVAL1)?.deg ?: return null - val crval2 = header.getDoubleOrNull(FitsKeyword.CRVAL2)?.deg ?: return null val width = header.getIntOrNull(FitsKeyword.NAXIS1) ?: header.getInt("IMAGEW", 0) val height = header.getIntOrNull(FitsKeyword.NAXIS2) ?: header.getInt("IMAGEH", 0) diff --git a/nebulosa-xisf/src/main/kotlin/nebulosa/xisf/XisfFormat.kt b/nebulosa-xisf/src/main/kotlin/nebulosa/xisf/XisfFormat.kt index 5806bf3c2..59db063ef 100644 --- a/nebulosa-xisf/src/main/kotlin/nebulosa/xisf/XisfFormat.kt +++ b/nebulosa-xisf/src/main/kotlin/nebulosa/xisf/XisfFormat.kt @@ -4,8 +4,11 @@ import nebulosa.image.format.Hdu import nebulosa.image.format.ImageFormat import nebulosa.image.format.ImageHdu import nebulosa.io.SeekableSource +import nebulosa.io.sink +import nebulosa.io.transferFully import okio.Buffer import okio.Sink +import java.io.ByteArrayInputStream /** * Extensible Image Serialization Format (XISF) is the native file format of PixInsight. @@ -23,12 +26,15 @@ data object XisfFormat : ImageFormat { // Header length (4) + reserved (4) source.read(buffer, 4 + 4) - val headerLength = buffer.readIntLe().toLong() - buffer.skip(4) // reserved + val headerLength = buffer.readIntLe() + // buffer.skip(4) // reserved + buffer.clear() // XISF Header. - source.read(buffer, headerLength) - val stream = XisfHeaderInputStream(buffer.inputStream()) + val headerData = ByteArray(headerLength) + val headerSink = headerData.sink() + buffer.transferFully(source, headerSink, headerLength.toLong()) + val stream = XisfHeaderInputStream(ByteArrayInputStream(headerData)) val hdus = ArrayList(2) while (true) { diff --git a/nebulosa-xisf/src/main/kotlin/nebulosa/xisf/XisfMonolithicFileHeaderImageData.kt b/nebulosa-xisf/src/main/kotlin/nebulosa/xisf/XisfMonolithicFileHeaderImageData.kt index 89203ae55..7894cd97f 100644 --- a/nebulosa-xisf/src/main/kotlin/nebulosa/xisf/XisfMonolithicFileHeaderImageData.kt +++ b/nebulosa-xisf/src/main/kotlin/nebulosa/xisf/XisfMonolithicFileHeaderImageData.kt @@ -60,20 +60,26 @@ internal data class XisfMonolithicFileHeaderImageData( } private fun readChannel(channel: ImageChannel): FloatArray { - return if (image.pixelStorage == PixelStorageModel.NORMAL) readNormal(channel) - else readPlanar(channel) + val output = FloatArray(numberOfPixels) + readChannelTo(channel, output) + return output + } + + override fun readChannelTo(channel: ImageChannel, output: FloatArray) { + // TODO: Read channel from source only if not initialized (remove lazy from red, green and blue). + if (image.pixelStorage == PixelStorageModel.NORMAL) readNormal(channel, output) + else readPlanar(channel, output) } /** * In the planar storage model, each channel of an image shall be stored as * a contiguous sequence of pixel samples (each channel is stored in a separate block). */ - private fun readPlanar(channel: ImageChannel): FloatArray { + private fun readPlanar(channel: ImageChannel, data: FloatArray): FloatArray { val startIndex = numberOfPixels * image.sampleFormat.byteLength * channel.index source.seek(image.position + startIndex) - val data = FloatArray(numberOfPixels) var remainingPixels = data.size var pos = 0 @@ -118,13 +124,12 @@ internal data class XisfMonolithicFileHeaderImageData( * In the normal storage model, all pixel samples of an image shall be stored as * a contiguous sequence (all pixel samples are stored in a single block). */ - private fun readNormal(channel: ImageChannel): FloatArray { + private fun readNormal(channel: ImageChannel, data: FloatArray): FloatArray { source.seek(image.position) val blockSizeInBytes = numberOfChannels * image.sampleFormat.byteLength val bytesToSkipBefore = channel.index * image.sampleFormat.byteLength val bytesToSkipAfter = blockSizeInBytes - bytesToSkipBefore - image.sampleFormat.byteLength - val data = FloatArray(numberOfPixels) var remainingPixels = data.size var pos = 0 From c1e90f6405ceea31302864fd37ed06a6d7458c28 Mon Sep 17 00:00:00 2001 From: tiagohm Date: Fri, 29 Mar 2024 01:12:05 -0300 Subject: [PATCH 07/15] [api]: Implement XISF read/write --- .../src/main/kotlin/nebulosa/fits/Bitpix.kt | 14 +- .../kotlin/nebulosa/fits/FitsHeaderCard.kt | 2 +- .../nebulosa/fits/FitsHeaderCardFormatter.kt | 17 +- .../nebulosa/fits/FitsHeaderCardType.kt | 3 +- .../nebulosa/image/format/HeaderCard.kt | 2 + .../nebulosa/image/format/HeaderCardType.kt | 6 + .../xisf/AstronomicalImageProperties.kt | 55 ++++++ .../kotlin/nebulosa/xisf/XisfHeaderCard.kt | 187 ++++++++++++++++++ .../nebulosa/xisf/XisfHeaderInputStream.kt | 31 +-- .../nebulosa/xisf/XisfMonolithicFileHeader.kt | 10 +- .../kotlin/nebulosa/xisf/XisfPropertyType.kt | 114 +++++++++++ .../src/test/kotlin/XisfFormatTest.kt | 22 +-- 12 files changed, 420 insertions(+), 43 deletions(-) create mode 100644 nebulosa-image-format/src/main/kotlin/nebulosa/image/format/HeaderCardType.kt create mode 100644 nebulosa-xisf/src/main/kotlin/nebulosa/xisf/AstronomicalImageProperties.kt create mode 100644 nebulosa-xisf/src/main/kotlin/nebulosa/xisf/XisfHeaderCard.kt create mode 100644 nebulosa-xisf/src/main/kotlin/nebulosa/xisf/XisfPropertyType.kt diff --git a/nebulosa-fits/src/main/kotlin/nebulosa/fits/Bitpix.kt b/nebulosa-fits/src/main/kotlin/nebulosa/fits/Bitpix.kt index d5bc2e127..a88e641bb 100644 --- a/nebulosa-fits/src/main/kotlin/nebulosa/fits/Bitpix.kt +++ b/nebulosa-fits/src/main/kotlin/nebulosa/fits/Bitpix.kt @@ -4,13 +4,13 @@ import nebulosa.image.format.HeaderCard import nebulosa.image.format.ReadableHeader import kotlin.math.abs -enum class Bitpix(val type: Class, val code: Int) : HeaderCard by FitsHeaderCard.create(FitsKeyword.BITPIX, code) { - BYTE(Byte::class.javaPrimitiveType!!, 8), - SHORT(Short::class.javaPrimitiveType!!, 16), - INTEGER(Int::class.javaPrimitiveType!!, 32), - LONG(Long::class.javaPrimitiveType!!, 64), - FLOAT(Float::class.javaPrimitiveType!!, -32), - DOUBLE(Double::class.javaPrimitiveType!!, -64); +enum class Bitpix(val code: Int) : HeaderCard by FitsHeaderCard.create(FitsKeyword.BITPIX, code) { + BYTE(8), + SHORT(16), + INTEGER(32), + LONG(64), + FLOAT(-32), + DOUBLE(-64); @JvmField internal val byteLength = abs(code) / 8 diff --git a/nebulosa-fits/src/main/kotlin/nebulosa/fits/FitsHeaderCard.kt b/nebulosa-fits/src/main/kotlin/nebulosa/fits/FitsHeaderCard.kt index 752b63add..81406208b 100644 --- a/nebulosa-fits/src/main/kotlin/nebulosa/fits/FitsHeaderCard.kt +++ b/nebulosa-fits/src/main/kotlin/nebulosa/fits/FitsHeaderCard.kt @@ -12,7 +12,7 @@ import kotlin.math.max data class FitsHeaderCard( override val key: String, override val value: String, - override val comment: String, val type: FitsHeaderCardType, + override val comment: String, override val type: FitsHeaderCardType, ) : HeaderCard, Serializable { internal constructor(parsed: FitsHeaderCardParser) : this( diff --git a/nebulosa-fits/src/main/kotlin/nebulosa/fits/FitsHeaderCardFormatter.kt b/nebulosa-fits/src/main/kotlin/nebulosa/fits/FitsHeaderCardFormatter.kt index 088474020..4ec34e436 100644 --- a/nebulosa-fits/src/main/kotlin/nebulosa/fits/FitsHeaderCardFormatter.kt +++ b/nebulosa-fits/src/main/kotlin/nebulosa/fits/FitsHeaderCardFormatter.kt @@ -1,11 +1,12 @@ package nebulosa.fits +import nebulosa.image.format.HeaderCard import java.util.* import kotlin.math.min object FitsHeaderCardFormatter { - fun format(card: FitsHeaderCard): String { + fun format(card: HeaderCard): String { return with(StringBuilder(FitsHeaderCard.FITS_HEADER_CARD_SIZE)) { appendKey(card) @@ -26,10 +27,10 @@ object FitsHeaderCardFormatter { } @JvmStatic - private fun StringBuilder.appendKey(card: FitsHeaderCard) { + private fun StringBuilder.appendKey(card: HeaderCard) { var key = card.key - if (card.hasHierarchKey) { + if (card is FitsHeaderCard && card.hasHierarchKey) { key = HierarchKeyFormatter.format(key) if (key.length > FitsHeaderCard.MAX_HIERARCH_KEYWORD_LENGTH) { @@ -50,7 +51,7 @@ object FitsHeaderCardFormatter { } @JvmStatic - private fun StringBuilder.appendValue(card: FitsHeaderCard): Int { + private fun StringBuilder.appendValue(card: HeaderCard): Int { val value = card.value if (card.isCommentStyle) { @@ -84,7 +85,7 @@ object FitsHeaderCardFormatter { } @JvmStatic - private fun StringBuilder.appendQuotedValue(card: FitsHeaderCard, from: Int): Int { + private fun StringBuilder.appendQuotedValue(card: HeaderCard, from: Int): Int { // Always leave room for an extra & character at the end... var available = availableCharCount() - QUOTES_LENGTH @@ -158,7 +159,7 @@ object FitsHeaderCardFormatter { } @JvmStatic - private fun StringBuilder.appendLongStringComment(card: FitsHeaderCard) { + private fun StringBuilder.appendLongStringComment(card: HeaderCard) { // We can wrap the comment to our delight, with CONTINUE! val iLast = length - 1 val comment = card.comment @@ -211,7 +212,7 @@ object FitsHeaderCardFormatter { } @JvmStatic - private fun StringBuilder.appendComment(card: FitsHeaderCard): Boolean { + private fun StringBuilder.appendComment(card: HeaderCard): Boolean { val comment = card.comment if (comment.isEmpty()) { @@ -318,7 +319,7 @@ object FitsHeaderCardFormatter { } @JvmStatic - private fun FitsHeaderCard.minTruncatedCommentSize(): Int { + private fun HeaderCard.minTruncatedCommentSize(): Int { var firstWordLength = comment.indexOf(' ') if (firstWordLength < 0) { diff --git a/nebulosa-fits/src/main/kotlin/nebulosa/fits/FitsHeaderCardType.kt b/nebulosa-fits/src/main/kotlin/nebulosa/fits/FitsHeaderCardType.kt index fbadf7fc8..d8b7832b6 100644 --- a/nebulosa-fits/src/main/kotlin/nebulosa/fits/FitsHeaderCardType.kt +++ b/nebulosa-fits/src/main/kotlin/nebulosa/fits/FitsHeaderCardType.kt @@ -1,10 +1,11 @@ package nebulosa.fits +import nebulosa.image.format.HeaderCardType import org.apache.commons.numbers.complex.Complex import java.math.BigDecimal import java.math.BigInteger -enum class FitsHeaderCardType(@JvmField internal val type: Class<*>) { +enum class FitsHeaderCardType(@JvmField internal val type: Class<*>) : HeaderCardType { NONE(Nothing::class.javaObjectType), TEXT(String::class.javaObjectType), BOOLEAN(Boolean::class.javaObjectType), diff --git a/nebulosa-image-format/src/main/kotlin/nebulosa/image/format/HeaderCard.kt b/nebulosa-image-format/src/main/kotlin/nebulosa/image/format/HeaderCard.kt index 86c8687d5..fd74b7fdf 100644 --- a/nebulosa-image-format/src/main/kotlin/nebulosa/image/format/HeaderCard.kt +++ b/nebulosa-image-format/src/main/kotlin/nebulosa/image/format/HeaderCard.kt @@ -2,6 +2,8 @@ package nebulosa.image.format interface HeaderCard : HeaderKey, HeaderValue, Map.Entry { + val type: HeaderCardType + val isCommentStyle: Boolean val isKeyValuePair: Boolean diff --git a/nebulosa-image-format/src/main/kotlin/nebulosa/image/format/HeaderCardType.kt b/nebulosa-image-format/src/main/kotlin/nebulosa/image/format/HeaderCardType.kt new file mode 100644 index 000000000..8bcf6c168 --- /dev/null +++ b/nebulosa-image-format/src/main/kotlin/nebulosa/image/format/HeaderCardType.kt @@ -0,0 +1,6 @@ +package nebulosa.image.format + +interface HeaderCardType { + + val name: String +} diff --git a/nebulosa-xisf/src/main/kotlin/nebulosa/xisf/AstronomicalImageProperties.kt b/nebulosa-xisf/src/main/kotlin/nebulosa/xisf/AstronomicalImageProperties.kt new file mode 100644 index 000000000..b63fac4c9 --- /dev/null +++ b/nebulosa-xisf/src/main/kotlin/nebulosa/xisf/AstronomicalImageProperties.kt @@ -0,0 +1,55 @@ +package nebulosa.xisf + +import nebulosa.fits.FitsHeaderKey +import nebulosa.fits.FitsKeyword + +object AstronomicalImageProperties : Map by mapOf( + "Observer:EmailAddress" to null, + "Observer:Name" to null, + "Observer:PostalAddress" to null, + "Observer:Website" to null, + "Organization:EmailAddress" to null, + "Organization:Name" to null, + "Organization:PostalAddress" to null, + "Organization:Website" to null, + "Observation:CelestialReferenceSystem" to FitsKeyword.RADESYS, + "Observation:BibliographicReferences" to null, + "Observation:Center:Dec" to FitsKeyword.DEC, + "Observation:Center:RA" to FitsKeyword.RA, + "Observation:Center:X" to null, + "Observation:Center:Y" to null, + "Observation:Description" to null, + "Observation:Equinox" to FitsKeyword.EQUINOX, + "Observation:GeodeticReferenceSystem" to null, + "Observation:Location:Elevation" to null, + "Observation:Location:Latitude" to FitsKeyword.SITELAT, + "Observation:Location:Longitude" to FitsKeyword.SITELONG, + "Observation:Location:Name" to null, + "Observation:RelatedResources" to null, + "Observation:Time:End" to FitsKeyword.DATE_END, + "Observation:Time:Start" to null, + "Observation:Title" to null, + "Instrument:Camera:Gain" to FitsKeyword.GAIN, + "Instrument:Camera:ISOSpeed" to FitsKeyword.ISOSPEED, + "Instrument:Camera:Name" to FitsKeyword.CAMERA, + "Instrument:Camera:ReadoutNoise" to FitsKeyword.RDNOISE, + "Instrument:Camera:Rotation" to FitsKeyword.ROTATANG, + "Instrument:Camera:XBinning" to FitsKeyword.XBINNING, + "Instrument:Camera:YBinning" to FitsKeyword.YBINNING, + "Instrument:ExposureTime" to FitsKeyword.EXPOSURE, + "Instrument:Filter:Name" to FitsKeyword.FILTER, + "Instrument:Focuser:Position" to FitsKeyword.FILPOS, + "Instrument:Sensor:TargetTemperature" to null, + "Instrument:Sensor:Temperature" to null, + "Instrument:Sensor:XPixelSize" to FitsKeyword.XPIXSZ, + "Instrument:Sensor:YPixelSize" to FitsKeyword.YPIXSZ, + "Instrument:Telescope:Aperture" to FitsKeyword.APERDIA, + "Instrument:Telescope:CollectingArea" to null, + "Instrument:Telescope:FocalLength" to FitsKeyword.FOCALLEN, + "Instrument:Telescope:Name" to FitsKeyword.INSTRUME, + "Image:FrameNumber" to null, + "Image:GroupId" to null, + "Image:SubgroupId" to null, + "Processing:Description" to null, + // "Processing:History" to null, // Too long. +) diff --git a/nebulosa-xisf/src/main/kotlin/nebulosa/xisf/XisfHeaderCard.kt b/nebulosa-xisf/src/main/kotlin/nebulosa/xisf/XisfHeaderCard.kt new file mode 100644 index 000000000..4079a4228 --- /dev/null +++ b/nebulosa-xisf/src/main/kotlin/nebulosa/xisf/XisfHeaderCard.kt @@ -0,0 +1,187 @@ +package nebulosa.xisf + +import nebulosa.fits.FitsHeaderCardFormatter +import nebulosa.image.format.HeaderCard +import nebulosa.image.format.HeaderKey +import nebulosa.log.loggerFor +import org.apache.commons.numbers.complex.Complex +import java.io.Serializable +import java.math.BigDecimal +import java.math.BigInteger + +data class XisfHeaderCard( + override val key: String, override val value: String, + override val comment: String, override val type: XisfPropertyType, +) : HeaderCard, Serializable { + + override val isCommentStyle + get() = false + + override val isKeyValuePair + get() = !isCommentStyle && key.isNotEmpty() + + override val isBooleanType + get() = type == XisfPropertyType.BOOLEAN + + override val isStringType + get() = type == XisfPropertyType.STRING || + type == XisfPropertyType.TIMEPOINT + + override val isDecimalType + get() = type == XisfPropertyType.FLOAT32 || + type == XisfPropertyType.FLOAT64 || + type == XisfPropertyType.FLOAT128 + + override val isIntegerType + get() = type == XisfPropertyType.UINT8 || + type == XisfPropertyType.UINT16 || + type == XisfPropertyType.UINT32 || + type == XisfPropertyType.UINT64 || + type == XisfPropertyType.UINT128 || + type == XisfPropertyType.INT8 || + type == XisfPropertyType.INT16 || + type == XisfPropertyType.INT32 || + type == XisfPropertyType.INT64 || + type == XisfPropertyType.INT128 + + override val isBlank + get() = if (!isCommentStyle || key.isNotBlank()) false else comment.isBlank() + + private fun getBooleanValue(defaultValue: Boolean): Boolean { + return if (value == "T") true else if (value == "F") false else defaultValue + } + + private fun getNumericValue(asType: Class, defaultValue: T): T { + return try { + val decimal = BigDecimal(value.uppercase().replace('D', 'E')) + + if (Byte::class.javaObjectType.isAssignableFrom(asType)) { + asType.cast(decimal.toByte()) + } else if (Short::class.javaObjectType.isAssignableFrom(asType)) { + asType.cast(decimal.toShort()) + } else if (Int::class.javaObjectType.isAssignableFrom(asType)) { + asType.cast(decimal.toInt()) + } else if (Long::class.javaObjectType.isAssignableFrom(asType)) { + asType.cast(decimal.toLong()) + } else if (Float::class.javaObjectType.isAssignableFrom(asType)) { + asType.cast(decimal.toFloat()) + } else if (Double::class.javaObjectType.isAssignableFrom(asType)) { + asType.cast(decimal.toDouble()) + } else if (BigInteger::class.javaObjectType.isAssignableFrom(asType)) { + asType.cast(decimal.toBigInteger()) + } else if (BigDecimal::class.javaObjectType.isAssignableFrom(asType)) { + asType.cast(decimal) + } else { + throw IllegalArgumentException("unsupported class $asType") + } + } catch (e: NumberFormatException) { + LOG.error("failed to parse numeric value", e) + defaultValue + } + } + + override fun getValue(asType: Class, defaultValue: T): T { + return if (Boolean::class.javaObjectType.isAssignableFrom(asType)) { + asType.cast(getBooleanValue(defaultValue as Boolean)) + } else if (Number::class.javaObjectType.isAssignableFrom(asType)) { + getNumericValue(asType, defaultValue) + } else if (String::class.javaObjectType.isAssignableFrom(asType)) { + asType.cast(value) + } else if (Complex::class.java.isAssignableFrom(asType)) { + asType.cast(Complex.parse(value.trim().uppercase().replace('D', 'E'))) + } else if (value.isBlank()) { + defaultValue + } else { + throw IllegalArgumentException("unsupported class $asType") + } + } + + override fun formatted(): String { + return FitsHeaderCardFormatter.format(this) + } + + companion object { + + @JvmStatic private val LOG = loggerFor() + + @JvmStatic + fun create(header: HeaderKey, value: Boolean): XisfHeaderCard { + return create(header.key, value, header.comment) + } + + @JvmStatic + fun create(header: HeaderKey, value: Int): XisfHeaderCard { + return create(header.key, "$value", header.comment) + } + + @JvmStatic + fun create(header: HeaderKey, value: Long): XisfHeaderCard { + return create(header.key, "$value", header.comment) + } + + @JvmStatic + fun create(header: HeaderKey, value: BigInteger): XisfHeaderCard { + return create(header.key, "$value", header.comment) + } + + @JvmStatic + fun create(header: HeaderKey, value: Float): XisfHeaderCard { + return create(header.key, "$value", header.comment) + } + + @JvmStatic + fun create(header: HeaderKey, value: Double): XisfHeaderCard { + return create(header.key, "$value", header.comment) + } + + @JvmStatic + fun create(key: HeaderKey, value: BigDecimal, comment: String = ""): XisfHeaderCard { + return create(key.key, "$value", comment) + } + + @JvmStatic + fun create(header: HeaderKey, value: String): XisfHeaderCard { + return create(header.key, value, header.comment) + } + + @JvmStatic + fun create(key: String, value: Boolean, comment: String = ""): XisfHeaderCard { + return XisfHeaderCard(key, if (value) "T" else "F", comment, XisfPropertyType.BOOLEAN) + } + + @JvmStatic + fun create(key: String, value: Int, comment: String = ""): XisfHeaderCard { + return XisfHeaderCard(key, "$value", comment, XisfPropertyType.INT32) + } + + @JvmStatic + fun create(key: String, value: Long, comment: String = ""): XisfHeaderCard { + return XisfHeaderCard(key, "$value", comment, XisfPropertyType.INT64) + } + + @JvmStatic + fun create(key: String, value: BigInteger, comment: String = ""): XisfHeaderCard { + return XisfHeaderCard(key, "$value", comment, XisfPropertyType.INT128) + } + + @JvmStatic + fun create(key: String, value: Float, comment: String = ""): XisfHeaderCard { + return XisfHeaderCard(key, "$value", comment, XisfPropertyType.FLOAT32) + } + + @JvmStatic + fun create(key: String, value: Double, comment: String = ""): XisfHeaderCard { + return XisfHeaderCard(key, "$value", comment, XisfPropertyType.FLOAT64) + } + + @JvmStatic + fun create(key: String, value: BigDecimal, comment: String = ""): XisfHeaderCard { + return XisfHeaderCard(key, "$value", comment, XisfPropertyType.FLOAT128) + } + + @JvmStatic + fun create(key: String, value: String, comment: String = ""): XisfHeaderCard { + return XisfHeaderCard(key, value, comment, XisfPropertyType.STRING) + } + } +} diff --git a/nebulosa-xisf/src/main/kotlin/nebulosa/xisf/XisfHeaderInputStream.kt b/nebulosa-xisf/src/main/kotlin/nebulosa/xisf/XisfHeaderInputStream.kt index 38955627f..ccdb7e3f7 100644 --- a/nebulosa-xisf/src/main/kotlin/nebulosa/xisf/XisfHeaderInputStream.kt +++ b/nebulosa-xisf/src/main/kotlin/nebulosa/xisf/XisfHeaderInputStream.kt @@ -1,8 +1,7 @@ package nebulosa.xisf import com.fasterxml.aalto.stax.InputFactoryImpl -import nebulosa.fits.FitsHeaderCard -import nebulosa.fits.FitsHeaderCardType +import nebulosa.image.format.HeaderCard import nebulosa.io.ByteOrder import nebulosa.xisf.XisfMonolithicFileHeader.* import nebulosa.xml.attribute @@ -45,9 +44,8 @@ class XisfHeaderInputStream(source: InputStream) : Closeable { val pixelStorage = reader.attribute("pixelStorage")?.uppercase()?.let(PixelStorageModel::valueOf) val byteOrder = reader.attribute("byteOrder")?.uppercase()?.let(ByteOrder::valueOf) val compression = reader.attribute("compression")?.let { CompressionFormat.parse(it) } + val bounds = reader.attribute("bounds")?.split(":")?.let { it[0].toFloat()..it[1].toFloat() } val (keywords, thumbnail) = parseKeywords() - // TODO: bounds (Representable Range) - // TODO: Convert metadata into FITS keywords? return Image( width.toInt(), height.toInt(), numberOfChannels.toInt(), @@ -55,14 +53,15 @@ class XisfHeaderInputStream(source: InputStream) : Closeable { sampleFormat, colorSpace ?: ColorSpace.GRAY, pixelStorage ?: PixelStorageModel.PLANAR, byteOrder ?: ByteOrder.LITTLE, - compression, keywords, thumbnail, + compression, bounds ?: XisfMonolithicFileHeader.DEFAULT_BOUNDS, + keywords, thumbnail, ) } - private fun parseKeywords(): Pair, Image?> { + private fun parseKeywords(): Pair, Image?> { val name = reader.localName - val keywords = ArrayList() + val keywords = ArrayList() var thumbnail: Image? = null while (reader.hasNext()) { @@ -74,6 +73,7 @@ class XisfHeaderInputStream(source: InputStream) : Closeable { when (reader.localName) { "FITSKeyword" -> keywords.add(parseFITSKeyword()) "Thumbnail" -> thumbnail = parseImage() + "Property" -> keywords.add(parseProperty() ?: continue) } } } @@ -81,15 +81,20 @@ class XisfHeaderInputStream(source: InputStream) : Closeable { return keywords to thumbnail } - private fun parseFITSKeyword(): FitsHeaderCard { + private fun parseFITSKeyword(): HeaderCard { val name = reader.attribute("name") ?: "" val value = reader.attribute("value")?.trim() ?: "" - val trimmedValue = value.trim('\'') val comment = reader.attribute("comment") ?: "" - val isStringType = value.startsWith('\'') && value.endsWith('\'') - // TODO: Identify other types - val type = if (isStringType) FitsHeaderCardType.TEXT else FitsHeaderCardType.NONE - return FitsHeaderCard(name, trimmedValue, comment, type) + val type = XisfPropertyType.fromValue(value) + return XisfHeaderCard(name, value.trim('\'').trim(), comment, type) + } + + private fun parseProperty(): HeaderCard? { + val id = reader.attribute("id")!! + val key = AstronomicalImageProperties[id] ?: return null + val propertyType = XisfPropertyType.fromTypeName(reader.attribute("type")!!) ?: return null + val value = reader.attribute("value") ?: reader.elementText.trim() + return XisfHeaderCard(key.key, value, key.comment, propertyType) } override fun close() { diff --git a/nebulosa-xisf/src/main/kotlin/nebulosa/xisf/XisfMonolithicFileHeader.kt b/nebulosa-xisf/src/main/kotlin/nebulosa/xisf/XisfMonolithicFileHeader.kt index fd70065d6..00d79d997 100644 --- a/nebulosa-xisf/src/main/kotlin/nebulosa/xisf/XisfMonolithicFileHeader.kt +++ b/nebulosa-xisf/src/main/kotlin/nebulosa/xisf/XisfMonolithicFileHeader.kt @@ -1,6 +1,6 @@ package nebulosa.xisf -import nebulosa.fits.FitsHeaderCard +import nebulosa.image.format.HeaderCard import nebulosa.io.ByteOrder sealed interface XisfMonolithicFileHeader { @@ -68,7 +68,13 @@ sealed interface XisfMonolithicFileHeader { @JvmField val sampleFormat: SampleFormat, @JvmField val colorSpace: ColorSpace, @JvmField val pixelStorage: PixelStorageModel, @JvmField val byteOrder: ByteOrder, @JvmField val compressionFormat: CompressionFormat? = null, - @JvmField val keywords: List = emptyList(), + @JvmField val bounds: ClosedFloatingPointRange = DEFAULT_BOUNDS, + @JvmField val keywords: List = emptyList(), @JvmField val thumbnail: Image? = null, ) : XisfMonolithicFileHeader + + companion object { + + @JvmStatic val DEFAULT_BOUNDS = 0f..1f + } } diff --git a/nebulosa-xisf/src/main/kotlin/nebulosa/xisf/XisfPropertyType.kt b/nebulosa-xisf/src/main/kotlin/nebulosa/xisf/XisfPropertyType.kt new file mode 100644 index 000000000..543e7c0c2 --- /dev/null +++ b/nebulosa-xisf/src/main/kotlin/nebulosa/xisf/XisfPropertyType.kt @@ -0,0 +1,114 @@ +package nebulosa.xisf + +import nebulosa.image.format.HeaderCardType +import java.math.BigDecimal +import java.math.BigInteger + +enum class XisfPropertyType(@JvmField val typeName: String) : HeaderCardType { + BOOLEAN("Boolean"), + INT8("Int8"), + UINT8("UInt8"), + INT16("Int16"), + UINT16("UInt16"), + INT32("Int32"), + UINT32("UInt32"), + INT64("Int64"), + UINT64("UInt64"), + INT128("Int128"), + UINT128("UInt128"), + FLOAT32("Float32"), + FLOAT64("Float64"), + FLOAT128("Float128"), + COMPLEX32("Complex32"), + COMPLEX64("Complex64"), + COMPLEX128("Complex128"), + STRING("String"), + TIMEPOINT("TimePoint"), + VECTOR_INT8("I8Vector"), + VECTOR_UINT8("UI8Vector"), + VECTOR_INT16("I16Vector"), + VECTOR_UINT16("UI16Vector"), + VECTOR_INT32("I32Vector"), + VECTOR_UINT32("UI32Vector"), + VECTOR_INT64("I64Vector"), + VECTOR_UINT64("UI64Vector"), + VECTOR_INT128("I128Vector"), + VECTOR_UINT128("UI128Vector"), + VECTOR_FLOAT32("F32Vector"), + VECTOR_FLOAT64("F64Vector"), + VECTOR_FLOAT128("F128Vector"), + VECTOR_COMPLEX32("C32Vector"), + VECTOR_COMPLEX64("C64Vector"), + VECTOR_COMPLEX128("C128Vector"), + MATRIX_INT8("I8Matrix"), + MATRIX_UINT8("UI8Matrix"), + MATRIX_INT16("I16Matrix"), + MATRIX_UINT16("UI16Matrix"), + MATRIX_INT32("I32Matrix"), + MATRIX_UINT32("UI32Matrix"), + MATRIX_INT64("I64Matrix"), + MATRIX_UINT64("UI64Matrix"), + MATRIX_INT128("I128Matrix"), + MATRIX_UINT128("UI128Matrix"), + MATRIX_FLOAT32("F32Matrix"), + MATRIX_FLOAT64("F64Matrix"), + MATRIX_FLOAT128("F128Matrix"), + MATRIX_COMPLEX32("C32Matrix"), + MATRIX_COMPLEX64("C64Matrix"), + MATRIX_COMPLEX128("C128Matrix"); + + companion object { + + @JvmStatic private val MAPPED = entries.associateBy { it.typeName } + + @JvmStatic + fun fromTypeName(typeName: String) = MAPPED[typeName] + + @JvmStatic + fun fromValue(value: String) = if (value.startsWith('\'') && value.endsWith('\'')) STRING + else if (value == "T" || value == "F") BOOLEAN + else if (value.isBlank()) STRING + else if ('.' in value || 'D' in value || 'E' in value) getDecimalType(value) + else getIntegerType(value) + + private fun getDecimalType(value: String): XisfPropertyType { + val transformedValue = if ('D' in value) { + // Convert the Double Scientific Notation specified by FITS to pure IEEE. + value.uppercase().replace('D', 'E') + } else { + value + } + + val big = BigDecimal(transformedValue) + + // Check for zero, and deal with it separately... + if (big.stripTrailingZeros().compareTo(BigDecimal.ZERO) == 0) { + val decimals = big.scale() + + return if (decimals <= 7) FLOAT32 + else if (decimals <= 16) FLOAT64 + else FLOAT128 + } + + // Now non-zero values... + val decimals = big.precision() - 1 + + val f = big.toFloat() + if (decimals <= 7 && f != 0.0f && f.isFinite()) { + return FLOAT32 + } + + val d = big.toDouble() + + return if (decimals <= 16 && d != 0.0 && d.isFinite()) FLOAT64 + else FLOAT128 + } + + private fun getIntegerType(value: String): XisfPropertyType { + val bits = BigInteger(value).bitLength() + return if (bits < 32) INT32 + else if (bits < 64) INT64 + else INT128 + } + } +} diff --git a/nebulosa-xisf/src/test/kotlin/XisfFormatTest.kt b/nebulosa-xisf/src/test/kotlin/XisfFormatTest.kt index b7ade6e09..fe3e0c97a 100644 --- a/nebulosa-xisf/src/test/kotlin/XisfFormatTest.kt +++ b/nebulosa-xisf/src/test/kotlin/XisfFormatTest.kt @@ -24,7 +24,7 @@ class XisfFormatTest : FitsStringSpec() { width shouldBeExactly 512 height shouldBeExactly 512 numberOfChannels shouldBeExactly 1 - header shouldHaveSize 22 + header shouldHaveSize 29 data.red.size shouldBeExactly 512 * 512 data.green shouldBeSameInstanceAs data.red data.blue shouldBeSameInstanceAs data.green @@ -43,7 +43,7 @@ class XisfFormatTest : FitsStringSpec() { width shouldBeExactly 512 height shouldBeExactly 512 numberOfChannels shouldBeExactly 1 - header shouldHaveSize 22 + header shouldHaveSize 29 data.red.size shouldBeExactly 512 * 512 data.green shouldBeSameInstanceAs data.red data.blue shouldBeSameInstanceAs data.green @@ -62,7 +62,7 @@ class XisfFormatTest : FitsStringSpec() { width shouldBeExactly 512 height shouldBeExactly 512 numberOfChannels shouldBeExactly 1 - header shouldHaveSize 22 + header shouldHaveSize 29 data.red.size shouldBeExactly 512 * 512 data.green shouldBeSameInstanceAs data.red data.blue shouldBeSameInstanceAs data.green @@ -81,7 +81,7 @@ class XisfFormatTest : FitsStringSpec() { width shouldBeExactly 512 height shouldBeExactly 512 numberOfChannels shouldBeExactly 1 - header shouldHaveSize 22 + header shouldHaveSize 29 data.red.size shouldBeExactly 512 * 512 data.green shouldBeSameInstanceAs data.red data.blue shouldBeSameInstanceAs data.green @@ -100,7 +100,7 @@ class XisfFormatTest : FitsStringSpec() { width shouldBeExactly 512 height shouldBeExactly 512 numberOfChannels shouldBeExactly 1 - header shouldHaveSize 22 + header shouldHaveSize 29 data.red.size shouldBeExactly 512 * 512 data.green shouldBeSameInstanceAs data.red data.blue shouldBeSameInstanceAs data.green @@ -119,7 +119,7 @@ class XisfFormatTest : FitsStringSpec() { width shouldBeExactly 512 height shouldBeExactly 512 numberOfChannels shouldBeExactly 3 - header shouldHaveSize 22 + header shouldHaveSize 29 data.red.size shouldBeExactly 512 * 512 data.green shouldNotBeSameInstanceAs data.red data.blue shouldNotBeSameInstanceAs data.green @@ -138,7 +138,7 @@ class XisfFormatTest : FitsStringSpec() { width shouldBeExactly 512 height shouldBeExactly 512 numberOfChannels shouldBeExactly 3 - header shouldHaveSize 22 + header shouldHaveSize 29 data.red.size shouldBeExactly 512 * 512 data.green shouldNotBeSameInstanceAs data.red data.blue shouldNotBeSameInstanceAs data.green @@ -157,7 +157,7 @@ class XisfFormatTest : FitsStringSpec() { width shouldBeExactly 512 height shouldBeExactly 512 numberOfChannels shouldBeExactly 3 - header shouldHaveSize 22 + header shouldHaveSize 29 data.red.size shouldBeExactly 512 * 512 data.green shouldNotBeSameInstanceAs data.red data.blue shouldNotBeSameInstanceAs data.green @@ -176,7 +176,7 @@ class XisfFormatTest : FitsStringSpec() { width shouldBeExactly 512 height shouldBeExactly 512 numberOfChannels shouldBeExactly 3 - header shouldHaveSize 22 + header shouldHaveSize 29 data.red.size shouldBeExactly 512 * 512 data.green shouldNotBeSameInstanceAs data.red data.blue shouldNotBeSameInstanceAs data.green @@ -195,7 +195,7 @@ class XisfFormatTest : FitsStringSpec() { width shouldBeExactly 512 height shouldBeExactly 512 numberOfChannels shouldBeExactly 3 - header shouldHaveSize 22 + header shouldHaveSize 29 data.red.size shouldBeExactly 512 * 512 data.green shouldNotBeSameInstanceAs data.red data.blue shouldNotBeSameInstanceAs data.green @@ -214,7 +214,7 @@ class XisfFormatTest : FitsStringSpec() { width shouldBeExactly 512 height shouldBeExactly 512 numberOfChannels shouldBeExactly 1 - header shouldHaveSize 22 + header shouldHaveSize 29 data.red.size shouldBeExactly 512 * 512 data.green shouldBeSameInstanceAs data.red data.blue shouldBeSameInstanceAs data.green From 17be4b02b3d1f9e28785a370edac864eb1dc3939 Mon Sep 17 00:00:00 2001 From: tiagohm Date: Fri, 29 Mar 2024 01:38:08 -0300 Subject: [PATCH 08/15] [api]: Implement XISF read/write --- nebulosa-fits/build.gradle.kts | 2 +- .../kotlin/nebulosa/fits/FitsHeaderCard.kt | 56 ---- nebulosa-image-format/build.gradle.kts | 1 + .../nebulosa/image/format/HeaderCard.kt | 3 +- .../nebulosa/image/format/HeaderValue.kt | 52 ++- ...mTest.kt => FitsTransformAlgorithmTest.kt} | 110 +++---- .../test/kotlin/XisfTransformAlgorithmTest.kt | 303 ++++++++++++++++++ .../kotlin/nebulosa/xisf/XisfHeaderCard.kt | 56 ---- settings.gradle.kts | 1 + 9 files changed, 414 insertions(+), 170 deletions(-) rename nebulosa-image/src/test/kotlin/{TransformAlgorithmTest.kt => FitsTransformAlgorithmTest.kt} (66%) create mode 100644 nebulosa-image/src/test/kotlin/XisfTransformAlgorithmTest.kt diff --git a/nebulosa-fits/build.gradle.kts b/nebulosa-fits/build.gradle.kts index e6a2aa750..cec8ef9cb 100644 --- a/nebulosa-fits/build.gradle.kts +++ b/nebulosa-fits/build.gradle.kts @@ -7,7 +7,7 @@ dependencies { api(project(":nebulosa-math")) api(project(":nebulosa-io")) api(project(":nebulosa-image-format")) - api("org.apache.commons:commons-numbers-complex:1.1") + api(libs.apache.numbers.complex) implementation(project(":nebulosa-log")) testImplementation(project(":nebulosa-test")) } diff --git a/nebulosa-fits/src/main/kotlin/nebulosa/fits/FitsHeaderCard.kt b/nebulosa-fits/src/main/kotlin/nebulosa/fits/FitsHeaderCard.kt index 81406208b..c4571dc62 100644 --- a/nebulosa-fits/src/main/kotlin/nebulosa/fits/FitsHeaderCard.kt +++ b/nebulosa-fits/src/main/kotlin/nebulosa/fits/FitsHeaderCard.kt @@ -2,9 +2,7 @@ package nebulosa.fits import nebulosa.image.format.HeaderCard import nebulosa.image.format.HeaderKey -import nebulosa.log.loggerFor import okio.Buffer -import org.apache.commons.numbers.complex.Complex import java.io.Serializable import java.math.BigDecimal import java.math.BigInteger @@ -37,69 +35,15 @@ data class FitsHeaderCard( override val isIntegerType get() = type == FitsHeaderCardType.INTEGER || type == FitsHeaderCardType.BIG_INTEGER - override val isBlank - get() = if (!isCommentStyle || key.isNotBlank()) false else comment.isBlank() - val hasHierarchKey get() = isHierarchKey(key) - private fun getBooleanValue(defaultValue: Boolean): Boolean { - return if (value == "T") true else if (value == "F") false else defaultValue - } - - private fun getNumericValue(asType: Class, defaultValue: T): T { - return try { - val decimal = BigDecimal(value.uppercase().replace('D', 'E')) - - if (Byte::class.javaObjectType.isAssignableFrom(asType)) { - asType.cast(decimal.toByte()) - } else if (Short::class.javaObjectType.isAssignableFrom(asType)) { - asType.cast(decimal.toShort()) - } else if (Int::class.javaObjectType.isAssignableFrom(asType)) { - asType.cast(decimal.toInt()) - } else if (Long::class.javaObjectType.isAssignableFrom(asType)) { - asType.cast(decimal.toLong()) - } else if (Float::class.javaObjectType.isAssignableFrom(asType)) { - asType.cast(decimal.toFloat()) - } else if (Double::class.javaObjectType.isAssignableFrom(asType)) { - asType.cast(decimal.toDouble()) - } else if (BigInteger::class.javaObjectType.isAssignableFrom(asType)) { - asType.cast(decimal.toBigInteger()) - } else if (BigDecimal::class.javaObjectType.isAssignableFrom(asType)) { - asType.cast(decimal) - } else { - throw IllegalArgumentException("unsupported class $asType") - } - } catch (e: NumberFormatException) { - LOG.error("failed to parse numeric value", e) - defaultValue - } - } - - override fun getValue(asType: Class, defaultValue: T): T { - return if (Boolean::class.javaObjectType.isAssignableFrom(asType)) { - asType.cast(getBooleanValue(defaultValue as Boolean)) - } else if (Number::class.javaObjectType.isAssignableFrom(asType)) { - getNumericValue(asType, defaultValue) - } else if (String::class.javaObjectType.isAssignableFrom(asType)) { - asType.cast(value) - } else if (Complex::class.java.isAssignableFrom(asType)) { - asType.cast(Complex.parse(value.trim().uppercase().replace('D', 'E'))) - } else if (value.isBlank()) { - defaultValue - } else { - throw IllegalArgumentException("unsupported class $asType") - } - } - override fun formatted(): String { return FitsHeaderCardFormatter.format(this) } companion object { - @JvmStatic private val LOG = loggerFor() - const val FITS_HEADER_CARD_SIZE = 80 const val MAX_KEYWORD_LENGTH = 8 const val STRING_QUOTES_LENGTH = 2 diff --git a/nebulosa-image-format/build.gradle.kts b/nebulosa-image-format/build.gradle.kts index bc8cae46b..f21b2894d 100644 --- a/nebulosa-image-format/build.gradle.kts +++ b/nebulosa-image-format/build.gradle.kts @@ -5,6 +5,7 @@ plugins { dependencies { api(project(":nebulosa-io")) + api(libs.apache.numbers.complex) implementation(project(":nebulosa-log")) testImplementation(project(":nebulosa-test")) } diff --git a/nebulosa-image-format/src/main/kotlin/nebulosa/image/format/HeaderCard.kt b/nebulosa-image-format/src/main/kotlin/nebulosa/image/format/HeaderCard.kt index fd74b7fdf..005ce5d53 100644 --- a/nebulosa-image-format/src/main/kotlin/nebulosa/image/format/HeaderCard.kt +++ b/nebulosa-image-format/src/main/kotlin/nebulosa/image/format/HeaderCard.kt @@ -19,7 +19,8 @@ interface HeaderCard : HeaderKey, HeaderValue, Map.Entry { val isNumericType get() = isDecimalType || isIntegerType - val isBlank: Boolean + val isBlank + get() = if (!isCommentStyle || key.isNotBlank()) false else comment.isBlank() companion object { diff --git a/nebulosa-image-format/src/main/kotlin/nebulosa/image/format/HeaderValue.kt b/nebulosa-image-format/src/main/kotlin/nebulosa/image/format/HeaderValue.kt index 2f0d528e4..997bd211c 100644 --- a/nebulosa-image-format/src/main/kotlin/nebulosa/image/format/HeaderValue.kt +++ b/nebulosa-image-format/src/main/kotlin/nebulosa/image/format/HeaderValue.kt @@ -1,10 +1,60 @@ package nebulosa.image.format +import org.apache.commons.numbers.complex.Complex +import java.math.BigDecimal +import java.math.BigInteger + interface HeaderValue { val value: String - fun getValue(asType: Class, defaultValue: T): T + fun getBooleanValue(defaultValue: Boolean): Boolean { + return if (value == "T") true else if (value == "F") false else defaultValue + } + + fun getNumericValue(asType: Class, defaultValue: T): T { + return try { + val decimal = BigDecimal(value.uppercase().replace('D', 'E')) + + if (Byte::class.javaObjectType.isAssignableFrom(asType)) { + asType.cast(decimal.toByte()) + } else if (Short::class.javaObjectType.isAssignableFrom(asType)) { + asType.cast(decimal.toShort()) + } else if (Int::class.javaObjectType.isAssignableFrom(asType)) { + asType.cast(decimal.toInt()) + } else if (Long::class.javaObjectType.isAssignableFrom(asType)) { + asType.cast(decimal.toLong()) + } else if (Float::class.javaObjectType.isAssignableFrom(asType)) { + asType.cast(decimal.toFloat()) + } else if (Double::class.javaObjectType.isAssignableFrom(asType)) { + asType.cast(decimal.toDouble()) + } else if (BigInteger::class.javaObjectType.isAssignableFrom(asType)) { + asType.cast(decimal.toBigInteger()) + } else if (BigDecimal::class.javaObjectType.isAssignableFrom(asType)) { + asType.cast(decimal) + } else { + throw IllegalArgumentException("unsupported class $asType") + } + } catch (e: NumberFormatException) { + defaultValue + } + } + + fun getValue(asType: Class, defaultValue: T): T { + return if (Boolean::class.javaObjectType.isAssignableFrom(asType)) { + asType.cast(getBooleanValue(defaultValue as Boolean)) + } else if (Number::class.javaObjectType.isAssignableFrom(asType)) { + getNumericValue(asType, defaultValue) + } else if (String::class.javaObjectType.isAssignableFrom(asType)) { + asType.cast(value) + } else if (Complex::class.java.isAssignableFrom(asType)) { + asType.cast(Complex.parse(value.trim().uppercase().replace('D', 'E'))) + } else if (value.isBlank()) { + defaultValue + } else { + throw IllegalArgumentException("unsupported class $asType") + } + } fun formatted(): String } diff --git a/nebulosa-image/src/test/kotlin/TransformAlgorithmTest.kt b/nebulosa-image/src/test/kotlin/FitsTransformAlgorithmTest.kt similarity index 66% rename from nebulosa-image/src/test/kotlin/TransformAlgorithmTest.kt rename to nebulosa-image/src/test/kotlin/FitsTransformAlgorithmTest.kt index 8e1a0b309..6f818f193 100644 --- a/nebulosa-image/src/test/kotlin/TransformAlgorithmTest.kt +++ b/nebulosa-image/src/test/kotlin/FitsTransformAlgorithmTest.kt @@ -11,27 +11,27 @@ import nebulosa.image.algorithms.transformation.convolution.* import nebulosa.image.format.ImageChannel import nebulosa.test.FitsStringSpec -class TransformAlgorithmTest : FitsStringSpec() { +class FitsTransformAlgorithmTest : FitsStringSpec() { init { "mono:raw" { val mImage = Image.open(NGC3344_MONO_8_FITS_PATH.fits()) - mImage.save("mono-raw").second shouldBe "e17cfc29c3b343409cd8617b6913330e" + mImage.save("fits-mono-raw").second shouldBe "e17cfc29c3b343409cd8617b6913330e" } "mono:vertical flip" { val mImage = Image.open(NGC3344_MONO_8_FITS_PATH.fits()) mImage.transform(VerticalFlip) - mImage.save("mono-vertical-flip").second shouldBe "262260dfe719726c0e7829a088279a21" + mImage.save("fits-mono-vertical-flip").second shouldBe "262260dfe719726c0e7829a088279a21" } "mono:horizontal flip" { val mImage = Image.open(NGC3344_MONO_8_FITS_PATH.fits()) mImage.transform(HorizontalFlip) - mImage.save("mono-horizontal-flip").second shouldBe "daf0f05db5de3750962f338527564b27" + mImage.save("fits-mono-horizontal-flip").second shouldBe "daf0f05db5de3750962f338527564b27" } "mono:vertical & horizontal flip" { val mImage = Image.open(NGC3344_MONO_8_FITS_PATH.fits()) mImage.transform(VerticalFlip, HorizontalFlip) - mImage.save("mono-vertical-horizontal-flip").second shouldBe "3bc81f579a0e34ce9312c3b242209166" + mImage.save("fits-mono-vertical-horizontal-flip").second shouldBe "3bc81f579a0e34ce9312c3b242209166" } "mono:subframe" { val mImage = Image.open(NGC3344_MONO_8_FITS_PATH.fits()) @@ -39,87 +39,87 @@ class TransformAlgorithmTest : FitsStringSpec() { nImage.width shouldBeExactly 16 nImage.height shouldBeExactly 16 nImage.mono.shouldBeTrue() - nImage.save("mono-subframe").second shouldBe "4d9984e778f82dde10b9aeeee7a29fe0" + nImage.save("fits-mono-subframe").second shouldBe "4d9984e778f82dde10b9aeeee7a29fe0" } "mono:sharpen" { val mImage = Image.open(NGC3344_MONO_8_FITS_PATH.fits()) mImage.transform(Sharpen) - mImage.save("mono-sharpen").second shouldBe "0b162242a4e673f6480b5206cf49ca50" + mImage.save("fits-mono-sharpen").second shouldBe "0b162242a4e673f6480b5206cf49ca50" } "mono:mean" { val mImage = Image.open(NGC3344_MONO_8_FITS_PATH.fits()) mImage.transform(Mean) - mImage.save("mono-mean").second shouldBe "cf866292f657c379ae3965931dd8eeea" + mImage.save("fits-mono-mean").second shouldBe "cf866292f657c379ae3965931dd8eeea" } "mono:invert" { val mImage = Image.open(NGC3344_MONO_8_FITS_PATH.fits()) mImage.transform(Invert) - mImage.save("mono-invert").second shouldBe "6e94463bb5b9561de1f0ee0a154db53e" + mImage.save("fits-mono-invert").second shouldBe "6e94463bb5b9561de1f0ee0a154db53e" } "mono:emboss" { val mImage = Image.open(NGC3344_MONO_8_FITS_PATH.fits()) mImage.transform(Emboss) - mImage.save("mono-emboss").second shouldBe "94a8ef5e4573e392d087cf10c905ba12" + mImage.save("fits-mono-emboss").second shouldBe "94a8ef5e4573e392d087cf10c905ba12" } "mono:edges" { val mImage = Image.open(NGC3344_MONO_8_FITS_PATH.fits()) mImage.transform(Edges) - mImage.save("mono-edges").second shouldBe "27ccd5f5e6098d0cae27e7495e18dd72" + mImage.save("fits-mono-edges").second shouldBe "27ccd5f5e6098d0cae27e7495e18dd72" } "mono:blur" { val mImage = Image.open(NGC3344_MONO_8_FITS_PATH.fits()) mImage.transform(Blur) - mImage.save("mono-blur").second shouldBe "f2c5466dccf71b5c4bee86c5fbbb95fc" + mImage.save("fits-mono-blur").second shouldBe "f2c5466dccf71b5c4bee86c5fbbb95fc" } "mono:gaussian blur" { val mImage = Image.open(NGC3344_MONO_8_FITS_PATH.fits()) mImage.transform(GaussianBlur(sigma = 5.0, size = 9)) - mImage.save("mono-gaussian-blur").second shouldBe "69057b0c4461fb0d55b779da9e72fd69" + mImage.save("fits-mono-gaussian-blur").second shouldBe "69057b0c4461fb0d55b779da9e72fd69" } "mono:STF:midtone = 0.1, shadow = 0.0, highlight = 1.0" { val mImage = Image.open(NGC3344_MONO_8_FITS_PATH.fits()) mImage.transform(ScreenTransformFunction(0.1f)) - mImage.save("mono-stf-01-00-10").second shouldBe "22c0bd985e70a01330722d912869d6ee" + mImage.save("fits-mono-stf-01-00-10").second shouldBe "22c0bd985e70a01330722d912869d6ee" } "mono:STF:midtone = 0.9, shadow = 0.0, highlight = 1.0" { val mImage = Image.open(NGC3344_MONO_8_FITS_PATH.fits()) mImage.transform(ScreenTransformFunction(0.9f)) - mImage.save("mono-stf-09-00-10").second shouldBe "553ccb7546dce3a8f742d5e8f7c58a3f" + mImage.save("fits-mono-stf-09-00-10").second shouldBe "553ccb7546dce3a8f742d5e8f7c58a3f" } "mono:STF:midtone = 0.1, shadow = 0.5, highlight = 1.0" { val mImage = Image.open(NGC3344_MONO_8_FITS_PATH.fits()) mImage.transform(ScreenTransformFunction(0.1f, shadow = 0.5f)) - mImage.save("mono-stf-01-05-10").second shouldBe "f31db854fab72033dce2f8c572ec6783" + mImage.save("fits-mono-stf-01-05-10").second shouldBe "f31db854fab72033dce2f8c572ec6783" } "mono:STF:midtone = 0.9, shadow = 0.5, highlight = 1.0" { val mImage = Image.open(NGC3344_MONO_8_FITS_PATH.fits()) mImage.transform(ScreenTransformFunction(0.9f, shadow = 0.5f)) - mImage.save("mono-stf-09-05-10").second shouldBe "633b49c4a1dbb5ad8e6a9d74f330636d" + mImage.save("fits-mono-stf-09-05-10").second shouldBe "633b49c4a1dbb5ad8e6a9d74f330636d" } "mono:STF:midtone = 0.1, shadow = 0.0, highlight = 0.5" { val mImage = Image.open(NGC3344_MONO_8_FITS_PATH.fits()) mImage.transform(ScreenTransformFunction(0.1f, highlight = 0.5f)) - mImage.save("mono-stf-01-00-05").second shouldBe "26036937eb3e5f99cd6129f709ce4b31" + mImage.save("fits-mono-stf-01-00-05").second shouldBe "26036937eb3e5f99cd6129f709ce4b31" } "mono:STF:midtone = 0.9, shadow = 0.0, highlight = 0.5" { val mImage = Image.open(NGC3344_MONO_8_FITS_PATH.fits()) mImage.transform(ScreenTransformFunction(0.9f, highlight = 0.5f)) - mImage.save("mono-stf-09-00-05").second shouldBe "e8f694dae666ac15ce2f8a169eb84024" + mImage.save("fits-mono-stf-09-00-05").second shouldBe "e8f694dae666ac15ce2f8a169eb84024" } "mono:STF:midtone = 0.1, shadow = 0.4, highlight = 0.6" { val mImage = Image.open(NGC3344_MONO_8_FITS_PATH.fits()) mImage.transform(ScreenTransformFunction(0.1f, 0.4f, 0.6f)) - mImage.save("mono-stf-01-04-06").second shouldBe "5226aba21669a24f985703b3e7220568" + mImage.save("fits-mono-stf-01-04-06").second shouldBe "5226aba21669a24f985703b3e7220568" } "mono:STF:midtone = 0.9, shadow = 0.4, highlight = 0.6" { val mImage = Image.open(NGC3344_MONO_8_FITS_PATH.fits()) mImage.transform(ScreenTransformFunction(0.9f, 0.4f, 0.6f)) - mImage.save("mono-stf-09-04-06").second shouldBe "c2acb25ef7be92a51f63e673ec9a850f" + mImage.save("fits-mono-stf-09-04-06").second shouldBe "c2acb25ef7be92a51f63e673ec9a850f" } "mono:auto STF" { val mImage = Image.open(NGC3344_MONO_8_FITS_PATH.fits()) mImage.transform(AutoScreenTransformFunction) - mImage.save("mono-auto-stf").second shouldBe "e17cfc29c3b343409cd8617b6913330e" + mImage.save("fits-mono-auto-stf").second shouldBe "e17cfc29c3b343409cd8617b6913330e" } "!mono:reload" { val mImage0 = Image.open(NGC3344_MONO_8_FITS_PATH.fits()) @@ -128,26 +128,26 @@ class TransformAlgorithmTest : FitsStringSpec() { mImage1.transform(Invert) mImage0.load(mImage1.hdu) - mImage0.save("mono-reload").second shouldBe "6e94463bb5b9561de1f0ee0a154db53e" + mImage0.save("fits-mono-reload").second shouldBe "6e94463bb5b9561de1f0ee0a154db53e" } "color:raw" { val mImage = Image.open(NGC3344_COLOR_32_FITS_PATH.fits()) - mImage.save("color-raw").second shouldBe "18fb83e240bc7a4cbafbc1aba2741db6" + mImage.save("fits-color-raw").second shouldBe "18fb83e240bc7a4cbafbc1aba2741db6" } "color:vertical flip" { val mImage = Image.open(NGC3344_COLOR_32_FITS_PATH.fits()) mImage.transform(VerticalFlip) - mImage.save("color-vertical-flip").second shouldBe "b717ecda5c5bba50cfa06304ef2bca88" + mImage.save("fits-color-vertical-flip").second shouldBe "b717ecda5c5bba50cfa06304ef2bca88" } "color:horizontal flip" { val mImage = Image.open(NGC3344_COLOR_32_FITS_PATH.fits()) mImage.transform(HorizontalFlip) - mImage.save("color-horizontal-flip").second shouldBe "f70228600c77551473008ed4b9986439" + mImage.save("fits-color-horizontal-flip").second shouldBe "f70228600c77551473008ed4b9986439" } "color:vertical & horizontal flip" { val mImage = Image.open(NGC3344_COLOR_32_FITS_PATH.fits()) mImage.transform(VerticalFlip, HorizontalFlip) - mImage.save("color-vertical-horizontal-flip").second shouldBe "1237314044f20307b76203148af855e3" + mImage.save("fits-color-vertical-horizontal-flip").second shouldBe "1237314044f20307b76203148af855e3" } "color:subframe" { val mImage = Image.open(NGC3344_COLOR_32_FITS_PATH.fits()) @@ -155,144 +155,144 @@ class TransformAlgorithmTest : FitsStringSpec() { nImage.width shouldBeExactly 16 nImage.height shouldBeExactly 16 nImage.mono.shouldBeFalse() - nImage.save("color-subframe").second shouldBe "282fc4fdf9142fcb4b18e1df1eef4caa" + nImage.save("fits-color-subframe").second shouldBe "282fc4fdf9142fcb4b18e1df1eef4caa" } "color:sharpen" { val mImage = Image.open(NGC3344_COLOR_32_FITS_PATH.fits()) mImage.transform(Sharpen) - mImage.save("color-sharpen").second shouldBe "e562282bdafdeba6ce88981bb9c3ba61" + mImage.save("fits-color-sharpen").second shouldBe "e562282bdafdeba6ce88981bb9c3ba61" } "color:mean" { val mImage = Image.open(NGC3344_COLOR_32_FITS_PATH.fits()) mImage.transform(Mean) - mImage.save("color-mean").second shouldBe "a8380d928aaa756e202ba43bd3a2f207" + mImage.save("fits-color-mean").second shouldBe "a8380d928aaa756e202ba43bd3a2f207" } "color:invert" { val mImage = Image.open(NGC3344_COLOR_32_FITS_PATH.fits()) mImage.transform(Invert) - mImage.save("color-invert").second shouldBe "decad269ec26450aebeaf7546867b5f8" + mImage.save("fits-color-invert").second shouldBe "decad269ec26450aebeaf7546867b5f8" } "color:emboss" { val mImage = Image.open(NGC3344_COLOR_32_FITS_PATH.fits()) mImage.transform(Emboss) - mImage.save("color-emboss").second shouldBe "58d69250f1233055aa33f9ec7ca40af1" + mImage.save("fits-color-emboss").second shouldBe "58d69250f1233055aa33f9ec7ca40af1" } "color:edges" { val mImage = Image.open(NGC3344_COLOR_32_FITS_PATH.fits()) mImage.transform(Edges) - mImage.save("color-edges").second shouldBe "091f2955740a8edcd2401dc416d19d51" + mImage.save("fits-color-edges").second shouldBe "091f2955740a8edcd2401dc416d19d51" } "color:blur" { val mImage = Image.open(NGC3344_COLOR_32_FITS_PATH.fits()) mImage.transform(Blur) - mImage.save("color-blur").second shouldBe "0fca440b763de5380fa29de736f3c792" + mImage.save("fits-color-blur").second shouldBe "0fca440b763de5380fa29de736f3c792" } "color:gaussian blur" { val mImage = Image.open(NGC3344_COLOR_32_FITS_PATH.fits()) mImage.transform(GaussianBlur(sigma = 5.0, size = 9)) - mImage.save("color-gaussian-blur").second shouldBe "394d1a4f136f15c802dd73004c421d64" + mImage.save("fits-color-gaussian-blur").second shouldBe "394d1a4f136f15c802dd73004c421d64" } "color:STF:midtone = 0.1, shadow = 0.0, highlight = 1.0" { val mImage = Image.open(NGC3344_COLOR_32_FITS_PATH.fits()) mImage.transform(ScreenTransformFunction(0.1f)) - mImage.save("color-stf-01-00-10").second shouldBe "e952bd263df6fd275b9a80aca554cb4b" + mImage.save("fits-color-stf-01-00-10").second shouldBe "e952bd263df6fd275b9a80aca554cb4b" } "color:STF:midtone = 0.9, shadow = 0.0, highlight = 1.0" { val mImage = Image.open(NGC3344_COLOR_32_FITS_PATH.fits()) mImage.transform(ScreenTransformFunction(0.9f)) - mImage.save("color-stf-09-00-10").second shouldBe "038809d7612018e2e5c19d5e1f551abd" + mImage.save("fits-color-stf-09-00-10").second shouldBe "038809d7612018e2e5c19d5e1f551abd" } "color:STF:midtone = 0.1, shadow = 0.5, highlight = 1.0" { val mImage = Image.open(NGC3344_COLOR_32_FITS_PATH.fits()) mImage.transform(ScreenTransformFunction(0.1f, shadow = 0.5f)) - mImage.save("color-stf-01-05-10").second shouldBe "70e812260f56f8621002327575611f31" + mImage.save("fits-color-stf-01-05-10").second shouldBe "70e812260f56f8621002327575611f31" } "color:STF:midtone = 0.9, shadow = 0.5, highlight = 1.0" { val mImage = Image.open(NGC3344_COLOR_32_FITS_PATH.fits()) mImage.transform(ScreenTransformFunction(0.9f, shadow = 0.5f)) - mImage.save("color-stf-09-05-10").second shouldBe "6ca400f617f466a9eb02a3a6f2985d99" + mImage.save("fits-color-stf-09-05-10").second shouldBe "6ca400f617f466a9eb02a3a6f2985d99" } "color:STF:midtone = 0.1, shadow = 0.0, highlight = 0.5" { val mImage = Image.open(NGC3344_COLOR_32_FITS_PATH.fits()) mImage.transform(ScreenTransformFunction(0.1f, highlight = 0.5f)) - mImage.save("color-stf-01-00-05").second shouldBe "3cd98ee9a8949d5100295acccd77010b" + mImage.save("fits-color-stf-01-00-05").second shouldBe "3cd98ee9a8949d5100295acccd77010b" } "color:STF:midtone = 0.9, shadow = 0.0, highlight = 0.5" { val mImage = Image.open(NGC3344_COLOR_32_FITS_PATH.fits()) mImage.transform(ScreenTransformFunction(0.9f, highlight = 0.5f)) - mImage.save("color-stf-09-00-05").second shouldBe "2cfeffc88c893cc5883d8a2221f29b91" + mImage.save("fits-color-stf-09-00-05").second shouldBe "2cfeffc88c893cc5883d8a2221f29b91" } "color:STF:midtone = 0.1, shadow = 0.4, highlight = 0.6" { val mImage = Image.open(NGC3344_COLOR_32_FITS_PATH.fits()) mImage.transform(ScreenTransformFunction(0.1f, 0.4f, 0.6f)) - mImage.save("color-stf-01-04-06").second shouldBe "532a07a1a166eb007c2e40651aec2097" + mImage.save("fits-color-stf-01-04-06").second shouldBe "532a07a1a166eb007c2e40651aec2097" } "color:STF:midtone = 0.9, shadow = 0.4, highlight = 0.6" { val mImage = Image.open(NGC3344_COLOR_32_FITS_PATH.fits()) mImage.transform(ScreenTransformFunction(0.9f, 0.4f, 0.6f)) - mImage.save("color-stf-09-04-06").second shouldBe "eb3d940d9fd2c8814e930715e89897c4" + mImage.save("fits-color-stf-09-04-06").second shouldBe "eb3d940d9fd2c8814e930715e89897c4" } "color:auto STF" { val mImage = Image.open(NGC3344_COLOR_32_FITS_PATH.fits()) mImage.transform(AutoScreenTransformFunction) - mImage.save("color-auto-stf").second shouldBe "a9c3657d8597b927607eb438e666d3a0" + mImage.save("fits-color-auto-stf").second shouldBe "a9c3657d8597b927607eb438e666d3a0" } "color:SCNR Maximum Mask" { val mImage = Image.open(NGC3344_COLOR_32_FITS_PATH.fits()) mImage.transform(SubtractiveChromaticNoiseReduction(ImageChannel.RED, 1f, ProtectionMethod.MAXIMUM_MASK)) - mImage.save("color-scnr-maximum-mask").second shouldBe "e7d2155e18ff1e3172f4e849ae983145" + mImage.save("fits-color-scnr-maximum-mask").second shouldBe "e7d2155e18ff1e3172f4e849ae983145" } "color:SCNR Additive Mask" { val mImage = Image.open(NGC3344_COLOR_32_FITS_PATH.fits()) mImage.transform(SubtractiveChromaticNoiseReduction(ImageChannel.RED, 1f, ProtectionMethod.ADDITIVE_MASK)) - mImage.save("color-scnr-additive-mask").second shouldBe "a458c44cedcda704de16d80053fd87eb" + mImage.save("fits-color-scnr-additive-mask").second shouldBe "a458c44cedcda704de16d80053fd87eb" } "color:SCNR Average Neutral" { val mImage = Image.open(NGC3344_COLOR_32_FITS_PATH.fits()) mImage.transform(SubtractiveChromaticNoiseReduction(ImageChannel.RED, 1f, ProtectionMethod.AVERAGE_NEUTRAL)) - mImage.save("color-scnr-average-neutral").second shouldBe "e07345ffc4982a62301c95c76d3efb35" + mImage.save("fits-color-scnr-average-neutral").second shouldBe "e07345ffc4982a62301c95c76d3efb35" } "color:SCNR Maximum Neutral" { val mImage = Image.open(NGC3344_COLOR_32_FITS_PATH.fits()) mImage.transform(SubtractiveChromaticNoiseReduction(ImageChannel.RED, 1f, ProtectionMethod.MAXIMUM_NEUTRAL)) - mImage.save("color-scnr-maximum-neutral").second shouldBe "a1d4b04f57b001ba4a996bab0407fd7e" + mImage.save("fits-color-scnr-maximum-neutral").second shouldBe "a1d4b04f57b001ba4a996bab0407fd7e" } "color:SCNR Minimum Neutral" { val mImage = Image.open(NGC3344_COLOR_32_FITS_PATH.fits()) mImage.transform(SubtractiveChromaticNoiseReduction(ImageChannel.RED, 1f, ProtectionMethod.MINIMUM_NEUTRAL)) - mImage.save("color-scnr-minimum-neutral").second shouldBe "8b7be57ff38da9c97b35d7888047c0f9" + mImage.save("fits-color-scnr-minimum-neutral").second shouldBe "8b7be57ff38da9c97b35d7888047c0f9" } "color:grayscale BT-709" { val mImage = Image.open(NGC3344_COLOR_32_FITS_PATH.fits()) val nImage = mImage.transform(Grayscale.BT709) - nImage.save("color-grayscale-bt709").second shouldBe "cab675aa35390a2d58cd48555d91054f" + nImage.save("fits-color-grayscale-bt709").second shouldBe "cab675aa35390a2d58cd48555d91054f" } "color:grayscale RMY" { val mImage = Image.open(NGC3344_COLOR_32_FITS_PATH.fits()) val nImage = mImage.transform(Grayscale.RMY) - nImage.save("color-grayscale-rmy").second shouldBe "e113627002a4178d1010a2f6246e325f" + nImage.save("fits-color-grayscale-rmy").second shouldBe "e113627002a4178d1010a2f6246e325f" } "color:grayscale Y" { val mImage = Image.open(NGC3344_COLOR_32_FITS_PATH.fits()) val nImage = mImage.transform(Grayscale.Y) - nImage.save("color-grayscale-y").second shouldBe "24dd4a7e0fa9e4be34c53c924a78a940" + nImage.save("fits-color-grayscale-y").second shouldBe "24dd4a7e0fa9e4be34c53c924a78a940" } "color:debayer" { val mImage = Image.open(DEBAYER_FITS_PATH.fits()) val nImage = mImage.transform(AutoScreenTransformFunction) - nImage.save("color-debayer").second shouldBe "86b5bdd67dfd6bbf5495afae4bf2bc04" + nImage.save("fits-color-debayer").second shouldBe "86b5bdd67dfd6bbf5495afae4bf2bc04" } "color:no-debayer" { val mImage = Image.open(DEBAYER_FITS_PATH.fits(), false) val nImage = mImage.transform(AutoScreenTransformFunction) - nImage.save("color-no-debayer").second shouldBe "958ccea020deec1f0c075042a9ba37c3" + nImage.save("fits-color-no-debayer").second shouldBe "958ccea020deec1f0c075042a9ba37c3" } "color:reload" { val mImage0 = Image.open(NGC3344_COLOR_32_FITS_PATH.fits()) var mImage1 = Image.open(DEBAYER_FITS_PATH.fits()) mImage1.load(mImage0.hdu).shouldNotBeNull() - mImage1.save("color-reload").second shouldBe "18fb83e240bc7a4cbafbc1aba2741db6" + mImage1.save("fits-color-reload").second shouldBe "18fb83e240bc7a4cbafbc1aba2741db6" mImage1 = Image.open(DEBAYER_FITS_PATH.fits(), false) diff --git a/nebulosa-image/src/test/kotlin/XisfTransformAlgorithmTest.kt b/nebulosa-image/src/test/kotlin/XisfTransformAlgorithmTest.kt new file mode 100644 index 000000000..a3ef8d1c7 --- /dev/null +++ b/nebulosa-image/src/test/kotlin/XisfTransformAlgorithmTest.kt @@ -0,0 +1,303 @@ +import io.kotest.matchers.booleans.shouldBeFalse +import io.kotest.matchers.booleans.shouldBeTrue +import io.kotest.matchers.ints.shouldBeExactly +import io.kotest.matchers.nulls.shouldBeNull +import io.kotest.matchers.nulls.shouldNotBeNull +import io.kotest.matchers.shouldBe +import nebulosa.image.Image +import nebulosa.image.algorithms.transformation.* +import nebulosa.image.algorithms.transformation.convolution.* +import nebulosa.image.format.ImageChannel +import nebulosa.test.FitsStringSpec +import nebulosa.xisf.xisf + +class XisfTransformAlgorithmTest : FitsStringSpec() { + + init { + "mono:raw" { + val mImage = Image.open(M82_MONO_8_XISF.xisf()) + mImage.save("xisf-mono-raw").second shouldBe "0dca7efedef5b3525f8037f401518b0b" + } + "mono:vertical flip" { + val mImage = Image.open(M82_MONO_8_XISF.xisf()) + mImage.transform(VerticalFlip) + mImage.save("xisf-mono-vertical-flip").second shouldBe "d8250e5ac45d9a6ec04bed2a583a70b2" + } + "mono:horizontal flip" { + val mImage = Image.open(M82_MONO_8_XISF.xisf()) + mImage.transform(HorizontalFlip) + mImage.save("xisf-mono-horizontal-flip").second shouldBe "9e2a05c331a5daeff20671a365e8b74c" + } + "mono:vertical & horizontal flip" { + val mImage = Image.open(M82_MONO_8_XISF.xisf()) + mImage.transform(VerticalFlip, HorizontalFlip) + mImage.save("xisf-mono-vertical-horizontal-flip").second shouldBe "c7d55e870850c10619f389e3f9ec1243" + } + "mono:subframe" { + val mImage = Image.open(M82_MONO_8_XISF.xisf()) + val nImage = mImage.transform(SubFrame(45, 70, 16, 16)) + nImage.width shouldBeExactly 16 + nImage.height shouldBeExactly 16 + nImage.mono.shouldBeTrue() + nImage.save("xisf-mono-subframe").second shouldBe "dc0ca19c5d40f90e4daac87fbab8f449" + } + "mono:sharpen" { + val mImage = Image.open(M82_MONO_8_XISF.xisf()) + mImage.transform(Sharpen) + mImage.save("xisf-mono-sharpen").second shouldBe "08421f6afef422cdaa9f464a860808ce" + } + "mono:mean" { + val mImage = Image.open(M82_MONO_8_XISF.xisf()) + mImage.transform(Mean) + mImage.save("xisf-mono-mean").second shouldBe "4127027d467ce9537049dc5f25f23ede" + } + "mono:invert" { + val mImage = Image.open(M82_MONO_8_XISF.xisf()) + mImage.transform(Invert) + mImage.save("xisf-mono-invert").second shouldBe "a6ec4a55225cb18f004e159a60137fe9" + } + "mono:emboss" { + val mImage = Image.open(M82_MONO_8_XISF.xisf()) + mImage.transform(Emboss) + mImage.save("xisf-mono-emboss").second shouldBe "2f07b3964b52f6b141b8cc45639b2287" + } + "mono:edges" { + val mImage = Image.open(M82_MONO_8_XISF.xisf()) + mImage.transform(Edges) + mImage.save("xisf-mono-edges").second shouldBe "897af72d536bca57cce77f09e396adb7" + } + "mono:blur" { + val mImage = Image.open(M82_MONO_8_XISF.xisf()) + mImage.transform(Blur) + mImage.save("xisf-mono-blur").second shouldBe "5a850ef20c0ebd461e676523823ff6ea" + } + "mono:gaussian blur" { + val mImage = Image.open(M82_MONO_8_XISF.xisf()) + mImage.transform(GaussianBlur(sigma = 5.0, size = 9)) + mImage.save("xisf-mono-gaussian-blur").second shouldBe "cb7489cb1948e802ea4d92bba24e0739" + } + "mono:STF:midtone = 0.1, shadow = 0.0, highlight = 1.0" { + val mImage = Image.open(M82_MONO_8_XISF.xisf()) + mImage.transform(ScreenTransformFunction(0.1f)) + mImage.save("xisf-mono-stf-01-00-10").second shouldBe "91621dba5a58081347d156f2152bd8c6" + } + "mono:STF:midtone = 0.9, shadow = 0.0, highlight = 1.0" { + val mImage = Image.open(M82_MONO_8_XISF.xisf()) + mImage.transform(ScreenTransformFunction(0.9f)) + mImage.save("xisf-mono-stf-09-00-10").second shouldBe "9a67728cfc4f871ea8ab6557f381949e" + } + "mono:STF:midtone = 0.1, shadow = 0.5, highlight = 1.0" { + val mImage = Image.open(M82_MONO_8_XISF.xisf()) + mImage.transform(ScreenTransformFunction(0.1f, shadow = 0.5f)) + mImage.save("xisf-mono-stf-01-05-10").second shouldBe "c70b9caaaf88bba9c64891a2b3ba8033" + } + "mono:STF:midtone = 0.9, shadow = 0.5, highlight = 1.0" { + val mImage = Image.open(M82_MONO_8_XISF.xisf()) + mImage.transform(ScreenTransformFunction(0.9f, shadow = 0.5f)) + mImage.save("xisf-mono-stf-09-05-10").second shouldBe "4f4c49b96bd9aa417f22c59b8224ea90" + } + "mono:STF:midtone = 0.1, shadow = 0.0, highlight = 0.5" { + val mImage = Image.open(M82_MONO_8_XISF.xisf()) + mImage.transform(ScreenTransformFunction(0.1f, highlight = 0.5f)) + mImage.save("xisf-mono-stf-01-00-05").second shouldBe "b0c9598e3003d72a5fba617c30dc1821" + } + "mono:STF:midtone = 0.9, shadow = 0.0, highlight = 0.5" { + val mImage = Image.open(M82_MONO_8_XISF.xisf()) + mImage.transform(ScreenTransformFunction(0.9f, highlight = 0.5f)) + mImage.save("xisf-mono-stf-09-00-05").second shouldBe "5824ac8c2d44c2c8ff8121e0904bb77b" + } + "mono:STF:midtone = 0.1, shadow = 0.4, highlight = 0.6" { + val mImage = Image.open(M82_MONO_8_XISF.xisf()) + mImage.transform(ScreenTransformFunction(0.1f, 0.4f, 0.6f)) + mImage.save("xisf-mono-stf-01-04-06").second shouldBe "20417dfc43fc4c5cb425875614d8066c" + } + "mono:STF:midtone = 0.9, shadow = 0.4, highlight = 0.6" { + val mImage = Image.open(M82_MONO_8_XISF.xisf()) + mImage.transform(ScreenTransformFunction(0.9f, 0.4f, 0.6f)) + mImage.save("xisf-mono-stf-09-04-06").second shouldBe "13d13ad164a952a29f7ad76e1e51e7d0" + } + "mono:auto STF" { + val mImage = Image.open(M82_MONO_8_XISF.xisf()) + mImage.transform(AutoScreenTransformFunction) + mImage.save("xisf-mono-auto-stf").second shouldBe "9204a71df3770e8fe5ca49e3420eed72" + } + "!mono:reload" { + val mImage0 = Image.open(M82_MONO_8_XISF.xisf()) + + val mImage1 = Image.open(M82_MONO_8_XISF.xisf()) + mImage1.transform(Invert) + + mImage0.load(mImage1.hdu) + mImage0.save("xisf-mono-reload").second shouldBe "6e94463bb5b9561de1f0ee0a154db53e" + } + "color:raw" { + val mImage = Image.open(M82_COLOR_32_XISF.xisf()) + mImage.save("xisf-color-raw").second shouldBe "764e326cc5260d81f3761112ad6a1969" + } + "color:vertical flip" { + val mImage = Image.open(M82_COLOR_32_XISF.xisf()) + mImage.transform(VerticalFlip) + mImage.save("xisf-color-vertical-flip").second shouldBe "595d8d3e46e91d7adf7591e591a7a98d" + } + "color:horizontal flip" { + val mImage = Image.open(M82_COLOR_32_XISF.xisf()) + mImage.transform(HorizontalFlip) + mImage.save("xisf-color-horizontal-flip").second shouldBe "b3d9609ef88db9b9215b4e21fdd4992a" + } + "color:vertical & horizontal flip" { + val mImage = Image.open(M82_COLOR_32_XISF.xisf()) + mImage.transform(VerticalFlip, HorizontalFlip) + mImage.save("xisf-color-vertical-horizontal-flip").second shouldBe "1c9be1a7e5a66a989f6d0715c7ff30e4" + } + "color:subframe" { + val mImage = Image.open(M82_COLOR_32_XISF.xisf()) + val nImage = mImage.transform(SubFrame(45, 70, 16, 16)) + nImage.width shouldBeExactly 16 + nImage.height shouldBeExactly 16 + nImage.mono.shouldBeFalse() + nImage.save("xisf-color-subframe").second shouldBe "dcf5bc8908ea6a32a5e98f14152f47b9" + } + "color:sharpen" { + val mImage = Image.open(M82_COLOR_32_XISF.xisf()) + mImage.transform(Sharpen) + mImage.save("xisf-color-sharpen").second shouldBe "1017a88ff2caeb83a650d94d96c59347" + } + "color:mean" { + val mImage = Image.open(M82_COLOR_32_XISF.xisf()) + mImage.transform(Mean) + mImage.save("xisf-color-mean").second shouldBe "eb948cab18442d008381f392bf43542a" + } + "color:invert" { + val mImage = Image.open(M82_COLOR_32_XISF.xisf()) + mImage.transform(Invert) + mImage.save("xisf-color-invert").second shouldBe "bbc97cdcde240873439bc29ff1adf169" + } + "color:emboss" { + val mImage = Image.open(M82_COLOR_32_XISF.xisf()) + mImage.transform(Emboss) + mImage.save("xisf-color-emboss").second shouldBe "fba6827f204df93f4aaf2f99b113a8f7" + } + "color:edges" { + val mImage = Image.open(M82_COLOR_32_XISF.xisf()) + mImage.transform(Edges) + mImage.save("xisf-color-edges").second shouldBe "71d6b5c936ab8165c7c1b63514d2da7b" + } + "color:blur" { + val mImage = Image.open(M82_COLOR_32_XISF.xisf()) + mImage.transform(Blur) + mImage.save("xisf-color-blur").second shouldBe "5c9f738a309fc86956d124f0f109eea2" + } + "color:gaussian blur" { + val mImage = Image.open(M82_COLOR_32_XISF.xisf()) + mImage.transform(GaussianBlur(sigma = 5.0, size = 9)) + mImage.save("xisf-color-gaussian-blur").second shouldBe "648beabcea0b486efc3f0c4ded632a06" + } + "color:STF:midtone = 0.1, shadow = 0.0, highlight = 1.0" { + val mImage = Image.open(M82_COLOR_32_XISF.xisf()) + mImage.transform(ScreenTransformFunction(0.1f)) + mImage.save("xisf-color-stf-01-00-10").second shouldBe "d84577785e44179f7af7c00807be5260" + } + "color:STF:midtone = 0.9, shadow = 0.0, highlight = 1.0" { + val mImage = Image.open(M82_COLOR_32_XISF.xisf()) + mImage.transform(ScreenTransformFunction(0.9f)) + mImage.save("xisf-color-stf-09-00-10").second shouldBe "11771bfe0e180e1efea4568902109013" + } + "color:STF:midtone = 0.1, shadow = 0.5, highlight = 1.0" { + val mImage = Image.open(M82_COLOR_32_XISF.xisf()) + mImage.transform(ScreenTransformFunction(0.1f, shadow = 0.5f)) + mImage.save("xisf-color-stf-01-05-10").second shouldBe "4e3b204d8a7ed06dfd05b7d010ef267b" + } + "color:STF:midtone = 0.9, shadow = 0.5, highlight = 1.0" { + val mImage = Image.open(M82_COLOR_32_XISF.xisf()) + mImage.transform(ScreenTransformFunction(0.9f, shadow = 0.5f)) + mImage.save("xisf-color-stf-09-05-10").second shouldBe "95c5b801978abdbb51afc9d0de12c218" + } + "color:STF:midtone = 0.1, shadow = 0.0, highlight = 0.5" { + val mImage = Image.open(M82_COLOR_32_XISF.xisf()) + mImage.transform(ScreenTransformFunction(0.1f, highlight = 0.5f)) + mImage.save("xisf-color-stf-01-00-05").second shouldBe "08322042c9e57102fec77a06b28c263d" + } + "color:STF:midtone = 0.9, shadow = 0.0, highlight = 0.5" { + val mImage = Image.open(M82_COLOR_32_XISF.xisf()) + mImage.transform(ScreenTransformFunction(0.9f, highlight = 0.5f)) + mImage.save("xisf-color-stf-09-00-05").second shouldBe "c99990d3a4bc6fc3aa7a8ac90d452419" + } + "color:STF:midtone = 0.1, shadow = 0.4, highlight = 0.6" { + val mImage = Image.open(M82_COLOR_32_XISF.xisf()) + mImage.transform(ScreenTransformFunction(0.1f, 0.4f, 0.6f)) + mImage.save("xisf-color-stf-01-04-06").second shouldBe "33bce2d7f7cde67d0ee618439f438ee7" + } + "color:STF:midtone = 0.9, shadow = 0.4, highlight = 0.6" { + val mImage = Image.open(M82_COLOR_32_XISF.xisf()) + mImage.transform(ScreenTransformFunction(0.9f, 0.4f, 0.6f)) + mImage.save("xisf-color-stf-09-04-06").second shouldBe "923e56840bcea4462160e36f2e801f5e" + } + "color:auto STF" { + val mImage = Image.open(M82_COLOR_32_XISF.xisf()) + mImage.transform(AutoScreenTransformFunction) + mImage.save("xisf-color-auto-stf").second shouldBe "b1460451ad0f0580802d3d6d3a6750ba" + } + "color:SCNR Maximum Mask" { + val mImage = Image.open(M82_COLOR_32_XISF.xisf()) + mImage.transform(SubtractiveChromaticNoiseReduction(ImageChannel.RED, 1f, ProtectionMethod.MAXIMUM_MASK)) + mImage.save("xisf-color-scnr-maximum-mask").second shouldBe "e465a2fc0814055e089a3180c0235c8b" + } + "color:SCNR Additive Mask" { + val mImage = Image.open(M82_COLOR_32_XISF.xisf()) + mImage.transform(SubtractiveChromaticNoiseReduction(ImageChannel.RED, 1f, ProtectionMethod.ADDITIVE_MASK)) + mImage.save("xisf-color-scnr-additive-mask").second shouldBe "1016ec07253f869097d2d9c67194b3e3" + } + "color:SCNR Average Neutral" { + val mImage = Image.open(M82_COLOR_32_XISF.xisf()) + mImage.transform(SubtractiveChromaticNoiseReduction(ImageChannel.RED, 1f, ProtectionMethod.AVERAGE_NEUTRAL)) + mImage.save("xisf-color-scnr-average-neutral").second shouldBe "2f2583bfb2ae4a9e4441dc9b827196f7" + } + "color:SCNR Maximum Neutral" { + val mImage = Image.open(M82_COLOR_32_XISF.xisf()) + mImage.transform(SubtractiveChromaticNoiseReduction(ImageChannel.RED, 1f, ProtectionMethod.MAXIMUM_NEUTRAL)) + mImage.save("xisf-color-scnr-maximum-neutral").second shouldBe "dabd995db4fba052617b148b3700378d" + } + "color:SCNR Minimum Neutral" { + val mImage = Image.open(M82_COLOR_32_XISF.xisf()) + mImage.transform(SubtractiveChromaticNoiseReduction(ImageChannel.RED, 1f, ProtectionMethod.MINIMUM_NEUTRAL)) + mImage.save("xisf-color-scnr-minimum-neutral").second shouldBe "b92e5130ec2a44c0afd1ca3782261e47" + } + "color:grayscale BT-709" { + val mImage = Image.open(M82_COLOR_32_XISF.xisf()) + val nImage = mImage.transform(Grayscale.BT709) + nImage.save("xisf-color-grayscale-bt709").second shouldBe "bf78482866a0b3a216fa5262f28b0e5e" + } + "color:grayscale RMY" { + val mImage = Image.open(M82_COLOR_32_XISF.xisf()) + val nImage = mImage.transform(Grayscale.RMY) + nImage.save("xisf-color-grayscale-rmy").second shouldBe "e75085eea073811aef41624aab318b48" + } + "color:grayscale Y" { + val mImage = Image.open(M82_COLOR_32_XISF.xisf()) + val nImage = mImage.transform(Grayscale.Y) + nImage.save("xisf-color-grayscale-y").second shouldBe "7a2bef966d460742533a1c8c3a74f1c5" + } + "!color:debayer" { + val mImage = Image.open(DEBAYER_FITS_PATH.xisf()) + val nImage = mImage.transform(AutoScreenTransformFunction) + nImage.save("xisf-color-debayer").second shouldBe "86b5bdd67dfd6bbf5495afae4bf2bc04" + } + "!color:no-debayer" { + val mImage = Image.open(DEBAYER_FITS_PATH.xisf(), false) + val nImage = mImage.transform(AutoScreenTransformFunction) + nImage.save("xisf-color-no-debayer").second shouldBe "958ccea020deec1f0c075042a9ba37c3" + } + "!color:reload" { + val mImage0 = Image.open(M82_COLOR_32_XISF.xisf()) + var mImage1 = Image.open(DEBAYER_FITS_PATH.xisf()) + + mImage1.load(mImage0.hdu).shouldNotBeNull() + mImage1.save("xisf-color-reload").second shouldBe "18fb83e240bc7a4cbafbc1aba2741db6" + + mImage1 = Image.open(DEBAYER_FITS_PATH.xisf(), false) + + mImage1.load(mImage0.hdu).shouldBeNull() + mImage0.load(mImage1.hdu).shouldBeNull() + } + } +} diff --git a/nebulosa-xisf/src/main/kotlin/nebulosa/xisf/XisfHeaderCard.kt b/nebulosa-xisf/src/main/kotlin/nebulosa/xisf/XisfHeaderCard.kt index 4079a4228..4de97f999 100644 --- a/nebulosa-xisf/src/main/kotlin/nebulosa/xisf/XisfHeaderCard.kt +++ b/nebulosa-xisf/src/main/kotlin/nebulosa/xisf/XisfHeaderCard.kt @@ -3,8 +3,6 @@ package nebulosa.xisf import nebulosa.fits.FitsHeaderCardFormatter import nebulosa.image.format.HeaderCard import nebulosa.image.format.HeaderKey -import nebulosa.log.loggerFor -import org.apache.commons.numbers.complex.Complex import java.io.Serializable import java.math.BigDecimal import java.math.BigInteger @@ -44,66 +42,12 @@ data class XisfHeaderCard( type == XisfPropertyType.INT64 || type == XisfPropertyType.INT128 - override val isBlank - get() = if (!isCommentStyle || key.isNotBlank()) false else comment.isBlank() - - private fun getBooleanValue(defaultValue: Boolean): Boolean { - return if (value == "T") true else if (value == "F") false else defaultValue - } - - private fun getNumericValue(asType: Class, defaultValue: T): T { - return try { - val decimal = BigDecimal(value.uppercase().replace('D', 'E')) - - if (Byte::class.javaObjectType.isAssignableFrom(asType)) { - asType.cast(decimal.toByte()) - } else if (Short::class.javaObjectType.isAssignableFrom(asType)) { - asType.cast(decimal.toShort()) - } else if (Int::class.javaObjectType.isAssignableFrom(asType)) { - asType.cast(decimal.toInt()) - } else if (Long::class.javaObjectType.isAssignableFrom(asType)) { - asType.cast(decimal.toLong()) - } else if (Float::class.javaObjectType.isAssignableFrom(asType)) { - asType.cast(decimal.toFloat()) - } else if (Double::class.javaObjectType.isAssignableFrom(asType)) { - asType.cast(decimal.toDouble()) - } else if (BigInteger::class.javaObjectType.isAssignableFrom(asType)) { - asType.cast(decimal.toBigInteger()) - } else if (BigDecimal::class.javaObjectType.isAssignableFrom(asType)) { - asType.cast(decimal) - } else { - throw IllegalArgumentException("unsupported class $asType") - } - } catch (e: NumberFormatException) { - LOG.error("failed to parse numeric value", e) - defaultValue - } - } - - override fun getValue(asType: Class, defaultValue: T): T { - return if (Boolean::class.javaObjectType.isAssignableFrom(asType)) { - asType.cast(getBooleanValue(defaultValue as Boolean)) - } else if (Number::class.javaObjectType.isAssignableFrom(asType)) { - getNumericValue(asType, defaultValue) - } else if (String::class.javaObjectType.isAssignableFrom(asType)) { - asType.cast(value) - } else if (Complex::class.java.isAssignableFrom(asType)) { - asType.cast(Complex.parse(value.trim().uppercase().replace('D', 'E'))) - } else if (value.isBlank()) { - defaultValue - } else { - throw IllegalArgumentException("unsupported class $asType") - } - } - override fun formatted(): String { return FitsHeaderCardFormatter.format(this) } companion object { - @JvmStatic private val LOG = loggerFor() - @JvmStatic fun create(header: HeaderKey, value: Boolean): XisfHeaderCard { return create(header.key, value, header.comment) diff --git a/settings.gradle.kts b/settings.gradle.kts index fab773656..dded4a1c2 100644 --- a/settings.gradle.kts +++ b/settings.gradle.kts @@ -30,6 +30,7 @@ dependencyResolutionManagement { library("apache-lang3", "org.apache.commons:commons-lang3:3.14.0") library("apache-codec", "commons-codec:commons-codec:1.16.1") library("apache-collections", "org.apache.commons:commons-collections4:4.4") + library("apache-numbers-complex", "org.apache.commons:commons-numbers-complex:1.1") library("oshi", "com.github.oshi:oshi-core:6.4.13") library("timeshape", "net.iakovlev:timeshape:2022g.17") library("jna", "net.java.dev.jna:jna:5.14.0") From 73e059662c91d288b751469615436effe36a78f8 Mon Sep 17 00:00:00 2001 From: tiagohm Date: Fri, 29 Mar 2024 22:25:45 -0300 Subject: [PATCH 09/15] [api][desktop]: Implement CCD Guide Head --- api/src/main/kotlin/nebulosa/api/README.md | 2 +- .../api/alignment/polar/darv/DARVJob.kt | 2 +- .../api/alignment/polar/tppa/TPPAStep.kt | 4 +- .../api/cameras/CameraCaptureEventHandler.kt | 2 +- .../api/cameras/CameraCaptureListener.kt | 2 +- .../api/cameras/CameraExposureStep.kt | 31 +- .../nebulosa/api/cameras/CameraSerializer.kt | 19 +- .../api/wizard/flat/FlatWizardStep.kt | 9 +- desktop/src/shared/types/camera.types.ts | 11 +- desktop/src/shared/types/device.types.ts | 4 + .../alpaca/indi/device/ASCOMDevice.kt | 8 +- .../alpaca/indi/device/cameras/ASCOMCamera.kt | 206 ++++----- .../indi/device/focusers/ASCOMFocuser.kt | 41 +- .../alpaca/indi/device/mounts/ASCOMMount.kt | 97 ++--- .../indi/device/wheels/ASCOMFilterWheel.kt | 15 +- .../main/kotlin/nebulosa/fits/FitsHeader.kt | 4 +- .../kotlin/nebulosa/image/format/Header.kt | 2 + .../nebulosa/image/format/WritableHeader.kt | 2 + .../nebulosa/indi/client/device/GPSDevice.kt | 7 +- .../nebulosa/indi/client/device/INDIDevice.kt | 28 +- .../device/INDIDeviceProtocolHandler.kt | 19 +- .../indi/client/device/cameras/INDICamera.kt | 398 ++++++++++-------- .../client/device/focusers/INDIFocuser.kt | 22 +- .../indi/client/device/mounts/INDIMount.kt | 39 +- .../client/device/wheels/INDIFilterWheel.kt | 5 +- .../nebulosa/indi/device/CompanionDevice.kt | 6 + .../kotlin/nebulosa/indi/device/Device.kt | 8 +- .../nebulosa/indi/device/camera/Camera.kt | 7 +- .../indi/device/camera/CameraFrameCaptured.kt | 23 +- .../nebulosa/indi/device/camera/GuideHead.kt | 8 + 30 files changed, 507 insertions(+), 524 deletions(-) create mode 100644 nebulosa-indi-device/src/main/kotlin/nebulosa/indi/device/CompanionDevice.kt create mode 100644 nebulosa-indi-device/src/main/kotlin/nebulosa/indi/device/camera/GuideHead.kt diff --git a/api/src/main/kotlin/nebulosa/api/README.md b/api/src/main/kotlin/nebulosa/api/README.md index 7a6187f39..c4f03ed8a 100644 --- a/api/src/main/kotlin/nebulosa/api/README.md +++ b/api/src/main/kotlin/nebulosa/api/README.md @@ -52,7 +52,7 @@ URL: `localhost:{PORT}/ws` "offset": 0, "offsetMin": 0, "offsetMax": 0, - "hasGuiderHead": false, + "hasGuideHead": false, "pixelSizeX": 0, "pixelSizeY": 0, "capturesPath": "", diff --git a/api/src/main/kotlin/nebulosa/api/alignment/polar/darv/DARVJob.kt b/api/src/main/kotlin/nebulosa/api/alignment/polar/darv/DARVJob.kt index e034700f4..95c69cbfc 100644 --- a/api/src/main/kotlin/nebulosa/api/alignment/polar/darv/DARVJob.kt +++ b/api/src/main/kotlin/nebulosa/api/alignment/polar/darv/DARVJob.kt @@ -67,7 +67,7 @@ data class DARVJob( onNext(DARVEvent.Finished(id)) } - override fun onExposureFinished(step: CameraExposureStep, stepExecution: StepExecution, image: ImageRepresentation, savedPath: Path) { + override fun onExposureFinished(step: CameraExposureStep, stepExecution: StepExecution, image: ImageRepresentation?, savedPath: Path) { onNext(CameraExposureFinished(stepExecution.jobExecution, step.camera, 1, 1, Duration.ZERO, 1.0, Duration.ZERO, savedPath)) } diff --git a/api/src/main/kotlin/nebulosa/api/alignment/polar/tppa/TPPAStep.kt b/api/src/main/kotlin/nebulosa/api/alignment/polar/tppa/TPPAStep.kt index e22f178be..af809ffa5 100644 --- a/api/src/main/kotlin/nebulosa/api/alignment/polar/tppa/TPPAStep.kt +++ b/api/src/main/kotlin/nebulosa/api/alignment/polar/tppa/TPPAStep.kt @@ -41,7 +41,7 @@ data class TPPAStep( @Volatile private var mountSlewStep: MountSlewStep? = null @Volatile private var noSolutionAttempts = 0 @Volatile private var stepExecution: StepExecution? = null - @Volatile private var savedImage: Pair? = null + @Volatile private var savedImage: Pair? = null val stepCount get() = alignment.state @@ -65,7 +65,7 @@ data class TPPAStep( return listeners.remove(listener) } - override fun onExposureFinished(step: CameraExposureStep, stepExecution: StepExecution, image: ImageRepresentation, savedPath: Path) { + override fun onExposureFinished(step: CameraExposureStep, stepExecution: StepExecution, image: ImageRepresentation?, savedPath: Path) { savedImage = image to savedPath } diff --git a/api/src/main/kotlin/nebulosa/api/cameras/CameraCaptureEventHandler.kt b/api/src/main/kotlin/nebulosa/api/cameras/CameraCaptureEventHandler.kt index 9e7a7d264..017228f44 100644 --- a/api/src/main/kotlin/nebulosa/api/cameras/CameraCaptureEventHandler.kt +++ b/api/src/main/kotlin/nebulosa/api/cameras/CameraCaptureEventHandler.kt @@ -33,7 +33,7 @@ data class CameraCaptureEventHandler(private val observer: Observer { - save(event.image, event.format) + save(event) } is CameraExposureAborted, is CameraExposureFailed, @@ -163,18 +163,26 @@ data class CameraExposureStep( } } - private fun save(image: ImageRepresentation, format: CameraFrameCaptured.Format) { + private fun save(event: CameraFrameCaptured) { try { - val savedPath = request.makeSavePath(camera, format) + val savedPath = request.makeSavePath(camera) - LOG.info("saving {} image at {}", format, savedPath) + LOG.info("saving FITS image at {}", savedPath) savedPath.createParentDirectories() - savedPath.outputStream().use { image.write(it.sink()) } - listeners.forEach { it.onExposureFinished(this, stepExecution!!, image, savedPath) } + if (event.stream != null) { + event.stream!!.transferAndClose(savedPath.outputStream()) + } else if (event.image != null) { + savedPath.sink().use(event.image!!::write) + } else { + LOG.warn("invalid event. camera={}", event.device) + return + } + + listeners.forEach { it.onExposureFinished(this, stepExecution!!, event.image, savedPath) } } catch (e: Throwable) { - LOG.error("failed to save $format image", e) + LOG.error("failed to save FITS image", e) aborted = true } finally { latch.countDown() @@ -219,16 +227,15 @@ data class CameraExposureStep( @JvmStatic internal fun CameraStartCaptureRequest.makeSavePath( - camera: Camera, format: CameraFrameCaptured.Format, - autoSave: Boolean = this.autoSave, + camera: Camera, autoSave: Boolean = this.autoSave, ): Path { return if (autoSave) { val now = LocalDateTime.now() val savePath = autoSubFolderMode.pathFor(savePath!!, now) - val fileName = "%s-%s.%s".format(now.format(DATE_TIME_FORMAT), frameType, format.extension) + val fileName = "%s-%s.fits".format(now.format(DATE_TIME_FORMAT), frameType) Path.of("$savePath", fileName) } else { - val fileName = "%s.%s".format(camera.name, format.extension) + val fileName = "%s.fits".format(camera.name) Path.of("$savePath", fileName) } } diff --git a/api/src/main/kotlin/nebulosa/api/cameras/CameraSerializer.kt b/api/src/main/kotlin/nebulosa/api/cameras/CameraSerializer.kt index 0a01653b8..97769f311 100644 --- a/api/src/main/kotlin/nebulosa/api/cameras/CameraSerializer.kt +++ b/api/src/main/kotlin/nebulosa/api/cameras/CameraSerializer.kt @@ -4,6 +4,7 @@ import com.fasterxml.jackson.core.JsonGenerator import com.fasterxml.jackson.databind.SerializerProvider import com.fasterxml.jackson.databind.ser.std.StdSerializer import nebulosa.indi.device.camera.Camera +import nebulosa.indi.device.camera.GuideHead import org.springframework.stereotype.Component import java.nio.file.Path @@ -57,7 +58,7 @@ class CameraSerializer(private val capturesPath: Path) : StdSerializer(C gen.writeNumberField("offset", value.offset) gen.writeNumberField("offsetMin", value.offsetMin) gen.writeNumberField("offsetMax", value.offsetMax) - gen.writeBooleanField("hasGuiderHead", value.hasGuiderHead) + gen.writeBooleanField("hasGuideHead", value.guideHead != null) gen.writeNumberField("pixelSizeX", value.pixelSizeX) gen.writeNumberField("pixelSizeY", value.pixelSizeY) gen.writeBooleanField("canPulseGuide", value.canPulseGuide) @@ -65,6 +66,22 @@ class CameraSerializer(private val capturesPath: Path) : StdSerializer(C gen.writeBooleanField("hasThermometer", value.hasThermometer) gen.writeNumberField("temperature", value.temperature) gen.writeObjectField("capturesPath", Path.of("$capturesPath", value.name)) + + if (value is GuideHead) { + gen.writeMainOrGuideHead(value.main, "main") + } else if (value.guideHead != null) { + gen.writeMainOrGuideHead(value.guideHead!!, "guideHead") + } + gen.writeEndObject() } + + private fun JsonGenerator.writeMainOrGuideHead(camera: Camera, fieldName: String) { + writeObjectFieldStart(fieldName) + writeStringField("id", camera.id) + writeStringField("name", camera.name) + writeStringField("sender", camera.sender.id) + writeBooleanField("connected", camera.connected) + writeEndObject() + } } diff --git a/api/src/main/kotlin/nebulosa/api/wizard/flat/FlatWizardStep.kt b/api/src/main/kotlin/nebulosa/api/wizard/flat/FlatWizardStep.kt index b172c33e8..c71444fc7 100644 --- a/api/src/main/kotlin/nebulosa/api/wizard/flat/FlatWizardStep.kt +++ b/api/src/main/kotlin/nebulosa/api/wizard/flat/FlatWizardStep.kt @@ -7,6 +7,7 @@ import nebulosa.api.image.ImageBucket import nebulosa.batch.processing.Step import nebulosa.batch.processing.StepExecution import nebulosa.batch.processing.StepResult +import nebulosa.fits.fits import nebulosa.image.Image import nebulosa.image.algorithms.computation.Statistics import nebulosa.image.format.ImageRepresentation @@ -76,11 +77,11 @@ data class FlatWizardStep( ) ) - var saved: Pair? = null + var saved: Pair? = null val listener = object : CameraCaptureListener { - override fun onExposureFinished(step: CameraExposureStep, stepExecution: StepExecution, image: ImageRepresentation, savedPath: Path) { + override fun onExposureFinished(step: CameraExposureStep, stepExecution: StepExecution, image: ImageRepresentation?, savedPath: Path) { saved = image to savedPath } } @@ -93,7 +94,9 @@ data class FlatWizardStep( if (!stopped && saved != null) { val (imageRepresentation, savedPath) = saved!! - image = image?.load(imageRepresentation) ?: Image.open(imageRepresentation, false) + image = if (imageRepresentation != null) image?.load(imageRepresentation) ?: Image.open(imageRepresentation, false) + else savedPath.fits().use { image?.load(it) ?: Image.open(it, false) } + imageBucket?.put(savedPath, image!!) val statistics = STATISTICS.compute(image!!) diff --git a/desktop/src/shared/types/camera.types.ts b/desktop/src/shared/types/camera.types.ts index 75e188f5d..2400c2e09 100644 --- a/desktop/src/shared/types/camera.types.ts +++ b/desktop/src/shared/types/camera.types.ts @@ -1,6 +1,6 @@ import { MessageEvent } from './api.types' import { Thermometer } from './auxiliary.types' -import { PropertyState } from './device.types' +import { CompanionDevice, Device, PropertyState } from './device.types' import { GuideOutput } from './guider.types' export type CameraDialogMode = 'CAPTURE' | 'SEQUENCER' | 'FLAT_WIZARD' | 'TPPA' | 'DARV' @@ -62,10 +62,15 @@ export interface Camera extends GuideOutput, Thermometer { offset: number offsetMin: number offsetMax: number - hasGuiderHead: boolean + hasGuideHead: boolean pixelSizeX: number pixelSizeY: number capturesPath: string + guideHead?: Device +} + +export interface GuideHead extends Camera, CompanionDevice { + } export const EMPTY_CAMERA: Camera = { @@ -112,7 +117,7 @@ export const EMPTY_CAMERA: Camera = { offset: 0, offsetMin: 0, offsetMax: 0, - hasGuiderHead: false, + hasGuideHead: false, pixelSizeX: 0, pixelSizeY: 0, capturesPath: '', diff --git a/desktop/src/shared/types/device.types.ts b/desktop/src/shared/types/device.types.ts index 53b60d1a7..934a9509f 100644 --- a/desktop/src/shared/types/device.types.ts +++ b/desktop/src/shared/types/device.types.ts @@ -15,6 +15,10 @@ export interface Device { connected: boolean } +export interface CompanionDevice extends Device { + main: D +} + export interface INDIMessageEvent extends DeviceMessageEvent { property?: INDIProperty message?: string diff --git a/nebulosa-alpaca-indi/src/main/kotlin/nebulosa/alpaca/indi/device/ASCOMDevice.kt b/nebulosa-alpaca-indi/src/main/kotlin/nebulosa/alpaca/indi/device/ASCOMDevice.kt index e3af0574c..4c4111955 100644 --- a/nebulosa-alpaca-indi/src/main/kotlin/nebulosa/alpaca/indi/device/ASCOMDevice.kt +++ b/nebulosa-alpaca-indi/src/main/kotlin/nebulosa/alpaca/indi/device/ASCOMDevice.kt @@ -18,9 +18,6 @@ abstract class ASCOMDevice : Device { protected abstract val service: AlpacaDeviceService abstract override val sender: AlpacaClient - @Suppress("PropertyName") - @JvmField protected val LOG = loggerFor(javaClass) - override val name get() = device.name @@ -153,4 +150,9 @@ abstract class ASCOMDevice : Device { } } } + + companion object { + + @JvmStatic private val LOG = loggerFor() + } } diff --git a/nebulosa-alpaca-indi/src/main/kotlin/nebulosa/alpaca/indi/device/cameras/ASCOMCamera.kt b/nebulosa-alpaca-indi/src/main/kotlin/nebulosa/alpaca/indi/device/cameras/ASCOMCamera.kt index 12cfa270d..a8a4df2d1 100644 --- a/nebulosa-alpaca-indi/src/main/kotlin/nebulosa/alpaca/indi/device/cameras/ASCOMCamera.kt +++ b/nebulosa-alpaca-indi/src/main/kotlin/nebulosa/alpaca/indi/device/cameras/ASCOMCamera.kt @@ -14,15 +14,17 @@ import nebulosa.fits.FitsKeyword import nebulosa.image.algorithms.transformation.CfaPattern import nebulosa.image.format.BasicImageHdu import nebulosa.image.format.FloatImageData +import nebulosa.image.format.HeaderCard import nebulosa.indi.device.Device import nebulosa.indi.device.camera.* -import nebulosa.indi.device.camera.Camera.Companion.NANO_SECONDS +import nebulosa.indi.device.camera.Camera.Companion.NANO_TO_SECONDS import nebulosa.indi.device.guide.GuideOutputPulsingChanged import nebulosa.indi.device.mount.Mount import nebulosa.indi.protocol.INDIProtocol import nebulosa.indi.protocol.PropertyState import nebulosa.io.readDoubleLe import nebulosa.io.readFloatLe +import nebulosa.log.loggerFor import nebulosa.math.formatHMS import nebulosa.math.formatSignedDMS import nebulosa.math.normalized @@ -39,117 +41,73 @@ import java.time.format.DateTimeFormatter import kotlin.math.max import kotlin.math.min +@Suppress("RedundantModalityModifier") data class ASCOMCamera( override val device: ConfiguredDevice, override val service: AlpacaCameraService, override val sender: AlpacaClient, ) : ASCOMDevice(), Camera { - @Volatile override var exposuring = false - private set - @Volatile override var hasCoolerControl = false - private set - @Volatile override var coolerPower = 0.0 - private set - @Volatile override var cooler = false - private set - @Volatile override var hasDewHeater = false - private set - @Volatile override var dewHeater = false - private set - @Volatile override var frameFormats = emptyList() - private set - @Volatile override var canAbort = false - private set - @Volatile override var cfaOffsetX = 0 - private set - @Volatile override var cfaOffsetY = 0 - private set - @Volatile override var cfaType = CfaPattern.RGGB - private set - @Volatile override var exposureMin: Duration = Duration.ZERO - private set - @Volatile override var exposureMax: Duration = Duration.ZERO - private set - @Volatile override var exposureState = PropertyState.IDLE - private set - @Volatile override var exposureTime: Duration = Duration.ZERO - private set - @Volatile override var hasCooler = false - private set - @Volatile override var canSetTemperature = false - private set - @Volatile override var canSubFrame = true - private set - @Volatile override var x = 0 - private set - @Volatile override var minX = 0 - private set - @Volatile override var maxX = 0 - private set - @Volatile override var y = 0 - private set - @Volatile override var minY = 0 - private set - @Volatile override var maxY = 0 - private set - @Volatile override var width = 0 - private set - @Volatile override var minWidth = 0 - private set - @Volatile override var maxWidth = 0 - private set - @Volatile override var height = 0 - private set - @Volatile override var minHeight = 0 - private set - @Volatile override var maxHeight = 0 - private set - @Volatile override var canBin = true - private set - @Volatile override var maxBinX = 1 - private set - @Volatile override var maxBinY = 1 - private set - @Volatile override var binX = 1 - private set - @Volatile override var binY = 1 - private set - @Volatile override var gain = 0 - private set - @Volatile override var gainMin = 0 - private set - @Volatile override var gainMax = 0 - private set - @Volatile override var offset = 0 - private set - @Volatile override var offsetMin = 0 - private set - @Volatile override var offsetMax = 0 - private set - @Volatile override var hasGuiderHead = false // TODO: ASCOM has guider head? - private set - @Volatile override var pixelSizeX = 0.0 - private set - @Volatile override var pixelSizeY = 0.0 - private set - - @Volatile override var hasThermometer = false - private set - @Volatile override var temperature = 0.0 - private set - - @Volatile override var canPulseGuide = false - private set - @Volatile override var pulseGuiding = false - private set + @Volatile final override var exposuring = false + @Volatile final override var hasCoolerControl = false + @Volatile final override var coolerPower = 0.0 + @Volatile final override var cooler = false + @Volatile final override var hasDewHeater = false + @Volatile final override var dewHeater = false + @Volatile final override var frameFormats = emptyList() + @Volatile final override var canAbort = false + @Volatile final override var cfaOffsetX = 0 + @Volatile final override var cfaOffsetY = 0 + @Volatile final override var cfaType = CfaPattern.RGGB + @Volatile final override var exposureMin: Duration = Duration.ZERO + @Volatile final override var exposureMax: Duration = Duration.ZERO + @Volatile final override var exposureState = PropertyState.IDLE + @Volatile final override var exposureTime: Duration = Duration.ZERO + @Volatile final override var hasCooler = false + @Volatile final override var canSetTemperature = false + @Volatile final override var canSubFrame = true + @Volatile final override var x = 0 + @Volatile final override var minX = 0 + @Volatile final override var maxX = 0 + @Volatile final override var y = 0 + @Volatile final override var minY = 0 + @Volatile final override var maxY = 0 + @Volatile final override var width = 0 + @Volatile final override var minWidth = 0 + @Volatile final override var maxWidth = 0 + @Volatile final override var height = 0 + @Volatile final override var minHeight = 0 + @Volatile final override var maxHeight = 0 + @Volatile final override var canBin = true + @Volatile final override var maxBinX = 1 + @Volatile final override var maxBinY = 1 + @Volatile final override var binX = 1 + @Volatile final override var binY = 1 + @Volatile final override var gain = 0 + @Volatile final override var gainMin = 0 + @Volatile final override var gainMax = 0 + @Volatile final override var offset = 0 + @Volatile final override var offsetMin = 0 + @Volatile final override var offsetMax = 0 + @Volatile final override var pixelSizeX = 0.0 + @Volatile final override var pixelSizeY = 0.0 + + @Volatile final override var hasThermometer = false + @Volatile final override var temperature = 0.0 + + @Volatile final override var canPulseGuide = false + @Volatile final override var pulseGuiding = false + + final override val guideHead = null // TODO: ASCOM has guide head? @Volatile private var cameraState = CameraState.IDLE @Volatile private var frameType = FrameType.LIGHT - @Volatile private var mount: Mount? = null + @Volatile private var fitsKeywords: Array = emptyArray() private val imageReadyWaiter = ImageReadyWaiter() + override val snoopedDevices = ArrayList(4) + init { refresh(0L) imageReadyWaiter.start() @@ -202,7 +160,7 @@ data class ASCOMCamera( override fun startCapture(exposureTime: Duration) { this.exposureTime = exposureTime - service.startExposure(device.number, exposureTime.toNanos() / NANO_SECONDS, frameType == FrameType.DARK).doRequest { + service.startExposure(device.number, exposureTime.toNanos() / NANO_TO_SECONDS, frameType == FrameType.DARK).doRequest { imageReadyWaiter.captureStarted() } } @@ -243,13 +201,16 @@ data class ASCOMCamera( override fun snoop(devices: Iterable) { for (device in devices) { - if (device is Mount) mount = device + device?.also(snoopedDevices::add) } } - override fun handleMessage(message: INDIProtocol) { + override fun fitsKeywords(vararg cards: HeaderCard) { + fitsKeywords = cards } + override fun handleMessage(message: INDIProtocol) = Unit + override fun onConnected() { processExposureMinMax() processFrameMinMax() @@ -261,8 +222,7 @@ data class ASCOMCamera( processReadoutModes() } - override fun onDisconnected() { - } + override fun onDisconnected() = Unit override fun reset() { super.reset() @@ -308,7 +268,6 @@ data class ASCOMCamera( offset = 0 offsetMin = 0 offsetMax = 0 - hasGuiderHead = false pixelSizeX = 0.0 pixelSizeY = 0.0 hasThermometer = false @@ -565,8 +524,8 @@ data class ASCOMCamera( private fun processExposureMinMax() { service.exposureMin(device.number).doRequest { min -> service.exposureMax(device.number).doRequest { max -> - exposureMin = Duration.ofNanos((min.value * NANO_SECONDS).toLong()) - exposureMax = Duration.ofNanos((max.value * NANO_SECONDS).toLong()) + exposureMin = Duration.ofNanos((min.value * NANO_TO_SECONDS).toLong()) + exposureMax = Duration.ofNanos((max.value * NANO_TO_SECONDS).toLong()) sender.fireOnEventReceived(CameraExposureMinMaxChanged(this)) } @@ -622,28 +581,21 @@ data class ASCOMCamera( val numberOfChannels = max(1, metadata.dimension3) val source = stream.source().buffer() val data = FloatImageData(width, height, numberOfChannels) + val channels = arrayOf(data.red, data.green, data.blue) for (x in 0 until width) { for (y in 0 until height) { val idx = y * width + x for (p in 0 until numberOfChannels) { - val pixel = when (metadata.imageElementType.bitpix) { + channels[p][idx] = when (metadata.imageElementType.bitpix) { Bitpix.BYTE -> (source.readByte().toInt() and 0xFF) / 255f Bitpix.SHORT -> (source.readShortLe().toInt() + 32768) / 65535f - Bitpix.INTEGER -> ((source.readIntLe().toLong() + 2147483648) / 4294967295.0).toFloat() + Bitpix.INTEGER -> ((source.readIntLe().toLong() + 2147483648L) / 4294967295.0).toFloat() Bitpix.FLOAT -> source.readFloatLe() Bitpix.DOUBLE -> source.readDoubleLe().toFloat() Bitpix.LONG -> return } - - val channel = when (p) { - 0 -> data.red - 1 -> data.green - else -> data.blue - } - - channel[idx] = pixel } } } @@ -670,6 +622,8 @@ data class ASCOMCamera( header.add("FRAME", frameType.description, "Frame Type") header.add(FitsKeyword.IMAGETYP, "${frameType.description} Frame") + val mount = snoopedDevices.firstOrNull { it is Mount } as? Mount + mount?.also { header.add(FitsKeyword.TELESCOP, it.name) header.add(FitsKeyword.SITELAT, it.latitude.toDegrees) @@ -689,12 +643,14 @@ data class ASCOMCamera( header.add("OFFSET", offset, "Offset") } + fitsKeywords.forEach(header::add) + val hdu = BasicImageHdu(width, height, numberOfChannels, header, data) - val fits = Fits() - fits.add(hdu) + val image = Fits() + image.add(hdu) - sender.fireOnEventReceived(CameraFrameCaptured(this, fits, false, CameraFrameCaptured.Format.FITS)) + sender.fireOnEventReceived(CameraFrameCaptured(this, image = image)) } ?: LOG.error("image body is null. device={}", name) } @@ -713,8 +669,7 @@ data class ASCOMCamera( " canBin=$canBin, maxBinX=$maxBinX, maxBinY=$maxBinY," + " binX=$binX, binY=$binY, gain=$gain, gainMin=$gainMin," + " gainMax=$gainMax, offset=$offset, offsetMin=$offsetMin," + - " offsetMax=$offsetMax, hasGuiderHead=$hasGuiderHead," + - " canPulseGuide=$canPulseGuide, pulseGuiding=$pulseGuiding)" + " offsetMax=$offsetMax, canPulseGuide=$canPulseGuide, pulseGuiding=$pulseGuiding)" data class ImageMetadata( @JvmField val metadataVersion: Int, // Bytes 0..3 - Metadata version = 1 @@ -786,4 +741,9 @@ data class ASCOMCamera( } } } + + companion object { + + @JvmStatic private val LOG = loggerFor() + } } diff --git a/nebulosa-alpaca-indi/src/main/kotlin/nebulosa/alpaca/indi/device/focusers/ASCOMFocuser.kt b/nebulosa-alpaca-indi/src/main/kotlin/nebulosa/alpaca/indi/device/focusers/ASCOMFocuser.kt index 70247550c..e3b44fcd5 100644 --- a/nebulosa-alpaca-indi/src/main/kotlin/nebulosa/alpaca/indi/device/focusers/ASCOMFocuser.kt +++ b/nebulosa-alpaca-indi/src/main/kotlin/nebulosa/alpaca/indi/device/focusers/ASCOMFocuser.kt @@ -14,37 +14,28 @@ import nebulosa.indi.device.thermometer.ThermometerDetached import nebulosa.indi.device.thermometer.ThermometerTemperatureChanged import nebulosa.indi.protocol.INDIProtocol +@Suppress("RedundantModalityModifier") data class ASCOMFocuser( override val device: ConfiguredDevice, override val service: AlpacaFocuserService, override val sender: AlpacaClient, ) : ASCOMDevice(), Focuser { - @Volatile override var moving = false - private set - @Volatile override var position = 0 - private set - @Volatile override var canAbsoluteMove = false - private set - @Volatile override var canRelativeMove = false - private set - @Volatile override var canAbort = false - private set - @Volatile override var canReverse = false - private set - @Volatile override var reversed = false - private set - @Volatile override var canSync = false - private set - @Volatile override var hasBacklash = false - private set - @Volatile override var maxPosition = 0 - private set - - @Volatile override var hasThermometer = false - private set - @Volatile override var temperature = 0.0 - private set + @Volatile final override var moving = false + @Volatile final override var position = 0 + @Volatile final override var canAbsoluteMove = false + @Volatile final override var canRelativeMove = false + @Volatile final override var canAbort = false + @Volatile final override var canReverse = false + @Volatile final override var reversed = false + @Volatile final override var canSync = false + @Volatile final override var hasBacklash = false + @Volatile final override var maxPosition = 0 + + @Volatile final override var hasThermometer = false + @Volatile final override var temperature = 0.0 + + override val snoopedDevices = emptyList() override fun moveFocusIn(steps: Int) { if (canAbsoluteMove) { diff --git a/nebulosa-alpaca-indi/src/main/kotlin/nebulosa/alpaca/indi/device/mounts/ASCOMMount.kt b/nebulosa-alpaca-indi/src/main/kotlin/nebulosa/alpaca/indi/device/mounts/ASCOMMount.kt index d87ded2f8..02947cb0a 100644 --- a/nebulosa-alpaca-indi/src/main/kotlin/nebulosa/alpaca/indi/device/mounts/ASCOMMount.kt +++ b/nebulosa-alpaca-indi/src/main/kotlin/nebulosa/alpaca/indi/device/mounts/ASCOMMount.kt @@ -8,6 +8,7 @@ import nebulosa.indi.device.guide.GuideOutputPulsingChanged import nebulosa.indi.device.mount.* import nebulosa.indi.device.mount.PierSide import nebulosa.indi.protocol.INDIProtocol +import nebulosa.log.loggerFor import nebulosa.math.* import nebulosa.nova.position.ICRF import nebulosa.time.CurrentTime @@ -15,66 +16,43 @@ import java.time.Duration import java.time.OffsetDateTime import java.time.ZoneOffset +@Suppress("RedundantModalityModifier") data class ASCOMMount( override val device: ConfiguredDevice, override val service: AlpacaTelescopeService, override val sender: AlpacaClient, ) : ASCOMDevice(), Mount { - @Volatile override var slewing = false - private set - @Volatile override var tracking = false - private set - @Volatile override var parking = false - private set - @Volatile override var parked = false - private set - @Volatile override var canAbort = true - private set - @Volatile override var canSync = false - private set - @Volatile override var canGoTo = false - private set - @Volatile override var canPark = false - private set - @Volatile override var canHome = false - private set - @Volatile override var slewRates = emptyList() - private set - @Volatile override var slewRate: SlewRate? = null - private set - @Volatile override var mountType = MountType.EQ_GEM - private set - @Volatile override var trackModes = emptyList() - private set - @Volatile override var trackMode = TrackMode.SIDEREAL - private set - @Volatile override var pierSide = PierSide.NEITHER - private set - @Volatile override var guideRateWE = 0.0 - private set - @Volatile override var guideRateNS = 0.0 - private set - @Volatile override var rightAscension = 0.0 - private set - @Volatile override var declination = 0.0 - private set - - @Volatile override var canPulseGuide = false - private set - @Volatile override var pulseGuiding = false - private set - - @Volatile override var hasGPS = false - private set - @Volatile override var longitude = 0.0 - private set - @Volatile override var latitude = 0.0 - private set - @Volatile override var elevation = 0.0 - private set - @Volatile override var dateTime = OffsetDateTime.now()!! - private set + @Volatile final override var slewing = false + @Volatile final override var tracking = false + @Volatile final override var parking = false + @Volatile final override var parked = false + @Volatile final override var canAbort = true + @Volatile final override var canSync = false + @Volatile final override var canGoTo = false + @Volatile final override var canPark = false + @Volatile final override var canHome = false + @Volatile final override var slewRates = emptyList() + @Volatile final override var slewRate: SlewRate? = null + @Volatile final override var mountType = MountType.EQ_GEM + @Volatile final override var trackModes = emptyList() + @Volatile final override var trackMode = TrackMode.SIDEREAL + @Volatile final override var pierSide = PierSide.NEITHER + @Volatile final override var guideRateWE = 0.0 + @Volatile final override var guideRateNS = 0.0 + @Volatile final override var rightAscension = 0.0 + @Volatile final override var declination = 0.0 + + @Volatile final override var canPulseGuide = false + @Volatile final override var pulseGuiding = false + + @Volatile final override var hasGPS = false + @Volatile final override var longitude = 0.0 + @Volatile final override var latitude = 0.0 + @Volatile final override var elevation = 0.0 + @Volatile final override var dateTime = OffsetDateTime.now()!! + + override val snoopedDevices = emptyList() private val axisRates = HashMap(4) @Volatile private var axisRate: AxisRate? = null @@ -236,8 +214,8 @@ data class ASCOMMount( override fun coordinates(longitude: Angle, latitude: Angle, elevation: Distance) { service.siteLongitude(device.number, longitude.toDegrees).doRequest {} && - service.siteLatitude(device.number, latitude.toDegrees).doRequest {} && - service.siteElevation(device.number, elevation.toMeters).doRequest {} + service.siteLatitude(device.number, latitude.toDegrees).doRequest {} && + service.siteElevation(device.number, elevation.toMeters).doRequest {} } override fun dateTime(dateTime: OffsetDateTime) { @@ -255,8 +233,6 @@ data class ASCOMMount( processDateTime() equatorialSystem = service.equatorialSystem(device.number).doRequest()?.value ?: equatorialSystem - - LOG.info("The mount {} uses {} equatorial system", name, equatorialSystem) } override fun onDisconnected() {} @@ -475,4 +451,9 @@ data class ASCOMMount( } } } + + companion object { + + @JvmStatic private val LOG = loggerFor() + } } diff --git a/nebulosa-alpaca-indi/src/main/kotlin/nebulosa/alpaca/indi/device/wheels/ASCOMFilterWheel.kt b/nebulosa-alpaca-indi/src/main/kotlin/nebulosa/alpaca/indi/device/wheels/ASCOMFilterWheel.kt index 846b76726..b790fc497 100644 --- a/nebulosa-alpaca-indi/src/main/kotlin/nebulosa/alpaca/indi/device/wheels/ASCOMFilterWheel.kt +++ b/nebulosa-alpaca-indi/src/main/kotlin/nebulosa/alpaca/indi/device/wheels/ASCOMFilterWheel.kt @@ -10,20 +10,19 @@ import nebulosa.indi.device.filterwheel.FilterWheelNamesChanged import nebulosa.indi.device.filterwheel.FilterWheelPositionChanged import nebulosa.indi.protocol.INDIProtocol +@Suppress("RedundantModalityModifier") data class ASCOMFilterWheel( override val device: ConfiguredDevice, override val service: AlpacaFilterWheelService, override val sender: AlpacaClient, ) : ASCOMDevice(), FilterWheel { - @Volatile override var count = 0 - private set - @Volatile override var position = 0 - private set - @Volatile override var moving = false - private set - @Volatile override var names: List = emptyList() - private set + @Volatile final override var count = 0 + @Volatile final override var position = 0 + @Volatile final override var moving = false + @Volatile final override var names = emptyList() + + override val snoopedDevices = emptyList() override fun onConnected() { processPosition() diff --git a/nebulosa-fits/src/main/kotlin/nebulosa/fits/FitsHeader.kt b/nebulosa-fits/src/main/kotlin/nebulosa/fits/FitsHeader.kt index c91302739..2925f66b3 100644 --- a/nebulosa-fits/src/main/kotlin/nebulosa/fits/FitsHeader.kt +++ b/nebulosa-fits/src/main/kotlin/nebulosa/fits/FitsHeader.kt @@ -54,7 +54,7 @@ open class FitsHeader : AbstractHeader { FitsHeaderCard.create(key, value, comment).also(::add) } - open fun add(card: FitsHeaderCard) { + override fun add(card: HeaderCard) { if (!card.isKeyValuePair) cards.add(card) else { val index = cards.indexOfFirst { it.key == card.key } @@ -87,7 +87,7 @@ open class FitsHeader : AbstractHeader { final override fun add(key: String, value: String, comment: String) = Unit - final override fun add(card: FitsHeaderCard) = Unit + final override fun add(card: HeaderCard) = Unit final override fun delete(key: HeaderKey) = false diff --git a/nebulosa-image-format/src/main/kotlin/nebulosa/image/format/Header.kt b/nebulosa-image-format/src/main/kotlin/nebulosa/image/format/Header.kt index 637b5633f..e8fd2a4f0 100644 --- a/nebulosa-image-format/src/main/kotlin/nebulosa/image/format/Header.kt +++ b/nebulosa-image-format/src/main/kotlin/nebulosa/image/format/Header.kt @@ -28,6 +28,8 @@ interface Header : ReadableHeader, WritableHeader, Cloneable { override fun add(key: String, value: String, comment: String) = Unit + override fun add(card: HeaderCard) = Unit + override fun delete(key: String) = false override fun hasNext() = false diff --git a/nebulosa-image-format/src/main/kotlin/nebulosa/image/format/WritableHeader.kt b/nebulosa-image-format/src/main/kotlin/nebulosa/image/format/WritableHeader.kt index 72e18ca79..deb3515cd 100644 --- a/nebulosa-image-format/src/main/kotlin/nebulosa/image/format/WritableHeader.kt +++ b/nebulosa-image-format/src/main/kotlin/nebulosa/image/format/WritableHeader.kt @@ -20,6 +20,8 @@ interface WritableHeader { fun add(key: String, value: String, comment: String = "") + fun add(card: HeaderCard) + fun delete(key: HeaderKey) = delete(key.key) fun delete(key: String): Boolean diff --git a/nebulosa-indi-client/src/main/kotlin/nebulosa/indi/client/device/GPSDevice.kt b/nebulosa-indi-client/src/main/kotlin/nebulosa/indi/client/device/GPSDevice.kt index f9616ba1d..37c82ab5b 100644 --- a/nebulosa-indi-client/src/main/kotlin/nebulosa/indi/client/device/GPSDevice.kt +++ b/nebulosa-indi-client/src/main/kotlin/nebulosa/indi/client/device/GPSDevice.kt @@ -18,15 +18,10 @@ internal open class GPSDevice( ) : INDIDevice(), GPS { @Volatile final override var hasGPS = true - private set @Volatile final override var longitude = 0.0 - private set @Volatile final override var latitude = 0.0 - private set @Volatile final override var elevation = 0.0 - private set @Volatile final override var dateTime = OffsetDateTime.MIN!! - private set override fun handleMessage(message: INDIProtocol) { when (message) { @@ -63,6 +58,6 @@ internal open class GPSDevice( override fun toString(): String { return "GPS(hasGPS=$hasGPS, longitude=$longitude, latitude=$latitude," + - " elevation=$elevation, dateTime=$dateTime)" + " elevation=$elevation, dateTime=$dateTime)" } } diff --git a/nebulosa-indi-client/src/main/kotlin/nebulosa/indi/client/device/INDIDevice.kt b/nebulosa-indi-client/src/main/kotlin/nebulosa/indi/client/device/INDIDevice.kt index d8abf136e..4c02e94da 100644 --- a/nebulosa-indi-client/src/main/kotlin/nebulosa/indi/client/device/INDIDevice.kt +++ b/nebulosa-indi-client/src/main/kotlin/nebulosa/indi/client/device/INDIDevice.kt @@ -3,11 +3,6 @@ package nebulosa.indi.client.device import nebulosa.indi.client.INDIClient import nebulosa.indi.client.device.cameras.INDICamera import nebulosa.indi.device.* -import nebulosa.indi.device.camera.Camera -import nebulosa.indi.device.filterwheel.FilterWheel -import nebulosa.indi.device.focuser.Focuser -import nebulosa.indi.device.mount.Mount -import nebulosa.indi.device.rotator.Rotator import nebulosa.indi.protocol.* import nebulosa.indi.protocol.Vector import nebulosa.log.loggerFor @@ -25,6 +20,8 @@ internal abstract class INDIDevice : Device { @Volatile override var connected = false protected set + override val snoopedDevices = ArrayList(4) + private fun addMessageAndFireEvent(text: String) { synchronized(messages) { messages.addFirst(text) @@ -183,23 +180,10 @@ internal abstract class INDIDevice : Device { } override fun snoop(devices: Iterable) { - val ccd = devices.firstOrNull { it is Camera }?.name ?: "" - val telescope = devices.firstOrNull { it is Mount }?.name ?: "" - val focuser = devices.firstOrNull { it is Focuser }?.name ?: "" - val filter = devices.firstOrNull { it is FilterWheel }?.name ?: "" - val rotator = devices.firstOrNull { it is Rotator }?.name ?: "" - - LOG.info( - "$name is snooping devices. ccd={}, telescope={}, focuser={}, filter={}, rotator={}", - ccd, telescope, focuser, filter, rotator - ) - - if (this is Camera) { - sendNewText( - "ACTIVE_DEVICES", - "ACTIVE_TELESCOPE" to telescope, "ACTIVE_ROTATOR" to rotator, - "ACTIVE_FOCUSER" to focuser, "ACTIVE_FILTER" to filter, - ) + snoopedDevices.clear() + + for (device in devices) { + device?.also(snoopedDevices::add) } } diff --git a/nebulosa-indi-client/src/main/kotlin/nebulosa/indi/client/device/INDIDeviceProtocolHandler.kt b/nebulosa-indi-client/src/main/kotlin/nebulosa/indi/client/device/INDIDeviceProtocolHandler.kt index 824c40ee4..0da39ca34 100644 --- a/nebulosa-indi-client/src/main/kotlin/nebulosa/indi/client/device/INDIDeviceProtocolHandler.kt +++ b/nebulosa-indi-client/src/main/kotlin/nebulosa/indi/client/device/INDIDeviceProtocolHandler.kt @@ -4,6 +4,7 @@ import nebulosa.indi.device.* import nebulosa.indi.device.camera.Camera import nebulosa.indi.device.camera.CameraAttached import nebulosa.indi.device.camera.CameraDetached +import nebulosa.indi.device.camera.GuideHead import nebulosa.indi.device.filterwheel.FilterWheel import nebulosa.indi.device.filterwheel.FilterWheelAttached import nebulosa.indi.device.filterwheel.FilterWheelDetached @@ -86,11 +87,25 @@ abstract class INDIDeviceProtocolHandler : MessageSender, INDIProtocolParser, Cl internal fun unregisterGPS(device: GPS) { if (device.name in gps) { - guideOutputs.remove(device.name) + gps.remove(device.name) fireOnEventReceived(GPSDetached(device)) } } + internal fun registerGuideHead(device: GuideHead) { + if (device.name !in cameras) { + cameras[device.name] = device + fireOnEventReceived(CameraAttached(device)) + } + } + + internal fun unregisterGuiderHead(device: GuideHead) { + if (device.name in cameras) { + cameras.remove(device.name) + fireOnEventReceived(CameraDetached(device)) + } + } + internal fun registerGuideOutput(device: GuideOutput) { if (device.name !in guideOutputs) { guideOutputs[device.name] = device @@ -287,7 +302,7 @@ abstract class INDIDeviceProtocolHandler : MessageSender, INDIProtocolParser, Cl if (device == null) { val text = "[%s]: %s\n".format(message.timestamp, message.message) fireOnEventReceived(DeviceMessageReceived(null, text)) - } else { + } else if (message.name.isNotEmpty()) { device.handleMessage(message) } diff --git a/nebulosa-indi-client/src/main/kotlin/nebulosa/indi/client/device/cameras/INDICamera.kt b/nebulosa-indi-client/src/main/kotlin/nebulosa/indi/client/device/cameras/INDICamera.kt index d796e03f2..c633a3d7d 100644 --- a/nebulosa-indi-client/src/main/kotlin/nebulosa/indi/client/device/cameras/INDICamera.kt +++ b/nebulosa-indi-client/src/main/kotlin/nebulosa/indi/client/device/cameras/INDICamera.kt @@ -1,20 +1,22 @@ package nebulosa.indi.client.device.cameras -import nebulosa.fits.fits +import nebulosa.fits.FitsHeaderCard import nebulosa.image.algorithms.transformation.CfaPattern +import nebulosa.image.format.HeaderCard import nebulosa.indi.client.INDIClient import nebulosa.indi.client.device.INDIDevice +import nebulosa.indi.device.Device import nebulosa.indi.device.camera.* -import nebulosa.indi.device.camera.Camera.Companion.NANO_SECONDS +import nebulosa.indi.device.camera.Camera.Companion.NANO_TO_SECONDS +import nebulosa.indi.device.filterwheel.FilterWheel +import nebulosa.indi.device.focuser.Focuser import nebulosa.indi.device.guide.GuideOutputPulsingChanged +import nebulosa.indi.device.mount.Mount +import nebulosa.indi.device.rotator.Rotator import nebulosa.indi.protocol.* import nebulosa.io.Base64InputStream -import nebulosa.io.transferAndClose import nebulosa.log.loggerFor -import nebulosa.xisf.xisf -import java.nio.file.Files import java.time.Duration -import kotlin.io.path.outputStream // https://github.com/indilib/indi/blob/master/libs/indibase/indiccd.cpp @@ -24,119 +26,72 @@ internal open class INDICamera( ) : INDIDevice(), Camera { @Volatile final override var exposuring = false - private set @Volatile final override var hasCoolerControl = false - private set @Volatile final override var coolerPower = 0.0 - private set @Volatile final override var cooler = false - private set @Volatile final override var hasDewHeater = false - private set @Volatile final override var dewHeater = false - private set @Volatile final override var frameFormats = emptyList() - private set @Volatile final override var canAbort = false - private set @Volatile final override var cfaOffsetX = 0 - private set @Volatile final override var cfaOffsetY = 0 - private set @Volatile final override var cfaType = CfaPattern.RGGB - private set @Volatile final override var exposureMin: Duration = Duration.ZERO - private set @Volatile final override var exposureMax: Duration = Duration.ZERO - private set @Volatile final override var exposureState = PropertyState.IDLE - private set @Volatile final override var exposureTime: Duration = Duration.ZERO - private set @Volatile final override var hasCooler = false - private set @Volatile final override var canSetTemperature = false - private set @Volatile final override var canSubFrame = false - private set @Volatile final override var x = 0 - private set @Volatile final override var minX = 0 - private set @Volatile final override var maxX = 0 - private set @Volatile final override var y = 0 - private set @Volatile final override var minY = 0 - private set @Volatile final override var maxY = 0 - private set @Volatile final override var width = 0 - private set @Volatile final override var minWidth = 0 - private set @Volatile final override var maxWidth = 0 - private set @Volatile final override var height = 0 - private set @Volatile final override var minHeight = 0 - private set @Volatile final override var maxHeight = 0 - private set @Volatile final override var canBin = false - private set @Volatile final override var maxBinX = 1 - private set @Volatile final override var maxBinY = 1 - private set @Volatile final override var binX = 1 - private set @Volatile final override var binY = 1 - private set @Volatile final override var gain = 0 - private set @Volatile final override var gainMin = 0 - private set @Volatile final override var gainMax = 0 - private set @Volatile final override var offset = 0 - private set @Volatile final override var offsetMin = 0 - private set @Volatile final override var offsetMax = 0 - private set - @Volatile final override var hasGuiderHead = false // TODO: Handle guider head. - private set @Volatile final override var pixelSizeX = 0.0 - private set @Volatile final override var pixelSizeY = 0.0 - private set @Volatile final override var hasThermometer = false - private set @Volatile final override var temperature = 0.0 - private set @Volatile final override var canPulseGuide = false - private set @Volatile final override var pulseGuiding = false - private set - private val savePath = Files.createTempFile(name, ".camera") + final override var guideHead: GuideHeadCamera? = null + private set override fun handleMessage(message: INDIProtocol) { + val isGuider = message.name[0] == 'G' + val isGuideHead = this is GuideHead + when (message) { is SwitchVector<*> -> { when (message.name) { "CCD_COOLER" -> { if (message is DefSwitchVector) { hasCoolerControl = true - sender.fireOnEventReceived(CameraCoolerControlChanged(this)) } cooler = message["COOLER_ON"]?.value ?: false - sender.fireOnEventReceived(CameraCoolerChanged(this)) } "CCD_CAPTURE_FORMAT" -> { @@ -145,8 +100,9 @@ internal open class INDICamera( sender.fireOnEventReceived(CameraFrameFormatsChanged(this)) } } - "CCD_ABORT_EXPOSURE" -> { - if (message is DefSwitchVector) { + "CCD_ABORT_EXPOSURE", + "GUIDER_ABORT_EXPOSURE" -> { + if (isGuider == isGuideHead && message is DefSwitchVector) { canAbort = message.isNotReadOnly sender.fireOnEventReceived(CameraCanAbortChanged(this)) } @@ -165,47 +121,53 @@ internal open class INDICamera( } is NumberVector<*> -> { when (message.name) { - "CCD_INFO" -> { - pixelSizeX = message["CCD_PIXEL_SIZE_X"]?.value ?: 0.0 - pixelSizeY = message["CCD_PIXEL_SIZE_Y"]?.value ?: 0.0 - - sender.fireOnEventReceived(CameraPixelSizeChanged(this)) - } - "CCD_EXPOSURE" -> { - val element = message["CCD_EXPOSURE_VALUE"]!! + "CCD_INFO", + "GUIDER_INFO" -> { + if (isGuider == isGuideHead) { + pixelSizeX = message["CCD_PIXEL_SIZE_X"]?.value ?: 0.0 + pixelSizeY = message["CCD_PIXEL_SIZE_Y"]?.value ?: 0.0 - if (element is DefNumber) { - exposureMin = Duration.ofNanos((element.min * NANO_SECONDS).toLong()) - exposureMax = Duration.ofNanos((element.max * NANO_SECONDS).toLong()) - sender.fireOnEventReceived(CameraExposureMinMaxChanged(this)) + sender.fireOnEventReceived(CameraPixelSizeChanged(this)) } + } + "CCD_EXPOSURE", + "GUIDER_EXPOSURE" -> { + if (isGuider == isGuideHead) { + val element = message[if (isGuider) "GUIDER_EXPOSURE_VALUE" else "CCD_EXPOSURE_VALUE"]!! + + if (element is DefNumber) { + exposureMin = Duration.ofNanos((element.min * NANO_TO_SECONDS).toLong()) + exposureMax = Duration.ofNanos((element.max * NANO_TO_SECONDS).toLong()) + sender.fireOnEventReceived(CameraExposureMinMaxChanged(this)) + } - val prevExposureState = exposureState - exposureState = message.state + val prevExposureState = exposureState + exposureState = message.state - if (exposureState == PropertyState.BUSY || exposureState == PropertyState.OK) { - exposureTime = Duration.ofNanos((element.value * NANO_SECONDS).toLong()) + if (exposureState == PropertyState.BUSY || exposureState == PropertyState.OK) { + exposureTime = Duration.ofNanos((element.value * NANO_TO_SECONDS).toLong()) - sender.fireOnEventReceived(CameraExposureProgressChanged(this)) - } + sender.fireOnEventReceived(CameraExposureProgressChanged(this)) + } - val prevIsExposuring = exposuring - exposuring = exposureState == PropertyState.BUSY + val prevIsExposuring = exposuring + exposuring = exposureState == PropertyState.BUSY - if (prevIsExposuring != exposuring) { - sender.fireOnEventReceived(CameraExposuringChanged(this)) - } + if (prevIsExposuring != exposuring) { + sender.fireOnEventReceived(CameraExposuringChanged(this)) + } - if (exposureState == PropertyState.IDLE && (prevExposureState == PropertyState.BUSY || exposuring)) { - sender.fireOnEventReceived(CameraExposureAborted(this)) - } else if (exposureState == PropertyState.OK && prevExposureState == PropertyState.BUSY) { - sender.fireOnEventReceived(CameraExposureFinished(this)) - } else if (exposureState == PropertyState.ALERT && prevExposureState != PropertyState.ALERT) { - sender.fireOnEventReceived(CameraExposureFailed(this)) - } + if (exposureState == PropertyState.IDLE && (prevExposureState == PropertyState.BUSY || exposuring)) { + sender.fireOnEventReceived(CameraExposureAborted(this)) + } else if (exposureState == PropertyState.OK && prevExposureState == PropertyState.BUSY) { + sender.fireOnEventReceived(CameraExposureFinished(this)) + } else if (exposureState == PropertyState.ALERT && prevExposureState != PropertyState.ALERT) { + sender.fireOnEventReceived(CameraExposureFailed(this)) + } - if (prevExposureState != exposureState) { - sender.fireOnEventReceived(CameraExposureStateChanged(this, prevExposureState)) + if (prevExposureState != exposureState) { + sender.fireOnEventReceived(CameraExposureStateChanged(this, prevExposureState)) + } } } "CCD_COOLER_POWER" -> { @@ -220,7 +182,7 @@ internal open class INDICamera( sender.fireOnEventReceived(CameraHasCoolerChanged(this)) sender.fireOnEventReceived(CameraCanSetTemperatureChanged(this)) - if (!hasThermometer) { + if (!hasThermometer && !isGuideHead) { hasThermometer = true sender.registerThermometer(this) } @@ -229,108 +191,104 @@ internal open class INDICamera( temperature = message["CCD_TEMPERATURE_VALUE"]!!.value sender.fireOnEventReceived(CameraTemperatureChanged(this)) } - "CCD_FRAME" -> { - if (message is DefNumberVector) { - canSubFrame = message.isNotReadOnly - sender.fireOnEventReceived(CameraCanSubFrameChanged(this)) - - val minX = message["X"]!!.min.toInt() - val maxX = message["X"]!!.max.toInt() - val minY = message["Y"]!!.min.toInt() - val maxY = message["Y"]!!.max.toInt() - val minWidth = message["WIDTH"]!!.min.toInt() - val maxWidth = message["WIDTH"]!!.max.toInt() - val minHeight = message["HEIGHT"]!!.min.toInt() - val maxHeight = message["HEIGHT"]!!.max.toInt() - - this.minX = minX - this.maxX = maxX - this.minY = minY - this.maxY = maxY - this.minWidth = minWidth - this.maxWidth = maxWidth - this.minHeight = minHeight - this.maxHeight = maxHeight - } - - val x = message["X"]!!.value.toInt() - val y = message["Y"]!!.value.toInt() - val width = message["WIDTH"]!!.value.toInt() - val height = message["HEIGHT"]!!.value.toInt() + "CCD_FRAME", + "GUIDER_FRAME" -> { + if (isGuider == isGuideHead) { + if (message is DefNumberVector) { + canSubFrame = message.isNotReadOnly + sender.fireOnEventReceived(CameraCanSubFrameChanged(this)) + + minX = message["X"]!!.min.toInt() + maxX = message["X"]!!.max.toInt() + minY = message["Y"]!!.min.toInt() + maxY = message["Y"]!!.max.toInt() + minWidth = message["WIDTH"]!!.min.toInt() + maxWidth = message["WIDTH"]!!.max.toInt() + minHeight = message["HEIGHT"]!!.min.toInt() + maxHeight = message["HEIGHT"]!!.max.toInt() + } - this.x = x - this.y = y - this.width = width - this.height = height + x = message["X"]!!.value.toInt() + y = message["Y"]!!.value.toInt() + width = message["WIDTH"]!!.value.toInt() + height = message["HEIGHT"]!!.value.toInt() - sender.fireOnEventReceived(CameraFrameChanged(this)) + sender.fireOnEventReceived(CameraFrameChanged(this)) + } } - "CCD_BINNING" -> { - if (message is DefNumberVector) { - canBin = message.isNotReadOnly - maxBinX = message["HOR_BIN"]!!.max.toInt() - maxBinY = message["VER_BIN"]!!.max.toInt() + "CCD_BINNING", + "GUIDER_BINNING" -> { + if (isGuider == isGuideHead) { + if (message is DefNumberVector) { + canBin = message.isNotReadOnly + maxBinX = message["HOR_BIN"]!!.max.toInt() + maxBinY = message["VER_BIN"]!!.max.toInt() + sender.fireOnEventReceived(CameraCanBinChanged(this)) + } - sender.fireOnEventReceived(CameraCanBinChanged(this)) + binX = message["HOR_BIN"]!!.value.toInt() + binY = message["VER_BIN"]!!.value.toInt() + sender.fireOnEventReceived(CameraBinChanged(this)) } - - binX = message["HOR_BIN"]!!.value.toInt() - binY = message["VER_BIN"]!!.value.toInt() - - sender.fireOnEventReceived(CameraBinChanged(this)) } "TELESCOPE_TIMED_GUIDE_NS", "TELESCOPE_TIMED_GUIDE_WE" -> { - if (!canPulseGuide && message is DefNumberVector) { - canPulseGuide = true + if (!isGuideHead) { + if (!canPulseGuide && message is DefNumberVector) { + canPulseGuide = true - sender.registerGuideOutput(this) + sender.registerGuideOutput(this) - LOG.info("guide output attached: {}", name) - } else { - val prevIsPulseGuiding = pulseGuiding - pulseGuiding = message.isBusy + LOG.info("guide output attached: {}", name) + } else { + val prevIsPulseGuiding = pulseGuiding + pulseGuiding = message.isBusy - if (pulseGuiding != prevIsPulseGuiding) { - sender.fireOnEventReceived(GuideOutputPulsingChanged(this)) + if (pulseGuiding != prevIsPulseGuiding) { + sender.fireOnEventReceived(GuideOutputPulsingChanged(this)) + } } + + return } } } } - is SetBLOBVector -> { - when (message.name) { - "CCD1" -> { - val ccd1 = message["CCD1"]!! - - val format = CameraFrameCaptured.Format.from(ccd1.format) + is DefBLOBVector -> { + if (!isGuideHead && message.name == "CCD2" && guideHead == null) { + guideHead = GuideHeadCamera(this) + sender.registerGuideHead(guideHead!!) - if (format != CameraFrameCaptured.Format.RAW) { - val stream = Base64InputStream(ccd1.value) - stream.transferAndClose(savePath.outputStream()) + LOG.info("guide head attached: {}", name) - val compressed = COMPRESSION_FORMATS.any { ccd1.format.endsWith(it, true) } - - val image = when (format) { - CameraFrameCaptured.Format.FITS -> savePath.fits() - CameraFrameCaptured.Format.XISF -> savePath.xisf() - else -> throw IllegalStateException("impossible format") - } + return + } + } + is SetBLOBVector -> { + // Main camera handles both messages. + if (!isGuideHead) { + val ccd = message[message.name]!! - LOG.info("saved {} file at {}. compressed={}", format, savePath, compressed) + if (ccd.format.contains("fits", true)) { + val compressed = COMPRESSION_FORMATS.any { ccd.format.endsWith(it, true) } - sender.fireOnEventReceived(CameraFrameCaptured(this, image, compressed, format)) + if (!compressed) { + val stream = Base64InputStream(ccd.value) + val camera = if (message.name == "CCD2") guideHead!! else this + sender.fireOnEventReceived(CameraFrameCaptured(camera, stream = stream)) + } else { + LOG.warn("compressed FITS is not supported yet") } } - "CCD2" -> { - // TODO: Handle Guider Head frame. - } + + return } } else -> Unit } super.handleMessage(message) + guideHead?.handleMessage(message) } override fun cooler(enabled: Boolean) { @@ -354,7 +312,8 @@ internal open class INDICamera( } override fun frameType(type: FrameType) { - sendNewSwitch("CCD_FRAME_TYPE", "FRAME_$type" to true) + val name = if (this is GuideHead) "GUIDER_FRAME_TYPE" else "CCD_FRAME_TYPE" + sendNewSwitch(name, "FRAME_$type" to true) } override fun frame(x: Int, y: Int, width: Int, height: Int) { @@ -375,13 +334,21 @@ internal open class INDICamera( override fun offset(value: Int) = Unit override fun startCapture(exposureTime: Duration) { - val exposureInSeconds = exposureTime.toNanos() / NANO_SECONDS - sendNewNumber("CCD_EXPOSURE", "CCD_EXPOSURE_VALUE" to exposureInSeconds) + sendNewSwitch("CCD_TRANSFER_FORMAT", "FORMAT_FITS" to true) + + val exposureInSeconds = exposureTime.toNanos() / NANO_TO_SECONDS + + if (this is GuideHead) { + sendNewNumber("GUIDER_EXPOSURE", "GUIDER_EXPOSURE_VALUE" to exposureInSeconds) + } else { + sendNewNumber("CCD_EXPOSURE", "CCD_EXPOSURE_VALUE" to exposureInSeconds) + } } override fun abortCapture() { if (canAbort) { - sendNewSwitch("CCD_ABORT_EXPOSURE", "ABORT" to true) + val name = if (this is GuideHead) "GUIDER_ABORT_EXPOSURE" else "CCD_ABORT_EXPOSURE" + sendNewSwitch(name, "ABORT" to true) } } @@ -409,6 +376,30 @@ internal open class INDICamera( } } + override fun snoop(devices: Iterable) { + super.snoop(devices) + + val telescope = devices.firstOrNull { it is Mount }?.name ?: "" + val focuser = devices.firstOrNull { it is Focuser }?.name ?: "" + val filter = devices.firstOrNull { it is FilterWheel }?.name ?: "" + val rotator = devices.firstOrNull { it is Rotator }?.name ?: "" + + sendNewText( + "ACTIVE_DEVICES", + "ACTIVE_TELESCOPE" to telescope, "ACTIVE_ROTATOR" to rotator, + "ACTIVE_FOCUSER" to focuser, "ACTIVE_FILTER" to filter, + ) + } + + private fun sendFITSKeyword(card: HeaderCard) { + sendNewText("FITS_HEADER", "KEYWORD_NAME" to card.key, "KEYWORD_VALUE" to card.value, "KEYWORD_COMMENT" to card.comment) + } + + override fun fitsKeywords(vararg cards: HeaderCard) { + sendFITSKeyword(INDI_CLEAR) + cards.forEach(::sendFITSKeyword) + } + override fun close() { if (hasThermometer) { sender.unregisterThermometer(this) @@ -421,6 +412,12 @@ internal open class INDICamera( canPulseGuide = false LOG.info("guide output detached: {}", name) } + + if (guideHead != null) { + guideHead?.also(sender::unregisterGuiderHead) + guideHead = null + LOG.info("guide head detached: {}", name) + } } protected fun processGain(message: NumberVector<*>, element: NumberElement) { @@ -464,12 +461,65 @@ internal open class INDICamera( " canBin=$canBin, maxBinX=$maxBinX, maxBinY=$maxBinY," + " binX=$binX, binY=$binY, gain=$gain, gainMin=$gainMin," + " gainMax=$gainMax, offset=$offset, offsetMin=$offsetMin," + - " offsetMax=$offsetMax, hasGuiderHead=$hasGuiderHead," + - " canPulseGuide=$canPulseGuide, pulseGuiding=$pulseGuiding)" + " offsetMax=$offsetMax, canPulseGuide=$canPulseGuide, pulseGuiding=$pulseGuiding)" + + internal data class GuideHeadCamera(override val main: INDICamera) : GuideHead, INDICamera(main.sender, main.name + " $GUIDE_HEAD_SUFFIX") { + + init { + exposuring = main.exposuring + hasCoolerControl = main.hasCoolerControl + coolerPower = main.coolerPower + cooler = main.cooler + hasDewHeater = main.hasDewHeater + dewHeater = main.dewHeater + frameFormats = main.frameFormats + canAbort = main.canAbort + cfaOffsetX = main.cfaOffsetX + cfaOffsetY = main.cfaOffsetY + cfaType = main.cfaType + exposureMin = main.exposureMin + exposureMax = main.exposureMax + exposureState = main.exposureState + exposureTime = main.exposureTime + hasCooler = main.hasCooler + canSetTemperature = main.canSetTemperature + canSubFrame = main.canSubFrame + x = main.x + minX = main.minX + maxX = main.maxX + y = main.y + minY = main.minY + maxY = main.maxY + width = main.width + minWidth = main.minWidth + maxWidth = main.maxWidth + height = main.height + minHeight = main.minHeight + maxHeight = main.maxHeight + canBin = main.canBin + maxBinX = main.maxBinX + maxBinY = main.maxBinY + binX = main.binX + binY = main.binY + gain = main.gain + gainMin = main.gainMin + gainMax = main.gainMax + offset = main.offset + offsetMin = main.offsetMin + offsetMax = main.offsetMax + pixelSizeX = main.pixelSizeX + pixelSizeY = main.pixelSizeY + } + + override fun toString() = "GuideHead(guideHead=${super.toString()}, main=$main)" + } companion object { - @JvmStatic private val COMPRESSION_FORMATS = arrayOf(".fz", ".gz", ".z") + const val GUIDE_HEAD_SUFFIX = "(Guide Head)" + + @JvmStatic private val COMPRESSION_FORMATS = arrayOf(".fz", ".gz") @JvmStatic private val LOG = loggerFor() + @JvmStatic private val INDI_CLEAR = FitsHeaderCard.create("INDI_CLEAR", "", "") } } diff --git a/nebulosa-indi-client/src/main/kotlin/nebulosa/indi/client/device/focusers/INDIFocuser.kt b/nebulosa-indi-client/src/main/kotlin/nebulosa/indi/client/device/focusers/INDIFocuser.kt index c3f85c2b9..fc167a083 100644 --- a/nebulosa-indi-client/src/main/kotlin/nebulosa/indi/client/device/focusers/INDIFocuser.kt +++ b/nebulosa-indi-client/src/main/kotlin/nebulosa/indi/client/device/focusers/INDIFocuser.kt @@ -16,30 +16,18 @@ internal open class INDIFocuser( ) : INDIDevice(), Focuser { @Volatile final override var moving = false - private set @Volatile final override var position = 0 - private set @Volatile final override var canAbsoluteMove = false - private set @Volatile final override var canRelativeMove = false - private set @Volatile final override var canAbort = false - private set @Volatile final override var canReverse = false - private set @Volatile final override var reversed = false - private set @Volatile final override var canSync = false - private set @Volatile final override var hasBacklash = false - private set @Volatile final override var maxPosition = 0 - private set @Volatile final override var hasThermometer = false - private set @Volatile final override var temperature = 0.0 - private set override fun handleMessage(message: INDIProtocol) { when (message) { @@ -200,10 +188,10 @@ internal open class INDIFocuser( override fun toString(): String { return "Focuser(name=$name, moving=$moving, position=$position," + - " canAbsoluteMove=$canAbsoluteMove, canRelativeMove=$canRelativeMove," + - " canAbort=$canAbort, canReverse=$canReverse, reversed=$reversed," + - " canSync=$canSync, hasBacklash=$hasBacklash," + - " maxPosition=$maxPosition, hasThermometer=$hasThermometer," + - " temperature=$temperature)" + " canAbsoluteMove=$canAbsoluteMove, canRelativeMove=$canRelativeMove," + + " canAbort=$canAbort, canReverse=$canReverse, reversed=$reversed," + + " canSync=$canSync, hasBacklash=$hasBacklash," + + " maxPosition=$maxPosition, hasThermometer=$hasThermometer," + + " temperature=$temperature)" } } diff --git a/nebulosa-indi-client/src/main/kotlin/nebulosa/indi/client/device/mounts/INDIMount.kt b/nebulosa-indi-client/src/main/kotlin/nebulosa/indi/client/device/mounts/INDIMount.kt index 630f44325..25c2ba6c7 100644 --- a/nebulosa-indi-client/src/main/kotlin/nebulosa/indi/client/device/mounts/INDIMount.kt +++ b/nebulosa-indi-client/src/main/kotlin/nebulosa/indi/client/device/mounts/INDIMount.kt @@ -23,59 +23,34 @@ internal open class INDIMount( ) : INDIDevice(), Mount { @Volatile final override var slewing = false - private set @Volatile final override var tracking = false - private set @Volatile final override var parking = false - private set @Volatile final override var parked = false - private set @Volatile final override var canAbort = false - private set @Volatile final override var canSync = false - private set @Volatile final override var canGoTo = false - private set @Volatile final override var canPark = false - private set @Volatile final override var canHome = false protected set @Volatile final override var slewRates = emptyList() - private set @Volatile final override var slewRate: SlewRate? = null - private set @Volatile final override var mountType = MountType.EQ_GEM // TODO: Ver os telescópios possui tipos. - private set @Volatile final override var trackModes = emptyList() - private set @Volatile final override var trackMode = TrackMode.SIDEREAL - private set @Volatile final override var pierSide = PierSide.NEITHER - private set @Volatile final override var guideRateWE = 0.0 // TODO: Tratar para cada driver. iOptronV3 tem RA/DE. LX200 tem 1.0x, 0.8x, 0.6x, 0.4x. - private set @Volatile final override var guideRateNS = 0.0 - private set @Volatile final override var rightAscension = 0.0 - private set @Volatile final override var declination = 0.0 - private set @Volatile final override var canPulseGuide = false - private set @Volatile final override var pulseGuiding = false - private set @Volatile final override var hasGPS = false - private set @Volatile final override var longitude = 0.0 - private set @Volatile final override var latitude = 0.0 - private set @Volatile final override var elevation = 0.0 - private set @Volatile final override var dateTime = OffsetDateTime.now()!! - private set override fun handleMessage(message: INDIProtocol) { when (message) { @@ -356,13 +331,13 @@ internal open class INDIMount( override fun toString(): String { return "Mount(name=$name, connected=$connected, slewing=$slewing, tracking=$tracking," + - " parking=$parking, parked=$parked, canAbort=$canAbort," + - " canSync=$canSync, canPark=$canPark, slewRates=$slewRates," + - " slewRate=$slewRate, mountType=$mountType, trackModes=$trackModes," + - " trackMode=$trackMode, pierSide=$pierSide, guideRateWE=$guideRateWE," + - " guideRateNS=$guideRateNS, rightAscension=$rightAscension," + - " declination=$declination, canPulseGuide=$canPulseGuide," + - " pulseGuiding=$pulseGuiding)" + " parking=$parking, parked=$parked, canAbort=$canAbort," + + " canSync=$canSync, canPark=$canPark, slewRates=$slewRates," + + " slewRate=$slewRate, mountType=$mountType, trackModes=$trackModes," + + " trackMode=$trackMode, pierSide=$pierSide, guideRateWE=$guideRateWE," + + " guideRateNS=$guideRateNS, rightAscension=$rightAscension," + + " declination=$declination, canPulseGuide=$canPulseGuide," + + " pulseGuiding=$pulseGuiding)" } companion object { diff --git a/nebulosa-indi-client/src/main/kotlin/nebulosa/indi/client/device/wheels/INDIFilterWheel.kt b/nebulosa-indi-client/src/main/kotlin/nebulosa/indi/client/device/wheels/INDIFilterWheel.kt index bd95e4c43..c7ce30b1e 100644 --- a/nebulosa-indi-client/src/main/kotlin/nebulosa/indi/client/device/wheels/INDIFilterWheel.kt +++ b/nebulosa-indi-client/src/main/kotlin/nebulosa/indi/client/device/wheels/INDIFilterWheel.kt @@ -13,11 +13,8 @@ internal open class INDIFilterWheel( ) : INDIDevice(), FilterWheel { @Volatile final override var count = 0 - private set @Volatile final override var position = 0 - private set @Volatile final override var moving = false - private set final override val names = ArrayList(12) @@ -90,6 +87,6 @@ internal open class INDIFilterWheel( override fun toString(): String { return "FilterWheel(name=$name, slotCount=$count, position=$position," + - " moving=$moving)" + " moving=$moving)" } } diff --git a/nebulosa-indi-device/src/main/kotlin/nebulosa/indi/device/CompanionDevice.kt b/nebulosa-indi-device/src/main/kotlin/nebulosa/indi/device/CompanionDevice.kt new file mode 100644 index 000000000..1b5385bb2 --- /dev/null +++ b/nebulosa-indi-device/src/main/kotlin/nebulosa/indi/device/CompanionDevice.kt @@ -0,0 +1,6 @@ +package nebulosa.indi.device + +interface CompanionDevice : Device { + + val main: Device +} diff --git a/nebulosa-indi-device/src/main/kotlin/nebulosa/indi/device/Device.kt b/nebulosa-indi-device/src/main/kotlin/nebulosa/indi/device/Device.kt index c936a63ab..60757ac91 100644 --- a/nebulosa-indi-device/src/main/kotlin/nebulosa/indi/device/Device.kt +++ b/nebulosa-indi-device/src/main/kotlin/nebulosa/indi/device/Device.kt @@ -18,6 +18,8 @@ interface Device : INDIProtocolHandler, Closeable, Comparable { val messages: List + val snoopedDevices: List + fun connect() fun disconnect() @@ -52,7 +54,7 @@ interface Device : INDIProtocolHandler, Closeable, Comparable { elements: Iterable>, ) { val vector = NewSwitchVector() - vector.device = this.name + vector.device = if (this is CompanionDevice) main.name else this.name vector.name = name for ((first, second) in elements) { @@ -77,7 +79,7 @@ interface Device : INDIProtocolHandler, Closeable, Comparable { elements: Iterable>, ) { val vector = NewNumberVector() - vector.device = this.name + vector.device = if (this is CompanionDevice) main.name else this.name vector.name = name for ((first, second) in elements) { @@ -102,7 +104,7 @@ interface Device : INDIProtocolHandler, Closeable, Comparable { elements: Iterable>, ) { val vector = NewTextVector() - vector.device = this.name + vector.device = if (this is CompanionDevice) main.name else this.name vector.name = name for ((first, second) in elements) { diff --git a/nebulosa-indi-device/src/main/kotlin/nebulosa/indi/device/camera/Camera.kt b/nebulosa-indi-device/src/main/kotlin/nebulosa/indi/device/camera/Camera.kt index 033e115d1..3ec33dcb5 100644 --- a/nebulosa-indi-device/src/main/kotlin/nebulosa/indi/device/camera/Camera.kt +++ b/nebulosa-indi-device/src/main/kotlin/nebulosa/indi/device/camera/Camera.kt @@ -1,6 +1,7 @@ package nebulosa.indi.device.camera import nebulosa.image.algorithms.transformation.CfaPattern +import nebulosa.image.format.HeaderCard import nebulosa.indi.device.guide.GuideOutput import nebulosa.indi.device.thermometer.Thermometer import nebulosa.indi.protocol.PropertyState @@ -90,7 +91,7 @@ interface Camera : GuideOutput, Thermometer { val offsetMax: Int - val hasGuiderHead: Boolean + val guideHead: GuideHead? val pixelSizeX: Double @@ -118,9 +119,11 @@ interface Camera : GuideOutput, Thermometer { fun abortCapture() + fun fitsKeywords(vararg cards: HeaderCard) + companion object { - const val NANO_SECONDS = 1_000_000_000.0 + const val NANO_TO_SECONDS = 1_000_000_000.0 @JvmStatic val DRIVERS = setOf( "indi_altair_ccd", diff --git a/nebulosa-indi-device/src/main/kotlin/nebulosa/indi/device/camera/CameraFrameCaptured.kt b/nebulosa-indi-device/src/main/kotlin/nebulosa/indi/device/camera/CameraFrameCaptured.kt index f39915186..73a022c70 100644 --- a/nebulosa-indi-device/src/main/kotlin/nebulosa/indi/device/camera/CameraFrameCaptured.kt +++ b/nebulosa-indi-device/src/main/kotlin/nebulosa/indi/device/camera/CameraFrameCaptured.kt @@ -1,23 +1,10 @@ package nebulosa.indi.device.camera -import nebulosa.image.format.ImageRepresentation +import nebulosa.fits.Fits +import java.io.InputStream data class CameraFrameCaptured( override val device: Camera, - @JvmField val image: ImageRepresentation, - @JvmField val compressed: Boolean, - @JvmField val format: Format, -) : CameraEvent { - - enum class Format(@JvmField val extension: String) { - FITS("fits"), - XISF("xisf"), - RAW("bin"); - - companion object { - - @JvmStatic - fun from(format: String) = entries.first { format.contains(it.extension, true) } - } - } -} + @JvmField val stream: InputStream? = null, + @JvmField val image: Fits? = null, +) : CameraEvent diff --git a/nebulosa-indi-device/src/main/kotlin/nebulosa/indi/device/camera/GuideHead.kt b/nebulosa-indi-device/src/main/kotlin/nebulosa/indi/device/camera/GuideHead.kt new file mode 100644 index 000000000..62b309530 --- /dev/null +++ b/nebulosa-indi-device/src/main/kotlin/nebulosa/indi/device/camera/GuideHead.kt @@ -0,0 +1,8 @@ +package nebulosa.indi.device.camera + +import nebulosa.indi.device.CompanionDevice + +interface GuideHead : Camera, CompanionDevice { + + override val main: Camera +} From 8674e55400e21f1e7bf9a6a2bc5127f92cc4f657 Mon Sep 17 00:00:00 2001 From: tiagohm Date: Sat, 30 Mar 2024 13:24:26 -0300 Subject: [PATCH 10/15] [api]: Implement XISF write --- .../src/main/kotlin/nebulosa/fits/Bitpix.kt | 2 +- .../main/kotlin/nebulosa/fits/FitsHelper.kt | 3 + .../nebulosa/io/AbstractSeekableSink.kt | 66 ++++ .../nebulosa/io/AbstractSeekableSource.kt | 59 ++++ .../main/kotlin/nebulosa/io/ByteArraySink.kt | 66 +--- .../kotlin/nebulosa/io/ByteArraySource.kt | 60 +--- .../main/kotlin/nebulosa/io/ByteBufferSink.kt | 65 +--- .../kotlin/nebulosa/io/ByteBufferSource.kt | 57 +--- nebulosa-io/src/main/kotlin/nebulosa/io/Io.kt | 12 +- .../nebulosa/io/RandomAccessFileSink.kt | 54 +--- .../nebulosa/io/RandomAccessFileSource.kt | 58 ++-- .../main/kotlin/nebulosa/io/RandomSource.kt | 62 +--- .../AbstractSeekableSinkAndSourceTest.kt | 293 ++++++++++++++++++ .../src/test/kotlin/BufferedByteArrayTest.kt | 124 -------- .../src/test/kotlin/BufferedByteBufferTest.kt | 128 -------- .../kotlin/BufferedRandomAccessFileTest.kt | 105 ------- .../src/test/kotlin/BufferedStringSpec.kt | 32 -- nebulosa-io/src/test/kotlin/ByteArrayTest.kt | 10 + .../ByteArrayWithOffsetAndLengthTest.kt | 22 ++ .../test/kotlin/ByteArrayWithOffsetTest.kt | 19 ++ nebulosa-io/src/test/kotlin/ByteBufferTest.kt | 11 + .../ByteBufferWithOffsetAndLengthTest.kt | 24 ++ .../test/kotlin/ByteBufferWithOffsetTest.kt | 21 ++ ...yteBufferWrappedWithOffsetAndLengthTest.kt | 24 ++ .../src/test/kotlin/RandomAccessFileTest.kt | 15 + ...andomSourceTest.kt => RandomSourceTest.kt} | 2 +- .../nebulosa/skycatalog/SkyObjectType.kt | 4 +- .../main/kotlin/nebulosa/xisf/XisfFormat.kt | 126 +++++++- .../nebulosa/xisf/XisfHeaderInputStream.kt | 4 +- .../nebulosa/xisf/XisfMonolithicFileHeader.kt | 37 ++- .../src/test/kotlin/XisfFormatTest.kt | 17 + .../test/kotlin/XisfHeaderInputStreamTest.kt | 28 +- 32 files changed, 853 insertions(+), 757 deletions(-) create mode 100644 nebulosa-io/src/main/kotlin/nebulosa/io/AbstractSeekableSink.kt create mode 100644 nebulosa-io/src/main/kotlin/nebulosa/io/AbstractSeekableSource.kt create mode 100644 nebulosa-io/src/test/kotlin/AbstractSeekableSinkAndSourceTest.kt delete mode 100644 nebulosa-io/src/test/kotlin/BufferedByteArrayTest.kt delete mode 100644 nebulosa-io/src/test/kotlin/BufferedByteBufferTest.kt delete mode 100644 nebulosa-io/src/test/kotlin/BufferedRandomAccessFileTest.kt delete mode 100644 nebulosa-io/src/test/kotlin/BufferedStringSpec.kt create mode 100644 nebulosa-io/src/test/kotlin/ByteArrayTest.kt create mode 100644 nebulosa-io/src/test/kotlin/ByteArrayWithOffsetAndLengthTest.kt create mode 100644 nebulosa-io/src/test/kotlin/ByteArrayWithOffsetTest.kt create mode 100644 nebulosa-io/src/test/kotlin/ByteBufferTest.kt create mode 100644 nebulosa-io/src/test/kotlin/ByteBufferWithOffsetAndLengthTest.kt create mode 100644 nebulosa-io/src/test/kotlin/ByteBufferWithOffsetTest.kt create mode 100644 nebulosa-io/src/test/kotlin/ByteBufferWrappedWithOffsetAndLengthTest.kt create mode 100644 nebulosa-io/src/test/kotlin/RandomAccessFileTest.kt rename nebulosa-io/src/test/kotlin/{BufferedRandomSourceTest.kt => RandomSourceTest.kt} (95%) diff --git a/nebulosa-fits/src/main/kotlin/nebulosa/fits/Bitpix.kt b/nebulosa-fits/src/main/kotlin/nebulosa/fits/Bitpix.kt index a88e641bb..f6bc99ba7 100644 --- a/nebulosa-fits/src/main/kotlin/nebulosa/fits/Bitpix.kt +++ b/nebulosa-fits/src/main/kotlin/nebulosa/fits/Bitpix.kt @@ -4,7 +4,7 @@ import nebulosa.image.format.HeaderCard import nebulosa.image.format.ReadableHeader import kotlin.math.abs -enum class Bitpix(val code: Int) : HeaderCard by FitsHeaderCard.create(FitsKeyword.BITPIX, code) { +enum class Bitpix(@JvmField val code: Int) : HeaderCard by FitsHeaderCard.create(FitsKeyword.BITPIX, code) { BYTE(8), SHORT(16), INTEGER(32), diff --git a/nebulosa-fits/src/main/kotlin/nebulosa/fits/FitsHelper.kt b/nebulosa-fits/src/main/kotlin/nebulosa/fits/FitsHelper.kt index 0f3f45d16..b829eb438 100644 --- a/nebulosa-fits/src/main/kotlin/nebulosa/fits/FitsHelper.kt +++ b/nebulosa-fits/src/main/kotlin/nebulosa/fits/FitsHelper.kt @@ -79,6 +79,9 @@ inline val ReadableHeader.filter inline val ReadableHeader.frame get() = (getStringOrNull("FRAME") ?: getStringOrNull(FitsKeyword.IMAGETYP))?.ifBlank { null }?.trim() +inline val ReadableHeader.camera + get() = getStringOrNull(FitsKeyword.CAMERA)?.ifBlank { null }?.trim() + inline val ReadableHeader.instrument get() = getStringOrNull(FitsKeyword.INSTRUME)?.ifBlank { null }?.trim() diff --git a/nebulosa-io/src/main/kotlin/nebulosa/io/AbstractSeekableSink.kt b/nebulosa-io/src/main/kotlin/nebulosa/io/AbstractSeekableSink.kt new file mode 100644 index 000000000..8b929d13c --- /dev/null +++ b/nebulosa-io/src/main/kotlin/nebulosa/io/AbstractSeekableSink.kt @@ -0,0 +1,66 @@ +package nebulosa.io + +import okio.Buffer +import okio.Timeout +import java.io.EOFException +import kotlin.math.max +import kotlin.math.min + +abstract class AbstractSeekableSink : SeekableSink { + + private val cursor = Buffer.UnsafeCursor() + + abstract val size: Long + abstract val timeout: Timeout + + override var position = 0L + protected set + + override val exhausted + get() = position >= size + + override fun seek(position: Long) { + val newPos = if (position < 0) size + position else position + this.position = max(0L, min(newPos, size)) + } + + protected abstract fun transfer(input: ByteArray, start: Int, length: Int): Int + + protected open fun computeTransferedSize(unsafeCursor: Buffer.UnsafeCursor, byteCount: Long): Long { + return min(min(size - position, unsafeCursor.remaining.toLong()), byteCount) + } + + override fun write(source: Buffer, byteCount: Long) { + if (byteCount == 0L) return + + // if (exhausted) throw EOFException("exhausted") + + var remaining = byteCount + + while (remaining > 0L) { + timeout.throwIfReached() + + source.readUnsafe(cursor).use { + it.seek(0L) + + val length = computeTransferedSize(it, remaining) + + if (length > 0L) { + val currentPosition = position + val transferedSize = transfer(it.data!!, it.start, length.toInt()).toLong() + position = currentPosition + transferedSize + remaining -= transferedSize + source.skip(transferedSize) + } else { + throw EOFException("exhausted") + } + } + } + } + + override fun timeout() = timeout + + override fun flush() = Unit + + override fun close() = cursor.close() +} diff --git a/nebulosa-io/src/main/kotlin/nebulosa/io/AbstractSeekableSource.kt b/nebulosa-io/src/main/kotlin/nebulosa/io/AbstractSeekableSource.kt new file mode 100644 index 000000000..65c980303 --- /dev/null +++ b/nebulosa-io/src/main/kotlin/nebulosa/io/AbstractSeekableSource.kt @@ -0,0 +1,59 @@ +package nebulosa.io + +import okio.Buffer +import okio.Timeout +import kotlin.math.max +import kotlin.math.min + +abstract class AbstractSeekableSource : SeekableSource { + + private val cursor = Buffer.UnsafeCursor() + + abstract val size: Long + abstract val timeout: Timeout + + override var position = 0L + protected set + + override val exhausted + get() = position >= size + + override fun seek(position: Long) { + val newPos = if (position < 0) size + position else position + this.position = max(0L, min(newPos, size)) + } + + protected abstract fun transfer(output: ByteArray, start: Int, length: Int): Int + + protected open fun computeTransferedSize(unsafeCursor: Buffer.UnsafeCursor, byteCount: Long): Long { + return min(min(size - position, 8192L), byteCount) + } + + override fun read(sink: Buffer, byteCount: Long): Long { + if (exhausted) return -1L + + return sink.readAndWriteUnsafe(cursor).use { + timeout.throwIfReached() + + val length = computeTransferedSize(it, byteCount) + val sinkSize = sink.size + + if (length > 0L) { + cursor.expandBuffer(length.toInt()) + + val currentPosition = position + val transferedSize = transfer(it.data!!, it.start, length.toInt()).toLong() + cursor.resizeBuffer(sinkSize + transferedSize) + position = currentPosition + transferedSize + transferedSize + } else { + cursor.resizeBuffer(sinkSize) + -1L + } + } + } + + override fun timeout() = timeout + + override fun close() = cursor.close() +} diff --git a/nebulosa-io/src/main/kotlin/nebulosa/io/ByteArraySink.kt b/nebulosa-io/src/main/kotlin/nebulosa/io/ByteArraySink.kt index 8419c146c..6e4319e07 100644 --- a/nebulosa-io/src/main/kotlin/nebulosa/io/ByteArraySink.kt +++ b/nebulosa-io/src/main/kotlin/nebulosa/io/ByteArraySink.kt @@ -1,68 +1,22 @@ package nebulosa.io -import okio.Buffer import okio.Timeout -import java.io.EOFException -import kotlin.math.max -import kotlin.math.min -internal class ByteArraySink( +@Suppress("ArrayInDataClass") +internal data class ByteArraySink( private val data: ByteArray, private val offset: Int = 0, - private val byteCount: Int = data.size - offset, - private val timeout: Timeout = Timeout.NONE, -) : SeekableSink { - - private val cursor = Buffer.UnsafeCursor() - - override var position = 0L - private set - - override val exhausted - get() = position >= byteCount + override val size: Long = (data.size - offset).toLong(), + override val timeout: Timeout = Timeout.NONE, +) : AbstractSeekableSink() { init { - require(byteCount > 0) { "byteCount <= 0: $byteCount" } - checkOffsetAndCount(data.size, offset, byteCount) + require(size > 0) { "size <= 0: $size" } + checkOffsetAndCount(data.size, offset, size.toInt()) } - @Synchronized - override fun seek(position: Long) { - val newPos = if (position < 0) byteCount + position else position - this.position = max(0L, min(newPos, byteCount.toLong())) - } - - @Synchronized - override fun write(source: Buffer, byteCount: Long) { - if (byteCount == 0L) return - - if (exhausted) throw EOFException("exhausted") - - var remaining = byteCount - - while (remaining > 0) { - timeout.throwIfReached() - - source.readUnsafe(cursor).use { - it.seek(0L) - - val length = min(min(this.byteCount - position, it.remaining.toLong()), remaining) - - if (length > 0) { - it.data!!.copyInto(data, (offset + position).toInt(), it.start, length.toInt()) - remaining -= length - position += length - source.skip(length) - } else { - throw EOFException("exhausted") - } - } - } + override fun transfer(input: ByteArray, start: Int, length: Int): Int { + input.copyInto(data, (offset + position).toInt(), start, start + length) + return length } - - override fun timeout() = timeout - - override fun flush() = Unit - - override fun close() = Unit } diff --git a/nebulosa-io/src/main/kotlin/nebulosa/io/ByteArraySource.kt b/nebulosa-io/src/main/kotlin/nebulosa/io/ByteArraySource.kt index cbcd2c4bd..99d98fac3 100644 --- a/nebulosa-io/src/main/kotlin/nebulosa/io/ByteArraySource.kt +++ b/nebulosa-io/src/main/kotlin/nebulosa/io/ByteArraySource.kt @@ -1,61 +1,23 @@ package nebulosa.io -import okio.Buffer import okio.Timeout -import kotlin.math.max -import kotlin.math.min -internal class ByteArraySource( +@Suppress("ArrayInDataClass") +internal data class ByteArraySource( private val data: ByteArray, private val offset: Int = 0, - private val byteCount: Int = data.size - offset, - private val timeout: Timeout = Timeout.NONE, -) : SeekableSource { - - private val cursor = Buffer.UnsafeCursor() - - override var position = 0L - private set - - override val exhausted - get() = position >= byteCount + override val size: Long = (data.size - offset).toLong(), + override val timeout: Timeout = Timeout.NONE, +) : AbstractSeekableSource() { init { - require(byteCount > 0) { "byteCount <= 0: $byteCount" } - checkOffsetAndCount(data.size, offset, byteCount) - } - - @Synchronized - override fun seek(position: Long) { - val newPos = if (position < 0) byteCount + position else position - this.position = max(0L, min(newPos, byteCount.toLong())) + require(size > 0) { "size <= 0: $size" } + checkOffsetAndCount(data.size, offset, size.toInt()) } - @Synchronized - override fun read(sink: Buffer, byteCount: Long): Long { - if (exhausted) return -1L - - return sink.readAndWriteUnsafe(cursor).use { - timeout.throwIfReached() - - val size = sink.size - val length = min(min(this.byteCount - position, 8192L), byteCount) - - if (length > 0) { - it.expandBuffer(length.toInt()) - val startIndex = offset + position - data.copyInto(it.data!!, it.start, startIndex.toInt(), (startIndex + length).toInt()) - it.resizeBuffer(size + length) - position += length - length - } else { - it.resizeBuffer(size) - -1L - } - } + override fun transfer(output: ByteArray, start: Int, length: Int): Int { + val startIndex = (offset + position).toInt() + data.copyInto(output, start, startIndex, startIndex + length) + return length } - - override fun timeout() = timeout - - override fun close() = Unit } diff --git a/nebulosa-io/src/main/kotlin/nebulosa/io/ByteBufferSink.kt b/nebulosa-io/src/main/kotlin/nebulosa/io/ByteBufferSink.kt index 308382ade..355ce5d0b 100644 --- a/nebulosa-io/src/main/kotlin/nebulosa/io/ByteBufferSink.kt +++ b/nebulosa-io/src/main/kotlin/nebulosa/io/ByteBufferSink.kt @@ -1,69 +1,24 @@ package nebulosa.io -import okio.Buffer import okio.Timeout -import java.io.EOFException import java.nio.ByteBuffer -import kotlin.math.max -import kotlin.math.min -internal class ByteBufferSink( +internal data class ByteBufferSink( private val data: ByteBuffer, private val offset: Int = 0, - private val byteCount: Int = data.capacity() - offset, - private val timeout: Timeout = Timeout.NONE, -) : SeekableSink { + override val size: Long = (data.remaining() - offset).toLong(), + override val timeout: Timeout = Timeout.NONE, +) : AbstractSeekableSink() { - private val cursor = Buffer.UnsafeCursor() - - override var position = 0L - private set - - override val exhausted - get() = position >= byteCount + private val initialPosition = data.position() init { - require(byteCount > 0) { "byteCount <= 0: $byteCount" } - checkOffsetAndCount(data.capacity(), offset, byteCount) + require(size > 0) { "size <= 0: $size" } + checkOffsetAndCount(data.remaining(), offset, size.toInt()) } - @Synchronized - override fun seek(position: Long) { - val newPos = if (position < 0) byteCount + position else position - this.position = max(0L, min(newPos, byteCount.toLong())) + override fun transfer(input: ByteArray, start: Int, length: Int): Int { + data.put(initialPosition + offset + position.toInt(), input, start, length) + return length } - - @Synchronized - override fun write(source: Buffer, byteCount: Long) { - if (byteCount == 0L) return - - if (exhausted) throw EOFException("exhausted") - - var remaining = byteCount - - while (remaining > 0) { - timeout.throwIfReached() - - source.readUnsafe(cursor).use { - it.seek(0L) - - val length = min(min(this.byteCount - position, it.remaining.toLong()), remaining) - - if (length > 0L) { - data.put(offset + position.toInt(), it.data!!, it.start, length.toInt()) - remaining -= length - position += length - source.skip(length) - } else { - throw EOFException("exhausted") - } - } - } - } - - override fun timeout() = timeout - - override fun flush() = Unit - - override fun close() = Unit } diff --git a/nebulosa-io/src/main/kotlin/nebulosa/io/ByteBufferSource.kt b/nebulosa-io/src/main/kotlin/nebulosa/io/ByteBufferSource.kt index 7bea53969..1423f3ca2 100644 --- a/nebulosa-io/src/main/kotlin/nebulosa/io/ByteBufferSource.kt +++ b/nebulosa-io/src/main/kotlin/nebulosa/io/ByteBufferSource.kt @@ -1,61 +1,24 @@ package nebulosa.io -import okio.Buffer import okio.Timeout import java.nio.ByteBuffer -import kotlin.math.max -import kotlin.math.min -internal class ByteBufferSource( +internal data class ByteBufferSource( private val data: ByteBuffer, private val offset: Int = 0, - private val byteCount: Int = data.capacity() - offset, - private val timeout: Timeout = Timeout.NONE, -) : SeekableSource { + override val size: Long = (data.remaining() - offset).toLong(), + override val timeout: Timeout = Timeout.NONE, +) : AbstractSeekableSource() { - private val cursor = Buffer.UnsafeCursor() - - override var position = 0L - private set - - override val exhausted - get() = position >= byteCount + private val initialPosition = data.position() init { - require(byteCount > 0) { "byteCount <= 0: $byteCount" } - checkOffsetAndCount(data.capacity(), offset, byteCount) + require(size > 0) { "size <= 0: $size" } + checkOffsetAndCount(data.remaining(), offset, size.toInt()) } - @Synchronized - override fun seek(position: Long) { - val newPos = if (position < 0) byteCount + position else position - this.position = max(0L, min(newPos, byteCount.toLong())) + override fun transfer(output: ByteArray, start: Int, length: Int): Int { + data.get(initialPosition + offset + position.toInt(), output, start, length) + return length } - - @Synchronized - override fun read(sink: Buffer, byteCount: Long): Long { - if (exhausted) return -1L - - return sink.readAndWriteUnsafe(cursor).use { - timeout.throwIfReached() - - val size = sink.size - val length = min(min(this.byteCount - position, 8192L), byteCount) - - if (length > 0L) { - it.expandBuffer(length.toInt()) - data.get(offset + position.toInt(), it.data!!, it.start, length.toInt()) - it.resizeBuffer(size + length) - position += length - length - } else { - it.resizeBuffer(size) - -1L - } - } - } - - override fun timeout() = timeout - - override fun close() = Unit } diff --git a/nebulosa-io/src/main/kotlin/nebulosa/io/Io.kt b/nebulosa-io/src/main/kotlin/nebulosa/io/Io.kt index 30f4c8b26..fca1d30ce 100644 --- a/nebulosa-io/src/main/kotlin/nebulosa/io/Io.kt +++ b/nebulosa-io/src/main/kotlin/nebulosa/io/Io.kt @@ -92,25 +92,25 @@ fun ByteArray.source( offset: Int = 0, byteCount: Int = size - offset, timeout: Timeout = Timeout.NONE, -): SeekableSource = ByteArraySource(this, offset, byteCount, timeout) +): SeekableSource = ByteArraySource(this, offset, byteCount.toLong(), timeout) fun ByteArray.sink( offset: Int = 0, byteCount: Int = size - offset, timeout: Timeout = Timeout.NONE, -): SeekableSink = ByteArraySink(this, offset, byteCount, timeout) +): SeekableSink = ByteArraySink(this, offset, byteCount.toLong(), timeout) fun ByteBuffer.sink( offset: Int = 0, - byteCount: Int = capacity() - offset, + byteCount: Int = remaining() - offset, timeout: Timeout = Timeout.NONE, -): SeekableSink = ByteBufferSink(this, offset, byteCount, timeout) +): SeekableSink = ByteBufferSink(this, offset, byteCount.toLong(), timeout) fun ByteBuffer.source( offset: Int = 0, - byteCount: Int = capacity() - offset, + byteCount: Int = remaining() - offset, timeout: Timeout = Timeout.NONE, -): SeekableSource = ByteBufferSource(this, offset, byteCount, timeout) +): SeekableSource = ByteBufferSource(this, offset, byteCount.toLong(), timeout) fun Random.source( maxSize: Long = Long.MAX_VALUE, diff --git a/nebulosa-io/src/main/kotlin/nebulosa/io/RandomAccessFileSink.kt b/nebulosa-io/src/main/kotlin/nebulosa/io/RandomAccessFileSink.kt index c5b0e018a..e7667779b 100644 --- a/nebulosa-io/src/main/kotlin/nebulosa/io/RandomAccessFileSink.kt +++ b/nebulosa-io/src/main/kotlin/nebulosa/io/RandomAccessFileSink.kt @@ -6,51 +6,31 @@ import java.io.RandomAccessFile import kotlin.math.max import kotlin.math.min -internal class RandomAccessFileSink( +internal data class RandomAccessFileSink( private val file: RandomAccessFile, - private val timeout: Timeout = Timeout.NONE, -) : SeekableSink { + override val timeout: Timeout = Timeout.NONE, +) : AbstractSeekableSink() { - private val cursor = Buffer.UnsafeCursor() + override val size + get() = file.length() - override val position + override var position get() = file.filePointer + set(value) { + file.seek(max(0L, min(value, size))) + } - override val exhausted - get() = position >= file.length() + override fun computeTransferedSize(unsafeCursor: Buffer.UnsafeCursor, byteCount: Long): Long { + return min(unsafeCursor.remaining.toLong(), byteCount) + } - @Synchronized - override fun seek(position: Long) { - val size = file.length() - if (size <= 0) return - val newPos = if (position < 0) size + position else position - file.seek(max(0L, min(newPos, size))) + override fun transfer(input: ByteArray, start: Int, length: Int): Int { + file.write(input, start, length) + return length } - @Synchronized override fun write(source: Buffer, byteCount: Long) { - if (!file.channel.isOpen) throw IllegalStateException("closed") - - if (byteCount == 0L) return - - var remaining = byteCount - - while (remaining > 0) { - timeout.throwIfReached() - - source.readUnsafe(cursor).use { - it.seek(0L) - val length = min(it.remaining.toLong(), remaining) - file.write(it.data!!, it.start, length.toInt()) - remaining -= length - source.skip(length) - } - } + check(file.channel.isOpen) { "closed" } + super.write(source, byteCount) } - - override fun timeout() = timeout - - override fun flush() = Unit - - override fun close() = Unit } diff --git a/nebulosa-io/src/main/kotlin/nebulosa/io/RandomAccessFileSource.kt b/nebulosa-io/src/main/kotlin/nebulosa/io/RandomAccessFileSource.kt index b48f13913..9e4bf5c1c 100644 --- a/nebulosa-io/src/main/kotlin/nebulosa/io/RandomAccessFileSource.kt +++ b/nebulosa-io/src/main/kotlin/nebulosa/io/RandomAccessFileSource.kt @@ -2,56 +2,38 @@ package nebulosa.io import okio.Buffer import okio.Timeout -import java.io.Closeable import java.io.RandomAccessFile -import kotlin.math.max import kotlin.math.min -internal class RandomAccessFileSource( +internal data class RandomAccessFileSource( private val file: RandomAccessFile, - private val timeout: Timeout = Timeout.NONE, -) : SeekableSource, Closeable by file { + override val timeout: Timeout = Timeout.NONE, +) : AbstractSeekableSource() { - private val cursor = Buffer.UnsafeCursor() + override val size + get() = file.length() - override val position + override var position get() = file.filePointer + set(value) { + file.seek(value) + } - override val exhausted - get() = position >= file.length() + override fun computeTransferedSize(unsafeCursor: Buffer.UnsafeCursor, byteCount: Long): Long { + return min(8192L, byteCount) + } - @Synchronized - override fun seek(position: Long) { - val size = file.length() - if (size <= 0) return - val newPos = if (position < 0) size + position else position - file.seek(max(0L, min(newPos, size))) + override fun transfer(output: ByteArray, start: Int, length: Int): Int { + return file.read(output, start, length) } - @Synchronized override fun read(sink: Buffer, byteCount: Long): Long { - if (!file.channel.isOpen) throw IllegalStateException("closed") - - if (exhausted) return -1L - - return sink.readAndWriteUnsafe(cursor).use { - timeout.throwIfReached() - - val size = sink.size - val length = min(8192L, byteCount) - - it.expandBuffer(length.toInt()) - val readCount = file.read(it.data!!, it.start, length.toInt()) - - if (readCount == -1) { - it.resizeBuffer(size) - -1L - } else { - cursor.resizeBuffer(size + readCount) - return readCount.toLong() - } - } + check(file.channel.isOpen) { "closed" } + return super.read(sink, byteCount) } - override fun timeout() = timeout + override fun close() { + super.close() + file.close() + } } diff --git a/nebulosa-io/src/main/kotlin/nebulosa/io/RandomSource.kt b/nebulosa-io/src/main/kotlin/nebulosa/io/RandomSource.kt index 8f2f97d2b..24fbe4a70 100644 --- a/nebulosa-io/src/main/kotlin/nebulosa/io/RandomSource.kt +++ b/nebulosa-io/src/main/kotlin/nebulosa/io/RandomSource.kt @@ -1,74 +1,34 @@ package nebulosa.io -import okio.Buffer import okio.Timeout import java.util.* -import kotlin.math.max import kotlin.math.min -internal class RandomSource( +internal data class RandomSource( private val random: Random, - private val maxSize: Long = Long.MAX_VALUE, - private val timeout: Timeout = Timeout.NONE, -) : SeekableSource { - - private val cursor = Buffer.UnsafeCursor() - - override var position = 0L - private set - - override val exhausted - get() = maxSize in 0L..position + override val size: Long = Long.MAX_VALUE, + override val timeout: Timeout = Timeout.NONE, +) : AbstractSeekableSource() { init { - require(maxSize > 0) { "maxSize <= 0: $maxSize" } + require(size > 0) { "size <= 0: $size" } } - @Synchronized - override fun seek(position: Long) { - val newPos = if (position < 0) maxSize + position else position - this.position = max(0L, min(newPos, maxSize - 1L)) + override fun transfer(output: ByteArray, start: Int, length: Int): Int { + random.nextBytes(output, start, length) + return length } - @Synchronized - override fun read(sink: Buffer, byteCount: Long): Long { - return sink.readAndWriteUnsafe(cursor).use { - timeout.throwIfReached() - - val size = sink.size - val length = min(min(maxSize - position, 8192L), byteCount) - - if (length > 0) { - cursor.expandBuffer(length.toInt()) - random.nextBytes(it.data!!, it.start, length.toInt()) - cursor.resizeBuffer(size + length) - position += length - length - } else { - cursor.resizeBuffer(size) - -1L - } - } - } - - override fun timeout() = timeout - - override fun close() = Unit - companion object { - private fun Random.nextBytes( - bytes: ByteArray, - offset: Int = 0, - byteCount: Int = bytes.size - offset, - ) { + @JvmStatic + private fun Random.nextBytes(bytes: ByteArray, offset: Int = 0, byteCount: Int = bytes.size - offset) { var i = 0 while (i < byteCount) { var rnd = nextInt() - var n = min(byteCount - i, 4) - while (n-- > 0) { + repeat(min(byteCount - i, 4)) { bytes[offset + i++] = rnd.toByte() rnd = rnd shr 8 } diff --git a/nebulosa-io/src/test/kotlin/AbstractSeekableSinkAndSourceTest.kt b/nebulosa-io/src/test/kotlin/AbstractSeekableSinkAndSourceTest.kt new file mode 100644 index 000000000..d7c219a92 --- /dev/null +++ b/nebulosa-io/src/test/kotlin/AbstractSeekableSinkAndSourceTest.kt @@ -0,0 +1,293 @@ +import io.kotest.core.spec.style.StringSpec +import io.kotest.matchers.booleans.shouldBeFalse +import io.kotest.matchers.booleans.shouldBeTrue +import io.kotest.matchers.ints.shouldBeExactly +import io.kotest.matchers.longs.shouldBeExactly +import io.kotest.matchers.shouldBe +import nebulosa.io.SeekableSink +import nebulosa.io.SeekableSource +import okio.Buffer + +abstract class AbstractSeekableSinkAndSourceTest : StringSpec() { + + abstract val sink: SeekableSink + abstract val source: SeekableSource + + init { + afterEach { + sink.seek(0) + source.seek(0) + } + + "byte" { + val buffer = Buffer() + buffer.writeByte(-12) + sink.seek(0) + sink.write(buffer, 1) + sink.exhausted.shouldBeFalse() + sink.position shouldBeExactly 1 + + source.seek(0) + source.read(buffer, 1) + source.exhausted.shouldBeFalse() + source.position shouldBeExactly 1 + buffer.readByte().toInt() shouldBeExactly -12 + } + "short-le" { + val buffer = Buffer() + buffer.writeShortLe(-23975) + sink.seek(0) + sink.write(buffer, 2) + sink.exhausted.shouldBeFalse() + sink.position shouldBeExactly 2 + + source.seek(0) + source.read(buffer, 2) + source.exhausted.shouldBeFalse() + source.position shouldBeExactly 2 + buffer.readShortLe().toInt() shouldBeExactly -23975 + } + "short" { + val buffer = Buffer() + buffer.writeShort(-23975) + sink.seek(0) + sink.write(buffer, 2) + sink.exhausted.shouldBeFalse() + sink.position shouldBeExactly 2 + + source.seek(0) + source.read(buffer, 2) + source.exhausted.shouldBeFalse() + source.position shouldBeExactly 2 + buffer.readShort().toInt() shouldBeExactly -23975 + } + "int-le" { + val buffer = Buffer() + buffer.writeIntLe(-145983) + sink.seek(0) + sink.write(buffer, 4) + sink.exhausted.shouldBeFalse() + sink.position shouldBeExactly 4 + + source.seek(0) + source.read(buffer, 4) + source.exhausted.shouldBeFalse() + source.position shouldBeExactly 4 + buffer.readIntLe() shouldBeExactly -145983 + } + "int" { + val buffer = Buffer() + buffer.writeInt(-145983) + sink.seek(0) + sink.write(buffer, 4) + sink.exhausted.shouldBeFalse() + sink.position shouldBeExactly 4 + + source.seek(0) + source.read(buffer, 4) + source.exhausted.shouldBeFalse() + source.position shouldBeExactly 4 + buffer.readInt() shouldBeExactly -145983 + } + "long-le" { + val buffer = Buffer() + buffer.writeLongLe(-3534545345345) + sink.seek(0) + sink.write(buffer, 8) + sink.exhausted.shouldBeTrue() + sink.position shouldBeExactly 8 + + source.seek(0) + source.read(buffer, 8) + source.exhausted.shouldBeTrue() + source.position shouldBeExactly 8 + buffer.readLongLe() shouldBeExactly -3534545345345 + } + "long" { + val buffer = Buffer() + buffer.writeLong(-3534545345345) + sink.seek(0) + sink.write(buffer, 8) + sink.exhausted.shouldBeTrue() + sink.position shouldBeExactly 8 + + source.seek(0) + source.read(buffer, 8) + source.exhausted.shouldBeTrue() + source.position shouldBeExactly 8 + buffer.readLong() shouldBeExactly -3534545345345 + } + "ascii" { + val buffer = Buffer() + buffer.writeString("Gê", Charsets.ISO_8859_1) + sink.seek(0) + sink.write(buffer, 2) + sink.exhausted.shouldBeFalse() + sink.position shouldBeExactly 2 + + source.seek(0) + source.read(buffer, 2) + source.exhausted.shouldBeFalse() + source.position shouldBeExactly 2 + buffer.readString(Charsets.ISO_8859_1) shouldBe "Gê" + } + "utf-8" { + val buffer = Buffer() + buffer.writeUtf8("\uD83D\uDE0A") + sink.seek(0) + sink.write(buffer, 4) + sink.exhausted.shouldBeFalse() + sink.position shouldBeExactly 4 + + source.seek(0) + source.read(buffer, 4) + source.exhausted.shouldBeFalse() + source.position shouldBeExactly 4 + buffer.readUtf8() shouldBe "\uD83D\uDE0A" + } + "seek and exhausted" { + val buffer = Buffer() + buffer.writeByte(99) + sink.seek(7) + sink.exhausted.shouldBeFalse() + sink.position shouldBeExactly 7 + sink.write(buffer, 1) + sink.exhausted.shouldBeTrue() + sink.position shouldBeExactly 8 + + source.seek(7) + source.exhausted.shouldBeFalse() + source.position shouldBeExactly 7 + source.read(buffer, 1) + source.exhausted.shouldBeTrue() + source.position shouldBeExactly 8 + buffer.readByte() shouldBe 99 + } + "seek and not exhausted" { + val buffer = Buffer() + buffer.writeByte(99) + sink.seek(6) + sink.exhausted.shouldBeFalse() + sink.position shouldBeExactly 6 + sink.write(buffer, 1) + sink.exhausted.shouldBeFalse() + sink.position shouldBeExactly 7 + + source.seek(6) + source.exhausted.shouldBeFalse() + source.position shouldBeExactly 6 + source.read(buffer, 1) + source.exhausted.shouldBeFalse() + source.position shouldBeExactly 7 + buffer.readByte() shouldBe 99 + } + "negative seek and exhausted" { + val buffer = Buffer() + buffer.writeByte(99) + sink.seek(-1) + sink.exhausted.shouldBeFalse() + sink.position shouldBeExactly 7 + sink.write(buffer, 1) + sink.exhausted.shouldBeTrue() + sink.position shouldBeExactly 8 + + source.seek(-1) + source.exhausted.shouldBeFalse() + source.position shouldBeExactly 7 + source.read(buffer, 1) + source.exhausted.shouldBeTrue() + source.position shouldBeExactly 8 + buffer.readByte() shouldBe 99 + } + "negative seek and not exhausted" { + val buffer = Buffer() + buffer.writeByte(99) + sink.seek(-2) + sink.exhausted.shouldBeFalse() + sink.position shouldBeExactly 6 + sink.write(buffer, 1) + sink.exhausted.shouldBeFalse() + sink.position shouldBeExactly 7 + + source.seek(-2) + source.exhausted.shouldBeFalse() + source.position shouldBeExactly 6 + source.read(buffer, 1) + source.exhausted.shouldBeFalse() + source.position shouldBeExactly 7 + buffer.readByte() shouldBe 99 + } + "skip and exhausted" { + val buffer = Buffer() + buffer.writeByte(99) + sink.skip(7) + sink.exhausted.shouldBeFalse() + sink.position shouldBeExactly 7 + sink.write(buffer, 1) + sink.exhausted.shouldBeTrue() + sink.position shouldBeExactly 8 + + source.skip(7) + source.exhausted.shouldBeFalse() + source.position shouldBeExactly 7 + source.read(buffer, 1) + source.exhausted.shouldBeTrue() + source.position shouldBeExactly 8 + buffer.readByte() shouldBe 99 + } + "skip and not exhausted" { + val buffer = Buffer() + buffer.writeByte(99) + sink.skip(6) + sink.exhausted.shouldBeFalse() + sink.position shouldBeExactly 6 + sink.write(buffer, 1) + sink.exhausted.shouldBeFalse() + sink.position shouldBeExactly 7 + + source.skip(6) + source.exhausted.shouldBeFalse() + source.position shouldBeExactly 6 + source.read(buffer, 1) + source.exhausted.shouldBeFalse() + source.position shouldBeExactly 7 + buffer.readByte() shouldBe 99 + } + "negative skip and exhausted" { + val buffer = Buffer() + buffer.writeByte(99) + sink.skip(-1) + sink.exhausted.shouldBeFalse() + sink.position shouldBeExactly 7 + sink.write(buffer, 1) + sink.exhausted.shouldBeTrue() + sink.position shouldBeExactly 8 + + source.skip(-1) + source.exhausted.shouldBeFalse() + source.position shouldBeExactly 7 + source.read(buffer, 1) + source.exhausted.shouldBeTrue() + source.position shouldBeExactly 8 + buffer.readByte() shouldBe 99 + } + "negative skip and not exhausted" { + val buffer = Buffer() + buffer.writeByte(99) + sink.skip(-2) + sink.exhausted.shouldBeFalse() + sink.position shouldBeExactly 6 + sink.write(buffer, 1) + sink.exhausted.shouldBeFalse() + sink.position shouldBeExactly 7 + + source.skip(-2) + source.exhausted.shouldBeFalse() + source.position shouldBeExactly 6 + source.read(buffer, 1) + source.exhausted.shouldBeFalse() + source.position shouldBeExactly 7 + buffer.readByte() shouldBe 99 + } + } +} diff --git a/nebulosa-io/src/test/kotlin/BufferedByteArrayTest.kt b/nebulosa-io/src/test/kotlin/BufferedByteArrayTest.kt deleted file mode 100644 index ebad8478a..000000000 --- a/nebulosa-io/src/test/kotlin/BufferedByteArrayTest.kt +++ /dev/null @@ -1,124 +0,0 @@ -import io.kotest.assertions.throwables.shouldNotThrow -import io.kotest.assertions.throwables.shouldThrow -import io.kotest.matchers.booleans.shouldBeFalse -import io.kotest.matchers.booleans.shouldBeTrue -import io.kotest.matchers.doubles.shouldBeExactly -import io.kotest.matchers.floats.shouldBeExactly -import io.kotest.matchers.ints.shouldBeExactly -import io.kotest.matchers.longs.shouldBeExactly -import io.kotest.matchers.shouldBe -import nebulosa.io.* -import okio.buffer -import okio.utf8Size -import java.io.EOFException - -class BufferedByteArrayTest : BufferedStringSpec() { - - init { - "read" { - val data = ByteArray(79) - data.sink().use { it.initialize() } - - val source = data.source() - - with(source.buffer()) { - readUnsignedByte() shouldBeExactly 0xAB - readShort().toInt() and 0xFFFF shouldBeExactly 0xABCD - readShortLe().toInt() and 0xFFFF shouldBeExactly 0x2143 - readInt() shouldBeExactly -0x543210FF - readIntLe() shouldBeExactly -0x789ABCDF - readLong() shouldBeExactly -0x543210FE789ABCDFL - readLongLe() shouldBeExactly -0x350145414F4EA400L - readFloat() shouldBeExactly 3.14F - readFloatLe() shouldBeExactly 3.14F - readDouble() shouldBeExactly 3.14 - readDoubleLe() shouldBeExactly 3.14 - readUtf8("təˈranəˌsôr".utf8Size()) shouldBe "təˈranəˌsôr" - readUtf8CodePoint() shouldBeExactly "µ".codePointAt(0) - readString(4, Charsets.UTF_32BE) shouldBe "c" - readByteArray(3) shouldBe byteArrayOf(1, 2, 3) - exhausted().shouldBeFalse() - readUnsignedByte() shouldBeExactly 0xF9 - exhausted().shouldBeTrue() - } - } - "seek and write" { - val data = ByteArray(79) - val sink = data.sink() - sink.seek(-1L) - - with(sink.buffer()) { - writeByte(0x44) - flush() - } - } - "skip and read" { - val data = ByteArray(79) - data.sink().use { it.initialize() } - - val source = data.source() - source.skip(78) - - with(source.buffer()) { - exhausted().shouldBeFalse() - readSignedByte() shouldBeExactly 0xF9.toByte().toInt() - exhausted().shouldBeTrue() - } - } - "seek and read" { - val data = ByteArray(79) - data.sink().use { it.initialize() } - - val source = data.source() - - with(source.buffer()) { - source.seek(-1L) - exhausted().shouldBeFalse() - readSignedByte() shouldBeExactly 0xF9.toByte().toInt() - exhausted().shouldBeTrue() - - source.seek(37) - exhausted().shouldBeFalse() - readDouble() shouldBeExactly 3.14 - exhausted().shouldBeFalse() - } - } - "write with offset and byte count" { - val data = ByteArray(79) - data.sink().use { it.initialize() } - - val sink = data.sink(36, 8) - - with(sink.buffer()) { - writeDouble(3.14) - shouldNotThrow { flush() } - - writeByte(0x10) - shouldThrow { flush() } - } - } - "read with offset and byte count" { - val data = ByteArray(79) - data.sink().use { it.initialize() } - - val source = data.source(37, 8) - - with(source.buffer()) { - exhausted().shouldBeFalse() - readDouble() shouldBeExactly 3.14 - exhausted().shouldBeTrue() - } - } - "close emits buffered bytes" { - val data = ByteArray(79) { 1 } - - val sink = data.sink() - sink.buffer().use { it.writeByte(0x99) } - - data.source().buffer().use { - it.readUnsignedByte() shouldBeExactly 0x99 - it.readUnsignedByte() shouldBeExactly 1 - } - } - } -} diff --git a/nebulosa-io/src/test/kotlin/BufferedByteBufferTest.kt b/nebulosa-io/src/test/kotlin/BufferedByteBufferTest.kt deleted file mode 100644 index 4846a8428..000000000 --- a/nebulosa-io/src/test/kotlin/BufferedByteBufferTest.kt +++ /dev/null @@ -1,128 +0,0 @@ -import io.kotest.assertions.throwables.shouldNotThrow -import io.kotest.assertions.throwables.shouldThrow -import io.kotest.matchers.booleans.shouldBeFalse -import io.kotest.matchers.booleans.shouldBeTrue -import io.kotest.matchers.doubles.shouldBeExactly -import io.kotest.matchers.floats.shouldBeExactly -import io.kotest.matchers.ints.shouldBeExactly -import io.kotest.matchers.longs.shouldBeExactly -import io.kotest.matchers.shouldBe -import nebulosa.io.* -import okio.buffer -import okio.utf8Size -import java.io.EOFException -import java.nio.ByteBuffer - -class BufferedByteBufferTest : BufferedStringSpec() { - - init { - "read" { - val data = ByteBuffer.allocate(79) - data.sink().use { it.initialize() } - - val source = data.source() - - with(source.buffer()) { - readUnsignedByte() shouldBeExactly 0xAB - readShort().toInt() and 0xFFFF shouldBeExactly 0XABCD - readShortLe().toInt() and 0xFFFF shouldBeExactly 0X2143 - readInt() shouldBeExactly -0x543210FF - readIntLe() shouldBeExactly -0x789ABCDF - readLong() shouldBeExactly -0x543210FE789ABCDFL - readLongLe() shouldBeExactly -0x350145414F4EA400L - readFloat() shouldBeExactly 3.14F - readFloatLe() shouldBeExactly 3.14F - readDouble() shouldBeExactly 3.14 - readDoubleLe() shouldBeExactly 3.14 - readUtf8("təˈranəˌsôr".utf8Size()) shouldBe "təˈranəˌsôr" - readUtf8CodePoint() shouldBeExactly "µ".codePointAt(0) - readString(4, Charsets.UTF_32BE) shouldBe "c" - readByteArray(3) shouldBe byteArrayOf(1, 2, 3) - exhausted().shouldBeFalse() - readUnsignedByte() shouldBeExactly 0xF9 - exhausted().shouldBeTrue() - } - } - "seek and write" { - val data = ByteBuffer.allocate(79) - - val sink = data.sink() - sink.initialize() - sink.seek(-1L) - - with(sink.buffer()) { - writeByte(0x44) - flush() - } - } - "skip and read" { - val data = ByteBuffer.allocate(79) - data.sink().use { it.initialize() } - - val source = data.source() - source.skip(78) - - with(source.buffer()) { - exhausted().shouldBeFalse() - readSignedByte() shouldBeExactly 0xF9.toByte().toInt() - exhausted().shouldBeTrue() - } - } - "seek and read" { - val data = ByteBuffer.allocate(79) - data.sink().use { it.initialize() } - - val source = data.source() - - with(source.buffer()) { - source.seek(-1L) - exhausted().shouldBeFalse() - readSignedByte() shouldBeExactly 0xF9.toByte().toInt() - exhausted().shouldBeTrue() - - source.seek(37) - exhausted().shouldBeFalse() - readDouble() shouldBeExactly 3.14 - exhausted().shouldBeFalse() - } - } - "write with offset and byte count" { - val data = ByteBuffer.allocate(79) - data.sink().use { it.initialize() } - - val sink = data.sink(2, 8) - - with(sink.buffer()) { - writeDouble(3.14) - shouldNotThrow { flush() } - - writeByte(0x10) - shouldThrow { flush() } - } - } - "read with offset and byte count" { - val data = ByteBuffer.allocate(79) - data.sink().use { it.initialize() } - - val source = data.source(37, 8) - - with(source.buffer()) { - exhausted().shouldBeFalse() - readDouble() shouldBeExactly 3.14 - exhausted().shouldBeTrue() - } - } - "close emits buffered bytes" { - val data = ByteBuffer.allocate(79) - repeat(data.capacity()) { data.put(1) } - - val sink = data.sink() - sink.buffer().use { it.writeByte(0x99) } - - data.source().buffer().use { - it.readUnsignedByte() shouldBeExactly 0x99 - it.readUnsignedByte() shouldBeExactly 1 - } - } - } -} diff --git a/nebulosa-io/src/test/kotlin/BufferedRandomAccessFileTest.kt b/nebulosa-io/src/test/kotlin/BufferedRandomAccessFileTest.kt deleted file mode 100644 index f76506540..000000000 --- a/nebulosa-io/src/test/kotlin/BufferedRandomAccessFileTest.kt +++ /dev/null @@ -1,105 +0,0 @@ -import io.kotest.engine.spec.tempfile -import io.kotest.matchers.booleans.shouldBeFalse -import io.kotest.matchers.booleans.shouldBeTrue -import io.kotest.matchers.doubles.shouldBeExactly -import io.kotest.matchers.floats.shouldBeExactly -import io.kotest.matchers.ints.shouldBeExactly -import io.kotest.matchers.longs.shouldBeExactly -import io.kotest.matchers.shouldBe -import nebulosa.io.* -import okio.buffer -import okio.utf8Size -import java.io.File - -class BufferedRandomAccessFileTest : BufferedStringSpec() { - - init { - "read" { - val file = makeFile() - val source = file.seekableSource() - - with(source.buffer()) { - readUnsignedByte() shouldBeExactly 0xab - readShort().toInt() and 0xffff shouldBeExactly 0xabcd - readShortLe().toInt() and 0xffff shouldBeExactly 0x2143 - readInt() shouldBeExactly -0x543210ff - readIntLe() shouldBeExactly -0x789abcdf - readLong() shouldBeExactly -0x543210fe789abcdfL - readLongLe() shouldBeExactly -0x350145414f4ea400L - readFloat() shouldBeExactly 3.14f - readFloatLe() shouldBeExactly 3.14f - readDouble() shouldBeExactly 3.14 - readDoubleLe() shouldBeExactly 3.14 - readUtf8("təˈranəˌsôr".utf8Size()) shouldBe "təˈranəˌsôr" - readUtf8CodePoint() shouldBeExactly "µ".codePointAt(0) - readString(4, Charsets.UTF_32BE) shouldBe "c" - readByteArray(3) shouldBe byteArrayOf(1, 2, 3) - exhausted().shouldBeFalse() - readUnsignedByte() shouldBeExactly 0xf9 - exhausted().shouldBeTrue() - } - } - "seek and write" { - val file = makeFile() - val sink = file.seekableSink() - sink.seek(-1L) - - with(sink.buffer()) { - writeByte(0x44) - flush() - } - - val source = file.seekableSource() - source.seek(-1L) - - with(source.buffer()) { - readByte().toInt() shouldBeExactly 0x44 - } - } - "skip and read" { - val file = makeFile() - val source = file.seekableSource() - source.skip(78) - - with(source.buffer()) { - exhausted().shouldBeFalse() - readSignedByte() shouldBeExactly 0xF9.toByte().toInt() - exhausted().shouldBeTrue() - } - } - "seek and read" { - val file = makeFile() - val source = file.seekableSource() - - with(source.buffer()) { - source.seek(-1L) - exhausted().shouldBeFalse() - readSignedByte() shouldBeExactly 0xF9.toByte().toInt() - exhausted().shouldBeTrue() - - source.seek(37) - exhausted().shouldBeFalse() - readDouble() shouldBeExactly 3.14 - exhausted().shouldBeFalse() - } - } - "close emits buffered bytes" { - val file = makeFile() - file.writeBytes(ByteArray(79) { 1 }) - - val sink = file.seekableSink() - sink.buffer().use { it.writeByte(0x99) } - - file.seekableSource().buffer().use { - it.readUnsignedByte() shouldBeExactly 0x99 - it.readUnsignedByte() shouldBeExactly 1 - } - } - } - - private fun makeFile(): File { - val file = tempfile() - file.seekableSink().use { it.initialize() } - return file - } -} diff --git a/nebulosa-io/src/test/kotlin/BufferedStringSpec.kt b/nebulosa-io/src/test/kotlin/BufferedStringSpec.kt deleted file mode 100644 index 1f051417b..000000000 --- a/nebulosa-io/src/test/kotlin/BufferedStringSpec.kt +++ /dev/null @@ -1,32 +0,0 @@ -import io.kotest.core.spec.style.StringSpec -import nebulosa.io.writeDouble -import nebulosa.io.writeDoubleLe -import nebulosa.io.writeFloat -import nebulosa.io.writeFloatLe -import okio.Sink -import okio.buffer - -abstract class BufferedStringSpec : StringSpec() { - - protected fun Sink.initialize() { - buffer().use { - it.writeByte(0xAB) - it.writeShort(0xABCD) - it.writeShortLe(0x2143) - it.writeInt(-0x543210FF) - it.writeIntLe(-0x789ABCDF) - it.writeLong(-0x543210FE789ABCDFL) - it.writeLongLe(-0x350145414F4EA400L) - it.writeFloat(3.14F) - it.writeFloatLe(3.14F) - it.writeDouble(3.14) - it.writeDoubleLe(3.14) - it.writeUtf8("təˈranəˌsôr") - it.writeUtf8CodePoint("µ".codePointAt(0)) - it.writeString("c", charset = Charsets.UTF_32BE) - it.write(byteArrayOf(1, 2, 3)) - it.writeByte(0xF9) - it.flush() - } - } -} diff --git a/nebulosa-io/src/test/kotlin/ByteArrayTest.kt b/nebulosa-io/src/test/kotlin/ByteArrayTest.kt new file mode 100644 index 000000000..70078b523 --- /dev/null +++ b/nebulosa-io/src/test/kotlin/ByteArrayTest.kt @@ -0,0 +1,10 @@ +import nebulosa.io.sink +import nebulosa.io.source + +class ByteArrayTest : AbstractSeekableSinkAndSourceTest() { + + private val data = ByteArray(8) + + override val sink = data.sink() + override val source = data.source() +} diff --git a/nebulosa-io/src/test/kotlin/ByteArrayWithOffsetAndLengthTest.kt b/nebulosa-io/src/test/kotlin/ByteArrayWithOffsetAndLengthTest.kt new file mode 100644 index 000000000..1fc9f0e40 --- /dev/null +++ b/nebulosa-io/src/test/kotlin/ByteArrayWithOffsetAndLengthTest.kt @@ -0,0 +1,22 @@ +import io.kotest.matchers.ints.shouldBeExactly +import nebulosa.io.sink +import nebulosa.io.source + +class ByteArrayWithOffsetAndLengthTest : AbstractSeekableSinkAndSourceTest() { + + private val data = ByteArray(16) { it.toByte() } + + override val sink = data.sink(5, 8) + override val source = data.source(5, 8) + + init { + afterEach { + for (i in 0..4) { + data[i].toInt() shouldBeExactly i + } + for (i in 13..15) { + data[i].toInt() shouldBeExactly i + } + } + } +} diff --git a/nebulosa-io/src/test/kotlin/ByteArrayWithOffsetTest.kt b/nebulosa-io/src/test/kotlin/ByteArrayWithOffsetTest.kt new file mode 100644 index 000000000..62c2a0994 --- /dev/null +++ b/nebulosa-io/src/test/kotlin/ByteArrayWithOffsetTest.kt @@ -0,0 +1,19 @@ +import io.kotest.matchers.ints.shouldBeExactly +import nebulosa.io.sink +import nebulosa.io.source + +class ByteArrayWithOffsetTest : AbstractSeekableSinkAndSourceTest() { + + private val data = ByteArray(16) { it.toByte() } + + override val sink = data.sink(8) + override val source = data.source(8) + + init { + afterEach { + for (i in 0..7) { + data[i].toInt() shouldBeExactly i + } + } + } +} diff --git a/nebulosa-io/src/test/kotlin/ByteBufferTest.kt b/nebulosa-io/src/test/kotlin/ByteBufferTest.kt new file mode 100644 index 000000000..7c182416c --- /dev/null +++ b/nebulosa-io/src/test/kotlin/ByteBufferTest.kt @@ -0,0 +1,11 @@ +import nebulosa.io.sink +import nebulosa.io.source +import java.nio.ByteBuffer + +class ByteBufferTest : AbstractSeekableSinkAndSourceTest() { + + private val data = ByteBuffer.allocate(8) + + override val sink = data.sink() + override val source = data.source() +} diff --git a/nebulosa-io/src/test/kotlin/ByteBufferWithOffsetAndLengthTest.kt b/nebulosa-io/src/test/kotlin/ByteBufferWithOffsetAndLengthTest.kt new file mode 100644 index 000000000..02bc3f0c9 --- /dev/null +++ b/nebulosa-io/src/test/kotlin/ByteBufferWithOffsetAndLengthTest.kt @@ -0,0 +1,24 @@ +import io.kotest.matchers.ints.shouldBeExactly +import nebulosa.io.sink +import nebulosa.io.source +import java.nio.ByteBuffer + +class ByteBufferWithOffsetAndLengthTest : AbstractSeekableSinkAndSourceTest() { + + private val bytes = ByteArray(16) { it.toByte() } + private val data = ByteBuffer.wrap(bytes) + + override val sink = data.sink(5, 8) + override val source = data.source(5, 8) + + init { + afterEach { + for (i in 0..4) { + bytes[i].toInt() shouldBeExactly i + } + for (i in 13..15) { + bytes[i].toInt() shouldBeExactly i + } + } + } +} diff --git a/nebulosa-io/src/test/kotlin/ByteBufferWithOffsetTest.kt b/nebulosa-io/src/test/kotlin/ByteBufferWithOffsetTest.kt new file mode 100644 index 000000000..f501d8691 --- /dev/null +++ b/nebulosa-io/src/test/kotlin/ByteBufferWithOffsetTest.kt @@ -0,0 +1,21 @@ +import io.kotest.matchers.ints.shouldBeExactly +import nebulosa.io.sink +import nebulosa.io.source +import java.nio.ByteBuffer + +class ByteBufferWithOffsetTest : AbstractSeekableSinkAndSourceTest() { + + private val bytes = ByteArray(16) { it.toByte() } + private val data = ByteBuffer.wrap(bytes) + + override val sink = data.sink(8) + override val source = data.source(8) + + init { + afterEach { + for (i in 0..7) { + bytes[i].toInt() shouldBeExactly i + } + } + } +} diff --git a/nebulosa-io/src/test/kotlin/ByteBufferWrappedWithOffsetAndLengthTest.kt b/nebulosa-io/src/test/kotlin/ByteBufferWrappedWithOffsetAndLengthTest.kt new file mode 100644 index 000000000..a273d0b20 --- /dev/null +++ b/nebulosa-io/src/test/kotlin/ByteBufferWrappedWithOffsetAndLengthTest.kt @@ -0,0 +1,24 @@ +import io.kotest.matchers.ints.shouldBeExactly +import nebulosa.io.sink +import nebulosa.io.source +import java.nio.ByteBuffer + +class ByteBufferWrappedWithOffsetAndLengthTest : AbstractSeekableSinkAndSourceTest() { + + private val bytes = ByteArray(16) { it.toByte() } + private val data = ByteBuffer.wrap(bytes, 5, 8) + + override val sink = data.sink() + override val source = data.source() + + init { + afterEach { + for (i in 0..4) { + bytes[i].toInt() shouldBeExactly i + } + for (i in 13..15) { + bytes[i].toInt() shouldBeExactly i + } + } + } +} diff --git a/nebulosa-io/src/test/kotlin/RandomAccessFileTest.kt b/nebulosa-io/src/test/kotlin/RandomAccessFileTest.kt new file mode 100644 index 000000000..3e759064b --- /dev/null +++ b/nebulosa-io/src/test/kotlin/RandomAccessFileTest.kt @@ -0,0 +1,15 @@ +import io.kotest.engine.spec.tempfile +import nebulosa.io.seekableSink +import nebulosa.io.seekableSource + +class RandomAccessFileTest : AbstractSeekableSinkAndSourceTest() { + + private val file = tempfile() + + override val sink = file.seekableSink() + override val source = file.seekableSource() + + init { + file.writeBytes(ByteArray(8)) + } +} diff --git a/nebulosa-io/src/test/kotlin/BufferedRandomSourceTest.kt b/nebulosa-io/src/test/kotlin/RandomSourceTest.kt similarity index 95% rename from nebulosa-io/src/test/kotlin/BufferedRandomSourceTest.kt rename to nebulosa-io/src/test/kotlin/RandomSourceTest.kt index b20e744cc..742d24245 100644 --- a/nebulosa-io/src/test/kotlin/BufferedRandomSourceTest.kt +++ b/nebulosa-io/src/test/kotlin/RandomSourceTest.kt @@ -4,7 +4,7 @@ import nebulosa.io.source import okio.buffer import java.util.* -class BufferedRandomSourceTest : StringSpec() { +class RandomSourceTest : StringSpec() { init { "read full segment" { diff --git a/nebulosa-skycatalog/src/main/kotlin/nebulosa/skycatalog/SkyObjectType.kt b/nebulosa-skycatalog/src/main/kotlin/nebulosa/skycatalog/SkyObjectType.kt index 9c7afe99e..142ace1b8 100644 --- a/nebulosa-skycatalog/src/main/kotlin/nebulosa/skycatalog/SkyObjectType.kt +++ b/nebulosa-skycatalog/src/main/kotlin/nebulosa/skycatalog/SkyObjectType.kt @@ -163,10 +163,10 @@ enum class SkyObjectType( companion object { - @JvmStatic private val MAPPED_ENTRIES = HashMap(entries.size * 2) + @JvmStatic private val MAPPED = HashMap(entries.size * 2) .apply { SkyObjectType.entries.forEach { entry -> entry.codes.forEach { this[it] = entry } } } @JvmStatic - fun parse(type: String) = MAPPED_ENTRIES[type] + fun parse(type: String) = MAPPED[type] } } diff --git a/nebulosa-xisf/src/main/kotlin/nebulosa/xisf/XisfFormat.kt b/nebulosa-xisf/src/main/kotlin/nebulosa/xisf/XisfFormat.kt index 59db063ef..fa2e43ee2 100644 --- a/nebulosa-xisf/src/main/kotlin/nebulosa/xisf/XisfFormat.kt +++ b/nebulosa-xisf/src/main/kotlin/nebulosa/xisf/XisfFormat.kt @@ -1,14 +1,18 @@ package nebulosa.xisf +import nebulosa.fits.ValueType +import nebulosa.fits.frame import nebulosa.image.format.Hdu import nebulosa.image.format.ImageFormat import nebulosa.image.format.ImageHdu -import nebulosa.io.SeekableSource -import nebulosa.io.sink -import nebulosa.io.transferFully +import nebulosa.io.* +import nebulosa.xisf.XisfMonolithicFileHeader.ColorSpace +import nebulosa.xisf.XisfMonolithicFileHeader.ImageType import okio.Buffer import okio.Sink +import okio.Timeout import java.io.ByteArrayInputStream +import kotlin.math.min /** * Extensible Image Serialization Format (XISF) is the native file format of PixInsight. @@ -22,10 +26,10 @@ data object XisfFormat : ImageFormat { override fun read(source: SeekableSource): List { return Buffer().use { buffer -> source.read(buffer, 8) // XISF0100 - buffer.readString(Charsets.US_ASCII) + check(buffer.readString(Charsets.US_ASCII) == "XISF0100") { "invalid magic bytes" } // Header length (4) + reserved (4) - source.read(buffer, 4 + 4) + source.read(buffer, 8) val headerLength = buffer.readIntLe() // buffer.skip(4) // reserved buffer.clear() @@ -50,6 +54,116 @@ data object XisfFormat : ImageFormat { } override fun write(sink: Sink, hdus: Iterable>) { - TODO("Not implemented yet") + Buffer().use { buffer -> + buffer.writeString(MAGIC_HEADER, Charsets.US_ASCII) + buffer.writeLongLe(0L) + buffer.writeUtf8(XML_VERSION) + buffer.writeUtf8(XML_COMMENT) + buffer.writeUtf8(XISF_START_TAG) + + for (hdu in hdus) { + if (hdu is ImageHdu) { + val header = hdu.header + val colorSpace = if (hdu.isMono) ColorSpace.GRAY else ColorSpace.RGB + val imageType = ImageType.valueOf(header.frame ?: "LIGHT") + val imageSize = hdu.width * hdu.height * hdu.numberOfChannels * 4 + + IMAGE_START_TAG + .format(hdu.width, hdu.height, hdu.numberOfChannels, colorSpace.code, imageType.code, MAX_HEADER_SIZE, imageSize) + .also(buffer::writeUtf8) + + for ((name, key) in AstronomicalImageProperties) { + if (key != null) { + if (key.valueType == ValueType.STRING || key.valueType == ValueType.ANY) { + val value = header.getStringOrNull(key) ?: continue + buffer.writeUtf8(STRING_PROPERTY_TAG.format(name, value)) + } else if (key.valueType == ValueType.LOGICAL) { + val value = header.getBooleanOrNull(key) ?: continue + buffer.writeUtf8(NON_STRING_PROPERTY_TAG.format(name, XisfPropertyType.BOOLEAN.typeName, if (value) 1 else 0)) + } else if (key.valueType == ValueType.INTEGER) { + val value = header.getLongOrNull(key) ?: continue + buffer.writeUtf8(NON_STRING_PROPERTY_TAG.format(name, XisfPropertyType.INT64.typeName, value)) + } else if (key.valueType == ValueType.REAL) { + val value = header.getDoubleOrNull(key) ?: continue + buffer.writeUtf8(NON_STRING_PROPERTY_TAG.format(name, XisfPropertyType.FLOAT64.typeName, value)) + } + } + } + + for (keyword in header) { + buffer.writeUtf8(FITS_KEYWORD_TAG.format(keyword.key, keyword.value, keyword.comment)) + } + } + } + + buffer.writeUtf8(IMAGE_END_TAG) + buffer.writeUtf8(XISF_END_TAG) + + val headerSize = buffer.size - 8 + + buffer.readAndWriteUnsafe().use { + it.seek(8L) + it.data!![it.start + 0] = (headerSize and 0xFF).toByte() + it.data!![it.start + 1] = (headerSize shr 8 and 0xFF).toByte() + it.data!![it.start + 2] = (headerSize shr 16 and 0xFF).toByte() + it.data!![it.start + 3] = (headerSize shr 24 and 0xFF).toByte() + } + + val byteCount = buffer.readAll(sink) + + val remainingBytes = MAX_HEADER_SIZE - byteCount + check(remainingBytes >= 0L) { "unexpected remaining bytes: $remainingBytes" } + buffer.write(ZeroSource, remainingBytes) + buffer.readAll(sink) + + for (hdu in hdus) { + if (hdu is ImageHdu) { + if (hdu.isMono) { + hdu.data.red.readTo(buffer, sink) + } else { + hdu.data.red.readTo(buffer, sink) + hdu.data.green.readTo(buffer, sink) + hdu.data.blue.readTo(buffer, sink) + } + } + } + } + } + + private fun FloatArray.readTo(buffer: Buffer, sink: Sink) { + var idx = 0 + + while (idx < size) { + repeat(min(256, size - idx)) { buffer.writeFloatLe(this[idx++]) } + buffer.readAll(sink) + } + + buffer.readAll(sink) + } + + private const val MAGIC_HEADER = "XISF0100" + private const val MAX_HEADER_SIZE = 4096 + private const val XML_VERSION = """""" + private const val XML_COMMENT = + """""" + private const val XISF_START_TAG = + """""" + private const val XISF_END_TAG = "" + private const val IMAGE_START_TAG = + """""" + private const val IMAGE_END_TAG = "" + private const val STRING_PROPERTY_TAG = """%s""" + private const val NON_STRING_PROPERTY_TAG = """""" + private const val FITS_KEYWORD_TAG = """""" + + private data object ZeroSource : AbstractSeekableSource() { + + override val size = Long.MAX_VALUE + override val timeout = Timeout.NONE + + override fun transfer(output: ByteArray, start: Int, length: Int): Int { + repeat(length) { output[start + it] = 0 } + return length + } } } diff --git a/nebulosa-xisf/src/main/kotlin/nebulosa/xisf/XisfHeaderInputStream.kt b/nebulosa-xisf/src/main/kotlin/nebulosa/xisf/XisfHeaderInputStream.kt index ccdb7e3f7..681e9cdd2 100644 --- a/nebulosa-xisf/src/main/kotlin/nebulosa/xisf/XisfHeaderInputStream.kt +++ b/nebulosa-xisf/src/main/kotlin/nebulosa/xisf/XisfHeaderInputStream.kt @@ -43,6 +43,7 @@ class XisfHeaderInputStream(source: InputStream) : Closeable { val colorSpace = reader.attribute("colorSpace")?.uppercase()?.let(ColorSpace::valueOf) val pixelStorage = reader.attribute("pixelStorage")?.uppercase()?.let(PixelStorageModel::valueOf) val byteOrder = reader.attribute("byteOrder")?.uppercase()?.let(ByteOrder::valueOf) + val imageType = reader.attribute("imageType")?.let { ImageType.parse(it) } val compression = reader.attribute("compression")?.let { CompressionFormat.parse(it) } val bounds = reader.attribute("bounds")?.split(":")?.let { it[0].toFloat()..it[1].toFloat() } val (keywords, thumbnail) = parseKeywords() @@ -53,7 +54,8 @@ class XisfHeaderInputStream(source: InputStream) : Closeable { sampleFormat, colorSpace ?: ColorSpace.GRAY, pixelStorage ?: PixelStorageModel.PLANAR, byteOrder ?: ByteOrder.LITTLE, - compression, bounds ?: XisfMonolithicFileHeader.DEFAULT_BOUNDS, + compression, imageType ?: ImageType.LIGHT, + bounds ?: XisfMonolithicFileHeader.DEFAULT_BOUNDS, keywords, thumbnail, ) } diff --git a/nebulosa-xisf/src/main/kotlin/nebulosa/xisf/XisfMonolithicFileHeader.kt b/nebulosa-xisf/src/main/kotlin/nebulosa/xisf/XisfMonolithicFileHeader.kt index 00d79d997..68b4b2def 100644 --- a/nebulosa-xisf/src/main/kotlin/nebulosa/xisf/XisfMonolithicFileHeader.kt +++ b/nebulosa-xisf/src/main/kotlin/nebulosa/xisf/XisfMonolithicFileHeader.kt @@ -1,5 +1,7 @@ package nebulosa.xisf +import nebulosa.fits.FitsHeaderCard +import nebulosa.fits.FitsKeyword import nebulosa.image.format.HeaderCard import nebulosa.io.ByteOrder @@ -14,10 +16,10 @@ sealed interface XisfMonolithicFileHeader { FLOAT64(8L), } - enum class ColorSpace { - GRAY, - RGB, - CIELAB, + enum class ColorSpace(@JvmField val code: String) { + GRAY("Gray"), + RGB("RGB"), + CIELAB("CIELab"), } enum class PixelStorageModel { @@ -32,6 +34,32 @@ sealed interface XisfMonolithicFileHeader { ZSTD, } + enum class ImageType(@JvmField val code: String) : HeaderCard by FitsHeaderCard.create(FitsKeyword.IMAGETYP, code) { + BIAS("Bias"), + DARK("Dark"), + FLAT("Flat"), + LIGHT("Light"), + MASTER_BIAS("MasterBias"), + MASTER_DARK("MasterDark"), + MASTER_FLAT("MasterFlat"), + MASTER_LIGHT("MasterLight"), + DEFECT_MAP("DefectMap"), + REJECTION_MAP_HIGH("RejectionMapHigh"), + REJECTION_MAP_LOW("RejectionMapLow"), + BINARY_REJECTION_MAP_HIGH("BinaryRejectionMapHigh"), + BINARY_REJECTION_MAP_LOW("BinaryRejectionMapLow"), + SLOPE_MAP("SlopeMap"), + WEIGHT_MAP("WeightMap"); + + companion object { + + @JvmStatic private val MAPPED = entries.associateBy { it.value } + + @JvmStatic + fun parse(text: String) = MAPPED[text] + } + } + data class CompressionFormat( @JvmField val type: CompressionType, @JvmField val shuffled: Boolean, @@ -68,6 +96,7 @@ sealed interface XisfMonolithicFileHeader { @JvmField val sampleFormat: SampleFormat, @JvmField val colorSpace: ColorSpace, @JvmField val pixelStorage: PixelStorageModel, @JvmField val byteOrder: ByteOrder, @JvmField val compressionFormat: CompressionFormat? = null, + @JvmField val imageType: ImageType = ImageType.LIGHT, @JvmField val bounds: ClosedFloatingPointRange = DEFAULT_BOUNDS, @JvmField val keywords: List = emptyList(), @JvmField val thumbnail: Image? = null, diff --git a/nebulosa-xisf/src/test/kotlin/XisfFormatTest.kt b/nebulosa-xisf/src/test/kotlin/XisfFormatTest.kt index fe3e0c97a..0ca6da519 100644 --- a/nebulosa-xisf/src/test/kotlin/XisfFormatTest.kt +++ b/nebulosa-xisf/src/test/kotlin/XisfFormatTest.kt @@ -1,9 +1,11 @@ +import io.kotest.engine.spec.tempfile import io.kotest.matchers.collections.shouldHaveSize import io.kotest.matchers.ints.shouldBeExactly import io.kotest.matchers.shouldBe import io.kotest.matchers.types.shouldBeSameInstanceAs import io.kotest.matchers.types.shouldNotBeSameInstanceAs import nebulosa.image.format.ImageHdu +import nebulosa.io.seekableSink import nebulosa.io.seekableSource import nebulosa.test.FitsStringSpec import nebulosa.xisf.XisfFormat @@ -223,6 +225,21 @@ class XisfFormatTest : FitsStringSpec() { image.save("xisf-mono-planar-8-zlib").second shouldBe "0dca7efedef5b3525f8037f401518b0b" } } + "mono:write" { + val source0 = closeAfterEach(M82_MONO_8_XISF.seekableSource()) + val hdus0 = XisfFormat.read(source0) + + val outputPath = tempfile() + val sink = closeAfterEach(outputPath.seekableSink()) + + XisfFormat.write(sink, hdus0) + + val source1 = closeAfterEach(outputPath.seekableSource()) + val hdus1 = XisfFormat.read(source1) + + hdus1 shouldHaveSize 1 + hdus1[0].header.size shouldBeExactly hdus0[0].header.size + } } companion object { diff --git a/nebulosa-xisf/src/test/kotlin/XisfHeaderInputStreamTest.kt b/nebulosa-xisf/src/test/kotlin/XisfHeaderInputStreamTest.kt index 04ba2c042..201390956 100644 --- a/nebulosa-xisf/src/test/kotlin/XisfHeaderInputStreamTest.kt +++ b/nebulosa-xisf/src/test/kotlin/XisfHeaderInputStreamTest.kt @@ -24,7 +24,7 @@ class XisfHeaderInputStreamTest : FitsStringSpec() { sampleFormat shouldBe XisfMonolithicFileHeader.SampleFormat.UINT8 colorSpace shouldBe XisfMonolithicFileHeader.ColorSpace.GRAY byteOrder shouldBe ByteOrder.LITTLE - keywords shouldHaveSize 22 + keywords shouldHaveSize 29 } } "read:8:gray:zlib" { @@ -40,7 +40,7 @@ class XisfHeaderInputStreamTest : FitsStringSpec() { colorSpace shouldBe XisfMonolithicFileHeader.ColorSpace.GRAY byteOrder shouldBe ByteOrder.LITTLE compressionFormat.shouldNotBeNull().type shouldBe XisfMonolithicFileHeader.CompressionType.ZLIB - keywords shouldHaveSize 22 + keywords shouldHaveSize 29 } } "read:8:gray:lz4" { @@ -56,7 +56,7 @@ class XisfHeaderInputStreamTest : FitsStringSpec() { colorSpace shouldBe XisfMonolithicFileHeader.ColorSpace.GRAY byteOrder shouldBe ByteOrder.LITTLE compressionFormat.shouldNotBeNull().type shouldBe XisfMonolithicFileHeader.CompressionType.LZ4 - keywords shouldHaveSize 22 + keywords shouldHaveSize 29 } } "read:8:gray:lz4-hc" { @@ -72,7 +72,7 @@ class XisfHeaderInputStreamTest : FitsStringSpec() { colorSpace shouldBe XisfMonolithicFileHeader.ColorSpace.GRAY byteOrder shouldBe ByteOrder.LITTLE compressionFormat.shouldNotBeNull().type shouldBe XisfMonolithicFileHeader.CompressionType.LZ4_HC - keywords shouldHaveSize 22 + keywords shouldHaveSize 29 } } "read:8:gray:zstd" { @@ -88,7 +88,7 @@ class XisfHeaderInputStreamTest : FitsStringSpec() { colorSpace shouldBe XisfMonolithicFileHeader.ColorSpace.GRAY byteOrder shouldBe ByteOrder.LITTLE compressionFormat.shouldNotBeNull().type shouldBe XisfMonolithicFileHeader.CompressionType.ZSTD - keywords shouldHaveSize 22 + keywords shouldHaveSize 29 } } "read:16:gray" { @@ -103,7 +103,7 @@ class XisfHeaderInputStreamTest : FitsStringSpec() { sampleFormat shouldBe XisfMonolithicFileHeader.SampleFormat.UINT16 colorSpace shouldBe XisfMonolithicFileHeader.ColorSpace.GRAY byteOrder shouldBe ByteOrder.LITTLE - keywords shouldHaveSize 22 + keywords shouldHaveSize 29 } } "read:32:gray" { @@ -118,7 +118,7 @@ class XisfHeaderInputStreamTest : FitsStringSpec() { sampleFormat shouldBe XisfMonolithicFileHeader.SampleFormat.UINT32 colorSpace shouldBe XisfMonolithicFileHeader.ColorSpace.GRAY byteOrder shouldBe ByteOrder.LITTLE - keywords shouldHaveSize 22 + keywords shouldHaveSize 29 } } "read:F32:gray" { @@ -133,7 +133,7 @@ class XisfHeaderInputStreamTest : FitsStringSpec() { sampleFormat shouldBe XisfMonolithicFileHeader.SampleFormat.FLOAT32 colorSpace shouldBe XisfMonolithicFileHeader.ColorSpace.GRAY byteOrder shouldBe ByteOrder.LITTLE - keywords shouldHaveSize 22 + keywords shouldHaveSize 29 } } "read:F64:gray" { @@ -148,7 +148,7 @@ class XisfHeaderInputStreamTest : FitsStringSpec() { sampleFormat shouldBe XisfMonolithicFileHeader.SampleFormat.FLOAT64 colorSpace shouldBe XisfMonolithicFileHeader.ColorSpace.GRAY byteOrder shouldBe ByteOrder.LITTLE - keywords shouldHaveSize 22 + keywords shouldHaveSize 29 } } "read:8:rgb" { @@ -163,7 +163,7 @@ class XisfHeaderInputStreamTest : FitsStringSpec() { sampleFormat shouldBe XisfMonolithicFileHeader.SampleFormat.UINT8 colorSpace shouldBe XisfMonolithicFileHeader.ColorSpace.RGB byteOrder shouldBe ByteOrder.LITTLE - keywords shouldHaveSize 22 + keywords shouldHaveSize 29 } } "read:16:rgb" { @@ -178,7 +178,7 @@ class XisfHeaderInputStreamTest : FitsStringSpec() { sampleFormat shouldBe XisfMonolithicFileHeader.SampleFormat.UINT16 colorSpace shouldBe XisfMonolithicFileHeader.ColorSpace.RGB byteOrder shouldBe ByteOrder.LITTLE - keywords shouldHaveSize 22 + keywords shouldHaveSize 29 } } "read:32:rgb" { @@ -193,7 +193,7 @@ class XisfHeaderInputStreamTest : FitsStringSpec() { sampleFormat shouldBe XisfMonolithicFileHeader.SampleFormat.UINT32 colorSpace shouldBe XisfMonolithicFileHeader.ColorSpace.RGB byteOrder shouldBe ByteOrder.LITTLE - keywords shouldHaveSize 22 + keywords shouldHaveSize 29 } } "read:F32:rgb" { @@ -208,7 +208,7 @@ class XisfHeaderInputStreamTest : FitsStringSpec() { sampleFormat shouldBe XisfMonolithicFileHeader.SampleFormat.FLOAT32 colorSpace shouldBe XisfMonolithicFileHeader.ColorSpace.RGB byteOrder shouldBe ByteOrder.LITTLE - keywords shouldHaveSize 22 + keywords shouldHaveSize 29 } } "read:F64:rgb" { @@ -223,7 +223,7 @@ class XisfHeaderInputStreamTest : FitsStringSpec() { sampleFormat shouldBe XisfMonolithicFileHeader.SampleFormat.FLOAT64 colorSpace shouldBe XisfMonolithicFileHeader.ColorSpace.RGB byteOrder shouldBe ByteOrder.LITTLE - keywords shouldHaveSize 22 + keywords shouldHaveSize 29 } } } From 3fa65d8bcaab610ef36936f7de9fbfd7541319db Mon Sep 17 00:00:00 2001 From: tiagohm Date: Sun, 31 Mar 2024 09:27:28 -0300 Subject: [PATCH 11/15] [api]: Fix possible memory leak --- .../nebulosa/api/atlas/SkyAtlasUpdateTask.kt | 10 +- .../main/kotlin/nebulosa/fits/FitsHeader.kt | 2 +- .../src/main/kotlin/nebulosa/nasa/daf/Daf.kt | 91 ++++++++++--------- .../kotlin/nebulosa/nasa/daf/SourceDaf.kt | 7 +- .../solving/quad/QuadDatabaseCellFile.kt | 2 +- .../main/kotlin/nebulosa/xisf/XisfFormat.kt | 3 +- 6 files changed, 59 insertions(+), 56 deletions(-) diff --git a/api/src/main/kotlin/nebulosa/api/atlas/SkyAtlasUpdateTask.kt b/api/src/main/kotlin/nebulosa/api/atlas/SkyAtlasUpdateTask.kt index 6aea23af6..b1392e952 100644 --- a/api/src/main/kotlin/nebulosa/api/atlas/SkyAtlasUpdateTask.kt +++ b/api/src/main/kotlin/nebulosa/api/atlas/SkyAtlasUpdateTask.kt @@ -74,10 +74,12 @@ class SkyAtlasUpdateTask( httpClient.newCall(request).execute().use { if (it.isSuccessful) { - val reader = SimbadDatabaseReader(it.body!!.byteStream().source()) - - for (entity in reader) { - simbadEntityRepository.save(entity) + it.body!!.byteStream().source().use { source -> + SimbadDatabaseReader(source).use { reader -> + for (entity in reader) { + simbadEntityRepository.save(entity) + } + } } } else if (it.code == 404) { finished = true diff --git a/nebulosa-fits/src/main/kotlin/nebulosa/fits/FitsHeader.kt b/nebulosa-fits/src/main/kotlin/nebulosa/fits/FitsHeader.kt index 2925f66b3..99267a3df 100644 --- a/nebulosa-fits/src/main/kotlin/nebulosa/fits/FitsHeader.kt +++ b/nebulosa-fits/src/main/kotlin/nebulosa/fits/FitsHeader.kt @@ -122,7 +122,7 @@ open class FitsHeader : AbstractHeader { @JvmStatic fun from(source: ByteArray): FitsHeader { - return from(source.source()) + return source.source().use(::from) } @JvmStatic diff --git a/nebulosa-nasa/src/main/kotlin/nebulosa/nasa/daf/Daf.kt b/nebulosa-nasa/src/main/kotlin/nebulosa/nasa/daf/Daf.kt index e71ae9184..c4e5a349b 100644 --- a/nebulosa-nasa/src/main/kotlin/nebulosa/nasa/daf/Daf.kt +++ b/nebulosa-nasa/src/main/kotlin/nebulosa/nasa/daf/Daf.kt @@ -18,43 +18,40 @@ abstract class Daf : Closeable { inline operator fun component2() = summaries open fun read() { - val buffer = Buffer() - - try { + Buffer().use { buffer -> // File record. - val source = buffer.readRecord(1) - // Gets the file format. - val format = buffer.read(source, 8L) { it.readAscii().uppercase() } - - if (format == "NAIF/DAF") { - source.seek(0L) - record = buffer.read(source, 88L) { it.parseFileRecord(false) } + buffer.readRecord(1).use { source -> + // Gets the file format. + val format = buffer.read(source, 8L) { it.readAscii().uppercase() } - if (record.nd != 2) { + if (format == "NAIF/DAF") { source.seek(0L) - record = buffer.read(source, 88L) { it.parseFileRecord(true) } + record = buffer.read(source, 88L) { it.parseFileRecord(false) } if (record.nd != 2) { - throw IOException("neither a big nor a little-endian scan of this file produces the expected ND=2") + source.seek(0L) + record = buffer.read(source, 88L) { it.parseFileRecord(true) } + + if (record.nd != 2) { + throw IOException("neither a big nor a little-endian scan of this file produces the expected ND=2") + } } - } - } else if (format.startsWith("DAF/")) { - source.seek(699L) + } else if (format.startsWith("DAF/")) { + source.seek(699L) - val magic = buffer.read(source, FTPSTR.length.toLong()) { it.readLatin1() } + val magic = buffer.read(source, FTPSTR.length.toLong()) { it.readLatin1() } - if (magic != FTPSTR) throw IOException("file has been damaged") + if (magic != FTPSTR) throw IOException("file has been damaged") - source.seek(88L) - val littleEndian = buffer.read(source, 8L) { it.readAscii().uppercase() == "LTL-IEEE" } + source.seek(88L) + val littleEndian = buffer.read(source, 8L) { it.readAscii().uppercase() == "LTL-IEEE" } - source.seek(0L) - record = buffer.read(source, 88L) { it.parseFileRecord(littleEndian) } - } else { - throw IOException("unsupported format: $format") + source.seek(0L) + record = buffer.read(source, 88L) { it.parseFileRecord(littleEndian) } + } else { + throw IOException("unsupported format: $format") + } } - } finally { - buffer.clear() } } @@ -66,18 +63,20 @@ abstract class Daf : Closeable { val summaries = ArrayList() var recordNumber = record.fward - val buffer = Buffer() - val length = record.nd * 8L + record.ni * 4L - val step = length - length % 8 + Buffer().use { buffer -> + val length = record.nd * 8L + record.ni * 4L + val step = length - length % 8 - while (recordNumber != 0) { - val data = buffer.readRecord(recordNumber) - val sc = buffer.read(data, 24L) { it.parseSummaryControlRecord() } - summaries.addAll(parseSummaries(recordNumber, sc.numberOfSummaries, data, step)) - recordNumber = sc.nextNumber - } + while (recordNumber != 0) { + buffer.readRecord(recordNumber).use { source -> + val sc = buffer.read(source, 24L) { it.parseSummaryControlRecord() } + summaries.addAll(parseSummaries(recordNumber, sc.numberOfSummaries, source, step)) + recordNumber = sc.nextNumber + } + } - summaries + summaries + } } private fun parseSummaries( @@ -89,17 +88,19 @@ abstract class Daf : Closeable { ): List { val summaries = ArrayList() - val buffer = Buffer() - val nameData = buffer.readRecord(recordNumber + 1) - val elementRecordSizeInBytes = record.nd * 8L + record.ni * 4L + Buffer().use { buffer -> + buffer.readRecord(recordNumber + 1).use { source -> + val elementRecordSizeInBytes = record.nd * 8L + record.ni * 4L - for (i in 0 until numberOfSummaries * step step step) { - nameData.seek(i) - val name = buffer.read(nameData, step).use { it.readAscii().trim() } + for (i in 0 until numberOfSummaries * step step step) { + source.seek(i) + val name = buffer.read(source, step).use { it.readAscii().trim() } - data.seek(24 + i) - val elements = buffer.read(data, elementRecordSizeInBytes) { it.parseElementRecords() } - summaries.add(Summary(name, elements.first, elements.second)) + data.seek(24 + i) + val elements = buffer.read(data, elementRecordSizeInBytes) { it.parseElementRecords() } + summaries.add(Summary(name, elements.first, elements.second)) + } + } } return summaries diff --git a/nebulosa-nasa/src/main/kotlin/nebulosa/nasa/daf/SourceDaf.kt b/nebulosa-nasa/src/main/kotlin/nebulosa/nasa/daf/SourceDaf.kt index 6dea30ff2..153001e80 100644 --- a/nebulosa-nasa/src/main/kotlin/nebulosa/nasa/daf/SourceDaf.kt +++ b/nebulosa-nasa/src/main/kotlin/nebulosa/nasa/daf/SourceDaf.kt @@ -12,9 +12,10 @@ class SourceDaf(private val source: SeekableSource) : Daf(), Closeable by source override fun read(start: Int, end: Int): DoubleArray { source.seek(8L * (start - 1)) val length = 1 + end - start - val buffer = Buffer() - source.read(buffer, length * 8L) - return buffer.readDoubleArray(length, record.order) + return Buffer().use { buffer -> + source.read(buffer, length * 8L) + buffer.readDoubleArray(length, record.order) + } } override fun Buffer.readRecord(index: Int): SeekableSource { diff --git a/nebulosa-watney/src/main/kotlin/nebulosa/watney/plate/solving/quad/QuadDatabaseCellFile.kt b/nebulosa-watney/src/main/kotlin/nebulosa/watney/plate/solving/quad/QuadDatabaseCellFile.kt index 886cd02c5..07d741fbd 100644 --- a/nebulosa-watney/src/main/kotlin/nebulosa/watney/plate/solving/quad/QuadDatabaseCellFile.kt +++ b/nebulosa-watney/src/main/kotlin/nebulosa/watney/plate/solving/quad/QuadDatabaseCellFile.kt @@ -88,7 +88,7 @@ internal data class QuadDatabaseCellFile(@JvmField val descriptor: QuadDatabaseC } } - buffer.clear() + buffer.close() source.close() return matchingQuadsWithinRange diff --git a/nebulosa-xisf/src/main/kotlin/nebulosa/xisf/XisfFormat.kt b/nebulosa-xisf/src/main/kotlin/nebulosa/xisf/XisfFormat.kt index fa2e43ee2..58146170e 100644 --- a/nebulosa-xisf/src/main/kotlin/nebulosa/xisf/XisfFormat.kt +++ b/nebulosa-xisf/src/main/kotlin/nebulosa/xisf/XisfFormat.kt @@ -36,8 +36,7 @@ data object XisfFormat : ImageFormat { // XISF Header. val headerData = ByteArray(headerLength) - val headerSink = headerData.sink() - buffer.transferFully(source, headerSink, headerLength.toLong()) + headerData.sink().use { buffer.transferFully(source, it, headerLength.toLong()) } val stream = XisfHeaderInputStream(ByteArrayInputStream(headerData)) val hdus = ArrayList(2) From fa944282d9d0d762c47908b97ad255dec25bb44d Mon Sep 17 00:00:00 2001 From: tiagohm Date: Sun, 31 Mar 2024 22:30:33 -0300 Subject: [PATCH 12/15] [api]: Implement XISF write --- .../nebulosa/io/AbstractSeekableSink.kt | 8 +-- .../nebulosa/io/AbstractSeekableSource.kt | 2 +- .../main/kotlin/nebulosa/xisf/XisfFormat.kt | 8 ++- .../nebulosa/xisf/XisfHeaderInputStream.kt | 16 ++++-- .../nebulosa/xisf/XisfMonolithicFileHeader.kt | 2 +- .../src/test/kotlin/XisfFormatTest.kt | 56 +++++++++++++++---- .../test/kotlin/XisfHeaderInputStreamTest.kt | 28 +++++----- .../src/main/kotlin/nebulosa/xml/XmlHelper.kt | 19 +++++++ 8 files changed, 100 insertions(+), 39 deletions(-) diff --git a/nebulosa-io/src/main/kotlin/nebulosa/io/AbstractSeekableSink.kt b/nebulosa-io/src/main/kotlin/nebulosa/io/AbstractSeekableSink.kt index 8b929d13c..aade67cdf 100644 --- a/nebulosa-io/src/main/kotlin/nebulosa/io/AbstractSeekableSink.kt +++ b/nebulosa-io/src/main/kotlin/nebulosa/io/AbstractSeekableSink.kt @@ -37,10 +37,10 @@ abstract class AbstractSeekableSink : SeekableSink { var remaining = byteCount - while (remaining > 0L) { - timeout.throwIfReached() + source.readUnsafe(cursor).use { + while (remaining > 0L) { + timeout.throwIfReached() - source.readUnsafe(cursor).use { it.seek(0L) val length = computeTransferedSize(it, remaining) @@ -62,5 +62,5 @@ abstract class AbstractSeekableSink : SeekableSink { override fun flush() = Unit - override fun close() = cursor.close() + override fun close() = Unit } diff --git a/nebulosa-io/src/main/kotlin/nebulosa/io/AbstractSeekableSource.kt b/nebulosa-io/src/main/kotlin/nebulosa/io/AbstractSeekableSource.kt index 65c980303..2c8338b95 100644 --- a/nebulosa-io/src/main/kotlin/nebulosa/io/AbstractSeekableSource.kt +++ b/nebulosa-io/src/main/kotlin/nebulosa/io/AbstractSeekableSource.kt @@ -55,5 +55,5 @@ abstract class AbstractSeekableSource : SeekableSource { override fun timeout() = timeout - override fun close() = cursor.close() + override fun close() = Unit } diff --git a/nebulosa-xisf/src/main/kotlin/nebulosa/xisf/XisfFormat.kt b/nebulosa-xisf/src/main/kotlin/nebulosa/xisf/XisfFormat.kt index 58146170e..7e704efb8 100644 --- a/nebulosa-xisf/src/main/kotlin/nebulosa/xisf/XisfFormat.kt +++ b/nebulosa-xisf/src/main/kotlin/nebulosa/xisf/XisfFormat.kt @@ -8,6 +8,7 @@ import nebulosa.image.format.ImageHdu import nebulosa.io.* import nebulosa.xisf.XisfMonolithicFileHeader.ColorSpace import nebulosa.xisf.XisfMonolithicFileHeader.ImageType +import nebulosa.xml.escapeXml import okio.Buffer import okio.Sink import okio.Timeout @@ -75,7 +76,7 @@ data object XisfFormat : ImageFormat { if (key != null) { if (key.valueType == ValueType.STRING || key.valueType == ValueType.ANY) { val value = header.getStringOrNull(key) ?: continue - buffer.writeUtf8(STRING_PROPERTY_TAG.format(name, value)) + buffer.writeUtf8(STRING_PROPERTY_TAG.format(name, value.escapeXml())) } else if (key.valueType == ValueType.LOGICAL) { val value = header.getBooleanOrNull(key) ?: continue buffer.writeUtf8(NON_STRING_PROPERTY_TAG.format(name, XisfPropertyType.BOOLEAN.typeName, if (value) 1 else 0)) @@ -90,7 +91,8 @@ data object XisfFormat : ImageFormat { } for (keyword in header) { - buffer.writeUtf8(FITS_KEYWORD_TAG.format(keyword.key, keyword.value, keyword.comment)) + val value = if (keyword.isStringType) "'${keyword.value.escapeXml()}'" else keyword.value + buffer.writeUtf8(FITS_KEYWORD_TAG.format(keyword.key, value, keyword.comment.escapeXml())) } } } @@ -98,7 +100,7 @@ data object XisfFormat : ImageFormat { buffer.writeUtf8(IMAGE_END_TAG) buffer.writeUtf8(XISF_END_TAG) - val headerSize = buffer.size - 8 + val headerSize = buffer.size - 16 buffer.readAndWriteUnsafe().use { it.seek(8L) diff --git a/nebulosa-xisf/src/main/kotlin/nebulosa/xisf/XisfHeaderInputStream.kt b/nebulosa-xisf/src/main/kotlin/nebulosa/xisf/XisfHeaderInputStream.kt index 681e9cdd2..2c703da0d 100644 --- a/nebulosa-xisf/src/main/kotlin/nebulosa/xisf/XisfHeaderInputStream.kt +++ b/nebulosa-xisf/src/main/kotlin/nebulosa/xisf/XisfHeaderInputStream.kt @@ -60,12 +60,18 @@ class XisfHeaderInputStream(source: InputStream) : Closeable { ) } - private fun parseKeywords(): Pair, Image?> { + private fun parseKeywords(): Pair, Image?> { val name = reader.localName - val keywords = ArrayList() + val cards = ArrayList() var thumbnail: Image? = null + fun addHeaderCard(card: HeaderCard) { + if (cards.find { it.key == card.key } == null) { + cards.add(card) + } + } + while (reader.hasNext()) { val type = reader.next() @@ -73,14 +79,14 @@ class XisfHeaderInputStream(source: InputStream) : Closeable { break } else if (type == XMLStreamConstants.START_ELEMENT) { when (reader.localName) { - "FITSKeyword" -> keywords.add(parseFITSKeyword()) + "FITSKeyword" -> addHeaderCard(parseFITSKeyword()) "Thumbnail" -> thumbnail = parseImage() - "Property" -> keywords.add(parseProperty() ?: continue) + "Property" -> addHeaderCard(parseProperty() ?: continue) } } } - return keywords to thumbnail + return cards to thumbnail } private fun parseFITSKeyword(): HeaderCard { diff --git a/nebulosa-xisf/src/main/kotlin/nebulosa/xisf/XisfMonolithicFileHeader.kt b/nebulosa-xisf/src/main/kotlin/nebulosa/xisf/XisfMonolithicFileHeader.kt index 68b4b2def..24c99282f 100644 --- a/nebulosa-xisf/src/main/kotlin/nebulosa/xisf/XisfMonolithicFileHeader.kt +++ b/nebulosa-xisf/src/main/kotlin/nebulosa/xisf/XisfMonolithicFileHeader.kt @@ -98,7 +98,7 @@ sealed interface XisfMonolithicFileHeader { @JvmField val compressionFormat: CompressionFormat? = null, @JvmField val imageType: ImageType = ImageType.LIGHT, @JvmField val bounds: ClosedFloatingPointRange = DEFAULT_BOUNDS, - @JvmField val keywords: List = emptyList(), + @JvmField val keywords: Collection = emptyList(), @JvmField val thumbnail: Image? = null, ) : XisfMonolithicFileHeader diff --git a/nebulosa-xisf/src/test/kotlin/XisfFormatTest.kt b/nebulosa-xisf/src/test/kotlin/XisfFormatTest.kt index 0ca6da519..4f7ebbc11 100644 --- a/nebulosa-xisf/src/test/kotlin/XisfFormatTest.kt +++ b/nebulosa-xisf/src/test/kotlin/XisfFormatTest.kt @@ -1,5 +1,6 @@ import io.kotest.engine.spec.tempfile import io.kotest.matchers.collections.shouldHaveSize +import io.kotest.matchers.floats.shouldBeExactly import io.kotest.matchers.ints.shouldBeExactly import io.kotest.matchers.shouldBe import io.kotest.matchers.types.shouldBeSameInstanceAs @@ -26,7 +27,7 @@ class XisfFormatTest : FitsStringSpec() { width shouldBeExactly 512 height shouldBeExactly 512 numberOfChannels shouldBeExactly 1 - header shouldHaveSize 29 + header shouldHaveSize 17 data.red.size shouldBeExactly 512 * 512 data.green shouldBeSameInstanceAs data.red data.blue shouldBeSameInstanceAs data.green @@ -45,7 +46,7 @@ class XisfFormatTest : FitsStringSpec() { width shouldBeExactly 512 height shouldBeExactly 512 numberOfChannels shouldBeExactly 1 - header shouldHaveSize 29 + header shouldHaveSize 17 data.red.size shouldBeExactly 512 * 512 data.green shouldBeSameInstanceAs data.red data.blue shouldBeSameInstanceAs data.green @@ -64,7 +65,7 @@ class XisfFormatTest : FitsStringSpec() { width shouldBeExactly 512 height shouldBeExactly 512 numberOfChannels shouldBeExactly 1 - header shouldHaveSize 29 + header shouldHaveSize 17 data.red.size shouldBeExactly 512 * 512 data.green shouldBeSameInstanceAs data.red data.blue shouldBeSameInstanceAs data.green @@ -83,7 +84,7 @@ class XisfFormatTest : FitsStringSpec() { width shouldBeExactly 512 height shouldBeExactly 512 numberOfChannels shouldBeExactly 1 - header shouldHaveSize 29 + header shouldHaveSize 17 data.red.size shouldBeExactly 512 * 512 data.green shouldBeSameInstanceAs data.red data.blue shouldBeSameInstanceAs data.green @@ -102,7 +103,7 @@ class XisfFormatTest : FitsStringSpec() { width shouldBeExactly 512 height shouldBeExactly 512 numberOfChannels shouldBeExactly 1 - header shouldHaveSize 29 + header shouldHaveSize 17 data.red.size shouldBeExactly 512 * 512 data.green shouldBeSameInstanceAs data.red data.blue shouldBeSameInstanceAs data.green @@ -121,7 +122,7 @@ class XisfFormatTest : FitsStringSpec() { width shouldBeExactly 512 height shouldBeExactly 512 numberOfChannels shouldBeExactly 3 - header shouldHaveSize 29 + header shouldHaveSize 17 data.red.size shouldBeExactly 512 * 512 data.green shouldNotBeSameInstanceAs data.red data.blue shouldNotBeSameInstanceAs data.green @@ -140,7 +141,7 @@ class XisfFormatTest : FitsStringSpec() { width shouldBeExactly 512 height shouldBeExactly 512 numberOfChannels shouldBeExactly 3 - header shouldHaveSize 29 + header shouldHaveSize 17 data.red.size shouldBeExactly 512 * 512 data.green shouldNotBeSameInstanceAs data.red data.blue shouldNotBeSameInstanceAs data.green @@ -159,7 +160,7 @@ class XisfFormatTest : FitsStringSpec() { width shouldBeExactly 512 height shouldBeExactly 512 numberOfChannels shouldBeExactly 3 - header shouldHaveSize 29 + header shouldHaveSize 17 data.red.size shouldBeExactly 512 * 512 data.green shouldNotBeSameInstanceAs data.red data.blue shouldNotBeSameInstanceAs data.green @@ -178,7 +179,7 @@ class XisfFormatTest : FitsStringSpec() { width shouldBeExactly 512 height shouldBeExactly 512 numberOfChannels shouldBeExactly 3 - header shouldHaveSize 29 + header shouldHaveSize 17 data.red.size shouldBeExactly 512 * 512 data.green shouldNotBeSameInstanceAs data.red data.blue shouldNotBeSameInstanceAs data.green @@ -197,7 +198,7 @@ class XisfFormatTest : FitsStringSpec() { width shouldBeExactly 512 height shouldBeExactly 512 numberOfChannels shouldBeExactly 3 - header shouldHaveSize 29 + header shouldHaveSize 17 data.red.size shouldBeExactly 512 * 512 data.green shouldNotBeSameInstanceAs data.red data.blue shouldNotBeSameInstanceAs data.green @@ -216,7 +217,7 @@ class XisfFormatTest : FitsStringSpec() { width shouldBeExactly 512 height shouldBeExactly 512 numberOfChannels shouldBeExactly 1 - header shouldHaveSize 29 + header shouldHaveSize 17 data.red.size shouldBeExactly 512 * 512 data.green shouldBeSameInstanceAs data.red data.blue shouldBeSameInstanceAs data.green @@ -238,7 +239,40 @@ class XisfFormatTest : FitsStringSpec() { val hdus1 = XisfFormat.read(source1) hdus1 shouldHaveSize 1 + hdus1[0].data.numberOfChannels shouldBeExactly 1 hdus1[0].header.size shouldBeExactly hdus0[0].header.size + hdus1[0].data.red.size shouldBeExactly hdus0[0].data.red.size + hdus1[0].data.red shouldNotBeSameInstanceAs hdus0[0].data.red + hdus1[0].data.red.forEachIndexed { i, value -> value shouldBeExactly hdus0[0].data.red[i] } + + val image = hdus1[0].makeImage() + image.save("xisf-mono-write").second shouldBe "0dca7efedef5b3525f8037f401518b0b" + } + "color:write" { + val source0 = closeAfterEach(M82_COLOR_32_XISF.seekableSource()) + val hdus0 = XisfFormat.read(source0) + + val outputPath = tempfile() + val sink = closeAfterEach(outputPath.seekableSink()) + + XisfFormat.write(sink, hdus0) + + val source1 = closeAfterEach(outputPath.seekableSource()) + val hdus1 = XisfFormat.read(source1) + + hdus1 shouldHaveSize 1 + hdus1[0].data.numberOfChannels shouldBeExactly 3 + hdus1[0].header.size shouldBeExactly hdus0[0].header.size + hdus1[0].data.red.size shouldBeExactly hdus0[0].data.red.size + hdus1[0].data.red shouldNotBeSameInstanceAs hdus0[0].data.red + hdus1[0].data.red.forEachIndexed { i, value -> value shouldBeExactly hdus0[0].data.red[i] } + hdus1[0].data.green shouldNotBeSameInstanceAs hdus0[0].data.green + hdus1[0].data.green.forEachIndexed { i, value -> value shouldBeExactly hdus0[0].data.green[i] } + hdus1[0].data.blue shouldNotBeSameInstanceAs hdus0[0].data.blue + hdus1[0].data.blue.forEachIndexed { i, value -> value shouldBeExactly hdus0[0].data.blue[i] } + + val image = hdus1[0].makeImage() + image.save("xisf-color-write").second shouldBe "89beed384ee9e97ce033ba447a377937" } } diff --git a/nebulosa-xisf/src/test/kotlin/XisfHeaderInputStreamTest.kt b/nebulosa-xisf/src/test/kotlin/XisfHeaderInputStreamTest.kt index 201390956..83f9e6764 100644 --- a/nebulosa-xisf/src/test/kotlin/XisfHeaderInputStreamTest.kt +++ b/nebulosa-xisf/src/test/kotlin/XisfHeaderInputStreamTest.kt @@ -24,7 +24,7 @@ class XisfHeaderInputStreamTest : FitsStringSpec() { sampleFormat shouldBe XisfMonolithicFileHeader.SampleFormat.UINT8 colorSpace shouldBe XisfMonolithicFileHeader.ColorSpace.GRAY byteOrder shouldBe ByteOrder.LITTLE - keywords shouldHaveSize 29 + keywords shouldHaveSize 17 } } "read:8:gray:zlib" { @@ -40,7 +40,7 @@ class XisfHeaderInputStreamTest : FitsStringSpec() { colorSpace shouldBe XisfMonolithicFileHeader.ColorSpace.GRAY byteOrder shouldBe ByteOrder.LITTLE compressionFormat.shouldNotBeNull().type shouldBe XisfMonolithicFileHeader.CompressionType.ZLIB - keywords shouldHaveSize 29 + keywords shouldHaveSize 17 } } "read:8:gray:lz4" { @@ -56,7 +56,7 @@ class XisfHeaderInputStreamTest : FitsStringSpec() { colorSpace shouldBe XisfMonolithicFileHeader.ColorSpace.GRAY byteOrder shouldBe ByteOrder.LITTLE compressionFormat.shouldNotBeNull().type shouldBe XisfMonolithicFileHeader.CompressionType.LZ4 - keywords shouldHaveSize 29 + keywords shouldHaveSize 17 } } "read:8:gray:lz4-hc" { @@ -72,7 +72,7 @@ class XisfHeaderInputStreamTest : FitsStringSpec() { colorSpace shouldBe XisfMonolithicFileHeader.ColorSpace.GRAY byteOrder shouldBe ByteOrder.LITTLE compressionFormat.shouldNotBeNull().type shouldBe XisfMonolithicFileHeader.CompressionType.LZ4_HC - keywords shouldHaveSize 29 + keywords shouldHaveSize 17 } } "read:8:gray:zstd" { @@ -88,7 +88,7 @@ class XisfHeaderInputStreamTest : FitsStringSpec() { colorSpace shouldBe XisfMonolithicFileHeader.ColorSpace.GRAY byteOrder shouldBe ByteOrder.LITTLE compressionFormat.shouldNotBeNull().type shouldBe XisfMonolithicFileHeader.CompressionType.ZSTD - keywords shouldHaveSize 29 + keywords shouldHaveSize 17 } } "read:16:gray" { @@ -103,7 +103,7 @@ class XisfHeaderInputStreamTest : FitsStringSpec() { sampleFormat shouldBe XisfMonolithicFileHeader.SampleFormat.UINT16 colorSpace shouldBe XisfMonolithicFileHeader.ColorSpace.GRAY byteOrder shouldBe ByteOrder.LITTLE - keywords shouldHaveSize 29 + keywords shouldHaveSize 17 } } "read:32:gray" { @@ -118,7 +118,7 @@ class XisfHeaderInputStreamTest : FitsStringSpec() { sampleFormat shouldBe XisfMonolithicFileHeader.SampleFormat.UINT32 colorSpace shouldBe XisfMonolithicFileHeader.ColorSpace.GRAY byteOrder shouldBe ByteOrder.LITTLE - keywords shouldHaveSize 29 + keywords shouldHaveSize 17 } } "read:F32:gray" { @@ -133,7 +133,7 @@ class XisfHeaderInputStreamTest : FitsStringSpec() { sampleFormat shouldBe XisfMonolithicFileHeader.SampleFormat.FLOAT32 colorSpace shouldBe XisfMonolithicFileHeader.ColorSpace.GRAY byteOrder shouldBe ByteOrder.LITTLE - keywords shouldHaveSize 29 + keywords shouldHaveSize 17 } } "read:F64:gray" { @@ -148,7 +148,7 @@ class XisfHeaderInputStreamTest : FitsStringSpec() { sampleFormat shouldBe XisfMonolithicFileHeader.SampleFormat.FLOAT64 colorSpace shouldBe XisfMonolithicFileHeader.ColorSpace.GRAY byteOrder shouldBe ByteOrder.LITTLE - keywords shouldHaveSize 29 + keywords shouldHaveSize 17 } } "read:8:rgb" { @@ -163,7 +163,7 @@ class XisfHeaderInputStreamTest : FitsStringSpec() { sampleFormat shouldBe XisfMonolithicFileHeader.SampleFormat.UINT8 colorSpace shouldBe XisfMonolithicFileHeader.ColorSpace.RGB byteOrder shouldBe ByteOrder.LITTLE - keywords shouldHaveSize 29 + keywords shouldHaveSize 17 } } "read:16:rgb" { @@ -178,7 +178,7 @@ class XisfHeaderInputStreamTest : FitsStringSpec() { sampleFormat shouldBe XisfMonolithicFileHeader.SampleFormat.UINT16 colorSpace shouldBe XisfMonolithicFileHeader.ColorSpace.RGB byteOrder shouldBe ByteOrder.LITTLE - keywords shouldHaveSize 29 + keywords shouldHaveSize 17 } } "read:32:rgb" { @@ -193,7 +193,7 @@ class XisfHeaderInputStreamTest : FitsStringSpec() { sampleFormat shouldBe XisfMonolithicFileHeader.SampleFormat.UINT32 colorSpace shouldBe XisfMonolithicFileHeader.ColorSpace.RGB byteOrder shouldBe ByteOrder.LITTLE - keywords shouldHaveSize 29 + keywords shouldHaveSize 17 } } "read:F32:rgb" { @@ -208,7 +208,7 @@ class XisfHeaderInputStreamTest : FitsStringSpec() { sampleFormat shouldBe XisfMonolithicFileHeader.SampleFormat.FLOAT32 colorSpace shouldBe XisfMonolithicFileHeader.ColorSpace.RGB byteOrder shouldBe ByteOrder.LITTLE - keywords shouldHaveSize 29 + keywords shouldHaveSize 17 } } "read:F64:rgb" { @@ -223,7 +223,7 @@ class XisfHeaderInputStreamTest : FitsStringSpec() { sampleFormat shouldBe XisfMonolithicFileHeader.SampleFormat.FLOAT64 colorSpace shouldBe XisfMonolithicFileHeader.ColorSpace.RGB byteOrder shouldBe ByteOrder.LITTLE - keywords shouldHaveSize 29 + keywords shouldHaveSize 17 } } } diff --git a/nebulosa-xml/src/main/kotlin/nebulosa/xml/XmlHelper.kt b/nebulosa-xml/src/main/kotlin/nebulosa/xml/XmlHelper.kt index a3e9eb174..db8c4e2ef 100644 --- a/nebulosa-xml/src/main/kotlin/nebulosa/xml/XmlHelper.kt +++ b/nebulosa-xml/src/main/kotlin/nebulosa/xml/XmlHelper.kt @@ -11,3 +11,22 @@ fun XMLStreamReader.attribute(name: String): String? { return null } + +private val XML_ESCAPE_CHARS = charArrayOf('"', '&', '<', '>') +private val XML_ESCAPE_CHAR_CODES = arrayOf(""", "&", "<", ">") + +fun String.escapeXml(): String { + if (none { it in XML_ESCAPE_CHARS }) return this + + return buildString(length) { + for (c in this) { + val index = XML_ESCAPE_CHARS.indexOf(c) + + if (index >= 0) { + append(XML_ESCAPE_CHAR_CODES[index]) + } else { + append(c) + } + } + } +} From 2e18a9fd72a9a64d84fcdb0a033bb64a345d268e Mon Sep 17 00:00:00 2001 From: tiagohm Date: Mon, 1 Apr 2024 09:02:45 -0300 Subject: [PATCH 13/15] [api][desktop]: Implement save as XISF --- .../kotlin/nebulosa/api/image/ImageService.kt | 27 +- .../src/shared/services/electron.service.ts | 11 +- .../main/kotlin/nebulosa/fits/FitsFormat.kt | 22 +- .../main/kotlin/nebulosa/fits/FitsHeader.kt | 3 + .../kotlin/nebulosa/fits/FitsHeaderCard.kt | 14 +- nebulosa-fits/src/test/kotlin/FitsReadTest.kt | 20 +- .../src/test/kotlin/FitsWriteTest.kt | 2 +- .../nebulosa/image/format/WritableHeader.kt | 2 + .../test/kotlin/ComputationAlgorithmTest.kt | 8 +- .../test/kotlin/FitsTransformAlgorithmTest.kt | 106 ++++---- nebulosa-io/src/main/kotlin/nebulosa/io/Io.kt | 19 +- .../kotlin/nebulosa/test/FitsStringSpec.kt | 23 +- .../src/test/kotlin/WatneyStarDetectorTest.kt | 2 +- .../main/kotlin/nebulosa/xisf/XisfFormat.kt | 177 +++++++++----- .../nebulosa/xisf/XisfHeaderInputStream.kt | 16 +- .../nebulosa/xisf/XisfMonolithicFileHeader.kt | 34 ++- .../xisf/XisfMonolithicFileHeaderImageData.kt | 14 +- .../xisf/XisfMonolithicFileHeaderImageHdu.kt | 2 +- .../src/test/kotlin/XisfFormatTest.kt | 230 ++++++++++++++---- .../test/kotlin/XisfHeaderInputStreamTest.kt | 28 +-- 20 files changed, 490 insertions(+), 270 deletions(-) diff --git a/api/src/main/kotlin/nebulosa/api/image/ImageService.kt b/api/src/main/kotlin/nebulosa/api/image/ImageService.kt index 6f610b4be..216841c87 100644 --- a/api/src/main/kotlin/nebulosa/api/image/ImageService.kt +++ b/api/src/main/kotlin/nebulosa/api/image/ImageService.kt @@ -14,7 +14,6 @@ import nebulosa.image.algorithms.computation.Statistics import nebulosa.image.algorithms.transformation.* import nebulosa.image.format.ImageChannel import nebulosa.indi.device.camera.Camera -import nebulosa.io.transferAndClose import nebulosa.log.debug import nebulosa.log.loggerFor import nebulosa.math.* @@ -29,6 +28,8 @@ import nebulosa.time.TimeYMDHMS import nebulosa.time.UTC import nebulosa.wcs.WCS import nebulosa.wcs.WCSException +import nebulosa.xisf.XisfFormat +import okio.sink import org.springframework.http.HttpStatus import org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor import org.springframework.stereotype.Service @@ -40,7 +41,6 @@ import java.util.* import java.util.concurrent.CompletableFuture import javax.imageio.ImageIO import kotlin.io.path.extension -import kotlin.io.path.inputStream import kotlin.io.path.outputStream @Service @@ -81,8 +81,8 @@ class ImageService( var stretchParams = ScreenTransformFunction.Parameters(midtone, shadow, highlight) val shouldBeTransformed = autoStretch || manualStretch - || mirrorHorizontal || mirrorVertical || invert - || scnrEnabled + || mirrorHorizontal || mirrorVertical || invert + || scnrEnabled var transformedImage = if (shouldBeTransformed) image.clone() else image val instrument = camera?.name ?: image.header.instrument @@ -246,16 +246,15 @@ class ImageService( fun saveImageAs(inputPath: Path, outputPath: Path) { if (inputPath != outputPath) { - if (inputPath.extension == outputPath.extension) { - inputPath.inputStream().transferAndClose(outputPath.outputStream()) - } else { - val image = imageBucket[inputPath]?.first ?: return - - when (outputPath.extension.uppercase()) { - "PNG" -> outputPath.outputStream().use { ImageIO.write(image, "PNG", it) } - "JPG", "JPEG" -> outputPath.outputStream().use { ImageIO.write(image, "JPEG", it) } - else -> throw ResponseStatusException(HttpStatus.BAD_REQUEST, "Invalid format") - } + val image = imageBucket[inputPath]?.first + ?: throw ResponseStatusException(HttpStatus.NOT_FOUND, "Image not found") + + when (outputPath.extension.uppercase()) { + "PNG" -> outputPath.outputStream().use { ImageIO.write(image, "PNG", it) } + "JPG", "JPEG" -> outputPath.outputStream().use { ImageIO.write(image, "JPEG", it) } + "FIT", "FITS" -> outputPath.sink().use { image.writeTo(it, FitsFormat) } + "XISF" -> outputPath.sink().use { image.writeTo(it, XisfFormat) } + else -> throw ResponseStatusException(HttpStatus.BAD_REQUEST, "Invalid format") } } } diff --git a/desktop/src/shared/services/electron.service.ts b/desktop/src/shared/services/electron.service.ts index 0c7ae92de..44b79941e 100644 --- a/desktop/src/shared/services/electron.service.ts +++ b/desktop/src/shared/services/electron.service.ts @@ -113,8 +113,9 @@ export class ElectronService { openFits(data?: OpenFile): Promise { return this.openFile({ ...data, filters: [ - { name: 'FITS files', extensions: ['fits', 'fit'] }, - { name: 'XISF files', extensions: ['xisf'] }, + { name: 'All', extensions: ['fits', 'fit', 'xisf'] }, + { name: 'FITS', extensions: ['fits', 'fit'] }, + { name: 'XISF', extensions: ['xisf'] }, ] }) } @@ -123,8 +124,10 @@ export class ElectronService { return this.saveFile({ ...data, filters: [ - { name: 'FITS files', extensions: ['fits', 'fit'] }, - { name: 'Image files', extensions: ['png', 'jpe?g'] }, + { name: 'All', extensions: ['fits', 'fit', 'xisf', 'png', 'jpe?g'] }, + { name: 'FITS', extensions: ['fits', 'fit'] }, + { name: 'XISF', extensions: ['xisf'] }, + { name: 'Image', extensions: ['png', 'jpe?g'] }, ] }) } diff --git a/nebulosa-fits/src/main/kotlin/nebulosa/fits/FitsFormat.kt b/nebulosa-fits/src/main/kotlin/nebulosa/fits/FitsFormat.kt index f10ca0cf3..0b9cf274c 100644 --- a/nebulosa-fits/src/main/kotlin/nebulosa/fits/FitsFormat.kt +++ b/nebulosa-fits/src/main/kotlin/nebulosa/fits/FitsFormat.kt @@ -149,25 +149,27 @@ data object FitsFormat : ImageFormat { } } + @JvmStatic internal fun Buffer.readPixel(bitpix: Bitpix): Float { return when (bitpix) { - Bitpix.BYTE -> (buffer.readByte().toInt() and 0xFF) / 255f - Bitpix.SHORT -> (buffer.readShort().toInt() + 32768) / 65535f - Bitpix.INTEGER -> ((buffer.readInt().toLong() + 2147483648L) / 4294967295.0).toFloat() + Bitpix.BYTE -> (readByte().toInt() and 0xFF) / 255f + Bitpix.SHORT -> (readShort().toInt() + 32768) / 65535f + Bitpix.INTEGER -> ((readInt().toLong() + 2147483648L) / 4294967295.0).toFloat() Bitpix.LONG -> TODO("Unsupported UInt64 sample format") - Bitpix.FLOAT -> buffer.readFloat() - Bitpix.DOUBLE -> buffer.readDouble().toFloat() + Bitpix.FLOAT -> readFloat() + Bitpix.DOUBLE -> readDouble().toFloat() } } + @JvmStatic internal fun Buffer.writePixel(pixel: Float, bitpix: Bitpix) { when (bitpix) { - Bitpix.BYTE -> buffer.writeByte((pixel * 255f).toInt()) - Bitpix.SHORT -> buffer.writeShort((pixel * 65535f).toInt()) - Bitpix.INTEGER -> buffer.writeInt((pixel * 4294967295.0).toInt()) + Bitpix.BYTE -> writeByte((pixel * 255f).toInt()) + Bitpix.SHORT -> writeShort((pixel * 65535f).toInt()) + Bitpix.INTEGER -> writeInt((pixel * 4294967295.0).toInt()) Bitpix.LONG -> TODO("Unsupported UInt64 sample format") - Bitpix.FLOAT -> buffer.writeFloat(pixel) - Bitpix.DOUBLE -> buffer.writeDouble(pixel.toDouble()) + Bitpix.FLOAT -> writeFloat(pixel) + Bitpix.DOUBLE -> writeDouble(pixel.toDouble()) } } diff --git a/nebulosa-fits/src/main/kotlin/nebulosa/fits/FitsHeader.kt b/nebulosa-fits/src/main/kotlin/nebulosa/fits/FitsHeader.kt index 99267a3df..994041e49 100644 --- a/nebulosa-fits/src/main/kotlin/nebulosa/fits/FitsHeader.kt +++ b/nebulosa-fits/src/main/kotlin/nebulosa/fits/FitsHeader.kt @@ -89,6 +89,8 @@ open class FitsHeader : AbstractHeader { final override fun add(card: HeaderCard) = Unit + final override fun addAll(cards: Iterable) = Unit + final override fun delete(key: HeaderKey) = false final override fun delete(key: String) = false @@ -102,6 +104,7 @@ open class FitsHeader : AbstractHeader { const val MIN_COMMENT_ALIGN = 20 const val MAX_COMMENT_ALIGN = 70 + @JvmStatic val EMPTY = ReadOnly() @JvmStatic private val LOG = loggerFor() var commentAlignPosition = DEFAULT_COMMENT_ALIGN diff --git a/nebulosa-fits/src/main/kotlin/nebulosa/fits/FitsHeaderCard.kt b/nebulosa-fits/src/main/kotlin/nebulosa/fits/FitsHeaderCard.kt index c4571dc62..9f2d7f8da 100644 --- a/nebulosa-fits/src/main/kotlin/nebulosa/fits/FitsHeaderCard.kt +++ b/nebulosa-fits/src/main/kotlin/nebulosa/fits/FitsHeaderCard.kt @@ -56,7 +56,9 @@ data class FitsHeaderCard( const val MAX_LONG_STRING_CONTINUE_OVERHEAD = 3 const val HIERARCH_WITH_DOT = "HIERARCH." + @JvmStatic val SIMPLE = create(FitsKeyword.SIMPLE, true) @JvmStatic val END = FitsHeaderCard("END", "", "", FitsHeaderCardType.NONE) + @JvmStatic val EXTENDED = create(FitsKeyword.EXTEND, true) @JvmStatic fun from(source: Buffer): FitsHeaderCard { @@ -75,32 +77,32 @@ data class FitsHeaderCard( @JvmStatic fun create(header: HeaderKey, value: Int): FitsHeaderCard { - return create(header.key, "$value", header.comment) + return create(header.key, value, header.comment) } @JvmStatic fun create(header: HeaderKey, value: Long): FitsHeaderCard { - return create(header.key, "$value", header.comment) + return create(header.key, value, header.comment) } @JvmStatic fun create(header: HeaderKey, value: BigInteger): FitsHeaderCard { - return create(header.key, "$value", header.comment) + return create(header.key, value, header.comment) } @JvmStatic fun create(header: HeaderKey, value: Float): FitsHeaderCard { - return create(header.key, "$value", header.comment) + return create(header.key, value, header.comment) } @JvmStatic fun create(header: HeaderKey, value: Double): FitsHeaderCard { - return create(header.key, "$value", header.comment) + return create(header.key, value, header.comment) } @JvmStatic fun create(key: HeaderKey, value: BigDecimal, comment: String = ""): FitsHeaderCard { - return create(key.key, "$value", comment) + return create(key.key, value, comment) } @JvmStatic diff --git a/nebulosa-fits/src/test/kotlin/FitsReadTest.kt b/nebulosa-fits/src/test/kotlin/FitsReadTest.kt index 6ae8b3ec1..a1685a3f3 100644 --- a/nebulosa-fits/src/test/kotlin/FitsReadTest.kt +++ b/nebulosa-fits/src/test/kotlin/FitsReadTest.kt @@ -10,70 +10,70 @@ class FitsReadTest : FitsStringSpec() { init { "mono:8-bit" { - val hdu = NGC3344_MONO_8_FITS_PATH.fits().filterIsInstance().first() + val hdu = NGC3344_MONO_8_FITS.fits().filterIsInstance().first() hdu.width shouldBeExactly 256 hdu.height shouldBeExactly 256 hdu.numberOfChannels shouldBeExactly 1 hdu.header.bitpix shouldBe Bitpix.BYTE } "mono:16-bit" { - val hdu = NGC3344_MONO_16_FITS_PATH.fits().filterIsInstance().first() + val hdu = NGC3344_MONO_16_FITS.fits().filterIsInstance().first() hdu.width shouldBeExactly 256 hdu.height shouldBeExactly 256 hdu.numberOfChannels shouldBeExactly 1 hdu.header.bitpix shouldBe Bitpix.SHORT } "mono:32-bit" { - val hdu = NGC3344_MONO_32_FITS_PATH.fits().filterIsInstance().first() + val hdu = NGC3344_MONO_32_FITS.fits().filterIsInstance().first() hdu.width shouldBeExactly 256 hdu.height shouldBeExactly 256 hdu.numberOfChannels shouldBeExactly 1 hdu.header.bitpix shouldBe Bitpix.INTEGER } "mono:32-bit floating-point" { - val hdu = NGC3344_MONO_F32_FITS_PATH.fits().filterIsInstance().first() + val hdu = NGC3344_MONO_F32_FITS.fits().filterIsInstance().first() hdu.width shouldBeExactly 256 hdu.height shouldBeExactly 256 hdu.numberOfChannels shouldBeExactly 1 hdu.header.bitpix shouldBe Bitpix.FLOAT } "mono:64-bit floating-point" { - val hdu = NGC3344_MONO_F64_FITS_PATH.fits().filterIsInstance().first() + val hdu = NGC3344_MONO_F64_FITS.fits().filterIsInstance().first() hdu.width shouldBeExactly 256 hdu.height shouldBeExactly 256 hdu.numberOfChannels shouldBeExactly 1 hdu.header.bitpix shouldBe Bitpix.DOUBLE } "color:8-bit" { - val hdu = NGC3344_COLOR_8_FITS_PATH.fits().filterIsInstance().first() + val hdu = NGC3344_COLOR_8_FITS.fits().filterIsInstance().first() hdu.width shouldBeExactly 256 hdu.height shouldBeExactly 256 hdu.numberOfChannels shouldBeExactly 4 hdu.header.bitpix shouldBe Bitpix.BYTE } "color:16-bit" { - val hdu = NGC3344_COLOR_16_FITS_PATH.fits().filterIsInstance().first() + val hdu = NGC3344_COLOR_16_FITS.fits().filterIsInstance().first() hdu.width shouldBeExactly 256 hdu.height shouldBeExactly 256 hdu.numberOfChannels shouldBeExactly 4 hdu.header.bitpix shouldBe Bitpix.SHORT } "color:32-bit" { - val hdu = NGC3344_COLOR_32_FITS_PATH.fits().filterIsInstance().first() + val hdu = NGC3344_COLOR_32_FITS.fits().filterIsInstance().first() hdu.width shouldBeExactly 256 hdu.height shouldBeExactly 256 hdu.numberOfChannels shouldBeExactly 4 hdu.header.bitpix shouldBe Bitpix.INTEGER } "color:32-bit floating-point" { - val hdu = NGC3344_COLOR_F32_FITS_PATH.fits().filterIsInstance().first() + val hdu = NGC3344_COLOR_F32_FITS.fits().filterIsInstance().first() hdu.width shouldBeExactly 256 hdu.height shouldBeExactly 256 hdu.numberOfChannels shouldBeExactly 4 hdu.header.bitpix shouldBe Bitpix.FLOAT } "color:64-bit floating-point" { - val hdu = NGC3344_COLOR_F64_FITS_PATH.fits().filterIsInstance().first() + val hdu = NGC3344_COLOR_F64_FITS.fits().filterIsInstance().first() hdu.width shouldBeExactly 256 hdu.height shouldBeExactly 256 hdu.numberOfChannels shouldBeExactly 4 diff --git a/nebulosa-fits/src/test/kotlin/FitsWriteTest.kt b/nebulosa-fits/src/test/kotlin/FitsWriteTest.kt index fd975c448..0e2f60cd2 100644 --- a/nebulosa-fits/src/test/kotlin/FitsWriteTest.kt +++ b/nebulosa-fits/src/test/kotlin/FitsWriteTest.kt @@ -11,7 +11,7 @@ class FitsWriteTest : FitsStringSpec() { init { "mono" { - val hdu0 = NGC3344_MONO_8_FITS_PATH.fits().filterIsInstance().first() + val hdu0 = NGC3344_MONO_8_FITS.fits().filterIsInstance().first() val data = ByteArray(69120) FitsFormat.write(data.sink(), listOf(hdu0)) data.toByteString(2880, 66240).md5().hex() shouldBe "e1735e21c94dc49885fabc429406e573" diff --git a/nebulosa-image-format/src/main/kotlin/nebulosa/image/format/WritableHeader.kt b/nebulosa-image-format/src/main/kotlin/nebulosa/image/format/WritableHeader.kt index deb3515cd..aaf1a1078 100644 --- a/nebulosa-image-format/src/main/kotlin/nebulosa/image/format/WritableHeader.kt +++ b/nebulosa-image-format/src/main/kotlin/nebulosa/image/format/WritableHeader.kt @@ -22,6 +22,8 @@ interface WritableHeader { fun add(card: HeaderCard) + fun addAll(cards: Iterable) = cards.forEach(::add) + fun delete(key: HeaderKey) = delete(key.key) fun delete(key: String): Boolean diff --git a/nebulosa-image/src/test/kotlin/ComputationAlgorithmTest.kt b/nebulosa-image/src/test/kotlin/ComputationAlgorithmTest.kt index 016f65b56..76566dc9e 100644 --- a/nebulosa-image/src/test/kotlin/ComputationAlgorithmTest.kt +++ b/nebulosa-image/src/test/kotlin/ComputationAlgorithmTest.kt @@ -13,11 +13,11 @@ class ComputationAlgorithmTest : FitsStringSpec() { init { "mono:median absolute deviation" { - val mImage = Image.open(NGC3344_MONO_F32_FITS_PATH.fits()) + val mImage = Image.open(NGC3344_MONO_F32_FITS.fits()) mImage.compute(MedianAbsoluteDeviation()) shouldBe (0.0862f plusOrMinus 1e-4f) } "mono:statistics" { - val mImage = Image.open(NGC3344_MONO_F32_FITS_PATH.fits()) + val mImage = Image.open(NGC3344_MONO_F32_FITS.fits()) val statistics = mImage.compute(Statistics.GRAY) statistics.count shouldBeExactly 65536 @@ -32,13 +32,13 @@ class ComputationAlgorithmTest : FitsStringSpec() { statistics.maximum shouldBeExactly 1f } "color:median absolute deviation" { - val cImage = Image.open(NGC3344_COLOR_F32_FITS_PATH.fits()) + val cImage = Image.open(NGC3344_COLOR_F32_FITS.fits()) cImage.compute(MedianAbsoluteDeviation(channel = ImageChannel.RED)) shouldBe (0.0823f plusOrMinus 1e-4f) cImage.compute(MedianAbsoluteDeviation(channel = ImageChannel.GREEN)) shouldBe (0.0745f plusOrMinus 1e-4f) cImage.compute(MedianAbsoluteDeviation(channel = ImageChannel.BLUE)) shouldBe (0.0705f plusOrMinus 1e-4f) } "color:statistics" { - val cImage = Image.open(NGC3344_COLOR_F32_FITS_PATH.fits()) + val cImage = Image.open(NGC3344_COLOR_F32_FITS.fits()) run { val statistics = cImage.compute(Statistics.RED) diff --git a/nebulosa-image/src/test/kotlin/FitsTransformAlgorithmTest.kt b/nebulosa-image/src/test/kotlin/FitsTransformAlgorithmTest.kt index 6f818f193..504a9cf05 100644 --- a/nebulosa-image/src/test/kotlin/FitsTransformAlgorithmTest.kt +++ b/nebulosa-image/src/test/kotlin/FitsTransformAlgorithmTest.kt @@ -15,26 +15,26 @@ class FitsTransformAlgorithmTest : FitsStringSpec() { init { "mono:raw" { - val mImage = Image.open(NGC3344_MONO_8_FITS_PATH.fits()) + val mImage = Image.open(NGC3344_MONO_8_FITS.fits()) mImage.save("fits-mono-raw").second shouldBe "e17cfc29c3b343409cd8617b6913330e" } "mono:vertical flip" { - val mImage = Image.open(NGC3344_MONO_8_FITS_PATH.fits()) + val mImage = Image.open(NGC3344_MONO_8_FITS.fits()) mImage.transform(VerticalFlip) mImage.save("fits-mono-vertical-flip").second shouldBe "262260dfe719726c0e7829a088279a21" } "mono:horizontal flip" { - val mImage = Image.open(NGC3344_MONO_8_FITS_PATH.fits()) + val mImage = Image.open(NGC3344_MONO_8_FITS.fits()) mImage.transform(HorizontalFlip) mImage.save("fits-mono-horizontal-flip").second shouldBe "daf0f05db5de3750962f338527564b27" } "mono:vertical & horizontal flip" { - val mImage = Image.open(NGC3344_MONO_8_FITS_PATH.fits()) + val mImage = Image.open(NGC3344_MONO_8_FITS.fits()) mImage.transform(VerticalFlip, HorizontalFlip) mImage.save("fits-mono-vertical-horizontal-flip").second shouldBe "3bc81f579a0e34ce9312c3b242209166" } "mono:subframe" { - val mImage = Image.open(NGC3344_MONO_8_FITS_PATH.fits()) + val mImage = Image.open(NGC3344_MONO_8_FITS.fits()) val nImage = mImage.transform(SubFrame(45, 70, 16, 16)) nImage.width shouldBeExactly 16 nImage.height shouldBeExactly 16 @@ -42,115 +42,115 @@ class FitsTransformAlgorithmTest : FitsStringSpec() { nImage.save("fits-mono-subframe").second shouldBe "4d9984e778f82dde10b9aeeee7a29fe0" } "mono:sharpen" { - val mImage = Image.open(NGC3344_MONO_8_FITS_PATH.fits()) + val mImage = Image.open(NGC3344_MONO_8_FITS.fits()) mImage.transform(Sharpen) mImage.save("fits-mono-sharpen").second shouldBe "0b162242a4e673f6480b5206cf49ca50" } "mono:mean" { - val mImage = Image.open(NGC3344_MONO_8_FITS_PATH.fits()) + val mImage = Image.open(NGC3344_MONO_8_FITS.fits()) mImage.transform(Mean) mImage.save("fits-mono-mean").second shouldBe "cf866292f657c379ae3965931dd8eeea" } "mono:invert" { - val mImage = Image.open(NGC3344_MONO_8_FITS_PATH.fits()) + val mImage = Image.open(NGC3344_MONO_8_FITS.fits()) mImage.transform(Invert) mImage.save("fits-mono-invert").second shouldBe "6e94463bb5b9561de1f0ee0a154db53e" } "mono:emboss" { - val mImage = Image.open(NGC3344_MONO_8_FITS_PATH.fits()) + val mImage = Image.open(NGC3344_MONO_8_FITS.fits()) mImage.transform(Emboss) mImage.save("fits-mono-emboss").second shouldBe "94a8ef5e4573e392d087cf10c905ba12" } "mono:edges" { - val mImage = Image.open(NGC3344_MONO_8_FITS_PATH.fits()) + val mImage = Image.open(NGC3344_MONO_8_FITS.fits()) mImage.transform(Edges) mImage.save("fits-mono-edges").second shouldBe "27ccd5f5e6098d0cae27e7495e18dd72" } "mono:blur" { - val mImage = Image.open(NGC3344_MONO_8_FITS_PATH.fits()) + val mImage = Image.open(NGC3344_MONO_8_FITS.fits()) mImage.transform(Blur) mImage.save("fits-mono-blur").second shouldBe "f2c5466dccf71b5c4bee86c5fbbb95fc" } "mono:gaussian blur" { - val mImage = Image.open(NGC3344_MONO_8_FITS_PATH.fits()) + val mImage = Image.open(NGC3344_MONO_8_FITS.fits()) mImage.transform(GaussianBlur(sigma = 5.0, size = 9)) mImage.save("fits-mono-gaussian-blur").second shouldBe "69057b0c4461fb0d55b779da9e72fd69" } "mono:STF:midtone = 0.1, shadow = 0.0, highlight = 1.0" { - val mImage = Image.open(NGC3344_MONO_8_FITS_PATH.fits()) + val mImage = Image.open(NGC3344_MONO_8_FITS.fits()) mImage.transform(ScreenTransformFunction(0.1f)) mImage.save("fits-mono-stf-01-00-10").second shouldBe "22c0bd985e70a01330722d912869d6ee" } "mono:STF:midtone = 0.9, shadow = 0.0, highlight = 1.0" { - val mImage = Image.open(NGC3344_MONO_8_FITS_PATH.fits()) + val mImage = Image.open(NGC3344_MONO_8_FITS.fits()) mImage.transform(ScreenTransformFunction(0.9f)) mImage.save("fits-mono-stf-09-00-10").second shouldBe "553ccb7546dce3a8f742d5e8f7c58a3f" } "mono:STF:midtone = 0.1, shadow = 0.5, highlight = 1.0" { - val mImage = Image.open(NGC3344_MONO_8_FITS_PATH.fits()) + val mImage = Image.open(NGC3344_MONO_8_FITS.fits()) mImage.transform(ScreenTransformFunction(0.1f, shadow = 0.5f)) mImage.save("fits-mono-stf-01-05-10").second shouldBe "f31db854fab72033dce2f8c572ec6783" } "mono:STF:midtone = 0.9, shadow = 0.5, highlight = 1.0" { - val mImage = Image.open(NGC3344_MONO_8_FITS_PATH.fits()) + val mImage = Image.open(NGC3344_MONO_8_FITS.fits()) mImage.transform(ScreenTransformFunction(0.9f, shadow = 0.5f)) mImage.save("fits-mono-stf-09-05-10").second shouldBe "633b49c4a1dbb5ad8e6a9d74f330636d" } "mono:STF:midtone = 0.1, shadow = 0.0, highlight = 0.5" { - val mImage = Image.open(NGC3344_MONO_8_FITS_PATH.fits()) + val mImage = Image.open(NGC3344_MONO_8_FITS.fits()) mImage.transform(ScreenTransformFunction(0.1f, highlight = 0.5f)) mImage.save("fits-mono-stf-01-00-05").second shouldBe "26036937eb3e5f99cd6129f709ce4b31" } "mono:STF:midtone = 0.9, shadow = 0.0, highlight = 0.5" { - val mImage = Image.open(NGC3344_MONO_8_FITS_PATH.fits()) + val mImage = Image.open(NGC3344_MONO_8_FITS.fits()) mImage.transform(ScreenTransformFunction(0.9f, highlight = 0.5f)) mImage.save("fits-mono-stf-09-00-05").second shouldBe "e8f694dae666ac15ce2f8a169eb84024" } "mono:STF:midtone = 0.1, shadow = 0.4, highlight = 0.6" { - val mImage = Image.open(NGC3344_MONO_8_FITS_PATH.fits()) + val mImage = Image.open(NGC3344_MONO_8_FITS.fits()) mImage.transform(ScreenTransformFunction(0.1f, 0.4f, 0.6f)) mImage.save("fits-mono-stf-01-04-06").second shouldBe "5226aba21669a24f985703b3e7220568" } "mono:STF:midtone = 0.9, shadow = 0.4, highlight = 0.6" { - val mImage = Image.open(NGC3344_MONO_8_FITS_PATH.fits()) + val mImage = Image.open(NGC3344_MONO_8_FITS.fits()) mImage.transform(ScreenTransformFunction(0.9f, 0.4f, 0.6f)) mImage.save("fits-mono-stf-09-04-06").second shouldBe "c2acb25ef7be92a51f63e673ec9a850f" } "mono:auto STF" { - val mImage = Image.open(NGC3344_MONO_8_FITS_PATH.fits()) + val mImage = Image.open(NGC3344_MONO_8_FITS.fits()) mImage.transform(AutoScreenTransformFunction) mImage.save("fits-mono-auto-stf").second shouldBe "e17cfc29c3b343409cd8617b6913330e" } "!mono:reload" { - val mImage0 = Image.open(NGC3344_MONO_8_FITS_PATH.fits()) + val mImage0 = Image.open(NGC3344_MONO_8_FITS.fits()) - val mImage1 = Image.open(NGC3344_MONO_8_FITS_PATH.fits()) + val mImage1 = Image.open(NGC3344_MONO_8_FITS.fits()) mImage1.transform(Invert) mImage0.load(mImage1.hdu) mImage0.save("fits-mono-reload").second shouldBe "6e94463bb5b9561de1f0ee0a154db53e" } "color:raw" { - val mImage = Image.open(NGC3344_COLOR_32_FITS_PATH.fits()) + val mImage = Image.open(NGC3344_COLOR_32_FITS.fits()) mImage.save("fits-color-raw").second shouldBe "18fb83e240bc7a4cbafbc1aba2741db6" } "color:vertical flip" { - val mImage = Image.open(NGC3344_COLOR_32_FITS_PATH.fits()) + val mImage = Image.open(NGC3344_COLOR_32_FITS.fits()) mImage.transform(VerticalFlip) mImage.save("fits-color-vertical-flip").second shouldBe "b717ecda5c5bba50cfa06304ef2bca88" } "color:horizontal flip" { - val mImage = Image.open(NGC3344_COLOR_32_FITS_PATH.fits()) + val mImage = Image.open(NGC3344_COLOR_32_FITS.fits()) mImage.transform(HorizontalFlip) mImage.save("fits-color-horizontal-flip").second shouldBe "f70228600c77551473008ed4b9986439" } "color:vertical & horizontal flip" { - val mImage = Image.open(NGC3344_COLOR_32_FITS_PATH.fits()) + val mImage = Image.open(NGC3344_COLOR_32_FITS.fits()) mImage.transform(VerticalFlip, HorizontalFlip) mImage.save("fits-color-vertical-horizontal-flip").second shouldBe "1237314044f20307b76203148af855e3" } "color:subframe" { - val mImage = Image.open(NGC3344_COLOR_32_FITS_PATH.fits()) + val mImage = Image.open(NGC3344_COLOR_32_FITS.fits()) val nImage = mImage.transform(SubFrame(45, 70, 16, 16)) nImage.width shouldBeExactly 16 nImage.height shouldBeExactly 16 @@ -158,122 +158,122 @@ class FitsTransformAlgorithmTest : FitsStringSpec() { nImage.save("fits-color-subframe").second shouldBe "282fc4fdf9142fcb4b18e1df1eef4caa" } "color:sharpen" { - val mImage = Image.open(NGC3344_COLOR_32_FITS_PATH.fits()) + val mImage = Image.open(NGC3344_COLOR_32_FITS.fits()) mImage.transform(Sharpen) mImage.save("fits-color-sharpen").second shouldBe "e562282bdafdeba6ce88981bb9c3ba61" } "color:mean" { - val mImage = Image.open(NGC3344_COLOR_32_FITS_PATH.fits()) + val mImage = Image.open(NGC3344_COLOR_32_FITS.fits()) mImage.transform(Mean) mImage.save("fits-color-mean").second shouldBe "a8380d928aaa756e202ba43bd3a2f207" } "color:invert" { - val mImage = Image.open(NGC3344_COLOR_32_FITS_PATH.fits()) + val mImage = Image.open(NGC3344_COLOR_32_FITS.fits()) mImage.transform(Invert) mImage.save("fits-color-invert").second shouldBe "decad269ec26450aebeaf7546867b5f8" } "color:emboss" { - val mImage = Image.open(NGC3344_COLOR_32_FITS_PATH.fits()) + val mImage = Image.open(NGC3344_COLOR_32_FITS.fits()) mImage.transform(Emboss) mImage.save("fits-color-emboss").second shouldBe "58d69250f1233055aa33f9ec7ca40af1" } "color:edges" { - val mImage = Image.open(NGC3344_COLOR_32_FITS_PATH.fits()) + val mImage = Image.open(NGC3344_COLOR_32_FITS.fits()) mImage.transform(Edges) mImage.save("fits-color-edges").second shouldBe "091f2955740a8edcd2401dc416d19d51" } "color:blur" { - val mImage = Image.open(NGC3344_COLOR_32_FITS_PATH.fits()) + val mImage = Image.open(NGC3344_COLOR_32_FITS.fits()) mImage.transform(Blur) mImage.save("fits-color-blur").second shouldBe "0fca440b763de5380fa29de736f3c792" } "color:gaussian blur" { - val mImage = Image.open(NGC3344_COLOR_32_FITS_PATH.fits()) + val mImage = Image.open(NGC3344_COLOR_32_FITS.fits()) mImage.transform(GaussianBlur(sigma = 5.0, size = 9)) mImage.save("fits-color-gaussian-blur").second shouldBe "394d1a4f136f15c802dd73004c421d64" } "color:STF:midtone = 0.1, shadow = 0.0, highlight = 1.0" { - val mImage = Image.open(NGC3344_COLOR_32_FITS_PATH.fits()) + val mImage = Image.open(NGC3344_COLOR_32_FITS.fits()) mImage.transform(ScreenTransformFunction(0.1f)) mImage.save("fits-color-stf-01-00-10").second shouldBe "e952bd263df6fd275b9a80aca554cb4b" } "color:STF:midtone = 0.9, shadow = 0.0, highlight = 1.0" { - val mImage = Image.open(NGC3344_COLOR_32_FITS_PATH.fits()) + val mImage = Image.open(NGC3344_COLOR_32_FITS.fits()) mImage.transform(ScreenTransformFunction(0.9f)) mImage.save("fits-color-stf-09-00-10").second shouldBe "038809d7612018e2e5c19d5e1f551abd" } "color:STF:midtone = 0.1, shadow = 0.5, highlight = 1.0" { - val mImage = Image.open(NGC3344_COLOR_32_FITS_PATH.fits()) + val mImage = Image.open(NGC3344_COLOR_32_FITS.fits()) mImage.transform(ScreenTransformFunction(0.1f, shadow = 0.5f)) mImage.save("fits-color-stf-01-05-10").second shouldBe "70e812260f56f8621002327575611f31" } "color:STF:midtone = 0.9, shadow = 0.5, highlight = 1.0" { - val mImage = Image.open(NGC3344_COLOR_32_FITS_PATH.fits()) + val mImage = Image.open(NGC3344_COLOR_32_FITS.fits()) mImage.transform(ScreenTransformFunction(0.9f, shadow = 0.5f)) mImage.save("fits-color-stf-09-05-10").second shouldBe "6ca400f617f466a9eb02a3a6f2985d99" } "color:STF:midtone = 0.1, shadow = 0.0, highlight = 0.5" { - val mImage = Image.open(NGC3344_COLOR_32_FITS_PATH.fits()) + val mImage = Image.open(NGC3344_COLOR_32_FITS.fits()) mImage.transform(ScreenTransformFunction(0.1f, highlight = 0.5f)) mImage.save("fits-color-stf-01-00-05").second shouldBe "3cd98ee9a8949d5100295acccd77010b" } "color:STF:midtone = 0.9, shadow = 0.0, highlight = 0.5" { - val mImage = Image.open(NGC3344_COLOR_32_FITS_PATH.fits()) + val mImage = Image.open(NGC3344_COLOR_32_FITS.fits()) mImage.transform(ScreenTransformFunction(0.9f, highlight = 0.5f)) mImage.save("fits-color-stf-09-00-05").second shouldBe "2cfeffc88c893cc5883d8a2221f29b91" } "color:STF:midtone = 0.1, shadow = 0.4, highlight = 0.6" { - val mImage = Image.open(NGC3344_COLOR_32_FITS_PATH.fits()) + val mImage = Image.open(NGC3344_COLOR_32_FITS.fits()) mImage.transform(ScreenTransformFunction(0.1f, 0.4f, 0.6f)) mImage.save("fits-color-stf-01-04-06").second shouldBe "532a07a1a166eb007c2e40651aec2097" } "color:STF:midtone = 0.9, shadow = 0.4, highlight = 0.6" { - val mImage = Image.open(NGC3344_COLOR_32_FITS_PATH.fits()) + val mImage = Image.open(NGC3344_COLOR_32_FITS.fits()) mImage.transform(ScreenTransformFunction(0.9f, 0.4f, 0.6f)) mImage.save("fits-color-stf-09-04-06").second shouldBe "eb3d940d9fd2c8814e930715e89897c4" } "color:auto STF" { - val mImage = Image.open(NGC3344_COLOR_32_FITS_PATH.fits()) + val mImage = Image.open(NGC3344_COLOR_32_FITS.fits()) mImage.transform(AutoScreenTransformFunction) mImage.save("fits-color-auto-stf").second shouldBe "a9c3657d8597b927607eb438e666d3a0" } "color:SCNR Maximum Mask" { - val mImage = Image.open(NGC3344_COLOR_32_FITS_PATH.fits()) + val mImage = Image.open(NGC3344_COLOR_32_FITS.fits()) mImage.transform(SubtractiveChromaticNoiseReduction(ImageChannel.RED, 1f, ProtectionMethod.MAXIMUM_MASK)) mImage.save("fits-color-scnr-maximum-mask").second shouldBe "e7d2155e18ff1e3172f4e849ae983145" } "color:SCNR Additive Mask" { - val mImage = Image.open(NGC3344_COLOR_32_FITS_PATH.fits()) + val mImage = Image.open(NGC3344_COLOR_32_FITS.fits()) mImage.transform(SubtractiveChromaticNoiseReduction(ImageChannel.RED, 1f, ProtectionMethod.ADDITIVE_MASK)) mImage.save("fits-color-scnr-additive-mask").second shouldBe "a458c44cedcda704de16d80053fd87eb" } "color:SCNR Average Neutral" { - val mImage = Image.open(NGC3344_COLOR_32_FITS_PATH.fits()) + val mImage = Image.open(NGC3344_COLOR_32_FITS.fits()) mImage.transform(SubtractiveChromaticNoiseReduction(ImageChannel.RED, 1f, ProtectionMethod.AVERAGE_NEUTRAL)) mImage.save("fits-color-scnr-average-neutral").second shouldBe "e07345ffc4982a62301c95c76d3efb35" } "color:SCNR Maximum Neutral" { - val mImage = Image.open(NGC3344_COLOR_32_FITS_PATH.fits()) + val mImage = Image.open(NGC3344_COLOR_32_FITS.fits()) mImage.transform(SubtractiveChromaticNoiseReduction(ImageChannel.RED, 1f, ProtectionMethod.MAXIMUM_NEUTRAL)) mImage.save("fits-color-scnr-maximum-neutral").second shouldBe "a1d4b04f57b001ba4a996bab0407fd7e" } "color:SCNR Minimum Neutral" { - val mImage = Image.open(NGC3344_COLOR_32_FITS_PATH.fits()) + val mImage = Image.open(NGC3344_COLOR_32_FITS.fits()) mImage.transform(SubtractiveChromaticNoiseReduction(ImageChannel.RED, 1f, ProtectionMethod.MINIMUM_NEUTRAL)) mImage.save("fits-color-scnr-minimum-neutral").second shouldBe "8b7be57ff38da9c97b35d7888047c0f9" } "color:grayscale BT-709" { - val mImage = Image.open(NGC3344_COLOR_32_FITS_PATH.fits()) + val mImage = Image.open(NGC3344_COLOR_32_FITS.fits()) val nImage = mImage.transform(Grayscale.BT709) nImage.save("fits-color-grayscale-bt709").second shouldBe "cab675aa35390a2d58cd48555d91054f" } "color:grayscale RMY" { - val mImage = Image.open(NGC3344_COLOR_32_FITS_PATH.fits()) + val mImage = Image.open(NGC3344_COLOR_32_FITS.fits()) val nImage = mImage.transform(Grayscale.RMY) nImage.save("fits-color-grayscale-rmy").second shouldBe "e113627002a4178d1010a2f6246e325f" } "color:grayscale Y" { - val mImage = Image.open(NGC3344_COLOR_32_FITS_PATH.fits()) + val mImage = Image.open(NGC3344_COLOR_32_FITS.fits()) val nImage = mImage.transform(Grayscale.Y) nImage.save("fits-color-grayscale-y").second shouldBe "24dd4a7e0fa9e4be34c53c924a78a940" } @@ -288,7 +288,7 @@ class FitsTransformAlgorithmTest : FitsStringSpec() { nImage.save("fits-color-no-debayer").second shouldBe "958ccea020deec1f0c075042a9ba37c3" } "color:reload" { - val mImage0 = Image.open(NGC3344_COLOR_32_FITS_PATH.fits()) + val mImage0 = Image.open(NGC3344_COLOR_32_FITS.fits()) var mImage1 = Image.open(DEBAYER_FITS_PATH.fits()) mImage1.load(mImage0.hdu).shouldNotBeNull() diff --git a/nebulosa-io/src/main/kotlin/nebulosa/io/Io.kt b/nebulosa-io/src/main/kotlin/nebulosa/io/Io.kt index fca1d30ce..bca1fda39 100644 --- a/nebulosa-io/src/main/kotlin/nebulosa/io/Io.kt +++ b/nebulosa-io/src/main/kotlin/nebulosa/io/Io.kt @@ -61,13 +61,24 @@ inline fun BufferedSource.readLatin1() = readString(Charsets.ISO_8859_1) inline fun BufferedSource.readLatin1(byteCount: Long) = readString(byteCount, Charsets.ISO_8859_1) -inline fun BufferedSink.writeFloat(f: Float) = writeInt(f.toBits()) +inline fun BufferedSink.writeShort(value: Int, order: ByteOrder) = if (order.isBigEndian) writeShort(value) else writeShortLe(value) -inline fun BufferedSink.writeFloatLe(f: Float) = writeIntLe(f.toBits()) +inline fun BufferedSink.writeInt(value: Int, order: ByteOrder) = if (order.isBigEndian) writeInt(value) else writeIntLe(value) -inline fun BufferedSink.writeDouble(d: Double) = writeLong(d.toBits()) +inline fun BufferedSink.writeLong(value: Long, order: ByteOrder) = if (order.isBigEndian) writeLong(value) else writeLongLe(value) -inline fun BufferedSink.writeDoubleLe(d: Double) = writeLongLe(d.toBits()) +inline fun BufferedSink.writeFloat(value: Float) = writeInt(value.toBits()) + +inline fun BufferedSink.writeFloatLe(value: Float) = writeIntLe(value.toBits()) + +inline fun BufferedSink.writeFloat(value: Float, order: ByteOrder) = if (order.isBigEndian) writeInt(value.toBits()) else writeIntLe(value.toBits()) + +inline fun BufferedSink.writeDouble(value: Double) = writeLong(value.toBits()) + +inline fun BufferedSink.writeDoubleLe(value: Double) = writeLongLe(value.toBits()) + +inline fun BufferedSink.writeDouble(value: Double, order: ByteOrder) = + if (order.isBigEndian) writeLong(value.toBits()) else writeLongLe(value.toBits()) inline fun ClassLoader.resource(name: String): InputStream? = getResourceAsStream(name) diff --git a/nebulosa-test/src/main/kotlin/nebulosa/test/FitsStringSpec.kt b/nebulosa-test/src/main/kotlin/nebulosa/test/FitsStringSpec.kt index 6870e3335..11e5464a3 100644 --- a/nebulosa-test/src/main/kotlin/nebulosa/test/FitsStringSpec.kt +++ b/nebulosa-test/src/main/kotlin/nebulosa/test/FitsStringSpec.kt @@ -46,18 +46,19 @@ abstract class FitsStringSpec : StringSpec() { protected val M82_COLOR_F64_XISF by lazy { download("M82.Color.F64.xisf", GITHUB_XISF_URL) } protected val DEBAYER_XISF_PATH by lazy { download("Debayer.xisf", GITHUB_XISF_URL) } - protected val NGC3344_COLOR_8_FITS_PATH by lazy { download("NGC3344.Color.8.fits", GITHUB_FITS_URL) } - protected val NGC3344_COLOR_16_FITS_PATH by lazy { download("NGC3344.Color.16.fits", GITHUB_FITS_URL) } - protected val NGC3344_COLOR_32_FITS_PATH by lazy { download("NGC3344.Color.32.fits", GITHUB_FITS_URL) } - protected val NGC3344_COLOR_F32_FITS_PATH by lazy { download("NGC3344.Color.F32.fits", GITHUB_FITS_URL) } - protected val NGC3344_COLOR_F64_FITS_PATH by lazy { download("NGC3344.Color.F64.fits", GITHUB_FITS_URL) } - protected val NGC3344_MONO_8_FITS_PATH by lazy { download("NGC3344.Mono.8.fits", GITHUB_FITS_URL) } - protected val NGC3344_MONO_16_FITS_PATH by lazy { download("NGC3344.Mono.16.fits", GITHUB_FITS_URL) } - protected val NGC3344_MONO_32_FITS_PATH by lazy { download("NGC3344.Mono.32.fits", GITHUB_FITS_URL) } - protected val NGC3344_MONO_F32_FITS_PATH by lazy { download("NGC3344.Mono.F32.fits", GITHUB_FITS_URL) } - protected val NGC3344_MONO_F64_FITS_PATH by lazy { download("NGC3344.Mono.F64.fits", GITHUB_FITS_URL) } - protected val DEBAYER_FITS_PATH by lazy { download("Debayer.fits", GITHUB_FITS_URL) } + protected val NGC3344_MONO_8_FITS by lazy { download("NGC3344.Mono.8.fits", GITHUB_FITS_URL) } + protected val NGC3344_MONO_16_FITS by lazy { download("NGC3344.Mono.16.fits", GITHUB_FITS_URL) } + protected val NGC3344_MONO_32_FITS by lazy { download("NGC3344.Mono.32.fits", GITHUB_FITS_URL) } + protected val NGC3344_MONO_F32_FITS by lazy { download("NGC3344.Mono.F32.fits", GITHUB_FITS_URL) } + protected val NGC3344_MONO_F64_FITS by lazy { download("NGC3344.Mono.F64.fits", GITHUB_FITS_URL) } + + protected val NGC3344_COLOR_8_FITS by lazy { download("NGC3344.Color.8.fits", GITHUB_FITS_URL) } + protected val NGC3344_COLOR_16_FITS by lazy { download("NGC3344.Color.16.fits", GITHUB_FITS_URL) } + protected val NGC3344_COLOR_32_FITS by lazy { download("NGC3344.Color.32.fits", GITHUB_FITS_URL) } + protected val NGC3344_COLOR_F32_FITS by lazy { download("NGC3344.Color.F32.fits", GITHUB_FITS_URL) } + protected val NGC3344_COLOR_F64_FITS by lazy { download("NGC3344.Color.F64.fits", GITHUB_FITS_URL) } + protected val DEBAYER_FITS_PATH by lazy { download("Debayer.fits", GITHUB_FITS_URL) } protected val M6707HH by lazyFITS("M6707HH.fits", ASTROPY_PHOTOMETRY_URL) protected val STAR_FOCUS_1 by lazyFITS("STAR.FOCUS.1.fits") diff --git a/nebulosa-watney/src/test/kotlin/WatneyStarDetectorTest.kt b/nebulosa-watney/src/test/kotlin/WatneyStarDetectorTest.kt index 429519a39..e038cb96f 100644 --- a/nebulosa-watney/src/test/kotlin/WatneyStarDetectorTest.kt +++ b/nebulosa-watney/src/test/kotlin/WatneyStarDetectorTest.kt @@ -17,7 +17,7 @@ class WatneyStarDetectorTest : FitsStringSpec() { val detector = WatneyStarDetector(computeHFD = true) "detect stars" { - var image = Image.open(NGC3344_COLOR_32_FITS_PATH.fits()) + var image = Image.open(NGC3344_COLOR_32_FITS.fits()) var stars = detector.detect(image.transform(Mean)) stars shouldHaveSize 1 image.transform(ImageStarsDraw(stars)).save("color-detected-stars-1") diff --git a/nebulosa-xisf/src/main/kotlin/nebulosa/xisf/XisfFormat.kt b/nebulosa-xisf/src/main/kotlin/nebulosa/xisf/XisfFormat.kt index 7e704efb8..308cda3ec 100644 --- a/nebulosa-xisf/src/main/kotlin/nebulosa/xisf/XisfFormat.kt +++ b/nebulosa-xisf/src/main/kotlin/nebulosa/xisf/XisfFormat.kt @@ -1,13 +1,13 @@ package nebulosa.xisf import nebulosa.fits.ValueType +import nebulosa.fits.bitpix import nebulosa.fits.frame import nebulosa.image.format.Hdu import nebulosa.image.format.ImageFormat import nebulosa.image.format.ImageHdu import nebulosa.io.* -import nebulosa.xisf.XisfMonolithicFileHeader.ColorSpace -import nebulosa.xisf.XisfMonolithicFileHeader.ImageType +import nebulosa.xisf.XisfMonolithicFileHeader.* import nebulosa.xml.escapeXml import okio.Buffer import okio.Sink @@ -45,7 +45,7 @@ data object XisfFormat : ImageFormat { val header = stream.read() ?: break when (header) { - is XisfMonolithicFileHeader.Image -> hdus.add(XisfMonolithicFileHeaderImageHdu(header, source)) + is Image -> hdus.add(XisfMonolithicFileHeaderImageHdu(header, source)) } } @@ -55,95 +55,140 @@ data object XisfFormat : ImageFormat { override fun write(sink: Sink, hdus: Iterable>) { Buffer().use { buffer -> - buffer.writeString(MAGIC_HEADER, Charsets.US_ASCII) - buffer.writeLongLe(0L) - buffer.writeUtf8(XML_VERSION) - buffer.writeUtf8(XML_COMMENT) - buffer.writeUtf8(XISF_START_TAG) + val headerSize = writeHeader(buffer, hdus) + val byteCount = buffer.readAll(sink) + + val remainingBytes = headerSize - byteCount + check(remainingBytes >= 0L) { "unexpected remaining bytes: $remainingBytes" } + buffer.write(ZeroSource, remainingBytes) + buffer.readAll(sink) for (hdu in hdus) { if (hdu is ImageHdu) { - val header = hdu.header - val colorSpace = if (hdu.isMono) ColorSpace.GRAY else ColorSpace.RGB - val imageType = ImageType.valueOf(header.frame ?: "LIGHT") - val imageSize = hdu.width * hdu.height * hdu.numberOfChannels * 4 - - IMAGE_START_TAG - .format(hdu.width, hdu.height, hdu.numberOfChannels, colorSpace.code, imageType.code, MAX_HEADER_SIZE, imageSize) - .also(buffer::writeUtf8) - - for ((name, key) in AstronomicalImageProperties) { - if (key != null) { - if (key.valueType == ValueType.STRING || key.valueType == ValueType.ANY) { - val value = header.getStringOrNull(key) ?: continue - buffer.writeUtf8(STRING_PROPERTY_TAG.format(name, value.escapeXml())) - } else if (key.valueType == ValueType.LOGICAL) { - val value = header.getBooleanOrNull(key) ?: continue - buffer.writeUtf8(NON_STRING_PROPERTY_TAG.format(name, XisfPropertyType.BOOLEAN.typeName, if (value) 1 else 0)) - } else if (key.valueType == ValueType.INTEGER) { - val value = header.getLongOrNull(key) ?: continue - buffer.writeUtf8(NON_STRING_PROPERTY_TAG.format(name, XisfPropertyType.INT64.typeName, value)) - } else if (key.valueType == ValueType.REAL) { - val value = header.getDoubleOrNull(key) ?: continue - buffer.writeUtf8(NON_STRING_PROPERTY_TAG.format(name, XisfPropertyType.FLOAT64.typeName, value)) - } - } + val bitpix = hdu.header.bitpix + val sampleFormat = SampleFormat.from(bitpix) + + if (hdu.isMono) { + hdu.data.red.writeTo(buffer, sink, sampleFormat) + } else { + hdu.data.red.writeTo(buffer, sink, sampleFormat) + hdu.data.green.writeTo(buffer, sink, sampleFormat) + hdu.data.blue.writeTo(buffer, sink, sampleFormat) } + } + } + } + } - for (keyword in header) { - val value = if (keyword.isStringType) "'${keyword.value.escapeXml()}'" else keyword.value - buffer.writeUtf8(FITS_KEYWORD_TAG.format(keyword.key, value, keyword.comment.escapeXml())) + private fun writeHeader(buffer: Buffer, hdus: Iterable>, initialHeaderSize: Int = 4096): Int { + buffer.clear() + + buffer.writeString(MAGIC_HEADER, Charsets.US_ASCII) + buffer.writeLongLe(0L) + buffer.writeUtf8(XML_VERSION) + buffer.writeUtf8(XML_COMMENT) + buffer.writeUtf8(XISF_START_TAG) + + for (hdu in hdus) { + if (hdu is ImageHdu) { + val header = hdu.header + val colorSpace = if (hdu.isMono) ColorSpace.GRAY else ColorSpace.RGB + val imageType = ImageType.parse(header.frame ?: "Light") ?: ImageType.LIGHT + val bitpix = hdu.header.bitpix + val sampleFormat = SampleFormat.from(bitpix) + val imageSize = hdu.width * hdu.height * hdu.numberOfChannels * sampleFormat.byteLength + + IMAGE_START_TAG + .format( + hdu.width, hdu.height, hdu.numberOfChannels, + sampleFormat.code, colorSpace.code, imageType.code, initialHeaderSize, imageSize + ).also(buffer::writeUtf8) + + for ((name, key) in AstronomicalImageProperties) { + if (key != null) { + if (key.valueType == ValueType.STRING || key.valueType == ValueType.ANY) { + val value = header.getStringOrNull(key) ?: continue + buffer.writeUtf8(STRING_PROPERTY_TAG.format(name, value.escapeXml())) + } else if (key.valueType == ValueType.LOGICAL) { + val value = header.getBooleanOrNull(key) ?: continue + buffer.writeUtf8(NON_STRING_PROPERTY_TAG.format(name, XisfPropertyType.BOOLEAN.typeName, if (value) 1 else 0)) + } else if (key.valueType == ValueType.INTEGER) { + val value = header.getLongOrNull(key) ?: continue + buffer.writeUtf8(NON_STRING_PROPERTY_TAG.format(name, XisfPropertyType.INT64.typeName, value)) + } else if (key.valueType == ValueType.REAL) { + val value = header.getDoubleOrNull(key) ?: continue + buffer.writeUtf8(NON_STRING_PROPERTY_TAG.format(name, XisfPropertyType.FLOAT64.typeName, value)) + } } } + + for (keyword in header) { + val value = if (keyword.isStringType) "'${keyword.value.escapeXml()}'" else keyword.value + buffer.writeUtf8(FITS_KEYWORD_TAG.format(keyword.key, value, keyword.comment.escapeXml())) + } } + } - buffer.writeUtf8(IMAGE_END_TAG) - buffer.writeUtf8(XISF_END_TAG) + buffer.writeUtf8(IMAGE_END_TAG) + buffer.writeUtf8(XISF_END_TAG) - val headerSize = buffer.size - 16 + val size = buffer.size + val remainingBytes = initialHeaderSize - size - buffer.readAndWriteUnsafe().use { - it.seek(8L) - it.data!![it.start + 0] = (headerSize and 0xFF).toByte() - it.data!![it.start + 1] = (headerSize shr 8 and 0xFF).toByte() - it.data!![it.start + 2] = (headerSize shr 16 and 0xFF).toByte() - it.data!![it.start + 3] = (headerSize shr 24 and 0xFF).toByte() - } + if (remainingBytes < 0) { + return writeHeader(buffer, hdus, initialHeaderSize * 2) + } - val byteCount = buffer.readAll(sink) + val headerSize = size - 16 - val remainingBytes = MAX_HEADER_SIZE - byteCount - check(remainingBytes >= 0L) { "unexpected remaining bytes: $remainingBytes" } - buffer.write(ZeroSource, remainingBytes) - buffer.readAll(sink) + buffer.readAndWriteUnsafe().use { + it.seek(8L) + it.data!![it.start + 0] = (headerSize and 0xFF).toByte() + it.data!![it.start + 1] = (headerSize shr 8 and 0xFF).toByte() + it.data!![it.start + 2] = (headerSize shr 16 and 0xFF).toByte() + it.data!![it.start + 3] = (headerSize shr 24 and 0xFF).toByte() + } - for (hdu in hdus) { - if (hdu is ImageHdu) { - if (hdu.isMono) { - hdu.data.red.readTo(buffer, sink) - } else { - hdu.data.red.readTo(buffer, sink) - hdu.data.green.readTo(buffer, sink) - hdu.data.blue.readTo(buffer, sink) - } - } - } + return initialHeaderSize + } + + @JvmStatic + internal fun Buffer.readPixel(format: SampleFormat, byteOrder: ByteOrder): Float { + return when (format) { + SampleFormat.UINT8 -> (readByte().toInt() and 0xFF) / 255f + SampleFormat.UINT16 -> (readShort(byteOrder).toInt() and 0xFFFF) / 65535f + SampleFormat.UINT32 -> ((readInt(byteOrder).toLong() and 0xFFFFFFFF) / 4294967295.0).toFloat() + SampleFormat.UINT64 -> TODO("Unsupported UInt64 sample format") + SampleFormat.FLOAT32 -> readFloat(byteOrder) + SampleFormat.FLOAT64 -> readDouble(byteOrder).toFloat() } } - private fun FloatArray.readTo(buffer: Buffer, sink: Sink) { + @JvmStatic + internal fun FloatArray.writeTo(buffer: Buffer, sink: Sink, format: SampleFormat) { var idx = 0 while (idx < size) { - repeat(min(256, size - idx)) { buffer.writeFloatLe(this[idx++]) } + repeat(min(256, size - idx)) { buffer.writePixel(this[idx++], format) } buffer.readAll(sink) } buffer.readAll(sink) } + @JvmStatic + internal fun Buffer.writePixel(pixel: Float, format: SampleFormat) { + when (format) { + SampleFormat.UINT8 -> writeByte((pixel * 255f).toInt()) + SampleFormat.UINT16 -> writeShortLe((pixel * 65535f).toInt()) + SampleFormat.UINT32 -> writeIntLe(((pixel * 4294967295.0).toLong() and 0xFFFFFFFF).toInt()) + SampleFormat.UINT64 -> TODO("Unsupported UInt64 sample format") + SampleFormat.FLOAT32 -> writeFloatLe(pixel) + SampleFormat.FLOAT64 -> writeDoubleLe(pixel.toDouble()) + } + } + private const val MAGIC_HEADER = "XISF0100" - private const val MAX_HEADER_SIZE = 4096 private const val XML_VERSION = """""" private const val XML_COMMENT = """""" @@ -151,7 +196,7 @@ data object XisfFormat : ImageFormat { """""" private const val XISF_END_TAG = "" private const val IMAGE_START_TAG = - """""" + """""" private const val IMAGE_END_TAG = "" private const val STRING_PROPERTY_TAG = """%s""" private const val NON_STRING_PROPERTY_TAG = """""" diff --git a/nebulosa-xisf/src/main/kotlin/nebulosa/xisf/XisfHeaderInputStream.kt b/nebulosa-xisf/src/main/kotlin/nebulosa/xisf/XisfHeaderInputStream.kt index 2c703da0d..4e9a15b6b 100644 --- a/nebulosa-xisf/src/main/kotlin/nebulosa/xisf/XisfHeaderInputStream.kt +++ b/nebulosa-xisf/src/main/kotlin/nebulosa/xisf/XisfHeaderInputStream.kt @@ -1,6 +1,9 @@ package nebulosa.xisf import com.fasterxml.aalto.stax.InputFactoryImpl +import nebulosa.fits.FitsHeader +import nebulosa.fits.FitsHeaderCard +import nebulosa.fits.FitsKeyword import nebulosa.image.format.HeaderCard import nebulosa.io.ByteOrder import nebulosa.xisf.XisfMonolithicFileHeader.* @@ -47,6 +50,17 @@ class XisfHeaderInputStream(source: InputStream) : Closeable { val compression = reader.attribute("compression")?.let { CompressionFormat.parse(it) } val bounds = reader.attribute("bounds")?.split(":")?.let { it[0].toFloat()..it[1].toFloat() } val (keywords, thumbnail) = parseKeywords() + val header = FitsHeader() + val isMono = numberOfChannels == "1" + + header.add(FitsHeaderCard.SIMPLE) + header.add(sampleFormat.bitpix) + header.add(FitsHeaderCard.create(FitsKeyword.NAXIS, if (isMono) 2 else 3)) + header.add(FitsHeaderCard.create(FitsKeyword.NAXIS1, width.toInt())) + header.add(FitsHeaderCard.create(FitsKeyword.NAXIS2, height.toInt())) + if (!isMono) header.add(FitsHeaderCard.create(FitsKeyword.NAXIS3, 3)) + header.add(FitsHeaderCard.EXTENDED) + header.addAll(keywords) return Image( width.toInt(), height.toInt(), numberOfChannels.toInt(), @@ -56,7 +70,7 @@ class XisfHeaderInputStream(source: InputStream) : Closeable { byteOrder ?: ByteOrder.LITTLE, compression, imageType ?: ImageType.LIGHT, bounds ?: XisfMonolithicFileHeader.DEFAULT_BOUNDS, - keywords, thumbnail, + header, thumbnail, ) } diff --git a/nebulosa-xisf/src/main/kotlin/nebulosa/xisf/XisfMonolithicFileHeader.kt b/nebulosa-xisf/src/main/kotlin/nebulosa/xisf/XisfMonolithicFileHeader.kt index 24c99282f..512375336 100644 --- a/nebulosa-xisf/src/main/kotlin/nebulosa/xisf/XisfMonolithicFileHeader.kt +++ b/nebulosa-xisf/src/main/kotlin/nebulosa/xisf/XisfMonolithicFileHeader.kt @@ -1,5 +1,7 @@ package nebulosa.xisf +import nebulosa.fits.Bitpix +import nebulosa.fits.FitsHeader import nebulosa.fits.FitsHeaderCard import nebulosa.fits.FitsKeyword import nebulosa.image.format.HeaderCard @@ -7,13 +9,29 @@ import nebulosa.io.ByteOrder sealed interface XisfMonolithicFileHeader { - enum class SampleFormat(val byteLength: Long) { - UINT8(1L), - UINT16(2L), - UINT32(4L), - UINT64(8L), - FLOAT32(4L), - FLOAT64(8L), + enum class SampleFormat( + @JvmField val byteLength: Long, + @JvmField val code: String, @JvmField val bitpix: Bitpix, + ) { + UINT8(1L, "UInt8", Bitpix.BYTE), + UINT16(2L, "UInt16", Bitpix.SHORT), + UINT32(4L, "UInt32", Bitpix.INTEGER), + UINT64(8L, "UInt64", Bitpix.LONG), + FLOAT32(4L, "Float32", Bitpix.FLOAT), + FLOAT64(8L, "Float64", Bitpix.DOUBLE); + + companion object { + + @JvmStatic + fun from(bitpix: Bitpix) = when (bitpix) { + Bitpix.BYTE -> UINT8 + Bitpix.SHORT -> UINT16 + Bitpix.INTEGER -> UINT32 + Bitpix.LONG -> UINT64 + Bitpix.FLOAT -> FLOAT32 + Bitpix.DOUBLE -> FLOAT64 + } + } } enum class ColorSpace(@JvmField val code: String) { @@ -98,7 +116,7 @@ sealed interface XisfMonolithicFileHeader { @JvmField val compressionFormat: CompressionFormat? = null, @JvmField val imageType: ImageType = ImageType.LIGHT, @JvmField val bounds: ClosedFloatingPointRange = DEFAULT_BOUNDS, - @JvmField val keywords: Collection = emptyList(), + @JvmField val keywords: FitsHeader = FitsHeader.EMPTY, @JvmField val thumbnail: Image? = null, ) : XisfMonolithicFileHeader diff --git a/nebulosa-xisf/src/main/kotlin/nebulosa/xisf/XisfMonolithicFileHeaderImageData.kt b/nebulosa-xisf/src/main/kotlin/nebulosa/xisf/XisfMonolithicFileHeaderImageData.kt index 7894cd97f..e5312f29b 100644 --- a/nebulosa-xisf/src/main/kotlin/nebulosa/xisf/XisfMonolithicFileHeaderImageData.kt +++ b/nebulosa-xisf/src/main/kotlin/nebulosa/xisf/XisfMonolithicFileHeaderImageData.kt @@ -2,7 +2,8 @@ package nebulosa.xisf import nebulosa.image.format.ImageChannel import nebulosa.image.format.ImageData -import nebulosa.io.* +import nebulosa.io.SeekableSource +import nebulosa.xisf.XisfFormat.readPixel import nebulosa.xisf.XisfMonolithicFileHeader.* import okio.Buffer import okio.InflaterSource @@ -153,17 +154,6 @@ internal data class XisfMonolithicFileHeaderImageData( return data } - private fun Buffer.readPixel(format: SampleFormat, byteOrder: ByteOrder): Float { - return when (format) { - SampleFormat.UINT8 -> (buffer.readByte().toInt() and 0xFF) / 255f - SampleFormat.UINT16 -> (buffer.readShort(byteOrder).toInt() and 0xFFFF) / 65535f - SampleFormat.UINT32 -> ((buffer.readInt(byteOrder).toLong() and 0xFFFFFFFF) / 4294967295.0).toFloat() - SampleFormat.UINT64 -> TODO("Unsupported UInt64 sample format") - SampleFormat.FLOAT32 -> buffer.readFloat(byteOrder) - SampleFormat.FLOAT64 -> buffer.readDouble(byteOrder).toFloat() - } - } - companion object { const val PIXEL_COUNT = 64 diff --git a/nebulosa-xisf/src/main/kotlin/nebulosa/xisf/XisfMonolithicFileHeaderImageHdu.kt b/nebulosa-xisf/src/main/kotlin/nebulosa/xisf/XisfMonolithicFileHeaderImageHdu.kt index 8f2e910ed..2611919b0 100644 --- a/nebulosa-xisf/src/main/kotlin/nebulosa/xisf/XisfMonolithicFileHeaderImageHdu.kt +++ b/nebulosa-xisf/src/main/kotlin/nebulosa/xisf/XisfMonolithicFileHeaderImageHdu.kt @@ -12,6 +12,6 @@ internal data class XisfMonolithicFileHeaderImageHdu( override val width = image.width override val height = image.height override val numberOfChannels = image.numberOfChannels - override val header = FitsHeader(image.keywords) + override val header = image.keywords override val data = XisfMonolithicFileHeaderImageData(image, source) } diff --git a/nebulosa-xisf/src/test/kotlin/XisfFormatTest.kt b/nebulosa-xisf/src/test/kotlin/XisfFormatTest.kt index 4f7ebbc11..f1086772b 100644 --- a/nebulosa-xisf/src/test/kotlin/XisfFormatTest.kt +++ b/nebulosa-xisf/src/test/kotlin/XisfFormatTest.kt @@ -5,6 +5,8 @@ import io.kotest.matchers.ints.shouldBeExactly import io.kotest.matchers.shouldBe import io.kotest.matchers.types.shouldBeSameInstanceAs import io.kotest.matchers.types.shouldNotBeSameInstanceAs +import nebulosa.fits.FitsFormat +import nebulosa.fits.bitpix import nebulosa.image.format.ImageHdu import nebulosa.io.seekableSink import nebulosa.io.seekableSource @@ -27,7 +29,7 @@ class XisfFormatTest : FitsStringSpec() { width shouldBeExactly 512 height shouldBeExactly 512 numberOfChannels shouldBeExactly 1 - header shouldHaveSize 17 + header shouldHaveSize 23 data.red.size shouldBeExactly 512 * 512 data.green shouldBeSameInstanceAs data.red data.blue shouldBeSameInstanceAs data.green @@ -46,7 +48,7 @@ class XisfFormatTest : FitsStringSpec() { width shouldBeExactly 512 height shouldBeExactly 512 numberOfChannels shouldBeExactly 1 - header shouldHaveSize 17 + header shouldHaveSize 23 data.red.size shouldBeExactly 512 * 512 data.green shouldBeSameInstanceAs data.red data.blue shouldBeSameInstanceAs data.green @@ -65,7 +67,7 @@ class XisfFormatTest : FitsStringSpec() { width shouldBeExactly 512 height shouldBeExactly 512 numberOfChannels shouldBeExactly 1 - header shouldHaveSize 17 + header shouldHaveSize 23 data.red.size shouldBeExactly 512 * 512 data.green shouldBeSameInstanceAs data.red data.blue shouldBeSameInstanceAs data.green @@ -84,7 +86,7 @@ class XisfFormatTest : FitsStringSpec() { width shouldBeExactly 512 height shouldBeExactly 512 numberOfChannels shouldBeExactly 1 - header shouldHaveSize 17 + header shouldHaveSize 23 data.red.size shouldBeExactly 512 * 512 data.green shouldBeSameInstanceAs data.red data.blue shouldBeSameInstanceAs data.green @@ -103,7 +105,7 @@ class XisfFormatTest : FitsStringSpec() { width shouldBeExactly 512 height shouldBeExactly 512 numberOfChannels shouldBeExactly 1 - header shouldHaveSize 17 + header shouldHaveSize 23 data.red.size shouldBeExactly 512 * 512 data.green shouldBeSameInstanceAs data.red data.blue shouldBeSameInstanceAs data.green @@ -122,7 +124,7 @@ class XisfFormatTest : FitsStringSpec() { width shouldBeExactly 512 height shouldBeExactly 512 numberOfChannels shouldBeExactly 3 - header shouldHaveSize 17 + header shouldHaveSize 24 data.red.size shouldBeExactly 512 * 512 data.green shouldNotBeSameInstanceAs data.red data.blue shouldNotBeSameInstanceAs data.green @@ -141,7 +143,7 @@ class XisfFormatTest : FitsStringSpec() { width shouldBeExactly 512 height shouldBeExactly 512 numberOfChannels shouldBeExactly 3 - header shouldHaveSize 17 + header shouldHaveSize 24 data.red.size shouldBeExactly 512 * 512 data.green shouldNotBeSameInstanceAs data.red data.blue shouldNotBeSameInstanceAs data.green @@ -160,7 +162,7 @@ class XisfFormatTest : FitsStringSpec() { width shouldBeExactly 512 height shouldBeExactly 512 numberOfChannels shouldBeExactly 3 - header shouldHaveSize 17 + header shouldHaveSize 24 data.red.size shouldBeExactly 512 * 512 data.green shouldNotBeSameInstanceAs data.red data.blue shouldNotBeSameInstanceAs data.green @@ -179,7 +181,7 @@ class XisfFormatTest : FitsStringSpec() { width shouldBeExactly 512 height shouldBeExactly 512 numberOfChannels shouldBeExactly 3 - header shouldHaveSize 17 + header shouldHaveSize 24 data.red.size shouldBeExactly 512 * 512 data.green shouldNotBeSameInstanceAs data.red data.blue shouldNotBeSameInstanceAs data.green @@ -198,7 +200,7 @@ class XisfFormatTest : FitsStringSpec() { width shouldBeExactly 512 height shouldBeExactly 512 numberOfChannels shouldBeExactly 3 - header shouldHaveSize 17 + header shouldHaveSize 24 data.red.size shouldBeExactly 512 * 512 data.green shouldNotBeSameInstanceAs data.red data.blue shouldNotBeSameInstanceAs data.green @@ -217,7 +219,7 @@ class XisfFormatTest : FitsStringSpec() { width shouldBeExactly 512 height shouldBeExactly 512 numberOfChannels shouldBeExactly 1 - header shouldHaveSize 17 + header shouldHaveSize 23 data.red.size shouldBeExactly 512 * 512 data.green shouldBeSameInstanceAs data.red data.blue shouldBeSameInstanceAs data.green @@ -227,52 +229,180 @@ class XisfFormatTest : FitsStringSpec() { } } "mono:write" { - val source0 = closeAfterEach(M82_MONO_8_XISF.seekableSource()) - val hdus0 = XisfFormat.read(source0) + val formats = arrayOf(M82_MONO_8_XISF, M82_MONO_16_XISF, M82_MONO_32_XISF, M82_MONO_F32_XISF, M82_MONO_F64_XISF) - val outputPath = tempfile() - val sink = closeAfterEach(outputPath.seekableSink()) + for (format in formats) { + val source0 = closeAfterEach(format.seekableSource()) + val hdus0 = XisfFormat.read(source0) - XisfFormat.write(sink, hdus0) + val outputPath = tempfile() + val sink = closeAfterEach(outputPath.seekableSink()) + XisfFormat.write(sink, hdus0) - val source1 = closeAfterEach(outputPath.seekableSource()) - val hdus1 = XisfFormat.read(source1) + val source1 = closeAfterEach(outputPath.seekableSource()) + val hdus1 = XisfFormat.read(source1) - hdus1 shouldHaveSize 1 - hdus1[0].data.numberOfChannels shouldBeExactly 1 - hdus1[0].header.size shouldBeExactly hdus0[0].header.size - hdus1[0].data.red.size shouldBeExactly hdus0[0].data.red.size - hdus1[0].data.red shouldNotBeSameInstanceAs hdus0[0].data.red - hdus1[0].data.red.forEachIndexed { i, value -> value shouldBeExactly hdus0[0].data.red[i] } + hdus1 shouldHaveSize 1 + hdus1[0].data.numberOfChannels shouldBeExactly 1 + hdus1[0].header.size shouldBeExactly hdus0[0].header.size + hdus1[0].data.red.size shouldBeExactly hdus0[0].data.red.size + hdus1[0].data.red shouldNotBeSameInstanceAs hdus0[0].data.red + hdus1[0].data.red.forEachIndexed { i, value -> value shouldBeExactly hdus0[0].data.red[i] } - val image = hdus1[0].makeImage() - image.save("xisf-mono-write").second shouldBe "0dca7efedef5b3525f8037f401518b0b" + val bitpix = hdus1[0].header.bitpix + val image = hdus1[0].makeImage() + image.save("xisf-mono-write-$bitpix").second shouldBe "0dca7efedef5b3525f8037f401518b0b" + } } "color:write" { - val source0 = closeAfterEach(M82_COLOR_32_XISF.seekableSource()) - val hdus0 = XisfFormat.read(source0) - - val outputPath = tempfile() - val sink = closeAfterEach(outputPath.seekableSink()) - - XisfFormat.write(sink, hdus0) - - val source1 = closeAfterEach(outputPath.seekableSource()) - val hdus1 = XisfFormat.read(source1) - - hdus1 shouldHaveSize 1 - hdus1[0].data.numberOfChannels shouldBeExactly 3 - hdus1[0].header.size shouldBeExactly hdus0[0].header.size - hdus1[0].data.red.size shouldBeExactly hdus0[0].data.red.size - hdus1[0].data.red shouldNotBeSameInstanceAs hdus0[0].data.red - hdus1[0].data.red.forEachIndexed { i, value -> value shouldBeExactly hdus0[0].data.red[i] } - hdus1[0].data.green shouldNotBeSameInstanceAs hdus0[0].data.green - hdus1[0].data.green.forEachIndexed { i, value -> value shouldBeExactly hdus0[0].data.green[i] } - hdus1[0].data.blue shouldNotBeSameInstanceAs hdus0[0].data.blue - hdus1[0].data.blue.forEachIndexed { i, value -> value shouldBeExactly hdus0[0].data.blue[i] } - - val image = hdus1[0].makeImage() - image.save("xisf-color-write").second shouldBe "89beed384ee9e97ce033ba447a377937" + val formats = arrayOf(M82_COLOR_8_XISF, M82_COLOR_16_XISF, M82_COLOR_32_XISF, M82_COLOR_F32_XISF, M82_COLOR_F64_XISF) + + for (format in formats) { + val source0 = closeAfterEach(format.seekableSource()) + val hdus0 = XisfFormat.read(source0) + + val outputPath = tempfile() + val sink = closeAfterEach(outputPath.seekableSink()) + XisfFormat.write(sink, hdus0) + + val source1 = closeAfterEach(outputPath.seekableSource()) + val hdus1 = XisfFormat.read(source1) + + hdus1 shouldHaveSize 1 + hdus1[0].data.numberOfChannels shouldBeExactly 3 + hdus1[0].header.size shouldBeExactly hdus0[0].header.size + hdus1[0].data.red.size shouldBeExactly hdus0[0].data.red.size + hdus1[0].data.red shouldNotBeSameInstanceAs hdus0[0].data.red + hdus1[0].data.red.forEachIndexed { i, value -> value shouldBeExactly hdus0[0].data.red[i] } + hdus1[0].data.green shouldNotBeSameInstanceAs hdus0[0].data.green + hdus1[0].data.green.forEachIndexed { i, value -> value shouldBeExactly hdus0[0].data.green[i] } + hdus1[0].data.blue shouldNotBeSameInstanceAs hdus0[0].data.blue + hdus1[0].data.blue.forEachIndexed { i, value -> value shouldBeExactly hdus0[0].data.blue[i] } + + val bitpix = hdus1[0].header.bitpix + val image = hdus1[0].makeImage() + image.save("xisf-color-write-$bitpix").second shouldBe "89beed384ee9e97ce033ba447a377937" + } + } + "fits-to-xisf:mono" { + val formats = arrayOf(NGC3344_MONO_8_FITS, NGC3344_MONO_16_FITS, NGC3344_MONO_32_FITS, NGC3344_MONO_F32_FITS, NGC3344_MONO_F64_FITS) + + for (format in formats) { + val source0 = closeAfterEach(format.seekableSource()) + val hdus0 = FitsFormat.read(source0).filterIsInstance() + + hdus0 shouldHaveSize 1 + + val outputPath = tempfile() + val sink = closeAfterEach(outputPath.seekableSink()) + XisfFormat.write(sink, hdus0) + + val source1 = closeAfterEach(outputPath.seekableSource()) + val hdus1 = XisfFormat.read(source1) + + hdus1 shouldHaveSize 1 + hdus1[0].data.numberOfChannels shouldBeExactly 1 + // hdus1[0].header.size shouldBeExactly hdus0[0].header.size + hdus1[0].data.red.size shouldBeExactly hdus0[0].data.red.size + hdus1[0].data.red shouldNotBeSameInstanceAs hdus0[0].data.red + hdus1[0].data.red.forEachIndexed { i, value -> value shouldBeExactly hdus0[0].data.red[i] } + + val bitpix = hdus1[0].header.bitpix + val image = hdus1[0].makeImage() + image.save("fits-to-xisf-mono-$bitpix").second shouldBe "e17cfc29c3b343409cd8617b6913330e" + } + } + "fits-to-xisf:color" { + val formats = arrayOf(NGC3344_COLOR_8_FITS, NGC3344_COLOR_16_FITS, NGC3344_COLOR_32_FITS, NGC3344_COLOR_F32_FITS, NGC3344_COLOR_F64_FITS) + + for (format in formats) { + val source0 = closeAfterEach(format.seekableSource()) + val hdus0 = FitsFormat.read(source0).filterIsInstance() + + hdus0 shouldHaveSize 1 + + val outputPath = tempfile() + val sink = closeAfterEach(outputPath.seekableSink()) + XisfFormat.write(sink, hdus0) + + val source1 = closeAfterEach(outputPath.seekableSource()) + val hdus1 = XisfFormat.read(source1) + + hdus1 shouldHaveSize 1 + hdus1[0].data.numberOfChannels shouldBeExactly 4 + // hdus1[0].header.size shouldBeExactly hdus0[0].header.size + hdus1[0].data.red.size shouldBeExactly hdus0[0].data.red.size + hdus1[0].data.red shouldNotBeSameInstanceAs hdus0[0].data.red + hdus1[0].data.red.forEachIndexed { i, value -> value shouldBeExactly hdus0[0].data.red[i] } + hdus1[0].data.green shouldNotBeSameInstanceAs hdus0[0].data.green + hdus1[0].data.green.forEachIndexed { i, value -> value shouldBeExactly hdus0[0].data.green[i] } + hdus1[0].data.blue shouldNotBeSameInstanceAs hdus0[0].data.blue + hdus1[0].data.blue.forEachIndexed { i, value -> value shouldBeExactly hdus0[0].data.blue[i] } + + val bitpix = hdus1[0].header.bitpix + val image = hdus1[0].makeImage() + image.save("fits-to-xisf-color-$bitpix").second shouldBe "18fb83e240bc7a4cbafbc1aba2741db6" + } + } + "xisf-to-fits:mono" { + val formats = arrayOf(M82_MONO_8_XISF, M82_MONO_16_XISF, M82_MONO_32_XISF, M82_MONO_F32_XISF, M82_MONO_F64_XISF) + + for (format in formats) { + val source0 = closeAfterEach(format.seekableSource()) + val hdus0 = XisfFormat.read(source0) + + hdus0 shouldHaveSize 1 + + val outputPath = tempfile() + val sink = closeAfterEach(outputPath.seekableSink()) + FitsFormat.write(sink, hdus0) + + val source1 = closeAfterEach(outputPath.seekableSource()) + val hdus1 = FitsFormat.read(source1).filterIsInstance() + + hdus1 shouldHaveSize 1 + hdus1[0].data.numberOfChannels shouldBeExactly 1 + // hdus1[0].header.size shouldBeExactly hdus0[0].header.size + hdus1[0].data.red.size shouldBeExactly hdus0[0].data.red.size + hdus1[0].data.red shouldNotBeSameInstanceAs hdus0[0].data.red + hdus1[0].data.red.forEachIndexed { i, value -> value shouldBeExactly hdus0[0].data.red[i] } + + val bitpix = hdus1[0].header.bitpix + val image = hdus1[0].makeImage() + image.save("xisf-to-fits-mono-$bitpix").second shouldBe "0dca7efedef5b3525f8037f401518b0b" + } + } + "xisf-to-fits:color" { + val formats = arrayOf(M82_COLOR_8_XISF, M82_COLOR_16_XISF, M82_COLOR_32_XISF, M82_COLOR_F32_XISF, M82_COLOR_F64_XISF) + + for (format in formats) { + val source0 = closeAfterEach(format.seekableSource()) + val hdus0 = XisfFormat.read(source0) + + hdus0 shouldHaveSize 1 + + val outputPath = tempfile() + val sink = closeAfterEach(outputPath.seekableSink()) + FitsFormat.write(sink, hdus0) + + val source1 = closeAfterEach(outputPath.seekableSource()) + val hdus1 = FitsFormat.read(source1).filterIsInstance() + + hdus1 shouldHaveSize 1 + hdus1[0].data.numberOfChannels shouldBeExactly 3 + // hdus1[0].header.size shouldBeExactly hdus0[0].header.size + hdus1[0].data.red.size shouldBeExactly hdus0[0].data.red.size + hdus1[0].data.red shouldNotBeSameInstanceAs hdus0[0].data.red + hdus1[0].data.red.forEachIndexed { i, value -> value shouldBeExactly hdus0[0].data.red[i] } + hdus1[0].data.green shouldNotBeSameInstanceAs hdus0[0].data.green + hdus1[0].data.green.forEachIndexed { i, value -> value shouldBeExactly hdus0[0].data.green[i] } + hdus1[0].data.blue shouldNotBeSameInstanceAs hdus0[0].data.blue + hdus1[0].data.blue.forEachIndexed { i, value -> value shouldBeExactly hdus0[0].data.blue[i] } + + val bitpix = hdus1[0].header.bitpix + val image = hdus1[0].makeImage() + image.save("xisf-to-fits-color-$bitpix").second shouldBe "89beed384ee9e97ce033ba447a377937" + } } } diff --git a/nebulosa-xisf/src/test/kotlin/XisfHeaderInputStreamTest.kt b/nebulosa-xisf/src/test/kotlin/XisfHeaderInputStreamTest.kt index 83f9e6764..a5943e1a2 100644 --- a/nebulosa-xisf/src/test/kotlin/XisfHeaderInputStreamTest.kt +++ b/nebulosa-xisf/src/test/kotlin/XisfHeaderInputStreamTest.kt @@ -24,7 +24,7 @@ class XisfHeaderInputStreamTest : FitsStringSpec() { sampleFormat shouldBe XisfMonolithicFileHeader.SampleFormat.UINT8 colorSpace shouldBe XisfMonolithicFileHeader.ColorSpace.GRAY byteOrder shouldBe ByteOrder.LITTLE - keywords shouldHaveSize 17 + keywords shouldHaveSize 23 } } "read:8:gray:zlib" { @@ -40,7 +40,7 @@ class XisfHeaderInputStreamTest : FitsStringSpec() { colorSpace shouldBe XisfMonolithicFileHeader.ColorSpace.GRAY byteOrder shouldBe ByteOrder.LITTLE compressionFormat.shouldNotBeNull().type shouldBe XisfMonolithicFileHeader.CompressionType.ZLIB - keywords shouldHaveSize 17 + keywords shouldHaveSize 23 } } "read:8:gray:lz4" { @@ -56,7 +56,7 @@ class XisfHeaderInputStreamTest : FitsStringSpec() { colorSpace shouldBe XisfMonolithicFileHeader.ColorSpace.GRAY byteOrder shouldBe ByteOrder.LITTLE compressionFormat.shouldNotBeNull().type shouldBe XisfMonolithicFileHeader.CompressionType.LZ4 - keywords shouldHaveSize 17 + keywords shouldHaveSize 23 } } "read:8:gray:lz4-hc" { @@ -72,7 +72,7 @@ class XisfHeaderInputStreamTest : FitsStringSpec() { colorSpace shouldBe XisfMonolithicFileHeader.ColorSpace.GRAY byteOrder shouldBe ByteOrder.LITTLE compressionFormat.shouldNotBeNull().type shouldBe XisfMonolithicFileHeader.CompressionType.LZ4_HC - keywords shouldHaveSize 17 + keywords shouldHaveSize 23 } } "read:8:gray:zstd" { @@ -88,7 +88,7 @@ class XisfHeaderInputStreamTest : FitsStringSpec() { colorSpace shouldBe XisfMonolithicFileHeader.ColorSpace.GRAY byteOrder shouldBe ByteOrder.LITTLE compressionFormat.shouldNotBeNull().type shouldBe XisfMonolithicFileHeader.CompressionType.ZSTD - keywords shouldHaveSize 17 + keywords shouldHaveSize 23 } } "read:16:gray" { @@ -103,7 +103,7 @@ class XisfHeaderInputStreamTest : FitsStringSpec() { sampleFormat shouldBe XisfMonolithicFileHeader.SampleFormat.UINT16 colorSpace shouldBe XisfMonolithicFileHeader.ColorSpace.GRAY byteOrder shouldBe ByteOrder.LITTLE - keywords shouldHaveSize 17 + keywords shouldHaveSize 23 } } "read:32:gray" { @@ -118,7 +118,7 @@ class XisfHeaderInputStreamTest : FitsStringSpec() { sampleFormat shouldBe XisfMonolithicFileHeader.SampleFormat.UINT32 colorSpace shouldBe XisfMonolithicFileHeader.ColorSpace.GRAY byteOrder shouldBe ByteOrder.LITTLE - keywords shouldHaveSize 17 + keywords shouldHaveSize 23 } } "read:F32:gray" { @@ -133,7 +133,7 @@ class XisfHeaderInputStreamTest : FitsStringSpec() { sampleFormat shouldBe XisfMonolithicFileHeader.SampleFormat.FLOAT32 colorSpace shouldBe XisfMonolithicFileHeader.ColorSpace.GRAY byteOrder shouldBe ByteOrder.LITTLE - keywords shouldHaveSize 17 + keywords shouldHaveSize 23 } } "read:F64:gray" { @@ -148,7 +148,7 @@ class XisfHeaderInputStreamTest : FitsStringSpec() { sampleFormat shouldBe XisfMonolithicFileHeader.SampleFormat.FLOAT64 colorSpace shouldBe XisfMonolithicFileHeader.ColorSpace.GRAY byteOrder shouldBe ByteOrder.LITTLE - keywords shouldHaveSize 17 + keywords shouldHaveSize 23 } } "read:8:rgb" { @@ -163,7 +163,7 @@ class XisfHeaderInputStreamTest : FitsStringSpec() { sampleFormat shouldBe XisfMonolithicFileHeader.SampleFormat.UINT8 colorSpace shouldBe XisfMonolithicFileHeader.ColorSpace.RGB byteOrder shouldBe ByteOrder.LITTLE - keywords shouldHaveSize 17 + keywords shouldHaveSize 24 } } "read:16:rgb" { @@ -178,7 +178,7 @@ class XisfHeaderInputStreamTest : FitsStringSpec() { sampleFormat shouldBe XisfMonolithicFileHeader.SampleFormat.UINT16 colorSpace shouldBe XisfMonolithicFileHeader.ColorSpace.RGB byteOrder shouldBe ByteOrder.LITTLE - keywords shouldHaveSize 17 + keywords shouldHaveSize 24 } } "read:32:rgb" { @@ -193,7 +193,7 @@ class XisfHeaderInputStreamTest : FitsStringSpec() { sampleFormat shouldBe XisfMonolithicFileHeader.SampleFormat.UINT32 colorSpace shouldBe XisfMonolithicFileHeader.ColorSpace.RGB byteOrder shouldBe ByteOrder.LITTLE - keywords shouldHaveSize 17 + keywords shouldHaveSize 24 } } "read:F32:rgb" { @@ -208,7 +208,7 @@ class XisfHeaderInputStreamTest : FitsStringSpec() { sampleFormat shouldBe XisfMonolithicFileHeader.SampleFormat.FLOAT32 colorSpace shouldBe XisfMonolithicFileHeader.ColorSpace.RGB byteOrder shouldBe ByteOrder.LITTLE - keywords shouldHaveSize 17 + keywords shouldHaveSize 24 } } "read:F64:rgb" { @@ -223,7 +223,7 @@ class XisfHeaderInputStreamTest : FitsStringSpec() { sampleFormat shouldBe XisfMonolithicFileHeader.SampleFormat.FLOAT64 colorSpace shouldBe XisfMonolithicFileHeader.ColorSpace.RGB byteOrder shouldBe ByteOrder.LITTLE - keywords shouldHaveSize 17 + keywords shouldHaveSize 24 } } } From d886ba7f2fe9b268764af9290cf77dc06c65e3c8 Mon Sep 17 00:00:00 2001 From: tiagohm Date: Mon, 1 Apr 2024 19:25:40 -0300 Subject: [PATCH 14/15] [api]: Implement XISF read/write --- .../nebulosa/api/mounts/MountService.kt | 2 - .../main/kotlin/nebulosa/fits/FitsFormat.kt | 9 +- nebulosa-fits/src/test/kotlin/FitsReadTest.kt | 4 +- .../src/test/kotlin/FitsWriteTest.kt | 4 +- .../test/kotlin/ComputationAlgorithmTest.kt | 4 +- .../test/kotlin/FitsTransformAlgorithmTest.kt | 12 +- nebulosa-image/src/test/kotlin/HFDTest.kt | 7 +- .../test/kotlin/XisfTransformAlgorithmTest.kt | 12 +- nebulosa-nova/src/test/kotlin/ICRFTest.kt | 5 +- .../nebulosa/test/AbstractFitsAndXisfTest.kt | 233 ++++++++++++++++++ .../kotlin/nebulosa/test/FitsStringSpec.kt | 162 ------------ .../nebulosa/test/Hips2FitsStringSpec.kt | 43 ---- .../src/test/kotlin/TAIMinusUTCTest.kt | 2 +- ...DBMinusTTByFairheadAndBretagnon1990Test.kt | 2 +- .../src/test/kotlin/WatnetPlateSolverTest.kt | 7 +- .../src/test/kotlin/WatneyStarDetectorTest.kt | 6 +- .../nebulosa/xisf/XisfHeaderInputStream.kt | 36 ++- .../nebulosa/xisf/XisfMonolithicFileHeader.kt | 2 + .../xisf/XisfMonolithicFileHeaderImageData.kt | 17 +- .../xisf/XisfMonolithicFileHeaderImageHdu.kt | 1 - .../src/test/kotlin/XisfFormatTest.kt | 71 ++---- .../test/kotlin/XisfHeaderInputStreamTest.kt | 4 +- 22 files changed, 336 insertions(+), 309 deletions(-) create mode 100644 nebulosa-test/src/main/kotlin/nebulosa/test/AbstractFitsAndXisfTest.kt delete mode 100644 nebulosa-test/src/main/kotlin/nebulosa/test/FitsStringSpec.kt delete mode 100644 nebulosa-test/src/main/kotlin/nebulosa/test/Hips2FitsStringSpec.kt diff --git a/api/src/main/kotlin/nebulosa/api/mounts/MountService.kt b/api/src/main/kotlin/nebulosa/api/mounts/MountService.kt index c97723dbe..9843904c0 100644 --- a/api/src/main/kotlin/nebulosa/api/mounts/MountService.kt +++ b/api/src/main/kotlin/nebulosa/api/mounts/MountService.kt @@ -16,8 +16,6 @@ import nebulosa.nova.position.GeographicPosition import nebulosa.nova.position.Geoid import nebulosa.nova.position.ICRF import nebulosa.time.CurrentTime -import nebulosa.time.TimeJD -import nebulosa.time.UTC import nebulosa.wcs.WCS import org.greenrobot.eventbus.Subscribe import org.greenrobot.eventbus.ThreadMode diff --git a/nebulosa-fits/src/main/kotlin/nebulosa/fits/FitsFormat.kt b/nebulosa-fits/src/main/kotlin/nebulosa/fits/FitsFormat.kt index 0b9cf274c..95e648f7a 100644 --- a/nebulosa-fits/src/main/kotlin/nebulosa/fits/FitsFormat.kt +++ b/nebulosa-fits/src/main/kotlin/nebulosa/fits/FitsFormat.kt @@ -123,7 +123,7 @@ data object FitsFormat : ImageFormat { Buffer().use { buffer -> for (channel in 0 until data.numberOfChannels) { for (i in 0 until data.numberOfPixels) { - buffer.writePixel(channels[0][i], bitpix) + buffer.writePixel(channels[channel][i], bitpix) if (buffer.size >= 1024L) { byteCount += buffer.readAll(sink) @@ -131,6 +131,7 @@ data object FitsFormat : ImageFormat { } } + byteCount += buffer.readAll(sink) val remainingBytes = computeRemainingBytesToSkip(byteCount) if (remainingBytes > 0) { @@ -165,9 +166,9 @@ data object FitsFormat : ImageFormat { internal fun Buffer.writePixel(pixel: Float, bitpix: Bitpix) { when (bitpix) { Bitpix.BYTE -> writeByte((pixel * 255f).toInt()) - Bitpix.SHORT -> writeShort((pixel * 65535f).toInt()) - Bitpix.INTEGER -> writeInt((pixel * 4294967295.0).toInt()) - Bitpix.LONG -> TODO("Unsupported UInt64 sample format") + Bitpix.SHORT -> writeShort((pixel * 65535f).toInt() - 32768) + Bitpix.INTEGER -> writeInt(((pixel * 4294967295.0).toLong() - 2147483648L).toInt()) + Bitpix.LONG -> TODO("Unsupported 64-bit format") Bitpix.FLOAT -> writeFloat(pixel) Bitpix.DOUBLE -> writeDouble(pixel.toDouble()) } diff --git a/nebulosa-fits/src/test/kotlin/FitsReadTest.kt b/nebulosa-fits/src/test/kotlin/FitsReadTest.kt index a1685a3f3..ce38e8d58 100644 --- a/nebulosa-fits/src/test/kotlin/FitsReadTest.kt +++ b/nebulosa-fits/src/test/kotlin/FitsReadTest.kt @@ -4,9 +4,9 @@ import nebulosa.fits.Bitpix import nebulosa.fits.bitpix import nebulosa.fits.fits import nebulosa.image.format.ImageHdu -import nebulosa.test.FitsStringSpec +import nebulosa.test.AbstractFitsAndXisfTest -class FitsReadTest : FitsStringSpec() { +class FitsReadTest : AbstractFitsAndXisfTest() { init { "mono:8-bit" { diff --git a/nebulosa-fits/src/test/kotlin/FitsWriteTest.kt b/nebulosa-fits/src/test/kotlin/FitsWriteTest.kt index 0e2f60cd2..f455b85c5 100644 --- a/nebulosa-fits/src/test/kotlin/FitsWriteTest.kt +++ b/nebulosa-fits/src/test/kotlin/FitsWriteTest.kt @@ -4,10 +4,10 @@ import nebulosa.fits.fits import nebulosa.image.format.ImageHdu import nebulosa.io.sink import nebulosa.io.source -import nebulosa.test.FitsStringSpec +import nebulosa.test.AbstractFitsAndXisfTest import okio.ByteString.Companion.toByteString -class FitsWriteTest : FitsStringSpec() { +class FitsWriteTest : AbstractFitsAndXisfTest() { init { "mono" { diff --git a/nebulosa-image/src/test/kotlin/ComputationAlgorithmTest.kt b/nebulosa-image/src/test/kotlin/ComputationAlgorithmTest.kt index 76566dc9e..1ade07c95 100644 --- a/nebulosa-image/src/test/kotlin/ComputationAlgorithmTest.kt +++ b/nebulosa-image/src/test/kotlin/ComputationAlgorithmTest.kt @@ -7,9 +7,9 @@ import nebulosa.image.Image import nebulosa.image.algorithms.computation.MedianAbsoluteDeviation import nebulosa.image.algorithms.computation.Statistics import nebulosa.image.format.ImageChannel -import nebulosa.test.FitsStringSpec +import nebulosa.test.AbstractFitsAndXisfTest -class ComputationAlgorithmTest : FitsStringSpec() { +class ComputationAlgorithmTest : AbstractFitsAndXisfTest() { init { "mono:median absolute deviation" { diff --git a/nebulosa-image/src/test/kotlin/FitsTransformAlgorithmTest.kt b/nebulosa-image/src/test/kotlin/FitsTransformAlgorithmTest.kt index 504a9cf05..855fc06ea 100644 --- a/nebulosa-image/src/test/kotlin/FitsTransformAlgorithmTest.kt +++ b/nebulosa-image/src/test/kotlin/FitsTransformAlgorithmTest.kt @@ -9,9 +9,9 @@ import nebulosa.image.Image import nebulosa.image.algorithms.transformation.* import nebulosa.image.algorithms.transformation.convolution.* import nebulosa.image.format.ImageChannel -import nebulosa.test.FitsStringSpec +import nebulosa.test.AbstractFitsAndXisfTest -class FitsTransformAlgorithmTest : FitsStringSpec() { +class FitsTransformAlgorithmTest : AbstractFitsAndXisfTest() { init { "mono:raw" { @@ -278,23 +278,23 @@ class FitsTransformAlgorithmTest : FitsStringSpec() { nImage.save("fits-color-grayscale-y").second shouldBe "24dd4a7e0fa9e4be34c53c924a78a940" } "color:debayer" { - val mImage = Image.open(DEBAYER_FITS_PATH.fits()) + val mImage = Image.open(DEBAYER_FITS.fits()) val nImage = mImage.transform(AutoScreenTransformFunction) nImage.save("fits-color-debayer").second shouldBe "86b5bdd67dfd6bbf5495afae4bf2bc04" } "color:no-debayer" { - val mImage = Image.open(DEBAYER_FITS_PATH.fits(), false) + val mImage = Image.open(DEBAYER_FITS.fits(), false) val nImage = mImage.transform(AutoScreenTransformFunction) nImage.save("fits-color-no-debayer").second shouldBe "958ccea020deec1f0c075042a9ba37c3" } "color:reload" { val mImage0 = Image.open(NGC3344_COLOR_32_FITS.fits()) - var mImage1 = Image.open(DEBAYER_FITS_PATH.fits()) + var mImage1 = Image.open(DEBAYER_FITS.fits()) mImage1.load(mImage0.hdu).shouldNotBeNull() mImage1.save("fits-color-reload").second shouldBe "18fb83e240bc7a4cbafbc1aba2741db6" - mImage1 = Image.open(DEBAYER_FITS_PATH.fits(), false) + mImage1 = Image.open(DEBAYER_FITS.fits(), false) mImage1.load(mImage0.hdu).shouldBeNull() mImage0.load(mImage1.hdu).shouldBeNull() diff --git a/nebulosa-image/src/test/kotlin/HFDTest.kt b/nebulosa-image/src/test/kotlin/HFDTest.kt index 8cffda51d..c5f4305a8 100644 --- a/nebulosa-image/src/test/kotlin/HFDTest.kt +++ b/nebulosa-image/src/test/kotlin/HFDTest.kt @@ -1,10 +1,11 @@ import io.kotest.matchers.floats.plusOrMinus import io.kotest.matchers.shouldBe +import nebulosa.fits.fits import nebulosa.image.Image import nebulosa.image.algorithms.computation.hfd.HFD -import nebulosa.test.FitsStringSpec +import nebulosa.test.AbstractFitsAndXisfTest -class HFDTest : FitsStringSpec() { +class HFDTest : AbstractFitsAndXisfTest() { init { "focus" { @@ -29,7 +30,7 @@ class HFDTest : FitsStringSpec() { ) for ((first, second) in starFocus) { - val focusImage = Image.open(first) + val focusImage = Image.open(closeAfterEach(first.fits())) val star = focusImage.compute(HFD(focusImage.width / 2, focusImage.height / 2, 50)) star.hfd shouldBe (second[0] plusOrMinus 0.1f) star.snr shouldBe (second[1] plusOrMinus 0.1f) diff --git a/nebulosa-image/src/test/kotlin/XisfTransformAlgorithmTest.kt b/nebulosa-image/src/test/kotlin/XisfTransformAlgorithmTest.kt index a3ef8d1c7..a50872f8a 100644 --- a/nebulosa-image/src/test/kotlin/XisfTransformAlgorithmTest.kt +++ b/nebulosa-image/src/test/kotlin/XisfTransformAlgorithmTest.kt @@ -8,10 +8,10 @@ import nebulosa.image.Image import nebulosa.image.algorithms.transformation.* import nebulosa.image.algorithms.transformation.convolution.* import nebulosa.image.format.ImageChannel -import nebulosa.test.FitsStringSpec +import nebulosa.test.AbstractFitsAndXisfTest import nebulosa.xisf.xisf -class XisfTransformAlgorithmTest : FitsStringSpec() { +class XisfTransformAlgorithmTest : AbstractFitsAndXisfTest() { init { "mono:raw" { @@ -278,23 +278,23 @@ class XisfTransformAlgorithmTest : FitsStringSpec() { nImage.save("xisf-color-grayscale-y").second shouldBe "7a2bef966d460742533a1c8c3a74f1c5" } "!color:debayer" { - val mImage = Image.open(DEBAYER_FITS_PATH.xisf()) + val mImage = Image.open(DEBAYER_FITS.xisf()) val nImage = mImage.transform(AutoScreenTransformFunction) nImage.save("xisf-color-debayer").second shouldBe "86b5bdd67dfd6bbf5495afae4bf2bc04" } "!color:no-debayer" { - val mImage = Image.open(DEBAYER_FITS_PATH.xisf(), false) + val mImage = Image.open(DEBAYER_FITS.xisf(), false) val nImage = mImage.transform(AutoScreenTransformFunction) nImage.save("xisf-color-no-debayer").second shouldBe "958ccea020deec1f0c075042a9ba37c3" } "!color:reload" { val mImage0 = Image.open(M82_COLOR_32_XISF.xisf()) - var mImage1 = Image.open(DEBAYER_FITS_PATH.xisf()) + var mImage1 = Image.open(DEBAYER_FITS.xisf()) mImage1.load(mImage0.hdu).shouldNotBeNull() mImage1.save("xisf-color-reload").second shouldBe "18fb83e240bc7a4cbafbc1aba2741db6" - mImage1 = Image.open(DEBAYER_FITS_PATH.xisf(), false) + mImage1 = Image.open(DEBAYER_FITS.xisf(), false) mImage1.load(mImage0.hdu).shouldBeNull() mImage0.load(mImage1.hdu).shouldBeNull() diff --git a/nebulosa-nova/src/test/kotlin/ICRFTest.kt b/nebulosa-nova/src/test/kotlin/ICRFTest.kt index ba3229db0..8725481cc 100644 --- a/nebulosa-nova/src/test/kotlin/ICRFTest.kt +++ b/nebulosa-nova/src/test/kotlin/ICRFTest.kt @@ -4,7 +4,10 @@ import io.kotest.matchers.shouldBe import nebulosa.math.* import nebulosa.nova.position.Geoid import nebulosa.nova.position.ICRF -import nebulosa.time.* +import nebulosa.time.IERS +import nebulosa.time.IERSA +import nebulosa.time.TT +import nebulosa.time.TimeYMDHMS import java.nio.file.Path import kotlin.io.path.inputStream diff --git a/nebulosa-test/src/main/kotlin/nebulosa/test/AbstractFitsAndXisfTest.kt b/nebulosa-test/src/main/kotlin/nebulosa/test/AbstractFitsAndXisfTest.kt new file mode 100644 index 000000000..7fda567c9 --- /dev/null +++ b/nebulosa-test/src/main/kotlin/nebulosa/test/AbstractFitsAndXisfTest.kt @@ -0,0 +1,233 @@ +package nebulosa.test + +import io.kotest.core.listeners.TestListener +import io.kotest.core.spec.style.StringSpec +import io.kotest.core.test.TestCase +import io.kotest.core.test.TestResult +import io.kotest.core.test.TestScope +import nebulosa.hips2fits.Hips2FitsService +import nebulosa.hips2fits.HipsSurvey +import nebulosa.image.format.ImageHdu +import nebulosa.io.transferAndCloseOutput +import nebulosa.math.Angle +import nebulosa.math.deg +import nebulosa.math.hours +import okhttp3.OkHttpClient +import okhttp3.Request +import okhttp3.logging.HttpLoggingInterceptor +import okio.ByteString.Companion.toByteString +import java.awt.image.BufferedImage +import java.awt.image.DataBufferByte +import java.awt.image.DataBufferInt +import java.io.Closeable +import java.nio.file.Path +import java.util.concurrent.ConcurrentHashMap +import java.util.concurrent.ConcurrentLinkedDeque +import java.util.concurrent.TimeUnit +import javax.imageio.ImageIO +import kotlin.io.path.* + +@Suppress("PropertyName") +abstract class AbstractFitsAndXisfTest : StringSpec() { + + protected val M82_MONO_8_LZ4_XISF by lazy { download("M82.Mono.8.LZ4.xisf", GITHUB_XISF_URL) } + protected val M82_MONO_8_LZ4_HC_XISF by lazy { download("M82.Mono.8.LZ4-HC.xisf", GITHUB_XISF_URL) } + protected val M82_MONO_8_XISF by lazy { download("M82.Mono.8.xisf", GITHUB_XISF_URL) } + protected val M82_MONO_8_ZLIB_XISF by lazy { download("M82.Mono.8.ZLib.xisf", GITHUB_XISF_URL) } + protected val M82_MONO_8_ZSTANDARD_XISF by lazy { download("M82.Mono.8.ZStandard.xisf", GITHUB_XISF_URL) } + protected val M82_MONO_16_XISF by lazy { download("M82.Mono.16.xisf", GITHUB_XISF_URL) } + protected val M82_MONO_32_XISF by lazy { download("M82.Mono.32.xisf", GITHUB_XISF_URL) } + protected val M82_MONO_F32_XISF by lazy { download("M82.Mono.F32.xisf", GITHUB_XISF_URL) } + protected val M82_MONO_F64_XISF by lazy { download("M82.Mono.F64.xisf", GITHUB_XISF_URL) } + + protected val M82_COLOR_8_LZ4_XISF by lazy { download("M82.Color.8.LZ4.xisf", GITHUB_XISF_URL) } + protected val M82_COLOR_8_LZ4_HC_XISF by lazy { download("M82.Color.8.LZ4-HC.xisf", GITHUB_XISF_URL) } + protected val M82_COLOR_8_XISF by lazy { download("M82.Color.8.xisf", GITHUB_XISF_URL) } + protected val M82_COLOR_8_ZLIB_XISF by lazy { download("M82.Color.8.ZLib.xisf", GITHUB_XISF_URL) } + protected val M82_COLOR_8_ZSTANDARD_XISF by lazy { download("M82.Color.8.ZStandard.xisf", GITHUB_XISF_URL) } + protected val M82_COLOR_16_XISF by lazy { download("M82.Color.16.xisf", GITHUB_XISF_URL) } + protected val M82_COLOR_32_XISF by lazy { download("M82.Color.32.xisf", GITHUB_XISF_URL) } + protected val M82_COLOR_F32_XISF by lazy { download("M82.Color.F32.xisf", GITHUB_XISF_URL) } + protected val M82_COLOR_F64_XISF by lazy { download("M82.Color.F64.xisf", GITHUB_XISF_URL) } + protected val DEBAYER_XISF_PATH by lazy { download("Debayer.xisf", GITHUB_XISF_URL) } + + protected val NGC3344_MONO_8_FITS by lazy { download("NGC3344.Mono.8.fits", GITHUB_FITS_URL) } + protected val NGC3344_MONO_16_FITS by lazy { download("NGC3344.Mono.16.fits", GITHUB_FITS_URL) } + protected val NGC3344_MONO_32_FITS by lazy { download("NGC3344.Mono.32.fits", GITHUB_FITS_URL) } + protected val NGC3344_MONO_F32_FITS by lazy { download("NGC3344.Mono.F32.fits", GITHUB_FITS_URL) } + protected val NGC3344_MONO_F64_FITS by lazy { download("NGC3344.Mono.F64.fits", GITHUB_FITS_URL) } + + protected val NGC3344_COLOR_8_FITS by lazy { download("NGC3344.Color.8.fits", GITHUB_FITS_URL) } + protected val NGC3344_COLOR_16_FITS by lazy { download("NGC3344.Color.16.fits", GITHUB_FITS_URL) } + protected val NGC3344_COLOR_32_FITS by lazy { download("NGC3344.Color.32.fits", GITHUB_FITS_URL) } + protected val NGC3344_COLOR_F32_FITS by lazy { download("NGC3344.Color.F32.fits", GITHUB_FITS_URL) } + protected val NGC3344_COLOR_F64_FITS by lazy { download("NGC3344.Color.F64.fits", GITHUB_FITS_URL) } + + protected val PALETTE_MONO_8_FITS by lazy { download("PALETTE.Mono.8.fits", GITHUB_FITS_URL) } + protected val PALETTE_MONO_16_FITS by lazy { download("PALETTE.Mono.16.fits", GITHUB_FITS_URL) } + protected val PALETTE_MONO_32_FITS by lazy { download("PALETTE.Mono.32.fits", GITHUB_FITS_URL) } + protected val PALETTE_MONO_F32_FITS by lazy { download("PALETTE.Mono.F32.fits", GITHUB_FITS_URL) } + protected val PALETTE_MONO_F64_FITS by lazy { download("PALETTE.Mono.F64.fits", GITHUB_FITS_URL) } + + protected val PALETTE_COLOR_8_FITS by lazy { download("PALETTE.Color.8.fits", GITHUB_FITS_URL) } + protected val PALETTE_COLOR_16_FITS by lazy { download("PALETTE.Color.16.fits", GITHUB_FITS_URL) } + protected val PALETTE_COLOR_32_FITS by lazy { download("PALETTE.Color.32.fits", GITHUB_FITS_URL) } + protected val PALETTE_COLOR_F32_FITS by lazy { download("PALETTE.Color.F32.fits", GITHUB_FITS_URL) } + protected val PALETTE_COLOR_F64_FITS by lazy { download("PALETTE.Color.F64.fits", GITHUB_FITS_URL) } + + protected val PALETTE_MONO_8_XISF by lazy { download("PALETTE.Mono.8.xisf", GITHUB_XISF_URL) } + protected val PALETTE_MONO_16_XISF by lazy { download("PALETTE.Mono.16.xisf", GITHUB_XISF_URL) } + protected val PALETTE_MONO_32_XISF by lazy { download("PALETTE.Mono.32.xisf", GITHUB_XISF_URL) } + protected val PALETTE_MONO_F32_XISF by lazy { download("PALETTE.Mono.F32.xisf", GITHUB_XISF_URL) } + protected val PALETTE_MONO_F64_XISF by lazy { download("PALETTE.Mono.F64.xisf", GITHUB_XISF_URL) } + + protected val PALETTE_COLOR_8_XISF by lazy { download("PALETTE.Color.8.xisf", GITHUB_XISF_URL) } + protected val PALETTE_COLOR_16_XISF by lazy { download("PALETTE.Color.16.xisf", GITHUB_XISF_URL) } + protected val PALETTE_COLOR_32_XISF by lazy { download("PALETTE.Color.32.xisf", GITHUB_XISF_URL) } + protected val PALETTE_COLOR_F32_XISF by lazy { download("PALETTE.Color.F32.xisf", GITHUB_XISF_URL) } + protected val PALETTE_COLOR_F64_XISF by lazy { download("PALETTE.Color.F64.xisf", GITHUB_XISF_URL) } + + protected val DEBAYER_FITS by lazy { download("Debayer.fits", GITHUB_FITS_URL) } + protected val M6707HH by lazy { download("M6707HH.fits", ASTROPY_PHOTOMETRY_URL) } + protected val M31_FITS by lazy { download("00 42 44.3".hours, "41 16 9".deg, 3.deg) } + + protected val STAR_FOCUS_1 by lazy { download("STAR.FOCUS.1.fits", GITHUB_FITS_URL) } + protected val STAR_FOCUS_2 by lazy { download("STAR.FOCUS.2.fits", GITHUB_FITS_URL) } + protected val STAR_FOCUS_3 by lazy { download("STAR.FOCUS.3.fits", GITHUB_FITS_URL) } + protected val STAR_FOCUS_4 by lazy { download("STAR.FOCUS.4.fits", GITHUB_FITS_URL) } + protected val STAR_FOCUS_5 by lazy { download("STAR.FOCUS.5.fits", GITHUB_FITS_URL) } + protected val STAR_FOCUS_6 by lazy { download("STAR.FOCUS.6.fits", GITHUB_FITS_URL) } + protected val STAR_FOCUS_7 by lazy { download("STAR.FOCUS.7.fits", GITHUB_FITS_URL) } + protected val STAR_FOCUS_8 by lazy { download("STAR.FOCUS.8.fits", GITHUB_FITS_URL) } + protected val STAR_FOCUS_9 by lazy { download("STAR.FOCUS.9.fits", GITHUB_FITS_URL) } + protected val STAR_FOCUS_10 by lazy { download("STAR.FOCUS.10.fits", GITHUB_FITS_URL) } + protected val STAR_FOCUS_11 by lazy { download("STAR.FOCUS.11.fits", GITHUB_FITS_URL) } + protected val STAR_FOCUS_12 by lazy { download("STAR.FOCUS.12.fits", GITHUB_FITS_URL) } + protected val STAR_FOCUS_13 by lazy { download("STAR.FOCUS.13.fits", GITHUB_FITS_URL) } + protected val STAR_FOCUS_14 by lazy { download("STAR.FOCUS.14.fits", GITHUB_FITS_URL) } + protected val STAR_FOCUS_15 by lazy { download("STAR.FOCUS.15.fits", GITHUB_FITS_URL) } + protected val STAR_FOCUS_16 by lazy { download("STAR.FOCUS.16.fits", GITHUB_FITS_URL) } + protected val STAR_FOCUS_17 by lazy { download("STAR.FOCUS.17.fits", GITHUB_FITS_URL) } + + private val afterEach = AfterEach() + + init { + prependExtension(afterEach) + } + + protected fun TestScope.closeAfterEach(closeable: T) = closeable.apply { + afterEach.add(testCase to this) + } + + protected fun BufferedImage.save(name: String): Pair { + val path = Path.of("..", "data", "test", "$name.png").createParentDirectories() + ImageIO.write(this, "PNG", path.toFile()) + val md5 = path.md5() + println("$name: $md5") + return path to md5 + } + + protected fun ByteArray.md5(): String { + return toByteString().md5().hex() + } + + protected fun Path.md5(): String { + return readBytes().md5() + } + + protected fun download(name: String, baseUrl: String): Path { + return synchronize(name) { + val path = Path.of(System.getProperty("java.io.tmpdir"), name) + + if (!path.exists() || path.fileSize() <= 0L) { + val request = Request.Builder() + .get() + .url("$baseUrl/$name") + .build() + + val call = HTTP_CLIENT.newCall(request) + + call.execute().use { + it.body?.byteStream()?.transferAndCloseOutput(path.outputStream()) + } + } + + path + } + } + + protected fun download(centerRA: Angle, centerDEC: Angle, fov: Angle): Path { + val name = "$centerRA@$centerDEC@$fov".toByteArray().md5() + + return synchronize(name) { + val path = Path.of(System.getProperty("java.io.tmpdir"), name) + + if (!path.exists() || path.fileSize() <= 0L) { + HIPS_SERVICE + .query(CDS_P_DSS2_NIR.id, centerRA, centerDEC, 1280, 720, 0.0, fov) + .execute() + .body()!! + .use { it.byteStream().transferAndCloseOutput(path.outputStream()) } + } + + path + } + } + + protected fun ImageHdu.makeImage(): BufferedImage { + val type = if (numberOfChannels == 1) BufferedImage.TYPE_BYTE_GRAY else BufferedImage.TYPE_INT_RGB + val image = BufferedImage(width, height, type) + val numberOfPixels = data.numberOfPixels + + if (numberOfChannels == 1) { + val buffer = (image.raster.dataBuffer as DataBufferByte).data + + repeat(numberOfPixels) { + buffer[it] = (data.red[it] * 255f).toInt().toByte() + } + } else { + val buffer = (image.raster.dataBuffer as DataBufferInt).data + + repeat(numberOfPixels) { + val red = (data.red[it] * 255f).toInt() and 0xFF + val green = (data.green[it] * 255f).toInt() and 0xFF + val blue = (data.blue[it] * 255f).toInt() and 0xFF + buffer[it] = blue or (green shl 8) or (red shl 16) + } + } + + return image + } + + @Suppress("BlockingMethodInNonBlockingContext") + private class AfterEach : ConcurrentLinkedDeque>(), TestListener { + + override suspend fun afterEach(testCase: TestCase, result: TestResult) { + find { it.first === testCase }?.second?.close() ?: return + } + } + + companion object { + + const val ASTROPY_PHOTOMETRY_URL = "https://www.astropy.org/astropy-data/photometry" + const val GITHUB_FITS_URL = "https://github.com/tiagohm/nebulosa.data/raw/main/test/fits" + const val GITHUB_XISF_URL = "https://github.com/tiagohm/nebulosa.data/raw/main/test/xisf" + + @JvmStatic val HTTP_CLIENT = OkHttpClient.Builder() + .readTimeout(60L, TimeUnit.SECONDS) + .writeTimeout(60L, TimeUnit.SECONDS) + .connectTimeout(60L, TimeUnit.SECONDS) + .callTimeout(60L, TimeUnit.SECONDS) + .addInterceptor(HttpLoggingInterceptor().setLevel(HttpLoggingInterceptor.Level.BASIC)) + .build() + + @JvmStatic val HIPS_SERVICE = Hips2FitsService(httpClient = HTTP_CLIENT) + @JvmStatic val CDS_P_DSS2_NIR = HipsSurvey("CDS/P/DSS2/NIR") + @JvmStatic @PublishedApi internal val SYNC_KEYS = ConcurrentHashMap() + + inline fun synchronize(key: String, block: () -> R): R { + val lock = synchronized(SYNC_KEYS) { SYNC_KEYS.getOrPut(key) { Any() } } + return synchronized(lock, block) + } + } +} diff --git a/nebulosa-test/src/main/kotlin/nebulosa/test/FitsStringSpec.kt b/nebulosa-test/src/main/kotlin/nebulosa/test/FitsStringSpec.kt deleted file mode 100644 index 11e5464a3..000000000 --- a/nebulosa-test/src/main/kotlin/nebulosa/test/FitsStringSpec.kt +++ /dev/null @@ -1,162 +0,0 @@ -package nebulosa.test - -import io.kotest.core.listeners.TestListener -import io.kotest.core.spec.style.StringSpec -import io.kotest.core.test.TestCase -import io.kotest.core.test.TestResult -import io.kotest.core.test.TestScope -import nebulosa.fits.FitsPath -import nebulosa.fits.fits -import nebulosa.io.transferAndCloseOutput -import nebulosa.xisf.XisfPath -import nebulosa.xisf.xisf -import okhttp3.OkHttpClient -import okhttp3.Request -import okhttp3.logging.HttpLoggingInterceptor -import okio.ByteString.Companion.toByteString -import java.awt.image.BufferedImage -import java.io.Closeable -import java.nio.file.Path -import java.util.concurrent.ConcurrentHashMap -import java.util.concurrent.TimeUnit -import javax.imageio.ImageIO -import kotlin.io.path.* - -@Suppress("PropertyName") -abstract class FitsStringSpec : StringSpec() { - - protected val M82_MONO_8_LZ4_XISF by lazy { download("M82.Mono.8.LZ4.xisf", GITHUB_XISF_URL) } - protected val M82_MONO_8_LZ4_HC_XISF by lazy { download("M82.Mono.8.LZ4-HC.xisf", GITHUB_XISF_URL) } - protected val M82_MONO_8_XISF by lazy { download("M82.Mono.8.xisf", GITHUB_XISF_URL) } - protected val M82_MONO_8_ZLIB_XISF by lazy { download("M82.Mono.8.ZLib.xisf", GITHUB_XISF_URL) } - protected val M82_MONO_8_ZSTANDARD_XISF by lazy { download("M82.Mono.8.ZStandard.xisf", GITHUB_XISF_URL) } - protected val M82_MONO_16_XISF by lazy { download("M82.Mono.16.xisf", GITHUB_XISF_URL) } - protected val M82_MONO_32_XISF by lazy { download("M82.Mono.32.xisf", GITHUB_XISF_URL) } - protected val M82_MONO_F32_XISF by lazy { download("M82.Mono.F32.xisf", GITHUB_XISF_URL) } - protected val M82_MONO_F64_XISF by lazy { download("M82.Mono.F64.xisf", GITHUB_XISF_URL) } - - protected val M82_COLOR_8_LZ4_XISF by lazy { download("M82.Color.8.LZ4.xisf", GITHUB_XISF_URL) } - protected val M82_COLOR_8_LZ4_HC_XISF by lazy { download("M82.Color.8.LZ4-HC.xisf", GITHUB_XISF_URL) } - protected val M82_COLOR_8_XISF by lazy { download("M82.Color.8.xisf", GITHUB_XISF_URL) } - protected val M82_COLOR_8_ZLIB_XISF by lazy { download("M82.Color.8.ZLib.xisf", GITHUB_XISF_URL) } - protected val M82_COLOR_8_ZSTANDARD_XISF by lazy { download("M82.Color.8.ZStandard.xisf", GITHUB_XISF_URL) } - protected val M82_COLOR_16_XISF by lazy { download("M82.Color.16.xisf", GITHUB_XISF_URL) } - protected val M82_COLOR_32_XISF by lazy { download("M82.Color.32.xisf", GITHUB_XISF_URL) } - protected val M82_COLOR_F32_XISF by lazy { download("M82.Color.F32.xisf", GITHUB_XISF_URL) } - protected val M82_COLOR_F64_XISF by lazy { download("M82.Color.F64.xisf", GITHUB_XISF_URL) } - protected val DEBAYER_XISF_PATH by lazy { download("Debayer.xisf", GITHUB_XISF_URL) } - - protected val NGC3344_MONO_8_FITS by lazy { download("NGC3344.Mono.8.fits", GITHUB_FITS_URL) } - protected val NGC3344_MONO_16_FITS by lazy { download("NGC3344.Mono.16.fits", GITHUB_FITS_URL) } - protected val NGC3344_MONO_32_FITS by lazy { download("NGC3344.Mono.32.fits", GITHUB_FITS_URL) } - protected val NGC3344_MONO_F32_FITS by lazy { download("NGC3344.Mono.F32.fits", GITHUB_FITS_URL) } - protected val NGC3344_MONO_F64_FITS by lazy { download("NGC3344.Mono.F64.fits", GITHUB_FITS_URL) } - - protected val NGC3344_COLOR_8_FITS by lazy { download("NGC3344.Color.8.fits", GITHUB_FITS_URL) } - protected val NGC3344_COLOR_16_FITS by lazy { download("NGC3344.Color.16.fits", GITHUB_FITS_URL) } - protected val NGC3344_COLOR_32_FITS by lazy { download("NGC3344.Color.32.fits", GITHUB_FITS_URL) } - protected val NGC3344_COLOR_F32_FITS by lazy { download("NGC3344.Color.F32.fits", GITHUB_FITS_URL) } - protected val NGC3344_COLOR_F64_FITS by lazy { download("NGC3344.Color.F64.fits", GITHUB_FITS_URL) } - - protected val DEBAYER_FITS_PATH by lazy { download("Debayer.fits", GITHUB_FITS_URL) } - protected val M6707HH by lazyFITS("M6707HH.fits", ASTROPY_PHOTOMETRY_URL) - - protected val STAR_FOCUS_1 by lazyFITS("STAR.FOCUS.1.fits") - protected val STAR_FOCUS_2 by lazyFITS("STAR.FOCUS.2.fits") - protected val STAR_FOCUS_3 by lazyFITS("STAR.FOCUS.3.fits") - protected val STAR_FOCUS_4 by lazyFITS("STAR.FOCUS.4.fits") - protected val STAR_FOCUS_5 by lazyFITS("STAR.FOCUS.5.fits") - protected val STAR_FOCUS_6 by lazyFITS("STAR.FOCUS.6.fits") - protected val STAR_FOCUS_7 by lazyFITS("STAR.FOCUS.7.fits") - protected val STAR_FOCUS_8 by lazyFITS("STAR.FOCUS.8.fits") - protected val STAR_FOCUS_9 by lazyFITS("STAR.FOCUS.9.fits") - protected val STAR_FOCUS_10 by lazyFITS("STAR.FOCUS.10.fits") - protected val STAR_FOCUS_11 by lazyFITS("STAR.FOCUS.11.fits") - protected val STAR_FOCUS_12 by lazyFITS("STAR.FOCUS.12.fits") - protected val STAR_FOCUS_13 by lazyFITS("STAR.FOCUS.13.fits") - protected val STAR_FOCUS_14 by lazyFITS("STAR.FOCUS.14.fits") - protected val STAR_FOCUS_15 by lazyFITS("STAR.FOCUS.15.fits") - protected val STAR_FOCUS_16 by lazyFITS("STAR.FOCUS.16.fits") - protected val STAR_FOCUS_17 by lazyFITS("STAR.FOCUS.17.fits") - - private val afterEach = AfterEach() - - init { - prependExtension(afterEach) - } - - protected fun TestScope.closeAfterEach(closeable: T) = closeable.apply { - afterEach[testCase] = this - } - - protected fun BufferedImage.save(name: String): Pair { - val path = Path.of("..", "data", "test", "$name.png").createParentDirectories() - ImageIO.write(this, "PNG", path.toFile()) - val md5 = path.md5() - println("$name: $md5") - return path to md5 - } - - protected fun Path.md5(): String { - return readBytes().toByteString().md5().hex() - } - - protected fun lazyFITS(name: String, baseUrl: String = GITHUB_FITS_URL): Lazy { - return lazy { download(name, baseUrl).fits() } - } - - protected fun lazyXISF(name: String, baseUrl: String = GITHUB_XISF_URL): Lazy { - return lazy { download(name, baseUrl).xisf() } - } - - protected fun download(name: String, baseUrl: String): Path { - return synchronize(name) { - val path = Path.of(System.getProperty("java.io.tmpdir"), name) - - if (!path.exists() || path.fileSize() <= 0L) { - val request = Request.Builder() - .get() - .url("$baseUrl/$name") - .build() - - val call = HTTP_CLIENT.newCall(request) - - call.execute().use { - it.body?.byteStream()?.transferAndCloseOutput(path.outputStream()) - } - } - - path - } - } - - @Suppress("BlockingMethodInNonBlockingContext") - private class AfterEach : ConcurrentHashMap(), TestListener { - - override suspend fun afterEach(testCase: TestCase, result: TestResult) { - remove(testCase)?.close() - } - } - - companion object { - - const val ASTROPY_PHOTOMETRY_URL = "https://www.astropy.org/astropy-data/photometry" - const val GITHUB_FITS_URL = "https://github.com/tiagohm/nebulosa.data/raw/main/test/fits" - const val GITHUB_XISF_URL = "https://github.com/tiagohm/nebulosa.data/raw/main/test/xisf" - - @JvmStatic val HTTP_CLIENT = OkHttpClient.Builder() - .readTimeout(60L, TimeUnit.SECONDS) - .writeTimeout(60L, TimeUnit.SECONDS) - .connectTimeout(60L, TimeUnit.SECONDS) - .callTimeout(60L, TimeUnit.SECONDS) - .addInterceptor(HttpLoggingInterceptor().setLevel(HttpLoggingInterceptor.Level.BASIC)) - .build() - - @JvmStatic @PublishedApi internal val SYNC_KEYS = ConcurrentHashMap() - - inline fun synchronize(key: String, block: () -> R): R { - val lock = synchronized(SYNC_KEYS) { SYNC_KEYS.getOrPut(key) { Any() } } - return synchronized(lock, block) - } - } -} diff --git a/nebulosa-test/src/main/kotlin/nebulosa/test/Hips2FitsStringSpec.kt b/nebulosa-test/src/main/kotlin/nebulosa/test/Hips2FitsStringSpec.kt deleted file mode 100644 index 89f5715fa..000000000 --- a/nebulosa-test/src/main/kotlin/nebulosa/test/Hips2FitsStringSpec.kt +++ /dev/null @@ -1,43 +0,0 @@ -package nebulosa.test - -import nebulosa.fits.fits -import nebulosa.hips2fits.Hips2FitsService -import nebulosa.hips2fits.HipsSurvey -import nebulosa.io.transferAndCloseOutput -import nebulosa.math.Angle -import nebulosa.math.deg -import nebulosa.math.hours -import okio.ByteString.Companion.toByteString -import java.nio.file.Path -import kotlin.io.path.exists -import kotlin.io.path.fileSize -import kotlin.io.path.outputStream - -@Suppress("PropertyName") -abstract class Hips2FitsStringSpec : FitsStringSpec() { - - protected val M31 by lazy { download("00 42 44.3".hours, "41 16 9".deg, 3.deg).fits() } - - protected fun download(centerRA: Angle, centerDEC: Angle, fov: Angle): Path { - val name = "$centerRA@$centerDEC@$fov".toByteArray().toByteString().md5().hex() - val path = Path.of(System.getProperty("java.io.tmpdir"), name) - - if (path.exists() && path.fileSize() > 0L) { - return path - } - - HIPS_SERVICE - .query(CDS_P_DSS2_NIR.id, centerRA, centerDEC, 1280, 720, 0.0, fov) - .execute() - .body()!! - .use { it.byteStream().transferAndCloseOutput(path.outputStream()) } - - return path - } - - companion object { - - @JvmStatic val HIPS_SERVICE = Hips2FitsService(httpClient = HTTP_CLIENT) - @JvmStatic val CDS_P_DSS2_NIR = HipsSurvey("CDS/P/DSS2/NIR") - } -} diff --git a/nebulosa-time/src/test/kotlin/TAIMinusUTCTest.kt b/nebulosa-time/src/test/kotlin/TAIMinusUTCTest.kt index 2ed368ac6..28cbe7cc3 100644 --- a/nebulosa-time/src/test/kotlin/TAIMinusUTCTest.kt +++ b/nebulosa-time/src/test/kotlin/TAIMinusUTCTest.kt @@ -1,7 +1,7 @@ import io.kotest.core.spec.style.StringSpec import io.kotest.matchers.doubles.shouldBeExactly -import nebulosa.time.TimeDelta import nebulosa.time.TAIMinusUTC +import nebulosa.time.TimeDelta import nebulosa.time.TimeYMDHMS class TAIMinusUTCTest : StringSpec(), TimeDelta by TAIMinusUTC { diff --git a/nebulosa-time/src/test/kotlin/TDBMinusTTByFairheadAndBretagnon1990Test.kt b/nebulosa-time/src/test/kotlin/TDBMinusTTByFairheadAndBretagnon1990Test.kt index 1d88388e3..213306b9f 100644 --- a/nebulosa-time/src/test/kotlin/TDBMinusTTByFairheadAndBretagnon1990Test.kt +++ b/nebulosa-time/src/test/kotlin/TDBMinusTTByFairheadAndBretagnon1990Test.kt @@ -1,9 +1,9 @@ import io.kotest.core.spec.style.StringSpec import io.kotest.matchers.doubles.plusOrMinus import io.kotest.matchers.shouldBe -import nebulosa.time.TimeDelta import nebulosa.time.TDB import nebulosa.time.TDBMinusTTByFairheadAndBretagnon1990 +import nebulosa.time.TimeDelta class TDBMinusTTByFairheadAndBretagnon1990Test : StringSpec(), TimeDelta by TDBMinusTTByFairheadAndBretagnon1990 { diff --git a/nebulosa-watney/src/test/kotlin/WatnetPlateSolverTest.kt b/nebulosa-watney/src/test/kotlin/WatnetPlateSolverTest.kt index c669eaa33..552d408a6 100644 --- a/nebulosa-watney/src/test/kotlin/WatnetPlateSolverTest.kt +++ b/nebulosa-watney/src/test/kotlin/WatnetPlateSolverTest.kt @@ -3,9 +3,10 @@ import io.kotest.matchers.collections.shouldHaveSize import io.kotest.matchers.doubles.plusOrMinus import io.kotest.matchers.ints.shouldBeExactly import io.kotest.matchers.shouldBe +import nebulosa.fits.fits import nebulosa.image.Image import nebulosa.math.deg -import nebulosa.test.Hips2FitsStringSpec +import nebulosa.test.AbstractFitsAndXisfTest import nebulosa.test.NonGitHubOnlyCondition import nebulosa.watney.plate.solving.WatneyPlateSolver import nebulosa.watney.plate.solving.quad.CompactQuadDatabase @@ -13,7 +14,7 @@ import nebulosa.watney.star.detection.Star import java.nio.file.Path @EnabledIf(NonGitHubOnlyCondition::class) -class WatnetPlateSolverTest : Hips2FitsStringSpec() { +class WatnetPlateSolverTest : AbstractFitsAndXisfTest() { init { val quadDir = Path.of("/home/tiagohm/Downloads/watneyqdb") @@ -21,7 +22,7 @@ class WatnetPlateSolverTest : Hips2FitsStringSpec() { val solver = WatneyPlateSolver(quadDatabase) "blind" { - val image = Image.open(M31) + val image = Image.open(closeAfterEach(M31_FITS.fits())) println(solver.solve(null, image, 0.0, 0.0, 0.deg)) } "form image star quads" { diff --git a/nebulosa-watney/src/test/kotlin/WatneyStarDetectorTest.kt b/nebulosa-watney/src/test/kotlin/WatneyStarDetectorTest.kt index e038cb96f..1499471a9 100644 --- a/nebulosa-watney/src/test/kotlin/WatneyStarDetectorTest.kt +++ b/nebulosa-watney/src/test/kotlin/WatneyStarDetectorTest.kt @@ -5,13 +5,13 @@ import nebulosa.image.Image import nebulosa.image.algorithms.transformation.Draw import nebulosa.image.algorithms.transformation.convolution.Mean import nebulosa.star.detection.ImageStar -import nebulosa.test.FitsStringSpec +import nebulosa.test.AbstractFitsAndXisfTest import nebulosa.watney.star.detection.WatneyStarDetector import java.awt.Color import java.awt.Graphics2D import kotlin.math.roundToInt -class WatneyStarDetectorTest : FitsStringSpec() { +class WatneyStarDetectorTest : AbstractFitsAndXisfTest() { init { val detector = WatneyStarDetector(computeHFD = true) @@ -23,7 +23,7 @@ class WatneyStarDetectorTest : FitsStringSpec() { image.transform(ImageStarsDraw(stars)).save("color-detected-stars-1") .second shouldBe "bb237ce03f7cc9e44e69a5354b7a6fd1" - image = Image.open(M6707HH) + image = Image.open(M6707HH.fits()) stars = detector.detect(image.transform(Mean)) stars shouldHaveSize 870 image.transform(ImageStarsDraw(stars)).save("color-detected-stars-870") diff --git a/nebulosa-xisf/src/main/kotlin/nebulosa/xisf/XisfHeaderInputStream.kt b/nebulosa-xisf/src/main/kotlin/nebulosa/xisf/XisfHeaderInputStream.kt index 4e9a15b6b..fceda6a25 100644 --- a/nebulosa-xisf/src/main/kotlin/nebulosa/xisf/XisfHeaderInputStream.kt +++ b/nebulosa-xisf/src/main/kotlin/nebulosa/xisf/XisfHeaderInputStream.kt @@ -8,6 +8,7 @@ import nebulosa.image.format.HeaderCard import nebulosa.io.ByteOrder import nebulosa.xisf.XisfMonolithicFileHeader.* import nebulosa.xml.attribute +import okio.ByteString.Companion.decodeBase64 import java.io.Closeable import java.io.InputStream import javax.xml.stream.XMLStreamConstants @@ -16,6 +17,13 @@ class XisfHeaderInputStream(source: InputStream) : Closeable { private val reader = XML_INPUT_FACTORY.createXMLStreamReader(source) + @Suppress("ArrayInDataClass") + private data class ParsedAttributes( + @JvmField val cards: Collection, + @JvmField val image: Image?, + @JvmField val embedded: ByteArray, + ) + fun read(): XisfMonolithicFileHeader? { while (reader.hasNext()) { when (reader.next()) { @@ -39,9 +47,6 @@ class XisfHeaderInputStream(source: InputStream) : Closeable { val (width, height, numberOfChannels) = reader.attribute("geometry")!!.split(":") val location = reader.attribute("location")!! - check(location.startsWith("attachment")) - val (_, position, size) = location.split(":") - val sampleFormat = SampleFormat.valueOf(reader.attribute("sampleFormat")!!.uppercase()) val colorSpace = reader.attribute("colorSpace")?.uppercase()?.let(ColorSpace::valueOf) val pixelStorage = reader.attribute("pixelStorage")?.uppercase()?.let(PixelStorageModel::valueOf) @@ -49,9 +54,18 @@ class XisfHeaderInputStream(source: InputStream) : Closeable { val imageType = reader.attribute("imageType")?.let { ImageType.parse(it) } val compression = reader.attribute("compression")?.let { CompressionFormat.parse(it) } val bounds = reader.attribute("bounds")?.split(":")?.let { it[0].toFloat()..it[1].toFloat() } - val (keywords, thumbnail) = parseKeywords() + val (keywords, thumbnail, embedded) = parseAttributes() val header = FitsHeader() val isMono = numberOfChannels == "1" + var position = 0L + var size = 0L + + if (location.startsWith("attachment")) { + with(location.split(":")) { + position = this[1].toLong() + size = this[2].toLong() + } + } header.add(FitsHeaderCard.SIMPLE) header.add(sampleFormat.bitpix) @@ -64,21 +78,22 @@ class XisfHeaderInputStream(source: InputStream) : Closeable { return Image( width.toInt(), height.toInt(), numberOfChannels.toInt(), - position.toLong(), size.toLong(), + position, size, sampleFormat, colorSpace ?: ColorSpace.GRAY, pixelStorage ?: PixelStorageModel.PLANAR, byteOrder ?: ByteOrder.LITTLE, compression, imageType ?: ImageType.LIGHT, bounds ?: XisfMonolithicFileHeader.DEFAULT_BOUNDS, - header, thumbnail, + header, thumbnail, embedded, ) } - private fun parseKeywords(): Pair, Image?> { + private fun parseAttributes(): ParsedAttributes { val name = reader.localName val cards = ArrayList() var thumbnail: Image? = null + var embeddedData = ByteArray(0) fun addHeaderCard(card: HeaderCard) { if (cards.find { it.key == card.key } == null) { @@ -96,11 +111,12 @@ class XisfHeaderInputStream(source: InputStream) : Closeable { "FITSKeyword" -> addHeaderCard(parseFITSKeyword()) "Thumbnail" -> thumbnail = parseImage() "Property" -> addHeaderCard(parseProperty() ?: continue) + "Data" -> embeddedData = parseEmbeddedData() } } } - return cards to thumbnail + return ParsedAttributes(cards, thumbnail, embeddedData) } private fun parseFITSKeyword(): HeaderCard { @@ -119,6 +135,10 @@ class XisfHeaderInputStream(source: InputStream) : Closeable { return XisfHeaderCard(key.key, value, key.comment, propertyType) } + private fun parseEmbeddedData(): ByteArray { + return reader.elementText.trim().decodeBase64()!!.toByteArray() + } + override fun close() { reader.close() } diff --git a/nebulosa-xisf/src/main/kotlin/nebulosa/xisf/XisfMonolithicFileHeader.kt b/nebulosa-xisf/src/main/kotlin/nebulosa/xisf/XisfMonolithicFileHeader.kt index 512375336..26180c557 100644 --- a/nebulosa-xisf/src/main/kotlin/nebulosa/xisf/XisfMonolithicFileHeader.kt +++ b/nebulosa-xisf/src/main/kotlin/nebulosa/xisf/XisfMonolithicFileHeader.kt @@ -108,6 +108,7 @@ sealed interface XisfMonolithicFileHeader { } } + @Suppress("ArrayInDataClass") data class Image( @JvmField val width: Int, @JvmField val height: Int, @JvmField val numberOfChannels: Int, @JvmField val position: Long, @JvmField val size: Long, @@ -118,6 +119,7 @@ sealed interface XisfMonolithicFileHeader { @JvmField val bounds: ClosedFloatingPointRange = DEFAULT_BOUNDS, @JvmField val keywords: FitsHeader = FitsHeader.EMPTY, @JvmField val thumbnail: Image? = null, + @JvmField val embedded: ByteArray = ByteArray(0), ) : XisfMonolithicFileHeader companion object { diff --git a/nebulosa-xisf/src/main/kotlin/nebulosa/xisf/XisfMonolithicFileHeaderImageData.kt b/nebulosa-xisf/src/main/kotlin/nebulosa/xisf/XisfMonolithicFileHeaderImageData.kt index e5312f29b..0f17b1a67 100644 --- a/nebulosa-xisf/src/main/kotlin/nebulosa/xisf/XisfMonolithicFileHeaderImageData.kt +++ b/nebulosa-xisf/src/main/kotlin/nebulosa/xisf/XisfMonolithicFileHeaderImageData.kt @@ -3,6 +3,7 @@ package nebulosa.xisf import nebulosa.image.format.ImageChannel import nebulosa.image.format.ImageData import nebulosa.io.SeekableSource +import nebulosa.io.source import nebulosa.xisf.XisfFormat.readPixel import nebulosa.xisf.XisfMonolithicFileHeader.* import okio.Buffer @@ -20,10 +21,14 @@ internal data class XisfMonolithicFileHeaderImageData( override val height = image.height override val numberOfChannels = image.numberOfChannels + private val isEmbedded = image.embedded.isNotEmpty() + + private val realSource by lazy { if (isEmbedded) image.embedded.source() else source } + init { val uncompressedSize = image.compressionFormat?.uncompressedSize ?: image.size val expectedSize = numberOfChannels * numberOfPixels * image.sampleFormat.byteLength - check(uncompressedSize == expectedSize) { "invalid size. $uncompressedSize != $expectedSize" } + check(isEmbedded || uncompressedSize == expectedSize) { "invalid size. $uncompressedSize != $expectedSize" } } override val red by lazy { readImage(ImageChannel.RED) } @@ -79,7 +84,7 @@ internal data class XisfMonolithicFileHeaderImageData( private fun readPlanar(channel: ImageChannel, data: FloatArray): FloatArray { val startIndex = numberOfPixels * image.sampleFormat.byteLength * channel.index - source.seek(image.position + startIndex) + realSource.seek(image.position + startIndex) var remainingPixels = data.size var pos = 0 @@ -87,11 +92,11 @@ internal data class XisfMonolithicFileHeaderImageData( var closeable: (() -> Unit)? = null val compressedSource = when (image.compressionFormat?.type) { - CompressionType.ZLIB -> InflaterSource(source, Inflater(false).also { closeable = it::end }) + CompressionType.ZLIB -> InflaterSource(realSource, Inflater(false).also { closeable = it::end }) CompressionType.LZ4 -> TODO("Not implemented yet") CompressionType.LZ4_HC -> TODO("Not implemented yet") CompressionType.ZSTD -> TODO("Not implemented yet") - null -> source + null -> realSource } try { @@ -126,7 +131,7 @@ internal data class XisfMonolithicFileHeaderImageData( * a contiguous sequence (all pixel samples are stored in a single block). */ private fun readNormal(channel: ImageChannel, data: FloatArray): FloatArray { - source.seek(image.position) + realSource.seek(image.position) val blockSizeInBytes = numberOfChannels * image.sampleFormat.byteLength val bytesToSkipBefore = channel.index * image.sampleFormat.byteLength @@ -139,7 +144,7 @@ internal data class XisfMonolithicFileHeaderImageData( val n = min(PIXEL_COUNT, remainingPixels) val byteCount = n * blockSizeInBytes - check(source.read(buffer, byteCount) == byteCount) + check(realSource.read(buffer, byteCount) == byteCount) repeat(n) { if (bytesToSkipBefore > 0) buffer.skip(bytesToSkipBefore) diff --git a/nebulosa-xisf/src/main/kotlin/nebulosa/xisf/XisfMonolithicFileHeaderImageHdu.kt b/nebulosa-xisf/src/main/kotlin/nebulosa/xisf/XisfMonolithicFileHeaderImageHdu.kt index 2611919b0..49ae60e59 100644 --- a/nebulosa-xisf/src/main/kotlin/nebulosa/xisf/XisfMonolithicFileHeaderImageHdu.kt +++ b/nebulosa-xisf/src/main/kotlin/nebulosa/xisf/XisfMonolithicFileHeaderImageHdu.kt @@ -1,6 +1,5 @@ package nebulosa.xisf -import nebulosa.fits.FitsHeader import nebulosa.image.format.ImageHdu import nebulosa.io.SeekableSource diff --git a/nebulosa-xisf/src/test/kotlin/XisfFormatTest.kt b/nebulosa-xisf/src/test/kotlin/XisfFormatTest.kt index f1086772b..289992b3c 100644 --- a/nebulosa-xisf/src/test/kotlin/XisfFormatTest.kt +++ b/nebulosa-xisf/src/test/kotlin/XisfFormatTest.kt @@ -10,13 +10,10 @@ import nebulosa.fits.bitpix import nebulosa.image.format.ImageHdu import nebulosa.io.seekableSink import nebulosa.io.seekableSource -import nebulosa.test.FitsStringSpec +import nebulosa.test.AbstractFitsAndXisfTest import nebulosa.xisf.XisfFormat -import java.awt.image.BufferedImage -import java.awt.image.DataBufferByte -import java.awt.image.DataBufferInt -class XisfFormatTest : FitsStringSpec() { +class XisfFormatTest : AbstractFitsAndXisfTest() { init { "mono:planar:8" { @@ -130,7 +127,7 @@ class XisfFormatTest : FitsStringSpec() { data.blue shouldNotBeSameInstanceAs data.green val image = makeImage() - image.save("xisf-color-planar-8").second shouldBe "89beed384ee9e97ce033ba447a377937" + image.save("xisf-color-planar-8").second shouldBe "764e326cc5260d81f3761112ad6a1969" } } "color:planar:16" { @@ -149,7 +146,7 @@ class XisfFormatTest : FitsStringSpec() { data.blue shouldNotBeSameInstanceAs data.green val image = makeImage() - image.save("xisf-color-planar-16").second shouldBe "89beed384ee9e97ce033ba447a377937" + image.save("xisf-color-planar-16").second shouldBe "764e326cc5260d81f3761112ad6a1969" } } "color:planar:32" { @@ -168,7 +165,7 @@ class XisfFormatTest : FitsStringSpec() { data.blue shouldNotBeSameInstanceAs data.green val image = makeImage() - image.save("xisf-color-planar-32").second shouldBe "89beed384ee9e97ce033ba447a377937" + image.save("xisf-color-planar-32").second shouldBe "764e326cc5260d81f3761112ad6a1969" } } "color:planar:F32" { @@ -187,7 +184,7 @@ class XisfFormatTest : FitsStringSpec() { data.blue shouldNotBeSameInstanceAs data.green val image = makeImage() - image.save("xisf-color-planar-F32").second shouldBe "89beed384ee9e97ce033ba447a377937" + image.save("xisf-color-planar-F32").second shouldBe "764e326cc5260d81f3761112ad6a1969" } } "color:planar:F64" { @@ -206,7 +203,7 @@ class XisfFormatTest : FitsStringSpec() { data.blue shouldNotBeSameInstanceAs data.green val image = makeImage() - image.save("xisf-color-planar-F64").second shouldBe "89beed384ee9e97ce033ba447a377937" + image.save("xisf-color-planar-F64").second shouldBe "764e326cc5260d81f3761112ad6a1969" } } "mono:planar:8:zlib" { @@ -229,7 +226,7 @@ class XisfFormatTest : FitsStringSpec() { } } "mono:write" { - val formats = arrayOf(M82_MONO_8_XISF, M82_MONO_16_XISF, M82_MONO_32_XISF, M82_MONO_F32_XISF, M82_MONO_F64_XISF) + val formats = arrayOf(PALETTE_MONO_8_XISF, PALETTE_MONO_16_XISF, PALETTE_MONO_32_XISF, PALETTE_MONO_F32_XISF, PALETTE_MONO_F64_XISF) for (format in formats) { val source0 = closeAfterEach(format.seekableSource()) @@ -251,11 +248,11 @@ class XisfFormatTest : FitsStringSpec() { val bitpix = hdus1[0].header.bitpix val image = hdus1[0].makeImage() - image.save("xisf-mono-write-$bitpix").second shouldBe "0dca7efedef5b3525f8037f401518b0b" + image.save("xisf-mono-write-$bitpix").second shouldBe "07762064ff54ccc7771ba5b34fca86cf" } } "color:write" { - val formats = arrayOf(M82_COLOR_8_XISF, M82_COLOR_16_XISF, M82_COLOR_32_XISF, M82_COLOR_F32_XISF, M82_COLOR_F64_XISF) + val formats = arrayOf(PALETTE_COLOR_8_XISF, PALETTE_COLOR_16_XISF, PALETTE_COLOR_32_XISF, PALETTE_COLOR_F32_XISF, PALETTE_COLOR_F64_XISF) for (format in formats) { val source0 = closeAfterEach(format.seekableSource()) @@ -281,11 +278,11 @@ class XisfFormatTest : FitsStringSpec() { val bitpix = hdus1[0].header.bitpix val image = hdus1[0].makeImage() - image.save("xisf-color-write-$bitpix").second shouldBe "89beed384ee9e97ce033ba447a377937" + image.save("xisf-color-write-$bitpix").second shouldBe "7233886f62065800b43419f3b1b6c833" } } "fits-to-xisf:mono" { - val formats = arrayOf(NGC3344_MONO_8_FITS, NGC3344_MONO_16_FITS, NGC3344_MONO_32_FITS, NGC3344_MONO_F32_FITS, NGC3344_MONO_F64_FITS) + val formats = arrayOf(PALETTE_MONO_8_FITS, PALETTE_MONO_16_FITS, PALETTE_MONO_32_FITS, PALETTE_MONO_F32_FITS, PALETTE_MONO_F64_FITS) for (format in formats) { val source0 = closeAfterEach(format.seekableSource()) @@ -309,11 +306,11 @@ class XisfFormatTest : FitsStringSpec() { val bitpix = hdus1[0].header.bitpix val image = hdus1[0].makeImage() - image.save("fits-to-xisf-mono-$bitpix").second shouldBe "e17cfc29c3b343409cd8617b6913330e" + image.save("fits-to-xisf-mono-$bitpix").second shouldBe "07762064ff54ccc7771ba5b34fca86cf" } } "fits-to-xisf:color" { - val formats = arrayOf(NGC3344_COLOR_8_FITS, NGC3344_COLOR_16_FITS, NGC3344_COLOR_32_FITS, NGC3344_COLOR_F32_FITS, NGC3344_COLOR_F64_FITS) + val formats = arrayOf(PALETTE_COLOR_8_FITS, PALETTE_COLOR_16_FITS, PALETTE_COLOR_32_FITS, PALETTE_COLOR_F32_FITS, PALETTE_COLOR_F64_FITS) for (format in formats) { val source0 = closeAfterEach(format.seekableSource()) @@ -329,7 +326,7 @@ class XisfFormatTest : FitsStringSpec() { val hdus1 = XisfFormat.read(source1) hdus1 shouldHaveSize 1 - hdus1[0].data.numberOfChannels shouldBeExactly 4 + hdus1[0].data.numberOfChannels shouldBeExactly 3 // hdus1[0].header.size shouldBeExactly hdus0[0].header.size hdus1[0].data.red.size shouldBeExactly hdus0[0].data.red.size hdus1[0].data.red shouldNotBeSameInstanceAs hdus0[0].data.red @@ -341,11 +338,11 @@ class XisfFormatTest : FitsStringSpec() { val bitpix = hdus1[0].header.bitpix val image = hdus1[0].makeImage() - image.save("fits-to-xisf-color-$bitpix").second shouldBe "18fb83e240bc7a4cbafbc1aba2741db6" + image.save("fits-to-xisf-color-$bitpix").second shouldBe "7233886f62065800b43419f3b1b6c833" } } "xisf-to-fits:mono" { - val formats = arrayOf(M82_MONO_8_XISF, M82_MONO_16_XISF, M82_MONO_32_XISF, M82_MONO_F32_XISF, M82_MONO_F64_XISF) + val formats = arrayOf(PALETTE_MONO_8_XISF, PALETTE_MONO_16_XISF, PALETTE_MONO_32_XISF, PALETTE_MONO_F32_XISF, PALETTE_MONO_F64_XISF) for (format in formats) { val source0 = closeAfterEach(format.seekableSource()) @@ -369,11 +366,11 @@ class XisfFormatTest : FitsStringSpec() { val bitpix = hdus1[0].header.bitpix val image = hdus1[0].makeImage() - image.save("xisf-to-fits-mono-$bitpix").second shouldBe "0dca7efedef5b3525f8037f401518b0b" + image.save("xisf-to-fits-mono-$bitpix").second shouldBe "07762064ff54ccc7771ba5b34fca86cf" } } "xisf-to-fits:color" { - val formats = arrayOf(M82_COLOR_8_XISF, M82_COLOR_16_XISF, M82_COLOR_32_XISF, M82_COLOR_F32_XISF, M82_COLOR_F64_XISF) + val formats = arrayOf(PALETTE_COLOR_8_XISF, PALETTE_COLOR_16_XISF, PALETTE_COLOR_32_XISF, PALETTE_COLOR_F32_XISF, PALETTE_COLOR_F64_XISF) for (format in formats) { val source0 = closeAfterEach(format.seekableSource()) @@ -401,36 +398,8 @@ class XisfFormatTest : FitsStringSpec() { val bitpix = hdus1[0].header.bitpix val image = hdus1[0].makeImage() - image.save("xisf-to-fits-color-$bitpix").second shouldBe "89beed384ee9e97ce033ba447a377937" - } - } - } - - companion object { - - @JvmStatic - private fun ImageHdu.makeImage(): BufferedImage { - val type = if (numberOfChannels == 1) BufferedImage.TYPE_BYTE_GRAY else BufferedImage.TYPE_INT_RGB - val image = BufferedImage(width, height, type) - - if (numberOfChannels == 1) { - val buffer = (image.raster.dataBuffer as DataBufferByte) - - repeat(width * height) { - buffer.data[it] = (data.red[it] * 255f).toInt().toByte() - } - } else { - val buffer = (image.raster.dataBuffer as DataBufferInt) - - repeat(width * height) { - val red = (data.red[it] * 255f).toInt() and 0xFF - val green = (data.green[it] * 255f).toInt() and 0xFF - val blue = (data.blue[it] * 255f).toInt() and 0xFF - buffer.data[it] = red or (green shl 8) or (blue shl 16) - } + image.save("xisf-to-fits-color-$bitpix").second shouldBe "7233886f62065800b43419f3b1b6c833" } - - return image } } } diff --git a/nebulosa-xisf/src/test/kotlin/XisfHeaderInputStreamTest.kt b/nebulosa-xisf/src/test/kotlin/XisfHeaderInputStreamTest.kt index a5943e1a2..457aa4c2f 100644 --- a/nebulosa-xisf/src/test/kotlin/XisfHeaderInputStreamTest.kt +++ b/nebulosa-xisf/src/test/kotlin/XisfHeaderInputStreamTest.kt @@ -4,12 +4,12 @@ import io.kotest.matchers.nulls.shouldNotBeNull import io.kotest.matchers.shouldBe import io.kotest.matchers.types.shouldBeInstanceOf import nebulosa.io.ByteOrder -import nebulosa.test.FitsStringSpec +import nebulosa.test.AbstractFitsAndXisfTest import nebulosa.xisf.XisfHeaderInputStream import nebulosa.xisf.XisfMonolithicFileHeader import kotlin.io.path.inputStream -class XisfHeaderInputStreamTest : FitsStringSpec() { +class XisfHeaderInputStreamTest : AbstractFitsAndXisfTest() { init { "read:8:gray" { From 5558cfbad517c0ff043a5d27f29bcfefc82268db Mon Sep 17 00:00:00 2001 From: tiagohm Date: Mon, 1 Apr 2024 19:51:13 -0300 Subject: [PATCH 15/15] [api]: Fix "Missing bounds Image attribute" --- nebulosa-xisf/src/main/kotlin/nebulosa/xisf/XisfFormat.kt | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/nebulosa-xisf/src/main/kotlin/nebulosa/xisf/XisfFormat.kt b/nebulosa-xisf/src/main/kotlin/nebulosa/xisf/XisfFormat.kt index 308cda3ec..6ce39ef86 100644 --- a/nebulosa-xisf/src/main/kotlin/nebulosa/xisf/XisfFormat.kt +++ b/nebulosa-xisf/src/main/kotlin/nebulosa/xisf/XisfFormat.kt @@ -97,11 +97,13 @@ data object XisfFormat : ImageFormat { val bitpix = hdu.header.bitpix val sampleFormat = SampleFormat.from(bitpix) val imageSize = hdu.width * hdu.height * hdu.numberOfChannels * sampleFormat.byteLength + val extra = if (bitpix.code < 0) " bounds=\"0:1\"" else "" IMAGE_START_TAG .format( hdu.width, hdu.height, hdu.numberOfChannels, - sampleFormat.code, colorSpace.code, imageType.code, initialHeaderSize, imageSize + sampleFormat.code, colorSpace.code, imageType.code, + initialHeaderSize, imageSize, extra ).also(buffer::writeUtf8) for ((name, key) in AstronomicalImageProperties) { @@ -196,7 +198,7 @@ data object XisfFormat : ImageFormat { """""" private const val XISF_END_TAG = "" private const val IMAGE_START_TAG = - """""" + """""" private const val IMAGE_END_TAG = "" private const val STRING_PROPERTY_TAG = """%s""" private const val NON_STRING_PROPERTY_TAG = """"""

%X|7C>};`m2bhd-CsiSiJiTwq{ScEoPd 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 zwfGnDQ4goCD>4>>777111999777222333>>>111333666;;;444444666333...555000+++...---(((///>>>===,,,:::;;;SSS;;;888OOO666SSSVVVPPP===IIIDDDAAA<<>>222***+++111888'''(((%%%%%%***%%%&&&%%%$$$&&&$$$'''###  +++(((!!!"""!!!!!!!!!###"""$$$ ###'''%%%///###%%%((((((&&&***'''>>>(((---333---111bbb***555666$$$###%%%,,,+++((()))000999KKKBBBDDDNNN<<<<<>>//////666@@@999555---222333333666:::444'''''':::111///333---PPPCCC???KKKLLLFFF===JJJGGGCCCIIIMMM@@@AAAGGG@@@CCC:::888111,,,...---///111)))***///$$$000%%%(((***%%%(((&&&$$$"""!!!!!!''':::((( %%% """!!!&&&$$$!!! 666***'''&&&"""!!! ###"""!!!'''!!!$$$222---(((---,,,&&&///444///333+++222+++,,,%%%>>><<<'''+++333%%%$$$++++++//////666LLLWWW333000999KKKUUU===III444000......///666777(((+++,,,...(((+++(((&&&%%%((('''***+++333111///---++++++555((()))---'''+++,,,000...---/////////>>>999555000555777666777222...000...444444333<<<======:::===GGGAAA???<<>>222+++---:::>>>GGG333666:::>>>777888:::LLLcccVVVKKKRRRPPPTTTCCC===```BBBPPP777===///111,,,///,,,+++KKK%%%%%%''',,,'''111000%%%&&&$$$ ***(((;;;=== """###444$$$"""666$$$###$$$+++###:::"""!!!""" ,,,===(((,,,///%%%+++((((((000+++///AAA111888111<<<,,,***888***555$$$(((%%%)))000***000---333===888444555CCC<<>>333!!!---)))((()))((($$$222444777JJJRRR666222888)))%%% ###...:::---000---222,,,888444---///444777555???DDD333---///111+++((()))***,,,)))---111000333333(((666222(((&&&(((444QQQ---(((***((('''((('''++++++******)))---///555666NNN888::::::666666777???555999222---///111444999<<<777666:::>>>^^^CCCaaaAAA??????DDDOOOHHHAAA888AAAJJJ:::>>>///===[[[BBBUUUDDD:::NNN;;;555555;;;777EEECCCJJJQQQNNNQQQMMMHHHMMM\\\KKKMMM@@@CCCWWW:::KKKRRRbbb444666000***...+++111&&&***""")))***%%%%%%!!! !!! &&&!!!&&&!!!!!!((((((---!!!'''$$$&&&111 $$$ 000%%%&&&)))555111((($$$)))000111******&&&)))FFFDDDmmm{{{VVV555,,,(((%%%&&&!!!'''111LLL***555...000+++444///,,,///222999777222111888333444000000999------+++111111111HHH555555+++''',,,***'''(((+++'''***111((('''***)))***+++...***//////,,,,,,444333---444777333444666555;;;222222888999???555999<<<666555888999VVVNNNJJJTTTMMMGGGMMMBBBAAAAAA@@@GGGHHH333...333HHHFFFHHHCCCQQQ]]]>>>---333@@@:::333:::@@@bbbVVVMMMWWW```SSSPPPHHHQQQOOOCCCDDDBBBEEEMMM[[[RRR:::000111111///333(((000,,,'''***+++$$$'''$$$'''### !!!FFF!!!(((!!! !!!)))"""%%%###%%% ###000$$$888******(((---***@@@kkk;;;555'''///))))))///...---333KKKrrrI%```///***'''%%%"""###'''111222......---...111...)))///)))///222999222888BBBKKK555111+++555//////000))),,,444,,,***+++)))&&&$$$''')))'''%%%%%%---555''''''(((***...+++///---***000111000333000111222000333000000555888444222888777999???999FFF999888555333???MMMEEElllRRRBBBEEECCCAAABBBOOOJJJ999444999999RRR]]]VVVUUU\\\DDD777666MMMAAA555666>>>XXXMMMHHHUUUZZZXXXbbbRRR[[[SSSRRRUUU^^^kkkQQQMMMGGG===222...---444+++***333,,,%%%''')))$$$""""""###''''''###(((///###===!!!222???QQQ"""!!!000###&&& $$$<<< """,,,"""'''CCC///666AAA222---VVV+++***'''//////)))...BBB'''+++,,,111000CCC___mmm===000+++((($$$'''(((+++...666+++//////333:::///+++++++++000777DDDJJJEEEddd888444222---+++(((+++...%%%%%%,,,++++++***$$$---***777111HHH%%%)))***++++++&&&%%%)))---))),,,///000...,,,///111///444222555000222000222222444CCC999;;;:::DDD>>>666888:::777:::444:::;;;MMMCCCXXXLLLAAADDD???BBB===AAAFFFFFFFFF888HHH zzzGGGFFFNNNnnnCCC000111???555???OOODDDIIIKKKSSSWWWiii|||LLLVVVBBBkkkgggGGGHHHCCCLLLRRR333111777000///000222###%%%%%%"""!!!'''000000'''###!!!///"""@@@((( ---(((&&& &&&+++222### )))***&&&CCCGGG%%%,,,000>>>444***(((((('''***111<<<***777III///CCC222***:::ZZZPPPRRR000+++)))111---111,,,***000...333000---???111))),,,111++++++000777VVVSSS >>>222...(((((((((+++;;;+++)))(((+++JJJ///&&&'''&&&+++...///,,,%%%###(((''',,,'''(((***+++------,,,000---000000///***///000333111666333444000KKK333555;;;888;;;555>>>CCCHHH===111555;;;FFFMMMhhhDDDBBBOOODDDCCCAAAEEEUUU;;;AAA<<>>000,,,999ccc\\\RRRRRRPPP YYYhhhXXXPPPCCCWWWjjjEEE>>>AAA<<<777<<<444AAA111333///222&&&))))))((('''%%%### !!! """)))%%%OOO !!!+++WWW111\\\((((((###""" %%%******222==='''222&&&###+++---111555'''///...777,,,---'''+++FFF888000555111KKK???777222@@@---:::AAA777...333&&&(((+++---000EEE(((...888...///---***&&& """&&&%%%///000FFFiiioooCCC...000888---***'''***333***&&&+++000999,,,...///***)))&&&'''$$$%%%&&&+++:::&&&(((,,,,,,+++%%%---------,,,+++...000...///...000888555999555555;;;111777888777888???@@@???;;;:::444999XXX```DDDVVVGGGDDDUUUKKKAAAQQQFFFDDD:::===999>>>EEEqqqMMMIII???@@@===FFF;;;:::LLLJJJDDDMMMPPPSSSbbbUUUJJJKKKnnnPPPYYYYYYXXXWWWCCCGGGDDDAAA000///888EEE888333***)))(((,,,***(((>>> ###"""$$$$$$###!!!*** '''"""!!!...222'''RRR222222$$$"""--- """!!!!!!---***###&&&$$$...777MMM$$$%%%&&&===///555...111(((,,,...---...BBB---222333666++++++JJJ999999(((+++222111333...+++(((&&&---///222(((///000//////,,,+++)))$$$  !!!111===000888ppp@@@***222---(((111111###;;;DDD,,,---111;;;000444---))))))555///(((''''''+++,,,***,,,)))'''+++000///***)))++++++000***,,,...///000222777___iii777XXXDDD777333777=========;;;:::444>>>CCC???CCC<<>>DDD222"""###"""###%%%"""!!!!!!...%%%,,,,,,###:::  %%%!!! !!!&&&!!!"""&&&))))))CCCQQQ555DDDTTT777...888QQQ@@@==='''222333+++...:::ddd222((((((***(((000)))***(((...AAA444000///'''$$$'''$$$***,,,:::,,,***,,,,,,---+++,,,---%%%&&& !!!$$$***---+++&&&FFF[[[***$$$$$$%%%))))))---111000,,,111,,,111777***+++&&&---))),,,+++)))&&&&&&(((&&&'''+++***+++((()))++++++,,,***000...+++000222777555888<<<;;;>>>LLL===999333>>>:::;;;888<<<999999???<<<@@@>>>DDDAAADDDFFFPPPDDDFFF???GGGHHHDDD777888IIInnn===BBBQQQ]]]<<<222333JJJDDDCCCiiisssHHHHHHBBBFFFGGGPPPbbbXXXuuukkkAAA;;;FFF>>>@@@:::222:::???888///111111333222222'''&&&%%%###&&&"""$$$!!!!!!&&&### !!!  &&& 111---$$$%%%000 %%%### $$$&&&***###+++222!!!'''###"""555***555+++888CCC+++LLL>>>AAABBBNNN???...)))%%%###(((888JJJ"""!!!(((%%%...&&&### +++((((((;;;QQQ)))$$$''''''***(((222***,,,///'''***)))"""###%%%$$$###&&&***%%%&&&%%%%%%&&&888((()))***(((%%%000777666000222(((222111<<<+++)))((('''777,,,***---***)))''''''(((************///---,,,---...///...///......000333333888999>>>999:::>>>===AAA;;;555:::;;;:::;;;444===:::PPPBBBAAAAAA???III???EEEHHHGGGDDDDDD???<<>>===BBBDDDIII___PPP___JJJHHHIIIUUUSSS]]]ooonnnKKKBBB999:::AAABBBIII===<<<:::...222666222666666000,,,%%%%%%(((***(((===!!!  &&&...'''!!!))) !!!%%%,,,%%%(((%%%$$$###$$$999"""%%%999&&&"""---000222666+++---666222;;;ZZZcccfff...???***%%%###""")))&&& !!! &&&---$$$&&&'''###,,,!!!$$$)))&&&%%%AAA&&&***111@@@)))///)))999000******)))$$$&&&333,,,%%%'''***+++***((('''<<<$$$%%%---(((///,,,111555333---...+++999+++999+++---+++%%%)))333///***+++&&&---444222)))(((,,,...///***......111...222///000...---000///222RRR666QQQJJJLLL;;;:::<<<:::888999888;;;555888888777???@@@:::AAAHHHEEEGGGTTTPPPMMM@@@EEE<<<777;;;BBBGGGHHHIIIIII>>>>>>;;;??????<<<;;;SSSLLLTTTlllRRR[[[WWWdddQQQTTTLLLIIIGGG:::666>>>===>>>:::444555444...---000333<<<111%%%'''''')))+++&&&,,,---$$$###&&&!!!###$$$"""$$$    (((555'''""">>>///))) ###!!! ,,,+++###000...###...000(((---///111444///...555CCCXXX___777999888000------+++%%%""""""!!!%%%+++###$$$&&&###$$$%%%'''(((***,,,&&&&&&&&&...FFFZZZ)))+++)))???&&&$$$&&&000***"""(((///&&&'''***---'''&&&'''(((&&&'''&&&)))+++444,,,///000;;;...)))...:::------'''(((+++000+++...444,,,222***......++++++***+++000777///666555444666111111,,,,,,...222777333111::::::===LLL<<<<<<;;;:::;;;<<<333555777666444CCCEEECCCAAACCC???AAAKKKJJJLLLsss;;;888777HHHJJJMMM<<>>===666999VVVcccYYY[[[ppp]]]XXXNNNKKKFFF===555<<<===666222666///777777555---...333222***%%%)))%%%'''###!!!$$$!!!!!!###!!!""" ###$$$ '''DDD!!!$$$### ///!!!$$$000 !!!!!!###### ######===(((777,,,444222111///000666888777888111777RRR:::777111:::///***(((%%%&&&""" ###(((###!!!"""!!!//////,,,******///***&&&------111***,,,(((<<<''''''&&&III'''%%%&&&'''BBB((())))))'''&&&(((((((((%%%,,,&&&&&&)))......///,,,---+++555666;;;***999000)))---+++---111000000///000000...222///000111;;;111:::111555444666///,,,,,,,,,---444777444...333UUUxxx>>>======>>>>>>888:::<<<333555999@@@FFFGGG>>>EEEQQQFFFAAALLLIIIDDDAAA<<<>>>===dddPPPWWWJJJ===???777<<>><<<111000///555AAA222...,,,///---======999)))%%%'''$$$$$$%%%!!!(((""""""######!!!$$$''' ...%%%&&&!!!###))) 000 ///&&&)))III;;;&&&""")))+++'''888$$$&&&---***///777111BBB===;;;FFF888LLL444;;;???@@@888666///+++111+++222&&&###(((///000###$$$ &&&(((''')))"""%%%***)))%%%###'''***%%%'''((()))((())),,,&&&&&&''''''222$$$&&&***(((***+++---,,,)))---XXX)))333,,,)))AAA111---'''''')))'''111rrr666---...000,,,111---222GGG///000999000......333444999555666777111222333@@@111555555111333999999444333333===GGG888555777===;;;666======666444:::999;;;AAA???PPP???GGGLLLDDDEEEMMMCCC@@@???===@@@@@@EEEAAADDD???::::::;;;======888111'''###LLLQQQPPPhhhOOORRROOOYYY@@@BBBEEE===DDD999///000===555......;;;444+++,,,***;;;111+++***$$$''')))''')))>>>&&&+++$$$"""&&&######***555:::"""(((  >>>:::  %%%###%%%$$$OOO$$$%%%!!!!!!)))$$$$$$&&&%%%+++((('''...???333555@@@888+++---555YYYgggLLLGGG@@@888000,,,---///((("""+++***---000'''%%%)))---+++&&&!!!"""***(((&&&))))))+++(((---***$$$%%%)))((("""''',,,000******111'''&&&(((''''''***)))///333)))&&&...***,,,&&&&&&+++***000---111222///+++...222///...///999888222///***222555333111777;;;777555999:::333111333111444777555333000777222111BBB:::777888777::::::@@@999999555555<<<:::666DDDLLLSSSGGGFFF@@@BBB@@@MMMEEEEEE???BBB;;;<<>>...,,,(((&&&'''%%%)))'''""",,,%%%(((///"""###!!!!!!!!! %%%%%%<<<'''%%%&&&%%%)))***111)))___'''&&&%%%$$$%%%   ***$$$###%%%******222(((......;;;DDDAAA333222444111]]]cccLLL:::JJJ///+++---!!!,,,%%%(((222))))))'''))),,,,,,888((($$$ &&&***)))***'''aaa)))((($$$''')))&&&(((&&&%%%&&&)))...222111222+++((($$$***((()))(((***'''*********)))''''''(((...///555666///333111,,,......000555...---///777...333555///000555111///888...666999999::::::222555<<>>FFFEEEBBBAAA>>>???RRR>>>FFFCCC;;;:::>>>===<<<<<<===777777444GGGhhhpppzzz___YYYWWWSSSMMMHHHGGG???888555999999666777666999111111@@@,,,+++)))###((('''''''''(((%%%%%%$$$%%% $$$%%%)))***  ,,,,,,!!!!!!!!!$$$ &&& """###((($$$(((///'''### %%%!!!$$$&&&)))###"""!!!'''000...)))&&&111444111777444TTTWWWIIIoooU&ccc???---111222&&&''',,,444)))+++((())),,,(((***,,,***)))...%%%'''$$$)))(((''''''((((((&&&###$$$'''***%%%'''(((''''''"""&&&+++((((((%%%)))((()))+++'''***+++,,,,,,+++(((***+++))))));;;000,,,---//////...,,,---///999888444...111555222555AAA:::444222///555444666666AAAOOO555999;;;:::999777999666===>>><<<;;;888:::777777@@@<<<;;;EEE===<<<@@@III;;;>>>>>>:::???AAADDDGGGAAA:::EEEIII@@@===BBBBBB===>>>???BBBLLLJJJCCCAAA>>><<<===666333888@@@^^^xxx[[[PPPPPP___[[[RRRVVVNNNFFF>>>VVV;;;666@@@===FFFkkkEEE444;;;UUU///000+++000...)))"""%%%$$$666WWW...%%%!!!)))"""###""" ,,,$$$!!!  '''### """%%%XXX///+++'''&&&YYY+++)))!!!'''""""""777,,,!!!OOO!!!$$$"""$$$!!!)))000'''111333)))&&&)))###666EEEJJJnnn& XXX999222888...)))%%%***222*********888222---***)))((((((&&&555)))"""%%%222)))'''%%%'''((('''''''''$$$(((&&&'''***+++***,,,+++...---%%%(((---***///,,,&&&%%%&&&------)))---777...000>>>000111111---222333222///333;;;<<<>>>888222999444000???888333444333555888555111777<<<:::@@@;;;888>>>777???===:::<<<<<<666<<<===:::555:::===888;;;HHH===DDDEEE@@@<<<>>>GGG<<>>@@@NNNCCCZZZLLLXXXOOO???AAADDDDDDAAAEEE===;;;;;;999222333000555CCCDDDRRRUUUTTTZZZRRRoooQQQGGGXXX>>><<<===:::===555333666111666FFF...)))---(((111000''''''&&&444JJJ---&&&)))### """'''$$$((((((%%%###999 444!!!sss !!!&&&999111$$$""" !!!'''+++"""&&&<<<%%%'''###"""((('''hhh555$$$&&&"""%%%(((JJJMMM}}}yyy___333888222000>>>555(((---******)))---***...,,,,,,'''(((&&&)))'''!!!&&&((($$$(((---666)))***+++(((+++...'''000+++---...---,,,...+++(((,,,,,,,,,---...'''+++))))))***,,,,,,,,,000CCC777222...999888???999555444999444??????===<<<===555888KKK222888999:::444:::666///555555===>>><<>>BBB???LLL<<<>>>CCCAAA===BBBPPPDDDSSS???CCC@@@>>>EEE@@@===???::::::>>>>>>===;;;999...///666DDDRRRVVVjjjZZZNNNRRRPPPLLLLLLZZZ999@@@DDD:::999<<<555444000000)))///333---,,,333777+++***)))000%%%...'''...%%%!!!$$$###  %%%))),,,******%%%$$$!!!"""000***,,,###(((***333###%%% $$$ +++######!!!$$$%%%!!!###"""222""""""###%%%%%%&&&%%%$$$&&&+++""",,,;;;MMMdddKKK222===FFF444333333,,,(((222)))111///444...111000...)))$$$&&&((((((******)))---+++(((+++...///***%%%***//////(((,,,///...---,,,,,,111000...111---...++++++///+++---***------///555444000111...444...000333222444555888@@@555666333999;;;???777444===AAA666333666000222999;;;RRR<<<===AAATTTCCC777555===>>>>>>888999888888999:::999888999OOO>>>>>>HHHEEE===>>>@@@DDD@@@;;;===BBBDDD===GGGIIILLLCCCBBBFFFDDDAAAEEE???;;;===???BBBFFFAAA999999;;;333888???QQQHHHCCCNNNgggPPP^^^GGG@@@999AAA>>>???:::888444...///,,,***///,,,......111@@@999666,,,222++++++'''%%%111(((***...>>>!!!$$$DDD)))$$$%%%'''***???WWW '''!!!)))%%%"""000"""###!!!,,,%%%'''!!!######"""###!!!((('''+++$$$ """!!!######%%%,,,000///555000@@@TTTNNN<<>>666555999888444======;;;888BBB:::888===<<<:::;;;666666;;;BBBAAAAAA@@@AAA:::DDD888@@@>>>@@@???BBBEEEIIIEEEDDD@@@@@@@@@AAA@@@DDD@@@???HHHHHH???;;;888:::===AAA:::JJJAAAKKK[[[bbbSSSFFF===LLL===JJJIIIGGG@@@:::888BBB333//////555///''',,,GGG666+++@@@@@@000(((((((((///---$$$%%%$$$###%%%!!!000777 """"""!!! //////111)))%%%"""###"""444&&&%%% """###///"""###  '''""""""555###%%%"""'''$$$ &&&)))$$$$$$###'''+++***&&&999AAANNNVVVJJJIIIFFF;;;...999666222333///***000///777...)))---+++###)))'''---(((***------***---222---555999...***000///333---///.........+++---***;;;///111...+++---......111---000///---...000222222///333,,,///...777111222333888999jjj@@@<<<999BBB===888444444---999444111111FFF:::666666@@@===CCC888555333666333888@@@AAA:::BBB:::999888777:::888666777DDDDDDCCCAAAEEE:::666888555???AAA???CCCPPPPPPCCCBBBAAAAAAAAACCCDDDEEEFFFKKKAAA@@@CCCAAA@@@BBB@@@@@@:::GGG^^^___QQQiiiPPPAAAFFF<<>>>>>888BBBDDD999777:::777:::KKKZZZ@@@>>>:::777444444<<>>DDDCCCLLLJJJEEELLLLLLHHHTTTHHHBBBMMMJJJ[[[BBBNNN777555888444111555111222------>>>333555HHH;;;999333)))"""######$$$###$$$$$$NNNIII,,,GGG222---$$$%%%/// ***$$$IIIFFF888!!!"""GGG(((&&&FFF$$$!!!###'''######'''###,,,'''%%%###%%%&&&)))(((+++)))&&&444???HHHjjj4aaaMMM666;;;666PPP???+++(((///000---:::///555,,,...'''***&&&///===888---,,,,,,111777DDD777333000444888222---111555333555666444444BBB777999777HHH>>>888DDD>>>888BBB???888333555888777444444111222///999666999EEE???999>>>888555DDDUUUQQQ:::666444000<<<444444111333666999666>>>;;;===555666BBB>>>>>>222666DDD:::FFF@@@FFF:::777<<<;;;>>>999999777777>>>>>>===<<<@@@777::::::::::::@@@???HHHLLLHHHMMM>>>???<<>>@@@999CCC444111333444111111444444777:::;;;<<>>GGG666555666<<<...000///666111111666666???555888666BBBGGG:::>>>:::DDD999\\\???CCCNNN;;;======AAA;;;<<<<<<999888BBB@@@>>><<<;;;;;;@@@???@@@===IIIEEEDDDGGGHHHNNNBBB???FFFAAAEEEFFF???DDDBBBQQQGGG???@@@>>>DDDZZZJJJJJJMMMEEEHHHGGGMMM^^^iiiaaaQQQOOOGGG:::666555888555444000...+++000---///TTT \\\333,,,$$$+++&&&,,,%%%%%%""" !!!///'''$$$111$$$###((("""###!!!666%%% $$$&&&!!!"""###$$$!!!!!!777!!!222111+++!!! $$$$$$!!!%%% +++"""""")))######&&&)))222%%%&&&$$$%%%)))&&&"""###444444???VVVsss7)aaaXXXCCC555;;;666<<<777444888111222---+++---444BBB000///444...333000555555444111---...---333333333BBBAAA>>>888999888777666999444<<<999>>>===:::ZZZ===888<<<888555999===;;;666555444<<<555555444333666888333222333333666999444555222???BBB;;;444]]]JJJAAA777555000444333666///555444777:::BBB<<<;;;:::FFFBBB<<>>;;;555666888777888222888555iii===888:::;;;:::666333444HHH222444111222<<>>AAAEEE666222;;;999<<<>>><<>>HHH:::777999===<<<555===<<<@@@BBBJJJEEEEEEJJJHHHDDDBBBAAAGGGEEEEEEBBB;;;AAAGGGGGGGGGDDD@@@???@@@:::999<<>><<<;;;999:::999???777;;;@@@777555888:::999555WWW888777555666888===666===@@@>>>@@@555999777666444666555111222000...444888RRRPPP===???333222333333---555000111555777<<>>IIIFFFAAADDDBBB999444<<<999:::888===@@@555444777SSS:::444555===JJJFFFTTTJJJ]]]bbbNNN@@@GGG@@@===BBBEEECCC@@@CCC??????IIIEEESSS999>>>;;;777,,,000FFFCCCQQQZZZ[[[ xxxQQQQQQQQQBBB>>>HHH888555222///......,,,---''',,,...&&&***333***((( &&&$$$%%%!!!"""(((%%%!!!'''!!!!!!"""++++++---$$$***'''222777666!!!!!!!!!'''$$$ +++""""""######$$$!!!%%% """$$$$$$"""###"""...'''444---:::@@@PPPLLL;;;@@@VVVQQQAAA333444333999FFF777555333444777333222222;;;)))---///111000,,,***999;;;777222333555555AAA<<<@@@AAADDD777???BBB;;;:::@@@:::@@@@@@555555777;;;;;;;;;777777888999>>>BBBCCC>>><<<888999666:::999BBB===;;;===888888888555888666222444111111999888GGG;;;CCCooo===000222CCC...111222111777;;;999888AAARRR111000444999:::OOO<<>>CCCHHH666===<<>>???:::>>>DDDCCCCCCBBB===DDDLLLGGGHHHCCCBBB666222///333333???eeerrr^^^VVVEEEHHHHHH;;;777999333@@@222---***)))'''%%%))))))(((---+++'''(((***### %%%'''&&&)))$$$ !!!""""""%%%(((***$$$000FFF******$$$ $$$((($$$ )))***!!! """444///!!!)))***444'''(((&&&###!!! !!!$$$###'''+++,,,((((((000===,,,:::444KKKXXXCCCQQQ:::HHH??????EEE<<<999333000555555000222...111+++000...333222///333333555555;;;>>>YYYDDD<<>>>>>===???BBB@@@;;;666;;;===???;;;===BBB@@@:::>>>;;;888444888???<<<888666999999777555444777999444888<<<:::>>>@@@:::888999999:::222444555@@@LLL666<<<<<>>>>>555:::AAA;;;444::::::===EEE```999999333LLLDDDYYY???000111888;;;666888TTT777:::cccFFFDDDCCCDDDEEEBBBCCCAAACCC===???@@@@@@FFFCCCCCCEEELLLeeeMMM[[[;;;///+++000///000bbbeeeyyyhhhSSSFFF;;;HHH999333444333333)))666+++)))(((000$$$&&&---+++---###,,,''')))''''''%%%$$$&&&######%%%'''//////***RRR666)))$$$$$$&&& ---))) (((%%%$$$444...<<<$$$"""&&&$$$))) :::%%%!!!$$$)))---### ...'''&&&333***$$$'''(((%%%***///'''...999GGG -]]]AAA999888666[[[@@@???UUU666777999555444888777777444555333888888<<<666;;;<<>>DDDAAA<<<:::===BBB===>>><<<>>>CCC>>>:::EEEDDD>>>FFFAAA@@@@@@AAA@@@>>>>>>BBBAAABBBBBB<<<:::<<<;;;<<<777444QQQ666<<<555888888777===777888<<<777AAAHHH@@@UUUDDD999;;;666777;;;666222444444555;;;@@@;;;AAA555;;;===CCC999<<<;;;;;;777<<>>444111555:::666...---'''***$$$+++444###""")))(((333((((((,,,)))&&&%%%%%%"""$$$$$$***### ###%%%&&&555;;;KKK333222)))$$$+++ !!! '''((( (((III:::"""!!!$$$%%%###,,,$$$"""!!!...---)))######  ###&&&000((("""%%%+++)))$$$)))(((,,,777??????GGG___:::777777888BBB999KKK888444>>>DDD222111555444333@@@666555999===AAACCC@@@BBBDDD>>>CCCDDDAAAGGGDDDFFF===>>><<<======>>>BBBBBBHHHDDDNNNKKKBBBHHHBBBHHHLLLBBB===@@@EEEMMMCCC>>>BBB@@@;;;>>>;;;:::;;;444333777777555555777<<<:::<<<:::>>>999FFFEEEOOO888EEE888999;;;:::FFF333777666999555666999>>>888<<>>>>><<<777===<<>>HHH===///111777;;;666@@@<<<666<<>>NNNDDD:::777:::666;;;<<<444999???BBBDDDAAA???DDD@@@FFFLLLCCCEEEDDDIIIAAAGGGAAAGGGMMM@@@444999@@@111??????EEEaaaHHHFFFPPPgggOOOPPPFFFAAA:::>>>;;;333444111+++PPP111***222******''')))((()))---***(((%%%111%%%'''(((333888000%%%$$$%%%&&&''''''OOO~~~777&&&+++###%%% *** ---'''999$$$999###*** ######""""""'''777>>>444222111***"""""" ''')))&&&///%%%***'''***(((%%%((((((++++++)))///...//////333333GGG```[[[888EEE;;;999<<<666666111:::777===999@@@KKK:::<<>>>>>======;;;===:::>>>888777777888:::777<<<666777555999===HHH===:::;;;???IIIEEEDDDEEE999:::333:::;;;[[[QQQBBB777===;;;666???JJJ999999222@@@333666:::;;;999;;;999999???DDD>>>>>>===>>>>>>@@@III999777III???BBBAAA===BBBGGG@@@EEE<<>>AAAIII;;;777666888???333888555;;;GGG>>>===<<<;;;EEEAAACCCDDDDDDGGGDDDAAAGGGDDDMMMLLLSSSJJJRRRJJJIII[[[HHHiiiOOOGGGKKKGGGQQQNNNLLLNNNJJJSSSOOOQQQIIIUUUOOOUUUWWWIIIAAABBBDDDFFFEEE>>>GGGAAADDD>>>BBBCCC==================>>>@@@777999555777===FFFAAAAAA<<<:::;;;CCCAAACCC777<<<:::===>>>MMMUUU======;;;;;;===AAA===;;;666666???:::???666999<<<666;;;???>>><<<888<<>>@@@BBBCCCBBB@@@===<<>>;;;666:::999:::;;;>>>FFFFFF@@@===>>>DDD???===CCC>>>@@@EEEDDDJJJHHHDDDIIIXXXNNNGGG[[[UUUrrr```NNNLLLTTTGGGNNNGGGNNNSSSPPPOOORRRQQQDDDGGGHHHFFFHHHPPPNNNJJJDDDHHHLLLKKKGGGFFFAAABBBAAAAAA???BBB>>>???===???EEEAAADDDCCC<<<===:::999CCCHHH\\\NNNDDDCCCCCC>>>AAA???===;;;:::EEEFFFDDDGGG>>>>>>@@@888:::999QQQ;;;@@@888>>><<<;;;FFF===LLLKKKDDDZZZlllBBBAAAFFF@@@DDDLLLRRR===888???BBB999BBBFFF===BBBCCC<<>>===555999000888---...999---******+++///+++((((((###%%%%%%%%%!!!''''''(((???,,,{{{BBB""" """000555%%%%%%###111"""###!!!(((...)))$$$ !!!!!!!!!!!!###!!!111333)))333$$$,,,)))000%%%###...'''&&&###"""$$$ (((%%%///---555777222<<<<<<@@@MMMHHHFFF<<<:::AAACCC;;;@@@KKKHHH???<<<:::??????]]]DDD???NNN777===999DDDCCCDDDFFFKKKEEEKKKKKKLLLSSSLLLgggWWWCCCAAABBBQQQLLLNNNMMMVVVQQQKKKNNNcccHHHLLLKKKGGGCCCEEEQQQBBBAAA???HHHPPPTTTLLLJJJFFFGGGGGGDDD???BBBBBBLLLEEEAAACCCJJJHHHGGGAAABBB<<<<<>>>>>???III@@@<<<===JJJIIIBBBDDD@@@>>>FFFEEEPPPOOOWWWGGGLLLHHHIIIKKKFFFFFF@@@???===<<<(((000888888555999EEEGGGKKKFFFAAA:::<<<999:::222///111>>>111444///...))))))((('''...&&&!!! !!!$$$%%%000333111<<<(((###!!!!!!%%%...---$$$ GGG######)))999 !!!"""%%%###$$$OOO///444&&&)))((($$$$$$&&&===@@@((())),,,&&&###&&&)))***%%%***,,,...@@@;;;333666===CCCJJJJJJ>>>___[[[OOOEEE<<>>AAA===999999AAA@@@DDDAAAGGGOOO???CCCEEECCCAAACCCAAAXXXPPPjjjNNN]]]NNNWWWPPPJJJMMMKKKLLLMMMOOOYYYXXXOOOPPPTTTNNNPPPKKKRRRJJJBBB???CCCLLLLLLOOOCCCJJJQQQVVVQQQWWWJJJdddTTTJJJPPPEEEGGGFFFDDDGGGIIIGGGKKKRRRIIIHHHEEEHHHBBBGGGFFFGGGGGGIIIGGGJJJFFFEEEHHHIIIKKKIIIMMMEEEDDDAAAFFFHHHJJJ===>>>;;;@@@<<<<<<999CCCBBB;;;@@@AAA??????DDDRRROOODDDCCCGGGSSS>>>;;;888666EEEKKKFFFCCCAAAAAA>>>BBBKKKMMMKKKGGGTTTGGGHHHJJJCCCIIIBBB@@@AAAGGG((("""888CCC???999===HHHDDD@@@DDD>>>>>>;;;???444///666666444222???))))))+++777'''((('''$$$&&&###%%%$$$ '''%%%%%%+++:::UUU)))&&&+++"""%%%###!!!((("""%%%)))))) @@@''''''(((666###'''  $$$555###!!!+++)))(((...RRR(((''''''...%%%"""$$$((()))((($$$222;;;===YYY555555777@@@<<>>CCC>>>HHHIII:::======???DDDBBBDDDRRRRRRPPPDDD@@@BBBDDDUUULLLEEELLL\\\LLLRRRGGGMMMMMMNNNIIIOOOTTTUUUQQQRRR^^^TTTQQQKKKNNNMMMQQQNNN===:::JJJ]]]fffFFFFFFPPPUUU\\\YYYSSSOOOPPPIIISSSQQQSSSLLLHHHIIIEEENNNLLLOOOEEEJJJFFFFFFJJJKKKGGGIIIHHHMMMOOOTTTMMMQQQIIIMMMGGGPPPFFFHHHSSSCCC???TTTHHHDDDJJJ;;;999<<<:::???AAA;;;KKKEEE===AAA===CCC>>>CCCBBBAAA@@@>>>@@@??????===???<<>>>>>YYYMMMEEECCCKKKMMMgggkkkHHHDDDAAAGGGEEELLLLLLTTT\\\hhh]]]MMMNNNdddSSSJJJfffZZZZZZ[[[UUUPPPOOOPPPNNNVVVWWWQQQMMMUUU[[[WWWeeeaaa___\\\\\\hhhlllZZZ```\\\UUU\\\ZZZTTTPPPJJJKKKFFFLLLOOOLLLTTTKKKGGGLLLDDDJJJRRRKKKLLLKKKTTTNNNRRRSSSOOONNNOOOGGGMMMEEEHHHVVVRRR@@@EEEKKKRRRIIICCC@@@CCCBBBDDDBBBCCCHHH>>><<>>===AAA>>>CCCCCC===HHHCCCAAA@@@\\\EEEBBBCCCKKKHHHHHHLLLIII\\\TTTJJJBBB<<>><<<;;;:::GGG???===@@@WWWBBB777======<<>>GGGEEEDDDAAABBB???BBBAAA???FFFJJJ===999:::<<>>FFFEEEIIIHHHHHHKKKDDDEEEJJJFFFEEEEEELLLFFFGGGIIIEEEEEECCCLLL<<<555///;;;;;;FFFRRRIIIGGGTTTBBBDDDBBB<<<333333666222444---000111---&&&///$$$((((((((('''###$$$###$$$%%%###)))*********&&&&&&###""" """  ''''''!!!555$$$!!!&&&$$$%%%###$$$%%%***)))"""!!!!!!'''###!!!&&& %%%///'''BBB@@@---***777666999@@@AAA>>>EEEAAA@@@EEEFFFTTT___>>>888;;;===AAA???FFF@@@BBBCCCFFF===FFFAAAKKKCCCKKKEEEHHHFFF>>>RRRZZZ~~~\\\TTTXXXjjjYYY\\\[[[eee___ZZZ[[[dddYYYaaaWWW[[[RRROOOWWWMMMMMMOOONNNVVVWWW[[[bbb```ZZZ]]][[[[[[iiiiiinnn%0mmm```TTT\\\\\\XXX^^^VVVPPPJJJOOONNNPPPUUUSSS[[[SSSMMMGGGHHHKKKPPPJJJ^^^QQQKKKKKKPPPRRRJJJHHHKKKIIILLLJJJNNNEEE@@@888999???NNNJJJBBBBBBJJJCCCGGGKKKIII@@@@@@???CCC>>>@@@BBB<<<@@@BBB@@@>>>>>>@@@;;;AAADDDUUUHHHDDDOOOLLLIII>>>AAA@@@FFFFFFFFFEEESSSJJJJJJQQQxxxEEECCCNNNDDD999------:::???AAAQQQKKKIIIFFFGGG@@@999111000111888111333OOO000000(((,,,%%%***%%%(((%%%---&&&((($$$&&&FFF&&&((()))+++---###((((((######!!!,,,"""&&&!!! $$$AAA!!!'''###!!!"""!!!''' ))) """,,,###"""""" !!!###!!!###$$$&&&$$$"""$$$(((...111555+++111333444...555555OOOGGG;;;666999<<<===GGGbbbVVVBBB===AAAHHHFFF<<>>CCCDDDNNNLLLJJJGGGFFFNNNLLLMMMBBBAAABBBEEEBBB@@@HHHBBBBBBDDDLLLDDD>>>BBB999LLL>>>IIIKKKBBB???;;;AAA<<>>333+++222111///000,,,555???DDD:::;;;111666555999AAADDDQQQPPP@@@999>>>QQQCCCEEEPPPeeeKKKFFFUUUDDDRRREEEIIIRRRGGGJJJMMMXXXUUUpppC6uuuppp zzzmmm zzzxxx___VVV]]]eeeiiieee___QQQ___iiiiii&sss```^^^^^^VVVRRRoooooottteee]]]~~~ooofff______fffhhhccc___YYYUUUVVVUUUaaaXXXUUUWWWdddYYYSSSRRRRRRSSSPPPSSSLLLOOOWWWKKKJJJ;;;:::FFFLLLIIINNNJJJJJJIIIEEEMMMTTTNNNIIIFFFGGGFFFOOOLLLJJJDDDFFFGGGIIIHHH@@@BBBGGGBBBAAAFFFDDDBBBEEEVVVJJJ@@@BBBFFFEEEBBB===CCCKKK===???@@@CCCEEECCCIIIJJJIIIIIIEEEFFFGGGFFF<<<000@@@NNNEEEGGGIIIEEENNNIIIRRROOOAAA222666BBB===888222333777...---%%%***---&&&)))(((%%%---$$$!!!%%%###!!!!!!%%%(((((((((###***&&&"""###%%%'''%%% """"""%%% (((+++!!!###%%%///AAA)))'''"""---&&&&&&'''""",,,***...555111&&&(((000666,,,...,,,---333<<<,,,111:::ZZZ888777333555888333000111333555333777777999BBBBBB[[[xxxLLLIIITTTFFFFFFIIIFFFIIIGGGIIIKKKNNN```iii mmmoooccchhhHaaalllhhhhhhhhhUUUTTT___TTTUUUWWWfffVVVjjjqqqjjjeee\\\LLLPPPcccfffjjj___cccbbb{{{yyytttzzznnnrrrjjjeeeaaaaaa^^^eee[[[ZZZXXXZZZ\\\]]]\\\```^^^ZZZSSSRRRTTTRRROOOTTTOOO???:::777FFFNNNRRRYYYVVVPPPQQQLLLuuuiiiPPPEEEGGGHHH\\\LLLLLLLLLaaaNNNJJJHHHHHHCCCCCC===GGGDDDEEEFFFFFF888444777>>>KKKOOOJJJDDDFFF???DDDCCC===<<>>===333///,,,000---///'''(((+++'''&&&+++&&&&&&&&&((("""(((######(((+++---'''@@@"""!!!#########*** AAA%%%###$$$((($$$###333$$$((($$$###$$$###555+++###$$$---!!!'''+++%%%...***999...///...<<<)))///444444000000000---222444---222444======@@@???;;;:::222:::777888@@@BBB???DDDDDDBBB>>>CCCGGGDDDCCCGGGBBBFFFKKKKKKHHHPPPfffddd~~~pppqqqoooeee```pppzzzbbbhhh}}}lll]]]bbb]]]YYYTTTaaa___YYYWWWPPPZZZ]]]\\\bbb___WWWXXX]]]kkkccciii}}}xxxrrrccc```mmmfffpppnnnnnnvvvlllnnnnnn|||ppp[[[aaaiiikkkiiioooaaa\\\]]]\\\YYYVVVSSSTTTSSSYYYVVVTTTEEEFFFIIIMMMNNNTTTTTTUUUNNNUUUVVVYYYMMMIIIOOOPPPjjjUUURRR[[[ VVVMMMIIINNNLLLFFFCCCQQQIIIGGGIIIBBB<<<===111AAAZZZFFFGGGEEEKKK???<<>><<>>PPPQQQWWWVVViiiSSSXXX\\\iiigggzzzssssssbbbeeefffhhh[[[___[[[UUUOOO]]]KKKOOOQQQWWWPPPRRR[[[WWW[[[nnngggkkkiiieeeyyyxxxzzzhhhcccZZZmmmdddcccgggiiiiiinnn nnnsssdddUUUUUU^^^fffaaaaaa\\\``````VVVUUUTTTXXX^^^]]]YYYWWWRRRJJJQQQOOORRRQQQRRRQQQWWWiii```XXX]]]GGGKKKOOOiii(^^^RRRRRRTTTXXXQQQKKKLLLJJJ@@@AAAGGGJJJHHHQQQEEE===<<<>>><<>>EEEFFFLLLIIIGGGEEE???>>>???>>>CCCBBB:::444333111///,,,000000(((###(((((('''&&&))),,,((($$$'''$$$///%%%"""%%%$$$"""$$$### ###"""'''%%%!!!###---""""""'''CCCccc%%%!!!''',,,555;;;@@@:::>>>'''%%%---&&&"""!!!######'''(((444...---+++...,,,***)))+++111---***,,,777///444111888888@@@:::555EEE===888999===@@@EEEQQQDDDDDDBBBAAAFFF<<<999;;;BBB<<>>QQQWWW<<>>FFFIIINNNLLLMMMKKKMMMRRRMMMLLLNNNppp---000:::AAA>>>@@@BBBQQQIIICCC@@@??????FFF===???:::EEE777444555000444(((%%%///+++%%%&&&&&&'''&&&+++)))((()))+++(((###"""666"""###%%%(((&&&###&&&*** $$$###'''$$$###***777666888:::sssuuuRRR,,,)))***&&&###888AAAkkk"""%%%,,,CCC---,,,111(((...888%%%222666333777666555??????OOO@@@666777>>>:::===GGG???III===888:::AAADDD999???>>>999888:::???SSShhhQQQLLLQQQMMMKKKKKKKKKRRRSSSYYYMMMKKKUUUYYY```\\\YYY___XXXaaa___\\\]]]TTTVVVcccXXXVVVVVVUUUTTTUUU[[[PPP```eeeaaa]]]aaagggvvvgggUUUccceeeooouuueeefffjjjhhhfff^^^iiigggcccbbb\\\jjjiiidddeee]]]ZZZ[[[ZZZ```___\\\ccc\\\]]]```dddbbbcccddd[[[[[[[[[WWWSSSVVVXXXZZZ[[[hhh[[[WWW]]]lllWWWVVVXXXVVVLLLQQQQQQRRRMMMKKKGGG>>>EEEIIIFFFNNNPPPMMM999@@@QQQ>>>777CCCOOO^^^rrrTTTTTTUUU===<<>>DDDIIILLLEEEBBB???DDD:::AAA===AAA;;;KKK>>>111888***+++---"""(((!!!###%%%&&&,,,...333***))),,,)))$$$""""""$$$"""###!!!###'''888((($$$555(((###!!!%%%---"""!!!///HHH222+++777cccJJJ(((&&&))) %%%---===sss'''+++222555,,,666222===(((333000444FFF111555555EEE<<>>===???BBBKKKXbbbUUUuuuEEE???AAA:::BBBGGGDDDNNNLLLKKKMMMNNNPPPGGGEEE999666666444,,,888@@@BBBGGGEEE>>>@@@AAA===EEE???>>>;;;;;;eee@@@888---'''(((%%%''''''''''''%%%***&&&+++===---,,,''')))$$$###$$$&&&"""$$$&&&$$$'''777 ###$$$###---&&&***)))$$$QQQ:::333???999)))%%%---+++'''###***######@@@+++000+++///888111666000777333///555777DDD555PPP;;;666999;;;NNNPPP<<<>>>???@@@OOONNNNNNFFF@@@<<<@@@===;;;888:::999888AAA===111<<<<<>>===AAAMMMggg -XXXIIIKKKJJJLLLCCCBBB???GGGHHHIIIIIIMMMRRRLLLSSSNNNJJJOOO<<<***000,,,555CCCHHHGGG???EEELLLBBBDDDFFFRRR>>>;;;<<<===777222,,,+++***%%%$$$'''999$$$&&&###+++'''///'''&&&$$$######,,,$$$%%%###%%%&&&*** """ &&&$$$'''GGG---'''!!!(((FFF:::,,,%%%222+++%%%$$$$$$$$$(((111AAA,,,---'''(((///,,,///000+++...555333222777666===IIICCC666:::JJJIIIKKKBBB<<<888999QQQ^^^UUUAAA@@@CCC<<<;;;999555999HHHXXX>>>EEE;;;666======CCCIIIIIIFFFPPPNNNccc -qqqXXXSSSHHHPPPWWW^^^SSSQQQeeeQQQVVVZZZ[[[WWW___VVVRRRPPPSSSUUUWWWXXXYYYIIILLLXXX\\\RRR\\\bbbqqqeeeggg\\\bbb``````cccjjjeeelllsssgggeeehhhnnndddhhhjjjqqqnnnjjjlllmmmiii```___ccckkkggg\\\XXX\\\ccc[[[\\\]]]bbbbbbaaa```___]]]bbb]]]]]]aaabbb^^^]]]\\\UUUYYYYYY]]]ZZZSSSUUUPPPOOOPPPTTTQQQVVVRRRJJJNNNKKKKKKKKKJJJDDDDDDBBBBBBBBBCCCNNNJJJWWWKKKLLLGGGKKKGGGAAA>>>GGGHHHHHHKKKLLLMMMQQQJJJMMMJJJ^^^WWWIII888CCC222DDDGGGIIIKKKEEEBBBCCCEEEKKKBBB>>>======999777===444000******'''&&&%%%---+++---(((>>>&&&$$$%%%"""$$$###$$$%%%&&&$$$ %%%(((###%%%%%% """""" ###'''%%%!!!'''+++!!!***'''///000,,,''')))***'''&&&+++...000+++111222,,,222---,,,---***'''...000???HHHMMM@@@===EEEDDD???===@@@999;;;:::<<<888777::::::DDDEEE<<<<<<000333888HHHQQQ;;;HHHIIINNNNNNEEEHHHLLLLLLFFFKKKYYY[[[QQQ^^^YYYYYYVVVJJJTTTUUULLL```ZZZ\\\\\\YYY[[[VVVWWWRRRNNNQQQSSSUUUSSSZZZ___FFFTTTXXXSSSQQQdddccc___bbbccc```]]]______uuueeeggguuutttlllgggddddddeeerrrfffiiihhhhhhttttttiiieeecccbbbeeeaaa```___ZZZYYYZZZWWWZZZZZZ^^^[[[YYYZZZ[[[YYYaaa\\\^^^bbb___^^^^^^^^^WWWXXXZZZWWWWWWTTTYYYPPPMMMTTTVVVRRRNNNLLLMMMMMMKKKKKKOOONNNMMMHHHCCCCCCAAA>>>>>>BBBJJJMMMDDDDDDBBB???@@@DDDDDDDDDIIIMMMNNNJJJLLLLLLHHHOOOOOO???666@@@555444EEEOOOPPP@@@EEEDDDCCCBBB;;;===;;;;;;;;;AAA@@@ZZZ222---333///&&&&&&***''')))+++)))***,,,+++777"""+++$$$$$$%%%111666???111 ######+++###!!!&&&((("""''''''"""&&&++++++,,,---"""+++999***''',,,333,,,***111777***+++******)))---555777<<>>???DDDMMMIIIHHH===<<<:::AAAKKKUUUMMMQQQJJJPPPLLLEEEWWWPPPDDD@@@HHHBBB///PPPZZZ\\\JJJCCCPPPGGGCCCBBB===@@@===AAA======666+++)))...))),,,555///(((***(((***'''+++***&&&'''$$$... """%%%$$$JJJ'''!!!###((($$$###''')))((( !!!)))!!! (((%%%666...---***)))))))))***(((+++&&&LLL+++111+++111---///666999===555666999:::III777999EEE???:::888>>>LLL:::BBB;;;555>>>BBB;;;:::777:::>>>333999GGGRRR@@@AAAPPPTTTXXXLLLPPPHHHFFFDDDIIIMMMWWW{{{ddd\\\ZZZ]]]IIISSSQQQRRRUUUQQQYYYRRRGGG]]]MMMMMMDDDTTTKKKLLLQQQQQQIIICCCJJJGGGOOO[[[```ddddddccccccbbb\\\XXXbbbjjjdddtttccceeejjjhhhjjjnnnhhhbbbffflllgggjjjqqqqqqrrrlllxxxssssssuuummmnnneeeaaabbbdddhhh\\\^^^\\\aaa______eee```^^^XXX[[[YYY]]]jjjccc``````cccccc]]]]]][[[YYYVVVWWWWWWSSSPPPNNNRRROOOIIIHHHJJJIIIHHHQQQ___PPPMMMKKKKKKIIIBBB999<<>>GGGNNNPPPIIIMMMJJJLLLLLLYYYSSSMMMCCC>>>KKK000???CCCIIIJJJ\\\DDDFFFBBBCCCCCC======888:::333333,,,***...***(((***......"""&&&###&&&&&&'''000,,,###### '''222$$$ $$$###(((''')))&&&&&&'''$$$"""+++111***BBB$$$"""&&&###FFF)))***++++++'''---'''+++AAA))))))......111444999:::666CCC888???<<>>HHHHHH[[[SSSJJJNNNOOO[[[NNNDDDGGGFFFKKKZZZppp\\\YYYWWWaaa\\\ZZZRRRYYYSSSVVV___WWWLLLUUUMMMBBBAAADDDIIIFFFJJJXXXMMMHHHFFFLLLSSS]]]fffbbb^^^___ccceeeddd___eeeeee___bbb```eeeppptttnnnjjjtttcccdddfffjjjkkkmmmkkkssstttvvv{{{tttqqqppphhhjjjllljjjiiibbbbbbZZZ\\\^^^^^^___bbb``````ZZZ[[[^^^___eeeddd```^^^ggg]]]^^^[[[\\\UUU\\\VVVTTTUUUZZZSSSQQQKKKMMMKKKHHHJJJIIIKKKIIILLLMMMLLLRRR]]]>>><<<===NNNCCCBBB@@@>>><<<;;;???CCCTTTJJJMMMNNNNNNQQQXXXWWWKKKFFFBBB@@@<<<555BBBEEEAAAEEEAAAEEEBBBBBBAAACCC888444999999///---,,,000(((,,,)))+++((((((%%%)))&&&+++---+++%%%555///'''"""''''''((('''%%%'''###,,,,,,%%%"""###'''&&&)))&&&&&&&&&$$$%%%'''%%%<<<+++(((***===+++///%%%&&&,,,)))''',,,555333333<<<888666CCCMMMSSSaaavvvUUUGGG999>>>@@@CCCMMMAAAEEEBBB<<<>>>888;;;@@@<<<444777666===CCCGGG@@@XXXNNNQQQSSSJJJVVV^^^OOOQQQIIIMMMMMMNNNUUUVVVTTTJJJQQQZZZjjj\\\]]]fffaaaRRROOOOOOPPPIIIBBB<<>>CCCEEEAAA???:::888111???DDDLLLOOOPPPOOOTTTRRROOONNNIIIAAA777777<<>>888666???------***>>>///...(((%%%%%%***%%%"""&&&&&&%%%$$$"""&&&(((%%%!!!###%%%)))***---,,,000AAA"""%%%%%%###111&&&<<<555###$$$((((((***&&&***,,,222+++444***'''###''')))(((......000666FFF;;;999555:::>>>```aaaEEEZZZFFF@@@;;;IIIOOO___HHHFFF;;;;;;<<<^^^VVV999;;;555666444888;;;AAAJJJQQQLLLRRRIIIIIIGGGHHHUUUQQQCCCJJJLLLPPPPPPNNNGGGSSSTTTXXXfffeeeiiiwwwRRRLLLOOO^^^PPPFFFCCC???GGGGGGEEELLLMMMRRR]]]WWWYYYVVVccc\\\\\\___oookkkfffssseeebbbjjjnnnffffffvvvttttttmmmpppmmmooommmgggiiiiiixxx}}}vvv}}}wwwooopppwwwwwwwww|||wwwooolllqqqkkkhhhdddfffcccfffddd______aaaaaaeeehhhdddcccaaaaaa]]]]]]\\\\\\[[[ZZZWWW^^^]]]VVVNNNEEEQQQ\\\ZZZVVVVVVQQQTTTNNNQQQQQQLLLJJJGGG===???BBBEEE;;;888333999777CCCJJJJJJJJJKKKPPPQQQUUUHHHEEEBBBGGGFFFGGGWWWNNNDDDEEECCCCCC???MMMGGGFFF>>>888333000//////111+++---222+++111%%%!!! &&&$$$"""######$$$((($$$&&&######"""'''''')))***---)))***&&&!!!&&&$$$(((...""" $$$&&&((()))"""(((---GGG)))%%%((($$$%%%((("""///444000>>>OOOFFF999<<>>;;;999222555222888:::MMMIIIFFFCCCEEEBBBGGGJJJHHHNNNNNNGGGJJJFFFVVVUUUOOOLLLHHHHHH:::BBBBBBeeegggYYYRRRVVV[[[QQQMMMQQQRRROOOIIIQQQRRRSSSZZZ]]]aaaZZZ___[[[]]]```aaa]]][[[ccc```}}}nnngggfffdddgggjjjqqqoookkkeeecccgggiiilllzzz.@xxxwwwjjjmmmqqqrrruuu}}}www{{{xxxvvvzzz}}}oookkkggghhhjjjkkkccccccllljjjgggfffkkknnneeennn^^^```[[[bbbfffbbb]]]YYYZZZLLLEEEOOOVVVUUUTTTQQQPPPPPPUUUQQQOOOMMMFFFEEEGGGHHHIIIGGG===555...;;;@@@IIINNNKKKLLLLLLOOONNNEEEGGGHHHLLLOOOMMMAAA===KKKGGGAAA???AAAFFFAAAKKKBBBAAAHHH444444;;;333,,,...)))555------,,,111***111...(((&&&)))AAA===///+++&&&'''(((&&&%%%'''&&&(((111777///,,,///+++###%%%$$$$$$%%%%%%)))---&&&***///)))'''''''''222+++...444...666333777555333999:::888CCCDDDJJJUUULLLBBB<<>>GGG???GGGFFFqqq]]]FFFFFFIII<<>>BBBMMM===HHHDDD@@@FFFEEEGGGSSSOOOHHHDDDFFFIII^^^dddIIINNNOOOSSSLLLRRRQQQMMMMMMQQQSSSQQQPPP]]]SSSWWWSSSMMMHHHOOOOOO^^^WWWRRRXXXXXXggg```YYY]]]gggjjjpppuuubbbhhhllljjjzzzwwwooohhh{{{wwwmmm[[[SSS\\\ZZZ[[[eeekkkxxxvvvxxxmmmllljjjnnn}}}www -zzzkkkuuurrr{{{wwwrrrpppttthhhbbbfffuuuaaaiiibbbgggiiinnnmmm|||yyyuuuhhhkkkiii]]]VVVSSS```TTTOOOVVVQQQ[[[XXXSSSZZZWWWXXX]]]SSSQQQEEEHHHNNNMMMKKKHHH@@@444<<>>IIIMMMKKKMMMOOOWWWQQQSSSLLLIIIDDDNNNLLLGGGGGGBBB:::>>>666???<<<---((()))---000,,,+++,,,'''///000---...******,,,&&&%%%***((()))&&&***((()))'''---)))###000333***)))***)))%%%---###+++)))...+++((('''''',,,***,,,444+++555;;;777999333HHHFFFKKKgggQQQBBBYYYDDDGGGNNNBBBDDDLLLDDDEEEMMMHHHXXXCCC999<<<<<<999:::EEEEEEBBB:::999JJJSSSGGGIIIKKKGGGUUUJJJbbb???EEEHHHRRRlll\\\UUUNNN```bbbWWWTTTNNNOOO___ZZZNNNNNNPPPOOOOOOHHHGGGEEEQQQUUU^^^VVVVVVSSSZZZ[[[___aaa]]]bbbiiifffhhhgggqqqiiikkkppprrrrrr{{{ -gggTTTQQQWWWhhhqqqrrrsss}}}vvvoooyyyvvvvvvzzz||| }}}{{{xxx{{{ yyyuuupppqqqjjjgggiii|||}}}llldddbbbgggkkk|||yyygggjjjeee]]]YYY[[[ZZZOOOSSS^^^ZZZWWWYYY]]]YYYUUUSSSTTTQQQPPPHHHJJJSSSFFFDDD888PPPOOOGGGDDDJJJIIILLLKKKLLLLLLGGGAAA>>>NNNQQQKKKXXXaaahhhXXXYYYYYYJJJGGGOOOUUUDDDKKKOOONNNCCC???<<<555///...///000...(((+++***''',,,111,,,***)))+++000QQQ???AAA)))(((&&&%%%...((('''))))))>>>RRR&&&'''"""&&&(((+++...---$$$)))'''###'''###((((((+++///---555LLL666???>>>WWWJJJQQQ}}}]]]HHHLLLCCC<<<>>>III@@@;;;:::???AAAPPPRRRUUU???;;;IIIEEE777BBBAAA@@@>>>@@@DDDEEEHHHGGGHHHPPPPPPOOOXXXIIIMMMRRReeeXXXhhhTTTVVVTTTRRRYYYVVVHHHOOOOOOSSS```IIIEEECCCBBBIIITTTIIIUUUVVVSSSOOOSSSVVVXXXfff```\\\XXXUUUrrr}}}kkkaaawww]]]\\\```\\\___cccnnnnnnlllmmmjjj^^^```gggpppttt2xxxnnnqqquuu -  -  {{{ssspppnnnnnnoookkkbbbeeegggdddnnnzzz lllllljjjeee\\\\\\VVVXXXQQQPPPXXXcccXXXUUUUUUWWWVVVTTTOOOSSSIIIHHHJJJIIIMMMKKK\\\KKKGGGLLLIIIPPPLLLJJJNNNUUUDDD<<>>333111:::===<<>><<<555TTT___```]]]SSSZZZggg\\\XXXMMMEEECCCDDDEEEZZZGGGMMM@@@???DDD999555===111///---)))111111444---***...'''***---000///<<>>DDD888777EEEBBBoooaaayyyvvvXXXVVVUUU]]]eeeZZZ___]]]\\\WWWqqqpppQQQOOOVVVaaaaaaRRRUUUKKKHHHMMMOOOHHHKKKOOOBBB<<<<<>>888CCCOOO~~~ yyyfffbbbdddgggkkklllaaaaaapppWWW[[[TTTVVVRRRJJJOOONNNOOOLLLLLLJJJOOOGGGCCC;;;BBBEEEGGGIIIJJJHHHSSSUUU[[[YYY]]]aaaeeefff___^^^ggg```aaabbbhhhuuufffiiiwwwooopppvvvrrrpppoooeeemmmtttsssvvvsssppp~~~ "="''#$-!vvvooopppssszzzxxxxxxwwwzzzssslllnnnqqqsss|||qqq{{{|||wwwmmmhhhcccLLL@@@CCCIIIQQQTTT]]]\\\XXXTTTOOOPPPKKKVVVbbb [[[OOONNNOOOQQQMMM>>>;;;GGGGGGKKKEEELLLQQQQQQ\\\aaaXXXRRREEEOOOJJJOOOLLLHHHMMMJJJIIIJJJHHHOOO>>>;;;<<<888999AAA@@@666555000,,,,,,+++---666)))***///---HHH888<<<...---444222FFF444...333@@@000''')))***'''(((---***,,,,,,222///333222000'''))):::'''///000555NNNJJJLLLpppgggsssiiibbbYYYjjj%xxxaaaHHHHHHEEEBBBBBBCCCMMM999999>>>BBBQQQzzz$22 vvv|||zzznnnwwwnnnrrr~~~bbbYYYZZZdddOOOHHHTTTOOOOOOPPPNNNJJJHHHCCCNNN;;;===FFFJJJPPPGGGMMMSSSSSSSSSUUU^^^\\\iiieeeccc^^^```jjj]]]```gggmmmuuurrrsssuuu{{{zzz~~~xxxyyyqqqrrrrrrsssyyyzzzuuu~~~ ~~~ 57/ # )pppqqqssszzz}}}{{{~~~tttyyy{{{sssooorrrzzzyyyzzzrrrwwwrrrlllnnn[[[KKKHHHRRRUUUTTT[[[bbbgggUUUKKK@@@EEESSSZZZpppUUUHHHHHHJJJ@@@???FFFGGGIIILLLIIIIIIKKKMMM[[[TTT]]]TTTMMM@@@...999EEEKKKJJJNNNQQQGGGMMMHHHAAA<<<777IIIPPP999:::999777444111...------------...222///...'''---:::111444888---HHHGGG...***bbb444)))+++(((111%%%***999DDD//////(((444)))+++''''''///111+++444666HHHAAA@@@cccnnn\\\kkkhhhiiimmm|||GGGQQQCCCCCC>>>???VVV@@@@@@@@@@@@???NNNwww4'&9(bbb[[[^^^^^^TTTWWWPPPKKKMMMOOOPPPMMMMMMLLLPPPKKKZZZIIIMMMJJJOOONNNNNNRRRRRRVVVWWWaaa\\\[[[eeeeeeaaabbbgggjjjjjjiiixxxtttxxxxxx~~~{{{{{{sssyyy}}} - -yyyxxxjjj,(3"! sssnnntttuuuzzzssszzzzzzxxxxxxnnnzzzuuurrrzzzyyywwwuuuoootttcccRRRXXXVVVcccXXXZZZ]]]]]]SSSRRRRRREEESSSYYYyyy___UUUMMM@@@FFFCCCMMMKKKIIIKKKIII]]]VVVUUUiiiUUUUUULLLHHH444---???HHHQQQUUUUUU\\\TTTJJJOOO<<>>555444///+++,,,+++///...333000...000///222AAA111666KKK,,,,,,---)))---333...(((''',,,...---+++///000555'''******---)))+++***(((000)))KKKOOOCCCPPPNNNXXXeee{{{mmmfff```___cccfffNNNJJJeeeMMMQQQAAA===AAAIIICCCBBBIIINNNLLL[[[>=.95+-'#'6lll]]]___^^^RRRMMMOOOOOOQQQPPPNNNMMMRRR___eeeuuuGGGVVVHHHMMMJJJNNNMMMNNNMMMTTTXXXXXXWWWdddhhhhhhiiinnnvvvxxxmmmmmmvvvxxx~~~zzzE', & www|||{{{%$~~~   uuujjjvvv~~~  yyyxxx{{{{{{|||rrr|||zzztttnnnsss|||eee\\\^^^^^^ZZZTTTZZZUUUUUUQQQNNNCCCKKKHHHWWWwwwQQQMMMIIIMMMFFFCCCFFFIIIPPPPPPRRR___VVVXXXSSS___\\\NNNYYYiiiGGGNNNTTTZZZNNNIIIFFFIIIFFFDDDQQQAAAXXX~~~lll:::333222444///,,,+++///444222222+++...,,,222222iii:::333999,,,)))((()))---222333+++...333+++---,,,+++......***000+++---,,,///222---111333666RRRHHH@@@YYYDDDLLLuuujjjaaaEEETTTFFFTTTTTTXXXGGGHHHFFFFFFBBBBBB===???CCCJJJKKKTTT\\\}}}IKFCEH?@Lzzzkkkjjjhhh]]]VVVPPPKKKMMMMMMMMMIIIRRRPPPPPPhhh\\\AAA@@@BBBFFFIIIOOOLLLCCCRRRaaa___```ddd]]]gggeeekkk___sssyyy~~~zzzqqq1# # &8!   - # ~~~uuu~~~yyy - yyytttuuuppplllssszzzkkk^^^[[[UUUSSSRRRUUU\\\XXXMMMPPP\\\WWWGGGNNNYYYNNNKKKEEEBBB===DDDAAABBBOOOPPP\\\[[[___^^^]]]ZZZPPPGGGKKKnnnaaaRRRRRRQQQTTTIIIRRRCCCFFFHHHDDDAAA;;;@@@FFF333...111000222AAA999111)))444000))),,,///***444EEE???AAA888...(((555222333888;;;333555LLL555555333000111444000333------///,,,...BBB000444888FFFGGG<<<>>>EEEjjjlllJJJEEEFFFCCCJJJBBBFFFOOONNNJJJBBBHHHBBB===???DDDDDDEEENNN[[[fffyyy-ZYZ]ZZ`9 -{{{nnn[[[]]]TTTPPPNNNLLLQQQIIIEEENNNXXXWWWvvvWWWIIILLLMMMOOOKKKQQQPPPTTTZZZ\\\___ggggggbbbeee```iiilllqqq }}}vvvwwwvvv|||$' %,CW@    - }}} {{{yyy~~~   - ~~~~~~yyyyyylllnnnnnnmmmhhhhhhuuusssqqq\\\___RRRddd]]]]]]ddd[[[CCCVVV___LLLHHHNNNOOOOOOKKK<<<;;;===;;;HHHBBBFFFMMMPPP\\\eee]]]ZZZWWWUUU]]]eeeTTTUUUMMMNNNTTTNNNIIIFFFCCCBBBJJJ???<<<<<<:::===>>>444111111222EEE:::222:::++++++---///222:::EEEFFFAAADDD---(((%%%111FFF999444...111000222666444000,,,---222222222...//////......222888BBB@@@FFFNNNOOOJJJSSSxxxJJJHHHAAAIIIHHHCCCPPPLLLUUUMMMKKK>>>===PPPGGG???AAACCCKKKPPP]]]iiixxxAQkmkgmYA)hhh\\\TTTRRRRRRNNNMMMIIICCCFFFJJJ]]]^^^FFFOOOaaaRRRTTTQQQWWWUUU\\\XXX\\\ddd``````eee[[[___fffhhhoooppp~~~wwwrrr{{{wwwyyy~~~ )%#&GA |||}}}}}}  qqq - }}} |||  -xxxvvvuuuwwwuuuooouuupppvvvlllnnniii[[[[[[^^^]]]``````\\\ZZZQQQUUUGGG===KKKYYYTTTKKKKKKDDD???===888???DDDGGGJJJSSSSSS]]]ZZZWWWVVVcccfffllldddIIIWWWOOOKKKRRRGGGAAA@@@EEEFFFBBBBBB@@@999999===666666222888<<<666888333)))***///---555;;;PPPEEETTTjjj666,,,))),,,]]]555///222111111///111888333***+++000111333+++++++++...???444000666777EEEDDDFFFEEEAAAFFFCCCLLLDDDAAANNNTTTWWWRRRUUUqqq@@@<<<>>>ZZZ>>>===@@@CCCDDDOOOZZZbbbzzzDan{{tj_I8~~~iii```\\\XXXRRRKKKCCCBBBCCCBBBFFF===555<<>>>>>??????KKKLLLMMMSSSXXXTTTWWW[[[```rrruuuooo[[[OOOzzzLLLKKKBBB@@@BBBIIIPPPEEEBBB999888888???RRR333<<<111:::999>>>CCC222555***,,,666:::IIIcccyyyPPP222(((***///111000444,,,222)))+++111111...,,,555---...,,,...+++222666@@@///<<<000111AAA@@@LLL[[[DDD===EEEOOOJJJJJJIIIIII]]]HHHFFFIII999666<<<@@@>>>999>>>CCCEEENNNZZZaaawwwEaq~tj_P6nnn___ZZZ\\\RRRJJJAAADDDBBB???:::444YYYHHHSSSVVVbbbZZZ]]]kkklllllliiioooccckkkffffffllljjjdddcccmmm|||rrrxxx  - - -  -~~~}}}yyymmmkkkoooppp}}}rrr zzz  ttt  -xxxzzzpppllljjjrrr~~~|||ooohhheee]]]\\\___^^^\\\ZZZ\\\VVV^^^RRR\\\^^^YYYXXXWWWOOOPPPDDDHHHDDDCCCFFFIIIJJJMMMTTTYYYWWW[[[fffggghhhaaagggmmmfffMMMIIIDDD@@@AAA___LLLVVVDDD???<<<:::888KKK444555222777???888000777,,,111CCC555===666999IIIaaaTTT111%%%---+++444222000222)))111%%%)))(((***111000+++***+++///444---000555666---999GGGIIIFFFHHHHHH===<<>>QQQ\\\]]]\\\iiijjjnnniiipppooogggmmmrrrnnnhhhppptttpppsssppp~~~tttwwwzzz% zzzppptttyyykkkooosssyyy~~~{{{|||yyy |||  uuuppp -|||www  lllvvvrrrqqqtttllllllhhhccchhhdddZZZaaaaaaaaaZZZ]]]WWWUUUXXXWWWXXXTTTRRRPPPIIIHHHIIIFFFHHHLLLHHHMMMyyyWWWaaaYYY[[[bbb^^^^^^SSS[[[|||PPPBBB???EEECCChhhUUUGGGAAAEEEHHHGGG;;;555777777===444,,,777===>>>NNN777:::222777777FFF666TTT555DDD///------444222AAA222***000$$$'''&&&***&&&(((+++(((+++///+++333000...777===FFFccc:::HHH???EEEAAABBBMMM@@@CCC<<<::::::@@@999999555777777666999999@@@>>>EEEEEEQQQYYYdddrrr -:dlovreT< pppmmmiii```XXXJJJDDDJJJKKKKKKEEE@@@LLLPPPSSS[[[]]]___fffvvvvvv}}}mmmooo}}}oooeeeooopppkkk|||}}}wwwyyy 2(, -  -}}}rrrmmmjjjlllxxx}}}{{{tttsss{{{}}}}}}   |||ttt ddd tttvvv|||vvvnnnfffdddkkkiii\\\]]]```eee\\\fffYYYUUUVVVTTT]]]YYYXXXYYYIIIEEEJJJGGGIIIFFFKKKRRRYYYSSSWWWZZZ```fffmmmaaaWWW\\\QQQQQQDDD@@@???>>>OOOFFFIIIBBBAAALLLAAA???DDDsss;;;:::111777;;;:::888<<<111EEE:::999999QQQ???555222...111@@@<<>>???:::===EEE666222666JJJ===999:::??????HHHPPPWWWVVVfffKRYcyyiO:!dddaaa]]]TTTLLLGGGKKKSSS[[[MMMLLLQQQRRRSSSRRRYYYbbbbbbgggsss|||xxxppphhheeewwwzzzrrr{{{yyy )2/!yyy -  }}}uuummmjjjvvv}}}}}}|||wwwzzz - -}}}~~~  sss  {{{xxx)+|||vvveeegggxxxeeeVVVaaaaaaYYY[[[]]]\\\YYYXXXWWW]]]tttUUUTTTQQQ???KKKLLLLLLLLLKKKTTTTTTRRRYYYaaaeeettthhhddd[[[ZZZ???333<<>>555---888???:::AAA>>>333:::;;;555'''(((%%%%%%(((&&&&&&(((333,,,---...111...::::::===BBB666888777EEEEEEBBB===???MMMCCC:::===:::KKK222000,,,555>>>777888444:::<<>>:::DDDMMMLLLOOODDDFFFBBBBBB???333333///555:::555111333999:::===666444<<<444///---:::BBBIIIIII:::777AAAAAACCC%%%***!!!$$$(((%%%''''''$$$+++...---444+++444:::===>>>@@@:::BBBIIIRRR:::888444000111555222111AAA111+++---///;;;666777444<<<@@@LLLHHHKKKTTTvvv|||9PQXM8/yyymmmggg]]]___SSSQQQKKKPPPUUUSSSSSSQQQRRRYYYVVV^^^vvvzzzrrrvvvuuu~~~zzz uuuuuuppp~~~  zzzyyywwwqqqyyyxxxzzz}}}~~~  -  -   - % xxx  uuuiiixxxooo 1Luuuxxx }}}yyy}}}vvvqqqfffaaaggg~~~ iii^^^hhhhhhddd[[[[[[]]]^^^\\\YYYcccTTToooGGGCCCCCCHHHIIINNNPPPOOO```XXXlllqqqiiimmmsssppp```[[[GGG>>>:::EEEGGGCCC:::<<>>>>>;;;<<<555333,,,333,,,,,,000000000000000///>>>>>>999DDD>>>WWWDDDDDD888<<<444111222HHH&&&***((( !!!###&&&'''(((,,,///111000111333999<<<:::777333>>>===;;;888777333555...,,,+++000333333333666///666???888999:::>>>KKKGGGVVVXXXSSS```4.49-0uuudddOOOQQQKKKPPPMMMVVVTTTSSSRRR___ZZZeeegggjjjrrr-||||||sss|||||| www    }}}}}} -   -  rrrhhhjjj .6uuu~~~sss wwwvvvzzzyyyoootttwwwddd___YYYeeecccfff```[[[[[[[[[WWWVVVVVVSSSUUUVVVIII<<<@@@YYYXXXNNNNNNUUUXXXVVVlll|||llleee```~~~yyyKKKAAAAAACCC>>>???DDDFFFCCCBBBCCCEEE999666999999222---000---...222111***///;;;<<>>QQQBBBMMMCCCTTT888???000...DDD^^^&&&!!!'''"""""")))%%%'''))),,,111///...222666AAA888;;;888666777EEEEEE888333333444000---444444444444444666777777222888444777CCCBBB]]]SSSPPPEEElll}}}  qqq^^^XXXQQQGGGOOOWWWTTT[[[jjjjjjkkkoooqqqeeeqqq}}}~~~vvvvvv|||yyy~~~qqqkkkooonnnrrr  -yyyttt      ~~~ #kkk``` }}}xxxzzzxxxqqqlllnnnpppttttttjjjgggbbbQQQVVV```gggmmmVVVQQQ[[[ZZZ\\\___]]]XXXWWWIIIDDDDDD@@@KKKXXXRRROOOJJJTTT___gggnnnhhhdddddd```mmmdddWWW@@@AAACCC777:::DDD@@@<<>>555555%%%,,,<<<999555111...444;;;KKKvvvwwwHHHIIIlllQQQ???333111---111<<<######((($$$,,,&&&'''***,,,.........++++++...333555;;;888===999===555555777555<<<111555???UUU777111000444666ddd;;;555666777<<>>777AAA===222:::EEEBBBjjjFFFGGGAAACCCIII<<<:::>>>,,,111333000<<<000333444>>>XXX___lllIIIvvv8PPP888777444555@@@CCC%%%&&&'''555///***,,,***+++---,,,///222000---000777777<<<999;;;;;;FFF999333111000///888111555111000,,,000666000;;;555555888PPPfffDDDBBB???PPPPPPMMMOOOPPPZZZZZZVVVYYYYYYTTTkkkZZZwwwaaaIIIGGGFFF^^^VVVWWW[[[mmmsssfffddd^^^iiihhhuuutttwwwxxxwwwxxxnnntttwwwppppppsssoooyyy - -vvv vvv}}} - -    -  -  -~~~uuuyyy {{{kkk$ -{{{iiiooo{{{tttmmmsssqqqtttvvvccceeeSSSPPPiiiooonnnrrrlll]]]dddbbbqqqsssaaa```SSSMMMQQQCCCOOOPPPRRRUUUUUUHHHXXX___ZZZ\\\nnnfffddd___fffeeeGGGKKKLLL???===HHH<<<:::666999FFFKKK@@@DDD;;;>>>;;;333555555222///...333:::777CCCVVV___VVVwwwKKKLLLyyyUUU===///333333666222###"""!!!'''///'''+++***,,,---222---222===555000444555888;;;666:::333;;;222444333000333---,,,...000666333999666222777000HHHYYY<<<===???JJJHHHEEEJJJLLLJJJTTTWWWSSS^^^eeeeeelllddd\\\{{{VVVSSSYYYcccYYYeeeiiirrrpppeeepppbbbmmmpppuuu{{{zzzvvvwwwvvvrrrqqqrrrtttjjjrrrwwwzzzyyy -www|||~~~zzz     -   |||   -{{{aaaxxx$ sss```nnntttvvvtttpppttthhhgggfff[[[[[[dddlllooossspppccc\\\aaaZZZaaa[[[]]]UUUMMMPPPPPPTTTmmmIIIPPP|||IIIOOOTTTbbbgggsssjjjllllll___QQQeeeJJJ===<<<>>>EEE===???===999???>>>@@@AAA>>>;;;777555000111333888<<<;;;555999@@@EEECCC EEE222SSS[[[VVVBBBOOO??????@@@:::%%%###'''((('''((()))+++%%%'''@@@TTTPPP>>>777===555333@@@444???AAA666777888999///000++++++///,,,------111111///333888OOOQQQ<<<===@@@HHHEEE@@@IIIJJJJJJLLLXXXTTTXXX\\\fffkkkpppmmmhhhbbbwwwrrriii```^^^gggjjjxxx~~~{{{vvvmmmrrr|||zzz~~~|||wwwrrrzzznnnhhh]]][[[]]]jjjmmmnnn||| ~~~}}} ~~~sss - {{{ -   !  {{{www{{{7 -xxxwwwrrrsssvvvtttqqqsssnnndddhhhaaa___kkkooolllkkkdddfff___dddccc\\\ZZZVVVKKKQQQWWW^^^{{{uuuIIIPPPPPPSSSSSShhhpppdddkkk{{{{{{jjjMMMJJJIIIBBBAAAIIICCCAAA@@@888===JJJ???===??????:::111555,,,777+++333RRR777222888BBB\\\ooo SSSWWWMMMOOOQQQEEEooorrrBBB<<<666"""!!!"""$$$'''(((---***...,,,HHHYYYEEE@@@>>>666777444333222888888444111444222///+++222,,,,,,,,,...---444666...333OOOJJJ999888999FFFBBB<<<@@@;;;BBBUUU]]]YYYVVV^^^ooovvvzzzllleeeggg}}}hhhpppmmmwwwrrrwww xxxsssssswww}}}xxxrrrfff```ZZZ______qqqnnnxxx -{{{{{{rrrwww{{{lll |||~~~!$##!# ~~~    }}}vvv{{{uuupppqqq~~~kkkeeennnfffaaaiiilllqqqeeejjjiiinnneeeeeeXXX]]]ZZZWWW\\\ZZZnnn~~~___bbbMMMRRRYYYbbboooiiiggg______XXXSSS:::MMMQQQKKKAAA@@@===DDDGGG777888:::===<<>>555<<>>444;;;CCC888===666555333222777222;;;555///...>>>GGGNNNaaa@@@222///888:::===GGGFFF===BBBEEE555...+++$$$&&&$$$&&&(((,,,***,,,222///666GGGQQQ>>>>>>666777;;;777777===XXX===...---+++,,,,,,***''',,,444000333333FFFAAA333222777AAA666333444:::===CCCRRR[[[^^^```hhhtttdddssseeellleee~~~zzzppp{{{sss?)-4kkk{{{tttzzzuuuoooqqqwwwssswww ~~~zzzsssuuuyyy  }}}nnnsss~~~ -    #$&*+*)'&"$##)! -vvv}}}  - {{{ooodddoootttpppgggaaadddbbbhhhrrrwwwnnnfffkkklllppptttrrr___]]]LLLUUUZZZYYY[[[dddyyyuuu___\\\FFFGGGHHHNNNKKKGGG[[[iiipppZZZ333IIIiiibbbPPPLLLEEEEEE>>><<<555999;;;888DDDAAA444888333666222444444777:::///999>>>DDD[[[HHH999+++///...555666999???444===]]]BBB(((!!! !!!(((%%%&&&'''JJJIII555IIIQQQttt???888222BBBAAA333000333333444,,,,,,,,,---***+++(((,,,,,,//////>>>444555555333<<<555333555999<<>>OOO]]]AAA999:::AAA???;;;888888111111555444///222+++111***)))&&&))),,,000555///,,,+++555666333:::<<<;;;AAA888>>>EEEPPPPPP\\\cccaaagggB;mmmbbbllljjj```kkksssttt{{{ppphhhmmmkkkmmmqqqpppuuuzzzuuuuuu*Bwwwzzz}}}ggghhhiii ~~~|||~~~}}}  ~~~yyy }}} -!$'*+*,-..,**''%!!    }}}zzz   ooopppooowwwnnniiinnnnnnooorrrwww~~~oooooofff~~~wwwxxxzzz^^^mmm^^^aaaSSSYYYVVVPPPRRRZZZddd\\\TTTLLL444;;;CCCIIIKKKQQQ]]]VVVIIINNNNNNFFFFFFLLLJJJBBBBBB<<<;;;======;;;999777:::777777777555;;;999666???LLLCCCMMMAAAHHHSSSDDD999LLL222444111222,,,.........(((+++222###***)))%%%111...444999444EEELLL<<<@@@[[[@@@BBB\\\BBBCCC...222333888+++333,,,...)))---///++++++000999...------222???666333444777===<<<999MMMCCCPPPQQQ___aaappp~~~ ^^^YYYfff\\\aaaaaalllrrr}}}jjjooo{{{}}}zzzxxxqqqiiilll -8}}}uuuyyy~~~lllfff {{{kkkwwwyyy~~~ ~~~~~~  -!$%)+,0//011//.+(# "  vvv - ssspppiiiiiiwwwqqqwwwwwwppprrrqqquuugggwww{{{zzzqqqooo[[[```UUURRRPPP___\\\^^^VVVLLLBBB333444;;;DDDBBBCCCPPP[[[UUUUUUbbbOOOCCCEEEGGGIII<<<444999888666:::777;;;;;;;;;999888AAA777;;;JJJHHHBBB>>>EEEBBBFFFKKKUUU^^^000---///***---222000,,,...+++///+++==="""...333***+++(((333;;;888444000;;;:::BBBGGGQQQ;;;;;;;;;BBB222111111+++000+++,,,***,,,&&&)))111999......,,,***000222444///...000444222>>>??????EEETTT\\\WWWgggmmmrrrZZZOOOWWWLLLaaaeeelllnnnoooqqqlllppppppkkkmmmrrrwww```IIIaaa|||vvvvvvvvv}}} zzznnnggg}}} mmmnnn|||{{{fffsss|||~~~   $'(+--0122344221.,($! xxxxxx||| }}}vvvlllfffwwwwwwpppuuuyyyxxxwwwooo {{{tttlllsssfff^^^bbbZZZjjjtttnnnTTTNNN111555666000444333:::???cccOOOYYYOOOQQQ___III999;;;888///;;;@@@===???;;;666<<<999BBB???<<>>>>>???GGGQQQIIISSS```^^^ZZZGGGQQQllldddlllooo|||wwwzzzllliiidddeeekkk~~~ppptttsss___SSSNNNccceeesssttt |||wwwvvv}}} wwwsssjjjxxxuuuwwwwwwxxxmmmwwwlllnnn{{{}}}www}}}~~~ - $%').,-13576765541.)&"zzztttgggxxxzzzuuutttrrrlllpppyyyzzztttmmmnnnooojjjtttvvvoookkkssspppjjjccc]]]ZZZ]]]fffUUUIIIOOOFFF===:::999333888AAAIIIOOOUUUVVVRRRSSSZZZSSS;;;444444<<<>>>@@@@@@BBBFFF@@@===>>>GGGAAA???888===???>>>---111888DDDbbb<<<;;;???666777...111333444444---///'''%%%###+++)))''';;;%%%777666333000***...---***...111999CCC999444DDD@@@888SSS;;;333[[[...@@@111111222,,,+++555+++---,,,---000///(((...444000111111>>>QQQCCCEEESSSKKKFFFPPP___\\\^^^aaa}}}ZZZrrr mmmrrr{{{zzzsssllleeeaaadddooooooppphhh]]]rrrtttnnn___eee|||yyy|||rrryyyzzz~~~zzzvvvqqqnnn~~~oooppp||||||vvvppphhhnnn|||yyyuuu}}}  "#&)*-//257899887654/,)'"zzz~~~rrr}}}{{{yyytttkkk```rrrxxx}}}{{{uuuuuupppqqqhhhiiihhhkkkrrrsssjjjiiisssiii```XXX]]]\\\___XXXJJJGGGEEEJJJAAAAAAEEEGGGTTTIIILLLUUUWWWWWWUUURRRIII666777IIICCCAAA@@@CCC888999DDD===;;;888???@@@>>>@@@999222000666>>>EEEJJJEEE777<<>>---444333***((()))---$$$BBB)))***(((!!!&&&NNN444***''',,,444555777///222000===FFF666777CCCZZZ===999???===JJJ:::GGG444///555&&&&&&***))),,,===...+++,,,000+++///===888<<>=;89750-*($ -  vvv|||vvveeevvviiihhhsssjjjvvvfffgggkkklllnnnmmmzzzsssccceee[[[UUUTTTWWWZZZUUUHHHEEEBBBFFFGGGNNNOOOLLLRRRZZZddd\\\YYYEEE...:::IIIJJJHHHHHHLLLIIIMMMCCC???DDDKKK???@@@JJJKKKNNN???ZZZ===LLLDDDMMM@@@iii[[[666===555999---000888---...+++'''***)))///%%%%%%>>>"""///MMM,,,&&&(((111555222444222>>>666HHHJJJ>>>GGG^^^DDD===HHH???UUUAAA---***444666''''''---+++)))+++***'''...+++222222AAABBBDDD===NNNJJJJJJKKKMMMXXX``````aaabbb^^^LLL```XXX\\\wwwrrrnnnjjjiiigggfff^^^\\\ddd```]]]mmmqqqkkkqqq%!~~~nnnrrrmmmqqqtttrrrtttpppwwwqqqiiiiiiccc```kkkpppvvvxxx|||}}}tttiiikkkdddyyyzzz -!$%&,/016:==@?@?AA@=;9453.,&% - uuu}}}{{{vvv{{{zzziiiwwweeeaaallllllzzzwwwvvvvvvjjjiiipppfffiiiyyywwwzzztttaaaaaa^^^VVVSSSVVVRRRKKKEEEAAACCCJJJOOOSSS```LLLKKKPPPWWWffflllOOO>>>???RRRFFFFFFLLLGGGHHHGGG<<<:::???FFFCCCjjjKKKGGGSSSCCCGGGJJJ???@@@GGGCCC\\\GGG888444:::777666666>>>???444---''''''***%%%***,,,)))###+++333III,,,...444000///333222>>>888DDDHHHSSS===:::???999AAA???>>>555888111111+++'''+++***)))++++++)))---...///222;;;999DDDEEEHHHFFFNNNJJJJJJQQQUUUXXXddd```XXXOOOTTTVVVooogggiiiuuujjjccc___XXX]]]SSSVVVbbbZZZ___bbbkkklllfff ~~~vvvlllkkkoooqqqssssssqqqqqqqqqooojjj[[[ggghhhqqqxxxvvv}}}zzztttsssuuuvvvxxxzzz ""$)//33:>@BDEDDDDCCB?<9741-(&   -}}}xxx -iii{{{{{{vvv}}}yyyyyy{{{zzzvvv|||vvvkkkdddiiiiiippp|||vvvkkkcccVVVSSSTTTRRRRRRCCCOOOAAAHHHBBBQQQHHHMMMWWWVVVUUUNNNZZZyyyYYYNNNFFFAAAKKKFFFCCCJJJHHHLLL:::999;;;BBB>>>QQQnnnOOOpppMMMJJJHHHAAABBB>>>UUUAAA\\\@@@<<<555///444222000555...(((''')))---...111%%%+++ '''---$$$???BBB777+++---<<<666333///777BBBAAAIIIKKK???CCCVVVSSS:::777444111//////111......((()))...---@@@666333444666FFFCCCEEEHHHKKKNNNOOOQQQQQQPPPQQQPPPUUUPPPMMMPPPCCCHHHffftttmmmkkknnndddoooZZZSSS\\\kkk]]]^^^dddjjj[[[ccc```ffflllmmmmmmyyyvvvnnn~~~pppooommm___\\\hhhjjjwww{{{rrr|||xxxuuu|||~~~~~~yyyooovvv -""'(,237>>BBBDDDAAA999777222---EEE///,,,)))((('''&&&%%%&&&***(((###&&&%%%&&&$$$&&&999555...///...///777444111:::@@@@@@???FFFDDD```EEE999333EEE000222---)))+++...333222000222:::;;;888===AAARRRJJJLLLHHHMMMNNNRRRQQQUUU```WWWRRRJJJYYYXXXJJJUUUOOOttttttwww|||aaaccc^^^VVV]]]hhhbbb^^^```______^^^kkkjjjlllwwwmmmiiinnnkkkvvvtttmmm]]]ZZZ]]]dddeeemmmqqq xxx~~~~~~{{{|||}}}|||tttxxx !%(-/27=BDGHJLMMMMLIHGDB@=851-& |||}}}xxxvvv~~~}}}yyy{{{zzz  {{{xxxsssyyy~~~tttsssqqqqqqyyyxxxqqqnnnddd\\\lllCCC888999999AAADDDBBBEEEWWWIIIGGGIIIKKKIIIJJJJJJNNNQQQFFF000:::HHHWWWWWWOOOIIICCC;;;IIIDDDYYYSSSHHHSSSXXXMMMDDDDDD@@@???CCCDDDGGGFFF555JJJBBB777333666******%%%''''''%%%(((***)))&&&&&&'''(((((("""))),,,DDD>>>***---555888NNN555:::;;;:::<<<@@@IIIqqqbbb===CCC888111...+++---+++111111333555555???>>>EEEQQQDDDGGGFFFKKKOOOOOOSSSQQQTTTcccXXX\\\WWWUUU]]] ___nnnwwwoookkkkkkeeeiii|||ddddddfffpppjjjiiieeefffiiillliiihhhgggccciiiiiirrrqqqllliiidddeee```oooqqqpppuuu~~~vvvyyyyyyrrrzzzuuuwwwyyy|||{{{tttqqqyyy"',015>BFHKMNQQQOPOLJIFDA?953+'#%  ~~~|||zzz}}}~~~|||xxxwww# zzzwwwsss~~~zzzqqqrrruuuqqqkkkbbbXXXLLLCCCKKK@@@888999>>>AAAMMMOOOPPPHHHBBBHHHKKKMMMJJJGGGFFF@@@''';;;LLLYYYPPPLLLNNNFFFKKKIIITTTeeeMMMFFFPPPBBBEEEFFFBBB>>>LLLEEEHHHUUU777444:::777;;;BBB000...---+++***)))%%%&&&&&&%%%$$$###***(((###&&&)))000555FFF222000AAAHHHUUU;;;FFFGGG???@@@AAA]]]999;;;:::EEE222222...***+++***111444<<<888@@@FFFNNNNNNHHHAAANNNDDDHHHHHHJJJNNNSSSTTTYYYWWWYYYZZZUUUXXXuuuvvv{{{llluuugggaaa```cccdddjjjdddmmm```mmmsssmmmoooeeebbbhhhhhhrrrnnnnnnmmmdddeeeeeesssppppppmmmtttooorrr}}}vvvuuummmtttzzz{{{{{{{{{~~~yyynnnuuuxxx #&+1215CFILMQRTTTUTSPMJGFC?;63.'%! yyy xxx~~~xxxtttyyy -zzzzzz{{{oooxxxxxxppppppwwwtttvvvuuu]]]RRRMMMNNNQQQLLLAAABBBFFFDDDOOOGGGIIIAAAFFFKKKQQQJJJIIILLL???222999DDDGGGKKKKKKSSSJJJDDDIIIEEEPPPtttHHHBBBMMMSSSIII;;;>>>:::EEEFFFQQQLLL666:::JJJ444000...,,,///...555,,,%%%###+++'''""""""***+++%%%###"""&&&666---666NNN999<<>>OOOAAADDD;;;EEE777<<<888---++++++,,,444555:::YYYWWWGGG???FFFAAADDDGGGNNNpppRRRHHHMMMOOOOOOYYY[[[TTT]]]```kkkmmmrrr|||yyyeeehhhwwwbbb^^^lllmmmoooiiipppiii|||gggiiinnnlllssshhhrrr}}}oooqqqnnnpppddd___qqqqqqpppnnngggvvv}}}|||}}}{{{qqqxxx{{{xxxvvv "*,/46:?GIMPQUVXYYXVUSRNKID@<74--+  xxx -yyyzzzrrruuuzzz , uuulllmmmppprrrzzz{{{llldddYYYVVVMMMQQQKKKLLLCCC???BBBEEEFFFAAAAAAHHHLLLLLLMMMKKKSSSPPPHHH:::NNNHHHVVVQQQUUUKKKDDDCCCFFFCCCMMMKKKGGG???HHHQQQBBB???AAA@@@<<>>AAABBBBBBHHHMMMNNNTTTNNNIIIHHHPPP[[[dddeeeaaa\\\```ooolllsssppppppggghhhrrrttt[[[[[[hhh```fffeeejjj|||xxxuuujjjlllhhhkkkooonnnkkkoooxxxuuuooossstttgggtttiiimmmjjjxxx zzzvvvuuuuuuyyy $*.269>DHMPSUWY[\\\ZYWTRNJFC?950.-! www -xxxsss{{{vvvuuunnnpppnnnoooqqqsss|||xxxqqqkkkdddZZZSSSNNNOOOLLLJJJJJJ===AAAGGGCCCHHHSSSKKKOOOPPPNNNQQQRRR[[[MMMHHHQQQUUUXXXhhhTTTKKK???CCC@@@>>>777666999<<>>DDDIIIEEEfffNNNEEE===666333000KKK,,,+++444,,,,,,***)))000lll===;;;;;;BBBEEE???DDDQQQ\\\RRRUUUZZZWWWgggmmmuuunnn^^^qqqkkkyyy{{{uuuccc___^^^\\\[[[\\\``````]]]^^^```]]]^^^ppp{{{eeegggeeekkkiiippprrrqqqkkkqqqppprrriiifffiiirrrnnnpppssswww|||{{{pppxxx !%.036=CJNRVY\_abddc`][YUQOKFA;63.(# zzz{{{ ~~~wwwrrrpppsssxxx -yyytttssspppppp pppxxxlllhhh___YYYRRRQQQQQQJJJEEE???HHHAAAAAA@@@BBBFFFLLLHHHLLLSSSRRRNNNEEECCCRRRUUU[[[cccUUUMMMCCCHHHIIIAAAAAACCC666222???@@@LLLCCCQQQ]]]eeeNNN>>>EEE<<<999:::666222---333...,,,***'''"""$$$&&&$$$!!!!!!(((***+++444...333???BBB>>>===MMMaaaiiiFFFCCCJJJbbb===444///999000---+++''',,,(((+++...///------???PPP:::DDDBBBPPPOOONNNQQQNNN______hhhvvv{{{ vvvxxxlllkkk\\\]]]UUUTTTRRRXXXZZZZZZ^^^ZZZ\\\]]]```qqqjjjfffcccmmmiiidddcccllluuu}}}uuubbbgggpppjjjpppppp{{{xxxxxxdddjjjYYYeeexxx|||   -!'-028AFLOTY]`cefggfcb`[XSQLGB<83.*$  xxxzzzvvvvvvssstttuuu }}}yyyzzzoooqqqnnnuuu!rrroooeeeccc\\\XXXSSSPPPMMMLLLOOOUUUJJJ>>>AAAFFFBBBFFFGGGIIIUUUQQQYYYOOOCCC777LLLTTTbbbZZZSSSEEEFFFIIIJJJ===???666999999999===<<>>999===@@@???AAADDDAAAEEEMMMDDDWWWOOOXXXpppNNN;;;333@@@222'''%%%///222111///)))444((('''######(((%%%###------,,,...:::999JJJNNNlllZZZUUUIIIOOOBBBEEEFFF???111444------,,,(((%%%$$$+++***111111000777666777UUUGGGFFFFFFRRRMMMNNNZZZiii\\\dddaaa}}}yyyxxxnnnvvv|||xxxnnnggg______\\\TTTNNN[[[[[[aaa```uuu cccgggbbbbbbfffeeedddggg^^^hhhsss||| rrrsssvvvsssrrriiiooovvvzzzzzzxxx}}}{{{ }}}nnntttttt}}} ',/39>CHOTY]aeilnnnkjfa_ZVQLHC=82.*# rrrzzzsss|||zzzjjjqqqqqqsssvvv~~~{{{iiijjjnnnqqq}}}nnnmmmhhhddd```___aaacccSSSTTTQQQIIIHHHDDDIIIPPPDDDDDDEEE===DDDHHHKKKMMMPPP???;;;TTTSSSZZZTTTSSSMMMIIIDDDCCC>>>@@@??????AAADDDBBBAAADDDUUU888KKKHHHUUUAzzzCCC444888000,,,,,,,,,000AAA888+++'''$$$&&&!!!777$$$(((,,,***222666EEEYYYgggvvvDDDHHHNNN???AAA???LLLGGG555---...111***%%%###+++,,,///000------...>>>???{{{GGGBBBJJJKKKNNNOOOVVV___WWWggg^^^ppp~~~ssshhhVVVbbbtttyyyvvvhhhaaa\\\\\\\\\TTTYYY\\\eeeiiihhhiiihhhwww[[[ooogggxxxgggeeefffkkkyyyppppppssscccmmmuuusssttt{{{tttrrrrrryyy~~~qqq - $),-5:AFJPTX]cglqusrnkfc_ZVRLHD>84.)"  rrrtttrrruuusssyyyzzz"|||vvvgggiiippp~~~mmmllldddfff___hhhlll[[[^^^UUUMMMMMMMMMPPPPPPKKK@@@999666000@@@KKKLLLKKKGGGGGGCCCLLLNNNSSSPPPMMMUUUSSSEEEBBB??????AAAMMMLLLTTTPPPKKKNNNGGGGGG888NNNGGGhhhttt??????+++444///555(((***444,,,&&&"""%%%&&&###!!!$$$888EEE---???000333888???cccxxxhhhgggPPP:::;;;LLLEEE===777333...+++)))'''%%%'''(((<<<+++***555333666555>>>DDDIIICCCGGGWWWMMMYYYPPPUUUXXXxxxJJJ]]]|||YYYNNNXXXWWWhhhwwwfffbbb```___]]]yyycccddd]]]fffeeewwwjjjmmmkkkeeeeeecccfffoookkkdddfff{{{ \\\fffvvvsssuuupppooosss|||qqqrrrzzzrrrvvv|||sssnnn||| -%*.18=BHKQUY]cglsz{vqlhc_[WRLHB?83-)# |||ssstttxxx{{{ssstttzzz~~~ -zzznnnjjjllloookkkiiiaaakkkuuu^^^]]]\\\MMMCCCFFF[[[EEEBBB@@@888000999AAAHHHMMMNNNEEERRR>>>GGGKKKRRRTTTPPP[[[MMM[[[EEE:::;;;;;;HHHeeeWWWMMMaaaaaaGGG???>>>CCCJJJLLLCCC999333......777...KKK444,,,((("""###+++666"""&&&###***444///???888222EEEDDDaaaWWWJJJHHHGGG444:::JJJDDDBBB999:::///)))@@@...,,,&&&++++++,,,)))666555FFF444;;;:::CCC>>>LLLMMMMMMIIIMMMhhh|||NNNbbbuuu}}}QQQDDDlllbbbbbbfffddddddaaa]]]fffwwwbbb```ddd```oooaaabbbqqqlll```mmmllljjjhhhiiihhheeeFFFdddeeeqqqsssnnnkkkttttttsssuuuwww~~~mmmqqq}}} '+-29>CHMRVZ^chkqx{wqlhc_[WQLGB=82,*$ ~~~vvvrrrrrrxxxyyyuuu~~~zzzwwwrrruuupppuuu -vvvmmmooopppfff```gggdddVVVSSSUUUFFFCCCAAAIII======>>>===:::>>>FFFJJJLLLLLLIII<<>>333......***'''%%%&&&(((&&&!!!!!! '''!!!***999<<>DIMRW[^bgkouwuojfa^YUPKG@;70+($ - ~~~~~~{{{zzzssssss~~~{{{uuutttwwwvvv/vvvyyylll|||kkkkkk^^^^^^\\\]]]]]]LLLRRRMMMGGGEEEAAA???;;;LLLGGGEEE@@@CCCEEEEEEFFF777:::PPPYYY___UUUHHHLLLMMMJJJGGGDDDAAALLLZZZOOOIIILLLMMMsssKKKAAATTTGGG888gggFFF>>>///222<<<+++,,,FFF,,,)))******!!!###!!!%%% """%%%&&&222gggXXXJJJPPPPPPPPPWWW;;;888999888999<<<777BBB555555mmmKKK)))&&&)))(((>>>222;;;>>>===:::BBB>>>TTTXXXSSSOOOEEERRRKKKXXXaaadddiii{{{]]]OOOIIIPPP]]]hhhgggfffwwwcccjjjffflllttthhhVVV^^^ccc\\\[[[gggccc```eeeiiikkkqqqpppvvvwwwooo|||zzztttlllhhhZZZbbbmmmnnnlllqqqtttyyyxxxsss___hhhqqqzzzxxxzzz ~~~ zzz "$*/3:?EHMRWZ^adhjoqojgd`\WTNJD?:6/)&"zzzwwwvvvsssvvv}}}}}}uuu{{{ -uuuuuuqqqyyy|||sssdddaaaYYYXXXUUUSSSGGGEEEEEEFFFOOO@@@<<<999@@@EEETTTPPPBBB@@@FFFGGG777LLLIIIVVVkkkuuuNNNJJJJJJNNNJJJMMMDDD>>>HHHRRRLLLPPPPPPPPPOOOOOO[[[GGGHHHHHHNNN555222+++,,,---&&&)))"""###&&&)))%%% !!!""" !!!!!!888///nnnSSStttDDD^^^III<<<;;;888222444444,,,777???555999EEE***---(((+++///;;;TTTKKKBBB===MMMHHH;;;IIIjjjUUUEEEOOOYYY]]]nnndddjjjwwwzzz___XXXYYYVVVhhhgggnnniiiuuuiiiZZZ___jjj\\\ZZZNNNGGGTTTaaapppggg___iiinnnsssnnnvvvyyyvvvnnnppphhhUUUhhhqqqqqqnnnnnnuuuyyy|||~~~fff```mmmnnn}}}zzz $+.38@DGNRUY]`cehkljfdc^[VQMHC>94/+% ~~~uuunnnuuu}}}{{{uuuqqqzzz |||@{{{qqqssskkknnnooohhh^^^XXX^^^YYYUUUVVVKKKFFFFFFIIIHHHAAA???;;;@@@???HHHAAABBBKKKPPPeeeGGGNNNUUUSSS___[[[QQQKKKVVVOOOCCCUUUFFFHHHEEEGGGHHHMMMNNNTTT[[[kkkYYYVVVSSSFFFJJJ...000(((+++///&&&"""!!!###$$$$$$(((###"""!!!###!!!---222666TTT~~~OOOAAA???888>>>>>>666111000888999---000;;;---555---)))+++///000:::MMM===EEEwww|||[[[RRRRRRDDDMMMMMM```___dddbbb___nnn,DaaabbbiiidddrrrhhhRRRTTT___rrrzzzqqqzzz]]]RRRYYYUUUWWWjjjiiiWWWeeellltttoooooo xxx{{{qqqzzzccc^^^mmmrrrttttttvvvtttuuuzzzqqqbbblllzzzzzz -"(-48>AGMRUX[^acdggfca_[XSOKGA;72/)#{{{wwwlllrrrsssuuuqqqwww -~~~yyy{{{ooonnnnnneee___\\\___RRRVVVRRRSSSGGGSSSCCCHHH:::<<<@@@@@@:::@@@EEESSSUUUPPPHHHTTTQQQVVV[[[___^^^]]]KKKIIIEEEBBBIIIFFFLLL???CCCLLLWWWVVVpppyyyZZZ]]]GGGFFF\\\TTT+++)))'''+++&&&%%%&&&$$$ ######,,,((( """''''''<<<>>>000:::aaa===333:::CCC<<<:::777:::000333333FFF111555444///000111)))===]]]CCC===HHHZZZ!JJJ???AAANNNFFFFFFWWW```^^^dddeee{{{,"~~~iiiiiidddjjjiiimmm}}}tttyyyiiijjjfffYYYkkkccc[[[YYYVVVYYYffffffZZZbbb]]]eee|||mmmttt0yyyssspppsssnnnlllzzzyyyzzz|||~~~uuukkkwwwtttmmmzzz%,38>>444<<<222333111:::444333444DDD333:::777222777333555AAA222111444)))999===111999aaaHHHFFFDDDIIITTTOOOKKKRRRPPP```bbbkkkiiiwwwzzzyyyhhhjjj```___[[[aaaqqquuunnnmmmmmmrrrTTTSSSSSSWWWUUUUUUXXXUUU\\\^^^dddoooYYY```[[[jjjtttsssuuuoooyyyxxxrrrnnnlllrrruuuxxx|||wwwzzznnnpppvvvnnnZZZyyy   "#+26>>---,,,333666777AAAEEE???888@@@BBBOOOPPPMMMTTTPPPWWWSSSaaavvvfff^^^ooo~~~ooonnnaaaUUU^^^]]]```fffeee{{{oooiiizzzUUU^^^UUUIIIFFFPPPRRRZZZaaa[[[YYYZZZVVVccckkkjjj}}}{{{qqqsssUUUbbbqqqooobbbrrr}}}|||qqqgggvvvfffzzz~~~|||ttt  - !#(24:?DGKOQTWXY[[\YVVUROKGC?:5/-&#  |||!uuurrr" -~~~sssjjjdddeeennn~~~{{{ mmmccceeeggg[[[SSSXXX[[[SSSGGGNNNCCC999>>>555===@@@???666DDDMMMPPPNNNPPPKKKddd\\\VVVZZZYYYZZZ___NNNLLLMMMCCC;;;BBBJJJ???EEEGGGJJJXXX]]]]]]MMMXXX;;;;;;444KKK,,,))))))$$$%%%((($$$&&&((($$$""")))$$$%%%222$$$!!!"""@@@222444888CCC333000888111---000...'''///888BBB:::222888888:::333---...***,,,///777333555:::KKKGGGJJJZZZEEEEEE^^^kkkWWWTTT^^^eeeaaajjjlllbbb___]]][[[aaa___www\\\dddrrrrrryyyvvvbbbgggsssNNNQQQRRR]]]VVVYYYggg^^^iiijjjgggiiilll2qqqlllYYY^^^pppwwwiiisssqqqoooxxx~~~aaa~~~uuu - ""%/17>BGIMORTVVVWWVRTROMHDB=92,($" - sssyyysssvvv,~~~vvvjjjssskkkzzz)pppmmmooocccUUUPPP```cccPPPIIIBBBWWW@@@===???AAA555333999DDDOOOPPPSSSYYYYYYNNN\\\QQQTTTYYYYYYQQQMMMIIIDDDBBBDDDBBB===CCCMMMLLLAAAOOO]]]lllQQQCCC===:::666999,,,)))111''''''+++111)))))),,,(((&&&!!!(((""""""$$$"""III___999AAA999333......111///......+++111555...222222000///111***000///...888666:::...555<<97/)%#  qqqpppuuuxxxzzzyyy -~~~zzzqqqnnnnnnmmmuuuooolllzzz}}}tttvvvnnndddaaa[[[TTTVVVPPPJJJBBB@@@@@@GGG@@@???777===UUUHHH@@@PPPYYY[[[ZZZXXXeee\\\VVVPPP\\\]]]WWWYYYDDD>>>@@@@@@???@@@???NNNFFFAAABBBOOOTTTWWWEEEOOO===777(((///444333///,,,)))&&&&&&&&&)))&&&%%%777!!!!!! ;;;FFFEEEBBB000111...---111///;;;555111000333...000666111''''''333...:::111666999___AAAAAA>>>DDDUUUDDDCCCMMMWWWOOOJJJUUUXXXeeerrrjjj^^^hhhfffggg___[[[llleeebbboooeeeiiirrrJJJXXX]]]NNNVVVeeecccYYYVVVXXXYYY\\\___eeeaaaaaasssxxxggg]]]WWW___kkk```fff}}}jjjiiirrrkkkqqqiiijjjoooxxxqqqrrr~~~  !(-14;?CEIJLNPQPNOPMIIGDA>;62-'$! -  vvvpppppppppqqquuu ~~~xxx|||lllyyyrrroooyyyyyy{{{tttooogggzzz]]]bbbqqqmmmRRRNNNCCCNNNVVVGGG@@@>>><<>>:::???GGGCCCEEEGGG@@@CCCLLLSSShhhMMMEEE555PPP<<<'''...111***...,,,%%%%%%(((###$$$%%%%%% ###111;;;FFFGGG888666555555@@@444666999---+++///...000---'''$$$&&&///333666>>>000999IIIAAA999===???AAAEEEIIIHHHQQQQQQLLLMMMZZZ[[[bbb\\\WWW^^^___eeeggg^^^gggiiikkk|||iiinnnccc888999HHHHHHVVVXXX\\\\\\[[[gggVVVYYYhhhdddeeeiiifffqqqbbb```SSS^^^aaahhhdddyyyeeeoooyyyxxxrrrjjjlllwwwooo___yyy~~~  !&,118=ACEGIKLMMLKKIEECA>:72,+(#!  sssiiikkkeeeuuu}}} ~~~xxx - lllrrruuuqqqsss{{{uuummmhhh^^^\\\XXXXXX\\\LLL@@@>>>FFFDDDDDDGGG>>>HHHEEEPPP[[[VVV\\\[[[\\\^^^ccciii}}}eeebbb]]]WWWJJJWWWaaaEEE<<<>>>???BBBAAADDDRRR===888...000NNN@@@@@@000///---)))'''***(((&&&''')))%%%$$$%%%%%%### !!!***$$$ :::@@@LLL777111555111222555555111333666000333BBB;;;%%%(((&&&)))...000666888WWW999888888555;;;:::CCCIIISSSQQQVVVOOOXXXVVV```^^^```qqqpppiii]]]eeehhhlllwwwwwwppp```QQQVVVIIIRRRWWWcccZZZXXXYYYbbb^^^]]]ZZZNNNNNNTTTccckkkhhhUUU[[[[[[```aaajjjtttuuu~~~xxxnnnhhh}}}uuuhhh~~~  - -  &,2358>@DEFHIJJHHGFCB?>;61-.*& -~~~nnngggbbbiiiuuu|||  uuuuuuzzztttssszzzooorrr}}}vvvoookkkaaaWWWVVV___QQQLLLZZZFFF>>>>>>;;;>>>AAAGGGMMMOOOPPPQQQXXXZZZXXX^^^```ZZZiiiccc]]]QQQ===;;;AAAMMMQQQNNNDDDGGGCCC<<<@@@@@@:::@@@RRR111---666444333111,,,---000+++...))))))+++'''''' $$$'''..."""!!!###"""rrrLLLOOO666888PPP000...111444FFF666555222***///+++,,,///(((222111444111777 BBB666666888:::BBBDDDMMMIIITTTUUUWWW\\\ccc^^^eeebbb___dddkkkXXX___``````nnngggnnn[[[^^^GGGGGGXXXyyymmmXXX```iii```[[[___```aaabbbXXX```hhheeecccmmm___cccaaalllwwwzzz}}} ~~~~~~xxxjjjuuu     %*/147:>ACDFFGFEDDB@>;:83.+(%" -~~~sssmmmrrrrrrjjjttt|||{{{}}}|||uuu}}}}}}xxxxxxpppxxxmmmfffggg___ZZZ___]]]TTTZZZJJJAAA???<<>>@@@@@@CCC>>>>>>777888333,,,,,,...+++,,,)))&&&---,,,((("""$$$""""""$$$&&&%%%%%%###!!! tttWWW@@@666FFF>>>///***)))JJJ888000...???)))''''''///222(((---111333...<<>>;;;444888888;;;AAACCCCCCEEE]]]ZZZ[[[VVVXXXXXXdddeee^^^```[[[```gggZZZhhhgggpppwwwsss]]]jjjQQQHHHSSS[[[XXXQQQWWWccc]]]ZZZ\\\ggg___ddd```sssaaaccc\\\]]]bbb^^^[[[___tttvvvpppttt}}}{{{tttbbbzzzvvv  -  #)+/368=:851/+*'%  ~~~xxxxxxqqqnnnjjjvvvyyyyyyqqqlllrrr -uuu{{{zzzuuuyyyxxxxxxqqqjjjfffccccccaaasss\\\QQQPPPIIIGGGCCCBBBGGGKKKQQQLLLYYYWWW\\\bbbaaafffhhhTTTSSSPPPTTTRRRPPPOOOKKKOOOMMMRRRGGGLLLAAA;;;===JJJPPPDDD888888:::...---,,,...++++++)))$$$%%%%%%%%%)))&&&!!!""" """!!!(((---!!!###""" ???BBB666555///---++++++---BBB333222---333...(((444---(((---,,,///999///...;;;AAAAAA:::333666;;;===>>>AAADDDJJJWWWRRRYYYYYY[[[ccckkklllXXXXXXTTTRRRZZZ___ccckkkgggkkkeeeZZZRRRHHHFFFRRR[[[LLLTTTbbbZZZaaalll\\\WWWXXXXXX[[[ZZZYYY[[[\\\NNNWWWbbb\\\___llltttqqqttt lllccc|||rrr - -    !!'+-0458=>??????>=:7610-,*$"! - |||yyyjjjiiipppvvvuuuyyyrrrxxx   xxxzzz}}}}}}}}}{{{qqqnnnnnncccsss|||lll___VVVTTTHHHIII???AAA<<>>999,,,(((&&&$$$>>>---111...999333>>>:::999444<<<;;;AAAEEEYYYMMMSSSddd[[[SSSaaaZZZ___[[[RRRRRRNNNQQQ\\\]]]bbbeee___[[[^^^[[[```\\\qqqbbbOOOWWWXXXYYY^^^[[[ZZZ]]]ggg```XXXRRRTTTYYY~~~[[[ZZZ\\\\\\cccllltttzzz - uuu  -}}} - |||""'+-257::<=<=<;98632/-+'&!! www|||{{{pppkkkuuuxxxwwwuuu~~~ ! ~~~wwwwwwsss|||uuurrrmmmlllooopppcccPPPNNNPPPRRRFFFCCCCCCJJJFFFOOOLLL[[[OOOrrr\\\[[[XXXUUUWWW\\\VVVSSSTTTPPPRRRPPPPPPOOOZZZPPPHHHHHHHHHHHHVVVBBB:::666555222000222KKK+++...///***&&&///777((((((%%%###$$$&&&"""""" !!! ### '''"""### +++@@@FFF555......---///((((((###///...444000>>>999888((((((...+++%%%$$$)))777222333000888CCC999EEECCC???EEEEEE\\\RRRnnnooocccVVVBBBGGGSSSNNNPPPccc]]]WWWYYYccchhhlllcccfff```YYYaaa\\\WWW```]]]YYYVVV```bbb]]]fffVVVZZZRRRkkkbbbaaa]]]]]]```XXXVVViiipppvvv~~~||||||{{{zzz |||{{{ !"%*+155889;;;965531.-,)$#  yyyyyyyyy}}}vvvuuuxxxwwwzzz}}}xxxyyyyyyvvvyyy~~~nnnmmmvvvllldddYYY]]]jjjSSSZZZNNNGGGJJJKKKOOORRRTTT[[[XXX[[[ZZZ[[[YYYYYYYYYYYYMMMFFFQQQRRRiiiSSSRRRRRRUUUQQQMMMVVVSSSOOONNNDDD;;;<<<999555...---,,,---'''(((+++)))---...%%%!!!$$$%%%###'''!!!+++"""$$$"""///&&&&&&###&&&...222444...333,,,///222***)))%%%***///000000///000000///---<<<***&&&&&&&&&'''111444111333???999VVV<<<<<({{{qqq}}}uuuwww{{{|||  - -xxx #$(-,/143454421-+''$"" }}}qqq|||}}}xxx -www}}}}}}xxxzzz{{{yyyuuuwwwxxx}}}}}}sssnnnttttttyyyxxx```SSSPPPXXXYYYVVVJJJGGG[[[TTTUUU[[[{{{[[[YYY___ZZZZZZXXXRRROOOWWWQQQXXXVVV]]]ZZZVVVVVVTTTNNNPPPHHHHHHMMMOOOKKK???===FFF222///@@@444@@@***&&&)))***%%%###(((###"""$$$"""%%%%%%!!!$$$$$$###"""$$$$$$&&&FFF999...###,,,111000111,,,999---444111///---000111:::BBB===******===NNN)))&&&'''+++,,,111444;;;666444888???HHHKKKVVV^^^]]]cccxxxXXX```rrriiigggeee^^^[[[gggjjj___XXXlllOOOZZZNNNaaa@@@PPPDDDJJJJJJPPPQQQRRR\\\aaa______gggaaaSSS```cccSSS[[[\\\YYYiiilllvvvvvv~~~.GUTLC' {{{tttrrr~~~ uuu{{{ ##$'*,////0/../,+-)# vvv}}}zzzzzz {{{wwwvvvuuuooowwwvvv}}}wwwtttvvv xxxsssjjjlllSSSWWWTTT@@@LLLDDDKKKHHHQQQvvvXXXXXXaaa```]]]YYYccc```TTTSSS[[[VVVXXXSSSJJJKKK^^^XXXRRRYYYkkkIIILLLFFFFFFEEEDDD???[[[<<<<<<;;;888---***(((+++%%%&&&&&&000&&&$$$((( !!!"""&&&$$$'''%%% """""""""$$$'''222$$$""" 999000111000333...===777///===|||:::,,,888===...)))***333&&&...!!!,,,///...555555999222===KKK@@@dddPPPUUU]]] vvvgggsssuuuggggggooouuuqqq}}}rrr\\\[[[XXXTTTsssddd```VVVKKKNNNUUULLL???>>>BBBHHHSSSUUUaaakkk]]]^^^gggiii___XXXgggeee^^^[[[```iiiggguuuqqquuu}}}1Ksz]G3 xxxzzzvvvvvv|||  wwwxxx "$$%(*+--,,+'&%%#$!! zzzxxxzzz }}}~~~zzzzzztttrrrsssyyy{{{~~~uuudddhhhbbbNNNKKKJJJ@@@AAA>>>KKKQQQVVViiiXXXXXXjjjdddccc\\\}}}]]]QQQZZZ___YYYTTTZZZOOO^^^lllbbb```[[[SSSGGGYYYGGGHHHDDDQQQKKKTTTHHHDDD444666+++%%%$$$''''''(((///&&&%%%$$$"""000&&&999444%%%!!!&&&''''''000)))+++%%%&&&%%%,,,???111//////222,,,---+++***...---///,,,000555///+++%%%'''%%%------,,,+++555666666AAA///...444DDDBBBLLLLLLZZZbbbaaaVVV[[[pppaaa___YYYoooiiiaaaaaaWWWYYY```SSSwww^^^QQQOOOUUUNNN===>>>???HHHGGGLLLjjjbbbbbbXXX```WWWXXXXXXYYY___sss___aaadddmmmtttuuuyyy5Kpx[:*zzz{{{tttrrr - !$%&(++*.**)'&#! !~~~{{{yyy}}}}}}~~~  - |||yyywwwxxx}}}ssskkkvvv|||!zzz(yyy```cccdddVVVJJJLLLAAACCCIIINNNRRR___WWWWWWXXX\\\WWW```dddWWWVVVXXXZZZ]]][[[YYYUUURRRSSSbbbhhh^^^```aaaooocccKKKVVVUUUZZZGGGAAA;;;555III,,,666(((&&&))))))&&&%%%!!!###'''###---555(((666&&&)))(((444NNNYYYEEE222+++444'''+++888...---)))+++---+++JJJ+++///...'''(((&&&"""******###111'''+++555777+++...000333888000,,,222===NNNLLLLLL^^^xxxiiiZZZjjjpppiii^^^VVVccclllmmmdddnnnlllVVVYYYWWWgggaaaOOOQQQQQQLLLCCCBBB;;;???KKKOOOHHHTTT^^^ZZZ___XXXYYYQQQSSSVVVTTTTTTaaaiiiiiigggooojjjsssyyy~~~0RU^S4 vvvtttiii~~~~~~ -  $%&)((*'((()'% ~~~~~~yyy  -! yyy~~~lllwwwnnnwww uuu||||||qqqmmmTTTNNNKKKIIIIIILLLMMMPPPQQQLLLNNN]]][[[WWWYYYXXX]]]___[[[YYY[[[bbbaaaaaaVVV___bbbhhhbbbwwwjjj[[[JJJJJJGGG@@@===444<<<444000(((''')))'''"""%%%'''***+++'''---)))###)))((((((,,,---555ccc444333777222000,,,444999>>>222(((%%%777000***)))***------)))777$$$&&&%%%&&&***...---*********...555111111555CCC777555444GGG???EEE]]]eeeYYY .yyyrrrSSSXXXllljjjfffXXXRRRTTTZZZ]]]SSSRRRMMMMMMLLLOOOCCC>>>;;;@@@CCCGGGKKKVVVPPPUUUZZZ```VVVVVVIIIGGGSSSQQQSSSgggmmmaaa[[[iiiqqq {{{ -6/6?9>{{{rrrzzzxxx{{{}}}{{{iiirrr -   "#%('()'('''$!    - xxx|||vvvooolllppptttwwwxxxxxx|||ooozzz ccc[[[UUUDDDEEEIIIRRRKKKOOOVVVNNNSSSQQQPPPYYYVVVUUUeee]]]nnnmmm___\\\vvvsss^^^]]]___^^^YYYooo___JJJGGGAAAEEE@@@===444444333---///---"""&&&'''++++++)))$$$$$$(((((((((((()))&&&bbb---///888+++<<<===MMM999999JJJJJJ===444***'''***''')))%%%"""***(((;;;%%%((('''***'''&&&***))),,,111222666...111000111///<<<===;;;HHHCCC???EEE\\\bbb[[[EOOOLLL___hhhgggYYYQQQXXXUUUMMMUUUQQQPPPIIIIIIFFFJJJ>>>@@@===AAACCCFFFFFFLLLTTTVVVjjj[[[SSSOOOLLLNNNRRRRRRWWWccciii```\\\nnnrrrqqq  mmmuuuyyy|||uuuxxxttt{{{ - - - $%%''$#$##"!   {{{mmmoooooovvvnnnwwwxxxyyy~~~ *kkkeee___dddXXXSSSJJJDDDGGGOOO[[[JJJUUUNNNXXXUUUNNNVVVWWWWWWRRR]]]bbbeeeggg^^^ccc]]]```gggfffpppjjjOOOFFF\\\HHHEEECCCAAA@@@???MMM333///000555111***)))((()))...FFFLLL)))+++(((&&&(((***///&&&***&&&,,,...++++++---RRR222QQQPPP000444///...+++*********,,,...==='''""""""'''(((---///&&&&&&000###444777111333...333...333GGG555666XXXDDDBBBIIIRRRVVVeeecccjjjPPPTTT[[[ddddddnnnOOOKKKSSSLLLLLLOOOOOOCCCJJJGGGIIIFFFHHHCCCFFFFFFVVVHHHHHHKKKMMMOOOUUUXXXTTTGGGMMMYYYRRRMMMUUUZZZ^^^___XXXlllhhh{{{ppp}}}zzz zzzlllpppmmmeee~~~tttvvvzzz   "! "! sss}}} -   vvvsss|||pppkkkpppssswwwrrr}}}wwwnnn}}}qqqYYYZZZTTTUUUJJJQQQLLLEEEGGGRRRXXXOOOKKKQQQLLLRRRXXXTTTTTTOOO]]]fffjjjuuu```[[[fffeee______jjj]]]TTTOOOEEEBBBDDDCCCAAA===:::999:::555444000---+++((()))---(((%%%^^^777///***---333((('''%%%"""---&&&%%%&&&$$$$$$&&&???111555000---444,,,((((((&&&...+++&&&((("""$$$+++999&&&)))---+++%%%(((%%%%%%444///333,,,//////888666@@@<<>>GGGFFFJJJLLLeeePPPYYYRRRZZZTTTWWWQQQWWWSSSYYY___ccc```ccc^^^aaaaaabbb^^^gggkkkXXXIIINNN```III<<<;;;::::::777;;;999333222---)))%%%&&&))))))***+++XXX666)))(((---((((((+++$$$'''+++***'''+++...***333VVVFFF+++***%%%222)))'''))),,,'''***&&&(((###%%%'''000&&&###!!!EEE%%%///666,,,'''+++555---333///FFF???DDDMMMOOOHHH{{{[[[HHH[[[HHHNNNUUU]]]rrruuujjj```VVVSSSkkkPPPPPPYYYTTT]]]GGGIIIXXXmmmJJJ<<>>333888]]]WWWEEEMMMBBBKKKFFF===HHH```aaahhhaaacccYYYQQQTTTOOOMMMQQQYYYOOOHHHNNNJJJ@@@@@@>>>???GGGHHHIIICCCJJJKKKNNNOOOSSSSSSRRROOODDD555...FFFLLLdddTTT______SSSSSSnnn  -uuujjj[[[cccjjjxxxcccqqqgggZZZfffwww|||ooo -  - (  - - -~~~ ~~~!uuuvvvpppooorrrqqqvvv~~~tttxxxfffjjj```XXXOOOQQQKKKFFFDDDaaaWWWNNNNNNSSSUUU^^^^^^ZZZVVVWWWOOOLLLPPPYYYYYYYYYZZZ___qqq```^^^ddd______aaakkkUUU```CCCFFF===999???777666777222888;;;000000+++---&&&$$$&&&&&&'''$$$!!!$$$&&&......(((111)))---...&&&888$$$&&&'''000((('''###)))&&&,,,333...%%%$$$&&&$$$&&&###''''''(((---%%%(((### ###!!!'''***+++GGG000+++000666666999444IIIBBBKKKBBB;;;<<>>>>>;;;;;;EEEMMMrrraaaiii___]]]QQQNNNQQQPPPMMMKKKHHHMMMEEEGGG@@@<<>>777DDDGGGFFF@@@EEEqqqBBBPPPJJJTTTSSSZZZLLLHHHHHHVVVAAADDDPPP^^^rrrwwwaaa```dddmmmyyyrrrbbbiii|||wwwvvvuuupppwwwvvv___mmm```dddfff{{{nnnjjj}}} ~~~ - -     ||||||vvvsssyyy}}}vvv~~~||||||www{{{|||yyyvvviiihhh___UUUYYYRRRTTTQQQSSSNNNMMMZZZSSSSSSUUUUUUPPPOOORRRRRRUUU[[[WWW[[[YYYWWWZZZ]]]___aaaaaacccddd]]]aaaZZZPPPJJJCCC>>>FFFAAA===999===NNN111777222999GGG///...(((---$$$)))&&&######'''000+++---...---***''')))222GGG333***)))***%%%))))))%%%***$$$$$$***333...+++555,,,***...******+++### $$$!!!""" 000 '''%%%......222***(((---000222333888888;;;BBBCCCUUUQQQMMMdddggg[[[kkkmmmnnnkkkgggVVVTTTLLLMMMKKKMMMIIIIIITTT>>>999AAA@@@EEEGGGDDDQQQGGGFFFDDDDDDLLLFFFJJJHHHGGGJJJFFFBBB:::LLLGGGRRR___```aaajjj{{{mmm\\\^^^cccjjjvvvrrryyy{{{www}}}hhhssszzztttpppwwwvvvnnnuuu    -  -  - yyy  - yyyxxx{{{uuuvvvuuu{{{xxx|||{{{xxxvvvuuuwww}}}xxxqqqcccSSSUUU\\\^^^TTTRRRQQQUUUQQQPPPRRR[[[VVVWWWPPPWWWUUUYYYbbbRRRJJJVVVZZZ\\\```]]]______cccaaa___^^^hhh{{{MMMBBBAAACCCFFFAAA888:::999???KKK222///666...000,,,)))(((%%%)))((("""######$$$%%%###&&&,,,===+++777999--->>>&&&++++++)))+++&&&%%%222+++&&&'''(((333+++111---)))%%%%%%)))333'''(((###$$$"""!!!"""---(((""",,,---444///---444666...333333444444EEE<<>>;;;:::FFF777MMM]]]bbbeeegggwwwiiibbbeeemmmvvvwwwvvvqqqzzzsssuuu -wwwyyyuuuvvvooonnnyyy -     - - {{{zzz -, -~~~~~~{{{ooossssssuuuppp zzzyyysssvvvsssuuuxxxoooaaaaaaZZZWWWlll\\\NNNOOO^^^RRROOOMMM\\\VVVWWWRRRSSSXXXZZZ\\\VVVUUUSSSXXX[[[___^^^fff^^^cccaaa^^^YYYVVVgggdddIII<<<===<<<:::999999888888666CCC@@@CCC000,,,---))))))&&&$$$&&&%%%&&&###$$$'''(((+++,,,)))&&&***------777---222TTT***,,,,,,###!!!222444(((000)))''''''NNN---***&&&%%%>>>qqq...rrr'''###$$$###"""###$$$333///333,,,,,,222@@@000333333555:::???;;;CCCQQQTTTNNNSSS[[[ZZZkkkqqqkkkfff\\\[[[OOOFFFJJJCCCDDDFFFKKKHHH@@@>>>>>>FFFAAA???AAADDDMMMEEECCCEEECCCJJJTTTLLLFFFEEEAAACCCAAABBBRRR```[[[\\\eeedddllleeeqqq{{{yyyxxx}}}rrrtttuuuxxx}}}1/qqqwwwwwwrrrtttvvv    -  -    yyy~~~~~~~~~{{{xxxrrrnnnsssrrrvvvwwwzzzooommmqqqyyysssnnnaaa```[[[[[[\\\[[[^^^RRRNNNRRRTTTZZZUUUYYYXXXYYYYYYTTTXXXzzzcccbbb\\\^^^YYY\\\mmmfffmmm\\\]]]cccUUUSSSJJJFFFGGGFFFDDDTTT666999777444999777OOO{{{LLL...333++++++)))+++$$$&&&(((((())),,,---000:::(((888***000111UUUCCC222+++555:::222+++$$$ DDD"""'''%%%"""333$$$''''''(((===FFF>>>)))$$$### %%%***<<<***'''...(((777)))///333000333999;;;===KKK;;;BBBIIIUUUSSSTTTZZZwwwiiiaaaXXX\\\\\\SSSSSSHHHUUUWWWOOOAAAGGG@@@;;;AAABBBBBB??????FFFIIIAAAEEECCCBBBBBBHHHEEEBBBDDD===>>>BBBQQQuuuWWWZZZ``````nnnaaarrrsssuuuxxxrrrrrrjjjrrr)lllxxxrrrttt -xxxzzz - {{{|||||| }}}  -   -~~~}}} vvvssssssrrroooxxxwww|||zzzrrriiiiiiooolll ddddddXXXddd\\\YYYRRR^^^QQQSSSUUUUUUWWWTTTZZZUUU[[[TTTUUUUUUbbb\\\UUURRRTTTYYYUUUZZZ___^^^[[[YYYZZZUUUMMMJJJFFFAAA???CCCAAAMMM>>><<<;;;777777AAAaaatttwww555000+++***'''((((((+++000$$$$$$,,,,,,((((((,,,999111///222:::FFF(((+++'''888GGG%%%$$$!!!%%%"""%%%%%%$$$!!!'''111999''''''$$$(((### ###)))(((+++%%%!!!)))###,,,999555999<<<444666777@@@NNNJJJZZZMMMSSSjjjtttqqqbbb```aaaXXXdddZZZBBBGGGNNNDDDPPPJJJCCCEEE???@@@FFFEEECCCCCCGGGQQQBBBFFFHHHHHHCCCHHH???BBB???AAACCCEEEDDDHHHFFFOOOaaabbbhhhqqq{{{~~~wwwssssss tttqqqnnnwwwwww -~~~pppuuusss|||~~~ ( {{{ ~~~ # ~~~}}}xxxxxxzzz{{{ !}}}zzzyyyrrrwww{{{uuu{{{tttsssvvvnnnkkkeeekkkddd\\\___```YYY___}}}UUUOOOSSSYYYaaa^^^]]]]]]XXXTTTQQQOOOLLLTTTUUUOOOGGGPPP\\\```aaa___aaabbb]]]ZZZTTTNNNHHHCCC@@@CCC;;;999???BBB@@@@@@>>>@@@???MMMUUUFFFBBB888111---111***...&&&"""&&&)))$$$###&&&)))///<<<000555+++111777888%%%+++,,,%%% '''""" +++******!!!###!!!$$$&&&!!!$$$!!!""" )))$$$---(((+++000NNN***'''%%%"""'''777777---111YYY555999EEEVVVJJJTTTVVVbbbbbbvvv"tttwwwuuuddd]]]LLLNNN>>>NNNRRROOOCCCIIIVVVDDD@@@@@@DDDBBB@@@HHHNNNDDDAAAEEEAAAKKKCCCHHHHHHEEEEEE???AAAAAABBB===>>>PPPfff\\\gggvvv~~~sssxxxwwwsssuuuxxxzzzyyyjjjqqq&qqqjjjrrrrrrqqqsss   - - -$}}}~~~yyy  - -}}}{{{|||zzz}}}sssuuuwwwsssxxxttt{{{vvvnnnjjjkkkdddeeelllfffaaaaaa\\\TTTTTTVVVOOONNNXXX\\\WWWbbbtttZZZPPPOOOMMMNNNJJJOOOZZZTTT\\\eeehhhgggcccbbb```YYY[[[RRRNNNKKKAAA@@@???;;;AAAGGGAAAAAA>>>BBB>>>KKK<<>>@@@DDDDDDOOOQQQNNNDDD???LLLIIIaaaUUURRR888///111???+++'''(((222'''%%%$$$'''''''''***+++333000888;;;000444(((///$$$$$$"""!!!$$$...(((&&&!!!***(((555$$$###$$$%%%!!!"""))) ###+++111444sssnnn+++,,,:::---+++///&&&,,,DDD///;;;EEECCC===BBB;;;===HHHHHHLLL===mmm!'"WWWNNNFFF<<>>AAA;;;<<>>444111,,,******&&&***+++&&&$$$%%%444ddd555)))(((,,,,,,+++***555333### ///???)))------%%%$$$)))444!!!"""%%%&&&$$$:::OOO((($$$$$$''';;;000..."""...'''""" '''"""222@@@555;;;555777???999HHHGGGIIIMMM@@@IIIQQQWWWfffXXXLLLOOOLLLEEELLLEEEDDD???LLLGGGDDDBBB===BBBBBBEEE___RRRPPP@@@IIIZZZ:::???BBBBBBBBBEEECCC>>>AAA===;;;CCCCCCSSSUUUccc```iiiwww|||ppplll||| www```xxx}}}wwwzzz|||sssrrrzzz}}} yyy|||}}}zzzyyywwwzzz  - -     -}}}vvv|||xxx{{{+ yyykkkgggfffeeevvv^^^aaaaaa[[[]]]YYYXXXSSSOOOPPPOOOMMM\\\WWWRRRWWW\\\eee]]]dddaaaaaaaaa___bbblllggggggkkk___ZZZ[[[ |||SSSHHHEEELLLCCCSSSBBBOOOZZZBBBBBB@@@JJJmmm]]]TTTHHH888///333+++,,,111---'''+++***222&&&***+++,,,111///,,,+++))),,,,,,,,,,,,:::///%%%---...&&&888$$$'''...000...(((666"""###$$$111'''111+++&&&$$$(((---)))***000(((---###***:::!!!!!! """+++333//////555;;;999BBB999JJJOOOQQQmmmAAADDDYYYZZZlllHHHFFFFFFOOOKKKJJJNNNKKKFFF:::DDD???DDD???@@@>>>UUUYYYBBBUUUAAACCCJJJ???CCC@@@SSSKKKIIIBBB>>>GGGBBBEEECCCAAAXXXMMMVVV```xxxmmmrrrvvvttt}}}tttmmmiiiWWWooowww}}}xxx |||zzzoooiii~~~vvvxxx    $ #yyyssswwwtttuuuuuu{{{{{{pppsssnnnhhhfffeee\\\XXX\\\XXXVVVUUURRRPPPMMMSSSQQQRRRVVVOOOUUU]]]ZZZuuuwwwfffbbbgggccc___^^^___jjjYYYVVVUUUTTTrrryyyLLLEEEHHHUUUBBBEEEDDDLLL^^^HHHVVVDDDVVVbbbAAA===AAA???222555111,,,222+++''')))******///(((((()))---888)))'''(((---&&&)))''',,,&&&((((((333111%%%%%%'''%%%000777$$$'''000"""%%%"""))):::???666"""333&&&777666ZZZJJJ222###'''!!!$$$"""###%%%,,,111333111777666999===GGGOOOdddWWW___\\\VVV[[[GGGMMMRRRQQQKKKJJJNNNTTTKKKHHH999555999CCCHHHBBBBBBBBBAAABBBCCCPPPBBB???EEEDDDNNNGGGIIIBBB@@@FFF>>>HHHAAA>>>OOOOOOeee]]]}}}yyylllrrrooo___VVV___yyyWWW^^^mmmvvv{{{xxxxxxvvv|||zzzqqqwww  - -  ||| zzz{{{yyyvvvsssyyy }}}{{{pppssspppnnnnnnnnneeebbb[[[```RRRYYYWWWUUUTTTWWW[[[SSSZZZXXXRRRSSSVVVQQQXXXaaaeeefffeeehhh```dddwww``````aaa[[[TTTUUUOOOYYYNNNIIIDDDFFFDDDGGGXXXKKKQQQRRRPPPQQQMMMEEEBBB555;;;]]]CCC,,,+++333***&&&%%%***)))222(((+++)))&&&...))))))''')))(((***,,,%%%999'''III---'''&&&,,,VVV<<<)))---JJJ111%%%$$$222$$$!!!&&&'''???'''### 999'''AAA.[[[+++!!!!!!###!!!444###:::FFF555:::555666BBB===BBB]]]YYYNNN```aaa```___RRRYYYTTTTTTKKKYYYcccNNNLLLTTT\\\DDDCCCDDD<<>>>>>@@@LLLEEECCC???IIIaaaKKKNNNDDD???III??????===???DDDMMMPPPccc|||tttooovvvyyyoooPPPXXX]]]bbb[[[OOOTTTgggiiilllmmmuuuuuu||||||xxx   -}}}~~~vvvxxxyyy{{{yyyyyyuuu sssoooxxxqqqwwwpppxxx{{{wwwoooffftttaaaaaaVVVVVVaaaWWWSSSOOONNNTTT^^^UUUuuu^^^\\\YYYSSSQQQTTT]]][[[eeefffiiieeebbbbbbddddddjjjeee[[[fff]]]QQQRRRFFFKKKFFFAAA===AAACCC???CCCFFF@@@[[[JJJIIILLLAAA888555,,,333000---+++((('''(((000---((('''++++++''',,,)))(((###$$$&&&&&&+++&&&***...---(((+++$$$%%%...111222%%%---;;;--- !!!!!!$$$+++(((###%%%))) !!!'''CCC^^^***"""===???000222111999EEE???SSSJJJNNNQQQRRRbbb[[[PPPPPPVVVYYYddd```LLLYYYMMMTTTJJJJJJFFFBBB;;;>>>CCCDDDFFFXXXDDD>>>???>>>???EEE>>>@@@EEEIIIWWWKKKCCCFFFEEEDDDCCC???BBBHHHYYYrrr(}}}{{{mmmbbbyyyttt\\\___eeeeeeUUUIIIRRRbbboooqqqiiiqqqsssqqqlllrrr}}}zzzxxx  ~~~}}}{{{yyyuuuqqqssswwwxxx ~~~ uuuvvvuuukkknnngggkkkeee___dddfffcccffffffaaaaaaSSSMMMKKKYYYYYYVVVNNNSSSUUUUUUUUU^^^]]]WWWUUUTTTQQQWWWYYY```hhhbbbaaa___ccc^^^^^^[[[]]]aaa\\\[[[QQQMMMMMMFFF>>>HHH???@@@CCCFFFHHHEEE@@@999DDDMMMWWWDDD333...///555---///+++&&&***(((...///,,,***111******+++888&&&&&&''''''''''''$$$&&&BBBJJJ***###&&&>>>111+++///(((###777+++ %%%444)))(((""" ######"""%%%222%%%$$$***999///000XXX>>>BBB>>>FFFJJJOOOOOOTTTJJJPPPNNN]]]ZZZ]]]gggLLLHHHCCCBBBGGGJJJ===222888???IIIDDDJJJ\\\GGG<<<<<>>ZZZNNNDDDCCC;;;DDDoooFFFwww111111111555:::666...,,,++++++***///111---&&&---...,,,###%%%***&&&((('''...%%%###+++JJJDDD)))(((+++(((:::666777###(((555XXX))) """$$$ """ """&&&&&&$$$>>>,,,//////<<<@@@NNNAAAHHHNNNHHHRRRPPPNNNPPPPPP\\\TTT]]]___QQQEEEPPPSSSLLLEEE777333;;;===HHHEEE@@@@@@AAA===@@@CCCBBBDDDCCCDDDBBB<<<;;;;;;???===???@@@BBBKKKOOOSSSGGGJJJWWWqqqiii]]]ddduuurrrwww```JJJYYYZZZbbbcccddd```rrrvvvmmmxxxmmm^^^RRR___gggzzzzzzyyy||| -~~~  yyy}}}{{{oooqqqrrrmmmtttvvvsss|||tttmmmsssjjjiiiuuuwwwnnneeemmm[[[ccc\\\ddd```eeeaaaiii[[[VVVVVVWWW\\\UUUUUUXXXRRROOOMMMOOOXXXbbb ^^^fffWWWiiigggaaa```dddiiibbbkkkiiifffhhhppp^^^XXXVVVUUUQQQOOONNNEEEBBB===EEEAAA???DDD@@@nnnIIIHHHLLL777888===555222888333---BBB222BBB///222999+++...,,,(((+++***+++###)))((('''((()))&&&%%%;;;''',,,&&&######&&&$$$***333&&&'''+++444222222''')))111###$$$""" """>>>######&&&(((+++---+++///777555FFFIII^^^GGGQQQIIIMMMVVVOOOPPPWWWZZZ^^^\\\]]]aaaTTTWWW@@@111111777AAA:::>>>???III<<<======???AAAFFFJJJ>>>???;;;AAA???@@@???GGGEEEDDDCCC@@@BBBEEELLLWWWbbbxxxgggppptttsssyyysssQQQJJJlllrrrgggaaannn|||ppplllZZZKKK]]]```zzzsssuuu~~~|||yyyvvvxxxttttttyyyppprrrmmmuuuqqqtttqqqyyy}}}|||vvvxxxvvveeecccmmmzzzggg\\\ZZZ```___```bbb]]]TTTVVVYYYVVVYYYZZZVVVZZZ```___eeeWWWRRRUUU\\\ZZZUUUYYY]]]bbbkkkiiiaaaeeegggccchhhddd``````]]]kkkUUUTTTHHHIIIDDDAAAGGGDDDBBB>>>EEEKKKJJJOOO<<<:::@@@777666333333...111111111---+++...++++++000***666666---+++''';;;))),,,)))(((&&&((( $$$111&&&444$$$"""%%%$$$###***)))%%%***+++111>>>'''444 !!!!!!***666!!!666!!!'''""" &&& ###***+++CCC,,,;;;;;;;;;888777888<<>>???======>>>AAAJJJLLLAAA>>>>>>BBB===AAAAAABBBBBB???;;;FFFHHHSSSuuuWWWccczzzccchhhtttuuuzzzrrrrrr___ZZZiii sssoooooojjjwwwvvv eeeSSSRRRTTT\\\eeessspppoootttvvv}}}|||}}} mmmrrrqqqvvvtttnnniiipppiiinnnfffiiilllsssiiiwwwwww kkkiiitttbbbwwwccc```^^^]]]]]]zzzcccZZZ```WWWTTT\\\]]]ggg^^^\\\]]]XXX[[[VVVYYYVVViii\\\XXXcccbbbeeegggfffgggddddddhhhccceee]]]\\\ZZZ[[[WWWGGGEEENNN<<<999DDDEEE@@@DDDDDDAAA333444222222555444------(((---...000///+++///+++,,,111***---<<<...+++'''$$$((()))000%%%$$$333%%% ###)))!!!!!!###&&&"""$$$,,,(((,,,(((&&&"""555$$$&&& :::ccc!!!###'''+++111555LLLIII888111555<<>>>>>CCCDDD===777555===<<<:::GGGNNN@@@III<<>>EEE888======AAAFFFwwwNNNNNNRRRUUUpppllljjjgggjjjlllDDD999222444***222@@@:::>>>>>>;;;777<<<;;;>>>AAAAAA@@@===777666<<<>>>AAASSS::::::???;;;CCCQQQSSS^^^UUUTTTYYYgggfffvvvxxxuuuqqqcccZZZPPP]]]vvvuuuggglll___nnnpppjjj^^^ccccccnnncccfffjjjccc``````ssspppxxxqqq|||vvvxxxsssmmmrrrvvvqqqxxx zzzgggiii___qqqeeebbbTTT```\\\VVV```cccnnn```___bbbUUUXXXYYY[[[ZZZaaa\\\TTTYYY^^^kkkiiibbb```aaabbb]]]]]]]]]\\\YYYfff[[[UUUTTTXXX\\\[[[aaaddddddlllrrreeeccckkkjjjdddVVVPPPNNNKKKKKKOOO:::999;;;:::777;;;;;;AAArrrrrrDDD111777888444777999777111///...///---333,,,))),,,...$$$+++---111000)))===,,,$$$(((---,,,'''%%%"""!!!!!!"""!!!$$$***&&&+++DDDPPP---+++(((+++666+++'''000!!! $$$...$$$$$$...666555666999???AAA>>>BBBJJJMMMVVVRRRYYYdddkkk^^^^^^kkk___TTT^^^ZZZ:::<<<555222222222333:::;;;666======AAA@@@BBBHHH@@@===DDD555@@@FFFLLLAAA<<<<<<<<<@@@DDDHHHVVVYYYYYY\\\pppgggwwwxxxqqqpppsss}}}aaa]]]hhheeexxxnnnhhhhhhhhhsssXXXssstttpppssshhhggg^^^___YYY^^^}}}ppptttvvvpppdddiiisssvvvvvvooorrrsssrrr 5qqqlllssskkkbbb___ZZZTTTWWWZZZoooooo~~~aaaXXXWWWUUUUUURRRccc\\\aaa^^^WWW\\\^^^\\\]]][[[___hhh___hhhcccZZZZZZSSSWWWQQQRRRMMMXXXYYY\\\ZZZ```gggcccdddrrriiieeeaaa^^^\\\TTTMMMGGGHHHHHHddd===@@@;;;???888:::EEEBBBHHHHHHLLL<<<;;;999666333...111888555777000((()))++++++,,,,,,,,,'''%%%(((%%%'''LLL'''$$$$$$***)))(((&&&%%%$$$$$$######222)))+++RRRUUU)))***'''???222:::))),,, """$$$  $$$ ///333...555AAA@@@DDDPPPBBBEEEMMM___UUUPPPOOOZZZ```mmmaaa^^^PPP___XXX@@@222......333111999aaa===AAA...///666<<<>>>777@@@<<>>888555999999CCC@@@<<<999::::::;;;@@@HHHDDD>>>999@@@DDDEEEIIIOOORRRVVVMMMTTTOOOUUUggghhhlllkkkrrrooo]]]eeehhhjjjfffmmmllljjjqqqllljjjkkkvvvyyyrrrbbbeeebbbWWWQQQaaa]]]UUU___^^^eeekkkbbbjjjbbbmmmhhhfffhhhwwwxxxlllxxxdddddddddaaa^^^UUU\\\bbb\\\ZZZYYYXXXVVVWWWfff]]]``````ZZZ\\\bbbbbb___ffffffjjjhhhrrrdddddddddgggooo]]]]]]fffooohhhcccZZZ```ooobbbbbbaaaqqqfffhhhWWWVVVPPPQQQFFFHHHCCCAAA???TTTDDD;;;>>>777666:::aaaGGG:::KKKJJJIII@@@888666:::///***(((---******000***(((,,,+++******%%%"""$$$%%%&&&(((%%%---%%%)))&&&%%%%%%""" $$$''''''111111///,,,***&&&(((333---,,,---+++LLL***"""!!!!!!###///$$$!!!)))$$$///,,,+++...111<<>>FFFccc666777111222000,,,***...(((&&&'''+++******)))'''***%%%&&&"""%%%((('''((('''(((***///,,,"""%%%***&&&...>>>555CCC)))+++...333444999888)))### $$$+++!!!((( 222+++  """***,,,$$$******111GGG444SSS>>>IIIMMMOOOTTT\\\IIIOOOeeeuuubbb[[[TTTPPPNNNOOOGGGMMMAAAFFFUUUSSS+++///777777999666;;;444<<<444999777<<<999;;;;;;@@@<<>>===<<<555888CCC@@@:::999>>>BBB>>>@@@888CCC<<<;;;333888222222,,,)))+++,,,))),,,444,,,,,,+++((('''%%%###%%%'''######***,,,%%%%%%***&&&,,,%%%!!! $$$)))FFF???:::,,,:::'''@@@777(((''' !!!'''$$$$$$!!!666999777%%%!!!"""...///(((***111666FFFggg888CCCNNNNNNMMMDDD\\\JJJGGGKKKWWWggg```SSSMMM[[[TTTMMMPPPUUUIIIHHHBBBHHHHHH000)))---666:::222777222333222333;;;666777888666>>>AAA888:::GGGUUUGGGNNNMMM]]]TTTXXXEEEMMMYYYgggiii```pppjjjqqqzzziiicccWWWfffXXXuuuqqqttttttzzzpppqqq^^^[[[ZZZbbbeeegggkkkoooQQQOOO```jjj\\\ZZZ[[[[[[ZZZUUUfffgggjjjuuujjjaaa]]]ccc]]]aaa___\\\ZZZVVV```gggggghhhbbbdddooo~~~lllpppjjjkkkiiinnnnnnooooooiiijjj rrrlllzzzmmmuuulllllloootttnnnqqqkkkooo[[[LLLNNNNNNOOOQQQ^^^[[[UUUKKKIII;;;;;;777:::KKKNNNGGG:::555888;;;>>>BBB===666555777666777111///...+++,,,)))''')))((((((((())),,,+++(((222)))(((%%%222###'''&&&###$$$'''###$$$'''%%%%%%111%%%'''((((((###///###ggg,,,%%% &&&((( )))RRR ...'''***...222333DDDGGGBBBEEEJJJCCCLLLMMMHHHLLLSSSLLLJJJPPPXXXYYYMMM```WWWFFFFFFDDDJJJ<<<:::,,,***...---111222555<<<666666<<<555<<>>:::@@@777<<<@@@JJJNNNRRRTTTPPPDDDOOOJJJXXXVVVZZZccclllooooooeee]]]]]]MMMEEE___mmmkkkmmm3 ggghhh^^^ccchhhlll```TTTTTTTTTOOOZZZaaabbb```^^^aaaYYYUUUWWW\\\ccc]]]iiinnnnnnjjj^^^[[[aaa```ddd\\\ggg___]]]```dddaaacccbbbeeedddmmmkkklllfffdddeeeooojjjhhhmmmmmmfffpppuuuyyyyyyqqqqqqooouuurrrttt{{{qqqoooiii^^^```TTTSSSZZZUUUNNNOOO\\\bbbQQQJJJ<<<<<<999@@@???888@@@AAA;;;:::111???@@@===<<<777555;;;000---...000---:::,,,///&&&%%%&&&''')))%%%%%%)))+++***&&&******((((((""""""###!!!%%%###$$$$$$CCC+++(((***(((+++///"""+++)))444)))???FFF!!!$$$ $$$)))***'''(((%%%(((000333:::===@@@???JJJJJJJJJKKKUUUTTTQQQ]]]ZZZFFFNNNXXXSSSPPPLLLRRRHHHFFF@@@AAA@@@UUU666444///***///888555222444999777===999:::;;;<<<888<<<;;;777<<<;;;@@@IIIGGGRRRRRReeeFFFFFFEEEVVVWWWdddkkkaaa^^^aaa[[[UUU\\\ZZZSSS@@@\\\hhhoooyyy|||ccciiilllnnneee\\\XXXZZZPPPUUU```fff___```ZZZOOOXXXXXXZZZ\\\^^^ddd\\\mmmmmm``````aaa```^^^[[[bbb___hhhkkkiiieeehhhmmmeeedddcccgggfff```bbbeeeiiijjjgggjjjrrrllloooooossspppzzzuuuwwwuuuooonnnpppxxxjjjeeeggg```VVVRRRRRRRRRSSSMMMVVVOOOOOOCCC:::<<>>!!!'''&&&)))///<<<<<>>@@@@@@GGG===???KKK000***,,,///---444777;;;:::===:::<<<<<<999999:::::::::777HHHHHHDDDEEELLL???QQQAAA@@@IIIJJJ]]]___ZZZWWWRRR^^^eee^^^```[[[PPPaaauuummmjjjkkkyyynnnjjjbbbxxx|||pppddd```___^^^[[[SSSPPPGGG\\\WWW^^^nnnhhhooonnngggYYYXXXkkkdddZZZgggddddddgggdddeee```eeeccckkkmmmkkkccc```bbbbbbcccaaafffllldddccciiinnnmmmbbbggglllnnniiijjjxxxlllpppvvvrrrqqqgggaaakkkwwwsss]]][[[WWWZZZ[[[WWWSSSOOOWWW___HHHBBB<<>>IIIFFFSSSTTTVVVKKKMMMPPPOOOOOOOOOIIIUUUKKKNNNKKKHHHEEEEEEFFF???<<>>===AAAEEEHHHWWWKKK???BBB777CCC??????JJJFFFOOOQQQTTT___tttaaa```vvvUUUeeeZZZeeebbbfffbbb^^^RRRVVVVVVccceeedddddd______aaa___hhhNNNIIIQQQ[[[ooowww~~~iii[[[llldddcccbbb\\\]]]kkksssrrrbbbkkklllkkkjjjiiijjjfffdddhhhdddggg]]]llllllggghhhgggeeecccxxxwwwmmmiiigggoooxxxwwwppphhhgggfffhhhjjjjjjgggccc\\\UUUSSSbbbUUU[[[pppFFFBBBCCCGGGAAACCCDDDEEE<<<@@@>>>666>>>:::===EEEDDDLLLAAA;;;>>>888333...333111000///---...111***''''''333***)))''''''&&&+++sss%%%'''((((((&&&"""%%%%%%'''444(((,,,&&&###%%%$$$&&&!!!'''222111000 777 !!!&&&%%%+++---,,,666YYY===777MMMCCCMMMIIIPPPJJJMMMXXXVVVVVVNNNJJJXXXAAAAAAFFFGGGLLLCCC;;;444<<>>CCC===TTT;;;???555DDDPPPZZZGGGNNNOOOPPPCCCIIIFFFGGGRRRIIICCCAAAAAA777???SSSDDD111111111,,,///222QQQ555222111444555::::::???===333666<<>>sssTTTGGGRRRJJJDDDHHHVVVDDD???DDDDDDIIIEEEQQQ[[[YYYVVVcccbbbfffdddfffdddkkkbbbccchhhfffllllllrrreee^^^OOOTTT\\\XXXYYY___aaannnttt sssllldddmmmsssjjjiiigggdddjjjjjjrrrkkkjjjiiimmmwwwppprrrnnnkkkhhh___kkkhhheeevvvtttqqqqqqiiieeeeeecccjjjdddhhhooobbbfffoookkk^^^ddd``````TTTSSSTTTQQQTTTQQQZZZUUU^^^VVVAAAOOOLLLSSSjjjmmmEEEHHHDDDLLLIII???<<>>///222555222444222555,,,111)))&&&++++++((())))))%%%######!!!###)))***888,,,%%%))))))((($$$%%%((()))$$$"""&&&###!!!%%%### !!! $$$!!!$$$***,,,111888:::FFFAAA888888888===KKKPPPPPPJJJOOOKKKNNNFFFGGGEEEDDDDDDEEE???DDDAAAJJJPPP999888222---...111///111777222111111444222444<<<@@@666222:::CCC<<<777<<>>>>>HHH222444000+++555666222111...000...444'''++++++...'''###!!!$$$###"""######((())))))///&&&)))))),,,'''222((('''$$$!!!!!!!!!###%%%%%% ---""" !!!"""444 777666!!!$$$$$$(((///---222<<<:::444999@@@@@@FFFKKKIIISSSRRRJJJEEEYYYFFFKKKCCCEEECCCAAA<<<@@@===AAA999666666777222'''%%%+++---///000------///444555777<<<777333333IIIMMM666000999HHHBBB:::AAAQQQAAAKKKLLLEEE@@@DDD>>>DDD]]]XXXQQQ\\\ddd```ddddddcccZZZ[[[```\\\aaa[[[}}} wwwiiiccchhhnnneeemmmjjjttthhheeejjj  llljjjqqqoooyyygggyyyuuuooopppppplllhhhgggjjjrrrpppdddkkk}}}ooojjjkkkiii~~~|||wwwfffddd[[[fff]]]___ZZZ]]]UUUUUURRRVVVRRRPPPUUUMMMQQQKKKHHHJJJJJJKKKGGGFFFDDDDDDMMMJJJTTTeee$7fffQQQHHH???@@@:::>>>777<<<999HHH???555333222333777222000???000???000)))&&&&&&$$$%%%!!! ###'''+++,,,+++333+++888++++++,,,***>>>((('''((( ,,,%%%((("""### )));;;"""$$$555"""!!! (((!!!&&&)))***+++333333<<<666OOODDDCCCBBBQQQNNNKKKMMMMMMIIIHHHFFFOOOEEECCCAAAEEEFFF===;;;CCC:::888>>>@@@[[[333---***---(((---+++///111444GGG444888999...555666BBB888555>>>???JJJ<<>>===CCC<<<:::>>>DDD333<<<555---333888NNN+++***///"""&&&'''"""%%% $$$&&&///------777111>>>,,,'''((((((***'''%%%)))!!!'''%%%$$$###$$$!!!)))<<<!!!######---000)))555IIIFFFFFFOOOBBBIIIDDDGGGXXXFFFQQQJJJ___TTTHHHGGGFFFHHHHHHFFF;;;BBBKKK:::888LLL777444<<>>@@@BBB@@@DDDqqq999EEE999666]]]NNN<<>>===>>>@@@lll777EEEOOO777CCC222000444//////.........222:::999000888BBBDDD<<<===CCCCCC???BBBFFFCCCDDDLLLIIIIIIFFFPPP<<>>FFFEEE???>>>CCCyyyaaaNNN===999>>>555111///333...&&&***###%%%%%%###BBB111"""$$$$$$###---MMM---333***+++)))%%%&&&$$$$$$111;;;(((+++...000___)))$$$***+++)))###'''!!!... ((('''***222 """((('''$$$===BBB<<>>AAA>>><<<333EEE333:::+++555000444///))),,,---+++'''...111999777111555777;;;999888BBBGGGHHH@@@AAAHHHJJJFFFFFFHHHbbb```AAANNNCCCHHHOOOLLLYYYQQQOOO[[[XXXdddWWWWWWeeeMMMZZZUUUYYY]]][[[^^^^^^YYYWWW___aaafffgggeeebbb```XXX\\\lllvvvrrrwwwgggbbb___dddWWW]]]bbbWWW^^^RRRPPPbbbbbbrrrccccccfffbbb\\\[[[UUUUUUWWWTTTSSSRRRNNNLLLHHHIIISSSKKKKKKHHHJJJKKK[[[DDDLLLKKKJJJDDDBBBZZZcccxxx oooiiiQQQNNNMMMCCCEEEDDDIIIGGGIIIIIIOOO;;;FFFJJJ===BBBKKK888:::WWWPPPAAAOOOMMM333000,,,,,,111***...,,,)))%%%===:::777333$$$000***###)))---111'''(((---111******)))---444***&&&222(((---QQQnnn)))%%%%%%+++))) &&&===!!!&&&'''&&&!!!$$$!!!)))...000666:::@@@IIILLLDDD;;;FFFMMMMMMPPPPPPVVVLLLIIIJJJQQQFFFMMMEEE@@@HHH;;;;;;888???111:::333888;;;...999***,,,---***'''+++...111777555555<<<===???<<<@@@FFFAAA===EEEGGGFFFBBBFFFEEERRRSSS[[[AAA>>>BBBJJJKKKRRRUUULLLSSSSSS\\\QQQMMMHHHEEE???JJJPPP^^^PPPUUUZZZSSSUUU[[[jjjdddXXXmmm\\\OOORRRYYYUUUNNN___pppggg```hhhjjjaaa___ZZZ[[[```YYYYYYQQQWWWZZZ[[[[[[^^^iiiggg^^^]]]SSSPPPVVVKKKLLLHHHXXX^^^AAAGGGGGGCCCXXXCCCAAAFFFKKKDDDDDDKKKDDDAAA???___{{{rrrrrruuufffKKK^^^JJJ@@@???AAAXXX<<<:::@@@AAA>>>===<<>>>>><<<666888RRR666333777LLL///(((111,,,000!!!!!!***"""***III((()))+++)))&&&%%%$$$(((+++((((((000&&&***&&&+++$$$444,,,%%%%%%%%%,,,333000)))%%%###"""%%% &&&///"""$$$$$$$$$ '''---+++222===999DDD>>>FFFEEENNNJJJIIIIIILLLNNNVVVXXXLLLrrrNNNCCC<<<@@@:::CCC>>>555777111---222111222111222......)))%%%,,,...+++666555666999FFFEEEAAA>>>@@@CCCDDD@@@;;;CCCDDD???GGGLLLTTTnnnBBB999777???MMMHHHHHHSSSMMMMMMRRRQQQLLLDDDDDDCCCGGGPPPOOOPPPNNNPPPUUUVVVWWW\\\XXXZZZaaaYYY[[[pppPPPIIIQQQ\\\UUURRRVVV\\\YYY]]]dddaaaTTTYYYUUUYYYWWWRRRPPPJJJWWWWWWZZZWWWZZZeeeQQQIIIJJJIIIEEELLLEEEKKKAAA@@@BBBEEEBBBJJJCCCNNNGGGBBBBBBFFFCCCBBB:::OOOSSSwwwXXXCCCOOOTTTBBBGGGDDDIIIFFF<<>>GGGPPPBBBEEEWWWFFFOOOHHHHHHJJJIIIFFFKKKQQQOOOHHHJJJ@@@DDDDDD???888777333888000333777999;;;666666333...###000444666555<<>>CCC===EEEHHHGGGSSSCCC>>><<>>LLLOOOHHHGGGRRREEEJJJSSS___JJJFFFCCCQQQNNNFFF???;;;888444777999AAANNNppp===//////...***+++555:::???VVV]]]LLLQQQWWWEEE@@@===FFF>>>BBB@@@999XXXMMMTTTQQQDDDBBB;;;333999EEEHHHHHHNNNJJJRRRLLLUUUjjjKKKFFFKKKCCCJJJGGGFFFLLL\\\8nnnNNNGGGKKKIIIIIIMMMPPPRRRMMMVVVPPPNNNKKKLLLKKKTTTJJJPPPKKKIIIFFF>>>DDDIIIGGGFFFKKKNNNGGGEEELLL\\\OOOKKKEEE>>>DDDFFFGGG@@@<<<===@@@???>>>CCC@@@MMMDDD\\\DDDNNNAAA@@@BBBAAACCCOOONNN___IIISSS@@@CCCCCCuuuCCC<<<999===888<<<222666555555333---111//////---@@@///III555GGG666***(((&&&$$$)))&&&***&&&"""%%%))),,,&&&333---&&&%%%(((666---+++((((((---444CCC///)))***888222111111---$$$(((%%%IIIXXX+++!!! !!!666 )))""" 000$$$%%%""",,,)))+++FFF;;;;;;EEE>>>???CCC<<>>BBB@@@III>>>???<<<;;;<<>><<<<<>>888BBB???@@@;;;---&&&000AAAMMM===BBB@@@@@@SSS===BBBBBBMMMEEE>>>>>>@@@EEEGGGEEEFFFCCCRRRLLL...000??????IIIMMMLLLJJJFFFOOOXXXKKKEEEBBBdddKKKYYYUUUVVVIIIWWWMMMNNNBBB>>>===AAAHHHGGGFFFIIIHHHGGGIIIVVVIIIEEEAAAAAA???>>>BBBAAABBB>>>@@@CCCGGG???@@@AAAHHHHHHIIIFFFFFFEEEBBBAAABBBCCCBBB>>>???@@@;;;999<<<<<<<<>>FFFBBBEEEPPPNNN]]]AAAQQQRRRaaaHHHIIIGGGKKKQQQYYY@@@===???<<<777;;;===<<<))))))555===<<<>>>???;;;;;;AAA;;;888:::UUU???AAA<<>>:::>>>BBB>>>>>>CCCAAACCCDDDDDDMMMFFFKKKFFF??????@@@???BBB<<<:::888FFFDDD@@@:::===>>>???HHHeeeRRRVVVFFF<<>>333\\\???222666222333333000///***SSS444777888///))))))%%%$$$$$$###***)))'''******---+++111000---+++:::...///888---222---+++444000\\\999222---@@@///&&&***888444(((000"""$$$***%%%!!! )))'''!!!"""$$$$$$&&&$$$###'''222555999<<<===BBBfff666<<<@@@IIIBBBBBB@@@===HHHZZZJJJcccNNNSSSSSSQQQ@@@JJJ<<>>;;;666???CCC======TTTEEEEEENNNUUULLLQQQcccppp;;;AAA555555@@@FFFIIIXXXOOOGGGLLLSSSVVV@@@>>>::::::MMM===UUU@@@@@@AAACCC===???777CCCJJJVVVpppiiiGGG>>>;;;IIIHHH<<<<<>>AAA@@@BBBFFF@@@GGGAAABBBCCCBBBBBBCCCCCC@@@@@@CCC:::>>>:::===:::888<<>>EEE;;;===777===>>>777<<<444111///...444QQQ444000...***+++...777333999555***(((+++,,,***)))CCC111333,,,...<<<...111666666AAAUUU999555:::111666,,,------>>>TTT///666******'''(((***"""///%%%222 )))!!!(((%%%!!!!!!"""###;;;...&&&555888<<<111888<<>>AAA@@@>>>===BBB<<>>===;;;;;;999@@@@@@<<<>>>;;;;;;BBB???===AAACCC>>>???>>>???CCC;;;777;;;:::<<<;;;AAAOOO999<<>>888888<<<888???666888222111///666666...444...///++++++///+++000WWWAAA***)))///888888gggNNNZZZ555777999777777666999333AAA222......222777???111DDD@@@@@@444///'''%%%"""+++"""###)))&&&!!! 777###000 """...777)))'''***<<>>GGGHHH>>>CCCAAAJJJGGG<<<@@@===:::@@@IIIPPPCCCFFF999555<<<777CCCCCCFFF@@@HHHOOOTTTJJJQQQFFF:::666333???>>>BBB;;;999;;;<<<@@@>>>>>>IIINNNXXXKKKBBB@@@EEE???FFFCCC;;;===777:::;;;;;;;;;777<<>>AAADDD???BBB??????EEEIII>>><<<<<<:::IIICCC>>>FFFMMMNNN>>>;;;000444222222...000000DDD999444333===///444///TTT>>>000888///999555666===UUU:::OOOKKK>>>...;;;ZZZ<<>>AAA@@@<<>>===:::@@@@@@JJJoookkkTTT===:::@@@===999999666444888555444888???>>>777>>>???@@@>>>@@@;;;;;;===:::HHH<<>>===555777444DDDFFF???<<<888;;;<<<<<<<<<;;;<<<888555:::<<<333;;;GGGQQQ222333666YYY:::<<<>>>@@@<<>>eee:::===LLL000///555:::DDDDDD222222444333...+++111```YYY444///+++&&&%%% &&&(((&&&$$$***&&&$$$"""OOO"""111"""***>>>AAACCC@@@+++&&&444------444222;;;:::===222444555777555333777WWWLLLUUUFFFFFFNNNLLLOOOAAA>>>AAA===>>>]]]XXXKKK;;;555---333999===:::555222222,,,888<<<777===777<<>>666777<<<:::<<>>CCC999666888<<<@@@===@@@???<<>>888===BBB<<<===DDDCCC888999888<<<:::???BBBBBB999BBB;;;BBB>>>===999222444>>>888<<>>[[[;;;===EEE111666MMMGGG222;;;???XXX888999kkk???CCC444111AAA444333222---555555---000===---***AAA>>>sssLLL000******&&&+++...###'''%%%"""///$$$ $$$YYY EEE+++***DDD444 ///666333444+++...111111666555666999777888222333111>>>mmmEEEEEESSSTTTJJJBBBDDDJJJMMM===>>>ZZZbbbIIIIII888...999777999AAA:::999777111333555777666888999BBBEEEOOOFFFEEEGGGCCCJJJ;;;BBB<<>><<<;;;:::888;;;666===BBB===CCC;;;;;;555:::DDD222444000666666;;;YYY;;;;;;777MMM===:::GGGppp???CCC444444888~~~\\\666DDD]]]???444QQQGGG;;;;;;666888<<<555:::777999444333MMMTTT777333///(((+++)))333444888+++...---666...(((...+++'''...+++%%%AAA......BBB>>>!!!&&&+++%%%%%%<<<''' 333FFF,,,555,,,$$$$$$###+++******---222+++///222222222000666333444888KKK -IIIHHHQQQMMMdddBBBFFFiiiDDDDDDFFFYYYCCC===HHH444555;;;777DDDAAA;;;666111,,,000555===:::777>>>:::???UUUHHHRRRDDDHHHIII<<>>FFF<<<===sssGGGMMM000666<<>>LLL===@@@888AAA@@@>>>AAAGGGGGGAAAYYY======999AAA;;;999888999:::<<<<<<999===???CCC666???===FFFHHHTTTKKKFFFAAAEEE;;;IIIAAAMMM@@@DDD???KKK<<<@@@TTT===777777===---===888>>>:::BBB555AAADDD<<<:::000555>>>;;;777222WWWDDD>>>:::EEE;;;<<>>===;;;999111777777222===333444777888<<>>EEEJJJ>>>>>>>>>@@@111>>>:::KKK???===:::888111222777BBB999NNN999<<>>eee;;;;;;555<<<;;;ddd>>>RRRIIITTT???BBBHHH<<>>777111666222((("""&&&'''///,,,...%%%===***111>>>***))),,,"""%%%!!!RRR&&&&&&"""###$$$---"""&&&///---333III111DDD555333///AAA666BBB000;;;BBBBBBBBB>>>AAAGGGIII>>>JJJ???:::;;;;;;===mmmLLL<<<666===>>> FFF@@@:::<<<444...333;;;===;;;AAA@@@;;;JJJEEE@@@LLLEEEBBBLLLCCC;;;EEEvvvNNNJJJ666FFFBBBHHH@@@CCC555MMMNNNJJJEEE666888DDDEEEBBB<<<======999<<>>??????999===>>>@@@???FFFFFFHHH999>>>===;;;???:::999>>><<<===HHH>>>GGG@@@666999999;;;:::BBBeeeRRR???DDDDDD???<<<;;;>>>444666888333999>>>777OOO===EEE666@@@;;;>>>777NNN;;;+++888NNN111333999555CCC777444:::333666???333666777***555777444;;;777JJJ111222555222+++III>>>777...+++---***((())))))'''+++)))333///---000777;;;@@@)))))))))CCC&&&&&&***111...&&&...555777000gggJJJ### 555&&&'''""""""666(((222333222///...---222:::333000///,,,+++...333;;;JJJ>>>===HHHnnnNNNDDDEEE>>>888999AAABBBNNNAAAQQQ???555888NNN<<<999777222222,,,,,,777;;;;;;PPPBBBAAAEEE@@@EEENNNTTTKKKNNNEEE>>>UUULLLEEEBBB444222///444???HHH;;;???888CCC<<<>>>555BBBFFF???<<>>DDD@@@?????????EEEHHHCCC???FFFFFFHHHDDDMMMAAABBBSSS@@@>>>:::@@@BBBXXX@@@CCCEEE;;;<<>>GGG;;;AAA:::;;;888999EEEIIIHHHBBB===sssYYY>>>===???AAA:::999SSSrrr[[[IIICCCQQQ===@@@666<<<:::DDD666999888999888777444///444+++***+++)))222888333@@@BBB???999222///111///777HHHEEE===888GGGBBB777///333000222,,,...&&&***---(((---///+++444---000///???000111III---(((...'''(((&&&,,,888***666---,,,<<>>===OOODDDGGGQQQ888000:::444;;;<<<333333;;;555;;;===<<<;;;GGGBBB===KKK<<<===<<<===>>>LLL>>>???[[[GGGCCCDDDEEELLLFFFAAABBB FFFBBB??????HHHDDDEEE???HHHRRRDDD@@@IIIJJJ???>>>888DDDFFFAAAAAA:::FFF666:::;;;===<<<>>>JJJPPP???ZZZ777<<<888AAA@@@^^^SSSZZZLLLRRRLLLAAAEEE<<<>>>222===;;;>>>999555000888...---333,,,%%%***...111888+++444888222???------+++KKK444333---===<<<333AAA@@@999000666---***(((---...IIIBBB---000,,,+++AAA333---:::888///777111+++$$$,,,+++***:::///)))'''>>>,,,""">>>$$$&&&@@@"""444%%%%%%(((+++...BBB///555555===---111444444,,,///444444<<<;;;???EEEAAAEEEQQQPPPeeePPPDDDUUUSSSfffHHHCCCDDDAAALLL888FFF:::===III^^^PPPBBBDDD666444444888;;;<<<===KKK]]]TTTdddaaaGGGBBB:::EEEBBB=========222;;;888DDD999888000>>>...111666444999:::;;;999;;;666<<<===BBBLLLEEECCCDDDEEEGGG>>>AAAHHHEEEKKK???;;;<<>>@@@MMMTTT\\\fffHHHCCC===>>>CCCHHH>>>===BBB<<>>NNNKKKGGGGGGBBB:::===999BBB333666:::???<<<>>>NNNpppVVV===;;;BBB777777444555444222666666000...111222000000111000111333...333444<<<(((111:::000DDD333222///222000222444333111444000***--->>>333...+++))),,,---,,,(((555,,,&&&%%%===***+++(((***'''>>>ZZZ___(((+++''''''$$$$$$ ###!!!$$$%%%%%%&&&%%%""")))111...000CCC:::///222666...---888555:::AAAJJJHHHJJJOOOVVVJJJAAABBBHHHNNNaaaKKKAAADDDKKKGGGXXXCCC111333888@@@wwwZZZYYY|||======AAA222000BBBAAAHHHOOOiiiwwwGGG;;;555888111222;;;CCC===888888???[[[===111999AAA[[[;;;;;;>>>888===KKK<<<999777===AAA666>>>777>>>===CCC;;;???DDDNNNGGG???;;;AAAHHH@@@;;;???>>>CCC;;;HHHKKKFFFRRRDDD===AAA>>>:::888>>>BBB:::<<<;;;JJJ===DDD>>>DDD888======@@@===AAA999222???<<<===;;;???===___dddSSSBBB666;;;777666555...333;;;---///---333888666111666111<<<555666+++///000,,,...,,,+++111222>>>333...---;;;000)))666,,,...+++***666111---&&&$$$$$$%%%///$$$,,,000+++''''''000(((&&&...###,,,333000===///'''###000***%%% !!!111,,,&&&---000---AAA---555888555<<<222...111333666777;;;SSSHHH^^^PPPuuuTTTwwwPPPRRRHHH[[[EEEOOOQQQiiimmmTTT:::...111999[[[VVVLLL>>>666;;;BBBKKK<<<888666DDDQQQQQQ 5PPPKKKRRRAAA;;;777888MMMIII======EEE;;;;;;>>>;;;666::::::GGG<<<===:::<<<666??????444444777===999999:::;;;BBB<<<:::999OOOGGG<<<;;;RRRHHHDDDAAA<<<@@@BBBLLLEEE___fff<<<;;;======888999777<<<>>>AAAIIIAAA888EEE===KKKJJJDDD;;;>>>888:::===999GGGHHH>>>MMM===EEE===HHHKKK```GGG333222333::::::555///,,,444///...)))000222,,,,,,000===999JJJ;;;...+++:::(((***(((111,,,...000111...777---******---,,,+++222---******000(((&&&,,,&&&)))'''///000&&&,,,((('''***'''%%%$$$###+++)))&&&''',,,((("""###'''$$$!!!&&&!!!$$$$$$+++(((***%%%222...---111...555111444:::KKK222...333555===LLLPPP```LLLLLLVVVGGGGGGAAA;;;___HHHJJJsssYYY]]]YYYFFF777>>>JJJ<<<:::HHHBBBEEECCCCCCccc___HHH:::>>>IIIZZZpppZZZGGG<<<;;;555555111333VVV======KKKAAABBB@@@CCC999111111>>>???888999222999;;;666222444999;;;;;;999:::777777;;;:::@@@777===@@@IIIBBBDDDAAAGGG>>>:::888JJJIII:::;;;>>><<<333666888<<<222...666:::AAALLL===EEERRRgggOOO999444888888HHH<<<888DDD666FFFAAA888CCCBBBIIIGGGJJJ;;;:::CCC888SSS999@@@000000***666+++///+++333111555///777111WWW333@@@---++++++555...444......111000///888<<<---&&&'''---******000)))***+++(((///333***000222///%%%'''%%%...'''...)));;;""""""+++&&&%%%###222---###"""!!!!!!999&&&&&&&&&+++''''''$$$111===///333+++999111111;;;333===000555666999SSSYYYEEEGGGAAAHHHCCC<<<@@@???YYYPPPMMMXXXOOODDD888WWW999999666;;;LLLEEELLLHHH@@@EEEIIIgggOOOUUUrrrEEEDDDBBBzzzWWW???333555555111888:::;;;;;;777<<<@@@@@@AAA<<<===111///555777666555777888888666333:::999888555666444;;;;;;<<<666444444222OOORRR999GGG@@@CCC???999111222111000555777666444777555444666111///:::IIIfffCCCKKKjjj sss<<>>999:::<<<888555555<<<;;;^^^[[[KKKJJJ===DDDGGG@@@555...AAA333===---+++...000000---+++000777---888///,,,,,,111999999333555333111000111777***'''(((%%%$$$&&&+++''''''+++'''***(((777)))...???GGGqqqDDD444000333...___III///(((---666)))'''$$$,,,888,,,%%% $$$&&&777555,,,%%%###%%%&&&555555$$$///000++++++...///111CCC000///555000@@@888KKKKKKNNNFFF>>>TTT888IIIBBBLLLIIITTTQQQIII777@@@AAA>>>555222777???GGGFFF:::@@@KKKdddeee[[[rrr888FFF;;;cccwwwHHH<<<666;;;===777999???666888222???DDD;;;JJJ===999>>>...555aaa444CCC444PPP888555GGG:::;;;666888888999<<<;;;666999:::666;;;:::>>>BBBMMM333333888333111000777888888888777555222...222111///777<<>>YYYKKK>>>HHHOOO444111:::<<>>555FFF000'''------000000...555DDD...)))(((---@@@000)))&&&---BBBSSS???777///333777888333***///&&&'''(((%%%)))***444666)))>>>111+++)))///888???JJJoooEEEHHH]]]000222???///)))***QQQ...333(((((((((%%%((($$$'''@@@;;;333666&&&***!!!"""%%%(((***000<<<<<<666999111//////999222222111999<<<___PPPHHHCCCFFFEEE^^^BBBEEERRRUUU[[[FFF>>>:::>>>888CCC;;;;;;===CCCCCC:::DDDIIIPPPYYYeee]]]???666999fffQQQAAAbbb999;;;999111444777---,,,111HHHMMM]]]HHH555777333222333ZZZ666...>>>...444;;;555111333:::===RRR555888;;;666666999777333999@@@DDD::::::;;;555111222555111333000111888222777333555///111222:::DDD999777KKKZZZFFF@@@>>>IIIFFFLLLEEEGGG???555333999777888333KKKaaa888444000111333***///(((+++111---......666222555...)))---222...+++<<>>@@@888,,,777666000))),,,///---***(((''',,,)))///++++++---CCC222+++***...444NNNGkkkBBB???777FFFDDD---000---,,,###$$$***+++'''JJJ000)))))) """%%%###SSS,,,%%%'''((('''$$$***'''###$$$)))...PPP111DDD;;;000222555777999111777<<>>555<<<000222111333666666AAA111555555000777999DDDPPPaaaBBB333///777???444111((($$$///111444666AAA:::999555NNN777444888444000999<<<333:::DDD<<<999:::;;;;;;BBB777<<<444///---333333000333:::000333777999333;;;888@@@666EEE\\\LLL???HHHJJJIIIDDDFFFLLLGGG;;;555444+++444444555777111///333...,,,***%%%&&&)))666333...+++555WWW111===(((111***///333;;;MMM===:::888......111FFF111(((&&&***)))222((($$$'''"""&&&###'''++++++***&&&...'''888kkkzzz<<>>BBBBBBeee;;;000444000//////---111000111///222444888111111444@@@555000333<<<:::777DDD>>>AAA@@@===555888333111111444111222777///222555,,,'''$$$'''111***...000)))---+++555222:::666222---000...555111...===888555AAA,,,CCC888'''###$$$%%%...***(((&&&###@@@&&&###***///???)))!!!(((UUUiii666:::111333***333///FFF@@@222777YYY)))///999$$$,,,)))333===  !!!%%%###===***...===666'''(((222+++---***&&&+++HHH)))***---OOO555555666777<<<666TTTBBB999@@@WWWNNNEEEMMM>>>DDDKKK^^^OOO>>>JJJTTTPPPnnnAAAEEENNN>>>HHHHHH===YYYuuuppp{{{LLL@@@PPP---(((,,,666999::::::888===555:::===<<>>555<<>>555333---777222333...222...***)))+++(((///111111///...222000777444000BBB222,,,444...))))))000666222+++000:::666(((;;;%%%!!!$$$&&&***%%%(((,,,$$$"""######)))***---(((******???...+++---777222//////111444666***)))DDD777333222222(((%%%((()))'''###""" $$$"""(((444444444PPP000$$$###222'''111(((///:::RRR,,,+++***666333333444666;;;>>>~~~<<<333FFF^^^JJJLLLfffPPPFFFKKKLLLGGGAAACCCLLLMMMooo>>>???:::AAAGGGKKKUUUwwwxxxXXXJJJKKK444///444555666@@@888999>>>@@@:::444@@@OOO???888777666333999666111EEE===???HHH---///444666555111777III::::::444fff777<<<444555777222000444444777555III:::444///222444222000---+++000///777666111222333...111111111444:::SSS555000HHHSSS>>>>>>666@@@000***444111111EEE...777KKK000000222333+++000111...555---777======666777---+++...,,,+++222......---000888---(((%%%"""******&&&''''''&&&""" ###%%%"""$$$)))''',,,666<<<;;;666+++AAA:::>>>///333777222222999000999((($$$$$$***+++---DDDUUU$$$"""###VVV<<>>333000888@@@NNN777===666IIIAAACCCKKKKKKFFFGGG\\\XXXKKKHHHIIIEEEHHHEEE@@@<<>>666888777>>>999000000III111111666:::666111<<<555IIIaaafff---///>>>444777FFFEEE444222AAA666)))000999:::555555444///,,,+++???222...---111111000111000111///222555kkk888000,,,111000000222888888AAAEEE;;;CCC777777jjjPPP999888111222AAA???NNNHHH>>>444222111444III,,,''')))LLL444333<<>>LLL///)))444111+++(((***000)))888---$$$'''###$$$'''%%%$$$(((((($$$'''&&&'''888UUU--->>><<>>CCCWWWOOO^^^===;;;LLL$$$"""'''***222))))))$$$  !!!999"""%%%666111111---$$$,,,%%%&&&&&&$$$"""...777'''""",,,,,,...(((444111777CCC:::666333:::===AAAKKKAAAxxxIIIPPPJJJEEEGGG\\\HHHKKKhhhbbbDDDIIIdddUUU'nnn[[[iiizzzCCC;;;CCCJJJ___OOO111555777999333555:::GGGMMM///---GGG333444***,,,222111:::222888WWWccc444999::::::666BBB999<<<333111999555---222;;;;;;666555///***(((...---///......333222888444;;;......000999,,,///111---...111555///;;;GGG555EEE666666IIIjjjCCC555000444444;;;???uuuBBBBBBCCC888444111111///000,,,999&&&***---000+++---888+++,,,@@@999777555222000222???///((())))))000444((()))$$$777@@@(((###+++,,,+++&&&222>>>)))000///OOO555***)))###///111999???TTTGGG666888---111$$$,,,$$$'''&&&&&&   &&&&&&)))222 ###'''+++"""&&&$$$((('''&&&+++333EEE$$$'''%%%---333333555888FFF>>>UUU111<<<@@@BBB@@@???EEEQQQVVVJJJFFF\\\GGGJJJEEEGGG@@@999CCCBBBJJJ;;;[[[XXXLLLWWWbbbUUUFFFHHHOOOIII666666666999333333777===222444222444NNN444...222---333111222...rrrmmmBBB---000BBB666333333===:::???:::444555888777<<<:::666666555555000000///......///222<<>>---...000...555666+++000,,,222,,,555111+++444000''',,,RRR444GGG555///,,,777111&&&???---)))(((%%%'''---222000:::666...OOO:::444<<<***###444000999444CCCIII777...000999555LLL...### ###;;;      +++)))###000...%%% &&&,,,***$$$%%%''')))UUU444...%%%$$$&&&$$$:::---,,,...:::777:::777888===???<<>>CCCEEE@@@111444???NNNAAADDDMMMTTTGGG```QQQHHHjjjAAABBBEEE***555555111:::<<>>///<<<+++)))111---222444666,,,222///'''%%%'''%%%))))))+++)))111999222ZZZTTTRRR999---888JJJ\\\777,,,***""">>>LLL666///###+++NNN222+++---###    <<<!!!!!!+++((())),,,!!!'''%%%###)))*** !!!###%%%###***,,,***///NNNVVVAAA///777>>>999KKK>>>???:::===HHHLLLEEEDDDAAA>>>OOO@@@OOOAAADDD>>>AAA777XXX666AAAGGGVVV[[[MMMSSSZZZTTTIIIVVV222888III---444555PPP===777333111KKK---......333777:::>>>...444666CCC000+++555bbbOOODDDVVVEEE???777@@@GGG???555000555333TTTVVV===<<<666DDD777<<>>???===;;;;;;@@@===222+++......555222666888555444555III444222*** %%%777777<<<555HHH888CCC888777888444555666;;;000)))******,,,+++444111uuu111222>>>333...,,,000333+++444777===333;;;222111+++***,,,111******111;;;UUUOOOYYY___999///LLLHHH///,,,CCC+++555''''''000000---%%%QQQ$$$---GGG&&&###   ---  %%%"""&&&MMM ---'''***))))))%%%'''$$$(((&&&$$$&&&###&&&,,,)))...KKK666:::444111777:::444555555@@@JJJ777:::>>>AAACCCCCC===JJJCCC===FFFEEEJJJXXXIII555999===<<>>@@@444@@@999EEEHHHYYYppp\\\gggDDD>>>:::@@@444AAATTT{{{JJJ<<<+++,,,,,,///;;;///999___333...:::555666555444===555111222444000......(((444;;;;;;777;;;999777FFFCCC555555...111??????:::888EEEZZZIIIIIILLLVVV}}}GGG[[[@@@???888555666;;;DDD888555222222...777444000444000555BBB:::|||JJJ111222:::333888;;;<<<444kkk666///888>>>:::444555///888///111999===???777,,,***,,,888999777[[[qqqGGG999555000222---===***,,,,,,'''///@@@555444NNN}}}SSSAAACCC[[[:::??????000;;;---333***///+++EEE333AAAMMM000***((($$$"""QQQ,,,  666   !!!444999555:::333000$$$$$$$$$ ###!!! !!!$$$333+++,,,,,,***)))''',,,222:::333666111;;;555555OOORRR888444888555:::???===888;;;CCCBBBFFF^^^uuukkk]]]HHHNNNEEE,,,<<>>999555UUU777)))((('''444fff```]]]-oooCCCBBB---***444(((222CCC444$$$''''''444666III888======555...111(((333***+++...'''***+++WWW666:::---999JJJ===@@@222...---       """ """###"""BBBGGG000000$$$ ### $$$"""&&&)))+++333,,,&&&,,,222000666222666---111333444333>>>;;;444333555666444999CCC999BBBFFFBBBNNNnnn___YYYpppVVVXXX@@@222777444;;;<<>>111///...444000555:::///666555777:::((('''(((EEE===XXX\\\VVVFFFAAA222333(((...!!!&&&888###"""CCC------(((111NNN444;;;'''(((%%%...&&&%%%...###%%%%%%***@@@III)))888cccDDDYYYFFF@@@((( ,,,  - - -   %%%===))),,,$$$777///###$$$!!!(((PPP%%%%%%777---++++++222///+++&&&)))...///888GGGJJJ---222555;;;444>>>000777@@@BBB:::@@@YYYGGGXXXyyy{{{PPPPPPIII333111---///333...666///+++111555999555555555666::::::<<>>222111///+++111>>>000///999666...000000000777GGGSSS...+++777(((%%%:::444>>>AAA888AAAHHH666333###%%%!!!### ***(((!!!,,,333TTTPPP%%%---uuu%%%$$$&&&%%%)))%%%FFF000***...XXXPPPSSSAAATTTiii>>>777    - - -  - - -  ///--- QQQ"""--- '''%%%$$$###&&&"""$$$HHH"""'''...(((&&&,,,111333---///******///666555jjj888333333777111===555;;;;;;===999???MMM@@@EEETTT___WWW~~~HHH@@@;;;+++""" """222;;;333222222---333222777:::BBBPPPGGG777SSSPPP777777GGG666<<<999???QQQ:::@@@777666777888EEEEEE555???FFFEEE888222===OOOmmmeeeYYYVVVqqq - dddVVVEEE777999999777---///000555:::111///...999888@@@FFF;;;EEE:::>>>CCChhhIII222777777UUU<<<===333999;;;EEE000555333777999...///333CCCXXX000KKK444$$$***)))222DDDJJJIII???@@@444///'''$$$""""""###...$$$***&&&''' ,,,aaa$$$ ---$$$000""")))'''666,,,+++GGG+++DDDCCC***FFF@@@***"""!!!"""      - - -  $$$"""888222"""'''+++!!!"""###""""""$$$###&&&###...))))))(((NNN;;;...111+++000444333888888777......777111TTT777222333555===333888???GGGmmmUUUcccWWWTTTNNN???666<<>>\\\pppRRRIIICCCDDDXXX OVVVDDD999888888:::444000222000555666444999222BBBCCCXXXFFF???:::<<>>333QQQ555555MMMKKK555444000000000111???111FFFKKK444:::EEE444222444***---,,,@@@444DDD444,,,444111---&&&***$$$!!!"""%%%!!!"""!!!!!!000... )))&&&'''000...&&&+++&&&***888...,,,$$$&&&'''"""%%%&&&     222//////>>>!!!!!!"""###'''&&&,,,)))111 !!!'''&&&$$$333***,,,---111444:::+++;;;444999444...333;;;777888555999777444KKK999FFFhhh&kkkKKK@@@GGGAAAIII777666555111333///444222666...000,,,000000444999lllEEE@@@===666III777333777>>>BBB;;;777999@@@<<<:::<<<<<<:::BBB>>>:::999AAAGGG@@@888444AAABBB@@@??????UUU 1bbbRRRCCCHHH555HHH999888000...///777444;;;???:::666BBB@@@555@@@777:::999:::888111GGG444888666666555000888777666@@@@@@JJJ888@@@888555@@@AAA;;;AAA666;;;111000---333,,,...222333---***%%%)))######!!!(((000###%%%,,, ((("""(((&&&%%%,,,000000,,,MMM777,,,555$$$!!!!!!000 )))      !!!@@@SSS:::AAA 333'''"""%%%"""!!! ,,,###;;;&&&###(((&&&***,,,...///333444111///,,,111---444---777;;;...QQQ@@@:::999888:::BBBCCCQQQAAAHHHOOO999GGG>>>555444666777888???HHH333111111111///555888333///<<<888999666222UUU:::DDD<<<@@@ccc===<<<;;;999>>>@@@:::666555AAAEEE???:::AAAQQQ<<<666;;;;;;AAARRRQQQCCCDDDgggddddddAAA999BBB888777::::::AAA555777:::===HHHOOOMMM>>>@@@888===;;;999;;;000888111666>>>888444///555UUU???:::<<>>HHH...333999555JJJ444222333222+++...000333DDDIIIBBB666888999;;;===EEEGGGNNNYYYEEE;;;QQQAAA@@@888III<<>>;;;AAA:::BBBPPPNNN;;;===VVVIIIAAADDD777;;;<<<<<<<<<;;;444KKK111,,,888999]]]HHHEEE<<>>AAADDDFFFDDDBBB111,,,666000888222777...))):::+++BBB222,,,444111111111...GGG]]]bbb>>><<>>EEE<<<888AAA;;;???@@@AAACCC???>>>VVVaaa111333444888;;;444DDDIIIEEE<<<===RRR555;;;EEE666555000111>>>HHH999111555>>><<<@@@999888222zzzFFFRRRUUUeeeZZZFFF;;;///222888111111)))+++BBB666+++111%%%%%%***%%%&&&######$$$$$$%%%)))(((LLL&&&%%% +++""" """---"""    777444OOO888###%%%""" ///!!!###(((+++"""+++------BBB===999666)))333999\\\UUU,,,))),,,&&&//////444999===MMM???WWWKKKDDD===;;;CCC<<>>111666LLL222000///***;;;/////////555>>>>>>GGGMMM???FFFAAA888555999999:::OOOTTThhhQQQ///---000888AAA:::???:::222666444HHHNNN\\\<<>>>>>FFFEEE888333999SSS;;;:::444<<<===<<>>;;;<<<:::555999<<<666bbbRRRHHH333333::::::>>>DDD333777555444;;;DDDJJJAAA999===AAAIII...///,,,222999888<<<555777555555777333999777777===999222777444@@@===666@@@GGG---999222222<<>>444777---...222...&&&,,,---,,,;;;,,,DDD===+++lll*** !!!""""""%%% '''###'''"""###### 555111%%%!!!$$$%%%$$$!!!  """   """(((333___---###+++***"""&&&$$$ !!!)))'''===VVV>>>000bbb\\\===SSS000777///,,,---111...AAA===,,,&&&;;;&&&$$$777444^^^;;;RRR===DDDFFFBBBwww]]]oooCCCdddooofff<<<;;;777222...111111111UUU<<>>>>>777...;;;222111///<<<>>>666;;;666777444666444;;;,,,///222333777===:::NNNQQQ666222444888@@@222:::...333333000888???888999IIIAAA999bbb>>>222888777KKKIII:::<<<222...888555XXX555AAA\\\QQQIII555999>>>444111***''''''...'''(((***222''')))000AAAAAA...!!! !!!%%%:::333$$$666111888"""###!!!&&&NNN000***)))***$$$$$$%%%---######(((###===        SSSYYY((( +++ 555)));;;eee+++)))222222UUU<<<333------...EEE000555222111777&&&((('''"""555111;;;---<<<@@@666333HHHNNNtttIIIOOO```mmmhhh:::888666:::000000---III???...,,,JJJ>>><<<888:::444000+++,,,000...///111222CCCOOO<<<555888EEEJJJ666<<<888000+++555444555666......000555,,,222:::666//////111///111>>>777444---222000555888777GGG444222555555222BBB@@@???555:::666IIICCC666777DDDTTTHHHDDD444666...333OOO;;;@@@>>>777AAA222999,,,777,,,///'''+++...YYY666555FFFSSSKKK333555yyyBBB...+++&&&***###&&&EEEZZZ '''111,,, &&&222&&&***&&&---'''LLL!!!%%%'''JJJ111FFFBBB999CCC---...'''"""+++    ***)))CCC:::888(((&&&kkkrrr)))***999'''666CCC333(((---222333000---222555...222%%%***"""---666444///888...---///BBBBBBIIIOOOFFFiiiyyyQQQ444+++&&&111000333111)))666///---EEE999KKK<<<---333999///......111000===CCC<<<666777777bbbZZZ===---+++***...333'''222666---:::111;;;888...000;;;222111222333666888000333333777555;;;444999999666===???>>>@@@999CCCAAA???@@@===<<>>IIIHHH444CCC555[[[SSSDDDAAA666+++###'''+++:::CCC<<<--->>>++++++---111'''+++...AAA---,,,,,,333444:::...222333444===ttt KKKGGG444***)))&&&'''HHH:::444:::999...---///)))(((---444+++444666222777...111444333777999:::333777EEE666999<<<;;;<<>>DDD999111222555@@@000111,,,;;;111++++++000+++555111&&&###)))BBB'''***:::...&&&(((***777'''...FFFIII<<>>,,,""""""333%%% 333######111111///OOO------JJJ[[[IIIooo.8|||UUU<<<888$$$%%%       %%%000$$$###GGG"""$$$!!!###%%%)))NNN'''''':::>>>III999JJJ1|||:::<<<===<<<+++'''!!!)))---***---333...EEEMMM...111LLL444111;;;000''''''$$$111111***333000000%%%+++(((***111((()))***'''000999,,,...444111LLL///555222,,,444KKKvvvTTT;;;:::000''')))&&&+++777777***++++++(((...444///<<<222000333...222444111333000///555555999///:::>>>888[[[>>>HHH888kkk999:::888;;;:::666,,,444EEE666111999...111&&&$$$666666''''''(((,,,&&&,,,AAA)))&&&$$$((('''###'''!!!''' )))AAA<<<;;;***<<<111***!!!%%% (((%%%$$$"""222*** ***!!!333"""+++,,,!!!666===FFFBBBDDDFFFXXXAAAVVV"BkkkIIIDDD[[[444OOO!!!      '''!!!%%%  ***'''!!!((('''$$$$$$888+++777GGGVVVZZZWWWIII666+++&&&$$$'''!!!"""$$$ %%%+++''',,,&&&***'''===333MMMRRR111555AAA444------***)))++++++555000...***%%%$$$%%%'''(((///)))'''000111666+++...---'''***+++111222:::???222444000&&&***'''%%%******///222---///111,,,+++,,,---000///222:::===222444333///...///444...;;;888@@@<<<===888FFFHHHDDD>>>;;;666555777]]]:::333999999666===EEE555444***(((%%%???###"""111???%%%((())),,,'''%%%"""######!!!""" ###___000###999,,,111UUU%%%)))&&&!!!&&& !!!000--- """***EEE&&&XXX((('''???000444;;;eeegggYYYWWW^^^]]]-\\\|||ggg)))!!!%%%   ###$$$   ///PPP$$$]]]888###$$$'''000333333&&&***000:::___ cccVVVNNNjjj999GGG,,,666,,,""")))&&& (((&&&'''(((+++111---+++333<<<555---+++***(((222<<<((((((!!!"""///+++000///,,,)))###'''(((...)))$$$---+++```+++222---111+++111777999$$$###)))(((%%%((()))***&&&&&&,,,>>>$$$(((III---000,,,***///---555(((***''',,,444---111000PPP444555555<<>>;;;ZZZ999111WWWXXXCCCUUUAAA555555///OOOgggDDD222...000&&&+++,,,///000:::GGG)))%%%(((+++...444###&&&$$$###$$$$$$!!!###555(((!!!''''''...888DDDSSS+++&&&+++777>>>111444 (((555###%%%###!!!&&&vvv///GGGppp#yyyUUUYYYPPPfffZZZpppOOO444$$$---&&&VVV&&&))) '''+++%%%   - - - ///!!!$$$&&&DDD,,,&&&000///222...###***???999lllhhh{{{NNN:::iiinnn...333222+++''''''$$$!!!;;;FFF%%%$$$&&&'''HHH***,,,<<>>***,,,---&&&---PPP(((&&&333444888@@@111333;;;666<<<444444;;;::::::???>>>ZZZSSS]]]DDD888BBB333222???<<>>$$$iii"""***%%%???CCC@@@&&& 444'''SSS''';;;444888111@@@<<>>@@@888555@@@333555333$$$++++++(((###!!!%%%!!!)))$$$(((((('''!!!(((---333!!!!!!111$$$---000222"""===(((???===%%%***!!!$$$ $$$333((("""###&&&""""""###%%%OOO(((,,,AAA111&&&@@@,,,///GGG111@@@     - - - - - -  AAA!!!%%%DDDCCC///(((""""""!!!111RRR===---222000SSS\\\LLL666TTT)))AAA===DDD%%%%%% &&&$$$%%%$$$###'''%%%$$$######'''%%%"""&&&$$$***'''((((((###///&&&'''$$$&&&222111######+++,,,)))###""""""!!!///...+++"""!!!"""&&&/// """***!!!&&&(((&&&"""'''***---EEE---(((888000,,,''')))---666AAA===^^^JJJXXXtttoooSSS555,,,+++000///>>>VVVmmmIIIMMM333HHH666444)))'''(((111 !!!###### """ $$$"""!!!!!!$$$&&& !!!&&&"""OOO"""***@@@333===$$$>>>)))### ###///(((fff###<<<111...--->>>!!!###$$$"""GGG%%%&&&111CCC'''---555'''       !!!:::rrr!!!!!!###!!!(((III777000---(((***JJJGGG,,,///...,,, ###!!!$$$...###!!!///%%%)))###---!!!%%%###$$$$$$###(((&&&"""&&&,,,(((***(((666TTT###$$$"""222)))"""###!!!###!!!!!!"""!!!???%%%!!!$$$!!! !!!""""""###&&&&&&(((&&&///:::DDD???+++(((:::---111888666:::kkkuuu|||mmmddd777222222%%%,,,:::)))...555...333222<<<''''''(((###%%%$$$...+++,,,)))###!!! :::777***$$$???111444<<<''' %%%'''444 ###HHH???!!!''''''000,,,'''***<<<%%%+++!!!+++     )))...XXX<<<(((777"""!!! JJJ:::999((($$$&&&RRRuuuYYYBBB+++!!! 000&&&!!!+++"""$$$"""***000!!!'''$$$&&&''')))'''%%%$$$!!!$$$"""$$$###!!!***%%%@@@&&&999kkk"""""",,,(((!!!!!!((($$$$$$*** 111$$$!!!...'''"""!!! !!!"""%%%777???>>>vvvSSS...222000999999888444444}}}% ggglllOOO<<<---,,,,,,''':::,,,$$$###!!!)))444'''---888%%%,,,((((((((('''$$$$$$!!! ###000!!!999PPP;;;777DDDOOO+++&&&  (((!!!"""000'''++++++222&&&(((       '''666111444...###!!!444$$$<<<000HHH999777$$$'''$$$+++...  %%%666)))'''333%%%$$$(((...(((((('''!!! ...))) &&&""""""'''%%%***%%%&&&$$$******"""$$$ ''',,,&&&!!! """!!!EEE"""### ### ###%%%&&&!!!!!!AAA))):::'''***%%%...444***---+++<<<<<>>999999..."""+++555PPP555YYYMMM888///(((%%%&&& """&&&***+++$$$"""$$$---***&&&###111+++%%%!!!'''###$$$((('''+++%%% !!!&&&"""%%%  !!!$$$((( !!! ///!!!"""JJJ''',,,''',,,+++111NNN555XXX^^^XXX???''')))***777999@@@)))###000((($$$III%%%''''''666 ((( %%%777$$$"""###)))"""!!!)))888///$$$!!!"""      BBBMMM... ,,,&&&)))rrr&&&666!OOO---%%%!!!=== (((%%%"""$$$???222---FFF111888<<<111&&&,,,$$$((("""$$$ $$$(((&&& """%%%### !!!""")))###&&&!!!'''!!!$$$***''''''111???222>>>***%%%888NNNddd]]]YYY'''000 888MMM666>>>+++,,,;;;000!!!!!!333%%%%%%%%%---***###000 %%%'''  - - -  - - - - - - $$$aaaSSS222 $$$""",,,***^^^)))888@@@EEE$$$)))###444 $$$,,,$$$%%%###******$$$%%%333CCCSSSBBBEEE000### ###"""&&&&&& ***!!!%%%555''')))""""""### &&& """ ...  +++!!!666"""%%% %%%$$$###%%%|||DDD$$$###,,, !!!&&&***===&&&!!!PPP!!!***$$$<<<%%%!!!222  VVV         888HHH...$$$###&&&777)))!!!$$$BBB((("""(((111"""$$$""" 888###$$$$$$###111^^^CCC333RRR !!!%%%!!!!!!&&&!!!### ,,,333888333)))$$$!!!&&&"""!!!"""%%% !!!!!!"""---"""!!!$$$!!!!!!444!!!### ===''',,,eee)))555 $$$&&&!!!(((--- $$$ 222)))!!! ((("""  - - -       )))***===MMM333???$$$"""---***000***(((######""" %%%!!!###&&&(((&&&$$$$$$'''DDD666...///NNN$$$###!!!$$$""""""%%%!!!### ***######!!!!!!(((  ))) !!!!!!+++JJJ""" '''!!!'''&&&((( 222((($$$"""!!!### """   \ No newline at end of file diff --git a/data/fits/NGC3344.Mono.8.fits b/data/fits/NGC3344.Mono.8.fits deleted file mode 100644 index c84ac2c68..000000000 --- a/data/fits/NGC3344.Mono.8.fits +++ /dev/null @@ -1,12 +0,0 @@ -SIMPLE = T / file does conform to FITS standard BITPIX = 8 / number of bits per data pixel NAXIS = 2 / number of data axes NAXIS1 = 256 / length of data axis 1 NAXIS2 = 256 / length of data axis 2 EXTEND = T / FITS dataset may contain extensions COMMENT FITS (Flexible Image Transport System) format is defined in 'AstronomyCOMMENT and Astrophysics', volume 376, page 359; bibcode: 2001A&A...376..359H PROGRAM = 'PixInsight 1.8.9-2' / Software that created this HDU COMMENT PixInsight Class Library: PCL 2.6.1 COMMENT FITS module version 1.2.0 ROWORDER= 'TOP-DOWN' / Order of pixel rows stored in the image array END % &%## #" "#&!- "$('8*,(&13))/3,(*Ff0+/21NeRTtbE@O5Cp?*1.1+3/3-.*6)$DM+/,+,+//+'5../,4(012/.,.4<217553236:@6977V38;8352=4=2719723>136;4463.50+.-(/>=,:;S;8O6SVP=IDA2*+18'(%%*%&%$&$'#  +(!"!!!#"$ #'%/#%((&*'>(-3-1b*56$#%,+()09KBDN<//6@95-2336:4'':1/3-PC?KLF=JGCIM@AG@C:81,.-/1)*/$0%(*%(&$"!!':( % "!&$! 6*'&"! #"!'!$2-(-,&/4/3+2+,%><'+3%$++//6LW309KU=I40../67(+,.(+(&%('*+31/-++5()-'+,0.-///>95057672.0.443<==:=GA?2+-:>G36:>78:LcVKRPTC=`BP7=/1,/,+K%%','10%&$ *(;= "#4$"6$#$+#:"!" ,=(,/%+((0+/A181<,*8*5$(%)0*0-3=845C3!-)()($247JR628)% #.:-0-2,84-/475?D3-/1+()*,)-1033(62(&(4Q-(*('('++**)-/56N8::667?592-/149<76:>^CaA??DOHA8AJ:>/=[BUD:N;55;7ECJQNQMHM\KM@CW:KRb460*.+1&*")*%%! ! &!&!!((-!'$&1 $ 0%&)51($)01**&)FDm{V5,(%&!'1L*5.0+4/,/29721834009--+111H55+',*'(+'*1('*)*+.*//,,43-473465;2289?59<6589VNJTMGMBAA@GH3.3HFHCQ]>-3@:3:@bVMW`SPHQOCDBEM[R:011/3(0,'*+$'$'# !F!(! !)"%#% #0$8**(-*@k;5'/))/.-3Krɥ`/*'%"#'12..-.1.)/)/2928BK51+5//0),4,*+)&$')'%%-5''(*.+/-*010301203005842879?9F9853?MElRBECABOJ9499R]VU\D76MA56>XMHUZXbR[SRU^kQMG=2.-4+*3,%')$""#''#(/#=!2?Q"!0#& $< ","'C/6A2-V+*'//).B'+,10C_m=0+($'(+.6+//3:/+++07DJEd842-+(+.%%,++*$-*71H%)*++&%)-),/0.,/1/425020224C9;:D>68:7:4:;MCXLAD?B=AFFF8HzGFNnC01?5?ODIKSWi|LVBkgGHCLR3170/02#%%"!'00'#!/"@( -(& &+2# )*&CG%,0>4*(('*1<*7I/C2*:ZPR0+)1-1,*0.30-?1),1++07VS>2.(((+;+)(+J/&'&+./,%#(','(*+--,0-00/*/0316340K35;8;5>CH=15;FMhDBODCAEU;A0,9c\RRPYhXPCWjE>A<7<4A13/2&))('%# ! ")%O !+W1\((#" %**2='2&#+-15'/.7,-'+F8051K?72@-:A7.3&(+-0E(.8./-*& "&%/0FioC.08-*'*3*&+09,./*)&'$%&+:&(,,+%---,+.0./.085955;17878?@?;:49X`DVGDUKAQFD:=9>EqMI?@=F;:LJDMPSbUJKnPYYXWCGDA0/8E83*)(,*(> #"$$#!* '"!.2'R22$"- "!!-*#&$.7M$%&=/5.1(,.-.B-236++J99(+213.+(&-/2(/0//,+)$  !1=08p@*2-(11#;D,-1;04-))5/(''+,*,)'+0/*)++0*,./027_i7XD737===;:4>C?CD2"#"#%"!!.%,,#:  %! !&!"&))CQ5DT7.8Q@='23+.:d2((*(0)*(.A40/'$'$*,:,*,,-+,-%& !$*-+&F[*$$%))-10,1,17*+&-),+)&&(&'+*+()++,*0.+02758<;>L=93>:;8<99?<@>DADFPDF?GHD78In=BQ]<23JDCisHHBFGPbXukA;F>@:2:?8/11322'&%#&"$!!&# !  & 1-$%0 %# $&*#+2!'#"5*5+8C+L>ABN?.)%#(8J"!(%.&# +((;Q)$''*(2*,/'*)"#%$#&*%&%%&8()*(%07602(21<+)('7,*-*)''(****/-,-././..03389>9:>=A;5:;:;4=:PBAA?I?EHGDD?=BDI_P_JHIUS]onKB9:ABI=<:.262660,%%(*(=!  &.'!) !%,%(%$#$9"%9&"-026+-62;Zcf.?*%#")& ! &-$&'#,!$)&%A&*1@)/)90**)$&3,%'*+*('<$%-(/,153-.+9+9+-+%)3/*+&-42)(,./*..1.2/0.-0/2R6QJL;:<:898;5887?@:AHEGTPM@E<7;BGHII>>;??<;SLTlR[WdQTLIG:6>=>:454.-03<1%'')+&,-$#&!#$"$    (5'">/) #! ,+#0.#.0(-/14/.5CX_7980--+%""!%+#$&#$%'(*,&&&.FZ)+)?&$&0*"(/&'*-'&'(&'&)+4,/0;.).:--'(+0+.4,2*..++*+07/654611,,.2731::=L<<;:;<35764CECAC?AKJLs;87HJM=69VcY[p]XNKF=5<=626/775-.32*%)%'#!$!!#!" #$ 'D!$# /!$0 !!## ##=(7,421/0687817R:71:/*(%&" #(#!"!//,**/*&--1*,(<''&I'%&'B())'&(((%,&&)../,-+56;*90)-+-100/00.2/01;1:1546/,,,-474.3Ux>==>>8:<359@FG>EQFALIDA<>=dPWJ=?7<10/5A2.,/-==9)%'$$%!(""##!$' .%&!#) 0 /&)I;&")+'8$&-*/71B=;F8L4;?@86/+1+2&#(/0#$ &(')"%*)%#'*%'()(),&&''2$&*(*+-,)-X)3,)A1-'')'1r6-.0,1-2G/090..349567123@1551399433=G857=;6==64:9;A?P?GLDEMC@?=@@EAD?::;==81'#LQPhOROY@BE=D9/0=5..;4+,*;1+*$')')>&+$"&##*5:"(  >:  %#%$O$%!!)$$&%+('.?35@8+-5YgLG@80,-/("+*-0'%)-+&!"*(&))+(-*$%)("',0**1'&(''*)/3)&.*,&&+*0-12/+.2/./982/*25317;759:313147530721B:787::@9955<:6DLSGF@B@MEE?B;.,(&'%)'",%(/"#!!! %%<'%&%)*1)_'&%$%   *$#%**2(..;DA3241]cL:J/+-!,%(2))'),,8($ &*)*'a)($')&(&%&).212+($*()(*'***)''(./56/31,..05.-/7.35/051/8.699::25FEBA>?R>FC;:>=<<=774Ghpz_YWSMHG?8599676911@,+)#('''(%%$% $%)*  ,,!!!$ & "#($(/'# %!$&)#"!'0.)&14174TWIoզc?-12&',4)+(),(*,*).%'$)(''((&#$'*%'(''"&+((%)()+'*+,,+(*+));0,-//.,-/984.1525A:42/5466AO59;:9796=><;8:77@<;E=<@I;>>:?ADGA:EI@=BB=>?BLJCA><=638@^x[PP_[RVNF>V;6@=FkE4;U/0+0.)"%$6W.%!)"#" ,$!  '# "%X/+'&Y+)!'""7,!O!$"$!)0'13)&)#6EJnX928.)%*2***82-*)((&5)"%2)'%'('''$(&'*+*,+.-%(-*/,&%&--)-7.0>011-232/3;<>82940?834358517<:@;8>7?=:<<6<=:5:=8;H=DE@<>G@NCZLXO?ADDAE=;;92305CDRUTZRoQGX><=:=53616F.)-(10''&4J-&)# "'$((%#9 4!s !&91$" !'+"&<%'#"('h5$&"%(JM}y_3820>5(-**)-*.,,'(&)'!&($(-6)*+(+.'0+-.-,.+(,,,-.'+))*,,,0C72.98?95494??=<=58K289:4:6/55=>B?L<>CA=BPDS?C@>E@=?::>>=;9./6DRVjZNRPLLZ9@D:9<5400)/3-,37+*)0%.'.%!$#  %),**%$!"0*,#(*3#% $ +##!$%!#"2""#%%&%$&+",;MdK2=F433,(2)1/4.10.)$&((**)-+(+./*%*//(,/.-,,10.1-.++/+-*--/5401.4.032458@5639;?74=A636029;R<=ATC75=>>89889:989O>>HE=>@D@;=BD=GILCBFDAE?;=?BFA99;38?QHCNgP^G@9A>?:84./,*/,..1@96,2++'%1(*.>!$D)$%'*?W '!)%"0"#!,%'!##"#!('+$ "!##%,0/50@TN65984==;8B:8=<:;66;BAA@A:D8@>@?BEIED@@@A@D@?HH?;8:=A:JAK[bSF=L=JIG@:8B3//5/',G6+@@0(((/-$%$#%!07 ""! //1)%"#"4&% "#/"#  '""5#%"'$ &)$$#'+*&9ANVJIF;.9623/*0/7.)-+#)'-(*--*-2-59.*0/3-/...+-*;/1.+-..1-0/-.022/3,/.712389j@<9B=844-9411F:66@=C853638@A:B:987:867DDCAE:685?A?CPPCBAAACDEFKA@CA@B@@:G^_QiPAF>8BD97:7:KZ@>:744DCLJELLHTHBMJ[BN75841512-->35H;93)"##$#$$NI,G2-$%/ *$IF8!"G(&F$!#'##'#,'%#%&)(+)&4?HjaM6;6P?+(/0-:/5,.'*&/=8-,,17D730482-1535644B797H>8D>8B?835874412/969E?9>85DUQ:640<4413696>;=56B>>26D:F@F:7<;>9977>>=<@7::::@?HLHM>?@9C413411447:;G656<.0/61166?586BG:>:D9\?CN;==A;<<98B@><;;@?@=IEDGHNB?FAEF?DBQG?@>DZJJMEHGM^iaQOG:658540.+0-/T\3,$+&,%%" !/'$1$#("#!6% $&!"#$!!7!21+! $$!% +"")##&)2%&$%)&"#44?VsaXC5;6<74812-+-4B0/4.305541-.-333BA>8987694<9>=:Z=8<859=;654<554368323369452?B;4]JA750436/547:B<;:FB;56878285i=8:;:634H2412AE62;9<>H:79=<5=<@BJEEJHDBAGEEB;AGGGD@?@:9<;9:9?7;@758:95W87568=6=@>@5976465120.48RP=?3233-50157IFADB94<9:8=@547S:45=JFTJ]bN@G@=BEC@C??IES9>;7,0FCQZ[xQQQB>H852/..,-',.&*3*( &$%!"(%!'!!"++-$*'276!!!'$ +""##$!% "$$"#".'4-:@PL;@VQA3439F75347322;)-/10,*9;72355A<@AD7?B;:@:@@557;;;7789>BC><896:9B=;=888586241198G;Co=02C.1217;98AR1049:OCH6=?:>DCCB=DLGHCB62/33?er^VEHH;793@2-*)'%))(-+'(*# %'&)$ !""%(*$0F**$ $($ )*! "4/!)*4'(&#! !$#'+,((0=,:4KXCQ:H??E<9305502.1+0.32/3355;>YD>=?B@;6;=?;=B@:>;848?<86997547948<:>@:899:245@L6<>5:A;4::=E`993LDY?018;68T7:cFDCDEBCAC=?@@FCCELeM[;/+0/0beyhSF;H93433)6+)(0$&-+-#,')''%$&##%'//*R6)$$& -) (%$4.<$"&$) :%!$)-# .'&3*$'(%*/'.9G]A986[@?U6795487745388<6;DA<:=B=><>C>:ED>FA@@A@>>BABB<:<;<74Q6<5887=78<7AH@UD9;67;62445;@;A5;=C9<;;7415:6.-'*$+4#")(3((,)&%%"$$*# #%&5;K32)$+ ! '( (I:"!$%#,$"!.-)##  #&0("%+)$)(,7??G_:778B9K84>D21543@659=AC@BD>CDAGDF=><==>BBHDNKBHBHLB=@EMC>B@;>;:;4377557<:<:>9FEO8E89;:F3769569>8><7=H=/17;6@<6ND:7:6;<49?BDA?D@FLCEDIAGAGM@49@1??EaHFPgOPFA:>;341+P1*2**')()-*(%1%'(380%$%&''O~7&+#% * -'9$9#* ##""'7>421*"" ')&/%*'*(%((++)/.//33G`[8E;9<661:7=9@K:>==;=:>8778:7<6759=H=:;?IEDE9:3:;[QB7=;6?J992@36:;9;99?D>>=>>@I97I?BA=BG@EAI;768?385;G>=<;EACDDGDAGDMLSJRJI[HiOGKGQNLNJSOQIUOUWIABDFE>GAD>BC======>@7957=FAA<:;CAC7<:=>MU==;;=A=;66?:?69<6;?><8@BCB@=;6:9:;>FF@=>D?=C>@EDJHDIXNG[Ur`NLTGNGNSPORQDGHFHPNJDHLKGFABAA?B>?=?EADC<=:9CH\NDCC>A?=;:EFDG>>@8:9Q;@8><;F=LKDZlBAF@DLR=8?B9BF=BC=5908-.9-**+/+((#%%%!''(?,{B" "05%%#1"#!(.)$ !!!!#!13)3$,)0%#.'&#"$ (%/-572<<@MHF<:AC;@KH?<:??]D?N7=9DCDFKEKKLSLgWCABQLNMVQKNcHLKGCEQBA?HPTLJFGGD?BBLEACJHGAB<>?I@<=JIBD@>FEPOWGLHIKFF@?=<(08859EGKFA:<9:2/1>14/.))('.&! !$%031<(#!!%.-$ G##)9 !"%#$O/4&)($$&=@(),&#&)*%*,.@;36=CJJ>_[OEA=99A@DAGO?CECACAXPjN]NWPJMKLMOYXOPTNPKRJB?CLLOCJQVQWJdTJPEGFDGIGKRIHEHBGFGGIGJFEHIKIMEDAFHJ=>;@<<9CB;@A??DRODCGS>;86EKFCAA>BKMKGTGHJCIB@AG("8C?9=HD@D>>;?4/6642?))+7'('$&#%$ '%%+:U)&+"%#!("%)) @''(6#'  $5#!+)(.R(''.%"$()($2;=Y557@C>HI:==?DBDRRPD@BDULEL\LRGMMNIOTUQR^TQKNMQN=:J]fFFPU\YSOPISQSLHIENLOEJFFJKGIHMOTMQIMGPFHSC?THDJ;9<:?A;KE=A=C>CBA@>@??=?>YMECKMgkHDAGELLT\h]MNdSJfZZ[UPOPNVWQMU[Wea_\\hlZ`\U\ZTPJKFLOLTKGLDJRKLKTNRSONOGMEHVR@EKRIC@CBDBCH>=A>CC=HCA@\EBCKHHLI\TJB<;:G?=@WB7==GEDAB?BA?FJ=9:FEIHHKDEJFEELFGIEECL<5/;;FRIGTBDB<33624-01-&/$((('#$#$%#)***&&#" "  ''!5$!&$%#$%*)"!!'#!& %/'B@-*769@A>EA@EFT_>8;=A?F@BCF=FAKCKEHF>RZ~\TXjY\[e_Z[dYaW[ROWMMONVW[b`Z][[iinm`T\\X^VPJONPUS[SMGHKPJ^QKKPRJHKILJNE@89?NJBBJCGKI@@?C>@B<@B@>>@;ADUHDOLI>A@FFFESJJQxECND9--:?AQKIFG@9101813O00(,%*%(%-&($&F&()+-#((##!,"&! $A!'#!"!' ) ",#"" !#!#$&$"$(.15+134.55OG;69<=GbVB=AHFCDNLJGFNLMBABEB@HBBDLD>B9L>IKB?;A3+21/0,5?D:;1659ADQP@9>QCEPeKFUDREIRGJMXUpöupzmzx_V]eie_Q_iis`^^VRoote]~of__fhc_YUVUaXUWdYSRRSPSLOWKJ;:FLINJJIEMTNIFGFOLJDFGIH@BGBAFDBEVJ@BFEB=CK=?@CECIJIIEFGF<0@NEGIENIROA26B=8237.-%*-&)(%-$!%#!!%(((#*&"#%'% ""% (+!#%/A)'"-&&'",*.51&(06,.,-3<,1:Z87358301353779BB[xLITFFIFIGIKN`imochȅalhhhUT_TUWfVjqje\LPcfj_cb{ytznrjeaa^e[ZXZ\]\`^ZSRTROTO?:7FNRYVPQLuiPEGH\LLLaNJHHCC=GDEFF847>KOJDF?DC==3/,0-/'(+'&+&&&("(##(+-'@"!###* A%#$($#3$($#$#5+#$-!'+%.*9./.<)/44000-24-24==@?;:2:78@B?DDB>CGDCGBFKKHPfd~pqoe`pzbh}l]b]YTa_YWPZ]\b_WX]kci}xrc`mfpnnvlnn|p[aikioa\]\YVSTSYVTEFIMNTTUNUVYMIOPjUR[VMINLFCQIGIB<=1AZFGEK?PQWViSX\igzssbefh[_[UO]KOQWPR[W[ngkieyxzhcZmdcgiinnsdUU^faa\``VUTX^]YWRJQORQRQWi`X]GKOi^RRTXQKLJ@AGJHQE=<>EFLIGE?>?>CB:431/,00(#(('&),($'$/%"%$"$# #"'%!#-""'Cc%!',5;@:>'%-&"!##'(4.-+.,*)+1-*,7/4188@:5E=89=@EQDDBAF<9;BQWFINLMKMRMLNp-0:A>@BQIC@??F=?:E74504(%/+%&&'&+)()+(#"6"#%(&#&* $#'$#*768:suR,)*&#8Ak"%,C-,1(.8%263765??O@67>:=G?I=8:AD9?>98:?ShQLQMKKKRSYMKUY`\Y_Xa_\]TVcXVVUTU[P`ea]agvgUceouefjhf^igcb\jide]Z[Z`_\c\]`dbcd[[[WSVXZ[h[W]lWVXVLQQRMKG>EIFNPM9@Q>7CO^rTTU=DILEB?D:A=A;K>18*+-"(!#%&,.3*),)$""$"#!#'8($5(#!%-"!/H2+7cJ(&) %-=s'+25,62=(304F155E=?BKbUuE?A:BGDNLKMNPGE9664,8@BGE>@A=E?>;;e@8-'(%''''%*&+=-,')$#$&"$&$'7 #$#-&*)$Q:3?9)%-+'#*##@+0+/816073/57D5P;69;NP<>?@ONNF@<@=;8:98A=1<=AMgXIKJLCB?GHIIMRLSNJO<*0,5CHG?ELBDFR>;<=72,+*%$'9$&#+'/'&$##,$%#%&* " &$'G-'!(F:,%2+%$$$(1A,-'(/,/0+.53276=IC6:JIKB<89Q^UA@C<;959HX>E;6==CIIFPNcqXSHPW^SQeQVZ[W_VRPSUWXYILX\R\bqeg\b``cjelsgehndhjqnjlmi`_ckg\X\c[\]bba`_]b]]ab^]\UYY]ZSUPOPTQVRJNKKKJDDBBBCNJWKLGKGA>GHHKLMQJMJ^WI8C2DGIKEBCEKB>==97=40**'&%-+-(>&$%"$#$%&$ %(#%% "" #'%!'+!*'/0,')*'&+.0+12,2-,-*'.0?HM@=ED?=@9;:<87::DE<<038HQ;HINNEHLLFKY[Q^YYVJTUL`Z\\Y[VWRNQSUSZ_FTXSQdc_bc`]__uegutlgdderfihhttiecbea`_ZYZWZZ^[YZ[Ya\^b_^^^WXZWWTYPMTVRNLMMKKONMHCCA>>BJMDDB?@DDDIMNJLLHOO?6@54EOP@EDCB;=;;;A@Z2-3/&&*')+)*,+7"+$$%16?1 ##+#!&("''"&++,-"+9*',3,*17*+**)-57?DMIH=<:AKUMQJPLEWPD@HB/PZ\JCPGCB=@=A==6+).),5/(*(*'+*&'$. "%$J'!#($#')( !)! (%6.-*)))*(+&L+1+1-/69=569:I79E?:8>L:B;5>B;:7:>39GR@APTXLPHFDIMW{d\Z]ISQRUQYRG]MMDTKLQQICJGO[`ddccb\Xbjdtcejhjnhbflgjqqrlxssumneabdh\^\a__e`^X[Y]jc``cc]][YVWWSPNROIHJIHQ_PMKKIB9GNPIMJLLYSMC>K0?CIJ\DFBCC==8:33,*.*(*.."&#&&'0,## '2$ $#(')&&'$"+1*B$"&#F)*++'-'+A))..149:6C8?HH[SJNO[NDGFKZp\YWa\ZRYSV_WLUMBADIFJXMHFLS]fb^_ced_ee_b`eptnjtcdfjkmkstv{tqphjljibbZ\^^_b``Z[^_ed`^g]^[\U\VTUZSQKMKHJIKILMLR]><=NCB@><;?CTJMNNQXWKFB@<5BEAEAEBBAC8499/-,0(,)+((%)&+-+%5/'"''('%'#,,%"#'&)&&&$%'%<+(*=+/%&,)',533<86CMSavUG9>@CMAEB<>8;@<476=CG@XNQSJV^OQIMMNUVTJQZj\]faROOPIBCEA?:81?DLOPOTRONIA7786?--*>/.(%%*%"&&%$"&(%!#%)*-,0A"%%#1&<5#$((*&*,2+4*'#')(..06F;95:>`aEZF@;IO_HF;;<^V9;5648;AJQLRIIGHUQCJLPPNGSTXfeiwRLO^PFC?GGELMR]WYVc\\_okfsebjnffvttmpmomgiix}v}wopwww|wolqkhdfcfd__aaehdcaa]]\\[ZW^]VNEQ\ZVVQTNQQLJG=?BE;8397CJJJKPQUHEBGFGWNDECC?MGF>830//1+-2+1%! &$"##$($&##"'')*-)*&!&$(." $&()"(-G)%($%("/40>OF9;92528:MIFCEBGJHNNGJFVUOLHH:BBegYRV[QMQROIQRSZ]aZ_[]`a][c`}ngfdgjqokecgilzxwjmqru}w{xvz}okghjkccljgfknen^`[bfb]YZLEOVUTQPPUQOMFEGHIG=5.;@INKLLONEGHLOMA=KGA?AFAKBAH44;3,.)5--,1*1.(&)A=/+&'(&%'&(17/,/+#%$$%%)-&*/)'''2+.4.637539:8CDJULBG?GFq]FFIBM=HD@FEGSOHDFI^dINOSLRQMMQSQP]SWSMHOO^WRXXg`Y]gjpubhljzwoh{wm[S\Z[ekxvxmljn}wzkur{wrpthbfuaibginm|yuhki]VS`TOVQ[XSZWX]SQEHNMKH@4IMKMOWQSLIDNLGGB:>6?<-()-0,+,'/0-.**,&%*()&*()'-)#03*)*)%-#+).+('',*,4+5;793HFKgQBYDGNBDLDEMHXC9<<9:EEB:9JSGIKGUJb?EHRl\UN`bWTNO_ZNNPOOHGEQU^VVSZ[_a]bifhgqikprr{gTQWhqrs}voyvvz|}{x{yupqjgi|}ldbgk|ygje]Y[ZOS^ZWY]YUSTQPHJSFD8POGDJILKLLGA>NQKXahXYYJGOUDKONC?<5/./0.(+*',1,*)+0Q?A)(&%.('))>R&'"&(+.-$)'#'#((+/-5L6?>WJQ}]HLC<>I@;:?APRU?;IE7BA@>@DEHGHPPOXIMReXhTVTRYVHOOS`IECBITIUVSOSVXf`\XUr}kaw]\`\_cnnlmj^`gptxnqu{spnnokbegdnzllje\\VXQPXcXUUWVTOSIHJIMK\KGLIPLJNUD31:=<5T_`]SZg\XMECDEZGM@?D95=1/-)114-*.'*-0/D87EBoayvXVU]eZ_]\WqpQOVaaRUKHMOHKOB<8CO~yfbdgklaapW[TVRJONOLLJOGC;BEGIJHSU[Y]aef_^g`abhufiwopvrpoemtsvsp~vopszxxwzslnqs|q{|wmhcL@CIQT]\XTOPKVb[ONOQM>;GGKELQQ\aXREOJOLHMJIJHO>;<89A@650,,+-6)*/-H8<.-42F4.3@0')*'(-*,,2/320'):'/05NJLpgsibYjxaHHEBBCM99>BQzv|znwnr~bYZdOHTOOPNJHCN;=FJPGMSSSU^\iec^`j]`gmursu{z~xyqrrsyzu~~pqsz}{~ty{sorzyzrwrln[KHRUT[bgUK@ESZpUHHJ@?FGILIIKM[T]TM@.9EKJNQGMHA<7IP9:9741.----.2/.'-:148-HG.*b4)+(1%*9D//(4)+''/1+46HA@cn\khim|GQCC>?V@@@@?Nwb[^^TWPKMOPMMLPKZIMJONNRRVWa\[eeabgjjixtxx~{{sy}yxjsntuzszzxxnzurzywuotcRXVcXZ]]SRRESYy_UM@FCMKIKI]VUiUULH4-?HQUU\TJO54/+,+/.30.0/2A16K,,-)-3.(',.-+/05'**-)+*(0)KOCPNXe{mf`_cfNJeMQA=AICBINL[l]_^RMOOQPNMR_euGVHMJNMNMTXXWdhhinvxmmvx~zŧw|{~ujv~yx{{|r|ztns|e\^^ZTZUUQNCKHWwQMIMFCFIPPR_VXS_\NYiGNTZNIFIFDQAX~l:324/,+/422+.,22i:39,)()-23+.3+-,+..*0+-,/2-136RH@YDLujaETFTTXGHFFBB=?CJKT\}ȿ̙zkjh]VPKMMMIRPPh\A@BFIOLCRa_`d]gek_sy~zq~u~yytuplszk^[USRU\XMP\WGNYNKEB=DABOP\[_^]ZPGKnaRRQTIRCFHDA;@F3.102A91)40),/*4E?A8.(5238;35L55301403--/,.B048FG<>EjlJEFCJBFONJBHB=?DDEN[fy๞{n[]TPNLQIENXWvWILMOKQPTZ\_ggbe`ilq}vwv|}{y~~~yylnnmhhusq\_Rd]]d[CV_LHNOOK<;=;HBFMP\e]ZWU]eTUMNTNIFCBJ?<<:=>4112E:2:++-/2:EFAD-(%1F94.102640,-222.//..28B@FNOJSxJHAIHCPLUMK>=PG?ACKP]ixh\TRRNMICFJ]^FOaRTQWU\X\d``e[_fhop~wr{wy~|}}q}|xvuwuoupvlni[[^]``\ZQUG=KYTKKD?=8?DGJSS]ZWVcfldIWOKRGA@EFBB@99=6628<683)*/-5;PETj6,),]5/211/183*+013+++.?4067EDFEAFCLDANTWRUq@<>Z>=@CDOZbzɸ~i`\XRKCBCBF=5>??KLMSXTW[`ruo[OzLKB@BIPEB988?R3<1:9>C25*,6:IcyP2(*/104,2)+11.,5-.,.+26@/<01A@L[D=EOJJII]HFI96<@>9>CENZawжn_Z\RJADB?:4YHSVbZ]klliockffljdcm|rx~}ymkop}rztxzpljr~|ohe]\_^\Z\V^R\^YXWOPDHDCFIJMTYW[fghagmfMID@A_LVD?<:8K4527?807,1C5=69IaT1%-+4202)1%)(*10+*+/4-056-9GIFHH=Q\]\ijnipogmrnhptpsp~twzzptykosy~{|y|up|wlvrqtllhchdZaaaZ]WUXWXTRPIHIFHLHMyWaY[b^^S[|PB?EChUGAEHG;577=4,7=>N7:277F6T5D/--42A2*0$'&*&(+(+/+30.7=Fc:H?EABM@C<::@99577699@>EEQYdrԼpmi`XJDJKKE@LPS[]_fvv}mo}oeopk|}wy}rmjlx}{ts{}}|tdtv|vnfdki\]`e\fYUVT]YXYIEJGIFKRYSWZ`fmaW\QQD@?>OFIBALA?Ds;:17;:8<1E:99Q?52.1@?:=E626J=9:??HPWVfϺda]TLGKS[MLQRSRYbbgs|xphewzr{yy}umjv}}|wz}~s{x|vegxeVaaY[]\YXW]tUTQ?KLLLKTTRYaethd[Z?35-8?:A>3:;5'(%%(&&(3,-.1.::=B687EEB=?MC:=:K20,5>784::DMLODFBB?33/5:5139:=64<4/-:BII:7AAC%*!$(%''$+.-4+4:=>@:BIR:8401521A1+-/;674<@LHKTv|͸ymg]_SQKPUSSQRYV^vzrvu~zuup~zywqyxz}~xuixo̞ux}y}vqfag~i^hhd[[]^\YcToGCCHINPO`Xlqimsp`[G>:EGC:>;<53,3,,00000/>>9D>WDD8<412H&*( !#&'(,/10139<:73>=;8735.,+03336/6?89:>KGVXS`udOQKPMVTSR_Zegjr||s||w}}rhju~swvzyotwd_Yecf`[[[WVVSUVI<@YXNNUXVl|le`~yKAAC>?DFCBCE96992-0-.21*/;QBMCT8?0.D^&!'"")%'),1/.26A8;867EE83340-444446772847CB]SPEl}q^XQGOWT[jjkoqeq}~vv|y~qkonryt~k`}xzxqlnpttjgbQV`gmVQ[Z\_]XWIDD@KXROJT_gnhdd`mdW@AC7:D@55%,<951.4;KvwHIlQ?31-1<##($,&'*,...++.35;8=9=5575<15?U71046d;5677A=2:EBjFGACI<:>,130<034>X_lIvP8745@C%&'5/*,*+-,/20-077<9;;F9310/81510,060;558PfDB?PPMOPZZVYYTkZwaIGF^VW[msfd^ihutwxwxntwppsoyvv}~uy{k{io{tmsqtvceSPionrl]dbqsa`SMQCOPRUUHX_Z\nfd_feGKL?=H<:69FK@D;>;3552/.3:7CV_VwKLyU=/3362#"!'/'+*,-2-2=50458;6:3;24303-,.06396270HY<=?JHEJLJTWS^eeld\{VSYcYeirpepbmpu{zvwvrqrtjrwzyw|~z|{axs`ntvtpthgf[[dlospc\aZa[]UMPPTmIP|IOTbgsjll_QeJ=<>E=?=9?>@A>;750138<;59@ECE2S[VBO??@:%#'('()+%'@TP>7=53@4?A6789/0++/,--11/38OQ<=@HE@IJJLXTX\fkpmhbwri`^gjx~{vmr|z~|wrznh][]jmn|~}~s{{w{xwrsvtqsndha_kolkdf_dc\ZVKQW^{uIPPSShpdk{{jMJIBAICA@8=J?=??:15,7+3R728B\oSWMOQEorB<6"!"$'(-*.,HYE@>67432884142/+2,,,.-46.3OJ989FB<@;BU]YV^ovzleg}hpmwrwxssw}xrf`Z__qnx{{rw{l|~~}v{upq~kenfailqejineeX]ZW\Zn~_bMRYboig__XS:MQKA@=DG78:=54;C8=653272;5/.>GNa@2/8:=GF=BE5.+$&$&(,*,2/6GQ>>67;77=X=.-+,,*',4033FA327A634:=CR[^`htdsele~zp{sk{tzuoqwsw~zsuy}ns~v}{odotpgadbhrwnfklptr_]LUZY[dyu_\FGHNKG[ipZ3IibPLEE><59;8DA48362447:/9>D[H9+/.569?4=]B(! !(%&'JI5IQt?82BA30334,,,-*+(,,//>4553<5359O]A9:A?;881154/2+1*)&),05/,+563:<;A8>EPP\cag»mblj`kst{phmkmqpuzuuŸwz}ghi~|~}~y}}zopowninnorw~oof~wxz^m^aSYVPRZd\TL4;CIKQ]VINNFFLJBB<;==;97:7775;96?LCMAHSD9L2412,...(+2#*)%1.494EL<@[@B\BC.238+3,.)-/++09.--2?6347=<9MCPQ_ap~^Yf\aalr}jo{}zxqil}uy~lf{kwy~~~vspiiwqwwprqugw{zqo[`URP_\^VLB34;DBCP[UUbOCEGI<4986:7;;;98A7;JHB>EBFKU^0-/*-20,.+/+=".3*+(3;840;:BGQ;;;B211+0+,*,&)19..,*024/.042>??ET\WgmrZOWLaelnoqlppkmrw`Ia|vvv}zng}mn|{fs|~xx|}vlfwwpuyxwo{tlsf^bZjtnTN156043:?cOYOQ_I9;8/;@=?;6<9B?>?GQIS`^ZGQldlo|wzlidek~pts_SNcest|wv}wsjxuwwxmwln{}w}~ztgxzutrlpyztmnojtvokspjc]Z]fUIOF=:938AIOUVRSZS;44<>@@BF@=>GA?8=?>-18Db<;?67.1344-/'%#+)';%7630*.-*.19C94D@8S;3[.@112,+5+-,-0/(.4011>QCESKFP_\^a}Zrmr{zsleadooph]rtn_e|y|ryz~zvqn~op||vphn|yu}z~r}{ytk`rx}{uupqhihkrsjisi`X]\_XJGEJAAEGTILUWWURI67ICA@C89D=;8?@>@9206>EJE7-43*()-$B)*(!&N4*',457/20=F67CZ=9?=J:G4/5&&*),=.+,0+/=8"/M,&(15242>6HJ>G^D=H?UA-*46''-+)+*'.+22ABD=NJJKMX``ab^L`X\wrnjigf^\d`]mqkq~nrmqtrtpwqiic`kpvx|}tikdyzu}{v{ziweallzwvvjipfiywztaa^VSVRKEACJOS`LKPWflO>?RFFLGHG<:?FCjKGSCGJ?@GC\G84:766>?4-''*%*,)#+3I,.40/32>8DHS=:?9A?>5811+'+*)++)-./2;9DEHFNJJQUXd`XOTVogiujc_X]SVbZ_bklf~vlkoqssqqqoj[ghqxv}ztsuvxz¿}xi{{v}yy{zv|vkdiip|vkcVSTRRCOAHBQHMWVUNZyYNFAKFCJHL:9;B>QnOpMJHAB>UA\@<5/4205.(')-.1%+ '-$?B7+-<63/7BAIK?CVS:741//1..().-@6346FCEHKNOQQPQPUPMPCHftmkndoZS\k]^dj[c`flmmyvn~pom_\hjw{r|xu|~~yov¿}t~vnn|z~|~wr~fsrq{swtiy[POF<;=DE=AELONRRVUUTE9FCLcQH@8AIBrsRJDEEB9H>BDA972-E/,)('&%&*(#&%&$&95././741:@@?FD`E93E02-)+.3202:;8=ARJLHMNRQU`WRJYXJUOttw|ac^V]hb^`__^kjlwminkvtm]Z]demqx~~{|}|tx|}xv~}y{z{xsy~tsqqyxqnd\lC899ADBEWIGIKIJJNQF0:HWWOIC;IDYSHSXMDD@?CDGF5JB736**%''%(*)&&'(("),D>*-58N5:;:<@Iqb=C81.+-+11355?>EQDGFKOOSQTcX\WU]_nwokkei|ddfpjiefilihgciirqlide`oqpu~vyyrzuwy|{tqy~|z}~|xwzws~zqruqkbXLCK@89>AMOPHBHKMJGF@';LYPLNFKITeMFPBEFB>LEHU74:7;B0.-+*)%&&%$#*(#&)05F20AHU;FG?@A]9;:E22.*+*14<8@FNNHANDHHJNSTYWYZUXuv{luga`cdjdm`msmoebhhrnnmdeesppmtor}vumtz{{{~ynuxÿyx~xtyzz{oxxppwtvu]RMNQLABFDOGIAFKQJIL?29DGKKSJDIEPtHBMSI;>:EFQL6:J40.,/.5,%#+'""*+%#"&6-6N9OAD;E7<8-++,45:YWG?FADGNpRHMOOY[T]`kmr|yehwb^lmoipi|ginlshr}oqnpd_qqpngv}|}{qx{xvxyzruzulmprz{ldYVMQKLC?BEFAAHLLMKSPH:NHVQUKDCFCMKG?HQB?A@ABBHMNTNIHP[dea\`olsppghrt[[h`fej|xujlhkonkoxuostgtimjxzvuuyÿwxs{vunpnoqs|xqkdZSNOLJJ=AGCHSKOPNQR[MHQUXhTK?C@>769DIEfNE=630K,+4,,*)0l=;;BE?DQ\RUZWgmun^qky{uc_^\[\``]^`]^p{egekiprqkqprifirnpsw|{pxz{~wrpsxytspppxlh_YRQQJE?HAA@BFLHLSRNECRU[cUMCHIAAC62?@LCQ]eN>E<9:62-3.,*'"$&$!!(*+4.3?B>=MaiFCJb=4/90-+',(+./--?P:DBPONQN__hv{vxlk\]UTRXZZ^Z\]`qjfcmidclu}ubgpjpp{xxdjYex|¼xzvvstu}yzoqnuroec\XSPMLOUJ>AFBFGIUQYOC7LTbZSEFIJ=?6999=9=@?ADAEMDWOXpN;3@2'%/21/)4('##(%#--,.:9JNlZUIOBEF?14--,(%$+*110767UGFFRMNZi\da}yxnv|xng__\TN[[a`ucgbbfedg^hs|rsvsriovzzx}{}ntt}ýrzs|zjqqsv~{ijnq}nmhd`_acSTQIHDIPDDE=DHKMP?;TSZTSMIDC>@??ADBADU8KHUzC480,,,0A8+'$&!7$(,*26EYgvDHN?A?LG5-.1*%#+,/0--.>?{GBJKNOV_Wg^p~shVbtyvha\\\TY\eihihw[ogxgefkyppscmust{trry~qľrtrusyz|vgip~mldf_hl[^UMMMPPK@960@KLKGGCLNSPMUSEB??AMLTPKNGG8NGht??+4/5(*4,&"%&#!$8E-?038?cxhgP:;LE=73.+)'%'(<+*5365>DICGWMYPUXxJ]|YNXWhwfb`_]ycd]fewjmkeecfokdf{\fvsupos|qrzrv|sn|¿|stx{stz~znjlokiaku^]\MCF[EB@809AHMNER>GKRTP[M[E:;;HeWMaaG?>CJLC93..7.K4,("#+6"&#*4/?82EDaWJHG4:JDB9:/)@.,&++,)65F4;:C>LMMIMh|Nbu}QDlbbfdda]fwb`d`oabql`mljhiheFdeqsnkttsuw~mq}½~vrrxyu~zwrupuvmopf`gdVSUFCAI==>=:>FJLLI3..*'%&(&!! '!*9/2<+,F,)**!#!% "%&2gXJPPPW;8989<7B55mK)&)(>2;>=:B>TXSOERKXadi{]OIP]hgfwcjflthV^c\[gc`eikqpvwo|ztlhZbmnlqtyxs_hqzxz~zĿzwvsv}}u{uuqy|sdaYXUSGEEFO@<9@ETPB@FG7LIVkuNJJNJMD>HRLPPPOO[GHHN52+,-&)"#&)% !" !!8/nStD^I<;8244,7?59E*-(+/;TKB=MH;IjUEOY]ndjwz_XYVhgniuiZ_j\ZNGTapg_insnvyvnphUhqqnnuy|~f`mn}zþ~unu}{uqz|{qsknoh^X^YUVKFFIHA?;@?HABKPeGNUS_[QKVOCUFHEGHMNT[kYVSFJ.0(+/&"!#$$(#"!#!-26T~OA?8>>61089-0;-5-)+/0:M=Ew|[RRDMM`_db_nĀabidrhRT_rzqz]RYUWjiWeltoox{qzc^mrttvtuzqblzz{wlrsuqw~y{onne_\_RVRSGSCH:<@@:@ESUPHTQV[_^]KIEBIFL?CLWVpyZ]GF\T+)'+&%&$ ##,( "''<>0:a=3:C<:7:033F154/01)=]C=HZJ?ANFFW`^de{~iidjim}tyijfYkc[YVYffZb]e|mtyspsnlzyz|~ukwtmzĿwoqpihq~wonl{vw}~|hmbcYVLKGC<:B957A=9@LTQNGITW\``QIDIRH?C@Em^hpVYfexM1($" #!#'&%!?>4<231:434D3:72735A214)9=19aHFDITOKRP`bkiwzyhj`_[aqunmmrTSSWUUXU\^doY`[jtsuoyxrnlrux|wznpvnZy¼}{njq}~|lffoyuxttlk`mXWNFCAA9?8;=@:7EMSRRVMNd^emUKDHDC??BJ{dZ]W_YiZM3' ""(&#%($"$#9=340-325205169=5556;3>-,367AE?8@BOPMTPWSavf^o~onaU^]`fe{oizU^UIFPRZa[YZVckj}{qsUbqobr}|qgvfz~|tÿ|ur~sjden~{mceg[SX[SGNC9>5=@?6DMPNPKd\VZYZ_NLMC;BJ?EGJX]]MX;;4K,))$%($&($")$%2$!"@248C3081-0.'/8B:288:3-.*,/735:KGJZEE^kWT^eajlb_][a_w\drryvbgsNQR]VYg^ijgilqlY^pwisqox~a~u½sysv~vjskzpmocUP`cPIBW@=?A539DOPSYYN\QTYYQMIDBDB=CMLAO]lQC=:69,)1''+1)),(&!(""$"I_9A93..1/..+15.220/1*0/.86:.5@@?@?NFABOTWEO=7(/43/,)&&&)&%7!! ;FEB01.-1/;5103.061''3.:169_AA>DUDCMWOJUXerj^hfg_[leboeirJX]NVecYVXY\_eaasxg]W_k`f}jirkqijoxqr~vpppqu~x|lyroyy{togz]bqmRNCNVG@>:?GCEG@CLShME5P<'.1*.,%%(#$%% #1;FG8655@469-+/.0-'$&/36>09IA9=?AEIHQQLMZ[b\W^_eg^gik|inc89HHVX\\[gVYhdeifqb`S^ahdyeoyxrjlwo_y~sikeu}~xlruqs{umh^\XX\L@>FDDG>HEP[V\[\^ci}eb]WJWaE<>?BADR=8.0N@@0/-)'*(&')%$%%# !*$ :@L715125513603B;%(&).068W9885;:CISQVOXV`^`qpi]ehlwwp`QVIRWcZXYb^]ZNNTckhU[[`ajtu~xnh}uh~¿~ngbiu|uuztszor}vokaWV_QLZF>>;>AGMOPQXZX^`Zic]Q=;AMQNDGC<@@:@R1-6431,-0+.))+'' $'."!#"rLO68P0.14F652*/+,/(21417B668:BDMITUW\c^eb_dkX_``ngn[^GGXymX`i`[_`abX`hecm_calwz}~~xju~smrrjt|{}|u}}xxpxmfg_Z_]TZJA?@@C>>783,,.+,)&-,("$""$&%%#! tW@6F>/*)J80.?)''/2(-13.;488;ACCE]Z[VXXde^`[`gZhgpws]jQHS[XQWc]Z\g_d`sac\]b^[_tvpt}{tbzv¿~xxqnjvyyqlru{zuyxxqjfccas\QPIGCBGKQLYW\bafhTSPTRPOKOMRGLA;=JPD88:.-,.++)$%%%)&!" "!(-!#" ?B65/-++-B32-3.(4-(-,/9/.;AA:36;=>ADJWRYY[cklXXTRZ_ckgkeZRHFR[LTbZal\WXX[ZY[\NWb\_ltqtlc|r|yjipvuyrxxz}}}{qnncs|l_VTHI?A9,(&$>-1.93>:94<;AEYMSd[SaZ_[RRNQ\]be_[^[`\qbOWXY^[Z]g`XRTY~[Z\\cltzu}|w|{pkuxwu~~wws|urmlopcPNPRFCCJFOL[Or\[XUW\VSTPRPPOZPHHHHVB:65202K+./*&/7((%#$&"" ! # '"# +@F5..-/((#/.40>98((.+%$)72308C9EC?EE\RnocVBGSNPc]WYchlcf`Ya\W`]YV`b]fVZRkba]]`XVipv~||{z|{yyy}vuxwz}xyyvy~nmvldY]jSZNGJKORT[X[Z[YYYYMFQRiSRRUQMVSOND;<95.-,-'(+)-.%!$%#'!+"$"/&&#&.24.3,/2*)%*/00/00/-<*&&&'1413?9V<BHSUak]^gi_Xge^[`iguqu}dzxzvv|wxzxz}~zztrsy{~udhbNKJ@A>KQViXXjdc\}]QZ_YTZO^lb`[SGYGHDQKTHD46+%$''(/&%$"0&94%!&''0)+%&%,?1//2,-+*.-/,05/+%'%--,+566A/.4DBLLZbaV[pa_YoiaaWY`Sw^QOUN=>?HGLjbbX`WXXY_s_admtuyۺz{tr~{y}}~|ywx}skv|zy`cdVJLACINR_WWX\W`dWVXZ][YURSbh^`aocKVUZGA;5I,6(&))&%!#'#-5(6&)(4NYE2+4'+8.-)+-+J+/.'(&"**#1'+57+.0380,2=NLL^xiZjpi^VclmdnlVYWgaOQQLCB;?KOHT^Z_XYQSVTTaiigojsy~Ӵvti~~~~yy~lwnwu||qmTNKIILMPQLN][WYX]_[Y[baaV_bhbwj[JJG@=4<40(')'"%'*+'-)#)((,-5c43720,49>2(%70*)*--)7$&%&*.-***.5115C754G?E]eYyrSXljfXRTZ]SRMMLOC>;@CGKVPUZ`VVIGSQSgma[iq{{rzx{}{irx|volptwxx|ozc[UDEIRKOVNSQPYVUe]nm_\vs^]_^Yo_JGAE@=443-/-"&'++)$$(((()&b-/8+<=M99JJ=4*'*')%"*(;%('*'&*),126.101/<=;HC?E\b[ŁOL_hgYQXUMUQPIIFJ>@=ACFFLTVj[SOLNRRWci`\nrqmuy|uxt{{moovnwxy~ke_dXSJDGO[JUNXUNVWWR]beg^c]`gfpjOF\HECA@?M3/051*)().FL)+(&(*/&*&,.++-R2QP04/.+***,.='""'(-/&&0#4713.3.3G56XDBIRVecjPT[ddnOKSLLOOCJGIFHCFFVHHKMOUXTGMYRMUZ^_Xlh{p}zzlpme~tvzs}vs|pkpswr}wn}qYZTUJQLEGRXOKQLRXTTO]fju`[fe__j]TOEBDCA=:9:540-+()-(%^7/*-3('%"-&%&$$&?150-4,((&.+&("$+9&)-+%(%%4/3,//86@GFJLePYRZTWQWSY_c`c^aab^gkXIN`I<;::7;932-)%&))*+X6)(-((+$'+*'+.*3VF+*%2)'),'*&(#%'0&#!E%/6,'+5-3/F?DMOH{[H[HNU]ruj`VSkPPYT]GIXmJ38]WEMBKF=H`ahacYQTOMQYOHNJ@@>?GHICJKNOSSROD5.FLdT__SSnuj[cjxcqgZfw|o~~uvporqv~txfj`XOQKFDaWNNSU^^ZVWOLPYYYZ_q`^d__akU`CF=9?76728;00+-&$&&'$!$&..(1)-.&8$&'0('#)&,3.%$&$&#''(-%(# #!'*+G0+06694IBKB;>;;EMrai_]QNQPMKHMEG@7DGF@EqBPJTSZLHHVADP^rwa`dmyrbi|wvupwv_m`df{nj}~||vsy}v~||w{|yvih_UYRTQSNMZSSUUPORRU[W[YWZ]_aacd]aZPJC>FA=9=N1729G/.(-$)&##'0+-.-*')2G3*)*%))%*$$*3.+5,*.**+# $!" 0 '%..2*(-02388;BCUQMdg[kmnkgVTLMKMIIT>9A@EGDQGFDDLFJHGJFB:LGR_`aj{m\^cjvry{w}hsztpwvnuyyx{uvu{x|{xvuw}xqcSU\^TRQUQPR[VWPWUYbRJVZ\`]__ca_^h{MBACFA8:9?K2/6.0,)(%)("##$%#&,=+79->&++)+&%2+&'(3+1-)%%)3'(#$"!"-(",-4/-46.3344E;:F7M]begwibemvwvqzsuwyuvony{z~~{ossupzysvsuxoaaZWl\NO^ROM\VWRSXZ\VUSX[_^f^ca^YVgdI<=<:99886C@C0,-))&$&%&#$'(+,)&*--7-2T*,,#!24(0)''N-*&%>q.r'#$#"#$3/3,,2@0335:?;CQTNS[Zkqkf\[OFJCDFKH@>>FA?ADMECECJTLFEACABR`[\edleq{yx}rtux}qwwrtvy~~~{xrnsrvwzomqysna`[[\[^RNRTZUYXYYTXzcb\^Y\mfm\]cUSJFGFDT697497O{L.3++)+$&((),-0:(8*01UC2+5:2+$ D"'%"3$''(=F>)$# %*<*'.(7)/3039;=K;BIUSTZwiaX\\SSHUWOAG@;ABB??FIAECBBHEBD=>BQuWZ``narsuxrrjrlxrtxz{||}~}vssroxw|zriiolddXd\YR^QSUUWTZU[TUUb\URTYUZ_^[YZUMJFA?CAM><;77Aatw50+*'((+0$$,,((,91/2:F(+'8G%$!%"%%$!'19''$(# #)(+%!)#,959<467@NJZMSjtqb`aXdZBGNDPJCE?@FECCGQBFHHCH?B?ACEDHFOabhq{~wsstqnww~pus|~{~~}xxz{}zyrw{u{tsvnkekd\_`Y_}UOSYa^]]XTQOLTUOGP\`a_ab]ZTNHC@C;9?B@@>@?MUFB81-1*.&"&)$#&)/<05+178%+,% '" +**!#!$&!$!" )$-(+0N*'%"'77-1Y59EVJTVbbvtwud]LN>NROCIVD@@DB@HNDAEAKCHHEE?AAB=>Pf\gv~sxwsuxzyjqqjrrqs}~y}{|z}suwsxt{vnjkdelfaa\TTVONX\WbtZPOMNJOZT\ehgcb`Y[RNKA@?;AGAA>B>K@DDOQND?LIaUR8/1?+'(2'%$'''*+308;04(/$$"!$.(&!*(5$#$%!") #+14sn+,:-+/&,D/;EC=B;=HHL=mWNFA;41,**&*+&$%4d5)(,,+*53# /?)--%$)4!"%&$:O($$';0.".'" '"2@5;57?9HGIM@IQWfXLOLELED?LGDB=BBE_RP@IZ:?BBBEC>A=;CCSUc`iw|pl|w`x}wz|srz}y|}zywz}v|x{ykgfev^aa[]YXSOPOM\WRW\e]daaa_blggk_Z[|SHELCSBOZBB@Jm]TH8/3+,1-'+*2&*+,1/,+),,,,:/%-.&8$'.0.(6"#$1'1+&$(-)*0(-#*:!! "+3//5;9B9JOQmADYZlHFFOKJNKF:D?D?@>UYBUACJ?C@SKIB>GBECAXMV`xmrvt}tmiWow}x|zoi~vxyswtuu{{psnhfe\X\XVURPMSQRVOU]Zuwfbgc_^_jYVUTryLEHUBEDL^HVDVbA=A?251,2+')**/(()-8)'(-&)',&((31%%'%07$'0"%"):?6"3&76ZJ2#'!$"#%,131769=GOdW_\V[GMRQKJNTKH959CHBBBABCPB?EDNGIB@F>HA>OOe]}ylro_V_yW^mv{xxv|zqw|z{yvsy}{pspnnneb[`RYWUTW[SZXRSVQXaefeh`dw``a[TUOYNIDFDGXKQRPQMEB5;]C,+3*&%*)2(+)&.))')(*,%9'I-'&,V<)-J1%$2$!&'?'# 9'A[+!!#!4#:F5:56B=B]YN`a`_RYTTKYcNLT\DCD>@LEC?IaKND?I??=?DMPc|tovyoPX]b[OTgilmuu||x}~vxy{yyusoxqwpx{woftaaVVaWSONT^Uu^\YSQT][efiebbddje[f]QRFKFA=AC?CF@[JILA85,30-+('(0-('++',)(#$&&+&*.-(+$%.12%-;- !!$+(#%) !'C^*"=?0219E?SJNQRb[PPVYd`LYMTJJFB;>CDFXD>?>?E>@EIWKCFEDC?BHYr}{mbyt\_eeUIRboqiqsqlr}zx~}{yuqswx~uvukngke_dfcffaaSMKYYVNSUUU^]WUTQWY`hba_c^^[]a\[QMMF>H?@CFHE@9DMWD3./5-/+&*(./,*1**+8&&''''$&BJ*#&>1+/(#7+ %4)(" ##"%2%$*9/0X>B>FJOOTJPN]Z]gLHCBGJ=28?IDJ\G<ZNDC;DoFw1115:6.,++*/1-&-.,#%*&('.%#+JD)(+(:67#(5X) "$ " "&&$>,//<@NAHNHRPNPP\T]_QEPSLE73;=HE@@A=@CBDCDB<;;?=?@BKOSGJWqi]durw`JYZbcd`rvmxm^R_gzzy|~y}{oqrmtvs|tmsjiuwnem[c\d`eai[VVW\UUXROMOXb^fWiga`dibkifhp^XVUQONEB=EA?D@nIHL78=5283-B2B/29+.,(+*+#)('()&%;',&##&$*3&'+422')1#$" ">##&(+-+/75FI^GQIMVOPWZ^\]aTW@117A:>?I<==?AFJ>?;A?@?GEDC@BELWbxgptsysQJlrgan|plZK]`zsu~|yvxttyprmuqtqy}|vxvecmzg\Z`_`b]TVYVYZVZ`_eWRU\ZUY]bkiaegchd``]kUTHIDAGDB>EKJO<:@7633.111-+.++0*66-+';),)(&( $1&4$"%$#*)%*+1>'4 !!*6!6!'" & #*+C,;;;878?==>AJLA>>B=AABB?;FHSuWczchtuzrr_ZisoojwveSRT\espotv}|}mrqvtnipinfilsiwwkitbwc`^]]zcZ`WT\]g^\]X[VYVi\Xcbegfgddhce]\Z[WGEN<9DE@DDA342254--(-.0/+/+,1*-<.+'$()0%$3% #)!!#&"$,(,(&"5$& :c!#'+15LI815>CD=75=<:GN@IE8==AFwNNRUpljgjlD924*2@:>>;7<;>AA@=76<>AS::?;CQS^UTYgfvxuqcZP]vugl_npj^ccncfjc``spxq|vxsmrvqxzgi_qebT`\V`cn`_bUXY[Za\TY^kib`ab]]]\Yf[UTX\[addlreckjdVPNKKO:9;:7;;ArrD17847971/./-3,),.$+-10)=,$(-,'%"!!"!$*&+DP-+(+6+'0! $.$$.6569?A>BJMVRYdk^^k_T^Z:<52223:;6==A@BH@=D5@FLA<<<@DHVYY\pgwxqps}a]hexnhhhsXstpshg^_Y^}ptvpdisvvorsrqlskb_ZTWZoo~aXWUURc\a^W\^\][_h_hcZZSWQRMXY\Z`gcdriea^\TMGHHd=@;?8:EBHHL<;963.18570()++,,,'%(%'L'$$*)(&%$$##2)+RU)*'?2:), "$  $ /3.5A@DPBEM_UPOZ`ma^P_X@2..319a=A./6<>7@8599C@<9::;@HD>9@DEIORVMTOUghlkro]ehjfmljqljkvyrbebWQa]U_^ekbjbmhfhwxlxddda^U\b\ZYXVWf]``Z\bb_ffjhrdddgo]]fohcZ`obbaqfhWVPQFHCA?TD;>76:aG:KJI@86:/*(-**0*(,+**%"$%&(%-%)&%%" $''11/,*&(3-,-+L*"!!#/$!)$/,+.1Fc67120,*.(&'+**)'*%&"%('('(*/,"%*&.>5C)+.3498)# $+!( 2+  "*,$**1G4S>IMOT\IOeub[TPNOGMAFUS+/7796;4<497<9;;@=<58C@:9>B>@8C<;3822,)+,),4,,+('%#%'##*,%%*&,%! $)F?:,:'@7(' !'$$!697%!"./(*16Fg8CNNMD\JGKWg`SM[TMPUIHBHH0)-6:272323;6786>A8:GUGNM]TXEMYgi`pjqzicWfXuqttzpq^[ZbegkoQO`j\Z[[ZUfgjuja]c]a_\ZV`gghbdo~lpjkinnooijrlzmullotnqko[LNNOQ^[UKI;;7:KNG:58;>B=657671/.+,)')(((),+(2)(%2#'&#$'#$'%%1%'((#/#g,% &( )R .'*.23DGBEJCLMHLSLJPXYM`WFFDJ<:,*.-125<66<5:@7<@JNRTPDOJXVZclooe]]ME_mkmgh^chl`TTTOZab`^aYUW\c]innj^[a`d\g_]`dacbedmklfdeojhmmfpuyyqqourt{qoi^`TSZUNO\bQJ<<9@?8@A;:1?@=<75;0-.0-:,/&%&')%%)+*&**((""#!%#$$C+(*(+/"+)4)?F!$ $)*'(%(03:=@?JJJKUTQ]ZFNXSPLRHF@A@U64/*/852497=9:;<8<;7<;@IGRReFFEVWdka^a[U\ZS@\hoy|cilne\XZPU`f_`ZOXXZ\^d\mm``a`^[b_hkiehmedcgf`beijgjrloospzuwuonpxjeg`VRRRSMVOOC:!'&)/<@@G=?K0*,/-47;:=:<<99:::7HHDEL?QA@IJ]_ZWR^e^`[Paumjkynjbx|pd`_^[SPG\W^nhongYXkdZgddgde`eckmkc`bbcafldcinmbglnijxlpvrqgakws][WZ[WSOW_HBIFSTVKMPOOOIUKNKHEEF?=AEHWK?B7C??JFOQT_ta`vUeZebfb^RVVcedd__a_hNIQ[ow~i[ldcb\]ksrbklkjijfdhdg]llghgecxwmigoxwphgfhjjgc\USbU[pFBCGACDE<@>6>:=EDLA;>83.310/-.1*''3*)''&+s%'((&"%%'4(,&#%$&!'210 7 !&%+-,6Y=7MCMIPJMXVVNJXAAFGLC;4C=T;?5DPZGNOPCIFGRICAA7?SD111,/2Q52145::?=36sTGRJDHVD?DDIEQ[YVcbfdfdkbchfllre^OT\XY_antsldmsjigdjjrkjimwprnkh_khevtqqieecjdhobfok^d``TSTQTQZU^VAOLSjmEHDLI?/252425,1)&++())%##!#)*8,%))($%()$"&#!%# ! $!$*,18:FA888=KPPJOKNFGEDDE?DAJP982-.1/17211424<@62:C<7>H240+5621.0.4'++.'#!$#"##())/&)),'2('$!!!#%% -" !"4 76!$$(/-2<:49@@FKISRJEYFKCECA<@=A96672'%+-/0--/457<733IM609HB:AQAKLE@D>D]XQ\d`ddcZ[`\a[}wichnemjthejljqoygyuopplhgjrpdk}ojki~|wfd[f]_Z]UURVRPUMQKHJJKGFDDMJTefQH?@:>7<9H?5323720?0?0)&&$%! #'+,+3+8++,*>('( ,%("# );"$5"! (!&)*+33<6ODCBQNKMMIHFOECAEF=;C:8>@[3-*-(-+/14G489.56B85>?J=C<:>D3<5-38N+*/"&'"% $&/--71>,'((*'%)!'%$#$!)<!##-0)5IFFOBIDGXFQJ_THGFHHF;BK:8L74@B@Dq9E96]N=>@l7EO7C204//...2:908BD<=CC?BFCDLIIFPFE?>CyaN=9>51/3.&*#%%#B1"$$#-M-3*+)%&$$1;(+.0_)$*+)#'!. ('*2 "('$=BA><3E3:+504/),-+'.197157;98BGH@AHJFFHb`ANCHOLYQO[XdWWeMZUY][^^YW_afgeb`X\lvrwgb_dW]bW^RPbbrccfb\[UUWTSRNLHISKKHJK[DLKJDBZcxoiQNMCEDIGIIO;FJ=BK8:WPAOM30,,1*.,)%=:73$0*#)-1'(-1**)-4*&2(-Qn)%%+) &=!&'&!$!).06:@ILD;FMMPPVLIJQFME@H;;8?1:38;.9*,-*'+.1755<=?<@FA=EGFBFERS[A>BJKRULSS\QMHE?JP^PUZSU[jdXm\ORYUN_pg`hja_Z[`YYQWZ[[^ig^]SPVKLHX^AGGCXCAFKDDKDA?_{rrufK^J@?AX<:@A>=><68R637L/(1,0!!*"*I()+)&%$(+((0&*&+$4,%%%,30)%#"% &/"$$$ '-+2=9D>FENJIILNVXLrNC<@:C>571-21212..)%,.+6569FEA>@CD@;CD?GLTnB97?MHHSMMRQLDDCGPOPNPUVW\XZaY[pPIQ\URV\Y]daTYUYWRPJWWZWZeQIJIELEKA@BEBJCNGBBFCB:OSwXCOTBGDIFGPBEWFOHHJIFKQOHJ@DD?87380379;663.#0465C=EHGSC>LOHGREJS_JFCQNF?;8479ANp=//.*+5:?V]LQWE@=F>B@9XMTQDB;39EHHNJRLUjKFKCJGFL\nNGKIIMPRMVPNKLKTJPKIF>DIGFKNGEL\OKE>DFG@<=@?>C@MD\DNA@BACON_IS@CCuC<9=8<26553-1//-@/I5G6*(&$)&*&"%),&3-&%(6-+((-4C/)*8211-$(%IX+! !6 )" 0$%",)+F;;E>?CB@I>?<;<8B?@;-&0AM=B@@S=BBME>>@EGEFCRL.0??IMLJFOXKEBdKYUVIWMNB>=AHGFIHGIVIEAA?>BAB>@CG?@AHHIFFEBABCB>?@;9<<FBEPN]AQRaHIGKQY@=?<7;=<))5=<>?;;A;8:U?A:>B>>CACDDMFKF??@?B<:8FD@:=>?HeRVF3\?262330/*S478/))%$$#*)'**-+10-+:./8-2-+40\92-@/&*84(0"$*%! )'!"$$&$#'259<=Bf6<@IBB@=HZJcNSSQ@J;6?C==TEENULQcp;A55@FIXOGLSV@>::M=U@@AC=?7CJVpiG>;IH<A@BF@GABCBBCC@@C:>:=:8E;=7=>7<41/.4Q40.*+.7395*(+,*)C13,.<.166AU95:16,-->T/6**'(*"/%2 )!(%!!"#;.&58<18A@>=B=;;9@@<>;;B?=AC>?>?C;7;:<;AO988<8?6821/66.4./++/+0WA*)/88gNZ57977693A2..27?1D@@4/'%"+"#)&! 7#0 ".7)'*GH>CAJG<@=:@IPCF95<7CCF@HOTJQF:63?>B;9;<@>>INXKB@E?FC;=7:;;;7AD?B??EI><<:IC>FMN>;0422.00D943=/4/T>08/956=U:OK>.;ZA@=:@@JokT=:@=99648548?>7>?@>@;;=:H=574DF?<8;<<<;<85:<3;GQ236Y:<>@e:=L0/5:DD2243.+1`Y4/+&% &(&$*&$"O"1"*>AC@+&4--42;:=2457537WLUFFNLOA>A=>]XK;5-39=:522,8<7=767<:C968<@=@?8=B<=DC898<:?BB9B;B>=924>8[;=E16MG2;?X89k?C41A432-55-0=-*A>sL0**&+.#'%"/$ $Y E+*D4 /634+.11656978231>mEESTJBDJM=>ZbII8.979A:971357689BEOFEGCJ;B<;:8;6=B=C;;5:D24066;Y;;7M=:Gp?C448~\6D]?4QG;;68<5:7943MT73/(+)348+.-6.(.+'.+%A..B>!&+%%<' 3F,5,$$#+**-2+/22206348KIHQMdBFiDDFYC=H45;7DA;61,05=:7>:?UHRDHIF<=sGM06L=@8A@>AGGAY==9A;989:<<9=?C6?=FHTKFAE;IAM@D?K<@T=77=-=8>:B5AD<:05>;72WD>:E;=;91772=3478EJ>>>@1>:K?=:8127B9N9e;;5<;d>RIT?BH7162("&'/,.%=*1>*),"%!R&&"#$-"&/-3I1D53/A6B0;BBB>AGI>J?:;;=mL<6=>F@:<4.3;=;A@;JE@LEBLC;EvNJ6FBH@C5MNJE68DEB<==9??9=>@?FFH9>=;?:9><=H>G@699;:BeR?DD?<;>46839>7O=E6@;>7N;+8N1395C74:36?367*574;7J1252+I>7.+-*())'+)3/-07;@)))C&&*1.&.570gJ# 5&'""6(232/.-2:30/,+.3;J>=HnNDE>89ABNAQ?58N<9722,,7;;PBAE@ENTKNE>ULEB42/4?H;?8C<>5BF?D@???EHC?FFHDMABS@>:@BX@CE;G;A:;89EIHB=sY>=?A:9Sr[ICQ=@6<:D6989874/4+*+)283@B?92/1/7HE=8GB7/302,.&*-(-/+4-0/?01I-(.'(&,8*6-,=ODGQ80:4;<33;5;=<;GB=K<=<=>L>?[GCDELFABFB??HDE?HRD@IJ?>8DFAA:F6:;=<>JP?Z7<8A@^SZLRLAE<>2=;>9508.-3,%*.18+482?--+K43-=<3A@906-*(-.IB-0,+A3-:8/71+$,+*:/)'>,">$&@"4%%(+.B/55=-144,/44<;?EAEQPePDUSfHCDAL8F:=I^PBD6448;<=K]TdaGB:EB===2;8D980>.1649:;9;6<=BLECDEG>AHEK?;@MT\fHC=>CH>=BNKGGB:=9B36:?<>NpV=;B774542660.12001013.34<(1:0D32/20243140*->3.+),-,(5,&%=*+(*'>Z_(+''$$ #!$%%&%")1.0C:/26.-85:AJHJOVJABHNaKADKGXC138@wZY|==A20BAHOiwG;5812;C=88?[=19A[;;>8=K<97=A6>7>=C;?DNG?;AH@;?>C;HKFRD=A>:8>B:<;J=D>D8==@=A92?<=;?=_dSB6;765.3;-/-386161<56+/0,.,+12>3.-;0)6,.+*61-&$$%/$,0+''0(&.#,30=/'#0*% !1,&-0-A-585<2.1367;SH^PuTwPRH[EOQimT:.19[VL>6;BK<86DQQPKRA;78MI==E;;>;6::G<=:<6??447=99:;B<:9OG<;RHDA<@BLE_f<;==897<>AIA8E=KJD;>8:=9GH>M=E=HK`G323::5/,4/.)02,,0=9J;.+:(*(1,.01.7-**-,+2-**0(&,&)'/0&,('*'%$#+)&',("#'$!&!$$+(*%2.-1.514:K2.35=LP`LLVGGA;_HJsY]YF7>J<:HBECCc_H:>IZpZG<;5513V==KAB@C911>?8929;6249;;9:77;:@7=@IBDAG>:8JI:;><368<2.6:AL=ERgO9488H<8D6FA8CBIGJ;:C8S9@00*6+/+315/71W3@-++5.4..10/8<-&'-**0)*+(/3*02/%'%.'.);""+&%#2-#"!!9&&&+''$1=/3+911;3=0569SYEGAHC<@?YPMXOD8W996;LELH@EIgOUrEDBzW?35518:;;7<@@A<=1/576578863:98564;;<6442OR9G@C?91210576475461/:IfCKjs9:<855<;^[KJ=DG@5.A3=-+.00-+07-8/,,1993531017*'(%$&+''+'*(7).?GqD403._I/(-6)'$,8,% $&75,%#%&55$/0++./1C0/50@8KKNF>T8IBLITQI7@A>527?GF:@Kde[r8F;cwH<6;=79?682?D;J=9>.5a4C4P85G:;6889<;69:6;:>BM3383107888752.21/7YK>HO41:5F0'--00.5D.)(-@0)&-BS?7/3783*/&'(%)*46)>1+)/8?JoEH]02?/)*Q.3(((%($'@;36&*!"%(*0<<691//92219<_PHCFE^BERU[F>:>8C;;=CC:DIPYe]?69fQAb9;9147-,1HM]H57323Z6.>.4;513:=R58;669739@D::;5125130182735/12:D97KZF@>IFLEG?539783Ka84013*/(+1-..625.)-2.+@8,760),/-*(',)/++-C2+*.4NkB?7FD-0-,#$*+'J0)) "%#S,%'('$*'#$).P1D;02579175<021366A155079DPaB3/7?41($/146A:95N748409<3:D<9:;;B7<4/-3303:03793;8@6E\L?HJIDFLG;54+44571/3.,*%&)63.+5W1=(1*/3;M=:8..1F1(&*)2($'"&#'++*&.'8kzBBe;040//-101/248114@503<:7D>A@=583114127/25,'$'1*.0)-+52:62-0.51.=85A,C8'#$%.*(&#@&#*/?)!(Ui6:13*3/F@27Y)/9$,)3=  !%#=*.=6'(2+-*&+H)*-O5567<6TB9@WNEM>DK^O>JTPnAEN>HH=Yup{L@P-(,69::8=5:=553-723.2.*)+(/11/.20740B2,4.))062+0:6(;%!$&*%(,$"##)*-(**?.+-72//146*)D7322(%()'#" $"(444P0$#2'1(/:R,+*63346;>~<3F^JLfPFKLGACLMo>?:AGKUwxXJK4/456@89>@:4@O?8763961E=?H-/46517I::4f7<457204475I:4/2420-+0/76123.1114:S50HS>>6@0*411E.7K0023+01.5-7==67-+.,+2..-08-(%"**&''&" #%"$)',6<;6+A:>/3722909($$*+-DU$"#V308@N7=6IACKKFG\XKHIEHE@687>900I116:61<5Iaf-/>47FE42A6)09:554/,+?2.-110101/25k80,100288AE;C77jP9812A?NH>4214I,')L43L/)41+(*0)8-$'#$'%$(($'&'8U->CWO^=;L$"'*2))$  !9"%611-$,%&&$".7'",,.(417C:63:=AKAxIPJEG\HKhbDIdUn[izC;CJ_O157935:GM/-G34*,21:28Wc49::6B9<3195-2;;65/*(.-/..3284;..09,/1-.15/;G5E66IjC5044;?uBBC8411/0,9&*-0+-8+,@975202?/())04()$7@(#+,+&2>)0/O5*)#/19?TG68-1$,$'&&   &&)2 #'+"&$('&+3E$'%-3358F>U1<@B@?EQVJF\GJEG@9CBJ;[XLWbUFHOI6669337=2424N4.2-312.rmB-0B633=:?:4587<:665500/../2-.0.56+0,2,51+40',R4G5/,71&?-)(%'-20:6.O:4<*#4094CI7.095L.# #;      +)#0.% &,*$%')U4.%$&$:-,.:7:78=?CE@14?NADMTG`QHjABE*551:/<+)1-246,2/'%'%))+)192ZTR9-8J\7,*">L6/#+N2+-#    <!!+(),!'%#)* !#%#*,*/NVA/7>9K>?:=HLEDA>O@OAD>A7X6AGV[MSZTIV28I-45P=731K-..37:>.46C0+5bODVE?7@G?5053TV=<6D7?=;;@=2+..5268545I42* %77<5H8C878456;0)**,+41u12>3.,03+47=3;21+*,1**1;UOY_9/LH/,C+5''00-%Q$-G&#   -  %"&M -'*))%'$(&$&#&,).K6:417:455@J7:>ACC=JC=FEJXI59=@4@9EHYp\gD>:@4AT{J<+,,/;/9_3.:5654=51240..(4;;7;97FC55.1??:8EZIILV}G[@?856;D8522.740405B:|J12:38;<4k6/8>:45/8/19=?7,*,897[qG9502-=*,,'/@54N}SAC[:??0;-3*/+E3AM0*($"Q,  6   !495:30$$$ #! !$3+,,*)',2:361;55OR8485:?=8;CBF^uk]HNE,95U7)('4f`]oCB-*4(2C4$''46I8==5.1(3*+.'*+W6:-9J=@2.-       " "#"BG00$ # $"&)+3,&,20626-1343>;435649C9BFBNn_YpVX@274;1/.405:/657:('(E=X\VFA23(.!&8#"C--(1N4;'(%.&%.#%%*@I)8cDYF@( ,  -   %=),$7/#$!(P%%7-++2/+&)./8GJ-25;4>07@B:@YGXy{PPI31-/3.6/+1595556::21/+1>0/96.0007GS.+7(%:4>A8AH63#%!# *(!,3TP%-u%$&%)%F0*.XPSATi>7    -  -  /- Q"- '%$#&"$H"'.(&,13-/**/65j83371=5;;=9?M@ET_W~H@;+" "2;322-327:BPG7SP77G6<9?Q:@7678EE5?FE82=OmeYVqdVE7997-/05:1/.98@F;E:>ChI277U<=39;E05379./3CX0K4$*)2DJI?@4/'$""#.$*&' ,a$ -$0")'6,+G+DC*F@*"!"      -  $"82"'+!"#""$#&#.))(N;.1+043887..71T7235=38?GmUcWTN?6\pRICDXτVD988:402056492BCXF?:3Q55MK540001?1FK4:E424*-,@4D4,41-&*$!"%!"!!0. )&'0.&+&*8.,$&'"%&     2//>!!"#'&,)1 !'&$3*,-14:+;494.3;785974K9FhkK@GAI76513/426.0,0049lE@=6I737>B;79@<:<<:B>:9AG@84AB@??UbRCH5H980./74;?:6B@5@7:9:81G486650876@@J8@85@A;A6;10-3,.23-*%)##!(0#%, ("(&%,00,M7,5$!!0 )      !@S:A 3'"%"! ,#;&#(&*,./341/,1-4-7;.Q@:98:BCQAHO9G>54678?H3111/583/<8962U:D<@c=<;9>@:65AE?:AQ<6;;ARQCDgddA9B87::A57:=HOM>@8=;9;0816>84/5U?:H.395J4232+.03DIB689;=EGNYE;QA@8I;A:BPN;=VIAD7;<<<;4K1,89]HEADFDB1,60827.):+B2,4111.G]b>E<8A;?@AC?>Va1348;4DIE<=R5;E6501>H915><@982zFRUeZF;/2811)+B6+1%%*%&##$$%)(L&% +" "-"    74O8#%" /!#(+"+--B=96)39\U,),&//49=M?WKD=;C16L20/*;///5>>GM?FA8599:OThQ/-08A:?:264HN\>FE839S;:4<=;<:59<6bRH33::>D3754;DJA9=AI./,298<575573977=9274@=6@G-92247-.2.&,-,;,D=+l* !""% '#'"## 51%!$%$!  "   "(3_-#+*"&$ !)'=V>0b\=S07/,-1.A=,&;&$74^;R=DFBw]oCdof<;72.111U>7.;21/<>6;67464;,/237=:NQ6248@2:.3308?89IA9b>287KI:<2.85X5A\QI59>41*''.'(*2')0AA.! !%:3$618"#!&N0*)*$$%-##(#=        SY( + 5);e+)22U<3--.E05217&('"51;-<@63HNtIO`mh:86:00-I?.,J><8:40+,0./12CO<58EJ6<80+5456..05,2:6//1/1>74-20587G42552B@?5:6IC67DTHD46.3O;@>7A29,7,/'+.Y65FSK35yB.+&*#&EZ '1, &2&*&-'L!%'J1FB9C-.'"+    *)C:8(&kr)*9'6C3(-230-25.2%*"-64/8.-/BBIOFiyQ4+&1031)6/-E9K<-39/..10=C<677bZ=-+*.3'26-:1;8.0;21236803375;4996=?>@9CA?@=IH4C5[SDA6+#'+:C<->++-1'+.A-,,34:.234=tKG4*)&'H:4:9.-/)(-4+4627.14379:37E69<;D9125@01,;1++0+51&#)B'*:.&(*7'.FI,""3% 3##11/O--J[Io|U<8$%       %0$#G"$!#%)N'':>I9J|:<=<+'!)-*-3.EM.1L41;0''$11*300%+(*1()*'09,.41L/52,4KvT;:0')&+77*++(.4/<203.24130/559/:>8[>H8k9:8;:6,4E619.1&$66''(,&,A)&$('#'!' )A<;*<1*!% (%$"2* *!3"+,!6=FBDFXAVkID[4O!      '!%  *'!('$$8+7GVZWI6+&$'!"$ %+',&*'=3MR15A4--*)++50.*%$%'(/)'016+.-'*+12:?240&*'%**/2-/1,+,-0/2:=243/./4.;8@<=8FHD>;657]:3996=E54*(%?#"1?%(),'%"##!" #_0#9,1U%)&!& !0- "*E&X('?04;egYW^]\|g)!%   #$   /P$]8#$'033&*0:_cVNj9G,6,")& (&'(+1-+3<5-+*(2<((!"/+0/,)#'(.)$-+`+2-1+179$#)(%()*&&,>$(I-0,*/-5(*',4-10P455;Z91WXCUA55/OgD2.0&+,/0:G)%(+.4#&$#$$!#5(!''.8DS+&+7>14 (5#%#!&v/GpyUYPfZpO4$-&V&) '+%   - /!$&D,&0/2.#*?9lh{N:in.32+''$!;F%$&'H*,*,-&-P(&348@13;6<44;::?>ZS]D8B32?$i"*%?C@& 4'S';481@@85@353$++(#!%!)$(('!(-3!!1$-02"=(?=%*!$ $3("#&""#%O(,A1&@,/G1@     - -  A!%DC/(""!1R=-20S\L6T)A=D%% &$%$#'%$##'%"&$*'((#/&'$&21##+,)#""!/.+"!"&/ "*!&(&"'*-E-(80,')-6A=^JXtoS5,+0/>VmIM3H64)'(1 !## " $"!!$& !&"O"*@3=$>)# #/(f#<1.->!#$"G%&1C'-5'       !:r!!#!(I70-(*JG,/., #!$.#!/%)#-!%#$$#(&"&,(*(6T#$"2)"#!#!!"!?%!$! !""#&&(&/:D?+(:-186:ku|md722%,:).5.32<''(#%$.+,)#! :7*$?14<' %'4 #H?!''0,'*<%+!+     ).X<(7"! J:9($&RuYB+! 0&!+"$"*0!'$&')'%$!$"$#!*%@&9k"",(!!($$* 1$!.'"! !"%7?>vS.2099844}glO<-,,':,$#!)4'-8%,((('$$! #0!9P;7DO+&  (!"0'++2&(       '614.#!4$<0H97$'$+.  %6)'3%$(.(('! .) &""'%*%&$**"$ ',&! "!E"# # #%&!!A):'*%.4*-+<99."+5P5YM8/(%& "&*+$"$-*+%!'#$('+% !&"%  !$( ! /!"J',',+1N5X^X?')*79@)#0($I%''6 ( %7$"#)"!)8/$!"      BM. ,&)r&6O-%!= (%"$?2-F18<1&,$("$ $(& "%# !")#&!'!$*''1?2>*%8Nd]Y'0 8M6>+,;0!!3%%%-*#0 %'  -  - - $aS2 $",*^)8@E$)#4 $,$%#**$%3CSBE0# #"&& *!%5')""# & " .  +!6"% %$#%|D$#, !&*=&!P!*$<%!2  V         8H.$#&7)!$B("(1"$" 8#$$#1^C3R !%!!&!# ,383)$!&"!"% !!"-"!$!!4!# =',e)5 $&!(- $ 2)! ("  -       )*=M3?$"-*0*(##" %!#&(&$$'D6./N$#!$""%!# *##!!(  ) !!+J" '!'&( 2($"!# "   \ No newline at end of file diff --git a/data/fits/NGC3344.Mono.F32.fits b/data/fits/NGC3344.Mono.F32.fits deleted file mode 100644 index 50fcbe8e34dd1a9c946166f543e9a8df19a242e0..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 267840 zcmeF)Z?N8HS{LxBQKLr9XdL5A9nXvEmYGt*QZQhf)0M7vXBIZITZg{zMY}XhJG0w% z+MwMTUla@&;ebau;sFC5G+@982aOQ4YS4;dsT#Flz^YM;Mywij#i;eq_jBd4EnYp;{`?|0H*Y&-h=bR+l554b8PQCxV8ygRAe477zeB*OAKJx5GPj5W^{OOlA zzWn*;KJxsFAKN(d{Kjv4-{T+JcOd*-E$7qWl)sWVS)yzuPHr$72BrsnXa?|I^VAIk32#`mfA#>`VM zC({4J|Bb!R{j~Pp{rO*z_&$32xvx0$jQAFN&%U$~`TyPjjlFmOKiZ4@|L*_Z`^4k# z{nAH2t-Xy6{g~1V?WNOaHa_;$$F=3mQ_nuPar)&mr=NT2+2^18l>EQ=17Gqb@BPxp z<8Bo1`)waR{qnOPPD|hSv8TS`^v2^aKK0y7FFgO^nT-#9{G~IeKlWK0TKv?Rjb#1w z>5n}7-07z`V*6e1dFjlH&p-G4$3FgZ_R{=~VZZRq$6tE(%U^oe{TsjQ`Hz0($4+m2 z-f#Yb`!`--{_{Tn3x7-c{NXQu{^`?SwDIoa$3OQyzv(>>Jn%py^8Y^n3m@A!^}!GP z_7A@2OVZzWoqG1=_a%X^c;?K;=RR=afiL{*cfTw7e(3p+ocY~Py?A=#%rgn=%U?YG z)S1L|=9vWe*rUJWe<@?*TQl~>AARbjmp0!2?1x``>cx+L(Z;DSe*eb1ANYa?{tr!E zvs!yoy^lTr^jD^Izw7ji>YOOw{lM`x+5emE2S4y-ANb&-@BLu%ef$HbKKs!ReA$=2 zYfbNSHa_s;(|6%<7Z5K#|GQrb(w=|uZX?b-b9&?1>D*H`*ts!y`-?;IUbGFiV zcl-9goqM{6&i#J;vB_@FwOLvI4xarQ{^_55@baG<`_5vD-pM1|fAHkS-glh5=lr*w zd@?rgORmTFzkhi2AARkwoqYf6f8*r67rt}op;!OnoGU|qD>1zunMbbv@X7lx{ppir z9=rCVqkBGfKkL|z8V)N_1?(0v!lGwlf+yB_f$KUwzlVAI_zwe}+e$PAq zbzvo_CG$e+*&Ki8oBv>Ju_sP^tJt1NzVftx`mLWnNfupNa#Hh;zWuMJ_H@{w zf98|_Vf9)0rbd~)vS)Hfcz+FH+%3=)s}q0G_L!oGMS1D7!Na^7Egvgh93 zJ)F41x2F$hY}Y=%n9Ye8<>D+Caf^)&wG}siY<$;u{mEJN$h*rn-lgbg_D5b1f{Us1 z3z;Fkrz`FYsV`gXvM*kB<6pe&nh!B7IG=lavtcz;_E}f+eJ!(JGP~DdY7X;w`lAnK z#MxfI(6RL8zVwrf{^FS_^JdlK*Ft2>p83(w+Bu$CGYj-!(QKOSZ~o>#GV_yq56;aM z5<}{F^3|+6iNpP4nW@_0j}3D8{Fd;-oKQerXTRi&GHv%rj zB6s902m0;bUi!km&v8A;><+%+S^dB98~?!EtC#Ole2NL*o-VuMWn1mks(rvyD|P1A zY^Ygh48MD`mixg(=6hx}^E^0MW_U1=yA^ITD}%YK3&vnCIjwkPVXVaNQj4*%zu=PI z#o(K6dIH1dV({;b&z6-Ad)2`YriR#XM(g+Z^sWWt^;x-_%jdtlC0}_CwwF6K8eM0( z#{Ya~A6hVeEb&)Xjnxaj&50VzIWns^!QJv6jI4V)bj^|eCI1y3=<468`0f0_6Itu= z^j#m#C@iptZ_e=9bw>1&*ixhU9zf1qm}hhNJ>T=ER-Zk5x;v5Hq3Xhu80+6%&sH&a zw#1_jjj1@0XXAn+dgc|sImoU4JJ-!YzQrJ!;$3e2{1#XB<$~m^PH=``$O>2R1&`}* zinoCbU-s;i!?S;K?cK2#2fp~)Be9dm<3|i+$`dbLXMOpRANlL^JwQJ$q$Yc*P3Cwo zFV?Hc*PDk=7f)UK4%n-m`m&)HNL}%*WYq>=zcMF-qg%`8AWU3I{miTWr9blq+zH;U z2ZQlFcp#V9hL^YoW65D~tX_$29W$^p^PgUfEM3G7z3s%YAH3#`o4vd8y$9s7PP}61 zoqcW5PwXQrRyue{j5kvI;CH^8yO*<-&h32f$XS18PnQl#>?0=!^`aM>lh1;)k)aRc z&t&a8VNETk#(boX(+j;zZD+4<`k`-l=#liu*`2x5H?v|jr^n;}zVrvrYW~DRmo1oL z!=2SEnm>N&qz|Lx^MpO~c{wtVEuU$8vtczi$1*F8&593a;t->Ia_;yNk2<(VwO1W+ zA^iGqZeH?a53e)JE?--zF)Dt0~a4 z_@IZUj(mv2XSF-_=(P6Ee$PV3O2<7}_RlBBo%9Rd;or|_ejX4{W_*YZeUcNu-T=1L zSUp=)K7FRBTWfCqko?tI4b{g?-iocPGdIpRGw0^s8mx5YKLsZjgUh{OE+p^4%6{+# zM=)tc`Q>hS$#->kHJIarT}0m58-y! zRp0c6jg7?Gm97~(mHwHt&Wahve=_q#mY@2T$1~|IduGB)_IPkeo-I6Bs$H{W&QiyT zr}t(>yp0JS+2NB+u_*^cuCdw6*~-r!|KopRbe!3-_RX;JgWRF|5U2Rqg%>%<58)xT z5kEO^fPB|;;2$66$kL&&{;$S9eEpTb@>d7@?6eksM$dc=pI>i-9#mIs@caWm@PmU( z-=oyfy;$K~Ovs*Z*yWEMH6ds9hVW%I!``F*3_#x7z;3@Eyq4a`OD_7XW_quN`l9xD zW=}2c%?UDZ<|XT3IP<@n?d!qAwaj~B7z~pO4G-Qf2D{dq!3deX;A@dx*&uTxaV3V~ z!4jG1j8FRLl?BIaq;A7Y4OZ9|mpih%vE`1O`0RVnHXk{UPyW?XevQ*ACOq=Df?qr~ z*ps)jwfo4=9hpVm+z#%unz8vzS5Gs1BtF$${ngFc`bhet?(X!$Jdk073?3OgeL|J> zS!bqx>Zktxre6N+&;G~xp2!9)vQgWOgPqiC?2tQ=xnSRHoXX6YTe?+iw~nUBi${!)CNPaHex&&BwKIiJ_ov*|0$qs;2?<;t%(tDr^nO)dD9ANj14Gpw^u$KD2Zyu5of=wGNBiMFlG>}W8M`ktg*Fn4d9c_2pZJNtxB7h06TO22WPc)c z>il@~-+Jq(H{bW8pV<73-}zlLD`eQB%fGilEY9ZPv0#9W+OgtW>!T}KSh0%Ptnmp` zbj*%DpGbamk1x2iiiI4$w@dzFac+#_loMNcNL}cPi$43U6F>Z0&2`V>T<6)dDfUx& z8=8kVqHlmTb2n#lV`+$zk%$Y)*V) zi;v=bR_`Cem%CLQ<^rkT3-RYI$eGO4GIbu@tE+mN8FTzZboE^x`eQ!YA97^Sz3H(Y znlXGbvALRk_VQM;*9$S3d*N1s{CUHCCmr}2p)AVCz+h+~u&0y=+-MJ?}_~~b%6~RO1Vm^1trbcKm z2!FxJ$aD{Lbgl-ER`>Aeo*e}DuLMW<>?NNeeDZ3LT;_8;u@CMdKW`PgWI}^Qs~Iw* z$7095Hvy5$I&$U7X}KHuMP_1^pP1!C4-CJpCZ=9(K%yy?Zl9rWms? z4$1Is*398A`}(bknSXW~vy~34)PH$9nJ;mxf!wTQ=;Mn`P0S-5GI&;Jag!G-a@W|c zh#hiP=g$2T>Ak%g1yEkhvIa!d-Dn2ll;>K9AXR z);l=PJkPs9$LBUVy|nTvE;)IZ{H`xJm|nu~-rjfkI~tqbPJb68{x{WSKk~Voc)bg6 zB>vi~Z+#Pk-0|cicQw*Keb95%y0;I@49}ZjzhG=I75Tw^W?$b1D=?6H3@(!IU^y`k zey;{^_V~ydhKhY>I7;4w@#Hx8zZmQ%$C0;3>M5SQRV)03Kl7mua%3mAcP@E^_0(PfjJ>WiHn{%enaa%NkO_37T+@k!5o^XE)QPR)TH!Y9LD zsr<%M`#pL)znHx46s9YKmM;K5A$~^ad^k=;ay+U-}i5I!l!Ev z=)$<#|C4|6Pv;GR{rVz9r~Y=6|4wpb!+W!ret9!qOT2u!Del!!Kg@<$&H2s99Zp<_5{KTPoM-;ce(qN|AnUtBY^*R2&j{X2&hX|O z8#8Nq&j&mwhrzqGd$Jc}7v@s`+4HBrkL7MVKQCO#o}CMsCp@yZf>XH7S?uGNO|dU{ z9&EFZ;6F1}Tu%+y;Bzfzb{p^H+}T$v^Qul_GgJEK+_~0ky)c7h%%GYdPyLW(tk6B=;D!Mi!6OScj94(PcnGLvla18-Yke!@7o(aWmnwh=*iSw?P0{c zu*p8V*5L#iMv%&aA=}%vxW_n{U-8-vQ1iW;KC3*xXAluopk8 z_r-evr?9`BIm?RB>X~}MW3dnO=D`eyKl2Z(;dO83`dPTbUgl(QQ!J9d5&U0WFnlFC z&alJT(tZ9I5mCE+KNOw+p7l68(9j%{$$$ z@-+9(jYV8yq!*fd*dnJ^_GS^83!ek#T0Qwzb2F(Q?#zlFnQ8Sle`c7BInh&mm_Yhu zHP3wXOx~QGN-plqJezRbm8_buYwg({4vRH=xyvQF56O=$I+b<56^#2G6ux^zw>2PZ z*2Kh*eOI-h$1huC>AA6Fhr02+jkZ|ob`>IzN))bE%p*m_heykJ2k=MpYLFM^H+b<&U|k3dp5N-3-HZ$ z=U^vwq-T!c|DXM{e?GrM@LsV=k54}MeJ!=!PyRpiGyiga4*wLvus@V|^f>b{xVjoV+`5aS6&A>v8!|V8efKb9e=WF$x7-hJInQ?t zI`PrZ;Q8E7K7+L@c_UErT;bmxT;5L2*b@ss*7%aoyi1v@u}S|<>d+ZA7knna;V16e zA~QVkG=6cLEpqIbEpV@9u-}%&7AIz#bZmrFA^yah4 z9I(p|J{j`*(OR?Z4(YjhVo$F6h{WVx%=WO-cfy%`{7enl<%hmKUu5v?t=-FyUHbLm zPJPY%6ZyQc=ePdNnpqb&J$x~e7Z*F;gT~by$lModSQhJ zdw48v^bcP>yLw;AIPWDEJtU9xvES!?zur#mVDnshhuq8AN}e5j-wnx{4g9`AeH+NI z>w62I)}7Rs4t~EAct8A1_GW76yNB4C8@tZr*%gNz)J0$PsB8PBp6zq%Zl!M)VeVRV z7u=35eahWnCb*n8V!`NO)Bfi2^TL(*PVeUox3`ve;%e}_e;4;-o3F$%xW>P@{A^** zUP$i;<7>P*^TjScyKpNfd9a!D+&4xscOSiZ2f`Z+z=C=nNKtCnGL=w(0Q)L+rSdD}6rKS9i{A@K2tN`V&8y zQ|YrACBqLNY*yAD@oOdPPJYg8*yFjo5Ig$ft=x(4-S{ci$|V~@O5dZ(sj z)p|R%fPJ{Xm^$qxPWUE+&n`W-&StLr{Qxe}%jq?8&o-jt?0df$*$rMMe&4-(--kna zxFf?B+v1WVn{aEzQ%kv6*K4Ep{HbC4uFq<&M|z>|YMH(d_WJo?M(xc5ELhF&&D6@8 znEUxUScJ2y!Q`#r6Je4u+H8ddZJ8l-> z!93BWhl+>9KlPIb|9Vp2>Z>2EdHcoxeVGGsx-ap+l{hcQe*0-PV`OSi9Q65QOYH9Z z28hqTJTl!|Yg^u8pwFfm7K3~1GwDO~Wse=Xk+qVk4R{q39&(THs-u>CJ&}3uY}@Mr z5(}cw9(nWbPAmvUc9R1P6nFSycP7s^UAD!ipRjH923Xb9-sf=N7T@35>D#fL{<-r$ zuuYzxdEnC?!K}FWb9X6u`~2`b1o+SVZvOn}`uyKde&TH=cb7)qqD7?Xxy_tcT+xZ*~Zieh(4Bd!d^5x|`_+l@5LuTRJ-Fb&` zz6R@8^8G#e4Mwj9>#5(Te8%tPX9F^ekBK8bLdM&jP$CBId zucycIUg93ReG~B2)$FRH`7#sgXRbQ?PbBXrm(L8VJMtG&TfMgL9MUn@Y^pmxImQnj>;PJM8P*{%q`%H4CV+cqQ^|vVq8%C)Bva z0I%jvP2fQ+<{IwlRK_Y+e8figY^rg2chS|%3odZ)rKCDpPuNgp2I0} zHgkG!Hc@BNdV9ftR&w+C9xTr1@ReZn`tmtV4*yQ#W0w#3OFSzZ$#wN-0jbwu{A%iu z7*=nJdE+O!_p^NB;V1Sdhu9sPw^EPP(SES32lDRBnt!w8oV+I1=2Kf{SgcRRwz$cv zTQOHW>zz8XXCBD!M%K*X>9xM%cTU;XC#&ADotjRq#c2kd`Bf|T`XC;?(hL0&OM6G& zJzjfB$9-4*XA6-<{5Lhmtvy}$>dT&cWRFh=(RW6A#h-qVWvl%Yr#-T#2U~3DrCjxMFEz5V zvzuC;OFz5`FzLI2c-*sNkKEHI>yBN-ZheYL>}sc(!;?M965Vq%nn&{=FnNJq1793Ef~JJU_LhIyMs97 zOD8inpUY%2Q^osyK3~bZkbGA-hs#^}Tqlceob@AV91=& zGehLWh6hub#nPwXjjWt%kL}K&c>dde`|tAxTnXOym+$=7@@^#l!Fci++-J^LpU=1Q z4v@Ke_p^QWx9`3W(_3@tXKp^@Z}1#>e#cg1i~GJ0Y_Go|=6T)#xbK@GUSx*kuVzS{ z&4gN;HTUMvoaJY=&0qURb~k_Bw|wjTESG$y*E^|8u>c?Hw_aN|))B0U5T7)nZ5<#jKwAEH;DeB04Z)-}u z-!Ob3Ia}cz9?bwbcwz&eJ$CS5nojS<#TNT`booQ}jhA2eHlsI__a}2_zJ0Fvd7|&a zc6vpQAN7%2Ya{OFjwfFve*MsIJv8h3*Iu@tW(Apttn;~J_LlSLnuYKN&%x--W@k3@ z-Otq3DwpW5KF6=*4Y-ld^^140H!F-gM|SkszZUFAZe~{ueS^d;9;+Ei>~vP&L6X}l zZn-ojItva)J~~r}*q!s8^d_=X6LV=t|W`0`O(dn>*enu?cCq$K=Ban^TTJ5j=S5gW^z@T&*oVEwN|!u6HoOC<{^>dIrsg}Tv$udQ zyZno6a6g=rfsO%l^RfU0jdpkz084Jv&&Q^YwgxmyemEAO7HfKi>mT z@|*LOybF49Xzsd ziTE_@c&!OpXYsLVC2K9orTTd6s*_dz_Tu7`4YKvG)@1m0XLX18wW=e1buxoiwL>mY({=?**Rm&tibo3#FM-R=f!hu&iUHi&-B54;-ByK$#33(tN9K9+ri{~e zrbqs)h5z0~Zv2Q(4dszo=6&E3Rw6&xug%-}jvzLqGh1pYPqOaF zx>qAVr~T*u{9jJ~yMOoZ{fsm3w7Pe`)mDGlprfWRh>9h9eStZ|FWJ`K**oQo-ALMQB?d6=l&)$k(e0E;R z(D8FGJN9(pla5u6-Vn0Le0S!z(-$`3YB%+P$6{1(*hBnT#S3?AvX4i{%9lMN&j+lt z&vtqJ3>Sy{z0~|%=EC=LvhLZSFBW^U?)X6N5PshQHI%2=*t?M0UrG<&NY0njzw_w{ z9)IFN`0B+69k!jts#bE;E2NKoi}hJQ&8nK{b!U>S85fT^usWMTv$wnjgQWxU>yGW% z8@$~~Ua{5B`LP?B!TNq=Zr%NJyZMfABR>aR$>;vX$cM&0KX8^f=8X}TSeLhD{F-xo z@#EiKFr0YCz8J(RKDmh*HHYT2*c^Z6k6%QV3_6xNTiLT`kBpe~&Yb0)TFtPYZbe`1 z#fQj>nGdz{Ug-rH_3b-s@4mk1EV)kJa(1tO;&5lB$DVt!TAdLY{_V-N_jv1m?cI@K z6Vb8avuQ>6>+?mIUh^?S@|G_i*<#J!jJr3hY6u(VkgWRotgMWcJ+>-;AvG}LmA#nQ z`W~^5UySif&)R))(zDO&%5SI7{hY=twya`h8}83#2JC$n`xyWp#o$i=-S;zJe$}5t&7Q^){%N7>WgZ^)!p;W5ay9(<3z`?+ico{OE(8coxt25okUcT9bzw*r!{rabe2kYk5 zis)^n7cfGXZFb08@yXC-OHI|<-;pVH@yWU)%LaU+>Z@@vg0CLV?i-^$Ik-anSjnAB zFWAQG+fY1vGrR*0^~%iByfRyBwB5_z*>24TtyFWIkfMMobGB?q1EjtM2;_pAY|1`0dA5{Oc_YkWp(h+@8=^JMpR?IeDu$`(kqD z53ldAJ)&=A)7trGXWce`?)h<7;-hxN=^nn__pY+|WE-!&J7@k8eZKnkxR)2*<_$k; z@kVCxmDKlz^vv0;n&o0wulaCi&jwOc^Ig2MLC@zTT{RGcdu#DpO!W<5*PZx^7dp=8 zGCPP(dN5s|^#Ql;tmO8B8DziyevrXqj~(&DGrrjC!=9cM@dux;rlx-X=lg(vH^c{B zcGQkt*vGTCs3BoD39Om%r~M-=TK~!?Sr{9OR!%|!r#r*4j%BVrXa4X*j(3RjHB@gex;4-%GMxGyYFK0aUK9G8_rB;b)?4QUTTqM5vevm!> z(DnSj0o};EvaA!I7};Sj`>`WGgvYmgtK7+Nq~84CHGg+_=Bw|%9>mxD+09O5FQhKk zQ{kz%UYIXuJrKV-o5RkWewcaoOJv1hZSUxjV^dGtV|z2fHlOTS**8;gLXVuad-v|x z6JKK`CuXzQ*qn<=e#j%T^onyldo^%}#HOEYcyG?8?y#U%Y`Rxd{^*mn7SGK?F6NwV zcE}?(^nn~bXEv(qDJv>30>=<7oYm^Ok!}>3;y9s z3~IrTJF})1yUR}&I42!GzxQDC#^q8)^+{=aR<;;Me zd+2(r?8&>+6Y=pYA9X|KMPJO1`XaL!-OXPSJKo^-7XL`%>!C+z;EZ@BQ zeoSnMWq!60L*kqm_!nDj&(8?rl>=X9j1OldZ$w5N@Wf7rPj=~;b#>Nb@9#VB{MY$A z03XbEwEXY(uDyZ~x3Psw_QsZ0p-r;&f)4jQ)$S ze$8F)VUI2IW^dl)Vbe#x`h8nA^=2FaN%D}A3; z>ckiSYJEQQLZ6)8@Il5NkF0xdAD!Cc%N>lvGxDC$WtXh;tEq{f2YlAB(f2^kYSFq_ z)xNW4t~x{Nn$O_*b8Gd{H}h@&$-#iL`A3Hm*Ma1GFmcm`39@=(g%$WGXHQNnbm@^{ zGkkcjTroOt!L58=!}Fcgfjk??>{!h^f8t~3`toOsx6_}+$Gj!%FZ%PYEHR8-x?)5y zCsrgjXFkX~vtf_#+}t|T`gSSy@@JHrzxfBRY<|{vf6w$}KXo%}>ThP$!3@cRuKAJ& zUobBwtGlzwQ;*cxxmd?zuRWzt$GuhmN^F=p^TbzYnt!o4v)y?oXO_*+<=E=G;hsL9 zbnu%`;~=vhml*h5>@61Ov3#YyAfOHJw6 z_ub)jzFgR+Rh^u=xV5~OTwWrH&@ecd$5T4lh!7q_#uQh02_>?1gy529i&EGkh@9x)A z8-L%A4E@%9y;ov}<9=3{FEiIS!HoI7iQwP7lZOvv-*>^CJ%WjY%kSW0da$t#gpW1kZ~Gj~%DJ=jZ4VBd`B;gg9$ zy^%Sl>%H~&7q??y-|_X0eVDMw(OOo*>Nu_xP{nuB{jyfyBf#URF=%mu$bf9-vDc`dn} zPrvBHwv{Y@W=HSwta3#C8G;XSh*v-O)qnZ&L&rOPIXUL%&iVYmo!s$C{LnXBauKT< zs>%9Hsgt>4A0M9KU(KwreIRk-!vPGy5j?o-nGO8j!53nm9$TH?WflhOi_T#8TD}Y1 zSbkr3efjJ<@n;7IF zPj`5za#porSKsAi2J{ckVZOM5Gd(b0YDnIypL!>Ez382@z1|>pyt90Ce)U~{)R3Ld z1bMpbAwFS1T%B+B&DPoENUw2sC0l*6WJ=D+{B$1KF@I)@uin8no8-utb#|;|N_^Rq z7r*+zFrw=YUg+}U@4K?02ITSdg1ob}aaUjN-Vk^6_;4pa-_yh`MkEh5x6^Mi@#S94 z$kVN##z;@yo!NtVKUcslJLUnM%iN&Wt2X&8-(Bm4M^FCj^scos5BwswKJkekoBuwH z|F-+9xifp-7P?3c)kf}g^ja=v%Pg5QGi~6?e{LVdX&d$>JYNoaB$h5B|Z_ zDk~t^%^^L#JA{7Pn(-O`0VqvM!f^HwFIIN=uxCTgNK9fU*V(KN`P$>(o_=+m)qy-4WZ;E;x(N2qr(drH zo6U|4J zJ3JKsR`YMhVSua^!Fc5(GngUU_d$#Z-Y+cv=+jyB2Isfavjf50t<;Y{GRt}Odp&uH zu|DMj7y8ZCq10L2_R(L*@w^$=^8MjX=39^0D7N`(j(jGT`B{N&IkKrb3FV^==iyQ62%=T7F7Eqw8_ZO-&rtoH0*$PD`q0{8ZG&|dH&KmAf4ZNcPk#b_SR9 z;(PY=4(7A?#`1H(vW~stkBnISyd)p~qci^FZ*Y7kdB^{Jf3Q#7D_@mY!@fCUUE*HF z;VgDJm=|?$R&PBz7u#ymKH;mAS$0X5GGLx@bFjkUgJS5LbC!&67Pn@t8@UP5iOz4j-nRt@5@u zkJdmQ$XPt(y3&=SnE5c*YGiM9SKDONhaL5C$8Ps*(J8*ww(@vnvO_WHg_(EdmLrhk>#WI}|J8&xxyw=dlzWTW<_RY1}^n?sw>L@PXM=k_^_~wgm{oBv{ z^=A>^W!U6PTw)fx*7culglEz!mzU#yc>}jK0EcNhB=Q-vTCP4 zVwQ_IVOnj(K&BXHgDpHn)?0x`wt176x4I%S>Z~_rL*L|Tmh_`FHxKSQd)uj#`1F7s zanf_o7JYlGIYI2X(_=Wq+e+MIoXvw3k3X{2H7CyH+mnUq^T}21$m}IQI<@0%z@uk1 zul$SuTxx^gyo(2MBXzbmFLGin-dYc_xbt}?hn>`)|JG7Ih(EEBW!HVN*gwBe&tl%4 z+B);gu6Uj4>y2F4ao;%Xk@rDu_~ldF_1zw`L7!dyAn=K zuT6XLvxVsTbAPpGQ$PIsp!N-qO)-jHjB;g<9T=cv55Mbgfq5_Xt#C$WBl7S-r?|jl zSABg>;s?vK_B~)vT<;`qb;IZX@ZFyqiqTmQBu~Dq{L)oZHm%WF-P6Cl{9eF%CwVS5 z2djrtTl##ef!zBU%ZGc!S92DdxseAM{Po=Bi^PxAhdk_CJ9BEHkKSV6{nba$^r16m z?vQ$Rro030^&8&s&0pt8&;7Ti%nuoJhMad2Gb$c0BsR0==Mh-ypEX=c+~mY(_O_N; z(IY;Q@9h_pKO5xOq-S2mRR3b2cO!YIF_Ht4tF<$z26}<)o3s4X0pB|ze|mgYpDlAQ z-r~kemL2uBl2dQ-s|%Zrg%395P7j#}InZ}s8}8aGdwOzT&#`;@;v&bNJ$e51jemP} zBr9$?!#JCMZ$PJSf<1nHwr*ytcoQo-Wc9_L%jnhRV1_TcVvz%1W*?s9i_ELJgIRX_ znP%mKjQJ*aH1+D-A4*)X$X4;`&U@{5wZ&1^!DF$`hq+>t{=t05zmwnd-M;%X_pCWj z4}!P(OuvyF)j|9RQa8kZ;+gwf%bx{io$m;-Id*$)tbL!@f>)$=eJjL>#J<>=Rh;70 zv&c@|Y_aQ2aHn2Kerl|qoh$R9|9Yek`k`<7sXvX&%)2)qbj*vK@x;l7*$_V>XT|T{ zEWx@ym~XRSTZHfQ4Seuz`-Y`VjD zCL?w^eL5nezG|axYGF^d?-G0JQEak@XC>P^I_#-MVx9l4cYUfQa;9r_)(@l~>|341 z!md3ze75oQ&nic6s@jQ_P4U#0_?lnqV3jY~+9-~#Z0Z%=_MU%s&6Zg+H{ufqIX%;# zz2MNQkM+~HqqT)=w%9=CxOUC6^U>IY`*rLG8^!D3Am_mm+@M2=n?7ub(c41bo%aEL z@X3%3&F}oIH`e~%ul@(;^Si(BSMiDUU}{I7Z*~*s>hqtC+vy1zzEJE;tn!h+cj4Sx zoZ@f?=WHS|st+C?Rz%LdoY=;bt2eMSVty{Be%5QL^KSIvP>1XOkTJ z;-EMdEjsPjj($zS)r*Jjk=P!DIhQYR+fnT8G-EqlWa@6hmX@ z6R9aI)VBQSluw3#Jo;=lFSahH&*rgtk)i9ZeWt@l^VMJSwP)Wvn+qL0^(5E$_0pLw zG0W8q!4)6kwCW|yv!`#Df)8gl>B)-^y5fO#dgj(Fo^`Nr zaQXAHd(sy~POR|rvp@SEC+|av=|E~^VKb+i>%h=5Qta!0Iwi4T5`&K^VZ?63r zV9tZPBX@saFmKYGav z#K}>MPCZB8^ zP8^XPBEufc(21S-{7=mDT^`20uXK<&68G@P^2OGnycJ~g`8t1A$8O|THWK4}pJ;4q zEI)b5rTK{g;i;`Ui`l(53|}18@iy{hbuSk>=1JbZ1F+M1-ifRl`yH*%VR7h@+UTcV zb%v~T^$9t%ZEozz(x=BhJDtm}KKJ(${~LLa;MeOuExYG42K5uN7iP3RlKCmr8`*t2J^GrEyEtx-*doWi zyY_<(b+R@_I`SZE7CHwTspFye=7)^9#4RVf;_B@1)wswN>*7Ps-UN5%9{Jq&KEgj= z)+4bC2ZvL`qp6?sfyCs_8PW5`_`b;wc|5VYr+YBDH2&}g(~IB1^sT!;&yQ{PLn9*} zzC!bPAN-FUIk4-F?49NJ39&Oa#OZyE%-rFNL0tTb1&%K)`^Crb#4L6;$W`81&CG|I z!w(-w-Nb5^&L<}Q(P#MDN}PH~hOWN2w{FL#UaKFQsPm@(dMZY=msr~4-l;h}nmOy0 zR{E&DW0!xn_^qDU=!;j~t$g9B1KH*;AA7p(xzE@8l8etEvxJYt zjhX{JIg3dQ_~zEhB3)N9^RjFZLlcg}nt_Wg#x`b;0k=GDvCNO7{_yVPv)l~B;j!i4^UzuR54Lar+@JaJGx4}5$4=~x zt;kIta7(V|#x5Uv4`xQ~P?-hReH+gdO!{8()3TWnT0EZKvmY#&7XN z-W^%1v;9_PM*M7h%k@|9=($5|S@FcfKH{5Sd^RfMEEi`n(7{9I!5trF+2^gfLgdwy zJUu-WYjdLm_sHiI{KLLER~K__e=PRd?d)%)o~YQzKOA4yqlw%8-uU%)l-NM-g2Q5d za2Na!Ci9t(-+jLijGy=#zIi&B9OTMh_VfDywsRhPjiK>~A@R%|-}LF3&n1U>C-7ru z_K9P1kvEyMxr0shU=QBaOpo#PUtjga9?xD6E=Jz$yEkikV?NerhCCnoNyojFjJd$K zvbmkS-La>?@cT|?ub&^V^+xIg(|A6geKw1MtTQ~i_j&DYz+($uoM8kxpHKd9Sh>Cr zY{4(x(B?1ry=Ujo6aAUuoB3}a{KoJ6uFZTN&36m$g*Qbl#Dv7@O)AFCeEq?!_rZI_ zzEwQtSpI53h7KEj3(A*^yUN1AZe|2eKI*9E`k{xgi|<|^kiEL|$u1jo5P5fc(B8pQ z_f~hk*K@suJ$Z@CUcTaDn`~!Ce@kMOzj%;b%`Uze#LbpG%qQ~hh>^Y4h7UI7BR=vl zUaYHyv-dz;_z2e1$H9ZyKbjcutbDm2X4#( z`Pkk3g+mZMvTA3=@9Hg37q~S4^ysLoIo?bEkQ$N`Bm1beRzJ0dJ2+Bfw#cY2 zT|Fv~Px3Hjt^O;SD}M11J8W3l#)CCH=f;f>qkS99g7dl^{^ckZF^R>>29hIr{>`Ns z<%=F$R<%KN)e?`6&oKCgce=xQV@2+vMBL;D@i^$`Pi7Xx& zHBgJjFE+ixXJ343`%thz&b^wb@wwPgCw(O24REIqX2rev-itr8g3mUdxid%Z;8L&k z2hQo4Y4>_<-#IXg@Imfo{@d_h{8wMw{DOQ2|EkEret7f01Ce|;fBm<8`}}v~@&>@? z{O>w_GH;Xj1g^~lJojDbcLnjehwae(cg*}ZSImVs0nrtg_X2r;=*Qmt_v+utJMiZ|7saQ}Mh$tJQ-Z|5y=_I*S?Y+AiZ%@OYVou%&szxHZpg)ehXRvmZJS3S`iHFd9! z#gKbv^;J)At~)&P#Xp;L$?Hk)$ZcmH_4I6Jio8|N$&htsUrzKZ>mJ{|&jfQIW_vS5 zuCrm~tMNAG#$kn7b4gDQY>TI|%}dSXBStfARvQDX;+c7G18l>|(Zua@|9{3YJ|4Us zOdigM6N`P%FjjKM4vZa2ZJg=clX$HM?*4wx-Tdy)43k^GW9$Cq-v!0TybHAhoASCh zIkHK&G4r|bd`Fq@5-=># zkays0YK45qg-3IyXJ&CL^+C>E+f%cmr?3c{$!&1$a~{r?&-%?@^M}8AGd=Ykp`Y>d z-zI~*60GqDgH~r4dOfk4+c)yRVVd6fJI3?BW190|{7UK~-o4a|zsQem_iW+4mfZc_ z58pw&4c?tMllxn5{q%fSs4ZAW-W2bLdZ_Du>TKo98)cO}3V7ocW6N!4t z(T9s*Z}!Jh3wvwH{h|1^9!^fEI_$8)ADM&kSsCkn>DhtYAsB{v{3Cb&Twv^EKfJ^^ zxOZlM;jeh~9?uLWzWI4%u`{{wD-N;qaU%1?H!RxA)vEs95odKp>QR!9w-SGSuZBpT zdfLw)vYkcq;9lL^cl~M~%s}U;dv{yOOV7}Da^FktFnTSv--)lAvFqOfz&{MZNqF<~ z_a_q*EM8B%{@Y}}yTcQn6(-=ueD|~18^Fiq+r+2cP#iGo*2AI z;uIh3qqp<9EQaj;>@vK(%OeB(;$V+$tDNxQv9T1#-T<*%%X2OU;lt;<`Nv1zIA`mn z%mO_!WMNa@d7GwoWV{=R%kMWwzOrnTViql$oe)u)}2=>Kj{>`-6x1xLE>%P>@ zyHM=F9Sjx!R{r4|cATvXuIF>tY#dxZx81XGI5{I{KIp{m$eRiF;M~2vcw%FGsR3PQ zD}C{?D`x!qpo`~B&MJO+!Y4iXyTj)bALh?RSKZXu*<0RvRbSolTTiQZ2=47W2RpHi zr}l8vetUz-n4|5)wv~MJ-MyLAJ3Mmc)2z`qzc8ZTFbN~h{#+oqpU-UH+Y$VF8{pAf z0Bi7UHRt@mmt5`ZgFkaej!!Eb_s<{sW7p@r9(!-t_byyczq|q7DQ7z55&Ziz1K&^B z6C*jXpjXoyvBG}w?@dASCUY_Uk~dkg!?GB~tJZRmi?e-KGGbt>Z&~p{K6jgDfn7SN zzSvQt-OMB(-gAAT@2r1h^bhv+wf%Juw{*>K`)tO}W?tE`IyWA@_2!77Z;zFq+LJ@y z4Ziqho1eZ(c;?Q1SM$c7nS|f+`+iq=z1@_wW$8Z)4t=wz8P?jZ!XRy9;EL2y_J~E2wAz{JL@sbz!rJ>ee=yC zTYJgFTp)8|g_Zrp>U*u#AWYo6EmEP$60KB8_2LDKR(IH z1r={tBOULJp6WNh#j&@> zTS6Wt>6mwV=7R0>nO8pPkhSWCwR!2mgQ*Fu!T~>Qh>vYCu*EhWUx*L$X;06LnQ`-N zmf5q17uYlV_otrr#}X5QCoBHFiHoe&*&gN&B`=?!Sy!L!`0S9O?`(y&1NnV`ocdny zk^SmBJsEMb31?#W`C;bO=6L!h26Bt-c|XXijad{E|76ug{p=sj?1D*a62WA1umt4Qc;=!&n zESR@q$UMVK@dP9A03)#N-X8Vy)e0|rsR?^9#s*z0?7W?K%SyIymN!8^$iw{`sh3>( z_W1mz(>Fz&WbomiUa`LZb~Sc-bjXN{4&3A0(<#B98p%tJu+3@+p9z8fPi!gM5>cAe%z{bJE2(Nty;09jcgFNiv zSz(wS>Yi?Ftnduqe6dYNF7}Ju_*wi9j`^48c4T2weCn(BJ3sfPjD0cWJz3e1tG9wr zdi41dFZ?=_;a@&|1NA{o$Rf4Wul7Qn)lVJuNzIXXU|HYQTm8w-1p&mdPOU#fv>V#Yt_! z-sQ{$y!JhChFiFTB`b{k8Nk_|zBrIvyv1T-|5oZi&bjXZc_c3~VuyF{3!Xfj$=kDO z4)|JsE9ACRY#}+&Q)|@sPo13AMQw|xV$dw=5qb5u$AcyFWCrv;eE%EW zn`TX|$$KZ+A!9Z=C*BxyrT?8XJ$B~9Jw0y?d+1bZZkElG_lM8Qi3N`jG1Vu&c|-a~ zhCa-}$wqv^y8Sxg!TYhiEwIEU9sbGPn|i@>a6DMFC)>Bc9*?Z~hf|nebjB7LK59$t z)#v@`vwF$homlu52Yc+$vm!aUgJOTya9kXh#k-4_nwE+2?(zAED^Ha^r6 z$-UUuUp#L+Z1tUYhI^~tS@qm(=(`^4Uvi&1t1aE?>}J+|M}S$g#P)XZ(a#dP{E`!k znczb_X2iTdlAMpnu9;JglZ$$kyCj7n)uq`$OyVWh;km&=VLg z;lUR&A0_=H>t3D7tFJk?x0)IAV6UgBa`3O0^zE&3U`wyeARp$JZ#Fuo=1Uyz?b&qh z+hpF%q`9|0mEOPxj3O9>&7<)NOE6>INKM!%ZrumZEBqfx{CK^GcV~Ki3!ImCV07)> z@#*eh;U-0RO0e!y_EcR zQmc#Um06~9HNGwdNBV>M{SQwMVGb4B@B(}KMaGOEJhNr4%Cnjaa(YFlGr=}r zh@Q_5x;|gv*9`UD!teZwg)ehwj;*DBW~o6jVqPCgosK0}bYE(4Phx>LxGL^o$=UoL zO5FBGmcN^yb+8PB;uNp_fy4#th`bfX`SC`u!xzfl&;Ro~0QclkFS?8?=Jd$RnO&=Mby^E`*IPI`mz;}# zJ=TA#*@8p!Y993VVq&MWpZw?}vhFV>KXXfGH}!fm{>j5}-;dfc&t&;}ocvM_G#9uD!y_)Hhq&D0F$?fu+vCm4A=l z;HhL&V8vzSNJTRVAJ_XVxbG;hZ5h>#DFIj_izsHY~b7D^Myx`jC0oc zyMg8c-#vTckT z=EltU{Bq`x92&JEWDz^&L!aoFV;F#;;|lak~?vJk&!S_!Ogi z)STR*%3jLMs5w$!eL0^wRa3Q5FMU$4?$wchvTCiy$h|qye>gW!YOGi0O5OF_omp|m z7dv#>;zz%bT*QP=mkvLVB%j)&M@Mb+oP9BnN5#B(HlyYf!8;6{h+eVOGagJIOAK&p zMexfvU3>(u_>ZMmaPC~ZZzL~w_okL>Hdenc#&b8#uTn?o|Y=}$jPcPbCI1JLBOJpsoZ7<=JUOGIi3#sma>J)%#pj=$dlD*&K}-vD*iU$`=ZdJcnXqd)qj zZsb~9^<>9ATlz;1Pi=h%U|(!>*>k_2Sk5OV{p=fXDY2VD?*P7e;;a1^51Gyd88ZnF zX0><~znNnP?WJdIHP+6Txiv$`o*%a9)|YtLWz!z6;HN(m;3K#u=dSl~yN++zh4tdE zZwVf(`yIZ$zaQky@OuO+JMK~62rGNu5%$E@JzST>CN5|G$XOA2tGBE5vnQ*r$a|ny z@aAk)BQ}TJv}vt zW(=7*?*V-?+s_YuCodO%#b6#gv*we|gUJuwmt5Sz(TU7eF%MJjtndn7$Qd@vtNg+E zg>(0?OqYE)d?Ym%J0153{`FW5*p&~wvcW#Ph#mJP1$)^}&qjWo@_=9!i$18GK9MDZ zkMQ({j6G6gy;O79(*w9pK(_or@V2bSA=I>@`ChisV-b3&I5HucsjPJYj22HdmL zp6hXCi+w&}0@e}i-Jcxbw79}Mni$|YeH!e+qd7YqzsPwb@mY^0*Ye5SlXws;!YA9^ zlV#T$-T7T#`n$p`eLicK54!mFY{>~vjE$jta`J*fdCD6m)Jv`5R(-7A0CQh_tGixV z^-B-kTj}VVdn;Ww+Dkoze?G1JtF`-ciOC%46Wqfvn_}V%zn@F?W=UVomV13Pb5^r} zigR-;Msso@HR<=&`Z5#vW_d65L(cVK-o1hBld*~gUhKsUvp$=xdc`OF+ZTJVNT#?X zi-*XPgIni!^6!TI+r=-+za#eVgL0nl|8%_{@c&kNh2Bp6khjMMF3;!p1KMr57I!gs$5sCD0LwZm6u{ZU8vdP2uuZ}m#=?5#cr z^xG_$3A6E7{Fuq!kt?yU{`%!D;NP9TnhhAhBg3zGH3w`V^XjdzI-3Kt>+|VEbj)er z0<-*3@`rn?&)8#$yI8V^Sy(HPG5==WJ^aHgyxZdy!+gn=ef)cp!@a4a8nMeyEB*Jtr|M^-eFhlM{caJhJAh7~f63$RRfABlGJsRnNsr$6R^` z`0abp+3nd}nHRX0uf6w=E}r?vx5ryBF`w7oWuMbN_xXN3b-k8+?cYf5@YL@M;-lNo zeHi^@>XzRTY^Il+4}9I_x@|RV&|Ccjm=j3_h0-zi<0aM|~zdWREdv7Wh@-w8S+e#F9t zIOyQ9TY@+K#V4=-!Por<{d?W%0MBGHnM@{=iA*LUl1^17GOMbhDyr#IomEk>s#Zm1 zS5Pa~A}AIelc`K6Q=OgI=@7eNf{xAX24RCBR+uk>Ao#LD5Cma^APDk@>vipYeLU^r zk2CjupC9jY&ij2`*ZbV}^L)RLE1uh%`RvI(j^Yn);vyb@DgQTS{vVsh?a|D^Pc)6c z`B5wt&-ObVuy3{%ew?nD!!zIO ze^-6*%KdnUZ`!rtYW}Z~=K44D?-uj_2>SQ8XFvS+JX%e-I(x!%9LIb4o*v+P&Kdrl zqyGb`SO1<+Uu~{$$G5&cntx{ieBb);AE&L$)q1SoJnrpBUwh^UMZ0Hvcs97h^~Zuc zzIKo6V#Tjdg)8dSO#{^9-grGOi;b9jhDSwQ#fyFQikRywcCPA-V~-wL8+=&<{WHHl zY{7@CGEBpxf)DTtyW=~4D!7JcyT{q_jUM3HhcmD8@%Re|^;eA5cU*O^zpJ7@Zmf^1 zG1p|D?3q*Db@79`E3#Mj>?v$bt32!DY7EY^MIX$g*duMgee?2#e9bqw=*oZc47|Hn z_;(s$3_kFoG3wb8GyXHj{L8j`vEpa(6E8N{#ba|WPHW$sForAV@uKge+2fb9M|fge zaj(tw@%YX9J>$2lKI{)mY-?i&Ru#C0q4C`_&NzF^xj67*{D?d1!`bo?*3^fm{qBIH zI3#zPo0dGCSa_CSaS~5okKbJNolP9W-`MasOUmslzwkTze+!w<*sP`h2O6yiCaNL0 zj=R=yS#-hwO=unJtbcsA2Yk05XByg|&R*S{-+H1ieW%dR-lik`ieL7{S9s5->iFIs z`BJ+*^Ref}L!aq4Zi@>|5F5CFQnpx+19LE@es)}~$GpP?yyyda?07a_ zfzR22-C-Jc#y|J?_}=VeoWpb6Qm-A~#(Vwn5LeaBj=J;DY#58LSA`F3;if+7c4bFD zeax@TeD2w1M=`H4uKcK-p5Z5MemYoSpKo!DFU6go_yO+uh+iIyJ$0V>%T?UQqo*>5 z{L7|zDen1FKV`mE|E25!CfHsa-OCNyV36;J4ZOq&+|kE+;7vcVeIol*C)RTG)A5gI z1wO`edo>Tc_Q@9RKN;UB!ztXdvvaDx+>Tiwa zv|cuLewW9?@p3nq=y{zM&=LQifO`es!^55nF3GpSOLN{b&i`qa=bjPdee>fxEpbm5 zaxOUW*ILa@v&M64#Bo}~&vbS=V1Ebyt3l2v#u-n)a2ZzkjNkd1ANkd@{Z2z&`CR+_ zAwJ?VOu!<1-IsMPc4DSZA9#U5cy(2@JAdN8nDeuCxD-SFc5i-#9b>ZA`pTNvH^%ze zfamcaZ}1z>#&h@hhF5rYQ^w%h*9I%D>Tpv#E?X0O)~Vju#JjpMTWn}k?B&b3>ZAUO ztk3=CG=>fYXYH>KP1sex^|fYw?SsFjZRQXk{;)pr7fANwW%_Aoo|4e-BSzp}dAAEo*`IN8pSznsr3@vXexFmn#3O?wEJ4X)g zHv|0je}!J1e-C&2pZMOh#JJ!5a1w{v!B=@cJa0b7>C2MW6K@*RtN#O)t!O~sL%cs| z^G={YY(x+G-eCT%F*?(6H-5)=`hV2AKiubYYo!JHMt^Dx|Lsee2JnG0|G|=2@*RK7 zhx`a{`iaB*E*|1Hev5m!SdC*BFX03x^<~?={*PtN?7|eR!rr%&KMoZs~Ceyv@-x$s$?m}L*`r)_Io3^%tnMXYCoeYUNc4Qqu_ zR~S?WkFM6lC;H-n=NIE!>vcWPnb)I{&I}4)yqO$|gLof)_Pd-u;a&NQ$GCcB^7gIq z0q)D^Kk_>tE2rgj{J;74{r&;2D16+%1_`U-dNLgW0cpdDC2M=)b=D znA;leiNDp;fE%(#Hm}Qm)wy4xNo<&3Uvp}6uRn|#V{SHab$;S+bBPziT~4z$_ps_7FRYa=IRDzOIy}LD zzJ%NHhY#^ArQZYS;T!q=9=yg`T*Ya;kDtm{ynfdo{6qb}0k1yt{Pj5x%lod%PyKVx z_HT^5Bk!<@b>H#n3p;eex!)YxX+W;kV!Xg{>)6_GU%jg~^@=z+E8xGqj_dS{M%a7$ zRCBVY?wt?#P^`tm`AclX7XQRsJC3=>OEEnk6aF)ow#S2KSGL4gfm?V}=zy4-gB|@` zVauH2E6(bzN%3qxw&=;u0Qy)Xe8Y}4IV`?ixS7Cywo-P0`<2bF;Jccs5qq8mwO|?0I=zOb=`}_IYm3 z_;G*akDg`DVoG2B;&bbsZt?{`+#f&C0y@B7@nO%LIeQk{uow+fns;#QLi~n5;=KHF z@LMh`_suC5VlRebD%N5ocCK5?>fyi|XeXzT{tY4E4Y8>pZ~sI zf6RA1ai;h^0OtU{yf*I#Kl%@S`7E(N6RR6@wpWMyd;j-MLD8RX^wC(!f${73REAQLl10!N01~gYZr}en#SuF7!HpM#r zZvGMf^YJ!b?uIup7F)$Qu{NJR$}{1I*qH-%w6is==nD_*sXLDm{Wb^Qz%~uQAN!#R z_=~4Ftl%j=Y8xlVY4fnb)_6-ta2BuJtG_$gVxL{yogMcyfPLKFoW`5OIQQqr;iYlf z)mty#*sHz6DvZM?Ji|CX&;WSK->>R9j}NV1;X}Mq#FX#&Md2^?d>`EOj2cW7qqpa~ zmJ-YtgTYI&1yeBN8vgWW-QmV*El+2^bV5ALKdg9$m+eQJ^>~I0+QhH+svnG4EAFq* z06d2i`^QH zE{5vi4gS>W1NZPHKH?6a+Kg4iQlHPp&tfa4I19_J3OnMwyg_Hor_NX$`*hZ99(~z_ z8JHbL%!TK;dT(&aE({rmQ?BZ9_G`0;@fkN))Qy|&Z^|6nj5o$udZ5mH=GG6l`9(YK zFZUZ0-?rWS&a!x|1Os2u-&~3|%?_Q1DtT+Q0bWp(1|H z0%EZEj{oASz`)v{j!(r*z4+>DO$rPu*3Kqvvw!p9zp{J}n>0Y-7u?2)Tzf|G9KMt{ z;m#?KhHvE-j)Ye|+snz(zVgx8Ue3mG`@cTCbVj-|@BCMXuj+0{&K7Sr%ri|+EbGG? zqt7(KH-LBLtdMxuuh-<9FXyxAJECXv(Exgb*SIY1_CkxM0qT7}z+al6KBc;34NAsM z$NFu4TBxtJ(gJm~f_)g{Z#kIHJ-Zhp+*I&=aT)*RA@-cbXnI#BKnyu3s;Q#A`3HER-F*)Ub&v+~!%en4d z)zbquaS|7;dwJZtZi$~CfllbvZRzV9#e9Q&U9E-U`a zX+QRRo-F>IY2`52_aA>hQ{E8Aox$P4yw^iJ6Z(;;;Y@-t;zka;%x5< z4RF4AF|kzO1~;77;hkTUc~jfI>l>3&KG9(MqVA^f{Q7WPU*#Qn*YbBp6XWV_xZWIYE`L{m=Fk(|H{LnG z-|*lox|V&N&K;Ko+xYJrgkr4z$G3!&7Qu`4WPjBO>w7gh$(0V^Js;8&bz<{O@cV3V zt2`YXi-GI-C$8cHOR)M#;wLurM4R}*m+LgZRUJGi!-DvWExy8rx!I;E;tM05w+8p@ z%$}?KI;^ur=V9~y>tMq(tudb7@DIPzFut(IN5j=&LEfXk{K5yW%2Qb*pBbxO!FPoY&`5E^ zHL){>&*eUR_?dt0ub=&_zwyG^NAv&n`8$31lJ%XP{e|cH`|Vku998T%hrlH+PS3@b zU9n#gFZ)^S^*1L?vOjCHPW|YHeOjY2_6ZlX?)mu1JaRppnqOP6TaL>?_>O1Zk#X|i zeZPA-xBP@Z{wJzqIE-iK&*e8K$E$bFcYjm(i~osT^YiMo(qw^ zw4Zg@Yv!&l;5=K-?0ACv{N(#4pW?kU7QW-9IJg%x_!3vK^o;l8D4gP__`~Kf2fJeJ zS$sFv9O7p_aeX=*(8eAcbV>Zpui!Ym4o@%wH?Y1ryidZEdR$8E$}7CXGwZ-*T)QPU zX@EBO_==CWWe)ZBfG@^4|FiYZtWPdyi+%Oxbgv$ET@`g~n``r^!*#`6=46*|^wp0| z>*oh&n{SOSTg%1R6t6FZyPoyo1JA~L=3g;b9p5Yt_QFq!@%o9u3t1Daz^t?Gr}9qm z3;*Fi>h&A`$v^E?UDnle0e)SX@p6k8u_1n9BYy1igLsM6=7Jq~k)K_)=?72NE#}6s z!4^Eg7>wY&av{FN{paE<`ph4`X>Ho=0dvy_ z>pgOG`AfIN1E2BRICDe`s&7|CYw+9}XoO;}>Cp8#b7XA$9%IUT`p92mrZ_9T7`!R; zfDZW9FrVYxG*^7xi#5zWnH(lA;s;}5E{2OE+~S3t<2oF|=z0AR%W)qj=!|FeFyL8# z_C348&9D#KunybiROD>);tf9GpMtZnsNKD*T)cdYkE_?u9Jr4!_?p=Fy`C*?bcB8U zRfoUE-xD9J_l)1hs$bFHT#9=|8{XT`^lLt~KRWzI_U4{1t&1PriwDk##r%a!_RkO6 zXvwrpf9>k|8joW846lFMU;ImFKlkta-Lqfy1FxU`>VN+qdi@pu=C$6_1ns_84P&tL zOx7_{zG?^=$U+8BV6{#^U|r&mOICeLjA{bp9i5?zQ6(j^Z7y%O09b@%ozZ2`BB%8C{N+`+vq?eZG56PA&I?fv?Ev;d8ZR z+GBp&<2*%^t_oN2l0F!FL(T~FgHBinJ-9p^*Y3=3o|I}D-s3f%JKG<&Pr8BQbj>{W zWjsxDZybL_8;Tnmh~xa>%5OUZXqzs;0v{`4C1&%#c+h0Af-{(cFIbZM#nHWjGw`Mz zuHCCMW_X5a_SqDBnzDCU>k)ex(l%XzFE-#GPsUTc8F%nfF*hzM;}?DKY)x|UEwOi7 z){TpJDsR&(++f?D@LZd^=^`KTjkwTozOh#tz`xT1^=uf=r`j%LU2o?6hX+~X*)RF$|KjY| z1W<6qC5Djn1g+`@t-y*)?nSi zSI_Cr@6P%5KqGSPGaJ^bK6cCh*=Cb&WskL~oejFNGyk#H`i}-!r@3erU(!^%jL%}> z%J*_T%;TsSiy4jAS1jO8KYS5WycKV_Q(#o zp1Yc7T=k6ixHrwQR-A)5{FC$bu_oBWU6{nv_hv2lrw_ZZCwH)~U-bK=6>Q-&-WsPp zu`9Q=DY&hTecG~TSKK$od^q{R_|6*HGBsff)ZISb&KXM1Fu zP4?~g{Jz~!KmF&k-yZBdc*!ManfJv1?6=?lU>L5PBVmIb z{N!)zvVLn86LIHLzJe#~6nj{@ki8mf{doOS)~v`w;x7j3@m|q(G5&l$zS9PKZ)I<< zX20+Y@8ig|;g>z(gE~3Z)w3c8;~ibNDevX90Eg7!9G>AM?x%ls!&y7pQeJDjEZTr) zaAGaiYTd5{gE*CS^?c5Tv24rH^kunUo4K6TgY$Bie$g&h>)y8pemCwo`{Q-(8gK3P zWgcU)uCDL6uYd5!+U7@oiyqd8){Xx=lZ&U=PJ0()aZ@MO`naE7;4ysSjQESSE3OTj z@PYq$Z``;qzTWYy0Vdt^se1k4nk{&Suf2a*k9s(RcUZ%JS^;zThimexKHBiiGk)Tm z_34LW_XK0OVm|AzPJM!p@)&p7Ws@CO++QE}(+YL^7(-)Raoza$1^3#_YfjJRb-pn- zfAODUUG`?5UkDcGSH7gZ>a^>}SN3Rst_r)(HTcMeabm=WzMsL9Z~Gt3cR&394gclM zGxz0<_0x#qbre13QbCSdRbJZcV$=pX7VkEN1W>cJLgZ>4^JRvQ{`; z?BP?JIkW}uy~?qk&9Bb6HrPIMhH-vh4!=3)X*n0~@f`o0!LJEd)Y-TEySz*@^m7i# z{>p#-QksK~HJskfaTfQ-d+YL?byXkbR_`G+D)pU@$|>{J;S6N=$U3rBRpF#PTCJUID@x1s<5R$9dgBOTuw~;bH4by zb*{7k?{{U#^WD)kW9|qKwkGrPz4h?Z_G=#d=QsLi|I<2s)#12ue&6=6dVTDfpA_eB zei!3lp}FG&`9G}E|1ADH`?de^jkDjBpB?@B;P#jQtABkKyZv3`>;ulqKl+Tf&t)It zPgnTLmHsN`GPl@^G}FCTkqW>6Lo^ z6m#{9J*`*ddU1k5+`{n}v;SbN7{yaq4u1Qd5`Hun<0Zb~A@0LCe!;%)c({TSxWm$G4K@+n6#?&5hTuj8mJ$x+peVNd<8ILWT@xPZ&-;4CgHc&1Ll5qovTA9eU;oSaWD z*uo>Wwdv!Trs$X4bJ77?Kof$e)4vPSpAN7$O>t#I*`BP|eAbH7ioI&L2E4M@jdA4z z>!vN{upVnWg#k*?Ifm3H~bhv-f}F)n)BH6W~YkV#iN|UW;$=BIBwr*7aumZLjo2{=`k3Rpiz2 z+!e>wO>@HWa&q7I)a!%G&Kmft?tFiC@mEQG`Ra^roIS8A`ty^01S5RXJ!k#3<%}h!7lR#Fv0A)v$=THRW%0v%SG-q0El^Jb)Wd`` zHk`qRyaOw+f%~w*zPZ?^xBTwhK?i66%;G9u;u#KnA^U-CZSp*uk7h5<1fFRGz9{&D zcZ!^g7sk1=tDbFjY~voT;EAg-@5>ssvxhs1XWaT+e5ZUqe8i30vZu?^FL63)0bNkk zg=6JDo9ugb-Td|?=bxXCuRM>(IBxCsa94ci-WpulW81p<%YLkLdt#ff#Nyz8xqwH( zdimz}|I)ud3(WYlpZz!gR(}sBxwH9FPLw0W7?0(3yk}2r#b4d(r}Ix{Z7`F$%9Y@{ z7{{|YtB)j)pcFa7wGz35NRIQDCw;&1;igb%nV zzV;r!mXG50VsNV9D{k&Apl#;?T7cKI1po0ufj7LN2QY%G&jrWyf_|IZUSNv`(0A?T zU}t>C{n^C{JY^gH*f*EH3jAxw6FiURov!Zj=&K9fY&>0{C!Xan_X-}ei&Hpb(SHT!&EZP_jGe}@ ziKl!RKEifmfUD2t|FHGW9R28dz?BxrBblq%4wj207!bqryr;uBF8=J{J$-mOdbD%p z#jHJCFYei8@2#v!N!)iHtrp=Otm6XySex~RtIdJh@lq~@c{xA!PUror!!^%%GybZ> zeRa+f&hPN=tbspxIBx29d2%iL#<8CmcJ1mnKOTpx!q=YrH)gtB+@Uu%G1aVn@6lk1m-T)$FDdC z^3k_t9KXQ=AHfB#EBii9(Kh5>Qdvl?@Xl~>23P;WD+1^*rrh1%Y%hj_&0~CF5)YUUv z58)Ndz;I+tmU+Kd!ixsFI3qMtI4O ziFw~4UI|8UUlB9-zYv^?EsnCSPJZ^RUW{q`GvNT8cOJxP82I*Z|KY4l!GHYKCMUqj zmlAt8F^*kvd@&fMJBs%lBukvrlK>de8cLHWwa$efFfp_vN7ebU__H z;v$aVpS8jx9em^m&n?9uU)eYA|u7=}NWz2L=N!4nPmLa>MH7lZRJ#y8)V zT%?a&XO0Kr7yXRKK|H}XT+!z08E^D4A6>$CgD*` z!ZmZc;yS(Xtj+q(tc<}U~M%bu;%Jc{}0 zi8K14$@NLjnVrXY?djWgzUMoA`E~K3e|fI&`2+89d}qUr6AxN}7dR`X7mi#ZF7WVN zFlQVr;riz@_b?^*%T>xF$&ce1JUtU`u|KTfpL^?oFZv;0!7J_?KVHK+e!!r9_z2&y zkI$}m$JTg&clfisdw+a^ch(BO=5~e6&CB;Wvvuv}H=a$!{A?y>J@Y3<&H4Js{qK&g z>A?H4SABO~e#h1637%RryVhn7&&KKFS$|h{aNb_j8Ka&*wk~_q#%FlUZ|3Do8m;~d z(NOn%?27AnES7jX&3`HOpU*nP3y%0nA9i5`I}kG>)9WF zyBY_Ru5fxW+U1@;gwv;YR$Rn$T)@+7!Z(=5dpw~7?&059Jb5d4NKWY(nvl86b$p*@ z;NCH={n%I3jqk4P%d0fSy!eRU^6l>B_jlxHaB}>(tq$K6_1e`bG{LtFZQc=JD)#$s zMDNULZoD=JA7t*v0{>_y{?i)!;1lc4xN7Hf!2zD}D_^@N9@R(pv{^2GAsC|Jig=4V z?Z9*K6KfbSC;qxFm*Y47FR#FoxXTsl#K1jW&;}RgWLvDwrQjhAfghNJS=hyCcpZja zKOKC)vo`#f|J~ya{Np|j$dmYSU-rP3c5TKR$L{A7Ywv>bbD!}J#_bQ@9}2&%-F%91 z_s4hfc{Kp%-0MBc8K&4X9(L0o@5&A1orQ51hw+~N;!N7c(dKev z!q2t^Yp3^f+{UGG_&oR7y(Iq09*T*?uUeq5e$x%(6W*{n1PsvpX#niwl#+Rx2VjdW_Vri9otD6*vABm5 z?!(jG!!K^&kbZdM-c`X(e84X}!6m%G4QCS1cV%8S*oXJ*wfM3=dC(fhAsWFKu&h5$ z;b>yh?|-h*-4p+D^0sj4j@UIn-pQBjSUU|E$MN2}wjOIzXZ^0~@!I;`v$w*&x%6Yt zGh5cpFSLU_*DofoZ0*)S2R+knyt6)W6g$3f9)}aWl}q4&F5|j)$rm%{E3u8E!&a`< zP&$B*u%>7?X7%zXj>Vs~4Og@Tmf%Z)O}NaM<~|(2O$9IT1IAN-!jAY@Lu{9`;X>Q2 z-JF+2EAY!$yjnlDkJ5EpJB^|z`mCQZ@-Uw6ir4tNg3t1??{v!et=+R+kL%0(#;?f# z_-l~{MDbH(3Q_6 z#t#NBIR0?_;{D*>tOK_7RgaVUJ(hfn12`dP;*NqFFmH^pw8U8U;hqNVJq2I%m5a2~ z9&6Lj9Jq;hV&uH0*sr`F-g00%*%JXfVgD1ShF;3zDoAiawcxS^O zYr;G4Z%2FAD2Ij@Jx>@fZq}g~Z=G3R*G^k-Ykb5pd%~-0bLO{K_V8M+e^>s!gK}$r z7f10siNQd>`Ds^he^=*#n{!UUefRjwt}_80U^{wM-dYRIvSw?dW4qd`XJf4`IP6$^ z=j-t-KA(2h@3?*Fx#_iP?@`cE(UjDN-K+31JZi2rNR#OLELd=Q(LGS(HA z-pra_iJzU*(q8QPzk*;L5Bz*T>unyweSF&4j$PyF0Bi(j zqpjTYuC_HU@7!+^`}C2c@5|VSqc?C4 z-=5il`Ma_nbqa3XpFQBev1}P<4c4U&&!!LNU_ixfPlDI((LVW>4ZQd4{?L@3 z7mUFVc!h6zA=d}T9Rq*CQF$tlYjgI`9OY$r&^mKE1L$LY;Ys`9g*DoXvAB)%c+SSb z`)Y-II+HSeo9(t+qk^NZxRy9Kr!VKr_xL;wNUW*_=XJo(0H*_ZpIBBqeJf;_4_%LS zca6vSf9Is`J$ltP>$Vo_a@Cgx@RPlY>&3(#rw-rLS1$w;+QdT}J*KJhKhBG_c7A;; z*b;N^5Ntjb+~Fr|-~;@?k$i&lu~{6Lk4&%*b{^c(E@I-L# zY93mlO@ZC}gCjU*PjL_T%kQ4?>T9z;{M84?aBJE?dmar>y<^CO##*~Qn8P@Ac!OJ> zjh{{TiD7d-PAa&cc=sMJ?T>Hp(th3ByY<r&WPaMhm7Z7=MqH;;M4n_kUh zE&A*0SzpiAZ2ji4C-a!oJk~@{ACG1!G};;L(1Ej$Y{AfTnF}Z7 zTYQEG_=^t8`PFgp#&i8#;pvskDIdIu6KQX5q5;;6>o}CQ7InCjv9%GLH?NM1)=RH;y*V0*zlldR zY@ByZ40;xNPktv)@vL59e4__=Eg#~AvFdPM8Q+ad9xZ=ycsRys1*Y+duE4qL3J$Ct7e1T4uxEa}$Aw3d z_pSfo;Da6Q_-3v6<{qb*>lA+cCG!vXs4X$YCrtrYE8zm ziL*Ew%=CWqV>@QT{!FR`B_fUpEfu@UYgtt@9<}? z%wK#v6FWD%;y(R>aaseXa+LLFUCs4)L!V|#Th=OvH9u<8N5Li9u(9}Lo#X!v;r@-s zw?1nh_wiVM_uV5g>F-VZH-}1M*Wb(cyZNi52l__K`z{bX_1%D;n1cr3uXBJkd8Px_ z&EGiqdd@fYV2$IyzBq5quJ$A@v|3#GU*RY5$hA4zv-ZTX^FdU0v|l4r*y_2VGUjeqzQ|Cf9AXN>m5v->r- zwOBVBo~_y3_Jwy_x2t;Gr6CGi#<`lGeb->5xnCdq#eHRcjA6&T)~ZdNXZ3vW+3-r? z<0oSGne_4fR@`YjEIb`85exO=i1)|Yy*UI1U;#hjM_JA{o<86md_9->#W6OD+wiXK z*Z$zUZqJvm#|JBNI6T8U%)OjgTAO-jTWvJMTD8gl@JXk<*Y7*J9Em5F#kcxcQ?#WT zk-Bo-8rYmx&=$|Mz&!ZJp8Txf>vDc#QZD=Mp(F<7`|ZcyRPi?ef}@tz(Sn@`jAx6M z(6z5V1K{4)=iZvF|BdiL$(~O9kFTl+^h&?%p;|##`SsAz#sl|pnwBJPjnkpMwJTzY&mKyA)qAELu8O(jI$Gdf9St-G9im(2W!pS#vNO)$i!r#BIJG2Zp}>zUIV##eCBt{%{V$Q*jm3wY`+}KcBI#IFCp0ftTv|Q#)iJm8|Wx%mpiQ z0^2Yl=K85md-)YypKQV@j>GUcZZ7>VX3uXNzb6Q*>J@d~J!pYvYl6e$406&SJjmL1 zwkW^lN;%!n;_wUaJ<|gBN^GC{$ou#z=R3p8`{OeH<2KIk?*qL*{~pKBg0Qr}U-A{30&SSNb2? zT79I``b|&8nZMPEiD$7D2R5{crL#M%xY7i<6qfM$i^;F}dVg%dIZVQ=+`K;eKN-B@ zA&ju)ir;vk;2*r=jq*_T#kPC)wZSU8$lN%8A)I2<9Qxc7zu+eR;G1=B zZe!^};?no~V6yzeb9HPaKXg1h#^M^zv1k15+2#k_cQuFg*oU=k-)uM&8L!PaWn3Ts zUD?NZSMyq{^M|qQtJ`?KpmpY#_s#da!yCS&OXtsSay`C09lOC!&)Pc|>>LOSFon+@XvIcH>ibAC8{n#0%>+-<+j zYcBP29J};_uEciprE>ueB%bA(951ia0r&Ve-s7R%{H}bz_wD}H<7azclXrQX-??6X zAMfM;{yR$lmeRd)UI!Adj!O(rKO>Y=3m$n-d&1h`XZd`rCKYYi};zrY5jWcHYtKPjUd-9eTKNGx(t>-U=5BLaU?mw5c zD4x|n5pLkWGbR2zUn=hDfVOecJ-ix^3+{2{(^(Vl;5iPe!)1NGHJEVK2WN1AJ@s3Y zE6&pab7~)l@CCn(b4~0{-}Ifm@yivj>6~1wFMG4$>KPxm2G4BkZ*6oj`xdj4R@#I5 zhY}Zkr&(JuZM4>58E6Hh!|Y@g3qm`I-K z8izYM7Or4LUwO#57ouCnz!Kbeh6(tC(<>4${o#sT_Vm>ro6Xa($v%v!UoqG6yRn|( zk}dbI2Lr}hmwV%J1PAC5tY31x^Ix8GGQN06#*>We8GG*x*XDfy_wnuKypt=qDd*!p z-sA1KFPG!K9FON8$iK5x{0-nc^LIiMpFU3urUS;%4z?1{+MWi{fMBdTM321x)2jHe zYo^WFYxz#Aw0Wo6KIs5%M+560@rj>KWBFAqrorOyaxlW5D=!6e=5f`Z-}#ttX}I`0 z1K>X1KOM|J8!XBtaJAg#UV%4UTan}3!yY?w(*v=O1F#CGY`EWeyd6iTE4WSvXoYt3 z!?|(l*_@_Wr+Rkp&z`j525rFEk7xflhhKP(|LUFdjq|*=%koSIaLG9J&ICB<8PC~1 zuL0I0-{P}2>*P1}G{N57b#d+nfDayqet^+e|0$pC9_h+MHg)5bvHBXTA0JpZ4&ul1@%yqK+`$+31H!5`|_#=T&sx*`9vdsp^{zpnb5(|)YgGrv5W@z!T8+N_-q@zpxa&4#hoqNvAl z8sMsr`mNb~3L9cD`;VoMx#uhEek$w6-*Fg!t%={%X%{0L!zGvqcIro1ff@bvc|LO* z<4idI!jjx`{Jg7qnGLqmr)P9L$N%X7-kMLncquT)HhbC+-1c07^RP}+*wJ4<>yamS z-j9#^%@23zH~pan_;pP*_D|oHm7-ezgUvV|gnMxnNG9UlaU`5=Y4F2Q_*DnW;IEc&3H?W5H`iLJ~=_60m z4D(ovJ~#pY?9dHGe>}krSGkNv=%-yyvu-xEn@62{bL)rqp4G#tdpyT0w&Y^`Qnm(d zc!pOBj$IdfuDFhSS7rXhu4e}Nq#g&2P0XtecV~aN$gVkY(O#?*=eL(nhYx&az53D* z{dbl(k9D|O!?^F+y|tSAgNcdxz9sQw(|qD#PX2oAoCY{^(Ha~dcioG{6Pe@5*p`3s z92VqNzQ#po1buOR@uwY6XC2zyFOMX~uv_lKnRshs8^`4%#r=vlbJ1$^zZjot!*w=b z9(Tis<}O$cHv7!h&H!@1oPR~m&bZ^702}a(L%x|Mj?J}l?tU*{zE|SgzN7CwA7>T3 zm)mjsBl)>T;?%#V;CjCJyNZfFG$HXhodM_o9dQOoOuynCz!`uJ1#|s*p#1OWg0z5k z(YoxTJXc54vY*C@4k&W^;j8i(m(}xC>f4`xjC(7X(|5Wl-U=;9oAb!2UHoA~+~MTQ z!JmR(umi{N_E6RdWA5b|d^Zl};1E`{d-ibHcshV9F#RoAC);?!zI2rA1d=49YO)KzI{9xdjtV0_ucs6U*KJG4W(*WGVeP;tj>|u`0x8n!#V^2?y!+el;mh)wPx%Sgwb264d}80U@Y3LrU*pq` z(NDbTCqL6$KKHC29PCU$m*E7SU=7ys@-vz5;Unj`hjkdlUwvV4dI9rrr_d4o@O#)b z27X`^7U5h@9Di`hI<1dQyx-hxX=l$^TH#r{@#^sr?{P?fJd?w5D{&~l6Nhr%HCSkU z;?T2xw7FOO*UskjgDw1YHP85r-}a$=HvYC(YjQT){^^B#dbIUf6J23byZW`W$@hFS zpU)qBX#aRU-}5J*o0BH5FCCWC`BA%giMb;F@Z;PkCeLPH;)nA%dLjCxj!oQEJktgI z#d|hz8;0Oh8_cq=o-LZ<`h521ysADpY@T-hg;{wo*Vf@aEx0VPgaEfd`3YbAMua`tI)BkBhj!?|irCdmZlM?(#i;Ck|&H%kR4;CjEa?{oko8>S%&K z`c4B9x7tZ8`yQ|}z^!=)aQ?qJ-yHW1AlNGBt#j}D>g?BE?2E2tKlP>kI~zpj%IWx` zeWL^Q7r(JZM`EwOG8Ttu1bt+KkJRlvrd~hKVkbWISzP4`*n@uszhD~Q;26f_JLm4@ zJy$qW;1VWr0jBTI+%RjL0*CsW2hQEI53ll%zOJwf=h~EU%s9{HHwTWI*ZOc1pX5yZ zR)U3c|E8?VJuOg=gLtlJQ?FbR+uCS{dA>Dq(VwoEi*M}Fy}j9k>jUwpHQEoq;t>AM zpTSG{j`wW2s#C0)J>|2BmpS>GAJ6Yq-seAskF-CLwc#*-i6I~3dw5rj*&qIjGtSDF zxT@eJ{=yy%C@*9!uVjxG^Gzw(Y`cEy^@R~vI^isDZqLfA!Hd1G4|~Sa5%X$e+j$-? z=>=@#E{>QFHrWZr+s~TSWsS}M_>Tv)1FqR*BXK)%U*11|_LuwP@6$Iv-|Ie<^FHo> zG&%jQaN6Hb!1b@o&q(|o)fIm`A$s4xp^!LLALxK_iCxbQ-UWOMVAmO7|8CN^M%wd^ zd=cXaK+Q8NO!>-RK!Z zJzw!H|I-K0aBv|Qgr7%)6?la+Se_2RBOSm;*n2!Yc_gvIIamF);o*2`JYL}kyZCLK zd;Gy&Gyu) z!`^Gde>U*Z{J}?``CxOKOPl?EHgU6G?eZPn)NWnYYrJAj)`I)4xNrTmgRj|OlYbO* zvFV-;cvkpX9Sz_+zQuc2IhSw5(;51*_~Z4gMZEFG`4T^20DqkU@Dq=p&l$DYzayLx5;<9+b4INP6ipD7Vu%(Y;9NsJ1@Rki@;QNwbRJk;JwN`6eKe%-USUE6V zO)!_f;Y7cuU7PP~-uvZToZHX%@o_)fbH&r0_i-7oaUbVDk$<0%xSxu@o#6TB{k@CT z0sTIfGs4~n*uj546WBYzd-5Id{J#sJMK?y1d;`2Dob`TUtye_{g10{V_Ce>If1C~I z0j}FGZQ~oyd`Iu{+%o{(RIbc>Pi&X}^BEr-qs;%bAvR99;6IpkZp1&hl2;xL4`2_U zU=sdte|cY(9XLWqTVb9m4PyAi(-IP7Xr!C{-+SStlw&{l}pV-R-@uR)j2fpx!^?J5O z&-`L<)@^Te$vFI;9^t<=S+n)o!#F%WvCr93XANQ~PW;42=2MLI4o3^b5})Zh4&m5a z$(_!XaN~-TI139n>}*dH^oJR_++4242CJvI&Cxu z$Bm&$?0bKWPMzL`aorfWrCG=OZ83lO@$RoJcKXh|pZDQ@V%u}~yN;jn$@|{Pq63W?PKzbJ=DufstNqr^`|dsYv09{ z|1-WiGJVh{PVn<&FbPw*18>7E@&2K)r5s%pTlP8zB3%hRc|e>!5n z_O93~|L`S#yV6DVe2w>Fh|_ZUGuaRRY7r`3A#SMYDVeJ%boUQuV9J+XB$x)g4f zgD~frJ^k#NeSF?MKI*5QHn43jS2{vl*hs(S`sOeASLiQXivfLLOTmHERReH8`h3cr zu%1|*@~Qlq7?=M!!}VwJa`ElQ@ANpMJNM&k{C?s-UgP&K`2Ls5`(N~rUp`CxPUTbi z*(NQ}9=$$kfOCNNfSm#M4v^UPXMr@p_XlfoCdnTA9q{01d5`;Y4!%3r%j5QVSz_-j zz#n|er*!e~O?{F+^@a0=-!I^g*%BM^cAYk}v6#|Vv4b7hlW$>5KEY{NS6~?)VG~#3 zPG6YU7Y2>PSGft6;8nkI{;6OcZs6BAJYnm>>+%YRa9sO&-qRjy(q_D(?&0{& z`tS))aY~85Pw((}tUYmSJ)8v_)qxvg)APpjIsX~YjxlrukL?*A&5M8bWbb@rU-rvS z_FzqTZJcumJFfJ~T-L-s?V%U!*spQ=u*06Y-1D>f`B!n)m*?rWa|q6gwR`KqH<(cu z{^3V+2QJbGaTgDKHpUeW*rRLO)a#p^Q9T%!wJo0;$EN4u$=t?hGtcmMF+QLxF!*M8 zj>}gD>(0%&?^z`EeIK|qXItmt1OGi6_}QL9E97|`x;o#zIgjv z{<@dMw0e^m_Z`4H2<}^(bz84;O>}FypD*m0&f)aVL-y#rhO>Cjmn(cD@6!r)odx84 z=PEJaf10bm@$q}@(-SeH31TYV@Q1Uo1J}4do{p>Vh;I*tBjYy=;`nsH)i_*L*o9j; z>Dl044uxMf&Ed)(JdY!;@+I8sV;}Zo9_v%b2K~St<8cd@6n(~d{G$svtl)L9(sq5W zN=}YH?&J@ATpK&I2AA1Sd{24bo@f?d&;cC9KN{#Bhl7)H-`xDcw)ujY-g~y5V6^MA zN8{{UF(+I6V;+0wL;K!YfzQNGjOmg%^YM6?yxFre{AkB#=W%`5qSLO=WsQnhYCC^V zKja*|HJ2++i-$Hm&wR~M>dn1+efY&yzpSshNjnXY>+pH_cFqq6I-YjPhcK=Wez+z+ z#d+dZp5O;wslPryU-KS}|NG`I_s7>K{@&oC)*hVOM?DQ;fhT z{Fwv)tZy8>Km6Tz`4#VRcs#@V=w#3Ji9@gPwg2-6_wS^S?+mYTay&JjooSRganv5< zMY!e%Yy46)g^p^+ae5T|l-tYq)?hv6F$eqlX;;icTkK^z>zSt7v$(j5S4w@7`0c#g z`~Wlf09RryXDrtEiSPU<7EffaV)Rtj^mOJ|@ZWX)XaP>k-MB1{^v2$u7d!_?#a%R} zIZfV{gJ=$)&<&VlCh=>RMb_qZ?r;s1@t zcYpl%{muCs|8LLvKmIO9aW!!*cav+%ecZk;Ji&E;Fa4X6D}Tkmd9B60dYYim&H>I1 zG=MGN5}Yd%&(7m#0JP_8^1Hyd(Kq2eNFK5T^c8pAtVe@6!X%!Bxk)AOGo)H6-5MH+<-`rw}m(OQ!cnT-Jk6oMh$^5QKb4Frae839qc*fV`+|cp( z&*r$#mRv7SL_^B?ar{EoiNiF&yy|HM{NQ-z=~-6(!DDss>FU{<L;ACLQDDdun?{&XHkVFUMJ99MDA{o~<^dj;lk z*1bM-0#5b81H5F1J-FSyK5QBH`RF+QkN4-f|4{Zn9l!~B*c|4{vvXX1!3Mr*$0gid z@yv!cxfbtn&{-hdlC-n#04Mb?{&`YzTx?n_tpHz``?=L$8Y;zZ=e09?2jHK)_pIa6Zr3)!OsEC z^PhdcS71J84&NT|fBApkDRJNX|M9)Pns%Q1_J;fR%?EHU-ZXR1_i5*xQ=B-a*2M^h_Cb*{)?yceOU@bmx!9n-t9ry7L_i-Ng z@Xhmd02lR@m(62;!AbXmkJeyK=Cwxa(cjwD>BBeHqK+Nh=PPTO{+L_wtbM%aWA^yK zc>A(fd*myHCb+(se!&II)Zch5cFuOrY}S%^m+#u}5LXrZ7}xQ9nxKs~z=l5RoiD?w z+S0bX0Z-NdKe?87@nw0L?@*1O{je#PI6fZJjn{tg_s-fs_${`z+k-W|{eRy1&Drw^ z8`)pqakB4X8AlS&p8u~qzWw8u{O`M;cYpl5J>UJl`t0xBA8$Vy?0+hAd}H3{@jAY5 zp2zq2zx@Br|NX81FaP)czwdu^CNV$#{ErSL)?e}SKisF4)-R6EIJg{s?!BhxA9_d^ z75t~!@ssmG+i8Gre|RqjG#JPE(HK6ZyT(Kps;}ZG&gx-9Y~?iZdNSCQo8=fWghTv> zz0X8X6u5MSQ}_CfkMOFm9EV5n$lf#I0BzaxaE(Xiz#VpIhq>Y0GmOEtHL$lencp1v zhC_E{?XK2yUJLMg`4`vefNQYR!dEN$sW*n*?ZNtKl|ABywbB@UXn}t8LcKNMwyS;N zH2$-_x$)jPgGOj)pAG)RfA{>QuusSM$=>r0AlEgvVkaj*9b2@CzAo?M9S&Q!dwx{J z+Ow;%FfyKs4;%~+c&?a7Jxs|b;(^CF=?og5`KHy}BtMylP4k-r&WwXOZ7>;*7mMBl zv?(;e^P9o+f#KTrGmN9HT$eNDO698X2amja#K$f8f9vsY`{jS%;+)Bqug%Zs_xpaI z2><2pum1Muod0Y8;~PEy}4%DCVMfYz1e8#{07Y!AU`oK9UI#J#5JC4zTKF2?ePtF?6 z|DO5xt#CyA6fsv|Odcz+W;G74 z;n{e$@rfPzihcF49E?{(*3aH?Kpz-42H#-Pd^nFwGyr#&U$rgI;pIX@K>bgB|zNQe!>aqq*q< zU+}AVu%(^`;TJB!gP6@{*6BHUxqHA}yv4(D`K4%6@Y9&+NAqDoA2^^H_V0OmVXko= zpM$sB#p$<_Ct(X#;gWrJ#gYc_1AeQg8T!a$Z{$05uwHz7Cox7lJ87#99Ph^EMdH@? zHs zdFOy}-?stniFtodV7~+Ob@?5FkL7y;Z83+r-k+Z}?B4*>B5RVHaX)-KX@H#V-0oXu zG_PlX*W%qOd|KXlCz`3#Go2&U1xMW{H zg$+EzrEy+f9oKLg*Y_NZG}p%mJ^RPsC;qEb@R^ptYkVOt#j7>q$j&yntFO5~9^5ML zjSubJImNp8il69?b-gotu}=1l=Rch0KN`Rn_NC1{_$nrB*uOa8wzY|!cKE;-{1HQa z_#BsTSYO=be^;EO$IhSp!UoQ(=TH8%F1WyRHrO_nt>C6Phi^RxljSfz=e~8uncv!7 z;ZMgjlorCOBjNs z=?VPcuCu>>=74AC27S!K7MvUF9v9evMPsdf*rrj&(2>No-yzO(3$Ec4pRY>4Yhq8) zC(r#ozqI$dKCU>5&-WxxnKv=0R$A-!kMp!j(Jy%F{Oa+YjrhKPa!&_b<^FMBd+^mg z;=O(2F+SKU4OD0jKPb;-3_s$%oa#QYEN)`AxW)^-)sC;}+q2-SS(kXTXwqZ)u1Lqvtz>a%ymA{j_%Xb(`Y5onSPv53y&)EU4`3jA2h3(C6y=>$3xINCp zvseb_#dhMd)x7E{p0`g|3l%X@BjF}_ka9P9Ls0Cb_T%l#PWyy z?$3Vihx^9(-GTk?ADe9Z-9Kml+w;v~`QNucniO32J%t7+*;n<<)xPYB2Jiu{!vw$Z zAO7+g|E9h_H?V)>oS|UVd%)hu*pI#XZT7?r{}u6s1KRH@_IT;KGk`0O;^X~^nf(7? z)~0xNg5xeNbkig6ExbMA5Z(QuZgn9n`T884T}6;Fpl#?uG= zt=l}oez_Ih?>+9z^R75=?=(P>pQ8b%-}Tc5TN&G*0kUC_xIK>I6OP`U9A(eer;q!4 z<40G0wJX*}6Y&1y;oJwaZ|&-CiEr7m4|d%1SN7K55AjWhrtt&4p?~Zt{6Pcwkp_sL z^I!H~Oa<@F8Tfi||HNM$ls{g}TKQ5tZp*v)PFwL+tfsN9+7-UXQR_A@onkZg`i^Ve z?80c`)x6^#&JJGpy;GlX{FL|M+1&6fX4c1U`kb(f8?Y?LCtmPgOkWl9{*|$_@(*wNdx>o06qAI{CrSJ%unzAzWdRU{rf*> z|NZXo{{Ii(A!$*t)$_^q$M62_+n@d6vEppw8J}?-(3Qf@V za5(2mYv6ypXOAveUvSPJ-Lw7Ef?*N{-v|fgMZA*NaXr2(--DCpcASS7SKOuvaF#lJ zZ;9<*gS|W1v=;owT|9Rlz-#l|AAG9!>}ntG)$@(MuIliguhbcz!m7n?1{`r}I`2p|o-5zn&JwNa@KI6;_vBSS& z{dUH?!isjj*2aHgt?zMW(65@ok9fGgt~-yJPdxdVy`2p_i?Q4RM;EhS`9;j&lNPW; zqdZ%adl~?{^o|B-^KHRCyu(_bwPYX7>v%4==^NZu3ogxj@;Hx2&IR(O>$Q2GPMpu2 zvlHWT4*ze4V~Z;S>38aQ@uCfA{-= zeE0KvM$Y|y?s#jyAMNaaW4`_4KdoBs5AMqSW3SZ$n9ZKcaeIt*R6FCp?$KF7y)m>g z`)};|T`cfMoZ$c_oDpd${NtdwY3F+}g(n)Yd-)r8@e=>x7M{m_IECGZvrgEA6a8Ir z+x&6{jKGR~;VKvD=e%GX`?xXAvx^7j|5A8rO|YxzpXa`d8>8T+`S9tM;8Y2h@%Srv zj{CvG>3neXYacwu|M;hxK|AnIJ^T1*o%o9Hp7A|c>T|Td+7sPxo4wFRhZCyqs?@ihKND{>K&h7ayI+_jACHWM1#<`#B&k<8>nkOYq;C!}0FTRk=L*UvZ|P zk9;LYIG*}GCr&*#ygO$K`{WB_Xk>iZt5}MS@$eEoZ6CjXl=DR6K?7(q9iY>AD?fO4 zPygW<)^GvuaZ{d(e~MSSfd9);G(^l5_<=VVg4NY~#$)!4HOH>z_6@BoZ4#a1@kI#EHpcgwYL^tkqcD6peVc$AjaTIqI zbA2$_-t*?;8+Ev^&4mG+w+0N}mE1JVFz09?jt=K%cnKH$20&&dbv^L5An`D1Ki+wbfjI==bSmwof2J97Wc z`FW&*v-t1aFYn{JvwN_3I@933ILj*9v~~t2m3hcIUI# zf;IY}k2r{xJRx>)1#j{$UOpJxid^IhkN0LA{?Uv_k~7sCgWv4HQF3%K2RF0n9;WDt zzVPi#u{qe@9JJ$$Ij7*AbMRpAr9 z;a}J3p}pI;*l3%N@%dur$61`iFIvE+c!>S@4-4*b(Kxo)5f?reEA4WC7>s;9{+=h)A|3Z z%;kK)y7;W${$sQ6`>ydH9q2azSN5g>)^lI#@YUSPgYkRtaN;mccz5txlR4Q}#&`A<_KjCh1H?ein1;|A*s%tD7bkNr|LY5T`VWh63Y)l3o19OyS$Fz2 zr_pAZhNG*4^Z2j0PyO1PFXha=L;IQc&I0o5jR*gox#j;`kKY5_86Yt_odKo+dlzsP zpaZzBxL2p(J-twj8}~nucmDmnFE}{;zMtH0{@~#B-JeDUlidT}EA~d$?47PIW_*YH zzM0TJzOc_jFUI}qN$ToT{xwEy*oq&^e|2~+j^ZT7^j&ceTW}4V_$mJ=@UIR=U=sIW z11^RWS2p3w+UdTv!^Uz0y?|5rUT@jnTt=HGw1={yWW+4(*e)p zv~{_+7usR|t;u?}7yP$3zJPHt$3t}r+s0c14Wt3Mh5vj`KgG;F-toI@;@x-VS7Jj9 z_+1RddtAde?fTCi`+ROa;zwK9$9eH%pDp#`pga+u=}TAGr|mGIur0l z|0I9c=tucGhjNbm*R0N<2x4<_;J)#${Tw}Kh`GWJULHlEn^-o-5(Q+}LtCH5__ zBnRk|iNAaI$4~v{$31>D?hT;e2fyLI^Nz31Z9jV0z#jfGkF)ZETp~BIfsNX7fVr(v z%PC@-93huCXV9~~_&^@vBR<1XoWnD*`zSW>F~2X*isdKSM~uZr9~YJ3Dm7k}r`C$A zLf&2Ne$ci?9Mw2IU9j`}*gqLOwm(~}C8tg9^PDI71{e4J3BSd;d=OtZM+Cp+dScZ( zPW@QE|6yHm*TMVpgZ{XHTl)Ua-zER`*Svq^fc1^x%Ddqt z?!S_KmH7PR7|y%*6VuM&TliewtJfyuPFBMC{@sA^fA4^DU;gA{HJ-5tC)vpse8zEm z@)f&+huXtu#+Q4@;yruV7X0)KZ0Fnik;M~wU& zw>F#}-=a8Nd3RN0itXb)RNg0U=R1GD2gm`5-QK(XKES8v^7m<;&bI-mlU?+@O4N4WRtq+5>h-7nwB zJ@_9yG(WLRVLv++c`RpZPQ+2gyIsB(AHI{972|ShazoG07uLgf{ML7X-%sTQKJ_lJ z?ouzEa)6jA;wO&cC+_!xRlIa3z@0lt+n-69mjk>DcL#|#9dyE(JOWGfXv4U+oI!^g z|Bcg2AO6F;cLGk4znL?Q3-1LtiPOn%ZTG8!Z|?W;T5Sy1-R*pX&uaabq8k^r69?m$ zynj8oZeGA;XUF}w<1<{gZu@GRmy>W@Uz=_Az-43GPtKy_=gI48a?b4RiZfbozxhI5 zFvl1C!sq#mJjClN7-L~o(%qyl`G8AwY;oNpLkd=u4KfP?vG-x{kI2M z^RvUeoKD7CeS2Gr_pqC~*bfJaS95IpCg+6d$8zU;6XP*X!?v-+sC8o2cf#KL zzWLqz@(_D`w+E{|BOCG8nR3SZgCFn}N4>q|O#B~@y$QnQ=8Y%v{UeVoAEsZP-OaWW8`ry{w=?A zR`qg$JHK-F#nH&MWRLRS{&=rk%U!2vznt^4!yfju_p9N7+MaUQucO=EjNOk73V+JgIJi3*=O?$Axx>l8hWi6= z<>&Eyai-fobjcysJ#0WoOMlGf|iHnMR zM;|Wk1jk~mO_vz!!@}ivsayh|urZx##adX>mTNAHbvMF8TzDro;+wk__tf$ajwKGw z3%H0|a)fV$m!ebg1_(yVIrH(+`3}HyzBaGMWAjJ9Il>pGkD^0t9ALPR+?h<`wcVLGI!nJMTdF z9WU@iOonam<8d0_pNJpE3pqqifO$MR?)=S{`?!T?zW?#xxA*=G0RQ(p0M5F<@qcfC z#Hl>T_Z7Uy`N`qFbwA0s{_cI>6^ZHj-}ZSi-y6A;}H(BHIj(zQ+ZTwm=ul#MB zZO*b>wY}Ko9bgZ&J@DO``NSGU9QcLL#K;|<98jEyAAj;0nU7KEwsc*kK@zwGHU2+Tk+sl~s-WOlz-RiyW&Kw`{ z=!dy8@x#5zpL-L)FRsJ3``^9BPVa!ku6)9Cd`}*zet5?-`V?<&{Fh^t618sGiIfOE@d8 zFrbM0z1*K-i<_{8m*ikZfeG9d<43`^F*>x#%NOo0ZE|vk_N{P^-i_01jQsKitnc1~ zX%ebY+a~xLm6@E%QI%Xcmj49S_4H!u5rERJ~-R6;JKVBUpT)td=r`ag>U6VesTBDPsR_~=5=pI zIY1$29uCA>jNt&5#1;7q|m|l{3K>J_IA>0e;{EoZu4fX(z_z_Dj(h|CZO|y*UNPjVYHh`gGY# zuEAgPuf%qD^0oL#t#3Y9IPYtA=}!h{Z)6{~vrEx-R<>rJ^EZbd#}C`Xxx9DqUfXv7 zAKZ#<{K04V=3a0P{&dfZAs>sQyzVz7cQbCgcdZdOeOweT^4@)XEpBX+FZfkFZYC#+ zzoIXW;)?&|=uqg?hada1N85g6;e##qau@AB!ik^c-R#fR{QH^Y)c)NXzp>*}V%7T_ z?sL|D(>oV@!*0&md(C{})Etq!uXiEr!>Dn2gRc0z?{A!ZF>iA34*XvZ*gGKcXb$i; zSxJ1_X0KwLoctvZxclj$SFwlpxI5n7?tS%gfbSJ{d82sy^9e3H9}cHz_iiUc{*Y}h zuvQ`O?Z78;0zJ+y$IG$u$DzCP{FZ)yBY+w2Ja`ZrF~ipngH;%~6E55g2H+0<#Gfv> zQN&!lVNi_s-m`x3hgY)tw}T_PV9^*XS?A9A&-snfez>Rj#!_hBetMZHNj}y3t zQ+S>@l-G%G`HO?v_-vjJa3%ga$KCIVN9T;MSYuAE(Kc>9zSFxr;Et9baN4^7|FwOa z;{Gc+A3KeaTYj>RZN}I{&RYH8zr|kmx0b)e;*<1oQ2vd-`^FUu+!I4F*H*+{|F}EL zlaHdGANgH;tf5o<#K=DQPro?u`>%7B8?jOB#m}6WiOz`ct{&*ja&_q?~QyYkQRi?b{4e>}mB<1Vc{E(G7@O5#}F zjfdlCu+jTEvFY9Iw}4=(-vZ)yC!Yd#49`<+z%!~szsbZ>iuM*}pPYu0#&b+hB7`eCnLtSN!l-jNs{Z@B(LW_|MtHy$log!wvBi>%|-Awdt^4 zn+`aDQ@H>>VdB39TXeu3?8rH=XDy7tEIaU>4)S!s9$S8qT#qO0c_sRB1>fW6@)mcs z$L-|D@>-2+){?hwYxHr<`Pk^qf!jaM{>Bs2w%z0SNRNHYYpeN7Jen_+`IJ}G$re%>JPkBhk z#PrNZ@qcBOL&&cfV~5qIPYs1;rHU?Cy4hBOe@yn0;Um|UPF?&tmQ&d2%jAK&B{+{fYF z+3dq_cmM8md26`~@3pPNf5ka)-JJJ~^U;5trG5#gd*8c5#oc`%NA6v~cX&^?H;^1e zHh!&be2oWUB(^uhCs-3x7!iBe5a+w$)nW__xNqD#-+i$4MX)RGxc*V_o&4Rr@9r>f zJniNm>)B%L_QCt#Eko-^U=WidxyPMRL~t#$H? zT!RZZudqj14hja&9Ai)V5{KGh&R%$9Oq4C zf``iieCiB|S8?a>qr;RK-N`sB zh3*e?2Jx0#-~|@8FKpb;`4sm8OyQ|K!DhI?XF1?X?jUb(+=#z=Z^mbrJSv8c?}g$w z-02+_Ji~G^o?K9F;KkFq>(uTxZF}Gi4jRWL1+VZ>9vE*gzXRleOP=o=U#-X$?qIz4 z)>jhi>PnpZo8R`a7dvoIo>I@g* zBPQ0u1l#Osy>a=554FudicjGH&d9o--i^uN)>Tx_VY+HV~xqpuM*}9sHpfSK~a6`;Kz&^P%s3wK2SxW4)8o zrn4BZ_pwiZ7ZxY65j$~$0hoskJQPoH6f?0F_swtITE#q$<2GK)+4v5J#+GMbz&zQl zvlm>$_dg%p$EEiYUw5z?4{#87@CjFO>j$w5#F_OadgY&2#sa%yFHg?)6hS$Q|H#Cti= zJ3v0zR8|;5@(^$U^oJVd@%V%s)j;KETSLo*hJdbSs>06$E z-22+(^vSvl_#Z~ZNxbid6XGjg-hN{IL2^Efh&Aqt_wu^fTI%N^PCY!t_L%Ci&OF0$uE6e$1!?w$5`Tb<_B%_ ziB0o>wl#@o$8lNTJ}}J(ld+e*=_IelS8Z$Xoc>_0b{Us9j2jbEd5#|ZX5ZG^L!NOi zdz-g69^xFH;VLe{JicqMzMH-9SWblnxmS+mQ|AyH{uV<;oIZ@r45xKCEzlGDVCE;foe{nl#3gBs`ajz6)9@35xey&_LI6InPm z=4{5`+j`@^0q{q`@4vn8jp5ne7q}!ZT*-S{&iK1<_PM+R5}%XXiDB>kz3tuga)5&G z}diy7q{d+$4A{iT(B#1LtF-F?o1$c*^Hu z#I75`27g)etK{`tu}ys9U)V2a_?pjgU3_p)tgY8KzMOJ5HqH0D1DsuMpd0Tm<3!$C zc}2M&ALz?f;>Le$yAvOXy}e;h*_zx#I>u<{lsa6N~a~{12bXLA;Y2tdRq78lMxd{uZd-8(-U8;@dnU*U-1U z@!uFe(~sN66nyucFYmC$oPCW)_IxME58-d^V88DUa#>eD;kA3*_db5dKh;4`_AT%6 zUryyiKI2a~c^G_(7aR;nVh1yDCccVT;k#U|@I8K$v0i-d1@o}9LPng$%U;&Oz~XNY zcM-kj;c7U>HMn!<@$w3mBgi-i(gwCgGB{5aSLCqHD;b} zJl%Tw$l+=Q}wMzAN2;RGJY;J>)hA#aJdI~@LgmvfPam0-76c3-*MlLLxV*f8d9H*PJvok^Qr z*2BLw?zQ7Luk-H5b$rBqJj7FdTy)ot`{OOXxMy*a40&tmQSbX<`6TgcE-;VNa+o_; zPNH8KujwK`J01_`aa19rubzDR&4+BEC$@F&SW`apkMq0lDwTPG&w#U38Ue{03cJ-<6>cmGG>j(K|Q z2fGT4xm#f!?qM5-a1-{8jeD;J=dWfxUXjNo1=m*M^Ky!eF*yX!R`A9ey3EN5WH0Nlh|dW~tDXCHa?D%P17&$Q2fXRHrz=IJAgd)CTNv&Y))>AZM_pZw)* zpzxD2ZvH9$;B&vX%eRZ87%y)8F7~%_K5c91eE)cN-H3gPm?&}pZfk!Kn{VgbUK$2qBlmc@_H_1jN3ogh@EO^1BK}o(PTo+Q$^8RsbSgNY-W$OC z8&B~ractYW8JBPfpZ43p?(E|&-uu=ayS$){mltpHw)KtUJ{dak)p%@f4l(w`k#ELh zW7e>P>}0g*IXGVXwnz3UkMTQv?r(|s?c8zz{_D$w`f>rE%8B^w&Gd(03?>w@ycfJG zFd=sMKaAWD?pDNX{Ks|W!{Bsdp7zPZ^*#{A8kN#0_s_TAXcXMDIAJc_LE zDwyDVUaGief@s_(0+wFt@FhHmMV26(Bk;~{H z`*D2wr^F6+aU6%)#Kz;hxbrXro56Qw-RrQt`)&6fd|5j^pC&GFkN@7b?r@w=+{%4- zx1t{|mf!e^gHMKwIEJIv7)w5Ckst7pthLjrzT_?)`gF(#igse$wfgiJQCl>rH7UMl1-HhG#(H1Lxg)V*h;8xCPUfUQOk8*Z-0#=N}teoNfN+!6*r(zzC@xVL5JtxmCH#l$dMeq52!^gk< zJuWdQuZ`nfVo^DDbeH?`ggNgAZFlzag5UO@PHsqC`!$~gKd}18$_x+>KZ|3=9-vIJ9zmCuIwRnrk?qM}v8iOHt z!D(aa zIDvCNhz)p>_@3>=^2`A^XD%`7{cMf=f}3)RJ>&+MmphCr^s0?nZ~yi2)t>lhOn#!n z8nUy+{ABIV7Pck+=evX+W9*{C+r&B7-g)U#%qzdmUF;3Of8ru;;vv5B@HiHKpWoYZ zgKx3Bv7fwn;Jp5=*d_+}E(ZM1Pm7On{3TCTaTl;d!SCBS`}94`dH7VGqDyS~Tg>4D ze%K;c!Ku4xV{$<-T&|DP@Qdp>kK5yQxYG4FGH!V9$^q`kz5nqrvgLc?Q0^s8ClAHM z-HUgLRf~D+jmZPn>J&c$9cKKH-)w8;HNgoJ!HRo{5jnB84kLHi zbpHOoJjHh0el0#yZ*P0zo&Ag}-WvQQFX9%T;4-_}Ar|8BDE7GX*`WS3YsJ%?_ouI!bEH>836Ut za1{r4*C#d|ci-dbYPrDg{rYkMIYq8`DtTddzA@{_ShF_+JIGzw(mdt;z!tT)e2VwS z$$#f|HhB%NwQ)RWw*Su29Et04D8KL}dFyb0{$C8#<30R{kvPK7?t0wDUB#TfTpVsU zN6XvdIgV@FALjP1lk??*|+}&(~Q+%Um99y5>V52t1*X1uhC+5Ao*+RycVh=gZxp0Ub z<`ehoq03q}$a`w*oXc8gw`Tc(o%Y}hoTnRCwed5J{&0oEBeX3pI)?!yl}?T#=9D>wmrc%YDjUw44>;wMhv>dOar@J2Ca z4&M~~S2nNx^Y{qw@e9Z01(@D?T$Cg508gXGpVj#tufOH-v+=~e^&!)Dg0*zpLt9}7 z-Ix4_J$*dizVy&-%-n2sUi$b&PLw10<^AZm8~wMlj(_=24DkdHf}!34VufeR0pd^o zM)q<>I&k$~Y@|y(ej5&njXn5A-?(B8yjXAUR?erGQ(I?FEq2pq5A)W@HSA%VZ%xbVYw=@w7@U-+S<|=t6X7G?$|V=? z_mhiR*E^VudF!%A?|%8i-}^VFn5QrP?tO^=e9yLhf8%O6D&KTZytnu9e(#^@+lvnM zVPDr<=N`xH=&ldsE$3D9k8_)oC-}*m&znj;zVDk5AGO(rlVSlk#>GTFa9=AA!x!8Z zZ*uNm{jK{?i2>ZmC&L)si!B|nW(}MTCvXK9cn;gJ0yD-Hc|dI(uI&dmWN;J5UX5OL zV%xhjaVaO&IP^@gCXValI}XVYI3-tDk4tpIkTJZ|zLNbF98OHu@BjZ}xyRm*$0qxz z?PiGJV+^<1p!OcI-n?R55kK<^9ltu>12E%# z2sge5;Wm8PTfBJ2ndJiZk3+a1$0aBDH~P&D`uL&972(7A7Ef%dH?b+Vyz%i)KfdmL zPv$$hr{ni>Pa6jna+~+2&v(NcFXr#zG#qc`I*R%^8g+ zF8zBucpMpHdmB`T^^Q=7tZj26K3i2W0am=v|9z z&mDg!*T3D}cYAzM|Cq-+zx6A4=nejKxa-aTcz8-i&T!8s-qk_p{tZy#dU73aV)w~^ zIy2TisH(YW(^^NXb#5BUKnkMDrq>p1Iv z9v|`7-6{@ZZr)ls1b5BBfOx@<`vb<*dn@3%HTJbmJdDw0{c3y41@M8}@O3lzQDD*= z!#?^j0#7hxA9}2JPmeET@B&Bh8>h4nUbd~T;5ONx#V5E&^5Ir%`6_BOTg^MbeO2y=-QD;@4DgXY+!5==K%C`z`{J`Wk+&b- z+aD&ht=G1g8{gKDf)37Zsjvvm;0C3&C|#B-^3U0eH?x-KDZvexbjkD5`*$3 zd^^7d@E(80C!E7&oX0166m57kCr{9ahj<#jz3*Yrm_o1p)W(C0eH(OKUw)wv?i1(Q zv3uP(`;+f_=jpTC{LZm6u}7Y9c5%aPxlSb9k)atU2R1b3T3f7%uE*Y;h$+x3Tg6gZN8fw^&=Zdjuw78MhwG z{C>OsbAHoGzyHlG-`nv`d4?D9egEw`Kf#Ra=ec%lG%l=rS@n5arleIW+oj0&H9*u*q=6u$gm&@r^Cr0I{J#ZEG&1olQ z<*s$)GT!e8^TAu!o3qyb9Bq^TNFCjXKp&|A&*$Udw|_= z1+&5H8@W^a)`d|q$4^}RY5uz=|Cm2(!bv<*o`@cN#}~YCH{!ATSRa5|vwi_5#0zWNmoJ_^PZepT??Jpd=-DqiqmoSZRO z@dkh$?+I~Qz7{XzYJMh1pPGK(8|LHx+Vn6Oh9Tc)Y8ZeoSh44S$vI$XV{j4O&8Kpy zv#`tl?mqXpyLo)ZX?|4Wmv-V&UXo>-I~2ch&^m>zHRikn60dSvK5&1LmkSger_&gn zVv$(&ZEtRS%2Dv0eL822g5&P%Yw^$3oW zH{anGK9kiJQ~nY={=XBSuuIMFtNENR{lx%h@mH;ohYxXqjqM?CJFoSVoxB+DokADe zjVbPa_}ZJ)yAglASKV8=dy41ud!NRC#XDXp{7D|xU@ZJ;ACKv9Pk9fgU;g7+_+HNA zTDV-UlePAc>lnTI8QN{o7^8^>RFKhB#|tTV1{jlQ-sklUIk!uO4N z59og#h#qC z5951ydyw-T9PWL`e!PYEx<;Qb> zij5p$jrHHgc09qU$+>Uw%9R&fSf##&FfWq~P?pO$L9h8K3<|7#vhC*y^7b zn3pTaCeE#W-xzmpcfa5GvR8AN^EtQgHwFLUN*$ejJ9*>CdwwVJW|sGH7l-+KHJ^*& za=AE&8~hkE4FwxZf3R9T!Dn?wNAG{*_G1@2X3uosKHuP% zczqIG;Y05X@epr*l=sPq^ZnQ+&X@cbCw=~>lYiB?YD}zF#6jEKz4%t!ImK4o?#3VX z8vo@4xkVnJ%X)40D#zVYuHrZjJ{B2V)`uPW3yyHsxtvLD4*y|CK9Do;@A2>)Cvk`l z?|S@}8*tj4it}=VT;NR_Y?pWVo&76EPx5d%nV6LK#=et#S-IqVu<*v-^YQ~btg#=S zn^)+^Z^b@ryv$KY?x|huc1E`1b=q{*H|D&PGG5R_X5ti=g64hKW0{@}m3`N`pXc3P*9P2Fz>-xvDw2%qtTwp#wU5qaEK^UeI6 zIKW+FAtrcoKX#iJ7lqIDc*x92pp(pI+-W zu2$HrHYd(v&JMf}Cvc&^hr8?W9roegoIZKDapvJ0&e)$jslTf|8Qzh1zsntR!|u&- z&Al6*c0civ8*noIFV8bq-s32JIP7l5VKQoO1aoo$ea01g%U|E-w+OnOA^OW@ymeM` zxR2jT?5qCdhvqDNm%E(V+9OAm^ZL=#eejPAZt@xbD=@2Q<2g?AleqAeoQb3SqAm6? zv3CF&K9(QGeg0ft;d}g7J_{y|lVyi><23BTgF4th@A6?rZ4RES$1OO5E%NScn8!n$ zzZOj6Al~3Gj;S}kG4qOfYsdMgvKOx6wn9eza?UGH&`pPNa&m)le3x7F$^0TQRf}(8 zdGgj8Yw55Td3#TeJ+uxV=}iMOzHD#SiAheepGJt-iJPxD{Wq zA$NP<(PDr%upQo&x6Xn8xlfC4IF-}jO@U$i$#GG%E<$qn*>B4^+}d-2`6$U8^#7``9;K5em&b>1QP zYk$1AUX7D-hT8YEJAL2Q&g}f+h--4ES{e6YLR^>U`B?m6#2lZkz#+bhmoZp?BYo>& z#eL7W^xNB>)+sn^y*aVb-yO~dxPc9^7IzpKCXB&_F_?xAYqEE9vp&w_-)q@R9>6(m z92;+OZ8EqHM{mYnwL(@NA+O-zWx-kFFo^@!;I1*Y(?y4U$7^qJW8rn*>d$7KJNw8p z{rf)OeDi<%=Z5eQx$2DGaUQ?>cLd1g{q}nBdHx0)*e|8O7dYxH5uvci$C8<+^@zyJjXu;H}Hb&tI_*>_Ek?#OcS@tnZsfHH*efLJ@CkeAH-%d#?;#v z=gAt2J$S!TA6kd!PaeEZtoxS7-;KwYTT{M|^NI8B|H<|o?6scHoY^@Qyu&L#z7cgN!dEVC2t@LwMAMtCguF}}hE{D~L5!V+%4t2O5E?W^n$m-wZ|6TWeN zcn;@V+|TahEBV$>?D|dcoxJJo_eAb`+_&$yxt|mNH+<*&j+Y1gJs{ug?(@j@u21eL ze~-6FZLxpwP@C`@&-IP#tMj?@@y$GrIhz>neCF`q8uJf=RYg7|xBDHpoteMg zt!iWOSKk_ZvOG!`ztGEv_AayAN>`k8$IrU|C;2P~$328h;@+sr7LR@8Q$9wZ_OR z;~YKq*C$8kTRFSE6=TuYJ6`Uw_L-a~7%G=>JJ@Ru2)5kqopX1E&&>no<&jU47vzhh z(A9ObXJ_LJcJKk8@zn>}moLQwpKx1WydOkXOz!3Euz@S&UQf2sM&S;SAA z<-*luwJ+DuE6(x(zD}pMwRF)ruET~k_Gb^?2dCZJ{^ZG8&jwtE5iu5jG1nGn*bwWz z`(P55-iuFQ0p8w89Pv%TX*gVYHRt(p&SPAyT#F4jYMn9}yo5nq$89zK;IaD3@n*+W z`iVyF?R1Uk!?f9+l{NV8Xoq)ZOYkmj@%60mJ z@7EKT<`jC_rk*YK#~J!n(x=X zQN=Xhn#C@=aMD@%Qe5aXCT5ErU)xWO+rK`zE-#TWCKs_qo1AmQ2W-H?-V$=b-lcL3 z%stHh@mJfpfM;xW595Sl95z#WFT1z#5P$K_{I|(5_?aBn{Nb$D$bWkq+3&O1DR*eo z$2a(&ee6kp_s9Rl4R6ay`$d1}*<@e)DeOq>$|ZiqVf*7(O8;KW&VZx%qh^P393v~w z?Y^gn4s!Ts4}0;CGq|t$joh(MxoHeXcgNdH4qP7OZ~1k+r<3jcp%|C9_%2xN9`rp5 z@Ay*OFiGjHX5IBwq9&$2&$|2#I~skTA}Mwc7-4c1|o zoEYISzT!R(kK4Exp7mZem+|&9URmqq6})*bapf;|8?!Gx%O~_6`J{XfXM2aI?meD( zwdOziotMAm2Qu+<=i}G%oIL*Pn}aL%l4bMGu)K$Rxc+Y9#YP2JKZuPmhi{5lCsw_~ zvUlUlCb$t-wLbpxH9N(^KH50T7vs8|AYQ-Bd9{t(S0T#|^I}M5^X^}I6gaRJZoECr z!8S~Nn0?`uZ7_(BcpN_ztGEZ}FnBL9zy~sLY>l(v4Nk(c^U-aMVq8tPIqmpe>75Ku z*4fWq-{gGJ-`@!2A>(BB2Cz4|j5mM$Ip=4G`;{H$#%X7>7hXQdeWg8{w8`TyKfnq< zjBn%k{NqgWg?+5Co{To1tk{bl=cQ{trhoaty5O#b|KtHSv&|m-WS-4@4p%s$$N^#s zJHLo8w8dXrfeZQ+7<)7JnTK0A)3#P^4$tsgjqmcnxUDvawVF=*(uG%9Uwy$&@BfDn|9knY4>Pg5 zcYFNUd9}I3;4JIQ1+(o!Z_nlYY@iVU7h&{J+*4=aXFaF{umT)udz#Ba2 zKgv19?w7HZ?(30X5d(ALX-|Gu#(8_*ivPxczN155KJr!}OZSR7a@IYFKiR0nAHDD6 zi}FY=<3BtyhI@WzgIO4luZmSNUj#$x_g*%xkWVaHf0;8(hdDfTc7Cw8Hr-^%ewFiT z^BtbiWlY%}Y%JLBp9%h(|M|aa=jZW}asI|f`uUfy-6`7EE8iw|&ca4>_^F5+{>2}i zXPbF_ZME~`H2u!A+B$nEa;tUnES+#+ufx}skvsUpI%maI=amE4w*A;|z4x5BDdb^6 zJmCWt-;K}U#r-sFkc9*BCkMB%1Y1{g7Cg2NZsY>o!a2OgH|3Ssy)sUd!EJr|)z4%v z1)r@agV*Gax$-`D>gr;Bd-0PP=+i-`bK!$?8E40poLL@$z344x6PMllcz)jZ!Bct9 z*ICzGkeKzpk6-nxBf6Rw@LxMRsuvFJ_gZ2hV zf<5sEuXh*!IqQZ^XZb8XfLk>goC@#y8-RIp^x&d+I6H2S|N1yWmRw5T0ek}g_EuY~ z=;Mbxu{@A{`#yLg=T6-EJ0BYr`{I^!*kdtpPG>fzwue~Z7#VHj?6>x?tv+HKy|~9F z^Y(E5ah8ldF%=VSBaKTVw38ejC!M`3M#B_mhxkyzaduf$R8#8qF8$7!)u zE8Ch*GYuoQi&hmKP=Qyn3_t)X8ayhnkV%2dqnZ&)^ zPyAkgn70DC_`S8Ut<#2AHYm=Gdwj%yawfj>F^=Dj-TbS@tLQ$*#8GUGk%a-@eP1{PnF<;9wY`(^~V!^x18Hw%m`Oao+wo zU<`KPI=(2*Vg659kK=F+yXIgOhH*LmI&;C=)_oOQ{Qhn|zF4c?-G~=-+7nlBhK#l3 z?4h=YJ?*E?`=oy+keK#2)nKAF=qJ`^p`Xt2ny!z6XIvB)F>!wO(9IUPK_Nrd8ijpi z6n3%0xi0tPxA}=KvifA@6gufPHoa_=L&%b23!7jAmhc<~#2Y?fPOQXItalH*lNg9U zeR731Ov0IXi$4ra4xZt99Mo1|eB-agKe)L$Tz)e9j^DUpy>Yx%kGtBFzmmPJ!Efcw z_)}qnJ?NjVpT!S!8CTo?&cQ)@i?!k%A>Pr^I{KRra6LXgIjx;I_D+v~+uoSi(G{Ej ziu>Vf`OoIr$PT%X-8hFcd@3&DidS$3Q_BhRH=M!3?nE-;b36W_LwxneXEnaUfjq5k zKSfN{;;z0C+t+_9*pVNsSq|7cg-&bj0}HouE;hm!d*m&-z!=Q?`!I5r`w7L>%y64JYFGZgeQ(sK^82DgI(^4!3_6o8Xd+93l2{ z1f1EQ4EZ;+_x0F*Eq089@Qu&7h^Lp_4@WwNt9VTYAGNI^e_4|ocOq9lksa6V#jdyG zM>f(wjyc0y@g3|tSLS+uf1R_2_kEM&CVBkLzSS?!IFs?Td)LR$%?scB<#&g(owzkm zm`|Kq{+PY!P@Ijed}A+dh2Qv{ed6T|IEBmN^;RNjNT?^+5 z%;N7C*@q5iz#;2#0It6b=A6}9zahYUd|TY9m2kKD5JwfZz$JOLv*RZn{DmjGSJ`2I z98Em?4#0i9Gltvbafn@t{)7CtS;%R#)4Anj^Z2K>mpxPZ=LOpKf(d$OgR>g5UrOI0 z@_@6#C)xPN-&Ja#-<)keBx{V1>0$>z!h<;Q2m8fAZkmsLyTO`TOy7<#a07S58Q;a8 zjC(0~!NZ_lhN&&_3Rzs+Hd9(r-Y*|Vm3BJt^cADQ#+kFU>nfp)NHj;*IGOwot? zS2KruY;ZQbw-1|PVSdG7MeJ^79i6x116&eI@gom=@&!3~!yj#Nhxy&hVs|U&Qm$nU zKfRj!!QT8MW_+U-%hh5_#vI$UVPJQMwQRDNdN#u!TOP*$?qoK>Bb#BA-SKDfixaqJ z99NwUo~<44#YKr+|2&T`t+y7hoqhMMJYt`5cXyvX@r5tRTC;WRx2JVvvTy&KP~7zK zdG9T?zW2p+B^UHe)+=%n?gta)?zj1ShrwC%#pm(i&dx^X{v!TW@LVyLefwvV-pAF^yxi;X?W z;6J^QEBBLUakk^^xc`^G7g!!=yx;bTcR3y`oxI-|?kBFNyfylYxx}g86!zsGHp&6o z;~TE?JHF!0?bs<7izN=>Z`%EB2k(uOxfh?|3yzV4bv*hYXIAJXCtr&xA8c=VfZy04 zo@B&R(caiNFV1j4&vGg`ZF}6!x#GL?J!0>@IoXIS_=oH9Q89enZ{-+%IfL`#7|g?U zYH$2E{`LQO)Zge|45r65xTX*9=yZPhXT|>Z#9O>HZ;d{m;RAmqmes?COJ05!zmUf( zYpnky{vyu?c3QJ>GVHOJd_;EVV4qxL%$&2+&vr73c{u{tkMEJaBPwrPUI?c8U4{G0 z8|>WqVZ^zePh9wc&Fqp7h6(X=*NLIK^WE&NE#`PH)-YnuIR0A$3-CeaT6_Xa@Vxf0 z_F8PhwP%A5HSFVH6s)y@%K z^nD+F<8pOf$@%DvTsbQ)(OC|MXTAI5!}B{}?ZmY*k#DWPvBaruF?Dw5at1YD{Veh3 zD}G%JZfAZ)P8P!t;}da%HF3plam6dKj(yDu_j5+M!u;Z>rsJL9k01Dkuhil#j&gvx z>>g?61H#8x(wgkT~EO?Bg_^e4PE&xWzvBbT;RqQ(p|= z+jseujO9(`F72NW;u)^S*S!brX$_x5kAIVUzK8GvxA0ZlJ~%=4kndVHv5}r}lDsnh zlVLM1(Z|N!=WNioR+}z%$`$sfXSw0H>pLe8;I*?jui_g3ZruNP@7=F9_eK0~?(4+E zT6@`pe!gBD)ch&08h2&|Z^Tv%#b@7&VlKY$XdY&ijgeEx!HY8ds1>-9GqmwfTm6IB z0{gGV_w*Szrr;fZ;{{puD~XM9c|mQhHoaF9AN;lkujs<1r-C>772}sVhdi7)Z?IHe zei?qIRF|>%^t`v@OI&y7^$ie?HD6@x%mImY^%&DmJeE6J(?^F~6YQQgIWs@;zj7nz z7+-b=;yj$;{r$-6<5>17u5r$J#8aMtV|l>&@W)-PR;&|K`H$?i;6x7KV|MVDSmL$V zi2X1y8^v5Pw?baNQEtY+_P&!C*@xY*Vt=;EY4R7&Jj#CZfpg&#{Ho#CnVkdQ;2oDf zOU!Z1oe2B-zfa8L?|!@E0zX?%KV9@JH#$E~+tVB!{5US*j`si`+J`PS8rN3VW~+VF zxJ{moYJGETQ}mq!_i>vZV|!y*M~-gu>{?!MHe=5ARbuj|_}+a_md@rBS z#aFHw25#moY}KdNUiO7CHrNx!=y2EQE4OoQHnClPa6Xt6huyERZZG_TV>OQ8kQ#sQ z$9CsX@QFV$R)Z-jfVD|jD2HxHOgEXwu7w&NQ!zPXIm9(J+OIr)a|{4D?S zF`MvQOw=%&J%wcd`#1V#H74il6Qe<6_1JF;MH16Bjj~ z(IpSC@4eVRY}m&*KC5A3dul6W*r(vQdN@g4_d6HhfH+!@B4fw|5i8{={A6x#7j`)( z{wwse-I(0R?_vW});pVgfb+&-5N5h+R9G6dn-D%*(#6X z1^?ph^smGqP}tQRQ@UWpbH-8k_%VtFHUTL5Bq7G zXP>_KD|E0=oZrb=ABC<3)UU)_7rj zJT%Xz3Vw~-e8Ucyf0*;pyY~RDe0lu$xBYhj6#q`hpXafkE_>pf{%1M=?qlQniv8HL zdGff2zvk>?9&YTtHXFZ6Y-2<7fP759amCr_w3oH`J6~wigU{ySN^w@PRrBTQP3^LBJyk4-S6)`u-P!gXB5X$3!x zDfo)-%8?KHoow#qoaf#6lOA$gWBqc%bm>1Cj)lW}3zX0LIIrGbxGv7dQ}>QeJj(U> zykqfi`Ha(tOmjr=)baSZ>&(jo$tUMG0PfQ_-G@##*AC}ouk+1E&iP(2fyaEVzk+l8 zjqeIxiK8*OVBFvPOq{gGHTtZvR$ix9jO6UA;fNTCqgt*or>!iWYCMO7cj7xT?1cs6 z)~W4-|7?Rpd$TV-IC*bOvG#uA470;;{98=NcfH$|3vd}f;2odfR^R>i=lDn2oovn4 z`5tk{!L4EqK7^nBvjqP?0RK$@|He2N>A&p_j>=&=gM;$(kMS9soWqzJe~c;GIG>!+ z|IW~JIluhj{@=YVU$L9qe%J7Kkf+n!@8fg*z2}|7I(GYpz+?H0Z~0Dv0psG!mpH8K zdl8?-Lu}aOEcS5@wzI`r`+l4JEXIoX+z3|T=-1(oax1tM`?n%{EwR97Tz@BejKd5} znNyQ5uPtkal^&@5YsvV$b*voASr{I75g1$Z6AqS1WWpoAahrcQ{|X+av9h zhv{pV!|_GOV{`lQPw#ze;X7ySc>L7+KR#;?uuj2ybBeb0sn0w^CS$dgy=-?jJaiWP z!Kv(Do{E9;LCzw6;)o|=E|xeB3!4`&V`}^wU*!*d+|L+As|aN{iYg-NwDz$F`<>tff=!e_SJ*7?fvtgIDiZ8~@c;VzYJh>pz+E z(wXt{njPNN8E>C0&Y>UQ@4l{W!AW@>oQ=ol`yjsa2KcM@Krp$SVeft?SgYVYed@2n zaXD)F%sF;WXT>jEa=(k$aDlHFYzUR$$f3(xbMvLh$lbtoA|<-J@K3! zYJO9*NiNtM0FK@YcdUnlt2sa4u@%>i>(ed%Fy<_5b`JbEMi1MpVLSWc&vF+3^(Aqud8{3+2ynnyIe@DchGx{Fz z-xNx${69kb-&l|zd?SdTwREwAo$?VoKFj%y(YbxtWA1nhG%tLSJo?A{|B{}LFZQOF z54=_A;s-ua<3B%GgY)tyId~9r^}WOl9?Xfeb^81aFJi#gVy>p=81H{S1{Up0*Wx2C zig>E&70=}aF&$pT9cJ|5z<%%pQ!o^M74I)(Ts!(zd{KlN|Zej`B>~l`M#UETIXUtjQT^}#Z$FD7TrX62*jrDRIj^dZvyqq8o{@W=y z?cXN^3mumyyeIrO0p$SS>U@lU*0Y`d2f;Uc*q~3p8vo@eZMIoMMlC{ru(3ILDv3#Q*&6E)+ZQ8n2hz#TpKW2QgTln7lq7iskaT zSjM(;SsdX6uVIMKuLX-@#V+M)Y+o_ITtM#K_>-OX5&zv436|1$zk$> z_r86srIRf3;o)|j~McYbK766zVUG&Ys$~W5&xSPtRr zUI-?dR}y>qrtcFrT@M!IB|cz(?5e$d%0D%sJsTUC5i|G@8-DvBXH<)i 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