}d#P
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
diff --git a/docs/source/apis/components/index.rst b/docs/source/apis/components/index.rst
index 3a311617..24890fa4 100644
--- a/docs/source/apis/components/index.rst
+++ b/docs/source/apis/components/index.rst
@@ -1,3 +1,5 @@
+.. _apis-components:
+
Components
==============
@@ -10,9 +12,9 @@ Overview
components.agent
components.model_client
components.data_process
-
+
.. components.reasoning
-
+
components.retriever
components.output_parsers
@@ -65,4 +67,3 @@ Retrievers
:maxdepth: 1
components.retriever
-
diff --git a/docs/source/apis/core/index.rst b/docs/source/apis/core/index.rst
index dc5dc194..c9f7399b 100644
--- a/docs/source/apis/core/index.rst
+++ b/docs/source/apis/core/index.rst
@@ -1,3 +1,5 @@
+.. _apis-core:
+
Core
===================
@@ -7,7 +9,7 @@ Overview
----------
.. autosummary::
- core.base_data_class
+ core.base_data_class
core.component
core.db
core.default_prompt_template
diff --git a/docs/source/apis/eval/index.rst b/docs/source/apis/eval/index.rst
index 966c01a1..d3b09e39 100644
--- a/docs/source/apis/eval/index.rst
+++ b/docs/source/apis/eval/index.rst
@@ -1,3 +1,5 @@
+.. _apis-eval:
+
Evaluation
==============
diff --git a/docs/source/apis/optim/index.rst b/docs/source/apis/optim/index.rst
index 74894349..3e2f23d8 100644
--- a/docs/source/apis/optim/index.rst
+++ b/docs/source/apis/optim/index.rst
@@ -1,3 +1,5 @@
+.. _apis-optim:
+
.. Optimizer
.. ==============
@@ -22,4 +24,4 @@ Optimizer
optim.sampler
optim.few_shot_optimizer
optim.llm_augment
- optim.llm_optimizer
\ No newline at end of file
+ optim.llm_optimizer
diff --git a/docs/source/apis/tracing/index.rst b/docs/source/apis/tracing/index.rst
index 66ffceef..7a266ecd 100644
--- a/docs/source/apis/tracing/index.rst
+++ b/docs/source/apis/tracing/index.rst
@@ -1,3 +1,5 @@
+.. _apis-tracing:
+
Tracing
==============
@@ -22,4 +24,4 @@ Loggers
:maxdepth: 1
tracing.generator_state_logger
- tracing.generator_call_logger
\ No newline at end of file
+ tracing.generator_call_logger
diff --git a/docs/source/apis/utils/index.rst b/docs/source/apis/utils/index.rst
index 4f13a5c5..fb339773 100644
--- a/docs/source/apis/utils/index.rst
+++ b/docs/source/apis/utils/index.rst
@@ -1,3 +1,5 @@
+.. _apis-utils:
+
Utils
=============================
@@ -31,4 +33,3 @@ Setup_env
:maxdepth: 1
utils.setup_env
-
diff --git a/docs/source/developer_notes/index.rst b/docs/source/developer_notes/index.rst
index 7fca9427..463b03a5 100644
--- a/docs/source/developer_notes/index.rst
+++ b/docs/source/developer_notes/index.rst
@@ -4,7 +4,7 @@
Tutorials
=============================
-*Why and How Each Part works*
+.. *Why and How Each Part works*
Learn the `why` and `how-to` (customize and integrate) behind each core part within the `LightRAG` library.
These are our most important tutorials before you move ahead to build use cases (LLM applications) end to end.
@@ -47,7 +47,8 @@ Building
-------------------
Base classes
~~~~~~~~~~~~~~~~~~~~~~
-Code path: ``lightrag.core``.
+Code path: :ref:`lightrag.core `.
+
.. list-table::
:widths: 20 80
@@ -56,9 +57,9 @@ Code path: ``lightrag.core``.
* - Base Class
- Description
* - :doc:`component`
- - Similar to ``Module`` in `PyTorch`, it standardizes the interface of all components with `call`, `acall`, and `__call__` methods, handles states, and serialization. Components can be easily chained togehter via `Sequential` for now.
+ - The building block for task pipeline. It standardizes the interface of all components with `call`, `acall`, and `__call__` methods, handles state serialization, nested components, and parameters for optimization. Components can be easily chained together via ``Sequential``.
* - :doc:`base_data_class`
- - Leverages the ``dataclasses`` module in Python to ease the data interaction with prompt and serialization.
+ - The base class for data. It eases the data interaction with LLMs for both prompt formatting and output parsing.
@@ -79,10 +80,10 @@ RAG components
^^^^^^^^^^^^^^^^^^^
-Code path: ``lightrag.core``. For abstract classes:
+Code path: :ref:`lightrag.core`. For abstract classes:
-- ``ModelClient``: the functional subclass is in ``lightrag.components.model_client``.
-- ``Retriever``: the functional subclass is in ``lightrag.components.retriever``. It works hand-in-hand with the ``LocalDB`` and Cloud DB in ``lightrag.database``.
+- ``ModelClient``: the functional subclass is in :ref:`lightrag.components.model_client`.
+- ``Retriever``: the functional subclass is in :ref:`lightrag.components.retriever`.
.. list-table::
@@ -92,11 +93,13 @@ Code path: ``lightrag.core``. For abstract classes:
* - Part
- Description
* - :doc:`prompt`
- - Built on ``jinja2``, it programmablly and flexibly format prompt(text) as **input to the generator**.
+ - Built on `jinja2`, it programmatically and flexibly formats prompts as input to the generator.
* - :doc:`model_client`
- ``ModelClient`` is the protocol and base class for LightRAG to **integrate all models**, either APIs or local, LLMs or Embedding models or any others.
* - :doc:`generator`
- The **center component** that orchestrates the model client(LLMs in particular), prompt, and output processors for format parsing or any post processing.
+ * - :doc:`output_parsers`
+ - The component that parses the output string to structured data.
* - :doc:`embedder`
- The component that orchestrates model client (Embedding models in particular) and output processors.
* - :doc:`retriever`
@@ -133,6 +136,7 @@ Components work on a sequence of ``Document`` and return a sequence of ``Documen
prompt
model_client
generator
+ output_parsers
embedder
retriever
text_splitter
diff --git a/docs/source/developer_notes/output_parsers.rst b/docs/source/developer_notes/output_parsers.rst
new file mode 100644
index 00000000..dc1f8e4c
--- /dev/null
+++ b/docs/source/developer_notes/output_parsers.rst
@@ -0,0 +1,2 @@
+OutputParser
+=============
diff --git a/docs/source/developer_notes/prompt.rst b/docs/source/developer_notes/prompt.rst
index 2c73bc85..720c3ebc 100644
--- a/docs/source/developer_notes/prompt.rst
+++ b/docs/source/developer_notes/prompt.rst
@@ -5,12 +5,60 @@ Prompt
`Li Yin `_
+Context
+----------------
+
+The prompt refers to the text input to the LLM models.
+When sent to an LLM, the model uses the prompt to auto-regressively generate the next tokens, continuing the process until it reaches a specified stopping criterion.
+The prompt itself plays a crucial role in the performance of the desired tasks.
+Researchers often use `special tokens` to separate different sections of the prompt, such as the system message, user message, and assistant message.
+Ideally, developers should format this prompt with special tokens specific to the model's at training time.
+However, many proprietary APIs did not disclose their special tokens, and requires users to send them in the forms of messages of different roles.
+
+In LLM applications, the first thing you need is to
+
+Design
+----------------
+
+The prompt refers to the text input to the LLM models.
+You can use any of Python's native string formatting.
+The ``format()`` with kwargs is the one that allows you to use placeholders and treat them as key-word arguments.
+
+.. code-block:: python
+ :linenos:
+
+ # percent(%) formatting
+ name = "Alice"
+ age = 20
+ print("My name is %s, and I am %d years old." % (name, age))
+
+ # format() method with kwargs
+ print("My name is {name}, and I am {age} years old.".format(name=name, age=age))
+
+ # f-string
+ print(f"My name is {name}, and I am {age} years old.")
+
+ # Templates
+ from string import Template
+ t = Template('My name is $name, and I am $age years old.')
+ print(t.substitute(name=name, age=age))
+
+
+
+
+
We strick to maximize developers' control towards the final experience and performance, simplify the development process, and minimize the token consumption.
For the major chat models, we eventually will only send two messages to the model: the system message and the user message. The user message is simple,
often you have a message `{'role': 'user', 'content': 'Hello, how are you?'}`. The system message is more complex, it contains the task description, tools, examples, chat history, context, and
intermediate step history from agents.
+
+
+**Data Flow in LLM applications**
+
+**Benefits of using Jinja2**
+
Prompt template
---------------------
@@ -166,6 +214,14 @@ Output yaml or json format can lead to different performance. We have better luc
- Few-shot works so well in some case, but it can lead to regression in some cases.
- It is not fun to be a prompt engineer! But what can we do for now.
+.. admonition:: References
+ :class: highlight
+
+ 1. Jinja2: https://jinja.palletsprojects.com/en/3.1.x/
+ 2. Llama3 special tokens: https://llama.meta.com/docs/model-cards-and-prompt-formats/meta-llama-3/
+
+.. admonition:: API References
+ :class: highlight
-Resources:
-1. `Jinja2`:
+ - :class:`core.prompt_builder.Prompt`
+ - :constant:`core.prompt_builder.DEFAULT_LIGHTRAG_SYSTEM_PROMPT`
diff --git a/docs/source/insert_labels.py b/docs/source/insert_labels.py
index bdf5f036..324c10af 100644
--- a/docs/source/insert_labels.py
+++ b/docs/source/insert_labels.py
@@ -4,17 +4,21 @@
def add_reference_labels(directory: str):
try:
for filename in os.listdir(directory):
- if filename.endswith(".rst") and "index" not in filename:
+ if filename.endswith(".rst"):
+ if filename == "index.rst":
+ module_label = "-".join(directory.split("/")[-2:])
+ else:
+ module_label = filename.replace(".rst", "").replace(".", "-")
filepath = os.path.join(directory, filename)
with open(filepath, "r+") as file:
content = file.read()
file.seek(0, 0)
- module_label = filename.replace(".rst", "").replace(".", "-")
+ # module_label = filename.replace(".rst", "").replace(".", "-")
if module_label not in content:
label_line = f".. _{module_label}:\n\n"
file.write(label_line + content)
- except:
- print(f"directory {directory} not exists")
+ except Exception as e:
+ print(f"directory {directory} not exists: {e}")
if __name__ == "__main__":
diff --git a/images/LightRAG-logo-circle.png b/images/LightRAG-logo-circle.png
deleted file mode 100644
index 899dba0c6465abcdd4c3d2ee9b3c34ceeea1013e..0000000000000000000000000000000000000000
GIT binary patch
literal 0
HcmV?d00001
literal 12146
zcmV-&FOATNP)PyA07*naRCr$1eF>OdRh90)&$(mGRha{sM-s@uC@3gOBcOmdU@N{S4&D0vY(cx#
zr%zkod(hh5w%YyFrX3o6YCF-$s5B~r0s;vH0)!-F1X4+*GSqbEbI$JkYwvyTsmfGS
z68id;p>ExK?mqk9Yps9%Ywdj%{);@c))xS{13>EthujO`N~P3;BYfWpdAT|vpL&!J
z)mksnz;nr$9fN@`RZ6XUrQQEAxX;nuqSksffHOw-?lHgX38mDTW4_8bT;PNPqP4yj
z&^H4obQnXY@qJ3E?~lXWj_ML8WF~Z^LjazPSVo|aF!&QPM2;s?O8KLj)iJ#3xZbUf
z^x&C~KRr4MAjfr>2aQE3b=(GUTs}zas8>U^5RK#yKRgvbbEIX(R}LPkL-x4bfEik!
zQfj0OZ^X88Oz%f)JzFE%s-a+h1_MH$m6EA;(|a`6RUhsN0K`r19HrE@5zq86-*C(T
zsp>%U;tq&NNAOfCUgvaDbkO{X2ch|_2IwKQMihqdQiRMs>Xvc>0WqQP7`d@=2SjV#
zT7vE|U}ywkh>V|>iFXf15?Tl6Jqoq_>w9h}nok0riTQ&cuN*+^xZ0FbOgzW!F|L3V
zLS528j!WKGX5|YoT=XH3@+`G-%i9BJM#{P_&KJFELdq3TTbkdqB;#wu`3hL9Y>rK9YYRf
z5#te8#tz6GJ2iafdG!5}xEnC{upM=HJ^O)utfN}sDt<~^t
zY3I^7?Tj;V(s+HVhv}6@f;c{PyLq!WULHq)POYKvQZDHG_+@}fmF$p=wRp*
z-3u2s*%G5m7?=gwZzs!%b`m%amdAzA<5xbeU^PcNkyG@
z56(aN5*zBQ&O_elZo|B5Xy)XuHCjs<6(GOguXQ;9v=2lcP*p(92l{Kkj(z|
zI5PZT9U=50X!!87Cmxz>(7?penTHT|UdkJ}rV5kqu{&3c&290)+qy{nm<`ttD41%X15c*K)4XxgUvT94sF`0XF`D
zHUgbBe%pmjYq-XRMoz&i`zk%GDW5*6viUhc_dSly7_qS6EFUr&6dyAyU4F
zrgR$nYYZ?PJe@X!Oa;pu^H?^0Di%-AV%B8fWL2lW&T^jZ1MYpc3%`H48#}d+nGKDY
zR2sk==Fh<8r#EAkrOA|BeQE++c=8c64NfgHO_~x32A#N}-sKwOR#w2+1E2t4dleW6
zfv&0$K+H@73tE8*cF~ZQa|UVM{D@oxq=qOAGU2oiK4QheL=^Y`&JX(Vhb6NN3lQA-
zk`_NNHy!{{4G1eHKr3=04vI^NqfQy17`SN{oQzx^2x>sB1gIKj=?a!M=Wxc1$$0JJ
z7EHCPl~-U4T3Z4hTsMH{Nsn$lxDX!=C)4n09rFZE(1)+niWcO=9`UE
zFhk->yRkk>
z0e;Sa5d}cCAD2&?g!yf4XwRp_*td7@#>Txnv9}hWhKz~fwK6U{WiBo|WdfF_OcI+5
z4R_$wO7M>hp$AW=SV!V%1st)SazsG3S;3G~Xz6;K2yqoVARMi9F4pGfF%zR3;%eQ}
z2Ryd92aoL7jWwKsR0B{W<;@s(mSqem;L-^VxcaP_Seh}`;)4H!8#=N2i6=3)r48?X
z&1;YJ31*-dUSEp2ii+7va1)K4vi#+C{|s
zBakE>TPwibtG46uUHkD2U2jmvl1AV?E0*E%sh%tX#xW5>=@vDRx8Nu;GN~)rflHmi
zIx{;#N?vg2$6^1lRqNh%poMHSXXBQmy7bn*)t+qRkgL1QcBud4+xcFC!kgyGeV_}t
z`>Cy1J5WPkDsKottqNqwT&kE+8Nk^cO?dM;^RTGFSOBlPaR7MeHxHq$;^94)oQDN%
zMiY~q0U8kk^dOC&Z0^DL*LGr~*DguqlvD}l<~2TW{sJt?+m&u7mG31G{NVy%&?gK0
zV=wUSM>b+rxh#{=S}EhI2~+Ur=g+`oYrzf_OJ9Tl&^en*Xg${)G(ju}rw?5YJ}e+l
zX|1Q&l|XkHGB2{hO!CqY$XLqB--YYfL%WT86oHFUH_v!!L`b6yPi~gL&>cOz2l(aV
zYq6yUZ1o#Zs`@~t5vVcQh|mxY;L3T^@uuZXm}4h_3*x?qcA&Ux2R?ko*_a^7nwiLM
z0IaXR@0U-ZD?J5Jw88;g(Nx6s7cG!jzyQq$?~4nI?uUznj~3KK7tqK_{MiiP=a28i
zEt@w(<(n}%%3>lyy!Vo&SkYiyw^Onu=}g2xR}FQZ!!mKIFt$@I2Pki=(2kf_&v#JNU
z@7b+by|;`_OozQjlamnnS^+El8ZKQjAD7Sf#2V7aw
zf~BOae{v!@LA0Fvb{BEmn&uSI)kGzPr-F+zfz#gs8t#f94{4kase9;iZrOeIeFt4K>
z^CmW9@l;@T6L7L+YrL~5!vf^4t>msADg*e~+-bOOWrrk7MAc=pI-)$zER?zLkccJO
zD-}2XYnP$bj2uQBJ2P&TN=e>9X6F8-E8_&*zZbau$t`%OCjzp~miyCh7Lc#?<0C7V
z;Nm$soJ2qefVoX3M*XA<_}pWgfhdP&Kg7FRtGNDx`RJfK2})@9awcU-EA)H7&!6eW
zt?M@8*>oCH!y3MI)vGbjuLo%^HiE&$LU%~l_J=ZX|7PHKdwYQ*A>#r}sM&NSeE7U^
zu0jG-!J@E;#W{tQGpFG6d97HKL$qi}Gv2`#a@#tMY#R`zF~7JUUw*>^yt>`^$#hsl
zj&4Nqu?V5o(6+hHhL=Q3k8xa5Pq!4Uu8tb9P*m2)D65n}cx#S2J6HCr?Z7{+ejdA-
zKV);Z02Tm21?T2dxbDn3IIGprUs~H=-2XEEqu`4<&aU<1$5$^A&}bQ4P$U3;z{ONU
z*~{WN4gCFWkKiR0;=CDC@mFUqz!c73WD`rSE6)JZ1K>CPz&)M7-MdRb|A6h(2#ncR
z2pvs}sy1CUZ=PbD^W(hdnr$#pxX7#Ex0fy*gu$R+)@pt2rykyZ^F4b5Ks5nD6>rOz
z@rg?oU_Sj{7@?V{a{+jD<|B(?P)koF6YeAgYF(y=UhgESQqAxb6bCIDdCDjs9J943
z=f7V7@U2I8qy`~{D>5nq;>Bty|HeNvE-=P$^*`JN{CM>y+*1gFwy8#r@vA_k
zh<8qyh;z@K|_e9KD(m=Y|xYB$Y80f|gb0^^a%UUG1WF`B_2qfm3HmBle*%eUrI7-$&
zBGgm{J19n0fY0Bx3WZb-vnmCA>TR#WsSNmb4!96qZee1m1;oV+-mR-XT0mT);G`x3
zRRx}yZ}+FffUq;2FCI{acdtGm*xq>e2CVfa+F((_tHb^H{98^FO^2+dK~{xh7iR5A
z%c#V2yJD1&$mS=>1j#2Lig~p!T+OX5M-J*SDL@p}q~yTFvV@eFKm9suDL>y-#`m6k
z5j}nrPz`}>R^*recisMkt6CG2ijf@1=470k`$3Tc1ZI1-xm-1bpK3$&y2~
zknf0z8Ks{w&d%weI3gF9I(%#{gGh}$YsbL<_LG2AbY)2<$~-5Ij`Y(9b}7TTzrC)A
zZ$7^RNVfs$G&1G=I8PPumsg&OB?@xW4X7bt)0^TgNgd4&gr8_W)s;4rgLm4Pb5l+i
zitms?JqiU336eT66q?s#Pq3enAv14b;pwRYaQ~yvW2)BpR
zr8~i_Qx&3w2xVwwkr!t5&5ghhpWcl2sDQtD=Q6Bh%!n#zBmx96OP0k_`%z5_Iw!JHpc!WaNtt|#FQT)q_!$(TkV8uD
z`?J5@gY`WHoZ1lKlb6jANu?P9qDqKNCJU`tTMv>u}ZAoxtIY~Sd%~S4z@ePssdMFFNj8~?CvXL=|^)TyF
zTmUB5VZlvm;W8ODiGzWkN6iuo#-{7;ei_^Qi@0b)8rS{F97!y55gY!pQo)W;H6(!W
zGpluvA*nW14XH^f0v&223(~&p6F}=ED9i&k0l4|0
z&G<2k&Ys1Uc7hq6ufU`lW0ZBo+=?+wpl~kVq`MifAANYlQknwV90KFAgWen
zfW~qX-D=i4riwqiU?I+JG@!8l
z+`@&yn8}}m#}k(vS>O@<&^9{qrLv%G1Dm6&Lsud1#RXM<1~n=s&xTirDAmeHryEVM
zwKBB!YXX!K8cd>B&qw&7Jsz;(Kz?xbFQ37_NaIV(XXEYjTf{%Z?x~Q;
zb4(%jtj@zGi-z*tAl$6G6F_)ELIgZ`&`l@2e=XD~Kw%)Igw@=#p%=Gr+<`S!4@fr|
zP*jA)x`fwGYsI_HnJ#gKxk|EDz{HxLO;;x2fjtp2^QI)yIO;Nbz_y5FuvIs(3N(K4LZ
zVrnR^cEb0u10|;S^?}7rbFoKFOuqG0gF;L!xSAonPDNUiRJ2OROcFYIB7!ajP}!V_
znYD~@VHExz+YkKf1FP|n-+~~;>VyXj^h*o-N>#zdbEo2s%O;3?&)DJ$H%S&kr)08x
zZ7Y8D73frCx2J?<5osrWcY@;xg|^s
z+oys3KJep>JMo=ox^S|e!MEPBM6z;PJueye;n_`IhCL=Dx>@^43rNQF7!7Bb!UEmo
zqgQE7hhhDN9u~m
zZO#;&KfeRZn+-4=J6#z8V)-C1zO06FRD<@Ix^W+()4*Kan$MWqq79j;CLkIpm5|Mw
z#)**qwqeS&ih69^D?#xW+L>(+GPC6-z%yc|Z5eX%`rrS44W8NMV|iOUZoGJglpkp6
z^aPRHYR6_9rU;2V!~x*|IFwr&WF9ecF(9ljQFmovN?cj4Od8ld|u)oyKcBj
zm@PBdvn}*DyMZ6AT90SQz|yTIw$MLu-3R@cQ|rgdMjvO-o{p7sJ1{F-?+$c3tK1s1
zsZd;-=5)Gs;u1+Gv2d7tzxmf~@*z!TiIi`2`7lLGzQU=#PTny&1+^wu>*oP0H{SUW
zs--quvTzapd_`LF83PDWu+|m%F&{Y?h{JKHWJnnj?7vFt;JNjBC1Ch+P+%RbV4TFk(
zA^$rL_%`RD#AFweD+{<8S6VZLbG>#hj1ES!T&lDvxQAC&Atom83-zz^za9
z;_yC|lyKlrdFTFkOepL1SiX3nu3?nAYAR<D61&3f{?6~|)>
zP@0*GeQ8ob8tUs}f)oG2wBd_mvMrSk7@Gg~0C;pu0S~;e4O>FsSs^@Zv|{r@&NyER
zZ`^^!tI*dIunH4SEt2H3YoQGCbHemU!q7r<1ipIyzo+=_Ii-*+=P|zhbsJz)|
zBeUlc6l-1e%7xg}K6s);{Pi8{@N5)eW>CS+Z$AUmt*bJcfxCwB{@U#0I)rtM4VJM1
zl1Ri%)@*WMm(GjVKD>1sa~)G3Ca<
zE*ZO<)!`;OP=denK1D=yhXz>riI(OpiK6EBHdOG%=e7X3HbV%?C4BablklM#z)U%_
zz`*WFyGkfDS2BJQ2;281&MJ{6u$7gih5vc?3wW%S#>Ak6FJE>F&XG=)02u@bkP|?%
zlKhZ-Ft1?+w4T=-%(6xXLh{vP1cVwC6+<4YVO@jxEzy!qc9S;3zDtBeEOaJgeU>ZW
z4U*c~oTg1T2wm0ncW=g{Q3lAfi7x_*J^21bvv7G6&=!y(Gj355rv>oyouFu_E_Xf1
zVsM1Z1NJE37u~?uf4>2tpTaq9S^V$Uoh$?)E7g0lMFR-;gcv!RwAYiSi=>+!Jp_Z_
zNkBwg9Nh&S4Rp~UsqZIuuLyM0>pckn_GqH;Ku2
zQCyS*ibr|Ku$x^2i21F~%;W!ZK*VU+)MrpNkZC0+(*Q!Iv>z$#Bptnf6YeT1Ak$)Y
z$EXmm3-;q1moJg+1vy%hG8U4R<_fbt*cNL|o+%oC1!*sXPF1)$r1$J|w?B!_Y9l83z?a{;NV-a-GRTebB6;wNnV9g(
zI9=V}9auV!0ffhKj13TpmKI#w@;j)GlrU*G?j+-KfEa2?K11$o_B}9mP+PiXC-9ZW
z)}xb2BBhrMH{cZU-iaA}>f9-It2ASo5$!#<+0ga})9(0umb-@8GODsdbHBZ%7r%IN
zBc=suTyx$ETsqSw=YBMA35tALq<)TmW$`)yWAT#2SW*3qx*(
zq`*`-IA3Y_ktYco8}>+bzx-4I-`~E+$Sfi=Q=}~6ua?fhHS@A|M-)puwv*WPJF-?_-S-0g=Y@*bA9~ICs7O({&aE&-v8=ZVi~zmqs3lCK
zp_Qy%?!kzbN7DaB>dD3oh@-vr6vWN;p_Y)1D9M)y2VnR%H8a+^Q<2G_3(83PAAN8S
ze%BWOd5R#B974deHvZSrS$NNEU))Sn(jN}-naoI(P+(vBtr(O3Y1NDP#Y_9KIGe@|
z7cIf5S*zw&fks?I?m6AqN&f}%!pdz-K
zQt
zAj})MU+}`8t;6=VlO=A5m2h83wSXI!&cVCp1KgO}AfCgpG;?NJf^fX;rh!KNhOehTyhuJ17`iNSwQa8VK@5v
zb)CB&4>05-4{EkP5nmVK0I``gr-gt}3*__@kW+5m1mq?Ip376XU9BH~xo{#rxVT9s
zRgT4Aeh{bpW}VUa2rOL{t?lbSx(`#DC*lKFE)#ZUx0DX<85`3I8}*yxuge%@Yom2r
zqaKDVLK7t!F!_)eVuQL^$ZZ=?;%+Y46i?*Lu^9htGHLI0*+1AyjwShl?FF_W#Hq%V
z{BOEv754QN@a{Lg4ktAl5SjA14gX`hhcUi6c^u#g1;kYHjdO4Zi@Cx#6LSLc`a9O4
zlTIncYN6SONZR|ROc`H#!yH-Z+*cmAz}f_r*5OV8dSc6dJh*BV-u%XkvDlvcAXWY#
zKtqaqt4{3WNPt|+7T)7EJceM36ck;AZL+V}Qh!S0bTj|sk1ykQ0~89`?sV>t(ihgp)WTMfVnL2ZZ&pg?QpLG_26nAp5zG8ZbPeKJhykeddl3FBJ@Wo@f
z#x>$f!us#`K8iD6^(stkF)^c=2lQ3S2(yj#MDKX5z(ah_(9=r~1&HgGIp)K3fUtFk
z-8JT@JflNVs-VR2FE18x!D)N;
z>mqRNy=#En3{zjEOdnAE13q)w6kI<8m~2H(;%Sr~YsXuL8ERSL#_yM$S%3HVOZd)SQrZTSN^@wn086q}-2VEh!nD%X(K7F#E2L;H-MrH8Z;pSH
z9F5tbwm;7
zxL8RN5W6Eve7jxTZrk%mf4v@$g$?!`Ek@}GD0Jc*E2ra~vsxu%XS}bbOdOH8WPz1p
zArpK%YjS>7#E{OUly#Qln~5ChT==5_GMh&bju8Eky?h8DMn$z}yT5K^%V^ZEKH9e?3`;jYZmx?HX19o${p`l^?27>I{k!R@
z0epQkx6SeFtg>n5E%xDtl}mB$424N@3LIlYO|}>)x093^yl2`=2?#3~tYaAMYt(Z)
z;x`@*3`aPQdSQO^nmxbksIMK#3!JyIwZufPtgFVE^O>q?PjZrH55$$fzVjvgk*8_P
zLB>3fv4YE6v-sOrPsKFNb4bX*O7>)J%Mj#F9UMkAGv~G+*LXgTM~xdAOhw$Df;^IG
zKm2PA+cjF2+3iGV5&@PkpwCJH6dU(gbwV`4gFPb!BQ
zqTlzi{=nk+!ml^r*O8ntZDjdUH$E{lhmWi<+Y)Fz?h-uP#B?*7W(D_sBE~9N6OZk4
zoH3|hZaA*Wy?R7|9E%_ydkyI>=fkX6X;^oS9Xwz;>!S!?6yS$@fsg+BITTx_8U?s1
zg|qv%;vcVC3DQD-=`Q=c9rcx33G)`7NaT?y7#Q5H$`Mb(2%sAY7{iVsLqC69EhV;w
zdebcr^mp)Z3#9p~qAI#eRYZ-=B0ApmXg7Yaa{vYDgs%d%J@~&%X5rd}4U&_v`@X@G
z1DEWEV)I>DCLb}CaMxXbtNbASv`AB^!KL
zBmd%^>v31A!yE{l3UPWgfdBvIMe;%*@uWJSyJ>nBh1>qm%6P=cRI$uYT+pO%d__wNMW|L6wPxJ7}FY61W6thu;+
zx;w{Z3zI`&k_w?*cOk_r_WIi2<(kKU_KpRNaRFq^
zpv0NFIlx99${dOrZ^_`{*5*uE!=ECJK&8;HJlPlj#RsInGS-RrQesxi}3xO~oJynDq&X`*8`
zOQ?dHIVxS4mqUB(>ie*hzTvRtaabFJKV~E{OI_%7*|a;?>un@2
z9?5HmldB8{B%#AQ2_>1a+oj{gN3(^&?AI#s+pi#g5bxE}=?SK#+`74h->qJQHXY)+
zx1EnAX?rT1SV`DIQgWKUVJP
zP>38?KoY>zoAE3HhX=$uwfHF3!9h5zX{a=bZ6IGT!?RWTZ3__(R(s&N-B`E!30!g3
z*?9Gm3Gw0i>`IBEDl$BT;LuV1peDBQw1mT5>x2N30A^4x@xk8d5dLb&oz(Yfng60>
z$Px+v|~J0?|a2q$kA@lo;Yzw@)(d|
o0@7Oqu4q^4_ecATSHj=_6Uhr_l&FPM#sB~S07*qoM6N<$f_s%na%$?b=yH>5*X|0`pYwar1C}{>@(%0701|Sds
zcm)0dq*)+PE7a{402mqq5&!^D1LP1MfC8kzB!C*^4cKcfO>t6yO8-%59ow>$uC&q&dbuJq-=JtER@-q+WYj0pg|yaWAB
zbuJ5Bx3m(VS_WIg0kDFR+1@e0SN-bME5~L2bNyZZpP#+q-)#p5rH;$`!~UNmn4O#h
z96{l)g2^460vx?Sx)K1$vmAZ>0|9{Ym@gC(=zC0q5n%HN8wk>I$F$2|bk;HL@E865
zcbaRa8ep1MuuJIe?fqQ<;6xwD7YKHA0n0dn0qJwzPHx@+z$gIHYF=JGP9S{~q{YEB
zz94;EzLLYgmE-bnw7tE6(Kyn4XN+F+c;Pov}hKIS{za?{oWX(o^kbqmzH2GU$09p@aNW%hTP9Dg6vzw08a
zzU8l>{x`qV-XEm?s%t99!~B?kT>h4;v)%{wG$;!+_?Ex+vFyj`6TAXI>bLCB99K8J
z)lSZuS|AO|4qbNk
zHb0j4xE!2s;N|1Gz`W$NzMjA52FNEDboSIa<_m(fTtKkd-+9R`0{yQY^TBqK-|`K-
zdaOgRo#f%}_WD;r8f*{wBj5_40cZjOKoA%m03W~|aQn7ivku<<^+X%62mApSz!{MG
zoAXZP28G;IA1F4r~D4V48qG`7Zx{>I?*fe8L~@UwNf~Tfd(M|IXn7`~++80t^68
z@IDBnoxwc+)Mf!JfE>3!_y5#x50>c&w$~Gk$It(J{y*G*rBnyyz4CY7pnqx=(B`
zY5tM-pB_IR9|7lzj!p|5Zw$b7&wqo&gOX-!OkS7uP@mb#O;;7SQu{JbOk!=A4Wi
z037cx$7ujy+vNAY0pa-iFW$Xr0Jw-Ikw~BZ#nVRvK)E6~{XhPTC$0nl%yaL3v~V1waM31ZV;JfH80lumo(u@#+eWbAKQNhy?Bc
z4}e5)2Yw1<0@*+w@D?ZqJ^(d9JLq0;9AYG7t$QWc6
zvI5zH9FjrF=*if~_{c=bq{)=X)X5CUu94j!b0PC13n#lz_K@ru*=w>AvTCv>vTm{=
zvKg{9vRxB}`G1Llr3+fMzh9*GMp|7E3&^oZ62ca|2b?5;(B{?g(
z0J#)6f_2Hw$sNi4$fL=V$TP{`l2?~Ix
zQ@o+5qG$u>(jvtkB_$;Xr5L3mI2SD`-6 | |