From 17bd152b588a58937df43a8ec56b4e09702f368c Mon Sep 17 00:00:00 2001 From: Thierry FOURNIER Date: Wed, 11 Mar 2015 20:31:00 +0100 Subject: [PATCH] DOC: lua api This contains the Lua API documentation and the build environment for Sphinx. --- doc/lua-api/Makefile | 153 +++++++ doc/lua-api/_static/channel.fig | 54 +++ doc/lua-api/_static/channel.png | Bin 0 -> 29133 bytes doc/lua-api/conf.py | 242 ++++++++++ doc/lua-api/index.rst | 759 ++++++++++++++++++++++++++++++++ 5 files changed, 1208 insertions(+) create mode 100644 doc/lua-api/Makefile create mode 100644 doc/lua-api/_static/channel.fig create mode 100644 doc/lua-api/_static/channel.png create mode 100644 doc/lua-api/conf.py create mode 100644 doc/lua-api/index.rst diff --git a/doc/lua-api/Makefile b/doc/lua-api/Makefile new file mode 100644 index 0000000000..b21857d258 --- /dev/null +++ b/doc/lua-api/Makefile @@ -0,0 +1,153 @@ +# Makefile for Sphinx documentation +# + +# You can set these variables from the command line. +SPHINXOPTS = +SPHINXBUILD = sphinx-build +PAPER = +BUILDDIR = _build + +# Internal variables. +PAPEROPT_a4 = -D latex_paper_size=a4 +PAPEROPT_letter = -D latex_paper_size=letter +ALLSPHINXOPTS = -d $(BUILDDIR)/doctrees $(PAPEROPT_$(PAPER)) $(SPHINXOPTS) . +# the i18n builder cannot share the environment and doctrees with the others +I18NSPHINXOPTS = $(PAPEROPT_$(PAPER)) $(SPHINXOPTS) . + +.PHONY: help clean html dirhtml singlehtml pickle json htmlhelp qthelp devhelp epub latex latexpdf text man changes linkcheck doctest gettext + +help: + @echo "Please use \`make ' where is one of" + @echo " html to make standalone HTML files" + @echo " dirhtml to make HTML files named index.html in directories" + @echo " singlehtml to make a single large HTML file" + @echo " pickle to make pickle files" + @echo " json to make JSON files" + @echo " htmlhelp to make HTML files and a HTML help project" + @echo " qthelp to make HTML files and a qthelp project" + @echo " devhelp to make HTML files and a Devhelp project" + @echo " epub to make an epub" + @echo " latex to make LaTeX files, you can set PAPER=a4 or PAPER=letter" + @echo " latexpdf to make LaTeX files and run them through pdflatex" + @echo " text to make text files" + @echo " man to make manual pages" + @echo " texinfo to make Texinfo files" + @echo " info to make Texinfo files and run them through makeinfo" + @echo " gettext to make PO message catalogs" + @echo " changes to make an overview of all changed/added/deprecated items" + @echo " linkcheck to check all external links for integrity" + @echo " doctest to run all doctests embedded in the documentation (if enabled)" + +clean: + -rm -rf $(BUILDDIR)/* + +html: + $(SPHINXBUILD) -b html $(ALLSPHINXOPTS) $(BUILDDIR)/html + @echo + @echo "Build finished. The HTML pages are in $(BUILDDIR)/html." + +dirhtml: + $(SPHINXBUILD) -b dirhtml $(ALLSPHINXOPTS) $(BUILDDIR)/dirhtml + @echo + @echo "Build finished. The HTML pages are in $(BUILDDIR)/dirhtml." + +singlehtml: + $(SPHINXBUILD) -b singlehtml $(ALLSPHINXOPTS) $(BUILDDIR)/singlehtml + @echo + @echo "Build finished. The HTML page is in $(BUILDDIR)/singlehtml." + +pickle: + $(SPHINXBUILD) -b pickle $(ALLSPHINXOPTS) $(BUILDDIR)/pickle + @echo + @echo "Build finished; now you can process the pickle files." + +json: + $(SPHINXBUILD) -b json $(ALLSPHINXOPTS) $(BUILDDIR)/json + @echo + @echo "Build finished; now you can process the JSON files." + +htmlhelp: + $(SPHINXBUILD) -b htmlhelp $(ALLSPHINXOPTS) $(BUILDDIR)/htmlhelp + @echo + @echo "Build finished; now you can run HTML Help Workshop with the" \ + ".hhp project file in $(BUILDDIR)/htmlhelp." + +qthelp: + $(SPHINXBUILD) -b qthelp $(ALLSPHINXOPTS) $(BUILDDIR)/qthelp + @echo + @echo "Build finished; now you can run "qcollectiongenerator" with the" \ + ".qhcp project file in $(BUILDDIR)/qthelp, like this:" + @echo "# qcollectiongenerator $(BUILDDIR)/qthelp/haproxy-lua.qhcp" + @echo "To view the help file:" + @echo "# assistant -collectionFile $(BUILDDIR)/qthelp/haproxy-lua.qhc" + +devhelp: + $(SPHINXBUILD) -b devhelp $(ALLSPHINXOPTS) $(BUILDDIR)/devhelp + @echo + @echo "Build finished." + @echo "To view the help file:" + @echo "# mkdir -p $$HOME/.local/share/devhelp/haproxy-lua" + @echo "# ln -s $(BUILDDIR)/devhelp $$HOME/.local/share/devhelp/haproxy-lua" + @echo "# devhelp" + +epub: + $(SPHINXBUILD) -b epub $(ALLSPHINXOPTS) $(BUILDDIR)/epub + @echo + @echo "Build finished. The epub file is in $(BUILDDIR)/epub." + +latex: + $(SPHINXBUILD) -b latex $(ALLSPHINXOPTS) $(BUILDDIR)/latex + @echo + @echo "Build finished; the LaTeX files are in $(BUILDDIR)/latex." + @echo "Run \`make' in that directory to run these through (pdf)latex" \ + "(use \`make latexpdf' here to do that automatically)." + +latexpdf: + $(SPHINXBUILD) -b latex $(ALLSPHINXOPTS) $(BUILDDIR)/latex + @echo "Running LaTeX files through pdflatex..." + $(MAKE) -C $(BUILDDIR)/latex all-pdf + @echo "pdflatex finished; the PDF files are in $(BUILDDIR)/latex." + +text: + $(SPHINXBUILD) -b text $(ALLSPHINXOPTS) $(BUILDDIR)/text + @echo + @echo "Build finished. The text files are in $(BUILDDIR)/text." + +man: + $(SPHINXBUILD) -b man $(ALLSPHINXOPTS) $(BUILDDIR)/man + @echo + @echo "Build finished. The manual pages are in $(BUILDDIR)/man." + +texinfo: + $(SPHINXBUILD) -b texinfo $(ALLSPHINXOPTS) $(BUILDDIR)/texinfo + @echo + @echo "Build finished. The Texinfo files are in $(BUILDDIR)/texinfo." + @echo "Run \`make' in that directory to run these through makeinfo" \ + "(use \`make info' here to do that automatically)." + +info: + $(SPHINXBUILD) -b texinfo $(ALLSPHINXOPTS) $(BUILDDIR)/texinfo + @echo "Running Texinfo files through makeinfo..." + make -C $(BUILDDIR)/texinfo info + @echo "makeinfo finished; the Info files are in $(BUILDDIR)/texinfo." + +gettext: + $(SPHINXBUILD) -b gettext $(I18NSPHINXOPTS) $(BUILDDIR)/locale + @echo + @echo "Build finished. The message catalogs are in $(BUILDDIR)/locale." + +changes: + $(SPHINXBUILD) -b changes $(ALLSPHINXOPTS) $(BUILDDIR)/changes + @echo + @echo "The overview file is in $(BUILDDIR)/changes." + +linkcheck: + $(SPHINXBUILD) -b linkcheck $(ALLSPHINXOPTS) $(BUILDDIR)/linkcheck + @echo + @echo "Link check complete; look for any errors in the above output " \ + "or in $(BUILDDIR)/linkcheck/output.txt." + +doctest: + $(SPHINXBUILD) -b doctest $(ALLSPHINXOPTS) $(BUILDDIR)/doctest + @echo "Testing of doctests in the sources finished, look at the " \ + "results in $(BUILDDIR)/doctest/output.txt." diff --git a/doc/lua-api/_static/channel.fig b/doc/lua-api/_static/channel.fig new file mode 100644 index 0000000000..0838a37cd1 --- /dev/null +++ b/doc/lua-api/_static/channel.fig @@ -0,0 +1,54 @@ +#FIG 3.2 Produced by xfig version 3.2.5b +Landscape +Center +Metric +A4 +100.00 +Single +-2 +1200 2 +1 1 0 1 0 7 50 -1 -1 0.000 1 0.0000 4500 1620 1260 585 4500 1620 5760 2205 +2 3 0 1 0 7 50 -1 -1 0.000 0 0 -1 0 0 9 + 1170 1350 1170 1890 2790 1890 2790 2070 3240 1620 2790 1170 + 2790 1350 1170 1350 1170 1350 +2 3 0 1 0 7 50 -1 -1 0.000 0 0 -1 0 0 9 + 5760 1350 5760 1890 7380 1890 7380 2070 7830 1620 7380 1170 + 7380 1350 5760 1350 5760 1350 +2 1 1 1 0 7 50 -1 -1 1.000 0 0 -1 1 0 2 + 5 1 1.00 60.00 120.00 + 6210 540 6210 1440 +2 1 1 1 0 7 50 -1 -1 1.000 0 0 -1 1 0 2 + 5 1 1.00 60.00 120.00 + 6210 2340 6210 1800 +2 1 1 1 0 7 50 -1 -1 1.000 0 0 -1 1 0 2 + 5 1 1.00 60.00 120.00 + 1350 2520 1350 1800 +2 1 1 1 0 7 50 -1 -1 1.000 0 0 -1 1 0 2 + 5 1 1.00 60.00 120.00 + 1350 360 1350 1440 +3 0 1 1 0 7 50 -1 -1 1.000 0 0 1 5 + 5 1 1.00 60.00 120.00 + 2970 1665 3105 1125 3330 900 3600 765 3915 720 + 0.000 1.000 1.000 1.000 0.000 +3 0 1 1 0 7 50 -1 -1 1.000 0 0 1 5 + 5 1 1.00 60.00 120.00 + 6030 1665 5895 1125 5670 900 5400 765 5040 720 + 0.000 1.000 1.000 1.000 0.000 +4 2 0 50 -1 16 12 0.0000 4 195 750 1080 1665 producer\001 +4 1 0 50 -1 16 12 0.0000 4 195 1785 4500 1575 HAProxy processing\001 +4 1 0 50 -1 16 12 0.0000 4 195 1260 4500 1815 (including Lua)\001 +4 0 0 50 -1 16 12 0.0000 4 105 855 7920 1665 consumer\001 +4 0 0 50 -1 12 12 0.0000 4 150 600 1440 2205 set()\001 +4 0 0 50 -1 12 12 0.0000 4 165 960 1440 2400 append()\001 +4 0 0 50 -1 16 12 0.0000 4 150 1260 1260 2700 write functions\001 +4 0 0 50 -1 16 12 0.0000 4 150 1230 1260 315 read functions\001 +4 0 0 50 -1 12 12 0.0000 4 165 600 1440 540 dup()\001 +4 0 0 50 -1 12 12 0.0000 4 165 600 1440 735 get()\001 +4 0 0 50 -1 12 12 0.0000 4 165 1200 1440 930 get_line()\001 +4 0 0 50 -1 12 12 0.0000 4 165 1440 1440 1125 get_in_len()\001 +4 1 0 50 -1 12 12 0.0000 4 150 1080 4500 765 forward()\001 +4 0 0 50 -1 16 12 0.0000 4 150 1260 6120 495 write functions\001 +4 0 0 50 -1 12 12 0.0000 4 150 720 6300 1110 send()\001 +4 0 0 50 -1 12 12 0.0000 4 165 1560 6255 2205 get_out_len()\001 +4 0 0 50 -1 16 12 0.0000 4 150 1230 6120 2520 read functions\001 +4 1 0 50 -1 16 12 0.0000 4 150 1650 4500 540 both side functions\001 diff --git a/doc/lua-api/_static/channel.png b/doc/lua-api/_static/channel.png new file mode 100644 index 0000000000000000000000000000000000000000..79eb6f78df3b472b97d5baa4b89f4009c7b781a0 GIT binary patch literal 29133 zc-lm}1z6MH8#WGz0#YLcq>)x6CpkpAOS+{QDKU_i7NlE*QPMJ`8-yt#!i0g7mU6)8 z(fJ?W-~WAIu4`QT)H&z#oaecp`+m+@yq=CK`F+OwczAf^>S{_a@$l}1;o;$v6BFRh zEZVW(#ls^J2P-P-IXF7mLfrjqe4OnB!S?oecyIEv(wy}&Xq+1Psra>8x z9q~81)$2+KGiG2p=W911hH$y~Qtm$z`lm51^&3FEZmI<`ZF1Hq<+S%g~?~ z_6I}5WU*s1===|NUQpe|d!dZ~^5xwSIr?B7H5Ue=9**>!51#0i6_UlZD?WBSyc6Tl zUaS@0xX1?(p6R`}A=c71cyCt;-Z~|-Tj9NBzKdsU__6~JPl^;zAPm<4p3faTQ*WD4 zW;|1Un^0Cf(@Q)#B0O567bV|ASM(Q8!;cB@_-6O-lGKZ|Gv73s%Ik2+#b#`v?GWC+ zum7IzA?;|=?R%t7Zytve$!o#z@V;_94W*Ie5VZb!R#>cZFE(~>S7_m!fB=s;c(3>7 z4&LJ71S5VMDc+x+@Wx8lw>wsNFH>$t4O0k&@8fsu>@}QD+lVpa;j!|4#iLV;BB*@J zvmQy68^Qf2lBO+6g75{OJ09yd#ru04La^ zB$(Jw1L&viiVS>1sYx6Oppx!a`b4FyL_RK`2oSVOlH`ECW1~(`V)s^ioF22vDU(M1 ziMdLiF_mtWewEqhZhJf#XG$uG1Kk4%MSQMNFMpHFAJcd#^uhFNlif`O`Jmlk5=y|NK?z? z*#y+STll6{^43)8GY^!@`cX2V;vJisVfv%tcdJ_WIm^=Tt7UyMo=~132In;?(Q((L zJsnzDbvfYidDtF5r`e+jeI%s+jgOJ`i3T2bT0_)JWpIUMX`;cx%PK?1YN@H5ychF2 zwI$G!g(4k2xruM!86c6l{f5ep$|#pl>&D~ey7I_+KDYIc|*K;_g(fC_U)HVzVm)yFo@asx+)SN`Y{)kYal?N8MQW` z;gIzu%!$1IANM!zMD9o~A8uD}K{euO28)920Uf8Ddfi60FLLTXG-uQY)OOO`bC}aC zGt;vgvJ%oBXK$u5W}S15runDqq%R1~KfN-%$6NYz874dMok6O1k@m0)WB`vRd5qH(QV?H2T%;i^laCSs;SLf z-8`;&$F+2ZXJ&t~i>*R`VzJLA3K3z2YH@>*7xYIVmwr*)rWkv;5YF>I#vr$uE;$<=4c%D?B z?47tzwGzjpMI)3k&lAd1s6DE6R=!={=v3`QYGS^Vg>O_petSab?oxGasS ziut4m)>J@j>KT}mxwr08+zGFaz=iMM z92-X*O}c90FkvVWi9iXc#rxT=&JP!KCt;L%alNWZgTA^Rx;@Ty^qXrtkgskbwKFr5 z&GQR?xBrEHy{Jlw)s02e^$^;yEt)UVhsB1Sh26Q{~Gl+g8_)7|5{ zB9Z-3=8<$!EKws-F&yU{77CtmKcab}kE5yJk^Omay5CZ@GHsrZ=eWA~F8hL#j@mI^ zo~hHRT}%Bc0|P@z&X4w}`lxEDM$#72lF~@^J@p~_SP;gl@kmuFi$SX>(|g}!Qf*!rQhUC4$%T=n`JUFTDBi?mvOi;I>j_a}4W&GU{I@hq7v z>M~(Zg!%Y{-n5FnarP<>Svu|?wi4`|Nl;2SRkrVZ8i2Zad%>|3S1em|Vz_(ulG!Sx z=3CLH28Z@clOT*LoUJCza+;|#pz>$a*3k3*p2<+k%lqq_x6x|MlTg8fS~@3}y|Z zxhcn@EqVT>udKL6zq|f`VafEko?csC`;MGh)B%nS zUiOO_H5?|pCl|+*R@gTGl@9Dt%^m+cIi9BTlHthZf9)1?7W1vzUIFBJWd7Gq2Nvkm z4LuY~ql|38=CH9ye{!E_wH~U zaQS!n8M`%~gR$1>)(CF~njBXADTLHLvnjk9Ij-wFOFgTSxRiJjp3{>R7JON--`R7w zFvfY;U_t09U3lvC>t)W9m9G_lb&;ACJu+NhhEoe>F^q;|cex4FU* zDU#P}X1;iMWIDGW{P2K8PTWZrKV?%t11~4P09zkNJXJj{c2yTIUq4@aAMk5Gb}2#O zXV^Nc6g)h3Jar{`!#DZc1-k2(r&c%Es`+`ZfNc}3Swc9V#euJh=)K21$OG4`Rj0ca z)L)1;?mL+iPRqJPzH4UZuFtHcZzYM0gXaIrh+|Dx41TPkkP?~R+WRtyn)kqCWXE{x zl0vt~YvH4V=!XwKxx@<5D|<`WVXobiC)f{Mh``?Kd5>0$B!B`jM|3I{3#%e$kG?&i zysLpQ%ivN65X#CBb40SgwlX317OCM19_75fu3vnZ{|ua`qCeRP_i0Zosf1xVU_!4b zGhvzS|L>MAy8}=iX6EEdU_=Yq^)*r99bdwyLqF!hlPl7nnzud9{+%~qdI4iVV9UiL zZu>J`bVZHNIF*_bVU~l3|&M)tmZiq zN*V;#YOb7KAsPgt*!Ms}2w#Ts9Xi4YTZV~#5CRK|+ZQ%MK@eDhk(Vh6CB*)Wu}hK^ z)>&fZ-~{tbd%}eypN;z>Wq!~2cpCoX*u}ec$ITO*G0nDAHn@%^mkRVR%H4wtUYFMB4 zVJy{PyR_yGB_=4Z{EjodLT-6g&*nuKC&SzSOh;OVPOI!_gt>7jS#a2r zDt$x;R%hbO^1$I;v3nx>)j?^a=1&fl#{I{}A}3C?S&q}s>5?HF(dPb5sv3;3Y3M)z z;TuJuHYq%HSPN&Fq0tu`fn3#m(K;IGt2+fiS8E>i<&GV@`nJwa3&9*8c|#1gq|Sa#Y$OKwQrF9#bN#cvK#vwVwGKH z%TNyf@xpYrC42SInCY?>{EA{vjVo>F0Q9$bwB?raC6uhQFSZ_TDOPf;M`mIbb(M&h zIs~)b*VtVJ`e4nbtNOzd9JddP{7bDW))V0r%~;*a0n=#Q8lq7Q0;#~1HirE3?=*Vy z1m6tdQ$wps6l+VXJkHm#km>?O+l~loGD2jhUKY(Df0Vw?98r`en(S~57uWi(X=GGY zn15_B{)UEeO7~=JA&hcr`hWg8=g~R~KYF}T4#R*DRA2rGCUHgMrUs}j@TdjO7X#P} z;AGk$X8Pii0Qpf$6FXC0EyS(<2ou^;g<Ig#-n?pYFRAjb9Hb5r3C9;>HU#%SvheSc|*l7&TMHxk2CRwG_)NHKO1 z;0Ct!NZY`y_F?tD(r}xlU@2cU=3F!@Wmde#S!w7spR8(W<9i-lHznY_70CwScK|!J znq=1h3xa|MXKfyhK`PN?aY;bcC`ZI?i~ZQHDs6@jvof4M58F1S82#F46ozUilHHUH zq#+Lg7e$oJ{yIp*W1?)P46d}Ni;VUqB>5h*EgmPQ4Qs@XW*SV=oI1 zP>|XAjS{{{{F*6^o*A%j@Bo+k>QIu-n4%K`8`5k(JYA7s%kAvEnRnb8HPaH8$~16t zH7>VpmR&X9tHYbTa*cno^ChRcI%F|`xuUw-U_dGvxy?(2kMPNMJT++XCxz?nlwvw; z8D=XA7JgZn2G98Fw1i_r*{nqm=TqbCsq|5h>9lXa(NQNPm`vrx1$9#hW~-^9nepFQ zPYS;SJoy$39W+5?HPBZTqnn8breq82QxXpT(^wpaOVM^t&vRu$qf_B7ApK;#5^W>* zD_Q%LS0?b;C7CVd=axcPKld(h#jGxcUAMKH#)@542J>KFb_pL)8w>KfIP68PbA7%Z z`E}3izL``JI`F02a>>`X9*jwutx;tawhRXb(HZF#Z&^O&;-FFQ>z`haMrnKa%&5~H z?x#=ZWIAmbI$*m&S##8WZ7H!Hvj!hu3_)H8C4aXbE5H*8OeYcp36fE(J5tF`3!8N$ z?!TY8Kw-O<##8@)Bz1qz99s;|BX2$0IPDSo2wM5%5E+urg$sB@mV54;|BqJnbi(5i zd${lFt$^ll90RalEkYH5Cvv$c;+X zTn>c#1uSq$ghz^f^JX@3=@+s@Jv-zJt1i=t#f){pVgMc=VxB5yF244UmkRml+Ld7R zvzzy2w&R7Vy%d3c4pS((xx9m+Uv`HR4w!1%9d| z7r`*>#HoO{lL-S9ozxUTJ_37>2e!1{y8Oz>{H6Bxk6W#{BwP`ralr5duE>65(BatB4}MIJ1bSrtaa;5Xz^~8Z8lIPt8XRq3eBAyo2+&qEGiWDx6g4S! z5!5YC#+gvE<`WnmzIaWRF>C9ZarY5ySOXa=+_+L4J9NH3EXGMJ_EQa zya?}?ckbz5pp6#4QYUexH8(Q)BG03{-jS@h>H-%7wOFaMRye{ z(Whx}UaW*F3Nq*oAmT6Ol98j7t%sf>v0b0vk0F-E>!F?gU*F0;jK-byu%CSBt#-4O zUczT6cLCEg@tL}vm=|}=jEop!dv-?>@sGX^Bsn!szj~h;Yh+|Qatxk{KnErzCW(79 ze=Kju7$pjSd!x`Y`;?WWS`?lhzCwb^c>OCZc3WHC1zDI`^gPzFqrOSCgYnDSFR~O5 zj9G9{?BMZNu9Sg9t%EkQSlit4jX)?2^JiHyIWc}qmjI(Hwi(j;zC`at|KTIq;w;K^ zXp%ENRP;-+YLHz?%hezJ9HX19H-D-qMFR_b99NHV=>+)N?D&oey)lax((uYVuY3wp zfDWWpc9l5=A&|hVP7)3PM;_O(YqO{}(wi9xG^sI4apOT?p-!5vpFkXU;N4`uvljtQ6z1amB}@hv1|+ac{E%>cN7E~yX@>XUuYA?f0^v~B ztt$p={@|2d4FaHNBMmEYt!Nl zM`fYl;z{u{M}~TjS%r5?5VBY4WR5!Ngf?oivnv-pfPRQoNXaVkrkD%rK?G4o6B|Z= z!FOmGsF&tmbp1UJL~Di$aq?zWEW+;y_WlV zAL?8L#tudS?B4YErP>BFJ%tiKacNh9@E0l~0TZ+YzJ0*AYdY~r>hyVQdS6}({HCBtqtvPd! zngVJ)m%T-^(-lROC0B%0)i0$`}sTf)%hQKFdqO?x@DkNT;mWKeCxf-9pQ|I9MN8puIoRFhe20@y%K{ zv_jk?_)aO`%u$G_b|YFI$HmPlPd>`OOE@R_jFHwhFcgrMU3x_f&!Cph;APA~tUhGz z+;T`K;=qO3A#+kU_nIui&4FMFk|Y3uNLZn!LLE5P@A0K2@oJl86R$5EL68lfStDi( zZ*>&fy4hiR-QPJUCUy2 zBYVB-+mmT`aWys7y*6+jpGr~}q@8keptvC(9Y}m*GE%$5Mn72p^Yw03S9hrS%V3jG zcet>BRx;9eDZ*^|!#+lT`;SF<8TT`Rhup-l5`B5)ASZe)>i=CLD$0V8= zrwd&&9Ro!WlT;Hl6snLV!apse{o^>Q$UL;`KtiPu3pYi?5s1>vKD<-uB^R%L%kctT zUQhV~V`b)aIn=42WkE@^qXD8EIELlJcN@N~FdQdLW#U9&t>n+5Q+4=cZ@H(!P|T~( zXqP`Nvdtv8BS8%SVTEBO_bUD^KnZkd;lwdHTsU_@XGs3nQdljs{s_3;vP8PO!@J&; zR=LmOKb|RwXCkY*(obXfvW#_+tIrnP!HaoKC_kOjE0ks2fB3~+<1;B+FpMBgTm$}7) zH5DsVaFbU$SLdgSaxjkZp&$^TLOHj3I$y#bq!Q+a1g=OzXDY{EoXj)`NPN^rcqXQD zM9*>E#sGlwO*$70Q}V147q}k0>J8?#hT+Uq=WCXP5|^#UX?HTXo`kWHquFn##tpgGLw=7tV9sVO7$cxR+jB+^XKpgZ#gmGb z<*h@@{*R+7sH5s?ilBI{$lVLs022i@rU6_IUJ%R!=ZRaQ_u6ZcM8>JBmbBr^gH-(6 z)Tbu_-3eJ)AjC9jvX-VQJ|Zkk|6hlKVd$;Q9k1eA_Lc=oSx&9*1KD_h5X<5Eg_4Vmee% zyU-I`uV}K+9V~}>`T$Wppdqd*$I2_NoAosUi?gb`WgTiWB6+3hM9Ne8fi^P8Qeg;E zM4IxGaPcIVc_-WP87!@YPYbyJd?z1xpaz|jVQ4~)wlu%A?O4}L!qJ0pXqN`>D+YovcWxr&|TAcI@2xI}R}_;0@u zRA-1KGkUbjj#Eqabq-AeBf?}T$UfPVk%^Y=0pBq!$k5o8nTb%IGyWy<_#3|}k<#s| zU?1U&?%?SBWB|d~I?Y`Jv+RPDz{yA#uidj(D+hi0qF-qd>+#pi;r| z6nYG?@&GRN5@|vm8@5eLfh{xnxx20jOa0@J?rvy8(S(ZQsAA_ka9%kk2>sZpcU0k> zRWk7hY!k+G@uZ9aXQT#!kbtBWhRxpY`i!L38Huh=1LvLhgm-*;A^c+H`fc6&P6{az1(gK=2m$A2 zi?ub&7B$B+ibx}NWKhW~Pr9IfsMEvC`ij z?G%d#L*wpi`)FFBYNo2u4YI1yWaVPoVq}UT^z)vr>mCs|nSkY;9g2~T!2*7cXtD^L zaxS%kl(Eq|q`enJi)lqRCkO9f`vqEM4APaMSrzW-XwOyE& zP>`9?n|b9$*9UU=FZk!`>M3! zX|t7OI2}s(q}MHW_>}aci4&$=%fO7KaPD_zcAt4U;KewWVbDQNB}&BJh=V382{Oe& z@AI0=R4hmI7Y`TtD7rm6$Jkexv6TUzSNE?kP zjf3fuYqMQi|C#U&@xzcsib(c^l5PJBVP%H@G7c`s7G0fB8UsXW&4$wxG7=-J<=Muh z`Tlp2mxGeR@VP>jNtn%}(nj;z1CW<0DL~=fz_JEsq=J|PnM~;%9>hwB?mb@u85}3w zCJR=Xzj<5I#*~9c)+QkHRijcum94_f527t;aQWAJiMbTo5KcsHH{0Sd`~JI~*T-z2 zworJSm0-^H%*^}m%kOrcQRZ{08`osPFqosDR~L5_lJ8L!D(nBnkpGsi5Z@FSI#V%c<5%I=X8tCnn>4J zjK&MY3sMzrDNn{3PQRNFr*V<|;I?~EZS}Ad=C)M|&a-7mdJ7U@Eh254Yimuq7$2IM z7cQ?o)+3t$YUe(Ue!;)hLQ{Ry#W=(hx1ICLsBE78quK$;rq=nbk9^o9v zc!~pwFVqvv=GrujR9}P-@-;aVujci4AwUCJ` zrYJ~=WraAJYyCCv>Z=w9u8_su#bQ1jKc0O0adbeK3}SC&l#Rrc2>)qM zFX|c^8nP&%ZSYJc*&c#kLUWHpWJemT>PkE{d;2H>epfqzi^Lxu0E&!^v^|FQ*$cv5 zpAfh6+*Y`P4aSf_kG9-0gjHn6A^8dUOAi%wupFB$L$#B{@7ZL@x@)>*hCQJ@5 zbAcj}u9Bk9BfJ>fRhS2dv6qa!&qS8qnC0uI~9@x8+sr5TR>OAlNtx*e=x6G|Cj5$3l(^a z2XcZDSiOi!Z+8G;Qtr@kZD8GTK`PFSebhrR{0r=&7qkQBF`Ha61RQ;0&i2SbD0wBf z`~%l;a}y5*e2;O3koW^2JCiM`n<5|;E#+!a^2N~#rB7Sc@W8_1&uv}P*36i*gzuIJ zviC*<9L=PYef1{wtxyf!qLW`NK^Ao=;)l!)DVPq^s7#fAfvkk`R;X(AI|$9lO-;3F z&)yDGfn~|C+<=g-I1@$&)u9&vDDVa$^?z`J8D&kZ;n!^~(K4d2BWot9c>IBhXj*_Y zM!cnTXq`J)bu^Bh_yB}xNZe3b{YRznr-dbUDc_2D%Smad7#FW9GBGa1@2=f5O{MSp zY0h+hLgAYk9Be{1gyk$vAJ8JcA+tH_te*yjT8^$_G#x{l&WO%$<`m zAE-^WD*NPU7|4mc&b_9(Von`81hHiph#FnvRdR$5tHj#=)VNP08h-1P@&GLlf_DDR z4r>9r8Oy@9XiL^XZ`_e!4whfCkV{?nt{sle;(VgbHS}$CMO7{PE<3_EmVjpBt1#I} z!$0H;;%>FA(0n&K2Mw&yDz8<=Gbc z_utn{-qm3S%ux^kVe*P_P;RQYEdyh$2#qT8XIX`#nOXMHVANgtS9wks0@5GlXndsq zYp2C)Wx=0iP$~de49+vdL8t%O+EPtty^20iS6gdH>ldV3V1(mYB7(dFq~-B_zv!op zvj=$bB!lY%f~puDvNIt8%cY>oRjuPTf|c@Pj+Z#Mhh(SAlS0K-0_@=8L~#@j4@$HK%QP z<@|99jjhL93h#j0B4Y~|7J22JqKA?0cH|SiLGL8{mGvL80!I1bYY^ zhB3dY4z(20J`$M=Jb4(_$n?J6vnL(XQO~1Jt*qY}LGzGU@O~Bl>|+DiPV0lHu6rqa zc$GQS*IGzJLHfSxSk^2HSS8iY=U)&OepO^PE7L(YOVTt55rwD_7+Le#kW3Cj%Wv=@ zuzR*c*pPP1>a0(DTVDi7lhgov389l0AEhZ20?rrnL5N_GezxN%@|hBh5jWw)k+13^ z)zb-K4I-=|Zd8^xYaO1SV{Jd9 zFjcj=GQR>}ZZA1Q(JzOW;OwNKHsxE(scO_5(bcM$j)6hSiaT!mOF6y1-;Yd3w7XGe*+$uAn2rNNmO=gzQEjA(qruTgBcMe8e9}9A z%5|zSb#YN20o4Ato3THgp0*d-8y;7}CouA|)m@y)!R^P>+iFqswEH>boM-Fy(~7?r z*Mb+J|D^){e5@K}j=0s5q;Ngx=gD6^yK%O;j%F(a9JAXk)zt<&YP{5g`wJ;-)S*HC z*wFB9>(lE-zj~GFC~`k<9mb zj%IcbXh=1ElrMSoQ8Gpcpg|unt+E2~w|q5SSrZlS_i9ML^!ovdw=yfn_8kL9^qb|* zj5&O^BmdvDc8YP~|3(_zdC4|97Q(}W{}!_O1pX&^;JA1?rXZL5YbsIXwi<$de#7Ku zh1yk;X!t*S0ifvl*9|6efzTY?aUi(@O$vIrm-=T!n8bE`C*9 z-+9#6#j=q1H7R5Qiuu>QikEH|$*7y=7IbKa?FlcV%DY>z-XeduVcG6JM>WuaZ^en0 zIr*??>R9~^e%4FM@#*)s^hR)A^2#@F(9JH1ZxM&e+C{vA+#9)KCAP7P54S6@12nCnhLnjsu<%G)a*7Lesb~(h`9hL z$oD(y)vs;;_eujm?VOP{yL!`F1K}ofj!7w;K_6?SQj)a+9Ab})O6t@ZZ$;VXS-wr`2{`wBGjgzbwpTkLQ zzGNWLn$vzhgz4wyfO&QqprjFsC4bAPSTl8>pc3Xb=-nVtQ+jv1?q~QP5Mgd987a2dCsh%l4QnD-=EasK}!{p@_S6bl$(SU?!HSuVtIV@%aHr zRe>bIxTGT?h`nX#8@-YrhlUjk(Oq_LgST>J`rMvE5UWnu`$ca|=KJuV$KvZ@vpBTpl!kx1$=|kH(MT`vS4ohYp>+CH)h0Kh!@XN@L}8 zcj#s$sp^KEI2w@iSueK#gW?WHLzA&?vyhqS);GKWDHH(yMPR0f6sLLKfT%?8-)0WW zd(xRM7b;S#_kh2(T|E=StbKdxbxhk{S$_FSV#X;Joy!HZ*h46I=wDWNI(cLIhgF86 zx;9OzXg_!cG<@-xJqfk`?%;=ui95{^6teeOQ>m_M`Lw$NTJ<|rt$knyx!Xz2X(6x6 zKIzJTd#os4N6MjeO*`oA`68-6(5IfxF%W7~?%ZeAr|@RwM_Fq@KFMu;sF=#|o!izf zm%K{ff3%=at3m0E%QBclm(Y7*adD*>hg{2&&)qVNd?)~CQD60LmzBDEdvWyJwfYC7 z7$a@GC?qzYYKk~Ro+YJqWaN{;ZkK)#IQ8yR_6w-JS^}L0ie_G)W0jD=No#E+Eor{x zN|!8vI$@IL^1T-)&#KnkTbx25Roswbl%Q!kxh+1te}RVLXn6-r=pPM;h0x>^xEdq9 zI@BD@Fl=o|o{&vs!u3Va|EWQcbuM3mr;zMUu{@6SSFSxBI%+Vl71T2~BKCed_8EjQ zsd=#3Rb$WE4(Br^lYB=Y7>aCu6*W~7(-WaK28-l1~ydAwa zSjEAZP`(Hw?L*6Y8cy>NL#%cbT9^!p+&kn_*Xz5EuwhT1RTJxY^g2hykpUKJ&5xr? za~n`9?&^;MLWz5v0Z#q51qWHWht#btRkN zqT_+mNhJx`F*9vEKFBR^x31Iw7wBp+B!bJ;|65BPSo*w4Gf()>?6EE}M{p&rvWQ20 zsHg?=pjjPiJ-f$J(4=MxbhmOvlAiAouCM%F^@YcVg(l=U7_-z|XMNajHiag03%t+q z%a_tIyUI}!s@lg?Hs9C!LWu7Y3U z+iuAii*K_zNtfoPfI5;Q)jJ%Q#n5I#X%vnE%l`LB>)`q(4Zln&8ASS}AC9*fO@)wg znhd(%<=cExFvTD}R}r&`WyA>y^75H^uF@KW6kk^d%xL^!EJx$Jp^Zv{$(C();(x#D zFmqGB>8`hl-~0QOag1_AUJAgl7YU479ymootYt-2ac?%I(*4K@|b zL0g<2f>JOP8Hz`NR<}da{IMupT8S8*rI)|>7idj;SD9Dp382U_PFW#q_Kn1 z^ko>2UZ^z{E;Rd6EA}rg{<-3%T zN;0Oy**uUOp1S6RzB7e3y4@k+*Ct1pY+RV}W){=oZzVw-DVe+?SsquQ6=TbQIg%!W zPq{u*KOa8}+3{;bkXIwlZX@I}Qx1@9P}l*pc?13=plMc{Q6uU=A(?DIt89hJNx41* z?P>+(P@FteIFj<^lO5zh_%5DcL1@`^j@OmvKe3kt-Jguoxx8;{B6Qa5jkrmbOqNAh z2OQKo7(6OI&llT;&b+NbH>0dCHcfiZw;B=80}odBR|dU$ua4_( z&g;U@Mr@qglV7is*r~3au}|@O#rj6oKnJ7B--X|tgx~zO@RAKYP(n8G z>O#A&j%OFof47FA1H#ZxY|eg6-b=@dhHPW)7W~bmfg_>|uEY8A2QrLS)&pj%l4GVc zp_>MUL2Fqi*O=aG(tzvMg&<6v+~rb0@5Q`{b>NzB;l&)EL8|`W88oQ)5ClyLzg$sx z$98i%xSaz91s#A}kh^vS%BiLkVQRjj@Ou_2CRO@krps5`k#aQzR{6UO!nHy<`Rt#lUn0c?AQK<#Mn;&lS*(ny{Y4)IrL;*Yg~iZ zIREq;?{g7{R^9M(J*Oii@_AOlU?lTzP+IIPv&X_80US|gWh3l zCShgHakxfz+-xppzHf0f5^Q3`7gnF%f<^I=2Jvw zXUXBOnd3&3(VXhk9N)eNl^5zT58kf1iSE!p9rV`8Wc2FVAEQT1) z=?SYt^z66FE@W{x1cH)P3ftWTxg}1MkggOys4S_fl}sEH{acZlnUim7VNDS!bHiPy zAu9b@JluBuH5(BU7*I==78kGO!&Yy;Wb}!y*qd+CSvTEBQI=MDDbN~+${PVU!rr&L zcyVo!-EPE{`!2VjPODt1)XxwbA#?MyPGf>nc9%YOA|ti22-ES?hebJ*N4*4de%ZT# zqdv0albT4sSLqGlyxZ+E{L!x{zlbdbE<6aF<%Xh@uB(bnxyUP@3z3xZa;!x0sBAWF zD;=4kAhgOR#Y_{xDabq)#OK8~9#PrPn3N|>KyW>oV~J|^=o}Bw$MF++dzID9Nk{=& z>XGA=iMLwC=RUcb+wDy5vn?J>EBSWCTnUd7+s$id8Y{pF@Y^a|<-RKvT{ES@x*%B! zH7V=!(FON5wb+t9f3vw!nkIjdIHtioxblz5RwQfw-@E%$=(XG*NI8q-_eWex++^^v z)1lIp=b?)yATKf`#mX;J-Br21$r8S%Y4z|)jd)T(uVynjllVvSm-t`s$h_+) zVvgo zY|m_GmYuIQvv}jm`I}}eVDUsG2k6voy({{_YlyEnI}Ufb>$Qr=S8SL5qc6ireQgNR z7aP;j6B+qB46&U%ma3JAQK!w(t4l`Vo4#D|{{|ERJ(6Wkyn=fzeQK^S)* zOr{$yeH^_frXe5SQsVO(37q;SV1*)w>+yPcrTyK~LS`Pr6{JqR>FkKAo=JR6Iv13e z34-!^c#^p=#Gc!}g~qllT)0*o0?F)A*Iz92%#9vs6(|KM0EQ3)8+TwRH~t0^{o-?w zL?%?5PjR*8W5zzr~%_>oD^Bpu;A2Gw3>DmdfAfo$gjPFihzm~ zvB|j5(mX&?HYKb}5X=~G$MkNke|}5{PIy)A;I+roNRX92jj2E6t92z7T0B|%`1=Mo z688{_HR6w><+6+m_3EF{{+-I7H~qOb)YT{r3!P&o8gb4hb*s)$N&eoc=lQO~zQKR1 zdATwlfB(Dd$yckh5&!6Hv#cTk1ZndBiyx^mC0my5vEHw8iI=$!JE2n%7gsC5-u6_8CTPdSuy`^P$9NMP1}W%iLpd0V&V;Utzx`T`Igi36!b8yv6x?hO!12$#@(P=+q-I6PeQmSipIA`Bqs5bvhQyK~ zZ|0*9_!}hh<-e`BKUp0UTlmXHADh3knYjy{^elr|N&IFUY50sWM;&#*MjC)*iscI^ zNK%K6n&EEX(XSZaEt~AJb2@F963d`jtubfzYFB3`d_wX$nfqHUM!isIOcm&=(PLx4 zRM!V!mfd|gp^0M}1cH^$(7=BcVVf1t&&N|JQUIIr7nyw?1|nT;)Sf?N@!uVkL6Z$cKAGPGj~v3 z*TK}Dg&@*!kcB)`*0#lr^m8#W8P7k~+qem+*;y)Mg&6?uUQm zq#O*O)E-tuL0H(bs&Rkmag>2adK>&PJX%>+)aAE()58DWVUzSu#f`)2L4m4G`|8q* zBdJHbZM#KegHDb6p==9miziccU9;Qb$@X)BIQnV6B9UxA=zY8Aui}c(Bc*DAa4pxv zo{%WbKS6h4dvzr;;ZKV6`igzzCN9V-xcpL4lhSgnnA1Ftxp_gvn zchlLaQ_J|V_E^{Lzj0aIU#lsQsJS*tDXOl%-A@_Ko%hl=jJiP}c>g=S?!zTG+x6bU zlM~A8zmx-_xpUMw$PYVeFp=NhmiE`96f0`ZXM&>pK>URuguz{-mCp0{gc^R?X54^% zl#cM*TZ7|(CHpFDT(Y|E_!Hv6^tb^N8yQ_4>fRhK5dA4e48@+i+t9E2osR@+G*#uC z@DO3xHt9Z_>M{|&G@9a{XsoWj=GNU?A1|fy;A#CaV zrm3L;_Ul;QOohtM%d8e|URCx6t2(oxRYW#9Ca~Y=*gYBp>N$ImmE<-u#o$_3|?L`+EYd~vO6H}g1ri&jP75;duY&7@{bl6?UTb#V{A@iR+70pC0!nT&>VYp@ElgaY&945H%kU?z#~Rz#hRQA zEfuz-Y+TB(Y|ESQJ=|ewlV1&7XiI73eYs%?knOmuhER%T9(8_>{ZJQnR3j?`y1B%L z@6(5Se;aa9Sdkp-y&UOfc4Og?7|Gz()j6{hUj1>^Pv7(U@N|_!FT2cR_KwwT=j6y& z3J=-C07=Z{J%}CGFkeE=LrfLeoL2cD;Ly>N=&ia3JnI@kL5M3w`PiAN=d(c7vMQIMK(x=i1Dii7va6cQ zt{ljnkzramJ`|p!vaNDIoBAUXU4%Z7Q}|+ zpT5A+uCq5+N2u_B&S5IZCVHC?ePq+E$Zku~Qw;EIwHRqQ&MxFymG=%(4;;qS^$N1k z-xfMH%5u(wYp8uHcL<59at2O=%bde08@tapi8rRDHslj9o)>=g2FRw)PMML01_8xS zkF!09?j`j<6N(nrZuBiSC60LJJm@VwsPqcw%gHNS=FW5quRfrFqb-V`Zh!3~GE{u@ zkxL#>Nq&d8oooUD3p;7_U}ACM1tzANrJ>KB)O8(n?}mE0Dh@@h6rGOU3!c*KjoegC zVEg~t`|^J%-|v6>QkJnKdxWSoMPoO~*c!4gA)}OSWM{}8F=P)>GS)0JYO=3InncKC zYplsqQzoObmhioAuh;wgcz^zb&*SsRPuw%E`&!O*&huR7JkMo1qRBb{iNYvUDiD3Y zY9u>cI#4d(s*P&{x-;gLfOWSP3E{E$!lO1Ti;Rbq*-VJLDPS`Bd}y-dApKz6imw0* zq6_U15%lno|q9I@rYh3XGoyFv}m+wOWpt-Tr{*mgePH8XO8sTyx#z zK|qn6bO0AULWherYunW88Oq;Z4SPG$6f4zm5}8#ml-D7P&eu#Qm0n-GW)WI=J5+r- zQT`Ag!pt>^KI+>~EtI`Oq5_ZUg3L{LYMu&9G4Y1GgE-yg^bBiVNJcloBJG}`GGd#!ln!pziYK7 zrr|jzCuD-Hu`=CV`1LP>GLnn*J?hF6yHgL#+*VX>BM}FMQY|In0-h9~HubTSaV(hSe(WsCT`sp^DPNcMetO5lOmDDLoW(De^0rL%ObTwnIk zCqX%bNq08X-fzT1bRk^g)^H&jZkajbEN^v5noVJlg5|oPh20yNsq5hxtC=k}bpCsc zsml4m0~o3tc+f8Wikrpe?vRKMu_bFZQ)u7CwYO(Up^&{#E z$6TAQLvGzwEzymJQ0#b?F^ZmgiSLC}e2tHm=}4X8KC99*4{Dg*WMB!ak+jRN2s!vC zW!t<9W{RTl(eQ8-1O1P;Q{!4NiV{$OocG**v-)S@$lg|&QO3D-y!olTexnS@DBw|N z+EF`R?xjJ_`)xH}z6m>9Mb}S6{>(0lq_<6S?C+o(mWSD>BI3I3iO z7?XDIhy{o#z8JcBR~RdOy1|e!#9=|A7zQJBt%$x|)gHrIdy|6GBt+LnIbT{vn3oJm z3aqe=)=#tJHR{%OFmu}-3+l_u*?Bp8f2cZp182z%djTLO1}wq3Cq9c(_G;1m3h;+q zd4;)dm?g9CTR*N7$cY0Ff~gy5-iJ57wX))auX$7u2=nS2Q87scj!!8aD?I_vZdkDx z|L)M~8%rLtScqz$@ydUXFW@QN6P#Qzw6$F_Rpin`QOp}$_~+GCxyn`_SKccu0=jVJ z=3D|Qboa3H&DfVIGZLDuTXBR2<4VvE|@d+A~K+$UVEy8_OAA%>Bv%ikO!-LZ(pY?9H1tElKVX`sn zmtxj8ru;TnZV$%h)g}%k1}tc4#lEZc*hMj16I?8>0?+lVPi!<{ZE z67A1h~<@D_yAy15%P47hf_kh{%Jv037s{l@&U@SgTeYUSiwJ-AN3* z-vW#}DdAvU}9`j?Ni5n@I|<2%bozlxtbymR??ZSMrT} zjb$ZjC4%h3sll`~_~3lv_T6WHe)dOfhRr1$_Fd;Q5xrQd#pv|>5;aU-zZ^`c(FmHs zqbI=-0`J7K%#mNct*4|Dfx#T11G6`(I*=lZ9EQ!bPXWH~^S!N%y{&(u0{=76aQ=-% z@MwISbzJzurG^b;(xQbagr&__a`XN2m-X-p1Qpy$WE_uI0(57xt@P%6FvY9(uLf2(h&{~>Fy z4tVHnPvCu?xuv(5)Ta+m7n62wCYRm>0Fq{P#5ur8zw&!Hk9hK3vUr#Hdo8&_>J!Qh z3Z`dC(yX^tca^Nz|Jk3Fd-2HLk0YSCG_MZsO$U*q<^_swE~KeJ{SHmAQnWlc%BerT zwC&|#++9ce$eb9(t;UPcTCqf$fhCJ>jT4kYQ_)Ft#V&@WyKbD}s%-jn!8vMu?9!E} zMn#if5*fb4R^1tm%PmV9Jh^TLmaYy$MQgmV6H8{Cns=s}q9VGd-ZToZ#M0UTFE<=h z`3h$GSj!@G5KwL!U?@-!#~c5PX7*9t%u*0cc8!RTn|`Chq+*flW^1cfHpWG|>Tm~q zLy!X8Xo0PxEBm=q3Y`Vyn!5;NeWt*?JD#wXQH%r&qo(Tzd(JcD)fW1hlT}(&-g2tv z_o3)jr#yO2yvuzz5#x~lVpjyzu#npS$%@0$cFbGLRnjy|*7}f$oKKb3Q>F@$G`5v< z&2R55nOzk&%ymQO6YWmIdOOP9&sowzX?7r5uCKKpes^F+7gmsy=a`kw4hRbj38xg>CC*y{LU|Wivw!V6y zOeo4+jQL0oQ%=DhS)@=3V8ab8rz0Veh181+55<=TY2cT!!O`-UdQN>cy8|Zcbq5qw z;C-gJ804-q4n3$qi}yI>!dc8=<r9JRc#I?Fbq{W zn<);A733=ikX&%M=|6S!ffD*NLohpc4fR2|`H7ZXuG=AlIrTxW#`yyZ8ceb^{r3jh z%e7R9;bwqQ-Y07Yx6JbM>W3O@ldB2F2P~p9jz-{Vn#inAfg%QcOi4%bzp&&KTI3>sVmx#Vo+5z%L&au%M_U2OmRT1KCHMr0>$MPkCc!QlaJ$mQmb(c7b~O*+x!R zmYYV_Ll_C?Eie_+Nl~bJEZOBPFMIHdw$9GOh{qI~V*gDHtVS{A#GjY10tU!)wn5D^ zzLiaLh6?>zd^!{}6y@8Q3BZD(^DEGfx#bJ$se$db!!W?&np)d@3=~hKbVK7IZN$}` zR^ewRvkWw?7d18V;R@C4d_k z4Bkj$s1WE!|Dq{3m1OvZLv=o4&FLfT+8pP&D-)^fLd;@$HfeF@Bn>cs zfcg5&_f{iUO(C(RHs8p1wY+w_e8J@%$wyN#sOm8x3~EJ5%G8>4M)R~hiXzd2%!id3f!nwn>69)DWy&vJexyhY;`ib2>G_MYz489l{hE2+BUCu#I3k zl9QMk-MqqXUR2on$OnTWIj&DAwZS94#>Dj1J*G{K(Kgx9DI%^DOJNlb`a=56G3NDj5hGc!|ps#CzpOTQ;~#_I8F~rW||*d>`zO zYicd1k7dt~_=oT3@E@r&zuv5#K6c91w&YrUo4KW6uA2(h%kQf$cpeq<+|l-s4(H;v z3ygr8es2;vo3YSBAmB~guf4m>q0Et@*0HkbwC<`nuMSNvt*wn3`QWXZq;vQ3U~uy+ z;Pi28rIemAwVoN?9r$PkPlPW$!kLp}S9m*&@$D*w1nw0@JB#(KVZjYWY^RQkFri%pJ5;~)rgBak7 zg!b3HJo8FMNE(2q_`K(lY-&9E-d~QZ$++`phLxV z?rU65<_J2)vP6o)G>7l$5!U$;R#<6lea{U=!JyOznKCYa)hn7i4)`eP0pjw>rR(8O ze7zMv;=cOMa(+WsQr4)`p4nd3=eYfZL2jAVs6f}rB}$7daV2$Z=a?1JvpGPRXe`a~pW@&pecG`yBllYS7sJXpEnC zPM)@V*O<|ru<~Hd_K&?GU^>p@TWq>l^DDxSoEw?x5QuCmRY0W4Lk#X#M2f1Ij$lyS zLHfA(4gJcgv+;8)WZmy*b@uVMo-i!SjnjE1+A2Q;4u21SZufMqjaa6TMbUYWfXGhX zH;Ya&V7b4b-mbk{g|xJ_rPlk@+P@0;bG7VCFEe8ve{^0J-^p}69?J>2m`~L|5!rdR zd(w;Hx>{9(F}{V=D&(EGoR;S56hUgs)aI>Z_xlGsVQhGseRW5@epMXZ0OlIexI9jjc2EqBQh7(9@j0TIPB$>*M1Xu`6cKFT3rKB{7T^(sR1B2 zBCXWzM3Yb1%XwKlK18qW?Rc7W7r(!MHFRa9(pUagbE~~aZ|g+;!E@a5i8HB&*DvG` z#S3Hkur6Be)2rIfXpjb-^l)jG-A8g&yU2s}Z6aF{Hk)J%EHm9-9{5yjO?`R{np3qw zzNn0V8I$=Qw32WTMDG`_&=vs%g9LrQB+eoNWM)8EtRJ2S{wS42DzBc8L40NdtYZz& zDd~7^m}396ZaV}Ih(#nXEL{UxtFyDSn=4ID(5c3j!ztYbm)QgmAj5-ypJVMZwK00k zi3vOiq?uPC`dd&@X=Jp7bi9*b14sVk0R)kA!~X~XQy5Q-ANv37fiSoWfw?#8(0;O_JD2NJN<_3VXj-rDSZ^BjacpI(|eA;>cwE|RV0d1fxf0D%@Ur{SRKzH zJq+tszh70Eg#IsT^twzNuK+koHn2DbR(;yi#h!x6kuuae{fhu$x|@T{Dt_~L0q~&# zu<^B0vM!^bzsUzf1n>sd@ql!xLe|3h;HK-a5f}z_c;SA92#an^b%QoJLg?11{?edi zNZ?tJKilQ~=E7D-%qz?E1;E?%9Rf`MvkhN|T<+OQ!ioMm)rVk|lG-)d%jrL977cZoCtp8K6@D5V-$Hq@(t>6SzR#P2x(T8b~~53Y)*q+nedvOA{q zes#>+-}p8wkIZVKiQ{$B_=7=BsPb$B(6kRbF(IAzq!_MJs)dVESmHCMUaV?w)XFSM zfqV^J$T!=fu)?yR&jdXXNg=DVO~HElpT9@-fpqR=5hHT*oEq?Z)U4k_%0x{|k1ALt z36eG(q`#rspwO?(5eKLiqGHI#d9Tyr2xXpGBML@+gjX{`wT&1`yta`?6-0b9{*|L) zE-z}hUt%ksXLD%$-j7qrkroe- zt#ZqWw46eaiBF0L1Z`u(pMrT_G9KcVLIJToi<3hxk>>Tp7rC>2voJ9W=_AAIrS>gM zlAw!UJt`ATkp>#QI8?M}#vv_>%-Us7h8*Q!qF^FAs6`piKl2Uq(f}zp$D3GC8fk4< zmlrWOYU|22BqZ1Ejrve~d;4<8Ls`zgn58zlx|tr4d!mv^Q%FA3ve6(_rFnOsFeS#9 z>_}-`P!CkQpH|)nMwU|-gf}Jn>n86OSIyhl+IqaAf>hBK9h)2oLK3hC)UXe$!5y8Q zPidmf^niH?G`rj3MoW{4l^F-2 z13up5Rqf=`=XW{dAwM&}QbH7#zisb!hX-AKt=R9sXLOK1giYFr1S=bQk@xa>JF11N z=Y#iJtT0wd`~1je)Kt^dilLyvvaJ=cke6O%%1cPYL9*j83^y6y3b;2O%jV?OFJAKT zPREsB^F5z;Jp*^_08fHLv={|z%{Qzeqod=}9C4_pO+GK`+2pK0rY>=H*aUI9qIA#% zTHEsPzTv?!FS#rKRMpe0G|AFWpT2NbSUF-pt!D5XlIvuvc=n1{ygh)6^R<)*vCqDlNxe@y(j@e&_hN84S51KClO(BC#`$S2$-Uk(vAY@&{j>QMcNoP+-dtBwH#1r;Xb#-~P$BDbzLH>s z{>&Lb7xDG{7(E8OQsc0dXkR-VmQ4+_GDf(+G3?nA5al`F+IPxoaNhj*LbwnX0(}~y zEvW$KCRGs*Tz*e$tU#wP1W&e3co%2Y>bU2elt}w3TKR0kTdJo#A;QCGW0`pA%`%v? z4QK!kX|)V$nDV$%@=?&5=d!{x1EKIikedATb&H5lfIhb$ij z=^*(>V76z!Z)aBY{8Lk}R3~WR!T4DKxJDIzs_s}ht4YJ|=NxYX7UHc8#sfvc;WBGk zO99VfeaIrW{6w!s^dqIXwf>Ajs8Zt5sI*J9$*pQ-94ePZdtTN;X{BpqBFIinV!x+S zLOSEBJi@K_6{NXy87v{bJd#DyKOkjBIDV<6bk76GwAG1lT;0NbxlZ0At8j-DVt4Js zK|APF&o!uR_{Ko`?y#lcsl5K}?d_0K{#GS>Cp0Wh>T0(!f+Ni0W+7#wggZ`|gGv39 zL{F@FEAhru(`nz&(dpTRWmogvZEfxOUz`6qirZRz4cJodjYQe_%tU7GUZ2pjk?#O= z|2PYsZ(!MbY3vKK*Los|7*w>NUaD@n00};0B`~aoe(KAl$jOVpp4K4`mP$I#>|)t& z%*`v;%pyTA>v|ywcEUdQ9<}wvvv*-P8y(T+tPYp&6B1=4jGla&AaZF!FqyZ--{ah6 zk^BZj&YUT}GU$9lMBf@-`Xt`XfnZ>zQZ8T|bH_RmbX{L-M=1cxXfS?d`(1wBK)cTr zg5y!*!wNhtJWJNTTM)sbTP$>)0%oO2$NNnAD;WXK)=)`@-`D9xJCiIH2P!)*2`nk3 zIMK&v=Om+l9bg)RyaCvR*~Zj8%kY-4J={F zL^aubYS?&Pe`*NIyiv4jqv5AQA&Chwx*~|(>=q3s~CU6M`1pGw~n`l{8z1%{}k5CDa<>D#Ap{p5_nvuj<#$Js+k~63CCuBmfN%e8P{7Y0o_7B9Yf4K7G)f>lL())-$R`&! z=4SFu#$@~29?W#8Mpr@_$?tIcl7x_47+5Q>eKzlukwU*!{*Xwd2urN@;k(qaM&yu3jeOU}{)gfM-~8HR>1F99Htl|g+&OaxPXOJvW)Nvu zmye->@_O~`V6x?UAGl2QeDP^yr-t`n@Og0iFIcu4nR}RT+WqCycXv24^mmvP6dqZaUa=7 z7XroEFDIA21CJ8^aH7haLOeNC*2*&-g_y$&Yux=)qf>&O7|X`{rRCO@8mPif_g4APovzhqv5a@Y z6QYukLkCH~OR?l|!N}P>l$yV@vhF!hUAg_t{C2grI`Qd&@D*cAA}w4P+eRdr>bQoi zku0v;x898p!dF`s4Ef-80yzyS7t`nkK?fvegV$&(4)_jrJgDfa5R zKd3UzU+4R!!-a8S~+pei5gu}FzwWRc){nM)gbczdTcFm@_;jkk6QR}40*~Irb z3G+TvLJ09uJii^@ZTT+dTqMivW&(sryVhl!UJU(0H;zE?S%)2{63b9ZyvUu9EW&4c z(xcPAm+@b*UoxW{5c)oFDjqV-~0X^g}Dp5=T)X+HN zi5jK!_qJQ8Yr0;uImKjUNj~2{}TE*ze4-D4(6L)YQ9)b?b zpBU3u6<-aLN~jFL57NL)pNO~`cjxcD7k}@)_#z?i3>f!?Ty+Obn3PLIwu? p$MOsed^Apm^RNCs`uphbqrZ>-uRglV-B{0hSmGeB?0-A8{|^@<@ag~n literal 0 Hc-jL100001 diff --git a/doc/lua-api/conf.py b/doc/lua-api/conf.py new file mode 100644 index 0000000000..fd7e0ee88b --- /dev/null +++ b/doc/lua-api/conf.py @@ -0,0 +1,242 @@ +# -*- coding: utf-8 -*- +# +# haproxy-lua documentation build configuration file, created by +# sphinx-quickstart on Tue Mar 10 11:15:09 2015. +# +# This file is execfile()d with the current directory set to its containing dir. +# +# Note that not all possible configuration values are present in this +# autogenerated file. +# +# All configuration values have a default; values that are commented out +# serve to show the default. + +import sys, os + +# If extensions (or modules to document with autodoc) are in another directory, +# add these directories to sys.path here. If the directory is relative to the +# documentation root, use os.path.abspath to make it absolute, like shown here. +#sys.path.insert(0, os.path.abspath('.')) + +# -- General configuration ----------------------------------------------------- + +# If your documentation needs a minimal Sphinx version, state it here. +#needs_sphinx = '1.0' + +# Add any Sphinx extension module names here, as strings. They can be extensions +# coming with Sphinx (named 'sphinx.ext.*') or your custom ones. +extensions = [] + +# Add any paths that contain templates here, relative to this directory. +templates_path = ['_templates'] + +# The suffix of source filenames. +source_suffix = '.rst' + +# The encoding of source files. +#source_encoding = 'utf-8-sig' + +# The master toctree document. +master_doc = 'index' + +# General information about the project. +project = u'haproxy-lua' +copyright = u'2015, Thierry FOURNIER' + +# The version info for the project you're documenting, acts as replacement for +# |version| and |release|, also used in various other places throughout the +# built documents. +# +# The short X.Y version. +version = '1.0' +# The full version, including alpha/beta/rc tags. +release = '1.0' + +# The language for content autogenerated by Sphinx. Refer to documentation +# for a list of supported languages. +#language = None + +# There are two options for replacing |today|: either, you set today to some +# non-false value, then it is used: +#today = '' +# Else, today_fmt is used as the format for a strftime call. +#today_fmt = '%B %d, %Y' + +# List of patterns, relative to source directory, that match files and +# directories to ignore when looking for source files. +exclude_patterns = ['_build'] + +# The reST default role (used for this markup: `text`) to use for all documents. +#default_role = None + +# If true, '()' will be appended to :func: etc. cross-reference text. +#add_function_parentheses = True + +# If true, the current module name will be prepended to all description +# unit titles (such as .. function::). +#add_module_names = True + +# If true, sectionauthor and moduleauthor directives will be shown in the +# output. They are ignored by default. +#show_authors = False + +# The name of the Pygments (syntax highlighting) style to use. +pygments_style = 'sphinx' + +# A list of ignored prefixes for module index sorting. +#modindex_common_prefix = [] + + +# -- Options for HTML output --------------------------------------------------- + +# The theme to use for HTML and HTML Help pages. See the documentation for +# a list of builtin themes. +html_theme = 'default' + +# Theme options are theme-specific and customize the look and feel of a theme +# further. For a list of options available for each theme, see the +# documentation. +#html_theme_options = {} + +# Add any paths that contain custom themes here, relative to this directory. +#html_theme_path = [] + +# The name for this set of Sphinx documents. If None, it defaults to +# " v documentation". +#html_title = None + +# A shorter title for the navigation bar. Default is the same as html_title. +#html_short_title = None + +# The name of an image file (relative to this directory) to place at the top +# of the sidebar. +#html_logo = None + +# The name of an image file (within the static path) to use as favicon of the +# docs. This file should be a Windows icon file (.ico) being 16x16 or 32x32 +# pixels large. +#html_favicon = None + +# Add any paths that contain custom static files (such as style sheets) here, +# relative to this directory. They are copied after the builtin static files, +# so a file named "default.css" will overwrite the builtin "default.css". +html_static_path = ['_static'] + +# If not '', a 'Last updated on:' timestamp is inserted at every page bottom, +# using the given strftime format. +#html_last_updated_fmt = '%b %d, %Y' + +# If true, SmartyPants will be used to convert quotes and dashes to +# typographically correct entities. +#html_use_smartypants = True + +# Custom sidebar templates, maps document names to template names. +#html_sidebars = {} + +# Additional templates that should be rendered to pages, maps page names to +# template names. +#html_additional_pages = {} + +# If false, no module index is generated. +#html_domain_indices = True + +# If false, no index is generated. +#html_use_index = True + +# If true, the index is split into individual pages for each letter. +#html_split_index = False + +# If true, links to the reST sources are added to the pages. +#html_show_sourcelink = True + +# If true, "Created using Sphinx" is shown in the HTML footer. Default is True. +#html_show_sphinx = True + +# If true, "(C) Copyright ..." is shown in the HTML footer. Default is True. +#html_show_copyright = True + +# If true, an OpenSearch description file will be output, and all pages will +# contain a tag referring to it. The value of this option must be the +# base URL from which the finished HTML is served. +#html_use_opensearch = '' + +# This is the file name suffix for HTML files (e.g. ".xhtml"). +#html_file_suffix = None + +# Output file base name for HTML help builder. +htmlhelp_basename = 'haproxy-luadoc' + + +# -- Options for LaTeX output -------------------------------------------------- + +latex_elements = { +# The paper size ('letterpaper' or 'a4paper'). +#'papersize': 'letterpaper', + +# The font size ('10pt', '11pt' or '12pt'). +#'pointsize': '10pt', + +# Additional stuff for the LaTeX preamble. +#'preamble': '', +} + +# Grouping the document tree into LaTeX files. List of tuples +# (source start file, target name, title, author, documentclass [howto/manual]). +latex_documents = [ + ('index', 'haproxy-lua.tex', u'haproxy-lua Documentation', + u'Thierry FOURNIER', 'manual'), +] + +# The name of an image file (relative to this directory) to place at the top of +# the title page. +#latex_logo = None + +# For "manual" documents, if this is true, then toplevel headings are parts, +# not chapters. +#latex_use_parts = False + +# If true, show page references after internal links. +#latex_show_pagerefs = False + +# If true, show URL addresses after external links. +#latex_show_urls = False + +# Documents to append as an appendix to all manuals. +#latex_appendices = [] + +# If false, no module index is generated. +#latex_domain_indices = True + + +# -- Options for manual page output -------------------------------------------- + +# One entry per manual page. List of tuples +# (source start file, name, description, authors, manual section). +man_pages = [ + ('index', 'haproxy-lua', u'haproxy-lua Documentation', + [u'Thierry FOURNIER'], 1) +] + +# If true, show URL addresses after external links. +#man_show_urls = False + + +# -- Options for Texinfo output ------------------------------------------------ + +# Grouping the document tree into Texinfo files. List of tuples +# (source start file, target name, title, author, +# dir menu entry, description, category) +texinfo_documents = [ + ('index', 'haproxy-lua', u'haproxy-lua Documentation', + u'Thierry FOURNIER', 'haproxy-lua', 'One line description of project.', + 'Miscellaneous'), +] + +# Documents to append as an appendix to all manuals. +#texinfo_appendices = [] + +# If false, no module index is generated. +#texinfo_domain_indices = True + +# How to display URL addresses: 'footnote', 'no', or 'inline'. +#texinfo_show_urls = 'footnote' diff --git a/doc/lua-api/index.rst b/doc/lua-api/index.rst new file mode 100644 index 0000000000..3c76e50bbe --- /dev/null +++ b/doc/lua-api/index.rst @@ -0,0 +1,759 @@ +.. toctree:: + :maxdepth: 2 + + +How Lua runs in HAProxy +======================= + +HAProxy Lua running contexts +---------------------------- + +The Lua code executed in HAProxy can be processed in 2 main modes. The first one +is the **initialisation mode**, and the second is the **runtime mode**. + +* In the **initialisation mode**, we can perform DNS solves, but we cannot + perform socket I/O. In this initialisation mode, HAProxy still blocked during + the execution of the Lua program. + +* In the **runtime mode**, we cannot perform DNS solves, but we can use sockets. + The execution of the Lua code is multiplexed with the requests processing, so + the Lua code seems to be run in blocking, but it is not the case. + +The Lua code is loaded in one or more files. These files contains main code and +functions. Lua have 6 execution context. + +1. The Lua file **body context**. It is executed during the load of the Lua file + in the HAProxy `[global]` section with the directive `lua-load`. It is + executed in initialisation mode. This section is use for configuring Lua + bindings in HAProxy. + +2. The Lua **init context**. It is an Lua function executed just after the + HAProxy configuration parsing. The execution is in initialisation mode. In + this context the HAProxy environment are already initialized. It is useful to + check configuration, or initializing socket connections or tasks. These + functions are declared in the body context with the Lua function + `core.register_init()`. The prototype of the function is a simple function + without return value and without parameters, like this: `function fcn()`. + +3. The Lua **task context**. It is an Lua function executed after the start + of the HAProxy scheduler, and just after the declaration of the task with the + Lua function `core.register_task()`. This context can be concurrent with the + traffic processing. It is executed in runtime mode. The prototype of the + function is a simple function without return value and without parameters, + like this: `function fcn()`. + +4. The **action context**. It is an Lua function conditionally executed. These + actions are declared by the HAProxy directives "`tcp-request content lua + `", "`tcp-response content lua `", "`http-request lua + `" and "`http-response lua `". The prototype of the + Lua called function is a function with doesn't returns anything and that take + an object of class TXN as entry. `function fcn(txn)` + +5. The **sample-fetch context**. This function takes a TXN object as entry + argument and returns a string. These types of function cannot execute any + blocking function. They are useful to aggregate some of original HAProxy + sample-fetches and return the result. The prototype of the function is + `function string fcn(txn)`. These functions can be registered with the Lua + function `core.register_fetches()`. Each declared sample-fetch is prefixed by + the string "lua.". + + **NOTE**: It is possible that this function cannot found the required data + in the original HAProxy sample-fetches, in this case, it cannot return the + result. This case is not yet supported + +6. The **converter context**. It is an Lua function that takes a string as input + and returns another string as output. These types of function are stateless, + it cannot access to any context. They don't execute any blocking function. + The call prototype is `function string fcn(string)`. This function can be + registered with the Lua function `core.register_converters()`. Each declared + converter is prefixed by the string "lua.". + +HAProxy Lua Hello world +----------------------- + +HAProxy configuration file (`hello_world.conf`): + +:: + + global + lua-load hello_world.lua + + listen proxy + bind 127.0.0.1:10001 + tcp-request content lua hello_world + +HAProxy Lua file (`hello_world.lua`): + +.. code-block:: lua + + function hello_world(txn) + local res = txn:res_channel() + res:send("hello world\n") + end + +How to start HAProxy for testing this configuration: + +:: + + ./haproxy -f hello_world.conf + +On other terminal, you can test with telnet: + +:: + + #:~ telnet 127.0.0.1 10001 + hello world + +Core class +========== + +.. js:class:: core + + The "core" class contains all the HAProxy core functions. These function are + useful for the controlling the execution flow, registering hooks, manipulating + global maps or ACL, ... + + "core" class is basically provided with HAProxy. No `require` line is + required to uses these function. + + The "core" class is static, t is not possible to create a new object of this + type. + +.. js:function:: core.add_acl(filename, key) + + **context**: init, task, action, sample-fetch, converter + + Add the ACL *key* in the ACLs list referenced by the file *filename*. + + :param string filename: the filename that reference the ACL entries. + :param string key: the key which will be added. + +.. js:function:: core.del_acl(filename, key) + + **context**: init, task, action, sample-fetch, converter + + Delete the ACL entry referenced by the key *key* in the list of ACLs + referenced by *filename*. + + :param string filename: the filename that reference the ACL entries. + :param string key: the key which will be deleted. + +.. js:function:: core.del_map(filename, key) + + **context**: init, task, action, sample-fetch, converter + + Delete the map entry indexed with the specified key in the list of maps + referenced by his filename. + + :param string filename: the filename that reference the map entries. + :param string key: the key which will be deleted. + +.. js:function:: core.msleep(milliseconds) + + **context**: body, init, task, action + + The `core.msleep()` stops the Lua execution between specified milliseconds. + + :param integer milliseconds: the required milliseconds. + +.. js:function:: core.register_converters(name, func) + + **context**: body + + Register an Lua function executed as converter. All the registered converters + can be used in HAProxy with the prefix "lua.". An converter get a string as + input and return a string as output. The registered function can take up to 9 + values as parameter. All the value are strings. + + :param string name: is the name of the converter. + :param function func: is the Lua function called to work as converter. + + The prototype of the Lua function used as argument is: + +.. code-block:: lua + + function(str, [p1 [, p2 [, ... [, p5]]]]) +.. + + * **str** (*string*): this is the input value automatically converted in + string. + * **p1** .. **p5** (*string*): this is a list of string arguments declared in + the haroxy configuration file. The number of arguments doesn't exceed 5. + The order and the nature of these is conventionally choose by the + developper. + +.. js:function:: core.register_fetches(name, func) + + **context**: body + + Register an Lua function executed as sample fetch. All the registered sample + fetchs can be used in HAProxy with the prefix "lua.". A Lua sample fetch + return a string as output. The registered function can take up to 9 values as + parameter. All the value are strings. + + :param string name: is the name of the converter. + :param function func: is the Lua function called to work as sample fetch. + + The prototype of the Lua function used as argument is: + +.. code-block:: lua + + string function(txn, [p1 [, p2 [, ... [, p5]]]]) +.. + + * **txn** (*class txn*): this is the txn object associated with the current + request. + * **p1** .. **p5** (*string*): this is a list of string arguments declared in + the haroxy configuration file. The number of arguments doesn't exceed 5. + The order and the nature of these is conventionally choose by the + developper. + * **Returns**: A string containing some data, ot nil if the value cannot be + returned now. + + lua example code: + +.. code-block:: lua + + core.register_fetches("hello", function(txn) + return "hello" + end) +.. + + HAProxy example configuration: + +:: + + frontend example + http-request redirect location /%[lua.hello] + +.. js:function:: core.register_init(func) + + **context**: body + + Register a function executed after the configuration parsing. This is useful + to check any parameters. + + :param fuction func: is the Lua function called to work as initializer. + + The prototype of the Lua function used as argument is: + +.. code-block:: lua + + function() +.. + + It takes no input, and no output is expected. + +.. js:function:: core.register_task(func) + + **context**: body, init, task, action, sample-fetch, converter + + Register and start independent task. The task is started when the HAProxy + main scheduler starts. For example this type of tasks can be executed to + perform complex health checks. + + :param fuction func: is the Lua function called to work as initializer. + + The prototype of the Lua function used as argument is: + +.. code-block:: lua + + function() +.. + + It takes no input, and no output is expected. + +.. js:function:: core.set_nice(nice) + + **context**: task, action, sample-fetch, converter + + Change the nice of the current task or current session. + + :param integer nice: the nice value, it must be between -1024 and 1024. + +.. js:function:: core.set_map(filename, key, value) + + **context**: init, task, action, sample-fetch, converter + + set the value *value* associated to the key *key* in the map referenced by + *filename*. + +.. js:function:: core.sleep(int seconds) + + **context**: body, init, task, action + + The `core.sleep()` functions stop the Lua execution between specified seconds. + + :param integer seconds: the required seconds. + +.. js:function:: core.tcp() + + **context**: init, task, action + + This function returns a new object of a *socket* class. + + :returns: A socket class object. + +.. js:function:: socket core.yield() + + **context**: task, action, sample-fetch, converter + + Give back the hand at the HAProxy scheduler. It is used when the LUA + processing consumes a lot of processing time. + +Fetches class +============= + +.. js:class:: Fetches + + This class contains a lot of internal HAProxy sample fetches. See the + HAProxy documentation for more information about her usage. + +Converters class +================ + +.. js:class:: Converters + + This class contains a lot of internal HAProxy sample converters. See the + HAProxy documentation for more information about her usage. + +Channel class +============= + +.. js:class:: Channel + + HAProxy uses two buffers for the processing of the requests. The first one is + used with the request data (from the client to the server) and the second is + used for the response data (from the server to the client). + + Each buffer contains two types of data. The first type is the incoming data + waiting for a processing. The second part is the outgoing data already + processed. Usually, the incoming data is processed, after it is tagged as + outgoing data, and finally it is sent. The following functions provides tools + for manipulating these data in a buffer. + + The following diagram shows where the channel class function are applied. + + **Warning**: It is not possible to read from the response in request action, + and it is not possible to read for the request channel in response action. + +.. image:: _static/channel.png + +.. js:function:: channel.dup(channel) + + This function returns a string that contain the entire buffer. The data is + not remove from the buffer and can be reprocessed later. + + If the buffer cant receive more data, a 'nil' value is returned. + + :param class_channel channel: The manipulated channel. + :returns: a string containig all the avalaible data or nil. + +.. js:function:: channel.get(channel) + + This function returns a string that contain the entire buffer. The data is + consumed from the buffer. + + If the buffer cant receive more data, a 'nil' value is returned. + + :param class_channel channel: The manipulated channel. + :returns: a string containig all the avalaible data or nil. + +.. js:function:: channel.get_line(channel) + + This function returns a string that contain the first line of the buffer. The + data is consumed. If the data returned doesn't contains a final '\n' its + assumed than its the last available data in the buffer. + + If the buffer cant receive more data, a 'nil' value is returned. + + :param class_channel channel: The manipulated channel. + :returns: a string containig the avalaiable line or nil. + +.. js:function:: channel.set(channel, string) + + This function replace the content of the buffer by the string. The function + returns the copied length, otherwise, it returns -1. + + The data set with this function are not send. They wait for the end of + HAProxy processing, so the buffer can be full. + + :param class_channel channel: The manipulated channel. + :param string string: The data which will sent. + :returns: an integer containing the amount of butes copyed or -1. + +.. js:function:: channel.append(channel, string) + + This function append the string argument to the content of the buffer. The + function returns the copied length, otherwise, it returns -1. + + The data set with this function are not send. They wait for the end of + HAProxy processing, so the buffer can be full. + + :param class_channel channel: The manipulated channel. + :param string string: The data which will sent. + :returns: an integer containing the amount of butes copyed or -1. + +.. js:function:: int channel.send(channel, string) + + This function required immediate send of the data. Unless if the connection + is close, the buffer is regularly flushed and all the string can be sent. + + :param class_channel channel: The manipulated channel. + :param string string: The data which will sent. + :returns: an integer containing the amount of butes copyed or -1. + +.. js:function:: int channel.get_in_length(channel) + + This function returns the length of the input part of the buffer. + + :param class_channel channel: The manipulated channel. + :returns: an integer containing the amount of avalaible bytes. + +.. js:function:: int channel.get_out_length(channel) + + This function returns the length of the output part of the buffer. + + :param class_channel channel: The manipulated channel. + :returns: an integer containing the amount of avalaible bytes. + +.. js:function:: channel.forward(channel, int) + + This function transfer bytes from the input part of the buffer to the output + part. + + :param class_channel channel: The manipulated channel. + :param integer int: The amount of data which will be forwarded. + +TXN class +========= + +.. js:class:: TXN + + The txn class contain all the functions relative to the http or tcp + transaction (Note than a tcp stream is the same than a tcp transaction, but + an HTTP transaction is not the same than a tcp stream). + + The usage of this class permits to retrieve data from the requests, alter it + and forward it. + + All the functions provided by this class are available in the context + **sample-fetches** and **actions**. + +.. js:attribute:: txn.c + + This attribute contains a Converters class object. + +.. js:attribute:: txn.sc + + This attribute contains a Converters class object. The functions of + this object returns always a string. + +.. js:attribute:: txn.f + + This attribute contains a Fetches class object. + +.. js:attribute:: txn.sf + + This attribute contains a Fetches class object. The functions of + this object returns always a string. + +.. js:attribute:: txn.req + + This attribute contains a channel class object for the request buffer. + +.. js:attribute:: txn.res + + This attribute contains a channel class object for the response buffer. + +.. js:function:: txn.get_priv(txn) + + Return Lua data stored in the current transaction (with the `txn.set_priv()`) + function. If no data are stored, it returns a nil value. + + :param class_txn txn: The class txn object containing the data. + :returns: the opaque data previsously stored, or nil if nothing is + avalaible. + +.. js:function:: txn.set_priv(txn, data) + + Store any data in the current HAProxy transaction. This action replace the + old stored data. + + :param class_txn txn: The class txn object containing the data. + :param opaque data: The data which is stored in the transaction. + +.. js:function:: txn.get_headers(txn) + + This function returns an array of headers. + + :param class_txn txn: The class txn object containing the data. + :returns: an array of headers. + +.. js:function:: txn.close(txn) + + This function close the transaction and the associated session. It can be + used when a critical error is detected. + + :param class_txn txn: The class txn object containing the data. + +.. js:function:: txn.http.redirect(txn, location) + + Not yet avalaible. + +.. js:function:: txn.http.req.add_header(txn, name, value) + + Not yet avalaible. + +.. js:function:: txn.http.req.set_method(txn, string) + + Not yet avalaible. + +.. js:function:: txn.http.req.set_path(txn, string) + + Not yet avalaible. + +.. js:function:: txn.http.req.set_query(txn, string) + + Not yet avalaible. + +.. js:function:: txn.http.req.set_uri(txn, string) + + Not yet avalaible. + +.. js:function:: txn.http.req.set_header(txn, name, value) + + Not yet avalaible. + +.. js:function:: txn.http.req.del_header(txn, name) + + Not yet avalaible. + +.. js:function:: txn.http.req.replace_header(txn, name, regex, string) + + Not yet avalaible. + +.. js:function:: txn.http.req.replace_value(txn, name, regex, string) + + Not yet avalaible. + +.. js:function:: txn.http.res.set_header(txn, name, value) + + Not yet avalaible. + +.. js:function:: txn.http.res.del_header(txn, name) + + Not yet avalaible. + +.. js:function:: txn.http.res.replace_header(txn, name, regex, string) + + Not yet avalaible. + +.. js:function:: txn.http.res.replace_value(txn, name, regex, string) + + Not yet avalaible. + +Socket class +============ + +.. js:class:: Socket + + This class must be compatible with the Lua Socket class. Only the 'client' + functions are available. See the Lua Socket documentation: + + `http://w3.impa.br/~diego/software/luasocket/tcp.html + `_ + +.. js:function:: socket.close(socket) + + Closes a TCP object. The internal socket used by the object is closed and the + local address to which the object was bound is made available to other + applications. No further operations (except for further calls to the close + method) are allowed on a closed socket. + + :param class_socket socket: Is the manipulated socket. + + Note: It is important to close all used sockets once they are not needed, + since, in many systems, each socket uses a file descriptor, which are limited + system resources. Garbage-collected objects are automatically closed before + destruction, though. + +.. js:function:: socket.connect(socket, address, port) + + Attempts to connect a socket object to a remote host. + + Address can be an IP address or a host name. Port must be an integer number + in the range [1..64K). + + In case of error, the method returns nil followed by a string describing the + error. In case of success, the method returns 1. + + :param class_socket socket: Is the manipulated socket. + :returns: 1 or nil. + + Note: The function socket.connect is available and is a shortcut for the + creation of client sockets. + + Note: Starting with LuaSocket 2.0, the settimeout method affects the behavior + of connect, causing it to return with an error in case of a timeout. If that + happens, you can still call socket.select with the socket in the sendt table. + The socket will be writable when the connection is established. + +.. js:function:: socket.connect_ssl(socket, address, port) + + Same behavior than the function socket:connect, but uses SSL. + + :param class_socket socket: Is the manipulated socket. + :returns: 1 or nil. + +.. js:function:: socket.getpeername(socket) + + Returns information about the remote side of a connected client object. + + Returns a string with the IP address of the peer, followed by the port number + that peer is using for the connection. In case of error, the method returns + nil. + + :param class_socket socket: Is the manipulated socket. + :returns: a string containing the server information. + +.. js:function:: socket.getsockname(socket) + + Returns the local address information associated to the object. + + The method returns a string with local IP address and a number with the port. + In case of error, the method returns nil. + + :param class_socket socket: Is the manipulated socket. + :returns: a string containing the client information. + +.. js:function:: socket.receive(socket, [pattern [, prefix]]) + + Reads data from a client object, according to the specified read pattern. + Patterns follow the Lua file I/O format, and the difference in performance + between all patterns is negligible. + + :param class_socket socket: Is the manipulated socket. + :param string|integer pattern: Describe what is required (see below). + :param string prefix: A string which will be prefix the returned data. + :returns: a string containing the required data or nil. + + Pattern can be any of the following: + + * **`*a`**: reads from the socket until the connection is closed. No + end-of-line translation is performed; + + * **`*l`**: reads a line of text from the socket. The line is terminated by a + LF character (ASCII 10), optionally preceded by a CR character + (ASCII 13). The CR and LF characters are not included in the + returned line. In fact, all CR characters are ignored by the + pattern. This is the default pattern. + + * **number**: causes the method to read a specified number of bytes from the + socket. Prefix is an optional string to be concatenated to the + beginning of any received data before return. + + If successful, the method returns the received pattern. In case of error, the + method returns nil followed by an error message which can be the string + 'closed' in case the connection was closed before the transmission was + completed or the string 'timeout' in case there was a timeout during the + operation. Also, after the error message, the function returns the partial + result of the transmission. + + Important note: This function was changed severely. It used to support + multiple patterns (but I have never seen this feature used) and now it + doesn't anymore. Partial results used to be returned in the same way as + successful results. This last feature violated the idea that all functions + should return nil on error. Thus it was changed too. + +.. js:function:: socket.send(socket, data [, start [, end ]]) + + Sends data through client object. + + :param class_socket socket: Is the manipulated socket. + :param string data: The data that will be sent. + :param integer start: The start position in the buffer of the data which will + be sent. + :param integer end: The end position in the buffer of the data which will + be sent. + :returns: see below. + + Data is the string to be sent. The optional arguments i and j work exactly + like the standard string.sub Lua function to allow the selection of a + substring to be sent. + + If successful, the method returns the index of the last byte within [start, + end] that has been sent. Notice that, if start is 1 or absent, this is + effectively the total number of bytes sent. In case of error, the method + returns nil, followed by an error message, followed by the index of the last + byte within [start, end] that has been sent. You might want to try again from + the byte following that. The error message can be 'closed' in case the + connection was closed before the transmission was completed or the string + 'timeout' in case there was a timeout during the operation. + + Note: Output is not buffered. For small strings, it is always better to + concatenate them in Lua (with the '..' operator) and send the result in one + call instead of calling the method several times. + +.. js:function:: socket.setoption(socket, option [, value]) + + Just implemented for compatibility, this cal does nothing. + +.. js:function:: socket.settimeout(socket, value [, mode]) + + Changes the timeout values for the object. All I/O operations are blocking. + That is, any call to the methods send, receive, and accept will block + indefinitely, until the operation completes. The settimeout method defines a + limit on the amount of time the I/O methods can block. When a timeout time + has elapsed, the affected methods give up and fail with an error code. + + The amount of time to wait is specified as the value parameter, in seconds. + + The timeout modes are bot implemented, the only settable timeout is the + inactivity time waiting for complete the internal buffer send or waiting for + receive data. + + :param class_socket socket: Is the manipulated socket. + :param integer value: The timeout value. + +External Lua libraries +====================== + +A lot of useful lua libraries can be found here: + +* `https://lua-toolbox.com/ `_ + +Redis acces: + +* `https://github.com/nrk/redis-lua `_ + +This is an example about the usage of the Redis library with HAProxy. Note that +each call of any function of this library can throw an error if the socket +connection fails. + +.. code-block:: lua + + -- load the redis library + local redis = require("redis"); + + function do_something(txn) + + -- create and connect new tcp socket + local tcp = core.tcp(); + tcp:settimeout(1); + tcp:connect("127.0.0.1", 6379); + + -- use the redis library with this new socket + local client = redis.connect({socket=tcp}); + client:ping(); + + end + +OpenSSL: + +* `http://mkottman.github.io/luacrypto/index.html + `_ + +* `https://github.com/brunoos/luasec/wiki + `_ + -- 2.47.3