From ead45803fc587fe964120a41d9c488fcb680ed4a Mon Sep 17 00:00:00 2001 From: Ruud Arentsen Date: Wed, 26 Dec 2018 14:15:14 +0100 Subject: [PATCH 1/2] Setup for BrewBuddy on Darwin --- Darwin-copy-resources-to-bundle.sh | 5 + .../usr/local/lib/libdoublefann.2.2.0.dylib | Bin 0 -> 109416 bytes .../fann/usr/local/lib/libfann.2.2.0.dylib | Bin 0 -> 109360 bytes .../usr/local/lib/libfixedfann.2.2.0.dylib | Bin 0 -> 69336 bytes .../usr/local/lib/libfloatfann.2.2.0.dylib | Bin 0 -> 109360 bytes Source/Units/backup/backup/containers.pas.bak | 3524 +++++++++++++++++ Source/Units/backup/bh_report.pas | 2464 ++++++++++++ Source/Units/backup/containers.pas | 3524 +++++++++++++++++ Source/Units/backup/fann.pas | 1228 ++++++ Source/Units/backup/hulpfuncties.pas | 2531 ++++++++++++ Source/Units/bh_report.pas | 7 +- Source/Units/containers.pas | 14 +- Source/Units/fann.pas | 2456 ++++++------ Source/Units/hulpfuncties.pas | 8 +- .../Forms/backup/frrestoredatabases.pas | 102 + .../Forms/frrestoredatabases.pas | 5 +- Source/backup/brewbuddy.pas | 51 + Source/backup/brewbuddy_osx.lpi | 1846 +++++++++ Source/brewbuddy.pas | 2 +- Source/brewbuddy_osx.lpi | 334 +- 20 files changed, 16799 insertions(+), 1302 deletions(-) create mode 100755 Darwin-copy-resources-to-bundle.sh create mode 100755 Source/3rdParty/fann/usr/local/lib/libdoublefann.2.2.0.dylib create mode 100755 Source/3rdParty/fann/usr/local/lib/libfann.2.2.0.dylib create mode 100755 Source/3rdParty/fann/usr/local/lib/libfixedfann.2.2.0.dylib create mode 100755 Source/3rdParty/fann/usr/local/lib/libfloatfann.2.2.0.dylib create mode 100644 Source/Units/backup/backup/containers.pas.bak create mode 100644 Source/Units/backup/bh_report.pas create mode 100644 Source/Units/backup/containers.pas create mode 100644 Source/Units/backup/fann.pas create mode 100644 Source/Units/backup/hulpfuncties.pas create mode 100644 Source/UserInterface/Forms/backup/frrestoredatabases.pas create mode 100644 Source/backup/brewbuddy.pas create mode 100644 Source/backup/brewbuddy_osx.lpi diff --git a/Darwin-copy-resources-to-bundle.sh b/Darwin-copy-resources-to-bundle.sh new file mode 100755 index 00000000..62228424 --- /dev/null +++ b/Darwin-copy-resources-to-bundle.sh @@ -0,0 +1,5 @@ +#!/bin/sh + +appfolder=BrewBuddy.app +cp -R ./Misc/Standaard\ databanken/* Output/$appfolder/Contents/Resources/ +cp ./Misc/Handleiding/Introductie\ BrouwHulp\ Sassy\ Saison.pdf Output/$appfolder/Contents/Resources/Introductie\ BrewBuddy\ Sassy\ Saison.pdf diff --git a/Source/3rdParty/fann/usr/local/lib/libdoublefann.2.2.0.dylib b/Source/3rdParty/fann/usr/local/lib/libdoublefann.2.2.0.dylib new file mode 100755 index 0000000000000000000000000000000000000000..da74893dafe801669477cf0a5f17ad21d4c21417 GIT binary patch literal 109416 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 z�!r;Mg;(gJYxls;sfOtu>U};@-b)@l-vE5ON z{^wCms&m>}51(Uas`+YOQ)^|t$$zl2v6^!ciMonQQ4DESQ)6SKsb)t0PsFSN4~UNs}g?1wq@?4Q>9U z2sQb*u;Riw6~Vg3s+LG)G=jobwL*lRKQ}S*@L7oKTPuSNb&VdD0(v;kV zTHP6>^-DHv#y-?;(gqYwI6K%`Ii~JsvP&X6Qc`fWGvQ(E$pE+>A?cDx-QwETU_)Dd zYh81F9W<%q&(xdAt&6z=og-{|6DM`K z(LZ6@I; zQX3+xUHBF-lj_ji(2q%8ehHx%{h|F7#6jUu z2Zv_mAOthYSWt1d3`gs(ibN4s9aMOy)JLfO*0)ths;8nq>yU;>Wg~(?RAY#s73x@j zakwUHj4Yuh>9(C~2t2_r{{l}qR#F-n8usF~D}EeiwHAtj>( zT!EHE#!pq_#fiXF10p#gz*bSw;5Y#y)#28ruugeGP**;4ss^WO=0Z=xfpz9Z zB^S;un={*1nUhFmYIVvAl#1d|moDw;)|`$kvDSnL*tBGgX_FdlsWLUC4)SP833O>l ztJy*LkgQjED34}zzzuE6S0hTOM;lt9q6yt_!F-X)*UH1D4n{?tG3AMaOtfKT~pU6K}OS90hYpYazMk+U}1+D z9(IVWtQ@MOo)n4JGyDjJ4sA;R@u2^s*eH6wYOZXlY>2c*TA~zz!Vt9_7OvQ}V<%Tn z44xN>*0n^cgKXxU14T2bsAgimDzQy;CY#aL(t^R2n=EJz>c&xQ8mA@auIUY+Ju2U9vUJIO)XahhwsHsD=Q^rP5 z3D#gdh4E4~MzfzS(h`h&b)<_ieX%%r1!O|w8?sq5(t>th)YL-soR~imXNcs)MU+fQ zE?b%!eAxQO(25_U#+oJ!yFNoi=ey)^5ih)O&V`gCGYt`rHo@3wfgwEs^?~UOyz?z2 zo7bKSVYMH`h_5o}t_@qTZb8`P@rybElK_novspfxu6S)2Z685|d1fMn%hAvlZ4EBM$hRgK!K>#ASS)DX(bkr>s@Ara$e|P9oVw;z zKtH!_Q8a={4yr|1L0}A)i%}Q=jZLjVBvDt5nhsjAiQGvBCS{G)k);%)E=proLN9`8 zM}nFQtBTUJyEU_IZiz&Zbr8&h(4hVoVSI^bY`<9ZRFo{xm5q(Tab#A|ycNrVq3Wi_ zFJgRJ*;-ZWWrIx644E;FJ_DaG1yz1N>l+gp(}g|?hbCHP>*+uqwlY^M?O+$v;xfQPNVDVt=@!qAfq zt=T2>=6$oGBs{D5nzgXWgbxp3Z$`SWz>ybFuVW{1mW&$zIpykz#g;#tn%>BaMA zlsW@=4#^pC!Thor-=K*lXW-mo2VDvE?wRvv&j`;dn_W^YnXyCX70;F==FXc_!Gz^= zOEfzxWO|uo*U4jE>4haI%&hYyZ3BkqezUy1WZs2kGlWao`Q>xUglet^!gJ@9R9swU zC1gT*W3uxnpUM|4jam-j7P)s05Bm;HU(SO5msjj!NLD1ddAJs05Bm;HU)t z|B%42F~NnSi!Ux-h~pLLZ&)ZC4r9rw>N2dWT^3&4R@qXmF1Wm~ONUou&a7E=g{rTt zuLfD$qVS?ROfFQAqQm)tDokwjKb>rfk-=^7gekCTh*_IE<&p!hm^|2ShES! z+~Lzh+nUM!E3A5kHbhz$N5VX%9i|Cob;l?@?d=SEXcR3=s>CRj3%OIo_p`_qC#?RQ z)1+4A)<)29dBWQG&agLu`sjG=Gojfxp^W#RpaN0#AK5g^9hBD%-3gs5=AX3ZXg%22@uB zth;bbNp?g%A83Og7_EUhrF73Il^s=Y1!^kcC?+fF)X;7?6@_bQx>Bvpp`|*(K#*0n zk!p44NcOf+>qn!Ity!9(dgu6nieHTsd%kbVeNRq~O1EP^D$v%bcIH4@O%2pkOatl7 ziKzPuKyz)D!u8jnL_y#@sznr4v0PdX#S%oAmms35Z*-38xrgYQuT(eZHejJZH;~7N z=BTdwff!t+{+ZjVwhnAm?+vV1j|^H=r~Wbs3pOpfvHa&?YEM5Zu$Oqk>h@u_D}eg_ zF?#7=bsih7l*d<{{pnN!HYpJ{=fQ zD+Z~6E{VD&k2{Y#kf&Yb)PsX^RP0rvu4`4l%fp+Y9*cZNC#ZLjZdkpT=T#O_)eDSi z5PNl&bxr+vFbWEe;Jb&ei8Ni4xT2MiH?npaxn&SJh^uRdfo>n+$UjfrH%NEAW%*!& zU_@smIf|-@IR@+VY#3#%&C!^b$9?%Ss6-gRtL{opu{zs0`KYklYGQhyjNjnfnU%4lvr z{Nni;)t(k8zBJK^iisT{NyI*)Yxl=26~3nV8mIGPv$2Y<9vED$9tM5SKbhuJG{Z^Z zN$R>G5cGZ7c$e%P48lgZ3^Z2Ot2YL>s&}c{e*;uawOTU-tunuV}!9Yjr!~7Asl+wZZ4=)?Z>NZN@GU>sk3*X zOA|k49=NI;o#669t3jzXg>|d|8`O1$q6^iHh2X!QV)fic*Y02Q^*7*vdR%Nfw5smH zuzCZ+>e-Zu+X39Q#~}BN;~u-G(DM1(|9J@T5sJl_*f0z8Phh%%0awOr2VHf`Fcn8i z$<2gGZ=sl0E7&s3ZX7RAb`nGs-^!%=`Y1DejKd$N$hzfQELI)k_A7f8xrjgELwK); z@Gl@tfDl<@a(P2Me~i2{?mY>O;z?q}zPaknW8isq5ORq-0zaa_mB)e;0>O!|v27H~ z->c-*h z%=W@?%7}^&ho{>UK*t4rzefK-qqh+H8K4tDBMH97o?@BvHG!)N$QzNx5suc@)wHUv z<4}RkVuPq()Ww^6(BC)p|_&r*v339`-C*fT5vz9#sZUa!Fz*4v` z9}ibhtzX|F^+6QSyMG^rZuBC@*+ti$m*^Vnr5a*aE_KU@Ce@C&oY?$P^=E#;|6+vt z=LnT!tB`FY>eRC%jPm&F2(4uHjX*d4Bb7w-%U?#&CKlREgSWtbVB;@yim&kXRn9|_ zudh)onB_N&WH*thdI|}%{``QFx@L7wdwN4NYU({ zjMOjJbtrZ6uf*T^!v1iix(S*x{jL{r{V4SlQlV)^FzcU>QqLf$Yab;UdylT&|KQ|f zIrO|b2h8( z50OSdmvD=`+SL=IbqQYpar|Z?>%Nt)i63*spYn5@!|$SNd;?z}pzJm_sZU13OGzz< z9T|Iw5x6p9-3f%a6^JAw(tPcHn26GR?b$@6ES$$q;QIN9s2^d9M^PHxoDL$e=Sd3e ze$EQK53jqfofO!kue+Gw_r%d@sQ&asW5C{q7>Qn@itpy@t8`7jPBHXrRqZ&@yl;1c zINnDDu@8tqzuy0TqSdIyM_PSMgdZ}$k2r1Kvt;eEP3Vzr$zXdB)RyVL@?@K_ z`uoYQ5rVPp9}#zKhkL(z3L}DR$2g6_7ce65x&z;Ra%LWWhdjiQ2gro4Ny<;a8}nVC zn7`6{=G5~+lp=;hyjlFTc%f;r-98y!*g;3<~X5s9kzQDb_SgL>i=^$fA+SV>Q; zcU-a7o(k#H*DFliWv8mu2urS_6l1G7UB0Ft1C{>knH(0W{ zpja@OmB{HDU6dXa8xRU62PE>z^{ptG70d3dGogj!6uPXEn#O z7RH98kEuxJ#0Mq^CIZQ<3Q!H`&Poo54Tv*`uB@)Cg%uSsTw+x&37&iHs`w+x-Ql=BXU@$$X`1 zao_YHcA(>4v{m0XVGsRqz!N59@%_!Svs5AA!BaFm8S|k-^TDhVLmvFi61Y&{O9c)I z+$wN|z#RfF6d1z>RRC6nw8tNR$KpqD*L@7C2?EE@)#;rta1i;SKRQ^F=;QP~7W`rQ zNAshDeDK$SAK@z&GpK$daMxEfjN&uC=y44{FL3fC&HrtIE54-RT-=DC+N{#y+ zI9;sqdksv7GtnOeO#By))!-zq~RFBpTmxOslS^9 zA0MpozZSTg&RxLYR)J$IG^J?xN{^xU8LjpSTyc(u4+6gYj7 zhR+eWg3eXMU#WqU45}J|n_tuLN`ZT>)bK3=$0h#V0tfeKJVqa!e)4q(091?sMG##ZE6a1+HhXg)PU?u6-2%Hc+ z^ren3{O%DrDE;AigQtdzzXK+|z^4w-@e>mNe1Ute((+g&aD1tTzbEj*6E(kU1#TAj z$0q)tHT~TJrzQSlCjK6ce^uZvq2DiXOz4LW)cH%ls_9P_c%i^&2^Eo!1MtYs*j|=PZ<20l3x>F;Ex233p_ke$B#?=GX-Aw7ajj%frA3C zH1q=hLg1wE+iv1ZdEOK_B<1&WS=k2L=e1@002FuYqRe`$eF7dTX}=}QEz5dBdB zu#)sA3LF%;Sm5TF99?}w;Pg!zzR1wutl{qpoD_JOz}*6`GxU9${&s;Y1WpKCn4|Oi zioj{X?-w}vcO5@(ur5z5U(=5gIK5xv|6Sm&&uRSE1r8n1_*#JzLpA;?LofLM6gc>O zP5(22<4Fx~G4$OUepBGI;PddIAd+{H*aN2v-1C~IpCxeYUJbVh9F+F{Ljw!{M+6R; z`W9G8f9w-DCi=7xXR}iJ@fo^&XA2w@eHbyY(YFFG6#N4wzTp30@B$w&@g==c1v7JX1GaM5v^zEa?j z$m{=^_yYfzz)JMfZwy}G9VWiOdjw7hoHb16Cn5aC2pkiAb)LW>fm;l{z+D0>fgcb! zDE8TN0#}HBddI|<_A>YwoxT!zd`aMDk;nN0_lQ3Hw!pFP>GoG|;tSj^aOeY#|B-=} zmgfe6o1fMAEdp2kRm0B<9NVhlmjy2RqK^Nbi9boh1u&qgz4oLv{TP8`?`rsLfhz=m zvB2?nH2!jdyZ35%t%?6P4gXT$o_!jASm5OQ8h&2j<}o@yZwTBi_VYgt{EVg_ic`b5 zf1Ro6CkU+0(eO6}PCuvVBLeqq)9_US2X|_CoxnveY4|sWUhtT`)%xU*8vi$e<6qY4 z4L*+dl4t-Vqdf3<5B%>Qc%}zl;DImmz*l(S6(0CT5Bwt!{4)=Hy9d6<13%z_H+$eG zJn%Cf_(c!=ng`zFf&b=#KlH#Kd*A@ZhY-Fc|3M!37!Q2B2R_LIf6)U|GkPAs9{gUw zkDA5r@p}osKj7DkA2p3X;rB9ryYYJkKkEKuQYP_x4L?#Bq@qY|k*XneK_*2CKYG=^ zjh}Sk(2IE9h2Ot2?V!SJJ$zQ|iL{IWYb8%8;dx4DYx<(9J!^YYaDu_&n7|lhtn(KLEIIHkHt3Qh8UIo>k^NXO_PsXzv>_qA0csV#K z8LVouT``2T2_72qs6BA>VnwxYATJ90P}79ID;Vo8+QY^-RMx27IPII`6Xr{8e0tpU z66zO2&#b%1wSe67^qQbL;&rt#;oJ_iN0OAdI-KZRo! z-iN?*CWt@9AzAn?gk` zQ`mUp3Fz=d&`bV@B*}0T$fR~UGh||YToi1gjB_*`LeMz3$w9TK-%K9&76(iADsVfy zc(86C9~)_VuIVuH3>KdahgHI%W&zeF%=8L0IP_ANAE6G<^!L@_8Lq)Pn3`n9s=JL6 zg`j2Q$gFlw&NS&V!r8M@^V2xzi&KX<{4zD6K9|tx4J+aB5_frb7=wx2$6W~9HUi36 zj+wc2Al>bOPVsQQ(>3hWP*#Yoqgvp}t1}uU=STYy0v0DepD^+%aRggFC(bbTmGcJp za@7@O()04>ChSdtjBKZMoM~-2LPW}rmf&NEIfMF(;55=SeMTFLMvNb*6dhI4zhOlc z=7SB3bK@adxHNiyj9iM_LuA=KrYhZ;vCxOijZNiz)Ag5<`$a-j#zYkNM!Uowdyr@k zW#~D|;6rBR(lYU!{A@eS-`Mb{b=qwH6#ZEwPHKOf%}ar5G`=$J5`~p_n$tGIl8VP{xiE?>2TaFmS@O3ubsy9EY)ENAfpz2!9x3ryr7jj2$O+ zrm^G1_G|1gQGdcV69O*xPFoCG;rbdp#8#vI3?2*XXYdfxYw%E*E`p;Lq)g5MLNs%` zfMhpguYeA3CHHar(fJy4zF>4wEZt;Ga&NHK3x*%REVT=sq+o}L2YO~Ww;b`+^udZt zXC}sK{h6toHs`{)C$w}y5ayW4k}&ZEb*8BMXw+3&*+OQ|Vn~1`v#|IGYDO7YU71F( zf_8c9yCV9MOQ1`(!pWeF&%GZrTZ4$CJaLVqE$pU4Y|O*XO~-yq4Ou%aHAt{kuD4quyH rTwXF)=`elHnlr>c0?ip}9eL&qES@p1?4sg%I8>Lv`WG9fKZ{4@DoXy zq|M=UG$_@eMT1Yl2vvd>2v~4ZYLjAx02QKEjZoo?Mh&Hp1g!ME@3r-ygJZLdzwK6|gd{`T5`YyX^Q-~Q`62Nx8K8(&aR@Gks{@f$8GC}=5&B2-ZDKKv>U zDkxaE@WR-<3neQ1&!Ta8-+{9LXapw#7A{^j|K%;VBybk7E=c-wQ1;pM?cY z;n#%=uU}UGx$FI?Tzs$AD4sP2g70BYCm4K`ng0~u!X=kqz4Y?yx!N>P3c>~N6TDb7C>z7@3|lBNV{C zTQpg`B68uv`fF~u@|wj9ue|1pYvny#-gOHVpDl8}=i;!q`J|l;Aj`sqHPshZhf=J4 zs5uoBfn>~)u4v+VlIubEzR?Pc{}V0ilHuDiDW zh9&h^FP(nHXRoMK9TR75Yn5n-Uk zzYiA_G*vPHz9{PiJSm6$SBv)!FgW~0JWI%l@>b9?uHY{Sx7~^O_ZAc!hH$OPL>uLA z3x3bwXPPX8M*r*j`nZCbqoWHxfH>;lbGQDs=G3p8KJoF5TcF|J^G{q@&TBm8~p#_N||{)H3H3hU(< zz!Fbea$G?r2uw5Y>E>|-RR|yWcR&LNG;lxz2Q+X%0|zv4Km!Lfa6khGG;lxz2Q+X% z0|zv4Km!Lfa6khGG;lxz2Q+X%0|zwlzn=!`;?AGq%ZCQx`fpB0radwI&YnGyX%7#| za4jB@X0BI8 zDkN8AT1({~#8ntnsVaFh_*d7;n<0AlB6%~M+`ClX40~T_ic}be>)Rp~Muf(WxZ6U0 z;!aBiz~gSpuvIQ^s||N$^7gP{GAeIRkk`2L#00$6xGfZ}`Z2Du)i}@0bxXafaRmwY z@VQRiNR1QQR^#I5^m@-7jU^=~)*Vkab{9lixEgd~+Ub3gOGaG<-bqk#yf-$0w}Q-T z_!CdX2IHwz0ZBUXXgrmO;yIzWs*np+y|PTz8{0&9H@0b3Y+EF?++=eTgUPolAXyx& zIjI`_jjTMHfGrHiFYAlDtC?aw!nG%mWKBVVvCk;h zw8TECE!gKUGf(^BpgivFm&e^{d93b|N2)^}Ep2$9C|mJ>fi}sbr9mRaTp{)nyg3gq z#@|TuV(ie6{%GiR4KJcgMalRNi#(6R*N*8Tn>vgynO){X}GQLfN?7Sja`tL zyg&~#sZuv(SgMq_)k`I9wHofjWH9bLT#hvN3GzADZ4rUo;ss~W77v;0Bu3^!*-qoO zxo*)BFi^auVTl6;k>*2a7%>!BV!#<^;>tzuD4AqK6d+jfWPzces$hh%zRbrF(cOeU zD9zK362tC8);<{aQG`v+Xg!4mTJ*~4e9VM_|NX<`3Y?ZjU@vnBDoX}nfNPN|<-~?z zHbm|9#&(E(#|ByUZep7QGuaqV{&^CVF;C^L#UrxvI4pL?Q$>H`!%a!jWs_Rt<2LSj zITJzTiT{YFil=~$xvWXO8=)R(va!#r7Eb1plhrP;O-H)*@T;8;cm(UccZ|~B;1h}&dmdNzQCPKxHnOQ zMBZ=Yftx09m4tiN!d;UGZk)g!Pq^<}xQ0A%zb>aku!o>5U>ElY)Ko&v zw@{Y>TQ=0q0##0^|FBT?qoC>pYBHgUEmYGesObV#MkqG4qL150K^-DclL*ygq3#4! zt~I@JB&CcJ?k)@WP#(Bn2;4-%ebK_L9Yyu)0yTk9pRiEh&4aB`;0g)H3MVo=nFp>; z;0gf8c3EmS>e0x**qCuMfHcFX`EjQ@YHB!|dbAC_X{j%##?p}%?j}H${x9@VsM68X zq)NMWY%=;#f~7)Z7jR~#6EfMDMw@Y@X1Yc)HKqgbS3gLF4HFz7#Q4am#EAb1H2!^& z7Pd%e?%ArNxnBYJ$YEEs9k+YWo=W`Y;n##;Cw~3-jo?=fY;pXS;@6H}8oyWZqqr`bH#Ll%^PsyW>v%u#1OVKkRWEN<6tKddX9fBbyMm z{Y?jg$Woj_mNz0Lv0YB%F!Fhbi|vY>&=Xm~oJ4w+h4B7356xNQu=i{1#ejxwbD291 zIQA__(ikh&7dE?#JJC)PO6nB2WplQ0e-1t=OleUL&+kGhFww{Df&xCXWwdGIBtUzk3% zCz9kyHk9k>_*KutcKh9UVX|kO6E8$g1`^E~0HQ3`$mn!Uh7}(9_QEHOZg0s%y^0{? zhstEnB5C+L@s^q zjmW%>Qi^WAdM;H^P$MX> z=nRYmI`6b5y003Kouw4Pui;=hEwU}v1e$SeNVaC~S)!I4)KlL!}f z#a;4I-xUYh>4%H;!yngAe_Zw97~PERkNe(VLBRUshFF4}KjrnuRUvh>KdwKIKaP$I zCpDLvHU2n;)gQ;Sus^N}@75nDX`}pcgn$b9*oQw3x`}Ob8~f42&?!fkfp_8?$Q^RZ zeWpZ5dx#r=<>6QS!Q&Yfa>`XAqwkdC3(S+Yh*{cTl(RH5pDK46cO@Hl9TZ8*49X70 zXJW+D-3oZ9zmVkM@4;-*LxY+-4LWKF$Zb9z3+m=r(b>#Oc^pcPmGUF{EImq}Q;x(l za?uVXeY6ZgG!kAfh_Uh&9|cQ52Zn*sxf7TW@2#ePNq}G)SC%mnfzM8sY}GSuVsG{0 zAUHb+R@oph%?rZID}o9w-oV*K1R2QFmJcGW(4@Qa2Hk9#=<8-c(nL25LN^x& zF{-WR58D{Gi7{M0ct|iHTdzbRHcOx0Yet_A;jBJ4z^vGK9Q1B&Jl=t_@m~72KBxRc zpGWV+Gjh>iku>9H8g=?BeAXcE?@geXCB>N1RVFay7bbA@W(3fDdU3ajG6AZjJp3Lh zS<1<9IDH;kq^yYAiHu;@))C5VUYd5>mq$)UFO1cVzaOZ>|+yVJ5OdFbK8*b;R zM3c7-18W;@#eCm}o61eNw+X8)@{c*FelJ!~@ED8TdB#oba-Q|xJd`5WBk}AC0ZKMh z>9?i!J=aRm8f_uXe~ht1JGI@ zl&Vb51hlE$s$BXidc7B5!9toqz06|K!>GcXR1o@J3*B2)5dwt*!k|kCdQ$+pBm_Dy z8+0B)KN*0|3qZRoSQElbH!+48KImtVs8Am1@w4(UhI#&cuo1MkNq~?^Ro*RwhO9h{ zVV*~VJOUKtsT#!_W0>c*Addj~d1PttefHIDhW?6xR3EO_)W2q zfsJ2w9>y@w&Ug883lO8lY`f#5WMB;QJQ?H>pde4}s632ep4)>w0ucHAddhsk2DR<@M&sM0qS@{nMT|$kyPpW2-Z{V$c4>{w7`pz68O)~$D5Ol}_M)UStE^(A-GV{ond!<<1>%n2b>6;^H{ z$IhZ;PZ@U@1;Z#r%Pn+h7<)m;%8l- zxeNv2#@3CGbvg9Zf)yid=G{m^chKkkii_N%R>!WTX6?M-O7=#oLs`tTYRscLY1qZRk}dLlIA_yL3mp!&f`^F0cJ7;V6~OO0D1B>y!?^sanI zb$l(c3`g{7`J# zz@{^k5W7!{aT~iZuNc?kJnL{*S*S2Ju+5=9tfx7-X^~8>M$NC54{;oT6&sl)V0(mg z;_jC!SUsKkR+N9NnQ`vfv#|@XH?|cz!&<@CS+Px#<`Y%B!){_LR=Xq7!ZuKCl{d3+ zOZ%A!aIv4QnWrEZ4Z0Fa2k3|t7*;t5w#!7YGPV1OYF{0A??8#RN1C63=R)4NIHFr5 zkjm2a5bbHPe_eq*@tu0J;)S|{fTSP(m*l6gBaZSBqwnvLrAE_ z_K}jhHvCC!(8NMMj>D2FtW5-nb2{rDDzn>zIJ#XL2e`F;u>%k_uxX7wW zc9R_FcY;25TEw`NTQwW2X|W9uBStYKjeGk*-4jP?7qQ=ZHesl(j%FPf+C8k*jMQ4s- zMKlX)w98tw6P{aw&MsBRiqwx1=@as&vuuzItIf(ix_CC`E1rHW9=EVx^82dJDjNdX zvQfyr6^ue_!Q_R`Diwv+QVBx`dI*Z-Bo+yzkQ$nJTb>Ej#rX+ZGXGo}W7Ui`LvOJS zkrQIgkri}f@)dC~_6!D7@(SQ+qWOx*m-}WQrs;~vHGQm`D|ktkfFmhwlhT?ONtzdG z@(@)u!A;z0_pFwn=;uk%>wfi>hrsQM>bQju>{$&Ly|8DIOw9b@5NUG3?}o?+CP~{FxwK~|_EZHZR~eKy02OyyeO^(Q9;vA7Q2ZA^Pt=t_ z6{*;WV2TTq-iHkd##<6hP!iFU#xKYrH^q>PDjAyM#aphB-GRSGV^86xj81wJg~+6D zjZRu&lD;}Ri3P-5%}AmI<=`$;Z6YZr<^3*j<5~IoZ&h9C&w;Qgn+F z3-h_3Lc8hv(!ANEKw9=8xFBhEPa-= zcwwxE8?5G8YMxVe!dmU|l)n`e|AhB9=Y}VXiJy~;fkVG-ev$RCtr<}7df&*c; zk26@zv(!AN9JW7L$TqQ2#blfB`YdVbClzastKSeM!&yTT@OMCN%$r@RZ1?B3AnH!J;%oTkOMov9kfG052 z5kvnB@Wo*O2SP#jkcK>_d+0{c8!t$sDZZcyMK=&#O&Bz(=tIK94pl*bzxck_4ISM; zsof{UUA>;zR~!z?A_zP3E<|PCZ)0*q(`3L37*QXrs7wD2zA$70^U)S!1tsjvl(Dmn zR3>I_g5qUd0rG&VgZ2Skl3F*Kht9q8z+}=f&*JNqb|2%24YWCCH+12FveKbYj`+JR z6r29Cl~oGu?!V=xZ$vr^?QYe4F`vRe;H3xepa9x~wn}f~Xig*iY^M^BokTh>rw%o|M%zY$rGAePv6q8jkNGbH6%^dgE4 ztqcvcj?-9dV!o6$g>bT)c@Xe)m(hJy2;~lD?t&1aon-e+wpe;}j?8(JSdz(2mBxXR zyFM-Qh!n}6RY=yB3y{OEl5lmyE@s^S7up0DGh{1~p=UCcAydv$$=jP@GEV`goD0A? zpxz#~kdn{U^+}wmbRS25QsBIe#dVzZ#JU}+s5b=bzGlHucw$DkRiIV9fSxBjp$wdr zm7rvJVle;m%@yQnI(Y(wfF~Ok9TaJqXWpRZrYMqGEW^Dq5`()4zMaI#EYU+GS%D~) z2Fji$-b7-uJpg%VvAe`sv@7#-$eLGjWpuRU$NyO*7aM})T99Lw#$-ZkX%Ny#ZZhR5 zjjO>=hP_5!o)pDsp4y=&R$t$Ovh8R2kO;#wMmRu(ickqY@Pune6oiP zN^xgS6d=IPm1BF{#`7NiLkMS@UJZM|53pEPR&JL@y^Ws8*{TtAJaLPZtPP-^Mytw* z9R(}_iNS6>jbT7y%54k-!*1pk~Lq5e+1=T)U% z-xSBPhg;X=o&2hBFybV`%Tx zI{;|}GC@?`$2`QMDG`68??vWDIY~fT<|)YsO`iyka3lu}$ZH3AUlPQu;wuTsDgYrR zQ(hsP(?-aj{x&4!rU@piEA+q~q;nJ@aknfIam4TCJw#wFT+0T;REQ^P1@NV~`|v!5 zTydXyiyAVC&I@eD7Da!GJ2 zsPqS`vin#<8q`D_8QjFWU@3^zIuwcCT`0Is zwfP`Jkpbkqe2}5Y0CG`2$WWw=E!N4{VqNAmNMS_sg{jICW=TGDp~!&n(tMDi$N;h- zA7m&pfNaVK8HyYwOopW+ZPTU~wf=^WCwkuBUJ6y_Hwyu)^;3-yNBp?-CntDEfCXWW zL~g}-wRhqU#uuw+(sb@ZrIo;&@8EQC4VF!4II!>~CeIR_z}Omddd`vV;)zOT;&S}M z49#_(_8JGtCEJd3fd3o}J2}&l_X-|IaJZa`4$3{pymp~cpg$Ibx-kd9%%>KDTCQye zQr`szx^ZZvTqwQ?iVS)0COJpkk%B-^wSfd?S{m-kd{42X8Z4$XIQ%JUEN1J6_wZf- z&-*@=YsXk!*vAbJ2xC|BI+!DPZO=8a#gXK#KKqz7v$wkddDhA4hr%DzFA|C=kr=|% z3QXLcv=b%O5jtbdHiC5XI5@sI9WOA5SWWu}#^D#e6Hf31C zkhgWaFz*G-SM8nog9GLXX_(hc`Is-Y%+Gxxr1?4;rLEnpQca3XnAc!F=IJ3-<{9!L z%KU&bk5LNeoA@o?#KO}FefE6JZfabqW8ub;$b%~f$qPII2y!@vY~lS|<#wizIb3gS z2mk~gcIV8-^s4)}e5*$Tx+1R12>RESqX8N|EOHo5F*2)n*7NL~c2m!pYtU31v~Fz3 z?{$wsn);iD{XTYx9j|l@LsHp?GEc+&EPH5V-D>hQRd_;^>nyJgcw!KP-dvt;c*OAZ zqvryieuH)|4^PJd113L3pQ6@vY(%VXVl-o%+K*z){SEU8WAg&W7|g@i?;kddm4+Cr z-aBLO4HzTV{bp?EuYJZA1&lG6hq0Jt?3VsOW1VOP_oA^6Ns-8Cl34ePu`15q1ICsF zj4_ypv32W>#$I_gU@Ve{F^q$<&5H>0@ifZ3$kWd;<1wYUG~kKBJUo?Io<14k>1M#@ zDhoVW^V%gsi?WC{A7i7;i;Nu~FxC(-#$X=CZvBZ-)+5gZ%6b`~dtvO+fH7j-Z^pj< zlCQC*fH4O1F!t(?4P#S6jGeQ0#x{!NqA_9}i!n4gzyojHZaqkX&0?eWi($X2>=dJ8 z^q=h75y0fen~s`?J0Yg^IEihzaE$E_=AYi%F9JloU%Za2r4;DHE#CVeOonwMo;v+s zsy#Tgw>eL5E{qnyqt%P-=FE@mh1$WZ@RIbwA;WfL=!O>oba!BztkZYm^VmfC=IhRj z$eBV;>{oMRJESSxk@*=~9Avs5nUH)9`2y=0;#S0yy-~vUl(WDDue@$cgQx8nJ6@o3qio?^nc~@Z1xf`W?vF4JP<52lH`7mT9*^y9&`e zoTnov6t+cHtOPEud)zD5AijT1Mw2?R4T~Sx8LTvbgRLCU4;TqCcHDvC`nm4x-nr=g5*V!}+=98&;LRCnt$S3i->JDh@n}u! z#CK(y3>zQZ3me>sVcB?JDmZPxjf%LtsORlM?8uU_vx$^>G}lwiwMLL1+8l7}yWj|d0eoQ_?E|w|l&MYx zyvzqMOfb_Z6uQothcljD`!e9Y7g2Z?94P3L535$K@*noF7)`~1&s}s*x8F zb{2V&75jn26Mc)h;4X;4%qL;WCd!un(TI}uK&qb$81b2I?QC~x6>hY08!Es-WqjI5 zyvHkaHjmpm?KuafjN1;eZcAeS5xgA`?qjAQ;0vMQ~Z9lF@UDp`o(AI@pK+z6HRlR`q zFMjD(NVYV62x414=eoEXhba1ZdC7J+wjId(q#gN-Vn8lX<4mt^JI3sCTSh&SP?E9r zIg82B#Ck;6F*>~Xy?}$p*joHaba)G%(;?iQq6=L?>j;{kKcYy**Q8Z9>$dm9;O! zF}yt6Wi`h#|0$-NCLni zD+#8hPXCT%z!K&c7o!(P{0xnM$i$;GtIN5NkIQho#(76*YMQC3;&00W8@WfKmjOrV&5=O_bJc{161RlwTM1?0ow|&Untl!3ieeW?6xMT)`#RBh4(1ra|&4> zK(d|nAvXc?28G;4NR%JBzeTxEgZufK`bsFZOj9=?b(W^?45d!i)NZ6s(bRF$ND1cU zbXhCFdI0SHrAYnm5CBJ83eW|B-zvcSLjVOZVFg$RfX5Z!m=FNH*$U7JfV&jnq!7Ra zA7Cv28WiA+5CHw#ilGAl7b(EGA%J$D$u$5tMFB1f0d)8P?EolMfW-#DeP|7maYr7M z|MphVz%oB+tt7P}=?|LJ>?f_4q*X}Tq)B)BNgE`o6-htPq_uuhw2o!!)2S0p>Wsn8|>-4^XD(SmmbcAd;Me zzcBMhh$B_>_t(&*)pP!imQ${KaO;Muo&K}jNz1Xi=1!s^51`vNclyQb6#hO?%bIh5 zz@QK~LkT27Krpj=l6wiv_#US*C=^(261-Of6I=+!HSnOe2-k~AiR!`PYIDjJBCr3( zETlst;f3@*=E#Om4prLml|P_#>e<5MXFGBls>VzJ!U^$d*gfHmcQ#)6`~&yjf4@_Q z;XOK-*-(nJu_f))4Mv(d7&Zf$LEb4D+a76t593b29~s*2VM|YUONbUu&#}J>(up`0 zoVuajm@E^+&Su4iBFPIxV$PbuK*GcH;i~5+@^;S3Q8Bd?gh16!U*f9t#JS_r5T%tK52zKU3<}TYm@svP+m^`E|@n5rD!hA6x}@&Ry^1n>qBl7+a^BzM5hs@A|+#r zZM&p0hQ)?awv5Wnp}!w!Vn2(G$E#3m{ZedSLV_)}%j$L+t3c89aRuw-cR+8@E{D~1 z%Y+qqyW_aFR4zt`ygU@was==|R+%7aQ6~C)&upIv-shK7<|ZjMbIHDNs-@PSiG@nd zU(U@OE~V!0r!(zo++EoQvZLF#!2U7lWL(Ik?|F^K;sth* zxk=HdbFv>|(Vwg67v_-90GW^n9!0+zF`|+25>rP(Ub;J^l_)5gb`IQJL2gnrJ`K9@ zl=RUo+D{8wSl5X_BG`;}PA8md=QbjB8{53cxHe_&;K!)g+=#cU3z4|$8RgW5a$?c? zFkb--Xl~R&6cj-)w!-u|{kDe^56(jQZ_joE0+6>alaXqyAHU2BX) zuW^mZN;HTX25wIy+Eg9d$wq4E(BTg3>ZxiF3Fx6` zGKMc8@IrbFJq&aDs70{n+lJv&!UU!(fi4gTF`OI=-;V=)4_bV$azV=~;18vufEx@x zpXo(L71PGTd{uzC&SG8_#!Oc?RC`Je=H*QV6jAiN^=D(K;iv%l$hV9driYPNDDv00 z1bUWB0ew|3?`bC;(e~wIk?Ch6uG+rClIi2(mDNtqB$45VAfuRJ%ta%DnC3ijEX3ak z5YM!TuMHz!qKKDdA>QpH{>hVLC?*jg{sT5_gQ+&}ybRn1fNRDHo50cwB&Z zg+=@Xm!_;L9>Lfh#ra2!KLS1saiJon34#6RX@m{r9Chl?u8vJgjoj{kxA zdEQ1YgZAC1;=>m4{4nAR6!ErR!m$&fxvlZ7;_k5!-xDC-@=c?Pf-vH@N`&K%EW{l? z;+nA#Ul|}?Y7u{*%WqZ{9g6r1S%}yAi2w4_F;sCeT!D;mmV8K5&Z$$@fPiAVYL6DXdexuEn4UE`{l6^ ze=k6M|D8q=e}wnPSHy4LEsFSB7UC`+@zG-;zBNF6zD3*`M!Z}RcmA9TvlY7EN4yp0 zk+-F&3J{Nc-EcfTjJSe`**w@y~ld|r5XH-TBjk#?o$T@k58HWX!hZM8N5|0HankKc?N5Kr=xR7#93zvc0Qs>!3KPc6Z37r zH)Z7AVdOe8OskBvQZpXHjDm&+9W4c3nLOl{QA%Kh?==?J3+qBU+IraNG9ufNq$#7d zhDu1d(PcFJ@EB#ZMVfS>KiSg%RG9u;(9eJ#M$kEB^cLqcD&8G}K933hN?-*26KzIS zyB-LM_t!&-gjGj&rMDxDA1aCLO8+M4LXoqGCB-iUi87C}!kmocCkq9p^hgnehzQ%uK=OhL{NN9(M_8{a3VpzczDj;{sLg5ME_aGri62}s0*-L-84e3rML=DfMI9~R zn;Wl6_Uv)6H$FAv40aN!I{F=GU5BG9mKpYY4o0AHE9TmVAcWL5@70%}?bM8GF^M9y z6XSBkAAd52ImQJ{%B%RRro3wI50%&Hhm0~uZo0ok3#!aeQ8CR{``q?ou@J|!GhBSP zN_!SAzSLI?{Y^gz(SKsXSmxM~RtX{AL1T$`i@=C@Cs_2ChtXdO^f@hJNW4=G2_s%D z2AQL)TFZ}3RSS#vBWcgV;{7OP#QRfcNW9;p*z(u5UtxA*?O!P5scjDljEMJ1i+)8I z{jEShws;pC5=OjvdBwZ$p*-TfENxI&yk}P#@!l1tzvo?Ji8mn-uSO{35pM@(HLTt! z;iVS+_rD*~UI);RE#A$N-S5m6nxPHWFBb}V z#CvZb-W?WwAC}wvfl*J_6FfmuOFJl$!TE8Zdb#H*J^ zDJ+{NmkXXhXd3|A-3ABVMDxhyx(J{6B4f>uW=qL z#B*BC`=wC|i}xu@|Ms;Z^(M!UCEl+LZHU+R!!g8rNMJ;~U9CpEW8IkxIVPtHZ)a;TN`+IyZzX0yDKJocrg`CTcSmh}pE%`QRzWoBJqVHkABkM_6 z#nI(|*u-Y<vKDLW7`O0&a3stI`wTWA6$yM#_NJ`eGwqJ zzKcKeV(p@k;CLP9(@bo~7Fc{f6q6rW3l^{r(>OvHt?GT557P($qtY5(Wd4qA7{0!v zMdM)vz?tYE|F<0vXzqt?v9Z|XgRSA0Vz2AP!dyr2iLxhwzWam7;Pmi2bQ|N-aF8Ec zk^5jx$;NF3k<>&an$pg&CUOfqnh&f7V%Q`rjBcXyg+V8_mSybLb)x=``#y`g6+piL z5aW%iE1^*64o5e+LuRBf!st|!lc8kjt6I0`$w`0U_=Ey23jw+3FVd}BZ0$Aq>TvQMO;nwHUKJ3B zD#T@35Ug5G%hk{`AiR4;)cGL@@UgrdFuJ{L3E{?hX@$Em2X4fND1LyA|l>00}w_M?hbKv~Vge~l$05^i>0Y&>3 zMuBPt%Adcdu%%Yv`W5a^IdEJwQ2ypBT&Kc4AA)o5SR)#a69S`Mh4@tnf*S7dHNvef z;OtU`dm#kp-hnujRh43ztq{M?f>r9Ip^x0|XmRJqI0Wp33GkHRE^4!FHgYg=Oj>bP>PB zO{{hL_~~HmwVsd7-E1AArRM<**H%4!MdY-@wj6@<8@SiD=s$tu#4XjWeQ`(5OQRF3 zX-#8W{OU5$=KXF_JZoB8B6xU*kX4~nKLScC)`3eBdxpfG0WtfX$@P+(UAm!o$z)&mVlzJvjMNH!#I}5PI{CBa0IERMpoo|zDue4EJEAse@D5S5OCKHK&|{*5>Ep3Cxc|hNjNB94!LkB7az;!LVajCTwEty+?kJy4PwSp`{ybbAM&|qQ!Y*p zbFnJS1$;rqE*`>!Eu;%|b>(m|gnrs-Y0bxlR5C4*&47X~9xw=k*Q;fQd*Wx2Fe*Z-0wO{H@byBj*7yyN&#B<{E1vw-JfjZG1+Ne+bCgZG4aA z1NM*;vpcu8aN5)OC<6yKQQR-Hw#G^43~&5yqXypz2j2_9n$vP2`JSVwx1o>nQOY+^ z`i{c_67bi;NfYY>a$d-fgG{Syksg6&)$V#YQ`dE0$t&)@Y3*`9rQQI-Iv`aToIS8&S_@EZCGTXz-vQx-y&)d z=eOPPyO6$W@k=V|(V#*tEwi@)v zHKT@(VclXMbB(hF9KC}%4TjQG%BPj;W0(|XcY|Hv5+~Enbti39s^OlHL~Go-bu|ty z=foy=s-C^$IPbp%^=zUBW=u%enO^2#?PWY87Px2tD36QFM~`u1sQqAZ;2){}^rzy> zhdPACqT|^1sk?98+*GV{ZYr^9ZmMp>+|(uA@zf>j=caIt5U(M1o98-{rp|R1 zOq~$NpXgj?+0-)7JsfnCBlrMK1rUdK0K6cpoqbzLa6%!I|8qW9V%rh&?G zQzW5FyD$nd!L_1;ei+6exQt`PSN3512a=7CQ|QVtM%-2P*AbI2>-~VMTvn(v!K$Uy zOXmGIuJ87ToOG*&8(HE7VZm=#d6iMAITFlpdgj}a+>942_v)2-W3KoLVp;SxA{ckF zYx7m+F8!JuRfehX;ao`y)_{!ymdHYlC`0_(?-Qw2IjdHMl=I<(L>;34z^&b82n9~* zc2tCRIHlVn&36)4YQ~csMWyP}riAWWz0VSQ0aR=W9UNxjZgi1`qF!#*?o4nKz%0Uz z$1S_O>&i%qP^{gNrm@}lr`j`@iW#YVyJdkozwB+)i#3d60o7+<*tn|I&ZJ& zkk?%ssA-TZQkGw7H{Do=ej4Sf=gagHwXGmyJwynR9fXslGIye;Qs|dKmST1n*=^_6{Q_>o2JJU!&6$Ev{1>^ow-N(NN`Dhfj2hDHYO@*>XsbLyZ|w!^_9%F zUu#FKIG>x5JGj3fAAg|8LpisC14_xToZ$JlI2c18I3HxB-w$m_@3b#%d;rqu9mRvP zX2Y`~vKBL#!ETN`n!xUNY9i15C@8Pd{OwyC``~~lO7y(W@*z4OtW`kuyal_YZV2Y! zU;%*NB*KSjAONmGh^+i-5i3s7clhA;8v7|CDSDRM?#wcz;kD@TuVE&CLTuQ-p1!CP zF@)J>zoAp~vc%xxZE>U@4n~-BtAXp!9I7#LTrCFgQ2bJM65GlU{}g`@ z?F?f;U#}J?JIWLMXLM^(Q|B6%whHw8*btJKWj=2smp_D>YM{;&sA%zb6q*-G%oAwP zp3hs$QGt;s>wz87TeM8-eG zzyAuEneEz(DiByiMmpK%T`uMbAfut22fS7gjJ( zpGRsJf|?OVzv>mpBOiUU958z}2W8+urUw%dz-ar}&x3$`>MORJYTS*!zY9s1Jaz5c zd-nVW`TvaHml5W#6jyTa*NNXV_%W?u_ntkc;zA4-JC= zdSP};v}iO~C2Wjv{XYIMr0v^~i(|KM;zlT3D1sh@v!EDykhzB-cdF<@KHQuh1bJ~r zH!}@skP0<$D6*m$)QpHhzi}2cD8#b*jpHS@Bo_1=g0P>w;ZM+SkO;4zMnci2kVz>W z4oZxvHfVzW-~~4yxhEvHBo_1sLQX0S{sjF2$<=`z4YNWyFCLK0^X;`jCAgah_2pGZ zpb{```8HV$f#AlVp-jYJc^SEZt@wFmtn_xpRtE;ez|oG%_e>I9-q#JvZi})@QAQJp z(XWuH)_-!aa`+X+shsH-$bO9aO6I>kI_YI7jY(xHS2)*ACaHLI5>?Gy2O&xBOv;>L zVmy$bWaauS?bPR#J|%rQCCvBvvARy=is4U5tiwm<8f5>xU67VuW{_RAFJv7=hCkR4 zkijA?IV!pjNW|t?*HtecH%ad?bRIBtKCaIxS80~9nQrr0Ezm5*wFX7EK~cF+6l4|c zD_CU+e@bGl8LRs(DE%>*KHE@yL=B|$3`6lNnq_RJn=-ceJ|kI6Voez+f=Y@t33-Ol zFtb~r?a#-E5K%=ZE9S6`*zbr{k51ZYlzZvuq~#{*ve8LVB%!$g8#?>1HlS4i1rNpM zS!$kB$`!?!(u$`68BKRkB6C~+>ts*2DpvC>HP0#cBOYoW8!LMqV%2AfT#e#?M{Ks{ z4(sV`BSy6$Xr858Rtf`C#_fwB`yZd}S2S0#d6t^zl&28CSGI|TZ0l3m=DYS(CDOh5 z-w{hFwtQloW*9KfQuCa0_`VpZr5L3~8QWJ-_!8L^kU<;^SY8;(&WrE*w5IqBMtCp} z*@vRv5aWo_d_zpF^??w`V?e^)H@w6y8>&Tzim}{rtc>FEnX1W{(gro)B0z(gqGN^Q zXz}~;1ll_04qu%%-*3U?y9H+KPz5HuUnB)ZiZ2)-$allIhrxa~Oqu^1T59Pnqs7;? z7#bL|(IqMu@d0WzcO&?dvKad;`2?o_&9GdNG#MBK4A0^hARL~hKb5C`GmKb4Nxm7T zynN2*g(d)D&G*8%lOczGC8G91pUI?ep2Z(my6kCXUj*pNlxisRH&_8;DHRIgFSmsY z;rXnz`mD4^)Ow0;lwyk(^C>)=4pnZ9H^os7ZoD?h9!>GZbf~KEQxz;UXg_Sw z@|lIU3|S1?DAE1_O&bg)#TSc~FzCGH(_@Nu0??W<5jBg8L6&dgs0?>%Job-0dyc|* z?ri+lyt!vjJH~V`<9WsizQ={QZ{e2#!tog2eHFhxz<(6!;}LfxezWky@vHFnwaPiz zldXW**{6;YYzK@q({V+g5$>IUf57`77+{3A8pbYx$?rly?_vq>FXT#v;xiXY!f!T! z%*Z5bKk8I<>fw^&uW`hkgWGoFSM7lt4R_Di_xWo?@`s z>GXOnO+<}-WKQ)wxQj3zZ6GYi()Pd}(sHp6T)$09N3^H^2LjH~Bvni+f; ztC*Ov!Pa*#*FhZ@%)@0$1G;K2{HOgpUb^&-7k-D#O?2Ty>u{HZ2s@LEnX3^);IHNY;}gLaxXK4U%>aK+VhrX;1@69_Cryk{(qZML{jh5_DXX;ZdlO7(&}-ZyRa@bA`)k z3iRAU2UT(KF<9fis|NQ=@zX-%;2y?aa-gnps|w|L94YO!%z%_b0W8bSPf+liA8rg?PtyZMg{TGSy z)@I2&UghoI4|&fI7&2nl;b!Jxet2WPd}f0sitDt7{o9^`Vr{a_Ho?Ur`Y&9b`F38d zybVhhUG2kEbWJRxvL);xmgKz5R(KoGSFr}#`=7GwBgoAuqcv_|mE#-s z+`>1=w|w=}Y3wvfwr&!PRk~f`lRvA1J)yO~fQ40vKfE<9^aaHwm?>%Ju$+*P0sTX_ z$&{yy=&nO)@JqB-IMCBCN$>(6eg#I=+6kGX2*U>On-%MbG;cyKNL18vv#Gq=M4&Lj zO~iRwO~gcSEEs|U14h=2VMOERaDKy*RVFYF2rj$!^BbE~cKN_9K5|JErcw{rNTp^W zLLzAdkd)mBuu?$A`cVn3<^nZ0wn;7-z7||VQXw#iwPt_i7G}eq4Za7UYLyg3@iOvx zGJqRkt^uU=n>5>E*m#>qK1yNkILqMpgWsC4n<%4tGTT{iPE&1;*4gB}>nv26T&YN4 zfYtQ>3eCM}TO4cS+@B)GoH+r*N52Bw`}H_BWGzJxUO()fJqf)+<{&4w1B08$ZS=?r z9^OIeAsY8q_J!lp|B~o|$ZcD*qW>w;+akApD;(_|jQjT@&G%%*O~76Lk>=~dap^ZD zJB~MSF*ab}Fx=rEX`Yi6Hxa#Pr1`vXT>6b9?&FMYh}Kz}-z~!M-bvDK%arTvPG=_l_>lv&*z6^@vADy1%IO^B$#ZkW=dGrqP$O%=q zL~f&>lt|rpL$YU_6K`Pp5Z4s5$3MxTS{eNCXis=NeakmVl%uGrh=%dDqoU5SoapyGTU7tl}Q71rp=PV@`goademNC#f2d2T!&c9z# z@9)bl0+}{c#NESDB3)FznMHI;IQe)58mqnZVQa4^RZejB?<>H&aFi><&uD4=PBsn$ zc~n@J#=pW;ceJIAUUpI?l3+I+O%PN+8SKP5@Y;pwemu2PT6w(b?Y_B8tOA9SZ$QjJ z9Z~5<8PnSlmP8br^mc;)GDF)mvIM;yRKz=0_dc|R-I2x7!`gPD%^ucn=#7yAmhaQE zQ2(1}AuQ$!Q1nXa?7j?-m(sGgBb}l5NL3sj8J)yfBR3??8Rh;4A_x#b`9_T`8^GbDPSijEC`(ueO=?hSe6F0-*#CG4uBDCXhJX6;p)KrdhY z)B9T;&JbA{<)hfBKrD8=%5KL2hEYs&%J|*qXStj6SzF7uarTkGK)j!K&NjzDg|!xC zBAd#Pivy7PiEW6&mmaXs428+4l8J30C@I>0Dcb(bgAgWfd%&r54SFJ0@crc*B2}V> zBMU5EB%Gsg1AsiR zo&cbv4()%5d^;kMHm(VH8*bBbA=4Xz*hwOctl!JnYhDZ;A3mM|uo%Fi39LxZPju5g zyMlY?7!OhBbBbbNGaohyh!Z3je{y#S^3!kVgIOowonO@M+%gB$d6+}&elrL0{+}{8 z7A>hwkhqBJ(3zjGdnLvS*@J}?cNmfm{Lx}nQ6Zt|V&FML-2$MdAB&>~Y zimb4})uVymW0XtVK=qMwCK5y&S9Bt50)C~kfG|F(R2`XmGy`MTe^WKs7ow)11M(}s zX$Wj3lC}VK%2Xn$Q;=q50dmrIx=lq{smB!MODxiOtejvVY~5O^2M@7p!>z*=(w%Os za~3uV=-Pg8Y5^~lO=nw zX31%4QMe@3ifvIz*U%|e+?jbvtT;5@>oOt~gCJYg|5thjD%TqFSB+%{eS)#2ljD z>0Mee)0f_**|9F__UN4dK=)b zgCWj;n#;0_L~kXj1$cUAex8(%O#`C%dMH=><7i?PprO!c;?77#=`p~A5_=l^X`LPp z?9fi|6!N@8JM>5ckng~wp0n8qn= zdVUuxWTbIwmBy(xvvjxkZ`dSV@|5qtK~;9=EXq5cHLVr)a0f4>9c24<#Fi3L;;b3fAJ6(U+7M#?23vm;&R8`}ug& z#9M{@GS;f20P|!C0WsagXK!@%ZVHyhv6RU1aDg~Zn2NbhMf@^M9eVy)7$3(4lMzJ2 z$GfRKzr5hb&cDp9`n-?jGJJTE-%rK{bR0eM6839{>c&5H^C+HnC{NCrA)eUtfH<%~ z!o-gFRa>y4Ihv(x{RR3_Z_O}1&Esw4>J}Z%`o#h9{aDG_&4X7+UO$KnV7y~s@Y!N# zm0v#m%yz40vm_=0D?aCm$UV~MLykclq0?^=sy5rio)lm9+=p(#x*?B;+d^E6i;M%1 z&`xngC3JM2xQ(yP8jK|(tB|PQG3Zl5A8G1KlQUPy9f>kJWRZ(a510UxBYI!P)mrdib@o#fcX+?cs;zF@<|yZP5JXPmHI>Ppv`}NV`WJm!d{$#^toS(^;}{Pd?pkoh^0-oN|`nVX-(vi-}ikh%Feirc^Z3YnXq)0zFtuaLR0*T;EI<^<5Gzo zIGH;ryx?v%e5XsPf;IX4Tstr(M{pCmTa|lZ>zsYCb>k_9t=ceKC+&kR^iiVofefz+L6;RCG*!{|nt;Lf*U=Nx z>`}Fsppyu_>PDx>lX5W^*oEP%a2z4?1r{NVqMrBfVdb(nww*YkLs;8pZ{EcO;0jb@ zKgw7}pc5pWW6V0ha0A)5W&}6!v0$_?xeJW;v;%hy40@-$ADa-kG~U?n?Vb-C!1aT? zjc=>o#wX&iR{QdlcSBd?PDC;T1WLuvGH&#sQS+rbX+Lm(pMdJevt-0jL|x0Ex1j=y zVy6KryUk9$_2=2$B$(Whl?hJeh;05hj;SQGa4ieO_D0=)vcJt{b9sHuTV(pdhVV{iB zmk87wiI~*yUH3A|45KlwiQ~ie_-^A*Sc*jcu~*ckvYP`GjuvG=+C*Zee9Nt&iVd7S zn+@WuvnQL|FW)0v&?pnb?)gYec-W%&<1k`BgI?Fk?1Myq=s%bJp)tLgEpx=qeF?#9IfgWPO=b zKRtduzzGO8!4&m6#8&a-e$Sn+IoXL|jtB)0;e54w@=o?PUg}o{Z{dIileI5h-qclA z816=t{bp|wXb0aiZA59{7EeReU0Md(SczWjz3)|nv+a)v=(sz3e7SFVOaIg0*Z>^= zmb~AFBSV?WC-2?c4BkmES+KF?T?*Pc^8UlfJL1+Z_L@9{?E8ZVh@d*Y-?w}-t~6P< zBkR8<-%l^HjOUZ@2^=CPi{8mETClO@YXj{Z`D}UO)3j4fi^wAVG>*YZ@wPISdkrKY zl_(j23G0JO&tayVqP z>)F~+alie2AWltIdlJa=k-YMlP9skxG__Ld9%>~Tx1T>3=IYTshWMo+;#vJ0T5|1p z!6T|MzV!DV98MhF{{B$f0XTf(i*PlIvoW6hvu*;$cI(K>l}t?)-6=q!bA>+AYk*Xy z;hDwSpeU_5m>6qxA{-sX%v+;R2}i%>M{{26wC9xHcI^(g2Vv`sY`kcmE;La7$?jGJ(P+|-h|gvI0V2Q;L;^eLOvWuYf5moG zT*8WB3!7Jb?4CaNmE3*BqGwm(@iH!AA7qT=l`Yxmhm>5WW<2rvH|xFR+vu6g15DDV zCL6coa&Hba)$eixLSmmjf72L~I{gaaZ#!wg|8a3z>Q`+8*gRX;!(@#0bYP$*W*E-nvgx(8LIg;EQD#YXax2x?R`?gT&t0u;xL{VV=p6BrCFQ zp}3@CW-GGyTdw#sXA?sGc40r4h2X$P`dC@vv!)GT7^RJ$>GJ)o;?o|M!XD0CjjEK( zT6q?0Xq@)Snr*y%`~hpDvgWWhD(fiL0-J@hh2>qD7PZgvG3WR8d&MwQ?iFPDo(YW{ zOtT%}pY6c_bXIIvB#BFXP(FiNK7(APPGYHE%Ek;kDcoRaVR;)h%s+|kveXm-xQPP# z43G23D;7ltf_tZt0UU&78WfoZgI&16pmrfjhB(0Sf*4u@9L?q{>bE)0vX!s+b14&W zk~&8ylF1S3sl5p$L}XQbo*tJ8WW?b!tb?((kR)n8#&bFx_w|C3%b<1grS<}NF~ofE zoRARVwy_W*-8N2EQ71wxqQF2=hat+W$C&vW)v*hIxCp}1=g}0fY(}EBlSvfmxPQX? zIjg$PZ1Rr3qpa_v@Kt8vD-Yr0HjIBC-`M;eElm+Ca>Lj}3j(6q<7xA~a(k)!^s6(GyT?SU0 z1Ze_Dt62y{iaC5fq%Tf2NPqbE5YiNp7E)A$6zpSn$Adtg2Ko;Xeb6=K;q_LF_S0ds zrvPodm&buP1|KjJIf#8YHQ;_3RO*K#4}Q7K+2gz;$B}TD#;H%^^VWb(d$-0z`FZND zzOTkTTXNMz9z44&=HL=QbB<{zQa$^5FKDgCoddu|4}fzNus7cG+Ci|f?zr<3(Bpyo zw#Mrq+m>4gATigkKZ$V=cN%AuS0&(f#e!f2e5%tXgSaU0Q2dfU3Gv*tj#L}3DY*?y;Z#)_%;H( z9#_LAwCG@5?l~1Myk{@s>lv@p%G_FLI5yxsZ@$qdtDPt%ZtWHD${cVo6YI|g$HqpeTGT*{Fnr=fV|L!sh$lqN|IVb;ek z&sV{b6t3X?Sv4DPl-bm5yopF!v;P?*YPbWnX2Y2{R?R-29MMBqF%)8La#qdm*P4Bw zAWZ^=DVRw09o>!Ju6W&ck4#W$?G0>f2R@XJH3H zwX;nRDh8V#Fo<%i&%+=Z1v1#}6@spr_=9{G=Hb*^xK2Q56pPe}A-_)aYn>R(HgbTn z^%HQ^i7aq1GO7v%vwl-2Q2eG&$f4I@Jt#S}C{!QJGB$ddhdwT9+e`QP%MXUM6-BqF zB8pRPB_~~YAI~v*LZVijz={>6R%!k+k%I~2u-Ke3?T>E>Bm9|GGn99)_f%uPYKEja z6EGVDy8Z7w+s`8X{pmdaHbrVfpZ9aRx~x@HWK}WKd461w?oa1=mqofXjP!-9Dh8yi zVnOG*qgsk$FBW{3Mf<)m+FP=!n6=;vI0kUtJ?ms$o+t$G6Iy#C8o$#?_4)Dt8j_5cMG&mYoKxU-)B1Ah9^Zm?(gL3E@xr&+O8Q9*~RzVfp%0uT#9$nRoqcL278)(M8 zb6FXQooy36_c&a^OQYptR7^Pv+j!1X_F?wvp103>D$!PwZWU;Xv!#@@Rc}Hg$L?_D}0K1HFSA4z1R|fO3cSi&^uG3P8Y|bL%hmADI5uY20NtbfLRF3s}%a+wPWrTv@e03;`7FXO9Rqn7>0k zg2JV1?EI47HNuI-Sd2DhYa~OH;TY4na=N&l_3oO*tfRWWV{*vte6MM!xBM|g_j1rR z6GynJ&@X=?z*Z>?>CiG4+ggk5<}fzy4>sdUj0YkQ0wZUNZ=NQKuv^-4am};1riXF; z0{r{9hJ0KPC@$M^=Hi-YalL}YAisyd6}ZCt9N^qsj3~%A$X;2;Yuj|ZCS6r*jIkO) zF;??ISrWNZonW5@9si=kV4PN^Jw&#@1N&z}hLad{8?jlA!zu6Xe*r@+#bxgtQ%cE zfFe^Ne{6}>=-l;lbQ7iv;{83zC*vr1xE9Lr_epMxgw*JvxO{x`BzV5=K~&a)89d4O zV$AJ`Mw49h6w8zYNUriCVq%-*cg@FRByxct$!#PC@=~64T7W_!um7vPuaA$ixb~mT zCK6IGK~WL3E?PbpUrM7`FBQ>5h=zL!q=1U8?Glm=NzI$t1kqb>7lJ@c@vhdkQuQ|4 z*6Q`8@wN2&!m3#DeXF!Zt3SgPb)yv5szqBX_j_LEdD(q}@%HoSKR*NeJkObP=FH5Q zne&{PIWtdUsf)n*0vfo)4a5c!Pb%=3b}i~gswr984V+IKd3pN|9HzYZ5{fPF^Ki%T zSYA)%xaIX!BiHW|Tfd%) zcgssHPo?t@Deo=ghAFS7e&5APS73QPmE)GzQ;q)edMe&6ucwLpL&|#}jwKuF;x0{A zE|wIVU)Gh{B7_dX*T>(r#eoA>8$>`caveDS8*8#24BqqBwS)YX-7a~%w@c>g%aQlT zzn13a|K^weuKd4KE+s&`%?PoU-kA|H#$r0p-ls;P329-YtO z(S39Hp36Zr$fxG;{&Xh~qHcmY3>}Uskbt86U2%1pel6c`#9iVYdkfB&Wo$_`hKHG%el$PPW z!3_Np8LnQ3X&LthOXRzn$q`HBJYHQ6mY}@*{St%@rV(g&6D|=@b#%51t$hWLi*J4e6JaVIaC9E@=bbYQWm_e+gpv~q7%@t zrwTtl$AzK~*S)q{arnFeVJLe1Te9R>`*-WNnI(bxjb4M$Q;vSSd!bjqd9WkbZ+L3cZb<#G^<;Zt)s$mJmBMKFgz{r30D;gj_n z-uc7nH;>HoJK+fR8wxP2e)I4jxqi!&$Z+)Nii6PtbK##*Z)DkK}noN{x09x zP6iiQb1-(uwkxX{%oP2ZY)&XFvf#XU@|UaGo_Q2U_V!`};V7V0V~LL#jlBcrgUS9y z8u;~WrV96}!kcS|7v6$+0rYJ0V67?~%hR~K5Q~;`_G#Sl(3>l27uy)ShNOw-MYhWC z+G8B$SIg=%pMw~8!*aOSNX%nAR*0{Ec%u?kumH0oI7u20(akWr4k;PUJH4n0%b{vgv1D}x`_@&mPJ z-prAkA3GN%`(NyGWOZ-Rd>GY3V<-!34e@!<#Z;i&@uZVJzE)ehhI|PS1BF{jg@Y_< zW#dtvwJAEGl8`e9-&e*|ebr@{=qg9!>4j@$;C>Sxujcq)u6hrAMV~q@nGL0vj^os3 zeGN17;9A05v+%FIK!z+BQCFbL!nYBcgIp$gP2trkl=v>!+wg}Zu?@2h5iVO8opEQl za?4-A^(j-=z3PvwW0X&DOWuS@?i{z|vpKai3>?x-7&@?9@_hiPGHDKhHDjg>dMJ$P zQ(6T_Z6807=c;@vwl`qZDp@#&^hwoABXd>W295Y3Ns_D4x>DaFvOR|Kj1f&HL>Yn2 zOy0`;_4c`403PSBZ{xt&xht_>upqPc3pVHc>AXRl2Jpe$nJcIA36wn1v0>KHV2L%l znhGLCJL6Lf=7M!uWtrt~1N*)@9=Ecpzb_2oKOLrZcnPwLFs&sP`kqwBk4zOTS_m52R019T2z zO2tXdpk;y+^%pDX$u`OJFpY!4oq$yZ5<_42b`<){M^T|uTnRZ2 z*liF+={e7_I`9l7&Vq;MIGWbR6#3e_kr2s`f%_TQLJKC$J)61iB-S8MC)i?;DyB^E z8Mv2d6MPx_7WlnPN&@dkG%+(Y7gwyg(K8l_=$y-*asbG#@L8#R1}Q|E^7kztnw+sK zOCJsG1;jf8;BZSLGqi_sHSmlrtJy}rsjH6!o)~P0!|k@xb<~y^B#Jaqtb-j-92md$ z0xzC9tShxaph%alT_9l5L69&pLC?ZE%+xeaKS^HAI66jUTn$91NMtLa7>r3FSFF=g zr11J{LEl@GViBZDS5E}U&s$1Y`%8H!Fx>EL!Jiu1f)>No@R75_5laYj9Dl72)$!TP zlXIwx(@7iIzB6Zp)$fZ%3z&kBJ@XW~Rmc`fqH_XJK#B+y=C zo(Q2aps_f(@R>8vaV1~|8#P;b8R(Mi%yn6mq;&0kF6kgv%O4sFQFQ24Y*85Od8h;@ zk@SofbWf@T80Lf1Ikq8`yOuU2sNcOqucN=IV2}gMp^3_0dmeLuq|=%}hNfbuNuQNH zzjH=O=p9Oj-ea^7gNWyU6@h6s>QD|eTJRh}Z)9hg5r1Nqu>)LHsVr#^y1d}^*Po%%#(1Z`dMP73nTR^*~$40=FbU@-!bpTt(g=94k|c+7QEU-#Wu?3T#A)#H_FJ5$~7 zu4m=)t1g2d1gGPTUyPw~82%A8TY|9Fh4@mnpe31#C7gBSnWnx-Kl$_BSDqJAT^Q!> zU-i@8CoiTXi&^(^f~@YzUA;G$$B?YpK%y-hWvx}qgG#S zv7Wlm*@pTBBG%xWrG48px8rQ(O?@tz}Z2|wI2|c7NBY1_-9sDyc7A) zw?O!pxY_q?-{rvz4WWakM{1z@$>G_hoddkF&cF(`D14B1(z`OnS~RGGqhRn z8MTxd3@dA)(gO6;e57h;X)c6*Vrm}mVf@Z#fv^u}#xO_JUGM4D%CS0_<41pTIZkmn z@)_Q;@Jgq>3)5Q;p#+KP>Zz8pXA?aJv%cQL`Uw#p%AO!oIhS><%UUdH62c~W3}$_X zhjqKldPV^2_YZb*O=ywECVC8J{nk6KK*obeJ4`Q|X1=!>Ib(YJ8=VKHYE9LO*7j6r zG^z0OvlB86lp*wR$bd4_yFN<=kiDw`RsMBPe!{i@ee_=USNT|{oTo3*Dqj*@!qFa% zcZl$|v+g8QY9==G(!N1vL0in(ca+_rNV!7ub^>cp!^258IAft0jTiTms*lDY3u!+7 zuJ^ItOQ3&I%1hF{AKFvxppUD2LkI@7>APfG4yLjgVPQm|Gp|7->T_`D+vrF7CiWN; znECXaFJyCsSBo66O*RCogG@QpAw1V;R9=G;;fM43YVbT4&!cOO-a4;0C1>`99;@zo zJJkDeFBOLlpkG>0dMV^;2*TSoQHBa2#+f15MKW>&Ko>OCHH*CiX8< zP>q1YN+^*eqRRIwoDMA*ws?tLx}qgV?${>WIYi$PkylmTcu!oG>3#KkjLLZ|2j8*2 z6-!7-%b4ziV=X4D5;>DVGgbk!TiFYKF_9^d;+&+dZWn)`dZ@rjXQFVQ&nl3a797h%-#9^gH0-`frog?b8 zCztIa(AyGbxOruUE~4f|O=uf%Zq0sCgTa zkT!AQmb4JhQf=M_geg`waa^CH=w-{$G++r;hLQo zV-e81{w8ojE=U2=h$+C|aMiAU(69-~_KW>S9bT_I#3PP44&(e3&Ju-6du#$oGhmJ% znsG0Gw>Hx`T?b0^5yd|FxKZdYu*e44@&9y8nQWye{_e;yJ&?!~Aj;sr9SLm5$EOBM zdzKgaM1`INB#8L9)^PQI-}+zjSB>cxl6Nsl=hnxn$Ph%mr07Q6`pWxO79PE)_mZbb zGU$8N#H#Q3-gl}u6s|{?>xb8V&+Fmd?rnYD+h9;(H*n7oY%2bSZgua5CP=t+9a{(+ zie3&AS3Y3bV`5hIBL_Gg6fFa)u;LWxLHbSrj_pMd<1ktf+!yk2luM2_#zk=@Yfa-M zx2HkgIwZjN{@7gL@3CQz(K=C2t+qe0(YnjL&>~l`IO}&xs3i zTm>2wj=#4MNp`z@#16UDs1yO4g~$Ax#NPxOYE5Wb5ADDQ4!5FpU5zlbI{BcDZFqvs zp7e{@#PMLSMh~N*DF%q4S4g*fzDL} zUN-a+wx6k>;#wAEbi%v5^>2k1WyP2tT83Iv8;OW-m7aYiDJi@`w?n|_p7@d~`Vb$T zt=}Ttu#{_i9DU~ur-4&0@1|v3vBsG+d24kC`INr zN2Bzidyorl2(+madJP8jP#<}UuG-QM-fRo5h3Dn@_$|P1I)2W1`*i-J7>3f2uuRkU z9jr!J#mLGLiV>3z*o|=RG*yfnPWcY2t_|}(gn}avOsx4-E~O&}o`s=^gN86Aiw}jC zuDh1RxS{A8x}oko>V?~FhDWYA8<|we2jS`p%&bkn4n=C<2u$M+VKY2*^-yOX`!Q%| zC@mk8Ta{0AuUix+7_b`4xz)#1gBp+0LH{KBR<3TEp*T(kx zj|+RV{8GdCv~L9j=fhR^{5nK<$cFJaR~u(^KJ*4;LuVdf%VGD{Oy_8b#oeS3K|yln z-B#>G9_@BZGF)K(^I1DDVM>}#!~8BaAP5hl#SS(-w;Ph~JL{#MH$&C+f5JHcILjLw z%#W|`MJDGKSNB#I^9mJNlH7nOI?n5$_iR1R4gVj|r|Cq(KJ1UDv%HxDMlkpg@5l&G zr?&=J@Hl%aKiA{!X*qK+@$s1#+4}1eu+sqdeospDp>4m1|#dbjJ}SUDqSPmiOdk%gY#8zFT)M(w6+*kj1F5380K84DO(p zj0VHi4ZYP3uvz{71LS{!){MNbyBhfj!lO9;?*S+!>nDxh$9k46;ynJ|^TSCSgUUDG zY}4-_ar#2(PoJjKKRJD+%1gg*-OdrkSE{`DBtL3jBa@#{dh<{5X-Q&a@rBYGzmI2X zKe_y5#)B#^|9$H=ji~%e6%haa5ye-kfcU8q#aF6;_~~Kei?&|3RSEpn_@;p-WEt>){$ z@O2(v=kv9euM7FQn6GE^bqQa;#@F-s`c1wr4?PyO_C z13i&-*+k29L*J#RP4u*yo_k2+=g^t(=-K7IOW|M775DYu__$7u+k zb>lVLQmFmYf3$HUXa`R_UMegGU8^ph;}5-f=PgPWx%cCBUz*#P1=K zxNi=ATM%!?1OL4C%ez+IHVAs)?B5`0`L9B5S%L?@eEA-_FI{q65rr>pY~0P^7eDbQ zra!gh=X6iJ`Mn*R_0Hiq(vj{JtJeRK@f$ZjuHk8h-~8S?44-uQp3R`^-?;H+4p;iC zl|F)WQ^aS-#a)E2&~#VMl5|r~J++JZoLcfrj=yo^3k)Ocn?X!(qy#F}Xy*_i|d z+26dni(;LTFGc3Zx;xw3B4$d1DKYaRQ>HgiU}VaP4UsAF5;M20qq{58!o-o`{!S+9 zHf9t*E^>TiS#uqtMk3YC4Gpojea7}jE&snqwW%)X?)u~$ds8hji`%>ET5SF!b!`ot zi&)%OT#8~z>)YGfV)b3k?QMP)^%Zf=lPMY zi#mp(M3j^9qdHmKS=Zdw+_pSY*Rs65v$?CO)#2wpe_pcSRcOnp+|*&8>J0{<8&~7pv>!JP$7mWJ9Il5Vy9s#@f2NgUaU+f3>^0 z{``(kWnZmaK%)x~2dY<(9*nDgf+ zMjk#5aZ6WSq_w#%hoyqKoSC?8<-Un$*Tw7W8e)-l=?C>qb#2R$^-km+?bYF|;;_{9 zX!Xqv)Jy{+oIE9mT6xF2>Xx_FG22*2dwr9125tSC4VQ5MwV$*VMN`fmc216|``PT0 z$VN&Eu5KoB80TaFTt`THVXS$1Q&*(5yQQnSqoo;|)bnTS&F0qS8PHR5iK(7eh)``` zjemVg!#9M#?WmTuhdSOBi*>Zc;_;Y6pUd0L$nwti?he25^2?&FeOjcw(G`b}R!G0p z5L@x3?oPCv_EytrEJ6}|~0GHYlIqf2_fcaGW=7xSu@(M}_#TXWaSd@?9 zq78?mR^;Yi+BFw$S#uYp+1wK4PB%<>^KsI%qi)X*WH#-D@)#PZwhlLa<>yBSu=EqS zz1V4e@o0T}w{{epOc2>DGo?G?WW+<^Q3v~Gp3w~WS{FOJ0#)(|mxr?kYV z{kC*B#2RLyKTAk!tga2gAZoNk&S&19PD#<-j`g?5c%}<}R4;s?6g_Wr{jw1xiKns7s&r^lMH} zmRM^-1Z-Ne#&k)owlw*gQi5`{qz3vlq|@vmd`LD|d6*o{=z&|iO`t~9&>U^(gsLX= z!*wftFloTtjOFPohrsQ*IjTK?Vt6iojps!5YdbgCuj$-ybP$i0bHal(oXOR0cwPE~ zoak;5RXNd{HCS;u;Q<=U6Dtqv#0%(Is>t?95`=U*VQe29JVaidm8-7E+VJVCJRQ^A zra@N2I025L@^V0f&tu_+SsrePtE4|t@pjlZ zov@vcLw#Td1Fv}p$rg1^g|McNV31cA@z;hcSid0L@&rXa4&(l|7+M9j8aF8+y%4h! zk*=m#Bpz$QObME%s~Vhn1z)^w46sKKVX>Y2;BvHf$GalSFxYL3#PGIR0V4&?JKojV zUEkH+8QXUPoKxR43g{PgFN?=8uR*m4!v~DPaybeEpsl?tf+U(7P}317Hj#VDz+`S) zLu@6*XpYk`mC(yz&5@uM!H}Xf-CoUXJ33==WE}*HAv9?GWf)Q-8k;Q6)D$HPbX{9p zWGYz_G*!iNV5p(J?Vm6tt?R09%4LI0(4?5PhCT(KVP}cs;8!W8Jt~hG`+!0i#TsD)T)ke$#g;_Yr2tI;#Q$E z0z6U;OxY%L5=NVBTg|Upy!hPOs_4ARbE_8mgBDdUSh#rhS&Jof@xscv^P_X;&t6zn zQ#F5a6MFTS9=3^+Q=L5)wAZ#{#Tky@&+!d^w3pN?>^(K`Lm<*=FYFG)Xcb{ zi!0}A5{niusAa;MMODJi2|0bPX4lJOarMF~6lUHWP1}OeMd#MkR4raOceZkwduGjo zxk|N2fas#dRki2LbrQ0nfiYc%InmCnJZsUSxs__&TF51r^xbe@npN}W&0V0ylIPrr zQrKwi+^X3s5N}8>^&-?`PRVC4Sd<$CD#;aam@voMh&fE}5!~r7f*)2N=`WN$+?W}7 zpx+yFh+3Y*xQ{VmY(kN+!OKmk|9i$vHU$#El);y)s)Xb}^?sAy@6`MKdjGZF(|UhV z?>qIrTkjv}z2FStJ4WvZ>pi0PWAuKa-cQwgwcZ!%{XD%l>b*nn7wdhE-Y?htcfKL% zUa9w+^uAf|X}#~z`=9l0r8D}Q68{LjPuF{u-p|o{z1})EV`^2vx}W3F=$7ap(IK0f(UcMY`3!SZn)=m<=qq zftb0pVKXEf9i4E_XtaS966oZOR?~@VwT5?kQmW;!6>&d@B?!fYCsqn5-co|vniK+K7^o!~eY zi+~&CXG@u3sH?NBzLkoJS)!;ZG6jv8yp5VK!hf%;88g8bqgKG0U9Y0Dt`;}99d1hN z%|M9fNX@+kb!K}(gSji*Y3?mVnWE8(sHADc%mtSoGIeFA#$;a zn!&<$v%aV)hK9|AvOBdGT<{!}r5FcWrJDd)7$IHHD_YE)|%Y!{p*%`bLFK ze-l_IyOCtfJR9zYe-|xud8ITk(GLOb3#7aYyR~q8xtx1Ju;7+3JxX4^n)Qa^0 zX(GSgA8hUgVobf+ThwJ98P#Uq8`WYqk6zYn-WZK_nNDdg-y1_M>OV`}m7J)#X`H*r zZ+?G(Eb5yL2gd94@s;st#pbfZ3|jG(`#B3#QFFs+h>$!Lqvpo_T3V>-nqMAZ_VcZF zoA>vVrHiQP`Mldv%tJ@yuR%W=X*DlD5^oMkohi?Mb|%?u)T)NC4SUKnS>P3*;QwvE*W{Nh+{xaJj9dGb}_ zH?Wg9Ma|Gy^Ozgq()~3;-~JNeX+-FMjUuGzz|R6WOm;S}KnAbh-~1d}sQ(Qv>AQsE z9N)ixEZ$|3Xg;ZRVU&2)1f;k=3`ATOaZ0wOev|e zcc4oLuV)@NP(CEVHDykNGMAM#vjS{2$uiZ2<_Bfqe-p*Z-ppwY&^2){IG`SvyRNF{ z&a$X^jfAy1ANLG!mmdI5jN=}gDRaEJK0FvXb1|#OIheh`BvO=OKdunI)XBBu%ne9s z;33Y@!-R2K!9(NR#_>F5=Mf^x@-?-EBRt9sf6d{z;*CkJ6pk08S$}}vV{8XZ>kycHoH_9| zjVlRU{Pfk~*4%htL(Du$@dMG168cTz^aREB$K81#Ii{K3@yKidx@SD2Zvr~a=vMQC z@$9Dd{CLWUxnVqf*d7BqtLS?K{eqw$BJ|ThC!gd}@HNfXEMJpPAx~j_BeFQ6@uud+ zE_3BUsK5@jLQK!WU9r}V7@7=RBg}6h-~oHslWM> zy3v=^ACOdV0ludBn&oTq84l-b zny*>DCZFYSzNT?C1@O&eGfAz|pB&;?kLwOcWkB!#;*bV&4=DtWl}!_e>^4#zk3tDJ z3isth;N&U#b%-pu-+}^qch5w0&EIhxzV^RB&*>MbhS+1vTsxuNT#C1xTK#c@vss}# ze>TDFonQ)G74rCmX7lU>t33WVL6pq9P=Se;s3fXi-k3lwnYPK`E$|_*Ssd?!6kp-% z4!ZWg%GaF~3x@gk4`pwVxOox@v;OGJ;wEbfS40L1_d*fbY>Y z`w?9eJ%#k#TL|Xz7WP;RZ%x!UuqW&tM_we;z%5Gb``FIkX zk<1#{k*WI_fh!|^co-qBBLnk(LJaUVE6)#5Nb*4IYxNgTz|MVV1JGn*%yc^{W4z%>6+Y0G32#s zo;lpUZ?_TqH;Ewo9udf^WY6JFqgL-{^EVJC_b{iwaN4{Z$=N?)Zuxw^Q|&!RfbCvT zJEs4-BV5L2&k?>6g0<~8tE08Yao;?N5y9n?y~g147!l+;`u^gG{5;%;JR}oEDBu8J z)3};&Zp?QAV%{dZ;mmI$C`DkbpTm>M?wiuh4(2Y6^?SrhuHtn0n&xYkugTRM&et?w zvwThVAa4cmDK>AxT`X#zgm(#gg=M{dG6~N@nPW}xh{etOs4>~UU>-Zt zJWcFD4-Pr8-uA`%kE6hyDKu`+QKlDR>2;hgUz6+UdGHaWPJh{%{Y9xU<%xs(i?U-< z1?l2}P=8TkbT*O>r3#ai%Cn=B`&C2+_e+A;xmfwhUEnd9%R(sc_^(fq$uRl6Lju?^*mPy@4Zy|Cl*~6H34TD9K;N4#6Lx@PP6^$>Np%UldL$ z996jE0*T*c;hh3suJC}uKU28;HNih>@e03U<1753!dZpK7i)bezY`T6cwP9Nqi~19 zms)y-f1+@?!dn$ys^!^f@mijbZ2VV+|D@4cpKl2K6@~j%zGo{u@EyT_OW~}-35Ao& z|9c8YND<=i7Ye727Wgq6zfj;;6t4J-@c*;IWu#c~HxBO>?r#czQQ=6N&{rv3ruw-~ z;Q?)5IA=lHdza8(rts1w0^gu;M@HcLEWOI(cNWI`kN)0OI8EoZ;BO3cALVaQ^~GTd zrw$kVG>ccbQsL~G9Nqk@g?}XQ*$PLl5%^m+zQU^%9#HuE3U|CI^fxNpuW(A?T9x0+ z3Rk=(^m`O8-y?AG7%h+L_lXLZe<=8WRyaLI%J(k{ClueLa6btJe-~SN#b2RtB*AEN zy~5cY0&lkQ?-Y2a!WF8oi^od-D%2kMqQVhv&+`;c-XZZj74A^{4;3y~{tsAsTi*)T zYJbFBsI(u|pJg}!m5Nq2N6PmVg_EiuV-{BZxK81;;_tEXmEZ3zUgOjD}1komHtJAJG6i7RyZD9A8mZi|Cj?*{>twdg;S~@&r~?A`ta)tC;naJ)uOObxJTjS`+~pL(uXAd zyDk1%!EaW$f0w||Dx7*m;6EsA_`4N2a9rWC6NFzW3}|Yvkv|FjWQEgNfxn_~|2qPo zqi}Y&z!xZN6y9Ltzb*KmD;#-O;QJIV*YZ89aK(|5pH~%Ls`m5W6drt9;_p9R@>}s` zp+8RH4vahK?_U)z`;E}Y6plP0@WnR%Hi5ry;q3z7sc=^DzfsuyLGZg3t}U1J#vH`^ zMg#!K#2onO9QdDe;4^aIB{}f0mD()dvmdJeze z;`clJevcnDlNa!N5kG1YFX2ZA`2IiqsLK!Hw*x)Tz2 z3ngubABH}Pr;RL0Gz13n(r*AYP22l|vAQCjG=ZVI679!{4^BW>Ahq?~@zZN)Pz;$r z_mPW${Il^w&=AXYsj=bQ4#e|FOWY8XFkOrA6M9nxVSqP|L(dL7K1dcZY%)O(Kte8F zBJxa*S+qjzLT*oT*Fyub&U~jQG997klP2-EZV5g*?KIR#x!$MUg)TpHEH4dU$89gDE_7;Q<6WXL{az{QNA6by#rJKOFlMaM)mtgWaDd9*Yqzl3BVM*Q!ch;Hm+Ohibi@AXC*A^FSNp@-Bt zvd2>bA`}sO0-a@FIYcZF178N0wYb+|u^;b_II0tUy4@=$i`Rp~0%F?3bnr> zze`IF*6+#VB3=J92_p|+^~~^CB^+v(SzW?>-#?2(FZFo~N_f6suY~8h086mbcD<|j zE=m=G$i|adaYA-Gv(-9z;p{&t`~>HHaY~5C`%(zyTtTnTtA@k-TeImmn9vdY2-h|O z%36;3x%D9Z?SYQu@V?Up_G&06#MM!q@Yj`$#>vIeeS~sQSG|BR@*MF5JDw%pF!qSc z4G82a6=l=Q<;_hvHw7}Xz1DHQwdD!PZzTbSm^Wy+2wo#i==0iGJZ8N;wdkml0Q<#C zFBltD7sh?E@M(0a`G92niaUqMv3r6u5 z8#`X?u*MD(4JT|nA%GEQ~C`^jrNnXn&4)R(# z`I`b1k+&m2!n?>x+Rw~m9 zR?$A6d|$*sat-v!RykRe^{fwKmM6oUxQ-b2xd9J5GClh!1#)&!3P`P)Hd)fA+1<%OvaypNoqd#md^;%d8X~*ZpzlJev|rNhl+-$ap{{~3jj$*ew@?OWNWZcMZny4DWhW9f@D8VA!mZZG`RU+0R)V# literal 0 HcmV?d00001 diff --git a/Source/3rdParty/fann/usr/local/lib/libfixedfann.2.2.0.dylib b/Source/3rdParty/fann/usr/local/lib/libfixedfann.2.2.0.dylib new file mode 100755 index 0000000000000000000000000000000000000000..1e5b85953a63c4914d1fd68f6ca87702ccafc8fa GIT binary patch literal 69336 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%0AaBL2bqQ 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 literal 0 HcmV?d00001 diff --git a/Source/3rdParty/fann/usr/local/lib/libfloatfann.2.2.0.dylib b/Source/3rdParty/fann/usr/local/lib/libfloatfann.2.2.0.dylib new file mode 100755 index 0000000000000000000000000000000000000000..b817a85dd6755ecb3b9e68bc2d09a66f01633410 GIT binary patch literal 109360 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 qYpNC*36sOpydmy6X5LWe+%j)q v do Dec(Hi); + if Lo <= Hi then + begin + TB:= A[Lo]; + A[Lo]:= A[Hi]; + A[Hi]:= TB; + Inc(Lo); + Dec(Hi); + end; + until Lo > Hi; + if Hi > iLo then QuickSort(A, iLo, Hi); + if Lo < iHi then QuickSort(A, Lo, iHi); + end; + + procedure QuickSortDec(var A: array of TBase; iLo, iHi: Integer); + var Lo, Hi: Integer; + v : variant; + TB : TBase; + begin + Lo := iLo; + Hi := iHi; + v:= A[(Lo + Hi) div 2].ValueByIndex[Index]; + repeat + while A[Lo].ValueByIndex[Index] > v do Inc(Lo); + while A[Hi].ValueByIndex[Index] < v do Dec(Hi); + if Lo <= Hi then + begin + TB := A[Lo]; + A[Lo] := A[Hi]; + A[Hi] := TB; + Inc(Lo); + Dec(Hi); + end; + until Lo > Hi; + if Hi > iLo then QuickSortDec(A, iLo, Hi); + if Lo < iHi then QuickSortDec(A, Lo, iHi); + end; + +begin + if (High(FCollection) > 0) and (Index > -1) then + begin + if (NEnd = 0) or (NStart >= NEnd) then + begin + NStart:= Low(FCollection); + NEnd:= High(FCollection); + end; + if Decending then + QuickSortDec(FCollection, NStart, NEnd) + else + QuickSort(FCollection, NStart, NEnd); + end; +end; + +Procedure TContainer.SortByIndex2(I1, I2 : integer; Decending : boolean); +var a, b : integer; + V1 : variant; +begin + SortByIndex(I1, Decending, 0, 0); + a:= 0; b:= 1; + while b <= High(FCollection) do + begin + V1:= FCollection[a].ValueByIndex[I1]; + while (b <= High(FCollection)) and (FCollection[b].ValueByIndex[I1] = V1) do + Inc(b); + if (a < (b-1)) then + SortByIndex(I2, Decending, a, b-1); + a:= b; + end; +end; + +Procedure TContainer.SortByName(s : string); +var i : integer; +begin + if High(FCollection) > -1 then + begin + i:= FCollection[0].IndexByName[s]; + if i > -1 then SortByIndex(i, false, 0, 0); + end; +end; + +Procedure TContainer.FreeCollection; +var i : integer; +begin + for i:= Low(FCollection) to High(FCollection) do + FCollection[i].Free; + SetLength(FCollection, 0); +end; + +Procedure TContainer.SetSelected(i : integer); +begin + if (i >= Low(FCollection)) and (i <= High(FCollection)) then + FSelected:= i; +end; + +Procedure TContainer.UnSelect; +begin + FSelected:= -1; +end; + +Function TContainer.AddItem : TBase; +begin + Result:= NIL; + try + SetLength(FCollection, High(FCollection)+2); + FSelected:= High(FCollection); + Result:= FCollection[FSelected]; +// Result.AutoNr.Value:= MaxAutoNr; + finally + end; +end; + +Procedure TContainer.InsertItem(i : integer); +var j : integer; +begin + if (i >= Low(FCollection)) and (i <= High(FCollection)) then + begin + SetLength(FCollection, High(FCollection)+2); + for j:= High(FCollection) downto i + 1 do + FCollection[j]:= FCollection[j-1]; + end; +end; + +Procedure TContainer.RemoveItem(i : integer); +var j : integer; +begin + if (i >= Low(FCollection)) and (i <= High(FCollection)) then + begin + FCollection[i].Free; + for j:= i to High(FCollection) - 1 do + FCollection[j]:= FCollection[j+1]; + SetLength(FCollection, High(FCollection)); + end; +end; + +Procedure TContainer.RemoveByReference(Item : TBase); +var i : integer; +begin + for i:= Low(FCollection) to High(FCollection) do + if FCollection[i] = Item then + begin + RemoveItem(i); + Exit; + end; +end; + +Function TContainer.FindByName(s : string) : TBase; +var i : integer; +begin + Result:= NIL; + for i:= Low(FCollection) to High(FCollection) do + if Trim(UpperCase(FCollection[i].Name.Value)) = Trim(Uppercase(s)) then + begin + Result:= FCollection[i]; + Exit; + end; +end; + +Function TContainer.FindByNameOnStock(s : string) : TBase; +var i : integer; + ing : TIngredient; +begin + Result:= NIL; + ing:= NIL; + for i:= Low(FCollection) to High(FCollection) do + begin + if FCollection[i] is TIngredient then + begin + if Trim(UpperCase(FCollection[i].Name.Value)) = Trim(Uppercase(s)) then + begin + ing:= TIngredient(FCollection[i]); + if Result = NIL then Result:= ing + else + begin + if ing.Inventory.Value > TIngredient(Result).Inventory.Value then + Result:= ing; + end; + end; + end; + end; +end; + +Function TContainer.IndexByName(s : string) : integer; +var i : integer; +begin + Result:= -1; + for i:= Low(FCollection) to High(FCollection) do + if Trim(UpperCase(FCollection[i].Name.Value)) = Trim(Uppercase(s)) then + begin + Result:= i; + Exit; + end; +end; + +Function TContainer.FindByAutoNr(i : integer) : TBase; +var j : integer; +begin + Result:= NIL; + for j:= 0 to High(FCollection) do + if FCollection[j].AutoNr.Value = i then + begin + Result:= FCollection[j]; + Exit; + end; +end; + +Procedure TContainer.RemoveByAutoNr(i : integer); +var j : integer; +begin + for j:= Low(FCollection) to High(FCollection) do + if FCollection[j].AutoNr.Value = i then + begin + RemoveItem(j); + Exit; + end; +end; + +Function TContainer.GetNumItems : integer; +begin + Result:= High(FCollection) + 1; +end; + +Function TContainer.GetItem(i : integer) : TBase; +begin + Result:= NIL; + if (i >= Low(FCollection)) and (i <= High(FCollection)) then + Result:= FCollection[i]; +end; + + +{=========================== TFermentables ====================================} + +Constructor TFermentables.Create; +begin + Inherited; + FLabel:= 'FERMENTABLES'; + FFileName:= 'fermentables.xml'; +end; + +Procedure TFermentables.SaveXML; +var i : integer; + FN : string; +begin + try + Inherited SaveXML; + FN:= Settings.DataLocation.Value + FFileName; + for i:= Low(FCollection) to High(FCollection) do + TFermentable(FCollection[i]).SaveXML(FDoc, FRootNode, false); + writeXMLFile(FDoc, FN); + finally + FDoc.Free; + end; +end; + +Procedure TFermentables.ReadXML; +var i : integer; +begin + Inherited ReadXML; + if FRootNode <> NIL then + begin + try + i:= 0; + FChild:= FRootNode.FirstChild; + while FChild <> NIL do + begin + inc(i); + SetLength(FCollection, i); + FCollection[i-1]:= TFermentable.Create(NIL); + TFermentable(FCollection[i-1]).ReadXML(FChild); + FChild:= FChild.NextSibling; + end; + finally + FDoc.Free; + end; + end; +end; + +Function TFermentables.ImportXML : boolean; +var i : integer; +begin + Inherited ImportXML; + if FRootNode <> NIL then + begin + try + i:= High(FCollection) + 1; + FChild:= FRootNode.FirstChild; + while FChild <> NIL do + begin + inc(i); + SetLength(FCollection, i); + FCollection[i-1]:= TFermentable.Create(NIL); + TFermentable(FCollection[i-1]).ReadXML(FChild); + if TFermentable(FCollection[i-1]).Yield.Value < 1 then + RemoveByReference(FCollection[i-1]); + FChild:= FChild.NextSibling; + end; + Result:= TRUE; + finally + FDoc.Free; + end; + end; +end; + +Function TFermentables.GetSelectedItem : TFermentable; +begin + Result:= NIL; + if FSelected > -1 then + Result:= TFermentable(FCollection[FSelected]); +end; + +Function TFermentables.AddItem : TFermentable; +begin + Result:= NIL; + try + SetLength(FCollection, High(FCollection)+2); + FSelected:= High(FCollection); + FCollection[High(FCollection)]:= TFermentable.Create(NIL); + Result:= TFermentable(FCollection[High(FCollection)]); + finally + end; +end; + +Procedure TFermentables.InsertItem(i : integer); +begin + Inherited; + if (i >= Low(FCollection)) and (i <= High(FCollection)) then + FCollection[i]:= TFermentable.Create(NIL); +end; + +Function TFermentables.FindByNameAndSupplier(N, S : string) : TFermentable; +var i : integer; +begin + Result:= NIL; + if (N <> '') AND (S <> '') then + begin + for i:= Low(FCollection) to High(FCollection) do + if (Lowercase(TFermentable(FCollection[i]).Name.Value) = Lowercase(N)) and + (Lowercase(TFermentable(FCollection[i]).Supplier.Value) = Lowercase(S)) then + begin + Result:= TFermentable(FCollection[i]); + Exit; + end; + end; +end; + +{================================== THops =====================================} + +Constructor THops.Create; +begin + Inherited; + FLabel:= 'HOPS'; + FFileName:= 'hops.xml'; + FSelected:= -1; +end; + +Procedure THops.SaveXML; +var i : integer; + FN : string; +begin + try + Inherited SaveXML; + for i:= Low(FCollection) to High(FCollection) do + THop(FCollection[i]).SaveXML(FDoc, FRootNode, false); + FN:= Settings.DataLocation.Value + FFileName; + writeXMLFile(FDoc, FN); + finally + FDoc.Free; + end; +end; + +Procedure THops.ReadXML; +var i : integer; +begin + Inherited ReadXML; + if FRootNode <> NIL then + begin + try + i:= 0; + FChild:= FRootNode.FirstChild; + while FChild <> NIL do + begin + inc(i); + SetLength(FCollection, i); + FCollection[i-1]:= THop.Create(NIL); + THop(FCollection[i-1]).ReadXML(FChild); + FChild:= FChild.NextSibling; + end; + finally + FDoc.Free; + end; + end; +end; + +Function THops.ImportXML : boolean; +var i : integer; +begin + Inherited ImportXML; + if FRootNode <> NIL then + begin + try + i:= High(FCollection) + 1; + FChild:= FRootNode.FirstChild; + while FChild <> NIL do + begin + inc(i); + SetLength(FCollection, i); + FCollection[i-1]:= THop.Create(NIL); + THop(FCollection[i-1]).ReadXML(FChild); + if THop(FCollection[i-1]).Alfa.Value <= 0.5 then + RemoveByReference(FCollection[i-1]); + FChild:= FChild.NextSibling; + end; + Result:= TRUE; + finally + FDoc.Free; + end; + end; +end; + +Function THops.GetSelectedItem : THop; +begin + Result:= NIL; + if FSelected > -1 then + Result:= THop(FCollection[FSelected]); +end; + +Function THops.AddItem : THop; +begin + Result:= NIL; + try + SetLength(FCollection, High(FCollection)+2); + FSelected:= High(FCollection); + Result:= NIL; + FCollection[High(FCollection)]:= THop.Create(NIL); + Result:= THop(FCollection[FSelected]); + finally + end; +end; + +Procedure THops.InsertItem(i : integer); +begin + Inherited; + if (i >= Low(FCollection)) and (i <= High(FCollection)) then + FCollection[i]:= THop.Create(NIL); +end; + +Function THops.FindByNameAndOriginAndAlfa(N, O : string; A : double) : THop; +var i : integer; + A2 : double; + N2, O2 : string; +begin + Result:= NIL; + N:= LowerCase(Trim(N)); + O:= LowerCase(Trim(O)); + A:= RoundTo(A, -1); + if (N <> '') AND (O <> '') then + begin + for i:= Low(FCollection) to High(FCollection) do + begin + N2:= Lowercase(Trim(THop(FCollection[i]).Name.Value)); + O2:= Lowercase(Trim(THop(FCollection[i]).Origin.Value)); + A2:= THop(FCollection[i]).Alfa.Value; + A2:= RoundTo(A2, -1); + if (N2 = N) and (O2 = O) and (A2 = A) then + begin + Result:= THop(FCollection[i]); + Exit; + end; + end; + end; +end; + +{================================== TMiscs ====================================} + +Constructor TMiscs.Create; +begin + Inherited; + FLabel:= 'MISCS'; + FFileName:= 'miscs.xml'; + FSelected:= -1; +end; + +Procedure TMiscs.SaveXML; +var i : integer; + FN : string; +begin + try + Inherited SaveXML; + FN:= Settings.DataLocation.Value + FFileName; + for i:= Low(FCollection) to High(FCollection) do + TMisc(FCollection[i]).SaveXML(FDoc, FRootNode, false); + writeXMLFile(FDoc, FN); + finally + FDoc.Free; + end; +end; + +Procedure TMiscs.ReadXML; +var i : integer; +begin + Inherited ReadXML; + if FRootNode <> NIL then + begin + try + i:= 0; + FChild:= FRootNode.FirstChild; + while FChild <> NIL do + begin + inc(i); + SetLength(FCollection, i); + FCollection[i-1]:= TMisc.Create(NIL); + TMisc(FCollection[i-1]).ReadXML(FChild); + FChild:= FChild.NextSibling; + end; + finally + FDoc.Free; + end; + end; +end; + +Function TMiscs.ImportXML : boolean; +var i : integer; +begin + Inherited ImportXML; + if FRootNode <> NIL then + begin + try + i:= High(FCollection) + 1; + FChild:= FRootNode.FirstChild; + while FChild <> NIL do + begin + inc(i); + SetLength(FCollection, i); + FCollection[i-1]:= TMisc.Create(NIL); + TMisc(FCollection[i-1]).ReadXML(FChild); + {if TMisc(FCollection[i-1])..Value < 1 then + RemoveByReference(FCollection[i-1]);} + FChild:= FChild.NextSibling; + end; + Result:= TRUE; + finally + FDoc.Free; + end; + end; +end; + +Function TMiscs.GetSelectedItem : TMisc; +begin + Result:= NIL; + if FSelected > -1 then + Result:= TMisc(FCollection[FSelected]); +end; + +Function TMiscs.AddItem : TMisc; +begin + Result:= NIL; + try + SetLength(FCollection, High(FCollection)+2); + FSelected:= High(FCollection); + FCollection[High(FCollection)]:= TMisc.Create(NIL); + Result:= TMisc(FCollection[High(FCollection)]); + finally + end; +end; + +Procedure TMiscs.InsertItem(i : integer); +begin + Inherited; + if (i >= Low(FCollection)) and (i <= High(FCollection)) then + FCollection[i]:= TMisc.Create(NIL); +end; + +{================================== TYeasts ===================================} + +Constructor TYeasts.Create; +begin + Inherited; + FLabel:= 'YEASTS'; + FFileName:= 'yeasts.xml'; + FSelected:= -1; +end; + +Procedure TYeasts.SaveXML; +var i : integer; + FN : string; +begin + try + Inherited SaveXML; + FN:= Settings.DataLocation.Value + FFileName; + for i:= Low(FCollection) to High(FCollection) do + TYeast(FCollection[i]).SaveXML(FDoc, FRootNode, false); + writeXMLFile(FDoc, FN); + finally + FDoc.Free; + end; +end; + +Procedure TYeasts.ReadXML; +var i : integer; +begin + Inherited ReadXML; + if FRootNode <> NIL then + begin + try + i:= 0; + FChild:= FRootNode.FirstChild; + while FChild <> NIL do + begin + inc(i); + SetLength(FCollection, i); + FCollection[i-1]:= TYeast.Create(NIL); + TYeast(FCollection[i-1]).ReadXML(FChild); + FChild:= FChild.NextSibling; + end; + finally + FDoc.Free; + end; + end; +end; + +Function TYeasts.ImportXML : boolean; +var i : integer; +begin + Inherited ImportXML; + if FRootNode <> NIL then + begin + try + i:= High(FCollection) + 1; + FChild:= FRootNode.FirstChild; + while FChild <> NIL do + begin + inc(i); + SetLength(FCollection, i); + FCollection[i-1]:= TYeast.Create(NIL); + TYeast(FCollection[i-1]).ReadXML(FChild); + if TYeast(FCollection[i-1]).Laboratory.Value = '' then + RemoveByReference(FCollection[i-1]); + FChild:= FChild.NextSibling; + end; + Result:= TRUE; + finally + FDoc.Free; + end; + end; +end; +Function TYeasts.GetSelectedItem : TYeast; +begin + Result:= NIL; + if FSelected > -1 then + Result:= TYeast(FCollection[FSelected]); +end; + +Function TYeasts.AddItem : TYeast; +begin + Result:= NIL; + try + SetLength(FCollection, High(FCollection)+2); + FSelected:= High(FCollection); + FCollection[High(FCollection)]:= TYeast.Create(NIL); + Result:= TYeast(FCollection[High(FCollection)]); + finally + end; +end; + +Procedure TYeasts.InsertItem(i : integer); +begin + Inherited; + if (i >= Low(FCollection)) and (i <= High(FCollection)) then + FCollection[i]:= TYeast.Create(NIL); +end; + +Function TYeasts.FindByNameAndLaboratory(N, L : string) : TYeast; +var i : integer; +begin + Result:= NIL; + if (N <> '') and (L <> '') then + begin + for i:= Low(FCollection) to High(FCollection) do + if (Lowercase(TYeast(FCollection[i]).Name.Value) = Lowercase(N)) and + (Lowercase(TYeast(FCollection[i]).Laboratory.Value) = Lowercase(L)) then + begin + Result:= TYeast(FCollection[i]); + Exit; + end; + end; +end; + +{================================== TWaters ===================================} + +Constructor TWaters.Create; +begin + Inherited; + FLabel:= 'WATERS'; + FFileName:= 'waters.xml'; + FSelected:= -1; +end; + +Procedure TWaters.SaveXML; +var i : integer; + FN : string; +begin + try + Inherited SaveXML; + FN:= Settings.DataLocation.Value + FFileName; + for i:= Low(FCollection) to High(FCollection) do + TWater(FCollection[i]).SaveXML(FDoc, FRootNode, false); + writeXMLFile(FDoc, FN); + finally + FDoc.Free; + end; +end; + +Procedure TWaters.ReadXML; +var i : integer; +begin + Inherited ReadXML; + if FRootNode <> NIL then + begin + try + i:= 0; + FChild:= FRootNode.FirstChild; + while FChild <> NIL do + begin + inc(i); + SetLength(FCollection, i); + FCollection[i-1]:= TWater.Create(NIL); + TWater(FCollection[i-1]).ReadXML(FChild); + FChild:= FChild.NextSibling; + end; + finally + FDoc.Free; + end; + end; +end; + +Function TWaters.ImportXML : boolean; +var i : integer; +begin + Inherited ImportXML; + if FRootNode <> NIL then + begin + try + i:= High(FCollection) + 1; + FChild:= FRootNode.FirstChild; + while FChild <> NIL do + begin + inc(i); + SetLength(FCollection, i); + FCollection[i-1]:= TWater.Create(NIL); + TWater(FCollection[i-1]).ReadXML(FChild); + if TWater(FCollection[i-1]).Bicarbonate.Value < 0.1 then + RemoveByReference(FCollection[i-1]); + FChild:= FChild.NextSibling; + end; + Result:= TRUE; + finally + FDoc.Free; + end; + end; +end; + +Function TWaters.GetSelectedItem : TWater; +begin + Result:= NIL; + if FSelected > -1 then + Result:= TWater(FCollection[FSelected]); +end; + +Function TWaters.AddItem : TWater; +begin + Result:= NIL; + try + SetLength(FCollection, High(FCollection)+2); + FSelected:= High(FCollection); + FCollection[High(FCollection)]:= TWater.Create(NIL); + Result:= TWater(FCollection[High(FCollection)]); + finally + end; +end; + +Procedure TWaters.InsertItem(i : integer); +begin + Inherited; + if (i >= Low(FCollection)) and (i <= High(FCollection)) then + FCollection[i]:= TWater.Create(NIL); +end; + +Function TWaters.GetDefaultWater : TWater; +var i : integer; + W : TWater; +begin + Result:= NIL; + for i:= 0 to NumItems - 1 do + begin + W:= TWater(Item[i]); + if W.DefaultWater.Value then Result:= W; + end; +end; + +Function TWaters.GetDemiWater : TWater; +var i : integer; + W : TWater; +begin + Result:= NIL; + for i:= 0 to NumItems - 1 do + begin + W:= TWater(Item[i]); + if W.DemiWater then Result:= W; + end; + if Result = NIL then + W:= TWater(FindByName('Gedemineraliseerd water')); + if Result = NIL then + W:= TWater(FindByName('Demiwater')); + if Result = NIL then + W:= TWater(FindByName('Osmosewater')); +end; + +{================================== TBeerstyles ===============================} + +Constructor TBeerstyles.Create; +begin + Inherited; + FLabel:= 'STYLES'; + FFileName:= 'styles.xml'; + FSelected:= -1; +end; + +Procedure TBeerstyles.SaveXML; +var i : integer; + FN : string; +begin + try + Inherited SaveXML; + FN:= Settings.DataLocation.Value + FFileName; + for i:= Low(FCollection) to High(FCollection) do + TBeerstyle(FCollection[i]).SaveXML(FDoc, FRootNode, false); + writeXMLFile(FDoc, FN); + finally + FDoc.Free; + end; +end; + +Procedure TBeerstyles.ReadXML; +var i : integer; +begin + Inherited ReadXML; + if FRootNode <> NIL then + begin + try + i:= 0; + FChild:= FRootNode.FirstChild; + while FChild <> NIL do + begin + inc(i); + SetLength(FCollection, i); + FCollection[i-1]:= TBeerStyle.Create(NIL); + TBeerStyle(FCollection[i-1]).ReadXML(FChild); + FChild:= FChild.NextSibling; + end; + finally + FDoc.Free; + end; + end; +end; + +Function TBeerstyles.ImportXML : boolean; +var i : integer; +begin + Inherited ImportXML; + if FRootNode <> NIL then + begin + try + i:= High(FCollection) + 1; + FChild:= FRootNode.FirstChild; + while FChild <> NIL do + begin + inc(i); + SetLength(FCollection, i); + FCollection[i-1]:= TBeerstyle.Create(NIL); + TBeerstyle(FCollection[i-1]).ReadXML(FChild); + if TBeerstyle(FCollection[i-1]).StyleLetter.Value = '' then + RemoveByReference(FCollection[i-1]); + FChild:= FChild.NextSibling; + end; + Result:= TRUE; + finally + FDoc.Free; + end; + end; +end; +Function TBeerstyles.GetSelectedItem : TBeerstyle; +begin + Result:= NIL; + if FSelected > -1 then + Result:= TBeerstyle(FCollection[FSelected]); +end; + +Function TBeerstyles.AddItem : TBeerStyle; +begin + Result:= NIL; + try + SetLength(FCollection, High(FCollection)+2); + FSelected:= High(FCollection); + FCollection[High(FCollection)]:= TBeerstyle.Create(NIL); + Result:= TBeerstyle(FCollection[High(FCollection)]); + finally + end; +end; + +Procedure TBeerstyles.InsertItem(i : integer); +begin + Inherited; + if (i >= Low(FCollection)) and (i <= High(FCollection)) then + FCollection[i]:= TBeerstyle.Create(NIL); +end; + +{================================== TEquipments ===============================} + +Constructor TEquipments.Create; +begin + Inherited; + FLabel:= 'EQUIPMENTS'; + FFileName:= 'equipments.xml'; + FSelected:= -1; +end; + +Procedure TEquipments.SaveXML; +var i : integer; + FN : string; +begin + try + Inherited SaveXML; + FN:= Settings.DataLocation.Value + FFileName; + for i:= Low(FCollection) to High(FCollection) do + TEquipment(FCollection[i]).SaveXML(FDoc, FRootNode, false); + writeXMLFile(FDoc, FN); + finally + FDoc.Free; + end; +end; + +Procedure TEquipments.ReadXML; +var i : integer; +begin + Inherited ReadXML; + if FRootNode <> NIL then + begin + try + i:= 0; + FChild:= FRootNode.FirstChild; + while FChild <> NIL do + begin + inc(i); + SetLength(FCollection, i); + FCollection[i-1]:= TEquipment.Create(NIL); + TEquipment(FCollection[i-1]).ReadXML(FChild); + FChild:= FChild.NextSibling; + end; + finally + FDoc.Free; + end; + end; +end; + +Function TEquipments.GetSelectedItem : TEquipment; +begin + Result:= NIL; + if FSelected > -1 then + Result:= TEquipment(FCollection[FSelected]); +end; + +Function TEquipments.AddItem : TEquipment; +begin + Result:= NIL; + try + SetLength(FCollection, High(FCollection)+2); + FSelected:= High(FCollection); + FCollection[High(FCollection)]:= TEquipment.Create(NIL); + Result:= TEquipment(FCollection[High(FCollection)]); + finally + end; +end; + +Procedure TEquipments.InsertItem(i : integer); +begin + Inherited; + if (i >= Low(FCollection)) and (i <= High(FCollection)) then + FCollection[i]:= TEquipment.Create(NIL); +end; + +Procedure TEquipments.CalcEfficiencyRegressionFactors; +var i : integer; +begin + for i:= Low(FCollection) to High(FCollection) do + TEquipment(FCollection[i]).CalcEfficiencyFactors; +end; + +Procedure TEquipments.CalcAttenuationRegressionFactors; +var i : integer; +begin + for i:= Low(FCollection) to High(FCollection) do + TEquipment(FCollection[i]).CalcAttenuationFactors; +end; + +{================================== TMashs ====================================} + +Constructor TMashs.Create; +begin + Inherited; + FLabel:= 'MASHS'; + FFileName:= 'mashs.xml'; + FSelected:= -1; +end; + +Procedure TMashs.SaveXML; +var i : integer; + FN : string; +begin + try + Inherited SaveXML; + FN:= Settings.DataLocation.Value + FFileName; + for i:= Low(FCollection) to High(FCollection) do + TMash(FCollection[i]).SaveXML(FDoc, FRootNode, false); + writeXMLFile(FDoc, FN); + finally + FDoc.Free; + end; +end; + +Procedure TMashs.ReadXML; +var i : integer; +begin + Inherited ReadXML; + if FRootNode <> NIL then + begin + try + i:= 0; + FChild:= FRootNode.FirstChild; + while FChild <> NIL do + begin + inc(i); + SetLength(FCollection, i); + FCollection[i-1]:= TMash.Create(NIL); + TMash(FCollection[i-1]).ReadXML(FChild); + FChild:= FChild.NextSibling; + end; + finally + FDoc.Free; + end; + end; +end; + +Function TMashs.ImportXML : boolean; +var i : integer; +begin + Inherited ImportXML; + if FRootNode <> NIL then + begin + try + i:= High(FCollection) + 1; + FChild:= FRootNode.FirstChild; + while FChild <> NIL do + begin + inc(i); + SetLength(FCollection, i); + FCollection[i-1]:= TMash.Create(NIL); + TMash(FCollection[i-1]).ReadXML(FChild); + if TMash(FCollection[i-1]).NumMashSteps = 0 then + RemoveByReference(FCollection[i-1]); + FChild:= FChild.NextSibling; + end; + Result:= TRUE; + finally + FDoc.Free; + end; + end; +end; + +Function TMashs.GetSelectedItem : TMash; +begin + Result:= NIL; + if FSelected > -1 then + Result:= TMash(FCollection[FSelected]); +end; + +Function TMashs.AddItem : TMash; +begin + Result:= NIL; + try + SetLength(FCollection, High(FCollection)+2); + FSelected:= High(FCollection); + FCollection[High(FCollection)]:= TMash.Create(NIL); + Result:= TMash(FCollection[High(FCollection)]); + finally + end; +end; + +Procedure TMashs.InsertItem(i : integer); +begin + Inherited; + if (i >= Low(FCollection)) and (i <= High(FCollection)) then + FCollection[i]:= TMash.Create(NIL); +end; + +{================================== TRecipes ==================================} + + +Constructor TRecipes.Create; +begin + Inherited; + FLabel:= 'RECIPES'; + FFileName:= 'recipes.xml'; + FSelected:= -1; + SetLength(FFermentablesMinMaxArray, 0); + SetLength(FBitterhopMinMaxArray, 0); + SetLength(FAromahopMinMaxArray, 0); + SetLength(FDryhopMinMaxArray, 0); + SetLength(FYeastMinMaxArray, 0); + SetLength(FMiscMinMaxArray, 0); + SetLength(FCommonMinMaxArray, 0); +end; + +Destructor TRecipes.Destroy; +begin + SetLength(FFermentablesMinMaxArray, 0); + SetLength(FBitterhopMinMaxArray, 0); + SetLength(FAromahopMinMaxArray, 0); + SetLength(FDryhopMinMaxArray, 0); + SetLength(FYeastMinMaxArray, 0); + SetLength(FMiscMinMaxArray, 0); + SetLength(FCommonMinMaxArray, 0); + Inherited; +end; + +Procedure TRecipes.SaveXML; +var i : integer; + FN : string; +begin + try + Inherited SaveXML; + FN:= Settings.DataLocation.Value + FFileName; + for i:= Low(FCollection) to High(FCollection) do + begin + TRecipe(FCollection[i]).SaveXML(FDoc, FRootNode, false); + Application.ProcessMessages; + end; + writeXMLFile(FDoc, FN); + finally + FDoc.Free; + end; +end; + +Procedure TRecipes.ReadXML; +var i : integer; + R : TRecipe; +begin + Inherited ReadXML; + if FRootNode <> NIL then + begin + try + i:= 0; + FChild:= FRootNode.FirstChild; + while FChild <> NIL do + begin + inc(i); + SetLength(FCollection, i); + Application.ProcessMessages; + FCollection[i-1]:= TRecipe.Create(NIL); + R:= TRecipe(FCollection[i-1]); + if FFileName = 'brews.xml' then R.RecType:= rtBrew + else if FFileName = 'recipes.xml' then R.RecType:= rtRecipe + else R.RecType:= rtCloud; + R.ReadXML(FChild); + FChild:= FChild.NextSibling; + end; + finally + FDoc.Free; + end; + end; +end; + +Function TRecipes.FindByNameAndNr(Nm, Nr : string) : TRecipe; +var i : integer; + R : TRecipe; +begin + Result:= NIL; + Nm:= Lowercase(Nm); + Nr:= Lowercase(Nr); + for i:= 0 to High(FCollection) do + begin + R:= TRecipe(FCollection[i]); + if (Lowercase(R.NrRecipe.Value) = Nr) and (Lowercase(R.Name.Value) = Nm) then + begin + Result:= R; + Exit; + end; + end; +end; + +Function TRecipes.FindByAutoNr(nr : integer) : TRecipe; +var i : integer; + R : TRecipe; +begin + Result:= NIL; + for i:= 0 to High(FCollection) do + begin + R:= TRecipe(FCollection[i]); + if (R.AutoNr.Value = Nr) then + begin + Result:= R; + Exit; + end; + end; +end; + +Procedure TRecipes.CheckAutoNrs; +var i, maxnr : integer; + R : TRecipe; +begin + maxnr:= MaxAutoNr; + for i:= Low(FCollection) to High(FCollection) do + begin + R:= TRecipe(FCollection[i]); + if R.AutoNr.Value = 0 then + begin + inc(maxnr); + R.AutoNr.Value:= maxnr; + end; + end; +end; + +Function TRecipes.ImportFiles(FN : TStrings; DN : string; Equip : TEquipment; + FT : TFileType) : boolean; +begin + Result:= false; + case FT of + ftXML: Result:= ImportXMLs(FN, DN, Equip); + ftPromash: Result:= ImportRECs(FN, DN, Equip); + ftInvalid: Result:= false; + end; + SaveXML; +end; + +Function TRecipes.ImportXMLs(FN : TStrings; DN : string; Equip : TEquipment) : boolean; +var SL : TStringList; + i : integer; + mask : string; + ps : TProgressBar; +begin + Result:= false; + if DN <> '' then + begin + try + Screen.Cursor:= crHourglass; + {$ifdef WINDOWS} + mask:= '*.xml'; + {$else} + mask:= '*xml'; + {$endif} + SL:= FindAllFiles(DN, mask, false); +{ FrmMain.sbMain.Panels[0].Text:= 'Importeren...'; + ps:= TProgressBar.Create(FrmMain.sbMain); + ps.Parent:= FrmMain.sbMain; + ps.Left:= FrmMain.sbMain.Panels[0].Width + 1; + ps.Width:= FrmMain.sbMain.Panels[1].Width; + ps.Min:= 0; + ps.Max:= SL.Count - 1; + ps.Position:= 0;} + for i:= 0 to SL.Count - 1 do + begin + ImportXML(SL[i], Equip); +// ps.Position:= i; + Application.ProcessMessages; + end; + Result:= TRUE; + finally + Screen.Cursor:= crDefault; +// ps.Free; + SL.Free; +// FrmMain.sbMain.Panels[0].Text:= ''; + ShowMessage('Importeren klaar'); + end; + end + else + begin + for i:= 0 to FN.Count - 1 do + begin + Result:= ImportXML(FN[i], Equip); + end; + end; +end; + +Function TRecipes.GetMaxAutoNr : integer; +var i : integer; +begin + Result:= 0; + for i:= Low(FCollection) to High(FCollection) do + if TRecipe(FCollection[i]).AutoNr.Value > Result then + Result:= TRecipe(FCollection[i]).AutoNr.Value; +end; + +Function TRecipes.ImportXML(FN : string; Equip : TEquipment) : boolean; +var R : TRecipe; + s : string; +begin + Result:= false; + FDoc := TXMLDocument.Create; + FRootNode:= NIL; + try + if FileExists(FN) then + begin + ReadXMLFile(FDoc, FN); + s:= ExtractFileNameOnly(FN); + FRootNode:= FDoc.FindNode(FLabel); + if FRootNode <> NIL then + begin + FChild:= FRootNode.FirstChild; + while FChild <> NIL do + begin + R:= AddItem; + Application.ProcessMessages; + R.ReadXML(FChild); + R.AutoNr.Value:= GetMaxAutoNr + 1; + R.ParentAutoNr.Value:= ''; + + CheckBeerStyle(R); + CheckFermentables(R); + CheckYeasts(R); + + //change the equipment + if Equip <> NIL then R.ChangeEquipment(Equip) + else R.RemoveNonBrewsData; + + if FFileName = 'brews.xml' then R.RecType:= rtBrew + else if FFileName = 'recipes.xml' then R.RecType:= rtRecipe + else R.RecType:= rtCloud; + + FChild:= FChild.NextSibling; + Result:= TRUE; + end; + end; + end; + finally + FDoc.Free; + end; +end; + +Function TRecipes.ImportRECs(FN : TStrings; DN : string; Equip : TEquipment) : boolean; +var SL : TStringList; + i : integer; + mask : string; + ps : TProgressBar; +begin + Result:= false; + if DN <> '' then + begin + try + Screen.Cursor:= crHourglass; + {$ifdef WINDOWS} + mask:= '*.rec'; + {$else} + mask:= '*rec'; + {$endif} + SL:= FindAllFiles(DN, mask, false); +{ FrmMain.sbMain.Panels[0].Text:= 'Importeren...'; + ps:= TProgressBar.Create(FrmMain.sbMain); + ps.Parent:= FrmMain.sbMain; + ps.Left:= FrmMain.sbMain.Panels[0].Width + 1; + ps.Width:= FrmMain.sbMain.Panels[1].Width; + ps.Min:= 0; + ps.Max:= SL.Count - 1; + ps.Position:= 0;} + for i:= 0 to SL.Count - 1 do + begin + ImportREC(SL[i], Equip); +// ps.Position:= i; + Application.ProcessMessages; + end; + Result:= TRUE; + finally + Screen.Cursor:= crDefault; +// ps.Free; + SL.Free; +// FrmMain.sbMain.Panels[0].Text:= ''; + ShowMessage('Importeren klaar'); + end; + end + else + for i:= 0 to FN.Count - 1 do + begin + Result:= ImportREC(FN[i], Equip); + end; +end; + +Function TRecipes.ImportREC(FN : string; Equip : TEquipment) : boolean; +var PI : TPromash; + R : TRecipe; + s : string; +begin + Result:= false; + PI := TPromash.Create(FrmMain); + try + FN:= ConvertStringEnc(FN); + if FileExists(FN) then + begin + if PI.OpenReadRec(FN) then + begin + R:= AddItem; + if R <> NIL then + begin + PI.Convert(R); + s:= R.Style.Name.Value; + R.AutoNr.Value:= MaxAutoNr + 1; + + CheckBeerStyle(R); + CheckFermentables(R); + CheckYeasts(R); + + //change the equipment + if Equip <> NIL then + R.ChangeEquipment(Equip); + + if FFileName = 'brews.xml' then R.RecType:= rtBrew + else if FFileName = 'recipes.xml' then R.RecType:= rtRecipe + else R.RecType:= rtCloud; + + Result:= TRUE; + end; + end; + end; + finally + PI.Free; + end; +end; + +Procedure TRecipes.QuickSortRecipes(var Arr : array of TBase); + procedure QuickSort(var A: array of TBase; iLo, iHi: Integer); + var Lo, Hi: Integer; + s : string; + T : TRecipe; + begin + Lo := iLo; + Hi := iHi; + s:= TRecipe(A[(Lo + Hi) div 2]).NrRecipe.Value; + repeat + while TRecipe(A[Lo]).NrRecipe.Value < s do Inc(Lo); + while TRecipe(A[Hi]).NrRecipe.Value > s do Dec(Hi); + if Lo <= Hi then + begin + T := TRecipe(A[Lo]); + TRecipe(A[Lo]) := TRecipe(A[Hi]); + TRecipe(A[Hi]) := T; + Inc(Lo); + Dec(Hi); + end; + until Lo > Hi; + if Hi > iLo then QuickSort(A, iLo, Hi); + if Lo < iHi then QuickSort(A, Lo, iHi); + end; +begin + if High(Arr) > -1 then QuickSort(Arr, Low(Arr), High(Arr)); +end; + +Procedure TRecipes.Sort; +begin + QuickSortRecipes(FCollection); +end; + +Function TRecipes.GetLastNrRecipe : string; +begin + Sort; + Result:= ''; + if High(FCollection) >= 0 then + Result:= TRecipe(FCollection[High(FCollection)]).NrRecipe.Value; +end; + +Function TRecipes.GetSelectedItem : TRecipe; +begin + Result:= NIL; + if FSelected > -1 then + Result:= TRecipe(FCollection[FSelected]); +end; + +Function TRecipes.AddItem : TRecipe; +begin + Result:= NIL; + try + SetLength(FCollection, High(FCollection)+2); + FSelected:= High(FCollection); + FCollection[High(FCollection)]:= TRecipe.Create(NIL); + Result:= TRecipe(FCollection[High(FCollection)]); + finally + end; +end; + +Procedure TRecipes.InsertItem(i : integer); +var R : TRecipe; +begin + Inherited; + if (i >= Low(FCollection)) and (i <= High(FCollection)) then + begin + FCollection[i]:= TRecipe.Create(NIL); + R:= TRecipe(FCollection[i]); + if FFileName = 'brews.xml' then R.RecType:= rtBrew + else if FFileName = 'recipes.xml' then R.RecType:= rtRecipe + else R.RecType:= rtCloud; + end; +end; + +Function TRecipes.ExportToCSV(A : array of longint) : boolean; +var i, j : integer; + dlg : TSaveDialog; + SL : TStringList; + line : string; + R : TRecipe; +begin + Result:= false; + dlg:= TSaveDialog.Create(frmMain); + if High(FCollection) > 0 then + try + SL:= TStringList.Create; + SL.Sorted:= false; + with dlg do + begin + DefaultExt:= '.csv'; + FileName:= '*.csv'; + Filter:= 'Comma separated values|*.csv'; + if dlg.Execute then + begin + R:= TRecipe(FCollection[0]); + Line:= 'Code;Nr;Naam;Gist naam;'; + for j:= Low(A) to High(A) do + begin + line:= line + R.GetNumberNameByIndex(A[j]); + if j < High(A) then line:= line + ';'; + end; + SL.Add(line); + for i:= Low(FCollection) to High(FCollection) do + begin + line:= ''; + R:= TRecipe(FCollection[i]); + line:= R.NrRecipe.Value + ';'; + line:= line + R.Name.Value + ';'; + line:= line + R.Yeast[0].Name.Value + ';'; + for j:= Low(A) to High(A) do + begin + line:= line + VarToStr(R.GetNumberByIndex(A[j])); + if j < High(A) then line:= line + ';'; + end; + SL.Add(line); + end; + SL.SaveToFile(dlg.FileName); + end; + end; + Result:= TRUE; + finally + dlg.Free; + SL.Free; + end; +end; + +Procedure TRecipes.QuickSortA(var Arr : array of TMinMax); + procedure QuickSort(var A: array of TMinMax; iLo, iHi: Integer); + var Lo, Hi: Integer; + s : single; + T : TMinMax; + begin + Lo := iLo; + Hi := iHi; + s:= A[(Lo + Hi) div 2].PercRecipes; + repeat + while A[Lo].PercRecipes > s do Inc(Lo); + while A[Hi].PercRecipes < s do Dec(Hi); + if Lo <= Hi then + begin + T := A[Lo]; + A[Lo] := A[Hi]; + A[Hi] := T; + Inc(Lo); + Dec(Hi); + end; + until Lo > Hi; + if Hi > iLo then QuickSort(A, iLo, Hi); + if Lo < iHi then QuickSort(A, Lo, iHi); + end; +begin + if High(Arr) > -1 then QuickSort(Arr, Low(Arr), High(Arr)); +end; + +Function TRecipes.Exists(Arr : TMinMaxArray; FName : string) : integer; +var n : integer; +begin + Result:= -1; + for n:= Low(Arr) to High(Arr) do + if Arr[n].Name = FName then + begin + Result:= n; + Exit; + end; +end; + +Function TRecipes.AnalyseFermentables(Lett, Nm : string) : integer; //returns number of recipes +var i, j, k : integer; + R : TRecipe; + F : TFermentable; + FN : string; +begin + Result:= 0; + SetLength(FFermentablesMinMaxArray, 0); + for i:= Low(FCollection) to High(FCollection) do + begin + R:= TRecipe(FCollection[i]); + if (R.Style <> NIL) and + ((LowerCase(R.Style.StyleLetter.Value) = LowerCase(Lett)) and + (Lowercase(R.Style.Name.Value) = Lowercase(Nm))) then + begin + Inc(Result); + R.CalcOG; + for j:= 0 to R.NumFermentables - 1 do + begin + F:= R.Fermentable[j]; + FN:= F.Name.Value; + k:= Exists(FFermentablesMinMaxArray, FN); + if k = -1 then + begin + SetLength(FFermentablesMinMaxArray, High(FFermentablesMinMaxArray) + 2); + k:= High(FFermentablesMinMaxArray); + FFermentablesMinMaxArray[k].Name:= FN; + FFermentablesMinMaxArray[k].PercRecipes:= 1; + FFermentablesMinMaxArray[k].MinUse:= F.Percentage.Value; + FFermentablesMinMaxArray[k].AvUse:= F.Percentage.Value; + FFermentablesMinMaxArray[k].MaxUse:= F.Percentage.Value; + end + else + begin + //temporarily store the number of recipes with this ingredient in PercRecipes + FFermentablesMinMaxArray[k].PercRecipes:= FFermentablesMinMaxArray[k].PercRecipes + 1; + FFermentablesMinMaxArray[k].AvUse:= FFermentablesMinMaxArray[k].AvUse + F.Percentage.Value; + if F.Percentage.Value < FFermentablesMinMaxArray[k].MinUse then + FFermentablesMinMaxArray[k].MinUse:= F.Percentage.Value; + if F.Percentage.Value > FFermentablesMinMaxArray[k].MaxUse then + FFermentablesMinMaxArray[k].MaxUse:= F.Percentage.Value; + end; + end; + end; + end; + if (High(FCollection) >= 0) then + begin + for i:= Low(FFermentablesMinMaxArray) to High(FFermentablesMinMaxArray) do + begin + if FFermentablesMinMaxArray[i].PercRecipes > 0 then + FFermentablesMinMaxArray[i].AvUse:= FFermentablesMinMaxArray[i].AvUse / FFermentablesMinMaxArray[i].PercRecipes + else + FFermentablesMinMaxArray[i].AvUse:= 0; + if Result > 0 then + FFermentablesMinMaxArray[i].PercRecipes:= 100 * FFermentablesMinMaxArray[i].PercRecipes / Result + else + FFermentablesMinMaxArray[i].PercRecipes:= 0; + end; + QuickSortA(FFermentablesMinMaxArray); + end; +end; + +Function TRecipes.AnalyseHops(Lett, Nm : string) : integer; //returns number of recipes +type + THR = record + name : string; + conc : double; + end; +var i, j, k : integer; + R : TRecipe; + H : THop; + FN : string; + conc : double; + HRAB, HRAA, HRAD : array of THR; + function FindHR(var HRA : array of THR; nm : string) : integer; + var n : integer; + begin + Result:= -1; + for n:= Low(HRA) to High(HRA) do + if HRA[n].name = nm then + begin + Result:= n; + Exit; + end; + end; + Procedure FillArrays(var MMA : TMinMaxArray; HRA : array of THR); + var j : integer; + begin + for j:= 0 to High(HRA) do + begin + k:= Exists(MMA, HRA[j].Name); + if k = -1 then + begin + SetLength(MMA, High(MMA) + 2); + k:= High(MMA); + MMA[k].Name:= HRA[j].Name; + MMA[k].PercRecipes:= 1; + MMA[k].MinUse:= HRA[j].Conc; + MMA[k].AvUse:= MMA[k].MinUse; + MMA[k].MaxUse:= MMA[k].MinUse; + end + else + begin + //temporarily store the number of recipes with this ingredient in PercRecipes + MMA[k].PercRecipes:= MMA[k].PercRecipes + 1; + MMA[k].AvUse:= MMA[k].AvUse + HRA[j].Conc; + if HRA[j].Conc < MMA[k].MinUse then + MMA[k].MinUse:= HRA[j].Conc; + if HRA[j].Conc > MMA[k].MaxUse then + MMA[k].MaxUse:= HRA[j].Conc; + end; + end; + end; + +begin + Result:= 0; + SetLength(FBitterhopMinMaxArray, 0); + SetLength(FAromahopMinMaxArray, 0); + SetLength(FDryhopMinMaxArray, 0); + SetLength(HRAB, 0); + SetLength(HRAA, 0); + SetLength(HRAD, 0); + for i:= Low(FCollection) to High(FCollection) do + begin + R:= TRecipe(FCollection[i]); + if (R.Style <> NIL) and + ((LowerCase(R.Style.StyleLetter.Value) = LowerCase(Lett)) and + (Lowercase(R.Style.Name.Value) = Lowercase(Nm))) then + begin + Inc(Result); + for j:= 0 to R.NumHops - 1 do + begin + H:= R.Hop[j]; + FN:= H.Name.Value; + if (H.Use = huBoil) or (H.Use = huAroma) or (H.Use = huFirstWort) + or (H.Use = huWhirlpool) then + begin + if H.Time.Value > 30 then + begin + conc:= H.BitternessContribution; + k:= FindHR(HRAB, FN); + if k = -1 then + begin + SetLength(HRAB, High(HRAB) + 2); + k:= High(HRAB); + HRAB[k].Name:= FN; + HRAB[k].Conc:= 0; + end; + HRAB[k].Conc:= HRAB[k].Conc + conc; + end + else if R.BatchSize.DisplayValue > 0 then + begin + Conc:= H.Amount.DisplayValue / R.BatchSize.DisplayValue; + k:= FindHR(HRAA, FN); + if k = -1 then + begin + SetLength(HRAA, High(HRAA) + 2); + k:= High(HRAA); + HRAA[k].Name:= FN; + HRAA[k].Conc:= 0; + end; + HRAA[k].Conc:= HRAA[k].Conc + conc; + end; + end + else if H.Use = huDryhop then + begin + if R.BatchSize.DisplayValue > 0 then + begin + conc:= H.Amount.DisplayValue / R.BatchSize.DisplayValue; + k:= FindHR(HRAD, FN); + if k = -1 then + begin + SetLength(HRAD, High(HRAD) + 2); + k:= High(HRAD); + HRAD[k].Name:= FN; + HRAD[k].Conc:= 0; + end; + HRAD[k].Conc:= HRAD[k].Conc + conc; + end; + end; + end; + + FillArrays(FBitterhopMinMaxArray, HRAB); + FillArrays(FAromahopMinMaxArray, HRAA); + FillArrays(FDryHopMinMaxArray, HRAD); + SetLength(HRAB, 0); + SetLength(HRAA, 0); + SetLength(HRAD, 0); + end; + end; + if (High(FCollection) >= 0) then + begin + for i:= Low(FBitterhopMinMaxArray) to High(FBitterhopMinMaxArray) do + begin + if FBitterhopMinMaxArray[i].PercRecipes > 0 then + FBitterhopMinMaxArray[i].AvUse:= FBitterhopMinMaxArray[i].AvUse + / FBitterhopMinMaxArray[i].PercRecipes + else + FBitterhopMinMaxArray[i].AvUse:= 0; + if Result > 0 then + FBitterhopMinMaxArray[i].PercRecipes:= + 100 * FBitterhopMinMaxArray[i].PercRecipes / Result + else + FBitterhopMinMaxArray[i].PercRecipes:= 0; + end; + QuickSortA(FBitterhopMinMaxArray); + + for i:= Low(FAromahopMinMaxArray) to High(FAromahopMinMaxArray) do + begin + if FAromahopMinMaxArray[i].PercRecipes > 0 then + FAromahopMinMaxArray[i].AvUse:= FAromahopMinMaxArray[i].AvUse + / FAromahopMinMaxArray[i].PercRecipes + else + FAromahopMinMaxArray[i].AvUse:= 0; + if Result > 0 then + FAromahopMinMaxArray[i].PercRecipes:= + 100 * FAromahopMinMaxArray[i].PercRecipes / Result + else + FAromahopMinMaxArray[i].PercRecipes:= 0; + end; + QuickSortA(FAromahopMinMaxArray); + + for i:= Low(FDryhopMinMaxArray) to High(FDryhopMinMaxArray) do + begin + if FDryhopMinMaxArray[i].PercRecipes > 0 then + FDryhopMinMaxArray[i].AvUse:= FDryhopMinMaxArray[i].AvUse + / FDryhopMinMaxArray[i].PercRecipes + else + FDryhopMinMaxArray[i].AvUse:= 0; + if Result > 0 then + FDryhopMinMaxArray[i].PercRecipes:= + 100 * FDryhopMinMaxArray[i].PercRecipes / Result + else + FDryhopMinMaxArray[i].PercRecipes:= 0; + end; + QuickSortA(FDryhopMinMaxArray); + end; +end; + +Function TRecipes.AnalyseYeasts(Lett, Nm : string) : integer; //returns number of recipes +var i, j, k : integer; + R : TRecipe; + Y : TYeast; + FN : string; +begin + Result:= 0; + if High(FYeastMinMaxArray) >= 0 then + SetLength(FYeastMinMaxArray, 0); + for i:= Low(FCollection) to High(FCollection) do + begin + R:= TRecipe(FCollection[i]); + if (R.Style <> NIL) and + ((LowerCase(R.Style.StyleLetter.Value) = LowerCase(Lett)) and + (Lowercase(R.Style.Name.Value) = Lowercase(Nm))) then + begin + Inc(Result); + for j:= 0 to R.NumYeasts - 1 do + begin + Y:= R.Yeast[j]; + FN:= Y.Name.Value; + k:= Exists(FYeastMinMaxArray, FN); + if k = -1 then + begin + SetLength(FYeastMinMaxArray, High(FYeastMinMaxArray) + 2); + k:= High(FYeastMinMaxArray); + FYeastMinMaxArray[k].Name:= FN; + FYeastMinMaxArray[k].PercRecipes:= 1; + {FYeastMinMaxArray[k].MinUse:= F.Percentage.Value; + FYeastMinMaxArray[k].AvUse:= F.Percentage.Value; + FYeastMinMaxArray[k].MaxUse:= F.Percentage.Value;} + end + else + begin + //temporarily store the number of recipes with this ingredient in PercRecipes + FYeastMinMaxArray[k].PercRecipes:= FYeastMinMaxArray[k].PercRecipes + 1; + {FYeastMinMaxArray[k].AvUse:= FYeastMinMaxArray[k].AvUse + F.Percentage.Value; + if F.Percentage.Value < FYeastMinMaxArray[k].MinUse then + FYeastMinMaxArray[k].MinUse:= F.Percentage.Value; + if F.Percentage.Value > FYeastMinMaxArray[k].MaxUse then + FYeastMinMaxArray[k].MaxUse:= F.Percentage.Value;} + end; + end; + end; + end; + if (High(FCollection) >= 0) then + begin + for i:= Low(FYeastMinMaxArray) to High(FYeastMinMaxArray) do + begin + { if FYeastMinMaxArray[i].PercRecipes > 0 then + FYeastMinMaxArray[i].AvUse:= FYeastMinMaxArray[i].AvUse / FYeastMinMaxArray[i].PercRecipes + else + FYeastMinMaxArray[i].AvUse:= 0;} + if Result > 0 then + FYeastMinMaxArray[i].PercRecipes:= 100 * FYeastMinMaxArray[i].PercRecipes / Result + else + FYeastMinMaxArray[i].PercRecipes:= 0; + end; + QuickSortA(FYeastMinMaxArray); + end; +end; + +Function TRecipes.AnalyseMiscs(Lett, Nm : string) : integer; //returns number of recipes +var i, j, k : integer; + R : TRecipe; + M : TMisc; + FN : string; + conc : double; +begin + Result:= 0; + if High(FMiscMinMaxArray) >= 0 then + SetLength(FMiscMinMaxArray, 0); + for i:= Low(FCollection) to High(FCollection) do + begin + R:= TRecipe(FCollection[i]); + if (R.Style <> NIL) and + ((LowerCase(R.Style.StyleLetter.Value) = LowerCase(Lett)) and + (Lowercase(R.Style.Name.Value) = Lowercase(Nm))) then + begin + Inc(Result); + for j:= 0 to R.NumMiscs - 1 do + begin + M:= R.Misc[j]; + FN:= M.Name.Value; + if ((M.MiscType = mtSpice) or (M.MiscType = mtHerb) or (M.MiscType = mtFlavor) + or (M.MiscType = mtOther)) and (R.BatchSize.DisplayValue > 0) then + begin + conc:= M.Amount.DisplayValue / R.BatchSize.DisplayValue; + k:= Exists(FMiscMinMaxArray, FN); + if k = -1 then + begin + SetLength(FMiscMinMaxArray, High(FMiscMinMaxArray) + 2); + k:= High(FMiscMinMaxArray); + FMiscMinMaxArray[k].Name:= FN; + FMiscMinMaxArray[k].PercRecipes:= 1; + FMiscMinMaxArray[k].MinUse:= Conc; + FMiscMinMaxArray[k].AvUse:= Conc; + FMiscMinMaxArray[k].MaxUse:= Conc; + end + else + begin + //temporarily store the number of recipes with this ingredient in PercRecipes + FMiscMinMaxArray[k].PercRecipes:= FMiscMinMaxArray[k].PercRecipes + 1; + FMiscMinMaxArray[k].AvUse:= FMiscMinMaxArray[k].AvUse + Conc; + if Conc < FMiscMinMaxArray[k].MinUse then + FMiscMinMaxArray[k].MinUse:= Conc; + if Conc > FMiscMinMaxArray[k].MaxUse then + FMiscMinMaxArray[k].MaxUse:= Conc; + end; + end; + end; + end; + end; + if (High(FCollection) >= 0) then + begin + for i:= Low(FMiscMinMaxArray) to High(FMiscMinMaxArray) do + begin + if FMiscMinMaxArray[i].PercRecipes > 0 then + FMiscMinMaxArray[i].AvUse:= FMiscMinMaxArray[i].AvUse / FMiscMinMaxArray[i].PercRecipes + else + FMiscMinMaxArray[i].AvUse:= 0; + if Result > 0 then + FMiscMinMaxArray[i].PercRecipes:= 100 * FMiscMinMaxArray[i].PercRecipes / Result + else + FMiscMinMaxArray[i].PercRecipes:= 0; + end; + QuickSortA(FMiscMinMaxArray); + end; +end; + +Function TRecipes.AnalyseRecipes(Lett, Nm : string) : integer; //returns number of recipes +var i, j : integer; + R : TRecipe; + SGp, bitt, x : double; +begin + Result:= 0; + SetLength(FCommonMinMaxArray, 0); + SetLength(FCommonMinMaxArray, 3); + for j:= 0 to High(FCommonMinMaxArray) do + begin + FCommonMinMaxArray[j].PercRecipes:= 0; + FCommonMinMaxArray[j].MinUse:= 10000; + FCommonMinMaxArray[j].AvUse:= 0; + FCommonMinMaxArray[j].MaxUse:= 0; + FCommonMinMaxArray[j].Name:= ''; + end; + //0 = SG points + FCommonMinMaxArray[0].Name:= 'SG punten'; + //1 = Bitterness + FCommonMinMaxArray[1].Name:= 'Bitterheid (IBU)'; + //2 = Color + FCommonMinMaxArray[2].Name:= 'Kleur (' + TRecipe(FCollection[0]).EstColor.DisplayUnitString + ')'; + { //3 = BitternessIndex + FCommonMinMaxArray[3].Name:= 'Bitterheidsindex';} + + for i:= Low(FCollection) to High(FCollection) do + begin + R:= TRecipe(FCollection[i]); + if (R.Style <> NIL) and + ((LowerCase(R.Style.StyleLetter.Value) = LowerCase(Lett)) and + (Lowercase(R.Style.Name.Value) = Lowercase(Nm))) then + begin + Inc(Result); + + R.CalcOG; + if R.OG.Value > 1 then + SGp:= 1000 * (R.OG.Value - 1) + else + SGp:= 1000 * (R.EstOG.Value - 1); + FCommonMinMaxArray[0].AvUse:= FCommonMinMaxArray[0].AvUse + SGp; + if SGp < FCommonMinMaxArray[0].MinUse then + FCommonMinMaxArray[0].MinUse:= SGp; + if SGp > FCommonMinMaxArray[0].MaxUse then + FCommonMinMaxArray[0].MaxUse:= SGp; + + R.CalcBitterness; + bitt:= R.IBUcalc.DisplayValue; + FCommonMinMaxArray[1].AvUse:= FCommonMinMaxArray[1].AvUse + bitt; + if bitt < FCommonMinMaxArray[1].MinUse then + FCommonMinMaxArray[1].MinUse:= bitt; + if bitt > FCommonMinMaxArray[1].MaxUse then + FCommonMinMaxArray[1].MaxUse:= bitt; + +{ if SGp > 0 then x:= bitt / SGp + else x:= 0; + FCommonMinMaxArray[2].AvUse:= FCommonMinMaxArray[2].AvUse + x; + if x < FCommonMinMaxArray[2].MinUse then + FCommonMinMaxArray[2].MinUse:= x; + if x > FCommonMinMaxArray[2].MaxUse then + FCommonMinMaxArray[2].MaxUse:= x;} + + R.CalcColor; + x:= R.EstColor.DisplayValue; + FCommonMinMaxArray[2].AvUse:= FCommonMinMaxArray[2].AvUse + x; + if x < FCommonMinMaxArray[2].MinUse then + FCommonMinMaxArray[2].MinUse:= x; + if x > FCommonMinMaxArray[2].MaxUse then + FCommonMinMaxArray[2].MaxUse:= x; + end; + end; + if (High(FCollection) >= 0) then + begin + for i:= Low(FCommonMinMaxArray) to High(FCommonMinMaxArray) do + begin + if Result > 0 then + FCommonMinMaxArray[i].AvUse:= FCommonMinMaxArray[i].AvUse / Result + else + FCommonMinMaxArray[i].AvUse:= 0; + end; + end; +end; +{============================= TRecipesByStyle ================================} + +{ TStyleRec = record + Name : string; + Recipes : array of TRecipe; + end; + + TStyleLetters = record + Letter : string; + Styles : array of TStyleRec; + end;} + +Constructor TRecipesByStyle.Create(R : TRecipes); + begin + Inherited Create; + FCollection:= R; + Fill; + Sort; + end; + +Destructor TRecipesByStyle.Destroy; +begin + Empty; + Inherited; +end; + +Procedure TRecipesByStyle.SaveXML; +var Doc : TXMLDocument; + iRootNode : TDOMNode; + n, s, i : integer; +begin + try + Doc := TXMLDocument.Create; + iRootNode := Doc.CreateElement('RECIPES'); + Doc.Appendchild(iRootNode); + + for n:= Low(FStyleLetters) to High(FStyleLetters) do + begin + for s:= Low(FStyleLetters[n].Styles) to High(FStyleLetters[n].Styles) do + begin + for i:= Low(FStyleLetters[n].Styles[s].Recipes) to High(FStyleLetters[n].Styles[s].Recipes) do + FStyleLetters[n].Styles[s].Recipes[i].SaveXML(Doc, iRootNode, false); + end; + end; + + writeXMLFile(Doc, Settings.DataLocation.Value + 'recipes.xml'); + finally + Doc.Free; + end; +end; + +Procedure TRecipesByStyle.Fill; +var n, n2, s, s2, i, r : integer; + Num, Stl : string; + Rec : TRecipe; +begin + Empty; + for i:= 1 to FCollection.GetNumItems do + begin + Rec:= TRecipe(FCollection.Item[i-1]); + Num:= Rec.Style.StyleLetter.Value; + Stl:= Rec.Style.Name.Value; + n:= GetLetterByName(Num); + s:= GetStyleByName(Num, Stl); + if n < 0 then //Style Number does not exist + begin + n2:= High(FStyleLetters) + 1; + SetLength(FStyleLetters, n2 + 1); + FStyleLetters[n2].Letter:= Num; + SetLength(FStyleLetters[n2].Styles, 1); + FStyleLetters[n2].Styles[0].Name:= Stl; + SetLength(FStyleLetters[n2].Styles[0].Recipes, 1); + FStyleLetters[n2].Styles[0].Recipes[0]:= Rec; + end + else if s < 0 then //Style does not exist + begin + s2:= High(FStyleLetters[n].Styles) + 1; + SetLength(FStyleLetters[n].Styles, s2 + 1); + FStyleLetters[n].Styles[s2].Name:= Stl; + SetLength(FStyleLetters[n].Styles[s2].Recipes, 1); + FStyleLetters[n].Styles[s2].Recipes[0]:= Rec; + end + else //Both exist + begin + r:= High(FStyleLetters[n].Styles[s].Recipes) + 1; + SetLength(FStyleLetters[n].Styles[s].Recipes, r+1); + FStyleLetters[n].Styles[s].Recipes[r]:= Rec; + end; + end; +end; + +Procedure TRecipesByStyle.Empty; +var n, s, i : integer; +begin + for n:= Low(FStyleLetters) to High(FStyleLetters) do + begin + for s:= Low(FStyleLetters[n].Styles) to High(FStyleLetters[n].Styles) do + begin + for i:= Low(FStyleLetters[n].Styles[s].Recipes) to High(FStyleLetters[n].Styles[s].Recipes) do + FStyleLetters[n].Styles[s].Recipes[i]:= NIL; + SetLength(FStyleLetters[n].Styles[s].Recipes, 0); + end; + SetLength(FStyleLetters[n].Styles, 0); + end; + SetLength(FStyleLetters, 0); +end; + +Procedure TRecipesByStyle.QuickSortInStyles(var Arr : array of TRecipe); + procedure QuickSort(var A: array of TRecipe; iLo, iHi: Integer); + var Lo, Hi: Integer; + l : string; + T : TRecipe; + begin + Lo := iLo; + Hi := iHi; + l:= A[(Lo + Hi) div 2].NrRecipe.Value; + repeat + while A[Lo].NrRecipe.Value < l do Inc(Lo); + while A[Hi].NrRecipe.Value > l do Dec(Hi); + if Lo <= Hi then + begin + T := A[Lo]; + A[Lo] := A[Hi]; + A[Hi] := T; + Inc(Lo); + Dec(Hi); + end; + until Lo > Hi; + if Hi > iLo then QuickSort(A, iLo, Hi); + if Lo < iHi then QuickSort(A, Lo, iHi); + end; +begin + if High(Arr) > -1 then QuickSort(Arr, Low(Arr), High(Arr)); +end; + +Procedure TRecipesByStyle.QuickSortStyles(var Arr : array of TStyleRec); + procedure QuickSort(var A: array of TStyleRec; iLo, iHi: Integer); + var Lo, Hi: Integer; + s : string; + T : TStyleRec; + begin + Lo := iLo; + Hi := iHi; + s:= A[(Lo + Hi) div 2].Name; + repeat + while A[Lo].Name < s do Inc(Lo); + while A[Hi].Name > s do Dec(Hi); + if Lo <= Hi then + begin + T := A[Lo]; + A[Lo] := A[Hi]; + A[Hi] := T; + Inc(Lo); + Dec(Hi); + end; + until Lo > Hi; + if Hi > iLo then QuickSort(A, iLo, Hi); + if Lo < iHi then QuickSort(A, Lo, iHi); + end; +begin + if High(Arr) > -1 then QuickSort(Arr, Low(Arr), High(Arr)); +end; + +Procedure TRecipesByStyle.QuickSortLetters(var Arr : array of TStyleLetters); + procedure QuickSort(var A: array of TStyleLetters; iLo, iHi: Integer); + var Lo, Hi: Integer; + l : string; + T : TStyleLetters; + begin + Lo := iLo; + Hi := iHi; + l := A[(Lo + Hi) div 2].Letter; + repeat + while A[Lo].Letter < l do Inc(Lo); + while A[Hi].Letter > l do Dec(Hi); + if Lo <= Hi then + begin + T := A[Lo]; + A[Lo] := A[Hi]; + A[Hi] := T; + Inc(Lo); + Dec(Hi); + end; + until Lo > Hi; + if Hi > iLo then QuickSort(A, iLo, Hi); + if Lo < iHi then QuickSort(A, Lo, iHi); + end; +begin + if High(Arr) > -1 then QuickSort(Arr, Low(Arr), High(Arr)); +end; + +Procedure TRecipesByStyle.Sort; +var n, s : integer; +begin +//sort recipes in every style by recipe number + for n:= Low(FStyleLetters) to High(FStyleLetters) do + for s:= Low(FStyleLetters[n].Styles) to High(FStyleLetters[n].Styles) do + QuickSortInStyles(FStyleLetters[n].Styles[s].Recipes); + +//sort style names + for n:= Low(FStyleLetters) to High(FStyleLetters) do + QuickSortStyles(FStyleLetters[n].Styles); +//sort style letters + QuickSortLetters(FStyleLetters); +end; + +Function TRecipesByStyle.GetLetterByName(Num : string) : integer; +var n : integer; +begin + Result:= -1; + for n:= Low(FStyleLetters) to High(FStyleLetters) do + if FStyleLetters[n].Letter = Num then + begin + Result:= n; + Exit; + end; +end; + +Function TRecipesByStyle.GetStyleByName(Num, Stl : string) : integer; +var n, s : integer; +begin + Result:= -1; + n:= GetLetterByName(Num); + if n > -1 then + begin + for s:= Low(FStyleLetters[n].Styles) to High(FStyleLetters[n].Styles) do + if FStyleLetters[n].Styles[s].Name = Stl then + begin + Result:= s; + Exit; + end; + end; +end; + +Function TRecipesByStyle.GetNumStyleLetters : integer; +begin + Result:= High(FStyleLetters) + 1; +end; + +Function TRecipesByStyle.GetNumStyles(i : integer) : integer; +begin + Result:= -1; + if (i >= Low(FStyleLetters)) and (i <= High(FStyleLetters)) then + Result:= High(FStyleLetters[i].Styles) + 1; +end; + +Function TRecipesByStyle.GetStyleLetter(i : integer) : string; +begin + Result:= ''; + if (i >= Low(FStyleLetters)) and (i <= High(FStyleLetters)) then + Result:= FStyleLetters[i].Letter; +end; + +Function TRecipesByStyle.GetStyleName(n : integer; s : integer) : string; +begin + Result:= ''; + if (n >= Low(FStyleLetters)) and (n <= High(FStyleLetters)) then + if (s >= Low(FStyleLetters[n].Styles)) and (s <= High(FStyleLetters[n].Styles)) then + Result:= FStyleLetters[n].Styles[s].Name; +end; + +Function TRecipesByStyle.GetNumRecipes(n : integer; s : integer) : integer; +begin + Result:= -1; + if (n >= Low(FStyleLetters)) and (n <= High(FStyleLetters)) then + if (s >= Low(FStyleLetters[n].Styles)) and (s <= High(FStyleLetters[n].Styles)) then + Result:= High(FStyleLetters[n].Styles[s].Recipes) + 1; +end; + +Function TRecipesByStyle.GetRecipe(n : integer; s : integer; i : integer) : TRecipe; +begin + Result:= NIL; + if (n >= Low(FStyleLetters)) and (n <= High(FStyleLetters)) then + if (s >= Low(FStyleLetters[n].Styles)) and (s <= High(FStyleLetters[n].Styles)) then + if (i >= Low(FStyleLetters[n].Styles[s].Recipes)) and (i <= High(FStyleLetters[n].Styles[s].Recipes)) then + Result:= FStyleLetters[n].Styles[s].Recipes[i]; +end; + +{============================= System functions ===============================} + +Procedure CheckBeerStyle(Rec : TRecipe); +var s : string; + OK : boolean; + BS : TBeerStyle; +begin +//check if beerstyle exist in the database. +//If not, check the substitution database, otherwise ask for an alternative + s:= ''; + if Rec.Style <> NIL then + s:= Rec.Style.Name.Value; + if Beerstyles.FindByName(s) = NIL then + begin + //first, look for subtitute in the substitutions database + OK:= StyleSubs.OriginalExists(s); + if OK then + begin + s:= StyleSubs.FindSubstitute(s); + BS:= TBeerStyle(BeerStyles.FindByName(s)); + OK:= (BS <> NIL); + if not OK then + StyleSubs.RemoveOriginal(s); + end; + if OK then + Rec.Style.Assign(BS) + else + begin + FrmSelectBeerStyle:= TFrmSelectBeerStyle.Create(FrmMain); + if FrmSelectBeerStyle.Execute(s) then + begin + //put style replacement in the substitutions database + if (not StyleSubs.OriginalExists(s)) then + StyleSubs.Add(s, FrmSelectBeerStyle.BeerStyle.Name.Value); + Rec.Style.Assign(FrmSelectBeerStyle.BeerStyle); + end; + FrmSelectBeerStyle.Free; + end; + end; +end; + +Procedure CheckFermentables(Rec : TRecipe); +var s, s2 : string; + OK : boolean; + i : integer; + F : TFermentable; + am, perc, yield, color, CoarseFineDiff, moisture, DiastaticPower, Protein, + DissolvedProtein, IbuGalPerLb: double; +begin +//check if fermentable exist in the database. +//If not, check the substitution database, otherwise ask for an alternative + for i:= 0 to Rec.NumFermentables - 1 do + begin + s:= Rec.Fermentable[i].Name.Value; + s2:= Rec.Fermentable[i].Supplier.Value; + OK:= (Fermentables.FindByNameAndSupplier(s, s2) <> NIL); + if (not OK) then + begin + OK:= FermentableSubs.OriginalExists(s, s2); + if OK then + begin + FermentableSubs.FindSubstitute(s, s2, s, s2); + F:= TFermentable(Fermentables.FindByNameAndSupplier(s, s2)); + if F <> NIL then + begin + am:= Rec.Fermentable[i].Amount.Value; + perc:= Rec.Fermentable[i].Percentage.Value; + Yield:= Rec.Fermentable[i].Yield.Value; + Color:= Rec.Fermentable[i].Color.Value; + CoarseFineDiff:= Rec.Fermentable[i].CoarseFineDiff.Value; + Moisture:= Rec.Fermentable[i].Moisture.Value; + DiastaticPower:= Rec.Fermentable[i].DiastaticPower.Value; + Protein:= Rec.Fermentable[i].Protein.Value; + DissolvedProtein:= Rec.Fermentable[i].DissolvedProtein.Value; + IbuGalPerLb:= Rec.Fermentable[i].IbuGalPerLb.Value; + + Rec.Fermentable[i].Assign(F); + Rec.Fermentable[i].Amount.Value:= am; + Rec.Fermentable[i].Percentage.Value:= perc; + Rec.Fermentable[i].Yield.Value:= Yield; + Rec.Fermentable[i].Color.Value:= Color; + Rec.Fermentable[i].CoarseFineDiff.Value:= CoarseFineDiff; + Rec.Fermentable[i].Moisture.Value:= Moisture; + Rec.Fermentable[i].DiastaticPower.Value:= DiastaticPower; + Rec.Fermentable[i].Protein.Value:= Protein; + Rec.Fermentable[i].DissolvedProtein.Value:= DissolvedProtein; + Rec.Fermentable[i].IbuGalPerLb.Value:= IbuGalPerLb; + end + else + FermentableSubs.RemoveOriginal(s, s2); + end; + end; + end; +end; + +Procedure CheckYeasts(Rec : TRecipe); +var s, s2 : string; + OK : boolean; + i : integer; + Y : TYeast; + am : double; +begin +//check if beerstyle exist in the database. +//If not, check the substitution database, otherwise ask for an alternative + for i:= 0 to Rec.NumYeasts - 1 do + begin + s:= Rec.Yeast[i].Name.Value; + s2:= Rec.Yeast[i].Laboratory.Value; + OK:= (Yeasts.FindByNameAndLaboratory(s, s2) <> NIL); + if (not OK) then + begin + OK:= YeastSubs.OriginalExists(s, s2); + if OK then + begin + YeastSubs.FindSubstitute(s, s2, s, s2); + Y:= TYeast(Yeasts.FindByNameAndLaboratory(s, s2)); + if Y <> NIL then + begin + am:= Rec.Yeast[i].Amount.Value; + Rec.Yeast[i].Assign(Y); + Rec.Yeast[i].Amount.Value:= am; + end + else + YeastSubs.RemoveOriginal(s, s2); + end; + end; + end; +end; + +Procedure Backup; + function CheckCopyFile(sd, dd, fn : string) : boolean; + begin + Result:= false; + if FileExists(sd + fn) then + result:= CopyFile(sd + fn, dd + fn); + end; +var sourcedata, destdata : string; + year, month, day : word; + i : integer; + SearchResult : TSearchRec; + SL : TStringList; +begin + sourcedata:= Settings.DataLocation.Value; + DecodeDate(now, year, month, day); + destdata:= BHFolder + 'backup-' + IntToStr(Year) + '-' + IntToStr(Month) + '-' + + IntToStr(day) + Slash; + CreateDir(destdata); + CheckCopyFile(sourcedata, destdata, 'settings.xml'); + CheckCopyFile(sourcedata, destdata, 'fermentables.xml'); + CheckCopyFile(sourcedata, destdata, 'hops.xml'); + CheckCopyFile(sourcedata, destdata, 'yeasts.xml'); + CheckCopyFile(sourcedata, destdata, 'miscs.xml'); + CheckCopyFile(sourcedata, destdata, 'mashs.xml'); + CheckCopyFile(sourcedata, destdata, 'waters.xml'); + CheckCopyFile(sourcedata, destdata, 'styles.xml'); + CheckCopyFile(sourcedata, destdata, 'equipments.xml'); + CheckCopyFile(sourcedata, destdata, 'recipes.xml'); + CheckCopyFile(sourcedata, destdata, 'brews.xml'); + CheckCopyFile(sourcedata, destdata, 'cloud.xml'); + CheckCopyFile(sourcedata, destdata, 'stylesubs.xml'); + CheckCopyFile(sourcedata, destdata, 'fermentablesubs.xml'); + CheckCopyFile(sourcedata, destdata, 'yeastsubs.xml'); + CheckCopyFile(sourcedata, destdata, 'neuralnetworks.xml'); + SL:= FindAllFiles(sourcedata, '*.nn', false); + for i:= 0 to SL.Count - 1 do + CheckCopyFile(sourcedata, destdata, ExtractFileName(SL.Strings[i])); + FreeAndNIL(SL); + // CheckCopyFile(sourcedata, destdata, 'styles-BJCP.xml'); + // CheckCopyFile(sourcedata, destdata, 'White Labs.xml'); + CheckCopyFile(sourcedata, destdata, 'logo.png'); +end; + +Procedure Restore(sourcedata : string); + function CheckCopyFile(sd, dd, fn : string) : boolean; + begin + Result:= false; + if FileExists(sd + fn) then + result:= CopyFile(sd + fn, dd + fn); + end; +var destdata : string; + year, month, day : word; + i : integer; + SL : TStringList; +begin + destdata:= Settings.DataLocation.Value; + if not DirectoryExists(destdata) then CreateDir(destdata); + CheckCopyFile(sourcedata, destdata, 'settings.xml'); + CheckCopyFile(sourcedata, destdata, 'fermentables.xml'); + CheckCopyFile(sourcedata, destdata, 'hops.xml'); + CheckCopyFile(sourcedata, destdata, 'yeasts.xml'); + CheckCopyFile(sourcedata, destdata, 'miscs.xml'); + CheckCopyFile(sourcedata, destdata, 'mashs.xml'); + CheckCopyFile(sourcedata, destdata, 'waters.xml'); + CheckCopyFile(sourcedata, destdata, 'styles.xml'); + CheckCopyFile(sourcedata, destdata, 'equipments.xml'); + CheckCopyFile(sourcedata, destdata, 'recipes.xml'); + CheckCopyFile(sourcedata, destdata, 'brews.xml'); + CheckCopyFile(sourcedata, destdata, 'cloud.xml'); + CheckCopyFile(sourcedata, destdata, 'stylesubs.xml'); + CheckCopyFile(sourcedata, destdata, 'fermentablesubs.xml'); + CheckCopyFile(sourcedata, destdata, 'yeastsubs.xml'); + CheckCopyFile(sourcedata, destdata, 'neuralnetworks.xml'); + SL:= FindAllFiles(sourcedata, '*.nn', false); + for i:= 0 to SL.Count - 1 do + CheckCopyFile(sourcedata, destdata, ExtractFileName(SL.Strings[i])); + FreeAndNIL(SL); + +// CheckCopyFile(sourcedata, destdata, 'styles-BJCP.xml'); +// CheckCopyFile(sourcedata, destdata, 'White Labs.xml'); + CheckCopyFile(sourcedata, destdata, 'logo.png'); + + Fermentables.ReadXML; + Hops.ReadXML; + Miscs.ReadXML; + Yeasts.ReadXML; + Waters.ReadXML; + Equipments.ReadXML; + Beerstyles.ReadXML; + Mashs.ReadXML; + Application.ProcessMessages; + Recipes.ReadXML; + Application.ProcessMessages; + Brews.ReadXML; +end; + +Procedure CheckDataFolder; + function CheckFile(sd, dd, fn : string) : boolean; + var destOK, sourceOK : boolean; + begin + Result:= false; + destOK:= FileExists(dd + fn); + sourceOK:= FileExists(sd + fn); + if (not destOK) and (sourceOK) then + try + result:= CopyFile(sd + fn, dd + fn); + except + ShowMessage('Fout bij aanmaken ' + dd + fn + '.'); + Halt; + end + else if (not destOK) and (not sourceOK) then + ShowMessage('Fout: ' + sd + fn + ' niet gevonden.'); + end; +var sourcedata, destdata, sourcesounds, destsounds : string; +begin + {$ifdef UNIX} + sourcedata:= '/usr/share/brewbuddy/'; + {$endif} + {$ifdef darwin} + sourcedata:= '/usr/share/brewbuddy/'; + {$endif} + {$ifdef Windows} + sourcedata:= ExtractFilePath(Application.ExeName) + 'brewbuddy\'; + if OnUSB then BHFolder:= DriveLetter + '\brewbuddy\brewbuddy\'; + log('Checkdatafolder: BHFolder = ' + BHFolder); + {$endif} + destdata:= BHFolder; + if not DirectoryExists(BHFolder) then + CreateDir(BHFolder); + if not DirectoryExists(SoundFolder) then + CreateDir(SoundFolder); + sourcesounds:= sourcedata + 'sounds' + Slash; + destsounds:= SoundFolder; + Settings := TBSettings.Create; + if CheckFile(sourcedata, destdata, 'settings.xml') then + begin + Settings.DataLocation.Value:= BHFolder; + end + else + Settings.Read; + log('Settings.Datalocation = ' + Settings.DataLocation.Value); + + IF OnUSB then + begin + Settings.DataLocation.Value:= BHFolder; + destdata:= BHFolder; + end + else if (Settings.DataLocation.Value <> '') and (not OnUSB) then + destdata:= Settings.DataLocation.Value + else + destdata:= BHFolder; + log('Settings.Datalocation = ' + Settings.DataLocation.Value); + if not DirectoryExists(destdata) then + CreateDir(destdata); + + if CheckFile(sourcedata, destdata, 'equipments.xml') then + ShowMessage('Data niet gevonden. Nieuwe databank wordt gemaakt.'); + CheckFile(sourcedata, destdata, 'fermentables.xml'); + CheckFile(sourcedata, destdata, 'hops.xml'); + CheckFile(sourcedata, destdata, 'mashs.xml'); + CheckFile(sourcedata, destdata, 'miscs.xml'); + CheckFile(sourcedata, destdata, 'recipes.xml'); + CheckFile(sourcedata, destdata, 'styles-BJCP.xml'); + CheckFile(sourcedata, destdata, 'styles.xml'); + CheckFile(sourcedata, destdata, 'waters.xml'); +// CheckFile(sourcedata, destdata, 'White Labs.xml'); + CheckFile(sourcedata, destdata, 'yeasts.xml'); + CheckFile(sourcedata, destdata, 'logo.png'); + {$ifdef Windows} + CheckFile(sourcedata, destdata, 'Introductie BrewBuddy Sassy Saison.pdf'); + {$endif} + {$ifdef Darwin} + CheckFile(sourcedata, destdata, 'Introductie BrewBuddy Sassy Saison.pdf'); + {$endif} + {$ifdef linux} + CheckFile('/usr/share/doc/brewbuddy/', destdata, 'Introductie BrewBuddy Sassy Saison.pdf'); + {$endif} + CheckFile(sourcesounds, destsounds, 'alarm.wav'); +// CheckFile(sourcesounds, destsounds, 'alarm02.wav'); + CheckFile(sourcesounds, destsounds, 'end.wav'); + CheckFile(sourcesounds, destsounds, 'warning.wav'); + CheckFile(sourcesounds, destsounds, 'welcome.wav'); +end; + +Procedure Reload; +begin + Fermentables.Free; + Hops.Free; + Miscs.Free; + Yeasts.Free; + Waters.Free; + Equipments.Free; + Beerstyles.Free; + Mashs.Free; + Recipes.Free; + Brews.Free; + Settings.Free; + Settings := TBSettings.Create; + Settings.Read; + + CheckDataFolder; + + Fermentables:= TFermentables.Create; + Hops:= THops.Create; + Miscs:= TMiscs.Create; + Yeasts:= TYeasts.Create; + Waters:= TWaters.Create; + Equipments:= TEquipments.Create; + Beerstyles:= TBeerstyles.Create; + Mashs:= TMashs.Create; + Recipes:= TRecipes.Create; + + Brews:= TRecipes.Create; + Brews.FileName:= 'brews.xml'; + + loc:= Settings.DataLocation.Value; + if (loc = '') or OnUSB then loc:= BHFolder; + if InitializeHD('fermentables.xml', loc) then + begin + Settings.DataLocation.Value:= loc; + Fermentables.ReadXML; + Hops.ReadXML; + Miscs.ReadXML; + Yeasts.ReadXML; + Waters.ReadXML; + Equipments.ReadXML; + Beerstyles.ReadXML; + Mashs.ReadXML; + Application.ProcessMessages; + Recipes.ReadXML; + Recipes.CheckAutoNrs; + Application.ProcessMessages; + Brews.ReadXML; + Brews.CheckAutoNrs; + + CheckSalts; + end + else + ShowMessage('Databestanden niet gevonden'); +end; + +Procedure ChangeDatabaseLocation(source, destination : string; copy, deleteold : boolean); + function CheckCopyFile(sd, dd, fn : string) : boolean; + begin + Result:= false; + if FileExists(sd + fn) then + result:= CopyFile(sd + fn, dd + fn); + end; +var SearchResult : TSearchRec; + i : integer; + SL : TStringList; + StylesN, FermN, HopN, MiscN, YeastN, WaterN, sourcedata : string; +begin + {$ifdef UNIX} + destination:= destination + '/'; + {$else} + destination:= destination + '\'; + {$endif} + Settings.DataLocation.Value:= destination; + + if not copy then + begin + StylesN:= destination + 'styles.xml'; + FermN:= destination + 'fermentables.xml'; + HopN:= destination + 'hops.xml'; + MiscN:= destination + 'miscs.xml'; + YeastN:= destination + 'yeasts.xml'; + WaterN:= destination + 'waters.xml'; + if FileExists(StylesN) and FileExists(FermN) and FileExists(HopN) and + FileExists(MiscN) and FileExists(YeastN) and FileExists(WaterN) then + begin + Brews.ReadXML; + Equipments.ReadXML; + Fermentables.ReadXML; + Hops.ReadXML; + Mashs.ReadXML; + Miscs.ReadXML; + Recipes.ReadXML; + Beerstyles.ReadXML; + Waters.ReadXML; + Yeasts.ReadXML; + StyleSubs.ReadXML; + FermentableSubs.ReadXML; + YeastSubs.ReadXML; + BHNNs.ReadXML; + end + else //copy previous database to new location, but clear brews + begin + {$ifdef UNIX} + sourcedata:= '/usr/share/brewbuddy/'; + {$endif} + {$ifdef darwin} + sourcedata:= '/usr/share/brewbuddy/'; + {$endif} + {$ifdef Windows} + sourcedata:= ExtractFilePath(Application.ExeName) + 'brewbuddy\'; + if OnUSB then BHFolder:= DriveLetter + '\brewbuddy\brewbuddy\' + else BHFolder:= destination; + {$endif} + + Equipments.SaveXML; + Fermentables.SaveXML; + Hops.SaveXML; + Mashs.SaveXML; + Miscs.SaveXML; + Recipes.SaveXML; + Beerstyles.SaveXML; + Waters.SaveXML; + Yeasts.SaveXML; + StyleSubs.SaveXML; + FermentableSubs.SaveXML; + YeastSubs.SaveXML; + BHNNs.SaveXML; + SL:= FindAllFiles(source, '*.nn', false); + for i:= 0 to SL.Count - 1 do + CheckCopyFile(source, destination, ExtractFileName(SL.Strings[i])); + FreeAndNIL(SL); + Brews.FreeCollection; + CheckCopyFile(source, destination, 'Introductie BrewBuddy Sassy Saison.pdf'); + CheckCopyFile(source, destination, 'styles-BJCP.xml'); + CheckCopyFile(source, destination, 'logo.png'); + CheckDataFolder; + end; + + //delete files in old directory + if deleteold then + begin + DeleteFile(PChar(source + 'brews.xml')); + DeleteFile(PChar(source + 'equipments.xml')); + DeleteFile(PChar(source + 'fermentables.xml')); + DeleteFile(PChar(source + 'hops.xml')); + DeleteFile(PChar(source + 'mashs.xml')); + DeleteFile(PChar(source + 'miscs.xml')); + DeleteFile(PChar(source + 'recipes.xml')); + DeleteFile(PChar(source + 'styles.xml')); + DeleteFile(PChar(source + 'waters.xml')); + DeleteFile(PChar(source + 'yeasts.xml')); + DeleteFile(PChar(source + 'stylesubs.xml')); + DeleteFile(PChar(source + 'fermentablesubs.xml')); + DeleteFile(PChar(source + 'yeastsubs.xml')); + DeleteFile(PChar(source + 'neuralnetworks.xml')); + SL:= FindAllFiles(source, '*.nn', false); + for i:= 0 to SL.Count - 1 do + DeleteFile(PChar(SL.Strings[i])); + FreeAndNIL(SL); + DeleteFile(PChar(source + 'Introductie BrewBuddy Sassy Saison.pdf')); + DeleteFile(PChar(source + 'styles-BJCP.xml')); + DeleteFile(PChar(source + 'logo.png')); + end; + FrmMain.cbBrewsSortChange(FrmMain); + FrmMain.cbRecipesSortChange(FrmMain); + end + else //copy from old directory and overwrite files in new directory + begin + Brews.SaveXML; + Equipments.SaveXML; + Fermentables.SaveXML; + Hops.SaveXML; + Mashs.SaveXML; + Miscs.SaveXML; + Recipes.SaveXML; + Beerstyles.SaveXML; + Waters.SaveXML; + Yeasts.SaveXML; + StyleSubs.SaveXML; + FermentableSubs.SaveXML; + YeastSubs.SaveXML; + BHNNs.SaveXML; + SL:= FindAllFiles(source, '*.nn', false); + for i:= 0 to SL.Count - 1 do + CheckCopyFile(source, destination, ExtractFileName(SL.Strings[i])); + FreeAndNIL(SL); + + //delete files in old directory + if deleteold then + begin + DeleteFile(PChar(source + 'brews.xml')); + DeleteFile(PChar(source + 'equipments.xml')); + DeleteFile(PChar(source + 'fermentables.xml')); + DeleteFile(PChar(source + 'hops.xml')); + DeleteFile(PChar(source + 'mashs.xml')); + DeleteFile(PChar(source + 'miscs.xml')); + DeleteFile(PChar(source + 'recipes.xml')); + DeleteFile(PChar(source + 'styles.xml')); + DeleteFile(PChar(source + 'waters.xml')); + DeleteFile(PChar(source + 'yeasts.xml')); + DeleteFile(PChar(source + 'stylesubs.xml')); + DeleteFile(PChar(source + 'fermentablesubs.xml')); + DeleteFile(PChar(source + 'yeastsubs.xml')); + DeleteFile(PChar(source + 'neuralnetworks.xml')); + SL:= FindAllFiles(source, '*.nn', false); + for i:= 0 to SL.Count - 1 do + DeleteFile(PChar(SL.Strings[i])); + FreeAndNIL(SL); + end; + end; + Settings.Save; +end; + +{====================== Initialization and Finalization =======================} + +Initialization + if DoLog then slLog:= TStringList.Create + else slLog:= NIL; + Screen.Cursor:= crHourglass; + + ExecFolder:= Application.Location; + log('ExecFolder = ' + ExecFolder); + OnUSB:= false; + {$ifdef UNIX} + {DriveLetter:= LeftStr(ExecFolder, 6); + if DriveLetter = '/media' then + begin + BHFolder:= ExecFolder; + end + else + begin} + BHFolder:= GetUserDir + '.brewbuddy/'; + // DataFolder:= GetUserDir + '.brewbuddy/'; + { end;} + SoundFolder:= BHFolder + 'sounds/'; + IconFolder:= BHFolder + 'icons/'; + Slash:= '/'; + {$endif} + {$ifdef darwin} + BHFolder:= GetUserDir + '.brewbuddy/'; +// DataFolder:= GetUserDir + '.brewbuddy/'; + SoundFolder:= BHFolder + 'sounds/'; + IconFolder:= BHFolder + 'icons/'; + Slash:= '/'; + {$endif} + {$ifdef windows} + DriveLetter:= LeftStr(ExecFolder, 2); + if GetDriveType(PChar(DriveLetter)) = DRIVE_REMOVABLE then + begin + Log('Gestart van USB'); + BHFolder:= DriveLetter + '\brewbuddy\brewbuddy\'; + OnUSB:= TRUE; + end + else + begin + Log('Gestart van harddisk'); + BHFolder:= GetWindowsSpecialDir(CSIDL_PERSONAL); //GetUserDir + if FileExists(BHFolder + 'My Documents\brewbuddy\settings.xml') then + BHFolder:= BHFolder + 'My Documents\brewbuddy\' + else + BHFolder:= BHFolder + 'brewbuddy\'; + end; + log('BHFolder = ' + BHFolder); + SoundFolder:= BHFolder + 'sounds\'; + IconFolder:= BHFolder + 'icons\'; + Slash:= '\'; + {$endif} + + CheckDataFolder; //settings are read here + + Fermentables:= TFermentables.Create; + Hops:= THops.Create; + Miscs:= TMiscs.Create; + Yeasts:= TYeasts.Create; + Waters:= TWaters.Create; + Equipments:= TEquipments.Create; + Beerstyles:= TBeerstyles.Create; + Mashs:= TMashs.Create; + Recipes:= TRecipes.Create; + + Brews:= TRecipes.Create; + Brews.FileName:= 'brews.xml'; + + BHNNs:= TBHNNs.Create; + + loc:= Settings.DataLocation.Value; + if loc = '' then loc:= BHFolder; + if OnUSB then //datalocation is also on the USB + loc:= BHFolder; + if InitializeHD('fermentables.xml', loc) then + begin + if not OnUSB then Settings.DataLocation.Value:= loc; + + BHCloud:= TBHCloud.Create; +// BHCloud.ReadCloud; + + Fermentables.ReadXML; + Hops.ReadXML; + Miscs.ReadXML; + Yeasts.ReadXML; + Waters.ReadXML; + Equipments.ReadXML; + Beerstyles.ReadXML; + Mashs.ReadXML; + Application.ProcessMessages; + Recipes.ReadXML; + Recipes.CheckAutoNrs; + Application.ProcessMessages; + Brews.ReadXML; + Brews.CheckAutoNrs; + + StyleSubs.ReadXML; + FermentableSubs.ReadXML; + YeastSubs.ReadXML; + + BHNNs.ReadXML; + + CheckSalts; + end + else + ShowMessage('Databestanden niet gevonden'); +// Equipments.CalcEfficiencyRegressionFactors; +// Equipments.CalcAttenuationRegressionFactors; + + { SetLength(Arr, 8); + Arr[0]:= 4; + Arr[1]:= 56; + Arr[2]:= 45; + Arr[3]:= 19; + Arr[4]:= 22; + Arr[5]:= 23; + Arr[6]:= 9; + Arr[7]:= 11; + Brews.ExportToCSV(Arr); + SetLength(Arr, 0);} + + Screen.Cursor:= crDefault; + +Finalization + if OnUSB then + begin + Settings.DataLocation.Value:= ''; + Settings.Save; + end; + Log(''); +// Log('CONTAINERS'); + FreeAndNIL(BHCloud); +// Log('BHCloud afgesloten'); + StyleSubs.SaveXML; +// Log('StyleSubs opgeslagen'); + FermentableSubs.SaveXML; +// Log('FermentableSubs opgeslagen'); + YeastSubs.SaveXML; +// Log('YeastSubs opgeslagen'); + FreeAndNIL(StyleSubs); +// Log('StyleSubs afgesloten'); + FreeAndNIL(FermentableSubs); +// Log('FermentableSubs afgesloten'); + FreeAndNIL(YeastSubs); +// Log('YeastSubs afgesloten'); + + FreeAndNIL(Fermentables); +// Log('Fermentables afgesloten'); + FreeAndNIL(Hops); +// Log('Hops afgesloten'); + FreeAndNIL(Miscs); +// Log('Miscs afgesloten'); + FreeAndNIL(Yeasts); +// Log('Yeasts afgesloten'); + FreeAndNIL(Waters); +// Log('Waters afgesloten'); + FreeAndNIL(Equipments); +// Log('Equipments afgesloten'); + FreeAndNIL(Beerstyles); +// Log('Beerstyles afgesloten'); + FreeAndNIL(Mashs); +// Log('Mashs afgesloten'); + FreeAndNIL(Recipes); +// Log('Recipes afgesloten'); + FreeAndNIL(Brews); +// Log('Brews afgesloten'); + FreeAndNIL(BHNNs); +// Log('BHNNs afgesloten'); + + Settings.Save; + Log('Settings opgeslagen'); + FreeAndNIL(Settings); +// Log('Settings afgesloten'); + + if DoLog then FreeAndNIL(slLog); +end. + diff --git a/Source/Units/backup/bh_report.pas b/Source/Units/backup/bh_report.pas new file mode 100644 index 00000000..ae2cec49 --- /dev/null +++ b/Source/Units/backup/bh_report.pas @@ -0,0 +1,2464 @@ +unit BH_report; + +{$mode objfpc}{$H+} + +interface + +uses + Classes, SysUtils, Graphics, ExtCtrls, Printers, Types, TAGraph; + +type + TBHRDocument = class; + + TBHRElement = class(TObject) + Constructor Create(D : TBHRDocument); virtual; + Destructor Destroy; override; + private + FDocument : TBHRDocument; + FRect : TRect; + FPageNrS, FPageNrE, FMinHeight : integer; + FKeepWithNext : boolean; + FKeepTogether : boolean; + FPrior, FNext : TBHRElement; + Procedure SetRect(R : TRect); + Function GetLeft : word; + Function GetRight : word; + Function GetTop : word; + Function GetBottom : word; + Function GetMinHeight : word; + Procedure SetLeft(l : word); virtual; + Procedure SetRight(r : word); virtual; + procedure SetTop(t : word); virtual; + Procedure SetBottom(b : word); virtual; + procedure SetMinHeight(h : word); virtual; + Procedure SetNext(E : TBHRElement); virtual; + Procedure SetPrior(E : TBHRElement); virtual; + Procedure SetPageNrS(i : integer); virtual; + Procedure SetPageNrE(i : integer); virtual; + Procedure SetKeepTogether(b : boolean); virtual; + protected + Procedure DeployKeepWithNext; virtual; + Procedure Move(PNr, Tp : word); virtual; + public + Procedure Draw(Cnvs : TCanvas; Pnr : integer; Scale : single); virtual; + Procedure CalcRect; virtual; + property Rect : TRect read FRect write SetRect; + property Left : word read GetLeft write SetLeft; + property Right : word read GetRight write SetRight; + property Top : word read GetTop write SetTop; + property Bottom : word read GetBottom write SetBottom; + property MinHeight : word read GetMinHeight write SetMinHeight; + property PageNrS : integer read FPageNrS write SetPageNrS; + property PageNrE : integer read FPageNrE write SetPageNrE; + property KeepWithNext : boolean read FKeepWithNext write FKeepWithNext; + property KeepTogether : boolean read FKeepTogether write SetKeepTogether; + property Next : TBHRElement read FNext write SetNext; + property Prior : TBHRElement read FPrior write SetPrior; + published + end; + + TBHRImage = class(TBHRElement) + Constructor Create(D : TBHRDocument); override; + Destructor Destroy; override; + private + FPicture : TPicture; + FStretch : boolean; + protected + public + Procedure Draw(Cnvs : TCanvas; Pnr : integer; Scale : single); override; + Procedure CalcRect; override; + published + property Picture : TPicture read FPicture; + property Stretch : boolean read FStretch write FStretch; + end; + + { TBHRBHGraph = class(TBHRElement) + Constructor Create(D : TBHRDocument); override; + Destructor Destroy; override; + private + FGraph : TBHGraph; + FStretch : boolean; + protected + public + Procedure Draw(Cnvs : TCanvas; Pnr : integer; Scale : single); override; + Procedure CalcRect; override; + published + property Graph : TBHGraph read FGraph write FGraph; + property Stretch : boolean read FStretch write FStretch; + end; } + + TBHRChart = class(TBHRElement) + Constructor Create(D : TBHRDocument); override; + Destructor Destroy; override; + private + FChart : TChart; + FStretch : boolean; + protected + public + Procedure Draw(Cnvs : TCanvas; Pnr : integer; Scale : single); override; + Procedure CalcRect; override; + published + property Chart : TChart read FChart write FChart; + property Stretch : boolean read FStretch write FStretch; + end; + + TBHRText = class; + TBHRCell = class; + + TBHRTable = class(TBHRElement) + Constructor Create(D : TBHRDocument); override; + Destructor Destroy; override; + private + FCells : array of array of TBHRCell; + FAutoSizeCells : boolean; + FColsEven : boolean; + Function GetRowColor(i : word) : TColor; + Procedure SetRowColor(i : word; cl : TColor); + Function GetColColor(i : word) : TColor; + Procedure SetColColor(i : word; cl : TColor); + Procedure SetPageNrS(i : integer); override; + Procedure SetPageNrE(i : integer); override; + Procedure SetAutoSizeCells(b : boolean); + Procedure SetKeepTogether(b : boolean); override; + protected + Procedure Move(PNr, Tp : word); override; + public + Function GetCell(aRow, aCol : integer) : TBHRCell; + Function NumRows : integer; + Function NumCols : integer; + Function GetColWidth(aCol : integer) : word; + Procedure SetColWidth(aCol : integer; Width : word); + Procedure SetColsEven(b : boolean); + Function GetRowHeight(aRow : integer) : word; + Procedure SetRowHeight(ARow : integer; Height : word); + Procedure AddRow; + Procedure AddCol; + Procedure SetSize(NRows, NCols : integer); + Procedure Draw(Cnvs : TCanvas; Pnr : integer; Scale : single); override; + Procedure CalcRect; override; + property Cells[ARow, ACol: integer] : TBHRCell read GetCell; + property ColWidth[ACol : integer] : word read GetColWidth write SetColWidth; + property RowHeight[ARow : integer] : word read GetRowHeight write SetRowHeight; + property RowColor[i : word] : TColor read GetRowColor write SetRowColor; + property ColColor[i : word] : TColor read GetColColor write SetColColor; + published + property AutoSizeCells : boolean read FAutoSizeCells write SetAutoSizeCells; + property ColsEven : boolean read FColsEven write SetColsEven; + end; + + TBHRCell = class(TBHRElement) + Constructor Create(D : TBHRDocument; R, C : integer); + Destructor Destroy; override; + private + FText : TBHRText; + FTable : TBHRTable; + FRow, FColumn : integer; + Procedure SetLeft(l : word); override; + Procedure SetRight(r : word); override; + procedure SetTop(t : word); override; + Procedure SetBottom(b : word); override; + Function GetFont : TFont; + Function GetBrush : TBrush; + Function GetPen : TPen; + Function GetAlignment : TAlignment; + Procedure SetAlignment(al : TAlignment); + Function GetKeepTogether : boolean; + Function GetMarge : word; + Procedure SetMarge(w : word); + Function GetAutoSize : boolean; + Procedure SetAutoSize(b : boolean); + Procedure SetKeepTogether(b : boolean); override; + Procedure SetNext(E : TBHRElement); override; + Procedure SetPrior(E : TBHRElement); override; + Function GetCheckBoxes : boolean; + Procedure SetCheckBoxes(b : boolean); + Function GetCheckBoxSize : LongInt; + Procedure SetCheckBoxSize(L : LongInt); + Procedure SetPageNrS(i : integer); override; + Procedure SetPageNrE(i : integer); override; + protected + Procedure Move(PNr, Tp : word); override; + public + Procedure Draw(Cnvs : TCanvas; Pnr : integer; Scale : single); override; + Procedure CalcRect; override; + published + Property Content : TBHRText read FText; + property Row : integer read FRow write FRow; + property Column : integer read FColumn write FColumn; + property Font : TFont read GetFont; + property Brush : TBrush read GetBrush; + property Pen : TPen read GetPen; + property Alignment : TAlignment read GetAlignment write SetAlignment; + property KeepTogether : boolean read GetKeepTogether write SetKeepTogether; + property Marge : word read GetMarge write SetMarge; + property AutoSize : boolean read GetAutoSize write SetAutoSize; + property CheckBoxes : boolean read GetCheckBoxes write SetCheckBoxes; + property CheckBoxSize : LongInt read GetCheckBoxSize write SetCheckBoxSize; + property Table : TBHRTable read FTable write FTable; + end; + + TWhere = (twAbove, twBelow); + TLineProps = record + Rect : TRect; + PageNr : integer; + TextRect : TRect; + end; + + TBHRText = class(TBHRElement) + Constructor Create(D : TBHRDocument); override; + Destructor Destroy; override; + private + FCell : TBHRCell; + FStrings : TStringList; + FFont : TFont; + FBrush : TBrush; + FPen : TPen; + FAlignment : TAlignment; + FLineProps : Array of TLineProps; + FMarge : word; + FAutoSize : boolean; + FCheckBoxes : boolean; + FChecked : boolean; + FCheckBoxSize : Longint; + FFontHeight : integer; + Function GetString(i : integer) : string; + Procedure SetString(i : integer; s : string); + Procedure SetMarge(w : word); + protected + Procedure Move(PNr, Tp : word); override; + public + Procedure Draw(Cnvs : TCanvas; Pnr : integer; Scale : single); override; + Procedure CalcRect; override; + Procedure AddString(s : string); + Procedure RemoveString(i : integer); + Procedure InsertString(s : string; i : integer; Where : TWhere); + property Line[i : integer] : string read GetString write SetString; + published + property Cell : TBHRCell read FCell write FCell; + property Font : TFont read FFont; + property Brush : TBrush read FBrush; + property Pen : TPen read FPen; + property Alignment : TAlignment read FAlignment write FAlignment; + property Marge : word read FMarge write SetMarge; + property AutoSize : boolean read FAutoSize write FAutoSize; + property CheckBoxes : boolean read FCheckBoxes write FCheckBoxes; + property Checked : boolean read FChecked write FChecked; + property CheckBoxSize : LongInt read FCheckBoxSize write FCheckBoxSize; + end; + + THeaderType = (thHeader, thFooter); + + TBHRHeader = class(TBHRElement) + Constructor Create(D : TBHRDocument; HT : THeaderType); + Destructor Destroy; override; + private + FPicture : TPicture; + FPictRect, FTxtRect : TRect; + FText : string; + FHeight : LongInt; + FHeaderType : THeaderType; + FFont : TFont; + FFontHeight : integer; + FBrush : TBrush; + FPen : TPen; + FAlignment : TAlignment; + FMarge : word; + Procedure SetPictRect(R : TRect); + Function GetPictRect : TRect; + Procedure SetTxtRect(R : TRect); + Function GetTxtRect : TRect; + Procedure SetHeight(H : LongInt); + Procedure SetText(S : string); + protected + public + Procedure Draw(Cnvs : TCanvas; Pnr : integer; Scale : single); override; + Procedure CalcRect; override; + property PictRect : TRect read GetPictRect write SetPictRect; + property TxtRect : TRect read GetPictRect write SetPictRect; + published + property Picture : TPicture read FPicture; + property Height : LongInt read FHeight write SetHeight; + property Text : string read FText write SetText; + property Font : TFont read FFont; + property Brush : TBrush read FBrush; + property Pen : TPen read FPen; + property Alignment : TAlignment read FAlignment write FAlignment; + property Marge : word read FMarge write FMarge; + end; + + TBHRDocument = class(TObject) + Constructor Create; + Destructor Destroy; override; + private + FHeader : TBHRHeader; + FFooter : TBHRHeader; + FNumPages : word; + FElements : array of TBHRElement; + FPageRect, FPrintRect : TRect; + FMarginBT : single; + FMarginLR : single; + FMarginBTpx : integer; + FMarginLRpx : integer; + FLastY : word; + FLastPage : word; + Procedure GetPrinterProps; + Function GetNumElements : integer; + Procedure CalcRects; + Function GetElement(i : integer) : TBHRElement; + protected + public + Procedure AddPage; + Procedure RemovePage; + Function AddText(Rect : TRect; s : string) : TBHRText; + Function AddTable(Rect : TRect; nCol, nRow : integer) : TBHRTable; + Function AddImage(Rect : TRect) : TBHRImage; +// Function AddGraph(Rect : TRect) : TBHRBHGraph; + Function AddChart(Rect : TRect) : TBHRChart; + Function AddSpace(Rect : TRect; h : word) : TBHRElement; + Procedure Print(FromPage, ToPage, Copies : integer); + Procedure PrintPreview; + Procedure DrawPages(cnvs : TCanvas; Scale : single); + Procedure DrawPage(cnvs : TCanvas; PageNr : integer; Scale : single); + Procedure Repaginate; + Function GetLineHeight(fh : integer) : integer; + property Element[i : integer] : TBHRElement read GetElement; + property Header : TBHRHeader read FHeader; + property Footer : TBHRHeader read FFooter; + property PageRect : TRect read FPageRect; + property PrintRect : TRect read FPrintRect; + published + property MarginBT : single read FMarginBT write FMarginBT; + property MarginLR : single read FMarginLR write FMarginLR; + property NumElements : integer read GetNumElements; + property NumPages : word read FNumPages; + property LastY : word read FLastY; + end; + +implementation + +uses frmain, HulpFuncties, frprintpreview, StrUtils, TASeries, Controls; + +Function CmToPixX(cm : single) : word; +begin + if Printer <> NIL then Result:= round(cm / 2.54 * Printer.XDPI) + else Result:= round(cm / 2.54 * 600); +end; + +Function CmToPixY(cm : single) : word; +begin + if Printer <> NIL then Result:= round(cm / 2.54 * Printer.YDPI) + else Result:= round(cm / 2.54 * 600); +end; + +Function FontSizeToPix(sz, scale : single) : word; +var dpy : integer; +begin + if Printer <> NIL then dpy:= Printer.YDPI + else dpy:= 600; + if abs(sz) < 40 then Result:= round(scale * abs(sz) / 72 * dpy) + else Result:= round(scale * 8 / 72 * dpy); +end; + +Function ScaleRect(R : TRect; scale : single) : TRect; +begin + Result.Left:= round(scale * R.Left); + Result.Right:= round(scale * R.Right); + Result.Top:= round(scale * R.Top); + Result.Bottom:= round(scale * R.Bottom); +end; + +Constructor TBHRElement.Create(D : TBHRDocument); +begin + Inherited Create; + FDocument:= D; + FRect.Bottom:= 0; + FRect.Top:= 0; + FRect.Left:= 0; + FRect.Right:= 0; + FPageNrS:= FDocument.NumPages; + FPageNrE:= FDocument.NumPages; + FKeepWithNext:= false; + FKeepTogether:= TRUE; + FNext:= NIL; + FPrior:= NIL; +end; + +Destructor TBHRElement.Destroy; +begin + Inherited Destroy; +end; + +Procedure TBHRElement.Draw(Cnvs : TCanvas; Pnr : integer; Scale : single); +begin +end; + +Procedure TBHRElement.SetRect(R : TRect); +begin + FRect.Left:= R.Left; + FRect.Right:= R.Right; + FRect.Top:= R.Top; + FRect.Bottom:= R.Bottom; +end; + +Function TBHRElement.GetLeft : word; +begin + Result:= FRect.Left; +end; + +Procedure TBHRElement.SetLeft(l : word); +begin + FRect.Left:= l; +end; + +Function TBHRElement.GetRight : word; +begin + Result:= FRect.Right; +end; + +Procedure TBHRElement.SetRight(r : word); +begin + FRect.Right:= r; +end; + +Function TBHRElement.GetTop : word; +begin + Result:= FRect.Top; +end; + +procedure TBHRElement.SetTop(t : word); +begin + FRect.Top:= t; +end; + +Function TBHRElement.GetBottom : word; +begin + Result:= FRect.Bottom; +end; + +Procedure TBHRElement.SetBottom(b : word); +begin + FRect.Bottom:= b; +end; + +Procedure TBHRElement.SetKeepTogether(b : boolean); +begin + if FKeepTogether <> b then + begin + FKeepTogether:= b; + end; +end; + +Function TBHRElement.GetMinHeight : word; +begin + Result:= FMinHeight; +end; + +Procedure TBHRElement.SetMinHeight(h : word); +begin + FMinHeight:= h; +end; + +Procedure TBHRElement.SetNext(E : TBHRElement); +begin + FNext:= E; +end; + +Procedure TBHRElement.SetPrior(E : TBHRElement); +begin + FPrior:= E; +end; + +Procedure TBHRElement.SetPageNrS(i : integer); +begin + if (i > 0) {and (i <= FDocument.NumPages)} then + begin + FPageNrS:= i; + if FPageNrE < FPageNrS then + FPageNrE:= FPageNrS; + end; +end; + +Procedure TBHRElement.SetPageNrE(i : integer); +begin + if (i > 0) {and (i <= FDocument.NumPages)} then + begin + FPageNrE:= i; + if FPageNrE < FPageNrS then + FPageNrS:= FPageNrE; + end; +end; + +Procedure TBHRElement.Move(PNr, Tp : word); +var h : word; + i, j : integer; +begin + j:= 0; + if FPageNrE > FPageNrS then + begin + h:= FDocument.PrintRect.Bottom - FRect.Top; + for i:= 1 to (FPageNrE - FPageNrS - 1) do + begin + Inc(j); + h:= h + FDocument.PrintRect.Bottom - FDocument.PrintRect.Top; + end; + Inc(j); + h:= FRect.Bottom - FDocument.PrintRect.Top; + end + else + h:= FRect.Bottom - FRect.Top; + FRect.Top:= tp; + FPageNrS:= PNr; + FPageNrE:= FPageNrS + j; + while h > 0 do + begin + FRect.Bottom:= tp + h; + if FRect.Bottom > FDocument.PrintRect.Bottom then + begin + h:= h - (FDocument.PrintRect.Bottom - FDocument.PrintRect.Top); + tp:= FDocument.PrintRect.Top; + end + else + begin + h:= 0; + end; + end; +end; + +Procedure TBHRElement.CalcRect; +begin + if FPrior <> NIL then + begin + Top:= FPrior.Bottom; + FPageNrS:= FPrior.PageNrE; + end + else + begin + //Top:= FDocument.FPrintRect.Top; + //FPageNrS:= 1; + end; + FPageNRE:= FPageNRS; + Bottom:= Top + FMinHeight; +end; + +Procedure TBHRElement.DeployKeepWithNext; +var E : TBHRElement; + PNr, Tp : word; +begin + if FPrior <> NIL then + begin + if (FPrior.KeepWithNext) and (FPageNRS > FPrior.PageNrE) then + begin + E:= FPrior; + While (E.Prior <> NIL) and E.Prior.KeepWithNext do + E:= E.Prior; + Tp:= FDocument.PrintRect.Top; + PNr:= E.PageNrS + 1; + While E <> self.Next do + begin + E.Move(PNr, Tp); + PNr:= E.PageNrE; + Tp:= E.Bottom; + E:= E.Next; + end; + end; + end; +end; + +{========================== TBHRHeader =======================================} + +Constructor TBHRHeader.Create(D : TBHRDocument; HT : THeaderType); +begin + Inherited Create(D); + FHeaderType:= HT; + FText:= ''; + FPicture := TPicture.Create; + FFont := TFont.Create; + with FFont do + begin +// CharSet:= DEFAULT_CHARSET; + Color:= clBlack; + Size:= 14; +// Name:= default; + Orientation:= 0; + Pitch:= fpDefault; + Quality:= fqDefault; //fqAntiAliased + Style:= []; + end; + FBrush:= TBrush.Create; + with FBrush do + begin + Color:= clWhite; + Style:= bsSolid; + end; + FPen:= TPen.Create; + with FPen do + begin + Color:= clBlack; + Style:= psSolid; + Width:= 1; + end; + FMarge:= CmToPixY(0.2); + + if FHeaderType = thHeader then + begin + FRect.Top:= FMarge; + FRect.Left:= FMarge; + FRect.Right:= FDocument.PageRect.Right - FMarge; + FRect.Bottom:= FDocument.PrintRect.Top; + FPictRect.Top:= FRect.Top + FMarge; + FPictRect.Bottom:= FRect.Bottom - FMarge; + FPictRect.Left:= 0; + FPictRect.Right:= 0; + FAlignment:= taCenter; + end + else + begin + FRect.Top:= FDocument.PrintRect.Bottom + FMarge; + FRect.Left:= FMarge; + FRect.Right:= FDocument.PageRect.Right - FMarge; + FRect.Bottom:= FDocument.PageRect.Bottom - FMarge; + FPictRect.Top:= FRect.Top + 5; + FPictRect.Bottom:= FRect.Bottom - 5; + FPictRect.Left:= 0; + FPictRect.Right:= 0; + FAlignment:= taRightJustify; + end; + FHeight:= FRect.Bottom - FRect.Top; +end; + +Destructor TBHRHeader.Destroy; +begin + FPicture.Free; + FFont.Free; + FBrush.Free; + FPen.Free; + Inherited; +end; + +Procedure TBHRHeader.SetPictRect(R : TRect); +begin + FPictRect:= R; +end; + +Function TBHRHeader.GetPictRect : TRect; +begin + Result:= FPictRect; +end; + +Procedure TBHRHeader.SetTxtRect(R : TRect); +begin + FTxtRect:= R; +end; + +Function TBHRHeader.GetTxtRect : TRect; +begin + Result:= FTxtRect; +end; + +Procedure TBHRHeader.SetText(S : string); +begin + FText:= S; +end; + +Procedure TBHRHeader.SetHeight(H : LongInt); +begin + if (FHeight <> H) and (H >= 0) and + (H < round(0.1 * (FDocument.PageRect.Bottom - FDocument.PageRect.Top))) then + begin + FHeight:= H; + if FHeaderType = thHeader then + FDocument.FPrintRect.Top:= FDocument.PageRect.Top + FHeight + else + FDocument.FPrintRect.Bottom:= FDocument.PageRect.Bottom - FHeight; + CalcRect; + end; +end; + +Procedure TBHRHeader.Draw(Cnvs : TCanvas; Pnr : integer; Scale : single); +var R, SRect : TRect; + mh, FH : LongInt; +begin + //Draw the picture + if (not FPicture.Bitmap.Empty) or (not FPicture.Graphic.Empty) or (not FPicture.Jpeg.Empty) + or (not FPicture.PNG.Empty) or (not FPicture.PNM.Empty) or (not FPicture.Pixmap.Empty) then + begin + R.Left:= 0; + R.Top:= 0; + R.Right:= FPicture.Width; + R.Bottom:= FPicture.Height; + SRect:= ScaleRect(FPictRect, Scale); + + cnvs.Pen.Style:= psClear; + cnvs.Brush.Color:= clWhite; + cnvs.Rectangle(FPictRect); + cnvs.CopyMode:= cmSrcCopy; + cnvs.CopyRect(SRect, FPicture.Bitmap.Canvas, R); + end; + + //Draw the text + cnvs.Font.Assign(FFont); + FH:= round(1.2 * FontSizeToPix(cnvs.Font.Size, 1)); + //first, try if the text fits in the designated area. If not, lower the font size + mh:= cnvs.TextWidth(FText); + while (mh > (FTxtRect.Right - FTxtRect.Left)) and (FFont.Size >= 1) do + begin + cnvs.Font.Size:= cnvs.Font.Size - 1; + FH:= round(1.2 * FontSizeToPix(cnvs.Font.Size, 1)); + mh:= cnvs.TextWidth(FText); + end; + FTxtRect.Top:= FTxtRect.Bottom - FH; + + SRect:= ScaleRect(FTxtRect, Scale); + cnvs.Font.Height:= FontSizeToPix(FFont.Size, Scale); + mh:= round((SRect.Bottom + SRect.Top) / 2); + DrawTxt(Cnvs, mh, SRect.Left, SRect.Right, FText, FAlignment, TRUE); + + //Draw the line + cnvs.Pen.Assign(FPen); + SRect:= ScaleRect(FRect, Scale); + if FHeaderType = thHeader then + begin + cnvs.MoveTo(SRect.Left, SRect.Bottom); + cnvs.LineTo(SRect.Right, SRect.Bottom); + end + else + begin + cnvs.MoveTo(SRect.Left, SRect.Top); + cnvs.LineTo(SRect.Right, SRect.Top); + end; +end; + +Procedure TBHRHeader.CalcRect; +var W, H : LongInt; + WH : double; +begin + if FHeaderType = thHeader then + begin + FRect.Top:= FDocument.PageRect.Top + FMarge; + FRect.Left:= FDocument.PrintRect.Left; + FRect.Right:= FDocument.PrintRect.Right; + FRect.Bottom:= FDocument.PrintRect.Top - FMarge; + FPictRect.Top:= FRect.Top + FMarge; + FPictRect.Bottom:= FRect.Bottom - FMarge; + FPictRect.Left:= FRect.Left; + FPictRect.Right:= 0; + end + else + begin + FRect.Top:= FDocument.PrintRect.Bottom + FMarge; + FRect.Left:= FDocument.PrintRect.Left; + FRect.Right:= FDocument.PrintRect.Right; + FRect.Bottom:= FDocument.PageRect.Bottom - FMarge; + FPictRect.Top:= FRect.Top + FMarge; + FPictRect.Bottom:= FRect.Bottom - FMarge; + FPictRect.Left:= FRect.Left; + FPictRect.Right:= 0; + end; + FHeight:= FRect.Bottom - FRect.Top; + + W:= FPicture.Width; + H:= FPicture.Height; + if H > 0 then + begin + WH:= W / H; + FPictRect.Right:= FPictRect.Left + round(WH * (FPictRect.Bottom - FPictRect.Top)); + end; + + FTxtRect.Left:= FPictRect.Right + FMarge; + FTxtRect.Right:= FRect.Right; + FFontHeight:= round(1.2 * FontSizeToPix(FFont.Size, 1)); + + if FHeaderType = thHeader then + begin + FTxtRect.Bottom:= FRect.Bottom - FMarge; + FTxtRect.Top:= FTxtRect.Bottom - FFontHeight; + end + else + begin + FTxtRect.Top:= FRect.Top + FMarge; + FTxtRect.Bottom:= FTxtRect.Top + FFontHeight; + end; +end; + +{========================== TBHRImage =======================================} + +Constructor TBHRImage.Create(D : TBHRDocument); +begin + Inherited Create(D); + FPicture := TPicture.Create; + FStretch:= false; +end; + +Destructor TBHRImage.Destroy; +begin + FPicture.Free; + Inherited; +end; + +Procedure TBHRImage.Draw(Cnvs : TCanvas; Pnr : integer; Scale : single); +var R, SRect : TRect; +begin + if (FPageNrS = PNr) then + begin + R.Left:= 0; + R.Top:= 0; + R.Right:= FPicture.Width; + R.Bottom:= FPicture.Height; + SRect:= ScaleRect(FRect, Scale); + + cnvs.Brush.Color:= clWhite; + cnvs.Rectangle(FRect); + cnvs.CopyMode:= cmSrcCopy; + cnvs.CopyRect(SRect, FPicture.Bitmap.Canvas, R); + end; +end; + +Procedure TBHRImage.CalcRect; +var W, H : LongInt; + WH : double; +begin + Inherited CalcRect; + if not FStretch then + begin + W:= FPicture.Width; + H:= FPicture.Height; + if H > 0 then + begin + WH:= W / H; + if WH > 1 then + begin + FRect.Right:= FRect.Left + W; + FRect.Bottom:= FRect.Top + round((FRect.Right - FRect.Left) / WH); + end + else + begin + FRect.Bottom:= FRect.Top + H; + FRect.Right:= FRect.Left + round((FRect.Bottom - FRect.Top) * WH); + end; + end; + end; + DeployKeepWithNext; +end; + +{============================TBHRBHGraph ======================================} + +{Constructor TBHRBHGraph.Create(D : TBHRDocument); +begin + Inherited Create(D); + FStretch:= false; + FGraph:= NIL; +end; + +Destructor TBHRBHGraph.Destroy; +begin + FGraph:= NIL; + Inherited; +end; + +Procedure TBHRBHGraph.Draw(Cnvs : TCanvas; Pnr : integer; Scale : single); +var SRect : TRect; +begin + if (FPageNrS = PNr) and (FGraph <> NIL) then + begin + SRect:= ScaleRect(FRect, Scale); + + cnvs.Brush.Color:= clWhite; + cnvs.Rectangle(FRect); + + FGraph.PaintTo(cnvs, SRect); + end; +end; + +Procedure TBHRBHGraph.CalcRect; +var W, H : LongInt; + WH : double; +begin + Inherited CalcRect; + if not FStretch then + begin + W:= FGraph.Width; + H:= FGraph.Height; + if H > 0 then + begin + WH:= W / H; + if WH > 1 then + begin + FRect.Bottom:= FRect.Top + round((FRect.Right - FRect.Left) / WH); + FRect.Right:= FRect.Left + W; + end + else + begin + FRect.Right:= FRect.Left + round((FRect.Bottom - FRect.Top) * WH); + FRect.Bottom:= FRect.Top + H; + end; + end; + end; + DeployKeepWithNext; +end; } + +{============================TBHRChart =========================================} + +Constructor TBHRChart.Create(D : TBHRDocument); +begin + Inherited Create(D); + FStretch:= false; + FChart:= NIL; +end; + +Destructor TBHRChart.Destroy; +begin + FChart:= NIL; + Inherited; +end; + +Procedure TBHRChart.Draw(Cnvs : TCanvas; Pnr : integer; Scale : single); +var SRect, BRect : TRect; + bmp : tbitmap; + GSc : single; + i, OLineWidth, OLegendMargin, OSymbolWidth : integer; + OMFH, OTFH, OTL, OLFH : integer; +{const FH = 100; + PenW = 10;} +begin + if FPageNrS = Pnr then + begin + GSc:= Scale * (FRect.Right - FRect.Left) / (FChart.Width); + + FChart.Paint; + FChart.Proportional:= TRUE; + + SRect:= ScaleRect(FRect, Scale); + bmp:= TBitmap.Create; + Bmp.SetSize(SRect.Right - SRect.Left, SRect.Bottom - SRect.Top); + BRect.Top:= 0; + BRect.Left:= 0; + BRect.Bottom:= SRect.Bottom - SRect.Top; + BRect.Right:= SRect.Right - SRect.Left; + {$ifndef Darwin} + OTFH:= FChart.AxisList[0].Title.Font.Size; + {$endif} + OMFH:= FChart.AxisList[0].Marks.LabelFont.Size; + OTL:= FChart.AxisList[0].TickLength; + OLFH:= FChart.Legend.Font.Size; + OLegendMargin:= FChart.Legend.MarginX; + OSymbolWidth:= FChart.Legend.SymbolWidth; + OLineWidth:= TLineSeries(FChart.Series[0]).LinePen.Width; + + for i:= 0 to FChart.AxisList.Count - 1 do + begin + FChart.AxisList[i].Marks.LabelFont.Size:= round(GSc * 9); + {$ifndef Darwin} + FChart.AxisList[i].Title.Font.Size:= round(GSC * 9); + {$endif} + FChart.AxisList[i].TickLength:= round(GSc * OTL); + end; + FChart.Legend.Font.Size:= round(GSc * 9); + FChart.Legend.MarginX:= round(GSc * OLegendMargin); + FChart.Legend.SymbolWidth:= round(GSc * OSymbolWidth); + + //Adjust line width of chart series + for i:= 0 to FChart.SeriesCount - 1 do + TLineSeries(FChart.Series[i]).LinePen.Width:= round(GSc * OLineWidth); + + FChart.PaintOnCanvas(Bmp.Canvas, BRect); + + for i:= 0 to FChart.AxisList.Count - 1 do + begin + FChart.AxisList[i].Marks.LabelFont.Size:= OMFH; + {$IFNDEF LCL qt} + FChart.AxisList[i].Title.Font.Size:= OTFH; + {$ENDIF} + FChart.AxisList[i].TickLength:= OTL; + end; + FChart.Legend.Font.Size:= OLFH; + FChart.Legend.MarginX:= OLegendMargin; + FChart.Legend.SymbolWidth:= OSymbolWidth; + for i:= 0 to FChart.SeriesCount - 1 do + TLineSeries(FChart.Series[i]).LinePen.Width:= OLineWidth; + + cnvs.Brush.Color:= clWhite; + cnvs.Rectangle(FRect); + cnvs.CopyMode:= cmSrcCopy; + cnvs.CopyRect(SRect, Bmp.Canvas, BRect); + Bmp.Free; + end; +end; + +Procedure TBHRChart.CalcRect; +var W, H : LongInt; + WH : double; +begin + Inherited CalcRect; + if not FStretch then + begin + W:= FChart.Width; + H:= FChart.Height; + if H > 0 then + begin + WH:= W / H; + if WH > 1 then + begin + FRect.Bottom:= FRect.Top + round((FRect.Right - FRect.Left) / WH); + // FRect.Right:= FRect.Left + W; + end + else + begin + FRect.Right:= FRect.Left + round((FRect.Bottom - FRect.Top) * WH); + // FRect.Bottom:= FRect.Top + H; + end; + end; + if FRect.Bottom > FDocument.FPrintRect.Bottom then + begin + FPageNrS:= FPageNrS + 1; + FPageNrE:= FPageNrS; + FRect.Top:= FDocument.PrintRect.Top; + if WH > 1 then + begin + FRect.Bottom:= FRect.Top + round((FRect.Right - FRect.Left) / WH); + // FRect.Right:= FRect.Left + W; + end + else + begin + FRect.Right:= FRect.Left + round((FRect.Bottom - FRect.Top) * WH); + FRect.Bottom:= FRect.Top + H; + end; + end; + end; + DeployKeepWithNext; +end; + + +{========================== TBHRText ==========================================} + +Constructor TBHRText.Create(D : TBHRDocument); +begin + Inherited Create(D); + FCell:= NIL; + FStrings := TStringList.Create; + FFont := TFont.Create; + with FFont do + begin +// CharSet:= DEFAULT_CHARSET; + Color:= clBlack; + Size:= 10; +// Name:= default; + Orientation:= 0; + Pitch:= fpDefault; + Quality:= fqDefault; //fqAntiAliased + Style:= []; + end; + FAlignment:= taLeftJustify; + FBrush:= TBrush.Create; + with FBrush do + begin + Color:= clWhite; + Style:= bsSolid; + end; + FPen:= TPen.Create; + with FPen do + begin + Color:= clWhite; + Style:= psSolid; + Width:= 1; + end; + FMarge:= CmToPixY(0.05); + FAutoSize:= false; + FCheckBoxes:= false; + FChecked:= false; + FCheckBoxSize:= CmToPixY(0.4); +end; + +Destructor TBHRText.Destroy; +begin + FStrings.Free; + SetLength(FLineProps, 0); + FFont.Free; + FBrush.Free; + FPen.Free; + Inherited; +end; + +Function TBHRText.GetString(i : integer) : string; +begin + Result:= ''; + if (i >= 0) and (i < FStrings.Count) then + Result:= FStrings[i]; +end; + +Procedure TBHRText.SetString(i : integer; s : string); +begin + if (i >= 0) and (i < FStrings.Count) then + FStrings[i]:= s + else if (i > FStrings.Count - 1) then + AddString(s) + else if (i < 0) then + InsertString(s, 0, twBelow); +end; + +Procedure TBHRText.AddString(s : string); +var i : integer; +begin + FStrings.Add(s); + SetLength(FLineProps, High(FLineProps) + 2); + i:= High(FLineProps); + FLineProps[i].Rect.Left:= FRect.Left; + FLineProps[i].Rect.Right:= FRect.Right; + FLineProps[i].PageNr:= FPageNrS; + FLineProps[i].TextRect.Left:= FRect.Left + FMarge; + FLineProps[i].TextRect.Right:= FRect.Right - FMarge; + FKeepTogether:= false; +end; + +Procedure TBHRText.RemoveString(i : integer); +var j : integer; +begin + if (i >= 0) and (i < FStrings.Count) then + begin + FStrings.Delete(i); + for j:= i to High(FLineProps) - 1 do + FLineProps[j]:= FLineProps[j-1]; + SetLength(FLineProps, High(FLineProps)); + end; +end; + +Procedure TBHRText.InsertString(s : string; i : integer; Where : TWhere); +var j : integer; +begin + if (i >= 0) and (i < FStrings.Count) then + case Where of + twAbove: + begin + FStrings.Insert(i, s); + SetLength(FLineProps, High(FLineProps) + 2); + for j:= High(FLineProps) downto i + 1 do + FLineProps[j]:= FLineProps[j-1]; + FLineProps[i].Rect.Left:= FRect.Left; + FLineProps[i].Rect.Right:= FRect.Right; + FLineProps[i].PageNr:= FPageNrS; + FLineProps[i].TextRect.Left:= FRect.Left + FMarge; + FLineProps[i].TextRect.Right:= FRect.Right - FMarge; + end; + twBelow: + if i = 0 then + begin + FStrings.Add(''); + for j:= FStrings.Count - 1 to 1 do + FStrings[j]:= FStrings[j-1]; + FStrings[0]:= s; + SetLength(FLineProps, High(FLineProps) + 2); + for j:= High(FLineProps) downto 1 do + FLineProps[j]:= FLineProps[j-1]; + FLineProps[0].Rect.Left:= FRect.Left; + FLineProps[0].Rect.Right:= FRect.Right; + FLineProps[0].PageNr:= FPageNrS; + FLineProps[0].TextRect.Left:= FRect.Left + FMarge; + FLineProps[0].TextRect.Right:= FRect.Right - FMarge; + end + else + begin + FStrings.Insert(i-1, s); + SetLength(FLineProps, High(FLineProps) + 2); + for j:= High(FLineProps) downto i + 1 do + FLineProps[j]:= FLineProps[j-1]; + FLineProps[i].Rect.Left:= FRect.Left; + FLineProps[i].Rect.Right:= FRect.Right; + FLineProps[i].PageNr:= FPageNrS; + FLineProps[i].TextRect.Left:= FRect.Left + FMarge; + FLineProps[i].TextRect.Right:= FRect.Right - FMarge; + end; + end; +end; + +Procedure TBHRText.SetMarge(w : word); +begin + if FMarge <> w then FMarge:= w; +end; + +Procedure TBHRText.Move(PNr, Tp : word); +var i, j, t, h: integer; + tot, LL, LMarge, w,fh : LongInt; + s : string; +begin + Inherited Move(PNr, Tp); + FFontHeight:= round(1.2 * FontSizeToPix(FFont.Size, 1)); + if (High(FLineProps) >= 0) then + begin + if FCheckBoxes then LMarge:= 2 * FMarge + FCheckBoxSize + 2 * FMarge + else LMarge:= 2 * FMarge; + tot:= 0; + FLineProps[0].Rect.Top:= FRect.Top; + FLineProps[0].TextRect.Top:= FRect.Top + FMarge; + for i:= 0 to FStrings.Count - 1 do + begin + if i = 0 then FLineProps[i].PageNr:= FPageNrS + else FLineProps[i].PageNr:= FLineProps[i-1].PageNr; + FLineProps[i].TextRect.Left:= FRect.Left + LMarge; + FLineProps[i].TextRect.Right:= FRect.Right - 2 * FMarge; + if i > 0 then + begin + FLineProps[i].Rect.Top:= FLineProps[i-1].Rect.Bottom; + FLineProps[i].PageNr:= FLineProps[i-1].PageNr; + end; + FLineProps[i].TextRect.Top:= FLineProps[i].Rect.Top + FMarge; + s:= FStrings[i]; + w:= FLineProps[i].TextRect.Right - FLineProps[i].TextRect.Left; + if FAutoSize and (w > 0) then + begin + fh:= FFont.Height; + FFont.Height:= FFontHeight; + LL:= CalcAmountLines2(FFont, s, w); + FFont.Height:= fh; + end + else + LL:= 1; + + LL:= LL * FFontHeight; + FLineProps[i].TextRect.Bottom:= FLineProps[i].TextRect.Top + LL; + FLineProps[i].Rect.Bottom:= FLineProps[i].TextRect.Bottom + FMarge; + t:= FLineProps[i].Rect.Bottom - FLineProps[i].Rect.Top; + if (FLineProps[i].Rect.Bottom > FDocument.FPrintRect.Bottom) and + ((not FKeepTogether) or (i = 0))then + begin + FLineProps[i].PageNr:= FLineProps[i].PageNr + 1; + FPageNrE:= FPageNrE + 1; + if i = 0 then FPageNRS:= FPageNRE; + FLineProps[i].Rect.Top:= FDocument.FPrintRect.Top; + FLineProps[i].Rect.Bottom:= FLineProps[i].Rect.Top + t; + FLineProps[i].TextRect.Top:= FLineProps[i].Rect.Top + FMarge; + FLineProps[i].TextRect.Bottom:= FLineProps[i].Rect.Bottom - FMarge; + end; + if (i > 0) and FKeepTogether and (FLineProps[i-1].PageNr < FLineProps[i].PageNr) then + begin + FPageNrS:= FPageNRE; + for j:= 0 to i do + begin + h:= FLineProps[j].Rect.Bottom - FLineProps[j].Rect.Top; + if j = 0 then FLineProps[j].Rect.Top:= FDocument.FPrintRect.Top + else FLineProps[j].Rect.Top:= FLineProps[j-1].Rect.Bottom; + FLineProps[j].Rect.Bottom:= FLineProps[j].Rect.Top + h; + FLineProps[j].TextRect.Top:= FLineProps[j].Rect.Top + FMarge; + FLineProps[j].TextRect.Bottom:= FLineProps[j].Rect.Bottom - FMarge; + FLineProps[j].PageNr:= FPageNrS; + end; + if (FLineProps[i].Rect.Bottom > FDocument.FPrintRect.Bottom) and FKeeptogether then + //lines do not fit on the page all, so Keeptogether cannot be implemented + begin + FKeeptogether:= false; + CalcRect; + end; + end; + tot:= tot + t; + end; + FRect.Top:= FLineProps[0].Rect.Top; + FRect.Bottom:= FLineProps[FStrings.Count - 1].Rect.Bottom; + end + else //make the text at least 1 line high + begin + FRect.Bottom:= FRect.Top + FFontHeight; + end; +end; + +Procedure TBHRText.CalcRect; +//Calculate the height of the text given the width and font size +var i, j, t, h: integer; + tot, LL, LMarge, w,fh : LongInt; + s : string; +begin + Inherited CalcRect; + FFontHeight:= round(1.2 * FontSizeToPix(FFont.Size, 1)); + if (High(FLineProps) >= 0) then + begin + if FCheckBoxes then LMarge:= 2 * FMarge + FCheckBoxSize + 2 * FMarge + else LMarge:= 2 * FMarge; + tot:= 0; + FLineProps[0].Rect.Top:= FRect.Top; + FLineProps[0].TextRect.Top:= FRect.Top + FMarge; + for i:= 0 to FStrings.Count - 1 do + begin + if i = 0 then FLineProps[i].PageNr:= FPageNrS + else FLineProps[i].PageNr:= FLineProps[i-1].PageNr; + FLineProps[i].TextRect.Left:= FRect.Left + LMarge; + FLineProps[i].TextRect.Right:= FRect.Right - 2 * FMarge; + if i > 0 then + begin + FLineProps[i].Rect.Top:= FLineProps[i-1].Rect.Bottom; + FLineProps[i].PageNr:= FLineProps[i-1].PageNr; + end; + FLineProps[i].TextRect.Top:= FLineProps[i].Rect.Top + FMarge; + s:= FStrings[i]; + w:= FLineProps[i].TextRect.Right - FLineProps[i].TextRect.Left; + if FAutoSize and (w > 0) then + begin + fh:= FFont.Height; + FFont.Height:= FFontHeight; + LL:= CalcAmountLines2(FFont, s, w); + FFont.Height:= fh; + end + else + LL:= 1; + + LL:= LL * FFontHeight; + FLineProps[i].TextRect.Bottom:= FLineProps[i].TextRect.Top + LL; + FLineProps[i].Rect.Bottom:= FLineProps[i].TextRect.Bottom + FMarge; + t:= FLineProps[i].Rect.Bottom - FLineProps[i].Rect.Top; + if (FLineProps[i].Rect.Bottom > FDocument.FPrintRect.Bottom) and + ((not FKeepTogether) or (i = 0))then + begin + FLineProps[i].PageNr:= FLineProps[i].PageNr + 1; + FPageNrE:= FPageNrE + 1; + if i = 0 then FPageNRS:= FPageNRE; + FLineProps[i].Rect.Top:= FDocument.FPrintRect.Top; + FLineProps[i].Rect.Bottom:= FLineProps[i].Rect.Top + t; + FLineProps[i].TextRect.Top:= FLineProps[i].Rect.Top + FMarge; + FLineProps[i].TextRect.Bottom:= FLineProps[i].Rect.Bottom - FMarge; + end; + if (i > 0) and FKeepTogether and (FLineProps[i-1].PageNr < FLineProps[i].PageNr) then + begin + FPageNrS:= FPageNRE; + for j:= 0 to i do + begin + h:= FLineProps[j].Rect.Bottom - FLineProps[j].Rect.Top; + if j = 0 then FLineProps[j].Rect.Top:= FDocument.FPrintRect.Top + else FLineProps[j].Rect.Top:= FLineProps[j-1].Rect.Bottom; + FLineProps[j].Rect.Bottom:= FLineProps[j].Rect.Top + h; + FLineProps[j].TextRect.Top:= FLineProps[j].Rect.Top + FMarge; + FLineProps[j].TextRect.Bottom:= FLineProps[j].Rect.Bottom - FMarge; + FLineProps[j].PageNr:= FPageNrS; + end; + if (FLineProps[i].Rect.Bottom > FDocument.FPrintRect.Bottom) and FKeeptogether then + //lines do not fit on the page all, so Keeptogether cannot be implemented + begin + FKeeptogether:= false; + CalcRect; + end; + end; + tot:= tot + t; + end; + FRect.Top:= FLineProps[0].Rect.Top; + FRect.Bottom:= FLineProps[FStrings.Count - 1].Rect.Bottom; + end + else //make the text at least 1 line high + begin + FRect.Bottom:= FRect.Top + FFontHeight; + end; + DeployKeepWithNext; +end; + +Procedure TBHRText.Draw(Cnvs : TCanvas; Pnr : integer; Scale : single); +var i : integer; + s : string; + t, mh : LongInt; + fsz : word; + OFont : TFont; + OBrush : TBrush; + OPen : TPen; + cbR : TRect; + SRect : TRect; +begin + if (FPageNrS <= PNr) and (FPageNrE >= PNr) then + begin + t:= FRect.Top; + OFont:= TFont.Create; + OBrush:= TBrush.Create; + OPen:= TPen.Create; + OFont.Assign(Cnvs.Font); + OBrush.Assign(Cnvs.Brush); + OPen.Assign(Cnvs.Pen); + Cnvs.Font.Assign(FFont); + + Cnvs.Brush.Assign(FBrush); + Cnvs.Pen.Color:= Cnvs.Brush.Color; + Cnvs.Pen.Width:= 0; + if FRect.Bottom < FRect.Top then //Text spans more pages + begin + CbR:= FRect; + if PNr = FPageNrS then + begin + CbR.Bottom:= FDocument.PrintRect.Bottom; + end + else if (PNr > FPageNrS) and (PNr < FPageNrE) then + begin + CbR.Top:= FDocument.PrintRect.Top; + CbR.Bottom:= FDocument.PrintRect.Bottom; + end + else if PNr = FPageNrE then + begin + CbR.Top:= FDocument.PrintRect.Top; + end; + SRect:= ScaleRect(CbR, Scale); + end + else + begin + SRect:= ScaleRect(FRect, Scale); + end; + Cnvs.Rectangle(SRect); + + for i:= 0 to FStrings.Count - 1 do + if FLineProps[i].PageNr = PNr then + begin + Cnvs.Pen.Assign(FPen); + cnvs.Pen.Style:= psSolid; + cnvs.Pen.Color:= clBlack; + Cnvs.Brush.Color:= clWhite; + fsz:= FFont.Size; + if FCheckBoxes then + begin + cbR.Top:= FLineProps[i].TextRect.Top; + cbR.Bottom:= cbR.Top + FontSizeToPix(fsz, 1); + cbR.Left:= FRect.Left + FMarge; + cbR.Right:= cbR.Left + FontSizeToPix(fsz, 1); + cbR:= ScaleRect(cbR, Scale); + Cnvs.Rectangle(cbR); + if FChecked then + begin + Cnvs.MoveTo(cbR.Left, cbR.Top); + Cnvs.LineTo(cbR.Right, cbR.Bottom); + Cnvs.MoveTo(cbR.Right, cbR.Top); + Cnvs.LineTo(cbR.Left, cbR.Bottom); + end; + end; + + Cnvs.Font.Height:= FontSizeToPix(fsz, Scale); + SRect:= ScaleRect(FLineProps[i].TextRect, Scale); + mh:= Round((SRect.Bottom + SRect.Top) / 2); + s:= FStrings[i]; + t:= t + DrawTxt(Cnvs, mh, SRect.Left, SRect.Right, s, FAlignment, TRUE); + Cnvs.Font.Size:= fsz; + end; + + Cnvs.Font.Assign(OFont); + Cnvs.Brush.Assign(OBrush); + Cnvs.Pen.Assign(OPen); + OFont.Free; + OBrush.Free; + OPen.Free; + end; +end; + +{============================TBHRCell =========================================} + +Constructor TBHRCell.Create(D : TBHRDocument; R, C : integer); +begin + Inherited Create(D); + FText := TBHRText.Create(D); + FText.Cell:= self; + FText.AutoSize:= false; + FTable:= NIL; + FRow:= R; + FColumn:= C; +end; + +Destructor TBHRCell.Destroy; +begin + FText.Free; + Inherited Destroy; +end; + +Procedure TBHRCell.SetLeft(l : word); +begin + Inherited SetLeft(l); + if FText <> NIL then + FText.Left:= l; +end; + +Procedure TBHRCell.SetRight(r : word); +begin + Inherited SetRight(r); + if FText <> NIL then + FText.Right:= r; +end; + +procedure TBHRCell.SetTop(t : word); +begin + Inherited SetTop(t); + if FText <> NIL then + begin + FText.Top:= t; + // FText.CalcRect; + end; +end; + +Procedure TBHRCell.SetBottom(b : word); +begin + Inherited SetBottom(b); + if FText <> NIL then + FText.Bottom:= b; +end; + +Procedure TBHRCell.SetKeepTogether(b : boolean); +begin + if FKeepTogether <> b then + begin + FKeepTogether:= b; + FKeepWithNext:= b; + FText.KeepTogether:= b; + FText.KeepWithNext:= b; + end; +end; + +Function TBHRCell.GetFont : TFont; +begin + Result:= NIL; + if FText <> NIL then Result:= FText.Font; +end; + +Function TBHRCell.GetBrush : TBrush; +begin + Result:= NIL; + if FText <> NIL then Result:= FText.Brush; +end; + +Function TBHRCell.GetPen : TPen; +begin + Result:= NIL; + if FText <> NIL then Result:= FText.Pen; +end; + +Function TBHRCell.GetAlignment : TAlignment; +begin + Result:= taLeftJustify; + if FText <> NIL then Result:= FText.Alignment; +end; + +Procedure TBHRCell.SetAlignment(al : TAlignment); +begin + if FText <> NIL then FText.Alignment:= al; +end; + +Function TBHRCell.GetKeepTogether : boolean; +begin + Result:= TRUE; + if FText <> NIL then Result:= FText.KeepTogether; +end; + +Function TBHRCell.GetMarge : word; +begin + Result:= 0; + if FText <> NIL then Result:= FText.Marge; +end; + +Procedure TBHRCell.SetMarge(w : word); +begin + if FText <> NIL then FText.Marge:= w; +end; + +Function TBHRCell.GetAutoSize : boolean; +begin + Result:= false; + if FText <> NIL then Result:= FText.AutoSize; +end; + +Procedure TBHRCell.SetAutoSize(b : boolean); +begin + if FText <> NIL then FText.AutoSize:= b; +end; + +Function TBHRCell.GetCheckBoxes : boolean; +begin + Result:= false; + if FText <> NIL then Result:= FText.CheckBoxes; +end; + +Procedure TBHRCell.SetCheckBoxes(b : boolean); +begin + if FText <> NIL then FText.CheckBoxes:= b; +end; + +Function TBHRCell.GetCheckBoxSize : LongInt; +begin + Result:= 0; + if FText <> NIL then Result:= FText.CheckBoxSize; +end; + +Procedure TBHRCell.SetCheckBoxSize(L : LongInt); +begin + if FText <> NIL then FText.CheckBoxSize:= L; +end; + +Procedure TBHRCell.SetNext(E : TBHRElement); +begin + Inherited SetNext(E); + FText.Next:= E; +end; + +Procedure TBHRCell.SetPrior(E : TBHRElement); +begin + Inherited SetPrior(E); + FText.Prior:= E; +end; + +Procedure TBHRCell.SetPageNrS(i : integer); +begin + if (i > 0) {and (i <= FDocument.NumPages)} then + begin + Inherited SetPageNrS(i); + FText.PageNrS:= i; + end; +end; + +Procedure TBHRCell.SetPageNrE(i : integer); +begin + if (i > 0) {and (i <= FDocument.NumPages)} then + begin + Inherited SetPageNrE(i); + FText.PageNrE:= i; + end; +end; + +Procedure TBHRCell.Draw(Cnvs : TCanvas; Pnr : integer; Scale : single); +begin + if FText <> NIL then FText.Draw(Cnvs, Pnr, Scale); +end; + +Procedure TBHRCell.Move(PNr, Tp : word); +begin + if (FRow = 0) and (FColumn = 0) and (FTable <> NIL) then FTable.Move(PNr, Tp); +{ if FText <> NIL then FText.Move(PNr, Tp); + FRect:= FText.Rect; + FPageNrS:= FText.PageNrS; + FPageNrE:= FText.PageNrE;} +end; + +Procedure TBHRCell.CalcRect; +begin + Inherited CalcRect; + if FText <> NIL then FText.CalcRect; + FRect:= FText.Rect; + FPageNrS:= FText.PageNrS; + FPageNrE:= FText.PageNrE; + DeployKeepWithNext; +end; + +{========================== TBHRTable =========================================} + +Constructor TBHRTable.Create(D : TBHRDocument); +begin + Inherited Create(D); + FAutoSizeCells := false; + FColsEven := TRUE; + FKeepTogether:= TRUE; +end; + +Destructor TBHRTable.Destroy; +var R, C : integer; +begin + for R:= Low(FCells) to High(FCells) do + begin + for C:= Low(FCells[R]) to High(FCells[R]) do + FCells[R, C].Free; + SetLength(FCells[R], 0); + end; + SetLength(FCells, 0); + Inherited Destroy; +end; + +Function TBHRTable.GetCell(aRow, aCol : integer) : TBHRCell; +begin + if (aRow >= Low(FCells)) and (aRow <= High(FCells)) then + if (aCol >= Low(FCells[aRow])) and (aCol <= High(FCells[aRow])) then + Result:= FCells[aRow, aCol]; +end; + +Procedure TBHRTable.SetSize(NRows, NCols : integer); +var R, C : integer; +begin + SetLength(FCells, NRows); + for R:= 0 to NRows - 1 do + begin + SetLength(FCells[R], NCols); + for C:= 0 to NCols - 1 do + begin + if FCells[R, C] = NIL then + begin + FCells[R, C]:= TBHRCell.Create(FDocument, R, C); + FCells[R, C].Table:= self; + if C = 0 then FCells[R, C].Left:= FRect.Left + else FCells[R, C].Left:= FCells[R, C-1].Right; + if R = 0 then + begin + FCells[R, C].Top:= FRect.Top; + end + else + begin + FCells[R, C].Top:= FCells[R-1, C].Bottom; + FCells[R, C].Prior:= FCells[R-1, C]; + FCells[R-1, C].Next:= FCells[R, C]; + end; + end; + FCells[R, C].Keeptogether:= FKeepTogether; + end; + end; + SetColsEven(TRUE); +end; + +Function TBHRTable.NumRows : integer; +begin + Result:= High(FCells) + 1; +end; + +Function TBHRTable.NumCols : integer; +begin + Result:= 0; + if NumRows > 0 then + Result:= High(FCells[0]) + 1; +end; + +Procedure TBHRTable.SetKeepTogether(b : boolean); +var C, R : integer; +begin + FKeepTogether:= b; + for R:= 0 to NumRows - 2 do + for C:= 0 to NumCols - 1 do + FCells[R, C].KeepWithNext:= b; + FDocument.CalcRects; +end; + +Function TBHRTable.GetRowColor(i : word) : TColor; +begin + Result:= clWhite; + if (i >= Low(FCells)) and (i <= High(FCells)) then + Result:= FCells[i, 0].Brush.Color; +end; + +Procedure TBHRTable.SetRowColor(i : word; cl : TColor); +var j : integer; +begin + if (i >= Low(FCells)) and (i <= High(FCells)) then + for j:= Low(FCells[i]) to High(FCells[i]) do + begin + FCells[i, j].Brush.Color:= cl; + FCells[i, j].Brush.Style:= bsSolid; + end; +end; + +Function TBHRTable.GetColColor(i : word) : TColor; +begin + Result:= clWhite; + if (i >= Low(FCells[0])) and (i <= High(FCells[0])) then + Result:= FCells[0, i].Brush.Color; +end; + +Procedure TBHRTable.SetColColor(i : word; cl : TColor); +var j : integer; +begin + if (i >= Low(FCells[0])) and (i <= High(FCells[0])) then + for j:= Low(FCells) to High(FCells) do + begin + FCells[j, i].Brush.Color:= cl; + FCells[j, i].Brush.Style:= bsSolid; + end; +end; + +Function TBHRTable.GetColWidth(aCol : integer) : word; +var C : TBHRCell; +begin + Result:= 0; + C:= GetCell(0, aCol); + if C <> NIL then Result:= C.Rect.Right - C.Rect.Left; +end; + +Procedure TBHRTable.SetColWidth(aCol : integer; Width : word); +var Cell, Cell2 : TBHRCell; + R : integer; +begin + FColsEven:= false; + for R:= 0 to NumRows - 1 do + begin + Cell:= GetCell(R, aCol); + if Cell <> NIL then + begin + if aCol = 0 then + begin + //Cell.FText.Left:= FRect.Left; + Cell.Left:= FRect.Left; + end + else + begin + Cell2:= GetCell(R, aCol-1); + if Cell2 <> NIL then + begin + //Cell.FText.Left:= Cell2.Rect.Right; + Cell.Left:= Cell2.Rect.Right; + end; + end; + //Cell.FText.Right:= Cell.Rect.Left + Width; + Cell.Right:= Cell.Rect.Left + Width; + end; + end; +end; + +Procedure TBHRTable.SetColsEven(b : boolean); +var Cell, Cell2, Cell1 : TBHRCell; + R, C : integer; + W : single; +begin + FColsEven:= b; + if b and (NumCols > 0) then + begin + W:= (FRect.Right - FRect.Left) / NumCols; + for R:= 0 to NumRows - 1 do + begin + Cell1:= GetCell(R, 0); + for C:= 0 to NumCols - 1 do + begin + Cell:= GetCell(R, C); + if Cell <> NIL then + begin + if C = 0 then + Cell.FText.Left:= FRect.Left + else + begin + Cell2:= GetCell(R, C-1); + if Cell2 <> NIL then + Cell.FText.Left:= Cell2.Rect.Right; + end; + Cell.Right:= Cell1.Left + round((C + 1) * W); + end; + end; + end; + end; +end; + +Function TBHRTable.GetRowHeight(aRow : integer) : word; +var C : TBHRCell; +begin + Result:= 0; + C:= GetCell(aRow, 0); + if C <> NIL then Result:= C.Rect.Bottom - C.Rect.Top; +end; + +Procedure TBHRTable.SetRowHeight(ARow : integer; Height : word); +var Cell, Cell2 : TBHRCell; + C : integer; +begin + for C:= 0 to NumCols - 1 do + begin + Cell:= GetCell(aRow, C); + if Cell <> NIL then + begin + if aRow = 0 then + Cell.FText.Top:= FRect.Top + else + begin + Cell2:= GetCell(aRow-1, C); + if Cell2 <> NIL then + Cell.FText.Left:= Cell2.Rect.Bottom; + end; + Cell.FText.Bottom:= Cell.FText.Top + Height; + end; + end; +end; + +Procedure TBHRTable.SetAutoSizeCells(b : boolean); +var C, R : integer; +begin + FAutoSizeCells:= b; + for R:= 0 to NumRows - 1 do + for C:= 0 to NumCols - 1 do + FCells[R, C].AutoSize:= b; + FDocument.CalcRects; +end; + +Procedure TBHRTable.SetPageNrS(i : integer); +var C, R : integer; +begin + if (i > 0) {and (i <= FDocument.NumPages)} then + begin + Inherited SetPageNrS(i); + for R:= 0 to NumRows - 1 do + for C:= 0 to NumCols - 1 do + FCells[R, C].PageNrS:= i; + end; +end; + +Procedure TBHRTable.SetPageNrE(i : integer); +var C, R : integer; +begin + if (i > 0) {and (i <= FDocument.NumPages)} then + begin + Inherited SetPageNrE(i); + for R:= 0 to NumRows - 1 do + for C:= 0 to NumCols - 1 do + FCells[R, C].PageNrE:= i; + end; +end; + +Procedure TBHRTable.AddRow; +var C, R : integer; + Cell : TBHRCell; +begin + SetLength(FCells, High(FCells) + 2); + SetLength(FCells[High(FCells)], NumCols); + R:= High(FCells); + for C:= 0 to NumCols - 1 do + begin + FCells[R, C]:= TBHRCell.Create(FDocument, R, C); + FCells[R, C].Table:= self; + FCells[R, C].Keeptogether:= FKeeptogether; + if (R > 0) then + begin + Cell:= GetCell(R-1, C); + if Cell <> NIL then + begin + { if (not FAutoHeight) then + begin + FCells[R, C].Top:= Cell.Bottom; + FCells[R, C].Bottom:= Cell.Bottom + (Cell.Bottom - Cell.Top); + end; } + FCells[R, C].Left:= Cell.Left; + FCells[R, C].Right:= Cell.Right; + FCells[R, C].Prior:= Cell; + Cell.Next:= FCells[R, C]; + end; + end + else + begin + FCells[R, C].Top:= FRect.Top; + FCells[R, C].Bottom:= FRect.Bottom; + if C = 0 then + begin + FCells[R, C].Left:= FRect.Left; + if NumCols = 0 then + FCells[R, C].Right:= FRect.Right + else + FCells[R, C].Right:= FRect.Left + round((FRect.Right - FRect.Left) / NumCols); + end + else + begin + Cell:= GetCell(R, C-1); + FCells[R, C].Left:= Cell.Right; + FCells[R, C].Right:= FRect.Left + round((C + 1) * (FRect.Right - FRect.Left) / NumCols); + end; + end; + end; +end; + +Procedure TBHRTable.AddCol; +var C, R : integer; + Cell : TBHRCell; +begin + for R:= 0 to High(FCells) do + begin + SetLength(FCells[R], High(FCells[R]) + 2); + C:= High(FCells[R]); + FCells[R, C]:= TBHRCell.Create(FDocument, R, C); + FCells[R, C].Table:= self; + FCells[R, C].Keeptogether:= FKeepTogether; + if R > 0 then + begin + FCells[R, C].Prior:= FCells[R-1, C]; + FCells[R-1, C].Next:= FCells[R, C]; + end; + end; + + if FColsEven then SetColsEven(TRUE) + else if C > 0 then + begin + for R:= 0 to High(FCells) do + begin + Cell:= GetCell(R, C-1); + FCells[R, C].Top:= Cell.Top; + FCells[R, C].Bottom:= Cell.Bottom; + FCells[R, C].Left:= Cell.Right; + FCells[R, C].Right:= Cell.Right + (Cell.Right - Cell.Left); + end; + end + else + begin + for R:= 0 to High(FCells) do + begin + FCells[R, C].Left:= FRect.Right; + FCells[R, C].Right:= FRect.Left; + end; +{ if not FAutoHeight then + begin + FCells[0, C].Top:= FRect.Top; + if NumRows > 0 then + FCells[0, C].Bottom:= FRect.Top + round((FRect.Bottom - FRect.Top) / NumRows) + else FCells[0, C].Bottom:= FRect.Bottom; + for R:= 1 to High(FCells) do + begin + Cell:= GetCell(R-1, C); + FCells[R, C].Top:= Cell.Top; + FCells[R, C].Bottom:= FRect.Top + round((R + 1) * (FRect.Bottom - FRect.Top) / NumRows); + FCells[R, C].Left:= FRect.Right; + FCells[R, C].Right:= FRect.Left; + end; + end;} + end; +end; + +Procedure TBHRTable.Draw(Cnvs : TCanvas; Pnr : integer; Scale : single); +var R, C : integer; +begin + for R:= 0 to NumRows - 1 do + for C:= 0 to NumCols - 1 do + FCells[R, C].Draw(Cnvs, PNr, Scale); +end; + +Procedure TBHRTable.Move(PNr, Tp : word); +var R, C, PaNr : integer; + MaxH : word; + RTp : LongInt; + Cell : TBHRCell; +begin + Inherited Move(PNr, Tp); + RTp:= FRect.Top; + MaxH:= 0; + PaNr:= FPageNrS; + for R:= 0 to NumRows - 1 do + begin + //first, calculate the height of every cell in row R + for C:= 0 to NumCols - 1 do + begin + Cell:= FCells[R, C]; + if R = 0 then + begin + Cell.PageNrS:= FPageNrS; + Cell.PageNrE:= FPageNrS; + Cell.Top:= RTp; + end + else + begin + Cell.PageNrS:= FCells[R-1, C].FPageNrE; + Cell.PageNrE:= Cell.FPageNrS; + end; + Cell.CalcRect; + end; + + //then find the maximum height of the cells in row R + MaxH:= 0; + for C:= 0 to NumCols - 1 do + begin + Cell:= FCells[R, C]; + if (Cell.Bottom - Cell.Top) > MaxH then + MaxH:= Cell.Bottom - Cell.Top; + if Cell.PageNrE > FPageNrE then + PaNr:= Cell.PageNrE; + end; + if PaNr > FPageNrE then + begin + for C:= 0 to NumCols - 1 do + begin + Cell:= FCells[R, C]; + Cell.Top:= FDocument.PrintRect.Top; + Cell.PageNrS:= PaNr; + Cell.PageNrE:= PaNr; + end; + FPageNrE:= PaNr; + end; + RTp:= FCells[R, 0].Top + MaxH; + for C:= 0 to NumCols - 1 do + FCells[R, C].Bottom:= RTp; + end; + + Cell:= FCells[NumRows-1, NumCols-1]; + Bottom:= Cell.Bottom; + FPageNrE:= Cell.PageNrE; +end; + +Procedure TBHRTable.CalcRect; + Procedure DoCalcRect; + var R, C, PNr : integer; + MaxH, RTp : word; + Cell : TBHRCell; + begin + RTp:= FRect.Top; + MaxH:= 0; + PNr:= FPageNrS; + for R:= 0 to NumRows - 1 do + begin + //first, calculate the height of every cell in row R + for C:= 0 to NumCols - 1 do + begin + Cell:= FCells[R, C]; + if R = 0 then + begin + Cell.PageNrS:= FPageNrS; + Cell.PageNrE:= FPageNrS; + Cell.Top:= RTp; + end + else + begin + { Cell.PageNrS:= FCells[R-1, C].FPageNrE; + Cell.PageNrE:= Cell.FPageNrS;} + end; + Cell.CalcRect; + end; + + //then find the maximum height of the cells in row R + MaxH:= 0; + for C:= 0 to NumCols - 1 do + begin + Cell:= FCells[R, C]; + if (Cell.Bottom - Cell.Top) > MaxH then + MaxH:= Cell.Bottom - Cell.Top; + if Cell.PageNrE > FPageNrE then + PNr:= Cell.PageNrE; + end; + if PNr > FPageNrE then + begin + for C:= 0 to NumCols - 1 do + begin + Cell:= FCells[R, C]; + Cell.Top:= FDocument.PrintRect.Top; + Cell.PageNrS:= PNr; + Cell.PageNrE:= PNr; + end; + FPageNrE:= PNr; + end; + RTp:= FCells[R, 0].Top + MaxH; + for C:= 0 to NumCols - 1 do + FCells[R, C].Bottom:= RTp; + end; + + Cell:= FCells[NumRows-1, NumCols-1]; + Bottom:= Cell.Bottom; + FPageNrE:= Cell.PageNrE; + end; + +begin + Inherited CalcRect; + + DoCalcRect; + + if FKeepTogether and (FPageNrE > FPageNrS) then + begin + if FPageNrE - FPageNRS > 1 then //cannot keep together + begin + KeepTogether:= false; + end + else //place table on FPageNRE + begin + FPageNRS:= FPageNrE; + FRect.Top:= FDocument.PrintRect.Top; + end; + DoCalcRect; + end; + + DeployKeepWithNext; +end; + +{====================== TBHRDocument ==========================================} + +Constructor TBHRDocument.Create; +begin + Inherited; + FNumPages:= 1; + FMarginBT := 2; //cm + FMarginLR := 1.5; //cm + GetPrinterProps; + FHeader:= TBHRHeader.Create(self, thHeader); + FFooter:= TBHRHeader.Create(self, thFooter); +end; + +Destructor TBHRDocument.Destroy; +var i : integer; +begin + FHeader.Free; + FFooter.Free; + for i:= 0 to High(FElements) do + FElements[i].Free; + SetLength(FElements, 0); + Inherited; +end; + +Function TBHRDocument.GetLineHeight(fh : integer) : integer; +begin + Result:= Round(1.0 * FontSizeToPix(fh, 1)); +end; + +Procedure TBHRDocument.GetPrinterProps; +var dx : word; + dy : word; +begin + if Printer <> NIL then + begin + dx:= Printer.XDPI; + dy:= Printer.YDPI; + FMarginBTpx := round(FMarginBT / 2.54 * dy); + FMarginLRpx := round(FMarginLR / 2.54 * dx); + + FPageRect.Top:= 0; + FPageRect.Left:= 0; + FPageRect.Right:= Printer.PageWidth; + FPageRect.Bottom:= Printer.PageHeight; + + FPrintRect.Top:= FMarginBTpx; + FPrintRect.Bottom:= Printer.PageHeight - FMarginBTpx; + FPrintRect.Left:= FMarginLRpx; + FPrintRect.Right:= Printer.PageWidth - FMarginLRpx; + end + else + begin + dx:= 600; + dy:= 600; + FMarginBTpx := round(FMarginBT / 2.54 * dy); + FMarginLRpx := round(FMarginLR / 2.54 * dx); + + FPageRect.Top:= 0; + FPageRect.Left:= 0; + FPageRect.Right:= round(21.0 / 2.54 * 600); + FPageRect.Bottom:= round(29.7 / 2.54 * 600); + + FPrintRect.Top:= FMarginBTpx; + FPrintRect.Bottom:= round(29.7 / 2.54 * 600) - FMarginBTpx; + FPrintRect.Left:= FMarginLRpx; + FPrintRect.Right:= round(21.0 / 2.54 * 600) - FMarginLRpx; + end; +end; + +Function TBHRDocument.GetNumElements : integer; +begin + Result:= High(FElements) + 1; +end; + +Function Overlap(R1, R2 : TRect) : boolean; +var R : TRect; +begin + Result:= Intersectrect(R, R1, R2); +end; + +Procedure TBHRDocument.CalcRects; +var i : integer; + E : TBHRElement; +begin + if FHeader <> NIL then FHeader.CalcRect; + if FFooter <> NIL then FFooter.CalcRect; + FLastY:= FPrintRect.Top; + FLastPage:= 1; FNumPages:= 1; + for i:= 0 to High(FElements) do + begin + E:= FElements[i]; + if i = 0 then + begin + E.Top:= FPrintRect.Top; + E.PageNrS:= 1; + E.PageNrE:= 1; + end; + E.CalcRect; + FLastPage:= E.PageNrE; + FNumPages:= FLastPage; + end; +end; + +Procedure TBHRDocument.AddPage; +begin + Inc(FNumPages); +end; + +Procedure TBHRDocument.RemovePage; +begin + FNumPages:= FNumPages - 1; + if FNumPages < 1 then FNumPages:= 1; +end; + +Function TBHRDocument.AddSpace(Rect : TRect; h : word) : TBHRElement; +begin + Result:= NIL; + CalcRects; + SetLength(FElements, High(FElements) + 2); + FElements[High(FElements)]:= TBHRElement.Create(self); + Result:= FElements[High(FElements)]; + Result.Top:= FLastY; + Result.MinHeight:= h; + Result.Bottom:= Result.Top + h; + Result.Left:= Rect.Left; + Result.Right:= Rect.Right; + if High(FElements) > 0 then + begin + Result.Prior:= FElements[High(FElements)-1]; + FElements[High(FElements)-1].Next:= Result; + end; +end; + +Function TBHRDocument.AddText(Rect : TRect; s : string) : TBHRText; +var n : integer; + line : string; + ch : TSysCharSet; +//const lnrt = #10#13; +begin + Result:= NIL; + CalcRects; + SetLength(FElements, High(FElements) + 2); + FElements[High(FElements)]:= TBHRText.Create(self); + Result:= TBHRText(FElements[High(FElements)]); + ch:= [#10]; + n:= 1; Line:= ''; + repeat + Line:= ExtractWord(n, s, ch); + if Line <> '' then Result.AddString(Line); + inc(n); + until Line = ''; + +// Result.AddString(s); + Result.Top:= FLastY; + Result.Left:= Rect.Left; + Result.Right:= Rect.Right; + if High(FElements) > 0 then + begin + Result.Prior:= FElements[High(FElements)-1]; + FElements[High(FElements)-1].Next:= Result; + end; +end; + +Function TBHRDocument.AddTable(Rect : TRect; nCol, nRow : integer) : TBHRTable; +begin + Result:= NIL; + CalcRects; + SetLength(FElements, High(FElements) + 2); + FElements[High(FElements)]:= TBHRTable.Create(self); + Result:= TBHRTable(FElements[High(FElements)]); + Result.Top:= Rect.Top; + Result.Left:= Rect.Left; + Result.Right:= Rect.Right; + Result.SetSize(nRow, nCol); + Result.ColsEven:= TRUE; +// Result.AutoHeight:= TRUE; + Result.Top:= FLastY; + if High(FElements) > 0 then + begin + Result.Prior:= FElements[High(FElements)-1]; + FElements[High(FElements)-1].Next:= Result; + end; +end; + +Function TBHRDocument.AddImage(Rect : TRect) : TBHRImage; +begin + Result:= NIL; + CalcRects; + SetLength(FElements, High(FElements) + 2); + FElements[High(FElements)]:= TBHRImage.Create(self); + Result:= TBHRImage(FElements[High(FElements)]); + Result.Top:= FLastY; + Result.Left:= Rect.Left; + Result.Right:= Rect.Right; + if High(FElements) > 0 then + begin + Result.Prior:= FElements[High(FElements)-1]; + FElements[High(FElements)-1].Next:= Result; + end; +end; + +{Function TBHRDocument.AddGraph(Rect : TRect) : TBHRBHGraph; +begin + Result:= NIL; + CalcRects; + SetLength(FElements, High(FElements) + 2); + FElements[High(FElements)]:= TBHRBHGraph.Create(self); + Result:= TBHRBHGraph(FElements[High(FElements)]); + Result.Top:= FLastY; + Result.Left:= Rect.Left; + Result.Right:= Rect.Right; + if High(FElements) > 0 then + begin + Result.Prior:= FElements[High(FElements)-1]; + FElements[High(FElements)-1].Next:= Result; + end; +end; } + +Function TBHRDocument.AddChart(Rect : TRect) : TBHRChart; +begin + Result:= NIL; + CalcRects; + SetLength(FElements, High(FElements) + 2); + FElements[High(FElements)]:= TBHRChart.Create(self); + Result:= TBHRChart(FElements[High(FElements)]); + Result.Top:= FLastY; + Result.Left:= Rect.Left; + Result.Right:= Rect.Right; + if High(FElements) > 0 then + begin + Result.Prior:= FElements[High(FElements)-1]; + FElements[High(FElements)-1].Next:= Result; + end; +end; + +Function TBHRDocument.GetElement(i : integer) : TBHRElement; +begin + Result:= NIL; + if (i >= Low(FElements)) and (i <= High(FElements)) then + Result:= FElements[i]; +end; + +Procedure TBHRDocument.Print(FromPage, ToPage, Copies : integer); +var p, i : integer; +begin + try + if Printer <> NIL then + begin + for i:= 1 to Copies do + begin + Printer.BeginDoc; + Printer.Canvas.CopyMode:= cmSrcCopy; + for p:= FromPage to ToPage do + begin + DrawPage(Printer.Canvas, p, 1); + if p < ToPage then Printer.NewPage; + end; + Printer.EndDoc; + end; + end; + finally + end; +end; + +Procedure TBHRDocument.PrintPreview; +var fpp : TFrmPrintPreview; +begin + CalcRects; + fpp:= TFrmPrintPreview.Create(FrmMain); + fpp.Execute(self); + { try + CalcRects; + FrmPrintPreview:= TFrmPrintPreview.Create(FrmMain); + FrmPrintPreview.Execute(self); + finally + FrmPrintPreview.Free; + Free; + end; } +end; + +Procedure TBHRDocument.DrawPages(cnvs : TCanvas; Scale : single); +var p : integer; +begin + if Printer <> NIL then + for p:= 1 to FNumPages do + begin + DrawPage(cnvs, p, Scale); + if p < FNumPages then Printer.NewPage; + end; +end; + +Procedure TBHRDocument.DrawPage(cnvs : TCanvas; PageNr : integer; Scale : single); +var i : integer; + E : TBHRElement; + SRect : TRect; +begin + CalcRects; + with Cnvs do + begin + Brush.Color:= clWhite; + Pen.Color:= clWhite; + SRect:= ScaleRect(FPageRect, Scale); + Rectangle(SRect); + end; + FFooter.Text:= 'Bladzijde '+ IntToStr(PageNr) + ' van ' + IntToStr(NumPages); + if FHeader <> NIL then FHeader.Draw(Cnvs, PageNr, Scale); + if FFooter <> NIL then FFooter.Draw(Cnvs, PageNr, Scale); + + for i:= Low(FElements) to High(FElements) do + begin + E:= Element[i]; + if E <> NIL then + E.Draw(cnvs, PageNr, Scale); + end; +end; + +Procedure TBHRDocument.Repaginate; +begin + CalcRects; +end; + +end. + diff --git a/Source/Units/backup/containers.pas b/Source/Units/backup/containers.pas new file mode 100644 index 00000000..2cfc1d00 --- /dev/null +++ b/Source/Units/backup/containers.pas @@ -0,0 +1,3524 @@ +unit Containers; + +{$mode objfpc}{$H+} + +interface + +uses + Classes, SysUtils, {$ifdef Windows}windows, windirs, {$endif}Forms, Controls, Dialogs, + Data, Hulpfuncties, DOM, XMLRead, XMLWrite, XMLUtils, variants, frimport; + +type + TContainer = class(TObject) + private + FFileName : string; + FImportFileName : string; + FLabel : string; + FCollection : array of TBase; + FSelected : integer; + FDoc : TXMLDocument; + FRootNode, FChild : TDOMNode; + Procedure SetSelected(i : integer); + public + Constructor Create; virtual; + Destructor Destroy; override; + Procedure SaveXML; virtual; + Procedure ReadXML; virtual; + Function ImportXML : boolean; virtual; + Procedure SortByIndex(Index : integer; Decending : boolean; Nstart, Nend : integer); + Procedure SortByIndex2(I1, I2 : integer; Decending : boolean); + Procedure SortByName(s : string); + Procedure UnSelect; + Function AddItem : TBase; virtual; + Procedure InsertItem(i : integer); virtual; + Procedure RemoveItem(i : integer); virtual; + Procedure RemoveByReference(Item : TBase); virtual; + Procedure FreeCollection; + Function GetNumItems : integer; + Function GetItem(i : integer) : TBase; + Function FindByName(s : string) : TBase; + Function FindByNameOnStock(s : string) : TBase; + Function FindByAutoNr(i : integer) : TBase; + Procedure RemoveByAutoNr(i : integer); + Function IndexByName(s : string) : integer; + property Item[i: integer] : TBase read GetItem; + published + property FileName : string read FFileName write FFileName; + property ImportFileName : string read FImportFileName; + property Selected : integer read FSelected write SetSelected; + property NodeLabel : string read FLabel write FLabel; + property NumItems : integer read GetNumItems; + end; + + TFermentables = class(TContainer) + private + public + Constructor Create; override; + Procedure SaveXML; override; + Procedure ReadXML; override; + Function ImportXML : boolean; override; + Function GetSelectedItem : TFermentable; + Function AddItem : TFermentable; + Procedure InsertItem(i : integer); override; + Function FindByNameAndSupplier(N, S : string) : TFermentable; + published + property SelectedItem : TFermentable read GetSelectedItem; + end; + + THops = class(TContainer) + private + public + Constructor Create; override; + Procedure SaveXML; override; + Procedure ReadXML; override; + Function ImportXML : boolean; override; + Function GetSelectedItem : THop; + Function AddItem : THop; + Procedure InsertItem(i : integer); override; + Function FindByNameAndOriginAndAlfa(N, O : string; A : double) : THop; + published + property SelectedItem : THop read GetSelectedItem; + end; + + TMiscs = class(TContainer) + private + public + Constructor Create; override; + Procedure SaveXML; override; + Procedure ReadXML; override; + Function ImportXML : boolean; override; + Function GetSelectedItem : TMisc; + Function AddItem : TMisc; + Procedure InsertItem(i : integer); override; + published + property SelectedItem : TMisc read GetSelectedItem; + end; + + TYeasts = class(TContainer) + private + public + Constructor Create; override; + Procedure SaveXML; override; + Procedure ReadXML; override; + Function ImportXML : boolean; override; + Function GetSelectedItem : TYeast; + Function AddItem : TYeast; + Procedure InsertItem(i : integer); override; + Function FindByNameAndLaboratory(N, L : string) : TYeast; + published + property SelectedItem : TYeast read GetSelectedItem; + end; + + TWaters = class(TContainer) + private + public + Constructor Create; override; + Procedure SaveXML; override; + Procedure ReadXML; override; + Function ImportXML : boolean; override; + Function GetSelectedItem : TWater; + Function AddItem : TWater; + Procedure InsertItem(i : integer); override; + Function GetDefaultWater : TWater; + Function GetDemiWater : TWater; + published + property SelectedItem : TWater read GetSelectedItem; + end; + + TEquipments = class(TContainer) + private + public + Constructor Create; override; + Procedure SaveXML; override; + Procedure ReadXML; override; +// Function ImportXML : boolean; override; + Function GetSelectedItem : TEquipment; + Function AddItem : TEquipment; + Procedure InsertItem(i : integer); override; + Procedure CalcEfficiencyRegressionFactors; + Procedure CalcAttenuationRegressionFactors; + published + property SelectedItem : TEquipment read GetSelectedItem; + end; + + TBeerStyles = class(TContainer) + private + public + Constructor Create; override; + Procedure SaveXML; override; + Procedure ReadXML; override; + Function ImportXML : boolean; override; + Function GetSelectedItem : TBeerStyle; + Function AddItem : TBeerStyle; + Procedure InsertItem(i : integer); override; + published + property SelectedItem : TBeerStyle read GetSelectedItem; + end; + + TMashs = class(TContainer) + private + public + Constructor Create; override; + Procedure SaveXML; override; + Procedure ReadXML; override; + Function ImportXML : boolean; override; + Function GetSelectedItem : TMash; + Function AddItem : TMash; + Procedure InsertItem(i : integer); override; + published + property SelectedItem : TMash read GetSelectedItem; + end; + + TMinMax = record + Name : string; + PercRecipes : single; //% of recipes with ingredient + MinUse, AvUse, MaxUse : single; //use of the ingredient in recipes' + end; + + TMinMaxArray = array of TMinMax; + + TRecipes = class(TContainer) + private + FFermentablesMinMaxArray : TMinMaxArray; + FBitterhopMinMaxArray : TMinMaxArray; + FAromahopMinMaxArray : TMinMaxArray; + FDryhopMinMaxArray : TMinMaxArray; + FYeastMinMaxArray : TMinMaxArray; + FMiscMinMaxArray : TMinMaxArray; + FCommonMinMaxArray : TMinMaxArray; + Procedure QuickSortRecipes(var Arr : array of TBase); + Function ImportXMLs(FN : TStrings; DN : string; Equip : TEquipment) : boolean; + Function ImportXML(FN : string; Equip : TEquipment) : boolean; + Function ImportRECs(FN : TStrings; DN : string; Equip : TEquipment) : boolean; + Function ImportREC(FN : string; Equip : TEquipment) : boolean; + Function GetLastNrRecipe : string; + Procedure QuickSortA(var Arr : array of TMinMax); + Function Exists(Arr : TMinMaxArray; FName : string) : integer; + Function GetMaxAutoNr : integer; + public + Constructor Create; override; + Destructor Destroy; override; + Procedure SaveXML; override; + Procedure ReadXML; override; + Procedure CheckAutoNrs; + Function ImportFiles(FN : TStrings; DN : string; Equip : TEquipment; + FT : TFileType) : boolean; + Procedure Sort; + Function GetSelectedItem : TRecipe; + Function AddItem : TRecipe; + Procedure InsertItem(i : integer); override; + Function FindByNameAndNr(Nm, Nr : string) : TRecipe; + Function FindByAutoNr(nr : integer) : TRecipe; + Function ExportToCSV(A : array of integer) : boolean; + Function AnalyseFermentables(Lett, Nm : string) : integer; //returns number of recipes + Function AnalyseHops(Lett, Nm : string) : integer; //returns number of recipes + Function AnalyseYeasts(Lett, Nm : string) : integer; //returns number of recipes + Function AnalyseMiscs(Lett, Nm : string) : integer; + Function AnalyseRecipes(Lett, Nm : string) : integer; + property FermentablesMinMaxArray : TMinMaxArray read FFermentablesMinMaxArray; + property BitterhopMinMaxArray : TMinMaxArray read FBitterhopMinMaxArray; + property AromahopMinMaxArray : TMinMaxArray read FAromahopMinMaxArray; + property DryhopMinMaxArray : TMinMaxArray read FDryhopMinMaxArray; + property YeastMinMaxArray : TMinMaxArray read FYeastMinMaxArray; + property MiscMinMaxArray : TMinMaxArray read FMiscMinMaxArray; + property CommonMinMaxArray : TMinMaxArray read FCommonMinMaxArray; + published + property SelectedItem : TRecipe read GetSelectedItem; + property LastNrRecipe : string read GetLastNrRecipe; + property MaxAutoNr : integer read GetMaxAutoNr; + end; + + TStyleRec = record + Name : string; + Recipes : array of TRecipe; + end; + + TStyleLetters = record + Letter : string; + Styles : array of TStyleRec; + end; + + TRecipesByStyle = class(TObject) + private + FStyleLetters : array of TStyleLetters; + FCollection : TRecipes; + Procedure Fill; + Procedure Empty; + Procedure Sort; + Function GetNumStyleLetters : integer; + Function GetNumStyles(i : integer) : integer; + Function GetStyleLetter(i : integer) : string; + Function GetStyleName(n : integer; s : integer) : string; + Function GetNumRecipes(n : integer; s : integer) : integer; + Function GetRecipe(n : integer; s : integer; i : integer) : TRecipe; + Procedure QuickSortInStyles(var Arr : array of TRecipe); + Procedure QuickSortStyles(var Arr : array of TStyleRec); + Procedure QuickSortLetters(var Arr : array of TStyleLetters); + public + Constructor Create(R : TRecipes); + Destructor Destroy; override; + Procedure SaveXML; + Function GetLetterByName(Num : string) : integer; + Function GetStyleByName(Num, Stl : string) : integer; + property NumStyles[i : integer] : integer read GetNumStyles; + property NumRecipes[n : integer; s : integer] : integer read GetNumRecipes; + property Recipe[n : integer; s : integer; i : integer] : TRecipe read GetRecipe; + property StyleLetter[i : integer] : string read GetStyleLetter; + property StyleName[n : integer; s : integer] : string read GetStyleName; + published + property NumStyleLetters : integer read GetNumStyleLetters; + end; + + Procedure Reload; + Procedure Backup; + Procedure Restore(sourcedata : string); + Procedure CheckBeerStyle(Rec : TRecipe); + Procedure CheckFermentables(Rec : TRecipe); + Procedure CheckYeasts(Rec : TRecipe); + Procedure CheckDataFolder; + Procedure ChangeDatabaseLocation(source, destination : string; copy, deleteold : boolean); + +var + Fermentables : TFermentables; + Hops : THops; + Miscs : TMiscs; + Yeasts : TYeasts; + Waters : TWaters; + Equipments : TEquipments; + Beerstyles : TBeerstyles; + Mashs : TMashs; + Recipes : TRecipes; + Brews : TRecipes; + + Loc : string; + + Arr : array of longint; + +implementation + +uses frmain, ComCtrls, frselectbeerstyle, fileutil, LazFileUtils, promashimport, cloud, subs, + neuroot, strutils, math; + +Procedure CheckSalts; +var M : TMisc; +begin + if Miscs.FindByName('CaCl2') = NIL then + begin + M:= Miscs.AddItem; + M.Name.Value:= 'CaCl2'; + M.AmountIsWeight.Value:= true; + M.Amount.vUnit:= kilogram; + M.Amount.DisplayUnit:= gram; + M.Amount.Value:= 0; + M.MiscType:= mtWaterAgent; + M.Use:= muMash; + M.UseFor.Value:= 'Voor het maken van een ander waterprofiel. Voegt calcium en chloride toe. Voor het verbeteren van zoetere bieren.'; + M.Inventory.vUnit:= M.Amount.vUnit; + M.Inventory.DisplayUnit:= M.Amount.DisplayUnit; + M.Inventory.Value:= 0; + end; + if Miscs.FindByName('CaCO3') = NIL then + begin + M:= Miscs.AddItem; + M.Name.Value:= 'CaCO3'; + M.AmountIsWeight.Value:= true; + M.Amount.vUnit:= kilogram; + M.Amount.DisplayUnit:= gram; + M.Amount.Value:= 0; + M.MiscType:= mtWaterAgent; + M.Use:= muMash; + M.UseFor.Value:= 'Kalk. Voor het maken van een ander waterprofiel. Voegt calcium en (bi)carbonaat toe. Voor het verhogen van de pH tijdens het maischen.'; + M.Inventory.vUnit:= M.Amount.vUnit; + M.Inventory.DisplayUnit:= M.Amount.DisplayUnit; + M.Inventory.Value:= 0; + end; + if Miscs.FindByName('CaSO4') = NIL then + begin + M:= Miscs.AddItem; + M.Name.Value:= 'CaSO4'; + M.AmountIsWeight.Value:= true; + M.Amount.vUnit:= kilogram; + M.Amount.DisplayUnit:= gram; + M.Amount.Value:= 0; + M.MiscType:= mtWaterAgent; + M.Use:= muMash; + M.UseFor.Value:= 'Gips. Voor het maken van een ander waterprofiel. Voegt calcium en sulfaat toe. Voor het verbeteren van bittere bieren.'; + M.Inventory.vUnit:= M.Amount.vUnit; + M.Inventory.DisplayUnit:= M.Amount.DisplayUnit; + M.Inventory.Value:= 0; + end; + if Miscs.FindByName('MgSO4') = NIL then + begin + M:= Miscs.AddItem; + M.Name.Value:= 'MgSO4'; + M.AmountIsWeight.Value:= true; + M.Amount.vUnit:= kilogram; + M.Amount.DisplayUnit:= gram; + M.Amount.Value:= 0; + M.MiscType:= mtWaterAgent; + M.Use:= muMash; + M.UseFor.Value:= 'Epsom zout. Voor het maken van een ander waterprofiel. Voegt magnesium en sulfaat toe. Gebruik spaarzaam!'; + M.Inventory.vUnit:= M.Amount.vUnit; + M.Inventory.DisplayUnit:= M.Amount.DisplayUnit; + M.Inventory.Value:= 0; + end; + if Miscs.FindByName('NaCl') = NIL then + begin + M:= Miscs.AddItem; + M.Name.Value:= 'NaCl'; + M.AmountIsWeight.Value:= true; + M.Amount.vUnit:= kilogram; + M.Amount.DisplayUnit:= gram; + M.Amount.Value:= 0; + M.MiscType:= mtWaterAgent; + M.Use:= muMash; + M.UseFor.Value:= 'Keukenzout. Voor het maken van een ander waterprofiel. Voegt natrium en chloride toe. Voor het accentueren van zoetheid. Bij hoge dosering wordt het bier ziltig.'; + M.Inventory.vUnit:= M.Amount.vUnit; + M.Inventory.DisplayUnit:= M.Amount.DisplayUnit; + M.Inventory.Value:= 0; + end; + if Miscs.FindByName('NaHCO3') = NIL then + begin + M:= Miscs.AddItem; + M.Name.Value:= 'NaHCO3'; + M.AmountIsWeight.Value:= true; + M.Amount.vUnit:= kilogram; + M.Amount.DisplayUnit:= gram; + M.Amount.Value:= 0; + M.MiscType:= mtWaterAgent; + M.Use:= muMash; + M.UseFor.Value:= 'Baksoda of bakpoeder. Voor het maken van een ander waterprofiel. Voegt natrium en bicarbonaat toe. Kan gebruikt worden voor verhoging van de pH tijdens het maischen.'; + M.Inventory.vUnit:= M.Amount.vUnit; + M.Inventory.DisplayUnit:= M.Amount.DisplayUnit; + M.Inventory.Value:= 0; + end; + if Miscs.FindByName('Melkzuur') = NIL then + begin + M:= Miscs.AddItem; + M.Name.Value:= 'Melkzuur'; + M.AmountIsWeight.Value:= false; + M.Amount.vUnit:= liter; + M.Amount.DisplayUnit:= milliliter; + M.Amount.Value:= 0; + M.MiscType:= mtWaterAgent; + M.Use:= muMash; + M.UseFor.Value:= 'Melkzuur wordt gebruikt voor het verlagen van de pH tijdens het maischen en het verlagen van de pH van het spoelwater.'; + M.Inventory.vUnit:= M.Amount.vUnit; + M.Inventory.DisplayUnit:= M.Amount.DisplayUnit; + M.Inventory.Value:= 0; + end; +end; + +Constructor TContainer.Create; +begin + Inherited; + FFileName:= ''; + FSelected:= -1; + FLabel:= ''; +end; + +Destructor TContainer.Destroy; +begin + FreeCollection; + Inherited; +end; + +Procedure TContainer.SaveXML; +begin + FDoc := TXMLDocument.Create; +// FDoc.Encoding:= 'ISO-8859-1'; + FRootNode := FDoc.CreateElement(FLabel); + FDoc.Appendchild(FRootNode); +end; + +Procedure TContainer.ReadXML; +var FN : string; +begin + FRootNode:= NIL; + try + FreeCollection; + FN:= Settings.DataLocation.Value + FFileName; + if FileExists(FN) then + begin + ReadXMLFile(FDoc, FN); + FRootNode:= FDoc.FindNode(FLabel); + end; + except + FDoc.Free; + end; +end; + +Function TContainer.ImportXML : boolean; +var dlg : TOpenDialog; +begin + Result:= false; + FRootNode:= NIL; + FDoc := TXMLDocument.Create; + dlg:= TOpenDialog.Create(frmMain); + with dlg do + begin + DefaultExt:= '.xml'; + FileName:= '*.xml'; + Filter:= 'BrewBuddy xml|*.xml'; + end; + FImportFileName:= ''; + try + if (dlg.Execute) and (FileExists(dlg.FileName)) then + begin + FImportFileName:= dlg.FileName; + dlg.Free; + ReadXMLFile(FDoc, FImportFileName); + FRootNode:= FDoc.FindNode(FLabel); + Result:= TRUE; + end; + except + FDoc.Free; + end; +end; + +Procedure TContainer.SortByIndex(Index : integer; Decending : boolean; Nstart, Nend : integer); + procedure QuickSort(var A: array of TBase; iLo, iHi: Integer); + var Lo, Hi: Integer; + v : variant; + TB : TBase; + begin + Lo := iLo; + Hi := iHi; + v:= A[(Lo + Hi) div 2].ValueByIndex[Index]; + repeat + while A[Lo].ValueByIndex[Index] < v do Inc(Lo); + while A[Hi].ValueByIndex[Index] > v do Dec(Hi); + if Lo <= Hi then + begin + TB:= A[Lo]; + A[Lo]:= A[Hi]; + A[Hi]:= TB; + Inc(Lo); + Dec(Hi); + end; + until Lo > Hi; + if Hi > iLo then QuickSort(A, iLo, Hi); + if Lo < iHi then QuickSort(A, Lo, iHi); + end; + + procedure QuickSortDec(var A: array of TBase; iLo, iHi: Integer); + var Lo, Hi: Integer; + v : variant; + TB : TBase; + begin + Lo := iLo; + Hi := iHi; + v:= A[(Lo + Hi) div 2].ValueByIndex[Index]; + repeat + while A[Lo].ValueByIndex[Index] > v do Inc(Lo); + while A[Hi].ValueByIndex[Index] < v do Dec(Hi); + if Lo <= Hi then + begin + TB := A[Lo]; + A[Lo] := A[Hi]; + A[Hi] := TB; + Inc(Lo); + Dec(Hi); + end; + until Lo > Hi; + if Hi > iLo then QuickSortDec(A, iLo, Hi); + if Lo < iHi then QuickSortDec(A, Lo, iHi); + end; + +begin + if (High(FCollection) > 0) and (Index > -1) then + begin + if (NEnd = 0) or (NStart >= NEnd) then + begin + NStart:= Low(FCollection); + NEnd:= High(FCollection); + end; + if Decending then + QuickSortDec(FCollection, NStart, NEnd) + else + QuickSort(FCollection, NStart, NEnd); + end; +end; + +Procedure TContainer.SortByIndex2(I1, I2 : integer; Decending : boolean); +var a, b : integer; + V1 : variant; +begin + SortByIndex(I1, Decending, 0, 0); + a:= 0; b:= 1; + while b <= High(FCollection) do + begin + V1:= FCollection[a].ValueByIndex[I1]; + while (b <= High(FCollection)) and (FCollection[b].ValueByIndex[I1] = V1) do + Inc(b); + if (a < (b-1)) then + SortByIndex(I2, Decending, a, b-1); + a:= b; + end; +end; + +Procedure TContainer.SortByName(s : string); +var i : integer; +begin + if High(FCollection) > -1 then + begin + i:= FCollection[0].IndexByName[s]; + if i > -1 then SortByIndex(i, false, 0, 0); + end; +end; + +Procedure TContainer.FreeCollection; +var i : integer; +begin + for i:= Low(FCollection) to High(FCollection) do + FCollection[i].Free; + SetLength(FCollection, 0); +end; + +Procedure TContainer.SetSelected(i : integer); +begin + if (i >= Low(FCollection)) and (i <= High(FCollection)) then + FSelected:= i; +end; + +Procedure TContainer.UnSelect; +begin + FSelected:= -1; +end; + +Function TContainer.AddItem : TBase; +begin + Result:= NIL; + try + SetLength(FCollection, High(FCollection)+2); + FSelected:= High(FCollection); + Result:= FCollection[FSelected]; +// Result.AutoNr.Value:= MaxAutoNr; + finally + end; +end; + +Procedure TContainer.InsertItem(i : integer); +var j : integer; +begin + if (i >= Low(FCollection)) and (i <= High(FCollection)) then + begin + SetLength(FCollection, High(FCollection)+2); + for j:= High(FCollection) downto i + 1 do + FCollection[j]:= FCollection[j-1]; + end; +end; + +Procedure TContainer.RemoveItem(i : integer); +var j : integer; +begin + if (i >= Low(FCollection)) and (i <= High(FCollection)) then + begin + FCollection[i].Free; + for j:= i to High(FCollection) - 1 do + FCollection[j]:= FCollection[j+1]; + SetLength(FCollection, High(FCollection)); + end; +end; + +Procedure TContainer.RemoveByReference(Item : TBase); +var i : integer; +begin + for i:= Low(FCollection) to High(FCollection) do + if FCollection[i] = Item then + begin + RemoveItem(i); + Exit; + end; +end; + +Function TContainer.FindByName(s : string) : TBase; +var i : integer; +begin + Result:= NIL; + for i:= Low(FCollection) to High(FCollection) do + if Trim(UpperCase(FCollection[i].Name.Value)) = Trim(Uppercase(s)) then + begin + Result:= FCollection[i]; + Exit; + end; +end; + +Function TContainer.FindByNameOnStock(s : string) : TBase; +var i : integer; + ing : TIngredient; +begin + Result:= NIL; + ing:= NIL; + for i:= Low(FCollection) to High(FCollection) do + begin + if FCollection[i] is TIngredient then + begin + if Trim(UpperCase(FCollection[i].Name.Value)) = Trim(Uppercase(s)) then + begin + ing:= TIngredient(FCollection[i]); + if Result = NIL then Result:= ing + else + begin + if ing.Inventory.Value > TIngredient(Result).Inventory.Value then + Result:= ing; + end; + end; + end; + end; +end; + +Function TContainer.IndexByName(s : string) : integer; +var i : integer; +begin + Result:= -1; + for i:= Low(FCollection) to High(FCollection) do + if Trim(UpperCase(FCollection[i].Name.Value)) = Trim(Uppercase(s)) then + begin + Result:= i; + Exit; + end; +end; + +Function TContainer.FindByAutoNr(i : integer) : TBase; +var j : integer; +begin + Result:= NIL; + for j:= 0 to High(FCollection) do + if FCollection[j].AutoNr.Value = i then + begin + Result:= FCollection[j]; + Exit; + end; +end; + +Procedure TContainer.RemoveByAutoNr(i : integer); +var j : integer; +begin + for j:= Low(FCollection) to High(FCollection) do + if FCollection[j].AutoNr.Value = i then + begin + RemoveItem(j); + Exit; + end; +end; + +Function TContainer.GetNumItems : integer; +begin + Result:= High(FCollection) + 1; +end; + +Function TContainer.GetItem(i : integer) : TBase; +begin + Result:= NIL; + if (i >= Low(FCollection)) and (i <= High(FCollection)) then + Result:= FCollection[i]; +end; + + +{=========================== TFermentables ====================================} + +Constructor TFermentables.Create; +begin + Inherited; + FLabel:= 'FERMENTABLES'; + FFileName:= 'fermentables.xml'; +end; + +Procedure TFermentables.SaveXML; +var i : integer; + FN : string; +begin + try + Inherited SaveXML; + FN:= Settings.DataLocation.Value + FFileName; + for i:= Low(FCollection) to High(FCollection) do + TFermentable(FCollection[i]).SaveXML(FDoc, FRootNode, false); + writeXMLFile(FDoc, FN); + finally + FDoc.Free; + end; +end; + +Procedure TFermentables.ReadXML; +var i : integer; +begin + Inherited ReadXML; + if FRootNode <> NIL then + begin + try + i:= 0; + FChild:= FRootNode.FirstChild; + while FChild <> NIL do + begin + inc(i); + SetLength(FCollection, i); + FCollection[i-1]:= TFermentable.Create(NIL); + TFermentable(FCollection[i-1]).ReadXML(FChild); + FChild:= FChild.NextSibling; + end; + finally + FDoc.Free; + end; + end; +end; + +Function TFermentables.ImportXML : boolean; +var i : integer; +begin + Inherited ImportXML; + if FRootNode <> NIL then + begin + try + i:= High(FCollection) + 1; + FChild:= FRootNode.FirstChild; + while FChild <> NIL do + begin + inc(i); + SetLength(FCollection, i); + FCollection[i-1]:= TFermentable.Create(NIL); + TFermentable(FCollection[i-1]).ReadXML(FChild); + if TFermentable(FCollection[i-1]).Yield.Value < 1 then + RemoveByReference(FCollection[i-1]); + FChild:= FChild.NextSibling; + end; + Result:= TRUE; + finally + FDoc.Free; + end; + end; +end; + +Function TFermentables.GetSelectedItem : TFermentable; +begin + Result:= NIL; + if FSelected > -1 then + Result:= TFermentable(FCollection[FSelected]); +end; + +Function TFermentables.AddItem : TFermentable; +begin + Result:= NIL; + try + SetLength(FCollection, High(FCollection)+2); + FSelected:= High(FCollection); + FCollection[High(FCollection)]:= TFermentable.Create(NIL); + Result:= TFermentable(FCollection[High(FCollection)]); + finally + end; +end; + +Procedure TFermentables.InsertItem(i : integer); +begin + Inherited; + if (i >= Low(FCollection)) and (i <= High(FCollection)) then + FCollection[i]:= TFermentable.Create(NIL); +end; + +Function TFermentables.FindByNameAndSupplier(N, S : string) : TFermentable; +var i : integer; +begin + Result:= NIL; + if (N <> '') AND (S <> '') then + begin + for i:= Low(FCollection) to High(FCollection) do + if (Lowercase(TFermentable(FCollection[i]).Name.Value) = Lowercase(N)) and + (Lowercase(TFermentable(FCollection[i]).Supplier.Value) = Lowercase(S)) then + begin + Result:= TFermentable(FCollection[i]); + Exit; + end; + end; +end; + +{================================== THops =====================================} + +Constructor THops.Create; +begin + Inherited; + FLabel:= 'HOPS'; + FFileName:= 'hops.xml'; + FSelected:= -1; +end; + +Procedure THops.SaveXML; +var i : integer; + FN : string; +begin + try + Inherited SaveXML; + for i:= Low(FCollection) to High(FCollection) do + THop(FCollection[i]).SaveXML(FDoc, FRootNode, false); + FN:= Settings.DataLocation.Value + FFileName; + writeXMLFile(FDoc, FN); + finally + FDoc.Free; + end; +end; + +Procedure THops.ReadXML; +var i : integer; +begin + Inherited ReadXML; + if FRootNode <> NIL then + begin + try + i:= 0; + FChild:= FRootNode.FirstChild; + while FChild <> NIL do + begin + inc(i); + SetLength(FCollection, i); + FCollection[i-1]:= THop.Create(NIL); + THop(FCollection[i-1]).ReadXML(FChild); + FChild:= FChild.NextSibling; + end; + finally + FDoc.Free; + end; + end; +end; + +Function THops.ImportXML : boolean; +var i : integer; +begin + Inherited ImportXML; + if FRootNode <> NIL then + begin + try + i:= High(FCollection) + 1; + FChild:= FRootNode.FirstChild; + while FChild <> NIL do + begin + inc(i); + SetLength(FCollection, i); + FCollection[i-1]:= THop.Create(NIL); + THop(FCollection[i-1]).ReadXML(FChild); + if THop(FCollection[i-1]).Alfa.Value <= 0.5 then + RemoveByReference(FCollection[i-1]); + FChild:= FChild.NextSibling; + end; + Result:= TRUE; + finally + FDoc.Free; + end; + end; +end; + +Function THops.GetSelectedItem : THop; +begin + Result:= NIL; + if FSelected > -1 then + Result:= THop(FCollection[FSelected]); +end; + +Function THops.AddItem : THop; +begin + Result:= NIL; + try + SetLength(FCollection, High(FCollection)+2); + FSelected:= High(FCollection); + Result:= NIL; + FCollection[High(FCollection)]:= THop.Create(NIL); + Result:= THop(FCollection[FSelected]); + finally + end; +end; + +Procedure THops.InsertItem(i : integer); +begin + Inherited; + if (i >= Low(FCollection)) and (i <= High(FCollection)) then + FCollection[i]:= THop.Create(NIL); +end; + +Function THops.FindByNameAndOriginAndAlfa(N, O : string; A : double) : THop; +var i : integer; + A2 : double; + N2, O2 : string; +begin + Result:= NIL; + N:= LowerCase(Trim(N)); + O:= LowerCase(Trim(O)); + A:= RoundTo(A, -1); + if (N <> '') AND (O <> '') then + begin + for i:= Low(FCollection) to High(FCollection) do + begin + N2:= Lowercase(Trim(THop(FCollection[i]).Name.Value)); + O2:= Lowercase(Trim(THop(FCollection[i]).Origin.Value)); + A2:= THop(FCollection[i]).Alfa.Value; + A2:= RoundTo(A2, -1); + if (N2 = N) and (O2 = O) and (A2 = A) then + begin + Result:= THop(FCollection[i]); + Exit; + end; + end; + end; +end; + +{================================== TMiscs ====================================} + +Constructor TMiscs.Create; +begin + Inherited; + FLabel:= 'MISCS'; + FFileName:= 'miscs.xml'; + FSelected:= -1; +end; + +Procedure TMiscs.SaveXML; +var i : integer; + FN : string; +begin + try + Inherited SaveXML; + FN:= Settings.DataLocation.Value + FFileName; + for i:= Low(FCollection) to High(FCollection) do + TMisc(FCollection[i]).SaveXML(FDoc, FRootNode, false); + writeXMLFile(FDoc, FN); + finally + FDoc.Free; + end; +end; + +Procedure TMiscs.ReadXML; +var i : integer; +begin + Inherited ReadXML; + if FRootNode <> NIL then + begin + try + i:= 0; + FChild:= FRootNode.FirstChild; + while FChild <> NIL do + begin + inc(i); + SetLength(FCollection, i); + FCollection[i-1]:= TMisc.Create(NIL); + TMisc(FCollection[i-1]).ReadXML(FChild); + FChild:= FChild.NextSibling; + end; + finally + FDoc.Free; + end; + end; +end; + +Function TMiscs.ImportXML : boolean; +var i : integer; +begin + Inherited ImportXML; + if FRootNode <> NIL then + begin + try + i:= High(FCollection) + 1; + FChild:= FRootNode.FirstChild; + while FChild <> NIL do + begin + inc(i); + SetLength(FCollection, i); + FCollection[i-1]:= TMisc.Create(NIL); + TMisc(FCollection[i-1]).ReadXML(FChild); + {if TMisc(FCollection[i-1])..Value < 1 then + RemoveByReference(FCollection[i-1]);} + FChild:= FChild.NextSibling; + end; + Result:= TRUE; + finally + FDoc.Free; + end; + end; +end; + +Function TMiscs.GetSelectedItem : TMisc; +begin + Result:= NIL; + if FSelected > -1 then + Result:= TMisc(FCollection[FSelected]); +end; + +Function TMiscs.AddItem : TMisc; +begin + Result:= NIL; + try + SetLength(FCollection, High(FCollection)+2); + FSelected:= High(FCollection); + FCollection[High(FCollection)]:= TMisc.Create(NIL); + Result:= TMisc(FCollection[High(FCollection)]); + finally + end; +end; + +Procedure TMiscs.InsertItem(i : integer); +begin + Inherited; + if (i >= Low(FCollection)) and (i <= High(FCollection)) then + FCollection[i]:= TMisc.Create(NIL); +end; + +{================================== TYeasts ===================================} + +Constructor TYeasts.Create; +begin + Inherited; + FLabel:= 'YEASTS'; + FFileName:= 'yeasts.xml'; + FSelected:= -1; +end; + +Procedure TYeasts.SaveXML; +var i : integer; + FN : string; +begin + try + Inherited SaveXML; + FN:= Settings.DataLocation.Value + FFileName; + for i:= Low(FCollection) to High(FCollection) do + TYeast(FCollection[i]).SaveXML(FDoc, FRootNode, false); + writeXMLFile(FDoc, FN); + finally + FDoc.Free; + end; +end; + +Procedure TYeasts.ReadXML; +var i : integer; +begin + Inherited ReadXML; + if FRootNode <> NIL then + begin + try + i:= 0; + FChild:= FRootNode.FirstChild; + while FChild <> NIL do + begin + inc(i); + SetLength(FCollection, i); + FCollection[i-1]:= TYeast.Create(NIL); + TYeast(FCollection[i-1]).ReadXML(FChild); + FChild:= FChild.NextSibling; + end; + finally + FDoc.Free; + end; + end; +end; + +Function TYeasts.ImportXML : boolean; +var i : integer; +begin + Inherited ImportXML; + if FRootNode <> NIL then + begin + try + i:= High(FCollection) + 1; + FChild:= FRootNode.FirstChild; + while FChild <> NIL do + begin + inc(i); + SetLength(FCollection, i); + FCollection[i-1]:= TYeast.Create(NIL); + TYeast(FCollection[i-1]).ReadXML(FChild); + if TYeast(FCollection[i-1]).Laboratory.Value = '' then + RemoveByReference(FCollection[i-1]); + FChild:= FChild.NextSibling; + end; + Result:= TRUE; + finally + FDoc.Free; + end; + end; +end; +Function TYeasts.GetSelectedItem : TYeast; +begin + Result:= NIL; + if FSelected > -1 then + Result:= TYeast(FCollection[FSelected]); +end; + +Function TYeasts.AddItem : TYeast; +begin + Result:= NIL; + try + SetLength(FCollection, High(FCollection)+2); + FSelected:= High(FCollection); + FCollection[High(FCollection)]:= TYeast.Create(NIL); + Result:= TYeast(FCollection[High(FCollection)]); + finally + end; +end; + +Procedure TYeasts.InsertItem(i : integer); +begin + Inherited; + if (i >= Low(FCollection)) and (i <= High(FCollection)) then + FCollection[i]:= TYeast.Create(NIL); +end; + +Function TYeasts.FindByNameAndLaboratory(N, L : string) : TYeast; +var i : integer; +begin + Result:= NIL; + if (N <> '') and (L <> '') then + begin + for i:= Low(FCollection) to High(FCollection) do + if (Lowercase(TYeast(FCollection[i]).Name.Value) = Lowercase(N)) and + (Lowercase(TYeast(FCollection[i]).Laboratory.Value) = Lowercase(L)) then + begin + Result:= TYeast(FCollection[i]); + Exit; + end; + end; +end; + +{================================== TWaters ===================================} + +Constructor TWaters.Create; +begin + Inherited; + FLabel:= 'WATERS'; + FFileName:= 'waters.xml'; + FSelected:= -1; +end; + +Procedure TWaters.SaveXML; +var i : integer; + FN : string; +begin + try + Inherited SaveXML; + FN:= Settings.DataLocation.Value + FFileName; + for i:= Low(FCollection) to High(FCollection) do + TWater(FCollection[i]).SaveXML(FDoc, FRootNode, false); + writeXMLFile(FDoc, FN); + finally + FDoc.Free; + end; +end; + +Procedure TWaters.ReadXML; +var i : integer; +begin + Inherited ReadXML; + if FRootNode <> NIL then + begin + try + i:= 0; + FChild:= FRootNode.FirstChild; + while FChild <> NIL do + begin + inc(i); + SetLength(FCollection, i); + FCollection[i-1]:= TWater.Create(NIL); + TWater(FCollection[i-1]).ReadXML(FChild); + FChild:= FChild.NextSibling; + end; + finally + FDoc.Free; + end; + end; +end; + +Function TWaters.ImportXML : boolean; +var i : integer; +begin + Inherited ImportXML; + if FRootNode <> NIL then + begin + try + i:= High(FCollection) + 1; + FChild:= FRootNode.FirstChild; + while FChild <> NIL do + begin + inc(i); + SetLength(FCollection, i); + FCollection[i-1]:= TWater.Create(NIL); + TWater(FCollection[i-1]).ReadXML(FChild); + if TWater(FCollection[i-1]).Bicarbonate.Value < 0.1 then + RemoveByReference(FCollection[i-1]); + FChild:= FChild.NextSibling; + end; + Result:= TRUE; + finally + FDoc.Free; + end; + end; +end; + +Function TWaters.GetSelectedItem : TWater; +begin + Result:= NIL; + if FSelected > -1 then + Result:= TWater(FCollection[FSelected]); +end; + +Function TWaters.AddItem : TWater; +begin + Result:= NIL; + try + SetLength(FCollection, High(FCollection)+2); + FSelected:= High(FCollection); + FCollection[High(FCollection)]:= TWater.Create(NIL); + Result:= TWater(FCollection[High(FCollection)]); + finally + end; +end; + +Procedure TWaters.InsertItem(i : integer); +begin + Inherited; + if (i >= Low(FCollection)) and (i <= High(FCollection)) then + FCollection[i]:= TWater.Create(NIL); +end; + +Function TWaters.GetDefaultWater : TWater; +var i : integer; + W : TWater; +begin + Result:= NIL; + for i:= 0 to NumItems - 1 do + begin + W:= TWater(Item[i]); + if W.DefaultWater.Value then Result:= W; + end; +end; + +Function TWaters.GetDemiWater : TWater; +var i : integer; + W : TWater; +begin + Result:= NIL; + for i:= 0 to NumItems - 1 do + begin + W:= TWater(Item[i]); + if W.DemiWater then Result:= W; + end; + if Result = NIL then + W:= TWater(FindByName('Gedemineraliseerd water')); + if Result = NIL then + W:= TWater(FindByName('Demiwater')); + if Result = NIL then + W:= TWater(FindByName('Osmosewater')); +end; + +{================================== TBeerstyles ===============================} + +Constructor TBeerstyles.Create; +begin + Inherited; + FLabel:= 'STYLES'; + FFileName:= 'styles.xml'; + FSelected:= -1; +end; + +Procedure TBeerstyles.SaveXML; +var i : integer; + FN : string; +begin + try + Inherited SaveXML; + FN:= Settings.DataLocation.Value + FFileName; + for i:= Low(FCollection) to High(FCollection) do + TBeerstyle(FCollection[i]).SaveXML(FDoc, FRootNode, false); + writeXMLFile(FDoc, FN); + finally + FDoc.Free; + end; +end; + +Procedure TBeerstyles.ReadXML; +var i : integer; +begin + Inherited ReadXML; + if FRootNode <> NIL then + begin + try + i:= 0; + FChild:= FRootNode.FirstChild; + while FChild <> NIL do + begin + inc(i); + SetLength(FCollection, i); + FCollection[i-1]:= TBeerStyle.Create(NIL); + TBeerStyle(FCollection[i-1]).ReadXML(FChild); + FChild:= FChild.NextSibling; + end; + finally + FDoc.Free; + end; + end; +end; + +Function TBeerstyles.ImportXML : boolean; +var i : integer; +begin + Inherited ImportXML; + if FRootNode <> NIL then + begin + try + i:= High(FCollection) + 1; + FChild:= FRootNode.FirstChild; + while FChild <> NIL do + begin + inc(i); + SetLength(FCollection, i); + FCollection[i-1]:= TBeerstyle.Create(NIL); + TBeerstyle(FCollection[i-1]).ReadXML(FChild); + if TBeerstyle(FCollection[i-1]).StyleLetter.Value = '' then + RemoveByReference(FCollection[i-1]); + FChild:= FChild.NextSibling; + end; + Result:= TRUE; + finally + FDoc.Free; + end; + end; +end; +Function TBeerstyles.GetSelectedItem : TBeerstyle; +begin + Result:= NIL; + if FSelected > -1 then + Result:= TBeerstyle(FCollection[FSelected]); +end; + +Function TBeerstyles.AddItem : TBeerStyle; +begin + Result:= NIL; + try + SetLength(FCollection, High(FCollection)+2); + FSelected:= High(FCollection); + FCollection[High(FCollection)]:= TBeerstyle.Create(NIL); + Result:= TBeerstyle(FCollection[High(FCollection)]); + finally + end; +end; + +Procedure TBeerstyles.InsertItem(i : integer); +begin + Inherited; + if (i >= Low(FCollection)) and (i <= High(FCollection)) then + FCollection[i]:= TBeerstyle.Create(NIL); +end; + +{================================== TEquipments ===============================} + +Constructor TEquipments.Create; +begin + Inherited; + FLabel:= 'EQUIPMENTS'; + FFileName:= 'equipments.xml'; + FSelected:= -1; +end; + +Procedure TEquipments.SaveXML; +var i : integer; + FN : string; +begin + try + Inherited SaveXML; + FN:= Settings.DataLocation.Value + FFileName; + for i:= Low(FCollection) to High(FCollection) do + TEquipment(FCollection[i]).SaveXML(FDoc, FRootNode, false); + writeXMLFile(FDoc, FN); + finally + FDoc.Free; + end; +end; + +Procedure TEquipments.ReadXML; +var i : integer; +begin + Inherited ReadXML; + if FRootNode <> NIL then + begin + try + i:= 0; + FChild:= FRootNode.FirstChild; + while FChild <> NIL do + begin + inc(i); + SetLength(FCollection, i); + FCollection[i-1]:= TEquipment.Create(NIL); + TEquipment(FCollection[i-1]).ReadXML(FChild); + FChild:= FChild.NextSibling; + end; + finally + FDoc.Free; + end; + end; +end; + +Function TEquipments.GetSelectedItem : TEquipment; +begin + Result:= NIL; + if FSelected > -1 then + Result:= TEquipment(FCollection[FSelected]); +end; + +Function TEquipments.AddItem : TEquipment; +begin + Result:= NIL; + try + SetLength(FCollection, High(FCollection)+2); + FSelected:= High(FCollection); + FCollection[High(FCollection)]:= TEquipment.Create(NIL); + Result:= TEquipment(FCollection[High(FCollection)]); + finally + end; +end; + +Procedure TEquipments.InsertItem(i : integer); +begin + Inherited; + if (i >= Low(FCollection)) and (i <= High(FCollection)) then + FCollection[i]:= TEquipment.Create(NIL); +end; + +Procedure TEquipments.CalcEfficiencyRegressionFactors; +var i : integer; +begin + for i:= Low(FCollection) to High(FCollection) do + TEquipment(FCollection[i]).CalcEfficiencyFactors; +end; + +Procedure TEquipments.CalcAttenuationRegressionFactors; +var i : integer; +begin + for i:= Low(FCollection) to High(FCollection) do + TEquipment(FCollection[i]).CalcAttenuationFactors; +end; + +{================================== TMashs ====================================} + +Constructor TMashs.Create; +begin + Inherited; + FLabel:= 'MASHS'; + FFileName:= 'mashs.xml'; + FSelected:= -1; +end; + +Procedure TMashs.SaveXML; +var i : integer; + FN : string; +begin + try + Inherited SaveXML; + FN:= Settings.DataLocation.Value + FFileName; + for i:= Low(FCollection) to High(FCollection) do + TMash(FCollection[i]).SaveXML(FDoc, FRootNode, false); + writeXMLFile(FDoc, FN); + finally + FDoc.Free; + end; +end; + +Procedure TMashs.ReadXML; +var i : integer; +begin + Inherited ReadXML; + if FRootNode <> NIL then + begin + try + i:= 0; + FChild:= FRootNode.FirstChild; + while FChild <> NIL do + begin + inc(i); + SetLength(FCollection, i); + FCollection[i-1]:= TMash.Create(NIL); + TMash(FCollection[i-1]).ReadXML(FChild); + FChild:= FChild.NextSibling; + end; + finally + FDoc.Free; + end; + end; +end; + +Function TMashs.ImportXML : boolean; +var i : integer; +begin + Inherited ImportXML; + if FRootNode <> NIL then + begin + try + i:= High(FCollection) + 1; + FChild:= FRootNode.FirstChild; + while FChild <> NIL do + begin + inc(i); + SetLength(FCollection, i); + FCollection[i-1]:= TMash.Create(NIL); + TMash(FCollection[i-1]).ReadXML(FChild); + if TMash(FCollection[i-1]).NumMashSteps = 0 then + RemoveByReference(FCollection[i-1]); + FChild:= FChild.NextSibling; + end; + Result:= TRUE; + finally + FDoc.Free; + end; + end; +end; + +Function TMashs.GetSelectedItem : TMash; +begin + Result:= NIL; + if FSelected > -1 then + Result:= TMash(FCollection[FSelected]); +end; + +Function TMashs.AddItem : TMash; +begin + Result:= NIL; + try + SetLength(FCollection, High(FCollection)+2); + FSelected:= High(FCollection); + FCollection[High(FCollection)]:= TMash.Create(NIL); + Result:= TMash(FCollection[High(FCollection)]); + finally + end; +end; + +Procedure TMashs.InsertItem(i : integer); +begin + Inherited; + if (i >= Low(FCollection)) and (i <= High(FCollection)) then + FCollection[i]:= TMash.Create(NIL); +end; + +{================================== TRecipes ==================================} + + +Constructor TRecipes.Create; +begin + Inherited; + FLabel:= 'RECIPES'; + FFileName:= 'recipes.xml'; + FSelected:= -1; + SetLength(FFermentablesMinMaxArray, 0); + SetLength(FBitterhopMinMaxArray, 0); + SetLength(FAromahopMinMaxArray, 0); + SetLength(FDryhopMinMaxArray, 0); + SetLength(FYeastMinMaxArray, 0); + SetLength(FMiscMinMaxArray, 0); + SetLength(FCommonMinMaxArray, 0); +end; + +Destructor TRecipes.Destroy; +begin + SetLength(FFermentablesMinMaxArray, 0); + SetLength(FBitterhopMinMaxArray, 0); + SetLength(FAromahopMinMaxArray, 0); + SetLength(FDryhopMinMaxArray, 0); + SetLength(FYeastMinMaxArray, 0); + SetLength(FMiscMinMaxArray, 0); + SetLength(FCommonMinMaxArray, 0); + Inherited; +end; + +Procedure TRecipes.SaveXML; +var i : integer; + FN : string; +begin + try + Inherited SaveXML; + FN:= Settings.DataLocation.Value + FFileName; + for i:= Low(FCollection) to High(FCollection) do + begin + TRecipe(FCollection[i]).SaveXML(FDoc, FRootNode, false); + Application.ProcessMessages; + end; + writeXMLFile(FDoc, FN); + finally + FDoc.Free; + end; +end; + +Procedure TRecipes.ReadXML; +var i : integer; + R : TRecipe; +begin + Inherited ReadXML; + if FRootNode <> NIL then + begin + try + i:= 0; + FChild:= FRootNode.FirstChild; + while FChild <> NIL do + begin + inc(i); + SetLength(FCollection, i); + Application.ProcessMessages; + FCollection[i-1]:= TRecipe.Create(NIL); + R:= TRecipe(FCollection[i-1]); + if FFileName = 'brews.xml' then R.RecType:= rtBrew + else if FFileName = 'recipes.xml' then R.RecType:= rtRecipe + else R.RecType:= rtCloud; + R.ReadXML(FChild); + FChild:= FChild.NextSibling; + end; + finally + FDoc.Free; + end; + end; +end; + +Function TRecipes.FindByNameAndNr(Nm, Nr : string) : TRecipe; +var i : integer; + R : TRecipe; +begin + Result:= NIL; + Nm:= Lowercase(Nm); + Nr:= Lowercase(Nr); + for i:= 0 to High(FCollection) do + begin + R:= TRecipe(FCollection[i]); + if (Lowercase(R.NrRecipe.Value) = Nr) and (Lowercase(R.Name.Value) = Nm) then + begin + Result:= R; + Exit; + end; + end; +end; + +Function TRecipes.FindByAutoNr(nr : integer) : TRecipe; +var i : integer; + R : TRecipe; +begin + Result:= NIL; + for i:= 0 to High(FCollection) do + begin + R:= TRecipe(FCollection[i]); + if (R.AutoNr.Value = Nr) then + begin + Result:= R; + Exit; + end; + end; +end; + +Procedure TRecipes.CheckAutoNrs; +var i, maxnr : integer; + R : TRecipe; +begin + maxnr:= MaxAutoNr; + for i:= Low(FCollection) to High(FCollection) do + begin + R:= TRecipe(FCollection[i]); + if R.AutoNr.Value = 0 then + begin + inc(maxnr); + R.AutoNr.Value:= maxnr; + end; + end; +end; + +Function TRecipes.ImportFiles(FN : TStrings; DN : string; Equip : TEquipment; + FT : TFileType) : boolean; +begin + Result:= false; + case FT of + ftXML: Result:= ImportXMLs(FN, DN, Equip); + ftPromash: Result:= ImportRECs(FN, DN, Equip); + ftInvalid: Result:= false; + end; + SaveXML; +end; + +Function TRecipes.ImportXMLs(FN : TStrings; DN : string; Equip : TEquipment) : boolean; +var SL : TStringList; + i : integer; + mask : string; + ps : TProgressBar; +begin + Result:= false; + if DN <> '' then + begin + try + Screen.Cursor:= crHourglass; + {$ifdef WINDOWS} + mask:= '*.xml'; + {$else} + mask:= '*xml'; + {$endif} + SL:= FindAllFiles(DN, mask, false); +{ FrmMain.sbMain.Panels[0].Text:= 'Importeren...'; + ps:= TProgressBar.Create(FrmMain.sbMain); + ps.Parent:= FrmMain.sbMain; + ps.Left:= FrmMain.sbMain.Panels[0].Width + 1; + ps.Width:= FrmMain.sbMain.Panels[1].Width; + ps.Min:= 0; + ps.Max:= SL.Count - 1; + ps.Position:= 0;} + for i:= 0 to SL.Count - 1 do + begin + ImportXML(SL[i], Equip); +// ps.Position:= i; + Application.ProcessMessages; + end; + Result:= TRUE; + finally + Screen.Cursor:= crDefault; +// ps.Free; + SL.Free; +// FrmMain.sbMain.Panels[0].Text:= ''; + ShowMessage('Importeren klaar'); + end; + end + else + begin + for i:= 0 to FN.Count - 1 do + begin + Result:= ImportXML(FN[i], Equip); + end; + end; +end; + +Function TRecipes.GetMaxAutoNr : integer; +var i : integer; +begin + Result:= 0; + for i:= Low(FCollection) to High(FCollection) do + if TRecipe(FCollection[i]).AutoNr.Value > Result then + Result:= TRecipe(FCollection[i]).AutoNr.Value; +end; + +Function TRecipes.ImportXML(FN : string; Equip : TEquipment) : boolean; +var R : TRecipe; + s : string; +begin + Result:= false; + FDoc := TXMLDocument.Create; + FRootNode:= NIL; + try + if FileExists(FN) then + begin + ReadXMLFile(FDoc, FN); + s:= ExtractFileNameOnly(FN); + FRootNode:= FDoc.FindNode(FLabel); + if FRootNode <> NIL then + begin + FChild:= FRootNode.FirstChild; + while FChild <> NIL do + begin + R:= AddItem; + Application.ProcessMessages; + R.ReadXML(FChild); + R.AutoNr.Value:= GetMaxAutoNr + 1; + R.ParentAutoNr.Value:= ''; + + CheckBeerStyle(R); + CheckFermentables(R); + CheckYeasts(R); + + //change the equipment + if Equip <> NIL then R.ChangeEquipment(Equip) + else R.RemoveNonBrewsData; + + if FFileName = 'brews.xml' then R.RecType:= rtBrew + else if FFileName = 'recipes.xml' then R.RecType:= rtRecipe + else R.RecType:= rtCloud; + + FChild:= FChild.NextSibling; + Result:= TRUE; + end; + end; + end; + finally + FDoc.Free; + end; +end; + +Function TRecipes.ImportRECs(FN : TStrings; DN : string; Equip : TEquipment) : boolean; +var SL : TStringList; + i : integer; + mask : string; + ps : TProgressBar; +begin + Result:= false; + if DN <> '' then + begin + try + Screen.Cursor:= crHourglass; + {$ifdef WINDOWS} + mask:= '*.rec'; + {$else} + mask:= '*rec'; + {$endif} + SL:= FindAllFiles(DN, mask, false); +{ FrmMain.sbMain.Panels[0].Text:= 'Importeren...'; + ps:= TProgressBar.Create(FrmMain.sbMain); + ps.Parent:= FrmMain.sbMain; + ps.Left:= FrmMain.sbMain.Panels[0].Width + 1; + ps.Width:= FrmMain.sbMain.Panels[1].Width; + ps.Min:= 0; + ps.Max:= SL.Count - 1; + ps.Position:= 0;} + for i:= 0 to SL.Count - 1 do + begin + ImportREC(SL[i], Equip); +// ps.Position:= i; + Application.ProcessMessages; + end; + Result:= TRUE; + finally + Screen.Cursor:= crDefault; +// ps.Free; + SL.Free; +// FrmMain.sbMain.Panels[0].Text:= ''; + ShowMessage('Importeren klaar'); + end; + end + else + for i:= 0 to FN.Count - 1 do + begin + Result:= ImportREC(FN[i], Equip); + end; +end; + +Function TRecipes.ImportREC(FN : string; Equip : TEquipment) : boolean; +var PI : TPromash; + R : TRecipe; + s : string; +begin + Result:= false; + PI := TPromash.Create(FrmMain); + try + FN:= ConvertStringEnc(FN); + if FileExists(FN) then + begin + if PI.OpenReadRec(FN) then + begin + R:= AddItem; + if R <> NIL then + begin + PI.Convert(R); + s:= R.Style.Name.Value; + R.AutoNr.Value:= MaxAutoNr + 1; + + CheckBeerStyle(R); + CheckFermentables(R); + CheckYeasts(R); + + //change the equipment + if Equip <> NIL then + R.ChangeEquipment(Equip); + + if FFileName = 'brews.xml' then R.RecType:= rtBrew + else if FFileName = 'recipes.xml' then R.RecType:= rtRecipe + else R.RecType:= rtCloud; + + Result:= TRUE; + end; + end; + end; + finally + PI.Free; + end; +end; + +Procedure TRecipes.QuickSortRecipes(var Arr : array of TBase); + procedure QuickSort(var A: array of TBase; iLo, iHi: Integer); + var Lo, Hi: Integer; + s : string; + T : TRecipe; + begin + Lo := iLo; + Hi := iHi; + s:= TRecipe(A[(Lo + Hi) div 2]).NrRecipe.Value; + repeat + while TRecipe(A[Lo]).NrRecipe.Value < s do Inc(Lo); + while TRecipe(A[Hi]).NrRecipe.Value > s do Dec(Hi); + if Lo <= Hi then + begin + T := TRecipe(A[Lo]); + TRecipe(A[Lo]) := TRecipe(A[Hi]); + TRecipe(A[Hi]) := T; + Inc(Lo); + Dec(Hi); + end; + until Lo > Hi; + if Hi > iLo then QuickSort(A, iLo, Hi); + if Lo < iHi then QuickSort(A, Lo, iHi); + end; +begin + if High(Arr) > -1 then QuickSort(Arr, Low(Arr), High(Arr)); +end; + +Procedure TRecipes.Sort; +begin + QuickSortRecipes(FCollection); +end; + +Function TRecipes.GetLastNrRecipe : string; +begin + Sort; + Result:= ''; + if High(FCollection) >= 0 then + Result:= TRecipe(FCollection[High(FCollection)]).NrRecipe.Value; +end; + +Function TRecipes.GetSelectedItem : TRecipe; +begin + Result:= NIL; + if FSelected > -1 then + Result:= TRecipe(FCollection[FSelected]); +end; + +Function TRecipes.AddItem : TRecipe; +begin + Result:= NIL; + try + SetLength(FCollection, High(FCollection)+2); + FSelected:= High(FCollection); + FCollection[High(FCollection)]:= TRecipe.Create(NIL); + Result:= TRecipe(FCollection[High(FCollection)]); + finally + end; +end; + +Procedure TRecipes.InsertItem(i : integer); +var R : TRecipe; +begin + Inherited; + if (i >= Low(FCollection)) and (i <= High(FCollection)) then + begin + FCollection[i]:= TRecipe.Create(NIL); + R:= TRecipe(FCollection[i]); + if FFileName = 'brews.xml' then R.RecType:= rtBrew + else if FFileName = 'recipes.xml' then R.RecType:= rtRecipe + else R.RecType:= rtCloud; + end; +end; + +Function TRecipes.ExportToCSV(A : array of longint) : boolean; +var i, j : integer; + dlg : TSaveDialog; + SL : TStringList; + line : string; + R : TRecipe; +begin + Result:= false; + dlg:= TSaveDialog.Create(frmMain); + if High(FCollection) > 0 then + try + SL:= TStringList.Create; + SL.Sorted:= false; + with dlg do + begin + DefaultExt:= '.csv'; + FileName:= '*.csv'; + Filter:= 'Comma separated values|*.csv'; + if dlg.Execute then + begin + R:= TRecipe(FCollection[0]); + Line:= 'Code;Nr;Naam;Gist naam;'; + for j:= Low(A) to High(A) do + begin + line:= line + R.GetNumberNameByIndex(A[j]); + if j < High(A) then line:= line + ';'; + end; + SL.Add(line); + for i:= Low(FCollection) to High(FCollection) do + begin + line:= ''; + R:= TRecipe(FCollection[i]); + line:= R.NrRecipe.Value + ';'; + line:= line + R.Name.Value + ';'; + line:= line + R.Yeast[0].Name.Value + ';'; + for j:= Low(A) to High(A) do + begin + line:= line + VarToStr(R.GetNumberByIndex(A[j])); + if j < High(A) then line:= line + ';'; + end; + SL.Add(line); + end; + SL.SaveToFile(dlg.FileName); + end; + end; + Result:= TRUE; + finally + dlg.Free; + SL.Free; + end; +end; + +Procedure TRecipes.QuickSortA(var Arr : array of TMinMax); + procedure QuickSort(var A: array of TMinMax; iLo, iHi: Integer); + var Lo, Hi: Integer; + s : single; + T : TMinMax; + begin + Lo := iLo; + Hi := iHi; + s:= A[(Lo + Hi) div 2].PercRecipes; + repeat + while A[Lo].PercRecipes > s do Inc(Lo); + while A[Hi].PercRecipes < s do Dec(Hi); + if Lo <= Hi then + begin + T := A[Lo]; + A[Lo] := A[Hi]; + A[Hi] := T; + Inc(Lo); + Dec(Hi); + end; + until Lo > Hi; + if Hi > iLo then QuickSort(A, iLo, Hi); + if Lo < iHi then QuickSort(A, Lo, iHi); + end; +begin + if High(Arr) > -1 then QuickSort(Arr, Low(Arr), High(Arr)); +end; + +Function TRecipes.Exists(Arr : TMinMaxArray; FName : string) : integer; +var n : integer; +begin + Result:= -1; + for n:= Low(Arr) to High(Arr) do + if Arr[n].Name = FName then + begin + Result:= n; + Exit; + end; +end; + +Function TRecipes.AnalyseFermentables(Lett, Nm : string) : integer; //returns number of recipes +var i, j, k : integer; + R : TRecipe; + F : TFermentable; + FN : string; +begin + Result:= 0; + SetLength(FFermentablesMinMaxArray, 0); + for i:= Low(FCollection) to High(FCollection) do + begin + R:= TRecipe(FCollection[i]); + if (R.Style <> NIL) and + ((LowerCase(R.Style.StyleLetter.Value) = LowerCase(Lett)) and + (Lowercase(R.Style.Name.Value) = Lowercase(Nm))) then + begin + Inc(Result); + R.CalcOG; + for j:= 0 to R.NumFermentables - 1 do + begin + F:= R.Fermentable[j]; + FN:= F.Name.Value; + k:= Exists(FFermentablesMinMaxArray, FN); + if k = -1 then + begin + SetLength(FFermentablesMinMaxArray, High(FFermentablesMinMaxArray) + 2); + k:= High(FFermentablesMinMaxArray); + FFermentablesMinMaxArray[k].Name:= FN; + FFermentablesMinMaxArray[k].PercRecipes:= 1; + FFermentablesMinMaxArray[k].MinUse:= F.Percentage.Value; + FFermentablesMinMaxArray[k].AvUse:= F.Percentage.Value; + FFermentablesMinMaxArray[k].MaxUse:= F.Percentage.Value; + end + else + begin + //temporarily store the number of recipes with this ingredient in PercRecipes + FFermentablesMinMaxArray[k].PercRecipes:= FFermentablesMinMaxArray[k].PercRecipes + 1; + FFermentablesMinMaxArray[k].AvUse:= FFermentablesMinMaxArray[k].AvUse + F.Percentage.Value; + if F.Percentage.Value < FFermentablesMinMaxArray[k].MinUse then + FFermentablesMinMaxArray[k].MinUse:= F.Percentage.Value; + if F.Percentage.Value > FFermentablesMinMaxArray[k].MaxUse then + FFermentablesMinMaxArray[k].MaxUse:= F.Percentage.Value; + end; + end; + end; + end; + if (High(FCollection) >= 0) then + begin + for i:= Low(FFermentablesMinMaxArray) to High(FFermentablesMinMaxArray) do + begin + if FFermentablesMinMaxArray[i].PercRecipes > 0 then + FFermentablesMinMaxArray[i].AvUse:= FFermentablesMinMaxArray[i].AvUse / FFermentablesMinMaxArray[i].PercRecipes + else + FFermentablesMinMaxArray[i].AvUse:= 0; + if Result > 0 then + FFermentablesMinMaxArray[i].PercRecipes:= 100 * FFermentablesMinMaxArray[i].PercRecipes / Result + else + FFermentablesMinMaxArray[i].PercRecipes:= 0; + end; + QuickSortA(FFermentablesMinMaxArray); + end; +end; + +Function TRecipes.AnalyseHops(Lett, Nm : string) : integer; //returns number of recipes +type + THR = record + name : string; + conc : double; + end; +var i, j, k : integer; + R : TRecipe; + H : THop; + FN : string; + conc : double; + HRAB, HRAA, HRAD : array of THR; + function FindHR(var HRA : array of THR; nm : string) : integer; + var n : integer; + begin + Result:= -1; + for n:= Low(HRA) to High(HRA) do + if HRA[n].name = nm then + begin + Result:= n; + Exit; + end; + end; + Procedure FillArrays(var MMA : TMinMaxArray; HRA : array of THR); + var j : integer; + begin + for j:= 0 to High(HRA) do + begin + k:= Exists(MMA, HRA[j].Name); + if k = -1 then + begin + SetLength(MMA, High(MMA) + 2); + k:= High(MMA); + MMA[k].Name:= HRA[j].Name; + MMA[k].PercRecipes:= 1; + MMA[k].MinUse:= HRA[j].Conc; + MMA[k].AvUse:= MMA[k].MinUse; + MMA[k].MaxUse:= MMA[k].MinUse; + end + else + begin + //temporarily store the number of recipes with this ingredient in PercRecipes + MMA[k].PercRecipes:= MMA[k].PercRecipes + 1; + MMA[k].AvUse:= MMA[k].AvUse + HRA[j].Conc; + if HRA[j].Conc < MMA[k].MinUse then + MMA[k].MinUse:= HRA[j].Conc; + if HRA[j].Conc > MMA[k].MaxUse then + MMA[k].MaxUse:= HRA[j].Conc; + end; + end; + end; + +begin + Result:= 0; + SetLength(FBitterhopMinMaxArray, 0); + SetLength(FAromahopMinMaxArray, 0); + SetLength(FDryhopMinMaxArray, 0); + SetLength(HRAB, 0); + SetLength(HRAA, 0); + SetLength(HRAD, 0); + for i:= Low(FCollection) to High(FCollection) do + begin + R:= TRecipe(FCollection[i]); + if (R.Style <> NIL) and + ((LowerCase(R.Style.StyleLetter.Value) = LowerCase(Lett)) and + (Lowercase(R.Style.Name.Value) = Lowercase(Nm))) then + begin + Inc(Result); + for j:= 0 to R.NumHops - 1 do + begin + H:= R.Hop[j]; + FN:= H.Name.Value; + if (H.Use = huBoil) or (H.Use = huAroma) or (H.Use = huFirstWort) + or (H.Use = huWhirlpool) then + begin + if H.Time.Value > 30 then + begin + conc:= H.BitternessContribution; + k:= FindHR(HRAB, FN); + if k = -1 then + begin + SetLength(HRAB, High(HRAB) + 2); + k:= High(HRAB); + HRAB[k].Name:= FN; + HRAB[k].Conc:= 0; + end; + HRAB[k].Conc:= HRAB[k].Conc + conc; + end + else if R.BatchSize.DisplayValue > 0 then + begin + Conc:= H.Amount.DisplayValue / R.BatchSize.DisplayValue; + k:= FindHR(HRAA, FN); + if k = -1 then + begin + SetLength(HRAA, High(HRAA) + 2); + k:= High(HRAA); + HRAA[k].Name:= FN; + HRAA[k].Conc:= 0; + end; + HRAA[k].Conc:= HRAA[k].Conc + conc; + end; + end + else if H.Use = huDryhop then + begin + if R.BatchSize.DisplayValue > 0 then + begin + conc:= H.Amount.DisplayValue / R.BatchSize.DisplayValue; + k:= FindHR(HRAD, FN); + if k = -1 then + begin + SetLength(HRAD, High(HRAD) + 2); + k:= High(HRAD); + HRAD[k].Name:= FN; + HRAD[k].Conc:= 0; + end; + HRAD[k].Conc:= HRAD[k].Conc + conc; + end; + end; + end; + + FillArrays(FBitterhopMinMaxArray, HRAB); + FillArrays(FAromahopMinMaxArray, HRAA); + FillArrays(FDryHopMinMaxArray, HRAD); + SetLength(HRAB, 0); + SetLength(HRAA, 0); + SetLength(HRAD, 0); + end; + end; + if (High(FCollection) >= 0) then + begin + for i:= Low(FBitterhopMinMaxArray) to High(FBitterhopMinMaxArray) do + begin + if FBitterhopMinMaxArray[i].PercRecipes > 0 then + FBitterhopMinMaxArray[i].AvUse:= FBitterhopMinMaxArray[i].AvUse + / FBitterhopMinMaxArray[i].PercRecipes + else + FBitterhopMinMaxArray[i].AvUse:= 0; + if Result > 0 then + FBitterhopMinMaxArray[i].PercRecipes:= + 100 * FBitterhopMinMaxArray[i].PercRecipes / Result + else + FBitterhopMinMaxArray[i].PercRecipes:= 0; + end; + QuickSortA(FBitterhopMinMaxArray); + + for i:= Low(FAromahopMinMaxArray) to High(FAromahopMinMaxArray) do + begin + if FAromahopMinMaxArray[i].PercRecipes > 0 then + FAromahopMinMaxArray[i].AvUse:= FAromahopMinMaxArray[i].AvUse + / FAromahopMinMaxArray[i].PercRecipes + else + FAromahopMinMaxArray[i].AvUse:= 0; + if Result > 0 then + FAromahopMinMaxArray[i].PercRecipes:= + 100 * FAromahopMinMaxArray[i].PercRecipes / Result + else + FAromahopMinMaxArray[i].PercRecipes:= 0; + end; + QuickSortA(FAromahopMinMaxArray); + + for i:= Low(FDryhopMinMaxArray) to High(FDryhopMinMaxArray) do + begin + if FDryhopMinMaxArray[i].PercRecipes > 0 then + FDryhopMinMaxArray[i].AvUse:= FDryhopMinMaxArray[i].AvUse + / FDryhopMinMaxArray[i].PercRecipes + else + FDryhopMinMaxArray[i].AvUse:= 0; + if Result > 0 then + FDryhopMinMaxArray[i].PercRecipes:= + 100 * FDryhopMinMaxArray[i].PercRecipes / Result + else + FDryhopMinMaxArray[i].PercRecipes:= 0; + end; + QuickSortA(FDryhopMinMaxArray); + end; +end; + +Function TRecipes.AnalyseYeasts(Lett, Nm : string) : integer; //returns number of recipes +var i, j, k : integer; + R : TRecipe; + Y : TYeast; + FN : string; +begin + Result:= 0; + if High(FYeastMinMaxArray) >= 0 then + SetLength(FYeastMinMaxArray, 0); + for i:= Low(FCollection) to High(FCollection) do + begin + R:= TRecipe(FCollection[i]); + if (R.Style <> NIL) and + ((LowerCase(R.Style.StyleLetter.Value) = LowerCase(Lett)) and + (Lowercase(R.Style.Name.Value) = Lowercase(Nm))) then + begin + Inc(Result); + for j:= 0 to R.NumYeasts - 1 do + begin + Y:= R.Yeast[j]; + FN:= Y.Name.Value; + k:= Exists(FYeastMinMaxArray, FN); + if k = -1 then + begin + SetLength(FYeastMinMaxArray, High(FYeastMinMaxArray) + 2); + k:= High(FYeastMinMaxArray); + FYeastMinMaxArray[k].Name:= FN; + FYeastMinMaxArray[k].PercRecipes:= 1; + {FYeastMinMaxArray[k].MinUse:= F.Percentage.Value; + FYeastMinMaxArray[k].AvUse:= F.Percentage.Value; + FYeastMinMaxArray[k].MaxUse:= F.Percentage.Value;} + end + else + begin + //temporarily store the number of recipes with this ingredient in PercRecipes + FYeastMinMaxArray[k].PercRecipes:= FYeastMinMaxArray[k].PercRecipes + 1; + {FYeastMinMaxArray[k].AvUse:= FYeastMinMaxArray[k].AvUse + F.Percentage.Value; + if F.Percentage.Value < FYeastMinMaxArray[k].MinUse then + FYeastMinMaxArray[k].MinUse:= F.Percentage.Value; + if F.Percentage.Value > FYeastMinMaxArray[k].MaxUse then + FYeastMinMaxArray[k].MaxUse:= F.Percentage.Value;} + end; + end; + end; + end; + if (High(FCollection) >= 0) then + begin + for i:= Low(FYeastMinMaxArray) to High(FYeastMinMaxArray) do + begin + { if FYeastMinMaxArray[i].PercRecipes > 0 then + FYeastMinMaxArray[i].AvUse:= FYeastMinMaxArray[i].AvUse / FYeastMinMaxArray[i].PercRecipes + else + FYeastMinMaxArray[i].AvUse:= 0;} + if Result > 0 then + FYeastMinMaxArray[i].PercRecipes:= 100 * FYeastMinMaxArray[i].PercRecipes / Result + else + FYeastMinMaxArray[i].PercRecipes:= 0; + end; + QuickSortA(FYeastMinMaxArray); + end; +end; + +Function TRecipes.AnalyseMiscs(Lett, Nm : string) : integer; //returns number of recipes +var i, j, k : integer; + R : TRecipe; + M : TMisc; + FN : string; + conc : double; +begin + Result:= 0; + if High(FMiscMinMaxArray) >= 0 then + SetLength(FMiscMinMaxArray, 0); + for i:= Low(FCollection) to High(FCollection) do + begin + R:= TRecipe(FCollection[i]); + if (R.Style <> NIL) and + ((LowerCase(R.Style.StyleLetter.Value) = LowerCase(Lett)) and + (Lowercase(R.Style.Name.Value) = Lowercase(Nm))) then + begin + Inc(Result); + for j:= 0 to R.NumMiscs - 1 do + begin + M:= R.Misc[j]; + FN:= M.Name.Value; + if ((M.MiscType = mtSpice) or (M.MiscType = mtHerb) or (M.MiscType = mtFlavor) + or (M.MiscType = mtOther)) and (R.BatchSize.DisplayValue > 0) then + begin + conc:= M.Amount.DisplayValue / R.BatchSize.DisplayValue; + k:= Exists(FMiscMinMaxArray, FN); + if k = -1 then + begin + SetLength(FMiscMinMaxArray, High(FMiscMinMaxArray) + 2); + k:= High(FMiscMinMaxArray); + FMiscMinMaxArray[k].Name:= FN; + FMiscMinMaxArray[k].PercRecipes:= 1; + FMiscMinMaxArray[k].MinUse:= Conc; + FMiscMinMaxArray[k].AvUse:= Conc; + FMiscMinMaxArray[k].MaxUse:= Conc; + end + else + begin + //temporarily store the number of recipes with this ingredient in PercRecipes + FMiscMinMaxArray[k].PercRecipes:= FMiscMinMaxArray[k].PercRecipes + 1; + FMiscMinMaxArray[k].AvUse:= FMiscMinMaxArray[k].AvUse + Conc; + if Conc < FMiscMinMaxArray[k].MinUse then + FMiscMinMaxArray[k].MinUse:= Conc; + if Conc > FMiscMinMaxArray[k].MaxUse then + FMiscMinMaxArray[k].MaxUse:= Conc; + end; + end; + end; + end; + end; + if (High(FCollection) >= 0) then + begin + for i:= Low(FMiscMinMaxArray) to High(FMiscMinMaxArray) do + begin + if FMiscMinMaxArray[i].PercRecipes > 0 then + FMiscMinMaxArray[i].AvUse:= FMiscMinMaxArray[i].AvUse / FMiscMinMaxArray[i].PercRecipes + else + FMiscMinMaxArray[i].AvUse:= 0; + if Result > 0 then + FMiscMinMaxArray[i].PercRecipes:= 100 * FMiscMinMaxArray[i].PercRecipes / Result + else + FMiscMinMaxArray[i].PercRecipes:= 0; + end; + QuickSortA(FMiscMinMaxArray); + end; +end; + +Function TRecipes.AnalyseRecipes(Lett, Nm : string) : integer; //returns number of recipes +var i, j : integer; + R : TRecipe; + SGp, bitt, x : double; +begin + Result:= 0; + SetLength(FCommonMinMaxArray, 0); + SetLength(FCommonMinMaxArray, 3); + for j:= 0 to High(FCommonMinMaxArray) do + begin + FCommonMinMaxArray[j].PercRecipes:= 0; + FCommonMinMaxArray[j].MinUse:= 10000; + FCommonMinMaxArray[j].AvUse:= 0; + FCommonMinMaxArray[j].MaxUse:= 0; + FCommonMinMaxArray[j].Name:= ''; + end; + //0 = SG points + FCommonMinMaxArray[0].Name:= 'SG punten'; + //1 = Bitterness + FCommonMinMaxArray[1].Name:= 'Bitterheid (IBU)'; + //2 = Color + FCommonMinMaxArray[2].Name:= 'Kleur (' + TRecipe(FCollection[0]).EstColor.DisplayUnitString + ')'; + { //3 = BitternessIndex + FCommonMinMaxArray[3].Name:= 'Bitterheidsindex';} + + for i:= Low(FCollection) to High(FCollection) do + begin + R:= TRecipe(FCollection[i]); + if (R.Style <> NIL) and + ((LowerCase(R.Style.StyleLetter.Value) = LowerCase(Lett)) and + (Lowercase(R.Style.Name.Value) = Lowercase(Nm))) then + begin + Inc(Result); + + R.CalcOG; + if R.OG.Value > 1 then + SGp:= 1000 * (R.OG.Value - 1) + else + SGp:= 1000 * (R.EstOG.Value - 1); + FCommonMinMaxArray[0].AvUse:= FCommonMinMaxArray[0].AvUse + SGp; + if SGp < FCommonMinMaxArray[0].MinUse then + FCommonMinMaxArray[0].MinUse:= SGp; + if SGp > FCommonMinMaxArray[0].MaxUse then + FCommonMinMaxArray[0].MaxUse:= SGp; + + R.CalcBitterness; + bitt:= R.IBUcalc.DisplayValue; + FCommonMinMaxArray[1].AvUse:= FCommonMinMaxArray[1].AvUse + bitt; + if bitt < FCommonMinMaxArray[1].MinUse then + FCommonMinMaxArray[1].MinUse:= bitt; + if bitt > FCommonMinMaxArray[1].MaxUse then + FCommonMinMaxArray[1].MaxUse:= bitt; + +{ if SGp > 0 then x:= bitt / SGp + else x:= 0; + FCommonMinMaxArray[2].AvUse:= FCommonMinMaxArray[2].AvUse + x; + if x < FCommonMinMaxArray[2].MinUse then + FCommonMinMaxArray[2].MinUse:= x; + if x > FCommonMinMaxArray[2].MaxUse then + FCommonMinMaxArray[2].MaxUse:= x;} + + R.CalcColor; + x:= R.EstColor.DisplayValue; + FCommonMinMaxArray[2].AvUse:= FCommonMinMaxArray[2].AvUse + x; + if x < FCommonMinMaxArray[2].MinUse then + FCommonMinMaxArray[2].MinUse:= x; + if x > FCommonMinMaxArray[2].MaxUse then + FCommonMinMaxArray[2].MaxUse:= x; + end; + end; + if (High(FCollection) >= 0) then + begin + for i:= Low(FCommonMinMaxArray) to High(FCommonMinMaxArray) do + begin + if Result > 0 then + FCommonMinMaxArray[i].AvUse:= FCommonMinMaxArray[i].AvUse / Result + else + FCommonMinMaxArray[i].AvUse:= 0; + end; + end; +end; +{============================= TRecipesByStyle ================================} + +{ TStyleRec = record + Name : string; + Recipes : array of TRecipe; + end; + + TStyleLetters = record + Letter : string; + Styles : array of TStyleRec; + end;} + +Constructor TRecipesByStyle.Create(R : TRecipes); + begin + Inherited Create; + FCollection:= R; + Fill; + Sort; + end; + +Destructor TRecipesByStyle.Destroy; +begin + Empty; + Inherited; +end; + +Procedure TRecipesByStyle.SaveXML; +var Doc : TXMLDocument; + iRootNode : TDOMNode; + n, s, i : integer; +begin + try + Doc := TXMLDocument.Create; + iRootNode := Doc.CreateElement('RECIPES'); + Doc.Appendchild(iRootNode); + + for n:= Low(FStyleLetters) to High(FStyleLetters) do + begin + for s:= Low(FStyleLetters[n].Styles) to High(FStyleLetters[n].Styles) do + begin + for i:= Low(FStyleLetters[n].Styles[s].Recipes) to High(FStyleLetters[n].Styles[s].Recipes) do + FStyleLetters[n].Styles[s].Recipes[i].SaveXML(Doc, iRootNode, false); + end; + end; + + writeXMLFile(Doc, Settings.DataLocation.Value + 'recipes.xml'); + finally + Doc.Free; + end; +end; + +Procedure TRecipesByStyle.Fill; +var n, n2, s, s2, i, r : integer; + Num, Stl : string; + Rec : TRecipe; +begin + Empty; + for i:= 1 to FCollection.GetNumItems do + begin + Rec:= TRecipe(FCollection.Item[i-1]); + Num:= Rec.Style.StyleLetter.Value; + Stl:= Rec.Style.Name.Value; + n:= GetLetterByName(Num); + s:= GetStyleByName(Num, Stl); + if n < 0 then //Style Number does not exist + begin + n2:= High(FStyleLetters) + 1; + SetLength(FStyleLetters, n2 + 1); + FStyleLetters[n2].Letter:= Num; + SetLength(FStyleLetters[n2].Styles, 1); + FStyleLetters[n2].Styles[0].Name:= Stl; + SetLength(FStyleLetters[n2].Styles[0].Recipes, 1); + FStyleLetters[n2].Styles[0].Recipes[0]:= Rec; + end + else if s < 0 then //Style does not exist + begin + s2:= High(FStyleLetters[n].Styles) + 1; + SetLength(FStyleLetters[n].Styles, s2 + 1); + FStyleLetters[n].Styles[s2].Name:= Stl; + SetLength(FStyleLetters[n].Styles[s2].Recipes, 1); + FStyleLetters[n].Styles[s2].Recipes[0]:= Rec; + end + else //Both exist + begin + r:= High(FStyleLetters[n].Styles[s].Recipes) + 1; + SetLength(FStyleLetters[n].Styles[s].Recipes, r+1); + FStyleLetters[n].Styles[s].Recipes[r]:= Rec; + end; + end; +end; + +Procedure TRecipesByStyle.Empty; +var n, s, i : integer; +begin + for n:= Low(FStyleLetters) to High(FStyleLetters) do + begin + for s:= Low(FStyleLetters[n].Styles) to High(FStyleLetters[n].Styles) do + begin + for i:= Low(FStyleLetters[n].Styles[s].Recipes) to High(FStyleLetters[n].Styles[s].Recipes) do + FStyleLetters[n].Styles[s].Recipes[i]:= NIL; + SetLength(FStyleLetters[n].Styles[s].Recipes, 0); + end; + SetLength(FStyleLetters[n].Styles, 0); + end; + SetLength(FStyleLetters, 0); +end; + +Procedure TRecipesByStyle.QuickSortInStyles(var Arr : array of TRecipe); + procedure QuickSort(var A: array of TRecipe; iLo, iHi: Integer); + var Lo, Hi: Integer; + l : string; + T : TRecipe; + begin + Lo := iLo; + Hi := iHi; + l:= A[(Lo + Hi) div 2].NrRecipe.Value; + repeat + while A[Lo].NrRecipe.Value < l do Inc(Lo); + while A[Hi].NrRecipe.Value > l do Dec(Hi); + if Lo <= Hi then + begin + T := A[Lo]; + A[Lo] := A[Hi]; + A[Hi] := T; + Inc(Lo); + Dec(Hi); + end; + until Lo > Hi; + if Hi > iLo then QuickSort(A, iLo, Hi); + if Lo < iHi then QuickSort(A, Lo, iHi); + end; +begin + if High(Arr) > -1 then QuickSort(Arr, Low(Arr), High(Arr)); +end; + +Procedure TRecipesByStyle.QuickSortStyles(var Arr : array of TStyleRec); + procedure QuickSort(var A: array of TStyleRec; iLo, iHi: Integer); + var Lo, Hi: Integer; + s : string; + T : TStyleRec; + begin + Lo := iLo; + Hi := iHi; + s:= A[(Lo + Hi) div 2].Name; + repeat + while A[Lo].Name < s do Inc(Lo); + while A[Hi].Name > s do Dec(Hi); + if Lo <= Hi then + begin + T := A[Lo]; + A[Lo] := A[Hi]; + A[Hi] := T; + Inc(Lo); + Dec(Hi); + end; + until Lo > Hi; + if Hi > iLo then QuickSort(A, iLo, Hi); + if Lo < iHi then QuickSort(A, Lo, iHi); + end; +begin + if High(Arr) > -1 then QuickSort(Arr, Low(Arr), High(Arr)); +end; + +Procedure TRecipesByStyle.QuickSortLetters(var Arr : array of TStyleLetters); + procedure QuickSort(var A: array of TStyleLetters; iLo, iHi: Integer); + var Lo, Hi: Integer; + l : string; + T : TStyleLetters; + begin + Lo := iLo; + Hi := iHi; + l := A[(Lo + Hi) div 2].Letter; + repeat + while A[Lo].Letter < l do Inc(Lo); + while A[Hi].Letter > l do Dec(Hi); + if Lo <= Hi then + begin + T := A[Lo]; + A[Lo] := A[Hi]; + A[Hi] := T; + Inc(Lo); + Dec(Hi); + end; + until Lo > Hi; + if Hi > iLo then QuickSort(A, iLo, Hi); + if Lo < iHi then QuickSort(A, Lo, iHi); + end; +begin + if High(Arr) > -1 then QuickSort(Arr, Low(Arr), High(Arr)); +end; + +Procedure TRecipesByStyle.Sort; +var n, s : integer; +begin +//sort recipes in every style by recipe number + for n:= Low(FStyleLetters) to High(FStyleLetters) do + for s:= Low(FStyleLetters[n].Styles) to High(FStyleLetters[n].Styles) do + QuickSortInStyles(FStyleLetters[n].Styles[s].Recipes); + +//sort style names + for n:= Low(FStyleLetters) to High(FStyleLetters) do + QuickSortStyles(FStyleLetters[n].Styles); +//sort style letters + QuickSortLetters(FStyleLetters); +end; + +Function TRecipesByStyle.GetLetterByName(Num : string) : integer; +var n : integer; +begin + Result:= -1; + for n:= Low(FStyleLetters) to High(FStyleLetters) do + if FStyleLetters[n].Letter = Num then + begin + Result:= n; + Exit; + end; +end; + +Function TRecipesByStyle.GetStyleByName(Num, Stl : string) : integer; +var n, s : integer; +begin + Result:= -1; + n:= GetLetterByName(Num); + if n > -1 then + begin + for s:= Low(FStyleLetters[n].Styles) to High(FStyleLetters[n].Styles) do + if FStyleLetters[n].Styles[s].Name = Stl then + begin + Result:= s; + Exit; + end; + end; +end; + +Function TRecipesByStyle.GetNumStyleLetters : integer; +begin + Result:= High(FStyleLetters) + 1; +end; + +Function TRecipesByStyle.GetNumStyles(i : integer) : integer; +begin + Result:= -1; + if (i >= Low(FStyleLetters)) and (i <= High(FStyleLetters)) then + Result:= High(FStyleLetters[i].Styles) + 1; +end; + +Function TRecipesByStyle.GetStyleLetter(i : integer) : string; +begin + Result:= ''; + if (i >= Low(FStyleLetters)) and (i <= High(FStyleLetters)) then + Result:= FStyleLetters[i].Letter; +end; + +Function TRecipesByStyle.GetStyleName(n : integer; s : integer) : string; +begin + Result:= ''; + if (n >= Low(FStyleLetters)) and (n <= High(FStyleLetters)) then + if (s >= Low(FStyleLetters[n].Styles)) and (s <= High(FStyleLetters[n].Styles)) then + Result:= FStyleLetters[n].Styles[s].Name; +end; + +Function TRecipesByStyle.GetNumRecipes(n : integer; s : integer) : integer; +begin + Result:= -1; + if (n >= Low(FStyleLetters)) and (n <= High(FStyleLetters)) then + if (s >= Low(FStyleLetters[n].Styles)) and (s <= High(FStyleLetters[n].Styles)) then + Result:= High(FStyleLetters[n].Styles[s].Recipes) + 1; +end; + +Function TRecipesByStyle.GetRecipe(n : integer; s : integer; i : integer) : TRecipe; +begin + Result:= NIL; + if (n >= Low(FStyleLetters)) and (n <= High(FStyleLetters)) then + if (s >= Low(FStyleLetters[n].Styles)) and (s <= High(FStyleLetters[n].Styles)) then + if (i >= Low(FStyleLetters[n].Styles[s].Recipes)) and (i <= High(FStyleLetters[n].Styles[s].Recipes)) then + Result:= FStyleLetters[n].Styles[s].Recipes[i]; +end; + +{============================= System functions ===============================} + +Procedure CheckBeerStyle(Rec : TRecipe); +var s : string; + OK : boolean; + BS : TBeerStyle; +begin +//check if beerstyle exist in the database. +//If not, check the substitution database, otherwise ask for an alternative + s:= ''; + if Rec.Style <> NIL then + s:= Rec.Style.Name.Value; + if Beerstyles.FindByName(s) = NIL then + begin + //first, look for subtitute in the substitutions database + OK:= StyleSubs.OriginalExists(s); + if OK then + begin + s:= StyleSubs.FindSubstitute(s); + BS:= TBeerStyle(BeerStyles.FindByName(s)); + OK:= (BS <> NIL); + if not OK then + StyleSubs.RemoveOriginal(s); + end; + if OK then + Rec.Style.Assign(BS) + else + begin + FrmSelectBeerStyle:= TFrmSelectBeerStyle.Create(FrmMain); + if FrmSelectBeerStyle.Execute(s) then + begin + //put style replacement in the substitutions database + if (not StyleSubs.OriginalExists(s)) then + StyleSubs.Add(s, FrmSelectBeerStyle.BeerStyle.Name.Value); + Rec.Style.Assign(FrmSelectBeerStyle.BeerStyle); + end; + FrmSelectBeerStyle.Free; + end; + end; +end; + +Procedure CheckFermentables(Rec : TRecipe); +var s, s2 : string; + OK : boolean; + i : integer; + F : TFermentable; + am, perc, yield, color, CoarseFineDiff, moisture, DiastaticPower, Protein, + DissolvedProtein, IbuGalPerLb: double; +begin +//check if fermentable exist in the database. +//If not, check the substitution database, otherwise ask for an alternative + for i:= 0 to Rec.NumFermentables - 1 do + begin + s:= Rec.Fermentable[i].Name.Value; + s2:= Rec.Fermentable[i].Supplier.Value; + OK:= (Fermentables.FindByNameAndSupplier(s, s2) <> NIL); + if (not OK) then + begin + OK:= FermentableSubs.OriginalExists(s, s2); + if OK then + begin + FermentableSubs.FindSubstitute(s, s2, s, s2); + F:= TFermentable(Fermentables.FindByNameAndSupplier(s, s2)); + if F <> NIL then + begin + am:= Rec.Fermentable[i].Amount.Value; + perc:= Rec.Fermentable[i].Percentage.Value; + Yield:= Rec.Fermentable[i].Yield.Value; + Color:= Rec.Fermentable[i].Color.Value; + CoarseFineDiff:= Rec.Fermentable[i].CoarseFineDiff.Value; + Moisture:= Rec.Fermentable[i].Moisture.Value; + DiastaticPower:= Rec.Fermentable[i].DiastaticPower.Value; + Protein:= Rec.Fermentable[i].Protein.Value; + DissolvedProtein:= Rec.Fermentable[i].DissolvedProtein.Value; + IbuGalPerLb:= Rec.Fermentable[i].IbuGalPerLb.Value; + + Rec.Fermentable[i].Assign(F); + Rec.Fermentable[i].Amount.Value:= am; + Rec.Fermentable[i].Percentage.Value:= perc; + Rec.Fermentable[i].Yield.Value:= Yield; + Rec.Fermentable[i].Color.Value:= Color; + Rec.Fermentable[i].CoarseFineDiff.Value:= CoarseFineDiff; + Rec.Fermentable[i].Moisture.Value:= Moisture; + Rec.Fermentable[i].DiastaticPower.Value:= DiastaticPower; + Rec.Fermentable[i].Protein.Value:= Protein; + Rec.Fermentable[i].DissolvedProtein.Value:= DissolvedProtein; + Rec.Fermentable[i].IbuGalPerLb.Value:= IbuGalPerLb; + end + else + FermentableSubs.RemoveOriginal(s, s2); + end; + end; + end; +end; + +Procedure CheckYeasts(Rec : TRecipe); +var s, s2 : string; + OK : boolean; + i : integer; + Y : TYeast; + am : double; +begin +//check if beerstyle exist in the database. +//If not, check the substitution database, otherwise ask for an alternative + for i:= 0 to Rec.NumYeasts - 1 do + begin + s:= Rec.Yeast[i].Name.Value; + s2:= Rec.Yeast[i].Laboratory.Value; + OK:= (Yeasts.FindByNameAndLaboratory(s, s2) <> NIL); + if (not OK) then + begin + OK:= YeastSubs.OriginalExists(s, s2); + if OK then + begin + YeastSubs.FindSubstitute(s, s2, s, s2); + Y:= TYeast(Yeasts.FindByNameAndLaboratory(s, s2)); + if Y <> NIL then + begin + am:= Rec.Yeast[i].Amount.Value; + Rec.Yeast[i].Assign(Y); + Rec.Yeast[i].Amount.Value:= am; + end + else + YeastSubs.RemoveOriginal(s, s2); + end; + end; + end; +end; + +Procedure Backup; + function CheckCopyFile(sd, dd, fn : string) : boolean; + begin + Result:= false; + if FileExists(sd + fn) then + result:= CopyFile(sd + fn, dd + fn); + end; +var sourcedata, destdata : string; + year, month, day : word; + i : integer; + SearchResult : TSearchRec; + SL : TStringList; +begin + sourcedata:= Settings.DataLocation.Value; + DecodeDate(now, year, month, day); + destdata:= BHFolder + 'backup-' + IntToStr(Year) + '-' + IntToStr(Month) + '-' + + IntToStr(day) + Slash; + CreateDir(destdata); + CheckCopyFile(sourcedata, destdata, 'settings.xml'); + CheckCopyFile(sourcedata, destdata, 'fermentables.xml'); + CheckCopyFile(sourcedata, destdata, 'hops.xml'); + CheckCopyFile(sourcedata, destdata, 'yeasts.xml'); + CheckCopyFile(sourcedata, destdata, 'miscs.xml'); + CheckCopyFile(sourcedata, destdata, 'mashs.xml'); + CheckCopyFile(sourcedata, destdata, 'waters.xml'); + CheckCopyFile(sourcedata, destdata, 'styles.xml'); + CheckCopyFile(sourcedata, destdata, 'equipments.xml'); + CheckCopyFile(sourcedata, destdata, 'recipes.xml'); + CheckCopyFile(sourcedata, destdata, 'brews.xml'); + CheckCopyFile(sourcedata, destdata, 'cloud.xml'); + CheckCopyFile(sourcedata, destdata, 'stylesubs.xml'); + CheckCopyFile(sourcedata, destdata, 'fermentablesubs.xml'); + CheckCopyFile(sourcedata, destdata, 'yeastsubs.xml'); + CheckCopyFile(sourcedata, destdata, 'neuralnetworks.xml'); + SL:= FindAllFiles(sourcedata, '*.nn', false); + for i:= 0 to SL.Count - 1 do + CheckCopyFile(sourcedata, destdata, ExtractFileName(SL.Strings[i])); + FreeAndNIL(SL); + // CheckCopyFile(sourcedata, destdata, 'styles-BJCP.xml'); + // CheckCopyFile(sourcedata, destdata, 'White Labs.xml'); + CheckCopyFile(sourcedata, destdata, 'logo.png'); +end; + +Procedure Restore(sourcedata : string); + function CheckCopyFile(sd, dd, fn : string) : boolean; + begin + Result:= false; + if FileExists(sd + fn) then + result:= CopyFile(sd + fn, dd + fn); + end; +var destdata : string; + year, month, day : word; + i : integer; + SL : TStringList; +begin + destdata:= Settings.DataLocation.Value; + if not DirectoryExists(destdata) then CreateDir(destdata); + CheckCopyFile(sourcedata, destdata, 'settings.xml'); + CheckCopyFile(sourcedata, destdata, 'fermentables.xml'); + CheckCopyFile(sourcedata, destdata, 'hops.xml'); + CheckCopyFile(sourcedata, destdata, 'yeasts.xml'); + CheckCopyFile(sourcedata, destdata, 'miscs.xml'); + CheckCopyFile(sourcedata, destdata, 'mashs.xml'); + CheckCopyFile(sourcedata, destdata, 'waters.xml'); + CheckCopyFile(sourcedata, destdata, 'styles.xml'); + CheckCopyFile(sourcedata, destdata, 'equipments.xml'); + CheckCopyFile(sourcedata, destdata, 'recipes.xml'); + CheckCopyFile(sourcedata, destdata, 'brews.xml'); + CheckCopyFile(sourcedata, destdata, 'cloud.xml'); + CheckCopyFile(sourcedata, destdata, 'stylesubs.xml'); + CheckCopyFile(sourcedata, destdata, 'fermentablesubs.xml'); + CheckCopyFile(sourcedata, destdata, 'yeastsubs.xml'); + CheckCopyFile(sourcedata, destdata, 'neuralnetworks.xml'); + SL:= FindAllFiles(sourcedata, '*.nn', false); + for i:= 0 to SL.Count - 1 do + CheckCopyFile(sourcedata, destdata, ExtractFileName(SL.Strings[i])); + FreeAndNIL(SL); + +// CheckCopyFile(sourcedata, destdata, 'styles-BJCP.xml'); +// CheckCopyFile(sourcedata, destdata, 'White Labs.xml'); + CheckCopyFile(sourcedata, destdata, 'logo.png'); + + Fermentables.ReadXML; + Hops.ReadXML; + Miscs.ReadXML; + Yeasts.ReadXML; + Waters.ReadXML; + Equipments.ReadXML; + Beerstyles.ReadXML; + Mashs.ReadXML; + Application.ProcessMessages; + Recipes.ReadXML; + Application.ProcessMessages; + Brews.ReadXML; +end; + +Procedure CheckDataFolder; + function CheckFile(sd, dd, fn : string) : boolean; + var destOK, sourceOK : boolean; + begin + Result:= false; + destOK:= FileExists(dd + fn); + sourceOK:= FileExists('"' + sd + fn + '"'); + if (not destOK) and (sourceOK) then + try + result:= CopyFile(sd + fn, dd + fn); + except + ShowMessage('Fout bij aanmaken ' + dd + fn + '.'); + Halt; + end + else if (not destOK) and (not sourceOK) then + ShowMessage('Fout: ' + sd + fn + ' niet gevonden.'); + end; +var sourcedata, destdata, sourcesounds, destsounds : string; +begin + {$ifdef linux} + sourcedata:= '/usr/share/brewbuddy/'; + {$endif} + {$ifdef darwin} + sourcedata:= ProgramDirectory() + 'BrewBuddy.app/Contents/Resources/'; + {$endif} + {$ifdef Windows} + sourcedata:= ExtractFilePath(Application.ExeName) + 'brewbuddy\'; + if OnUSB then BHFolder:= DriveLetter + '\brewbuddy\brewbuddy\'; + log('Checkdatafolder: BHFolder = ' + BHFolder); + {$endif} + destdata:= BHFolder; + if not DirectoryExists(BHFolder) then + CreateDir(BHFolder); + if not DirectoryExists(SoundFolder) then + CreateDir(SoundFolder); + sourcesounds:= sourcedata + 'sounds' + Slash; + destsounds:= SoundFolder; + Settings := TBSettings.Create; + if CheckFile(sourcedata, destdata, 'settings.xml') then + begin + Settings.DataLocation.Value:= BHFolder; + end + else + Settings.Read; + log('Settings.Datalocation = ' + Settings.DataLocation.Value); + + IF OnUSB then + begin + Settings.DataLocation.Value:= BHFolder; + destdata:= BHFolder; + end + else if (Settings.DataLocation.Value <> '') and (not OnUSB) then + destdata:= Settings.DataLocation.Value + else + destdata:= BHFolder; + log('Settings.Datalocation = ' + Settings.DataLocation.Value); + if not DirectoryExists(destdata) then + CreateDir(destdata); + + if CheckFile(sourcedata, destdata, 'equipments.xml') then + ShowMessage('Data niet gevonden. Nieuwe databank wordt gemaakt.'); + CheckFile(sourcedata, destdata, 'fermentables.xml'); + CheckFile(sourcedata, destdata, 'hops.xml'); + CheckFile(sourcedata, destdata, 'mashs.xml'); + CheckFile(sourcedata, destdata, 'miscs.xml'); + CheckFile(sourcedata, destdata, 'recipes.xml'); + CheckFile(sourcedata, destdata, 'styles-BJCP.xml'); + CheckFile(sourcedata, destdata, 'styles.xml'); + CheckFile(sourcedata, destdata, 'waters.xml'); +// CheckFile(sourcedata, destdata, 'White Labs.xml'); + CheckFile(sourcedata, destdata, 'yeasts.xml'); + CheckFile(sourcedata, destdata, 'logo.png'); + {$ifdef Windows} + CheckFile(sourcedata, destdata, 'Introductie BrewBuddy Sassy Saison.pdf'); + {$endif} + {$ifdef Darwin} + CheckFile(sourcedata, destdata, 'Introductie BrewBuddy Sassy Saison.pdf'); + {$endif} + {$ifdef linux} + CheckFile('/usr/share/doc/brewbuddy/', destdata, 'Introductie BrewBuddy Sassy Saison.pdf'); + {$endif} + CheckFile(sourcesounds, destsounds, 'alarm.wav'); +// CheckFile(sourcesounds, destsounds, 'alarm02.wav'); + CheckFile(sourcesounds, destsounds, 'end.wav'); + CheckFile(sourcesounds, destsounds, 'warning.wav'); + CheckFile(sourcesounds, destsounds, 'welcome.wav'); +end; + +Procedure Reload; +begin + Fermentables.Free; + Hops.Free; + Miscs.Free; + Yeasts.Free; + Waters.Free; + Equipments.Free; + Beerstyles.Free; + Mashs.Free; + Recipes.Free; + Brews.Free; + Settings.Free; + Settings := TBSettings.Create; + Settings.Read; + + CheckDataFolder; + + Fermentables:= TFermentables.Create; + Hops:= THops.Create; + Miscs:= TMiscs.Create; + Yeasts:= TYeasts.Create; + Waters:= TWaters.Create; + Equipments:= TEquipments.Create; + Beerstyles:= TBeerstyles.Create; + Mashs:= TMashs.Create; + Recipes:= TRecipes.Create; + + Brews:= TRecipes.Create; + Brews.FileName:= 'brews.xml'; + + loc:= Settings.DataLocation.Value; + if (loc = '') or OnUSB then loc:= BHFolder; + if InitializeHD('fermentables.xml', loc) then + begin + Settings.DataLocation.Value:= loc; + Fermentables.ReadXML; + Hops.ReadXML; + Miscs.ReadXML; + Yeasts.ReadXML; + Waters.ReadXML; + Equipments.ReadXML; + Beerstyles.ReadXML; + Mashs.ReadXML; + Application.ProcessMessages; + Recipes.ReadXML; + Recipes.CheckAutoNrs; + Application.ProcessMessages; + Brews.ReadXML; + Brews.CheckAutoNrs; + + CheckSalts; + end + else + ShowMessage('Databestanden niet gevonden'); +end; + +Procedure ChangeDatabaseLocation(source, destination : string; copy, deleteold : boolean); + function CheckCopyFile(sd, dd, fn : string) : boolean; + begin + Result:= false; + if FileExists(sd + fn) then + result:= CopyFile(sd + fn, dd + fn); + end; +var SearchResult : TSearchRec; + i : integer; + SL : TStringList; + StylesN, FermN, HopN, MiscN, YeastN, WaterN, sourcedata : string; +begin + {$ifdef UNIX} + destination:= destination + '/'; + {$else} + destination:= destination + '\'; + {$endif} + Settings.DataLocation.Value:= destination; + + if not copy then + begin + StylesN:= destination + 'styles.xml'; + FermN:= destination + 'fermentables.xml'; + HopN:= destination + 'hops.xml'; + MiscN:= destination + 'miscs.xml'; + YeastN:= destination + 'yeasts.xml'; + WaterN:= destination + 'waters.xml'; + if FileExists(StylesN) and FileExists(FermN) and FileExists(HopN) and + FileExists(MiscN) and FileExists(YeastN) and FileExists(WaterN) then + begin + Brews.ReadXML; + Equipments.ReadXML; + Fermentables.ReadXML; + Hops.ReadXML; + Mashs.ReadXML; + Miscs.ReadXML; + Recipes.ReadXML; + Beerstyles.ReadXML; + Waters.ReadXML; + Yeasts.ReadXML; + StyleSubs.ReadXML; + FermentableSubs.ReadXML; + YeastSubs.ReadXML; + BHNNs.ReadXML; + end + else //copy previous database to new location, but clear brews + begin + {$ifdef linux} + sourcedata:= '/usr/share/brewbuddy/'; + {$endif} + {$ifdef darwin} + sourcedata:= '/usr/local/share/brewbuddy/'; + {$endif} + {$ifdef Windows} + sourcedata:= ExtractFilePath(Application.ExeName) + 'brewbuddy\'; + if OnUSB then BHFolder:= DriveLetter + '\brewbuddy\brewbuddy\' + else BHFolder:= destination; + {$endif} + + Equipments.SaveXML; + Fermentables.SaveXML; + Hops.SaveXML; + Mashs.SaveXML; + Miscs.SaveXML; + Recipes.SaveXML; + Beerstyles.SaveXML; + Waters.SaveXML; + Yeasts.SaveXML; + StyleSubs.SaveXML; + FermentableSubs.SaveXML; + YeastSubs.SaveXML; + BHNNs.SaveXML; + SL:= FindAllFiles(source, '*.nn', false); + for i:= 0 to SL.Count - 1 do + CheckCopyFile(source, destination, ExtractFileName(SL.Strings[i])); + FreeAndNIL(SL); + Brews.FreeCollection; + CheckCopyFile(source, destination, 'Introductie BrewBuddy Sassy Saison.pdf'); + CheckCopyFile(source, destination, 'styles-BJCP.xml'); + CheckCopyFile(source, destination, 'logo.png'); + CheckDataFolder; + end; + + //delete files in old directory + if deleteold then + begin + DeleteFile(PChar(source + 'brews.xml')); + DeleteFile(PChar(source + 'equipments.xml')); + DeleteFile(PChar(source + 'fermentables.xml')); + DeleteFile(PChar(source + 'hops.xml')); + DeleteFile(PChar(source + 'mashs.xml')); + DeleteFile(PChar(source + 'miscs.xml')); + DeleteFile(PChar(source + 'recipes.xml')); + DeleteFile(PChar(source + 'styles.xml')); + DeleteFile(PChar(source + 'waters.xml')); + DeleteFile(PChar(source + 'yeasts.xml')); + DeleteFile(PChar(source + 'stylesubs.xml')); + DeleteFile(PChar(source + 'fermentablesubs.xml')); + DeleteFile(PChar(source + 'yeastsubs.xml')); + DeleteFile(PChar(source + 'neuralnetworks.xml')); + SL:= FindAllFiles(source, '*.nn', false); + for i:= 0 to SL.Count - 1 do + DeleteFile(PChar(SL.Strings[i])); + FreeAndNIL(SL); + DeleteFile(PChar(source + 'Introductie BrewBuddy Sassy Saison.pdf')); + DeleteFile(PChar(source + 'styles-BJCP.xml')); + DeleteFile(PChar(source + 'logo.png')); + end; + FrmMain.cbBrewsSortChange(FrmMain); + FrmMain.cbRecipesSortChange(FrmMain); + end + else //copy from old directory and overwrite files in new directory + begin + Brews.SaveXML; + Equipments.SaveXML; + Fermentables.SaveXML; + Hops.SaveXML; + Mashs.SaveXML; + Miscs.SaveXML; + Recipes.SaveXML; + Beerstyles.SaveXML; + Waters.SaveXML; + Yeasts.SaveXML; + StyleSubs.SaveXML; + FermentableSubs.SaveXML; + YeastSubs.SaveXML; + BHNNs.SaveXML; + SL:= FindAllFiles(source, '*.nn', false); + for i:= 0 to SL.Count - 1 do + CheckCopyFile(source, destination, ExtractFileName(SL.Strings[i])); + FreeAndNIL(SL); + + //delete files in old directory + if deleteold then + begin + DeleteFile(PChar(source + 'brews.xml')); + DeleteFile(PChar(source + 'equipments.xml')); + DeleteFile(PChar(source + 'fermentables.xml')); + DeleteFile(PChar(source + 'hops.xml')); + DeleteFile(PChar(source + 'mashs.xml')); + DeleteFile(PChar(source + 'miscs.xml')); + DeleteFile(PChar(source + 'recipes.xml')); + DeleteFile(PChar(source + 'styles.xml')); + DeleteFile(PChar(source + 'waters.xml')); + DeleteFile(PChar(source + 'yeasts.xml')); + DeleteFile(PChar(source + 'stylesubs.xml')); + DeleteFile(PChar(source + 'fermentablesubs.xml')); + DeleteFile(PChar(source + 'yeastsubs.xml')); + DeleteFile(PChar(source + 'neuralnetworks.xml')); + SL:= FindAllFiles(source, '*.nn', false); + for i:= 0 to SL.Count - 1 do + DeleteFile(PChar(SL.Strings[i])); + FreeAndNIL(SL); + end; + end; + Settings.Save; +end; + +{====================== Initialization and Finalization =======================} + +Initialization + if DoLog then slLog:= TStringList.Create + else slLog:= NIL; + Screen.Cursor:= crHourglass; + + ExecFolder:= Application.Location; + log('ExecFolder = ' + ExecFolder); + OnUSB:= false; + {$ifdef linux} + {DriveLetter:= LeftStr(ExecFolder, 6); + if DriveLetter = '/media' then + begin + BHFolder:= ExecFolder; + end + else + begin} + BHFolder:= GetUserDir + '.brewbuddy/'; + // DataFolder:= GetUserDir + '.brewbuddy/'; + { end;} + SoundFolder:= BHFolder + 'sounds/'; + IconFolder:= BHFolder + 'icons/'; + Slash:= '/'; + {$endif} + {$ifdef darwin} + BHFolder:= GetUserDir + '.brewbuddy/'; +// DataFolder:= GetUserDir + '.brewbuddy/'; + SoundFolder:= BHFolder + 'sounds/'; + IconFolder:= BHFolder + 'icons/'; + Slash:= '/'; + {$endif} + {$ifdef windows} + DriveLetter:= LeftStr(ExecFolder, 2); + if GetDriveType(PChar(DriveLetter)) = DRIVE_REMOVABLE then + begin + Log('Gestart van USB'); + BHFolder:= DriveLetter + '\brewbuddy\brewbuddy\'; + OnUSB:= TRUE; + end + else + begin + Log('Gestart van harddisk'); + BHFolder:= GetWindowsSpecialDir(CSIDL_PERSONAL); //GetUserDir + if FileExists(BHFolder + 'My Documents\brewbuddy\settings.xml') then + BHFolder:= BHFolder + 'My Documents\brewbuddy\' + else + BHFolder:= BHFolder + 'brewbuddy\'; + end; + log('BHFolder = ' + BHFolder); + SoundFolder:= BHFolder + 'sounds\'; + IconFolder:= BHFolder + 'icons\'; + Slash:= '\'; + {$endif} + + CheckDataFolder; //settings are read here + + Fermentables:= TFermentables.Create; + Hops:= THops.Create; + Miscs:= TMiscs.Create; + Yeasts:= TYeasts.Create; + Waters:= TWaters.Create; + Equipments:= TEquipments.Create; + Beerstyles:= TBeerstyles.Create; + Mashs:= TMashs.Create; + Recipes:= TRecipes.Create; + + Brews:= TRecipes.Create; + Brews.FileName:= 'brews.xml'; + + BHNNs:= TBHNNs.Create; + + loc:= Settings.DataLocation.Value; + if loc = '' then loc:= BHFolder; + if OnUSB then //datalocation is also on the USB + loc:= BHFolder; + if InitializeHD('fermentables.xml', loc) then + begin + if not OnUSB then Settings.DataLocation.Value:= loc; + + BHCloud:= TBHCloud.Create; +// BHCloud.ReadCloud; + + Fermentables.ReadXML; + Hops.ReadXML; + Miscs.ReadXML; + Yeasts.ReadXML; + Waters.ReadXML; + Equipments.ReadXML; + Beerstyles.ReadXML; + Mashs.ReadXML; + Application.ProcessMessages; + Recipes.ReadXML; + Recipes.CheckAutoNrs; + Application.ProcessMessages; + Brews.ReadXML; + Brews.CheckAutoNrs; + + StyleSubs.ReadXML; + FermentableSubs.ReadXML; + YeastSubs.ReadXML; + + BHNNs.ReadXML; + + CheckSalts; + end + else + ShowMessage('Databestanden niet gevonden'); +// Equipments.CalcEfficiencyRegressionFactors; +// Equipments.CalcAttenuationRegressionFactors; + + { SetLength(Arr, 8); + Arr[0]:= 4; + Arr[1]:= 56; + Arr[2]:= 45; + Arr[3]:= 19; + Arr[4]:= 22; + Arr[5]:= 23; + Arr[6]:= 9; + Arr[7]:= 11; + Brews.ExportToCSV(Arr); + SetLength(Arr, 0);} + + Screen.Cursor:= crDefault; + +Finalization + if OnUSB then + begin + Settings.DataLocation.Value:= ''; + Settings.Save; + end; + Log(''); +// Log('CONTAINERS'); + FreeAndNIL(BHCloud); +// Log('BHCloud afgesloten'); + StyleSubs.SaveXML; +// Log('StyleSubs opgeslagen'); + FermentableSubs.SaveXML; +// Log('FermentableSubs opgeslagen'); + YeastSubs.SaveXML; +// Log('YeastSubs opgeslagen'); + FreeAndNIL(StyleSubs); +// Log('StyleSubs afgesloten'); + FreeAndNIL(FermentableSubs); +// Log('FermentableSubs afgesloten'); + FreeAndNIL(YeastSubs); +// Log('YeastSubs afgesloten'); + + FreeAndNIL(Fermentables); +// Log('Fermentables afgesloten'); + FreeAndNIL(Hops); +// Log('Hops afgesloten'); + FreeAndNIL(Miscs); +// Log('Miscs afgesloten'); + FreeAndNIL(Yeasts); +// Log('Yeasts afgesloten'); + FreeAndNIL(Waters); +// Log('Waters afgesloten'); + FreeAndNIL(Equipments); +// Log('Equipments afgesloten'); + FreeAndNIL(Beerstyles); +// Log('Beerstyles afgesloten'); + FreeAndNIL(Mashs); +// Log('Mashs afgesloten'); + FreeAndNIL(Recipes); +// Log('Recipes afgesloten'); + FreeAndNIL(Brews); +// Log('Brews afgesloten'); + FreeAndNIL(BHNNs); +// Log('BHNNs afgesloten'); + + Settings.Save; + Log('Settings opgeslagen'); + FreeAndNIL(Settings); +// Log('Settings afgesloten'); + + if DoLog then FreeAndNIL(slLog); +end. + diff --git a/Source/Units/backup/fann.pas b/Source/Units/backup/fann.pas new file mode 100644 index 00000000..2504568a --- /dev/null +++ b/Source/Units/backup/fann.pas @@ -0,0 +1,1228 @@ +unit FANN; +{$mode delphi} +interface +{******************************************************* + + Only Delphi 6 and above supports variable arguments + functions. + If you are using a older version of Delphi comment the + VARIABLE_ARGUMENTS directive. + If you disable the VARIABLE_ARGUMENTS directive the + following functions will not be available: + fann_create_shortcut + fann_create_sparse + fann_create_standard + +********************************************************} + +{$DEFINE VARIABLE_ARGUMENTS} + +{******************************************************* + + If you want to use Fixed Fann or Double Fann please + uncomment the corresponding definition. + As default fann.pas uses the fannfloat dll. + +********************************************************} +//{$DEFINE FIXEDFANN} //Uncomment for fixed fann +{$DEFINE DOUBLEFANN} //Uncomment for double fann + + + + +{$ifdef windows} +{$IF Defined(FIXEDFANN)} +const DLL_FILE = 'fannfixed.dll'; +{$ELSEIF Defined(DOUBLEFANN)} +const DLL_FILE = 'fanndouble.dll'; +{$ELSE} +const DLL_FILE = 'fannfloat.dll'; +{$IFEND} +{$endif} +{$ifdef linux} +{$IF Defined(FIXEDFANN)} +const DLL_FILE = 'libfixedfann.so'; +{$ELSEIF Defined(DOUBLEFANN)} +const DLL_FILE = 'libdoublefann.so'; +{$ELSE} +const DLL_FILE = 'libfloatfann.so'; +{$IFEND} +{$endif} +{$ifdef darwin} +{$IF Defined(FIXEDFANN)} +const DLL_FILE = 'libfixedfann.2.2.0.dylib'; +{$ELSEIF Defined(DOUBLEFANN)} +const DLL_FILE = '/usr/local/lib/libdoublefann.2.2.0.dylib'; +{$ELSE} +const DLL_FILE = 'libfloatfann.2.2.0.dylib'; +{$IFEND} +{$endif} + + +type + + {$IF Defined(FIXEDFANN)} + fann_type = integer; + {$ELSEIF Defined(DOUBLEFANN)} + fann_type = double; + {$ELSE} + fann_type = single; + {$IFEND} + + + PFann_Type = ^fann_type; + + PPFann_Type = ^pfann_type; + + Fann_Type_Array = array [0..65535] of fann_type; + + PFann_Type_Array = ^Fann_type_array; + + PPFann_Type_Array = array [0..65535] of ^Fann_Type_Array; + + + + + (* MICROSOFT VC++ STDIO'S FILE DEFINITION*) + _iobuf = packed record + _ptr: Pchar; + _cnt: integer; + _base: Pchar; + _flag: integer; + _file: integer; + _charbuf: integer; + _bufsiz: integer; + _tmpfname: Pchar; + end; + + + PFile = ^TFile; + TFile = _iobuf; + + + PPFann_Neuron = ^PFann_Neuron; + PFann_Neuron = ^TFann_Neuron; + TFann_Neuron = packed record + first_con: Cardinal; + last_con: Cardinal; + sum: fann_type; + value: fann_type; + activation_steepness: fann_type; + activation_function: Cardinal; //enum + end; + + + PFann_Layer = ^TFann_Layer; + TFann_Layer = packed record + first_neuron: PFann_Neuron; + last_neuron: PFann_Neuron; + end; + + PFann = ^TFann; + TFann = packed record + errno_f: cardinal; + error_log: PFile; + errstr: Pchar; + + learning_rate: single; + learning_momentum: single; + connection_rate: single; + + network_type: Cardinal; //ENUM + + first_layer: PFann_Layer; + last_layer: PFann_Layer; + + total_neurons: cardinal; + num_input: cardinal; + num_output: cardinal; + + weights: Pfann_type; + + connections: PPFann_Neuron; + + train_errors: Pfann_type; + + training_algorithm: cardinal; //ENUM + + + {$IFDEF FIXEDFANN} + decimal_point: cardinal; + multiplier: cardinal; + + sigmoid_results: array [0..5] of fann_type; + sigmoid_values: array [0..5] of fann_type; + symmetric_results: array [0..5] of fann_type; + symmetric_values: array [0..5] of fann_type; + + {$ENDIF} + + total_connections: cardinal; + output: pfann_type; + + num_MSE: cardinal; + MSE_value: single; + + num_bit_fail: cardinal; + bit_fail_limit: fann_type; + + train_error_function: cardinal;//enum + train_stop_function: cardinal; //enum + + callback: Pointer; //TFANN_CALLBACK + + user_data: Pointer; + + cascade_output_change_fraction: single; + cascade_output_stagnation_epochs: Cardinal; + cascade_candidate_change_fraction: single; + cascade_candidate_stagnation_epochs: Cardinal; + cascade_best_candidate: Cardinal; + + cascade_candidate_limit: fann_type; + cascade_weight_multiplier: fann_type; + + cascade_max_out_epochs: Cardinal; + cascade_max_cand_epochs: Cardinal; + + cascade_activation_functions: PCardinal; + cascade_activation_functions_count: Cardinal; + + cascade_activation_steepnesses: PFann_Type; + + cascade_activation_steepnesses_count: Cardinal; + cascade_num_candidate_groups: Cardinal; + + cascade_candidate_scores: PFann_Type; + + total_neurons_allocated: Cardinal; + total_connections_allocated: Cardinal; + + + + quickprop_decay: single; + quickprop_mu: single; + + rprop_increase_factor: single; + rprop_decrease_factor: single; + + rprop_delta_min: single; + rprop_delta_max: single; + + rprop_delta_zero: single; + + train_slopes: pfann_type; + + prev_steps: pfann_type; + + prev_train_slopes: pfann_type; + + prev_weights_deltas: pfann_type; + + {$IFNDEF FIXEDFANN} + scale_mean_in: psingle; + scale_deviation_in: psingle; + scale_new_min_in: psingle; + scale_factor_in: psingle; + scale_mean_out: psingle; + scale_deviation_out: psingle; + scale_new_min_out: psingle; + scale_factor_out: psingle; + + {$ENDIF} + end; + + PFann_Train_Data = ^TFann_Train_Data; + TFann_Train_Data = packed record + errno_f: cardinal; + erro_log: PFile; + errstr: Pchar; + num_data: cardinal; + num_input: cardinal; + num_ouput: cardinal; + input: PPFann_Type_Array; + output: PPFann_Type_Array; + end; + + PFann_Connection = ^TFann_Connection; + TFann_Connection = packed record + from_neuron: Cardinal; + to_neuron: Cardinal; + weight: fann_type; + end; + + PFann_Error = ^TFann_Error; + TFann_Error = packed record + errno_f: Cardinal; //Enum + error_log: PFile; + errstr: PChar; + end; + + + //_Fann_Train = + const + + FANN_TRAIN_INCREMENTAL = 0; + FANN_TRAIN_BATCH = 1; + FANN_TRAIN_RPROP = 2; + FANN_TRAIN_QUICKPROP = 3; + + + //_Fann_Error_Func = + + FANN_ERRORFUNC_LINEAR = 0; + FANN_ERRORFUNC_TANH = 1; + + + //_Fann_Activation_Func = + FANN_LINEAR = 0; + FANN_THRESHOLD = 1; + FANN_THRESHOLD_SYMMETRIC = 2; + FANN_SIGMOID = 3; + FANN_SIGMOID_STEPWISE = 4; + FANN_SIGMOID_SYMMETRIC = 5; + FANN_SIGMOID_SYMMETRIC_STEPWISE = 6; + FANN_GAUSSIAN = 7; + FANN_GAUSSIAN_SYMMETRIC = 8; + FANN_GAUSSIAN_STEPWISE = 9; + FANN_ELLIOT = 10; + FANN_ELLIOT_SYMMETRIC = 11; + FANN_LINEAR_PIECE = 12; + FANN_LINEAR_PIECE_SYMMETRIC = 13; + FANN_SIN_SYMMETRIC = 14; + FANN_COS_SYMMETRIC = 15; + FANN_SIN = 16; + FANN_COS = 17; + + + //_Fann_ErroNo = + FANN_E_NO_ERROR = 0; + FANN_E_CANT_OPEN_CONFIG_R = 1; + FANN_E_CANT_OPEN_CONFIG_W = 2; + FANN_E_WRONG_CONFIG_VERSION = 3; + FANN_E_CANT_READ_CONFIG = 4; + FANN_E_CANT_READ_NEURON = 5; + FANN_E_CANT_READ_CONNECTIONS = 6; + FANN_E_WRONG_NUM_CONNECTIONS = 7; + FANN_E_CANT_OPEN_TD_W = 8; + FANN_E_CANT_OPEN_TD_R = 9; + FANN_E_CANT_READ_TD = 10; + FANN_E_CANT_ALLOCATE_MEM = 11; + FANN_E_CANT_TRAIN_ACTIVATION = 12; + FANN_E_CANT_USE_ACTIVATION = 13; + FANN_E_TRAIN_DATA_MISMATCH = 14; + FANN_E_CANT_USE_TRAIN_ALG = 15; + FANN_E_TRAIN_DATA_SUBSET = 16; + FANN_E_INDEX_OUT_OF_BOUND = 17; + FANN_E_SCALE_NOT_PRESENT = 18; + + + //_Fann_Stop_Func = + + FANN_STOPFUNC_MSE = 0; + FANN_STOPFUNC_BIT = 1; + + //_Fann_Net_Type = + FANN_NETTYPE_LAYER = 0; + FANN_NETTYPE_SHORTCUT = 1; + + type + + TFann_CallBack = function(Ann: PFann; + train: PFann_Train_Data; + max_epochs: Cardinal; + epochs_between_reports: cardinal; + desired_error: single; + epochs: cardinal): integer; cdecl; + + TUser_Function = procedure(num: Cardinal; + num_input: Cardinal; + num_output: cardinal; + input: PFann_Type; + output: PFann_Type); cdecl; + + + + +var + FANN_ERRORFUNC_NAMES: array [0..1] of string = ( + 'FANN_ERRORFUNC_LINEAR', + 'FANN_ERRORFUNC_TANH' + ); + + FANN_TRAIN_NAMES: array [0..3] of string = + ( + 'FANN_TRAIN_INCREMENTAL', + 'FANN_TRAIN_BATCH', + 'FANN_TRAIN_RPROP', + 'FANN_TRAIN_QUICKPROP' + ); + + FANN_ACTIVATIONFUNC_NAMES: array [0..17] of string = + ( + 'FANN_LINEAR', + 'FANN_THRESHOLD', + 'FANN_THRESHOLD_SYMMETRIC', + 'FANN_SIGMOID', + 'FANN_SIGMOID_STEPWISE', + 'FANN_SIGMOID_SYMMETRIC', + 'FANN_SIGMOID_SYMMETRIC_STEPWISE', + 'FANN_GAUSSIAN', + 'FANN_GAUSSIAN_SYMMETRIC', + 'FANN_GAUSSIAN_STEPWISE', + 'FANN_ELLIOT', + 'FANN_ELLIOT_SYMMETRIC', + 'FANN_LINEAR_PIECE', + 'FANN_LINEAR_PIECE_SYMMETRIC', + 'FANN_SIN_SYMMETRIC', + 'FANN_COS_SYMMETRIC', + 'FANN_SIN', + 'FANN_COS' + ); + + FANN_STOPFUNC_NAMES: array [0..1] of string = + ( + 'FANN_STOPFUNC_MSE', + 'FANN_STOPFUNC_BIT' + ); + + FANN_NETTYPE_NAMES: array [0..1] of string = + ( + 'FANN_NETTYPE_LAYER', + 'FANN_NETTYPE_SHORTCUT' + ); + + + //DECLARATIONS FROM FANN.H + + {$IFDEF VARIABLE_ARGUMENTS} + + { + + ATTENTION! + If your compilation breaks here maybe you are using a version of Delphi + prior to 6. In this case you should comment the VARIABLE_ARGUMENTS define + at the beginning of this file and live without this functions! + + } + function fann_create_standard(num_layers: Cardinal): PFann; cdecl; varargs; + + function fann_create_sparse(connection_rate: single; num_layers: Cardinal): PFann; cdecl; varargs; + + function fann_create_shortcut(connection_rate: single): PFann; cdecl; varargs; + + + {$ENDIF} + + + function fann_create_standard_array(num_layers: Cardinal; const layers: PCardinal): PFann; cdecl; + + function fann_create_sparse_array(connection_rate: single; num_layers: Cardinal; const layers: PCardinal): PFann; cdecl; + + function fann_create_shortcut_array(num_layers: cardinal;const layers: Pcardinal): PFann; cdecl; + + + procedure fann_destroy(Ann: PFann); cdecl; + + + function fann_run(ann: PFann; input: PFann_Type): Pfann_type_array; cdecl; + + + procedure fann_randomize_weights(Ann: PFann; Min_weight: fann_type; Max_weight: fann_type); cdecl; + + procedure fann_init_weights(Ann: PFann; train_data: PFann_Train_Data); cdecl; + + + procedure fann_print_connections(ann: PFann);cdecl; + + procedure fann_print_parameters(ann: PFann);cdecl; + + + function fann_get_num_input(Ann: PFann): cardinal;cdecl; + + function fann_get_num_output(Ann: PFann): cardinal;cdecl; + + function fann_get_total_neurons(Ann: PFann): cardinal; cdecl; + + function fann_get_total_connections(Ann: PFann): cardinal; cdecl; + + + function fann_get_network_type(Ann: PFann): cardinal; cdecl; + + function fann_get_connection_rate(Ann: PFann): single; cdecl; + + + function fann_get_num_layers(Ann: PFann): cardinal; cdecl; + + + procedure fann_get_layer_array(Ann: PFann; layers: PCardinal); cdecl; + + procedure fann_get_bias_array(Ann: PFann; bias: PCardinal);cdecl; + + + procedure fann_get_connection_array(Ann: PFann; connections: PFann_Connection);cdecl; + + + procedure fann_set_weight_array(Ann: PFann; connections: PFann_Connection; num_connection: Cardinal);cdecl; + + + procedure fann_set_weight(Ann: PFann; from_neuron: Cardinal; to_neuron: Cardinal; weight: fann_type);cdecl; + + procedure fann_set_user_data(Ann: PFann; user_data: Pointer);cdecl; + + function fann_get_user_data(Ann: PFann): Pointer; cdecl; + + + {$IFDEF FIXEDFANN} + + function fann_get_decimal_point(Ann: Pfann): cardinal; cdecl; + + function fann_get_multiplier(Ann: PFann): cardinal;cdecl; + + {$ENDIF} + + //END OF DECLARATIONS FROM FANN.H + + + + //DECLARATIONS FROM FANN_IO.H + + + function fann_create_from_file(const configuration_file: PChar): PFann; cdecl; + + procedure fann_save(Ann: PFann; Const Configuration_File: PChar);cdecl; + + function fann_save_to_fixed(Ann: PFann; Const Configuration_File: PChar): integer;cdecl; + + //END OF DECLARATIONS FROM FANN_IO.H + + + //DECLARATIONS FROM FANN_TRAIN.H + + {$IFNDEF FIXEDFANN} + procedure fann_train(Ann: PFann; Input: PFann_Type; Desired_Output: PFann_Type);cdecl; + {$ENDIF} + + function fann_test(Ann: PFann; Input: PFann_Type; Desired_Output: Pfann_Type): Pfann_type_array;cdecl; + + + function fann_get_MSE(Ann: PFann): single;cdecl; + + function fann_get_bit_fail(Ann: PFann): Cardinal;cdecl; + + procedure fann_reset_MSE(Ann: Pfann); cdecl; + + + {$IFNDEF FIXEDFANN} + + + procedure fann_train_on_data(Ann: PFann; Data: PFann_Train_Data;max_epochs: cardinal;epochs_between_reports: cardinal; desired_error: single);cdecl; + + procedure fann_train_on_file(Ann: PFann; Filename: Pchar;max_epochs: cardinal;epochs_between_reports: cardinal; desired_error: single); cdecl; + + + + function fann_train_epoch(Ann: PFann; data: PFann_Train_Data): single; cdecl; + + + function fann_test_data(Ann: PFann; data: PFann_Train_Data): single; cdecl; + + {$ENDIF} + + function fann_read_train_from_file(const filename: PChar): PFann_Train_Data; cdecl; + + + + function fann_create_train_from_callback(num_data: Cardinal; + num_input: Cardinal; + num_output: Cardinal; + user_function: TUser_Function): PFann_Train_Data; cdecl; + + + + procedure fann_destroy_train(train_data: PFann_Train_Data); cdecl; + + + procedure fann_shuffle_train_data(Train_Data: PFann_Train_Data);cdecl; + + + procedure fann_scale_train(Ann: PFann; data: PFann_Train_Data);cdecl; + + procedure fann_descale_train(Ann: PFann; data: PFann_Train_Data);cdecl; + + + function fann_set_input_scaling_params(Ann: PFann; + const data: PFann_Train_Data; + new_input_min: single; + new_input_max: single): integer;cdecl; + + + function fann_set_output_scaling_params(Ann: PFann; + const data: PFann_Train_Data; + new_output_min: single; + new_output_max: single): integer;cdecl; + + + + function fann_set_scaling_params(Ann: PFann; + const data: PFann_Train_Data; + new_input_min: single; + new_input_max: single; + new_output_min: single; + new_output_max: single): integer; cdecl; + + + function fann_clear_scaling_params(Ann: PFann): integer; cdecl; + + + + procedure fann_scale_input(Ann: PFann; input_vector: PFann_type); cdecl; + + + procedure fann_scale_output(Ann: PFann; output_vector: PFann_type); cdecl; + + + procedure fann_descale_input(Ann: PFann; input_vector: PFann_type); cdecl; + + + procedure fann_descale_output(Ann: PFann; output_vector: PFann_type); cdecl; + + + procedure fann_scale_input_train_data(Train_Data: PFann_Train_Data; + new_min: fann_type; + new_max: fann_type); cdecl; + + + procedure fann_scale_output_train_data(Train_Data: PFann_Train_Data; + new_min: fann_type; + new_max: fann_type); cdecl; + + + procedure fann_scale_train_data(Train_Data: PFann_Train_Data; + new_min: fann_type; + new_max: fann_type); cdecl; + + + function fann_merge_train_data(Data1: PFann_Train_Data; Data2: PFann_Train_Data): PFann_Train_Data; cdecl; + + + function fann_duplicate_train_data(Data: PFann_Train_Data): PFann_Train_Data;cdecl; + + + function fann_subset_train_data(data: PFann_Train_Data; pos: Cardinal; length: Cardinal): PFann_Train_Data; cdecl; + + + function fann_length_train_data(data: PFann_Train_Data): Cardinal; cdecl; + + + function fann_num_input_train_data(data: PFann_Train_Data): Cardinal; cdecl; + + function fann_num_output_train_data(data: PFann_Train_Data): Cardinal; cdecl; + + function fann_save_train(Data: PFann_train_Data; const Filename: PChar): integer;cdecl; + + function fann_save_train_to_fixed(Data: PFann_train_Data; const FileName: Pchar; decimal_point: cardinal): integer;cdecl; + + + + function fann_get_training_algorithm(Ann: Pfann): cardinal;cdecl; + + procedure fann_set_training_algorithm(Ann: PFann; Training_Algorithm: cardinal);cdecl; + + function fann_get_learning_rate(Ann: PFann): single;cdecl; + + procedure fann_set_learning_rate(Ann: PFann; Learning_Rate: Single); cdecl; + + function fann_get_learning_momentum(Ann: PFann): single;cdecl; + + procedure fann_set_learning_momentum(Ann: PFann; learning_momentum: Single); cdecl; + + + + function fann_get_activation_function(Ann: PFann; layer: integer; neuron: integer): Cardinal; cdecl; //ENUM + + procedure fann_set_activation_function(Ann: PFann; activation_function: Cardinal; layer: integer; neuron: integer); cdecl; //ENUM + + + procedure fann_set_activation_function_layer(Ann: PFann; activation_function: Cardinal; layer: integer); cdecl; //ENUM + + + procedure fann_set_activation_function_hidden(Ann: Pfann; Activation_function: cardinal); cdecl; + + procedure fann_set_activation_function_output(Ann: Pfann; Activation_Function: cardinal); cdecl; + + function fann_get_activation_steepness(Ann: PFann; layer: integer; neuron: integer): fann_type; cdecl; + + + procedure fann_set_activation_steepness(Ann: PFann; steepness: fann_type; layer: integer; neuron: integer); cdecl; + + + procedure fann_set_activation_steepness_layer(Ann: PFann; steepness: fann_type; layer: integer); cdecl; + + + procedure fann_set_activation_steepness_hidden(Ann: PFann; steepness: Fann_Type); cdecl; + + procedure fann_set_activation_steepness_output(Ann: PFann; steepness: Fann_Type);cdecl; + + function fann_get_train_error_function(Ann: PFann): cardinal;cdecl; + + procedure fann_set_train_error_function(Ann: PFann; Train_Error_Function: cardinal); cdecl; + + function fann_get_train_stop_function(Ann: PFann): Cardinal; cdecl; + + procedure fann_set_train_stop_function(Ann: PFann; train_stop_function: cardinal); cdecl; + + function fann_get_bit_fail_limit(Ann: PFann): fann_type; cdecl; + + procedure fann_set_bit_fail_limit(Ann: PFann; bit_fail_limit: fann_type); cdecl; + + procedure fann_set_callback(Ann: PFann; callback: TFann_Callback); cdecl; + + function fann_get_quickprop_decay(Ann: PFann): single;cdecl; + + procedure fann_set_quickprop_decay(Ann: Pfann; quickprop_decay: Single);cdecl; + + function fann_get_quickprop_mu(Ann: PFann): single;cdecl; + + procedure fann_set_quickprop_mu(Ann: PFann; Mu: Single);cdecl; + + function fann_get_rprop_increase_factor(Ann: PFann): single;cdecl; + + procedure fann_set_rprop_increase_factor(Ann: PFann;rprop_increase_factor: single);cdecl; + + function fann_get_rprop_decrease_factor(Ann: PFann): single;cdecl; + + procedure fann_set_rprop_decrease_factor(Ann: PFann;rprop_decrease_factor: single); cdecl; + + function fann_get_rprop_delta_min(Ann: PFann): single; cdecl; + + procedure fann_set_rprop_delta_min(Ann: PFann; rprop_delta_min: Single); cdecl; + + function fann_get_rprop_delta_max(Ann: PFann): single;cdecl; + + procedure fann_set_rprop_delta_max(Ann: PFann; rprop_delta_max: Single); cdecl; + + function fann_get_rprop_delta_zero(Ann: PFann): single;cdecl; + + procedure fann_set_rprop_delta_zero(Ann: PFann; rprop_delta_zero: Single); cdecl; + + //END OF DECLARATIONS OF FANN_TRAIN.H + + + //DECLARATIONS OF FANN_ERROR.H + + procedure fann_set_error_log(errdat: PFann_Error; Log_File: PFile);cdecl; + + function fann_get_errno(errdat: PFann_Error): cardinal;cdecl; + + procedure fann_reset_errno(errdat: PFann_Error);cdecl; + + procedure fann_reset_errstr(errdat: PFann_Error);cdecl; + + function fann_get_errstr(errdat: PFann_Error): PChar;cdecl; + + procedure fann_print_error(Errdat: PFann_Error);cdecl; + + + //END OF DECLARATIONS OF FANN_ERROR + + //DECLARATIONS OF FANN_CASCADE.H + + procedure fann_cascadetrain_on_data(Ann: PFann; + data: PFann_Train_Data; + max_neurons: Cardinal; + neurons_between_reports: Cardinal; + desired_error: single); cdecl; + + procedure fann_cascadetrain_on_file(Ann: PFann; + const filename: PChar; + max_neurons: Cardinal; + neurons_between_reports: Cardinal; + desired_error: single); cdecl; + + + function fann_get_cascade_output_change_fraction(Ann: PFann): single; cdecl; + + + procedure fann_set_cascade_output_change_fraction(Ann: PFann; cascade_output_change_fraction: single); cdecl; + + + function fann_get_cascade_output_stagnation_epochs(Ann: PFann): cardinal; cdecl; + + + procedure fann_set_cascade_output_stagnation_epochs(Ann: PFann; cascade_output_stagnation_epochs: cardinal); cdecl; + + + function fann_get_cascade_candidate_change_fraction(Ann: PFann): single; cdecl; + + + procedure fann_set_cascade_candidate_change_fraction(Ann: PFann; cascade_candidate_change_fraction: single); cdecl; + + + function fann_get_cascade_candidate_stagnation_epochs(Ann: PFann): cardinal; cdecl; + + + procedure fann_set_cascade_candidate_stagnation_epochs(Ann: PFann; cascade_candidate_stagnation_epochs: cardinal); cdecl; + + + function fann_get_cascade_weight_multiplier(Ann: PFann): fann_type; cdecl; + + + procedure fann_set_cascade_weight_multiplier(Ann: PFann; cascade_weight_multiplier: fann_type); cdecl; + + + function fann_get_cascade_candidate_limit(Ann: PFann): fann_type; cdecl; + + + procedure fann_set_cascade_candidate_limit(Ann: PFann; cascade_candidate_limit: fann_type); cdecl; + + + + function fann_get_cascade_max_out_epochs(Ann: PFann): cardinal; cdecl; + + + procedure fann_set_cascade_max_out_epochs(Ann: PFann; cascade_max_out_epochs: cardinal); cdecl; + + + function fann_get_cascade_max_cand_epochs(Ann: PFann): cardinal; cdecl; + + + procedure fann_set_cascade_max_cand_epochs(Ann: PFann; cascade_max_cand_epochs: cardinal); cdecl; + + + function fann_get_cascade_num_candidates(Ann: PFann): cardinal; cdecl; + + + function fann_get_cascade_activation_functions_count(Ann: PFann): cardinal; cdecl; + + + + function fann_get_cascade_activation_functions(Ann: PFann): PCardinal; cdecl; + + + procedure fann_set_cascade_activation_functions(Ann: PFann; cascade_activation_functions: PCardinal; cascade_activation_functions_count: Cardinal); cdecl; + + + function fann_get_cascade_activation_steepnesses_count(Ann: PFann): cardinal; cdecl; + + + function fann_get_cascade_activation_steepnesses(Ann: PFann): pfann_type; cdecl; + + procedure fann_set_cascade_activation_steepnesses(Ann: PFann; cascade_activation_steepnesses: PFann_Type; cascade_activation_steepnesses_count: Cardinal); cdecl; + + + function fann_get_cascade_num_candidate_groups(Ann: PFann): cardinal; cdecl; + + + procedure fann_set_cascade_num_candidate_groups(Ann: PFann; cascade_num_candidate_groups: cardinal); cdecl; + + + //END OF DECLARATIONS OF FANN_CASCADE.H + + + +implementation + + + {$IFDEF VARIABLE_ARGUMENTS} + + function fann_create_standard; external DLL_FILE; + + {$ENDIF} + + + function fann_create_standard_array; external DLL_FILE; + + + {$IFDEF VARIABLE_ARGUMENTS} + + function fann_create_sparse; external DLL_FILE; + + {$ENDIF} + + + + function fann_create_sparse_array; external DLL_FILE; + + + + {$IFDEF VARIABLE_ARGUMENTS} + + function fann_create_shortcut; external DLL_FILE; + + {$ENDIF} + + + function fann_create_shortcut_array; external DLL_FILE; + + + procedure fann_destroy; external DLL_FILE; + + + function fann_run; external DLL_FILE; + + + procedure fann_randomize_weights; external DLL_FILE; + + procedure fann_init_weights; external DLL_FILE; + + + procedure fann_print_connections; external DLL_FILE; + + procedure fann_print_parameters; external DLL_FILE; + + + function fann_get_num_input; external DLL_FILE; + + function fann_get_num_output; external DLL_FILE; + + function fann_get_total_neurons; external DLL_FILE; + + function fann_get_total_connections; external DLL_FILE; + + + function fann_get_network_type; external DLL_FILE; + + function fann_get_connection_rate; external DLL_FILE; + + + function fann_get_num_layers; external DLL_FILE; + + + procedure fann_get_layer_array; external DLL_FILE; + + procedure fann_get_bias_array; external DLL_FILE; + + + procedure fann_get_connection_array; external DLL_FILE; + + + procedure fann_set_weight_array; external DLL_FILE; + + + procedure fann_set_weight; external DLL_FILE; + + procedure fann_set_user_data; external DLL_FILE; + + function fann_get_user_data; external DLL_FILE; + + + {$IFDEF FIXEDFANN} + + function fann_get_decimal_point; external DLL_FILE; + + function fann_get_multiplier; external DLL_FILE; + + {$ENDIF} + + //END OF DECLARATIONS FROM FANN.H + + + + //DECLARATIONS FROM FANN_IO.H + + + function fann_create_from_file; external DLL_FILE; + + procedure fann_save; external DLL_FILE; + + function fann_save_to_fixed; external DLL_FILE; + + //END OF DECLARATIONS FROM FANN_IO.H + + + //DECLARATIONS FROM FANN_TRAIN.H + + {$IFNDEF FIXEDFANN} + procedure fann_train; external DLL_FILE; + {$ENDIF} + + function fann_test; external DLL_FILE; + + + function fann_get_MSE; external DLL_FILE; + + function fann_get_bit_fail; external DLL_FILE; + + procedure fann_reset_MSE; external DLL_FILE; + + + {$IFNDEF FIXEDFANN} + + + procedure fann_train_on_data; external DLL_FILE; + + procedure fann_train_on_file; external DLL_FILE; + + + + function fann_train_epoch; external DLL_FILE; + + + function fann_test_data; external DLL_FILE; + + {$ENDIF} + + function fann_read_train_from_file; external DLL_FILE; + + + + function fann_create_train_from_callback; external DLL_FILE; + + + + procedure fann_destroy_train; external DLL_FILE; + + + procedure fann_shuffle_train_data; external DLL_FILE; + + + procedure fann_scale_train; external DLL_FILE; + + procedure fann_descale_train; external DLL_FILE; + + + function fann_set_input_scaling_params; external DLL_FILE; + + + function fann_set_output_scaling_params; external DLL_FILE; + + + + function fann_set_scaling_params; external DLL_FILE; + + + function fann_clear_scaling_params; external DLL_FILE; + + + + procedure fann_scale_input; external DLL_FILE; + + + procedure fann_scale_output; external DLL_FILE; + + + procedure fann_descale_input; external DLL_FILE; + + + procedure fann_descale_output; external DLL_FILE; + + + procedure fann_scale_input_train_data; external DLL_FILE; + + + procedure fann_scale_output_train_data; external DLL_FILE; + + + procedure fann_scale_train_data; external DLL_FILE; + + + function fann_merge_train_data; external DLL_FILE; + + + function fann_duplicate_train_data; external DLL_FILE; + + + function fann_subset_train_data; external DLL_FILE; + + + function fann_length_train_data; external DLL_FILE; + + + function fann_num_input_train_data; external DLL_FILE; + + function fann_num_output_train_data; external DLL_FILE; + + function fann_save_train; external DLL_FILE; + + function fann_save_train_to_fixed; external DLL_FILE; + + + + function fann_get_training_algorithm; external DLL_FILE; + + procedure fann_set_training_algorithm; external DLL_FILE; + + function fann_get_learning_rate; external DLL_FILE; + + procedure fann_set_learning_rate; external DLL_FILE; + + function fann_get_learning_momentum; external DLL_FILE; + + procedure fann_set_learning_momentum; external DLL_FILE; + + + + function fann_get_activation_function; external DLL_FILE; //ENUM + + procedure fann_set_activation_function; external DLL_FILE; //ENUM + + + procedure fann_set_activation_function_layer; external DLL_FILE; //ENUM + + + procedure fann_set_activation_function_hidden; external DLL_FILE; + + procedure fann_set_activation_function_output; external DLL_FILE; + + function fann_get_activation_steepness; external DLL_FILE; + + + procedure fann_set_activation_steepness; external DLL_FILE; + + + procedure fann_set_activation_steepness_layer; external DLL_FILE; + + + procedure fann_set_activation_steepness_hidden; external DLL_FILE; + + procedure fann_set_activation_steepness_output; external DLL_FILE; + + function fann_get_train_error_function; external DLL_FILE; + + procedure fann_set_train_error_function; external DLL_FILE; + + function fann_get_train_stop_function; external DLL_FILE; + + procedure fann_set_train_stop_function; external DLL_FILE; + + function fann_get_bit_fail_limit; external DLL_FILE; + + procedure fann_set_bit_fail_limit; external DLL_FILE; + + procedure fann_set_callback; external DLL_FILE; + + function fann_get_quickprop_decay; external DLL_FILE; + + procedure fann_set_quickprop_decay; external DLL_FILE; + + function fann_get_quickprop_mu; external DLL_FILE; + + procedure fann_set_quickprop_mu; external DLL_FILE; + + function fann_get_rprop_increase_factor; external DLL_FILE; + + procedure fann_set_rprop_increase_factor; external DLL_FILE; + + function fann_get_rprop_decrease_factor; external DLL_FILE; + + procedure fann_set_rprop_decrease_factor; external DLL_FILE; + + function fann_get_rprop_delta_min; external DLL_FILE; + + procedure fann_set_rprop_delta_min; external DLL_FILE; + + function fann_get_rprop_delta_max; external DLL_FILE; + + procedure fann_set_rprop_delta_max; external DLL_FILE; + + function fann_get_rprop_delta_zero; external DLL_FILE; + + procedure fann_set_rprop_delta_zero; external DLL_FILE; + + //END OF DECLARATIONS OF FANN_TRAIN.H + + + //DECLARATIONS OF FANN_ERROR.H + + procedure fann_set_error_log; external DLL_FILE; + + function fann_get_errno; external DLL_FILE; + + procedure fann_reset_errno; external DLL_FILE; + + procedure fann_reset_errstr; external DLL_FILE; + + function fann_get_errstr; external DLL_FILE; + + procedure fann_print_error; external DLL_FILE; + + + //END OF DECLARATIONS OF FANN_ERROR + + //DECLARATIONS OF FANN_CASCADE.H + + procedure fann_cascadetrain_on_data; external DLL_FILE; + + procedure fann_cascadetrain_on_file; external DLL_FILE; + + + function fann_get_cascade_output_change_fraction; external DLL_FILE; + + + procedure fann_set_cascade_output_change_fraction; external DLL_FILE; + + + function fann_get_cascade_output_stagnation_epochs; external DLL_FILE; + + + procedure fann_set_cascade_output_stagnation_epochs; external DLL_FILE; + + + function fann_get_cascade_candidate_change_fraction; external DLL_FILE; + + + procedure fann_set_cascade_candidate_change_fraction; external DLL_FILE; + + + function fann_get_cascade_candidate_stagnation_epochs; external DLL_FILE; + + + procedure fann_set_cascade_candidate_stagnation_epochs; external DLL_FILE; + + + function fann_get_cascade_weight_multiplier; external DLL_FILE; + + + procedure fann_set_cascade_weight_multiplier; external DLL_FILE; + + + function fann_get_cascade_candidate_limit; external DLL_FILE; + + + procedure fann_set_cascade_candidate_limit; external DLL_FILE; + + + + function fann_get_cascade_max_out_epochs; external DLL_FILE; + + + procedure fann_set_cascade_max_out_epochs; external DLL_FILE; + + + function fann_get_cascade_max_cand_epochs; external DLL_FILE; + + + procedure fann_set_cascade_max_cand_epochs; external DLL_FILE; + + + function fann_get_cascade_num_candidates; external DLL_FILE; + + + function fann_get_cascade_activation_functions_count; external DLL_FILE; + + + + function fann_get_cascade_activation_functions; external DLL_FILE; + + + procedure fann_set_cascade_activation_functions; external DLL_FILE; + + + function fann_get_cascade_activation_steepnesses_count; external DLL_FILE; + + + function fann_get_cascade_activation_steepnesses; external DLL_FILE; + + procedure fann_set_cascade_activation_steepnesses; external DLL_FILE; + + + function fann_get_cascade_num_candidate_groups; external DLL_FILE; + + + procedure fann_set_cascade_num_candidate_groups; external DLL_FILE; + + + +end. + diff --git a/Source/Units/backup/hulpfuncties.pas b/Source/Units/backup/hulpfuncties.pas new file mode 100644 index 00000000..60080101 --- /dev/null +++ b/Source/Units/backup/hulpfuncties.pas @@ -0,0 +1,2531 @@ +unit Hulpfuncties; + +// temporarily removed the whole OpenAL sound library from the program for Linux since it causes weird floating point exceptions + +interface +uses + {$ifdef unix}clocale,{$endif} Classes, SysUtils, Variants, Math, Graphics, + Forms, Dialogs, strutils, frQuestion, frgetstring, frgetpasswd, + FrNotification //{$ifdef linux}, openal{$endif} + {$ifdef windows}, MMsystem{$endif}, Process; + +type + TUnit = (milligram, gram, kilogram, milliliter, liter, hectoliter, IBU, EBC, SRM, + SG, plato, brix, celcius, fahrenheit, minuut, uur, dag, week, ppm, volco2, + abv, perc, euro, pH, pph, calgdeg, kPa, bar, lintner, windischkolbach, + gpl, cal, pks, stks, depots, watt, lph, lpm, lpkg, meter, centimeter, meql, none); + THopUse = (huMash, huFirstwort, huBoil, huAroma, huWhirlpool, huDryhop); + THopType = (htBittering, htAroma, htBoth); + THopForm = (hfPellet, hfPlug, hfLeaf); + TFermentableType = (ftGrain, ftSugar, ftExtract, ftDryExtract, ftAdjunct); + TGrainType = (gtBase, gtRoast, gtCrystal, gtKilned, gtSour, gtSpecial, gtNone); + TAddedType = (atMash, atBoil, atFermentation, atLagering, atBottle); + TYeastType = (ytLager, ytAle, ytWheat, ytWine, ytChampagne); + TYeastForm = (yfLiquid, yfDry, yfSlant, yfCulture, yfFrozen, yfBottle); + TFlocculation = (flLow, flMedium, flHigh, lfVeryHigh); + TStarterType = (stSimple, stAerated, stStirred); + TMiscType = (mtSpice, mtHerb, mtFlavor, mtFining, mtWaterAgent, mtNutrient, mtOther); + TMiscUse = (muStarter, muMash, muBoil, muPrimary, muSecondary, muBottling); + TStyleType = (stLager, stAle, stMead, stWheat, stMixed, stCider); + TMashStepType = (mstInfusion, mstTemperature, mstDecoction); + TRecipeType = (rtExtract, rtPartialMash, rtAllGrain); + TIBUmethod = (imTinseth, imRager, imGaretz, imDaniels, imMosher, imNoonan); + TColorMethod = (cmMorey, cmMosher, cmDaniels); + TIngredientType = (itFermentable, itHop, itMisc, itYeast, itWater); + TDataType = (dtFermentable, dtHop, dtMisc, dtYeast, dtWater, dtMash, dtEquipment, + dtRecipe, dtStyle, dtMeasurements); + TCoolingMethod = (cmEmpty, cmEmersion, cmCouterFlow, cmAuBainMarie, cmNatural); + TAerationType = (atNone, atAir, atOxygen); + TPrimingSugar = (psSaccharose, psGlucose, psHoney, psDME, psMolassis); + TFileType = (ftPromash, ftXML, ftOther); + TAcidType = (atLactic, atHydrochloric, atPhosphoric, atSulfuric); + TBaseType = (btNaHCO3, btNa2CO3, btCaCO3, btCaOH2); + + TRecType = (rtRecipe, rtBrew, rtCloud); + + TSpecificHeat = record + Material : string; + SpecificHeat : double; + end; + + TCellCoord = record + Col : integer; + Row : integer; + end; + + TEndChar = set of char; + +const + UnitNames : array[TUnit] of string = ('mg', 'g', 'kg', 'ml', 'l', 'hl', 'IBU', 'EBC', + '°L', 'SG', '°P', '°B', '°C', '°F', 'min.', 'uren', 'dagen', + 'weken', 'mg/l', 'vol.', 'vol.%', '%', '€', 'pH', '%/uur', 'cal/g.°C', + 'kPa', 'bar', '°Lintner', '°WK', 'g/l', 'kcal/l', 'pak(ken)', + 'stuks', 'depots', 'W', 'l/uur', 'l/min', 'l/kg', + 'm', 'cm', 'mEq/l', ''); + DefaultDecimals : array[TUnit] of word = (1, 1, 2, 1, 2, 1, 0, 0, 1, 3, 1, 1, 1, 0, + 0, 0, 0, 0, 1, 1, 1, 1, 2, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 0); + DefaultIncrement : array[TUnit] of single = (1, 1, 0.5, 1, 0.5, 0.5, 1, 1, 1, 0.001, 0.5, + 0.5, 1, 1, 1, 1, 1, 1, 1, 1, 0.5, 1, 0.5, + 0.1, 0.5, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 0.1, 0); + DefaultMinValue : array[TUnit] of single = (0, 0, 0, 0, 0, 0, 0, 0, 0, 1.0, 0, + 0, 0, 32, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 1, 0, 0, 0, 0); + DefaultMaxValue : array[TUnit] of single = (2000, 10000, 10000, 10000, 10000, 100000, + 200, 1000, 1000, 1.3, 50, 50, 110, 230, + 240, 480, 365, 52, 10000, 10000, 100, 100, + 100000, 14, 100, 100000, 100, 100, 10000, + 10000, 1000, 1000, 1000, 1000, 1000, + 10000, 100, 100, 10, 10000, 10000, 1000, 0); + HopUseNames : array[THopUse] of string = ('Mash', 'First wort', 'Boil', 'Aroma', 'Whirlpool', 'Dry hop'); + HopUseDisplayNames : array[THopUse] of string = ('maischhop', 'first wort hop', 'koken', 'vlamuit', 'whirlpool', 'koudhop'); + HopTypeNames : array[THopType] of string = ('Bittering', 'Aroma', 'Both'); + HopTypeDisplayNames : array[THopType] of string = ('bitterhop', 'aromahop', 'beide'); + HopFormNames : array[THopForm] of string = ('Pellet', 'Plug', 'Leaf'); + HopFormDisplayNames : array[THopForm] of string = ('pellets', 'plugs', 'bellen'); + FermentableTypeNames : array[TFermentableType] of string = ('Grain', 'Sugar', 'Extract', 'Dry extract', 'Adjunct'); + FermentableTypeDisplayNames : array[TFermentableType] of string = ('mout', 'suiker', 'vloeibaar extract', 'droog extract', 'ongemout graan'); + GrainTypeNames : array[TGrainType] of string = ('Base', 'Roast', 'Crystal', 'Kilned', 'Sour malt', 'Special', 'No malt'); + GrainTypeDisplayNames : array[TGrainType] of string = ('basismout', 'geroosterde mout', 'cara- of crystalmout', 'geëeste mout', 'zuurmout', 'speciale mout', 'n.v.t.'); + AddedTypeNames : array[TAddedType] of string = ('Mash', 'Boil', 'Fermentation', 'Lagering', 'Bottle'); + AddedTypeDisplayNames : array[TAddedType] of string = ('maischen', 'koken', 'vergisten', 'nagisten/lageren', 'bottelen'); + YeastTypeNames : array[TYeastType] of string = ('Lager', 'Ale', 'Wheat', 'Wine', 'Champagne'); + YeastTypeDisplayNames : array[TYeastType] of string = ('ondergist', 'bovengist', 'weizengist', 'wijngist', 'champagnegist'); + YeastFormNames : array[TYeastForm] of string = ('Liquid', 'Dry', 'Slant', 'Culture', 'Frozen', 'Bottle'); + YeastFormDisplayNames : array[TYeastForm] of string = ('vloeibaar', 'droog', 'schuine buis', 'slurry', 'ingevroren', 'depot'); + FlocculationNames : array[TFlocculation] of string = ('Low', 'Medium', 'High', 'Very high'); + FlocculationDisplayNames : array[TFlocculation] of string = ('laag', 'medium', 'hoog', 'zeer hoog'); + StarterTypeNames : array[TStarterType] of string = ('Simple', 'Aerated', 'Stirred'); + StarterTypeDisplayNames : array[TStarterType] of string = ('simpel', 'belucht', 'geroerd'); + MiscTypeNames : array[TMiscType] of string = ('Spice', 'Herb', 'Flavor', 'Fining', 'Water agent', 'Yeast nutrient', 'Other'); + MiscTypeDisplayNames : array[TMiscType] of string = ('specerij', 'kruid', 'smaakstof', 'klaringsmiddel', 'brouwzout', 'gistvoeding', 'anders'); + MiscUseNames : array[TMiscUse] of string = ('Starter', 'Mash', 'Boil', 'Primary', 'Secondary', 'Bottling'); + MiscUseDisplayNames : array[TMiscUse] of string = ('starter', 'maischen', 'koken', 'hoofdvergisting', 'nagisting/lagering', 'bottelen'); + StyleTypeNames : array[TStyleType] of string = ('Lager', 'Ale', 'Mead', 'Wheat', 'Mixed', 'Cider'); + StyleTypeDisplayNames : array[TStyleType] of string = ('Ondergistend bier', 'Bovengistend bier', 'Mede', 'Tarwebier', 'Gemengd', 'Cider'); + MashStepTypeNames : array[TMashStepType] of string = ('Infusion', 'Temperature', 'Decoction'); + MashStepTypeDisplayNames : array[TMashStepType] of string = ('Infusie', 'Directe verwarming', 'Decoctie'); + RecipeTypeNames : array[TRecipeType] of string = ('Extract', 'Partial Mash', 'All Grain'); + RecipeTypeDisplayNames : array[TRecipeType] of string = ('Extract', 'Deelmaisch', 'Mout'); + IBUmethodNames : array[TIBUmethod] of string = ('Tinseth', 'Rager', 'Garetz', 'Daniels', 'Mosher', 'Noonan'); + IBUmethodDisplayNames : array[TIBUmethod] of string = ('Tinseth', 'Rager', 'Garetz', 'Daniels', 'Mosher', 'Noonan'); + ColorMethodNames : array[TColorMethod] of string = ('Morey', 'Mosher', 'Daniels'); + ColorMethodDisplayNames : array[TColorMethod] of string = ('Morey', 'Mosher', 'Daniels'); + IngredientTypeDisplayNames : array[TIngredientType] of string = ('Mout', 'Hop', 'Ov.', 'Gist', 'Water'); + CoolingMethodNames : array[TCoolingMethod] of string = ('-', 'Emersion chiller', 'Counterflow chiller', 'Au bain marie', 'Natural'); + CoolingMethodDisplayNames : array[TCoolingMethod] of string = ('-', 'Dompelkoeler', 'Tegenstroomkoeler', 'Au bain marie', 'Laten afkoelen'); + AerationTypeNames : array[TAerationType] of string = ('None', 'Air', 'Oxygen'); + AerationTypeDisplayNames : array[TAerationType] of string = ('Geen', 'Lucht', 'Zuurstof'); + PrimingSugarNames : array[TPrimingSugar] of string = ('Saccharose', 'Glucose or dextrose', 'Honey', 'DME', 'Molassis'); + PrimingSugarDisplayNames : array[TPrimingSugar] of string = ('Kristalsuiker', 'Glucose/dextrose', 'Honing', 'Moutextract', 'Melasse'); + PrimingSugarFactors : array[TPrimingSugar] of double = (1, 1.16, 1.28, 1.74, 3.83); + FileTypeNames : array[TFileType] of string = ('Promash', 'XML', 'Other'); + FileTypeDisplayNames : array[TFileType] of string = ('Promash', 'XML', 'Anders'); + AcidTypeNames : array[TAcidType] of string = ('Lactic', 'Hydrochloric', 'Phosphoric', 'Sulfuric'); + AcidTypeDisplayNames : array[TAcidType] of string = ('Melkzuur', 'Zoutzuur', 'Fosforzuur', 'Zwavelzuur'); + BaseTypeNames : array[TBaseType] of string = ('Sodiumbicarbonate', 'Sodiumcarbonate', 'Calciumcarbonate', 'Calciumhydroxide'); + BaseTypeDisplayNames : array[TBaseType] of string = ('NaHCO3', 'Na2CO3', 'CaCO3', 'Ca(OH)2'); + + + SpecificHeatWater : double = 1.0; //cal/g.°C + SpecificHeatMalt : double = 0.399; //cal/g.°C + SlakingHeat : double = 10.318; //cal/g.°C + MaltVolume : double = 0.87; //l/kg 0.688 VOLGENS INTERNETBRONNEN, GEMETEN 0.874 l/kg, na enige tijd maischen 0,715 l/kg + ExpansionFactor : double = 1.04; //4% increase in water volume between 20 and 100°C + SugarDensity : double = 1.611; //kg/l in solution + WaterDensity20 : double = 0.9982; //kg/l at 20°C + + Months : array[1..12] of string = ('januari', 'februari', 'maart', 'april', 'mei', + 'juni', 'juli', 'augustus', 'september', 'oktober', + 'november', 'december'); + MonthsShort : array[1..12] of string = ('jan', 'feb', 'mrt', 'apr', 'mei', + 'jun', 'jul', 'aug', 'sep', 'okt', + 'nov', 'dec'); + + SRMtoRGB : array[0..299, 0..3] of real = ((0.1, 250, 250, 210), (0.2, 250, 250, 204), (0.3, 250, 250, 199), (0.4, 250, 250, 193), (0.5, 250, 250, 188), (0.6, 250, 250, 182), (0.7, 250, 250, 177), (0.8, 250, 250, 171), (0.9, 250, 250, 166), (1, 250, 250, 160), (1.1, 250, 250, 155), (1.2, 250, 250, 149), (1.3, 250, 250, 144), (1.4, 250, 250, 138), (1.5, 250, 250, 133), (1.6, 250, 250, 127), (1.7, 250, 250, 122), (1.8, 250, 250, 116), (1.9, 250, 250, 111), (2, 250, 250, 105), (2.1, 250, 250, 100), (2.2, 250, 250, 94), (2.3, 250, 250, 89), (2.4, 250, 250, 83), (2.5, 250, 250, 78), (2.6, 249, 250, 72), (2.7, 248, 249, 67), (2.8, 247, 248, 61), (2.9, 246, 247, 56), (3, 245, 246, 50), (3.1, 244, 245, 45), (3.2, 243, 244, 45), (3.3, 242, 242, 45), (3.4, 241, 240, 46), (3.5, 240, 238, 46), (3.6, 239, 236, 46), (3.7, 238, 234, 46), (3.8, 237, 232, 47), (3.9, 236, 230, 47), (4, 235, 228, 47), (4.1, 234, 226, 47), (4.2, 233, 224, 48), (4.3, 232, 222, 48), (4.4, 231, 220, 48), (4.5, 230, 218, 48), (4.6, 229, 216, 49), (4.7, 228, 214, 49), (4.8, 227, 212, 49), (4.9, 226, 210, 49), (5, 225, 208, 50), (5.1, 224, 206, 50), (5.2, 223, 204, 50), (5.3, 222, 202, 50), (5.4, 221, 200, 51), (5.5, 220, 198, 51), (5.6, 219, 196, 51), (5.7, 218, 194, 51), (5.8, 217, 192, 52), (5.9, 216, 190, 52), (6, 215, 188, 52), (6.1, 214, 186, 52), (6.2, 213, 184, 53), (6.3, 212, 182, 53), (6.4, 211, 180, 53), (6.5, 210, 178, 53), (6.6, 209, 176, 54), (6.7, 208, 174, 54), (6.8, 207, 172, 54), (6.9, 206, 170, 54), (7, 205, 168, 55), (7.1, 204, 166, 55), (7.2, 203, 164, 55), (7.3, 202, 162, 55), (7.4, 201, 160, 56), (7.5, 200, 158, 56), (7.6, 200, 156, 56), (7.7, 199, 154, 56), (7.8, 199, 152, 56), (7.9, 198, 150, 56), (8, 198, 148, 56), (8.1, 197, 146, 56), (8.2, 197, 144, 56), (8.3, 196, 142, 56), (8.4, 196, 141, 56), (8.5, 195, 140, 56), (8.6, 195, 139, 56), (8.7, 194, 139, 56), (8.8, 194, 138, 56), (8.9, 193, 137, 56), (9, 193, 136, 56), (9.1, 192, 136, 56), (9.2, 192, 135, 56), (9.3, 192, 134, 56), (9.4, 192, 133, 56), (9.5, 192, 133, 56), (9.6, 192, 132, 56), (9.7, 192, 131, 56), (9.8, 192, 130, 56), (9.9, 192, 130, 56), (10, 192, 129, 56), (10.1, 192, 128, 56), (10.2, 192, 127, 56), (10.3, 192, 127, 56), (10.4, 192, 126, 56), (10.5, 192, 125, 56), (10.6, 192, 124, 56), (10.7, 192, 124, 56), (10.8, 192, 123, 56), (10.9, 192, 122, 56), (11, 192, 121, 56), (11.1, 192, 121, 56), (11.2, 192, 120, 56), (11.3, 192, 119, 56), (11.4, 192, 118, 56), (11.5, 192, 118, 56), (11.6, 192, 117, 56), (11.7, 192, 116, 56), (11.8, 192, 115, 56), (11.9, 192, 115, 56), (12, 192, 114, 56), (12.1, 192, 113, 56), (12.2, 192, 112, 56), (12.3, 192, 112, 56), (12.4, 192, 111, 56), (12.5, 192, 110, 56), (12.6, 192, 109, 56), (12.7, 192, 109, 56), (12.8, 192, 108, 56), (12.9, 191, 107, 56), (13, 190, 106, 56), (13.1, 189, 106, 56), (13.2, 188, 105, 56), (13.3, 187, 104, 56), (13.4, 186, 103, 56), (13.5, 185, 103, 56), (13.6, 184, 102, 56), (13.7, 183, 101, 56), (13.8, 182, 100, 56), (13.9, 181, 100, 56), (14, 180, 99, 56), (14.1, 179, 98, 56), (14.2, 178, 97, 56), (14.3, 177, 97, 56), (14.4, 175, 96, 55), (14.5, 174, 95, 55), (14.6, 172, 94, 55), (14.7, 171, 94, 55), (14.8, 169, 93, 54), (14.9, 168, 92, 54), (15, 167, 91, 54), (15.1, 165, 91, 54), (15.2, 164, 90, 53), (15.3, 162, 89, 53), (15.4, 161, 88, 53), (15.5, 159, 88, 53), (15.6, 158, 87, 52), (15.7, 157, 86, 52), (15.8, 155, 85, 52), (15.9, 154, 85, 52), (16, 152, 84, 51), (16.1, 151, 83, 51), (16.2, 149, 82, 51), (16.3, 148, 82, 51), (16.4, 147, 81, 50), (16.5, 145, 80, 50), (16.6, 144, 79, 50), (16.7, 142, 78, 50), (16.8, 141, 77, 49), (16.9, 139, 76, 49), (17, 138, 75, 48), (17.1, 137, 75, 47), (17.2, 135, 74, 47), (17.3, 134, 73, 46), (17.4, 132, 72, 45), (17.5, 131, 72, 45), (17.6, 129, 71, 44), (17.7, 128, 70, 43), (17.8, 127, 69, 43), (17.9, 125, 69, 42), (18, 124, 68, 41), (18.1, 122, 67, 41), (18.2, 121, 66, 40), (18.3, 119, 66, 39), (18.4, 118, 65, 39), (18.5, 117, 64, 38), (18.6, 115, 63, 37), (18.7, 114, 63, 37), (18.8, 112, 62, 36), (18.9, 111, 61, 35), (19, 109, 60, 34), (19.1, 108, 60, 33), (19.2, 107, 59, 32), (19.3, 105, 58, 31), (19.4, 104, 57, 29), (19.5, 102, 57, 28), (19.6, 101, 56, 27), (19.7, 99, 55, 26), (19.8, 98, 54, 25), (19.9, 97, 54, 24), (20, 95, 53, 23), (20.1, 94, 52, 21), (20.2, 92, 51, 20), (20.3, 91, 51, 19), (20.4, 89, 50, 18), (20.5, 88, 49, 17), (20.6, 87, 48, 16), (20.7, 85, 48, 15), (20.8, 84, 47, 13), (20.9, 82, 46, 12), (21, 81, 45, 11), (21.1, 79, 45, 10), (21.2, 78, 44, 9), (21.3, 77, 43, 8), (21.4, 75, 42, 9), (21.5, 74, 42, 9), (21.6, 72, 41, 10), (21.7, 71, 40, 10), (21.8, 69, 39, 11), (21.9, 68, 39, 11), (22, 67, 38, 12), (22.1, 65, 37, 12), (22.2, 64, 36, 13), (22.3, 62, 36, 13), (22.4, 61, 35, 14), (22.5, 59, 34, 14), (22.6, 58, 33, 15), (22.7, 57, 33, 15), (22.8, 55, 32, 16), (22.9, 54, 31, 16), (23, 52, 30, 17), (23.1, 51, 30, 17), (23.2, 49, 29, 18), (23.3, 48, 28, 18), (23.4, 47, 27, 19), (23.5, 45, 27, 19), (23.6, 44, 26, 20), (23.7, 42, 25, 20), (23.8, 41, 24, 21), (23.9, 39, 24, 21), (24, 38, 23, 22), (24.1, 37, 22, 21), (24.2, 37, 22, 21), (24.3, 36, 22, 21), (24.4, 36, 21, 20), (24.5, 35, 21, 20), (24.6, 35, 21, 20), (24.7, 34, 20, 19), (24.8, 34, 20, 19), (24.9, 33, 20, 19), (25, 33, 19, 18), (25.1, 32, 19, 18), (25.2, 32, 19, 18), (25.3, 31, 18, 17), (25.4, 31, 18, 17), (25.5, 30, 18, 17), (25.6, 30, 17, 16), (25.7, 29, 17, 16), (25.8, 29, 17, 16), (25.9, 28, 16, 15), (26, 28, 16, 15), (26.1, 27, 16, 15), (26.2, 27, 15, 14), (26.3, 26, 15, 14), (26.4, 26, 15, 14), (26.5, 25, 14, 13), (26.6, 25, 14, 13), (26.7, 24, 14, 13), (26.8, 24, 13, 12), (26.9, 23, 13, 12), (27, 23, 13, 12), (27.1, 22, 12, 11), (27.2, 22, 12, 11), (27.3, 21, 12, 11), (27.4, 21, 11, 10), (27.5, 20, 11, 10), (27.6, 20, 11, 10), (27.7, 19, 10, 9), (27.8, 19, 10, 9), (27.9, 18, 10, 9), (28, 18, 9, 8), (28.1, 17, 9, 8), (28.2, 17, 9, 8), (28.3, 16, 8, 7), (28.4, 16, 8, 7), (28.5, 15, 8, 7), (28.6, 15, 7, 6), (28.7, 14, 7, 6), (28.8, 14, 7, 6), (28.9, 13, 6, 5), (29, 13, 6, 5), (29.1, 12, 6, 5), (29.2, 12, 5, 4), (29.3, 11, 5, 4), (29.4, 11, 5, 4), (29.5, 10, 4, 3), (29.6, 10, 4, 3), (29.7, 9, 4, 3), (29.8, 9, 3, 2), (29.9, 8, 3, 2), (30, 8, 3, 2)); + + MMCa : double = 40.048; + MMMg : double = 24.305; + MMNa : double = 22.98976928; + MMCl : double = 35.453; + MMSO4 : double = 96.0626; + MMCO3 : double = 60.01684; + MMHCO3 : double = 61.01684; + MMCaSO4 : double = 172.171; + MMCaCl2 : double = 147.015; + MMCaCO3 : double = 100.087; + MMMgSO4 : double = 246.475; + MMNaHCO3 : double = 84.007; + MMNa2CO3 : double = 105.996; + MMNaCl : double = 58.443; + MMCaOH2 : double = 74.06268; + + {$ifdef unix} + numbuffers = 4; + numsources = 4; + startprog = 0; + warning = 1; + alarm = 2; + endprog = 3; + {$endif} + + AnalysisActive = TRUE; + FANNActive = TRUE; + + DoLog = false; + + {$ifdef windows} + DefaultFontHeight = 15; + {$endif} + {$ifdef linux} + DefaultFontHeight = 12; + {$endif} + {$ifdef darwin} + DefaultFontHeight = 12; + {$endif} + + +var + SpecificHeats : array[0..3] of TSpecificHeat; + DriveLetter : string; + OnUSB : boolean; + ExecFolder : string; + BHFolder : string; + SoundFolder : string; + IconFolder : string; + Slash : string; + EndChar : TEndChar; + FermentableColor, HopColor, MiscColor, WaterAgentColor, WaterColor, YeastColor, + FiningColor: TColor; + MaxGrowthFactor : double; + AmCellspGramDry, AmCellspPack, AmCellspMlSlurry : double; + + +// {$ifdef linux} +// buffer : array [0..numbuffers] of TALuint; //TALuint; +// source : array [0..numsources] of TALuint; //TALuint; +// sourcepos: array [0..2] of TALfloat= ( 0.0, 0.0, 0.0 ); //TALfloat= ( 0.0, 0.0, 0.0 ); +// sourcevel: array [0..2] of TALfloat= ( 0.0, 0.0, 0.0 ); //TALfloat= ( 0.0, 0.0, 0.0 ); +// listenerpos: array [0..2] of TALfloat= ( 0.0, 0.0, 0.0); //TALfloat= ( 0.0, 0.0, 0.0 ); +// listenervel: array [0..2] of TALfloat= ( 0.0, 0.0, 0.0); //TALfloat= ( 0.0, 0.0, 0.0 ); +// listenerori: array [0..5] of TALfloat= ( 0.0, 0.0, -1.0, 0.0, 1.0, 0.0); //TALfloat= ( 0.0, 0.0, -1.0, 0.0, 1.0, 0.0); +// +// argv: array of PalByte; +// format: TALEnum; //TALEnum; +// size: TALSizei; //TALSizei; +// freq: TALSizei; //TALSizei; +// loop: TALInt; //TALInt; +// dat: TALVoid; //TALVoid; +// {$endif} + + StartSound, EndSound, WarningSound, AlarmSound : string; + + slLog : TStringList; + +Function GetTaskBarSize: TRect; +Function InitializeHD(FN : string; var Dir : string) : boolean; +Function Convert(FromUnit : TUnit; ToUnit : TUnit; val : double) : double; +Procedure ConvertSeconds(var h, m, s, mi : word); +Function Sinus(angle : double) : double; //angle in degrees +Function Cosinus(angle : double) : double; //angle in degrees +Function Between(value, low, high : double) : boolean; +Function MaxD(a, b : double) : double; +Function MinD(a, b : double) : double; +Function MaxA(a : array of double) : double; +Function MinA(a : array of double) : double; +Function MinI(a, b : integer) : integer; +Function MaxI(a, b : integer) : integer; +Function RoundUp( R : Double) : LongInt; +Function InvLog(i : double) : double; +Procedure SwapW(var a, b : double); +Function DecimalsSc(S : Double) : LongInt; +Function GetOrdinals(S : extended) : LongInt; +Function GetDecimals(S : Double) : LongInt; +Function TLC(s : string) : string; +Function FormatString(S : extended; D : LongInt) : String; +Function StringFormat(S, X : Double; D : SmallInt) : string; +Function StrToReal(S : string) : Double; +Function RealToStr(S : Double) : string; +Function ValidateRealStr(S : string) : boolean; +Function RealToStrSci(S : Double; Prec : LongInt) : string; +Function RealToStrDEC(S : Double; D : SmallInt) : string; +Function RealToStrSignif(S : Double; Signif : SmallInt) : string; +Function Order(R : Double) : SmallInt; +Function StringToDate(s : string) : TDateTime; +Function IsValidDate(s : string) : boolean; +Function StringToTime(s : string) : TDateTime; +Function IsValidTime(s : string) : boolean; +Function SetDecimalSeparator(Sin : string) : string; +Function SetDecimalPoint(Sin : string) : string; +Function CountSubssInString(s, sub : string) : integer; +Function IsInString(searchString, SubString : string) : boolean; +Function FloatToStringDec(d : double; Dec: integer) : string; +Function FloatToDisplayString(d : double; Dec : integer; u : string) : string; +Function IntToDisplayString(i : integer; u : string) : string; +Procedure QuickSortArray(var Arr : array of double); +Procedure SelectionSortArray(var List : array of double); +Function SolveQuadratic(a, b, c : double; var X1, X2 : double) : integer; +Function SolveCubic(a, b, c, d : double; var X1, X2, X3 : double) : integer; +Procedure ShowNotification(sender : TComponent; s : string); +Procedure ShowNotificationModal(sender : TComponent; s : string); +Function Question(sender : TComponent; s : string) : boolean; +Function GetAnswer(sender : TComponent; Q : string) : string; +Function GetPasswd(sender : TComponent) : string; +Function RemInvChars(S : string) : string; + +Function DrawTxt(Canvas : TCanvas; MiddleHeight, Left, Right : LongInt; + Text : string; Alignment : TAlignment; + MoreLines : boolean) : integer; +Function DrawTxtRct( Canvas : TCanvas; R : TRect; + Text : string; Alignment : TAlignment; + MoreLines : boolean) : integer; +Procedure DrawTxtVarRct(canvas : TCanvas; Text : string; var R : TRect); +Function RotateText(Canvas : TCanvas; Xt, Yl, Deg : LongInt; Txt : string; + BackColor : tColor; Transparant : boolean) : boolean; +Procedure Scaling(var Min, Max, De : double; var Astr : LongInt); +Procedure CalcScale(var Min, Max, De : double; var AStr : LongInt); +Procedure ScaleFixed(var Min, Max, De : double; var Astr : LongInt); +Procedure ScaleDate(var Min, Max, De : TDateTime; var Astr : LongInt); +Function CalcTextHeight( FontSize, PPIY : integer) : integer; +Function CalcAmountLines( Canvas : TCanvas; Text : string; + Width : LongInt) : LongInt; +Function CalcAmountLines2(Font : TFont; Text : string; Width : LongInt) : LongInt; +Function CalcMaxWidth( Canvas : TCanvas; Text : string) : LongInt; +Function GiveNextLine( Canvas : TCanvas; Text : string; + Width : LongInt; var Pos : LongInt) : string; +Function NextWord( Line : string; var Pos : LongInt) : string; + +Function CalcFrac(TpH, pK1, pK2, pK3 : double) : double; +Function SRMtoEBC(d : double) : double; +Function EBCtoSRM(d : double) : double; +Function EBCtoColor(EBC : double) : TColor; +Function SRMtoColor(SRM : double) : TColor; +Function SGtoPlato(SG : Double) : Double; +Function PlatoToSG(plato : Double) : Double; +Function PlatoToExtract(P : Double) : Double; +Function SGtoBrix(SG : Double) : Double; +Function BrixToSG(Brix : Double) : Double; +Function BrixToFG(OBrix, FBrix : double) : double; +Function SGtoExtract(SG : Double) : Double; +Function ExtractToSG(E : Double) : Double; +Function BrixToRI(Brix : Double) : Double; +Function RE(SG : Double; Brix : Double) : Double; +Function AlcByVol(SG : Double; Brix : Double) : Double; +Function ABVol(OG : Double; FG : Double) : Double; +Function ABW(ABVol : Double; FG : Double) : Double; +Function ABW2(FG : Double; Brix : Double) : Double; +Function SGFerm(OBrix : Double; FBrix : Double) : Double; +Function RealExtract(FG : Double; Brix : Double) : Double; +Function FtoC(f : double) : double; +Function CtoF(c : double) : double; +Function Waterdensity(T : Double) : Double; +Function pHRoom(pHmash, Tm : double) : double; +Function DwatT(T : double; Tref : Double) : Double; +Function FreezingPoint(SG : Double; FG : Double) : Double; +Function StarterSize(types : Integer; soort : Double; V : Double; SG : Double; start : Double) : double; +Function StarterSize2(types : Integer; Needed : double; start : Double) : double; +Function AmountCells(types : Integer; V : Double; start : Double) : double; +Function GrowthFactor(types : Integer; V : Double; start : Double) : double; +Function CalcIBU(Method : TIBUmethod; HopUse : THopUse; AA : Double; AM : Double; Vw : Double; Vf : Double; SG : Double; Tboil : Double; HopVorm : THopForm; BNAP : Double) : Double; +Function AmHop(Method : TIBUmethod; HopUse : THopUse; AA : Double; IBU : Double; Vw : double; Vf : Double; SG : Double; Tboil : Double; HopVorm : THopForm; BNAP : Double) : Double; +Function IonBalance(Ca, Mg, Na, Cl, SO4, HCO3 : double) : double; +Function CarbStoCO2(S : double; T : double; SFactor : double) : double; +Function CarbCO2toS(CO2 : double; T : double; SFactor : double) : double; +Function CarbCO2toPressure(CO2 : double; T : double) : double; +Function CarbPressuretoCO2(P : double; T : double) : double; +Function ActualIBU(origibu, HSI, Temp : double; Elapsed, storagetype : longint) : double; + +Procedure PlayStartProg; +Procedure PlayEndProg; +Procedure PlayWarning; +Procedure PlayAlarm; + +//Procedure SetFontHeight(F : TForm; fs : integer); + +Function ConvertStringEnc(s : string) : string; + +Function ZipFiles(l : TStringList; zipfn : string) : boolean; +Function UnZipFiles(zipfn, outpath : string) : boolean; + +Procedure Log(s : string); + +implementation + +uses Data, FrMain, lconvencoding, Zipper; + +function GetTaskBarSize: TRect; +begin + {$ifdef Windows} +// SystemParametersInfo(SPI_GETWORKAREA, 0, @Result, 0); + {$endif} +end; + +Function ConvertStringEnc(s : string) : string; +var encs, encto: string; +begin + encto := GetDefaultTextEncoding; + encs := 'utf8'; + Result := ConvertEncoding(s, encs, encto); +// Result:= UTF8toANSI(Result); +end; + +Function InitializeHD(FN : string; var Dir : string) : boolean; +const waitT : word = 1; + Trials : integer = 5; +var i : integer; + sdd : TSelectDirectoryDialog; +begin + Result:= false; + i:= 1; + while (not Result) and (i < Trials) do + begin + Result:= FileExists(Dir + FN); + if (not Result) then + Sleep(1000 * waitT); + inc(i); + end; + if not Result then + begin + sdd:= TSelectDirectoryDialog.Create(frmMain); + sdd.Title:= 'Geef map met ' + FN; + sdd.Filter:= 'XML bestand|*.xml'; + sdd.FilterIndex:= 0; + if sdd.Execute then + begin + Dir:= sdd.FileName + Slash; + Result:= FileExists(Dir + FN); + end; + sdd.free; +// ShowNotification(frmMain, FN + 'niet gevonden.' + #10#13 + 'BrouwHulp sluit af'); + end; +end; + +Function Convert(FromUnit : TUnit; ToUnit : TUnit; val : double) : double; +begin +// TUnit = (milligram, gram, kilogram, milliliter, liter, hectoliter, IBU, EBC, SRM, +// SG, plato, brix, celcius, fahrenheit, minuut, uur, dag, week, ppm, +// volco2, abv, perc, euro, pH, pph, calgdeg, empty); + Result:= val; + case FromUnit of + milligram: + case ToUnit of + gram: Result:= val / 1000; + kilogram: Result:= val / 1000000; + end; + gram: + case ToUnit of + milligram: Result:= 1000 * val; + kilogram: Result:= val / 1000; + end; + kilogram: + case ToUnit of + milligram: Result:= 1000000 * val; + gram: Result:= 1000 * val; + end; + milliliter: + case ToUnit of + liter: Result:= val / 1000; + hectoliter: Result:= val / 100000; + end; + liter: + case ToUnit of + milliliter: Result:= 1000 * val; + hectoliter: Result:= 100 * val; + end; + hectoliter: + case ToUnit of + milliliter: Result:= 100000 * val; + liter: Result:= 100 * val; + end; + meter: + case ToUnit of + centimeter: Result:= 100 * val; + end; + centimeter: + case ToUnit of + meter: Result:= val / 100; + end; + EBC: + case ToUnit of + SRM: Result:= EBCtoSRM(val); + end; + SRM: + case ToUnit of + EBC: Result:= SRMtoEBC(val); + end; + SG: + case ToUnit of + plato: Result:= SGtoPlato(val); + brix: Result:= SGToPlato(val) * Settings.BrixCorrection.Value; + end; + plato: + case ToUnit of + SG: Result:= PlatoToSG(val); + brix: Result:= val * Settings.BrixCorrection.Value; + end; + brix: + if Settings.BrixCorrection.Value > 0 then + case ToUnit of + SG: Result:= PlatoToSG(val / Settings.BrixCorrection.Value); + plato: Result:= val / Settings.BrixCorrection.Value; + end; + celcius: + case ToUnit of + fahrenheit: Result:= CtoF(val); + end; + fahrenheit: + Case ToUnit of + celcius: Result:= FtoC(val); + end; + minuut: + case ToUnit of + uur: Result:= val / 60; + dag: Result:= val / (60 * 24); + week: Result:= val / (60 * 24 * 7); + end; + uur: + case ToUnit of + minuut: Result:= val * 60; + dag: Result:= val / 24; + week: Result:= val / (7 * 24); + end; + dag: + case ToUnit of + minuut : Result:= val * (60 * 24); + uur : Result:= val * 24; + week: Result:= val / 7; + end; + week: + case ToUnit of + minuut: Result:= val * 7 * 24 * 60; + uur: Result:= val * 7 * 24; + dag : Result:= val * 7; + end; + kPa: + case ToUnit of + bar: Result:= val / 100; + end; + bar: + case ToUnit of + kPa: Result:= 100 * val; + end; + lintner: + case ToUnit of + windischkolbach: Result:= 3.5 * val - 16; + end; + windischkolbach: + case ToUnit of + lintner: Result:= (val + 16) / 3.5; + end; + end; +end; + +Procedure ConvertSeconds(var h, m, s, mi : word); +begin + mi:= 0; + m:= s div 60; + s:= s mod 60; + h:= m div 60; + m:= m mod 60; +end; + +Function Sinus(angle : double) : double; //angle in degrees +var rad : double; +begin + rad:= 2 * PI * angle/360; + Result:= Sin(rad); +end; + +Function Cosinus(angle : double) : double; //angle in degrees +var rad : double; +begin + rad:= 2 * PI * angle/360; + Result:= Cos(rad); +end; + +Function Between(value, low, high : double) : boolean; +begin + Result:= false; + if (value >= low) and (value <= high) then Result:= TRUE; +end; + +Function MaxD(a, b : double) : double; +begin + if a > b then result:= a else result:= b; +end; + +Function MinD(a, b : double) : double; +begin + if a < b then result:= a else result:= b; +end; + +Function MaxA(a : array of double) : double; +var i : integer; +begin + Result:= a[Low(a)]; + for i:= Low(a) + 1 to High(a) do + if a[i] > Result then + Result:= a[i]; +end; + +Function MinA(a : array of double) : double; +var i : integer; +begin + Result:= a[Low(a)]; + for i:= Low(a) + 1 to High(a) do + if a[i] < Result then + Result:= a[i]; +end; + +Function MinI(a, b : integer) : integer; +begin + if a < b then Result:= a + else Result:= b; +end; + +Function MaxI(a, b : integer) : integer; +begin + if a > b then Result:= a + else Result:= b; +end; + +Function RoundUp( R : Double) : LongInt; +begin + Result:= Trunc(R); + if R < 0 then Result:= Trunc(R) - 1 + else if R > 0 then Result:= Trunc(R) + 1; +end; + +Function InvLog(i : double) : double; +begin + Result:= power(10, i); +end; + +Procedure SwapW(var a, b : double); +var c : double; +begin + c:= b; + b:= a; + a:= c; +end; + +Function DecimalsSc( S: Double): LongInt; +begin + if Abs(S) < 1 then Result:= Abs(Order(S)) + else Result:= 0; +end; + +Function GetOrdinals( S : Extended) : LongInt; +var AbsS : Extended; +begin + AbsS:= Abs(S); + if AbsS < 1 then result:= 1 {0,..} + else Result:= Trunc(Log10(AbsS)) + 1; + if S < 0 then Inc(Result); {Minus-sign} +end; + +Function GetDecimals( S : Double) : LongInt; +begin + if (ABS(S) < 100) and (S <> 0) then + begin + if S >= 1 then Result:= 1 - Trunc( log10(ABS(S)) ) + else Result:= Abs(Order(S)) + 2; + end + else Result:= 0; +end; + +Function TLC(s : string) : string; +begin + Result:= Trim(LowerCase(s)); +end; + +Function FormatString(S : extended; D : LongInt) : String; +var O : LongInt; +begin + O:= GetOrdinals(S); + if D > 0 then O:= O + 1 + D; + Result:= '%' + IntToStr(O) + '.' + IntToStr(D) + 'f'; + FmtStr(Result, Result, [S]); +end; + +Function StringFormat( S, X : Double; D : SmallInt) : string; +var Total, Whole, dec : LongInt; +begin + if (ABS(S) < 100) and (S <> 0) and (D < 0) then + begin + if S >= 1 then Dec:= 1 - Trunc( log10(ABS(S)) ) + else Dec:= Abs(Order(S)) + 2; + end + else if (ABS(S) < 100) and (S <> 0) and (D >= 0) then + Dec:= D + else Dec:= 0; + + if X > 1 then Whole:= Trunc(log10(abs(X))) + 1 + else Whole:= 1; + + if Dec > 0 then Total:= Whole + Dec + 1 + else Total:= Whole; + + if X < 0 then Inc(Total); + + Result:= '%' + IntToStr(Total) + '.' + IntToStr(Dec) + 'f'; +end; + +Function RealToStr( S : Double) : string; +var StrF : string; + Total, D : LongInt; +begin + Total:= GetOrdinals(S); + D:= GetDecimals(S); + if D > 0 then Total:= Total + 1 + D; + StrF:= '%' + IntToStr(Total) + '.' + IntToStr(D) + 'f'; + + FmtStr(Result, StrF, [S]); +end; + +Function RealToStrSci(S : Double; Prec : LongInt) : string; +var StrF, str : string; + p : LongInt; +begin + StrF:= '%.' + IntToStr(Prec) + 'e'; + FmtStr(Result, StrF, [S]); + p:= pos('E', Result) + 1; + str:= Copy(Result, p, Length(Result) - p + 1); + result:= copy(result, 1, p - 1); + result:= result + IntToStr(StrToInt(str)); +end; + +Function RealToStrDEC( S : Double; D : SmallInt) : string; +var StrF : string; + Total : LongInt; +begin + Total:= GetOrdinals(S); + if D > 0 then + begin + Total:= Total + 1 + D; + StrF:= '%' + IntToStr(Total) + '.' + IntToStr(D) + 'f'; + FmtStr(Result, StrF, [S]); + end + else Result:= IntToStr(Round(S)); +end; + +Function RealToStrSignif(S : Double; Signif : SmallInt) : string; +var O, D : LongInt; +begin + O:= GetOrdinals(S); + if O > Signif then Result:= RealToStrSci(S, Signif) + else if GetDecimals(S) <= Signif then + begin + D:= Signif - O; + Result:= RealToStrDec(S, D); + end + else Result:= RealToStrSci(S, Signif); +end; + +Function Pos2(LS, S : string) : LongInt; +var i : LongInt; +begin + Result:= -1; + for i:= 1 to Length(S) do + begin + if S[i] = LS then Result:= i; + end; +end; + +Function StrToReal( S : string) : Double; +var Code, p : integer; + SO : string; + D : double; +begin + Code:= 0; + try + p:= Pos2(DecimalSeparator, S); + if (p >= 0) and (p < Length(S)) then S[p]:= '.'; + Val(S, D, Code); + Result:= D; + except + SO:= Copy(S, Code, 1); + ShowMessage('Fout in conversie van tekst naar getal (karakter ' + SO + ')'); + Result:= 0; + end; +end; + +Function ValidateRealStr(S : string) : boolean; +var Code, p : integer; + SO : string; + D : double; +begin + Code:= 0; + try + p:= Pos2(DecimalSeparator, S); + if (p >= 0) and (p < Length(S)) then S[p]:= '.'; + Val(S, D, Code); + Result:= TRUE; + except + SO:= Copy(S, Code, 1); + ShowMessage('Fout in conversie van tekst naar getal (karakter ' + SO + ')'); + Result:= false; + end; +end; + +Function Order( R : Double) : SmallInt; +begin + if R = 0 then Result:= 0 + else + begin + if Abs(R) >= 1 then + begin + Result:= Trunc(Log10(Abs(R))); + end + else Result:= Trunc(Log10(Abs(R)))-1; + end; +end; + +{function MyStrToDate(DateStr: String): TDateTime; +var + F: TFormatSettings; + s: String; + i: Integer; + separator: integer; +begin + GetLocaleFormatSettings(0, F); + F.ShortDateFormat := 'd-m-yyyy'; + F.ShortTimeFormat := 'hh:mm:ss'; + F.DateSeparator := '-'; + F.TimeSeparator := ':'; + + separator := Pos(F.DateSeparator, DateStr); + + if separator = 0 then + Raise Exception.Create('No date separator in date ' + DateStr); + + s := Copy(DateStr, 1, separator-1 ); + + i := High(ShortMonthNames); + + while ( i >= Low(ShortMonthNames) ) and not SameText ( s, ShortMonthNames[i] ) do + dec ( i ); + + s := IntToStr(i) + Copy ( DateStr, separator, length(DateStr) ); + if i >= Low(ShortMonthNames) then + result := StrToDateTime ( s, F ) + else + Raise Exception.Create('Could not convert the date ' + DateStr) +end;} + +Function StringToDate(s : string) : TDateTime; +var ns : string; + rf : TReplaceFlags; +const OldPattern : array[0..19] of string = (' ', '/', '\', '.', '. ', 'jan', 'feb', 'mrt', 'mar', 'apr', 'mei', 'may', 'jun', 'jul', 'aug', 'sep', 'okt', 'oct', 'nov', 'dec'); + NewPattern : array[0..19] of string = ('-', '-', '-', '-', '-', '1', '2', '3', '3', '4', '5', '5', '6', '7', '8', '9', '10', '10', '11', '12'); +begin + rf:= [rfReplaceAll, rfIgnoreCase]; + ns:= StringsReplace(s, OldPattern, NewPattern, rf); + + Result:= 0; + + if s <> 'NTB' then + begin + LongTimeFormat := 'hh:mm:ss'; + ShortDateFormat := 'DD-MM-YYYY'; + DateSeparator := '-'; + TimeSeparator := ':'; + try + Result:= StrToDate(ns); + except + Result:= 0; + end; + if Result = 0 then + begin + ShortDateFormat := 'DD-MM-YY'; + try + Result:= StrToDate(ns); + except + Result:= 0; + end; + end; + if Result = 0 then + begin + ShortDateFormat := 'MM-DD-YY'; + try + Result:= StrToDate(ns); + except + Result:= 0; + end; + end; + if Result = 0 then + begin + ShortDateFormat := 'YY-MM-DD'; + try + Result:= StrToDate(ns); + except + Result:= 0; + end; + end; + if Result = 0 then + begin + ShortDateFormat := 'YYYY-MM-DD'; + try + Result:= StrToDate(ns); + except + Result:= 0; + end; + end; + if Result = 0 then + begin + ShortDateFormat := 'D-M-YY'; + try + Result:= StrToDate(ns); + except + Result:= 0; + end; + end; + if Result = 0 then + begin + ShortDateFormat := 'M-D-YYYY'; + try + Result:= StrToDate(ns); + except + Result:= 0; + end; + end; + if Result = 0 then + begin + ShortDateFormat := 'M-D-YY'; + try + Result:= StrToDate(ns); + except + Result:= 0; + end; + end; + if Result = 0 then + begin + ShortDateFormat := 'YY-M-D'; + try + Result:= StrToDate(ns); + except + Result:= 0; + end; + end; + if Result = 0 then + begin + ShortDateFormat := 'YYYY-M-D'; + try + Result:= StrToDate(ns); + except + Result:= 0; + end; + end; + end; +end; + +Function IsValidDate(s : string) : boolean; +begin + Result:= (StringToDate(s) > 0); +end; + +Function StringToTime(s : string) : TDateTime; +begin + LongTimeFormat := 'hh:mm:ss'; + ShortDateFormat := 'DD-MM-YYY'; + DateSeparator := '-'; + TimeSeparator := ':'; + try + Result:= StrToTime(s); + except + Result:= 0; + end; +end; + +Function IsValidTime(s : string) : boolean; +begin + Result:= (StringToTime(s) > 0); +end; + +Function SetDecimalSeparator(Sin : string) : string; +var OldPattern : array[0..0] of string; + NewPattern : array[0..0] of string; + rf : TReplaceFlags; +begin + rf:= [rfReplaceAll, rfIgnoreCase]; + OldPattern[0]:= '.'; + NewPattern[0]:= DefaultFormatSettings.DecimalSeparator; + Result:= StringsReplace(Sin, OldPattern, NewPattern, rf); +end; + +Function SetDecimalPoint(Sin : string) : string; +var OldPattern : array[0..0] of string; + NewPattern : array[0..0] of string; + rf : TReplaceFlags; +begin + rf:= [rfReplaceAll, rfIgnoreCase]; + OldPattern[0]:= DefaultFormatSettings.DecimalSeparator; + NewPattern[0]:= '.'; + Result:= StringsReplace(Sin, OldPattern, NewPattern, rf); +end; + +Function CountSubssInString(s, sub : string) : integer; +var i, lsub : integer; + ssub : string; +begin + Result:= 0; + lsub:= length(sub); + for i:= 0 to Length(s) - lsub + 1 do + begin + ssub:= midstr(s, i, lsub); + if ssub = sub then + Inc(Result); + end; +end; + +Function IsInString(searchString, SubString : string) : boolean; +begin + Result:= false; + Result:= countsubssinstring(lowercase(searchstring), LowerCase(SubString)) > 0; +end; + +Function FloatToStringDec(d : double; Dec: integer) : string; +begin + Result:= RealToStrDec(d, Dec); +end; + +Function FloatToDisplayString(d : double; Dec : integer; u : string) : string; +begin + Result:= RealToStrDec(d, Dec) + ' ' + u; +end; + +Function IntToDisplayString(i : integer; u : string) : string; +begin + Result:= IntToStr(i) + ' ' + u; +end; + +Function SolveQuadratic(a, b, c : double; var X1, X2 : double) : integer; +var D : double; +begin + X1:= 0; X2:= 0; + Result:= 0; + D:= b * b - 4 * a * c; + if D < 0 then Result:= 0 + else if D = 0 then Result:= 1 + else Result:= 2; + if (Result = 1) and (a > 0) then + begin + X1:= -b / (2 * a); + end + else if (Result = 2) and (a <> 0) then + begin + X1:= (-b - SQRT(D)) / (2 * a); + X2:= (-b + SQRT(D)) / (2 * a); + end; +end; + +Function SolveCubic(a, b, c, d : double; var X1, X2, X3 : double) : integer; +var Di, E : double; +begin + Result:= 0; + X1:= 0; X2:= 0; X3:= 0; + Di:= 4 * Power(-b*b + 3*a*c, 3) + + Power(-2 * Power(b, 3) + 9*a*b*c - 27*a*a*d, 2); + if (Di > 0) and (a <> 0) and (E <> 0) then + begin + E:= Power(-2*b*b*b + 9*a*b*c - 27*a*a*d + SQRT(Di), 1/3); + X1:= -b/(3*a) - (Power(2, 1/3) * (-b*b+3*a*c)) / (3 * a * E) + + E / (3 * Power(2, 1/3) * a); + end; +end; + +Procedure QuickSortArray(var Arr : array of double); + procedure QuickSort(var A: array of double; iLo, iHi: Integer); + var Lo, Hi: Integer; + Mid, T : double; + begin + Lo := iLo; + Hi := iHi; + Mid := A[(Lo + Hi) div 2]; + repeat + while A[Lo] < Mid do Inc(Lo); + while A[Hi] > Mid do Dec(Hi); + if Lo <= Hi then + begin + T := A[Lo]; + A[Lo] := A[Hi]; + A[Hi] := T; + Inc(Lo); + Dec(Hi); + end; + until Lo > Hi; + if Hi > iLo then QuickSort(A, iLo, Hi); + if Lo < iHi then QuickSort(A, Lo, iHi); + end; +begin + QuickSort(Arr, Low(Arr), High(Arr)); +end; + +Procedure SelectionSortArray(var List : array of double); +var + i, j, best_j : integer; + best_value : double; +begin + for i := Low(List) to High(List) - 1 do + begin + best_value := List[i]; + best_j := i; + for j := i + 1 to High(List) do + begin + if (List[j] < best_value) Then + begin + best_value := List[j]; + best_j := j; + end; + end; // for j := i + 1 to max do + List[best_j] := List[i]; + List[i] := best_value; + end; // for i := min to max - 1 do +end; + +Procedure ShowNotification(sender : TComponent; s : string); +begin + if FrmNotification = NIL then + begin + FrmNotification:= TFrmNotification.Create(sender); + FrmNotification.ShowFrm(s); + end + else if FrmNotification.Showing then + FrmNotification.AddText(s) + else + begin + FreeAndNIL(FrmNotification); + FrmNotification:= TFrmNotification.Create(sender); + FrmNotification.ShowFrm(s); + end; +end; + +Procedure ShowNotificationModal(sender : TComponent; s : string); +begin + FrmNotification:= TFrmNotification.Create(sender); + FrmNotification.Execute(s); +end; + +Function Question(sender : TComponent; s : string) : boolean; +begin + FrmQuestion:= TFrmQuestion.Create(sender); + Result:= FrmQuestion.Question(s); + FreeAndNil(frmQuestion); +end; + +Function GetAnswer(sender : TComponent; Q : string) : string; +begin + FrmGetString:= TFrmGetString.Create(sender); + Result:= FrmGetString.GetAnswer(Q); + FreeAndNil(FrmGetString); +end; + +Function GetPasswd(sender : TComponent) : string; +begin + FrmGetPasswd:= TFrmGetPasswd.Create(sender); + Result:= FrmGetPasswd.GetAnswer; + FreeAndNil(FrmGetString); +end; + +{Graph related functions} + +Procedure CalcScale(var Min, Max, De : double; var AStr : LongInt); +var Lg, Fr : double; + Ast : LongInt; +Const StrMax = 15; + StrMin = 6; +begin + if Min <> 0 then De:= InvLog(Order(Min)) + else if Max <> 0 then De:= InvLog(Order(Max)); + + if De <> 0 then ASt:= round(Abs(Max - Min)/ De) + else Ast:= StrMin; + While ((Ast < StrMin) or (Ast > StrMax)) and (De <> 0) do + begin + ASt:= round(Abs(Max - Min)/ De); + + Lg:= Log10(De); + if Frac(Lg) = 0 then Lg:= De + else if (Lg < 0) then Lg:= InvLog(Trunc(Lg) - 1) + else Lg:= InvLog(Trunc(Lg)); + Fr:= De / Lg; + if Fr > 5 then Fr:= 1; + if Fr < 1 then Fr:= 5; + if Ast <= 2 then De:= 0.1 * De + else if Ast >= 100 then De:= 10 * De + else if Ast < StrMin then + begin + if (Fr > 0.9) and (Fr < 1.1) then De:= De / 2 + else if (Fr > 4.9) and (Fr < 5.1) then De:= De / 2 + else if (Fr > 2.4) and (Fr < 2.6) then De:= De / 2.5; + end + else if Ast > StrMax then + begin + if (Fr > 0.9) and (Fr < 1.1) then De:= De * 2.5 + else if (Fr > 4.9) and (Fr < 5.1) then De:= De * 2 + else if (Fr > 2.4) and (Fr < 2.6) then De:= De * 2; + end; + end; + if De > 0 then + begin + if Frac(Min / De) <> 0.0 then + begin + if Min > 0 then Min:= Trunc(Min / De) * De + else Min:= (Trunc(Min / De) - 1) * De; + end; + if Frac(Max / De) <> 0.0 then + begin + if Max > 0 then Max:= (Trunc(Max / De) + 1) * De + else Max:= Trunc(Max / De) * De; + end; + AStr:= round(Abs(Max - Min)/ De); + if Min > Max then SwapW(Min, Max); + end; +end; + +Function RoundOrder( R : double) : double; +begin + Result:= Int(R / InvLog(Order(R))) * InvLog(Order(R)); +end; + +Function OrderHigh( R : double) : integer; +begin + if Frac(Log10(R)) = 0 then Result:= Order(R) + else Result:= Order(R) + 1; +end; + +Function RoundOrderHigh( R : double) : double; +begin + Result:= RoundUp(R / InvLog(Order(R))) * InvLog(Order(R)); +end; + +Procedure Scaling(var Min, Max, De : double; var Astr : LongInt); +var SignMin, SignMax : ShortInt; +begin + SignMin:= Sign(Min); SignMax:= Sign(Max); + if ((Min >= 0) and (Max >= 0)) then + begin + If Order(Min) = Order(Max) then + begin + Min:= RoundOrder(Min); Max:= RoundOrderHigh(Max); + end + else + begin + Min:= 0; Max:= RoundOrderHigh(Max); + end; + CalcScale(Min, Max, De, AStr); + end + else if ((Min <= 0) and (Max <= 0)) then + begin + if Order(Min) = Order(Max) then + begin + Min:= RoundOrderHigh(Min); Max:= RoundOrder(Max); + end + else + begin + Min:= RoundOrderHigh(Min); Max:= 0; + end; + CalcScale(Min, Max, De, AStr); + end + else + begin + if Order(Min) = Order(Max) then + begin + Min:= RoundOrderHigh(Min); Max:= RoundOrderHigh(Max); + end + else if Order(Min) > Order(Max) then + begin + Min:= RoundOrderHigh(Min); Max:= -Min; + end + else if Order(Max) > Order(Min) then + begin + Max:= RoundOrderHigh(Max); Min:= -Max; + end; + CalcScale(Min, Max, De, AStr); + end; + + {RelativeRound(Min, Max, De);} + if Sign(Min) <> SignMin then Min:= Abs(Min) * SignMin; + if Sign(Max) <> SignMax then Max:= Abs(Max) * SignMax; + if (Abs(round(Max) - Max) < abs(0.001 * Max)) and (abs(Max) > 1) then + Max:= round(Max); + if (Abs(round(Min) - Min) < abs(0.001 * Min)) and (abs(Min) > 1) then + Min:= round(Min); +end; + +Procedure ScaleDate(var Min, Max, De : TDateTime; var Astr : LongInt); +var //Y1, M1, D1 : longint; + Y2, M2, D2 : word; +{Const StrMax = 15; + StrMin = 6;} +begin +// DecodeDate(Min, Y1, M1, D1); + DecodeDate(Max, Y2, M2, D2); +{ case M2 of + 1, 3, 5, 7, 8, 10, 12 : D2:= 31; + 4, 6, 9, 11 : D2:= 30; + 2 : if Y2 mod 4 = 0 then D2:= 29 else D2:= 28; + end;} + + { Min:= EncodeDate(Y1, M1, 1); + Max:= EncodeDate(Y2, M2, D2);} + AStr:= 6; + De:= (Max - Min) / 6; +end; + +Procedure ScaleFixed(var Min, Max, De : double; var Astr : LongInt); +var Lg, Fr : double; + Ast : LongInt; +Const StrMax = 15; + StrMin = 6; +begin + ASt:= round(Max); + De:= 1; + While ((Ast < StrMin) or (Ast > StrMax)) and (De <> 0) do + begin + ASt:= round((Max) / De); + + Lg:= Log10(De); + if Frac(Lg) = 0 then Lg:= De + else if (Lg < 0) then Lg:= InvLog(Trunc(Lg) - 1) + else Lg:= InvLog(Trunc(Lg)); + Fr:= De / Lg; + if Fr > 5 then Fr:= 1; + if Fr < 1 then Fr:= 5; + if Ast <= 2 then De:= 0.1 * De + else if Ast >= 100 then De:= 10 * De + else if Ast < StrMin then + begin + if (Fr > 0.9) and (Fr < 1.1) then De:= De / 2 + else if (Fr > 4.9) and (Fr < 5.1) then De:= De / 2 + else if (Fr > 2.4) and (Fr < 2.6) then De:= De / 2.5; + end + else if Ast > StrMax then + begin + if (Fr > 0.9) and (Fr < 1.1) then De:= De * 2.5 + else if (Fr > 4.9) and (Fr < 5.1) then De:= De * 2 + else if (Fr > 2.4) and (Fr < 2.6) then De:= De * 2; + end; + end; + if De <> 0 then + begin + if Frac(Min / De) <> 0.0 then + begin + if Min > 0 then Min:= Trunc(Min / De) * De + else Min:= (Trunc(Min / De) - 1) * De; + end; + if Frac(Max / De) <> 0.0 then + begin + if Max > 0 then Max:= (Trunc(Max / De) + 1) * De + else Max:= Trunc(Max / De) * De; + end; + AStr:= round((Max) / De); + end; +end; + +Function DrawTxt( Canvas : TCanvas; MiddleHeight, Left, Right : LongInt; + Text : string; Alignment : TAlignment; + MoreLines : boolean) : integer; +var BoxWidth, X, AmountLines, counter, MH, Pos : LongInt; + Rec : TRect; + s : string; +begin + Rec.Right:= Right; Rec.Left:= Left; Result:= 0; + X:= 0; AmountLines:= 0; + with Canvas do + begin + BoxWidth:= Rec.Right - Rec.Left; + if MoreLines then + begin + Pos:= CalcMaxWidth(Canvas, Text); + BoxWidth:= MaxI(BoxWidth, Pos); + AmountLines:= CalcAmountLines(Canvas, Text, BoxWidth); + Result:= AmountLines * TextHeight(Text); + end + else Result:= TextHeight(Text); + Rec.Left:= Left; + Rec.Right:= Right; + Pos:= 1; + if MoreLines then + begin + for counter:= 1 to AmountLines do + begin + s:= GiveNextLine(Canvas, Text, BoxWidth, Pos); + MH:= MiddleHeight + round(-0.5 * Result + (counter - 0.5) * TextHeight(Text)); + Rec.Top:= MH - round(0.5 * TextHeight(Text)); + Rec.Bottom:= Rec.Top + TextHeight(Text); + + if Alignment = taLeftJustify then X:= Rec.Left + else if Alignment = taRightJustify then X:= MaxI(Rec.Right - TextWidth(s), 0) + else if Alignment = taCenter then X:= Rec.Left + round(0.5 * (BoxWidth - TextWidth(s))); + TextRect(Rec, X, Rec.Top, s); + end; + end + else + begin + Rec.Top:= MiddleHeight - round(0.5 * TextHeight(Text)); + Rec.Bottom:= Rec.Top + TextHeight(Text); + if Alignment = taLeftJustify then X:= Rec.Left + else if Alignment = taRightJustify then X:= MaxI(Rec.Right - TextWidth(Text), 0) + else if Alignment = taCenter then X:= MaxI(Rec.Left + round(0.5 * (BoxWidth - TextWidth(Text))), 0); + TextRect(Rec, X, Rec.Top, Text); + end; + end; + Result:= Rec.Bottom; +end; + +Procedure DrawTxtVarRct(canvas : TCanvas; Text : string; var R : TRect); +var TW : integer; +begin + TW:= canvas.TextWidth(Text); + R.Right:= R.Left + TW; + TW:= canvas.TextHeight(Text); + R.Bottom:= R.Top + TW; +end; + +Function DrawTxtRct( Canvas : TCanvas; R : TRect; + Text : string; Alignment : TAlignment; + MoreLines : boolean) : integer; +var BoxWidth, X, AmountLines, counter, TH, Pos : LongInt; + s : string; +begin + Result:= 0; + X:= 0; AmountLines:= 0; + with Canvas do + begin + BoxWidth:= R.Right - R.Left; + if MoreLines then + begin + Pos:= CalcMaxWidth(Canvas, Text); + BoxWidth:= MaxI(BoxWidth, Pos); + AmountLines:= CalcAmountLines(Canvas, Text, BoxWidth); + Result:= AmountLines * TextHeight(Text); + end + else Result:= TextHeight(Text); + TH:= TextHeight(Text); + Pos:= 1; + if MoreLines then + begin + for counter:= 1 to AmountLines do + begin + s:= GiveNextLine(Canvas, Text, BoxWidth, Pos); + if Alignment = taLeftJustify then X:= R.Left + else if Alignment = taRightJustify then X:= MaxI(R.Right - TextWidth(s), 0) + else if Alignment = taCenter then X:= R.Left + round(0.5 * (BoxWidth - TextWidth(s))); + TextRect(R, X, R.Top + (counter - 1) * TH , s); + end; + end + else + begin + if Alignment = taLeftJustify then X:= R.Left + else if Alignment = taRightJustify then X:= MaxI(R.Right - TextWidth(Text), 0) + else if Alignment = taCenter then X:= MaxI(R.Left + round(0.5 * (BoxWidth - TextWidth(Text))), 0); + TextRect(R, X, R.Top, Text); + end; + end; + Result:= R.Bottom; +end; + +Function RotateText(Canvas : TCanvas; Xt, Yl, Deg : LongInt; Txt : string; + BackColor : tColor; Transparant : boolean) : boolean; +var Bitmap : TBitmap; + Rec: TRect; + P1, P5, P6 : TPoint; + X, Y, W, H : LongInt; + Angle, Si, Co : double; +begin + Result:= false; + Rec:= Rect(0, 0, Canvas.TextWidth(Txt), Canvas.TextHeight(Txt)); + Bitmap:= TBitmap.Create; + Bitmap.PixelFormat:= pfDevice; + with Bitmap.Canvas do + begin + Font.Assign(Canvas.Font); + Pen.Assign(Canvas.Pen); + Brush.Assign(Canvas.Brush); + end; + Bitmap.Width:= Rec.Right - Rec.Left; + Bitmap.Height:= Rec.Bottom - Rec.Top; + Bitmap.Canvas.Rectangle(0, 0, Bitmap.Width, Bitmap.Height); + Bitmap.Canvas.TextRect(Rec, 1, 1, Txt); + Angle:= Deg/180*PI; + Si:= Sin(Angle); Co:= Cos(Angle); + W:= Rec.Right - Rec.Left; + H:= Rec.Bottom - Rec.Top; + P1.X:= Xt - round(0.5 * W * Co + 0.5 * H * Si); + P1.Y:= Yl - round(-0.5 * W * Si + 0.5 * H * Co); + if P1.X < 0 then P1.X:= 0; + if P1.Y < 0 then P1.Y:= 0; + + for Y:= 0 to Bitmap.Height - 2 do + begin + X:= 0; + P5.X:= P1.X + round(Y * Si); P5.Y:= P1.Y + round(Y * Co); + for X:= 0 to Bitmap.Width - 1 do + begin + P6.X:= P5.X + round(X * Co); P6.Y:= P5.Y - round(X * Si); + + if TransParant and ((Canvas.Pixels[P6.X, P6.Y] = BackColor) or (Canvas.Pixels[P6.X, P6.Y] = Canvas.Brush.Color)) then + Canvas.Pixels[P6.X, P6.Y]:= Bitmap.Canvas.Pixels[X, Y] + else if not Transparant then + Canvas.Pixels[P6.X, P6.Y]:= Bitmap.Canvas.Pixels[X, Y]; + end; + end; + Result:= TRUE; +end; + +Function GiveNextLine( Canvas : TCanvas; Text : string; + Width : LongInt; var Pos : LongInt) : string; +var LineTst, Wrd : string; + PosOld : longint; +begin + Result:= ''; LineTst:= ''; PosOld:= Pos; + repeat + Wrd:= NextWord(Text, Pos); + LineTst:= LineTst + Wrd; + if Canvas.TextWidth(LineTst) <= Width then + begin + if Pos <= Length(Text) then LineTst:= LineTst + ' '; + Result:= LineTst; + PosOld:= Pos; + end; + until ((PosOld <> Pos) or (Canvas.TextWidth(Result) >= width) or (Pos > Length(Text))); + Pos:= PosOld; +end; + +Function NextWord( Line : string; var Pos : LongInt) : string; +var Ch : string[1]; +begin + Result:= ''; + repeat + Ch:= Copy(Line, Pos, 1); + if (Ch <> ' ') then Result:= Result + Ch; + Inc(Pos); + until (Ch = ' ') or (Pos > Length(Line)); +end; + +Function RemInvChars(S : string) : string; +var i : integer; + C : char; + invCh : char; +begin + Result:= ''; + invch:= Char(0); + i:= 1; + Repeat + C:= S[i]; + if C <> invch then Result:= Result + S[i]; + inc(i); + until ((C = invch) or (i > Length(S))); +end; + +Function CalcTextHeight( FontSize, PPIY : integer) : integer; +begin + {Room for caption : } + Result:= round(FontSize * PPIY / 72); +end; + +Function CalcAmountLines( Canvas : TCanvas; Text : string; Width : LongInt) : LongInt; +var Pos : LongInt; + Line, LineTst, Wrd : string; +begin + Result:= 0; Pos:= 1; Wrd:= ''; + repeat + Line:= Wrd; LineTst:= Wrd; + repeat + Wrd:= NextWord(Text, Pos); + LineTst:= LineTst + ' ' + Wrd; + if Canvas.TextWidth(LineTst) <= Width then Line:= LineTst; + until (Canvas.TextWidth(LineTst) >= Width) or (Pos >= Length(Text)); + Inc(Result); + until Pos >= length(Text); + if LineTst <> Line then Inc(Result); +end; + +Function CalcAmountLines2(Font : TFont; Text : string; Width : LongInt) : LongInt; +var Pos : LongInt; + Line, LineTst, Wrd : string; + bmp : TBitmap; +begin + Result:= 0; + if Width > 0 then + begin + bmp:= TBitmap.Create; + bmp.Canvas.Font.Assign(Font); + Result:= 0; Pos:= 1; Wrd:= ''; + repeat + Line:= Wrd; LineTst:= Wrd; + repeat + Wrd:= NextWord(Text, Pos); + LineTst:= LineTst + ' ' + Wrd; + if bmp.Canvas.TextWidth(LineTst) <= Width then Line:= LineTst; + until (bmp.Canvas.TextWidth(LineTst) >= Width) or (Pos >= Length(Text)); + Inc(Result); + until Pos >= length(Text); + if LineTst <> Line then Inc(Result); + if Result > 1 then + bmp.Free + else + bmp.Free; + end; +end; + +Function CalcMaxWidth( Canvas : TCanvas; Text : string) : LongInt; +var Wrd : string; + Pos : LongInt; +begin + Result:= 0; + Pos:= 1; + while Pos <= Length(Text) do + begin + Wrd:= NextWord(Text, Pos); + if Canvas.TextWidth(Wrd) > Result then Result:= Canvas.TextWidth(Wrd); + end; +end; + +{============================= Brewing functions ==============================} + +Function CalcFrac(TpH, pK1, pK2, pK3 : double) : double; +var r1d, r2d, r3d, dd, f1d, f2d, f3d, f4d : double; +begin + r1d:= Power(10, TpH - pK1); + r2d:= Power(10, TpH - pK2); + r3d:= Power(10, TpH - pK3); + dd:= 1/(1 + r1d + r1d*r2d + r1d*r2d*r3d); + f1d:= dd; + f2d:= r1d*dd; + f3d:= r1d*r2d*dd; + f4d:= r1d*r2d*r3d*dd; + Result:= f2d + 2*f3d + 3*f4d; +end; + +Function SRMtoEBC(d : double) : double; +begin + Result:= 1.76506E-10 * Power(d, 4) + 1.54529E-07 * Power(d, 3) - 1.59428E-04 * SQR(d) + + 2.68837E+00 * d - 1.60040E+00; + If Result < 0 Then + Result:= 0; +end; + +Function EBCtoSRM(d : Double) : Double; +begin + Result:= -1.32303E-12 * Power(d, 4) - 0.00000000291515 * Power(d, 3) + + 0.00000818515 * SQR(d) + 0.372038 * d + 0.596351; +end; + +Function EBCtoColor(EBC : double) : TColor; +var SRM : Double; +begin + SRM:= EBCtoSRM(EBC); + Result:= SRMtoColor(SRM); +end; + +Function SRMtoColor(SRM : double) : TColor; +var i : integer; + R, G, B : longint; + Found : boolean; +begin + R:= 0; G:= 0; B:= 0; + Found:= false; + i:= 0; + while (not found) and (i <= 299) do + begin + if SRM <= SRMtoRGB[i, 0] then + begin + R:= Round(SRMtoRGB[i, 1]); + G:= Round(SRMtoRGB[i, 2]); + B:= Round(SRMtoRGB[i, 3]); + Found:= TRUE; + end; + Inc(i); + end; + Result:= RGBtoColor(R, G, B); +end; + +Function SGtoPlato(SG : Double) : Double; +begin +// Result:= -0.0000013437885 * Power(SG*1000, 3) + 0.004067348 * SQR(SG*1000) - 3.8532613 * SG*1000 + 1129.6644; + if SG > 0.5 then + Result:= 259 - 259 / SG + else Result:= 0; +end; + +Function PlatoToSG(plato : Double) : Double; +begin +// Result:= 0.0000006077377 * Power(plato, 3) - 0.00001025564 * SQR(plato) + 0.0040681865 * plato + 1; + Result:= 1.000; + if Plato < 259 then Result:= 259 / (259 - plato); +end; + +Function SGtoBrix(SG : Double) : Double; +begin + Result:= SGtoPlato(SG) * Settings.BrixCorrection.Value; +end; + +Function BrixToSG(Brix : Double) : Double; +begin + Result:= 1.000; + if Settings.BrixCorrection.Value > 0 then + Result:= PlatoToSG(Brix / Settings.BrixCorrection.Value); +end; + +Function BrixToFG(OBrix, FBrix : double) : double; +begin + Result:= 1.0031 - 0.002318474 * OBrix - 0.000007775 * (OBrix * OBrix) + - 0.000000034 * Power(OBrix, 3) + 0.00574 * (FBrix) + + 0.00003344 * (FBrix * FBrix) + 0.000000086 * Power(FBrix, 3); +end; + +Function PlatoToExtract(P : Double) : Double; +begin + Result:= 0.0061289 + 0.99464 * P + 0.0042888 * SQR(P); //kg/hl + Result:= 10 * Result; //g/l + If Result < 0 Then Result:= 0; +end; + +Function SGtoExtract(SG : Double) : Double; +begin + Result:= 10 * (-676.67 * SG + 1286.4 * SQR(SG) - 800.47 * Power(SG, 3) + 190.74 * Power(SG, 4)); +end; + +Function ExtractToSG(E : Double) : Double; +begin + Result:= -1.5703394E-14 * Power(E, 4) + 9.2822793E-012 * Power(E, 3) - 0.000000017126328 * Power(E, 2) + 0.00038807583 * E + 1; +end; + +Function BrixToRI(Brix : Double) : Double; +begin + Result:= 1.33302 + 0.001427193 * Brix + 0.000005791157 * SQR(Brix); +end; + +Function FtoC(f : double) : double; +begin + Result:= (f - 32) / 1.8; +end; + +Function CtoF(c : double) : double; +begin + Result:= 1.8 * c + 32 ; +end; + +Function RE(SG : Double; Brix : Double) : Double; +var RI : Double; +begin + RI:= BrixToRI(Brix); + Result:= 194.5935 + 129800 * SG + RI * (410.8815 * RI - 790.8732); +end; + +Function AlcByVol(SG : Double; Brix : Double) : Double; +begin; + Result:= (277.8851 - 277.4 * SG + 0.9956 * Brix + 0.00523 * SQR(Brix) + 0.000015 * Power(Brix, 3)) * (SG / 0.79); +end; + +Function ABVol(OG : Double; FG : Double) : Double; +begin + Result:= 0; + if (4.749804 - FG) <> 0 then + Result:= 486.8693 * (OG - FG) / (4.749804 - FG); +end; + +Function ABW(ABVol : Double; FG : Double) : Double; +begin + Result:= 0; + if FG > 0 then + Result:= ABVol * 794 / (1000 * FG); +end; + +Function ABW2(FG : Double; Brix : Double) : Double; +var RI : Double; +begin + RI:= BrixToRI(Brix); + Result:= 1017.5596 - (0.2774 * FG) + RI * ((937.8135 * RI) - 1805.1228); +end; + +Function SGFerm(OBrix : Double; FBrix : Double) : Double; +begin + Result:= ((1.001843 - 0.002318474 * OBrix - 0.000007775 * SQR(OBrix) - 0.000000034 * Power(OBrix, 3) + 0.00574 * (FBrix) + 0.00003344 * SQR(FBrix) + + 0.000000086 * Power(FBrix, 3)) + (1.313454) * 0.001) * 1000; +end; + +Function RealExtract(FG : Double; Brix : Double) : Double; +var RI : Double; +begin + RI:= BrixToRI(Brix); + Result:= 129.8 * FG + 194.5935 + RI * (410.882 * RI - 790.8732); +end; + +Function Waterdensity(T : Double) : Double; +begin + Result:= 1; + if (1 + 0.01687985 * T) <> 0 then + Result:= (999.83952 + 16.945176 * T - 0.0079870401 * SQR(T) - 0.000046170461 * Power(T, 3) + 0.00000010556302 * Power(T, 4) - 2.8054253E-10 * Power(T, 5)) / (1 + 0.01687985 * T); +end; + +Function pHRoom(pHmash, Tm : double) : double; +begin + Result:= pHmash + 0.0055 * (Tm - 20); +end; + +Function pHMash(pHroom, Tm : double) : double; +begin + Result:= pHRoom - 0.0055 * (Tm - 20); +end; + +Function DwatT(T : double; Tref : Double) : Double; +begin + Result:= Waterdensity(T) / Waterdensity(Tref); +end; + +Function FreezingPoint(SG : Double; FG : Double) : Double; +var SGP : Double; + AlBV : Double; + AlBW : Double; +begin + AlBV:= ABVol(SG, FG); + AlBW:= ABW(AlBV, FG); + SGP:= SGtoPlato(SG); + Result:= -0.42 * AlBW + 0.04 * SGP + 0.2; +end; + +Function StarterSize(types : Integer; soort : Double; V : Double; SG : Double; + start : Double) : double; + +{ types: 0 = simpel, 1 = belucht, 2 = geroerd + soort: 0 = bovengist, 1 = ondergist + V: volume te vergisten wort in liters + SG: startSG te vergisten wort in grammen per l of kilogrammen per liter + start: aantal gistcellen bij aanvang starter in miljard gistcellen + StarterSize: benodigde grootte giststarter in liters} + +var plato : Double; + a : Double; + b : Double; + f : Double; + acellen : Double; +begin + plato:= SGtoPlato(SG); + If soort = 0 Then + f:= 0.75 + Else f:= 1.5; + + acellen:= f * plato * V; //benodigd aantal cellen in miljard cellen + + if types = 0 Then + begin + a:= 0.8473; + b:= 85.577; + end + else If types = 1 Then + begin + a:= 1.02; + b:= 115; + end + else + begin + a:= 1.06302; + b:= 134.78259; + end; + + a:= a * start + b; + b:= 0.434; + + b:= 1 / b; +{ a:= Power((1 / a), b);} + + If acellen <= start Then + Result:= 0 + Else if a <> 0 then + Result:= Power(acellen/a, b); +end; + +Function StarterSize2(types : Integer; Needed : double; start : Double) : double; +{ types: 0 = simpel, 1 = belucht, 2 = geroerd + Needed: aantal te kweken cellen in miljard + start: aantal gistcellen bij aanvang starter in miljard gistcellen + StarterSize: benodigde grootte giststarter in liters} + +var a : Double; + b : Double; +begin + if types = 0 Then + begin + a:= 0.8473; + b:= 85.577; + end + else If types = 1 Then + begin + a:= 1.02; + b:= 115; + end + else + begin + a:= 1.06302; + b:= 134.78259; + end; + + a:= a * start + b; + b:= 0.434; + + b:= 1 / b; +{ a:= Power((1 / a), b);} + + If needed <= start Then + Result:= 0 + Else if a <> 0 then + Result:= Power(needed / a, b); +end; + +Function GrowthFactor(types : Integer; V : Double; start : Double) : double; +{ types: 0 = simpel, 1 = belucht, 2 = geroerd + V: volume van de giststarter, in liters + start: aantal gistcellen bij aanvang starter, in miljard gistcellen + Result: groeifactor} + +var a : Double; + b : Double; +begin + If types = 0 Then + begin + a:= 0.8473; + b:= 85.577; + end + Else If types = 1 Then + begin + a:= 1.02; + b:= 115; + end + Else + begin + a:= 1.06302; + b:= 134.78259; + End; + + a:= a * start + b; + b:= 0.434; + + Result:= a * Power(V, b); + if (start > 0) then + Result:= Result / start; + if Result > 6.1 then Result:= 6.1; +end; + +Function AmountCells(types : Integer; V : Double; start : Double) : double; + +{ types: 0 = simpel, 1 = belucht, 2 = geroerd + V: volume van de giststarter, in liters + start: aantal gistcellen bij aanvang starter, in miljard gistcellen + Result: aantal cellen na kweken, in miljard gistcellen} + +var a : Double; + b : Double; +begin + If types = 0 Then + begin + a:= 0.8473; + b:= 85.577; + end + Else If types = 1 Then + begin + a:= 1.02; + b:= 115; + end + Else + begin + a:= 1.06302; + b:= 134.78259; + End; + + a:= a * start + b; + b:= 0.434; + + Result:= a * Power(V, b); + if (start > 0) and (Result / start > 6.1) then Result:= 6.1 * start; +end; + +Function UkRager(kt : Double) : Double; +begin + If kt = -2 Then + Result:= 25 + Else If kt = -1 Then + Result:= 0 + Else If (kt >= 0) And (kt <= 5) Then + Result:= 5 + Else If kt <= 10 Then + Result:= 6 + Else If kt <= 15 Then + Result:= 8 + Else If kt <= 20 Then + Result:= 10.1 + Else If kt <= 25 Then + Result:= 12.1 + Else If kt <= 30 Then + Result:= 15.3 + Else If kt <= 35 Then + Result:= 18.8 + Else If kt <= 40 Then + Result:= 22.8 + Else If kt <= 45 Then + Result:= 26.9 + Else If kt <= 50 Then + Result:= 28.1 + Else If kt > 50 Then + Result:= 30 + Else + Result:= 0; +end; + +Function UkGaretz(kt : Double) : Double; +begin + If kt = -2 Then + Result:= 20 + Else If kt = -1 Then + Result:= 0 + Else If (kt >= 0) And (kt <= 10) Then + Result:= 0 + Else If kt <= 15 Then + Result:= 2 + Else If kt <= 20 Then + Result:= 5 + Else If kt <= 25 Then + Result:= 8 + Else If kt <= 30 Then + Result:= 11 + Else If kt <= 35 Then + Result:= 14 + Else If kt <= 40 Then + Result:= 16 + Else If kt <= 45 Then + Result:= 18 + Else If kt <= 50 Then + Result:= 19 + Else If kt <= 60 Then + Result:= 20 + Else If kt <= 70 Then + Result:= 21 + Else If kt <= 80 Then + Result:= 22 + Else If kt > 80 Then + Result:= 23 + Else + Result:= 0; +end; + +Function UkNoonan(kt : Double) : Double; +begin + If kt = -2 Then + Result:= 25 + Else If kt = -1 Then + Result:= 0 + Else If (kt >= 0) And (kt <= 5) Then + Result:= 5 + Else If kt <= 15 Then + Result:= 0.3 * kt + 3.5 + Else If kt <= 60 Then + Result:= 0.44444 * kt + 1 + 1 / 3 + Else If kt <= 90 Then + Result:= 0.1 * kt + 22 + Else If kt > 90 Then + Result:= 31 + Else + Result:= 0; +end; + +Function UkDaniels(kt : Double) : Double; +begin + If kt = -2 Then + Result:= 23 + Else If kt = -1 Then + Result:= 0 + Else If (kt >= 0) And (kt <= 7.5) Then + Result:= 5 + Else If kt <= 17.5 Then + Result:= 12 + Else If kt <= 27.5 Then + Result:= 15 + Else If kt <= 42.5 Then + Result:= 19 + Else If kt <= 57.5 Then + Result:= 22 + Else If kt <= 72.5 Then + Result:= 24 + Else If kt <= 90 Then + Result:= 27 + Else If kt > 90 Then + Result:= 27 + Else + Result:= 0; +end; + +Function CalcIbuU(Method : TIBUmethod; SG : Double; Tboil : Double; HopVorm : THopForm; + HopUse : THopUse; BNAP : Double) : double; +var Ubt : Double; + Fbg : Double; + Fhf : Double; + Fhu : double; + Fbp : Double; + Fst : Double; + Fhb : Double; + Fyf : Double; + Ffil : Double; +begin + Ubt:= 25; + Fbg:= 1; + Fhf:= 1; + Fhu:= 1; + Fbp:= 1; + Fst:= 1; + Fhb:= 1; + Fyf:= 1; + Ffil:= 1; + + Case Method of + imRager: + begin + Ubt:= UkRager(Tboil); + If SG > 1.050 Then Fbg:= 1 / (1 + 5 * (SG - 1.050)); + Case HopVorm of + hfLeaf: + Fhf:= 1; + hfPlug: + Fhf:= 1 + Settings.PlugFactor.Value / 100; + hfPellet: + Fhf:= 1 + Settings.PelletFactor.Value / 100; + End; + end; + imGaretz: + begin + Ubt:= UkGaretz(Tboil); + If SG > 1.050 Then Fbg:= 1 / (1 + 5 * (SG - 1.050)); + Case HopVorm of + hfLeaf: + Fhf:= 1; + hfPlug: + Fhf:= 1 + Settings.PlugFactor.Value / 100; + hfPellet: + If (Tboil >= 10) And (Tboil <= 30) Then + Fhf:= 1 + Settings.PelletFactor.Value / 100; + Else + Fhf:= 1; + End; + end; + imMosher: + begin + If Tboil = -1 Then + Ubt:= 0 + Else If Tboil = -2 Then + Ubt:= 21.23082 * (1 - Exp(-0.028784 * 60)) + Else + Ubt:= 21.23082 * (1 - Exp(-0.028784 * Tboil)); + + Fbg:= 1.0526 * (SG - 40 * SQR(SG - 1)); + Case HopVorm of + hfLeaf: + Fhf:= 1; + hfPlug: + Fhf:= 1 + Settings.PlugFactor.Value / 100; + hfPellet: + Fhf:= 1 + Settings.PelletFactor.Value / 100; + End; + end; + imTinseth: + begin + If Tboil = -1 Then + Ubt:= 0 + Else If Tboil = -2 Then + Ubt:= 25.367715 * (1 - Exp(-0.04 * 60)) + Else + Ubt:= 25.367715 * (1 - Exp(-0.04 * Tboil)); + Fbg:= 1.5673 * Power(0.000125, (SG - 1)); + Case HopVorm of + hfPlug: + Fhf:= 1 + Settings.PlugFactor.Value / 100; + hfPellet: + Fhf:= 1 + Settings.PelletFactor.Value / 100; + End; + end; + imNoonan: + begin + Ubt:= UkNoonan(Tboil); + If SG > 1.050 Then + Fbg:= 1 / (1 + 5 * (SG - 1.050)); + Case HopVorm of + hfLeaf: + Fhf:= 1; + hfPlug: + Fhf:= 1 + Settings.PlugFactor.Value / 100; + hfPellet: + Fhf:= 1 + Settings.PelletFactor.Value / 100; + End; + end; + imDaniels: + begin + Ubt:= UkDaniels(Tboil); + If SG > 1.050 Then + Fbg:= 1 / (1 + 5 * (SG - 1.050)); + Case HopVorm of + hfLeaf: + Fhf:= 1; + hfPlug: + Fhf:= 1 + Settings.PlugFactor.Value / 100; + hfPellet: + Fhf:= 1 + Settings.PelletFactor.Value / 100; + End; + end; + end; + + case HopUse of + huBoil: Fhu:= 1.0; + huAroma: Fhu:= 1.0; //vlamuit + huDryhop: Fhu:= 0.0; + huMash: Fhu:= 1 + Settings.MashHopFactor.Value / 100; + huFirstWort: FHu:= 1 + Settings.FWHFactor.Value / 100; + end; + + Fbp:= 1 / (1 + (BNAP / 0.3048) / 27500); + + Result:= (Ubt * Fbg * Fhf * Fhu * Fbp * Fst * Fhb * Fyf * Ffil) / 100; +end; + +Function CalcIBU(Method : TIBUmethod; HopUse : THopUse; AA : Double; AM : Double; Vw : Double; + Vf : Double; SG : Double; Tboil : Double; HopVorm : THopForm; + BNAP : Double) : Double; +var IBUi : Double; + U : Double; + a : Double; + b : Double; + c : Double; +begin + U:= 1; + if Vf > 0 then IBUi:= 10 * AM * AA / Vf + else IBUi:= 0; + + U:= CalcIBUU(Method, SG, Tboil, HopVorm, HopUse, BNAP); + + { If (Method = imGaretz) Or (Method = imDaniels) Then + begin + a:= Vf / (260 * Vw); + b:= 1; + c:= -IBUi * U; + + Result:= (-b + Sqrt(SQR(b) - 4 * a * c)) / (2 * a); + end + Else } + Result:= IBUi * U; +end; + +Function AmHop(Method : TIBUmethod; HopUse : THopUse; AA : Double; IBU : Double; Vw : double; Vf : Double; SG : Double; + Tboil : Double; HopVorm : THopForm; BNAP : Double) : Double; +var U : Double; +begin + Result:= 0; + U:= CalcIBUU(Method, SG, Tboil, HopVorm, HopUse, BNAP); + + if (U > 0) and (AA > 0) then + Result:= (Vf * IBU) / (10 * AA * U) +end; + +Function IonBalance(Ca, Mg, Na, Cl, SO4, HCO3 : double) : double; +var MCa, MMg, MNa, MCl, MSO4, MHCO3 : double; +begin + MCa:= Ca / MMCa; + MMg:= Mg / MMMg; + MNa:= Na / MMNa; + MCl:= Cl / MMCl; + MSO4:= SO4 / MMSO4; + MHCO3:= HCO3 / MMHCO3; + + Result:= 2 * MCa + 2 * MMg + MNa - MCl - 2 * MSO4 - MHCO3; +end; + +Function CarbStoCO2(S : double; T : double; SFactor : double) : double; +begin + Result:= 0; + if SFactor > 0 then + Result:= 0.286 * S / SFactor + 0.000849151 * T * T - 0.0587512 * T + 1.71137; +end; + +Function CarbCO2toS(CO2 : double; T : double; SFactor : double) : double; +begin + Result:= SFactor * (CO2 - (0.000849151 * T * T - 0.0587512 * T + 1.71137)) / 0.286; +end; + +Function CarbCO2toPressure(CO2 : double; T : double) : double; +begin + Result:= (CO2 - (-0.000005594056 * Power(T, 4) + 0.000144357886 * Power(T, 3) + + 0.000362999168 * T * T - 0.064872987645 * T + 1.641145175049)) + / (0.00000498031 * Power(T, 4) - 0.00024358267 * Power(T, 3) + + 0.00385867329 * T * T - 0.05671206825 * T + 1.53801423376); +end; + +Function CarbPressuretoCO2(P : double; T : double) : double; +begin + Result:= P * (0.00000498031 * Power(T, 4) - 0.00024358267 * Power(T, 3) + + 0.00385867329 * T * T - 0.05671206825 * T + 1.53801423376) + + (-0.000005594056 * Power(T, 4) + 0.000144357886 * Power(T, 3) + + 0.000362999168 * T * T - 0.064872987645 * T + 1.641145175049); +end; + +Function ActualIBU(origibu, HSI, Temp : double; Elapsed, storagetype : longint) : double; +var iTemp, iType, e : double; +begin + iTemp:= 0.396865 * EXP(0.046221 * Temp); + case storagetype of + 0: iType:= 1; + 1: iType:= 0.75; + else iType:= 0.5; + end; + e:= 2 * (Elapsed / 365.25) * iTemp * iType; //years + Result:= origibu * Power(1 - HSI/100, e); +end; + +Function ZipFiles(l : TStringList; zipfn : string) : boolean; +var i : integer; + Zipper: TZipper; +begin + Result:= false; + if (l <> NIL) and (l.Count > 0) then + begin + Zipper := TZipper.Create; + try + Zipper.FileName := zipfn; + for I := 1 to l.Count - 1 do + Zipper.Entries.AddFileEntry(l.Strings[i], zipfn); + Zipper.ZipAllFiles; + Result:= TRUE; + finally + Zipper.Free; + end; + end; +end; + +Function UnZipFiles(zipfn, outpath : string) : boolean; +var i : integer; + Zipper: TUnZipper; +begin + Result:= false; + Zipper := TUnZipper.Create; + try + Zipper.FileName := zipfn; + Zipper.OutputPath := outpath; + Zipper.Examine; + Zipper.UnZipAllFiles; + Result:= TRUE; + finally + Zipper.Free; + end; +end; + +{Procedure SetFontHeight(F : TForm; fs : integer); +var i : integer; +begin + if F <> NIL then + begin + F.Font.Height:= fs; + for i:= 0 to F.ControlCount - 1 do + begin + F.Controls[i].Font.Height:= fs; + F.Repaint; + end; + end; +end;} + +Procedure PlayStartProg; +var sound : TProcess; +begin +// {$ifdef linux} +// AlSourcePlay(source[startprog]); +// {$endif} + {$ifdef darwin} + sound:= TProcess.Create(NIL); + sound.CommandLine:= 'afplay ' + StartSound; + sound.Execute; + sound.Free; + {$endif} + {$ifdef windows} + Application.ProcessMessages; + sndPlaySound(PChar(StartSound), snd_Async or snd_NoDefault);//snd_Async or snd_NoDefault); + Application.ProcessMessages; + {$endif} +end; + +Procedure PlayWarning; +var sound : TProcess; +begin +// {$ifdef linux} +// AlSourcePlay(source[warning]); +// {$endif} + {$ifdef darwin} + sound:= TProcess.Create(NIL); + sound.CommandLine:= 'afplay ' + WarningSound; + sound.Execute; + sound.Free; + {$endif} + {$ifdef windows} + Application.ProcessMessages; + sndPlaySound(PChar(WarningSound), snd_Async or snd_NoDefault);//snd_Async or snd_NoDefault); + Application.ProcessMessages; + {$endif} +end; + +Procedure PlayAlarm; +var sound : TProcess; +begin +// {$ifdef linux} +// AlSourcePlay(source[alarm]); +// {$endif} + {$ifdef darwin} + sound:= TProcess.Create(NIL); + sound.CommandLine:= 'afplay ' + AlarmSound; + sound.Execute; + sound.Free; + {$endif} + {$ifdef windows} + Application.ProcessMessages; + sndPlaySound(PChar(AlarmSound), snd_Async or snd_NoDefault);//snd_Async or snd_NoDefault); + Application.ProcessMessages; + {$endif} +end; + +Procedure PlayEndProg; +var sound : TProcess; +begin +// {$ifdef linux} +// AlSourcePlay(source[endprog]); +// {$endif} + {$ifdef darwin} + sound:= TProcess.Create(NIL); + sound.CommandLine:= 'afplay ' + StartSound; + sound.Execute; + sound.Free; + {$endif} + {$ifdef windows} + Application.ProcessMessages; + sndPlaySound(PChar(EndSound), snd_Async or snd_NoDefault);//snd_Async or snd_NoDefault); + Application.ProcessMessages; + {$endif} +end; + +Procedure Log(s : string); +const fn = 'brewbuddy.log'; +var fnp : string; +begin + if (slLog <> NIL) and DoLog then + begin + slLog.Add(s); + try + fnp:= Settings.DataLocation.Value + fn; + slLog.SaveToFile(fnp); + except + ShowMessage('Fout bij schrijven van logbestand'); + end; + end; +end; + +Initialization + MaxGrowthFactor:= 6.1; + + AmCellspGramDry:= 15000000000; //8695652173; //20000000000 according to MrMalty + AmCellspPack:= 100000000000; + AmCellspMlSlurry:= 1700000000; + + SpecificHeats[0].Material:= 'Aluminium'; + SpecificHeats[0].SpecificHeat:= 0.22; //cal/g.°C + SpecificHeats[1].Material:= 'Koper'; + SpecificHeats[1].SpecificHeat:= 0.092; //cal/g.°C + SpecificHeats[2].Material:= 'Kunststof'; + SpecificHeats[2].SpecificHeat:= 0.46; //cal/g.°C + SpecificHeats[3].Material:= 'RVS'; + SpecificHeats[3].SpecificHeat:= 0.11; //cal/g.°C + + EndChar:= ['a', 'e', 'i', 'o', 'u', 's']; + + if not DirectoryExists(Settings.DataLocation.Value) then + if not CreateDir(Settings.DataLocation.Value) then ShowMessage('Data folder could not be created.'); + + FermentableColor:= RGBtoColor(250, 195, 65); + HopColor:= RGBtoColor(100, 250, 65); + MiscColor:= RGBtoColor(240, 250, 65); + WaterAgentColor:= RGBtoColor(240, 140, 130); + FiningColor:= RGBtoColor(95, 180, 25); + YeastColor:= RGBtoColor(175, 175, 255); + WaterColor:= RGBtoColor(120, 255, 250); + + AlarmSound:= SoundFolder + 'alarm.wav'; + StartSound:= SoundFolder + 'welcome.wav'; + EndSound:= SoundFolder + 'end.wav'; + WarningSound:= SoundFolder + 'warning.wav'; + +// {$ifdef linux} +// //Initialize the sound system +// InitOpenAL; +// AlutInit(nil,argv); +// alGenBuffers(numbuffers, buffer); +// alGenSources(numsources, source); + +// AlutLoadWavFile(StartSound, format, dat, size, freq, loop); +// AlBufferData(buffer[startprog], format, dat, size, freq); +// AlutUnloadWav(format, dat, size, freq); + +// AlutLoadWavFile(WarningSound, format, dat, size, freq, loop); +// AlBufferData(buffer[warning], format, dat, size, freq); +// AlutUnloadWav(format, dat, size, freq); + +// AlutLoadWavFile(AlarmSound, format, dat, size, freq, loop); +// AlBufferData(buffer[alarm], format, dat, size, freq); +// AlutUnloadWav(format, dat, size, freq); + +// AlutLoadWavFile(EndSound, format, dat, size, freq, loop); +// AlBufferData(buffer[endprog], format, dat, size, freq); +// AlutUnloadWav(format, dat, size, freq); + +// AlSourcei( source[startprog], AL_BUFFER, buffer[startprog]); +// AlSourcef( source[startprog], AL_PITCH, 1.0 ); +// AlSourcef( source[startprog], AL_GAIN, 1.0 ); +// AlSourcefv( source[startprog], AL_POSITION, @sourcepos); +// AlSourcefv( source[startprog], AL_VELOCITY, @sourcevel); +// AlSourcei( source[startprog], AL_LOOPING, loop); + +// AlSourcei( source[warning], AL_BUFFER, buffer[warning]); +// AlSourcef( source[warning], AL_PITCH, 1.0 ); +// AlSourcef( source[warning], AL_GAIN, 1.0 ); +// AlSourcefv( source[warning], AL_POSITION, @sourcepos); +// AlSourcefv( source[warning], AL_VELOCITY, @sourcevel); +// AlSourcei( source[warning], AL_LOOPING, loop); + +// AlSourcei( source[alarm], AL_BUFFER, buffer[alarm]); +// AlSourcef( source[alarm], AL_PITCH, 1.0 ); +// AlSourcef( source[alarm], AL_GAIN, 1.0 ); +// AlSourcefv( source[alarm], AL_POSITION, @sourcepos); +// AlSourcefv( source[alarm], AL_VELOCITY, @sourcevel); +// AlSourcei( source[alarm], AL_LOOPING, loop); + +// AlSourcei( source[endprog], AL_BUFFER, buffer[endprog]); +// AlSourcef( source[endprog], AL_PITCH, 1.0 ); +// AlSourcef( source[endprog], AL_GAIN, 1.0 ); +// AlSourcefv( source[endprog], AL_POSITION, @sourcepos); +// AlSourcefv( source[endprog], AL_VELOCITY, @sourcevel); +// AlSourcei( source[endprog], AL_LOOPING, loop); + +// AlListenerfv( AL_POSITION, @listenerpos); +// AlListenerfv( AL_VELOCITY, @listenervel); +// AlListenerfv( AL_ORIENTATION, @listenerori); +// {$endif} + +finalization +// {$ifdef linux} +//Terminate the sound system +// Log(''); +// Log('HULPFUNCTIES'); +// AlDeleteBuffers(1, @buffer); +// Log('alBuffers afgesloten'); +// AlDeleteSources(1, @source); +// Log('alSources afgesloten'); +// AlutExit(); +// Log('Sound system afgesloten'); +// {$endif} + {$ifdef linux} + Log(''); + {$endif} +end. diff --git a/Source/Units/bh_report.pas b/Source/Units/bh_report.pas index c48e5f21..3e92b35d 100644 --- a/Source/Units/bh_report.pas +++ b/Source/Units/bh_report.pas @@ -934,8 +934,9 @@ procedure TBHRElement.SetTop(t : word); BRect.Left:= 0; BRect.Bottom:= SRect.Bottom - SRect.Top; BRect.Right:= SRect.Right - SRect.Left; - + {$ifndef Darwin} OTFH:= FChart.AxisList[0].Title.Font.Size; + {$endif} OMFH:= FChart.AxisList[0].Marks.LabelFont.Size; OTL:= FChart.AxisList[0].TickLength; OLFH:= FChart.Legend.Font.Size; @@ -946,7 +947,9 @@ procedure TBHRElement.SetTop(t : word); for i:= 0 to FChart.AxisList.Count - 1 do begin FChart.AxisList[i].Marks.LabelFont.Size:= round(GSc * 9); + {$ifndef Darwin} FChart.AxisList[i].Title.Font.Size:= round(GSC * 9); + {$endif} FChart.AxisList[i].TickLength:= round(GSc * OTL); end; FChart.Legend.Font.Size:= round(GSc * 9); @@ -962,7 +965,9 @@ procedure TBHRElement.SetTop(t : word); for i:= 0 to FChart.AxisList.Count - 1 do begin FChart.AxisList[i].Marks.LabelFont.Size:= OMFH; + {$ifndef Darwin} FChart.AxisList[i].Title.Font.Size:= OTFH; + {$endif} FChart.AxisList[i].TickLength:= OTL; end; FChart.Legend.Font.Size:= OLFH; diff --git a/Source/Units/containers.pas b/Source/Units/containers.pas index bdb3f8cb..609cf72b 100644 --- a/Source/Units/containers.pas +++ b/Source/Units/containers.pas @@ -3059,11 +3059,11 @@ TStyleLetters = record end; var sourcedata, destdata, sourcesounds, destsounds : string; begin - {$ifdef UNIX} + {$ifdef linux} sourcedata:= '/usr/share/brewbuddy/'; {$endif} {$ifdef darwin} - sourcedata:= '/usr/share/brewbuddy/'; + sourcedata:= ProgramDirectory() + 'BrewBuddy.app/Contents/Resources/'; {$endif} {$ifdef Windows} sourcedata:= ExtractFilePath(Application.ExeName) + 'brewbuddy\'; @@ -3116,9 +3116,9 @@ TStyleLetters = record CheckFile(sourcedata, destdata, 'Introductie BrewBuddy Sassy Saison.pdf'); {$endif} {$ifdef Darwin} - CheckFile('/usr/share/doc/brewbuddy/', destdata, 'Introductie BrewBuddy Sassy Saison.pdf'); + CheckFile(sourcedata, destdata, 'Introductie BrewBuddy Sassy Saison.pdf'); {$endif} - {$ifdef Unix} + {$ifdef linux} CheckFile('/usr/share/doc/brewbuddy/', destdata, 'Introductie BrewBuddy Sassy Saison.pdf'); {$endif} CheckFile(sourcesounds, destsounds, 'alarm.wav'); @@ -3232,11 +3232,11 @@ TStyleLetters = record end else //copy previous database to new location, but clear brews begin - {$ifdef UNIX} + {$ifdef linux} sourcedata:= '/usr/share/brewbuddy/'; {$endif} {$ifdef darwin} - sourcedata:= '/usr/share/brewbuddy/'; + sourcedata:= '/usr/local/share/brewbuddy/'; {$endif} {$ifdef Windows} sourcedata:= ExtractFilePath(Application.ExeName) + 'brewbuddy\'; @@ -3353,7 +3353,7 @@ TStyleLetters = record ExecFolder:= Application.Location; log('ExecFolder = ' + ExecFolder); OnUSB:= false; - {$ifdef UNIX} + {$ifdef linux} {DriveLetter:= LeftStr(ExecFolder, 6); if DriveLetter = '/media' then begin diff --git a/Source/Units/fann.pas b/Source/Units/fann.pas index 690d8717..5fe450be 100644 --- a/Source/Units/fann.pas +++ b/Source/Units/fann.pas @@ -1,1228 +1,1228 @@ -unit FANN; -{$mode delphi} -interface -{******************************************************* - - Only Delphi 6 and above supports variable arguments - functions. - If you are using a older version of Delphi comment the - VARIABLE_ARGUMENTS directive. - If you disable the VARIABLE_ARGUMENTS directive the - following functions will not be available: - fann_create_shortcut - fann_create_sparse - fann_create_standard - -********************************************************} - -{$DEFINE VARIABLE_ARGUMENTS} - -{******************************************************* - - If you want to use Fixed Fann or Double Fann please - uncomment the corresponding definition. - As default fann.pas uses the fannfloat dll. - -********************************************************} -//{$DEFINE FIXEDFANN} //Uncomment for fixed fann -{$DEFINE DOUBLEFANN} //Uncomment for double fann - - - - -{$ifdef windows} -{$IF Defined(FIXEDFANN)} -const DLL_FILE = 'fannfixed.dll'; -{$ELSEIF Defined(DOUBLEFANN)} -const DLL_FILE = 'fanndouble.dll'; -{$ELSE} -const DLL_FILE = 'fannfloat.dll'; -{$IFEND} -{$endif} -{$ifdef linux} -{$IF Defined(FIXEDFANN)} -const DLL_FILE = 'libfixedfann.so'; -{$ELSEIF Defined(DOUBLEFANN)} -const DLL_FILE = 'libdoublefann.so'; -{$ELSE} -const DLL_FILE = 'libfloatfann.so'; -{$IFEND} -{$endif} -{$ifdef darwin} -{$IF Defined(FIXEDFANN)} -const DLL_FILE = 'libfixedfann.2.2.0.dylib'; -{$ELSEIF Defined(DOUBLEFANN)} -const DLL_FILE = 'libdoublefann.2.2.0.dylib'; -{$ELSE} -const DLL_FILE = 'libfloatfann.2.2.0.dylib'; -{$IFEND} -{$endif} - - -type - - {$IF Defined(FIXEDFANN)} - fann_type = integer; - {$ELSEIF Defined(DOUBLEFANN)} - fann_type = double; - {$ELSE} - fann_type = single; - {$IFEND} - - - PFann_Type = ^fann_type; - - PPFann_Type = ^pfann_type; - - Fann_Type_Array = array [0..65535] of fann_type; - - PFann_Type_Array = ^Fann_type_array; - - PPFann_Type_Array = array [0..65535] of ^Fann_Type_Array; - - - - - (* MICROSOFT VC++ STDIO'S FILE DEFINITION*) - _iobuf = packed record - _ptr: Pchar; - _cnt: integer; - _base: Pchar; - _flag: integer; - _file: integer; - _charbuf: integer; - _bufsiz: integer; - _tmpfname: Pchar; - end; - - - PFile = ^TFile; - TFile = _iobuf; - - - PPFann_Neuron = ^PFann_Neuron; - PFann_Neuron = ^TFann_Neuron; - TFann_Neuron = packed record - first_con: Cardinal; - last_con: Cardinal; - sum: fann_type; - value: fann_type; - activation_steepness: fann_type; - activation_function: Cardinal; //enum - end; - - - PFann_Layer = ^TFann_Layer; - TFann_Layer = packed record - first_neuron: PFann_Neuron; - last_neuron: PFann_Neuron; - end; - - PFann = ^TFann; - TFann = packed record - errno_f: cardinal; - error_log: PFile; - errstr: Pchar; - - learning_rate: single; - learning_momentum: single; - connection_rate: single; - - network_type: Cardinal; //ENUM - - first_layer: PFann_Layer; - last_layer: PFann_Layer; - - total_neurons: cardinal; - num_input: cardinal; - num_output: cardinal; - - weights: Pfann_type; - - connections: PPFann_Neuron; - - train_errors: Pfann_type; - - training_algorithm: cardinal; //ENUM - - - {$IFDEF FIXEDFANN} - decimal_point: cardinal; - multiplier: cardinal; - - sigmoid_results: array [0..5] of fann_type; - sigmoid_values: array [0..5] of fann_type; - symmetric_results: array [0..5] of fann_type; - symmetric_values: array [0..5] of fann_type; - - {$ENDIF} - - total_connections: cardinal; - output: pfann_type; - - num_MSE: cardinal; - MSE_value: single; - - num_bit_fail: cardinal; - bit_fail_limit: fann_type; - - train_error_function: cardinal;//enum - train_stop_function: cardinal; //enum - - callback: Pointer; //TFANN_CALLBACK - - user_data: Pointer; - - cascade_output_change_fraction: single; - cascade_output_stagnation_epochs: Cardinal; - cascade_candidate_change_fraction: single; - cascade_candidate_stagnation_epochs: Cardinal; - cascade_best_candidate: Cardinal; - - cascade_candidate_limit: fann_type; - cascade_weight_multiplier: fann_type; - - cascade_max_out_epochs: Cardinal; - cascade_max_cand_epochs: Cardinal; - - cascade_activation_functions: PCardinal; - cascade_activation_functions_count: Cardinal; - - cascade_activation_steepnesses: PFann_Type; - - cascade_activation_steepnesses_count: Cardinal; - cascade_num_candidate_groups: Cardinal; - - cascade_candidate_scores: PFann_Type; - - total_neurons_allocated: Cardinal; - total_connections_allocated: Cardinal; - - - - quickprop_decay: single; - quickprop_mu: single; - - rprop_increase_factor: single; - rprop_decrease_factor: single; - - rprop_delta_min: single; - rprop_delta_max: single; - - rprop_delta_zero: single; - - train_slopes: pfann_type; - - prev_steps: pfann_type; - - prev_train_slopes: pfann_type; - - prev_weights_deltas: pfann_type; - - {$IFNDEF FIXEDFANN} - scale_mean_in: psingle; - scale_deviation_in: psingle; - scale_new_min_in: psingle; - scale_factor_in: psingle; - scale_mean_out: psingle; - scale_deviation_out: psingle; - scale_new_min_out: psingle; - scale_factor_out: psingle; - - {$ENDIF} - end; - - PFann_Train_Data = ^TFann_Train_Data; - TFann_Train_Data = packed record - errno_f: cardinal; - erro_log: PFile; - errstr: Pchar; - num_data: cardinal; - num_input: cardinal; - num_ouput: cardinal; - input: PPFann_Type_Array; - output: PPFann_Type_Array; - end; - - PFann_Connection = ^TFann_Connection; - TFann_Connection = packed record - from_neuron: Cardinal; - to_neuron: Cardinal; - weight: fann_type; - end; - - PFann_Error = ^TFann_Error; - TFann_Error = packed record - errno_f: Cardinal; //Enum - error_log: PFile; - errstr: PChar; - end; - - - //_Fann_Train = - const - - FANN_TRAIN_INCREMENTAL = 0; - FANN_TRAIN_BATCH = 1; - FANN_TRAIN_RPROP = 2; - FANN_TRAIN_QUICKPROP = 3; - - - //_Fann_Error_Func = - - FANN_ERRORFUNC_LINEAR = 0; - FANN_ERRORFUNC_TANH = 1; - - - //_Fann_Activation_Func = - FANN_LINEAR = 0; - FANN_THRESHOLD = 1; - FANN_THRESHOLD_SYMMETRIC = 2; - FANN_SIGMOID = 3; - FANN_SIGMOID_STEPWISE = 4; - FANN_SIGMOID_SYMMETRIC = 5; - FANN_SIGMOID_SYMMETRIC_STEPWISE = 6; - FANN_GAUSSIAN = 7; - FANN_GAUSSIAN_SYMMETRIC = 8; - FANN_GAUSSIAN_STEPWISE = 9; - FANN_ELLIOT = 10; - FANN_ELLIOT_SYMMETRIC = 11; - FANN_LINEAR_PIECE = 12; - FANN_LINEAR_PIECE_SYMMETRIC = 13; - FANN_SIN_SYMMETRIC = 14; - FANN_COS_SYMMETRIC = 15; - FANN_SIN = 16; - FANN_COS = 17; - - - //_Fann_ErroNo = - FANN_E_NO_ERROR = 0; - FANN_E_CANT_OPEN_CONFIG_R = 1; - FANN_E_CANT_OPEN_CONFIG_W = 2; - FANN_E_WRONG_CONFIG_VERSION = 3; - FANN_E_CANT_READ_CONFIG = 4; - FANN_E_CANT_READ_NEURON = 5; - FANN_E_CANT_READ_CONNECTIONS = 6; - FANN_E_WRONG_NUM_CONNECTIONS = 7; - FANN_E_CANT_OPEN_TD_W = 8; - FANN_E_CANT_OPEN_TD_R = 9; - FANN_E_CANT_READ_TD = 10; - FANN_E_CANT_ALLOCATE_MEM = 11; - FANN_E_CANT_TRAIN_ACTIVATION = 12; - FANN_E_CANT_USE_ACTIVATION = 13; - FANN_E_TRAIN_DATA_MISMATCH = 14; - FANN_E_CANT_USE_TRAIN_ALG = 15; - FANN_E_TRAIN_DATA_SUBSET = 16; - FANN_E_INDEX_OUT_OF_BOUND = 17; - FANN_E_SCALE_NOT_PRESENT = 18; - - - //_Fann_Stop_Func = - - FANN_STOPFUNC_MSE = 0; - FANN_STOPFUNC_BIT = 1; - - //_Fann_Net_Type = - FANN_NETTYPE_LAYER = 0; - FANN_NETTYPE_SHORTCUT = 1; - - type - - TFann_CallBack = function(Ann: PFann; - train: PFann_Train_Data; - max_epochs: Cardinal; - epochs_between_reports: cardinal; - desired_error: single; - epochs: cardinal): integer; cdecl; - - TUser_Function = procedure(num: Cardinal; - num_input: Cardinal; - num_output: cardinal; - input: PFann_Type; - output: PFann_Type); cdecl; - - - - -var - FANN_ERRORFUNC_NAMES: array [0..1] of string = ( - 'FANN_ERRORFUNC_LINEAR', - 'FANN_ERRORFUNC_TANH' - ); - - FANN_TRAIN_NAMES: array [0..3] of string = - ( - 'FANN_TRAIN_INCREMENTAL', - 'FANN_TRAIN_BATCH', - 'FANN_TRAIN_RPROP', - 'FANN_TRAIN_QUICKPROP' - ); - - FANN_ACTIVATIONFUNC_NAMES: array [0..17] of string = - ( - 'FANN_LINEAR', - 'FANN_THRESHOLD', - 'FANN_THRESHOLD_SYMMETRIC', - 'FANN_SIGMOID', - 'FANN_SIGMOID_STEPWISE', - 'FANN_SIGMOID_SYMMETRIC', - 'FANN_SIGMOID_SYMMETRIC_STEPWISE', - 'FANN_GAUSSIAN', - 'FANN_GAUSSIAN_SYMMETRIC', - 'FANN_GAUSSIAN_STEPWISE', - 'FANN_ELLIOT', - 'FANN_ELLIOT_SYMMETRIC', - 'FANN_LINEAR_PIECE', - 'FANN_LINEAR_PIECE_SYMMETRIC', - 'FANN_SIN_SYMMETRIC', - 'FANN_COS_SYMMETRIC', - 'FANN_SIN', - 'FANN_COS' - ); - - FANN_STOPFUNC_NAMES: array [0..1] of string = - ( - 'FANN_STOPFUNC_MSE', - 'FANN_STOPFUNC_BIT' - ); - - FANN_NETTYPE_NAMES: array [0..1] of string = - ( - 'FANN_NETTYPE_LAYER', - 'FANN_NETTYPE_SHORTCUT' - ); - - - //DECLARATIONS FROM FANN.H - - {$IFDEF VARIABLE_ARGUMENTS} - - { - - ATTENTION! - If your compilation breaks here maybe you are using a version of Delphi - prior to 6. In this case you should comment the VARIABLE_ARGUMENTS define - at the beginning of this file and live without this functions! - - } - function fann_create_standard(num_layers: Cardinal): PFann; cdecl; varargs; - - function fann_create_sparse(connection_rate: single; num_layers: Cardinal): PFann; cdecl; varargs; - - function fann_create_shortcut(connection_rate: single): PFann; cdecl; varargs; - - - {$ENDIF} - - - function fann_create_standard_array(num_layers: Cardinal; const layers: PCardinal): PFann; cdecl; - - function fann_create_sparse_array(connection_rate: single; num_layers: Cardinal; const layers: PCardinal): PFann; cdecl; - - function fann_create_shortcut_array(num_layers: cardinal;const layers: Pcardinal): PFann; cdecl; - - - procedure fann_destroy(Ann: PFann); cdecl; - - - function fann_run(ann: PFann; input: PFann_Type): Pfann_type_array; cdecl; - - - procedure fann_randomize_weights(Ann: PFann; Min_weight: fann_type; Max_weight: fann_type); cdecl; - - procedure fann_init_weights(Ann: PFann; train_data: PFann_Train_Data); cdecl; - - - procedure fann_print_connections(ann: PFann);cdecl; - - procedure fann_print_parameters(ann: PFann);cdecl; - - - function fann_get_num_input(Ann: PFann): cardinal;cdecl; - - function fann_get_num_output(Ann: PFann): cardinal;cdecl; - - function fann_get_total_neurons(Ann: PFann): cardinal; cdecl; - - function fann_get_total_connections(Ann: PFann): cardinal; cdecl; - - - function fann_get_network_type(Ann: PFann): cardinal; cdecl; - - function fann_get_connection_rate(Ann: PFann): single; cdecl; - - - function fann_get_num_layers(Ann: PFann): cardinal; cdecl; - - - procedure fann_get_layer_array(Ann: PFann; layers: PCardinal); cdecl; - - procedure fann_get_bias_array(Ann: PFann; bias: PCardinal);cdecl; - - - procedure fann_get_connection_array(Ann: PFann; connections: PFann_Connection);cdecl; - - - procedure fann_set_weight_array(Ann: PFann; connections: PFann_Connection; num_connection: Cardinal);cdecl; - - - procedure fann_set_weight(Ann: PFann; from_neuron: Cardinal; to_neuron: Cardinal; weight: fann_type);cdecl; - - procedure fann_set_user_data(Ann: PFann; user_data: Pointer);cdecl; - - function fann_get_user_data(Ann: PFann): Pointer; cdecl; - - - {$IFDEF FIXEDFANN} - - function fann_get_decimal_point(Ann: Pfann): cardinal; cdecl; - - function fann_get_multiplier(Ann: PFann): cardinal;cdecl; - - {$ENDIF} - - //END OF DECLARATIONS FROM FANN.H - - - - //DECLARATIONS FROM FANN_IO.H - - - function fann_create_from_file(const configuration_file: PChar): PFann; cdecl; - - procedure fann_save(Ann: PFann; Const Configuration_File: PChar);cdecl; - - function fann_save_to_fixed(Ann: PFann; Const Configuration_File: PChar): integer;cdecl; - - //END OF DECLARATIONS FROM FANN_IO.H - - - //DECLARATIONS FROM FANN_TRAIN.H - - {$IFNDEF FIXEDFANN} - procedure fann_train(Ann: PFann; Input: PFann_Type; Desired_Output: PFann_Type);cdecl; - {$ENDIF} - - function fann_test(Ann: PFann; Input: PFann_Type; Desired_Output: Pfann_Type): Pfann_type_array;cdecl; - - - function fann_get_MSE(Ann: PFann): single;cdecl; - - function fann_get_bit_fail(Ann: PFann): Cardinal;cdecl; - - procedure fann_reset_MSE(Ann: Pfann); cdecl; - - - {$IFNDEF FIXEDFANN} - - - procedure fann_train_on_data(Ann: PFann; Data: PFann_Train_Data;max_epochs: cardinal;epochs_between_reports: cardinal; desired_error: single);cdecl; - - procedure fann_train_on_file(Ann: PFann; Filename: Pchar;max_epochs: cardinal;epochs_between_reports: cardinal; desired_error: single); cdecl; - - - - function fann_train_epoch(Ann: PFann; data: PFann_Train_Data): single; cdecl; - - - function fann_test_data(Ann: PFann; data: PFann_Train_Data): single; cdecl; - - {$ENDIF} - - function fann_read_train_from_file(const filename: PChar): PFann_Train_Data; cdecl; - - - - function fann_create_train_from_callback(num_data: Cardinal; - num_input: Cardinal; - num_output: Cardinal; - user_function: TUser_Function): PFann_Train_Data; cdecl; - - - - procedure fann_destroy_train(train_data: PFann_Train_Data); cdecl; - - - procedure fann_shuffle_train_data(Train_Data: PFann_Train_Data);cdecl; - - - procedure fann_scale_train(Ann: PFann; data: PFann_Train_Data);cdecl; - - procedure fann_descale_train(Ann: PFann; data: PFann_Train_Data);cdecl; - - - function fann_set_input_scaling_params(Ann: PFann; - const data: PFann_Train_Data; - new_input_min: single; - new_input_max: single): integer;cdecl; - - - function fann_set_output_scaling_params(Ann: PFann; - const data: PFann_Train_Data; - new_output_min: single; - new_output_max: single): integer;cdecl; - - - - function fann_set_scaling_params(Ann: PFann; - const data: PFann_Train_Data; - new_input_min: single; - new_input_max: single; - new_output_min: single; - new_output_max: single): integer; cdecl; - - - function fann_clear_scaling_params(Ann: PFann): integer; cdecl; - - - - procedure fann_scale_input(Ann: PFann; input_vector: PFann_type); cdecl; - - - procedure fann_scale_output(Ann: PFann; output_vector: PFann_type); cdecl; - - - procedure fann_descale_input(Ann: PFann; input_vector: PFann_type); cdecl; - - - procedure fann_descale_output(Ann: PFann; output_vector: PFann_type); cdecl; - - - procedure fann_scale_input_train_data(Train_Data: PFann_Train_Data; - new_min: fann_type; - new_max: fann_type); cdecl; - - - procedure fann_scale_output_train_data(Train_Data: PFann_Train_Data; - new_min: fann_type; - new_max: fann_type); cdecl; - - - procedure fann_scale_train_data(Train_Data: PFann_Train_Data; - new_min: fann_type; - new_max: fann_type); cdecl; - - - function fann_merge_train_data(Data1: PFann_Train_Data; Data2: PFann_Train_Data): PFann_Train_Data; cdecl; - - - function fann_duplicate_train_data(Data: PFann_Train_Data): PFann_Train_Data;cdecl; - - - function fann_subset_train_data(data: PFann_Train_Data; pos: Cardinal; length: Cardinal): PFann_Train_Data; cdecl; - - - function fann_length_train_data(data: PFann_Train_Data): Cardinal; cdecl; - - - function fann_num_input_train_data(data: PFann_Train_Data): Cardinal; cdecl; - - function fann_num_output_train_data(data: PFann_Train_Data): Cardinal; cdecl; - - function fann_save_train(Data: PFann_train_Data; const Filename: PChar): integer;cdecl; - - function fann_save_train_to_fixed(Data: PFann_train_Data; const FileName: Pchar; decimal_point: cardinal): integer;cdecl; - - - - function fann_get_training_algorithm(Ann: Pfann): cardinal;cdecl; - - procedure fann_set_training_algorithm(Ann: PFann; Training_Algorithm: cardinal);cdecl; - - function fann_get_learning_rate(Ann: PFann): single;cdecl; - - procedure fann_set_learning_rate(Ann: PFann; Learning_Rate: Single); cdecl; - - function fann_get_learning_momentum(Ann: PFann): single;cdecl; - - procedure fann_set_learning_momentum(Ann: PFann; learning_momentum: Single); cdecl; - - - - function fann_get_activation_function(Ann: PFann; layer: integer; neuron: integer): Cardinal; cdecl; //ENUM - - procedure fann_set_activation_function(Ann: PFann; activation_function: Cardinal; layer: integer; neuron: integer); cdecl; //ENUM - - - procedure fann_set_activation_function_layer(Ann: PFann; activation_function: Cardinal; layer: integer); cdecl; //ENUM - - - procedure fann_set_activation_function_hidden(Ann: Pfann; Activation_function: cardinal); cdecl; - - procedure fann_set_activation_function_output(Ann: Pfann; Activation_Function: cardinal); cdecl; - - function fann_get_activation_steepness(Ann: PFann; layer: integer; neuron: integer): fann_type; cdecl; - - - procedure fann_set_activation_steepness(Ann: PFann; steepness: fann_type; layer: integer; neuron: integer); cdecl; - - - procedure fann_set_activation_steepness_layer(Ann: PFann; steepness: fann_type; layer: integer); cdecl; - - - procedure fann_set_activation_steepness_hidden(Ann: PFann; steepness: Fann_Type); cdecl; - - procedure fann_set_activation_steepness_output(Ann: PFann; steepness: Fann_Type);cdecl; - - function fann_get_train_error_function(Ann: PFann): cardinal;cdecl; - - procedure fann_set_train_error_function(Ann: PFann; Train_Error_Function: cardinal); cdecl; - - function fann_get_train_stop_function(Ann: PFann): Cardinal; cdecl; - - procedure fann_set_train_stop_function(Ann: PFann; train_stop_function: cardinal); cdecl; - - function fann_get_bit_fail_limit(Ann: PFann): fann_type; cdecl; - - procedure fann_set_bit_fail_limit(Ann: PFann; bit_fail_limit: fann_type); cdecl; - - procedure fann_set_callback(Ann: PFann; callback: TFann_Callback); cdecl; - - function fann_get_quickprop_decay(Ann: PFann): single;cdecl; - - procedure fann_set_quickprop_decay(Ann: Pfann; quickprop_decay: Single);cdecl; - - function fann_get_quickprop_mu(Ann: PFann): single;cdecl; - - procedure fann_set_quickprop_mu(Ann: PFann; Mu: Single);cdecl; - - function fann_get_rprop_increase_factor(Ann: PFann): single;cdecl; - - procedure fann_set_rprop_increase_factor(Ann: PFann;rprop_increase_factor: single);cdecl; - - function fann_get_rprop_decrease_factor(Ann: PFann): single;cdecl; - - procedure fann_set_rprop_decrease_factor(Ann: PFann;rprop_decrease_factor: single); cdecl; - - function fann_get_rprop_delta_min(Ann: PFann): single; cdecl; - - procedure fann_set_rprop_delta_min(Ann: PFann; rprop_delta_min: Single); cdecl; - - function fann_get_rprop_delta_max(Ann: PFann): single;cdecl; - - procedure fann_set_rprop_delta_max(Ann: PFann; rprop_delta_max: Single); cdecl; - - function fann_get_rprop_delta_zero(Ann: PFann): single;cdecl; - - procedure fann_set_rprop_delta_zero(Ann: PFann; rprop_delta_zero: Single); cdecl; - - //END OF DECLARATIONS OF FANN_TRAIN.H - - - //DECLARATIONS OF FANN_ERROR.H - - procedure fann_set_error_log(errdat: PFann_Error; Log_File: PFile);cdecl; - - function fann_get_errno(errdat: PFann_Error): cardinal;cdecl; - - procedure fann_reset_errno(errdat: PFann_Error);cdecl; - - procedure fann_reset_errstr(errdat: PFann_Error);cdecl; - - function fann_get_errstr(errdat: PFann_Error): PChar;cdecl; - - procedure fann_print_error(Errdat: PFann_Error);cdecl; - - - //END OF DECLARATIONS OF FANN_ERROR - - //DECLARATIONS OF FANN_CASCADE.H - - procedure fann_cascadetrain_on_data(Ann: PFann; - data: PFann_Train_Data; - max_neurons: Cardinal; - neurons_between_reports: Cardinal; - desired_error: single); cdecl; - - procedure fann_cascadetrain_on_file(Ann: PFann; - const filename: PChar; - max_neurons: Cardinal; - neurons_between_reports: Cardinal; - desired_error: single); cdecl; - - - function fann_get_cascade_output_change_fraction(Ann: PFann): single; cdecl; - - - procedure fann_set_cascade_output_change_fraction(Ann: PFann; cascade_output_change_fraction: single); cdecl; - - - function fann_get_cascade_output_stagnation_epochs(Ann: PFann): cardinal; cdecl; - - - procedure fann_set_cascade_output_stagnation_epochs(Ann: PFann; cascade_output_stagnation_epochs: cardinal); cdecl; - - - function fann_get_cascade_candidate_change_fraction(Ann: PFann): single; cdecl; - - - procedure fann_set_cascade_candidate_change_fraction(Ann: PFann; cascade_candidate_change_fraction: single); cdecl; - - - function fann_get_cascade_candidate_stagnation_epochs(Ann: PFann): cardinal; cdecl; - - - procedure fann_set_cascade_candidate_stagnation_epochs(Ann: PFann; cascade_candidate_stagnation_epochs: cardinal); cdecl; - - - function fann_get_cascade_weight_multiplier(Ann: PFann): fann_type; cdecl; - - - procedure fann_set_cascade_weight_multiplier(Ann: PFann; cascade_weight_multiplier: fann_type); cdecl; - - - function fann_get_cascade_candidate_limit(Ann: PFann): fann_type; cdecl; - - - procedure fann_set_cascade_candidate_limit(Ann: PFann; cascade_candidate_limit: fann_type); cdecl; - - - - function fann_get_cascade_max_out_epochs(Ann: PFann): cardinal; cdecl; - - - procedure fann_set_cascade_max_out_epochs(Ann: PFann; cascade_max_out_epochs: cardinal); cdecl; - - - function fann_get_cascade_max_cand_epochs(Ann: PFann): cardinal; cdecl; - - - procedure fann_set_cascade_max_cand_epochs(Ann: PFann; cascade_max_cand_epochs: cardinal); cdecl; - - - function fann_get_cascade_num_candidates(Ann: PFann): cardinal; cdecl; - - - function fann_get_cascade_activation_functions_count(Ann: PFann): cardinal; cdecl; - - - - function fann_get_cascade_activation_functions(Ann: PFann): PCardinal; cdecl; - - - procedure fann_set_cascade_activation_functions(Ann: PFann; cascade_activation_functions: PCardinal; cascade_activation_functions_count: Cardinal); cdecl; - - - function fann_get_cascade_activation_steepnesses_count(Ann: PFann): cardinal; cdecl; - - - function fann_get_cascade_activation_steepnesses(Ann: PFann): pfann_type; cdecl; - - procedure fann_set_cascade_activation_steepnesses(Ann: PFann; cascade_activation_steepnesses: PFann_Type; cascade_activation_steepnesses_count: Cardinal); cdecl; - - - function fann_get_cascade_num_candidate_groups(Ann: PFann): cardinal; cdecl; - - - procedure fann_set_cascade_num_candidate_groups(Ann: PFann; cascade_num_candidate_groups: cardinal); cdecl; - - - //END OF DECLARATIONS OF FANN_CASCADE.H - - - -implementation - - - {$IFDEF VARIABLE_ARGUMENTS} - - function fann_create_standard; external DLL_FILE; - - {$ENDIF} - - - function fann_create_standard_array; external DLL_FILE; - - - {$IFDEF VARIABLE_ARGUMENTS} - - function fann_create_sparse; external DLL_FILE; - - {$ENDIF} - - - - function fann_create_sparse_array; external DLL_FILE; - - - - {$IFDEF VARIABLE_ARGUMENTS} - - function fann_create_shortcut; external DLL_FILE; - - {$ENDIF} - - - function fann_create_shortcut_array; external DLL_FILE; - - - procedure fann_destroy; external DLL_FILE; - - - function fann_run; external DLL_FILE; - - - procedure fann_randomize_weights; external DLL_FILE; - - procedure fann_init_weights; external DLL_FILE; - - - procedure fann_print_connections; external DLL_FILE; - - procedure fann_print_parameters; external DLL_FILE; - - - function fann_get_num_input; external DLL_FILE; - - function fann_get_num_output; external DLL_FILE; - - function fann_get_total_neurons; external DLL_FILE; - - function fann_get_total_connections; external DLL_FILE; - - - function fann_get_network_type; external DLL_FILE; - - function fann_get_connection_rate; external DLL_FILE; - - - function fann_get_num_layers; external DLL_FILE; - - - procedure fann_get_layer_array; external DLL_FILE; - - procedure fann_get_bias_array; external DLL_FILE; - - - procedure fann_get_connection_array; external DLL_FILE; - - - procedure fann_set_weight_array; external DLL_FILE; - - - procedure fann_set_weight; external DLL_FILE; - - procedure fann_set_user_data; external DLL_FILE; - - function fann_get_user_data; external DLL_FILE; - - - {$IFDEF FIXEDFANN} - - function fann_get_decimal_point; external DLL_FILE; - - function fann_get_multiplier; external DLL_FILE; - - {$ENDIF} - - //END OF DECLARATIONS FROM FANN.H - - - - //DECLARATIONS FROM FANN_IO.H - - - function fann_create_from_file; external DLL_FILE; - - procedure fann_save; external DLL_FILE; - - function fann_save_to_fixed; external DLL_FILE; - - //END OF DECLARATIONS FROM FANN_IO.H - - - //DECLARATIONS FROM FANN_TRAIN.H - - {$IFNDEF FIXEDFANN} - procedure fann_train; external DLL_FILE; - {$ENDIF} - - function fann_test; external DLL_FILE; - - - function fann_get_MSE; external DLL_FILE; - - function fann_get_bit_fail; external DLL_FILE; - - procedure fann_reset_MSE; external DLL_FILE; - - - {$IFNDEF FIXEDFANN} - - - procedure fann_train_on_data; external DLL_FILE; - - procedure fann_train_on_file; external DLL_FILE; - - - - function fann_train_epoch; external DLL_FILE; - - - function fann_test_data; external DLL_FILE; - - {$ENDIF} - - function fann_read_train_from_file; external DLL_FILE; - - - - function fann_create_train_from_callback; external DLL_FILE; - - - - procedure fann_destroy_train; external DLL_FILE; - - - procedure fann_shuffle_train_data; external DLL_FILE; - - - procedure fann_scale_train; external DLL_FILE; - - procedure fann_descale_train; external DLL_FILE; - - - function fann_set_input_scaling_params; external DLL_FILE; - - - function fann_set_output_scaling_params; external DLL_FILE; - - - - function fann_set_scaling_params; external DLL_FILE; - - - function fann_clear_scaling_params; external DLL_FILE; - - - - procedure fann_scale_input; external DLL_FILE; - - - procedure fann_scale_output; external DLL_FILE; - - - procedure fann_descale_input; external DLL_FILE; - - - procedure fann_descale_output; external DLL_FILE; - - - procedure fann_scale_input_train_data; external DLL_FILE; - - - procedure fann_scale_output_train_data; external DLL_FILE; - - - procedure fann_scale_train_data; external DLL_FILE; - - - function fann_merge_train_data; external DLL_FILE; - - - function fann_duplicate_train_data; external DLL_FILE; - - - function fann_subset_train_data; external DLL_FILE; - - - function fann_length_train_data; external DLL_FILE; - - - function fann_num_input_train_data; external DLL_FILE; - - function fann_num_output_train_data; external DLL_FILE; - - function fann_save_train; external DLL_FILE; - - function fann_save_train_to_fixed; external DLL_FILE; - - - - function fann_get_training_algorithm; external DLL_FILE; - - procedure fann_set_training_algorithm; external DLL_FILE; - - function fann_get_learning_rate; external DLL_FILE; - - procedure fann_set_learning_rate; external DLL_FILE; - - function fann_get_learning_momentum; external DLL_FILE; - - procedure fann_set_learning_momentum; external DLL_FILE; - - - - function fann_get_activation_function; external DLL_FILE; //ENUM - - procedure fann_set_activation_function; external DLL_FILE; //ENUM - - - procedure fann_set_activation_function_layer; external DLL_FILE; //ENUM - - - procedure fann_set_activation_function_hidden; external DLL_FILE; - - procedure fann_set_activation_function_output; external DLL_FILE; - - function fann_get_activation_steepness; external DLL_FILE; - - - procedure fann_set_activation_steepness; external DLL_FILE; - - - procedure fann_set_activation_steepness_layer; external DLL_FILE; - - - procedure fann_set_activation_steepness_hidden; external DLL_FILE; - - procedure fann_set_activation_steepness_output; external DLL_FILE; - - function fann_get_train_error_function; external DLL_FILE; - - procedure fann_set_train_error_function; external DLL_FILE; - - function fann_get_train_stop_function; external DLL_FILE; - - procedure fann_set_train_stop_function; external DLL_FILE; - - function fann_get_bit_fail_limit; external DLL_FILE; - - procedure fann_set_bit_fail_limit; external DLL_FILE; - - procedure fann_set_callback; external DLL_FILE; - - function fann_get_quickprop_decay; external DLL_FILE; - - procedure fann_set_quickprop_decay; external DLL_FILE; - - function fann_get_quickprop_mu; external DLL_FILE; - - procedure fann_set_quickprop_mu; external DLL_FILE; - - function fann_get_rprop_increase_factor; external DLL_FILE; - - procedure fann_set_rprop_increase_factor; external DLL_FILE; - - function fann_get_rprop_decrease_factor; external DLL_FILE; - - procedure fann_set_rprop_decrease_factor; external DLL_FILE; - - function fann_get_rprop_delta_min; external DLL_FILE; - - procedure fann_set_rprop_delta_min; external DLL_FILE; - - function fann_get_rprop_delta_max; external DLL_FILE; - - procedure fann_set_rprop_delta_max; external DLL_FILE; - - function fann_get_rprop_delta_zero; external DLL_FILE; - - procedure fann_set_rprop_delta_zero; external DLL_FILE; - - //END OF DECLARATIONS OF FANN_TRAIN.H - - - //DECLARATIONS OF FANN_ERROR.H - - procedure fann_set_error_log; external DLL_FILE; - - function fann_get_errno; external DLL_FILE; - - procedure fann_reset_errno; external DLL_FILE; - - procedure fann_reset_errstr; external DLL_FILE; - - function fann_get_errstr; external DLL_FILE; - - procedure fann_print_error; external DLL_FILE; - - - //END OF DECLARATIONS OF FANN_ERROR - - //DECLARATIONS OF FANN_CASCADE.H - - procedure fann_cascadetrain_on_data; external DLL_FILE; - - procedure fann_cascadetrain_on_file; external DLL_FILE; - - - function fann_get_cascade_output_change_fraction; external DLL_FILE; - - - procedure fann_set_cascade_output_change_fraction; external DLL_FILE; - - - function fann_get_cascade_output_stagnation_epochs; external DLL_FILE; - - - procedure fann_set_cascade_output_stagnation_epochs; external DLL_FILE; - - - function fann_get_cascade_candidate_change_fraction; external DLL_FILE; - - - procedure fann_set_cascade_candidate_change_fraction; external DLL_FILE; - - - function fann_get_cascade_candidate_stagnation_epochs; external DLL_FILE; - - - procedure fann_set_cascade_candidate_stagnation_epochs; external DLL_FILE; - - - function fann_get_cascade_weight_multiplier; external DLL_FILE; - - - procedure fann_set_cascade_weight_multiplier; external DLL_FILE; - - - function fann_get_cascade_candidate_limit; external DLL_FILE; - - - procedure fann_set_cascade_candidate_limit; external DLL_FILE; - - - - function fann_get_cascade_max_out_epochs; external DLL_FILE; - - - procedure fann_set_cascade_max_out_epochs; external DLL_FILE; - - - function fann_get_cascade_max_cand_epochs; external DLL_FILE; - - - procedure fann_set_cascade_max_cand_epochs; external DLL_FILE; - - - function fann_get_cascade_num_candidates; external DLL_FILE; - - - function fann_get_cascade_activation_functions_count; external DLL_FILE; - - - - function fann_get_cascade_activation_functions; external DLL_FILE; - - - procedure fann_set_cascade_activation_functions; external DLL_FILE; - - - function fann_get_cascade_activation_steepnesses_count; external DLL_FILE; - - - function fann_get_cascade_activation_steepnesses; external DLL_FILE; - - procedure fann_set_cascade_activation_steepnesses; external DLL_FILE; - - - function fann_get_cascade_num_candidate_groups; external DLL_FILE; - - - procedure fann_set_cascade_num_candidate_groups; external DLL_FILE; - - - -end. - \ No newline at end of file +unit FANN; +{$mode delphi} +interface +{******************************************************* + + Only Delphi 6 and above supports variable arguments + functions. + If you are using a older version of Delphi comment the + VARIABLE_ARGUMENTS directive. + If you disable the VARIABLE_ARGUMENTS directive the + following functions will not be available: + fann_create_shortcut + fann_create_sparse + fann_create_standard + +********************************************************} + +{$DEFINE VARIABLE_ARGUMENTS} + +{******************************************************* + + If you want to use Fixed Fann or Double Fann please + uncomment the corresponding definition. + As default fann.pas uses the fannfloat dll. + +********************************************************} +//{$DEFINE FIXEDFANN} //Uncomment for fixed fann +{$DEFINE DOUBLEFANN} //Uncomment for double fann + + + + +{$ifdef windows} +{$IF Defined(FIXEDFANN)} +const DLL_FILE = 'fannfixed.dll'; +{$ELSEIF Defined(DOUBLEFANN)} +const DLL_FILE = 'fanndouble.dll'; +{$ELSE} +const DLL_FILE = 'fannfloat.dll'; +{$IFEND} +{$endif} +{$ifdef linux} +{$IF Defined(FIXEDFANN)} +const DLL_FILE = 'libfixedfann.so'; +{$ELSEIF Defined(DOUBLEFANN)} +const DLL_FILE = 'libdoublefann.so'; +{$ELSE} +const DLL_FILE = 'libfloatfann.so'; +{$IFEND} +{$endif} +{$ifdef darwin} +{$IF Defined(FIXEDFANN)} +const DLL_FILE = 'libfixedfann.2.2.0.dylib'; +{$ELSEIF Defined(DOUBLEFANN)} +const DLL_FILE = 'libdoublefann.2.2.0.dylib'; +{$ELSE} +const DLL_FILE = 'libfloatfann.2.2.0.dylib'; +{$IFEND} +{$endif} + + +type + + {$IF Defined(FIXEDFANN)} + fann_type = integer; + {$ELSEIF Defined(DOUBLEFANN)} + fann_type = double; + {$ELSE} + fann_type = single; + {$IFEND} + + + PFann_Type = ^fann_type; + + PPFann_Type = ^pfann_type; + + Fann_Type_Array = array [0..65535] of fann_type; + + PFann_Type_Array = ^Fann_type_array; + + PPFann_Type_Array = array [0..65535] of ^Fann_Type_Array; + + + + + (* MICROSOFT VC++ STDIO'S FILE DEFINITION*) + _iobuf = packed record + _ptr: Pchar; + _cnt: integer; + _base: Pchar; + _flag: integer; + _file: integer; + _charbuf: integer; + _bufsiz: integer; + _tmpfname: Pchar; + end; + + + PFile = ^TFile; + TFile = _iobuf; + + + PPFann_Neuron = ^PFann_Neuron; + PFann_Neuron = ^TFann_Neuron; + TFann_Neuron = packed record + first_con: Cardinal; + last_con: Cardinal; + sum: fann_type; + value: fann_type; + activation_steepness: fann_type; + activation_function: Cardinal; //enum + end; + + + PFann_Layer = ^TFann_Layer; + TFann_Layer = packed record + first_neuron: PFann_Neuron; + last_neuron: PFann_Neuron; + end; + + PFann = ^TFann; + TFann = packed record + errno_f: cardinal; + error_log: PFile; + errstr: Pchar; + + learning_rate: single; + learning_momentum: single; + connection_rate: single; + + network_type: Cardinal; //ENUM + + first_layer: PFann_Layer; + last_layer: PFann_Layer; + + total_neurons: cardinal; + num_input: cardinal; + num_output: cardinal; + + weights: Pfann_type; + + connections: PPFann_Neuron; + + train_errors: Pfann_type; + + training_algorithm: cardinal; //ENUM + + + {$IFDEF FIXEDFANN} + decimal_point: cardinal; + multiplier: cardinal; + + sigmoid_results: array [0..5] of fann_type; + sigmoid_values: array [0..5] of fann_type; + symmetric_results: array [0..5] of fann_type; + symmetric_values: array [0..5] of fann_type; + + {$ENDIF} + + total_connections: cardinal; + output: pfann_type; + + num_MSE: cardinal; + MSE_value: single; + + num_bit_fail: cardinal; + bit_fail_limit: fann_type; + + train_error_function: cardinal;//enum + train_stop_function: cardinal; //enum + + callback: Pointer; //TFANN_CALLBACK + + user_data: Pointer; + + cascade_output_change_fraction: single; + cascade_output_stagnation_epochs: Cardinal; + cascade_candidate_change_fraction: single; + cascade_candidate_stagnation_epochs: Cardinal; + cascade_best_candidate: Cardinal; + + cascade_candidate_limit: fann_type; + cascade_weight_multiplier: fann_type; + + cascade_max_out_epochs: Cardinal; + cascade_max_cand_epochs: Cardinal; + + cascade_activation_functions: PCardinal; + cascade_activation_functions_count: Cardinal; + + cascade_activation_steepnesses: PFann_Type; + + cascade_activation_steepnesses_count: Cardinal; + cascade_num_candidate_groups: Cardinal; + + cascade_candidate_scores: PFann_Type; + + total_neurons_allocated: Cardinal; + total_connections_allocated: Cardinal; + + + + quickprop_decay: single; + quickprop_mu: single; + + rprop_increase_factor: single; + rprop_decrease_factor: single; + + rprop_delta_min: single; + rprop_delta_max: single; + + rprop_delta_zero: single; + + train_slopes: pfann_type; + + prev_steps: pfann_type; + + prev_train_slopes: pfann_type; + + prev_weights_deltas: pfann_type; + + {$IFNDEF FIXEDFANN} + scale_mean_in: psingle; + scale_deviation_in: psingle; + scale_new_min_in: psingle; + scale_factor_in: psingle; + scale_mean_out: psingle; + scale_deviation_out: psingle; + scale_new_min_out: psingle; + scale_factor_out: psingle; + + {$ENDIF} + end; + + PFann_Train_Data = ^TFann_Train_Data; + TFann_Train_Data = packed record + errno_f: cardinal; + erro_log: PFile; + errstr: Pchar; + num_data: cardinal; + num_input: cardinal; + num_ouput: cardinal; + input: PPFann_Type_Array; + output: PPFann_Type_Array; + end; + + PFann_Connection = ^TFann_Connection; + TFann_Connection = packed record + from_neuron: Cardinal; + to_neuron: Cardinal; + weight: fann_type; + end; + + PFann_Error = ^TFann_Error; + TFann_Error = packed record + errno_f: Cardinal; //Enum + error_log: PFile; + errstr: PChar; + end; + + + //_Fann_Train = + const + + FANN_TRAIN_INCREMENTAL = 0; + FANN_TRAIN_BATCH = 1; + FANN_TRAIN_RPROP = 2; + FANN_TRAIN_QUICKPROP = 3; + + + //_Fann_Error_Func = + + FANN_ERRORFUNC_LINEAR = 0; + FANN_ERRORFUNC_TANH = 1; + + + //_Fann_Activation_Func = + FANN_LINEAR = 0; + FANN_THRESHOLD = 1; + FANN_THRESHOLD_SYMMETRIC = 2; + FANN_SIGMOID = 3; + FANN_SIGMOID_STEPWISE = 4; + FANN_SIGMOID_SYMMETRIC = 5; + FANN_SIGMOID_SYMMETRIC_STEPWISE = 6; + FANN_GAUSSIAN = 7; + FANN_GAUSSIAN_SYMMETRIC = 8; + FANN_GAUSSIAN_STEPWISE = 9; + FANN_ELLIOT = 10; + FANN_ELLIOT_SYMMETRIC = 11; + FANN_LINEAR_PIECE = 12; + FANN_LINEAR_PIECE_SYMMETRIC = 13; + FANN_SIN_SYMMETRIC = 14; + FANN_COS_SYMMETRIC = 15; + FANN_SIN = 16; + FANN_COS = 17; + + + //_Fann_ErroNo = + FANN_E_NO_ERROR = 0; + FANN_E_CANT_OPEN_CONFIG_R = 1; + FANN_E_CANT_OPEN_CONFIG_W = 2; + FANN_E_WRONG_CONFIG_VERSION = 3; + FANN_E_CANT_READ_CONFIG = 4; + FANN_E_CANT_READ_NEURON = 5; + FANN_E_CANT_READ_CONNECTIONS = 6; + FANN_E_WRONG_NUM_CONNECTIONS = 7; + FANN_E_CANT_OPEN_TD_W = 8; + FANN_E_CANT_OPEN_TD_R = 9; + FANN_E_CANT_READ_TD = 10; + FANN_E_CANT_ALLOCATE_MEM = 11; + FANN_E_CANT_TRAIN_ACTIVATION = 12; + FANN_E_CANT_USE_ACTIVATION = 13; + FANN_E_TRAIN_DATA_MISMATCH = 14; + FANN_E_CANT_USE_TRAIN_ALG = 15; + FANN_E_TRAIN_DATA_SUBSET = 16; + FANN_E_INDEX_OUT_OF_BOUND = 17; + FANN_E_SCALE_NOT_PRESENT = 18; + + + //_Fann_Stop_Func = + + FANN_STOPFUNC_MSE = 0; + FANN_STOPFUNC_BIT = 1; + + //_Fann_Net_Type = + FANN_NETTYPE_LAYER = 0; + FANN_NETTYPE_SHORTCUT = 1; + + type + + TFann_CallBack = function(Ann: PFann; + train: PFann_Train_Data; + max_epochs: Cardinal; + epochs_between_reports: cardinal; + desired_error: single; + epochs: cardinal): integer; cdecl; + + TUser_Function = procedure(num: Cardinal; + num_input: Cardinal; + num_output: cardinal; + input: PFann_Type; + output: PFann_Type); cdecl; + + + + +var + FANN_ERRORFUNC_NAMES: array [0..1] of string = ( + 'FANN_ERRORFUNC_LINEAR', + 'FANN_ERRORFUNC_TANH' + ); + + FANN_TRAIN_NAMES: array [0..3] of string = + ( + 'FANN_TRAIN_INCREMENTAL', + 'FANN_TRAIN_BATCH', + 'FANN_TRAIN_RPROP', + 'FANN_TRAIN_QUICKPROP' + ); + + FANN_ACTIVATIONFUNC_NAMES: array [0..17] of string = + ( + 'FANN_LINEAR', + 'FANN_THRESHOLD', + 'FANN_THRESHOLD_SYMMETRIC', + 'FANN_SIGMOID', + 'FANN_SIGMOID_STEPWISE', + 'FANN_SIGMOID_SYMMETRIC', + 'FANN_SIGMOID_SYMMETRIC_STEPWISE', + 'FANN_GAUSSIAN', + 'FANN_GAUSSIAN_SYMMETRIC', + 'FANN_GAUSSIAN_STEPWISE', + 'FANN_ELLIOT', + 'FANN_ELLIOT_SYMMETRIC', + 'FANN_LINEAR_PIECE', + 'FANN_LINEAR_PIECE_SYMMETRIC', + 'FANN_SIN_SYMMETRIC', + 'FANN_COS_SYMMETRIC', + 'FANN_SIN', + 'FANN_COS' + ); + + FANN_STOPFUNC_NAMES: array [0..1] of string = + ( + 'FANN_STOPFUNC_MSE', + 'FANN_STOPFUNC_BIT' + ); + + FANN_NETTYPE_NAMES: array [0..1] of string = + ( + 'FANN_NETTYPE_LAYER', + 'FANN_NETTYPE_SHORTCUT' + ); + + + //DECLARATIONS FROM FANN.H + + {$IFDEF VARIABLE_ARGUMENTS} + + { + + ATTENTION! + If your compilation breaks here maybe you are using a version of Delphi + prior to 6. In this case you should comment the VARIABLE_ARGUMENTS define + at the beginning of this file and live without this functions! + + } + function fann_create_standard(num_layers: Cardinal): PFann; cdecl; varargs; + + function fann_create_sparse(connection_rate: single; num_layers: Cardinal): PFann; cdecl; varargs; + + function fann_create_shortcut(connection_rate: single): PFann; cdecl; varargs; + + + {$ENDIF} + + + function fann_create_standard_array(num_layers: Cardinal; const layers: PCardinal): PFann; cdecl; + + function fann_create_sparse_array(connection_rate: single; num_layers: Cardinal; const layers: PCardinal): PFann; cdecl; + + function fann_create_shortcut_array(num_layers: cardinal;const layers: Pcardinal): PFann; cdecl; + + + procedure fann_destroy(Ann: PFann); cdecl; + + + function fann_run(ann: PFann; input: PFann_Type): Pfann_type_array; cdecl; + + + procedure fann_randomize_weights(Ann: PFann; Min_weight: fann_type; Max_weight: fann_type); cdecl; + + procedure fann_init_weights(Ann: PFann; train_data: PFann_Train_Data); cdecl; + + + procedure fann_print_connections(ann: PFann);cdecl; + + procedure fann_print_parameters(ann: PFann);cdecl; + + + function fann_get_num_input(Ann: PFann): cardinal;cdecl; + + function fann_get_num_output(Ann: PFann): cardinal;cdecl; + + function fann_get_total_neurons(Ann: PFann): cardinal; cdecl; + + function fann_get_total_connections(Ann: PFann): cardinal; cdecl; + + + function fann_get_network_type(Ann: PFann): cardinal; cdecl; + + function fann_get_connection_rate(Ann: PFann): single; cdecl; + + + function fann_get_num_layers(Ann: PFann): cardinal; cdecl; + + + procedure fann_get_layer_array(Ann: PFann; layers: PCardinal); cdecl; + + procedure fann_get_bias_array(Ann: PFann; bias: PCardinal);cdecl; + + + procedure fann_get_connection_array(Ann: PFann; connections: PFann_Connection);cdecl; + + + procedure fann_set_weight_array(Ann: PFann; connections: PFann_Connection; num_connection: Cardinal);cdecl; + + + procedure fann_set_weight(Ann: PFann; from_neuron: Cardinal; to_neuron: Cardinal; weight: fann_type);cdecl; + + procedure fann_set_user_data(Ann: PFann; user_data: Pointer);cdecl; + + function fann_get_user_data(Ann: PFann): Pointer; cdecl; + + + {$IFDEF FIXEDFANN} + + function fann_get_decimal_point(Ann: Pfann): cardinal; cdecl; + + function fann_get_multiplier(Ann: PFann): cardinal;cdecl; + + {$ENDIF} + + //END OF DECLARATIONS FROM FANN.H + + + + //DECLARATIONS FROM FANN_IO.H + + + function fann_create_from_file(const configuration_file: PChar): PFann; cdecl; + + procedure fann_save(Ann: PFann; Const Configuration_File: PChar);cdecl; + + function fann_save_to_fixed(Ann: PFann; Const Configuration_File: PChar): integer;cdecl; + + //END OF DECLARATIONS FROM FANN_IO.H + + + //DECLARATIONS FROM FANN_TRAIN.H + + {$IFNDEF FIXEDFANN} + procedure fann_train(Ann: PFann; Input: PFann_Type; Desired_Output: PFann_Type);cdecl; + {$ENDIF} + + function fann_test(Ann: PFann; Input: PFann_Type; Desired_Output: Pfann_Type): Pfann_type_array;cdecl; + + + function fann_get_MSE(Ann: PFann): single;cdecl; + + function fann_get_bit_fail(Ann: PFann): Cardinal;cdecl; + + procedure fann_reset_MSE(Ann: Pfann); cdecl; + + + {$IFNDEF FIXEDFANN} + + + procedure fann_train_on_data(Ann: PFann; Data: PFann_Train_Data;max_epochs: cardinal;epochs_between_reports: cardinal; desired_error: single);cdecl; + + procedure fann_train_on_file(Ann: PFann; Filename: Pchar;max_epochs: cardinal;epochs_between_reports: cardinal; desired_error: single); cdecl; + + + + function fann_train_epoch(Ann: PFann; data: PFann_Train_Data): single; cdecl; + + + function fann_test_data(Ann: PFann; data: PFann_Train_Data): single; cdecl; + + {$ENDIF} + + function fann_read_train_from_file(const filename: PChar): PFann_Train_Data; cdecl; + + + + function fann_create_train_from_callback(num_data: Cardinal; + num_input: Cardinal; + num_output: Cardinal; + user_function: TUser_Function): PFann_Train_Data; cdecl; + + + + procedure fann_destroy_train(train_data: PFann_Train_Data); cdecl; + + + procedure fann_shuffle_train_data(Train_Data: PFann_Train_Data);cdecl; + + + procedure fann_scale_train(Ann: PFann; data: PFann_Train_Data);cdecl; + + procedure fann_descale_train(Ann: PFann; data: PFann_Train_Data);cdecl; + + + function fann_set_input_scaling_params(Ann: PFann; + const data: PFann_Train_Data; + new_input_min: single; + new_input_max: single): integer;cdecl; + + + function fann_set_output_scaling_params(Ann: PFann; + const data: PFann_Train_Data; + new_output_min: single; + new_output_max: single): integer;cdecl; + + + + function fann_set_scaling_params(Ann: PFann; + const data: PFann_Train_Data; + new_input_min: single; + new_input_max: single; + new_output_min: single; + new_output_max: single): integer; cdecl; + + + function fann_clear_scaling_params(Ann: PFann): integer; cdecl; + + + + procedure fann_scale_input(Ann: PFann; input_vector: PFann_type); cdecl; + + + procedure fann_scale_output(Ann: PFann; output_vector: PFann_type); cdecl; + + + procedure fann_descale_input(Ann: PFann; input_vector: PFann_type); cdecl; + + + procedure fann_descale_output(Ann: PFann; output_vector: PFann_type); cdecl; + + + procedure fann_scale_input_train_data(Train_Data: PFann_Train_Data; + new_min: fann_type; + new_max: fann_type); cdecl; + + + procedure fann_scale_output_train_data(Train_Data: PFann_Train_Data; + new_min: fann_type; + new_max: fann_type); cdecl; + + + procedure fann_scale_train_data(Train_Data: PFann_Train_Data; + new_min: fann_type; + new_max: fann_type); cdecl; + + + function fann_merge_train_data(Data1: PFann_Train_Data; Data2: PFann_Train_Data): PFann_Train_Data; cdecl; + + + function fann_duplicate_train_data(Data: PFann_Train_Data): PFann_Train_Data;cdecl; + + + function fann_subset_train_data(data: PFann_Train_Data; pos: Cardinal; length: Cardinal): PFann_Train_Data; cdecl; + + + function fann_length_train_data(data: PFann_Train_Data): Cardinal; cdecl; + + + function fann_num_input_train_data(data: PFann_Train_Data): Cardinal; cdecl; + + function fann_num_output_train_data(data: PFann_Train_Data): Cardinal; cdecl; + + function fann_save_train(Data: PFann_train_Data; const Filename: PChar): integer;cdecl; + + function fann_save_train_to_fixed(Data: PFann_train_Data; const FileName: Pchar; decimal_point: cardinal): integer;cdecl; + + + + function fann_get_training_algorithm(Ann: Pfann): cardinal;cdecl; + + procedure fann_set_training_algorithm(Ann: PFann; Training_Algorithm: cardinal);cdecl; + + function fann_get_learning_rate(Ann: PFann): single;cdecl; + + procedure fann_set_learning_rate(Ann: PFann; Learning_Rate: Single); cdecl; + + function fann_get_learning_momentum(Ann: PFann): single;cdecl; + + procedure fann_set_learning_momentum(Ann: PFann; learning_momentum: Single); cdecl; + + + + function fann_get_activation_function(Ann: PFann; layer: integer; neuron: integer): Cardinal; cdecl; //ENUM + + procedure fann_set_activation_function(Ann: PFann; activation_function: Cardinal; layer: integer; neuron: integer); cdecl; //ENUM + + + procedure fann_set_activation_function_layer(Ann: PFann; activation_function: Cardinal; layer: integer); cdecl; //ENUM + + + procedure fann_set_activation_function_hidden(Ann: Pfann; Activation_function: cardinal); cdecl; + + procedure fann_set_activation_function_output(Ann: Pfann; Activation_Function: cardinal); cdecl; + + function fann_get_activation_steepness(Ann: PFann; layer: integer; neuron: integer): fann_type; cdecl; + + + procedure fann_set_activation_steepness(Ann: PFann; steepness: fann_type; layer: integer; neuron: integer); cdecl; + + + procedure fann_set_activation_steepness_layer(Ann: PFann; steepness: fann_type; layer: integer); cdecl; + + + procedure fann_set_activation_steepness_hidden(Ann: PFann; steepness: Fann_Type); cdecl; + + procedure fann_set_activation_steepness_output(Ann: PFann; steepness: Fann_Type);cdecl; + + function fann_get_train_error_function(Ann: PFann): cardinal;cdecl; + + procedure fann_set_train_error_function(Ann: PFann; Train_Error_Function: cardinal); cdecl; + + function fann_get_train_stop_function(Ann: PFann): Cardinal; cdecl; + + procedure fann_set_train_stop_function(Ann: PFann; train_stop_function: cardinal); cdecl; + + function fann_get_bit_fail_limit(Ann: PFann): fann_type; cdecl; + + procedure fann_set_bit_fail_limit(Ann: PFann; bit_fail_limit: fann_type); cdecl; + + procedure fann_set_callback(Ann: PFann; callback: TFann_Callback); cdecl; + + function fann_get_quickprop_decay(Ann: PFann): single;cdecl; + + procedure fann_set_quickprop_decay(Ann: Pfann; quickprop_decay: Single);cdecl; + + function fann_get_quickprop_mu(Ann: PFann): single;cdecl; + + procedure fann_set_quickprop_mu(Ann: PFann; Mu: Single);cdecl; + + function fann_get_rprop_increase_factor(Ann: PFann): single;cdecl; + + procedure fann_set_rprop_increase_factor(Ann: PFann;rprop_increase_factor: single);cdecl; + + function fann_get_rprop_decrease_factor(Ann: PFann): single;cdecl; + + procedure fann_set_rprop_decrease_factor(Ann: PFann;rprop_decrease_factor: single); cdecl; + + function fann_get_rprop_delta_min(Ann: PFann): single; cdecl; + + procedure fann_set_rprop_delta_min(Ann: PFann; rprop_delta_min: Single); cdecl; + + function fann_get_rprop_delta_max(Ann: PFann): single;cdecl; + + procedure fann_set_rprop_delta_max(Ann: PFann; rprop_delta_max: Single); cdecl; + + function fann_get_rprop_delta_zero(Ann: PFann): single;cdecl; + + procedure fann_set_rprop_delta_zero(Ann: PFann; rprop_delta_zero: Single); cdecl; + + //END OF DECLARATIONS OF FANN_TRAIN.H + + + //DECLARATIONS OF FANN_ERROR.H + + procedure fann_set_error_log(errdat: PFann_Error; Log_File: PFile);cdecl; + + function fann_get_errno(errdat: PFann_Error): cardinal;cdecl; + + procedure fann_reset_errno(errdat: PFann_Error);cdecl; + + procedure fann_reset_errstr(errdat: PFann_Error);cdecl; + + function fann_get_errstr(errdat: PFann_Error): PChar;cdecl; + + procedure fann_print_error(Errdat: PFann_Error);cdecl; + + + //END OF DECLARATIONS OF FANN_ERROR + + //DECLARATIONS OF FANN_CASCADE.H + + procedure fann_cascadetrain_on_data(Ann: PFann; + data: PFann_Train_Data; + max_neurons: Cardinal; + neurons_between_reports: Cardinal; + desired_error: single); cdecl; + + procedure fann_cascadetrain_on_file(Ann: PFann; + const filename: PChar; + max_neurons: Cardinal; + neurons_between_reports: Cardinal; + desired_error: single); cdecl; + + + function fann_get_cascade_output_change_fraction(Ann: PFann): single; cdecl; + + + procedure fann_set_cascade_output_change_fraction(Ann: PFann; cascade_output_change_fraction: single); cdecl; + + + function fann_get_cascade_output_stagnation_epochs(Ann: PFann): cardinal; cdecl; + + + procedure fann_set_cascade_output_stagnation_epochs(Ann: PFann; cascade_output_stagnation_epochs: cardinal); cdecl; + + + function fann_get_cascade_candidate_change_fraction(Ann: PFann): single; cdecl; + + + procedure fann_set_cascade_candidate_change_fraction(Ann: PFann; cascade_candidate_change_fraction: single); cdecl; + + + function fann_get_cascade_candidate_stagnation_epochs(Ann: PFann): cardinal; cdecl; + + + procedure fann_set_cascade_candidate_stagnation_epochs(Ann: PFann; cascade_candidate_stagnation_epochs: cardinal); cdecl; + + + function fann_get_cascade_weight_multiplier(Ann: PFann): fann_type; cdecl; + + + procedure fann_set_cascade_weight_multiplier(Ann: PFann; cascade_weight_multiplier: fann_type); cdecl; + + + function fann_get_cascade_candidate_limit(Ann: PFann): fann_type; cdecl; + + + procedure fann_set_cascade_candidate_limit(Ann: PFann; cascade_candidate_limit: fann_type); cdecl; + + + + function fann_get_cascade_max_out_epochs(Ann: PFann): cardinal; cdecl; + + + procedure fann_set_cascade_max_out_epochs(Ann: PFann; cascade_max_out_epochs: cardinal); cdecl; + + + function fann_get_cascade_max_cand_epochs(Ann: PFann): cardinal; cdecl; + + + procedure fann_set_cascade_max_cand_epochs(Ann: PFann; cascade_max_cand_epochs: cardinal); cdecl; + + + function fann_get_cascade_num_candidates(Ann: PFann): cardinal; cdecl; + + + function fann_get_cascade_activation_functions_count(Ann: PFann): cardinal; cdecl; + + + + function fann_get_cascade_activation_functions(Ann: PFann): PCardinal; cdecl; + + + procedure fann_set_cascade_activation_functions(Ann: PFann; cascade_activation_functions: PCardinal; cascade_activation_functions_count: Cardinal); cdecl; + + + function fann_get_cascade_activation_steepnesses_count(Ann: PFann): cardinal; cdecl; + + + function fann_get_cascade_activation_steepnesses(Ann: PFann): pfann_type; cdecl; + + procedure fann_set_cascade_activation_steepnesses(Ann: PFann; cascade_activation_steepnesses: PFann_Type; cascade_activation_steepnesses_count: Cardinal); cdecl; + + + function fann_get_cascade_num_candidate_groups(Ann: PFann): cardinal; cdecl; + + + procedure fann_set_cascade_num_candidate_groups(Ann: PFann; cascade_num_candidate_groups: cardinal); cdecl; + + + //END OF DECLARATIONS OF FANN_CASCADE.H + + + +implementation + + + {$IFDEF VARIABLE_ARGUMENTS} + + function fann_create_standard; external DLL_FILE; + + {$ENDIF} + + + function fann_create_standard_array; external DLL_FILE; + + + {$IFDEF VARIABLE_ARGUMENTS} + + function fann_create_sparse; external DLL_FILE; + + {$ENDIF} + + + + function fann_create_sparse_array; external DLL_FILE; + + + + {$IFDEF VARIABLE_ARGUMENTS} + + function fann_create_shortcut; external DLL_FILE; + + {$ENDIF} + + + function fann_create_shortcut_array; external DLL_FILE; + + + procedure fann_destroy; external DLL_FILE; + + + function fann_run; external DLL_FILE; + + + procedure fann_randomize_weights; external DLL_FILE; + + procedure fann_init_weights; external DLL_FILE; + + + procedure fann_print_connections; external DLL_FILE; + + procedure fann_print_parameters; external DLL_FILE; + + + function fann_get_num_input; external DLL_FILE; + + function fann_get_num_output; external DLL_FILE; + + function fann_get_total_neurons; external DLL_FILE; + + function fann_get_total_connections; external DLL_FILE; + + + function fann_get_network_type; external DLL_FILE; + + function fann_get_connection_rate; external DLL_FILE; + + + function fann_get_num_layers; external DLL_FILE; + + + procedure fann_get_layer_array; external DLL_FILE; + + procedure fann_get_bias_array; external DLL_FILE; + + + procedure fann_get_connection_array; external DLL_FILE; + + + procedure fann_set_weight_array; external DLL_FILE; + + + procedure fann_set_weight; external DLL_FILE; + + procedure fann_set_user_data; external DLL_FILE; + + function fann_get_user_data; external DLL_FILE; + + + {$IFDEF FIXEDFANN} + + function fann_get_decimal_point; external DLL_FILE; + + function fann_get_multiplier; external DLL_FILE; + + {$ENDIF} + + //END OF DECLARATIONS FROM FANN.H + + + + //DECLARATIONS FROM FANN_IO.H + + + function fann_create_from_file; external DLL_FILE; + + procedure fann_save; external DLL_FILE; + + function fann_save_to_fixed; external DLL_FILE; + + //END OF DECLARATIONS FROM FANN_IO.H + + + //DECLARATIONS FROM FANN_TRAIN.H + + {$IFNDEF FIXEDFANN} + procedure fann_train; external DLL_FILE; + {$ENDIF} + + function fann_test; external DLL_FILE; + + + function fann_get_MSE; external DLL_FILE; + + function fann_get_bit_fail; external DLL_FILE; + + procedure fann_reset_MSE; external DLL_FILE; + + + {$IFNDEF FIXEDFANN} + + + procedure fann_train_on_data; external DLL_FILE; + + procedure fann_train_on_file; external DLL_FILE; + + + + function fann_train_epoch; external DLL_FILE; + + + function fann_test_data; external DLL_FILE; + + {$ENDIF} + + function fann_read_train_from_file; external DLL_FILE; + + + + function fann_create_train_from_callback; external DLL_FILE; + + + + procedure fann_destroy_train; external DLL_FILE; + + + procedure fann_shuffle_train_data; external DLL_FILE; + + + procedure fann_scale_train; external DLL_FILE; + + procedure fann_descale_train; external DLL_FILE; + + + function fann_set_input_scaling_params; external DLL_FILE; + + + function fann_set_output_scaling_params; external DLL_FILE; + + + + function fann_set_scaling_params; external DLL_FILE; + + + function fann_clear_scaling_params; external DLL_FILE; + + + + procedure fann_scale_input; external DLL_FILE; + + + procedure fann_scale_output; external DLL_FILE; + + + procedure fann_descale_input; external DLL_FILE; + + + procedure fann_descale_output; external DLL_FILE; + + + procedure fann_scale_input_train_data; external DLL_FILE; + + + procedure fann_scale_output_train_data; external DLL_FILE; + + + procedure fann_scale_train_data; external DLL_FILE; + + + function fann_merge_train_data; external DLL_FILE; + + + function fann_duplicate_train_data; external DLL_FILE; + + + function fann_subset_train_data; external DLL_FILE; + + + function fann_length_train_data; external DLL_FILE; + + + function fann_num_input_train_data; external DLL_FILE; + + function fann_num_output_train_data; external DLL_FILE; + + function fann_save_train; external DLL_FILE; + + function fann_save_train_to_fixed; external DLL_FILE; + + + + function fann_get_training_algorithm; external DLL_FILE; + + procedure fann_set_training_algorithm; external DLL_FILE; + + function fann_get_learning_rate; external DLL_FILE; + + procedure fann_set_learning_rate; external DLL_FILE; + + function fann_get_learning_momentum; external DLL_FILE; + + procedure fann_set_learning_momentum; external DLL_FILE; + + + + function fann_get_activation_function; external DLL_FILE; //ENUM + + procedure fann_set_activation_function; external DLL_FILE; //ENUM + + + procedure fann_set_activation_function_layer; external DLL_FILE; //ENUM + + + procedure fann_set_activation_function_hidden; external DLL_FILE; + + procedure fann_set_activation_function_output; external DLL_FILE; + + function fann_get_activation_steepness; external DLL_FILE; + + + procedure fann_set_activation_steepness; external DLL_FILE; + + + procedure fann_set_activation_steepness_layer; external DLL_FILE; + + + procedure fann_set_activation_steepness_hidden; external DLL_FILE; + + procedure fann_set_activation_steepness_output; external DLL_FILE; + + function fann_get_train_error_function; external DLL_FILE; + + procedure fann_set_train_error_function; external DLL_FILE; + + function fann_get_train_stop_function; external DLL_FILE; + + procedure fann_set_train_stop_function; external DLL_FILE; + + function fann_get_bit_fail_limit; external DLL_FILE; + + procedure fann_set_bit_fail_limit; external DLL_FILE; + + procedure fann_set_callback; external DLL_FILE; + + function fann_get_quickprop_decay; external DLL_FILE; + + procedure fann_set_quickprop_decay; external DLL_FILE; + + function fann_get_quickprop_mu; external DLL_FILE; + + procedure fann_set_quickprop_mu; external DLL_FILE; + + function fann_get_rprop_increase_factor; external DLL_FILE; + + procedure fann_set_rprop_increase_factor; external DLL_FILE; + + function fann_get_rprop_decrease_factor; external DLL_FILE; + + procedure fann_set_rprop_decrease_factor; external DLL_FILE; + + function fann_get_rprop_delta_min; external DLL_FILE; + + procedure fann_set_rprop_delta_min; external DLL_FILE; + + function fann_get_rprop_delta_max; external DLL_FILE; + + procedure fann_set_rprop_delta_max; external DLL_FILE; + + function fann_get_rprop_delta_zero; external DLL_FILE; + + procedure fann_set_rprop_delta_zero; external DLL_FILE; + + //END OF DECLARATIONS OF FANN_TRAIN.H + + + //DECLARATIONS OF FANN_ERROR.H + + procedure fann_set_error_log; external DLL_FILE; + + function fann_get_errno; external DLL_FILE; + + procedure fann_reset_errno; external DLL_FILE; + + procedure fann_reset_errstr; external DLL_FILE; + + function fann_get_errstr; external DLL_FILE; + + procedure fann_print_error; external DLL_FILE; + + + //END OF DECLARATIONS OF FANN_ERROR + + //DECLARATIONS OF FANN_CASCADE.H + + procedure fann_cascadetrain_on_data; external DLL_FILE; + + procedure fann_cascadetrain_on_file; external DLL_FILE; + + + function fann_get_cascade_output_change_fraction; external DLL_FILE; + + + procedure fann_set_cascade_output_change_fraction; external DLL_FILE; + + + function fann_get_cascade_output_stagnation_epochs; external DLL_FILE; + + + procedure fann_set_cascade_output_stagnation_epochs; external DLL_FILE; + + + function fann_get_cascade_candidate_change_fraction; external DLL_FILE; + + + procedure fann_set_cascade_candidate_change_fraction; external DLL_FILE; + + + function fann_get_cascade_candidate_stagnation_epochs; external DLL_FILE; + + + procedure fann_set_cascade_candidate_stagnation_epochs; external DLL_FILE; + + + function fann_get_cascade_weight_multiplier; external DLL_FILE; + + + procedure fann_set_cascade_weight_multiplier; external DLL_FILE; + + + function fann_get_cascade_candidate_limit; external DLL_FILE; + + + procedure fann_set_cascade_candidate_limit; external DLL_FILE; + + + + function fann_get_cascade_max_out_epochs; external DLL_FILE; + + + procedure fann_set_cascade_max_out_epochs; external DLL_FILE; + + + function fann_get_cascade_max_cand_epochs; external DLL_FILE; + + + procedure fann_set_cascade_max_cand_epochs; external DLL_FILE; + + + function fann_get_cascade_num_candidates; external DLL_FILE; + + + function fann_get_cascade_activation_functions_count; external DLL_FILE; + + + + function fann_get_cascade_activation_functions; external DLL_FILE; + + + procedure fann_set_cascade_activation_functions; external DLL_FILE; + + + function fann_get_cascade_activation_steepnesses_count; external DLL_FILE; + + + function fann_get_cascade_activation_steepnesses; external DLL_FILE; + + procedure fann_set_cascade_activation_steepnesses; external DLL_FILE; + + + function fann_get_cascade_num_candidate_groups; external DLL_FILE; + + + procedure fann_set_cascade_num_candidate_groups; external DLL_FILE; + + + +end. + diff --git a/Source/Units/hulpfuncties.pas b/Source/Units/hulpfuncties.pas index d61b7bb6..06f08325 100644 --- a/Source/Units/hulpfuncties.pas +++ b/Source/Units/hulpfuncties.pas @@ -2358,7 +2358,7 @@ function GetTaskBarSize: TRect; // {$endif} {$ifdef darwin} sound:= TProcess.Create(NIL); - sound.CommandLine:= 'afplay ' + StartSound; + sound.CommandLine:= 'afplay ' + WarningSound; sound.Execute; sound.Free; {$endif} @@ -2375,9 +2375,9 @@ function GetTaskBarSize: TRect; // {$ifdef linux} // AlSourcePlay(source[alarm]); // {$endif} - {$ifdef darwub} + {$ifdef darwin} sound:= TProcess.Create(NIL); - sound.CommandLine:= 'afplay ' + StartSound; + sound.CommandLine:= 'afplay ' + AlarmSound; sound.Execute; sound.Free; {$endif} @@ -2396,7 +2396,7 @@ function GetTaskBarSize: TRect; // {$endif} {$ifdef darwin} sound:= TProcess.Create(NIL); - sound.CommandLine:= 'afplay ' + StartSound; + sound.CommandLine:= 'afplay ' + EndSound; sound.Execute; sound.Free; {$endif} diff --git a/Source/UserInterface/Forms/backup/frrestoredatabases.pas b/Source/UserInterface/Forms/backup/frrestoredatabases.pas new file mode 100644 index 00000000..6c648d50 --- /dev/null +++ b/Source/UserInterface/Forms/backup/frrestoredatabases.pas @@ -0,0 +1,102 @@ +unit frrestoredatabases; + +{$mode objfpc}{$H+} + +interface + +uses + Classes, SysUtils, FileUtil, Forms, Controls, Graphics, Dialogs, Buttons, + ExtCtrls, StdCtrls; + +type + + { TfrmRestoreDatabase } + + TfrmRestoreDatabase = class(TForm) + bbOK: TBitBtn; + bbCancel: TBitBtn; + cgDatabases: TCheckGroup; + cbAll: TCheckBox; + procedure cbAllChange(Sender: TObject); + private + { private declarations } + public + { public declarations } + Function Execute : boolean; + end; + +var + frmRestoreDatabase: TfrmRestoreDatabase; + +implementation + +{$R *.lfm} +uses Containers, Data, Hulpfuncties; + +procedure TfrmRestoreDatabase.cbAllChange(Sender: TObject); +var i : integer; +begin + for i:= 0 to cgDatabases.Items.Count - 1 do + cgDatabases.Checked[i]:= cbAll.Checked; +end; + +Function TfrmRestoreDatabase.Execute : boolean; + function CheckCopyFile(sd, dd, fn : string) : boolean; + begin + Result:= false; + if FileExists(sd + fn) then + result:= CopyFile(sd + fn, dd + fn); + end; +var sourcedata, destdata : string; +begin + Settings.Style.SetControlsStyle(self); +// SetFontHeight(self, Settings.FontHeight.Value); + Result:= (showmodal = mrOK); + if Result then + if Question(self, 'Weet je zeker dat je de databanken wilt overschrijven?') then + begin + Screen.Cursor:= crHourglass; + Backup; + {$ifdef linux} + sourcedata:= '/usr/share/brewbuddy/'; + {$endif} + {$ifdef Darwin} + sourcedata:= '/usr/share/brewbuddy/'; + {$endif} + {$ifdef Windows} + sourcedata:= ExtractFilePath(Application.ExeName) + 'brewbuddy\'; + {$endif} + destdata:= Settings.DataLocation.Value; + if cgDatabases.Checked[0] then + if CheckCopyFile(sourcedata, destdata, 'fermentables.xml') then + Fermentables.ReadXML; + if cgDatabases.Checked[1] then + if CheckCopyFile(sourcedata, destdata, 'hops.xml') then + Hops.ReadXML; + if cgDatabases.Checked[2] then + if CheckCopyFile(sourcedata, destdata, 'yeasts.xml') then + Yeasts.ReadXML; + if cgDatabases.Checked[3] then + if CheckCopyFile(sourcedata, destdata, 'miscs.xml') then + Miscs.ReadXML; + if cgDatabases.Checked[4] then + if CheckCopyFile(sourcedata, destdata, 'mashs.xml') then + Mashs.ReadXML; + if cgDatabases.Checked[5] then + if CheckCopyFile(sourcedata, destdata, 'waters.xml') then + Waters.ReadXML; + if cgDatabases.Checked[6] then + if CheckCopyFile(sourcedata, destdata, 'styles.xml') then + Beerstyles.ReadXML; + if cgDatabases.Checked[7] then + if CheckCopyFile(sourcedata, destdata, 'equipments.xml') then + Equipments.ReadXML; + if cgDatabases.Checked[8] then + if CheckCopyFile(sourcedata, destdata, 'recipes.xml') then + Recipes.ReadXML; + Screen.Cursor:= crDefault; + end; +end; + +end. + diff --git a/Source/UserInterface/Forms/frrestoredatabases.pas b/Source/UserInterface/Forms/frrestoredatabases.pas index 32dae37e..83654ed7 100644 --- a/Source/UserInterface/Forms/frrestoredatabases.pas +++ b/Source/UserInterface/Forms/frrestoredatabases.pas @@ -57,9 +57,12 @@ procedure TfrmRestoreDatabase.cbAllChange(Sender: TObject); begin Screen.Cursor:= crHourglass; Backup; - {$ifdef UNIX} + {$ifdef linux} sourcedata:= '/usr/share/brewbuddy/'; {$endif} + {$ifdef Darwin} + sourcedata:= ProgramDirectory() + 'BrewBuddy.app/Contents/Resources/'; + {$endif} {$ifdef Windows} sourcedata:= ExtractFilePath(Application.ExeName) + 'brewbuddy\'; {$endif} diff --git a/Source/backup/brewbuddy.pas b/Source/backup/brewbuddy.pas new file mode 100644 index 00000000..062ff8fd --- /dev/null +++ b/Source/backup/brewbuddy.pas @@ -0,0 +1,51 @@ +program brewbuddy; + +{$mode objfpc}{$H+} + +uses + {$IFDEF UNIX}{$IFDEF UseCThreads} + cthreads, + {$ENDIF}{$ENDIF} + {$ifdef UNIX} + clocale, + {$endif} + SysUtils, Interfaces, // this includes the LCL widgetset + printer4lazarus, tachartprint, Forms, FrMain, Data, subs, Hulpfuncties, + Containers, FrBeerstyles, FrHop2, frQuestion, frgetstring, FrEquipments, + FrFermentables2, FrMiscs2, frmashs, FrYeasts2, FrWaters, frmashstep, + FrFermentables, PositieInterval, FrHop, FrMiscs, FrYeasts, frmiscs3, + frfermentables3, frhop3, frwateradjustment, FrNotification, TimeEdit, + frmeasurements, frimport, frselectbeerstyle, frrecipetobrew, BH_report, + frprintpreview, BHprintforms, frpropagation, frrefractometer, frboilmethod, + fdatabaselocation, utypes, umulfit, frdividebrew, fryeasts3, + frchoosebeerstyle, frchoosebrewschars, frsplash, frinfo, vinfo, frsynchronize, + frchoosebrews, PromashImport, laz_synapse, frrestoredatabases, frsettings, + cloud, frgetpasswd, frdownloadprogress, pexpandpanels, uniqueinstance_package;//, neuroot; + +{$R *.res} + +begin + Application.Title:='BrewBuddy'; + try + Application.Initialize; + Application.CreateForm(TfrmMain, frmMain); + Application.Run; + except + {if CloudActive then} FreeAndNIL(BHCloud); + FreeAndNIL(StyleSubs); + FreeAndNIL(FermentableSubs); + FreeAndNIL(YeastSubs); + FreeAndNIL(Fermentables); + FreeAndNIL(Hops); + FreeAndNIL(Miscs); + FreeAndNIL(Yeasts); + FreeAndNIL(Waters); + FreeAndNIL(Equipments); + FreeAndNIL(Beerstyles); + FreeAndNIL(Mashs); + FreeAndNIL(Recipes); + FreeAndNIL(Brews); + FreeAndNIL(Settings); + end; +end. + diff --git a/Source/backup/brewbuddy_osx.lpi b/Source/backup/brewbuddy_osx.lpi new file mode 100644 index 00000000..572ca2bf --- /dev/null +++ b/Source/backup/brewbuddy_osx.lpi @@ -0,0 +1,1846 @@ + + + + + + + + + <ResourceType Value="res"/> + </General> + <i18n> + <EnableI18N LFM="False"/> + </i18n> + <VersionInfo> + <UseVersionInfo Value="True"/> + <MajorVersionNr Value="5"/> + <MinorVersionNr Value="4"/> + <Language Value="0413"/> + <StringTable CompanyName="Brouwerij Het Witte Paard" FileDescription="BrewBuddy Sassy Saison" InternalName="BrewBuddy" OriginalFilename="BrewBuddy" ProductName="BrewBuddy" ProductVersion="5.3.5.2"/> + </VersionInfo> + <MacroValues Count="1"> + <Macro1 Name="LCLWidgetType" Value="cocoa"/> + </MacroValues> + <BuildModes Count="1" Active="Default"> + <Item1 Name="Default" Default="True"/> + <SharedMatrixOptions Count="1"> + <Item1 ID="090156190409" Modes="Default" Type="IDEMacro" MacroName="LCLWidgetType" Value="cocoa"/> + </SharedMatrixOptions> + </BuildModes> + <PublishOptions> + <Version Value="2"/> + </PublishOptions> + <RunParams> + <FormatVersion Value="2"/> + <Modes Count="1"> + <Mode0 Name="default"/> + </Modes> + </RunParams> + <RequiredPackages Count="9"> + <Item1> + <PackageName Value="TAChartPrint"/> + </Item1> + <Item2> + <PackageName Value="Pexpandpanels"/> + </Item2> + <Item3> + <PackageName Value="uniqueinstance_package"/> + </Item3> + <Item4> + <PackageName Value="SynEdit"/> + <MinVersion Major="1" Valid="True"/> + </Item4> + <Item5> + <PackageName Value="laz_synapse"/> + <MinVersion Valid="True"/> + </Item5> + <Item6> + <PackageName Value="printers4lazide"/> + </Item6> + <Item7> + <PackageName Value="Printer4Lazarus"/> + </Item7> + <Item8> + <PackageName Value="TAChartLazarusPkg"/> + <MinVersion Major="1" Valid="True"/> + </Item8> + <Item9> + <PackageName Value="LCL"/> + </Item9> + </RequiredPackages> + <Units Count="209"> + <Unit0> + <Filename Value="brewbuddy.pas"/> + <IsPartOfProject Value="True"/> + <IsVisibleTab Value="True"/> + <EditorIndex Value="4"/> + <CursorPos X="50" Y="7"/> + <UsageCount Value="201"/> + <Loaded Value="True"/> + </Unit0> + <Unit1> + <Filename Value="UserInterface/Forms/frmain.pas"/> + <IsPartOfProject Value="True"/> + <ComponentName Value="frmMain"/> + <HasResources Value="True"/> + <ResourceBaseClass Value="Form"/> + <UnitName Value="FrMain"/> + <EditorIndex Value="7"/> + <TopLine Value="3534"/> + <CursorPos X="72" Y="3538"/> + <UsageCount Value="201"/> + <Loaded Value="True"/> + </Unit1> + <Unit2> + <Filename Value="Units/data.pas"/> + <IsPartOfProject Value="True"/> + <UnitName Value="Data"/> + <EditorIndex Value="-1"/> + <CursorPos X="58" Y="28"/> + <UsageCount Value="201"/> + </Unit2> + <Unit3> + <Filename Value="/usr/lib/lazarus/0.9.30/ide/lazarus.pp"/> + <UnitName Value="Lazarus"/> + <UsageCount Value="2"/> + </Unit3> + <Unit4> + <Filename Value="/usr/lib/lazarus/0.9.30/lcl/lconvencoding.pas"/> + <UnitName Value="LConvEncoding"/> + <TopLine Value="13"/> + <CursorPos X="24" Y="27"/> + <UsageCount Value="2"/> + </Unit4> + <Unit5> + <Filename Value="/usr/lib/lazarus/0.9.30/ide/ideinfodlg.pas"/> + <UnitName Value="IDEInfoDlg"/> + <TopLine Value="19"/> + <UsageCount Value="2"/> + </Unit5> + <Unit6> + <Filename Value="../lazarus/0.9.30/ide/lazarus.pp"/> + <UnitName Value="Lazarus"/> + <UsageCount Value="2"/> + </Unit6> + <Unit7> + <Filename Value="/usr/lib/lazarus/0.9.30/ide/idecmdline.pas"/> + <UnitName Value="IDECmdLine"/> + <UsageCount Value="2"/> + </Unit7> + <Unit8> + <Filename Value="/usr/lib/lazarus/0.9.30/debugger/gdbmidebugger.pp"/> + <UnitName Value="GDBMIDebugger"/> + <TopLine Value="9582"/> + <CursorPos X="7" Y="9596"/> + <UsageCount Value="2"/> + </Unit8> + <Unit9> + <Filename Value="/usr/lib/lazarus/0.9.30/converter/convertdelphi.pas"/> + <UnitName Value="ConvertDelphi"/> + <TopLine Value="803"/> + <CursorPos X="28" Y="817"/> + <UsageCount Value="2"/> + </Unit9> + <Unit10> + <Filename Value="/usr/lib/lazarus/0.9.30/ide/lazconf.pp"/> + <UnitName Value="LazConf"/> + <UsageCount Value="2"/> + </Unit10> + <Unit11> + <Filename Value="Units/hulpfuncties.pas"/> + <IsPartOfProject Value="True"/> + <UnitName Value="Hulpfuncties"/> + <EditorIndex Value="2"/> + <CursorPos X="15" Y="7"/> + <UsageCount Value="201"/> + <Loaded Value="True"/> + </Unit11> + <Unit12> + <Filename Value="lnet/lazaruspackage/lnetbase.pas"/> + <UsageCount Value="3"/> + </Unit12> + <Unit13> + <Filename Value="Units/containers.pas"/> + <IsPartOfProject Value="True"/> + <UnitName Value="Containers"/> + <TopLine Value="3055"/> + <CursorPos X="74" Y="3066"/> + <UsageCount Value="200"/> + <Loaded Value="True"/> + </Unit13> + <Unit14> + <Filename Value="appsettings.pas"/> + <CursorPos Y="131"/> + <UsageCount Value="3"/> + </Unit14> + <Unit15> + <Filename Value="icetabset.pas"/> + <UnitName Value="IceTabSet"/> + <TopLine Value="42"/> + <CursorPos X="22" Y="55"/> + <UsageCount Value="2"/> + </Unit15> + <Unit16> + <Filename Value="ovctable.pas"/> + <TopLine Value="21"/> + <CursorPos X="2" Y="34"/> + <UsageCount Value="2"/> + </Unit16> + <Unit17> + <Filename Value="ovccmd.pas"/> + <TopLine Value="698"/> + <CursorPos X="49" Y="711"/> + <UsageCount Value="2"/> + </Unit17> + <Unit18> + <Filename Value="/usr/lib/lazarus/0.9.30.4/ide/lazconf.pp"/> + <UnitName Value="LazConf"/> + <UsageCount Value="6"/> + </Unit18> + <Unit19> + <Filename Value="/usr/lib/lazarus/0.9.30.4/ideintf/actionseditor.pas"/> + <ComponentName Value="ActionListEditor"/> + <HasResources Value="True"/> + <ResourceBaseClass Value="Form"/> + <UnitName Value="ActionsEditor"/> + <TopLine Value="20"/> + <CursorPos X="22" Y="33"/> + <UsageCount Value="6"/> + </Unit19> + <Unit20> + <Filename Value="UserInterface/Forms/frbeerstyles.pas"/> + <IsPartOfProject Value="True"/> + <ComponentName Value="FrmBeerstyles"/> + <HasResources Value="True"/> + <ResourceBaseClass Value="Form"/> + <UnitName Value="FrBeerstyles"/> + <EditorIndex Value="-1"/> + <TopLine Value="108"/> + <CursorPos Y="120"/> + <UsageCount Value="201"/> + </Unit20> + <Unit21> + <Filename Value="/usr/lib/lazarus/0.9.30.4/lcl/include/customlistbox.inc"/> + <TopLine Value="453"/> + <CursorPos Y="466"/> + <UsageCount Value="2"/> + </Unit21> + <Unit22> + <Filename Value="/usr/lib/lazarus/0.9.30.4/lcl/include/control.inc"/> + <TopLine Value="2775"/> + <CursorPos Y="2788"/> + <UsageCount Value="8"/> + </Unit22> + <Unit23> + <Filename Value="/usr/lib/lazarus/0.9.30.4/lcl/include/buttoncontrol.inc"/> + <TopLine Value="50"/> + <CursorPos Y="63"/> + <UsageCount Value="2"/> + </Unit23> + <Unit24> + <Filename Value="/usr/lib/lazarus/0.9.30.4/lcl/include/buttons.inc"/> + <TopLine Value="162"/> + <CursorPos Y="175"/> + <UsageCount Value="2"/> + </Unit24> + <Unit25> + <Filename Value="/usr/lib/lazarus/0.9.30.4/lcl/include/bitbtn.inc"/> + <TopLine Value="45"/> + <CursorPos Y="58"/> + <UsageCount Value="2"/> + </Unit25> + <Unit26> + <Filename Value="UserInterface/Forms/frhop2.pas"/> + <IsPartOfProject Value="True"/> + <ComponentName Value="FrmHop2"/> + <HasResources Value="True"/> + <ResourceBaseClass Value="Form"/> + <UnitName Value="FrHop2"/> + <EditorIndex Value="-1"/> + <TopLine Value="94"/> + <CursorPos X="17" Y="125"/> + <UsageCount Value="202"/> + </Unit26> + <Unit27> + <Filename Value="UserInterface/Forms/frquestion.pas"/> + <IsPartOfProject Value="True"/> + <ComponentName Value="FrmQuestion"/> + <HasResources Value="True"/> + <ResourceBaseClass Value="Form"/> + <UnitName Value="frQuestion"/> + <EditorIndex Value="-1"/> + <TopLine Value="7"/> + <CursorPos X="31" Y="39"/> + <UsageCount Value="200"/> + </Unit27> + <Unit28> + <Filename Value="UserInterface/Forms/frgetstring.pas"/> + <IsPartOfProject Value="True"/> + <ComponentName Value="FrmGetString"/> + <HasResources Value="True"/> + <ResourceBaseClass Value="Form"/> + <EditorIndex Value="-1"/> + <TopLine Value="10"/> + <CursorPos Y="47"/> + <UsageCount Value="200"/> + </Unit28> + <Unit29> + <Filename Value="UserInterface/Forms/frequipments.pas"/> + <IsPartOfProject Value="True"/> + <ComponentName Value="FrmEquipments"/> + <HasResources Value="True"/> + <ResourceBaseClass Value="Form"/> + <UnitName Value="FrEquipments"/> + <EditorIndex Value="-1"/> + <TopLine Value="104"/> + <CursorPos Y="120"/> + <UsageCount Value="200"/> + </Unit29> + <Unit30> + <Filename Value="UserInterface/Forms/frfermentables2.pas"/> + <IsPartOfProject Value="True"/> + <ComponentName Value="FrmFermentables2"/> + <HasResources Value="True"/> + <ResourceBaseClass Value="Form"/> + <UnitName Value="FrFermentables2"/> + <EditorIndex Value="-1"/> + <TopLine Value="134"/> + <CursorPos Y="161"/> + <UsageCount Value="201"/> + </Unit30> + <Unit31> + <Filename Value="UserInterface/Forms/frmiscs2.pas"/> + <IsPartOfProject Value="True"/> + <ComponentName Value="FrmMiscs2"/> + <HasResources Value="True"/> + <ResourceBaseClass Value="Form"/> + <UnitName Value="FrMiscs2"/> + <EditorIndex Value="-1"/> + <TopLine Value="106"/> + <CursorPos Y="146"/> + <UsageCount Value="200"/> + </Unit31> + <Unit32> + <Filename Value="UserInterface/Forms/frmashs.pas"/> + <IsPartOfProject Value="True"/> + <ComponentName Value="FrmMashs"/> + <HasResources Value="True"/> + <ResourceBaseClass Value="Form"/> + <EditorIndex Value="-1"/> + <TopLine Value="47"/> + <CursorPos Y="72"/> + <UsageCount Value="201"/> + </Unit32> + <Unit33> + <Filename Value="UserInterface/Forms/fryeasts2.pas"/> + <IsPartOfProject Value="True"/> + <ComponentName Value="FrmYeasts2"/> + <HasResources Value="True"/> + <ResourceBaseClass Value="Form"/> + <UnitName Value="FrYeasts2"/> + <EditorIndex Value="-1"/> + <TopLine Value="126"/> + <CursorPos X="39" Y="146"/> + <UsageCount Value="200"/> + </Unit33> + <Unit34> + <Filename Value="/usr/lib/lazarus/0.9.30.4/lcl/interfaces/gtk2/gtk2wscontrols.pp"/> + <UnitName Value="Gtk2WSControls"/> + <TopLine Value="293"/> + <CursorPos Y="306"/> + <UsageCount Value="6"/> + </Unit34> + <Unit35> + <Filename Value="UserInterface/Forms/frwaters.pas"/> + <IsPartOfProject Value="True"/> + <ComponentName Value="FrmWaters"/> + <HasResources Value="True"/> + <ResourceBaseClass Value="Form"/> + <UnitName Value="FrWaters"/> + <EditorIndex Value="-1"/> + <TopLine Value="82"/> + <CursorPos Y="106"/> + <UsageCount Value="200"/> + </Unit35> + <Unit36> + <Filename Value="UserInterface/Forms/frmashstep.pas"/> + <IsPartOfProject Value="True"/> + <ComponentName Value="FrmMashStep"/> + <HasResources Value="True"/> + <ResourceBaseClass Value="Form"/> + <EditorIndex Value="-1"/> + <TopLine Value="52"/> + <CursorPos Y="89"/> + <UsageCount Value="201"/> + </Unit36> + <Unit37> + <Filename Value="/usr/lib/lazarus/0.9.30.4/lcl/grids.pas"/> + <UnitName Value="Grids"/> + <TopLine Value="8206"/> + <CursorPos Y="8219"/> + <UsageCount Value="5"/> + </Unit37> + <Unit38> + <Filename Value="UserInterface/Forms/frfermentables.pas"/> + <IsPartOfProject Value="True"/> + <ComponentName Value="FrmFermentables"/> + <HasResources Value="True"/> + <ResourceBaseClass Value="Form"/> + <UnitName Value="FrFermentables"/> + <EditorIndex Value="-1"/> + <TopLine Value="129"/> + <CursorPos Y="135"/> + <UsageCount Value="200"/> + </Unit38> + <Unit39> + <Filename Value="Units/positieinterval.pas"/> + <IsPartOfProject Value="True"/> + <UnitName Value="PositieInterval"/> + <EditorIndex Value="-1"/> + <TopLine Value="6"/> + <CursorPos X="5" Y="648"/> + <UsageCount Value="200"/> + </Unit39> + <Unit40> + <Filename Value="UserInterface/Forms/frhop.pas"/> + <IsPartOfProject Value="True"/> + <ComponentName Value="FrmHop"/> + <HasResources Value="True"/> + <ResourceBaseClass Value="Form"/> + <UnitName Value="FrHop"/> + <EditorIndex Value="-1"/> + <TopLine Value="112"/> + <CursorPos Y="137"/> + <UsageCount Value="200"/> + </Unit40> + <Unit41> + <Filename Value="UserInterface/Forms/frmiscs.pas"/> + <IsPartOfProject Value="True"/> + <ComponentName Value="FrmMiscs"/> + <HasResources Value="True"/> + <ResourceBaseClass Value="Form"/> + <UnitName Value="FrMiscs"/> + <EditorIndex Value="-1"/> + <TopLine Value="74"/> + <CursorPos Y="97"/> + <UsageCount Value="200"/> + </Unit41> + <Unit42> + <Filename Value="UserInterface/Forms/fryeasts.pas"/> + <IsPartOfProject Value="True"/> + <ComponentName Value="FrmYeasts"/> + <HasResources Value="True"/> + <ResourceBaseClass Value="Form"/> + <UnitName Value="FrYeasts"/> + <EditorIndex Value="-1"/> + <TopLine Value="93"/> + <CursorPos Y="119"/> + <UsageCount Value="200"/> + </Unit42> + <Unit43> + <Filename Value="UserInterface/Forms/frmiscs3.pas"/> + <IsPartOfProject Value="True"/> + <ComponentName Value="FrmMiscs3"/> + <HasResources Value="True"/> + <ResourceBaseClass Value="Form"/> + <EditorIndex Value="-1"/> + <TopLine Value="160"/> + <CursorPos X="28" Y="183"/> + <UsageCount Value="200"/> + </Unit43> + <Unit44> + <Filename Value="/usr/lib/lazarus/0.9.30.4/lcl/include/headercontrol.inc"/> + <TopLine Value="384"/> + <CursorPos Y="416"/> + <UsageCount Value="2"/> + </Unit44> + <Unit45> + <Filename Value="UserInterface/Forms/frfermentables3.pas"/> + <IsPartOfProject Value="True"/> + <ComponentName Value="FrmFermentables3"/> + <HasResources Value="True"/> + <ResourceBaseClass Value="Form"/> + <EditorIndex Value="-1"/> + <TopLine Value="230"/> + <CursorPos X="76" Y="240"/> + <UsageCount Value="200"/> + </Unit45> + <Unit46> + <Filename Value="UserInterface/Forms/frhop3.pas"/> + <IsPartOfProject Value="True"/> + <ComponentName Value="FrmHop3"/> + <HasResources Value="True"/> + <ResourceBaseClass Value="Form"/> + <EditorIndex Value="-1"/> + <TopLine Value="146"/> + <CursorPos X="5" Y="149"/> + <UsageCount Value="200"/> + </Unit46> + <Unit47> + <Filename Value="/usr/lib/lazarus/0.9.30.4/lcl/interfaces/qt/qtwscontrols.pp"/> + <UnitName Value="QtWSControls"/> + <TopLine Value="281"/> + <CursorPos Y="295"/> + <UsageCount Value="3"/> + </Unit47> + <Unit48> + <Filename Value="UserInterface/Forms/frwateradjustment.pas"/> + <IsPartOfProject Value="True"/> + <ComponentName Value="FrmWaterAdjustment"/> + <HasResources Value="True"/> + <ResourceBaseClass Value="Form"/> + <EditorIndex Value="-1"/> + <TopLine Value="826"/> + <CursorPos X="59" Y="866"/> + <UsageCount Value="200"/> + </Unit48> + <Unit49> + <Filename Value="UserInterface/Forms/frnotification.pas"/> + <IsPartOfProject Value="True"/> + <ComponentName Value="FrmNotification"/> + <HasResources Value="True"/> + <ResourceBaseClass Value="Form"/> + <UnitName Value="FrNotification"/> + <EditorIndex Value="-1"/> + <TopLine Value="43"/> + <CursorPos X="3" Y="45"/> + <UsageCount Value="200"/> + </Unit49> + <Unit50> + <Filename Value="acs_lame.pas"/> + <TopLine Value="10"/> + <UsageCount Value="158"/> + </Unit50> + <Unit51> + <Filename Value="/usr/lib/lazarus/0.9.30.4/lcl/include/customedit.inc"/> + <TopLine Value="500"/> + <CursorPos Y="513"/> + <UsageCount Value="8"/> + </Unit51> + <Unit52> + <Filename Value="ttimeedit.pas"/> + <TopLine Value="376"/> + <UsageCount Value="2"/> + </Unit52> + <Unit53> + <Filename Value="rxtimeedit.pas"/> + <UnitName Value="RxTimeEdit"/> + <TopLine Value="66"/> + <CursorPos X="2" Y="34"/> + <UsageCount Value="196"/> + </Unit53> + <Unit54> + <Filename Value="rxspin.pas"/> + <TopLine Value="957"/> + <CursorPos X="4" Y="981"/> + <UsageCount Value="2"/> + </Unit54> + <Unit55> + <Filename Value="../Software/Lazarus/Componenten/FortesReport/rlreg.pas"/> + <UnitName Value="RLReg"/> + <UsageCount Value="2"/> + </Unit55> + <Unit56> + <Filename Value="UserInterface/Forms/frmeasurements.pas"/> + <IsPartOfProject Value="True"/> + <ComponentName Value="frmMeasurements"/> + <HasResources Value="True"/> + <ResourceBaseClass Value="Form"/> + <EditorIndex Value="-1"/> + <TopLine Value="216"/> + <CursorPos Y="216"/> + <UsageCount Value="201"/> + </Unit56> + <Unit57> + <Filename Value="graph.pas"/> + <UnitName Value="ASGraph"/> + <CursorPos Y="98"/> + <UsageCount Value="7"/> + </Unit57> + <Unit58> + <Filename Value="brewbuddygraph.pas"/> + <UnitName Value="BrewBuddyGraph"/> + <TopLine Value="449"/> + <CursorPos X="81" Y="463"/> + <UsageCount Value="196"/> + </Unit58> + <Unit59> + <Filename Value="PrintDialog.pas"/> + <ComponentName Value="PrinterForm"/> + <HasResources Value="True"/> + <ResourceBaseClass Value="Form"/> + <CursorPos X="15" Y="13"/> + <UsageCount Value="7"/> + </Unit59> + <Unit60> + <Filename Value="/usr/lib/lazarus/0.9.30.4/components/printers/printer4lazarus.pas"/> + <UnitName Value="Printer4Lazarus"/> + <CursorPos X="29" Y="10"/> + <UsageCount Value="6"/> + </Unit60> + <Unit61> + <Filename Value="/usr/lib/lazarus/0.9.30.4/components/printers/design/ideprinting.pas"/> + <UsageCount Value="6"/> + </Unit61> + <Unit62> + <Filename Value="/usr/lib/lazarus/0.9.30.4/components/lazcontrols/extendednotebook.pas"/> + <UnitName Value="ExtendedNotebook"/> + <UsageCount Value="6"/> + </Unit62> + <Unit63> + <Filename Value="/usr/lib/lazarus/0.9.30.4/ide/lazarus.pp"/> + <UnitName Value="Lazarus"/> + <UsageCount Value="6"/> + </Unit63> + <Unit64> + <Filename Value="/usr/lib/lazarus/0.9.30.4/lcl/include/customcheckbox.inc"/> + <TopLine Value="141"/> + <CursorPos Y="153"/> + <UsageCount Value="2"/> + </Unit64> + <Unit65> + <Filename Value="UserInterface/Forms/frimport.pas"/> + <IsPartOfProject Value="True"/> + <ComponentName Value="FrmImport"/> + <HasResources Value="True"/> + <ResourceBaseClass Value="Form"/> + <EditorIndex Value="-1"/> + <TopLine Value="103"/> + <CursorPos Y="142"/> + <UsageCount Value="200"/> + </Unit65> + <Unit66> + <Filename Value="filefind.pas"/> + <UnitName Value="FileFind"/> + <TopLine Value="151"/> + <CursorPos Y="221"/> + <UsageCount Value="7"/> + </Unit66> + <Unit67> + <Filename Value="UserInterface/Forms/frselectbeerstyle.pas"/> + <IsPartOfProject Value="True"/> + <ComponentName Value="FrmSelectBeerStyle"/> + <HasResources Value="True"/> + <ResourceBaseClass Value="Form"/> + <EditorIndex Value="-1"/> + <TopLine Value="27"/> + <CursorPos X="21" Y="62"/> + <UsageCount Value="200"/> + </Unit67> + <Unit68> + <Filename Value="promashimport.pas"/> + <UnitName Value="PromashImport"/> + <TopLine Value="1992"/> + <CursorPos X="17" Y="2005"/> + <UsageCount Value="5"/> + </Unit68> + <Unit69> + <Filename Value="/usr/lib/lazarus/0.9.30.4/lcl/interfaces/qt/qtobject.inc"/> + <TopLine Value="243"/> + <CursorPos Y="256"/> + <UsageCount Value="5"/> + </Unit69> + <Unit70> + <Filename Value="UserInterface/Forms/frrecipetobrew.pas"/> + <IsPartOfProject Value="True"/> + <ComponentName Value="frmRecipeToBrew"/> + <HasResources Value="True"/> + <ResourceBaseClass Value="Form"/> + <EditorIndex Value="-1"/> + <TopLine Value="73"/> + <CursorPos X="8" Y="106"/> + <UsageCount Value="200"/> + </Unit70> + <Unit71> + <Filename Value="Units/bh_report.pas"/> + <IsPartOfProject Value="True"/> + <UnitName Value="BH_report"/> + <EditorIndex Value="1"/> + <TopLine Value="983"/> + <CursorPos X="31" Y="1007"/> + <UsageCount Value="200"/> + <Loaded Value="True"/> + </Unit71> + <Unit72> + <Filename Value="UserInterface/Forms/frprintpreview.pas"/> + <IsPartOfProject Value="True"/> + <ComponentName Value="FrmPrintPreview"/> + <HasResources Value="True"/> + <ResourceBaseClass Value="Form"/> + <EditorIndex Value="-1"/> + <TopLine Value="71"/> + <CursorPos Y="71"/> + <UsageCount Value="201"/> + </Unit72> + <Unit73> + <Filename Value="Units/bhprintforms.pas"/> + <IsPartOfProject Value="True"/> + <UnitName Value="BHprintforms"/> + <EditorIndex Value="-1"/> + <TopLine Value="680"/> + <CursorPos X="9" Y="694"/> + <UsageCount Value="200"/> + </Unit73> + <Unit74> + <Filename Value="/usr/lib/lazarus/0.9.30.4/lcl/include/font.inc"/> + <TopLine Value="796"/> + <CursorPos Y="810"/> + <UsageCount Value="3"/> + </Unit74> + <Unit75> + <Filename Value="/usr/lib/lazarus/0.9.30.4/lcl/include/rasterimage.inc"/> + <TopLine Value="292"/> + <CursorPos Y="308"/> + <UsageCount Value="3"/> + </Unit75> + <Unit76> + <Filename Value="etiket.pas"/> + <UnitName Value="Etiket"/> + <TopLine Value="977"/> + <CursorPos Y="1000"/> + <UsageCount Value="197"/> + </Unit76> + <Unit77> + <Filename Value="etiketlabel.pas"/> + <UnitName Value="EtiketLabel"/> + <TopLine Value="575"/> + <CursorPos Y="587"/> + <UsageCount Value="197"/> + </Unit77> + <Unit78> + <Filename Value="/usr/lib/lazarus/0.9.30.4/components/tachart/tagraph.pas"/> + <UnitName Value="TAGraph"/> + <TopLine Value="307"/> + <CursorPos Y="414"/> + <UsageCount Value="7"/> + </Unit78> + <Unit79> + <Filename Value="/usr/lib/lazarus/0.9.30.4/components/tachart/tachartaxis.pas"/> + <UnitName Value="TAChartAxis"/> + <TopLine Value="794"/> + <CursorPos X="15" Y="808"/> + <UsageCount Value="6"/> + </Unit79> + <Unit80> + <Filename Value="/usr/lib/lazarus/0.9.30.4/components/tachart/demo/save/main.pas"/> + <TopLine Value="56"/> + <UsageCount Value="7"/> + </Unit80> + <Unit81> + <Filename Value="/usr/lib/lazarus/0.9.30.4/components/tachart/tadrawutils.pas"/> + <UnitName Value="TADrawUtils"/> + <TopLine Value="28"/> + <UsageCount Value="7"/> + </Unit81> + <Unit82> + <Filename Value="/usr/lib/lazarus/0.9.30.4/components/tachart/demo/basic/unit1.pas"/> + <ComponentName Value="Form1"/> + <HasResources Value="True"/> + <ResourceBaseClass Value="Form"/> + <TopLine Value="103"/> + <CursorPos X="3" Y="118"/> + <UsageCount Value="7"/> + </Unit82> + <Unit83> + <Filename Value="/usr/lib/lazarus/0.9.30.4/components/tachart/tacustomseries.pas"/> + <UnitName Value="TACustomSeries"/> + <TopLine Value="635"/> + <CursorPos Y="648"/> + <UsageCount Value="7"/> + </Unit83> + <Unit84> + <Filename Value="UserInterface/Forms/frpropagation.pas"/> + <IsPartOfProject Value="True"/> + <ComponentName Value="FrmPropagation"/> + <HasResources Value="True"/> + <ResourceBaseClass Value="Form"/> + <EditorIndex Value="-1"/> + <TopLine Value="71"/> + <CursorPos X="5" Y="88"/> + <UsageCount Value="200"/> + </Unit84> + <Unit85> + <Filename Value="UserInterface/Forms/frrefractometer.pas"/> + <IsPartOfProject Value="True"/> + <ComponentName Value="FrmRefractometer"/> + <HasResources Value="True"/> + <ResourceBaseClass Value="Form"/> + <EditorIndex Value="-1"/> + <TopLine Value="33"/> + <CursorPos X="6" Y="63"/> + <UsageCount Value="200"/> + </Unit85> + <Unit86> + <Filename Value="UserInterface/Forms/frboilmethod.pas"/> + <IsPartOfProject Value="True"/> + <ComponentName Value="FrmBoilMethod"/> + <HasResources Value="True"/> + <ResourceBaseClass Value="Form"/> + <EditorIndex Value="-1"/> + <TopLine Value="58"/> + <CursorPos X="7" Y="85"/> + <UsageCount Value="200"/> + </Unit86> + <Unit87> + <Filename Value="UserInterface/Forms/fdatabaselocation.pas"/> + <IsPartOfProject Value="True"/> + <ComponentName Value="FrmDatabaseLocation"/> + <HasResources Value="True"/> + <ResourceBaseClass Value="Form"/> + <EditorIndex Value="-1"/> + <TopLine Value="76"/> + <CursorPos X="48" Y="116"/> + <UsageCount Value="200"/> + </Unit87> + <Unit88> + <Filename Value="../Software/Lazarus/Componenten/Mathematisch/dmat086/Units/uminmax.pas"/> + <UsageCount Value="3"/> + </Unit88> + <Unit89> + <Filename Value="Units/umulfit.pas"/> + <IsPartOfProject Value="True"/> + <EditorIndex Value="-1"/> + <TopLine Value="64"/> + <CursorPos X="30" Y="15"/> + <UsageCount Value="200"/> + </Unit89> + <Unit90> + <Filename Value="Units/utypes.pas"/> + <IsPartOfProject Value="True"/> + <EditorIndex Value="-1"/> + <UsageCount Value="200"/> + </Unit90> + <Unit91> + <Filename Value="UserInterface/Forms/frdividebrew.pas"/> + <IsPartOfProject Value="True"/> + <ComponentName Value="FrmDivideBrew"/> + <HasResources Value="True"/> + <ResourceBaseClass Value="Form"/> + <EditorIndex Value="-1"/> + <TopLine Value="15"/> + <CursorPos X="3" Y="41"/> + <UsageCount Value="200"/> + </Unit91> + <Unit92> + <Filename Value="UserInterface/Forms/fryeasts3.pas"/> + <IsPartOfProject Value="True"/> + <ComponentName Value="FrmYeasts3"/> + <HasResources Value="True"/> + <ResourceBaseClass Value="Form"/> + <EditorIndex Value="-1"/> + <TopLine Value="77"/> + <CursorPos X="13" Y="117"/> + <UsageCount Value="200"/> + </Unit92> + <Unit93> + <Filename Value="UserInterface/Forms/frchoosebeerstyle.pas"/> + <IsPartOfProject Value="True"/> + <ComponentName Value="FrmChooseBeerstyle"/> + <HasResources Value="True"/> + <ResourceBaseClass Value="Form"/> + <EditorIndex Value="-1"/> + <TopLine Value="12"/> + <CursorPos X="68" Y="46"/> + <UsageCount Value="200"/> + </Unit93> + <Unit94> + <Filename Value="UserInterface/Forms/frchoosebrewschars.pas"/> + <IsPartOfProject Value="True"/> + <ComponentName Value="FrmChooseBrewChars"/> + <HasResources Value="True"/> + <ResourceBaseClass Value="Form"/> + <EditorIndex Value="-1"/> + <TopLine Value="48"/> + <CursorPos Y="70"/> + <UsageCount Value="200"/> + </Unit94> + <Unit95> + <Filename Value="UserInterface/Forms/frsplash.pas"/> + <IsPartOfProject Value="True"/> + <ComponentName Value="FrmSplash"/> + <HasResources Value="True"/> + <ResourceBaseClass Value="Form"/> + <EditorIndex Value="-1"/> + <TopLine Value="23"/> + <CursorPos X="16" Y="58"/> + <UsageCount Value="200"/> + </Unit95> + <Unit96> + <Filename Value="/usr/lib/lazarus/0.9.30.4/ide/idecmdline.pas"/> + <UnitName Value="IDECmdLine"/> + <UsageCount Value="2"/> + </Unit96> + <Unit97> + <Filename Value="/usr/share/fpcsrc/2.6.0/rtl/objpas/sysutils/osutilsh.inc"/> + <CursorPos X="20" Y="41"/> + <UsageCount Value="2"/> + </Unit97> + <Unit98> + <Filename Value="/usr/share/fpcsrc/2.6.0/rtl/objpas/sysutils/osutil.inc"/> + <TopLine Value="104"/> + <CursorPos X="30" Y="127"/> + <UsageCount Value="2"/> + </Unit98> + <Unit99> + <Filename Value="/usr/share/fpcsrc/2.6.0/rtl/objpas/sysutils/fina.inc"/> + <TopLine Value="37"/> + <UsageCount Value="2"/> + </Unit99> + <Unit100> + <Filename Value="/usr/share/fpcsrc/2.6.0/rtl/objpas/objpas.pp"/> + <TopLine Value="174"/> + <CursorPos X="18" Y="221"/> + <UsageCount Value="2"/> + </Unit100> + <Unit101> + <Filename Value="/usr/share/fpcsrc/2.6.0/rtl/objpas/sysutils/sysutils.inc"/> + <UsageCount Value="2"/> + </Unit101> + <Unit102> + <Filename Value="/usr/share/fpcsrc/2.6.0/rtl/win/windirs.pp"/> + <TopLine Value="91"/> + <UsageCount Value="2"/> + </Unit102> + <Unit103> + <Filename Value="/usr/lib/lazarus/0.9.30.4/components/tachart/talegend.pas"/> + <UnitName Value="TALegend"/> + <TopLine Value="179"/> + <CursorPos X="9" Y="192"/> + <UsageCount Value="2"/> + </Unit103> + <Unit104> + <Filename Value="../../lazarus/fpc/2.6.0/source/rtl/win/windirs.pp"/> + <CursorPos X="46" Y="4"/> + <UsageCount Value="3"/> + </Unit104> + <Unit105> + <Filename Value="../../lazarus/lcl/include/treeview.inc"/> + <TopLine Value="1426"/> + <CursorPos Y="1437"/> + <UsageCount Value="2"/> + </Unit105> + <Unit106> + <Filename Value="../../lazarus/lcl/include/control.inc"/> + <TopLine Value="2278"/> + <CursorPos Y="2289"/> + <UsageCount Value="2"/> + </Unit106> + <Unit107> + <Filename Value="../../lazarus/lcl/include/buttoncontrol.inc"/> + <TopLine Value="52"/> + <CursorPos Y="63"/> + <UsageCount Value="2"/> + </Unit107> + <Unit108> + <Filename Value="../../lazarus/lcl/include/customedit.inc"/> + <TopLine Value="501"/> + <CursorPos Y="512"/> + <UsageCount Value="3"/> + </Unit108> + <Unit109> + <Filename Value="../../lazarus/lcl/grids.pas"/> + <UnitName Value="Grids"/> + <TopLine Value="5051"/> + <CursorPos X="23" Y="5058"/> + <UsageCount Value="4"/> + </Unit109> + <Unit110> + <Filename Value="../../lazarus/lcl/include/spinedit.inc"/> + <CursorPos X="3" Y="3"/> + <UsageCount Value="3"/> + </Unit110> + <Unit111> + <Filename Value="../../lazarus/lcl/spin.pp"/> + <UnitName Value="Spin"/> + <TopLine Value="105"/> + <CursorPos X="22" Y="181"/> + <UsageCount Value="3"/> + </Unit111> + <Unit112> + <Filename Value="../../lazarus/lcl/include/wincontrol.inc"/> + <TopLine Value="5231"/> + <CursorPos Y="5242"/> + <UsageCount Value="3"/> + </Unit112> + <Unit113> + <Filename Value="../../lazarus/lcl/lclmessageglue.pas"/> + <UnitName Value="LCLMessageGlue"/> + <TopLine Value="106"/> + <CursorPos Y="121"/> + <UsageCount Value="3"/> + </Unit113> + <Unit114> + <Filename Value="../../lazarus/lcl/lclclasses.pp"/> + <UnitName Value="LCLClasses"/> + <TopLine Value="129"/> + <CursorPos Y="141"/> + <UsageCount Value="3"/> + </Unit114> + <Unit115> + <Filename Value="../../lazarus/lcl/interfaces/win32/win32callback.inc"/> + <TopLine Value="2498"/> + <CursorPos Y="2511"/> + <UsageCount Value="3"/> + </Unit115> + <Unit116> + <Filename Value="../../lazarus/lcl/forms.pp"/> + <UnitName Value="Forms"/> + <TopLine Value="59"/> + <CursorPos X="41" Y="70"/> + <UsageCount Value="4"/> + </Unit116> + <Unit117> + <Filename Value="/usr/lib/lazarus/0.9.30.4/lcl/comctrls.pp"/> + <UnitName Value="ComCtrls"/> + <TopLine Value="3045"/> + <CursorPos X="13" Y="2234"/> + <UsageCount Value="7"/> + </Unit117> + <Unit118> + <Filename Value="UserInterface/Forms/frinfo.pas"/> + <IsPartOfProject Value="True"/> + <ComponentName Value="frmInfo"/> + <HasResources Value="True"/> + <ResourceBaseClass Value="Form"/> + <EditorIndex Value="-1"/> + <CursorPos X="3" Y="79"/> + <UsageCount Value="200"/> + </Unit118> + <Unit119> + <Filename Value="Units/vinfo.pas"/> + <IsPartOfProject Value="True"/> + <EditorIndex Value="-1"/> + <CursorPos X="44" Y="8"/> + <UsageCount Value="200"/> + </Unit119> + <Unit120> + <Filename Value="/usr/share/fpcsrc/2.6.0/packages/fcl-res/src/versiontypes.pp"/> + <TopLine Value="25"/> + <CursorPos X="3" Y="49"/> + <UsageCount Value="7"/> + </Unit120> + <Unit121> + <Filename Value="webstuff.pas"/> + <UnitName Value="Webstuff"/> + <TopLine Value="127"/> + <CursorPos Y="92"/> + <UsageCount Value="17"/> + </Unit121> + <Unit122> + <Filename Value="/Software/Lazarus/proejct1/unit1.pas"/> + <UnitName Value="Unit1"/> + <TopLine Value="38"/> + <CursorPos Y="58"/> + <UsageCount Value="7"/> + </Unit122> + <Unit123> + <Filename Value="Synapse/source/lib/ftpsend.pas"/> + <CursorPos X="86" Y="4"/> + <UsageCount Value="5"/> + </Unit123> + <Unit124> + <Filename Value="UserInterface/Forms/frsynchronize.pas"/> + <IsPartOfProject Value="True"/> + <ComponentName Value="frmFTPList"/> + <HasResources Value="True"/> + <ResourceBaseClass Value="Form"/> + <EditorIndex Value="-1"/> + <CursorPos X="39" Y="9"/> + <UsageCount Value="200"/> + </Unit124> + <Unit125> + <Filename Value="/usr/lib/lazarus/0.9.30.4/lcl/stdctrls.pp"/> + <UnitName Value="StdCtrls"/> + <TopLine Value="1173"/> + <CursorPos X="3" Y="1185"/> + <UsageCount Value="7"/> + </Unit125> + <Unit126> + <Filename Value="UserInterface/Forms/frchoosebrews.pas"/> + <IsPartOfProject Value="True"/> + <ComponentName Value="frmChooseBrewsList"/> + <HasResources Value="True"/> + <ResourceBaseClass Value="Form"/> + <EditorIndex Value="-1"/> + <TopLine Value="69"/> + <CursorPos X="31" Y="84"/> + <UsageCount Value="201"/> + </Unit126> + <Unit127> + <Filename Value="AlReport/alrep.pas"/> + <UnitName Value="Alrep"/> + <UsageCount Value="1"/> + </Unit127> + <Unit128> + <Filename Value="/usr/lib/lazarus/0.9.30.4/lcl/include/customform.inc"/> + <TopLine Value="114"/> + <CursorPos Y="134"/> + <UsageCount Value="2"/> + </Unit128> + <Unit129> + <Filename Value="/usr/share/lazarus/1.0/components/tachart/tachartaxis.pas"/> + <UnitName Value="TAChartAxis"/> + <TopLine Value="13"/> + <CursorPos X="3" Y="27"/> + <UsageCount Value="1"/> + </Unit129> + <Unit130> + <Filename Value="/usr/share/lazarus/1.0/components/tachart/tadraweraggpas.pas"/> + <UnitName Value="TADrawerAggPas"/> + <TopLine Value="8"/> + <CursorPos X="22" Y="23"/> + <UsageCount Value="1"/> + </Unit130> + <Unit131> + <Filename Value="/usr/share/lazarus/1.0/lcl/grids.pas"/> + <UnitName Value="Grids"/> + <TopLine Value="5448"/> + <CursorPos Y="5462"/> + <UsageCount Value="2"/> + </Unit131> + <Unit132> + <Filename Value="/usr/share/lazarus/1.0/components/tachart/tagraph.pas"/> + <UnitName Value="TAGraph"/> + <TopLine Value="1133"/> + <CursorPos X="46" Y="1146"/> + <UsageCount Value="1"/> + </Unit132> + <Unit133> + <Filename Value="/usr/share/lazarus/1.0/components/tachart/tadrawercanvas.pas"/> + <UnitName Value="TADrawerCanvas"/> + <TopLine Value="175"/> + <CursorPos Y="137"/> + <UsageCount Value="1"/> + </Unit133> + <Unit134> + <Filename Value="/usr/share/lazarus/1.0/components/tachart/taprint.pas"/> + <UnitName Value="TAPrint"/> + <TopLine Value="30"/> + <UsageCount Value="1"/> + </Unit134> + <Unit135> + <Filename Value="/usr/share/lazarus/1.0/lcl/include/rasterimage.inc"/> + <TopLine Value="291"/> + <CursorPos Y="305"/> + <UsageCount Value="1"/> + </Unit135> + <Unit136> + <Filename Value="/usr/share/lazarus/1.0/lcl/include/customedit.inc"/> + <TopLine Value="517"/> + <CursorPos Y="526"/> + <UsageCount Value="1"/> + </Unit136> + <Unit137> + <Filename Value="/usr/share/lazarus/1.0/lcl/include/control.inc"/> + <TopLine Value="2729"/> + <CursorPos Y="2743"/> + <UsageCount Value="1"/> + </Unit137> + <Unit138> + <Filename Value="/usr/share/lazarus/1.0/packager/registration/registerfcl.pas"/> + <UnitName Value="RegisterFCL"/> + <UsageCount Value="1"/> + </Unit138> + <Unit139> + <Filename Value="/usr/share/lazarus/1.0/packager/registration/fcllaz.pas"/> + <UsageCount Value="1"/> + </Unit139> + <Unit140> + <Filename Value="Synapse/source/lib/laz_synapse.pas"/> + <EditorIndex Value="-1"/> + <CursorPos X="22" Y="14"/> + <UsageCount Value="6"/> + </Unit140> + <Unit141> + <Filename Value="/usr/share/lazarus/1.0/lcl/interfaces/lcl.pas"/> + <UnitName Value="LCL"/> + <UsageCount Value="1"/> + </Unit141> + <Unit142> + <Filename Value="/usr/share/lazarus/1.0/lcl/alllclunits.pp"/> + <UsageCount Value="1"/> + </Unit142> + <Unit143> + <Filename Value="/usr/share/lazarus/1.0/components/aggpas/lazarus/aggpaslcl.pas"/> + <UnitName Value="AggPasLCL"/> + <UsageCount Value="1"/> + </Unit143> + <Unit144> + <Filename Value="/usr/share/lazarus/1.0/components/tachart/tachartprint.pas"/> + <UnitName Value="TAChartPrint"/> + <CursorPos X="3" Y="10"/> + <UsageCount Value="1"/> + </Unit144> + <Unit145> + <Filename Value="/usr/share/lazarus/1.0/components/tachart/tadrawerwmf.pas"/> + <UnitName Value="TADrawerWMF"/> + <UsageCount Value="1"/> + </Unit145> + <Unit146> + <Filename Value="/usr/share/lazarus/1.0/lcl/include/customcheckbox.inc"/> + <TopLine Value="109"/> + <CursorPos Y="123"/> + <UsageCount Value="2"/> + </Unit146> + <Unit147> + <Filename Value="UserInterface/Forms/frgristwizard.pas"/> + <IsPartOfProject Value="True"/> + <ComponentName Value="FrmGristWizard"/> + <HasResources Value="True"/> + <ResourceBaseClass Value="Form"/> + <EditorIndex Value="-1"/> + <TopLine Value="2"/> + <CursorPos X="86" Y="8"/> + <UsageCount Value="175"/> + </Unit147> + <Unit148> + <Filename Value="/usr/share/lazarus/1.0/components/lazutils/fileutil.inc"/> + <TopLine Value="986"/> + <CursorPos Y="1000"/> + <UsageCount Value="2"/> + </Unit148> + <Unit149> + <Filename Value="/usr/share/fpcsrc/2.6.0/packages/fcl-xml/src/xmlread.pp"/> + <UnitName Value="XMLRead"/> + <TopLine Value="30"/> + <CursorPos X="27" Y="44"/> + <UsageCount Value="6"/> + </Unit149> + <Unit150> + <Filename Value="Units/cloud.pas"/> + <IsPartOfProject Value="True"/> + <EditorIndex Value="-1"/> + <TopLine Value="1307"/> + <CursorPos X="42" Y="194"/> + <UsageCount Value="123"/> + </Unit150> + <Unit151> + <Filename Value="/usr/share/lazarus/1.0.2/lcl/extctrls.pp"/> + <UnitName Value="ExtCtrls"/> + <TopLine Value="37"/> + <CursorPos X="35" Y="61"/> + <UsageCount Value="3"/> + </Unit151> + <Unit152> + <Filename Value="/usr/share/lazarus/1.0.2/lcl/include/page.inc"/> + <CursorPos X="34" Y="21"/> + <UsageCount Value="3"/> + </Unit152> + <Unit153> + <Filename Value="/usr/share/lazarus/1.0.2/lcl/controls.pp"/> + <UnitName Value="Controls"/> + <TopLine Value="3176"/> + <CursorPos X="48" Y="1975"/> + <UsageCount Value="3"/> + </Unit153> + <Unit154> + <Filename Value="/usr/share/lazarus/1.0.2/lcl/buttons.pp"/> + <UnitName Value="Buttons"/> + <TopLine Value="564"/> + <UsageCount Value="3"/> + </Unit154> + <Unit155> + <Filename Value="UserInterface/Forms/frsettings.pas"/> + <IsPartOfProject Value="True"/> + <ComponentName Value="frmSettings"/> + <HasResources Value="True"/> + <ResourceBaseClass Value="Form"/> + <EditorIndex Value="-1"/> + <TopLine Value="91"/> + <CursorPos X="32" Y="115"/> + <UsageCount Value="124"/> + </Unit155> + <Unit156> + <Filename Value="UserInterface/Forms/frrestoredatabases.pas"/> + <IsPartOfProject Value="True"/> + <ComponentName Value="frmRestoreDatabase"/> + <HasResources Value="True"/> + <ResourceBaseClass Value="Form"/> + <EditorIndex Value="3"/> + <TopLine Value="49"/> + <CursorPos X="76" Y="64"/> + <UsageCount Value="123"/> + <Loaded Value="True"/> + </Unit156> + <Unit157> + <Filename Value="Units/neuroot.pas"/> + <IsPartOfProject Value="True"/> + <EditorIndex Value="-1"/> + <CursorPos X="71" Y="8"/> + <UsageCount Value="123"/> + </Unit157> + <Unit158> + <Filename Value="fann.pas"/> + <UnitName Value="FANN"/> + <UsageCount Value="4"/> + </Unit158> + <Unit159> + <Filename Value="fannnetwork.pas"/> + <UnitName Value="FannNetwork"/> + <UsageCount Value="4"/> + </Unit159> + <Unit160> + <Filename Value="frnntrain.pas"/> + <ComponentName Value="FrmNNTrain"/> + <HasResources Value="True"/> + <ResourceBaseClass Value="Form"/> + <TopLine Value="65"/> + <CursorPos X="40" Y="88"/> + <UsageCount Value="63"/> + </Unit160> + <Unit161> + <Filename Value="Synapse/source/lib/httpsend.pas"/> + <TopLine Value="250"/> + <CursorPos X="26" Y="274"/> + <UsageCount Value="5"/> + </Unit161> + <Unit162> + <Filename Value="UserInterface/Forms/frgetpasswd.pas"/> + <IsPartOfProject Value="True"/> + <ComponentName Value="frmGetPasswd"/> + <HasResources Value="True"/> + <ResourceBaseClass Value="Form"/> + <EditorIndex Value="-1"/> + <TopLine Value="7"/> + <CursorPos Y="21"/> + <UsageCount Value="106"/> + </Unit162> + <Unit163> + <Filename Value="UserInterface/Forms/frdownloadprogress.pas"/> + <IsPartOfProject Value="True"/> + <ComponentName Value="FrmDownloadProgress"/> + <HasResources Value="True"/> + <ResourceBaseClass Value="Form"/> + <EditorIndex Value="-1"/> + <TopLine Value="29"/> + <CursorPos Y="57"/> + <UsageCount Value="100"/> + </Unit163> + <Unit164> + <Filename Value="/usr/share/fpcsrc/2.6.0/packages/fcl-xml/src/xmlutils.pp"/> + <TopLine Value="83"/> + <CursorPos X="61" Y="97"/> + <UsageCount Value="5"/> + </Unit164> + <Unit165> + <Filename Value="Synapse/source/lib/synautil.pas"/> + <TopLine Value="268"/> + <UsageCount Value="5"/> + </Unit165> + <Unit166> + <Filename Value="/usr/share/fpcsrc/2.6.0/rtl/inc/variants.pp"/> + <TopLine Value="96"/> + <CursorPos X="43" Y="110"/> + <UsageCount Value="5"/> + </Unit166> + <Unit167> + <Filename Value="franalysis.pas"/> + <ComponentName Value="FrmAnalysis"/> + <HasResources Value="True"/> + <ResourceBaseClass Value="Form"/> + <EditorIndex Value="-1"/> + <TopLine Value="58"/> + <CursorPos X="60" Y="84"/> + <UsageCount Value="6"/> + </Unit167> + <Unit168> + <Filename Value="/usr/share/lazarus/1.4.2/lcl/editbtn.pas"/> + <UnitName Value="EditBtn"/> + <EditorIndex Value="-1"/> + <TopLine Value="35"/> + <CursorPos X="34" Y="55"/> + <UsageCount Value="6"/> + </Unit168> + <Unit169> + <Filename Value="/usr/share/lazarus/1.4.2/lcl/controls.pp"/> + <UnitName Value="Controls"/> + <EditorIndex Value="-1"/> + <TopLine Value="1886"/> + <CursorPos X="3" Y="1861"/> + <UsageCount Value="6"/> + </Unit169> + <Unit170> + <Filename Value="/usr/lib/lazarus/1.6/ide/lazarus.pp"/> + <UnitName Value="Lazarus"/> + <EditorIndex Value="-1"/> + <WindowIndex Value="-1"/> + <TopLine Value="37"/> + <CursorPos X="3" Y="54"/> + <UsageCount Value="6"/> + </Unit170> + <Unit171> + <Filename Value="/usr/lib/lazarus/1.6/lcl/grids.pas"/> + <UnitName Value="Grids"/> + <EditorIndex Value="-1"/> + <TopLine Value="5711"/> + <CursorPos Y="5723"/> + <UsageCount Value="6"/> + </Unit171> + <Unit172> + <Filename Value="/usr/lib/lazarus/1.6/lcl/interfaces/qt/qtwidgets.pas"/> + <EditorIndex Value="-1"/> + <TopLine Value="5552"/> + <CursorPos X="46" Y="5587"/> + <UsageCount Value="6"/> + </Unit172> + <Unit173> + <Filename Value="/usr/lib/lazarus/1.6/lcl/include/spinedit.inc"/> + <EditorIndex Value="-1"/> + <TopLine Value="116"/> + <CursorPos Y="140"/> + <UsageCount Value="6"/> + </Unit173> + <Unit174> + <Filename Value="rcstrngs.pas"/> + <EditorIndex Value="-1"/> + <TopLine Value="519"/> + <CursorPos X="48" Y="541"/> + <UsageCount Value="7"/> + </Unit174> + <Unit175> + <Filename Value="subs.pas"/> + <EditorIndex Value="-1"/> + <TopLine Value="354"/> + <CursorPos X="32" Y="375"/> + <UsageCount Value="7"/> + </Unit175> + <Unit176> + <Filename Value="/usr/lib/lazarus/1.6/lcl/dialogs.pp"/> + <UnitName Value="Dialogs"/> + <EditorIndex Value="-1"/> + <TopLine Value="160"/> + <CursorPos X="3" Y="180"/> + <UsageCount Value="6"/> + </Unit176> + <Unit177> + <Filename Value="/usr/lib/lazarus/1.6/lcl/stdctrls.pp"/> + <UnitName Value="StdCtrls"/> + <EditorIndex Value="-1"/> + <TopLine Value="1618"/> + <CursorPos X="20" Y="1636"/> + <UsageCount Value="6"/> + </Unit177> + <Unit178> + <Filename Value="/usr/lib/lazarus/1.6/lcl/include/lcl_defines.inc"/> + <EditorIndex Value="-1"/> + <UsageCount Value="6"/> + </Unit178> + <Unit179> + <Filename Value="/usr/lib/lazarus/1.6/lcl/include/customlabel.inc"/> + <EditorIndex Value="-1"/> + <TopLine Value="46"/> + <UsageCount Value="6"/> + </Unit179> + <Unit180> + <Filename Value="ExpandPanels/expandpanels.pas"/> + <UnitName Value="ExpandPanels"/> + <EditorIndex Value="-1"/> + <TopLine Value="70"/> + <CursorPos X="3" Y="42"/> + <UsageCount Value="6"/> + </Unit180> + <Unit181> + <Filename Value="uniqueinstance-1.0/uniqueinstance.pas"/> + <UnitName Value="UniqueInstance"/> + <EditorIndex Value="-1"/> + <TopLine Value="24"/> + <CursorPos X="3" Y="41"/> + <UsageCount Value="6"/> + </Unit181> + <Unit182> + <Filename Value="/usr/share/lazarus/1.8.2/components/lazutils/fileutil.pas"/> + <UnitName Value="FileUtil"/> + <EditorIndex Value="-1"/> + <TopLine Value="10"/> + <CursorPos X="17" Y="19"/> + <UsageCount Value="6"/> + </Unit182> + <Unit183> + <Filename Value="frmain.lfm"/> + <EditorIndex Value="-1"/> + <UsageCount Value="6"/> + <DefaultSyntaxHighlighter Value="LFM"/> + </Unit183> + <Unit184> + <Filename Value="/usr/share/lazarus/1.8.2/lcl/spin.pp"/> + <UnitName Value="Spin"/> + <EditorIndex Value="-1"/> + <TopLine Value="175"/> + <CursorPos X="17" Y="212"/> + <UsageCount Value="8"/> + </Unit184> + <Unit185> + <Filename Value="/usr/share/lazarus/1.8.2/lcl/widgetset/wsspin.pp"/> + <UnitName Value="WSSpin"/> + <EditorIndex Value="-1"/> + <CursorPos X="56" Y="49"/> + <UsageCount Value="7"/> + </Unit185> + <Unit186> + <Filename Value="/usr/share/lazarus/1.8.2/lcl/include/spinedit.inc"/> + <EditorIndex Value="-1"/> + <TopLine Value="190"/> + <CursorPos X="24" Y="205"/> + <UsageCount Value="8"/> + </Unit186> + <Unit187> + <Filename Value="/usr/share/lazarus/1.8.2/lcl/stdctrls.pp"/> + <UnitName Value="StdCtrls"/> + <EditorIndex Value="-1"/> + <TopLine Value="1645"/> + <CursorPos X="19" Y="1665"/> + <UsageCount Value="7"/> + </Unit187> + <Unit188> + <Filename Value="/usr/share/lazarus/1.8.2/lcl/include/customedit.inc"/> + <EditorIndex Value="-1"/> + <CursorPos X="75" Y="15"/> + <UsageCount Value="7"/> + </Unit188> + <Unit189> + <Filename Value="/usr/share/lazarus/1.8.2/lcl/controls.pp"/> + <UnitName Value="Controls"/> + <EditorIndex Value="-1"/> + <TopLine Value="2901"/> + <CursorPos X="11" Y="2710"/> + <UsageCount Value="8"/> + </Unit189> + <Unit190> + <Filename Value="/usr/share/lazarus/1.8.2/ide/lazarus.pp"/> + <UnitName Value="Lazarus"/> + <EditorIndex Value="-1"/> + <TopLine Value="121"/> + <CursorPos Y="161"/> + <UsageCount Value="7"/> + </Unit190> + <Unit191> + <Filename Value="/usr/include/c++/7/fenv.h"/> + <EditorIndex Value="-1"/> + <TopLine Value="41"/> + <CursorPos Y="81"/> + <UsageCount Value="8"/> + <DefaultSyntaxHighlighter Value="C++"/> + </Unit191> + <Unit192> + <Filename Value="openal.pas"/> + <EditorIndex Value="-1"/> + <TopLine Value="2172"/> + <CursorPos Y="2191"/> + <UsageCount Value="24"/> + </Unit192> + <Unit193> + <Filename Value="/usr/share/fpcsrc/3.0.4/packages/openal/src/openal.pas"/> + <EditorIndex Value="-1"/> + <CursorPos Y="40"/> + <UsageCount Value="8"/> + </Unit193> + <Unit194> + <Filename Value="alch.inc"/> + <EditorIndex Value="-1"/> + <TopLine Value="190"/> + <UsageCount Value="8"/> + </Unit194> + <Unit195> + <Filename Value="alexth.inc"/> + <EditorIndex Value="-1"/> + <TopLine Value="80"/> + <CursorPos X="63" Y="95"/> + <UsageCount Value="8"/> + </Unit195> + <Unit196> + <Filename Value="alh.inc"/> + <EditorIndex Value="-1"/> + <TopLine Value="375"/> + <CursorPos X="10" Y="90"/> + <UsageCount Value="8"/> + </Unit196> + <Unit197> + <Filename Value="../Synapse/source/lib/laz_synapse.pas"/> + <EditorIndex Value="-1"/> + <CursorPos X="3" Y="11"/> + <UsageCount Value="10"/> + </Unit197> + <Unit198> + <Filename Value="../../../MAGWEG/BrewBuddy/Source/3rdParty/Synapse/source/lib/laz_synapse.pas"/> + <EditorIndex Value="-1"/> + <CursorPos X="3" Y="11"/> + <UsageCount Value="10"/> + </Unit198> + <Unit199> + <Filename Value="../../../../fpcupdeluxe/lazarus/components/tachart/tachartaxis.pas"/> + <UnitName Value="TAChartAxis"/> + <EditorIndex Value="-1"/> + <TopLine Value="157"/> + <CursorPos X="14" Y="185"/> + <UsageCount Value="10"/> + </Unit199> + <Unit200> + <Filename Value="../../../../fpcupdeluxe/lazarus/components/tachart/tachartaxisutils.pas"/> + <UnitName Value="TAChartAxisUtils"/> + <EditorIndex Value="-1"/> + <TopLine Value="4"/> + <CursorPos X="3" Y="39"/> + <UsageCount Value="10"/> + </Unit200> + <Unit201> + <Filename Value="Units/fann.pas"/> + <IsPartOfProject Value="True"/> + <UnitName Value="FANN"/> + <EditorIndex Value="-1"/> + <TopLine Value="34"/> + <CursorPos X="19" Y="55"/> + <UsageCount Value="25"/> + </Unit201> + <Unit202> + <Filename Value="../../app/Source/Units/containers.pas"/> + <UnitName Value="Containers"/> + <EditorIndex Value="-1"/> + <TopLine Value="3277"/> + <CursorPos X="58" Y="3292"/> + <UsageCount Value="10"/> + </Unit202> + <Unit203> + <Filename Value="../../app/Source/UserInterface/Forms/frmain.pas"/> + <UnitName Value="FrMain"/> + <EditorIndex Value="-1"/> + <TopLine Value="4579"/> + <CursorPos X="28" Y="4597"/> + <UsageCount Value="10"/> + </Unit203> + <Unit204> + <Filename Value="../../app/Source/UserInterface/Forms/backup/frmain.pas"/> + <UnitName Value="FrMain"/> + <EditorIndex Value="-1"/> + <TopLine Value="4579"/> + <CursorPos X="28" Y="4597"/> + <UsageCount Value="10"/> + </Unit204> + <Unit205> + <Filename Value="Units/backup/containers.pas"/> + <UnitName Value="Containers"/> + <EditorIndex Value="-1"/> + <TopLine Value="3092"/> + <CursorPos X="5" Y="3119"/> + <UsageCount Value="10"/> + </Unit205> + <Unit206> + <Filename Value="../../../../fpcupdeluxe/fpcsrc/rtl/objpas/sysutils/finah.inc"/> + <EditorIndex Value="-1"/> + <TopLine Value="13"/> + <CursorPos X="25" Y="23"/> + <UsageCount Value="10"/> + </Unit206> + <Unit207> + <Filename Value="../../../../fpcupdeluxe/lazarus/lcl/forms.pp"/> + <UnitName Value="Forms"/> + <EditorIndex Value="6"/> + <TopLine Value="1540"/> + <CursorPos X="24" Y="1417"/> + <UsageCount Value="11"/> + <Loaded Value="True"/> + </Unit207> + <Unit208> + <Filename Value="../../../../fpcupdeluxe/lazarus/lcl/include/winapi.inc"/> + <EditorIndex Value="5"/> + <TopLine Value="164"/> + <CursorPos X="21" Y="180"/> + <UsageCount Value="10"/> + <Loaded Value="True"/> + </Unit208> + </Units> + <JumpHistory Count="30" HistoryIndex="29"> + <Position1> + <Filename Value="Units/containers.pas"/> + <Caret Line="2954" Column="11" TopLine="2933"/> + </Position1> + <Position2> + <Filename Value="Units/containers.pas"/> + <Caret Line="3073" Column="11" TopLine="3060"/> + </Position2> + <Position3> + <Filename Value="Units/containers.pas"/> + <Caret Line="3074" TopLine="3060"/> + </Position3> + <Position4> + <Filename Value="Units/containers.pas"/> + <Caret Line="3076" TopLine="3060"/> + </Position4> + <Position5> + <Filename Value="Units/containers.pas"/> + <Caret Line="3064" Column="34" TopLine="3057"/> + </Position5> + <Position6> + <Filename Value="Units/containers.pas"/> + <Caret Line="3066" Column="33" TopLine="3054"/> + </Position6> + <Position7> + <Filename Value="Units/containers.pas"/> + <Caret Line="3069" Column="33" TopLine="3054"/> + </Position7> + <Position8> + <Filename Value="Units/containers.pas"/> + <Caret Line="3242" Column="37" TopLine="3217"/> + </Position8> + <Position9> + <Filename Value="Units/containers.pas"/> + <Caret Line="3066" Column="26" TopLine="3060"/> + </Position9> + <Position10> + <Filename Value="Units/containers.pas"/> + <Caret Line="3111" Column="55" TopLine="3061"/> + </Position10> + <Position11> + <Filename Value="Units/containers.pas"/> + <Caret Line="3066" Column="44" TopLine="3061"/> + </Position11> + <Position12> + <Filename Value="../../../../fpcupdeluxe/lazarus/lcl/forms.pp"/> + <Caret Line="1848" Column="51" TopLine="1833"/> + </Position12> + <Position13> + <Filename Value="Units/containers.pas"/> + <Caret Line="3119" Column="9" TopLine="3102"/> + </Position13> + <Position14> + <Filename Value="Units/containers.pas"/> + <Caret Line="3044" Column="12" TopLine="3104"/> + </Position14> + <Position15> + <Filename Value="Units/containers.pas"/> + <Caret Line="3238" Column="21" TopLine="3229"/> + </Position15> + <Position16> + <Filename Value="Units/containers.pas"/> + <Caret Line="3371" Column="17" TopLine="3347"/> + </Position16> + <Position17> + <Filename Value="Units/containers.pas"/> + <Caret Line="3065" Column="17" TopLine="3050"/> + </Position17> + <Position18> + <Filename Value="Units/containers.pas"/> + <Caret Line="3119" Column="74" TopLine="3104"/> + </Position18> + <Position19> + <Filename Value="Units/containers.pas"/> + <Caret Line="3122" Column="91" TopLine="3104"/> + </Position19> + <Position20> + <Filename Value="Units/containers.pas"/> + <Caret Line="3265" Column="81" TopLine="3240"/> + </Position20> + <Position21> + <Filename Value="Units/containers.pas"/> + <Caret Line="3292" Column="72" TopLine="3267"/> + </Position21> + <Position22> + <Filename Value="Units/containers.pas"/> + <Caret Line="3116" Column="74" TopLine="451"/> + </Position22> + <Position23> + <Filename Value="Units/bh_report.pas"/> + <Caret Line="15" Column="58" TopLine="157"/> + </Position23> + <Position24> + <Filename Value="Units/hulpfuncties.pas"/> + <Caret Line="2515" Column="66" TopLine="2496"/> + </Position24> + <Position25> + <Filename Value="Units/hulpfuncties.pas"/> + <Caret Line="2342" Column="30" TopLine="2326"/> + </Position25> + <Position26> + <Filename Value="Units/hulpfuncties.pas"/> + <Caret Line="2361" Column="47" TopLine="2341"/> + </Position26> + <Position27> + <Filename Value="Units/hulpfuncties.pas"/> + <Caret Line="2447" Column="44" TopLine="2432"/> + </Position27> + <Position28> + <Filename Value="Units/hulpfuncties.pas"/> + <Caret Line="7" Column="15"/> + </Position28> + <Position29> + <Filename Value="Units/hulpfuncties.pas"/> + <Caret Line="165" Column="15" TopLine="160"/> + </Position29> + <Position30> + <Filename Value="brewbuddy.pas"/> + <Caret Line="7" Column="50"/> + </Position30> + </JumpHistory> + </ProjectOptions> + <CompilerOptions> + <Version Value="11"/> + <Target> + <Filename Value="../Output/BrewBuddy"/> + </Target> + <SearchPaths> + <IncludeFiles Value="../Output;$(ProjOutDir)"/> + <OtherUnitFiles Value="UserInterface/Forms;Units"/> + <UnitOutputDirectory Value="../Output/units"/> + </SearchPaths> + <CodeGeneration> + <Optimizations> + <OptimizationLevel Value="0"/> + <VariablesInRegisters Value="True"/> + </Optimizations> + </CodeGeneration> + <Linking> + <Debugging> + <DebugInfoType Value="dsDwarf2Set"/> + </Debugging> + </Linking> + <Other> + <CustomOptions Value="-k$(ProjSrcPath)3rdParty/fann/usr/local/lib/libdoublefann.2.2.0.dylib"/> + </Other> + </CompilerOptions> + <Debugging> + <BreakPoints Count="3"> + <Item1> + <Kind Value="bpkSource"/> + <WatchScope Value="wpsLocal"/> + <WatchKind Value="wpkWrite"/> + <Source Value="hulpfuncties.pas"/> + <Line Value="2462"/> + </Item1> + <Item2> + <Kind Value="bpkSource"/> + <WatchScope Value="wpsLocal"/> + <WatchKind Value="wpkWrite"/> + <Source Value="openal.pas"/> + <Line Value="2189"/> + </Item2> + <Item3> + <Kind Value="bpkSource"/> + <WatchScope Value="wpsLocal"/> + <WatchKind Value="wpkWrite"/> + <Source Value="openal.pas"/> + <Line Value="1973"/> + </Item3> + </BreakPoints> + <Watches Count="2"> + <Item1> + <Expression Value="TYeast(FYeasts[i]).FAmountYeast.fValue"/> + </Item1> + <Item2> + <Expression Value="TYeast(FYeasts[i]).fAmount.FValue"/> + </Item2> + </Watches> + <Exceptions Count="4"> + <Item1> + <Name Value="EAbort"/> + </Item1> + <Item2> + <Name Value="ECodetoolError"/> + </Item2> + <Item3> + <Name Value="EFOpenError"/> + </Item3> + <Item4> + <Name Value="EReadError"/> + </Item4> + </Exceptions> + </Debugging> +</CONFIG> diff --git a/Source/brewbuddy.pas b/Source/brewbuddy.pas index 698d6834..062ff8fd 100644 --- a/Source/brewbuddy.pas +++ b/Source/brewbuddy.pas @@ -25,7 +25,7 @@ {$R *.res} begin - Application.Title:='brewbuddy'; + Application.Title:='BrewBuddy'; try Application.Initialize; Application.CreateForm(TfrmMain, frmMain); diff --git a/Source/brewbuddy_osx.lpi b/Source/brewbuddy_osx.lpi index 5ded8c0e..ce932805 100644 --- a/Source/brewbuddy_osx.lpi +++ b/Source/brewbuddy_osx.lpi @@ -1,14 +1,12 @@ <?xml version="1.0" encoding="UTF-8"?> <CONFIG> <ProjectOptions> - <Version Value="10"/> + <Version Value="11"/> <General> <MainUnit Value="0"/> <AutoCreateForms Value="False"/> - <Title Value="brewbuddy"/> - <UseAppBundle Value="False"/> + <Title Value="BrewBuddy"/> <ResourceType Value="res"/> - <Icon Value="0"/> </General> <i18n> <EnableI18N LFM="False"/> @@ -20,18 +18,23 @@ <Language Value="0413"/> <StringTable CompanyName="Brouwerij Het Witte Paard" FileDescription="BrewBuddy Sassy Saison" InternalName="BrewBuddy" OriginalFilename="BrewBuddy" ProductName="BrewBuddy" ProductVersion="5.3.5.2"/> </VersionInfo> + <MacroValues Count="1"> + <Macro1 Name="LCLWidgetType" Value="cocoa"/> + </MacroValues> <BuildModes Count="1" Active="Default"> <Item1 Name="Default" Default="True"/> + <SharedMatrixOptions Count="1"> + <Item1 ID="090156190409" Modes="Default" Type="IDEMacro" MacroName="LCLWidgetType" Value="cocoa"/> + </SharedMatrixOptions> </BuildModes> <PublishOptions> <Version Value="2"/> - <IncludeFileFilter Value="*.(pas|pp|inc|lfm|lpr|lrs|lpi|lpk|sh|xml)"/> - <ExcludeFileFilter Value="*.(bak|ppu|o|so);*~;backup"/> </PublishOptions> <RunParams> - <local> - <FormatVersion Value="1"/> - </local> + <FormatVersion Value="2"/> + <Modes Count="1"> + <Mode0 Name="default"/> + </Modes> </RunParams> <RequiredPackages Count="9"> <Item1> @@ -65,14 +68,14 @@ <PackageName Value="LCL"/> </Item9> </RequiredPackages> - <Units Count="199"> + <Units Count="212"> <Unit0> <Filename Value="brewbuddy.pas"/> <IsPartOfProject Value="True"/> - <EditorIndex Value="-1"/> - <TopLine Value="7"/> - <CursorPos Y="29"/> + <EditorIndex Value="5"/> + <CursorPos X="50" Y="7"/> <UsageCount Value="201"/> + <Loaded Value="True"/> </Unit0> <Unit1> <Filename Value="UserInterface/Forms/frmain.pas"/> @@ -81,12 +84,11 @@ <HasResources Value="True"/> <ResourceBaseClass Value="Form"/> <UnitName Value="FrMain"/> - <IsVisibleTab Value="True"/> - <TopLine Value="1047"/> - <CursorPos Y="1048"/> + <EditorIndex Value="8"/> + <TopLine Value="1475"/> + <CursorPos X="20" Y="1491"/> <UsageCount Value="201"/> <Loaded Value="True"/> - <LoadedDesigner Value="True"/> </Unit1> <Unit2> <Filename Value="Units/data.pas"/> @@ -147,10 +149,11 @@ <Filename Value="Units/hulpfuncties.pas"/> <IsPartOfProject Value="True"/> <UnitName Value="Hulpfuncties"/> - <EditorIndex Value="-1"/> - <TopLine Value="2490"/> - <CursorPos Y="2526"/> + <EditorIndex Value="2"/> + <TopLine Value="2375"/> + <CursorPos X="11" Y="2391"/> <UsageCount Value="201"/> + <Loaded Value="True"/> </Unit11> <Unit12> <Filename Value="lnet/lazaruspackage/lnetbase.pas"/> @@ -160,9 +163,10 @@ <Filename Value="Units/containers.pas"/> <IsPartOfProject Value="True"/> <UnitName Value="Containers"/> - <EditorIndex Value="-1"/> - <CursorPos Y="3349"/> + <TopLine Value="3055"/> + <CursorPos X="74" Y="3066"/> <UsageCount Value="200"/> + <Loaded Value="True"/> </Unit13> <Unit14> <Filename Value="appsettings.pas"/> @@ -651,10 +655,11 @@ <Filename Value="Units/bh_report.pas"/> <IsPartOfProject Value="True"/> <UnitName Value="BH_report"/> - <EditorIndex Value="-1"/> - <TopLine Value="993"/> - <CursorPos X="8" Y="1013"/> + <EditorIndex Value="1"/> + <TopLine Value="983"/> + <CursorPos X="31" Y="1007"/> <UsageCount Value="200"/> + <Loaded Value="True"/> </Unit71> <Unit72> <Filename Value="UserInterface/Forms/frprintpreview.pas"/> @@ -1186,7 +1191,7 @@ <EditorIndex Value="-1"/> <TopLine Value="2"/> <CursorPos X="86" Y="8"/> - <UsageCount Value="170"/> + <UsageCount Value="176"/> </Unit147> <Unit148> <Filename Value="/usr/share/lazarus/1.0/components/lazutils/fileutil.inc"/> @@ -1207,7 +1212,7 @@ <EditorIndex Value="-1"/> <TopLine Value="1307"/> <CursorPos X="42" Y="194"/> - <UsageCount Value="118"/> + <UsageCount Value="124"/> </Unit150> <Unit151> <Filename Value="/usr/share/lazarus/1.0.2/lcl/extctrls.pp"/> @@ -1243,7 +1248,7 @@ <EditorIndex Value="-1"/> <TopLine Value="91"/> <CursorPos X="32" Y="115"/> - <UsageCount Value="119"/> + <UsageCount Value="125"/> </Unit155> <Unit156> <Filename Value="UserInterface/Forms/frrestoredatabases.pas"/> @@ -1251,17 +1256,18 @@ <ComponentName Value="frmRestoreDatabase"/> <HasResources Value="True"/> <ResourceBaseClass Value="Form"/> - <EditorIndex Value="-1"/> - <CursorPos X="47" Y="16"/> - <UsageCount Value="118"/> + <EditorIndex Value="4"/> + <TopLine Value="49"/> + <CursorPos X="76" Y="64"/> + <UsageCount Value="124"/> + <Loaded Value="True"/> </Unit156> <Unit157> <Filename Value="Units/neuroot.pas"/> <IsPartOfProject Value="True"/> <EditorIndex Value="-1"/> - <TopLine Value="189"/> - <CursorPos X="25" Y="213"/> - <UsageCount Value="118"/> + <CursorPos X="71" Y="8"/> + <UsageCount Value="124"/> </Unit157> <Unit158> <Filename Value="fann.pas"/> @@ -1297,7 +1303,7 @@ <EditorIndex Value="-1"/> <TopLine Value="7"/> <CursorPos Y="21"/> - <UsageCount Value="101"/> + <UsageCount Value="107"/> </Unit162> <Unit163> <Filename Value="UserInterface/Forms/frdownloadprogress.pas"/> @@ -1308,7 +1314,7 @@ <EditorIndex Value="-1"/> <TopLine Value="29"/> <CursorPos Y="57"/> - <UsageCount Value="95"/> + <UsageCount Value="101"/> </Unit163> <Unit164> <Filename Value="/usr/share/fpcsrc/2.6.0/packages/fcl-xml/src/xmlutils.pp"/> @@ -1560,39 +1566,249 @@ <CursorPos X="3" Y="11"/> <UsageCount Value="10"/> </Unit198> + <Unit199> + <Filename Value="../../../../fpcupdeluxe/lazarus/components/tachart/tachartaxis.pas"/> + <UnitName Value="TAChartAxis"/> + <EditorIndex Value="-1"/> + <TopLine Value="157"/> + <CursorPos X="14" Y="185"/> + <UsageCount Value="10"/> + </Unit199> + <Unit200> + <Filename Value="../../../../fpcupdeluxe/lazarus/components/tachart/tachartaxisutils.pas"/> + <UnitName Value="TAChartAxisUtils"/> + <EditorIndex Value="-1"/> + <TopLine Value="4"/> + <CursorPos X="3" Y="39"/> + <UsageCount Value="10"/> + </Unit200> + <Unit201> + <Filename Value="Units/fann.pas"/> + <IsPartOfProject Value="True"/> + <UnitName Value="FANN"/> + <EditorIndex Value="-1"/> + <TopLine Value="34"/> + <CursorPos X="19" Y="55"/> + <UsageCount Value="26"/> + </Unit201> + <Unit202> + <Filename Value="../../app/Source/Units/containers.pas"/> + <UnitName Value="Containers"/> + <EditorIndex Value="-1"/> + <TopLine Value="3277"/> + <CursorPos X="58" Y="3292"/> + <UsageCount Value="10"/> + </Unit202> + <Unit203> + <Filename Value="../../app/Source/UserInterface/Forms/frmain.pas"/> + <UnitName Value="FrMain"/> + <EditorIndex Value="-1"/> + <TopLine Value="4579"/> + <CursorPos X="28" Y="4597"/> + <UsageCount Value="10"/> + </Unit203> + <Unit204> + <Filename Value="../../app/Source/UserInterface/Forms/backup/frmain.pas"/> + <UnitName Value="FrMain"/> + <EditorIndex Value="-1"/> + <TopLine Value="4579"/> + <CursorPos X="28" Y="4597"/> + <UsageCount Value="10"/> + </Unit204> + <Unit205> + <Filename Value="Units/backup/containers.pas"/> + <UnitName Value="Containers"/> + <EditorIndex Value="-1"/> + <TopLine Value="3092"/> + <CursorPos X="5" Y="3119"/> + <UsageCount Value="10"/> + </Unit205> + <Unit206> + <Filename Value="../../../../fpcupdeluxe/fpcsrc/rtl/objpas/sysutils/finah.inc"/> + <EditorIndex Value="-1"/> + <TopLine Value="13"/> + <CursorPos X="25" Y="23"/> + <UsageCount Value="10"/> + </Unit206> + <Unit207> + <Filename Value="../../../../fpcupdeluxe/lazarus/lcl/forms.pp"/> + <UnitName Value="Forms"/> + <EditorIndex Value="7"/> + <TopLine Value="1540"/> + <CursorPos X="24" Y="1417"/> + <UsageCount Value="11"/> + <Loaded Value="True"/> + </Unit207> + <Unit208> + <Filename Value="../../../../fpcupdeluxe/lazarus/lcl/include/winapi.inc"/> + <EditorIndex Value="6"/> + <TopLine Value="164"/> + <CursorPos Y="180"/> + <UsageCount Value="10"/> + <Loaded Value="True"/> + </Unit208> + <Unit209> + <Filename Value="Units/backup/hulpfuncties.pas"/> + <UnitName Value="Hulpfuncties"/> + <EditorIndex Value="3"/> + <TopLine Value="2375"/> + <CursorPos X="11" Y="2391"/> + <UsageCount Value="10"/> + <Loaded Value="True"/> + </Unit209> + <Unit210> + <Filename Value="UserInterface/Forms/frhistogram.pas"/> + <EditorIndex Value="9"/> + <TopLine Value="36"/> + <CursorPos X="15" Y="51"/> + <UsageCount Value="10"/> + <Loaded Value="True"/> + </Unit210> + <Unit211> + <Filename Value="3rdParty/Orpheus/tests/TestTblEdits/unit1.pas"/> + <UnitName Value="Unit1"/> + <IsVisibleTab Value="True"/> + <EditorIndex Value="10"/> + <TopLine Value="66"/> + <CursorPos X="18" Y="82"/> + <UsageCount Value="10"/> + <Loaded Value="True"/> + </Unit211> </Units> - <JumpHistory Count="1"> + <JumpHistory Count="30" HistoryIndex="29"> <Position1> - <Filename Value="UserInterface/Forms/frmain.pas"/> - <Caret Line="1048" TopLine="1046"/> + <Filename Value="Units/containers.pas"/> + <Caret Line="3119" Column="74" TopLine="3104"/> </Position1> + <Position2> + <Filename Value="Units/containers.pas"/> + <Caret Line="3122" Column="91" TopLine="3104"/> + </Position2> + <Position3> + <Filename Value="Units/containers.pas"/> + <Caret Line="3265" Column="81" TopLine="3240"/> + </Position3> + <Position4> + <Filename Value="Units/containers.pas"/> + <Caret Line="3292" Column="72" TopLine="3267"/> + </Position4> + <Position5> + <Filename Value="Units/containers.pas"/> + <Caret Line="3116" Column="74" TopLine="451"/> + </Position5> + <Position6> + <Filename Value="Units/bh_report.pas"/> + <Caret Line="15" Column="58" TopLine="157"/> + </Position6> + <Position7> + <Filename Value="Units/hulpfuncties.pas"/> + <Caret Line="2515" Column="66" TopLine="2496"/> + </Position7> + <Position8> + <Filename Value="Units/hulpfuncties.pas"/> + <Caret Line="2342" Column="30" TopLine="2326"/> + </Position8> + <Position9> + <Filename Value="Units/hulpfuncties.pas"/> + <Caret Line="2361" Column="47" TopLine="2341"/> + </Position9> + <Position10> + <Filename Value="Units/hulpfuncties.pas"/> + <Caret Line="2447" Column="44" TopLine="2432"/> + </Position10> + <Position11> + <Filename Value="Units/hulpfuncties.pas"/> + <Caret Line="7" Column="15"/> + </Position11> + <Position12> + <Filename Value="Units/hulpfuncties.pas"/> + <Caret Line="165" Column="15" TopLine="160"/> + </Position12> + <Position13> + <Filename Value="brewbuddy.pas"/> + <Caret Line="7" Column="50"/> + </Position13> + <Position14> + <Filename Value="Units/hulpfuncties.pas"/> + <Caret Line="9" Column="61"/> + </Position14> + <Position15> + <Filename Value="Units/hulpfuncties.pas"/> + <Caret Line="185" Column="17" TopLine="159"/> + </Position15> + <Position16> + <Filename Value="Units/hulpfuncties.pas"/> + <Caret Line="2340" Column="17" TopLine="2318"/> + </Position16> + <Position17> + <Filename Value="Units/hulpfuncties.pas"/> + <Caret Line="2359" Column="17" TopLine="2361"/> + </Position17> + <Position18> + <Filename Value="Units/hulpfuncties.pas"/> + <Caret Line="2378" Column="17" TopLine="2361"/> + </Position18> + <Position19> + <Filename Value="Units/hulpfuncties.pas"/> + <Caret Line="2391" Column="22" TopLine="2371"/> + </Position19> + <Position20> + <Filename Value="Units/hulpfuncties.pas"/> + <Caret Line="341" Column="11" TopLine="333"/> + </Position20> + <Position21> + <Filename Value="Units/hulpfuncties.pas"/> + <Caret Line="2391" Column="11" TopLine="2375"/> + </Position21> + <Position22> + <Filename Value="Units/backup/hulpfuncties.pas"/> + <Caret Line="341" Column="11" TopLine="325"/> + </Position22> + <Position23> + <Filename Value="Units/backup/hulpfuncties.pas"/> + <Caret Line="2391" Column="11" TopLine="2375"/> + </Position23> + <Position24> + <Filename Value="UserInterface/Forms/frmain.pas"/> + <Caret Line="1491" Column="31" TopLine="1485"/> + </Position24> + <Position25> + <Filename Value="UserInterface/Forms/frmain.pas"/> + <Caret Line="701" Column="26" TopLine="686"/> + </Position25> + <Position26> + <Filename Value="UserInterface/Forms/frmain.pas"/> + <Caret Line="1491" Column="31" TopLine="1465"/> + </Position26> + <Position27> + <Filename Value="UserInterface/Forms/frmain.pas"/> + <Caret Line="701" Column="15" TopLine="686"/> + </Position27> + <Position28> + <Filename Value="UserInterface/Forms/frmain.pas"/> + <Caret Line="1491" Column="20" TopLine="1475"/> + </Position28> + <Position29> + <Filename Value="UserInterface/Forms/frhistogram.pas"/> + <Caret Line="51" Column="15" TopLine="36"/> + </Position29> + <Position30> + <Filename Value="3rdParty/Orpheus/tests/TestTblEdits/unit1.pas"/> + <Caret Line="36" Column="15" TopLine="20"/> + </Position30> </JumpHistory> </ProjectOptions> <CompilerOptions> <Version Value="11"/> <Target> - <Filename Value="../Output/brewbuddy"/> + <Filename Value="../Output/BrewBuddy"/> </Target> <SearchPaths> <IncludeFiles Value="../Output;$(ProjOutDir)"/> <OtherUnitFiles Value="UserInterface/Forms;Units"/> <UnitOutputDirectory Value="../Output/units"/> </SearchPaths> - <Parsing> - <SyntaxOptions> - <IncludeAssertionCode Value="True"/> - </SyntaxOptions> - </Parsing> <CodeGeneration> - <Checks> - <IOChecks Value="True"/> - <RangeChecks Value="True"/> - <OverflowChecks Value="True"/> - <StackChecks Value="True"/> - </Checks> - <VerifyObjMethodCallValidity Value="True"/> - <TargetCPU Value=""/> - <TargetOS Value=""/> <Optimizations> <OptimizationLevel Value="0"/> <VariablesInRegisters Value="True"/> @@ -1600,14 +1816,12 @@ </CodeGeneration> <Linking> <Debugging> - <UseValgrind Value="True"/> + <DebugInfoType Value="dsDwarf2Set"/> </Debugging> - <Options> - <Win32> - <GraphicApplication Value="True"/> - </Win32> - </Options> </Linking> + <Other> + <CustomOptions Value="-k$(ProjSrcPath)3rdParty/fann/usr/local/lib/libdoublefann.2.2.0.dylib"/> + </Other> </CompilerOptions> <Debugging> <BreakPoints Count="3"> From 7b5bcbe2819b2bad7d6b173763daa7224e4d7d52 Mon Sep 17 00:00:00 2001 From: Ruud Arentsen <ruud.arentsen@gmail.com> Date: Wed, 26 Dec 2018 14:30:29 +0100 Subject: [PATCH 2/2] Removed backup directories --- Source/Units/backup/backup/containers.pas.bak | 3524 ----------------- Source/Units/backup/bh_report.pas | 2464 ------------ Source/Units/backup/containers.pas | 3524 ----------------- Source/Units/backup/fann.pas | 1228 ------ Source/Units/backup/hulpfuncties.pas | 2531 ------------ .../Forms/backup/frrestoredatabases.pas | 102 - Source/backup/brewbuddy.pas | 51 - Source/backup/brewbuddy_osx.lpi | 1846 --------- 8 files changed, 15270 deletions(-) delete mode 100644 Source/Units/backup/backup/containers.pas.bak delete mode 100644 Source/Units/backup/bh_report.pas delete mode 100644 Source/Units/backup/containers.pas delete mode 100644 Source/Units/backup/fann.pas delete mode 100644 Source/Units/backup/hulpfuncties.pas delete mode 100644 Source/UserInterface/Forms/backup/frrestoredatabases.pas delete mode 100644 Source/backup/brewbuddy.pas delete mode 100644 Source/backup/brewbuddy_osx.lpi diff --git a/Source/Units/backup/backup/containers.pas.bak b/Source/Units/backup/backup/containers.pas.bak deleted file mode 100644 index 3c3b071b..00000000 --- a/Source/Units/backup/backup/containers.pas.bak +++ /dev/null @@ -1,3524 +0,0 @@ -unit Containers; - -{$mode objfpc}{$H+} - -interface - -uses - Classes, SysUtils, {$ifdef Windows}windows, windirs, {$endif}Forms, Controls, Dialogs, - Data, Hulpfuncties, DOM, XMLRead, XMLWrite, XMLUtils, variants, frimport; - -type - TContainer = class(TObject) - private - FFileName : string; - FImportFileName : string; - FLabel : string; - FCollection : array of TBase; - FSelected : integer; - FDoc : TXMLDocument; - FRootNode, FChild : TDOMNode; - Procedure SetSelected(i : integer); - public - Constructor Create; virtual; - Destructor Destroy; override; - Procedure SaveXML; virtual; - Procedure ReadXML; virtual; - Function ImportXML : boolean; virtual; - Procedure SortByIndex(Index : integer; Decending : boolean; Nstart, Nend : integer); - Procedure SortByIndex2(I1, I2 : integer; Decending : boolean); - Procedure SortByName(s : string); - Procedure UnSelect; - Function AddItem : TBase; virtual; - Procedure InsertItem(i : integer); virtual; - Procedure RemoveItem(i : integer); virtual; - Procedure RemoveByReference(Item : TBase); virtual; - Procedure FreeCollection; - Function GetNumItems : integer; - Function GetItem(i : integer) : TBase; - Function FindByName(s : string) : TBase; - Function FindByNameOnStock(s : string) : TBase; - Function FindByAutoNr(i : integer) : TBase; - Procedure RemoveByAutoNr(i : integer); - Function IndexByName(s : string) : integer; - property Item[i: integer] : TBase read GetItem; - published - property FileName : string read FFileName write FFileName; - property ImportFileName : string read FImportFileName; - property Selected : integer read FSelected write SetSelected; - property NodeLabel : string read FLabel write FLabel; - property NumItems : integer read GetNumItems; - end; - - TFermentables = class(TContainer) - private - public - Constructor Create; override; - Procedure SaveXML; override; - Procedure ReadXML; override; - Function ImportXML : boolean; override; - Function GetSelectedItem : TFermentable; - Function AddItem : TFermentable; - Procedure InsertItem(i : integer); override; - Function FindByNameAndSupplier(N, S : string) : TFermentable; - published - property SelectedItem : TFermentable read GetSelectedItem; - end; - - THops = class(TContainer) - private - public - Constructor Create; override; - Procedure SaveXML; override; - Procedure ReadXML; override; - Function ImportXML : boolean; override; - Function GetSelectedItem : THop; - Function AddItem : THop; - Procedure InsertItem(i : integer); override; - Function FindByNameAndOriginAndAlfa(N, O : string; A : double) : THop; - published - property SelectedItem : THop read GetSelectedItem; - end; - - TMiscs = class(TContainer) - private - public - Constructor Create; override; - Procedure SaveXML; override; - Procedure ReadXML; override; - Function ImportXML : boolean; override; - Function GetSelectedItem : TMisc; - Function AddItem : TMisc; - Procedure InsertItem(i : integer); override; - published - property SelectedItem : TMisc read GetSelectedItem; - end; - - TYeasts = class(TContainer) - private - public - Constructor Create; override; - Procedure SaveXML; override; - Procedure ReadXML; override; - Function ImportXML : boolean; override; - Function GetSelectedItem : TYeast; - Function AddItem : TYeast; - Procedure InsertItem(i : integer); override; - Function FindByNameAndLaboratory(N, L : string) : TYeast; - published - property SelectedItem : TYeast read GetSelectedItem; - end; - - TWaters = class(TContainer) - private - public - Constructor Create; override; - Procedure SaveXML; override; - Procedure ReadXML; override; - Function ImportXML : boolean; override; - Function GetSelectedItem : TWater; - Function AddItem : TWater; - Procedure InsertItem(i : integer); override; - Function GetDefaultWater : TWater; - Function GetDemiWater : TWater; - published - property SelectedItem : TWater read GetSelectedItem; - end; - - TEquipments = class(TContainer) - private - public - Constructor Create; override; - Procedure SaveXML; override; - Procedure ReadXML; override; -// Function ImportXML : boolean; override; - Function GetSelectedItem : TEquipment; - Function AddItem : TEquipment; - Procedure InsertItem(i : integer); override; - Procedure CalcEfficiencyRegressionFactors; - Procedure CalcAttenuationRegressionFactors; - published - property SelectedItem : TEquipment read GetSelectedItem; - end; - - TBeerStyles = class(TContainer) - private - public - Constructor Create; override; - Procedure SaveXML; override; - Procedure ReadXML; override; - Function ImportXML : boolean; override; - Function GetSelectedItem : TBeerStyle; - Function AddItem : TBeerStyle; - Procedure InsertItem(i : integer); override; - published - property SelectedItem : TBeerStyle read GetSelectedItem; - end; - - TMashs = class(TContainer) - private - public - Constructor Create; override; - Procedure SaveXML; override; - Procedure ReadXML; override; - Function ImportXML : boolean; override; - Function GetSelectedItem : TMash; - Function AddItem : TMash; - Procedure InsertItem(i : integer); override; - published - property SelectedItem : TMash read GetSelectedItem; - end; - - TMinMax = record - Name : string; - PercRecipes : single; //% of recipes with ingredient - MinUse, AvUse, MaxUse : single; //use of the ingredient in recipes' - end; - - TMinMaxArray = array of TMinMax; - - TRecipes = class(TContainer) - private - FFermentablesMinMaxArray : TMinMaxArray; - FBitterhopMinMaxArray : TMinMaxArray; - FAromahopMinMaxArray : TMinMaxArray; - FDryhopMinMaxArray : TMinMaxArray; - FYeastMinMaxArray : TMinMaxArray; - FMiscMinMaxArray : TMinMaxArray; - FCommonMinMaxArray : TMinMaxArray; - Procedure QuickSortRecipes(var Arr : array of TBase); - Function ImportXMLs(FN : TStrings; DN : string; Equip : TEquipment) : boolean; - Function ImportXML(FN : string; Equip : TEquipment) : boolean; - Function ImportRECs(FN : TStrings; DN : string; Equip : TEquipment) : boolean; - Function ImportREC(FN : string; Equip : TEquipment) : boolean; - Function GetLastNrRecipe : string; - Procedure QuickSortA(var Arr : array of TMinMax); - Function Exists(Arr : TMinMaxArray; FName : string) : integer; - Function GetMaxAutoNr : integer; - public - Constructor Create; override; - Destructor Destroy; override; - Procedure SaveXML; override; - Procedure ReadXML; override; - Procedure CheckAutoNrs; - Function ImportFiles(FN : TStrings; DN : string; Equip : TEquipment; - FT : TFileType) : boolean; - Procedure Sort; - Function GetSelectedItem : TRecipe; - Function AddItem : TRecipe; - Procedure InsertItem(i : integer); override; - Function FindByNameAndNr(Nm, Nr : string) : TRecipe; - Function FindByAutoNr(nr : integer) : TRecipe; - Function ExportToCSV(A : array of integer) : boolean; - Function AnalyseFermentables(Lett, Nm : string) : integer; //returns number of recipes - Function AnalyseHops(Lett, Nm : string) : integer; //returns number of recipes - Function AnalyseYeasts(Lett, Nm : string) : integer; //returns number of recipes - Function AnalyseMiscs(Lett, Nm : string) : integer; - Function AnalyseRecipes(Lett, Nm : string) : integer; - property FermentablesMinMaxArray : TMinMaxArray read FFermentablesMinMaxArray; - property BitterhopMinMaxArray : TMinMaxArray read FBitterhopMinMaxArray; - property AromahopMinMaxArray : TMinMaxArray read FAromahopMinMaxArray; - property DryhopMinMaxArray : TMinMaxArray read FDryhopMinMaxArray; - property YeastMinMaxArray : TMinMaxArray read FYeastMinMaxArray; - property MiscMinMaxArray : TMinMaxArray read FMiscMinMaxArray; - property CommonMinMaxArray : TMinMaxArray read FCommonMinMaxArray; - published - property SelectedItem : TRecipe read GetSelectedItem; - property LastNrRecipe : string read GetLastNrRecipe; - property MaxAutoNr : integer read GetMaxAutoNr; - end; - - TStyleRec = record - Name : string; - Recipes : array of TRecipe; - end; - - TStyleLetters = record - Letter : string; - Styles : array of TStyleRec; - end; - - TRecipesByStyle = class(TObject) - private - FStyleLetters : array of TStyleLetters; - FCollection : TRecipes; - Procedure Fill; - Procedure Empty; - Procedure Sort; - Function GetNumStyleLetters : integer; - Function GetNumStyles(i : integer) : integer; - Function GetStyleLetter(i : integer) : string; - Function GetStyleName(n : integer; s : integer) : string; - Function GetNumRecipes(n : integer; s : integer) : integer; - Function GetRecipe(n : integer; s : integer; i : integer) : TRecipe; - Procedure QuickSortInStyles(var Arr : array of TRecipe); - Procedure QuickSortStyles(var Arr : array of TStyleRec); - Procedure QuickSortLetters(var Arr : array of TStyleLetters); - public - Constructor Create(R : TRecipes); - Destructor Destroy; override; - Procedure SaveXML; - Function GetLetterByName(Num : string) : integer; - Function GetStyleByName(Num, Stl : string) : integer; - property NumStyles[i : integer] : integer read GetNumStyles; - property NumRecipes[n : integer; s : integer] : integer read GetNumRecipes; - property Recipe[n : integer; s : integer; i : integer] : TRecipe read GetRecipe; - property StyleLetter[i : integer] : string read GetStyleLetter; - property StyleName[n : integer; s : integer] : string read GetStyleName; - published - property NumStyleLetters : integer read GetNumStyleLetters; - end; - - Procedure Reload; - Procedure Backup; - Procedure Restore(sourcedata : string); - Procedure CheckBeerStyle(Rec : TRecipe); - Procedure CheckFermentables(Rec : TRecipe); - Procedure CheckYeasts(Rec : TRecipe); - Procedure CheckDataFolder; - Procedure ChangeDatabaseLocation(source, destination : string; copy, deleteold : boolean); - -var - Fermentables : TFermentables; - Hops : THops; - Miscs : TMiscs; - Yeasts : TYeasts; - Waters : TWaters; - Equipments : TEquipments; - Beerstyles : TBeerstyles; - Mashs : TMashs; - Recipes : TRecipes; - Brews : TRecipes; - - Loc : string; - - Arr : array of longint; - -implementation - -uses frmain, ComCtrls, frselectbeerstyle, fileutil, LazFileUtils, promashimport, cloud, subs, - neuroot, strutils, math; - -Procedure CheckSalts; -var M : TMisc; -begin - if Miscs.FindByName('CaCl2') = NIL then - begin - M:= Miscs.AddItem; - M.Name.Value:= 'CaCl2'; - M.AmountIsWeight.Value:= true; - M.Amount.vUnit:= kilogram; - M.Amount.DisplayUnit:= gram; - M.Amount.Value:= 0; - M.MiscType:= mtWaterAgent; - M.Use:= muMash; - M.UseFor.Value:= 'Voor het maken van een ander waterprofiel. Voegt calcium en chloride toe. Voor het verbeteren van zoetere bieren.'; - M.Inventory.vUnit:= M.Amount.vUnit; - M.Inventory.DisplayUnit:= M.Amount.DisplayUnit; - M.Inventory.Value:= 0; - end; - if Miscs.FindByName('CaCO3') = NIL then - begin - M:= Miscs.AddItem; - M.Name.Value:= 'CaCO3'; - M.AmountIsWeight.Value:= true; - M.Amount.vUnit:= kilogram; - M.Amount.DisplayUnit:= gram; - M.Amount.Value:= 0; - M.MiscType:= mtWaterAgent; - M.Use:= muMash; - M.UseFor.Value:= 'Kalk. Voor het maken van een ander waterprofiel. Voegt calcium en (bi)carbonaat toe. Voor het verhogen van de pH tijdens het maischen.'; - M.Inventory.vUnit:= M.Amount.vUnit; - M.Inventory.DisplayUnit:= M.Amount.DisplayUnit; - M.Inventory.Value:= 0; - end; - if Miscs.FindByName('CaSO4') = NIL then - begin - M:= Miscs.AddItem; - M.Name.Value:= 'CaSO4'; - M.AmountIsWeight.Value:= true; - M.Amount.vUnit:= kilogram; - M.Amount.DisplayUnit:= gram; - M.Amount.Value:= 0; - M.MiscType:= mtWaterAgent; - M.Use:= muMash; - M.UseFor.Value:= 'Gips. Voor het maken van een ander waterprofiel. Voegt calcium en sulfaat toe. Voor het verbeteren van bittere bieren.'; - M.Inventory.vUnit:= M.Amount.vUnit; - M.Inventory.DisplayUnit:= M.Amount.DisplayUnit; - M.Inventory.Value:= 0; - end; - if Miscs.FindByName('MgSO4') = NIL then - begin - M:= Miscs.AddItem; - M.Name.Value:= 'MgSO4'; - M.AmountIsWeight.Value:= true; - M.Amount.vUnit:= kilogram; - M.Amount.DisplayUnit:= gram; - M.Amount.Value:= 0; - M.MiscType:= mtWaterAgent; - M.Use:= muMash; - M.UseFor.Value:= 'Epsom zout. Voor het maken van een ander waterprofiel. Voegt magnesium en sulfaat toe. Gebruik spaarzaam!'; - M.Inventory.vUnit:= M.Amount.vUnit; - M.Inventory.DisplayUnit:= M.Amount.DisplayUnit; - M.Inventory.Value:= 0; - end; - if Miscs.FindByName('NaCl') = NIL then - begin - M:= Miscs.AddItem; - M.Name.Value:= 'NaCl'; - M.AmountIsWeight.Value:= true; - M.Amount.vUnit:= kilogram; - M.Amount.DisplayUnit:= gram; - M.Amount.Value:= 0; - M.MiscType:= mtWaterAgent; - M.Use:= muMash; - M.UseFor.Value:= 'Keukenzout. Voor het maken van een ander waterprofiel. Voegt natrium en chloride toe. Voor het accentueren van zoetheid. Bij hoge dosering wordt het bier ziltig.'; - M.Inventory.vUnit:= M.Amount.vUnit; - M.Inventory.DisplayUnit:= M.Amount.DisplayUnit; - M.Inventory.Value:= 0; - end; - if Miscs.FindByName('NaHCO3') = NIL then - begin - M:= Miscs.AddItem; - M.Name.Value:= 'NaHCO3'; - M.AmountIsWeight.Value:= true; - M.Amount.vUnit:= kilogram; - M.Amount.DisplayUnit:= gram; - M.Amount.Value:= 0; - M.MiscType:= mtWaterAgent; - M.Use:= muMash; - M.UseFor.Value:= 'Baksoda of bakpoeder. Voor het maken van een ander waterprofiel. Voegt natrium en bicarbonaat toe. Kan gebruikt worden voor verhoging van de pH tijdens het maischen.'; - M.Inventory.vUnit:= M.Amount.vUnit; - M.Inventory.DisplayUnit:= M.Amount.DisplayUnit; - M.Inventory.Value:= 0; - end; - if Miscs.FindByName('Melkzuur') = NIL then - begin - M:= Miscs.AddItem; - M.Name.Value:= 'Melkzuur'; - M.AmountIsWeight.Value:= false; - M.Amount.vUnit:= liter; - M.Amount.DisplayUnit:= milliliter; - M.Amount.Value:= 0; - M.MiscType:= mtWaterAgent; - M.Use:= muMash; - M.UseFor.Value:= 'Melkzuur wordt gebruikt voor het verlagen van de pH tijdens het maischen en het verlagen van de pH van het spoelwater.'; - M.Inventory.vUnit:= M.Amount.vUnit; - M.Inventory.DisplayUnit:= M.Amount.DisplayUnit; - M.Inventory.Value:= 0; - end; -end; - -Constructor TContainer.Create; -begin - Inherited; - FFileName:= ''; - FSelected:= -1; - FLabel:= ''; -end; - -Destructor TContainer.Destroy; -begin - FreeCollection; - Inherited; -end; - -Procedure TContainer.SaveXML; -begin - FDoc := TXMLDocument.Create; -// FDoc.Encoding:= 'ISO-8859-1'; - FRootNode := FDoc.CreateElement(FLabel); - FDoc.Appendchild(FRootNode); -end; - -Procedure TContainer.ReadXML; -var FN : string; -begin - FRootNode:= NIL; - try - FreeCollection; - FN:= Settings.DataLocation.Value + FFileName; - if FileExists(FN) then - begin - ReadXMLFile(FDoc, FN); - FRootNode:= FDoc.FindNode(FLabel); - end; - except - FDoc.Free; - end; -end; - -Function TContainer.ImportXML : boolean; -var dlg : TOpenDialog; -begin - Result:= false; - FRootNode:= NIL; - FDoc := TXMLDocument.Create; - dlg:= TOpenDialog.Create(frmMain); - with dlg do - begin - DefaultExt:= '.xml'; - FileName:= '*.xml'; - Filter:= 'BrewBuddy xml|*.xml'; - end; - FImportFileName:= ''; - try - if (dlg.Execute) and (FileExists(dlg.FileName)) then - begin - FImportFileName:= dlg.FileName; - dlg.Free; - ReadXMLFile(FDoc, FImportFileName); - FRootNode:= FDoc.FindNode(FLabel); - Result:= TRUE; - end; - except - FDoc.Free; - end; -end; - -Procedure TContainer.SortByIndex(Index : integer; Decending : boolean; Nstart, Nend : integer); - procedure QuickSort(var A: array of TBase; iLo, iHi: Integer); - var Lo, Hi: Integer; - v : variant; - TB : TBase; - begin - Lo := iLo; - Hi := iHi; - v:= A[(Lo + Hi) div 2].ValueByIndex[Index]; - repeat - while A[Lo].ValueByIndex[Index] < v do Inc(Lo); - while A[Hi].ValueByIndex[Index] > v do Dec(Hi); - if Lo <= Hi then - begin - TB:= A[Lo]; - A[Lo]:= A[Hi]; - A[Hi]:= TB; - Inc(Lo); - Dec(Hi); - end; - until Lo > Hi; - if Hi > iLo then QuickSort(A, iLo, Hi); - if Lo < iHi then QuickSort(A, Lo, iHi); - end; - - procedure QuickSortDec(var A: array of TBase; iLo, iHi: Integer); - var Lo, Hi: Integer; - v : variant; - TB : TBase; - begin - Lo := iLo; - Hi := iHi; - v:= A[(Lo + Hi) div 2].ValueByIndex[Index]; - repeat - while A[Lo].ValueByIndex[Index] > v do Inc(Lo); - while A[Hi].ValueByIndex[Index] < v do Dec(Hi); - if Lo <= Hi then - begin - TB := A[Lo]; - A[Lo] := A[Hi]; - A[Hi] := TB; - Inc(Lo); - Dec(Hi); - end; - until Lo > Hi; - if Hi > iLo then QuickSortDec(A, iLo, Hi); - if Lo < iHi then QuickSortDec(A, Lo, iHi); - end; - -begin - if (High(FCollection) > 0) and (Index > -1) then - begin - if (NEnd = 0) or (NStart >= NEnd) then - begin - NStart:= Low(FCollection); - NEnd:= High(FCollection); - end; - if Decending then - QuickSortDec(FCollection, NStart, NEnd) - else - QuickSort(FCollection, NStart, NEnd); - end; -end; - -Procedure TContainer.SortByIndex2(I1, I2 : integer; Decending : boolean); -var a, b : integer; - V1 : variant; -begin - SortByIndex(I1, Decending, 0, 0); - a:= 0; b:= 1; - while b <= High(FCollection) do - begin - V1:= FCollection[a].ValueByIndex[I1]; - while (b <= High(FCollection)) and (FCollection[b].ValueByIndex[I1] = V1) do - Inc(b); - if (a < (b-1)) then - SortByIndex(I2, Decending, a, b-1); - a:= b; - end; -end; - -Procedure TContainer.SortByName(s : string); -var i : integer; -begin - if High(FCollection) > -1 then - begin - i:= FCollection[0].IndexByName[s]; - if i > -1 then SortByIndex(i, false, 0, 0); - end; -end; - -Procedure TContainer.FreeCollection; -var i : integer; -begin - for i:= Low(FCollection) to High(FCollection) do - FCollection[i].Free; - SetLength(FCollection, 0); -end; - -Procedure TContainer.SetSelected(i : integer); -begin - if (i >= Low(FCollection)) and (i <= High(FCollection)) then - FSelected:= i; -end; - -Procedure TContainer.UnSelect; -begin - FSelected:= -1; -end; - -Function TContainer.AddItem : TBase; -begin - Result:= NIL; - try - SetLength(FCollection, High(FCollection)+2); - FSelected:= High(FCollection); - Result:= FCollection[FSelected]; -// Result.AutoNr.Value:= MaxAutoNr; - finally - end; -end; - -Procedure TContainer.InsertItem(i : integer); -var j : integer; -begin - if (i >= Low(FCollection)) and (i <= High(FCollection)) then - begin - SetLength(FCollection, High(FCollection)+2); - for j:= High(FCollection) downto i + 1 do - FCollection[j]:= FCollection[j-1]; - end; -end; - -Procedure TContainer.RemoveItem(i : integer); -var j : integer; -begin - if (i >= Low(FCollection)) and (i <= High(FCollection)) then - begin - FCollection[i].Free; - for j:= i to High(FCollection) - 1 do - FCollection[j]:= FCollection[j+1]; - SetLength(FCollection, High(FCollection)); - end; -end; - -Procedure TContainer.RemoveByReference(Item : TBase); -var i : integer; -begin - for i:= Low(FCollection) to High(FCollection) do - if FCollection[i] = Item then - begin - RemoveItem(i); - Exit; - end; -end; - -Function TContainer.FindByName(s : string) : TBase; -var i : integer; -begin - Result:= NIL; - for i:= Low(FCollection) to High(FCollection) do - if Trim(UpperCase(FCollection[i].Name.Value)) = Trim(Uppercase(s)) then - begin - Result:= FCollection[i]; - Exit; - end; -end; - -Function TContainer.FindByNameOnStock(s : string) : TBase; -var i : integer; - ing : TIngredient; -begin - Result:= NIL; - ing:= NIL; - for i:= Low(FCollection) to High(FCollection) do - begin - if FCollection[i] is TIngredient then - begin - if Trim(UpperCase(FCollection[i].Name.Value)) = Trim(Uppercase(s)) then - begin - ing:= TIngredient(FCollection[i]); - if Result = NIL then Result:= ing - else - begin - if ing.Inventory.Value > TIngredient(Result).Inventory.Value then - Result:= ing; - end; - end; - end; - end; -end; - -Function TContainer.IndexByName(s : string) : integer; -var i : integer; -begin - Result:= -1; - for i:= Low(FCollection) to High(FCollection) do - if Trim(UpperCase(FCollection[i].Name.Value)) = Trim(Uppercase(s)) then - begin - Result:= i; - Exit; - end; -end; - -Function TContainer.FindByAutoNr(i : integer) : TBase; -var j : integer; -begin - Result:= NIL; - for j:= 0 to High(FCollection) do - if FCollection[j].AutoNr.Value = i then - begin - Result:= FCollection[j]; - Exit; - end; -end; - -Procedure TContainer.RemoveByAutoNr(i : integer); -var j : integer; -begin - for j:= Low(FCollection) to High(FCollection) do - if FCollection[j].AutoNr.Value = i then - begin - RemoveItem(j); - Exit; - end; -end; - -Function TContainer.GetNumItems : integer; -begin - Result:= High(FCollection) + 1; -end; - -Function TContainer.GetItem(i : integer) : TBase; -begin - Result:= NIL; - if (i >= Low(FCollection)) and (i <= High(FCollection)) then - Result:= FCollection[i]; -end; - - -{=========================== TFermentables ====================================} - -Constructor TFermentables.Create; -begin - Inherited; - FLabel:= 'FERMENTABLES'; - FFileName:= 'fermentables.xml'; -end; - -Procedure TFermentables.SaveXML; -var i : integer; - FN : string; -begin - try - Inherited SaveXML; - FN:= Settings.DataLocation.Value + FFileName; - for i:= Low(FCollection) to High(FCollection) do - TFermentable(FCollection[i]).SaveXML(FDoc, FRootNode, false); - writeXMLFile(FDoc, FN); - finally - FDoc.Free; - end; -end; - -Procedure TFermentables.ReadXML; -var i : integer; -begin - Inherited ReadXML; - if FRootNode <> NIL then - begin - try - i:= 0; - FChild:= FRootNode.FirstChild; - while FChild <> NIL do - begin - inc(i); - SetLength(FCollection, i); - FCollection[i-1]:= TFermentable.Create(NIL); - TFermentable(FCollection[i-1]).ReadXML(FChild); - FChild:= FChild.NextSibling; - end; - finally - FDoc.Free; - end; - end; -end; - -Function TFermentables.ImportXML : boolean; -var i : integer; -begin - Inherited ImportXML; - if FRootNode <> NIL then - begin - try - i:= High(FCollection) + 1; - FChild:= FRootNode.FirstChild; - while FChild <> NIL do - begin - inc(i); - SetLength(FCollection, i); - FCollection[i-1]:= TFermentable.Create(NIL); - TFermentable(FCollection[i-1]).ReadXML(FChild); - if TFermentable(FCollection[i-1]).Yield.Value < 1 then - RemoveByReference(FCollection[i-1]); - FChild:= FChild.NextSibling; - end; - Result:= TRUE; - finally - FDoc.Free; - end; - end; -end; - -Function TFermentables.GetSelectedItem : TFermentable; -begin - Result:= NIL; - if FSelected > -1 then - Result:= TFermentable(FCollection[FSelected]); -end; - -Function TFermentables.AddItem : TFermentable; -begin - Result:= NIL; - try - SetLength(FCollection, High(FCollection)+2); - FSelected:= High(FCollection); - FCollection[High(FCollection)]:= TFermentable.Create(NIL); - Result:= TFermentable(FCollection[High(FCollection)]); - finally - end; -end; - -Procedure TFermentables.InsertItem(i : integer); -begin - Inherited; - if (i >= Low(FCollection)) and (i <= High(FCollection)) then - FCollection[i]:= TFermentable.Create(NIL); -end; - -Function TFermentables.FindByNameAndSupplier(N, S : string) : TFermentable; -var i : integer; -begin - Result:= NIL; - if (N <> '') AND (S <> '') then - begin - for i:= Low(FCollection) to High(FCollection) do - if (Lowercase(TFermentable(FCollection[i]).Name.Value) = Lowercase(N)) and - (Lowercase(TFermentable(FCollection[i]).Supplier.Value) = Lowercase(S)) then - begin - Result:= TFermentable(FCollection[i]); - Exit; - end; - end; -end; - -{================================== THops =====================================} - -Constructor THops.Create; -begin - Inherited; - FLabel:= 'HOPS'; - FFileName:= 'hops.xml'; - FSelected:= -1; -end; - -Procedure THops.SaveXML; -var i : integer; - FN : string; -begin - try - Inherited SaveXML; - for i:= Low(FCollection) to High(FCollection) do - THop(FCollection[i]).SaveXML(FDoc, FRootNode, false); - FN:= Settings.DataLocation.Value + FFileName; - writeXMLFile(FDoc, FN); - finally - FDoc.Free; - end; -end; - -Procedure THops.ReadXML; -var i : integer; -begin - Inherited ReadXML; - if FRootNode <> NIL then - begin - try - i:= 0; - FChild:= FRootNode.FirstChild; - while FChild <> NIL do - begin - inc(i); - SetLength(FCollection, i); - FCollection[i-1]:= THop.Create(NIL); - THop(FCollection[i-1]).ReadXML(FChild); - FChild:= FChild.NextSibling; - end; - finally - FDoc.Free; - end; - end; -end; - -Function THops.ImportXML : boolean; -var i : integer; -begin - Inherited ImportXML; - if FRootNode <> NIL then - begin - try - i:= High(FCollection) + 1; - FChild:= FRootNode.FirstChild; - while FChild <> NIL do - begin - inc(i); - SetLength(FCollection, i); - FCollection[i-1]:= THop.Create(NIL); - THop(FCollection[i-1]).ReadXML(FChild); - if THop(FCollection[i-1]).Alfa.Value <= 0.5 then - RemoveByReference(FCollection[i-1]); - FChild:= FChild.NextSibling; - end; - Result:= TRUE; - finally - FDoc.Free; - end; - end; -end; - -Function THops.GetSelectedItem : THop; -begin - Result:= NIL; - if FSelected > -1 then - Result:= THop(FCollection[FSelected]); -end; - -Function THops.AddItem : THop; -begin - Result:= NIL; - try - SetLength(FCollection, High(FCollection)+2); - FSelected:= High(FCollection); - Result:= NIL; - FCollection[High(FCollection)]:= THop.Create(NIL); - Result:= THop(FCollection[FSelected]); - finally - end; -end; - -Procedure THops.InsertItem(i : integer); -begin - Inherited; - if (i >= Low(FCollection)) and (i <= High(FCollection)) then - FCollection[i]:= THop.Create(NIL); -end; - -Function THops.FindByNameAndOriginAndAlfa(N, O : string; A : double) : THop; -var i : integer; - A2 : double; - N2, O2 : string; -begin - Result:= NIL; - N:= LowerCase(Trim(N)); - O:= LowerCase(Trim(O)); - A:= RoundTo(A, -1); - if (N <> '') AND (O <> '') then - begin - for i:= Low(FCollection) to High(FCollection) do - begin - N2:= Lowercase(Trim(THop(FCollection[i]).Name.Value)); - O2:= Lowercase(Trim(THop(FCollection[i]).Origin.Value)); - A2:= THop(FCollection[i]).Alfa.Value; - A2:= RoundTo(A2, -1); - if (N2 = N) and (O2 = O) and (A2 = A) then - begin - Result:= THop(FCollection[i]); - Exit; - end; - end; - end; -end; - -{================================== TMiscs ====================================} - -Constructor TMiscs.Create; -begin - Inherited; - FLabel:= 'MISCS'; - FFileName:= 'miscs.xml'; - FSelected:= -1; -end; - -Procedure TMiscs.SaveXML; -var i : integer; - FN : string; -begin - try - Inherited SaveXML; - FN:= Settings.DataLocation.Value + FFileName; - for i:= Low(FCollection) to High(FCollection) do - TMisc(FCollection[i]).SaveXML(FDoc, FRootNode, false); - writeXMLFile(FDoc, FN); - finally - FDoc.Free; - end; -end; - -Procedure TMiscs.ReadXML; -var i : integer; -begin - Inherited ReadXML; - if FRootNode <> NIL then - begin - try - i:= 0; - FChild:= FRootNode.FirstChild; - while FChild <> NIL do - begin - inc(i); - SetLength(FCollection, i); - FCollection[i-1]:= TMisc.Create(NIL); - TMisc(FCollection[i-1]).ReadXML(FChild); - FChild:= FChild.NextSibling; - end; - finally - FDoc.Free; - end; - end; -end; - -Function TMiscs.ImportXML : boolean; -var i : integer; -begin - Inherited ImportXML; - if FRootNode <> NIL then - begin - try - i:= High(FCollection) + 1; - FChild:= FRootNode.FirstChild; - while FChild <> NIL do - begin - inc(i); - SetLength(FCollection, i); - FCollection[i-1]:= TMisc.Create(NIL); - TMisc(FCollection[i-1]).ReadXML(FChild); - {if TMisc(FCollection[i-1])..Value < 1 then - RemoveByReference(FCollection[i-1]);} - FChild:= FChild.NextSibling; - end; - Result:= TRUE; - finally - FDoc.Free; - end; - end; -end; - -Function TMiscs.GetSelectedItem : TMisc; -begin - Result:= NIL; - if FSelected > -1 then - Result:= TMisc(FCollection[FSelected]); -end; - -Function TMiscs.AddItem : TMisc; -begin - Result:= NIL; - try - SetLength(FCollection, High(FCollection)+2); - FSelected:= High(FCollection); - FCollection[High(FCollection)]:= TMisc.Create(NIL); - Result:= TMisc(FCollection[High(FCollection)]); - finally - end; -end; - -Procedure TMiscs.InsertItem(i : integer); -begin - Inherited; - if (i >= Low(FCollection)) and (i <= High(FCollection)) then - FCollection[i]:= TMisc.Create(NIL); -end; - -{================================== TYeasts ===================================} - -Constructor TYeasts.Create; -begin - Inherited; - FLabel:= 'YEASTS'; - FFileName:= 'yeasts.xml'; - FSelected:= -1; -end; - -Procedure TYeasts.SaveXML; -var i : integer; - FN : string; -begin - try - Inherited SaveXML; - FN:= Settings.DataLocation.Value + FFileName; - for i:= Low(FCollection) to High(FCollection) do - TYeast(FCollection[i]).SaveXML(FDoc, FRootNode, false); - writeXMLFile(FDoc, FN); - finally - FDoc.Free; - end; -end; - -Procedure TYeasts.ReadXML; -var i : integer; -begin - Inherited ReadXML; - if FRootNode <> NIL then - begin - try - i:= 0; - FChild:= FRootNode.FirstChild; - while FChild <> NIL do - begin - inc(i); - SetLength(FCollection, i); - FCollection[i-1]:= TYeast.Create(NIL); - TYeast(FCollection[i-1]).ReadXML(FChild); - FChild:= FChild.NextSibling; - end; - finally - FDoc.Free; - end; - end; -end; - -Function TYeasts.ImportXML : boolean; -var i : integer; -begin - Inherited ImportXML; - if FRootNode <> NIL then - begin - try - i:= High(FCollection) + 1; - FChild:= FRootNode.FirstChild; - while FChild <> NIL do - begin - inc(i); - SetLength(FCollection, i); - FCollection[i-1]:= TYeast.Create(NIL); - TYeast(FCollection[i-1]).ReadXML(FChild); - if TYeast(FCollection[i-1]).Laboratory.Value = '' then - RemoveByReference(FCollection[i-1]); - FChild:= FChild.NextSibling; - end; - Result:= TRUE; - finally - FDoc.Free; - end; - end; -end; -Function TYeasts.GetSelectedItem : TYeast; -begin - Result:= NIL; - if FSelected > -1 then - Result:= TYeast(FCollection[FSelected]); -end; - -Function TYeasts.AddItem : TYeast; -begin - Result:= NIL; - try - SetLength(FCollection, High(FCollection)+2); - FSelected:= High(FCollection); - FCollection[High(FCollection)]:= TYeast.Create(NIL); - Result:= TYeast(FCollection[High(FCollection)]); - finally - end; -end; - -Procedure TYeasts.InsertItem(i : integer); -begin - Inherited; - if (i >= Low(FCollection)) and (i <= High(FCollection)) then - FCollection[i]:= TYeast.Create(NIL); -end; - -Function TYeasts.FindByNameAndLaboratory(N, L : string) : TYeast; -var i : integer; -begin - Result:= NIL; - if (N <> '') and (L <> '') then - begin - for i:= Low(FCollection) to High(FCollection) do - if (Lowercase(TYeast(FCollection[i]).Name.Value) = Lowercase(N)) and - (Lowercase(TYeast(FCollection[i]).Laboratory.Value) = Lowercase(L)) then - begin - Result:= TYeast(FCollection[i]); - Exit; - end; - end; -end; - -{================================== TWaters ===================================} - -Constructor TWaters.Create; -begin - Inherited; - FLabel:= 'WATERS'; - FFileName:= 'waters.xml'; - FSelected:= -1; -end; - -Procedure TWaters.SaveXML; -var i : integer; - FN : string; -begin - try - Inherited SaveXML; - FN:= Settings.DataLocation.Value + FFileName; - for i:= Low(FCollection) to High(FCollection) do - TWater(FCollection[i]).SaveXML(FDoc, FRootNode, false); - writeXMLFile(FDoc, FN); - finally - FDoc.Free; - end; -end; - -Procedure TWaters.ReadXML; -var i : integer; -begin - Inherited ReadXML; - if FRootNode <> NIL then - begin - try - i:= 0; - FChild:= FRootNode.FirstChild; - while FChild <> NIL do - begin - inc(i); - SetLength(FCollection, i); - FCollection[i-1]:= TWater.Create(NIL); - TWater(FCollection[i-1]).ReadXML(FChild); - FChild:= FChild.NextSibling; - end; - finally - FDoc.Free; - end; - end; -end; - -Function TWaters.ImportXML : boolean; -var i : integer; -begin - Inherited ImportXML; - if FRootNode <> NIL then - begin - try - i:= High(FCollection) + 1; - FChild:= FRootNode.FirstChild; - while FChild <> NIL do - begin - inc(i); - SetLength(FCollection, i); - FCollection[i-1]:= TWater.Create(NIL); - TWater(FCollection[i-1]).ReadXML(FChild); - if TWater(FCollection[i-1]).Bicarbonate.Value < 0.1 then - RemoveByReference(FCollection[i-1]); - FChild:= FChild.NextSibling; - end; - Result:= TRUE; - finally - FDoc.Free; - end; - end; -end; - -Function TWaters.GetSelectedItem : TWater; -begin - Result:= NIL; - if FSelected > -1 then - Result:= TWater(FCollection[FSelected]); -end; - -Function TWaters.AddItem : TWater; -begin - Result:= NIL; - try - SetLength(FCollection, High(FCollection)+2); - FSelected:= High(FCollection); - FCollection[High(FCollection)]:= TWater.Create(NIL); - Result:= TWater(FCollection[High(FCollection)]); - finally - end; -end; - -Procedure TWaters.InsertItem(i : integer); -begin - Inherited; - if (i >= Low(FCollection)) and (i <= High(FCollection)) then - FCollection[i]:= TWater.Create(NIL); -end; - -Function TWaters.GetDefaultWater : TWater; -var i : integer; - W : TWater; -begin - Result:= NIL; - for i:= 0 to NumItems - 1 do - begin - W:= TWater(Item[i]); - if W.DefaultWater.Value then Result:= W; - end; -end; - -Function TWaters.GetDemiWater : TWater; -var i : integer; - W : TWater; -begin - Result:= NIL; - for i:= 0 to NumItems - 1 do - begin - W:= TWater(Item[i]); - if W.DemiWater then Result:= W; - end; - if Result = NIL then - W:= TWater(FindByName('Gedemineraliseerd water')); - if Result = NIL then - W:= TWater(FindByName('Demiwater')); - if Result = NIL then - W:= TWater(FindByName('Osmosewater')); -end; - -{================================== TBeerstyles ===============================} - -Constructor TBeerstyles.Create; -begin - Inherited; - FLabel:= 'STYLES'; - FFileName:= 'styles.xml'; - FSelected:= -1; -end; - -Procedure TBeerstyles.SaveXML; -var i : integer; - FN : string; -begin - try - Inherited SaveXML; - FN:= Settings.DataLocation.Value + FFileName; - for i:= Low(FCollection) to High(FCollection) do - TBeerstyle(FCollection[i]).SaveXML(FDoc, FRootNode, false); - writeXMLFile(FDoc, FN); - finally - FDoc.Free; - end; -end; - -Procedure TBeerstyles.ReadXML; -var i : integer; -begin - Inherited ReadXML; - if FRootNode <> NIL then - begin - try - i:= 0; - FChild:= FRootNode.FirstChild; - while FChild <> NIL do - begin - inc(i); - SetLength(FCollection, i); - FCollection[i-1]:= TBeerStyle.Create(NIL); - TBeerStyle(FCollection[i-1]).ReadXML(FChild); - FChild:= FChild.NextSibling; - end; - finally - FDoc.Free; - end; - end; -end; - -Function TBeerstyles.ImportXML : boolean; -var i : integer; -begin - Inherited ImportXML; - if FRootNode <> NIL then - begin - try - i:= High(FCollection) + 1; - FChild:= FRootNode.FirstChild; - while FChild <> NIL do - begin - inc(i); - SetLength(FCollection, i); - FCollection[i-1]:= TBeerstyle.Create(NIL); - TBeerstyle(FCollection[i-1]).ReadXML(FChild); - if TBeerstyle(FCollection[i-1]).StyleLetter.Value = '' then - RemoveByReference(FCollection[i-1]); - FChild:= FChild.NextSibling; - end; - Result:= TRUE; - finally - FDoc.Free; - end; - end; -end; -Function TBeerstyles.GetSelectedItem : TBeerstyle; -begin - Result:= NIL; - if FSelected > -1 then - Result:= TBeerstyle(FCollection[FSelected]); -end; - -Function TBeerstyles.AddItem : TBeerStyle; -begin - Result:= NIL; - try - SetLength(FCollection, High(FCollection)+2); - FSelected:= High(FCollection); - FCollection[High(FCollection)]:= TBeerstyle.Create(NIL); - Result:= TBeerstyle(FCollection[High(FCollection)]); - finally - end; -end; - -Procedure TBeerstyles.InsertItem(i : integer); -begin - Inherited; - if (i >= Low(FCollection)) and (i <= High(FCollection)) then - FCollection[i]:= TBeerstyle.Create(NIL); -end; - -{================================== TEquipments ===============================} - -Constructor TEquipments.Create; -begin - Inherited; - FLabel:= 'EQUIPMENTS'; - FFileName:= 'equipments.xml'; - FSelected:= -1; -end; - -Procedure TEquipments.SaveXML; -var i : integer; - FN : string; -begin - try - Inherited SaveXML; - FN:= Settings.DataLocation.Value + FFileName; - for i:= Low(FCollection) to High(FCollection) do - TEquipment(FCollection[i]).SaveXML(FDoc, FRootNode, false); - writeXMLFile(FDoc, FN); - finally - FDoc.Free; - end; -end; - -Procedure TEquipments.ReadXML; -var i : integer; -begin - Inherited ReadXML; - if FRootNode <> NIL then - begin - try - i:= 0; - FChild:= FRootNode.FirstChild; - while FChild <> NIL do - begin - inc(i); - SetLength(FCollection, i); - FCollection[i-1]:= TEquipment.Create(NIL); - TEquipment(FCollection[i-1]).ReadXML(FChild); - FChild:= FChild.NextSibling; - end; - finally - FDoc.Free; - end; - end; -end; - -Function TEquipments.GetSelectedItem : TEquipment; -begin - Result:= NIL; - if FSelected > -1 then - Result:= TEquipment(FCollection[FSelected]); -end; - -Function TEquipments.AddItem : TEquipment; -begin - Result:= NIL; - try - SetLength(FCollection, High(FCollection)+2); - FSelected:= High(FCollection); - FCollection[High(FCollection)]:= TEquipment.Create(NIL); - Result:= TEquipment(FCollection[High(FCollection)]); - finally - end; -end; - -Procedure TEquipments.InsertItem(i : integer); -begin - Inherited; - if (i >= Low(FCollection)) and (i <= High(FCollection)) then - FCollection[i]:= TEquipment.Create(NIL); -end; - -Procedure TEquipments.CalcEfficiencyRegressionFactors; -var i : integer; -begin - for i:= Low(FCollection) to High(FCollection) do - TEquipment(FCollection[i]).CalcEfficiencyFactors; -end; - -Procedure TEquipments.CalcAttenuationRegressionFactors; -var i : integer; -begin - for i:= Low(FCollection) to High(FCollection) do - TEquipment(FCollection[i]).CalcAttenuationFactors; -end; - -{================================== TMashs ====================================} - -Constructor TMashs.Create; -begin - Inherited; - FLabel:= 'MASHS'; - FFileName:= 'mashs.xml'; - FSelected:= -1; -end; - -Procedure TMashs.SaveXML; -var i : integer; - FN : string; -begin - try - Inherited SaveXML; - FN:= Settings.DataLocation.Value + FFileName; - for i:= Low(FCollection) to High(FCollection) do - TMash(FCollection[i]).SaveXML(FDoc, FRootNode, false); - writeXMLFile(FDoc, FN); - finally - FDoc.Free; - end; -end; - -Procedure TMashs.ReadXML; -var i : integer; -begin - Inherited ReadXML; - if FRootNode <> NIL then - begin - try - i:= 0; - FChild:= FRootNode.FirstChild; - while FChild <> NIL do - begin - inc(i); - SetLength(FCollection, i); - FCollection[i-1]:= TMash.Create(NIL); - TMash(FCollection[i-1]).ReadXML(FChild); - FChild:= FChild.NextSibling; - end; - finally - FDoc.Free; - end; - end; -end; - -Function TMashs.ImportXML : boolean; -var i : integer; -begin - Inherited ImportXML; - if FRootNode <> NIL then - begin - try - i:= High(FCollection) + 1; - FChild:= FRootNode.FirstChild; - while FChild <> NIL do - begin - inc(i); - SetLength(FCollection, i); - FCollection[i-1]:= TMash.Create(NIL); - TMash(FCollection[i-1]).ReadXML(FChild); - if TMash(FCollection[i-1]).NumMashSteps = 0 then - RemoveByReference(FCollection[i-1]); - FChild:= FChild.NextSibling; - end; - Result:= TRUE; - finally - FDoc.Free; - end; - end; -end; - -Function TMashs.GetSelectedItem : TMash; -begin - Result:= NIL; - if FSelected > -1 then - Result:= TMash(FCollection[FSelected]); -end; - -Function TMashs.AddItem : TMash; -begin - Result:= NIL; - try - SetLength(FCollection, High(FCollection)+2); - FSelected:= High(FCollection); - FCollection[High(FCollection)]:= TMash.Create(NIL); - Result:= TMash(FCollection[High(FCollection)]); - finally - end; -end; - -Procedure TMashs.InsertItem(i : integer); -begin - Inherited; - if (i >= Low(FCollection)) and (i <= High(FCollection)) then - FCollection[i]:= TMash.Create(NIL); -end; - -{================================== TRecipes ==================================} - - -Constructor TRecipes.Create; -begin - Inherited; - FLabel:= 'RECIPES'; - FFileName:= 'recipes.xml'; - FSelected:= -1; - SetLength(FFermentablesMinMaxArray, 0); - SetLength(FBitterhopMinMaxArray, 0); - SetLength(FAromahopMinMaxArray, 0); - SetLength(FDryhopMinMaxArray, 0); - SetLength(FYeastMinMaxArray, 0); - SetLength(FMiscMinMaxArray, 0); - SetLength(FCommonMinMaxArray, 0); -end; - -Destructor TRecipes.Destroy; -begin - SetLength(FFermentablesMinMaxArray, 0); - SetLength(FBitterhopMinMaxArray, 0); - SetLength(FAromahopMinMaxArray, 0); - SetLength(FDryhopMinMaxArray, 0); - SetLength(FYeastMinMaxArray, 0); - SetLength(FMiscMinMaxArray, 0); - SetLength(FCommonMinMaxArray, 0); - Inherited; -end; - -Procedure TRecipes.SaveXML; -var i : integer; - FN : string; -begin - try - Inherited SaveXML; - FN:= Settings.DataLocation.Value + FFileName; - for i:= Low(FCollection) to High(FCollection) do - begin - TRecipe(FCollection[i]).SaveXML(FDoc, FRootNode, false); - Application.ProcessMessages; - end; - writeXMLFile(FDoc, FN); - finally - FDoc.Free; - end; -end; - -Procedure TRecipes.ReadXML; -var i : integer; - R : TRecipe; -begin - Inherited ReadXML; - if FRootNode <> NIL then - begin - try - i:= 0; - FChild:= FRootNode.FirstChild; - while FChild <> NIL do - begin - inc(i); - SetLength(FCollection, i); - Application.ProcessMessages; - FCollection[i-1]:= TRecipe.Create(NIL); - R:= TRecipe(FCollection[i-1]); - if FFileName = 'brews.xml' then R.RecType:= rtBrew - else if FFileName = 'recipes.xml' then R.RecType:= rtRecipe - else R.RecType:= rtCloud; - R.ReadXML(FChild); - FChild:= FChild.NextSibling; - end; - finally - FDoc.Free; - end; - end; -end; - -Function TRecipes.FindByNameAndNr(Nm, Nr : string) : TRecipe; -var i : integer; - R : TRecipe; -begin - Result:= NIL; - Nm:= Lowercase(Nm); - Nr:= Lowercase(Nr); - for i:= 0 to High(FCollection) do - begin - R:= TRecipe(FCollection[i]); - if (Lowercase(R.NrRecipe.Value) = Nr) and (Lowercase(R.Name.Value) = Nm) then - begin - Result:= R; - Exit; - end; - end; -end; - -Function TRecipes.FindByAutoNr(nr : integer) : TRecipe; -var i : integer; - R : TRecipe; -begin - Result:= NIL; - for i:= 0 to High(FCollection) do - begin - R:= TRecipe(FCollection[i]); - if (R.AutoNr.Value = Nr) then - begin - Result:= R; - Exit; - end; - end; -end; - -Procedure TRecipes.CheckAutoNrs; -var i, maxnr : integer; - R : TRecipe; -begin - maxnr:= MaxAutoNr; - for i:= Low(FCollection) to High(FCollection) do - begin - R:= TRecipe(FCollection[i]); - if R.AutoNr.Value = 0 then - begin - inc(maxnr); - R.AutoNr.Value:= maxnr; - end; - end; -end; - -Function TRecipes.ImportFiles(FN : TStrings; DN : string; Equip : TEquipment; - FT : TFileType) : boolean; -begin - Result:= false; - case FT of - ftXML: Result:= ImportXMLs(FN, DN, Equip); - ftPromash: Result:= ImportRECs(FN, DN, Equip); - ftInvalid: Result:= false; - end; - SaveXML; -end; - -Function TRecipes.ImportXMLs(FN : TStrings; DN : string; Equip : TEquipment) : boolean; -var SL : TStringList; - i : integer; - mask : string; - ps : TProgressBar; -begin - Result:= false; - if DN <> '' then - begin - try - Screen.Cursor:= crHourglass; - {$ifdef WINDOWS} - mask:= '*.xml'; - {$else} - mask:= '*xml'; - {$endif} - SL:= FindAllFiles(DN, mask, false); -{ FrmMain.sbMain.Panels[0].Text:= 'Importeren...'; - ps:= TProgressBar.Create(FrmMain.sbMain); - ps.Parent:= FrmMain.sbMain; - ps.Left:= FrmMain.sbMain.Panels[0].Width + 1; - ps.Width:= FrmMain.sbMain.Panels[1].Width; - ps.Min:= 0; - ps.Max:= SL.Count - 1; - ps.Position:= 0;} - for i:= 0 to SL.Count - 1 do - begin - ImportXML(SL[i], Equip); -// ps.Position:= i; - Application.ProcessMessages; - end; - Result:= TRUE; - finally - Screen.Cursor:= crDefault; -// ps.Free; - SL.Free; -// FrmMain.sbMain.Panels[0].Text:= ''; - ShowMessage('Importeren klaar'); - end; - end - else - begin - for i:= 0 to FN.Count - 1 do - begin - Result:= ImportXML(FN[i], Equip); - end; - end; -end; - -Function TRecipes.GetMaxAutoNr : integer; -var i : integer; -begin - Result:= 0; - for i:= Low(FCollection) to High(FCollection) do - if TRecipe(FCollection[i]).AutoNr.Value > Result then - Result:= TRecipe(FCollection[i]).AutoNr.Value; -end; - -Function TRecipes.ImportXML(FN : string; Equip : TEquipment) : boolean; -var R : TRecipe; - s : string; -begin - Result:= false; - FDoc := TXMLDocument.Create; - FRootNode:= NIL; - try - if FileExists(FN) then - begin - ReadXMLFile(FDoc, FN); - s:= ExtractFileNameOnly(FN); - FRootNode:= FDoc.FindNode(FLabel); - if FRootNode <> NIL then - begin - FChild:= FRootNode.FirstChild; - while FChild <> NIL do - begin - R:= AddItem; - Application.ProcessMessages; - R.ReadXML(FChild); - R.AutoNr.Value:= GetMaxAutoNr + 1; - R.ParentAutoNr.Value:= ''; - - CheckBeerStyle(R); - CheckFermentables(R); - CheckYeasts(R); - - //change the equipment - if Equip <> NIL then R.ChangeEquipment(Equip) - else R.RemoveNonBrewsData; - - if FFileName = 'brews.xml' then R.RecType:= rtBrew - else if FFileName = 'recipes.xml' then R.RecType:= rtRecipe - else R.RecType:= rtCloud; - - FChild:= FChild.NextSibling; - Result:= TRUE; - end; - end; - end; - finally - FDoc.Free; - end; -end; - -Function TRecipes.ImportRECs(FN : TStrings; DN : string; Equip : TEquipment) : boolean; -var SL : TStringList; - i : integer; - mask : string; - ps : TProgressBar; -begin - Result:= false; - if DN <> '' then - begin - try - Screen.Cursor:= crHourglass; - {$ifdef WINDOWS} - mask:= '*.rec'; - {$else} - mask:= '*rec'; - {$endif} - SL:= FindAllFiles(DN, mask, false); -{ FrmMain.sbMain.Panels[0].Text:= 'Importeren...'; - ps:= TProgressBar.Create(FrmMain.sbMain); - ps.Parent:= FrmMain.sbMain; - ps.Left:= FrmMain.sbMain.Panels[0].Width + 1; - ps.Width:= FrmMain.sbMain.Panels[1].Width; - ps.Min:= 0; - ps.Max:= SL.Count - 1; - ps.Position:= 0;} - for i:= 0 to SL.Count - 1 do - begin - ImportREC(SL[i], Equip); -// ps.Position:= i; - Application.ProcessMessages; - end; - Result:= TRUE; - finally - Screen.Cursor:= crDefault; -// ps.Free; - SL.Free; -// FrmMain.sbMain.Panels[0].Text:= ''; - ShowMessage('Importeren klaar'); - end; - end - else - for i:= 0 to FN.Count - 1 do - begin - Result:= ImportREC(FN[i], Equip); - end; -end; - -Function TRecipes.ImportREC(FN : string; Equip : TEquipment) : boolean; -var PI : TPromash; - R : TRecipe; - s : string; -begin - Result:= false; - PI := TPromash.Create(FrmMain); - try - FN:= ConvertStringEnc(FN); - if FileExists(FN) then - begin - if PI.OpenReadRec(FN) then - begin - R:= AddItem; - if R <> NIL then - begin - PI.Convert(R); - s:= R.Style.Name.Value; - R.AutoNr.Value:= MaxAutoNr + 1; - - CheckBeerStyle(R); - CheckFermentables(R); - CheckYeasts(R); - - //change the equipment - if Equip <> NIL then - R.ChangeEquipment(Equip); - - if FFileName = 'brews.xml' then R.RecType:= rtBrew - else if FFileName = 'recipes.xml' then R.RecType:= rtRecipe - else R.RecType:= rtCloud; - - Result:= TRUE; - end; - end; - end; - finally - PI.Free; - end; -end; - -Procedure TRecipes.QuickSortRecipes(var Arr : array of TBase); - procedure QuickSort(var A: array of TBase; iLo, iHi: Integer); - var Lo, Hi: Integer; - s : string; - T : TRecipe; - begin - Lo := iLo; - Hi := iHi; - s:= TRecipe(A[(Lo + Hi) div 2]).NrRecipe.Value; - repeat - while TRecipe(A[Lo]).NrRecipe.Value < s do Inc(Lo); - while TRecipe(A[Hi]).NrRecipe.Value > s do Dec(Hi); - if Lo <= Hi then - begin - T := TRecipe(A[Lo]); - TRecipe(A[Lo]) := TRecipe(A[Hi]); - TRecipe(A[Hi]) := T; - Inc(Lo); - Dec(Hi); - end; - until Lo > Hi; - if Hi > iLo then QuickSort(A, iLo, Hi); - if Lo < iHi then QuickSort(A, Lo, iHi); - end; -begin - if High(Arr) > -1 then QuickSort(Arr, Low(Arr), High(Arr)); -end; - -Procedure TRecipes.Sort; -begin - QuickSortRecipes(FCollection); -end; - -Function TRecipes.GetLastNrRecipe : string; -begin - Sort; - Result:= ''; - if High(FCollection) >= 0 then - Result:= TRecipe(FCollection[High(FCollection)]).NrRecipe.Value; -end; - -Function TRecipes.GetSelectedItem : TRecipe; -begin - Result:= NIL; - if FSelected > -1 then - Result:= TRecipe(FCollection[FSelected]); -end; - -Function TRecipes.AddItem : TRecipe; -begin - Result:= NIL; - try - SetLength(FCollection, High(FCollection)+2); - FSelected:= High(FCollection); - FCollection[High(FCollection)]:= TRecipe.Create(NIL); - Result:= TRecipe(FCollection[High(FCollection)]); - finally - end; -end; - -Procedure TRecipes.InsertItem(i : integer); -var R : TRecipe; -begin - Inherited; - if (i >= Low(FCollection)) and (i <= High(FCollection)) then - begin - FCollection[i]:= TRecipe.Create(NIL); - R:= TRecipe(FCollection[i]); - if FFileName = 'brews.xml' then R.RecType:= rtBrew - else if FFileName = 'recipes.xml' then R.RecType:= rtRecipe - else R.RecType:= rtCloud; - end; -end; - -Function TRecipes.ExportToCSV(A : array of longint) : boolean; -var i, j : integer; - dlg : TSaveDialog; - SL : TStringList; - line : string; - R : TRecipe; -begin - Result:= false; - dlg:= TSaveDialog.Create(frmMain); - if High(FCollection) > 0 then - try - SL:= TStringList.Create; - SL.Sorted:= false; - with dlg do - begin - DefaultExt:= '.csv'; - FileName:= '*.csv'; - Filter:= 'Comma separated values|*.csv'; - if dlg.Execute then - begin - R:= TRecipe(FCollection[0]); - Line:= 'Code;Nr;Naam;Gist naam;'; - for j:= Low(A) to High(A) do - begin - line:= line + R.GetNumberNameByIndex(A[j]); - if j < High(A) then line:= line + ';'; - end; - SL.Add(line); - for i:= Low(FCollection) to High(FCollection) do - begin - line:= ''; - R:= TRecipe(FCollection[i]); - line:= R.NrRecipe.Value + ';'; - line:= line + R.Name.Value + ';'; - line:= line + R.Yeast[0].Name.Value + ';'; - for j:= Low(A) to High(A) do - begin - line:= line + VarToStr(R.GetNumberByIndex(A[j])); - if j < High(A) then line:= line + ';'; - end; - SL.Add(line); - end; - SL.SaveToFile(dlg.FileName); - end; - end; - Result:= TRUE; - finally - dlg.Free; - SL.Free; - end; -end; - -Procedure TRecipes.QuickSortA(var Arr : array of TMinMax); - procedure QuickSort(var A: array of TMinMax; iLo, iHi: Integer); - var Lo, Hi: Integer; - s : single; - T : TMinMax; - begin - Lo := iLo; - Hi := iHi; - s:= A[(Lo + Hi) div 2].PercRecipes; - repeat - while A[Lo].PercRecipes > s do Inc(Lo); - while A[Hi].PercRecipes < s do Dec(Hi); - if Lo <= Hi then - begin - T := A[Lo]; - A[Lo] := A[Hi]; - A[Hi] := T; - Inc(Lo); - Dec(Hi); - end; - until Lo > Hi; - if Hi > iLo then QuickSort(A, iLo, Hi); - if Lo < iHi then QuickSort(A, Lo, iHi); - end; -begin - if High(Arr) > -1 then QuickSort(Arr, Low(Arr), High(Arr)); -end; - -Function TRecipes.Exists(Arr : TMinMaxArray; FName : string) : integer; -var n : integer; -begin - Result:= -1; - for n:= Low(Arr) to High(Arr) do - if Arr[n].Name = FName then - begin - Result:= n; - Exit; - end; -end; - -Function TRecipes.AnalyseFermentables(Lett, Nm : string) : integer; //returns number of recipes -var i, j, k : integer; - R : TRecipe; - F : TFermentable; - FN : string; -begin - Result:= 0; - SetLength(FFermentablesMinMaxArray, 0); - for i:= Low(FCollection) to High(FCollection) do - begin - R:= TRecipe(FCollection[i]); - if (R.Style <> NIL) and - ((LowerCase(R.Style.StyleLetter.Value) = LowerCase(Lett)) and - (Lowercase(R.Style.Name.Value) = Lowercase(Nm))) then - begin - Inc(Result); - R.CalcOG; - for j:= 0 to R.NumFermentables - 1 do - begin - F:= R.Fermentable[j]; - FN:= F.Name.Value; - k:= Exists(FFermentablesMinMaxArray, FN); - if k = -1 then - begin - SetLength(FFermentablesMinMaxArray, High(FFermentablesMinMaxArray) + 2); - k:= High(FFermentablesMinMaxArray); - FFermentablesMinMaxArray[k].Name:= FN; - FFermentablesMinMaxArray[k].PercRecipes:= 1; - FFermentablesMinMaxArray[k].MinUse:= F.Percentage.Value; - FFermentablesMinMaxArray[k].AvUse:= F.Percentage.Value; - FFermentablesMinMaxArray[k].MaxUse:= F.Percentage.Value; - end - else - begin - //temporarily store the number of recipes with this ingredient in PercRecipes - FFermentablesMinMaxArray[k].PercRecipes:= FFermentablesMinMaxArray[k].PercRecipes + 1; - FFermentablesMinMaxArray[k].AvUse:= FFermentablesMinMaxArray[k].AvUse + F.Percentage.Value; - if F.Percentage.Value < FFermentablesMinMaxArray[k].MinUse then - FFermentablesMinMaxArray[k].MinUse:= F.Percentage.Value; - if F.Percentage.Value > FFermentablesMinMaxArray[k].MaxUse then - FFermentablesMinMaxArray[k].MaxUse:= F.Percentage.Value; - end; - end; - end; - end; - if (High(FCollection) >= 0) then - begin - for i:= Low(FFermentablesMinMaxArray) to High(FFermentablesMinMaxArray) do - begin - if FFermentablesMinMaxArray[i].PercRecipes > 0 then - FFermentablesMinMaxArray[i].AvUse:= FFermentablesMinMaxArray[i].AvUse / FFermentablesMinMaxArray[i].PercRecipes - else - FFermentablesMinMaxArray[i].AvUse:= 0; - if Result > 0 then - FFermentablesMinMaxArray[i].PercRecipes:= 100 * FFermentablesMinMaxArray[i].PercRecipes / Result - else - FFermentablesMinMaxArray[i].PercRecipes:= 0; - end; - QuickSortA(FFermentablesMinMaxArray); - end; -end; - -Function TRecipes.AnalyseHops(Lett, Nm : string) : integer; //returns number of recipes -type - THR = record - name : string; - conc : double; - end; -var i, j, k : integer; - R : TRecipe; - H : THop; - FN : string; - conc : double; - HRAB, HRAA, HRAD : array of THR; - function FindHR(var HRA : array of THR; nm : string) : integer; - var n : integer; - begin - Result:= -1; - for n:= Low(HRA) to High(HRA) do - if HRA[n].name = nm then - begin - Result:= n; - Exit; - end; - end; - Procedure FillArrays(var MMA : TMinMaxArray; HRA : array of THR); - var j : integer; - begin - for j:= 0 to High(HRA) do - begin - k:= Exists(MMA, HRA[j].Name); - if k = -1 then - begin - SetLength(MMA, High(MMA) + 2); - k:= High(MMA); - MMA[k].Name:= HRA[j].Name; - MMA[k].PercRecipes:= 1; - MMA[k].MinUse:= HRA[j].Conc; - MMA[k].AvUse:= MMA[k].MinUse; - MMA[k].MaxUse:= MMA[k].MinUse; - end - else - begin - //temporarily store the number of recipes with this ingredient in PercRecipes - MMA[k].PercRecipes:= MMA[k].PercRecipes + 1; - MMA[k].AvUse:= MMA[k].AvUse + HRA[j].Conc; - if HRA[j].Conc < MMA[k].MinUse then - MMA[k].MinUse:= HRA[j].Conc; - if HRA[j].Conc > MMA[k].MaxUse then - MMA[k].MaxUse:= HRA[j].Conc; - end; - end; - end; - -begin - Result:= 0; - SetLength(FBitterhopMinMaxArray, 0); - SetLength(FAromahopMinMaxArray, 0); - SetLength(FDryhopMinMaxArray, 0); - SetLength(HRAB, 0); - SetLength(HRAA, 0); - SetLength(HRAD, 0); - for i:= Low(FCollection) to High(FCollection) do - begin - R:= TRecipe(FCollection[i]); - if (R.Style <> NIL) and - ((LowerCase(R.Style.StyleLetter.Value) = LowerCase(Lett)) and - (Lowercase(R.Style.Name.Value) = Lowercase(Nm))) then - begin - Inc(Result); - for j:= 0 to R.NumHops - 1 do - begin - H:= R.Hop[j]; - FN:= H.Name.Value; - if (H.Use = huBoil) or (H.Use = huAroma) or (H.Use = huFirstWort) - or (H.Use = huWhirlpool) then - begin - if H.Time.Value > 30 then - begin - conc:= H.BitternessContribution; - k:= FindHR(HRAB, FN); - if k = -1 then - begin - SetLength(HRAB, High(HRAB) + 2); - k:= High(HRAB); - HRAB[k].Name:= FN; - HRAB[k].Conc:= 0; - end; - HRAB[k].Conc:= HRAB[k].Conc + conc; - end - else if R.BatchSize.DisplayValue > 0 then - begin - Conc:= H.Amount.DisplayValue / R.BatchSize.DisplayValue; - k:= FindHR(HRAA, FN); - if k = -1 then - begin - SetLength(HRAA, High(HRAA) + 2); - k:= High(HRAA); - HRAA[k].Name:= FN; - HRAA[k].Conc:= 0; - end; - HRAA[k].Conc:= HRAA[k].Conc + conc; - end; - end - else if H.Use = huDryhop then - begin - if R.BatchSize.DisplayValue > 0 then - begin - conc:= H.Amount.DisplayValue / R.BatchSize.DisplayValue; - k:= FindHR(HRAD, FN); - if k = -1 then - begin - SetLength(HRAD, High(HRAD) + 2); - k:= High(HRAD); - HRAD[k].Name:= FN; - HRAD[k].Conc:= 0; - end; - HRAD[k].Conc:= HRAD[k].Conc + conc; - end; - end; - end; - - FillArrays(FBitterhopMinMaxArray, HRAB); - FillArrays(FAromahopMinMaxArray, HRAA); - FillArrays(FDryHopMinMaxArray, HRAD); - SetLength(HRAB, 0); - SetLength(HRAA, 0); - SetLength(HRAD, 0); - end; - end; - if (High(FCollection) >= 0) then - begin - for i:= Low(FBitterhopMinMaxArray) to High(FBitterhopMinMaxArray) do - begin - if FBitterhopMinMaxArray[i].PercRecipes > 0 then - FBitterhopMinMaxArray[i].AvUse:= FBitterhopMinMaxArray[i].AvUse - / FBitterhopMinMaxArray[i].PercRecipes - else - FBitterhopMinMaxArray[i].AvUse:= 0; - if Result > 0 then - FBitterhopMinMaxArray[i].PercRecipes:= - 100 * FBitterhopMinMaxArray[i].PercRecipes / Result - else - FBitterhopMinMaxArray[i].PercRecipes:= 0; - end; - QuickSortA(FBitterhopMinMaxArray); - - for i:= Low(FAromahopMinMaxArray) to High(FAromahopMinMaxArray) do - begin - if FAromahopMinMaxArray[i].PercRecipes > 0 then - FAromahopMinMaxArray[i].AvUse:= FAromahopMinMaxArray[i].AvUse - / FAromahopMinMaxArray[i].PercRecipes - else - FAromahopMinMaxArray[i].AvUse:= 0; - if Result > 0 then - FAromahopMinMaxArray[i].PercRecipes:= - 100 * FAromahopMinMaxArray[i].PercRecipes / Result - else - FAromahopMinMaxArray[i].PercRecipes:= 0; - end; - QuickSortA(FAromahopMinMaxArray); - - for i:= Low(FDryhopMinMaxArray) to High(FDryhopMinMaxArray) do - begin - if FDryhopMinMaxArray[i].PercRecipes > 0 then - FDryhopMinMaxArray[i].AvUse:= FDryhopMinMaxArray[i].AvUse - / FDryhopMinMaxArray[i].PercRecipes - else - FDryhopMinMaxArray[i].AvUse:= 0; - if Result > 0 then - FDryhopMinMaxArray[i].PercRecipes:= - 100 * FDryhopMinMaxArray[i].PercRecipes / Result - else - FDryhopMinMaxArray[i].PercRecipes:= 0; - end; - QuickSortA(FDryhopMinMaxArray); - end; -end; - -Function TRecipes.AnalyseYeasts(Lett, Nm : string) : integer; //returns number of recipes -var i, j, k : integer; - R : TRecipe; - Y : TYeast; - FN : string; -begin - Result:= 0; - if High(FYeastMinMaxArray) >= 0 then - SetLength(FYeastMinMaxArray, 0); - for i:= Low(FCollection) to High(FCollection) do - begin - R:= TRecipe(FCollection[i]); - if (R.Style <> NIL) and - ((LowerCase(R.Style.StyleLetter.Value) = LowerCase(Lett)) and - (Lowercase(R.Style.Name.Value) = Lowercase(Nm))) then - begin - Inc(Result); - for j:= 0 to R.NumYeasts - 1 do - begin - Y:= R.Yeast[j]; - FN:= Y.Name.Value; - k:= Exists(FYeastMinMaxArray, FN); - if k = -1 then - begin - SetLength(FYeastMinMaxArray, High(FYeastMinMaxArray) + 2); - k:= High(FYeastMinMaxArray); - FYeastMinMaxArray[k].Name:= FN; - FYeastMinMaxArray[k].PercRecipes:= 1; - {FYeastMinMaxArray[k].MinUse:= F.Percentage.Value; - FYeastMinMaxArray[k].AvUse:= F.Percentage.Value; - FYeastMinMaxArray[k].MaxUse:= F.Percentage.Value;} - end - else - begin - //temporarily store the number of recipes with this ingredient in PercRecipes - FYeastMinMaxArray[k].PercRecipes:= FYeastMinMaxArray[k].PercRecipes + 1; - {FYeastMinMaxArray[k].AvUse:= FYeastMinMaxArray[k].AvUse + F.Percentage.Value; - if F.Percentage.Value < FYeastMinMaxArray[k].MinUse then - FYeastMinMaxArray[k].MinUse:= F.Percentage.Value; - if F.Percentage.Value > FYeastMinMaxArray[k].MaxUse then - FYeastMinMaxArray[k].MaxUse:= F.Percentage.Value;} - end; - end; - end; - end; - if (High(FCollection) >= 0) then - begin - for i:= Low(FYeastMinMaxArray) to High(FYeastMinMaxArray) do - begin - { if FYeastMinMaxArray[i].PercRecipes > 0 then - FYeastMinMaxArray[i].AvUse:= FYeastMinMaxArray[i].AvUse / FYeastMinMaxArray[i].PercRecipes - else - FYeastMinMaxArray[i].AvUse:= 0;} - if Result > 0 then - FYeastMinMaxArray[i].PercRecipes:= 100 * FYeastMinMaxArray[i].PercRecipes / Result - else - FYeastMinMaxArray[i].PercRecipes:= 0; - end; - QuickSortA(FYeastMinMaxArray); - end; -end; - -Function TRecipes.AnalyseMiscs(Lett, Nm : string) : integer; //returns number of recipes -var i, j, k : integer; - R : TRecipe; - M : TMisc; - FN : string; - conc : double; -begin - Result:= 0; - if High(FMiscMinMaxArray) >= 0 then - SetLength(FMiscMinMaxArray, 0); - for i:= Low(FCollection) to High(FCollection) do - begin - R:= TRecipe(FCollection[i]); - if (R.Style <> NIL) and - ((LowerCase(R.Style.StyleLetter.Value) = LowerCase(Lett)) and - (Lowercase(R.Style.Name.Value) = Lowercase(Nm))) then - begin - Inc(Result); - for j:= 0 to R.NumMiscs - 1 do - begin - M:= R.Misc[j]; - FN:= M.Name.Value; - if ((M.MiscType = mtSpice) or (M.MiscType = mtHerb) or (M.MiscType = mtFlavor) - or (M.MiscType = mtOther)) and (R.BatchSize.DisplayValue > 0) then - begin - conc:= M.Amount.DisplayValue / R.BatchSize.DisplayValue; - k:= Exists(FMiscMinMaxArray, FN); - if k = -1 then - begin - SetLength(FMiscMinMaxArray, High(FMiscMinMaxArray) + 2); - k:= High(FMiscMinMaxArray); - FMiscMinMaxArray[k].Name:= FN; - FMiscMinMaxArray[k].PercRecipes:= 1; - FMiscMinMaxArray[k].MinUse:= Conc; - FMiscMinMaxArray[k].AvUse:= Conc; - FMiscMinMaxArray[k].MaxUse:= Conc; - end - else - begin - //temporarily store the number of recipes with this ingredient in PercRecipes - FMiscMinMaxArray[k].PercRecipes:= FMiscMinMaxArray[k].PercRecipes + 1; - FMiscMinMaxArray[k].AvUse:= FMiscMinMaxArray[k].AvUse + Conc; - if Conc < FMiscMinMaxArray[k].MinUse then - FMiscMinMaxArray[k].MinUse:= Conc; - if Conc > FMiscMinMaxArray[k].MaxUse then - FMiscMinMaxArray[k].MaxUse:= Conc; - end; - end; - end; - end; - end; - if (High(FCollection) >= 0) then - begin - for i:= Low(FMiscMinMaxArray) to High(FMiscMinMaxArray) do - begin - if FMiscMinMaxArray[i].PercRecipes > 0 then - FMiscMinMaxArray[i].AvUse:= FMiscMinMaxArray[i].AvUse / FMiscMinMaxArray[i].PercRecipes - else - FMiscMinMaxArray[i].AvUse:= 0; - if Result > 0 then - FMiscMinMaxArray[i].PercRecipes:= 100 * FMiscMinMaxArray[i].PercRecipes / Result - else - FMiscMinMaxArray[i].PercRecipes:= 0; - end; - QuickSortA(FMiscMinMaxArray); - end; -end; - -Function TRecipes.AnalyseRecipes(Lett, Nm : string) : integer; //returns number of recipes -var i, j : integer; - R : TRecipe; - SGp, bitt, x : double; -begin - Result:= 0; - SetLength(FCommonMinMaxArray, 0); - SetLength(FCommonMinMaxArray, 3); - for j:= 0 to High(FCommonMinMaxArray) do - begin - FCommonMinMaxArray[j].PercRecipes:= 0; - FCommonMinMaxArray[j].MinUse:= 10000; - FCommonMinMaxArray[j].AvUse:= 0; - FCommonMinMaxArray[j].MaxUse:= 0; - FCommonMinMaxArray[j].Name:= ''; - end; - //0 = SG points - FCommonMinMaxArray[0].Name:= 'SG punten'; - //1 = Bitterness - FCommonMinMaxArray[1].Name:= 'Bitterheid (IBU)'; - //2 = Color - FCommonMinMaxArray[2].Name:= 'Kleur (' + TRecipe(FCollection[0]).EstColor.DisplayUnitString + ')'; - { //3 = BitternessIndex - FCommonMinMaxArray[3].Name:= 'Bitterheidsindex';} - - for i:= Low(FCollection) to High(FCollection) do - begin - R:= TRecipe(FCollection[i]); - if (R.Style <> NIL) and - ((LowerCase(R.Style.StyleLetter.Value) = LowerCase(Lett)) and - (Lowercase(R.Style.Name.Value) = Lowercase(Nm))) then - begin - Inc(Result); - - R.CalcOG; - if R.OG.Value > 1 then - SGp:= 1000 * (R.OG.Value - 1) - else - SGp:= 1000 * (R.EstOG.Value - 1); - FCommonMinMaxArray[0].AvUse:= FCommonMinMaxArray[0].AvUse + SGp; - if SGp < FCommonMinMaxArray[0].MinUse then - FCommonMinMaxArray[0].MinUse:= SGp; - if SGp > FCommonMinMaxArray[0].MaxUse then - FCommonMinMaxArray[0].MaxUse:= SGp; - - R.CalcBitterness; - bitt:= R.IBUcalc.DisplayValue; - FCommonMinMaxArray[1].AvUse:= FCommonMinMaxArray[1].AvUse + bitt; - if bitt < FCommonMinMaxArray[1].MinUse then - FCommonMinMaxArray[1].MinUse:= bitt; - if bitt > FCommonMinMaxArray[1].MaxUse then - FCommonMinMaxArray[1].MaxUse:= bitt; - -{ if SGp > 0 then x:= bitt / SGp - else x:= 0; - FCommonMinMaxArray[2].AvUse:= FCommonMinMaxArray[2].AvUse + x; - if x < FCommonMinMaxArray[2].MinUse then - FCommonMinMaxArray[2].MinUse:= x; - if x > FCommonMinMaxArray[2].MaxUse then - FCommonMinMaxArray[2].MaxUse:= x;} - - R.CalcColor; - x:= R.EstColor.DisplayValue; - FCommonMinMaxArray[2].AvUse:= FCommonMinMaxArray[2].AvUse + x; - if x < FCommonMinMaxArray[2].MinUse then - FCommonMinMaxArray[2].MinUse:= x; - if x > FCommonMinMaxArray[2].MaxUse then - FCommonMinMaxArray[2].MaxUse:= x; - end; - end; - if (High(FCollection) >= 0) then - begin - for i:= Low(FCommonMinMaxArray) to High(FCommonMinMaxArray) do - begin - if Result > 0 then - FCommonMinMaxArray[i].AvUse:= FCommonMinMaxArray[i].AvUse / Result - else - FCommonMinMaxArray[i].AvUse:= 0; - end; - end; -end; -{============================= TRecipesByStyle ================================} - -{ TStyleRec = record - Name : string; - Recipes : array of TRecipe; - end; - - TStyleLetters = record - Letter : string; - Styles : array of TStyleRec; - end;} - -Constructor TRecipesByStyle.Create(R : TRecipes); - begin - Inherited Create; - FCollection:= R; - Fill; - Sort; - end; - -Destructor TRecipesByStyle.Destroy; -begin - Empty; - Inherited; -end; - -Procedure TRecipesByStyle.SaveXML; -var Doc : TXMLDocument; - iRootNode : TDOMNode; - n, s, i : integer; -begin - try - Doc := TXMLDocument.Create; - iRootNode := Doc.CreateElement('RECIPES'); - Doc.Appendchild(iRootNode); - - for n:= Low(FStyleLetters) to High(FStyleLetters) do - begin - for s:= Low(FStyleLetters[n].Styles) to High(FStyleLetters[n].Styles) do - begin - for i:= Low(FStyleLetters[n].Styles[s].Recipes) to High(FStyleLetters[n].Styles[s].Recipes) do - FStyleLetters[n].Styles[s].Recipes[i].SaveXML(Doc, iRootNode, false); - end; - end; - - writeXMLFile(Doc, Settings.DataLocation.Value + 'recipes.xml'); - finally - Doc.Free; - end; -end; - -Procedure TRecipesByStyle.Fill; -var n, n2, s, s2, i, r : integer; - Num, Stl : string; - Rec : TRecipe; -begin - Empty; - for i:= 1 to FCollection.GetNumItems do - begin - Rec:= TRecipe(FCollection.Item[i-1]); - Num:= Rec.Style.StyleLetter.Value; - Stl:= Rec.Style.Name.Value; - n:= GetLetterByName(Num); - s:= GetStyleByName(Num, Stl); - if n < 0 then //Style Number does not exist - begin - n2:= High(FStyleLetters) + 1; - SetLength(FStyleLetters, n2 + 1); - FStyleLetters[n2].Letter:= Num; - SetLength(FStyleLetters[n2].Styles, 1); - FStyleLetters[n2].Styles[0].Name:= Stl; - SetLength(FStyleLetters[n2].Styles[0].Recipes, 1); - FStyleLetters[n2].Styles[0].Recipes[0]:= Rec; - end - else if s < 0 then //Style does not exist - begin - s2:= High(FStyleLetters[n].Styles) + 1; - SetLength(FStyleLetters[n].Styles, s2 + 1); - FStyleLetters[n].Styles[s2].Name:= Stl; - SetLength(FStyleLetters[n].Styles[s2].Recipes, 1); - FStyleLetters[n].Styles[s2].Recipes[0]:= Rec; - end - else //Both exist - begin - r:= High(FStyleLetters[n].Styles[s].Recipes) + 1; - SetLength(FStyleLetters[n].Styles[s].Recipes, r+1); - FStyleLetters[n].Styles[s].Recipes[r]:= Rec; - end; - end; -end; - -Procedure TRecipesByStyle.Empty; -var n, s, i : integer; -begin - for n:= Low(FStyleLetters) to High(FStyleLetters) do - begin - for s:= Low(FStyleLetters[n].Styles) to High(FStyleLetters[n].Styles) do - begin - for i:= Low(FStyleLetters[n].Styles[s].Recipes) to High(FStyleLetters[n].Styles[s].Recipes) do - FStyleLetters[n].Styles[s].Recipes[i]:= NIL; - SetLength(FStyleLetters[n].Styles[s].Recipes, 0); - end; - SetLength(FStyleLetters[n].Styles, 0); - end; - SetLength(FStyleLetters, 0); -end; - -Procedure TRecipesByStyle.QuickSortInStyles(var Arr : array of TRecipe); - procedure QuickSort(var A: array of TRecipe; iLo, iHi: Integer); - var Lo, Hi: Integer; - l : string; - T : TRecipe; - begin - Lo := iLo; - Hi := iHi; - l:= A[(Lo + Hi) div 2].NrRecipe.Value; - repeat - while A[Lo].NrRecipe.Value < l do Inc(Lo); - while A[Hi].NrRecipe.Value > l do Dec(Hi); - if Lo <= Hi then - begin - T := A[Lo]; - A[Lo] := A[Hi]; - A[Hi] := T; - Inc(Lo); - Dec(Hi); - end; - until Lo > Hi; - if Hi > iLo then QuickSort(A, iLo, Hi); - if Lo < iHi then QuickSort(A, Lo, iHi); - end; -begin - if High(Arr) > -1 then QuickSort(Arr, Low(Arr), High(Arr)); -end; - -Procedure TRecipesByStyle.QuickSortStyles(var Arr : array of TStyleRec); - procedure QuickSort(var A: array of TStyleRec; iLo, iHi: Integer); - var Lo, Hi: Integer; - s : string; - T : TStyleRec; - begin - Lo := iLo; - Hi := iHi; - s:= A[(Lo + Hi) div 2].Name; - repeat - while A[Lo].Name < s do Inc(Lo); - while A[Hi].Name > s do Dec(Hi); - if Lo <= Hi then - begin - T := A[Lo]; - A[Lo] := A[Hi]; - A[Hi] := T; - Inc(Lo); - Dec(Hi); - end; - until Lo > Hi; - if Hi > iLo then QuickSort(A, iLo, Hi); - if Lo < iHi then QuickSort(A, Lo, iHi); - end; -begin - if High(Arr) > -1 then QuickSort(Arr, Low(Arr), High(Arr)); -end; - -Procedure TRecipesByStyle.QuickSortLetters(var Arr : array of TStyleLetters); - procedure QuickSort(var A: array of TStyleLetters; iLo, iHi: Integer); - var Lo, Hi: Integer; - l : string; - T : TStyleLetters; - begin - Lo := iLo; - Hi := iHi; - l := A[(Lo + Hi) div 2].Letter; - repeat - while A[Lo].Letter < l do Inc(Lo); - while A[Hi].Letter > l do Dec(Hi); - if Lo <= Hi then - begin - T := A[Lo]; - A[Lo] := A[Hi]; - A[Hi] := T; - Inc(Lo); - Dec(Hi); - end; - until Lo > Hi; - if Hi > iLo then QuickSort(A, iLo, Hi); - if Lo < iHi then QuickSort(A, Lo, iHi); - end; -begin - if High(Arr) > -1 then QuickSort(Arr, Low(Arr), High(Arr)); -end; - -Procedure TRecipesByStyle.Sort; -var n, s : integer; -begin -//sort recipes in every style by recipe number - for n:= Low(FStyleLetters) to High(FStyleLetters) do - for s:= Low(FStyleLetters[n].Styles) to High(FStyleLetters[n].Styles) do - QuickSortInStyles(FStyleLetters[n].Styles[s].Recipes); - -//sort style names - for n:= Low(FStyleLetters) to High(FStyleLetters) do - QuickSortStyles(FStyleLetters[n].Styles); -//sort style letters - QuickSortLetters(FStyleLetters); -end; - -Function TRecipesByStyle.GetLetterByName(Num : string) : integer; -var n : integer; -begin - Result:= -1; - for n:= Low(FStyleLetters) to High(FStyleLetters) do - if FStyleLetters[n].Letter = Num then - begin - Result:= n; - Exit; - end; -end; - -Function TRecipesByStyle.GetStyleByName(Num, Stl : string) : integer; -var n, s : integer; -begin - Result:= -1; - n:= GetLetterByName(Num); - if n > -1 then - begin - for s:= Low(FStyleLetters[n].Styles) to High(FStyleLetters[n].Styles) do - if FStyleLetters[n].Styles[s].Name = Stl then - begin - Result:= s; - Exit; - end; - end; -end; - -Function TRecipesByStyle.GetNumStyleLetters : integer; -begin - Result:= High(FStyleLetters) + 1; -end; - -Function TRecipesByStyle.GetNumStyles(i : integer) : integer; -begin - Result:= -1; - if (i >= Low(FStyleLetters)) and (i <= High(FStyleLetters)) then - Result:= High(FStyleLetters[i].Styles) + 1; -end; - -Function TRecipesByStyle.GetStyleLetter(i : integer) : string; -begin - Result:= ''; - if (i >= Low(FStyleLetters)) and (i <= High(FStyleLetters)) then - Result:= FStyleLetters[i].Letter; -end; - -Function TRecipesByStyle.GetStyleName(n : integer; s : integer) : string; -begin - Result:= ''; - if (n >= Low(FStyleLetters)) and (n <= High(FStyleLetters)) then - if (s >= Low(FStyleLetters[n].Styles)) and (s <= High(FStyleLetters[n].Styles)) then - Result:= FStyleLetters[n].Styles[s].Name; -end; - -Function TRecipesByStyle.GetNumRecipes(n : integer; s : integer) : integer; -begin - Result:= -1; - if (n >= Low(FStyleLetters)) and (n <= High(FStyleLetters)) then - if (s >= Low(FStyleLetters[n].Styles)) and (s <= High(FStyleLetters[n].Styles)) then - Result:= High(FStyleLetters[n].Styles[s].Recipes) + 1; -end; - -Function TRecipesByStyle.GetRecipe(n : integer; s : integer; i : integer) : TRecipe; -begin - Result:= NIL; - if (n >= Low(FStyleLetters)) and (n <= High(FStyleLetters)) then - if (s >= Low(FStyleLetters[n].Styles)) and (s <= High(FStyleLetters[n].Styles)) then - if (i >= Low(FStyleLetters[n].Styles[s].Recipes)) and (i <= High(FStyleLetters[n].Styles[s].Recipes)) then - Result:= FStyleLetters[n].Styles[s].Recipes[i]; -end; - -{============================= System functions ===============================} - -Procedure CheckBeerStyle(Rec : TRecipe); -var s : string; - OK : boolean; - BS : TBeerStyle; -begin -//check if beerstyle exist in the database. -//If not, check the substitution database, otherwise ask for an alternative - s:= ''; - if Rec.Style <> NIL then - s:= Rec.Style.Name.Value; - if Beerstyles.FindByName(s) = NIL then - begin - //first, look for subtitute in the substitutions database - OK:= StyleSubs.OriginalExists(s); - if OK then - begin - s:= StyleSubs.FindSubstitute(s); - BS:= TBeerStyle(BeerStyles.FindByName(s)); - OK:= (BS <> NIL); - if not OK then - StyleSubs.RemoveOriginal(s); - end; - if OK then - Rec.Style.Assign(BS) - else - begin - FrmSelectBeerStyle:= TFrmSelectBeerStyle.Create(FrmMain); - if FrmSelectBeerStyle.Execute(s) then - begin - //put style replacement in the substitutions database - if (not StyleSubs.OriginalExists(s)) then - StyleSubs.Add(s, FrmSelectBeerStyle.BeerStyle.Name.Value); - Rec.Style.Assign(FrmSelectBeerStyle.BeerStyle); - end; - FrmSelectBeerStyle.Free; - end; - end; -end; - -Procedure CheckFermentables(Rec : TRecipe); -var s, s2 : string; - OK : boolean; - i : integer; - F : TFermentable; - am, perc, yield, color, CoarseFineDiff, moisture, DiastaticPower, Protein, - DissolvedProtein, IbuGalPerLb: double; -begin -//check if fermentable exist in the database. -//If not, check the substitution database, otherwise ask for an alternative - for i:= 0 to Rec.NumFermentables - 1 do - begin - s:= Rec.Fermentable[i].Name.Value; - s2:= Rec.Fermentable[i].Supplier.Value; - OK:= (Fermentables.FindByNameAndSupplier(s, s2) <> NIL); - if (not OK) then - begin - OK:= FermentableSubs.OriginalExists(s, s2); - if OK then - begin - FermentableSubs.FindSubstitute(s, s2, s, s2); - F:= TFermentable(Fermentables.FindByNameAndSupplier(s, s2)); - if F <> NIL then - begin - am:= Rec.Fermentable[i].Amount.Value; - perc:= Rec.Fermentable[i].Percentage.Value; - Yield:= Rec.Fermentable[i].Yield.Value; - Color:= Rec.Fermentable[i].Color.Value; - CoarseFineDiff:= Rec.Fermentable[i].CoarseFineDiff.Value; - Moisture:= Rec.Fermentable[i].Moisture.Value; - DiastaticPower:= Rec.Fermentable[i].DiastaticPower.Value; - Protein:= Rec.Fermentable[i].Protein.Value; - DissolvedProtein:= Rec.Fermentable[i].DissolvedProtein.Value; - IbuGalPerLb:= Rec.Fermentable[i].IbuGalPerLb.Value; - - Rec.Fermentable[i].Assign(F); - Rec.Fermentable[i].Amount.Value:= am; - Rec.Fermentable[i].Percentage.Value:= perc; - Rec.Fermentable[i].Yield.Value:= Yield; - Rec.Fermentable[i].Color.Value:= Color; - Rec.Fermentable[i].CoarseFineDiff.Value:= CoarseFineDiff; - Rec.Fermentable[i].Moisture.Value:= Moisture; - Rec.Fermentable[i].DiastaticPower.Value:= DiastaticPower; - Rec.Fermentable[i].Protein.Value:= Protein; - Rec.Fermentable[i].DissolvedProtein.Value:= DissolvedProtein; - Rec.Fermentable[i].IbuGalPerLb.Value:= IbuGalPerLb; - end - else - FermentableSubs.RemoveOriginal(s, s2); - end; - end; - end; -end; - -Procedure CheckYeasts(Rec : TRecipe); -var s, s2 : string; - OK : boolean; - i : integer; - Y : TYeast; - am : double; -begin -//check if beerstyle exist in the database. -//If not, check the substitution database, otherwise ask for an alternative - for i:= 0 to Rec.NumYeasts - 1 do - begin - s:= Rec.Yeast[i].Name.Value; - s2:= Rec.Yeast[i].Laboratory.Value; - OK:= (Yeasts.FindByNameAndLaboratory(s, s2) <> NIL); - if (not OK) then - begin - OK:= YeastSubs.OriginalExists(s, s2); - if OK then - begin - YeastSubs.FindSubstitute(s, s2, s, s2); - Y:= TYeast(Yeasts.FindByNameAndLaboratory(s, s2)); - if Y <> NIL then - begin - am:= Rec.Yeast[i].Amount.Value; - Rec.Yeast[i].Assign(Y); - Rec.Yeast[i].Amount.Value:= am; - end - else - YeastSubs.RemoveOriginal(s, s2); - end; - end; - end; -end; - -Procedure Backup; - function CheckCopyFile(sd, dd, fn : string) : boolean; - begin - Result:= false; - if FileExists(sd + fn) then - result:= CopyFile(sd + fn, dd + fn); - end; -var sourcedata, destdata : string; - year, month, day : word; - i : integer; - SearchResult : TSearchRec; - SL : TStringList; -begin - sourcedata:= Settings.DataLocation.Value; - DecodeDate(now, year, month, day); - destdata:= BHFolder + 'backup-' + IntToStr(Year) + '-' + IntToStr(Month) + '-' - + IntToStr(day) + Slash; - CreateDir(destdata); - CheckCopyFile(sourcedata, destdata, 'settings.xml'); - CheckCopyFile(sourcedata, destdata, 'fermentables.xml'); - CheckCopyFile(sourcedata, destdata, 'hops.xml'); - CheckCopyFile(sourcedata, destdata, 'yeasts.xml'); - CheckCopyFile(sourcedata, destdata, 'miscs.xml'); - CheckCopyFile(sourcedata, destdata, 'mashs.xml'); - CheckCopyFile(sourcedata, destdata, 'waters.xml'); - CheckCopyFile(sourcedata, destdata, 'styles.xml'); - CheckCopyFile(sourcedata, destdata, 'equipments.xml'); - CheckCopyFile(sourcedata, destdata, 'recipes.xml'); - CheckCopyFile(sourcedata, destdata, 'brews.xml'); - CheckCopyFile(sourcedata, destdata, 'cloud.xml'); - CheckCopyFile(sourcedata, destdata, 'stylesubs.xml'); - CheckCopyFile(sourcedata, destdata, 'fermentablesubs.xml'); - CheckCopyFile(sourcedata, destdata, 'yeastsubs.xml'); - CheckCopyFile(sourcedata, destdata, 'neuralnetworks.xml'); - SL:= FindAllFiles(sourcedata, '*.nn', false); - for i:= 0 to SL.Count - 1 do - CheckCopyFile(sourcedata, destdata, ExtractFileName(SL.Strings[i])); - FreeAndNIL(SL); - // CheckCopyFile(sourcedata, destdata, 'styles-BJCP.xml'); - // CheckCopyFile(sourcedata, destdata, 'White Labs.xml'); - CheckCopyFile(sourcedata, destdata, 'logo.png'); -end; - -Procedure Restore(sourcedata : string); - function CheckCopyFile(sd, dd, fn : string) : boolean; - begin - Result:= false; - if FileExists(sd + fn) then - result:= CopyFile(sd + fn, dd + fn); - end; -var destdata : string; - year, month, day : word; - i : integer; - SL : TStringList; -begin - destdata:= Settings.DataLocation.Value; - if not DirectoryExists(destdata) then CreateDir(destdata); - CheckCopyFile(sourcedata, destdata, 'settings.xml'); - CheckCopyFile(sourcedata, destdata, 'fermentables.xml'); - CheckCopyFile(sourcedata, destdata, 'hops.xml'); - CheckCopyFile(sourcedata, destdata, 'yeasts.xml'); - CheckCopyFile(sourcedata, destdata, 'miscs.xml'); - CheckCopyFile(sourcedata, destdata, 'mashs.xml'); - CheckCopyFile(sourcedata, destdata, 'waters.xml'); - CheckCopyFile(sourcedata, destdata, 'styles.xml'); - CheckCopyFile(sourcedata, destdata, 'equipments.xml'); - CheckCopyFile(sourcedata, destdata, 'recipes.xml'); - CheckCopyFile(sourcedata, destdata, 'brews.xml'); - CheckCopyFile(sourcedata, destdata, 'cloud.xml'); - CheckCopyFile(sourcedata, destdata, 'stylesubs.xml'); - CheckCopyFile(sourcedata, destdata, 'fermentablesubs.xml'); - CheckCopyFile(sourcedata, destdata, 'yeastsubs.xml'); - CheckCopyFile(sourcedata, destdata, 'neuralnetworks.xml'); - SL:= FindAllFiles(sourcedata, '*.nn', false); - for i:= 0 to SL.Count - 1 do - CheckCopyFile(sourcedata, destdata, ExtractFileName(SL.Strings[i])); - FreeAndNIL(SL); - -// CheckCopyFile(sourcedata, destdata, 'styles-BJCP.xml'); -// CheckCopyFile(sourcedata, destdata, 'White Labs.xml'); - CheckCopyFile(sourcedata, destdata, 'logo.png'); - - Fermentables.ReadXML; - Hops.ReadXML; - Miscs.ReadXML; - Yeasts.ReadXML; - Waters.ReadXML; - Equipments.ReadXML; - Beerstyles.ReadXML; - Mashs.ReadXML; - Application.ProcessMessages; - Recipes.ReadXML; - Application.ProcessMessages; - Brews.ReadXML; -end; - -Procedure CheckDataFolder; - function CheckFile(sd, dd, fn : string) : boolean; - var destOK, sourceOK : boolean; - begin - Result:= false; - destOK:= FileExists(dd + fn); - sourceOK:= FileExists(sd + fn); - if (not destOK) and (sourceOK) then - try - result:= CopyFile(sd + fn, dd + fn); - except - ShowMessage('Fout bij aanmaken ' + dd + fn + '.'); - Halt; - end - else if (not destOK) and (not sourceOK) then - ShowMessage('Fout: ' + sd + fn + ' niet gevonden.'); - end; -var sourcedata, destdata, sourcesounds, destsounds : string; -begin - {$ifdef UNIX} - sourcedata:= '/usr/share/brewbuddy/'; - {$endif} - {$ifdef darwin} - sourcedata:= '/usr/share/brewbuddy/'; - {$endif} - {$ifdef Windows} - sourcedata:= ExtractFilePath(Application.ExeName) + 'brewbuddy\'; - if OnUSB then BHFolder:= DriveLetter + '\brewbuddy\brewbuddy\'; - log('Checkdatafolder: BHFolder = ' + BHFolder); - {$endif} - destdata:= BHFolder; - if not DirectoryExists(BHFolder) then - CreateDir(BHFolder); - if not DirectoryExists(SoundFolder) then - CreateDir(SoundFolder); - sourcesounds:= sourcedata + 'sounds' + Slash; - destsounds:= SoundFolder; - Settings := TBSettings.Create; - if CheckFile(sourcedata, destdata, 'settings.xml') then - begin - Settings.DataLocation.Value:= BHFolder; - end - else - Settings.Read; - log('Settings.Datalocation = ' + Settings.DataLocation.Value); - - IF OnUSB then - begin - Settings.DataLocation.Value:= BHFolder; - destdata:= BHFolder; - end - else if (Settings.DataLocation.Value <> '') and (not OnUSB) then - destdata:= Settings.DataLocation.Value - else - destdata:= BHFolder; - log('Settings.Datalocation = ' + Settings.DataLocation.Value); - if not DirectoryExists(destdata) then - CreateDir(destdata); - - if CheckFile(sourcedata, destdata, 'equipments.xml') then - ShowMessage('Data niet gevonden. Nieuwe databank wordt gemaakt.'); - CheckFile(sourcedata, destdata, 'fermentables.xml'); - CheckFile(sourcedata, destdata, 'hops.xml'); - CheckFile(sourcedata, destdata, 'mashs.xml'); - CheckFile(sourcedata, destdata, 'miscs.xml'); - CheckFile(sourcedata, destdata, 'recipes.xml'); - CheckFile(sourcedata, destdata, 'styles-BJCP.xml'); - CheckFile(sourcedata, destdata, 'styles.xml'); - CheckFile(sourcedata, destdata, 'waters.xml'); -// CheckFile(sourcedata, destdata, 'White Labs.xml'); - CheckFile(sourcedata, destdata, 'yeasts.xml'); - CheckFile(sourcedata, destdata, 'logo.png'); - {$ifdef Windows} - CheckFile(sourcedata, destdata, 'Introductie BrewBuddy Sassy Saison.pdf'); - {$endif} - {$ifdef Darwin} - CheckFile(sourcedata, destdata, 'Introductie BrewBuddy Sassy Saison.pdf'); - {$endif} - {$ifdef linux} - CheckFile('/usr/share/doc/brewbuddy/', destdata, 'Introductie BrewBuddy Sassy Saison.pdf'); - {$endif} - CheckFile(sourcesounds, destsounds, 'alarm.wav'); -// CheckFile(sourcesounds, destsounds, 'alarm02.wav'); - CheckFile(sourcesounds, destsounds, 'end.wav'); - CheckFile(sourcesounds, destsounds, 'warning.wav'); - CheckFile(sourcesounds, destsounds, 'welcome.wav'); -end; - -Procedure Reload; -begin - Fermentables.Free; - Hops.Free; - Miscs.Free; - Yeasts.Free; - Waters.Free; - Equipments.Free; - Beerstyles.Free; - Mashs.Free; - Recipes.Free; - Brews.Free; - Settings.Free; - Settings := TBSettings.Create; - Settings.Read; - - CheckDataFolder; - - Fermentables:= TFermentables.Create; - Hops:= THops.Create; - Miscs:= TMiscs.Create; - Yeasts:= TYeasts.Create; - Waters:= TWaters.Create; - Equipments:= TEquipments.Create; - Beerstyles:= TBeerstyles.Create; - Mashs:= TMashs.Create; - Recipes:= TRecipes.Create; - - Brews:= TRecipes.Create; - Brews.FileName:= 'brews.xml'; - - loc:= Settings.DataLocation.Value; - if (loc = '') or OnUSB then loc:= BHFolder; - if InitializeHD('fermentables.xml', loc) then - begin - Settings.DataLocation.Value:= loc; - Fermentables.ReadXML; - Hops.ReadXML; - Miscs.ReadXML; - Yeasts.ReadXML; - Waters.ReadXML; - Equipments.ReadXML; - Beerstyles.ReadXML; - Mashs.ReadXML; - Application.ProcessMessages; - Recipes.ReadXML; - Recipes.CheckAutoNrs; - Application.ProcessMessages; - Brews.ReadXML; - Brews.CheckAutoNrs; - - CheckSalts; - end - else - ShowMessage('Databestanden niet gevonden'); -end; - -Procedure ChangeDatabaseLocation(source, destination : string; copy, deleteold : boolean); - function CheckCopyFile(sd, dd, fn : string) : boolean; - begin - Result:= false; - if FileExists(sd + fn) then - result:= CopyFile(sd + fn, dd + fn); - end; -var SearchResult : TSearchRec; - i : integer; - SL : TStringList; - StylesN, FermN, HopN, MiscN, YeastN, WaterN, sourcedata : string; -begin - {$ifdef UNIX} - destination:= destination + '/'; - {$else} - destination:= destination + '\'; - {$endif} - Settings.DataLocation.Value:= destination; - - if not copy then - begin - StylesN:= destination + 'styles.xml'; - FermN:= destination + 'fermentables.xml'; - HopN:= destination + 'hops.xml'; - MiscN:= destination + 'miscs.xml'; - YeastN:= destination + 'yeasts.xml'; - WaterN:= destination + 'waters.xml'; - if FileExists(StylesN) and FileExists(FermN) and FileExists(HopN) and - FileExists(MiscN) and FileExists(YeastN) and FileExists(WaterN) then - begin - Brews.ReadXML; - Equipments.ReadXML; - Fermentables.ReadXML; - Hops.ReadXML; - Mashs.ReadXML; - Miscs.ReadXML; - Recipes.ReadXML; - Beerstyles.ReadXML; - Waters.ReadXML; - Yeasts.ReadXML; - StyleSubs.ReadXML; - FermentableSubs.ReadXML; - YeastSubs.ReadXML; - BHNNs.ReadXML; - end - else //copy previous database to new location, but clear brews - begin - {$ifdef UNIX} - sourcedata:= '/usr/share/brewbuddy/'; - {$endif} - {$ifdef darwin} - sourcedata:= '/usr/share/brewbuddy/'; - {$endif} - {$ifdef Windows} - sourcedata:= ExtractFilePath(Application.ExeName) + 'brewbuddy\'; - if OnUSB then BHFolder:= DriveLetter + '\brewbuddy\brewbuddy\' - else BHFolder:= destination; - {$endif} - - Equipments.SaveXML; - Fermentables.SaveXML; - Hops.SaveXML; - Mashs.SaveXML; - Miscs.SaveXML; - Recipes.SaveXML; - Beerstyles.SaveXML; - Waters.SaveXML; - Yeasts.SaveXML; - StyleSubs.SaveXML; - FermentableSubs.SaveXML; - YeastSubs.SaveXML; - BHNNs.SaveXML; - SL:= FindAllFiles(source, '*.nn', false); - for i:= 0 to SL.Count - 1 do - CheckCopyFile(source, destination, ExtractFileName(SL.Strings[i])); - FreeAndNIL(SL); - Brews.FreeCollection; - CheckCopyFile(source, destination, 'Introductie BrewBuddy Sassy Saison.pdf'); - CheckCopyFile(source, destination, 'styles-BJCP.xml'); - CheckCopyFile(source, destination, 'logo.png'); - CheckDataFolder; - end; - - //delete files in old directory - if deleteold then - begin - DeleteFile(PChar(source + 'brews.xml')); - DeleteFile(PChar(source + 'equipments.xml')); - DeleteFile(PChar(source + 'fermentables.xml')); - DeleteFile(PChar(source + 'hops.xml')); - DeleteFile(PChar(source + 'mashs.xml')); - DeleteFile(PChar(source + 'miscs.xml')); - DeleteFile(PChar(source + 'recipes.xml')); - DeleteFile(PChar(source + 'styles.xml')); - DeleteFile(PChar(source + 'waters.xml')); - DeleteFile(PChar(source + 'yeasts.xml')); - DeleteFile(PChar(source + 'stylesubs.xml')); - DeleteFile(PChar(source + 'fermentablesubs.xml')); - DeleteFile(PChar(source + 'yeastsubs.xml')); - DeleteFile(PChar(source + 'neuralnetworks.xml')); - SL:= FindAllFiles(source, '*.nn', false); - for i:= 0 to SL.Count - 1 do - DeleteFile(PChar(SL.Strings[i])); - FreeAndNIL(SL); - DeleteFile(PChar(source + 'Introductie BrewBuddy Sassy Saison.pdf')); - DeleteFile(PChar(source + 'styles-BJCP.xml')); - DeleteFile(PChar(source + 'logo.png')); - end; - FrmMain.cbBrewsSortChange(FrmMain); - FrmMain.cbRecipesSortChange(FrmMain); - end - else //copy from old directory and overwrite files in new directory - begin - Brews.SaveXML; - Equipments.SaveXML; - Fermentables.SaveXML; - Hops.SaveXML; - Mashs.SaveXML; - Miscs.SaveXML; - Recipes.SaveXML; - Beerstyles.SaveXML; - Waters.SaveXML; - Yeasts.SaveXML; - StyleSubs.SaveXML; - FermentableSubs.SaveXML; - YeastSubs.SaveXML; - BHNNs.SaveXML; - SL:= FindAllFiles(source, '*.nn', false); - for i:= 0 to SL.Count - 1 do - CheckCopyFile(source, destination, ExtractFileName(SL.Strings[i])); - FreeAndNIL(SL); - - //delete files in old directory - if deleteold then - begin - DeleteFile(PChar(source + 'brews.xml')); - DeleteFile(PChar(source + 'equipments.xml')); - DeleteFile(PChar(source + 'fermentables.xml')); - DeleteFile(PChar(source + 'hops.xml')); - DeleteFile(PChar(source + 'mashs.xml')); - DeleteFile(PChar(source + 'miscs.xml')); - DeleteFile(PChar(source + 'recipes.xml')); - DeleteFile(PChar(source + 'styles.xml')); - DeleteFile(PChar(source + 'waters.xml')); - DeleteFile(PChar(source + 'yeasts.xml')); - DeleteFile(PChar(source + 'stylesubs.xml')); - DeleteFile(PChar(source + 'fermentablesubs.xml')); - DeleteFile(PChar(source + 'yeastsubs.xml')); - DeleteFile(PChar(source + 'neuralnetworks.xml')); - SL:= FindAllFiles(source, '*.nn', false); - for i:= 0 to SL.Count - 1 do - DeleteFile(PChar(SL.Strings[i])); - FreeAndNIL(SL); - end; - end; - Settings.Save; -end; - -{====================== Initialization and Finalization =======================} - -Initialization - if DoLog then slLog:= TStringList.Create - else slLog:= NIL; - Screen.Cursor:= crHourglass; - - ExecFolder:= Application.Location; - log('ExecFolder = ' + ExecFolder); - OnUSB:= false; - {$ifdef UNIX} - {DriveLetter:= LeftStr(ExecFolder, 6); - if DriveLetter = '/media' then - begin - BHFolder:= ExecFolder; - end - else - begin} - BHFolder:= GetUserDir + '.brewbuddy/'; - // DataFolder:= GetUserDir + '.brewbuddy/'; - { end;} - SoundFolder:= BHFolder + 'sounds/'; - IconFolder:= BHFolder + 'icons/'; - Slash:= '/'; - {$endif} - {$ifdef darwin} - BHFolder:= GetUserDir + '.brewbuddy/'; -// DataFolder:= GetUserDir + '.brewbuddy/'; - SoundFolder:= BHFolder + 'sounds/'; - IconFolder:= BHFolder + 'icons/'; - Slash:= '/'; - {$endif} - {$ifdef windows} - DriveLetter:= LeftStr(ExecFolder, 2); - if GetDriveType(PChar(DriveLetter)) = DRIVE_REMOVABLE then - begin - Log('Gestart van USB'); - BHFolder:= DriveLetter + '\brewbuddy\brewbuddy\'; - OnUSB:= TRUE; - end - else - begin - Log('Gestart van harddisk'); - BHFolder:= GetWindowsSpecialDir(CSIDL_PERSONAL); //GetUserDir - if FileExists(BHFolder + 'My Documents\brewbuddy\settings.xml') then - BHFolder:= BHFolder + 'My Documents\brewbuddy\' - else - BHFolder:= BHFolder + 'brewbuddy\'; - end; - log('BHFolder = ' + BHFolder); - SoundFolder:= BHFolder + 'sounds\'; - IconFolder:= BHFolder + 'icons\'; - Slash:= '\'; - {$endif} - - CheckDataFolder; //settings are read here - - Fermentables:= TFermentables.Create; - Hops:= THops.Create; - Miscs:= TMiscs.Create; - Yeasts:= TYeasts.Create; - Waters:= TWaters.Create; - Equipments:= TEquipments.Create; - Beerstyles:= TBeerstyles.Create; - Mashs:= TMashs.Create; - Recipes:= TRecipes.Create; - - Brews:= TRecipes.Create; - Brews.FileName:= 'brews.xml'; - - BHNNs:= TBHNNs.Create; - - loc:= Settings.DataLocation.Value; - if loc = '' then loc:= BHFolder; - if OnUSB then //datalocation is also on the USB - loc:= BHFolder; - if InitializeHD('fermentables.xml', loc) then - begin - if not OnUSB then Settings.DataLocation.Value:= loc; - - BHCloud:= TBHCloud.Create; -// BHCloud.ReadCloud; - - Fermentables.ReadXML; - Hops.ReadXML; - Miscs.ReadXML; - Yeasts.ReadXML; - Waters.ReadXML; - Equipments.ReadXML; - Beerstyles.ReadXML; - Mashs.ReadXML; - Application.ProcessMessages; - Recipes.ReadXML; - Recipes.CheckAutoNrs; - Application.ProcessMessages; - Brews.ReadXML; - Brews.CheckAutoNrs; - - StyleSubs.ReadXML; - FermentableSubs.ReadXML; - YeastSubs.ReadXML; - - BHNNs.ReadXML; - - CheckSalts; - end - else - ShowMessage('Databestanden niet gevonden'); -// Equipments.CalcEfficiencyRegressionFactors; -// Equipments.CalcAttenuationRegressionFactors; - - { SetLength(Arr, 8); - Arr[0]:= 4; - Arr[1]:= 56; - Arr[2]:= 45; - Arr[3]:= 19; - Arr[4]:= 22; - Arr[5]:= 23; - Arr[6]:= 9; - Arr[7]:= 11; - Brews.ExportToCSV(Arr); - SetLength(Arr, 0);} - - Screen.Cursor:= crDefault; - -Finalization - if OnUSB then - begin - Settings.DataLocation.Value:= ''; - Settings.Save; - end; - Log(''); -// Log('CONTAINERS'); - FreeAndNIL(BHCloud); -// Log('BHCloud afgesloten'); - StyleSubs.SaveXML; -// Log('StyleSubs opgeslagen'); - FermentableSubs.SaveXML; -// Log('FermentableSubs opgeslagen'); - YeastSubs.SaveXML; -// Log('YeastSubs opgeslagen'); - FreeAndNIL(StyleSubs); -// Log('StyleSubs afgesloten'); - FreeAndNIL(FermentableSubs); -// Log('FermentableSubs afgesloten'); - FreeAndNIL(YeastSubs); -// Log('YeastSubs afgesloten'); - - FreeAndNIL(Fermentables); -// Log('Fermentables afgesloten'); - FreeAndNIL(Hops); -// Log('Hops afgesloten'); - FreeAndNIL(Miscs); -// Log('Miscs afgesloten'); - FreeAndNIL(Yeasts); -// Log('Yeasts afgesloten'); - FreeAndNIL(Waters); -// Log('Waters afgesloten'); - FreeAndNIL(Equipments); -// Log('Equipments afgesloten'); - FreeAndNIL(Beerstyles); -// Log('Beerstyles afgesloten'); - FreeAndNIL(Mashs); -// Log('Mashs afgesloten'); - FreeAndNIL(Recipes); -// Log('Recipes afgesloten'); - FreeAndNIL(Brews); -// Log('Brews afgesloten'); - FreeAndNIL(BHNNs); -// Log('BHNNs afgesloten'); - - Settings.Save; - Log('Settings opgeslagen'); - FreeAndNIL(Settings); -// Log('Settings afgesloten'); - - if DoLog then FreeAndNIL(slLog); -end. - diff --git a/Source/Units/backup/bh_report.pas b/Source/Units/backup/bh_report.pas deleted file mode 100644 index ae2cec49..00000000 --- a/Source/Units/backup/bh_report.pas +++ /dev/null @@ -1,2464 +0,0 @@ -unit BH_report; - -{$mode objfpc}{$H+} - -interface - -uses - Classes, SysUtils, Graphics, ExtCtrls, Printers, Types, TAGraph; - -type - TBHRDocument = class; - - TBHRElement = class(TObject) - Constructor Create(D : TBHRDocument); virtual; - Destructor Destroy; override; - private - FDocument : TBHRDocument; - FRect : TRect; - FPageNrS, FPageNrE, FMinHeight : integer; - FKeepWithNext : boolean; - FKeepTogether : boolean; - FPrior, FNext : TBHRElement; - Procedure SetRect(R : TRect); - Function GetLeft : word; - Function GetRight : word; - Function GetTop : word; - Function GetBottom : word; - Function GetMinHeight : word; - Procedure SetLeft(l : word); virtual; - Procedure SetRight(r : word); virtual; - procedure SetTop(t : word); virtual; - Procedure SetBottom(b : word); virtual; - procedure SetMinHeight(h : word); virtual; - Procedure SetNext(E : TBHRElement); virtual; - Procedure SetPrior(E : TBHRElement); virtual; - Procedure SetPageNrS(i : integer); virtual; - Procedure SetPageNrE(i : integer); virtual; - Procedure SetKeepTogether(b : boolean); virtual; - protected - Procedure DeployKeepWithNext; virtual; - Procedure Move(PNr, Tp : word); virtual; - public - Procedure Draw(Cnvs : TCanvas; Pnr : integer; Scale : single); virtual; - Procedure CalcRect; virtual; - property Rect : TRect read FRect write SetRect; - property Left : word read GetLeft write SetLeft; - property Right : word read GetRight write SetRight; - property Top : word read GetTop write SetTop; - property Bottom : word read GetBottom write SetBottom; - property MinHeight : word read GetMinHeight write SetMinHeight; - property PageNrS : integer read FPageNrS write SetPageNrS; - property PageNrE : integer read FPageNrE write SetPageNrE; - property KeepWithNext : boolean read FKeepWithNext write FKeepWithNext; - property KeepTogether : boolean read FKeepTogether write SetKeepTogether; - property Next : TBHRElement read FNext write SetNext; - property Prior : TBHRElement read FPrior write SetPrior; - published - end; - - TBHRImage = class(TBHRElement) - Constructor Create(D : TBHRDocument); override; - Destructor Destroy; override; - private - FPicture : TPicture; - FStretch : boolean; - protected - public - Procedure Draw(Cnvs : TCanvas; Pnr : integer; Scale : single); override; - Procedure CalcRect; override; - published - property Picture : TPicture read FPicture; - property Stretch : boolean read FStretch write FStretch; - end; - - { TBHRBHGraph = class(TBHRElement) - Constructor Create(D : TBHRDocument); override; - Destructor Destroy; override; - private - FGraph : TBHGraph; - FStretch : boolean; - protected - public - Procedure Draw(Cnvs : TCanvas; Pnr : integer; Scale : single); override; - Procedure CalcRect; override; - published - property Graph : TBHGraph read FGraph write FGraph; - property Stretch : boolean read FStretch write FStretch; - end; } - - TBHRChart = class(TBHRElement) - Constructor Create(D : TBHRDocument); override; - Destructor Destroy; override; - private - FChart : TChart; - FStretch : boolean; - protected - public - Procedure Draw(Cnvs : TCanvas; Pnr : integer; Scale : single); override; - Procedure CalcRect; override; - published - property Chart : TChart read FChart write FChart; - property Stretch : boolean read FStretch write FStretch; - end; - - TBHRText = class; - TBHRCell = class; - - TBHRTable = class(TBHRElement) - Constructor Create(D : TBHRDocument); override; - Destructor Destroy; override; - private - FCells : array of array of TBHRCell; - FAutoSizeCells : boolean; - FColsEven : boolean; - Function GetRowColor(i : word) : TColor; - Procedure SetRowColor(i : word; cl : TColor); - Function GetColColor(i : word) : TColor; - Procedure SetColColor(i : word; cl : TColor); - Procedure SetPageNrS(i : integer); override; - Procedure SetPageNrE(i : integer); override; - Procedure SetAutoSizeCells(b : boolean); - Procedure SetKeepTogether(b : boolean); override; - protected - Procedure Move(PNr, Tp : word); override; - public - Function GetCell(aRow, aCol : integer) : TBHRCell; - Function NumRows : integer; - Function NumCols : integer; - Function GetColWidth(aCol : integer) : word; - Procedure SetColWidth(aCol : integer; Width : word); - Procedure SetColsEven(b : boolean); - Function GetRowHeight(aRow : integer) : word; - Procedure SetRowHeight(ARow : integer; Height : word); - Procedure AddRow; - Procedure AddCol; - Procedure SetSize(NRows, NCols : integer); - Procedure Draw(Cnvs : TCanvas; Pnr : integer; Scale : single); override; - Procedure CalcRect; override; - property Cells[ARow, ACol: integer] : TBHRCell read GetCell; - property ColWidth[ACol : integer] : word read GetColWidth write SetColWidth; - property RowHeight[ARow : integer] : word read GetRowHeight write SetRowHeight; - property RowColor[i : word] : TColor read GetRowColor write SetRowColor; - property ColColor[i : word] : TColor read GetColColor write SetColColor; - published - property AutoSizeCells : boolean read FAutoSizeCells write SetAutoSizeCells; - property ColsEven : boolean read FColsEven write SetColsEven; - end; - - TBHRCell = class(TBHRElement) - Constructor Create(D : TBHRDocument; R, C : integer); - Destructor Destroy; override; - private - FText : TBHRText; - FTable : TBHRTable; - FRow, FColumn : integer; - Procedure SetLeft(l : word); override; - Procedure SetRight(r : word); override; - procedure SetTop(t : word); override; - Procedure SetBottom(b : word); override; - Function GetFont : TFont; - Function GetBrush : TBrush; - Function GetPen : TPen; - Function GetAlignment : TAlignment; - Procedure SetAlignment(al : TAlignment); - Function GetKeepTogether : boolean; - Function GetMarge : word; - Procedure SetMarge(w : word); - Function GetAutoSize : boolean; - Procedure SetAutoSize(b : boolean); - Procedure SetKeepTogether(b : boolean); override; - Procedure SetNext(E : TBHRElement); override; - Procedure SetPrior(E : TBHRElement); override; - Function GetCheckBoxes : boolean; - Procedure SetCheckBoxes(b : boolean); - Function GetCheckBoxSize : LongInt; - Procedure SetCheckBoxSize(L : LongInt); - Procedure SetPageNrS(i : integer); override; - Procedure SetPageNrE(i : integer); override; - protected - Procedure Move(PNr, Tp : word); override; - public - Procedure Draw(Cnvs : TCanvas; Pnr : integer; Scale : single); override; - Procedure CalcRect; override; - published - Property Content : TBHRText read FText; - property Row : integer read FRow write FRow; - property Column : integer read FColumn write FColumn; - property Font : TFont read GetFont; - property Brush : TBrush read GetBrush; - property Pen : TPen read GetPen; - property Alignment : TAlignment read GetAlignment write SetAlignment; - property KeepTogether : boolean read GetKeepTogether write SetKeepTogether; - property Marge : word read GetMarge write SetMarge; - property AutoSize : boolean read GetAutoSize write SetAutoSize; - property CheckBoxes : boolean read GetCheckBoxes write SetCheckBoxes; - property CheckBoxSize : LongInt read GetCheckBoxSize write SetCheckBoxSize; - property Table : TBHRTable read FTable write FTable; - end; - - TWhere = (twAbove, twBelow); - TLineProps = record - Rect : TRect; - PageNr : integer; - TextRect : TRect; - end; - - TBHRText = class(TBHRElement) - Constructor Create(D : TBHRDocument); override; - Destructor Destroy; override; - private - FCell : TBHRCell; - FStrings : TStringList; - FFont : TFont; - FBrush : TBrush; - FPen : TPen; - FAlignment : TAlignment; - FLineProps : Array of TLineProps; - FMarge : word; - FAutoSize : boolean; - FCheckBoxes : boolean; - FChecked : boolean; - FCheckBoxSize : Longint; - FFontHeight : integer; - Function GetString(i : integer) : string; - Procedure SetString(i : integer; s : string); - Procedure SetMarge(w : word); - protected - Procedure Move(PNr, Tp : word); override; - public - Procedure Draw(Cnvs : TCanvas; Pnr : integer; Scale : single); override; - Procedure CalcRect; override; - Procedure AddString(s : string); - Procedure RemoveString(i : integer); - Procedure InsertString(s : string; i : integer; Where : TWhere); - property Line[i : integer] : string read GetString write SetString; - published - property Cell : TBHRCell read FCell write FCell; - property Font : TFont read FFont; - property Brush : TBrush read FBrush; - property Pen : TPen read FPen; - property Alignment : TAlignment read FAlignment write FAlignment; - property Marge : word read FMarge write SetMarge; - property AutoSize : boolean read FAutoSize write FAutoSize; - property CheckBoxes : boolean read FCheckBoxes write FCheckBoxes; - property Checked : boolean read FChecked write FChecked; - property CheckBoxSize : LongInt read FCheckBoxSize write FCheckBoxSize; - end; - - THeaderType = (thHeader, thFooter); - - TBHRHeader = class(TBHRElement) - Constructor Create(D : TBHRDocument; HT : THeaderType); - Destructor Destroy; override; - private - FPicture : TPicture; - FPictRect, FTxtRect : TRect; - FText : string; - FHeight : LongInt; - FHeaderType : THeaderType; - FFont : TFont; - FFontHeight : integer; - FBrush : TBrush; - FPen : TPen; - FAlignment : TAlignment; - FMarge : word; - Procedure SetPictRect(R : TRect); - Function GetPictRect : TRect; - Procedure SetTxtRect(R : TRect); - Function GetTxtRect : TRect; - Procedure SetHeight(H : LongInt); - Procedure SetText(S : string); - protected - public - Procedure Draw(Cnvs : TCanvas; Pnr : integer; Scale : single); override; - Procedure CalcRect; override; - property PictRect : TRect read GetPictRect write SetPictRect; - property TxtRect : TRect read GetPictRect write SetPictRect; - published - property Picture : TPicture read FPicture; - property Height : LongInt read FHeight write SetHeight; - property Text : string read FText write SetText; - property Font : TFont read FFont; - property Brush : TBrush read FBrush; - property Pen : TPen read FPen; - property Alignment : TAlignment read FAlignment write FAlignment; - property Marge : word read FMarge write FMarge; - end; - - TBHRDocument = class(TObject) - Constructor Create; - Destructor Destroy; override; - private - FHeader : TBHRHeader; - FFooter : TBHRHeader; - FNumPages : word; - FElements : array of TBHRElement; - FPageRect, FPrintRect : TRect; - FMarginBT : single; - FMarginLR : single; - FMarginBTpx : integer; - FMarginLRpx : integer; - FLastY : word; - FLastPage : word; - Procedure GetPrinterProps; - Function GetNumElements : integer; - Procedure CalcRects; - Function GetElement(i : integer) : TBHRElement; - protected - public - Procedure AddPage; - Procedure RemovePage; - Function AddText(Rect : TRect; s : string) : TBHRText; - Function AddTable(Rect : TRect; nCol, nRow : integer) : TBHRTable; - Function AddImage(Rect : TRect) : TBHRImage; -// Function AddGraph(Rect : TRect) : TBHRBHGraph; - Function AddChart(Rect : TRect) : TBHRChart; - Function AddSpace(Rect : TRect; h : word) : TBHRElement; - Procedure Print(FromPage, ToPage, Copies : integer); - Procedure PrintPreview; - Procedure DrawPages(cnvs : TCanvas; Scale : single); - Procedure DrawPage(cnvs : TCanvas; PageNr : integer; Scale : single); - Procedure Repaginate; - Function GetLineHeight(fh : integer) : integer; - property Element[i : integer] : TBHRElement read GetElement; - property Header : TBHRHeader read FHeader; - property Footer : TBHRHeader read FFooter; - property PageRect : TRect read FPageRect; - property PrintRect : TRect read FPrintRect; - published - property MarginBT : single read FMarginBT write FMarginBT; - property MarginLR : single read FMarginLR write FMarginLR; - property NumElements : integer read GetNumElements; - property NumPages : word read FNumPages; - property LastY : word read FLastY; - end; - -implementation - -uses frmain, HulpFuncties, frprintpreview, StrUtils, TASeries, Controls; - -Function CmToPixX(cm : single) : word; -begin - if Printer <> NIL then Result:= round(cm / 2.54 * Printer.XDPI) - else Result:= round(cm / 2.54 * 600); -end; - -Function CmToPixY(cm : single) : word; -begin - if Printer <> NIL then Result:= round(cm / 2.54 * Printer.YDPI) - else Result:= round(cm / 2.54 * 600); -end; - -Function FontSizeToPix(sz, scale : single) : word; -var dpy : integer; -begin - if Printer <> NIL then dpy:= Printer.YDPI - else dpy:= 600; - if abs(sz) < 40 then Result:= round(scale * abs(sz) / 72 * dpy) - else Result:= round(scale * 8 / 72 * dpy); -end; - -Function ScaleRect(R : TRect; scale : single) : TRect; -begin - Result.Left:= round(scale * R.Left); - Result.Right:= round(scale * R.Right); - Result.Top:= round(scale * R.Top); - Result.Bottom:= round(scale * R.Bottom); -end; - -Constructor TBHRElement.Create(D : TBHRDocument); -begin - Inherited Create; - FDocument:= D; - FRect.Bottom:= 0; - FRect.Top:= 0; - FRect.Left:= 0; - FRect.Right:= 0; - FPageNrS:= FDocument.NumPages; - FPageNrE:= FDocument.NumPages; - FKeepWithNext:= false; - FKeepTogether:= TRUE; - FNext:= NIL; - FPrior:= NIL; -end; - -Destructor TBHRElement.Destroy; -begin - Inherited Destroy; -end; - -Procedure TBHRElement.Draw(Cnvs : TCanvas; Pnr : integer; Scale : single); -begin -end; - -Procedure TBHRElement.SetRect(R : TRect); -begin - FRect.Left:= R.Left; - FRect.Right:= R.Right; - FRect.Top:= R.Top; - FRect.Bottom:= R.Bottom; -end; - -Function TBHRElement.GetLeft : word; -begin - Result:= FRect.Left; -end; - -Procedure TBHRElement.SetLeft(l : word); -begin - FRect.Left:= l; -end; - -Function TBHRElement.GetRight : word; -begin - Result:= FRect.Right; -end; - -Procedure TBHRElement.SetRight(r : word); -begin - FRect.Right:= r; -end; - -Function TBHRElement.GetTop : word; -begin - Result:= FRect.Top; -end; - -procedure TBHRElement.SetTop(t : word); -begin - FRect.Top:= t; -end; - -Function TBHRElement.GetBottom : word; -begin - Result:= FRect.Bottom; -end; - -Procedure TBHRElement.SetBottom(b : word); -begin - FRect.Bottom:= b; -end; - -Procedure TBHRElement.SetKeepTogether(b : boolean); -begin - if FKeepTogether <> b then - begin - FKeepTogether:= b; - end; -end; - -Function TBHRElement.GetMinHeight : word; -begin - Result:= FMinHeight; -end; - -Procedure TBHRElement.SetMinHeight(h : word); -begin - FMinHeight:= h; -end; - -Procedure TBHRElement.SetNext(E : TBHRElement); -begin - FNext:= E; -end; - -Procedure TBHRElement.SetPrior(E : TBHRElement); -begin - FPrior:= E; -end; - -Procedure TBHRElement.SetPageNrS(i : integer); -begin - if (i > 0) {and (i <= FDocument.NumPages)} then - begin - FPageNrS:= i; - if FPageNrE < FPageNrS then - FPageNrE:= FPageNrS; - end; -end; - -Procedure TBHRElement.SetPageNrE(i : integer); -begin - if (i > 0) {and (i <= FDocument.NumPages)} then - begin - FPageNrE:= i; - if FPageNrE < FPageNrS then - FPageNrS:= FPageNrE; - end; -end; - -Procedure TBHRElement.Move(PNr, Tp : word); -var h : word; - i, j : integer; -begin - j:= 0; - if FPageNrE > FPageNrS then - begin - h:= FDocument.PrintRect.Bottom - FRect.Top; - for i:= 1 to (FPageNrE - FPageNrS - 1) do - begin - Inc(j); - h:= h + FDocument.PrintRect.Bottom - FDocument.PrintRect.Top; - end; - Inc(j); - h:= FRect.Bottom - FDocument.PrintRect.Top; - end - else - h:= FRect.Bottom - FRect.Top; - FRect.Top:= tp; - FPageNrS:= PNr; - FPageNrE:= FPageNrS + j; - while h > 0 do - begin - FRect.Bottom:= tp + h; - if FRect.Bottom > FDocument.PrintRect.Bottom then - begin - h:= h - (FDocument.PrintRect.Bottom - FDocument.PrintRect.Top); - tp:= FDocument.PrintRect.Top; - end - else - begin - h:= 0; - end; - end; -end; - -Procedure TBHRElement.CalcRect; -begin - if FPrior <> NIL then - begin - Top:= FPrior.Bottom; - FPageNrS:= FPrior.PageNrE; - end - else - begin - //Top:= FDocument.FPrintRect.Top; - //FPageNrS:= 1; - end; - FPageNRE:= FPageNRS; - Bottom:= Top + FMinHeight; -end; - -Procedure TBHRElement.DeployKeepWithNext; -var E : TBHRElement; - PNr, Tp : word; -begin - if FPrior <> NIL then - begin - if (FPrior.KeepWithNext) and (FPageNRS > FPrior.PageNrE) then - begin - E:= FPrior; - While (E.Prior <> NIL) and E.Prior.KeepWithNext do - E:= E.Prior; - Tp:= FDocument.PrintRect.Top; - PNr:= E.PageNrS + 1; - While E <> self.Next do - begin - E.Move(PNr, Tp); - PNr:= E.PageNrE; - Tp:= E.Bottom; - E:= E.Next; - end; - end; - end; -end; - -{========================== TBHRHeader =======================================} - -Constructor TBHRHeader.Create(D : TBHRDocument; HT : THeaderType); -begin - Inherited Create(D); - FHeaderType:= HT; - FText:= ''; - FPicture := TPicture.Create; - FFont := TFont.Create; - with FFont do - begin -// CharSet:= DEFAULT_CHARSET; - Color:= clBlack; - Size:= 14; -// Name:= default; - Orientation:= 0; - Pitch:= fpDefault; - Quality:= fqDefault; //fqAntiAliased - Style:= []; - end; - FBrush:= TBrush.Create; - with FBrush do - begin - Color:= clWhite; - Style:= bsSolid; - end; - FPen:= TPen.Create; - with FPen do - begin - Color:= clBlack; - Style:= psSolid; - Width:= 1; - end; - FMarge:= CmToPixY(0.2); - - if FHeaderType = thHeader then - begin - FRect.Top:= FMarge; - FRect.Left:= FMarge; - FRect.Right:= FDocument.PageRect.Right - FMarge; - FRect.Bottom:= FDocument.PrintRect.Top; - FPictRect.Top:= FRect.Top + FMarge; - FPictRect.Bottom:= FRect.Bottom - FMarge; - FPictRect.Left:= 0; - FPictRect.Right:= 0; - FAlignment:= taCenter; - end - else - begin - FRect.Top:= FDocument.PrintRect.Bottom + FMarge; - FRect.Left:= FMarge; - FRect.Right:= FDocument.PageRect.Right - FMarge; - FRect.Bottom:= FDocument.PageRect.Bottom - FMarge; - FPictRect.Top:= FRect.Top + 5; - FPictRect.Bottom:= FRect.Bottom - 5; - FPictRect.Left:= 0; - FPictRect.Right:= 0; - FAlignment:= taRightJustify; - end; - FHeight:= FRect.Bottom - FRect.Top; -end; - -Destructor TBHRHeader.Destroy; -begin - FPicture.Free; - FFont.Free; - FBrush.Free; - FPen.Free; - Inherited; -end; - -Procedure TBHRHeader.SetPictRect(R : TRect); -begin - FPictRect:= R; -end; - -Function TBHRHeader.GetPictRect : TRect; -begin - Result:= FPictRect; -end; - -Procedure TBHRHeader.SetTxtRect(R : TRect); -begin - FTxtRect:= R; -end; - -Function TBHRHeader.GetTxtRect : TRect; -begin - Result:= FTxtRect; -end; - -Procedure TBHRHeader.SetText(S : string); -begin - FText:= S; -end; - -Procedure TBHRHeader.SetHeight(H : LongInt); -begin - if (FHeight <> H) and (H >= 0) and - (H < round(0.1 * (FDocument.PageRect.Bottom - FDocument.PageRect.Top))) then - begin - FHeight:= H; - if FHeaderType = thHeader then - FDocument.FPrintRect.Top:= FDocument.PageRect.Top + FHeight - else - FDocument.FPrintRect.Bottom:= FDocument.PageRect.Bottom - FHeight; - CalcRect; - end; -end; - -Procedure TBHRHeader.Draw(Cnvs : TCanvas; Pnr : integer; Scale : single); -var R, SRect : TRect; - mh, FH : LongInt; -begin - //Draw the picture - if (not FPicture.Bitmap.Empty) or (not FPicture.Graphic.Empty) or (not FPicture.Jpeg.Empty) - or (not FPicture.PNG.Empty) or (not FPicture.PNM.Empty) or (not FPicture.Pixmap.Empty) then - begin - R.Left:= 0; - R.Top:= 0; - R.Right:= FPicture.Width; - R.Bottom:= FPicture.Height; - SRect:= ScaleRect(FPictRect, Scale); - - cnvs.Pen.Style:= psClear; - cnvs.Brush.Color:= clWhite; - cnvs.Rectangle(FPictRect); - cnvs.CopyMode:= cmSrcCopy; - cnvs.CopyRect(SRect, FPicture.Bitmap.Canvas, R); - end; - - //Draw the text - cnvs.Font.Assign(FFont); - FH:= round(1.2 * FontSizeToPix(cnvs.Font.Size, 1)); - //first, try if the text fits in the designated area. If not, lower the font size - mh:= cnvs.TextWidth(FText); - while (mh > (FTxtRect.Right - FTxtRect.Left)) and (FFont.Size >= 1) do - begin - cnvs.Font.Size:= cnvs.Font.Size - 1; - FH:= round(1.2 * FontSizeToPix(cnvs.Font.Size, 1)); - mh:= cnvs.TextWidth(FText); - end; - FTxtRect.Top:= FTxtRect.Bottom - FH; - - SRect:= ScaleRect(FTxtRect, Scale); - cnvs.Font.Height:= FontSizeToPix(FFont.Size, Scale); - mh:= round((SRect.Bottom + SRect.Top) / 2); - DrawTxt(Cnvs, mh, SRect.Left, SRect.Right, FText, FAlignment, TRUE); - - //Draw the line - cnvs.Pen.Assign(FPen); - SRect:= ScaleRect(FRect, Scale); - if FHeaderType = thHeader then - begin - cnvs.MoveTo(SRect.Left, SRect.Bottom); - cnvs.LineTo(SRect.Right, SRect.Bottom); - end - else - begin - cnvs.MoveTo(SRect.Left, SRect.Top); - cnvs.LineTo(SRect.Right, SRect.Top); - end; -end; - -Procedure TBHRHeader.CalcRect; -var W, H : LongInt; - WH : double; -begin - if FHeaderType = thHeader then - begin - FRect.Top:= FDocument.PageRect.Top + FMarge; - FRect.Left:= FDocument.PrintRect.Left; - FRect.Right:= FDocument.PrintRect.Right; - FRect.Bottom:= FDocument.PrintRect.Top - FMarge; - FPictRect.Top:= FRect.Top + FMarge; - FPictRect.Bottom:= FRect.Bottom - FMarge; - FPictRect.Left:= FRect.Left; - FPictRect.Right:= 0; - end - else - begin - FRect.Top:= FDocument.PrintRect.Bottom + FMarge; - FRect.Left:= FDocument.PrintRect.Left; - FRect.Right:= FDocument.PrintRect.Right; - FRect.Bottom:= FDocument.PageRect.Bottom - FMarge; - FPictRect.Top:= FRect.Top + FMarge; - FPictRect.Bottom:= FRect.Bottom - FMarge; - FPictRect.Left:= FRect.Left; - FPictRect.Right:= 0; - end; - FHeight:= FRect.Bottom - FRect.Top; - - W:= FPicture.Width; - H:= FPicture.Height; - if H > 0 then - begin - WH:= W / H; - FPictRect.Right:= FPictRect.Left + round(WH * (FPictRect.Bottom - FPictRect.Top)); - end; - - FTxtRect.Left:= FPictRect.Right + FMarge; - FTxtRect.Right:= FRect.Right; - FFontHeight:= round(1.2 * FontSizeToPix(FFont.Size, 1)); - - if FHeaderType = thHeader then - begin - FTxtRect.Bottom:= FRect.Bottom - FMarge; - FTxtRect.Top:= FTxtRect.Bottom - FFontHeight; - end - else - begin - FTxtRect.Top:= FRect.Top + FMarge; - FTxtRect.Bottom:= FTxtRect.Top + FFontHeight; - end; -end; - -{========================== TBHRImage =======================================} - -Constructor TBHRImage.Create(D : TBHRDocument); -begin - Inherited Create(D); - FPicture := TPicture.Create; - FStretch:= false; -end; - -Destructor TBHRImage.Destroy; -begin - FPicture.Free; - Inherited; -end; - -Procedure TBHRImage.Draw(Cnvs : TCanvas; Pnr : integer; Scale : single); -var R, SRect : TRect; -begin - if (FPageNrS = PNr) then - begin - R.Left:= 0; - R.Top:= 0; - R.Right:= FPicture.Width; - R.Bottom:= FPicture.Height; - SRect:= ScaleRect(FRect, Scale); - - cnvs.Brush.Color:= clWhite; - cnvs.Rectangle(FRect); - cnvs.CopyMode:= cmSrcCopy; - cnvs.CopyRect(SRect, FPicture.Bitmap.Canvas, R); - end; -end; - -Procedure TBHRImage.CalcRect; -var W, H : LongInt; - WH : double; -begin - Inherited CalcRect; - if not FStretch then - begin - W:= FPicture.Width; - H:= FPicture.Height; - if H > 0 then - begin - WH:= W / H; - if WH > 1 then - begin - FRect.Right:= FRect.Left + W; - FRect.Bottom:= FRect.Top + round((FRect.Right - FRect.Left) / WH); - end - else - begin - FRect.Bottom:= FRect.Top + H; - FRect.Right:= FRect.Left + round((FRect.Bottom - FRect.Top) * WH); - end; - end; - end; - DeployKeepWithNext; -end; - -{============================TBHRBHGraph ======================================} - -{Constructor TBHRBHGraph.Create(D : TBHRDocument); -begin - Inherited Create(D); - FStretch:= false; - FGraph:= NIL; -end; - -Destructor TBHRBHGraph.Destroy; -begin - FGraph:= NIL; - Inherited; -end; - -Procedure TBHRBHGraph.Draw(Cnvs : TCanvas; Pnr : integer; Scale : single); -var SRect : TRect; -begin - if (FPageNrS = PNr) and (FGraph <> NIL) then - begin - SRect:= ScaleRect(FRect, Scale); - - cnvs.Brush.Color:= clWhite; - cnvs.Rectangle(FRect); - - FGraph.PaintTo(cnvs, SRect); - end; -end; - -Procedure TBHRBHGraph.CalcRect; -var W, H : LongInt; - WH : double; -begin - Inherited CalcRect; - if not FStretch then - begin - W:= FGraph.Width; - H:= FGraph.Height; - if H > 0 then - begin - WH:= W / H; - if WH > 1 then - begin - FRect.Bottom:= FRect.Top + round((FRect.Right - FRect.Left) / WH); - FRect.Right:= FRect.Left + W; - end - else - begin - FRect.Right:= FRect.Left + round((FRect.Bottom - FRect.Top) * WH); - FRect.Bottom:= FRect.Top + H; - end; - end; - end; - DeployKeepWithNext; -end; } - -{============================TBHRChart =========================================} - -Constructor TBHRChart.Create(D : TBHRDocument); -begin - Inherited Create(D); - FStretch:= false; - FChart:= NIL; -end; - -Destructor TBHRChart.Destroy; -begin - FChart:= NIL; - Inherited; -end; - -Procedure TBHRChart.Draw(Cnvs : TCanvas; Pnr : integer; Scale : single); -var SRect, BRect : TRect; - bmp : tbitmap; - GSc : single; - i, OLineWidth, OLegendMargin, OSymbolWidth : integer; - OMFH, OTFH, OTL, OLFH : integer; -{const FH = 100; - PenW = 10;} -begin - if FPageNrS = Pnr then - begin - GSc:= Scale * (FRect.Right - FRect.Left) / (FChart.Width); - - FChart.Paint; - FChart.Proportional:= TRUE; - - SRect:= ScaleRect(FRect, Scale); - bmp:= TBitmap.Create; - Bmp.SetSize(SRect.Right - SRect.Left, SRect.Bottom - SRect.Top); - BRect.Top:= 0; - BRect.Left:= 0; - BRect.Bottom:= SRect.Bottom - SRect.Top; - BRect.Right:= SRect.Right - SRect.Left; - {$ifndef Darwin} - OTFH:= FChart.AxisList[0].Title.Font.Size; - {$endif} - OMFH:= FChart.AxisList[0].Marks.LabelFont.Size; - OTL:= FChart.AxisList[0].TickLength; - OLFH:= FChart.Legend.Font.Size; - OLegendMargin:= FChart.Legend.MarginX; - OSymbolWidth:= FChart.Legend.SymbolWidth; - OLineWidth:= TLineSeries(FChart.Series[0]).LinePen.Width; - - for i:= 0 to FChart.AxisList.Count - 1 do - begin - FChart.AxisList[i].Marks.LabelFont.Size:= round(GSc * 9); - {$ifndef Darwin} - FChart.AxisList[i].Title.Font.Size:= round(GSC * 9); - {$endif} - FChart.AxisList[i].TickLength:= round(GSc * OTL); - end; - FChart.Legend.Font.Size:= round(GSc * 9); - FChart.Legend.MarginX:= round(GSc * OLegendMargin); - FChart.Legend.SymbolWidth:= round(GSc * OSymbolWidth); - - //Adjust line width of chart series - for i:= 0 to FChart.SeriesCount - 1 do - TLineSeries(FChart.Series[i]).LinePen.Width:= round(GSc * OLineWidth); - - FChart.PaintOnCanvas(Bmp.Canvas, BRect); - - for i:= 0 to FChart.AxisList.Count - 1 do - begin - FChart.AxisList[i].Marks.LabelFont.Size:= OMFH; - {$IFNDEF LCL qt} - FChart.AxisList[i].Title.Font.Size:= OTFH; - {$ENDIF} - FChart.AxisList[i].TickLength:= OTL; - end; - FChart.Legend.Font.Size:= OLFH; - FChart.Legend.MarginX:= OLegendMargin; - FChart.Legend.SymbolWidth:= OSymbolWidth; - for i:= 0 to FChart.SeriesCount - 1 do - TLineSeries(FChart.Series[i]).LinePen.Width:= OLineWidth; - - cnvs.Brush.Color:= clWhite; - cnvs.Rectangle(FRect); - cnvs.CopyMode:= cmSrcCopy; - cnvs.CopyRect(SRect, Bmp.Canvas, BRect); - Bmp.Free; - end; -end; - -Procedure TBHRChart.CalcRect; -var W, H : LongInt; - WH : double; -begin - Inherited CalcRect; - if not FStretch then - begin - W:= FChart.Width; - H:= FChart.Height; - if H > 0 then - begin - WH:= W / H; - if WH > 1 then - begin - FRect.Bottom:= FRect.Top + round((FRect.Right - FRect.Left) / WH); - // FRect.Right:= FRect.Left + W; - end - else - begin - FRect.Right:= FRect.Left + round((FRect.Bottom - FRect.Top) * WH); - // FRect.Bottom:= FRect.Top + H; - end; - end; - if FRect.Bottom > FDocument.FPrintRect.Bottom then - begin - FPageNrS:= FPageNrS + 1; - FPageNrE:= FPageNrS; - FRect.Top:= FDocument.PrintRect.Top; - if WH > 1 then - begin - FRect.Bottom:= FRect.Top + round((FRect.Right - FRect.Left) / WH); - // FRect.Right:= FRect.Left + W; - end - else - begin - FRect.Right:= FRect.Left + round((FRect.Bottom - FRect.Top) * WH); - FRect.Bottom:= FRect.Top + H; - end; - end; - end; - DeployKeepWithNext; -end; - - -{========================== TBHRText ==========================================} - -Constructor TBHRText.Create(D : TBHRDocument); -begin - Inherited Create(D); - FCell:= NIL; - FStrings := TStringList.Create; - FFont := TFont.Create; - with FFont do - begin -// CharSet:= DEFAULT_CHARSET; - Color:= clBlack; - Size:= 10; -// Name:= default; - Orientation:= 0; - Pitch:= fpDefault; - Quality:= fqDefault; //fqAntiAliased - Style:= []; - end; - FAlignment:= taLeftJustify; - FBrush:= TBrush.Create; - with FBrush do - begin - Color:= clWhite; - Style:= bsSolid; - end; - FPen:= TPen.Create; - with FPen do - begin - Color:= clWhite; - Style:= psSolid; - Width:= 1; - end; - FMarge:= CmToPixY(0.05); - FAutoSize:= false; - FCheckBoxes:= false; - FChecked:= false; - FCheckBoxSize:= CmToPixY(0.4); -end; - -Destructor TBHRText.Destroy; -begin - FStrings.Free; - SetLength(FLineProps, 0); - FFont.Free; - FBrush.Free; - FPen.Free; - Inherited; -end; - -Function TBHRText.GetString(i : integer) : string; -begin - Result:= ''; - if (i >= 0) and (i < FStrings.Count) then - Result:= FStrings[i]; -end; - -Procedure TBHRText.SetString(i : integer; s : string); -begin - if (i >= 0) and (i < FStrings.Count) then - FStrings[i]:= s - else if (i > FStrings.Count - 1) then - AddString(s) - else if (i < 0) then - InsertString(s, 0, twBelow); -end; - -Procedure TBHRText.AddString(s : string); -var i : integer; -begin - FStrings.Add(s); - SetLength(FLineProps, High(FLineProps) + 2); - i:= High(FLineProps); - FLineProps[i].Rect.Left:= FRect.Left; - FLineProps[i].Rect.Right:= FRect.Right; - FLineProps[i].PageNr:= FPageNrS; - FLineProps[i].TextRect.Left:= FRect.Left + FMarge; - FLineProps[i].TextRect.Right:= FRect.Right - FMarge; - FKeepTogether:= false; -end; - -Procedure TBHRText.RemoveString(i : integer); -var j : integer; -begin - if (i >= 0) and (i < FStrings.Count) then - begin - FStrings.Delete(i); - for j:= i to High(FLineProps) - 1 do - FLineProps[j]:= FLineProps[j-1]; - SetLength(FLineProps, High(FLineProps)); - end; -end; - -Procedure TBHRText.InsertString(s : string; i : integer; Where : TWhere); -var j : integer; -begin - if (i >= 0) and (i < FStrings.Count) then - case Where of - twAbove: - begin - FStrings.Insert(i, s); - SetLength(FLineProps, High(FLineProps) + 2); - for j:= High(FLineProps) downto i + 1 do - FLineProps[j]:= FLineProps[j-1]; - FLineProps[i].Rect.Left:= FRect.Left; - FLineProps[i].Rect.Right:= FRect.Right; - FLineProps[i].PageNr:= FPageNrS; - FLineProps[i].TextRect.Left:= FRect.Left + FMarge; - FLineProps[i].TextRect.Right:= FRect.Right - FMarge; - end; - twBelow: - if i = 0 then - begin - FStrings.Add(''); - for j:= FStrings.Count - 1 to 1 do - FStrings[j]:= FStrings[j-1]; - FStrings[0]:= s; - SetLength(FLineProps, High(FLineProps) + 2); - for j:= High(FLineProps) downto 1 do - FLineProps[j]:= FLineProps[j-1]; - FLineProps[0].Rect.Left:= FRect.Left; - FLineProps[0].Rect.Right:= FRect.Right; - FLineProps[0].PageNr:= FPageNrS; - FLineProps[0].TextRect.Left:= FRect.Left + FMarge; - FLineProps[0].TextRect.Right:= FRect.Right - FMarge; - end - else - begin - FStrings.Insert(i-1, s); - SetLength(FLineProps, High(FLineProps) + 2); - for j:= High(FLineProps) downto i + 1 do - FLineProps[j]:= FLineProps[j-1]; - FLineProps[i].Rect.Left:= FRect.Left; - FLineProps[i].Rect.Right:= FRect.Right; - FLineProps[i].PageNr:= FPageNrS; - FLineProps[i].TextRect.Left:= FRect.Left + FMarge; - FLineProps[i].TextRect.Right:= FRect.Right - FMarge; - end; - end; -end; - -Procedure TBHRText.SetMarge(w : word); -begin - if FMarge <> w then FMarge:= w; -end; - -Procedure TBHRText.Move(PNr, Tp : word); -var i, j, t, h: integer; - tot, LL, LMarge, w,fh : LongInt; - s : string; -begin - Inherited Move(PNr, Tp); - FFontHeight:= round(1.2 * FontSizeToPix(FFont.Size, 1)); - if (High(FLineProps) >= 0) then - begin - if FCheckBoxes then LMarge:= 2 * FMarge + FCheckBoxSize + 2 * FMarge - else LMarge:= 2 * FMarge; - tot:= 0; - FLineProps[0].Rect.Top:= FRect.Top; - FLineProps[0].TextRect.Top:= FRect.Top + FMarge; - for i:= 0 to FStrings.Count - 1 do - begin - if i = 0 then FLineProps[i].PageNr:= FPageNrS - else FLineProps[i].PageNr:= FLineProps[i-1].PageNr; - FLineProps[i].TextRect.Left:= FRect.Left + LMarge; - FLineProps[i].TextRect.Right:= FRect.Right - 2 * FMarge; - if i > 0 then - begin - FLineProps[i].Rect.Top:= FLineProps[i-1].Rect.Bottom; - FLineProps[i].PageNr:= FLineProps[i-1].PageNr; - end; - FLineProps[i].TextRect.Top:= FLineProps[i].Rect.Top + FMarge; - s:= FStrings[i]; - w:= FLineProps[i].TextRect.Right - FLineProps[i].TextRect.Left; - if FAutoSize and (w > 0) then - begin - fh:= FFont.Height; - FFont.Height:= FFontHeight; - LL:= CalcAmountLines2(FFont, s, w); - FFont.Height:= fh; - end - else - LL:= 1; - - LL:= LL * FFontHeight; - FLineProps[i].TextRect.Bottom:= FLineProps[i].TextRect.Top + LL; - FLineProps[i].Rect.Bottom:= FLineProps[i].TextRect.Bottom + FMarge; - t:= FLineProps[i].Rect.Bottom - FLineProps[i].Rect.Top; - if (FLineProps[i].Rect.Bottom > FDocument.FPrintRect.Bottom) and - ((not FKeepTogether) or (i = 0))then - begin - FLineProps[i].PageNr:= FLineProps[i].PageNr + 1; - FPageNrE:= FPageNrE + 1; - if i = 0 then FPageNRS:= FPageNRE; - FLineProps[i].Rect.Top:= FDocument.FPrintRect.Top; - FLineProps[i].Rect.Bottom:= FLineProps[i].Rect.Top + t; - FLineProps[i].TextRect.Top:= FLineProps[i].Rect.Top + FMarge; - FLineProps[i].TextRect.Bottom:= FLineProps[i].Rect.Bottom - FMarge; - end; - if (i > 0) and FKeepTogether and (FLineProps[i-1].PageNr < FLineProps[i].PageNr) then - begin - FPageNrS:= FPageNRE; - for j:= 0 to i do - begin - h:= FLineProps[j].Rect.Bottom - FLineProps[j].Rect.Top; - if j = 0 then FLineProps[j].Rect.Top:= FDocument.FPrintRect.Top - else FLineProps[j].Rect.Top:= FLineProps[j-1].Rect.Bottom; - FLineProps[j].Rect.Bottom:= FLineProps[j].Rect.Top + h; - FLineProps[j].TextRect.Top:= FLineProps[j].Rect.Top + FMarge; - FLineProps[j].TextRect.Bottom:= FLineProps[j].Rect.Bottom - FMarge; - FLineProps[j].PageNr:= FPageNrS; - end; - if (FLineProps[i].Rect.Bottom > FDocument.FPrintRect.Bottom) and FKeeptogether then - //lines do not fit on the page all, so Keeptogether cannot be implemented - begin - FKeeptogether:= false; - CalcRect; - end; - end; - tot:= tot + t; - end; - FRect.Top:= FLineProps[0].Rect.Top; - FRect.Bottom:= FLineProps[FStrings.Count - 1].Rect.Bottom; - end - else //make the text at least 1 line high - begin - FRect.Bottom:= FRect.Top + FFontHeight; - end; -end; - -Procedure TBHRText.CalcRect; -//Calculate the height of the text given the width and font size -var i, j, t, h: integer; - tot, LL, LMarge, w,fh : LongInt; - s : string; -begin - Inherited CalcRect; - FFontHeight:= round(1.2 * FontSizeToPix(FFont.Size, 1)); - if (High(FLineProps) >= 0) then - begin - if FCheckBoxes then LMarge:= 2 * FMarge + FCheckBoxSize + 2 * FMarge - else LMarge:= 2 * FMarge; - tot:= 0; - FLineProps[0].Rect.Top:= FRect.Top; - FLineProps[0].TextRect.Top:= FRect.Top + FMarge; - for i:= 0 to FStrings.Count - 1 do - begin - if i = 0 then FLineProps[i].PageNr:= FPageNrS - else FLineProps[i].PageNr:= FLineProps[i-1].PageNr; - FLineProps[i].TextRect.Left:= FRect.Left + LMarge; - FLineProps[i].TextRect.Right:= FRect.Right - 2 * FMarge; - if i > 0 then - begin - FLineProps[i].Rect.Top:= FLineProps[i-1].Rect.Bottom; - FLineProps[i].PageNr:= FLineProps[i-1].PageNr; - end; - FLineProps[i].TextRect.Top:= FLineProps[i].Rect.Top + FMarge; - s:= FStrings[i]; - w:= FLineProps[i].TextRect.Right - FLineProps[i].TextRect.Left; - if FAutoSize and (w > 0) then - begin - fh:= FFont.Height; - FFont.Height:= FFontHeight; - LL:= CalcAmountLines2(FFont, s, w); - FFont.Height:= fh; - end - else - LL:= 1; - - LL:= LL * FFontHeight; - FLineProps[i].TextRect.Bottom:= FLineProps[i].TextRect.Top + LL; - FLineProps[i].Rect.Bottom:= FLineProps[i].TextRect.Bottom + FMarge; - t:= FLineProps[i].Rect.Bottom - FLineProps[i].Rect.Top; - if (FLineProps[i].Rect.Bottom > FDocument.FPrintRect.Bottom) and - ((not FKeepTogether) or (i = 0))then - begin - FLineProps[i].PageNr:= FLineProps[i].PageNr + 1; - FPageNrE:= FPageNrE + 1; - if i = 0 then FPageNRS:= FPageNRE; - FLineProps[i].Rect.Top:= FDocument.FPrintRect.Top; - FLineProps[i].Rect.Bottom:= FLineProps[i].Rect.Top + t; - FLineProps[i].TextRect.Top:= FLineProps[i].Rect.Top + FMarge; - FLineProps[i].TextRect.Bottom:= FLineProps[i].Rect.Bottom - FMarge; - end; - if (i > 0) and FKeepTogether and (FLineProps[i-1].PageNr < FLineProps[i].PageNr) then - begin - FPageNrS:= FPageNRE; - for j:= 0 to i do - begin - h:= FLineProps[j].Rect.Bottom - FLineProps[j].Rect.Top; - if j = 0 then FLineProps[j].Rect.Top:= FDocument.FPrintRect.Top - else FLineProps[j].Rect.Top:= FLineProps[j-1].Rect.Bottom; - FLineProps[j].Rect.Bottom:= FLineProps[j].Rect.Top + h; - FLineProps[j].TextRect.Top:= FLineProps[j].Rect.Top + FMarge; - FLineProps[j].TextRect.Bottom:= FLineProps[j].Rect.Bottom - FMarge; - FLineProps[j].PageNr:= FPageNrS; - end; - if (FLineProps[i].Rect.Bottom > FDocument.FPrintRect.Bottom) and FKeeptogether then - //lines do not fit on the page all, so Keeptogether cannot be implemented - begin - FKeeptogether:= false; - CalcRect; - end; - end; - tot:= tot + t; - end; - FRect.Top:= FLineProps[0].Rect.Top; - FRect.Bottom:= FLineProps[FStrings.Count - 1].Rect.Bottom; - end - else //make the text at least 1 line high - begin - FRect.Bottom:= FRect.Top + FFontHeight; - end; - DeployKeepWithNext; -end; - -Procedure TBHRText.Draw(Cnvs : TCanvas; Pnr : integer; Scale : single); -var i : integer; - s : string; - t, mh : LongInt; - fsz : word; - OFont : TFont; - OBrush : TBrush; - OPen : TPen; - cbR : TRect; - SRect : TRect; -begin - if (FPageNrS <= PNr) and (FPageNrE >= PNr) then - begin - t:= FRect.Top; - OFont:= TFont.Create; - OBrush:= TBrush.Create; - OPen:= TPen.Create; - OFont.Assign(Cnvs.Font); - OBrush.Assign(Cnvs.Brush); - OPen.Assign(Cnvs.Pen); - Cnvs.Font.Assign(FFont); - - Cnvs.Brush.Assign(FBrush); - Cnvs.Pen.Color:= Cnvs.Brush.Color; - Cnvs.Pen.Width:= 0; - if FRect.Bottom < FRect.Top then //Text spans more pages - begin - CbR:= FRect; - if PNr = FPageNrS then - begin - CbR.Bottom:= FDocument.PrintRect.Bottom; - end - else if (PNr > FPageNrS) and (PNr < FPageNrE) then - begin - CbR.Top:= FDocument.PrintRect.Top; - CbR.Bottom:= FDocument.PrintRect.Bottom; - end - else if PNr = FPageNrE then - begin - CbR.Top:= FDocument.PrintRect.Top; - end; - SRect:= ScaleRect(CbR, Scale); - end - else - begin - SRect:= ScaleRect(FRect, Scale); - end; - Cnvs.Rectangle(SRect); - - for i:= 0 to FStrings.Count - 1 do - if FLineProps[i].PageNr = PNr then - begin - Cnvs.Pen.Assign(FPen); - cnvs.Pen.Style:= psSolid; - cnvs.Pen.Color:= clBlack; - Cnvs.Brush.Color:= clWhite; - fsz:= FFont.Size; - if FCheckBoxes then - begin - cbR.Top:= FLineProps[i].TextRect.Top; - cbR.Bottom:= cbR.Top + FontSizeToPix(fsz, 1); - cbR.Left:= FRect.Left + FMarge; - cbR.Right:= cbR.Left + FontSizeToPix(fsz, 1); - cbR:= ScaleRect(cbR, Scale); - Cnvs.Rectangle(cbR); - if FChecked then - begin - Cnvs.MoveTo(cbR.Left, cbR.Top); - Cnvs.LineTo(cbR.Right, cbR.Bottom); - Cnvs.MoveTo(cbR.Right, cbR.Top); - Cnvs.LineTo(cbR.Left, cbR.Bottom); - end; - end; - - Cnvs.Font.Height:= FontSizeToPix(fsz, Scale); - SRect:= ScaleRect(FLineProps[i].TextRect, Scale); - mh:= Round((SRect.Bottom + SRect.Top) / 2); - s:= FStrings[i]; - t:= t + DrawTxt(Cnvs, mh, SRect.Left, SRect.Right, s, FAlignment, TRUE); - Cnvs.Font.Size:= fsz; - end; - - Cnvs.Font.Assign(OFont); - Cnvs.Brush.Assign(OBrush); - Cnvs.Pen.Assign(OPen); - OFont.Free; - OBrush.Free; - OPen.Free; - end; -end; - -{============================TBHRCell =========================================} - -Constructor TBHRCell.Create(D : TBHRDocument; R, C : integer); -begin - Inherited Create(D); - FText := TBHRText.Create(D); - FText.Cell:= self; - FText.AutoSize:= false; - FTable:= NIL; - FRow:= R; - FColumn:= C; -end; - -Destructor TBHRCell.Destroy; -begin - FText.Free; - Inherited Destroy; -end; - -Procedure TBHRCell.SetLeft(l : word); -begin - Inherited SetLeft(l); - if FText <> NIL then - FText.Left:= l; -end; - -Procedure TBHRCell.SetRight(r : word); -begin - Inherited SetRight(r); - if FText <> NIL then - FText.Right:= r; -end; - -procedure TBHRCell.SetTop(t : word); -begin - Inherited SetTop(t); - if FText <> NIL then - begin - FText.Top:= t; - // FText.CalcRect; - end; -end; - -Procedure TBHRCell.SetBottom(b : word); -begin - Inherited SetBottom(b); - if FText <> NIL then - FText.Bottom:= b; -end; - -Procedure TBHRCell.SetKeepTogether(b : boolean); -begin - if FKeepTogether <> b then - begin - FKeepTogether:= b; - FKeepWithNext:= b; - FText.KeepTogether:= b; - FText.KeepWithNext:= b; - end; -end; - -Function TBHRCell.GetFont : TFont; -begin - Result:= NIL; - if FText <> NIL then Result:= FText.Font; -end; - -Function TBHRCell.GetBrush : TBrush; -begin - Result:= NIL; - if FText <> NIL then Result:= FText.Brush; -end; - -Function TBHRCell.GetPen : TPen; -begin - Result:= NIL; - if FText <> NIL then Result:= FText.Pen; -end; - -Function TBHRCell.GetAlignment : TAlignment; -begin - Result:= taLeftJustify; - if FText <> NIL then Result:= FText.Alignment; -end; - -Procedure TBHRCell.SetAlignment(al : TAlignment); -begin - if FText <> NIL then FText.Alignment:= al; -end; - -Function TBHRCell.GetKeepTogether : boolean; -begin - Result:= TRUE; - if FText <> NIL then Result:= FText.KeepTogether; -end; - -Function TBHRCell.GetMarge : word; -begin - Result:= 0; - if FText <> NIL then Result:= FText.Marge; -end; - -Procedure TBHRCell.SetMarge(w : word); -begin - if FText <> NIL then FText.Marge:= w; -end; - -Function TBHRCell.GetAutoSize : boolean; -begin - Result:= false; - if FText <> NIL then Result:= FText.AutoSize; -end; - -Procedure TBHRCell.SetAutoSize(b : boolean); -begin - if FText <> NIL then FText.AutoSize:= b; -end; - -Function TBHRCell.GetCheckBoxes : boolean; -begin - Result:= false; - if FText <> NIL then Result:= FText.CheckBoxes; -end; - -Procedure TBHRCell.SetCheckBoxes(b : boolean); -begin - if FText <> NIL then FText.CheckBoxes:= b; -end; - -Function TBHRCell.GetCheckBoxSize : LongInt; -begin - Result:= 0; - if FText <> NIL then Result:= FText.CheckBoxSize; -end; - -Procedure TBHRCell.SetCheckBoxSize(L : LongInt); -begin - if FText <> NIL then FText.CheckBoxSize:= L; -end; - -Procedure TBHRCell.SetNext(E : TBHRElement); -begin - Inherited SetNext(E); - FText.Next:= E; -end; - -Procedure TBHRCell.SetPrior(E : TBHRElement); -begin - Inherited SetPrior(E); - FText.Prior:= E; -end; - -Procedure TBHRCell.SetPageNrS(i : integer); -begin - if (i > 0) {and (i <= FDocument.NumPages)} then - begin - Inherited SetPageNrS(i); - FText.PageNrS:= i; - end; -end; - -Procedure TBHRCell.SetPageNrE(i : integer); -begin - if (i > 0) {and (i <= FDocument.NumPages)} then - begin - Inherited SetPageNrE(i); - FText.PageNrE:= i; - end; -end; - -Procedure TBHRCell.Draw(Cnvs : TCanvas; Pnr : integer; Scale : single); -begin - if FText <> NIL then FText.Draw(Cnvs, Pnr, Scale); -end; - -Procedure TBHRCell.Move(PNr, Tp : word); -begin - if (FRow = 0) and (FColumn = 0) and (FTable <> NIL) then FTable.Move(PNr, Tp); -{ if FText <> NIL then FText.Move(PNr, Tp); - FRect:= FText.Rect; - FPageNrS:= FText.PageNrS; - FPageNrE:= FText.PageNrE;} -end; - -Procedure TBHRCell.CalcRect; -begin - Inherited CalcRect; - if FText <> NIL then FText.CalcRect; - FRect:= FText.Rect; - FPageNrS:= FText.PageNrS; - FPageNrE:= FText.PageNrE; - DeployKeepWithNext; -end; - -{========================== TBHRTable =========================================} - -Constructor TBHRTable.Create(D : TBHRDocument); -begin - Inherited Create(D); - FAutoSizeCells := false; - FColsEven := TRUE; - FKeepTogether:= TRUE; -end; - -Destructor TBHRTable.Destroy; -var R, C : integer; -begin - for R:= Low(FCells) to High(FCells) do - begin - for C:= Low(FCells[R]) to High(FCells[R]) do - FCells[R, C].Free; - SetLength(FCells[R], 0); - end; - SetLength(FCells, 0); - Inherited Destroy; -end; - -Function TBHRTable.GetCell(aRow, aCol : integer) : TBHRCell; -begin - if (aRow >= Low(FCells)) and (aRow <= High(FCells)) then - if (aCol >= Low(FCells[aRow])) and (aCol <= High(FCells[aRow])) then - Result:= FCells[aRow, aCol]; -end; - -Procedure TBHRTable.SetSize(NRows, NCols : integer); -var R, C : integer; -begin - SetLength(FCells, NRows); - for R:= 0 to NRows - 1 do - begin - SetLength(FCells[R], NCols); - for C:= 0 to NCols - 1 do - begin - if FCells[R, C] = NIL then - begin - FCells[R, C]:= TBHRCell.Create(FDocument, R, C); - FCells[R, C].Table:= self; - if C = 0 then FCells[R, C].Left:= FRect.Left - else FCells[R, C].Left:= FCells[R, C-1].Right; - if R = 0 then - begin - FCells[R, C].Top:= FRect.Top; - end - else - begin - FCells[R, C].Top:= FCells[R-1, C].Bottom; - FCells[R, C].Prior:= FCells[R-1, C]; - FCells[R-1, C].Next:= FCells[R, C]; - end; - end; - FCells[R, C].Keeptogether:= FKeepTogether; - end; - end; - SetColsEven(TRUE); -end; - -Function TBHRTable.NumRows : integer; -begin - Result:= High(FCells) + 1; -end; - -Function TBHRTable.NumCols : integer; -begin - Result:= 0; - if NumRows > 0 then - Result:= High(FCells[0]) + 1; -end; - -Procedure TBHRTable.SetKeepTogether(b : boolean); -var C, R : integer; -begin - FKeepTogether:= b; - for R:= 0 to NumRows - 2 do - for C:= 0 to NumCols - 1 do - FCells[R, C].KeepWithNext:= b; - FDocument.CalcRects; -end; - -Function TBHRTable.GetRowColor(i : word) : TColor; -begin - Result:= clWhite; - if (i >= Low(FCells)) and (i <= High(FCells)) then - Result:= FCells[i, 0].Brush.Color; -end; - -Procedure TBHRTable.SetRowColor(i : word; cl : TColor); -var j : integer; -begin - if (i >= Low(FCells)) and (i <= High(FCells)) then - for j:= Low(FCells[i]) to High(FCells[i]) do - begin - FCells[i, j].Brush.Color:= cl; - FCells[i, j].Brush.Style:= bsSolid; - end; -end; - -Function TBHRTable.GetColColor(i : word) : TColor; -begin - Result:= clWhite; - if (i >= Low(FCells[0])) and (i <= High(FCells[0])) then - Result:= FCells[0, i].Brush.Color; -end; - -Procedure TBHRTable.SetColColor(i : word; cl : TColor); -var j : integer; -begin - if (i >= Low(FCells[0])) and (i <= High(FCells[0])) then - for j:= Low(FCells) to High(FCells) do - begin - FCells[j, i].Brush.Color:= cl; - FCells[j, i].Brush.Style:= bsSolid; - end; -end; - -Function TBHRTable.GetColWidth(aCol : integer) : word; -var C : TBHRCell; -begin - Result:= 0; - C:= GetCell(0, aCol); - if C <> NIL then Result:= C.Rect.Right - C.Rect.Left; -end; - -Procedure TBHRTable.SetColWidth(aCol : integer; Width : word); -var Cell, Cell2 : TBHRCell; - R : integer; -begin - FColsEven:= false; - for R:= 0 to NumRows - 1 do - begin - Cell:= GetCell(R, aCol); - if Cell <> NIL then - begin - if aCol = 0 then - begin - //Cell.FText.Left:= FRect.Left; - Cell.Left:= FRect.Left; - end - else - begin - Cell2:= GetCell(R, aCol-1); - if Cell2 <> NIL then - begin - //Cell.FText.Left:= Cell2.Rect.Right; - Cell.Left:= Cell2.Rect.Right; - end; - end; - //Cell.FText.Right:= Cell.Rect.Left + Width; - Cell.Right:= Cell.Rect.Left + Width; - end; - end; -end; - -Procedure TBHRTable.SetColsEven(b : boolean); -var Cell, Cell2, Cell1 : TBHRCell; - R, C : integer; - W : single; -begin - FColsEven:= b; - if b and (NumCols > 0) then - begin - W:= (FRect.Right - FRect.Left) / NumCols; - for R:= 0 to NumRows - 1 do - begin - Cell1:= GetCell(R, 0); - for C:= 0 to NumCols - 1 do - begin - Cell:= GetCell(R, C); - if Cell <> NIL then - begin - if C = 0 then - Cell.FText.Left:= FRect.Left - else - begin - Cell2:= GetCell(R, C-1); - if Cell2 <> NIL then - Cell.FText.Left:= Cell2.Rect.Right; - end; - Cell.Right:= Cell1.Left + round((C + 1) * W); - end; - end; - end; - end; -end; - -Function TBHRTable.GetRowHeight(aRow : integer) : word; -var C : TBHRCell; -begin - Result:= 0; - C:= GetCell(aRow, 0); - if C <> NIL then Result:= C.Rect.Bottom - C.Rect.Top; -end; - -Procedure TBHRTable.SetRowHeight(ARow : integer; Height : word); -var Cell, Cell2 : TBHRCell; - C : integer; -begin - for C:= 0 to NumCols - 1 do - begin - Cell:= GetCell(aRow, C); - if Cell <> NIL then - begin - if aRow = 0 then - Cell.FText.Top:= FRect.Top - else - begin - Cell2:= GetCell(aRow-1, C); - if Cell2 <> NIL then - Cell.FText.Left:= Cell2.Rect.Bottom; - end; - Cell.FText.Bottom:= Cell.FText.Top + Height; - end; - end; -end; - -Procedure TBHRTable.SetAutoSizeCells(b : boolean); -var C, R : integer; -begin - FAutoSizeCells:= b; - for R:= 0 to NumRows - 1 do - for C:= 0 to NumCols - 1 do - FCells[R, C].AutoSize:= b; - FDocument.CalcRects; -end; - -Procedure TBHRTable.SetPageNrS(i : integer); -var C, R : integer; -begin - if (i > 0) {and (i <= FDocument.NumPages)} then - begin - Inherited SetPageNrS(i); - for R:= 0 to NumRows - 1 do - for C:= 0 to NumCols - 1 do - FCells[R, C].PageNrS:= i; - end; -end; - -Procedure TBHRTable.SetPageNrE(i : integer); -var C, R : integer; -begin - if (i > 0) {and (i <= FDocument.NumPages)} then - begin - Inherited SetPageNrE(i); - for R:= 0 to NumRows - 1 do - for C:= 0 to NumCols - 1 do - FCells[R, C].PageNrE:= i; - end; -end; - -Procedure TBHRTable.AddRow; -var C, R : integer; - Cell : TBHRCell; -begin - SetLength(FCells, High(FCells) + 2); - SetLength(FCells[High(FCells)], NumCols); - R:= High(FCells); - for C:= 0 to NumCols - 1 do - begin - FCells[R, C]:= TBHRCell.Create(FDocument, R, C); - FCells[R, C].Table:= self; - FCells[R, C].Keeptogether:= FKeeptogether; - if (R > 0) then - begin - Cell:= GetCell(R-1, C); - if Cell <> NIL then - begin - { if (not FAutoHeight) then - begin - FCells[R, C].Top:= Cell.Bottom; - FCells[R, C].Bottom:= Cell.Bottom + (Cell.Bottom - Cell.Top); - end; } - FCells[R, C].Left:= Cell.Left; - FCells[R, C].Right:= Cell.Right; - FCells[R, C].Prior:= Cell; - Cell.Next:= FCells[R, C]; - end; - end - else - begin - FCells[R, C].Top:= FRect.Top; - FCells[R, C].Bottom:= FRect.Bottom; - if C = 0 then - begin - FCells[R, C].Left:= FRect.Left; - if NumCols = 0 then - FCells[R, C].Right:= FRect.Right - else - FCells[R, C].Right:= FRect.Left + round((FRect.Right - FRect.Left) / NumCols); - end - else - begin - Cell:= GetCell(R, C-1); - FCells[R, C].Left:= Cell.Right; - FCells[R, C].Right:= FRect.Left + round((C + 1) * (FRect.Right - FRect.Left) / NumCols); - end; - end; - end; -end; - -Procedure TBHRTable.AddCol; -var C, R : integer; - Cell : TBHRCell; -begin - for R:= 0 to High(FCells) do - begin - SetLength(FCells[R], High(FCells[R]) + 2); - C:= High(FCells[R]); - FCells[R, C]:= TBHRCell.Create(FDocument, R, C); - FCells[R, C].Table:= self; - FCells[R, C].Keeptogether:= FKeepTogether; - if R > 0 then - begin - FCells[R, C].Prior:= FCells[R-1, C]; - FCells[R-1, C].Next:= FCells[R, C]; - end; - end; - - if FColsEven then SetColsEven(TRUE) - else if C > 0 then - begin - for R:= 0 to High(FCells) do - begin - Cell:= GetCell(R, C-1); - FCells[R, C].Top:= Cell.Top; - FCells[R, C].Bottom:= Cell.Bottom; - FCells[R, C].Left:= Cell.Right; - FCells[R, C].Right:= Cell.Right + (Cell.Right - Cell.Left); - end; - end - else - begin - for R:= 0 to High(FCells) do - begin - FCells[R, C].Left:= FRect.Right; - FCells[R, C].Right:= FRect.Left; - end; -{ if not FAutoHeight then - begin - FCells[0, C].Top:= FRect.Top; - if NumRows > 0 then - FCells[0, C].Bottom:= FRect.Top + round((FRect.Bottom - FRect.Top) / NumRows) - else FCells[0, C].Bottom:= FRect.Bottom; - for R:= 1 to High(FCells) do - begin - Cell:= GetCell(R-1, C); - FCells[R, C].Top:= Cell.Top; - FCells[R, C].Bottom:= FRect.Top + round((R + 1) * (FRect.Bottom - FRect.Top) / NumRows); - FCells[R, C].Left:= FRect.Right; - FCells[R, C].Right:= FRect.Left; - end; - end;} - end; -end; - -Procedure TBHRTable.Draw(Cnvs : TCanvas; Pnr : integer; Scale : single); -var R, C : integer; -begin - for R:= 0 to NumRows - 1 do - for C:= 0 to NumCols - 1 do - FCells[R, C].Draw(Cnvs, PNr, Scale); -end; - -Procedure TBHRTable.Move(PNr, Tp : word); -var R, C, PaNr : integer; - MaxH : word; - RTp : LongInt; - Cell : TBHRCell; -begin - Inherited Move(PNr, Tp); - RTp:= FRect.Top; - MaxH:= 0; - PaNr:= FPageNrS; - for R:= 0 to NumRows - 1 do - begin - //first, calculate the height of every cell in row R - for C:= 0 to NumCols - 1 do - begin - Cell:= FCells[R, C]; - if R = 0 then - begin - Cell.PageNrS:= FPageNrS; - Cell.PageNrE:= FPageNrS; - Cell.Top:= RTp; - end - else - begin - Cell.PageNrS:= FCells[R-1, C].FPageNrE; - Cell.PageNrE:= Cell.FPageNrS; - end; - Cell.CalcRect; - end; - - //then find the maximum height of the cells in row R - MaxH:= 0; - for C:= 0 to NumCols - 1 do - begin - Cell:= FCells[R, C]; - if (Cell.Bottom - Cell.Top) > MaxH then - MaxH:= Cell.Bottom - Cell.Top; - if Cell.PageNrE > FPageNrE then - PaNr:= Cell.PageNrE; - end; - if PaNr > FPageNrE then - begin - for C:= 0 to NumCols - 1 do - begin - Cell:= FCells[R, C]; - Cell.Top:= FDocument.PrintRect.Top; - Cell.PageNrS:= PaNr; - Cell.PageNrE:= PaNr; - end; - FPageNrE:= PaNr; - end; - RTp:= FCells[R, 0].Top + MaxH; - for C:= 0 to NumCols - 1 do - FCells[R, C].Bottom:= RTp; - end; - - Cell:= FCells[NumRows-1, NumCols-1]; - Bottom:= Cell.Bottom; - FPageNrE:= Cell.PageNrE; -end; - -Procedure TBHRTable.CalcRect; - Procedure DoCalcRect; - var R, C, PNr : integer; - MaxH, RTp : word; - Cell : TBHRCell; - begin - RTp:= FRect.Top; - MaxH:= 0; - PNr:= FPageNrS; - for R:= 0 to NumRows - 1 do - begin - //first, calculate the height of every cell in row R - for C:= 0 to NumCols - 1 do - begin - Cell:= FCells[R, C]; - if R = 0 then - begin - Cell.PageNrS:= FPageNrS; - Cell.PageNrE:= FPageNrS; - Cell.Top:= RTp; - end - else - begin - { Cell.PageNrS:= FCells[R-1, C].FPageNrE; - Cell.PageNrE:= Cell.FPageNrS;} - end; - Cell.CalcRect; - end; - - //then find the maximum height of the cells in row R - MaxH:= 0; - for C:= 0 to NumCols - 1 do - begin - Cell:= FCells[R, C]; - if (Cell.Bottom - Cell.Top) > MaxH then - MaxH:= Cell.Bottom - Cell.Top; - if Cell.PageNrE > FPageNrE then - PNr:= Cell.PageNrE; - end; - if PNr > FPageNrE then - begin - for C:= 0 to NumCols - 1 do - begin - Cell:= FCells[R, C]; - Cell.Top:= FDocument.PrintRect.Top; - Cell.PageNrS:= PNr; - Cell.PageNrE:= PNr; - end; - FPageNrE:= PNr; - end; - RTp:= FCells[R, 0].Top + MaxH; - for C:= 0 to NumCols - 1 do - FCells[R, C].Bottom:= RTp; - end; - - Cell:= FCells[NumRows-1, NumCols-1]; - Bottom:= Cell.Bottom; - FPageNrE:= Cell.PageNrE; - end; - -begin - Inherited CalcRect; - - DoCalcRect; - - if FKeepTogether and (FPageNrE > FPageNrS) then - begin - if FPageNrE - FPageNRS > 1 then //cannot keep together - begin - KeepTogether:= false; - end - else //place table on FPageNRE - begin - FPageNRS:= FPageNrE; - FRect.Top:= FDocument.PrintRect.Top; - end; - DoCalcRect; - end; - - DeployKeepWithNext; -end; - -{====================== TBHRDocument ==========================================} - -Constructor TBHRDocument.Create; -begin - Inherited; - FNumPages:= 1; - FMarginBT := 2; //cm - FMarginLR := 1.5; //cm - GetPrinterProps; - FHeader:= TBHRHeader.Create(self, thHeader); - FFooter:= TBHRHeader.Create(self, thFooter); -end; - -Destructor TBHRDocument.Destroy; -var i : integer; -begin - FHeader.Free; - FFooter.Free; - for i:= 0 to High(FElements) do - FElements[i].Free; - SetLength(FElements, 0); - Inherited; -end; - -Function TBHRDocument.GetLineHeight(fh : integer) : integer; -begin - Result:= Round(1.0 * FontSizeToPix(fh, 1)); -end; - -Procedure TBHRDocument.GetPrinterProps; -var dx : word; - dy : word; -begin - if Printer <> NIL then - begin - dx:= Printer.XDPI; - dy:= Printer.YDPI; - FMarginBTpx := round(FMarginBT / 2.54 * dy); - FMarginLRpx := round(FMarginLR / 2.54 * dx); - - FPageRect.Top:= 0; - FPageRect.Left:= 0; - FPageRect.Right:= Printer.PageWidth; - FPageRect.Bottom:= Printer.PageHeight; - - FPrintRect.Top:= FMarginBTpx; - FPrintRect.Bottom:= Printer.PageHeight - FMarginBTpx; - FPrintRect.Left:= FMarginLRpx; - FPrintRect.Right:= Printer.PageWidth - FMarginLRpx; - end - else - begin - dx:= 600; - dy:= 600; - FMarginBTpx := round(FMarginBT / 2.54 * dy); - FMarginLRpx := round(FMarginLR / 2.54 * dx); - - FPageRect.Top:= 0; - FPageRect.Left:= 0; - FPageRect.Right:= round(21.0 / 2.54 * 600); - FPageRect.Bottom:= round(29.7 / 2.54 * 600); - - FPrintRect.Top:= FMarginBTpx; - FPrintRect.Bottom:= round(29.7 / 2.54 * 600) - FMarginBTpx; - FPrintRect.Left:= FMarginLRpx; - FPrintRect.Right:= round(21.0 / 2.54 * 600) - FMarginLRpx; - end; -end; - -Function TBHRDocument.GetNumElements : integer; -begin - Result:= High(FElements) + 1; -end; - -Function Overlap(R1, R2 : TRect) : boolean; -var R : TRect; -begin - Result:= Intersectrect(R, R1, R2); -end; - -Procedure TBHRDocument.CalcRects; -var i : integer; - E : TBHRElement; -begin - if FHeader <> NIL then FHeader.CalcRect; - if FFooter <> NIL then FFooter.CalcRect; - FLastY:= FPrintRect.Top; - FLastPage:= 1; FNumPages:= 1; - for i:= 0 to High(FElements) do - begin - E:= FElements[i]; - if i = 0 then - begin - E.Top:= FPrintRect.Top; - E.PageNrS:= 1; - E.PageNrE:= 1; - end; - E.CalcRect; - FLastPage:= E.PageNrE; - FNumPages:= FLastPage; - end; -end; - -Procedure TBHRDocument.AddPage; -begin - Inc(FNumPages); -end; - -Procedure TBHRDocument.RemovePage; -begin - FNumPages:= FNumPages - 1; - if FNumPages < 1 then FNumPages:= 1; -end; - -Function TBHRDocument.AddSpace(Rect : TRect; h : word) : TBHRElement; -begin - Result:= NIL; - CalcRects; - SetLength(FElements, High(FElements) + 2); - FElements[High(FElements)]:= TBHRElement.Create(self); - Result:= FElements[High(FElements)]; - Result.Top:= FLastY; - Result.MinHeight:= h; - Result.Bottom:= Result.Top + h; - Result.Left:= Rect.Left; - Result.Right:= Rect.Right; - if High(FElements) > 0 then - begin - Result.Prior:= FElements[High(FElements)-1]; - FElements[High(FElements)-1].Next:= Result; - end; -end; - -Function TBHRDocument.AddText(Rect : TRect; s : string) : TBHRText; -var n : integer; - line : string; - ch : TSysCharSet; -//const lnrt = #10#13; -begin - Result:= NIL; - CalcRects; - SetLength(FElements, High(FElements) + 2); - FElements[High(FElements)]:= TBHRText.Create(self); - Result:= TBHRText(FElements[High(FElements)]); - ch:= [#10]; - n:= 1; Line:= ''; - repeat - Line:= ExtractWord(n, s, ch); - if Line <> '' then Result.AddString(Line); - inc(n); - until Line = ''; - -// Result.AddString(s); - Result.Top:= FLastY; - Result.Left:= Rect.Left; - Result.Right:= Rect.Right; - if High(FElements) > 0 then - begin - Result.Prior:= FElements[High(FElements)-1]; - FElements[High(FElements)-1].Next:= Result; - end; -end; - -Function TBHRDocument.AddTable(Rect : TRect; nCol, nRow : integer) : TBHRTable; -begin - Result:= NIL; - CalcRects; - SetLength(FElements, High(FElements) + 2); - FElements[High(FElements)]:= TBHRTable.Create(self); - Result:= TBHRTable(FElements[High(FElements)]); - Result.Top:= Rect.Top; - Result.Left:= Rect.Left; - Result.Right:= Rect.Right; - Result.SetSize(nRow, nCol); - Result.ColsEven:= TRUE; -// Result.AutoHeight:= TRUE; - Result.Top:= FLastY; - if High(FElements) > 0 then - begin - Result.Prior:= FElements[High(FElements)-1]; - FElements[High(FElements)-1].Next:= Result; - end; -end; - -Function TBHRDocument.AddImage(Rect : TRect) : TBHRImage; -begin - Result:= NIL; - CalcRects; - SetLength(FElements, High(FElements) + 2); - FElements[High(FElements)]:= TBHRImage.Create(self); - Result:= TBHRImage(FElements[High(FElements)]); - Result.Top:= FLastY; - Result.Left:= Rect.Left; - Result.Right:= Rect.Right; - if High(FElements) > 0 then - begin - Result.Prior:= FElements[High(FElements)-1]; - FElements[High(FElements)-1].Next:= Result; - end; -end; - -{Function TBHRDocument.AddGraph(Rect : TRect) : TBHRBHGraph; -begin - Result:= NIL; - CalcRects; - SetLength(FElements, High(FElements) + 2); - FElements[High(FElements)]:= TBHRBHGraph.Create(self); - Result:= TBHRBHGraph(FElements[High(FElements)]); - Result.Top:= FLastY; - Result.Left:= Rect.Left; - Result.Right:= Rect.Right; - if High(FElements) > 0 then - begin - Result.Prior:= FElements[High(FElements)-1]; - FElements[High(FElements)-1].Next:= Result; - end; -end; } - -Function TBHRDocument.AddChart(Rect : TRect) : TBHRChart; -begin - Result:= NIL; - CalcRects; - SetLength(FElements, High(FElements) + 2); - FElements[High(FElements)]:= TBHRChart.Create(self); - Result:= TBHRChart(FElements[High(FElements)]); - Result.Top:= FLastY; - Result.Left:= Rect.Left; - Result.Right:= Rect.Right; - if High(FElements) > 0 then - begin - Result.Prior:= FElements[High(FElements)-1]; - FElements[High(FElements)-1].Next:= Result; - end; -end; - -Function TBHRDocument.GetElement(i : integer) : TBHRElement; -begin - Result:= NIL; - if (i >= Low(FElements)) and (i <= High(FElements)) then - Result:= FElements[i]; -end; - -Procedure TBHRDocument.Print(FromPage, ToPage, Copies : integer); -var p, i : integer; -begin - try - if Printer <> NIL then - begin - for i:= 1 to Copies do - begin - Printer.BeginDoc; - Printer.Canvas.CopyMode:= cmSrcCopy; - for p:= FromPage to ToPage do - begin - DrawPage(Printer.Canvas, p, 1); - if p < ToPage then Printer.NewPage; - end; - Printer.EndDoc; - end; - end; - finally - end; -end; - -Procedure TBHRDocument.PrintPreview; -var fpp : TFrmPrintPreview; -begin - CalcRects; - fpp:= TFrmPrintPreview.Create(FrmMain); - fpp.Execute(self); - { try - CalcRects; - FrmPrintPreview:= TFrmPrintPreview.Create(FrmMain); - FrmPrintPreview.Execute(self); - finally - FrmPrintPreview.Free; - Free; - end; } -end; - -Procedure TBHRDocument.DrawPages(cnvs : TCanvas; Scale : single); -var p : integer; -begin - if Printer <> NIL then - for p:= 1 to FNumPages do - begin - DrawPage(cnvs, p, Scale); - if p < FNumPages then Printer.NewPage; - end; -end; - -Procedure TBHRDocument.DrawPage(cnvs : TCanvas; PageNr : integer; Scale : single); -var i : integer; - E : TBHRElement; - SRect : TRect; -begin - CalcRects; - with Cnvs do - begin - Brush.Color:= clWhite; - Pen.Color:= clWhite; - SRect:= ScaleRect(FPageRect, Scale); - Rectangle(SRect); - end; - FFooter.Text:= 'Bladzijde '+ IntToStr(PageNr) + ' van ' + IntToStr(NumPages); - if FHeader <> NIL then FHeader.Draw(Cnvs, PageNr, Scale); - if FFooter <> NIL then FFooter.Draw(Cnvs, PageNr, Scale); - - for i:= Low(FElements) to High(FElements) do - begin - E:= Element[i]; - if E <> NIL then - E.Draw(cnvs, PageNr, Scale); - end; -end; - -Procedure TBHRDocument.Repaginate; -begin - CalcRects; -end; - -end. - diff --git a/Source/Units/backup/containers.pas b/Source/Units/backup/containers.pas deleted file mode 100644 index 2cfc1d00..00000000 --- a/Source/Units/backup/containers.pas +++ /dev/null @@ -1,3524 +0,0 @@ -unit Containers; - -{$mode objfpc}{$H+} - -interface - -uses - Classes, SysUtils, {$ifdef Windows}windows, windirs, {$endif}Forms, Controls, Dialogs, - Data, Hulpfuncties, DOM, XMLRead, XMLWrite, XMLUtils, variants, frimport; - -type - TContainer = class(TObject) - private - FFileName : string; - FImportFileName : string; - FLabel : string; - FCollection : array of TBase; - FSelected : integer; - FDoc : TXMLDocument; - FRootNode, FChild : TDOMNode; - Procedure SetSelected(i : integer); - public - Constructor Create; virtual; - Destructor Destroy; override; - Procedure SaveXML; virtual; - Procedure ReadXML; virtual; - Function ImportXML : boolean; virtual; - Procedure SortByIndex(Index : integer; Decending : boolean; Nstart, Nend : integer); - Procedure SortByIndex2(I1, I2 : integer; Decending : boolean); - Procedure SortByName(s : string); - Procedure UnSelect; - Function AddItem : TBase; virtual; - Procedure InsertItem(i : integer); virtual; - Procedure RemoveItem(i : integer); virtual; - Procedure RemoveByReference(Item : TBase); virtual; - Procedure FreeCollection; - Function GetNumItems : integer; - Function GetItem(i : integer) : TBase; - Function FindByName(s : string) : TBase; - Function FindByNameOnStock(s : string) : TBase; - Function FindByAutoNr(i : integer) : TBase; - Procedure RemoveByAutoNr(i : integer); - Function IndexByName(s : string) : integer; - property Item[i: integer] : TBase read GetItem; - published - property FileName : string read FFileName write FFileName; - property ImportFileName : string read FImportFileName; - property Selected : integer read FSelected write SetSelected; - property NodeLabel : string read FLabel write FLabel; - property NumItems : integer read GetNumItems; - end; - - TFermentables = class(TContainer) - private - public - Constructor Create; override; - Procedure SaveXML; override; - Procedure ReadXML; override; - Function ImportXML : boolean; override; - Function GetSelectedItem : TFermentable; - Function AddItem : TFermentable; - Procedure InsertItem(i : integer); override; - Function FindByNameAndSupplier(N, S : string) : TFermentable; - published - property SelectedItem : TFermentable read GetSelectedItem; - end; - - THops = class(TContainer) - private - public - Constructor Create; override; - Procedure SaveXML; override; - Procedure ReadXML; override; - Function ImportXML : boolean; override; - Function GetSelectedItem : THop; - Function AddItem : THop; - Procedure InsertItem(i : integer); override; - Function FindByNameAndOriginAndAlfa(N, O : string; A : double) : THop; - published - property SelectedItem : THop read GetSelectedItem; - end; - - TMiscs = class(TContainer) - private - public - Constructor Create; override; - Procedure SaveXML; override; - Procedure ReadXML; override; - Function ImportXML : boolean; override; - Function GetSelectedItem : TMisc; - Function AddItem : TMisc; - Procedure InsertItem(i : integer); override; - published - property SelectedItem : TMisc read GetSelectedItem; - end; - - TYeasts = class(TContainer) - private - public - Constructor Create; override; - Procedure SaveXML; override; - Procedure ReadXML; override; - Function ImportXML : boolean; override; - Function GetSelectedItem : TYeast; - Function AddItem : TYeast; - Procedure InsertItem(i : integer); override; - Function FindByNameAndLaboratory(N, L : string) : TYeast; - published - property SelectedItem : TYeast read GetSelectedItem; - end; - - TWaters = class(TContainer) - private - public - Constructor Create; override; - Procedure SaveXML; override; - Procedure ReadXML; override; - Function ImportXML : boolean; override; - Function GetSelectedItem : TWater; - Function AddItem : TWater; - Procedure InsertItem(i : integer); override; - Function GetDefaultWater : TWater; - Function GetDemiWater : TWater; - published - property SelectedItem : TWater read GetSelectedItem; - end; - - TEquipments = class(TContainer) - private - public - Constructor Create; override; - Procedure SaveXML; override; - Procedure ReadXML; override; -// Function ImportXML : boolean; override; - Function GetSelectedItem : TEquipment; - Function AddItem : TEquipment; - Procedure InsertItem(i : integer); override; - Procedure CalcEfficiencyRegressionFactors; - Procedure CalcAttenuationRegressionFactors; - published - property SelectedItem : TEquipment read GetSelectedItem; - end; - - TBeerStyles = class(TContainer) - private - public - Constructor Create; override; - Procedure SaveXML; override; - Procedure ReadXML; override; - Function ImportXML : boolean; override; - Function GetSelectedItem : TBeerStyle; - Function AddItem : TBeerStyle; - Procedure InsertItem(i : integer); override; - published - property SelectedItem : TBeerStyle read GetSelectedItem; - end; - - TMashs = class(TContainer) - private - public - Constructor Create; override; - Procedure SaveXML; override; - Procedure ReadXML; override; - Function ImportXML : boolean; override; - Function GetSelectedItem : TMash; - Function AddItem : TMash; - Procedure InsertItem(i : integer); override; - published - property SelectedItem : TMash read GetSelectedItem; - end; - - TMinMax = record - Name : string; - PercRecipes : single; //% of recipes with ingredient - MinUse, AvUse, MaxUse : single; //use of the ingredient in recipes' - end; - - TMinMaxArray = array of TMinMax; - - TRecipes = class(TContainer) - private - FFermentablesMinMaxArray : TMinMaxArray; - FBitterhopMinMaxArray : TMinMaxArray; - FAromahopMinMaxArray : TMinMaxArray; - FDryhopMinMaxArray : TMinMaxArray; - FYeastMinMaxArray : TMinMaxArray; - FMiscMinMaxArray : TMinMaxArray; - FCommonMinMaxArray : TMinMaxArray; - Procedure QuickSortRecipes(var Arr : array of TBase); - Function ImportXMLs(FN : TStrings; DN : string; Equip : TEquipment) : boolean; - Function ImportXML(FN : string; Equip : TEquipment) : boolean; - Function ImportRECs(FN : TStrings; DN : string; Equip : TEquipment) : boolean; - Function ImportREC(FN : string; Equip : TEquipment) : boolean; - Function GetLastNrRecipe : string; - Procedure QuickSortA(var Arr : array of TMinMax); - Function Exists(Arr : TMinMaxArray; FName : string) : integer; - Function GetMaxAutoNr : integer; - public - Constructor Create; override; - Destructor Destroy; override; - Procedure SaveXML; override; - Procedure ReadXML; override; - Procedure CheckAutoNrs; - Function ImportFiles(FN : TStrings; DN : string; Equip : TEquipment; - FT : TFileType) : boolean; - Procedure Sort; - Function GetSelectedItem : TRecipe; - Function AddItem : TRecipe; - Procedure InsertItem(i : integer); override; - Function FindByNameAndNr(Nm, Nr : string) : TRecipe; - Function FindByAutoNr(nr : integer) : TRecipe; - Function ExportToCSV(A : array of integer) : boolean; - Function AnalyseFermentables(Lett, Nm : string) : integer; //returns number of recipes - Function AnalyseHops(Lett, Nm : string) : integer; //returns number of recipes - Function AnalyseYeasts(Lett, Nm : string) : integer; //returns number of recipes - Function AnalyseMiscs(Lett, Nm : string) : integer; - Function AnalyseRecipes(Lett, Nm : string) : integer; - property FermentablesMinMaxArray : TMinMaxArray read FFermentablesMinMaxArray; - property BitterhopMinMaxArray : TMinMaxArray read FBitterhopMinMaxArray; - property AromahopMinMaxArray : TMinMaxArray read FAromahopMinMaxArray; - property DryhopMinMaxArray : TMinMaxArray read FDryhopMinMaxArray; - property YeastMinMaxArray : TMinMaxArray read FYeastMinMaxArray; - property MiscMinMaxArray : TMinMaxArray read FMiscMinMaxArray; - property CommonMinMaxArray : TMinMaxArray read FCommonMinMaxArray; - published - property SelectedItem : TRecipe read GetSelectedItem; - property LastNrRecipe : string read GetLastNrRecipe; - property MaxAutoNr : integer read GetMaxAutoNr; - end; - - TStyleRec = record - Name : string; - Recipes : array of TRecipe; - end; - - TStyleLetters = record - Letter : string; - Styles : array of TStyleRec; - end; - - TRecipesByStyle = class(TObject) - private - FStyleLetters : array of TStyleLetters; - FCollection : TRecipes; - Procedure Fill; - Procedure Empty; - Procedure Sort; - Function GetNumStyleLetters : integer; - Function GetNumStyles(i : integer) : integer; - Function GetStyleLetter(i : integer) : string; - Function GetStyleName(n : integer; s : integer) : string; - Function GetNumRecipes(n : integer; s : integer) : integer; - Function GetRecipe(n : integer; s : integer; i : integer) : TRecipe; - Procedure QuickSortInStyles(var Arr : array of TRecipe); - Procedure QuickSortStyles(var Arr : array of TStyleRec); - Procedure QuickSortLetters(var Arr : array of TStyleLetters); - public - Constructor Create(R : TRecipes); - Destructor Destroy; override; - Procedure SaveXML; - Function GetLetterByName(Num : string) : integer; - Function GetStyleByName(Num, Stl : string) : integer; - property NumStyles[i : integer] : integer read GetNumStyles; - property NumRecipes[n : integer; s : integer] : integer read GetNumRecipes; - property Recipe[n : integer; s : integer; i : integer] : TRecipe read GetRecipe; - property StyleLetter[i : integer] : string read GetStyleLetter; - property StyleName[n : integer; s : integer] : string read GetStyleName; - published - property NumStyleLetters : integer read GetNumStyleLetters; - end; - - Procedure Reload; - Procedure Backup; - Procedure Restore(sourcedata : string); - Procedure CheckBeerStyle(Rec : TRecipe); - Procedure CheckFermentables(Rec : TRecipe); - Procedure CheckYeasts(Rec : TRecipe); - Procedure CheckDataFolder; - Procedure ChangeDatabaseLocation(source, destination : string; copy, deleteold : boolean); - -var - Fermentables : TFermentables; - Hops : THops; - Miscs : TMiscs; - Yeasts : TYeasts; - Waters : TWaters; - Equipments : TEquipments; - Beerstyles : TBeerstyles; - Mashs : TMashs; - Recipes : TRecipes; - Brews : TRecipes; - - Loc : string; - - Arr : array of longint; - -implementation - -uses frmain, ComCtrls, frselectbeerstyle, fileutil, LazFileUtils, promashimport, cloud, subs, - neuroot, strutils, math; - -Procedure CheckSalts; -var M : TMisc; -begin - if Miscs.FindByName('CaCl2') = NIL then - begin - M:= Miscs.AddItem; - M.Name.Value:= 'CaCl2'; - M.AmountIsWeight.Value:= true; - M.Amount.vUnit:= kilogram; - M.Amount.DisplayUnit:= gram; - M.Amount.Value:= 0; - M.MiscType:= mtWaterAgent; - M.Use:= muMash; - M.UseFor.Value:= 'Voor het maken van een ander waterprofiel. Voegt calcium en chloride toe. Voor het verbeteren van zoetere bieren.'; - M.Inventory.vUnit:= M.Amount.vUnit; - M.Inventory.DisplayUnit:= M.Amount.DisplayUnit; - M.Inventory.Value:= 0; - end; - if Miscs.FindByName('CaCO3') = NIL then - begin - M:= Miscs.AddItem; - M.Name.Value:= 'CaCO3'; - M.AmountIsWeight.Value:= true; - M.Amount.vUnit:= kilogram; - M.Amount.DisplayUnit:= gram; - M.Amount.Value:= 0; - M.MiscType:= mtWaterAgent; - M.Use:= muMash; - M.UseFor.Value:= 'Kalk. Voor het maken van een ander waterprofiel. Voegt calcium en (bi)carbonaat toe. Voor het verhogen van de pH tijdens het maischen.'; - M.Inventory.vUnit:= M.Amount.vUnit; - M.Inventory.DisplayUnit:= M.Amount.DisplayUnit; - M.Inventory.Value:= 0; - end; - if Miscs.FindByName('CaSO4') = NIL then - begin - M:= Miscs.AddItem; - M.Name.Value:= 'CaSO4'; - M.AmountIsWeight.Value:= true; - M.Amount.vUnit:= kilogram; - M.Amount.DisplayUnit:= gram; - M.Amount.Value:= 0; - M.MiscType:= mtWaterAgent; - M.Use:= muMash; - M.UseFor.Value:= 'Gips. Voor het maken van een ander waterprofiel. Voegt calcium en sulfaat toe. Voor het verbeteren van bittere bieren.'; - M.Inventory.vUnit:= M.Amount.vUnit; - M.Inventory.DisplayUnit:= M.Amount.DisplayUnit; - M.Inventory.Value:= 0; - end; - if Miscs.FindByName('MgSO4') = NIL then - begin - M:= Miscs.AddItem; - M.Name.Value:= 'MgSO4'; - M.AmountIsWeight.Value:= true; - M.Amount.vUnit:= kilogram; - M.Amount.DisplayUnit:= gram; - M.Amount.Value:= 0; - M.MiscType:= mtWaterAgent; - M.Use:= muMash; - M.UseFor.Value:= 'Epsom zout. Voor het maken van een ander waterprofiel. Voegt magnesium en sulfaat toe. Gebruik spaarzaam!'; - M.Inventory.vUnit:= M.Amount.vUnit; - M.Inventory.DisplayUnit:= M.Amount.DisplayUnit; - M.Inventory.Value:= 0; - end; - if Miscs.FindByName('NaCl') = NIL then - begin - M:= Miscs.AddItem; - M.Name.Value:= 'NaCl'; - M.AmountIsWeight.Value:= true; - M.Amount.vUnit:= kilogram; - M.Amount.DisplayUnit:= gram; - M.Amount.Value:= 0; - M.MiscType:= mtWaterAgent; - M.Use:= muMash; - M.UseFor.Value:= 'Keukenzout. Voor het maken van een ander waterprofiel. Voegt natrium en chloride toe. Voor het accentueren van zoetheid. Bij hoge dosering wordt het bier ziltig.'; - M.Inventory.vUnit:= M.Amount.vUnit; - M.Inventory.DisplayUnit:= M.Amount.DisplayUnit; - M.Inventory.Value:= 0; - end; - if Miscs.FindByName('NaHCO3') = NIL then - begin - M:= Miscs.AddItem; - M.Name.Value:= 'NaHCO3'; - M.AmountIsWeight.Value:= true; - M.Amount.vUnit:= kilogram; - M.Amount.DisplayUnit:= gram; - M.Amount.Value:= 0; - M.MiscType:= mtWaterAgent; - M.Use:= muMash; - M.UseFor.Value:= 'Baksoda of bakpoeder. Voor het maken van een ander waterprofiel. Voegt natrium en bicarbonaat toe. Kan gebruikt worden voor verhoging van de pH tijdens het maischen.'; - M.Inventory.vUnit:= M.Amount.vUnit; - M.Inventory.DisplayUnit:= M.Amount.DisplayUnit; - M.Inventory.Value:= 0; - end; - if Miscs.FindByName('Melkzuur') = NIL then - begin - M:= Miscs.AddItem; - M.Name.Value:= 'Melkzuur'; - M.AmountIsWeight.Value:= false; - M.Amount.vUnit:= liter; - M.Amount.DisplayUnit:= milliliter; - M.Amount.Value:= 0; - M.MiscType:= mtWaterAgent; - M.Use:= muMash; - M.UseFor.Value:= 'Melkzuur wordt gebruikt voor het verlagen van de pH tijdens het maischen en het verlagen van de pH van het spoelwater.'; - M.Inventory.vUnit:= M.Amount.vUnit; - M.Inventory.DisplayUnit:= M.Amount.DisplayUnit; - M.Inventory.Value:= 0; - end; -end; - -Constructor TContainer.Create; -begin - Inherited; - FFileName:= ''; - FSelected:= -1; - FLabel:= ''; -end; - -Destructor TContainer.Destroy; -begin - FreeCollection; - Inherited; -end; - -Procedure TContainer.SaveXML; -begin - FDoc := TXMLDocument.Create; -// FDoc.Encoding:= 'ISO-8859-1'; - FRootNode := FDoc.CreateElement(FLabel); - FDoc.Appendchild(FRootNode); -end; - -Procedure TContainer.ReadXML; -var FN : string; -begin - FRootNode:= NIL; - try - FreeCollection; - FN:= Settings.DataLocation.Value + FFileName; - if FileExists(FN) then - begin - ReadXMLFile(FDoc, FN); - FRootNode:= FDoc.FindNode(FLabel); - end; - except - FDoc.Free; - end; -end; - -Function TContainer.ImportXML : boolean; -var dlg : TOpenDialog; -begin - Result:= false; - FRootNode:= NIL; - FDoc := TXMLDocument.Create; - dlg:= TOpenDialog.Create(frmMain); - with dlg do - begin - DefaultExt:= '.xml'; - FileName:= '*.xml'; - Filter:= 'BrewBuddy xml|*.xml'; - end; - FImportFileName:= ''; - try - if (dlg.Execute) and (FileExists(dlg.FileName)) then - begin - FImportFileName:= dlg.FileName; - dlg.Free; - ReadXMLFile(FDoc, FImportFileName); - FRootNode:= FDoc.FindNode(FLabel); - Result:= TRUE; - end; - except - FDoc.Free; - end; -end; - -Procedure TContainer.SortByIndex(Index : integer; Decending : boolean; Nstart, Nend : integer); - procedure QuickSort(var A: array of TBase; iLo, iHi: Integer); - var Lo, Hi: Integer; - v : variant; - TB : TBase; - begin - Lo := iLo; - Hi := iHi; - v:= A[(Lo + Hi) div 2].ValueByIndex[Index]; - repeat - while A[Lo].ValueByIndex[Index] < v do Inc(Lo); - while A[Hi].ValueByIndex[Index] > v do Dec(Hi); - if Lo <= Hi then - begin - TB:= A[Lo]; - A[Lo]:= A[Hi]; - A[Hi]:= TB; - Inc(Lo); - Dec(Hi); - end; - until Lo > Hi; - if Hi > iLo then QuickSort(A, iLo, Hi); - if Lo < iHi then QuickSort(A, Lo, iHi); - end; - - procedure QuickSortDec(var A: array of TBase; iLo, iHi: Integer); - var Lo, Hi: Integer; - v : variant; - TB : TBase; - begin - Lo := iLo; - Hi := iHi; - v:= A[(Lo + Hi) div 2].ValueByIndex[Index]; - repeat - while A[Lo].ValueByIndex[Index] > v do Inc(Lo); - while A[Hi].ValueByIndex[Index] < v do Dec(Hi); - if Lo <= Hi then - begin - TB := A[Lo]; - A[Lo] := A[Hi]; - A[Hi] := TB; - Inc(Lo); - Dec(Hi); - end; - until Lo > Hi; - if Hi > iLo then QuickSortDec(A, iLo, Hi); - if Lo < iHi then QuickSortDec(A, Lo, iHi); - end; - -begin - if (High(FCollection) > 0) and (Index > -1) then - begin - if (NEnd = 0) or (NStart >= NEnd) then - begin - NStart:= Low(FCollection); - NEnd:= High(FCollection); - end; - if Decending then - QuickSortDec(FCollection, NStart, NEnd) - else - QuickSort(FCollection, NStart, NEnd); - end; -end; - -Procedure TContainer.SortByIndex2(I1, I2 : integer; Decending : boolean); -var a, b : integer; - V1 : variant; -begin - SortByIndex(I1, Decending, 0, 0); - a:= 0; b:= 1; - while b <= High(FCollection) do - begin - V1:= FCollection[a].ValueByIndex[I1]; - while (b <= High(FCollection)) and (FCollection[b].ValueByIndex[I1] = V1) do - Inc(b); - if (a < (b-1)) then - SortByIndex(I2, Decending, a, b-1); - a:= b; - end; -end; - -Procedure TContainer.SortByName(s : string); -var i : integer; -begin - if High(FCollection) > -1 then - begin - i:= FCollection[0].IndexByName[s]; - if i > -1 then SortByIndex(i, false, 0, 0); - end; -end; - -Procedure TContainer.FreeCollection; -var i : integer; -begin - for i:= Low(FCollection) to High(FCollection) do - FCollection[i].Free; - SetLength(FCollection, 0); -end; - -Procedure TContainer.SetSelected(i : integer); -begin - if (i >= Low(FCollection)) and (i <= High(FCollection)) then - FSelected:= i; -end; - -Procedure TContainer.UnSelect; -begin - FSelected:= -1; -end; - -Function TContainer.AddItem : TBase; -begin - Result:= NIL; - try - SetLength(FCollection, High(FCollection)+2); - FSelected:= High(FCollection); - Result:= FCollection[FSelected]; -// Result.AutoNr.Value:= MaxAutoNr; - finally - end; -end; - -Procedure TContainer.InsertItem(i : integer); -var j : integer; -begin - if (i >= Low(FCollection)) and (i <= High(FCollection)) then - begin - SetLength(FCollection, High(FCollection)+2); - for j:= High(FCollection) downto i + 1 do - FCollection[j]:= FCollection[j-1]; - end; -end; - -Procedure TContainer.RemoveItem(i : integer); -var j : integer; -begin - if (i >= Low(FCollection)) and (i <= High(FCollection)) then - begin - FCollection[i].Free; - for j:= i to High(FCollection) - 1 do - FCollection[j]:= FCollection[j+1]; - SetLength(FCollection, High(FCollection)); - end; -end; - -Procedure TContainer.RemoveByReference(Item : TBase); -var i : integer; -begin - for i:= Low(FCollection) to High(FCollection) do - if FCollection[i] = Item then - begin - RemoveItem(i); - Exit; - end; -end; - -Function TContainer.FindByName(s : string) : TBase; -var i : integer; -begin - Result:= NIL; - for i:= Low(FCollection) to High(FCollection) do - if Trim(UpperCase(FCollection[i].Name.Value)) = Trim(Uppercase(s)) then - begin - Result:= FCollection[i]; - Exit; - end; -end; - -Function TContainer.FindByNameOnStock(s : string) : TBase; -var i : integer; - ing : TIngredient; -begin - Result:= NIL; - ing:= NIL; - for i:= Low(FCollection) to High(FCollection) do - begin - if FCollection[i] is TIngredient then - begin - if Trim(UpperCase(FCollection[i].Name.Value)) = Trim(Uppercase(s)) then - begin - ing:= TIngredient(FCollection[i]); - if Result = NIL then Result:= ing - else - begin - if ing.Inventory.Value > TIngredient(Result).Inventory.Value then - Result:= ing; - end; - end; - end; - end; -end; - -Function TContainer.IndexByName(s : string) : integer; -var i : integer; -begin - Result:= -1; - for i:= Low(FCollection) to High(FCollection) do - if Trim(UpperCase(FCollection[i].Name.Value)) = Trim(Uppercase(s)) then - begin - Result:= i; - Exit; - end; -end; - -Function TContainer.FindByAutoNr(i : integer) : TBase; -var j : integer; -begin - Result:= NIL; - for j:= 0 to High(FCollection) do - if FCollection[j].AutoNr.Value = i then - begin - Result:= FCollection[j]; - Exit; - end; -end; - -Procedure TContainer.RemoveByAutoNr(i : integer); -var j : integer; -begin - for j:= Low(FCollection) to High(FCollection) do - if FCollection[j].AutoNr.Value = i then - begin - RemoveItem(j); - Exit; - end; -end; - -Function TContainer.GetNumItems : integer; -begin - Result:= High(FCollection) + 1; -end; - -Function TContainer.GetItem(i : integer) : TBase; -begin - Result:= NIL; - if (i >= Low(FCollection)) and (i <= High(FCollection)) then - Result:= FCollection[i]; -end; - - -{=========================== TFermentables ====================================} - -Constructor TFermentables.Create; -begin - Inherited; - FLabel:= 'FERMENTABLES'; - FFileName:= 'fermentables.xml'; -end; - -Procedure TFermentables.SaveXML; -var i : integer; - FN : string; -begin - try - Inherited SaveXML; - FN:= Settings.DataLocation.Value + FFileName; - for i:= Low(FCollection) to High(FCollection) do - TFermentable(FCollection[i]).SaveXML(FDoc, FRootNode, false); - writeXMLFile(FDoc, FN); - finally - FDoc.Free; - end; -end; - -Procedure TFermentables.ReadXML; -var i : integer; -begin - Inherited ReadXML; - if FRootNode <> NIL then - begin - try - i:= 0; - FChild:= FRootNode.FirstChild; - while FChild <> NIL do - begin - inc(i); - SetLength(FCollection, i); - FCollection[i-1]:= TFermentable.Create(NIL); - TFermentable(FCollection[i-1]).ReadXML(FChild); - FChild:= FChild.NextSibling; - end; - finally - FDoc.Free; - end; - end; -end; - -Function TFermentables.ImportXML : boolean; -var i : integer; -begin - Inherited ImportXML; - if FRootNode <> NIL then - begin - try - i:= High(FCollection) + 1; - FChild:= FRootNode.FirstChild; - while FChild <> NIL do - begin - inc(i); - SetLength(FCollection, i); - FCollection[i-1]:= TFermentable.Create(NIL); - TFermentable(FCollection[i-1]).ReadXML(FChild); - if TFermentable(FCollection[i-1]).Yield.Value < 1 then - RemoveByReference(FCollection[i-1]); - FChild:= FChild.NextSibling; - end; - Result:= TRUE; - finally - FDoc.Free; - end; - end; -end; - -Function TFermentables.GetSelectedItem : TFermentable; -begin - Result:= NIL; - if FSelected > -1 then - Result:= TFermentable(FCollection[FSelected]); -end; - -Function TFermentables.AddItem : TFermentable; -begin - Result:= NIL; - try - SetLength(FCollection, High(FCollection)+2); - FSelected:= High(FCollection); - FCollection[High(FCollection)]:= TFermentable.Create(NIL); - Result:= TFermentable(FCollection[High(FCollection)]); - finally - end; -end; - -Procedure TFermentables.InsertItem(i : integer); -begin - Inherited; - if (i >= Low(FCollection)) and (i <= High(FCollection)) then - FCollection[i]:= TFermentable.Create(NIL); -end; - -Function TFermentables.FindByNameAndSupplier(N, S : string) : TFermentable; -var i : integer; -begin - Result:= NIL; - if (N <> '') AND (S <> '') then - begin - for i:= Low(FCollection) to High(FCollection) do - if (Lowercase(TFermentable(FCollection[i]).Name.Value) = Lowercase(N)) and - (Lowercase(TFermentable(FCollection[i]).Supplier.Value) = Lowercase(S)) then - begin - Result:= TFermentable(FCollection[i]); - Exit; - end; - end; -end; - -{================================== THops =====================================} - -Constructor THops.Create; -begin - Inherited; - FLabel:= 'HOPS'; - FFileName:= 'hops.xml'; - FSelected:= -1; -end; - -Procedure THops.SaveXML; -var i : integer; - FN : string; -begin - try - Inherited SaveXML; - for i:= Low(FCollection) to High(FCollection) do - THop(FCollection[i]).SaveXML(FDoc, FRootNode, false); - FN:= Settings.DataLocation.Value + FFileName; - writeXMLFile(FDoc, FN); - finally - FDoc.Free; - end; -end; - -Procedure THops.ReadXML; -var i : integer; -begin - Inherited ReadXML; - if FRootNode <> NIL then - begin - try - i:= 0; - FChild:= FRootNode.FirstChild; - while FChild <> NIL do - begin - inc(i); - SetLength(FCollection, i); - FCollection[i-1]:= THop.Create(NIL); - THop(FCollection[i-1]).ReadXML(FChild); - FChild:= FChild.NextSibling; - end; - finally - FDoc.Free; - end; - end; -end; - -Function THops.ImportXML : boolean; -var i : integer; -begin - Inherited ImportXML; - if FRootNode <> NIL then - begin - try - i:= High(FCollection) + 1; - FChild:= FRootNode.FirstChild; - while FChild <> NIL do - begin - inc(i); - SetLength(FCollection, i); - FCollection[i-1]:= THop.Create(NIL); - THop(FCollection[i-1]).ReadXML(FChild); - if THop(FCollection[i-1]).Alfa.Value <= 0.5 then - RemoveByReference(FCollection[i-1]); - FChild:= FChild.NextSibling; - end; - Result:= TRUE; - finally - FDoc.Free; - end; - end; -end; - -Function THops.GetSelectedItem : THop; -begin - Result:= NIL; - if FSelected > -1 then - Result:= THop(FCollection[FSelected]); -end; - -Function THops.AddItem : THop; -begin - Result:= NIL; - try - SetLength(FCollection, High(FCollection)+2); - FSelected:= High(FCollection); - Result:= NIL; - FCollection[High(FCollection)]:= THop.Create(NIL); - Result:= THop(FCollection[FSelected]); - finally - end; -end; - -Procedure THops.InsertItem(i : integer); -begin - Inherited; - if (i >= Low(FCollection)) and (i <= High(FCollection)) then - FCollection[i]:= THop.Create(NIL); -end; - -Function THops.FindByNameAndOriginAndAlfa(N, O : string; A : double) : THop; -var i : integer; - A2 : double; - N2, O2 : string; -begin - Result:= NIL; - N:= LowerCase(Trim(N)); - O:= LowerCase(Trim(O)); - A:= RoundTo(A, -1); - if (N <> '') AND (O <> '') then - begin - for i:= Low(FCollection) to High(FCollection) do - begin - N2:= Lowercase(Trim(THop(FCollection[i]).Name.Value)); - O2:= Lowercase(Trim(THop(FCollection[i]).Origin.Value)); - A2:= THop(FCollection[i]).Alfa.Value; - A2:= RoundTo(A2, -1); - if (N2 = N) and (O2 = O) and (A2 = A) then - begin - Result:= THop(FCollection[i]); - Exit; - end; - end; - end; -end; - -{================================== TMiscs ====================================} - -Constructor TMiscs.Create; -begin - Inherited; - FLabel:= 'MISCS'; - FFileName:= 'miscs.xml'; - FSelected:= -1; -end; - -Procedure TMiscs.SaveXML; -var i : integer; - FN : string; -begin - try - Inherited SaveXML; - FN:= Settings.DataLocation.Value + FFileName; - for i:= Low(FCollection) to High(FCollection) do - TMisc(FCollection[i]).SaveXML(FDoc, FRootNode, false); - writeXMLFile(FDoc, FN); - finally - FDoc.Free; - end; -end; - -Procedure TMiscs.ReadXML; -var i : integer; -begin - Inherited ReadXML; - if FRootNode <> NIL then - begin - try - i:= 0; - FChild:= FRootNode.FirstChild; - while FChild <> NIL do - begin - inc(i); - SetLength(FCollection, i); - FCollection[i-1]:= TMisc.Create(NIL); - TMisc(FCollection[i-1]).ReadXML(FChild); - FChild:= FChild.NextSibling; - end; - finally - FDoc.Free; - end; - end; -end; - -Function TMiscs.ImportXML : boolean; -var i : integer; -begin - Inherited ImportXML; - if FRootNode <> NIL then - begin - try - i:= High(FCollection) + 1; - FChild:= FRootNode.FirstChild; - while FChild <> NIL do - begin - inc(i); - SetLength(FCollection, i); - FCollection[i-1]:= TMisc.Create(NIL); - TMisc(FCollection[i-1]).ReadXML(FChild); - {if TMisc(FCollection[i-1])..Value < 1 then - RemoveByReference(FCollection[i-1]);} - FChild:= FChild.NextSibling; - end; - Result:= TRUE; - finally - FDoc.Free; - end; - end; -end; - -Function TMiscs.GetSelectedItem : TMisc; -begin - Result:= NIL; - if FSelected > -1 then - Result:= TMisc(FCollection[FSelected]); -end; - -Function TMiscs.AddItem : TMisc; -begin - Result:= NIL; - try - SetLength(FCollection, High(FCollection)+2); - FSelected:= High(FCollection); - FCollection[High(FCollection)]:= TMisc.Create(NIL); - Result:= TMisc(FCollection[High(FCollection)]); - finally - end; -end; - -Procedure TMiscs.InsertItem(i : integer); -begin - Inherited; - if (i >= Low(FCollection)) and (i <= High(FCollection)) then - FCollection[i]:= TMisc.Create(NIL); -end; - -{================================== TYeasts ===================================} - -Constructor TYeasts.Create; -begin - Inherited; - FLabel:= 'YEASTS'; - FFileName:= 'yeasts.xml'; - FSelected:= -1; -end; - -Procedure TYeasts.SaveXML; -var i : integer; - FN : string; -begin - try - Inherited SaveXML; - FN:= Settings.DataLocation.Value + FFileName; - for i:= Low(FCollection) to High(FCollection) do - TYeast(FCollection[i]).SaveXML(FDoc, FRootNode, false); - writeXMLFile(FDoc, FN); - finally - FDoc.Free; - end; -end; - -Procedure TYeasts.ReadXML; -var i : integer; -begin - Inherited ReadXML; - if FRootNode <> NIL then - begin - try - i:= 0; - FChild:= FRootNode.FirstChild; - while FChild <> NIL do - begin - inc(i); - SetLength(FCollection, i); - FCollection[i-1]:= TYeast.Create(NIL); - TYeast(FCollection[i-1]).ReadXML(FChild); - FChild:= FChild.NextSibling; - end; - finally - FDoc.Free; - end; - end; -end; - -Function TYeasts.ImportXML : boolean; -var i : integer; -begin - Inherited ImportXML; - if FRootNode <> NIL then - begin - try - i:= High(FCollection) + 1; - FChild:= FRootNode.FirstChild; - while FChild <> NIL do - begin - inc(i); - SetLength(FCollection, i); - FCollection[i-1]:= TYeast.Create(NIL); - TYeast(FCollection[i-1]).ReadXML(FChild); - if TYeast(FCollection[i-1]).Laboratory.Value = '' then - RemoveByReference(FCollection[i-1]); - FChild:= FChild.NextSibling; - end; - Result:= TRUE; - finally - FDoc.Free; - end; - end; -end; -Function TYeasts.GetSelectedItem : TYeast; -begin - Result:= NIL; - if FSelected > -1 then - Result:= TYeast(FCollection[FSelected]); -end; - -Function TYeasts.AddItem : TYeast; -begin - Result:= NIL; - try - SetLength(FCollection, High(FCollection)+2); - FSelected:= High(FCollection); - FCollection[High(FCollection)]:= TYeast.Create(NIL); - Result:= TYeast(FCollection[High(FCollection)]); - finally - end; -end; - -Procedure TYeasts.InsertItem(i : integer); -begin - Inherited; - if (i >= Low(FCollection)) and (i <= High(FCollection)) then - FCollection[i]:= TYeast.Create(NIL); -end; - -Function TYeasts.FindByNameAndLaboratory(N, L : string) : TYeast; -var i : integer; -begin - Result:= NIL; - if (N <> '') and (L <> '') then - begin - for i:= Low(FCollection) to High(FCollection) do - if (Lowercase(TYeast(FCollection[i]).Name.Value) = Lowercase(N)) and - (Lowercase(TYeast(FCollection[i]).Laboratory.Value) = Lowercase(L)) then - begin - Result:= TYeast(FCollection[i]); - Exit; - end; - end; -end; - -{================================== TWaters ===================================} - -Constructor TWaters.Create; -begin - Inherited; - FLabel:= 'WATERS'; - FFileName:= 'waters.xml'; - FSelected:= -1; -end; - -Procedure TWaters.SaveXML; -var i : integer; - FN : string; -begin - try - Inherited SaveXML; - FN:= Settings.DataLocation.Value + FFileName; - for i:= Low(FCollection) to High(FCollection) do - TWater(FCollection[i]).SaveXML(FDoc, FRootNode, false); - writeXMLFile(FDoc, FN); - finally - FDoc.Free; - end; -end; - -Procedure TWaters.ReadXML; -var i : integer; -begin - Inherited ReadXML; - if FRootNode <> NIL then - begin - try - i:= 0; - FChild:= FRootNode.FirstChild; - while FChild <> NIL do - begin - inc(i); - SetLength(FCollection, i); - FCollection[i-1]:= TWater.Create(NIL); - TWater(FCollection[i-1]).ReadXML(FChild); - FChild:= FChild.NextSibling; - end; - finally - FDoc.Free; - end; - end; -end; - -Function TWaters.ImportXML : boolean; -var i : integer; -begin - Inherited ImportXML; - if FRootNode <> NIL then - begin - try - i:= High(FCollection) + 1; - FChild:= FRootNode.FirstChild; - while FChild <> NIL do - begin - inc(i); - SetLength(FCollection, i); - FCollection[i-1]:= TWater.Create(NIL); - TWater(FCollection[i-1]).ReadXML(FChild); - if TWater(FCollection[i-1]).Bicarbonate.Value < 0.1 then - RemoveByReference(FCollection[i-1]); - FChild:= FChild.NextSibling; - end; - Result:= TRUE; - finally - FDoc.Free; - end; - end; -end; - -Function TWaters.GetSelectedItem : TWater; -begin - Result:= NIL; - if FSelected > -1 then - Result:= TWater(FCollection[FSelected]); -end; - -Function TWaters.AddItem : TWater; -begin - Result:= NIL; - try - SetLength(FCollection, High(FCollection)+2); - FSelected:= High(FCollection); - FCollection[High(FCollection)]:= TWater.Create(NIL); - Result:= TWater(FCollection[High(FCollection)]); - finally - end; -end; - -Procedure TWaters.InsertItem(i : integer); -begin - Inherited; - if (i >= Low(FCollection)) and (i <= High(FCollection)) then - FCollection[i]:= TWater.Create(NIL); -end; - -Function TWaters.GetDefaultWater : TWater; -var i : integer; - W : TWater; -begin - Result:= NIL; - for i:= 0 to NumItems - 1 do - begin - W:= TWater(Item[i]); - if W.DefaultWater.Value then Result:= W; - end; -end; - -Function TWaters.GetDemiWater : TWater; -var i : integer; - W : TWater; -begin - Result:= NIL; - for i:= 0 to NumItems - 1 do - begin - W:= TWater(Item[i]); - if W.DemiWater then Result:= W; - end; - if Result = NIL then - W:= TWater(FindByName('Gedemineraliseerd water')); - if Result = NIL then - W:= TWater(FindByName('Demiwater')); - if Result = NIL then - W:= TWater(FindByName('Osmosewater')); -end; - -{================================== TBeerstyles ===============================} - -Constructor TBeerstyles.Create; -begin - Inherited; - FLabel:= 'STYLES'; - FFileName:= 'styles.xml'; - FSelected:= -1; -end; - -Procedure TBeerstyles.SaveXML; -var i : integer; - FN : string; -begin - try - Inherited SaveXML; - FN:= Settings.DataLocation.Value + FFileName; - for i:= Low(FCollection) to High(FCollection) do - TBeerstyle(FCollection[i]).SaveXML(FDoc, FRootNode, false); - writeXMLFile(FDoc, FN); - finally - FDoc.Free; - end; -end; - -Procedure TBeerstyles.ReadXML; -var i : integer; -begin - Inherited ReadXML; - if FRootNode <> NIL then - begin - try - i:= 0; - FChild:= FRootNode.FirstChild; - while FChild <> NIL do - begin - inc(i); - SetLength(FCollection, i); - FCollection[i-1]:= TBeerStyle.Create(NIL); - TBeerStyle(FCollection[i-1]).ReadXML(FChild); - FChild:= FChild.NextSibling; - end; - finally - FDoc.Free; - end; - end; -end; - -Function TBeerstyles.ImportXML : boolean; -var i : integer; -begin - Inherited ImportXML; - if FRootNode <> NIL then - begin - try - i:= High(FCollection) + 1; - FChild:= FRootNode.FirstChild; - while FChild <> NIL do - begin - inc(i); - SetLength(FCollection, i); - FCollection[i-1]:= TBeerstyle.Create(NIL); - TBeerstyle(FCollection[i-1]).ReadXML(FChild); - if TBeerstyle(FCollection[i-1]).StyleLetter.Value = '' then - RemoveByReference(FCollection[i-1]); - FChild:= FChild.NextSibling; - end; - Result:= TRUE; - finally - FDoc.Free; - end; - end; -end; -Function TBeerstyles.GetSelectedItem : TBeerstyle; -begin - Result:= NIL; - if FSelected > -1 then - Result:= TBeerstyle(FCollection[FSelected]); -end; - -Function TBeerstyles.AddItem : TBeerStyle; -begin - Result:= NIL; - try - SetLength(FCollection, High(FCollection)+2); - FSelected:= High(FCollection); - FCollection[High(FCollection)]:= TBeerstyle.Create(NIL); - Result:= TBeerstyle(FCollection[High(FCollection)]); - finally - end; -end; - -Procedure TBeerstyles.InsertItem(i : integer); -begin - Inherited; - if (i >= Low(FCollection)) and (i <= High(FCollection)) then - FCollection[i]:= TBeerstyle.Create(NIL); -end; - -{================================== TEquipments ===============================} - -Constructor TEquipments.Create; -begin - Inherited; - FLabel:= 'EQUIPMENTS'; - FFileName:= 'equipments.xml'; - FSelected:= -1; -end; - -Procedure TEquipments.SaveXML; -var i : integer; - FN : string; -begin - try - Inherited SaveXML; - FN:= Settings.DataLocation.Value + FFileName; - for i:= Low(FCollection) to High(FCollection) do - TEquipment(FCollection[i]).SaveXML(FDoc, FRootNode, false); - writeXMLFile(FDoc, FN); - finally - FDoc.Free; - end; -end; - -Procedure TEquipments.ReadXML; -var i : integer; -begin - Inherited ReadXML; - if FRootNode <> NIL then - begin - try - i:= 0; - FChild:= FRootNode.FirstChild; - while FChild <> NIL do - begin - inc(i); - SetLength(FCollection, i); - FCollection[i-1]:= TEquipment.Create(NIL); - TEquipment(FCollection[i-1]).ReadXML(FChild); - FChild:= FChild.NextSibling; - end; - finally - FDoc.Free; - end; - end; -end; - -Function TEquipments.GetSelectedItem : TEquipment; -begin - Result:= NIL; - if FSelected > -1 then - Result:= TEquipment(FCollection[FSelected]); -end; - -Function TEquipments.AddItem : TEquipment; -begin - Result:= NIL; - try - SetLength(FCollection, High(FCollection)+2); - FSelected:= High(FCollection); - FCollection[High(FCollection)]:= TEquipment.Create(NIL); - Result:= TEquipment(FCollection[High(FCollection)]); - finally - end; -end; - -Procedure TEquipments.InsertItem(i : integer); -begin - Inherited; - if (i >= Low(FCollection)) and (i <= High(FCollection)) then - FCollection[i]:= TEquipment.Create(NIL); -end; - -Procedure TEquipments.CalcEfficiencyRegressionFactors; -var i : integer; -begin - for i:= Low(FCollection) to High(FCollection) do - TEquipment(FCollection[i]).CalcEfficiencyFactors; -end; - -Procedure TEquipments.CalcAttenuationRegressionFactors; -var i : integer; -begin - for i:= Low(FCollection) to High(FCollection) do - TEquipment(FCollection[i]).CalcAttenuationFactors; -end; - -{================================== TMashs ====================================} - -Constructor TMashs.Create; -begin - Inherited; - FLabel:= 'MASHS'; - FFileName:= 'mashs.xml'; - FSelected:= -1; -end; - -Procedure TMashs.SaveXML; -var i : integer; - FN : string; -begin - try - Inherited SaveXML; - FN:= Settings.DataLocation.Value + FFileName; - for i:= Low(FCollection) to High(FCollection) do - TMash(FCollection[i]).SaveXML(FDoc, FRootNode, false); - writeXMLFile(FDoc, FN); - finally - FDoc.Free; - end; -end; - -Procedure TMashs.ReadXML; -var i : integer; -begin - Inherited ReadXML; - if FRootNode <> NIL then - begin - try - i:= 0; - FChild:= FRootNode.FirstChild; - while FChild <> NIL do - begin - inc(i); - SetLength(FCollection, i); - FCollection[i-1]:= TMash.Create(NIL); - TMash(FCollection[i-1]).ReadXML(FChild); - FChild:= FChild.NextSibling; - end; - finally - FDoc.Free; - end; - end; -end; - -Function TMashs.ImportXML : boolean; -var i : integer; -begin - Inherited ImportXML; - if FRootNode <> NIL then - begin - try - i:= High(FCollection) + 1; - FChild:= FRootNode.FirstChild; - while FChild <> NIL do - begin - inc(i); - SetLength(FCollection, i); - FCollection[i-1]:= TMash.Create(NIL); - TMash(FCollection[i-1]).ReadXML(FChild); - if TMash(FCollection[i-1]).NumMashSteps = 0 then - RemoveByReference(FCollection[i-1]); - FChild:= FChild.NextSibling; - end; - Result:= TRUE; - finally - FDoc.Free; - end; - end; -end; - -Function TMashs.GetSelectedItem : TMash; -begin - Result:= NIL; - if FSelected > -1 then - Result:= TMash(FCollection[FSelected]); -end; - -Function TMashs.AddItem : TMash; -begin - Result:= NIL; - try - SetLength(FCollection, High(FCollection)+2); - FSelected:= High(FCollection); - FCollection[High(FCollection)]:= TMash.Create(NIL); - Result:= TMash(FCollection[High(FCollection)]); - finally - end; -end; - -Procedure TMashs.InsertItem(i : integer); -begin - Inherited; - if (i >= Low(FCollection)) and (i <= High(FCollection)) then - FCollection[i]:= TMash.Create(NIL); -end; - -{================================== TRecipes ==================================} - - -Constructor TRecipes.Create; -begin - Inherited; - FLabel:= 'RECIPES'; - FFileName:= 'recipes.xml'; - FSelected:= -1; - SetLength(FFermentablesMinMaxArray, 0); - SetLength(FBitterhopMinMaxArray, 0); - SetLength(FAromahopMinMaxArray, 0); - SetLength(FDryhopMinMaxArray, 0); - SetLength(FYeastMinMaxArray, 0); - SetLength(FMiscMinMaxArray, 0); - SetLength(FCommonMinMaxArray, 0); -end; - -Destructor TRecipes.Destroy; -begin - SetLength(FFermentablesMinMaxArray, 0); - SetLength(FBitterhopMinMaxArray, 0); - SetLength(FAromahopMinMaxArray, 0); - SetLength(FDryhopMinMaxArray, 0); - SetLength(FYeastMinMaxArray, 0); - SetLength(FMiscMinMaxArray, 0); - SetLength(FCommonMinMaxArray, 0); - Inherited; -end; - -Procedure TRecipes.SaveXML; -var i : integer; - FN : string; -begin - try - Inherited SaveXML; - FN:= Settings.DataLocation.Value + FFileName; - for i:= Low(FCollection) to High(FCollection) do - begin - TRecipe(FCollection[i]).SaveXML(FDoc, FRootNode, false); - Application.ProcessMessages; - end; - writeXMLFile(FDoc, FN); - finally - FDoc.Free; - end; -end; - -Procedure TRecipes.ReadXML; -var i : integer; - R : TRecipe; -begin - Inherited ReadXML; - if FRootNode <> NIL then - begin - try - i:= 0; - FChild:= FRootNode.FirstChild; - while FChild <> NIL do - begin - inc(i); - SetLength(FCollection, i); - Application.ProcessMessages; - FCollection[i-1]:= TRecipe.Create(NIL); - R:= TRecipe(FCollection[i-1]); - if FFileName = 'brews.xml' then R.RecType:= rtBrew - else if FFileName = 'recipes.xml' then R.RecType:= rtRecipe - else R.RecType:= rtCloud; - R.ReadXML(FChild); - FChild:= FChild.NextSibling; - end; - finally - FDoc.Free; - end; - end; -end; - -Function TRecipes.FindByNameAndNr(Nm, Nr : string) : TRecipe; -var i : integer; - R : TRecipe; -begin - Result:= NIL; - Nm:= Lowercase(Nm); - Nr:= Lowercase(Nr); - for i:= 0 to High(FCollection) do - begin - R:= TRecipe(FCollection[i]); - if (Lowercase(R.NrRecipe.Value) = Nr) and (Lowercase(R.Name.Value) = Nm) then - begin - Result:= R; - Exit; - end; - end; -end; - -Function TRecipes.FindByAutoNr(nr : integer) : TRecipe; -var i : integer; - R : TRecipe; -begin - Result:= NIL; - for i:= 0 to High(FCollection) do - begin - R:= TRecipe(FCollection[i]); - if (R.AutoNr.Value = Nr) then - begin - Result:= R; - Exit; - end; - end; -end; - -Procedure TRecipes.CheckAutoNrs; -var i, maxnr : integer; - R : TRecipe; -begin - maxnr:= MaxAutoNr; - for i:= Low(FCollection) to High(FCollection) do - begin - R:= TRecipe(FCollection[i]); - if R.AutoNr.Value = 0 then - begin - inc(maxnr); - R.AutoNr.Value:= maxnr; - end; - end; -end; - -Function TRecipes.ImportFiles(FN : TStrings; DN : string; Equip : TEquipment; - FT : TFileType) : boolean; -begin - Result:= false; - case FT of - ftXML: Result:= ImportXMLs(FN, DN, Equip); - ftPromash: Result:= ImportRECs(FN, DN, Equip); - ftInvalid: Result:= false; - end; - SaveXML; -end; - -Function TRecipes.ImportXMLs(FN : TStrings; DN : string; Equip : TEquipment) : boolean; -var SL : TStringList; - i : integer; - mask : string; - ps : TProgressBar; -begin - Result:= false; - if DN <> '' then - begin - try - Screen.Cursor:= crHourglass; - {$ifdef WINDOWS} - mask:= '*.xml'; - {$else} - mask:= '*xml'; - {$endif} - SL:= FindAllFiles(DN, mask, false); -{ FrmMain.sbMain.Panels[0].Text:= 'Importeren...'; - ps:= TProgressBar.Create(FrmMain.sbMain); - ps.Parent:= FrmMain.sbMain; - ps.Left:= FrmMain.sbMain.Panels[0].Width + 1; - ps.Width:= FrmMain.sbMain.Panels[1].Width; - ps.Min:= 0; - ps.Max:= SL.Count - 1; - ps.Position:= 0;} - for i:= 0 to SL.Count - 1 do - begin - ImportXML(SL[i], Equip); -// ps.Position:= i; - Application.ProcessMessages; - end; - Result:= TRUE; - finally - Screen.Cursor:= crDefault; -// ps.Free; - SL.Free; -// FrmMain.sbMain.Panels[0].Text:= ''; - ShowMessage('Importeren klaar'); - end; - end - else - begin - for i:= 0 to FN.Count - 1 do - begin - Result:= ImportXML(FN[i], Equip); - end; - end; -end; - -Function TRecipes.GetMaxAutoNr : integer; -var i : integer; -begin - Result:= 0; - for i:= Low(FCollection) to High(FCollection) do - if TRecipe(FCollection[i]).AutoNr.Value > Result then - Result:= TRecipe(FCollection[i]).AutoNr.Value; -end; - -Function TRecipes.ImportXML(FN : string; Equip : TEquipment) : boolean; -var R : TRecipe; - s : string; -begin - Result:= false; - FDoc := TXMLDocument.Create; - FRootNode:= NIL; - try - if FileExists(FN) then - begin - ReadXMLFile(FDoc, FN); - s:= ExtractFileNameOnly(FN); - FRootNode:= FDoc.FindNode(FLabel); - if FRootNode <> NIL then - begin - FChild:= FRootNode.FirstChild; - while FChild <> NIL do - begin - R:= AddItem; - Application.ProcessMessages; - R.ReadXML(FChild); - R.AutoNr.Value:= GetMaxAutoNr + 1; - R.ParentAutoNr.Value:= ''; - - CheckBeerStyle(R); - CheckFermentables(R); - CheckYeasts(R); - - //change the equipment - if Equip <> NIL then R.ChangeEquipment(Equip) - else R.RemoveNonBrewsData; - - if FFileName = 'brews.xml' then R.RecType:= rtBrew - else if FFileName = 'recipes.xml' then R.RecType:= rtRecipe - else R.RecType:= rtCloud; - - FChild:= FChild.NextSibling; - Result:= TRUE; - end; - end; - end; - finally - FDoc.Free; - end; -end; - -Function TRecipes.ImportRECs(FN : TStrings; DN : string; Equip : TEquipment) : boolean; -var SL : TStringList; - i : integer; - mask : string; - ps : TProgressBar; -begin - Result:= false; - if DN <> '' then - begin - try - Screen.Cursor:= crHourglass; - {$ifdef WINDOWS} - mask:= '*.rec'; - {$else} - mask:= '*rec'; - {$endif} - SL:= FindAllFiles(DN, mask, false); -{ FrmMain.sbMain.Panels[0].Text:= 'Importeren...'; - ps:= TProgressBar.Create(FrmMain.sbMain); - ps.Parent:= FrmMain.sbMain; - ps.Left:= FrmMain.sbMain.Panels[0].Width + 1; - ps.Width:= FrmMain.sbMain.Panels[1].Width; - ps.Min:= 0; - ps.Max:= SL.Count - 1; - ps.Position:= 0;} - for i:= 0 to SL.Count - 1 do - begin - ImportREC(SL[i], Equip); -// ps.Position:= i; - Application.ProcessMessages; - end; - Result:= TRUE; - finally - Screen.Cursor:= crDefault; -// ps.Free; - SL.Free; -// FrmMain.sbMain.Panels[0].Text:= ''; - ShowMessage('Importeren klaar'); - end; - end - else - for i:= 0 to FN.Count - 1 do - begin - Result:= ImportREC(FN[i], Equip); - end; -end; - -Function TRecipes.ImportREC(FN : string; Equip : TEquipment) : boolean; -var PI : TPromash; - R : TRecipe; - s : string; -begin - Result:= false; - PI := TPromash.Create(FrmMain); - try - FN:= ConvertStringEnc(FN); - if FileExists(FN) then - begin - if PI.OpenReadRec(FN) then - begin - R:= AddItem; - if R <> NIL then - begin - PI.Convert(R); - s:= R.Style.Name.Value; - R.AutoNr.Value:= MaxAutoNr + 1; - - CheckBeerStyle(R); - CheckFermentables(R); - CheckYeasts(R); - - //change the equipment - if Equip <> NIL then - R.ChangeEquipment(Equip); - - if FFileName = 'brews.xml' then R.RecType:= rtBrew - else if FFileName = 'recipes.xml' then R.RecType:= rtRecipe - else R.RecType:= rtCloud; - - Result:= TRUE; - end; - end; - end; - finally - PI.Free; - end; -end; - -Procedure TRecipes.QuickSortRecipes(var Arr : array of TBase); - procedure QuickSort(var A: array of TBase; iLo, iHi: Integer); - var Lo, Hi: Integer; - s : string; - T : TRecipe; - begin - Lo := iLo; - Hi := iHi; - s:= TRecipe(A[(Lo + Hi) div 2]).NrRecipe.Value; - repeat - while TRecipe(A[Lo]).NrRecipe.Value < s do Inc(Lo); - while TRecipe(A[Hi]).NrRecipe.Value > s do Dec(Hi); - if Lo <= Hi then - begin - T := TRecipe(A[Lo]); - TRecipe(A[Lo]) := TRecipe(A[Hi]); - TRecipe(A[Hi]) := T; - Inc(Lo); - Dec(Hi); - end; - until Lo > Hi; - if Hi > iLo then QuickSort(A, iLo, Hi); - if Lo < iHi then QuickSort(A, Lo, iHi); - end; -begin - if High(Arr) > -1 then QuickSort(Arr, Low(Arr), High(Arr)); -end; - -Procedure TRecipes.Sort; -begin - QuickSortRecipes(FCollection); -end; - -Function TRecipes.GetLastNrRecipe : string; -begin - Sort; - Result:= ''; - if High(FCollection) >= 0 then - Result:= TRecipe(FCollection[High(FCollection)]).NrRecipe.Value; -end; - -Function TRecipes.GetSelectedItem : TRecipe; -begin - Result:= NIL; - if FSelected > -1 then - Result:= TRecipe(FCollection[FSelected]); -end; - -Function TRecipes.AddItem : TRecipe; -begin - Result:= NIL; - try - SetLength(FCollection, High(FCollection)+2); - FSelected:= High(FCollection); - FCollection[High(FCollection)]:= TRecipe.Create(NIL); - Result:= TRecipe(FCollection[High(FCollection)]); - finally - end; -end; - -Procedure TRecipes.InsertItem(i : integer); -var R : TRecipe; -begin - Inherited; - if (i >= Low(FCollection)) and (i <= High(FCollection)) then - begin - FCollection[i]:= TRecipe.Create(NIL); - R:= TRecipe(FCollection[i]); - if FFileName = 'brews.xml' then R.RecType:= rtBrew - else if FFileName = 'recipes.xml' then R.RecType:= rtRecipe - else R.RecType:= rtCloud; - end; -end; - -Function TRecipes.ExportToCSV(A : array of longint) : boolean; -var i, j : integer; - dlg : TSaveDialog; - SL : TStringList; - line : string; - R : TRecipe; -begin - Result:= false; - dlg:= TSaveDialog.Create(frmMain); - if High(FCollection) > 0 then - try - SL:= TStringList.Create; - SL.Sorted:= false; - with dlg do - begin - DefaultExt:= '.csv'; - FileName:= '*.csv'; - Filter:= 'Comma separated values|*.csv'; - if dlg.Execute then - begin - R:= TRecipe(FCollection[0]); - Line:= 'Code;Nr;Naam;Gist naam;'; - for j:= Low(A) to High(A) do - begin - line:= line + R.GetNumberNameByIndex(A[j]); - if j < High(A) then line:= line + ';'; - end; - SL.Add(line); - for i:= Low(FCollection) to High(FCollection) do - begin - line:= ''; - R:= TRecipe(FCollection[i]); - line:= R.NrRecipe.Value + ';'; - line:= line + R.Name.Value + ';'; - line:= line + R.Yeast[0].Name.Value + ';'; - for j:= Low(A) to High(A) do - begin - line:= line + VarToStr(R.GetNumberByIndex(A[j])); - if j < High(A) then line:= line + ';'; - end; - SL.Add(line); - end; - SL.SaveToFile(dlg.FileName); - end; - end; - Result:= TRUE; - finally - dlg.Free; - SL.Free; - end; -end; - -Procedure TRecipes.QuickSortA(var Arr : array of TMinMax); - procedure QuickSort(var A: array of TMinMax; iLo, iHi: Integer); - var Lo, Hi: Integer; - s : single; - T : TMinMax; - begin - Lo := iLo; - Hi := iHi; - s:= A[(Lo + Hi) div 2].PercRecipes; - repeat - while A[Lo].PercRecipes > s do Inc(Lo); - while A[Hi].PercRecipes < s do Dec(Hi); - if Lo <= Hi then - begin - T := A[Lo]; - A[Lo] := A[Hi]; - A[Hi] := T; - Inc(Lo); - Dec(Hi); - end; - until Lo > Hi; - if Hi > iLo then QuickSort(A, iLo, Hi); - if Lo < iHi then QuickSort(A, Lo, iHi); - end; -begin - if High(Arr) > -1 then QuickSort(Arr, Low(Arr), High(Arr)); -end; - -Function TRecipes.Exists(Arr : TMinMaxArray; FName : string) : integer; -var n : integer; -begin - Result:= -1; - for n:= Low(Arr) to High(Arr) do - if Arr[n].Name = FName then - begin - Result:= n; - Exit; - end; -end; - -Function TRecipes.AnalyseFermentables(Lett, Nm : string) : integer; //returns number of recipes -var i, j, k : integer; - R : TRecipe; - F : TFermentable; - FN : string; -begin - Result:= 0; - SetLength(FFermentablesMinMaxArray, 0); - for i:= Low(FCollection) to High(FCollection) do - begin - R:= TRecipe(FCollection[i]); - if (R.Style <> NIL) and - ((LowerCase(R.Style.StyleLetter.Value) = LowerCase(Lett)) and - (Lowercase(R.Style.Name.Value) = Lowercase(Nm))) then - begin - Inc(Result); - R.CalcOG; - for j:= 0 to R.NumFermentables - 1 do - begin - F:= R.Fermentable[j]; - FN:= F.Name.Value; - k:= Exists(FFermentablesMinMaxArray, FN); - if k = -1 then - begin - SetLength(FFermentablesMinMaxArray, High(FFermentablesMinMaxArray) + 2); - k:= High(FFermentablesMinMaxArray); - FFermentablesMinMaxArray[k].Name:= FN; - FFermentablesMinMaxArray[k].PercRecipes:= 1; - FFermentablesMinMaxArray[k].MinUse:= F.Percentage.Value; - FFermentablesMinMaxArray[k].AvUse:= F.Percentage.Value; - FFermentablesMinMaxArray[k].MaxUse:= F.Percentage.Value; - end - else - begin - //temporarily store the number of recipes with this ingredient in PercRecipes - FFermentablesMinMaxArray[k].PercRecipes:= FFermentablesMinMaxArray[k].PercRecipes + 1; - FFermentablesMinMaxArray[k].AvUse:= FFermentablesMinMaxArray[k].AvUse + F.Percentage.Value; - if F.Percentage.Value < FFermentablesMinMaxArray[k].MinUse then - FFermentablesMinMaxArray[k].MinUse:= F.Percentage.Value; - if F.Percentage.Value > FFermentablesMinMaxArray[k].MaxUse then - FFermentablesMinMaxArray[k].MaxUse:= F.Percentage.Value; - end; - end; - end; - end; - if (High(FCollection) >= 0) then - begin - for i:= Low(FFermentablesMinMaxArray) to High(FFermentablesMinMaxArray) do - begin - if FFermentablesMinMaxArray[i].PercRecipes > 0 then - FFermentablesMinMaxArray[i].AvUse:= FFermentablesMinMaxArray[i].AvUse / FFermentablesMinMaxArray[i].PercRecipes - else - FFermentablesMinMaxArray[i].AvUse:= 0; - if Result > 0 then - FFermentablesMinMaxArray[i].PercRecipes:= 100 * FFermentablesMinMaxArray[i].PercRecipes / Result - else - FFermentablesMinMaxArray[i].PercRecipes:= 0; - end; - QuickSortA(FFermentablesMinMaxArray); - end; -end; - -Function TRecipes.AnalyseHops(Lett, Nm : string) : integer; //returns number of recipes -type - THR = record - name : string; - conc : double; - end; -var i, j, k : integer; - R : TRecipe; - H : THop; - FN : string; - conc : double; - HRAB, HRAA, HRAD : array of THR; - function FindHR(var HRA : array of THR; nm : string) : integer; - var n : integer; - begin - Result:= -1; - for n:= Low(HRA) to High(HRA) do - if HRA[n].name = nm then - begin - Result:= n; - Exit; - end; - end; - Procedure FillArrays(var MMA : TMinMaxArray; HRA : array of THR); - var j : integer; - begin - for j:= 0 to High(HRA) do - begin - k:= Exists(MMA, HRA[j].Name); - if k = -1 then - begin - SetLength(MMA, High(MMA) + 2); - k:= High(MMA); - MMA[k].Name:= HRA[j].Name; - MMA[k].PercRecipes:= 1; - MMA[k].MinUse:= HRA[j].Conc; - MMA[k].AvUse:= MMA[k].MinUse; - MMA[k].MaxUse:= MMA[k].MinUse; - end - else - begin - //temporarily store the number of recipes with this ingredient in PercRecipes - MMA[k].PercRecipes:= MMA[k].PercRecipes + 1; - MMA[k].AvUse:= MMA[k].AvUse + HRA[j].Conc; - if HRA[j].Conc < MMA[k].MinUse then - MMA[k].MinUse:= HRA[j].Conc; - if HRA[j].Conc > MMA[k].MaxUse then - MMA[k].MaxUse:= HRA[j].Conc; - end; - end; - end; - -begin - Result:= 0; - SetLength(FBitterhopMinMaxArray, 0); - SetLength(FAromahopMinMaxArray, 0); - SetLength(FDryhopMinMaxArray, 0); - SetLength(HRAB, 0); - SetLength(HRAA, 0); - SetLength(HRAD, 0); - for i:= Low(FCollection) to High(FCollection) do - begin - R:= TRecipe(FCollection[i]); - if (R.Style <> NIL) and - ((LowerCase(R.Style.StyleLetter.Value) = LowerCase(Lett)) and - (Lowercase(R.Style.Name.Value) = Lowercase(Nm))) then - begin - Inc(Result); - for j:= 0 to R.NumHops - 1 do - begin - H:= R.Hop[j]; - FN:= H.Name.Value; - if (H.Use = huBoil) or (H.Use = huAroma) or (H.Use = huFirstWort) - or (H.Use = huWhirlpool) then - begin - if H.Time.Value > 30 then - begin - conc:= H.BitternessContribution; - k:= FindHR(HRAB, FN); - if k = -1 then - begin - SetLength(HRAB, High(HRAB) + 2); - k:= High(HRAB); - HRAB[k].Name:= FN; - HRAB[k].Conc:= 0; - end; - HRAB[k].Conc:= HRAB[k].Conc + conc; - end - else if R.BatchSize.DisplayValue > 0 then - begin - Conc:= H.Amount.DisplayValue / R.BatchSize.DisplayValue; - k:= FindHR(HRAA, FN); - if k = -1 then - begin - SetLength(HRAA, High(HRAA) + 2); - k:= High(HRAA); - HRAA[k].Name:= FN; - HRAA[k].Conc:= 0; - end; - HRAA[k].Conc:= HRAA[k].Conc + conc; - end; - end - else if H.Use = huDryhop then - begin - if R.BatchSize.DisplayValue > 0 then - begin - conc:= H.Amount.DisplayValue / R.BatchSize.DisplayValue; - k:= FindHR(HRAD, FN); - if k = -1 then - begin - SetLength(HRAD, High(HRAD) + 2); - k:= High(HRAD); - HRAD[k].Name:= FN; - HRAD[k].Conc:= 0; - end; - HRAD[k].Conc:= HRAD[k].Conc + conc; - end; - end; - end; - - FillArrays(FBitterhopMinMaxArray, HRAB); - FillArrays(FAromahopMinMaxArray, HRAA); - FillArrays(FDryHopMinMaxArray, HRAD); - SetLength(HRAB, 0); - SetLength(HRAA, 0); - SetLength(HRAD, 0); - end; - end; - if (High(FCollection) >= 0) then - begin - for i:= Low(FBitterhopMinMaxArray) to High(FBitterhopMinMaxArray) do - begin - if FBitterhopMinMaxArray[i].PercRecipes > 0 then - FBitterhopMinMaxArray[i].AvUse:= FBitterhopMinMaxArray[i].AvUse - / FBitterhopMinMaxArray[i].PercRecipes - else - FBitterhopMinMaxArray[i].AvUse:= 0; - if Result > 0 then - FBitterhopMinMaxArray[i].PercRecipes:= - 100 * FBitterhopMinMaxArray[i].PercRecipes / Result - else - FBitterhopMinMaxArray[i].PercRecipes:= 0; - end; - QuickSortA(FBitterhopMinMaxArray); - - for i:= Low(FAromahopMinMaxArray) to High(FAromahopMinMaxArray) do - begin - if FAromahopMinMaxArray[i].PercRecipes > 0 then - FAromahopMinMaxArray[i].AvUse:= FAromahopMinMaxArray[i].AvUse - / FAromahopMinMaxArray[i].PercRecipes - else - FAromahopMinMaxArray[i].AvUse:= 0; - if Result > 0 then - FAromahopMinMaxArray[i].PercRecipes:= - 100 * FAromahopMinMaxArray[i].PercRecipes / Result - else - FAromahopMinMaxArray[i].PercRecipes:= 0; - end; - QuickSortA(FAromahopMinMaxArray); - - for i:= Low(FDryhopMinMaxArray) to High(FDryhopMinMaxArray) do - begin - if FDryhopMinMaxArray[i].PercRecipes > 0 then - FDryhopMinMaxArray[i].AvUse:= FDryhopMinMaxArray[i].AvUse - / FDryhopMinMaxArray[i].PercRecipes - else - FDryhopMinMaxArray[i].AvUse:= 0; - if Result > 0 then - FDryhopMinMaxArray[i].PercRecipes:= - 100 * FDryhopMinMaxArray[i].PercRecipes / Result - else - FDryhopMinMaxArray[i].PercRecipes:= 0; - end; - QuickSortA(FDryhopMinMaxArray); - end; -end; - -Function TRecipes.AnalyseYeasts(Lett, Nm : string) : integer; //returns number of recipes -var i, j, k : integer; - R : TRecipe; - Y : TYeast; - FN : string; -begin - Result:= 0; - if High(FYeastMinMaxArray) >= 0 then - SetLength(FYeastMinMaxArray, 0); - for i:= Low(FCollection) to High(FCollection) do - begin - R:= TRecipe(FCollection[i]); - if (R.Style <> NIL) and - ((LowerCase(R.Style.StyleLetter.Value) = LowerCase(Lett)) and - (Lowercase(R.Style.Name.Value) = Lowercase(Nm))) then - begin - Inc(Result); - for j:= 0 to R.NumYeasts - 1 do - begin - Y:= R.Yeast[j]; - FN:= Y.Name.Value; - k:= Exists(FYeastMinMaxArray, FN); - if k = -1 then - begin - SetLength(FYeastMinMaxArray, High(FYeastMinMaxArray) + 2); - k:= High(FYeastMinMaxArray); - FYeastMinMaxArray[k].Name:= FN; - FYeastMinMaxArray[k].PercRecipes:= 1; - {FYeastMinMaxArray[k].MinUse:= F.Percentage.Value; - FYeastMinMaxArray[k].AvUse:= F.Percentage.Value; - FYeastMinMaxArray[k].MaxUse:= F.Percentage.Value;} - end - else - begin - //temporarily store the number of recipes with this ingredient in PercRecipes - FYeastMinMaxArray[k].PercRecipes:= FYeastMinMaxArray[k].PercRecipes + 1; - {FYeastMinMaxArray[k].AvUse:= FYeastMinMaxArray[k].AvUse + F.Percentage.Value; - if F.Percentage.Value < FYeastMinMaxArray[k].MinUse then - FYeastMinMaxArray[k].MinUse:= F.Percentage.Value; - if F.Percentage.Value > FYeastMinMaxArray[k].MaxUse then - FYeastMinMaxArray[k].MaxUse:= F.Percentage.Value;} - end; - end; - end; - end; - if (High(FCollection) >= 0) then - begin - for i:= Low(FYeastMinMaxArray) to High(FYeastMinMaxArray) do - begin - { if FYeastMinMaxArray[i].PercRecipes > 0 then - FYeastMinMaxArray[i].AvUse:= FYeastMinMaxArray[i].AvUse / FYeastMinMaxArray[i].PercRecipes - else - FYeastMinMaxArray[i].AvUse:= 0;} - if Result > 0 then - FYeastMinMaxArray[i].PercRecipes:= 100 * FYeastMinMaxArray[i].PercRecipes / Result - else - FYeastMinMaxArray[i].PercRecipes:= 0; - end; - QuickSortA(FYeastMinMaxArray); - end; -end; - -Function TRecipes.AnalyseMiscs(Lett, Nm : string) : integer; //returns number of recipes -var i, j, k : integer; - R : TRecipe; - M : TMisc; - FN : string; - conc : double; -begin - Result:= 0; - if High(FMiscMinMaxArray) >= 0 then - SetLength(FMiscMinMaxArray, 0); - for i:= Low(FCollection) to High(FCollection) do - begin - R:= TRecipe(FCollection[i]); - if (R.Style <> NIL) and - ((LowerCase(R.Style.StyleLetter.Value) = LowerCase(Lett)) and - (Lowercase(R.Style.Name.Value) = Lowercase(Nm))) then - begin - Inc(Result); - for j:= 0 to R.NumMiscs - 1 do - begin - M:= R.Misc[j]; - FN:= M.Name.Value; - if ((M.MiscType = mtSpice) or (M.MiscType = mtHerb) or (M.MiscType = mtFlavor) - or (M.MiscType = mtOther)) and (R.BatchSize.DisplayValue > 0) then - begin - conc:= M.Amount.DisplayValue / R.BatchSize.DisplayValue; - k:= Exists(FMiscMinMaxArray, FN); - if k = -1 then - begin - SetLength(FMiscMinMaxArray, High(FMiscMinMaxArray) + 2); - k:= High(FMiscMinMaxArray); - FMiscMinMaxArray[k].Name:= FN; - FMiscMinMaxArray[k].PercRecipes:= 1; - FMiscMinMaxArray[k].MinUse:= Conc; - FMiscMinMaxArray[k].AvUse:= Conc; - FMiscMinMaxArray[k].MaxUse:= Conc; - end - else - begin - //temporarily store the number of recipes with this ingredient in PercRecipes - FMiscMinMaxArray[k].PercRecipes:= FMiscMinMaxArray[k].PercRecipes + 1; - FMiscMinMaxArray[k].AvUse:= FMiscMinMaxArray[k].AvUse + Conc; - if Conc < FMiscMinMaxArray[k].MinUse then - FMiscMinMaxArray[k].MinUse:= Conc; - if Conc > FMiscMinMaxArray[k].MaxUse then - FMiscMinMaxArray[k].MaxUse:= Conc; - end; - end; - end; - end; - end; - if (High(FCollection) >= 0) then - begin - for i:= Low(FMiscMinMaxArray) to High(FMiscMinMaxArray) do - begin - if FMiscMinMaxArray[i].PercRecipes > 0 then - FMiscMinMaxArray[i].AvUse:= FMiscMinMaxArray[i].AvUse / FMiscMinMaxArray[i].PercRecipes - else - FMiscMinMaxArray[i].AvUse:= 0; - if Result > 0 then - FMiscMinMaxArray[i].PercRecipes:= 100 * FMiscMinMaxArray[i].PercRecipes / Result - else - FMiscMinMaxArray[i].PercRecipes:= 0; - end; - QuickSortA(FMiscMinMaxArray); - end; -end; - -Function TRecipes.AnalyseRecipes(Lett, Nm : string) : integer; //returns number of recipes -var i, j : integer; - R : TRecipe; - SGp, bitt, x : double; -begin - Result:= 0; - SetLength(FCommonMinMaxArray, 0); - SetLength(FCommonMinMaxArray, 3); - for j:= 0 to High(FCommonMinMaxArray) do - begin - FCommonMinMaxArray[j].PercRecipes:= 0; - FCommonMinMaxArray[j].MinUse:= 10000; - FCommonMinMaxArray[j].AvUse:= 0; - FCommonMinMaxArray[j].MaxUse:= 0; - FCommonMinMaxArray[j].Name:= ''; - end; - //0 = SG points - FCommonMinMaxArray[0].Name:= 'SG punten'; - //1 = Bitterness - FCommonMinMaxArray[1].Name:= 'Bitterheid (IBU)'; - //2 = Color - FCommonMinMaxArray[2].Name:= 'Kleur (' + TRecipe(FCollection[0]).EstColor.DisplayUnitString + ')'; - { //3 = BitternessIndex - FCommonMinMaxArray[3].Name:= 'Bitterheidsindex';} - - for i:= Low(FCollection) to High(FCollection) do - begin - R:= TRecipe(FCollection[i]); - if (R.Style <> NIL) and - ((LowerCase(R.Style.StyleLetter.Value) = LowerCase(Lett)) and - (Lowercase(R.Style.Name.Value) = Lowercase(Nm))) then - begin - Inc(Result); - - R.CalcOG; - if R.OG.Value > 1 then - SGp:= 1000 * (R.OG.Value - 1) - else - SGp:= 1000 * (R.EstOG.Value - 1); - FCommonMinMaxArray[0].AvUse:= FCommonMinMaxArray[0].AvUse + SGp; - if SGp < FCommonMinMaxArray[0].MinUse then - FCommonMinMaxArray[0].MinUse:= SGp; - if SGp > FCommonMinMaxArray[0].MaxUse then - FCommonMinMaxArray[0].MaxUse:= SGp; - - R.CalcBitterness; - bitt:= R.IBUcalc.DisplayValue; - FCommonMinMaxArray[1].AvUse:= FCommonMinMaxArray[1].AvUse + bitt; - if bitt < FCommonMinMaxArray[1].MinUse then - FCommonMinMaxArray[1].MinUse:= bitt; - if bitt > FCommonMinMaxArray[1].MaxUse then - FCommonMinMaxArray[1].MaxUse:= bitt; - -{ if SGp > 0 then x:= bitt / SGp - else x:= 0; - FCommonMinMaxArray[2].AvUse:= FCommonMinMaxArray[2].AvUse + x; - if x < FCommonMinMaxArray[2].MinUse then - FCommonMinMaxArray[2].MinUse:= x; - if x > FCommonMinMaxArray[2].MaxUse then - FCommonMinMaxArray[2].MaxUse:= x;} - - R.CalcColor; - x:= R.EstColor.DisplayValue; - FCommonMinMaxArray[2].AvUse:= FCommonMinMaxArray[2].AvUse + x; - if x < FCommonMinMaxArray[2].MinUse then - FCommonMinMaxArray[2].MinUse:= x; - if x > FCommonMinMaxArray[2].MaxUse then - FCommonMinMaxArray[2].MaxUse:= x; - end; - end; - if (High(FCollection) >= 0) then - begin - for i:= Low(FCommonMinMaxArray) to High(FCommonMinMaxArray) do - begin - if Result > 0 then - FCommonMinMaxArray[i].AvUse:= FCommonMinMaxArray[i].AvUse / Result - else - FCommonMinMaxArray[i].AvUse:= 0; - end; - end; -end; -{============================= TRecipesByStyle ================================} - -{ TStyleRec = record - Name : string; - Recipes : array of TRecipe; - end; - - TStyleLetters = record - Letter : string; - Styles : array of TStyleRec; - end;} - -Constructor TRecipesByStyle.Create(R : TRecipes); - begin - Inherited Create; - FCollection:= R; - Fill; - Sort; - end; - -Destructor TRecipesByStyle.Destroy; -begin - Empty; - Inherited; -end; - -Procedure TRecipesByStyle.SaveXML; -var Doc : TXMLDocument; - iRootNode : TDOMNode; - n, s, i : integer; -begin - try - Doc := TXMLDocument.Create; - iRootNode := Doc.CreateElement('RECIPES'); - Doc.Appendchild(iRootNode); - - for n:= Low(FStyleLetters) to High(FStyleLetters) do - begin - for s:= Low(FStyleLetters[n].Styles) to High(FStyleLetters[n].Styles) do - begin - for i:= Low(FStyleLetters[n].Styles[s].Recipes) to High(FStyleLetters[n].Styles[s].Recipes) do - FStyleLetters[n].Styles[s].Recipes[i].SaveXML(Doc, iRootNode, false); - end; - end; - - writeXMLFile(Doc, Settings.DataLocation.Value + 'recipes.xml'); - finally - Doc.Free; - end; -end; - -Procedure TRecipesByStyle.Fill; -var n, n2, s, s2, i, r : integer; - Num, Stl : string; - Rec : TRecipe; -begin - Empty; - for i:= 1 to FCollection.GetNumItems do - begin - Rec:= TRecipe(FCollection.Item[i-1]); - Num:= Rec.Style.StyleLetter.Value; - Stl:= Rec.Style.Name.Value; - n:= GetLetterByName(Num); - s:= GetStyleByName(Num, Stl); - if n < 0 then //Style Number does not exist - begin - n2:= High(FStyleLetters) + 1; - SetLength(FStyleLetters, n2 + 1); - FStyleLetters[n2].Letter:= Num; - SetLength(FStyleLetters[n2].Styles, 1); - FStyleLetters[n2].Styles[0].Name:= Stl; - SetLength(FStyleLetters[n2].Styles[0].Recipes, 1); - FStyleLetters[n2].Styles[0].Recipes[0]:= Rec; - end - else if s < 0 then //Style does not exist - begin - s2:= High(FStyleLetters[n].Styles) + 1; - SetLength(FStyleLetters[n].Styles, s2 + 1); - FStyleLetters[n].Styles[s2].Name:= Stl; - SetLength(FStyleLetters[n].Styles[s2].Recipes, 1); - FStyleLetters[n].Styles[s2].Recipes[0]:= Rec; - end - else //Both exist - begin - r:= High(FStyleLetters[n].Styles[s].Recipes) + 1; - SetLength(FStyleLetters[n].Styles[s].Recipes, r+1); - FStyleLetters[n].Styles[s].Recipes[r]:= Rec; - end; - end; -end; - -Procedure TRecipesByStyle.Empty; -var n, s, i : integer; -begin - for n:= Low(FStyleLetters) to High(FStyleLetters) do - begin - for s:= Low(FStyleLetters[n].Styles) to High(FStyleLetters[n].Styles) do - begin - for i:= Low(FStyleLetters[n].Styles[s].Recipes) to High(FStyleLetters[n].Styles[s].Recipes) do - FStyleLetters[n].Styles[s].Recipes[i]:= NIL; - SetLength(FStyleLetters[n].Styles[s].Recipes, 0); - end; - SetLength(FStyleLetters[n].Styles, 0); - end; - SetLength(FStyleLetters, 0); -end; - -Procedure TRecipesByStyle.QuickSortInStyles(var Arr : array of TRecipe); - procedure QuickSort(var A: array of TRecipe; iLo, iHi: Integer); - var Lo, Hi: Integer; - l : string; - T : TRecipe; - begin - Lo := iLo; - Hi := iHi; - l:= A[(Lo + Hi) div 2].NrRecipe.Value; - repeat - while A[Lo].NrRecipe.Value < l do Inc(Lo); - while A[Hi].NrRecipe.Value > l do Dec(Hi); - if Lo <= Hi then - begin - T := A[Lo]; - A[Lo] := A[Hi]; - A[Hi] := T; - Inc(Lo); - Dec(Hi); - end; - until Lo > Hi; - if Hi > iLo then QuickSort(A, iLo, Hi); - if Lo < iHi then QuickSort(A, Lo, iHi); - end; -begin - if High(Arr) > -1 then QuickSort(Arr, Low(Arr), High(Arr)); -end; - -Procedure TRecipesByStyle.QuickSortStyles(var Arr : array of TStyleRec); - procedure QuickSort(var A: array of TStyleRec; iLo, iHi: Integer); - var Lo, Hi: Integer; - s : string; - T : TStyleRec; - begin - Lo := iLo; - Hi := iHi; - s:= A[(Lo + Hi) div 2].Name; - repeat - while A[Lo].Name < s do Inc(Lo); - while A[Hi].Name > s do Dec(Hi); - if Lo <= Hi then - begin - T := A[Lo]; - A[Lo] := A[Hi]; - A[Hi] := T; - Inc(Lo); - Dec(Hi); - end; - until Lo > Hi; - if Hi > iLo then QuickSort(A, iLo, Hi); - if Lo < iHi then QuickSort(A, Lo, iHi); - end; -begin - if High(Arr) > -1 then QuickSort(Arr, Low(Arr), High(Arr)); -end; - -Procedure TRecipesByStyle.QuickSortLetters(var Arr : array of TStyleLetters); - procedure QuickSort(var A: array of TStyleLetters; iLo, iHi: Integer); - var Lo, Hi: Integer; - l : string; - T : TStyleLetters; - begin - Lo := iLo; - Hi := iHi; - l := A[(Lo + Hi) div 2].Letter; - repeat - while A[Lo].Letter < l do Inc(Lo); - while A[Hi].Letter > l do Dec(Hi); - if Lo <= Hi then - begin - T := A[Lo]; - A[Lo] := A[Hi]; - A[Hi] := T; - Inc(Lo); - Dec(Hi); - end; - until Lo > Hi; - if Hi > iLo then QuickSort(A, iLo, Hi); - if Lo < iHi then QuickSort(A, Lo, iHi); - end; -begin - if High(Arr) > -1 then QuickSort(Arr, Low(Arr), High(Arr)); -end; - -Procedure TRecipesByStyle.Sort; -var n, s : integer; -begin -//sort recipes in every style by recipe number - for n:= Low(FStyleLetters) to High(FStyleLetters) do - for s:= Low(FStyleLetters[n].Styles) to High(FStyleLetters[n].Styles) do - QuickSortInStyles(FStyleLetters[n].Styles[s].Recipes); - -//sort style names - for n:= Low(FStyleLetters) to High(FStyleLetters) do - QuickSortStyles(FStyleLetters[n].Styles); -//sort style letters - QuickSortLetters(FStyleLetters); -end; - -Function TRecipesByStyle.GetLetterByName(Num : string) : integer; -var n : integer; -begin - Result:= -1; - for n:= Low(FStyleLetters) to High(FStyleLetters) do - if FStyleLetters[n].Letter = Num then - begin - Result:= n; - Exit; - end; -end; - -Function TRecipesByStyle.GetStyleByName(Num, Stl : string) : integer; -var n, s : integer; -begin - Result:= -1; - n:= GetLetterByName(Num); - if n > -1 then - begin - for s:= Low(FStyleLetters[n].Styles) to High(FStyleLetters[n].Styles) do - if FStyleLetters[n].Styles[s].Name = Stl then - begin - Result:= s; - Exit; - end; - end; -end; - -Function TRecipesByStyle.GetNumStyleLetters : integer; -begin - Result:= High(FStyleLetters) + 1; -end; - -Function TRecipesByStyle.GetNumStyles(i : integer) : integer; -begin - Result:= -1; - if (i >= Low(FStyleLetters)) and (i <= High(FStyleLetters)) then - Result:= High(FStyleLetters[i].Styles) + 1; -end; - -Function TRecipesByStyle.GetStyleLetter(i : integer) : string; -begin - Result:= ''; - if (i >= Low(FStyleLetters)) and (i <= High(FStyleLetters)) then - Result:= FStyleLetters[i].Letter; -end; - -Function TRecipesByStyle.GetStyleName(n : integer; s : integer) : string; -begin - Result:= ''; - if (n >= Low(FStyleLetters)) and (n <= High(FStyleLetters)) then - if (s >= Low(FStyleLetters[n].Styles)) and (s <= High(FStyleLetters[n].Styles)) then - Result:= FStyleLetters[n].Styles[s].Name; -end; - -Function TRecipesByStyle.GetNumRecipes(n : integer; s : integer) : integer; -begin - Result:= -1; - if (n >= Low(FStyleLetters)) and (n <= High(FStyleLetters)) then - if (s >= Low(FStyleLetters[n].Styles)) and (s <= High(FStyleLetters[n].Styles)) then - Result:= High(FStyleLetters[n].Styles[s].Recipes) + 1; -end; - -Function TRecipesByStyle.GetRecipe(n : integer; s : integer; i : integer) : TRecipe; -begin - Result:= NIL; - if (n >= Low(FStyleLetters)) and (n <= High(FStyleLetters)) then - if (s >= Low(FStyleLetters[n].Styles)) and (s <= High(FStyleLetters[n].Styles)) then - if (i >= Low(FStyleLetters[n].Styles[s].Recipes)) and (i <= High(FStyleLetters[n].Styles[s].Recipes)) then - Result:= FStyleLetters[n].Styles[s].Recipes[i]; -end; - -{============================= System functions ===============================} - -Procedure CheckBeerStyle(Rec : TRecipe); -var s : string; - OK : boolean; - BS : TBeerStyle; -begin -//check if beerstyle exist in the database. -//If not, check the substitution database, otherwise ask for an alternative - s:= ''; - if Rec.Style <> NIL then - s:= Rec.Style.Name.Value; - if Beerstyles.FindByName(s) = NIL then - begin - //first, look for subtitute in the substitutions database - OK:= StyleSubs.OriginalExists(s); - if OK then - begin - s:= StyleSubs.FindSubstitute(s); - BS:= TBeerStyle(BeerStyles.FindByName(s)); - OK:= (BS <> NIL); - if not OK then - StyleSubs.RemoveOriginal(s); - end; - if OK then - Rec.Style.Assign(BS) - else - begin - FrmSelectBeerStyle:= TFrmSelectBeerStyle.Create(FrmMain); - if FrmSelectBeerStyle.Execute(s) then - begin - //put style replacement in the substitutions database - if (not StyleSubs.OriginalExists(s)) then - StyleSubs.Add(s, FrmSelectBeerStyle.BeerStyle.Name.Value); - Rec.Style.Assign(FrmSelectBeerStyle.BeerStyle); - end; - FrmSelectBeerStyle.Free; - end; - end; -end; - -Procedure CheckFermentables(Rec : TRecipe); -var s, s2 : string; - OK : boolean; - i : integer; - F : TFermentable; - am, perc, yield, color, CoarseFineDiff, moisture, DiastaticPower, Protein, - DissolvedProtein, IbuGalPerLb: double; -begin -//check if fermentable exist in the database. -//If not, check the substitution database, otherwise ask for an alternative - for i:= 0 to Rec.NumFermentables - 1 do - begin - s:= Rec.Fermentable[i].Name.Value; - s2:= Rec.Fermentable[i].Supplier.Value; - OK:= (Fermentables.FindByNameAndSupplier(s, s2) <> NIL); - if (not OK) then - begin - OK:= FermentableSubs.OriginalExists(s, s2); - if OK then - begin - FermentableSubs.FindSubstitute(s, s2, s, s2); - F:= TFermentable(Fermentables.FindByNameAndSupplier(s, s2)); - if F <> NIL then - begin - am:= Rec.Fermentable[i].Amount.Value; - perc:= Rec.Fermentable[i].Percentage.Value; - Yield:= Rec.Fermentable[i].Yield.Value; - Color:= Rec.Fermentable[i].Color.Value; - CoarseFineDiff:= Rec.Fermentable[i].CoarseFineDiff.Value; - Moisture:= Rec.Fermentable[i].Moisture.Value; - DiastaticPower:= Rec.Fermentable[i].DiastaticPower.Value; - Protein:= Rec.Fermentable[i].Protein.Value; - DissolvedProtein:= Rec.Fermentable[i].DissolvedProtein.Value; - IbuGalPerLb:= Rec.Fermentable[i].IbuGalPerLb.Value; - - Rec.Fermentable[i].Assign(F); - Rec.Fermentable[i].Amount.Value:= am; - Rec.Fermentable[i].Percentage.Value:= perc; - Rec.Fermentable[i].Yield.Value:= Yield; - Rec.Fermentable[i].Color.Value:= Color; - Rec.Fermentable[i].CoarseFineDiff.Value:= CoarseFineDiff; - Rec.Fermentable[i].Moisture.Value:= Moisture; - Rec.Fermentable[i].DiastaticPower.Value:= DiastaticPower; - Rec.Fermentable[i].Protein.Value:= Protein; - Rec.Fermentable[i].DissolvedProtein.Value:= DissolvedProtein; - Rec.Fermentable[i].IbuGalPerLb.Value:= IbuGalPerLb; - end - else - FermentableSubs.RemoveOriginal(s, s2); - end; - end; - end; -end; - -Procedure CheckYeasts(Rec : TRecipe); -var s, s2 : string; - OK : boolean; - i : integer; - Y : TYeast; - am : double; -begin -//check if beerstyle exist in the database. -//If not, check the substitution database, otherwise ask for an alternative - for i:= 0 to Rec.NumYeasts - 1 do - begin - s:= Rec.Yeast[i].Name.Value; - s2:= Rec.Yeast[i].Laboratory.Value; - OK:= (Yeasts.FindByNameAndLaboratory(s, s2) <> NIL); - if (not OK) then - begin - OK:= YeastSubs.OriginalExists(s, s2); - if OK then - begin - YeastSubs.FindSubstitute(s, s2, s, s2); - Y:= TYeast(Yeasts.FindByNameAndLaboratory(s, s2)); - if Y <> NIL then - begin - am:= Rec.Yeast[i].Amount.Value; - Rec.Yeast[i].Assign(Y); - Rec.Yeast[i].Amount.Value:= am; - end - else - YeastSubs.RemoveOriginal(s, s2); - end; - end; - end; -end; - -Procedure Backup; - function CheckCopyFile(sd, dd, fn : string) : boolean; - begin - Result:= false; - if FileExists(sd + fn) then - result:= CopyFile(sd + fn, dd + fn); - end; -var sourcedata, destdata : string; - year, month, day : word; - i : integer; - SearchResult : TSearchRec; - SL : TStringList; -begin - sourcedata:= Settings.DataLocation.Value; - DecodeDate(now, year, month, day); - destdata:= BHFolder + 'backup-' + IntToStr(Year) + '-' + IntToStr(Month) + '-' - + IntToStr(day) + Slash; - CreateDir(destdata); - CheckCopyFile(sourcedata, destdata, 'settings.xml'); - CheckCopyFile(sourcedata, destdata, 'fermentables.xml'); - CheckCopyFile(sourcedata, destdata, 'hops.xml'); - CheckCopyFile(sourcedata, destdata, 'yeasts.xml'); - CheckCopyFile(sourcedata, destdata, 'miscs.xml'); - CheckCopyFile(sourcedata, destdata, 'mashs.xml'); - CheckCopyFile(sourcedata, destdata, 'waters.xml'); - CheckCopyFile(sourcedata, destdata, 'styles.xml'); - CheckCopyFile(sourcedata, destdata, 'equipments.xml'); - CheckCopyFile(sourcedata, destdata, 'recipes.xml'); - CheckCopyFile(sourcedata, destdata, 'brews.xml'); - CheckCopyFile(sourcedata, destdata, 'cloud.xml'); - CheckCopyFile(sourcedata, destdata, 'stylesubs.xml'); - CheckCopyFile(sourcedata, destdata, 'fermentablesubs.xml'); - CheckCopyFile(sourcedata, destdata, 'yeastsubs.xml'); - CheckCopyFile(sourcedata, destdata, 'neuralnetworks.xml'); - SL:= FindAllFiles(sourcedata, '*.nn', false); - for i:= 0 to SL.Count - 1 do - CheckCopyFile(sourcedata, destdata, ExtractFileName(SL.Strings[i])); - FreeAndNIL(SL); - // CheckCopyFile(sourcedata, destdata, 'styles-BJCP.xml'); - // CheckCopyFile(sourcedata, destdata, 'White Labs.xml'); - CheckCopyFile(sourcedata, destdata, 'logo.png'); -end; - -Procedure Restore(sourcedata : string); - function CheckCopyFile(sd, dd, fn : string) : boolean; - begin - Result:= false; - if FileExists(sd + fn) then - result:= CopyFile(sd + fn, dd + fn); - end; -var destdata : string; - year, month, day : word; - i : integer; - SL : TStringList; -begin - destdata:= Settings.DataLocation.Value; - if not DirectoryExists(destdata) then CreateDir(destdata); - CheckCopyFile(sourcedata, destdata, 'settings.xml'); - CheckCopyFile(sourcedata, destdata, 'fermentables.xml'); - CheckCopyFile(sourcedata, destdata, 'hops.xml'); - CheckCopyFile(sourcedata, destdata, 'yeasts.xml'); - CheckCopyFile(sourcedata, destdata, 'miscs.xml'); - CheckCopyFile(sourcedata, destdata, 'mashs.xml'); - CheckCopyFile(sourcedata, destdata, 'waters.xml'); - CheckCopyFile(sourcedata, destdata, 'styles.xml'); - CheckCopyFile(sourcedata, destdata, 'equipments.xml'); - CheckCopyFile(sourcedata, destdata, 'recipes.xml'); - CheckCopyFile(sourcedata, destdata, 'brews.xml'); - CheckCopyFile(sourcedata, destdata, 'cloud.xml'); - CheckCopyFile(sourcedata, destdata, 'stylesubs.xml'); - CheckCopyFile(sourcedata, destdata, 'fermentablesubs.xml'); - CheckCopyFile(sourcedata, destdata, 'yeastsubs.xml'); - CheckCopyFile(sourcedata, destdata, 'neuralnetworks.xml'); - SL:= FindAllFiles(sourcedata, '*.nn', false); - for i:= 0 to SL.Count - 1 do - CheckCopyFile(sourcedata, destdata, ExtractFileName(SL.Strings[i])); - FreeAndNIL(SL); - -// CheckCopyFile(sourcedata, destdata, 'styles-BJCP.xml'); -// CheckCopyFile(sourcedata, destdata, 'White Labs.xml'); - CheckCopyFile(sourcedata, destdata, 'logo.png'); - - Fermentables.ReadXML; - Hops.ReadXML; - Miscs.ReadXML; - Yeasts.ReadXML; - Waters.ReadXML; - Equipments.ReadXML; - Beerstyles.ReadXML; - Mashs.ReadXML; - Application.ProcessMessages; - Recipes.ReadXML; - Application.ProcessMessages; - Brews.ReadXML; -end; - -Procedure CheckDataFolder; - function CheckFile(sd, dd, fn : string) : boolean; - var destOK, sourceOK : boolean; - begin - Result:= false; - destOK:= FileExists(dd + fn); - sourceOK:= FileExists('"' + sd + fn + '"'); - if (not destOK) and (sourceOK) then - try - result:= CopyFile(sd + fn, dd + fn); - except - ShowMessage('Fout bij aanmaken ' + dd + fn + '.'); - Halt; - end - else if (not destOK) and (not sourceOK) then - ShowMessage('Fout: ' + sd + fn + ' niet gevonden.'); - end; -var sourcedata, destdata, sourcesounds, destsounds : string; -begin - {$ifdef linux} - sourcedata:= '/usr/share/brewbuddy/'; - {$endif} - {$ifdef darwin} - sourcedata:= ProgramDirectory() + 'BrewBuddy.app/Contents/Resources/'; - {$endif} - {$ifdef Windows} - sourcedata:= ExtractFilePath(Application.ExeName) + 'brewbuddy\'; - if OnUSB then BHFolder:= DriveLetter + '\brewbuddy\brewbuddy\'; - log('Checkdatafolder: BHFolder = ' + BHFolder); - {$endif} - destdata:= BHFolder; - if not DirectoryExists(BHFolder) then - CreateDir(BHFolder); - if not DirectoryExists(SoundFolder) then - CreateDir(SoundFolder); - sourcesounds:= sourcedata + 'sounds' + Slash; - destsounds:= SoundFolder; - Settings := TBSettings.Create; - if CheckFile(sourcedata, destdata, 'settings.xml') then - begin - Settings.DataLocation.Value:= BHFolder; - end - else - Settings.Read; - log('Settings.Datalocation = ' + Settings.DataLocation.Value); - - IF OnUSB then - begin - Settings.DataLocation.Value:= BHFolder; - destdata:= BHFolder; - end - else if (Settings.DataLocation.Value <> '') and (not OnUSB) then - destdata:= Settings.DataLocation.Value - else - destdata:= BHFolder; - log('Settings.Datalocation = ' + Settings.DataLocation.Value); - if not DirectoryExists(destdata) then - CreateDir(destdata); - - if CheckFile(sourcedata, destdata, 'equipments.xml') then - ShowMessage('Data niet gevonden. Nieuwe databank wordt gemaakt.'); - CheckFile(sourcedata, destdata, 'fermentables.xml'); - CheckFile(sourcedata, destdata, 'hops.xml'); - CheckFile(sourcedata, destdata, 'mashs.xml'); - CheckFile(sourcedata, destdata, 'miscs.xml'); - CheckFile(sourcedata, destdata, 'recipes.xml'); - CheckFile(sourcedata, destdata, 'styles-BJCP.xml'); - CheckFile(sourcedata, destdata, 'styles.xml'); - CheckFile(sourcedata, destdata, 'waters.xml'); -// CheckFile(sourcedata, destdata, 'White Labs.xml'); - CheckFile(sourcedata, destdata, 'yeasts.xml'); - CheckFile(sourcedata, destdata, 'logo.png'); - {$ifdef Windows} - CheckFile(sourcedata, destdata, 'Introductie BrewBuddy Sassy Saison.pdf'); - {$endif} - {$ifdef Darwin} - CheckFile(sourcedata, destdata, 'Introductie BrewBuddy Sassy Saison.pdf'); - {$endif} - {$ifdef linux} - CheckFile('/usr/share/doc/brewbuddy/', destdata, 'Introductie BrewBuddy Sassy Saison.pdf'); - {$endif} - CheckFile(sourcesounds, destsounds, 'alarm.wav'); -// CheckFile(sourcesounds, destsounds, 'alarm02.wav'); - CheckFile(sourcesounds, destsounds, 'end.wav'); - CheckFile(sourcesounds, destsounds, 'warning.wav'); - CheckFile(sourcesounds, destsounds, 'welcome.wav'); -end; - -Procedure Reload; -begin - Fermentables.Free; - Hops.Free; - Miscs.Free; - Yeasts.Free; - Waters.Free; - Equipments.Free; - Beerstyles.Free; - Mashs.Free; - Recipes.Free; - Brews.Free; - Settings.Free; - Settings := TBSettings.Create; - Settings.Read; - - CheckDataFolder; - - Fermentables:= TFermentables.Create; - Hops:= THops.Create; - Miscs:= TMiscs.Create; - Yeasts:= TYeasts.Create; - Waters:= TWaters.Create; - Equipments:= TEquipments.Create; - Beerstyles:= TBeerstyles.Create; - Mashs:= TMashs.Create; - Recipes:= TRecipes.Create; - - Brews:= TRecipes.Create; - Brews.FileName:= 'brews.xml'; - - loc:= Settings.DataLocation.Value; - if (loc = '') or OnUSB then loc:= BHFolder; - if InitializeHD('fermentables.xml', loc) then - begin - Settings.DataLocation.Value:= loc; - Fermentables.ReadXML; - Hops.ReadXML; - Miscs.ReadXML; - Yeasts.ReadXML; - Waters.ReadXML; - Equipments.ReadXML; - Beerstyles.ReadXML; - Mashs.ReadXML; - Application.ProcessMessages; - Recipes.ReadXML; - Recipes.CheckAutoNrs; - Application.ProcessMessages; - Brews.ReadXML; - Brews.CheckAutoNrs; - - CheckSalts; - end - else - ShowMessage('Databestanden niet gevonden'); -end; - -Procedure ChangeDatabaseLocation(source, destination : string; copy, deleteold : boolean); - function CheckCopyFile(sd, dd, fn : string) : boolean; - begin - Result:= false; - if FileExists(sd + fn) then - result:= CopyFile(sd + fn, dd + fn); - end; -var SearchResult : TSearchRec; - i : integer; - SL : TStringList; - StylesN, FermN, HopN, MiscN, YeastN, WaterN, sourcedata : string; -begin - {$ifdef UNIX} - destination:= destination + '/'; - {$else} - destination:= destination + '\'; - {$endif} - Settings.DataLocation.Value:= destination; - - if not copy then - begin - StylesN:= destination + 'styles.xml'; - FermN:= destination + 'fermentables.xml'; - HopN:= destination + 'hops.xml'; - MiscN:= destination + 'miscs.xml'; - YeastN:= destination + 'yeasts.xml'; - WaterN:= destination + 'waters.xml'; - if FileExists(StylesN) and FileExists(FermN) and FileExists(HopN) and - FileExists(MiscN) and FileExists(YeastN) and FileExists(WaterN) then - begin - Brews.ReadXML; - Equipments.ReadXML; - Fermentables.ReadXML; - Hops.ReadXML; - Mashs.ReadXML; - Miscs.ReadXML; - Recipes.ReadXML; - Beerstyles.ReadXML; - Waters.ReadXML; - Yeasts.ReadXML; - StyleSubs.ReadXML; - FermentableSubs.ReadXML; - YeastSubs.ReadXML; - BHNNs.ReadXML; - end - else //copy previous database to new location, but clear brews - begin - {$ifdef linux} - sourcedata:= '/usr/share/brewbuddy/'; - {$endif} - {$ifdef darwin} - sourcedata:= '/usr/local/share/brewbuddy/'; - {$endif} - {$ifdef Windows} - sourcedata:= ExtractFilePath(Application.ExeName) + 'brewbuddy\'; - if OnUSB then BHFolder:= DriveLetter + '\brewbuddy\brewbuddy\' - else BHFolder:= destination; - {$endif} - - Equipments.SaveXML; - Fermentables.SaveXML; - Hops.SaveXML; - Mashs.SaveXML; - Miscs.SaveXML; - Recipes.SaveXML; - Beerstyles.SaveXML; - Waters.SaveXML; - Yeasts.SaveXML; - StyleSubs.SaveXML; - FermentableSubs.SaveXML; - YeastSubs.SaveXML; - BHNNs.SaveXML; - SL:= FindAllFiles(source, '*.nn', false); - for i:= 0 to SL.Count - 1 do - CheckCopyFile(source, destination, ExtractFileName(SL.Strings[i])); - FreeAndNIL(SL); - Brews.FreeCollection; - CheckCopyFile(source, destination, 'Introductie BrewBuddy Sassy Saison.pdf'); - CheckCopyFile(source, destination, 'styles-BJCP.xml'); - CheckCopyFile(source, destination, 'logo.png'); - CheckDataFolder; - end; - - //delete files in old directory - if deleteold then - begin - DeleteFile(PChar(source + 'brews.xml')); - DeleteFile(PChar(source + 'equipments.xml')); - DeleteFile(PChar(source + 'fermentables.xml')); - DeleteFile(PChar(source + 'hops.xml')); - DeleteFile(PChar(source + 'mashs.xml')); - DeleteFile(PChar(source + 'miscs.xml')); - DeleteFile(PChar(source + 'recipes.xml')); - DeleteFile(PChar(source + 'styles.xml')); - DeleteFile(PChar(source + 'waters.xml')); - DeleteFile(PChar(source + 'yeasts.xml')); - DeleteFile(PChar(source + 'stylesubs.xml')); - DeleteFile(PChar(source + 'fermentablesubs.xml')); - DeleteFile(PChar(source + 'yeastsubs.xml')); - DeleteFile(PChar(source + 'neuralnetworks.xml')); - SL:= FindAllFiles(source, '*.nn', false); - for i:= 0 to SL.Count - 1 do - DeleteFile(PChar(SL.Strings[i])); - FreeAndNIL(SL); - DeleteFile(PChar(source + 'Introductie BrewBuddy Sassy Saison.pdf')); - DeleteFile(PChar(source + 'styles-BJCP.xml')); - DeleteFile(PChar(source + 'logo.png')); - end; - FrmMain.cbBrewsSortChange(FrmMain); - FrmMain.cbRecipesSortChange(FrmMain); - end - else //copy from old directory and overwrite files in new directory - begin - Brews.SaveXML; - Equipments.SaveXML; - Fermentables.SaveXML; - Hops.SaveXML; - Mashs.SaveXML; - Miscs.SaveXML; - Recipes.SaveXML; - Beerstyles.SaveXML; - Waters.SaveXML; - Yeasts.SaveXML; - StyleSubs.SaveXML; - FermentableSubs.SaveXML; - YeastSubs.SaveXML; - BHNNs.SaveXML; - SL:= FindAllFiles(source, '*.nn', false); - for i:= 0 to SL.Count - 1 do - CheckCopyFile(source, destination, ExtractFileName(SL.Strings[i])); - FreeAndNIL(SL); - - //delete files in old directory - if deleteold then - begin - DeleteFile(PChar(source + 'brews.xml')); - DeleteFile(PChar(source + 'equipments.xml')); - DeleteFile(PChar(source + 'fermentables.xml')); - DeleteFile(PChar(source + 'hops.xml')); - DeleteFile(PChar(source + 'mashs.xml')); - DeleteFile(PChar(source + 'miscs.xml')); - DeleteFile(PChar(source + 'recipes.xml')); - DeleteFile(PChar(source + 'styles.xml')); - DeleteFile(PChar(source + 'waters.xml')); - DeleteFile(PChar(source + 'yeasts.xml')); - DeleteFile(PChar(source + 'stylesubs.xml')); - DeleteFile(PChar(source + 'fermentablesubs.xml')); - DeleteFile(PChar(source + 'yeastsubs.xml')); - DeleteFile(PChar(source + 'neuralnetworks.xml')); - SL:= FindAllFiles(source, '*.nn', false); - for i:= 0 to SL.Count - 1 do - DeleteFile(PChar(SL.Strings[i])); - FreeAndNIL(SL); - end; - end; - Settings.Save; -end; - -{====================== Initialization and Finalization =======================} - -Initialization - if DoLog then slLog:= TStringList.Create - else slLog:= NIL; - Screen.Cursor:= crHourglass; - - ExecFolder:= Application.Location; - log('ExecFolder = ' + ExecFolder); - OnUSB:= false; - {$ifdef linux} - {DriveLetter:= LeftStr(ExecFolder, 6); - if DriveLetter = '/media' then - begin - BHFolder:= ExecFolder; - end - else - begin} - BHFolder:= GetUserDir + '.brewbuddy/'; - // DataFolder:= GetUserDir + '.brewbuddy/'; - { end;} - SoundFolder:= BHFolder + 'sounds/'; - IconFolder:= BHFolder + 'icons/'; - Slash:= '/'; - {$endif} - {$ifdef darwin} - BHFolder:= GetUserDir + '.brewbuddy/'; -// DataFolder:= GetUserDir + '.brewbuddy/'; - SoundFolder:= BHFolder + 'sounds/'; - IconFolder:= BHFolder + 'icons/'; - Slash:= '/'; - {$endif} - {$ifdef windows} - DriveLetter:= LeftStr(ExecFolder, 2); - if GetDriveType(PChar(DriveLetter)) = DRIVE_REMOVABLE then - begin - Log('Gestart van USB'); - BHFolder:= DriveLetter + '\brewbuddy\brewbuddy\'; - OnUSB:= TRUE; - end - else - begin - Log('Gestart van harddisk'); - BHFolder:= GetWindowsSpecialDir(CSIDL_PERSONAL); //GetUserDir - if FileExists(BHFolder + 'My Documents\brewbuddy\settings.xml') then - BHFolder:= BHFolder + 'My Documents\brewbuddy\' - else - BHFolder:= BHFolder + 'brewbuddy\'; - end; - log('BHFolder = ' + BHFolder); - SoundFolder:= BHFolder + 'sounds\'; - IconFolder:= BHFolder + 'icons\'; - Slash:= '\'; - {$endif} - - CheckDataFolder; //settings are read here - - Fermentables:= TFermentables.Create; - Hops:= THops.Create; - Miscs:= TMiscs.Create; - Yeasts:= TYeasts.Create; - Waters:= TWaters.Create; - Equipments:= TEquipments.Create; - Beerstyles:= TBeerstyles.Create; - Mashs:= TMashs.Create; - Recipes:= TRecipes.Create; - - Brews:= TRecipes.Create; - Brews.FileName:= 'brews.xml'; - - BHNNs:= TBHNNs.Create; - - loc:= Settings.DataLocation.Value; - if loc = '' then loc:= BHFolder; - if OnUSB then //datalocation is also on the USB - loc:= BHFolder; - if InitializeHD('fermentables.xml', loc) then - begin - if not OnUSB then Settings.DataLocation.Value:= loc; - - BHCloud:= TBHCloud.Create; -// BHCloud.ReadCloud; - - Fermentables.ReadXML; - Hops.ReadXML; - Miscs.ReadXML; - Yeasts.ReadXML; - Waters.ReadXML; - Equipments.ReadXML; - Beerstyles.ReadXML; - Mashs.ReadXML; - Application.ProcessMessages; - Recipes.ReadXML; - Recipes.CheckAutoNrs; - Application.ProcessMessages; - Brews.ReadXML; - Brews.CheckAutoNrs; - - StyleSubs.ReadXML; - FermentableSubs.ReadXML; - YeastSubs.ReadXML; - - BHNNs.ReadXML; - - CheckSalts; - end - else - ShowMessage('Databestanden niet gevonden'); -// Equipments.CalcEfficiencyRegressionFactors; -// Equipments.CalcAttenuationRegressionFactors; - - { SetLength(Arr, 8); - Arr[0]:= 4; - Arr[1]:= 56; - Arr[2]:= 45; - Arr[3]:= 19; - Arr[4]:= 22; - Arr[5]:= 23; - Arr[6]:= 9; - Arr[7]:= 11; - Brews.ExportToCSV(Arr); - SetLength(Arr, 0);} - - Screen.Cursor:= crDefault; - -Finalization - if OnUSB then - begin - Settings.DataLocation.Value:= ''; - Settings.Save; - end; - Log(''); -// Log('CONTAINERS'); - FreeAndNIL(BHCloud); -// Log('BHCloud afgesloten'); - StyleSubs.SaveXML; -// Log('StyleSubs opgeslagen'); - FermentableSubs.SaveXML; -// Log('FermentableSubs opgeslagen'); - YeastSubs.SaveXML; -// Log('YeastSubs opgeslagen'); - FreeAndNIL(StyleSubs); -// Log('StyleSubs afgesloten'); - FreeAndNIL(FermentableSubs); -// Log('FermentableSubs afgesloten'); - FreeAndNIL(YeastSubs); -// Log('YeastSubs afgesloten'); - - FreeAndNIL(Fermentables); -// Log('Fermentables afgesloten'); - FreeAndNIL(Hops); -// Log('Hops afgesloten'); - FreeAndNIL(Miscs); -// Log('Miscs afgesloten'); - FreeAndNIL(Yeasts); -// Log('Yeasts afgesloten'); - FreeAndNIL(Waters); -// Log('Waters afgesloten'); - FreeAndNIL(Equipments); -// Log('Equipments afgesloten'); - FreeAndNIL(Beerstyles); -// Log('Beerstyles afgesloten'); - FreeAndNIL(Mashs); -// Log('Mashs afgesloten'); - FreeAndNIL(Recipes); -// Log('Recipes afgesloten'); - FreeAndNIL(Brews); -// Log('Brews afgesloten'); - FreeAndNIL(BHNNs); -// Log('BHNNs afgesloten'); - - Settings.Save; - Log('Settings opgeslagen'); - FreeAndNIL(Settings); -// Log('Settings afgesloten'); - - if DoLog then FreeAndNIL(slLog); -end. - diff --git a/Source/Units/backup/fann.pas b/Source/Units/backup/fann.pas deleted file mode 100644 index 2504568a..00000000 --- a/Source/Units/backup/fann.pas +++ /dev/null @@ -1,1228 +0,0 @@ -unit FANN; -{$mode delphi} -interface -{******************************************************* - - Only Delphi 6 and above supports variable arguments - functions. - If you are using a older version of Delphi comment the - VARIABLE_ARGUMENTS directive. - If you disable the VARIABLE_ARGUMENTS directive the - following functions will not be available: - fann_create_shortcut - fann_create_sparse - fann_create_standard - -********************************************************} - -{$DEFINE VARIABLE_ARGUMENTS} - -{******************************************************* - - If you want to use Fixed Fann or Double Fann please - uncomment the corresponding definition. - As default fann.pas uses the fannfloat dll. - -********************************************************} -//{$DEFINE FIXEDFANN} //Uncomment for fixed fann -{$DEFINE DOUBLEFANN} //Uncomment for double fann - - - - -{$ifdef windows} -{$IF Defined(FIXEDFANN)} -const DLL_FILE = 'fannfixed.dll'; -{$ELSEIF Defined(DOUBLEFANN)} -const DLL_FILE = 'fanndouble.dll'; -{$ELSE} -const DLL_FILE = 'fannfloat.dll'; -{$IFEND} -{$endif} -{$ifdef linux} -{$IF Defined(FIXEDFANN)} -const DLL_FILE = 'libfixedfann.so'; -{$ELSEIF Defined(DOUBLEFANN)} -const DLL_FILE = 'libdoublefann.so'; -{$ELSE} -const DLL_FILE = 'libfloatfann.so'; -{$IFEND} -{$endif} -{$ifdef darwin} -{$IF Defined(FIXEDFANN)} -const DLL_FILE = 'libfixedfann.2.2.0.dylib'; -{$ELSEIF Defined(DOUBLEFANN)} -const DLL_FILE = '/usr/local/lib/libdoublefann.2.2.0.dylib'; -{$ELSE} -const DLL_FILE = 'libfloatfann.2.2.0.dylib'; -{$IFEND} -{$endif} - - -type - - {$IF Defined(FIXEDFANN)} - fann_type = integer; - {$ELSEIF Defined(DOUBLEFANN)} - fann_type = double; - {$ELSE} - fann_type = single; - {$IFEND} - - - PFann_Type = ^fann_type; - - PPFann_Type = ^pfann_type; - - Fann_Type_Array = array [0..65535] of fann_type; - - PFann_Type_Array = ^Fann_type_array; - - PPFann_Type_Array = array [0..65535] of ^Fann_Type_Array; - - - - - (* MICROSOFT VC++ STDIO'S FILE DEFINITION*) - _iobuf = packed record - _ptr: Pchar; - _cnt: integer; - _base: Pchar; - _flag: integer; - _file: integer; - _charbuf: integer; - _bufsiz: integer; - _tmpfname: Pchar; - end; - - - PFile = ^TFile; - TFile = _iobuf; - - - PPFann_Neuron = ^PFann_Neuron; - PFann_Neuron = ^TFann_Neuron; - TFann_Neuron = packed record - first_con: Cardinal; - last_con: Cardinal; - sum: fann_type; - value: fann_type; - activation_steepness: fann_type; - activation_function: Cardinal; //enum - end; - - - PFann_Layer = ^TFann_Layer; - TFann_Layer = packed record - first_neuron: PFann_Neuron; - last_neuron: PFann_Neuron; - end; - - PFann = ^TFann; - TFann = packed record - errno_f: cardinal; - error_log: PFile; - errstr: Pchar; - - learning_rate: single; - learning_momentum: single; - connection_rate: single; - - network_type: Cardinal; //ENUM - - first_layer: PFann_Layer; - last_layer: PFann_Layer; - - total_neurons: cardinal; - num_input: cardinal; - num_output: cardinal; - - weights: Pfann_type; - - connections: PPFann_Neuron; - - train_errors: Pfann_type; - - training_algorithm: cardinal; //ENUM - - - {$IFDEF FIXEDFANN} - decimal_point: cardinal; - multiplier: cardinal; - - sigmoid_results: array [0..5] of fann_type; - sigmoid_values: array [0..5] of fann_type; - symmetric_results: array [0..5] of fann_type; - symmetric_values: array [0..5] of fann_type; - - {$ENDIF} - - total_connections: cardinal; - output: pfann_type; - - num_MSE: cardinal; - MSE_value: single; - - num_bit_fail: cardinal; - bit_fail_limit: fann_type; - - train_error_function: cardinal;//enum - train_stop_function: cardinal; //enum - - callback: Pointer; //TFANN_CALLBACK - - user_data: Pointer; - - cascade_output_change_fraction: single; - cascade_output_stagnation_epochs: Cardinal; - cascade_candidate_change_fraction: single; - cascade_candidate_stagnation_epochs: Cardinal; - cascade_best_candidate: Cardinal; - - cascade_candidate_limit: fann_type; - cascade_weight_multiplier: fann_type; - - cascade_max_out_epochs: Cardinal; - cascade_max_cand_epochs: Cardinal; - - cascade_activation_functions: PCardinal; - cascade_activation_functions_count: Cardinal; - - cascade_activation_steepnesses: PFann_Type; - - cascade_activation_steepnesses_count: Cardinal; - cascade_num_candidate_groups: Cardinal; - - cascade_candidate_scores: PFann_Type; - - total_neurons_allocated: Cardinal; - total_connections_allocated: Cardinal; - - - - quickprop_decay: single; - quickprop_mu: single; - - rprop_increase_factor: single; - rprop_decrease_factor: single; - - rprop_delta_min: single; - rprop_delta_max: single; - - rprop_delta_zero: single; - - train_slopes: pfann_type; - - prev_steps: pfann_type; - - prev_train_slopes: pfann_type; - - prev_weights_deltas: pfann_type; - - {$IFNDEF FIXEDFANN} - scale_mean_in: psingle; - scale_deviation_in: psingle; - scale_new_min_in: psingle; - scale_factor_in: psingle; - scale_mean_out: psingle; - scale_deviation_out: psingle; - scale_new_min_out: psingle; - scale_factor_out: psingle; - - {$ENDIF} - end; - - PFann_Train_Data = ^TFann_Train_Data; - TFann_Train_Data = packed record - errno_f: cardinal; - erro_log: PFile; - errstr: Pchar; - num_data: cardinal; - num_input: cardinal; - num_ouput: cardinal; - input: PPFann_Type_Array; - output: PPFann_Type_Array; - end; - - PFann_Connection = ^TFann_Connection; - TFann_Connection = packed record - from_neuron: Cardinal; - to_neuron: Cardinal; - weight: fann_type; - end; - - PFann_Error = ^TFann_Error; - TFann_Error = packed record - errno_f: Cardinal; //Enum - error_log: PFile; - errstr: PChar; - end; - - - //_Fann_Train = - const - - FANN_TRAIN_INCREMENTAL = 0; - FANN_TRAIN_BATCH = 1; - FANN_TRAIN_RPROP = 2; - FANN_TRAIN_QUICKPROP = 3; - - - //_Fann_Error_Func = - - FANN_ERRORFUNC_LINEAR = 0; - FANN_ERRORFUNC_TANH = 1; - - - //_Fann_Activation_Func = - FANN_LINEAR = 0; - FANN_THRESHOLD = 1; - FANN_THRESHOLD_SYMMETRIC = 2; - FANN_SIGMOID = 3; - FANN_SIGMOID_STEPWISE = 4; - FANN_SIGMOID_SYMMETRIC = 5; - FANN_SIGMOID_SYMMETRIC_STEPWISE = 6; - FANN_GAUSSIAN = 7; - FANN_GAUSSIAN_SYMMETRIC = 8; - FANN_GAUSSIAN_STEPWISE = 9; - FANN_ELLIOT = 10; - FANN_ELLIOT_SYMMETRIC = 11; - FANN_LINEAR_PIECE = 12; - FANN_LINEAR_PIECE_SYMMETRIC = 13; - FANN_SIN_SYMMETRIC = 14; - FANN_COS_SYMMETRIC = 15; - FANN_SIN = 16; - FANN_COS = 17; - - - //_Fann_ErroNo = - FANN_E_NO_ERROR = 0; - FANN_E_CANT_OPEN_CONFIG_R = 1; - FANN_E_CANT_OPEN_CONFIG_W = 2; - FANN_E_WRONG_CONFIG_VERSION = 3; - FANN_E_CANT_READ_CONFIG = 4; - FANN_E_CANT_READ_NEURON = 5; - FANN_E_CANT_READ_CONNECTIONS = 6; - FANN_E_WRONG_NUM_CONNECTIONS = 7; - FANN_E_CANT_OPEN_TD_W = 8; - FANN_E_CANT_OPEN_TD_R = 9; - FANN_E_CANT_READ_TD = 10; - FANN_E_CANT_ALLOCATE_MEM = 11; - FANN_E_CANT_TRAIN_ACTIVATION = 12; - FANN_E_CANT_USE_ACTIVATION = 13; - FANN_E_TRAIN_DATA_MISMATCH = 14; - FANN_E_CANT_USE_TRAIN_ALG = 15; - FANN_E_TRAIN_DATA_SUBSET = 16; - FANN_E_INDEX_OUT_OF_BOUND = 17; - FANN_E_SCALE_NOT_PRESENT = 18; - - - //_Fann_Stop_Func = - - FANN_STOPFUNC_MSE = 0; - FANN_STOPFUNC_BIT = 1; - - //_Fann_Net_Type = - FANN_NETTYPE_LAYER = 0; - FANN_NETTYPE_SHORTCUT = 1; - - type - - TFann_CallBack = function(Ann: PFann; - train: PFann_Train_Data; - max_epochs: Cardinal; - epochs_between_reports: cardinal; - desired_error: single; - epochs: cardinal): integer; cdecl; - - TUser_Function = procedure(num: Cardinal; - num_input: Cardinal; - num_output: cardinal; - input: PFann_Type; - output: PFann_Type); cdecl; - - - - -var - FANN_ERRORFUNC_NAMES: array [0..1] of string = ( - 'FANN_ERRORFUNC_LINEAR', - 'FANN_ERRORFUNC_TANH' - ); - - FANN_TRAIN_NAMES: array [0..3] of string = - ( - 'FANN_TRAIN_INCREMENTAL', - 'FANN_TRAIN_BATCH', - 'FANN_TRAIN_RPROP', - 'FANN_TRAIN_QUICKPROP' - ); - - FANN_ACTIVATIONFUNC_NAMES: array [0..17] of string = - ( - 'FANN_LINEAR', - 'FANN_THRESHOLD', - 'FANN_THRESHOLD_SYMMETRIC', - 'FANN_SIGMOID', - 'FANN_SIGMOID_STEPWISE', - 'FANN_SIGMOID_SYMMETRIC', - 'FANN_SIGMOID_SYMMETRIC_STEPWISE', - 'FANN_GAUSSIAN', - 'FANN_GAUSSIAN_SYMMETRIC', - 'FANN_GAUSSIAN_STEPWISE', - 'FANN_ELLIOT', - 'FANN_ELLIOT_SYMMETRIC', - 'FANN_LINEAR_PIECE', - 'FANN_LINEAR_PIECE_SYMMETRIC', - 'FANN_SIN_SYMMETRIC', - 'FANN_COS_SYMMETRIC', - 'FANN_SIN', - 'FANN_COS' - ); - - FANN_STOPFUNC_NAMES: array [0..1] of string = - ( - 'FANN_STOPFUNC_MSE', - 'FANN_STOPFUNC_BIT' - ); - - FANN_NETTYPE_NAMES: array [0..1] of string = - ( - 'FANN_NETTYPE_LAYER', - 'FANN_NETTYPE_SHORTCUT' - ); - - - //DECLARATIONS FROM FANN.H - - {$IFDEF VARIABLE_ARGUMENTS} - - { - - ATTENTION! - If your compilation breaks here maybe you are using a version of Delphi - prior to 6. In this case you should comment the VARIABLE_ARGUMENTS define - at the beginning of this file and live without this functions! - - } - function fann_create_standard(num_layers: Cardinal): PFann; cdecl; varargs; - - function fann_create_sparse(connection_rate: single; num_layers: Cardinal): PFann; cdecl; varargs; - - function fann_create_shortcut(connection_rate: single): PFann; cdecl; varargs; - - - {$ENDIF} - - - function fann_create_standard_array(num_layers: Cardinal; const layers: PCardinal): PFann; cdecl; - - function fann_create_sparse_array(connection_rate: single; num_layers: Cardinal; const layers: PCardinal): PFann; cdecl; - - function fann_create_shortcut_array(num_layers: cardinal;const layers: Pcardinal): PFann; cdecl; - - - procedure fann_destroy(Ann: PFann); cdecl; - - - function fann_run(ann: PFann; input: PFann_Type): Pfann_type_array; cdecl; - - - procedure fann_randomize_weights(Ann: PFann; Min_weight: fann_type; Max_weight: fann_type); cdecl; - - procedure fann_init_weights(Ann: PFann; train_data: PFann_Train_Data); cdecl; - - - procedure fann_print_connections(ann: PFann);cdecl; - - procedure fann_print_parameters(ann: PFann);cdecl; - - - function fann_get_num_input(Ann: PFann): cardinal;cdecl; - - function fann_get_num_output(Ann: PFann): cardinal;cdecl; - - function fann_get_total_neurons(Ann: PFann): cardinal; cdecl; - - function fann_get_total_connections(Ann: PFann): cardinal; cdecl; - - - function fann_get_network_type(Ann: PFann): cardinal; cdecl; - - function fann_get_connection_rate(Ann: PFann): single; cdecl; - - - function fann_get_num_layers(Ann: PFann): cardinal; cdecl; - - - procedure fann_get_layer_array(Ann: PFann; layers: PCardinal); cdecl; - - procedure fann_get_bias_array(Ann: PFann; bias: PCardinal);cdecl; - - - procedure fann_get_connection_array(Ann: PFann; connections: PFann_Connection);cdecl; - - - procedure fann_set_weight_array(Ann: PFann; connections: PFann_Connection; num_connection: Cardinal);cdecl; - - - procedure fann_set_weight(Ann: PFann; from_neuron: Cardinal; to_neuron: Cardinal; weight: fann_type);cdecl; - - procedure fann_set_user_data(Ann: PFann; user_data: Pointer);cdecl; - - function fann_get_user_data(Ann: PFann): Pointer; cdecl; - - - {$IFDEF FIXEDFANN} - - function fann_get_decimal_point(Ann: Pfann): cardinal; cdecl; - - function fann_get_multiplier(Ann: PFann): cardinal;cdecl; - - {$ENDIF} - - //END OF DECLARATIONS FROM FANN.H - - - - //DECLARATIONS FROM FANN_IO.H - - - function fann_create_from_file(const configuration_file: PChar): PFann; cdecl; - - procedure fann_save(Ann: PFann; Const Configuration_File: PChar);cdecl; - - function fann_save_to_fixed(Ann: PFann; Const Configuration_File: PChar): integer;cdecl; - - //END OF DECLARATIONS FROM FANN_IO.H - - - //DECLARATIONS FROM FANN_TRAIN.H - - {$IFNDEF FIXEDFANN} - procedure fann_train(Ann: PFann; Input: PFann_Type; Desired_Output: PFann_Type);cdecl; - {$ENDIF} - - function fann_test(Ann: PFann; Input: PFann_Type; Desired_Output: Pfann_Type): Pfann_type_array;cdecl; - - - function fann_get_MSE(Ann: PFann): single;cdecl; - - function fann_get_bit_fail(Ann: PFann): Cardinal;cdecl; - - procedure fann_reset_MSE(Ann: Pfann); cdecl; - - - {$IFNDEF FIXEDFANN} - - - procedure fann_train_on_data(Ann: PFann; Data: PFann_Train_Data;max_epochs: cardinal;epochs_between_reports: cardinal; desired_error: single);cdecl; - - procedure fann_train_on_file(Ann: PFann; Filename: Pchar;max_epochs: cardinal;epochs_between_reports: cardinal; desired_error: single); cdecl; - - - - function fann_train_epoch(Ann: PFann; data: PFann_Train_Data): single; cdecl; - - - function fann_test_data(Ann: PFann; data: PFann_Train_Data): single; cdecl; - - {$ENDIF} - - function fann_read_train_from_file(const filename: PChar): PFann_Train_Data; cdecl; - - - - function fann_create_train_from_callback(num_data: Cardinal; - num_input: Cardinal; - num_output: Cardinal; - user_function: TUser_Function): PFann_Train_Data; cdecl; - - - - procedure fann_destroy_train(train_data: PFann_Train_Data); cdecl; - - - procedure fann_shuffle_train_data(Train_Data: PFann_Train_Data);cdecl; - - - procedure fann_scale_train(Ann: PFann; data: PFann_Train_Data);cdecl; - - procedure fann_descale_train(Ann: PFann; data: PFann_Train_Data);cdecl; - - - function fann_set_input_scaling_params(Ann: PFann; - const data: PFann_Train_Data; - new_input_min: single; - new_input_max: single): integer;cdecl; - - - function fann_set_output_scaling_params(Ann: PFann; - const data: PFann_Train_Data; - new_output_min: single; - new_output_max: single): integer;cdecl; - - - - function fann_set_scaling_params(Ann: PFann; - const data: PFann_Train_Data; - new_input_min: single; - new_input_max: single; - new_output_min: single; - new_output_max: single): integer; cdecl; - - - function fann_clear_scaling_params(Ann: PFann): integer; cdecl; - - - - procedure fann_scale_input(Ann: PFann; input_vector: PFann_type); cdecl; - - - procedure fann_scale_output(Ann: PFann; output_vector: PFann_type); cdecl; - - - procedure fann_descale_input(Ann: PFann; input_vector: PFann_type); cdecl; - - - procedure fann_descale_output(Ann: PFann; output_vector: PFann_type); cdecl; - - - procedure fann_scale_input_train_data(Train_Data: PFann_Train_Data; - new_min: fann_type; - new_max: fann_type); cdecl; - - - procedure fann_scale_output_train_data(Train_Data: PFann_Train_Data; - new_min: fann_type; - new_max: fann_type); cdecl; - - - procedure fann_scale_train_data(Train_Data: PFann_Train_Data; - new_min: fann_type; - new_max: fann_type); cdecl; - - - function fann_merge_train_data(Data1: PFann_Train_Data; Data2: PFann_Train_Data): PFann_Train_Data; cdecl; - - - function fann_duplicate_train_data(Data: PFann_Train_Data): PFann_Train_Data;cdecl; - - - function fann_subset_train_data(data: PFann_Train_Data; pos: Cardinal; length: Cardinal): PFann_Train_Data; cdecl; - - - function fann_length_train_data(data: PFann_Train_Data): Cardinal; cdecl; - - - function fann_num_input_train_data(data: PFann_Train_Data): Cardinal; cdecl; - - function fann_num_output_train_data(data: PFann_Train_Data): Cardinal; cdecl; - - function fann_save_train(Data: PFann_train_Data; const Filename: PChar): integer;cdecl; - - function fann_save_train_to_fixed(Data: PFann_train_Data; const FileName: Pchar; decimal_point: cardinal): integer;cdecl; - - - - function fann_get_training_algorithm(Ann: Pfann): cardinal;cdecl; - - procedure fann_set_training_algorithm(Ann: PFann; Training_Algorithm: cardinal);cdecl; - - function fann_get_learning_rate(Ann: PFann): single;cdecl; - - procedure fann_set_learning_rate(Ann: PFann; Learning_Rate: Single); cdecl; - - function fann_get_learning_momentum(Ann: PFann): single;cdecl; - - procedure fann_set_learning_momentum(Ann: PFann; learning_momentum: Single); cdecl; - - - - function fann_get_activation_function(Ann: PFann; layer: integer; neuron: integer): Cardinal; cdecl; //ENUM - - procedure fann_set_activation_function(Ann: PFann; activation_function: Cardinal; layer: integer; neuron: integer); cdecl; //ENUM - - - procedure fann_set_activation_function_layer(Ann: PFann; activation_function: Cardinal; layer: integer); cdecl; //ENUM - - - procedure fann_set_activation_function_hidden(Ann: Pfann; Activation_function: cardinal); cdecl; - - procedure fann_set_activation_function_output(Ann: Pfann; Activation_Function: cardinal); cdecl; - - function fann_get_activation_steepness(Ann: PFann; layer: integer; neuron: integer): fann_type; cdecl; - - - procedure fann_set_activation_steepness(Ann: PFann; steepness: fann_type; layer: integer; neuron: integer); cdecl; - - - procedure fann_set_activation_steepness_layer(Ann: PFann; steepness: fann_type; layer: integer); cdecl; - - - procedure fann_set_activation_steepness_hidden(Ann: PFann; steepness: Fann_Type); cdecl; - - procedure fann_set_activation_steepness_output(Ann: PFann; steepness: Fann_Type);cdecl; - - function fann_get_train_error_function(Ann: PFann): cardinal;cdecl; - - procedure fann_set_train_error_function(Ann: PFann; Train_Error_Function: cardinal); cdecl; - - function fann_get_train_stop_function(Ann: PFann): Cardinal; cdecl; - - procedure fann_set_train_stop_function(Ann: PFann; train_stop_function: cardinal); cdecl; - - function fann_get_bit_fail_limit(Ann: PFann): fann_type; cdecl; - - procedure fann_set_bit_fail_limit(Ann: PFann; bit_fail_limit: fann_type); cdecl; - - procedure fann_set_callback(Ann: PFann; callback: TFann_Callback); cdecl; - - function fann_get_quickprop_decay(Ann: PFann): single;cdecl; - - procedure fann_set_quickprop_decay(Ann: Pfann; quickprop_decay: Single);cdecl; - - function fann_get_quickprop_mu(Ann: PFann): single;cdecl; - - procedure fann_set_quickprop_mu(Ann: PFann; Mu: Single);cdecl; - - function fann_get_rprop_increase_factor(Ann: PFann): single;cdecl; - - procedure fann_set_rprop_increase_factor(Ann: PFann;rprop_increase_factor: single);cdecl; - - function fann_get_rprop_decrease_factor(Ann: PFann): single;cdecl; - - procedure fann_set_rprop_decrease_factor(Ann: PFann;rprop_decrease_factor: single); cdecl; - - function fann_get_rprop_delta_min(Ann: PFann): single; cdecl; - - procedure fann_set_rprop_delta_min(Ann: PFann; rprop_delta_min: Single); cdecl; - - function fann_get_rprop_delta_max(Ann: PFann): single;cdecl; - - procedure fann_set_rprop_delta_max(Ann: PFann; rprop_delta_max: Single); cdecl; - - function fann_get_rprop_delta_zero(Ann: PFann): single;cdecl; - - procedure fann_set_rprop_delta_zero(Ann: PFann; rprop_delta_zero: Single); cdecl; - - //END OF DECLARATIONS OF FANN_TRAIN.H - - - //DECLARATIONS OF FANN_ERROR.H - - procedure fann_set_error_log(errdat: PFann_Error; Log_File: PFile);cdecl; - - function fann_get_errno(errdat: PFann_Error): cardinal;cdecl; - - procedure fann_reset_errno(errdat: PFann_Error);cdecl; - - procedure fann_reset_errstr(errdat: PFann_Error);cdecl; - - function fann_get_errstr(errdat: PFann_Error): PChar;cdecl; - - procedure fann_print_error(Errdat: PFann_Error);cdecl; - - - //END OF DECLARATIONS OF FANN_ERROR - - //DECLARATIONS OF FANN_CASCADE.H - - procedure fann_cascadetrain_on_data(Ann: PFann; - data: PFann_Train_Data; - max_neurons: Cardinal; - neurons_between_reports: Cardinal; - desired_error: single); cdecl; - - procedure fann_cascadetrain_on_file(Ann: PFann; - const filename: PChar; - max_neurons: Cardinal; - neurons_between_reports: Cardinal; - desired_error: single); cdecl; - - - function fann_get_cascade_output_change_fraction(Ann: PFann): single; cdecl; - - - procedure fann_set_cascade_output_change_fraction(Ann: PFann; cascade_output_change_fraction: single); cdecl; - - - function fann_get_cascade_output_stagnation_epochs(Ann: PFann): cardinal; cdecl; - - - procedure fann_set_cascade_output_stagnation_epochs(Ann: PFann; cascade_output_stagnation_epochs: cardinal); cdecl; - - - function fann_get_cascade_candidate_change_fraction(Ann: PFann): single; cdecl; - - - procedure fann_set_cascade_candidate_change_fraction(Ann: PFann; cascade_candidate_change_fraction: single); cdecl; - - - function fann_get_cascade_candidate_stagnation_epochs(Ann: PFann): cardinal; cdecl; - - - procedure fann_set_cascade_candidate_stagnation_epochs(Ann: PFann; cascade_candidate_stagnation_epochs: cardinal); cdecl; - - - function fann_get_cascade_weight_multiplier(Ann: PFann): fann_type; cdecl; - - - procedure fann_set_cascade_weight_multiplier(Ann: PFann; cascade_weight_multiplier: fann_type); cdecl; - - - function fann_get_cascade_candidate_limit(Ann: PFann): fann_type; cdecl; - - - procedure fann_set_cascade_candidate_limit(Ann: PFann; cascade_candidate_limit: fann_type); cdecl; - - - - function fann_get_cascade_max_out_epochs(Ann: PFann): cardinal; cdecl; - - - procedure fann_set_cascade_max_out_epochs(Ann: PFann; cascade_max_out_epochs: cardinal); cdecl; - - - function fann_get_cascade_max_cand_epochs(Ann: PFann): cardinal; cdecl; - - - procedure fann_set_cascade_max_cand_epochs(Ann: PFann; cascade_max_cand_epochs: cardinal); cdecl; - - - function fann_get_cascade_num_candidates(Ann: PFann): cardinal; cdecl; - - - function fann_get_cascade_activation_functions_count(Ann: PFann): cardinal; cdecl; - - - - function fann_get_cascade_activation_functions(Ann: PFann): PCardinal; cdecl; - - - procedure fann_set_cascade_activation_functions(Ann: PFann; cascade_activation_functions: PCardinal; cascade_activation_functions_count: Cardinal); cdecl; - - - function fann_get_cascade_activation_steepnesses_count(Ann: PFann): cardinal; cdecl; - - - function fann_get_cascade_activation_steepnesses(Ann: PFann): pfann_type; cdecl; - - procedure fann_set_cascade_activation_steepnesses(Ann: PFann; cascade_activation_steepnesses: PFann_Type; cascade_activation_steepnesses_count: Cardinal); cdecl; - - - function fann_get_cascade_num_candidate_groups(Ann: PFann): cardinal; cdecl; - - - procedure fann_set_cascade_num_candidate_groups(Ann: PFann; cascade_num_candidate_groups: cardinal); cdecl; - - - //END OF DECLARATIONS OF FANN_CASCADE.H - - - -implementation - - - {$IFDEF VARIABLE_ARGUMENTS} - - function fann_create_standard; external DLL_FILE; - - {$ENDIF} - - - function fann_create_standard_array; external DLL_FILE; - - - {$IFDEF VARIABLE_ARGUMENTS} - - function fann_create_sparse; external DLL_FILE; - - {$ENDIF} - - - - function fann_create_sparse_array; external DLL_FILE; - - - - {$IFDEF VARIABLE_ARGUMENTS} - - function fann_create_shortcut; external DLL_FILE; - - {$ENDIF} - - - function fann_create_shortcut_array; external DLL_FILE; - - - procedure fann_destroy; external DLL_FILE; - - - function fann_run; external DLL_FILE; - - - procedure fann_randomize_weights; external DLL_FILE; - - procedure fann_init_weights; external DLL_FILE; - - - procedure fann_print_connections; external DLL_FILE; - - procedure fann_print_parameters; external DLL_FILE; - - - function fann_get_num_input; external DLL_FILE; - - function fann_get_num_output; external DLL_FILE; - - function fann_get_total_neurons; external DLL_FILE; - - function fann_get_total_connections; external DLL_FILE; - - - function fann_get_network_type; external DLL_FILE; - - function fann_get_connection_rate; external DLL_FILE; - - - function fann_get_num_layers; external DLL_FILE; - - - procedure fann_get_layer_array; external DLL_FILE; - - procedure fann_get_bias_array; external DLL_FILE; - - - procedure fann_get_connection_array; external DLL_FILE; - - - procedure fann_set_weight_array; external DLL_FILE; - - - procedure fann_set_weight; external DLL_FILE; - - procedure fann_set_user_data; external DLL_FILE; - - function fann_get_user_data; external DLL_FILE; - - - {$IFDEF FIXEDFANN} - - function fann_get_decimal_point; external DLL_FILE; - - function fann_get_multiplier; external DLL_FILE; - - {$ENDIF} - - //END OF DECLARATIONS FROM FANN.H - - - - //DECLARATIONS FROM FANN_IO.H - - - function fann_create_from_file; external DLL_FILE; - - procedure fann_save; external DLL_FILE; - - function fann_save_to_fixed; external DLL_FILE; - - //END OF DECLARATIONS FROM FANN_IO.H - - - //DECLARATIONS FROM FANN_TRAIN.H - - {$IFNDEF FIXEDFANN} - procedure fann_train; external DLL_FILE; - {$ENDIF} - - function fann_test; external DLL_FILE; - - - function fann_get_MSE; external DLL_FILE; - - function fann_get_bit_fail; external DLL_FILE; - - procedure fann_reset_MSE; external DLL_FILE; - - - {$IFNDEF FIXEDFANN} - - - procedure fann_train_on_data; external DLL_FILE; - - procedure fann_train_on_file; external DLL_FILE; - - - - function fann_train_epoch; external DLL_FILE; - - - function fann_test_data; external DLL_FILE; - - {$ENDIF} - - function fann_read_train_from_file; external DLL_FILE; - - - - function fann_create_train_from_callback; external DLL_FILE; - - - - procedure fann_destroy_train; external DLL_FILE; - - - procedure fann_shuffle_train_data; external DLL_FILE; - - - procedure fann_scale_train; external DLL_FILE; - - procedure fann_descale_train; external DLL_FILE; - - - function fann_set_input_scaling_params; external DLL_FILE; - - - function fann_set_output_scaling_params; external DLL_FILE; - - - - function fann_set_scaling_params; external DLL_FILE; - - - function fann_clear_scaling_params; external DLL_FILE; - - - - procedure fann_scale_input; external DLL_FILE; - - - procedure fann_scale_output; external DLL_FILE; - - - procedure fann_descale_input; external DLL_FILE; - - - procedure fann_descale_output; external DLL_FILE; - - - procedure fann_scale_input_train_data; external DLL_FILE; - - - procedure fann_scale_output_train_data; external DLL_FILE; - - - procedure fann_scale_train_data; external DLL_FILE; - - - function fann_merge_train_data; external DLL_FILE; - - - function fann_duplicate_train_data; external DLL_FILE; - - - function fann_subset_train_data; external DLL_FILE; - - - function fann_length_train_data; external DLL_FILE; - - - function fann_num_input_train_data; external DLL_FILE; - - function fann_num_output_train_data; external DLL_FILE; - - function fann_save_train; external DLL_FILE; - - function fann_save_train_to_fixed; external DLL_FILE; - - - - function fann_get_training_algorithm; external DLL_FILE; - - procedure fann_set_training_algorithm; external DLL_FILE; - - function fann_get_learning_rate; external DLL_FILE; - - procedure fann_set_learning_rate; external DLL_FILE; - - function fann_get_learning_momentum; external DLL_FILE; - - procedure fann_set_learning_momentum; external DLL_FILE; - - - - function fann_get_activation_function; external DLL_FILE; //ENUM - - procedure fann_set_activation_function; external DLL_FILE; //ENUM - - - procedure fann_set_activation_function_layer; external DLL_FILE; //ENUM - - - procedure fann_set_activation_function_hidden; external DLL_FILE; - - procedure fann_set_activation_function_output; external DLL_FILE; - - function fann_get_activation_steepness; external DLL_FILE; - - - procedure fann_set_activation_steepness; external DLL_FILE; - - - procedure fann_set_activation_steepness_layer; external DLL_FILE; - - - procedure fann_set_activation_steepness_hidden; external DLL_FILE; - - procedure fann_set_activation_steepness_output; external DLL_FILE; - - function fann_get_train_error_function; external DLL_FILE; - - procedure fann_set_train_error_function; external DLL_FILE; - - function fann_get_train_stop_function; external DLL_FILE; - - procedure fann_set_train_stop_function; external DLL_FILE; - - function fann_get_bit_fail_limit; external DLL_FILE; - - procedure fann_set_bit_fail_limit; external DLL_FILE; - - procedure fann_set_callback; external DLL_FILE; - - function fann_get_quickprop_decay; external DLL_FILE; - - procedure fann_set_quickprop_decay; external DLL_FILE; - - function fann_get_quickprop_mu; external DLL_FILE; - - procedure fann_set_quickprop_mu; external DLL_FILE; - - function fann_get_rprop_increase_factor; external DLL_FILE; - - procedure fann_set_rprop_increase_factor; external DLL_FILE; - - function fann_get_rprop_decrease_factor; external DLL_FILE; - - procedure fann_set_rprop_decrease_factor; external DLL_FILE; - - function fann_get_rprop_delta_min; external DLL_FILE; - - procedure fann_set_rprop_delta_min; external DLL_FILE; - - function fann_get_rprop_delta_max; external DLL_FILE; - - procedure fann_set_rprop_delta_max; external DLL_FILE; - - function fann_get_rprop_delta_zero; external DLL_FILE; - - procedure fann_set_rprop_delta_zero; external DLL_FILE; - - //END OF DECLARATIONS OF FANN_TRAIN.H - - - //DECLARATIONS OF FANN_ERROR.H - - procedure fann_set_error_log; external DLL_FILE; - - function fann_get_errno; external DLL_FILE; - - procedure fann_reset_errno; external DLL_FILE; - - procedure fann_reset_errstr; external DLL_FILE; - - function fann_get_errstr; external DLL_FILE; - - procedure fann_print_error; external DLL_FILE; - - - //END OF DECLARATIONS OF FANN_ERROR - - //DECLARATIONS OF FANN_CASCADE.H - - procedure fann_cascadetrain_on_data; external DLL_FILE; - - procedure fann_cascadetrain_on_file; external DLL_FILE; - - - function fann_get_cascade_output_change_fraction; external DLL_FILE; - - - procedure fann_set_cascade_output_change_fraction; external DLL_FILE; - - - function fann_get_cascade_output_stagnation_epochs; external DLL_FILE; - - - procedure fann_set_cascade_output_stagnation_epochs; external DLL_FILE; - - - function fann_get_cascade_candidate_change_fraction; external DLL_FILE; - - - procedure fann_set_cascade_candidate_change_fraction; external DLL_FILE; - - - function fann_get_cascade_candidate_stagnation_epochs; external DLL_FILE; - - - procedure fann_set_cascade_candidate_stagnation_epochs; external DLL_FILE; - - - function fann_get_cascade_weight_multiplier; external DLL_FILE; - - - procedure fann_set_cascade_weight_multiplier; external DLL_FILE; - - - function fann_get_cascade_candidate_limit; external DLL_FILE; - - - procedure fann_set_cascade_candidate_limit; external DLL_FILE; - - - - function fann_get_cascade_max_out_epochs; external DLL_FILE; - - - procedure fann_set_cascade_max_out_epochs; external DLL_FILE; - - - function fann_get_cascade_max_cand_epochs; external DLL_FILE; - - - procedure fann_set_cascade_max_cand_epochs; external DLL_FILE; - - - function fann_get_cascade_num_candidates; external DLL_FILE; - - - function fann_get_cascade_activation_functions_count; external DLL_FILE; - - - - function fann_get_cascade_activation_functions; external DLL_FILE; - - - procedure fann_set_cascade_activation_functions; external DLL_FILE; - - - function fann_get_cascade_activation_steepnesses_count; external DLL_FILE; - - - function fann_get_cascade_activation_steepnesses; external DLL_FILE; - - procedure fann_set_cascade_activation_steepnesses; external DLL_FILE; - - - function fann_get_cascade_num_candidate_groups; external DLL_FILE; - - - procedure fann_set_cascade_num_candidate_groups; external DLL_FILE; - - - -end. - diff --git a/Source/Units/backup/hulpfuncties.pas b/Source/Units/backup/hulpfuncties.pas deleted file mode 100644 index 60080101..00000000 --- a/Source/Units/backup/hulpfuncties.pas +++ /dev/null @@ -1,2531 +0,0 @@ -unit Hulpfuncties; - -// temporarily removed the whole OpenAL sound library from the program for Linux since it causes weird floating point exceptions - -interface -uses - {$ifdef unix}clocale,{$endif} Classes, SysUtils, Variants, Math, Graphics, - Forms, Dialogs, strutils, frQuestion, frgetstring, frgetpasswd, - FrNotification //{$ifdef linux}, openal{$endif} - {$ifdef windows}, MMsystem{$endif}, Process; - -type - TUnit = (milligram, gram, kilogram, milliliter, liter, hectoliter, IBU, EBC, SRM, - SG, plato, brix, celcius, fahrenheit, minuut, uur, dag, week, ppm, volco2, - abv, perc, euro, pH, pph, calgdeg, kPa, bar, lintner, windischkolbach, - gpl, cal, pks, stks, depots, watt, lph, lpm, lpkg, meter, centimeter, meql, none); - THopUse = (huMash, huFirstwort, huBoil, huAroma, huWhirlpool, huDryhop); - THopType = (htBittering, htAroma, htBoth); - THopForm = (hfPellet, hfPlug, hfLeaf); - TFermentableType = (ftGrain, ftSugar, ftExtract, ftDryExtract, ftAdjunct); - TGrainType = (gtBase, gtRoast, gtCrystal, gtKilned, gtSour, gtSpecial, gtNone); - TAddedType = (atMash, atBoil, atFermentation, atLagering, atBottle); - TYeastType = (ytLager, ytAle, ytWheat, ytWine, ytChampagne); - TYeastForm = (yfLiquid, yfDry, yfSlant, yfCulture, yfFrozen, yfBottle); - TFlocculation = (flLow, flMedium, flHigh, lfVeryHigh); - TStarterType = (stSimple, stAerated, stStirred); - TMiscType = (mtSpice, mtHerb, mtFlavor, mtFining, mtWaterAgent, mtNutrient, mtOther); - TMiscUse = (muStarter, muMash, muBoil, muPrimary, muSecondary, muBottling); - TStyleType = (stLager, stAle, stMead, stWheat, stMixed, stCider); - TMashStepType = (mstInfusion, mstTemperature, mstDecoction); - TRecipeType = (rtExtract, rtPartialMash, rtAllGrain); - TIBUmethod = (imTinseth, imRager, imGaretz, imDaniels, imMosher, imNoonan); - TColorMethod = (cmMorey, cmMosher, cmDaniels); - TIngredientType = (itFermentable, itHop, itMisc, itYeast, itWater); - TDataType = (dtFermentable, dtHop, dtMisc, dtYeast, dtWater, dtMash, dtEquipment, - dtRecipe, dtStyle, dtMeasurements); - TCoolingMethod = (cmEmpty, cmEmersion, cmCouterFlow, cmAuBainMarie, cmNatural); - TAerationType = (atNone, atAir, atOxygen); - TPrimingSugar = (psSaccharose, psGlucose, psHoney, psDME, psMolassis); - TFileType = (ftPromash, ftXML, ftOther); - TAcidType = (atLactic, atHydrochloric, atPhosphoric, atSulfuric); - TBaseType = (btNaHCO3, btNa2CO3, btCaCO3, btCaOH2); - - TRecType = (rtRecipe, rtBrew, rtCloud); - - TSpecificHeat = record - Material : string; - SpecificHeat : double; - end; - - TCellCoord = record - Col : integer; - Row : integer; - end; - - TEndChar = set of char; - -const - UnitNames : array[TUnit] of string = ('mg', 'g', 'kg', 'ml', 'l', 'hl', 'IBU', 'EBC', - '°L', 'SG', '°P', '°B', '°C', '°F', 'min.', 'uren', 'dagen', - 'weken', 'mg/l', 'vol.', 'vol.%', '%', '€', 'pH', '%/uur', 'cal/g.°C', - 'kPa', 'bar', '°Lintner', '°WK', 'g/l', 'kcal/l', 'pak(ken)', - 'stuks', 'depots', 'W', 'l/uur', 'l/min', 'l/kg', - 'm', 'cm', 'mEq/l', ''); - DefaultDecimals : array[TUnit] of word = (1, 1, 2, 1, 2, 1, 0, 0, 1, 3, 1, 1, 1, 0, - 0, 0, 0, 0, 1, 1, 1, 1, 2, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 0); - DefaultIncrement : array[TUnit] of single = (1, 1, 0.5, 1, 0.5, 0.5, 1, 1, 1, 0.001, 0.5, - 0.5, 1, 1, 1, 1, 1, 1, 1, 1, 0.5, 1, 0.5, - 0.1, 0.5, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 0.1, 0); - DefaultMinValue : array[TUnit] of single = (0, 0, 0, 0, 0, 0, 0, 0, 0, 1.0, 0, - 0, 0, 32, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 1, 0, 0, 0, 0); - DefaultMaxValue : array[TUnit] of single = (2000, 10000, 10000, 10000, 10000, 100000, - 200, 1000, 1000, 1.3, 50, 50, 110, 230, - 240, 480, 365, 52, 10000, 10000, 100, 100, - 100000, 14, 100, 100000, 100, 100, 10000, - 10000, 1000, 1000, 1000, 1000, 1000, - 10000, 100, 100, 10, 10000, 10000, 1000, 0); - HopUseNames : array[THopUse] of string = ('Mash', 'First wort', 'Boil', 'Aroma', 'Whirlpool', 'Dry hop'); - HopUseDisplayNames : array[THopUse] of string = ('maischhop', 'first wort hop', 'koken', 'vlamuit', 'whirlpool', 'koudhop'); - HopTypeNames : array[THopType] of string = ('Bittering', 'Aroma', 'Both'); - HopTypeDisplayNames : array[THopType] of string = ('bitterhop', 'aromahop', 'beide'); - HopFormNames : array[THopForm] of string = ('Pellet', 'Plug', 'Leaf'); - HopFormDisplayNames : array[THopForm] of string = ('pellets', 'plugs', 'bellen'); - FermentableTypeNames : array[TFermentableType] of string = ('Grain', 'Sugar', 'Extract', 'Dry extract', 'Adjunct'); - FermentableTypeDisplayNames : array[TFermentableType] of string = ('mout', 'suiker', 'vloeibaar extract', 'droog extract', 'ongemout graan'); - GrainTypeNames : array[TGrainType] of string = ('Base', 'Roast', 'Crystal', 'Kilned', 'Sour malt', 'Special', 'No malt'); - GrainTypeDisplayNames : array[TGrainType] of string = ('basismout', 'geroosterde mout', 'cara- of crystalmout', 'geëeste mout', 'zuurmout', 'speciale mout', 'n.v.t.'); - AddedTypeNames : array[TAddedType] of string = ('Mash', 'Boil', 'Fermentation', 'Lagering', 'Bottle'); - AddedTypeDisplayNames : array[TAddedType] of string = ('maischen', 'koken', 'vergisten', 'nagisten/lageren', 'bottelen'); - YeastTypeNames : array[TYeastType] of string = ('Lager', 'Ale', 'Wheat', 'Wine', 'Champagne'); - YeastTypeDisplayNames : array[TYeastType] of string = ('ondergist', 'bovengist', 'weizengist', 'wijngist', 'champagnegist'); - YeastFormNames : array[TYeastForm] of string = ('Liquid', 'Dry', 'Slant', 'Culture', 'Frozen', 'Bottle'); - YeastFormDisplayNames : array[TYeastForm] of string = ('vloeibaar', 'droog', 'schuine buis', 'slurry', 'ingevroren', 'depot'); - FlocculationNames : array[TFlocculation] of string = ('Low', 'Medium', 'High', 'Very high'); - FlocculationDisplayNames : array[TFlocculation] of string = ('laag', 'medium', 'hoog', 'zeer hoog'); - StarterTypeNames : array[TStarterType] of string = ('Simple', 'Aerated', 'Stirred'); - StarterTypeDisplayNames : array[TStarterType] of string = ('simpel', 'belucht', 'geroerd'); - MiscTypeNames : array[TMiscType] of string = ('Spice', 'Herb', 'Flavor', 'Fining', 'Water agent', 'Yeast nutrient', 'Other'); - MiscTypeDisplayNames : array[TMiscType] of string = ('specerij', 'kruid', 'smaakstof', 'klaringsmiddel', 'brouwzout', 'gistvoeding', 'anders'); - MiscUseNames : array[TMiscUse] of string = ('Starter', 'Mash', 'Boil', 'Primary', 'Secondary', 'Bottling'); - MiscUseDisplayNames : array[TMiscUse] of string = ('starter', 'maischen', 'koken', 'hoofdvergisting', 'nagisting/lagering', 'bottelen'); - StyleTypeNames : array[TStyleType] of string = ('Lager', 'Ale', 'Mead', 'Wheat', 'Mixed', 'Cider'); - StyleTypeDisplayNames : array[TStyleType] of string = ('Ondergistend bier', 'Bovengistend bier', 'Mede', 'Tarwebier', 'Gemengd', 'Cider'); - MashStepTypeNames : array[TMashStepType] of string = ('Infusion', 'Temperature', 'Decoction'); - MashStepTypeDisplayNames : array[TMashStepType] of string = ('Infusie', 'Directe verwarming', 'Decoctie'); - RecipeTypeNames : array[TRecipeType] of string = ('Extract', 'Partial Mash', 'All Grain'); - RecipeTypeDisplayNames : array[TRecipeType] of string = ('Extract', 'Deelmaisch', 'Mout'); - IBUmethodNames : array[TIBUmethod] of string = ('Tinseth', 'Rager', 'Garetz', 'Daniels', 'Mosher', 'Noonan'); - IBUmethodDisplayNames : array[TIBUmethod] of string = ('Tinseth', 'Rager', 'Garetz', 'Daniels', 'Mosher', 'Noonan'); - ColorMethodNames : array[TColorMethod] of string = ('Morey', 'Mosher', 'Daniels'); - ColorMethodDisplayNames : array[TColorMethod] of string = ('Morey', 'Mosher', 'Daniels'); - IngredientTypeDisplayNames : array[TIngredientType] of string = ('Mout', 'Hop', 'Ov.', 'Gist', 'Water'); - CoolingMethodNames : array[TCoolingMethod] of string = ('-', 'Emersion chiller', 'Counterflow chiller', 'Au bain marie', 'Natural'); - CoolingMethodDisplayNames : array[TCoolingMethod] of string = ('-', 'Dompelkoeler', 'Tegenstroomkoeler', 'Au bain marie', 'Laten afkoelen'); - AerationTypeNames : array[TAerationType] of string = ('None', 'Air', 'Oxygen'); - AerationTypeDisplayNames : array[TAerationType] of string = ('Geen', 'Lucht', 'Zuurstof'); - PrimingSugarNames : array[TPrimingSugar] of string = ('Saccharose', 'Glucose or dextrose', 'Honey', 'DME', 'Molassis'); - PrimingSugarDisplayNames : array[TPrimingSugar] of string = ('Kristalsuiker', 'Glucose/dextrose', 'Honing', 'Moutextract', 'Melasse'); - PrimingSugarFactors : array[TPrimingSugar] of double = (1, 1.16, 1.28, 1.74, 3.83); - FileTypeNames : array[TFileType] of string = ('Promash', 'XML', 'Other'); - FileTypeDisplayNames : array[TFileType] of string = ('Promash', 'XML', 'Anders'); - AcidTypeNames : array[TAcidType] of string = ('Lactic', 'Hydrochloric', 'Phosphoric', 'Sulfuric'); - AcidTypeDisplayNames : array[TAcidType] of string = ('Melkzuur', 'Zoutzuur', 'Fosforzuur', 'Zwavelzuur'); - BaseTypeNames : array[TBaseType] of string = ('Sodiumbicarbonate', 'Sodiumcarbonate', 'Calciumcarbonate', 'Calciumhydroxide'); - BaseTypeDisplayNames : array[TBaseType] of string = ('NaHCO3', 'Na2CO3', 'CaCO3', 'Ca(OH)2'); - - - SpecificHeatWater : double = 1.0; //cal/g.°C - SpecificHeatMalt : double = 0.399; //cal/g.°C - SlakingHeat : double = 10.318; //cal/g.°C - MaltVolume : double = 0.87; //l/kg 0.688 VOLGENS INTERNETBRONNEN, GEMETEN 0.874 l/kg, na enige tijd maischen 0,715 l/kg - ExpansionFactor : double = 1.04; //4% increase in water volume between 20 and 100°C - SugarDensity : double = 1.611; //kg/l in solution - WaterDensity20 : double = 0.9982; //kg/l at 20°C - - Months : array[1..12] of string = ('januari', 'februari', 'maart', 'april', 'mei', - 'juni', 'juli', 'augustus', 'september', 'oktober', - 'november', 'december'); - MonthsShort : array[1..12] of string = ('jan', 'feb', 'mrt', 'apr', 'mei', - 'jun', 'jul', 'aug', 'sep', 'okt', - 'nov', 'dec'); - - SRMtoRGB : array[0..299, 0..3] of real = ((0.1, 250, 250, 210), (0.2, 250, 250, 204), (0.3, 250, 250, 199), (0.4, 250, 250, 193), (0.5, 250, 250, 188), (0.6, 250, 250, 182), (0.7, 250, 250, 177), (0.8, 250, 250, 171), (0.9, 250, 250, 166), (1, 250, 250, 160), (1.1, 250, 250, 155), (1.2, 250, 250, 149), (1.3, 250, 250, 144), (1.4, 250, 250, 138), (1.5, 250, 250, 133), (1.6, 250, 250, 127), (1.7, 250, 250, 122), (1.8, 250, 250, 116), (1.9, 250, 250, 111), (2, 250, 250, 105), (2.1, 250, 250, 100), (2.2, 250, 250, 94), (2.3, 250, 250, 89), (2.4, 250, 250, 83), (2.5, 250, 250, 78), (2.6, 249, 250, 72), (2.7, 248, 249, 67), (2.8, 247, 248, 61), (2.9, 246, 247, 56), (3, 245, 246, 50), (3.1, 244, 245, 45), (3.2, 243, 244, 45), (3.3, 242, 242, 45), (3.4, 241, 240, 46), (3.5, 240, 238, 46), (3.6, 239, 236, 46), (3.7, 238, 234, 46), (3.8, 237, 232, 47), (3.9, 236, 230, 47), (4, 235, 228, 47), (4.1, 234, 226, 47), (4.2, 233, 224, 48), (4.3, 232, 222, 48), (4.4, 231, 220, 48), (4.5, 230, 218, 48), (4.6, 229, 216, 49), (4.7, 228, 214, 49), (4.8, 227, 212, 49), (4.9, 226, 210, 49), (5, 225, 208, 50), (5.1, 224, 206, 50), (5.2, 223, 204, 50), (5.3, 222, 202, 50), (5.4, 221, 200, 51), (5.5, 220, 198, 51), (5.6, 219, 196, 51), (5.7, 218, 194, 51), (5.8, 217, 192, 52), (5.9, 216, 190, 52), (6, 215, 188, 52), (6.1, 214, 186, 52), (6.2, 213, 184, 53), (6.3, 212, 182, 53), (6.4, 211, 180, 53), (6.5, 210, 178, 53), (6.6, 209, 176, 54), (6.7, 208, 174, 54), (6.8, 207, 172, 54), (6.9, 206, 170, 54), (7, 205, 168, 55), (7.1, 204, 166, 55), (7.2, 203, 164, 55), (7.3, 202, 162, 55), (7.4, 201, 160, 56), (7.5, 200, 158, 56), (7.6, 200, 156, 56), (7.7, 199, 154, 56), (7.8, 199, 152, 56), (7.9, 198, 150, 56), (8, 198, 148, 56), (8.1, 197, 146, 56), (8.2, 197, 144, 56), (8.3, 196, 142, 56), (8.4, 196, 141, 56), (8.5, 195, 140, 56), (8.6, 195, 139, 56), (8.7, 194, 139, 56), (8.8, 194, 138, 56), (8.9, 193, 137, 56), (9, 193, 136, 56), (9.1, 192, 136, 56), (9.2, 192, 135, 56), (9.3, 192, 134, 56), (9.4, 192, 133, 56), (9.5, 192, 133, 56), (9.6, 192, 132, 56), (9.7, 192, 131, 56), (9.8, 192, 130, 56), (9.9, 192, 130, 56), (10, 192, 129, 56), (10.1, 192, 128, 56), (10.2, 192, 127, 56), (10.3, 192, 127, 56), (10.4, 192, 126, 56), (10.5, 192, 125, 56), (10.6, 192, 124, 56), (10.7, 192, 124, 56), (10.8, 192, 123, 56), (10.9, 192, 122, 56), (11, 192, 121, 56), (11.1, 192, 121, 56), (11.2, 192, 120, 56), (11.3, 192, 119, 56), (11.4, 192, 118, 56), (11.5, 192, 118, 56), (11.6, 192, 117, 56), (11.7, 192, 116, 56), (11.8, 192, 115, 56), (11.9, 192, 115, 56), (12, 192, 114, 56), (12.1, 192, 113, 56), (12.2, 192, 112, 56), (12.3, 192, 112, 56), (12.4, 192, 111, 56), (12.5, 192, 110, 56), (12.6, 192, 109, 56), (12.7, 192, 109, 56), (12.8, 192, 108, 56), (12.9, 191, 107, 56), (13, 190, 106, 56), (13.1, 189, 106, 56), (13.2, 188, 105, 56), (13.3, 187, 104, 56), (13.4, 186, 103, 56), (13.5, 185, 103, 56), (13.6, 184, 102, 56), (13.7, 183, 101, 56), (13.8, 182, 100, 56), (13.9, 181, 100, 56), (14, 180, 99, 56), (14.1, 179, 98, 56), (14.2, 178, 97, 56), (14.3, 177, 97, 56), (14.4, 175, 96, 55), (14.5, 174, 95, 55), (14.6, 172, 94, 55), (14.7, 171, 94, 55), (14.8, 169, 93, 54), (14.9, 168, 92, 54), (15, 167, 91, 54), (15.1, 165, 91, 54), (15.2, 164, 90, 53), (15.3, 162, 89, 53), (15.4, 161, 88, 53), (15.5, 159, 88, 53), (15.6, 158, 87, 52), (15.7, 157, 86, 52), (15.8, 155, 85, 52), (15.9, 154, 85, 52), (16, 152, 84, 51), (16.1, 151, 83, 51), (16.2, 149, 82, 51), (16.3, 148, 82, 51), (16.4, 147, 81, 50), (16.5, 145, 80, 50), (16.6, 144, 79, 50), (16.7, 142, 78, 50), (16.8, 141, 77, 49), (16.9, 139, 76, 49), (17, 138, 75, 48), (17.1, 137, 75, 47), (17.2, 135, 74, 47), (17.3, 134, 73, 46), (17.4, 132, 72, 45), (17.5, 131, 72, 45), (17.6, 129, 71, 44), (17.7, 128, 70, 43), (17.8, 127, 69, 43), (17.9, 125, 69, 42), (18, 124, 68, 41), (18.1, 122, 67, 41), (18.2, 121, 66, 40), (18.3, 119, 66, 39), (18.4, 118, 65, 39), (18.5, 117, 64, 38), (18.6, 115, 63, 37), (18.7, 114, 63, 37), (18.8, 112, 62, 36), (18.9, 111, 61, 35), (19, 109, 60, 34), (19.1, 108, 60, 33), (19.2, 107, 59, 32), (19.3, 105, 58, 31), (19.4, 104, 57, 29), (19.5, 102, 57, 28), (19.6, 101, 56, 27), (19.7, 99, 55, 26), (19.8, 98, 54, 25), (19.9, 97, 54, 24), (20, 95, 53, 23), (20.1, 94, 52, 21), (20.2, 92, 51, 20), (20.3, 91, 51, 19), (20.4, 89, 50, 18), (20.5, 88, 49, 17), (20.6, 87, 48, 16), (20.7, 85, 48, 15), (20.8, 84, 47, 13), (20.9, 82, 46, 12), (21, 81, 45, 11), (21.1, 79, 45, 10), (21.2, 78, 44, 9), (21.3, 77, 43, 8), (21.4, 75, 42, 9), (21.5, 74, 42, 9), (21.6, 72, 41, 10), (21.7, 71, 40, 10), (21.8, 69, 39, 11), (21.9, 68, 39, 11), (22, 67, 38, 12), (22.1, 65, 37, 12), (22.2, 64, 36, 13), (22.3, 62, 36, 13), (22.4, 61, 35, 14), (22.5, 59, 34, 14), (22.6, 58, 33, 15), (22.7, 57, 33, 15), (22.8, 55, 32, 16), (22.9, 54, 31, 16), (23, 52, 30, 17), (23.1, 51, 30, 17), (23.2, 49, 29, 18), (23.3, 48, 28, 18), (23.4, 47, 27, 19), (23.5, 45, 27, 19), (23.6, 44, 26, 20), (23.7, 42, 25, 20), (23.8, 41, 24, 21), (23.9, 39, 24, 21), (24, 38, 23, 22), (24.1, 37, 22, 21), (24.2, 37, 22, 21), (24.3, 36, 22, 21), (24.4, 36, 21, 20), (24.5, 35, 21, 20), (24.6, 35, 21, 20), (24.7, 34, 20, 19), (24.8, 34, 20, 19), (24.9, 33, 20, 19), (25, 33, 19, 18), (25.1, 32, 19, 18), (25.2, 32, 19, 18), (25.3, 31, 18, 17), (25.4, 31, 18, 17), (25.5, 30, 18, 17), (25.6, 30, 17, 16), (25.7, 29, 17, 16), (25.8, 29, 17, 16), (25.9, 28, 16, 15), (26, 28, 16, 15), (26.1, 27, 16, 15), (26.2, 27, 15, 14), (26.3, 26, 15, 14), (26.4, 26, 15, 14), (26.5, 25, 14, 13), (26.6, 25, 14, 13), (26.7, 24, 14, 13), (26.8, 24, 13, 12), (26.9, 23, 13, 12), (27, 23, 13, 12), (27.1, 22, 12, 11), (27.2, 22, 12, 11), (27.3, 21, 12, 11), (27.4, 21, 11, 10), (27.5, 20, 11, 10), (27.6, 20, 11, 10), (27.7, 19, 10, 9), (27.8, 19, 10, 9), (27.9, 18, 10, 9), (28, 18, 9, 8), (28.1, 17, 9, 8), (28.2, 17, 9, 8), (28.3, 16, 8, 7), (28.4, 16, 8, 7), (28.5, 15, 8, 7), (28.6, 15, 7, 6), (28.7, 14, 7, 6), (28.8, 14, 7, 6), (28.9, 13, 6, 5), (29, 13, 6, 5), (29.1, 12, 6, 5), (29.2, 12, 5, 4), (29.3, 11, 5, 4), (29.4, 11, 5, 4), (29.5, 10, 4, 3), (29.6, 10, 4, 3), (29.7, 9, 4, 3), (29.8, 9, 3, 2), (29.9, 8, 3, 2), (30, 8, 3, 2)); - - MMCa : double = 40.048; - MMMg : double = 24.305; - MMNa : double = 22.98976928; - MMCl : double = 35.453; - MMSO4 : double = 96.0626; - MMCO3 : double = 60.01684; - MMHCO3 : double = 61.01684; - MMCaSO4 : double = 172.171; - MMCaCl2 : double = 147.015; - MMCaCO3 : double = 100.087; - MMMgSO4 : double = 246.475; - MMNaHCO3 : double = 84.007; - MMNa2CO3 : double = 105.996; - MMNaCl : double = 58.443; - MMCaOH2 : double = 74.06268; - - {$ifdef unix} - numbuffers = 4; - numsources = 4; - startprog = 0; - warning = 1; - alarm = 2; - endprog = 3; - {$endif} - - AnalysisActive = TRUE; - FANNActive = TRUE; - - DoLog = false; - - {$ifdef windows} - DefaultFontHeight = 15; - {$endif} - {$ifdef linux} - DefaultFontHeight = 12; - {$endif} - {$ifdef darwin} - DefaultFontHeight = 12; - {$endif} - - -var - SpecificHeats : array[0..3] of TSpecificHeat; - DriveLetter : string; - OnUSB : boolean; - ExecFolder : string; - BHFolder : string; - SoundFolder : string; - IconFolder : string; - Slash : string; - EndChar : TEndChar; - FermentableColor, HopColor, MiscColor, WaterAgentColor, WaterColor, YeastColor, - FiningColor: TColor; - MaxGrowthFactor : double; - AmCellspGramDry, AmCellspPack, AmCellspMlSlurry : double; - - -// {$ifdef linux} -// buffer : array [0..numbuffers] of TALuint; //TALuint; -// source : array [0..numsources] of TALuint; //TALuint; -// sourcepos: array [0..2] of TALfloat= ( 0.0, 0.0, 0.0 ); //TALfloat= ( 0.0, 0.0, 0.0 ); -// sourcevel: array [0..2] of TALfloat= ( 0.0, 0.0, 0.0 ); //TALfloat= ( 0.0, 0.0, 0.0 ); -// listenerpos: array [0..2] of TALfloat= ( 0.0, 0.0, 0.0); //TALfloat= ( 0.0, 0.0, 0.0 ); -// listenervel: array [0..2] of TALfloat= ( 0.0, 0.0, 0.0); //TALfloat= ( 0.0, 0.0, 0.0 ); -// listenerori: array [0..5] of TALfloat= ( 0.0, 0.0, -1.0, 0.0, 1.0, 0.0); //TALfloat= ( 0.0, 0.0, -1.0, 0.0, 1.0, 0.0); -// -// argv: array of PalByte; -// format: TALEnum; //TALEnum; -// size: TALSizei; //TALSizei; -// freq: TALSizei; //TALSizei; -// loop: TALInt; //TALInt; -// dat: TALVoid; //TALVoid; -// {$endif} - - StartSound, EndSound, WarningSound, AlarmSound : string; - - slLog : TStringList; - -Function GetTaskBarSize: TRect; -Function InitializeHD(FN : string; var Dir : string) : boolean; -Function Convert(FromUnit : TUnit; ToUnit : TUnit; val : double) : double; -Procedure ConvertSeconds(var h, m, s, mi : word); -Function Sinus(angle : double) : double; //angle in degrees -Function Cosinus(angle : double) : double; //angle in degrees -Function Between(value, low, high : double) : boolean; -Function MaxD(a, b : double) : double; -Function MinD(a, b : double) : double; -Function MaxA(a : array of double) : double; -Function MinA(a : array of double) : double; -Function MinI(a, b : integer) : integer; -Function MaxI(a, b : integer) : integer; -Function RoundUp( R : Double) : LongInt; -Function InvLog(i : double) : double; -Procedure SwapW(var a, b : double); -Function DecimalsSc(S : Double) : LongInt; -Function GetOrdinals(S : extended) : LongInt; -Function GetDecimals(S : Double) : LongInt; -Function TLC(s : string) : string; -Function FormatString(S : extended; D : LongInt) : String; -Function StringFormat(S, X : Double; D : SmallInt) : string; -Function StrToReal(S : string) : Double; -Function RealToStr(S : Double) : string; -Function ValidateRealStr(S : string) : boolean; -Function RealToStrSci(S : Double; Prec : LongInt) : string; -Function RealToStrDEC(S : Double; D : SmallInt) : string; -Function RealToStrSignif(S : Double; Signif : SmallInt) : string; -Function Order(R : Double) : SmallInt; -Function StringToDate(s : string) : TDateTime; -Function IsValidDate(s : string) : boolean; -Function StringToTime(s : string) : TDateTime; -Function IsValidTime(s : string) : boolean; -Function SetDecimalSeparator(Sin : string) : string; -Function SetDecimalPoint(Sin : string) : string; -Function CountSubssInString(s, sub : string) : integer; -Function IsInString(searchString, SubString : string) : boolean; -Function FloatToStringDec(d : double; Dec: integer) : string; -Function FloatToDisplayString(d : double; Dec : integer; u : string) : string; -Function IntToDisplayString(i : integer; u : string) : string; -Procedure QuickSortArray(var Arr : array of double); -Procedure SelectionSortArray(var List : array of double); -Function SolveQuadratic(a, b, c : double; var X1, X2 : double) : integer; -Function SolveCubic(a, b, c, d : double; var X1, X2, X3 : double) : integer; -Procedure ShowNotification(sender : TComponent; s : string); -Procedure ShowNotificationModal(sender : TComponent; s : string); -Function Question(sender : TComponent; s : string) : boolean; -Function GetAnswer(sender : TComponent; Q : string) : string; -Function GetPasswd(sender : TComponent) : string; -Function RemInvChars(S : string) : string; - -Function DrawTxt(Canvas : TCanvas; MiddleHeight, Left, Right : LongInt; - Text : string; Alignment : TAlignment; - MoreLines : boolean) : integer; -Function DrawTxtRct( Canvas : TCanvas; R : TRect; - Text : string; Alignment : TAlignment; - MoreLines : boolean) : integer; -Procedure DrawTxtVarRct(canvas : TCanvas; Text : string; var R : TRect); -Function RotateText(Canvas : TCanvas; Xt, Yl, Deg : LongInt; Txt : string; - BackColor : tColor; Transparant : boolean) : boolean; -Procedure Scaling(var Min, Max, De : double; var Astr : LongInt); -Procedure CalcScale(var Min, Max, De : double; var AStr : LongInt); -Procedure ScaleFixed(var Min, Max, De : double; var Astr : LongInt); -Procedure ScaleDate(var Min, Max, De : TDateTime; var Astr : LongInt); -Function CalcTextHeight( FontSize, PPIY : integer) : integer; -Function CalcAmountLines( Canvas : TCanvas; Text : string; - Width : LongInt) : LongInt; -Function CalcAmountLines2(Font : TFont; Text : string; Width : LongInt) : LongInt; -Function CalcMaxWidth( Canvas : TCanvas; Text : string) : LongInt; -Function GiveNextLine( Canvas : TCanvas; Text : string; - Width : LongInt; var Pos : LongInt) : string; -Function NextWord( Line : string; var Pos : LongInt) : string; - -Function CalcFrac(TpH, pK1, pK2, pK3 : double) : double; -Function SRMtoEBC(d : double) : double; -Function EBCtoSRM(d : double) : double; -Function EBCtoColor(EBC : double) : TColor; -Function SRMtoColor(SRM : double) : TColor; -Function SGtoPlato(SG : Double) : Double; -Function PlatoToSG(plato : Double) : Double; -Function PlatoToExtract(P : Double) : Double; -Function SGtoBrix(SG : Double) : Double; -Function BrixToSG(Brix : Double) : Double; -Function BrixToFG(OBrix, FBrix : double) : double; -Function SGtoExtract(SG : Double) : Double; -Function ExtractToSG(E : Double) : Double; -Function BrixToRI(Brix : Double) : Double; -Function RE(SG : Double; Brix : Double) : Double; -Function AlcByVol(SG : Double; Brix : Double) : Double; -Function ABVol(OG : Double; FG : Double) : Double; -Function ABW(ABVol : Double; FG : Double) : Double; -Function ABW2(FG : Double; Brix : Double) : Double; -Function SGFerm(OBrix : Double; FBrix : Double) : Double; -Function RealExtract(FG : Double; Brix : Double) : Double; -Function FtoC(f : double) : double; -Function CtoF(c : double) : double; -Function Waterdensity(T : Double) : Double; -Function pHRoom(pHmash, Tm : double) : double; -Function DwatT(T : double; Tref : Double) : Double; -Function FreezingPoint(SG : Double; FG : Double) : Double; -Function StarterSize(types : Integer; soort : Double; V : Double; SG : Double; start : Double) : double; -Function StarterSize2(types : Integer; Needed : double; start : Double) : double; -Function AmountCells(types : Integer; V : Double; start : Double) : double; -Function GrowthFactor(types : Integer; V : Double; start : Double) : double; -Function CalcIBU(Method : TIBUmethod; HopUse : THopUse; AA : Double; AM : Double; Vw : Double; Vf : Double; SG : Double; Tboil : Double; HopVorm : THopForm; BNAP : Double) : Double; -Function AmHop(Method : TIBUmethod; HopUse : THopUse; AA : Double; IBU : Double; Vw : double; Vf : Double; SG : Double; Tboil : Double; HopVorm : THopForm; BNAP : Double) : Double; -Function IonBalance(Ca, Mg, Na, Cl, SO4, HCO3 : double) : double; -Function CarbStoCO2(S : double; T : double; SFactor : double) : double; -Function CarbCO2toS(CO2 : double; T : double; SFactor : double) : double; -Function CarbCO2toPressure(CO2 : double; T : double) : double; -Function CarbPressuretoCO2(P : double; T : double) : double; -Function ActualIBU(origibu, HSI, Temp : double; Elapsed, storagetype : longint) : double; - -Procedure PlayStartProg; -Procedure PlayEndProg; -Procedure PlayWarning; -Procedure PlayAlarm; - -//Procedure SetFontHeight(F : TForm; fs : integer); - -Function ConvertStringEnc(s : string) : string; - -Function ZipFiles(l : TStringList; zipfn : string) : boolean; -Function UnZipFiles(zipfn, outpath : string) : boolean; - -Procedure Log(s : string); - -implementation - -uses Data, FrMain, lconvencoding, Zipper; - -function GetTaskBarSize: TRect; -begin - {$ifdef Windows} -// SystemParametersInfo(SPI_GETWORKAREA, 0, @Result, 0); - {$endif} -end; - -Function ConvertStringEnc(s : string) : string; -var encs, encto: string; -begin - encto := GetDefaultTextEncoding; - encs := 'utf8'; - Result := ConvertEncoding(s, encs, encto); -// Result:= UTF8toANSI(Result); -end; - -Function InitializeHD(FN : string; var Dir : string) : boolean; -const waitT : word = 1; - Trials : integer = 5; -var i : integer; - sdd : TSelectDirectoryDialog; -begin - Result:= false; - i:= 1; - while (not Result) and (i < Trials) do - begin - Result:= FileExists(Dir + FN); - if (not Result) then - Sleep(1000 * waitT); - inc(i); - end; - if not Result then - begin - sdd:= TSelectDirectoryDialog.Create(frmMain); - sdd.Title:= 'Geef map met ' + FN; - sdd.Filter:= 'XML bestand|*.xml'; - sdd.FilterIndex:= 0; - if sdd.Execute then - begin - Dir:= sdd.FileName + Slash; - Result:= FileExists(Dir + FN); - end; - sdd.free; -// ShowNotification(frmMain, FN + 'niet gevonden.' + #10#13 + 'BrouwHulp sluit af'); - end; -end; - -Function Convert(FromUnit : TUnit; ToUnit : TUnit; val : double) : double; -begin -// TUnit = (milligram, gram, kilogram, milliliter, liter, hectoliter, IBU, EBC, SRM, -// SG, plato, brix, celcius, fahrenheit, minuut, uur, dag, week, ppm, -// volco2, abv, perc, euro, pH, pph, calgdeg, empty); - Result:= val; - case FromUnit of - milligram: - case ToUnit of - gram: Result:= val / 1000; - kilogram: Result:= val / 1000000; - end; - gram: - case ToUnit of - milligram: Result:= 1000 * val; - kilogram: Result:= val / 1000; - end; - kilogram: - case ToUnit of - milligram: Result:= 1000000 * val; - gram: Result:= 1000 * val; - end; - milliliter: - case ToUnit of - liter: Result:= val / 1000; - hectoliter: Result:= val / 100000; - end; - liter: - case ToUnit of - milliliter: Result:= 1000 * val; - hectoliter: Result:= 100 * val; - end; - hectoliter: - case ToUnit of - milliliter: Result:= 100000 * val; - liter: Result:= 100 * val; - end; - meter: - case ToUnit of - centimeter: Result:= 100 * val; - end; - centimeter: - case ToUnit of - meter: Result:= val / 100; - end; - EBC: - case ToUnit of - SRM: Result:= EBCtoSRM(val); - end; - SRM: - case ToUnit of - EBC: Result:= SRMtoEBC(val); - end; - SG: - case ToUnit of - plato: Result:= SGtoPlato(val); - brix: Result:= SGToPlato(val) * Settings.BrixCorrection.Value; - end; - plato: - case ToUnit of - SG: Result:= PlatoToSG(val); - brix: Result:= val * Settings.BrixCorrection.Value; - end; - brix: - if Settings.BrixCorrection.Value > 0 then - case ToUnit of - SG: Result:= PlatoToSG(val / Settings.BrixCorrection.Value); - plato: Result:= val / Settings.BrixCorrection.Value; - end; - celcius: - case ToUnit of - fahrenheit: Result:= CtoF(val); - end; - fahrenheit: - Case ToUnit of - celcius: Result:= FtoC(val); - end; - minuut: - case ToUnit of - uur: Result:= val / 60; - dag: Result:= val / (60 * 24); - week: Result:= val / (60 * 24 * 7); - end; - uur: - case ToUnit of - minuut: Result:= val * 60; - dag: Result:= val / 24; - week: Result:= val / (7 * 24); - end; - dag: - case ToUnit of - minuut : Result:= val * (60 * 24); - uur : Result:= val * 24; - week: Result:= val / 7; - end; - week: - case ToUnit of - minuut: Result:= val * 7 * 24 * 60; - uur: Result:= val * 7 * 24; - dag : Result:= val * 7; - end; - kPa: - case ToUnit of - bar: Result:= val / 100; - end; - bar: - case ToUnit of - kPa: Result:= 100 * val; - end; - lintner: - case ToUnit of - windischkolbach: Result:= 3.5 * val - 16; - end; - windischkolbach: - case ToUnit of - lintner: Result:= (val + 16) / 3.5; - end; - end; -end; - -Procedure ConvertSeconds(var h, m, s, mi : word); -begin - mi:= 0; - m:= s div 60; - s:= s mod 60; - h:= m div 60; - m:= m mod 60; -end; - -Function Sinus(angle : double) : double; //angle in degrees -var rad : double; -begin - rad:= 2 * PI * angle/360; - Result:= Sin(rad); -end; - -Function Cosinus(angle : double) : double; //angle in degrees -var rad : double; -begin - rad:= 2 * PI * angle/360; - Result:= Cos(rad); -end; - -Function Between(value, low, high : double) : boolean; -begin - Result:= false; - if (value >= low) and (value <= high) then Result:= TRUE; -end; - -Function MaxD(a, b : double) : double; -begin - if a > b then result:= a else result:= b; -end; - -Function MinD(a, b : double) : double; -begin - if a < b then result:= a else result:= b; -end; - -Function MaxA(a : array of double) : double; -var i : integer; -begin - Result:= a[Low(a)]; - for i:= Low(a) + 1 to High(a) do - if a[i] > Result then - Result:= a[i]; -end; - -Function MinA(a : array of double) : double; -var i : integer; -begin - Result:= a[Low(a)]; - for i:= Low(a) + 1 to High(a) do - if a[i] < Result then - Result:= a[i]; -end; - -Function MinI(a, b : integer) : integer; -begin - if a < b then Result:= a - else Result:= b; -end; - -Function MaxI(a, b : integer) : integer; -begin - if a > b then Result:= a - else Result:= b; -end; - -Function RoundUp( R : Double) : LongInt; -begin - Result:= Trunc(R); - if R < 0 then Result:= Trunc(R) - 1 - else if R > 0 then Result:= Trunc(R) + 1; -end; - -Function InvLog(i : double) : double; -begin - Result:= power(10, i); -end; - -Procedure SwapW(var a, b : double); -var c : double; -begin - c:= b; - b:= a; - a:= c; -end; - -Function DecimalsSc( S: Double): LongInt; -begin - if Abs(S) < 1 then Result:= Abs(Order(S)) - else Result:= 0; -end; - -Function GetOrdinals( S : Extended) : LongInt; -var AbsS : Extended; -begin - AbsS:= Abs(S); - if AbsS < 1 then result:= 1 {0,..} - else Result:= Trunc(Log10(AbsS)) + 1; - if S < 0 then Inc(Result); {Minus-sign} -end; - -Function GetDecimals( S : Double) : LongInt; -begin - if (ABS(S) < 100) and (S <> 0) then - begin - if S >= 1 then Result:= 1 - Trunc( log10(ABS(S)) ) - else Result:= Abs(Order(S)) + 2; - end - else Result:= 0; -end; - -Function TLC(s : string) : string; -begin - Result:= Trim(LowerCase(s)); -end; - -Function FormatString(S : extended; D : LongInt) : String; -var O : LongInt; -begin - O:= GetOrdinals(S); - if D > 0 then O:= O + 1 + D; - Result:= '%' + IntToStr(O) + '.' + IntToStr(D) + 'f'; - FmtStr(Result, Result, [S]); -end; - -Function StringFormat( S, X : Double; D : SmallInt) : string; -var Total, Whole, dec : LongInt; -begin - if (ABS(S) < 100) and (S <> 0) and (D < 0) then - begin - if S >= 1 then Dec:= 1 - Trunc( log10(ABS(S)) ) - else Dec:= Abs(Order(S)) + 2; - end - else if (ABS(S) < 100) and (S <> 0) and (D >= 0) then - Dec:= D - else Dec:= 0; - - if X > 1 then Whole:= Trunc(log10(abs(X))) + 1 - else Whole:= 1; - - if Dec > 0 then Total:= Whole + Dec + 1 - else Total:= Whole; - - if X < 0 then Inc(Total); - - Result:= '%' + IntToStr(Total) + '.' + IntToStr(Dec) + 'f'; -end; - -Function RealToStr( S : Double) : string; -var StrF : string; - Total, D : LongInt; -begin - Total:= GetOrdinals(S); - D:= GetDecimals(S); - if D > 0 then Total:= Total + 1 + D; - StrF:= '%' + IntToStr(Total) + '.' + IntToStr(D) + 'f'; - - FmtStr(Result, StrF, [S]); -end; - -Function RealToStrSci(S : Double; Prec : LongInt) : string; -var StrF, str : string; - p : LongInt; -begin - StrF:= '%.' + IntToStr(Prec) + 'e'; - FmtStr(Result, StrF, [S]); - p:= pos('E', Result) + 1; - str:= Copy(Result, p, Length(Result) - p + 1); - result:= copy(result, 1, p - 1); - result:= result + IntToStr(StrToInt(str)); -end; - -Function RealToStrDEC( S : Double; D : SmallInt) : string; -var StrF : string; - Total : LongInt; -begin - Total:= GetOrdinals(S); - if D > 0 then - begin - Total:= Total + 1 + D; - StrF:= '%' + IntToStr(Total) + '.' + IntToStr(D) + 'f'; - FmtStr(Result, StrF, [S]); - end - else Result:= IntToStr(Round(S)); -end; - -Function RealToStrSignif(S : Double; Signif : SmallInt) : string; -var O, D : LongInt; -begin - O:= GetOrdinals(S); - if O > Signif then Result:= RealToStrSci(S, Signif) - else if GetDecimals(S) <= Signif then - begin - D:= Signif - O; - Result:= RealToStrDec(S, D); - end - else Result:= RealToStrSci(S, Signif); -end; - -Function Pos2(LS, S : string) : LongInt; -var i : LongInt; -begin - Result:= -1; - for i:= 1 to Length(S) do - begin - if S[i] = LS then Result:= i; - end; -end; - -Function StrToReal( S : string) : Double; -var Code, p : integer; - SO : string; - D : double; -begin - Code:= 0; - try - p:= Pos2(DecimalSeparator, S); - if (p >= 0) and (p < Length(S)) then S[p]:= '.'; - Val(S, D, Code); - Result:= D; - except - SO:= Copy(S, Code, 1); - ShowMessage('Fout in conversie van tekst naar getal (karakter ' + SO + ')'); - Result:= 0; - end; -end; - -Function ValidateRealStr(S : string) : boolean; -var Code, p : integer; - SO : string; - D : double; -begin - Code:= 0; - try - p:= Pos2(DecimalSeparator, S); - if (p >= 0) and (p < Length(S)) then S[p]:= '.'; - Val(S, D, Code); - Result:= TRUE; - except - SO:= Copy(S, Code, 1); - ShowMessage('Fout in conversie van tekst naar getal (karakter ' + SO + ')'); - Result:= false; - end; -end; - -Function Order( R : Double) : SmallInt; -begin - if R = 0 then Result:= 0 - else - begin - if Abs(R) >= 1 then - begin - Result:= Trunc(Log10(Abs(R))); - end - else Result:= Trunc(Log10(Abs(R)))-1; - end; -end; - -{function MyStrToDate(DateStr: String): TDateTime; -var - F: TFormatSettings; - s: String; - i: Integer; - separator: integer; -begin - GetLocaleFormatSettings(0, F); - F.ShortDateFormat := 'd-m-yyyy'; - F.ShortTimeFormat := 'hh:mm:ss'; - F.DateSeparator := '-'; - F.TimeSeparator := ':'; - - separator := Pos(F.DateSeparator, DateStr); - - if separator = 0 then - Raise Exception.Create('No date separator in date ' + DateStr); - - s := Copy(DateStr, 1, separator-1 ); - - i := High(ShortMonthNames); - - while ( i >= Low(ShortMonthNames) ) and not SameText ( s, ShortMonthNames[i] ) do - dec ( i ); - - s := IntToStr(i) + Copy ( DateStr, separator, length(DateStr) ); - if i >= Low(ShortMonthNames) then - result := StrToDateTime ( s, F ) - else - Raise Exception.Create('Could not convert the date ' + DateStr) -end;} - -Function StringToDate(s : string) : TDateTime; -var ns : string; - rf : TReplaceFlags; -const OldPattern : array[0..19] of string = (' ', '/', '\', '.', '. ', 'jan', 'feb', 'mrt', 'mar', 'apr', 'mei', 'may', 'jun', 'jul', 'aug', 'sep', 'okt', 'oct', 'nov', 'dec'); - NewPattern : array[0..19] of string = ('-', '-', '-', '-', '-', '1', '2', '3', '3', '4', '5', '5', '6', '7', '8', '9', '10', '10', '11', '12'); -begin - rf:= [rfReplaceAll, rfIgnoreCase]; - ns:= StringsReplace(s, OldPattern, NewPattern, rf); - - Result:= 0; - - if s <> 'NTB' then - begin - LongTimeFormat := 'hh:mm:ss'; - ShortDateFormat := 'DD-MM-YYYY'; - DateSeparator := '-'; - TimeSeparator := ':'; - try - Result:= StrToDate(ns); - except - Result:= 0; - end; - if Result = 0 then - begin - ShortDateFormat := 'DD-MM-YY'; - try - Result:= StrToDate(ns); - except - Result:= 0; - end; - end; - if Result = 0 then - begin - ShortDateFormat := 'MM-DD-YY'; - try - Result:= StrToDate(ns); - except - Result:= 0; - end; - end; - if Result = 0 then - begin - ShortDateFormat := 'YY-MM-DD'; - try - Result:= StrToDate(ns); - except - Result:= 0; - end; - end; - if Result = 0 then - begin - ShortDateFormat := 'YYYY-MM-DD'; - try - Result:= StrToDate(ns); - except - Result:= 0; - end; - end; - if Result = 0 then - begin - ShortDateFormat := 'D-M-YY'; - try - Result:= StrToDate(ns); - except - Result:= 0; - end; - end; - if Result = 0 then - begin - ShortDateFormat := 'M-D-YYYY'; - try - Result:= StrToDate(ns); - except - Result:= 0; - end; - end; - if Result = 0 then - begin - ShortDateFormat := 'M-D-YY'; - try - Result:= StrToDate(ns); - except - Result:= 0; - end; - end; - if Result = 0 then - begin - ShortDateFormat := 'YY-M-D'; - try - Result:= StrToDate(ns); - except - Result:= 0; - end; - end; - if Result = 0 then - begin - ShortDateFormat := 'YYYY-M-D'; - try - Result:= StrToDate(ns); - except - Result:= 0; - end; - end; - end; -end; - -Function IsValidDate(s : string) : boolean; -begin - Result:= (StringToDate(s) > 0); -end; - -Function StringToTime(s : string) : TDateTime; -begin - LongTimeFormat := 'hh:mm:ss'; - ShortDateFormat := 'DD-MM-YYY'; - DateSeparator := '-'; - TimeSeparator := ':'; - try - Result:= StrToTime(s); - except - Result:= 0; - end; -end; - -Function IsValidTime(s : string) : boolean; -begin - Result:= (StringToTime(s) > 0); -end; - -Function SetDecimalSeparator(Sin : string) : string; -var OldPattern : array[0..0] of string; - NewPattern : array[0..0] of string; - rf : TReplaceFlags; -begin - rf:= [rfReplaceAll, rfIgnoreCase]; - OldPattern[0]:= '.'; - NewPattern[0]:= DefaultFormatSettings.DecimalSeparator; - Result:= StringsReplace(Sin, OldPattern, NewPattern, rf); -end; - -Function SetDecimalPoint(Sin : string) : string; -var OldPattern : array[0..0] of string; - NewPattern : array[0..0] of string; - rf : TReplaceFlags; -begin - rf:= [rfReplaceAll, rfIgnoreCase]; - OldPattern[0]:= DefaultFormatSettings.DecimalSeparator; - NewPattern[0]:= '.'; - Result:= StringsReplace(Sin, OldPattern, NewPattern, rf); -end; - -Function CountSubssInString(s, sub : string) : integer; -var i, lsub : integer; - ssub : string; -begin - Result:= 0; - lsub:= length(sub); - for i:= 0 to Length(s) - lsub + 1 do - begin - ssub:= midstr(s, i, lsub); - if ssub = sub then - Inc(Result); - end; -end; - -Function IsInString(searchString, SubString : string) : boolean; -begin - Result:= false; - Result:= countsubssinstring(lowercase(searchstring), LowerCase(SubString)) > 0; -end; - -Function FloatToStringDec(d : double; Dec: integer) : string; -begin - Result:= RealToStrDec(d, Dec); -end; - -Function FloatToDisplayString(d : double; Dec : integer; u : string) : string; -begin - Result:= RealToStrDec(d, Dec) + ' ' + u; -end; - -Function IntToDisplayString(i : integer; u : string) : string; -begin - Result:= IntToStr(i) + ' ' + u; -end; - -Function SolveQuadratic(a, b, c : double; var X1, X2 : double) : integer; -var D : double; -begin - X1:= 0; X2:= 0; - Result:= 0; - D:= b * b - 4 * a * c; - if D < 0 then Result:= 0 - else if D = 0 then Result:= 1 - else Result:= 2; - if (Result = 1) and (a > 0) then - begin - X1:= -b / (2 * a); - end - else if (Result = 2) and (a <> 0) then - begin - X1:= (-b - SQRT(D)) / (2 * a); - X2:= (-b + SQRT(D)) / (2 * a); - end; -end; - -Function SolveCubic(a, b, c, d : double; var X1, X2, X3 : double) : integer; -var Di, E : double; -begin - Result:= 0; - X1:= 0; X2:= 0; X3:= 0; - Di:= 4 * Power(-b*b + 3*a*c, 3) + - Power(-2 * Power(b, 3) + 9*a*b*c - 27*a*a*d, 2); - if (Di > 0) and (a <> 0) and (E <> 0) then - begin - E:= Power(-2*b*b*b + 9*a*b*c - 27*a*a*d + SQRT(Di), 1/3); - X1:= -b/(3*a) - (Power(2, 1/3) * (-b*b+3*a*c)) / (3 * a * E) - + E / (3 * Power(2, 1/3) * a); - end; -end; - -Procedure QuickSortArray(var Arr : array of double); - procedure QuickSort(var A: array of double; iLo, iHi: Integer); - var Lo, Hi: Integer; - Mid, T : double; - begin - Lo := iLo; - Hi := iHi; - Mid := A[(Lo + Hi) div 2]; - repeat - while A[Lo] < Mid do Inc(Lo); - while A[Hi] > Mid do Dec(Hi); - if Lo <= Hi then - begin - T := A[Lo]; - A[Lo] := A[Hi]; - A[Hi] := T; - Inc(Lo); - Dec(Hi); - end; - until Lo > Hi; - if Hi > iLo then QuickSort(A, iLo, Hi); - if Lo < iHi then QuickSort(A, Lo, iHi); - end; -begin - QuickSort(Arr, Low(Arr), High(Arr)); -end; - -Procedure SelectionSortArray(var List : array of double); -var - i, j, best_j : integer; - best_value : double; -begin - for i := Low(List) to High(List) - 1 do - begin - best_value := List[i]; - best_j := i; - for j := i + 1 to High(List) do - begin - if (List[j] < best_value) Then - begin - best_value := List[j]; - best_j := j; - end; - end; // for j := i + 1 to max do - List[best_j] := List[i]; - List[i] := best_value; - end; // for i := min to max - 1 do -end; - -Procedure ShowNotification(sender : TComponent; s : string); -begin - if FrmNotification = NIL then - begin - FrmNotification:= TFrmNotification.Create(sender); - FrmNotification.ShowFrm(s); - end - else if FrmNotification.Showing then - FrmNotification.AddText(s) - else - begin - FreeAndNIL(FrmNotification); - FrmNotification:= TFrmNotification.Create(sender); - FrmNotification.ShowFrm(s); - end; -end; - -Procedure ShowNotificationModal(sender : TComponent; s : string); -begin - FrmNotification:= TFrmNotification.Create(sender); - FrmNotification.Execute(s); -end; - -Function Question(sender : TComponent; s : string) : boolean; -begin - FrmQuestion:= TFrmQuestion.Create(sender); - Result:= FrmQuestion.Question(s); - FreeAndNil(frmQuestion); -end; - -Function GetAnswer(sender : TComponent; Q : string) : string; -begin - FrmGetString:= TFrmGetString.Create(sender); - Result:= FrmGetString.GetAnswer(Q); - FreeAndNil(FrmGetString); -end; - -Function GetPasswd(sender : TComponent) : string; -begin - FrmGetPasswd:= TFrmGetPasswd.Create(sender); - Result:= FrmGetPasswd.GetAnswer; - FreeAndNil(FrmGetString); -end; - -{Graph related functions} - -Procedure CalcScale(var Min, Max, De : double; var AStr : LongInt); -var Lg, Fr : double; - Ast : LongInt; -Const StrMax = 15; - StrMin = 6; -begin - if Min <> 0 then De:= InvLog(Order(Min)) - else if Max <> 0 then De:= InvLog(Order(Max)); - - if De <> 0 then ASt:= round(Abs(Max - Min)/ De) - else Ast:= StrMin; - While ((Ast < StrMin) or (Ast > StrMax)) and (De <> 0) do - begin - ASt:= round(Abs(Max - Min)/ De); - - Lg:= Log10(De); - if Frac(Lg) = 0 then Lg:= De - else if (Lg < 0) then Lg:= InvLog(Trunc(Lg) - 1) - else Lg:= InvLog(Trunc(Lg)); - Fr:= De / Lg; - if Fr > 5 then Fr:= 1; - if Fr < 1 then Fr:= 5; - if Ast <= 2 then De:= 0.1 * De - else if Ast >= 100 then De:= 10 * De - else if Ast < StrMin then - begin - if (Fr > 0.9) and (Fr < 1.1) then De:= De / 2 - else if (Fr > 4.9) and (Fr < 5.1) then De:= De / 2 - else if (Fr > 2.4) and (Fr < 2.6) then De:= De / 2.5; - end - else if Ast > StrMax then - begin - if (Fr > 0.9) and (Fr < 1.1) then De:= De * 2.5 - else if (Fr > 4.9) and (Fr < 5.1) then De:= De * 2 - else if (Fr > 2.4) and (Fr < 2.6) then De:= De * 2; - end; - end; - if De > 0 then - begin - if Frac(Min / De) <> 0.0 then - begin - if Min > 0 then Min:= Trunc(Min / De) * De - else Min:= (Trunc(Min / De) - 1) * De; - end; - if Frac(Max / De) <> 0.0 then - begin - if Max > 0 then Max:= (Trunc(Max / De) + 1) * De - else Max:= Trunc(Max / De) * De; - end; - AStr:= round(Abs(Max - Min)/ De); - if Min > Max then SwapW(Min, Max); - end; -end; - -Function RoundOrder( R : double) : double; -begin - Result:= Int(R / InvLog(Order(R))) * InvLog(Order(R)); -end; - -Function OrderHigh( R : double) : integer; -begin - if Frac(Log10(R)) = 0 then Result:= Order(R) - else Result:= Order(R) + 1; -end; - -Function RoundOrderHigh( R : double) : double; -begin - Result:= RoundUp(R / InvLog(Order(R))) * InvLog(Order(R)); -end; - -Procedure Scaling(var Min, Max, De : double; var Astr : LongInt); -var SignMin, SignMax : ShortInt; -begin - SignMin:= Sign(Min); SignMax:= Sign(Max); - if ((Min >= 0) and (Max >= 0)) then - begin - If Order(Min) = Order(Max) then - begin - Min:= RoundOrder(Min); Max:= RoundOrderHigh(Max); - end - else - begin - Min:= 0; Max:= RoundOrderHigh(Max); - end; - CalcScale(Min, Max, De, AStr); - end - else if ((Min <= 0) and (Max <= 0)) then - begin - if Order(Min) = Order(Max) then - begin - Min:= RoundOrderHigh(Min); Max:= RoundOrder(Max); - end - else - begin - Min:= RoundOrderHigh(Min); Max:= 0; - end; - CalcScale(Min, Max, De, AStr); - end - else - begin - if Order(Min) = Order(Max) then - begin - Min:= RoundOrderHigh(Min); Max:= RoundOrderHigh(Max); - end - else if Order(Min) > Order(Max) then - begin - Min:= RoundOrderHigh(Min); Max:= -Min; - end - else if Order(Max) > Order(Min) then - begin - Max:= RoundOrderHigh(Max); Min:= -Max; - end; - CalcScale(Min, Max, De, AStr); - end; - - {RelativeRound(Min, Max, De);} - if Sign(Min) <> SignMin then Min:= Abs(Min) * SignMin; - if Sign(Max) <> SignMax then Max:= Abs(Max) * SignMax; - if (Abs(round(Max) - Max) < abs(0.001 * Max)) and (abs(Max) > 1) then - Max:= round(Max); - if (Abs(round(Min) - Min) < abs(0.001 * Min)) and (abs(Min) > 1) then - Min:= round(Min); -end; - -Procedure ScaleDate(var Min, Max, De : TDateTime; var Astr : LongInt); -var //Y1, M1, D1 : longint; - Y2, M2, D2 : word; -{Const StrMax = 15; - StrMin = 6;} -begin -// DecodeDate(Min, Y1, M1, D1); - DecodeDate(Max, Y2, M2, D2); -{ case M2 of - 1, 3, 5, 7, 8, 10, 12 : D2:= 31; - 4, 6, 9, 11 : D2:= 30; - 2 : if Y2 mod 4 = 0 then D2:= 29 else D2:= 28; - end;} - - { Min:= EncodeDate(Y1, M1, 1); - Max:= EncodeDate(Y2, M2, D2);} - AStr:= 6; - De:= (Max - Min) / 6; -end; - -Procedure ScaleFixed(var Min, Max, De : double; var Astr : LongInt); -var Lg, Fr : double; - Ast : LongInt; -Const StrMax = 15; - StrMin = 6; -begin - ASt:= round(Max); - De:= 1; - While ((Ast < StrMin) or (Ast > StrMax)) and (De <> 0) do - begin - ASt:= round((Max) / De); - - Lg:= Log10(De); - if Frac(Lg) = 0 then Lg:= De - else if (Lg < 0) then Lg:= InvLog(Trunc(Lg) - 1) - else Lg:= InvLog(Trunc(Lg)); - Fr:= De / Lg; - if Fr > 5 then Fr:= 1; - if Fr < 1 then Fr:= 5; - if Ast <= 2 then De:= 0.1 * De - else if Ast >= 100 then De:= 10 * De - else if Ast < StrMin then - begin - if (Fr > 0.9) and (Fr < 1.1) then De:= De / 2 - else if (Fr > 4.9) and (Fr < 5.1) then De:= De / 2 - else if (Fr > 2.4) and (Fr < 2.6) then De:= De / 2.5; - end - else if Ast > StrMax then - begin - if (Fr > 0.9) and (Fr < 1.1) then De:= De * 2.5 - else if (Fr > 4.9) and (Fr < 5.1) then De:= De * 2 - else if (Fr > 2.4) and (Fr < 2.6) then De:= De * 2; - end; - end; - if De <> 0 then - begin - if Frac(Min / De) <> 0.0 then - begin - if Min > 0 then Min:= Trunc(Min / De) * De - else Min:= (Trunc(Min / De) - 1) * De; - end; - if Frac(Max / De) <> 0.0 then - begin - if Max > 0 then Max:= (Trunc(Max / De) + 1) * De - else Max:= Trunc(Max / De) * De; - end; - AStr:= round((Max) / De); - end; -end; - -Function DrawTxt( Canvas : TCanvas; MiddleHeight, Left, Right : LongInt; - Text : string; Alignment : TAlignment; - MoreLines : boolean) : integer; -var BoxWidth, X, AmountLines, counter, MH, Pos : LongInt; - Rec : TRect; - s : string; -begin - Rec.Right:= Right; Rec.Left:= Left; Result:= 0; - X:= 0; AmountLines:= 0; - with Canvas do - begin - BoxWidth:= Rec.Right - Rec.Left; - if MoreLines then - begin - Pos:= CalcMaxWidth(Canvas, Text); - BoxWidth:= MaxI(BoxWidth, Pos); - AmountLines:= CalcAmountLines(Canvas, Text, BoxWidth); - Result:= AmountLines * TextHeight(Text); - end - else Result:= TextHeight(Text); - Rec.Left:= Left; - Rec.Right:= Right; - Pos:= 1; - if MoreLines then - begin - for counter:= 1 to AmountLines do - begin - s:= GiveNextLine(Canvas, Text, BoxWidth, Pos); - MH:= MiddleHeight + round(-0.5 * Result + (counter - 0.5) * TextHeight(Text)); - Rec.Top:= MH - round(0.5 * TextHeight(Text)); - Rec.Bottom:= Rec.Top + TextHeight(Text); - - if Alignment = taLeftJustify then X:= Rec.Left - else if Alignment = taRightJustify then X:= MaxI(Rec.Right - TextWidth(s), 0) - else if Alignment = taCenter then X:= Rec.Left + round(0.5 * (BoxWidth - TextWidth(s))); - TextRect(Rec, X, Rec.Top, s); - end; - end - else - begin - Rec.Top:= MiddleHeight - round(0.5 * TextHeight(Text)); - Rec.Bottom:= Rec.Top + TextHeight(Text); - if Alignment = taLeftJustify then X:= Rec.Left - else if Alignment = taRightJustify then X:= MaxI(Rec.Right - TextWidth(Text), 0) - else if Alignment = taCenter then X:= MaxI(Rec.Left + round(0.5 * (BoxWidth - TextWidth(Text))), 0); - TextRect(Rec, X, Rec.Top, Text); - end; - end; - Result:= Rec.Bottom; -end; - -Procedure DrawTxtVarRct(canvas : TCanvas; Text : string; var R : TRect); -var TW : integer; -begin - TW:= canvas.TextWidth(Text); - R.Right:= R.Left + TW; - TW:= canvas.TextHeight(Text); - R.Bottom:= R.Top + TW; -end; - -Function DrawTxtRct( Canvas : TCanvas; R : TRect; - Text : string; Alignment : TAlignment; - MoreLines : boolean) : integer; -var BoxWidth, X, AmountLines, counter, TH, Pos : LongInt; - s : string; -begin - Result:= 0; - X:= 0; AmountLines:= 0; - with Canvas do - begin - BoxWidth:= R.Right - R.Left; - if MoreLines then - begin - Pos:= CalcMaxWidth(Canvas, Text); - BoxWidth:= MaxI(BoxWidth, Pos); - AmountLines:= CalcAmountLines(Canvas, Text, BoxWidth); - Result:= AmountLines * TextHeight(Text); - end - else Result:= TextHeight(Text); - TH:= TextHeight(Text); - Pos:= 1; - if MoreLines then - begin - for counter:= 1 to AmountLines do - begin - s:= GiveNextLine(Canvas, Text, BoxWidth, Pos); - if Alignment = taLeftJustify then X:= R.Left - else if Alignment = taRightJustify then X:= MaxI(R.Right - TextWidth(s), 0) - else if Alignment = taCenter then X:= R.Left + round(0.5 * (BoxWidth - TextWidth(s))); - TextRect(R, X, R.Top + (counter - 1) * TH , s); - end; - end - else - begin - if Alignment = taLeftJustify then X:= R.Left - else if Alignment = taRightJustify then X:= MaxI(R.Right - TextWidth(Text), 0) - else if Alignment = taCenter then X:= MaxI(R.Left + round(0.5 * (BoxWidth - TextWidth(Text))), 0); - TextRect(R, X, R.Top, Text); - end; - end; - Result:= R.Bottom; -end; - -Function RotateText(Canvas : TCanvas; Xt, Yl, Deg : LongInt; Txt : string; - BackColor : tColor; Transparant : boolean) : boolean; -var Bitmap : TBitmap; - Rec: TRect; - P1, P5, P6 : TPoint; - X, Y, W, H : LongInt; - Angle, Si, Co : double; -begin - Result:= false; - Rec:= Rect(0, 0, Canvas.TextWidth(Txt), Canvas.TextHeight(Txt)); - Bitmap:= TBitmap.Create; - Bitmap.PixelFormat:= pfDevice; - with Bitmap.Canvas do - begin - Font.Assign(Canvas.Font); - Pen.Assign(Canvas.Pen); - Brush.Assign(Canvas.Brush); - end; - Bitmap.Width:= Rec.Right - Rec.Left; - Bitmap.Height:= Rec.Bottom - Rec.Top; - Bitmap.Canvas.Rectangle(0, 0, Bitmap.Width, Bitmap.Height); - Bitmap.Canvas.TextRect(Rec, 1, 1, Txt); - Angle:= Deg/180*PI; - Si:= Sin(Angle); Co:= Cos(Angle); - W:= Rec.Right - Rec.Left; - H:= Rec.Bottom - Rec.Top; - P1.X:= Xt - round(0.5 * W * Co + 0.5 * H * Si); - P1.Y:= Yl - round(-0.5 * W * Si + 0.5 * H * Co); - if P1.X < 0 then P1.X:= 0; - if P1.Y < 0 then P1.Y:= 0; - - for Y:= 0 to Bitmap.Height - 2 do - begin - X:= 0; - P5.X:= P1.X + round(Y * Si); P5.Y:= P1.Y + round(Y * Co); - for X:= 0 to Bitmap.Width - 1 do - begin - P6.X:= P5.X + round(X * Co); P6.Y:= P5.Y - round(X * Si); - - if TransParant and ((Canvas.Pixels[P6.X, P6.Y] = BackColor) or (Canvas.Pixels[P6.X, P6.Y] = Canvas.Brush.Color)) then - Canvas.Pixels[P6.X, P6.Y]:= Bitmap.Canvas.Pixels[X, Y] - else if not Transparant then - Canvas.Pixels[P6.X, P6.Y]:= Bitmap.Canvas.Pixels[X, Y]; - end; - end; - Result:= TRUE; -end; - -Function GiveNextLine( Canvas : TCanvas; Text : string; - Width : LongInt; var Pos : LongInt) : string; -var LineTst, Wrd : string; - PosOld : longint; -begin - Result:= ''; LineTst:= ''; PosOld:= Pos; - repeat - Wrd:= NextWord(Text, Pos); - LineTst:= LineTst + Wrd; - if Canvas.TextWidth(LineTst) <= Width then - begin - if Pos <= Length(Text) then LineTst:= LineTst + ' '; - Result:= LineTst; - PosOld:= Pos; - end; - until ((PosOld <> Pos) or (Canvas.TextWidth(Result) >= width) or (Pos > Length(Text))); - Pos:= PosOld; -end; - -Function NextWord( Line : string; var Pos : LongInt) : string; -var Ch : string[1]; -begin - Result:= ''; - repeat - Ch:= Copy(Line, Pos, 1); - if (Ch <> ' ') then Result:= Result + Ch; - Inc(Pos); - until (Ch = ' ') or (Pos > Length(Line)); -end; - -Function RemInvChars(S : string) : string; -var i : integer; - C : char; - invCh : char; -begin - Result:= ''; - invch:= Char(0); - i:= 1; - Repeat - C:= S[i]; - if C <> invch then Result:= Result + S[i]; - inc(i); - until ((C = invch) or (i > Length(S))); -end; - -Function CalcTextHeight( FontSize, PPIY : integer) : integer; -begin - {Room for caption : } - Result:= round(FontSize * PPIY / 72); -end; - -Function CalcAmountLines( Canvas : TCanvas; Text : string; Width : LongInt) : LongInt; -var Pos : LongInt; - Line, LineTst, Wrd : string; -begin - Result:= 0; Pos:= 1; Wrd:= ''; - repeat - Line:= Wrd; LineTst:= Wrd; - repeat - Wrd:= NextWord(Text, Pos); - LineTst:= LineTst + ' ' + Wrd; - if Canvas.TextWidth(LineTst) <= Width then Line:= LineTst; - until (Canvas.TextWidth(LineTst) >= Width) or (Pos >= Length(Text)); - Inc(Result); - until Pos >= length(Text); - if LineTst <> Line then Inc(Result); -end; - -Function CalcAmountLines2(Font : TFont; Text : string; Width : LongInt) : LongInt; -var Pos : LongInt; - Line, LineTst, Wrd : string; - bmp : TBitmap; -begin - Result:= 0; - if Width > 0 then - begin - bmp:= TBitmap.Create; - bmp.Canvas.Font.Assign(Font); - Result:= 0; Pos:= 1; Wrd:= ''; - repeat - Line:= Wrd; LineTst:= Wrd; - repeat - Wrd:= NextWord(Text, Pos); - LineTst:= LineTst + ' ' + Wrd; - if bmp.Canvas.TextWidth(LineTst) <= Width then Line:= LineTst; - until (bmp.Canvas.TextWidth(LineTst) >= Width) or (Pos >= Length(Text)); - Inc(Result); - until Pos >= length(Text); - if LineTst <> Line then Inc(Result); - if Result > 1 then - bmp.Free - else - bmp.Free; - end; -end; - -Function CalcMaxWidth( Canvas : TCanvas; Text : string) : LongInt; -var Wrd : string; - Pos : LongInt; -begin - Result:= 0; - Pos:= 1; - while Pos <= Length(Text) do - begin - Wrd:= NextWord(Text, Pos); - if Canvas.TextWidth(Wrd) > Result then Result:= Canvas.TextWidth(Wrd); - end; -end; - -{============================= Brewing functions ==============================} - -Function CalcFrac(TpH, pK1, pK2, pK3 : double) : double; -var r1d, r2d, r3d, dd, f1d, f2d, f3d, f4d : double; -begin - r1d:= Power(10, TpH - pK1); - r2d:= Power(10, TpH - pK2); - r3d:= Power(10, TpH - pK3); - dd:= 1/(1 + r1d + r1d*r2d + r1d*r2d*r3d); - f1d:= dd; - f2d:= r1d*dd; - f3d:= r1d*r2d*dd; - f4d:= r1d*r2d*r3d*dd; - Result:= f2d + 2*f3d + 3*f4d; -end; - -Function SRMtoEBC(d : double) : double; -begin - Result:= 1.76506E-10 * Power(d, 4) + 1.54529E-07 * Power(d, 3) - 1.59428E-04 * SQR(d) - + 2.68837E+00 * d - 1.60040E+00; - If Result < 0 Then - Result:= 0; -end; - -Function EBCtoSRM(d : Double) : Double; -begin - Result:= -1.32303E-12 * Power(d, 4) - 0.00000000291515 * Power(d, 3) - + 0.00000818515 * SQR(d) + 0.372038 * d + 0.596351; -end; - -Function EBCtoColor(EBC : double) : TColor; -var SRM : Double; -begin - SRM:= EBCtoSRM(EBC); - Result:= SRMtoColor(SRM); -end; - -Function SRMtoColor(SRM : double) : TColor; -var i : integer; - R, G, B : longint; - Found : boolean; -begin - R:= 0; G:= 0; B:= 0; - Found:= false; - i:= 0; - while (not found) and (i <= 299) do - begin - if SRM <= SRMtoRGB[i, 0] then - begin - R:= Round(SRMtoRGB[i, 1]); - G:= Round(SRMtoRGB[i, 2]); - B:= Round(SRMtoRGB[i, 3]); - Found:= TRUE; - end; - Inc(i); - end; - Result:= RGBtoColor(R, G, B); -end; - -Function SGtoPlato(SG : Double) : Double; -begin -// Result:= -0.0000013437885 * Power(SG*1000, 3) + 0.004067348 * SQR(SG*1000) - 3.8532613 * SG*1000 + 1129.6644; - if SG > 0.5 then - Result:= 259 - 259 / SG - else Result:= 0; -end; - -Function PlatoToSG(plato : Double) : Double; -begin -// Result:= 0.0000006077377 * Power(plato, 3) - 0.00001025564 * SQR(plato) + 0.0040681865 * plato + 1; - Result:= 1.000; - if Plato < 259 then Result:= 259 / (259 - plato); -end; - -Function SGtoBrix(SG : Double) : Double; -begin - Result:= SGtoPlato(SG) * Settings.BrixCorrection.Value; -end; - -Function BrixToSG(Brix : Double) : Double; -begin - Result:= 1.000; - if Settings.BrixCorrection.Value > 0 then - Result:= PlatoToSG(Brix / Settings.BrixCorrection.Value); -end; - -Function BrixToFG(OBrix, FBrix : double) : double; -begin - Result:= 1.0031 - 0.002318474 * OBrix - 0.000007775 * (OBrix * OBrix) - - 0.000000034 * Power(OBrix, 3) + 0.00574 * (FBrix) - + 0.00003344 * (FBrix * FBrix) + 0.000000086 * Power(FBrix, 3); -end; - -Function PlatoToExtract(P : Double) : Double; -begin - Result:= 0.0061289 + 0.99464 * P + 0.0042888 * SQR(P); //kg/hl - Result:= 10 * Result; //g/l - If Result < 0 Then Result:= 0; -end; - -Function SGtoExtract(SG : Double) : Double; -begin - Result:= 10 * (-676.67 * SG + 1286.4 * SQR(SG) - 800.47 * Power(SG, 3) + 190.74 * Power(SG, 4)); -end; - -Function ExtractToSG(E : Double) : Double; -begin - Result:= -1.5703394E-14 * Power(E, 4) + 9.2822793E-012 * Power(E, 3) - 0.000000017126328 * Power(E, 2) + 0.00038807583 * E + 1; -end; - -Function BrixToRI(Brix : Double) : Double; -begin - Result:= 1.33302 + 0.001427193 * Brix + 0.000005791157 * SQR(Brix); -end; - -Function FtoC(f : double) : double; -begin - Result:= (f - 32) / 1.8; -end; - -Function CtoF(c : double) : double; -begin - Result:= 1.8 * c + 32 ; -end; - -Function RE(SG : Double; Brix : Double) : Double; -var RI : Double; -begin - RI:= BrixToRI(Brix); - Result:= 194.5935 + 129800 * SG + RI * (410.8815 * RI - 790.8732); -end; - -Function AlcByVol(SG : Double; Brix : Double) : Double; -begin; - Result:= (277.8851 - 277.4 * SG + 0.9956 * Brix + 0.00523 * SQR(Brix) + 0.000015 * Power(Brix, 3)) * (SG / 0.79); -end; - -Function ABVol(OG : Double; FG : Double) : Double; -begin - Result:= 0; - if (4.749804 - FG) <> 0 then - Result:= 486.8693 * (OG - FG) / (4.749804 - FG); -end; - -Function ABW(ABVol : Double; FG : Double) : Double; -begin - Result:= 0; - if FG > 0 then - Result:= ABVol * 794 / (1000 * FG); -end; - -Function ABW2(FG : Double; Brix : Double) : Double; -var RI : Double; -begin - RI:= BrixToRI(Brix); - Result:= 1017.5596 - (0.2774 * FG) + RI * ((937.8135 * RI) - 1805.1228); -end; - -Function SGFerm(OBrix : Double; FBrix : Double) : Double; -begin - Result:= ((1.001843 - 0.002318474 * OBrix - 0.000007775 * SQR(OBrix) - 0.000000034 * Power(OBrix, 3) + 0.00574 * (FBrix) + 0.00003344 * SQR(FBrix) - + 0.000000086 * Power(FBrix, 3)) + (1.313454) * 0.001) * 1000; -end; - -Function RealExtract(FG : Double; Brix : Double) : Double; -var RI : Double; -begin - RI:= BrixToRI(Brix); - Result:= 129.8 * FG + 194.5935 + RI * (410.882 * RI - 790.8732); -end; - -Function Waterdensity(T : Double) : Double; -begin - Result:= 1; - if (1 + 0.01687985 * T) <> 0 then - Result:= (999.83952 + 16.945176 * T - 0.0079870401 * SQR(T) - 0.000046170461 * Power(T, 3) + 0.00000010556302 * Power(T, 4) - 2.8054253E-10 * Power(T, 5)) / (1 + 0.01687985 * T); -end; - -Function pHRoom(pHmash, Tm : double) : double; -begin - Result:= pHmash + 0.0055 * (Tm - 20); -end; - -Function pHMash(pHroom, Tm : double) : double; -begin - Result:= pHRoom - 0.0055 * (Tm - 20); -end; - -Function DwatT(T : double; Tref : Double) : Double; -begin - Result:= Waterdensity(T) / Waterdensity(Tref); -end; - -Function FreezingPoint(SG : Double; FG : Double) : Double; -var SGP : Double; - AlBV : Double; - AlBW : Double; -begin - AlBV:= ABVol(SG, FG); - AlBW:= ABW(AlBV, FG); - SGP:= SGtoPlato(SG); - Result:= -0.42 * AlBW + 0.04 * SGP + 0.2; -end; - -Function StarterSize(types : Integer; soort : Double; V : Double; SG : Double; - start : Double) : double; - -{ types: 0 = simpel, 1 = belucht, 2 = geroerd - soort: 0 = bovengist, 1 = ondergist - V: volume te vergisten wort in liters - SG: startSG te vergisten wort in grammen per l of kilogrammen per liter - start: aantal gistcellen bij aanvang starter in miljard gistcellen - StarterSize: benodigde grootte giststarter in liters} - -var plato : Double; - a : Double; - b : Double; - f : Double; - acellen : Double; -begin - plato:= SGtoPlato(SG); - If soort = 0 Then - f:= 0.75 - Else f:= 1.5; - - acellen:= f * plato * V; //benodigd aantal cellen in miljard cellen - - if types = 0 Then - begin - a:= 0.8473; - b:= 85.577; - end - else If types = 1 Then - begin - a:= 1.02; - b:= 115; - end - else - begin - a:= 1.06302; - b:= 134.78259; - end; - - a:= a * start + b; - b:= 0.434; - - b:= 1 / b; -{ a:= Power((1 / a), b);} - - If acellen <= start Then - Result:= 0 - Else if a <> 0 then - Result:= Power(acellen/a, b); -end; - -Function StarterSize2(types : Integer; Needed : double; start : Double) : double; -{ types: 0 = simpel, 1 = belucht, 2 = geroerd - Needed: aantal te kweken cellen in miljard - start: aantal gistcellen bij aanvang starter in miljard gistcellen - StarterSize: benodigde grootte giststarter in liters} - -var a : Double; - b : Double; -begin - if types = 0 Then - begin - a:= 0.8473; - b:= 85.577; - end - else If types = 1 Then - begin - a:= 1.02; - b:= 115; - end - else - begin - a:= 1.06302; - b:= 134.78259; - end; - - a:= a * start + b; - b:= 0.434; - - b:= 1 / b; -{ a:= Power((1 / a), b);} - - If needed <= start Then - Result:= 0 - Else if a <> 0 then - Result:= Power(needed / a, b); -end; - -Function GrowthFactor(types : Integer; V : Double; start : Double) : double; -{ types: 0 = simpel, 1 = belucht, 2 = geroerd - V: volume van de giststarter, in liters - start: aantal gistcellen bij aanvang starter, in miljard gistcellen - Result: groeifactor} - -var a : Double; - b : Double; -begin - If types = 0 Then - begin - a:= 0.8473; - b:= 85.577; - end - Else If types = 1 Then - begin - a:= 1.02; - b:= 115; - end - Else - begin - a:= 1.06302; - b:= 134.78259; - End; - - a:= a * start + b; - b:= 0.434; - - Result:= a * Power(V, b); - if (start > 0) then - Result:= Result / start; - if Result > 6.1 then Result:= 6.1; -end; - -Function AmountCells(types : Integer; V : Double; start : Double) : double; - -{ types: 0 = simpel, 1 = belucht, 2 = geroerd - V: volume van de giststarter, in liters - start: aantal gistcellen bij aanvang starter, in miljard gistcellen - Result: aantal cellen na kweken, in miljard gistcellen} - -var a : Double; - b : Double; -begin - If types = 0 Then - begin - a:= 0.8473; - b:= 85.577; - end - Else If types = 1 Then - begin - a:= 1.02; - b:= 115; - end - Else - begin - a:= 1.06302; - b:= 134.78259; - End; - - a:= a * start + b; - b:= 0.434; - - Result:= a * Power(V, b); - if (start > 0) and (Result / start > 6.1) then Result:= 6.1 * start; -end; - -Function UkRager(kt : Double) : Double; -begin - If kt = -2 Then - Result:= 25 - Else If kt = -1 Then - Result:= 0 - Else If (kt >= 0) And (kt <= 5) Then - Result:= 5 - Else If kt <= 10 Then - Result:= 6 - Else If kt <= 15 Then - Result:= 8 - Else If kt <= 20 Then - Result:= 10.1 - Else If kt <= 25 Then - Result:= 12.1 - Else If kt <= 30 Then - Result:= 15.3 - Else If kt <= 35 Then - Result:= 18.8 - Else If kt <= 40 Then - Result:= 22.8 - Else If kt <= 45 Then - Result:= 26.9 - Else If kt <= 50 Then - Result:= 28.1 - Else If kt > 50 Then - Result:= 30 - Else - Result:= 0; -end; - -Function UkGaretz(kt : Double) : Double; -begin - If kt = -2 Then - Result:= 20 - Else If kt = -1 Then - Result:= 0 - Else If (kt >= 0) And (kt <= 10) Then - Result:= 0 - Else If kt <= 15 Then - Result:= 2 - Else If kt <= 20 Then - Result:= 5 - Else If kt <= 25 Then - Result:= 8 - Else If kt <= 30 Then - Result:= 11 - Else If kt <= 35 Then - Result:= 14 - Else If kt <= 40 Then - Result:= 16 - Else If kt <= 45 Then - Result:= 18 - Else If kt <= 50 Then - Result:= 19 - Else If kt <= 60 Then - Result:= 20 - Else If kt <= 70 Then - Result:= 21 - Else If kt <= 80 Then - Result:= 22 - Else If kt > 80 Then - Result:= 23 - Else - Result:= 0; -end; - -Function UkNoonan(kt : Double) : Double; -begin - If kt = -2 Then - Result:= 25 - Else If kt = -1 Then - Result:= 0 - Else If (kt >= 0) And (kt <= 5) Then - Result:= 5 - Else If kt <= 15 Then - Result:= 0.3 * kt + 3.5 - Else If kt <= 60 Then - Result:= 0.44444 * kt + 1 + 1 / 3 - Else If kt <= 90 Then - Result:= 0.1 * kt + 22 - Else If kt > 90 Then - Result:= 31 - Else - Result:= 0; -end; - -Function UkDaniels(kt : Double) : Double; -begin - If kt = -2 Then - Result:= 23 - Else If kt = -1 Then - Result:= 0 - Else If (kt >= 0) And (kt <= 7.5) Then - Result:= 5 - Else If kt <= 17.5 Then - Result:= 12 - Else If kt <= 27.5 Then - Result:= 15 - Else If kt <= 42.5 Then - Result:= 19 - Else If kt <= 57.5 Then - Result:= 22 - Else If kt <= 72.5 Then - Result:= 24 - Else If kt <= 90 Then - Result:= 27 - Else If kt > 90 Then - Result:= 27 - Else - Result:= 0; -end; - -Function CalcIbuU(Method : TIBUmethod; SG : Double; Tboil : Double; HopVorm : THopForm; - HopUse : THopUse; BNAP : Double) : double; -var Ubt : Double; - Fbg : Double; - Fhf : Double; - Fhu : double; - Fbp : Double; - Fst : Double; - Fhb : Double; - Fyf : Double; - Ffil : Double; -begin - Ubt:= 25; - Fbg:= 1; - Fhf:= 1; - Fhu:= 1; - Fbp:= 1; - Fst:= 1; - Fhb:= 1; - Fyf:= 1; - Ffil:= 1; - - Case Method of - imRager: - begin - Ubt:= UkRager(Tboil); - If SG > 1.050 Then Fbg:= 1 / (1 + 5 * (SG - 1.050)); - Case HopVorm of - hfLeaf: - Fhf:= 1; - hfPlug: - Fhf:= 1 + Settings.PlugFactor.Value / 100; - hfPellet: - Fhf:= 1 + Settings.PelletFactor.Value / 100; - End; - end; - imGaretz: - begin - Ubt:= UkGaretz(Tboil); - If SG > 1.050 Then Fbg:= 1 / (1 + 5 * (SG - 1.050)); - Case HopVorm of - hfLeaf: - Fhf:= 1; - hfPlug: - Fhf:= 1 + Settings.PlugFactor.Value / 100; - hfPellet: - If (Tboil >= 10) And (Tboil <= 30) Then - Fhf:= 1 + Settings.PelletFactor.Value / 100; - Else - Fhf:= 1; - End; - end; - imMosher: - begin - If Tboil = -1 Then - Ubt:= 0 - Else If Tboil = -2 Then - Ubt:= 21.23082 * (1 - Exp(-0.028784 * 60)) - Else - Ubt:= 21.23082 * (1 - Exp(-0.028784 * Tboil)); - - Fbg:= 1.0526 * (SG - 40 * SQR(SG - 1)); - Case HopVorm of - hfLeaf: - Fhf:= 1; - hfPlug: - Fhf:= 1 + Settings.PlugFactor.Value / 100; - hfPellet: - Fhf:= 1 + Settings.PelletFactor.Value / 100; - End; - end; - imTinseth: - begin - If Tboil = -1 Then - Ubt:= 0 - Else If Tboil = -2 Then - Ubt:= 25.367715 * (1 - Exp(-0.04 * 60)) - Else - Ubt:= 25.367715 * (1 - Exp(-0.04 * Tboil)); - Fbg:= 1.5673 * Power(0.000125, (SG - 1)); - Case HopVorm of - hfPlug: - Fhf:= 1 + Settings.PlugFactor.Value / 100; - hfPellet: - Fhf:= 1 + Settings.PelletFactor.Value / 100; - End; - end; - imNoonan: - begin - Ubt:= UkNoonan(Tboil); - If SG > 1.050 Then - Fbg:= 1 / (1 + 5 * (SG - 1.050)); - Case HopVorm of - hfLeaf: - Fhf:= 1; - hfPlug: - Fhf:= 1 + Settings.PlugFactor.Value / 100; - hfPellet: - Fhf:= 1 + Settings.PelletFactor.Value / 100; - End; - end; - imDaniels: - begin - Ubt:= UkDaniels(Tboil); - If SG > 1.050 Then - Fbg:= 1 / (1 + 5 * (SG - 1.050)); - Case HopVorm of - hfLeaf: - Fhf:= 1; - hfPlug: - Fhf:= 1 + Settings.PlugFactor.Value / 100; - hfPellet: - Fhf:= 1 + Settings.PelletFactor.Value / 100; - End; - end; - end; - - case HopUse of - huBoil: Fhu:= 1.0; - huAroma: Fhu:= 1.0; //vlamuit - huDryhop: Fhu:= 0.0; - huMash: Fhu:= 1 + Settings.MashHopFactor.Value / 100; - huFirstWort: FHu:= 1 + Settings.FWHFactor.Value / 100; - end; - - Fbp:= 1 / (1 + (BNAP / 0.3048) / 27500); - - Result:= (Ubt * Fbg * Fhf * Fhu * Fbp * Fst * Fhb * Fyf * Ffil) / 100; -end; - -Function CalcIBU(Method : TIBUmethod; HopUse : THopUse; AA : Double; AM : Double; Vw : Double; - Vf : Double; SG : Double; Tboil : Double; HopVorm : THopForm; - BNAP : Double) : Double; -var IBUi : Double; - U : Double; - a : Double; - b : Double; - c : Double; -begin - U:= 1; - if Vf > 0 then IBUi:= 10 * AM * AA / Vf - else IBUi:= 0; - - U:= CalcIBUU(Method, SG, Tboil, HopVorm, HopUse, BNAP); - - { If (Method = imGaretz) Or (Method = imDaniels) Then - begin - a:= Vf / (260 * Vw); - b:= 1; - c:= -IBUi * U; - - Result:= (-b + Sqrt(SQR(b) - 4 * a * c)) / (2 * a); - end - Else } - Result:= IBUi * U; -end; - -Function AmHop(Method : TIBUmethod; HopUse : THopUse; AA : Double; IBU : Double; Vw : double; Vf : Double; SG : Double; - Tboil : Double; HopVorm : THopForm; BNAP : Double) : Double; -var U : Double; -begin - Result:= 0; - U:= CalcIBUU(Method, SG, Tboil, HopVorm, HopUse, BNAP); - - if (U > 0) and (AA > 0) then - Result:= (Vf * IBU) / (10 * AA * U) -end; - -Function IonBalance(Ca, Mg, Na, Cl, SO4, HCO3 : double) : double; -var MCa, MMg, MNa, MCl, MSO4, MHCO3 : double; -begin - MCa:= Ca / MMCa; - MMg:= Mg / MMMg; - MNa:= Na / MMNa; - MCl:= Cl / MMCl; - MSO4:= SO4 / MMSO4; - MHCO3:= HCO3 / MMHCO3; - - Result:= 2 * MCa + 2 * MMg + MNa - MCl - 2 * MSO4 - MHCO3; -end; - -Function CarbStoCO2(S : double; T : double; SFactor : double) : double; -begin - Result:= 0; - if SFactor > 0 then - Result:= 0.286 * S / SFactor + 0.000849151 * T * T - 0.0587512 * T + 1.71137; -end; - -Function CarbCO2toS(CO2 : double; T : double; SFactor : double) : double; -begin - Result:= SFactor * (CO2 - (0.000849151 * T * T - 0.0587512 * T + 1.71137)) / 0.286; -end; - -Function CarbCO2toPressure(CO2 : double; T : double) : double; -begin - Result:= (CO2 - (-0.000005594056 * Power(T, 4) + 0.000144357886 * Power(T, 3) - + 0.000362999168 * T * T - 0.064872987645 * T + 1.641145175049)) - / (0.00000498031 * Power(T, 4) - 0.00024358267 * Power(T, 3) - + 0.00385867329 * T * T - 0.05671206825 * T + 1.53801423376); -end; - -Function CarbPressuretoCO2(P : double; T : double) : double; -begin - Result:= P * (0.00000498031 * Power(T, 4) - 0.00024358267 * Power(T, 3) - + 0.00385867329 * T * T - 0.05671206825 * T + 1.53801423376) + - (-0.000005594056 * Power(T, 4) + 0.000144357886 * Power(T, 3) - + 0.000362999168 * T * T - 0.064872987645 * T + 1.641145175049); -end; - -Function ActualIBU(origibu, HSI, Temp : double; Elapsed, storagetype : longint) : double; -var iTemp, iType, e : double; -begin - iTemp:= 0.396865 * EXP(0.046221 * Temp); - case storagetype of - 0: iType:= 1; - 1: iType:= 0.75; - else iType:= 0.5; - end; - e:= 2 * (Elapsed / 365.25) * iTemp * iType; //years - Result:= origibu * Power(1 - HSI/100, e); -end; - -Function ZipFiles(l : TStringList; zipfn : string) : boolean; -var i : integer; - Zipper: TZipper; -begin - Result:= false; - if (l <> NIL) and (l.Count > 0) then - begin - Zipper := TZipper.Create; - try - Zipper.FileName := zipfn; - for I := 1 to l.Count - 1 do - Zipper.Entries.AddFileEntry(l.Strings[i], zipfn); - Zipper.ZipAllFiles; - Result:= TRUE; - finally - Zipper.Free; - end; - end; -end; - -Function UnZipFiles(zipfn, outpath : string) : boolean; -var i : integer; - Zipper: TUnZipper; -begin - Result:= false; - Zipper := TUnZipper.Create; - try - Zipper.FileName := zipfn; - Zipper.OutputPath := outpath; - Zipper.Examine; - Zipper.UnZipAllFiles; - Result:= TRUE; - finally - Zipper.Free; - end; -end; - -{Procedure SetFontHeight(F : TForm; fs : integer); -var i : integer; -begin - if F <> NIL then - begin - F.Font.Height:= fs; - for i:= 0 to F.ControlCount - 1 do - begin - F.Controls[i].Font.Height:= fs; - F.Repaint; - end; - end; -end;} - -Procedure PlayStartProg; -var sound : TProcess; -begin -// {$ifdef linux} -// AlSourcePlay(source[startprog]); -// {$endif} - {$ifdef darwin} - sound:= TProcess.Create(NIL); - sound.CommandLine:= 'afplay ' + StartSound; - sound.Execute; - sound.Free; - {$endif} - {$ifdef windows} - Application.ProcessMessages; - sndPlaySound(PChar(StartSound), snd_Async or snd_NoDefault);//snd_Async or snd_NoDefault); - Application.ProcessMessages; - {$endif} -end; - -Procedure PlayWarning; -var sound : TProcess; -begin -// {$ifdef linux} -// AlSourcePlay(source[warning]); -// {$endif} - {$ifdef darwin} - sound:= TProcess.Create(NIL); - sound.CommandLine:= 'afplay ' + WarningSound; - sound.Execute; - sound.Free; - {$endif} - {$ifdef windows} - Application.ProcessMessages; - sndPlaySound(PChar(WarningSound), snd_Async or snd_NoDefault);//snd_Async or snd_NoDefault); - Application.ProcessMessages; - {$endif} -end; - -Procedure PlayAlarm; -var sound : TProcess; -begin -// {$ifdef linux} -// AlSourcePlay(source[alarm]); -// {$endif} - {$ifdef darwin} - sound:= TProcess.Create(NIL); - sound.CommandLine:= 'afplay ' + AlarmSound; - sound.Execute; - sound.Free; - {$endif} - {$ifdef windows} - Application.ProcessMessages; - sndPlaySound(PChar(AlarmSound), snd_Async or snd_NoDefault);//snd_Async or snd_NoDefault); - Application.ProcessMessages; - {$endif} -end; - -Procedure PlayEndProg; -var sound : TProcess; -begin -// {$ifdef linux} -// AlSourcePlay(source[endprog]); -// {$endif} - {$ifdef darwin} - sound:= TProcess.Create(NIL); - sound.CommandLine:= 'afplay ' + StartSound; - sound.Execute; - sound.Free; - {$endif} - {$ifdef windows} - Application.ProcessMessages; - sndPlaySound(PChar(EndSound), snd_Async or snd_NoDefault);//snd_Async or snd_NoDefault); - Application.ProcessMessages; - {$endif} -end; - -Procedure Log(s : string); -const fn = 'brewbuddy.log'; -var fnp : string; -begin - if (slLog <> NIL) and DoLog then - begin - slLog.Add(s); - try - fnp:= Settings.DataLocation.Value + fn; - slLog.SaveToFile(fnp); - except - ShowMessage('Fout bij schrijven van logbestand'); - end; - end; -end; - -Initialization - MaxGrowthFactor:= 6.1; - - AmCellspGramDry:= 15000000000; //8695652173; //20000000000 according to MrMalty - AmCellspPack:= 100000000000; - AmCellspMlSlurry:= 1700000000; - - SpecificHeats[0].Material:= 'Aluminium'; - SpecificHeats[0].SpecificHeat:= 0.22; //cal/g.°C - SpecificHeats[1].Material:= 'Koper'; - SpecificHeats[1].SpecificHeat:= 0.092; //cal/g.°C - SpecificHeats[2].Material:= 'Kunststof'; - SpecificHeats[2].SpecificHeat:= 0.46; //cal/g.°C - SpecificHeats[3].Material:= 'RVS'; - SpecificHeats[3].SpecificHeat:= 0.11; //cal/g.°C - - EndChar:= ['a', 'e', 'i', 'o', 'u', 's']; - - if not DirectoryExists(Settings.DataLocation.Value) then - if not CreateDir(Settings.DataLocation.Value) then ShowMessage('Data folder could not be created.'); - - FermentableColor:= RGBtoColor(250, 195, 65); - HopColor:= RGBtoColor(100, 250, 65); - MiscColor:= RGBtoColor(240, 250, 65); - WaterAgentColor:= RGBtoColor(240, 140, 130); - FiningColor:= RGBtoColor(95, 180, 25); - YeastColor:= RGBtoColor(175, 175, 255); - WaterColor:= RGBtoColor(120, 255, 250); - - AlarmSound:= SoundFolder + 'alarm.wav'; - StartSound:= SoundFolder + 'welcome.wav'; - EndSound:= SoundFolder + 'end.wav'; - WarningSound:= SoundFolder + 'warning.wav'; - -// {$ifdef linux} -// //Initialize the sound system -// InitOpenAL; -// AlutInit(nil,argv); -// alGenBuffers(numbuffers, buffer); -// alGenSources(numsources, source); - -// AlutLoadWavFile(StartSound, format, dat, size, freq, loop); -// AlBufferData(buffer[startprog], format, dat, size, freq); -// AlutUnloadWav(format, dat, size, freq); - -// AlutLoadWavFile(WarningSound, format, dat, size, freq, loop); -// AlBufferData(buffer[warning], format, dat, size, freq); -// AlutUnloadWav(format, dat, size, freq); - -// AlutLoadWavFile(AlarmSound, format, dat, size, freq, loop); -// AlBufferData(buffer[alarm], format, dat, size, freq); -// AlutUnloadWav(format, dat, size, freq); - -// AlutLoadWavFile(EndSound, format, dat, size, freq, loop); -// AlBufferData(buffer[endprog], format, dat, size, freq); -// AlutUnloadWav(format, dat, size, freq); - -// AlSourcei( source[startprog], AL_BUFFER, buffer[startprog]); -// AlSourcef( source[startprog], AL_PITCH, 1.0 ); -// AlSourcef( source[startprog], AL_GAIN, 1.0 ); -// AlSourcefv( source[startprog], AL_POSITION, @sourcepos); -// AlSourcefv( source[startprog], AL_VELOCITY, @sourcevel); -// AlSourcei( source[startprog], AL_LOOPING, loop); - -// AlSourcei( source[warning], AL_BUFFER, buffer[warning]); -// AlSourcef( source[warning], AL_PITCH, 1.0 ); -// AlSourcef( source[warning], AL_GAIN, 1.0 ); -// AlSourcefv( source[warning], AL_POSITION, @sourcepos); -// AlSourcefv( source[warning], AL_VELOCITY, @sourcevel); -// AlSourcei( source[warning], AL_LOOPING, loop); - -// AlSourcei( source[alarm], AL_BUFFER, buffer[alarm]); -// AlSourcef( source[alarm], AL_PITCH, 1.0 ); -// AlSourcef( source[alarm], AL_GAIN, 1.0 ); -// AlSourcefv( source[alarm], AL_POSITION, @sourcepos); -// AlSourcefv( source[alarm], AL_VELOCITY, @sourcevel); -// AlSourcei( source[alarm], AL_LOOPING, loop); - -// AlSourcei( source[endprog], AL_BUFFER, buffer[endprog]); -// AlSourcef( source[endprog], AL_PITCH, 1.0 ); -// AlSourcef( source[endprog], AL_GAIN, 1.0 ); -// AlSourcefv( source[endprog], AL_POSITION, @sourcepos); -// AlSourcefv( source[endprog], AL_VELOCITY, @sourcevel); -// AlSourcei( source[endprog], AL_LOOPING, loop); - -// AlListenerfv( AL_POSITION, @listenerpos); -// AlListenerfv( AL_VELOCITY, @listenervel); -// AlListenerfv( AL_ORIENTATION, @listenerori); -// {$endif} - -finalization -// {$ifdef linux} -//Terminate the sound system -// Log(''); -// Log('HULPFUNCTIES'); -// AlDeleteBuffers(1, @buffer); -// Log('alBuffers afgesloten'); -// AlDeleteSources(1, @source); -// Log('alSources afgesloten'); -// AlutExit(); -// Log('Sound system afgesloten'); -// {$endif} - {$ifdef linux} - Log(''); - {$endif} -end. diff --git a/Source/UserInterface/Forms/backup/frrestoredatabases.pas b/Source/UserInterface/Forms/backup/frrestoredatabases.pas deleted file mode 100644 index 6c648d50..00000000 --- a/Source/UserInterface/Forms/backup/frrestoredatabases.pas +++ /dev/null @@ -1,102 +0,0 @@ -unit frrestoredatabases; - -{$mode objfpc}{$H+} - -interface - -uses - Classes, SysUtils, FileUtil, Forms, Controls, Graphics, Dialogs, Buttons, - ExtCtrls, StdCtrls; - -type - - { TfrmRestoreDatabase } - - TfrmRestoreDatabase = class(TForm) - bbOK: TBitBtn; - bbCancel: TBitBtn; - cgDatabases: TCheckGroup; - cbAll: TCheckBox; - procedure cbAllChange(Sender: TObject); - private - { private declarations } - public - { public declarations } - Function Execute : boolean; - end; - -var - frmRestoreDatabase: TfrmRestoreDatabase; - -implementation - -{$R *.lfm} -uses Containers, Data, Hulpfuncties; - -procedure TfrmRestoreDatabase.cbAllChange(Sender: TObject); -var i : integer; -begin - for i:= 0 to cgDatabases.Items.Count - 1 do - cgDatabases.Checked[i]:= cbAll.Checked; -end; - -Function TfrmRestoreDatabase.Execute : boolean; - function CheckCopyFile(sd, dd, fn : string) : boolean; - begin - Result:= false; - if FileExists(sd + fn) then - result:= CopyFile(sd + fn, dd + fn); - end; -var sourcedata, destdata : string; -begin - Settings.Style.SetControlsStyle(self); -// SetFontHeight(self, Settings.FontHeight.Value); - Result:= (showmodal = mrOK); - if Result then - if Question(self, 'Weet je zeker dat je de databanken wilt overschrijven?') then - begin - Screen.Cursor:= crHourglass; - Backup; - {$ifdef linux} - sourcedata:= '/usr/share/brewbuddy/'; - {$endif} - {$ifdef Darwin} - sourcedata:= '/usr/share/brewbuddy/'; - {$endif} - {$ifdef Windows} - sourcedata:= ExtractFilePath(Application.ExeName) + 'brewbuddy\'; - {$endif} - destdata:= Settings.DataLocation.Value; - if cgDatabases.Checked[0] then - if CheckCopyFile(sourcedata, destdata, 'fermentables.xml') then - Fermentables.ReadXML; - if cgDatabases.Checked[1] then - if CheckCopyFile(sourcedata, destdata, 'hops.xml') then - Hops.ReadXML; - if cgDatabases.Checked[2] then - if CheckCopyFile(sourcedata, destdata, 'yeasts.xml') then - Yeasts.ReadXML; - if cgDatabases.Checked[3] then - if CheckCopyFile(sourcedata, destdata, 'miscs.xml') then - Miscs.ReadXML; - if cgDatabases.Checked[4] then - if CheckCopyFile(sourcedata, destdata, 'mashs.xml') then - Mashs.ReadXML; - if cgDatabases.Checked[5] then - if CheckCopyFile(sourcedata, destdata, 'waters.xml') then - Waters.ReadXML; - if cgDatabases.Checked[6] then - if CheckCopyFile(sourcedata, destdata, 'styles.xml') then - Beerstyles.ReadXML; - if cgDatabases.Checked[7] then - if CheckCopyFile(sourcedata, destdata, 'equipments.xml') then - Equipments.ReadXML; - if cgDatabases.Checked[8] then - if CheckCopyFile(sourcedata, destdata, 'recipes.xml') then - Recipes.ReadXML; - Screen.Cursor:= crDefault; - end; -end; - -end. - diff --git a/Source/backup/brewbuddy.pas b/Source/backup/brewbuddy.pas deleted file mode 100644 index 062ff8fd..00000000 --- a/Source/backup/brewbuddy.pas +++ /dev/null @@ -1,51 +0,0 @@ -program brewbuddy; - -{$mode objfpc}{$H+} - -uses - {$IFDEF UNIX}{$IFDEF UseCThreads} - cthreads, - {$ENDIF}{$ENDIF} - {$ifdef UNIX} - clocale, - {$endif} - SysUtils, Interfaces, // this includes the LCL widgetset - printer4lazarus, tachartprint, Forms, FrMain, Data, subs, Hulpfuncties, - Containers, FrBeerstyles, FrHop2, frQuestion, frgetstring, FrEquipments, - FrFermentables2, FrMiscs2, frmashs, FrYeasts2, FrWaters, frmashstep, - FrFermentables, PositieInterval, FrHop, FrMiscs, FrYeasts, frmiscs3, - frfermentables3, frhop3, frwateradjustment, FrNotification, TimeEdit, - frmeasurements, frimport, frselectbeerstyle, frrecipetobrew, BH_report, - frprintpreview, BHprintforms, frpropagation, frrefractometer, frboilmethod, - fdatabaselocation, utypes, umulfit, frdividebrew, fryeasts3, - frchoosebeerstyle, frchoosebrewschars, frsplash, frinfo, vinfo, frsynchronize, - frchoosebrews, PromashImport, laz_synapse, frrestoredatabases, frsettings, - cloud, frgetpasswd, frdownloadprogress, pexpandpanels, uniqueinstance_package;//, neuroot; - -{$R *.res} - -begin - Application.Title:='BrewBuddy'; - try - Application.Initialize; - Application.CreateForm(TfrmMain, frmMain); - Application.Run; - except - {if CloudActive then} FreeAndNIL(BHCloud); - FreeAndNIL(StyleSubs); - FreeAndNIL(FermentableSubs); - FreeAndNIL(YeastSubs); - FreeAndNIL(Fermentables); - FreeAndNIL(Hops); - FreeAndNIL(Miscs); - FreeAndNIL(Yeasts); - FreeAndNIL(Waters); - FreeAndNIL(Equipments); - FreeAndNIL(Beerstyles); - FreeAndNIL(Mashs); - FreeAndNIL(Recipes); - FreeAndNIL(Brews); - FreeAndNIL(Settings); - end; -end. - diff --git a/Source/backup/brewbuddy_osx.lpi b/Source/backup/brewbuddy_osx.lpi deleted file mode 100644 index 572ca2bf..00000000 --- a/Source/backup/brewbuddy_osx.lpi +++ /dev/null @@ -1,1846 +0,0 @@ -<?xml version="1.0" encoding="UTF-8"?> -<CONFIG> - <ProjectOptions> - <Version Value="11"/> - <General> - <MainUnit Value="0"/> - <AutoCreateForms Value="False"/> - <Title Value="BrewBuddy"/> - <ResourceType Value="res"/> - </General> - <i18n> - <EnableI18N LFM="False"/> - </i18n> - <VersionInfo> - <UseVersionInfo Value="True"/> - <MajorVersionNr Value="5"/> - <MinorVersionNr Value="4"/> - <Language Value="0413"/> - <StringTable CompanyName="Brouwerij Het Witte Paard" FileDescription="BrewBuddy Sassy Saison" InternalName="BrewBuddy" OriginalFilename="BrewBuddy" ProductName="BrewBuddy" ProductVersion="5.3.5.2"/> - </VersionInfo> - <MacroValues Count="1"> - <Macro1 Name="LCLWidgetType" Value="cocoa"/> - </MacroValues> - <BuildModes Count="1" Active="Default"> - <Item1 Name="Default" Default="True"/> - <SharedMatrixOptions Count="1"> - <Item1 ID="090156190409" Modes="Default" Type="IDEMacro" MacroName="LCLWidgetType" Value="cocoa"/> - </SharedMatrixOptions> - </BuildModes> - <PublishOptions> - <Version Value="2"/> - </PublishOptions> - <RunParams> - <FormatVersion Value="2"/> - <Modes Count="1"> - <Mode0 Name="default"/> - </Modes> - </RunParams> - <RequiredPackages Count="9"> - <Item1> - <PackageName Value="TAChartPrint"/> - </Item1> - <Item2> - <PackageName Value="Pexpandpanels"/> - </Item2> - <Item3> - <PackageName Value="uniqueinstance_package"/> - </Item3> - <Item4> - <PackageName Value="SynEdit"/> - <MinVersion Major="1" Valid="True"/> - </Item4> - <Item5> - <PackageName Value="laz_synapse"/> - <MinVersion Valid="True"/> - </Item5> - <Item6> - <PackageName Value="printers4lazide"/> - </Item6> - <Item7> - <PackageName Value="Printer4Lazarus"/> - </Item7> - <Item8> - <PackageName Value="TAChartLazarusPkg"/> - <MinVersion Major="1" Valid="True"/> - </Item8> - <Item9> - <PackageName Value="LCL"/> - </Item9> - </RequiredPackages> - <Units Count="209"> - <Unit0> - <Filename Value="brewbuddy.pas"/> - <IsPartOfProject Value="True"/> - <IsVisibleTab Value="True"/> - <EditorIndex Value="4"/> - <CursorPos X="50" Y="7"/> - <UsageCount Value="201"/> - <Loaded Value="True"/> - </Unit0> - <Unit1> - <Filename Value="UserInterface/Forms/frmain.pas"/> - <IsPartOfProject Value="True"/> - <ComponentName Value="frmMain"/> - <HasResources Value="True"/> - <ResourceBaseClass Value="Form"/> - <UnitName Value="FrMain"/> - <EditorIndex Value="7"/> - <TopLine Value="3534"/> - <CursorPos X="72" Y="3538"/> - <UsageCount Value="201"/> - <Loaded Value="True"/> - </Unit1> - <Unit2> - <Filename Value="Units/data.pas"/> - <IsPartOfProject Value="True"/> - <UnitName Value="Data"/> - <EditorIndex Value="-1"/> - <CursorPos X="58" Y="28"/> - <UsageCount Value="201"/> - </Unit2> - <Unit3> - <Filename Value="/usr/lib/lazarus/0.9.30/ide/lazarus.pp"/> - <UnitName Value="Lazarus"/> - <UsageCount Value="2"/> - </Unit3> - <Unit4> - <Filename Value="/usr/lib/lazarus/0.9.30/lcl/lconvencoding.pas"/> - <UnitName Value="LConvEncoding"/> - <TopLine Value="13"/> - <CursorPos X="24" Y="27"/> - <UsageCount Value="2"/> - </Unit4> - <Unit5> - <Filename Value="/usr/lib/lazarus/0.9.30/ide/ideinfodlg.pas"/> - <UnitName Value="IDEInfoDlg"/> - <TopLine Value="19"/> - <UsageCount Value="2"/> - </Unit5> - <Unit6> - <Filename Value="../lazarus/0.9.30/ide/lazarus.pp"/> - <UnitName Value="Lazarus"/> - <UsageCount Value="2"/> - </Unit6> - <Unit7> - <Filename Value="/usr/lib/lazarus/0.9.30/ide/idecmdline.pas"/> - <UnitName Value="IDECmdLine"/> - <UsageCount Value="2"/> - </Unit7> - <Unit8> - <Filename Value="/usr/lib/lazarus/0.9.30/debugger/gdbmidebugger.pp"/> - <UnitName Value="GDBMIDebugger"/> - <TopLine Value="9582"/> - <CursorPos X="7" Y="9596"/> - <UsageCount Value="2"/> - </Unit8> - <Unit9> - <Filename Value="/usr/lib/lazarus/0.9.30/converter/convertdelphi.pas"/> - <UnitName Value="ConvertDelphi"/> - <TopLine Value="803"/> - <CursorPos X="28" Y="817"/> - <UsageCount Value="2"/> - </Unit9> - <Unit10> - <Filename Value="/usr/lib/lazarus/0.9.30/ide/lazconf.pp"/> - <UnitName Value="LazConf"/> - <UsageCount Value="2"/> - </Unit10> - <Unit11> - <Filename Value="Units/hulpfuncties.pas"/> - <IsPartOfProject Value="True"/> - <UnitName Value="Hulpfuncties"/> - <EditorIndex Value="2"/> - <CursorPos X="15" Y="7"/> - <UsageCount Value="201"/> - <Loaded Value="True"/> - </Unit11> - <Unit12> - <Filename Value="lnet/lazaruspackage/lnetbase.pas"/> - <UsageCount Value="3"/> - </Unit12> - <Unit13> - <Filename Value="Units/containers.pas"/> - <IsPartOfProject Value="True"/> - <UnitName Value="Containers"/> - <TopLine Value="3055"/> - <CursorPos X="74" Y="3066"/> - <UsageCount Value="200"/> - <Loaded Value="True"/> - </Unit13> - <Unit14> - <Filename Value="appsettings.pas"/> - <CursorPos Y="131"/> - <UsageCount Value="3"/> - </Unit14> - <Unit15> - <Filename Value="icetabset.pas"/> - <UnitName Value="IceTabSet"/> - <TopLine Value="42"/> - <CursorPos X="22" Y="55"/> - <UsageCount Value="2"/> - </Unit15> - <Unit16> - <Filename Value="ovctable.pas"/> - <TopLine Value="21"/> - <CursorPos X="2" Y="34"/> - <UsageCount Value="2"/> - </Unit16> - <Unit17> - <Filename Value="ovccmd.pas"/> - <TopLine Value="698"/> - <CursorPos X="49" Y="711"/> - <UsageCount Value="2"/> - </Unit17> - <Unit18> - <Filename Value="/usr/lib/lazarus/0.9.30.4/ide/lazconf.pp"/> - <UnitName Value="LazConf"/> - <UsageCount Value="6"/> - </Unit18> - <Unit19> - <Filename Value="/usr/lib/lazarus/0.9.30.4/ideintf/actionseditor.pas"/> - <ComponentName Value="ActionListEditor"/> - <HasResources Value="True"/> - <ResourceBaseClass Value="Form"/> - <UnitName Value="ActionsEditor"/> - <TopLine Value="20"/> - <CursorPos X="22" Y="33"/> - <UsageCount Value="6"/> - </Unit19> - <Unit20> - <Filename Value="UserInterface/Forms/frbeerstyles.pas"/> - <IsPartOfProject Value="True"/> - <ComponentName Value="FrmBeerstyles"/> - <HasResources Value="True"/> - <ResourceBaseClass Value="Form"/> - <UnitName Value="FrBeerstyles"/> - <EditorIndex Value="-1"/> - <TopLine Value="108"/> - <CursorPos Y="120"/> - <UsageCount Value="201"/> - </Unit20> - <Unit21> - <Filename Value="/usr/lib/lazarus/0.9.30.4/lcl/include/customlistbox.inc"/> - <TopLine Value="453"/> - <CursorPos Y="466"/> - <UsageCount Value="2"/> - </Unit21> - <Unit22> - <Filename Value="/usr/lib/lazarus/0.9.30.4/lcl/include/control.inc"/> - <TopLine Value="2775"/> - <CursorPos Y="2788"/> - <UsageCount Value="8"/> - </Unit22> - <Unit23> - <Filename Value="/usr/lib/lazarus/0.9.30.4/lcl/include/buttoncontrol.inc"/> - <TopLine Value="50"/> - <CursorPos Y="63"/> - <UsageCount Value="2"/> - </Unit23> - <Unit24> - <Filename Value="/usr/lib/lazarus/0.9.30.4/lcl/include/buttons.inc"/> - <TopLine Value="162"/> - <CursorPos Y="175"/> - <UsageCount Value="2"/> - </Unit24> - <Unit25> - <Filename Value="/usr/lib/lazarus/0.9.30.4/lcl/include/bitbtn.inc"/> - <TopLine Value="45"/> - <CursorPos Y="58"/> - <UsageCount Value="2"/> - </Unit25> - <Unit26> - <Filename Value="UserInterface/Forms/frhop2.pas"/> - <IsPartOfProject Value="True"/> - <ComponentName Value="FrmHop2"/> - <HasResources Value="True"/> - <ResourceBaseClass Value="Form"/> - <UnitName Value="FrHop2"/> - <EditorIndex Value="-1"/> - <TopLine Value="94"/> - <CursorPos X="17" Y="125"/> - <UsageCount Value="202"/> - </Unit26> - <Unit27> - <Filename Value="UserInterface/Forms/frquestion.pas"/> - <IsPartOfProject Value="True"/> - <ComponentName Value="FrmQuestion"/> - <HasResources Value="True"/> - <ResourceBaseClass Value="Form"/> - <UnitName Value="frQuestion"/> - <EditorIndex Value="-1"/> - <TopLine Value="7"/> - <CursorPos X="31" Y="39"/> - <UsageCount Value="200"/> - </Unit27> - <Unit28> - <Filename Value="UserInterface/Forms/frgetstring.pas"/> - <IsPartOfProject Value="True"/> - <ComponentName Value="FrmGetString"/> - <HasResources Value="True"/> - <ResourceBaseClass Value="Form"/> - <EditorIndex Value="-1"/> - <TopLine Value="10"/> - <CursorPos Y="47"/> - <UsageCount Value="200"/> - </Unit28> - <Unit29> - <Filename Value="UserInterface/Forms/frequipments.pas"/> - <IsPartOfProject Value="True"/> - <ComponentName Value="FrmEquipments"/> - <HasResources Value="True"/> - <ResourceBaseClass Value="Form"/> - <UnitName Value="FrEquipments"/> - <EditorIndex Value="-1"/> - <TopLine Value="104"/> - <CursorPos Y="120"/> - <UsageCount Value="200"/> - </Unit29> - <Unit30> - <Filename Value="UserInterface/Forms/frfermentables2.pas"/> - <IsPartOfProject Value="True"/> - <ComponentName Value="FrmFermentables2"/> - <HasResources Value="True"/> - <ResourceBaseClass Value="Form"/> - <UnitName Value="FrFermentables2"/> - <EditorIndex Value="-1"/> - <TopLine Value="134"/> - <CursorPos Y="161"/> - <UsageCount Value="201"/> - </Unit30> - <Unit31> - <Filename Value="UserInterface/Forms/frmiscs2.pas"/> - <IsPartOfProject Value="True"/> - <ComponentName Value="FrmMiscs2"/> - <HasResources Value="True"/> - <ResourceBaseClass Value="Form"/> - <UnitName Value="FrMiscs2"/> - <EditorIndex Value="-1"/> - <TopLine Value="106"/> - <CursorPos Y="146"/> - <UsageCount Value="200"/> - </Unit31> - <Unit32> - <Filename Value="UserInterface/Forms/frmashs.pas"/> - <IsPartOfProject Value="True"/> - <ComponentName Value="FrmMashs"/> - <HasResources Value="True"/> - <ResourceBaseClass Value="Form"/> - <EditorIndex Value="-1"/> - <TopLine Value="47"/> - <CursorPos Y="72"/> - <UsageCount Value="201"/> - </Unit32> - <Unit33> - <Filename Value="UserInterface/Forms/fryeasts2.pas"/> - <IsPartOfProject Value="True"/> - <ComponentName Value="FrmYeasts2"/> - <HasResources Value="True"/> - <ResourceBaseClass Value="Form"/> - <UnitName Value="FrYeasts2"/> - <EditorIndex Value="-1"/> - <TopLine Value="126"/> - <CursorPos X="39" Y="146"/> - <UsageCount Value="200"/> - </Unit33> - <Unit34> - <Filename Value="/usr/lib/lazarus/0.9.30.4/lcl/interfaces/gtk2/gtk2wscontrols.pp"/> - <UnitName Value="Gtk2WSControls"/> - <TopLine Value="293"/> - <CursorPos Y="306"/> - <UsageCount Value="6"/> - </Unit34> - <Unit35> - <Filename Value="UserInterface/Forms/frwaters.pas"/> - <IsPartOfProject Value="True"/> - <ComponentName Value="FrmWaters"/> - <HasResources Value="True"/> - <ResourceBaseClass Value="Form"/> - <UnitName Value="FrWaters"/> - <EditorIndex Value="-1"/> - <TopLine Value="82"/> - <CursorPos Y="106"/> - <UsageCount Value="200"/> - </Unit35> - <Unit36> - <Filename Value="UserInterface/Forms/frmashstep.pas"/> - <IsPartOfProject Value="True"/> - <ComponentName Value="FrmMashStep"/> - <HasResources Value="True"/> - <ResourceBaseClass Value="Form"/> - <EditorIndex Value="-1"/> - <TopLine Value="52"/> - <CursorPos Y="89"/> - <UsageCount Value="201"/> - </Unit36> - <Unit37> - <Filename Value="/usr/lib/lazarus/0.9.30.4/lcl/grids.pas"/> - <UnitName Value="Grids"/> - <TopLine Value="8206"/> - <CursorPos Y="8219"/> - <UsageCount Value="5"/> - </Unit37> - <Unit38> - <Filename Value="UserInterface/Forms/frfermentables.pas"/> - <IsPartOfProject Value="True"/> - <ComponentName Value="FrmFermentables"/> - <HasResources Value="True"/> - <ResourceBaseClass Value="Form"/> - <UnitName Value="FrFermentables"/> - <EditorIndex Value="-1"/> - <TopLine Value="129"/> - <CursorPos Y="135"/> - <UsageCount Value="200"/> - </Unit38> - <Unit39> - <Filename Value="Units/positieinterval.pas"/> - <IsPartOfProject Value="True"/> - <UnitName Value="PositieInterval"/> - <EditorIndex Value="-1"/> - <TopLine Value="6"/> - <CursorPos X="5" Y="648"/> - <UsageCount Value="200"/> - </Unit39> - <Unit40> - <Filename Value="UserInterface/Forms/frhop.pas"/> - <IsPartOfProject Value="True"/> - <ComponentName Value="FrmHop"/> - <HasResources Value="True"/> - <ResourceBaseClass Value="Form"/> - <UnitName Value="FrHop"/> - <EditorIndex Value="-1"/> - <TopLine Value="112"/> - <CursorPos Y="137"/> - <UsageCount Value="200"/> - </Unit40> - <Unit41> - <Filename Value="UserInterface/Forms/frmiscs.pas"/> - <IsPartOfProject Value="True"/> - <ComponentName Value="FrmMiscs"/> - <HasResources Value="True"/> - <ResourceBaseClass Value="Form"/> - <UnitName Value="FrMiscs"/> - <EditorIndex Value="-1"/> - <TopLine Value="74"/> - <CursorPos Y="97"/> - <UsageCount Value="200"/> - </Unit41> - <Unit42> - <Filename Value="UserInterface/Forms/fryeasts.pas"/> - <IsPartOfProject Value="True"/> - <ComponentName Value="FrmYeasts"/> - <HasResources Value="True"/> - <ResourceBaseClass Value="Form"/> - <UnitName Value="FrYeasts"/> - <EditorIndex Value="-1"/> - <TopLine Value="93"/> - <CursorPos Y="119"/> - <UsageCount Value="200"/> - </Unit42> - <Unit43> - <Filename Value="UserInterface/Forms/frmiscs3.pas"/> - <IsPartOfProject Value="True"/> - <ComponentName Value="FrmMiscs3"/> - <HasResources Value="True"/> - <ResourceBaseClass Value="Form"/> - <EditorIndex Value="-1"/> - <TopLine Value="160"/> - <CursorPos X="28" Y="183"/> - <UsageCount Value="200"/> - </Unit43> - <Unit44> - <Filename Value="/usr/lib/lazarus/0.9.30.4/lcl/include/headercontrol.inc"/> - <TopLine Value="384"/> - <CursorPos Y="416"/> - <UsageCount Value="2"/> - </Unit44> - <Unit45> - <Filename Value="UserInterface/Forms/frfermentables3.pas"/> - <IsPartOfProject Value="True"/> - <ComponentName Value="FrmFermentables3"/> - <HasResources Value="True"/> - <ResourceBaseClass Value="Form"/> - <EditorIndex Value="-1"/> - <TopLine Value="230"/> - <CursorPos X="76" Y="240"/> - <UsageCount Value="200"/> - </Unit45> - <Unit46> - <Filename Value="UserInterface/Forms/frhop3.pas"/> - <IsPartOfProject Value="True"/> - <ComponentName Value="FrmHop3"/> - <HasResources Value="True"/> - <ResourceBaseClass Value="Form"/> - <EditorIndex Value="-1"/> - <TopLine Value="146"/> - <CursorPos X="5" Y="149"/> - <UsageCount Value="200"/> - </Unit46> - <Unit47> - <Filename Value="/usr/lib/lazarus/0.9.30.4/lcl/interfaces/qt/qtwscontrols.pp"/> - <UnitName Value="QtWSControls"/> - <TopLine Value="281"/> - <CursorPos Y="295"/> - <UsageCount Value="3"/> - </Unit47> - <Unit48> - <Filename Value="UserInterface/Forms/frwateradjustment.pas"/> - <IsPartOfProject Value="True"/> - <ComponentName Value="FrmWaterAdjustment"/> - <HasResources Value="True"/> - <ResourceBaseClass Value="Form"/> - <EditorIndex Value="-1"/> - <TopLine Value="826"/> - <CursorPos X="59" Y="866"/> - <UsageCount Value="200"/> - </Unit48> - <Unit49> - <Filename Value="UserInterface/Forms/frnotification.pas"/> - <IsPartOfProject Value="True"/> - <ComponentName Value="FrmNotification"/> - <HasResources Value="True"/> - <ResourceBaseClass Value="Form"/> - <UnitName Value="FrNotification"/> - <EditorIndex Value="-1"/> - <TopLine Value="43"/> - <CursorPos X="3" Y="45"/> - <UsageCount Value="200"/> - </Unit49> - <Unit50> - <Filename Value="acs_lame.pas"/> - <TopLine Value="10"/> - <UsageCount Value="158"/> - </Unit50> - <Unit51> - <Filename Value="/usr/lib/lazarus/0.9.30.4/lcl/include/customedit.inc"/> - <TopLine Value="500"/> - <CursorPos Y="513"/> - <UsageCount Value="8"/> - </Unit51> - <Unit52> - <Filename Value="ttimeedit.pas"/> - <TopLine Value="376"/> - <UsageCount Value="2"/> - </Unit52> - <Unit53> - <Filename Value="rxtimeedit.pas"/> - <UnitName Value="RxTimeEdit"/> - <TopLine Value="66"/> - <CursorPos X="2" Y="34"/> - <UsageCount Value="196"/> - </Unit53> - <Unit54> - <Filename Value="rxspin.pas"/> - <TopLine Value="957"/> - <CursorPos X="4" Y="981"/> - <UsageCount Value="2"/> - </Unit54> - <Unit55> - <Filename Value="../Software/Lazarus/Componenten/FortesReport/rlreg.pas"/> - <UnitName Value="RLReg"/> - <UsageCount Value="2"/> - </Unit55> - <Unit56> - <Filename Value="UserInterface/Forms/frmeasurements.pas"/> - <IsPartOfProject Value="True"/> - <ComponentName Value="frmMeasurements"/> - <HasResources Value="True"/> - <ResourceBaseClass Value="Form"/> - <EditorIndex Value="-1"/> - <TopLine Value="216"/> - <CursorPos Y="216"/> - <UsageCount Value="201"/> - </Unit56> - <Unit57> - <Filename Value="graph.pas"/> - <UnitName Value="ASGraph"/> - <CursorPos Y="98"/> - <UsageCount Value="7"/> - </Unit57> - <Unit58> - <Filename Value="brewbuddygraph.pas"/> - <UnitName Value="BrewBuddyGraph"/> - <TopLine Value="449"/> - <CursorPos X="81" Y="463"/> - <UsageCount Value="196"/> - </Unit58> - <Unit59> - <Filename Value="PrintDialog.pas"/> - <ComponentName Value="PrinterForm"/> - <HasResources Value="True"/> - <ResourceBaseClass Value="Form"/> - <CursorPos X="15" Y="13"/> - <UsageCount Value="7"/> - </Unit59> - <Unit60> - <Filename Value="/usr/lib/lazarus/0.9.30.4/components/printers/printer4lazarus.pas"/> - <UnitName Value="Printer4Lazarus"/> - <CursorPos X="29" Y="10"/> - <UsageCount Value="6"/> - </Unit60> - <Unit61> - <Filename Value="/usr/lib/lazarus/0.9.30.4/components/printers/design/ideprinting.pas"/> - <UsageCount Value="6"/> - </Unit61> - <Unit62> - <Filename Value="/usr/lib/lazarus/0.9.30.4/components/lazcontrols/extendednotebook.pas"/> - <UnitName Value="ExtendedNotebook"/> - <UsageCount Value="6"/> - </Unit62> - <Unit63> - <Filename Value="/usr/lib/lazarus/0.9.30.4/ide/lazarus.pp"/> - <UnitName Value="Lazarus"/> - <UsageCount Value="6"/> - </Unit63> - <Unit64> - <Filename Value="/usr/lib/lazarus/0.9.30.4/lcl/include/customcheckbox.inc"/> - <TopLine Value="141"/> - <CursorPos Y="153"/> - <UsageCount Value="2"/> - </Unit64> - <Unit65> - <Filename Value="UserInterface/Forms/frimport.pas"/> - <IsPartOfProject Value="True"/> - <ComponentName Value="FrmImport"/> - <HasResources Value="True"/> - <ResourceBaseClass Value="Form"/> - <EditorIndex Value="-1"/> - <TopLine Value="103"/> - <CursorPos Y="142"/> - <UsageCount Value="200"/> - </Unit65> - <Unit66> - <Filename Value="filefind.pas"/> - <UnitName Value="FileFind"/> - <TopLine Value="151"/> - <CursorPos Y="221"/> - <UsageCount Value="7"/> - </Unit66> - <Unit67> - <Filename Value="UserInterface/Forms/frselectbeerstyle.pas"/> - <IsPartOfProject Value="True"/> - <ComponentName Value="FrmSelectBeerStyle"/> - <HasResources Value="True"/> - <ResourceBaseClass Value="Form"/> - <EditorIndex Value="-1"/> - <TopLine Value="27"/> - <CursorPos X="21" Y="62"/> - <UsageCount Value="200"/> - </Unit67> - <Unit68> - <Filename Value="promashimport.pas"/> - <UnitName Value="PromashImport"/> - <TopLine Value="1992"/> - <CursorPos X="17" Y="2005"/> - <UsageCount Value="5"/> - </Unit68> - <Unit69> - <Filename Value="/usr/lib/lazarus/0.9.30.4/lcl/interfaces/qt/qtobject.inc"/> - <TopLine Value="243"/> - <CursorPos Y="256"/> - <UsageCount Value="5"/> - </Unit69> - <Unit70> - <Filename Value="UserInterface/Forms/frrecipetobrew.pas"/> - <IsPartOfProject Value="True"/> - <ComponentName Value="frmRecipeToBrew"/> - <HasResources Value="True"/> - <ResourceBaseClass Value="Form"/> - <EditorIndex Value="-1"/> - <TopLine Value="73"/> - <CursorPos X="8" Y="106"/> - <UsageCount Value="200"/> - </Unit70> - <Unit71> - <Filename Value="Units/bh_report.pas"/> - <IsPartOfProject Value="True"/> - <UnitName Value="BH_report"/> - <EditorIndex Value="1"/> - <TopLine Value="983"/> - <CursorPos X="31" Y="1007"/> - <UsageCount Value="200"/> - <Loaded Value="True"/> - </Unit71> - <Unit72> - <Filename Value="UserInterface/Forms/frprintpreview.pas"/> - <IsPartOfProject Value="True"/> - <ComponentName Value="FrmPrintPreview"/> - <HasResources Value="True"/> - <ResourceBaseClass Value="Form"/> - <EditorIndex Value="-1"/> - <TopLine Value="71"/> - <CursorPos Y="71"/> - <UsageCount Value="201"/> - </Unit72> - <Unit73> - <Filename Value="Units/bhprintforms.pas"/> - <IsPartOfProject Value="True"/> - <UnitName Value="BHprintforms"/> - <EditorIndex Value="-1"/> - <TopLine Value="680"/> - <CursorPos X="9" Y="694"/> - <UsageCount Value="200"/> - </Unit73> - <Unit74> - <Filename Value="/usr/lib/lazarus/0.9.30.4/lcl/include/font.inc"/> - <TopLine Value="796"/> - <CursorPos Y="810"/> - <UsageCount Value="3"/> - </Unit74> - <Unit75> - <Filename Value="/usr/lib/lazarus/0.9.30.4/lcl/include/rasterimage.inc"/> - <TopLine Value="292"/> - <CursorPos Y="308"/> - <UsageCount Value="3"/> - </Unit75> - <Unit76> - <Filename Value="etiket.pas"/> - <UnitName Value="Etiket"/> - <TopLine Value="977"/> - <CursorPos Y="1000"/> - <UsageCount Value="197"/> - </Unit76> - <Unit77> - <Filename Value="etiketlabel.pas"/> - <UnitName Value="EtiketLabel"/> - <TopLine Value="575"/> - <CursorPos Y="587"/> - <UsageCount Value="197"/> - </Unit77> - <Unit78> - <Filename Value="/usr/lib/lazarus/0.9.30.4/components/tachart/tagraph.pas"/> - <UnitName Value="TAGraph"/> - <TopLine Value="307"/> - <CursorPos Y="414"/> - <UsageCount Value="7"/> - </Unit78> - <Unit79> - <Filename Value="/usr/lib/lazarus/0.9.30.4/components/tachart/tachartaxis.pas"/> - <UnitName Value="TAChartAxis"/> - <TopLine Value="794"/> - <CursorPos X="15" Y="808"/> - <UsageCount Value="6"/> - </Unit79> - <Unit80> - <Filename Value="/usr/lib/lazarus/0.9.30.4/components/tachart/demo/save/main.pas"/> - <TopLine Value="56"/> - <UsageCount Value="7"/> - </Unit80> - <Unit81> - <Filename Value="/usr/lib/lazarus/0.9.30.4/components/tachart/tadrawutils.pas"/> - <UnitName Value="TADrawUtils"/> - <TopLine Value="28"/> - <UsageCount Value="7"/> - </Unit81> - <Unit82> - <Filename Value="/usr/lib/lazarus/0.9.30.4/components/tachart/demo/basic/unit1.pas"/> - <ComponentName Value="Form1"/> - <HasResources Value="True"/> - <ResourceBaseClass Value="Form"/> - <TopLine Value="103"/> - <CursorPos X="3" Y="118"/> - <UsageCount Value="7"/> - </Unit82> - <Unit83> - <Filename Value="/usr/lib/lazarus/0.9.30.4/components/tachart/tacustomseries.pas"/> - <UnitName Value="TACustomSeries"/> - <TopLine Value="635"/> - <CursorPos Y="648"/> - <UsageCount Value="7"/> - </Unit83> - <Unit84> - <Filename Value="UserInterface/Forms/frpropagation.pas"/> - <IsPartOfProject Value="True"/> - <ComponentName Value="FrmPropagation"/> - <HasResources Value="True"/> - <ResourceBaseClass Value="Form"/> - <EditorIndex Value="-1"/> - <TopLine Value="71"/> - <CursorPos X="5" Y="88"/> - <UsageCount Value="200"/> - </Unit84> - <Unit85> - <Filename Value="UserInterface/Forms/frrefractometer.pas"/> - <IsPartOfProject Value="True"/> - <ComponentName Value="FrmRefractometer"/> - <HasResources Value="True"/> - <ResourceBaseClass Value="Form"/> - <EditorIndex Value="-1"/> - <TopLine Value="33"/> - <CursorPos X="6" Y="63"/> - <UsageCount Value="200"/> - </Unit85> - <Unit86> - <Filename Value="UserInterface/Forms/frboilmethod.pas"/> - <IsPartOfProject Value="True"/> - <ComponentName Value="FrmBoilMethod"/> - <HasResources Value="True"/> - <ResourceBaseClass Value="Form"/> - <EditorIndex Value="-1"/> - <TopLine Value="58"/> - <CursorPos X="7" Y="85"/> - <UsageCount Value="200"/> - </Unit86> - <Unit87> - <Filename Value="UserInterface/Forms/fdatabaselocation.pas"/> - <IsPartOfProject Value="True"/> - <ComponentName Value="FrmDatabaseLocation"/> - <HasResources Value="True"/> - <ResourceBaseClass Value="Form"/> - <EditorIndex Value="-1"/> - <TopLine Value="76"/> - <CursorPos X="48" Y="116"/> - <UsageCount Value="200"/> - </Unit87> - <Unit88> - <Filename Value="../Software/Lazarus/Componenten/Mathematisch/dmat086/Units/uminmax.pas"/> - <UsageCount Value="3"/> - </Unit88> - <Unit89> - <Filename Value="Units/umulfit.pas"/> - <IsPartOfProject Value="True"/> - <EditorIndex Value="-1"/> - <TopLine Value="64"/> - <CursorPos X="30" Y="15"/> - <UsageCount Value="200"/> - </Unit89> - <Unit90> - <Filename Value="Units/utypes.pas"/> - <IsPartOfProject Value="True"/> - <EditorIndex Value="-1"/> - <UsageCount Value="200"/> - </Unit90> - <Unit91> - <Filename Value="UserInterface/Forms/frdividebrew.pas"/> - <IsPartOfProject Value="True"/> - <ComponentName Value="FrmDivideBrew"/> - <HasResources Value="True"/> - <ResourceBaseClass Value="Form"/> - <EditorIndex Value="-1"/> - <TopLine Value="15"/> - <CursorPos X="3" Y="41"/> - <UsageCount Value="200"/> - </Unit91> - <Unit92> - <Filename Value="UserInterface/Forms/fryeasts3.pas"/> - <IsPartOfProject Value="True"/> - <ComponentName Value="FrmYeasts3"/> - <HasResources Value="True"/> - <ResourceBaseClass Value="Form"/> - <EditorIndex Value="-1"/> - <TopLine Value="77"/> - <CursorPos X="13" Y="117"/> - <UsageCount Value="200"/> - </Unit92> - <Unit93> - <Filename Value="UserInterface/Forms/frchoosebeerstyle.pas"/> - <IsPartOfProject Value="True"/> - <ComponentName Value="FrmChooseBeerstyle"/> - <HasResources Value="True"/> - <ResourceBaseClass Value="Form"/> - <EditorIndex Value="-1"/> - <TopLine Value="12"/> - <CursorPos X="68" Y="46"/> - <UsageCount Value="200"/> - </Unit93> - <Unit94> - <Filename Value="UserInterface/Forms/frchoosebrewschars.pas"/> - <IsPartOfProject Value="True"/> - <ComponentName Value="FrmChooseBrewChars"/> - <HasResources Value="True"/> - <ResourceBaseClass Value="Form"/> - <EditorIndex Value="-1"/> - <TopLine Value="48"/> - <CursorPos Y="70"/> - <UsageCount Value="200"/> - </Unit94> - <Unit95> - <Filename Value="UserInterface/Forms/frsplash.pas"/> - <IsPartOfProject Value="True"/> - <ComponentName Value="FrmSplash"/> - <HasResources Value="True"/> - <ResourceBaseClass Value="Form"/> - <EditorIndex Value="-1"/> - <TopLine Value="23"/> - <CursorPos X="16" Y="58"/> - <UsageCount Value="200"/> - </Unit95> - <Unit96> - <Filename Value="/usr/lib/lazarus/0.9.30.4/ide/idecmdline.pas"/> - <UnitName Value="IDECmdLine"/> - <UsageCount Value="2"/> - </Unit96> - <Unit97> - <Filename Value="/usr/share/fpcsrc/2.6.0/rtl/objpas/sysutils/osutilsh.inc"/> - <CursorPos X="20" Y="41"/> - <UsageCount Value="2"/> - </Unit97> - <Unit98> - <Filename Value="/usr/share/fpcsrc/2.6.0/rtl/objpas/sysutils/osutil.inc"/> - <TopLine Value="104"/> - <CursorPos X="30" Y="127"/> - <UsageCount Value="2"/> - </Unit98> - <Unit99> - <Filename Value="/usr/share/fpcsrc/2.6.0/rtl/objpas/sysutils/fina.inc"/> - <TopLine Value="37"/> - <UsageCount Value="2"/> - </Unit99> - <Unit100> - <Filename Value="/usr/share/fpcsrc/2.6.0/rtl/objpas/objpas.pp"/> - <TopLine Value="174"/> - <CursorPos X="18" Y="221"/> - <UsageCount Value="2"/> - </Unit100> - <Unit101> - <Filename Value="/usr/share/fpcsrc/2.6.0/rtl/objpas/sysutils/sysutils.inc"/> - <UsageCount Value="2"/> - </Unit101> - <Unit102> - <Filename Value="/usr/share/fpcsrc/2.6.0/rtl/win/windirs.pp"/> - <TopLine Value="91"/> - <UsageCount Value="2"/> - </Unit102> - <Unit103> - <Filename Value="/usr/lib/lazarus/0.9.30.4/components/tachart/talegend.pas"/> - <UnitName Value="TALegend"/> - <TopLine Value="179"/> - <CursorPos X="9" Y="192"/> - <UsageCount Value="2"/> - </Unit103> - <Unit104> - <Filename Value="../../lazarus/fpc/2.6.0/source/rtl/win/windirs.pp"/> - <CursorPos X="46" Y="4"/> - <UsageCount Value="3"/> - </Unit104> - <Unit105> - <Filename Value="../../lazarus/lcl/include/treeview.inc"/> - <TopLine Value="1426"/> - <CursorPos Y="1437"/> - <UsageCount Value="2"/> - </Unit105> - <Unit106> - <Filename Value="../../lazarus/lcl/include/control.inc"/> - <TopLine Value="2278"/> - <CursorPos Y="2289"/> - <UsageCount Value="2"/> - </Unit106> - <Unit107> - <Filename Value="../../lazarus/lcl/include/buttoncontrol.inc"/> - <TopLine Value="52"/> - <CursorPos Y="63"/> - <UsageCount Value="2"/> - </Unit107> - <Unit108> - <Filename Value="../../lazarus/lcl/include/customedit.inc"/> - <TopLine Value="501"/> - <CursorPos Y="512"/> - <UsageCount Value="3"/> - </Unit108> - <Unit109> - <Filename Value="../../lazarus/lcl/grids.pas"/> - <UnitName Value="Grids"/> - <TopLine Value="5051"/> - <CursorPos X="23" Y="5058"/> - <UsageCount Value="4"/> - </Unit109> - <Unit110> - <Filename Value="../../lazarus/lcl/include/spinedit.inc"/> - <CursorPos X="3" Y="3"/> - <UsageCount Value="3"/> - </Unit110> - <Unit111> - <Filename Value="../../lazarus/lcl/spin.pp"/> - <UnitName Value="Spin"/> - <TopLine Value="105"/> - <CursorPos X="22" Y="181"/> - <UsageCount Value="3"/> - </Unit111> - <Unit112> - <Filename Value="../../lazarus/lcl/include/wincontrol.inc"/> - <TopLine Value="5231"/> - <CursorPos Y="5242"/> - <UsageCount Value="3"/> - </Unit112> - <Unit113> - <Filename Value="../../lazarus/lcl/lclmessageglue.pas"/> - <UnitName Value="LCLMessageGlue"/> - <TopLine Value="106"/> - <CursorPos Y="121"/> - <UsageCount Value="3"/> - </Unit113> - <Unit114> - <Filename Value="../../lazarus/lcl/lclclasses.pp"/> - <UnitName Value="LCLClasses"/> - <TopLine Value="129"/> - <CursorPos Y="141"/> - <UsageCount Value="3"/> - </Unit114> - <Unit115> - <Filename Value="../../lazarus/lcl/interfaces/win32/win32callback.inc"/> - <TopLine Value="2498"/> - <CursorPos Y="2511"/> - <UsageCount Value="3"/> - </Unit115> - <Unit116> - <Filename Value="../../lazarus/lcl/forms.pp"/> - <UnitName Value="Forms"/> - <TopLine Value="59"/> - <CursorPos X="41" Y="70"/> - <UsageCount Value="4"/> - </Unit116> - <Unit117> - <Filename Value="/usr/lib/lazarus/0.9.30.4/lcl/comctrls.pp"/> - <UnitName Value="ComCtrls"/> - <TopLine Value="3045"/> - <CursorPos X="13" Y="2234"/> - <UsageCount Value="7"/> - </Unit117> - <Unit118> - <Filename Value="UserInterface/Forms/frinfo.pas"/> - <IsPartOfProject Value="True"/> - <ComponentName Value="frmInfo"/> - <HasResources Value="True"/> - <ResourceBaseClass Value="Form"/> - <EditorIndex Value="-1"/> - <CursorPos X="3" Y="79"/> - <UsageCount Value="200"/> - </Unit118> - <Unit119> - <Filename Value="Units/vinfo.pas"/> - <IsPartOfProject Value="True"/> - <EditorIndex Value="-1"/> - <CursorPos X="44" Y="8"/> - <UsageCount Value="200"/> - </Unit119> - <Unit120> - <Filename Value="/usr/share/fpcsrc/2.6.0/packages/fcl-res/src/versiontypes.pp"/> - <TopLine Value="25"/> - <CursorPos X="3" Y="49"/> - <UsageCount Value="7"/> - </Unit120> - <Unit121> - <Filename Value="webstuff.pas"/> - <UnitName Value="Webstuff"/> - <TopLine Value="127"/> - <CursorPos Y="92"/> - <UsageCount Value="17"/> - </Unit121> - <Unit122> - <Filename Value="/Software/Lazarus/proejct1/unit1.pas"/> - <UnitName Value="Unit1"/> - <TopLine Value="38"/> - <CursorPos Y="58"/> - <UsageCount Value="7"/> - </Unit122> - <Unit123> - <Filename Value="Synapse/source/lib/ftpsend.pas"/> - <CursorPos X="86" Y="4"/> - <UsageCount Value="5"/> - </Unit123> - <Unit124> - <Filename Value="UserInterface/Forms/frsynchronize.pas"/> - <IsPartOfProject Value="True"/> - <ComponentName Value="frmFTPList"/> - <HasResources Value="True"/> - <ResourceBaseClass Value="Form"/> - <EditorIndex Value="-1"/> - <CursorPos X="39" Y="9"/> - <UsageCount Value="200"/> - </Unit124> - <Unit125> - <Filename Value="/usr/lib/lazarus/0.9.30.4/lcl/stdctrls.pp"/> - <UnitName Value="StdCtrls"/> - <TopLine Value="1173"/> - <CursorPos X="3" Y="1185"/> - <UsageCount Value="7"/> - </Unit125> - <Unit126> - <Filename Value="UserInterface/Forms/frchoosebrews.pas"/> - <IsPartOfProject Value="True"/> - <ComponentName Value="frmChooseBrewsList"/> - <HasResources Value="True"/> - <ResourceBaseClass Value="Form"/> - <EditorIndex Value="-1"/> - <TopLine Value="69"/> - <CursorPos X="31" Y="84"/> - <UsageCount Value="201"/> - </Unit126> - <Unit127> - <Filename Value="AlReport/alrep.pas"/> - <UnitName Value="Alrep"/> - <UsageCount Value="1"/> - </Unit127> - <Unit128> - <Filename Value="/usr/lib/lazarus/0.9.30.4/lcl/include/customform.inc"/> - <TopLine Value="114"/> - <CursorPos Y="134"/> - <UsageCount Value="2"/> - </Unit128> - <Unit129> - <Filename Value="/usr/share/lazarus/1.0/components/tachart/tachartaxis.pas"/> - <UnitName Value="TAChartAxis"/> - <TopLine Value="13"/> - <CursorPos X="3" Y="27"/> - <UsageCount Value="1"/> - </Unit129> - <Unit130> - <Filename Value="/usr/share/lazarus/1.0/components/tachart/tadraweraggpas.pas"/> - <UnitName Value="TADrawerAggPas"/> - <TopLine Value="8"/> - <CursorPos X="22" Y="23"/> - <UsageCount Value="1"/> - </Unit130> - <Unit131> - <Filename Value="/usr/share/lazarus/1.0/lcl/grids.pas"/> - <UnitName Value="Grids"/> - <TopLine Value="5448"/> - <CursorPos Y="5462"/> - <UsageCount Value="2"/> - </Unit131> - <Unit132> - <Filename Value="/usr/share/lazarus/1.0/components/tachart/tagraph.pas"/> - <UnitName Value="TAGraph"/> - <TopLine Value="1133"/> - <CursorPos X="46" Y="1146"/> - <UsageCount Value="1"/> - </Unit132> - <Unit133> - <Filename Value="/usr/share/lazarus/1.0/components/tachart/tadrawercanvas.pas"/> - <UnitName Value="TADrawerCanvas"/> - <TopLine Value="175"/> - <CursorPos Y="137"/> - <UsageCount Value="1"/> - </Unit133> - <Unit134> - <Filename Value="/usr/share/lazarus/1.0/components/tachart/taprint.pas"/> - <UnitName Value="TAPrint"/> - <TopLine Value="30"/> - <UsageCount Value="1"/> - </Unit134> - <Unit135> - <Filename Value="/usr/share/lazarus/1.0/lcl/include/rasterimage.inc"/> - <TopLine Value="291"/> - <CursorPos Y="305"/> - <UsageCount Value="1"/> - </Unit135> - <Unit136> - <Filename Value="/usr/share/lazarus/1.0/lcl/include/customedit.inc"/> - <TopLine Value="517"/> - <CursorPos Y="526"/> - <UsageCount Value="1"/> - </Unit136> - <Unit137> - <Filename Value="/usr/share/lazarus/1.0/lcl/include/control.inc"/> - <TopLine Value="2729"/> - <CursorPos Y="2743"/> - <UsageCount Value="1"/> - </Unit137> - <Unit138> - <Filename Value="/usr/share/lazarus/1.0/packager/registration/registerfcl.pas"/> - <UnitName Value="RegisterFCL"/> - <UsageCount Value="1"/> - </Unit138> - <Unit139> - <Filename Value="/usr/share/lazarus/1.0/packager/registration/fcllaz.pas"/> - <UsageCount Value="1"/> - </Unit139> - <Unit140> - <Filename Value="Synapse/source/lib/laz_synapse.pas"/> - <EditorIndex Value="-1"/> - <CursorPos X="22" Y="14"/> - <UsageCount Value="6"/> - </Unit140> - <Unit141> - <Filename Value="/usr/share/lazarus/1.0/lcl/interfaces/lcl.pas"/> - <UnitName Value="LCL"/> - <UsageCount Value="1"/> - </Unit141> - <Unit142> - <Filename Value="/usr/share/lazarus/1.0/lcl/alllclunits.pp"/> - <UsageCount Value="1"/> - </Unit142> - <Unit143> - <Filename Value="/usr/share/lazarus/1.0/components/aggpas/lazarus/aggpaslcl.pas"/> - <UnitName Value="AggPasLCL"/> - <UsageCount Value="1"/> - </Unit143> - <Unit144> - <Filename Value="/usr/share/lazarus/1.0/components/tachart/tachartprint.pas"/> - <UnitName Value="TAChartPrint"/> - <CursorPos X="3" Y="10"/> - <UsageCount Value="1"/> - </Unit144> - <Unit145> - <Filename Value="/usr/share/lazarus/1.0/components/tachart/tadrawerwmf.pas"/> - <UnitName Value="TADrawerWMF"/> - <UsageCount Value="1"/> - </Unit145> - <Unit146> - <Filename Value="/usr/share/lazarus/1.0/lcl/include/customcheckbox.inc"/> - <TopLine Value="109"/> - <CursorPos Y="123"/> - <UsageCount Value="2"/> - </Unit146> - <Unit147> - <Filename Value="UserInterface/Forms/frgristwizard.pas"/> - <IsPartOfProject Value="True"/> - <ComponentName Value="FrmGristWizard"/> - <HasResources Value="True"/> - <ResourceBaseClass Value="Form"/> - <EditorIndex Value="-1"/> - <TopLine Value="2"/> - <CursorPos X="86" Y="8"/> - <UsageCount Value="175"/> - </Unit147> - <Unit148> - <Filename Value="/usr/share/lazarus/1.0/components/lazutils/fileutil.inc"/> - <TopLine Value="986"/> - <CursorPos Y="1000"/> - <UsageCount Value="2"/> - </Unit148> - <Unit149> - <Filename Value="/usr/share/fpcsrc/2.6.0/packages/fcl-xml/src/xmlread.pp"/> - <UnitName Value="XMLRead"/> - <TopLine Value="30"/> - <CursorPos X="27" Y="44"/> - <UsageCount Value="6"/> - </Unit149> - <Unit150> - <Filename Value="Units/cloud.pas"/> - <IsPartOfProject Value="True"/> - <EditorIndex Value="-1"/> - <TopLine Value="1307"/> - <CursorPos X="42" Y="194"/> - <UsageCount Value="123"/> - </Unit150> - <Unit151> - <Filename Value="/usr/share/lazarus/1.0.2/lcl/extctrls.pp"/> - <UnitName Value="ExtCtrls"/> - <TopLine Value="37"/> - <CursorPos X="35" Y="61"/> - <UsageCount Value="3"/> - </Unit151> - <Unit152> - <Filename Value="/usr/share/lazarus/1.0.2/lcl/include/page.inc"/> - <CursorPos X="34" Y="21"/> - <UsageCount Value="3"/> - </Unit152> - <Unit153> - <Filename Value="/usr/share/lazarus/1.0.2/lcl/controls.pp"/> - <UnitName Value="Controls"/> - <TopLine Value="3176"/> - <CursorPos X="48" Y="1975"/> - <UsageCount Value="3"/> - </Unit153> - <Unit154> - <Filename Value="/usr/share/lazarus/1.0.2/lcl/buttons.pp"/> - <UnitName Value="Buttons"/> - <TopLine Value="564"/> - <UsageCount Value="3"/> - </Unit154> - <Unit155> - <Filename Value="UserInterface/Forms/frsettings.pas"/> - <IsPartOfProject Value="True"/> - <ComponentName Value="frmSettings"/> - <HasResources Value="True"/> - <ResourceBaseClass Value="Form"/> - <EditorIndex Value="-1"/> - <TopLine Value="91"/> - <CursorPos X="32" Y="115"/> - <UsageCount Value="124"/> - </Unit155> - <Unit156> - <Filename Value="UserInterface/Forms/frrestoredatabases.pas"/> - <IsPartOfProject Value="True"/> - <ComponentName Value="frmRestoreDatabase"/> - <HasResources Value="True"/> - <ResourceBaseClass Value="Form"/> - <EditorIndex Value="3"/> - <TopLine Value="49"/> - <CursorPos X="76" Y="64"/> - <UsageCount Value="123"/> - <Loaded Value="True"/> - </Unit156> - <Unit157> - <Filename Value="Units/neuroot.pas"/> - <IsPartOfProject Value="True"/> - <EditorIndex Value="-1"/> - <CursorPos X="71" Y="8"/> - <UsageCount Value="123"/> - </Unit157> - <Unit158> - <Filename Value="fann.pas"/> - <UnitName Value="FANN"/> - <UsageCount Value="4"/> - </Unit158> - <Unit159> - <Filename Value="fannnetwork.pas"/> - <UnitName Value="FannNetwork"/> - <UsageCount Value="4"/> - </Unit159> - <Unit160> - <Filename Value="frnntrain.pas"/> - <ComponentName Value="FrmNNTrain"/> - <HasResources Value="True"/> - <ResourceBaseClass Value="Form"/> - <TopLine Value="65"/> - <CursorPos X="40" Y="88"/> - <UsageCount Value="63"/> - </Unit160> - <Unit161> - <Filename Value="Synapse/source/lib/httpsend.pas"/> - <TopLine Value="250"/> - <CursorPos X="26" Y="274"/> - <UsageCount Value="5"/> - </Unit161> - <Unit162> - <Filename Value="UserInterface/Forms/frgetpasswd.pas"/> - <IsPartOfProject Value="True"/> - <ComponentName Value="frmGetPasswd"/> - <HasResources Value="True"/> - <ResourceBaseClass Value="Form"/> - <EditorIndex Value="-1"/> - <TopLine Value="7"/> - <CursorPos Y="21"/> - <UsageCount Value="106"/> - </Unit162> - <Unit163> - <Filename Value="UserInterface/Forms/frdownloadprogress.pas"/> - <IsPartOfProject Value="True"/> - <ComponentName Value="FrmDownloadProgress"/> - <HasResources Value="True"/> - <ResourceBaseClass Value="Form"/> - <EditorIndex Value="-1"/> - <TopLine Value="29"/> - <CursorPos Y="57"/> - <UsageCount Value="100"/> - </Unit163> - <Unit164> - <Filename Value="/usr/share/fpcsrc/2.6.0/packages/fcl-xml/src/xmlutils.pp"/> - <TopLine Value="83"/> - <CursorPos X="61" Y="97"/> - <UsageCount Value="5"/> - </Unit164> - <Unit165> - <Filename Value="Synapse/source/lib/synautil.pas"/> - <TopLine Value="268"/> - <UsageCount Value="5"/> - </Unit165> - <Unit166> - <Filename Value="/usr/share/fpcsrc/2.6.0/rtl/inc/variants.pp"/> - <TopLine Value="96"/> - <CursorPos X="43" Y="110"/> - <UsageCount Value="5"/> - </Unit166> - <Unit167> - <Filename Value="franalysis.pas"/> - <ComponentName Value="FrmAnalysis"/> - <HasResources Value="True"/> - <ResourceBaseClass Value="Form"/> - <EditorIndex Value="-1"/> - <TopLine Value="58"/> - <CursorPos X="60" Y="84"/> - <UsageCount Value="6"/> - </Unit167> - <Unit168> - <Filename Value="/usr/share/lazarus/1.4.2/lcl/editbtn.pas"/> - <UnitName Value="EditBtn"/> - <EditorIndex Value="-1"/> - <TopLine Value="35"/> - <CursorPos X="34" Y="55"/> - <UsageCount Value="6"/> - </Unit168> - <Unit169> - <Filename Value="/usr/share/lazarus/1.4.2/lcl/controls.pp"/> - <UnitName Value="Controls"/> - <EditorIndex Value="-1"/> - <TopLine Value="1886"/> - <CursorPos X="3" Y="1861"/> - <UsageCount Value="6"/> - </Unit169> - <Unit170> - <Filename Value="/usr/lib/lazarus/1.6/ide/lazarus.pp"/> - <UnitName Value="Lazarus"/> - <EditorIndex Value="-1"/> - <WindowIndex Value="-1"/> - <TopLine Value="37"/> - <CursorPos X="3" Y="54"/> - <UsageCount Value="6"/> - </Unit170> - <Unit171> - <Filename Value="/usr/lib/lazarus/1.6/lcl/grids.pas"/> - <UnitName Value="Grids"/> - <EditorIndex Value="-1"/> - <TopLine Value="5711"/> - <CursorPos Y="5723"/> - <UsageCount Value="6"/> - </Unit171> - <Unit172> - <Filename Value="/usr/lib/lazarus/1.6/lcl/interfaces/qt/qtwidgets.pas"/> - <EditorIndex Value="-1"/> - <TopLine Value="5552"/> - <CursorPos X="46" Y="5587"/> - <UsageCount Value="6"/> - </Unit172> - <Unit173> - <Filename Value="/usr/lib/lazarus/1.6/lcl/include/spinedit.inc"/> - <EditorIndex Value="-1"/> - <TopLine Value="116"/> - <CursorPos Y="140"/> - <UsageCount Value="6"/> - </Unit173> - <Unit174> - <Filename Value="rcstrngs.pas"/> - <EditorIndex Value="-1"/> - <TopLine Value="519"/> - <CursorPos X="48" Y="541"/> - <UsageCount Value="7"/> - </Unit174> - <Unit175> - <Filename Value="subs.pas"/> - <EditorIndex Value="-1"/> - <TopLine Value="354"/> - <CursorPos X="32" Y="375"/> - <UsageCount Value="7"/> - </Unit175> - <Unit176> - <Filename Value="/usr/lib/lazarus/1.6/lcl/dialogs.pp"/> - <UnitName Value="Dialogs"/> - <EditorIndex Value="-1"/> - <TopLine Value="160"/> - <CursorPos X="3" Y="180"/> - <UsageCount Value="6"/> - </Unit176> - <Unit177> - <Filename Value="/usr/lib/lazarus/1.6/lcl/stdctrls.pp"/> - <UnitName Value="StdCtrls"/> - <EditorIndex Value="-1"/> - <TopLine Value="1618"/> - <CursorPos X="20" Y="1636"/> - <UsageCount Value="6"/> - </Unit177> - <Unit178> - <Filename Value="/usr/lib/lazarus/1.6/lcl/include/lcl_defines.inc"/> - <EditorIndex Value="-1"/> - <UsageCount Value="6"/> - </Unit178> - <Unit179> - <Filename Value="/usr/lib/lazarus/1.6/lcl/include/customlabel.inc"/> - <EditorIndex Value="-1"/> - <TopLine Value="46"/> - <UsageCount Value="6"/> - </Unit179> - <Unit180> - <Filename Value="ExpandPanels/expandpanels.pas"/> - <UnitName Value="ExpandPanels"/> - <EditorIndex Value="-1"/> - <TopLine Value="70"/> - <CursorPos X="3" Y="42"/> - <UsageCount Value="6"/> - </Unit180> - <Unit181> - <Filename Value="uniqueinstance-1.0/uniqueinstance.pas"/> - <UnitName Value="UniqueInstance"/> - <EditorIndex Value="-1"/> - <TopLine Value="24"/> - <CursorPos X="3" Y="41"/> - <UsageCount Value="6"/> - </Unit181> - <Unit182> - <Filename Value="/usr/share/lazarus/1.8.2/components/lazutils/fileutil.pas"/> - <UnitName Value="FileUtil"/> - <EditorIndex Value="-1"/> - <TopLine Value="10"/> - <CursorPos X="17" Y="19"/> - <UsageCount Value="6"/> - </Unit182> - <Unit183> - <Filename Value="frmain.lfm"/> - <EditorIndex Value="-1"/> - <UsageCount Value="6"/> - <DefaultSyntaxHighlighter Value="LFM"/> - </Unit183> - <Unit184> - <Filename Value="/usr/share/lazarus/1.8.2/lcl/spin.pp"/> - <UnitName Value="Spin"/> - <EditorIndex Value="-1"/> - <TopLine Value="175"/> - <CursorPos X="17" Y="212"/> - <UsageCount Value="8"/> - </Unit184> - <Unit185> - <Filename Value="/usr/share/lazarus/1.8.2/lcl/widgetset/wsspin.pp"/> - <UnitName Value="WSSpin"/> - <EditorIndex Value="-1"/> - <CursorPos X="56" Y="49"/> - <UsageCount Value="7"/> - </Unit185> - <Unit186> - <Filename Value="/usr/share/lazarus/1.8.2/lcl/include/spinedit.inc"/> - <EditorIndex Value="-1"/> - <TopLine Value="190"/> - <CursorPos X="24" Y="205"/> - <UsageCount Value="8"/> - </Unit186> - <Unit187> - <Filename Value="/usr/share/lazarus/1.8.2/lcl/stdctrls.pp"/> - <UnitName Value="StdCtrls"/> - <EditorIndex Value="-1"/> - <TopLine Value="1645"/> - <CursorPos X="19" Y="1665"/> - <UsageCount Value="7"/> - </Unit187> - <Unit188> - <Filename Value="/usr/share/lazarus/1.8.2/lcl/include/customedit.inc"/> - <EditorIndex Value="-1"/> - <CursorPos X="75" Y="15"/> - <UsageCount Value="7"/> - </Unit188> - <Unit189> - <Filename Value="/usr/share/lazarus/1.8.2/lcl/controls.pp"/> - <UnitName Value="Controls"/> - <EditorIndex Value="-1"/> - <TopLine Value="2901"/> - <CursorPos X="11" Y="2710"/> - <UsageCount Value="8"/> - </Unit189> - <Unit190> - <Filename Value="/usr/share/lazarus/1.8.2/ide/lazarus.pp"/> - <UnitName Value="Lazarus"/> - <EditorIndex Value="-1"/> - <TopLine Value="121"/> - <CursorPos Y="161"/> - <UsageCount Value="7"/> - </Unit190> - <Unit191> - <Filename Value="/usr/include/c++/7/fenv.h"/> - <EditorIndex Value="-1"/> - <TopLine Value="41"/> - <CursorPos Y="81"/> - <UsageCount Value="8"/> - <DefaultSyntaxHighlighter Value="C++"/> - </Unit191> - <Unit192> - <Filename Value="openal.pas"/> - <EditorIndex Value="-1"/> - <TopLine Value="2172"/> - <CursorPos Y="2191"/> - <UsageCount Value="24"/> - </Unit192> - <Unit193> - <Filename Value="/usr/share/fpcsrc/3.0.4/packages/openal/src/openal.pas"/> - <EditorIndex Value="-1"/> - <CursorPos Y="40"/> - <UsageCount Value="8"/> - </Unit193> - <Unit194> - <Filename Value="alch.inc"/> - <EditorIndex Value="-1"/> - <TopLine Value="190"/> - <UsageCount Value="8"/> - </Unit194> - <Unit195> - <Filename Value="alexth.inc"/> - <EditorIndex Value="-1"/> - <TopLine Value="80"/> - <CursorPos X="63" Y="95"/> - <UsageCount Value="8"/> - </Unit195> - <Unit196> - <Filename Value="alh.inc"/> - <EditorIndex Value="-1"/> - <TopLine Value="375"/> - <CursorPos X="10" Y="90"/> - <UsageCount Value="8"/> - </Unit196> - <Unit197> - <Filename Value="../Synapse/source/lib/laz_synapse.pas"/> - <EditorIndex Value="-1"/> - <CursorPos X="3" Y="11"/> - <UsageCount Value="10"/> - </Unit197> - <Unit198> - <Filename Value="../../../MAGWEG/BrewBuddy/Source/3rdParty/Synapse/source/lib/laz_synapse.pas"/> - <EditorIndex Value="-1"/> - <CursorPos X="3" Y="11"/> - <UsageCount Value="10"/> - </Unit198> - <Unit199> - <Filename Value="../../../../fpcupdeluxe/lazarus/components/tachart/tachartaxis.pas"/> - <UnitName Value="TAChartAxis"/> - <EditorIndex Value="-1"/> - <TopLine Value="157"/> - <CursorPos X="14" Y="185"/> - <UsageCount Value="10"/> - </Unit199> - <Unit200> - <Filename Value="../../../../fpcupdeluxe/lazarus/components/tachart/tachartaxisutils.pas"/> - <UnitName Value="TAChartAxisUtils"/> - <EditorIndex Value="-1"/> - <TopLine Value="4"/> - <CursorPos X="3" Y="39"/> - <UsageCount Value="10"/> - </Unit200> - <Unit201> - <Filename Value="Units/fann.pas"/> - <IsPartOfProject Value="True"/> - <UnitName Value="FANN"/> - <EditorIndex Value="-1"/> - <TopLine Value="34"/> - <CursorPos X="19" Y="55"/> - <UsageCount Value="25"/> - </Unit201> - <Unit202> - <Filename Value="../../app/Source/Units/containers.pas"/> - <UnitName Value="Containers"/> - <EditorIndex Value="-1"/> - <TopLine Value="3277"/> - <CursorPos X="58" Y="3292"/> - <UsageCount Value="10"/> - </Unit202> - <Unit203> - <Filename Value="../../app/Source/UserInterface/Forms/frmain.pas"/> - <UnitName Value="FrMain"/> - <EditorIndex Value="-1"/> - <TopLine Value="4579"/> - <CursorPos X="28" Y="4597"/> - <UsageCount Value="10"/> - </Unit203> - <Unit204> - <Filename Value="../../app/Source/UserInterface/Forms/backup/frmain.pas"/> - <UnitName Value="FrMain"/> - <EditorIndex Value="-1"/> - <TopLine Value="4579"/> - <CursorPos X="28" Y="4597"/> - <UsageCount Value="10"/> - </Unit204> - <Unit205> - <Filename Value="Units/backup/containers.pas"/> - <UnitName Value="Containers"/> - <EditorIndex Value="-1"/> - <TopLine Value="3092"/> - <CursorPos X="5" Y="3119"/> - <UsageCount Value="10"/> - </Unit205> - <Unit206> - <Filename Value="../../../../fpcupdeluxe/fpcsrc/rtl/objpas/sysutils/finah.inc"/> - <EditorIndex Value="-1"/> - <TopLine Value="13"/> - <CursorPos X="25" Y="23"/> - <UsageCount Value="10"/> - </Unit206> - <Unit207> - <Filename Value="../../../../fpcupdeluxe/lazarus/lcl/forms.pp"/> - <UnitName Value="Forms"/> - <EditorIndex Value="6"/> - <TopLine Value="1540"/> - <CursorPos X="24" Y="1417"/> - <UsageCount Value="11"/> - <Loaded Value="True"/> - </Unit207> - <Unit208> - <Filename Value="../../../../fpcupdeluxe/lazarus/lcl/include/winapi.inc"/> - <EditorIndex Value="5"/> - <TopLine Value="164"/> - <CursorPos X="21" Y="180"/> - <UsageCount Value="10"/> - <Loaded Value="True"/> - </Unit208> - </Units> - <JumpHistory Count="30" HistoryIndex="29"> - <Position1> - <Filename Value="Units/containers.pas"/> - <Caret Line="2954" Column="11" TopLine="2933"/> - </Position1> - <Position2> - <Filename Value="Units/containers.pas"/> - <Caret Line="3073" Column="11" TopLine="3060"/> - </Position2> - <Position3> - <Filename Value="Units/containers.pas"/> - <Caret Line="3074" TopLine="3060"/> - </Position3> - <Position4> - <Filename Value="Units/containers.pas"/> - <Caret Line="3076" TopLine="3060"/> - </Position4> - <Position5> - <Filename Value="Units/containers.pas"/> - <Caret Line="3064" Column="34" TopLine="3057"/> - </Position5> - <Position6> - <Filename Value="Units/containers.pas"/> - <Caret Line="3066" Column="33" TopLine="3054"/> - </Position6> - <Position7> - <Filename Value="Units/containers.pas"/> - <Caret Line="3069" Column="33" TopLine="3054"/> - </Position7> - <Position8> - <Filename Value="Units/containers.pas"/> - <Caret Line="3242" Column="37" TopLine="3217"/> - </Position8> - <Position9> - <Filename Value="Units/containers.pas"/> - <Caret Line="3066" Column="26" TopLine="3060"/> - </Position9> - <Position10> - <Filename Value="Units/containers.pas"/> - <Caret Line="3111" Column="55" TopLine="3061"/> - </Position10> - <Position11> - <Filename Value="Units/containers.pas"/> - <Caret Line="3066" Column="44" TopLine="3061"/> - </Position11> - <Position12> - <Filename Value="../../../../fpcupdeluxe/lazarus/lcl/forms.pp"/> - <Caret Line="1848" Column="51" TopLine="1833"/> - </Position12> - <Position13> - <Filename Value="Units/containers.pas"/> - <Caret Line="3119" Column="9" TopLine="3102"/> - </Position13> - <Position14> - <Filename Value="Units/containers.pas"/> - <Caret Line="3044" Column="12" TopLine="3104"/> - </Position14> - <Position15> - <Filename Value="Units/containers.pas"/> - <Caret Line="3238" Column="21" TopLine="3229"/> - </Position15> - <Position16> - <Filename Value="Units/containers.pas"/> - <Caret Line="3371" Column="17" TopLine="3347"/> - </Position16> - <Position17> - <Filename Value="Units/containers.pas"/> - <Caret Line="3065" Column="17" TopLine="3050"/> - </Position17> - <Position18> - <Filename Value="Units/containers.pas"/> - <Caret Line="3119" Column="74" TopLine="3104"/> - </Position18> - <Position19> - <Filename Value="Units/containers.pas"/> - <Caret Line="3122" Column="91" TopLine="3104"/> - </Position19> - <Position20> - <Filename Value="Units/containers.pas"/> - <Caret Line="3265" Column="81" TopLine="3240"/> - </Position20> - <Position21> - <Filename Value="Units/containers.pas"/> - <Caret Line="3292" Column="72" TopLine="3267"/> - </Position21> - <Position22> - <Filename Value="Units/containers.pas"/> - <Caret Line="3116" Column="74" TopLine="451"/> - </Position22> - <Position23> - <Filename Value="Units/bh_report.pas"/> - <Caret Line="15" Column="58" TopLine="157"/> - </Position23> - <Position24> - <Filename Value="Units/hulpfuncties.pas"/> - <Caret Line="2515" Column="66" TopLine="2496"/> - </Position24> - <Position25> - <Filename Value="Units/hulpfuncties.pas"/> - <Caret Line="2342" Column="30" TopLine="2326"/> - </Position25> - <Position26> - <Filename Value="Units/hulpfuncties.pas"/> - <Caret Line="2361" Column="47" TopLine="2341"/> - </Position26> - <Position27> - <Filename Value="Units/hulpfuncties.pas"/> - <Caret Line="2447" Column="44" TopLine="2432"/> - </Position27> - <Position28> - <Filename Value="Units/hulpfuncties.pas"/> - <Caret Line="7" Column="15"/> - </Position28> - <Position29> - <Filename Value="Units/hulpfuncties.pas"/> - <Caret Line="165" Column="15" TopLine="160"/> - </Position29> - <Position30> - <Filename Value="brewbuddy.pas"/> - <Caret Line="7" Column="50"/> - </Position30> - </JumpHistory> - </ProjectOptions> - <CompilerOptions> - <Version Value="11"/> - <Target> - <Filename Value="../Output/BrewBuddy"/> - </Target> - <SearchPaths> - <IncludeFiles Value="../Output;$(ProjOutDir)"/> - <OtherUnitFiles Value="UserInterface/Forms;Units"/> - <UnitOutputDirectory Value="../Output/units"/> - </SearchPaths> - <CodeGeneration> - <Optimizations> - <OptimizationLevel Value="0"/> - <VariablesInRegisters Value="True"/> - </Optimizations> - </CodeGeneration> - <Linking> - <Debugging> - <DebugInfoType Value="dsDwarf2Set"/> - </Debugging> - </Linking> - <Other> - <CustomOptions Value="-k$(ProjSrcPath)3rdParty/fann/usr/local/lib/libdoublefann.2.2.0.dylib"/> - </Other> - </CompilerOptions> - <Debugging> - <BreakPoints Count="3"> - <Item1> - <Kind Value="bpkSource"/> - <WatchScope Value="wpsLocal"/> - <WatchKind Value="wpkWrite"/> - <Source Value="hulpfuncties.pas"/> - <Line Value="2462"/> - </Item1> - <Item2> - <Kind Value="bpkSource"/> - <WatchScope Value="wpsLocal"/> - <WatchKind Value="wpkWrite"/> - <Source Value="openal.pas"/> - <Line Value="2189"/> - </Item2> - <Item3> - <Kind Value="bpkSource"/> - <WatchScope Value="wpsLocal"/> - <WatchKind Value="wpkWrite"/> - <Source Value="openal.pas"/> - <Line Value="1973"/> - </Item3> - </BreakPoints> - <Watches Count="2"> - <Item1> - <Expression Value="TYeast(FYeasts[i]).FAmountYeast.fValue"/> - </Item1> - <Item2> - <Expression Value="TYeast(FYeasts[i]).fAmount.FValue"/> - </Item2> - </Watches> - <Exceptions Count="4"> - <Item1> - <Name Value="EAbort"/> - </Item1> - <Item2> - <Name Value="ECodetoolError"/> - </Item2> - <Item3> - <Name Value="EFOpenError"/> - </Item3> - <Item4> - <Name Value="EReadError"/> - </Item4> - </Exceptions> - </Debugging> -</CONFIG>