From 84b81e29fe243cb5e0310bcc954baeba5ccecf5c Mon Sep 17 00:00:00 2001 From: =?utf8?q?Roland=20H=C3=A4der?= Date: Sat, 15 Apr 2017 23:57:41 +0200 Subject: [PATCH] Continued and discontinued: - jshop-ejb and jshop-receipt-ejb had persistence unit files which would make it impossible to have two shops at the same system. Well, mostly not what you want because you want performance, but who knows? MIME-Version: 1.0 Content-Type: text/plain; charset=utf8 Content-Transfer-Encoding: 8bit Signed-off-by: Roland Häder --- lib/gnu-jpdf/gnujpdf-1.7.0.jar | Bin 0 -> 47858 bytes lib/jproduct-core.jar | Bin 0 -> 21552 bytes lib/jshop-receipt-lib.jar | Bin 0 -> 1863 bytes lib/nblibraries.properties | 5 + nbproject/build-impl.xml | 28 ++- nbproject/project.properties | 7 + nbproject/project.xml | 3 + .../beans/checkout/CheckoutMessageBean.java | 206 ++++++++++++++++++ .../model/basket/BasketSessionBean.java | 117 ++++++++++ .../category/AdminCategorySessionBean.java | 130 +++++++++++ .../model/category/CategorySessionBean.java | 72 ++++++ .../customer/ShopCustomerSessionBean.java | 151 +++++++++++++ .../product/AdminProductSessionBean.java | 163 ++++++++++++++ .../model/product/ProductSessionBean.java | 103 +++++++++ .../model/receipt/PdfReceiptSessionBean.java | 136 ++++++++++++ .../pizzaservice/receipt/PdfReceiptBean.java | 56 +++++ .../pizzaservice/receipt/ReceiptFactory.java | 55 +++++ 17 files changed, 1224 insertions(+), 8 deletions(-) create mode 100644 lib/gnu-jpdf/gnujpdf-1.7.0.jar create mode 100644 lib/jproduct-core.jar create mode 100644 lib/jshop-receipt-lib.jar create mode 100644 src/java/org/mxchange/pizzaservice/beans/checkout/CheckoutMessageBean.java create mode 100644 src/java/org/mxchange/pizzaservice/model/basket/BasketSessionBean.java create mode 100644 src/java/org/mxchange/pizzaservice/model/category/AdminCategorySessionBean.java create mode 100644 src/java/org/mxchange/pizzaservice/model/category/CategorySessionBean.java create mode 100644 src/java/org/mxchange/pizzaservice/model/customer/ShopCustomerSessionBean.java create mode 100644 src/java/org/mxchange/pizzaservice/model/product/AdminProductSessionBean.java create mode 100644 src/java/org/mxchange/pizzaservice/model/product/ProductSessionBean.java create mode 100644 src/java/org/mxchange/pizzaservice/model/receipt/PdfReceiptSessionBean.java create mode 100644 src/java/org/mxchange/pizzaservice/receipt/PdfReceiptBean.java create mode 100644 src/java/org/mxchange/pizzaservice/receipt/ReceiptFactory.java diff --git a/lib/gnu-jpdf/gnujpdf-1.7.0.jar b/lib/gnu-jpdf/gnujpdf-1.7.0.jar new file mode 100644 index 0000000000000000000000000000000000000000..8b325eacfa1cd349bd7dde1a01d9c6acf6d66b61 GIT binary patch literal 47858 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℞9MJ=n`wKx>y+csGbx_@81@MCYj>kG6@^%UJ%6(CUj)3RFkW zpBn6meS-UGMjpF2+O*L0Hztt6553pC_s@}{2eY{}mz#<~^-TYxE}Ob`YF|N0Cv8NsSzO*!vv_N`1ug%E#C*x# z_GlJWCz4x(%4%1`d&cB?*O|QJ06*F3oJgcYp33`oTJ(GB9lUNeuI*JdKpTDjBwIXT7(h>8HdctDYAkMNkMqF!< zb1BaHJv|2c$5&)onXn3pb&PN~C=v2QVS+Udv5COU8_8iT%Kq3J$}uvl6U#TtpHxz^}En*~s0!3CV1O`H5!+~omZPsaH*Tr`Q z-QhY=T(E^}RS%T{A4T#8bZu){&)?^HrL$90-(UML`@R4ET~|KhTNiMq*J|&V|8J|a z*?ec?&x_0Bh?JgBd#@`qUAVSwSo2LC8{Hp8rzWZKV>k?t44f4aCieA!$6Jd0#1SRX zPJ+(gU52v2V#lclXRaILK;w$SL~HbBmo26GRZ}k!=JvwDwV^(`Sl&e~_t$?zJ|o0N zG~b6Vs7kcsWf1XgDTfr9nOmC{T#(Y0wGMb|%Pl#f2f1F4VD6@M3Z_o{H6}z1(`_3J zT=?;D3}+QFdH4VeK+-+o8Joe#E_a}g>H*`0qFu!$kw)-G|6H^By zR)3>GXQ#4x`}Tw@D{{o!#Fg6X9)P%)xa;roVZ`vVxrx2ePuHt#`D*?bG*d7}-%rN$ zPuu3mP5g#0MSfr`qE#Dnn{n{MEfGxUVl$MLTvIN4$)TtDfddwU^IL*q0<-l z@r91@sf>DW?e*gBg-AAN<$otg#&{3;!iVKdGM+#A$r$+sP}&pGa&9(0x-mArUf=jY zB>U8|bgsK0ECBLne(kxn`jj>w2v^@25`2uv<=_a{=3o8RIKzc4jVS^lV4 z28)jePaF})JS(^72iM%}``}q0PX=qe7-t4XT$s&GG(#zAC~3}#Ec0mhNSO3IcZ#k_lu(p`NHh!k^gfc)-f{jqTP{OlzS054UNdrZT~iV8o3 z8EP0P5H2U|?yl>N`@%;$Gj?#-7QC<1M^qg3e|9U@S4kUNYI zN~TfjExP>JfXe;i;pGqHu7k$Xnv09IHx9j4eVEGyL7ny)JzE2&$Z%;&~XAnrWC8H%E-(;g4}4Q(t+- z3s8dEYQl@FN9oT(u+oqAh0L$j4>mnTjiqx-kHJd|Pd7qUVHunx8}TcEM_OXyCDY3< zjX5F4%tfnJ>zrrX?qYu^zVcc7Up)8A4W*Ch3wVx=adAr!(A4?#UB2N5(9O9(@LGHG zV<|&;4sa9&rA1G_f;|c3^IMpYiaXBag?<^Z3Npk$3UHC16I4AikQFDNr~+yzLa>_z zqFBzpmut;U`5cs|OzI&j=;4b=p*e%@w#nQ_&!N4x5yH+(PeQCenHFJj3o4ap&?Sn^ zFX12#Gj4Qng(QcQTqx)|Pk7DPeUmnpTihj<+YcLESaA0CuEyjCO-6S~y3aiRn0HjV z(CpuICWgp>{-_{Bk^{ZA@W6vlzKH8m8<3AZKT+;lP2m zm2l&Y$y+zh1Yn%0SmKpv=R5ai66zn+hkR~$Jc?A&JS!}l)iC6kj>aCVX^g^5KlCXc zZdjlD% zn~W4MFGHfAbUBZ#_(CBVFMmVGz2e{(co0^xm;YK>*WX=(5MhNHd@i|+k(uUOwf>rV z#l%$N!H3fznNC-D#P6BNrDeW!N!zIGLR(tB)@0Dow2yZiN<&mOJPJR0z{3bWfuL0( zY#1hH?}K2jPhE{kqcu*#6(xG(vrc2;N!kYjOf6q@g3E|g#uf!bDsFth4XA`t{_B@$ zBw}sv0g0v9u3O&Fj@#~#kuCz&kGCtqZNDSwk7-ot%Kd87M*z2_++`PliOZG zXe8UTc7e22z8HT=S)#8me;)U@E<2O1Pwd$JLMc&5R0JiWW>N5oFOm5ONK>)RF%VJQw1{=mjmE1+Om-6mRlvJ=0j5{;fM)~`UV+!2 zWmE;MIAg~;vVqi3oUO~(!X~;9i8f!xry=EuKr*U&@Y^eSuvA%y?DmJ#H%>ZtOCega ziHXA8tA2oggG&^OQgb|-g>znfliRC(&}fWQhb6j58lje+STzqdT8 z;HWXgC$$Y9j0%{?Q&iy#6Om(mo{OiTk7htP-2JjoOf=`-d{-E={J?9rf4LwlLJ}v@ zp=#p9TgZ6V!)RI!cPWk2`bGW|W2ABI!_3?1PMfJ)Km z!>V67Xz?8uMo{Fqa5!EtlA!jXw%sRPPzRuC@vVb^;hGOA-b%2d8`o4<+cp5XfMk#e z5@5HhQtxix9%mMj;WudW+19RC-r-RrRa`o6*B;6Q&Rpb1YSIcGu!P6*%A`>s&G{ky zLCszh71M?M@|V}*!#5}#;Jost_-Q34r*_;@t9Ixk2fnzp@bA$5;>VpUvgtp$5{pXa z?LWPOqQ~z~N(7k~vN3|X#_tdPIR}uV2Z!#pwXxJmX_w0DDQ{zbcaIOoNjuOwUWd^R{ul%tt>cv^99Ay)Hqs;7 zK8b&D+srZUB5fHjcDC&cYac6zgf1L^g0L|6gTyo1s41J-^JC583CD1Gz{FR1g!3o# zk?mGg57uSd2EhCqQu4VPk-43J5=Ui-7bH(k7T0sX{`CmhuD>JvBQ4hS~T|O zfG1e#m>Okkwm3S4qwTjHOjN&1tCs5V_#Ruq#iRvGiDIFk=aq)Uwk?jG-OFk-Tg0l!O9@k+GOq!&f00fl{K5#emDnH50te8@cL3Spf^#=&%5f z6FakD4a|U#bg)ix#m2bQ#T~~_xk($-80S7b%$6+^noN1N9Bk5-uEG7}())S^-6>S@ z$J)^YDl9IeZ^*`k!{i2eyNHoYUfzqzYNrea`Rv$;A5}C7hfmSTtVq$YOFGPIzdZe_ z2nQu0B*$A^R!&GpGeUm4kyKhc!=*j!#&Gj}xFiUOj>-MftA_TGWjQGJ{P-kgkkO_K z5FE0{XDFK^PMkVX{PUNc*Y@b2-&Di?Pyi-cx{LkAjJv@8TXs*|P5q4~dp>)L{NG&h z0iNfo(H*kK>!^^W5Naab7iH}^Ly0=}3*yuJVt1h}Ed;n)A(lRs^+B5?&@R+pheA*) zLI>9YmKfzoel$WO;20NDe+^_0%PBD;a7a|y{eq#DRgk2>+PrYVS%k^UQl^6%kqg-- zwxa$;dITJ`*jSl#1=0jrH5Eio7MF6oZg#j6w)Y0zngRV=O(-0FkI?;ze1(dWp7(Jz zBWsO;K=b$T$r2;n7Y~zt2R9u@klo{Ni8L`fv?4zeJ@lLVhfb-_z~)bpV3vb>47L3d z>!gE_kFV4XC4v0vHLw8r=gt*csrgK?ufpLAA2$ z<52Am@-h)?JpkhD9~))uNnsk0+zxc}6b*$g zV1Xr;-!c}Xuf~E&jY`PTPo{>Y>82YSsH`~MogJKt*lW&qb;kRhHI)?&EtNGbRA`8s`#7#$%M{#FfVw6jn-6FnY+Qvin+%jn$ zmk)_FfTCy6er^ztnO6=s0XTzraUx&* z)2#mFBa%A@c&J>vZ9O;1FRZFSSP;kM zmR-ZwD#+h}=uq6s(czcs_U~P38Ku1=<3^(WQLY53jP%wK>6vJlM;qXIG2|P;F{MwPx)l z*fSC(#xj|LR>N@ldz&+5rImSaCC)jsB7KG%Tr)qA>p}0Z>TJuVavjrd<>i`2ee#nU zjB}$5WF$A-Zp9^=GajYEWSymJL(B(plz+zFQRSTT(?yTcJoupY{W*o@yySwt)tzG9 z=%$NuJ_T?>4%7|EFb`f=Mj~6IP&RGa^n;7I;|4x*BEgG54%!Tkbpii~nOx8z2WGZp_ePI>S& z!Hi{Cf?#jxXr0pWiHxXW7^x|0u`F7-rQN^M+)d;}H$maN#O3%MvRI_CzUBEy)w1GJ zxNDdr`oHI~Ze;%PQ!=v$ar$v+W}$RMW-;zg#6~Su+E>7`ed#!mu|MT<%nO@yP>6vw zhYB@l8r)RCGRxh=Lb!5#Q9HGNmm5O36QPR&@UsHsdh950aLEKZ%|A|{80y{&vObby z{rrgP{w2w*IE#^#1?NJ^UDM4})9FlulyRu)4c>M}LD3#OPBfuU$N-{!5V)p#;%Znz zNI2-*u@s>pg|Lc8yyJe%W4Bcw$_HH6)B4eT=VR0Y-VTyp)wXcf%thawikd5bB4%Lb zWPha9ky=`xxeuzm0K2bs=z6@}oep3mN*)0OIa#cFgvvgKK}LZ)=AxuO0NlxX#^I9k$LXoy$CK{y9`DYAX*pCZi=AuP`Rh8#E<&&xH>- z85-}ndVi@$;G7e5h@@kpa8R%{>Dmn6()22g3u&t|+Bpd1TW{N+sgt&aL3Wo8eQ^f2 z*R*-iFM@WW10;*jX#yxg{1Dx@d2N7%_e;iOM+!ObvI`@VF*b`A zy(f{h&fIAfTL@$my0w$+em1tR9OVaAr{!v8Et})+`pmYWmRe${97;eTBgQZ&GR!mv!6X*e$!@#=*mVQ zm1#Lg9t%!TU8)GaK%{-SGBb6#QM%ODr<7#;xD6y$^iTxIF277N?bcYA@!EGV4mQ1& zRQ5A%d^lI58R$97q~%a>Ayt1F=z}q9c*(r59cR3zXf}Mzw5Dk$%BXBf-#k1ne!hSa z5`qb=g^XYr?<(OhX0Qq~B3q%<4f*vuTxtQU;-I84s+E1n!Sb&ZGsZzayTa z`2f(fdaz_r=o#;$Yn*U(>T@?dltDd7mpDR;JWVeKA7iriC9NoF8a4($Z8~O1S>}<8 z&IfN9>yz6y*M|t@2HVuWgfn(z&)ho(488xaqRohBS^q6>72TDHW32zr8+Gq&F+Rk( zgz!-nGkQU(=n4MalizVk_VR{(Dwh1x-t}h;&B1v=oru*kC>?qz1}I+)QN7YQ`hNQ) zuzTVdlzTLPV!apsjb!&5$!%I+iMU1D{u!qY?g~CkMZ5Koxn&%LP%T#=ela0ixSFp( z4~~gcr#_uNAPY~1T+Za#5Tgw6$+_qYU$P9nU~|Rb?c6_Hc%Ovp?A|opZHEnV1~2lJ zaIYOgkZ0h);hC-4Km405%>yn?8C;u)3f5)=55el?9P*SQuQ0gC+W(kkxJF&?2R+NC z^jDLiy@;!0hTeW>E8N|;KNLuI{Uaj2l;5dww68OLJH4+7ihjb)XF_IZI-r{xv_mjR zgXl&z%EFK@VRx0t&-~As-?4=fTfR)>h#r}*dBa+_pd?`uTW-D1J$crKONwtEO1rBA zQ~l#&1o^T_!8z6Bn^nw-*8q|0bq-OrS;9q-7N@eZSVA-F>}S4XL| z@JEkZk2hcwBBuMhuda9%Nc|}CCbfTj*Mz?o_IU6%UNTTE(n;!*_bcVscrIXQT<^Sg zx-5jSH!2>po^H4h!yG=jv#L?JEk4NyOG_hTYd=p70i%o4sNVpO-_tA9e;ll_BpBis zq@Pys@fed?7B2prz#_3{Tmoak?mszQ_3^d%iM6}K3v5Rm@=n3C_fZyZiV;T*1GLM76rj;w^!NOz@mjd4(qV9nRa(yJBo38WW;+_@tosL|!{A}TVclk8uT8N-nJA*r zC=Ce6j;MdCKu9S`usGdPRo^m8LkQZ_F0cHF+z%9F+aq}%EcsPD=q#uOo?+1cVR`jF zDx4L9lmpvOZQP|j5nfkU(W|<=)>gJF?v$K z0vSVEHCh-{c9Mj!%^(Q$qlN@`+B@OT3$TfSOnb%CyL|Z!v*%MG*?%=Bt5wL}ki00q*0{I@Xyx;&8qu_gptz0ZUT{9V zN$eL6I2p{$kFx(K&KKF0feT>+BBZ>)&ts+uj62b5sEZQvfwu z>F5zI=;M~S@eIrB=W5rQE<)Tby&($iXa?NQM6aXh%_K1kelkpNutuv-#ygMH9S}Ob zYLRZvD(wIa7D?V%<^3pqNS`YAGiP2u;H6gz0*7@trf%we_YK=mPT4wDTAz}-hHl;O zM4vc#+1OTY9BnS6!UD=f|0|&St_`Sna{m1j*b9tQ}i(Y7+)@zL-sS2_tnMtR|rXf=|CXCjF(47S9beH<8bGkcv1etOF_6vT5$qVP_5JiaE+y3}3!>KRw54C|6r@Qn@LZ6*cv>uhXtmWQ6#UqzAt(|o&6ITN*mDw zpMk*MWCcmcMGL7Qf8HGTYZKu9%Mg(EK@O@GA&td|Y9AJpL>6g>bG{ zGEc@dBY@)-OwCh@jKfV*jEQ=vY^1^ruO)7^&wv%RDLZQI`x>jc7IE*8w2IHt@6MmM zr5+D8QyU1}1%dJ_Zv+Nb?!gwAVb(~~vNb)F?S(5prw&(8bp6mwpI0tmk2}u6$l^5) z3sA5m?Lk(=MP)1qmhGg*d*!Hr0WI40Lm_>%U$rAb?7q!>C| zo$vAe$o~A*Xq9Gbtti3Ru|=?jJ$5ptAIyCNsgMxS$9KRMkP$cd+c1Nto`4XDTJMgq zC}P6=RZ1wea55368NiYs5+05-}r=yTRtXkZlBcjmL7hNq5t%mjC${`2EnHA z=-EFh9y>JVSazrJuQsjcjYoW9#JZBuVq3wgqA69G2yBXl+zyK@<+veofC_(>hrgQc z2mAitI{u74&f3qVF6*2$9Nb2xDzOd-`5&mn8$gD7c^$*-9-&M_t%3axzCS_-2@jqdAb?6)w3*@hW>;wEajK-iJMokG}(Ua!H1&xN< z>RL0Z3^GBW%eU@#9Jo^ydq-hr8l}xe;5s#}4+WZb71A|oATk)8n&)aQ+ZHu#4?UF+ z0x_)rR)3Ok^nRPhx-uPlxO+4C9;ZYRe`?ZYnQoTs^Wdr9IO8eZcyCVaVto3Bi0sC~ z*_&NcKscB?;)ZOfZ3eZCc~%9t?Ome8RYL7W0(iXyM|Sbyu9R=&yT18#G-a%B1kj^u zQ>J=P`&%Gfy)`J?#l{@llhvqjS0>j2Wm~gJ|12ES0g$G?LL-o7zLEn{=+JnHj?%-R zIp)~{Qz?)ycW@z<0HfC1>gf1gVrp7?)!ln2Eu1m=u_6bH!Igy}cX*!iXdKr&zL zVHm!NT~-uo6O~>C-Z4O`|ZoNHoT@ za>=%M0&wy5w5I0fscSH|2d2m|l@{-Di;psn9XZ_6;a&2L)}5V~>sxt8k}#Y_8RAji zYpeu{<`Ug%38lT@(xG-NbqKAxSAEk`8n>e=YVK^j#wKjD!6@9$%}myk{)FWjhi8D^ zS?g(^qqseM5)_*rMTa$p=0h(bW^hjuwH7|Xif!3A4#>9hthI5ld5&Srfr^(l}@Vz7YAd=6q;XC^trt4u6Zfedi03#T>?JnzB zyP<)oLfd#CG^<=AxxJdS7ik_Rj8+vR`pPw$|LiUzPTojCsG#*TDg;=WUUf-Zy4w=H zwwRf%3#~ds{-#7ah8%Rj@-^nWT7i=+lU_Zb+Nklw3_f6RhyDGh5Bodn*TS{KNZvp| z`Iz?UuVITp9*AJ|ru3#-;Ym%Stk>P=L+B}NRwF76=~@==yA&jscVcy4#X(lCI;9_o z)*?i8Q9O#?C*&)Kx2}9Wv>o9`>ey)1ql$*D@ppdlJZpfZDbL z2_qkENmUqY3!rwZTg82_T5*C?FI2I)&@BssGE=e+&DOGE6x!;UQt~^+zH4DtvjI+F zbe3x#`rf5=BdtX$C+_itaX^J86O6iVW|pqj6y`KNd3VH>mf6MR1C~b3B?*2s(WM+F zpKE8_N|v`rTP}!F9kd)9)Kpdm;bL_P9VzQ;ARBX(jjg*q0F!Xe1w&1!tIcvm#@DVx z95uOv#$xUFes}nvMa-4X7z#q53Yj)rEFgSk7s*U3lx?1BAS;8U%-WM&U%W0ZS$;)q zh;8Btspe-^27|d}dmbzL(KSpZn_$cIk?*i9f=BI~P6?mIW_8AANY{;#~)EH?M-mG(pVHh_oQMhur+dO3nNa zWuHf|#q1F!N;z9pQ2LrLASbZfgX0Q)LDDhrN^IM3jb)6~pg}~Bn`QlqBRO*AQc{^Q zwVVMQgRiRRuRA&lpk?_q)Wmj;#(PArqA)XDD603iSh(In%fJ+*v?SYXupjt`iI)FM z+F54SG$WT_)Ptvr-{k#h6KPn5`Bp-(I|UstI0~aPVqCS+Bs;He?xt)xwIyet;#*T~ zrRq;Sd^>oFc_`Ng5B`#fx1~$CW!|Ekj$=-SvubEnPno!W*48?qvo|DzYkRmg5GHCH z9iJV`vu-u#C|y9edXhe%KyduYQRws(OO$4pfgiX+GxK>}T)Lg#cvw1B4?De_ZPeYI zqdt=MSgV1Y(6Y-9#-6~Kozy)C`Ih3mk1}c&A z$&kuAnsCKeDIb(sh-jNXU975C<^{U#uzFfUXVWdK24;zbXt^j9zc+ak1I6CVT7`xJ z!mr}MW`yizhO$OOi~F4x$S>SVajh(TK#n`m|i@xlvs*Hn#73QI}2QK|t z^jFzeDvzSUxe{aIJ0mk8e$lrCfJy&iK4GJXCu%mqirsTWSIN*HUZNpUlO+v8mZjVV zz(2nD0+({muHSe-6ThDoZ@QL@85mj&CTaUo7|7-HIgUI~ z7QMuoWLS{;AaS|x??mP;*;0_hci%hN_w&0_!0E8*>a4xqUhDHE9gW zUdo-Db?_~&<<==Rrg(XV*jp_JN(Ucu&p>w+?Odnp3zi%yD&X%ww#rddrSjOiTXjh(_IBFi48}h)q3WMG-mAczs<0 zkIxYe2X%#czGgCI{{YT~S-U6hRnqUy2}>!gwq^$(T4HHSiMoj6X?|s(Nm9e<$X$Ml z?+tx3gj{JDvuML0X+hWaz!L&Ya)+2^BugC8bFrwrDI@ zKmjWT%$j6`AVv~C9a2-9;ZOjEj*2o_Up5}}ZJ8Lk^F#n=kv_Wp0Zqy#O$t{eW|LVu z{f5I4$)hEFr|KJz&X|dp+~1bN!UHKmHC9gQT;(IZ)-5Z#l~4~Pl;TH}Z7E4s(oU$T zXKWvA6OfTwGdiyIFk{p7#gi1xK8cW}TVMIN;eh|(7A;jRYfpZsA5p&(Y5!^am$El^ z`0wbW%7*fyBAVVAy%iM95ko-*Rap(&zMgQ3Gcp*x_F))sHC&rPj#5heQ`!OzkI?tN z-{Iz`uk$9a+(*ON(~7o*fxQ36$LG&JI(Jimq524uJ>~eOkxTkCKgZJ=-|nd> zbi66wNDjb@FR>vIh>|CznWC6bPiCYw5FM%pJ&WB#VXQX<3j$qy*3)JSQZem!5K>5p z^H8bpe5u{dLn%bJQMTvIb+x=Hnk=7l-09bJ0h53*m25Iu%SFawP_?oN4x&WgL`u|Z zss_bVlAC_$*l7Jb=CdY5o8n@-WHD$A%m8K~A-6VGEb&rZJ84m$r3Z~{{Q0pgf&}-n z#3$!U?|rqlV~F4`xmL@&;fy1T;m8!{m;V0k#AxH1qmB9&azo)R%Ytn!71n4*uo6f5 zs%(9xX;T!RT5+4T5<4;@dY6dOP+Bl{7sic*F!Tl}33evK+{e0VET>MZnpK*d4thfE za`s#7L>^D^YgLyC`(ODb5Cf$LPy1_pcE$V4tnyh zKT1w~h_5ZjE1PBJJA?!h(PxN!A-=fs9uEf5;uF%FEFw)^43OcOG?MjmaSQJ)g;oa6E)Q7?@5O{>!xvFO_%Wq1f4)vT z{>GZKNC2wDecc@NHg%{-ZuaJ9Oq3=86BOo?4?-Li-}NfnT6P7z>S6IU-}&g$e`C?T z{x15kODv~M`Wq=GY6OkQF&9KGqJqM|Y6wXY-d8?RsE+CSI$Dm|78vlq!@m$${kEUq z`1gO`;a~j!NWDlq7?WB2mofamMnSI1hW&Q{n16$d*{PM>YEh^o9EHd!>$k29^nQ>! z5sjc2AKK07?-94ii!qLC9il|BA{4^DU&Q9lq*0TwtzE2n+&=EdfRFR1`1~JN2U-|3 zwbq*b?6FoHPLdQ7w64_>orns;%JbaWL z7K)eu)<_&#EG`WJl&*Gp`F>m+k|HqA_ux&weW#&lEQ*X^KXJ%}&uBlX@9+I)TO7Vl z&xRA3`%TKC59sjPPl^ZFl;f(8Y)Q3A21?}zhWA55yc-T%e7_@{w!(AhvGM4~k} z7*E4u)ibJ!*d584AS)MY+uG9s1jO&gE-5tsJRqYYo=L4pR!2i=&mUd(0)Uks{dSA zPwThIsa2SQ->b!J#7GpXE4gJ`k$0!95$jO&wqLA8VN}zQtM%=I@F{Q%h>hH9iw7p4 z&anc|vi!t_h!VTx;$S5b@qVFv!Wv4yLRDMQ(|S{jV#qOaU-Tqd8`#*VKBbP4XY-k@ z%y_zMFR2#U)h0FN?)_oFH5YGa`eXo6V}yw$f1ih%o+QR#myRmM=27U0UvEV9=sVh0 zrZ3iQ!e=QBX>Lx?y;}Jp~D^qWmAaefdEq*4EYqnms?(7-$(f{K%I5W{6Y2{2I zn!_vONO6ovNU2N|unq93+K}eo6v|t;V;X<#re*n#rOpIax0hMX){FZe$zV z35<+l$A~w(FxDPI#a2i}W?I^wSV#`mKH8t~Tn;afaj|(T@VKsxbTIXe`3I(JIpf^W zl#VhU#g$*wZa(~=-9fkSgDtq52q1LQ8Ue-7q8ry7VF&rZk0}ecX)((4*=i8)KB}%N zD@$pym{8BGBxd)a2Rh(J_(asK#dWb~63eu3vSpJFz5fo6=gAdU2BG02=WwcLY;|7( z#pmMzWral6ws~~?A}De^WF5`3B60nfh2x>S^iP1eU6F$>_znNWO^2FqlPMKci{y>t zeyQ;f%nk$ve!Awl^#rHirj5(k=oBY${DkYe*@Sb|Z`aiP(iM?DZm=6xPL^&;VSDXg zDx5r7uj#I#o=gA8fR=2L46mTx$|64pWUk|HtT5wAgy4u$q!HcOkt|smIsjJ2V3PR? z>`1buPjk86v3b)FL;SZe7loV;FoirNQ9Q4F9@g3`eh6DLU@C{?4sjfg#)w9b1-*{= zA0Eotb#u5~3Qqc@jhV)*(`?s8=x6*pl4lSQUj`*lI#MrT`(RQIo!eV(a1F1p$}VVr zaWAQ^_>}o3X%7|huAAbc_U(?i0rPiouQr@8xdpyW;y_q{?spfP%5LnaTgq2UK-j7A4R=mz_woltf9AgosKJG}feao9 zGRO=i_t6#|q0?y^j1PH|XzO$a1g*Y=3_PJ&iKH{nu7`ep1q%MmNj)MPGKQG-oW1Js zx0r47zPtLKxP0MjiK28tAsyA}yc%*;90@Sd(7w?tZ04p@6YXRNjew$1S{T(sQ(bgt zdAd6mj8Hmi&7oP8T52o|0yC$c?RbNFvNT*2dzeZ3FzXc4&9nx(8FFY3vQ4wdyV&sI zg6Tg~f>W|vu9cZAPqx4;vr`uhYq?1iL-FuW2{XHOJ-Zqm1PiR(DxMnISl7(qv$Z(= zp+nozW3O=JZeBC%C>VWLT2;kL?RRfQZ%qYp^na8QjYn(d-CWai#XzXRA7}0ihft30pV{~-rG-*7YV*4au5}Po2x{4(Ow$p}G7CC;3uYN;L zG!x6khF;lR<2gFBdyxh@;*jy;Ce;SJl9jTE+^_?e6x}I;o(?QjQ*}|C8+05DCOmp? zNVB#_K8aWIJ2;c^!LIv2YwqcMrhYcuBdJTNJZ48*F+*BwIM!U~2v2iv>8WEC4N~ms z@Yo*Q)$)9ElvxZq`|1j?v5Ww1iLYBvotYC1r@Q`-(qleu zTZH+0@ZNj_ME(<4qu}OhYi0jG?RT{o9aIY>|8y|-Cc2_TBB)lyns9ieOCufO8eQoa zp`aqk7CKY-7~;Zjh}`y*U;g@X>tlU{T?>1Eam!=l?4n?a;3MKGqMe01Cz+5Z!5v?w zgGG%w8o*L<}?rq^6iD$^jjPR%~NrLx!rKl~Xdr}z;2SMM(Er^WA3Q+GGrUhm$xFI!23TBI zhn|q}&3ZQW5bcRmctt&Y!$bxqs!;SzKHQ)ku3sr)+Q_=5&v^k{6Z=>(9x*or+ZIl` zLy#l_Xhg$F=0lNxp+UB5p)U(CWV0m5xXR-*8$6SLDD)!7S(~%e!j|j&u)Ko#mE0dy zG52Zcpz|wU?oV^rdvsZII{`cR^Q{ONT2?sryoExn<-BA44ghza$?mtP_rPJd?v6hF zRGdiYXYM^=X+X{=SPE7zD+Y;xQT&gFVwVDsjYoG7@|p(Afu*A30t~6Y46jr5ZEx#3 zkecXJOXj5389HF??`|Qk?p4E0GrdgpVSDwWyOjyK_a@CUuwh_qdiZZ79UI;clneuk zd$XPWAQ%MExD@0C3*1AI;8s2~Rtv(vIjoEhAJ3TmCfKMtNCb-BBix!;aTb7>7G;bS zD3vk?h%%Y(_x7}F=%3=GsrQirQmHAsk3m2RM+z^$#(Z^!i1^s%$3SY$aNU zc?C`BigU53plLIV?yXN$?dWaPtHCue_M;r&8x0|xSITq2>fm;C>sqb_YJInS5wy=( z`H|16!h!-O%vAd&!Lv8us1MZ7C zF#ZE($bz)b;Jq}@@VzQNvr;psU}joET4krN5AB8G0Md1;_^2an7mHcj%X!D~MJV0; zVX<`#Tp4+7(sEyUXwwT-5VMyHQ1vNVBU+ZK;Pe>>7Mi1mv%&iX|GzCpB4bP2m+r$e zu#BREmnJQmy%odLvbjfHL0j_l5po0*_5oXtGVh=y>nPQsfUB zOqF>HX0^eqr_&pKSv6Tqu=800^oJU&Ygn!S8VSsd=H@sQQ36O)=;IfsH>SW9DFt2Y zQ*$4wVx{JH3m2LK5>=IZ$b*%OM^8_0xk(Ea8&C^93RBBRTfi_Y*#W0Bj=$*5uBvz- z3)8L^VqIM}gN@Oy!3s{~Tz$|ApzZC|&NIV74Vd^at5YF@TUxnoI-A_NXk!tQ&`(R$ z`tUJEb4xsqPI(LGpxHdf7G%;Oevg1_+o;tsg@8Vg=!&vB0u{?)sL>jb)HGlguvgRZ zV<|>kqEDYEXw@usm3{(hDP1vEPkw}ep<3zHK>W2Jsv2Ubs8Xg<_q#7I?-@XoRy9z9 zkztwnz;eu4QEs=_*3cI_OE}u8$s1k>XG^J8|-e9$V7j zn=CmSMk>H5D8r#qdTL#bwiTO-Qj^r_1YwrVC#!$fu|Bo&<3a$4RxShD#_s#jC`d*2!g$v8rxl zS1vK3g7>Uzcu2-V^sJjEiJ2{=5LL`(r+t|wf0>qXo?0=RKC-Hw$yk{RSNVke3%Y&Y zR6oGBe2i2*4pv!dRlT9>hu5Oz+0ub@rieGH*mpi#=vJ!afn5q40_FJ!FXP|}fgYmm zj^H@#9TX3_TgY$5N4?2qP-NDc7dn=5m6&VPh^+2sz{!Ie(Jm2vLuskP1gjv=P-c#yo13-*}g|qS#hbWNWgVt57~O z0AvHp$0>?N$7Jwa*6hoNk=%z9r{ut5O<_b%*aDN^Rj1u6v26M8|LSOXncflqcW)$d zjC1JzTjH90OWgmbP;_&3bo=i@(NFc<-U-v2s+`jf5ASi0oPx+{M^Ed2|)ZA9O3)1peg^!RV$g@$du{7 zj+6J9x16`9-rf%cL&n<5)p*L{cFe(d>_p~Dl0&DwBqzeA5*zbxM=PJiJ_noo13(ND?0$oGfhUl?g)e(;UYUM*MS1BFdt| zbi}+rCm0irOE#$vMHk!*9JscGjeQ3*Qz^Nh6MP4wuX>#noW4di&M@XFF4D&!wd!jr zAy@;H7vU1RTy%$-e#(+EyUCGx>k26#oA ztP95Ez&4-Bo!YAEXoJ7FeaBqSnXImNj zRc0<3b5xevrbRHGk#_bdZ5g{VTj`Q>i&O7%sE41E&vC4~*h;m0jXmlb)j_U5`_m>2 z7~>v=)X%k}8kA47z6dN2zPWf+#ZE0JEzdSSX%F`|W#5c=W9JLCht6K6u|5@+7vC_3|^WfeYt2&t%;6j|&axaiY<>6Pf;YLY%pDuYD?nd-v9%1pZUgz)-Q+g@Gy z6DWe)jOI;Z*wMrXYAB-aL;B~FoSQ=GBXFZjF?_Fko*c9kDzirrF%T!Dg~J9Rm4RJG z$A?nex(-s3IgDvClocqZDp+b%2)}^DherRZv(Bn#f#iUi6J;36hlP6Pf6*y%O8#l> zY;{-_2!L%;R?5P8X7kHM34?}Hps<>C7x;{JtrF8%^Zq*RgKd;W)uq=(UW>i@8oSy} zNAAI@`0QVQ??=-6oCN|D^nE)N%9;``D{$hyAM+sh3%TlI*KhACMaVcrYr?;Cg%YR? z*&3jz6Lp1%kadNaoPHKYiHBk$5i3(DYYDMA;m>Di3yXqh6>vVY8PK%HqDM)q*WXxN zJIp<$m;6H_c<{r4g3U)A@2x+BL37`bbe#fbk4YXvWKoVO!p`@L+twP!oE$!uc(hVb z)cRbF-IV;x{0#a%LnylJ!k|~OAby(jRIlS#MUu}dNqtx zVff3Voc*5GUHbk99E*7NBV|_Spk2^EWIK3+(b}ojK8019F}uR?s?`ij88t`9kAHBc z$~8uf3 zgAT>2ZICMjCFfjG^+bAr5*-z_jRlMBeTH_bPfJi8)c)NoPvQE?I3fgqyQN~LT#l-i zKRBB{F;_)2OEn@-k>(flD2^j2z+492DD*-gotpBAdG zOR3N&8<(opGab3x9o-`u^A{LTT~5f<^A^uszKVO5wzT@-LRncouJ~p*J7&Az?w;EI z{TMOiAPvq4Pi8^`SYDGd@MEfy9h$55XF#Akp<^C-OUb8`??;D!6HNiOARIZ{UCZL!9_h8EPB{c$&HRsCw*1Wa-71C$!Tq}iw+&b z3nBW%hLbrjZH=Y4(sJ?h$&?jswXXWgyI5?}Q96u|<&2%Y-RGyAy?Bh)(lSg>BRL2V z8Ck)~V6b6MI9ag~zrB*dS=-!cM5-m;_UI^QNmOZIM(rJ!M$MVIa{6fM{qE=`uJ=U> zzXTz$MIJIGzkcHLbBW&^*|_oz;fZSaU7LW#{DRq`JxfA?NcqOqsdFyvJ{8I< zF;ZK5td~rYU&}!VKPp!G9M?B;p~Fl)k}fF?1ZNg}; z&`!%}KM55s&G1|3+fk;#ewrKK)KyaEH^r!VyyXc?X3La9LK1l7)ssZ78W3#_IAi>` z-~+Q9DpJ!>9UF;u<1v{@%WT4zX!mf$Q;On{JxCr*fG7Cv%`7A7rrLp<20(g@D)t9B zL77v$ZR|2s88hr7=Kn4jen~%mDt@2D+xSg3|IfX||2qu+yD6?=Wr(_h{F&!=VcpF^ zWNT}LJB6G;z5&A>bvgHqrBVseD?k{L8z5nnAd->LhZGgf-j-XOdn2;5T!?8cq32FW z=8{_^mCD|JO5K+G_a=}$Q|+!{Vw$kIC%DdXmXd zs|Q1@|BP4P7xo2=i=qhB7J%d%K2nDyC?rK=<6VIRxCOC|w#8 zGKd!DZq97n6@YxOJQr=yMAW=r*G7I;iJIJ(ra6sMpl4Kn-gZzo~Pqmr@`s+jG-rKALx8ofgM>`!I3j)WI8IjLg!z~> z6;Qz(=qx3$hJzSJL0Mxqg2D^Ovzt*-%fl`Yxu%~2cQKhI;A7?3xg=8`Ec(_mE}*_Z zPvqXYoUMB&5LD_i#O+&Ea^;|?R3i>IxrWBnZxIS8CHt({D z@>A8$)z!j%uIGB)@}&V=ox2QIZ*2S)mAqidDgh64#dm6T-Wa!$fuAZ8JgJ4< z7D20xY2(({RA&;UeEjjMgQd}G)x868ZQ-{ zez00cGT20yEGp|P`)I5^EXP&0@1Dj#6K&H4BZHn);Nj!M%r#S}icF$a7%44PURjRv zr&5y$!?`wnDU}8zs-6bpz+7Nb-Y<)by+|EJMzsr#QAIqr9N5;@<*15`ETc9r1olh3 z8211TK$C^l1Q>UwmaIANZ|xZTgtqzpyXyjn`1&&YGeOYVbi zcO46IR+Ao}0f5>YS&b-jPl-Qg%L$`U z@+uF|p)Ghdw18G0VG>rcZo4#mk!crP8HRdN=h1({h?g0E$6f^+tQYmdOrT$*! zPnC}U%WcgC%@BsqGg>R^%5qlZob^;gFGagukkVq~5RoTib+)ABuXkxn?!FV4T!RKz zOVKo+Lc>z!7G&iVQAmz>HD&eQI;OhE9ZNIypq}lvVsXQJ8JaU#DyhP{C81?6u(V|P zf$gGXLd$%x=j#vlAgZFBm8ElU^+>NM1@tPp$2S^Z>FKF6MW)mmlBKXr7Xt+PI0pI4*E zf(uavK+}#m;q2$5k0+Q8f5Al?rx*0#B^lDLqrH~J4D)H+vie(e_Yn13ega{0Z9Q<* zYCDV8w5RBO3>YYNC1if4og=ivK66(K?u5Mok9Ey%voyV=G`7dkc0Y@b?h>GRWv-pq zeoeU>xCJhA*ySJ)EWo}r%~Of;zR+W@#dhRKblb_jthfMyAZvUV$8dhzU@cM5xs>|& zzjar=4WxO0-=(q;640I!P7;B!shUtfDZMV9o~T>L-4|q&x~UD|m3Vl6F=7shUZwLL zWWCN8CvwLOwjf65c9zW%FK<_mUYyuhrI)YLEO?c_j<+LdvSlC^q_I>rX4OQp88b0L zz7tW9&B1G6W*mUWC|es?8oCmGC_elPhjGJ}_iI(67mKlBjv2Pw6eDK5H|x`rE`I$v z(?576iq#ygvLTSJ3C~YU(;1RFNf@V&{EwQ~lE*XY=Nl3-SCDxgJ-R0pJbsWQ(e`@E zuLEc>(jZn~o_ANE!*6g{yU~HkG1e?P&ctba|8TK)ujSxtmqyt;Zg#-hYr7$oV& zHiIY)t&J*VrnYm72ImZ7uWBBBEDgf^ey`S{SkD&n`H%$a27e42x~P^ku_c@pjPSIQ zX-2pPGAqCaj)Sv(<8riBq>*c4jr;1^!FceJCNKduYyGMoY4k=Lk(@&RjFlN&g|S502rv_jSkite1d>oRCRrsgCQF z)}*ChyMn{CQB8l$$C_MUH8Typu{>c|8i#hxS*$cux`_s->iv?ny}o$;zGVHTB#XbI zmES8yMg7VUaNVxW2LU#b{w*6(B^3hBCjD^#@V@~wx zevNOa`Z?I-U3=(pdTX8&*^ZGE!o1pznO!C$wx+?E-?X9MxLpIdzOHsxy^d3oF9j|- zXOe?IPWO#pn44OvyDP3WMRoG2|TJQeIcB4lv9chv_9rx56_1%_2J(#=`@Kj|WB3E=I=!j&cTX!(xck)eJu$vMU zUY(2UJ~a^YN|y1ME+Q%}1UO~VzpXjl%xNcSEgE8Q_8mPv2uK0b2QOZ_mo#f0dt35q zZ&OKd^R(inhYoG|cTZE0H{3|CjCR86iEXMp<*ROxkRy9nR-1`?4^0Ztx0apu2ls+AeBNnl44}` zljXf*V(!ez(M--&=~sw^8u) zk0VxcvRy%=-!ayN0+Au#u)}VVcnE3e?rD(Y=`e%A(RSATMaL@kaE~BrJ6)yh`7Il< zDefHsp=cW@&csp1JW~m?3O%H!zS94m9r=nkQDW1|p>|lFexlc0d(B!yjk;vRg0rEO;W^QJf`(7cdSy11pQ&jb-s=fEW`xQ%; zGc{|07lh1MSiF1Z@n)EmFN;;F2GSQ?`WXi4?PzIS?Y21w3GlM;H5hpnMU^+Y4E&79 zU6Hms7$SEQDg*BjZ;y&?2@+ekm$SwW+!5VvH(dH5=B5#IO+Ig3&uh^7R57%EiPOPe z)BRBRwJ8?|+vI!xU8Qdbu12}VlgLn0#KFOufWd87x~l5UnvaU#X4Uu3cOnMGp+8uN zCel7+OuVB1T1VEqNUP!&4A2uwLo=M56d|U@xA`aytWrZ(zb=A6LSI7VP@16&r0ug( zvKRaL%4#3OS0ZY_oN71*ZTLar`UKrHH0=G0!28HPw?*rS*eRa)Z!w-t(Rp@zXmYV_ zQA&Q7RxH{$uB<1kDFvqP~23@+XH0eMyWzqK=zr#Be`Z#Zd$_)9m7@|?+DBW zWl&zLS+;NQAv~IAYXv;>JoD9yHmZXI%aMXZXb7JVR2ORpH-HP+0qw6X6TBzpAoi1V z@~2CiZtW)E9#$}#i5WC)UKzY~I5Kb!mzzpO-K(b;OtGR2c-M4R=;1XL z)D&RM+h;H4^?|D+_F8D>N9P&+u($V6PcrGnowbGKy0GIq@7Xt?^l9s>Ze4UOR{sL` z)W{6%b_vPoX3w%fJq?NW{!y%UeaWn5Pf4sA4QoGa)S5Tv>9~fGdf4qsk}nKvK*$K| zrTOrVYUdUqgqmP)B%h4H70t0h@b4A-#o7&k{DXl7_Yx1_4-tG)%#Z|=mMd7wO+&a(WRFHgxLc8e@G)##)3H-X&`>%Pm7Cn_UC zRy*}&_Igy-1kf7e&Iki4)6@0=oI-3yEG|mr3bHp>-)$b3^Bwpz0@ond@~%wCx$WTl zyc=3gZH$E2GY`+!XT-fFBKJO3RwJi<7O5EJEh2LB*?SZUmo#3)sbDGRg+eTc6eJTp zS{01leXt(#-!mMKw4eVd(#xAajT1+nLcrVGDwa#t>hg+q8UP40qo~@Q`7C=o`n6Yg z+U?#UU^IR|&U*LT?)afnN)q>Ci<>4Ytvo-4cn+6bW=8yzvpV@C(nk|l9X`%T7I6Fs z@Qbmk%XdZq+osuvu8`FO)@Z!9DHWk*maBSq_f)4`9J3=crdN55*&ayrmh|^cB2}Ym zxxBmvsYz{EKB1nUKl+PiRqQ&W(>t3>Gp{N8EUw=S+{UHv%@9>psVan5O&xX<;wMG*YsUygI)P0fKAiMLcl@g$Y3kY^rk_&PT_HxV#XT> zU6@7IMrCE!HLG*x^B2p$MSB|12PP}i(z5s+BCN~$1D{>IohK!gM)z+Bzxc=4p#ErN z6yDQO8oX=@Z0Ak+Pka68lgL&`)xCSIyqtiZuOZkJY2*~pvH7>2WHE7(lrwWSU{OWDn6LUc=>`8|c-$Bdo@zY{(zUsqabJo1DYASVL4+plx0bq7#cV`bvFO#}iK!I{KPvC_|8`R20=1bhoR+18%o4hRk+ z+SZ=K6AJ0i`b1r44h4_lZT%oi$w1yYDyMDOBblGz+hAJDDG(Dm_>p3|05vzD*c_hz zou(LpV&1IPt3~Ywp&3FQPuTCP9eYF8l?dQ%$%r66ecm?G8_Y@nOw&tz-74!U0K{1p zvYCgiJ$wpbbeLIe_VuaPCA?Y%4x_ezKlTW*QQ@{3LcWX?+q=v@Mxbsy-zZdv!C4)gHZrCEsFnDTQCAKN?q? z@nbGjiMEpr#JMO08-x+4W0sQWv&3Z2F5>i@LinsjJ!GScR5Odu$HCymU*B`0G;Kt$ zJKNo9dp(`ejpLoi=!%By6vhZf(0lluic0q@xdoo{^YPZBTo(+hL_xIvP$ z>?veqAnzB3$FuwBpF;LhbXp0d3)@oS?*0_{mOQEgX&MP zsL2wXA2>=QcP}G~L4umFM;!SM{tjD4+j#5+P9%nq>PKJ+636{DUgRWzfz~q&07FkR zd>=S&M5oJMz;%Hf>8Nu@6dC{FjM7e)1txyiK@l{g*6U+) z*imAVeHR@>G=sIngpNepJX zBC{M>pOvzk)N{-lX6o95hXjl4?>~DfNHa)y1!`QBLRo%V6*YbF4GGh;%HI2pp0U77 zdeylpw0yGqQPw%2hq`$r)oMAG(c(js4O&O ze6L=c=}oal#lT!ORozB&x4Pc@p1(%1lh`>#jQA#4S2V7+sz*w^2bIntkM{MEe6spo zQ;CK^069=|x+hkHxky`s&krKlD{{VcS3?{oYtK5PPz&msfSI z-o2!PTlY)4p{{n6;TASPV{=xO^-WciJ=cjr!)l``C)*noLoLuMs{tB^)BUkUh85+{ z?Kt@a)q>%#cIxz+=?$2u)Bl~eq?g>A&>9M5uSFIdKo(Ac`E8XEkL-E?B;O_>P}KF%&kNw zx12Is!(y~yqBzI&ptzS-lw}k5veAg={XT*rHYJq!$~SDomvH4O?-AkAmeNW%f%!Ua z=#0E|UD^iqz{dqu9KF;30N1EzpP!^*669q?Qk1n_boJi&>%vs!b{6^A!G_os@+#6e zCOG*^oUhCglI#tsbgjq5`jNJSNiv(+m1n9MmC;v|)L;yX??Q|y=a5w^u;)2t(6q}& zP9w~<*z=%GA-1Dg-_lV+KyfI#uHzJ+>QMHvNn@xTsW+W~!krV}ryJ@4vfeZhiy}}O zVd(;N^h*EzK~Lq5`(h|^z{-*cYpM?vi7Au9la1%XMOaN}__=3w=vAn}8OY(QSAv_* znJt#x<>}7GrHcs_?^16tXBRTnkCv8KiK$G!)*s=Yivv)kW>Wo%sTl)L`RCS9@N~C! zu#^GVIsKLAF*ns#r5~o+XH# z&Vo|`R2kt)H$mT$E85Qy%!}{}TN~d^%tEEaSe;k7;w4O|+{EX?ZotQse2S4|Jm`w2 zK+*OtaISlD$4BnX23XV_%MO|YmN6aW&rkdt(T|1OrvZ^Sy=Xx*h_j21&f$ZUjJ>ZZ z>-lU_&5e@-NBQoy5yW?kinb|~oEw$Es$oCx){dl|(Qe)J`#Fggrp-%<_8M0tbh?p= zxSb=1n%x;p!$g$~U;I z8l(&QLhO}~sIQk);FbeEcSh4Wb7pk)O}P+$(}%NlbAQ>x820g<;Yz@So>Vr1qNj;6UPkc{!97=tEX?c)zM5lI>v-F`%6mF~OFG(nf^eQw3hZQrwwv$c&o zMH26yoi8Aq+8eclLqWAjUFxENy@rd3T`8N4*aGLUcu%E)Nbln}Ck^ir+ZlU}G-*P6 z5gwv{bh%!kVn4zER0}^QN^)9H+T5U12)@I+gye){%SV{qWVw)*l}bTipH}>l8=5j| zo~W4`gdpB7pw>#eUsf!JTjHcnYF30Wi11A%rA{sw|9Y4w=~aa_%p-!*Hc@c}&x;ob z6Xtsj8ky13&g`KjuC1&sX@lcF4lx!nh%$--QUhk1Rs+FfOhfH9o>*jGSSyVgl@B#4 zEg|nrgCYhuFBDdXW+fS}O{L0IFUS{nC@Gaedj;)YWU*ujOq;Uo%1UbI=Gi_`)Fk`G z!6ow8`o&u=`lQ=(*q?{zJR_niG7R{-=&KzMW%&VtO@!-^UM4%ice4OkD*cb21`F$m&?LX6p?ACVOZwu?hc zI#&DMec73oa`@hIU^$GrYNvKCASFY`lWQy|8o2mfGryro>5Yn<#8JN;s zIcVb0RJ*8`*3ad@1lkjGU{X6zK=6wQ&3SXqj$k;}E8ns-F>aZ5u10J?wY?8MFal1} zdj;ezyp58l{<`M z{`mm-^eOnqufrqY3U<3V(2=G^9cX~yr#|2~>`C2&WlO`)lXw#4sGla24%gYFST|l5 zV$SeoVJbOQZC$@XMuW4-U4ez8~6rsixD}^B;Qth zO}3jNPOHCaJr9yS$sjwIE1_2H-CW3`Q&S!U<=o|Zo?AK#zcsb#S_Ej>{01$usdG-H zw-|Uo5Hhh#ucasWfj`<}lxTu+xDhYX(ZHb&clW|AiqeV{_e|rpfvrXTyF7C;0$qH0 z%$z#76Ru2^k#x*5iCgmz#!mT~RAQgO`jGMr4O?Q+wg9p$=j&7)1{-fVKCZ=_uj33R z$0OQ~$yjF`vjkPw{&>=`Nj>yf|A2*V9^@fB*U(zAz1E^rF zd1Pj4#bpCp`teCWP+=Ogp|UV%jawciS}TSt(!rGCLQ_bt9jEzpiM3(EP>7JrVNRz!{kW3G>8Eo&=kN8U=%PoRZ$byQ?U^0?tpo$qIeQ{DM)@ zjd85FqqovX$Y;Pc{8OMeV6|dXs9ip2qlX@U&*=jeZL~U9U*I;n|D2U#(b#ppIYR;~ zJHwtIa#!e`HBZDH`8{H_woQ?2V$@5o2M<%gG+sm^cKKgF{8VVTu~|l|jPy z(a}VPq(VG=GkL+soYgE-7Q-{9{N> z!{k1W;1L!qIWWMEf=$YXCT;E<`5`H)YaYbOL$RHK{}jUQ`;vGXw9v>N9|{nt+&nwK zqk!xz+9WB3tQ#k}U{p(MsOdC(QTLdGTNuVrWeH-&y|<+Lftc_Zp~;gJHQB^nZx^pU zP4P);@{O4!-?XjU0)hOvHlLv*?&H$2abX@XuWV9V{J=1wTq;K=hpmCFvue}m;y^8> zUW9(O4pL6}Q-Up&wSkc`p3XT@u&jKtTCQc7gh(mPy>zbaJ@-Rf)K8JrR)%EVR89$# z@I@j`fC&%Y&$7*~b0Xx8{`a=`ByXp@SKDJrtS~_QeNDASC6bA5dsq|LI zdM{W}$ly6;bk_C!@U32(y{k(crj8U2)D&qK5jAk84N(1|NOMaJ>j{`{M(8D`# z$gSg2*vWc1Ws|WY0-@OXFBWv)5RhWOkh!d%E7z!&#itDC2+lx2kS&Wh;j4KgE2Nk% zr|u(HJ`Zw_8RZ6{1*Y^Z*;x#SGqmN1jPNx8J*GSpMVJK+wLax$h#Q)Fo-Cbi%)16%ZG>Sn|g5$cm{Tj1;b zO{__?n73`YBo*6|>e+(o428IM0g0&a)ti7(%(_C!qutwFPRW}LrHqL}o|sknDvHgN zPZnkEcNjR6y|)U=_LVvKVc(vh2_*yi{>68yV=nxufSKBWBp6A87~jQ3)*>Uqo9FF953eNMEnH z+61$QVh&SKwqlbUa?)0OT_raZ`wsTxs@0y4BB-kjsP)7c0GfQ(yC!fW!jl_7X2<5n zpfxiQtkc#u>$8$8M*`S&HW`F{;Snuet|G@mXn~Z&G@CUhQ6=I|<>H<>6-;DLlNdpd z-ln&=xPL$|S{=d18~xhAux`bA_KH4&8Ee#ms1Rv)>?m(lU}DJSgw+(UfO>k6sHZaD zj>0-KfORnGX4{cY$yd;3hF?#QECCRyYNO;5u*0vC^unW>?e?Yu+LfLaH&=#ZcC65! zex$*7d()PVh{)XP!{_0*X%H?B{1T<+RX%K*u+(Hsw7dZMw}s}I)FSZ>!>jS23d7nY zN@~Wz!Nw{8197tvqGaS)j?*MjBq<#I_pxI(KC-@`*OW{%oRVyYd6_unp6nL$og8sL z<+N97Z?z-Zt*LE)cW!M+X|OniAB6T z&jO^n0Hz$VwAmbkFEQc5z$H0j*JM2e+aaOoFK z&x_LD13=+e(_*=!vs>f-5^5;kJ`PtXZz!IPDY15;ZjO0Ct~u}fJlUnH;Q zjCaMCFC9xBKqs2JhVuY4iQ3D67cyiIgFP~j@E77PeVA#Yqy_R=0cp~HLd%;olnyc5 z>g&#A!M%OjjzwgR6gjuYs-JSIlWnU+N&PXl^_bSa4)0}P?l}#&H3#k&P4?B*M4&hy z)U&rmkkp=N3` zQ|Kq)-~q*{iM;h43EH-x>w-8rdHi$=w`;Td0FO$ibZ#P)%G9VI(`YR+3r}R#+OgRi zHPi`$dKWvzf5=st@#Y}3_+1vRQIOq!>4Dca+eg`ouS?xp_UoI3Ng`Cg9q!=8m!6Tg6Dl|t#F_bigGgWT4WAviv3zP(P1=ME6+*hK@ za-^$+*r{I^XHbr?F?E`gLqfBtNP5~{$i=Py(aNIDcCO5ZOY9DEV$=-Zf<_=zjP z^qm?cJ1q>O9QlL?d#2;5bUoRNIHye7dHp)?RuW?MC2?utQ|1($u@zR~SGbnj00Q#s zBRm*o4gn|t`W?;Cw7)lWVwmMCLQL9~7l$;7nDu)Z@j($RkGr{Su;2YkUCv-h>eBHk zv%m13hq|yZs^Kgn_5t|f#)d@w=PfV4SNgK>OUO64I$=qfLrsRi6d-5uAi;&^a$$+h zHDwXb{{S^2#KV`nV+@R;V!j(Zwo(iKs%_flL;@|HMYMHmB|@V%k)R4EU7_Dq zw1HkaE=nYiL38(IKbQ1%-w4q8NW62~b*hB~N3zjBIjBF5mb63FaSSLe=2v5ML*Y7w zMK*>hlMx#NbqSY=>v9$()9s4(0I7_UdxU!Fc#h0d^xzXzyG#(WmG%Xh!7L4%fPc;e>;7 z`0EYC<3E>nCBiA&*8m((f}65lx5=PcE_Y&Lx$LK}O|+X)e`Ro_9+p3!y*!^K@=QTC z$_TAlf!E}SXmNb$2shmFEtoyb|CIoDB=Y=O({953YzFy;Mmp(@%aF&OU)UbHpN`1+ ztU~@eKf)Rojpe6ZRYS&Hq>ndCPpmknm=votnTn<`5Q-hFg4^eu;%`b7& zGJ`vUp?JG{3$Er%`m+soh$oUXDL=Z%;Tkbtj5|K!6V^8;;{+gmnbQin6A^&5SllgN zLnJt;VTOH#RzP#Y;*z|v=y(S`p+~-jM_gnSVW~83KF1B3p_h7%eer=8hjAK3YD8-D z!HQ@!K4z#>L1Ov~6|>ZwKcUKqKmc18H|$cF+?M3Xi(THucK)%9#W7bFLX=Y8#rU8q z{_8#D2~RygA4u3zcF=30y^CP3f-3%Wj??B7t8|Q8+b3GTDv_-_ukYIg4;oxd2&E=C z`3$f*=6DjfcI)F}4V{|W^jO3N%oS?r7JbSWToc9_xQiH?Sd=5KGnxkOxChRHr?q8B z8qlTYzIsb{auy|NXUNoSWBGy~{Na7gaVlgl7GBs@6t z*_SOQCMUxhJ3P5}SE&{eUiF~0BcG}Iqi!;BwhW=qaxBMuwwZCs!)@Yk(3p91QC!st91eH4ta6kt;n8pZ`o ztdm5LzK4?F8_^ zZ@YJS?*;bHu(!tW1L(=KA?(jafUls4Z9JTe6Je~jD`YTGOjYel<&3gOe4J7B&0;$x z>S=9CooenzpYF-T3(A_HgxIHWWUk6CTpiLZ&6$7 z{piAn!_vkt7kFE|J)5K#KdTn?;&9juc)Q&#>pou;Yk-cc3kQOA#D7e6&{R&MvnN%c zMYo+ece!-oyC2v{&y7b**PMnWA0!c}rb(ULnvyefU74~oXLm<}eT!^RIa+%^x%-t5 z8#SS4AcoQ7)diz#?X|jHnsPJ0z1re4JSObjrT>Y_M8Y)s$t2EtVJU6EdhZ9_fn4zI z_u8|U233KP{pV7|hQs3JK^ld@X(1=@fTnEIf(wTJhP?+n18hRN3FtIKEf{at^G~(J zH9Zw&0n!GVi<4;8^(Zv3MyTrFXp|hcXjMH9MeA6V%g@C+^jJ!CxF_+i*aNg-Qh2>t zbEE`IJ(e4_*iZcO2nvi8$wNvbC&sWf=G9Q-9G&IBGo|+!VV%_#iK?Tueo(JCQAx4q{we0E3YV9 zHDU@=a^|#lo4K@zl+Z`FerG0fYkT7Z5phn2$D#K!8enXQf8piRmT%8o0u0OQHT1;v z+fIyZJFw|{)x9DHyO}u^kntLyZ|a!O`nGZ12 zjx8@n#OFBI5%11NPKVzxZ7@wY{V1L1bqp1Bnj~K>?-cBZh0&CU^>jq%LGUj4plIt2 zIt7P>=pSo5#s28&SHfU%t{dI$J7I?<7g)&&I&*%Xv$mpQX+Jk`y>@nu%JT?W@_y=| z%LtU(#oa{>E%G@jBIhU6KTmNna27g1;1k?e;Pe0IVIbNr0E<7*aMk`0(;}d*GsBS) zPj94vNvYW8YS~4h6@U<{pTnV`fR1G{B#@q_k|XScJty^nlA#cNeF5o%1(o3uz*ww1+OPxf~Q27)iynSsz1B<);0zI=yyU4Mbxx-u*eC z$)(1+`>7Lhp*ti-k!S(W#ksp%AjDJ{Nt(=rg`Bj1N_nf3;w^o$^X11pV{gMFO7SOW zVYI$kRzU*UpOS1*fIgK^dMgG$v(9dP@LFN*Le20LVYqp4RJTj%wZ#+%6=SehO-p~~ zTw4*|L9rIT;d=7nb8uY+8pL?FOilxFKG~}pS!-zW4d&|P6{%n(lk>i93wrIABmC~W z4UJg--YdbCqX=$}N{b3ooIOZoDl#<>=H+$P?FaQ8r*l)~A)0p?ZweHXrM5d%amvd+ z5or~FMSUqYbGmXneLfv!M@dvU6RC9&I@LWVG;C&5RAwMo6~VC0U=pOHxf2eFR5Cqh zVVo17Azu?u%djIOE@v5%Ih!itnvS`Xl?0CvYP0N6{NyiI?sw)R`a~bGVvcC;(JB63 zFi4fw8sKV=z@EC*hn1;s$XfeDd}kjaB{PDbokRAtgL9;BZ8HgB2i%7 z=-1ehydHmzCZOjPw|-sdi8}sPcFMrIsXwPE7f$dR_F6irvk4NWe>CGAdvCXo?|UDp zuX)=*(E=0##aAgzy3pQ+GGdmg)Mv5+@`+J{dz|X^%B4c)bnLMojzEhjCD4|+>Y}B1 zkIWd=f#(_t)WLY+`7(v)oB1aNfpnX1%A0wN3Yh^e`8O)`-x_^z5EHB=zn+ewXz;_8 zv}|Le)R1X+*^k-nG1>SWJ*?F_uzF3SV68ctR0VXkheoo^T2KtgH3od5v;UbHP4dsa zp`0X%zXZFiMuDRT|KYOw>jYjA;NUK1;_^p_xU1W$&x&9PLduB~)WXn-LDIuD?xLRu zBjm$WC5B#N^zHY(Ed$28r9*rl-q?x4lD2$+e4-ijZiYNm`C7Ywy5xGg-q!Z*>Tcf= z0@IVEn{)MiyEsA*a&Gf2rfEy>bRmg{<|<;h5$TyL2VOT;F|Sv5FA^e2xo2NsVua2B zFLo?mPN@vLkS6P7s%l+#OQ~tNb6Th+B!2dfx~;+Tz!0K_*I12=C-|@fmTSBmRqdU% z43&?xFp83@E_S0BFc^MV!TC@*7r=E7YcJynahNC5;YNK`wJB#I@d0e_#QqeN{o zjmA8uz3s4@zDf9uhG_y_MuV$ZPz)!`rYq;PS32L`jXSdM*M-`ER|sUB6(w6*EuzTI z6c3AYwZSR)O&4;#wo$g8LCu9}+b=mO;&QJuG&({^uhj?ZD{wvXOcJ$%k~#%!6!7;B zv^kJ!Nr#*(U8L|s-YunU1Vir@=*!kZ<0?g*}7aB{HfP60Lvw6R~I{T%Cou3*=78eotpHp`AzLHCsmZ^N-rYR^jiw@QIQp^?rO&@Ru+sKywj!j<*(VK^9d*)3)PJ9zf z+~$-`zZ5WyQ6GTl%~hVKIX@+3u4i@C81goaLCmhNp^nU@X$3(0^>uxL+>~?jUBuXm zthuGt6Nh6;qhxrr7uOq!NxQX~d2w@P8h4wc13kLtRgORt4=zX_m_#83v&W$`Hb_ zqf`}0A4W4_MQCXbZ4%Nvm0b)gHX}=>`91;l@b%a|r~nl_RRm>otFlPhc~?%GH?r3r zx!ylLJ-~oavUgcN91wDhnIEJky=S&`hS73u2|2=`u~Ze+B<4J5BaO|Vb10kAT(yu1 z7o6P!n~vX(`KojC2RO(~LWz5+@{nnps*EHdhwMbGcM%{7o{ZvX%-Hlqy}tpeB%7l zt+UNcxBg86i?;=N!_@T;bN)gZ zNF9ZU?*@8|G~kvrZs3jyc6wQ2wjg}M`WA4RHtmp56BOe$r3SkCK)ecl#zK2kiDq_} zSaydL)hk3UO&6jgO265cA;9DFe+wGKiRiBv zijo?ljIv5n%ugc_VCSg6s=`48f~$&jac*yc|LB+H8*GdHPbmzb2fzMLRYg%HSt&_% z4JJjY-vkHbZ}?>|7w8cJ^n1eYMA_4!^X+n;&0Xd2y`C| z-XCp7gMc_D`{PmdSH;4Bu)kLmb98qw2m5)5IePvvA%9=~4^GOL`kxnIZ?F;6KPK{T zjtAHs{#S$l_wv8|M5J6y?Ej1$eol$m4c!?B->)b54!|MD|0#t5+2H5se<)yGJ5dJ* z$3KnP&mnsjQF(gc_mo5MYW3H9%3q~0AeZEy5HUv=^S``So>OL2X8n1=lv^<6mnPR= zr7(aM+*N;XinxiJiJhb6fA1F$7c@L0u(a18Sla8?QsA#r7?4NtPmF}4nY%r};s3a) zpqYNWDsa!xfqUlH68x`H7{CJ_Q-5!cl;i)!n2AKT#3BU;D9Ao<3m(fq8Pb1<b9qfKn0^|NgdFF2Sob}x0>Nl%B;h(HuYplNwo?9Kgz=f4*&oF literal 0 HcmV?d00001 diff --git a/lib/jproduct-core.jar b/lib/jproduct-core.jar new file mode 100644 index 0000000000000000000000000000000000000000..af98d8965a43b0895fc4d1382c1a50b1a1b5f10b GIT binary patch literal 21552 zcmeHPYiu0Xbw0CP?ktx>@l8sUEUsk9;+vx0Z;PTxo3b9XNUNsggdQ!&1VmLuC~;@WXqw8)R1x%ZxX&bi+`vlI7Jg=0ifqARaIcY<7hH58^(qf^8E_e&4|Mnf*ik`<8IHIJB#OCm-Wo zXR>A@WyMD_*~LuO%!7D$U92wV$hi5H;^u@QVy6i_(R^J8;Fa7bGjNQ&kh_u(?e3dI=g^%h6cg0vU&_8Qf4mqvk(9LFF<4`)#?=0sYa)mMh$aTzNmsmLtWh` z{T0U3VK$G08pS3vOWA}qmP}b1wHFbT5?nH`ni}o%r(3=S5R@qlrZBe#&s@A@CGr}z zh)2oH;G~sJnyKU?=EanSzS1a!PZip#g*6zWYQCZfjv>;WDa;!B>z=KDxfS2=r}7@Q z8!p=E*Tbh`w1&EL>W)%R3|xC_sgL?&G(dwoZI9AWjCA>MN0fHPXcz5{(jJ}m#%Ley zuc1adpwmH}4x!yS(KuxU?;Agk_MOnEZUplsZ>IC-%+!)qt!?}J7hbQw`5L}3-NUcZ z;EKmGawwTj=8tH!qicnAyU(G!M=&2Xsy~@bTc?*6E?U_s9u|$7PG%Bj>YRz8!o7MJ z&d(=v8XX8=b%RD}OryAe+3{Ih5S{Ka=x!RPOK-9sl0T1)FHp7hK6w&JS8Zj~4FQKNo;QxjmqU@p2?dt19sI^8~*&nDAz z2l+XhNn1eCxv)Mklgr8$^@gmkk)F(r@;C@4=b^AJV&k)z8AX&%X24UUH4bflqESr> zCo$Uv9oT?&Q6z6&%MYHiayfI(8p~uCOjyRqL+WC`PkS!7#FnP?pifI^6Rgl0*v%%` zuMTQPoQCcZHna`TFtXxW!*}cP4g2R`!Kj6BzSQ#;Xj7eI@yb+%*W{3KWzAE<2yPLe=6=-)n?H|zn*=79eck{15p}e$G*K5 zdbT45McbtdAI^?lJlq?leK9E9fv9lgG3eb9E_`Q{j@HsJ9gEUPl#bUx3rBStgY88} zROIW48h+i?-~AsN873RP!oc<`wTiqzhlt-G!1*`N6Pk-cKdZYZ_ou6aj;bJLhBrvHQHZc zjpf1{u*VxKHA>4yz0!)qt_djYg+{&pX3%#MmJ2&rzm;qsIqEPRTA$jW1JQ;frL9M+ zTam6b{wog35CgP{=%*bT}ZMne_Go8*bMq=w@Vfp2ORoY{S zMO$=g)v2v=U*0*?`OR0~MaXWiy4Six_Nn=7=3!nhi&e;~*4BrEoNgsegy*eJm`gdV z-&U~P5S$~tKll-PU881aX;c^s=txLHKA5fy`4j*jTw(Dg97Tc38>sAip(P)OR=xVQuiux~e|`(K>d*?b%G<(~D%HkE9IH6&YyhCP$)L@2yG~mS__jL?Sg36p9jid&%e3BK^H+|ZRgRC{QqU?0z=L;) zK({$4=)iVm4bIrNgcYyF6#zLA>am?agL3Q#+IyNb#77~4I#p=|)G7QHRZDl#fCAE8 zbi+;bh!{z_i*`7NW_$|*z{^?%ao+9=QG2nwc<>uT|8g1gnm>1;K-rOWuL3@?sa^G} zo_GK1L)X;)q=15v@)NsUhhSdoixMJ(ItS46U6i3_(WKs5j+O92(5#PRP7i-%O$eIO zD_fUVyz>0*d}d$$%D$H)zkuQ3&(6U49I*M|iTL1w*Xy)Fr`w>yiOk~l;Z$msn{ma9 z+JK#gx}3AO!N@?fdjTSLBN*`8fQ7m3-6rQV52we|*muh(bNOTfJ9w={dl<(unUrOw zF_Sj9i2GD)bMvxmF}p^_0n99RyKJVbg8>@B-%F=*X9YmEz+cSnAO`~*X zaFwr6Do+pVbWJC0+*OLqH$Q#y7n_^W`m;;vd~(4$m&_%xdLL#8K_nVML2eWJacyvs z^O|ybE1j?gr?O@`mxQ*n^GT?1lqX|@OPSQpV4F|<@mW;d?DNH4R@y>}lQk=L4pAtY z%k%vl8dah^vT>%aFIrrF{P^hUsqrbGy&XREM>46U1)k{Pw7CG3pw;MCJ(cp?XNwRh>G920VCAqS1_91`&mozN)iEaj6am9&SF+uW8y z%?Q_2S5LYTF%>1_*w4qYmX}NGIz%EJh&p(ShGUKpVvhAV^OgXoqi{yXMqKl=PGG~G zILC3n$zm)8`w$`8nnPB`w)22|Lu#vm3$MdnFADbY7phplT?`|pXx?62EX>rl)6h8b zO$5oE=aG97;?Y$VHsWqCu2BwIez-Z1po4Vi0%;a!2O#p$pc+SU;s#;Wf-9DkU0#Rii?EPpR7tZFXF%J?cPXIe%vi!8CKz87jO;BK$wNdys`x9e$OQk*cd+?ZF0EFFxPlo8I@R?i8M^=@U{Qt>{~-Oaq=Y zYUFy-geQ>CeiD8aw5zbc#Zl}U9MkCE3;?D@gv(d(B#WNULGi9a;jTd`u0tmtLHS1^ z^<$XPk7KN!6s?I%ISZ}1pA+ZMia1o{6xtO+vH(FdB6`I54YlcXrjd6cFq>6V-TPu8 zxi7|Y$$hbBdd(?^ghuOKh@3IapxCrFjIN4^a~{y0DoX&5xN;XZI4C+Bl_VMc`NVM*yKAqZi&a`fz0X_^ysWFBx2e||i zubcTi6r~nEBlo(M&pUP61z$BWJbemFotdfWiP4#nVGeJHN`|aHg2CslEv9pJ^!WG` z$elfowQ0=*Q09=4cP zsOtu1*V$wI)sVRfSFo-be+V0aE2sAI71k5hCE14lrb5=AcP{ECd_*-gpiBF2UzqQq`gU@ z_ehv#8J$UIwHD>E38~6+=)^T*P2rxmsro%q7SxXL2(&o~M@Aemk%+_Q3;l#6a~y*C z;vfKV#)h{jB2B1&bx!ex=m_?h#8!Y{cZf`1Ci55?!hcggqVRN+j%?=W8&o51V%QVH zO|7^ws>Kbmn^9~{MBLQt@8GWL2GvYXhi_2ry$vzgE;KQuWZK4QF}Uk4wxic?)V=a`Y+UhY9}1MzE%lC(fP|6>72tbJ=~rTi zr*oW@n&-n3AFlG@VLn`|g$`Vg;p!2-dX%poIuFA9@j=sGL@%v`W)Zj$>-^5 zzIuiWJj1uYr_&d7`u)m*wV@ZkYJTw3j|QwYFUlSmzG^0cN+nYQG4aQpD#5y16ulWF zwzvp-L9cpM%my}Av&&o-F)GI0YL*sf%{&8dSPJ>9Qa?5Lkqg4BQQh=uLp@{mC^MjG zsGEswGJ(ErbXm@^RK{fZ)^Fi&BbIeGtwmYiCRYlaEY$JGChfE_>DmH4w!eRs9&%S{ zf9-2F(9mmcM-l}2Ic`MuPf1nydiC4Fw+Qw79H4CP=8y}DYU8ai zKg$)g=hnu1UVasdLM1n*`mtr*HaV>AFCg4$CWOEYTgz{T7?kRMNt(jLbU8q3nYsI$Yzg&<|*XA`BDHIqsp!z)b}$# zHtvY`3Jo9;I}LzMcN)MhfJFlT;ujR+3T;#fq_j@cLjQhYxP}=XJ1hf(0pA>}w&O^8sq?AmDZJD4Nsu<&yu3~~DUQrzf zL?Gm^M>(hzj-z1jgAk74u|#mD5k#LCnNBuBi1$qKEfZkSjtM*ub_`?20|C#Tb=5cR zK%QxD6ggcMXwPBoFc07@i8aY3tT`@2rBj065lItB1oH!Ro&ey;SKQQ)xZ=LywL)AB z2?zXfv7+ESVhPBxgbOIm<+~ZL)ET*q@>LCA#rUe0uMEDb4(juNn7>z~`ZDPoulOAf%K?<-TJPeR@hus}l6K-fkq85ooZA2*-~gK8HTRP)=^3Jgl#G>RLAL9u)igZdI$ z{bkIZuV4;6=jts+eR)6`gObpn#@i*Tx7?s;L?UlYQm!+f7i7G8C}BI6vm!JQiJcz#uCE}o0>oR^BMK&V1o<8W`F?;Pa;|CYM|=cPOL|9;8@__T|M>NY0!1A` zke~^r=X6RrqufIyji1JD%tsIf6FY+Z*jEs^KR-bfOza5q6A1EtfFRPmhOlM8%lV9O z4Gfqrf-;Q%71#%PQM}N9+CcN0}PA^+U9R1t4 z6fvjoyZird;?lAUo@MKnqDa=THBg4IE6YIj*>5iYgD-XA)nv3aip({Ux{dn0yUdwv z9OCg={L}%?{6hzP&ln{~E-JvAxJL`MRKb@9{0tV#;;(`JZJ5u6U%HY%ise-0^f>R& zVsQojd+8~Dm90?K^&?qs=HA~NlCUM$XXZc0nTPx_ayOePdVgfgmhz>i&IVFcLtJRLcn#bJJj8q8(&@T+ zaTj}kZpz{H1I$)`>Ak#cHiBmWFK(Cjmqi?2yOG&jl9xgg2A93v?%yi!FKsxSp2M4! z6>(CIqFkH2FYh{>UPcyj04Hbe6y77W`_S`doO`&q3%xIOI_&-%_O5bvs&yr}v2u9d z_j9;SAep)XZe`x}T0VH(M(>+Q4%a@|zX4wuhhK~<{57HzvK&o=q$2$Sf*KXNRn`X0XfUo91GmH+?% literal 0 HcmV?d00001 diff --git a/lib/jshop-receipt-lib.jar b/lib/jshop-receipt-lib.jar new file mode 100644 index 0000000000000000000000000000000000000000..eb2f505bfef616a27793c2cded9780dc2d6d06d5 GIT binary patch literal 1863 zcma)6Pfrs;6n|4nw_RBU#RQGU#sf-ByAUvfTwJgXl@`{rk`NDOx=dl4Ww+Vg5;*b+ zym;^f;Kh&N!GlLGp1gSTsEG%^0P)Q(-EEh$FvgrHh1jqtB`uzSC z^t2qLp;pqALS?NipPm4yA#@UIQ9@)Q`Rcw(uP*7m21>8n#}bIo6KV>30h=h4~H+jhVT^EFbfa z*Bz>xEWd0!ZQG$98lRFxNsMBQUnh+*+Rl!AF+w^+>>cR4)Y@SQ(7SPH%iXox4%3;@ z_7Zpx6M2LA)vb?zejtzc#jEkRoAn@+B}T2Pty8n8o78nrPQQFb3$u_DKoB5HK-{o9 zj?T)4$p}oS1BflUPYK+qcP!7?W1EI+G)$&gmhJhfy9CCn9CIMERzvokEfRRjr4EJc zQzyLTd1nMhxhdI1`Q`OSi|Jm50D%++&07kF{4ou~IA`!A)B7xW%A3a(=_di;T}II5 zahypNQ|Pt;HwCyQz<5lgkuLsnVJ6OmF)V%)`E`eyM$=#p>XY}6f{W5nOu5cHhC168 zLWcLL*}<$#UIJBZ)6fr*Ak^QiX_Z=u!2Q7#jXFEbL*&E3=OvTvp?mGH%@CBqAHA~v z5(6n$N>!Y5s!~^Qvs5RL*0xl1G<9Wp2c(w3gDBfQB1DgCGDtr0)6Ub+KXD3^k7$NQ%7-y^m88apE-rOw3EL?ARrnlMv!L)r)Ip_> z6L>p5dV*s}?J0yw&iS2!#+`r1Wl*LfpYc-03sulK;~y^j(vakg7p|aj>OK4 znq-F;vdE5>Xea#eu?)luTi4?8(TA(qJ6}M8PaF?CUK1im->|Y=EI>E#?vM9tsJc4L PUmrfZEUX~?x1YcN@Pf}u literal 0 HcmV?d00001 diff --git a/lib/nblibraries.properties b/lib/nblibraries.properties index 1aac91b..3eaecf1 100644 --- a/lib/nblibraries.properties +++ b/lib/nblibraries.properties @@ -13,3 +13,8 @@ libs.eclipselinkmodelgen.classpath=\ ${base}/eclipselinkmodelgen/org.eclipse.persistence.jpa.modelgen_2.5.2.v20140319-9ad6abd.jar libs.eclipselinkmodelgen.displayName=EclipseLink-ModelGen (JPA 2.1) libs.eclipselinkmodelgen.prop-maven-dependencies=org.eclipse.persistence:org.eclipse.persistence.jpa.modelgen.processor:2.5.2:jar +libs.GNU_JPDF_1.7.0.classpath=\ + ${base}/gnu-jpdf/gnujpdf-1.7.0.jar +libs.GNU_JPDF_1.7.0.displayName=GNU JPDF 1.7.0 +libs.GNU_JPDF_1.7.0.javadoc=\ + http://www.aip.de/~granzer/javadoc/jpdf/ diff --git a/nbproject/build-impl.xml b/nbproject/build-impl.xml index 4c1f755..2a4528f 100644 --- a/nbproject/build-impl.xml +++ b/nbproject/build-impl.xml @@ -858,9 +858,12 @@ exists or setup the property manually. For example like this: + + + @@ -881,15 +884,18 @@ exists or setup the property manually. For example like this: + + + - + @@ -904,13 +910,16 @@ exists or setup the property manually. For example like this: - - - - - - - + + + + + + + + + + @@ -928,9 +937,12 @@ exists or setup the property manually. For example like this: + + + diff --git a/nbproject/project.properties b/nbproject/project.properties index 9cdbf0b..5f9b6b8 100644 --- a/nbproject/project.properties +++ b/nbproject/project.properties @@ -33,8 +33,10 @@ file.reference.jcustomer-lib.jar=lib/jcustomer-lib.jar file.reference.jmailer-ee.jar=lib/jmailer-ee.jar file.reference.jphone-core.jar=lib/jphone-core.jar file.reference.jphone-lib.jar=lib/jphone-lib.jar +file.reference.jproduct-core.jar=lib/jproduct-core.jar file.reference.jshop-core.jar=lib/jshop-core.jar file.reference.jshop-ee-lib.jar=lib/jshop-ee-lib.jar +file.reference.jshop-receipt-lib.jar=lib/jshop-receipt-lib.jar file.reference.juser-core.jar=lib/juser-core.jar file.reference.juser-lib.jar=lib/juser-lib.jar file.reference.juser-activity-core.jar=lib/juser-activity-core.jar @@ -69,9 +71,12 @@ javac.classpath=\ ${file.reference.jcustomer-lib.jar}:\ ${file.reference.jphone-core.jar}:\ ${file.reference.jphone-lib.jar}:\ + ${file.reference.jproduct-core.jar}:\ ${file.reference.jshop-core.jar}:\ ${file.reference.jshop-ee-lib.jar}:\ + ${file.reference.jshop-receipt-lib.jar}:\ ${file.reference.jmailer-ee.jar}:\ + ${libs.GNU_JPDF_1.7.0.classpath}:\ ${reference.pizzaservice-core.jar}:\ ${reference.pizzaservice-lib.jar}:\ ${reference.pizzaservice-mailer.jar}:\ @@ -131,8 +136,10 @@ source.reference.jcustomer-lib.jar=../jcustomer-lib/src/ source.reference.jmailer-ee.jar=../jmailer-ee/src/ source.reference.jphone-core.jar=../jphone-core/src/ source.reference.jphone-lib.jar=../jphone-lib/src/ +source.reference.jproduct-core.jar=../jproduct-core/src/ source.reference.jshop-core.jar=../../jshop-core/src/ source.reference.jshop-ee-lib.jar=../../jshop-ee-lib/src/ +source.reference.jshop-receipt-lib.jar=../jshop-receipt-lib/src/ source.reference.juser-core.jar=../juser-core/src/ source.reference.juser-lib.jar=../juser-lib/src/ source.reference.juser-activity-core.jar=../juser-activity-core/src/ diff --git a/nbproject/project.xml b/nbproject/project.xml index 3282b42..06b9cc4 100644 --- a/nbproject/project.xml +++ b/nbproject/project.xml @@ -19,9 +19,12 @@ file.reference.jcustomer-lib.jar file.reference.jphone-core.jar file.reference.jphone-lib.jar + file.reference.jproduct-core.jar file.reference.jshop-core.jar file.reference.jshop-ee-lib.jar + file.reference.jshop-receipt-lib.jar file.reference.jmailer-ee.jar + libs.GNU_JPDF_1.7.0.classpath reference.pizzaservice-core.jar reference.pizzaservice-lib.jar reference.pizzaservice-mailer.jar diff --git a/src/java/org/mxchange/pizzaservice/beans/checkout/CheckoutMessageBean.java b/src/java/org/mxchange/pizzaservice/beans/checkout/CheckoutMessageBean.java new file mode 100644 index 0000000..7d2b021 --- /dev/null +++ b/src/java/org/mxchange/pizzaservice/beans/checkout/CheckoutMessageBean.java @@ -0,0 +1,206 @@ +/* + * Copyright (C) 2016 Roland Häder + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License as + * published by the Free Software Foundation, either version 3 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see . + */ +package org.mxchange.pizzaservice.beans.checkout; + +import java.io.Serializable; +import java.text.MessageFormat; +import java.util.List; +import javax.ejb.ActivationConfigProperty; +import javax.ejb.EJB; +import javax.ejb.MessageDriven; +import javax.jms.JMSException; +import javax.jms.Message; +import javax.jms.MessageListener; +import javax.jms.ObjectMessage; +import javax.naming.Context; +import javax.naming.InitialContext; +import javax.naming.NamingException; +import org.mxchange.jcoreeelogger.beans.local.logger.Log; +import org.mxchange.jcoreeelogger.beans.local.logger.LoggerBeanLocal; +import org.mxchange.jcustomercore.exceptions.CustomerAlreadyRegisteredException; +import org.mxchange.jcustomercore.model.customer.Customer; +import org.mxchange.jcustomercore.model.customer.CustomerSessionBeanRemote; +import org.mxchange.jshopcore.model.basket.AddableBasketItem; +import org.mxchange.jshopcore.model.basket.BasketSessionBeanRemote; +import org.mxchange.jshopcore.model.receipt.ReceiptBeanRemote; +import org.mxchange.jshopcore.wrapper.WrapableCheckout; + +/** + * A message-driven bean for checkouts + *

+ * @author Roland Häder + */ +@MessageDriven ( + name = "checkout", + description = "A message bean for shop checkouts", + activationConfig = { + @ActivationConfigProperty (propertyName = "destinationType", propertyValue = "javax.jms.Queue"), + @ActivationConfigProperty (propertyName = "destinationLookup", propertyValue = "jms/shopCheckoutQueue") + } +) +public class CheckoutMessageBean implements MessageListener { + + /** + * Basket bean + */ + @EJB + private BasketSessionBeanRemote basketBean; + + /** + * Customer instance + */ + @EJB + private CustomerSessionBeanRemote customerBean; + + /** + * Logger bean + */ + @Log + private LoggerBeanLocal loggerBeanLocal; + + /** + * Receipt bean + */ + @EJB + private ReceiptBeanRemote receiptBean; + + /** + * Default constructor + */ + public CheckoutMessageBean () { + try { + // Get initial context + Context context = new InitialContext(); + + // Lookup logger + this.loggerBeanLocal = (LoggerBeanLocal) context.lookup("java:global/jcore-logger-ejb/logger!org.mxchange.jcoreeelogger.beans.local.logger.LoggerBeanLocal"); //NOI18N + } catch (final NamingException ex) { + // Continue to throw + throw new RuntimeException(MessageFormat.format("context.lookup() failed: {0}", ex.getMessage()), ex); //NOI18N + } + } + + @Override + public void onMessage (final Message message) { + // Trace message + this.loggerBeanLocal.logTrace(MessageFormat.format("onMessage: message={0} - CALLED!", message)); //NOI18N + + // Is the message castable to ObjectMessage? + if (null == message) { + // message is null + throw new NullPointerException("message is null"); //NOI18N + } else if (!(message instanceof ObjectMessage)) { + // Not castable + throw new ClassCastException(MessageFormat.format("message cannot be casted to ObjectMessage: {0}", message)); //NOI18N + } + + // Securely cast it + ObjectMessage objectMessage = (ObjectMessage) message; + + // Init instance + Serializable object; + + try { + // Get object from it + object = objectMessage.getObject(); + } catch (final JMSException ex) { + // Log exception ... + this.loggerBeanLocal.logException(ex); + + // ... and don't continue + return; + } + + // Debug message + this.loggerBeanLocal.logDebug(MessageFormat.format("onMessage: object={0}", object)); //NOI18N + + // Does this object implement WrapableCheckout ? + if (null == object) { + // object cannot be null + throw new NullPointerException("object is null"); //NOI18N + } else if (!(object instanceof WrapableCheckout)) { + // Not proper interface used + throw new ClassCastException(MessageFormat.format("object does not implement WrapableCheckout: {0}", object)); //NOI18N + } + + // Securely cast it + WrapableCheckout checkout = (WrapableCheckout) object; + + // Get customer and list from it + Customer customer = checkout.getCustomer(); + List orderedItems = checkout.getList(); + + // Debug message + this.loggerBeanLocal.logDebug(MessageFormat.format("onMessage: customerInstance={0},itemList={1}", customer, orderedItems)); //NOI18N + + // Check both on null + if (null == customer) { + // customer is null + throw new NullPointerException("customer is null"); //NOI18N + } else if (null == orderedItems) { + // list is null + throw new NullPointerException("list is null"); //NOI18N + } + + try { + // Is the customer already registered? + if (this.customerBean.isRegistered(customer)) { + // Already registered, so get all data + customer = this.customerBean.fillCustomerData(customer); + } else { + // Register customer first, this generates a customer number + customer = this.customerBean.registerCustomer(customer); + } + } catch (final CustomerAlreadyRegisteredException ex) { + // Log exception and abort + this.loggerBeanLocal.logException(ex); + return; + } + + // Is the instance set? + if (null == customer) { + // Customer is null + throw new NullPointerException("customer is null"); //NOI18N + } + + // Make sure the number has been regenerated + if (customer.getCustomerNumber() == null) { + // Not assigned + throw new NullPointerException(MessageFormat.format("registerCustomer() did not create a custome number: customerInstance={0}", customer)); //NOI18N + } + + // Now add the ordered item list + String accessKey = this.basketBean.registerItems(customer, orderedItems); + + // Debug message + this.loggerBeanLocal.logDebug(MessageFormat.format("onMessage: accessKey={0}", accessKey)); //NOI18N + + // Should not be null + if (null == accessKey) { + // Abort here + throw new NullPointerException("accessKey is null"); //NOI18N + } + + // Set access key and customer + this.receiptBean.setAccessKey(accessKey); + this.receiptBean.setCustomer(customer); + + // Trace message + this.loggerBeanLocal.logTrace("onMessage: EXIT!"); //NOI18N + } + +} diff --git a/src/java/org/mxchange/pizzaservice/model/basket/BasketSessionBean.java b/src/java/org/mxchange/pizzaservice/model/basket/BasketSessionBean.java new file mode 100644 index 0000000..07f7148 --- /dev/null +++ b/src/java/org/mxchange/pizzaservice/model/basket/BasketSessionBean.java @@ -0,0 +1,117 @@ +/* + * Copyright (C) 2016 Roland Häder + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License as + * published by the Free Software Foundation, either version 3 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see . + */ +package org.mxchange.pizzaservice.model.basket; + +import java.text.MessageFormat; +import java.util.GregorianCalendar; +import java.util.List; +import javax.ejb.Stateless; +import javax.persistence.EntityExistsException; +import org.mxchange.jcoreee.database.BaseDatabaseBean; +import org.mxchange.jcustomercore.model.customer.Customer; +import org.mxchange.jshopcore.model.basket.AddableBasketItem; +import org.mxchange.jshopcore.model.basket.BasketSessionBeanRemote; +import org.mxchange.jshopcore.model.customer.CustomerUtils; +import org.mxchange.jshopcore.model.order.Orderable; +import org.mxchange.jshopcore.model.order.ShopOrder; + +/** + * A basket for orderable items + *

+ * @author Roland Häder + */ +@Stateless (name = "basket", description = "A bean handling persisting baskets of logged-in customers") +public class BasketSessionBean extends BaseDatabaseBean implements BasketSessionBeanRemote { + + /** + * Serial number + */ + private static final long serialVersionUID = 4_384_123_923_163_957L; + + /** + * Default constructor + */ + public BasketSessionBean () { + } + + @Override + public void clear () { + // @TODO Nothing done so far + } + + @Override + public String registerItems (final Customer customer, final List orderedItems) { + // Trace message + this.getLoggerBeanLocal().logTrace(MessageFormat.format("registerItems: customer={0},itemList={1} - CALLED!", customer, orderedItems)); //NOI18N + + // Init variable for access key + String accessKey; + + // customer/itemList should not be null + if (null == customer) { + // Abort here + throw new NullPointerException("customer is null"); //NOI18N + } else if (null == orderedItems) { + // Abort here + throw new NullPointerException("itemList is null"); //NOI18N + } else if (customer.getCustomerId() == null) { + // null pointer found + throw new NullPointerException(MessageFormat.format("customer {0} id is null", customer)); //NOI18N + } else if (customer.getCustomerId() == 0) { + // id not set + throw new IllegalArgumentException(MessageFormat.format("customer {0} has no id set", customer)); //NOI18N + } else if (orderedItems.isEmpty()) { + // Empty list + throw new IllegalArgumentException("item list is empty"); //NOI18N + } + + // First try to register the order (to get an id number from it) + try { + // Generate access key + accessKey = CustomerUtils.generateAccessKey(this.getEntityManager(), customer); + + // Debug message + this.getLoggerBeanLocal().logDebug(MessageFormat.format("registerItems: accessKey={0}", accessKey)); //NOI18N + + // Create order object + Orderable order = new ShopOrder(); + order.setCustomer(customer); + order.setAccessKey(accessKey); + order.setOrderedItems(orderedItems); + order.setOrderCreated(new GregorianCalendar()); + + // Persist it + this.getEntityManager().persist(order); + } catch (final EntityExistsException ex) { + // Log exception + this.getLoggerBeanLocal().logException(ex); + + /* + * Don't return an access key as the exception should never be + * thrown. + */ + accessKey = null; + } + + // Trace message + this.getLoggerBeanLocal().logTrace(MessageFormat.format("registerItems: accessKey={0} - EXIT!", accessKey)); //NOI18N + + // Return it + return accessKey; + } + +} diff --git a/src/java/org/mxchange/pizzaservice/model/category/AdminCategorySessionBean.java b/src/java/org/mxchange/pizzaservice/model/category/AdminCategorySessionBean.java new file mode 100644 index 0000000..afce2c3 --- /dev/null +++ b/src/java/org/mxchange/pizzaservice/model/category/AdminCategorySessionBean.java @@ -0,0 +1,130 @@ +/* + * Copyright (C) 2016 Roland Häder + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License as + * published by the Free Software Foundation, either version 3 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see . + */ +package org.mxchange.pizzaservice.model.category; + +import java.text.MessageFormat; +import javax.ejb.Stateless; +import javax.persistence.EntityNotFoundException; +import javax.persistence.NoResultException; +import javax.persistence.Query; +import org.mxchange.jcoreee.database.BaseDatabaseBean; +import org.mxchange.jproduct.exceptions.CannotAddCategoryException; +import org.mxchange.jproduct.exceptions.CategoryTitleAlreadyUsedException; +import org.mxchange.jproduct.model.category.Category; +import org.mxchange.jproduct.model.category.ProductCategory; +import org.mxchange.jshopcore.model.category.AdminCategorySessionBeanRemote; + +/** + * An EJB for administrative access on categories + *

+ * @author Roland Häder + */ +@Stateless (name = "admin_category", description = "An administrative bean handling product categories") +public class AdminCategorySessionBean extends BaseDatabaseBean implements AdminCategorySessionBeanRemote { + + /** + * Serial number + */ + private static final long serialVersionUID = 26_143_895_789_581L; + + @Override + public Category doAdminAddCategory (final Category category) throws CategoryTitleAlreadyUsedException, CannotAddCategoryException { + // Trace message + this.getLoggerBeanLocal().logTrace(MessageFormat.format("doAdminAddCategory: category={0} - CALLED!", category)); //NOI18N + + if (null == category) { + // category is null + throw new NullPointerException("category is null"); //NOI18N + } else if (this.getEntityManager() == null) { + // Connection is not there + throw new NullPointerException("connection is null"); //NOI18N + } + + // The connection must be there + if (this.isCategoryTitleUsed(category)) { + // Then abort here + throw new CategoryTitleAlreadyUsedException(category); + } + + // Perist the category + this.getEntityManager().persist(category); + + // Flush it + this.getEntityManager().flush(); + + // Trace message + this.getLoggerBeanLocal().logTrace(MessageFormat.format("doAdminAddCategory: category={0} - EXIT!", category)); //NOI18N + + // Return it + return category; + } + + /** + * Checks if the category's title has already been used as they need to be + * unique. This method works case-insensitive. Any spaces, new-line, + * carriage-return or tabulator characters are trimmed away. If the title + * has been used already, for performance reasons, the id and parent id are + * set in the category object. + *

+ * @param category Category instance + *

+ * @return Whether the category's title has been used + */ + private boolean isCategoryTitleUsed (final Category category) { + // Trace message + this.getLoggerBeanLocal().logTrace(MessageFormat.format("isCategoryTitleUsed: category={0} - CALLED!", category)); //NOI18N + + // The connection must be there + if (null == category) { + // category is null + throw new NullPointerException("category is null"); //NOI18N + } else if (this.getEntityManager() == null) { + // Connection is not there + throw new NullPointerException("connection is null"); //NOI18N + } + + // Default is not found + boolean isUsed = false; + + // Debug message + this.getLoggerBeanLocal().logDebug(MessageFormat.format("isCategoryTitleUsed: category.id={0},category.title={1},category.parentId={2}", category.getCategoryId(), category.getCategoryTitle(), category.getParentCategory())); //NOI18N + + // Try to locate it + try { + // Get query instance + Query query = this.getEntityManager().createQuery("SELECT c FROM category AS c WHERE LOWER(c.categoryTitle) = LOWER(:param)", ProductCategory.class); //NOI18N + query.setParameter("param", category.getCategoryTitle()); //NOI18N + Category cat = (Category) query.getSingleResult(); + + // Is found, so copy the object + category.copyAll(cat); + + // Mark as found + isUsed = true; + } catch (final EntityNotFoundException | NoResultException e) { + // Not found + this.getLoggerBeanLocal().logWarning(e.getMessage()); + } + + // Trace message + this.getLoggerBeanLocal().logTrace(MessageFormat.format("isCategoryTitleUsed: isUsed={0} - EXIT!", isUsed)); //NOI18N + + // Return it + return isUsed; + } + +} diff --git a/src/java/org/mxchange/pizzaservice/model/category/CategorySessionBean.java b/src/java/org/mxchange/pizzaservice/model/category/CategorySessionBean.java new file mode 100644 index 0000000..9f95f44 --- /dev/null +++ b/src/java/org/mxchange/pizzaservice/model/category/CategorySessionBean.java @@ -0,0 +1,72 @@ +/* + * Copyright (C) 2016 Roland Häder + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License as + * published by the Free Software Foundation, either version 3 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see . + */ +package org.mxchange.pizzaservice.model.category; + +import java.text.MessageFormat; +import java.util.List; +import javax.ejb.Stateless; +import javax.persistence.Query; +import org.mxchange.jcoreee.database.BaseDatabaseBean; +import org.mxchange.jproduct.model.category.Category; +import org.mxchange.jproduct.model.category.ProductCategory; +import org.mxchange.jshopcore.model.category.CategorySessionBeanRemote; + +/** + * Main shop class + *

+ * @author Roland Häder + */ +@Stateless (name = "category", description = "A bean handling categories for all others (non-admin)") +public class CategorySessionBean extends BaseDatabaseBean implements CategorySessionBeanRemote { + + /** + * Serial number + */ + private static final long serialVersionUID = 58_137_539_530_279L; + + /** + * Default constructor + */ + public CategorySessionBean () { + } + + @Override + @SuppressWarnings ("unchecked") + public List getAllCategories () { + // Trace message + this.getLoggerBeanLocal().logTrace("getAllCategories: CALLED!"); //NOI18N + + // The connection must be there + if (this.getEntityManager() == null) { + // Connection is not there + throw new NullPointerException("connection is null"); //NOI18N + } + + // Create statement + Query query = this.getEntityManager().createQuery("SELECT c FROM category AS c ORDER BY c.categoryId ASC", ProductCategory.class); + + // Get result + List list = query.getResultList(); + + // Trace message + this.getLoggerBeanLocal().logTrace(MessageFormat.format("getAllCategories: list({0})={1} - EXIT!", list.size(), list)); //NOI18N + + // Return it + return list; + } + +} diff --git a/src/java/org/mxchange/pizzaservice/model/customer/ShopCustomerSessionBean.java b/src/java/org/mxchange/pizzaservice/model/customer/ShopCustomerSessionBean.java new file mode 100644 index 0000000..d0274fd --- /dev/null +++ b/src/java/org/mxchange/pizzaservice/model/customer/ShopCustomerSessionBean.java @@ -0,0 +1,151 @@ +/* + * Copyright (C) 2016 Roland Häder + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License as + * published by the Free Software Foundation, either version 3 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see . + */ +package org.mxchange.pizzaservice.model.customer; + +import java.text.MessageFormat; +import java.util.GregorianCalendar; +import javax.ejb.Stateless; +import javax.persistence.EntityNotFoundException; +import org.mxchange.jcoreee.database.BaseDatabaseBean; +import org.mxchange.jcustomercore.exceptions.CustomerAlreadyRegisteredException; +import org.mxchange.jcustomercore.exceptions.CustomerNotFoundException; +import org.mxchange.jcustomercore.model.customer.Customer; +import org.mxchange.jcustomercore.model.customer.CustomerSessionBeanRemote; + +/** + * A customer bean which hides the customer instance + *

+ * @author Roland Häder + */ +@Stateless (name = "shop_customer", description = "A bean handling the customer data") +public class ShopCustomerSessionBean extends BaseDatabaseBean implements CustomerSessionBeanRemote { + + /** + * Serial number + */ + private static final long serialVersionUID = 542_145_347_916L; + + /** + * Default constructor + */ + public ShopCustomerSessionBean () { + } + + @Override + public Customer fillCustomerData (final Customer customer) { + // Trace message + this.getLoggerBeanLocal().logTrace(MessageFormat.format("fillCustomerData: customer={0} - CALLED!", customer)); //NOI18N + + // customer should not be null + if (null == customer) { + // Abort here + throw new NullPointerException("customer is null"); //NOI18N + } + + // Try it + try { + // Try to locate it + Customer cat = this.getEntityManager().getReference(Customer.class, customer); + + // Copy all data + customer.copyAll(cat); + } catch (final EntityNotFoundException ex) { + // Log it + this.getLoggerBeanLocal().logException(ex); + + // Return null + return null; + } + + // Trace message + this.getLoggerBeanLocal().logTrace(MessageFormat.format("fillCustomerData: customer={0} - EXIT!", customer)); //NOI18N + + // Return prepared instance + return customer; + } + + @Override + public Customer findCustomerById (final Long customerId) throws CustomerNotFoundException { + throw new UnsupportedOperationException("Not supported yet."); //To change body of generated methods, choose Tools | Templates. + } + + @Override + public boolean isRegistered (final Customer customer) { + // Trace message + this.getLoggerBeanLocal().logTrace(MessageFormat.format("isRegistered: customer={0} - CALLED!", customer)); //NOI18N + + // customer should not be null + if (null == customer) { + // Abort here + throw new NullPointerException("customer is null"); //NOI18N + } + + // Try this + try { + Customer c = this.getEntityManager().getReference(Customer.class, customer); + } catch (final EntityNotFoundException ex) { + // Log it + this.getLoggerBeanLocal().logException(ex); + + // Did not finish + return false; + } + + // Found it + return true; + } + + @Override + public Customer registerCustomer (final Customer customer) throws CustomerAlreadyRegisteredException { + // Trace message + this.getLoggerBeanLocal().logTrace(MessageFormat.format("registerCustomer: customer={0} - CALLED!", customer)); //NOI18N + + // customer should not be null + if (null == customer) { + // Abort here + throw new NullPointerException("customer is null"); //NOI18N + } + + // Is the customer registered? + if (this.isRegistered(customer)) { + // Already registered + throw new CustomerAlreadyRegisteredException(customer); + } + + // Debug message + this.getLoggerBeanLocal().logDebug(MessageFormat.format("registerCustomer: Preparing statement for customer={0}", customer)); //NOI18N + + // Set creation timestamp + customer.setCustomerCreated(new GregorianCalendar()); + + // Try to persist it + this.getEntityManager().persist(customer); + + // Flush it as the id might be needed + this.getEntityManager().flush(); + + // Debug message + this.getLoggerBeanLocal().logDebug(MessageFormat.format("registerCustomer: customer.id={0}", customer.getCustomerId())); //NOI18N + + // Trace message + this.getLoggerBeanLocal().logTrace(MessageFormat.format("registerCustomer: customer={0} - CALLED!", customer)); //NOI18N + + // Return prepared instance + return customer; + } + +} diff --git a/src/java/org/mxchange/pizzaservice/model/product/AdminProductSessionBean.java b/src/java/org/mxchange/pizzaservice/model/product/AdminProductSessionBean.java new file mode 100644 index 0000000..ae0f909 --- /dev/null +++ b/src/java/org/mxchange/pizzaservice/model/product/AdminProductSessionBean.java @@ -0,0 +1,163 @@ +/* + * Copyright (C) 2016 Roland Häder + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License as + * published by the Free Software Foundation, either version 3 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see . + */ +package org.mxchange.pizzaservice.model.product; + +import java.text.MessageFormat; +import java.util.List; +import javax.ejb.Stateless; +import javax.persistence.EntityExistsException; +import javax.persistence.EntityNotFoundException; +import javax.persistence.NoResultException; +import javax.persistence.Query; +import org.mxchange.jcoreee.database.BaseDatabaseBean; +import org.mxchange.jproduct.exceptions.CannotAddProductException; +import org.mxchange.jproduct.exceptions.ProductTitleAlreadyUsedException; +import org.mxchange.jproduct.model.product.GenericProduct; +import org.mxchange.jproduct.model.product.Product; +import org.mxchange.jshopcore.model.product.AdminProductSessionBeanRemote; + +/** + * A session bean for non-administrative roles for products + *

+ * @author Roland Häder + */ +@Stateless (name = "admin_product", description = "An administrative bean handling products") +public class AdminProductSessionBean extends BaseDatabaseBean implements AdminProductSessionBeanRemote { + + /** + * Serial number + */ + private static final long serialVersionUID = 65_173_487_394_812L; + + /** + * Default constructor + */ + public AdminProductSessionBean () { + } + + @Override + public Product doAdminAddProduct (final Product product) throws ProductTitleAlreadyUsedException, CannotAddProductException { + // Trace message + this.getLoggerBeanLocal().logTrace(MessageFormat.format("doAdminAddProduct: product={0} - CALLED!", product)); //NOI18N + + // Check if product's title is used + if (null == product) { + // product is null + throw new NullPointerException("product is null"); //NOI18N + } else if (this.getEntityManager() == null) { + // Connection is not there + throw new NullPointerException("connection is null"); //NOI18N + } else if (this.isProductTitleUsed(product)) { + // Throw exception + throw new ProductTitleAlreadyUsedException(product); + } + + try { + // Persist it + this.getEntityManager().persist(product); + + // Flush it as the id might be needed immediately + this.getEntityManager().flush(); + } catch (final EntityExistsException ex) { + // Continue to throw + throw new CannotAddProductException(ex); + } + + // Trace message + this.getLoggerBeanLocal().logTrace(MessageFormat.format("doAdminAddProduct: product={0} - EXIT!", product)); //NOI18N + + // Return it + return product; + } + + @Override + @SuppressWarnings ("unchecked") + public List getAllProducts () { + // Trace message + this.getLoggerBeanLocal().logTrace("getAllProducts: CALLED!"); //NOI18N + + // The connection must be there + if (this.getEntityManager() == null) { + // Connection is not there + throw new NullPointerException("connection is null"); //NOI18N + } + + // Create statement + Query query = this.getEntityManager().createQuery("SELECT p FROM products AS p ORDER BY p.productId ASC", GenericProduct.class); //NOI18N + + // Get list + List list = query.getResultList(); + + // Trace message + this.getLoggerBeanLocal().logTrace(MessageFormat.format("getAllProducts: list({0})={1} - EXIT!", list.size(), list)); //NOI18N + + // Return it + return list; + } + + /** + * Checks if the product's title has already been used as they need to be + * unique. This method works case-insensitive. Any spaces, new-line, + * carriage-return or tabulator characters are trimmed away. If the title + * has been used already, for performance reasons, the whole data is set in + * the product object. + *

+ * @param product Product instance + *

+ * @return Whether the product's title has been used + */ + private boolean isProductTitleUsed (final Product product) { + // Trace message + this.getLoggerBeanLocal().logTrace(MessageFormat.format("isProductTitleUsed: Product={0} - CALLED!", product)); //NOI18N + + // The connection must be there + if (null == product) { + // product is null + throw new NullPointerException("product is null"); //NOI18N + } else if (this.getEntityManager() == null) { + // Connection is not there + throw new NullPointerException("connection is null"); //NOI18N + } + + // Default is not found + boolean isUsed = false; + + // Try to locate it + try { + // Get query instance + Query query = this.getEntityManager().createQuery("SELECT p FROM products AS p WHERE LOWER(p.productTitle) = LOWER(:param)", GenericProduct.class); //NOI18N + query.setParameter("param", product.getProductTitle()); //NOI18N + Product pro = (Product) query.getSingleResult(); + + // Is found, so copy the object + product.copyAll(pro); + + // Mark as found + isUsed = true; + } catch (final EntityNotFoundException | NoResultException e) { + // Not found + this.getLoggerBeanLocal().logWarning(e.getMessage()); + } + + // Trace message + this.getLoggerBeanLocal().logTrace(MessageFormat.format("isProductTitleUsed: isUsed={0} - EXIT!", isUsed)); //NOI18N + + // Return it + return isUsed; + } + +} diff --git a/src/java/org/mxchange/pizzaservice/model/product/ProductSessionBean.java b/src/java/org/mxchange/pizzaservice/model/product/ProductSessionBean.java new file mode 100644 index 0000000..d7d0eef --- /dev/null +++ b/src/java/org/mxchange/pizzaservice/model/product/ProductSessionBean.java @@ -0,0 +1,103 @@ +/* + * Copyright (C) 2016 Roland Häder + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License as + * published by the Free Software Foundation, either version 3 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see . + */ +package org.mxchange.pizzaservice.model.product; + +import java.text.MessageFormat; +import java.util.Iterator; +import java.util.LinkedList; +import java.util.List; +import javax.ejb.EJB; +import javax.ejb.Stateless; +import org.mxchange.jcoreee.database.BaseDatabaseBean; +import org.mxchange.jproduct.model.product.Product; +import org.mxchange.jshopcore.model.product.AdminProductSessionBeanRemote; +import org.mxchange.jshopcore.model.product.ProductSessionBeanRemote; + +/** + * A session bean for non-administrative roles for products + *

+ * @author Roland Häder + */ +@Stateless (name = "product", description = "A bean handling products for all others (non-admin)") +public class ProductSessionBean extends BaseDatabaseBean implements ProductSessionBeanRemote { + + /** + * Serial number + */ + private static final long serialVersionUID = 65_173_487_394_812L; + + /** + * Administrative bean + */ + @EJB + private AdminProductSessionBeanRemote productBean; + + /** + * Default constructor + */ + public ProductSessionBean () { + } + + @Override + public List getAvailableProducts () { + // Trace message + this.getLoggerBeanLocal().logTrace("getAvailableProducts: CALLED!"); //NOI18N + + // The connection must be there + if (this.getEntityManager() == null) { + // Connection is not there + throw new NullPointerException("connection is null"); //NOI18N + } + + // Get all products + List allProducts = this.productBean.getAllProducts(); + + // Trace message + this.getLoggerBeanLocal().logTrace(MessageFormat.format("getAvailableProducts: allProducts({0})={1}", allProducts.size(), allProducts)); //NOI18N + + // Init deque + List deque = new LinkedList<>(); + + // Get iterator + Iterator iterator = allProducts.iterator(); + + // Walk through all and add only available + while (iterator.hasNext()) { + // Get element + Product localProduct = iterator.next(); + + // Debug message + this.getLoggerBeanLocal().logDebug(MessageFormat.format("getAvailableProducts: localProduct={0}", localProduct)); //NOI18N + + // Is this available? + if (localProduct.getProductAvailability()) { + // Debug message + this.getLoggerBeanLocal().logDebug(MessageFormat.format("getAvailableProducts: localProduct={0} - ADDED!", localProduct)); //NOI18N + + // Add it + deque.add(localProduct); + } + } + + // Trace message + this.getLoggerBeanLocal().logTrace(MessageFormat.format("getAvailableProducts: deque({0})={1} - EXIT!", deque.size(), deque)); //NOI18N + + // Return it + return deque; + } + +} diff --git a/src/java/org/mxchange/pizzaservice/model/receipt/PdfReceiptSessionBean.java b/src/java/org/mxchange/pizzaservice/model/receipt/PdfReceiptSessionBean.java new file mode 100644 index 0000000..34267c4 --- /dev/null +++ b/src/java/org/mxchange/pizzaservice/model/receipt/PdfReceiptSessionBean.java @@ -0,0 +1,136 @@ +/* + * Copyright (C) 2016 Roland Häder + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License as + * published by the Free Software Foundation, either version 3 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see . + */ +package org.mxchange.pizzaservice.model.receipt; + +import java.text.MessageFormat; +import javax.ejb.Stateless; +import javax.naming.Context; +import javax.naming.InitialContext; +import javax.naming.NamingException; +import org.mxchange.jcoreee.database.BaseDatabaseBean; +import org.mxchange.jcustomercore.model.customer.Customer; +import org.mxchange.jshopcore.model.receipt.ReceiptBeanRemote; +import org.mxchange.jshopcore.model.receipt.WrapableReceipt; +import org.mxchange.jshopreceipt.receipt.PdfReceiptBeanLocal; +import org.mxchange.jshopreceipt.receipt.Receipt; + +/** + * A stateless session bean for producing official receipts in Abobe's whacky + * binary format. This class uses GNUjpdf which allows using ordinary graphic + * libraries. + *

+ * @author Roland Häder + */ +@Stateless (name = "pdf", description = "A bean creating PDF receipts") +public class PdfReceiptSessionBean extends BaseDatabaseBean implements ReceiptBeanRemote { + + /** + * Serial number + */ + private static final long serialVersionUID = 384_578_171_659_628L; + + /** + * Access key + */ + private String accessKey; + + /** + * Customer instance + */ + private Customer customer; + + /** + * PDF receipt injection + */ + @Receipt + private PdfReceiptBeanLocal pdfReceiptBeanLocal; + + /** + * Default constructor + */ + public PdfReceiptSessionBean () { + try { + // Get initial context + Context context = new InitialContext(); + + // Lookup pdf receipt + this.pdfReceiptBeanLocal = (PdfReceiptBeanLocal) context.lookup("java:global/jshop-receipt-ejb/pdf-receipt!org.mxchange.jshopreceipt.receipt.PdfReceiptBeanLocal"); //NOI18N + } catch (final NamingException ex) { + // Continue to throw + throw new RuntimeException(MessageFormat.format("context.lookup() failed: {0}", ex.getMessage()), ex); //NOI18N + } + } + + @Override + public WrapableReceipt createReceiptFromAccessKey (final String accessKey) { + // Trace message + this.getLoggerBeanLocal().logTrace(MessageFormat.format("createReceiptFromAccessKey: accessKey={0} - CALLED!", accessKey)); //NOI18N + + return null; + } + + @Override + public String fetchAccessKey (final Customer customer) { + // Trace message + this.getLoggerBeanLocal().logTrace(MessageFormat.format("fetchAccessKey: customer={0} - EXIT!", customer)); //NOI18N + + // customer should not be null + if (null == customer) { + // Abort here + throw new NullPointerException("customer is null"); //NOI18N + } else if (this.getCustomer() == null) { + // Don't continue, too. + throw new NullPointerException("this.getCustomer() returns null"); //NOI18N + } + + // Default is null + String key = null; + + // Is customer the same? + if (customer.equals(this.getCustomer())) { + // Set access key + key = this.getAccessKey(); + } + + // Trace message + this.getLoggerBeanLocal().logTrace(MessageFormat.format("fetchAccessKey: key={0} - EXIT!", key)); //NOI18N + + // Return it + return key; + } + + @Override + public String getAccessKey () { + return this.accessKey; + } + + @Override + public void setAccessKey (final String accessKey) { + this.accessKey = accessKey; + } + + @Override + public Customer getCustomer () { + return this.customer; + } + + @Override + public void setCustomer (final Customer customer) { + this.customer = customer; + } + +} diff --git a/src/java/org/mxchange/pizzaservice/receipt/PdfReceiptBean.java b/src/java/org/mxchange/pizzaservice/receipt/PdfReceiptBean.java new file mode 100644 index 0000000..1650329 --- /dev/null +++ b/src/java/org/mxchange/pizzaservice/receipt/PdfReceiptBean.java @@ -0,0 +1,56 @@ +/* + * Copyright (C) 2016 Roland Häder + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License as + * published by the Free Software Foundation, either version 3 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see . + */ +package org.mxchange.pizzaservice.receipt; + +import gnu.jpdf.PDFJob; +import javax.ejb.Singleton; +import javax.ejb.Startup; +import javax.inject.Inject; +import org.mxchange.jshopreceipt.receipt.PdfReceiptBeanLocal; +import org.mxchange.jshopreceipt.receipt.Receipt; + +/** + * A "centralized" logger bean + *

+ * @author Roland Häder + */ +@Startup +@Singleton (name = "pdf-receipt", description = "An EJB for producing PDF receipts") +public class PdfReceiptBean implements PdfReceiptBeanLocal { + + /** + * PDF job instance + */ + @Inject + @Receipt + private PDFJob job; + + /** + * Default constructor + */ + public PdfReceiptBean () { + } + + /** + * Getter for PDF job + *

+ * @return PDF job + */ + private PDFJob getJob () { + return this.job; + } +} diff --git a/src/java/org/mxchange/pizzaservice/receipt/ReceiptFactory.java b/src/java/org/mxchange/pizzaservice/receipt/ReceiptFactory.java new file mode 100644 index 0000000..120a61d --- /dev/null +++ b/src/java/org/mxchange/pizzaservice/receipt/ReceiptFactory.java @@ -0,0 +1,55 @@ +/* + * Copyright (C) 2016 Roland Häder + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License as + * published by the Free Software Foundation, either version 3 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see . + */ +package org.mxchange.pizzaservice.receipt; + +import gnu.jpdf.PDFJob; +import javax.enterprise.inject.Produces; +import javax.enterprise.inject.spi.InjectionPoint; +import org.mxchange.jshopreceipt.receipt.Receipt; + +/** + * A logger factory + *

+ * @author Roland Häder + */ +public class ReceiptFactory { + + /** + * Own job + */ + private final PDFJob job; + + /** + * Factory method + */ + public ReceiptFactory () { + this.job = new PDFJob(); + } + + /** + * Produces a PDF job instance + *

+ * @param caller Injection point + *

+ * @return PDF job + */ + @Produces + @Receipt + public PDFJob getJob (final InjectionPoint caller) { + return this.job; + } +} -- 2.39.5