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 000000000..b21857d25 --- /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 000000000..0838a37cd --- /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 zcmYJa1zeNg8#WGz0#ZYemQF=-l0&4sq+7Z{VjwLY(k;R$X#wd5VM>TNVc?{t958xx z{vW=-|NFjtK7(z~cFuXux#PO7`zBsTOPTaO{e2u998y&kg_k%ucS3P+a7hXAfOi&c zSnlHB5Q#d=%j?+LJ6J>Ae6744ZTOvSZESV@J#~@BZW{HWn8hwoeGalRH zZuF?um*A=I@~Klau-f3WCB%UhQ;Xi>mcHaLRA>NEQ8g5qa1inc(JJce9KfY0(F^-S zA)(UPpHk@j_jg`U+{JmJi2L&8-C!A-AT1RqT7q8I^qlt|=#>?s#kDIQ795-t!;n6# z1<$z9dkBv4y|=-Zl2$lxSMlCDB(qrHyk)$LW2pbK69-3v7>6$u7y!rn4vw*xRR|-F zv947J6OQpEjtl_~6~T*=Zy_tXi>G17csM+>`*(>NggO{+nvG?(IAmfnHqbT*FQ3Tqzrus#i;lwsw!{Bl-UtaL9XW^Y$u;T#VShcIZb@8%B9 z;^726ZaXo~pWd*hN|(1g7C0|cZpQRe@C5JUcJAyoo=#hdFyi1a@qEFdR*A%`e9N^S zL6IBI`6q(1JyHz+1&7LQ#QqTs9HJZ<8d>3X5ZYkf6ZgrSdpEdX-%&?ZHRJ zDp~qe>Q$OmM(?{F@g(disYG_vXAEaiHaw*E#Rrv=)hXV(Qj>Q`U!Y38obKhtQkMjc zKW?Uwj`u4z`Zc@G^H{;En3(pJeqs`@btf&2&zJ57K|bmgTeAk6PY+zb&NNuM;dI3k zHArl+C%?5_78ke3=luDQCT?X(__di=Sv&n4kvUBrvp>05_=lm8e&oLQn@8Pu7f6{S zQsC&n@Ak4z9fG;9=|ibxqQkUVK!5N_Bk20GKx!%+Zd{oU$S5TVbBN$kssngwDw$lH zpxU^FuPP;PjTJs|!8k10l0g-5%qsfnY$I{28u!`D((kKeeKed`beLj-!FL$j_EuVtfnOSqT0 z9z1Q-{Al=5-A-ZkS>z8L+do30f(Nu&i6V(oi4wYvm7SH5P9N6|$4$q5N^DDrZ8U`B zg*+Rm8eTRSHhi!VSyu3ZdU5YN?aS@kE*pL0eow0xz42vL$Y1zFE-F`#4^KUEZBWfF z>vO0BX~RFxubhdT5ggu}E}Z--gwwQU1>1vK4ml0lP0XKVRKKgws1B;^q`BoVrkQ7^ zXEkOeq&?2wOr_5{=NL=#OV>(Y5SV{@rGJmR^y$iz40a!de|bOh`P6^E%;q-Z3o<=! zV0>Kh6wTdcvXeVkG#Akw(fuyCGq~l_;7sCfYecPFiCpx6Vzh~3c}a^+giZ7^=eHb2 zqU1;1@AbZIpnp6W;q7>A&-;vrl=msGD-XeA8XkWh8H3`=*9JBQkM+;>{~0_q=+Va- z%<41Oq)oNE?7PHH-kYSJdNvt3#X*S<FzERC*; z{<7Ts%__SyTQ$2jTf`Oo`|BrXQxWGfw};MCuQ;3k87mtzw@}aUOe@TQXCQ3`4N0x; ztp%;fM)hVX=aZR*FEGzV=f3q-`1wNho<8Y-p)sLnp?9t|Zj!ERuXpck-T96O!*{voaQFDG zP{cr_X#{oTqsY<7Xx4L9GdYjg?@?S)$59mUh=Dvf^>2wk(4_&A(7DBMVx=`aZyPmKDYUff9F4#aMe@!X@5-on8|vU=3Zd&;fj@;2dz{YkS|;Az;NDrhNUCy6Y*aSz4{G*+pxW+mkubmU;V&_(z$K zRHZ_n2=edNbby^|s2$Fo~9y8MPPqvru%FfWYmR+O|a z&-W)0cpB0h{bnv<{4UAy>EP35m0|6IQI9#Lm58aU)vPYJQCo$_{_De~H1<~I8O$0+ zeN*ODH#^_{1sNPt_S}1 zjh?oP88xg%yC)aN~;BOUvIo33$Y4&c3pQA6#Gm6jrD++&0fb1mOG<+#3;<}x&dNv8gX6XZR*u& zKj`%D@)LGzJ_lo|)uR^H0ya9V_)`e2e`Zy9HF{j%f0lYyC3Y$HBrK;lD>Ue`V85&P zZeg_JuHJ&cQ|hqP>(|TdCo5kn{%RxDB}TulRU=FbgZkbC(^;vSn4A&tm!x*Tq_MgJ zfE3Yd6%!vE91^YD2X2^uB0KQrBVR>hUp-F;Uw>P^%qJGr>Fed(ek2S*s3r z%^rLv*tqXtia#yw6cN|L!r72nOVdUa5ev)zl@ZI7E+6z*O)e!Oy{+$M-~;Xh_t720 ztxGcPUeAROcEa!9|KJcQM6c{EVMjQ2Po7}kb07lxuIJs`%#uKIgsf4iSZrMtDNEGt z3-Y^a2$KvBRS>?k6d`K_%WDfGLNB2jj-WC2+v~c;hxyN(^OSTao8aCZi6xbFn9e$Z zSLB&>nH~S{Bi%L!kb2C_$razI2D1B0qFfwL!pB2j#-Wod;ved_GtT~<*JF55M~lFg zi-zCMi^4BM_j9PSMG?XUHIW>uj6-Sn`81JW&83T0zM2L$V-z%zN1`8+B>5~!;W`E5V9mtoTwSJj{a%s;V@yLrt;X4$v5ym$hr=GS0{iQ5 z57-423)-QEIl{5k09a;vstF8T6($GAjWg;{d~ABjYj2J~Me>d6Z%dg6(#Pl;JZ$}h za@9mK4sA61G)=$Yv<>@_Yj1*1OwwC$6HQ&280cwYh$+UL*BKE3Gk9+cj;*Ue5PB9P zx>R&A6hjTZMX}aSc@F6ur#bJOmV>d)={>SmiLxgjf}-3QIipn46*N_LKlXGI+0|C|V1Gj` zvdgS#%bmZ!FrIDA;INM81nhoQvspLgbw|WlZ@(<`FSV*zM~GcGV|6RXnNsa`Bbr2@&C6gpyB9|Ia?>+}md1M~^qk>o5=m#pgf#NgPqY(SSAi*jnK{ z(V#tlc7_c?hR;q3(C?*`F*D`W0-UOBn2^>g484axSXy%O-WiiiUaQ!b%>NAWZW;Hj zXAyRQ5|21;pRm$IOk~{tjWQ=xLyYUZvyJXTGwjMmg5`1aBqC0!SV-AD{oS`B}( zAwl1b2P|xhO;gXLmackVVWi!hzm%sMb1s~fGAml+s4)DRM_ReG=^Ym^O^I{fig=@7 z9LPqcCYkB~20?zkvv&8UK&2>>*d(xWq&?zx!~tw~l_u@`St)jJy7o;8df#?Rx#8N0 zWLE_}N$5k+MG-lppB7U8m>`=WgCp(fBE4-1QNH_ZtNY1m;~Js8i5i0>y8v*c^YK_n zj-fR*3OYN#QNj~}TQjBBJLBvVG{~X4I-I2SQ{DlA4Q??VnXX8%=5%!2%sXz2oN0|s zWf(lU8kgBN$*!93)8bBExyC)&`J7W-9lYqzSW#WAHz<*e+~y|0MR;f1pX#;x5yN$M zN->?*w6hfj3%|^agJyiRTEnm*%$CB3^Qp166uKzrblO+&*q8&-nMCQu#e?Qx%vN(n z3;n;d-V|Otc=By9v{Q$W)WBXm!!57pPLI{ecig9D`vIHY=&ySw_e~^<&;c)9mrK69b*E3tY>OCyME)W`ZzWnKPZ<4fy z&x|?T;e7gZPO8hAwzFfuF7sJrkfyv)2e-_{f1*8**K=?@>sM=FV zPYarKChotRxjoao25tIO+(y;#H#$|ja6vmRq^2BT*~*Z6e50Lz(t%{ZNuw6O zBF^_iDY>W)!$Oz}dOMjgNY?d$EYO>8@A2T4##^Uf8JWLS-u`i|6%~ieW7H04pTOlA z@>j zBqb(^dNF<|@4y%&3VwYf*E;)@iKto_o*uSBgvxmRD>P)>xmY>Srlj@i4{naZ&DNVgRpi0}1>W|n$3Qv(zcx9(V?<;4NCT;V z<&{@H1uZ}aP${}dok9>ua8?%)D~L6ZW5lIJSQF{Rhy)we7^JvzA+Rt9b(fD2);qFf zxS>Oj6=CQJPjQZ=B2Df4av#D~iR?|-__Q@)PEkWYSmE-v=|j){iYH$xSQ8IO@Aon6 zSbIi3Q905?LAN`1Tv{ZZ@&~y$S?=tGJ0}Wqu>TSyfeV5XSj4`Ixx`WS@u{2OJp3zL zb+mv#oONr8LF(VxWuJ`--=Z~dM#mn@9DCkqE*Q1TI(KVj^>`y6Vc*9y*$iH|}{LG%V!F^UPZV5{ADxJh$D;?iTC1!Tzq8Bs(wFoX*CEOHoLOl#8 z$Y^H9@X`7VPwG_WQZSoJNJ-sYV9JD*HW>8)Df7h>s4Z>GP)M1pE=d*0@1(gu|_^u#ld zZSRE^E?rQ1Pvw>aR&A2)oVUy!nx=)0+=JAM@T?6y;it5$Sm`Yk`vI7FR~go;$V1_m zdpgHv7$dVBe%+UbU+jz&Y*ikzrnJ|t#?_Nh3xhgq+Ex@FedMbuhPp6(-=jZs;+lWR z+oTSbCYxrZx&qI|We0=i9s?Vf#-VzH(z8HG88N4r9l4QnMy&^U5V88re|ze{kPCtwBK?2s|3hjUFD;cACB1x@0ELd7glQz3S&>-TullDIWZvI*B0j-bfK zPfX#ng*RF%3>K(T9=T^RV9hl0@C1>WzfqBT1MgzFIbYE!5n9iR2B&>Ce`xnViIau5nj}9QbF&eF1Vx}2t`0;wTs=Ft| z^ktAyh#OqcFDse-V^X>E_ExNt#ETZ4v~uUpx*8h7YMkn}qVToypz>efF~P*2=?C7y zM0Ent*kh-wZypSapefVhgJ3UbX5R=>sVNbcZs%>b( zk_d4r+s+=RPQdcYN4&YOvJ9ImLYt3k{QU`TRz7#nSW+u;j)!McmPBxBM>)30RPGJ< zb1^z;m(tpAd|!FNI|ulu9ASHt?)^5$<{n^6o$TH)2DUdhiHyiI?3Ew&p@SsWuQ*r; z@p_G-7y(}BlxZIzgqWn5pd?dl zx#8$npU_T!TBTcvfLHu#Ap8pbO3qc>+W^JatpSi@Qn+C5g4VF?ucgphM%_{84)YSp zo=&d@V=Bddv;S}=KaP>K^2z|&$x-`;T`1`;~LAc5kyYdw%a%>rb#|z)i$Ug)@J+ApNrs zd!$mgv0zQf0u|Kknauo`vN!1~jG_=m$)$4` zKWB*|u~%0bX#8~jD51n@t7+Pe1g;}yXkc&h+o5Sg=Jl}ePyBllva%qEY2suJb(3tUg)Na)-BKSROm&8UgoOB)ofCh-C& z!l-^y+M2G5PhKP6lAX8*e>@04_FEld&61i(3sP@i3x7s#)dxz$Kk%>F2_>iig5ZR2 z)yg~C*dxEP0pKZO*zqQ>pA?x=>Hx)pZV8EmJ>7>#FLFA0uGY)M& z2fcI7GckR2?mYWg5SJg70YD#yYzwuk980t@V_n|VEIGdy{v`9#7)@}VX& z&|Gd9T11@k1Ap-(h;b*|{#jjG36BPHYmV|vbvvh#FGEk?fK%o&sGy>&?iZ}1x*CXh z6pDAygLNjftUijrmb8Y81;?Dg$C7hW*gN#Z`Pud@IS}n3@E8p8v5^mI;poLF95w-V zuNSnw+l(F959!-xLxIN{`QFnnch>!&n0xq}P2`LOo+=S`2d$R=_2epMmX!opX-!&^-Qu0QUWF;oIH2WUacJT>k5BqEs=~Q1kNM=bdF*?$$ILUKwA zAP54^$sA*Ck}YhCV-TK3Xiuw@SDtk7fKIE6i-`3jv*aANgOS^NKHf#_7pBG(;Cz36 z`oohzZ}5t6gB9T;UXU}&xtd3%iaDa^bt zjUovLm~*KGw2Ya`F6|vZT0|qFC27#yIZyak#$jaOix}(EUe8(4O#2k&Qzyfkhin?) zZ^c{UTDC3E3Gqx~sQW5i6JBS!*6u>LN3qw}&q?G-V7Dr#i{of#odqiEJ4vWZoQlNC zmkvQHe11lHFUFM@-S0`^zu=#$tA9$tZ5rZMPCvcNqc_SLmAR zV>Od7RkorOyIl#7)IBJF<}2gtESSLc(4AYm$#k@SR&#E5EH z=AV*0|GUV|N=~N#T&~I})QYXN$+Y$W;;Bpwl8YN$R%4Hl6A>ekDxJfDS_n|T<4GWa z1JrG@V3qN!mpN5*x%24S1a!V?OhTZtO|a!*lsP4kf4!C%OJR*+1f({AnlbzCn~mp( zY_O(4SgZwq&i2gAyKl>JJI~1TIaCd6vg$CHqrg`ecjS`qQ4}ib{>6~~maP!o;U=(_4$w@RJ!tZ9?pLim`9h@0lx+mbHE zhiB#m%WIEyNG8CVxlf~B@NTtIR^N2f4|BzC=ln7#o2U7pasaWaH8jcA^-Vu}MSHJT zFvmWg>_F_ZrOGW-kc+)=B1w}~O>eJr&EqoVo^4GcgcvB4JG;!bZXuGh1BII@5=0O_ zXT(kf3dzy=fTE}6_#T8OFmnB*v#!k+e1WLZ3@ddRZS;8NyQT2GQ6b>lQQ(+?wXn7Z zGI0fv)Pv0{MA01Uuen!Wwc2q6FYYcD^8omG^67`MK|vCzt${(dy}Rg#>pN|;?m?rx zr@eisYgkC|BA_WglS;OQqL;eD2Z zFqbEU9bC5xSCHOMKpJSzEkjsDbRLqPkiK+RQgxPLwx+Fi5c@rwEM9+2olILuT$m2l zjARicx$`*8#fOkC3LS8IFSLhuPmYj!j%AgF76S~G5elSTsWpZNwEz;~n+^hGQQ*8%FmjL zM}$d;pIEv(9}sxnvkT_QaH#%}yYB zCAa)N$4E;v7a4qyeg&WKJt#YqIjM)tKNT(EVpj6m-U6jdRn_>=%#8 z3j|sEqCoa0lF2?gle!kD#vb9x&*l)bdK4iYV`B=Y(>O9y>0ba7zN`hRTJ;V>Jz`T` zW!j^!)0l5rJT%uoxI5N}o>qDI1qcSdK}h_cIKharBvkY5u@q|^mD`av5tl!H&p*nW#>`0GQUCzoIo7Bur+0#F!LL zb^_L1tN!Sm*So8yni{HO5q2%>8I_*`K`a^O&5~x2`2*(+1j~EnbQIp8%Batl^=EGE z`iI(mO5w0uqm%_{xZ`#3 zZgyJoQO}qcwnv#W4S4~t_;awl;)NWl+IMXLGz-{7yGzL1sEVpumR%NvPYfRA#226# z)%Xwjg0M%fyw!#~05;ni0?1;0v)&zUePuv|eEy(t?!kYd^991I&#}Te&|@P$S8=wL z=H0h7qqus^peYIp!cSfi49raxwWg(y5u#K^{wS-kH!;aR8j8Ft`zp`jf=}{;45hc^ zf8(@zt}OUH8j|n_1Dd4?5IX(N)|P6z8kBUw+L{`}8o!`De50(-5)q`G5DoWl`$a#j z9NnE4Pck^(Bk)8z=yDyv^hN~^zVI5?_6BOj@z9Zzt8X?!ZJXzEagp>T>5-{d&0x(Z zqm6pY%&RZgyZ5FXEXtjQU6vV(a_YC51Rvf(Ccb8uy9xkwq2`&-j2C}J;{xlF*;QgR^a`7y+Z9PF_vI> z9me#kI>cN+^GIke;Dj!;iQ!#?M{hc&vw=(Xfue3#I3*n+|NSc7*~fZyJ8cgmyYHp! z;Z){4xCVqWewzO37^W<1C;FA+(a4dT)#iPRf}4t-OkD9JleLOR{XuV z=D!H}FBR}6uk>&SeKo&>xY7yQdp&dX_%{vt=j;48FtHXQpO4kme51jOIi&iUNC5U@ zA&Vy~;y-WcW7QaA_$`+NDhserlfQa*W37SO~E?tzA!2x8*+nGvHj__-~ing?olGi&Gq;L9tfB9RQ6>S|y%Nq4&xhrE1 zm-)!=H>aXy#K4R97zrUt8Ip-y>eD#9d>=OADu_~=y#LLONkttSS{(15KwgOww!uRt# zsHe-cc3C_-tVC*Oe!d_RmTk|eTC(HANL$e`7@jgzClBz&1z>)j z-;u9=ZTr1b7zAtPjIIGPX074gq_+FNfd0niwNk?Y!MQHcMUU2aU)8e;bU@|IxVRu; zL}X(yKweN1K>ZX0*s)KL>~mzD(FGDrBtdqYfS-Iw1^?~jhvBa8AlunV`fyntROU+t z6D`?o=Ytu3Tn?IMmw`%}U|7<(^zt=R_wfMvWXP+LucrF`h_#qNJ2$TLEvun31=%&G z{b^a`2_%GrXeK$i75C(Co|ii>2N{9zWkKzAAIhCevlSVKDp9N_Cj2>hFU6^qmkcDH zT^GB=rX2-7MVrgRrhYu3zPXSta9p;a~_b(X)^Eq zbs!)W3hrd}A(c2`-|C<528heUmTxu`L;F#<(LA4_wz{z4v$w>50`G_TWkjm2obC?a zj3!mxun2#qav3d{uThqlOG1Sthw?WIe{gwIWFGMEnB2l>eA3fELaULG$Z2LikssOO;j8`f;vXyBxAg z{r|y&evL+jGY<10R&9K*g~i2{VjyxYi$8bGFz_Y=okf1pxh*U8^z{Mo+ok$Dv=}34 zxF{eppK6RaL!Kq2b!Oxf)d9o4KmhFByX+TObF~CE4HnM4KF0zTsYy#sBo%SK`AWAm z=t06H<>fn1cCJ;8xwimAAeIN@LNUtblUwoO-3v4ffaO4s%s)!VBYdNe&ea&n)!~*P z+7U~A(u8aRBaYAfeoyrREpvGiJOre7ie&-NU%B>l_y|zt_;pMT2)&;E`~*Q5)jZtn zE;8%fy_hT@$At?9FA5|8RZwD99ac=Hnq$t#zUrB{W>>%TrU*6bU_?Fr?drXpmFx`h zWs5M9-c(GdVU%l`I}+PV-+UH~qUF2s4> zL4uq3h$H?6yB4mm`IPr-D-%-S_uDk^j0%&$tE=lqk!nBjP3M=fspzw-E9nF$Eq9bw zDv|$=iE-2ML2h}6Wxejd02i}iAs|=(ua-Kv^l6iF9{-=oW1y2FsFF%i$h{#%*o<+= zq#m`N-D}QoR5Jy+Te%`m!@~y5mEWhj@L0dlh!hB8=IZNAbOR<+XcE_e`>elw$nDby z1XtzAHVB@L{^E9P#iP=#b}Wdff$7N}1@r(j-g~qoHYhRaXn_K-)2DGI+!CJ-bNU!u ztIbL3G*>y)kp!{M;kY!0DicO2cN9?ezpu0nt#4BDN|lm8C13gixXoZHn1tPE$n7rA z=97XcTFJSJ=uIp=KqN@ZXXZIdYY-AV-JNv?<8(2sO>x5;m3Wh_+bo3te$`{(x*Yj{5fc|(?duK zhAcz=D8S-&N$TGh1xqUtBeOKJ7ykk*sqQLrOFRJ;nPe;K+RYv}U!OE}(i^`F<3jzSOxK_6Pj|7&Se(>0BHjlUoc`OpVC{u{BA{2^k z$1Bkdu_On+n`S>f$(4%rPB`Zq1sJ=JaZAo^3Zjl_Af*tK<5c^ZKx}Q7eaz zq}h9$l;6^0@O3OT@YqT#`9=Y{OwRhAn@0uT_$ou@ETe5P^kO7~JB3L) z@T6<;YWbZ&=!UwLjq=(V%M`a~j89|@Y$&okF6`zc?B=(br*y!90G zo)S74x}hv{J}z?!m+3y9apl&MRf^j5iMj30sdCSyQB5a_e{p_&(s#3abG>_em#8KL zu&WmhDIsnUEVJ~huuIqH%h#XfnPP9g|PjPY8?f>Jo!li+sD{apvWPiu-)m^;QVkcb2XD+Z*}l(U7WM9-QUsV(*OH}mXi z@fULlg78Q_;V-E7w@>F#P1iU0mO|G-N>*#)hu^zf$R>49>2>c(&#rXfeQ!f!FK4pX zQ&^Sf2Wcr=^XM~lp<_~8tdi~8zu;)w32;&g5T`e_yw!)FtZR&`aU15Je&v2HWY?x0 zc8v?nRiP)bny#;7%7tebXR}CBZMo+Fp%GRT;-}trz%{gI*%3+gDJ9`7f z0=EWtsU;p(`J6jy0{f6$tPJ*tNZ932*d;3L3N^%_ z%uhIl)(4s*-}qVxj2_&&Bu(#Lbm8SHcM7viD0WQj=A!TBA_I6Mr}vPvb7o}sYGGF* zS;XU~0tjC&?kG_DyHgN_9EYlniJ>E|BcyMZ_Y$b78!o(`PZ64(C569cj2%@(v#UN} z{rWAiyikjA=(gr2yhHPJ$V)4e-m`muu;TeqmCO}V=4!{kFDNYR2JnIFzXUR;w~sY} zuruMOJ|o707$^F2em+U5d)b+uI#i0;_R5SZ9$8}!kye4#W6bx{6IO?5SZZ*6mul7C3cwB&NNjxC%|u2w#t1M7#b*_GA)Rg!i>uLy|tbDnp>?&p1;}L zC{2^SNc^eBIJEMQ!CEM5{$JevDfC+IcchG2^1CAr1x^z9&(q=3mFFRgClF5(B-zR@ zW9?O${>c)a=4@MwTgF7zu1_Ln#jo4qK)a=F;}ic zj5(A(hNEa57zg321Q^QIm~tE%APh z1W$eCvp@m8%iQjsX@9pgkeSDDIf+v*Y8!&8XJQ|c&iQ4f0%6?l9wbh*G3VBAVKJ=> z7cLctU=mx@^=I=uQ-g;Z1qy+3pkc(|#+^EpD{mu_Zt*!pEEA^5BR$d~p&t?mYjd67 zpF6ZG^$*mdSF2-fniN`7Ghfr zuS@aMrXR9TD1^#P?zoXqvQ6KW+8s-QgpwEh7d zUHh2@&FUJq@AA5QQln3Oj69yDGn`}Jq}~e`Gx_d+MzI;zl3`InZtGy63&6n6x|E&p zX`tZAiccJ$p=IoT9jw76U0+v!kM&O4v#fKv%I8=Jv-scU7bC^&X`O&<0YPMNbgX{k zFEi`nd%Gg8OI2*FZGp<@Zo9G%vGaO+@69ReaWkKKbD|oOs_)fE$ITRbV!jz!`-(Wh zl*W4OypyU7u-7)i8}G}VVdzZQs_5G`uPHMwsL8f$xlOtO0pC)5F?fyZCz2n+aE z5xQCN{CqrxECsX~f05bmt|!#p{=nnAG;Z8M8EjeYaY0+0-}m6sD9Q(eY4?-dPL3G} zy~?4A2CWD!O}T-;NsO2BPZhqW&G_qTo;Xv*zC<{6tt^Ja$4A@HQ?31PszQDTX%>i% z4hbeMUXCq7Lh?&^7EXFkq=DRZ;Cu?e*X!S&SJbu_KyO4yGI5zBrJA;I{%wxyK*KPX zFHcVQSCCT`yBA#t^#br08zu%><<4EzR3qnUo4G@(+IGgakMP3eHb-1rb?1rHYYSX7 zf*cPn>Y9+yM`ewxd9jS!;>7mR1kwHJSe~IO$+;bhgsY!6;*A+X`NfoaO2qd@jcS?>ZQH2-JYl8ABctbBEm`1c=74rfhXv6p)wiSM zi{#e&prO{9@S%mBN3VmN)znGe^sidfW6A20X7E0`ANvtx!t7XXL2Dq)@^4e&)z%*F z>}JL{E6IMF;@u0((K%r}&PGR@es%ZVhl=5A=%t%?J=8X;52SpVdM)es-#9JquhkTY z)m$5;6jfK>_ESc2=DqX@ebC4kwEvApn{Elte7(2uN zOZw@MixjowGr-XO5MH3oSnsaEO4oUOLJhBU3$S2sg(KXKwxC#W$-WXZhqSgE?u2L% z4X|KB1B0tW?VG~|femCiN#{Z3g_822;EfP1V)c zoZ5Tqz0xw>&@z#ViLJtpvKFk_QWu*w}@yi40`uV_$)8oA;ae8>Y+#J4nC(2Hy+sJ%*4g#xT_T znf`q2VW+SVda>Pe(G8H4eojF~ee?Sfe+6z11ZE3eyzc|8RABPaPEyun+tJ1dmiE5B zzOF7G3nSDK->A|jcVEUUq2EDg`zc`%y95eXR0e~*q4`Wu(5{g{(8J8RKUlsO9}-yz zKMGmXGFAJ{Kui5B{+067IanZA=cT}9xP!m}iGP;Qb8N?rltJK_Phz7!<|R%va10L z?I~^CFE`9V(w%oz5DHO@V~)?U@9RU4YNVwgH<#G3eVQ<@uftAqKtZ7Iai4Swn%>ukr>m?w*=6ptcPwVRCP%-Jxl14Vi(@YDL2WojcoJ&pFjdZ` zREh`whxQ%>Z`Jmq#WnSg?0)Hk?D6(QfT!x!lF^bmmpu)svl1%l9P8f_A00r9+$%Bk zUKU-5g4B%DWtzTIAiQq}9s%L=B5Cn7iM^Yt-RlkPL@W#|7CRXK-~e>GcyqO=M|N}j zS%8MsJH}dFuUYNvepX`=heI9v0;g+=?wOXTaq<3{qzgKnqDU-ir&rZB^*l-b=~mS< zFJ-rR9oWO4fcI2r4^}NTtPnCCF0VNw*>HEbZW-a8yQCEpDNMH=HGOOGsL*Xx@^Gr+ zh7h$8n;ngTfi!U1UuAzO`h0zo17Qp_W%i$_x4iebaxiyBiecgSP;j=Uer84NV0zX} z%g9`FV>(&Oy;)+1asSuOBjEqX9BT~EGh^Wy3nIg^PhSAA>+H?d5i0DTW2h3cnZ_zu z7ukGEvfER11jTpV>l2#3cdxq9+ddF=eq^Y zm#Tyje+#cS3a_y;H$K2T@MWrbReIl#bQE&@BmDDK(nf;kd%`3PdAI5b%?Nl`?{X5*UcDYYaW=~r#!YPxkUXu1b9jHWWdmPRv6gA7{1EP52EK){jLr) zumPf~>$(rU^idtl)sVTJ_Z4j79L&oDLqV|{j$78%x*C1M}|&s?EeoALc}wImS^&J^M)clK1drx45u$ zaDzVt)`^cRor1Jo9)KEZ45L`^Oac^#>Q=uTT(Nv6wPBsop&y&e&rrt zJu4rxeNiS7I;>JN0`g;=?3nElQ;Bx8U)1XlFBP4g4T4j78E?B(HE}i5tZEn|KDUGm z#W1BQlz3X)@-7TNFnoPn*< zPQ0qW!4wG-kud>lli6d0gJy(<$w(D;KQqS1zA zz#OR{yxUp=MFI!|>QpW$J$^a97?kkjSSxY8HLRPzKq0`>h(o6?Y3L`S8PUL~Q#b|q zOu-qEYZKn-k`|~UXjZMBI%{k(vO8{iqUv0s-=tJX%Rl z=i_xQWh#(gLpLA5v_Rvt(BFbz+>)TXBMy>z9^rdU+vc9?#5A$CiY_vl22!A>rMeV6Z9?l<0uMLqDZhJN z={9hBR2iKFyL&`^}Q*-SE+uj>QF7WyxC_Cr|%)!aNR7n=W_?h!ZEu>}I zukdt@VpD};Thy`$ZJ%Bb>^>HGQLaUCVGGEk8)%vTxYq9o$~nO{$K9S? z7IP-Mv~521+HK$8+AnR0%4NWiVnDg-zNFE6ko2{Ks@m?@mEAFp&=2&1fq?~k8)eU| zg;R$FOakeixYze3USWh8m0ADz7IpQpjC6FJEh2s91lm%Bs#hCiCs%9j zyRJ2cwQ?u;Cy5AdjIzA62tgGMiE^(ojn>W_s8Fxj*u~86v;ks$H6uH7{})Mnzh7~% zZr=yWiNQ>8=BdY$n5}9!mki<&Yc^;EW0uXnf)XHZFt-1pKZ)wf@#xk{Gh>DSb>~tX zZb1#OiE+91&xmbn-9FE6Suz;^Y}4)?iytyy3~QZr%Nei8WiQ_6nOZZju~{~iWz|I! zQFYh27SvQ&AFn?tyPpqAw4^Jy=VQ=;dwiE~M=r117gBN$8V??$FLBOtLbPy)ZWE5Q z-RX41=Ar_lWc%=St;gJ+qCC2`3-h11FuwVeQ6SqpfVxHCE3PeL-Lb@BqKI2Mr=~2y|&iw4n$^G$M(niENW^-zN_}wSuTzbn`@6O zE%fk58`jC}Nx0^;;1lA8S)L+A_A1FV*2GP>`tM;8SaDp$R$#=|(wmIEu!iYX)9@ZI zme+x1kQh3Yq&YX)I>-^RO(36&(M?{YYvKOT8H!ovW^?si>r9mC7ZYVZ|B{AAKpOG| zV5Y3Ctx+h2n$>EEBAXtzcD(O{CUAv0WyiKZskS!<7CwZm zp~v*Qn%qcEXI#>Qmul(=cUO+}Hmtsp8qjgH3kZ1{D5ewxQ&UD0rLR<1l0kDu;1hQ1 z&dDC1+)4asIA~^w)J$`Pf4%E>37HIT4ZC@;=$p$0hnkM+oHbi|*~0Dc_-F22Sxs&L zK9!AB;K{@iO^dwcmlxj^t*~t{tc9(G40^Dr(=87?JR7@{_WalPzL2e;`4~RWO->WR z^TnF94lgc}f~56IAfQIw4}e=!Pz!-$a#iBUkDlgJ0DGKOKSBX_Z&al}LDFbgX|{D5 ztbJeXZ>Q{U|J@b%??%JfHzNL{(JfX{!HXB`s77&1=B6-)PHTZ&ueKkb8ryeQ_cZta z(?>w81r2sR2{soF%r2$m@>!KlT#?_+uZOxRMBAWmk&4f8l}j_2Oe}ZzxBKHek{k~= zgTv6uo*-)-)Y@68ZKeDg)LQR%*4~+{@ObW&++bT48kHeuz#{$1 z&*5zR$#?O>oxHps&KEvlZ-@7XXX;px6dtmd2690P`QTs1nYy^DM^Fc`@dq(Y!rD#>`a5&$#UJN zG(W|Yvn;ZGINU*fDS@9xpIG5X#PuwAF7k2jZ$67auo9pYuR%E&JcV$oa|E^W%I-3; zeQ(p%L*m3}-g>kEMH(0c2tk!-A+MgFd8)ZDOssE~YewS9`W6g2RSs|>Sy?;D5xW$W z>`0YkEo=CA?sC}X*u^Vh^|B^EL{dEQ%{sH{mjL6*p5+93lXkoX8yu07%VsPZ_W;Qj z(l!02o|_?(+yYj)!I-jFN~TXV%>xHOa8rj`fjoH}(Lcy$AJjkx2ZCKgLZoKiDAOsM zXF1u}s6HNJC0w<;2b}@*0SyOJ)n3F?UTzQPXrutHT0P z9_52WnAXlTzP-O}c9q{C%gHqdf8nH3Pg{wTw8ACO6n=UEETSyvf7!#3{beD` z^kA~I|9~U8INGVyvn)9{)KfCWeuA{K>w4#ggs*3@jJ+(-rOjA6IzN(Q_1a#+gPiVU z6krXvW!r5$bpt^kZaxAvl1Z1Ddr#7cHv!Dy`W7>xu+V(c`Nc=V%L8QSkFoyY(igi= zeKETS!FpXjxuq2z)2uX7H)w}IO%3$Wvk(j@r4rJTdEjM{M9{<6nDI(^G@8c+;Ml%i zpmYGI37adMOBDv!3h9-72-ouRW`5OB`im&f4Inyq1O1-A@u{X%meXPVd9?wz`h|ls z>U5G-efI|rlxQmBgU!IC{9CN)-!#X?p%-YZHCTx=K4>1Eax|oZtYMV?(N{p9lP>N^ z&S!>9(2Ae^yA?kRS0(6<w60<5Lkh`A3V=;4m2)jKl*}|o&^ubsV5oz49f$zAiRCz?PnE0331p3 z8nY6Z301fgke+qSxA}ZJSW{H29_2PCD#!aD1ML~0K4Kw!6?c5b5jmR(N5L3I^M2C> zYRQWAERGDf4XuVSBA2%z6w^VLw{k50+FOnT{v9pt?R-c;;>q^i#wb7@|92j z;Jl4r{!@Pk^Upl8Y(F{#ok(&fF7yw3G0a3K5mgw7RGpqz=Tp%R;;42(U?1D$b zTJY<;&HT?z=4e3E9mxJnLedXJ!RQ3*Am&K8yNKxpEhsmQC>e1)UVI+(J_Ss4Z z*)s;>sf)wJe7K%J5URLK%bw;v#Pl^ySDuxywF^;nBbZstEWmvjXz#wqbJiU`s}uvh zz)6hnf+KX?~RJ1NH_&K<7t5Nb>wIiSUShOI27GN0I6l<-6c2Hu};pODtqz2-}f zRadcsv9=5!b0%{+kxM9fR(ca+qFt`EpI=4Nt-+54I-!DQ>_V=|uV*OiCuH^#ebw1Q z=dQ@|=99iv=$e6KXM2W|!#>Li2HsLz)WfN>z!~A#N1)_nUPxSgFb6XONG>@FMNo(M z0s0%WUz-gbHF$-VTRcPGRdZa}1 z%^n%C5r?*rnTA^qQOV&umwV#@7E3^ z3k7Qz)v}y`%+vSY@)_5hsfMRy4N)#NJ*L7BIo-wj_;+&{NIq?D-B)9)n41gW8G@W_ zJRMr2uSTy#bh_cLSV#A5Hz61g+9=M07vw}M+wmApr8 ziPHkNde>EmO>n@cagOo&$&cA*`=uVM$m;|Bwy-o#xJP=liOO2EzYDBnm^t-1-`gJ7 z&|Fj-%UBrk4*t#XAE`mzXjDrc1H5L@_1YGc1rJbzVcopG0O^fvU%(5{k znNTceYBf8&*Z;v15sO&g zkFnHM5bI++`)&{E;*D4e8t|6#rCkza+LJ9fy6d#vv8axCTH(iZ#{af{U(Ks&Mv=jD z^>2(u>U_Ln2hkqg-leU(@Q|r$IP_*QDjMY8lEt=b1C+B>06SE>{HAPP7}Dd4vj_Io zyp($-!7C0@(~9gDp-igmdhVZ(t4iGDN)0ML!&#DwoHZw6IJr#a4>p#<=)Bk$rmH&c z*&Mn2!D^^t8b}JXIR&q<3hRg zN5fjjk&X;opEJ08VM&Y@s}=nB?Gze3bZ^cJrnS%Y*D{b!Dr(6nkx=Q9tBhR(_xlVS z*MCr`dH%0$2Gu8W{y8qzdJ+u~v{Ui~xdpYh*4B(+Zc0kPi)wCp)7oxYi!7<}tk-#& zsUxll7DZx2y7`LkZhq}=LHT9IR`&s%1Ns~TbSam<=oZW$2WymMA7SbE;?3Zvp6;?A z^1gV^v8=e35jRLPE*WlCXV|>>0T0PvXn>mhv}lzOTVAEw-ukr}`jL3}A# zN3(n&!ZV*#Zgejyv#GH%frr#Iy>%!4=7U4+N=y}G``2|nGs@=>n8A_N3i1>N{R>V` zTtIC`Hf`L%JdoF zQ>5UG4OEQc^0+-;uQ;Rk`LUeX zYnnG_*0nCXLNe&MN6T{uJVe*E3Y;0=#xfOPGYB@|F;l#y!Ec2&)Mm!undQ{M^9o2M z<3Y}c&4fH4b^gp62>fPffT{yXM#Ptp05>y$F#yXG@J+F#k;3}f2;?W=M&(k)eo8!A zOG&oxde;RcJCuuvo?E^Ssa65Bv$fXX0H3aJ0xE>uOH9DO1}HqZerv3+O;bmYInY6c zKr*Tv+1G>)OB!?)0j4`Vb<8+B(uOFJaiCQyuWL2 zP5-)ZxU&-V{^>VNkFuPKPU)eEK+JCM(Q}5YyknsGsu7x4>Uv#OoFO=&zA~Cwd|0VV z?Lm22oa?`&(VG%29Nf@VGC}4TShX38Ye4&yDQ2K~`Ueh1mzHUiUijt-K-OGAvhk%1 zs2g+p8ayy~kZ)k^4~iGdq%WTJZ@2+~Q4E?7sBr`sbRsJ20OQYl=Tu*@Up&lL5z^0g zy1zNM-4^l6B6$(4Ha&;H)c>3css(IwWw;Z4HNXX|MfZ0wc2@xb^i=YVO+6gWZKZ0~ zQ`|BzFAYz|Rj|EN2_#m6$A*68Gt(5yjr=(eQcK|_y@7S%galx3kkK}+`=f2n_SVXr zv{8BkS-3(wiOU~~gv!sUAksc+#{{(B7o)jKtmH39U;svI9qU@uYKbK=NUxy-Td^q! z%76U*Igc|kE?|AG!CzPJ)7P+GNY1?~U^v(~uL`~noAY`^oUCfPnC(PN!o1s6;qX z931rg5O7;y76$~?-hp`7QD!V*-36hF7XT?`vXs(XJo-f${|VhB5d6g z(HBH5>Mcwr*JkZ_4|=!*AG`SC7iqwd z;Ct#9Vt~x*%FbR_u;10!vVGqBhKINUn8XbUN{@#+vR}SvMK`f_zjxn=?R%Ua9rUv=ZghLIfQ*1 zR0$5yq~)nbQLSL3qZ8uHQRrt49v!tzQdS=lms#7a{a75)+JIzkS^e2NJTT@ab>(kY zJ&iKp5tlr3PLW?B%f~=5nHAkK&L~m9OL|XvBj~)Z3ROho4 z>}^FTWdLg^W8}>@2Ho4-g6wCTdrw&oETE1r2J>QJ@Mi&9qB00JLOJf>rEzk7scZ70 z|5Wp&dtrLD_RY+bB1vBa%briVi*=X8gg6^gSMe9$tU}B-hycvuswt!(g$eoiqtI-g z#fV7tg(C(aY4WqzO}ch3E8!<|dqn)v+E;!i+uI5rw)o3W+lXsK$wu+(PHHJgY#~p* zVr{?0hZBk*aShA=SlPCws6od5W{!8j4DnV11EA)-ywqyOVz9E<90HxO6FuhPf5}H} z^rZ~I++hh|=?N8ntw%`Fp z%AK8^fMTv@d0Pipr6{qhUB)d>uBEg(rb{gu~B0sqf=w)wR$`P6+_>F>HY~YSk$-Zxj6ROsK;v35ARp7 zs8+0Iu?X{*v*aGubbaPYC(FW7aU-cs8nQ|{PJhj!)tHS#s*yp2^0>2u2l^1US@%iJ zC!W6xx?OMYiej|8^Z*wtA!7LS<0PI{1BOYxD?FZeQxfRGhAy)tc!E+ME~Iy(Li}Wf zlO0aqQn`fNIO3j_FGP{Q)(VpW!Ds-;>)++n^tS@bAm+bf0c=DL20j;EJV=1n^WGpr zRGN6S$F#S+Ay{k;6}5SNnTfq%lFnd9I*=C!SqjNc_HtT#z5mBkj~27|Z$~{o&pktU z_vl!j=YjfOLCBW`xayVK+p&}nMj6xMW1R{qB#f^`kneup!$BFOsz)Z=8N=?Ppto)1;HJg_65x zF6VD&7C2bv56@iw_ygGGL6Z`s&JZ=w#B)kTjX9aDNSN$g-&Zmns?rewhA(z^FN*L= z1wmeUt#jF@3}yN(bA|*$1sEdT`O-+ubqBed@zZcVVSP?_P&)WN*6=oO1b7GW${HOtv0~aKjum{Khe@fwz<2{7dkIep8$j&3D{G#3ZOqSodgg%{@B$U; z%82cUC&*m_UZB^5Kn4V5DjQmfV6r{#A^F!iU*Q9n;){W4&$`wx7IaBNfD5zoMoFqY zFFhdd>W@X|2v?c5)^?r!;>r&d(u3aAcCcHbyi|nZuCB~gHOr$3AArZ5{J%Z!prns@ zNQ4p_$;9!w>CTlZxXf3izR)#}RFX9t7Vj4klwV18^1o?xo&7_dPwzjD8_3wo^0ZZZfC0GR==y5oO))v4I0 zvW@0p(1*mQ1P@)p_O#udkouIWFn3{ax~!81k@+7BP{Eo>2`M(hS*`NS?Q8rB5AQ)o zqXkD}8j5wfaB^qN4OMb2r<4tpj_n_pticQG(j}Wiq@8g&lU`#!r|wky0xwa&is4#k z>SnM9KbQdfK7QZZYs)MDJtR-YblqnMA56AK=O(C~>hch3!Y^ z9}>05E%%9o9R)9g_=^nc^0AI63T!j+9V0=m@Jlr#regG~IW&45B>bC>++9?&UCh*A zozL$XP}djLd5If-`nLh-SdngpsWOMJ?c<}CK*-36^+!j+4V9v1WacWxmz!lxm`$4* zi;Dk#e|nU`hhhbX-LP(~zy{qh49Z5;}9gLRnWn5p%nSp^K3Ek0-UBNo!h;8X#W}Z%VxxbykAE(NE1gZ(NO{S z-oECw%e?Gq4a`34Z#q8$ama2|q!0(f&;;#?D*5Dbn{D)Ueyr9c_U)>ldv28dxPQ;e zYT(&Cu-pKHtq*A25T>o^R-G^NpX7l@2L+?P;-c=LuW31VOL`X<^nkhN-lNh<=Bpml zGllqDO|urXAI#~OGz(p)-qTq9zHx_sr-#sjEPwUX8l< zXWxrI`(FIn_u|jK7k~D>__OcDpM5X>?0fNN-;4ii`(7{#|FiGKxIAr#7_6hiazFpb z;pj+BMuFO!pXh1stnW?J($GAA8B9k5tInsP(R(6IL&HgCp*j2N&yW7xi9ciF&#UnN VH7KO9)z>oei5%jP{P&{ve*hOF@ag~n literal 0 HcmV?d00001 diff --git a/doc/lua-api/conf.py b/doc/lua-api/conf.py new file mode 100644 index 000000000..fd7e0ee88 --- /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 000000000..3c76e50bb --- /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 + `_ +