文档目录

并行提问

基于 Wikipedia 上的 GDPR 词条运行一个 13 问题的合规简报,结果显示把所有问题批量放进一次 TypeSafe 调用既便宜 12.2 倍又快 10.0 倍,且答案完全一致。

非官方中文翻译 · 内容以 英文原文 ↗ 为准 · 同步于 2026-10-15

你有一份文档和关于它的 N 个问题。你可以发一个请求带上全部 N 个问题,也可以发 N 个请求,每个请求只带一个问题。使用 TypeSafe 时,两种方式得到的答案都一样:每个问题各自针对文档独立打分,所以其答案不依赖于请求里还有什么其他内容。

为了验证这一点,本实战示例(cookbook)在两种方式下都把每个问题问多次——一种是全部 N 个合在一个请求里,另一种是每个请求只问一个问题——并比较相邻两次重复之间的标准差:也就是从一个重复到下一个,答案的变动幅度。一个问题无论具有怎样的噪声,在两种批量策略下都具有同样的噪声。批量并不会新增噪声。两种方式下,大多数答案在 5 次重复中返回值完全一致——每次调用都得到同一个数值,标准差恰好为 0.0。

成本和速度确实会变。文档在每次请求中都占大头。N 次单题调用要付 N 次文档费用,外加 N 次往返;而批量调用只需付一次。文档越大,这笔节省就越接近完整的 N 倍。

本例是一个合规简报场景。文档是 Wikipedia 上的 GDPR 词条(约 54,000 字符,属于文档主导型负载,文档构成每次请求的绝大部分),合规团队要核查 13 个事项:8 个 Noul 问题、2 个 Choice 问题,以及 3 个 Score 问题。

环境准备

bash
pip install ipython 'cooksafe>=0.2.0,<0.3.0'

然后设置环境变量 TYPESAFE_API_KEY。

python
import json
import os
import urllib.request
from pathlib import Path
from statistics import mean, stdev
from time import perf_counter

from cooksafe import JsonCache, make_playground_link
from IPython.display import Markdown, display
from typesafe_sdk import Choice, ChoiceAnswer, Noul, NoulAnswer, Score, TypeSafeClient

TYPESAFE_MODEL = "jev-1.12"
PRICE = (
    0.042,
    0.00,
)  # $ per 1M tokens (input, output); TypeSafe jev-1.12 as of 2026-09, see README
RUNS = 5  # repeats per batching strategy, to estimate each answer's run-to-run std dev
client = TypeSafeClient(api_key=os.environ["TYPESAFE_API_KEY"], timeout=120.0)
json_cache = JsonCache(Path("json_cache.json"))

文档:Wikipedia 上的 GDPR 词条

以纯文本形式从该词条的一个固定版本拉取,并和 API 调用一起缓存到 json_cache.json 中。这样即便线上词条被编辑,文档及其数值也保持不变。

python
WIKIPEDIA_REVISION = 1363040264  # "General Data Protection Regulation", as of 2026-07


@json_cache
def fetch_article(revision_id: int) -> str:
    url = (
        "https://en.wikipedia.org/w/api.php?action=query&format=json"
        f"&prop=extracts&explaintext=1&revids={revision_id}"
    )
    request = urllib.request.Request(
        url, headers={"User-Agent": "typesafe-cookbook/1.0"}
    )
    with urllib.request.urlopen(request) as response:
        pages = json.loads(response.read())["query"]["pages"]
    return next(iter(pages.values()))["extract"]


DOCUMENT = {
    "source": f"https://en.wikipedia.org/?oldid={WIKIPEDIA_REVISION}",
    "text": fetch_article(WIKIPEDIA_REVISION),
}
print(f"{len(DOCUMENT['text']):,} characters")
display(Markdown(f"📄 [Read the pinned Wikipedia revision]({DOCUMENT['source']})"))
text
53,777 characters

📄 阅读固定的 Wikipedia 版本

问题集合:8 个 noul 题 + 2 个 choice 题 + 3 个 score 题

每个答案按题型追踪一个数值:

  • Noul:「yes」的概率。
  • Choice:最大概率(max prob),即被选中标签的概率。criteria 把每个标签映射到其含义。
  • Score:归一化到 0-1 的得分(normalized score),即原始分数除以最高档位。criteria 列出从档位 0 开始的各档位描述。
python
QUESTIONS = {
    "breach_72h": Noul(
        instructions="Must a personal data breach be reported to the supervisory authority within 72 hours?"
    ),
    "applies_non_eu": Noul(
        instructions="Does the regulation apply to organisations established outside the EU that offer goods or services to people in the EU?"
    ),
    "dpo_all_orgs": Noul(
        instructions="Must every organisation appoint a Data Protection Officer, regardless of what data it processes?"
    ),
    "pre_ticked_consent": Noul(
        instructions="Can valid consent be obtained through pre-ticked boxes or inactivity?"
    ),
    "right_erasure": Noul(
        instructions="Does the regulation grant individuals a right to erasure of their personal data?"
    ),
    "data_portability": Noul(
        instructions="Does the regulation include a right to data portability?"
    ),
    "us_federal_law": Noul(instructions="Is the GDPR a United States federal law?"),
    "criminal_penalties": Noul(
        instructions="Does the GDPR itself impose criminal penalties such as imprisonment?"
    ),
    "instrument_type": Choice(
        instructions="What kind of EU legal instrument is the GDPR?",
        criteria={
            "Regulation": "Directly binding law in all member states, no national implementation needed.",
            "Directive": "Sets goals that member states implement through national law.",
            "Treaty": "An international treaty between states.",
            "Recommendation": "Non-binding guidance.",
        },
    ),
    "max_fine": Choice(
        instructions="What is the maximum administrative fine for the most serious infringements?",
        criteria={
            "TwentyM_or_4pct": "Up to EUR 20 million or 4% of annual worldwide turnover, whichever is greater.",
            "TenM_or_2pct": "Up to EUR 10 million or 2% of annual worldwide turnover, whichever is greater.",
            "FixedCap": "A fixed amount not tied to turnover.",
            "NoFines": "The GDPR provides no administrative fines.",
        },
    ),
    "individual_rights": Score(
        instructions="How strong are the rights the GDPR grants to individuals over their data?",
        criteria=[
            "None: individuals get no rights over their data.",
            "Weak: a right to be informed, but little control.",
            "Moderate: access and correction rights, but limited means to act on them.",
            "Strong: access, erasure, portability, and objection rights, with enforcement behind them.",
        ],
    ),
    "penalty_severity": Score(
        instructions="How severe are the penalties the GDPR provides for non-compliance?",
        criteria=[
            "None: no penalties of any kind.",
            "Symbolic: small fixed fines unlikely to change behavior.",
            "Substantial: fines large enough to matter to most companies.",
            "Severe: fines scaled to global revenue, material even to the largest companies.",
        ],
    ),
    "compliance_burden": Score(
        instructions="How heavy is the compliance burden the GDPR places on organisations?",
        criteria=[
            "Negligible: no meaningful obligations.",
            "Light: a few notices and disclosures.",
            "Moderate: documented processes and some dedicated roles for larger processors.",
            "Heavy: records, impact assessments, officers, and breach procedures for many organisations.",
            "Extreme: obligations so demanding that ordinary organisations cannot fully comply.",
        ],
    ),
}
N = len(QUESTIONS)
METRIC = {  # question type -> the one number we track per answer
    Noul: "p(yes)",
    Choice: "max prob",
    Score: "normalized score",
}

两种方式各问 5 次

ask() 把任意子集的问题连同文档一起发送,并将每个答案归约为其唯一被追踪的数值。每次调用中的文档都完全一致。

两种批量策略各跑 RUNS = 5 次,每个问题在每种策略下都得到 5 个答案,足以比较均值(两种方式结果一致吗?)和标准差(批量会增加噪声吗?)。调用结果都缓存到 json_cache.json 中,该文件随实战示例一起发布,所以重新渲染是免费的;删除该文件后即可重新实时运行。

python
@json_cache
def ask(keys: tuple[str, ...], run: int):
    """One TypeSafe call -> ({key: tracked metric}, input_tokens, output_tokens, latency_s);
    ``run`` only forces a distinct live call per repeat."""
    started = perf_counter()
    response = client.system_one(
        state={"article": DOCUMENT},
        questions={key: QUESTIONS[key] for key in keys},
        model=TYPESAFE_MODEL,
    )
    values = {}
    for key in keys:
        answer = response.answers[key]
        if isinstance(answer, NoulAnswer):
            values[key] = answer.noul
        elif isinstance(answer, ChoiceAnswer):
            values[key] = max(answer.probabilities.values())
        else:
            values[key] = answer.score / (len(QUESTIONS[key].criteria) - 1)
    return (
        values,
        response.usage.input_tokens,
        response.usage.output_tokens,
        perf_counter() - started,
    )


def priced(result):
    """({key: metric}, in_tokens, out_tokens, latency) -> ({key: metric}, cost_usd, latency)."""
    values, input_tokens, output_tokens, latency = result
    return values, input_tokens / 1e6 * PRICE[0] + output_tokens / 1e6 * PRICE[1], latency


# Price after cache retrieval, so a price change needs no new calls.
batched = [
    priced(ask(tuple(QUESTIONS), run)) for run in range(RUNS)
]  # all N in one call, x RUNS
singles = [
    {key: priced(ask((key,), run)) for key in QUESTIONS} for run in range(RUNS)
]  # N x 1, x RUNS

批处理不会改变答案

每个问题:在每种批处理策略下,其跟踪指标在 5 次重复中的均值和标准差。如果批处理改变了答案,那么批处理列就会与单次列不同。均值偏移意味着偏差,标准差变大意味着噪声。

python
print(
    f"{'question':<22}{'metric':<18}{'batched mean':>13}{'single mean':>12}"
    f"{'batched std':>13}{'single std':>12}"
)
for key, question in QUESTIONS.items():
    batched_values = [values[key] for values, _cost, _latency in batched]
    single_values = [singles[run][key][0][key] for run in range(RUNS)]
    print(
        f"{key:<22}{METRIC[type(question)]:<18}{mean(batched_values):>13.3f}"
        f"{mean(single_values):>12.3f}{stdev(batched_values):>13.4f}{stdev(single_values):>12.4f}"
    )
text
question              metric             batched mean single mean  batched std  single std
breach_72h            p(yes)                    0.804       0.814       0.0055      0.0055
applies_non_eu        p(yes)                    0.990       0.990       0.0000      0.0000
dpo_all_orgs          p(yes)                    0.030       0.030       0.0000      0.0000
pre_ticked_consent    p(yes)                    0.040       0.040       0.0000      0.0000
right_erasure         p(yes)                    0.990       0.990       0.0000      0.0000
data_portability      p(yes)                    0.990       0.990       0.0000      0.0000
us_federal_law        p(yes)                    0.010       0.010       0.0000      0.0000
criminal_penalties    p(yes)                    0.108       0.108       0.0045      0.0084
instrument_type       max prob                  1.000       1.000       0.0000      0.0000
max_fine              max prob                  1.000       1.000       0.0000      0.0000
individual_rights     normalized score          1.000       1.000       0.0000      0.0000
penalty_severity      normalized score          1.000       1.000       0.0000      0.0000
compliance_burden     normalized score          0.750       0.750       0.0000      0.0000

按题型阅读这张表:

  • Choice(选择题)、Score(打分题)以及 8 道 Noul(是非题)中的 6 道,在 5 次重复中得到的答案完全一致:两种批处理策略下的标准差都恰好为 0.0,每次批处理调用和单次调用返回的都是同一个数字。一次性传入 N 个问题,与每次传入一个问题共 N 次调用,得到的答案相同。
  • breach_72h 和 criminal_penalties 带有一点逐次运行的采样噪声,且这种噪声在两种批处理策略下的规模相同,均值的差异也在该噪声范围内。噪声是问题本身的属性,而不是批处理方式的属性:批处理既不会偏移答案,也不会带来额外的方差。

无论怎么看,都不存在批处理效应:没有任何问题的答案依赖于与其共享同一请求的其他 12 个问题。

唯一的区别:成本和速度

答案相同,账单不同。那篇约 54,000 字符的文章主导了每一次请求,因此:

  • 成本:13 次单问题调用会重复发送这篇文章 13 次;批处理调用只发送一次。无论你如何发起调用,这种节省都成立。
  • 速度:图中汇总了 13 次单次调用的延迟,因此假设它们按顺序执行。如果改为并发执行,差距会缩小,但 13 倍的 token 成本不会变。

token 计数和延迟与答案一起被缓存;成本在之后才被施加,两者都取 5 次运行的平均值。

python
batched_cost = mean(cost for _values, cost, _latency in batched)
batched_latency = mean(latency for _values, _cost, latency in batched)
singles_cost = mean(
    sum(singles[run][key][1] for key in QUESTIONS) for run in range(RUNS)
)
singles_latency = mean(
    sum(singles[run][key][2] for key in QUESTIONS) for run in range(RUNS)
)
print(f"{'batching':<24}{'calls':>6}{'cost':>12}{'total time':>12}")
print(
    f"{f'one call, all {N}':<24}{1:>6}{'$' + format(batched_cost, '.6f'):>12}{format(batched_latency, '.2f') + 's':>12}"
)
print(
    f"{f'{N} calls, one each':<24}{N:>6}{'$' + format(singles_cost, '.6f'):>12}{format(singles_latency, '.2f') + 's':>12}"
)
print(
    f"\nbatching: {singles_cost / batched_cost:.1f}x cheaper, {singles_latency / batched_latency:.1f}x faster"
)
text
batching                 calls        cost  total time
one call, all 13             1   $0.000497       0.27s
13 calls, one each          13   $0.006090       2.71s

batching: 12.2x cheaper, 10.0x faster

在 TypeSafe playground 中打开

同一篇文章和同样的 13 个问题,打包成一个分享链接。打开它即可在线重新运行这场简报,会得到与之前相同的数字。

python
playground_link = make_playground_link(
    {"article": DOCUMENT}, QUESTIONS, models=[TYPESAFE_MODEL]
)
display(
    Markdown(
        f"🔗 [Open this article + questions in the TypeSafe playground]({playground_link})"
    )
)

🔗 [在 TypeSafe playground 中打开这篇文章和问题 →](https://console.typesafe.ai/playground#share/N4IgJg9gxgrgtgUwHYBcAqCAeKQC4AEIwAOiAIYBOKAllADYKkEkgDOEMFUje+pAFihQAHVrgD045ADoA7tQDW1YQjDUy0iBQDm4gPwQ6asAF4AjAGYAbBYAMAFlsAmK-dIAaPiBRYUTL2j8CPgA4sgIFGR0+AAiZChk+AAKFBA+UDQQSPgASgjaMHTx1Fn4ABR5BUWZ2WUAogCqAJT4TrZmVuJWAOwAnE2eZABGQxQIAG7qPmChMUk5ntSs+Il1nBAqZNkNSCXZY1XFpaXUSABmWnBH2cIU1ONkUACe+Kf4KEH4a6mb27ul9WaKyQMw+wW+GwQWy+UCyEDgtHwAEExol6nUkU1pPhAsEQnMcq9ltDqHBhFoEqh8LCyVlkCh8BAzl8GvhbvdHi8irJgTN+PBoXdtIJltzFjdKDRYEUKMiqLQGPgABxlMwtJnvT4AYX4koijOZADEYCCyIhUFFctRhShlhqwV91r98Ds9tiAJIMqLsfDaCDjCJIZYOlCRINnfUalQUdhIS1geKJDi26hgYIOxq8r4Y7G42bzADkyz93pWY3eEHwyF1SG4rxB91TMG9BepWVDhizQpFjIDsrB1Fl0djltOFwoVxqWZQldYpOEdGoZxeDoOhWuy3H9Z8FDjNUtQxgc6QCFYrA9DNYMGHqlPmuCcQSyVS6SnMUHCAy92CvQArOJ7E6OotV5QY4CybRGTBft+FObRWE8OcyUXM5qDvEMIgRJBDAgbQnmkYhiCQPMIWdJJKEXM16SzLUOFrahontT5SKhP49hWSBhGme980JUozHsZF2WiNoOk8Gd8CGT94WCBAzgjL8A0ZbInF-fAAFkyBeUSlWxJFiWyTM12qdiylOVgfDIGYNUSNQxkUhABh4-F5nwXVljsz8GQYbRLTksh739DQvRBfBIDvbCGTGABHGAP3eMNWHJOcp1OCS9z2S1uWxAAJCBZAmCJFi9OgfVuf1UzvM4GEwaghgY6gUBeLdTjUSYwGbaJEDgKTZQs+J0MrcC1GXco01NnN3KfHwM5UjgFp2EQA1XltNlUkmOcsnPQikH04Eq0wM0F2CJjggAIQoI9WAQIqq3krzxM+Yzrkkz8qJWfABouiatFerYXjSIJZW5YlUhNUFPlkLQjHFegYDUJBILeE6yAALwYzwACkyGELZPAAZTgjGtAQHHk34ZFJtoMgiZgD58AAaQJin8Gxu58AAGS2BQGa2GZAjIBiub0s4d3wBgyEmWGeJY6FXSyW7gldbiabgyA4CrOMMlUBblkI0gGhp3jtZARY01Qcnogkh0XJyXNtSiJctF2RJaKDeB9RSDlnmRDJyi1LUkkxQZOO40onCVfBUZNYIdM8dyvqQF4kL5u4aDveRqYtgkCKIjaNpMEx8CdnxUGWXONrzS3WnaKw3LIZYLry7IoF1LiIgQtta0DODfXCSJohKla9lb9l6P21vu0Ww7gsTfAryGAArG7gqptC7WZBMn1hVBUjoBgY0ZIdUm4M8tFb0MtlYCNd6jFusnjKfzdgigwAAWkxqgXlhE1Q2XxDrwiFatBeGQKm-AtB1W-m2SEkQpxmggq9BAnV9Q9R8KPeBqhwGURqoueqe82TICiMnTcn1RhQkbvNMeg9lpLAHvgMY1QNYSXip+JciISqH2PJBRKzYaity5q9JY3Bt5bAQBwTcpxLR9yoWta2eICQrCKpWDeCRzL4DMN0CwNCmEJEusITgCV6EKJlEueOsIVBdmuFEYIW5Vz5HXDOCgLwJGrSDIMZYuVt4rGWHVUU+QlgmSUslekyxADIBLkTRlp7CeEakGSk3BPBSW0MooY8ctKdw+PEHirDTzsPmsOG+0Q16JFYCAwoMwpJ8EIuAU81oTyglnH-YIVwkBKBBAbTOSBs5EVznnMIJ4e5LVKk44uJciJ5nutA4QC5l6vGZA6ApbcOzb3yjgzJR8KCeE+rMqeM955ezKLkpALQliSRrhrN4GYGjSI0YcaB8iVgTMXH1PevldisA3Mc861kqZzjTBLVkS57zv0MAwL2n0VnLH2bfJ8GomqNlaqWOg0BeozHMmVX5lyxnsRCssMKdyFwrkrA6MFncNRzKSUtDk419ngsoWmEG6TCW6IgOdau2KFFZBPF+UoElEglQjGeNKjFZQ0kQFwdQ0RHg0EmPVTOpByh5CgHVS0ZglRYg2kiKAsJH6pIJcxJ0rF87wgRPymW5TSBJGvnGfJU8jljkuA9NJ4ULq9WDJWEkxsaCoQ1p9MqJtULDEVDClqbUPTMieBwakWwcWeQyHQF4PqPWAOyIGpslpJrwk1Ok21E5riy2yGGmA+ATz6Lbt8-UsggjQR4smuF0QjkWQYrW91zD-UIGxAATXDUUjgRh3hkAUMEZKrqNV0QZA6LNk52L5rLMEIl4sZzaAQJW1OJMohm0+IgM+Gia43yGLG4WigLr4sevgI8GsyUIDqn9fAU7PrfSgle-ZFZXhNqGg6+szUU10BlSAHEnxbhMOZWmVCuxuHzR3HAZYV5SE11NSACFVqEgG08AbWd2gkOwbmdsry6GDaKK3jvdDvCUMHyyVoA207p4JG4m8FEUpFT2DaaMmxJlShYsLWkNkjKqBPoxnip9hKSP8vFlfGMeTJ5Pi3KlMT51YBJ0AYpMBd5PrclVuObg5oGQT0aAAbjcjlPKaz31HlDC8bQQNRBt24LuDWwxkwTUeJ3HlaR6RirbhVWgmnmQA2rkpKKp4aga3LYuq9tGFTBHsKHD+PaymnHGBAfttTp4IAQAoJ9-6AxUlslPPDQLEEwDnl5HjmpBwzA-pvJ4RZhZkFkJuKabZkJPE7sul6PlLRaBGhNOrb6ysmcqyp5AanUGoE8LPaGtAxXrNlFJy1SXZN1UAcA0BBCn1qFYPQJl6ZZwwGg4tpOUzCUWshUmZk0JMz7M8AcSgYAGBnnmkFytmynxjFLZ47In07NaYuXKOj4XQ5IPQrqQKLxRtgAXRp+aiQP7cY2XcQ8M3eF3rTAqpxEPshWSwksU+krghAI+Etn6J3iuPzbJ-exGioqDkc-M-DkZ97Q-100iOHrINP99PjiUEpqp4OUWXP8g+F3AZldC6eU-jQiyd0Uf+a2WxJcGaYvkHALgBrEwxVl08Hg8CONHWzQwcNtwadqupmCJ9vwe6V5BGDB6tSN5IWpZDikYEIpoY9muvNHEMDP9Zkn4PTVOH7R2tjhtjNEkkHOiYK44pG9iDcPVRRVtU-E9eegpG3YK+xueWNRet-JAqMtd8KUtksuAfMhZb-fdiugK4s1XBGiK8HzWSXZZI04tHHEIFhxUxi021NTYiCFXutqSDoeujZC5r7gQ+nG0yJCLRzY0NcleWKnGQkIaqpFi6H-k+C2BYKxtWQOxUiH7nT8VCRyTTd1vCW99yepVEaMK1AQJIrlT4OgergyYJJ9WmpFbd1ku0h1vWLcT9njmpIrNL8jArQBXl03ab2IvWy5OXFLXRLTRn2gVJVSmamRbpxdRcl1rZ2lBetv3aef2i4h55KAvUPdJQL-TDbIAo21Nr0I1ZqpXWU-PaCeNp4q6YdD-aNRWH7QvIc0GO0hLjV9x4r9uxQfprilSCUEA+Fa87VDsdQaCpSRXR4HeFqqJQ8CcyScbH191gIlIM8etFwWQQXY5I7le7S6lN0P4HFzKniDOHj39VsIO0L+JrNkqfQhqCKRVPqwz7EpZQ5493LLApUIoeQW4dDXm2nnskCOQ4JpjhP7j6stwItBHJaieBShW6Se4PZXlEEnBlgMu1cqmGNi5hUhZuqcBw1H4A7q87wQWgdH+jIBtA1MEJQzAklILM+0UqjnKTxZkpWsHsW1va3ynC6iNwwE5AfNFqQlsRIezbNKVo7L6V0LC+fewOIY+hudRuUhBGFyhCoexVMLfM9jS099nd8FbEvISBV5iU8hlLnHYRcGwVIgunAVHulR3ab1tCQNpENowWq6FtxuvRZNKfjVgO5c6JddhARR4Q4CWa4VGhOLTw1tskigtYzvxFWZWxgarMCKokhBA6AYA0yfpP0WX5EAi6e8HoPLXvyB+zEt5JYq0StAaFWk03vKnazC1dlCiu8BNrHHRUn0r3OwOiPkM5JFDkqN2TauPRBFwpJnY2nfzA0PRJwRVYTIDQ1AXBqh8gHfknCQpkB5+xvCWR8Q4LlcT6qkWwLgg2AMAqKMSyosqxM1KZqSRyfXIdSW6nb0hL0AtV6v7ZLMjpBPf1WnQ+m2hAjKi4I+O0ZAaoa4AqKirRP+5ZtIM+tS0Mi3yCgIz5dzLNTkuLQ0Y7hvQA0aCniVPYnU-ap9M+2bwHSsgDm0DLwlX6aa7wieGPYlgaMu8zAkXDaNjEQViztGGchpCgwrYmHKCz4kdPYni1RV-17iGLP3LRqWtEQYlBVQQq5kZJ9FoEZqVcR1XOEsGdLJgZVhJEXqtAGjP-M9npDFAmGcUsEj-SApRUVgDwPmKItnpFEQCC2V2RwosHts2kchx+CZTME7r7y7YPGbuonh2GK9yFUPjUFcMbQHQcYOaO2SRNexOWvMS6GYoJFcwb27fMfrqoYB0tRC4hJgXcfMUkUs1-6Nah8f4Ibz1VzXTVRQEyMzpPJZ8oI+wioq2RTwz7fTUpTyq9Rel1R9I0dKRYymqjwtVo2QH5MRoUWypjmTaTQgUcJIUrDJKqf6oxt3+99HYyJ34TWSXiKy8WPZGUC6nFofm1afkLSnQ8pxZhifQPCorX9z8NJpJoa0vi08jTeS7WsTnhJh41cO4d04IU9MmpUFtQ39sixbM5jnT6xn6LKEelb4PTRup5iCDsFHtge9oAM7UdGMf0aRMmLIDMBnj54zMGMEmBqFe72AmjaoQVZIxx5g6rw+eo-GQAjAFArsrAb033wSj1taTPEZACtCtGghE6FXRaKhtq6QqU1S4UaVXyVNosA1iYQc+32HNFNmGwvZLvknFN3BJTIM9IMutNhZhszOI6TDxrkxIL95SZUs8yx1HBBva73aE9JFhM6Hdyn0BEz0YtCal3EqJoFDUPFj96kA2JoiLieegEmLQRJxdCSeJ4GTCR353eAMeZCxDmTDhKSMYtMXMh19wp71MSC-BdULjPp6kzcdHNkmNJDx2fQZJeNsn3j2OECZDr0UVqaefTCIOqYqOymFDcimARotM0fZDFOFhCpQSYGbmrjw1FtOJGLNxKtuw+IrKGdKxpmIzbprMzGZzNxnijahsdCOyTOqi7xqZ0nOmbUtfank5hxLvmaQKFmZkslkYyyLGPlnpIfA-LDWciDCB6zp7O4U2fe6ywNokARwYxeTOdm1C3Z3s82FhMSWa8ZC0c4kD3N9Ic8EpsHRhEbgrrxUQUS81vkBK3nBFATey7kugp0bLV+ogxjIeMbca5sHCoM-JelI3DdJbDI6QZJVM1X8yfVHRLEfWIO6NgAI8aKebSsXmNLiMLfLlceRAbHRn1bk6UDnEjxsQR0I8I0RbXPEL9NYaWpcu26Gdq1rY3hIeAYiF0JVDQkaITTOOnzGrFDaeD2ZsT9nQmDFOZGUFQ1I7Rz81v5gbrV1DXZZrTJUsCEN1vX2IZFxNd1amCOQhlJx0ZUquqQC7HmpQQ-bzPdnUxplsmt4FhABaT9lJzg0prULzXf4UAL8OtlrPhsH7F0-aviffOxqIQdUx2gpJSQdrwayZCoQBACaKD6sr5Sm7GlmBQlXbHOYxl9BDK-LYgmNIlI0wsYvVYzj6B5C9eI3-GA1YVx3ERnOFpKuTz908fWp6hM7WJv1AIWOvUM3gSo3gslItYbgNTO9pyHEcVuHRuJiK4nMzYIvAw3GWSgbRrGs7bLBPWFwCL2YkMDHdzt0igLweylc0+C2zJJiGg9HumiMwiyd8R2KnjyCgpGieIMz+nWPb640rgVUI3Ad2ZBey9MnAYkILH1BOb4QjmIuuWE4VTwS7T6E9UBUo0c0P0NaZYGjOnlhRljYPRIJjcy6SU+5HEYOQOjJBSr+xEOicFvW0586TUE184-IHcRL3E7r6fERpP6l2Yc7InJ1IAgHuygh7WEKoqPY27fsWrE9wsfwCyj6Z52PEFe3WF87ym4NjqVVqciC2myCRMcMaxphsz-X2QBePq+eYGMaWrzM2Sax-OQXJaNE0dg7P-YJ27AidzErWdyiSmfC26OR9NeroubwU6oCnGDMgclP9aYuuxViyIbllWY0uwyY3hoe6AvziQEyKMigBAXsUfJhqjVRxfZoxzaegfI5KEfgE6LOMSAxh9gkEq3F2xv5KHOPAzMAF-87qWkWNgVSqVwTH6xxSkQ6N+bFVIOFSgdIxgOZ6oTkb1Mo74sSFkuoGWLIYCUj3ReBVZIC5doCzjKHTxrYLEsHLx2I2sMtZKAyT-ppWLKMuPNTa5tI1DrXVGmyt9HLo2Ij-N9GVhGV66IQXKDhdlgOxXhK90mMhj5N8j+WeUCVlNBAAKAR-3Yw-UnaNGAZB4acoDAUHBt06fsQVMlTXqVKFPB9ONr18mYolh4Ie64eD9jqihclz2conTQwQ8Y6jPlGex0i4IJ+uCCVATpWQcjZtbt5KzzBx6SHJwFKqHzqC80HqPJAhwnHkLbCLQD+VXD3qnnZSZMOwE4AldHWGe-aZcrDwMaWa16l6F2upwSptOSU49nSxFr+KyGoLae+txzGt3WUbmRYSfgv56E4OlaLeK6bJeLQsWsQJINkMv0gIjAlySVXBZlU86HwDLzcQKfUJBBVbWRvcjg4eh3Wc9D12fhZ3xti1FntooKAcExyUjhnwJ4AksAAQUyM70qNvvS8Zd1pSQicQZmc4NkyLeT5BjPJWCGpeRi0O+pkONmojpIdZeOyCO6DQDC3W4mGG8+ATMjaXO4aYW2OLGazPAuo8QBIKnlYCyvrIeQvbPbubUx12wpwaKEFyvCA8j4ljh1avM+DMu1D8z7x4LLEywLr9lefkr+nJFKB3EY65bTgWILf5HoYaIKMMOc5H1l+y8w2STBmelBvMvCREkGEuSPOs6Rh5E-ujFiQQ3+PrNVzZHcQV1XFtnNbdxOwtRBcLj9Qa1qI0jldiTDEBJzxCwk6agXeunZWxaUoKP8K7fKBvxHUQxBPwEefUKJCrhlBvWTDtSGezuAiR2g3QQ5BZwKBlRO6-4wK6gDaTZDhXoGV22ZtLS-JhVtyXjJI+2iNAn4QHx9JCIo1vGLQleSppB8KqEnRqJIpvuXDjtSFf0OtUypjizzhRgXQg7V4MBvrTCSYswrfkjyKBgC3gz2DWfW0C77YpSV4bQBPl5bYDwqwLqjiKrKQcGBXL95VWs+1dcPtJaJcuFqFLEG0HoRkvsi73sC+NeE9gdRGnMJBjqXJkS-I7KrhnRBy4VmeLvpe7fFv44Ah7YTp+iVgwNTlRop4VRk99MNwEFpAExq3yGfZPU4dkaglbhQUbJ1xxbTOfu2GFtAioRoOIDqAYgSc5WKijRp4fS8RD3G70MPJXSizpIN86gIjC667rMwvCCL-vlGyuq1AqkzVqoem20ZsQSnuoRkkFPu9VHDn+gQPpWy2bokgm-AIABwCZt3WEueGjZFGTyCK9OoRkpuD2b-5zGEAC4BJcTmEHQm53QXw-ZaGOX53PjnpKSDMtgTDawPYnguLHOnVjRDUa6hCfuc9Ig0wUUWTRPEwf27sH9-H62JhGsDmNo-tHdYc+azSzRv93v2sIe5VXyRPwixTfOqooTMTnZlvNsWcYxIjCQS3hr-9p9B4Zqod2y-DQYge6Vl++PMRCL2iD0GIc-ntAviwuiEtin2fKussCeswD6vqB1i315a3wKtXVkZQVKelFdFoQnK-d4zChCXQo7Cyk7Ux+qiBcSWDPpsWXiLxyP2IgxYYvUDGLhut+AudL5l8sKN462V+FkFmDy8aRL3soafM6nKrZBshGQZ8le+cBOA6WpECLbJsh-GfqQThgEUe7HvxsxUe6aX7sFl-QN+fzoZnyIdF-E5xfSxKXfZpxzLBYvbv7lYl6-SNipXBXDyIAshBCfQ-+qN45QFIQlRazcAfE+vlfElCF00f2L9J83g5d849X837wjdgzL6gPsJIG+9ZgwBMAEeNLdoHE+nDUEagRORgl5-6S8EfNZQ0I42hHQqk03UXcBm5qZ94PlTmbIMetyll2s02qcSpjRMgXIIr3JUOola6fAZ-DhjhBgVAzb697eiMAM58SCj2KHcMbILID2ygWG4it2w4OD0K8JrdASE2GJge6Gu+CG0IJ5txKBFe93IhoBLp1YAbREgWck9GAISQOcpMYFyi4EXIABT6E4AVyE8FXKWgNcmAB1y6YJwCNyiVGcYXuahu3Lo+wDN3Jn+ptNtADy7IMBIW6QQKPLFgqIDuCLARNOWDRshbNtCxicEI6JAW9hriwDI1CBaou8C-p4DnE1ZO5Ykwtiq4aFSFFKBhUWekscZIWaZFeBDs6hl4zLASoJ4BmAZgJ4DPyEkBYC9AN1JV4qeFgDia38QgdQhIs+fg9DYuDiH3bNg2yk074AGgUFCqe2gW4JiGwgSIz7OdiJ3BGB+JJIFmB3lmYBlAtir-4TQCHCXJAB+cgiCFyppv4GVg5cpXJIASANXLgwCAaigNySPM3L2QaCOLCYBljtEBdyxjgnKwiBAa6pJ0EkgZhb848hQFg81HjQEu4donGKNqm7sBar+RnPbTsBWxJwHJA8urWYeW+AGpAAAZCaRNAAgcXb5G-MidZtqfFpDCacespWYD+sqprauBpgaOiVg5gb+CeAVgJ4DdAN1L0A2BJPN9SsArYBFQSBMwdIE-YywD4yQBTgOsHZKLcHJa7ad8K6joi9phTQWcSllF4mYqlpmZmWmVlOC7BUgRJDmB9gIJASQTZr-5JSOHqBgfB2yq-RR440HM6BwWMh1g6gGMELDugAABobQD-u+ory1MH9Qf8llLzIAy2Yp9AtiN+jOYuEwRDm6z6V4IwiayqonMgVQ3vM76fAKdqCbqum-CCGzBz5u0EqgPtDgjAcDEGeoiUZ1gzqS4+NG0LzQr3L+AqgaoGVZfAVfhrSO8HjMRCOUHfPHIvixAdTZegXTFkgKMa8hp7K27Ek8C3QyRM5LkBNmOmwzSb0siTmoNVp9DFI50Jm52O4RMvAbQbMDyCi46Wr4REQrnmZbZW82BtBOwu9sqT4BJsBwrV05XC3KpsSbLBg5BqbORhMs08kvqTmkuOEIbww9rJTVEXoVeISQW7EjxdcmoQsSJhNKimFBc7dFnKlIjutdgF20drF5L4ijBhxTgGUBKFnsUluwo-QZSlKK6ojPrRppcWruXAiq1Jo8hcKDVjwYoWUkiB5aYMojCBwgNKiiBQgIxBiCHIRNIAjlgsYRn6HswQBkT+ixKMyB+gKDIeRU+p4ORi3uZuI-A+kGoOsL6gPKFpADcWarA60UK2FA7LoDjtmBIgP5NiyOB0TjFTF2RiipxpaBPgHTxO-UveEq+DQcaQWAZQD7R2KTGOrZo4OqsMYHh0tFyR4WffM7ZzoP9OCjFcraHh6L2BbDuIsUyokaFyUd-pagu0jYOLDlwPUhPJJwoCC3hAkrAEV5TgkmLHyZgXhHy7aMyiu5oUYAbJBAxuwzioD+Gs+IijUYNIo0C0KywMsI7oioCeGz6mYN6hB0avuCEpwDaJLhFaX4HWAiKioJBoO4XYb5DmQ1tvfy4O3eqQhfS6eoxGLgGhHcFooZVnnCZgeQAxZIeeBEZI7AHWK9xOAKwexh+4DER-jGR1KoEg-hWgpWBdhY9i+TFoX0mKYieyWH+ECRo4UviwsBsJZGvGp4EFZRCDZE+gycfvv9KoezIGy4Ye1eE3xAh1CLCpq2Nzm7TFuSvlZGIe2ZP4jCs9VsRQ0W0vKN6VYGUbC4rQT8AAAHT8CtAx+0IGH70hqrqhZBQgag0y7qk4DuBZqJkPRy+SkGvi6deFzum5HIlsB0R7gG6q6IZCbUOqA22loFhRaAOITUAtAj6FRwoE+ClS6wiMUdZFlRaEXmDW6bkaFY+EvVOS5ngudrZCFAwAjWq9CbZtRCfchNqgGlk8NIqhbRYNiqodGcVsdSEC1tIKiKM1Sp4iLQR0aVEcmlyK8ipgv0dNhPONWpAyAxbwMf5gIsMJqz9y7kVdGoAlWFyGZsARHPKrOBeKdisgJUXFE2R5USWiNCpyDfJaAyjBPBduXYHXAPAkNLoFrQyXprAXQUUrniChR1pqHeR0JEyqck80KEH4AwAb4ZBBYASEGABlYFAERBUQXAExBiAe8DIBCQWKxJBGAWj5pB2AZkG9yJ2P3LYRuQcl4FBY8oaGKOeYLf6vBU2PkDMSr0VfYmKeJJ-gggtYoHjxUEqKgGW09omDivR+MTyHwxJMYZBkxsUeybY4LQK6RQIV6DVQ0AEejjgcekQA8AdGwHLr4xgmMaoTeEJkVSBT6DIE-xPoeJvXjFRIcfFEDoc4cpBIGsML6JwceRk4jiIgfG+jZxyygDzrIiTtk7kiuTguw5uzINlQFOtnrUSxOphPlb1GRVi7zNm6oMyDYedOJT65u+OlCIjRMVAohN4VTm3A1OKgmhYEEPfIPGOWrIZMY3Ut0rRLE+8uOXZHoz2FXYWcNdlEx12MwA3b5SGoPNF9IVKOJD4qh-pJo9YYDvEBMcWtj4DYAiECYicmyfEKaCucEHzb0RrIIgLky2jlMjbWSxoDwLhp3AA45ZRmBo6ZrZqCIhKwP0c2lgaw6hisSg2GIjNuYF6rECfBfqBUV-xEuH7gmDW4pQEqyfQ5aOkjRxdUPD74B7Sf7pTwpbImYPQXnogByV6Ib6BjA0BUmBH+UpGDCdFGYZrK5FphGIiqJBeApWG6uDjslPoFVlOBqQzoeph2uxXsW5e5ZrueUyJV2AmblJKovT7g+kuLujQACgGPhvA0NvAg8IwrFqmpMS5b4FV+pWhUWgKThHlW6gZyHFBhEKgg+Q0RwrH2C8478Tb43F2IJpBJSXWUmBUwtuRhFuprRd8lconwMlDtqsNMmaJABsIyojONTPWSyo47r0ofANKjunOILhfCW227IgTS7wX0seAriSZahnHa3SfayGVXcYgrWC5zEciY2AQv9wX0j9tSROOOscgg+qqfoF6WE7pCgKdhsiGuSUAvSE5zXgB2bXwRFd6lcjDE-tncoSOVAHQKJE0FGSDLQ3-EIYGc6fgiI9VEfPgAAAWttj9oFAF1DNFkIhgJplyKBOoGw7VWyBMoBIfaxgCJonzwsU8WYRhBQ4NCTW-kEJRZBPAioN5jphOOFCHIFwadjDdizsFkURUl3NeD8qB7CRCaJtUlkX-uOkfvRXEWSTxDgQehHFj26PCXSAUcE8BenLuuQlegkFFIOcFBRN2nD7UYi0JjBZi6eLFQg0FkAwA5V3+l8AIBwxNjD4ao+jlIHUccoLD-lQcnxFXOoNM7VaIdAI0gKERWkw6d8HiOcXE85cDmyVFkzr+Q6cjxdED8JM6R1q8hlfO8DEG7ZdWWYwwZbXw+CUQbzlAkRiWrm9kC-LYwxy+9l7Cd+e+M4TzyiIBa5UAkRWtLjYmMPxHVBE4DpXqe+FFyoEu+qc2TCsKtZcVL0fmCxUY+eFWq5mkF0BsADcauD9pTWteB7Bk68Vsu5lwsiKMBwQO2i3zWozrKhRnOWAAOHx4gTuPVk48rogAjMftOrKVcPmJ3C6gX1abg1wo6KBUgM+DFhVXEvUZnmeAjSNnXOlR0rlA+5lXDHRAVqGYqph+Cwra7JGtu4HmGyJtFRsXvhspUKAJVgsbbG5+lZkPgHezOYy5WA6VGEm4B5Sbu8zfwe1NlMvBtIocI+6mZ17gQDHedPrSGHLSmwL3GrzoEvixkDnNuNv4cWP9GaR0SERlIgxmACKcxKTQo1ae8+N+H4OkuOHWMeXkJuCxFuRNbJOlBVjxAKZf4NeIV434PxuCQ4W8+4dAUW4HD2DGiXhsUQ8m7+4bQTgBisoDlcDhtUtD0APK1qN5GLhJ0+ci9392QsLeUMT5vveEbDa-JaCowmQ8mqJb8yWKltIVcDr06QBAPnPsQDDA5CcuNzQ+xBQFbU3Qd4xEihRT+PiK0L70-ni3p4i-YlpBtIz8idswpBALa11Bg3k9BzQsDeqQfbAaP9qbqQzS+OG9lYGBVCrs+josDyOqVXgxEI274ZTD0KcqgEAZvaDv7Ti4PzXMQkXuwllA7oAIgUm5G0uqFw9rKcA3UcnacNOQJvcKsq+O2+IREb7m8nSBboUewk8B-qU+gr+7Y2RoShmYKtlWKjMMrQXLYeQIZCOJEKyDi7khmO3Dl0u5HyWcMpjZqvCT6AbBqAa2dEA8jcAE8AVZ0gztx286YRmXVS1lCcxQ7aKMNNrSIMovIosvrZn30qwQExoDDsQMHnIe7iGPxTS6aH9vjbyqLOI-z9hAgDeLHsNc5Ch048VA1MrYjzW+mFFk9n+7yAzjuwpMdXcU-yr9jNOUFbxe1Dtg-AC3ZVgwo0iDYwoSJinoCxUA+mAqEinhA2ZhfGAh-JDvW+kybv4wqjRAMcOdm915cLtNcCORYq6clS0PJRErV9XTXt09atI4TQxuOWC67Eu9B0+UDe9jg-+yozutok3GozyVgQjrjBBBsBGH7eYFLlHElpYgBtA9I+5hSs1W526UCYTzGyECNDH3AjDIwXot6H2L7i47Ay1rsEbPSZPIr7CYg3oZ3PIA6wxL0vLHsLSvsQvizyLZCSQL4nlAj3a7lEQKK2JhUrD0CAeX7UdGUBJA7oEkAswH3CStxgsB0gDwHM2Bft0aXsKJC+MaBy4Mfcyu-jBjAeB8gdSmBB5aCIHU4GAeci6B1ARlA0PcAikwEHLOQbQDB9EBEHg67d0QA2IDsQag6yWQeNDUBxwfMwbME0i8HREHkC7cSvl27OesIQyCVR3oU8CR4FVrxqJLNbbVCMLsM+4ghIeqRrX2Exa8HDOADGA95TwIKR3HapeCzMkqwEh7YdPgzPKM3KM9h-0iOHrINP51YzyQ96ZMkhkNyR8ywCClBHeu6z7z0d4BEdEQjQEEiBl4ey8BstaEEYAbQk63sRIr2QB77e4ixOMQZHo4ZlBs+1MP7T7Z3unwcf7uXvsaROslFxl0CYRZ7utbSkF6VkHYex-uXbTFlWC371bQ7k5c4m-lzcgpcAENODiS3f0dGUYJqNYO0Q0D1wQ1bTE3WJ5OUfsL8c1gmBC0Gh70a7DvQ1qDaHEQF0aXiSAIRL+cjYQ96Vg-NgyD2M4I5YduGyR2XsFRlR9c3ugldQyD6QTe-SCGFTaxA7TsfEu6k4rFk8sfG8q1MEoN6Ruyvt5w5xx34SheQKNI981dScKShJzo0sRiBOQvwn7fSIIeR7D0DVS14mXQs3YAx+93CWgGJ3hXsQg0hJuNLKPhkBuHvDokKyz0tZX05kcByRg-iEXD4ziAmJQoHiAfmQOvuJ967+Il5Ie1VxEcFh8vyTQVEJdSpYZQGidEnU6yIaYnW0RtCitIIDjMOEsXk4n7JFYWKlC8mmg1CfQxoNjzvGaVEkaFHuudc2bbzjvYrfrPgBkel++ACEhZ+9IPyeyg0nvKDEN3AzMDJHx+7IgunRnkWQgAAAL7+nhsIQDq0XEKwAYA2ALwBEApACXYAA+l7L8A-gCwCpFPAAQBot3aB4BeAjqdNVrQ-gKQDqQfVIM5b1T4JPb84CWurOxUXUWnaMht5neHZAPdj7KsAegKQD+nyGOQC35sZ77ixnGCkmekAKZ3mcgAqFXQCZnpANmeqSA5ydkbETMb7sW8AHtQhGRjEwfwgeoeG+iDGsoOQXbhl3WljW7UBucjNnAZ22dgA5ILGerosZ3fw-+vAMmfz6A50OcjnIAGOfcIA5wWercFNW8FPMEjuISJAgh+adWYUeq9OwRJlCR3Sk0UhAr7nrZ14D-osZ1KAJYsZ7HS9n3gNee8A6Z4UB3nD5wPADndi9kA2NOA9RCaN5jc0SUeg+-620ACWP81V+24WIgsyTwGBdtnY8N2fzmYwPBf9nSF4OcZnwZ6OcteOZ0GATndU862vUYYOkKz53LOblPoEKl1XoydPDRdeABSLGeUaz00xeIXaZ6xcoX7F-eecX45yxeTnwrGOWFZcRqXx+cfyrz5SXpAEeCxn9S-uaxnQx5ed9nil14C3nql2he5nLF+6DCsXYaavcQ8a5uC3gfSNyDGXIAMSl0Asl4qP2h1lwhcqAN52xdtnjl9xeaXvF1lVeI3MXyMZkAV7giWoy2D2XzgrqqP30gfl9mcaYUF7ZdXn4VyxeNwYhNwCoX6l4+csXe-WM5NQ80%uM6eVxTSuXBIPudtntDc4bwX8pzmSaXXu3ug1Qlzc0JR0AFjRvyzkeuxiFoW+DUuP8-qVW2qXnR9+ADn3GotAlgl0Ggx0pt79DUuLThFwSkzid5-Yy24RuyxcI6plq2XkBLwA+O0B9+ARCqXchm-2mgNQAOf82fuANdqGh4+3A3XgZ22ft2Zl40QKXxV0pelX2LQ5eVX6F9VcITA9WQAd2w0ujiDSju3gT-+o+7x1Vick+cCVBRcG1deAHVwCLwXaALlCoATwOpBnnFALGf2AwgFScsXDQLLEsghIIEF2D4AeEF9yisdEDQNcQU8NaqoNKbFkBsrZpKqXGAEgBE3WgLGdOA5N34CU31N40CEgIATXOmmEhQbHM36g2qSxB9cuzeGY+QaQGuVPNzddtnuUpVV2L+RMdcVVRIyOjZ0ycHtyq32t14D82uUpyQDnq9a5ACcRLrDcvIHFUpBZy60AGfgXHF0Jexn5CP9epnXgP3mMXINypJVXSl7WmWc9jdBre2PYALHRLl+M+%bJLzhQUiY3pANjfqA-gF9mkAz17Tln5C9rsUTXEVAkHoyrfKpf7rfaAQDXVaIrsaXTNGd5C-pioERSW3+ZxFmCald-B0EmLIpgRB9YbR93cQ7zRcxhy8gs3cgA0+Egvt3bCBMIMXSdHJeNhL0u4L7ASRkQtpzWY0Yp1XbAqQD-ZXt3BiKjTwLGfnQGDD2ShXzF0pdB3PAFFeg3Tl+HcAMB91SbR3qV-gisezorpW-k1upNGp3-l5b4Z3vAFncgAOdwQDp6-+I-dnyd6M0hUiql9jCfE-iosIEAlo-+PMZM097P1l-aBXYKIQDcpz40vN22czGPuZSDknBAO7enz6eMgCEXx6gkWf8vHZWMj33Gn2C53hDyk5x1EkCF7PkuPKetJ0IIn5AbksVK500CHfR7db37V7isIAsZwz3tIx97ZekAZ9xVeh3YN9fc8geHHGimCQjy4UI5NxWyCoRG7m+drQH9+ndkAmd9ne2xmTFgwAP-UKxBwQrVDlFIkql4UM2gldyr08guzglwMmsDoCsDoCsDoCsDoCsDoCsDoCsDoCsDoCsDoCsDoCsDoCsDoCsDoCsDoCsDoCsDoCsDoCsDoCsDoCsDoCsDoCsDoCsDoCsDoCsDoCsDoCsDoCsDoCsDoCsDoCsDoCsDoCsDoCsDoCsDoCsDoCsDoCsDoCsDoCsDoCsDoCsDoCsDoCsDoCsDoCsDoCsDoCsDoCsDoCsDoCsDoCsDoCsDoCsDoCsDoCsDoCsDoCsDoCsDoCsDoCsDoCsDoCsDoCsDoCsDoCsDoCsDoCsDoCsDoCsDoCsDoCsDoCsDoCsDoCsDoCsDoCsDoCsDoCsDoCsDoCsDoCsDoCsDoCsDoCsDoCsDoCsDoCsDoCsDoCsDoCsDoCsDoCsDoCsDoCsDoCsDoCsDoCsDoCsDoCsDoCsDoCsDoCsDoCsDoCsDoCsDoCsDoCsDoCsDoCsDoCsDoCsDoCsDoCsDoCsDoCsDoCsDoCsDoCsDoCsDoCsDoCsDoCsDoCsDoCsDoCsDoCsDoCsDoCsDoCsDoCsDoCsDoCsDoCsDoCsDoCsDoCsDoCsDoCsDoCsDoCsDoCsDoCsDoCsDoCsDoCsDoCsDoCsDoCsDoCsDoCsDoCsDoCsDoCsDoCsDoCsDoCsDoCsDoCsDoCsDoCsDoCsDoCsDoCsDoCsDoCsDoCsDoCsDoCsDoCsDoCsDoCsDoCsDoCsDoCsDoCsDoCsDoCsDoCsDoCsDoCsDoCsDoCsDoCsDoCsDoCsDoCsDoCsDoCsDoCsDoCsDoCsDoCsDoCsDoCsDoCsDoCsDoCsDoCsDoCsDoCsDoCsDoCsDoCsDoCsDoCsDoCsDoCsDoCsDoCsDoCsDoCsDoCsDoCsDoCsDoCsDoCsDoCsDoCsDoCsDoCsDoCsDoCsDoCsDoCsDoCsDoCsDoCsDoCsDoCsDoCsDoCsDoCsDoCsDoCsDoCsDoCsDoCsDoCsDoCsDoCsDoCsDoCsDoCsDoCsDoCsDoCsDoCsDoCsDoCsDoCsDoCsDoCsDoCsDoCsDoCsDoCsDoCsDoCsDoCsDoCsDoCsDoCsDoCsDoCsDoCsDoCsDoCsDoCsDoCsDoCsDoCsDoCsDoCsDoCsDoCsDoCsDoCsDoCsDoCsDoCsDoCsDoCsDoCsDoCsDoCsDoCsDoCsDoCsDoCsDoCsDoCsDoCsDoCsDoCsDoCsDoCsDoCsDoCsDoCsDoCsDoCsDoCsDoCsDoCsDoCsDoCsDoCsDoCsDoCsDoCsDoCsDoCsDoCsDoCsDoCsDoCsDoCsDoCsDoCsDoCsDoCsDoCsDoCsDoCsDoCsDoCsDoCsDoCsDoCsDoCsDoCsDoCsDoCsDoCsDoCsDoCsDoCsDoCsDoCsDoCsDoCsDoCsDoCsDoCsDoCsDoCsDoCsDoCsDoCsDoCsDoCsDoCsDoCsDoCsDoCsDoCsDoCsDoCsDoCsDoCsDoCsDoCsDoCsDoCsDoCsDoCsDoCsDoCsDoCsDoCsDoCsDoCsDoCsDoCsDoCsDoCsDoCsDoCsDoCsDoCsDoCsDoCsDoCsDoCsDoCsDoCsDoCsDoCsDoCsDoCsDoCsDoCsDoCsDoCsDoCsDoCsDoCsDoCsDoCsDoCsDoCsDoCsDoCsDoCsDoCsDoCsDoCsDoCsDoCsDoCsDoCsDoCsDoCsDoCsDoCsDoCsDoCsDoCsDoCsDoCsDoCsDoCsDoCsDoCsDoCsDoCsDoCsDoCsDoCsDoCsDoCsDoCsDoCsDoCsDoCsDoCsDoCsDoCsDoCsDoCsDoCsDoCsDoCsDoCsDoCsDoCsDoCsDoCsDoCsDoCsDoCsDoCsDoCsDoCsDoCsDoCsDoCsDoCsDoCsDoCsDoCsDoCsDoCsDoCsDoCsDoCsDoCsDoCsDoCsDoCsDoCsDoCsDoCsDoCsDoCsDoCsDoCsDoCsDoCsDoCsDoCsDoCsDoCsDoCsDoCsDoCsDoCsDoCsDoCsDoCsDoCsDoCsDoCsDoCsDoCsDoCsDoCsDoCsDoCsDoCsDoCsDoCsDoCsDoCsDoCsDoCsDoCsDoCsDoCsDoCsDoCsDoCsDoCsDoCsDoCsDoCsDoCsDoCsDoCsDoCsDoCsDoCsDoCsDoCsDoCsDoCsDoCsDoCsDoCsDoCsDoCsDoCsDoCsDoCsDoCsDoCsDoCsDoCsDoCsDoCsDoCsDoCsDoCsDoCsDoCsDoCsDoCsDoCsDoCsDoCsDoCsDoCsDoCsDoCsDoCsDoCsDoCsDoCsDoCsDoCsDoCsDoCsDoCsDoCsDoCsDoCsDoCsDoCsDoCsDoCsDoCsDoCsDoCsDoCsDoCsDoCsDoCsDoCsDoCsDoCsDoCsDoCsDoCsDoCsDoCsDoCsDoCsDoCsDoCsDoCsDoCsDoCsDoCsDoCsDoCsDoCsDoCsDoCsDoCsDoCsDoCsDoCsDoCsDoCsDoCsDoCsDoCsDoCsDoCsDoCsDoCsDoCsDoCsDoCsDoCsDoCsDoCsDoCsDoCsDoCsDoCsDoCsDoCsDoCsDoCsDoCsDoCsDoCsDoCsDoCsDoCsDoCsDoCsDoCsDoCsDoCsDoCsDoCsDoCsDoCsDoCsDoCsDoCsDoCsDoCsDoCsDoCsDoCsDoCsDoCsDoCsDoCsDoCsDoCsDoCsDoCsDoCsDoCsDoCsDoCsDoCsDoCsDoCsDoCsDoCsDoCsDoCsDoCsDoCsDoCsDoCsDoCsDoCsDoCsDoCsDoCsDoCsDoCsDoCsDoCsDoCsDoCsDoCsDoCsDoCsDoCsDoCsDoCsDoCsDoCsDoCsDoCsDoCsDoCsDoCsDoCsDoCsDoCsDoCsDoCsDoCsDoCsDoCsDoCsDoCsDoCsDoCsDoCsDoCsDoCsDoCsDoCsDoCsDoCsDoCsDoCsDoCsDoCsDoCsDoCsDoCsDoCsDoCsDoCsDoCsDoCsDoCsDoCsDoCsDoCsDoCsDoCsDoCsDoCsDoCsDoCsDoCsDoCsDoCsDoCsDoCsDoCsDoCsDoCsDoCsDoCsDoCsDoCsDoCsDoCsDoCsDoCsDoCsDoCsDoCsDoCsDoCsDoCsDoCsDoCsDoCsDoCsDoCsDoCsDoCsDoCsDoCsDoCsDoCsDoCsDoCsDoCsDoCsDoCsDoCsDoCsDoCsDoCsDoCsDoCsDoCsDoCsDoCsDoCsDoCsDoCsDoCsDoCsDoCsDoCsDoCsDoCsDoCsDoCsDoCsDoCsDoCsDoCsDoCsDoCsDoCsDoCsDoCsDoCsDoCsDoCsDoCsDoCsDoCsDoCsDoCsDoCsDoCsDoCsDoCsDoCsDoCsDoCsDoCsDoCsDoCsDoCsDoCsDoCsDoCsDoCsDoCsDoCsDoCsDoCsDoCsDoCsDoCsDoCsDoCsDoCsDoCsDoCsDoCsDoCsDoCsDoCsDoCsDoCsDoCsDoCsDoCsDoCsDoCsDoCsDoCsDoCsDoCsDoCsDoCsDoCsDoCsDoCsDoCsDoCsDoCsDoCsDoCsDoCsDoCsDoCsDoCsDoCsDoCsDoCsDoCsDoCsDoCsDoCsDoCsDoCsDoCsDoCsDoCsDoCsDoCsDoCsDoCsDoCsDoCsDoCsDoCsDoCsDoCsDoCsDoCsDoCsDoCsDoCsDoCsDoCsDoCsDoCsDoCsDoCsDoCsDoCsDoCsDoCsDoCsDoCsDoCsDoCsDoCsDoCsDoCsDoCsDoCsDoCsDoCsDoCsDoCsDoCsDoCsDoCsDoCsDoCsDoCsDoCsDoCsDoCsDoCsDoCsDoCsDoCsDoCsDoCsDoCsDoCsDoCsDoCsDoCsDoCsDoCsDoCsDoCsDoCsDoCsDoCsDoCsDoCsDoCsDoCsDoCsDoCsDoCsDoCsDoCsDoCsDoCsDoCsDoCsDoCsDoCsDoCsDoCsDoCsDoCsDoCsDoCsDoCsDoCsDoCsDoCsDoCsDoCsDoCsDoCsDoCsDoCsDoCsDoCsDoCsDoCsDoCsDoCsDoCsDoCsDoCsDoCsDoCsDoCsDoCsDoCsDoCsDoCsDoCsDoCsDoCsDoCsDoCsDoCsDoCsDoCsDoCsDoCsDoCsDoCsDoCsDoCsDoCsDoCsDoCsDoCsDoCsDoCsDoCsDoCsDoCsDoCsDoCsDoCsDoCsDoCsDoCsDoCsDoCsDoCsDoCsDoCsDoCsDoCsDoCsDoCsDoCsDoCsDoCsDoCsDoCsDoCsDoCsDoCsDoCsDoCsDoCsDoCsDoCsDoCsDoCsDoCsDoCsDoCsDoCsDoCsDoCsDoCsDoCsDoCsDoCsDoCsDoCsDoCsDoCsDoCsDoCsDoCsDoCsDoCsDoCsDoCsDoCsDoCsDoCsDoCsDoCsDoCsDoCsDoCsDoCsDoCsDoCsDoCsDoCsDoCsDoCsDoCsDoCsDoCsDoCsDoCsDoCsDoCsDoCsDoCsDoCsDoCsDoCsDoCsDoCsDoCsDoCsDoCsDoCsDoCsDoCsDoCsDoCsDoCsDoCsDoCsDoCsDoCsDoCsDoCsDoCsDoCsDoCsDoCsDoCsDoCsDoCsDoCsDoCsDoCsDoCsDoCsDoCsDoCsDoCsDoCsDoCsDoCsDoCsDoCsDoCsDoCsDoCsDoCsDoCsDoCsDoCsDoCsDoCsDoCsDoCsDoCsDoCsDoCsDoCsDoCsDoCsDoCsDoCsDoCsDoCsDoCsDoCsDoCsDoCsDoCsDoCsDoCsDoCsDoCsDoCsDoCsDoCsDoCsDoCsDoCsDoCsDoCsDoCsDoCsDoCsDoCsDoCsDoCsDoCsDoCsDoCsDoCsDoCsDoCsDoCsDoCsDoCsDoCsDoCsDoCsDoCsDoCsDoCsDoCsDoCsDoCsDoCsDoCsDoCsDoCsDoCsDoCsDoCsDoCsDoCsDoCsDoCsDoCsDoCsDoCsDoCsDoCsDoCsDoCsDoCsDoCsDoCsDoCsDoCsDoCsDoCsDoCsDoCsDoCsDoCsDoCsDoCsDoCsDoCsDoCsDoCsDoCsDoCsDoCsDoCsDoCsDoCsDoCsDoCsDoCsDoCsDoCsDoCsDoCsDoCsDoCsDoCsDoCsDoCsDoCsDoCsDoCsDoCsDoCsDoCsDoCsDoCsDoCsDoCsDoCsDoCsDoCsDoCsDoCsDoCsDoCsDoCsDoCsDoCsDoCsDoCsDoCsDoCsDoCsDoCsDoCsDoCsDoCsDoCsDoCsDoCsDoCsDoCsDoCsDoCsDoCsDoCsDoCsDoCsDoCsDoCsDoCsDoCsDoCsDoCsDoCsDoCsDoCsDoCsDoCsDoCsDoCsDoCsDoCsDoCsDoCsDoCsDoCsDoCsDoCsDoCsDoCsDoCsDoCsDoCsDoCsDoCsDoCsDoCsDoCsDoCsDoCsDoCsDoCsDoCsDoCsDoCsDoCsDoCsDoCsDoCsDoCsDoCsDoCsDoCsDoCsDoCsDoCsDoCsDoCsDoCsDoCsDoCsDoCsDoCsDoCsDoCsDoCsDoCsDoCsDoCsDoCsDoCsDoCsDoCsDoCsDoCsDoCsDoCsDoCsDoCsDoCsDoCsDoCsDoCsDoCsDoCsDoCsDoCsDoCsDoCsDoCsDoCsDoCsDoCsDoCsDoCsDoCsDoCsDoCsDoCsDoCsDoCsDoCsDoCsDoCsDoCsDoCsDoCsDoCsDoCsDoCsDoCsDoCsDoCsDoCsDoCsDoCsDoCsDoCsDoCsDoCsDoCsDoCsDoCsDoCsDoCsDoCsDoCsDoCsDoCsDoCsDoCsDoCsDoCsDoCsDoCsDoCsDoCsDoCsDoCsDoCsDoCsDoCsDoCsDoCsDoCsDoCsDoCsDoCsDoCsDoCsDoCsDoCsDoCsDoCsDoCsDoCsDoCsDoCsDoCsDoCsDoCsDoCsDoCsDoCsDoCsDoCsDoCsDoCsDoCsDoCsDoCsDoCsDoCsDoCsDoCsDoCsDoCsDoCsDoCsDoCsDoCsDoCsDoCsDoCsDoCsDoCsDoCsDoCsDoCsDoCsDoCsDoCsDoCsDoCsDoCsDoCsDoCsDoCsDoCsDoCsDoCsDoCsDoCsDoCsDoCsDoCsDoCsDoCsDoCsDoCsDoCsDoCsDoCsDoCsDoCsDoCsDoCsDoCsDoCsDoCsDoCsDoCsDoCsDoCsDoCsDoCsDoCsDoCsDoCsDoCsDoCsDoCsDoCsDoCsDoCsDoCsDoCsDoCsDoCsDoCsDoCsDoCsDoCsDoCsDoCsDoCsDoCsDoCsDoCsDoCsDoCsDoCsDoCsDoCsDoCsDoCsDoCsDoCsDoCsDoCsDoCsDoCsDoCsDoCsDoCsDoCsDoCsDoCsDoCsDoCsDoCsDoCsDoCsDoCsDoCsDoCsDoCsDoCsDoCsDoCsDoCsDoCsDoCsDoCsDoCsDoCsDoCsDoCsDoCsDoCsDoCsDoCsDoCsDoCsDoCsDoCsDoCsDoCsDoCsDoCsDoCsDoCsDoCsDoCsDoCsDoCsDoCsDoCsDoCsDoCsDoCsDoCsDoCsDoCsDoCsDoCsDoCsDoCsDoCsDoCsDoCsDoCsDoCsDoCsDoCsDoCsDoCsDoCsDoCsDoCsDoCsDoCsDoCsDoCsDoCsDoCsDoCsDoCsDoCsDoCsDoCsDoCsDoCsDoCsDoCsDoCsDoCsDoCsDoCsDoCsDoCsDoCsDoCsDoCsDoCsDoCsDoCsDoCsDoCsDoCsDoCsDoCsDoCsDoCsDoCsDoCsDoCsDoCsDoCsDoCsDoCsDoCsDoCsDoCsDoCsDoCsDoCsDoCsDoCsDoCsDoCsDoCsDoCsDoCsDoCsDoCsDoCsDoCsDoCsDoCsDoCsDoCsDoCsDoCsDoCsDoCsDoCsDoCsDoCsDoCsDoCsDoCsDoCsDoCsDoCsDoCsDoCsDoCsDoCsDoCsDoCsDoCsDoCsDoCsDoCsDoCsDoCsDoCsDoCsDoCsDoCsDoCsDoCsDoCsDoCsDoCsDoCsDoCsDoCsDoCsDoCsDoCsDoCsDoCsDoCsDoCsDoCsDoCsDoCsDoCsDoCsDoCsDoCsDoCsDoCsDoCsDoCsDoCsDoCsDoCsDoCsDoCsDoCsDoCsDoCsDoCsDoCsDoCsDoCsDoCsDoCsDoCsDoCsDoCsDoCsDoCsDoCsDoCsDoCsDoCsDoCsDoCsDoCsDoCsDoCsDoCsDoCsDoCsDoCsDoCsDoCsDoCsDoCsDoCsDoCsDoCsDoCsDoCsDoCsDoCsDoCsDoCsDoCsDoCsDoCsDoCsDoCsDoCsDoCsDoCsDoCsDoCsDoCsDoCsDoCsDoCsDoCsDoCsDoCsDoCsDoCsDoCsDoCsDoCsDoCsDoCsDoCsDoCsDoCsDoCsDoCsDoCsDoCsDoCsDoCsDoCsDoCsDoCsDoCsDoCsDoCsDoCsDoCsDoCsDoCsDoCsDoCsDoCsDoCsDoCsDoCsDoCsDoCsDoCsDoCsDoCsDoCsDoCsDoCsDoCsDoCsDoCsDoCsDoCsDoCsDoCsDoCsDoCsDoCsDoCsDoCsDoCsDoCsDoCsDoCsDoCsDoCsDoCsDoCsDoCsDoCsDoCsDoCsDoCsDoCsDoCsDoCsDoCsDoCsDoCsDoCsDoCsDoCsDoCsDoCsDoCsDoCsDoCsDoCsDoCsDoCsDoCsDoCsDoCsDoCsDoCsDoCsDoCsDoCsDoCsDoCsDoCsDoCsDoCsDoCsDoCsDoCsDoCsDoCsDoCsDoCsDoCsDoCsDoCsDoCsDoCsDoCsDoCsDoCsDoCsDoCsDoCsDoCsDoCsDoCsDoCsDoCsDoCsDoCsDoCsDoCsDoCsDoCsDoCsDoCsDoCsDoCsDoCsDoCsDoCsDoCsDoCsDoCsDoCsDo