From 79ce6e4e12ce1ea78ddf9d51457469ac52a1d5e8 Mon Sep 17 00:00:00 2001 From: Merlin Unterfinger Date: Fri, 7 Jun 2024 16:46:43 +0200 Subject: [PATCH 1/6] Setup new main application - Command line tool to run the pipeline based on a request config from Excel. - Add generator, which creates the request but does not send it. - Add Excel file for config of IT test. - Add already preprocessed MATSim output files (network, transit schedule and vehicles), which are smaller than the originals and prevent from a really large input deadhead trip matrix. --- .gitignore | 2 +- ...eim-v3.0-25pct.rssched_request_config.xlsx | Bin 0 -> 18214 bytes .../kelheim-v3.0-25pct.output_network.xml.gz | Bin 0 -> 26316 bytes ...m-v3.0-25pct.output_transitSchedule.xml.gz | Bin 0 -> 45027 bytes ...m-v3.0-25pct.output_transitVehicles.xml.gz | Bin 0 -> 1004 bytes src/main/java/ch/sbb/rssched/Application.java | 46 ++++++++++++++++++ .../client/RsschedMatsimRequestGenerator.java | 24 +++++++++ 7 files changed, 71 insertions(+), 1 deletion(-) create mode 100644 integration-test/input/de/kelheim/kelheim-v3.0/25pct/kehlheim-v3.0-25pct.rssched_request_config.xlsx create mode 100644 integration-test/input/de/kelheim/kelheim-v3.0/25pct/kelheim-v3.0-25pct.output_network.xml.gz create mode 100644 integration-test/input/de/kelheim/kelheim-v3.0/25pct/kelheim-v3.0-25pct.output_transitSchedule.xml.gz create mode 100644 integration-test/input/de/kelheim/kelheim-v3.0/25pct/kelheim-v3.0-25pct.output_transitVehicles.xml.gz create mode 100644 src/main/java/ch/sbb/rssched/Application.java create mode 100644 src/main/java/ch/sbb/rssched/client/RsschedMatsimRequestGenerator.java diff --git a/.gitignore b/.gitignore index 61745f7..57f1e0d 100644 --- a/.gitignore +++ b/.gitignore @@ -20,5 +20,5 @@ buildNumber.properties src/main/java/ch/sbb/rssched/local/ # integration test data -integration-test/input/**/*.xml.gz +integration-test/input/**/*events.xml.gz integration-test/output/ diff --git a/integration-test/input/de/kelheim/kelheim-v3.0/25pct/kehlheim-v3.0-25pct.rssched_request_config.xlsx b/integration-test/input/de/kelheim/kelheim-v3.0/25pct/kehlheim-v3.0-25pct.rssched_request_config.xlsx new file mode 100644 index 0000000000000000000000000000000000000000..e778ee0c84f712f19603df69e51cd24b9d3dd80e GIT binary patch literal 18214 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 DL*I1m literal 0 HcmV?d00001 diff --git a/integration-test/input/de/kelheim/kelheim-v3.0/25pct/kelheim-v3.0-25pct.output_network.xml.gz b/integration-test/input/de/kelheim/kelheim-v3.0/25pct/kelheim-v3.0-25pct.output_network.xml.gz new file mode 100644 index 0000000000000000000000000000000000000000..390075616edf7edd97dbe69e054eea0f216af13c GIT binary patch literal 26316 zcmV*WKv};ZiwFP!00000|J8k4vtGGz-Lv&8Xuc1GJJ2qT{E#?#N+lIJ4}MZjBubii zG^3hfBs;%8Yhho3-8^U0`f&JZRF*Y|B-q#hx>w&;|KcD2?T_ER`}2n%fBN=^@4tTU zjD7#^!}q`W;kVy@|NF1s|F3`kFJIO7|M<(F{o?Qc^MC(O|NJli}P-Xi*G)D{PElW{eM4x`01BF`@7S>zWe^0KYsZ7{cnEw z;YUdF&BqV_^TY2x{0PB5{OaF-`uO3G@8A9AyKjE_>Ff9Z=bJx&W4`<5``?>i;g5d* z`}e>6r~mP*|N0L;)!={e^L;(6e)_kcxS_AUdiV81{(1M+S8Xrf|M1&&8~k7IzWwdj z@Bj4i*FS#v{kK2-+F2WYe*f;@zJ6b<*c?qNB~*wh>HWKZ|N4E3J|*$SmQt-0SKhyC zOZ}W{eR5HkeOecdMT)@^l0y!@Y>S5Iiix)7nyd@A7WFoTwrG}ue@t=SOR1%7lG+$U zFwT~g6ZUX#(UjsUX|6dKh#NvJ!EJ&{mTYPWCE!cMTWexdeigKq=uP%DxRQL`zTPCfnd5zH5|iQRlNaDdTdaQtvIA?RHL%U(FQnTuMIi?ktPq z^5XEl6Q9FPNsFtiq&@}<9pik$9nZ1u+m9g`SFx-uJij}O;>=e`vkTVbkV?)`WS6u$ zi+AQTURn;f7WEeIZ7FU0bd#0 zjIzH{T%>4hPLeGCvU`h`u&#+WDyBw<4dX#=$Kcj+SQXFW!rA_cxr}gL^56IxlB|N7Z_C;|*5!w)+IZ4j<4j-RtIr}Oef7&^| zTb$jlOD!&^5$GLUi0W>wS=-H9FO*LP|IhjwbJ;Hx4$>KXVkm|ZZ@tlA#qHb2XEP8o z6+G7D_w7TI;Os-83b?mufT-)D5mMruk}Hz@u1%f9h_4bN9){f8et`W6+Z)BH8z@bf zB3z>5mgbU8$==13-7WhBt#4)1`^n*v)&fPm{PAT`ms2v-xd{*Y*5QZb-Fi^aB`%l% zJL;if_xFUC4|N#*@F1Dy0R4TZT zSOQ1CXwK#IfnP1rnE(^r!#sT2WrHWM%1|iSB;IP;?H09?RKd4KPlrWE$KpJ3htjR{uTuawXDS3`6KjGk^OY3Ru8w-*I?YA7hw zbVDsG`EmVs(3Yz9hzZ6d%P&~kM9 znjYv0hesR?(0=diCA%G(;?NC#5KG|>tv|TU>2n;r_q|JMT z&k94D2;rc2Zryu$nH$~%)WI$-O+S&?ahr(EoJh1#()XmKf!e(?;BTA-@S6C;l6Wfp zWQo@CaqlgfSDVMjQOzF{<1YkS3&5(LxGw3OrSG%7+>?$w|(S&a|<<6qTZr*c&y1+5xo`2Y*>k%4va2KILkj}jLj*9xj8*<0EfV7rFhii83^1os0T zU)+r-&I_B5DL{OGOFQQfHZK?N9(NSh4M?}-1C)mVmkdV-ne)BP2ic5$4A4&yC|1TY z+zy~%ynt3b19bV`A;FxvZS%1R@S}qX0hrvw27xR?|s5Py8VMjXnZNqdF}{qdAJhL zFH(V6@7X(ensL)3KwmHy5ELKL#{JPl|FuvG#P{jm9fe=NX_5fzLnj9gDM0PMdsuAf z<^m9yUA$*S+bw#ui=TIg0A@k0E%vCWWEtKeu7%-qWjiN^_^p8|ghO5L8PU?BBkkck zxUi-zC?HwmVSP`hjj`r<>op7&p<`d z-r@Q0SjQ3&7zua{w%!6|rR2ODl1D{1_~|#K2ZzfV=x1nWobtPi)w#!EV#E22-&R_fBUoI4EnuVYY0JHXs{Cf# z-N$+ijRkl~VUO+*jbr~%g@xAd-lAy>ZNh^ri9vAy-kjyg6yU1DkOHT}alN@{-tMWR zZwF+9KU$ra{Yr@dTcvC(9$dV2r*KP-lvZVAQ1~E$KM%Ff;1<(8uzL3(WKA_~nvbCl zL+y;$?)G@8WzrGb55dNpp-rON-5G~2!9^`NXq)ryI74!4Y!X0qcMm`ly|02w_JC$U zckmK(EQdY;&}V4E*HrG^Q+W8BeP*7_;L->HgWZunEf{o{0B!;q-_rY4oI8*N^gfhc z24E<4KPMa%loYQ6ypwwYLmyW5#GQb5|d2BAWZ=mM@)b8KCTo#b)kN`nH`66cXba#0X-RdyTBmjfY4T8v|vb50$#s!P(Y($)uj9rtcc|?|8s%yVcq-PH3P@5(6=N z1xtXN$75;*JhwimOKDFKRSCvd3uijkT}~J(z|xQ?f2%>bv1TrNxdBWv<2WrQTk8=r zqPb_5h?)0$mlSAscgbLWVVnvh93|Joib6Y?7CO3@b@Fa6UwK$vgm15DGok<0~AFx+As^Q>}1w+@3!O2^%9*d^^ zG1W*=<1IeHUS$Mz1!%#LMXBkQk4seNx1b3S6c**{XJquKT*K1>RK-iRx6*jtFOJ)m zZiUMCxT=YzDyMWST?d9~>@9>*nDHmG-Pg2uwe)e42U5QUAQ=E%%NKAuP3Z%h0`qN&VTcW*Wh`82{N7u2kkGny z1EoGY{OMFHzvoe2=wPY%oLGwI?wRIL_vj9vU?qN}@a0Go;BR0amOrbv;?Gz##Z5mm zglQPmsvYSy+!i@^clkf=4*aJIfpld7Y!aox>XV5 zS%aH4CpT4mJZod6UaI>wWwAQ80aGfsDq^UK>lTP{zDDkRe=nZ{jF7kF0}lwm4CYE0jNUI)%Z^el;N{nQ_K77B zTVxNG7)YNNU+C!V=VWO~6TWu{w{U67ey`aJtW?K)!Xm)6haqM84PYAsoA*#u%6U(X z!)E}drzV8*JK~!7TdiTu7JQ;xF*w5S-6abwT7z2_OO#zh;ZwjA0;odimV4zJSX8!P zDa)alyhs%nGKQo10pN@U1GGB#5D$K<+bV+KI5TL(%9kANktB0K>ktxeBiw_#(Byl~ z-orfn#K_~G(xICRmFFbN;gQmnHgNfYB;vh;%I;JH{g^%l&wKvph6;Ga-tMNvGp3DW z#zWl^G(crwij&yq-qAz3+YLaA<(Gptjtpt-_lZFreCJe%P40n{3}w0HGBdy*@DhBT zB)iQEw$(N`eBzSsX}!I!(!x{*>>XbN678TI9|U?UGFAw5aZ8tEtg$N6D!fgsF|RnK zJrcp_OM&C;7+AZNa)sITKJK;|y2P`?gJJd^Lc%CO<->+SE#7>`0H-) zV#)>zo@L509~B%xYVds%``yC5Ps&v4rt`5ZJTg25c=boqk7F7e`Uz*3Z`l!Gk?oc` z=%j`eJ)^ou$Os-UEP-cVVhi-&Srp#eRv5rQc?L?xrz=N(EK%hrMyKIO+`FZ@)sn3- zZ3_rxVKJZ#vOBahd=kK4!mWEQKJ?L6S^BWjO1wYWbP3G}{&b)khTW6H;L`z!5ZTsy z5!iAxKCnzd`0^RusfSBOrwr~NOl!3F!lh6=@zD)BzWVK$9_EZ!2(+c}aTLO2HFSoA zBcRW+VuQaXFyDP^O+3dfXi_6Hj;w{^@_Q66;N`Q=)#C2myH7Q=DAVDHtkI9U})*NBILYvMq(?kdN6fyv&f}4ZyeNW*t zI&wJTtRsVcf|FPF9@hYW1>l!;M=ssG^w4ly!Q#WJOyJCvwGfc?Q@)rGETfI5KtzUX zX}o9c$xZFdnt-@#XI8?o#W^hYa=lKtXmD`x9df*vAF8lCTS-KLwRJN_Cp zxwRZ-ukSdK$tKcZ#x_$hnO_Akq$!%prT64p$cCUGpPW&Jenf7m01o&^#{ zC^}xlJvnh5w{XeBoW{V&@@AO@UOapp59a}R{|K0Prs7z_M^JocQAbO+yAGb_iN!qr zgvc{vWwyedz?HjmNwH`yTTC~z437Qi?9q`U-CSu%3$07MRi++Dma*xQM>V5z(YgmU zD`6QxB239~_gT5axE>pJ?#13&mhJb#%Eu(#ux3qVNvD8GH8!&E5)Rm2 zXi-@c(c0bPy_^$Fu?u?`;z3E=W{Fli`luds7S8M~!*CD)px6=P%6 ztuGo`0I_eLYLBHhE+6`tt+dR*^V8p|C&rp#kLs~1%uwSo2OE#d6`DbK4LR^u+*@?- zP4Su4?NG+7pFJEWS`d5_XoY$Y>qJ+=QMB}!)(i@@2OOC}AI zxPT>g2hV|)pBeE?X0uy}JeD;^`Z$)kz}(Va3-h3&_YkYw+lOGITAx%)I+nu^7pBXg zuyM!kc@DUN`vV1rXXhX}wPK3LF)^?O-CO_$ZuMkg(R!4DJ*d+MZ_aLKpO_tKHSYL} z_M%E4!AjB)a&m~hrJBhzu=DMBR_D`-1lc{&z$k@*cfz`jdq9s(Sli|w)jP$8)v)cp z;*T54hToRJJYvMS5+rP7gy+^5P2TV55#DGfaUadnxyLW#n!yid^YA@E+19k{lE-i) zz&-Nih`v6i3@R}9yE6>ZAIT+ExZ&vtK*52;k8w#8tCjC98h23kuwoDZxEKyh`j8G! z81cFvJ|4Tpd&(?3@bS1&KyD-(f=S5t9C5(ywaJTay_8l=P`yh#cE+7gWcYwWycvc_ zCE5LrK8OQ4GLu-9fMM}d`u8DbX!83c9=!4Mkoc*w5a%8GK)y{_(2^^aJz${sR!P*ovp z{ML$?Nhb?D9`Gj%yN-_#RIUK|p>ZADk~EW)XhSAB5$B3DiqaD!7VlXKI6U0gd!hm$ zY+Xr@if0FAu6F+(PyyF8v5d&tBd%vzCjl!cf&4tTR`qssaUWLr&e+%%(uTTVNd(T0 zt%LrA%^Ku^uC_PTX+A;yN3m~ENA77SIB~-IQRwJ1&sZg|0SziJ!7ap-N!75uQ)nzh zF99$1u+M-GjLSM^Jkvd+57oK5xQj0fc*nN1J(I~>%lfF+nt#t5%}Xlm-xjiB2Ap8r z;E(#F5-QOdCyytv^vy-f)|K_RdcBaBXTH`gJ*FX%Wu1A;5IrowQP@rJ(5li<(m{pD z0J*`X2OKFio+J9q#j%hr-Ag_+CZs(#N)jYI1zS(~X3u;pLA8~8Rm!349iA+O@~xfE zGj_kfduY%IY$+_XY%b;Ni}FrB*wexH+G>_)hgnQc4ejhfhDUa6gTwcvh`A#tGqigh z6#gN17kS^psojMbid9Ut+$-8)hH|HJc~HSt%x>ofdK9ZF>)JMN)C%qr)iRX*DO|*8 zBs89D#6x#fGZX4||DKQG?2B-mwn9bHzyRk)96S*3IqnV+5b5H2e+QPuC7=FK^q3ZE zyVcb5ZPFy=7>`0qfl&QKx^m7j3kT9D@F^a1pF&G14Qz?z8{rmJUfQ_}*<2 zzFVvM!`s|x;8+(Ej0nru?5)q);!B&)$gM-pm`QwIUJkI0cDT&9)McI#`spTaA(bfuFD;VC+TnYx%v^GF>H?#KDN~cUy$^vbUBxudBV~Up zC&2j99>}vL7+iedCvsZsP&u;vgRqvt$2)75oi+Vo8C$Hm_a8l~HJt4nJG(oZxDz20 zDU1&4U>q3hk&9!v_12n4$(JQnDEs(xW*Yp6;QDqOGT!bj*Q5BoX8vL1l<+me9ve!m z6%@c>E`JK*k*F(@cJN-=4nB0 zo2cj-2Mm08Y<5?kP;`vxlA#N>=+>IYBZ7Xc479Q1IvrtFrk~h|XKTIJDN(K4?c1X! z16AwyyxOB62y4Yptc;9PF~#ZPUX4ix2w~Gy8^?18f{-*~3*J47tEA-$*YC-GI6!s> zB=7xE-iqU@WH4cA#;t~EmWS?+c3A47^(MniHFVrr^L$5n;`#0c{f}z2q))l? zYDBWqIWmah>6|#yp#xar>Tmsh$OWzs1ak0!pp|52<7CB{WrQ)8n~4=+x^yqZ zWPdpuIXEKa=(&N12{>!vZrm$vl^xAKtb7LY?7S}z%KAccZ;@rkNiGH!jA=S|3Il(>+> z9_RrcU3pn2ZENoQB-mXf7<8m(Ir<=(@?b4Dux@&dCU{#jZ&`Vk9|p#FVLFpN3dSsJ z5`f|HhU_a`^ZT0X8%h#^;tWI4f3|c2g2&J$O=nW z4+qAP389iUH@+6G*w@^{{ZMBxL@^M~pR!%Vi%=hY1ND_IlYPy7{7J^vVH#j<4`%~@ zJiF5w^IC|VQa(QEpdEg1vowxmATi-`sahOJAw|lnif!hxq&%m*iP1bQP zH`bJOu)qUfy0?2wnzWMeQ#^}B;!fO6xJZ5;_CaL#GE&&q^jnZWkS)*vfVV#4qYZ>O z1{xrt_0jU)i0d4T2 zr@RgLgsmjSMRRM4dnKT@t+^+m8IEqXP^6)WN8vg>OhbkjyA$){I9A?m^~g8FRoT zS*^m(^AN}nc+gNVun3)O>B+y6+1i&Z50`Rd0k)*QZ`KH!Y6G4m94)LBgenM4)4sl< zD-X6CeoGNPPR5-Z>0yS*?~O^10^5EcWBNF~5jNJo$34g3{SMzbzsP#uxUr7xOCzam z8kJTN#>OZ2M-Y7)AjmHkT7eDSTfJ_Yh{>UWv+WOK#Ae!m%$B zyUW3D-F=KcGZ4gC#?HM`ud^;$);6@v_tQ9;SB9^wONPCCT!duYWWmH6-@931e+%b? zkheR&Ql_#l8RMgo=03=VO|^|28it7FUwh3PlX`eNk<40mK4nVltWtJB3OUm}dp37I zsX%^zvQyg^DN8 zg_$BJ(x22=_l?_>#W3V&Uu`m9mketx|8cmDB^m4S;F)maRKO)3?=i8khPfM-tlV32 z4Zo%msTW)32QKsWAOo#0d{oD2Yp*p1ZcA>dt4Ar|yjG$;D$a3Ei9ATJE#*N=co_GX z4f*V`ItVE7E@P`Lz!$w^8KDO4gB9gMQvXn6dki>z)Q8;b2Og(_N?fZ(9%mqk{2smW zx|y*|5<0{2rZJ?wc!23d)?l|WQu&o>D$A14e*Up9vAV6}dFe1KkvT!3Jd<-FTVTs`+xoE-EY46)1N;4`0Wo6+PZ(R_8*9~KK$-?AAa-k+dqH! z&4=&4`{~>N_W|;obo%*s-+ce!FW>(5;~&0$k4v21H>tVcwtJi>4esxL{NazMobT33 z@$m=chu?kp{`XvvHD~;jA3pr_rw<<}m%%%LoZtNB+mHBW92jle?}6Zdq$EG#hy3>+ zAk;Vf9q-@$k>8Df$@WDloGN9$NV!dx@1)#*_=Th_cco0Nk9d=kGzZce^Bn7zQztR| z)qF~DLLJ)!3+s!fZJ;U}SY+)tuui<(HULAw!T`>8_iPQLi+0+Ai>CD+uyc~dTxI4N z$aM>=wEY&=5qsMfylq_G1$x9Xm+$*66bGe1hI(IGGw#Ggi1xaJRoMPTE`1-z1|nkd|7yB(}0le;D*UrtJ_gJSDm zNaGubEkDIVE8MTC8%UQ8tg;SjXz2*sUonfhD@#x!{e3&UVwVjWo2+9*oX-Eu9Vj+; zmA1b`>%gT$5m~YnvPqWAjji5!JcQatkJggf;IwHwxZ2}Q*j|&aoGynsg9yTE$yC@u zIvTUcu2jxgNn}U&6E|?R$D6Ff1{MyH{Rj$a{os?qA;<*QgC?@1y9AW2j6bH zPS>N_ue~mUzXtaON=is=VP{%{q}bzC*j^X0DExE=o(+k@8AOa|hT#$k+shLh>I)mn z>E=z_z||gavUVF-y8`!T>_{LWk#@u3sirbMWT;RtjM|b}XQnPqSA)C?+pE%b-qOAU zCehi}A4>y9y*fISfQ>=+0ek@4{ZN0Qh< zlLB;;kI&vcH1X6~+#7m&sT>STmnZ>w(RMW6(mY6`r<( zt36(Y9Xx|&sMNLtvJ6Y(+oXTyh7EA~3Y;3B$fyoSqs)^(U#;;bYqx=w!C;fWq(Ukr zSb|(rZlu)x0kGL9;Bi;R6ek+vd^N_asAIUTaikoOv~ly3)PuP|Uq@563=73Cwy~TO z#!39hc`mr?F%OPeG0P*U7EnXnO!=?2 zcoDUK0=9M;fyf#SVT=!+4b$uwFh{-{EN)99Bbz3@5~p58?O%XvOk2Ahjx3NPL1^&o zKpudEkkON)7^IL;W+t32iXmQP9YPc39N!9#6u#uguq2@@7c5#xLX3T}>^aFqAW;;r zc#*Z2Kb`eYgs zQLa{alXgfGEMvQNZve`j0}V2noZ&n6@kJ80wiy7p(GxnD_GKEBlbz;J=C_(B~)^P)|OBx48PjVy?G^qx18LtuRn-Uor z@qcZ4+^j9st2y4J9T4?0jrGu{wPl7`=tM4tVF&PdIP_SOV<%6X8K$mRgS-hlgcw5? zrsg|1E(2wV`jRhDtY5o*ug0GNxzg?7?qlL58!G0Gf;kY z+6FYEtfc(5`8?-7>U=mu#0v@Wd@BMtPOC_i7eCwNnXBG6nC2 z{YRYVFeGaVEBOZq+fsbWy+lD)#z$6a*nL)(lMEJos4oa>>gw9 zdTGBrZ3l|YU8NmtZX?z>Rj9DelJlGygOgzgWM&GINej;@8!|H=Q#F&@gdNU6lAJ8A zXHG1T`JajTArs)~yGu*!Fdb%Pru>TgyUIFb#A56U`kn@>v-cl9{wdeC+M2SVO!Vb~&rDf{rTu4zO(W|UOJ_!ziyY0pkwc(f8KJIex zG86QO;svkL4te1rj6%rFc`c;U8f;nM0Lj{VEqroeW)woSr0^vO>TL>r7|XGyxNh zp{rATC7stA!D3-KZ)S{cBA{+o{<4K|tyA0vZ9H2_HCn~-U1jYyurf*?S#9r4SjeMs zM}i%yT{%Q4w(;}gIof&R2CjB^m9;N!S{NzM72kz}M;!+c*|D;Q#m1!0f`&?UvD4G! zzZ&9I)&a^%8`E@zuf)I-3&$6ciR}`;5_Zk_R(RkiCX}L8Oz|q~@B)_kHOC8Jn3IIH z!#RyHwl14^~@D(e^m_2)1&2d+2(HODg05>pRFSxH^Um0^r_m%1S09upkTkA-BqnG5O_=zC-PIDWqV_K!mo{DD2&=TQ zQn+gta>86)tbp^SF6qjc%0w_7-PICr(hiT9^g5>!%jgUn_DM4x{NRoSD50E68&Tp| zS1?h2#SpKe4o6_+T+~sEB^3Z55z$V#f;p16d&VVFm{{ExonnO-QHK|7+pw171;CpO zZER3z?J*ZDS2@onkvW_vF%d^NrBHg6cF>~Bw7T64aQbH^fd&U-q&!;T!cm?X{fizCU z!m$83rm>IM0nf2R8j6DR!zU&QqF1c(Dr}$2^Sw2oF0F-Mn61t(g%M9!h7{q_WS3=P zo+^wtHO)#0o6R;wKJ>ux_G7_KHPbg&ksyq|Uxg zX#mU`qc4HeM?+|X7^m$(=_Fo-9bPhU@;PHn)QrIDkbfDa`!j-hEAP<-Q6))(uWXuu3dv}O`6 z4xSA_9RR5?dMc!wooEVzQlF)j){G?w`0T7`mB7}S5-*7k_@*4bTUoBy1~X3EfEJ`C zBEE##mmhwS+LWl#8EH}u1vE@l5IK|2nzOft{;J$KuQ;xeWn^JuRz3!WxAu(=-X~=O1M0-wrD-2QK zb0nK4>dK%PTje4l!tIP)U>>PFW~2RnOlv zwChaMBL*F!p_zts7N<4Fa9RGDJexBB7iPwA75=PM)W3})+^EoJslk(xYk|dm2G`%U zku28vv9-{&QUV?hF567*pr{aNsZ0e!k25O?@CGctzrqs|ji``dZPE^R!8WS@{X6qR+rpXBahWSQq@^>SV20lc*R0HR zT{RM{Ro2n-OJ{W$Nkir%Q`pr@Eu&51G$OJzZ3Dn&PD?d7-P&NX5T0$S2$ zW((sp1kg-y02bIAYfL6~r$vSTY7=zid+_lby&-Q7x!`J*y~O6shDfZIvdguEB|bQ9 z2U;9?5q6AW=CiqSh0Hl@>|sHF9Z)4MP-Kl00BXfq%!D)={naY#%dvc5vS=BnrmST_?|x zkeHo~dJ}7!qr!5vN!!EU*zJG}?}jirlACYsZ8+?6K$>K{_#ca6xwl*+j?Y)Xp~N30OoTq^91jd>#Vb5zK! zR#E$6a^Kv-Lj^Gd0r5EJ#`@Gh0p(YxiGQ`gtEfZR!H07nKBoj2=qg}q7T(rD{{y}; zBmsO83LeS42xe9SP@AkTZs1L!T2=y3s+7USuGG=PD`^n}K!qs94oF7~#~A`Gw~!ib6#xZRA1&A z>M*E)BU4I%sjaRJ<(kMQS(L&GA8fud5DlT7r?Iw0t4v5tguG&`aCO+~?O=&md@#NN zmhG^L*0VQfBHAoUVS=VB=>fZQaZz0hTfE0Pq~gan3{Q&#Yw*BhnCR9Ptz==9b%;!* za?Un*HkW0l+c;Vi7JE$haONYk(UJ3ZC;E#;t65lu9U}SuOnU=I*Ra6RJ6!*vG|DGh zt4eZt`dV>f<5p4f{p|d_6e|yjh>$tqT%zUo6e-&#DrZl+K7SNhs?M$i7l?etP))JiPlz> zg6d7!OL;;^mr)9Puq3fe)Tf~$yi~)2T6U4*5N4K#h*D9#%G!rUs1ds+T{7Tj{1}L# z4vuZ|&_mIBMk%Vd^Fkw{6jQH~j;Ta@Ry58QhVh}w*@Lz8U!5-yJQFD{yILaS%=0v* zXtmUaUd#OxuD2nOA8qygg^%7KZ@e zkeY_1mvN|s1(t&n=1^NpmnKi-I1{CqdJ}eFEg_TEc?TQ@424yR+tOI&MFKb9sNUeN zxrwE)q7_rGvJOX(`}zdN^ zj0){&%6dZckYur@jR?i@*y639$k!l>-?9nY$JqKb7h4n) zBypuc9gnQ@g&r8oq4;kH9S&47lyr!Ok9wxsaY6pZ&c7)>=F@D98$P#Fn$39m>F5c>0CB09|6U)U# z8(O?d`=V3eIJdhpR>v;I%XGVBv9g2b&H&5AhI>&8uGIkCvnGo~skl~?MPtGdmKK-D zCR$tU!3`yP9JiBLzX!y`c-X`%q?KH28OI^v`z#q#QR=O=jPH|{hKV+=m;{#BatGUy zNWN|GM4L&hNy#y8=b6NCxJ+>YdZx{D82y&(uTI;5lG9pc9T;D8K2u#r`0fdy9v9h0 z#?gkVk_gDja`y=2#zw@MXQ0^IRoXt%2^e>>Rv~gmV8uON2zvTZE$i|V;gGk&irR@2 z5JfA;USu8I7MssqtlkAY$6R4{YsqW^x_DkBiez>aFV)VBU@7I;o3uk>UCMc4MIcF1 z0XQb7SRK#6lNdvo)y*Z*3!eE76z_KxcFcI$j(fUz>PrGkX!~n*6>xQBv^+ueW}xVa zxKpXe-lQE40YLwpI4#w%^qiqu=1#}FDY1^l-k6%4*`Fd>Irb{+kh!kmJTwG1oEO&Y?p~CG}yoZsHMWLy1>m$EyBt9-hNtrtn-MK>z9+@)Ac*&AwL=7G~HdNX){;rAgYh_~g0{a_T`I$PnK;2iV z93~rG7*a-;Uz{er(&4m9I< zhTL4Cl?bdyRg_|A2|q{vp^2$&rD%H-cJvG+bWtEy`oP{=)+voK2%G`bkYxuR=PS=7 zh!L%9dlhzo)isxnyR(rb6$t4$Ua3EV9B>2~rkJCbT%I_~LbR&wRn`FzwP4#RArlNI zuEMNYdcnOl$WTSD@tU}@Dz<4GPz>@SYwsL){MnhMdZkueHIiu!scn){L>f8hvqWP( zQF_G|U)i%sDR-vWl0eoNMozGUYgX7BPaVo)RtTSGim#aBRo1b;E}ipXjE@^nhO^cp z=*LM4Vt9nofJT-&Qw1r3=vCMe4aL&OabKz}fKMi@e}hE{FaQw9@n(vGZ`jq3YU z-T^?DoClL)&BWjOIB?cf~Sjx^FqFszR&{6AdwG$xgB0FC*T z(~0Xu5@gY46R*M!O<=jR2aRv8q{K*RBzx)rhzigWgA-&~f@+wU)lh~LZ^Dje&>rND zNf}5id^27Eo<}P1Xrd1sdRp0cU1tWXmEpvjussV-DCaV#%+bB%DHkWKw7I0k@Iox! z01#ubQ$s|`XyR4YF-jW46GrH?vBZn0V+&h6^M*JNlM7wR$wF*8AINKACp^1r3q5C< z*n=m^RN_t6!4?!bSNcK20}%z=*jeg2YO#w>2&2#6#>vBR$Zn=*ppGS8r0vu5EUWDLOHym+ z$B`A7glm+maPW0$fk-zqM5K%*US%EQEA<>_gg0+mQ7$iH^y5qgYkXuyb!5#ntnx%f zstzSygdJ>|@7QxVQ-Kugma(|t+@)BKv%d=5gXBqCF!LoVzVRyTi!}!DfQ(pp?w)Mf zWvFu^D`w^xKe8jk=1t^a5~bBptrNQR^*>9ao+wj`^{(=vsW!CnIzV)|=5Qc~aye(B zV+hq1`pD7F%-U#Ei#1$5x(07ssiMp#*4n8C_LH}jQ5iq1_veot;>BhIr3VL*119~I zDK#d`xx>OC*V9yDv}&}_=Xgn6klXB(KW&K%Tvu{5le&AT-!|2BRQOoLPB)_ zN6t=m?$QcV7>!OWMX`VeGmqe^5LaObrq_j*_b6v_tfYZ63>`r{foUw`-|OfICITgOk4vH227K=NU5c{+ZXpU04))sP};z=RG$>qFb3YW5TerSw} zhFz-C`ZuZ9C(5t!IV`dcO*!^lXbyF1d=ys&R*i$k25^r@3d0+HDH11Y8n5)0u9A+S zf^!xWN*rH5l?3@1FBn38!ml4~@~l}}ijAkquhjEIB?(Gi?{jTuWq)#H2P1xE93kW2 zT)8Nf8Ajo}^J#&C=#}2mP1vCzN%Gmf^##V3bUrzA9C5iYb0xBY<6$sM=j_B6pmdjR z!VanQA{{9XsnvziRtO`P{$9?L#|y^$u1u2VX#q3rKM_-w7Dl77fnpIh{GAkyQwbI#g`Fa`h&VOk0( zdZoW~ll3JYL&hv&tAIB`3N;Op?_yY1$Wj4(j2x%lp{pTYNuY+J9+5M!hmke-8L%=y zQ_4fcl0D*H$V3ejhd(*f5NI_$i>xnEL-|@cJhDPtdWbkoWEUd|U!8d$a@|dpUr8aV z!ykqRz@d2=hO7;Y!8;i17*eXt;HHXuSHncSskN4B58y&^_~Hu&<|mDg6$%eUI|>1dHiV6EB&RLutV+#5HEFxfR2~r zlvl^>$rvbX1^}*3;(z897h(rm@984!@C>3mn=;n(ctE;bY~&`~2uL$)FoZ|N0f7_Y zgf`J<752p)ysh7*^p~nqde&Q?FACJXb!~cBYi}Gc3X3DzCN6l^cHZ!?=#~D`Rn}L5 zKdv&KA}p?x%al~h5&%w{X2HT#b*W6xQ&Lx#IWsvY19OWFl$fFnHAiHqbB>?^OO-Hh zau^vywY1Q6&dgwNAsbLxX%Df8xB(_6+1WU9A!OL$il0|n<*CY22~ugQ1`cAVr#n<) z;V@l#=b4kghlZTQtcp+x0nW)h>gnh;QsGtBkv`t`H9PRnIU6tIB{LOShDVTiI_z*` znfb)jqE}i=H(|$Gh1|8d3m!q@tSC4+F2;)*B5yW_tHFyaaURbecAzpkWGw*Ed0u1* z1TcdoisWaK5%dI4qS%_rKQ@nADSEZHR51f&6ga(sw79nnl(O=4&_ao9Gw_RDBI8Dy z*UAF<71wu_b;#|yHrnXv;&0lppH8-S12 z4??cqFi?*BV>y1WjLuhK!4aqM;tlwjs8j1MU4#60%LdV}X7 ztRPP*h2UnYQf(3taPY-{EGgJ-8g(lICZ8dEuQEguh4~7ACVUEDrZ_VKq;!{VvJQwe z*fU95&SD@sfsv39WQ?G+s#N?Mdjls9(M)ZDlv&9#kDeM^P-%yi$z#CA z=Mq|A2!qcHYaCrAup2EJ3(OaeE^o_BRHt;8Zo&>b2>!eS*jWy3$uP+{NYVig4*@!q zMTL%p@5#=*Mv6^dg&nRDOTdmDz(|p$%MzNyHjnKTVq$+&~ko*8k>0MS*jkOl?94Eq3tzc{wcI0g7Cb7bCF)Xvj9wI%pfh-Wn z8ZQ}ccEx)Jc$(Ld5WUuBsxdw+6K{_Sh-%>8vqv`3w;3)G3$ZpRe+}P#Z15L7h{Y1C!aim9Wf}a06(G{LdK&HS-lH<=d;Q zgM(Sm^WlKjOpdLO6R^k+4CoaXsFLR)&~L~SizdC&UAl_ew?sL2_6kxZ2Op!Pff*3# zdqIK$6orCv3Z}CNT&efsLjC?4S zh=iWApU7Dhz1CT}$U3}Xl1ZJN$_z6gEW{x<)Ho^Hu?h`90*HjOENAA+l+Myk*lS7j zIa^bbX$0*tdMPq+7Wr%#mJl-cF~BvCCLwyIwR979WCHbFj1f*H=denvq#4@47-9s} zzyk)BixVjXqgNYC>&2^gbR17tC`Zzr;3?w)unuVG%Jg^ww%~zfPNEI-W*Bhxo&rUe z(IEqxUVivxGV@CBs4AsrhDDz8J1eDFtFS|p2+-G4-gIr|&LZm&|B2_(Q_rJnl%CU7 z))8}dKG)02K1BnQO%_DXm-BWWDGoNEB!(AZhhzqv5BrSvR+LeptFWWCly2n9%aBL= zY^8E2h5YwGonsW?Cm0I?>Jg_#+*+B`sHeFS5b!uZeNV(GH!XvwkB&^6Vh;j zs)=MIimYDAtcsqv10@JulxoD!a^17Z9-DGjILFV;^xWm96tb8AL@YcYRvmqJ|G`T*f$&U+gjT|nrjy_}Gw*NH2+m%9P z^ct^y`*?_<>uv*(5aAuk6&oIs7!@eVImWay^lY41*wN~ME?|0*b?A&)O6`y6TV)+z zCbxfx+1s(IfYf>k@3`6;%S7gcU^Rk6r7z%`2E#3BJTeK^%#Ux_v22L#SJpOHVVd|? zBdjFBM#gZC9%N^26jp;qH?$YF*@KZxOF8=}bHBerZm7|>kU;ia=gP(yR)P99@yIKQ zyx9CP4swtZral724vRwmPhfo3Lm`DXpgjh9hBhiY~Ii%#B7sJo_mFlmQtUC)#1B zxWlWkFXix3qN3+pDJ)gDBa-%^_za{}I9X!e*uK~b9|!q!igvs~>(9PO+^sb(+>nvr z;XEZM7n-V+E%0zC){XvR0tWK2O&f>Snn?H%oSNv3mpMTxfDM9EB`sgnO z8@9AkeY))Q94GGJYHL?vhqz(zXIgduc|#&?Poh-uLl?8pWMwaW#vEVi=kfk=vZoR_ zT!bAfP8$EC8z2UhqapryV8+eS%Y5 zUe#Y&=kDyPG6d6Vl^l7j!r-nXI%BNpW6gt|ScTr4+iOG5bwp6_t)T6-KPGj%^syfl-KV3fvOvAYrz8umtdk z3#kwbr|Zu2dKF%*P1vzPzMSJe)h5G9;*KQF7Y;!&HpL2r7dQqi&J3Gq%vh_eW8v+2 zJdMkoNdQ|0x4^?W52HiFmOPvS$s(+sH#rv@xZ2`X*5M5^NOJB6vqm6BWanC~GRn_j z6_s>i+n=8Zr4?qZP1cdxuCoIiLrHRE8;cG3(!s#6R!L+lt)$|ZX^S;xtX0@c2Kd|^ z%q*EwllWX6Dmj>fXUQR) zodm1mWMbq;;l)zx_Mqx*S9=?y$&EUyR=kLT^tPDH=qK(XC-J5*5s)gpSevjf*6p#P z&{!gc%4~ZYE)mmsxORm+BaOFr;tsTeEX^kyoPxIvUn%@ox|Es2e9ra?h`|au>e!?= zP9uZ80uF*#pIsr@#YD`YF<`C2zT`W?oiZ7!va%osR&_)SK>YL@1AbX%R+$Hd082@A zjgA-ajDd`qh?=bNxY<`#h0c7`V#z+NjP znyz)gzbxY9UB;tKFs>787owIpUxgh53F&+W0ZP-bcqy06S&eCUkT&CL`6L`eTqhQB zMkRH=$vTwpcz?E>_!mQFC5|D2qu~bhf*trm8hkR(l!*X7YN_*8)*+URb2;B3j=FV# zX)ZBloJz0KJ>#)~{jc;hvz<2%3R_SD39GaNlYHq0(*fWZ#(ZKHHYi?s(mbnFGx@Li z-!oN_!ZWrAJLFUV0?t!Pp=Atfz-%G|rW-10T{ZLr=nq?V2Tpy+N-SZOwm*YX&g?P{ z8rN{LC+jrx#{#u0ctg2Ks}5n9%UiBxY<%b%~(4vZ84 zS!YfS%VERtV>uSQglaEw{lu&y{Hx>>nFA+oK_ePlq#fc>_|PY1DltIev)qRz?^jP2 zIHQI(jM&+UH5gGzuWzFEuNe3F+&xr^Ay2!7oH2}rU_P)AERznA?LB#7OgSp)^;Omv zt6-p660Z>8Xo|Q-11U)4U_hT?BH*MrJ8$ZFj7oN0uVfqQQQOFHd}PMHeX&CoNisOv zLPwL;5_uvcNK~@xs*CGemGij}$wAo{&c<|ntOGx9WHUI!vX(izm}Wi#C9J;+I~>6> zEbs^kX2V)k)-X__@eXnHt@zNYJ)vo5o`FU)rZ7^B#4=DW#Z=&;Lh90y@UR#k+Jsw< z`D78w#0@BMeT^Ur>N1qu&v^0S>8QiAAuGbfBT#betFS|fK&ag~zNgWoN|JpOcC7Ph zU2@N6%9I@YChFkVI4AKonqavt8Ci2HB=B~kDNvH^o3I1>Fm8ft?>O7~ ze5hJWvah1{={Y#V`L0(JGmEmT^TN&qnW;yW6#FXb5M2SB2v6x(DmnH|+QBc&{yebY z73bc2Ksui|pqJ%1GBG<8wKV%G?a=58lT>a;Sn!UemKvoHnBq6hR7FbEf0cGHXI8rT zLC+H9Qu6GZtOFuq@zmWoBhW^hK}CKd@zqYOT8&DgeG_(Y@U!j6L0*pa1~Ca2t$G#~ zmzgBWQ5!TZ@%F-^x7ccxB7B>PWw%kuw5#KfM%TtkBC8}^v|OBbYsS9o zQ}d}6(%_MoiIYL2HiJrYZN@C=^EhW(s$F%?hBJ8E)RH!5N~HuGIvPVL#J}?4xrc5P#VUOkBP-$0NEU-HS?+~ zMdqulV^Kyo>BxEJ+A~|jJ=CIvF_MA@S`xO$F~k!o4WpK6*G$%^@ZsgaiD&5)yDcP- zts;Si{)J;bivYPzlE{3%sz2h4N9GHKpcP z$L!?u9D(KqD<+E*kx~~;%!D?f0yDH6-UvMl(_*A+XY1k2XQ0fQT7`YF*Mfl*@+`4) z5dsbT6!31iMM^5nbI&}1tI5Un2ui7Zv}ZjO;rVi&cwk3SszYpkxv!;g<-gCcp0%fk#IfI2o?w5bv` z!%v>M1Eun9m3AmxDk+|4nUUuim&XegO^E}~v(F~8%qAsx@eBF;v>hlN)~m2Xxe!C= z=e{-UAmFB0o&{F-RI9X?VwHikE?c1g$_};YE(K38ag~-m zzzR;}DvH`9D!GmePS$4z|#n6c5LW|8V=ZWuF8AY`TI|Q?=EnP4R_rwC!*2>(1AG!x~Homab z1Go;W%>)$6Fse=1!GjccMilr>-elI`!qFvtU>ubx$6@3`Iu+NN3#aWs^MMy(`%eAR zK_Zv{Z%A2Wff*u0|NSk3v5Tzsi#5Qa$xMr^45JF17;;H2tv~!SUc54JN|iE|#{KY& z-}!2FS7FB-ST}p{iLSbm2wsI9D_nC&k0urvKXI;mB6s<~i&Fr6pfA~nEgp7x;trI7 zQ=70uYefm?6j-ti_qbMr%ZgWv#e!GtWRP zlwO1#p<6mDBgXal5FEQ4NC%rnWyI+p(B8*(b{ko-r1o%$wST z9V!$9>N4k{co+^2pdKmyNlas{aQrCgqNa7dC*RK>{OJ!r{P^+Ll27uVfAj@# z8zk(e5G>+2A5WCX-Os*=j6GS{B2PIbS580qGV*oxYl}2Frty@QAAKPS{YAo1PkeXh zAAK1KJ1=MbU|BBTFv}PFhMj-#>6g;`H~6C71Ts62mUM9Bp-USxJj)^Y1*UO_Q+m0+ zp|f+d{-~b$GRX!DT?u8G=-do-(v4Liabz}$W8tOE)1x6@U)UmQucTbpxd$s8O~}ka z0Z`O|K!@|nV~dCtz#(aTJk!L#DzH`7PJXzL=dWM0H5F%MfjWW=9A2K@0#Oi9UMdU} zO%(sCJr+?16Oqql5Hziv=WPQV193@uBpPt{9bB;#1J0(@X+VhbYc?*Qs_d7aaZ2mC zk|wkGGsJ}kF{J?q1;A{cVN909+cU+F7x5QS`^!_yxz#GL3Z?Q@5{c%aIKrAjS`-)B zaMx+1EfhXo?@p7n7e3c>9s{V89g%e8(>`bDTvlw^8Q>g8U&yp10HwcLrA5@)H@Wr(2!mKg^QR0)<-PN&V=q4Za4yNKF< z`fgZ|=b#Qt%0nv6Ix@7wZ4vT^+iY7vaayA`#4lHK+YJj^e^f$0=QnePDeP@wH^yLX zi?L2fyn$bx7el1%ip$jm?PT|jg!>3xk!sJ;p(Vq19%L5|zaZAhmGvoMBG4&UQ@e;d z0G(Fbclf&!4PXMtSc{B>x52|wB~pVkNL{84>8A9GpbP2IQ2=q)^OcqZ<=})7nru2%j zy@siv+tW?Ywhd*ngm`vq zU%?4JHA0sHUGIV5S`F+p@vpXak@ar?C)BH@)o_A6_dC9V6SA>@&*aT2z^`p;KKaLaVu2&CRzzJm>&@uDgUoCAuQ(m2a^kt%b^=eEN34=}k85MfHTGK_;!J4)a zxc96ni=1=e7%x@{ct6pYR?V0;Q3n{A&lHz0Lm7vYfk|@}ha~I^pDDi*DPClK0S3PY zB;nas{7^{zm*}BSl>cf{6&#E$ok=xbhVd+5kT$_Idzaa!IZu4K8r4iKTB%1XSMxwW_bvIJWFD{r?mZKUcV1KJxlPWr?dTJOCKe!ETmpvSgb(n5gr69@|dVzX>0!XR-aX zk2M5vo+VY%Q`mkw)AOW0R!?C2NyN|>ggi@0MNeP*$$F5_LkxkmB)B;?aV%Dui8iBB z&Z(99b>))yVhwf@ULkMK%7`SRtT6{fkXu~m>x zUq1XK`N5u{_LHU0ut^YJOuO&%)vsEIZb>el)T6~z%+jb3XDVJy<2zg2W4j) zY%N}i6TksKhSi+O6*ngcemU1X6DlZu3#+ih^$FdyHs@_Hc%VWbipF((z7|-UIIdMi z&D5M;sfb#H9cqgD&I{@iXUFMRFvT?AE^av(*LoFM?M@ zA0SMdSd@HENP8Bw500G4wD2AinIjld1DYJjfZ4kjIPR5%c~0uYaDLB4dy;hQDmzo~ zaN>l4*j^+>KN6r)dS5aLH1K3oovAj}Rv&u-JieS=lw3JZmop+QeD5?80SBl}PHD&W z@f`g6NUW3~L~ zi&S*=JhPvau+bYmBNPitz<81MufSqrBJX^GIweK>{-;mBGdDBZ5chS>?eJ2GArG8!I?&>-g8uRN?~Sk zMb9aFmi2GM1CLj$s(Ij_r}wJ?RLdN0LgMi_vC_Mzl>KD3i|2hSkD$&Y|hSnmq{_IN(Ovk7=5~rpRP7_k@TeZ9(5(7^YT348y zu6cnzBlA2-4TZ-^$;b>Ln5W4nDKt(>Hf(T&o+yH((l{v*up!3yq9bPwK0(FCIGoYB zi7H=VaZK-AHb1DFr_HOhltF zIjzFJREY9&B}cGuvLn?JUj~fYM5V8gIjMyx)t}JhD|Ivg^PHr?(Y(10LzpPO)}rGt z4c}cA)+<#^j@?H#FdqpwMeIaCsnI!Ii?BKd(kCh*Q`nrY^r@di?omu&>KmWmyAr3~ z8;#A$<%=WY&b%sb3*{BYCPhL=^7#`}KyKmx0DJGN43(WEY|6Ek2*o3~KQo2b2%GFB zT`etnc4&1rs&L$Nrd}K<#zQhSC(8misQolG44@D;Eus#E4rl4!M)y-$Z+=5H>BM{%!bx z8e`KH%lBo4PXy%^(k890@HvsZLfWJi67)s2PXy%^)+V*6_Gz)aLfxdmvA*&0H9Q8b zntUTQ<=opavnF2QZqgXb&S>&!5_$@8(-liTZ8L>J>ZBu(lI_o{8?}_`)y*FIZJwuJMWb#~`fWbT(SE~rA&t68Yb*YooY@<;6)V(DT4(EL zsmEl*k}wO}J+%qg6UDz}SNjmt%Xf#fc7Q2!jm0JwVb8ofSF@^wn4Y%NOkr%J^l%X@F z*II6_bD2IT!2NbSJV_yNQkp(Kr?npTEZgXFp>~R;%+vWvp>I-k{^#`*guDi<8FTr1T|ZIah-`Ov&D_VOgU!`Hd?SRJ!tuwLOASonGtE@wq(x25Lw6;lJN+NMxUgx@=<(H75TLM8r zj58mn!qc?K`a)JVR`I6bRa)rnl>ER>=1mP*l5px9+4&|4ueh;FS`(My+z;|BY0acC zHEDdHL;v~H&}1crtx4-Y|GZg~Bmi(OI(V?zhL~p}GKH^6>1ydA&GUc)g|10~G@mm< z>J2$TlSbC0zTFz!Gd^C0t!b6@Z=xt6X>3hOf$ryJuimcJGTkI=`n($5w`+Ax3R{!L z_VqatSQ4vv@g&KJF~wFhGEICnf~=60eW{kNq%bmR5`NbEbkOcLXEJ~W==PcXC`ln@ zQkq?>`;4}(U?Q|j4%IqeV8G^O*OJ1@w1_$oNPNa?ZxYuVR)1t^EC!|`RTl-joQcE~ zLME-o(gz>zdZ~^@W-M@mH<0N_&J<#nv3LVo@Q}aTZ&D$aZg>y-f@M#f&Ldc}Bz4gpAZ~TGp&A!1KyFdHpjfh>6Lb|lb z`5z~CdAs4FSqadUR)jLpj@+Ld1B*}kzY=LUW6l$~fwN-ql^VAm>OM=2TULxF{NJj? z)~o$O4>N0)QIpZP0YRti3%+A;A>%V!ABGy>;EZeif)4gQ);!NJW{s+Fk@bacXGiuB zgNszM<*d*$1aLjuap^1h%q`B-+*vV=8s&ROF9Llc#sb;y zX%&mYRjBY54NsHFTm!jl&5>n!J#mqX#uwLk5Scb|6R(HDRjAN)^<-mjdp#67LX97! zL6y7ZXb>jAS4%1QLJc@k`kOOqI$A4eylMonNh%z=Bv&d+%lMV>dPmpL`ZW2KAnmmm zzN15f;&Udsh*Jty;@D7Y;ps=HJ}2;|B+WEC3Rj^LNP#6fz06lgAVM_JmrBb?)IM>Z zU{-hx7g2|5qjc`5eT9L8)kd&PmK7!N=qF~ivc_Y$$U0cf++Ch$;Xla=k>M)qSg>&V z{7=F?lNB1nMbKV$N$x(_C3{N?-8!nxFfpx_6(Yk$)|dRD=Ya$Ym7x;-@8{Y*&tSN$ za2aZ(`r+g#y)u=L$@IvaOZJuoKr@9`DD}fNW%oHP=5I&kmK7pH4KBp4TkL7V=UE{# zjMr|lXB}ymH6BBy#;!v<&*Nk(EQVM5km2S#mZd^OSFi#2WcJG4`7k7DJ62qEnjBqjnS)Lq%zRPIvqp z4r0v;kD=0C{&`bW-Y{pE6_!HBa=RmW*6bVfbZ+lzpK7oQ?}fCWGXpQpWBh_A#2uayo% z<>o8ZZJx70ok$iN>oQ4Vn)oU^?4>v_`gq35F1cU;7XUVK65=oE;)K_nIEDajmYX+A zmPJNaC$V1oK>O)ajHxBV&UZF#*f^@q1jW+^$yz4>L^JQcLRNR3owaP}rt~<5V(7%Fcv5kpF6R6<4dr%Vbn0Dudu9TQ_v!dSFqwiMaZig}d_x zZ9sU?6~$%m4W4mp}X2FaG|kuikzAkbmBN^%WQV`S%|_ T{^f@s@z?x+2(qFtd3OQ;vHziI literal 0 HcmV?d00001 diff --git a/integration-test/input/de/kelheim/kelheim-v3.0/25pct/kelheim-v3.0-25pct.output_transitSchedule.xml.gz b/integration-test/input/de/kelheim/kelheim-v3.0/25pct/kelheim-v3.0-25pct.output_transitSchedule.xml.gz new file mode 100644 index 0000000000000000000000000000000000000000..81216b748f46a62a854032c2632928a1db10e5c7 GIT binary patch literal 45027 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 a`6AH&mgZI5SI literal 0 HcmV?d00001 diff --git a/src/main/java/ch/sbb/rssched/Application.java b/src/main/java/ch/sbb/rssched/Application.java new file mode 100644 index 0000000..052eb13 --- /dev/null +++ b/src/main/java/ch/sbb/rssched/Application.java @@ -0,0 +1,46 @@ +package ch.sbb.rssched; + +import ch.sbb.rssched.client.RsschedMatsimClient; +import ch.sbb.rssched.client.RsschedMatsimRequestGenerator; +import ch.sbb.rssched.client.config.RsschedRequestConfig; +import ch.sbb.rssched.client.config.RsschedRequestConfigReader; +import ch.sbb.rssched.client.dto.response.Response; + +import java.io.IOException; + +/** + * Read the request configuration from an Excel file and optionally send the request to the solver using the + * RsschedMatsimClient + * + * @author munterfi + */ +public class Application { + + // TODO: Export also RSSched configuration excel to output folder + + // TODO: Use instance ID for file paths. + + // TODO: Set max deadhead trip to beeline distance times a factor. + + // TODO: make primary arg + private static final String REQUEST_CONFIG_XLSX = "integration-test/input/de/kelheim/kelheim-v3.0/25pct/kehlheim-v3.0-25pct.rssched_request_config.xlsx"; + // TODO: Make cmd options + private static final String SCHEDULER_BASE_URL = "http://localhost"; + private static final int SCHEDULER_PORT = 3000; + private static final boolean SEND_TO_SOLVER = false; + + public static void main(String[] args) throws IOException { + RsschedRequestConfig config = new RsschedRequestConfigReader().readExcelFile(REQUEST_CONFIG_XLSX); + + if (SEND_TO_SOLVER) { + // create request and send to solver + RsschedMatsimClient client = new RsschedMatsimClient(SCHEDULER_BASE_URL, SCHEDULER_PORT); + Response response = client.process(config); + } else { + // only create request and export as JSON + new RsschedMatsimRequestGenerator().process(config); + } + + } + +} diff --git a/src/main/java/ch/sbb/rssched/client/RsschedMatsimRequestGenerator.java b/src/main/java/ch/sbb/rssched/client/RsschedMatsimRequestGenerator.java new file mode 100644 index 0000000..18b6184 --- /dev/null +++ b/src/main/java/ch/sbb/rssched/client/RsschedMatsimRequestGenerator.java @@ -0,0 +1,24 @@ +package ch.sbb.rssched.client; + +import ch.sbb.rssched.client.config.RsschedRequestConfig; +import ch.sbb.rssched.client.dto.request.Request; +import ch.sbb.rssched.client.pipeline.request.RequestPipeline; + +import java.util.concurrent.atomic.AtomicReference; + +/** + * Generates a rolling stock scheduling solver request from a MATSim run output and exports it to a JSON file. + */ +public class RsschedMatsimRequestGenerator { + + public Request process(RsschedRequestConfig config) { + AtomicReference request = new AtomicReference<>(); + + var pipeline = new RequestPipeline(config); + pipeline.addSink(pipe -> request.set(pipe.getRequest())); + pipeline.run(); + + return request.get(); + } + +} From d0adbf2867b2fe58dd3e5b8a5b9629d947abb392 Mon Sep 17 00:00:00 2001 From: Merlin Unterfinger Date: Tue, 11 Jun 2024 13:37:26 +0200 Subject: [PATCH 2/6] Add command line runner for client - Application with command line interface. - Integration tests for command line application. - Extend client integration test with Excel example. - Update Excel config for integration test. --- README.md | 49 +- .../1pct/kelheim-v3.0-1pct.output_config.xml | 35667 ---------------- ...eim-v3.0-25pct.rssched_request_config.xlsx | Bin 18214 -> 0 bytes ...eim-v3.0-25pct.rssched_request_config.xlsx | Bin 0 -> 18617 bytes pom.xml | 14 + src/main/java/ch/sbb/rssched/Application.java | 106 +- src/main/java/ch/sbb/rssched/RunExample.java | 27 - .../java/ch/sbb/rssched/ApplicationIT.java | 41 + .../rssched/client/RsschedMatsimClientIT.java | 13 +- 9 files changed, 204 insertions(+), 35713 deletions(-) delete mode 100644 integration-test/input/de/kelheim/kelheim-v3.0/1pct/kelheim-v3.0-1pct.output_config.xml delete mode 100644 integration-test/input/de/kelheim/kelheim-v3.0/25pct/kehlheim-v3.0-25pct.rssched_request_config.xlsx create mode 100644 integration-test/input/de/kelheim/kelheim-v3.0/25pct/kelheim-v3.0-25pct.rssched_request_config.xlsx delete mode 100644 src/main/java/ch/sbb/rssched/RunExample.java create mode 100644 src/test/java/ch/sbb/rssched/ApplicationIT.java diff --git a/README.md b/README.md index de26df2..c23a035 100644 --- a/README.md +++ b/README.md @@ -31,6 +31,26 @@ The project has the following package structure: ## Usage +### Using Command-Line Application + +Read the request configuration from an Excel file and optionally send the request to the solver using the +RsschedMatsimClient: + +```sh +mvn exec:java -Dexec.args="path/to/config_file.xlsx -h localhost -p 3000 -d" +``` + +Options: + +- **Required:** + - `config_file`: Path to the Excel configuration file. +- **Optional:** + - `-h / --host`: Scheduler base URL (default: "http://localhost"). + - `-p / --port`: Scheduler port (default: 3000). + - `-d / --dry-run`: If present, do not send the request to the solver (default: false). + +### Using Client in Java + Set up the `RsschedRequestClient` and send a request to the rolling stock scheduling solver service using the `RsschedRequestConfig` to configure it. Optionally implement a transit line filter strategy. @@ -39,7 +59,7 @@ import ch.sbb.rssched.client.RsschedMatsimClient; import ch.sbb.rssched.client.config.RsschedRequestConfig; import ch.sbb.rssched.client.dto.response.Response; -public class Example { +public class RunExample { private static final String SCHEDULER_BASE_URL = "http://localhost"; private static final int SCHEDULER_PORT = 3000; @@ -65,9 +85,30 @@ public class Example { } ``` -Alternatively use an XLSX file to configure the request to the solver, -see [`RunExample`](src/main/java/ch/sbb/rssched/RunExample.java) -and [`request_config.xlsx`](src/test/resources/ch/sbb/rssched/client/config/request_config.xlsx). +Alternatively use an Excel file to configure the request to the solver: + +```java +import ch.sbb.rssched.client.RsschedMatsimClient; +import ch.sbb.rssched.client.config.RsschedRequestConfig; +import ch.sbb.rssched.client.config.RsschedRequestConfigReader; +import ch.sbb.rssched.client.dto.response.Response; + +import java.io.IOException; + +public class RunExample { + + private static final String REQUEST_CONFIG_XLSX = "rssched_request_config.xlsx"; + private static final String SCHEDULER_BASE_URL = "http://localhost"; + private static final int SCHEDULER_PORT = 3000; + + public static void main(String[] args) throws IOException { + RsschedRequestConfig config = new RsschedRequestConfigReader().readExcelFile(REQUEST_CONFIG_XLSX); + RsschedMatsimClient client = new RsschedMatsimClient(SCHEDULER_BASE_URL, SCHEDULER_PORT); + Response response = client.process(config); + } + +} +``` **Note:** There is a hard limit of 500 locations per instance, since the deadhead trip matrix grows exponentially. diff --git a/integration-test/input/de/kelheim/kelheim-v3.0/1pct/kelheim-v3.0-1pct.output_config.xml b/integration-test/input/de/kelheim/kelheim-v3.0/1pct/kelheim-v3.0-1pct.output_config.xml deleted file mode 100644 index 8584085..0000000 --- a/integration-test/input/de/kelheim/kelheim-v3.0/1pct/kelheim-v3.0-1pct.output_config.xml +++ /dev/null @@ -1,35667 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/integration-test/input/de/kelheim/kelheim-v3.0/25pct/kehlheim-v3.0-25pct.rssched_request_config.xlsx b/integration-test/input/de/kelheim/kelheim-v3.0/25pct/kehlheim-v3.0-25pct.rssched_request_config.xlsx deleted file mode 100644 index e778ee0c84f712f19603df69e51cd24b9d3dd80e..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 18214 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 DL*I1m diff --git a/integration-test/input/de/kelheim/kelheim-v3.0/25pct/kelheim-v3.0-25pct.rssched_request_config.xlsx b/integration-test/input/de/kelheim/kelheim-v3.0/25pct/kelheim-v3.0-25pct.rssched_request_config.xlsx new file mode 100644 index 0000000000000000000000000000000000000000..71306964fec4f7db566f90c28c56f147ddf4068f GIT binary patch literal 18617 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 s25.2.5 + + commons-cli + commons-cli + 1.8.0 + + @@ -142,6 +148,14 @@ + + org.codehaus.mojo + exec-maven-plugin + 3.0.0 + + ch.sbb.rssched.Application + + diff --git a/src/main/java/ch/sbb/rssched/Application.java b/src/main/java/ch/sbb/rssched/Application.java index 052eb13..19a21e5 100644 --- a/src/main/java/ch/sbb/rssched/Application.java +++ b/src/main/java/ch/sbb/rssched/Application.java @@ -5,15 +5,47 @@ import ch.sbb.rssched.client.config.RsschedRequestConfig; import ch.sbb.rssched.client.config.RsschedRequestConfigReader; import ch.sbb.rssched.client.dto.response.Response; +import lombok.AccessLevel; +import lombok.NoArgsConstructor; +import org.apache.commons.cli.CommandLine; +import org.apache.commons.cli.CommandLineParser; +import org.apache.commons.cli.DefaultParser; +import org.apache.commons.cli.HelpFormatter; +import org.apache.commons.cli.Option; +import org.apache.commons.cli.Options; +import org.apache.commons.cli.ParseException; import java.io.IOException; /** * Read the request configuration from an Excel file and optionally send the request to the solver using the - * RsschedMatsimClient - * - * @author munterfi + * RsschedMatsimClient. + *

+ * Usage: + *

+ * {@code ./rssched-matsim-client  -h / --host  -p / --port  -d / --dry-run}
+ * 
+ *

+ * If {@code -d / --dry-run} is present, the request is not sent to the solver. + *

+ * Required: + *

    + *
  • {@code config_file}: Path to the Excel configuration file
  • + *
+ *

+ * Optional: + *

    + *
  • {@code -h / --host}: Scheduler base URL (default: "localhost")
  • + *
  • {@code -p / --port}: Scheduler port (default: 3000)
  • + *
  • {@code -d / --dry-run}: If present, do not send the request to the solver (default: false)
  • + *
+ *

+ * Example with maven: + *

+ * {@code mvn exec:java -Dexec.args="path_to_file.xlsx -h localhost -p 3000 -d"}
+ * 
*/ +@NoArgsConstructor(access = AccessLevel.PRIVATE) public class Application { // TODO: Export also RSSched configuration excel to output folder @@ -22,25 +54,71 @@ public class Application { // TODO: Set max deadhead trip to beeline distance times a factor. - // TODO: make primary arg - private static final String REQUEST_CONFIG_XLSX = "integration-test/input/de/kelheim/kelheim-v3.0/25pct/kehlheim-v3.0-25pct.rssched_request_config.xlsx"; - // TODO: Make cmd options - private static final String SCHEDULER_BASE_URL = "http://localhost"; - private static final int SCHEDULER_PORT = 3000; - private static final boolean SEND_TO_SOLVER = false; + public static final String APP_CMD_SYNTAX = "rssched-matsim-client "; + public static final String DEFAULT_HOST = "http://localhost"; + public static final String DEFAULT_PORT = "3000"; - public static void main(String[] args) throws IOException { - RsschedRequestConfig config = new RsschedRequestConfigReader().readExcelFile(REQUEST_CONFIG_XLSX); + public static void main(String[] args) { + try { + runApplication(args); + } catch (IOException | RuntimeException e) { + System.err.println(e.getMessage()); + HelpFormatter formatter = new HelpFormatter(); + formatter.printHelp(APP_CMD_SYNTAX, initOptions()); + System.exit(1); + } + } + + static void runApplication(String[] args) throws IOException { + Options options = initOptions(); + + CommandLineParser parser = new DefaultParser(); + CommandLine cmd; + + try { + cmd = parser.parse(options, args); + } catch (ParseException e) { + throw new RuntimeException(e.getMessage()); + } + + String[] remainingArgs = cmd.getArgs(); + if (remainingArgs.length < 1) { + throw new RuntimeException("Missing required argument: config_file"); + } - if (SEND_TO_SOLVER) { + String requestConfigXlsx = remainingArgs[0]; + String schedulerBaseUrl = cmd.getOptionValue("host", DEFAULT_HOST); + int schedulerPort = Integer.parseInt(cmd.getOptionValue("port", DEFAULT_PORT)); + boolean sendToSolver = !cmd.hasOption("dry-run"); + + RsschedRequestConfig config = new RsschedRequestConfigReader().readExcelFile(requestConfigXlsx); + + if (sendToSolver) { // create request and send to solver - RsschedMatsimClient client = new RsschedMatsimClient(SCHEDULER_BASE_URL, SCHEDULER_PORT); + RsschedMatsimClient client = new RsschedMatsimClient(schedulerBaseUrl, schedulerPort); Response response = client.process(config); + System.out.println(response.getInfo()); } else { // only create request and export as JSON new RsschedMatsimRequestGenerator().process(config); } - } + private static Options initOptions() { + Options options = new Options(); + + Option hostOption = new Option("h", "host", true, "Scheduler base URL"); + hostOption.setRequired(false); + options.addOption(hostOption); + + Option portOption = new Option("p", "port", true, "Scheduler port"); + portOption.setRequired(false); + options.addOption(portOption); + + Option dryRunOption = new Option("d", "dry-run", false, "Dry run (do not send the request to the solver)"); + dryRunOption.setRequired(false); + options.addOption(dryRunOption); + + return options; + } } diff --git a/src/main/java/ch/sbb/rssched/RunExample.java b/src/main/java/ch/sbb/rssched/RunExample.java deleted file mode 100644 index 8e7acbd..0000000 --- a/src/main/java/ch/sbb/rssched/RunExample.java +++ /dev/null @@ -1,27 +0,0 @@ -package ch.sbb.rssched; - -import ch.sbb.rssched.client.RsschedMatsimClient; -import ch.sbb.rssched.client.config.RsschedRequestConfig; -import ch.sbb.rssched.client.config.RsschedRequestConfigReader; -import ch.sbb.rssched.client.dto.response.Response; - -import java.io.IOException; - -/** - * Read the request configuration from an Excel file and send the request to the solver using the RsschedMatsimClient - * - * @author munterfi - */ -public class RunExample { - - private static final String REQUEST_CONFIG_XLSX = "rssched_request_config.xlsx"; - private static final String SCHEDULER_BASE_URL = "http://localhost"; - private static final int SCHEDULER_PORT = 3000; - - public static void main(String[] args) throws IOException { - RsschedRequestConfig config = new RsschedRequestConfigReader().readExcelFile(REQUEST_CONFIG_XLSX); - RsschedMatsimClient client = new RsschedMatsimClient(SCHEDULER_BASE_URL, SCHEDULER_PORT); - Response response = client.process(config); - } - -} diff --git a/src/test/java/ch/sbb/rssched/ApplicationIT.java b/src/test/java/ch/sbb/rssched/ApplicationIT.java new file mode 100644 index 0000000..4a41f65 --- /dev/null +++ b/src/test/java/ch/sbb/rssched/ApplicationIT.java @@ -0,0 +1,41 @@ +package ch.sbb.rssched; + +import ch.sbb.rssched.client.IntegrationTestData; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; + +import java.io.IOException; + +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertThrows; + +class ApplicationIT { + + private static final String CONFIG_FILE = "integration-test/input/de/kelheim/kelheim-v3.0/25pct/kelheim-v3.0-25pct.rssched_request_config.xlsx"; + private static final String SCHEDULER_BASE_URL = "http://localhost"; + private static final String SCHEDULER_PORT = "3000"; + + @BeforeEach + void setUp() throws IOException { + new IntegrationTestData(false).setup(); + } + + @Test + void testMainWithDryRun() throws Exception { + String[] args = {CONFIG_FILE, "-d"}; + Application.runApplication(args); + } + + @Test + void testMainWithSendingToSolver() throws Exception { + String[] args = {CONFIG_FILE, "-h", SCHEDULER_BASE_URL, "-p", SCHEDULER_PORT}; + Application.runApplication(args); + } + + @Test + void testMissingRequiredArgument() { + String[] args = {}; + Exception exception = assertThrows(RuntimeException.class, () -> Application.runApplication(args)); + assertEquals("Missing required argument: config_file", exception.getMessage()); + } +} diff --git a/src/test/java/ch/sbb/rssched/client/RsschedMatsimClientIT.java b/src/test/java/ch/sbb/rssched/client/RsschedMatsimClientIT.java index b751251..94363b3 100644 --- a/src/test/java/ch/sbb/rssched/client/RsschedMatsimClientIT.java +++ b/src/test/java/ch/sbb/rssched/client/RsschedMatsimClientIT.java @@ -1,6 +1,7 @@ package ch.sbb.rssched.client; import ch.sbb.rssched.client.config.RsschedRequestConfig; +import ch.sbb.rssched.client.config.RsschedRequestConfigReader; import ch.sbb.rssched.client.config.selection.FilterStrategy; import ch.sbb.rssched.client.config.selection.TransitLineSelection; import ch.sbb.rssched.client.dto.response.Response; @@ -14,6 +15,7 @@ class RsschedMatsimClientIT { + private static final String REQUEST_CONFIG_XLSX = "integration-test/input/de/kelheim/kelheim-v3.0/25pct/kelheim-v3.0-25pct.rssched_request_config.xlsx"; private static final String SCHEDULER_BASE_URL = "http://localhost"; private static final int SCHEDULER_PORT = 3000; @@ -23,7 +25,16 @@ void setUp() throws IOException { } @Test - void testProcess() { + void testWithConfigReader() throws IOException { + RsschedRequestConfig config = new RsschedRequestConfigReader().readExcelFile(REQUEST_CONFIG_XLSX); + RsschedMatsimClient client = new RsschedMatsimClient(SCHEDULER_BASE_URL, SCHEDULER_PORT); + Response response = client.process(config); + + assertNotNull(response); + } + + @Test + void testWithConfigBuilder() { // filter to Kehlheim region FilterStrategy filterStrategy = scenario -> { TransitLineSelection selection = new TransitLineSelection(); From 88bd658c4b169d5496486bcd0b806df8624346a2 Mon Sep 17 00:00:00 2001 From: Merlin Unterfinger Date: Tue, 11 Jun 2024 13:44:51 +0200 Subject: [PATCH 3/6] Update README --- README.md | 14 +++++++++++++- 1 file changed, 13 insertions(+), 1 deletion(-) diff --git a/README.md b/README.md index c23a035..c6a515f 100644 --- a/README.md +++ b/README.md @@ -49,6 +49,12 @@ Options: - `-p / --port`: Scheduler port (default: 3000). - `-d / --dry-run`: If present, do not send the request to the solver (default: false). +See [kelheim-v3.0-25pct.rssched_request_config.xlsx](integration-test/input/de/kelheim/kelheim-v3.0/25pct/kelheim-v3.0-25pct.rssched_request_config.xlsx) +for reference of a request configuration. + +**Note**: To be able to run the integration test using the command line app, first execute the integration tests, which +downloads the needed matsim run outputs, see the paragraph **Testing** below. + ### Using Client in Java Set up the `RsschedRequestClient` and send a request to the rolling stock scheduling solver service using @@ -114,9 +120,15 @@ public class RunExample { ## Testing +Run the unit tests: + +```sh +mvn test +``` + Run the integration test to see the pipeline in action (needs a running solver on localhost and port 3000): -```shell +```sh mvn verify -Dit.test=RsschedMatsimClientIT ``` From 9f23b9d1ff2d6b21536f431108c9fbe148ae6477 Mon Sep 17 00:00:00 2001 From: Merlin Unterfinger Date: Tue, 11 Jun 2024 16:27:42 +0200 Subject: [PATCH 4/6] Instead of setting deadhead trips to Integer.MAX when not path is found, use the beeline distance and a factor to approximate those --- ...eim-v3.0-25pct.rssched_request_config.xlsx | Bin 18617 -> 18735 bytes src/main/java/ch/sbb/rssched/Application.java | 2 -- .../client/config/RsschedRequestConfig.java | 6 ++++++ .../config/RsschedRequestConfigReader.java | 4 ++++ .../pipeline/request/RequestComposer.java | 5 +++-- .../pipeline/request/TrainNetworkRouter.java | 15 ++++++++++++--- .../rssched/client/config/request_config.xlsx | Bin 18166 -> 18253 bytes 7 files changed, 25 insertions(+), 7 deletions(-) diff --git a/integration-test/input/de/kelheim/kelheim-v3.0/25pct/kelheim-v3.0-25pct.rssched_request_config.xlsx b/integration-test/input/de/kelheim/kelheim-v3.0/25pct/kelheim-v3.0-25pct.rssched_request_config.xlsx index 71306964fec4f7db566f90c28c56f147ddf4068f..3083db7fc6d11105b07772a99487bd04ad60d4ae 100644 GIT binary patch delta 5011 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 delta 4854 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 B?Cbyl diff --git a/src/main/java/ch/sbb/rssched/Application.java b/src/main/java/ch/sbb/rssched/Application.java index 19a21e5..235340c 100644 --- a/src/main/java/ch/sbb/rssched/Application.java +++ b/src/main/java/ch/sbb/rssched/Application.java @@ -52,8 +52,6 @@ public class Application { // TODO: Use instance ID for file paths. - // TODO: Set max deadhead trip to beeline distance times a factor. - public static final String APP_CMD_SYNTAX = "rssched-matsim-client "; public static final String DEFAULT_HOST = "http://localhost"; public static final String DEFAULT_PORT = "3000"; diff --git a/src/main/java/ch/sbb/rssched/client/config/RsschedRequestConfig.java b/src/main/java/ch/sbb/rssched/client/config/RsschedRequestConfig.java index 7d3de64..31bef87 100644 --- a/src/main/java/ch/sbb/rssched/client/config/RsschedRequestConfig.java +++ b/src/main/java/ch/sbb/rssched/client/config/RsschedRequestConfig.java @@ -146,6 +146,12 @@ public static class Global { */ private double deadHeadTripSpeedLimit = 90 / 3.6; + /** + * The factor that is applied to travel the beeline distance at speed limit, if no path in the network is found + * for the dead head trip between two locations. + */ + private double deadHeadTripBeelineDistanceFactor = 5; + /** * Allow deadhead trips? */ diff --git a/src/main/java/ch/sbb/rssched/client/config/RsschedRequestConfigReader.java b/src/main/java/ch/sbb/rssched/client/config/RsschedRequestConfigReader.java index 254dd81..0c1fbc0 100644 --- a/src/main/java/ch/sbb/rssched/client/config/RsschedRequestConfigReader.java +++ b/src/main/java/ch/sbb/rssched/client/config/RsschedRequestConfigReader.java @@ -83,6 +83,10 @@ private void parseScenarioInfoSheet(Sheet sheet) { case "deadHeadTripSpeedLimit": builder.config.getGlobal().setDeadHeadTripSpeedLimit(valueCell.getNumericCellValue()); break; + case "deadHeadTripBeelineDistanceFactor": + builder.config.getGlobal() + .setDeadHeadTripBeelineDistanceFactor(valueCell.getNumericCellValue()); + break; case "forbidDeadHeadTrips": builder.config.getGlobal().setForbidDeadHeadTrips(valueCell.getBooleanCellValue()); break; diff --git a/src/main/java/ch/sbb/rssched/client/pipeline/request/RequestComposer.java b/src/main/java/ch/sbb/rssched/client/pipeline/request/RequestComposer.java index 9d96ec6..dceb105 100644 --- a/src/main/java/ch/sbb/rssched/client/pipeline/request/RequestComposer.java +++ b/src/main/java/ch/sbb/rssched/client/pipeline/request/RequestComposer.java @@ -334,10 +334,11 @@ private void addDeadHeadTrips(Request.Builder builder, Scenario scenario) { log.info("Creating dead head trip matrix ({}x{}={})", locations.keySet().size(), locations.keySet().size(), locations.keySet().size() * locations.keySet().size()); TrainNetworkRouter trainNetworkRouter = new TrainNetworkRouter(scenario.getNetwork(), - config.getGlobal().getDeadHeadTripSpeedLimit()); + config.getGlobal().getDeadHeadTripSpeedLimit(), + config.getGlobal().getDeadHeadTripBeelineDistanceFactor()); locations.keySet().forEach(originId -> locations.keySet().forEach(destinationId -> { if (!originId.equals(destinationId)) { - var pathResult = trainNetworkRouter.calculate( + TrainNetworkRouter.PathResult pathResult = trainNetworkRouter.calculate( scenario.getTransitSchedule().getFacilities().get(originId), scenario.getTransitSchedule().getFacilities().get(destinationId)); builder.addDeadHeadTrip(originId.toString(), destinationId.toString(), pathResult.duration(), diff --git a/src/main/java/ch/sbb/rssched/client/pipeline/request/TrainNetworkRouter.java b/src/main/java/ch/sbb/rssched/client/pipeline/request/TrainNetworkRouter.java index d0daad6..990ce97 100644 --- a/src/main/java/ch/sbb/rssched/client/pipeline/request/TrainNetworkRouter.java +++ b/src/main/java/ch/sbb/rssched/client/pipeline/request/TrainNetworkRouter.java @@ -5,6 +5,7 @@ import org.matsim.api.core.v01.network.Network; import org.matsim.api.core.v01.network.Node; import org.matsim.api.core.v01.population.Person; +import org.matsim.core.network.NetworkUtils; import org.matsim.core.router.DijkstraFactory; import org.matsim.core.router.util.LeastCostPathCalculator; import org.matsim.core.router.util.TravelDisutility; @@ -25,11 +26,13 @@ public class TrainNetworkRouter { private static final Double TOLERANCE = 0.001; private final Network network; private final double freeSpeedLimit; + private final double beelineDistanceFactor; private final LeastCostPathCalculator lpc; - public TrainNetworkRouter(Network network, double freeSpeedLimit) { + public TrainNetworkRouter(Network network, double freeSpeedLimit, double beelineDistanceFactor) { this.network = network; this.freeSpeedLimit = freeSpeedLimit; + this.beelineDistanceFactor = beelineDistanceFactor; this.lpc = new DijkstraFactory(false).createPathCalculator(network, new TrainTravelDisutility(), new FreeSpeedTravelTime()); } @@ -46,8 +49,14 @@ public PathResult calculate(TransitStopFacility from, TransitStopFacility to) { Node toNode = network.getLinks().get(to.getLinkId()).getFromNode(); LeastCostPathCalculator.Path path = lpc.calcLeastCostPath(fromNode, toNode, 0, null, null); if (path == null) { - log.warn("Setting duration and distance to Integer.MAX_VALUE for route from {} to {}", fromNode, toNode); - return new PathResult(Integer.MAX_VALUE, Integer.MAX_VALUE); + double beelineDistance = NetworkUtils.getEuclideanDistance(fromNode.getCoord(), toNode.getCoord()); + double distance = beelineDistance * beelineDistanceFactor; + double duration = distance / freeSpeedLimit; + log.warn( + "Setting duration and distance to {}s / {}m (beeline distance: {}m times factor: {}) for route from {} to {}", + Math.round(duration), Math.round(distance), Math.round(beelineDistance), beelineDistanceFactor, + fromNode.getId(), toNode.getId()); + return new PathResult((int) Math.round(duration), (int) Math.round(distance)); } double travelTime = path.travelCost; double travelDistance = extractPathLength(path); diff --git a/src/test/resources/ch/sbb/rssched/client/config/request_config.xlsx b/src/test/resources/ch/sbb/rssched/client/config/request_config.xlsx index 013bbfbcd5bca766dd662a860e16ded26fc9bb17..8e60d0844c71abd258c994b28e1b0353e641fc49 100644 GIT binary patch delta 5659 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 From 00672e961969776a0939d1a328328266a1e7a347 Mon Sep 17 00:00:00 2001 From: Merlin Unterfinger Date: Tue, 11 Jun 2024 16:51:49 +0200 Subject: [PATCH 5/6] Introduce solver instance id to specify output directory and file names --- README.md | 1 + ...eim-v3.0-25pct.rssched_request_config.xlsx | Bin 18735 -> 18739 bytes .../client/config/RsschedRequestConfig.java | 10 ++++++++-- .../config/RsschedRequestConfigReader.java | 7 +++---- .../passenger/PassengerCSVWriter.java | 6 ++++-- .../pipeline/passenger/PassengerPipeline.java | 5 +++-- .../pipeline/request/RequestJSONWriter.java | 7 +++++-- .../pipeline/request/RequestPipeline.java | 12 ++++++------ .../pipeline/response/ResponseJSONWriter.java | 6 ++++-- .../pipeline/response/ResponsePipeline.java | 2 +- .../scenario/LineSelectionCSVWriter.java | 7 +++++-- .../pipeline/scenario/ScenarioExporter.java | 6 ++++-- .../pipeline/scenario/ScenarioPipeline.java | 7 ++++--- .../utils/io/OutputDirectoryManager.java | 8 +++++--- .../rssched/client/RsschedMatsimClientIT.java | 2 +- .../config/RsschedRequestConfigReaderIT.java | 5 ++--- .../rssched/client/config/request_config.xlsx | Bin 18253 -> 18255 bytes 17 files changed, 56 insertions(+), 35 deletions(-) diff --git a/README.md b/README.md index c6a515f..315bb39 100644 --- a/README.md +++ b/README.md @@ -75,6 +75,7 @@ public class RunExample { .setInputDirectory("path/to/input/directory") .setOutputDirectory("path/to/output/directory") .setRunId("runId") + .setInstanceId("rss001") // optionally set transit line filter, default is no filtering .setFilterStrategy(scenario -> { // implementation... diff --git a/integration-test/input/de/kelheim/kelheim-v3.0/25pct/kelheim-v3.0-25pct.rssched_request_config.xlsx b/integration-test/input/de/kelheim/kelheim-v3.0/25pct/kelheim-v3.0-25pct.rssched_request_config.xlsx index 3083db7fc6d11105b07772a99487bd04ad60d4ae..76f0930c793a4161feded8a63fb389bc5a3031df 100644 GIT binary patch delta 3904 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 Q1DHl+Kwn_UNB#!?ADYrUfB*mh delta 3880 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 cE)@v$JLrGp2v0P;2u{Z{7>Uw8K>cz28w^hx depotLocations = new HashSet<>(); private final Map depots = new HashMap<>(); + public Builder setInstanceId(String instanceId) { + config.instanceId = instanceId; + return this; + } + public Builder setRunId(String runId) { config.runId = runId; return this; @@ -111,9 +117,9 @@ public Builder addMaintenanceSlot(String id, String locationId, LocalDateTime st * @return The fully configured RequestConfig instance. */ public RsschedRequestConfig buildWithDefaults() { - if (config.runId == null || config.inputDirectory == null || config.outputDirectory == null) { + if (config.instanceId == null || config.runId == null || config.inputDirectory == null || config.outputDirectory == null) { throw new IllegalStateException( - "Mandatory fields (runId, inputDirectory, outputDirectory) must be set."); + "Mandatory fields (instanceId, runId, inputDirectory, outputDirectory) must be set."); } return config; } diff --git a/src/main/java/ch/sbb/rssched/client/config/RsschedRequestConfigReader.java b/src/main/java/ch/sbb/rssched/client/config/RsschedRequestConfigReader.java index 0c1fbc0..ab1613c 100644 --- a/src/main/java/ch/sbb/rssched/client/config/RsschedRequestConfigReader.java +++ b/src/main/java/ch/sbb/rssched/client/config/RsschedRequestConfigReader.java @@ -51,8 +51,6 @@ public RsschedRequestConfig readExcelFile(String filePath) throws IOException { private void parseScenarioInfoSheet(Sheet sheet) { checkIfSheetExists(sheet, Sheets.SCENARIO_INFO); - String instanceId = ""; - for (Row row : sheet) { Cell groupCell = row.getCell(0); Cell parameterCell = row.getCell(1); @@ -66,7 +64,8 @@ private void parseScenarioInfoSheet(Sheet sheet) { case "global": switch (parameter) { case "instanceId": - instanceId = valueCell.getStringCellValue(); + String instanceId = valueCell.getStringCellValue(); + builder.setInstanceId(instanceId); break; case "matsimRunId": builder.setRunId(valueCell.getStringCellValue()); @@ -75,7 +74,7 @@ private void parseScenarioInfoSheet(Sheet sheet) { builder.setInputDirectory(valueCell.getStringCellValue()); break; case "outputDirectory": - builder.setOutputDirectory(valueCell.getStringCellValue() + "/" + instanceId); + builder.setOutputDirectory(valueCell.getStringCellValue()); break; case "sampleSize": builder.config.getGlobal().setSampleSize(valueCell.getNumericCellValue()); diff --git a/src/main/java/ch/sbb/rssched/client/pipeline/passenger/PassengerCSVWriter.java b/src/main/java/ch/sbb/rssched/client/pipeline/passenger/PassengerCSVWriter.java index 8156086..e0d101a 100644 --- a/src/main/java/ch/sbb/rssched/client/pipeline/passenger/PassengerCSVWriter.java +++ b/src/main/java/ch/sbb/rssched/client/pipeline/passenger/PassengerCSVWriter.java @@ -27,14 +27,16 @@ class PassengerCSVWriter implements ResultSink { private static final String PASSENGER_FILE = "passenger.csv"; private static final String[] HEADER = {"transit_line_id", "transit_route_id", "departure_id", "stop_id", "stop_name", "arrival", "departure", "egress", "access", "to_stop_id", "to_stop_name", "passengers", "seats"}; private final String outputDirectory; + private final String instanceId; /** * Constructs a PassengerExporter with the specified output directory. * * @param outputDirectory the directory to export the passenger file to. */ - public PassengerCSVWriter(String outputDirectory) { + public PassengerCSVWriter(String outputDirectory, String instanceId) { this.outputDirectory = outputDirectory; + this.instanceId = instanceId; } public static void writeCsv(List entries, String filename) throws UncheckedIOException { @@ -80,7 +82,7 @@ public static void writeCsv(List entries, String filename) @Override public void process(PassengerPipe pipe) { - String passengerFilePath = new OutputDirectoryManager(outputDirectory, pipe.runId()).buildFilePath( + String passengerFilePath = new OutputDirectoryManager(outputDirectory, pipe.runId(), instanceId).buildFilePath( PASSENGER_FILE); log.info("Exporting passenger file to {}", passengerFilePath); writeCsv(pipe.entries(), passengerFilePath); diff --git a/src/main/java/ch/sbb/rssched/client/pipeline/passenger/PassengerPipeline.java b/src/main/java/ch/sbb/rssched/client/pipeline/passenger/PassengerPipeline.java index 1aec1fa..faf0c02 100644 --- a/src/main/java/ch/sbb/rssched/client/pipeline/passenger/PassengerPipeline.java +++ b/src/main/java/ch/sbb/rssched/client/pipeline/passenger/PassengerPipeline.java @@ -13,18 +13,19 @@ public class PassengerPipeline extends Pipeline { /** * Constructs a RepPipeline with the specified parameters. * + * @param instanceId the ID of the RSSched instance (=request) to solve * @param runId the ID of the scenario run * @param inputDirectory the input directory containing the scenario data (output files of the simulation) * @param outputDirectory the output directory to export the processed scenario files * @param filterStrategy the filter strategy for filtering transit lines */ - public PassengerPipeline(String runId, String inputDirectory, String outputDirectory, FilterStrategy filterStrategy, double sampleSize, int seatDurationThreshold) { + public PassengerPipeline(String instanceId, String runId, String inputDirectory, String outputDirectory, FilterStrategy filterStrategy, double sampleSize, int seatDurationThreshold) { // set source super(new EventSource(runId, inputDirectory)); // add filters addFilter(new TransitLineFilter(filterStrategy)); addFilter(new EventAnalysisFilter(sampleSize, seatDurationThreshold)); // add sink - addSink(new PassengerCSVWriter(outputDirectory)); + addSink(new PassengerCSVWriter(outputDirectory, instanceId)); } } diff --git a/src/main/java/ch/sbb/rssched/client/pipeline/request/RequestJSONWriter.java b/src/main/java/ch/sbb/rssched/client/pipeline/request/RequestJSONWriter.java index 3a32e0c..6b5bd47 100644 --- a/src/main/java/ch/sbb/rssched/client/pipeline/request/RequestJSONWriter.java +++ b/src/main/java/ch/sbb/rssched/client/pipeline/request/RequestJSONWriter.java @@ -20,14 +20,17 @@ public class RequestJSONWriter implements ResultSink { private static final String REQUEST_FILE_NAME = "scheduler_request.json"; private final String outputDirectory; + private final String instanceId; - public RequestJSONWriter(String outputDirectory) { + public RequestJSONWriter(String outputDirectory, String instanceId) { this.outputDirectory = outputDirectory; + this.instanceId = instanceId; } @Override public void process(RequestPipe pipe) { - String filePath = new OutputDirectoryManager(outputDirectory, pipe.getRunId()).buildFilePath(REQUEST_FILE_NAME); + String filePath = new OutputDirectoryManager(outputDirectory, pipe.getRunId(), instanceId).buildFilePath( + REQUEST_FILE_NAME); log.info("Exporting request JSON to {}", filePath); try (FileWriter fileWriter = new FileWriter(filePath)) { fileWriter.write(pipe.getRequest().toJSON()); diff --git a/src/main/java/ch/sbb/rssched/client/pipeline/request/RequestPipeline.java b/src/main/java/ch/sbb/rssched/client/pipeline/request/RequestPipeline.java index 2e3a485..fa32cde 100644 --- a/src/main/java/ch/sbb/rssched/client/pipeline/request/RequestPipeline.java +++ b/src/main/java/ch/sbb/rssched/client/pipeline/request/RequestPipeline.java @@ -24,14 +24,14 @@ public class RequestPipeline extends Pipeline { public RequestPipeline(RsschedRequestConfig config) { // set source super(new ScenarioPassengerCollector(config.getRunId(), - new ScenarioPipeline(config.getRunId(), config.getInputDirectory(), config.getOutputDirectory(), - config.getGlobal().getFilterStrategy()), - new PassengerPipeline(config.getRunId(), config.getInputDirectory(), config.getOutputDirectory(), - config.getGlobal().getFilterStrategy(), config.getGlobal().getSampleSize(), - config.getGlobal().getSeatDurationThreshold()))); + new ScenarioPipeline(config.getInstanceId(), config.getRunId(), config.getInputDirectory(), + config.getOutputDirectory(), config.getGlobal().getFilterStrategy()), + new PassengerPipeline(config.getInstanceId(), config.getRunId(), config.getInputDirectory(), + config.getOutputDirectory(), config.getGlobal().getFilterStrategy(), + config.getGlobal().getSampleSize(), config.getGlobal().getSeatDurationThreshold()))); // add filter addFilter(new RequestComposer(config)); // add sink - addSink(new RequestJSONWriter(config.getOutputDirectory())); + addSink(new RequestJSONWriter(config.getOutputDirectory(), config.getInstanceId())); } } diff --git a/src/main/java/ch/sbb/rssched/client/pipeline/response/ResponseJSONWriter.java b/src/main/java/ch/sbb/rssched/client/pipeline/response/ResponseJSONWriter.java index 91259e5..044df55 100644 --- a/src/main/java/ch/sbb/rssched/client/pipeline/response/ResponseJSONWriter.java +++ b/src/main/java/ch/sbb/rssched/client/pipeline/response/ResponseJSONWriter.java @@ -18,14 +18,16 @@ public class ResponseJSONWriter implements ResultSink { private static final String RESPONSE_FILE_NAME = "scheduler_response.json"; private final String outputDirectory; + private final String instanceId; - public ResponseJSONWriter(String outputDirectory) { + public ResponseJSONWriter(String outputDirectory, String instanceId) { this.outputDirectory = outputDirectory; + this.instanceId = instanceId; } @Override public void process(ResponsePipe pipe) { - String filePath = new OutputDirectoryManager(outputDirectory, pipe.getRunId()).buildFilePath( + String filePath = new OutputDirectoryManager(outputDirectory, pipe.getRunId(), instanceId).buildFilePath( RESPONSE_FILE_NAME); log.info("Exporting response JSON to {}", filePath); try (FileWriter fileWriter = new FileWriter(filePath)) { diff --git a/src/main/java/ch/sbb/rssched/client/pipeline/response/ResponsePipeline.java b/src/main/java/ch/sbb/rssched/client/pipeline/response/ResponsePipeline.java index 93551d9..4d3e3e7 100644 --- a/src/main/java/ch/sbb/rssched/client/pipeline/response/ResponsePipeline.java +++ b/src/main/java/ch/sbb/rssched/client/pipeline/response/ResponsePipeline.java @@ -11,7 +11,7 @@ public ResponsePipeline(RsschedRequestConfig config, String baseUrl, int port) { // add filter addFilter(new RequestSender(baseUrl, port)); // add sink - addSink(new ResponseJSONWriter(config.getOutputDirectory())); + addSink(new ResponseJSONWriter(config.getOutputDirectory(), config.getInstanceId())); } } diff --git a/src/main/java/ch/sbb/rssched/client/pipeline/scenario/LineSelectionCSVWriter.java b/src/main/java/ch/sbb/rssched/client/pipeline/scenario/LineSelectionCSVWriter.java index 12bfd60..150e92e 100644 --- a/src/main/java/ch/sbb/rssched/client/pipeline/scenario/LineSelectionCSVWriter.java +++ b/src/main/java/ch/sbb/rssched/client/pipeline/scenario/LineSelectionCSVWriter.java @@ -16,14 +16,16 @@ class LineSelectionCSVWriter implements ResultSink { private static final String LINE_SELECTION_FILE = "line_selection.csv"; private static final String[] HEADER = {"group", "transit_line_id", "transit_route_id"}; private final String outputDirectory; + private final String instanceId; /** * Constructs a PassengerExporter with the specified output directory. * * @param outputDirectory the directory to export the passenger file to. */ - public LineSelectionCSVWriter(String outputDirectory) { + public LineSelectionCSVWriter(String outputDirectory, String instanceId) { this.outputDirectory = outputDirectory; + this.instanceId = instanceId; } public static void writeCsv(TransitLineSelection selection, String filename) throws UncheckedIOException { @@ -48,7 +50,8 @@ public static void writeCsv(TransitLineSelection selection, String filename) thr @Override public void process(ScenarioPipe pipe) { - String filePath = new OutputDirectoryManager(outputDirectory, pipe.runId).buildFilePath(LINE_SELECTION_FILE); + String filePath = new OutputDirectoryManager(outputDirectory, pipe.runId, instanceId).buildFilePath( + LINE_SELECTION_FILE); log.info("Exporting line selection file to {}", filePath); writeCsv(pipe.selection, filePath); } diff --git a/src/main/java/ch/sbb/rssched/client/pipeline/scenario/ScenarioExporter.java b/src/main/java/ch/sbb/rssched/client/pipeline/scenario/ScenarioExporter.java index 3062eda..24ee323 100644 --- a/src/main/java/ch/sbb/rssched/client/pipeline/scenario/ScenarioExporter.java +++ b/src/main/java/ch/sbb/rssched/client/pipeline/scenario/ScenarioExporter.java @@ -21,14 +21,16 @@ class ScenarioExporter implements ResultSink { private static final String TRANSIT_SCHEDULE_FILE = "transitSchedule.xml.gz"; private static final String TRANSIT_VEHICLES_FILE = "transitVehicles.xml.gz"; private final String outputDirectory; + private final String instanceId; /** * Constructs a ScenarioExporter with the specified output directory. * * @param outputDirectory the directory to export the scenario files to */ - public ScenarioExporter(String outputDirectory) { + public ScenarioExporter(String outputDirectory, String instanceId) { this.outputDirectory = outputDirectory; + this.instanceId = instanceId; } @Override @@ -37,7 +39,7 @@ public void process(ScenarioPipe pipe) { } private void export(Scenario scenario, String runId) { - var directoryUtil = new OutputDirectoryManager(outputDirectory, runId); + var directoryUtil = new OutputDirectoryManager(outputDirectory, runId, instanceId); new NetworkWriter(scenario.getNetwork()).write(directoryUtil.buildFilePath(NETWORK_FILE)); new TransitScheduleWriter(scenario.getTransitSchedule()).writeFile( directoryUtil.buildFilePath(TRANSIT_SCHEDULE_FILE)); diff --git a/src/main/java/ch/sbb/rssched/client/pipeline/scenario/ScenarioPipeline.java b/src/main/java/ch/sbb/rssched/client/pipeline/scenario/ScenarioPipeline.java index 5c8ae4a..6dc476c 100644 --- a/src/main/java/ch/sbb/rssched/client/pipeline/scenario/ScenarioPipeline.java +++ b/src/main/java/ch/sbb/rssched/client/pipeline/scenario/ScenarioPipeline.java @@ -17,12 +17,13 @@ public class ScenarioPipeline extends Pipeline { /** * Constructs a RepPipeline with the specified parameters. * + * @param instanceId the ID of the RSSched instance (=request) to solve * @param runId the ID of the scenario run * @param inputDirectory the input directory containing the scenario data (output files of the simulation) * @param outputDirectory the output directory to export the processed scenario files * @param filterStrategy the strategy for filtering transit lines */ - public ScenarioPipeline(String runId, String inputDirectory, String outputDirectory, FilterStrategy filterStrategy) { + public ScenarioPipeline(String instanceId, String runId, String inputDirectory, String outputDirectory, FilterStrategy filterStrategy) { // set source super(new ScenarioSource(runId, inputDirectory)); // filter transit lines @@ -34,7 +35,7 @@ public ScenarioPipeline(String runId, String inputDirectory, String outputDirect // clear attributes addFilter(new AttributeRemover()); // add sink - addSink(new LineSelectionCSVWriter(outputDirectory)); - addSink(new ScenarioExporter(outputDirectory)); + addSink(new LineSelectionCSVWriter(outputDirectory, instanceId)); + addSink(new ScenarioExporter(outputDirectory, instanceId)); } } diff --git a/src/main/java/ch/sbb/rssched/client/pipeline/utils/io/OutputDirectoryManager.java b/src/main/java/ch/sbb/rssched/client/pipeline/utils/io/OutputDirectoryManager.java index 1f6cced..7be3204 100644 --- a/src/main/java/ch/sbb/rssched/client/pipeline/utils/io/OutputDirectoryManager.java +++ b/src/main/java/ch/sbb/rssched/client/pipeline/utils/io/OutputDirectoryManager.java @@ -15,10 +15,12 @@ public class OutputDirectoryManager { private static final String DIRECTORY_PREFIX = "rssched"; @Getter private final String path; + private final String instanceId; private final String runId; - public OutputDirectoryManager(String outputDirectory, String runId) { - this.path = String.format("%s/%s_%s", outputDirectory, DIRECTORY_PREFIX, runId); + public OutputDirectoryManager(String outputDirectory, String runId, String instanceId) { + this.instanceId = instanceId; + this.path = String.format("%s/%s_%s/%s", outputDirectory, DIRECTORY_PREFIX, runId, instanceId); this.runId = runId; createDirectory(path); } @@ -34,7 +36,7 @@ private static void createDirectory(String path) { } public String buildFilePath(String fileName) { - return String.format("%s/%s.%s", path, runId, fileName); + return String.format("%s/%s.%s.%s", path, instanceId, runId, fileName); } } diff --git a/src/test/java/ch/sbb/rssched/client/RsschedMatsimClientIT.java b/src/test/java/ch/sbb/rssched/client/RsschedMatsimClientIT.java index 94363b3..f49f9ff 100644 --- a/src/test/java/ch/sbb/rssched/client/RsschedMatsimClientIT.java +++ b/src/test/java/ch/sbb/rssched/client/RsschedMatsimClientIT.java @@ -49,7 +49,7 @@ void testWithConfigBuilder() { }; // build request config - RsschedRequestConfig.Builder builder = RsschedRequestConfig.builder() + RsschedRequestConfig.Builder builder = RsschedRequestConfig.builder().setInstanceId("it_builder") .setInputDirectory(MatsimRun.INPUT_DIRECTORY).setOutputDirectory(MatsimRun.OUTPUT_DIRECTORY) .setRunId(MatsimRun.ID).setFilterStrategy(filterStrategy); diff --git a/src/test/java/ch/sbb/rssched/client/config/RsschedRequestConfigReaderIT.java b/src/test/java/ch/sbb/rssched/client/config/RsschedRequestConfigReaderIT.java index 2c81b29..1195391 100644 --- a/src/test/java/ch/sbb/rssched/client/config/RsschedRequestConfigReaderIT.java +++ b/src/test/java/ch/sbb/rssched/client/config/RsschedRequestConfigReaderIT.java @@ -1,7 +1,5 @@ package ch.sbb.rssched.client.config; -import ch.sbb.rssched.client.config.RsschedRequestConfig; -import ch.sbb.rssched.client.config.RsschedRequestConfigReader; import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; @@ -26,9 +24,10 @@ void shouldReadConfigFile() throws IOException { RsschedRequestConfig config = reader.readExcelFile(filePath.getPath()); assertNotNull(config); + assertEquals("rss001", config.getInstanceId()); assertEquals("run_1", config.getRunId()); assertEquals("input/folder/path", config.getInputDirectory()); - assertEquals("output/folder/path/rss001", config.getOutputDirectory()); + assertEquals("output/folder/path", config.getOutputDirectory()); // global settings assertEquals(0.1, config.getGlobal().getSampleSize()); diff --git a/src/test/resources/ch/sbb/rssched/client/config/request_config.xlsx b/src/test/resources/ch/sbb/rssched/client/config/request_config.xlsx index 8e60d0844c71abd258c994b28e1b0353e641fc49..6775cd0c51e12b9fba295820c5cd435e85861607 100644 GIT binary patch delta 4521 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 Date: Tue, 11 Jun 2024 17:06:29 +0200 Subject: [PATCH 6/6] Additionally export request configuration --- src/main/java/ch/sbb/rssched/Application.java | 2 - .../client/config/RsschedRequestConfig.java | 18 +++++++++ .../pipeline/request/RequestConfigWriter.java | 39 +++++++++++++++++++ .../pipeline/request/RequestJSONWriter.java | 2 - .../pipeline/request/RequestPipeline.java | 1 + .../config/RsschedRequestConfigReaderIT.java | 1 - 6 files changed, 58 insertions(+), 5 deletions(-) create mode 100644 src/main/java/ch/sbb/rssched/client/pipeline/request/RequestConfigWriter.java diff --git a/src/main/java/ch/sbb/rssched/Application.java b/src/main/java/ch/sbb/rssched/Application.java index 235340c..6ca6497 100644 --- a/src/main/java/ch/sbb/rssched/Application.java +++ b/src/main/java/ch/sbb/rssched/Application.java @@ -50,8 +50,6 @@ public class Application { // TODO: Export also RSSched configuration excel to output folder - // TODO: Use instance ID for file paths. - public static final String APP_CMD_SYNTAX = "rssched-matsim-client "; public static final String DEFAULT_HOST = "http://localhost"; public static final String DEFAULT_PORT = "3000"; diff --git a/src/main/java/ch/sbb/rssched/client/config/RsschedRequestConfig.java b/src/main/java/ch/sbb/rssched/client/config/RsschedRequestConfig.java index f38cc44..0ce4cca 100644 --- a/src/main/java/ch/sbb/rssched/client/config/RsschedRequestConfig.java +++ b/src/main/java/ch/sbb/rssched/client/config/RsschedRequestConfig.java @@ -2,6 +2,12 @@ import ch.sbb.rssched.client.config.selection.FilterStrategy; import ch.sbb.rssched.client.config.selection.NoFilterStrategy; +import com.fasterxml.jackson.annotation.JsonIgnore; +import com.fasterxml.jackson.core.JsonProcessingException; +import com.fasterxml.jackson.databind.ObjectMapper; +import com.fasterxml.jackson.databind.SerializationFeature; +import com.fasterxml.jackson.datatype.jdk8.Jdk8Module; +import com.fasterxml.jackson.datatype.jsr310.JavaTimeModule; import lombok.AccessLevel; import lombok.Getter; import lombok.NoArgsConstructor; @@ -39,6 +45,15 @@ public static Builder builder() { return new Builder(); } + public String toJSON() throws JsonProcessingException { + ObjectMapper mapper = new ObjectMapper(); + mapper.registerModule(new Jdk8Module()); + mapper.registerModule(new JavaTimeModule()); + mapper.disable(SerializationFeature.WRITE_DATES_AS_TIMESTAMPS); // Ensure dates are written in ISO 8601 format + mapper.enable(SerializationFeature.INDENT_OUTPUT); + return mapper.writeValueAsString(this); + } + /** * Builder class for constructing a RequestConfig instance with customized settings. Allows addition of depots, * shunting locations, and maintenance slots. @@ -138,10 +153,13 @@ public static class Global { * Note: The transit vehicle type ids must match / exist in the matsim scenario. */ private final Set vehicleTypes = new HashSet<>(); + /** * The filter strategy to filter transit lines of interest, default is no filter. */ + @JsonIgnore private FilterStrategy filterStrategy = new NoFilterStrategy(); + /** * The sample size of the run, needed to scale to 100% for the demand. */ diff --git a/src/main/java/ch/sbb/rssched/client/pipeline/request/RequestConfigWriter.java b/src/main/java/ch/sbb/rssched/client/pipeline/request/RequestConfigWriter.java new file mode 100644 index 0000000..b951048 --- /dev/null +++ b/src/main/java/ch/sbb/rssched/client/pipeline/request/RequestConfigWriter.java @@ -0,0 +1,39 @@ +package ch.sbb.rssched.client.pipeline.request; + +import ch.sbb.rssched.client.config.RsschedRequestConfig; +import ch.sbb.rssched.client.pipeline.core.ResultSink; +import ch.sbb.rssched.client.pipeline.utils.io.OutputDirectoryManager; +import lombok.extern.log4j.Log4j2; + +import java.io.FileWriter; +import java.io.IOException; + + +/** + * Request config JSON writer + *

+ * Writes the scheduler request configuration to a JSON file in the specified output directory. + * + * @author munterfi + */ +@Log4j2 +public class RequestConfigWriter implements ResultSink { + private static final String REQUEST_CONFIG_FILE_NAME = "scheduler_request_config.json"; + private final RsschedRequestConfig config; + + public RequestConfigWriter(RsschedRequestConfig config) { + this.config = config; + } + + @Override + public void process(RequestPipe pipe) { + String filePath = new OutputDirectoryManager(config.getOutputDirectory(), pipe.getRunId(), + config.getInstanceId()).buildFilePath(REQUEST_CONFIG_FILE_NAME); + log.info("Exporting request config JSON to {}", filePath); + try (FileWriter fileWriter = new FileWriter(filePath)) { + fileWriter.write(config.toJSON()); + } catch (IOException e) { + throw new RuntimeException("Error writing the JSON file: " + e.getMessage(), e); + } + } +} diff --git a/src/main/java/ch/sbb/rssched/client/pipeline/request/RequestJSONWriter.java b/src/main/java/ch/sbb/rssched/client/pipeline/request/RequestJSONWriter.java index 6b5bd47..93fec5b 100644 --- a/src/main/java/ch/sbb/rssched/client/pipeline/request/RequestJSONWriter.java +++ b/src/main/java/ch/sbb/rssched/client/pipeline/request/RequestJSONWriter.java @@ -11,8 +11,6 @@ * Request JSON writer *

* Writes the scheduler request to a JSON file in the specified output directory. - *

- * Note: Although this would be a sink, * * @author munterfi */ diff --git a/src/main/java/ch/sbb/rssched/client/pipeline/request/RequestPipeline.java b/src/main/java/ch/sbb/rssched/client/pipeline/request/RequestPipeline.java index fa32cde..8384552 100644 --- a/src/main/java/ch/sbb/rssched/client/pipeline/request/RequestPipeline.java +++ b/src/main/java/ch/sbb/rssched/client/pipeline/request/RequestPipeline.java @@ -32,6 +32,7 @@ public RequestPipeline(RsschedRequestConfig config) { // add filter addFilter(new RequestComposer(config)); // add sink + addSink(new RequestConfigWriter(config)); addSink(new RequestJSONWriter(config.getOutputDirectory(), config.getInstanceId())); } } diff --git a/src/test/java/ch/sbb/rssched/client/config/RsschedRequestConfigReaderIT.java b/src/test/java/ch/sbb/rssched/client/config/RsschedRequestConfigReaderIT.java index 1195391..b13b550 100644 --- a/src/test/java/ch/sbb/rssched/client/config/RsschedRequestConfigReaderIT.java +++ b/src/test/java/ch/sbb/rssched/client/config/RsschedRequestConfigReaderIT.java @@ -39,7 +39,6 @@ void shouldReadConfigFile() throws IOException { assertEquals(999, config.getDepot().getDefaultCapacity()); assertEquals("dpt_", config.getDepot().getDefaultIdPrefix()); assertFalse(config.getDepot().isCreateAtTerminalLocations()); - } }