diff --git a/CHANGELOG b/CHANGELOG index 065e6f778add44e3be4ad4bee577b8bb91070599..9959818ffddcd6c0072ffe46f478a1a24cdbc057 100644 --- a/CHANGELOG +++ b/CHANGELOG @@ -1,5 +1,5 @@ ***************************************************************** -* ARIEL FGS HFS Repository, ARIEL-UVIE-PL-ML-001 0.4, CHANGELOG * +* ARIEL FGS HFS Repository, ARIEL-UVIE-PL-ML-001 0.2, CHANGELOG * ***************************************************************** ################################################################################ @@ -67,10 +67,29 @@ V0.4: - Extended Star catalouge to include neighbouring stars and load all catalouge stars during operation - Improved saving function to allow saving of current smearing and constant image components +################################################################################ +V0.5: +13.September, 2023 Gerald Mösenlechner <gerald.moesenlechner@univie.ac.at> + + Fixed Issues: + + - Fixed error with smearing kernel generation + + - Fixed errors in random seed saving - Known Issues: + - Fixed shot noise model + + - Fixed Simulink Bus data types + + - Fixed errors in centroiding algorithm implementation + + - Added Timing tolerance parameter + + - Fixed State preservation - - No Simulation of "Spaceball" events. Will be added once the effects on the FGS have been studied. + - Fixed uninitialized Parameters + - Fixed of minor errors + - Added Relativistic Aberration ################################################################################ diff --git a/JUSTIFICATION b/JUSTIFICATION index 81c5a4e5b5bd35af0faf0a199084db3f86be11f7..69dbe60a96a292550ca55391f6cb1a6f14f54441 100644 --- a/JUSTIFICATION +++ b/JUSTIFICATION @@ -1,5 +1,5 @@ ************************************************************ -* ARIEL FGS HFS, , ARIEL-UVIE-PL-ML-001 0.4, JUSTIFICATION * +* ARIEL FGS HFS, , ARIEL-UVIE-PL-ML-001 0.5, JUSTIFICATION * ************************************************************ This note describes the justification of the parameters and values diff --git a/MANUAL b/MANUAL index 3781f215a3b7293f20b7876328bf251d95b8ae99..bebdb7989cdd600e93d85e65c466c14870c9d1fe 100644 --- a/MANUAL +++ b/MANUAL @@ -27,6 +27,8 @@ from of a hfs_parameters struct update. The struct is defined as follows: - double ang_rate[3]: angular rate of the SC in arcsec/s + - double scVelocity[3]: Spacecraft Velocity in the SC reference frame in km/s + - double time: simulation time of the update - unsigned int channel: FGS channel to be used (1 or 2) diff --git a/Makefile b/Makefile index 6cb28f8669ca05126baa82ce81df171792a155e5..5cfd77421c35dc6f4c5f79a475a993815a67af4c 100644 --- a/Makefile +++ b/Makefile @@ -11,7 +11,7 @@ TEST_DIR = $(shell pwd)/test DEST_DIR = $(shell pwd)/src INCLUDE_DIR = $(shell pwd)/src -TESTS = $(TEST_DIR)/HFSTest.o $(TEST_DIR)/HFSTestMain.o +TESTS = $(TEST_DIR)/HFSTest.o $(TEST_DIR)/DetectorFeatureTest.o $(TEST_DIR)/UtilityTest.o $(TEST_DIR)/FCUTest.o $(TEST_DIR)/HFSTestMain.o LIBRARIES = $(DEST_DIR)/libutilities$(DLLEXT) $(DEST_DIR)/libdetector_features$(DLLEXT) $(DEST_DIR)/libfcu_algorithms$(DLLEXT) TARGET_API = $(DEST_DIR)/libHFS_API$(DLLEXT) @@ -23,10 +23,10 @@ $(TARGET_API): $(DEST_DIR)/lib%$(DLLEXT): $(SRC_DIR)/%.cpp $(CC) $< -shared -o $@ -L$(SRC_DIR) -lfcu_algorithms -lutilities -ldetector_features -ltinyxml2 -fopenmp -O3 -lstdc++ -xc++ -fPIC -Wall -Werror -Wl,-rpath=$(SRC_DIR) $(TESTS): $(TEST_DIR)/%.o: $(TEST_DIR)/%.cpp - g++ -c $< -o $@ -L$(SRC_DIR) -lHFS_API -lcppunit -ltinyxml2 -lstdc++ -Wall -Wl,-rpath=$(SRC_DIR) + g++ -c $< -o $@ -L$(SRC_DIR) -lfcu_algorithms -lutilities -ldetector_features -lHFS_API -lcppunit -ltinyxml2 -lstdc++ -Wall -Wl,-rpath=$(SRC_DIR) -API_Test: $(TEST_DIR)/HFSTest.o $(TEST_DIR)/HFSTestMain.o - g++ $(TEST_DIR)/HFSTestMain.o $(TEST_DIR)/HFSTest.o -o $(TEST_DIR)/API_Test -L$(SRC_DIR) -lHFS_API -lcppunit -ltinyxml2 -lstdc++ -Wall -Werror -Wl,-rpath=$(SRC_DIR) +API_Test: $(TEST_DIR)/HFSTest.o $(TEST_DIR)/DetectorFeatureTest.o $(TEST_DIR)/UtilityTest.o $(TEST_DIR)/FCUTest.o $(TEST_DIR)/HFSTestMain.o + g++ $(TEST_DIR)/HFSTestMain.o $(TEST_DIR)/HFSTest.o $(TEST_DIR)/DetectorFeatureTest.o $(TEST_DIR)/UtilityTest.o $(TEST_DIR)/FCUTest.o -o $(TEST_DIR)/API_Test -L$(SRC_DIR) -lfcu_algorithms -lutilities -ldetector_features -lHFS_API -lcppunit -ltinyxml2 -lstdc++ -Wall -Werror -Wl,-rpath=$(SRC_DIR) example: $(TEST_DIR)/example.cpp g++ $(TEST_DIR)/example.cpp -o ./example.out -L$(SRC_DIR) -lHFS_API -ltinyxml2 -lstdc++ -Wall -Werror -Wl,-rpath=$(SRC_DIR) diff --git a/Makefile_Centos b/Makefile_Centos index f3c9effe8b28f7717eca49073f8d9028892d2252..9f0459e024e54b32c434ad57261b80fdf972f0b8 100644 --- a/Makefile_Centos +++ b/Makefile_Centos @@ -11,7 +11,7 @@ TEST_DIR = $(shell pwd)/test DEST_DIR = $(shell pwd)/src INCLUDE_DIR = $(shell pwd)/src -TESTS = $(TEST_DIR)/HFSTest.o $(TEST_DIR)/HFSTestMain.o +TESTS = $(TEST_DIR)/HFSTest.o $(TEST_DIR)/DetectorFeatureTest.o $(TEST_DIR)/UtilityTest.o $(TEST_DIR)/FCUTest.o $(TEST_DIR)/HFSTestMain.o LIBRARIES = $(DEST_DIR)/libutilities$(DLLEXT) $(DEST_DIR)/libdetector_features$(DLLEXT) $(DEST_DIR)/libfcu_algorithms$(DLLEXT) TARGET_API = $(DEST_DIR)/libHFS_API$(DLLEXT) @@ -23,10 +23,10 @@ $(TARGET_API): $(DEST_DIR)/lib%$(DLLEXT): $(SRC_DIR)/%.cpp $(CC) $< -shared -o $@ -L$(SRC_DIR) -lfcu_algorithms -lutilities -ldetector_features -l:libtinyxml2.so.2 -lstdc++ -xc++ -fPIC -Wall -Werror -Wl,-rpath=$(SRC_DIR) $(TESTS): $(TEST_DIR)/%.o: $(TEST_DIR)/%.cpp - g++ -c $< -o $@ -L$(SRC_DIR) -lHFS_API -lcppunit -l:libtinyxml2.so.2 -lstdc++ -Wall -Wl,-rpath=$(SRC_DIR) + g++ -c $< -o $@ -L$(SRC_DIR) -lfcu_algorithms -lutilities -ldetector_features -lHFS_API -lcppunit -ltinyxml2 -lstdc++ -Wall -Wl,-rpath=$(SRC_DIR) -API_Test: $(TEST_DIR)/HFSTest.o $(TEST_DIR)/HFSTestMain.o - g++ $(TEST_DIR)/HFSTestMain.o $(TEST_DIR)/HFSTest.o -o $(TEST_DIR)/API_Test -L$(SRC_DIR) -lHFS_API -lcppunit -l:libtinyxml2.so.2 -lstdc++ -Wall -Werror -Wl,-rpath=$(SRC_DIR) +API_Test: $(TEST_DIR)/HFSTest.o $(TEST_DIR)/DetectorFeatureTest.o $(TEST_DIR)/UtilityTest.o $(TEST_DIR)/FCUTest.o $(TEST_DIR)/HFSTestMain.o + g++ $(TEST_DIR)/HFSTestMain.o $(TEST_DIR)/HFSTest.o $(TEST_DIR)/DetectorFeatureTest.o $(TEST_DIR)/UtilityTest.o $(TEST_DIR)/FCUTest.o -o $(TEST_DIR)/API_Test -L$(SRC_DIR) -lfcu_algorithms -lutilities -ldetector_features -lHFS_API -lcppunit -ltinyxml2 -lstdc++ -Wall -Werror -Wl,-rpath=$(SRC_DIR) example: $(TEST_DIR)/example.cpp g++ $(TEST_DIR)/example.cpp -o ./example.out -L$(SRC_DIR) -lHFS_API -l:libtinyxml2.so.2 -lstdc++ -Wall -Werror -Wl,-rpath=$(SRC_DIR) diff --git a/README b/README index b0e9627c20d39462e7e58aa42642722da24d3437..f93dc614e97992e602c44ef726ee17232332baaa 100644 --- a/README +++ b/README @@ -1,5 +1,5 @@ ****************************************************** -* ARIEL FGS HFS Repository, ARIEL-UVIE-PL-ML-001 0.4 * +* ARIEL FGS HFS Repository, ARIEL-UVIE-PL-ML-001 0.5 * ****************************************************** This repository contains the HFS, the simulator SW used to simulate the @@ -14,7 +14,8 @@ Files: src/HFS_bus.mat ................. Simulink bus object definitions for HFS src/HFS.config.xml .............. Config file for the HFS src/Star_catalouge.csv .......... Catalouge containing the star data - matlab_model/HFS_Wrapper ........ Simulink implementation example using legacy code tools (.cpp/.hpp/.m) + src/HFS_Wrapper.................. C++ side implementation of the Simulink wrapper + matlab_model/HFS_Wrapper ........ Simulink implementation example using legacy code tools (.m) matlab_model/Example_model.slx .. Simulink example showing the bus usage test/HFSTest .................... Unit tests for the HFS library (.cpp/.hpp) test/example.cpp ................ Example script showing the function of the library @@ -22,7 +23,6 @@ Files: CHANGELOG README MANUAL - JUSTIFICATION Dependencies: @@ -54,4 +54,4 @@ Run Quaternion_Calulator: The software provided here is ©University of Vienna. -GM 15.March, 2023 +GM 13th September, 2023 diff --git a/matlab_model/Example_model.slx b/matlab_model/Example_model.slx index 33118f153f2d4f0c084761eea4779725c1946c3b..ca28d2bcf29bf16b88c9a8f1eab8976003490316 100644 Binary files a/matlab_model/Example_model.slx and b/matlab_model/Example_model.slx differ diff --git a/matlab_model/HFS_Wrapper.m b/matlab_model/HFS_Wrapper.m index c10f7f237befa78f8d284d1228b7b04ccf428c57..87816199d902312c1ffccb4a174282b708481047 100644 --- a/matlab_model/HFS_Wrapper.m +++ b/matlab_model/HFS_Wrapper.m @@ -6,6 +6,11 @@ % Note that this example was tested in Matlab Version 2019a under Ubuntu 20.4 % and might need modification of include paths to work. + +sys = 'FGSBlock'; +new_system(sys) % Create the model +open_system(sys) % Open the model + evalin('base','load HFS_bus.mat'); def = legacy_code('initialize'); def.SFunctionName = 'FGS_HFS'; @@ -20,9 +25,168 @@ def.HostLibFiles = {'../src/libHFS_API.so'} def.Options.language = 'C++'; def.Options.useTlcWithAccel = false; +%importInfo = Simulink.importExternalCTypes('../src/HFS_API.hpp', 'Names', {'hfs_parameters','centroid_packet'}); legacy_code('generate_for_sim', def); legacy_code('rtwmakecfg_generate', def); -legacy_code('slblock_generate', def); +legacy_code('slblock_generate', def, sys); + +x = 30; +y = 30; +w = 30; +h = 30; +yStart = y; +offset = 40; + +pos = [x y+h/4 x+w y+h*.75]; +add_block('built-in/Inport',[sys '/mode'],'Position',pos); +set_param([sys '/mode'], 'OutDataTypeStr','uint32') +set_param([sys '/mode'], 'PortDimensions', num2str(1)); +y = y + offset; + +pos = [x y+h/4 x+w y+h*.75]; +add_block('built-in/Inport',[sys '/set_invalid'],'Position',pos); +set_param([sys '/set_invalid'], 'OutDataTypeStr','uint32') +set_param([sys '/set_invalid'], 'PortDimensions', num2str(1)); +y = y + offset; + +pos = [x y+h/4 x+w y+h*.75]; +add_block('built-in/Inport',[sys '/set_error'],'Position',pos); +set_param([sys '/set_error'], 'OutDataTypeStr','uint32') +set_param([sys '/set_error'], 'PortDimensions', num2str(1)); +y = y + offset; + +pos = [x y+h/4 x+w y+h*.75]; +add_block('built-in/Inport',[sys '/reset'],'Position',pos); +set_param([sys '/reset'], 'OutDataTypeStr','uint32') +set_param([sys '/reset'], 'PortDimensions', num2str(1)); +y = y + offset; + +pos = [x y+h/4 x+w y+h*.75]; +add_block('built-in/Inport',[sys '/save'],'Position',pos); +set_param([sys '/save'], 'OutDataTypeStr','uint32') +set_param([sys '/save'], 'PortDimensions', num2str(1)); +y = y + offset; + +pos = [x y+h/4 x+w y+h*.75]; +add_block('built-in/Inport',[sys '/channel'],'Position',pos); +set_param([sys '/channel'], 'OutDataTypeStr','uint32') +set_param([sys '/channel'], 'PortDimensions', num2str(1)); +y = y + offset; + +pos = [x y+h/4 x+w y+h*.75]; +add_block('built-in/Inport',[sys '/time'],'Position',pos); +set_param([sys '/time'], 'OutDataTypeStr', 'double'); +set_param([sys '/time'], 'PortDimensions', num2str(1)); +y = y + offset; + +pos = [x y+h/4 x+w y+h*.75]; +add_block('built-in/Inport',[sys '/scVelocity'],'Position',pos); +set_param([sys '/scVelocity'], 'OutDataTypeStr','double') +set_param([sys '/scVelocity'], 'PortDimensions', num2str(3)) +y = y + offset; + +pos = [x y+h/4 x+w y+h*.75]; +posHFS = [x+100 y+h/4 x+250 y+h*.75] +posOut = [x+300 y+h/4 x+330 y+h*.75] +set_param([sys '/FGS_HFS'],'Position',posHFS); +add_block('built-in/Inport',[sys '/ang_rate'],'Position',pos); +set_param([sys '/ang_rate'], 'OutDataTypeStr','double') +set_param([sys '/ang_rate'], 'PortDimensions', num2str(3)); +y = y + offset; + +pos = [x y+h/4 x+w y+h*.75]; +add_block('built-in/Inport',[sys '/position_quat'],'Position',pos); +set_param([sys '/position_quat'], 'OutDataTypeStr','double') +set_param([sys '/position_quat'], 'PortDimensions', num2str(4));y = y + offset; + +pos = [x y+h/4 x+w y+h*.75]; +add_block('built-in/Inport',[sys '/validation_signal'],'Position',pos); +set_param([sys '/validation_signal'], 'OutDataTypeStr','uint32') +set_param([sys '/validation_signal'], 'PortDimensions', num2str(1)); +y = y + offset; + +pos = [x y+h/4 x+w y+h*.75]; +add_block('built-in/Inport',[sys '/add_shift_x'],'Position',pos); +set_param([sys '/add_shift_x'], 'OutDataTypeStr','int32') +set_param([sys '/add_shift_x'], 'PortDimensions', num2str(1)); +y = y + offset; + +pos = [x y+h/4 x+w y+h*.75]; +add_block('built-in/Inport',[sys '/add_shift_y'],'Position',pos); +set_param([sys '/add_shift_y'], 'OutDataTypeStr','int32') +set_param([sys '/add_shift_y'], 'PortDimensions', num2str(1)); +y = y + offset; + +pos = [x y+h/4 x+w y+h*.75]; +add_block('built-in/Inport',[sys '/mult_shift_x'],'Position',pos); +set_param([sys '/mult_shift_x'], 'OutDataTypeStr','int32') +set_param([sys '/mult_shift_x'], 'PortDimensions', num2str(1)); +y = y + offset; + +pos = [x y+h/4 x+w y+h*.75]; +add_block('built-in/Inport',[sys '/mult_shift_y'],'Position',pos); +set_param([sys '/mult_shift_y'], 'OutDataTypeStr','int32') +set_param([sys '/mult_shift_y'], 'PortDimensions', num2str(1)); +y = y + offset; + +pos = [x y+h/4 x+w y+h*.75]; +add_block('built-in/Inport',[sys '/target_pos_x'],'Position',pos); +set_param([sys '/target_pos_x'], 'OutDataTypeStr','int32') +set_param([sys '/target_pos_x'], 'PortDimensions', num2str(1)); +y = y + offset; + +pos = [x y+h/4 x+w y+h*.75]; +add_block('built-in/Inport',[sys '/target_pos_y'],'Position',pos); +set_param([sys '/target_pos_y'], 'OutDataTypeStr','int32') +set_param([sys '/target_pos_y'], 'PortDimensions', num2str(1)); +y = y + offset; + +pos = [x+60 yStart-15 x+65 y+5]; +add_block('simulink/Commonly Used Blocks/Bus Creator', [sys '/BC1'],'Position',pos) +set_param([sys '/BC1'],'Inputs','17') +set_param([sys '/BC1'],'OutDataTypeStr','Bus: hfs_parameters'); + +add_block('built-in/Outport',[sys '/centroid_packet'], 'Position', posOut); +set_param([sys '/centroid_packet'], 'OutDataTypeStr','Bus: centroid_packet') + +modeHandle = add_line(sys, 'mode/1', 'BC1/1'); +set_param(modeHandle, 'Name', 'mode'); +invalidHandle = add_line(sys, 'set_invalid/1', 'BC1/2'); +set_param(invalidHandle, 'Name', 'set_invalid'); +errorHandle = add_line(sys, 'set_error/1', 'BC1/3'); +set_param(errorHandle, 'Name', 'set_error'); +resetHandle = add_line(sys, 'reset/1', 'BC1/4'); +set_param(resetHandle, 'Name', 'reset'); +saveHandle = add_line(sys, 'save/1', 'BC1/5'); +set_param(saveHandle, 'Name', 'save'); +channelHandle = add_line(sys, 'channel/1', 'BC1/6'); +set_param(channelHandle, 'Name', 'channel'); +timeHandle = add_line(sys, 'time/1', 'BC1/7'); +set_param(timeHandle, 'Name', 'time'); +velHandle = add_line(sys, 'scVelocity/1', 'BC1/8'); +set_param(velHandle, 'Name', 'scVelocity'); +rateHandle = add_line(sys, 'ang_rate/1', 'BC1/9'); +set_param(rateHandle, 'Name', 'ang_rate'); +quatHandle = add_line(sys, 'position_quat/1', 'BC1/10'); +set_param(quatHandle, 'Name', 'position_quat'); +valHandle = add_line(sys, 'validation_signal/1', 'BC1/11'); +set_param(valHandle, 'Name', 'validation_signal'); +addXHandle = add_line(sys, 'add_shift_x/1', 'BC1/12'); +set_param(addXHandle, 'Name', 'add_shift_x'); +addYHandle = add_line(sys, 'add_shift_y/1', 'BC1/13'); +set_param(addYHandle, 'Name', 'add_shift_y'); +multXHandle = add_line(sys, 'mult_shift_x/1', 'BC1/14'); +set_param(multXHandle, 'Name', 'mult_shift_x'); +multYHandle = add_line(sys, 'mult_shift_y/1', 'BC1/15'); +set_param(multYHandle, 'Name', 'mult_shift_y'); +targetXHandle = add_line(sys, 'target_pos_x/1', 'BC1/16'); +set_param(targetXHandle, 'Name', 'target_pos_x'); +targetYHandle = add_line(sys, 'target_pos_y/1', 'BC1/17'); +set_param(targetYHandle, 'Name', 'target_pos_y'); +add_line(sys, 'BC1/1', 'FGS_HFS/1'); +add_line(sys, 'FGS_HFS/1', 'centroid_packet/1'); + + diff --git a/matlab_model/HFS_bus.mat b/matlab_model/HFS_bus.mat index 71c5c6015783dd6b76241e1dc990e31d512d3c3f..1fa1f460b1d88e9cde084c98550fc49dc5b3f25c 100644 Binary files a/matlab_model/HFS_bus.mat and b/matlab_model/HFS_bus.mat differ diff --git a/matlab_model/HFS_config.xml b/matlab_model/HFS_config.xml index c29b31bae28b6d9aa7fa1de1543a7ed06647041e..1f2ea96f4f2f8e949613195269bef0c4e48bf5d5 100644 --- a/matlab_model/HFS_config.xml +++ b/matlab_model/HFS_config.xml @@ -1,4 +1,16 @@ <HFS_MetaInfo> + + <!-- Global timestep of the matlab simulink model. + Default: 0.015625 (64Hz)--> + <timestep>0.015625</timestep> + + <!-- Random seed used in the noise generation --> + <random_seed>135412</random_seed> + + <!-- Starting time of last integration, used for saving the current + simulator state. Default for new runs: 0 --> + <integration_start>0</integration_start> + <!-- The mean value for pixel sensitivities. Allowed value range: 0.0-1.0. Note that the simulated flat field is clipped at 1.0 per pixel. --> @@ -12,8 +24,8 @@ <!-- Fixed bias value that is included in the final image. --> <bias>2000.0</bias> - <!-- The mean read noise of a pixel in ADU per second. --> - <readout_noise>15.0</readout_noise> + <!-- The mean read noise of a pixel in ADU. --> + <readout_noise>20.0</readout_noise> <!-- The mean bkgr noise in photons per second. --> <bkgr_noise>1.1</bkgr_noise> @@ -35,10 +47,19 @@ <median_filter_threshold>1000</median_filter_threshold> <!-- Standard deviation of the centroid error induced by the spacecraft - jitter during the integration period in mas. This will be replaced - by a jitter model from power-spectra in future versions --> + jitter during the integration period in mas. --> <jitter_error_std>5.0</jitter_error_std> + <!-- Duration of the simulated FCU reset in s --> + <reset_duration>0.5</reset_duration> + + <!-- State variable denoting end of ongoing reset, Default: 0--> + <reset_end>0</reset_end> + + <!-- Tolerance for the timing related checks for centroid generation, rerset + and transitions, Default: 0.005--> + <timing_tolerance>0.0</timing_tolerance> + <!-- relative path of the Psf input files. The psfs are given as 40x40px arrays that are stored in the C array format --> @@ -46,6 +67,31 @@ <FGS2_Psf>../FGS2_270nm.txt</FGS2_Psf> + <!-- Plate scale of FGS1 in mas/px, Default: 175 --> + <FGS1_PS>175.0</FGS1_PS> + + <!-- Plate scale of FGS2 in mas/px, Default: 136 --> + <FGS2_PS>137.0</FGS2_PS> + + <!-- Focal length of FGS1 in m, Default: 21.21 --> + <FGS1_FL>21.21</FGS1_FL> + + <!-- Focal length of FGS2 in m, Default: 27.08 --> + <FGS2_FL>27.08</FGS2_FL> + + <!-- Quantum efficiency of FGS1, Default: 0.58 --> + <FGS1_QE>0.58</FGS1_QE> + + <!-- Quantum efficiency of FGS2, Default: 0.70 --> + <FGS2_QE>0.70</FGS2_QE> + + <!-- Angular missalignment of the FGS channels from the optical axis in the the detector plane in mas, No default values available --> + <FGS1_Offset_X>400</FGS1_Offset_X> + <FGS1_Offset_Y>200</FGS1_Offset_Y> + + <FGS2_Offset_X>200</FGS2_Offset_X> + <FGS2_Offset_Y>400</FGS2_Offset_Y> + <!-- Starting channel of the Simulator: 1 or 2 --> <FGS_channel>1</FGS_channel> @@ -56,16 +102,34 @@ --> <FGS_mode>Tracking</FGS_mode> + <!-- FWHM of the gaussian used as a weighting function in the centroid calculation in px. + Default: FGS1: x = 16, y = 15; FGS2: x = 11, y = 14 + --> + <FWHM_FGS1_x>5</FWHM_FGS1_x> + <FWHM_FGS1_y>5</FWHM_FGS1_y> + <FWHM_FGS2_x>6</FWHM_FGS2_x> + <FWHM_FGS2_y>6</FWHM_FGS2_y> + + <!-- Time delay causes by the mode switch in s. --> + <transition_delay>0.5</transition_delay> + + <!-- End time of an ongoing transition. Used for State saving. 0 denotes no transition. Default: 0 + --> + <transition_end>0</transition_end> + <!-- Target signal in ADU per second used for validation --> <target_signal>60000</target_signal> + <!-- lower signal limit ("There is a signal" check) for centroid validation in % of target signal. defalt 1%--> + <lower_signal_limit>1.0</lower_signal_limit> + <!-- Sigma threshold in ADU used in the validation procedure --> - <validation_sigma>20</validation_sigma> + <validation_sigma>10</validation_sigma> <!-- Threshold for the Pearson correlation used as the validity index. Index can range from -1 to 1. A value of 0.5 to 0.6 serves as a decent cutoff for invalid measurements--> - <validation_pearson_limit>0.5</validation_pearson_limit> + <validation_pearson_limit>0.6</validation_pearson_limit> <!-- Configuration of the Tracking procedure --> <Tracking> @@ -77,7 +141,11 @@ <thresholding>1</thresholding> <!-- Delay of the centroid packet in seconds. Note: must be lower than the integration time (0.125 s) --> - <delay>0.09</delay> + <delay>0.02</delay> + <!-- Exposure time for mode Tracking in s, default: 0.1 --> + <exposure_time>0.1</exposure_time> + <!-- Dimension of the Tracking window in px, default: 64 --> + <dim>64</dim> </Tracking> <!-- Configuration of the Acquisition procedure --> @@ -91,17 +159,35 @@ <!-- Delay of the centroid packet in seconds. Note: must be lower than the integration time (0.5 s) --> <delay>0.1</delay> + <!-- Exposure time for mode Acquisition in s, default: 0.5 --> + <exposure_time>0.5</exposure_time> <!-- Brightness tolerance for target identification default is 20% --> <tolerance>20</tolerance> + <!-- Dimensiton of the Acquisition window for FGS1, default: 128px --> + <FGS1_dim>128</FGS1_dim> + <!-- Dimensiton of the Acquisition window for FGS2, default: 161px --> + <FGS2_dim>161</FGS2_dim> + <!-- Limit of brightest sources to be considered in the source extraction. Default: 10--> + <target_limit>10</target_limit> + <!-- Signal Sigma Limit for Source extent check. Default: 1000. Possible cause for 107 error if set too high--> + <extension_sigma>1000</extension_sigma> </Acquisition> <!-- Relative path to the star catalouge --> <Star_catalouge>../src/Star_catalouge.csv</Star_catalouge> - <!-- Identifiers of the desired stars (max. 25)--> - <Targets> - <Target id="TRAPPIST-1"/> - <Target id="WASP-11"/> - </Targets> + <!-- Flag indicating if images features shall be generated from existing files. + Only applicable for saved states--> + <use_saved_files>0</use_saved_files> + + <hp_map>./HP_map.txt</hp_map> + + <flat>./flat_field.txt</flat> + + <smear>./smear_kernel.txt</smear> + + <smear_x>0.0</smear_x> + <smear_y>0.0</smear_y> + </HFS_MetaInfo> diff --git a/src/HFS_API.cpp b/src/HFS_API.cpp index 2e6a965a48eae4e349037632a03236ee8e880df6..4bdc3a03b653e72df9deed6c50a182f002ac5fba 100644 --- a/src/HFS_API.cpp +++ b/src/HFS_API.cpp @@ -1,8 +1,8 @@ /** * @file HFS_API.cpp * @author Gerald Mösenlechner (gerald.moesenlechner@univie.ac.at) -* @date Marc, 2023 -* @version 0.4 +* @date September, 2023 +* @version 0.5 * * @copyright * This program is free software; you can redistribute it and/or modify it @@ -50,14 +50,6 @@ double starimage[XDIM*YDIM]; unsigned int image[XDIM*YDIM]; unsigned int filtered_image[XDIM*YDIM]; -template <class T> -const char * to_char(T input) -{ - std::stringstream out_stream; - out_stream << input; - const char* str = out_stream.str().c_str(); - return str; -} /** * @brief resets all HFS parameters based on the provided configuration file @@ -67,255 +59,267 @@ const char * to_char(T input) * are also simulated at this stage. * * @param config_file: name and path of the configuration file + * @param hard_reset: flag to denote that the simulation time shall be reset * * @returns 0 on success */ -int FGS :: reset_fgs(const char* config_file) +int FGS :: reset_fgs(const char* config_file, int hard_reset) { - unsigned int i; - std::ifstream psf1_if, psf2_if, hp_if, flat_if, smear_if; - tinyxml2::XMLDocument config; - config.LoadFile(config_file); - tinyxml2::XMLElement *cRootElement = config.RootElement(); - unsigned int use_save; - const char* hp_buffer; - const char* flat_buffer; - const char* smear_buffer; - const char* psf1_buffer; - const char* psf2_buffer; - const char* catalouge_buffer; - - targets -> number = 0; - /* Initialise smearing points and counters*/ - x_smear_0 = 0.; - y_smear_0 = 0.; - sync_ctr = 0; - send_cent = 0; - sim_time = 0.; + unsigned int i; + std::ifstream psf1_if, psf2_if, hp_if, flat_if, smear_if; + tinyxml2::XMLDocument config; + config.LoadFile(config_file); + tinyxml2::XMLElement *cRootElement = config.RootElement(); + unsigned int use_save; + const char* hp_buffer; + const char* flat_buffer; + const char* smear_buffer; + const char* psf1_buffer; + const char* psf2_buffer; + const char* catalouge_buffer; + const char* modeInput; + + targets -> number = 0; + /* Initialise smearing points and counters*/ + x_smear_0 = 0.; + y_smear_0 = 0.; + sync_ctr = 0; + send_cent = 0; + sim_time = 0.; - /*parse xml file*/ - if (NULL != cRootElement) - { - cRootElement -> FirstChildElement("timestep") -> QueryDoubleText(×tep); - cRootElement -> FirstChildElement("random_seed") -> QueryUnsignedText(&rand_seed); - cRootElement -> FirstChildElement("integration_start") -> QueryDoubleText(&start_exposure); - cRootElement -> FirstChildElement("flat_mean") -> QueryDoubleText(&flat_mean); - cRootElement -> FirstChildElement("flat_sigma") -> QueryDoubleText(&flat_sigma); - cRootElement -> FirstChildElement("bias") -> QueryDoubleText(&bias_value); - cRootElement -> FirstChildElement("bkgr_noise") -> QueryDoubleText(&bkgr_noise); - cRootElement -> FirstChildElement("readout_noise") -> QueryDoubleText(&read_noise); - cRootElement -> FirstChildElement("dark_average") -> QueryDoubleText(&dark_mean); - cRootElement -> FirstChildElement("hotpixel_amount") -> QueryDoubleText(&hp_amount); - cRootElement -> FirstChildElement("full_well_capacity") -> QueryUnsignedText(&full_well_cap); - cRootElement -> FirstChildElement("median_filter_threshold") -> QueryUnsignedText(&med_threshold); - cRootElement -> FirstChildElement("jitter_error_std") -> QueryDoubleText(&jitter_error); - - /*Set random seed*/ - srandom(rand_seed); - - psf1_buffer = cRootElement -> FirstChildElement("FGS1_Psf") -> GetText(); - psf_fgs1.assign(psf1_buffer); - /*check if Psf inputs exist*/ - psf1_if.open(psf1_buffer, std::ifstream::in); - if (psf1_if.is_open()) - { - for (i = 0; i < XDIM_PSF*YDIM_PSF; i++) - { - psf1_if >> FGS1_Psf[i]; + /*parse xml file*/ + if (NULL != cRootElement){ + if(hard_reset == 1){ + cRootElement -> FirstChildElement("timestep") -> QueryDoubleText(×tep); + cRootElement -> FirstChildElement("random_seed") -> QueryUnsignedText(&rand_seed); + cRootElement -> FirstChildElement("integration_start") -> QueryDoubleText(&start_exposure); } - psf1_if.close(); - } - else { - std::cerr << "Can't find input file " << psf_fgs1 << std::endl; - return -1; - } - psf2_buffer = cRootElement -> FirstChildElement("FGS2_Psf") -> GetText(); - psf_fgs2.assign(psf2_buffer); - - psf2_if.open(psf2_buffer, std::ifstream::in); - if (psf2_if.is_open()) - { - for (i = 0; i < XDIM_PSF*YDIM_PSF; i++) - { - psf2_if >> FGS2_Psf[i]; + else{ + start_exposure = sim_time; } - psf2_if.close(); - } - else { - std::cerr << "Can't find input file " << psf_fgs2 << std::endl; - return -1; - } - cRootElement -> FirstChildElement("FGS1_PS") -> QueryDoubleText(&ps_fgs1); - cRootElement -> FirstChildElement("FGS2_PS") -> QueryDoubleText(&ps_fgs2); - cRootElement -> FirstChildElement("FGS1_FL") -> QueryDoubleText(&fl_fgs1); - cRootElement -> FirstChildElement("FGS2_FL") -> QueryDoubleText(&fl_fgs2); - cRootElement -> FirstChildElement("FGS1_QE") -> QueryDoubleText(&qe_fgs1); - cRootElement -> FirstChildElement("FGS2_QE") -> QueryDoubleText(&qe_fgs2); - cRootElement -> FirstChildElement("FGS1_Offset_X") -> QueryDoubleText(&offset_FGS1[0]); - cRootElement -> FirstChildElement("FGS1_Offset_Y") -> QueryDoubleText(&offset_FGS1[1]); - cRootElement -> FirstChildElement("FGS2_Offset_X") -> QueryDoubleText(&offset_FGS2[0]); - cRootElement -> FirstChildElement("FGS2_Offset_Y") -> QueryDoubleText(&offset_FGS2[1]); - - cRootElement -> FirstChildElement("FGS_channel") -> QueryUnsignedText(&channel); - mode = cRootElement -> FirstChildElement("FGS_mode") -> GetText(); - cRootElement -> FirstChildElement("FWHM_FGS1_x") -> QueryUnsignedText(&fwhm1_x); - cRootElement -> FirstChildElement("FWHM_FGS1_y") -> QueryUnsignedText(&fwhm1_y); - cRootElement -> FirstChildElement("FWHM_FGS2_x") -> QueryUnsignedText(&fwhm2_x); - cRootElement -> FirstChildElement("FWHM_FGS2_y") -> QueryUnsignedText(&fwhm2_y); - - cRootElement -> FirstChildElement("transition_delay") -> QueryDoubleText(&transition_delay); - cRootElement -> FirstChildElement("target_signal") -> QueryUnsignedText(&target_signal); - cRootElement -> FirstChildElement("lower_signal_limit") -> QueryDoubleText(&lower_sig_lim); - cRootElement -> FirstChildElement("validation_sigma") -> QueryUnsignedText(&val_sigma); - cRootElement -> FirstChildElement("validation_pearson_limit") -> QueryDoubleText(&pearson_limit); - - tinyxml2::XMLElement *cTracking = cRootElement -> FirstChildElement("Tracking"); - cTracking -> FirstChildElement("iterations") -> QueryUnsignedText(&iter_track); - cTracking -> FirstChildElement("median_filter") -> QueryUnsignedText(&med_track); - cTracking -> FirstChildElement("thresholding") -> QueryUnsignedText(&threshold_track); - cTracking -> FirstChildElement("delay") -> QueryDoubleText(&delay_track); - cTracking -> FirstChildElement("exposure_time") -> QueryDoubleText(&exp_track); - cTracking -> FirstChildElement("dim") -> QueryUnsignedText(&track_dim); - - tinyxml2::XMLElement *cAcquisition = cRootElement -> FirstChildElement("Acquisition"); - cAcquisition -> FirstChildElement("iterations") -> QueryUnsignedText(&iter_acq); - cAcquisition -> FirstChildElement("median_filter") -> QueryUnsignedText(&med_acq); - cAcquisition -> FirstChildElement("thresholding") -> QueryUnsignedText(&threshold_acq); - cAcquisition -> FirstChildElement("delay") -> QueryDoubleText(&delay_acq); - cAcquisition -> FirstChildElement("exposure_time") -> QueryDoubleText(&exp_acq); - cAcquisition -> FirstChildElement("tolerance") -> QueryUnsignedText(&tolerance_acq); - cAcquisition -> FirstChildElement("FGS1_dim") -> QueryUnsignedText(&acq_dim_fgs1); - cAcquisition -> FirstChildElement("FGS2_dim") -> QueryUnsignedText(&acq_dim_fgs2); - cAcquisition -> FirstChildElement("target_limit") -> QueryUnsignedText(&max_targets); - cAcquisition -> FirstChildElement("extension_sigma") -> QueryUnsignedText(&extension_sigma); - /*Parse and read stars from catalouge*/ - catalouge_buffer = cRootElement -> FirstChildElement("Star_catalouge") -> GetText(); - catalouge.assign(catalouge_buffer); - - search_star_id(targets, catalouge_buffer); - - cRootElement -> FirstChildElement("use_saved_files") -> QueryUnsignedText(&use_save); - hp_buffer = cRootElement -> FirstChildElement("hp_map") -> GetText(); - flat_buffer = cRootElement -> FirstChildElement("flat") -> GetText(); - smear_buffer = cRootElement -> FirstChildElement("smear") -> GetText(); - cRootElement -> FirstChildElement("smear_x") -> QueryDoubleText(&x_smear_0); - cRootElement -> FirstChildElement("smear_y") -> QueryDoubleText(&y_smear_0); - - /*reset all image buffers*/ - reset_arrays(1); - - centroid.x = 0.; - centroid.y = 0.; - centroid.validity.flag = 0.; - centroid.validity.index = 100; - - transition_end = 0.; - - /*Set starting conditions for dim, qe, delay and exposure*/ - if(channel == 1) - { - qe = qe_fgs1; - focal_length = fl_fgs1; - plate_scale = ps_fgs1; - offset[0] = offset_FGS1[0]; - offset[1] = offset_FGS1[1]; - } - else if(channel == 2) - { - qe = qe_fgs2; - focal_length = fl_fgs2; - plate_scale = ps_fgs2; - offset[0] = offset_FGS2[0]; - offset[1] = offset_FGS2[1]; - - } - - if(strcmp(mode, MODE_ACQU) == 0) - { - exposure_time = exp_acq; - delay = delay_acq; - if(channel == 1) - { - dim_x = acq_dim_fgs1; - dim_y = acq_dim_fgs1; + cRootElement -> FirstChildElement("flat_mean") -> QueryDoubleText(&flat_mean); + cRootElement -> FirstChildElement("flat_sigma") -> QueryDoubleText(&flat_sigma); + cRootElement -> FirstChildElement("bias") -> QueryDoubleText(&bias_value); + cRootElement -> FirstChildElement("bkgr_noise") -> QueryDoubleText(&bkgr_noise); + cRootElement -> FirstChildElement("readout_noise") -> QueryDoubleText(&read_noise); + cRootElement -> FirstChildElement("dark_average") -> QueryDoubleText(&dark_mean); + cRootElement -> FirstChildElement("hotpixel_amount") -> QueryDoubleText(&hp_amount); + cRootElement -> FirstChildElement("full_well_capacity") -> QueryUnsignedText(&full_well_cap); + cRootElement -> FirstChildElement("median_filter_threshold") -> QueryUnsignedText(&med_threshold); + cRootElement -> FirstChildElement("jitter_error_std") -> QueryDoubleText(&jitter_error); + + cRootElement -> FirstChildElement("reset_duration") -> QueryDoubleText(&reset_duration); + cRootElement -> FirstChildElement("reset_end") -> QueryDoubleText(&reset_end); + cRootElement -> FirstChildElement("timing_tolerance") -> QueryDoubleText(&timing_tolerance); + /*Set random seed*/ + srandom(rand_seed); + + psf1_buffer = cRootElement -> FirstChildElement("FGS1_Psf") -> GetText(); + psf_fgs1.assign(psf1_buffer); + /*check if Psf inputs exist*/ + psf1_if.open(psf1_buffer, std::ifstream::in); + if (psf1_if.is_open()){ + for (i = 0; i < XDIM_PSF*YDIM_PSF; i++){ + psf1_if >> FGS1_Psf[i]; + } + psf1_if.close(); + } + else { + std::cerr << "Can't find input file " << psf_fgs1 << std::endl; + return -1; + } + psf2_buffer = cRootElement -> FirstChildElement("FGS2_Psf") -> GetText(); + psf_fgs2.assign(psf2_buffer); + psf2_if.open(psf2_buffer, std::ifstream::in); + if (psf2_if.is_open()){ + for (i = 0; i < XDIM_PSF*YDIM_PSF; i++){ + psf2_if >> FGS2_Psf[i]; + } + psf2_if.close(); } - else if(channel == 2) - { - dim_x = acq_dim_fgs2; - dim_y = acq_dim_fgs2; + else { + std::cerr << "Can't find input file " << psf_fgs2 << std::endl; + return -1; } - } - else if(strcmp(mode, MODE_TRAC) == 0) - { - exposure_time = exp_track; - delay = delay_track; - /*Tracking uses 64x64 for both channels*/ - dim_x = track_dim; - dim_y = track_dim; - } - - /*Create static attributes of the image*/ - if(use_save == 0) - { - generate_flat(flat, flat_mean, flat_sigma, XDIM, YDIM); - generate_hotpixels(hot_pixels, hp_amount, hp_lower, hp_upper, XDIM, YDIM); - } - else - { - hp_if.open(hp_buffer, std::ifstream::in); - if (hp_if.is_open()) - { - for (i = 0; i < XDIM*YDIM; i++) - { - hp_if >> hot_pixels[i]; - } - } - else { - std::cerr << "Can't find input file " << hp_buffer << std::endl; - return -1; + cRootElement -> FirstChildElement("FGS1_PS") -> QueryDoubleText(&ps_fgs1); + cRootElement -> FirstChildElement("FGS2_PS") -> QueryDoubleText(&ps_fgs2); + cRootElement -> FirstChildElement("FGS1_FL") -> QueryDoubleText(&fl_fgs1); + cRootElement -> FirstChildElement("FGS2_FL") -> QueryDoubleText(&fl_fgs2); + cRootElement -> FirstChildElement("FGS1_QE") -> QueryDoubleText(&qe_fgs1); + cRootElement -> FirstChildElement("FGS2_QE") -> QueryDoubleText(&qe_fgs2); + cRootElement -> FirstChildElement("FGS1_Offset_X") -> QueryDoubleText(&offset_FGS1[0]); + cRootElement -> FirstChildElement("FGS1_Offset_Y") -> QueryDoubleText(&offset_FGS1[1]); + cRootElement -> FirstChildElement("FGS2_Offset_X") -> QueryDoubleText(&offset_FGS2[0]); + cRootElement -> FirstChildElement("FGS2_Offset_Y") -> QueryDoubleText(&offset_FGS2[1]); + + cRootElement -> FirstChildElement("FGS_channel") -> QueryUnsignedText(&channel); + modeInput = cRootElement -> FirstChildElement("FGS_mode") -> GetText(); + if (strcmp(modeInput, MODE_ACQU) == 0){ + mode = MODE_ACQU; + } + else if (strcmp(modeInput, MODE_TRAC) == 0){ + mode = MODE_TRAC; + } + else { + mode = MODE_STBY; + } + cRootElement -> FirstChildElement("FWHM_FGS1_x") -> QueryUnsignedText(&fwhm1_x); + cRootElement -> FirstChildElement("FWHM_FGS1_y") -> QueryUnsignedText(&fwhm1_y); + cRootElement -> FirstChildElement("FWHM_FGS2_x") -> QueryUnsignedText(&fwhm2_x); + cRootElement -> FirstChildElement("FWHM_FGS2_y") -> QueryUnsignedText(&fwhm2_y); + + cRootElement -> FirstChildElement("transition_delay") -> QueryDoubleText(&transition_delay); + cRootElement -> FirstChildElement("transition_end") -> QueryDoubleText(&transition_end); + cRootElement -> FirstChildElement("target_signal") -> QueryUnsignedText(&target_signal); + cRootElement -> FirstChildElement("lower_signal_limit") -> QueryDoubleText(&lower_sig_lim); + cRootElement -> FirstChildElement("validation_sigma") -> QueryUnsignedText(&val_sigma); + cRootElement -> FirstChildElement("validation_pearson_limit") -> QueryDoubleText(&pearson_limit); + + tinyxml2::XMLElement *cTracking = cRootElement -> FirstChildElement("Tracking"); + cTracking -> FirstChildElement("iterations") -> QueryUnsignedText(&iter_track); + cTracking -> FirstChildElement("median_filter") -> QueryUnsignedText(&med_track); + cTracking -> FirstChildElement("thresholding") -> QueryUnsignedText(&threshold_track); + cTracking -> FirstChildElement("delay") -> QueryDoubleText(&delay_track); + cTracking -> FirstChildElement("exposure_time") -> QueryDoubleText(&exp_track); + cTracking -> FirstChildElement("dim") -> QueryUnsignedText(&track_dim); + + tinyxml2::XMLElement *cAcquisition = cRootElement -> FirstChildElement("Acquisition"); + cAcquisition -> FirstChildElement("iterations") -> QueryUnsignedText(&iter_acq); + cAcquisition -> FirstChildElement("median_filter") -> QueryUnsignedText(&med_acq); + cAcquisition -> FirstChildElement("thresholding") -> QueryUnsignedText(&threshold_acq); + cAcquisition -> FirstChildElement("delay") -> QueryDoubleText(&delay_acq); + cAcquisition -> FirstChildElement("exposure_time") -> QueryDoubleText(&exp_acq); + cAcquisition -> FirstChildElement("tolerance") -> QueryUnsignedText(&tolerance_acq); + cAcquisition -> FirstChildElement("FGS1_dim") -> QueryUnsignedText(&acq_dim_fgs1); + cAcquisition -> FirstChildElement("FGS2_dim") -> QueryUnsignedText(&acq_dim_fgs2); + cAcquisition -> FirstChildElement("target_limit") -> QueryUnsignedText(&max_targets); + cAcquisition -> FirstChildElement("extension_sigma") -> QueryUnsignedText(&extension_sigma); + /*Parse and read stars from catalouge*/ + catalouge_buffer = cRootElement -> FirstChildElement("Star_catalouge") -> GetText(); + catalouge.assign(catalouge_buffer); + + search_star_id(targets, catalouge_buffer); + + cRootElement -> FirstChildElement("use_saved_files") -> QueryUnsignedText(&use_save); + hp_buffer = cRootElement -> FirstChildElement("hp_map") -> GetText(); + flat_buffer = cRootElement -> FirstChildElement("flat") -> GetText(); + smear_buffer = cRootElement -> FirstChildElement("smear") -> GetText(); + cRootElement -> FirstChildElement("smear_x") -> QueryDoubleText(&x_smear_0); + cRootElement -> FirstChildElement("smear_y") -> QueryDoubleText(&y_smear_0); + /*reset all image buffers*/ + if(hard_reset){ + reset_arrays(1); + } + else{ + transition_end = 0.0; + } + hp_upper = 0.; + hp_lower = 0.; //TODO Replace with config + + centroid.x = 0.; + centroid.y = 0.; + centroid.time = 0.; + centroid.validity.flag = 0.; + centroid.validity.index = 100; + centroid.validity.magnitude = 0; + + + /*Set starting conditions for dim, qe, delay and exposure*/ + if(channel == 1){ + qe = qe_fgs1; + focal_length = fl_fgs1; + plate_scale = ps_fgs1; + offset[0] = offset_FGS1[0]; + offset[1] = offset_FGS1[1]; + fwhm_x = fwhm1_x; + fwhm_y = fwhm1_y; + } + else if(channel == 2){ + qe = qe_fgs2; + focal_length = fl_fgs2; + plate_scale = ps_fgs2; + offset[0] = offset_FGS2[0]; + offset[1] = offset_FGS2[1]; + fwhm_x = fwhm2_x; + fwhm_y = fwhm2_y; } - hp_if.close(); + if(strcmp(mode, MODE_ACQU) == 0){ + exposure_time = exp_acq; + delay = delay_acq; + if(channel == 1){ + dim_x = acq_dim_fgs1; + dim_y = acq_dim_fgs1; + } + else if(channel == 2){ + dim_x = acq_dim_fgs2; + dim_y = acq_dim_fgs2; + } + } + else if(strcmp(mode, MODE_TRAC) == 0){ + exposure_time = exp_track; + delay = delay_track; + /*Tracking uses 64x64 for both channels*/ + dim_x = track_dim; + dim_y = track_dim; + } - flat_if.open(flat_buffer, std::ifstream::in); - if (flat_if.is_open()) - { - for (i = 0; i < XDIM*YDIM; i++) - { - flat_if >> flat[i]; - std::cout << flat[i] << " "; - } - } - else { - std::cerr << "Can't find input file " << flat_buffer << std::endl; - return -1; + /*Create static attributes of the image*/ + if(hard_reset == 0){ + return 0; + } + else if(use_save == 0){ + generate_flat(flat, flat_mean, flat_sigma, XDIM, YDIM); + generate_hotpixels(hot_pixels, hp_amount, hp_lower, hp_upper, XDIM, YDIM); } + else{ + hp_if.open(hp_buffer, std::ifstream::in); + if (hp_if.is_open()){ + for (i = 0; i < XDIM*YDIM; i++){ + hp_if >> hot_pixels[i]; + } + } + else { + std::cerr << "Can't find input file " << hp_buffer << std::endl; + return -1; + } + + hp_if.close(); + + flat_if.open(flat_buffer, std::ifstream::in); + if (flat_if.is_open()){ + for (i = 0; i < XDIM*YDIM; i++){ + flat_if >> flat[i]; + } + } + else { + std::cerr << "Can't find input file " << flat_buffer << std::endl; + return -1; + } - flat_if.close(); + flat_if.close(); - smear_if.open(smear_buffer, std::ifstream::in); - if (smear_if.is_open()) - { - for (i = 0; i < 125*125; i++) - { - smear_if >> smear_kernel_os[i]; - } - } - else { - std::cerr << "Can't find input file " << smear_buffer << std::endl; - return -1; - } + smear_if.open(smear_buffer, std::ifstream::in); + if (smear_if.is_open()){ + for (i = 0; i < 125*125; i++){ + smear_if >> smear_kernel_os[i]; + } + } + else { + std::cerr << "Can't find input file " << smear_buffer << std::endl; + return -1; + } - smear_if.close(); - } - } - else{ - std::cerr << "The config file appeares to be empty!" << std::endl; - return -1; - } - return 0; + smear_if.close(); + } + } + else{ + std::cerr << "The config file appeares to be empty!" << std::endl; + return -1; + } + return 0; } double angular_rate_sc[3]; @@ -339,41 +343,50 @@ double angular_rate_drf[3]; int FGS :: generate_smear(double (&angular_rate)[3], double dt) { - struct dmatrix rot_matrix_sc, rot_matrix_opt, ar, transf_opt, transf; - double unit_vec[3] = {0., 0., 1.}; - double x_smear, y_smear; - unsigned int i; - - rot_matrix_sc.data = ROTMATRIX_SC; - rot_matrix_sc.xdim = 3; - rot_matrix_sc.ydim = 3; - - rot_matrix_opt.data = ROTMATRIX; - rot_matrix_opt.xdim = 3; - rot_matrix_opt.ydim = 3; - - ar.data = angular_rate; - ar.xdim = 1; - ar.ydim = 3; - for (i = 0; i < 3; i++) - { - ar.data[i] = ar.data[i]/3600; /*convert to degrees/s*/ - } + struct dmatrix rot_matrix_sc, rot_matrix_opt, ar, transf_opt, transf; + double unit_vec[3] = {0., 0., 1.}; + double x_smear, y_smear; + unsigned int i; - transf_opt.data = angular_rate_sc; - transf.data = angular_rate_opt; + rot_matrix_sc.data = ROTMATRIX_SC; + rot_matrix_sc.xdim = 3; + rot_matrix_sc.ydim = 3; - dmatmult(rot_matrix_sc, ar, &transf_opt); - dmatmult(rot_matrix_opt, transf_opt, &transf); + rot_matrix_opt.data = ROTMATRIX; + rot_matrix_opt.xdim = 3; + rot_matrix_opt.ydim = 3; - cross3(transf.data, unit_vec, angular_rate_drf); + ar.data = angular_rate; + ar.xdim = 1; + ar.ydim = 3; + for (i = 0; i < 3; i++){ + ar.data[i] = ar.data[i]/3600; /*convert to degrees/s*/ + } - x_smear = angular_rate_drf[0]*dt*3600000/plate_scale; - y_smear = -angular_rate_drf[1]*dt*3600000/plate_scale; + transf_opt.data = angular_rate_sc; + transf.data = angular_rate_opt; - generate_linear_smearing_kernel(smear_kernel_os, x_smear_0 * 5, y_smear_0 * 5, x_smear * 5, y_smear * 5, 125); - x_smear_0 = x_smear; - y_smear_0 = y_smear; + dmatmult(rot_matrix_sc, ar, &transf_opt); + dmatmult(rot_matrix_opt, transf_opt, &transf); + + cross3(transf.data, unit_vec, angular_rate_drf); + + x_smear = angular_rate_drf[0]*dt*3600000/plate_scale; + y_smear = -angular_rate_drf[1]*dt*3600000/plate_scale; + + generate_linear_smearing_kernel(smear_kernel_os, x_smear_0 * 5, y_smear_0 * 5, x_smear * 5, y_smear * 5, 125); + x_smear_0 += x_smear; + y_smear_0 += y_smear; +#if 0 + std::ofstream test_file; + test_file.open("image.txt", std::ios_base::app); + for (i = 0; i < 125*125; i++) { + test_file << smear_kernel_os[i] << " "; + if (i && !((i + 1) % (int)125)) + test_file << "\n"; + } + test_file.close(); +#endif return 0; } @@ -388,51 +401,49 @@ int FGS :: generate_smear(double (&angular_rate)[3], double dt) int FGS :: generate_image() { - unsigned int i; + unsigned int i; - downsample_image(smear_kernel_os, smear_kernel, 125, 125, 5); + downsample_image(smear_kernel_os, smear_kernel, 125, 125, 5); - generate_bias(bias, bias_sample, bias_value, 128, dim_x, dim_y); + generate_bias(bias, bias_sample, bias_value, 128, dim_x, dim_y); - generate_dark(dark, dark_mean, exposure_time, hot_pixels, dim_x, dim_y); + generate_dark(dark, dark_mean, exposure_time, hot_pixels, dim_x, dim_y); - generate_background(bkgr, bkgr_noise, qe, exposure_time, dim_x, dim_y); + generate_background(bkgr, bkgr_noise, qe, exposure_time, dim_x, dim_y); - generate_starmask(starmask, *targets, exposure_time, dim_x, dim_y, channel); + generate_starmask(starmask, *targets, exposure_time, dim_x, dim_y, channel); - smear_star_image(smeared_mask, starmask, smear_kernel, dim_x, dim_y, XDIM_KERNEL, YDIM_KERNEL); + smear_star_image(smeared_mask, starmask, smear_kernel, dim_x, dim_y, XDIM_KERNEL, YDIM_KERNEL); - if(channel == 1){ - generate_star_image(starimage, FGS1_Psf, smeared_mask, dim_x, dim_y, XDIM_PSF, XDIM_PSF); - } - else if(channel == 2){ - generate_star_image(starimage, FGS2_Psf, smeared_mask, dim_x, dim_y, XDIM_PSF, XDIM_PSF); - } - else - { - std::cerr << "Unknown channel configured!" << std::endl; - } + if(channel == 1){ + generate_star_image(starimage, FGS1_Psf, smeared_mask, dim_x, dim_y, XDIM_PSF, XDIM_PSF); + } + else if(channel == 2){ + generate_star_image(starimage, FGS2_Psf, smeared_mask, dim_x, dim_y, XDIM_PSF, XDIM_PSF); + } + else{ + std::cerr << "Unknown channel configured!" << std::endl; + } - generate_shotnoise(shot, starimage, bkgr, dim_x*dim_y); + generate_shotnoise(shot, starimage, bkgr, dim_x*dim_y); - for(i = 0; i < dim_x*dim_y; i++) - { - image[i] = (unsigned int) (starimage[i] + bkgr[i] + shot[i])*flat[i] + bias[i] + dark[i]; - if (image[i] > full_well_cap) - image[i] = full_well_cap; - } + for(i = 0; i < dim_x*dim_y; i++){ + image[i] = (unsigned int) (shot[i] * flat[i] + bias[i] + dark[i]); + if (image[i] > full_well_cap) + image[i] = full_well_cap; + } /*Debug output for image*/ #if 0 std::ofstream test_file; test_file.open("image.txt"); for (i = 0; i < dim_x*dim_y; i++) { - test_file << flat[i] << " "; - if (i && !((i + 1) % (int)dim_x)) - test_file << "\n"; + test_file << image[i] << " "; + if (i && !((i + 1) % (int)dim_x)) + test_file << "\n"; } test_file.close(); #endif - return 0; + return 0; } /** @@ -447,57 +458,47 @@ int FGS :: generate_image() int FGS :: perform_algorithm() { - unsigned int min = 0; - struct coord output; - unsigned int i; - output.x = 0.; - output.y = 0.; - /*TODO validity borders*/ - if(strcmp(mode, MODE_ACQU) == 0) - { - if (threshold_acq == 1) - { - min = GetMin(image, dim_x*dim_y); - for(i = 0; i < dim_x*dim_y; i++) - { - image[i] = image[i] - min; - } - } - if (med_acq == 1) - { - MedFilter3x3(image, dim_x, dim_y, med_threshold, filtered_image); - output = SourceDetection(filtered_image, dim_x, dim_y, 0, channel, max_targets, target_signal*exposure_time, tolerance_acq, extension_sigma, iter_acq, fwhm_x, fwhm_y, target_signal*(lower_sig_lim/100), val_sigma, pearson_limit); - } - else - { - output = SourceDetection(image, dim_x, dim_y, 0, channel, max_targets, target_signal*exposure_time, tolerance_acq, extension_sigma, iter_acq, fwhm_x, fwhm_y, target_signal*(lower_sig_lim/100), val_sigma, pearson_limit); - } - } - else if (strcmp(mode, MODE_TRAC) == 0) - { - if (threshold_track == 1) - { - min = GetMin(image, dim_x*dim_y); - for(i = 0; i < dim_x*dim_y; i++) - { - image[i] = image[i] - min; - } - } - if(med_track == 1) - { - MedFilter3x3(image, dim_x, dim_y, med_threshold, filtered_image); - output = ArielCoG(filtered_image, dim_x, dim_y, iter_track, 0, fwhm_x, fwhm_y, channel, target_signal*(lower_sig_lim/100), val_sigma, pearson_limit); + unsigned int min = 0; + struct coord output; + unsigned int i; + output.x = 0.; + output.y = 0.; + + if(strcmp(mode, MODE_ACQU) == 0){ + if (threshold_acq == 1){ + min = GetMin(image, dim_x*dim_y); + for(i = 0; i < dim_x*dim_y; i++){ + image[i] = image[i] - min; + } + } + if (med_acq == 1){ + MedFilter3x3(image, dim_x, dim_y, med_threshold, filtered_image); + output = SourceDetection(filtered_image, dim_x, dim_y, 0, channel, max_targets, target_signal*exposure_time, tolerance_acq, extension_sigma, iter_acq, fwhm_x, fwhm_y, target_signal*(lower_sig_lim/100)*exposure_time, val_sigma, pearson_limit); + } + else{ + output = SourceDetection(image, dim_x, dim_y, 0, channel, max_targets, target_signal*exposure_time, tolerance_acq, extension_sigma, iter_acq, fwhm_x, fwhm_y, target_signal*(lower_sig_lim/100)*exposure_time, val_sigma, pearson_limit); + } } - else - { - output = ArielCoG(image, dim_x, dim_y, iter_track, 0, fwhm_x, fwhm_y, channel, target_signal*(lower_sig_lim/100), val_sigma, pearson_limit); + else if (strcmp(mode, MODE_TRAC) == 0){ + if (threshold_track == 1){ + min = GetMin(image, dim_x*dim_y); + for(i = 0; i < dim_x*dim_y; i++){ + image[i] = image[i] - min; + } + } + if(med_track == 1){ + MedFilter3x3(image, dim_x, dim_y, med_threshold, filtered_image); + output = ArielCoG(filtered_image, dim_x, dim_y, iter_track, 0, fwhm_x, fwhm_y, channel, target_signal*(lower_sig_lim/100)*exposure_time, val_sigma, pearson_limit); + } + else{ + output = ArielCoG(image, dim_x, dim_y, iter_track, 0, fwhm_x, fwhm_y, channel, target_signal*(lower_sig_lim/100)*exposure_time, val_sigma, pearson_limit); + } } - } - centroid.x = output.x; - centroid.y = output.y; - centroid.validity = output.validity; - return 0; + centroid.x = output.x; + centroid.y = output.y; + centroid.validity = output.validity; + return 0; } @@ -509,45 +510,40 @@ int FGS :: perform_algorithm() int FGS :: set_channel(unsigned int new_channel) { - channel = new_channel; - /*Set quantum efficiency*/ - if(channel == 1) - { - qe = qe_fgs1; - plate_scale = ps_fgs1; - focal_length = fl_fgs1; - fwhm_x = fwhm1_x; - fwhm_y = fwhm1_y; - offset[0] = offset_FGS1[0]; - offset[1] = offset_FGS1[1]; - - } - else if(channel == 2) - { - qe = qe_fgs2; - plate_scale = ps_fgs2; - focal_length = fl_fgs2; - fwhm_x = fwhm2_x; - fwhm_y = fwhm2_y; - offset[0] = offset_FGS2[0]; - offset[1] = offset_FGS2[1]; - } + channel = new_channel; + /*Set quantum efficiency*/ + if(channel == 1){ + qe = qe_fgs1; + plate_scale = ps_fgs1; + focal_length = fl_fgs1; + fwhm_x = fwhm1_x; + fwhm_y = fwhm1_y; + offset[0] = offset_FGS1[0]; + offset[1] = offset_FGS1[1]; - /*set dimensions for Acquisition, 22 arcsec*/ - if(strcmp(mode, MODE_ACQU) == 0) - { - if(channel == 1) - { - dim_x = acq_dim_fgs1; - dim_y = acq_dim_fgs1; } - else if(channel == 2) - { - dim_x = acq_dim_fgs2; - dim_y = acq_dim_fgs2; + else if(channel == 2){ + qe = qe_fgs2; + plate_scale = ps_fgs2; + focal_length = fl_fgs2; + fwhm_x = fwhm2_x; + fwhm_y = fwhm2_y; + offset[0] = offset_FGS2[0]; + offset[1] = offset_FGS2[1]; + } + + /*set dimensions for Acquisition, 22 arcsec*/ + if(strcmp(mode, MODE_ACQU) == 0){ + if(channel == 1){ + dim_x = acq_dim_fgs1; + dim_y = acq_dim_fgs1; + } + else if(channel == 2){ + dim_x = acq_dim_fgs2; + dim_y = acq_dim_fgs2; + } } - } - return 0; + return 0; } /** @@ -559,33 +555,29 @@ int FGS :: set_channel(unsigned int new_channel) int FGS :: set_mode(const char* new_mode) { - mode = new_mode; - /*Set image dimensiomean,ns based on FoV*/ - /* Target Acquisition, 22 arcsec */ - if(strcmp(mode, MODE_ACQU) == 0) - { - exposure_time = exp_acq; - delay = delay_acq; - if(channel == 1) - { - dim_x = acq_dim_fgs1; - dim_y = acq_dim_fgs1; + mode = new_mode; + /*Set image dimensiomean,ns based on FoV*/ + /* Target Acquisition, 22 arcsec */ + if(strcmp(mode, MODE_ACQU) == 0){ + exposure_time = exp_acq; + delay = delay_acq; + if(channel == 1){ + dim_x = acq_dim_fgs1; + dim_y = acq_dim_fgs1; + } + else if(channel == 2){ + dim_x = acq_dim_fgs2; + dim_y = acq_dim_fgs2; + } } - else if(channel == 2) - { - dim_x = acq_dim_fgs2; - dim_y = acq_dim_fgs2; + else if(strcmp(mode, MODE_TRAC) == 0){ + exposure_time = exp_track; + delay = delay_track; + /*Tracking uses 64x64 for both channels*/ + dim_x = track_dim; + dim_y = track_dim; } - } - else if(strcmp(mode, MODE_TRAC) == 0) - { - exposure_time = exp_track; - delay = delay_track; - /*Tracking uses 64x64 for both channels*/ - dim_x = track_dim; - dim_y = track_dim; - } - return 0; + return 0; } /** @@ -594,35 +586,31 @@ int FGS :: set_mode(const char* new_mode) int FGS :: reset_arrays(int reset_all) { - unsigned int i; - random_normal_trm(bias_sample, 0, read_noise, 128); - //#pragma omp parallel for - for(i = 0; i < XDIM*YDIM; i++) - { - bias[i] = 0.; - dark[i] = 0.; - shot[i] = 0.; - bkgr[i] = 0.; - starmask[i] = 0.; - starimage[i] = 0.; - smeared_mask[i] = 0.; - image[i] = 0; - filtered_image[i] = 0; - if(reset_all != 0) - { - flat[i] = 0.; - hot_pixels[i] = 0.; - } - if(i < 125*125) - { - smear_kernel_os[i] = 0.; - } - if(i < 25*25) - { - smear_kernel[i] = 0.; - } - } - return 0; + unsigned int i; + random_normal_trm(bias_sample, 0, read_noise, 128); + //#pragma omp parallel for + for(i = 0; i < XDIM*YDIM; i++){ + bias[i] = 0.; + dark[i] = 0.; + shot[i] = 0.; + bkgr[i] = 0.; + starmask[i] = 0.; + starimage[i] = 0.; + smeared_mask[i] = 0.; + image[i] = 0; + filtered_image[i] = 0; + if(reset_all != 0){ + flat[i] = 0.; + hot_pixels[i] = 0.; + } + if(i < 125*125){ + smear_kernel_os[i] = 0.; + } + if(i < 25*25){ + smear_kernel[i] = 0.; + } + } + return 0; } char hp_save[128]; @@ -703,6 +691,18 @@ int FGS :: generate_config(const char* output_file) tinyxml2::XMLElement* cJitter = config.NewElement("jitter_error_std"); cJitter->SetText(jitter_error); cRoot->InsertEndChild(cJitter); + + tinyxml2::XMLElement* cResetDuration = config.NewElement("reset_duration"); + cResetDuration->SetText(reset_duration); + cRoot->InsertEndChild(cResetDuration); + + tinyxml2::XMLElement* cResetState = config.NewElement("reset_end"); + cResetState->SetText(reset_end); + cRoot->InsertEndChild(cResetState); + + tinyxml2::XMLElement* cTimingTol = config.NewElement("timing_tolerance"); + cTimingTol->SetText(timing_tolerance); + cRoot->InsertEndChild(cTimingTol); tinyxml2::XMLElement* cFGSPSF1 = config.NewElement("FGS1_Psf"); cFGSPSF1->SetText(psf_fgs1.c_str()); @@ -780,6 +780,10 @@ int FGS :: generate_config(const char* output_file) cTransDelay->SetText(transition_delay); cRoot->InsertEndChild(cTransDelay); + tinyxml2::XMLElement* cTransEnd = config.NewElement("transition_end"); + cTransEnd->SetText(transition_end); + cRoot->InsertEndChild(cTransEnd); + tinyxml2::XMLElement* cTargetSig = config.NewElement("target_signal"); cTargetSig->SetText(target_signal); cRoot->InsertEndChild(cTargetSig); @@ -903,23 +907,20 @@ int FGS :: generate_config(const char* output_file) config.SaveFile(output_file); /*Write output files*/ hp_of.open(hp_save, std::ofstream::out | std::ofstream::app); - for (i = 0; i < XDIM*YDIM; i++) - { - hp_of << hot_pixels[i] << "\n"; + for (i = 0; i < XDIM*YDIM; i++){ + hp_of << hot_pixels[i] << "\n"; } hp_of.close(); flat_of.open(flat_save, std::ofstream::out | std::ofstream::app); - for (i = 0; i < XDIM*YDIM; i++) - { - flat_of << flat[i] << "\n"; + for (i = 0; i < XDIM*YDIM; i++){ + flat_of << flat[i] << "\n"; } flat_of.close(); smear_of.open(smear_save, std::ofstream::out | std::ofstream::app); - for (i = 0; i < 125*125; i++) - { - smear_of << smear_kernel_os[i] << "\n"; + for (i = 0; i < 125*125; i++){ + smear_of << smear_kernel_os[i] << "\n"; } smear_of.close(); @@ -934,42 +935,91 @@ int FGS :: generate_config(const char* output_file) struct hfs_state FGS :: get_hfs_state() { - struct hfs_state output; - - output.bias_value = bias_value; - output.qe = qe; - output.read_noise = read_noise; - output.dark_mean = dark_mean; - output.bkgr_noise = bkgr_noise; - output.exposure_time = exposure_time; - output.hp_amount = hp_amount; - output.hp_upper = hp_upper; - output.hp_lower = hp_lower; - output.flat_mean = flat_mean; - output.flat_sigma = flat_sigma; - output.plate_scale = plate_scale; - output.dim_x = dim_x; - output.dim_y = dim_y; - output.time = sim_time; - output.focal_length = focal_length; - output.delay = delay; - output.channel = channel; - output.iter_track = iter_track; - output.iter_acq = iter_acq; - output.med_track = med_track; - output.med_acq = med_acq; - output.threshold_track = threshold_track; - output.threshold_acq = threshold_acq; - output.mode = mode; - output.targets = targets; - output.exposure_start = start_exposure; - output.transition_end = transition_end; - - return output; + struct hfs_state output; + + output.bias_value = bias_value; + output.qe = qe; + output.read_noise = read_noise; + output.dark_mean = dark_mean; + output.bkgr_noise = bkgr_noise; + output.exposure_time = exposure_time; + output.sim_time = sim_time; + output.timestep = timestep; + output.hp_amount = hp_amount; + output.hp_upper = hp_upper; + output.hp_lower = hp_lower; + output.flat_mean = flat_mean; + output.flat_sigma = flat_sigma; + output.plate_scale = plate_scale; + output.pearson_limit = pearson_limit; + output.ps_fgs1 = ps_fgs1; + output.ps_fgs2 = ps_fgs2; + output.fl_fgs1 = fl_fgs1; + output.fl_fgs2 = fl_fgs2; + output.qe_fgs1 = qe_fgs1; + output.qe_fgs2 = qe_fgs2; + output.lower_sig_lim = lower_sig_lim; + output.dim_x = dim_x; + output.dim_y = dim_y; + output.start_exposure = start_exposure; + output.focal_length = focal_length; + output.delay = delay; + output.x_smear_0 = x_smear_0; + output.y_smear_0 = y_smear_0; + output.jitter_error = jitter_error; + output.delay_track = delay_track; + output.delay_acq = delay_acq; + output.transition_delay = transition_delay; + output.transition_end = transition_end; + output.exp_track = exp_track; + output.exp_acq = exp_acq; + output.reset_duration = reset_duration; + output.reset_end = reset_end; + output.timing_tolerance = timing_tolerance; + output.channel = channel; + output.iter_track = iter_track; + output.iter_acq = iter_acq; + output.med_track = med_track; + output.med_acq = med_acq; + output.threshold_track = threshold_track; + output.threshold_acq = threshold_acq; + output.tolerance_acq = tolerance_acq; + output.mode = mode; + output.targets = targets; + output.target_signal = target_signal; + output.full_well_cap = full_well_cap; + output.med_threshold = med_threshold; + output.sync_ctr = sync_ctr; + output.send_cent = send_cent; + output.val_sigma = val_sigma; + output.track_dim = track_dim; + output.acq_dim_fgs1 = acq_dim_fgs1; + output.acq_dim_fgs2 = acq_dim_fgs2; + output.rand_seed = rand_seed; + output.fwhm1_x = fwhm1_x; + output.fwhm1_y = fwhm1_y; + output.fwhm2_x = fwhm2_x; + output.fwhm2_y = fwhm2_y; + output.fwhm_x = fwhm_x; + output.fwhm_y = fwhm_y; + output.max_targets = max_targets; + output.extension_sigma = extension_sigma; + std::copy(offset_FGS1, offset_FGS1+2, output.offset_FGS1); + std::copy(offset_FGS2, offset_FGS2+2, output.offset_FGS2); + std::copy(offset, offset+2, output.offset); + output.psf_fgs1 = psf_fgs1; + output.psf_fgs2 = psf_fgs2; + output.input_file = input_file; + output.catalouge = catalouge; + output.targets = targets; + output.centroid = centroid; + return output; } double transform_sc[3]; double transform_opt[3]; +double transform_sc_vel[3]; +double transform_opt_vel[3]; /** * @brief transforms vector from spacecraft reference frame to detector @@ -981,83 +1031,91 @@ double transform_opt[3]; * dimensions. * * @param vec: input vector - * @param trf_x, trf_y: postion of FBT inside of FBA * @param[out] output: output vector * * @return 0 on success, 1 if the result is outside of the FOV */ -int FGS :: transform_to_detector(double (&vec)[3], int trf_x, int trf_y, double* output) +int FGS :: transform_to_detector(double (&vec)[3], double (&velVec)[3], int trf_x, int trf_y, double* output) { - struct dmatrix rot_matrix_sc, rot_matrix_opt, vector, transf_opt, transf; - double x_pos, y_pos; - - rot_matrix_sc.data = ROTMATRIX_SC; - rot_matrix_sc.xdim = 3; - rot_matrix_sc.ydim = 3; - - rot_matrix_opt.data = ROTMATRIX; - rot_matrix_opt.xdim = 3; - rot_matrix_opt.ydim = 3; - - vector.data = vec; - vector.xdim = 1; - vector.ydim = 3; - transf_opt.data = transform_sc; - transf.data = transform_opt; - - dmatmult(rot_matrix_sc, vector, &transf_opt); - dmatmult(rot_matrix_opt, transf_opt, &transf); - - if(strcmp(mode, MODE_TRAC) == 0) - { - /*Check if tracking window is inside of Acq window*/ - if(channel == 1) - { - if(abs(trf_x) > (acq_dim_fgs1/2 - dim_x/2)) - { - trf_x = acq_dim_fgs1/2 - dim_x/2; - } - if(abs(trf_y) > (acq_dim_fgs1/2 - dim_y/2)) - { - trf_y = acq_dim_fgs1/2 - dim_y/2; - } - } - else - { - if(abs(trf_x) > (acq_dim_fgs2/2 - dim_x/2)) - { - trf_x = acq_dim_fgs2/2 - dim_x/2; - } - if(abs(trf_y) > (acq_dim_fgs2/2 - dim_y/2)) - { - trf_y = acq_dim_fgs2/2 - dim_y/2; - } - } - x_pos = (transf.data[0]*(360/TWO_PI)*3600000 + offset[0])/plate_scale - trf_x; - y_pos = (transf.data[1]*(360/TWO_PI)*3600000 + offset[1])/plate_scale - trf_y; - } - else - { - x_pos = (transf.data[0]*(360/TWO_PI)*3600000 + offset[0])/plate_scale; - y_pos = (transf.data[1]*(360/TWO_PI)*3600000 + offset[1])/plate_scale; - } + struct dmatrix rot_matrix_sc, rot_matrix_opt, vector, transf_opt, transf, transf_opt_vel, transf_vel, velocity; + double x_pos, y_pos, x_vel, y_vel; + + rot_matrix_sc.data = ROTMATRIX_SC; + rot_matrix_sc.xdim = 3; + rot_matrix_sc.ydim = 3; + + rot_matrix_opt.data = ROTMATRIX; + rot_matrix_opt.xdim = 3; + rot_matrix_opt.ydim = 3; + + vector.data = vec; + vector.xdim = 1; + vector.ydim = 3; + velocity.data = velVec; + velocity.xdim = 1; + velocity.ydim = 3; + transf_opt.data = transform_sc; + transf.data = transform_opt; + transf_opt_vel.data = transform_sc_vel; + transf_vel.data = transform_opt_vel; + + dmatmult(rot_matrix_sc, vector, &transf_opt); + dmatmult(rot_matrix_opt, transf_opt, &transf); + + dmatmult(rot_matrix_sc, velocity, &transf_opt_vel); + dmatmult(rot_matrix_opt, transf_opt_vel, &transf_vel); + + x_vel = transf_vel.data[0]; + y_vel = transf_vel.data[1]; + + + if(strcmp(mode, MODE_TRAC) == 0){ + /*Check if tracking window is inside of Acq window*/ + if(channel == 1){ + if(abs(trf_x) > (acq_dim_fgs1/2 - dim_x/2)){ + trf_x = acq_dim_fgs1/2 - dim_x/2; + } + if(abs(trf_y) > (acq_dim_fgs1/2 - dim_y/2)){ + trf_y = acq_dim_fgs1/2 - dim_y/2; + } + } + else{ + if(abs(trf_x) > (acq_dim_fgs2/2 - dim_x/2)){ + trf_x = acq_dim_fgs2/2 - dim_x/2; + } + if(abs(trf_y) > (acq_dim_fgs2/2 - dim_y/2)){ + trf_y = acq_dim_fgs2/2 - dim_y/2; + } + } - if(abs(x_pos) < (dim_x/2)) - { + + transf.data[0] = acos((cos(transf.data[0]) - x_vel/CVEL)/(1 - cos(transf.data[0])*(x_vel/CVEL))); + transf.data[1] = acos((cos(transf.data[1]) - y_vel/CVEL)/(1 - cos(transf.data[1])*(y_vel/CVEL))); - if(abs(y_pos) < (dim_y/2)) - { - output[0] = x_pos; - output[1] = y_pos; - return 0; + x_pos = (transf.data[0]*(360/TWO_PI)*3600000 + offset[0])/plate_scale - trf_x; + y_pos = (transf.data[1]*(360/TWO_PI)*3600000 + offset[1])/plate_scale - trf_y; } + else{ + transf.data[0] = acos((cos(transf.data[0]) - x_vel/CVEL)/(1 - cos(transf.data[0])*(x_vel/CVEL))); + transf.data[1] = acos((cos(transf.data[1]) - y_vel/CVEL)/(1 - cos(transf.data[1])*(y_vel/CVEL))); + + + x_pos = (transf.data[0]*(360/TWO_PI)*3600000 + offset[0])/plate_scale; + y_pos = (transf.data[1]*(360/TWO_PI)*3600000 + offset[1])/plate_scale; } - else - { - return 1; - } - return 1; + + if(abs(x_pos) < (dim_x/2)){ + if(abs(y_pos) < (dim_y/2)){ + output[0] = x_pos; + output[1] = y_pos; + return 0; + } + } + else{ + return -1; + } + return -1; } double star_quat[4]; @@ -1075,57 +1133,54 @@ double res[2]; * coordinates are set * * @param quaternion: quaternion for trandformation (in J2000 to SC) - * @param trf_x, trf_y: postion of FBT inside of FBA + * @param trf_x: Position of the Tracking reference frame in px + * @param trf_y: Position of the Tracking reference frame in px * * @return 0 on success */ -int FGS :: transform_star_coordinates(double (&quaternion)[4], int trf_x, int trf_y) +int FGS :: transform_star_coordinates(double (&quaternion)[4], double (&velocity)[3], int trf_x, int trf_y) { - unsigned int i, flag; - double quaternion_inv[4] = {quaternion[0], -quaternion[1], -quaternion[2], -quaternion[3]}; + unsigned int i, flag; + double quaternion_inv[4] = {quaternion[0], -quaternion[1], -quaternion[2], -quaternion[3]}; - for(i = 0; i < targets -> number; i++) - { - star_quat[0] = 0.; - star_quat[1] = cos(targets -> dec[i] * (TWO_PI/360))*cos(targets -> ra[i] * (TWO_PI/360)); - star_quat[2] = cos(targets -> dec[i] * (TWO_PI/360))*sin(targets -> ra[i] * (TWO_PI/360)); - star_quat[3] = sin(targets -> dec[i] * (TWO_PI/360)); + for(i = 0; i < targets -> number; i++){ + star_quat[0] = 0.; + star_quat[1] = cos(targets -> dec[i] * (TWO_PI/360))*cos(targets -> ra[i] * (TWO_PI/360)); + star_quat[2] = cos(targets -> dec[i] * (TWO_PI/360))*sin(targets -> ra[i] * (TWO_PI/360)); + star_quat[3] = sin(targets -> dec[i] * (TWO_PI/360)); - /*apply quaternion to vector*/ - multiply_quaternion(quaternion, star_quat, tmp_quat); - multiply_quaternion(tmp_quat, quaternion_inv, sc_quat); + /*apply quaternion to vector*/ + multiply_quaternion(quaternion, star_quat, tmp_quat); + multiply_quaternion(tmp_quat, quaternion_inv, sc_quat); - /*extract vector*/ - sc_vec[0] = sc_quat[1]; - sc_vec[1] = sc_quat[2]; - sc_vec[2] = sc_quat[3]; + /*extract vector*/ + sc_vec[0] = sc_quat[1]; + sc_vec[1] = sc_quat[2]; + sc_vec[2] = sc_quat[3]; - flag = transform_to_detector(sc_vec, trf_x, trf_y, res); + flag = transform_to_detector(sc_vec, velocity, trf_x, trf_y, res); - if(flag == 0) - { - targets -> x[i] = res[0] + dim_x/2; - targets -> y[i] = res[1] + dim_y/2; - targets -> visible[i] = 1; - } - else - { - targets -> visible[i] = 0; + if(flag == 0){ + targets -> x[i] = res[0] + dim_x/2; + targets -> y[i] = res[1] + dim_y/2; + targets -> visible[i] = 1; + } + else{ + targets -> visible[i] = 0; + } } - } - #if 0 - for(i = 0; i < targets -> number; i++) - std::cout << targets -> id[i] << ": " << targets -> visible[i] << "\n"; - #endif +#if 0 + for(i = 0; i < targets -> number; i++) + std::cout << targets -> id[i] << ": " << targets -> visible[i] << "\n"; +#endif - return 0; + return 0; } - /** * @brief function that generates a centroid packet based on the current state of the simulation environment. * @@ -1133,76 +1188,72 @@ int FGS :: transform_star_coordinates(double (&quaternion)[4], int trf_x, int tr * @param[out] cent_packet: centroid packet struct passed to the simulation environment. */ -int FGS :: generate_centroid(hfs_parameters update, centroid_packet *cent_packet) +int FGS :: generate_centroid(hfs_parameters update) { - if(strcmp(mode, MODE_TRAC) == 0) - { - cent_packet -> mode = 2; - } - else - if(strcmp(mode, MODE_ACQU) == 0) - { - cent_packet -> mode = 1; - } - cent_packet -> channel = channel; - - transform_star_coordinates(update.position_quat, update.target_pos_x, update.target_pos_y); - generate_image(); - perform_algorithm(); - reset_arrays(0); - x_smear_0 = 0.; - y_smear_0 = 0.; - centroid.time = sim_time + delay; - /* Convert centroid to mas in FBT frame*/ - centroid.x = (centroid.x - dim_x/2) * plate_scale; - centroid.y = (centroid.y - dim_y/2) * plate_scale; - - centroid.x = (centroid.x + random_normal_number(0, jitter_error) + ((double) update.add_shift_x/10)) * update.mult_shift_x; - centroid.y = (centroid.y + random_normal_number(0, jitter_error) + ((double) update.add_shift_y/10)) * update.mult_shift_y; + transform_star_coordinates(update.position_quat, update.scVelocity, update.target_pos_x, update.target_pos_y); + generate_image(); + perform_algorithm(); + reset_arrays(0); + rand_seed = rand_seed * 1103515245 + 12345; + srand(rand_seed); + x_smear_0 = 0.; + y_smear_0 = 0.; + centroid.time = sim_time + delay; + /* Convert centroid to mas in FBT frame*/ + centroid.x = (centroid.x - dim_x/2) * plate_scale; + centroid.y = (centroid.y - dim_y/2) * plate_scale; + + centroid.x = (centroid.x + random_normal_number(0, jitter_error) + ((double) update.add_shift_x/10)) * update.mult_shift_x; + centroid.y = (centroid.y + random_normal_number(0, jitter_error) + ((double) update.add_shift_y/10)) * update.mult_shift_y; - if(centroid.validity.flag == 0) - { - centroid.x = 0; - centroid.y = 0; - } - send_cent = 1; + if(centroid.validity.flag == 0){ + centroid.x = 0; + centroid.y = 0; + } + send_cent = 1; - return 0; + return 0; } /** * @brief Function for updating the output centroid packet with the latest centroid measurement - * @param update: hfs parameter update + * * @param[out] cent_packet: centroid packet struct that is visible to the Simulink model */ int FGS :: send_centroid(hfs_parameters update, centroid_packet *cent_packet) { - cent_packet -> x = centroid.x; - cent_packet -> y = centroid.y; - cent_packet -> validity_flag = centroid.validity.flag; - cent_packet -> validity_index = centroid.validity.index; - cent_packet -> magnitude = centroid.validity.magnitude; - cent_packet -> time = centroid.time; - send_cent = 0; - - if(update.set_invalid != 0) - { - cent_packet -> validity_index = 100.; - cent_packet -> validity_flag = 0; - } - if(update.set_error != 0) - { - cent_packet -> validity_index = update.set_error; - cent_packet -> validity_flag = 0; - } + cent_packet -> x = centroid.x; + cent_packet -> y = centroid.y; + cent_packet -> validity_flag = centroid.validity.flag; + cent_packet -> validity_index = centroid.validity.index; + cent_packet -> magnitude = centroid.validity.magnitude; + cent_packet -> time = centroid.time; + send_cent = 0; + cent_packet -> channel = channel; + + if(strcmp(mode, MODE_TRAC) == 0){ + cent_packet -> mode = 2; + } + else + if(strcmp(mode, MODE_ACQU) == 0){ + cent_packet -> mode = 1; + } - return 0; + if(update.set_invalid != 0){ + cent_packet -> validity_index = 100.; + cent_packet -> validity_flag = 0; + } + if(update.set_error != 0){ + cent_packet -> validity_index = update.set_error; + cent_packet -> validity_flag = 0; + } + return 0; } char string_buffer[64]; @@ -1225,74 +1276,74 @@ char string_buffer[64]; int FGS :: set_params(hfs_parameters update, centroid_packet *cent_packet) { - const char* update_mode_char; + const char* update_mode_char; - if(update.mode == 1) - update_mode_char = MODE_ACQU; - else if(update.mode == 2) - update_mode_char = MODE_TRAC; - else - update_mode_char = MODE_STBY; - - sim_time = update.time; - - /*Check if state shall be saved*/ - if(update.save == 1) - { - snprintf(string_buffer, sizeof(string_buffer), "HFS_config_%.0f.xml", sim_time); - generate_config(string_buffer); - } + if(update.mode == 1) + update_mode_char = MODE_ACQU; + else if(update.mode == 2) + update_mode_char = MODE_TRAC; + else + update_mode_char = MODE_STBY; + + sim_time = update.time; + target_signal = update.validation_signal; + - /*Check if centroid shall be generated*/ - if(strcmp(mode, MODE_ACQU) == 0 || strcmp(mode, MODE_TRAC) == 0) - { - if((start_exposure + exposure_time) < sim_time && transition_end == 0) - { - generate_centroid(update, cent_packet); - start_exposure = sim_time; - - if((strcmp(mode, update_mode_char) != 0) || channel != update.channel || target_signal != update.validation_signal) - { - transition_end = sim_time + transition_delay; - } + + /*Check if state shall be saved*/ + if(update.save == 1){ + snprintf(string_buffer, sizeof(string_buffer), "HFS_config_%.0f.xml", sim_time); + generate_config(string_buffer); } - else - { - generate_smear(update.ang_rate, timestep); + + /*Check if centroid shall be generated*/ + if((strcmp(mode, MODE_ACQU) == 0 || strcmp(mode, MODE_TRAC) == 0) && reset_end == 0){ + if((start_exposure + exposure_time) < sim_time && transition_end == 0){ + generate_smear(update.ang_rate, timestep); + generate_centroid(update); + start_exposure = sim_time; + + if((strcmp(mode, update_mode_char) != 0) || channel != update.channel){ + transition_end = sim_time + transition_delay; + } + } + else{ + generate_smear(update.ang_rate, timestep); + } } - } - else - { - if(transition_end == 0) - { - if((strcmp(mode, update_mode_char) != 0) || channel != update.channel || target_signal != update.validation_signal) - { - transition_end = sim_time + transition_delay; - } + else{ + if(transition_end == 0){ + if((strcmp(mode, update_mode_char) != 0) || channel != update.channel){ + transition_end = sim_time + transition_delay; + } + } } - } - /* Check if centroid shall be sent*/ - if(centroid.time < sim_time && send_cent == 1) - { - send_centroid(update, cent_packet); - } + /* Check if centroid shall be sent*/ + if((centroid.time - timing_tolerance) < sim_time && send_cent == 1 && reset_end == 0){ + send_centroid(update, cent_packet); + } - if(transition_end != 0 && transition_end < sim_time) - { - set_mode(update_mode_char); - set_channel(update.channel); - target_signal = update.validation_signal; - reset_arrays(0); - transition_end = 0; - start_exposure = sim_time; - } + if(transition_end != 0 && (transition_end - timing_tolerance) < sim_time && reset_end == 0){ + set_mode(update_mode_char); + set_channel(update.channel); + reset_arrays(0); + x_smear_0 = 0.; + y_smear_0 = 0.; + transition_end = 0; + start_exposure = sim_time; + } - if(update.reset != 0) - { - reset_fgs(input_file); - } - return 0; + if(update.reset != 0){ + reset_end = sim_time + reset_duration; + } + + if(reset_end != 0 && (reset_end - timing_tolerance) < sim_time){ + reset_fgs(input_file, 0); + reset_end = 0.; + } + + return 0; } char line[1024]; @@ -1319,26 +1370,21 @@ int search_star_id(struct stars* sim_stars, const char* catalouge) unsigned int i; - if(stream == NULL) - { - std::cerr << "Star catalouge could not be found!\n"; - return -1; + if(stream == NULL){ + std::cerr << "Star catalouge could not be found!\n"; + return -1; } - while (fgets(line, 1024, stream)) - { + while (fgets(line, 1024, stream)){ tok = strtok(line, ","); - if(strcmp(tok, "Name") == 0) - { - continue; - } + if(strcmp(tok, "Name") == 0){ + continue; + } strcpy(sim_stars -> id[sim_stars -> number], tok); i = 0; - for(tok = strtok(NULL, ",\n"); tok && *tok; i++, tok = strtok(NULL, ",\n")) - { - switch(i) - { + for(tok = strtok(NULL, ",\n"); tok && *tok; i++, tok = strtok(NULL, ",\n")){ + switch(i){ case 0: strtod(tok, &end); break; @@ -1358,6 +1404,7 @@ int search_star_id(struct stars* sim_stars, const char* catalouge) } } } + fclose(stream); return 0; } @@ -1379,40 +1426,29 @@ double cross[3]; int multiply_quaternion(double (&quaternion1)[4], double (&quaternion2)[4], double (&output)[4]) { - double q_vec1[3] = {quaternion1[1], quaternion1[2], quaternion1[3]}; - double q_vec2[3] = {quaternion2[1], quaternion2[2], quaternion2[3]}; - double s1 = quaternion1[0]; - double s2 = quaternion2[0]; - unsigned int i; + double q_vec1[3] = {quaternion1[1], quaternion1[2], quaternion1[3]}; + double q_vec2[3] = {quaternion2[1], quaternion2[2], quaternion2[3]}; + double s1 = quaternion1[0]; + double s2 = quaternion2[0]; + unsigned int i; - cross3(q_vec1, q_vec2, cross); - output[0] = s1 * s2 - dot(q_vec1, q_vec2, 3); + cross3(q_vec1, q_vec2, cross); + output[0] = s1 * s2 - dot(q_vec1, q_vec2, 3); - for(i = 0; i < 3; i++) - { - output[i+1] = s1 * q_vec2[i] + s2 * q_vec1[i] + cross[i]; - } - return 0; + for(i = 0; i < 3; i++){ + output[i+1] = s1 * q_vec2[i] + s2 * q_vec1[i] + cross[i]; + } + return 0; } int generate_shotnoise(double *shot_noise, double* star_signal, double* bkgr_signal, unsigned int size) { - unsigned int i; - double sum = 0; - double mean; - - for(i=0; i < size; i++) - { - shot_noise[i] = random_poisson(sqrt(star_signal[i] + bkgr_signal[i])); - sum = sum + shot_noise[i]; - } - - mean = sum / size; - - for(i=0; i < size; i++) - { - shot_noise[i] = shot_noise[i] - mean; - } + unsigned int i; + + for(i=0; i < size; i++){ + shot_noise[i] = random_poisson(star_signal[i] + bkgr_signal[i]); + } - return 0; + + return 0; } diff --git a/src/HFS_API.hpp b/src/HFS_API.hpp index dc3a4bea8c3d21abca5e899bb79e663ecee8c119..cbb7639ef5fd15c2f3121b6d3ea7c8d84c201dc1 100644 --- a/src/HFS_API.hpp +++ b/src/HFS_API.hpp @@ -1,8 +1,8 @@ /** * @file HFS_API.hpp * @author Gerald Mösenlechner (gerald.moesenlechner@univie.ac.at) -* @date March, 2023 -* @version 0.4 +* @date September, 2023 +* @version 0.5 * * @copyright * This program is free software; you can redistribute it and/or modify it @@ -47,6 +47,7 @@ #define XDIM_KERNEL 25 #define YDIM_KERNEL 25 #define TWO_PI 6.28318531f +#define CVEL 299792.458f //km/s extern const char* MODE_ACQU; @@ -60,11 +61,81 @@ extern const char* MODE_STBY; */ struct hfs_state { - double bias_value, qe, read_noise, dark_mean, bkgr_noise, exposure_time, hp_amount, hp_lower, hp_upper, flat_mean, flat_sigma, plate_scale, dim_x, dim_y, time, focal_length, delay, transition_end, exposure_start; - - unsigned int channel, iter_track, iter_acq, med_track, med_acq, threshold_track, threshold_acq; + double bias_value; + double qe; + double read_noise; + double dark_mean; + double bkgr_noise; + double exposure_time; + double sim_time; + double timestep; + double hp_amount; + double hp_lower; + double hp_upper; + double flat_mean; + double flat_sigma; + double plate_scale; + double pearson_limit; + double ps_fgs1; + double ps_fgs2; + double fl_fgs1; + double fl_fgs2; + double qe_fgs1; + double qe_fgs2; + double lower_sig_lim; + double dim_x; + double dim_y; + double start_exposure; + double focal_length; + double delay; + double x_smear_0; + double y_smear_0; + double jitter_error; + double delay_track; + double delay_acq; + double transition_delay; + double transition_end; + double exp_track; + double exp_acq; + double reset_duration; + double reset_end; + double timing_tolerance; + unsigned int channel; + unsigned int iter_track; + unsigned int iter_acq; + unsigned int med_track; + unsigned int med_acq; + unsigned int threshold_track; + unsigned int threshold_acq; + unsigned int tolerance_acq; + unsigned int target_signal; + unsigned int full_well_cap; + unsigned int med_threshold; + unsigned int sync_ctr; + unsigned int send_cent; + unsigned int val_sigma; + unsigned int track_dim; + unsigned int acq_dim_fgs1; + unsigned int acq_dim_fgs2; + unsigned int rand_seed; + unsigned int fwhm1_x; + unsigned int fwhm1_y; + unsigned int fwhm2_x; + unsigned int fwhm2_y; + unsigned int fwhm_x; + unsigned int fwhm_y; + unsigned int max_targets; + unsigned int extension_sigma; + double offset_FGS1[2]; + double offset_FGS2[2]; + double offset[2]; const char* mode; - struct stars* targets; + std::string psf_fgs1; + std::string psf_fgs2; + const char* input_file; + std::string catalouge; + struct stars* targets = new stars(); + struct coord centroid; }; /** @@ -72,27 +143,36 @@ struct hfs_state * * @param position_quat: quaternion for the attitude of the spacecraft * @param ang_rate: angular rate of the spacecraft in sc reference frame [arcsec/s] - * @param time: current simulation time; + * @param scVelocity: spacecraft velocity vector in SC reference frame [km/s] + * @param time: current simulation time; + * @param sync_flag: synchronisation flag for HFS * @param channel: chosen channel for FGS * @param save: flag for saving the current state of the HFS * @param reset: flag for reseting the HFS * @param set_invalid: flag for setting the validity flag to false - * @param set_error: Set validity index of the centroid - * @param validation_signal: Target Signal used for validation and identification + * @param validation_signal: Target Signal used for validation and identification * @param set_error: Error code that will be set in the centroid, at 0, the HFS will use the code given by the validation * @param mode: operational mode of the FGS 0: Standby, 1: Acquisition, 2: Tracking - * @param add_shift_x/add_shift_y: additive shift of the centroid in centipx - * @param mult_shift_x/mult_shift_y: multiplicative shift of the centroid - * @param target_pos_x/target_pos_y: Position of the FBT inside of the FBA with respect to the center * @note Operational modes are integers as Simulink doesn't support c */ typedef struct{ double position_quat[4]; double ang_rate[3]; + double scVelocity[3]; double time; - unsigned int channel, save, reset, set_invalid, validation_signal, set_error; + unsigned int channel; + unsigned int save; + unsigned int reset; + unsigned int set_invalid; + unsigned int validation_signal; + unsigned int set_error; unsigned int mode; - int add_shift_x, add_shift_y, mult_shift_x, mult_shift_y, target_pos_x, target_pos_y; + int add_shift_x; + int add_shift_y; + int mult_shift_x; + int mult_shift_y; + int target_pos_x; + int target_pos_y; } hfs_parameters; /** @@ -100,6 +180,7 @@ typedef struct{ * * @param x,y: Position measurement in mas * @param time: time tag of the measurement + * @param last_sync: time tag of the last sync pulse * @param validity_flag: Flag for the validity of the measurement * @param validity_index: quality index of the measurement (-1 to 1 or error code) * @param magnitude: signal of the measured star in ADU @@ -147,12 +228,73 @@ int generate_shotnoise(double*, double*, double*, unsigned int); * */ class FGS{ - double bias_value, qe, read_noise, dark_mean, bkgr_noise, exposure_time, sim_time, timestep; - double hp_amount, hp_lower, hp_upper, flat_mean, flat_sigma, plate_scale, pearson_limit, ps_fgs1, ps_fgs2, fl_fgs1, fl_fgs2, qe_fgs1, qe_fgs2, lower_sig_lim; - double dim_x, dim_y, start_exposure, focal_length, delay, x_smear_0, y_smear_0, jitter_error, delay_track, delay_acq, transition_delay, transition_end, exp_track, exp_acq; - unsigned int channel, iter_track, iter_acq, med_track, med_acq, threshold_track; - unsigned int threshold_acq, tolerance_acq, target_signal, full_well_cap, med_threshold, sync_ctr, send_cent, val_sigma, track_dim, acq_dim_fgs1, acq_dim_fgs2, rand_seed, fwhm1_x, fwhm1_y, fwhm2_x, fwhm2_y, fwhm_x, fwhm_y, max_targets, extension_sigma; - double offset_FGS1[2], offset_FGS2[2]; + double bias_value; + double qe; + double read_noise; + double dark_mean; + double bkgr_noise; + double exposure_time; + double sim_time; + double timestep; + double hp_amount; + double hp_lower; + double hp_upper; + double flat_mean; + double flat_sigma; + double plate_scale; + double pearson_limit; + double ps_fgs1; + double ps_fgs2; + double fl_fgs1; + double fl_fgs2; + double qe_fgs1; + double qe_fgs2; + double lower_sig_lim; + double dim_x; + double dim_y; + double start_exposure; + double focal_length; + double delay; + double x_smear_0; + double y_smear_0; + double jitter_error; + double delay_track; + double delay_acq; + double transition_delay; + double transition_end; + double exp_track; + double exp_acq; + double reset_duration; + double reset_end; + double timing_tolerance; + unsigned int channel; + unsigned int iter_track; + unsigned int iter_acq; + unsigned int med_track; + unsigned int med_acq; + unsigned int threshold_track; + unsigned int threshold_acq; + unsigned int tolerance_acq; + unsigned int target_signal; + unsigned int full_well_cap; + unsigned int med_threshold; + unsigned int sync_ctr; + unsigned int send_cent; + unsigned int val_sigma; + unsigned int track_dim; + unsigned int acq_dim_fgs1; + unsigned int acq_dim_fgs2; + unsigned int rand_seed; + unsigned int fwhm1_x; + unsigned int fwhm1_y; + unsigned int fwhm2_x; + unsigned int fwhm2_y; + unsigned int fwhm_x; + unsigned int fwhm_y; + unsigned int max_targets; + unsigned int extension_sigma; + double offset_FGS1[2]; + double offset_FGS2[2]; double offset[2]; const char* mode; std::string psf_fgs1; @@ -162,17 +304,16 @@ class FGS{ struct stars* targets = new stars(); struct coord centroid; - public: FGS(const char* config_file){ input_file = config_file; - reset_fgs(config_file); + reset_fgs(config_file, 1); }; - int reset_fgs(const char*); + int reset_fgs(const char*, int); int generate_smear(double (&)[3], double); @@ -192,11 +333,11 @@ public: int reset_arrays(int); - int transform_to_detector(double (&)[3],int, int, double *); + int transform_to_detector(double (&)[3], double (&)[3],int, int, double *); - int transform_star_coordinates(double (&)[4], int, int); + int transform_star_coordinates(double (&)[4], double(&)[3], int, int); - int generate_centroid(hfs_parameters, centroid_packet *); + int generate_centroid(hfs_parameters); int send_centroid(hfs_parameters, centroid_packet *); }; @@ -208,5 +349,4 @@ extern void createFGS(const char*); extern void deleteFGS(); extern void updateFGS(hfs_parameters*, centroid_packet*); - -#endif //HFS_API_H +#endif diff --git a/src/HFS_Wrapper.cpp b/src/HFS_Wrapper.cpp index e081bdf574c33379994aa691cb3f714824a95863..ce95015ee1485e025c4134f9e39a2249d5d46449 100644 --- a/src/HFS_Wrapper.cpp +++ b/src/HFS_Wrapper.cpp @@ -1,8 +1,8 @@ /** * @file HFS_Wrapper.cpp * @author Gerald Mösenlechner (gerald.moesenlechner@univie.ac.at) -* @date March, 2023 -* @version 0.4 +* @date September, 2023 +* @version 0.5 * * @copyright * This program is free software; you can redistribute it and/or modify it diff --git a/src/HFS_config.xml b/src/HFS_config.xml index e655946f02a11d79d581a1ac25c4e6b42d65bf03..d72c9adf97291670590d03c2feda01046eeb29fa 100644 --- a/src/HFS_config.xml +++ b/src/HFS_config.xml @@ -24,7 +24,7 @@ <!-- Fixed bias value that is included in the final image. --> <bias>2000.0</bias> - <!-- The mean read noise of a pixel in ADU per second. --> + <!-- The mean read noise of a pixel in ADU. --> <readout_noise>20.0</readout_noise> <!-- The mean bkgr noise in photons per second. --> @@ -47,10 +47,19 @@ <median_filter_threshold>1000</median_filter_threshold> <!-- Standard deviation of the centroid error induced by the spacecraft - jitter during the integration period in mas. This will be replaced - by a jitter model from power-spectra in future versions --> + jitter during the integration period in mas. --> <jitter_error_std>5.0</jitter_error_std> + <!-- Duration of the simulated FCU reset in s --> + <reset_duration>0.5</reset_duration> + + <!-- State variable denoting end of ongoing reset, Default: 0--> + <reset_end>0</reset_end> + + <!-- Tolerance for the timing related checks for centroid generation, rerset + and transitions, Default: 0.005--> + <timing_tolerance>0.0</timing_tolerance> + <!-- relative path of the Psf input files. The psfs are given as 40x40px arrays that are stored in the C array format --> @@ -79,6 +88,7 @@ <!-- Angular missalignment of the FGS channels from the optical axis in the the detector plane in mas, No default values available --> <FGS1_Offset_X>400</FGS1_Offset_X> <FGS1_Offset_Y>200</FGS1_Offset_Y> + <FGS2_Offset_X>200</FGS2_Offset_X> <FGS2_Offset_Y>400</FGS2_Offset_Y> @@ -95,14 +105,18 @@ <!-- FWHM of the gaussian used as a weighting function in the centroid calculation in px. Default: FGS1: x = 16, y = 15; FGS2: x = 11, y = 14 --> - <FWHM_FGS1_x>16</FWHM_FGS1_x> - <FWHM_FGS1_y>15</FWHM_FGS1_y> - <FWHM_FGS2_x>11</FWHM_FGS2_x> - <FWHM_FGS2_y>14</FWHM_FGS2_y> + <FWHM_FGS1_x>5</FWHM_FGS1_x> + <FWHM_FGS1_y>5</FWHM_FGS1_y> + <FWHM_FGS2_x>6</FWHM_FGS2_x> + <FWHM_FGS2_y>6</FWHM_FGS2_y> <!-- Time delay causes by the mode switch in s. --> <transition_delay>0.5</transition_delay> + <!-- End time of an ongoing transition. Used for State saving. 0 denotes no transition. Default: 0 + --> + <transition_end>0</transition_end> + <!-- Target signal in ADU per second used for validation --> <target_signal>60000</target_signal> @@ -110,7 +124,7 @@ <lower_signal_limit>1.0</lower_signal_limit> <!-- Sigma threshold in ADU used in the validation procedure --> - <validation_sigma>20</validation_sigma> + <validation_sigma>10</validation_sigma> <!-- Threshold for the Pearson correlation used as the validity index. Index can range from -1 to 1. A value of 0.5 to 0.6 serves as a @@ -148,7 +162,7 @@ <!-- Exposure time for mode Acquisition in s, default: 0.5 --> <exposure_time>0.5</exposure_time> <!-- Brightness tolerance for target identification default is 20% --> - <tolerance>50</tolerance> + <tolerance>20</tolerance> <!-- Dimensiton of the Acquisition window for FGS1, default: 128px --> <FGS1_dim>128</FGS1_dim> <!-- Dimensiton of the Acquisition window for FGS2, default: 161px --> diff --git a/src/detector_features.c b/src/detector_features.c index 11dffb5dcabe7c6e79049ab40ffdbc1259d9edb5..b0ba366d46c2741bc2d9f4e76b05ded37b0171fc 100644 --- a/src/detector_features.c +++ b/src/detector_features.c @@ -1,8 +1,8 @@ /** * @file detector_features.c * @author Gerald Mösenlechner (gerald.moesenlechner@univie.ac.at) -* @date March, 2023 -* @version 0.4 +* @date September, 2023 +* @version 0.5 * * @copyright * This program is free software; you can redistribute it and/or modify it @@ -33,7 +33,9 @@ #include <stdbool.h> #include "./detector_features.h" +#define SWAP(T, a, b) do { T tmp = a; a = b; b = tmp; } while (0) #define SET_PIXEL(img,cols,x,y,val) ( img[x + cols * y] = val ) +#define SET_PIXEL_SMEAR(img,cols,x,y,val) ( img[x + cols * y] += val ) #define GET_PIXEL(img,cols,x,y) ( img[x + cols * y] ) #define TWO_PI 6.28318531f #define SIGDIVFWHM 0.42466452f @@ -57,12 +59,12 @@ */ void generate_bias(double *bias, double *rn_sample, double bias_value, unsigned int sample_length, unsigned int width, unsigned int height) { - unsigned int i, index; + unsigned int i, index; - for(i = 0; i<width*height; i++){ - index = (unsigned int) (random() * (1. / RAND_MAX) * sample_length); - bias[i] = bias_value + rn_sample[index]; - } + for(i = 0; i<width*height; i++){ + index = (unsigned int) (random() * (1. / RAND_MAX) * sample_length); + bias[i] = bias_value + rn_sample[index]; + } } @@ -79,20 +81,20 @@ void generate_bias(double *bias, double *rn_sample, double bias_value, unsigned */ void generate_dark(double *darkframe, double dark_mean, double exp_time, double *hot_pixels, unsigned int width, unsigned int height) { - unsigned int i; - - if(dark_mean == 0.){ - for(i = 0; i < width*height; i++){ - darkframe[i] = 0.0; - } - } - else{ - random_poisson_trm(darkframe, dark_mean*exp_time, width*height); - } - - for(i = 0; i < width*height; i++){ - darkframe[i] = darkframe[i] * hot_pixels[i]; - } + unsigned int i; + + if(dark_mean == 0.){ + for(i = 0; i < width*height; i++){ + darkframe[i] = 0.0; + } + } + else{ + random_poisson_trm(darkframe, dark_mean*exp_time, width*height); + } + + for(i = 0; i < width*height; i++){ + darkframe[i] = darkframe[i] * hot_pixels[i]; + } } /** @@ -107,24 +109,22 @@ void generate_dark(double *darkframe, double dark_mean, double exp_time, double */ void generate_hotpixels(double *hot_pixels, double amount, double lower, double upper, unsigned int width, unsigned int height) { - double value; - unsigned int count, x, y; - unsigned int i; - - srand(time(0)); - - count = (unsigned int) ceil(width*height*amount); - - for(i = 0; i < width*height; i++){ - hot_pixels[i] = 1.; - } - - for(i = 0; i < count; i++){ - x = (unsigned int) (random() * (1. / RAND_MAX) * width); - y = (unsigned int) (random() * (1. / RAND_MAX) * height); - value = lower + (random() * (1. / RAND_MAX) + (upper - lower)); - SET_PIXEL(hot_pixels,width,x,y,value); - } + double value; + unsigned int count, x, y; + unsigned int i; + + count = (unsigned int) ceil(width*height*amount); + + for(i = 0; i < width*height; i++){ + hot_pixels[i] = 1.; + } + + for(i = 0; i < count; i++){ + x = (unsigned int) (random() * (1. / RAND_MAX) * width); + y = (unsigned int) (random() * (1. / RAND_MAX) * height); + value = lower + (random() * (1. / RAND_MAX) + (upper - lower)); + SET_PIXEL(hot_pixels,width,x,y,value); + } } @@ -139,18 +139,18 @@ void generate_hotpixels(double *hot_pixels, double amount, double lower, double */ void generate_flat(double *flatfield, double flat_mean, double flat_sigma, unsigned int width, unsigned int height) { - unsigned int i; - - random_normal_trm(flatfield, flat_mean, flat_sigma, width*height); - - for(i = 0; i < width*height; i++){ - if(flatfield[i] > 1.0){ - flatfield[i] = 1.0; - } - else if(flatfield[i] < 0.0){ - flatfield[i] = 0.0; - } - } + unsigned int i; + + random_normal_trm(flatfield, flat_mean, flat_sigma, width*height); + + for(i = 0; i < width*height; i++){ + if(flatfield[i] > 1.0){ + flatfield[i] = 1.0; + } + else if(flatfield[i] < 0.0){ + flatfield[i] = 0.0; + } + } } @@ -177,9 +177,9 @@ void set_star_in_image(double *image, unsigned int width, unsigned int height, d y = y_orig + 0.5; px_x_low = (int) (x - 0.5); - px_y_low = (int) (y - 0.5); - px_x_high = (int) (x + 0.5); - px_y_high = (int) (y + 0.5); + px_y_low = (int) (y - 0.5); + px_x_high = (int) (x + 0.5); + px_y_high = (int) (y + 0.5); SET_PIXEL(image, height, px_x_low, px_y_low, (1.0-fabs((x_orig-px_x_low))) * (1.0-fabs((y_orig-px_y_low))) * signal); SET_PIXEL(image, height, px_x_high, px_y_high, (1.0-fabs((x_orig-px_x_high))) * (1.0-fabs((y_orig-px_y_high))) * signal); @@ -202,37 +202,30 @@ void set_star_in_image(double *image, unsigned int width, unsigned int height, d void generate_starmask(double *mask, struct stars star_field, double exposure_time, unsigned int detector_width, unsigned int detector_height, unsigned int channel) { - unsigned int i; - double signal; - - for(i = 0; i<star_field.number; i++) - { - if(star_field.visible[i] == 1) - { - if(star_field.x[i] > 0) - { - if(star_field.y[i] > 0) - { - if(star_field.x[i] < detector_width) - { - if(star_field.y[i] < detector_height) - { - if(channel == 1){ - signal = star_field.signalFGS1[i]; - } - else - { - signal = star_field.signalFGS2[i]; - } - set_star_in_image(mask, detector_width, detector_height, star_field.x[i], star_field.y[i], signal*exposure_time); - - } - } - } - } - } - } + unsigned int i; + double signal; + + for(i = 0; i<star_field.number; i++){ + if(star_field.visible[i] == 1){ + if(star_field.x[i] > 0){ + if(star_field.y[i] > 0){ + if(star_field.x[i] < detector_width){ + if(star_field.y[i] < detector_height){ + if(channel == 1){ + signal = star_field.signalFGS1[i]; + } + else{ + signal = star_field.signalFGS2[i]; + } + set_star_in_image(mask, detector_width, detector_height, star_field.x[i], star_field.y[i], signal*exposure_time); + } + } + } + } + } + } } + /* * @brief modified sliding window convolution used for the creation of stellar @@ -250,36 +243,27 @@ void convolve_starmask_fast(double *result, double *starmask, double *psf, int w unsigned int i, j, k, l, i_start, j_start; bzero(result, (size_t) width_star * height_star * sizeof(double)); //#pragma omp parallel for collapse(2) - for(i=0; i<height_star; i++) - { - for(j=0; j<width_star; j++) - { - if (starmask[i+height_star*j] > 0) - { - i_start = i - width_psf/2 + 1; - j_start = j - height_psf/2 + 1; - for(k=0; k<width_psf; k++) - { - for(l=0; l<height_psf; l++) - { - if((i_start + k) > 0) - { - if((j_start + l) > 0) - { - if((i_start + k) < height_star) - { - if((j_start + l) < width_star) - { - result[i_start + k + height_star * (j_start + l)] = result[i_start + k + height_star * (j_start + l)] + psf[k + width_psf*l] * starmask[i + height_star*j]; - } - } - } - } - } - } - } - } - } + for(i=0; i<height_star; i++){ + for(j=0; j<width_star; j++){ + if (starmask[i+height_star*j] > 0){ + i_start = i - (width_psf - 1)/2; + j_start = j - (height_psf - 1)/2; + for(k=0; k<width_psf; k++){ + for(l=0; l<height_psf; l++){ + if((i_start + k) > 0){ + if((j_start + l) > 0){ + if((i_start + k) < height_star){ + if((j_start + l) < width_star){ + result[i_start + k + height_star * (j_start + l)] = result[i_start + k + height_star * (j_start + l)] + psf[k + height_psf*l] * starmask[i + height_star*j]; + } + } + } + } + } + } + } + } + } } /* @@ -313,9 +297,24 @@ void generate_star_image(double *star_image, double *psf, double *starmask, int */ void generate_background(double *bkgrnoise, double background_signal, double qe, double exposure_time, int width, int height) { - double signal; - signal = background_signal*exposure_time*qe; - random_poisson_trm(bkgrnoise, signal, width*height); + double signal; + signal = background_signal*exposure_time*qe; + random_poisson_trm(bkgrnoise, signal, width*height); +} + +double round(double x) +{ + return floor(x) + 0.5; +} + +double fractional(double x) +{ + return x - floor(x); +} + +double complement(double x) +{ + return 1 - fractional(x); } /** @@ -329,6 +328,120 @@ void generate_background(double *bkgrnoise, double background_signal, double qe, * */ void generate_linear_smearing_kernel(double *smear_kernel, double x_origin, double y_origin, double x, double y, unsigned int dim) +{ + double dx, dy, grad, xEnd, yEnd, xGap, x0, x1, y0, y1, inter; + unsigned int xPoint1, xPoint2, yPoint1, yPoint2, i; + bool steep; + + x0 = dim/2 + x_origin; + y0 = dim/2 + y_origin; + x1 = x0 + x; + y1 = y0 + y; + + if(x0 == x1 && y0 == y1){ + SET_PIXEL_SMEAR(smear_kernel, dim, (int) y0, (int )y0, 1); + return; + } + + + if(x0 > (dim-1)){ + x0 = dim-1; + } + if(x0 < 0){ + x0 = 0; + } + if(x1 > (dim-1)){ + x1 = dim-1; + } + if(x1 < 0){ + x1 = 0; + } + if(y0 > (dim-1)){ + y0 = dim-1; + } + if(y0 < 0){ + y0 = 0; + } + if(y1 > (dim-1)){ + y1 = dim-1; + } + if(y1 < 0){ + y1 = 0; + } + + steep = abs(y1 - y0) > abs(x1 - x0); + if(steep){ + SWAP(double, x0, y0); + SWAP(double, x1, y1); + } + + if(x0 > x1){ + SWAP(double, x0, y0); + SWAP(double, x1, y1); + } + + dx = x1 - x0; + dy = y1 - y0; + + if(dx == 0.0){ + grad = 1.0; + } + else{ + grad = dy / dx; + } + + xEnd = round(x0); + yEnd = y0 + grad * (xEnd - x0); + xGap = complement(x0 + 0.5); + xPoint1 = (int) xEnd; + yPoint1 = (int) yEnd; + + if(steep){ + SET_PIXEL_SMEAR(smear_kernel, dim, yPoint1, xPoint1, complement(yEnd) * xGap); + SET_PIXEL_SMEAR(smear_kernel, dim, yPoint1 + 1, xPoint1, fractional(yEnd) * xGap); + } + else{ + SET_PIXEL_SMEAR(smear_kernel, dim, xPoint1, yPoint1, complement(yEnd) * xGap); + SET_PIXEL_SMEAR(smear_kernel, dim, xPoint1, yPoint1 + 1, fractional(yEnd) * xGap); + } + inter = yEnd + grad; + + xEnd = round(x1); + yEnd = y1 + grad * (xEnd - x1); + xGap = fractional(x1 + 0.5); + xPoint2 = (int) xEnd; + yPoint2 = (int) yEnd; + + if(steep){ + SET_PIXEL_SMEAR(smear_kernel, dim, yPoint2, xPoint2, complement(yEnd) * xGap); + SET_PIXEL_SMEAR(smear_kernel, dim, yPoint2 + 1, xPoint2, fractional(yEnd) * xGap); + } + else{ + SET_PIXEL_SMEAR(smear_kernel, dim, xPoint2, yPoint2, complement(yEnd) * xGap); + SET_PIXEL_SMEAR(smear_kernel, dim, xPoint2, yPoint2 + 1, fractional(yEnd) * xGap); + } + + if((xPoint2 - xPoint1) <=1 && (yPoint2 - yPoint1) <=1){ + return; + } + + if(steep){ + for(i = xPoint1; i < xPoint2; i++){ + SET_PIXEL_SMEAR(smear_kernel, dim, (int)inter, i, complement(inter)); + SET_PIXEL_SMEAR(smear_kernel, dim, (int)inter + 1, i, fractional(inter)); + inter = inter + grad; + } + } + else{ + for(i = xPoint1; i < xPoint2; i++){ + SET_PIXEL_SMEAR(smear_kernel, dim, i, (int)inter, complement(inter)); + SET_PIXEL_SMEAR(smear_kernel, dim, i, (int)inter + 1, fractional(inter)); + inter = inter + grad; + } + } +} + +void generate_linear_smearing_kernel_old(double *smear_kernel, double x_origin, double y_origin, double x, double y, unsigned int dim) { unsigned int x0, x1, y0, y1; @@ -339,73 +452,59 @@ void generate_linear_smearing_kernel(double *smear_kernel, double x_origin, doub x1 = (unsigned int) (dim/2) + floor(x); y1 = (unsigned int) (dim/2) + floor(y); - if(x0 > (dim-1)) - { - x0 = dim-1; - } - if(x0 < 0) - { - x0 = 0; - } - if(x1 > (dim-1)) - { - x1 = dim-1; - } - if(x1 < 0) - { - x1 = 0; - } - if(y0 > (dim-1)) - { - y0 = dim-1; - } - if(y0 < 0) - { - y0 = 0; - } - if(y1 > (dim-1)) - { - y1 = dim-1; - } - if(y1 < 0) - { - y1 = 0; - } + if(x0 > (dim-1)){ + x0 = dim-1; + } + if(x0 < 0){ + x0 = 0; + } + if(x1 > (dim-1)){ + x1 = dim-1; + } + if(x1 < 0){ + x1 = 0; + } + if(y0 > (dim-1)){ + y0 = dim-1; + } + if(y0 < 0){ + y0 = 0; + } + if(y1 > (dim-1)){ + y1 = dim-1; + } + if(y1 < 0){ + y1 = 0; + } dx = abs(x1 - x0); sx = x0 < x1 ? 1 : -1; dy = -abs(y1 - y0); sy = y0 < y1 ? 1 : -1; - err = dx + dy; /* error value e_xy */ - - if(err < 1) - { - SET_PIXEL(smear_kernel, dim, x0, y0, 1); - return; - } - - for (;;) - { /* loop */ - SET_PIXEL(smear_kernel, dim, x0, y0, 1); - if (x0 == x1 && y0 == y1) - break; - - e2 = 2 * err; - - if (e2 >= dy) - { - err += dy; - x0 += sx; + err = dx + dy; /* error value e_xy */ + + if(err < 1){ + SET_PIXEL(smear_kernel, dim, x0, y0, 1); + return; + } + + for(;;){ /* loop */ + SET_PIXEL(smear_kernel, dim, x0, y0, 1); + if(x0 == x1 && y0 == y1) + break; + + e2 = 2 * err; + + if(e2 >= dy){ + err += dy; + x0 += sx; } /* e_xy+e_x > 0 */ - if (e2 <= dx) - { - err += dx; - y0 += sy; + if (e2 <= dx){ + err += dx; + y0 += sy; } /* e_xy+e_y < 0 */ - } - + } } - /** * @brief function that generates a linear smearing kernel and convolves it with a given star-map * diff --git a/src/fcu_algorithms.c b/src/fcu_algorithms.c index 847152ac6bee7d3e4e62081a26e04cf640fad761..1cdd5adbbc0b98fd9e7c93b1c281c7866597f4ce 100644 --- a/src/fcu_algorithms.c +++ b/src/fcu_algorithms.c @@ -1,8 +1,8 @@ /** * @file fcu_algorithms.c * @author Gerald Mösenlechner (gerald.moesenlechner@univie.ac.at) -* @date March, 2023 -* @version 0.4 +* @date September, 2023 +* @version 0.5 * * @copyright * This program is free software; you can redistribute it and/or modify it @@ -25,6 +25,7 @@ #include <stdio.h> #include <stdlib.h> +#include <string.h> #include <math.h> #include <limits.h> #include <float.h> @@ -66,17 +67,15 @@ const float FGS2_X[25] = {0.00050931, 0.00081074, 0.00076338, 0.00113407, 0.0012 */ unsigned int GetMin(unsigned int* image, unsigned int length) { - unsigned int minimum, i; - minimum = image[0]; + unsigned int minimum, i; + minimum = image[0]; - for (i=1; i < length; i++) - { - if (image[i] < minimum) - { - minimum = image[i]; + for (i=1; i < length; i++){ + if (image[i] < minimum){ + minimum = image[i]; + } } - } - return minimum; + return minimum; } @@ -95,36 +94,33 @@ unsigned int GetMin(unsigned int* image, unsigned int length) */ void find_brightest_uint (unsigned int *buffer, unsigned int buflength, unsigned int listlength, unsigned int *list, unsigned int *positions) { - unsigned int ctr, lctr, i; - unsigned int temp, temp2, tidx, tidx2; - - for (i=0; i < listlength; i++) - list[i] = 0; - - list[0] = buffer[0]; - - for (ctr=1; ctr < buflength; ctr++) - { - temp = buffer[ctr]; - tidx = ctr; - - if (temp > list[listlength-1]) - { - for (lctr=0; lctr < listlength; lctr++) - { - if (temp > list[lctr]) - { - temp2 = list[lctr]; - tidx2 = positions[lctr]; - list[lctr] = temp; - positions[lctr] = tidx; - temp = temp2; - tidx = tidx2; - } + unsigned int ctr, lctr, i; + unsigned int temp, temp2, tidx, tidx2; + + for (i=0; i < listlength; i++) + list[i] = 0; + + list[0] = buffer[0]; + + for (ctr=1; ctr < buflength; ctr++){ + temp = buffer[ctr]; + tidx = ctr; + + if (temp > list[listlength-1]){ + for (lctr=0; lctr < listlength; lctr++){ + if (temp > list[lctr]){ + temp2 = list[lctr]; + tidx2 = positions[lctr]; + list[lctr] = temp; + positions[lctr] = tidx; + temp = temp2; + tidx = tidx2; + } + } } - } } - return; + + return; } /** @@ -148,14 +144,14 @@ void get_2D_gaussian (float *img, unsigned int cols, unsigned int rows, float ce fval = 1 / (sigx * sigy * TWO_PI); - for (y = 0; y < rows; y++) - for (x = 0; x < cols; x++) - { + for (y = 0; y < rows; y++){ + for (x = 0; x < cols; x++){ xdist = x - center_x; ydist = y - center_y; value = fval*exp(-((xdist*xdist)/(2*sigx*sigx)+(ydist*ydist)/(2*sigy*sigy))); - SET_PIXEL(img, cols, x, y, value); + SET_PIXEL(img, cols, x, y, value); } + } return; } @@ -181,40 +177,38 @@ void GetArielPSF(float *img, unsigned int cols, unsigned int rows, float center_ /* coefficients for intensity(dist) = a*dist + b */ if (Fgs == 1) { - a4 = -2.0340121888836554e-05; - b4 = 0.00040693710306002716; - a3 = -0.0003334301023466291; - b3 = 0.0041640168685535385; - a2 = -0.0010417032033561069; - b2 = 0.009830201676629366; - a1 = -0.0011177934419147849; - b1 = 0.0101345626308640 ; - a0 = -0.000463224129535777; - b0 = 0.00882542400610606; + a4 = -2.0340121888836554e-05; + b4 = 0.00040693710306002716; + a3 = -0.0003334301023466291; + b3 = 0.0041640168685535385; + a2 = -0.0010417032033561069; + b2 = 0.009830201676629366; + a1 = -0.0011177934419147849; + b1 = 0.0101345626308640 ; + a0 = -0.000463224129535777; + b0 = 0.00882542400610606; } else { /* only FGS == 2 applies */ - a4 = -2.0340121888836554e-05; - b4 = 0.00040693710306002716; - a3 = -0.0003334301023466291; - b3 = 0.0041640168685535385; - a2 = -0.0010417032033561069; - b2 = 0.009830201676629366; - a1 = -0.0011177934419147849; - b1 = 0.0101345626308640 ; - a0 = -0.000463224129535777; - b0 = 0.00882542400610606; + a4 = -2.0340121888836554e-05; + b4 = 0.00040693710306002716; + a3 = -0.0003334301023466291; + b3 = 0.0041640168685535385; + a2 = -0.0010417032033561069; + b2 = 0.009830201676629366; + a1 = -0.0011177934419147849; + b1 = 0.0101345626308640 ; + a0 = -0.000463224129535777; + b0 = 0.00882542400610606; } for (y = 0; y < rows; y++) - for (x = 0; x < cols; x++) - { + for (x = 0; x < cols; x++){ /* calculate distance square to center */ xdist = x - center_x; ydist = (y - center_y)/1.5; /* speed up */ - if ((xdist <= 20) || (ydist <= 20)) - { + if ((xdist <= 20) || (ydist <= 20)){ dist = sqrtf(xdist*xdist + ydist*ydist); /* fsqrts takes 22 cycles */ /* calculate PSF from piecewise linear approximation */ @@ -313,22 +307,24 @@ unsigned int torben(unsigned int *data, unsigned int lenght) * */ void check8 (unsigned int *image, unsigned int *sum, int *is_target, unsigned int x, unsigned int y, unsigned int width, unsigned int height, unsigned int threshold) { - unsigned int val, ctr=0; - int i, j; - - for(i = -1;i<=1;i++){ - for(j = -1;j<=1;j++){ - val = GET_PIXEL(image, width, x+i, y+j); - if (val > threshold){ - *sum = *sum + val; - ctr = ctr + 1; - } + unsigned int val, ctr=0; + int i, j; + + for(i = -1;i<=1;i++){ + for(j = -1;j<=1;j++){ + val = GET_PIXEL(image, width, x+i, y+j); + if (val > threshold){ + *sum = *sum + val; + ctr = ctr + 1; + } + } } - } - if (ctr<3){ - *is_target = 0; - } - return; + + if (ctr<3){ + *is_target = 0; + } + + return; } /** @@ -350,94 +346,83 @@ void check8 (unsigned int *image, unsigned int *sum, int *is_target, unsigned in */ int identify_star (unsigned int *image, unsigned int *brightness, int *is_target, unsigned int x_dim, unsigned int y_dim, unsigned int *positions, unsigned int length, unsigned int sigma, unsigned int target_brightness) { - unsigned int pos_x, pos_y, tmp_x, tmp_y; - unsigned int i, j, ctr = 0; - unsigned int brightness_diff[length]; - unsigned int loc, minimum; + unsigned int pos_x, pos_y, tmp_x, tmp_y; + unsigned int i, j, ctr = 0; + unsigned int brightness_diff[length]; + unsigned int loc, minimum; - if (x_dim == 0) - return -1; + if (x_dim == 0) + return -1; - if (y_dim == 0) - return -1; + if (y_dim == 0) + return -1; - for(i = 0; i < length; i++) - { - brightness[i] = 0; - is_target[i] = 1; - pos_x = (positions[i] % x_dim); - pos_y = (positions[i] / y_dim); - for(j = 0; j < i; j++) - { - tmp_x = (positions[j] % x_dim); - tmp_y = (positions[j] / y_dim); - if((abs(pos_x-tmp_x)+abs(pos_y-tmp_y)) == 1) - { - is_target[i] = 0; - } + for(i = 0; i < length; i++){ + brightness[i] = 0; + is_target[i] = 1; + pos_x = (positions[i] % x_dim); + pos_y = (positions[i] / x_dim); + for(j = 0; j < i; j++){ + tmp_x = (positions[j] % x_dim); + tmp_y = (positions[j] / x_dim); + if((abs(pos_x-tmp_x)+abs(pos_y-tmp_y)) == 1){ + is_target[i] = 0; + } } } - for(i = 0; i < length; i++) - { - if(positions[i] > (x_dim * y_dim - 2) || positions[i] < 2) - { - is_target[i] = 0; - } + for(i = 0; i < length; i++){ + if(positions[i] > (x_dim * y_dim - 2) || positions[i] < 2){ + is_target[i] = 0; + } - } - #if 0 - for(i=0; i<length; i++){ + } +#if 0 + for(i=0; i<length; i++){ printf("Position Targets: %i, %i, %i, %i\n", positions[i], positions[i] % x_dim, positions[i] / x_dim, is_target[i]); - } - #endif + } +#endif - for(i = 0; i < length; i++){ - if(is_target[i] != 0) - { - pos_x = (positions[i] % x_dim); - pos_y = (positions[i] / y_dim); - check8(image, &brightness[i], &is_target[i], pos_x, pos_y, x_dim, y_dim, sigma); + for(i = 0; i < length; i++){ + if(is_target[i] != 0){ + pos_x = (positions[i] % x_dim); + pos_y = (positions[i] / x_dim); + check8(image, &brightness[i], &is_target[i], pos_x, pos_y, x_dim, y_dim, sigma); + } } - } - #if 0 +#if 0 for(i=0; i<length; i++){ - printf("Position Targets after check8: %i, %i, %i, %i, %i\n", positions[i], positions[i] % x_dim, positions[i] / x_dim, is_target[i], brightness[i]); + printf("Position Targets after check8: %i, %i, %i, %i, %i\n", positions[i], positions[i] % x_dim, positions[i] / x_dim, is_target[i], brightness[i]); } - #endif +#endif - minimum = 0; - loc = 0; - for(i = 0; i < length; i++){ - if(is_target[i] != 0) - { - brightness_diff[i] = abs(brightness[i]-target_brightness); - if(ctr == 0) - { - minimum = brightness_diff[i]; - loc = i; - ctr = 1; - } - if(brightness_diff[i]<minimum) - { - minimum = brightness_diff[i]; - loc = i; - } + minimum = 0; + loc = 0; + for(i = 0; i < length; i++){ + if(is_target[i] != 0){ + brightness_diff[i] = abs(brightness[i]-target_brightness); + if(ctr == 0){ + minimum = brightness_diff[i]; + loc = i; + ctr = 1; + } + if(brightness_diff[i]<minimum){ + minimum = brightness_diff[i]; + loc = i; + } + } } - } - for(i = 0;i < length; i++) - { - if(i != loc) - { - is_target[i] = 0; + for(i = 0;i < length; i++){ + if(i != loc){ + is_target[i] = 0; + } } - } - return 0; + return 0; } @@ -487,19 +472,17 @@ unsigned int Med9USpoil (unsigned int *data) */ void extract_RoI (unsigned int *image, unsigned int width, unsigned int height, unsigned int target_x, unsigned int target_y, unsigned int *RoI) { - unsigned int x_ctr, y_ctr, x_start, y_start; + unsigned int x_ctr, y_ctr, x_start, y_start; - x_start = target_x * BIN; - y_start = target_y * BIN; + x_start = target_x * BIN; + y_start = target_y * BIN; - for (x_ctr = 0; x_ctr < ROISIZE*BIN; x_ctr++) - { - for (y_ctr = 0; y_ctr < ROISIZE*BIN; y_ctr++) - { - RoI[x_ctr + y_ctr*ROISIZE*BIN] = image[x_start+x_ctr + (y_start + y_ctr)*height]; - } + for (x_ctr = 0; x_ctr < ROISIZE*BIN; x_ctr++){ + for (y_ctr = 0; y_ctr < ROISIZE*BIN; y_ctr++){ + RoI[x_ctr + y_ctr*ROISIZE*BIN] = image[x_start+x_ctr + (y_start + y_ctr)*height]; + } } - return; + return; } /** @@ -513,54 +496,48 @@ void extract_RoI (unsigned int *image, unsigned int width, unsigned int height, */ int MeanSigma (int *data, int len, float *m, float *sig) { - int i; - double sum = 0.; - double sumq = 0.; - double mean, var, sigma; + int i; + double sum = 0.; + double sumq = 0.; + double mean, var, sigma; - /* avoid division by zero */ - if (len == 0) - { - /* m and sig will be undefined */ - return -1; + /* avoid division by zero */ + if (len == 0){ + /* m and sig will be undefined */ + return -1; } - else if (len == 1) - { - *m = data[0]; - *sig = 0.0f; - return -1; + else if (len == 1){ + *m = data[0]; + *sig = 0.0f; + return -1; } - for (i=0; i<len; i++) - sum += data[i]; + for (i=0; i<len; i++) + sum += data[i]; - mean = (double)sum/len; + mean = (double)sum/len; - for (i=0; i<len; i++) - sumq += (data[i]-mean) * (data[i]-mean); + for (i=0; i<len; i++) + sumq += (data[i]-mean) * (data[i]-mean); - var = 1./(len-1.) * sumq; /* with Bessel corr. */ - sigma = sqrt(var); + var = 1./(len-1.) * sumq; /* with Bessel corr. */ + sigma = sqrt(var); - if (mean != 0.0 && - (isnan(mean) || - isgreater(fabs(mean), FLT_MAX) || - isless(fabs(mean), FLT_MIN))) { - return -1; - } else { - *m = (float) mean; - } + if (mean != 0.0 && (isnan(mean) || isgreater(fabs(mean), FLT_MAX) || isless(fabs(mean), FLT_MIN))) { + return -1; + } + else{ + *m = (float) mean; + } - if (sigma != 0.0 && - (isnan(sigma) || - isgreater(fabs(sigma), FLT_MAX) || - isless(fabs(sigma), FLT_MIN))) { - return -1; - } else { - *sig = (float) sigma; - } + if (sigma != 0.0 && (isnan(sigma) || isgreater(fabs(sigma), FLT_MAX) || isless(fabs(sigma), FLT_MIN))) { + return -1; + } + else{ + *sig = (float) sigma; + } - return 0; + return 0; } @@ -576,66 +553,62 @@ int MeanSigma (int *data, int len, float *m, float *sig) */ int Median (int *data, int len) { - int i, less, greater, equal; - int min, max, guess, maxltguess, mingtguess; + int i, less, greater, equal; + int min, max, guess, maxltguess, mingtguess; - min = max = data[0] ; + min = max = data[0] ; - /* find min and max */ - for (i=1 ; i < len ; i++) - { - if (data[i] < min) - min=data[i]; + /* find min and max */ + for (i=1 ; i < len ; i++){ + if (data[i] < min) + min=data[i]; - if (data[i] > max) - max=data[i]; + if (data[i] > max) + max=data[i]; } - while (1) - { - /* update guesses */ - guess = (min + max) / 2; - less = 0; - greater = 0; - equal = 0; - maxltguess = min; - mingtguess = max; - - /* find number of smaller and larger elements than guess */ - for (i=0; i < len; i++) - { - if (data[i] < guess) - { - less++; - if (data[i] > maxltguess) - maxltguess = data[i]; + while (1){ + /* update guesses */ + guess = (min + max) / 2; + less = 0; + greater = 0; + equal = 0; + maxltguess = min; + mingtguess = max; + + /* find number of smaller and larger elements than guess */ + for (i=0; i < len; i++){ + if (data[i] < guess){ + less++; + if (data[i] > maxltguess) + maxltguess = data[i]; + } + else if (data[i] > guess){ + greater++; + if (data[i] < mingtguess) + mingtguess = data[i]; } - else if (data[i] > guess) - { - greater++; - if (data[i] < mingtguess) - mingtguess = data[i]; + else{ + equal++; } - else - equal++; } - /* half the elements are less and half are greater, we hav found the median */ - if ((less <= (len+1)>>1) && (greater <= (len+1)/2)) - break; + /* half the elements are less and half are greater, we hav found the median */ + if ((less <= (len+1)>>1) && (greater <= (len+1)/2)) + break; - else if (less > greater) - max = maxltguess ; - else - min = mingtguess; + else if (less > greater) + max = maxltguess ; + else + min = mingtguess; } - if (less >= (len+1)>>1) - return maxltguess; - else if (less+equal >= (len+1)>>1) - return guess; + if (less >= (len+1)>>1) + return maxltguess; + else if (less+equal >= (len+1)>>1) + return guess; - return mingtguess; + return mingtguess; } /** @@ -657,77 +630,68 @@ int Median (int *data, int len) */ int MedFilter3x3 (unsigned int *data, unsigned int xdim, unsigned int ydim, unsigned int threshold, unsigned int *filtered) { - unsigned int x, y, off; - unsigned int medwin[9]; - unsigned int pixval, median, diff; - - /* we start at 1,1 and run to xdim-1, ydim-1 so that a 1 pixel border is not processed */ - if (xdim < 3) - return -1; - if (ydim < 3) - return -1; - - for (y=1; y < (ydim-1); y++) - { - for (x=1; x < (xdim-1); x++) - { - /* first row */ - off = (y-1)*xdim; - medwin[0] = data[off + x-1]; - medwin[1] = data[off + x]; - medwin[2] = data[off + x+1]; - - /* last row */ - off = (y+1)*xdim; - medwin[6] = data[off + x-1]; - medwin[7] = data[off + x]; - medwin[8] = data[off + x+1]; - - /* middle row */ - off = y*xdim; - medwin[3] = data[off + x-1]; - pixval = data[off + x]; - medwin[4] = pixval; - medwin[5] = data[off + x+1]; - - median = Med9USpoil(medwin); - - if (pixval > median) - { - diff = pixval - median; - } - else - { - diff = median - pixval; - } - - if (diff > threshold) - { - filtered[off + x] = median; /* reuse off from middle row */ - } - else - { - filtered[off + x] = pixval; + unsigned int x, y, off; + unsigned int medwin[9]; + unsigned int pixval, median, diff; + + /* we start at 1,1 and run to xdim-1, ydim-1 so that a 1 pixel border is not processed */ + if (xdim < 3) + return -1; + if (ydim < 3) + return -1; + + for (y=1; y < (ydim-1); y++){ + for (x=1; x < (xdim-1); x++){ + /* first row */ + off = (y-1)*xdim; + medwin[0] = data[off + x-1]; + medwin[1] = data[off + x]; + medwin[2] = data[off + x+1]; + + /* last row */ + off = (y+1)*xdim; + medwin[6] = data[off + x-1]; + medwin[7] = data[off + x]; + medwin[8] = data[off + x+1]; + + /* middle row */ + off = y*xdim; + medwin[3] = data[off + x-1]; + pixval = data[off + x]; + medwin[4] = pixval; + medwin[5] = data[off + x+1]; + + median = Med9USpoil(medwin); + + if (pixval > median){ + diff = pixval - median; + } + else{ + diff = median - pixval; + } + + if (diff > threshold){ + filtered[off + x] = median; /* reuse off from middle row */ + } + else{ + filtered[off + x] = pixval; + } } - } } - /* now copy the borders */ - for (x=0; x < xdim; x++) - { - filtered[x] = data[x]; + /* now copy the borders */ + for (x=0; x < xdim; x++){ + filtered[x] = data[x]; } - for (x=(ydim-1)*xdim; x < ydim*xdim; x++) - { - filtered[x] = data[x]; + for (x=(ydim-1)*xdim; x < ydim*xdim; x++){ + filtered[x] = data[x]; } - for (y=1; y < (ydim-1); y++) - { - filtered[y*xdim] = data[y*xdim]; - filtered[y*xdim + (xdim-1)] = data[y*xdim + (xdim-1)]; + for (y=1; y < (ydim-1); y++){ + filtered[y*xdim] = data[y*xdim]; + filtered[y*xdim + (xdim-1)] = data[y*xdim + (xdim-1)]; } - return 0; + return 0; } /** @@ -747,8 +711,7 @@ void MinMaxU32 (unsigned int *data, unsigned int len, unsigned int *min, unsigne *min = 0xffffffffu; *max = 0x0u; - for (i=0; i < len; i++) - { + for (i=0; i < len; i++){ *min = *min > data[i] ? data[i] : *min; *max = *max < data[i] ? data[i] : *max; } @@ -771,12 +734,11 @@ void MinMaxU32 (unsigned int *data, unsigned int len, unsigned int *min, unsigne float pearson_r(unsigned int *measured_data, unsigned int *reference_data, unsigned int length_set) { unsigned int i; - float mean_data, mean_ref, sum1, sum2, sum3, coeff; + float mean_data, mean_ref, sum1, sum2, sum3, coeff, fraction; - if (length_set == 0) - { - coeff = -2.; - return coeff; + if (length_set == 0){ + coeff = -2.; + return coeff; } sum1 = 0; @@ -786,19 +748,24 @@ float pearson_r(unsigned int *measured_data, unsigned int *reference_data, unsig mean_ref = 0; for(i = 0; i<length_set; i++){ - mean_data = mean_data + measured_data[i]; - mean_ref = mean_ref + reference_data[i]; + mean_data = mean_data + measured_data[i]; + mean_ref = mean_ref + reference_data[i]; } mean_data = mean_data / length_set; mean_ref = mean_ref / length_set; for(i = 0; i<length_set; i++){ - sum1 = sum1 + (measured_data[i]-mean_data)*(reference_data[i]-mean_ref); - sum2 = sum2 + (measured_data[i]-mean_data)*(measured_data[i]-mean_data); - sum3 = sum3 + (reference_data[i]-mean_ref)*(reference_data[i]-mean_ref); - } + sum1 = sum1 + (measured_data[i]-mean_data)*(reference_data[i]-mean_ref); + sum2 = sum2 + (measured_data[i]-mean_data)*(measured_data[i]-mean_data); + sum3 = sum3 + (reference_data[i]-mean_ref)*(reference_data[i]-mean_ref); + } + /*Check to eliminate div by 0*/ + fraction = sqrt(sum2*sum3); + if(fraction != 0.) + coeff = sum1/sqrt(sum2*sum3); + else + coeff = -1.; - coeff = sum1/sqrt(sum2*sum3); return coeff; } @@ -825,33 +792,26 @@ void extract_strips(unsigned int *data, unsigned int *strip_x, unsigned int *str pos_x = x_origin; pos_y = y_origin; - for(i = 0; i<length; i++) - { - if((pos_x < 0)||(pos_x > (dim_x-1))) - { - strip_x[i] = 0; - } - else - { - strip_x[i] = GET_PIXEL(data, dim_x, pos_x, (int)floor(y)); - } + for(i = 0; i<length; i++){ + if((pos_x < 0)||(pos_x > (dim_x-1))){ + strip_x[i] = 0; + } + else{ + strip_x[i] = GET_PIXEL(data, dim_x, pos_x, (int)floor(y)); + } - if((pos_y < 0)||(pos_y > (dim_y-1))) - { - strip_y[i] = 0; - } - else - { - strip_y[i] = GET_PIXEL(data, dim_x, (int)floor(x), pos_y); - } - pos_x = pos_x + 1; - pos_y = pos_y + 1; + if((pos_y < 0)||(pos_y > (dim_y-1))){ + strip_y[i] = 0; + } + else{ + strip_y[i] = GET_PIXEL(data, dim_x, (int)floor(x), pos_y); + } + pos_x = pos_x + 1; + pos_y = pos_y + 1; } - - } -unsigned int binned_image[400]; +unsigned int binned_image[441]; unsigned int x_strip[25]; unsigned int y_strip[25]; unsigned int ref_x[25]; @@ -897,42 +857,36 @@ struct valpack CheckRoiForStar (unsigned int *data, unsigned int x_dim, unsigned unsigned int i; unsigned int median, minimum, maximum; unsigned int binwidth, binheight, binx, biny, x, y, xstart, ystart, rad; - float mean, sigma, xdist, ydist, dist, pearson_x, pearson_y; + float mean, sigma, xdist, ydist, pearson_x, pearson_y; unsigned int sum; int mag; struct valpack package; - if (x_dim == 0) - { + if (x_dim == 0){ package.index = 111; package.magnitude = 0; return package; } - if (y_dim == 0) - { + if (y_dim == 0){ package.index = 111; package.magnitude = 0; return package; } - if (fgs == 1) - { + if (fgs == 1){ rad = 7; } - else - { + else{ rad = 9; } sum = 0; - if ((x_dim >= 20) && (x_dim >= 20)) /* 3x3 bins make no sense for images < 3x3 */ - { - binwidth = x_dim / 20; - binheight = y_dim / 20; + if ((x_dim >= 21) && (x_dim >= 21)){ + binwidth = x_dim / 21; + binheight = y_dim / 21; } - else - { + else{ package.index = 111; package.magnitude = 0; return package; @@ -943,101 +897,81 @@ struct valpack CheckRoiForStar (unsigned int *data, unsigned int x_dim, unsigned and the rest is ignored */ /* clear the binned array first */ - for (i=0; i < 400; i++) - { + for (i=0; i < 441; i++){ binned_image[i] = 0; } /* bin to 3x3 */ - for (biny = 0; biny < 20; biny++) - { - for (y = 0; y < binheight; y++) - { - for (binx = 0; binx < 20; binx++) - { - for (x = 0; x < binwidth; x++) - { + for (biny = 0; biny < 21; biny++){ + for (y = 0; y < binheight; y++){ + for (binx = 0; binx < 21; binx++){ + for (x = 0; x < binwidth; x++){ xstart = x + binx*binwidth; ystart = (y + biny*binheight) * x_dim; - binned_image[binx + 20*biny] += data[xstart + ystart]; + binned_image[binx + 21*biny] += data[xstart + ystart]; } } } } /* convert the sums to averages */ - for (i=0; i < 400; i++) - { + for (i=0; i < 441; i++){ binned_image[i] /= (binwidth * binheight); } - MeanSigma ((int *)binned_image, 400, &mean, &sigma); + MeanSigma ((int *)binned_image, 441, &mean, &sigma); - median = Median ((int *)binned_image, 400); + median = Median ((int *)binned_image, 441); - MinMaxU32 (binned_image, 400, &minimum, &maximum); + MinMaxU32 (binned_image, 441, &minimum, &maximum); /* DEBUGP("CEN: Mean %f Sig: %f Med: %u Min: %u Max: %u\n", mean, sigma, median, minimum, maximum); */ /* rule 1: the image must not be constant */ - if (minimum == maximum) - { + if (minimum == maximum){ package.index = 101; package.magnitude = 0; return package; } /* rule 2: there must be a star */ - if (mean < median) - { + if (mean < median){ package.index = 102; package.magnitude = 0; return package; } /* rule 3: the star must be sharp */ - if ((median + 2*sigma) > maximum) - { + if ((median + 2*sigma) > maximum){ package.index = 103; package.magnitude = 0; return package; } /* rule 4: there must be a signal */ - if ((maximum - minimum) < CenSignalLimit) - { + if ((maximum - minimum) < CenSignalLimit){ package.index = 104; package.magnitude = 0; return package; } /* rule 5: the sigma must be large */ - if (sigma < CenSigmaLimit) - { + if (sigma < CenSigmaLimit){ package.index = 105; package.magnitude = 0; return package; } /*rule 6: the signal inside of a 5px radius circle around the estimated center must contain a certain percentage of the total signal*/ //#pragma omp parallel for private(xdist), private(ydist) - for (y = 0; y < y_dim; y++) - { - for (x = 0; x < x_dim; x++) - { + for (y = 0; y < y_dim; y++){ + for (x = 0; x < x_dim; x++){ /* calculate distance square to center */ - xdist = x - x_center; - ydist = y - y_center; + xdist = abs(x - x_center); + ydist = abs(y - y_center); /* speed up */ - if ((xdist <= rad) || (ydist <= rad)) - { - dist = sqrt(xdist*xdist + ydist*ydist);/* fsqrts takes 22 cycles */ - - if (dist <= rad) - { - sum += GET_PIXEL(data, x_dim, x, y); - - } + if ((xdist <= rad) || (ydist <= rad)){ + sum += GET_PIXEL(data, x_dim, x, y); } } } @@ -1046,18 +980,16 @@ struct valpack CheckRoiForStar (unsigned int *data, unsigned int x_dim, unsigned mag = sum; - if(fgs == 1) - { - for(i = 0; i < 25; i++) - { + /*Multiply with signal to scale reference to extracted sample*/ + + if(fgs == 1){ + for(i = 0; i < 25; i++){ ref_x[i] = (unsigned int) (FGS1_X[i]*mag); ref_y[i] = (unsigned int) (FGS1_Y[i]*mag); } } - else - { - for(i = 0; i < 25; i++) - { + else{ + for(i = 0; i < 25; i++){ ref_x[i] = (unsigned int) (FGS2_X[i]*mag); ref_y[i] = (unsigned int) (FGS2_Y[i]*mag); } @@ -1066,12 +998,10 @@ struct valpack CheckRoiForStar (unsigned int *data, unsigned int x_dim, unsigned pearson_x = pearson_r(x_strip, ref_x, 25); pearson_y = pearson_r(y_strip, ref_y, 25); - if ((pearson_x*pearson_y) < PearsonLimit) - { + if ((pearson_x*pearson_y) < PearsonLimit || pearson_x <= 0.0 || pearson_y <= 0.0){ package.index = 106; } - else - { + else{ package.index = pearson_x*pearson_y; } package.magnitude = mag; @@ -1093,17 +1023,15 @@ struct valpack CheckRoiForStar (unsigned int *data, unsigned int x_dim, unsigned */ void refine_RoI (unsigned int *image, unsigned int *region, unsigned int width, unsigned int height, unsigned int target_x, unsigned int target_y, unsigned int roi_size) { - unsigned int x_ctr, y_ctr; + unsigned int x_ctr, y_ctr; - for (x_ctr = 0; x_ctr < roi_size; x_ctr++) - { - for (y_ctr = 0; y_ctr < roi_size; y_ctr++) - { + for(x_ctr = 0; x_ctr < roi_size; x_ctr++){ + for (y_ctr = 0; y_ctr < roi_size; y_ctr++){ region[x_ctr + y_ctr*roi_size] = image[target_x+x_ctr + (target_y + y_ctr)*height]; - } + } } - return; + return; } /** @@ -1135,8 +1063,7 @@ void CenterOfGravity2D (unsigned int *img, unsigned int rows, unsigned int cols, /* for the y axis */ pos = 0.0; - for (i = 0; i < rows; i++) - { + for (i = 0; i < rows; i++){ tmp = 0; for (j = 0; j < cols; j++) @@ -1151,8 +1078,7 @@ void CenterOfGravity2D (unsigned int *img, unsigned int rows, unsigned int cols, /* for the x axis */ pos = 0.0; - for (j = 0; j < cols; j++) - { + for (j = 0; j < cols; j++){ tmp = 0; for (i = 0; i < rows; i++) @@ -1167,6 +1093,8 @@ void CenterOfGravity2D (unsigned int *img, unsigned int rows, unsigned int cols, return; } + +unsigned int tmpImg[2048*2048]; /** * @brief Calculates centroid using Weighted Center of Gravity for a 2d image * @@ -1191,10 +1119,9 @@ void WeightedCenterOfGravity2D (unsigned int *img, float *weights, unsigned int { unsigned int i; - for (i = 0; i < rows * cols; i++) - { + for (i = 0; i < rows * cols; i++){ /* multiply image with weights */ - img[i] = (unsigned int) (weights[i]*img[i]); + tmpImg[i] = (unsigned int) (weights[i]*img[i]); /* and find max value */ //max = img[i] > max ? img[i] : max; @@ -1202,7 +1129,7 @@ void WeightedCenterOfGravity2D (unsigned int *img, float *weights, unsigned int /* determine size of datatype and shift so that it is back within CogBits (e.g. 16) bits */ - CenterOfGravity2D (img, rows, cols, x, y); + CenterOfGravity2D (tmpImg, rows, cols, x, y); return; } @@ -1228,9 +1155,8 @@ void IntensityWeightedCenterOfGravity2D (unsigned int *img, unsigned int rows, u { unsigned int i; /* the IWC just works on the square of the image */ - for(i = 0; i<rows*cols;i++) - { - weight[i] = (float) img[i]; + for(i = 0; i<rows*cols;i++){ + weight[i] = (float) img[i]; } WeightedCenterOfGravity2D (img, weight, rows, cols, x, y); @@ -1263,16 +1189,13 @@ void IterativelyWeightedCenterOfGravity2D (unsigned int *img, float *weights, un { unsigned int i; - for (i = 0; i < iter; i++) - { - if (mode == MODE_GAUSS) - { + for (i = 0; i < iter; i++){ + if (mode == MODE_GAUSS){ get_2D_gaussian (weights, cols, rows, *x, *y, fwhm_x, fwhm_y); - } - else - { + } + else{ GetArielPSF (weights, cols, rows, *x, *y, fgs); - } + } WeightedCenterOfGravity2D (img, weights, rows, cols, x, y); } @@ -1309,78 +1232,77 @@ unsigned int roi_cog[REFINEDROISIZE*REFINEDROISIZE]; struct coord ArielCoG (unsigned int *img, unsigned int rows, unsigned int cols, unsigned int iterations, int mode, float fwhm_x, float fwhm_y, int fgs, unsigned int CenSignalLimit, unsigned int CenSigmaLimit, float PearsonLimit) { - float x_res, y_res; - float x_roi, y_roi; - unsigned int x_start, y_start; - unsigned int i; - struct coord res; + float x_res, y_res; + float x_roi, y_roi; + int x_start, y_start, x_shift, y_shift; + unsigned int i; + struct coord res; - x_res = (float) rows / 2; - y_res = (float) cols / 2; + memset(&res, 0, sizeof(res)); - IntensityWeightedCenterOfGravity2D (img, rows, cols, &x_res, &y_res); + x_res = (float) rows / 2; + y_res = (float) cols / 2; - x_start = (int) x_res - REFINEDROISIZE/2 + 1; /*FLP34-C violation due to execution time*/ - y_start = (int) y_res - REFINEDROISIZE/2 + 1; /*FLP34-C violation due to execution time*/ + IntensityWeightedCenterOfGravity2D (img, rows, cols, &x_res, &y_res); + x_start = (int) x_res - REFINEDROISIZE/2 + 1; /*FLP34-C violation due to execution time*/ + y_start = (int) y_res - REFINEDROISIZE/2 + 1; /*FLP34-C violation due to execution time*/ - x_roi = x_res - x_start; - y_roi = y_res - y_start; - for (i=0; i < iterations; i++) - { + x_roi = x_res - x_start; + y_roi = y_res - y_start; - if (i != 0) - { - x_start = (int) (x_start + x_roi) - REFINEDROISIZE/2 + 1; - y_start = (int) (y_start + y_roi) - REFINEDROISIZE/2 + 1; - } + for (i=0; i < iterations; i++){ - if (x_start < 0) - { - x_start = 0; - } - if (y_start < 0) - { - y_start = 0; - } - if (x_start > (rows - REFINEDROISIZE)) - { - x_start = rows - REFINEDROISIZE; - } - if (y_start > (cols - REFINEDROISIZE)) - { - y_start = cols - REFINEDROISIZE; - } - refine_RoI (img, roi_cog, rows, cols, x_start, y_start, REFINEDROISIZE); - if (mode == MODE_GAUSS) - { - get_2D_gaussian (weights_cog, REFINEDROISIZE, REFINEDROISIZE, x_roi, y_roi, fwhm_x, fwhm_y); - } - else - { - GetArielPSF (weights_cog, REFINEDROISIZE, REFINEDROISIZE, x_roi, y_roi, fgs); - } + if (i != 0){ + x_shift = (int) x_roi - REFINEDROISIZE/2 + 1; + y_shift = (int) y_roi - REFINEDROISIZE/2 + 1; - WeightedCenterOfGravity2D (roi_cog, weights_cog, REFINEDROISIZE, REFINEDROISIZE, &x_roi, &y_roi); + x_start = x_start + x_shift; + y_start = y_start + y_shift; - } + x_roi = x_roi - x_shift; + y_roi = y_roi - y_shift; - res.x = x_start + x_roi; - res.y = y_start + y_roi; + } - res.validity = CheckRoiForStar (img, rows, cols, CenSignalLimit, CenSigmaLimit, PearsonLimit,fgs , res.x, res.y); + if (x_start < 0){ + x_start = 0; + } + if (y_start < 0){ + y_start = 0; + } + if (x_start > (rows - REFINEDROISIZE)){ + x_start = rows - REFINEDROISIZE; + } + if (y_start > (cols - REFINEDROISIZE)){ + y_start = cols - REFINEDROISIZE; + } + refine_RoI (img, roi_cog, rows, cols, x_start, y_start, REFINEDROISIZE); + if (mode == MODE_GAUSS){ + get_2D_gaussian (weights_cog, REFINEDROISIZE, REFINEDROISIZE, x_roi, y_roi, fwhm_x, fwhm_y); + } + else{ + GetArielPSF (weights_cog, REFINEDROISIZE, REFINEDROISIZE, x_roi, y_roi, fgs); + } - if(res.validity.index > 99) - { - res.validity.flag = 0; - } - else - { - res.validity.flag = 1; - } + WeightedCenterOfGravity2D (roi_cog, weights_cog, REFINEDROISIZE, REFINEDROISIZE, &x_roi, &y_roi); + + } + + res.x = x_start + x_roi; + res.y = y_start + y_roi; + + res.validity = CheckRoiForStar (img, rows, cols, CenSignalLimit, CenSigmaLimit, PearsonLimit,fgs , res.x, res.y); + + if(res.validity.index > 99){ + res.validity.flag = 0; + } + else{ + res.validity.flag = 1; + } - return res; + return res; } unsigned int binned[XDIM/BIN * YDIM/BIN]; @@ -1412,51 +1334,42 @@ unsigned int roi[BIN*BIN*ROISIZE*ROISIZE]; struct coord SourceDetection(unsigned int *data, unsigned int xdim, unsigned int ydim, int mode, int fgs, unsigned int target_number, unsigned int target_brightness, unsigned int brightness_tolerance, unsigned int sigma, unsigned int iter, float fwhm_x, float fwhm_y, unsigned int CenSignalLimit, unsigned int CenSigmaLimit, float PearsonLimit) { - unsigned int binnedwidth, binnedheight, binx, biny, x, y, xstart, ystart; - unsigned int source_val[target_number]; - unsigned int source_pos[target_number]; - unsigned int source_br[target_number]; - int target[target_number]; - int pos_x, pos_y, flag; - unsigned int tmp_br = 0, sum = 0, th = 0, mean, i; /*tmp_br is a placeholder for the brightnes check*/ - flag = 0; - struct coord result; - - - - if ((xdim > BIN) && (ydim > BIN)) /* check binsize vs image size */ - { + unsigned int binnedwidth, binnedheight, binx, biny, x, y, xstart, ystart; + unsigned int source_val[target_number]; + unsigned int source_pos[target_number]; + unsigned int source_br[target_number]; + int target[target_number]; + int pos_x, pos_y, flag; + unsigned int tmp_br = 0, sum = 0, th = 0, mean, i; /*tmp_br is a placeholder for the brightnes check*/ + struct coord result; + + flag = 0; + + if ((xdim > BIN) && (ydim > BIN)){ binnedwidth = xdim / BIN; binnedheight = ydim / BIN; } - else - { - result.x = 0; - result.y = 0; - return result; + else{ + result.x = 0; + result.y = 0; + return result; } - if ((binnedwidth == 0) || (binnedheight == 0)) - { - result.validity.index = 108; - return result; - } + if ((binnedwidth == 0) || (binnedheight == 0)){ + result.validity.index = 108; + return result; + } - for (i=0; i < (binnedwidth*binnedheight); i++) - { - binned[i] = 0; - } + for (i=0; i < (binnedwidth*binnedheight); i++){ + binned[i] = 0; + } /* bin to 3x3 */ - for (biny = 0; biny < binnedheight; biny++) - { - for (y = 0; y < BIN; y++) - { - for (binx = 0; binx < binnedwidth; binx++) - { - for (x = 0; x < BIN; x++) - { + for (biny = 0; biny < binnedheight; biny++){ + for (y = 0; y < BIN; y++){ + for (binx = 0; binx < binnedwidth; binx++){ + for (x = 0; x < BIN; x++){ xstart = x + binx*BIN; ystart = (y + biny*BIN) * xdim; binned[binx + binnedwidth*biny] = binned[binx + binnedwidth*biny] + data[xstart + ystart]; @@ -1467,109 +1380,99 @@ struct coord SourceDetection(unsigned int *data, unsigned int xdim, unsigned int /* calc mean */ - for (i=0; i < (binnedwidth * binnedheight); i++) - { + for (i=0; i < (binnedwidth * binnedheight); i++){ sum = sum + binned[i]; } - mean = (unsigned int) sum / (binnedwidth * binnedheight); + mean = (unsigned int) sum / (binnedwidth * binnedheight); #if 0 - for(i=0; i<(binnedwidth * binnedheight); i++) - { - printf("%i ", binned[i]); - if (i && !((i + 1) % binnedwidth)) + for(i=0; i<(binnedwidth * binnedheight); i++){ + printf("%i ", binned[i]); + if (i && !((i + 1) % binnedwidth)) printf("\n"); } #endif - find_brightest_uint(binned, (binnedwidth * binnedheight), target_number, source_val, source_pos); + find_brightest_uint(binned, (binnedwidth * binnedheight), target_number, source_val, source_pos); /*Debug flag for source extraction*/ #if 0 - for(i=0; i<target_number; i++){ - printf("x = %i, y = %i, width = %i\n", source_pos[i]% binnedwidth, source_pos[i] / binnedwidth, binnedwidth); + for(i=0; i<target_number; i++){ + printf("x = %i, y = %i, width = %i\n", source_pos[i]% binnedwidth, source_pos[i] / binnedwidth, binnedwidth); } #endif - identify_star(binned, source_br, target, binnedwidth, binnedheight, source_pos, target_number, mean + sigma, target_brightness); + identify_star(binned, source_br, target, binnedwidth, binnedheight, source_pos, target_number, mean + sigma, target_brightness); /*Debug flag for target identification*/ #if 0 - for(i=0; i<target_number; i++){ - printf("%i, %i\n", target[i], source_br[i]); - } + for(i=0; i<target_number; i++){ + printf("%i, %i\n", target[i], source_br[i]); + } #endif - for(i=0; i<target_number;i++){ - if (target[i] == 1){ - if (source_br[i] > tmp_br && (abs(source_br[i]-target_brightness) < (int)(target_brightness*brightness_tolerance/100))){ - tmp_br = source_br[i]; - pos_x = (source_pos[i] % binnedwidth); - pos_y = (source_pos[i] / binnedwidth); - flag = 1; - } + for(i=0; i<target_number;i++){ + if (target[i] == 1){ + if (source_br[i] > tmp_br && (abs(source_br[i]-target_brightness) < (int)(target_brightness*brightness_tolerance/100))){ + tmp_br = source_br[i]; + pos_x = (source_pos[i] % binnedwidth); + pos_y = (source_pos[i] / binnedwidth); + flag = 1; + } + } } - } - pos_x = pos_x - ROISIZE/2; - pos_y = pos_y - ROISIZE/2; + pos_x = pos_x - ROISIZE/2; + pos_y = pos_y - ROISIZE/2; - if(flag == 0){ - pos_x = 0; - pos_y = 0; - } - if (pos_x < 0) - { - pos_x = 0; + if(flag == 0){ + pos_x = 0; + pos_y = 0; } - if (pos_y < 0) - { - pos_y = 0; + if (pos_x < 0){ + pos_x = 0; } - if (pos_x > (binnedwidth - ROISIZE)) - { - pos_x = binnedwidth - ROISIZE; + if (pos_y < 0){ + pos_y = 0; } - if (pos_y > (binnedheight - ROISIZE)) - { - pos_y = binnedheight - ROISIZE; + if (pos_x > (binnedwidth - ROISIZE)){ + pos_x = binnedwidth - ROISIZE; + } + if (pos_y > (binnedheight - ROISIZE)){ + pos_y = binnedheight - ROISIZE; } - extract_RoI(data, xdim, ydim, pos_x, pos_y, roi); + extract_RoI(data, xdim, ydim, pos_x, pos_y, roi); /*Debug flag Print RoI*/ #if 0 - for (i=0; i<ROISIZE*ROISIZE*BIN*BIN; i++) - { - printf("%i ", roi[i]); - if (i && !((i + 1) % (ROISIZE*BIN))) + for (i=0; i<ROISIZE*ROISIZE*BIN*BIN; i++){ + printf("%i ", roi[i]); + if (i && !((i + 1) % (ROISIZE*BIN))) printf("\n"); } #endif - th = GetMin(roi, ROISIZE*BIN*ROISIZE*BIN); + th = GetMin(roi, ROISIZE*BIN*ROISIZE*BIN); - for (i=0; i < (ROISIZE*BIN*ROISIZE*BIN); i++) - { - roi[i] = roi[i] - th; - } + for (i=0; i < (ROISIZE*BIN*ROISIZE*BIN); i++){ + roi[i] = roi[i] - th; + } - result = ArielCoG(roi, ROISIZE*BIN, ROISIZE*BIN, iter, mode, fwhm_x, fwhm_y, fgs, CenSignalLimit, CenSigmaLimit, PearsonLimit); - result.x = result.x + (float) (pos_x*BIN); - result.y = result.y + (float) (pos_y*BIN); - if(flag == 0){ - result.validity.index = 107; - } - if(result.validity.index > 99) - { - result.validity.flag = 0; - } - else - { - result.validity.flag = 1; - } - result.time = 0.; - return result; + result = ArielCoG(roi, ROISIZE*BIN, ROISIZE*BIN, iter, mode, fwhm_x, fwhm_y, fgs, CenSignalLimit, CenSigmaLimit, PearsonLimit); + result.x = result.x + (float) (pos_x*BIN); + result.y = result.y + (float) (pos_y*BIN); + if(flag == 0){ + result.validity.index = 107; + } + if(result.validity.index > 99){ + result.validity.flag = 0; + } + else{ + result.validity.flag = 1; + } + result.time = 0.; + return result; } diff --git a/src/utilities.c b/src/utilities.c index f8bef39d002bea2261fdcd50e4c5e4522b9c933c..c3be04e575931b417116bfbd00f080be07c62015 100644 --- a/src/utilities.c +++ b/src/utilities.c @@ -1,8 +1,8 @@ /** * @file utilities.c * @author Gerald Mösenlechner (gerald.moesenlechner@univie.ac.at) -* @date March, 2023 -* @version 0.4 +* @date September, 2023 +* @version 0.5 * * @copyright * This program is free software; you can redistribute it and/or modify it @@ -304,12 +304,11 @@ int downsample_image(double *image, double *downsampled_image , unsigned int wid sum = sum + value; } } - - for (i = 0; i < width_new * height_new; i++) - { - downsampled_image[i] = downsampled_image[i]/sum; - } - + if(sum > 0.){ + for (i = 0; i < width_new * height_new; i++){ + downsampled_image[i] = downsampled_image[i]/sum; + } + } return 0; } @@ -365,9 +364,12 @@ int dmatmult (struct dmatrix a, struct dmatrix b, struct dmatrix *result) { result->data[z*result->xdim + s] += a.data[z*a.xdim + i] * b.data[i*b.xdim + s]; } + return 0; } else + { fprintf (stderr, "ERROR: matrices are incompatible!\n"); - - return 0; + return -1; + } + return -1; } diff --git a/test/DetectorFeatureTest.cpp b/test/DetectorFeatureTest.cpp new file mode 100644 index 0000000000000000000000000000000000000000..65a5e078d885357570f2dfc9706a3dfb42dfba9e --- /dev/null +++ b/test/DetectorFeatureTest.cpp @@ -0,0 +1,314 @@ +#include <cppunit/config/SourcePrefix.h> +#include "../src/detector_features.h" +#include "DetectorFeatureTest.hpp" +#include <iostream> +#include <stdio.h> +#include <stdlib.h> +#include <experimental/filesystem> +#include <math.h> + +CPPUNIT_TEST_SUITE_REGISTRATION(DetectorFeaturesTest); + +void DetectorFeaturesTest::setUp() +{ + unsigned int i; + + for(i = 0; i < 200*200; i++){ + bias[i] = 0.; + dark[i] = 0.; + hp[i] = 0.; + flat[i] = 0.; + mask[i] = 0.; + psf[i] = 0.; + bkgr[i] = 0.; + } + + + for(i = 0; i < 125*125; i++){ + kernel[i] = 0.; + } +} + +void DetectorFeaturesTest::tearDown() +{ +} + +void DetectorFeaturesTest::testBias() +{ + unsigned int i; + + for(i = 0; i < 200; i++){ + rnSample[i] = 0.0; + } + + generate_bias(bias, rnSample, 123., 200, 200, 200); + std::cout << "Check if all pixels have the same bias values.\n"; + for(i = 0; i < 200*200; i++){ + CPPUNIT_ASSERT_DOUBLES_EQUAL(bias[i], 123., 0.001); + } +} + +void DetectorFeaturesTest::testDark() +{ + unsigned int i; + double mean, std; + + for(i = 0; i < 200*200; i++){ + hp[i] = 1.0; + } + + hp[100] = 100.; + + mean = 0.; + std = 0.; + generate_dark(dark, 10., 1., hp, 200, 200); + std::cout << "Check if dark values are not 0\n"; + for(i = 0; i < 200*200; i++) + { + CPPUNIT_ASSERT(dark[i] > 0.0); + mean = mean + dark[i]; + } + + mean = mean / (200*200); + for(i = 0; i < 200*200; i++) + { + std = std + (dark[i] - mean) * (dark[i] - mean); + } + std = sqrt(std/(200*200)); + + std::cout << "Check if single hot pixel is a statistical outlier.\n"; + + CPPUNIT_ASSERT(dark[100] > (mean + std)); +} + +void DetectorFeaturesTest::testHotPixels() +{ + unsigned int i; + double mean; + mean = 0; + + for(i = 0; i < 200*200; i++){ + hp[i] = 0.0; + } + + generate_hotpixels(hp, 0.5, 100, 10000, 200, 200); + std::cout << "Check if the hot pixel values are not 0\n"; + for(i = 0; i < 200*200; i++){ + CPPUNIT_ASSERT(hp[i] > 0.0); + mean = mean + hp[i]; + } + + mean = mean / (200*200); + std::cout << "Check if hot pixels where generated.\n"; + CPPUNIT_ASSERT(mean > 1.0); +} + +void DetectorFeaturesTest::testFlat() +{ + double flat[200*200]; + unsigned int i; + + for(i = 0; i < 200*200; i++){ + flat[i] = 0.0; + } + + generate_flat(flat, 0.9, 0.08, 200, 200); + std::cout << "Check if flat values are not 0 and below 1.\n"; + + for(i = 0; i < 200*200; i++){ + CPPUNIT_ASSERT(flat[i] > 0.0); + CPPUNIT_ASSERT(flat[i] <= 1.0); + } + +} + +void DetectorFeaturesTest::testStar() +{ + struct stars catalogue; + unsigned int i; + double sum; + sum = 0; + + for(i = 0; i < 2500; i++){ + catalogue.signalFGS1[i] = 0.; + catalogue.signalFGS2[i] = 0.; + catalogue.x[i] = 0.; + catalogue.y[i] = 0.; + catalogue.visible[i] = 0; + } + catalogue.number = 4; + + catalogue.signalFGS1[0] = 500; + catalogue.signalFGS2[0] = 1000; + + catalogue.signalFGS1[1] = 2000; + catalogue.signalFGS2[1] = 4000; + + catalogue.signalFGS1[2] = 6000; + catalogue.signalFGS2[2] = 8000; + + catalogue.signalFGS1[3] = 10000; + catalogue.signalFGS2[3] = 12000; + + catalogue.visible[0] = 1; + catalogue.visible[1] = 1; + catalogue.visible[2] = 1; + catalogue.visible[3] = 1; + + catalogue.x[0] = -10.0; + catalogue.y[0] = 30.0; + + catalogue.x[1] = 100.5; + catalogue.y[1] = 100.0; + + catalogue.x[2] = 30.0; + catalogue.y[2] = 60.0; + + catalogue.x[3] = 300.0; + catalogue.y[3] = 10.0; + + for(i = 0; i < 200*200; i++){ + mask[i] = 0.; + } + + generate_starmask(mask, catalogue, 1.0, 200, 200, 1); + + for(i = 0; i < 200*200; i++){ + sum = sum + mask[i]; + } + std::cout << "Check for correct mask generation with default config.\n"; + CPPUNIT_ASSERT_DOUBLES_EQUAL(sum, 8000., 0.0001); + + catalogue.visible[2] = 0; + + for(i = 0; i < 200*200; i++){ + mask[i] = 0.; + } + + generate_starmask(mask, catalogue, 1.0, 200, 200, 1); + sum = 0.; + for(i = 0; i < 200*200; i++){ + sum = sum + mask[i]; + } + std::cout << "Check for correct use of visible flag.\n"; + + CPPUNIT_ASSERT_DOUBLES_EQUAL(sum, 2000., 0.0001); + + for(i = 0; i < 200*200; i++){ + mask[i] = 0.; + } + + generate_starmask(mask, catalogue, 1.0, 200, 200, 2); + sum = 0.; + for(i = 0; i < 200*200; i++){ + sum = sum + mask[i]; + } + std::cout << "Check for correct use of channel config.\n"; + + CPPUNIT_ASSERT_DOUBLES_EQUAL(sum, 4000., 0.0001); + +} + +void DetectorFeaturesTest::testConvolve() +{ + struct stars catalogue; + const char psfName[128] = "./FGS1_270nm.txt"; + unsigned int i; + double sumMask, sumImage; + std::ifstream psfIf; + + sumMask = 0.; + sumImage = 0.; + + psfIf.open(psfName, std::ifstream::in); + if (psfIf.is_open()) + { + for (i = 0; i < 40*40; i++) + { + psfIf >> psf[i]; + } + psfIf.close(); + } + + + catalogue.number = 1; + + catalogue.signalFGS1[0] = 2000; + catalogue.signalFGS2[0] = 2000; + + + catalogue.visible[0] = 1; + + catalogue.x[0] = 100.0; + catalogue.y[0] = 100.0; + + for(i = 0; i < 200*200; i++){ + mask[i] = 0.; + } + + + + generate_starmask(mask, catalogue, 1.0, 200, 200, 1); + + for(i = 0; i < 200*200; i++){ + sumMask = sumMask + mask[i]; + } + + generate_star_image(image, psf, mask, 200, 200, 40, 40); + + for(i = 0; i < 200*200; i++){ + sumImage = sumImage + image[i]; + } + + std::cout << "Check if signal is conserved in convolution.\n"; + CPPUNIT_ASSERT_DOUBLES_EQUAL(sumMask, sumImage, 0.0001); +} + +void DetectorFeaturesTest::testBkgr() +{ + unsigned int i; + + for(i = 0; i < 200*200; i++){ + bkgr[i] = 0.0; + } + + generate_background(bkgr, 10, 1.0, 1.0, 200, 200); + std::cout << "Check if background is not 0.\n"; + + for(i = 0; i < 200*200; i++){ + CPPUNIT_ASSERT(bkgr[i] > 0.); + } + +} + +void DetectorFeaturesTest::testSmear() +{ + unsigned int i; + + for(i = 0; i < 125*125; i++){ + kernel[i] = 0.; + } + + generate_linear_smearing_kernel(kernel, 0, 0, 10, 10, 125); + std::cout << "Check endpoints of smear in positive smear direction.\n"; + CPPUNIT_ASSERT(kernel[62 + 125*62] > 0.0); + CPPUNIT_ASSERT(kernel[71 + 125*71] > 0.0); + + for(i = 0; i < 125*125; i++){ + kernel[i] = 0.; + } + + generate_linear_smearing_kernel(kernel, 0, 0, -10, -10, 125); + std::cout << "Check endpoints of smear in negative smear direction.\n"; + CPPUNIT_ASSERT(kernel[62 + 125*62] > 0.0); + CPPUNIT_ASSERT(kernel[52 + 125*52] > 0.0); + + for(i = 0; i < 125*125; i++){ + kernel[i] = 0.; + } + + generate_linear_smearing_kernel(kernel, -70, -70, 130, 130, 125); + std::cout << "Check limit failsave.\n"; + CPPUNIT_ASSERT(kernel[0] > 0.0); + CPPUNIT_ASSERT(kernel[122 + 122*125] > 0.0); +} diff --git a/test/DetectorFeatureTest.hpp b/test/DetectorFeatureTest.hpp new file mode 100644 index 0000000000000000000000000000000000000000..65d997dc498922a1f8ab25e54dee9b277af458bf --- /dev/null +++ b/test/DetectorFeatureTest.hpp @@ -0,0 +1,53 @@ +#ifndef DETECTORFEATURESTEST_H +#define DETECTORFEATURESTEST_H +#include <cppunit/TestCase.h> +#include <cppunit/extensions/HelperMacros.h> + +class DetectorFeaturesTest : public CppUnit::TestFixture +{ + CPPUNIT_TEST_SUITE(DetectorFeaturesTest); + CPPUNIT_TEST(testBias); + CPPUNIT_TEST(testDark); + CPPUNIT_TEST(testHotPixels); + CPPUNIT_TEST(testFlat); + CPPUNIT_TEST(testStar); + CPPUNIT_TEST(testConvolve); + CPPUNIT_TEST(testBkgr); + CPPUNIT_TEST(testSmear); + CPPUNIT_TEST_SUITE_END(); + + double bias[200*200]; + double rnSample[200]; + double dark[200*200]; + double hp[200*200]; + double flat[200*200]; + double mask[200*200]; + double psf[40*40]; + double image[1000*1000]; + double bkgr[200*200]; + double kernel[125*125]; + + +public: + + void setUp(); + void tearDown(); + + void testBias(); + + void testDark(); + + void testHotPixels(); + + void testFlat(); + + void testStar(); + + void testConvolve(); + + void testBkgr(); + + void testSmear(); +}; + +#endif //DETECTORFEATURESTEST_H diff --git a/test/FCUTest.cpp b/test/FCUTest.cpp new file mode 100644 index 0000000000000000000000000000000000000000..60a22fe5898abb72f81a2a5219b382c6080ab0d8 --- /dev/null +++ b/test/FCUTest.cpp @@ -0,0 +1,204 @@ +#include <cppunit/config/SourcePrefix.h> +#include "../src/fcu_algorithms.h" +#include "FCUTest.hpp" +#include <fstream> +#include <iostream> +#include <stdio.h> +#include <stdlib.h> +#include <experimental/filesystem> +#include <math.h> + +CPPUNIT_TEST_SUITE_REGISTRATION(FCUTest); + +void FCUTest::setUp() +{ + unsigned int i; + const char noStarName[128] = "./test/noStar.txt"; + const char acqImgName[128] = "./test/acquisitionTest.txt"; + const char starImgName[128] = "./test/trackingTest.txt"; + std::ifstream noStarIf, starImgIf, acqImgIf; + + acqImgIf.open(acqImgName, std::ifstream::in); + if (acqImgIf.is_open()) + { + for (i = 0; i < 200*200; i++) + { + acqImgIf >> acqImg[i]; + } + acqImgIf.close(); + } + + + for(i = 0; i < 64*64; i++){ + noSignal[i] = 0.; + } + + noStarIf.open(noStarName, std::ifstream::in); + + if (noStarIf.is_open()) + { + for (i = 0; i < 64*64; i++) + { + noStarIf >> noStar[i]; + } + noStarIf.close(); + } + + starImgIf.open(starImgName, std::ifstream::in); + if (starImgIf.is_open()) + { + for (i = 0; i < 64*64; i++) + { + starImgIf >> starImg[i]; + } + starImgIf.close(); + } + +} + +void FCUTest::tearDown() +{ +} + +void FCUTest::testMin() +{ + unsigned int testSet[10] = {3, 6, 0, 4, 9, 7, 5, 2, 8, 1}; + unsigned int res; + + res = GetMin(testSet, 10); + + CPPUNIT_ASSERT(res == 0); + +} + +void FCUTest::testMedianFilter() +{ + unsigned int input[64*64]; + unsigned int output[64*64]; + unsigned int i; + int flag; + + flag = 0; + + for(i = 0; i < 64*64; i++){ + input[i] = noStar[i]; + } + std::cout << "Check dimension checks of median filter.\n"; + input[120] = 100000.0; + flag = MedFilter3x3(input, 2, 64, 200, output); + CPPUNIT_ASSERT(flag == -1); + + flag = 0; + flag = MedFilter3x3(input, 64, 2, 200, output); + CPPUNIT_ASSERT(flag == -1); + std::cout << "Check function of median filter.\n"; + flag = 0; + flag = MedFilter3x3(input, 64, 64, 200, output); + CPPUNIT_ASSERT(flag == 0); + + CPPUNIT_ASSERT(output[120] < 500); + +} + +void FCUTest::testValidation() +{ + struct valpack package; + + + std::cout << "Check Dimension check.\n"; + package = CheckRoiForStar(noSignal, 0, 64, 100, 100, 0.6, 1, 32., 32.); + std::cout << package.index << "\n"; + CPPUNIT_ASSERT(package.index == 111); + + package.index = 0; + + package = CheckRoiForStar(noSignal, 64, 0, 100, 100, 0.6, 1, 32., 32.); + CPPUNIT_ASSERT(package.index == 111); + std::cout << package.index << "\n"; + + package.index = 0; + std::cout << "Check constant image check.\n"; + + package = CheckRoiForStar(noSignal, 64, 64, 100, 100, 0.6, 1, 32., 32.); + std::cout << package.index << "\n"; + CPPUNIT_ASSERT(package.index == 101); + + package.index = 0; + std::cout << "Check no star check.\n"; + + package = CheckRoiForStar(noStar, 64, 64, 100, 20, 0.6, 1, 32., 32.); + std::cout << package.index << "\n"; + CPPUNIT_ASSERT(package.index == 102); + + package.index = 0; + std::cout << "Check too low signal check.\n"; + + package = CheckRoiForStar(starImg, 64, 64, 10000, 20, 0.6, 1, 32., 32.); + std::cout << package.index << "\n"; + CPPUNIT_ASSERT(package.index == 104); + + package.index = 0; + std::cout << "Check too low sigma check.\n"; + + package = CheckRoiForStar(starImg, 64, 64, 100, 200, 0.6, 1, 32., 32.); + std::cout << package.index << "\n"; + CPPUNIT_ASSERT(package.index == 105); + + package.index = 0; + std::cout << "Check too low pearson check.\n"; + + package = CheckRoiForStar(starImg, 64, 64, 100, 20, 1.0, 1, 32., 32.); + std::cout << package.index << "\n"; + CPPUNIT_ASSERT(package.index == 106); + + package.index = 0; + std::cout << "Check valid output.\n"; + + package = CheckRoiForStar(starImg, 64, 64, 100, 20, 0.0, 1, 32., 32.); + std::cout << package.index << "\n"; + CPPUNIT_ASSERT(package.index < 1.0); + +} + +void FCUTest::testAcquisition() +{ + struct coord output; + + std::cout << "Check valid output.\n"; + + output = SourceDetection(acqImg, 200, 200, 0, 1, 4, 30000, 50, 20, 3, 5., 5., 100, 20, 0.3); + + CPPUNIT_ASSERT(output.x < 100.0); + CPPUNIT_ASSERT(output.x > 99.0); + CPPUNIT_ASSERT(output.y < 100.0); + CPPUNIT_ASSERT(output.y > 99.0); + CPPUNIT_ASSERT(output.validity.flag == 1); + CPPUNIT_ASSERT(output.validity.index < 1.0); + + std::cout << "Check no valid target.\n"; + + output = SourceDetection(acqImg, 200, 200, 0, 1, 4, 200000, 50, 20, 3, 5., 5., 100, 20, 0.3); + CPPUNIT_ASSERT(output.validity.flag == 0); +} + +void FCUTest::testCentroid() +{ + struct coord output; + + std::cout << "Check valid output.\n"; + + output = ArielCoG(starImg, 64, 64, 5, 0, 5., 5., 1, 100, 20, 0.3); + CPPUNIT_ASSERT(output.x < 32.0); + CPPUNIT_ASSERT(output.x > 31.0); + CPPUNIT_ASSERT(output.y < 32.0); + CPPUNIT_ASSERT(output.y > 31.0); + CPPUNIT_ASSERT(output.validity.flag == 1); + CPPUNIT_ASSERT(output.validity.index < 1.0); + + std::cout << "Check invalid output.\n"; + + output = ArielCoG(noStar, 64, 64, 5, 0, 5., 5., 1, 100, 200, 0.3); + CPPUNIT_ASSERT(output.validity.flag == 0); + +} + diff --git a/test/FCUTest.hpp b/test/FCUTest.hpp new file mode 100644 index 0000000000000000000000000000000000000000..18e4dfcd1132b35060f9b05b76c71e88b110b026 --- /dev/null +++ b/test/FCUTest.hpp @@ -0,0 +1,34 @@ +#ifndef FCUTEST_H +#define FCUTEST_H +#include <cppunit/TestCase.h> +#include <cppunit/extensions/HelperMacros.h> + +class FCUTest : public CppUnit::TestFixture +{ + CPPUNIT_TEST_SUITE(FCUTest); + CPPUNIT_TEST(testMin); + CPPUNIT_TEST(testMedianFilter); + CPPUNIT_TEST(testValidation); + CPPUNIT_TEST(testAcquisition); + CPPUNIT_TEST(testCentroid); + CPPUNIT_TEST_SUITE_END(); + unsigned int noSignal[64*64]; + unsigned int noStar[64*64]; + unsigned int starImg[64*64]; + unsigned int acqImg[200*200]; + + +public: + + + void setUp(); + void tearDown(); + + void testMin(); + void testMedianFilter(); + void testValidation(); + void testAcquisition(); + void testCentroid(); + }; + +#endif //FCUTEST_H diff --git a/test/HFSTest.cpp b/test/HFSTest.cpp index 6cc114c80332dcf31328f370de03e53be4d356d8..b4fffcc5a030b6a2662459f06353e386c8202212 100644 --- a/test/HFSTest.cpp +++ b/test/HFSTest.cpp @@ -5,6 +5,7 @@ #include <stdio.h> #include <stdlib.h> #include <experimental/filesystem> +#include <math.h> #define TWO_PI 6.28318531f @@ -22,120 +23,416 @@ void HFSTest::tearDown() void HFSTest::testConstructor() { - struct hfs_state state; - char path[] = "./test/HFS_config_test.xml"; - char* real_path = realpath(path, NULL); + struct hfs_state state; + char path[] = "./test/HFS_config_test.xml"; + char* real_path = realpath(path, NULL); - FGS fgs(real_path); + FGS fgs(real_path); - state = fgs.get_hfs_state(); + state = fgs.get_hfs_state(); - CPPUNIT_ASSERT_DOUBLES_EQUAL(state.flat_mean, 0.97, 0.001); + CPPUNIT_ASSERT_DOUBLES_EQUAL(state.timestep, 0.015625, 0.001); + + CPPUNIT_ASSERT_EQUAL((int) state.rand_seed, 135412); - CPPUNIT_ASSERT_DOUBLES_EQUAL(state.flat_sigma, 0.03, 0.001); + CPPUNIT_ASSERT_DOUBLES_EQUAL(state.start_exposure, 0.0, 0.001); - CPPUNIT_ASSERT_DOUBLES_EQUAL(state.bias_value, 2000, 0.001); + CPPUNIT_ASSERT_DOUBLES_EQUAL(state.flat_mean, 0.97, 0.001); - CPPUNIT_ASSERT_DOUBLES_EQUAL(state.read_noise, 20, 0.001); + CPPUNIT_ASSERT_DOUBLES_EQUAL(state.flat_sigma, 0.03, 0.001); - CPPUNIT_ASSERT_DOUBLES_EQUAL(state.dark_mean, 1, 0.001); + CPPUNIT_ASSERT_DOUBLES_EQUAL(state.bias_value, 2000, 0.001); - CPPUNIT_ASSERT_DOUBLES_EQUAL(state.hp_amount, 0, 0.001); + CPPUNIT_ASSERT_DOUBLES_EQUAL(state.read_noise, 20, 0.001); - CPPUNIT_ASSERT_EQUAL((int)state.channel, 1); + CPPUNIT_ASSERT_DOUBLES_EQUAL(state.bkgr_noise, 1.1, 0.001); - //CPPUNIT_ASSERT(strncmp(state.mode, "Tracking", 7) == 0); + CPPUNIT_ASSERT_DOUBLES_EQUAL(state.dark_mean, 1, 0.001); - CPPUNIT_ASSERT_DOUBLES_EQUAL(state.qe, 0.58, 0.001); + CPPUNIT_ASSERT_DOUBLES_EQUAL(state.hp_amount, 0, 0.0); - CPPUNIT_ASSERT_DOUBLES_EQUAL(state.exposure_time, 0.1, 0.001); + CPPUNIT_ASSERT_EQUAL((int) state.full_well_cap, 100000); - CPPUNIT_ASSERT_DOUBLES_EQUAL(state.plate_scale, 175, 0.001); + CPPUNIT_ASSERT_EQUAL((int) state.med_threshold, 1000); - CPPUNIT_ASSERT_DOUBLES_EQUAL(state.focal_length, 21.21, 0.001); + CPPUNIT_ASSERT_DOUBLES_EQUAL(state.jitter_error, 5.0, 0.001); - CPPUNIT_ASSERT_DOUBLES_EQUAL(state.delay, 0.02, 0.001); + CPPUNIT_ASSERT_DOUBLES_EQUAL(state.reset_duration, 0.5, 0.001); - CPPUNIT_ASSERT_EQUAL((int)state.dim_x, 64); + CPPUNIT_ASSERT_DOUBLES_EQUAL(state.reset_end, 0.0, 0.001); - CPPUNIT_ASSERT_EQUAL((int)state.dim_y, 64); + CPPUNIT_ASSERT_DOUBLES_EQUAL(state.timing_tolerance, 0.0, 0.001); - CPPUNIT_ASSERT_EQUAL((int)state.iter_track, 5); + CPPUNIT_ASSERT_DOUBLES_EQUAL(state.ps_fgs1, 175.0, 0.001); - CPPUNIT_ASSERT_EQUAL((int)state.med_track, 1); + CPPUNIT_ASSERT_DOUBLES_EQUAL(state.ps_fgs2, 137.0, 0.001); - CPPUNIT_ASSERT_EQUAL((int)state.threshold_track, 1); + CPPUNIT_ASSERT_DOUBLES_EQUAL(state.fl_fgs1, 21.21, 0.001); - CPPUNIT_ASSERT_EQUAL((int)state.iter_acq, 3); + CPPUNIT_ASSERT_DOUBLES_EQUAL(state.fl_fgs2, 27.08, 0.001); - CPPUNIT_ASSERT_EQUAL((int)state.med_acq, 0); + CPPUNIT_ASSERT_DOUBLES_EQUAL(state.qe_fgs1, 0.58, 0.001); - CPPUNIT_ASSERT_EQUAL((int)state.threshold_acq, 1); + CPPUNIT_ASSERT_DOUBLES_EQUAL(state.qe_fgs2, 0.70, 0.001); + + CPPUNIT_ASSERT_DOUBLES_EQUAL(state.offset_FGS1[0], 0, 0.001); + CPPUNIT_ASSERT_DOUBLES_EQUAL(state.offset_FGS1[1], 0, 0.001); + CPPUNIT_ASSERT_DOUBLES_EQUAL(state.offset_FGS2[0], 0, 0.001); + CPPUNIT_ASSERT_DOUBLES_EQUAL(state.offset_FGS2[1], 0, 0.001); + CPPUNIT_ASSERT_EQUAL((int)state.channel, 1); + + //CPPUNIT_ASSERT(strncmp(state.mode, "Tracking", 7) == 0); + + CPPUNIT_ASSERT_EQUAL((int) state.fwhm1_x, 5); + CPPUNIT_ASSERT_EQUAL((int) state.fwhm1_y, 5); + + CPPUNIT_ASSERT_EQUAL((int) state.fwhm2_x, 6); + CPPUNIT_ASSERT_EQUAL((int) state.fwhm2_y, 6); + + CPPUNIT_ASSERT_DOUBLES_EQUAL(state.transition_delay, 0.5, 0.001); + + CPPUNIT_ASSERT_DOUBLES_EQUAL(state.transition_end, 0.0, 0.001); + + CPPUNIT_ASSERT_EQUAL((int) state.target_signal, 80000); + + CPPUNIT_ASSERT_DOUBLES_EQUAL(state.lower_sig_lim, 1.0, 0.001); + + CPPUNIT_ASSERT_EQUAL((int) state.val_sigma, 10); + + CPPUNIT_ASSERT_DOUBLES_EQUAL(state.pearson_limit, 0.6, 0.001); + + CPPUNIT_ASSERT_DOUBLES_EQUAL(state.qe, 0.58, 0.001); + + CPPUNIT_ASSERT_EQUAL((int)state.iter_track, 5); + + CPPUNIT_ASSERT_EQUAL((int)state.med_track, 1); + + CPPUNIT_ASSERT_EQUAL((int)state.threshold_track, 1); + + CPPUNIT_ASSERT_DOUBLES_EQUAL(state.delay_track, 0.02, 0.001); + + CPPUNIT_ASSERT_DOUBLES_EQUAL(state.exp_track, 0.1, 0.001); + + CPPUNIT_ASSERT_EQUAL((int) state.track_dim, 64); + + CPPUNIT_ASSERT_EQUAL((int)state.iter_acq, 3); + + CPPUNIT_ASSERT_EQUAL((int)state.med_acq, 0); + + CPPUNIT_ASSERT_EQUAL((int)state.threshold_acq, 1); + + CPPUNIT_ASSERT_DOUBLES_EQUAL(state.delay_acq, 0.1, 0.001); + + CPPUNIT_ASSERT_DOUBLES_EQUAL(state.exp_acq, 0.5, 0.001); + + CPPUNIT_ASSERT_EQUAL((int) state.tolerance_acq, 20); + + CPPUNIT_ASSERT_EQUAL((int) state.acq_dim_fgs1, 128); + + CPPUNIT_ASSERT_EQUAL((int) state.acq_dim_fgs2, 161); + + CPPUNIT_ASSERT_EQUAL((int) state.max_targets, 10); + + CPPUNIT_ASSERT_EQUAL((int) state.extension_sigma, 1000); + + CPPUNIT_ASSERT_DOUBLES_EQUAL(state.x_smear_0, 0.0, 0.001); + + CPPUNIT_ASSERT_DOUBLES_EQUAL(state.y_smear_0, 0.0, 0.001); } void HFSTest::testChannelChange() { - struct hfs_state state; - char path[] = "./test/HFS_config_test.xml"; - char* real_path = realpath(path, NULL); - FGS fgs(real_path); - - fgs.set_channel(2); - state = fgs.get_hfs_state(); - CPPUNIT_ASSERT_EQUAL((int)state.channel, 2); - CPPUNIT_ASSERT_DOUBLES_EQUAL(state.qe, 0.70, 0.001); - CPPUNIT_ASSERT_DOUBLES_EQUAL(state.plate_scale, 137.1, 0.001); - CPPUNIT_ASSERT_DOUBLES_EQUAL(state.focal_length, 27.08, 0.001); + struct hfs_state state; + char path[] = "./test/HFS_config_test.xml"; + char* real_path = realpath(path, NULL); + FGS fgs(real_path); + + fgs.set_channel(2); + state = fgs.get_hfs_state(); + CPPUNIT_ASSERT_EQUAL((int)state.channel, 2); + CPPUNIT_ASSERT_DOUBLES_EQUAL(state.qe, 0.70, 0.001); + CPPUNIT_ASSERT_DOUBLES_EQUAL(state.plate_scale, 137.0, 0.001); + CPPUNIT_ASSERT_DOUBLES_EQUAL(state.focal_length, 27.08, 0.001); + + fgs.set_channel(1); + state = fgs.get_hfs_state(); + CPPUNIT_ASSERT_EQUAL((int)state.channel, 1); + CPPUNIT_ASSERT_DOUBLES_EQUAL(state.qe, 0.58, 0.001); + CPPUNIT_ASSERT_DOUBLES_EQUAL(state.plate_scale, 175.0, 0.001); + CPPUNIT_ASSERT_DOUBLES_EQUAL(state.focal_length, 21.21, 0.001); + } void HFSTest::testModeChange() { - struct hfs_state state; - char path[] = "./test/HFS_config_test.xml"; - char* real_path = realpath(path, NULL); - FGS fgs(real_path); + struct hfs_state state; + char path[] = "./test/HFS_config_test.xml"; + char* real_path = realpath(path, NULL); + FGS fgs(real_path); - fgs.set_mode("Acquisition"); + fgs.set_mode("Acquisition"); - state = fgs.get_hfs_state(); + state = fgs.get_hfs_state(); - CPPUNIT_ASSERT(strcmp(state.mode, "Acquisition") == 0); - CPPUNIT_ASSERT_DOUBLES_EQUAL(state.delay, 0.1, 0.001); - CPPUNIT_ASSERT_EQUAL((int)state.dim_x, 128); - CPPUNIT_ASSERT_EQUAL((int)state.dim_y, 128); - CPPUNIT_ASSERT_DOUBLES_EQUAL(state.exposure_time, 0.5, 0.001); + CPPUNIT_ASSERT(strcmp(state.mode, "Acquisition") == 0); + CPPUNIT_ASSERT_DOUBLES_EQUAL(state.delay, 0.1, 0.001); + CPPUNIT_ASSERT_EQUAL((int)state.dim_x, 128); + CPPUNIT_ASSERT_EQUAL((int)state.dim_y, 128); + CPPUNIT_ASSERT_DOUBLES_EQUAL(state.exposure_time, 0.5, 0.001); - fgs.set_mode("Tracking"); + fgs.set_mode("Tracking"); - state = fgs.get_hfs_state(); - CPPUNIT_ASSERT(strcmp(state.mode, "Tracking") == 0); + state = fgs.get_hfs_state(); + CPPUNIT_ASSERT(strcmp(state.mode, "Tracking") == 0); } void HFSTest::testTransformation() { - char path[] = "./test/HFS_config_test.xml"; - char* real_path = realpath(path, NULL); - FGS fgs(real_path); - double vecx[3] = {1e-5 ,0 , 0}; - double vecy[3] = {0 ,1e-5 , 0}; - double vecz[3] = {0 ,0 , 1e-5}; - double output[2]; + char path[] = "./test/HFS_config_test.xml"; + char* real_path = realpath(path, NULL); + FGS fgs(real_path); + double vecx[3] = {1e-5 ,0 , 0}; + double vecy[3] = {0 ,1e-5 , 0}; + double vecz[3] = {0 ,0 , 1e-5}; + double vecVel[3] = {0, 0, 0}; + double output[2]; + double velRes; + + fgs.transform_to_detector(vecx, vecVel, 0, 0, output); + CPPUNIT_ASSERT_DOUBLES_EQUAL(output[0], 0, 1e-7); + CPPUNIT_ASSERT_DOUBLES_EQUAL(output[1], acos(cos(1.7*1e-8))*(360/TWO_PI)*3600000/176.0, 0.001); - fgs.transform_to_detector(vecx, 0, 0, output); - CPPUNIT_ASSERT_DOUBLES_EQUAL(output[0], 0, 1e-7); - CPPUNIT_ASSERT_DOUBLES_EQUAL(output[1], 0.0017*1e-5*(360/TWO_PI)*3600000/175.0, 1e-7); + fgs.transform_to_detector(vecy, vecVel, 0, 0, output); + CPPUNIT_ASSERT_DOUBLES_EQUAL(output[0], acos(cos(1e-5))*(360/TWO_PI)*3600000/176.0, 0.1); + CPPUNIT_ASSERT_DOUBLES_EQUAL(output[1], 0, 1e-7); - fgs.transform_to_detector(vecy, 0, 0, output); - CPPUNIT_ASSERT_DOUBLES_EQUAL(output[0], 1e-5*(360/TWO_PI)*3600000/175.0, 1e-7); - CPPUNIT_ASSERT_DOUBLES_EQUAL(output[1], 0, 1e-7); + fgs.transform_to_detector(vecz, vecVel, 0, 0, output); + CPPUNIT_ASSERT_DOUBLES_EQUAL(output[0], 0, 1e-7); + CPPUNIT_ASSERT_DOUBLES_EQUAL(output[1], acos(cos(0.999998*1e-5))*(360/TWO_PI)*3600000/176.0, 0.1); + + vecVel[0] = 1000; + + fgs.transform_to_detector(vecx, vecVel, 0, 0, output); + velRes = acos((cos(1.7*1e-8) - 1.7/CVEL)/(1 - cos(1.7*1e-8)*(1.7/CVEL))); + CPPUNIT_ASSERT_DOUBLES_EQUAL(output[0], 0, 1e-7); + CPPUNIT_ASSERT_DOUBLES_EQUAL(output[1], velRes*(360/TWO_PI)*3600000/176.0, 0.001); - fgs.transform_to_detector(vecz, 0, 0, output); - CPPUNIT_ASSERT_DOUBLES_EQUAL(output[0], 0, 1e-7); - CPPUNIT_ASSERT_DOUBLES_EQUAL(output[1], 0.999998*1e-5*(360/TWO_PI)*3600000/175.0, 1e-5); } +void HFSTest::testMainLoop() +{ + char path[] = "./test/HFS_config_test.xml"; + char* real_path = realpath(path, NULL); + FGS fgs(real_path); + struct hfs_state state; + hfs_parameters update; + centroid_packet output; + double quat[4] = {0.8892834993148474, -0.0006038143244162956, 0.2873837014059442, -0.3557880006700909}; + double vel[3] = {0.0, 0.0, 0.0}; + double time; + double dt = 0.015625; + unsigned int i; + + output.time = 0.; + time = 0.; + update.reset = 0; + /*set FGS channel*/ + update.channel = 1; + update.mode = 2; + + /*create xml file with current state*/ + update.save = 0; + update.set_invalid = 0; + + update.set_error = 0; + update.time = time; + + /*set shifts*/ + update.add_shift_x = 0; + update.add_shift_y = 0; + update.mult_shift_x = 1; + update.mult_shift_y = 1; + + update.target_pos_x = 0; + update.target_pos_y = 0; + + /*Set signal for target identification in ADU/s*/ + update.validation_signal = 80000; + + /*Unit quaternion of the current SC attitude in reference to J2000*/ + update.position_quat[0] = quat[0]; + update.position_quat[1] = quat[1]; + update.position_quat[2] = quat[2]; + update.position_quat[3] = quat[3]; + + update.scVelocity[0] = vel[0]; + update.scVelocity[1] = vel[1]; + update.scVelocity[2] = vel[2]; + + /*Angular rate in the SC reference frame in arcsec/s*/ + update.ang_rate[0] = 0; + update.ang_rate[1] = 1; + update.ang_rate[2] = 1; + + fgs.set_params(update, &output); + state = fgs.get_hfs_state(); + CPPUNIT_ASSERT_DOUBLES_EQUAL(state.sim_time, 0.0, 0.00001); + std::cout << "Check exposure start\n"; + CPPUNIT_ASSERT_DOUBLES_EQUAL(state.start_exposure, 0.0, 0.00001); + + update.time = update.time + dt; + fgs.set_params(update, &output); + state = fgs.get_hfs_state(); + std::cout << "Check time propagation\n"; + CPPUNIT_ASSERT_DOUBLES_EQUAL(state.sim_time, dt, 0.00001); + CPPUNIT_ASSERT_DOUBLES_EQUAL(state.start_exposure, 0.0, 0.00001); + + for(i = 0; i < 10; i++) + { + update.time = update.time + dt; + fgs.set_params(update, &output); + } + + state = fgs.get_hfs_state(); + + std::cout << "Check new integration start\n"; + CPPUNIT_ASSERT_DOUBLES_EQUAL(state.start_exposure, 0.109375, 0.00001); + + std::cout << "Check generated centroid packet\n"; + CPPUNIT_ASSERT(output.x > 100); + CPPUNIT_ASSERT_DOUBLES_EQUAL(output.time, 0.12, 0.01); + + std::cout << "Check Channel transition\n"; + + update.channel = 2; + update.time = update.time + dt; + fgs.set_params(update, &output); + update.time = update.time + dt; + fgs.set_params(update, &output); + + /* Advance time to next centroid generation */ + update.time = update.time + dt; + fgs.set_params(update, &output); + + state = fgs.get_hfs_state(); + CPPUNIT_ASSERT_DOUBLES_EQUAL(state.transition_end, update.time + 0.5, 0.0001); + /* Advance time past transtion end*/ + for(i = 0; i < 50; i++) + { + update.time = update.time + dt; + fgs.set_params(update, &output); + } + + state = fgs.get_hfs_state(); + CPPUNIT_ASSERT_EQUAL((int )state.channel, 2); + + std::cout << "Check Reset of FGS\n"; + update.reset = 1; + update.time = update.time + dt; + fgs.set_params(update, &output); + + update.reset = 0; + update.channel = 1; + state = fgs.get_hfs_state(); + CPPUNIT_ASSERT_DOUBLES_EQUAL(state.reset_end, update.time + 0.5, 0.0001); + /* Advance time past reset end*/ + for(i = 0; i < 50; i++) + { + update.time = update.time + dt; + fgs.set_params(update, &output); + } + + state = fgs.get_hfs_state(); + + CPPUNIT_ASSERT_DOUBLES_EQUAL(state.reset_end, 0.0, 0.0001); + CPPUNIT_ASSERT_EQUAL((int )state.channel, 1); + CPPUNIT_ASSERT_DOUBLES_EQUAL(state.sim_time, update.time, 0.0001); + +} + +void HFSTest::testSave() +{ + char path[] = "./test/HFS_config_test.xml"; + char pathNew[] = "./HFS_config_1.xml"; + char* realPathNew = realpath(pathNew, NULL); + char* realPath = realpath(path, NULL); + FGS fgs(realPath); + struct hfs_state state; + struct hfs_state stateNew; + hfs_parameters update; + centroid_packet output; + double quat[4] = {0.8892834993148474, -0.0006038143244162956, 0.2873837014059442, -0.3557880006700909}; + double vel[3] = {0.0, 0.0, 0.0}; + double time; + double dt = 0.015625; + unsigned int i; + + output.time = 0.; + time = 0.; + update.reset = 0; + /*set FGS channel*/ + update.channel = 1; + update.mode = 2; + + /*create xml file with current state*/ + update.save = 0; + update.set_invalid = 0; + + update.set_error = 0; + update.time = time; + + /*set shifts*/ + update.add_shift_x = 0; + update.add_shift_y = 0; + update.mult_shift_x = 1; + update.mult_shift_y = 1; + + update.target_pos_x = 0; + update.target_pos_y = 0; + + /*Set signal for target identification in ADU/s*/ + update.validation_signal = 80000; + + /*Unit quaternion of the current SC attitude in reference to J2000*/ + update.position_quat[0] = quat[0]; + update.position_quat[1] = quat[1]; + update.position_quat[2] = quat[2]; + update.position_quat[3] = quat[3]; + + update.scVelocity[0] = vel[0]; + update.scVelocity[1] = vel[1]; + update.scVelocity[2] = vel[2]; + + /*Angular rate in the SC reference frame in arcsec/s*/ + update.ang_rate[0] = 0; + update.ang_rate[1] = 1; + update.ang_rate[2] = 1; + + fgs.set_params(update, &output); + + update.channel = 2; + + for(i = 0; i < 50; i++) + { + update.time = update.time + dt; + fgs.set_params(update, &output); + } + + update.save = 1; + fgs.set_params(update, &output); + update.save = 0; + + FGS fgsSave(realPathNew); + + state = fgs.get_hfs_state(); + stateNew = fgsSave.get_hfs_state(); + + CPPUNIT_ASSERT_EQUAL((int)stateNew.channel, 2); + CPPUNIT_ASSERT_DOUBLES_EQUAL(state.start_exposure, stateNew.start_exposure, 0.000001); + CPPUNIT_ASSERT_EQUAL((int) state.rand_seed, (int) stateNew.rand_seed); +} diff --git a/test/HFSTest.hpp b/test/HFSTest.hpp index b12f9cde28a50c300258bb0cecf4b3826acf25c1..69c6d235917dc8556003c9dc1230369444c12eb7 100644 --- a/test/HFSTest.hpp +++ b/test/HFSTest.hpp @@ -10,6 +10,8 @@ class HFSTest : public CppUnit::TestFixture CPPUNIT_TEST(testChannelChange); CPPUNIT_TEST(testModeChange); CPPUNIT_TEST(testTransformation); + CPPUNIT_TEST(testMainLoop); + CPPUNIT_TEST(testSave); CPPUNIT_TEST_SUITE_END(); public: @@ -24,6 +26,10 @@ public: void testTransformation(); + void testMainLoop(); + + void testSave(); + }; #endif //HFSTEST_H diff --git a/test/HFSTestMain.cpp b/test/HFSTestMain.cpp index e182bcd4ea50d80e3898bdd06e24fcc48f438055..0702f02e9fd63f6fb5dc2ea148ca6794d073a4d5 100644 --- a/test/HFSTestMain.cpp +++ b/test/HFSTestMain.cpp @@ -1,22 +1,29 @@ #include <cppunit/CompilerOutputter.h> #include <cppunit/extensions/TestFactoryRegistry.h> #include <cppunit/ui/text/TestRunner.h> -//#include "HFSTest.hpp" +#include "HFSTest.hpp" +#include "DetectorFeatureTest.hpp" +#include "UtilityTest.hpp" +#include "FCUTest.hpp" int main(int argc, char* argv[]) { - // Get the top level suite from the registry - CppUnit::Test *suite = CppUnit::TestFactoryRegistry::getRegistry().makeTest(); + // Get the top level suite from the registry - // Adds the test to the list of test to run - CppUnit::TextUi::TestRunner runner; - runner.addTest(suite); + // Adds the test to the list of test to run + CppUnit::TextUi::TestRunner runner; + runner.addTest(HFSTest::suite()); + runner.addTest(DetectorFeaturesTest::suite()); + runner.addTest(UtilityTest::suite()); + runner.addTest(FCUTest::suite()); - // Change the default outputter to a compiler error format outputter - runner.setOutputter( new CppUnit::CompilerOutputter(&runner.result(), std::cerr)); - // Run the tests. - bool wasSucessful = runner.run(); + + // Change the default outputter to a compiler error format outputter + runner.setOutputter( new CppUnit::CompilerOutputter(&runner.result(), std::cerr)); + + // Run the tests. + bool wasSucessful = runner.run(); - // Return error code 1 if the one of test failed. - return wasSucessful ? 0 : 1; + // Return error code 1 if the one of test failed. + return wasSucessful ? 0 : 1; } diff --git a/test/HFS_config_test.xml b/test/HFS_config_test.xml index 32301e0980403feb441bf82d0f0aa662e94ba18d..ce7ebb6aeead439d2ccd32f8543fecc1f947b0a3 100644 --- a/test/HFS_config_test.xml +++ b/test/HFS_config_test.xml @@ -24,7 +24,7 @@ <!-- Fixed bias value that is included in the final image. --> <bias>2000.0</bias> - <!-- The mean read noise of a pixel in ADU per second. --> + <!-- The mean read noise of a pixel in ADU. --> <readout_noise>20.0</readout_noise> <!-- The mean bkgr noise in photons per second. --> @@ -47,10 +47,19 @@ <median_filter_threshold>1000</median_filter_threshold> <!-- Standard deviation of the centroid error induced by the spacecraft - jitter during the integration period in mas. This will be replaced - by a jitter model from power-spectra in future versions --> + jitter during the integration period in mas. --> <jitter_error_std>5.0</jitter_error_std> + <!-- Duration of the simulated FCU reset in s --> + <reset_duration>0.5</reset_duration> + + <!-- State variable denoting end of ongoing reset, Default: 0--> + <reset_end>0</reset_end> + + <!-- Tolerance for the timing related checks for centroid generation, rerset + and transitions, Default: 0.005--> + <timing_tolerance>0.0</timing_tolerance> + <!-- relative path of the Psf input files. The psfs are given as 40x40px arrays that are stored in the C array format --> @@ -62,7 +71,7 @@ <FGS1_PS>175.0</FGS1_PS> <!-- Plate scale of FGS2 in mas/px, Default: 136 --> - <FGS2_PS>137.1</FGS2_PS> + <FGS2_PS>137.0</FGS2_PS> <!-- Focal length of FGS1 in m, Default: 21.21 --> <FGS1_FL>21.21</FGS1_FL> @@ -79,6 +88,7 @@ <!-- Angular missalignment of the FGS channels from the optical axis in the the detector plane in mas, No default values available --> <FGS1_Offset_X>0</FGS1_Offset_X> <FGS1_Offset_Y>0</FGS1_Offset_Y> + <FGS2_Offset_X>0</FGS2_Offset_X> <FGS2_Offset_Y>0</FGS2_Offset_Y> @@ -95,22 +105,26 @@ <!-- FWHM of the gaussian used as a weighting function in the centroid calculation in px. Default: FGS1: x = 16, y = 15; FGS2: x = 11, y = 14 --> - <FWHM_FGS1_x>16</FWHM_FGS1_x> - <FWHM_FGS1_y>15</FWHM_FGS1_y> - <FWHM_FGS2_x>11</FWHM_FGS2_x> - <FWHM_FGS2_y>14</FWHM_FGS2_y> + <FWHM_FGS1_x>5</FWHM_FGS1_x> + <FWHM_FGS1_y>5</FWHM_FGS1_y> + <FWHM_FGS2_x>6</FWHM_FGS2_x> + <FWHM_FGS2_y>6</FWHM_FGS2_y> <!-- Time delay causes by the mode switch in s. --> <transition_delay>0.5</transition_delay> + <!-- End time of an ongoing transition. Used for State saving. 0 denotes no transition. Default: 0 + --> + <transition_end>0</transition_end> + <!-- Target signal in ADU per second used for validation --> - <target_signal>60000</target_signal> + <target_signal>80000</target_signal> <!-- lower signal limit ("There is a signal" check) for centroid validation in % of target signal. defalt 1%--> <lower_signal_limit>1.0</lower_signal_limit> <!-- Sigma threshold in ADU used in the validation procedure --> - <validation_sigma>20</validation_sigma> + <validation_sigma>10</validation_sigma> <!-- Threshold for the Pearson correlation used as the validity index. Index can range from -1 to 1. A value of 0.5 to 0.6 serves as a @@ -148,7 +162,7 @@ <!-- Exposure time for mode Acquisition in s, default: 0.5 --> <exposure_time>0.5</exposure_time> <!-- Brightness tolerance for target identification default is 20% --> - <tolerance>50</tolerance> + <tolerance>20</tolerance> <!-- Dimensiton of the Acquisition window for FGS1, default: 128px --> <FGS1_dim>128</FGS1_dim> <!-- Dimensiton of the Acquisition window for FGS2, default: 161px --> diff --git a/test/UtilityTest.cpp b/test/UtilityTest.cpp new file mode 100644 index 0000000000000000000000000000000000000000..7521ce78fc96aea9c0195efb255d098eee24c2b9 --- /dev/null +++ b/test/UtilityTest.cpp @@ -0,0 +1,222 @@ +#include <cppunit/config/SourcePrefix.h> +#include "../src/utilities.h" +#include "UtilityTest.hpp" +#include <iostream> +#include <stdio.h> +#include <stdlib.h> +#include <experimental/filesystem> +#include <math.h> + +CPPUNIT_TEST_SUITE_REGISTRATION(UtilityTest); + +void UtilityTest::setUp() +{ +} + +void UtilityTest::tearDown() +{ +} + +void UtilityTest::testPoisson() +{ + double array[200*200]; + unsigned int i; + double mean; + + for(i = 0; i < 200*200; i++){ + array[i] = 0.0; + } + + random_poisson_trm(array, 10., 200*200); + mean = 0.; + + for(i = 0; i < 200*200; i++){ + mean = mean + array[i]; + } + + mean = mean / (200*200); + + std::cout << "Check if array has been populated with values.\n"; + CPPUNIT_ASSERT(mean != 0.0); +} + +void UtilityTest::testNormal() +{ + double array[200*200]; + unsigned int i; + double mean; + + for(i = 0; i < 200*200; i++){ + array[i] = 0.0; + } + + random_normal_trm(array, 10., 2.5, 200*200); + mean = 0.; + + for(i = 0; i < 200*200; i++){ + mean = mean + array[i]; + } + + mean = mean / (200*200); + + std::cout << "Check if array has been populated with values.\n"; + CPPUNIT_ASSERT(mean != 0.0); + + std::cout << "Check if mean is within margin.\n"; + CPPUNIT_ASSERT(mean > 9.5); + CPPUNIT_ASSERT(mean < 10.5); +} + +void UtilityTest::testUpsampling() +{ + double array[200*200], upArray[1000*1000]; + unsigned int i; + double sum, sumUp; + + for(i = 0; i < 200*200; i++){ + array[i] = 0.0; + } + + for(i = 0; i < 1000*1000; i++){ + upArray[i] = 0.0; + } + + array[0] = 10.0; + + upsample_image(array, upArray, 200, 200, 1000, 1000, 5, 0); + + std::cout << "Check if array has been upsampled.\n"; + for(i = 0; i < 5; i++){ + CPPUNIT_ASSERT(upArray[i] != 0); + } + + sum = 0.0; + sumUp = 0.0; + for(i = 0; i > 1000*1000; i++){ + if(i < 200*200){ + sum = sum + array[i]; + } + sumUp = sumUp + upArray[i]; + } + + std::cout << "Check sum off upsampled array without copy.\n"; + CPPUNIT_ASSERT_DOUBLES_EQUAL(sum, sumUp, 0.0001); + + for(i = 0; i < 1000*1000; i++){ + upArray[i] = 0.0; + } + + upsample_image(array, upArray, 200, 200, 1000, 1000, 5, 1); + sum = 0.0; + sumUp = 0.0; + for(i = 0; i > 1000*1000; i++){ + if(i < 200*200){ + sum = sum + array[i]; + } + sumUp = sumUp + upArray[i]; + } + + std::cout << "Check sum off upsampled array with copy.\n"; + CPPUNIT_ASSERT_DOUBLES_EQUAL(sum * 25, sumUp, 0.0001); + +} + +void UtilityTest::testDownsampling() +{ + double array[1000*1000], dsArray[200*200]; + unsigned int i; + double sum, sumDown; + + for(i = 0; i < 1000*1000; i++){ + array[i] = 0.0; + } + + for(i = 0; i < 200*200; i++){ + dsArray[i] = 0.0; + } + + for(i = 0; i < 5; i++){ + array[i] = 10.; + } + + downsample_image(array, dsArray, 1000, 1000, 5); + + std::cout << "Check if array has been downsampled.\n"; + CPPUNIT_ASSERT(dsArray[0] != 0); + CPPUNIT_ASSERT_DOUBLES_EQUAL(dsArray[1], 0.0, 0.0001); + sum = 0.0; + sumDown = 0.0; + for(i = 0; i > 1000*1000; i++){ + if(i < 200*200){ + sumDown = sumDown + dsArray[i]; + } + sum = sum + array[i]; + } + + std::cout << "Check sum off upsampled array without copy.\n"; + CPPUNIT_ASSERT_DOUBLES_EQUAL(sum, sumDown, 0.0001); + for(i = 0; i < 1000*1000; i++){ + array[i] = 0.0; + } + + downsample_image(array, dsArray, 1000, 1000, 5); + std::cout << "Check for division by zero error.\n"; + + for(i = 0; i < 200*200; i++){ + CPPUNIT_ASSERT_DOUBLES_EQUAL(dsArray[0], 0, 0.0001); + } +} + +void UtilityTest::testMatrixOp() +{ + double x[3] = {1., 0., 0.}; + double y[3] = {0., 1., 0.}; + double mxData[9] = {1. ,0., 0., 0., 1., 0., 0., 0., 1.}; + double resData[3]; + struct dmatrix inMatrix1, inMatrix2, resMatrix; + double resVec[3]; + double res; + int flag; + + std::cout << "Check Dot Product.\n"; + res = dot(x, y, 3); + + CPPUNIT_ASSERT_DOUBLES_EQUAL(res, 0.0, 0.0001); + + res = dot(x, x, 3); + + CPPUNIT_ASSERT_DOUBLES_EQUAL(res, 1.0, 0.0001); + + std::cout << "Check Cross Product.\n"; + + cross3(x, y, resVec); + + CPPUNIT_ASSERT_DOUBLES_EQUAL(resVec[0], 0.0, 0.0001); + CPPUNIT_ASSERT_DOUBLES_EQUAL(resVec[1], 0.0, 0.0001); + CPPUNIT_ASSERT_DOUBLES_EQUAL(resVec[2], 1.0, 0.0001); + + inMatrix1.data = mxData; + inMatrix1.xdim = 3; + inMatrix1.ydim = 3; + + inMatrix2.data = x; + inMatrix2.xdim = 1; + inMatrix2.ydim = 3; + + resMatrix.data = resData; + + + std::cout << "Check Matrix Multiplication.\n"; + flag = dmatmult(inMatrix1, inMatrix2, &resMatrix); + + CPPUNIT_ASSERT(flag == 0); + CPPUNIT_ASSERT_DOUBLES_EQUAL(resMatrix.data[0], 1.0, 0.0001); + CPPUNIT_ASSERT_DOUBLES_EQUAL(resMatrix.data[1], 0.0, 0.0001); + CPPUNIT_ASSERT_DOUBLES_EQUAL(resMatrix.data[2], 0.0, 0.0001); + + inMatrix2.ydim = 4; + flag = dmatmult(inMatrix1, inMatrix2, &resMatrix); + + CPPUNIT_ASSERT(flag == -1); + +} diff --git a/test/UtilityTest.hpp b/test/UtilityTest.hpp new file mode 100644 index 0000000000000000000000000000000000000000..2e4b853b881c74d71b9502dceec2009494005438 --- /dev/null +++ b/test/UtilityTest.hpp @@ -0,0 +1,30 @@ +#ifndef UTILITYTEST_H +#define UTILITYTEST_H +#include <cppunit/TestCase.h> +#include <cppunit/extensions/HelperMacros.h> + +class UtilityTest : public CppUnit::TestFixture +{ + CPPUNIT_TEST_SUITE(UtilityTest); + CPPUNIT_TEST(testPoisson); + CPPUNIT_TEST(testNormal); + CPPUNIT_TEST(testUpsampling); + CPPUNIT_TEST(testDownsampling); + CPPUNIT_TEST(testMatrixOp); + CPPUNIT_TEST_SUITE_END(); + +public: + + + void setUp(); + void tearDown(); + + void testPoisson(); + void testNormal(); + void testUpsampling(); + void testDownsampling(); + void testMatrixOp(); + + }; + +#endif //UTILITYTEST_H diff --git a/test/acquisitionTest.txt b/test/acquisitionTest.txt new file mode 100644 index 0000000000000000000000000000000000000000..3fa3feed83e5bb56bf9f59f56fbed9d8a68bcc5c --- /dev/null +++ b/test/acquisitionTest.txt @@ -0,0 +1,40000 @@ +39 +75 +48 +47 +0 +0 +76 +36 +42 +59 +41 +47 +37 +47 +22 +38 +89 +51 +50 +41 +74 +49 +84 +55 +17 +34 +79 +60 +39 +65 +81 +52 +71 +46 +1 +70 +32 +21 +11 +67 +51 +34 +66 +26 +34 +21 +18 +13 +51 +38 +79 +48 +54 +46 +37 +49 +75 +35 +54 +4 +62 +24 +62 +62 +44 +43 +36 +63 +24 +36 +31 +34 +65 +24 +40 +56 +87 +49 +11 +7 +39 +56 +49 +49 +45 +15 +41 +38 +37 +1 +24 +55 +30 +86 +33 +69 +0 +37 +55 +41 +7 +58 +28 +2 +22 +53 +66 +31 +35 +43 +45 +39 +3 +81 +1 +50 +74 +61 +55 +43 +15 +57 +45 +55 +49 +59 +76 +25 +20 +1 +14 +29 +10 +38 +68 +50 +10 +11 +43 +69 +69 +36 +54 +84 +80 +0 +36 +15 +53 +46 +52 +6 +11 +53 +45 +28 +73 +53 +40 +48 +40 +50 +68 +71 +35 +25 +64 +56 +56 +19 +63 +66 +87 +48 +89 +59 +23 +72 +38 +59 +72 +4 +24 +62 +68 +47 +69 +31 +18 +44 +52 +45 +66 +26 +40 +17 +39 +69 +32 +46 +50 +73 +41 +60 +9 +48 +67 +37 +35 +52 +77 +25 +25 +41 +45 +56 +54 +30 +62 +40 +58 +51 +67 +16 +73 +40 +58 +18 +37 +47 +68 +68 +23 +51 +6 +72 +46 +71 +81 +39 +35 +39 +50 +17 +87 +28 +64 +53 +71 +52 +25 +83 +41 +40 +34 +49 +40 +61 +31 +72 +87 +46 +36 +40 +40 +37 +61 +15 +57 +55 +61 +30 +55 +37 +15 +51 +65 +43 +23 +35 +61 +53 +47 +22 +21 +14 +69 +29 +55 +53 +24 +44 +88 +38 +62 +74 +69 +25 +3 +28 +46 +12 +61 +25 +40 +69 +1 +8 +62 +33 +56 +11 +48 +42 +0 +46 +56 +65 +39 +66 +89 +53 +46 +15 +0 +36 +29 +56 +41 +84 +67 +36 +43 +40 +89 +39 +46 +38 +26 +16 +17 +29 +70 +78 +66 +3 +87 +27 +47 +38 +76 +51 +46 +73 +66 +26 +73 +49 +45 +25 +70 +52 +52 +46 +42 +22 +59 +37 +11 +44 +75 +21 +49 +87 +33 +41 +0 +1 +17 +64 +21 +31 +51 +39 +4 +32 +33 +70 +29 +59 +56 +32 +16 +45 +49 +45 +15 +5 +89 +36 +89 +7 +41 +56 +50 +78 +50 +19 +40 +57 +37 +59 +21 +35 +31 +65 +15 +33 +45 +57 +77 +80 +36 +80 +57 +57 +44 +57 +46 +44 +36 +16 +33 +42 +22 +41 +41 +58 +31 +63 +21 +50 +68 +73 +79 +36 +54 +50 +43 +36 +53 +42 +20 +65 +58 +84 +62 +41 +69 +46 +8 +27 +0 +56 +69 +72 +82 +37 +49 +53 +54 +62 +19 +58 +9 +38 +21 +27 +33 +50 +59 +50 +57 +40 +33 +8 +66 +64 +26 +50 +51 +26 +44 +44 +58 +43 +40 +50 +16 +29 +44 +22 +53 +41 +69 +39 +78 +22 +59 +35 +34 +61 +42 +72 +81 +66 +18 +24 +31 +25 +71 +53 +51 +6 +33 +11 +35 +56 +31 +14 +43 +34 +85 +43 +18 +51 +70 +33 +1 +51 +48 +53 +51 +72 +48 +28 +63 +64 +37 +72 +51 +52 +8 +38 +76 +29 +65 +0 +33 +32 +71 +22 +34 +46 +36 +36 +53 +8 +19 +58 +33 +52 +85 +25 +49 +28 +57 +36 +34 +16 +89 +80 +57 +63 +44 +50 +47 +50 +87 +15 +55 +36 +31 +36 +35 +61 +18 +32 +54 +69 +39 +69 +12 +87 +22 +77 +36 +53 +52 +75 +86 +34 +46 +38 +45 +27 +29 +89 +37 +66 +43 +28 +55 +24 +21 +22 +57 +64 +19 +51 +52 +62 +85 +65 +51 +23 +79 +45 +32 +40 +17 +18 +19 +87 +75 +61 +46 +54 +67 +54 +27 +68 +45 +27 +13 +40 +54 +35 +53 +38 +32 +51 +43 +10 +68 +57 +41 +87 +36 +38 +0 +43 +55 +19 +30 +42 +64 +32 +45 +60 +58 +60 +29 +87 +50 +42 +65 +35 +39 +20 +14 +66 +25 +24 +11 +51 +0 +62 +1 +33 +28 +51 +64 +48 +37 +58 +1 +65 +53 +32 +43 +42 +0 +71 +0 +53 +54 +69 +54 +60 +56 +50 +25 +15 +23 +50 +18 +66 +51 +12 +40 +25 +46 +68 +77 +42 +3 +57 +46 +48 +37 +51 +27 +21 +36 +30 +24 +9 +45 +42 +8 +53 +68 +87 +0 +32 +62 +62 +57 +52 +48 +68 +61 +20 +39 +56 +52 +32 +17 +34 +80 +39 +9 +21 +25 +53 +70 +42 +14 +57 +88 +39 +66 +74 +75 +40 +81 +52 +57 +54 +47 +43 +53 +63 +16 +29 +18 +26 +22 +37 +78 +1 +33 +36 +59 +0 +87 +34 +32 +66 +34 +54 +40 +12 +59 +22 +69 +14 +4 +6 +9 +37 +17 +5 +68 +35 +62 +10 +68 +64 +68 +33 +36 +61 +42 +58 +59 +47 +71 +62 +52 +24 +0 +75 +82 +64 +54 +39 +19 +24 +50 +34 +28 +9 +12 +28 +22 +52 +31 +66 +53 +53 +78 +78 +18 +69 +37 +30 +48 +66 +14 +38 +20 +30 +72 +66 +56 +88 +13 +51 +34 +87 +14 +43 +53 +38 +52 +76 +13 +17 +74 +59 +17 +59 +49 +62 +35 +42 +70 +71 +63 +41 +25 +15 +0 +15 +48 +57 +83 +37 +24 +17 +39 +64 +17 +18 +49 +47 +59 +49 +14 +65 +50 +90 +51 +48 +37 +54 +75 +37 +44 +34 +29 +79 +22 +15 +49 +52 +21 +48 +29 +70 +19 +71 +22 +52 +47 +0 +67 +16 +25 +34 +79 +61 +15 +6 +25 +31 +14 +49 +76 +29 +26 +49 +38 +79 +80 +46 +67 +81 +33 +36 +23 +59 +20 +87 +2 +17 +29 +58 +62 +35 +39 +39 +14 +56 +63 +49 +65 +13 +1 +48 +48 +70 +11 +65 +32 +38 +25 +31 +36 +40 +36 +31 +67 +82 +27 +46 +46 +36 +56 +53 +41 +19 +46 +15 +69 +53 +35 +42 +74 +62 +60 +23 +79 +24 +66 +48 +54 +45 +54 +12 +48 +70 +82 +34 +9 +47 +31 +45 +51 +61 +65 +55 +20 +49 +17 +47 +36 +48 +49 +18 +32 +57 +60 +30 +76 +48 +64 +49 +67 +62 +34 +7 +46 +23 +28 +27 +54 +57 +82 +51 +57 +68 +71 +3 +54 +88 +54 +23 +63 +1 +68 +18 +63 +66 +71 +45 +29 +71 +88 +69 +56 +42 +48 +22 +23 +69 +62 +35 +36 +50 +36 +29 +51 +71 +49 +51 +15 +58 +58 +32 +43 +63 +42 +25 +67 +44 +45 +63 +48 +51 +51 +51 +44 +58 +35 +52 +2 +41 +58 +11 +9 +63 +28 +50 +69 +0 +54 +44 +18 +25 +66 +54 +71 +80 +68 +84 +65 +69 +49 +45 +87 +78 +66 +33 +9 +32 +38 +42 +75 +21 +49 +24 +75 +58 +62 +6 +6 +47 +61 +44 +58 +58 +32 +26 +33 +37 +31 +62 +33 +69 +25 +44 +50 +33 +56 +27 +69 +45 +25 +41 +13 +63 +40 +80 +44 +25 +57 +36 +31 +73 +58 +51 +48 +44 +47 +37 +39 +48 +19 +47 +39 +44 +68 +69 +58 +55 +68 +61 +72 +49 +24 +57 +48 +7 +68 +60 +87 +49 +41 +23 +32 +19 +22 +36 +38 +84 +31 +35 +57 +55 +73 +48 +1 +56 +56 +71 +43 +15 +26 +27 +21 +42 +59 +32 +22 +45 +39 +29 +9 +35 +35 +20 +40 +72 +32 +40 +52 +29 +60 +0 +0 +6 +41 +32 +70 +76 +26 +80 +57 +32 +9 +44 +54 +42 +42 +35 +43 +71 +52 +41 +28 +32 +26 +61 +18 +61 +15 +54 +67 +52 +31 +25 +68 +31 +82 +26 +65 +33 +25 +63 +50 +35 +57 +67 +64 +41 +25 +25 +28 +55 +61 +73 +28 +40 +30 +66 +34 +51 +45 +34 +67 +48 +65 +36 +25 +47 +63 +34 +57 +86 +13 +39 +47 +5 +61 +37 +65 +44 +10 +65 +78 +14 +7 +85 +89 +39 +76 +32 +52 +60 +40 +19 +41 +51 +26 +28 +41 +59 +68 +58 +48 +59 +15 +35 +60 +89 +37 +72 +81 +44 +42 +51 +0 +25 +36 +51 +41 +31 +68 +17 +58 +89 +81 +43 +32 +67 +76 +47 +37 +70 +58 +50 +52 +58 +28 +32 +48 +48 +42 +12 +35 +30 +55 +65 +39 +42 +38 +42 +63 +82 +89 +15 +13 +69 +90 +34 +24 +43 +8 +31 +6 +69 +82 +34 +2 +50 +1 +67 +46 +75 +64 +37 +7 +73 +72 +55 +65 +82 +36 +68 +32 +59 +36 +58 +57 +38 +59 +47 +51 +41 +10 +19 +37 +34 +84 +55 +43 +45 +64 +25 +38 +60 +2 +73 +53 +57 +39 +30 +60 +51 +17 +30 +47 +36 +47 +33 +83 +74 +67 +80 +59 +66 +46 +27 +58 +22 +68 +22 +26 +35 +56 +29 +53 +13 +25 +67 +26 +66 +26 +29 +65 +50 +23 +68 +47 +44 +62 +19 +49 +27 +50 +55 +18 +49 +66 +37 +35 +67 +57 +60 +80 +59 +34 +40 +9 +1 +25 +81 +65 +43 +27 +75 +35 +33 +27 +72 +44 +8 +32 +49 +57 +63 +43 +34 +76 +76 +22 +80 +35 +30 +41 +50 +56 +32 +39 +53 +53 +62 +53 +51 +53 +46 +41 +18 +52 +0 +64 +88 +34 +59 +44 +88 +40 +59 +35 +33 +65 +28 +33 +34 +8 +37 +53 +38 +58 +59 +55 +77 +52 +64 +52 +76 +47 +39 +13 +31 +53 +72 +47 +50 +62 +68 +48 +0 +47 +49 +59 +55 +64 +10 +1 +25 +56 +20 +51 +3 +27 +1 +60 +55 +74 +59 +57 +66 +57 +48 +32 +30 +22 +64 +46 +33 +27 +42 +48 +71 +27 +38 +20 +69 +38 +33 +28 +34 +17 +68 +50 +30 +32 +53 +75 +7 +65 +78 +67 +23 +43 +36 +60 +61 +63 +36 +77 +66 +39 +59 +41 +87 +59 +62 +65 +89 +85 +44 +30 +27 +46 +38 +48 +53 +34 +46 +79 +68 +72 +17 +70 +27 +38 +47 +63 +74 +55 +65 +34 +47 +33 +43 +62 +56 +55 +22 +24 +73 +57 +35 +39 +46 +55 +3 +39 +61 +41 +50 +22 +8 +78 +53 +55 +31 +52 +58 +45 +40 +20 +55 +49 +32 +62 +67 +65 +46 +11 +34 +28 +61 +72 +28 +67 +72 +47 +46 +85 +30 +8 +64 +10 +8 +11 +45 +35 +55 +8 +59 +23 +55 +60 +40 +30 +41 +50 +59 +23 +20 +31 +41 +37 +83 +9 +63 +83 +61 +77 +71 +60 +62 +83 +11 +22 +46 +67 +66 +62 +51 +67 +17 +18 +40 +53 +34 +87 +76 +52 +7 +40 +35 +16 +23 +21 +46 +19 +62 +45 +68 +24 +16 +51 +50 +5 +27 +63 +85 +36 +65 +50 +71 +87 +26 +49 +41 +33 +57 +63 +39 +44 +46 +3 +58 +61 +42 +38 +87 +36 +24 +42 +1 +33 +36 +64 +29 +36 +45 +14 +41 +42 +54 +30 +29 +28 +32 +15 +51 +40 +20 +60 +88 +18 +81 +0 +22 +24 +66 +43 +34 +18 +47 +60 +41 +49 +33 +54 +33 +63 +26 +14 +45 +67 +22 +68 +41 +58 +76 +61 +6 +37 +47 +50 +16 +14 +37 +59 +0 +55 +75 +41 +48 +12 +40 +52 +33 +50 +23 +42 +13 +52 +35 +35 +24 +45 +31 +30 +28 +49 +49 +44 +30 +48 +89 +22 +51 +56 +40 +56 +42 +41 +64 +7 +58 +22 +77 +9 +51 +77 +73 +33 +23 +48 +61 +48 +37 +32 +43 +51 +21 +24 +36 +54 +6 +15 +52 +50 +41 +8 +49 +65 +21 +42 +18 +63 +33 +88 +58 +37 +19 +47 +44 +48 +37 +32 +31 +55 +65 +49 +43 +85 +27 +48 +18 +47 +56 +38 +83 +35 +70 +18 +32 +46 +41 +37 +87 +56 +43 +36 +65 +87 +33 +36 +21 +71 +37 +33 +18 +38 +50 +56 +77 +21 +41 +46 +43 +61 +73 +36 +90 +72 +73 +53 +44 +60 +24 +30 +55 +7 +47 +23 +3 +27 +55 +80 +39 +47 +16 +87 +53 +50 +60 +47 +7 +64 +61 +80 +24 +50 +36 +54 +73 +43 +56 +42 +70 +67 +62 +81 +58 +17 +0 +22 +57 +48 +47 +26 +38 +40 +76 +59 +51 +38 +54 +67 +31 +40 +72 +31 +37 +74 +26 +62 +23 +46 +87 +47 +18 +28 +54 +89 +56 +54 +44 +53 +56 +42 +38 +51 +2 +43 +5 +77 +40 +16 +34 +28 +38 +15 +27 +65 +50 +37 +37 +39 +65 +43 +1 +0 +33 +68 +37 +44 +45 +26 +74 +23 +3 +41 +29 +27 +59 +29 +23 +41 +41 +44 +43 +10 +32 +44 +74 +60 +57 +71 +43 +62 +34 +66 +4 +65 +87 +38 +33 +65 +46 +11 +23 +28 +72 +62 +74 +61 +45 +10 +40 +48 +43 +88 +25 +44 +87 +63 +88 +65 +58 +45 +60 +24 +46 +53 +64 +47 +47 +66 +47 +54 +63 +17 +37 +59 +33 +39 +49 +81 +67 +28 +11 +37 +41 +27 +82 +33 +25 +31 +51 +87 +29 +54 +41 +36 +72 +61 +34 +38 +37 +25 +43 +84 +31 +54 +24 +55 +55 +70 +49 +47 +47 +76 +23 +51 +83 +8 +11 +74 +46 +26 +89 +53 +51 +83 +41 +63 +48 +12 +26 +71 +60 +60 +21 +34 +50 +73 +76 +73 +34 +75 +49 +39 +69 +30 +48 +36 +12 +67 +68 +52 +44 +11 +49 +54 +38 +49 +34 +0 +77 +69 +42 +38 +46 +81 +59 +53 +51 +31 +55 +63 +62 +54 +38 +4 +57 +5 +45 +47 +34 +17 +44 +51 +22 +41 +68 +30 +59 +41 +53 +87 +69 +48 +55 +43 +52 +9 +46 +30 +59 +35 +57 +27 +64 +5 +31 +86 +51 +67 +41 +40 +16 +41 +10 +36 +78 +45 +16 +5 +1 +82 +74 +38 +57 +54 +44 +53 +39 +38 +25 +87 +46 +40 +57 +66 +56 +34 +33 +35 +0 +38 +87 +4 +38 +62 +67 +90 +27 +29 +56 +47 +48 +43 +38 +89 +66 +43 +24 +34 +30 +38 +35 +43 +46 +29 +58 +14 +18 +47 +39 +30 +29 +5 +34 +48 +89 +16 +39 +33 +32 +10 +46 +80 +71 +44 +60 +53 +30 +8 +51 +48 +89 +71 +35 +59 +64 +4 +43 +63 +60 +84 +9 +16 +72 +69 +52 +18 +37 +33 +55 +11 +89 +18 +75 +61 +39 +16 +42 +45 +67 +75 +84 +41 +41 +31 +29 +42 +30 +65 +18 +60 +44 +15 +8 +90 +0 +20 +41 +0 +52 +27 +25 +62 +57 +18 +87 +55 +28 +37 +34 +29 +65 +36 +11 +40 +12 +13 +45 +32 +90 +89 +15 +66 +16 +0 +44 +61 +49 +13 +54 +42 +43 +47 +37 +49 +50 +10 +43 +66 +32 +40 +64 +59 +7 +64 +14 +79 +58 +9 +86 +41 +59 +48 +30 +47 +15 +67 +16 +76 +22 +47 +45 +54 +44 +10 +45 +56 +49 +31 +57 +33 +65 +34 +51 +31 +57 +9 +25 +12 +58 +86 +14 +45 +38 +1 +10 +17 +76 +0 +15 +50 +54 +53 +40 +73 +0 +43 +24 +19 +41 +65 +25 +23 +49 +31 +53 +43 +6 +43 +1 +63 +65 +38 +47 +59 +36 +44 +27 +32 +62 +37 +58 +14 +66 +1 +30 +61 +49 +53 +57 +0 +59 +89 +47 +7 +54 +72 +3 +60 +60 +77 +24 +46 +31 +88 +34 +87 +29 +80 +75 +89 +30 +36 +57 +67 +26 +36 +68 +46 +11 +39 +30 +73 +14 +64 +62 +40 +64 +57 +43 +7 +47 +49 +21 +26 +47 +24 +25 +61 +4 +72 +51 +41 +54 +89 +57 +46 +61 +16 +71 +21 +60 +38 +26 +33 +35 +52 +43 +30 +62 +50 +43 +10 +43 +61 +70 +77 +5 +6 +28 +29 +24 +23 +68 +1 +41 +40 +33 +42 +19 +51 +52 +45 +2 +76 +81 +53 +46 +20 +53 +54 +44 +62 +17 +64 +49 +29 +51 +56 +50 +69 +52 +45 +63 +0 +26 +28 +45 +47 +50 +60 +18 +45 +57 +5 +37 +25 +80 +10 +79 +64 +25 +64 +67 +79 +32 +36 +59 +25 +50 +41 +37 +46 +17 +43 +34 +58 +22 +58 +39 +29 +8 +75 +19 +30 +71 +55 +66 +71 +37 +18 +47 +61 +58 +16 +61 +81 +15 +56 +63 +39 +62 +1 +30 +55 +12 +75 +16 +37 +55 +49 +25 +87 +55 +8 +36 +28 +39 +45 +31 +30 +10 +54 +43 +67 +25 +45 +72 +31 +59 +54 +42 +53 +74 +16 +65 +48 +39 +20 +59 +22 +38 +75 +69 +19 +14 +52 +83 +26 +53 +87 +33 +25 +23 +30 +46 +59 +51 +1 +1 +36 +63 +72 +24 +54 +55 +37 +0 +33 +65 +57 +48 +83 +42 +40 +39 +19 +23 +67 +21 +38 +72 +77 +62 +39 +55 +21 +40 +40 +28 +90 +27 +34 +58 +44 +61 +35 +45 +63 +60 +38 +44 +49 +28 +34 +41 +79 +25 +41 +48 +46 +38 +40 +57 +57 +33 +50 +63 +15 +63 +67 +45 +64 +35 +59 +51 +9 +62 +75 +0 +35 +42 +50 +10 +19 +24 +24 +43 +73 +6 +52 +60 +54 +32 +5 +78 +55 +28 +60 +16 +25 +44 +19 +35 +43 +78 +55 +49 +37 +87 +42 +32 +62 +42 +44 +33 +42 +43 +46 +59 +35 +41 +62 +41 +23 +40 +58 +21 +55 +19 +10 +17 +18 +41 +41 +55 +51 +37 +42 +38 +30 +47 +20 +82 +56 +55 +31 +49 +22 +27 +45 +54 +35 +13 +54 +30 +7 +35 +15 +31 +63 +78 +19 +50 +40 +23 +38 +51 +70 +56 +65 +39 +60 +54 +60 +35 +50 +71 +44 +28 +15 +28 +76 +35 +69 +55 +56 +1 +58 +57 +65 +50 +14 +47 +26 +18 +56 +81 +27 +35 +68 +18 +50 +29 +68 +51 +13 +48 +58 +61 +57 +47 +47 +50 +52 +61 +56 +74 +22 +68 +43 +29 +32 +76 +29 +20 +57 +63 +51 +64 +73 +40 +35 +61 +80 +45 +26 +57 +47 +54 +62 +57 +31 +72 +43 +61 +89 +79 +23 +18 +56 +49 +10 +88 +65 +51 +63 +40 +63 +11 +69 +1 +1 +56 +49 +72 +20 +52 +78 +35 +44 +35 +3 +79 +62 +68 +76 +35 +51 +33 +46 +21 +46 +42 +30 +31 +7 +35 +77 +11 +19 +36 +39 +31 +35 +52 +0 +53 +33 +40 +0 +77 +44 +9 +71 +53 +60 +46 +36 +55 +56 +29 +18 +63 +59 +57 +36 +20 +56 +67 +72 +41 +18 +51 +83 +32 +34 +25 +48 +36 +64 +64 +71 +17 +69 +36 +56 +58 +33 +60 +29 +33 +17 +49 +5 +37 +34 +57 +27 +58 +58 +29 +51 +40 +52 +75 +0 +40 +71 +70 +9 +34 +27 +31 +44 +44 +47 +44 +35 +73 +41 +32 +51 +67 +52 +54 +79 +35 +57 +51 +31 +51 +8 +39 +2 +56 +55 +27 +21 +39 +48 +30 +42 +54 +55 +79 +57 +39 +49 +24 +50 +87 +58 +37 +75 +83 +22 +52 +47 +23 +14 +26 +62 +1 +18 +12 +47 +44 +76 +79 +13 +23 +69 +31 +20 +79 +30 +72 +62 +33 +29 +28 +46 +42 +64 +25 +52 +59 +58 +35 +35 +48 +78 +80 +58 +0 +41 +51 +26 +60 +47 +53 +7 +1 +15 +32 +76 +36 +37 +80 +37 +13 +45 +22 +53 +34 +45 +11 +47 +57 +76 +7 +31 +68 +30 +57 +41 +35 +16 +62 +49 +54 +50 +78 +0 +52 +77 +50 +34 +16 +77 +59 +51 +27 +46 +88 +30 +53 +35 +26 +30 +38 +83 +62 +14 +43 +10 +50 +28 +67 +20 +73 +28 +69 +60 +69 +77 +27 +53 +19 +59 +58 +4 +29 +49 +41 +26 +36 +11 +37 +35 +68 +8 +50 +35 +35 +61 +54 +26 +36 +28 +55 +55 +54 +44 +74 +26 +41 +44 +57 +23 +65 +21 +44 +34 +57 +50 +38 +87 +40 +48 +22 +31 +24 +35 +37 +14 +63 +43 +14 +44 +29 +43 +71 +33 +36 +57 +56 +86 +43 +58 +26 +63 +19 +27 +60 +26 +27 +36 +16 +55 +9 +19 +59 +43 +38 +48 +0 +1 +35 +38 +40 +70 +54 +68 +1 +28 +18 +46 +27 +30 +15 +40 +70 +37 +22 +56 +14 +45 +80 +42 +19 +15 +49 +36 +27 +76 +35 +23 +61 +17 +78 +23 +41 +17 +1 +61 +43 +41 +15 +79 +33 +36 +25 +76 +24 +43 +38 +21 +29 +46 +63 +66 +45 +61 +38 +54 +28 +85 +28 +41 +68 +45 +0 +19 +20 +14 +45 +6 +43 +22 +17 +32 +49 +33 +78 +50 +47 +76 +56 +25 +73 +51 +15 +18 +48 +67 +38 +0 +24 +47 +83 +51 +52 +76 +53 +52 +61 +68 +44 +26 +50 +54 +33 +60 +26 +24 +15 +59 +20 +48 +35 +50 +66 +76 +64 +4 +53 +42 +83 +62 +48 +64 +21 +47 +56 +52 +30 +44 +82 +50 +50 +25 +53 +26 +53 +62 +50 +56 +30 +64 +65 +58 +36 +32 +34 +78 +33 +56 +33 +69 +43 +37 +13 +15 +2 +35 +51 +48 +58 +32 +74 +70 +77 +57 +28 +5 +26 +29 +89 +48 +50 +46 +34 +55 +41 +52 +68 +31 +56 +16 +30 +34 +31 +58 +50 +69 +64 +39 +50 +50 +35 +72 +70 +13 +17 +58 +83 +57 +47 +52 +18 +55 +39 +29 +67 +74 +39 +34 +6 +57 +39 +29 +73 +33 +53 +11 +47 +60 +31 +14 +43 +19 +29 +38 +20 +53 +89 +29 +31 +58 +53 +36 +42 +43 +35 +75 +61 +30 +33 +7 +76 +53 +62 +57 +59 +43 +62 +33 +54 +49 +33 +12 +60 +45 +24 +50 +20 +79 +68 +28 +18 +72 +41 +11 +42 +50 +42 +40 +29 +36 +53 +54 +49 +32 +38 +2 +50 +2 +62 +38 +59 +34 +25 +18 +57 +22 +64 +42 +59 +27 +46 +27 +45 +42 +69 +21 +29 +48 +89 +35 +25 +55 +83 +39 +60 +41 +25 +49 +68 +29 +86 +49 +12 +70 +37 +89 +36 +51 +48 +64 +34 +0 +39 +30 +64 +67 +36 +39 +64 +15 +29 +69 +62 +76 +2 +33 +73 +58 +38 +45 +43 +45 +27 +47 +47 +59 +38 +56 +53 +28 +58 +81 +36 +57 +50 +36 +61 +30 +43 +24 +73 +58 +42 +90 +54 +51 +42 +17 +9 +51 +44 +33 +68 +66 +46 +57 +75 +43 +47 +3 +50 +28 +23 +87 +34 +54 +44 +45 +38 +73 +37 +4 +41 +80 +31 +82 +88 +64 +26 +7 +50 +36 +61 +40 +67 +24 +22 +68 +41 +8 +9 +39 +40 +33 +24 +0 +61 +21 +14 +80 +67 +63 +87 +37 +72 +74 +9 +21 +48 +30 +24 +49 +46 +15 +35 +82 +34 +32 +36 +53 +62 +15 +43 +67 +47 +21 +29 +19 +63 +51 +56 +48 +24 +87 +31 +25 +39 +44 +54 +63 +51 +45 +68 +77 +60 +33 +45 +19 +10 +37 +36 +74 +11 +0 +46 +90 +14 +77 +17 +25 +62 +41 +62 +45 +49 +64 +66 +33 +28 +44 +14 +39 +36 +53 +76 +42 +31 +32 +66 +53 +74 +42 +0 +45 +65 +81 +43 +72 +32 +35 +61 +35 +76 +27 +9 +87 +45 +33 +63 +35 +51 +21 +20 +18 +70 +51 +16 +45 +5 +34 +37 +48 +28 +71 +45 +25 +60 +25 +67 +55 +35 +47 +40 +83 +58 +65 +23 +33 +33 +78 +65 +40 +26 +51 +57 +31 +22 +0 +26 +54 +84 +39 +42 +41 +80 +3 +66 +56 +52 +44 +35 +17 +30 +22 +63 +30 +59 +64 +35 +56 +85 +18 +55 +53 +32 +61 +51 +31 +20 +20 +20 +51 +44 +47 +38 +1 +23 +27 +35 +25 +18 +57 +27 +44 +43 +20 +34 +37 +52 +4 +56 +64 +42 +87 +34 +50 +70 +36 +74 +22 +48 +37 +28 +44 +45 +50 +50 +53 +43 +79 +55 +67 +43 +30 +49 +47 +49 +37 +11 +57 +16 +34 +57 +39 +25 +36 +47 +62 +33 +23 +35 +43 +57 +74 +45 +14 +54 +39 +0 +64 +56 +27 +47 +82 +72 +26 +68 +14 +73 +55 +39 +52 +42 +51 +53 +27 +68 +85 +30 +51 +59 +35 +79 +35 +62 +53 +31 +63 +53 +65 +87 +44 +41 +38 +18 +73 +56 +24 +70 +59 +29 +23 +75 +10 +57 +57 +1 +50 +10 +36 +61 +55 +63 +43 +35 +38 +16 +51 +69 +55 +28 +40 +89 +46 +27 +19 +34 +28 +62 +85 +25 +1 +62 +1 +63 +45 +16 +36 +29 +82 +50 +69 +49 +32 +10 +21 +50 +56 +24 +51 +36 +12 +26 +39 +39 +3 +78 +11 +44 +68 +27 +16 +11 +67 +35 +40 +50 +34 +7 +79 +30 +31 +45 +71 +15 +42 +47 +17 +62 +61 +46 +60 +53 +38 +9 +75 +28 +24 +15 +61 +48 +53 +46 +20 +30 +34 +17 +68 +68 +44 +58 +80 +60 +55 +27 +61 +37 +54 +84 +51 +64 +72 +58 +18 +28 +18 +55 +62 +45 +42 +19 +38 +65 +60 +32 +41 +21 +31 +61 +25 +82 +29 +9 +67 +55 +51 +22 +59 +66 +25 +30 +38 +39 +56 +59 +60 +89 +44 +66 +25 +59 +41 +36 +48 +35 +16 +56 +55 +65 +50 +88 +63 +38 +36 +20 +70 +28 +88 +7 +42 +66 +57 +55 +40 +0 +74 +55 +31 +60 +0 +41 +39 +57 +9 +62 +60 +68 +43 +80 +7 +32 +57 +28 +38 +64 +39 +34 +1 +50 +80 +44 +25 +50 +58 +14 +87 +44 +49 +39 +31 +5 +61 +54 +33 +49 +53 +55 +59 +87 +14 +83 +61 +42 +68 +56 +89 +45 +74 +48 +65 +68 +60 +19 +51 +47 +19 +28 +57 +20 +45 +26 +46 +56 +44 +34 +41 +2 +83 +52 +23 +61 +31 +10 +22 +59 +46 +62 +34 +38 +55 +28 +1 +15 +64 +25 +55 +6 +26 +57 +7 +17 +80 +77 +18 +39 +29 +52 +33 +89 +46 +40 +64 +32 +61 +31 +35 +60 +87 +33 +15 +71 +43 +72 +39 +54 +17 +25 +21 +42 +39 +29 +55 +32 +14 +36 +5 +47 +25 +50 +31 +51 +47 +42 +67 +21 +31 +26 +62 +36 +38 +27 +30 +42 +85 +52 +62 +44 +16 +88 +18 +48 +75 +40 +29 +16 +56 +86 +22 +1 +67 +59 +82 +74 +0 +82 +61 +54 +52 +43 +14 +14 +57 +38 +49 +48 +24 +63 +54 +24 +55 +10 +49 +32 +52 +32 +62 +63 +20 +42 +24 +34 +47 +51 +46 +31 +42 +45 +40 +53 +58 +44 +23 +41 +62 +57 +30 +72 +60 +26 +33 +41 +23 +39 +18 +78 +43 +49 +30 +61 +77 +56 +25 +64 +41 +0 +43 +54 +30 +68 +59 +52 +55 +35 +43 +54 +29 +15 +64 +53 +82 +30 +89 +79 +50 +52 +36 +39 +60 +45 +57 +38 +56 +42 +63 +48 +69 +41 +68 +59 +49 +42 +31 +40 +41 +33 +29 +28 +52 +39 +34 +26 +7 +62 +44 +59 +72 +60 +70 +72 +60 +54 +31 +42 +22 +36 +61 +31 +28 +24 +50 +25 +65 +71 +25 +22 +56 +39 +26 +62 +78 +32 +62 +19 +43 +53 +9 +1 +34 +37 +42 +52 +8 +46 +60 +3 +65 +0 +21 +36 +50 +71 +61 +46 +31 +81 +59 +49 +45 +25 +15 +41 +39 +30 +56 +52 +37 +43 +26 +36 +35 +31 +34 +50 +58 +79 +12 +67 +37 +25 +31 +23 +87 +38 +48 +45 +67 +22 +55 +58 +80 +49 +87 +67 +24 +76 +16 +36 +52 +24 +29 +67 +15 +0 +58 +57 +67 +58 +78 +40 +18 +45 +41 +57 +86 +35 +63 +57 +74 +39 +32 +54 +36 +85 +65 +40 +31 +13 +13 +77 +62 +79 +51 +34 +78 +51 +50 +38 +21 +24 +52 +38 +82 +24 +31 +52 +16 +53 +61 +20 +35 +20 +60 +38 +23 +48 +44 +19 +1 +65 +50 +14 +48 +44 +60 +59 +45 +61 +61 +43 +38 +36 +37 +21 +34 +67 +54 +60 +33 +38 +73 +77 +14 +57 +40 +40 +53 +30 +87 +50 +63 +45 +42 +26 +41 +4 +31 +87 +76 +55 +56 +69 +70 +15 +44 +65 +73 +17 +56 +41 +49 +52 +44 +89 +28 +40 +45 +74 +32 +59 +1 +51 +29 +51 +19 +12 +31 +50 +36 +32 +70 +24 +60 +65 +61 +0 +32 +56 +60 +36 +54 +1 +38 +45 +12 +24 +50 +54 +61 +53 +63 +45 +46 +39 +47 +60 +58 +75 +38 +16 +69 +42 +67 +45 +8 +77 +48 +22 +21 +40 +47 +41 +63 +59 +24 +43 +70 +28 +20 +12 +17 +61 +51 +45 +43 +87 +56 +66 +61 +72 +77 +40 +53 +47 +59 +51 +58 +25 +87 +50 +42 +36 +47 +28 +43 +58 +67 +51 +47 +78 +67 +69 +60 +62 +21 +35 +31 +57 +70 +36 +10 +69 +10 +71 +20 +54 +77 +56 +14 +59 +57 +25 +24 +42 +75 +14 +52 +75 +59 +62 +39 +13 +36 +90 +55 +52 +68 +57 +35 +13 +44 +37 +58 +25 +34 +41 +45 +33 +86 +43 +65 +24 +42 +33 +62 +88 +14 +31 +4 +0 +27 +64 +83 +14 +20 +31 +27 +24 +23 +5 +58 +49 +89 +39 +58 +27 +30 +12 +50 +68 +33 +24 +33 +28 +33 +39 +44 +44 +80 +53 +22 +26 +79 +16 +42 +55 +71 +56 +28 +66 +56 +52 +2 +41 +33 +38 +18 +62 +29 +38 +46 +45 +60 +45 +73 +59 +58 +56 +59 +58 +18 +34 +89 +41 +36 +11 +57 +56 +72 +57 +87 +74 +73 +20 +44 +38 +41 +53 +3 +62 +89 +48 +72 +48 +56 +82 +78 +43 +7 +39 +72 +59 +17 +51 +42 +65 +42 +44 +87 +61 +61 +40 +30 +53 +39 +41 +62 +77 +33 +73 +54 +51 +15 +36 +13 +32 +69 +72 +14 +52 +44 +56 +62 +6 +33 +77 +58 +40 +16 +58 +48 +43 +23 +79 +56 +71 +25 +60 +55 +40 +87 +30 +31 +19 +89 +24 +40 +27 +55 +50 +24 +8 +58 +42 +43 +27 +39 +67 +50 +37 +39 +36 +31 +31 +62 +44 +28 +72 +54 +57 +35 +52 +33 +0 +18 +25 +65 +45 +25 +50 +70 +44 +45 +42 +15 +65 +32 +10 +29 +89 +74 +39 +36 +51 +0 +36 +48 +36 +79 +14 +53 +41 +49 +5 +49 +48 +61 +33 +82 +26 +72 +56 +30 +55 +48 +35 +64 +61 +72 +31 +50 +20 +83 +30 +79 +30 +57 +28 +30 +49 +52 +77 +35 +34 +9 +54 +52 +21 +16 +27 +48 +38 +64 +20 +48 +66 +1 +59 +71 +0 +51 +0 +41 +38 +62 +72 +69 +30 +64 +30 +25 +23 +45 +63 +39 +40 +63 +87 +76 +34 +56 +35 +39 +59 +18 +64 +0 +53 +68 +48 +6 +83 +39 +18 +58 +21 +75 +35 +35 +5 +66 +83 +39 +41 +73 +24 +65 +36 +47 +42 +36 +44 +76 +63 +74 +25 +43 +57 +89 +22 +9 +4 +36 +43 +5 +64 +27 +39 +54 +23 +33 +89 +47 +37 +66 +2 +12 +1 +19 +28 +55 +28 +29 +63 +89 +19 +50 +68 +57 +44 +28 +29 +41 +52 +25 +54 +62 +59 +25 +52 +36 +18 +65 +47 +54 +27 +43 +1 +11 +70 +31 +14 +50 +73 +49 +30 +11 +27 +45 +52 +37 +22 +60 +49 +61 +35 +39 +32 +70 +61 +78 +40 +15 +34 +62 +15 +54 +38 +74 +51 +50 +67 +55 +33 +41 +70 +31 +58 +43 +72 +23 +52 +21 +58 +65 +90 +37 +50 +14 +0 +87 +33 +17 +55 +6 +46 +31 +84 +50 +32 +27 +34 +38 +61 +60 +44 +23 +4 +48 +15 +55 +33 +30 +30 +8 +46 +75 +88 +73 +10 +56 +1 +47 +45 +32 +41 +83 +40 +47 +56 +73 +39 +41 +35 +34 +46 +38 +67 +58 +28 +72 +45 +0 +44 +89 +56 +23 +40 +40 +47 +1 +18 +53 +89 +37 +3 +41 +40 +25 +10 +17 +50 +46 +46 +80 +18 +51 +28 +63 +73 +6 +43 +13 +43 +61 +29 +51 +39 +38 +12 +58 +50 +3 +34 +34 +37 +27 +37 +32 +89 +85 +38 +70 +73 +33 +24 +29 +33 +52 +45 +66 +47 +16 +0 +21 +9 +52 +54 +57 +27 +55 +15 +56 +26 +34 +30 +27 +47 +55 +72 +5 +55 +39 +45 +84 +73 +40 +37 +63 +45 +51 +23 +53 +64 +44 +65 +85 +39 +21 +23 +40 +32 +87 +47 +28 +41 +83 +33 +39 +57 +40 +46 +53 +66 +84 +26 +17 +63 +35 +87 +35 +21 +62 +53 +21 +60 +45 +3 +65 +67 +42 +26 +66 +59 +76 +31 +19 +42 +64 +34 +70 +90 +37 +78 +46 +44 +24 +62 +46 +44 +60 +46 +35 +67 +35 +32 +57 +64 +38 +32 +36 +51 +47 +67 +36 +38 +47 +33 +37 +31 +60 +61 +30 +49 +67 +27 +51 +29 +37 +49 +34 +23 +17 +51 +69 +66 +64 +25 +23 +42 +31 +24 +18 +8 +30 +34 +37 +60 +46 +65 +31 +11 +40 +24 +60 +46 +17 +29 +89 +69 +74 +88 +31 +25 +71 +49 +35 +0 +64 +39 +35 +87 +43 +84 +51 +65 +47 +63 +37 +33 +50 +27 +0 +2 +51 +15 +46 +40 +23 +4 +1 +1 +19 +58 +18 +48 +41 +53 +46 +47 +28 +71 +22 +37 +57 +56 +30 +54 +38 +45 +70 +22 +9 +65 +68 +50 +51 +10 +29 +2 +39 +36 +42 +0 +26 +49 +61 +82 +35 +28 +62 +15 +59 +84 +22 +18 +77 +56 +55 +28 +26 +28 +79 +22 +57 +46 +64 +27 +27 +28 +20 +0 +59 +49 +5 +10 +89 +29 +0 +26 +66 +50 +69 +20 +39 +31 +31 +46 +41 +62 +45 +89 +63 +87 +47 +84 +52 +72 +59 +43 +36 +14 +48 +55 +44 +15 +22 +75 +85 +8 +0 +4 +78 +59 +28 +26 +38 +69 +18 +52 +4 +87 +47 +6 +1 +77 +4 +35 +19 +51 +65 +30 +50 +62 +72 +74 +49 +9 +22 +1 +36 +48 +23 +36 +71 +31 +22 +74 +48 +43 +66 +16 +58 +39 +72 +89 +36 +78 +36 +44 +56 +25 +56 +52 +12 +43 +52 +34 +30 +39 +35 +46 +22 +61 +61 +1 +56 +57 +60 +18 +49 +47 +12 +61 +41 +78 +33 +58 +63 +41 +49 +28 +52 +27 +40 +25 +38 +1 +43 +39 +87 +53 +42 +54 +24 +58 +1 +81 +38 +63 +19 +53 +0 +40 +45 +55 +40 +56 +39 +78 +81 +2 +26 +30 +46 +28 +35 +33 +0 +85 +74 +20 +52 +21 +87 +35 +36 +76 +73 +64 +63 +36 +40 +63 +63 +45 +52 +36 +82 +29 +20 +75 +35 +41 +21 +59 +74 +10 +46 +57 +71 +36 +35 +33 +37 +15 +41 +41 +68 +63 +40 +0 +86 +41 +40 +13 +54 +23 +43 +29 +24 +90 +64 +28 +22 +49 +1 +34 +55 +20 +64 +48 +50 +73 +44 +64 +42 +33 +40 +33 +62 +27 +55 +0 +32 +46 +41 +28 +25 +41 +0 +68 +23 +29 +18 +80 +55 +51 +29 +64 +11 +89 +31 +80 +13 +1 +54 +74 +20 +47 +18 +45 +77 +0 +46 +31 +61 +37 +13 +58 +43 +71 +74 +50 +39 +88 +19 +32 +39 +28 +55 +18 +74 +41 +28 +10 +22 +8 +4 +45 +80 +42 +47 +52 +21 +31 +37 +32 +40 +25 +70 +12 +46 +83 +26 +75 +80 +88 +36 +37 +24 +66 +64 +29 +49 +76 +43 +22 +26 +52 +51 +44 +40 +21 +24 +86 +81 +71 +43 +31 +58 +33 +23 +42 +36 +29 +66 +44 +87 +78 +37 +26 +81 +67 +19 +27 +31 +47 +36 +34 +60 +37 +89 +22 +0 +78 +57 +27 +63 +22 +52 +46 +43 +68 +70 +45 +34 +36 +52 +57 +54 +12 +80 +29 +33 +53 +49 +57 +75 +62 +27 +67 +66 +87 +66 +63 +85 +44 +42 +85 +53 +87 +17 +30 +68 +56 +43 +23 +32 +47 +23 +47 +36 +46 +6 +30 +60 +52 +50 +34 +46 +43 +43 +31 +33 +59 +39 +51 +43 +48 +66 +22 +33 +26 +48 +59 +43 +39 +44 +35 +48 +85 +64 +35 +29 +43 +39 +21 +50 +34 +24 +13 +62 +7 +38 +74 +40 +82 +81 +36 +44 +50 +27 +47 +30 +59 +68 +37 +89 +34 +71 +42 +11 +82 +4 +68 +54 +58 +49 +43 +61 +41 +38 +55 +41 +15 +56 +38 +33 +45 +4 +1 +24 +45 +15 +34 +13 +35 +49 +19 +25 +55 +60 +41 +21 +19 +58 +29 +43 +51 +44 +29 +43 +40 +51 +57 +73 +27 +1 +20 +44 +81 +40 +11 +46 +60 +44 +55 +69 +66 +66 +25 +23 +35 +40 +22 +89 +28 +87 +54 +52 +66 +34 +82 +35 +81 +40 +1 +41 +49 +10 +33 +39 +22 +32 +40 +47 +32 +3 +62 +26 +30 +80 +87 +29 +15 +18 +54 +51 +45 +34 +48 +12 +31 +44 +49 +1 +64 +71 +51 +23 +57 +90 +67 +69 +2 +38 +20 +28 +17 +31 +84 +9 +76 +40 +69 +61 +22 +29 +59 +9 +45 +33 +34 +61 +33 +63 +44 +15 +41 +3 +27 +49 +35 +64 +56 +19 +8 +24 +0 +61 +47 +52 +63 +7 +25 +24 +24 +48 +32 +84 +23 +60 +40 +36 +72 +41 +29 +41 +46 +84 +21 +38 +55 +46 +41 +75 +46 +48 +20 +53 +36 +14 +33 +52 +70 +20 +44 +17 +25 +26 +51 +30 +82 +24 +28 +33 +87 +47 +21 +14 +57 +3 +66 +8 +16 +26 +29 +76 +41 +28 +56 +17 +34 +65 +26 +28 +42 +81 +31 +20 +48 +80 +67 +71 +56 +5 +46 +15 +88 +5 +77 +32 +24 +55 +74 +63 +1 +4 +24 +52 +54 +43 +42 +11 +50 +54 +58 +2 +56 +53 +32 +0 +40 +55 +20 +23 +53 +37 +53 +79 +55 +32 +7 +87 +47 +45 +32 +43 +58 +32 +41 +49 +47 +15 +88 +34 +15 +22 +48 +38 +75 +52 +40 +26 +0 +61 +27 +25 +39 +52 +41 +41 +16 +43 +22 +54 +31 +47 +32 +44 +32 +34 +19 +31 +48 +18 +57 +52 +64 +49 +48 +40 +65 +32 +38 +24 +17 +36 +45 +57 +41 +20 +44 +58 +40 +63 +37 +78 +73 +33 +44 +57 +47 +87 +22 +29 +43 +37 +45 +35 +34 +66 +53 +19 +59 +47 +43 +79 +26 +16 +24 +24 +40 +34 +37 +74 +1 +48 +87 +81 +22 +30 +49 +21 +35 +52 +37 +57 +53 +51 +23 +64 +24 +41 +42 +56 +21 +40 +47 +81 +36 +54 +18 +24 +58 +18 +64 +12 +41 +52 +41 +66 +27 +55 +66 +33 +64 +38 +62 +47 +59 +26 +87 +74 +46 +30 +0 +17 +31 +43 +26 +87 +25 +35 +59 +18 +21 +1 +80 +62 +47 +40 +73 +72 +56 +24 +47 +44 +66 +58 +31 +57 +59 +33 +30 +46 +88 +41 +75 +81 +27 +37 +61 +31 +26 +23 +36 +10 +42 +50 +54 +49 +49 +51 +77 +56 +0 +48 +42 +48 +40 +9 +20 +56 +73 +1 +69 +60 +44 +75 +14 +62 +69 +61 +39 +44 +61 +48 +6 +46 +45 +79 +27 +63 +57 +69 +55 +22 +36 +74 +50 +59 +49 +60 +56 +30 +6 +58 +40 +43 +37 +28 +45 +0 +50 +35 +42 +41 +7 +81 +36 +15 +21 +51 +52 +60 +55 +64 +87 +45 +58 +22 +25 +70 +46 +35 +48 +49 +19 +16 +62 +18 +10 +23 +27 +13 +34 +38 +51 +54 +15 +24 +74 +59 +40 +40 +34 +50 +66 +42 +12 +63 +27 +42 +0 +86 +35 +62 +57 +27 +58 +63 +87 +28 +64 +22 +0 +62 +15 +6 +36 +20 +36 +28 +7 +87 +60 +11 +41 +87 +67 +68 +87 +25 +31 +53 +27 +66 +35 +39 +58 +68 +62 +32 +48 +8 +37 +34 +57 +6 +41 +40 +47 +21 +78 +50 +76 +26 +56 +68 +87 +35 +21 +52 +25 +0 +36 +34 +33 +63 +63 +34 +26 +3 +42 +60 +43 +38 +17 +43 +17 +40 +33 +28 +40 +43 +81 +55 +89 +63 +58 +49 +49 +87 +38 +39 +90 +56 +52 +39 +46 +32 +44 +59 +33 +50 +47 +81 +42 +87 +41 +76 +16 +56 +2 +70 +18 +44 +79 +50 +42 +36 +0 +87 +75 +49 +71 +11 +25 +23 +66 +18 +59 +17 +47 +74 +80 +59 +53 +36 +75 +0 +14 +50 +29 +25 +57 +47 +34 +63 +0 +40 +63 +23 +44 +46 +50 +41 +70 +57 +22 +43 +54 +50 +18 +86 +88 +48 +83 +64 +43 +76 +50 +68 +67 +23 +56 +7 +75 +20 +37 +31 +48 +87 +14 +60 +14 +1 +11 +32 +32 +37 +22 +37 +31 +63 +42 +47 +6 +32 +56 +66 +90 +22 +59 +49 +30 +55 +39 +52 +65 +71 +38 +84 +48 +8 +53 +71 +31 +0 +55 +59 +48 +42 +46 +22 +15 +55 +36 +53 +69 +1 +84 +58 +56 +18 +52 +40 +32 +82 +27 +59 +39 +68 +31 +40 +19 +23 +0 +25 +89 +48 +12 +72 +33 +56 +69 +74 +51 +64 +29 +25 +40 +36 +13 +75 +16 +49 +41 +49 +33 +32 +57 +44 +35 +76 +46 +40 +78 +78 +57 +35 +66 +48 +32 +32 +41 +42 +20 +66 +31 +89 +57 +62 +52 +71 +16 +57 +76 +13 +35 +43 +53 +83 +81 +65 +50 +77 +38 +70 +49 +50 +7 +24 +15 +45 +37 +57 +52 +30 +33 +0 +13 +39 +40 +67 +50 +40 +37 +71 +23 +37 +47 +23 +37 +74 +35 +78 +8 +50 +87 +33 +28 +61 +34 +37 +3 +1 +24 +29 +33 +18 +66 +47 +0 +51 +50 +63 +61 +33 +69 +37 +29 +41 +17 +28 +28 +20 +22 +43 +41 +45 +54 +75 +48 +36 +43 +72 +87 +54 +64 +5 +73 +21 +39 +34 +38 +76 +66 +42 +52 +44 +40 +42 +59 +4 +51 +45 +54 +65 +63 +61 +68 +62 +88 +14 +17 +42 +39 +33 +87 +50 +51 +42 +46 +66 +44 +55 +62 +33 +53 +87 +35 +83 +46 +51 +59 +10 +22 +46 +30 +0 +0 +89 +1 +43 +75 +39 +87 +46 +51 +77 +31 +45 +22 +52 +33 +61 +76 +28 +56 +64 +43 +58 +15 +28 +24 +25 +56 +39 +58 +39 +48 +56 +2 +28 +38 +20 +41 +49 +3 +54 +66 +28 +47 +29 +69 +59 +41 +26 +68 +40 +73 +28 +65 +20 +87 +0 +90 +35 +38 +51 +34 +46 +62 +67 +4 +53 +62 +59 +3 +48 +57 +61 +45 +28 +62 +34 +33 +48 +53 +44 +45 +78 +35 +73 +68 +27 +39 +32 +54 +84 +65 +21 +24 +34 +0 +54 +57 +35 +59 +41 +22 +3 +58 +39 +28 +40 +62 +34 +45 +70 +35 +20 +20 +55 +23 +50 +30 +21 +80 +70 +0 +47 +68 +68 +21 +61 +59 +40 +67 +76 +81 +40 +37 +44 +34 +85 +36 +59 +46 +56 +27 +1 +46 +58 +14 +4 +46 +18 +44 +26 +45 +58 +49 +42 +54 +42 +69 +26 +89 +48 +46 +15 +43 +25 +36 +37 +67 +78 +79 +63 +29 +37 +61 +8 +69 +6 +67 +32 +19 +87 +66 +55 +45 +25 +26 +33 +27 +20 +65 +62 +33 +31 +33 +26 +64 +31 +25 +49 +72 +26 +21 +29 +60 +59 +69 +66 +33 +36 +71 +45 +47 +52 +30 +54 +54 +34 +0 +32 +66 +45 +29 +53 +52 +43 +78 +49 +57 +43 +23 +88 +37 +52 +39 +29 +31 +34 +39 +87 +67 +70 +68 +5 +19 +25 +36 +85 +44 +45 +26 +67 +27 +27 +24 +81 +54 +48 +71 +47 +69 +1 +80 +36 +50 +47 +41 +17 +65 +53 +28 +5 +66 +63 +0 +64 +69 +25 +69 +63 +58 +10 +36 +0 +46 +43 +58 +89 +29 +40 +51 +12 +42 +7 +34 +44 +45 +73 +29 +40 +71 +74 +44 +44 +75 +51 +12 +50 +47 +52 +30 +11 +37 +1 +28 +48 +41 +79 +27 +11 +69 +21 +46 +41 +45 +59 +87 +51 +35 +87 +74 +55 +24 +39 +62 +33 +41 +87 +53 +14 +74 +37 +42 +87 +5 +46 +61 +37 +33 +53 +65 +48 +39 +52 +21 +79 +2 +41 +56 +2 +63 +28 +59 +45 +67 +51 +36 +39 +17 +18 +20 +16 +75 +32 +26 +56 +59 +18 +75 +87 +80 +40 +82 +49 +37 +45 +60 +29 +63 +55 +83 +57 +4 +49 +5 +17 +72 +20 +44 +50 +47 +34 +62 +35 +88 +64 +37 +45 +33 +55 +15 +21 +55 +65 +57 +42 +88 +64 +70 +43 +54 +20 +37 +72 +21 +71 +24 +34 +55 +42 +44 +85 +51 +64 +48 +9 +41 +50 +32 +24 +49 +33 +31 +61 +37 +19 +72 +43 +61 +22 +20 +31 +1 +29 +23 +57 +32 +26 +47 +40 +21 +31 +3 +37 +67 +28 +53 +37 +39 +20 +30 +58 +64 +46 +73 +51 +86 +72 +71 +48 +77 +43 +50 +68 +59 +1 +47 +66 +81 +1 +23 +26 +49 +44 +48 +50 +54 +3 +27 +60 +87 +0 +52 +13 +41 +78 +52 +27 +49 +23 +52 +65 +62 +21 +40 +50 +36 +64 +29 +31 +42 +70 +56 +38 +41 +69 +26 +25 +27 +25 +53 +40 +68 +34 +39 +11 +81 +43 +25 +73 +79 +40 +44 +53 +81 +56 +30 +17 +22 +51 +57 +45 +31 +25 +56 +1 +7 +60 +69 +34 +77 +61 +0 +15 +0 +12 +26 +19 +70 +46 +12 +29 +29 +88 +53 +23 +80 +50 +38 +52 +87 +59 +44 +49 +49 +14 +45 +51 +68 +49 +44 +42 +52 +67 +49 +32 +17 +75 +57 +32 +81 +10 +48 +7 +15 +57 +7 +41 +23 +78 +64 +89 +42 +16 +44 +27 +38 +62 +89 +75 +36 +43 +83 +22 +28 +29 +36 +50 +5 +47 +52 +46 +25 +25 +89 +5 +61 +41 +75 +34 +42 +42 +89 +64 +86 +6 +46 +66 +86 +43 +58 +39 +30 +47 +43 +31 +41 +56 +43 +36 +42 +51 +71 +39 +19 +26 +12 +61 +8 +22 +51 +89 +65 +49 +10 +36 +57 +38 +17 +26 +32 +67 +17 +53 +61 +36 +26 +40 +35 +28 +42 +87 +58 +31 +19 +21 +34 +62 +1 +26 +50 +48 +58 +70 +58 +54 +59 +36 +76 +52 +36 +35 +78 +68 +81 +56 +29 +28 +45 +10 +49 +17 +49 +53 +33 +51 +71 +51 +67 +2 +65 +43 +39 +44 +13 +47 +65 +42 +58 +41 +35 +59 +31 +7 +38 +20 +57 +44 +29 +69 +26 +33 +26 +65 +46 +4 +27 +61 +50 +45 +29 +36 +64 +59 +13 +67 +77 +43 +56 +45 +33 +38 +35 +54 +76 +66 +27 +4 +72 +34 +79 +67 +51 +73 +18 +50 +32 +72 +28 +45 +20 +24 +60 +61 +89 +53 +38 +45 +32 +34 +24 +74 +44 +0 +49 +19 +33 +47 +58 +52 +46 +1 +42 +64 +83 +30 +32 +9 +41 +37 +14 +54 +3 +21 +9 +74 +36 +7 +42 +65 +37 +27 +51 +39 +51 +20 +65 +15 +20 +42 +15 +68 +36 +43 +72 +25 +42 +23 +9 +7 +50 +40 +44 +60 +37 +71 +76 +30 +13 +39 +17 +46 +30 +0 +20 +49 +30 +62 +49 +4 +26 +11 +26 +21 +70 +67 +29 +45 +45 +11 +64 +52 +44 +21 +42 +11 +53 +41 +31 +59 +2 +41 +60 +35 +46 +38 +35 +28 +30 +62 +23 +24 +30 +87 +6 +1 +41 +26 +81 +24 +57 +8 +68 +19 +28 +30 +43 +53 +23 +36 +40 +62 +19 +39 +9 +28 +25 +23 +87 +45 +29 +48 +46 +44 +22 +35 +64 +24 +24 +89 +73 +42 +47 +42 +81 +31 +29 +41 +17 +39 +73 +27 +46 +72 +48 +37 +69 +31 +0 +51 +51 +25 +52 +71 +56 +57 +60 +31 +55 +53 +50 +32 +62 +37 +88 +66 +48 +33 +68 +46 +53 +70 +25 +58 +60 +81 +89 +81 +16 +57 +52 +63 +29 +38 +66 +22 +36 +38 +60 +63 +21 +4 +87 +28 +42 +29 +33 +68 +61 +80 +33 +71 +50 +48 +40 +60 +51 +47 +49 +22 +70 +52 +34 +41 +38 +28 +35 +52 +48 +68 +25 +59 +75 +67 +70 +53 +76 +2 +21 +53 +63 +7 +22 +21 +49 +24 +45 +53 +23 +57 +43 +18 +53 +55 +22 +34 +29 +53 +50 +43 +42 +29 +67 +61 +35 +66 +11 +51 +59 +42 +56 +48 +40 +47 +55 +46 +75 +54 +25 +53 +54 +48 +50 +53 +55 +35 +39 +28 +45 +42 +69 +70 +65 +3 +59 +38 +61 +42 +45 +14 +13 +35 +9 +81 +42 +39 +15 +10 +11 +47 +41 +0 +42 +19 +36 +49 +45 +22 +42 +50 +35 +64 +44 +23 +48 +59 +17 +31 +84 +46 +81 +14 +26 +32 +44 +52 +51 +40 +75 +55 +43 +35 +37 +83 +38 +80 +51 +48 +31 +56 +55 +51 +29 +89 +17 +63 +31 +68 +26 +6 +17 +64 +74 +56 +38 +51 +54 +77 +55 +66 +39 +61 +34 +57 +61 +47 +10 +53 +17 +28 +1 +45 +59 +60 +0 +43 +30 +54 +49 +30 +52 +87 +31 +22 +74 +53 +20 +49 +42 +45 +54 +31 +7 +28 +38 +39 +35 +51 +31 +11 +51 +25 +58 +53 +6 +36 +38 +17 +48 +1 +26 +28 +53 +41 +68 +52 +51 +45 +16 +20 +62 +0 +72 +89 +40 +5 +46 +45 +17 +42 +24 +59 +33 +31 +23 +39 +58 +33 +60 +55 +59 +81 +40 +71 +37 +73 +67 +60 +45 +46 +58 +56 +17 +85 +71 +52 +6 +66 +58 +38 +66 +90 +63 +73 +34 +50 +38 +70 +50 +57 +36 +51 +34 +81 +56 +52 +34 +51 +32 +62 +74 +14 +14 +23 +65 +59 +82 +9 +51 +30 +47 +54 +63 +39 +12 +54 +52 +34 +77 +68 +23 +29 +0 +18 +70 +47 +19 +22 +36 +49 +38 +25 +49 +11 +67 +43 +78 +63 +65 +41 +48 +40 +46 +38 +66 +56 +29 +64 +34 +35 +70 +43 +38 +39 +57 +15 +46 +75 +19 +40 +43 +17 +73 +24 +17 +41 +31 +5 +17 +40 +37 +30 +45 +25 +72 +27 +43 +57 +74 +50 +64 +13 +69 +38 +57 +59 +72 +60 +0 +64 +69 +0 +55 +48 +59 +25 +79 +75 +85 +57 +0 +44 +60 +45 +28 +55 +86 +11 +14 +35 +34 +33 +70 +3 +35 +4 +52 +67 +36 +66 +9 +32 +54 +36 +25 +73 +10 +45 +49 +24 +65 +48 +18 +1 +14 +61 +22 +33 +50 +14 +82 +27 +9 +60 +33 +37 +64 +63 +49 +26 +41 +28 +22 +47 +51 +60 +52 +51 +56 +11 +49 +55 +25 +56 +52 +58 +55 +61 +45 +12 +49 +78 +31 +65 +51 +81 +89 +77 +16 +53 +27 +33 +43 +27 +2 +31 +0 +46 +18 +53 +44 +30 +55 +34 +36 +53 +30 +40 +17 +33 +26 +20 +29 +20 +64 +56 +43 +16 +37 +43 +49 +41 +49 +68 +77 +43 +20 +38 +60 +19 +43 +40 +70 +81 +27 +42 +38 +0 +47 +62 +32 +36 +44 +54 +48 +45 +52 +34 +38 +63 +67 +46 +51 +2 +34 +21 +39 +65 +51 +22 +40 +73 +22 +65 +67 +85 +62 +60 +44 +48 +39 +58 +49 +10 +14 +69 +29 +44 +49 +65 +59 +28 +37 +34 +75 +46 +38 +41 +88 +47 +49 +60 +58 +42 +44 +1 +66 +26 +44 +5 +46 +89 +45 +66 +18 +63 +34 +14 +49 +34 +29 +52 +33 +68 +42 +38 +68 +40 +15 +45 +42 +36 +40 +66 +42 +73 +34 +35 +70 +52 +88 +19 +57 +60 +48 +50 +28 +14 +49 +31 +28 +61 +38 +40 +42 +65 +65 +12 +53 +54 +41 +58 +51 +51 +48 +54 +36 +28 +70 +31 +83 +13 +0 +54 +13 +61 +63 +50 +61 +69 +28 +39 +52 +69 +56 +41 +40 +27 +16 +3 +40 +31 +47 +45 +44 +33 +24 +74 +26 +30 +67 +78 +38 +32 +40 +57 +50 +61 +25 +47 +23 +25 +66 +65 +59 +46 +45 +5 +62 +31 +45 +57 +29 +58 +76 +66 +35 +59 +55 +58 +40 +36 +75 +65 +39 +47 +10 +19 +48 +18 +43 +23 +67 +25 +54 +27 +45 +51 +61 +43 +54 +27 +49 +35 +76 +41 +54 +39 +1 +12 +28 +4 +58 +28 +50 +40 +38 +54 +26 +45 +58 +56 +80 +27 +31 +19 +25 +26 +22 +39 +5 +56 +5 +39 +31 +69 +47 +2 +63 +62 +35 +56 +27 +16 +69 +25 +53 +44 +7 +63 +10 +27 +88 +66 +27 +43 +58 +23 +83 +45 +45 +19 +61 +28 +54 +38 +50 +69 +53 +47 +37 +30 +71 +79 +43 +24 +15 +65 +15 +40 +73 +53 +72 +28 +66 +67 +56 +39 +80 +35 +21 +19 +32 +73 +41 +65 +36 +66 +54 +11 +21 +9 +75 +65 +33 +61 +52 +29 +3 +50 +40 +1 +31 +68 +28 +76 +33 +25 +72 +38 +50 +90 +0 +32 +89 +65 +87 +60 +40 +39 +49 +41 +77 +41 +54 +43 +43 +57 +68 +89 +0 +41 +14 +30 +69 +0 +36 +30 +60 +21 +72 +17 +75 +58 +46 +73 +78 +62 +40 +16 +33 +42 +47 +63 +79 +27 +26 +35 +52 +38 +73 +46 +1 +54 +4 +87 +42 +57 +72 +60 +87 +48 +60 +46 +65 +12 +22 +1 +48 +56 +17 +47 +69 +77 +12 +53 +57 +53 +37 +2 +9 +29 +19 +16 +25 +50 +41 +51 +23 +67 +48 +45 +28 +15 +16 +38 +52 +50 +31 +36 +44 +15 +21 +53 +20 +24 +31 +28 +1 +2 +67 +53 +53 +21 +67 +87 +1 +23 +38 +28 +34 +62 +14 +82 +56 +32 +27 +72 +42 +28 +47 +25 +0 +32 +16 +38 +33 +41 +63 +70 +7 +51 +68 +53 +45 +70 +14 +73 +39 +51 +11 +39 +78 +84 +47 +65 +65 +53 +69 +46 +26 +45 +30 +56 +60 +45 +69 +37 +36 +68 +29 +45 +27 +25 +37 +59 +34 +36 +78 +46 +51 +22 +7 +69 +14 +75 +6 +47 +43 +36 +51 +40 +89 +48 +49 +89 +64 +33 +52 +6 +61 +37 +37 +19 +26 +51 +38 +44 +43 +14 +74 +2 +49 +31 +42 +33 +35 +3 +26 +69 +78 +45 +89 +22 +14 +25 +0 +42 +61 +50 +51 +46 +68 +78 +35 +10 +4 +46 +20 +17 +88 +33 +39 +0 +1 +43 +32 +27 +55 +64 +43 +47 +78 +44 +64 +50 +41 +45 +50 +61 +46 +50 +73 +29 +43 +27 +42 +39 +33 +65 +72 +69 +36 +49 +58 +25 +59 +25 +56 +35 +69 +48 +46 +49 +25 +3 +56 +55 +34 +19 +83 +84 +89 +53 +46 +78 +62 +43 +12 +11 +46 +42 +28 +67 +62 +34 +87 +38 +38 +60 +53 +52 +60 +30 +55 +21 +29 +65 +59 +51 +12 +58 +49 +86 +44 +63 +64 +10 +41 +57 +39 +36 +87 +35 +54 +87 +63 +50 +22 +69 +24 +18 +25 +84 +27 +40 +33 +58 +66 +47 +72 +55 +41 +51 +28 +45 +85 +50 +51 +81 +44 +55 +64 +13 +29 +35 +6 +71 +56 +44 +35 +71 +70 +46 +88 +35 +73 +70 +14 +64 +30 +25 +22 +38 +55 +1 +25 +36 +39 +87 +39 +7 +59 +39 +33 +59 +36 +13 +58 +53 +29 +52 +75 +54 +48 +69 +20 +50 +66 +90 +29 +75 +89 +57 +58 +52 +87 +59 +40 +28 +39 +75 +75 +67 +39 +28 +22 +87 +49 +48 +55 +35 +58 +14 +33 +30 +47 +75 +78 +43 +41 +60 +15 +47 +53 +78 +87 +52 +66 +15 +44 +37 +25 +56 +77 +2 +42 +82 +29 +76 +48 +81 +47 +36 +2 +19 +34 +31 +3 +62 +65 +50 +85 +29 +51 +51 +33 +28 +36 +60 +50 +28 +51 +73 +6 +76 +77 +46 +49 +47 +49 +62 +45 +1 +55 +66 +15 +49 +30 +63 +31 +31 +43 +17 +19 +56 +56 +25 +55 +24 +28 +72 +72 +0 +57 +59 +42 +49 +49 +44 +34 +40 +48 +44 +58 +65 +83 +2 +51 +38 +65 +72 +33 +25 +12 +0 +87 +84 +87 +22 +51 +31 +20 +8 +27 +53 +88 +45 +43 +51 +44 +59 +49 +20 +40 +44 +23 +62 +54 +30 +26 +25 +69 +43 +22 +66 +30 +23 +74 +40 +61 +46 +17 +59 +70 +24 +54 +32 +57 +29 +45 +27 +22 +40 +23 +22 +30 +38 +50 +67 +69 +68 +28 +57 +70 +29 +87 +47 +77 +26 +57 +39 +17 +44 +90 +4 +79 +64 +52 +41 +65 +35 +50 +42 +35 +62 +62 +17 +41 +65 +31 +80 +38 +53 +21 +70 +10 +29 +19 +52 +46 +28 +64 +1 +43 +49 +23 +16 +37 +0 +25 +68 +89 +37 +40 +67 +36 +54 +51 +58 +76 +56 +27 +59 +65 +44 +61 +7 +26 +16 +33 +88 +73 +60 +28 +34 +34 +54 +72 +63 +50 +48 +61 +49 +17 +54 +22 +26 +22 +58 +1 +27 +65 +43 +62 +40 +89 +14 +22 +12 +44 +33 +43 +5 +58 +10 +18 +46 +35 +49 +64 +36 +76 +44 +52 +47 +35 +41 +51 +61 +32 +39 +50 +32 +40 +78 +30 +52 +47 +26 +39 +87 +43 +34 +62 +34 +41 +35 +42 +78 +50 +52 +70 +50 +18 +50 +52 +74 +19 +52 +46 +39 +9 +89 +42 +62 +89 +31 +8 +47 +63 +31 +49 +1 +61 +75 +16 +38 +33 +67 +7 +16 +22 +45 +34 +31 +27 +50 +73 +56 +40 +34 +34 +55 +34 +47 +34 +6 +50 +67 +20 +53 +42 +23 +13 +65 +44 +61 +52 +60 +48 +5 +45 +12 +59 +73 +51 +41 +0 +65 +12 +21 +52 +56 +61 +12 +51 +20 +47 +62 +41 +40 +0 +43 +25 +47 +28 +46 +54 +23 +17 +32 +42 +54 +39 +54 +54 +36 +31 +68 +87 +46 +42 +36 +73 +66 +69 +71 +47 +35 +4 +53 +60 +49 +59 +28 +44 +30 +16 +43 +57 +40 +34 +35 +34 +34 +89 +35 +41 +46 +63 +28 +42 +62 +19 +32 +38 +18 +16 +50 +13 +39 +36 +75 +11 +4 +42 +59 +11 +39 +52 +26 +51 +35 +45 +44 +83 +26 +0 +46 +78 +28 +49 +38 +38 +62 +35 +42 +36 +33 +60 +66 +49 +32 +71 +86 +35 +41 +59 +27 +39 +49 +65 +24 +52 +36 +43 +0 +42 +49 +28 +61 +47 +62 +0 +20 +40 +63 +22 +53 +65 +55 +42 +45 +36 +90 +20 +64 +17 +46 +78 +29 +34 +18 +69 +23 +61 +22 +66 +19 +50 +41 +39 +19 +16 +1 +82 +44 +49 +30 +47 +44 +77 +35 +41 +47 +64 +73 +6 +24 +63 +32 +41 +39 +44 +60 +59 +32 +38 +67 +61 +87 +65 +13 +81 +48 +53 +39 +48 +76 +13 +66 +22 +25 +57 +43 +17 +15 +57 +31 +72 +25 +57 +44 +32 +1 +36 +60 +12 +21 +61 +42 +37 +49 +35 +42 +43 +1 +74 +24 +18 +28 +34 +25 +52 +68 +40 +28 +42 +72 +44 +76 +36 +43 +39 +30 +52 +79 +6 +29 +71 +35 +49 +88 +53 +65 +53 +65 +42 +76 +68 +61 +66 +45 +29 +43 +49 +52 +74 +43 +51 +82 +50 +56 +35 +37 +22 +32 +0 +47 +44 +37 +69 +58 +77 +38 +33 +27 +65 +78 +75 +78 +1 +88 +50 +37 +32 +1 +37 +51 +69 +29 +41 +6 +11 +24 +53 +0 +75 +36 +43 +18 +50 +75 +39 +50 +53 +5 +48 +31 +70 +43 +13 +56 +45 +13 +30 +21 +59 +24 +14 +41 +39 +30 +29 +30 +74 +65 +42 +60 +57 +65 +48 +82 +81 +29 +44 +37 +76 +23 +56 +40 +48 +35 +22 +70 +42 +19 +32 +71 +56 +50 +47 +80 +44 +45 +34 +42 +32 +47 +67 +39 +28 +62 +32 +38 +25 +55 +50 +48 +81 +49 +42 +45 +45 +49 +47 +22 +46 +22 +67 +71 +44 +39 +55 +32 +87 +65 +55 +84 +33 +79 +63 +71 +34 +57 +36 +46 +62 +19 +59 +68 +34 +55 +40 +25 +40 +28 +65 +19 +47 +49 +62 +90 +25 +59 +67 +70 +31 +38 +23 +0 +81 +50 +47 +7 +35 +53 +72 +20 +21 +46 +41 +73 +13 +30 +52 +45 +46 +58 +28 +26 +54 +22 +37 +24 +59 +50 +38 +55 +88 +17 +54 +21 +68 +63 +47 +22 +71 +8 +74 +14 +76 +25 +46 +42 +31 +36 +12 +44 +39 +41 +37 +21 +8 +31 +52 +40 +41 +45 +50 +7 +80 +44 +78 +42 +40 +86 +59 +60 +22 +56 +74 +31 +29 +60 +74 +3 +31 +89 +74 +66 +3 +16 +54 +63 +88 +89 +38 +59 +47 +36 +73 +27 +43 +75 +32 +79 +64 +40 +42 +25 +85 +41 +19 +47 +71 +33 +54 +75 +31 +51 +27 +25 +17 +51 +57 +20 +69 +65 +77 +78 +40 +28 +56 +28 +43 +55 +30 +52 +52 +71 +48 +54 +23 +89 +41 +37 +55 +60 +17 +1 +66 +48 +57 +19 +61 +53 +71 +53 +46 +41 +65 +40 +16 +17 +72 +6 +43 +89 +24 +65 +33 +1 +26 +23 +0 +40 +76 +24 +50 +39 +34 +42 +25 +44 +62 +39 +79 +30 +37 +47 +77 +50 +51 +47 +32 +42 +26 +87 +49 +21 +39 +22 +19 +20 +49 +45 +72 +62 +49 +81 +15 +54 +37 +60 +82 +48 +64 +43 +71 +66 +38 +20 +50 +17 +57 +40 +32 +28 +11 +22 +44 +9 +59 +46 +24 +30 +77 +57 +30 +38 +52 +47 +46 +19 +44 +42 +51 +60 +87 +38 +22 +40 +52 +59 +31 +33 +59 +53 +10 +49 +38 +45 +68 +78 +56 +48 +34 +24 +63 +57 +51 +8 +64 +46 +42 +35 +61 +50 +30 +68 +59 +56 +12 +52 +44 +54 +80 +45 +50 +0 +46 +38 +88 +32 +1 +46 +42 +62 +47 +44 +27 +30 +53 +35 +32 +64 +43 +63 +43 +53 +22 +50 +47 +59 +1 +34 +57 +39 +75 +48 +87 +15 +70 +38 +82 +34 +42 +18 +35 +20 +60 +36 +23 +34 +37 +60 +33 +43 +8 +24 +36 +71 +41 +44 +53 +32 +25 +39 +38 +63 +33 +63 +87 +59 +47 +2 +53 +10 +46 +17 +33 +53 +50 +70 +28 +26 +23 +28 +39 +45 +48 +6 +53 +42 +60 +58 +32 +40 +69 +29 +51 +8 +46 +68 +78 +78 +61 +60 +21 +41 +51 +39 +84 +22 +66 +89 +5 +59 +59 +17 +51 +24 +14 +45 +31 +1 +79 +51 +41 +28 +39 +30 +7 +78 +59 +51 +47 +18 +67 +70 +39 +48 +47 +54 +46 +44 +47 +25 +29 +59 +70 +88 +14 +30 +29 +23 +29 +60 +43 +31 +56 +49 +60 +20 +22 +63 +43 +17 +2 +46 +49 +60 +78 +30 +41 +9 +33 +40 +37 +43 +54 +53 +48 +73 +35 +36 +50 +14 +2 +45 +18 +59 +8 +31 +76 +30 +60 +36 +36 +18 +18 +28 +29 +22 +74 +84 +39 +56 +28 +74 +82 +69 +9 +65 +61 +51 +42 +23 +18 +25 +55 +57 +41 +46 +28 +8 +57 +51 +26 +33 +35 +10 +35 +67 +36 +34 +47 +31 +61 +42 +80 +77 +30 +87 +77 +11 +42 +54 +69 +14 +64 +41 +73 +48 +36 +55 +62 +57 +23 +41 +20 +26 +22 +53 +66 +1 +77 +24 +19 +21 +54 +30 +36 +61 +63 +32 +27 +79 +64 +40 +75 +48 +21 +57 +62 +55 +50 +36 +35 +67 +37 +41 +82 +51 +61 +42 +48 +20 +28 +48 +31 +76 +56 +34 +14 +50 +27 +39 +17 +80 +50 +52 +29 +89 +61 +61 +31 +76 +8 +45 +47 +61 +39 +36 +53 +6 +35 +45 +34 +19 +30 +43 +60 +20 +61 +56 +66 +44 +1 +49 +71 +37 +46 +77 +52 +35 +18 +49 +29 +44 +73 +40 +30 +55 +15 +24 +47 +43 +40 +38 +2 +65 +67 +53 +49 +7 +67 +63 +44 +41 +44 +54 +32 +33 +12 +64 +70 +46 +30 +40 +84 +40 +33 +14 +40 +48 +76 +82 +51 +0 +53 +57 +55 +37 +35 +54 +67 +19 +68 +76 +68 +54 +49 +57 +49 +81 +35 +39 +24 +58 +53 +27 +53 +42 +19 +40 +36 +55 +29 +29 +51 +26 +51 +68 +63 +32 +18 +16 +60 +45 +71 +57 +36 +73 +50 +37 +3 +25 +49 +59 +21 +35 +38 +29 +70 +23 +50 +59 +14 +52 +56 +73 +68 +88 +31 +46 +26 +24 +65 +31 +33 +10 +61 +14 +69 +59 +47 +26 +26 +49 +76 +22 +2 +41 +36 +19 +34 +87 +37 +61 +60 +48 +46 +47 +41 +25 +25 +68 +34 +40 +78 +76 +66 +90 +36 +23 +0 +49 +42 +73 +37 +38 +36 +23 +83 +32 +84 +52 +53 +67 +48 +47 +57 +80 +25 +46 +9 +44 +66 +72 +29 +15 +58 +20 +45 +73 +27 +27 +30 +54 +22 +62 +8 +21 +15 +77 +27 +35 +19 +47 +70 +70 +14 +60 +8 +26 +47 +7 +0 +43 +19 +34 +34 +32 +22 +55 +0 +41 +55 +78 +56 +24 +36 +48 +23 +30 +48 +62 +21 +78 +62 +21 +43 +49 +73 +29 +32 +50 +19 +67 +39 +57 +0 +43 +33 +37 +43 +67 +21 +26 +49 +41 +60 +10 +85 +55 +78 +77 +54 +50 +29 +79 +37 +26 +87 +87 +45 +81 +45 +32 +59 +63 +19 +73 +27 +62 +40 +57 +64 +46 +5 +32 +44 +72 +53 +44 +53 +38 +35 +47 +7 +78 +43 +19 +45 +42 +22 +46 +33 +15 +88 +86 +63 +48 +40 +80 +35 +18 +4 +15 +36 +39 +42 +22 +38 +15 +50 +39 +42 +40 +85 +32 +73 +40 +44 +42 +45 +25 +48 +64 +45 +39 +26 +29 +48 +10 +47 +50 +58 +57 +13 +49 +39 +29 +31 +26 +44 +50 +79 +25 +85 +38 +4 +66 +26 +4 +61 +1 +79 +43 +38 +6 +46 +0 +50 +31 +16 +12 +30 +19 +14 +81 +17 +63 +24 +44 +36 +82 +2 +53 +57 +19 +58 +29 +39 +70 +8 +12 +45 +1 +45 +34 +29 +54 +16 +55 +78 +90 +76 +8 +40 +53 +36 +55 +43 +24 +23 +28 +46 +18 +26 +56 +48 +40 +49 +61 +89 +47 +33 +48 +41 +39 +41 +14 +40 +45 +62 +47 +25 +14 +76 +81 +70 +39 +87 +38 +41 +32 +2 +31 +1 +50 +40 +48 +1 +0 +58 +45 +49 +10 +30 +26 +32 +47 +82 +31 +62 +30 +53 +32 +25 +55 +56 +49 +50 +67 +16 +76 +74 +28 +51 +33 +23 +50 +72 +59 +66 +47 +40 +17 +31 +88 +7 +44 +34 +49 +65 +46 +20 +73 +0 +55 +30 +57 +76 +67 +41 +77 +42 +5 +33 +46 +40 +31 +55 +42 +47 +45 +47 +25 +52 +54 +30 +64 +0 +33 +30 +54 +39 +27 +5 +39 +31 +60 +24 +49 +51 +37 +56 +89 +17 +14 +23 +66 +56 +52 +76 +52 +43 +60 +42 +51 +64 +17 +56 +13 +66 +54 +50 +80 +27 +51 +56 +37 +57 +0 +44 +41 +47 +25 +25 +82 +87 +29 +28 +48 +61 +66 +61 +73 +48 +27 +28 +48 +77 +15 +52 +39 +66 +18 +68 +66 +34 +48 +17 +46 +45 +60 +48 +27 +18 +37 +40 +54 +43 +53 +27 +41 +54 +58 +79 +29 +55 +20 +62 +42 +19 +62 +57 +51 +38 +39 +27 +17 +50 +20 +79 +81 +91 +0 +40 +34 +23 +7 +35 +78 +28 +44 +42 +36 +50 +54 +29 +76 +20 +75 +55 +68 +49 +84 +28 +56 +69 +41 +42 +45 +28 +1 +40 +38 +65 +19 +56 +30 +30 +77 +72 +45 +67 +49 +35 +34 +36 +0 +63 +55 +51 +63 +26 +56 +49 +54 +67 +59 +66 +54 +35 +25 +78 +61 +72 +29 +66 +34 +37 +89 +54 +25 +50 +50 +57 +34 +2 +44 +24 +33 +79 +60 +11 +52 +48 +36 +72 +23 +65 +62 +51 +31 +48 +34 +64 +57 +68 +16 +51 +37 +0 +32 +40 +28 +44 +1 +69 +66 +83 +39 +43 +16 +56 +25 +41 +55 +53 +14 +37 +49 +29 +59 +20 +40 +89 +52 +66 +51 +40 +24 +57 +42 +3 +88 +43 +73 +56 +75 +41 +52 +38 +32 +66 +71 +74 +88 +25 +59 +36 +1 +58 +58 +20 +52 +64 +70 +33 +59 +66 +50 +25 +31 +18 +8 +87 +61 +42 +58 +87 +50 +40 +65 +8 +27 +71 +54 +26 +51 +57 +52 +0 +42 +27 +44 +79 +30 +82 +47 +45 +30 +50 +82 +62 +39 +49 +0 +38 +40 +75 +27 +12 +19 +53 +51 +0 +63 +58 +44 +41 +22 +77 +56 +23 +59 +46 +40 +18 +50 +27 +87 +31 +43 +32 +34 +37 +89 +43 +45 +11 +67 +0 +53 +81 +40 +74 +50 +62 +0 +37 +45 +64 +62 +69 +32 +16 +45 +38 +34 +34 +39 +10 +38 +36 +68 +42 +12 +70 +60 +45 +83 +40 +65 +56 +26 +31 +25 +44 +19 +32 +42 +8 +28 +6 +18 +55 +69 +41 +67 +55 +25 +5 +24 +55 +59 +37 +33 +28 +11 +52 +23 +25 +28 +35 +47 +39 +6 +14 +0 +42 +21 +52 +52 +14 +14 +36 +78 +26 +34 +10 +66 +33 +30 +13 +23 +30 +23 +63 +53 +33 +73 +51 +43 +31 +44 +21 +55 +21 +65 +40 +42 +23 +40 +45 +44 +44 +76 +84 +73 +55 +33 +16 +47 +47 +17 +64 +63 +59 +52 +58 +45 +1 +14 +24 +34 +42 +48 +74 +48 +15 +22 +79 +1 +32 +52 +43 +21 +38 +43 +83 +45 +65 +37 +38 +47 +65 +58 +55 +31 +47 +81 +50 +69 +27 +21 +19 +34 +87 +26 +52 +0 +59 +64 +75 +46 +60 +42 +34 +21 +64 +32 +16 +55 +0 +69 +53 +59 +7 +72 +49 +1 +43 +8 +62 +27 +48 +63 +62 +27 +62 +85 +80 +37 +75 +46 +46 +27 +46 +41 +50 +45 +59 +25 +40 +42 +47 +2 +22 +87 +32 +55 +42 +42 +41 +18 +1 +45 +32 +78 +46 +29 +40 +70 +45 +57 +57 +74 +30 +15 +58 +0 +22 +31 +54 +27 +88 +48 +40 +21 +86 +89 +42 +55 +46 +89 +56 +24 +35 +39 +58 +36 +32 +39 +60 +64 +0 +23 +59 +8 +39 +70 +80 +61 +76 +21 +9 +46 +48 +65 +34 +34 +40 +52 +27 +43 +43 +51 +39 +63 +23 +44 +1 +61 +12 +75 +10 +67 +30 +73 +63 +23 +44 +43 +38 +36 +52 +52 +14 +27 +63 +54 +30 +65 +60 +27 +16 +61 +26 +52 +64 +46 +18 +82 +2 +23 +59 +81 +51 +46 +35 +0 +64 +50 +45 +31 +40 +47 +50 +44 +30 +44 +53 +7 +44 +57 +12 +6 +34 +73 +72 +37 +21 +12 +18 +71 +41 +67 +24 +15 +27 +77 +74 +33 +76 +0 +42 +28 +51 +24 +27 +70 +42 +31 +48 +64 +51 +46 +32 +63 +41 +49 +37 +69 +40 +89 +6 +37 +63 +61 +33 +46 +21 +76 +40 +42 +63 +45 +31 +83 +64 +28 +35 +32 +54 +54 +85 +14 +37 +87 +57 +68 +34 +82 +52 +73 +22 +18 +16 +36 +20 +42 +34 +34 +46 +74 +62 +66 +49 +54 +87 +65 +87 +19 +42 +45 +35 +32 +44 +57 +39 +52 +26 +50 +21 +57 +63 +72 +32 +68 +79 +33 +71 +87 +79 +15 +40 +50 +68 +44 +44 +61 +45 +22 +47 +45 +49 +33 +70 +51 +25 +51 +8 +47 +45 +13 +38 +40 +87 +58 +37 +47 +65 +55 +68 +33 +44 +40 +46 +53 +48 +47 +76 +30 +48 +48 +33 +89 +23 +68 +32 +66 +30 +63 +29 +64 +64 +28 +62 +67 +70 +54 +54 +15 +35 +56 +41 +73 +39 +61 +86 +23 +18 +28 +67 +45 +90 +39 +40 +40 +25 +57 +43 +89 +32 +17 +68 +43 +82 +82 +37 +45 +63 +51 +58 +41 +54 +50 +27 +15 +44 +68 +24 +54 +6 +36 +27 +53 +26 +34 +68 +15 +85 +40 +41 +42 +8 +1 +68 +69 +65 +39 +66 +58 +70 +41 +33 +66 +59 +78 +56 +29 +76 +12 +47 +39 +70 +30 +16 +33 +38 +90 +47 +83 +60 +63 +46 +28 +31 +39 +46 +8 +33 +65 +20 +46 +74 +80 +62 +40 +47 +43 +1 +55 +34 +57 +45 +46 +53 +39 +71 +32 +26 +39 +0 +51 +43 +69 +49 +78 +32 +1 +50 +78 +6 +64 +31 +53 +37 +87 +32 +35 +64 +24 +36 +16 +88 +0 +60 +20 +0 +38 +52 +51 +56 +31 +43 +50 +66 +34 +64 +52 +34 +25 +61 +65 +56 +12 +56 +50 +24 +31 +60 +0 +67 +87 +57 +47 +27 +88 +34 +56 +56 +66 +47 +42 +57 +26 +48 +48 +58 +1 +11 +56 +69 +57 +28 +53 +63 +27 +17 +44 +32 +34 +25 +70 +54 +71 +44 +20 +27 +42 +35 +43 +23 +85 +41 +56 +3 +65 +60 +17 +9 +1 +90 +14 +89 +40 +62 +30 +70 +34 +23 +36 +38 +30 +53 +24 +11 +47 +0 +14 +50 +46 +75 +90 +0 +46 +9 +33 +24 +1 +50 +1 +39 +36 +45 +20 +49 +21 +49 +87 +46 +78 +4 +22 +14 +35 +25 +47 +26 +55 +4 +54 +70 +76 +69 +25 +55 +62 +87 +6 +57 +38 +31 +70 +60 +29 +22 +48 +63 +69 +17 +21 +24 +44 +43 +72 +53 +39 +45 +64 +35 +30 +65 +11 +20 +72 +70 +57 +63 +35 +59 +8 +24 +50 +69 +71 +44 +21 +43 +38 +75 +30 +36 +64 +70 +37 +59 +87 +16 +38 +18 +31 +49 +48 +60 +29 +43 +13 +56 +50 +53 +15 +18 +48 +66 +57 +50 +55 +36 +33 +88 +41 +74 +74 +86 +37 +5 +68 +37 +5 +11 +17 +71 +60 +32 +15 +65 +68 +0 +62 +35 +52 +60 +38 +42 +19 +49 +36 +83 +44 +55 +45 +33 +42 +54 +38 +23 +58 +43 +57 +52 +52 +58 +65 +26 +37 +64 +23 +50 +48 +63 +27 +62 +72 +22 +73 +89 +51 +38 +53 +50 +24 +46 +60 +14 +19 +27 +56 +80 +42 +27 +61 +47 +30 +47 +49 +68 +69 +28 +34 +56 +43 +49 +56 +33 +33 +38 +63 +48 +53 +19 +28 +87 +55 +56 +10 +3 +18 +4 +33 +20 +35 +46 +60 +34 +61 +14 +41 +52 +57 +11 +49 +20 +32 +42 +47 +62 +3 +44 +26 +43 +80 +56 +29 +65 +0 +46 +13 +27 +23 +77 +39 +63 +47 +38 +23 +43 +64 +85 +44 +54 +58 +23 +56 +13 +44 +72 +42 +6 +38 +61 +82 +53 +47 +62 +47 +16 +35 +44 +51 +47 +69 +48 +44 +76 +54 +54 +57 +35 +83 +53 +57 +82 +65 +88 +37 +43 +45 +14 +14 +24 +69 +69 +20 +25 +54 +21 +70 +64 +51 +24 +76 +45 +46 +0 +41 +5 +46 +54 +59 +49 +53 +55 +42 +47 +28 +83 +26 +28 +28 +37 +42 +15 +41 +41 +75 +35 +42 +39 +14 +40 +38 +63 +41 +51 +37 +70 +48 +78 +73 +27 +73 +53 +19 +66 +61 +26 +23 +31 +66 +90 +54 +8 +30 +28 +16 +80 +49 +8 +19 +66 +55 +51 +62 +76 +19 +57 +40 +8 +48 +9 +0 +61 +77 +68 +3 +40 +43 +60 +44 +48 +52 +31 +82 +56 +62 +1 +35 +24 +19 +55 +57 +52 +65 +27 +16 +48 +67 +17 +81 +60 +58 +53 +32 +28 +48 +43 +82 +88 +19 +44 +56 +18 +68 +22 +59 +22 +72 +66 +48 +44 +23 +76 +20 +43 +35 +40 +49 +30 +20 +10 +36 +81 +64 +25 +53 +10 +58 +34 +14 +30 +61 +68 +50 +64 +68 +10 +62 +31 +40 +65 +50 +89 +63 +31 +66 +74 +79 +45 +48 +38 +25 +10 +22 +81 +36 +47 +82 +60 +36 +37 +38 +55 +75 +67 +62 +59 +42 +60 +52 +51 +49 +52 +66 +43 +66 +88 +2 +50 +66 +77 +1 +80 +36 +11 +25 +13 +53 +0 +48 +41 +56 +2 +21 +48 +50 +6 +52 +42 +31 +74 +87 +57 +46 +49 +47 +23 +49 +46 +51 +84 +24 +24 +59 +72 +15 +60 +45 +58 +58 +61 +61 +36 +43 +28 +41 +77 +22 +42 +9 +28 +27 +11 +30 +49 +48 +23 +30 +15 +86 +53 +54 +13 +65 +60 +22 +58 +42 +41 +16 +78 +8 +41 +9 +27 +44 +26 +44 +1 +44 +25 +19 +23 +17 +59 +20 +24 +68 +62 +65 +5 +44 +54 +31 +59 +18 +26 +41 +48 +26 +42 +40 +22 +46 +60 +37 +82 +5 +70 +47 +34 +36 +64 +32 +39 +64 +39 +57 +32 +47 +16 +15 +60 +47 +14 +52 +14 +39 +56 +60 +41 +46 +42 +26 +71 +33 +63 +31 +53 +37 +70 +27 +31 +28 +13 +50 +28 +76 +55 +0 +6 +51 +81 +34 +52 +63 +52 +38 +87 +0 +1 +51 +35 +46 +76 +47 +15 +12 +53 +28 +26 +63 +50 +25 +73 +55 +27 +23 +54 +63 +5 +14 +77 +42 +46 +60 +62 +15 +46 +54 +38 +34 +87 +47 +42 +61 +29 +73 +78 +39 +10 +87 +32 +57 +51 +68 +50 +26 +48 +64 +67 +70 +23 +24 +49 +26 +6 +39 +45 +71 +65 +49 +16 +4 +41 +29 +46 +49 +71 +71 +30 +48 +64 +58 +58 +49 +37 +69 +19 +44 +76 +14 +44 +65 +33 +50 +67 +43 +34 +39 +19 +57 +60 +36 +72 +41 +48 +35 +51 +81 +42 +46 +35 +70 +67 +43 +45 +70 +51 +49 +37 +32 +60 +66 +42 +44 +28 +40 +45 +63 +13 +48 +45 +46 +39 +9 +57 +36 +57 +29 +67 +59 +30 +46 +4 +65 +72 +20 +88 +62 +6 +49 +30 +33 +37 +60 +42 +47 +47 +67 +46 +60 +87 +35 +64 +48 +43 +41 +63 +70 +63 +53 +87 +28 +29 +76 +0 +27 +19 +28 +80 +24 +64 +35 +74 +36 +41 +52 +10 +75 +38 +18 +30 +27 +15 +75 +53 +14 +19 +80 +36 +0 +20 +44 +30 +29 +84 +85 +48 +53 +18 +71 +69 +72 +54 +42 +17 +54 +60 +29 +38 +29 +46 +55 +58 +60 +56 +22 +0 +84 +0 +4 +36 +37 +25 +25 +63 +4 +41 +45 +34 +30 +51 +3 +40 +36 +79 +38 +57 +37 +37 +50 +57 +60 +33 +84 +35 +69 +30 +47 +32 +38 +54 +31 +21 +28 +50 +75 +45 +71 +67 +60 +44 +46 +42 +37 +46 +52 +30 +19 +46 +64 +65 +88 +49 +48 +69 +61 +55 +13 +88 +50 +24 +59 +39 +80 +57 +62 +56 +0 +20 +45 +71 +53 +0 +32 +43 +61 +30 +74 +14 +37 +42 +76 +33 +51 +52 +37 +43 +78 +21 +43 +45 +33 +49 +87 +23 +73 +49 +19 +63 +42 +51 +62 +52 +81 +51 +56 +57 +40 +61 +64 +46 +44 +36 +16 +41 +10 +52 +47 +40 +53 +73 +25 +56 +71 +49 +66 +52 +18 +87 +22 +44 +61 +68 +87 +26 +37 +17 +47 +42 +59 +18 +77 +17 +70 +46 +47 +55 +50 +32 +33 +66 +59 +35 +31 +65 +46 +42 +52 +55 +62 +42 +60 +42 +47 +28 +77 +35 +31 +41 +61 +52 +25 +53 +28 +67 +61 +64 +31 +45 +70 +70 +16 +64 +67 +30 +47 +21 +51 +22 +11 +70 +1 +57 +43 +88 +68 +48 +42 +58 +10 +29 +52 +59 +15 +59 +25 +25 +87 +58 +50 +76 +46 +47 +62 +33 +13 +32 +44 +14 +42 +80 +22 +20 +52 +36 +13 +85 +73 +43 +32 +13 +50 +53 +75 +11 +42 +53 +62 +20 +55 +37 +87 +29 +58 +38 +87 +31 +56 +15 +18 +32 +8 +69 +46 +50 +26 +48 +27 +51 +15 +54 +65 +54 +50 +52 +52 +48 +77 +62 +11 +24 +47 +57 +48 +34 +69 +57 +83 +40 +46 +31 +87 +68 +44 +42 +22 +64 +25 +83 +68 +60 +35 +34 +46 +78 +26 +13 +46 +57 +75 +22 +19 +48 +50 +18 +32 +26 +25 +8 +61 +70 +40 +21 +41 +40 +44 +62 +57 +64 +66 +49 +27 +69 +0 +26 +30 +21 +2 +37 +60 +86 +26 +26 +34 +29 +42 +55 +6 +61 +87 +26 +57 +8 +1 +87 +42 +70 +17 +52 +41 +49 +45 +54 +22 +40 +69 +12 +81 +58 +25 +74 +40 +87 +44 +31 +41 +0 +30 +87 +46 +60 +27 +69 +8 +49 +61 +89 +23 +52 +40 +58 +14 +28 +77 +12 +39 +30 +19 +51 +49 +80 +22 +26 +35 +55 +63 +58 +37 +42 +87 +66 +88 +53 +67 +31 +89 +20 +20 +6 +43 +48 +52 +76 +75 +56 +1 +14 +7 +74 +71 +55 +21 +65 +76 +64 +41 +18 +62 +3 +65 +20 +51 +31 +51 +69 +70 +34 +13 +17 +35 +55 +65 +35 +47 +16 +69 +36 +0 +54 +6 +61 +38 +50 +29 +56 +60 +32 +48 +56 +60 +79 +66 +41 +36 +80 +60 +40 +76 +69 +52 +42 +3 +16 +58 +64 +44 +36 +32 +19 +53 +1 +33 +61 +22 +77 +48 +74 +52 +31 +79 +52 +77 +42 +32 +52 +42 +30 +8 +22 +35 +44 +63 +41 +66 +58 +9 +37 +87 +43 +40 +31 +18 +66 +55 +53 +55 +48 +89 +35 +9 +22 +44 +26 +39 +55 +9 +47 +85 +28 +58 +57 +64 +22 +70 +51 +31 +53 +61 +18 +30 +45 +60 +69 +45 +46 +59 +58 +56 +56 +34 +53 +40 +0 +48 +59 +45 +89 +49 +26 +14 +65 +56 +63 +46 +59 +72 +62 +47 +20 +33 +6 +6 +58 +27 +55 +17 +14 +77 +50 +57 +89 +38 +41 +35 +65 +31 +41 +70 +43 +63 +50 +43 +55 +29 +41 +36 +36 +56 +66 +29 +73 +54 +14 +38 +41 +34 +29 +49 +60 +46 +51 +24 +34 +64 +86 +41 +43 +18 +48 +40 +51 +44 +56 +57 +82 +13 +59 +62 +37 +42 +39 +40 +5 +34 +58 +89 +50 +27 +20 +6 +30 +2 +9 +52 +24 +39 +1 +15 +45 +26 +25 +57 +42 +44 +56 +64 +9 +69 +60 +17 +44 +81 +8 +17 +83 +54 +24 +64 +57 +47 +47 +60 +48 +87 +30 +33 +43 +44 +54 +16 +55 +44 +58 +35 +36 +32 +46 +49 +74 +36 +46 +52 +49 +8 +52 +87 +38 +71 +12 +37 +85 +80 +26 +20 +45 +58 +46 +64 +58 +52 +73 +65 +25 +43 +45 +74 +29 +19 +74 +51 +20 +68 +57 +54 +69 +74 +38 +27 +31 +42 +20 +24 +49 +56 +65 +42 +71 +50 +63 +44 +31 +52 +33 +37 +19 +64 +58 +55 +74 +47 +48 +62 +87 +71 +78 +67 +72 +21 +5 +11 +71 +28 +34 +41 +57 +67 +28 +41 +40 +32 +37 +23 +0 +21 +41 +77 +42 +16 +41 +42 +56 +81 +48 +47 +28 +33 +57 +25 +22 +53 +51 +18 +19 +30 +23 +66 +51 +54 +56 +38 +10 +39 +55 +81 +40 +81 +60 +28 +72 +38 +46 +48 +17 +44 +40 +22 +46 +7 +37 +35 +67 +16 +29 +8 +35 +18 +35 +28 +22 +43 +34 +70 +44 +63 +36 +18 +22 +49 +44 +74 +49 +40 +30 +32 +87 +44 +69 +35 +86 +72 +44 +66 +13 +23 +30 +86 +16 +23 +15 +80 +5 +1 +47 +64 +40 +48 +75 +45 +89 +78 +45 +87 +14 +79 +85 +40 +8 +53 +65 +66 +55 +39 +58 +67 +59 +46 +71 +63 +40 +39 +23 +43 +30 +17 +46 +55 +28 +51 +38 +66 +38 +36 +60 +42 +23 +32 +46 +60 +44 +56 +63 +44 +2 +22 +46 +63 +47 +49 +30 +31 +34 +13 +66 +30 +68 +2 +66 +7 +41 +77 +57 +54 +35 +14 +41 +80 +14 +59 +30 +80 +57 +70 +46 +87 +41 +90 +86 +18 +40 +43 +42 +17 +42 +5 +59 +36 +72 +54 +36 +27 +4 +54 +52 +17 +80 +10 +36 +30 +20 +83 +43 +45 +30 +39 +83 +21 +25 +47 +75 +1 +15 +26 +50 +47 +14 +48 +19 +0 +17 +24 +55 +34 +41 +48 +19 +35 +38 +51 +17 +87 +70 +0 +2 +65 +59 +22 +22 +30 +75 +74 +46 +53 +28 +34 +19 +51 +33 +69 +43 +50 +71 +36 +24 +72 +10 +7 +79 +61 +83 +26 +60 +71 +29 +74 +34 +67 +60 +40 +50 +60 +36 +14 +8 +35 +30 +57 +44 +42 +89 +42 +59 +18 +66 +14 +58 +39 +67 +50 +14 +37 +63 +14 +47 +37 +64 +65 +9 +31 +64 +83 +47 +48 +38 +38 +64 +46 +54 +56 +48 +7 +58 +24 +54 +46 +44 +54 +32 +11 +86 +15 +21 +45 +33 +17 +38 +27 +37 +55 +4 +63 +41 +8 +35 +45 +29 +28 +42 +34 +11 +41 +21 +18 +63 +1 +35 +44 +65 +52 +40 +47 +31 +14 +83 +52 +45 +28 +53 +56 +67 +28 +66 +59 +47 +0 +33 +36 +72 +59 +2 +61 +62 +64 +44 +6 +42 +58 +57 +54 +25 +38 +38 +60 +43 +22 +78 +72 +76 +12 +44 +29 +87 +42 +35 +11 +69 +29 +15 +79 +26 +32 +10 +64 +51 +52 +52 +35 +29 +41 +52 +29 +33 +60 +36 +30 +75 +7 +39 +12 +33 +23 +14 +61 +6 +28 +10 +27 +27 +61 +69 +67 +46 +82 +24 +53 +46 +84 +47 +53 +39 +41 +55 +43 +85 +61 +48 +66 +13 +41 +18 +66 +47 +38 +30 +16 +53 +47 +50 +19 +32 +46 +23 +21 +61 +18 +48 +65 +19 +48 +49 +66 +47 +65 +23 +42 +69 +79 +78 +20 +56 +14 +71 +37 +19 +49 +5 +13 +17 +81 +33 +23 +40 +24 +47 +36 +72 +75 +69 +26 +21 +85 +61 +89 +31 +32 +64 +55 +46 +42 +29 +44 +17 +24 +79 +49 +48 +45 +39 +80 +37 +40 +62 +8 +68 +39 +70 +70 +46 +20 +37 +10 +36 +10 +64 +28 +46 +67 +38 +34 +58 +19 +64 +36 +42 +15 +50 +68 +26 +45 +14 +19 +47 +89 +25 +40 +22 +37 +90 +32 +39 +45 +7 +15 +51 +59 +0 +36 +61 +47 +56 +30 +40 +19 +13 +45 +61 +15 +40 +49 +16 +62 +78 +47 +73 +56 +1 +62 +26 +55 +54 +23 +23 +53 +25 +47 +50 +61 +31 +17 +47 +80 +6 +52 +30 +32 +55 +68 +49 +50 +45 +83 +42 +19 +54 +36 +36 +26 +51 +44 +57 +10 +31 +40 +45 +73 +55 +56 +1 +37 +27 +20 +40 +56 +32 +72 +82 +56 +48 +5 +55 +49 +48 +81 +38 +70 +40 +36 +57 +45 +73 +67 +57 +31 +39 +60 +13 +61 +26 +47 +21 +29 +54 +26 +34 +39 +43 +27 +25 +80 +28 +33 +34 +31 +43 +76 +40 +43 +9 +50 +69 +52 +46 +23 +0 +62 +36 +25 +57 +87 +8 +26 +43 +12 +38 +5 +57 +27 +14 +90 +50 +39 +61 +64 +30 +39 +13 +29 +71 +44 +76 +17 +89 +62 +65 +45 +65 +9 +50 +62 +79 +60 +55 +49 +71 +43 +33 +42 +65 +47 +0 +38 +14 +16 +45 +62 +24 +89 +31 +55 +75 +76 +88 +15 +41 +74 +0 +17 +36 +0 +58 +66 +30 +34 +69 +26 +28 +28 +44 +10 +54 +54 +57 +55 +60 +50 +55 +33 +31 +21 +60 +26 +58 +39 +61 +34 +50 +32 +50 +42 +66 +56 +16 +50 +46 +61 +44 +48 +20 +61 +23 +3 +34 +70 +53 +48 +29 +69 +5 +40 +10 +50 +68 +9 +13 +71 +26 +33 +86 +47 +1 +51 +4 +0 +59 +3 +42 +76 +49 +28 +45 +60 +67 +40 +47 +44 +33 +42 +9 +51 +89 +63 +36 +55 +73 +38 +85 +44 +7 +19 +68 +55 +62 +33 +28 +89 +38 +54 +28 +59 +73 +89 +52 +22 +89 +43 +25 +68 +18 +35 +49 +45 +20 +53 +40 +29 +33 +28 +69 +76 +86 +47 +65 +23 +30 +63 +27 +21 +47 +49 +31 +30 +11 +1 +83 +27 +37 +29 +14 +65 +43 +44 +5 +47 +55 +28 +44 +17 +42 +36 +84 +74 +66 +40 +33 +33 +56 +41 +21 +60 +47 +73 +30 +30 +41 +20 +44 +70 +7 +49 +49 +22 +66 +60 +83 +56 +64 +55 +71 +52 +56 +49 +37 +62 +40 +49 +46 +58 +37 +35 +48 +64 +0 +38 +57 +62 +40 +70 +77 +52 +48 +61 +17 +40 +40 +20 +17 +51 +83 +24 +60 +68 +27 +38 +47 +56 +51 +16 +53 +42 +39 +55 +42 +35 +52 +45 +79 +56 +88 +61 +13 +34 +60 +58 +65 +22 +25 +30 +88 +26 +44 +60 +32 +16 +63 +40 +47 +48 +12 +20 +51 +55 +74 +51 +64 +53 +34 +6 +34 +43 +24 +26 +1 +21 +20 +19 +35 +51 +49 +18 +13 +52 +50 +38 +54 +1 +84 +57 +27 +56 +49 +70 +41 +67 +30 +50 +11 +18 +35 +61 +88 +21 +71 +55 +18 +36 +86 +29 +89 +40 +53 +43 +88 +77 +70 +87 +42 +50 +31 +47 +81 +26 +55 +49 +49 +88 +26 +44 +37 +25 +67 +43 +21 +44 +47 +73 +77 +37 +63 +46 +59 +45 +60 +49 +52 +66 +27 +88 +39 +29 +31 +37 +67 +91 +19 +40 +46 +38 +32 +68 +28 +18 +32 +22 +59 +1 +19 +26 +42 +30 +0 +31 +70 +35 +56 +40 +38 +1 +63 +52 +15 +60 +17 +75 +31 +30 +25 +41 +26 +2 +43 +58 +89 +60 +46 +42 +57 +54 +59 +65 +40 +26 +22 +46 +40 +17 +33 +32 +6 +41 +21 +53 +52 +14 +33 +42 +63 +42 +56 +6 +18 +59 +24 +34 +26 +14 +0 +58 +80 +50 +16 +53 +2 +49 +46 +73 +70 +29 +49 +57 +2 +48 +14 +88 +41 +42 +44 +36 +42 +51 +51 +35 +61 +44 +63 +83 +77 +71 +36 +61 +88 +86 +46 +73 +62 +34 +44 +78 +45 +41 +51 +51 +79 +48 +52 +17 +1 +25 +53 +81 +42 +11 +59 +25 +52 +38 +19 +25 +2 +49 +66 +12 +25 +40 +61 +46 +16 +29 +38 +22 +53 +20 +29 +59 +56 +70 +52 +55 +52 +6 +27 +87 +30 +56 +32 +37 +54 +70 +69 +32 +35 +67 +47 +29 +24 +66 +70 +34 +52 +55 +54 +65 +13 +29 +70 +80 +3 +68 +62 +85 +27 +54 +52 +45 +64 +42 +45 +41 +72 +47 +28 +41 +51 +34 +76 +6 +24 +81 +10 +42 +30 +16 +58 +26 +53 +43 +64 +45 +86 +48 +68 +27 +41 +19 +89 +48 +61 +30 +67 +70 +51 +46 +60 +61 +37 +69 +65 +73 +56 +58 +45 +0 +49 +40 +49 +23 +58 +59 +60 +1 +75 +18 +5 +66 +15 +36 +33 +42 +59 +55 +88 +38 +35 +42 +41 +23 +27 +38 +28 +59 +79 +9 +39 +37 +18 +40 +62 +46 +31 +57 +56 +65 +55 +38 +55 +52 +46 +53 +81 +20 +35 +33 +50 +88 +68 +56 +47 +54 +41 +45 +34 +55 +40 +32 +23 +40 +28 +21 +61 +39 +87 +17 +56 +55 +39 +56 +63 +86 +47 +21 +24 +43 +59 +43 +56 +53 +48 +17 +50 +75 +76 +65 +56 +80 +90 +64 +4 +43 +16 +25 +48 +9 +1 +8 +2 +43 +48 +81 +47 +71 +13 +39 +49 +0 +23 +18 +54 +80 +47 +34 +33 +16 +40 +30 +41 +57 +78 +38 +47 +73 +68 +26 +62 +55 +41 +23 +19 +88 +65 +44 +56 +48 +37 +35 +55 +20 +55 +51 +87 +51 +63 +21 +71 +43 +64 +15 +31 +2 +57 +0 +62 +36 +43 +18 +65 +66 +1 +89 +26 +48 +28 +34 +40 +0 +89 +45 +19 +15 +32 +33 +24 +48 +48 +25 +69 +32 +54 +1 +34 +87 +53 +77 +46 +67 +40 +32 +80 +40 +34 +37 +51 +27 +50 +46 +89 +47 +0 +31 +54 +61 +12 +58 +55 +49 +68 +61 +32 +50 +0 +39 +65 +3 +0 +47 +1 +29 +72 +43 +22 +85 +60 +21 +12 +74 +12 +32 +19 +46 +39 +55 +43 +55 +73 +24 +32 +21 +62 +79 +54 +42 +73 +17 +87 +45 +63 +74 +21 +29 +5 +20 +10 +36 +34 +56 +37 +36 +62 +74 +66 +54 +13 +41 +64 +42 +26 +20 +5 +54 +32 +62 +55 +37 +80 +9 +35 +2 +33 +32 +51 +0 +50 +31 +53 +22 +30 +43 +57 +25 +46 +45 +19 +48 +20 +54 +46 +35 +23 +6 +43 +63 +29 +22 +70 +72 +11 +69 +42 +25 +37 +34 +39 +46 +30 +57 +1 +66 +46 +51 +46 +84 +78 +37 +48 +86 +54 +37 +65 +47 +87 +45 +58 +40 +54 +33 +38 +52 +67 +40 +18 +7 +51 +0 +52 +11 +42 +59 +13 +59 +54 +59 +45 +40 +53 +58 +71 +53 +60 +49 +49 +20 +56 +68 +27 +35 +78 +34 +52 +25 +46 +86 +54 +1 +54 +48 +35 +25 +43 +58 +1 +70 +76 +15 +87 +32 +89 +25 +7 +55 +54 +2 +84 +87 +42 +42 +1 +41 +52 +0 +21 +22 +39 +49 +3 +21 +23 +64 +1 +36 +48 +47 +8 +34 +67 +70 +49 +57 +0 +50 +18 +32 +59 +23 +13 +39 +58 +50 +37 +68 +23 +90 +47 +61 +19 +87 +47 +31 +16 +46 +23 +73 +44 +52 +40 +1 +0 +4 +53 +50 +26 +38 +31 +30 +54 +22 +56 +56 +1 +41 +49 +50 +66 +24 +58 +60 +65 +1 +85 +38 +35 +51 +45 +24 +22 +27 +37 +34 +56 +15 +46 +52 +32 +31 +88 +42 +39 +6 +40 +44 +22 +38 +29 +65 +52 +30 +39 +64 +60 +60 +61 +23 +33 +8 +14 +23 +33 +30 +42 +38 +70 +41 +47 +70 +49 +9 +44 +14 +1 +72 +39 +87 +33 +75 +29 +27 +28 +0 +62 +45 +44 +66 +30 +44 +5 +42 +26 +42 +75 +26 +23 +37 +31 +79 +30 +35 +33 +89 +10 +43 +58 +89 +64 +21 +68 +73 +11 +87 +66 +18 +10 +55 +35 +47 +6 +34 +1 +17 +13 +54 +33 +32 +17 +48 +60 +65 +16 +70 +48 +32 +67 +68 +89 +55 +68 +61 +51 +57 +53 +5 +40 +36 +52 +87 +47 +89 +30 +31 +62 +59 +50 +10 +55 +65 +44 +78 +56 +55 +27 +43 +72 +57 +48 +52 +39 +49 +22 +54 +6 +39 +1 +45 +72 +37 +36 +53 +87 +41 +61 +44 +22 +12 +44 +37 +61 +62 +44 +65 +58 +62 +78 +33 +88 +30 +75 +30 +78 +57 +12 +77 +42 +36 +66 +82 +45 +64 +38 +62 +45 +59 +38 +36 +70 +62 +25 +73 +14 +11 +85 +65 +42 +55 +16 +34 +26 +70 +42 +47 +76 +12 +19 +83 +14 +60 +33 +22 +21 +52 +35 +10 +47 +83 +57 +6 +32 +30 +35 +70 +26 +10 +23 +45 +48 +24 +21 +61 +51 +33 +22 +82 +42 +8 +80 +40 +57 +22 +63 +27 +41 +48 +24 +49 +17 +64 +27 +63 +67 +60 +12 +56 +43 +42 +61 +21 +42 +25 +15 +36 +79 +51 +49 +24 +46 +87 +89 +70 +37 +52 +18 +37 +42 +42 +24 +59 +72 +34 +61 +36 +25 +38 +38 +55 +70 +18 +63 +69 +24 +29 +39 +42 +55 +19 +27 +29 +77 +65 +79 +54 +30 +37 +54 +52 +26 +12 +82 +42 +74 +48 +12 +63 +53 +20 +40 +51 +55 +45 +36 +45 +48 +34 +72 +61 +13 +46 +73 +77 +15 +43 +24 +43 +39 +49 +27 +34 +44 +35 +57 +52 +42 +33 +77 +87 +24 +38 +45 +59 +41 +59 +81 +48 +76 +40 +32 +23 +48 +47 +38 +58 +56 +36 +29 +68 +88 +52 +41 +65 +8 +30 +75 +58 +41 +20 +22 +34 +62 +62 +58 +73 +69 +71 +70 +28 +54 +42 +54 +44 +45 +1 +42 +31 +64 +68 +25 +40 +33 +19 +73 +38 +0 +66 +42 +63 +20 +57 +25 +85 +42 +55 +62 +51 +26 +59 +23 +30 +36 +64 +24 +27 +60 +71 +88 +67 +26 +37 +79 +70 +36 +27 +62 +38 +11 +58 +54 +59 +25 +67 +55 +48 +60 +48 +50 +43 +28 +22 +17 +42 +17 +17 +76 +60 +31 +88 +30 +67 +57 +12 +33 +12 +74 +57 +79 +53 +17 +34 +40 +33 +86 +51 +42 +60 +27 +5 +86 +27 +74 +29 +43 +64 +41 +28 +54 +55 +25 +70 +55 +38 +38 +25 +48 +40 +41 +70 +77 +32 +49 +17 +24 +25 +37 +6 +56 +35 +32 +13 +44 +60 +63 +34 +42 +56 +6 +27 +41 +54 +64 +47 +21 +18 +25 +61 +47 +63 +34 +17 +10 +59 +44 +50 +53 +15 +64 +84 +58 +56 +54 +54 +30 +50 +21 +22 +40 +47 +1 +69 +32 +0 +36 +64 +8 +9 +13 +44 +25 +62 +39 +31 +58 +52 +43 +68 +36 +65 +50 +72 +7 +61 +38 +82 +71 +42 +2 +63 +72 +51 +37 +65 +47 +6 +30 +59 +35 +38 +35 +69 +55 +31 +32 +40 +52 +37 +45 +83 +56 +54 +30 +43 +57 +21 +69 +42 +87 +19 +34 +52 +23 +51 +62 +48 +89 +22 +61 +30 +28 +43 +77 +57 +43 +57 +65 +58 +41 +45 +28 +39 +41 +56 +69 +51 +47 +5 +63 +71 +28 +43 +59 +40 +48 +43 +77 +52 +65 +9 +34 +42 +67 +51 +31 +46 +89 +34 +53 +32 +36 +61 +72 +79 +40 +51 +4 +0 +82 +46 +50 +61 +42 +50 +51 +51 +26 +34 +52 +50 +67 +59 +20 +48 +24 +58 +27 +71 +32 +45 +39 +52 +42 +20 +38 +9 +31 +23 +65 +29 +39 +25 +73 +69 +20 +55 +24 +61 +39 +44 +29 +74 +32 +77 +8 +22 +60 +38 +76 +56 +44 +47 +31 +16 +66 +11 +57 +55 +67 +12 +90 +35 +68 +35 +21 +34 +43 +49 +25 +60 +53 +33 +62 +36 +65 +22 +46 +25 +31 +26 +66 +62 +0 +62 +53 +63 +78 +32 +62 +29 +49 +54 +29 +64 +8 +53 +26 +58 +42 +54 +89 +46 +10 +23 +33 +53 +35 +41 +34 +26 +52 +56 +59 +39 +22 +54 +75 +62 +51 +77 +58 +53 +68 +48 +37 +69 +71 +12 +58 +64 +30 +60 +14 +38 +42 +87 +21 +70 +72 +27 +88 +39 +39 +44 +28 +0 +45 +66 +50 +53 +2 +9 +2 +10 +40 +87 +47 +53 +44 +36 +23 +12 +37 +66 +61 +56 +37 +27 +61 +52 +66 +79 +75 +65 +62 +47 +29 +31 +29 +43 +29 +25 +61 +29 +72 +87 +74 +23 +81 +34 +49 +33 +49 +74 +41 +50 +82 +15 +39 +46 +74 +28 +42 +22 +59 +31 +35 +71 +41 +44 +66 +33 +9 +41 +41 +24 +16 +61 +32 +45 +45 +2 +17 +30 +8 +24 +89 +39 +47 +11 +31 +89 +23 +43 +73 +48 +13 +32 +48 +51 +31 +24 +35 +60 +75 +20 +71 +23 +30 +74 +86 +64 +53 +78 +58 +60 +83 +26 +28 +46 +33 +57 +65 +77 +34 +61 +41 +40 +32 +47 +58 +47 +25 +89 +32 +32 +19 +33 +87 +73 +48 +27 +36 +57 +66 +19 +18 +66 +20 +0 +41 +50 +20 +3 +11 +36 +44 +47 +28 +40 +47 +27 +52 +63 +26 +20 +34 +41 +67 +1 +69 +15 +31 +46 +50 +35 +31 +52 +47 +44 +65 +0 +17 +36 +43 +0 +53 +46 +50 +27 +27 +47 +35 +50 +61 +28 +48 +1 +68 +24 +32 +18 +77 +9 +7 +42 +1 +43 +43 +87 +51 +47 +40 +32 +35 +16 +36 +53 +26 +54 +74 +55 +77 +63 +75 +74 +30 +41 +45 +55 +54 +46 +41 +1 +31 +32 +39 +52 +10 +22 +58 +67 +87 +44 +74 +48 +19 +84 +30 +52 +46 +37 +32 +56 +0 +28 +51 +8 +31 +45 +12 +35 +70 +29 +13 +64 +26 +52 +30 +37 +45 +87 +71 +31 +63 +43 +31 +8 +54 +35 +30 +39 +54 +54 +50 +39 +49 +20 +29 +22 +56 +60 +22 +74 +63 +72 +20 +67 +57 +19 +41 +61 +72 +17 +53 +4 +36 +47 +28 +38 +9 +48 +38 +42 +32 +71 +83 +89 +46 +10 +45 +35 +44 +38 +6 +16 +53 +3 +54 +47 +1 +43 +58 +27 +20 +20 +42 +65 +43 +29 +37 +6 +64 +22 +14 +50 +15 +54 +62 +61 +76 +20 +55 +72 +47 +35 +14 +60 +61 +58 +74 +31 +38 +44 +70 +50 +49 +36 +72 +52 +60 +12 +74 +32 +14 +18 +7 +47 +28 +41 +2 +34 +31 +31 +40 +51 +47 +43 +1 +29 +26 +59 +77 +30 +35 +17 +38 +55 +35 +26 +78 +52 +36 +43 +89 +0 +40 +61 +1 +53 +30 +77 +13 +68 +19 +17 +22 +75 +69 +33 +28 +29 +38 +47 +51 +29 +62 +18 +42 +44 +29 +73 +46 +38 +60 +46 +53 +31 +0 +90 +1 +53 +70 +18 +53 +46 +76 +67 +58 +79 +89 +46 +57 +60 +58 +42 +36 +33 +26 +44 +12 +37 +69 +46 +63 +40 +26 +45 +31 +44 +57 +90 +57 +60 +44 +36 +29 +73 +70 +37 +63 +26 +28 +78 +25 +19 +70 +38 +37 +38 +13 +39 +51 +87 +26 +77 +46 +61 +30 +39 +88 +41 +52 +50 +59 +32 +71 +36 +37 +26 +47 +37 +48 +52 +38 +41 +34 +1 +53 +12 +20 +18 +38 +34 +42 +73 +55 +53 +21 +30 +27 +34 +48 +48 +48 +59 +50 +43 +51 +52 +19 +15 +69 +34 +0 +36 +2 +60 +62 +50 +44 +78 +88 +49 +51 +56 +67 +17 +69 +31 +52 +46 +34 +70 +55 +3 +17 +8 +54 +62 +21 +27 +1 +61 +39 +18 +36 +60 +69 +14 +19 +63 +62 +62 +56 +40 +70 +71 +67 +64 +48 +34 +90 +59 +49 +33 +37 +1 +58 +70 +51 +52 +28 +46 +9 +71 +36 +31 +44 +27 +88 +78 +50 +53 +27 +58 +41 +32 +55 +40 +27 +40 +23 +53 +0 +50 +60 +43 +35 +22 +48 +61 +36 +44 +73 +74 +51 +85 +79 +59 +73 +17 +21 +49 +20 +65 +29 +68 +47 +38 +83 +43 +59 +11 +63 +52 +34 +50 +51 +30 +22 +69 +62 +21 +37 +63 +28 +37 +45 +39 +77 +73 +34 +14 +59 +61 +60 +21 +88 +23 +72 +48 +38 +55 +23 +64 +64 +67 +59 +39 +15 +54 +51 +41 +75 +44 +46 +45 +43 +65 +90 +56 +17 +17 +33 +65 +45 +33 +35 +66 +64 +57 +72 +46 +30 +47 +58 +69 +56 +50 +33 +16 +45 +40 +59 +21 +30 +84 +67 +60 +25 +27 +54 +52 +28 +29 +42 +42 +81 +0 +31 +9 +22 +65 +54 +48 +6 +57 +42 +53 +44 +50 +44 +1 +2 +57 +89 +61 +50 +57 +65 +13 +11 +63 +49 +18 +46 +2 +0 +23 +53 +62 +80 +53 +39 +85 +33 +30 +12 +45 +49 +69 +81 +29 +51 +71 +20 +41 +4 +53 +34 +30 +29 +57 +2 +61 +54 +13 +55 +33 +52 +13 +0 +68 +77 +72 +53 +77 +24 +24 +51 +58 +48 +48 +43 +45 +57 +49 +58 +12 +53 +71 +29 +2 +55 +63 +66 +67 +38 +1 +63 +55 +54 +68 +19 +77 +43 +41 +18 +12 +63 +59 +57 +32 +50 +58 +40 +25 +52 +41 +33 +77 +24 +49 +28 +35 +49 +40 +84 +64 +64 +43 +16 +41 +40 +68 +58 +31 +15 +23 +22 +73 +65 +39 +31 +0 +45 +43 +1 +65 +33 +62 +7 +62 +75 +10 +43 +72 +17 +18 +13 +50 +61 +52 +69 +53 +63 +65 +44 +52 +57 +46 +54 +41 +44 +55 +25 +9 +26 +46 +63 +27 +1 +76 +66 +56 +34 +79 +0 +71 +32 +28 +75 +20 +31 +82 +42 +31 +46 +35 +15 +24 +33 +26 +62 +62 +87 +43 +27 +89 +19 +67 +48 +65 +48 +43 +59 +42 +36 +58 +63 +48 +30 +36 +40 +33 +53 +89 +67 +18 +65 +48 +51 +89 +49 +52 +49 +37 +55 +42 +29 +71 +36 +87 +11 +28 +53 +64 +62 +43 +68 +53 +60 +35 +57 +52 +21 +9 +18 +59 +80 +38 +76 +63 +70 +55 +64 +58 +43 +41 +43 +30 +84 +41 +64 +72 +11 +66 +34 +67 +23 +56 +44 +39 +43 +20 +57 +38 +87 +43 +13 +30 +0 +61 +63 +68 +44 +34 +37 +41 +47 +46 +50 +72 +33 +57 +25 +32 +17 +33 +44 +89 +85 +37 +59 +58 +36 +32 +54 +77 +43 +69 +70 +67 +27 +31 +25 +24 +51 +30 +30 +63 +68 +56 +60 +22 +36 +1 +44 +20 +44 +80 +68 +85 +62 +22 +13 +46 +86 +44 +3 +69 +32 +30 +2 +46 +11 +16 +58 +13 +43 +18 +37 +62 +64 +32 +50 +60 +7 +36 +82 +65 +6 +30 +64 +43 +0 +67 +74 +66 +38 +65 +72 +70 +10 +28 +58 +53 +35 +63 +77 +54 +54 +53 +66 +2 +33 +33 +49 +28 +22 +30 +45 +49 +20 +65 +36 +51 +49 +68 +39 +44 +44 +87 +39 +37 +22 +6 +30 +58 +59 +0 +36 +37 +40 +29 +31 +11 +39 +41 +11 +64 +68 +53 +72 +60 +42 +21 +39 +88 +51 +33 +36 +61 +63 +47 +9 +50 +83 +57 +36 +63 +79 +54 +59 +35 +43 +53 +54 +62 +36 +21 +29 +33 +47 +43 +55 +77 +46 +44 +33 +33 +54 +48 +30 +42 +35 +69 +63 +27 +72 +49 +36 +69 +87 +63 +30 +32 +67 +44 +18 +69 +36 +38 +67 +49 +25 +69 +59 +77 +45 +82 +39 +21 +33 +35 +47 +50 +54 +45 +51 +33 +25 +35 +20 +49 +53 +11 +38 +89 +32 +28 +50 +60 +36 +53 +69 +64 +31 +33 +80 +68 +42 +26 +27 +49 +88 +27 +68 +4 +18 +52 +63 +64 +45 +9 +26 +30 +57 +52 +64 +56 +54 +74 +89 +28 +42 +26 +71 +29 +49 +36 +35 +68 +26 +18 +1 +16 +22 +33 +40 +42 +65 +38 +61 +0 +49 +29 +52 +23 +46 +37 +49 +32 +36 +16 +28 +33 +32 +46 +19 +68 +58 +48 +51 +72 +60 +45 +36 +1 +33 +63 +36 +47 +16 +39 +31 +41 +43 +4 +44 +56 +81 +62 +63 +12 +52 +73 +34 +57 +19 +27 +54 +85 +87 +28 +61 +24 +35 +84 +52 +34 +61 +67 +53 +47 +55 +87 +51 +55 +35 +49 +22 +24 +36 +17 +50 +55 +29 +67 +6 +51 +50 +51 +12 +40 +61 +85 +41 +20 +56 +30 +47 +19 +25 +29 +17 +22 +39 +6 +42 +43 +13 +10 +13 +63 +59 +41 +63 +12 +73 +16 +25 +36 +47 +51 +47 +50 +25 +46 +46 +23 +25 +28 +73 +40 +48 +45 +33 +43 +46 +15 +73 +39 +57 +65 +40 +25 +70 +30 +21 +75 +77 +48 +49 +31 +31 +45 +58 +56 +63 +36 +45 +68 +82 +23 +59 +37 +61 +45 +60 +16 +63 +42 +68 +13 +52 +62 +51 +71 +49 +13 +52 +27 +85 +63 +36 +40 +70 +51 +40 +40 +68 +26 +56 +83 +77 +1 +41 +41 +58 +47 +26 +43 +41 +59 +52 +81 +63 +55 +50 +80 +50 +27 +59 +18 +36 +28 +32 +79 +54 +45 +43 +24 +18 +42 +40 +9 +41 +55 +49 +80 +71 +15 +14 +42 +1 +36 +19 +40 +18 +88 +47 +17 +65 +32 +32 +40 +26 +48 +87 +64 +15 +56 +32 +87 +42 +65 +83 +48 +66 +76 +15 +26 +88 +70 +30 +73 +29 +29 +55 +79 +74 +29 +44 +76 +51 +11 +53 +52 +45 +19 +43 +41 +35 +89 +28 +20 +33 +11 +27 +29 +74 +73 +45 +42 +74 +46 +39 +47 +46 +18 +33 +33 +64 +10 +32 +55 +62 +80 +72 +75 +72 +53 +31 +29 +17 +29 +10 +60 +88 +70 +49 +53 +40 +44 +20 +32 +70 +61 +69 +43 +23 +63 +57 +42 +35 +27 +67 +69 +15 +32 +45 +27 +31 +32 +31 +37 +78 +64 +53 +90 +47 +29 +49 +71 +9 +1 +78 +44 +77 +64 +54 +51 +57 +49 +46 +27 +35 +32 +59 +29 +67 +32 +0 +57 +72 +87 +44 +30 +38 +72 +42 +18 +17 +85 +61 +45 +8 +17 +59 +70 +35 +13 +48 +48 +75 +30 +30 +75 +79 +69 +22 +33 +89 +67 +40 +42 +34 +37 +55 +71 +71 +38 +18 +64 +34 +2 +54 +28 +3 +6 +87 +0 +31 +38 +43 +27 +50 +26 +48 +30 +46 +29 +18 +40 +54 +66 +49 +46 +34 +44 +55 +58 +1 +63 +35 +76 +80 +55 +77 +23 +45 +33 +83 +33 +44 +87 +87 +45 +24 +26 +10 +16 +90 +48 +2 +29 +63 +15 +63 +19 +39 +25 +23 +59 +62 +30 +21 +89 +77 +65 +52 +20 +12 +12 +40 +67 +59 +58 +89 +32 +75 +38 +54 +25 +37 +43 +68 +59 +26 +44 +0 +72 +4 +29 +37 +40 +4 +31 +36 +0 +23 +48 +83 +45 +23 +81 +54 +57 +31 +60 +62 +55 +53 +49 +35 +35 +34 +17 +0 +32 +88 +69 +39 +7 +32 +35 +25 +65 +26 +52 +26 +22 +59 +45 +56 +72 +40 +80 +37 +77 +5 +57 +5 +3 +51 +17 +51 +61 +50 +48 +50 +53 +63 +43 +60 +88 +74 +73 +89 +73 +76 +1 +62 +30 +36 +15 +34 +52 +45 +45 +31 +87 +21 +70 +52 +74 +29 +54 +27 +34 +34 +64 +67 +61 +61 +44 +66 +44 +73 +40 +45 +63 +28 +52 +30 +58 +14 +89 +51 +59 +63 +59 +22 +23 +40 +1 +57 +40 +5 +62 +86 +45 +11 +71 +55 +69 +40 +20 +57 +68 +74 +76 +24 +34 +33 +51 +24 +68 +68 +27 +37 +24 +60 +58 +10 +86 +35 +1 +42 +15 +51 +59 +72 +48 +62 +45 +58 +64 +29 +29 +23 +16 +57 +68 +20 +50 +56 +84 +24 +47 +44 +65 +39 +49 +33 +17 +53 +62 +27 +9 +15 +67 +24 +60 +28 +48 +70 +70 +33 +46 +12 +51 +66 +15 +45 +27 +42 +37 +63 +69 +47 +44 +62 +30 +48 +58 +35 +32 +38 +69 +12 +34 +48 +78 +31 +23 +36 +51 +66 +22 +41 +59 +36 +15 +18 +42 +86 +70 +66 +44 +57 +45 +0 +36 +36 +46 +42 +39 +49 +38 +54 +36 +66 +64 +16 +61 +7 +33 +53 +64 +84 +50 +31 +58 +33 +76 +69 +53 +48 +51 +86 +41 +24 +35 +31 +41 +49 +71 +18 +48 +11 +43 +37 +45 +23 +41 +37 +78 +48 +6 +33 +71 +35 +39 +70 +47 +59 +50 +33 +51 +52 +56 +24 +44 +31 +45 +5 +0 +40 +50 +52 +42 +41 +56 +80 +35 +47 +22 +73 +48 +23 +49 +20 +85 +58 +67 +78 +61 +12 +44 +55 +16 +42 +43 +64 +45 +68 +64 +47 +57 +70 +51 +38 +32 +34 +39 +59 +41 +0 +64 +9 +62 +48 +64 +65 +32 +41 +61 +33 +62 +0 +85 +53 +12 +15 +61 +39 +32 +39 +27 +15 +52 +49 +44 +45 +43 +45 +41 +62 +67 +28 +52 +80 +25 +57 +2 +38 +41 +35 +47 +44 +61 +64 +53 +31 +54 +43 +60 +70 +25 +48 +43 +34 +28 +87 +12 +64 +57 +74 +56 +19 +49 +44 +59 +41 +11 +42 +62 +31 +53 +45 +35 +19 +49 +48 +49 +9 +85 +30 +77 +3 +68 +24 +30 +71 +8 +40 +40 +9 +61 +87 +50 +38 +38 +51 +39 +66 +1 +55 +27 +2 +72 +12 +1 +55 +1 +47 +38 +74 +41 +10 +23 +16 +23 +20 +23 +45 +41 +71 +38 +46 +32 +69 +70 +32 +59 +75 +87 +45 +89 +79 +64 +16 +76 +35 +18 +32 +11 +78 +59 +43 +63 +59 +20 +27 +58 +71 +33 +61 +55 +88 +19 +44 +45 +64 +14 +43 +25 +33 +33 +1 +72 +86 +78 +56 +14 +35 +46 +48 +23 +32 +14 +16 +71 +9 +25 +79 +16 +72 +42 +35 +35 +59 +49 +37 +40 +67 +21 +21 +40 +11 +26 +63 +28 +47 +68 +17 +28 +61 +72 +87 +34 +5 +56 +35 +39 +30 +52 +47 +12 +34 +28 +62 +59 +50 +50 +58 +60 +17 +26 +34 +37 +1 +56 +87 +41 +19 +60 +36 +64 +34 +63 +44 +36 +41 +45 +46 +17 +10 +17 +38 +37 +68 +62 +5 +10 +76 +43 +27 +61 +45 +73 +19 +31 +42 +28 +68 +57 +71 +36 +0 +44 +45 +17 +41 +38 +70 +48 +27 +66 +51 +17 +16 +43 +62 +46 +40 +43 +16 +61 +49 +42 +74 +59 +60 +26 +24 +0 +41 +52 +19 +55 +41 +30 +19 +71 +86 +62 +29 +60 +30 +45 +24 +34 +63 +51 +37 +25 +26 +61 +27 +54 +61 +57 +74 +15 +56 +25 +0 +35 +41 +20 +73 +32 +86 +41 +80 +109 +76 +43 +47 +35 +76 +88 +55 +50 +17 +67 +23 +49 +73 +52 +44 +8 +35 +41 +1 +18 +5 +62 +90 +36 +18 +62 +72 +38 +35 +78 +63 +77 +40 +22 +36 +80 +25 +88 +52 +64 +15 +57 +55 +73 +37 +29 +23 +66 +50 +11 +37 +59 +23 +64 +32 +65 +58 +48 +0 +34 +50 +32 +17 +39 +55 +36 +42 +59 +49 +31 +77 +55 +58 +37 +73 +26 +42 +26 +65 +76 +11 +32 +57 +25 +70 +69 +56 +46 +54 +40 +49 +88 +50 +13 +53 +45 +9 +54 +41 +0 +35 +18 +32 +46 +52 +13 +19 +84 +72 +65 +32 +44 +81 +72 +3 +44 +5 +29 +40 +26 +52 +57 +31 +57 +23 +27 +47 +29 +27 +54 +36 +0 +40 +47 +40 +7 +46 +47 +86 +15 +63 +70 +40 +39 +32 +47 +0 +49 +51 +80 +42 +71 +52 +68 +89 +37 +1 +33 +30 +27 +20 +27 +10 +8 +24 +61 +63 +49 +37 +47 +62 +35 +28 +56 +33 +68 +32 +35 +9 +70 +56 +20 +42 +15 +77 +74 +65 +51 +62 +11 +58 +73 +52 +47 +28 +78 +76 +100 +133 +148 +78 +63 +50 +34 +68 +11 +21 +68 +80 +31 +58 +31 +30 +23 +34 +23 +74 +49 +40 +61 +53 +14 +59 +63 +31 +63 +21 +31 +49 +39 +30 +39 +30 +62 +41 +11 +25 +39 +21 +45 +47 +26 +58 +46 +89 +48 +42 +0 +27 +40 +42 +48 +61 +29 +56 +78 +54 +46 +12 +35 +55 +58 +42 +29 +46 +71 +76 +42 +68 +31 +14 +52 +46 +12 +59 +68 +57 +55 +89 +37 +30 +87 +16 +1 +56 +72 +51 +51 +35 +15 +9 +42 +62 +51 +66 +70 +24 +71 +32 +63 +19 +78 +64 +57 +27 +9 +45 +17 +51 +34 +29 +37 +61 +17 +32 +71 +61 +30 +53 +39 +19 +38 +33 +37 +67 +37 +28 +56 +61 +48 +38 +37 +28 +20 +26 +56 +34 +62 +65 +61 +53 +15 +19 +70 +67 +87 +64 +35 +39 +44 +65 +66 +48 +85 +27 +75 +6 +41 +1 +33 +70 +20 +52 +37 +85 +60 +23 +27 +79 +12 +54 +53 +6 +53 +59 +74 +39 +60 +78 +59 +57 +89 +65 +43 +38 +69 +41 +72 +26 +48 +40 +27 +41 +46 +59 +43 +169 +334 +335 +304 +150 +44 +88 +44 +16 +0 +73 +54 +75 +57 +54 +52 +59 +65 +69 +36 +29 +31 +71 +66 +35 +43 +53 +42 +39 +56 +88 +35 +40 +23 +46 +87 +73 +46 +56 +51 +53 +59 +7 +22 +70 +35 +20 +83 +25 +67 +65 +89 +53 +59 +59 +5 +32 +88 +36 +9 +74 +30 +39 +19 +70 +55 +47 +70 +16 +52 +68 +8 +59 +74 +38 +25 +17 +33 +27 +60 +61 +37 +31 +49 +39 +57 +44 +87 +26 +52 +18 +32 +64 +90 +28 +4 +33 +41 +24 +55 +36 +88 +49 +41 +58 +19 +57 +58 +65 +54 +52 +23 +19 +22 +23 +40 +38 +83 +30 +39 +39 +51 +41 +64 +63 +34 +34 +87 +60 +38 +67 +34 +57 +50 +52 +53 +59 +75 +60 +32 +64 +60 +74 +16 +21 +43 +28 +9 +43 +74 +16 +47 +80 +31 +89 +18 +14 +33 +70 +31 +43 +46 +65 +30 +27 +2 +39 +39 +47 +45 +43 +64 +35 +45 +40 +65 +15 +23 +46 +55 +57 +11 +59 +36 +58 +59 +16 +45 +9 +75 +21 +29 +37 +32 +28 +75 +24 +76 +109 +183 +370 +520 +467 +474 +479 +260 +136 +79 +58 +19 +67 +73 +42 +29 +77 +38 +86 +63 +19 +71 +63 +74 +58 +89 +36 +67 +43 +67 +87 +40 +20 +17 +83 +38 +64 +83 +64 +37 +50 +39 +2 +77 +70 +0 +9 +38 +61 +47 +54 +49 +43 +68 +48 +59 +62 +50 +84 +43 +39 +8 +71 +53 +38 +74 +47 +39 +32 +14 +57 +27 +46 +45 +56 +47 +49 +56 +77 +63 +26 +47 +44 +44 +45 +65 +29 +60 +60 +61 +63 +39 +66 +51 +38 +84 +26 +40 +28 +9 +39 +79 +48 +51 +1 +84 +58 +47 +61 +42 +28 +60 +70 +73 +45 +74 +68 +81 +36 +45 +73 +38 +54 +69 +31 +30 +69 +76 +56 +13 +44 +49 +0 +50 +39 +67 +41 +29 +33 +65 +36 +76 +65 +72 +0 +40 +0 +45 +2 +25 +37 +42 +63 +49 +47 +72 +8 +41 +49 +53 +57 +0 +81 +60 +3 +44 +25 +72 +1 +24 +31 +47 +75 +36 +36 +11 +10 +44 +8 +11 +20 +54 +21 +14 +44 +45 +45 +73 +33 +81 +16 +92 +31 +26 +30 +13 +47 +48 +53 +39 +213 +360 +682 +901 +770 +758 +897 +703 +490 +215 +134 +119 +114 +74 +53 +102 +79 +70 +63 +54 +66 +48 +59 +40 +50 +30 +52 +50 +33 +29 +32 +3 +19 +0 +16 +1 +49 +56 +36 +34 +63 +71 +73 +68 +33 +20 +55 +24 +73 +87 +50 +45 +32 +89 +31 +23 +75 +81 +45 +31 +86 +77 +37 +16 +80 +42 +55 +0 +0 +47 +66 +25 +0 +65 +46 +30 +61 +13 +66 +52 +27 +66 +42 +20 +69 +35 +48 +16 +78 +22 +21 +0 +36 +77 +58 +64 +3 +59 +45 +66 +30 +28 +89 +54 +34 +16 +35 +11 +36 +3 +14 +70 +59 +61 +50 +87 +54 +71 +35 +19 +36 +19 +57 +25 +25 +48 +54 +21 +30 +42 +59 +20 +79 +36 +52 +20 +59 +54 +37 +36 +54 +55 +35 +48 +79 +54 +56 +66 +61 +63 +38 +42 +89 +39 +23 +52 +22 +12 +71 +22 +16 +32 +70 +27 +23 +24 +55 +30 +60 +72 +71 +18 +27 +22 +80 +87 +52 +59 +54 +39 +71 +17 +53 +90 +29 +30 +69 +32 +42 +8 +22 +44 +84 +74 +47 +51 +117 +93 +79 +64 +93 +179 +633 +1074 +758 +621 +856 +863 +755 +544 +268 +155 +74 +68 +56 +55 +62 +60 +18 +3 +37 +23 +60 +47 +62 +23 +29 +73 +51 +34 +53 +49 +89 +67 +55 +32 +30 +29 +67 +21 +53 +45 +22 +63 +16 +66 +67 +61 +58 +15 +37 +37 +54 +69 +69 +66 +32 +58 +40 +52 +44 +60 +29 +72 +1 +23 +16 +24 +56 +73 +42 +59 +74 +40 +58 +56 +46 +26 +40 +59 +11 +87 +46 +33 +89 +35 +24 +49 +43 +55 +34 +24 +40 +72 +37 +33 +51 +70 +36 +27 +23 +47 +44 +51 +1 +63 +60 +23 +0 +45 +31 +44 +87 +37 +6 +66 +65 +52 +18 +39 +54 +60 +89 +0 +77 +58 +60 +30 +15 +63 +55 +75 +53 +57 +56 +15 +59 +38 +70 +45 +22 +48 +23 +41 +8 +78 +44 +19 +38 +47 +44 +78 +29 +0 +68 +64 +52 +60 +55 +34 +57 +27 +69 +24 +35 +17 +47 +45 +29 +29 +48 +69 +5 +87 +10 +73 +87 +59 +34 +28 +41 +63 +35 +27 +22 +63 +70 +42 +51 +43 +21 +13 +43 +59 +60 +59 +48 +40 +49 +79 +69 +177 +262 +830 +789 +691 +745 +380 +232 +117 +73 +33 +57 +54 +74 +27 +48 +76 +54 +60 +75 +50 +34 +50 +27 +2 +34 +42 +52 +70 +35 +67 +70 +47 +2 +60 +62 +38 +38 +65 +31 +83 +84 +41 +42 +50 +52 +68 +44 +36 +53 +72 +0 +60 +46 +30 +29 +15 +18 +55 +38 +35 +44 +44 +54 +56 +70 +59 +69 +61 +33 +81 +16 +72 +76 +39 +23 +32 +29 +49 +41 +63 +3 +55 +45 +69 +1 +53 +39 +47 +69 +69 +59 +24 +35 +40 +44 +57 +57 +42 +42 +25 +65 +58 +65 +17 +21 +36 +44 +26 +58 +47 +73 +46 +58 +31 +71 +17 +57 +74 +38 +33 +80 +36 +50 +58 +69 +18 +87 +68 +54 +2 +67 +72 +52 +56 +59 +89 +60 +41 +30 +17 +23 +28 +37 +8 +78 +42 +31 +30 +17 +3 +42 +80 +44 +48 +33 +56 +38 +21 +57 +13 +45 +20 +48 +89 +60 +48 +52 +8 +42 +57 +38 +33 +47 +39 +0 +64 +70 +50 +21 +14 +63 +8 +27 +55 +21 +63 +42 +14 +53 +65 +26 +75 +39 +39 +65 +20 +71 +53 +79 +128 +101 +267 +599 +629 +219 +39 +40 +77 +63 +53 +78 +87 +42 +46 +57 +44 +2 +89 +27 +66 +41 +51 +63 +35 +42 +56 +71 +39 +13 +19 +9 +0 +33 +51 +10 +19 +55 +43 +73 +52 +40 +29 +41 +39 +33 +64 +63 +25 +10 +27 +57 +21 +45 +64 +47 +68 +6 +45 +63 +50 +87 +38 +81 +47 +30 +71 +52 +49 +66 +58 +76 +59 +45 +49 +67 +25 +34 +64 +22 +63 +42 +19 +57 +23 +89 +26 +45 +64 +71 +61 +44 +42 +53 +7 +46 +33 +45 +34 +35 +24 +34 +34 +39 +68 +29 +49 +24 +34 +24 +45 +66 +30 +49 +50 +37 +47 +38 +38 +72 +41 +36 +35 +53 +61 +37 +52 +57 +25 +62 +51 +27 +60 +25 +87 +52 +43 +33 +90 +43 +28 +10 +73 +8 +60 +37 +52 +35 +41 +51 +62 +59 +60 +87 +49 +33 +37 +13 +87 +59 +28 +27 +58 +0 +0 +45 +47 +50 +36 +30 +52 +47 +7 +35 +9 +64 +67 +22 +75 +82 +41 +65 +54 +54 +74 +49 +88 +51 +33 +24 +78 +38 +48 +20 +26 +47 +35 +60 +49 +44 +54 +49 +105 +206 +476 +227 +41 +79 +44 +21 +84 +28 +37 +35 +39 +22 +80 +77 +22 +3 +40 +33 +48 +41 +73 +25 +0 +39 +28 +64 +28 +14 +76 +64 +77 +44 +24 +55 +58 +64 +45 +51 +81 +2 +80 +35 +12 +57 +16 +29 +45 +60 +55 +42 +31 +35 +31 +37 +54 +17 +37 +37 +68 +64 +63 +87 +52 +52 +10 +30 +73 +46 +88 +44 +27 +40 +23 +58 +25 +21 +50 +34 +55 +45 +54 +89 +46 +41 +3 +60 +34 +28 +63 +38 +50 +57 +0 +65 +45 +3 +24 +63 +56 +54 +76 +30 +47 +37 +33 +49 +32 +0 +28 +65 +26 +60 +57 +30 +64 +74 +45 +29 +61 +2 +43 +40 +9 +65 +32 +58 +11 +58 +3 +20 +2 +46 +70 +56 +82 +46 +0 +28 +75 +19 +40 +62 +18 +69 +55 +45 +70 +1 +80 +44 +70 +37 +69 +72 +68 +49 +89 +31 +64 +37 +30 +44 +63 +22 +69 +29 +89 +32 +45 +51 +59 +43 +49 +28 +45 +10 +58 +64 +72 +59 +37 +36 +43 +19 +62 +80 +75 +68 +87 +59 +40 +56 +29 +60 +19 +40 +3 +59 +54 +64 +173 +201 +74 +41 +37 +21 +31 +64 +68 +75 +57 +39 +32 +62 +61 +57 +23 +46 +45 +22 +0 +74 +13 +30 +23 +41 +42 +44 +83 +24 +51 +32 +19 +34 +42 +33 +0 +56 +34 +18 +60 +69 +29 +59 +45 +1 +56 +39 +32 +87 +19 +71 +74 +11 +0 +83 +33 +48 +49 +57 +15 +87 +3 +20 +69 +28 +27 +26 +67 +31 +59 +40 +73 +82 +11 +41 +27 +89 +69 +85 +29 +32 +27 +34 +46 +42 +19 +42 +18 +29 +26 +54 +81 +71 +24 +62 +68 +69 +31 +65 +12 +84 +42 +48 +46 +19 +33 +39 +11 +47 +49 +48 +18 +20 +49 +71 +11 +82 +55 +3 +32 +39 +69 +43 +65 +74 +53 +44 +44 +32 +40 +52 +68 +18 +52 +26 +47 +62 +25 +45 +3 +61 +43 +78 +59 +23 +80 +7 +70 +30 +77 +57 +47 +44 +67 +42 +66 +63 +24 +90 +82 +3 +66 +63 +9 +33 +22 +32 +43 +39 +48 +56 +26 +57 +35 +52 +36 +20 +41 +0 +19 +55 +35 +17 +9 +53 +13 +78 +50 +28 +46 +57 +38 +33 +27 +35 +24 +22 +76 +54 +53 +79 +100 +93 +72 +37 +20 +27 +28 +31 +51 +33 +21 +56 +75 +57 +87 +87 +54 +7 +20 +68 +39 +64 +49 +34 +38 +34 +34 +41 +30 +42 +57 +22 +35 +57 +31 +65 +21 +61 +31 +36 +58 +16 +68 +36 +25 +40 +44 +42 +67 +81 +52 +11 +62 +19 +54 +21 +21 +62 +22 +83 +29 +44 +49 +0 +26 +65 +88 +51 +16 +47 +21 +53 +30 +64 +43 +36 +85 +62 +43 +25 +47 +7 +69 +60 +71 +34 +56 +42 +78 +10 +67 +49 +69 +56 +61 +20 +48 +15 +57 +11 +46 +60 +74 +0 +71 +17 +34 +47 +16 +84 +49 +20 +54 +54 +34 +63 +39 +68 +18 +29 +53 +42 +53 +44 +65 +45 +72 +65 +56 +23 +33 +54 +23 +15 +38 +30 +51 +46 +29 +26 +14 +53 +56 +61 +58 +29 +23 +67 +30 +31 +68 +43 +40 +49 +57 +49 +60 +1 +34 +36 +56 +61 +28 +73 +44 +43 +48 +31 +54 +26 +34 +15 +71 +64 +20 +29 +32 +18 +53 +52 +70 +22 +38 +31 +72 +90 +87 +26 +42 +19 +72 +44 +42 +28 +52 +30 +24 +43 +67 +76 +60 +81 +73 +76 +41 +67 +62 +35 +59 +38 +56 +65 +35 +35 +38 +87 +23 +78 +41 +28 +44 +79 +30 +23 +63 +81 +39 +13 +16 +33 +49 +68 +89 +23 +55 +50 +71 +56 +12 +49 +66 +68 +78 +88 +54 +77 +24 +51 +50 +70 +90 +85 +89 +46 +0 +68 +70 +39 +71 +50 +0 +64 +85 +54 +50 +27 +16 +19 +43 +27 +58 +23 +36 +76 +49 +53 +25 +24 +81 +11 +72 +44 +75 +49 +49 +26 +0 +25 +65 +61 +74 +52 +7 +60 +44 +59 +59 +48 +51 +26 +89 +57 +48 +46 +64 +49 +29 +31 +55 +40 +38 +45 +25 +25 +28 +48 +10 +47 +61 +15 +16 +13 +33 +57 +27 +61 +73 +7 +65 +78 +42 +13 +35 +47 +77 +38 +45 +87 +61 +31 +50 +38 +67 +24 +8 +49 +60 +63 +70 +21 +26 +41 +54 +8 +21 +70 +54 +29 +54 +49 +16 +46 +50 +70 +57 +19 +63 +72 +45 +55 +53 +14 +46 +42 +40 +55 +41 +54 +28 +19 +39 +86 +38 +54 +31 +72 +37 +39 +74 +89 +44 +48 +47 +69 +0 +37 +47 +59 +71 +62 +46 +48 +47 +44 +69 +18 +36 +27 +45 +58 +52 +30 +25 +41 +63 +45 +50 +79 +36 +21 +15 +19 +42 +72 +57 +53 +18 +39 +35 +34 +50 +54 +36 +89 +40 +74 +42 +51 +80 +61 +27 +65 +35 +54 +68 +31 +25 +45 +40 +41 +39 +32 +62 +79 +70 +9 +77 +44 +45 +19 +44 +28 +48 +51 +69 +30 +46 +34 +48 +19 +15 +61 +37 +71 +64 +39 +38 +33 +17 +50 +28 +61 +87 +64 +34 +40 +55 +51 +62 +17 +24 +59 +58 +7 +24 +44 +29 +45 +58 +61 +35 +26 +56 +14 +53 +43 +39 +60 +25 +41 +58 +21 +23 +21 +62 +30 +48 +45 +49 +40 +28 +56 +37 +17 +40 +56 +44 +56 +40 +38 +34 +21 +62 +30 +27 +41 +63 +46 +46 +76 +43 +52 +79 +67 +23 +40 +58 +32 +41 +62 +46 +50 +46 +77 +20 +21 +63 +18 +88 +27 +55 +86 +63 +56 +51 +22 +21 +53 +47 +25 +10 +59 +77 +63 +8 +57 +28 +35 +53 +14 +42 +23 +36 +70 +26 +58 +60 +63 +70 +48 +43 +37 +66 +79 +44 +21 +30 +59 +10 +19 +52 +41 +42 +14 +60 +14 +76 +63 +31 +37 +50 +25 +44 +50 +29 +71 +26 +77 +12 +49 +67 +30 +27 +39 +72 +89 +16 +26 +57 +40 +38 +6 +9 +53 +39 +41 +38 +45 +54 +31 +38 +22 +35 +65 +36 +85 +22 +27 +54 +67 +47 +65 +50 +55 +60 +38 +44 +24 +59 +52 +29 +36 +36 +39 +10 +16 +3 +48 +45 +54 +24 +37 +11 +73 +45 +41 +70 +32 +44 +69 +32 +44 +31 +55 +39 +53 +59 +68 +89 +77 +62 +22 +38 +62 +33 +87 +55 +21 +23 +21 +77 +27 +87 +50 +26 +89 +44 +85 +46 +41 +23 +40 +56 +28 +58 +50 +46 +49 +90 +35 +88 +43 +43 +29 +72 +13 +35 +38 +25 +19 +44 +19 +58 +22 +57 +50 +10 +52 +32 +26 +50 +24 +46 +49 +0 +41 +56 +52 +16 +19 +68 +30 +73 +32 +70 +25 +69 +44 +54 +28 +63 +70 +69 +32 +66 +31 +37 +76 +55 +44 +32 +26 +63 +32 +20 +39 +87 +14 +36 +78 +30 +58 +45 +62 +51 +35 +67 +19 +42 +39 +56 +54 +75 +66 +50 +55 +8 +63 +89 +71 +60 +56 +62 +50 +63 +66 +22 +8 +42 +49 +88 +19 +62 +50 +53 +40 +81 +34 +53 +52 +23 +48 +86 +78 +42 +84 +43 +29 +44 +57 +58 +27 +30 +42 +31 +44 +32 +12 +31 +43 +57 +32 +49 +71 +67 +69 +78 +87 +23 +66 +5 +50 +1 +56 +23 +59 +45 +36 +58 +44 +85 +20 +54 +4 +1 +45 +63 +39 +79 +15 +74 +83 +47 +30 +42 +44 +86 +63 +43 +52 +53 +52 +71 +47 +57 +18 +56 +84 +65 +62 +59 +67 +18 +57 +41 +49 +58 +69 +29 +58 +41 +36 +46 +26 +41 +1 +50 +31 +31 +64 +32 +0 +49 +50 +49 +17 +53 +29 +37 +57 +36 +71 +31 +90 +14 +8 +22 +14 +69 +78 +5 +42 +43 +78 +41 +35 +61 +40 +55 +49 +19 +61 +71 +31 +0 +3 +54 +1 +46 +29 +51 +56 +46 +9 +71 +89 +68 +65 +86 +34 +43 +35 +45 +49 +44 +72 +54 +43 +56 +1 +53 +9 +22 +54 +22 +57 +18 +75 +16 +22 +71 +40 +36 +42 +62 +63 +57 +27 +75 +45 +20 +16 +23 +79 +65 +39 +53 +78 +52 +47 +15 +64 +47 +23 +78 +50 +71 +50 +52 +70 +65 +60 +17 +26 +76 +56 +48 +33 +15 +22 +50 +37 +27 +38 +82 +11 +32 +24 +54 +76 +26 +55 +59 +42 +50 +46 +12 +37 +71 +42 +67 +36 +22 +52 +45 +73 +46 +47 +26 +15 +27 +47 +36 +87 +33 +13 +76 +42 +47 +70 +30 +3 +12 +13 +9 +44 +45 +60 +16 +76 +22 +59 +2 +36 +75 +39 +2 +46 +54 +0 +48 +25 +56 +20 +26 +24 +67 +26 +16 +59 +23 +20 +40 +62 +38 +66 +51 +61 +71 +61 +25 +23 +87 +86 +43 +29 +37 +63 +44 +37 +52 +54 +35 +38 +55 +57 +14 +38 +36 +15 +62 +78 +53 +52 +65 +32 +50 +49 +66 +67 +54 +50 +63 +34 +16 +1 +22 +68 +29 +70 +72 +25 +72 +1 +36 +36 +0 +60 +51 +46 +45 +36 +42 +56 +13 +57 +46 +52 +50 +72 +37 +37 +80 +59 +21 +81 +9 +27 +55 +53 +60 +10 +68 +77 +50 +71 +87 +53 +24 +58 +55 +27 +40 +16 +37 +5 +59 +52 +36 +51 +65 +72 +34 +29 +33 +24 +89 +54 +31 +61 +0 +62 +27 +23 +38 +55 +39 +30 +30 +69 +57 +17 +62 +58 +8 +57 +37 +54 +87 +64 +37 +86 +30 +81 +47 +35 +25 +58 +33 +52 +28 +87 +2 +66 +34 +40 +42 +53 +58 +46 +42 +56 +16 +37 +48 +45 +64 +66 +50 +54 +57 +41 +18 +42 +71 +73 +17 +40 +58 +0 +32 +36 +57 +17 +35 +38 +45 +60 +74 +53 +88 +64 +64 +7 +47 +12 +1 +4 +58 +26 +45 +29 +24 +35 +63 +60 +27 +24 +37 +35 +41 +24 +27 +85 +56 +41 +81 +87 +71 +61 +48 +48 +23 +54 +85 +60 +44 +70 +51 +81 +87 +57 +57 +12 +44 +33 +50 +58 +63 +50 +36 +80 +33 +23 +63 +24 +63 +16 +57 +84 +49 +43 +44 +54 +10 +31 +61 +28 +48 +53 +18 +59 +39 +0 +35 +53 +51 +25 +34 +14 +42 +39 +55 +44 +16 +23 +44 +51 +52 +7 +90 +23 +59 +50 +51 +67 +46 +42 +29 +33 +73 +3 +63 +34 +19 +43 +78 +41 +57 +44 +87 +61 +4 +41 +31 +75 +41 +77 +61 +86 +37 +73 +64 +53 +61 +47 +39 +31 +46 +45 +26 +85 +62 +75 +53 +31 +46 +23 +38 +36 +21 +0 +44 +32 +61 +16 +45 +45 +25 +35 +28 +55 +75 +37 +65 +84 +74 +60 +58 +28 +30 +39 +26 +48 +35 +1 +45 +84 +23 +26 +7 +1 +28 +55 +64 +67 +0 +89 +87 +73 +30 +21 +49 +68 +43 +23 +61 +70 +59 +41 +30 +38 +54 +62 +73 +80 +33 +34 +25 +14 +42 +33 +48 +86 +51 +53 +33 +71 +62 +79 +58 +17 +87 +38 +53 +24 +58 +49 +12 +44 +10 +0 +33 +79 +31 +40 +64 +1 +47 +16 +67 +38 +37 +55 +46 +32 +36 +36 +21 +61 +10 +33 +71 +34 +17 +26 +62 +70 +60 +44 +38 +83 +22 +40 +1 +67 +18 +73 +37 +60 +56 +1 +54 +26 +50 +65 +39 +52 +61 +35 +34 +19 +59 +82 +46 +39 +54 +80 +52 +81 +54 +28 +89 +55 +48 +67 +87 +77 +84 +73 +42 +47 +44 +62 +48 +55 +50 +33 +14 +31 +20 +79 +59 +77 +26 +25 +33 +8 +57 +32 +3 +28 +45 +82 +60 +31 +27 +51 +31 +36 +70 +69 +43 +25 +54 +29 +85 +29 +66 +56 +34 +71 +37 +19 +36 +45 +15 +40 +66 +31 +63 +64 +48 +0 +21 +40 +79 +46 +49 +24 +20 +34 +52 +2 +49 +36 +13 +25 +46 +31 +49 +44 +53 +39 +70 +27 +48 +41 +14 +50 +21 +69 +28 +26 +20 +36 +48 +2 +71 +24 +41 +41 +46 +66 +51 +23 +60 +19 +32 +43 +77 +72 +55 +65 +31 +68 +39 +57 +36 +58 +49 +36 +67 +26 +50 +23 +37 +39 +72 +77 +43 +61 +28 +13 +52 +33 +77 +41 +84 +57 +85 +33 +76 +69 +19 +37 +41 +54 +12 +30 +50 +81 +20 +41 +24 +71 +19 +35 +68 +25 +28 +41 +57 +22 +54 +68 +76 +63 +39 +51 +56 +80 +62 +38 +59 +54 +53 +56 +52 +27 +27 +39 +19 +46 +56 +37 +33 +43 +83 +29 +61 +89 +42 +45 +60 +27 +47 +56 +66 +48 +24 +48 +22 +78 +41 +57 +50 +40 +59 +17 +46 +81 +75 +40 +44 +67 +42 +53 +36 +59 +12 +74 +66 +34 +58 +31 +53 +58 +37 +6 +41 +63 +14 +30 +53 +61 +39 +35 +52 +64 +69 +18 +59 +57 +69 +45 +58 +71 +31 +19 +40 +51 +38 +59 +20 +32 +32 +52 +38 +18 +25 +73 +73 +48 +62 +25 +21 +90 +5 +65 +53 +84 +38 +55 +87 +0 +15 +45 +50 +56 +49 +33 +49 +73 +59 +4 +68 +56 +31 +33 +45 +41 +28 +65 +46 +26 +52 +62 +63 +60 +64 +20 +67 +36 +19 +42 +74 +31 +44 +88 +90 +30 +2 +36 +12 +42 +14 +24 +50 +58 +75 +18 +26 +50 +48 +48 +86 +32 +45 +62 +74 +45 +59 +22 +55 +75 +55 +32 +67 +34 +56 +30 +33 +63 +28 +73 +38 +57 +40 +79 +76 +10 +57 +57 +10 +70 +89 +79 +50 +46 +58 +34 +13 +66 +38 +27 +10 +18 +12 +82 +41 +71 +59 +59 +45 +30 +51 +33 +48 +13 +62 +28 +34 +52 +18 +58 +60 +29 +53 +61 +38 +24 +58 +31 +27 +45 +59 +21 +39 +66 +40 +30 +46 +30 +60 +66 +53 +45 +0 +33 +73 +71 +59 +64 +55 +40 +26 +29 +40 +73 +84 +61 +0 +33 +35 +34 +52 +56 +46 +70 +67 +63 +19 +47 +90 +29 +65 +48 +59 +4 +68 +59 +31 +47 +57 +22 +10 +48 +62 +46 +47 +49 +67 +67 +56 +35 +46 +66 +59 +76 +33 +71 +38 +70 +38 +0 +53 +5 +9 +55 +57 +63 +19 +29 +66 +52 +57 +69 +64 +15 +57 +29 +52 +7 +87 +50 +25 +23 +39 +16 +59 +51 +53 +67 +50 +63 +35 +38 +45 +24 +83 +42 +28 +36 +52 +29 +75 +57 +30 +40 +52 +40 +52 +36 +25 +31 +37 +24 +19 +54 +56 +73 +28 +39 +60 +5 +53 +30 +14 +85 +15 +44 +4 +87 +64 +27 +67 +48 +36 +24 +31 +2 +28 +47 +19 +29 +70 +46 +40 +0 +28 +49 +52 +33 +36 +3 +19 +19 +88 +64 +53 +45 +52 +70 +73 +40 +42 +59 +74 +57 +40 +62 +31 +60 +0 +36 +74 +48 +69 +5 +33 +33 +48 +18 +63 +34 +43 +61 +39 +45 +43 +40 +19 +74 +75 +31 +17 +7 +22 +0 +78 +24 +64 +30 +47 +25 +34 +62 +72 +83 +1 +41 +44 +42 +43 +57 +87 +42 +63 +44 +60 +49 +57 +32 +16 +24 +61 +57 +12 +56 +39 +54 +46 +42 +44 +3 +89 +74 +84 +28 +18 +22 +51 +50 +71 +77 +26 +28 +56 +8 +57 +52 +55 +71 +58 +42 +23 +14 +70 +61 +20 +52 +73 +65 +35 +55 +71 +23 +47 +24 +46 +41 +39 +17 +64 +26 +62 +58 +46 +67 +7 +71 +62 +37 +35 +47 +87 +45 +63 +52 +15 +53 +21 +51 +57 +33 +31 +39 +26 +41 +59 +55 +40 +22 +67 +42 +59 +57 +37 +34 +69 +55 +14 +53 +45 +56 +1 +29 +15 +60 +52 +68 +39 +43 +24 +23 +51 +44 +7 +54 +51 +60 +57 +83 +40 +82 +0 +31 +63 +77 +26 +57 +30 +49 +42 +40 +56 +59 +69 +21 +26 +41 +43 +9 +65 +89 +39 +25 +49 +34 +43 +26 +67 +53 +31 +63 +53 +14 +67 +40 +69 +46 +41 +47 +27 +33 +2 +43 +43 +32 +32 +72 +6 +14 +41 +55 +85 +22 +39 +28 +8 +52 +13 +63 +32 +58 +41 +77 +12 +47 +45 +1 +41 +56 +53 +8 +60 +65 +43 +89 +18 +15 +37 +70 +54 +22 +26 +44 +33 +50 +25 +73 +27 +27 +25 +14 +66 +55 +33 +58 +62 +22 +49 +18 +30 +12 +36 +62 +58 +85 +70 +45 +41 +79 +39 +53 +11 +13 +11 +33 +8 +30 +47 +16 +34 +0 +33 +89 +44 +34 +53 +54 +42 +37 +35 +46 +33 +40 +60 +44 +24 +53 +82 +41 +42 +1 +1 +27 +37 +52 +47 +61 +70 +46 +8 +87 +70 +50 +10 +43 +87 +44 +20 +42 +57 +58 +57 +31 +46 +75 +26 +20 +32 +17 +50 +36 +1 +64 +60 +38 +57 +80 +39 +42 +13 +0 +86 +66 +37 +56 +51 +30 +62 +71 +58 +52 +62 +47 +21 +23 +21 +34 +47 +31 +32 +41 +47 +79 +28 +73 +74 +40 +52 +89 +22 +59 +72 +15 +42 +75 +71 +23 +18 +58 +25 +45 +41 +34 +58 +48 +62 +65 +11 +57 +34 +48 +61 +60 +70 +69 +35 +39 +59 +7 +14 +35 +54 +59 +79 +67 +41 +72 +61 +9 +15 +33 +10 +33 +30 +64 +47 +29 +64 +47 +35 +64 +73 +4 +38 +36 +41 +38 +61 +47 +30 +43 +43 +30 +46 +62 +59 +70 +44 +25 +56 +42 +46 +43 +70 +22 +61 +46 +59 +36 +46 +58 +41 +58 +61 +9 +52 +87 +0 +61 +1 +41 +34 +60 +88 +24 +58 +44 +12 +58 +44 +42 +52 +52 +56 +89 +22 +63 +65 +33 +76 +37 +14 +50 +50 +51 +56 +31 +32 +56 +36 +76 +47 +12 +80 +75 +57 +25 +58 +48 +66 +55 +75 +40 +56 +0 +72 +6 +25 +61 +80 +57 +60 +81 +28 +23 +39 +16 +66 +45 +43 +26 +35 +56 +64 +40 +47 +6 +39 +84 +42 +23 +46 +39 +40 +21 +49 +33 +50 +53 +29 +57 +26 +50 +55 +24 +39 +68 +48 +51 +40 +57 +68 +54 +10 +24 +9 +29 +70 +46 +15 +47 +48 +19 +59 +27 +52 +25 +26 +65 +75 +43 +21 +58 +19 +45 +66 +46 +1 +46 +38 +10 +54 +53 +63 +85 +72 +63 +41 +56 +55 +35 +28 +49 +50 +50 +20 +66 +21 +69 +41 +15 +42 +19 +67 +15 +61 +26 +4 +59 +55 +41 +82 +50 +1 +45 +27 +71 +49 +49 +31 +62 +59 +3 +42 +70 +31 +55 +81 +5 +67 +46 +60 +2 +49 +47 +12 +46 +47 +0 +79 +30 +29 +67 +62 +32 +20 +83 +23 +39 +34 +46 +35 +80 +84 +89 +41 +41 +19 +31 +78 +58 +48 +12 +85 +58 +34 +39 +36 +87 +34 +23 +51 +44 +53 +28 +59 +56 +59 +38 +42 +63 +48 +88 +21 +44 +77 +0 +50 +24 +59 +44 +64 +29 +30 +71 +55 +68 +53 +46 +26 +75 +1 +22 +34 +60 +33 +32 +81 +50 +23 +31 +32 +87 +28 +58 +62 +51 +44 +19 +49 +2 +32 +67 +33 +14 +51 +32 +36 +27 +23 +24 +11 +54 +45 +89 +18 +51 +88 +41 +58 +24 +50 +47 +23 +42 +88 +26 +20 +53 +10 +38 +42 +12 +70 +30 +30 +44 +52 +33 +36 +67 +57 +46 +67 +12 +68 +56 +38 +49 +36 +51 +52 +39 +21 +28 +56 +27 +24 +36 +54 +12 +64 +62 +89 +59 +69 +43 +44 +56 +69 +44 +63 +18 +29 +18 +58 +30 +62 +42 +26 +28 +29 +41 +41 +36 +60 +71 +57 +89 +78 +54 +30 +9 +50 +45 +62 +26 +55 +12 +5 +35 +36 +53 +62 +80 +30 +42 +68 +8 +70 +81 +59 +42 +32 +36 +39 +11 +3 +21 +50 +41 +44 +11 +52 +27 +0 +18 +22 +25 +0 +40 +56 +64 +53 +37 +29 +85 +60 +26 +35 +30 +19 +50 +64 +38 +70 +44 +38 +60 +52 +48 +10 +70 +61 +62 +38 +87 +57 +47 +52 +66 +40 +40 +61 +26 +55 +35 +76 +77 +46 +66 +61 +19 +76 +26 +49 +65 +77 +68 +46 +50 +59 +59 +44 +87 +89 +70 +65 +60 +62 +18 +71 +79 +28 +37 +17 +18 +16 +88 +47 +61 +45 +30 +31 +41 +36 +25 +1 +89 +36 +41 +49 +39 +21 +1 +7 +42 +58 +47 +44 +27 +55 +47 +26 +30 +18 +37 +18 +64 +15 +54 +57 +21 +87 +70 +49 +45 +57 +55 +88 +29 +52 +88 +64 +24 +54 +51 +20 +11 +21 +64 +33 +75 +41 +0 +17 +44 +40 +87 +61 +58 +36 +44 +21 +41 +21 +59 +65 +65 +55 +46 +74 +4 +58 +42 +44 +48 +45 +65 +72 +39 +2 +38 +74 +69 +31 +78 +55 +29 +31 +72 +21 +37 +49 +68 +64 +37 +53 +42 +81 +1 +26 +56 +21 +70 +45 +84 +41 +56 +65 +23 +68 +42 +7 +63 +14 +85 +69 +76 +45 +48 +65 +27 +75 +29 +45 +35 +64 +35 +50 +87 +51 +22 +60 +64 +23 +68 +1 +4 +54 +52 +68 +90 +49 +75 +62 +49 +63 +46 +19 +28 +49 +4 +36 +76 +82 +64 +48 +74 +73 +63 +70 +38 +50 +52 +76 +20 +38 +51 +48 +41 +13 +32 +36 +1 +0 +33 +22 +11 +56 +38 +52 +30 +72 +25 +89 +66 +35 +55 +67 +44 +42 +27 +29 +71 +25 +48 +29 +52 +56 +64 +65 +43 +26 +47 +30 +63 +65 +49 +28 +47 +60 +82 +14 +31 +38 +6 +12 +58 +8 +41 +6 +56 +63 +50 +62 +84 +48 +68 +26 +54 +21 +62 +70 +3 +27 +63 +38 +78 +48 +57 +87 +41 +34 +38 +34 +27 +48 +86 +66 +59 +61 +32 +87 +29 +41 +63 +25 +5 +29 +72 +65 +36 +38 +26 +23 +84 +39 +60 +27 +35 +34 +13 +45 +90 +51 +45 +36 +31 +79 +49 +45 +0 +72 +2 +13 +65 +55 +42 +66 +31 +58 +38 +36 +26 +69 +76 +61 +87 +33 +66 +19 +43 +61 +15 +77 +16 +38 +27 +32 +34 +32 +64 +89 +45 +48 +26 +77 +25 +40 +30 +58 +22 +47 +37 +56 +52 +48 +47 +39 +34 +55 +40 +68 +34 +16 +66 +46 +90 +35 +44 +57 +30 +30 +35 +43 +44 +30 +28 +55 +70 +90 +27 +40 +33 +41 +47 +13 +37 +20 +36 +32 +74 +22 +12 +62 +29 +59 +70 +34 +42 +40 +1 +54 +72 +78 +36 +21 +29 +65 +11 +39 +32 +38 +25 +73 +52 +58 +25 +49 +55 +23 +30 +26 +0 +31 +56 +58 +32 +35 +48 +51 +29 +39 +48 +35 +45 +29 +26 +56 +22 +8 +65 +19 +39 +48 +38 +84 +62 +20 +33 +11 +71 +41 +6 +64 +43 +34 +45 +26 +26 +73 +14 +19 +73 +46 +87 +39 +34 +25 +41 +62 +25 +24 +11 +37 +87 +28 +17 +41 +17 +81 +46 +19 +48 +50 +19 +50 +37 +44 +20 +23 +19 +23 +25 +46 +54 +30 +54 +36 +24 +57 +43 +29 +44 +24 +35 +35 +0 +66 +65 +34 +87 +76 +40 +47 +43 +22 +87 +52 +57 +15 +53 +60 +23 +54 +68 +42 +17 +31 +29 +19 +56 +43 +43 +43 +60 +59 +91 +55 +48 +15 +50 +14 +48 +58 +47 +16 +40 +68 +63 +13 +20 +59 +81 +12 +61 +63 +58 +64 +72 +40 +72 +46 +4 +57 +30 +25 +87 +58 +58 +45 +51 +30 +26 +44 +56 +58 +17 +62 +34 +75 +59 +34 +39 +40 +45 +53 +40 +35 +3 +17 +38 +28 +39 +0 +16 +24 +14 +51 +18 +19 +12 +1 +58 +21 +51 +44 +75 +51 +39 +49 +38 +64 +22 +50 +46 +39 +23 +42 +35 +31 +21 +75 +43 +60 +46 +50 +28 +47 +30 +43 +87 +44 +29 +66 +19 +55 +67 +0 +17 +80 +39 +67 +37 +68 +35 +31 +56 +20 +45 +31 +36 +26 +39 +74 +29 +48 +26 +66 +56 +40 +35 +66 +0 +27 +9 +66 +61 +75 +40 +22 +79 +62 +84 +47 +75 +45 +48 +90 +89 +25 +53 +72 +88 +29 +47 +55 +59 +57 +37 +30 +23 +60 +30 +77 +87 +65 +56 +39 +22 +28 +37 +54 +57 +25 +35 +33 +56 +82 +35 +87 +40 +46 +60 +55 +15 +25 +42 +3 +40 +42 +72 +45 +35 +38 +42 +20 +31 +85 +22 +34 +58 +44 +7 +56 +6 +44 +67 +33 +65 +39 +48 +45 +35 +44 +50 +74 +67 +71 +45 +43 +35 +56 +73 +63 +33 +32 +53 +60 +13 +56 +27 +49 +72 +16 +23 +16 +29 +32 +69 +35 +53 +76 +76 +37 +67 +49 +54 +65 +41 +41 +51 +10 +39 +78 +70 +28 +47 +19 +80 +52 +60 +40 +56 +40 +76 +72 +34 +58 +17 +64 +22 +36 +13 +7 +53 +87 +4 +23 +67 +61 +34 +59 +60 +21 +31 +53 +44 +17 +51 +28 +45 +35 +18 +60 +61 +28 +75 +1 +0 +66 +36 +11 +34 +19 +59 +50 +23 +15 +17 +60 +17 +30 +43 +41 +18 +64 +35 +47 +87 +38 +50 +2 +54 +29 +57 +68 +18 +50 +38 +50 +9 +11 +55 +83 +35 +88 +52 +39 +41 +55 +51 +84 +87 +38 +23 +44 +65 +39 +19 +29 +45 +48 +62 +63 +42 +14 +35 +29 +55 +39 +83 +59 +22 +31 +33 +62 +57 +47 +33 +71 +15 +17 +36 +65 +26 +34 +50 +19 +36 +61 +48 +43 +18 +43 +62 +67 +7 +21 +57 +33 +76 +84 +31 +31 +57 +54 +22 +10 +60 +26 +55 +76 +56 +42 +37 +47 +37 +9 +66 +71 +29 +63 +25 +57 +8 +9 +27 +71 +46 +21 +58 +25 +57 +33 +48 +59 +26 +54 +45 +59 +46 +62 +49 +68 +38 +17 +57 +45 +45 +44 +38 +87 +19 +0 +56 +68 +58 +55 +34 +54 +10 +38 +32 +39 +48 +15 +11 +47 +60 +45 +90 +46 +39 +75 +79 +51 +30 +30 +80 +1 +85 +49 +39 +16 +53 +21 +50 +34 +47 +59 +43 +60 +64 +69 +54 +64 +77 +35 +71 +31 +61 +83 +69 +68 +0 +45 +13 +26 +49 +37 +23 +40 +56 +31 +28 +51 +76 +22 +35 +37 +27 +88 +32 +42 +19 +39 +6 +87 +78 +68 +33 +49 +39 +28 +56 +39 +64 +76 +18 +26 +77 +27 +34 +37 +35 +37 +80 +65 +72 +55 +43 +10 +30 +56 +2 +27 +53 +15 +89 +76 +29 +41 +32 +71 +44 +37 +54 +48 +0 +44 +16 +10 +37 +59 +71 +16 +42 +39 +46 +45 +87 +37 +68 +0 +64 +33 +6 +85 +58 +43 +17 +58 +2 +68 +43 +30 +61 +76 +68 +26 +62 +31 +38 +24 +43 +54 +33 +41 +90 +32 +64 +27 +43 +42 +16 +60 +27 +35 +67 +70 +27 +46 +29 +33 +26 +23 +49 +53 +42 +56 +67 +83 +50 +0 +32 +17 +61 +64 +47 +19 +26 +46 +54 +14 +82 +78 +51 +0 +87 +22 +59 +31 +71 +49 +87 +41 +61 +53 +1 +45 +73 +62 +0 +29 +45 +68 +49 +34 +37 +51 +39 +56 +39 +55 +29 +22 +67 +64 +84 +36 +74 +27 +39 +35 +22 +49 +73 +89 +78 +1 +61 +39 +65 +76 +24 +47 +45 +66 +37 +77 +52 +66 +75 +33 +60 +87 +31 +53 +27 +44 +19 +79 +45 +53 +29 +24 +62 +65 +30 +21 +22 +69 +32 +26 +61 +40 +87 +41 +78 +8 +6 +58 +32 +46 +62 +30 +80 +52 +24 +22 +60 +52 +23 +39 +30 +55 +30 +62 +68 +4 +29 +52 +85 +23 +37 +64 +42 +48 +62 +46 +60 +26 +43 +39 +52 +41 +62 +27 +44 +31 +17 +40 +50 +78 +69 +21 +65 +63 +50 +12 +1 +6 +76 +58 +65 +21 +14 +43 +10 +47 +63 +89 +21 +28 +71 +5 +19 +25 +62 +36 +54 +23 +0 +73 +8 +47 +48 +33 +79 +51 +34 +53 +27 +42 +54 +14 +43 +50 +51 +48 +66 +39 +82 +42 +64 +22 +6 +49 +40 +38 +71 +28 +8 +16 +24 +62 +72 +48 +25 +76 +70 +75 +22 +1 +32 +87 +74 +0 +30 +79 +40 +35 +44 +50 +53 +49 +0 +61 +88 +74 +68 +46 +47 +45 +10 +31 +61 +70 +38 +26 +50 +56 +29 +46 +36 +63 +21 +59 +63 +76 +18 +40 +17 +72 +44 +20 +23 +16 +47 +33 +53 +3 +54 +70 +2 +65 +32 +67 +44 +47 +30 +32 +16 +25 +50 +39 +36 +10 +47 +13 +50 +17 +27 +49 +46 +51 +24 +29 +54 +64 +7 +24 +17 +51 +27 +14 +11 +27 +23 +25 +26 +48 +44 +62 +61 +45 +15 +23 +59 +78 +62 +68 +51 +54 +27 +32 +13 +36 +36 +79 +45 +20 +45 +34 +84 +50 +38 +46 +26 +47 +61 +53 +83 +68 +79 +44 +26 +28 +51 +60 +0 +89 +56 +35 +39 +59 +86 +59 +51 +53 +29 +65 +40 +47 +49 +23 +76 +26 +52 +39 +53 +69 +57 +76 +32 +51 +47 +34 +46 +56 +24 +11 +33 +45 +73 +48 +35 +35 +31 +39 +67 +78 +51 +45 +89 +85 +25 +47 +33 +35 +32 +50 +47 +15 +15 +58 +50 +41 +37 +20 +49 +73 +32 +46 +61 +61 +63 +31 +28 +21 +37 +9 +57 +70 +71 +21 +55 +57 +14 +37 +39 +49 +1 +7 +11 +39 +46 +63 +33 +26 +71 +65 +37 +89 +59 +58 +41 +16 +2 +44 +55 +5 +36 +48 +63 +60 +32 +14 +1 +10 +52 +35 +19 +54 +57 +53 +45 +58 +61 +17 +52 +60 +24 +28 +71 +50 +23 +38 +59 +47 +3 +29 +58 +36 +54 +41 +60 +45 +44 +80 +41 +50 +31 +14 +67 +49 +32 +17 +74 +59 +29 +68 +56 +42 +46 +62 +32 +57 +20 +52 +22 +31 +87 +16 +37 +0 +67 +45 +31 +13 +18 +35 +33 +39 +66 +28 +28 +30 +29 +2 +58 +74 +26 +80 +39 +5 +32 +18 +32 +78 +58 +28 +51 +60 +32 +1 +42 +29 +17 +43 +86 +69 +39 +52 +47 +50 +42 +48 +72 +6 +39 +35 +27 +57 +59 +30 +49 +63 +32 +23 +15 +44 +12 +71 +60 +52 +84 +65 +65 +32 +46 +57 +26 +17 +89 +48 +34 +66 +61 +19 +63 +27 +9 +58 +73 +59 +14 +31 +55 +27 +24 +55 +53 +25 +0 +33 +37 +11 +37 +34 +70 +54 +62 +42 +53 +5 +48 +10 +0 +18 +47 +11 +34 +43 +54 +26 +10 +29 +41 +45 +41 +41 +39 +26 +37 +44 +32 +13 +26 +61 +37 +30 +87 +70 +52 +86 +37 +23 +49 +36 +41 +24 +38 +49 +25 +7 +44 +61 +71 +58 +46 +35 +52 +70 +17 +1 +72 +63 +87 +75 +23 +23 +48 +65 +18 +34 +42 +36 +63 +32 +48 +36 +22 +50 +6 +55 +27 +53 +25 +51 +82 +71 +30 +55 +0 +33 +25 +60 +32 +21 +73 +51 +55 +26 +12 +66 +21 +7 +59 +56 +78 +54 +84 +65 +47 +22 +60 +40 +12 +21 +42 +57 +61 +51 +39 +10 +60 +68 +64 +65 +56 +44 +38 +23 +35 +87 +16 +53 +1 +43 +53 +68 +35 +23 +15 +40 +54 +72 +14 +79 +59 +33 +55 +1 +33 +67 +57 +75 +11 +52 +42 +11 +52 +36 +87 +77 +85 +15 +27 +35 +23 +76 +77 +57 +53 +52 +9 +18 +62 +18 +54 +20 +31 +29 +52 +48 +68 +56 +0 +36 +15 +40 +43 +19 +35 +34 +32 +21 +35 +58 +23 +33 +64 +52 +48 +57 +14 +58 +27 +73 +89 +30 +1 +44 +28 +54 +33 +1 +68 +38 +67 +50 +59 +15 +2 +59 +53 +74 +39 +49 +52 +54 +54 +50 +67 +73 +56 +30 +18 +9 +49 +67 +69 +13 +40 +35 +27 +75 +71 +28 +42 +58 +2 +17 +61 +45 +57 +80 +88 +38 +32 +35 +33 +83 +61 +56 +0 +59 +18 +20 +35 +72 +54 +40 +52 +63 +28 +48 +15 +38 +25 +43 +39 +18 +38 +28 +13 +68 +50 +90 +1 +44 +23 +76 +31 +73 +81 +23 +3 +49 +22 +44 +20 +35 +26 +23 +16 +26 +32 +62 +7 +55 +42 +7 +39 +82 +71 +68 +25 +25 +52 +0 +63 +83 +19 +73 +46 +39 +76 +38 +37 +42 +32 +89 +83 +12 +48 +33 +87 +54 +62 +23 +46 +58 +54 +33 +66 +32 +17 +12 +50 +64 +28 +41 +19 +33 +40 +54 +32 +54 +79 +36 +36 +0 +47 +9 +33 +65 +31 +54 +39 +44 +8 +45 +25 +43 +21 +82 +14 +63 +26 +46 +8 +25 +2 +51 +57 +75 +45 +33 +15 +25 +87 +45 +59 +50 +49 +44 +39 +28 +31 +59 +76 +49 +24 +55 +62 +47 +25 +76 +20 +37 +42 +17 +60 +44 +20 +26 +39 +23 +57 +40 +20 +74 +23 +73 +56 +69 +28 +25 +36 +45 +62 +46 +32 +71 +41 +32 +23 +16 +36 +33 +52 +0 +48 +75 +17 +54 +77 +53 +58 +44 +22 +30 +76 +26 +54 +20 +50 +64 +30 +53 +51 +46 +26 +62 +46 +49 +44 +34 +17 +30 +22 +40 +82 +20 +53 +59 +45 +18 +58 +14 +63 +27 +62 +25 +37 +24 +0 +74 +85 +52 +34 +60 +70 +62 +48 +33 +18 +77 +42 +64 +51 +49 +39 +58 +19 +57 +23 +55 +0 +66 +57 +61 +58 +33 +48 +16 +11 +41 +12 +36 +67 +14 +31 +60 +51 +53 +30 +55 +52 +75 +35 +64 +40 +36 +67 +73 +47 +23 +55 +33 +52 +81 +15 +37 +55 +32 +31 +75 +35 +53 +32 +48 +12 +23 +61 +44 +57 +46 +70 +22 +49 +24 +33 +1 +62 +35 +86 +18 +55 +60 +33 +37 +46 +23 +69 +31 +33 +48 +87 +34 +45 +48 +56 +19 +62 +40 +24 +22 +1 +42 +68 +41 +58 +60 +75 +26 +0 +33 +61 +61 +53 +72 +81 +35 +79 +40 +66 +30 +0 +61 +63 +21 +42 +13 +85 +28 +65 +52 +63 +88 +15 +9 +18 +62 +20 +54 +7 +52 +36 +36 +17 +45 +0 +89 +27 +85 +60 +25 +4 +76 +63 +57 +35 +7 +38 +32 +40 +30 +33 +75 +37 +65 +32 +69 +34 +77 +65 +38 +55 +27 +47 +64 +67 +71 +70 +60 +64 +46 +2 +51 +28 +50 +42 +11 +45 +31 +30 +48 +52 +85 +18 +61 +52 +51 +0 +40 +67 +33 +20 +31 +32 +50 +37 +46 +77 +40 +44 +33 +12 +51 +84 +66 +57 +58 +8 +58 +42 +62 +55 +61 +18 +59 +40 +80 +51 +16 +23 +30 +24 +20 +43 +22 +45 +32 +14 +36 +50 +65 +14 +58 +36 +33 +43 +50 +38 +29 +69 +42 +7 +16 +51 +59 +59 +56 +84 +63 +82 +59 +28 +44 +16 +71 +56 +29 +68 +41 +40 +69 +49 +39 +19 +69 +14 +45 +59 +57 +56 +40 +59 +32 +46 +34 +53 +52 +0 +68 +57 +72 +45 +5 +74 +42 +67 +43 +81 +78 +48 +31 +14 +45 +63 +52 +40 +51 +34 +67 +57 +78 +30 +58 +53 +78 +57 +44 +1 +46 +50 +64 +36 +61 +30 +62 +54 +52 +36 +87 +53 +8 +70 +37 +36 +10 +70 +14 +74 +36 +46 +40 +64 +26 +38 +59 +19 +33 +14 +51 +21 +58 +35 +56 +32 +34 +45 +18 +54 +52 +81 +45 +79 +39 +37 +18 +55 +62 +46 +38 +71 +50 +60 +40 +39 +44 +29 +55 +34 +27 +64 +61 +34 +55 +56 +27 +40 +67 +28 +52 +24 +38 +83 +23 +21 +44 +48 +52 +15 +9 +48 +61 +13 +45 +57 +28 +65 +64 +8 +44 +76 +61 +43 +35 +36 +55 +27 +13 +46 +59 +8 +22 +43 +53 +43 +36 +59 +12 +49 +41 +87 +66 +69 +56 +39 +40 +40 +51 +80 +42 +61 +26 +28 +32 +49 +16 +2 +67 +6 +72 +81 +35 +37 +87 +57 +51 +50 +38 +9 +35 +2 +46 +47 +17 +40 +5 +80 +39 +40 +35 +1 +18 +1 +15 +9 +71 +61 +56 +5 +67 +64 +58 +39 +36 +37 +29 +71 +66 +88 +71 +50 +45 +2 +20 +48 +66 +13 +77 +26 +50 +53 +13 +6 +46 +42 +16 +73 +36 +40 +30 +2 +40 +5 +33 +39 +63 +55 +27 +15 +19 +33 +34 +46 +5 +53 +67 +38 +51 +82 +40 +30 +51 +42 +64 +3 +38 +34 +46 +67 +81 +27 +65 +26 +26 +82 +10 +0 +54 +45 +30 +59 +2 +75 +72 +43 +29 +87 +27 +36 +52 +7 +38 +73 +49 +45 +32 +25 +27 +31 +61 +60 +22 +55 +65 +88 +66 +54 +89 +40 +74 +61 +87 +52 +36 +20 +8 +1 +31 +59 +46 +33 +57 +32 +18 +18 +19 +53 +40 +18 +52 +60 +75 +90 +64 +63 +56 +35 +46 +78 +88 +42 +13 +43 +31 +31 +25 +37 +20 +88 +47 +39 +30 +49 +74 +27 +35 +12 +66 +63 +40 +76 +83 +15 +23 +20 +46 +47 +64 +71 +31 +42 +1 +70 +35 +13 +58 +39 +4 +57 +88 +30 +38 +62 +42 +51 +51 +42 +57 +24 +32 +44 +40 +35 +29 +33 +56 +13 +10 +27 +0 +35 +79 +62 +48 +30 +36 +38 +58 +0 +51 +3 +1 +63 +6 +52 +21 +89 +73 +0 +30 +23 +1 +26 +27 +48 +56 +6 +46 +49 +11 +45 +29 +61 +42 +38 +44 +15 +59 +48 +34 +50 +31 +36 +42 +16 +69 +28 +35 +38 +32 +48 +48 +27 +43 +55 +28 +38 +85 +21 +47 +61 +39 +59 +40 +72 +64 +88 +27 +59 +28 +1 +4 +75 +63 +87 +63 +46 +5 +47 +36 +76 +38 +89 +44 +44 +72 +47 +15 +16 +68 +30 +1 +41 +29 +47 +62 +57 +3 +46 +48 +65 +47 +56 +46 +51 +28 +54 +68 +30 +77 +14 +65 +67 +41 +43 +65 +56 +60 +47 +58 +37 +49 +6 +41 +42 +51 +40 +60 +0 +85 +70 +83 +20 +46 +49 +51 +57 +61 +2 +40 +33 +34 +46 +59 +49 +73 +41 +72 +73 +74 +35 +88 +0 +44 +57 +48 +67 +4 +52 +10 +30 +35 +41 +28 +2 +21 +39 +18 +36 +67 +20 +22 +34 +17 +22 +78 +35 +6 +46 +67 +51 +48 +30 +44 +50 +56 +73 +57 +35 +1 +53 +29 +10 +43 +25 +85 +19 +37 +44 +36 +63 +45 +43 +41 +87 +27 +60 +0 +7 +36 +59 +79 +44 +17 +30 +40 +47 +0 +35 +48 +48 +0 +52 +21 +26 +29 +68 +29 +79 +44 +25 +46 +52 +63 +54 +39 +55 +36 +31 +36 +48 +48 +50 +58 +31 +58 +1 +36 +75 +53 +30 +31 +44 +30 +38 +59 +41 +61 +66 +15 +70 +80 +59 +13 +13 +68 +57 +36 +55 +29 +69 +66 +32 +38 +61 +23 +66 +28 +36 +45 +29 +23 +74 +41 +54 +21 +54 +60 +39 +63 +71 +49 +83 +10 +43 +63 +62 +26 +90 +77 +34 +18 +33 +24 +70 +32 +74 +34 +47 +35 +52 +75 +41 +52 +46 +64 +59 +13 +50 +31 +19 +54 +37 +69 +47 +51 +58 +29 +70 +54 +35 +75 +45 +42 +37 +80 +8 +6 +87 +65 +38 +38 +11 +19 +80 +62 +31 +74 +50 +50 +49 +65 +21 +33 +37 +52 +38 +22 +64 +77 +45 +8 +24 +60 +57 +38 +39 +27 +50 +46 +50 +25 +55 +35 +52 +28 +61 +47 +53 +52 +77 +52 +34 +72 +5 +43 +11 +73 +35 +41 +70 +46 +63 +45 +43 +56 +1 +23 +34 +17 +27 +46 +35 +63 +29 +33 +16 +73 +26 +78 +14 +41 +38 +51 +17 +46 +16 +34 +39 +34 +50 +71 +64 +30 +52 +60 +90 +49 +75 +82 +53 +15 +77 +36 +59 +57 +17 +26 +34 +29 +63 +72 +15 +39 +88 +72 +41 +23 +18 +42 +44 +88 +51 +17 +28 +63 +43 +30 +88 +44 +29 +48 +49 +48 +44 +45 +62 +53 +59 +32 +29 +28 +44 +70 +67 +30 +18 +34 +45 +0 +16 +38 +72 +50 +61 +14 +82 +73 +80 +16 +74 +61 +79 +29 +53 +50 +20 +46 +47 +32 +53 +54 +25 +29 +53 +53 +42 +48 +30 +68 +63 +39 +23 +54 +80 +38 +37 +86 +12 +42 +32 +36 +75 +1 +69 +37 +40 +17 +57 +28 +57 +28 +22 +44 +61 +60 +37 +70 +64 +23 +35 +9 +48 +66 +14 +47 +53 +28 +57 +67 +60 +34 +46 +57 +76 +48 +47 +14 +87 +73 +56 +56 +45 +7 +22 +65 +34 +55 +47 +50 +44 +25 +39 +67 +52 +38 +75 +42 +62 +25 +8 +16 +89 +69 +60 +28 +73 +46 +15 +35 +51 +77 +53 +57 +54 +26 +32 +45 +82 +19 +12 +16 +34 +29 +38 +20 +56 +82 +31 +38 +15 +44 +34 +46 +72 +86 +85 +34 +58 +61 +79 +40 +57 +23 +67 +58 +0 +33 +35 +7 +55 +49 +39 +52 +16 +89 +38 +72 +61 +67 +82 +89 +42 +12 +37 +37 +21 +59 +64 +48 +42 +48 +64 +58 +62 +37 +38 +74 +46 +34 +66 +8 +44 +29 +89 +33 +43 +61 +39 +32 +66 +63 +4 +79 +25 +68 +35 +22 +0 +28 +35 +40 +22 +53 +10 +30 +33 +1 +64 +81 +73 +54 +20 +0 +32 +23 +44 +50 +56 +54 +88 +9 +48 +42 +2 +32 +71 +58 +57 +87 +60 +57 +50 +76 +85 +23 +18 +54 +19 +70 +67 +20 +7 +37 +69 +28 +39 +26 +46 +26 +34 +62 +59 +55 +36 +57 +7 +40 +54 +47 +56 +88 +24 +73 +73 +20 +26 +26 +18 +47 +34 +70 +42 +12 +41 +31 +66 +57 +66 +54 +27 +30 +31 +57 +28 +44 +27 +64 +72 +50 +26 +56 +1 +47 +45 +76 +64 +77 +49 +45 +43 +15 +33 +31 +49 +87 +29 +27 +73 +67 +0 +8 +53 +22 +49 +38 +62 +65 +22 +42 +24 +40 +36 +44 +22 +68 +82 +53 +29 +18 +42 +34 +70 +36 +61 +17 +41 +78 +14 +56 +61 +24 +73 +41 +18 +81 +56 +69 +56 +22 +51 +63 +14 +86 +40 +27 +23 +14 +51 +35 +14 +20 +64 +25 +70 +74 +76 +89 +35 +22 +55 +15 +62 +58 +61 +32 +60 +90 +21 +23 +76 +43 +37 +33 +26 +57 +3 +54 +61 +10 +39 +52 +30 +48 +84 +60 +29 +15 +45 +22 +12 +53 +19 +43 +69 +52 +63 +1 +7 +38 +61 +51 +56 +61 +89 +13 +67 +79 +23 +32 +75 +56 +31 +86 +36 +67 +56 +49 +6 +38 +43 +70 +60 +18 +18 +49 +43 +49 +11 +57 +32 +88 +55 +45 +35 +58 +62 +28 +16 +67 +31 +29 +88 +18 +89 +44 +61 +75 +53 +38 +71 +62 +20 +58 +35 +75 +1 +31 +2 +70 +71 +53 +62 +34 +37 +72 +10 +73 +76 +30 +25 +66 +45 +74 +60 +46 +50 +44 +34 +57 +43 +66 +25 +53 +1 +42 +39 +28 +38 +57 +31 +28 +23 +1 +22 +63 +16 +15 +88 +48 +53 +34 +46 +25 +0 +76 +65 +36 +20 +65 +35 +52 +55 +46 +21 +30 +45 +54 +12 +45 +23 +69 +67 +25 +41 +3 +62 +62 +64 +79 +56 +20 +15 +67 +45 +19 +87 +1 +50 +29 +60 +6 +39 +46 +77 +34 +73 +27 +37 +27 +35 +49 +4 +66 +23 +57 +27 +75 +17 +31 +56 +18 +61 +68 +43 +66 +65 +58 +46 +42 +70 +23 +17 +39 +45 +28 +45 +61 +20 +26 +24 +39 +47 +42 +63 +42 +41 +53 +27 +33 +15 +39 +27 +28 +46 +44 +17 +51 +67 +75 +32 +76 +41 +48 +55 +80 +89 +44 +35 +49 +22 +45 +16 +32 +42 +22 +73 +55 +50 +40 +72 +19 +85 +52 +43 +11 +56 +56 +16 +28 +54 +64 +25 +71 +41 +18 +1 +68 +61 +60 +38 +18 +68 +33 +16 +58 +70 +37 +53 +27 +33 +56 +55 +71 +37 +51 +0 +27 +20 +83 +10 +0 +60 +71 +89 +28 +68 +34 +28 +47 +56 +41 +47 +54 +24 +48 +41 +87 +22 +5 +63 +43 +80 +26 +90 +74 +33 +31 +37 +65 +56 +55 +25 +73 +45 +15 +43 +73 +43 +55 +84 +38 +31 +0 +20 +53 +29 +70 +21 +10 +22 +7 +35 +17 +37 +35 +30 +37 +38 +88 +16 +24 +57 +41 +33 +24 +25 +61 +55 +15 +55 +22 +40 +47 +25 +69 +77 +37 +44 +30 +43 +39 +70 +36 +32 +50 +18 +5 +35 +83 +87 +55 +76 +83 +54 +49 +66 +58 +44 +23 +9 +37 +30 +60 +35 +31 +41 +59 +65 +57 +35 +65 +42 +31 +40 +55 +51 +31 +40 +37 +45 +44 +38 +35 +53 +21 +24 +34 +45 +33 +66 +68 +33 +42 +1 +25 +55 +25 +41 +41 +49 +60 +41 +20 +6 +31 +34 +58 +46 +53 +16 +35 +31 +61 +47 +40 +42 +23 +42 +45 +48 +36 +80 +3 +43 +46 +50 +45 +60 +47 +58 +73 +52 +36 +34 +39 +58 +43 +2 +65 +16 +44 +27 +55 +58 +28 +32 +28 +55 +21 +42 +32 +44 +1 +30 +55 +53 +65 +42 +33 +59 +53 +26 +24 +5 +66 +35 +35 +15 +29 +57 +41 +56 +50 +65 +17 +27 +42 +21 +49 +52 +88 +42 +50 +55 +35 +72 +42 +29 +53 +14 +44 +6 +50 +39 +57 +56 +22 +15 +26 +44 +34 +59 +47 +10 +48 +50 +0 +27 +14 +43 +41 +80 +32 +19 +74 +53 +50 +60 +55 +56 +26 +27 +45 +43 +17 +58 +57 +31 +31 +34 +56 +43 +85 +29 +1 +56 +58 +87 +27 +42 +33 +52 +49 +32 +10 +6 +38 +0 +54 +47 +26 +45 +26 +55 +65 +43 +45 +37 +48 +17 +80 +45 +42 +71 +48 +48 +48 +28 +32 +11 +55 +43 +60 +10 +41 +39 +56 +65 +29 +36 +43 +50 +37 +16 +11 +15 +18 +68 +41 +37 +58 +15 +24 +59 +53 +38 +37 +40 +57 +38 +53 +17 +84 +79 +58 +57 +44 +15 +1 +46 +46 +47 +62 +13 +36 +66 +48 +87 +51 +87 +78 +38 +52 +34 +39 +0 +48 +71 +27 +32 +34 +25 +66 +46 +57 +48 +28 +62 +55 +87 +48 +46 +33 +42 +44 +36 +73 +36 +68 +85 +29 +64 +45 +47 +46 +44 +27 +58 +60 +43 +35 +69 +22 +37 +59 +62 +69 +45 +41 +78 +43 +69 +36 +53 +31 +31 +49 +66 +36 +15 +46 +65 +36 +41 +49 +8 +71 +49 +17 +53 +41 +72 +74 +52 +1 +17 +18 +55 +28 +39 +58 +89 +43 +21 +45 +38 +45 +75 +16 +15 +23 +34 +47 +70 +24 +72 +74 +63 +49 +43 +29 +66 +41 +34 +48 +47 +66 +65 +46 +27 +61 +45 +63 +61 +33 +68 +13 +30 +62 +49 +62 +44 +54 +63 +50 +33 +61 +36 +54 +45 +82 +45 +52 +28 +47 +64 +59 +18 +36 +42 +46 +37 +6 +26 +10 +12 +18 +88 +27 +36 +69 +47 +37 +72 +57 +39 +33 +68 +42 +63 +30 +57 +89 +66 +75 +63 +37 +41 +76 +34 +31 +33 +58 +46 +91 +44 +49 +71 +30 +44 +30 +70 +57 +26 +21 +47 +43 +28 +0 +24 +59 +39 +87 +58 +53 +33 +54 +32 +37 +15 +28 +25 +59 +49 +27 +37 +44 +20 +73 +7 +36 +67 +34 +72 +47 +50 +37 +18 +71 +37 +65 +87 +0 +9 +56 +70 +25 +55 +60 +26 +38 +80 +11 +42 +85 +60 +58 +51 +25 +80 +19 +41 +58 +56 +77 +43 +61 +62 +87 +50 +40 +61 +31 +66 +65 +75 +70 +54 +64 +77 +0 +37 +65 +21 +49 +43 +35 +90 +68 +51 +62 +65 +45 +39 +67 +49 +11 +37 +48 +41 +53 +83 +27 +76 +40 +44 +17 +11 +34 +35 +31 +61 +42 +70 +57 +27 +17 +48 +60 +74 +84 +37 +33 +59 +35 +37 +65 +50 +57 +54 +0 +41 +20 +44 +51 +82 +71 +64 +62 +70 +45 +41 +34 +85 +29 +18 +65 +37 +47 +6 +60 +54 +34 +34 +43 +8 +59 +36 +52 +77 +41 +46 +64 +60 +57 +55 +49 +39 +46 +39 +31 +67 +58 +31 +17 +66 +55 +11 +6 +36 +23 +73 +31 +48 +11 +18 +29 +30 +42 +62 +37 +70 +52 +69 +72 +35 +26 +56 +56 +2 +76 +71 +57 +45 +48 +46 +45 +55 +89 +29 +23 +50 +13 +31 +46 +5 +25 +47 +33 +82 +36 +0 +24 +45 +28 +38 +28 +47 +44 +44 +71 +11 +63 +73 +3 +67 +53 +37 +23 +65 +35 +36 +21 +30 +23 +46 +49 +42 +46 +72 +46 +45 +36 +72 +34 +20 +29 +8 +47 +18 +40 +28 +13 +48 +58 +41 +25 +54 +39 +28 +90 +43 +49 +70 +12 +89 +44 +57 +32 +75 +15 +64 +48 +54 +38 +55 +46 +77 +33 +52 +26 +66 +48 +0 +19 +26 +48 +45 +64 +25 +0 +6 +28 +30 +21 +52 +49 +41 +58 +59 +47 +44 +12 +31 +84 +55 +0 +30 +54 +87 +50 +50 +1 +51 +36 +37 +44 +26 +1 +40 +87 +29 +87 +72 +33 +56 +32 +63 +66 +79 +22 +29 +59 +19 +55 +47 +27 +34 +2 +49 +41 +40 +34 +21 +45 +54 +15 +55 +21 +89 +26 +18 +17 +55 +8 +45 +36 +57 +49 +10 +19 +12 +46 +59 +82 +43 +52 +38 +52 +56 +81 +14 +60 +30 +62 +59 +76 +25 +8 +24 +13 +45 +52 +42 +27 +24 +74 +42 +25 +80 +16 +39 +14 +50 +40 +58 +46 +19 +44 +35 +57 +62 +38 +50 +71 +46 +67 +16 +61 +38 +17 +57 +26 +43 +88 +89 +25 +43 +22 +21 +32 +57 +52 +46 +23 +23 +40 +17 +21 +56 +34 +49 +65 +48 +25 +16 +49 +44 +16 +0 +52 +46 +47 +80 +40 +33 +59 +52 +62 +0 +80 +87 +64 +39 +26 +72 +43 +39 +76 +39 +43 +69 +28 +67 +29 +46 +61 +87 +41 +37 +37 +53 +36 +51 +35 +0 +70 +45 +35 +21 +26 +71 +24 +72 +67 +33 +49 +72 +62 +33 +55 +55 +58 +37 +27 +67 +40 +58 +72 +55 +40 +75 +46 +57 +45 +35 +83 +58 +40 +87 +48 +28 +50 +42 +60 +34 +71 +68 +59 +74 +73 +18 +60 +87 +44 +29 +33 +32 +45 +9 +0 +53 +51 +81 +82 +59 +55 +59 +60 +51 +22 +76 +32 +73 +68 +81 +36 +35 +44 +87 +58 +53 +15 +55 +87 +45 +56 +50 +35 +3 +68 +41 +47 +50 +38 +49 +56 +46 +75 +63 +75 +32 +9 +53 +40 +69 +32 +40 +34 +44 +39 +70 +41 +0 +85 +64 +32 +89 +30 +36 +32 +53 +59 +69 +52 +80 +56 +72 +60 +30 +85 +32 +33 +48 +43 +27 +22 +59 +76 +37 +26 +30 +53 +56 +34 +52 +39 +35 +34 +74 +87 +89 +28 +29 +12 +79 +31 +47 +21 +20 +18 +66 +57 +42 +57 +50 +20 +57 +21 +39 +60 +22 +37 +26 +7 +87 +75 +39 +88 +53 +52 +71 +84 +25 +88 +34 +58 +55 +56 +14 +55 +62 +49 +51 +57 +38 +36 +51 +53 +91 +53 +89 +50 +46 +43 +70 +25 +68 +17 +43 +59 +1 +57 +32 +71 +41 +45 +31 +75 +34 +28 +52 +31 +19 +51 +41 +41 +40 +36 +57 +32 +76 +35 +77 +38 +32 +61 +63 +48 +40 +70 +1 +1 +42 +60 +23 +0 +57 +0 +70 +43 +28 +37 +43 +52 +35 +12 +8 +14 +13 +12 +17 +0 +58 +16 +52 +40 +32 +44 +21 +22 +44 +33 +21 +42 +50 +13 +29 +43 +13 +52 +59 +67 +56 +82 +42 +30 +42 +23 +40 +36 +26 +64 +76 +53 +54 +59 +18 +32 +10 +39 +33 +45 +86 +40 +57 +10 +79 +67 +51 +1 +58 +0 +33 +45 +88 +84 +20 +53 +39 +50 +20 +62 +60 +48 +78 +55 +7 +54 +58 +12 +58 +23 +75 +28 +23 +29 +25 +57 +37 +79 +49 +8 +19 +50 +41 +51 +66 +55 +43 +31 +63 +70 +50 +13 +60 +22 +44 +28 +60 +74 +61 +36 +43 +83 +34 +29 +38 +10 +50 +50 +35 +25 +39 +57 +20 +34 +47 +21 +87 +53 +21 +65 +36 +88 +51 +47 +65 +50 +38 +32 +30 +47 +61 +50 +15 +38 +47 +35 +31 +56 +84 +21 +65 +40 +71 +24 +82 +82 +40 +62 +31 +27 +7 +59 +32 +52 +37 +43 +60 +63 +47 +21 +37 +38 +27 +77 +71 +36 +58 +78 +31 +39 +66 +46 +43 +20 +43 +1 +62 +79 +43 +23 +43 +53 +63 +42 +55 +63 +87 +77 +15 +42 +21 +51 +25 +47 +63 +57 +4 +62 +48 +0 +27 +20 +38 +26 +70 +62 +56 +4 +45 +39 +64 +48 +76 +56 +43 +61 +12 +30 +18 +46 +54 +62 +60 +60 +33 +37 +54 +28 +57 +64 +31 +27 +48 +55 +21 +65 +17 +35 +50 +70 +59 +16 +49 +45 +48 +37 +62 +18 +76 +54 +40 +57 +10 +67 +74 +37 +16 +42 +54 +55 +40 +37 +58 +31 +54 +40 +26 +22 +4 +32 +71 +42 +70 +62 +0 +29 +18 +24 +38 +45 +59 +66 +31 +44 +18 +45 +19 +52 +25 +59 +88 +30 +33 +25 +48 +71 +66 +66 +31 +35 +31 +47 +49 +76 +48 +5 +66 +21 +41 +62 +61 +17 +60 +50 +0 +54 +39 +62 +22 +89 +52 +38 +35 +82 +66 +32 +24 +36 +44 +47 +19 +52 +7 +45 +35 +40 +78 +71 +19 +73 +12 +19 +55 +29 +50 +45 +53 +54 +83 +14 +58 +75 +56 +36 +20 +23 +30 +79 +0 +28 +44 +84 +21 +58 +33 +24 +38 +49 +35 +61 +27 +25 +34 +27 +21 +85 +48 +27 +12 +27 +8 +30 +53 +87 +10 +54 +25 +87 +58 +53 +0 +30 +63 +39 +58 +11 +24 +17 +35 +38 +43 +28 +37 +9 +0 +31 +24 +57 +60 +51 +43 +54 +48 +30 +48 +44 +60 +32 +31 +52 +50 +47 +21 +18 +66 +45 +65 +13 +27 +55 +39 +36 +23 +63 +37 +31 +44 +13 +43 +30 +87 +16 +1 +19 +63 +35 +51 +22 +21 +35 +48 +42 +65 +0 +43 +44 +57 +25 +11 +64 +28 +23 +29 +41 +24 +33 +35 +52 +39 +12 +21 +45 +64 +23 +35 +0 +79 +14 +1 +5 +44 +62 +54 +21 +87 +87 +24 +62 +39 +31 +64 +38 +45 +58 +55 +52 +41 +40 +31 +13 +8 +25 +47 +48 +63 +20 +59 +78 +27 +65 +40 +43 +55 +50 +45 +64 +20 +4 +70 +24 +47 +34 +33 +43 +78 +31 +0 +88 +33 +13 +49 +0 +25 +62 +58 +13 +31 +15 +45 +47 +50 +44 +36 +47 +47 +53 +17 +77 +32 +27 +30 +50 +9 +66 +87 +42 +87 +50 +34 +69 +70 +45 +27 +36 +88 +19 +64 +35 +62 +44 +36 +40 +22 +57 +41 +78 +8 +12 +59 +44 +54 +44 +6 +53 +52 +74 +61 +43 +87 +47 +39 +0 +39 +0 +53 +49 +42 +36 +57 +73 +25 +87 +16 +75 +31 +11 +28 +21 +53 +49 +61 +38 +34 +28 +65 +87 +84 +28 +53 +15 +61 +39 +31 +25 +43 +13 +17 +71 +59 +25 +54 +63 +67 +47 +91 +37 +29 +0 +28 +13 +49 +56 +63 +52 +49 +54 +45 +52 +59 +11 +16 +46 +68 +21 +48 +5 +33 +79 +21 +81 +90 +44 +61 +16 +43 +67 +40 +89 +52 +34 +8 +43 +59 +84 +21 +64 +26 +38 +68 +58 +67 +48 +23 +61 +53 +34 +87 +55 +55 +38 +38 +24 +16 +51 +22 +39 +38 +71 +13 +46 +19 +53 +51 +36 +54 +7 +37 +63 +48 +50 +14 +41 +56 +54 +53 +64 +11 +28 +39 +25 +23 +73 +49 +32 +65 +16 +39 +54 +38 +87 +82 +29 +39 +51 +29 +46 +18 +67 +36 +3 +35 +57 +42 +54 +40 +48 +64 +51 +41 +25 +31 +60 +46 +23 +0 +29 +52 +28 +37 +76 +52 +49 +59 +57 +28 +13 +14 +37 +20 +64 +89 +74 +29 +39 +51 +67 +54 +53 +64 +24 +30 +19 +52 +75 +57 +51 +73 +36 +36 +38 +29 +71 +65 +41 +40 +38 +40 +60 +68 +26 +76 +76 +34 +59 +65 +79 +87 +35 +59 +32 +16 +23 +40 +67 +64 +36 +31 +55 +64 +46 +48 +43 +13 +20 +32 +45 +74 +53 +18 +51 +43 +69 +72 +11 +47 +25 +27 +64 +17 +7 +12 +26 +26 +37 +36 +42 +84 +49 +58 +15 +30 +50 +27 +60 +85 +56 +51 +45 +67 +17 +13 +49 +4 +54 +27 +62 +42 +48 +21 +10 +61 +69 +68 +33 +53 +49 +22 +7 +0 +52 +54 +60 +57 +51 +59 +12 +89 +44 +21 +48 +48 +49 +76 +47 +59 +52 +56 +42 +63 +39 +59 +71 +1 +52 +58 +41 +51 +78 +33 +29 +61 +21 +25 +47 +8 +24 +57 +36 +87 +78 +57 +9 +0 +60 +50 +16 +45 +34 +31 +71 +56 +23 +37 +77 +11 +57 +48 +31 +54 +78 +37 +23 +43 +42 +44 +61 +43 +56 +33 +81 +83 +63 +46 +50 +27 +44 +22 +17 +38 +58 +0 +0 +59 +47 +13 +50 +22 +51 +89 +25 +53 +49 +18 +34 +80 +65 +64 +40 +32 +34 +42 +54 +52 +34 +80 +52 +28 +38 +42 +68 +9 +37 +27 +52 +52 +74 +41 +45 +33 +26 +89 +47 +26 +53 +57 +63 +63 +51 +10 +40 +37 +69 +48 +25 +59 +38 +52 +55 +55 +52 +65 +41 +51 +79 +74 +4 +71 +55 +31 +62 +45 +21 +89 +69 +69 +63 +71 +63 +48 +20 +66 +1 +43 +29 +51 +36 +29 +32 +43 +49 +22 +56 +76 +77 +20 +57 +45 +9 +38 +32 +67 +54 +55 +25 +49 +8 +51 +57 +66 +59 +55 +22 +72 +67 +17 +29 +11 +28 +19 +41 +22 +32 +15 +13 +58 +5 +32 +41 +40 +71 +30 +68 +21 +49 +32 +21 +26 +47 +16 +50 +34 +70 +21 +17 +45 +5 +23 +61 +47 +48 +48 +40 +57 +79 +50 +76 +17 +13 +70 +62 +74 +30 +47 +89 +40 +60 +56 +56 +43 +63 +25 +67 +1 +65 +58 +29 +16 +46 +0 +21 +30 +73 +17 +54 +42 +64 +31 +60 +58 +11 +27 +42 +34 +20 +40 +58 +56 +23 +12 +52 +64 +81 +28 +29 +89 +57 +87 +72 +6 +38 +44 +38 +50 +8 +68 +39 +15 +50 +21 +32 +36 +52 +87 +39 +40 +82 +57 +42 +66 +8 +77 +63 +45 +37 +15 +26 +30 +46 +54 +32 +35 +23 +80 +47 +13 +39 +51 +52 +50 +65 +59 +35 +11 +32 +87 +58 +27 +45 +45 +34 +46 +49 +69 +21 +69 +53 +77 +32 +23 +23 +55 +49 +58 +80 +39 +51 +48 +54 +78 +44 +12 +36 +51 +37 +89 +51 +46 +81 +79 +55 +38 +81 +42 +54 +39 +31 +55 +32 +1 +74 +34 +45 +7 +21 +34 +70 +49 +55 +45 +87 +10 +36 +64 +36 +44 +71 +30 +89 +52 +8 +52 +19 +16 +45 +2 +60 +32 +46 +24 +88 +40 +55 +39 +28 +44 +21 +25 +54 +1 +24 +66 +28 +18 +39 +65 +11 +41 +24 +16 +79 +43 +40 +35 +21 +8 +34 +56 +4 +36 +53 +64 +67 +42 +78 +13 +30 +33 +48 +55 +12 +60 +48 +59 +59 +22 +37 +1 +54 +39 +74 +67 +20 +61 +44 +48 +41 +33 +35 +64 +54 +48 +74 +70 +7 +63 +63 +75 +44 +76 +65 +32 +61 +58 +36 +49 +85 +80 +67 +73 +41 +33 +33 +66 +14 +73 +77 +43 +66 +17 +66 +8 +89 +76 +69 +68 +34 +57 +63 +23 +65 +35 +52 +87 +65 +42 +80 +79 +28 +50 +15 +69 +44 +10 +58 +13 +46 +41 +10 +35 +58 +75 +64 +71 +67 +18 +59 +0 +39 +27 +52 +60 +53 +27 +60 +70 +52 +53 +8 +57 +58 +45 +56 +81 +0 +42 +70 +41 +75 +20 +52 +51 +67 +5 +67 +36 +28 +25 +44 +74 +38 +48 +79 +45 +32 +51 +33 +61 +28 +27 +37 +40 +1 +19 +22 +88 +63 +34 +24 +39 +76 +12 +62 +83 +22 +76 +58 +53 +40 +37 +57 +41 +53 +30 +61 +61 +85 +33 +52 +78 +0 +3 +32 +54 +57 +84 +62 +14 +30 +15 +52 +44 +52 +61 +62 +44 +27 +47 +73 +63 +87 +19 +36 +31 +34 +40 +54 +32 +49 +67 +29 +40 +80 +37 +15 +53 +11 +27 +70 +13 +48 +19 +17 +61 +26 +87 +75 +64 +59 +44 +64 +36 +22 +69 +27 +43 +17 +52 +70 +47 +69 +20 +30 +49 +0 +44 +25 +67 +49 +52 +54 +89 +44 +15 +16 +28 +52 +41 +82 +76 +76 +60 +71 +22 +8 +18 +73 +21 +62 +44 +39 +33 +45 +52 +29 +30 +73 +45 +51 +65 +88 +65 +24 +45 +35 +71 +65 +62 +29 +29 +22 +71 +27 +48 +36 +72 +86 +49 +6 +26 +55 +41 +13 +48 +37 +38 +62 +58 +36 +39 +59 +43 +39 +54 +41 +2 +32 +58 +46 +39 +61 +42 +22 +41 +36 +47 +25 +48 +79 +19 +65 +56 +15 +72 +35 +89 +40 +53 +51 +38 +2 +23 +59 +50 +45 +32 +26 +44 +59 +47 +46 +62 +46 +59 +64 +39 +39 +67 +87 +60 +32 +53 +1 +0 +77 +76 +16 +77 +48 +89 +41 +65 +32 +19 +41 +64 +27 +6 +64 +63 +42 +34 +68 +39 +39 +53 +87 +22 +42 +44 +58 +48 +69 +23 +41 +11 +81 +53 +53 +85 +59 +39 +14 +59 +4 +64 +10 +1 +33 +25 +0 +47 +80 +45 +50 +52 +30 +32 +28 +47 +68 +7 +29 +31 +44 +87 +67 +23 +71 +43 +38 +38 +46 +39 +43 +64 +27 +56 +45 +14 +59 +88 +81 +7 +67 +74 +12 +82 +25 +76 +58 +12 +1 +11 +28 +38 +43 +52 +40 +65 +41 +51 +24 +65 +18 +19 +16 +0 +63 +58 +24 +16 +56 +0 +68 +80 +52 +42 +76 +55 +43 +0 +10 +4 +34 +40 +34 +40 +89 +61 +87 +16 +37 +87 +50 +28 +6 +34 +61 +38 +58 +68 +60 +37 +80 +36 +47 +46 +43 +53 +35 +11 +8 +70 +0 +39 +4 +22 +14 +19 +68 +75 +13 +81 +44 +85 +22 +87 +64 +50 +40 +45 +82 +29 +56 +62 +32 +40 +61 +16 +64 +30 +84 +44 +34 +22 +28 +40 +59 +33 +66 +59 +32 +88 +64 +76 +16 +46 +61 +87 +79 +69 +32 +43 +35 +90 +85 +30 +29 +18 +23 +66 +34 +26 +18 +8 +57 +54 +27 +72 +24 +33 +45 +42 +51 +80 +42 +27 +48 +29 +59 +50 +60 +53 +61 +11 +53 +43 +13 +49 +68 +11 +32 +31 +26 +48 +69 +87 +35 +19 +52 +34 +36 +44 +43 +78 +39 +71 +47 +35 +39 +53 +33 +51 +21 +76 +79 +63 +20 +50 +17 +23 +68 +60 +10 +89 +47 +59 +57 +27 +27 +28 +52 +56 +75 +32 +52 +54 +29 +38 +56 +62 +76 +0 +31 +26 +40 +33 +39 +42 +69 +73 +57 +59 +40 +40 +74 +64 +41 +22 +47 +35 +36 +18 +66 +65 +47 +30 +57 +89 +52 +23 +70 +32 +82 +40 +63 +80 +43 +88 +53 +61 +29 +43 +53 +51 +45 +5 +45 +30 +75 +35 +64 +7 +0 +59 +13 +71 +60 +55 +31 +42 +18 +65 +28 +23 +73 +67 +27 +35 +20 +71 +40 +20 +84 +89 +47 +79 +49 +46 +5 +42 +58 +69 +25 +55 +29 +27 +69 +45 +17 +81 +58 +76 +61 +44 +60 +32 +41 +73 +40 +43 +52 +46 +23 +38 +41 +26 +43 +19 +57 +30 +45 +53 +43 +34 +14 +52 +25 +50 +46 +19 +40 +79 +20 +82 +40 +63 +20 +53 +61 +32 +52 +50 +51 +16 +50 +48 +69 +45 +48 +0 +64 +47 +53 +10 +31 +32 +43 +77 +44 +68 +39 +18 +34 +81 +13 +64 +5 +60 +60 +10 +63 +54 +63 +60 +23 +54 +87 +59 +47 +11 +34 +44 +4 +67 +77 +73 +52 +49 +44 +8 +63 +49 +89 +72 +14 +58 +20 +66 +58 +84 +13 +70 +28 +12 +48 +0 +48 +0 +25 +20 +72 +37 +7 +46 +41 +17 +16 +14 +19 +37 +57 +38 +79 +18 +60 +59 +62 +45 +23 +25 +38 +49 +60 +9 +59 +41 +40 +3 +32 +25 +24 +63 +28 +40 +20 +61 +58 +20 +50 +61 +51 +6 +1 +49 +67 +8 +56 +33 +64 +36 +46 +10 +44 +82 +48 +36 +13 +84 +67 +55 +52 +81 +70 +33 +29 +60 +5 +4 +39 +22 +29 +73 +47 +0 +36 +57 +41 +47 +54 +81 +39 +34 +80 +41 +36 +47 +68 +72 +45 +42 +48 +55 +62 +28 +57 +31 +15 +83 +77 +46 +48 +69 +34 +88 +19 +10 +70 +1 +38 +52 +72 +54 +4 +53 +7 +51 +66 +43 +62 +1 +21 +9 +12 +13 +47 +53 +32 +33 +55 +56 +12 +23 +59 +60 +46 +46 +4 +42 +62 +32 +2 +45 +41 +19 +40 +42 +34 +38 +22 +60 +31 +79 +62 +33 +59 +56 +23 +71 +40 +74 +42 +24 +67 +21 +67 +46 +43 +59 +38 +50 +71 +32 +51 +22 +30 +52 +20 +48 +41 +71 +11 +25 +60 +1 +61 +39 +59 +48 +12 +38 +30 +65 +52 +75 +43 +45 +38 +53 +41 +47 +36 +55 +38 +29 +62 +53 +56 +42 +57 +44 +1 +35 +53 +41 +44 +27 +33 +45 +44 +72 +39 +64 +18 +45 +8 +54 +27 +9 +27 +22 +29 +58 +27 +0 +66 +12 +38 +0 +43 +42 +69 +43 +43 +82 +87 +76 +45 +81 +30 +43 +38 +38 +87 +33 +38 +32 +50 +81 +70 +68 +59 +63 +44 +29 +27 +67 +34 +55 +59 +32 +82 +21 +64 +71 +60 +61 +65 +78 +29 +32 +49 +20 +48 +28 +40 +78 +20 +3 +28 +43 +43 +72 +34 +27 +63 +73 +39 +13 +0 +39 +50 +56 +66 +8 +47 +36 +80 +84 +74 +57 +77 +42 +56 +54 +4 +73 +87 +75 +52 +50 +51 +44 +65 +25 +69 +59 +34 +41 +50 +55 +50 +81 +50 +74 +66 +47 +3 +80 +49 +89 +54 +44 +35 +89 +76 +42 +13 +65 +52 +55 +17 +75 +62 +23 +61 +32 +73 +64 +66 +51 +42 +2 +35 +45 +53 +47 +56 +23 +56 +26 +48 +35 +12 +29 +78 +42 +52 +66 +37 +42 +85 +54 +63 +11 +36 +4 +82 +37 +47 +88 +41 +31 +67 +31 +63 +33 +31 +11 +0 +38 +12 +30 +31 +16 +43 +84 +82 +4 +45 +30 +48 +37 +32 +23 +73 +30 +34 +78 +55 +44 +55 +54 +45 +47 +52 +36 +16 +46 +25 +18 +59 +32 +70 +24 +46 +51 +47 +70 +35 +39 +40 +36 +52 +19 +65 +10 +64 +23 +54 +49 +66 +63 +19 +42 +54 +40 +22 +81 +88 +5 +7 +28 +57 +29 +69 +53 +37 +48 +55 +28 +50 +52 +34 +50 +23 +71 +28 +77 +32 +59 +20 +6 +83 +17 +6 +35 +50 +46 +53 +87 +67 +37 +1 +68 +56 +28 +66 +47 +82 +34 +52 +37 +37 +42 +47 +78 +47 +82 +52 +42 +34 +31 +12 +62 +18 +45 +55 +71 +34 +25 +24 +44 +56 +79 +41 +20 +43 +57 +36 +16 +42 +36 +33 +80 +63 +59 +45 +76 +29 +14 +23 +29 +47 +33 +88 +82 +70 +54 +17 +61 +62 +62 +60 +46 +20 +87 +24 +59 +69 +47 +25 +49 +44 +48 +45 +73 +57 +33 +47 +1 +44 +59 +61 +27 +87 +44 +23 +75 +5 +61 +41 +54 +30 +29 +43 +40 +75 +76 +63 +41 +63 +25 +62 +23 +75 +64 +12 +88 +46 +80 +26 +21 +10 +54 +48 +8 +57 +28 +51 +41 +54 +61 +33 +43 +38 +10 +68 +45 +54 +6 +52 +72 +47 +17 +44 +19 +65 +31 +48 +0 +42 +87 +40 +89 +43 +59 +4 +54 +39 +48 +30 +34 +28 +58 +34 +9 +48 +55 +55 +23 +16 +37 +52 +17 +16 +45 +64 +27 +89 +46 +28 +40 +25 +70 +49 +68 +62 +84 +2 +46 +50 +75 +51 +1 +73 +46 +39 +61 +29 +71 +14 +59 +68 +39 +26 +60 +31 +60 +72 +44 +52 +42 +44 +67 +53 +70 +33 +90 +13 +72 +60 +61 +50 +72 +35 +18 +47 +5 +62 +52 +44 +33 +8 +77 +26 +46 +36 +56 +66 +28 +41 +39 +22 +55 +33 +73 +30 +62 +28 +37 +0 +50 +89 +31 +33 +56 +64 +34 +46 +87 +70 +17 +21 +33 +10 +55 +26 +78 +12 +69 +20 +35 +28 +40 +39 +32 +60 +61 +44 +44 +11 +58 +3 +34 +0 +47 +68 +78 +54 +88 +51 +89 +72 +53 +13 +33 +65 +7 +1 +76 +30 +41 +60 +34 +20 +30 +88 +1 +62 +89 +25 +52 +57 +38 +31 +87 +39 +64 +28 +76 +22 +3 +72 +52 +47 +38 +71 +54 +60 +31 +2 +50 +58 +68 +74 +41 +48 +26 +30 +47 +59 +57 +62 +52 +52 +32 +61 +39 +39 +87 +53 +42 +46 +62 +26 +36 +29 +80 +50 +50 +38 +52 +57 +24 +7 +68 +45 +23 +9 +47 +62 +37 +41 +13 +88 +69 +86 +42 +30 +86 +34 +19 +18 +62 +20 +43 +28 +43 +0 +70 +20 +69 +71 +34 +78 +22 +10 +44 +40 +73 +50 +38 +46 +47 +77 +58 +59 +30 +52 +63 +59 +47 +27 +70 +33 +45 +28 +59 +28 +62 +49 +44 +1 +29 +43 +58 +50 +32 +23 +38 +60 +55 +70 +22 +20 +19 +61 +86 +60 +59 +19 +82 +58 +26 +71 +51 +89 +56 +21 +47 +45 +24 +87 +52 +69 +73 +19 +22 +72 +19 +89 +52 +69 +57 +21 +36 +51 +32 +59 +65 +60 +28 +53 +35 +55 +41 +58 +34 +19 +40 +43 +62 +52 +49 +50 +88 +51 +9 +39 +65 +43 +23 +53 +21 +33 +50 +58 +74 +61 +32 +25 +80 +35 +3 +49 +43 +44 +59 +36 +47 +42 +39 +66 +0 +25 +23 +32 +51 +37 +61 +70 +70 +29 +52 +39 +37 +34 +37 +41 +57 +42 +55 +28 +21 +51 +62 +43 +28 +43 +71 +28 +38 +14 +58 +43 +1 +57 +1 +50 +41 +33 +63 +46 +56 +56 +45 +6 +48 +27 +54 +50 +65 +39 +32 +60 +63 +30 +88 +88 +32 +30 +35 +60 +87 +35 +23 +58 +42 +11 +22 +30 +35 +30 +74 +17 +51 +65 +72 +38 +51 +63 +74 +49 +82 +62 +87 +70 +11 +35 +69 +72 +60 +54 +68 +44 +71 +38 +0 +10 +27 +42 +74 +63 +43 +15 +76 +14 +56 +37 +45 +40 +49 +66 +3 +11 +74 +43 +48 +23 +41 +42 +54 +38 +8 +48 +30 +19 +66 +39 +27 +36 +16 +51 +59 +1 +70 +62 +37 +40 +52 +52 +27 +7 +58 +43 +41 +70 +26 +35 +46 +58 +28 +44 +58 +88 +47 +48 +4 +22 +28 +35 +23 +56 +31 +56 +14 +5 +58 +39 +32 +58 +59 +53 +0 +72 +28 +70 +16 +0 +52 +57 +82 +1 +29 +77 +12 +75 +72 +33 +54 +36 +55 +38 +37 +30 +51 +31 +54 +70 +5 +64 +26 +63 +38 +0 +47 +70 +46 +41 +34 +59 +16 +61 +26 +24 +39 +42 +34 +44 +57 +50 +31 +53 +24 +65 +45 +50 +40 +45 +63 +41 +45 +48 +48 +47 +35 +30 +67 +30 +44 +77 +48 +74 +56 +25 +87 +64 +66 +57 +67 +87 +84 +78 +23 +72 +17 +45 +35 +7 +36 +19 +49 +52 +62 +34 +41 +16 +34 +60 +0 +38 +61 +38 +18 +13 +24 +29 +39 +15 +29 +60 +18 +87 +45 +61 +18 +74 +50 +75 +46 +53 +60 +44 +57 +45 +56 +49 +71 +21 +47 +49 +30 +12 +39 +59 +18 +39 +25 +45 +27 +72 +64 +59 +32 +53 +47 +36 +12 +61 +39 +52 +20 +11 +19 +0 +85 +36 +28 +61 +38 +48 +17 +32 +22 +33 +72 +4 +72 +55 +71 +9 +28 +31 +29 +75 +34 +79 +44 +16 +56 +67 +28 +22 +34 +0 +26 +0 +62 +55 +39 +30 +45 +59 +50 +77 +89 +21 +57 +80 +64 +58 +62 +20 +60 +55 +62 +47 +38 +1 +88 +58 +23 +44 +71 +29 +80 +50 +78 +66 +37 +30 +24 +5 +28 +23 +49 +54 +87 +72 +31 +63 +16 +32 +45 +33 +68 +67 +40 +33 +12 +69 +31 +39 +71 +31 +58 +69 +23 +20 +17 +37 +44 +57 +87 +12 +46 +56 +33 +54 +42 +54 +32 +62 +41 +30 +46 +34 +74 +20 +15 +37 +32 +60 +46 +66 +43 +56 +58 +74 +65 +30 +48 +30 +47 +61 +32 +81 +35 +9 +24 +1 +26 +45 +14 +36 +59 +52 +66 +69 +65 +44 +52 +73 +36 +87 +54 +20 +82 +48 +62 +83 +0 +57 +44 +29 +42 +87 +62 +45 +35 +47 +51 +31 +52 +62 +53 +32 +47 +0 +51 +25 +36 +39 +56 +22 +34 +40 +36 +67 +50 +23 +42 +36 +16 +4 +50 +20 +52 +45 +63 +48 +40 +35 +19 +87 +41 +39 +36 +67 +67 +48 +46 +36 +42 +43 +71 +33 +52 +55 +35 +24 +88 +64 +52 +78 +77 +30 +35 +42 +15 +31 +53 +35 +13 +56 +77 +26 +72 +65 +37 +46 +54 +51 +55 +1 +55 +48 +0 +22 +28 +29 +27 +78 +70 +54 +10 +61 +51 +47 +32 +49 +50 +75 +32 +30 +32 +13 +52 +73 +83 +51 +63 +84 +30 +20 +29 +70 +21 +32 +49 +36 +44 +7 +50 +64 +15 +49 +0 +52 +28 +31 +15 +40 +47 +48 +56 +0 +33 +59 +57 +44 +63 +89 +44 +65 +55 +62 +35 +51 +31 +34 +14 +59 +26 +57 +62 +30 +38 +11 +38 +66 +48 +59 +1 +64 +12 +44 +17 +8 +37 +1 +38 +6 +44 +32 +61 +40 +41 +48 +21 +40 +19 +44 +44 +71 +42 +34 +10 +34 +47 +55 +25 +65 +66 +19 +44 +31 +23 +65 +54 +59 +38 +32 +55 +53 +32 +48 +33 +7 +32 +63 +20 +68 +76 +55 +36 +10 +49 +34 +45 +42 +62 +52 +88 +25 +42 +32 +50 +66 +18 +64 +83 +29 +18 +58 +48 +39 +41 +6 +51 +75 +53 +41 +47 +0 +34 +10 +40 +64 +26 +44 +32 +58 +43 +51 +24 +39 +24 +21 +57 +50 +49 +24 +6 +70 +19 +48 +85 +62 +70 +33 +67 +35 +30 +34 +48 +32 +87 +87 +32 +42 +9 +51 +60 +40 +47 +57 +34 +59 +51 +44 +68 +65 +27 +36 +51 +78 +71 +6 +46 +38 +1 +83 +0 +50 +45 +58 +7 +32 +1 +52 +17 +47 +69 +0 +41 +72 +59 +4 +51 +61 +51 +17 +87 +17 +52 +66 +10 +0 +65 +58 +49 +35 +52 +59 +30 +57 +66 +61 +61 +22 +50 +36 +53 +86 +17 +36 +43 +4 +42 +64 +40 +27 +33 +88 +14 +51 +14 +28 +18 +55 +33 +46 +27 +0 +51 +46 +12 +66 +52 +45 +35 +60 +44 +43 +62 +20 +61 +58 +84 +53 +36 +11 +70 +36 +68 +32 +14 +63 +42 +65 +16 +70 +39 +48 +42 +52 +68 +33 +30 +65 +1 +47 +61 +87 +16 +82 +44 +87 +65 +72 +79 +24 +32 +24 +51 +59 +58 +71 +30 +1 +30 +45 +20 +4 +34 +66 +51 +20 +20 +46 +73 +67 +53 +23 +64 +26 +43 +67 +61 +14 +1 +58 +35 +63 +19 +61 +0 +51 +29 +36 +59 +24 +22 +54 +48 +56 +20 +28 +17 +56 +51 +69 +31 +54 +51 +11 +33 +54 +28 +76 +39 +46 +46 +62 +78 +47 +54 +27 +78 +54 +35 +81 +19 +10 +37 +69 +58 +36 +6 +0 +26 +33 +43 +77 +2 +61 +52 +55 +38 +31 +57 +38 +54 +1 +33 +47 +46 +73 +43 +73 +75 +9 +42 +73 +3 +48 +22 +37 +59 +87 +18 +52 +4 +38 +34 +64 +68 +35 +62 +60 +3 +40 +27 +25 +35 +34 +23 +49 +61 +15 +45 +66 +62 +85 +71 +51 +31 +36 +37 +42 +49 +57 +52 +15 +22 +41 +9 +75 +52 +53 +57 +44 +34 +63 +17 +36 +30 +19 +66 +87 +66 +36 +59 +6 +60 +91 +46 +68 +15 +59 +21 +16 +5 +44 +34 +89 +63 +46 +62 +55 +39 +54 +67 +60 +0 +2 +25 +60 +57 +34 +14 +71 +40 +11 +40 +37 +51 +32 +62 +61 +42 +1 +54 +25 +59 +70 +35 +89 +12 +87 +46 +62 +34 +35 +61 +71 +64 +1 +45 +84 +33 +57 +26 +28 +70 +59 +70 +48 +30 +52 +61 +18 +22 +67 +50 +11 +4 +47 +34 +39 +43 +56 +36 +59 +70 +56 +30 +33 +31 +39 +57 +15 +44 +40 +53 +49 +35 +87 +32 +69 +82 +45 +89 +58 +6 +50 +55 +87 +34 +38 +5 +33 +21 +40 +26 +88 +74 +45 +87 +40 +14 +36 +40 +56 +43 +14 +67 +17 +57 +29 +49 +61 +25 +86 +43 +58 +20 +1 +12 +27 +81 +71 +24 +56 +17 +55 +57 +49 +43 +69 +42 +64 +55 +46 +52 +53 +70 +88 +75 +46 +80 +53 +70 +57 +44 +21 +29 +38 +88 +28 +33 +7 +16 +85 +49 +29 +74 +64 +6 +16 +9 +39 +56 +55 +44 +51 +18 +18 +42 +34 +13 +38 +52 +61 +17 +60 +18 +58 +87 +62 +22 +46 +46 +48 +56 +34 +33 +44 +44 +26 +71 +67 +47 +59 +20 +46 +45 +48 +68 +25 +40 +35 +24 +16 +37 +60 +38 +71 +31 +53 +47 +69 +33 +0 +62 +16 +54 +28 +50 +36 +60 +38 +47 +40 +30 +0 +25 +22 +59 +24 +49 +45 +53 +64 +13 +77 +60 +87 +27 +10 +62 +66 +58 +61 +28 +72 +89 +52 +33 +30 +29 +33 +60 +51 +27 +87 +21 +48 +40 +41 +58 +42 +32 +8 +19 +44 +27 +68 +70 +54 +25 +62 +66 +31 +33 +26 +44 +44 +1 +62 +10 +69 +18 +55 +76 +58 +44 +53 +87 +54 +62 +58 +25 +18 +80 +18 +66 +45 +43 +43 +8 +50 +18 +45 +69 +10 +1 +61 +45 +41 +48 +57 +21 +60 +4 +46 +61 +41 +84 +45 +43 +51 +32 +64 +64 +53 +32 +64 +34 +28 +65 +73 +68 +59 +41 +35 +87 +43 +1 +59 +46 +26 +48 +38 +51 +40 +54 +76 +49 +25 +29 +33 +10 +58 +51 +52 +87 +59 +57 +73 +54 +9 +67 +19 +52 +23 +26 +32 +20 +79 +61 +41 +17 +52 +44 +41 +55 +13 +53 +13 +52 +50 +38 +45 +81 +20 +31 +40 +51 +83 +36 +18 +29 +38 +55 +23 +72 +47 +15 +25 +67 +40 +71 +64 +76 +32 +89 +48 +33 +58 +32 +73 +63 +12 +70 +58 +73 +19 +72 +74 +47 +55 +78 +4 +30 +37 +58 +30 +31 +53 +22 +0 +45 +36 +45 +73 +83 +37 +87 +0 +35 +39 +27 +22 +34 +11 +48 +82 +52 +25 +49 +52 +7 +36 +64 +74 +0 +29 +22 +38 +13 +52 +60 +76 +50 +41 +18 +28 +6 +44 +19 +18 +60 +34 +52 +34 +62 +31 +85 +75 +32 +35 +38 +9 +37 +17 +36 +51 +73 +43 +0 +69 +61 +4 +18 +60 +48 +72 +56 +44 +71 +25 +40 +40 +32 +41 +40 +35 +87 +25 +29 +44 +67 +15 +22 +87 +49 +19 +66 +89 +49 +35 +33 +75 +24 +75 +44 +86 +22 +26 +22 +10 +45 +15 +23 +48 +42 +8 +69 +44 +26 +57 +56 +67 +36 +55 +19 +32 +35 +70 +9 +84 +39 +57 +65 +41 +34 +46 +74 +34 +39 +53 +8 +26 +10 +70 +62 +80 +41 +51 +71 +68 +34 +34 +73 +52 +51 +37 +34 +73 +72 +33 +22 +28 +21 +23 +73 +38 +16 +0 +28 +32 +44 +59 +29 +89 +87 +59 +9 +63 +88 +11 +77 +42 +29 +64 +47 +31 +42 +46 +68 +56 +53 +41 +64 +87 +76 +36 +62 +66 +44 +45 +74 +66 +45 +87 +14 +55 +44 +50 +74 +71 +20 +68 +45 +38 +22 +40 +72 +26 +42 +33 +57 +29 +22 +69 +3 +28 +53 +30 +32 +54 +49 +68 +27 +54 +26 +50 +48 +18 +70 +81 +37 +55 +53 +23 +52 +72 +66 +30 +48 +34 +53 +54 +19 +88 +44 +34 +67 +58 +71 +7 +7 +13 +54 +23 +18 +32 +41 +60 +35 +63 +22 +29 +35 +53 +39 +76 +32 +56 +82 +1 +53 +6 +22 +14 +5 +62 +50 +41 +84 +39 +44 +31 +59 +17 +32 +31 +65 +32 +20 +56 +46 +13 +17 +58 +54 +38 +14 +39 +53 +64 +18 +46 +12 +34 +38 +33 +36 +62 +0 +39 +23 +72 +57 +23 +50 +33 +59 +63 +25 +55 +0 +33 +0 +47 +68 +22 +36 +41 +35 +32 +27 +2 +64 +27 +30 +61 +59 +48 +26 +64 +66 +65 +47 +26 +26 +60 +69 +25 +33 +47 +13 +64 +29 +23 +71 +87 +31 +65 +7 +37 +20 +14 +53 +50 +52 +29 +50 +60 +44 +6 +40 +87 +32 +34 +50 +10 +31 +30 +71 +47 +27 +79 +30 +46 +7 +56 +35 +1 +23 +61 +21 +62 +62 +31 +84 +51 +51 +64 +28 +48 +16 +63 +33 +82 +71 +28 +34 +59 +73 +3 +53 +36 +22 +18 +36 +27 +63 +72 +70 +88 +15 +63 +52 +63 +12 +40 +67 +60 +64 +27 +32 +60 +47 +1 +6 +17 +32 +34 +76 +36 +72 +73 +49 +57 +31 +61 +16 +77 +37 +19 +33 +54 +21 +25 +58 +21 +34 +25 +38 +53 +20 +1 +52 +66 +41 +42 +13 +54 +20 +27 +47 +19 +43 +58 +32 +19 +50 +14 +50 +28 +52 +73 +38 +40 +63 +79 +76 +33 +37 +65 +29 +14 +38 +46 +44 +64 +87 +87 +56 +20 +25 +31 +27 +38 +87 +41 +69 +36 +41 +14 +6 +30 +11 +53 +81 +43 +48 +7 +67 +36 +46 +56 +70 +0 +63 +13 +72 +69 +12 +51 +40 +62 +46 +23 +37 +69 +13 +28 +76 +12 +49 +39 +19 +21 +13 +34 +49 +23 +55 +67 +71 +77 +58 +64 +1 +34 +39 +39 +35 +22 +12 +56 +7 +14 +61 +41 +0 +26 +79 +55 +24 +48 +53 +64 +65 +25 +8 +49 +28 +47 +51 +58 +11 +47 +51 +70 +9 +37 +50 +23 +30 +29 +64 +18 +49 +74 +50 +36 +42 +87 +40 +49 +58 +24 +31 +58 +49 +54 +22 +16 +44 +56 +37 +14 +31 +31 +89 +32 +64 +60 +60 +31 +39 +42 +51 +58 +59 +29 +0 +53 +4 +79 +50 +45 +41 +53 +35 +43 +69 +51 +40 +37 +54 +54 +43 +30 +23 +34 +56 +27 +27 +68 +51 +83 +40 +1 +24 +7 +49 +67 +79 +23 +53 +67 +63 +48 +64 +12 +22 +45 +1 +20 +61 +54 +63 +11 +43 +79 +21 +56 +20 +66 +21 +47 +38 +63 +57 +42 +29 +28 +70 +65 +41 +38 +62 +15 +42 +9 +1 +35 +79 +72 +51 +64 +25 +7 +88 +59 +58 +15 +25 +65 +31 +0 +86 +1 +37 +13 +19 +18 +48 +35 +35 +49 +59 +6 +70 +51 +49 +16 +40 +34 +61 +27 +21 +47 +9 +5 +67 +52 +15 +50 +71 +74 +30 +54 +31 +28 +44 +44 +38 +2 +71 +16 +66 +69 +40 +36 +53 +26 +53 +54 +13 +64 +58 +5 +65 +48 +22 +82 +13 +22 +46 +60 +76 +46 +40 +54 +29 +74 +30 +53 +41 +73 +75 +33 +29 +53 +53 +27 +21 +63 +52 +68 +87 +16 +52 +59 +74 +37 +82 +45 +31 +78 +48 +65 +45 +38 +11 +21 +88 +50 +17 +71 +43 +49 +56 +68 +66 +48 +42 +53 +60 +56 +15 +72 +44 +1 +60 +29 +46 +46 +41 +45 +66 +36 +88 +27 +36 +27 +13 +28 +62 +54 +74 +89 +10 +8 +26 +63 +23 +53 +52 +0 +32 +61 +0 +37 +51 +56 +44 +83 +50 +33 +49 +63 +60 +45 +17 +34 +28 +56 +89 +18 +58 +34 +12 +50 +17 +55 +42 +57 +59 +3 +66 +49 +0 +48 +65 +40 +29 +32 +26 +45 +25 +55 +28 +19 +59 +48 +62 +59 +25 +62 +57 +43 +41 +87 +40 +56 +30 +52 +29 +46 +1 +52 +59 +88 +59 +49 +30 +87 +81 +51 +43 +41 +46 +62 +11 +55 +67 +35 +63 +84 +72 +13 +66 +42 +40 +23 +40 +52 +28 +42 +22 +64 +53 +35 +10 +71 +55 +50 +58 +38 +7 +87 +35 +10 +68 +70 +46 +78 +49 +63 +63 +69 +32 +66 +24 +65 +60 +37 +38 +11 +69 +73 +70 +31 +68 +44 +10 +52 +70 +76 +22 +56 +62 +74 +58 +16 +6 +41 +34 +53 +60 +78 +62 +57 +53 +28 +18 +33 +34 +30 +34 +0 +57 +82 +65 +40 +25 +27 +59 +8 +60 +58 +36 +61 +57 +56 +15 +27 +45 +82 +27 +44 +74 +26 +46 +49 +66 +54 +48 +51 +37 +87 +89 +45 +42 +6 +57 +21 +33 +8 +18 +50 +38 +28 +38 +35 +32 +49 +50 +16 +55 +30 +87 +33 +44 +86 +10 +33 +87 +50 +67 +68 +58 +47 +72 +64 +52 +46 +42 +54 +49 +72 +56 +66 +18 +54 +64 +11 +40 +43 +11 +59 +30 +59 +50 +56 +34 +69 +65 +44 +48 +45 +37 +30 +42 +13 +78 +59 +54 +54 +54 +66 +52 +34 +50 +63 +89 +19 +62 +50 +44 +35 +47 +30 +9 +0 +0 +41 +55 +6 +68 +55 +77 +47 +42 +60 +26 +87 +26 +37 +37 +87 +51 +32 +66 +70 +27 +47 +39 +13 +4 +14 +53 +40 +48 +21 +51 +69 +64 +28 +21 +43 +45 +51 +60 +30 +53 +62 +42 +24 +36 +59 +23 +40 +33 +54 +42 +12 +62 +35 +77 +9 +30 +33 +33 +65 +36 +72 +84 +13 +9 +50 +56 +48 +37 +3 +56 +22 +0 +0 +87 +22 +38 +42 +29 +66 +43 +53 +24 +28 +1 +9 +25 +65 +54 +28 +29 +1 +29 +37 +61 +54 +21 +20 +49 +51 +31 +74 +39 +37 +47 +50 +0 +23 +26 +35 +42 +53 +33 +45 +27 +10 +30 +32 +21 +54 +76 +16 +50 +52 +67 +55 +76 +87 +40 +75 +36 +55 +76 +67 +47 +25 +79 +60 +29 +46 +59 +66 +85 +49 +12 +64 +37 +55 +35 +51 +62 +87 +66 +65 +57 +82 +27 +55 +10 +16 +0 +54 +61 +0 +55 +3 +71 +44 +77 +57 +34 +69 +58 +38 +20 +41 +83 +77 +78 +44 +77 +8 +40 +37 +24 +74 +33 +31 +52 +42 +22 +86 +36 +59 +71 +43 +55 +42 +37 +71 +21 +87 +40 +21 +15 +49 +33 +51 +39 +37 +1 +60 +16 +56 +54 +37 +67 +83 +88 +26 +38 +53 +54 +38 +58 +74 +69 +33 +44 +26 +39 +55 +79 +18 +52 +33 +73 +62 +47 +13 +58 +79 +52 +42 +57 +67 +63 +81 +45 +35 +71 +55 +66 +67 +87 +51 +58 +63 +72 +25 +36 +68 +43 +84 +46 +49 +54 +32 +36 +46 +31 +36 +37 +50 +45 +11 +46 +21 +87 +34 +32 +28 +53 +19 +54 +45 +38 +59 +53 +7 +48 +38 +30 +22 +33 +47 +62 +8 +37 +55 +20 +47 +53 +31 +85 +55 +23 +30 +87 +62 +31 +14 +89 +65 +0 +37 +61 +36 +70 +29 +49 +78 +37 +52 +77 +1 +55 +0 +37 +67 +45 +60 +38 +75 +31 +44 +69 +73 +52 +60 +68 +40 +23 +12 +20 +48 +52 +31 +58 +56 +78 +62 +42 +67 +13 +72 +21 +9 +44 +39 +56 +48 +54 +80 +73 +18 +47 +33 +40 +50 +37 +49 +45 +31 +10 +39 +41 +22 +79 +16 +31 +19 +55 +52 +5 +62 +35 +38 +12 +88 +87 +6 +44 +51 +24 +67 +79 +33 +74 +15 +42 +61 +32 +19 +34 +57 +37 +23 +87 +37 +57 +66 +13 +25 +62 +76 +2 +87 +44 +40 +38 +15 +29 +58 +1 +57 +52 +0 +67 +53 +40 +82 +89 +80 +48 +30 +26 +52 +31 +26 +40 +83 +40 +51 +40 +55 +36 +72 +57 +58 +32 +55 +65 +42 +1 +39 +27 +82 +43 +73 +0 +48 +48 +22 +51 +77 +47 +35 +63 +61 +8 +66 +61 +33 +47 +47 +57 +64 +51 +22 +26 +49 +31 +38 +52 +51 +41 +76 +39 +47 +23 +45 +60 +41 +32 +87 +46 +36 +70 +12 +32 +35 +23 +57 +66 +63 +84 +86 +73 +17 +61 +12 +65 +31 +46 +26 +58 +63 +63 +66 +39 +55 +55 +58 +54 +73 +47 +64 +52 +54 +44 +39 +44 +54 +87 +34 +39 +49 +11 +10 +65 +24 +40 +34 +58 +67 +24 +42 +87 +27 +37 +43 +58 +87 +56 +16 +52 +48 +23 +33 +75 +38 +35 +73 +52 +44 +29 +54 +25 +64 +22 +53 +61 +62 +12 +44 +54 +64 +44 +23 +73 +23 +40 +79 +45 +68 +46 +47 +0 +10 +75 +28 +60 +64 +22 +52 +33 +19 +59 +39 +31 +34 +16 +20 +27 +35 +85 +23 +18 +53 +56 +7 +48 +46 +45 +26 +36 +23 +60 +12 +19 +52 +13 +14 +82 +59 +46 +31 +48 +65 +37 +11 +27 +8 +30 +32 +66 +7 +58 +6 +60 +41 +58 +22 +69 +57 +36 +39 +34 +78 +72 +84 +40 +77 +26 +11 +76 +68 +52 +38 +82 +44 +35 +55 +85 +17 +57 +49 +76 +5 +67 +47 +75 +76 +61 +21 +36 +27 +4 +51 +0 +35 +33 +69 +26 +60 +55 +68 +56 +20 +34 +55 +33 +46 +25 +47 +57 +4 +39 +57 +50 +27 +38 +53 +32 +89 +57 +57 +56 +49 +60 +52 +35 +28 +58 +70 +82 +19 +31 +61 +87 +65 +12 +36 +41 +47 +51 +25 +87 +40 +32 +26 +36 +34 +17 +49 +59 +24 +9 +37 +11 +3 +62 +15 +43 +25 +33 +0 +61 +81 +52 +48 +38 +35 +54 +27 +1 +83 +41 +58 +53 +41 +44 +28 +68 +28 +1 +45 +61 +26 +69 +82 +43 +42 +25 +75 +72 +37 +71 +36 +36 +42 +76 +43 +50 +16 +58 +42 +27 +59 +27 +55 +21 +37 +63 +29 +54 +16 +43 +62 +19 +23 +9 +32 +50 +73 +34 +46 +9 +60 +39 +39 +52 +32 +56 +68 +74 +69 +38 +64 +72 +36 +63 +28 +78 +10 +49 +59 +51 +52 +53 +53 +25 +83 +39 +80 +71 +42 +6 +45 +29 +17 +74 +50 +21 +6 +77 +66 +40 +22 +61 +26 +87 +66 +14 +24 +75 +25 +52 +34 +43 +39 +16 +58 +56 +60 +37 +26 +65 +30 +44 +29 +40 +81 +16 +47 +41 +36 +49 +86 +25 +55 +15 +2 +17 +18 +28 +41 +20 +45 +28 +70 +89 +89 +26 +42 +80 +58 +28 +28 +34 +8 +28 +29 +50 +7 +40 +55 +44 +47 +28 +19 +43 +16 +72 +57 +61 +56 +61 +51 +32 +51 +29 +11 +37 +45 +52 +36 +44 +3 +22 +47 +79 +67 +55 +8 +88 +37 +39 +74 +21 +75 +22 +36 +29 +18 +22 +45 +28 +35 +37 +52 +36 +28 +63 +87 +58 +73 +5 +48 +75 +71 +50 +2 +82 +49 +63 +47 +34 +87 +28 +58 +16 +52 +28 +74 +33 +69 +50 +51 +60 +63 +36 +66 +32 +44 +39 +58 +39 +1 +42 +36 +17 +10 +74 +53 +34 +17 +38 +33 +50 +27 +70 +83 +24 +37 +60 +80 +59 +34 +18 +57 +22 +20 +42 +5 +17 +67 +24 +29 +21 +56 +70 +45 +33 +66 +34 +17 +40 +45 +36 +70 +24 +42 +81 +13 +60 +62 +40 +29 +35 +10 +48 +35 +47 +23 +49 +2 +24 +31 +37 +28 +14 +37 +62 +43 +49 +60 +41 +54 +1 +15 +49 +73 +56 +28 +87 +58 +51 +52 +59 +53 +27 +15 +24 +7 +74 +25 +45 +66 +59 +38 +16 +44 +56 +64 +76 +52 +18 +62 +76 +51 +56 +45 +85 +87 +0 +63 +84 +53 +76 +43 +27 +14 +40 +32 +27 +55 +80 +38 +20 +83 +14 +53 +19 +84 +24 +40 +9 +44 +54 +51 +30 +55 +67 +51 +71 +15 +34 +86 +74 +36 +66 +11 +72 +16 +63 +20 +26 +2 +16 +22 +54 +54 +43 +15 +71 +74 +5 +49 +63 +26 +39 +36 +56 +50 +18 +21 +89 +75 +23 +0 +59 +58 +57 +57 +87 +8 +53 +45 +80 +42 +44 +49 +61 +46 +19 +53 +19 +6 +2 +58 +46 +42 +56 +16 +66 +48 +52 +33 +60 +26 +38 +46 +81 +14 +11 +31 +14 +55 +22 +62 +48 +46 +16 +47 +25 +62 +70 +65 +53 +28 +48 +4 +32 +28 +6 +36 +46 +45 +19 +55 +49 +31 +40 +61 +44 +47 +33 +24 +59 +14 +52 +27 +6 +56 +39 +57 +62 +78 +34 +25 +7 +0 +60 +62 +63 +89 +75 +71 +35 +41 +60 +24 +68 +19 +63 +85 +48 +40 +40 +69 +52 +41 +25 +32 +46 +45 +71 +48 +0 +49 +41 +39 +43 +30 +73 +12 +50 +50 +43 +48 +87 +29 +54 +65 +89 +51 +34 +49 +37 +38 +67 +41 +58 +46 +70 +65 +28 +32 +25 +36 +33 +53 +89 +35 +70 +36 +39 +56 +48 +57 +69 +43 +33 +0 +59 +36 +37 +68 +42 +57 +56 +36 +48 +42 +13 +64 +44 +28 +43 +3 +17 +57 +41 +59 +44 +27 +45 +59 +0 +59 +69 +45 +41 +47 +50 +58 +45 +35 +8 +82 +59 +66 +54 +33 +39 +36 +47 +20 +63 +7 +53 +25 +72 +51 +43 +59 +50 +12 +14 +47 +50 +1 +59 +49 +20 +33 +74 +31 +25 +17 +63 +25 +42 +46 +22 +40 +71 +50 +64 +73 +22 +53 +25 +37 +44 +50 +58 +54 +41 +40 +50 +11 +18 +60 +43 +1 +52 +41 +29 +33 +78 +0 +13 +82 +59 +85 +0 +72 +2 +45 +24 +52 +23 +46 +80 +65 +45 +52 +44 +60 +42 +62 +63 +60 +51 +42 +59 +80 +65 +35 +57 +38 +29 +89 +69 +33 +29 +22 +28 +11 +53 +35 +20 +54 +86 +34 +30 +12 +51 +44 +29 +4 +35 +66 +35 +42 +61 +38 +48 +61 +62 +84 +84 +80 +58 +60 +34 +79 +28 +66 +83 +68 +19 +21 +28 +10 +26 +66 +50 +40 +64 +28 +21 +60 +46 +42 +2 +23 +45 +49 +34 +62 +53 +54 +44 +60 +30 +73 +59 +38 +18 +39 +13 +35 +26 +52 +22 +40 +0 +56 +68 +71 +61 +53 +39 +22 +26 +45 +32 +51 +78 +66 +45 +69 +75 +27 +8 +21 +56 +63 +60 +35 +53 +1 +70 +87 +37 +13 +69 +85 +46 +38 +25 +29 +41 +78 +47 +51 +46 +34 +73 +8 +50 +0 +29 +54 +29 +84 +46 +58 +27 +26 +23 +47 +45 +9 +30 +19 +31 +30 +30 +46 +26 +54 +40 +9 +65 +67 +35 +25 +43 +56 +24 +64 +74 +87 +42 +50 +62 +23 +38 +40 +3 +22 +53 +48 +27 +59 +47 +2 +52 +58 +53 +38 +27 +38 +54 +25 +27 +46 +40 +63 +2 +0 +82 +37 +19 +59 +0 +87 +63 +82 +69 +54 +52 +25 +61 +11 +35 +33 +75 +48 +76 +59 +80 +14 +32 +37 +47 +53 +19 +9 +87 +50 +33 +63 +45 +69 +58 +58 +73 +14 +53 +1 +44 +26 +43 +57 +53 +66 +73 +75 +35 +34 +30 +27 +0 +62 +16 +39 +49 +61 +30 +34 +51 +31 +52 +61 +46 +1 +52 +53 +8 +89 +51 +42 +77 +34 +25 +55 +44 +25 +56 +55 +57 +25 +57 +69 +32 +32 +48 +44 +69 +19 +63 +27 +30 +43 +37 +86 +58 +54 +24 +10 +15 +38 +15 +17 +44 +37 +33 +52 +56 +56 +81 +50 +60 +87 +77 +54 +49 +48 +73 +59 +14 +38 +89 +68 +62 +59 +46 +61 +54 +67 +35 +38 +56 +32 +39 +67 +84 +20 +87 +24 +59 +43 +51 +41 +87 +61 +43 +34 +38 +50 +12 +62 +25 +62 +48 +57 +11 +50 +27 +78 +85 +52 +23 +17 +35 +48 +31 +49 +35 +46 +72 +45 +49 +11 +35 +75 +68 +48 +7 +60 +43 +56 +43 +70 +21 +69 +16 +41 +42 +52 +43 +47 +31 +81 +38 +41 +47 +2 +13 +35 +45 +10 +59 +60 +66 +28 +31 +32 +14 +50 +72 +20 +62 +38 +26 +11 +83 +70 +0 +18 +74 +54 +37 +39 +39 +43 +69 +82 +40 +70 +36 +43 +66 +77 +15 +10 +42 +35 +27 +65 +51 +37 +23 +44 +55 +48 +20 +47 +16 +40 +61 +89 +9 +0 +43 +72 +0 +5 +64 +18 +74 +38 +50 +65 +54 +71 +31 +30 +62 +34 +29 +43 +87 +54 +68 +48 +11 +31 +29 +2 +69 +34 +28 +14 +51 +81 +55 +47 +60 +7 +52 +70 +51 +29 +51 +59 +33 +75 +56 +80 +42 +25 +62 +45 +37 +68 +38 +47 +15 +32 +88 +13 +50 +51 +73 +68 +64 +30 +36 +48 +21 +58 +42 +6 +55 +56 +34 +46 +42 +38 +14 +53 +37 +42 +41 +35 +77 +43 +16 +83 +46 +80 +23 +34 +31 +43 +42 +69 +39 +23 +47 +62 +39 +69 +57 +0 +53 +53 +56 +69 +72 +42 +53 +42 +67 +23 +54 +18 +53 +62 +31 +23 +86 +13 +35 +21 +77 +25 +30 +78 +51 +34 +12 +65 +38 +50 +38 +64 +44 +39 +68 +34 +89 +88 +35 +41 +70 +46 +21 +29 +47 +54 +33 +42 +47 +43 +54 +55 +68 +65 +56 +25 +53 +80 +55 +40 +1 +57 +59 +28 +58 +38 +22 +47 +41 +41 +60 +43 +63 +66 +72 +49 +52 +35 +44 +24 +90 +17 +33 +38 +58 +0 +31 +55 +52 +29 +75 +42 +28 +55 +53 +22 +40 +48 +76 +86 +38 +58 +70 +12 +24 +41 +66 +76 +69 +33 +88 +39 +79 +51 +16 +13 +2 +18 +38 +19 +51 +53 +76 +70 +67 +57 +13 +18 +16 +22 +56 +62 +38 +34 +31 +67 +23 +38 +27 +37 +21 +70 +23 +0 +72 +69 +0 +32 +36 +39 +46 +28 +21 +33 +53 +46 +66 +24 +9 +23 +21 +62 +84 +37 +42 +46 +25 +10 +36 +67 +46 +88 +66 +50 +79 +34 +44 +18 +45 +25 +43 +56 +64 +45 +42 +16 +72 +35 +59 +55 +49 +25 +51 +15 +51 +40 +62 +49 +86 +58 +3 +19 +17 +55 +59 +41 +28 +57 +47 +41 +47 +89 +35 +41 +71 +35 +71 +32 +32 +46 +39 +56 +66 +42 +17 +23 +20 +25 +24 +17 +55 +28 +90 +57 +42 +51 +45 +29 +74 +61 +0 +50 +52 +47 +62 +11 +38 +45 +34 +38 +62 +27 +51 +39 +39 +49 +44 +6 +55 +60 +45 +33 +68 +75 +32 +32 +30 +46 +31 +12 +44 +6 +41 +65 +46 +31 +47 +54 +33 +17 +27 +26 +35 +33 +4 +34 +32 +34 +14 +68 +25 +47 +67 +26 +32 +61 +34 +49 +0 +90 +27 +52 +63 +57 +73 +28 +57 +53 +51 +52 +46 +77 +84 +1 +38 +63 +74 +1 +53 +46 +47 +29 +49 +22 +51 +29 +78 +36 +73 +8 +52 +42 +8 +18 +72 +42 +68 +54 +53 +89 +56 +61 +88 +46 +46 +77 +29 +41 +58 +35 +30 +1 +65 +59 +47 +52 +0 +43 +76 +20 +66 +43 +12 +87 +42 +35 +31 +22 +28 +64 +7 +39 +59 +28 +19 +24 +67 +0 +44 +26 +4 +28 +67 +21 +10 +14 +83 +83 +62 +67 +51 +27 +32 +65 +65 +70 +28 +26 +15 +19 +23 +51 +25 +0 +60 +46 +36 +82 +54 +56 +2 +66 +56 +56 +50 +87 +61 +18 +50 +51 +76 +71 +72 +84 +20 +79 +34 +60 +53 +83 +32 +64 +1 +57 +51 +34 +87 +59 +57 +40 +55 +73 +22 +28 +22 +20 +75 +40 +25 +30 +30 +82 +76 +34 +28 +27 +54 +35 +0 +21 +48 +38 +25 +48 +25 +34 +69 +44 +79 +39 +34 +62 +42 +0 +26 +61 +20 +31 +35 +22 +48 +23 +49 +15 +72 +30 +53 +45 +23 +0 +72 +64 +44 +39 +22 +0 +86 +34 +37 +29 +53 +33 +49 +36 +35 +38 +15 +23 +63 +87 +43 +29 +53 +6 +22 +31 +42 +60 +9 +38 +42 +57 +29 +4 +30 +36 +58 +49 +34 +28 +49 +60 +67 +33 +57 +43 +42 +72 +65 +68 +58 +43 +48 +34 +33 +29 +29 +34 +50 +43 +1 +34 +28 +68 +47 +47 +32 +42 +44 +34 +25 +67 +44 +60 +16 +51 +63 +44 +16 +16 +83 +65 +55 +62 +52 +34 +1 +66 +66 +42 +56 +9 +25 +81 +66 +65 +31 +15 +47 +66 +6 +52 +51 +47 +42 +89 +1 +72 +73 +51 +7 +33 +49 +25 +31 +40 +30 +59 +48 +55 +68 +81 +4 +34 +60 +57 +27 +55 +52 +55 +76 +54 +67 +16 +74 +61 +51 +35 +57 +73 +28 +27 +58 +39 +73 +40 +68 +16 +58 +56 +68 +11 +22 +87 +70 +61 +67 +46 +49 +57 +32 +32 +26 +23 +82 +34 +44 +47 +48 +42 +35 +49 +50 +57 +47 +45 +39 +49 +67 +29 +89 +76 +70 +45 +68 +47 +39 +62 +65 +41 +8 +60 +66 +54 +89 +60 +60 +46 +43 +55 +76 +51 +11 +40 +28 +68 +22 +44 +36 +57 +58 +47 +42 +0 +43 +57 +31 +47 +53 +20 +3 +72 +35 +33 +54 +31 +27 +35 +16 +75 +72 +79 +21 +25 +63 +60 +32 +67 +42 +1 +15 +67 +51 +41 +0 +0 +40 +69 +55 +65 +20 +52 +16 +14 +35 +61 +35 +52 +33 +60 +42 +37 +60 +25 +87 +26 +63 +65 +71 +52 +30 +59 +46 +17 +57 +60 +50 +60 +55 +88 +45 +48 +41 +65 +52 +60 +40 +61 +13 +35 +50 +33 +29 +24 +48 +47 +26 +9 +60 +61 +59 +22 +27 +49 +2 +10 +49 +28 +41 +42 +58 +38 +42 +50 +66 +5 +7 +51 +43 +49 +24 +50 +45 +69 +51 +40 +58 +49 +15 +29 +0 +39 +32 +61 +40 +51 +12 +49 +56 +36 +57 +25 +26 +26 +31 +85 +67 +65 +32 +23 +59 +40 +45 +38 +46 +39 +25 +58 +76 +66 +15 +7 +52 +29 +57 +41 +49 +21 +26 +63 +48 +29 +36 +43 +30 +37 +17 +21 +40 +16 +34 +72 +65 +5 +1 +0 +22 +60 +47 +71 +48 +17 +38 +44 +67 +42 +64 +8 +40 +28 +56 +37 +45 +45 +44 +85 +35 +56 +55 +23 +46 +72 +11 +31 +71 +69 +77 +55 +24 +14 +53 +17 +70 +75 +24 +9 +63 +16 +24 +77 +87 +33 +60 +64 +39 +68 +72 +40 +64 +64 +3 +51 +50 +66 +63 +20 +39 +55 +89 +30 +46 +49 +75 +67 +21 +76 +40 +19 +40 +28 +62 +65 +34 +1 +22 +38 +33 +35 +16 +32 +26 +40 +72 +15 +62 +47 +63 +34 +31 +70 +62 +31 +12 +41 +82 +51 +38 +50 +22 +31 +59 +39 +31 +60 +34 +44 +37 +76 +46 +9 +34 +58 +16 +80 +87 +3 +65 +35 +40 +48 +79 +58 +73 +73 +7 +32 +65 +46 +29 +41 +40 +30 +31 +18 +29 +56 +26 +53 +34 +55 +25 +0 +12 +73 +65 +48 +63 +42 +46 +44 +19 +49 +65 +18 +76 +88 +0 +0 +34 +42 +50 +21 +14 +83 +37 +24 +62 +81 +68 +0 +5 +49 +55 +21 +50 +39 +41 +43 +52 +15 +28 +36 +45 +25 +32 +60 +14 +87 +17 +68 +47 +49 +56 +51 +83 +90 +24 +22 +18 +68 +65 +65 +1 +49 +28 +87 +72 +46 +41 +24 +74 +65 +52 +57 +26 +20 +68 +2 +60 +35 +23 +36 +60 +43 +10 +71 +39 +40 +66 +90 +49 +45 +43 +66 +73 +38 +22 +46 +43 +43 +54 +76 +1 +76 +59 +0 +34 +33 +52 +53 +37 +10 +32 +52 +42 +65 +36 +52 +50 +21 +43 +56 +55 +21 +51 +29 +54 +71 +16 +39 +7 +48 +64 +64 +33 +48 +88 +57 +20 +28 +35 +16 +37 +28 +25 +36 +55 +39 +54 +43 +30 +25 +70 +43 +69 +61 +48 +61 +35 +37 +28 +19 +88 +51 +57 +89 +90 +26 +87 +25 +45 +67 +14 +75 +10 +37 +55 +35 +65 +35 +39 +63 +59 +66 +42 +48 +89 +88 +16 +17 +39 +31 +53 +50 +38 +39 +20 +13 +75 +27 +71 +53 +68 +65 +58 +30 +21 +43 +35 +49 +49 +70 +70 +56 +61 +82 +87 +5 +37 +53 +45 +32 +52 +34 +49 +73 +4 +73 +49 +53 +42 +2 +59 +32 +7 +79 +85 +53 +50 +42 +21 +50 +49 +49 +43 +57 +63 +41 +56 +74 +25 +57 +48 +35 +39 +51 +43 +63 +35 +79 +69 +23 +29 +39 +33 +39 +54 +37 +55 +34 +41 +83 +35 +23 +65 +62 +37 +1 +50 +30 +30 +50 +82 +4 +47 +90 +11 +53 +28 +4 +48 +46 +15 +72 +47 +58 +25 +41 +65 +31 +56 +29 +72 +86 +67 +80 +88 +69 +32 +39 +30 +59 +85 +56 +55 +35 +76 +83 +22 +11 +68 +33 +88 +67 +52 +10 +44 +57 +78 +79 +43 +52 +6 +4 +27 +81 +34 +22 +89 +31 +38 +75 +49 +86 +43 +37 +63 +61 +62 +20 +39 +30 +19 +56 +59 +37 +56 +78 +42 +45 +38 +25 +35 +19 +18 +32 +41 +45 +53 +71 +36 +29 +69 +41 +32 +75 +41 +25 +39 +45 +35 +36 +57 +54 +51 +30 +64 +62 +43 +62 +32 +27 +44 +17 +20 +36 +48 +6 +18 +38 +30 +46 +54 +44 +38 +61 +42 +32 +57 +35 +45 +51 +65 +51 +2 +22 +39 +65 +33 +39 +50 +55 +70 +0 +73 +61 +42 +31 +66 +47 +48 +37 +38 +54 +15 +27 +2 +57 +74 +67 +38 +11 +38 +64 +87 +7 +55 +24 +46 +18 +40 +37 +8 +37 +34 +40 +41 +19 +34 +60 +52 +5 +42 +39 +69 +64 +32 +67 +79 +37 +41 +70 +30 +89 +25 +46 +54 +55 +87 +22 +72 +41 +22 +46 +33 +62 +55 +33 +62 +24 +27 +23 +27 +40 +60 +39 +62 +68 +32 +40 +44 +28 +23 +52 +39 +0 +61 +28 +40 +19 +33 +54 +29 +47 +37 +44 +31 +47 +31 +36 +24 +51 +18 +56 +63 +37 +30 +64 +56 +87 +88 +42 +69 +61 +66 +12 +52 +36 +54 +39 +43 +43 +19 +53 +52 +56 +30 +84 +54 +55 +42 +76 +35 +25 +59 +62 +64 +58 +36 +1 +34 +45 +43 +49 +71 +62 +53 +70 +85 +44 +65 +61 +19 +2 +46 +69 +73 +0 +39 +12 +74 +41 +72 +89 +49 +46 +0 +35 +47 +44 +75 +44 +44 +72 +44 +36 +67 +35 +44 +49 +88 +41 +65 +42 +39 +41 +20 +84 +48 +1 +38 +45 +68 +62 +53 +48 +49 +87 +30 +13 +54 +55 +83 +64 +1 +50 +59 +70 +19 +80 +50 +67 +9 +53 +40 +8 +48 +82 +45 +22 +43 +47 +43 +61 +37 +2 +51 +1 +38 +33 +54 +0 +46 +57 +41 +52 +29 +36 +27 +29 +20 +46 +60 +50 +73 +43 +45 +39 +30 +75 +51 +77 +21 +41 +11 +59 +63 +65 +23 +45 +56 +54 +45 +46 +12 +29 +58 +43 +15 +22 +22 +76 +35 +56 +70 +49 +52 +31 +22 +66 +46 +80 +48 +31 +79 +15 +31 +5 +43 +56 +30 +35 +54 +59 +49 +59 +2 +62 +83 +42 +32 +9 +7 +33 +56 +61 +40 +16 +44 +60 +28 +25 +42 +50 +62 +47 +56 +27 +35 +39 +56 +52 +41 +38 +38 +54 +70 +17 +5 +73 +39 +14 +27 +16 +9 +46 +45 +75 +38 +47 +37 +50 +50 +35 +72 +61 +60 +39 +20 +25 +21 +40 +54 +76 +67 +18 +14 +39 +54 +38 +9 +34 +50 +60 +50 +35 +12 +46 +65 +15 +17 +47 +15 +47 +72 +55 +17 +65 +34 +34 +51 +28 +51 +9 +49 +42 +18 +47 +46 +6 +37 +26 +23 +52 +34 +88 +30 +36 +47 +57 +72 +18 +68 +87 +48 +49 +0 +48 +38 +14 +74 +38 +38 +4 +65 +21 +34 +78 +10 +65 +68 +62 +57 +39 +17 +36 +34 +67 +65 +55 +39 +71 +29 +60 +74 +48 +48 +39 +88 +58 +53 +62 +32 +32 +58 +11 +51 +73 +56 +57 +89 +61 +24 +33 +31 +41 +0 +66 +89 +46 +35 +68 +57 +44 +24 +59 +33 +1 +47 +29 +54 +34 +49 +16 +41 +48 +58 +37 +74 +53 +63 +29 +11 +46 +43 +15 +47 +19 +54 +52 +54 +35 +89 +52 +24 +1 +57 +15 +49 +13 +9 +51 +57 +69 +82 +26 +45 +83 +12 +13 +48 +8 +59 +42 +26 +20 +8 +17 +25 +30 +40 +33 +68 +64 +71 +71 +27 +88 +29 +1 +73 +35 +30 +59 +10 +48 +66 +88 +79 +65 +60 +51 +81 +85 +41 +57 +30 +59 +81 +69 +36 +9 +72 +42 +43 +21 +24 +21 +39 +66 +60 +36 +53 +38 +37 +90 +78 +51 +46 +33 +12 +36 +32 +78 +65 +86 +49 +23 +47 +43 +43 +30 +84 +14 +41 +77 +68 +47 +87 +1 +60 +58 +49 +89 +4 +34 +40 +25 +39 +49 +68 +51 +3 +59 +40 +42 +72 +55 +52 +19 +64 +48 +80 +54 +35 +32 +63 +69 +68 +57 +50 +29 +26 +49 +47 +44 +36 +81 +15 +34 +69 +55 +79 +38 +37 +53 +28 +46 +52 +42 +33 +61 +22 +45 +60 +88 +59 +59 +53 +19 +77 +0 +65 +67 +39 +46 +35 +47 +45 +59 +24 +81 +27 +88 +37 +59 +50 +9 +27 +71 +27 +43 +27 +38 +42 +18 +38 +43 +43 +10 +87 +72 +57 +5 +56 +26 +44 +34 +67 +67 +58 +69 +41 +43 +62 +11 +46 +57 +72 +56 +18 +73 +59 +87 +24 +39 +8 +29 +73 +59 +37 +69 +50 +33 +35 +12 +60 +38 +21 +15 +72 +71 +23 +27 +69 +16 +39 +61 +32 +84 +38 +81 +26 +87 +51 +54 +50 +46 +54 +11 +42 +42 +31 +50 +22 +63 +82 +15 +86 +41 +36 +57 +7 +47 +42 +56 +0 +28 +0 +37 +42 +64 +24 +70 +45 +56 +60 +38 +23 +58 +32 +15 +51 +65 +22 +25 +0 +44 +14 +47 +89 +62 +46 +70 +51 +54 +38 +69 +21 +32 +39 +37 +49 +56 +56 +66 +48 +75 +74 +44 +0 +0 +36 +30 +71 +39 +62 +69 +55 +44 +55 +55 +33 +32 +41 +63 +35 +79 +51 +39 +49 +73 +0 +36 +54 +33 +80 +34 +34 +39 +53 +88 +66 +23 +48 +74 +60 +41 +23 +57 +48 +74 +80 +22 +42 +14 +22 +71 +40 +26 +24 +7 +70 +32 +73 +26 +36 +44 +67 +35 +73 +60 +37 +5 +51 +54 +79 +30 +30 +44 +64 +28 +21 +46 +65 +51 +90 +41 +42 +56 +59 +7 +70 +53 +36 +1 +48 +13 +40 +29 +74 +46 +44 +34 +44 +44 +2 +0 +26 +59 +38 +15 +52 +25 +28 +50 +63 +53 +66 +40 +89 +38 +39 +61 +23 +41 +50 +40 +12 +69 +42 +21 +71 +20 +59 +29 +36 +34 +49 +68 +27 +42 +60 +49 +68 +7 +31 +62 +40 +58 +19 +49 +35 +57 +11 +80 +30 +33 +12 +70 +44 +25 +24 +35 +19 +43 +33 +43 +80 +28 +36 +65 +47 +38 +34 +49 +36 +87 +47 +68 +21 +41 +39 +49 +75 +52 +63 +64 +21 +47 +27 +35 +17 +89 +48 +23 +60 +37 +35 +9 +67 +76 +49 +57 +48 +57 +49 +57 +37 +39 +43 +29 +87 +46 +33 +26 +29 +18 +10 +62 +44 +57 +15 +27 +14 +21 +9 +64 +4 +40 +13 +26 +57 +48 +87 +45 +39 +72 +0 +39 +53 +9 +55 +57 +37 +42 +41 +37 +32 +25 +58 +44 +67 +23 +23 +47 +34 +53 +36 +71 +50 +33 +2 +71 +34 +22 +86 +12 +33 +28 +62 +66 +18 +76 +42 +45 +52 +38 +2 +27 +89 +48 +12 +23 +74 +33 +38 +19 +41 +36 +0 +65 +82 +38 +30 +48 +20 +56 +53 +43 +57 +36 +8 +67 +43 +62 +30 +34 +58 +60 +75 +50 +33 +58 +74 +55 +81 +58 +28 +41 +83 +50 +32 +44 +60 +70 +52 +53 +47 +10 +0 +46 +65 +14 +68 +50 +28 +0 +25 +48 +68 +44 +13 +15 +42 +89 +28 +18 +23 +11 +28 +35 +58 +73 +64 +63 +87 +56 +3 +58 +6 +32 +28 +27 +75 +42 +61 +47 +82 +20 +72 +22 +34 +28 +40 +39 +9 +37 +59 +33 +9 +50 +29 +57 +49 +33 +6 +45 +57 +45 +75 +43 +39 +24 +32 +57 +33 +75 +17 +90 +17 +36 +76 +77 +31 +47 +62 +51 +49 +64 +77 +46 +57 +7 +35 +52 +35 +44 +60 +41 +2 +12 +77 +40 +0 +41 +15 +56 +70 +62 +14 +78 +1 +45 +48 +88 +62 +38 +38 +17 +42 +45 +48 +41 +50 +48 +39 +36 +37 +60 +2 +37 +42 +8 +45 +57 +73 +59 +21 +65 +27 +70 +89 +50 +31 +28 +73 +24 +54 +51 +53 +42 +44 +57 +41 +63 +42 +49 +38 +46 +75 +63 +47 +76 +17 +37 +73 +55 +54 +52 +23 +36 +71 +72 +69 +87 +61 +48 +86 +71 +88 +7 +9 +74 +53 +9 +52 +0 +45 +47 +50 +30 +61 +19 +1 +31 +47 +25 +36 +11 +59 +63 +31 +68 +35 +71 +72 +53 +25 +40 +0 +59 +41 +81 +46 +63 +54 +17 +37 +75 +0 +39 +70 +59 +69 +89 +1 +11 +40 +29 +65 +65 +55 +65 +36 +24 +40 +64 +37 +33 +58 +38 +41 diff --git a/test/example.cpp b/test/example.cpp index c8b2b7f65d488b356687ea11d244fe626a92912d..727655d9b0cc2077a8a479cace6fdab67de089be 100644 --- a/test/example.cpp +++ b/test/example.cpp @@ -19,6 +19,7 @@ int main() /*Quaternion to put WASP-11 in the center of the DRF*/ /*The resuling measurement of the */ double quat[4] = {0.8892834993148474, -0.0006038143244162956, 0.2873837014059442, -0.3557880006700909}; + double vel[3] = {0.0, 0.0, 0.0}; /*Initialise FGS simulator by calling constructor*/ FGS fgs(real_path); @@ -70,7 +71,7 @@ int main() update.target_pos_y = 0; /*Set signal for target identification in ADU/s*/ - update.validation_signal = 100000; + update.validation_signal = 80000; /*Unit quaternion of the current SC attitude in reference to J2000*/ update.position_quat[0] = quat[0]; @@ -78,13 +79,17 @@ int main() update.position_quat[2] = quat[2]; update.position_quat[3] = quat[3]; + update.scVelocity[0] = vel[0]; + update.scVelocity[1] = vel[1]; + update.scVelocity[2] = vel[2]; + /*Angular rate in the SC reference frame in arcsec/s*/ update.ang_rate[0] = 0; - update.ang_rate[1] = 0; - update.ang_rate[2] = 0; + update.ang_rate[1] = 1; + update.ang_rate[2] = 1; auto t1 = high_resolution_clock::now(); - for(i = 0; i < 100000; i++) + for(i = 0; i < 1000; i++) { /*time step equivilant to 64Hz sampling*/ /*call update method of FGS class, centroid packet output is @@ -108,6 +113,10 @@ int main() std::cout << "###################################\n"; update.mode = 1; + update.validation_signal = 80000; + + /*Unit quaternion of the current SC attitude in reference to J2000*/ + update.position_quat[0] = quat[0]; for(i = 0; i < 10000; i++) { @@ -127,10 +136,11 @@ int main() std::cout << "###################################\n"; std::cout << "Mode Change Acquisition -> Tracking\n"; std::cout << "Centroids set to invalid\n"; - std::cout << "###################################\n"; + std::cout << "##################################\n"; update.mode = 2; update.set_invalid = 1; + update.validation_signal = 80000; for(i = 0; i < 1000; i++) { @@ -172,9 +182,9 @@ int main() std::cout << "Sim is " << output.time / (ms_double.count()/1000) << " times faster than real time!\n"; std::cout << "Mean Measurement for Tracking: \n x: " << sum_x_tra/ctr_tra << "\n y: " << sum_y_tra/ctr_tra << "\n\n"; - std::cout << "Tracking Reference Values: \n x: ~ 638mas\n y: ~ 1096mas\n\n"; + std::cout << "Tracking Reference Values: \n x: 484.415mas\n y: 805.169mas\n\n"; std::cout << "Mean Measurement for Acquisition: \n x: " << sum_x_acq/ctr_acq << "\n y: " << sum_y_acq/ctr_acq << "\n\n"; - std::cout << "Acquisition Reference Values: \n x: ~ 636mas\n y: ~ 1076mas\n\n"; + std::cout << "Acquisition Reference Values: \n x: 692.876mas\n y: 1093.11mas\n\n"; } diff --git a/test/noStar.txt b/test/noStar.txt new file mode 100644 index 0000000000000000000000000000000000000000..e51b5351ca4afd6038ddc68d625f17e62e334712 --- /dev/null +++ b/test/noStar.txt @@ -0,0 +1,4096 @@ +202 +227 +219 +243 +216 +203 +194 +200 +199 +156 +171 +209 +198 +176 +164 +170 +214 +198 +221 +169 +216 +219 +197 +175 +216 +168 +180 +161 +223 +167 +188 +225 +206 +227 +203 +214 +240 +192 +237 +169 +190 +211 +194 +196 +198 +188 +191 +210 +192 +203 +174 +196 +212 +175 +231 +233 +156 +234 +184 +186 +156 +203 +222 +225 +156 +202 +224 +192 +198 +243 +226 +207 +191 +206 +189 +206 +194 +203 +185 +184 +188 +179 +187 +201 +225 +186 +183 +196 +187 +204 +186 +201 +227 +191 +176 +188 +200 +213 +202 +230 +230 +161 +208 +180 +227 +226 +193 +228 +209 +179 +203 +186 +243 +189 +207 +191 +182 +197 +179 +195 +220 +171 +196 +172 +213 +200 +200 +213 +239 +216 +195 +171 +223 +201 +221 +213 +165 +209 +188 +161 +233 +225 +166 +182 +176 +200 +218 +225 +208 +179 +220 +209 +181 +172 +170 +208 +240 +214 +218 +214 +186 +192 +204 +191 +202 +189 +180 +220 +239 +233 +195 +187 +210 +219 +200 +189 +173 +160 +231 +200 +201 +178 +208 +211 +157 +222 +187 +185 +214 +178 +202 +163 +194 +191 +157 +200 +199 +193 +157 +234 +228 +197 +157 +196 +208 +204 +156 +219 +228 +209 +185 +188 +206 +217 +203 +164 +194 +201 +208 +192 +234 +219 +180 +190 +168 +181 +202 +191 +176 +173 +205 +217 +178 +195 +232 +196 +173 +201 +220 +213 +216 +156 +168 +220 +195 +172 +204 +211 +181 +213 +227 +160 +167 +205 +190 +188 +182 +201 +192 +180 +176 +214 +181 +182 +200 +243 +215 +213 +189 +198 +182 +191 +214 +205 +210 +216 +235 +245 +186 +193 +226 +212 +203 +208 +219 +202 +224 +224 +237 +201 +209 +170 +222 +197 +238 +225 +201 +216 +176 +205 +229 +173 +205 +184 +175 +192 +197 +209 +170 +188 +182 +219 +195 +198 +194 +216 +243 +215 +178 +209 +210 +207 +191 +189 +216 +200 +180 +218 +235 +179 +164 +180 +219 +186 +210 +216 +234 +204 +213 +224 +207 +213 +225 +170 +210 +179 +186 +190 +229 +188 +178 +208 +214 +156 +194 +214 +179 +205 +186 +200 +170 +191 +185 +203 +181 +212 +229 +160 +190 +185 +196 +170 +197 +191 +213 +193 +201 +188 +209 +200 +199 +210 +204 +193 +179 +235 +193 +203 +208 +194 +187 +156 +180 +200 +187 +233 +245 +215 +207 +197 +215 +194 +156 +188 +180 +205 +174 +189 +195 +178 +198 +197 +192 +159 +245 +186 +245 +220 +220 +218 +219 +177 +216 +166 +201 +188 +212 +243 +199 +216 +193 +191 +200 +232 +193 +185 +207 +174 +215 +233 +162 +178 +185 +173 +229 +225 +197 +167 +223 +179 +194 +226 +181 +203 +157 +166 +231 +177 +200 +194 +184 +208 +184 +223 +198 +204 +234 +197 +177 +190 +170 +179 +231 +167 +195 +197 +167 +195 +223 +236 +242 +215 +193 +189 +158 +201 +214 +176 +157 +196 +192 +200 +163 +243 +209 +200 +174 +161 +204 +195 +203 +205 +160 +177 +190 +187 +211 +156 +225 +220 +159 +161 +204 +231 +202 +224 +169 +157 +156 +163 +246 +226 +199 +237 +194 +209 +176 +226 +199 +190 +213 +207 +206 +224 +193 +157 +174 +231 +216 +218 +220 +201 +207 +207 +213 +223 +185 +201 +169 +201 +211 +184 +212 +193 +198 +227 +203 +222 +195 +167 +192 +228 +221 +212 +177 +243 +192 +218 +188 +202 +183 +196 +204 +183 +187 +223 +234 +206 +185 +187 +185 +179 +190 +214 +187 +206 +192 +216 +217 +203 +208 +157 +207 +205 +185 +164 +191 +233 +237 +215 +209 +210 +217 +203 +207 +190 +189 +202 +173 +194 +208 +229 +200 +227 +191 +209 +188 +196 +174 +195 +165 +157 +235 +244 +212 +164 +193 +240 +175 +186 +198 +190 +197 +228 +214 +187 +198 +192 +162 +217 +165 +185 +186 +197 +156 +246 +246 +202 +198 +226 +207 +181 +211 +222 +221 +211 +187 +200 +209 +245 +176 +168 +193 +174 +204 +221 +240 +197 +230 +201 +187 +186 +157 +245 +195 +197 +219 +178 +236 +191 +176 +160 +162 +243 +219 +220 +165 +207 +209 +211 +203 +181 +195 +216 +239 +210 +179 +178 +201 +177 +195 +233 +232 +192 +212 +221 +207 +204 +207 +197 +189 +194 +205 +178 +170 +206 +208 +213 +187 +169 +209 +229 +212 +181 +183 +197 +204 +183 +161 +204 +217 +185 +222 +190 +206 +188 +157 +199 +209 +221 +231 +206 +225 +194 +220 +173 +208 +243 +165 +186 +172 +205 +211 +156 +179 +231 +196 +204 +187 +156 +174 +217 +172 +218 +189 +193 +223 +205 +202 +174 +205 +189 +194 +197 +207 +186 +182 +218 +188 +221 +199 +183 +178 +197 +191 +199 +193 +197 +189 +197 +221 +224 +189 +211 +210 +196 +185 +233 +201 +181 +199 +219 +246 +200 +207 +176 +167 +156 +211 +207 +184 +213 +209 +199 +195 +183 +173 +168 +205 +194 +245 +182 +177 +184 +162 +175 +207 +218 +166 +192 +188 +198 +208 +188 +181 +214 +216 +245 +213 +210 +169 +188 +180 +188 +179 +223 +208 +189 +181 +183 +205 +212 +197 +184 +198 +181 +240 +228 +218 +169 +170 +228 +212 +198 +197 +221 +187 +212 +184 +177 +191 +223 +193 +221 +171 +241 +192 +224 +237 +231 +198 +185 +187 +192 +208 +211 +229 +189 +232 +204 +199 +182 +186 +233 +239 +211 +177 +213 +210 +208 +243 +243 +218 +230 +196 +211 +207 +187 +169 +202 +209 +204 +243 +197 +214 +156 +207 +190 +202 +203 +178 +169 +170 +221 +205 +217 +172 +205 +228 +213 +194 +207 +156 +232 +198 +194 +164 +178 +172 +162 +206 +219 +190 +195 +171 +215 +199 +192 +223 +180 +190 +205 +176 +198 +184 +210 +234 +157 +160 +198 +211 +206 +195 +203 +174 +176 +225 +176 +183 +204 +190 +238 +174 +199 +237 +186 +213 +177 +222 +221 +164 +210 +185 +187 +189 +243 +208 +170 +188 +223 +216 +167 +191 +236 +214 +217 +173 +173 +165 +225 +192 +206 +222 +175 +197 +210 +187 +202 +184 +220 +210 +197 +225 +213 +202 +193 +216 +231 +225 +194 +211 +201 +210 +199 +165 +204 +209 +201 +203 +210 +195 +243 +181 +228 +176 +231 +241 +191 +211 +198 +193 +222 +165 +219 +208 +232 +173 +188 +209 +205 +201 +193 +223 +171 +229 +180 +176 +245 +222 +223 +157 +217 +177 +200 +184 +196 +186 +239 +197 +170 +174 +190 +204 +218 +183 +198 +181 +175 +225 +212 +210 +165 +181 +194 +219 +197 +161 +200 +208 +212 +174 +200 +204 +214 +197 +191 +202 +243 +201 +157 +185 +208 +236 +183 +204 +174 +198 +218 +223 +200 +238 +202 +185 +212 +189 +235 +206 +180 +197 +208 +212 +195 +172 +215 +192 +216 +188 +178 +229 +201 +156 +242 +199 +187 +188 +245 +228 +207 +197 +227 +156 +217 +198 +193 +213 +205 +206 +198 +214 +209 +178 +185 +192 +200 +240 +183 +181 +199 +171 +207 +186 +199 +214 +194 +166 +210 +176 +246 +245 +182 +228 +179 +230 +210 +195 +207 +212 +175 +178 +207 +186 +181 +242 +225 +195 +164 +204 +222 +198 +210 +209 +199 +173 +246 +204 +203 +203 +221 +156 +228 +191 +211 +243 +212 +208 +191 +174 +218 +221 +181 +187 +162 +181 +178 +212 +219 +218 +245 +184 +222 +192 +195 +231 +204 +217 +224 +156 +214 +191 +177 +207 +198 +204 +230 +211 +214 +199 +170 +187 +214 +214 +179 +156 +176 +240 +180 +202 +221 +186 +161 +241 +224 +207 +201 +202 +212 +203 +213 +225 +190 +176 +217 +186 +233 +229 +186 +202 +198 +194 +161 +216 +181 +185 +159 +213 +182 +158 +204 +190 +182 +220 +215 +157 +195 +185 +183 +197 +218 +208 +193 +224 +173 +224 +225 +205 +194 +180 +168 +219 +167 +245 +185 +190 +187 +189 +222 +243 +213 +209 +213 +206 +192 +206 +231 +210 +189 +203 +190 +215 +232 +178 +207 +233 +195 +203 +214 +162 +216 +221 +210 +218 +195 +184 +169 +192 +156 +202 +199 +197 +209 +193 +235 +243 +186 +203 +156 +177 +222 +159 +214 +184 +220 +176 +186 +203 +176 +168 +231 +177 +206 +174 +234 +221 +214 +184 +178 +175 +230 +184 +156 +182 +219 +193 +208 +233 +205 +199 +222 +188 +199 +217 +192 +199 +179 +234 +214 +160 +181 +221 +198 +208 +236 +220 +170 +169 +161 +161 +170 +190 +212 +199 +164 +221 +203 +177 +156 +188 +158 +230 +215 +177 +211 +165 +220 +198 +231 +238 +181 +226 +179 +189 +206 +229 +215 +197 +210 +179 +176 +197 +201 +219 +240 +199 +173 +204 +193 +158 +227 +186 +210 +200 +168 +203 +209 +190 +168 +175 +176 +216 +185 +197 +199 +180 +182 +177 +178 +172 +232 +246 +214 +184 +157 +164 +236 +206 +164 +233 +206 +245 +169 +228 +185 +212 +224 +179 +176 +225 +198 +188 +234 +182 +182 +236 +217 +221 +158 +191 +214 +190 +193 +206 +186 +194 +223 +181 +195 +206 +181 +161 +223 +205 +171 +166 +220 +244 +215 +214 +182 +194 +206 +207 +227 +194 +166 +189 +201 +207 +201 +203 +243 +205 +193 +198 +203 +197 +206 +198 +200 +229 +208 +203 +204 +179 +183 +197 +193 +212 +202 +193 +213 +208 +203 +205 +198 +208 +208 +235 +212 +164 +228 +178 +215 +202 +185 +245 +178 +209 +159 +216 +162 +194 +206 +238 +188 +194 +213 +179 +195 +187 +206 +207 +224 +209 +221 +196 +202 +180 +218 +233 +190 +178 +193 +219 +179 +204 +187 +240 +218 +218 +205 +204 +208 +199 +202 +221 +224 +207 +217 +212 +210 +195 +204 +193 +179 +191 +184 +157 +204 +188 +176 +243 +181 +192 +205 +203 +176 +171 +224 +217 +188 +169 +224 +245 +185 +169 +191 +190 +177 +214 +223 +206 +206 +179 +213 +221 +208 +196 +197 +198 +187 +195 +186 +223 +172 +173 +207 +195 +205 +157 +172 +197 +215 +220 +183 +233 +218 +203 +178 +229 +227 +195 +168 +226 +160 +192 +219 +202 +210 +233 +163 +157 +157 +220 +240 +182 +233 +211 +202 +200 +181 +172 +202 +211 +158 +207 +170 +184 +244 +184 +156 +205 +217 +177 +209 +215 +225 +199 +199 +160 +191 +171 +188 +209 +207 +174 +212 +185 +220 +185 +228 +222 +206 +191 +189 +214 +161 +180 +176 +164 +192 +167 +208 +217 +166 +203 +207 +223 +181 +190 +212 +187 +192 +210 +170 +192 +196 +205 +195 +189 +196 +218 +193 +184 +203 +199 +230 +221 +174 +169 +237 +208 +219 +156 +217 +169 +173 +168 +182 +159 +177 +195 +230 +179 +212 +194 +187 +183 +228 +220 +186 +186 +156 +219 +195 +202 +212 +175 +222 +221 +206 +234 +187 +173 +188 +177 +205 +165 +206 +184 +163 +215 +246 +161 +207 +198 +184 +195 +220 +229 +214 +212 +245 +207 +245 +209 +192 +188 +217 +184 +198 +243 +225 +179 +212 +213 +211 +176 +209 +218 +198 +182 +192 +187 +169 +213 +186 +234 +209 +219 +174 +210 +182 +243 +158 +200 +230 +222 +207 +216 +157 +200 +197 +179 +215 +207 +217 +187 +174 +246 +182 +156 +179 +167 +181 +189 +207 +212 +172 +226 +195 +203 +171 +218 +216 +183 +171 +204 +173 +218 +193 +192 +201 +157 +156 +169 +181 +178 +157 +207 +211 +163 +176 +186 +206 +230 +209 +166 +210 +185 +219 +203 +174 +218 +178 +197 +218 +175 +192 +241 +187 +196 +178 +189 +223 +195 +210 +213 +188 +180 +197 +176 +158 +208 +191 +178 +204 +199 +210 +196 +193 +211 +212 +191 +243 +194 +230 +216 +199 +221 +158 +170 +190 +175 +173 +211 +204 +193 +211 +204 +240 +173 +223 +173 +193 +194 +243 +218 +177 +209 +183 +200 +206 +188 +185 +228 +189 +197 +208 +166 +172 +172 +200 +226 +192 +226 +192 +230 +193 +203 +206 +180 +244 +200 +175 +207 +176 +166 +156 +207 +203 +234 +207 +188 +162 +175 +173 +176 +229 +202 +217 +195 +189 +208 +195 +209 +201 +175 +219 +222 +203 +190 +194 +201 +187 +199 +191 +158 +219 +206 +187 +206 +182 +220 +244 +230 +187 +202 +209 +204 +195 +196 +192 +195 +212 +201 +205 +192 +178 +215 +177 +190 +203 +174 +205 +230 +193 +212 +187 +194 +185 +201 +186 +181 +188 +220 +192 +215 +215 +213 +202 +211 +197 +221 +198 +206 +213 +223 +191 +221 +228 +206 +226 +164 +206 +156 +220 +186 +194 +186 +200 +217 +207 +223 +197 +235 +185 +188 +206 +191 +182 +162 +193 +191 +234 +216 +219 +160 +214 +216 +158 +180 +188 +160 +233 +207 +201 +206 +211 +194 +197 +179 +211 +207 +218 +162 +216 +189 +225 +176 +218 +156 +206 +188 +222 +166 +185 +169 +239 +245 +212 +219 +232 +200 +221 +186 +194 +193 +158 +186 +218 +200 +212 +232 +162 +157 +200 +181 +184 +191 +214 +204 +189 +228 +207 +192 +177 +240 +179 +214 +235 +171 +162 +225 +205 +194 +237 +210 +210 +222 +191 +179 +220 +194 +188 +202 +214 +186 +185 +200 +185 +194 +162 +223 +163 +156 +234 +179 +178 +157 +220 +223 +219 +212 +243 +171 +211 +198 +210 +193 +173 +172 +211 +188 +180 +243 +180 +199 +240 +244 +232 +212 +184 +243 +214 +172 +201 +222 +179 +189 +192 +223 +171 +165 +198 +186 +218 +174 +234 +210 +194 +190 +209 +178 +229 +213 +228 +199 +212 +194 +203 +233 +211 +179 +188 +206 +214 +177 +220 +162 +172 +174 +184 +207 +207 +215 +192 +172 +187 +197 +216 +214 +222 +211 +215 +193 +171 +157 +222 +199 +218 +185 +189 +210 +184 +205 +203 +194 +193 +198 +224 +211 +207 +189 +187 +225 +188 +216 +210 +218 +192 +179 +201 +243 +222 +230 +229 +214 +194 +214 +185 +190 +232 +197 +211 +203 +180 +218 +202 +202 +234 +156 +246 +169 +190 +203 +188 +243 +196 +183 +226 +163 +161 +200 +204 +196 +195 +194 +180 +183 +179 +206 +200 +200 +244 +169 +222 +190 +193 +175 +157 +190 +206 +241 +178 +177 +201 +201 +223 +200 +174 +215 +200 +186 +179 +196 +189 +178 +183 +213 +230 +180 +226 +189 +163 +212 +208 +210 +182 +198 +211 +217 +212 +183 +174 +220 +181 +210 +182 +206 +204 +243 +174 +207 +208 +159 +169 +178 +208 +221 +156 +205 +213 +210 +222 +175 +188 +228 +184 +183 +196 +222 +203 +193 +181 +229 +217 +168 +187 +201 +223 +197 +219 +172 +198 +232 +229 +205 +171 +205 +180 +186 +199 +173 +167 +197 +179 +193 +198 +233 +184 +195 +165 +192 +205 +199 +188 +222 +166 +204 +173 +183 +219 +207 +212 +170 +211 +185 +210 +210 +186 +166 +192 +224 +194 +181 +177 +180 +228 +208 +166 +216 +157 +164 +243 +209 +207 +225 +175 +175 +213 +221 +189 +185 +204 +214 +210 +193 +185 +201 +178 +168 +231 +211 +173 +188 +178 +206 +185 +203 +217 +190 +225 +185 +185 +232 +219 +214 +209 +183 +211 +221 +201 +179 +212 +208 +162 +207 +200 +200 +224 +220 +159 +244 +225 +229 +197 +167 +156 +237 +237 +156 +200 +193 +214 +231 +192 +156 +244 +225 +190 +200 +183 +182 +163 +168 +214 +174 +210 +227 +189 +191 +195 +193 +218 +160 +220 +206 +217 +205 +189 +246 +206 +170 +194 +213 +156 +211 +223 +201 +227 +210 +223 +196 +227 +172 +215 +213 +211 +191 +214 +207 +156 +176 +202 +201 +171 +218 +177 +193 +175 +165 +188 +211 +208 +172 +227 +156 +156 +196 +213 +174 +197 +217 +180 +196 +216 +156 +226 +224 +202 +234 +175 +210 +218 +209 +224 +237 +225 +197 +195 +159 +161 +213 +173 +172 +171 +190 +199 +183 +176 +224 +196 +202 +193 +222 +206 +195 +200 +193 +156 +229 +219 +228 +177 +208 +217 +170 +162 +177 +224 +188 +205 +222 +243 +195 +180 +232 +205 +178 +183 +188 +194 +195 +197 +227 +236 +219 +202 +185 +196 +202 +174 +191 +245 +178 +223 +157 +189 +195 +161 +181 +184 +213 +209 +184 +188 +173 +168 +206 +170 +239 +170 +198 +195 +198 +197 +185 +227 +228 +210 +243 +160 +198 +157 +180 +219 +173 +211 +229 +226 +164 +197 +197 +202 +205 +212 +210 +207 +183 +170 +237 +156 +222 +232 +180 +208 +230 +220 +200 +217 +205 +193 +209 +172 +211 +188 +209 +189 +230 +192 +202 +196 +223 +181 +184 +191 +184 +156 +244 +227 +204 +185 +219 +227 +203 +175 +199 +200 +210 +181 +193 +177 +210 +168 +213 +221 +196 +203 +192 +233 +190 +186 +171 +187 +210 +192 +182 +222 +199 +161 +203 +224 +198 +183 +199 +175 +206 +226 +194 +193 +203 +226 +201 +184 +226 +197 +238 +200 +202 +183 +218 +157 +230 +217 +198 +230 +186 +212 +204 +222 +229 +198 +215 +206 +194 +215 +156 +209 +189 +171 +220 +231 +182 +207 +157 +198 +223 +215 +194 +243 +243 +171 +170 +181 +199 +197 +188 +231 +177 +209 +218 +210 +205 +198 +236 +228 +223 +196 +179 +197 +243 +187 +194 +212 +189 +191 +199 +215 +196 +201 +231 +170 +204 +187 +157 +225 +205 +197 +206 +165 +202 +217 +200 +201 +188 +227 +193 +196 +210 +243 +175 +181 +190 +225 +195 +222 +214 +193 +158 +233 +215 +224 +213 +221 +217 +211 +156 +234 +190 +232 +186 +194 +217 +221 +212 +203 +185 +198 +190 +245 +229 +211 +190 +192 +225 +192 +174 +159 +244 +182 +185 +218 +170 +189 +191 +193 +197 +194 +224 +213 +197 +229 +233 +215 +211 +214 +202 +171 +197 +202 +182 +176 +199 +179 +156 +207 +194 +198 +210 +161 +156 +197 +229 +227 +181 +175 +233 +156 +220 +197 +200 +191 +157 +205 +182 +245 +172 +203 +187 +181 +178 +209 +243 +243 +216 +206 +157 +206 +193 +193 +185 +201 +213 +173 +233 +172 +208 +205 +194 +209 +226 +179 +191 +165 +202 +213 +209 +177 +156 +207 +213 +205 +177 +216 +223 +175 +186 +200 +231 +187 +172 +177 +220 +175 +209 +206 +203 +172 +177 +212 +201 +211 +233 +214 +203 +176 +191 +236 +244 +228 +209 +181 +232 +197 +199 +184 +170 +215 +215 +234 +197 +184 +205 +230 +225 +233 +176 +156 +225 +193 +158 +205 +218 +209 +214 +201 +187 +221 +207 +198 +180 +205 +212 +183 +225 +215 +172 +198 +180 +183 +233 +222 +216 +223 +219 +210 +210 +222 +185 +202 +209 +220 +196 +200 +212 +157 +206 +172 +171 +236 +177 +216 +210 +212 +206 +205 +223 +219 +187 +234 +213 +215 +178 +203 +229 +218 +237 +181 +239 +194 +222 +198 +206 +174 +200 +243 +197 +191 +199 +204 +239 +178 +203 +195 +194 +203 +179 +232 +230 +219 +203 +204 +224 +205 +191 +228 +198 +181 +216 +197 +214 +203 +176 +205 +245 +198 +229 +181 +158 +199 +243 +205 +185 +186 +228 +195 +163 +184 +210 +172 +177 +211 +202 +223 +172 +171 +166 +202 +192 +197 +191 +172 +184 +199 +157 +178 +200 +192 +181 +209 +218 +203 +215 +158 +175 +241 +210 +209 +226 +201 +164 +227 +244 +205 +174 +240 +192 +188 +237 +220 +213 +174 +175 +178 +213 +234 +187 +220 +192 +206 +200 +193 +244 +195 +182 +221 +188 +173 +174 +207 +209 +166 +212 +212 +215 +236 +188 +201 +219 +190 +176 +213 +242 +182 +210 +243 +196 +161 +197 +209 +245 +183 +196 +219 +235 +216 +177 +211 +180 +202 +216 +198 +156 +175 +200 +243 +177 +182 +211 +172 +164 +187 +213 +217 +211 +231 +173 +189 +220 +206 +194 +178 +230 +171 +191 +230 +186 +179 +182 +223 +189 +209 +159 +198 +203 +206 +235 +205 +170 +194 +213 +219 +191 +197 +221 +177 +182 +201 +156 +228 +230 +244 +191 +178 +181 +158 +159 +210 +218 +164 +187 +244 +199 +186 +191 +182 +172 +228 +218 +204 +219 +208 +226 +182 +211 +202 +201 +207 +209 +195 +189 +183 +220 +207 +222 +190 +180 +225 +201 +237 +184 +216 +198 +192 +173 +176 +204 +164 +202 +169 +193 +202 +167 +175 +207 +184 +198 +178 +190 +169 +178 +224 +183 +195 +221 +169 +206 +196 +190 +170 +204 +196 +187 +208 +195 +189 +219 +208 +177 +222 +207 +218 +229 +192 +215 +211 +162 +180 +198 +211 +197 +203 +181 +173 +241 +246 +215 +196 +196 +168 +216 +185 +202 +177 +193 +237 +202 +176 +211 +171 +186 +181 +156 +194 +214 +158 +225 +196 +178 +179 +172 +190 +191 +215 +203 +206 +218 +182 +194 +168 +173 +204 +212 +217 +217 +181 +221 +184 +191 +191 +178 +169 +208 +183 +217 +172 +188 +156 +214 +237 +180 +197 +170 +194 +208 +188 +173 +171 +216 +207 +178 +190 +178 +193 +212 +233 +197 +174 +185 +217 +211 +212 +238 +212 +197 +186 +202 +176 +186 +203 +186 +232 +187 +171 +240 +177 +239 +189 +218 +195 +195 +159 +192 +182 +223 +205 +170 +199 +194 +205 +200 +212 +169 +156 +203 +199 +184 +199 +156 +208 +198 +242 +225 +213 +181 +217 +218 +199 +213 +240 +244 +214 +209 +210 +212 +234 +159 +167 +219 +189 +204 +234 +174 +240 +209 +234 +184 +235 +191 +215 +158 +230 +179 +185 +204 +197 +243 +192 +191 +192 +204 +205 +196 +178 +191 +201 +195 +172 +181 +219 +215 +183 +156 +196 +193 +171 +204 +205 +205 +234 +218 +181 +177 +221 +198 +224 +206 +199 +178 +187 +199 +217 +192 +194 +180 +205 +198 +188 +202 +211 +207 +162 +193 +211 +225 +204 +200 +214 +209 +245 +241 +193 +207 +174 +172 +201 +197 +205 +179 +184 +219 +181 +202 +216 +198 +186 +196 +188 +227 +197 +226 +199 +198 +194 +215 +244 +185 +161 +203 +212 +235 +235 +160 +156 +181 +213 +205 +187 +190 +234 +222 +201 +193 +206 +193 +181 +212 +224 +176 +211 +209 +196 +219 +172 +172 +213 +191 +199 +196 +217 +238 +165 +243 +175 +191 +212 +215 +191 +190 +187 +178 +236 +206 +213 +170 +226 +187 +195 +157 +211 +202 +214 +188 +203 +208 +185 +191 +210 +198 +178 +245 +184 +220 +200 +213 +205 +156 +206 +226 +230 +234 +157 +180 +173 +196 +208 +196 +197 +208 +200 +209 +204 +192 +180 +197 +190 +190 +209 +225 +212 +182 +198 +157 +211 +204 +184 +211 +185 +190 +172 +188 +196 +198 +178 +171 +161 +241 +219 +214 +236 +199 +156 +180 +210 +186 +174 +194 +173 +196 +196 +197 +203 +170 +240 +209 +208 +221 +228 +186 +213 +188 +174 +225 +220 +198 +176 +227 +232 +226 +211 +201 +209 +170 +230 +181 +200 +177 +166 +204 +190 +167 +172 +179 +209 +224 +243 +231 +166 +189 +237 +206 +181 +204 +204 +205 +190 +177 +185 +193 +165 +208 +167 +238 +182 +218 +200 +222 +187 +210 +243 +211 +193 +182 +211 +217 +203 +201 +171 +181 +202 +216 +178 +182 +198 +185 +225 +181 +191 +187 +192 +190 +197 +170 +198 +203 +234 +193 +189 +207 +192 +162 +186 +192 +185 +182 +192 +202 +191 +209 +189 +227 +209 +232 +215 +194 +206 +207 +236 +221 +214 +196 +228 +191 +208 +192 +179 +193 +188 +196 +231 +213 +226 +207 +225 +243 +193 +219 +200 +201 +213 +223 +212 +190 +206 +211 +215 +204 +244 +215 +228 +199 +200 +180 +190 +203 +216 +179 +171 +195 +183 +171 +192 +188 +217 +238 +183 +182 +178 +231 +184 +215 +175 +213 +184 +243 +180 +198 +174 +218 +192 +157 +212 +203 +218 +206 +231 +205 +204 +208 +213 +216 +224 +198 +201 +224 +238 +200 +187 +223 +200 +205 +201 +202 +235 +200 +203 +196 +205 +156 +222 +225 +191 +195 +207 +199 +191 +176 +169 +213 +245 +201 +222 +200 +189 +177 +210 +192 +210 +217 +201 +158 +198 +210 +195 +186 +230 +215 +175 +190 +194 +207 +226 +226 +156 +202 +194 +200 +215 +212 +203 +182 +184 +192 +201 +218 +222 +213 +193 +239 +211 +218 +214 +197 +182 +179 +185 +192 +196 +164 +157 +243 +183 +180 +223 +218 +221 +198 +235 +169 +170 +191 +198 +178 +235 +183 +221 +172 +243 +214 +164 +168 +223 +212 +180 +157 +217 +182 +239 +234 +157 +180 +227 +188 +174 +217 +157 +166 +172 +219 +198 +192 +213 +198 +201 +179 +178 +219 +199 +190 +180 +206 +222 +220 +200 +163 +169 +163 +166 +194 +197 +206 +208 +224 +168 +192 +184 +170 +189 +156 +208 +178 +181 +211 +185 +193 +225 +163 +200 +207 +200 +208 +183 +199 +157 +225 +192 +237 +203 +168 +217 +165 +206 +195 +205 +203 +211 +200 +165 +199 +184 +209 +214 +186 +166 +211 +218 diff --git a/test/trackingTest.txt b/test/trackingTest.txt new file mode 100644 index 0000000000000000000000000000000000000000..87c887fa81f008dba07df7db7801ab284f12e518 --- /dev/null +++ b/test/trackingTest.txt @@ -0,0 +1,4096 @@ +34 +23 +49 +25 +49 +64 +34 +78 +25 +31 +48 +65 +38 +66 +68 +49 +57 +84 +34 +66 +43 +27 +70 +41 +60 +53 +63 +47 +66 +44 +32 +55 +50 +38 +36 +12 +51 +58 +29 +77 +36 +66 +68 +31 +89 +35 +32 +29 +46 +56 +83 +88 +48 +21 +4 +46 +13 +52 +48 +44 +37 +32 +45 +52 +58 +39 +29 +44 +27 +18 +66 +67 +13 +57 +22 +65 +57 +73 +38 +62 +33 +37 +38 +49 +81 +55 +24 +27 +26 +35 +34 +62 +48 +34 +50 +66 +53 +33 +68 +41 +22 +60 +48 +54 +16 +83 +41 +41 +52 +65 +23 +18 +45 +58 +30 +58 +56 +58 +74 +43 +50 +87 +7 +52 +41 +59 +76 +84 +34 +19 +61 +56 +11 +85 +71 +3 +36 +19 +34 +87 +48 +32 +1 +46 +57 +6 +44 +14 +55 +31 +77 +64 +38 +41 +62 +42 +36 +43 +39 +53 +77 +89 +12 +38 +56 +70 +31 +63 +26 +25 +63 +68 +35 +49 +32 +57 +0 +14 +54 +62 +90 +48 +20 +29 +47 +75 +63 +35 +41 +57 +17 +38 +79 +65 +62 +55 +27 +62 +13 +61 +51 +11 +13 +41 +39 +26 +24 +38 +53 +26 +45 +89 +77 +57 +59 +70 +29 +54 +24 +24 +29 +31 +28 +26 +0 +65 +88 +39 +40 +9 +48 +39 +25 +21 +58 +11 +25 +42 +82 +35 +28 +56 +39 +32 +54 +51 +64 +12 +38 +38 +30 +53 +64 +60 +54 +52 +9 +24 +41 +58 +71 +68 +34 +20 +32 +13 +26 +51 +32 +38 +13 +36 +37 +50 +40 +56 +45 +29 +29 +24 +19 +30 +27 +22 +29 +82 +43 +49 +22 +88 +10 +60 +14 +63 +41 +35 +0 +18 +0 +26 +4 +59 +74 +60 +25 +0 +9 +32 +17 +37 +41 +27 +45 +8 +31 +43 +87 +30 +76 +77 +48 +74 +69 +48 +39 +21 +67 +32 +64 +31 +51 +52 +34 +11 +42 +48 +55 +17 +26 +51 +13 +28 +42 +77 +49 +48 +45 +35 +55 +36 +30 +43 +9 +64 +78 +0 +2 +28 +69 +71 +38 +42 +62 +32 +62 +45 +21 +30 +40 +46 +18 +49 +74 +53 +23 +67 +51 +23 +47 +33 +0 +46 +60 +57 +56 +26 +60 +50 +6 +45 +77 +56 +60 +71 +29 +39 +25 +44 +57 +40 +45 +48 +22 +37 +44 +46 +46 +49 +66 +42 +31 +61 +42 +13 +25 +37 +9 +4 +56 +32 +39 +52 +71 +42 +51 +35 +21 +87 +49 +49 +39 +48 +89 +26 +85 +88 +24 +0 +34 +40 +64 +28 +84 +1 +61 +89 +85 +32 +54 +37 +50 +36 +44 +21 +61 +87 +20 +55 +49 +56 +87 +33 +22 +16 +34 +56 +56 +78 +35 +43 +60 +48 +45 +28 +73 +68 +57 +68 +26 +46 +36 +26 +70 +48 +42 +82 +53 +33 +51 +80 +59 +27 +20 +62 +10 +31 +38 +24 +30 +83 +48 +76 +31 +1 +18 +55 +55 +73 +7 +34 +38 +38 +44 +58 +37 +25 +9 +67 +52 +17 +68 +14 +61 +87 +81 +19 +53 +66 +19 +50 +58 +51 +37 +18 +70 +55 +34 +57 +38 +24 +47 +63 +79 +29 +30 +41 +52 +26 +61 +49 +54 +22 +75 +23 +88 +41 +16 +1 +72 +71 +26 +55 +3 +1 +16 +32 +38 +69 +34 +59 +53 +30 +37 +46 +16 +79 +76 +61 +41 +39 +25 +60 +18 +46 +46 +51 +24 +26 +61 +30 +17 +14 +38 +60 +58 +48 +50 +47 +7 +12 +53 +56 +50 +59 +48 +5 +17 +34 +43 +31 +53 +41 +28 +31 +13 +39 +41 +37 +53 +64 +59 +33 +13 +55 +59 +41 +16 +46 +32 +43 +50 +26 +56 +87 +71 +53 +36 +30 +26 +9 +1 +80 +60 +23 +30 +68 +31 +39 +59 +68 +54 +25 +38 +48 +39 +79 +44 +48 +51 +41 +32 +1 +33 +53 +19 +14 +49 +62 +74 +35 +64 +35 +23 +41 +62 +40 +49 +22 +77 +40 +18 +28 +66 +51 +58 +33 +27 +74 +50 +32 +38 +52 +36 +71 +48 +87 +39 +22 +48 +38 +51 +65 +24 +43 +54 +57 +70 +40 +64 +38 +12 +49 +27 +34 +50 +27 +63 +27 +13 +54 +41 +40 +61 +85 +50 +58 +24 +80 +40 +23 +14 +55 +73 +77 +48 +40 +48 +54 +36 +44 +33 +60 +61 +60 +88 +28 +42 +34 +41 +82 +26 +54 +74 +32 +87 +0 +33 +51 +28 +36 +79 +74 +66 +49 +41 +44 +80 +24 +47 +55 +31 +49 +23 +31 +48 +35 +49 +29 +29 +48 +41 +54 +42 +16 +18 +80 +75 +44 +80 +48 +59 +61 +0 +74 +64 +49 +26 +23 +87 +34 +46 +26 +47 +46 +56 +54 +47 +60 +79 +47 +13 +22 +39 +41 +57 +29 +61 +50 +26 +1 +40 +28 +31 +5 +9 +72 +1 +3 +38 +57 +0 +19 +6 +32 +31 +60 +28 +51 +50 +34 +39 +74 +76 +23 +25 +38 +23 +43 +39 +53 +45 +68 +21 +27 +8 +70 +47 +34 +57 +70 +33 +49 +33 +22 +23 +31 +71 +39 +46 +42 +82 +7 +32 +63 +54 +69 +22 +56 +53 +18 +62 +63 +18 +53 +59 +37 +31 +3 +82 +87 +28 +69 +39 +33 +48 +28 +46 +36 +58 +10 +17 +49 +75 +37 +23 +89 +62 +67 +67 +28 +57 +28 +47 +23 +48 +67 +87 +77 +40 +51 +65 +4 +45 +37 +6 +54 +26 +20 +77 +69 +54 +80 +68 +11 +19 +45 +85 +34 +43 +32 +69 +64 +0 +45 +61 +0 +40 +27 +56 +23 +58 +45 +45 +47 +6 +41 +0 +55 +5 +70 +64 +52 +71 +59 +68 +38 +0 +31 +13 +25 +70 +10 +22 +21 +26 +79 +66 +47 +48 +11 +63 +33 +25 +31 +48 +0 +80 +75 +60 +79 +58 +25 +72 +21 +44 +36 +58 +45 +72 +64 +68 +59 +58 +78 +17 +50 +34 +22 +51 +36 +52 +48 +77 +39 +65 +72 +62 +57 +27 +33 +56 +41 +0 +49 +79 +89 +33 +39 +44 +64 +35 +6 +42 +54 +21 +90 +54 +58 +54 +51 +65 +34 +25 +49 +34 +63 +11 +27 +78 +36 +26 +75 +61 +43 +45 +66 +19 +54 +69 +25 +22 +21 +29 +61 +52 +60 +17 +29 +4 +6 +0 +45 +46 +28 +34 +67 +0 +74 +34 +30 +15 +13 +0 +2 +39 +45 +20 +7 +0 +38 +43 +70 +50 +58 +41 +25 +48 +47 +60 +3 +28 +50 +29 +19 +49 +58 +20 +40 +27 +52 +51 +47 +38 +89 +17 +44 +41 +21 +73 +77 +11 +0 +63 +66 +10 +41 +40 +52 +0 +35 +59 +48 +76 +53 +72 +17 +14 +33 +51 +63 +45 +32 +60 +51 +42 +35 +24 +52 +40 +57 +68 +39 +57 +32 +47 +23 +55 +19 +46 +42 +52 +38 +58 +59 +29 +48 +85 +26 +51 +58 +70 +59 +37 +67 +23 +33 +68 +49 +34 +52 +5 +0 +28 +40 +57 +48 +24 +57 +49 +31 +65 +89 +36 +48 +42 +87 +75 +51 +47 +61 +56 +30 +55 +37 +37 +66 +27 +31 +31 +30 +20 +89 +44 +65 +49 +17 +59 +81 +63 +27 +66 +40 +64 +24 +63 +13 +23 +65 +3 +44 +25 +48 +65 +33 +34 +32 +53 +58 +54 +65 +47 +68 +38 +45 +34 +38 +52 +32 +23 +46 +75 +46 +52 +47 +80 +64 +64 +75 +60 +72 +11 +82 +30 +48 +33 +56 +35 +43 +45 +23 +56 +45 +35 +28 +58 +25 +63 +32 +44 +44 +57 +33 +50 +56 +13 +25 +35 +62 +42 +87 +33 +33 +60 +35 +28 +87 +32 +35 +59 +24 +57 +43 +57 +36 +62 +86 +88 +46 +43 +56 +36 +23 +34 +59 +72 +58 +30 +67 +36 +10 +47 +57 +42 +74 +24 +59 +7 +57 +68 +33 +51 +54 +4 +52 +25 +65 +2 +57 +20 +50 +40 +17 +58 +64 +46 +44 +40 +85 +28 +35 +45 +24 +52 +40 +49 +64 +46 +70 +39 +51 +57 +20 +40 +45 +32 +65 +64 +58 +65 +28 +53 +66 +85 +66 +66 +9 +13 +83 +44 +51 +56 +55 +86 +58 +89 +7 +19 +23 +46 +45 +34 +46 +75 +65 +35 +1 +19 +47 +30 +42 +36 +45 +55 +32 +53 +71 +77 +32 +57 +37 +39 +31 +27 +51 +9 +26 +77 +22 +54 +37 +28 +82 +69 +30 +47 +29 +14 +72 +28 +68 +39 +51 +21 +72 +36 +70 +42 +40 +76 +81 +30 +33 +47 +56 +54 +36 +57 +49 +51 +64 +32 +58 +18 +52 +34 +56 +43 +0 +68 +65 +40 +20 +26 +46 +20 +21 +6 +89 +46 +57 +34 +52 +19 +62 +15 +26 +79 +50 +10 +5 +20 +42 +40 +56 +75 +75 +53 +12 +87 +85 +69 +89 +35 +40 +61 +39 +23 +33 +13 +50 +34 +55 +50 +17 +37 +27 +41 +23 +32 +43 +33 +71 +40 +29 +33 +21 +33 +39 +46 +21 +29 +87 +61 +10 +45 +26 +31 +28 +47 +75 +42 +46 +38 +46 +50 +28 +31 +44 +66 +40 +65 +49 +28 +23 +75 +38 +87 +22 +38 +87 +28 +67 +87 +40 +13 +42 +22 +80 +68 +9 +0 +16 +66 +38 +45 +1 +43 +19 +76 +67 +92 +67 +39 +78 +90 +42 +46 +23 +33 +84 +49 +39 +27 +39 +31 +53 +32 +63 +83 +50 +77 +59 +22 +16 +14 +7 +25 +52 +21 +33 +37 +52 +60 +7 +77 +87 +43 +48 +31 +47 +45 +49 +49 +70 +42 +58 +41 +26 +10 +64 +48 +29 +47 +25 +61 +87 +46 +42 +16 +20 +67 +54 +79 +60 +41 +39 +29 +6 +14 +29 +44 +51 +59 +18 +56 +48 +58 +25 +22 +60 +33 +24 +53 +27 +89 +44 +54 +76 +21 +41 +48 +73 +16 +55 +59 +16 +47 +56 +20 +63 +45 +52 +47 +34 +34 +50 +34 +44 +61 +68 +46 +67 +72 +0 +42 +16 +41 +57 +26 +14 +28 +56 +84 +40 +38 +67 +74 +31 +33 +59 +76 +78 +71 +47 +72 +29 +45 +34 +45 +50 +45 +50 +42 +23 +68 +66 +54 +71 +31 +27 +19 +41 +14 +37 +21 +55 +39 +63 +44 +44 +40 +73 +80 +29 +86 +39 +27 +61 +37 +0 +33 +57 +37 +59 +59 +63 +50 +11 +57 +77 +78 +43 +65 +40 +62 +56 +61 +65 +91 +64 +83 +28 +54 +53 +51 +28 +30 +54 +53 +66 +64 +27 +79 +63 +21 +57 +45 +72 +52 +44 +32 +50 +50 +42 +30 +30 +55 +16 +57 +68 +18 +40 +29 +87 +7 +34 +50 +66 +14 +65 +46 +73 +47 +17 +40 +38 +23 +57 +66 +54 +28 +64 +87 +48 +44 +55 +38 +49 +22 +40 +42 +69 +113 +105 +154 +63 +21 +27 +53 +39 +73 +49 +41 +62 +75 +51 +33 +29 +64 +57 +20 +43 +20 +57 +76 +67 +75 +77 +38 +68 +44 +78 +27 +51 +11 +42 +31 +13 +42 +59 +40 +7 +52 +70 +41 +59 +38 +36 +24 +39 +77 +61 +54 +51 +71 +87 +89 +30 +43 +1 +71 +65 +45 +46 +90 +118 +312 +279 +344 +154 +60 +39 +20 +65 +52 +59 +30 +25 +81 +0 +45 +35 +31 +71 +39 +38 +19 +35 +27 +28 +54 +31 +71 +54 +10 +90 +69 +64 +72 +90 +37 +55 +25 +52 +75 +18 +18 +43 +57 +41 +60 +72 +10 +85 +56 +32 +62 +5 +75 +45 +32 +50 +44 +55 +30 +58 +75 +89 +183 +390 +655 +539 +514 +476 +264 +99 +43 +55 +17 +68 +63 +61 +66 +26 +36 +71 +77 +36 +54 +84 +19 +55 +31 +87 +23 +73 +19 +45 +38 +33 +42 +38 +49 +41 +41 +31 +14 +54 +0 +69 +36 +65 +18 +26 +5 +45 +36 +59 +62 +54 +49 +50 +61 +90 +19 +29 +23 +49 +25 +70 +119 +173 +300 +599 +948 +827 +763 +855 +682 +458 +215 +148 +92 +80 +58 +40 +62 +38 +46 +42 +50 +56 +28 +32 +53 +63 +58 +53 +3 +35 +38 +28 +49 +50 +67 +20 +22 +26 +46 +32 +25 +45 +28 +40 +21 +89 +31 +29 +23 +43 +36 +45 +60 +54 +25 +45 +26 +67 +58 +66 +51 +56 +58 +124 +102 +119 +200 +582 +1117 +816 +696 +832 +816 +824 +498 +288 +135 +122 +106 +58 +60 +75 +39 +25 +54 +62 +31 +39 +5 +65 +71 +42 +50 +28 +31 +30 +70 +45 +0 +41 +35 +75 +41 +52 +42 +6 +44 +54 +51 +20 +67 +18 +27 +48 +34 +92 +46 +3 +90 +53 +41 +46 +98 +58 +90 +18 +72 +89 +65 +98 +157 +322 +790 +958 +728 +689 +366 +214 +108 +97 +42 +74 +55 +60 +82 +18 +55 +65 +61 +23 +20 +39 +25 +71 +56 +40 +76 +44 +29 +24 +47 +24 +87 +55 +13 +8 +55 +82 +51 +0 +37 +37 +41 +37 +77 +57 +17 +28 +39 +38 +35 +15 +55 +61 +74 +30 +49 +39 +62 +70 +76 +21 +51 +40 +93 +153 +267 +663 +644 +236 +68 +62 +47 +61 +15 +92 +39 +48 +87 +46 +44 +57 +54 +83 +26 +49 +13 +49 +44 +49 +31 +26 +37 +0 +70 +20 +26 +34 +66 +19 +79 +47 +87 +26 +65 +65 +57 +51 +43 +65 +9 +12 +46 +55 +1 +35 +9 +60 +67 +51 +28 +30 +39 +12 +62 +43 +6 +46 +47 +38 +98 +174 +402 +194 +26 +61 +29 +54 +53 +37 +63 +61 +29 +56 +38 +44 +43 +40 +27 +20 +72 +74 +53 +66 +49 +36 +1 +50 +41 +37 +50 +57 +59 +12 +66 +42 +47 +14 +37 +1 +31 +19 +53 +38 +87 +45 +58 +54 +74 +63 +69 +27 +10 +65 +36 +81 +14 +85 +49 +70 +30 +90 +42 +29 +61 +79 +166 +142 +42 +60 +55 +20 +71 +84 +55 +18 +11 +49 +53 +52 +35 +27 +35 +24 +38 +39 +52 +54 +33 +85 +47 +71 +42 +34 +22 +46 +47 +17 +31 +38 +29 +67 +49 +85 +50 +40 +27 +46 +36 +5 +50 +0 +24 +64 +60 +23 +52 +38 +1 +36 +26 +45 +6 +19 +36 +34 +85 +4 +42 +11 +76 +94 +131 +33 +81 +65 +71 +47 +60 +18 +37 +62 +55 +89 +29 +12 +32 +27 +57 +42 +47 +32 +10 +44 +20 +66 +46 +49 +67 +36 +28 +31 +36 +89 +20 +50 +41 +66 +65 +67 +20 +40 +57 +17 +38 +61 +55 +27 +13 +25 +14 +64 +90 +40 +74 +27 +78 +60 +27 +40 +85 +57 +25 +46 +78 +27 +72 +54 +66 +48 +46 +50 +44 +57 +39 +6 +3 +49 +1 +39 +34 +47 +0 +41 +29 +44 +47 +53 +24 +36 +87 +65 +11 +45 +31 +44 +50 +73 +34 +15 +27 +8 +45 +24 +82 +26 +20 +19 +39 +48 +38 +63 +63 +30 +42 +84 +49 +73 +29 +0 +49 +29 +37 +19 +49 +34 +50 +21 +47 +37 +29 +45 +38 +65 +75 +26 +67 +46 +81 +80 +51 +46 +51 +78 +66 +27 +26 +29 +73 +29 +44 +53 +69 +68 +24 +32 +75 +72 +35 +64 +43 +41 +18 +21 +30 +40 +6 +66 +53 +21 +48 +30 +28 +88 +81 +46 +37 +69 +54 +40 +73 +30 +25 +80 +22 +66 +40 +54 +39 +63 +83 +29 +73 +22 +68 +34 +73 +50 +74 +65 +57 +38 +11 +44 +21 +54 +64 +57 +64 +37 +33 +59 +72 +60 +15 +69 +63 +20 +53 +46 +41 +64 +16 +69 +55 +79 +69 +25 +30 +23 +30 +65 +78 +62 +22 +14 +50 +71 +76 +45 +19 +66 +75 +53 +45 +39 +37 +89 +26 +9 +63 +24 +56 +38 +43 +49 +60 +89 +58 +52 +38 +66 +13 +43 +32 +2 +25 +1 +52 +51 +73 +25 +4 +35 +84 +30 +11 +27 +7 +64 +2 +81 +30 +19 +62 +45 +83 +55 +17 +20 +32 +40 +41 +60 +46 +63 +31 +17 +55 +4 +47 +27 +57 +53 +53 +74 +34 +12 +34 +46 +4 +5 +45 +44 +84 +86 +51 +30 +45 +68 +47 +63 +63 +60 +36 +21 +84 +16 +49 +32 +61 +26 +36 +87 +40 +7 +48 +57 +31 +51 +79 +44 +59 +40 +49 +66 +36 +59 +64 +33 +37 +28 +34 +63 +55 +38 +61 +36 +31 +58 +57 +58 +49 +65 +28 +37 +30 +87 +64 +66 +23 +80 +49 +41 +18 +73 +18 +48 +33 +52 +21 +13 +39 +42 +61 +55 +3 +42 +34 +65 +65 +91 +43 +56 +49 +31 +32 +46 +34 +47 +34 +29 +68 +55 +73 +61 +21 +53 +27 +28 +81 +78 +38 +41 +36 +53 +54 +22 +72 +76 +24 +48 +35 +19 +84 +0 +57 +28 +61 +69 +62 +32 +23 +67 +52 +8 +9 +66 +27 +41 +48 +9 +48 +56 +38 +49 +51 +71 +45 +28 +59 +31 +54 +44 +39 +32 +44 +48 +51 +18 +46 +73 +46 +19 +81 +27 +34 +21 +49 +70 +0 +41 +42 +60 +20 +25 +32 +63 +66 +44 +48 +60 +47 +87 +23 +73 +45 +53 +67 +77 +80 +51 +22 +33 +28 +0 +44 +77 +42 +59 +5 +14 +57 +38 +52 +67 +33 +34 +37 +14 +63 +33 +61 +61 +53 +70 +25 +64 +78 +31 +72 +43 +83 +65 +7 +1 +56 +17 +68 +43 +67 +8 +35 +20 +36 +47 +82 +39 +30 +59 +31 +49 +82 +26 +47 +30 +7 +42 +37 +67 +29 +44 +61 +27 +58 +31 +90 +19 +31 +61 +46 +47 +23 +31 +48 +46 +54 +16 +51 +30 +9 +57 +38 +34 +19 +40 +13 +68 +43 +44 +49 +73 +40 +38 +57 +75 +86 +13 +47 +59 +47 +45 +69 +37 +54 +36 +41 +52 +27 +47 +49 +1 +87 +87 +77 +31 +71 +36 +30 +57 +40 +38 +36 +4 +57 +39 +15 +19 +15 +48 +50 +57 +18 +12 +66 +58 +1 +2 +80 +0 +34 +63 +65 +1 +56 +17 +60 +44 +43 +47 +37 +66 +48 +53 +20 +69 +50 +39 +44 +29 +56 +37 +42 +37 +28 +47 +76 +57 +65 +51 +26 +37 +15 +49 +45 +50 +33 +75 +58 +37 +50 +51 +86 +55 +18 +43 +12 +39 +57 +42 +10 +55 +79 +64 +61 +61 +71 +50 +6 +42 +65 +49 +0 +67 +57 +70 +49 +22 +13 +11 +37 +73 +43 +27 +50 +63 +40 +38 +70 +28 +55 +54 +56 +60 +42 +51 +37 +58 +21 +51 +63 +39 +27 +81 +23 +1 +80 +87 +25 +42 +53 +19 +65 +37 +38 +79 +47 +37 +48 +53 +65 +25 +29 +27 +59 +60 +32 +42 +50 +0 +45 +62 +74 +51 +47 +18 +40 +44 +72 +72 +55 +41 +32 +39 +54 +43 +53 +50 +36 +38 +38 +19 +17 +32 +16 +33 +77 +37 +71 +47 +67 +28 +48 +82 +51 +80 +27 +63 +42 +62 +27 +3 +53 +37 +58 +29 +49 +75 +4 +66 +67 +38 +12 +19 +40 +41 +53 +40 +59 +0 +57 +49 +39 +10 +56 +53 +41 +0 +36 +38 +34 +52 +89 +60 +38 +38 +42 +51 +70 +71 +34 +18 +41 +34 +58 +63 +26 +30 +24 +15 +16 +48 +52 +89 +44 +36 +63 +91 +9 +25 +61 +24 +22 +14 +8 +43 +80 +49 +40 +43 +43 +44 +5 +26 +4 +57 +23 +49 +51 +44 +22 +57 +42 +38 +34 +73 +34 +19 +9 +30 +61 +64 +33 +48 +26 +45 +30 +22 +72 +47 +63 +33 +59 +24 +40 +35 +4 +29 +13 +50 +85 +9 +0 +82 +31 +49 +23 +23 +0 +9 +61 +45 +43 +68 +69 +59 +1 +45 +83 +25 +64 +66 +44 +83 +54 +15 +38 +32 +43 +0 +20 +40 +39 +55 +6 +51 +50 +36 +75 +59 +41 +60 +50 +73 +34 +18 +14 +58 +42 +32 +43 +18 +52 +35 +25 +44 +51 +43 +26 +57 +38 +30 +62 +43 +72 +1 +66 +60 +45 +35 +38 +84 +31 +48 +49 +61 +32 +17 +30 +32 +54 +41 +87 +0 +44 +26 +75 +45 +26 +62 +31 +59 +47 +36 +19 +32 +58 +19 +39 +32 +69 +32 +66 +61 +88 +23 +47 +34 +29 +50 +23 +39 +52 +48 +52 +2 +18 +23 +29 +60 +86 +73 +26 +60 +74 +2 +5 +68 +23 +46 +46 +49 +7 +52 +45 +76 +26 +39 +44 +36 +60 +80 +78 +64 +17 +42 +37 +2 +14 +89 +50 +43 +32 +46 +22 +10 +52 +60 +27 +55 +51 +1 +23 +14 +0 +31 +17 +33 +32 +65 +38 +75 +0 +59 +40 +53 +53 +58 +34 +3 +31 +66 +19 +29 +7 +54 +87 +65 +65 +31 +39 +48 +49 +41 +58 +36 +35 +67 +34 +37 +4 +67 +42 +53 +49 +60 +61 +75 +70 +33 +23 +36 +65 +49 +54 +77 +23 +35 +48 +48 +59 +52 +0 +38 +23 +62 +21 +44 +68 +68 +32 +48 +48 +41 +44 +40 +63 +33 +87 +40 +46 +0 +41 +25 +55 +51 +48 +34 +44 +39 +47 +61 +51 +79 +40 +60 +33 +66 +1 +39 +48 +35 +33 +52 +41 +63 +44 +15 +17 +46 +81 +55 +72 +54 +40 +69 +43 +46 +30 +22 +57 +27 +45 +36 +44 +32 +46 +78 +37 +43 +35 +36 +38 +48 +65 +47 +40 +23 +51 +47 +51 +64 +63 +46 +32 +63 +65 +36 +48 +66 +54 +11 +30 +31 +64 +46 +81 +62 +44 +20 +46 +36 +31 +64 +3 +33 +46 +22 +47 +0 +29 +58 +61 +27 +73 +17 +34 +32 +58 +73 +48 +62 +30 +77 +45 +33 +29 +51 +60 +38 +42 +52 +8 +41 +31 +74 +55 +53 +8 +11 +48 +28 +35 +12 +32 +64 +44 +89 +35 +51 +43 +11 +81 +52 +53 +61 +37 +49 +78 +50 +17 +28 +49 +60 +78 +41 +22 +34 +49 +22 +80 +66 +4 +5 +30 +48 +46 +15 +69 +32 +26 +60 +30 +61 +83 +30 +74 +37 +18 +87 +14 +25 +15 +31 +72 +40 +40 +78 +34 +43 +0 +66 +21 +68 +45 +83 +26 +45 +28 +44 +83 +20 +51 +47 +38 +40 +30 +0 +52 +24 +50 +46 +50 +11 +15 +44 +25 +52 +46 +44 +59 +36 +17 +25 +34 +76 +16 +47 +36 +34 +56 +45 +11 +39 +62 +79 +38 +42 +62 +48 +84 +39 +73 +56 +59 +61 +72 +11 +17 +7 +47 +56 +58 +39 +46 +55 +73 +74 +63 +64 +68 +51 +27 +55 +46 +40 +46 +39 +30 +59 +79 +38 +35 +41 +53 +34 +29 +67 +35 +13 +52 +30 +45 +60 +0 +61 +71 +6 +40 +60 +69 +1 +26 +36 +20 +29 +64 +32 +79 +76 +48 +44 +71 +35 +45 +61 +32 +40 +15 +1 +43 +34 +30 +40 +44 +56 +39 +1 +74 +37 +27 +52 +27 +33 +45 +35 +59 +90 +30 +67 +37 +2 +11 +38 +44 +42 +73 +33 +27 +78 +63 +69 +25 +89 +27 +59 +26 +35 +45 +41 +15 +43 +62 +52 +27 +37 +32 +18 +26 +45 +46 +77 +22 +48 +31 +63 +55 +35 +52 +12 +71 +0 +52 +68 +10 +53 +34 +67 +78 +43 +44 +44 +46 +67 +60 +89 +39 +28 +32 +59 +25 +0 +52 +58 +72 +69 +3 +0 +17 +49 +29 +68 +61 +62 +19 +84 +87 +53 +34 +64 +35 +30 +35 +16 +70 +15 +39 +48 +29 +0 +63 +49 +9 +19 +2 +62 +87 +49 +42 +78 +43 +41 +49 +41 +33 +49 +82 +34 +47 +20 +28 +30 +79 +34 +89 +39 +59 +45 +31 +38 +23 +73 +80 +69 +76 +34 +20 +87 +49 +54 +32 +66 +50 +68 +56 +28 +40 +42 +31 +64 +0 +16 +5 +34 +53 +59 +50 +46 +17 +53 +41 +49 +37 +44 +77 +70 +41 +41 +71 +40 +42 +27 +27 +20 +45 +87 +57 +30 +15 +48 +41 +23 +43 +77 +7 +48 +47 +5 +41 +69 +17 +24 +52 +41 +28 +14 +50 +19 +42 +45 +28 +47 +50 +64 +53 +49 +35 +32 +58 +40 +26 +69 +12 +15 +60 +73 +22 +78 +37 +53 +55 +87 +87 +47 +80 +68 +57 +52 +54 +87 +66 +58 +66 +37 +58 +78 +3 +32 +36 +15 +64 +42 +71 +66 +17 +13