From 65d85a9bbb0fbb9f6245544e41d7ea90718fd2c7 Mon Sep 17 00:00:00 2001 From: gerald <gerald.moesenlechner@univie.ac.at> Date: Wed, 13 Sep 2023 16:12:55 +0200 Subject: [PATCH] Formal release of V0.5 --- CHANGELOG | 25 +- JUSTIFICATION | 2 +- MANUAL | 2 + Makefile | 8 +- Makefile_Centos | 8 +- README | 8 +- matlab_model/Example_model.slx | Bin 23586 -> 24438 bytes matlab_model/HFS_Wrapper.m | 166 +- matlab_model/HFS_bus.mat | Bin 2737 -> 2840 bytes matlab_model/HFS_config.xml | 110 +- src/HFS_API.cpp | 1504 +- src/HFS_API.hpp | 196 +- src/HFS_Wrapper.cpp | 4 +- src/HFS_config.xml | 32 +- src/detector_features.c | 451 +- src/fcu_algorithms.c | 1105 +- src/utilities.c | 22 +- test/DetectorFeatureTest.cpp | 314 + test/DetectorFeatureTest.hpp | 53 + test/FCUTest.cpp | 204 + test/FCUTest.hpp | 34 + test/HFSTest.cpp | 431 +- test/HFSTest.hpp | 6 + test/HFSTestMain.cpp | 31 +- test/HFS_config_test.xml | 36 +- test/UtilityTest.cpp | 222 + test/UtilityTest.hpp | 30 + test/acquisitionTest.txt | 40000 +++++++++++++++++++++++++++++++ test/example.cpp | 24 +- test/noStar.txt | 4096 ++++ test/trackingTest.txt | 4096 ++++ 31 files changed, 51534 insertions(+), 1686 deletions(-) create mode 100644 test/DetectorFeatureTest.cpp create mode 100644 test/DetectorFeatureTest.hpp create mode 100644 test/FCUTest.cpp create mode 100644 test/FCUTest.hpp create mode 100644 test/UtilityTest.cpp create mode 100644 test/UtilityTest.hpp create mode 100644 test/acquisitionTest.txt create mode 100644 test/noStar.txt create mode 100644 test/trackingTest.txt diff --git a/CHANGELOG b/CHANGELOG index 065e6f7..9959818 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 81c5a4e..69dbe60 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 3781f21..bebdb79 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 6cb28f8..5cfd774 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 f3c9eff..9f0459e 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 b0e9627..f93dc61 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 GIT binary patch delta 20017 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 delta 19157 zcmeyik8#ls#?5lURm`k;M;`7CohYnU-y3w=@34WupQ$IlAE~_173HbL_^Q*3qs!rr zPW5cJBV{SG+y2;|o6KNausQwM=Erw^x6fbn>D&U}l__nD6kOyymQ`qW^VrIl{WJa4 zvvksBFV7PJ+-#M%ZBk7Wy$&~rnPx;ceVjAVq~)rlRb;eq53hCO0<{9JmnRlqYKkhq z%38lpvwAt}0}Gz(5e-Y{M0Hs^@1G}oG2`UToXGkYtIQwpII}V>F}2`Q`m<JaX>Rt8 zA4y8$S=>=Gx*yG(Id%TBIibFnS$r?Oj`_#2|K0ofzt;a+`X=fq1MlC3Vq8ma$7t|{ zc1;hknx^K{e0axmt_g}ij_gs{UfwQy>al^}AA^sJuSP50ned_O$m{JQ|Eumx@})2R z%w)25$Bi{sH+#w^YGu8-$NN2kX@BPQL;Ih|1oqtcZ@kV!NY}`Zt(JxN`KIV?cY4?A zTQkdA=Oz7<XusI@?GFnt@1KpuKg9#QnOP>+M@ntp%y@>8>$9sl*L)rZhCIH>oy;=z zcc=ffj=n8-EV%e;$rYRIuP+>VGqX5cJ0FP|x&{XKmYxYs7GA!>P$M+_tb6t{$IvrQ z!NGwc+9IyOQ;uAj(Y|B#`Mvw^)IWT3)B1k8`pxrkuVdeT-+WJH=4{ELP2C%u6$Jc} zm0MI-{N3+oCidaqDY0;lQ#T!ycPDT>@p-xaGf%x{hXG?_fv2Q$UPSxz^=Hp1zJKHK zEq7wq>C*EbZ$AIDzkRjeN8aa`S=#k#SG$_*ss3Iwe~pQj)PzMwQ=f|Ln~*AaA#b~` z<ceos9vdINxG3O_q{fsjPs`?<dl0_nc34KGhnx1>``17BJ=nHa^seH>l56~yMFv|U zi#{#e<FQWEePVsp#Q*D`yq+K~t9j8Tz4eBX+~3Kkm%E*OtRdT$(b2?U_9AuW_No)B zzPcP_c6Y9D{L}FJcbI*7`OK%Wk(>YgON$Af{NVZd`PH^vZbDb~wZ$(fnUpn`*KkJP z0*?Imo4r~d|K7XGMd{+4_d=3+35LI3Uf!(Wt}<!1)GaZQhc8bCdDky+|F$ZxwR`TI zIV^{`tDKE`W=ygA9;>cae<nWFVA{h_{-s<ePo7@hRc68J)4|Qb#Wu0p($~l5S?3)q z=il9Z2ao@b)@;_**V5Mdr7l|RGwn!>frL+fhIjtSr{DkkZFXK*_Ump~^yLoDJ5SEC zJ~E#=wegFt-Ki3Whfz}|Hy_?zzdc{_*4!xv1m)%V8%uV7xN^J5V)6DF`+fYE`z3FA zek!7vi|diclzHp)?sD4CeeCPj5z;vG#l=_0j-8nP_0=uEwq4Fbx7NR%QYT{YF0IW) zNYnbhTHIYjt*uuwjP$m?c{?SNW6qoq6~RS2MV$Q}nOXJQz1cox>c*CBo&9$oGhb${ zpS-{HwV1T9vuo(oxQH3EninmIGdzFkQc!H{-NouwC10OPuU@_S)b;htUwPRU1*SPK ztb3dwIeVrj<E>7IGrGFT)27+<mwTM+tbNiIzP`#xPik30-}jUL3TBheOq*K6#Kd&! z)vFx;Uq+ed|IT(<%rS|Vm$&g%(t}PXAtCd%YtGg4SH`uL>~!vqj%s0@I!8cGZhF$L zr8ax_bnSIjlDE6_Ds5_uLrth_;<6+C@|BH#dcK##tMfOd?O(8^=qvm3-OiH>ERLF2 z{E3dg`t;9@4}9t~W=WY@?7he@bda^xDR%3R`Ffr|eWckxUzv2y)VKH<@8j?zckbSu zd7!{Xx+PrhM*Z{S*XFG1EvwEvYGSQnX8j<|Mf>Tev!}Li%8#}=ZU5ilmEvAI^{;<! zeW(f+$Um5{ULoZW*U|jov-~$>)~@^7FT>P7Oa9bOu8o?v&Q@)cyskOB_{ZTXwUu9s zOOyInTgrcSJ3eo+*P+Xgrt3>KzTj?js?B_KWF?#an^MW0%k?AX)d$(6SwFiz>zPP- z<vZJ%%QwbZ9M(9y`V8|ak<I(|?fVs9Qc`<}_pILC3(^Oc+`i5KuX^f<BOh<P2sb>i zheu@(|I0a_j#zFvB5^XJtaqmO>LtHxBmKSDCZ9QT=8xmT6a8voOSm`Qe35fST;kYT zQ+EAgU0wb8)v^l9j~+6JpY>M7y#6NVoDCbwMYeofYUpM&%~r8^cB0HQsX2WM%U&Ki zkg(zX@m=%(wjMoN-7t6K_gdwPYi`-xm?yDbiRWKjyu_Y_&o5Hun=NV%P5pVPNzlCM znTAhYyY=t$+rCN2XFblAT)v~*g8AQ{&u>p&ym#Zr4$-X@Q@X7dSU>UX-gY>ww4~$o z>H5>(JvOZA6)T!@<@$C1SKpt{oo-sp$zLybV0+$GwWJco<Vj*O{ma&@DLH?};*Zcn z-_kADUK*~|UG%f6Fncve!Sy$9a{5_*&w3Z$W*Cw6_TDBVnSb+sUz-(uWT%i!A9wdr zxtf{1=L~+{W!kf%eB~@p4mLM8x5OOP#d<zV(iMWQ)gL;>rtkl5zw*=jOJ3e#Gk<Qp zL-D9^T=T;R4;It~I(aC^^<7OlsG^_xceTWibGqD*g_QR8?g-d_JRpB{!<@uRQ<li< zh<_EGmXe-YS)!9ZYwG-$n?yM+8^eCR2#C78=Bb|Mr|pq3CjyS0Z*^a0D{<@QY~K9$ zhj}a_KUi*Q|F70re^bu;_GyDj4=XQSSD2{y&`?4*Y|>kiX*b>9&6^{#=>6oK{o9XE zygYaL`+JINtN4x_Jvz16M<{>ao1;!Ugd`ewYOTG=y5Y>9KYz}D{`5sz$>ab_P0f>+ z4FcD$U8|oy#h_81;S9rTX72ZI-q@T!do@^~<L{sJ^A<tsTX#h4TBNmeQ~jrYe-)vN zvbXkrdhpiBH%cXxzqKmwleJIiRndm2Zi}zp+|P8RV*R@Nw=NXSbFiP%UZTt5^>HJ& zdF{LzAI^L?+h5E+d$O|4PO+|gb3a|O&@IZ~+f$uh`6!fe`>Zy%OKcBA9{u_GIpKw< zsAzwiZSwM({47tEDV6<)EX2jduO7Zue^f3uvFXsmlMc6z=6yE$dD}vhF=u;v^Zkc> z{OcQ!zUJ47pPg8L$feEH?U>UMc6RpHIifcneL0kQI7>_;<gr)ntR;R?3#v}NzJ5XI z^r=75M=ESzKD+sK*5u<yc29VvzA$0yi66K91kW^d?nusa*XQSdmVJGls*)au_w_jo z{9mfqYufIewA4Z0z)wNd@cF86uk#Equf3m{!|CE+kT{9YM7GE8WKQZPD|7w)MD?N` zms9r~-NPQw;cPuE_9uSjm07yCJ{taVetX`BRaNzG;f?-lCN^=RwL60Bq?GtPA_9Yr zH)n@tS<Gp4;#D{PHaV3mW2W&x<Fk^{=VMYo+W)LvRxiDnEB<|2Hp3fs^+o%6JZ?!v z<eV!v&RY1rl0{Tjq4dL>Ig1wUoBFXxD(3c$%y*y8WJRo*W;oqq&dQ7>nK$1=asOiA z(%@OyIjM$UhQ-W~+j{qsW$Pzi{j2{zVU?PiT8@MAn(TEvJ3jB)xl>XmH)_?HEv>8y z+}B^qo0#8`-M6l%UO4G*zVW=&&b71SR<BqyM@o$=<)KE7&c^RdOjF9vzTemu_t<d5 zkKJD9tXLvD3LbdY8P>l#lTl+5RgqD($^85D*1daezrOpfBgE=#+V;6$WYhFLm7DLT z?ut!Nd;RjI<c?1puS~VpyTW?%&#jG`3GZI(r7nCMT51|*mT~tj$Gmy<vu9WTHQAW> z{n_1yhK64(wr8ylOj>o$@2zM2AMTB24t;lw{vAE}_U|E=yHe8g4LRSN81_np<#A?p zOYPpy|3l<|S+f5H+sr9`{YhPK^X{MEOHH*=ICAvp(I@tw^S1o&?bV#H&E(F$iO2u3 zR7YR<W^~_teSfvqEyMfy7S`vdiYnHd^Izb5^>0#Mkf2`gx2zc+fAm5!c{}~gCKOI| zGT88<@zS-Y_g&6$zxb0J{!?!Cu8%UClfGFVee=rm(fvoC#sBNyk8rMAv%Y?V>(Bf9 z&%b{DJiUEt`HPMx&!0Sb6I&AKr($Wl=aE{J_bF~g1-+Cv3)*C4W$RNXA6>gvVdLwG z2J`FPZ+e~kSeqhxbmGK`(|dcb-}xldWiw&vw1?i7aRD-|UbW$C<})l6??}tHw6MI( zGU@BI13zzcdwc8u{9$)vP0J1wpNHF(Cp~%`dFRin&6|GQZQ9rTzQH&;%H+VI;`Wx7 zFLlZ<)-7hay2!<$T`zO$*NMve+P7u!iv`UqR^4&;)#v)JUu8E<_0{vgmeqL4UUsfa z<KOSMKQg|Z*YE$PVfVagM?8!_W;6>F{3+fhtgO}W_U8Jv>;Io!^G8e7TE!%U!GbrZ zMfv)7nX12Y7W3)3UgY27bu4^cLY>wpHBP}-c3ge46(%l9SG!*JdAYaF|AOLmTc$03 zqqLQO2FLP}v)j2#o$8tQ+V0f;{5R*l*!%mgi;wEX?O7qWv-anQ4+gEXw{Oz=`7-$4 z<N3{A4lickyI0@9aea&KoIAI;%nePao--_Dy~%&%Q2dk4n}x60+48l8oMsn0=zPP| z!u`=Vvp3F-X--j6)0>(O-LKfg(BSQwyH=6wD8KREEN9cn4|Dq#{H?oup}yeFWB2Rj zpBLt8-MW?8-7WX?mc+yxH*Uy>XgxBD_mQ`hl5yyL@L+XU-`f7klW*QPF`cM=n*08_ zZLNQIrRu%vxP0o=s=QO;Ei49d2d*60cJp-jx+A?huV>HVdz|ZX%Ae<$lZ@)oBXZw& zta@PKaJ;gbU#9NNt-HLekxwJb%oeXru78m^XF>4)CC{VEUX+SxeO<u*WXY;muNFMz ze>8ovq|`DChcsrk`%7<4+*-Tr;43la6)T?=HXShME7rd264T)pW8plbI!RYNUFGpA zgBLmZ^J^{|@FrC|xtsVb-O`%7CnJCU#@Mb;mmPMui0HAbI)9nZLFGx#?61q&TwFL# zH?3<AcxI#bnT>~yfwe%UmG}0et{o~o)8hZPp7?Ec<KKS0pXt+UPj*)BYkxk$_2C14 zl_NI}@HAd7?)=FQ>ePrZFfed1tPjW!yERSLvx<p<L4kepe_{FhqoMcnXB!CAy^n9K zD9>sB`LHt}bM-FUoaz_1p1;cJV_{`Fbne=}@5U-i7M{K4`^rR9$?pEo&v(DyeE#Os z!j*g9-<ZAXu3qiFgnjMNcg3!jZT<2-Z@uTM_-EoXSLT-Qf3+}rK3nnq*ADp!t>v|; z)BfGM^-gxF+xm@-uFPeB7r!;HPg{7q%}jN%ve)Gcvl~8!+~toKV-@Uoe)n8_o_XHp z45{r4jvs9=%l>$<>f6S{OY6@)t==6Qs#Ckx(y5D8Gx9{IMu4z}vs;89Lq<oXR^gok zxfj2N-VXovan-B9=x~pJE2Gx#e<#)YH{HN&vA*&*?cdwBZci|KE+qAAd5)JRqd>jo zM6Fbp6&6Y>r#T3%>xxk2IPpVKx_#CCZC+I@$J*DeD@pw<l+`S0dn@>WnADl|8(L!D zu991O(ll_w<c4mSC5bwh)RX!W)0Tfrf8_H?p8fcgs#8olEg>w)6D_>DZUhRksZ7*R zD6;psI#Gx{M|SSB(0R_&SOQOaa`cHD?4GiuUdTy^eQ81H(x6ixSgst@GO$p1vhBX5 zTi>(HGy5++?l+NaUZwP0vh@DtlY#RT8+Qg3Z)K_0y!7uy)6vZ}_biTw^e0IeP2&<0 zJJmVmL`Oqe+7u79#Rfh?k!OCC9N2Joo7ge$P5$pvlH^w2-u3pgLYL7l`Ez%(4c@;F z%Rl2dTfMqo&OGGPTIav3li2QWR$*_uurcTfv+eJTGE@9koPXB4w$1eL{iB}?K7VJK zzHzs&mH<nOfXfCA#Z!V#NqiCoA&WxZn6t!($HzUre)oF7rW>W#p45N1Gi|A(waop) zFL+xYtmmG1abuy(Z{fL8R~9y3UfJ5;&ud%0^KP{Je7W6!)B~iwnOP8Nb84l=${9=y z3{N;17^E2{pO2EQUmFHbpEt65b8|Xo3Tfr$e&1rd<@IHg(Dq!RkUEzKIcNX<l4Mex zdC4qtmdC;8o8RxVuAhJS%d4Fy=Em>J+q7!V&MV667JEmoTr=nVo%Z+JJ$8hDJi6uN z*-wG1&xCw^m-WiZdxF2gb^g+8XYRBbp6-`0FIvd`fy<!#etqcQD;1lx3MLBG%ssfL z?a?ysmiIMI$`xDoHw76L-n&(s?|5guH}m=G=-NY>Cw5B5TlleG(dJtJ@>*qlR)n6+ z=D1fgt4}<&S{=G9El)s0QN2fL5|guyh)m-p5mwE|D?_HVdR|c7p!r1Ubm-dChZFaQ zdhrK#e%i?*x6pu-^HFC#*MtiTT~ro&awIO9%<*f5*}F~WR#_Rpo-tYTo>cR8w#Bm# zYrbFeTI!6%D%QxSp|bS~chkGfpS_54_^i49NwDzjs-?>-wj4LjJ$B>W+j)<-ob*}u z_<U&QvI=84g);5g#)90J>drg-X^ye_@|=4^{^s@h3+i_6**3|d@tE5Cw!?esUwO`b z?KFLv{*L)y%w~P$I^A_=w`T5<uLt-TrY*Y_?%|;-pgz$_LDjKLLHL+XtVsDsGvCc# z&)hf7{J^;|>PN;S_l63uT9!E(E~SSwx@+__%KI%ZO<wi-sBMEl=Bc0yJdM|c3fHN5 za2yiscRDAsT!3Zr+)p0@;@2D5oLIBnd`JDdQm)lC^3VP|`^<c>a++e(gy>o}LB|J| z1zs9V+Lq0-B0;)C>|SGC`Mm2wd(EfqOSt<<<965Uy*teAxr8P^4o~&byS+MN!#1BY z|6W`xy}8pm`}M0`o9l(1$4&UblN%K@w@$>}u-si~{r1;8*3DTLU$dlPcU{S;TPi=7 zJ6GgfT%fq8F>Y_I*006?yg%OFR44gEWPe%Dw^G*kd)6PRX9Sh3lMlv8ZC(-9#UzHD zl8u-Xb2V8R7_JLWc9fK_kIq*z7pc1+Z#b*nu2ei|WzcQbFqS5vOksfuF0ZmeXU=4P zeC$T>ZQ(=ze#yn};7M*@mbLm>W6#_3$De<iTWoXr=a)@sCyhN^S>G=cm%o+CWFu_( zbah_T%csBRU-I8uKG$1q({e>sZO?1Y5tF(yuU1c2nR_!VbA|82Cn`IYvtQIN6Ao&U z@#cyV?qy$M>sGPOXwJJWYKk9RG_odaS8CtluBEGV;O90Mhour3yhcpBo`<a7;$9in zkd^doiep~mc9(S;?k}c)YnQ+M?EUX2TbHj7Ow^u{+OjZ9-1o#90qN!)BBJLxcd_z| zoK6+aSd%_IC`aT3`>GdBMys}SJX@bEU!S?Id&_s{-Le)olNo9hW=zP;4-Sy!IJn+v zjl0Tawjx0xBf+3(trgX*%p3ItYt+jQ^4>DiTe$5?rm5!Rm!fJHJv<^j9~-Uz(=_qT z%E}9>=dKk9Dz^ts+1&IbN%-Q8KYky0B9!wl%ZV5HMhKe;#mrv5rJVPTq{&$i36sV5 zdF1Pv-kGfKcL+Z^Gx=9ds)lH@M4Y9s6U)wJmR}4fUXxg=!?#&+#=B(63)htLR!%v# z^EhL!%lgaD?|65ye2wz>#jC5l=KPB;Yk%X2SI;)`EA-~~H%3iSbpLzY=I4I_hSS%B zLw8NuVfJ+a=fN7;pirYta}RgFTg|xm=H&*1Z4TuwJoPp%7dwv${&D*@nKASw_mk`Q z=5097b7=ZXg$HfPminp>^5>=`dX?G*^IbgjaoLYQf6lipzibt{w%GfMo$n;c4XW4j zb}dOc7{GUHR@FtjfRnyzKRj*)8>qf5h?!)sWxVbG<&>z8(m6#ZYByW8#!T`xSDmv# z_g2dG8*`57#uUsktQV~@pKKi~bLN}Zovx`)H~Fr8x+Sqz{m6<&L(g^dI9I>PTYPEH zqqu6BJB;^~)1KUvo_r%<ky@Pv>!g0m+rJ)8y*qRF+HEJ_J~`8xP#ks3G5fvHp(9xh z`=&MRw4C$xabaf0!dF3ApO!Q2J(M_Et^JVk<rACM6f|@mNn2*$ea2|b?E0iu&&i8t zdz<TilfHap+mF0c1_xXg9hwoS=Dfk)$Z4nSVkUjnxUxN4m$~$7IJfWkd?)mP_18T4 zNA8NB-96{L?Oa>oXZ-ZZn>!b?ek{Ihm3DpM%6I&ho<h54+=yTPD|IQGP{-T9*8ksm zFH~OgdGkX{`zxm(hsD2Cym;h<^YdkUrR(Dwmi(H&q^#fi-IgZ%fR);ZK75(n^kA2l z&+W#_9xbco+fK`NS|4+8yT0$V?DZ$c>`Dhs49`9fxyP*L@^)YN>)2;TsmTlU+O{66 zzO(=2E*HJEca~o7Q-~B`tvqsiyGZH(Po~?v;^HEC-A~x7c&9{vlGSYewPUk|p(KBv zo{I3~`e!HaS1QYui|t$xAlGuk$lOuXMeeAN$^+T&l4V_I@4HEE*?Z*Cb)E-D&aplI zzW#^RG~Va3osmgvR&1zWd_wDT;F6Wkj!pb_VuA6+7m98zv&HR8p8Phb?=(4E=oVi6 z_dKhG4u@)jdcpOM8GpZ;bSzxAW0lH}gnJtC_K)rePd$@RzsDq2D0^A)eE-OB7v+u4 zH<B4;w7cFaXRc=uJ9B*26A8&Y?WM~Xu-tQgcE~b$&kxzS&IgXI)iv3VWj4BX?{7F) zmXV+KJ0|s2a_%ANBRdoy`2IAlwqI58>{XWX-oIVD`!s(uN%UOf>yTM7qtd>tR6VYi zr=PuIruqAyhS!aKpL?=?Gu!jw{EJ^-HXo8)owLS(;h(hU<!y&=^)co7PwFiC{hj;p z#JGQk7fzMGk6SLE_KyWrvLf0A8k;v%t`}lpsEwG+Cof-rHm16Gw%4Zr_Vb%A-L##0 z$5-dev?TZFgr8fl_sLIs>>IQ^Mp?pBMmZt<z^3zSf8X6+&A=(Ze53Dt=c%Pa7i=&8 zeLZj9yO{^8|JOv^I%S)Br)aMK)?<B9!7Gw?EPHy!{wh=bw}tV)pMN-eZ)SGT?;|sJ z=6Kd9gzi&`Y|9r>RXJE6|KYdOPoHUDf^&V|t=zd^p+~|ll|AtA)`wr8d~mK`UpG<F zzTm`_WwR0k&Z)2Sv)EgBQ}%m@W4814n`sjB|5e|Qt>Ss%IOF7E_LBL5Zr1JB3T&%f z(;fEAi11zzQhp`OJ@jhstzw6kNVU7qPEJlrDOB8^%U#76vN@7Z@*`)LM7=qmK|$3k zsUvd1_t|4AEc>5TZgXXvb4y^?Zy6oU%{(e69@=i6WBjRMj`8i-xw}4BcGPAr&vfgR z<bFMGQDwICo}Ee4{I~Dq(^m^`Y~G*k{9~a>k(3&L`r^yZr<X0C=Ip=H_`CSl#Kkj{ z8-owkKD1p_JzuKsz=DT6-`Y&bt9GuhxBDwQPgDHNS0}f-dp62kjxGFhZI+Ooy=3F! zYg1}x7sypMZ{^83z4P`(ch6rNuI?#QU2FC^ns;Teui6yrhqE3sFB5#feAe4@x(1vH z8?Wi~vPtl?-<@@^g!#jcTOX`{e5hV}Q~3Vez8zUxs@BSW-Cp7y{j1~QD&v68O>2VI z)-2stA7S=ZJ>_pwA$O|wMctQA))kgNEYe=OkTGzvnaxt;_+w?sGauL)?tS`WZCdV) zz|<$luguc_^XkikWdfTwePNcg<dMqG{OfqOhwZuFErG8B&y+69*i>vgt#SF}wA5Qa zr=2X?bHre(iiz(1)ad4g$`kzpPP4AIk_p;%LG+8ZQk_)&`yJOiU(dZ%opn0OqO`M< z@mb20Oovwj?EH46HT!JYX1@&!=Go)6e70-_=fC`QyKP!JFQi8M9#GMGY&HL^#aC74 z_`6ciMSI#0^QQY=cP!mx_U74bgQF_useO)pe(U*X$#1Ma_2;;7d$ow+gqOQh`)34e zrq)(HxtTuYN6Gvf-|DAGl)vnIy;H`Z+Gx&{)feP$=^fN8i&j{<mD}l|Xxn=AqlfZ- zcOKkuce;^{{hnNxBbtS8m><kEGx>2P{D-a7gY9P57oE3@d;Nb$#M|!ER>$8<zkLui zd)=4&Tb0+<M!uX^R<g1-`sKE=nw4|c@=bW=_#t!ldHW5ue^-|+efj;?#hLYPVZZio zU2Oe!_A={R7q_Nm&5{c0d-daHL0{F6THEXWTbrkTdm3ba#ZCQI=d#teK6ZY4EA)%? z<-T<rVndBxe&_CyUtqI*_4ALN=UKfjxy#sf-)CCf+?!#jXMDtU|200I+(j?rw=`$J z%~@Bv)!Enh*@br-+uqtG?fw$<U;JD0nlJUDuXz8iz7;6{V$1KEstv~u&NZ9+y58k` z{qf%o|C8DD=XT!Lcwf}nWS8@V_o+zMT&2ck`CA0+?ayDFSDU-)WsJ3zgUvsO-!*d| zf8AQP_GLGR{5sjLe~jy=mRYv{Zcu-bo9!NdurGb#>MO~6gyx^#YLokgF{3$II$oc# zJNZMWcm3T%*)JXor83OT-SbZ=M>*xT_@=X8H-4Bq^&OMg;w@_@&7b^ra>TSXF%Q2w z9^9<7@44OKf8X?<o_D+Zd~4;G{q^hkrgzI<UG^jA&(_~g|8E@64(2|7?TgX=^Da+( zj-Neq)hZ*IQR0W*v<GbW9=)t8xnG)g?N5(IieF^Ry|vX5=M(DZaVq|}@yKAZos;E^ zJ%4y4gNv%}w$y9fNf$Hydfa&<OMvvhzu~v<yJptS{k_{&#~}LBDWCAkvuE(X&Yht< zP0lA})ved1x0=^2k<W5JEm&yZJGazdz3<=)p-I#Fdqb92e`VV7?a-9au7?swHfeh8 zc<=OR?#ds<oTkSMYXgs*Tv_kGR#W+nVAtc_6OY=?Zm2y|P<Zgn;`Ye+kV~w8^%s0% z?-KNQ@Zr$8iC+$-*6n!`;Is0knOa&3-!;?Y*X}5O)0`O;eQs)w^(8&C>1oj|-Kl)X z>!y6|P;*q^m*5sGKc$h+QGB5$G{f}sy+?Yt;{zVAlUba7{8RTzw<*jT;YVgpua7)l zYFqb?V{J;)yfd;Z-j$r*BH_ZiL8&1&>zkp4LB+NcTevvYr~DSzThgHJ_Ch{rgOhc9 z;JaIlU4f?>Ql(OlrZA|Ro}cMCGvt(hOXQJ{i3esSrp2r%H+b5AXZdMC7O&Hi&Sw>t z+E*-SyTCH*+skH$1tmI-2K60{bL1|uDtxGKxG}-nnbA4$=IYKkmwLAwu@6palt_EA z{Lwr%>8a;Y(H8NRgRT4*Hwsx+tUaj1A1d{m=a`@Bx;2%jW~i;pe(mz=ZG;lbo(6@e zCa$*|`(_lW+w;gM8*NhN^03UjV#0H3cQ$*>r=AZ@ZReS8Z&%~iP&!*H?)CIbNzD1# zF5g^S>viY2+3jBAdB`<feea^VJu6inB$Y8rT352nZ+<#u)90Hvmdp8zADaD6=F!L2 z*RK!eu&roX%(O7drIM++^=|hmtLb|0LUkUw+1SK>O}q9-ze7=Md1`TcMNR9{<b8ZA z3oDO3=a}VOJUi*#nM0x?nc)UW*KYGAn<wn}S+LC4&$PC_*1BJCyY8Ef9X7&;o?WpQ zxht?|@8jETQ_`Ij-5IW)J0Uwaw<6EiO8G&;_J2m<0SCKne!na7l-X<+bLgn<=kT4$ zeGhZGHTw8@(@S<N{r}BKu;)?6<%GS-6C>1LJzX!HTO<DSu<GL#qBpaC2xaCOXEW8$ zo^_`5@@v^_KJ!WJ(e?KY*e+_dRn2{NNkX}w^Jq@_y23ePi+aLNoLDG(#=-9Dx0Siq zr<5N0vhv!G`EFGkxiwWTJzD%EtK-G*lbd>ut1n*8W%B1=wCDGmQqE$X-wGB^KIqba z=!wrvyL;C=^K}k=P?;OenrN}_x_9EF337t|Gfer*KOR`z{Ab2=1zqlb&ibG;w^TMN zJC-JN2Qj)Wm^`~(&BL9MdwYrk+p3=vb7xmDGdEsZ((>}g*0Y~)`iPkeuMG~=oHFU? z&E(t@I($J>E_6Tr{3tEBy7_3Gz}2MZe65wY^%t{w34Bj;l<n2^o^5v4@J#Hr!$<x) zJ&8<lscpVJJz!sl&e6RS&%eu-ovz_tKgDK>#fKl~KDoU+#b`Y{bKN031*aw#)m-JK z#I15^9=~T)rv~?}T`2wTbbR29TPvA`XPLY_aK_kG>RDN0V(bi&=NsnE@wRkX<?nlN z$;QeJBD1wJO}kQ#rSd5!d^i%n{C#xP({pLUZZdX<ZTFrvxpsd3vA&#guQwvW=WI;4 z(lhEEm5k!&{?hiE`*CrykIS<e^VIlc<P28Lm@z?L_xPiIsTy@x8b6hJ$}RY>YSaGl zk6!(&$)zhlPO@_pWmWUAV*g$ra;Icr>_X->6Xq=zekUDrnX_iP;Q3yo_*eQdo0q&l zKT}43^Unzq4)by)r}6Kct6y^Kl<Co|fQ{jATX)_qdsQ#_{w)9g?zKM(l>hC$l(Bl{ z*_~$@KCDn)Tl-?!?+taj>tmgF72J{uG(O?)zkUUKu)@D}yp>O$$uANqZm+CcXQIA1 zIeXs@#f<0`UfGA!>S6`9vM(*yDXG!+)Kh9!+IRSjTf0J=b-@m0sjKmf|G!RW&n>U5 zmXX_Z;-l1@i;8(Q_4y@?ukU}d&E7keEoH5o#L}yB9n3;=zk6-JJGG#;J52djmil~# z=D3cOTV^L!rH^w5>~RZ!^!Xvzjh*6M=BhgL-`Pay&vJB)lV);|pL(?Ce%0$!acT#e z4h7h!yfd1n`nISvkz;4!p_i)nG<fxoJ$yMKY02*wf6v<0d}V!-Rn}i$#r@n(+nHgR zuj&rZ+3iPD4=&5gkd*)Q^vt!CO*f0a#<u@vDLN?8`1PxWO-CTlA&0jK1`X>SS2rt^ zc+K^Fq#4P7z$pFn>N<u5fgr{3jq%Kz-B_ZQvutU*)fJe%;%?W5ub(*g30N<<Irp2r zY>1oX*Lc<-(?eUL+cc-B3%vQ&QJ=Y()xNqn$Va+4YsFrn4DXn)54f|R-M8DvRkqRo zo7YBX^_~sVC0dEsr&Qdz{O9A;315#My0Z59r`zq}j@u*^Z|gg6yBSrTx;gr+_UuWA zC)!JITK{OX;f7`}J?XZ9hnqs3GXAIYEfjFb*L^<k#<ZVO2ev6CNM}VxUGB3DTVfho ze<)+OKzNLK(0qox)juB}6y4DE>FKoYvwN>M?2vW7qtUqIdiUYn__boW(nk#+?%s9z zJ^!p)kKgQT-FDx9w{<H2E4~BwLZkn>?Y^3`UHa~`1(!pw%uU;W{gv}nhSuox3wh=f zH(h=C<yY;J_bXpH$a*|EIZNAS>CeY!pSnie{im+5zJ5|zNm8(<*Sg-7zY1r(G+*U9 z)9qUAcAupk`}a#EJvx&w`7wTJ*^6T@rcDh<yd>uOaat5_yywPWpIr*O(q-b9ugCRd zFJ0xsA`v(>l+$3+syE9$tU5B?DnG4GDgG;QZPTvY3(@MutD*|?{wSv2Uj6u&*3LT$ z$F^=M6aHGjlCynL{b8?3JMH(ERZsNqvp=%jEa?kh|FP}I+aF8pKBRguOS>tzXMJvC zp8VZy!CmWAZg;ryDt53;)sa26MfugucglHnPu|W`wK&8ZV*B9nfzL<umQ4}a{>^`f zMN<8~B8|(7Wf$q#&dUlsc4b~`y6(om{-#G%GQ+nV{xIcS=f@RCoZerpKYCXsa?6C3 z4=%3Mw&7#-<up7hTNv;zSoh8%(e?a1>2l2XXYc(x)xm6Y_4}x0LLITX2j1pZr3Q0K z-Iw0KH=M_zlTp#e=-rC-HjmzxCo;b;`~GSoPv%ZD_nB>zTaQj%SzwrS`(2lIf8K&0 z>yi#EeWbr4slDo)lI_kzk8LYce`(Zfr0Eq!or~!-xXHd*vto*;;mb2cE#b8_%=^oa zdDaKmX)ataF}g*3cay-eCE`C4Ol%l8sMQ#%BtCw?ma{t7dC!NYv&%Bnlist<PkG^+ zby?<DvR8u514ePaCI7|kn4ae4OMJ9BRVFr1{NA7c9ukFp%Nh=zFp$}O$A0TF$-cRB z>#fq=?rvLlVs-4CHwETL%N|LHABk6qc*U4rdfM>Kfh7;;e)rn6amx&y({f*DEaDP> z`;%|p-c7yIr{g;|TO2S^He0?s|A4aaz3E?0C1+JT+su0NF!4!C{5p>CXClXR<}DBP zs5vG5=d<Cr18eTT)o9l{+-uIHF!L1Ctgsk%kA;Eq_4D?Nzw4bVn0oNVo6GC}bH>z* z-`aZeOY)14+u62=@w(<HNChjZcC8S(?D)8}sl@uxa&fthVo_>Wk2P$z>zdKq@~9=P z<XY=2F_%7O4R2;aPlb|$iw|@<iNv|)SGI<qj5820Du4O&aL8qWUx#*Q22IT1i8r|R z?Ny?%r|oM^*VFZi2Oh8De9LQ7Yf~z(l67>USzl1$1g`J$++U9zkA8IM@{g<A7n%m| zIN!7Mdzeo0!Ug%ykCh1WPm8#6;={+>>z#QHn{B2Ge(huFZ<qH!%kc82!k>TE{&9P6 z_gboMQavlXaZmO3-))By{%Ak-@?-YgC{w(CAKSjJ-!1&}=9YJ{DA#+<_L{!u=%Jj5 z%C6R%T2r6L$3#D3JS6^fR?<`MfbM_%Zaue;v?d(>({O`pNxWgxQt#V;84p~0_t5P# z!@)NusV85gWkzo@+cZ(rM>Okj#DYwPo8NoSXB|@6T3Yg8W#8eGe{U6@5}W7BE0KG5 z<<&oKQ*(^}s%VQX_~X5YOIPjFgZiyEUbuSI95JxE8L;iuosiite0NN`AJS?*_3^DU zdCT2dtd7jKEM`6~lCOKUEm-=U&Cia*E05N)?su|1n)pG|@CY~Or2jSo@=BBU#l@V| z6MxOD!?0|gB*V!rO}nF#dYR(e#OH+-`}_*H@R3t|{l4bF7vJi=9aM@Kj=W0$D<uA{ zeu;(C{-%!|?Kg^}R&5E2-x$<;|KcH`$TA(~NeOr6{5Z<{r+-q~k=IU(W{Pduyt*O2 zu0bm5(u0m>-C6r1&K>{qn(6D3Lq~6Uho@|+@@9G&mA}>Jy`Spd)<bi-xXkCT+>o-@ zWc9j~CE?-Qzq%Nk&)W21bKtJ8K68utymO9j6Mq$5e|8sV>FuXxdG^7vKc^LjWuH7% zm%8@%)Gf!7qc29tg?xDP&iLv%+w>_{BR0K?i+o&WYHfb4?A_GtKQXPJ%cpFT^1gO> zb^ntz)2Y@QPx-#wxu^Hk-{-4zZqGQ8r5m|s-MUg&XZ2+(^C}s<-)h+xdra5R^Q_g@ zzE{2J-laW;3(KF^pR8K{nb&ihT+~VfhStBUof^^~#cj~vr<xI&7V@g7SKZlOqrL7! z&Xd&Ri&{3cIy!#2SHb!2(q_x(75hyBB}16@?(Tcu`{}{AJ6C-69o@S0tM}!pZr@Mt zySB>U%>3C4a;G1OmfCL;ni*nTvUu;dlI1ZEm$z@#n3F$O@&2XnOFO;lkN(-cGi-bO zy1e&0`}S__+qU#w_vR^GpRZLZgmcV2&l~qC`B-$;eiPr77CpCTC*D~zq0xTthlul% zt(!}K&bg?6sCNCn%3!Uksrf(Deog!#e(13Ie^%51uky1mCT);nU`TIfU=U|uU?|Sa zEzQZy%hpfM&r6&9)_}j>ZPNdF`<spy#lBr8bNiFF-`vHzT|&9<CJJ>gc(Xbucct5b z2`(%NGZ-DZf4*M7JDq_^<(Z>u_0LHsg8o0dX#981yo1N<ZI*fFpH7wQe)Ig_&F=8O za_5}{kKTOsye?9w{>O#?$A6Z~w<|>-Tiqc3{QlP}`TTeFPZKZx4mw;{^^vQ7;^CI3 zKTW-Vp8u=hcUt9~T-=otc20~ouQj_)Tcm&I>`x2I`SkDS{(pZzK7BKx<@v%MbJmhe z^(+6IO_=nyiX+Ixd19W+vCT^Fzl-hW{qxND^rDvU)zb@48QUIsUw`TDd-wJK%=i7- z`G41Y^QjIh2Ub4ZkasHEY@OuRfA?neZtPu9pRg(7z>{Ck4MK!_Z)i+1RzCZ{F1}+) z{kc<45*iQm9Zv|wP3&4TyFkSLlZM8RW7lq3ba&5C)!U?5y=S7}^uM3W@3QP~>E8O} zXOzmswX!!VEcs6>-TM^ZX8FzPIp^6&Z?1k%UvFP?-h5{vORj-aoaBy*uMr;G1UV0z zUS+Po?ORnJyX<>R+~@q(6USJmvm89ud${0});XISH)r_p8hnY|-0}azF@yU&-+ylL z>8d#RiT#4`2Hk1ikEL3cPT4SjqS^KUt(&jr*C!es<13iL{CJ6o>AxDONAq<=z8jui zwkM*S!!6unHw#Plwui<ya%1u;eb=|vPEcu+J+)NAYvOa$M`rcUg&8NYRBd3GCTSMe zE3Klf_&90qxAW^=k11_Cc+{99bJL^mla4-g>F_;ztX1c8(z)=Bo=Kt)Euy<xBi2r+ zUZauAZE|kn&gQdfos}l%nm(S{IjcA!dSS#}d-;ufUZ~CMv^n<jY)a4Mdzp$xW_^z( z4);wvI!CldF|ur;%?-B0m+E~F1xhbcXxMU0QetuRhN55bHb$B{uTlyPMFn%Vtk0fT zI3p~dSzF}ruid+xqZxSL<UCUlQ4P2p*0VWi%1;aJA6_fjPS0`Zdpt#Tf6L>N!w0%5 z8?UU&_-1zW_hau=p0jG7dY5<ZNnw?~|L3Wi&=0ORfo}{ltS;P+Nz;)`pDnbl{_y^; z=X)<*xTSIKLe9aoV5#R5>mC{uIq**THUI9G$riobPj2`eF_HaTwE4K&+?!IqEZux* zX*nX9w-0aaxG?Sg&Iby6ZcfNN9cB^}zS`-KQ=?bw%f@X60>`vpR5NvPMSXRD7;(zU z@Zb`*#$%St)80Q@rq{f3GMmXMHkDO*7q>mDkAJi$#q*Cf`@<r?#S`W%<^C9YqFqL$ zsnp6PI?{LR;^JR(HFW2M+*^{#P#ibKX!Y*!$7gey+2$p0j#|_co4mbx*CCJPRd<5l zotd1ew_M3DLAB@0@6ymCfq7|Dq>lCm#XT?H$MSelUHfN)h`(%&k&8=>BYIC*$e1!L z=DKn@s-r$|&W*C3X+}qPczxlL(VxCCGi+C3&Mvv9+zwGIFZP|(^`0PTf8^$;O8$SB zpLE;~+WU1&$PSOpKh~0++xA-Z7~C%NW}oRiPla9aS-YF^1)iW4^XlKVXS1n&cj{=_ ztRw$Kyl`Vrr4Zx$31=E-A3R?i_pItFdl9RzjcDX?zc}6n_3lwOCu{n*-r?oyvOnEx zK2PjxXT@GG8QTpk+l+6mR{ZmZbzfWW-yNEIkKZ2UV`t)yIH0FE{{}OkT{XiktG20K z2ktXT*Kqv)G3nc>`V*ZyJzRbmJP(x2+JA0=_t$Msnn(9$s<EgWcWu<2rm}mrI}fL& zC8wBc?aAppNqZ$HfAFu5IL^H<E&9V{#UmP;LT}m_-#5H9>|)dC$qta?{Bg+Q^`?TI zE9W0jUH<RbO(_wd!oXvk6+5c()I`2mc(G_J7_Hs4d8LWz+S@!e5BEepv1L~dytS-s zgKkb>Fxx4%8GBrdXJ?9LZT@w&ZTV68`z);!a#ABNcNgtE;=!GA$ERfK+WJVbPcNEU z`IQA~-7lOwWExQ8b;Q<r=3{~V?RU&FTwj@re6iaUx-suvcJc!8+{_yXCTmT2H)-kW z<Gd?Owq9Me^QP<4m5sW8!%c2jwsi*O_6hB|wY$~S`q1Tq&BpxBfA>y2T9to7qBQH@ zKT89_8R1^{CSUzj@mPBAyuD_vZlccm^*@(I1kY%?BJZ=!y5;EczpqMuKU4CQVm46u zal(@2S@ZeCXgQH^^Q#I+?l76IY%8BSb)}g0)_K=?G^<3Mi!;xik$AJ9a+}!WbZ)^% zNmE3ADs=0;pIoE3LG<*WGj8XYc17tuHembgto7NHr|3jc^olU%WjuQpWxKp6lw4-m zIekIBTI4eiUnc8A?F?UH|Howiz8BQBg*_%}=A&JE=Q&317DyE{%$#Ue@bkil24$_; ze)CJux7aZ1e~Nn|v)2E~>J70gS9eKl*L&x<?pe~r8QnrEcI=xO`_v>3`ZAsS|5hzX zaP`Tw<KCCJSdGl`SEn97(P1pS?<uE?>ks?pu8c|HmG#yI1(8l%w|gb0RVoHWm0#95 zaPHjE?V7(sPq<lKnR7PbyUov#V}kuL#i1v&1Dts}470PY8rdA~P`_zyH(#Y&!ASjn z;>?bG^;Y%wHNu&H_AQz4;(Vv?xtNWd1;5pt*BhKOEEPVWZ>U}QCi8!K?Y*B#Y-+k} z)4RMic}_`O-eFMhV^F>O;jH#oJW9>WcrW!lRyCdYdxExn?i}6qk<VP?J$M$S&TP%f zzAkZEBt*S<+S(od^2Ik+iPvy)J=Q+KIRBaUePz}~@;V1OY-Kz5&S%Jx^$>U`Jz4U? z>}kt8F7DXy#6>}^dS6r6ij)MVqRGDxznZ|dWrF^+Yg!y7*Ft^@x6~VHZ47HzSQy0~ z_vuzZ^NoBVB}2=e1U^w)&Gp`#2Sc|h&7PdBl0IErW^32?g8C-&)AHOCj6b=~nrz_4 z63ct$G*7XEUB%wpm3otQwF>tg&6qWH>QAB9o5Q|my*%u<r717z%zoZQ@dx!5E>*4C zY$G>UKzMH|=Q5r82N(4prk)9_pUEI9ZPjMXW>hKUH22+^6tC4!XEc;;tJrelc%*_e ze_ELOzUc?ASl;duGv?co-!yl&v*<FbE5%Ao64{6P6`w_3Rx~+Pci_^m9T#m&JK9@Z z;uP;}*T3<3hT4u(MID#Fr8mv9N;`F6mCYlb(=AsQZ&|C(s&5|sbkdG$#sjmjb34}m zvtM)RTJMUlPnZ5+Tc)QU^E#M0YVjw=E9<5vUo&Nx66tYrS?3AcD;2$qWy0n#)c<V| z$-1by>Ak@B4l(f>hU1fs7H3!-OjJ6}d8&e=(ay!cL!)fQ!pqSIdwwywd3bDfoETHN z`P|=~th>c~59OSg#F8*G+c+bLqw?5;x2`eKvh~}87F?F)VOv%>Z<A7t^-ck<6qm+t zJB?DW#a?hQSu<asC5D$@H{r|ix0~J9HO}T`3(C#Do;G<22kSeg9@D-B)Ar?U{;|DC z{-jk^lSLS-<JzT#28ntsKh+o1KL4}b=vYOh`Qsw3Vx7Ad7tc$mD9k&kw^!Vgr_6lo z(~ThsQO6_d9d{lKyw&7a+qCdf>0{~X?H85QA9EB1BvjP;e$)_JVWS|~vnQnNeqM5P z?<<QfV!~HgW@LSn6*+TIzG}8@N`m=?yAjNrZT|Fz#qT)#MKba3P0oU?D}GF0zF_5% z_fZQtlG*IHcPE6ZH$D9NOZ!VwviI(=rb(^dVxO`+qqWXhJ*v+>voc`m-8t%Wp0bBZ z=q0ZEe!*^w9H%6U)zl=zgF=7$cy>FTWxF{04(rp}ea&V;A>sGly%u@i+2OxxXYB$; z=0HjP9Bz?mch4O;;M(=$s^eC78;&*|9fyqqFGW9f2qm;R7b_f*XN#D8-TwGj*_4ZO z@*{E*bl31Cd^vgEsp!d-dWHQ5lB~PG@3`*ts^{hESxw1$FEsDyNI#e(<aOli@@*I5 zChroR&0%t3s`jP4r8~8CcwahiP}|y?y7)GanYN|<29@yWGbV~xw*G5)+%LW9Y=r~c zCcmE&tXrj`-(H<?+u?3ohR5-n0&7Yeqc5)ho$YwfvD9RBznbQ;4(&8cwoU5wY{i}T zE}3e3ofIl4Y2=>g)38=@o#Esl_g}_sH%0XeSdPuK&|vL0u(D|U|NA1phWsL<*sqye z!=+CNGF$U+a@DGs<IB3O$@}49$9YYR?(fud#2adT6|5pQ=g9A@<W+uf@>9W6nF+IQ zH$PIaf6_efQlf4+_gb_4?0)UtjBkbZ*Qan<y4x_VU(eyOyZK+zGNz0rOqLwquN~RU zyyorELuWrs<FZ}#;!xQV3!b*(c?Zu=+|94DZ|Cu(Jga4;$E%&%BDNO9UoX`3HaXXH zqfDZ4@$scQ*q!gp<hJj)u4R7dp~$6$4twJh3KqY7JAKB%6M55ab#I@Wby1Lu{h8K% z2akwF_4=y}7K&}-dw#5T#m9S}10EYs7W^>#|I@DrFSwQniW}>-m;6e!xOs0fYxbvi z=kM+2I3Drw*Rg`EZR)c*wk)hG>ADu76mU66@A&eI-mCIHW=^Vcx4Bp{IcZwy!>ehE z9~&+?S|4P7ut(y7X5xygq5oyVPYW;J>G<E+`B;YR_F@~E`Y4Xjb!lq*m?RS=Id7`y zaT!ec!fpIu^@NF5ceeSOMjSt#B)9(Bi~o}+%-SmJ8~mQLRQsUDJC9#KU#s3fwotFc z!A#Bm&-GP5-XG_GUtjTm+xPA33&lF~fBxQHZ?5X|QR1F+(5x1|$jnJmOP6|POrP%T zwfl(4N?D`JDy5#jlebN)m!99Y^~sM3?^2KZ)vo$dvcM#Lo$kq!BXc%Ymg?8t4i}U^ zp+4*E(w~R=4w)SJVz&DHy_}A{b8g+_I{1$5j802(M7hY3cXw~Q-KkQzr6m1>C;oYu z%&rHo%w2QW?%3h=zEWhR&tjRvFZ?@?{yY@rk$cBha4L6!;sbVHzv<1<w)K4VY3h~= z_ElC2Z}*&wf7hmwzR6Z&s|SOW{>k;bj~p_M4E?i_rNtsz(j_QV-YGb|e|F#u-^D5% z*KH2%Tp!YQJV?gpxSy=^O5?O?KRio&j%x{+tG*3e(QxY7^s>Vmg2j_x3RJ7*T<_l< zJ%dkd@<G<PnGVjv(NiO(D`S_1ZZf@ISnvOTPSFOpkGD36>WEZa4mFfES?YE3-OCC4 z#MAeRSa1ANf6`n=Bu4C*f@5s;DqAnDcOr`dRPTuI{>4A-&}FmcM>!MLY`F1AE#!L1 z+thtuO{Cj(EOUdht_L+P-}IQ>@}@<ow9nNhUh6ZB(I4!8#NCxo6nzk{``&_WR*r%f zm(Jq)cP}<9``x3Ob;&neo$tVzXio8%Wrb}U=Xd6<duQc7<;fA7Ri#!53`=JDeDAxe z@>s{m%ZJTdd#0Dd?6Uo8yHxlOcm%yw3;kf}b>oy{*HZg1r#n{R4{rs%>B<!~l8n;4 zA{)DE@|J*5^-$e~29ukgo!+VbmLa9=yR~_D^z1obw$&G1`t&q*PV1!PR37hl?>_3g z-BF*{8ysuEXvd>7{cD=`tCql-fsgdV#X0vK*=g6j<!<Ui)?-KR%xV6#sJJL}#lLf3 zf|@t=t;$)+7CA-rX8-BfV+UmCeG<`itWc`leC+?--R5l*GWM&8s(XA=<H<L?6(W?{ zCHo>fu%vRL+TAYA`VU2mvz@d5TE^F~zP%Z+$G%c4jx~qp-$~Im?_*WhM4hZ@6I1zS zd+wRc_l4I}^=r)<m)a^GPZ#uax7}*q$~{S4dAh%A+|s(a=NiPsS9VSQqbDCGTle() z?HTpfoXxu{Pkl_$t7nQ9<TY3`)&Hf-mnUM&3g@kkc+$VMnDun9=hAxd0uT0<gB3>7 z{x5!<=4WNTJO7r)#vb8Qnbl6&ExY#luliA9u<Ohw73qtnvBeK}SosH>Td=EZ&!nT> zN}RS%9<zhx*Bmu}>z;WcVe>{w+Xd?n1=t@+GP?5SRf%kZxI+7e3CDl!ILtiHaEVUy z%_SfDts`q*tF7Ix9-w=5X>PKINWGoIl`zH(ZT?LiU27vV_8Kl-_@n<^<io(oOHwR4 z*JGFTT#TJKYnEu`LjT6qH_NuZ`?Ptrq-Nq4A7-8YeTR~3w>2D<46w>Oz|6YSd46lf z26=4-=Y;SZ-+AUfzTw%Hbo%RAf9|PT#hdv5i1Y_dG~bi4dh!d=(-o{np(4&~cbpd1 z|Jo$*LP&(Wl}lcSMSQYj!_@Zg3T)fvv28y1q27kWeQ_)MRPCnET=&JCR2IxgF35V_ z9J1&2U1nz{rOU~Y`p5RTG5rf$zoNspRL}5kP3*DNo2nu??iW1TwA{#Qn{6Qfl1qJV z6AdkMug#822)ORINqPCvZIk)et~<M?L^}Glc1FEBL)_l|m+YUj*BfrXn7Zuub4Sio zA@44nsBqx#*>YB@PyMT^N&39HLlZJGVjp)K{g-JDn*6ZJeBBhi!rlMAPPw_}?Zp0f z-mmXy&;9qK^ULYWFAjeH#*lIUX7i^L$={C1{M;^Q(OsUi-BtbG;n0WA{$=jC@ym(N z<o>C@Ce|;%oe!x$XYCboaN@p~)yZZ2p}c0PZQU{UlP~P?|NrXi!J7|+<+W??@|E^) znwP%bW^w+fUuLtzSngRG+}HT?wY_=TF6F{qdzSca+m+>C|DH=`t*=f+T+WM&#`y}G zA|(bNFM7^stMC7EOa9<Rc3VMn;gfm?rq3+7{*Rf@Ekcu}yE<sSR{d=guFaDJt{$uK z>OWQ3^p<IMU7Xs#p3vp2{tTB)=c+$gWiEb9P>1E&-Y1*^HS1ZAD1>gEbI)P#&6S@_ zHU3!J9C*p1QC-BWp8J#e4TrpSrIE!OkAfeLp?p7HRy6RXxNkemUpvvJCx70VcO{?M z#j;O1-JF>5h55c%q5HRU{MA$I?fy;dW%_V=I`{cJu}6*RuMX`ouR2$Mc+#tL?)$Aa zd42JAH(KbLY`MdFiSyCCoc1hN&(y~0;_6dnEz0tvR_xUdo1A{mkmV?!a{J=zebHOe zlylxczVOLP%^<b^afVaA)z|a)=gj0>9X>^KeM<gj&sFPReO@=+C0gOsJypY_$A8pI zSpG3DUA!vjhU2u(MO71S-#fpNw^Y&X-xl57?^0~z8rD_hC+__g^Hp{}*N20f&hvz= ztpAtu@6E59SEN_2n!#XHZ)RIze40(!+r{Glx`y<tALjM$37q;i@ItT^^W@9+(~oZc z=($)WyLrd&-Ipai+n%{hn^0?6dG^AF0C(s7j&1eoe~ahYO|sk9?E2yPvQ6qO-ww(~ z2yISVf5`FDnj6iXpDt{F>+xUWW$s(KiVf@1q@QdH<Co0}-|Slzy_;Qdg7a^QM{@pe zZ}ME0VS8z?=(3?)oZqGWTT9y081nC~esHsRf){6aXRdySmR`nt3w37x!y;C#2J6o$ zTDF8mWS!-IU7yIG@V28Z>-xcGsyih&m+zDb4rpgRJ4x~SlDkh`_b$G~@@wu^8%Oa; zTeU>aowJ#&GXGh()PMD*o_t-RD|C|&9y0M-wa3o>=-OketZJ4|)Kb0rU3$;P@XxJw za}UVqoIb$$l|9^U^)6|4U*DG^2e)TG7fwFcchPd~d#~U9vvX|s)pLZ*J@GiY)5*TN zk)Jg|W5R>d6_edvj@m8PxwmGD&CQpW{!E^+pj$I@&7T*ZN#Z#L{{04l53jt84U=D4 z!6lV5<(lgcuh##o&Q@w|i}99Qcc;_i7uQM89a?`@^s>*LziRc=s1w%h|No13zl!QK zn0@5?-{L)aRpC05t*zeg(!P{m@6Nxrd;z1>6z`hs^Cq)?aWV68pP0yd?P0UY3iBBU zO<sSGPEfjT-hJ=Ku5#%Z%XSt<UIW?tpIP45|G4bGcYkm5?ETSy4t^7KDgE{OL;Hn; zz1_0!I{!{B3AgZldjEdQnl7ot_~4sf>tDNhnQ!9S6Su!AyK`>|>%vdDS0B$^wd@b` z*WKSI$GO{bZq|I!$dT{ym3Q(IcYnp{GLzj(qR+2m+*PC2-zX~)YyDm=i8aygA5V3Z z_0LT^HcuAu@U8#a{{DruV;evBmg|k5R%E|WyPj_o-~Hu9bl6+o10J_mS2Or!$)7)| z{cYXjEfXhPKE0qyZ`RfGOT*%y#E3;KU3rJS=SkEQzV3&jTsv4&%ocB4waQI?ZJ(D~ z`lap7FQ5MZHR;fo?8vVsn?vtB>ihh9lAg|<k8`r#GHlUSk9o#CN4$O$Yvuk=r<H5J z-+Csz`b*odI}b8XbPDi4O>5k=<P!U-INk%7FY@o2Z(INO&)Lu0&&ThnNX&dzcCkhH z%PYYjBF7X~dv@mWoO<<{`{d1LtC-4t7QfoMcAwQfZ}8Nu>&F$g=y2z@gsGR_w2RE& zv{|Qans)2rkogZaH;S?JbQd{YG^>9o>stEabI!jrLd*;vOYiuxEUdC@xzo7%(3;<s zr@oZR?cN++5+D42k<(J~cIN+S7mvTySy#Me-66(591k9rGgwzo6p&waNyq%-6#G>{ z8UG^gv?}@53jBx^Ocq#h(!ucLQZp;r^Q*TiM4U98(fc=NmfEr_JJod~)%~M(B~(9N zUGLj`@Xc25`P=6hh$uf5h%NQFQmFJr;pl^X3f0ek?J$kl^|oMz{pH@Ozy7<FqorTQ zg`T>X9V-0&Rg8OiwB7g2saxbrQ?d$HPx^Ar>u#>VrRj^;9dMiy)B3|LO4e29$gx7k zs&mdA|828=HL{#H{q<b`Ec2TEg%VwFC(g<aQsNG*x0HIPogcb0<EvWMf16)vX|fru zheBrQZJRHCx$~_O&x8m3k6#I`Tpd^Sd#8tRXuvC#rMtSnZNHQ^&HMJ*i@Bu{i|4uB ziL#&R_UGPYvwa&qpKrXjwnbh%w13L{hFjm4DmzBK_?xf4);n&p<>|t&452yxw~riS z^%Xn(;4{myV)YmG;`;M1o^#)n?v|6fU~Az$<#$fM*^W)(<LGioe)htH^X9~>S(jE@ z-cK=3`^zSoS3B46(?t%`x5}Q?-?ysX3H|juApElD-8HGvjoMEg!)otk6wD8oPpeP; zkrURu>sOC;M)hIiWez=lwR1kbnmxO3ZPWd(fP<SJR+$QR_I9U9xkW7ev~t<2&mVbD zZL`e2xr=%3eIwOU?%#DGhu#`Rp7prDDqp$eLZGqnOr@m({bo%&U(VfI`+ZOOx5xb- z=5IFt@VI@u{kMO$Jj>e~qpR}moBQ=cA1{bIzyG)W<elF8`E<@+Dn8H1z;J|xfkB>O zvSEy3eQ(IYyxRsmd%tV*$X4B&^~5Zvue-$8Tz;BFZk1M-)7Fgk*}6N0L{+4}y-!Z6 z_ORM{!&B_%4-dObUHaQgMRN~WnN(@1i6;v-p6hjr^=n=J=r4QW%sEHn*W_HAaa!vt z%eD!YD(QhD=@*@@8HjSn-<NV;nb)JLKB>^=lvBgf<@J1qF9qkWJpA$Psm-%(-7n@u z+10ntIim3(k;&h<-2IxdlA-Ix!ugNZsd`TQV^#mL&Cd3F&$_+!H5D25GSi~MCV%_1 z&bH`63h%1rZqMu+q8>j^e!kX0jC=6|{mYyekA7=ewf$XF*deK=zTPzfif`w2c}>e# z4$$U!z9x0$#64Wg>rY${%3g73;xhhMv)`F5%id{w?Cr<j@n7FtzOT6*F>yg$v+JvN z`&Y~AH)+q@QuArn*_@Zz*Xr`i-oEG;e<d9rde@0@nz<O;wmjB8qvkzZU%k6<mO*cG zS~J&`-s_fy>CWCf`f_jU56E1oIlQ%<A%3ZMq~Mc@e_NQfc%mBD26{_n9!U|io4sph zzT)@aS?hdt1J{@Fc07qI=3LJlbUZm>@9$6iLTnwu=9_;?b=C{yCvt3^{`Tt{HkO(B zl80a2PhidO%gGeAzN+|CF#UJTk;NCRzp$gu7FM{)Tz|p9z+gG~uAf@He~W=Y+xy?z zv+jA@=S)v(*qi(4;E@&8X3m-7n?yKtU;V3oz3A9!pLr?IPR`zLQ}c^)?`_pDmm?DA z8TP!%Shh|6yr|t?xz1zlRpEAWH~(w*1!l{xajs!1Zrr@KK;oC!;>yF9FST=(8=m_< zh3#@A|IGFqwLYg+Q_?<Nv3A=Z{~~R3!k&ihCZ@tpkE_}PeirdwtP)vYY?R+{ao4xp z)<(;z-U3TD_NoMZv~9fewo_C~ck!AFuhcwewHw|#+PKkvnf<@1hIj9Hvg#H_smz=> z%i*BP!wWZJvgUCICRBC1Y?oNcJ?qqp{S2F>16Y|SJI84-F)&Qdjk9NZ$2fUioUBY9 z=!7Ij28R7ipe=+9V893_bC@T`M7lHmVwt>=QGRk|q`>4Wky1>*SSN2}(wHm}B_Q(| ze%ucOgBVx~jJU=&xtCdDa!izf^ey=ISq274s652{m6O|}bfi(YFhUeS<fA5^i_)8X zI!=m7TXORAxB#YGQj;y?HMJO-7#I*+9S|GGATz%p6CnC8N>7%E)|5f)g+O<JzT)KA zXl)tvxnqP0q9&8?8Awjv8?D9k%Wv|_XdM~U!UCj{fdOLMYX8ZGF@`emq{Ya<AOn$y zD%c)4xh}?o>1NR66EUGomBEwcV?&t4LnfET`Y<gGnS40bo5?VAvOt`%2rC;%qbP$Y Ng8>@@!<|qN4*=F<;Q;^u diff --git a/matlab_model/HFS_Wrapper.m b/matlab_model/HFS_Wrapper.m index c10f7f2..8781619 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 GIT binary patch delta 2552 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 delta 2448 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 diff --git a/matlab_model/HFS_config.xml b/matlab_model/HFS_config.xml index c29b31b..1f2ea96 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 2e6a965..4bdc3a0 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 dc3a4be..cbb7639 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 e081bdf..ce95015 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 e655946..d72c9ad 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 11dffb5..b0ba366 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 847152a..1cdd5ad 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 f8bef39..c3be04e 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 0000000..65a5e07 --- /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 0000000..65d997d --- /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 0000000..60a22fe --- /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 0000000..18e4dfc --- /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 6cc114c..b4fffcc 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 b12f9cd..69c6d23 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 e182bcd..0702f02 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 32301e0..ce7ebb6 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 0000000..7521ce7 --- /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 0000000..2e4b853 --- /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 0000000..3fa3fee --- /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 c8b2b7f..727655d 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 0000000..e51b535 --- /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 0000000..87c887f --- /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 -- GitLab