Making a showcase film that holds up
Reference bar: your best prior showcase film (the author's is a 164.8s,
1920x1080, 30fps, stereo cut at peak -3.0dB / mean -20.2dB).
Reference build system: a films/<slug>/ folder in your work repo holding
GRAMMAR.md, BEATMAP.md, SCRIPT.md, build.py, cards.py, bedcal.py, broll/, with a
director/ folder beside it (harvest_assets.py, assemble_film.py,
cards_html.py, device_frame.py). If none exists yet, this file is the spec.
0. Verify claims about the reference, including mine
Everything in this file that is a measurement carries the measurement. Where it does not, it is flagged UNVERIFIED. Honour that distinction and extend it: when a subagent reports a finding about the corpus, re-measure it yourself before acting on it. A wrong belief about the reference propagates into every film you build from it.
Verified 2026-08-01, reproducible:
- corpus audio: stereo 48kHz, mean -18.6 to -21.2dB, peaks -1.1 to -3.2dB
- bed
Slow Drift Ambient Synth.caf: 19.009909s long, trough -37.5dB at 4s and -36.4dB at 5s against -17 to -25dB elsewhere ffmpeg -h filter=alimiter->level <boolean> auto level (default true)
1. Derive the grammar — never assume it
If a catalog of reference films exists (e.g. an internal showcase catalog of ~48 films), measure it: sample 5+ films at 1Hz across their whole timelines, classify every frame by border signature, and check the segment order agrees across all of them. Measure cross-dissolves off the luma ramp.
A grammar derived this way on one internal catalog was reported as:
logo 3 | b-roll 23 | motion 23 | demo 81 | motion 22 | logo 3.
UNVERIFIED — treat as a starting hypothesis, not a spec. Those numbers come from a subagent that said it classified frames at 1Hz across five films. The method is sound but I have not independently reproduced the timings, and a different claim from the same report ("no voiceover") turned out to be false. Re-measure before you build to these numbers.
The reference catalog films ARE narrated. Measured 2026-08-01 across three of them: stereo 48kHz, mean -18.6 to -21.2dB, peaks -1.1 to -3.2dB, with level swinging -58 -> -39 -> -18 -> -22 -> -16 across 3s windows — the dynamic signature of speech with sentence pauses, not a flat music bed.
An earlier version of this skill claimed the corpus had "no voiceover at all".
That was a subagent's assertion I wrote down without measuring, and it was
WRONG. It nearly caused another session to tear out a working TTS pipeline.
Measure the reference audio yourself before you believe anything about it —
volumedetect over the whole file, then per-3s windows to see whether the level
moves. Flat means bed; swinging means voice.
2. Freeze the beatmap before capturing anything
One row per beat: what is on screen, what the VO says, the window length, and the visible proof. A beat without visible proof is a claim, and claims get cut. Parallel work before the beatmap is frozen produces pieces that don't cut together.
3. Capture
Tab-only, always. Desktop screen capture leaked private windows three
separate ways on this machine — see /tab-film. Use the browser extension's
recorder and drive frames with wait actions, not screenshot (same frames,
without flooding your context).
Product capture rules learned the expensive way:
- Citations resolve only when a message completes, and never inside a
markdown table cell — only in prose. Mid-stream frames carry raw
[doc:turnNdocN]tokens. - A follow-up in an existing thread answers from history without re-calling tools, so it has no citations at all. Fresh chat every time.
- Show the user's prompt in frame. Three "ask it for…" VO lines over answers with no visible question is a reviewer's first finding.
4. Narrate
Voice en-US-AndrewMultilingualNeural. If Azure Speech is Entra-only in
your tenant (local keys disabled on every Speech resource):
Authorization: aad#<resourceId>#<token>
resourceId /subscriptions/<subscription-id>/resourceGroups/<resource-group>/
providers/Microsoft.CognitiveServices/accounts/<speech-resource>
token az account get-access-token --resource https://cognitiveservices.azure.com
Local fallback: macOS say -v Daniel. Same slot structure, same fit-gate. A
film with a lesser voice ships; a film with no voice does not.
Fit-gate every slot. Read must land inside its window with air at the tail. If it does not fit, widen the window or shorten the copy — never speed up the read. Over ~2.6 words/sec reads rushed; name the slot and fix it.
5. Mix — three traps that each cost a rebuild
Contract: VO +6dB · bed at a level that is actually audible · sidechaincompress= threshold=0.015:ratio=8:attack=25:release=450:makeup=1 · alimiter ·
NEVER loudnorm.
alimiterhaslevel=trueby default, which makes it a normaliser that lifts the mix until peaks hit the ceiling. Lowering the ceiling makes clipping WORSE. Usealimiter=level=disabled:limit=0.891(-1.0 dBFS).amixadopts the FIRST input's channel layout. A mono VO bus silently collapses a stereo bed to mono. Checksidechannel energy in the output.- The Apple Loops bed loops every 19.0s with a -37dB trough 4-6s in. If a segment cut lands on it, it reads as dead audio. Mix the bed against a half-loop-offset copy of itself — same material, range drops from 12dB to under 3dB.
Gate: VO slots mean > -19dB; bed audible in every gap (~-27dB, not -50dB); peak below 0.0dB with nothing pinned at full scale; genuinely stereo.
6. Never motion-interpolate text
minterpolate with motion compensation warps pixels along estimated motion
vectors. Between frames of different text it produces unreadable ghosted soup.
Hard cuts, or crossfades <=0.3s. This shipped once.
7. Customer-facing versus internal
Two cuts, two vocabularies. Internal may name the build system. Customer-facing must not — no RAPP, Factory, RAPPlication, MVP, prototype, pipeline, brainstem, egg. Put a vocabulary gate in the build script that hard-fails on those in narration and card strings, and know it cannot see the pixels of captured shots — check frames by eye.
Synthetic data: badge on every data frame, and the disclaimer card lands before the first data frame, not after. Show roles, never invented person names.
8. B-roll must argue the scenario
Harvested stock that would drop unchanged into any other film is filler. If the corpus has nothing that fits the domain, cut the block short rather than pad it — and say so, so someone can source real footage. Never let b-roll carry another agent's product UI, customer name or scenario.
9. The gate
- Longest unchanged frame <= 5.0s.
- Watch it. Frames at ~1Hz across the whole timeline, READ them. A green build is not a watched film — this failed repeatedly, once shipping a smeared unwatchable cut and once a frame with raw citation tokens.
- Then a separate blind adversarial reviewer against the reference film, on grammar, pacing, legibility, audio and claim-vs-proof. Fix blockers, rebuild, re-review. Loop until PASS with zero blockers — and if you stop short, name exactly what is still wrong. A known flaw named is fine; one the customer finds is not.
Related
/tab-film (capture detail) · /cs-agent-live (get the agent presentable
first) · /msft-deck (the deck that travels with it)
Run this — do not improvise
This capability's deterministic implementation is a RAPP single-file agent, linked beside this file as showcase_film_agent.py and embedded as the fenced Python below (sha256 5dc5d9ae83b50a75…; a byte-exact copy is also vaulted in the capsule comment at the end of this file). On a host with sandbox execution, run the linked file directly — if it is missing, write the fence contents verbatim to showcase_film_agent.py first:
python3 showcase_film_agent.py '{"key": "value"}' # arguments as one JSON object
echo '{"key": "value"}' | python3 showcase_film_agent.py # or on stdin
python3 showcase_film_agent.py --tool # emit the JSON tool contract
Treat stdout as a tool result. If it reports missing or unresolved inputs, stop and collect them. If it returns steps, execute those steps in order exactly as returned; if it returns instructions, follow them with the supplied inputs. Otherwise use the result verbatim. Do not invent behavior beyond that output. On a host without code execution, treat the Parameters schema and the code below as the exact specification and never paraphrase a step. Never edit inside the generated markers; a converter-equipped host can instead restore the original file checksum-verified with the installed rapp-agent-converter/scripts/toast.py convert SKILL.md --to agent.
"""ShowcaseFilm -- Produce a catalog-quality showcase film from any source — an agent, an app, a portal, a process. The full pipeline: derive grammar from reference films, write the beatmap, capture, narrate, mix, gate. Trigger on any request for a showcase, demo film, sizzle reel, walkthrough or customer-facing video.
Generated by the rapp skill from showcase-film. The RCI capsule at the bottom of this file carries the full original; `toast.py convert` restores it byte-exact."""
import json
import re
import sys
try:
from agents.basic_agent import BasicAgent
except ImportError: # running OUTSIDE a brainstem -- stay executable anyway.
class BasicAgent: # noqa: D101 - minimal stand-in, same contract
def __init__(self, name=None, metadata=None):
if name:
self.name = name
if metadata:
self.metadata = metadata
def perform(self, **kwargs):
return "Not implemented."
def system_context(self):
return None
def to_tool(self):
return {"type": "function", "function": {
"name": self.name,
"description": self.metadata.get("description", ""),
"parameters": self.metadata.get("parameters", {})}}
# The procedural layer, verbatim from the source capability.
INSTRUCTIONS = '# Making a showcase film that holds up\n\nReference bar: your best prior showcase film (the author's is a 164.8s,\n1920x1080, 30fps, stereo cut at peak -3.0dB / mean -20.2dB).\nReference build system: a `films/<slug>/` folder in your work repo holding\nGRAMMAR.md, BEATMAP.md, SCRIPT.md, build.py, cards.py, bedcal.py, broll/, with a\n`director/` folder beside it (harvest_assets.py, assemble_film.py,\ncards_html.py, device_frame.py). If none exists yet, this file is the spec.\n\n## 0. Verify claims about the reference, including mine\n\nEverything in this file that is a measurement carries the measurement. Where it\ndoes not, it is flagged UNVERIFIED. Honour that distinction and extend it:\nwhen a subagent reports a finding about the corpus, **re-measure it yourself\nbefore acting on it**. A wrong belief about the reference propagates into every\nfilm you build from it.\n\nVerified 2026-08-01, reproducible:\n- corpus audio: stereo 48kHz, mean -18.6 to -21.2dB, peaks -1.1 to -3.2dB\n- bed `Slow Drift Ambient Synth.caf`: 19.009909s long, trough -37.5dB at 4s\n and -36.4dB at 5s against -17 to -25dB elsewhere\n- `ffmpeg -h filter=alimiter` -> `level <boolean> auto level (default true)`\n\n## 1. Derive the grammar — never assume it\n\nIf a catalog of reference films exists (e.g. an internal showcase catalog of\n~48 films), **measure it**: sample 5+ films at 1Hz across their whole timelines,\nclassify every frame by border signature, and check the segment order agrees\nacross all of them. Measure cross-dissolves off the luma ramp.\n\nA grammar derived this way on one internal catalog was reported as:\n`logo 3 | b-roll 23 | motion 23 | demo 81 | motion 22 | logo 3`.\n\n**UNVERIFIED — treat as a starting hypothesis, not a spec.** Those numbers come\nfrom a subagent that said it classified frames at 1Hz across five films. The\nmethod is sound but I have not independently reproduced the timings, and a\ndifferent claim from the same report ("no voiceover") turned out to be false.\nRe-measure before you build to these numbers.\n\n**The reference catalog films ARE narrated.** Measured 2026-08-01 across three of\nthem: stereo 48kHz, mean -18.6 to -21.2dB, peaks -1.1 to -3.2dB, with level\nswinging -58 -> -39 -> -18 -> -22 -> -16 across 3s windows — the dynamic\nsignature of speech with sentence pauses, not a flat music bed.\n\nAn earlier version of this skill claimed the corpus had "no voiceover at all".\nThat was a subagent's assertion I wrote down without measuring, and it was\nWRONG. It nearly caused another session to tear out a working TTS pipeline.\n**Measure the reference audio yourself before you believe anything about it** —\n`volumedetect` over the whole file, then per-3s windows to see whether the level\nmoves. Flat means bed; swinging means voice.\n\n## 2. Freeze the beatmap before capturing anything\n\nOne row per beat: what is on screen, what the VO says, the window length, and\n**the visible proof**. A beat without visible proof is a claim, and claims get\ncut. Parallel work before the beatmap is frozen produces pieces that don't cut\ntogether.\n\n## 3. Capture\n\n**Tab-only, always.** Desktop screen capture leaked private windows three\nseparate ways on this machine — see `/tab-film`. Use the browser extension's\nrecorder and drive frames with `wait` actions, not `screenshot` (same frames,\nwithout flooding your context).\n\nProduct capture rules learned the expensive way:\n- Citations resolve only when a message **completes**, and never inside a\n markdown table cell — only in prose. Mid-stream frames carry raw\n `[doc:turnNdocN]` tokens.\n- A follow-up in an existing thread answers from history without re-calling\n tools, so it has **no citations at all**. Fresh chat every time.\n- Show the user's prompt in frame. Three "ask it for…" VO lines over answers\n with no visible question is a reviewer's first finding.\n\n## 4. Narrate\n\nVoice `en-US-AndrewMultilingualNeural`. If Azure Speech is **Entra-only** in\nyour tenant (local keys disabled on every Speech resource):\n\n```\nAuthorization: aad#<resourceId>#<token>\nresourceId /subscriptions/<subscription-id>/resourceGroups/<resource-group>/\n providers/Microsoft.CognitiveServices/accounts/<speech-resource>\ntoken az account get-access-token --resource https://cognitiveservices.azure.com\n```\n\n**Local fallback: macOS `say -v Daniel`.** Same slot structure, same fit-gate. A\nfilm with a lesser voice ships; a film with no voice does not.\n\n**Fit-gate every slot.** Read must land inside its window with air at the tail.\nIf it does not fit, widen the window or shorten the copy — **never speed up the\nread**. Over ~2.6 words/sec reads rushed; name the slot and fix it.\n\n## 5. Mix — three traps that each cost a rebuild\n\nContract: VO +6dB · bed at a level that is actually audible · `sidechaincompress=\nthreshold=0.015:ratio=8:attack=25:release=450:makeup=1` · `alimiter` ·\n**NEVER loudnorm**.\n\n1. **`alimiter` has `level=true` by default**, which makes it a *normaliser* that\n lifts the mix until peaks hit the ceiling. Lowering the ceiling makes clipping\n WORSE. Use `alimiter=level=disabled:limit=0.891` (-1.0 dBFS).\n2. **`amix` adopts the FIRST input's channel layout.** A mono VO bus silently\n collapses a stereo bed to mono. Check `side` channel energy in the output.\n3. **The Apple Loops bed loops every 19.0s with a -37dB trough 4-6s in.** If a\n segment cut lands on it, it reads as dead audio. Mix the bed against a\n half-loop-offset copy of itself — same material, range drops from 12dB to\n under 3dB.\n\nGate: VO slots mean > -19dB; bed audible in every gap (~-27dB, not -50dB);\npeak below 0.0dB with nothing pinned at full scale; genuinely stereo.\n\n## 6. Never motion-interpolate text\n\n`minterpolate` with motion compensation warps pixels along estimated motion\nvectors. Between frames of *different text* it produces unreadable ghosted soup.\nHard cuts, or crossfades <=0.3s. This shipped once.\n\n## 7. Customer-facing versus internal\n\nTwo cuts, two vocabularies. Internal may name the build system. **Customer-facing\nmust not** — no RAPP, Factory, RAPPlication, MVP, prototype, pipeline, brainstem,\negg. Put a vocabulary gate in the build script that hard-fails on those in\nnarration and card strings, and know it **cannot see the pixels of captured\nshots** — check frames by eye.\n\nSynthetic data: badge on every data frame, and the disclaimer card lands\n**before** the first data frame, not after. Show roles, never invented person\nnames.\n\n## 8. B-roll must argue the scenario\n\nHarvested stock that would drop unchanged into any other film is filler. If the\ncorpus has nothing that fits the domain, **cut the block short rather than pad\nit** — and say so, so someone can source real footage. Never let b-roll carry\nanother agent's product UI, customer name or scenario.\n\n## 9. The gate\n\n- Longest unchanged frame <= 5.0s.\n- **Watch it.** Frames at ~1Hz across the whole timeline, READ them. A green\n build is not a watched film — this failed repeatedly, once shipping a smeared\n unwatchable cut and once a frame with raw citation tokens.\n- Then a **separate blind adversarial reviewer** against the reference film, on\n grammar, pacing, legibility, audio and claim-vs-proof. Fix blockers, rebuild,\n re-review. Loop until PASS with zero blockers — **and if you stop short, name\n exactly what is still wrong.** A known flaw named is fine; one the customer\n finds is not.\n\n## Related\n\n`/tab-film` (capture detail) · `/cs-agent-live` (get the agent presentable\nfirst) · `/msft-deck` (the deck that travels with it)'
# Ordered commands lifted verbatim from the capability's own documentation.
STEPS = []
class ShowcaseFilmAgent(BasicAgent):
def __init__(self):
self.name = 'ShowcaseFilm'
self.metadata = {
"name": "ShowcaseFilm",
"description": "Produce a catalog-quality showcase film from any source \u2014 an agent, an app, a portal, a process. The full pipeline: derive grammar from reference films, write the beatmap, capture, narrate, mix, gate. Trigger on any request for a showcase, demo film, sizzle reel, walkthrough or customer-facing video.",
"parameters": {
"type": "object",
"properties": {},
"required": []
}
}
super().__init__(name=self.name, metadata=self.metadata)
def perform(self, **kwargs): # toaster:generated-perform
return json.dumps({"status": "ok", "instructions": INSTRUCTIONS,
"inputs": kwargs,
"note": "Prose-only capability: follow INSTRUCTIONS "
"with the given inputs."}, indent=2)
if __name__ == "__main__":
# echo '{"arg": "value"}' | python3 showcase_film_agent.py
# python3 showcase_film_agent.py '{"arg": "value"}'
# python3 showcase_film_agent.py --tool # emit the JSON tool contract
_a = sys.argv[1:]
if _a and _a[0] == "--tool":
print(json.dumps(ShowcaseFilmAgent().to_tool(), indent=2))
else:
_raw = _a[0] if _a else (sys.stdin.read().strip() or "{}")
print(ShowcaseFilmAgent().perform(**json.loads(_raw)))
# rci-capsule:v1:H4sIAAAAAAAC/6V7aXPqWLLtX1G4P3SVsY0GkNDprooQswAxSSDg+kZbw9YAmtCIuO/2b3+5t8DnVMf79k5UhLGQ9s6dmWvlypTrf16MIvfi9OVHVATB24uNMiv1k9yPo5cfL+s0tgsLUQZlGbkRxO77tTACP6+pzIsry8gQ5fhBSDlpHFJGBJfjIoX7PwuWZjpwhTJcFOVv5FOSwE8qiVNYiXxKYwtl2QelebAM7E4lfoICP0I/KBulfokoNzXC0Eib9VPkoBRFVrNn9kZVqZ8jKoenTWTkoQHrW0aSFyl6oyIjTY0cPoT+7Y1y4SPsk/qui1IqjoitKboWKMspJ07BmueB3mDvMCZbvFGZf78HCO5EYHFlBJfcS+PC9Sh4xCqyPA5R+u4Ylh+5VOnbKP54eXtBNyNMApS9/Piv/3578eHz07l+lOVpYWHnwrcvf6MU44IfNf7Dnbln5JQXB3ZGFcln9Bltv49uGukPqgYvw5nB9iT1wZS/Pv0b9kgT1b9nlJ/B8gzf+ehlb58RI7L0jaF79BvF0U4CTsxyWDmG0+QUbJog40K9cx+03afaVIggbu8s/cHa/d8//mJG4Qc2ldXwdPgDNvgiIWn/MwsK98/2F/g0gBBSftTYWsXpBbyYxORUcOTPaLKVFEXafoT2G9UfSZoirclndbCV1xr5SDb5SGoc1tTOyCcT2ZYRNB/TOAjaEBc/9yjjM/qy/RRZeZz+3B98BFGh/Jz6zTPSEjz2LyPLUN6shT+GZoD+hY3HVz4jstG/vDxstrBR6VvwPaQhggu/f1CyQ0VxhCh087M8o2oEyZ174GRYA2FnY+dnCbI+cNz+9jeK/qD2kMxOTVmB4YcQDTMGX+PbvhP6DRxlBQV2DORrhPCjoxKlNawMl8CLP7cguUGCCtHJINdDABh2UOqjZvdfrn9QugdbgAM+IzuG76MY7PXJAk5gABpsarfcj7byWB4NP6hpHOFwkT1sOCCYhZMV4GLDiXMEP/z8x2dUeSjCWVuYBN8ktGmOjXL8iBzj5ymtOE0KSLTX1xS9P2zDJuDEyFDgfEYmAghCysJe8CRs5+evrx+UBACP4YIJnICc/5ffMIUkBgY35HmUxxTCTvuMCAxg/UeaEvbwcxIREgsfjs3SLP9O995p5g2bT4jOh2SA070/bAYQ2X784wmRTu8yvb89QMH0PngKdnxnGYyON4KcDK5/MOQyh6/ipSBhqS81iCtqCDvnlBSaPnaZWke592EZztcPihE/aFoUaTGjAjgxZFTDMu+c8NEFJEI0OtlnRJE4vHP8R6e52AUTXQOzCmwsNObg+1GQoQoHHhvw5Thhglzq3cMJBEf5Axg8BOZMv6j3P6mvAJwWUP804ziAk/2JmSOmmou/2cgxigC8nhbo969HRjMf1LChZxyMJ0U/KD/CIcDIKsIm7T4jgMx3/aBi5z95/Aml39CH+4ELBUQSpZER/KS1nw9/Rv/u9Jrnfscp9TOfXl8hUIR4qW7rsTK4iJneIbHSOCPY8IGKgIHAcj8klQZzIuAyyzBASfZQBOyUWVNmnGIOyXw3Mpqigt1veci6NChHLsFec5vhQpWAID02M6CcwVnhvvCDUh5Wkq/eAVhZHAAZwQ3kDiooQoOCbROSotK3T5sqaDfor4waYwOTz7eHno6pjOyBQbjbyCCHv+ByTHHU/6HMd8yTFIs/hzGBM/lMylyP+eUqC5+bx76IIa+vP7nhGd88hVILW2D050ZKEOvVSQzHyHxAORAM/goT4OsrVPYYwhcVoYnSDFAVQkY2WuEndxCyyQwfUwv1iAUGKInDf8bQwWlHgktkw2cUIqhzNuYzkB4QHhM4QqY8A27DpgAboQRoCzYK6m+cE5eSJADzsyauUEBs3yGZmTdU3fAGiTTOiMa/1G+fL1FMlTHUhRjy5fPldwqSI4IlCT3FAHjKMQCApF5+E96D436SEtyJffbtnYfHtb/w2zO+TTpL29FT19jYu4+0+pXLfuY6ZCPBC87A/w8Ke5RXwgefUVaBw3DI37s9TB7vnEh+MM1vkEHkN/5pBgdpCyGIq+w7f+B8dh0ZoW/Bck9oYahAziDLa7bLIAgNwRtFhr7TCkpWToVF5luYVhuwRBQyUigQKQXRyHAeE9jhhLj4kPcklI+AP2jdM2zqr1HEWQaI/XyBNTWcj1WT4Y8cBRmFtUJKYCLjsgS6E04VEWtx3Jsw+5i7DVIk8Qqfkb5dLScgGnLgRbASNAA+DyRbhAED3AL6F6+JkwFuIClkELWEnaxp6rck/sDJ8eSRvxZBUqW+y+lfMg1XTkACqN1GSTQ1FJPlIx5AFGUM9INslIN2+qKIN/D6DU9iyYEFDpT7BKTuL/EEkzOEb0PkJITGmiQJYQ2A55gECzItw8H6B/WdO8014vunSGLhdkjY+1/U/PMkjaYn5j/OgZ9aAQ+mUFUTIvOM/AeY0igj8Cf0MAhFb80lvOR+BSCus7fmaOQIYG7k5h4JGHYu/qb0M6wBsK6InUaD4LW/w/yX7xsVRvLrURoageciKHugpz+otZFCVkEhJfr3cZxfT4hlWBrfsXcbYsog4MgiQg5LsDj6e46lOcA4domjnx7jPqhB0+s8eMMw3+MowKo2gEqRYX4YouySx8nDG8/eCM5tXCAHoXUogUl+BhRTBmASJUZKrsMq2JcES6FhgeO/Gzsc+a92DntiZvr6oHbZ42AQEgBKIxZxav8dUACq/FEjwUk2UQ4Pcidg/6oMHzLPaPqiButfjc2gAOCb3wj/No9AvX4GwwnimGhN0mJYMVDGLf+dOKjpW/PvI6cF9GP44ISosaHolmADS3JOovkGfm4QCwBapD5T2J/UQ+rC1hlwAUgOqGIgMkByvr42YW8kD6gw3GoYWKZB7b4QegAPQbZYCHjo4Tmypk/iDSWCUnz7PcM1NXy6BCt5qFRGhRf6+i87tn7g+rKED8v//gLYXcDuD2ywhLscEJbvRYJXBEonSgp7BMfSwDSTVbjwkkIGYYTeqP7OZVDj0EkFBE4UrBsHuBuMMXd5wH6vr0CQ1rdPGoLEkACgZh7IILjSCCaspYhBKug14lzgONx6whnDBNfg5my4YuOq9PliZBe8DcABe4XlP18wQIkeawjoYTg2jKQI5uoH9EjPjjmToC+FBg1VZDfHT3Ez3/QfT5h0PqhlUzGJ+MecQ32h6H2nvkuRnaJKAXnrYycURrBEBeD1izR50h3njdrUJB+7YxTlqUEwBtDyYTWSdpDmBgiG34IYnEldEGAG9B0Ou43B03josQzOKzwe+f0HNubrCwS1RNp0/068DI20Yf/tn8/bZPvPv/2TxPtPjKHnRYpqQ136ntLgpvuXX999+8/28+YJtBEJ3PD8/d3FF/5sY7/+/AdhwrOLNGsrPi7bsZN/DGI38nOAh4pS3AJnbcOyQGDleDtymvfnon9icgIjH6sZWKuRWzERvsNnQM57c8f790OUl+dJ9qPdtp4bZY+NPgzs+Q9A2cNFmN0WxLsgqwLTsC4/MB2tVCAJkMTvJTU0Ih9B3CAuKmaKLAAGaSYtRLY39OHn780YSHo0iM3cAFgBl/amHkHL4SfZP0gf+7zjqROoZwP9UGrjx4KPGONNsQVbDDzQKDkVECUQPSYQz8r52NYnmoOoUMMPPkiX5Offe2BzsfQC4fpryWpmPaDyo4eeSeonsQBeCQ/h6NgUUEKO5TGmAQzaFf7q3ywIPihFdtbOkEXh74DsiszD5TnCTiJiF3sPm+74t2fXDEjqYrK6/ZRxGMkAiORRqhAUCLAnywkoicTFDw5ijBoLqjMAvMVDb/pZ0LQpkLYYc8qj0/yeakDIIMo1ETUY7o/bv7AXgXP8CNMvZFH2B5a2mIriwP6D/qCZ7o8Uo+iP3g8jzyFL/mDhCgLOz9AfnS79I4SqVyR/MF/fa/7sg5srOKrLEXQ80AUVdhSnIbgOnwI63tfXX27H/Nj0zX/gzvgLd4uPVhkXhcrzwRl4vwzH1KBe8VrwOOTZKzkqAWDgO/ljYgOOBcD4wUOCe/5jdIIINX1Qixg4riH276uPDazAT5IHiVP6aquOmmr8be4fjaFPVvpBLoPHeiK44jdQ+zRl98cqLpxsc04wB8qxHScP88byVtUgk5MCK2GIQhRByAIDCJCkvAQdJKAEImyCus5AMuJuixhkQYWCHEFNv0h6EBx5EI/4EdAwpJsm0f36XhlFKHXrZuyFsCaGjcE6DluH+yMpwV3+Io4TIi0hWvhTA0M8Ssme0H7nBMi4xzCl887jKRE2GE8kiHnPFh5PPzFcs2b6REZkDTwg0jYppVhkNxBoBJz9PXpplvKMwHnHlrxDV5+hvAEnVok5keVP5YRhFgJtpD6egqdGBKLCTvEBSJVmWGxxTJaEfhZQy9l9koQTeIjACAM0a3o43GyJdv8fjT0PyPjPsuOCwvzt3++sgNs4TCrvXdru//6Pz4iMeaE7AEqhyaz3wXRNlwDpFDXwJFP5DLgX/QPYPCqgQgM2m0A+iYGHEkuYpxkjvJPhRBIHmBqxIiO1Lvzl6lez22PqgPEMioYUQNBiaYIl8A0FeISCp3+42mN/2Y8HPqOSDHmhw+ijvMLC9qGcwNevP1t4vPUrjuO3si4IGxJF5nrAVLAkFCM8c5kaqY1zAAQQHuzj1tUxbHjkn4ATjowacD8JtSEhZf1n4yJACv/newCopEX2PaPBN2pV/Fg+r3A1sQyzCAw8sAWt8ZzlhFDMvkn41/k6Tvv/2ASaLFxhIGDfnRyuU1tpvX6jxgb2D3QC+NfAt4hr3yhlD9+BM/I4rxOois/OEg/SSSKjEMQ1coFu1qQN/bazJu9Pnnh8mEYEx+NNBbgPDPODR7+AZz5YIDWziuf8GI/WcVX+OXK5RJB/ECHQ1AB8XLNRc/pHAkBAHwIeagluBbKfp23GcI/IA/2iuokJGaui3Lco28iNH5Rp2C76qcTwxeapxgQyjvCzZkiQNjYSIsC1oGnYXl/JXY28/PV5MpNwIHofjfJNoWHG7cujHSjxDMPG/WkWE2eApc+06UHyNmM5EkcjdYtH8bVAT6Z+jO+bNm8scJrmMZk54k40LgKbEAbkMyZMPMIns2/8SquZKhDt0rwvCLB1stOIge/xR/YNdbKm4z+I3o5DyAQ8V7Ueo3YzwDsTzQFc9ej0gXgSA0LyyxyBOBPLsSwmTUQGyYonlRDY5ztBAB9IuDjOoY16Ugb0Uc/5JOl7PqPnZOQ5d0kendxOfvt+49bABGuhh7eebhWbd4nuQ+6/Q40A/4CDf7qqme7+8w/QM3TTRr2+6kaORT6pZePvqeO//zo6/o/BMaBrJA0f8108sQUiwqTdoMPPHhOrCi+Nt8Uh+dZOODYAF7ieIqBiCDFu3DGvNCTzeCcIFE9SH1cCslDTTRaNPCO3P5KxYVRoGr87tl8bRa1pYV9fv3t7E44ABG9jrjJwJfpupMAFz7r21ylT80I0Jod8zKeBQwgbvUEcXd/08Yvht8c46nse8l5m72RcAp0jFE+SULDr21MlvuEFoRdtDPggZf0hhtaSqjYnu6M0/n70p+IlAtsho66MDDpwnr6R9MCrohswIWnhG3EJlQQSjbxUamQLJqAITxUr8ozdgCaCYodzl2itR8rh5XBrmT1C+8y4LcIVjUjdX+Yh1G/PwYONsLz//Vtytq3snaT2ewA9D9wIPRLZqJmFY2ULP3GccZMCjPPLo2Hm5O+ggi9fzSteGz1JASR2iQmT+MrPf395ewHeh/Cj55tnfLyXHy/q443KGKyEm3A2hAgYLHv58T8v+GUannHiN9f/879vL/j9uA8J2LzHxkUDVojNM5TfF/g6gZMDP4bNzcRy4Csbr0Qmr/iDyXfgmWknk6Xm36DN708sK1jqbCZ2GevCSb2cuanJpVAXi3E26S5Me2H0RdfQCidwsyJdyOn8OlIHxjTcq93zaH9eh/P28SB6XGFr3UvJRop7mW1LIY86t9suD08j1RrVyO+d72s9Z49K+yCbIlswS+FiMBl3Fhbz1mLOHcxBcbPW69IoJrTv56rH0IJmdrnKtlmhf+iwaB7xASPcroEu3thNp8212+y63TMcNRSVSetUM4dD58Dpxe0+qxmzVNG4FYc1p09WQJHm8Z7rjLdj9zxinV2S28u4XXTQpK0nZzufaA5tCYfU1KRrZ1XsaWO61Rft3WHr8QqDciHKbGs5PS64FVOpB5ZHTHjk0kA/T+gl13POkngVDslR6XbDc0qbM6ZUAtN2SvE4MW/JsVyuGdM+s2buZWOtk/RvonVsJ710V5pmrtrpsUqn4a47nZViPBRiXRT2nHBJzOl+ozP24eAydhAwyxOTJu3LPe9omdW/nJjS2iGO6wrVfH2V9Zvd5pcHJlzfYtZe+4HSvne6aDpotaYDZjXmlkwWeJwld9b68tyvr4PqyDp0aiVr/3Jgth57vfkSajkTfzUX0HoA7jlPj0Uwa507LVOp6/Z41HPKcsFk00AsZDU1LtsJq52MIlqLi9NdW2mX7TkpRWd6uHWs9Xhvj3dW+xBy1mHpdcq1FXEiLR6C7q3oBkN2bmaiK570w7WrJ2rATWs4t6hOeqa11Hn9dmJtflc5B67oKW1rodebLZPZh97UbLNJqVneIjssToFurtkLL7BqfT+1TVrZLOfRMlLvt4nhAWGO67gW9teDXuxa+kzsTZLysuh7g7boD3ZKm261Wgqr96s1747jAz9FYZe7FjWTnvqT8XF1KE6LXSdddYxVPS1c7TTpg6y82xGKOL2/4zoLQeiqO282M2T/4hRLV1IO9tIccXbLWogbh61vksWj/YZf65WtpYe6nZ51tWDmbce5i5x9CFq9nDOrkvHZ7DTLQ7/KA3fETJbCXKzYybCKKiZi9W6q++Y1689p9aIJmxlAKtmduVmrsqc0Jy+YMBOFS63NjGp6r5KgG80rpSfv2NvoLoxOZ1M5xTovjWPbvFaStVi3SuY2WRcufTmmlhkvNc8TFrP16oayZHncyOZICmeupc/ON2d6by/GhtnphPmS7qjFYjg8L3rhptiMlyf7fvI7WZQIquh0q8t4yztjpXOwe4VyrsJRsVtPOgcAprBdo9sukXem3ktzZlVaemuzp+k5nUcH1DazATMvAaJXQznc9MWtkx18b28xQyj9flhvo3tVRu6sO1AULaqjm8MJdTp1VeHOjt1tnus9qbXmYnRG0zQpT+GN886t1p7nDtswbss5XZnRSrJmy9ag7VyjmmGTU8UUDEr3NdTf2yFRwkiOuWF9vTMXZWm30RCZ9W467FyZZS5nx3tfXawvwuxUzDrXybaUM+keh0JgF22NXp55t6soeigrvbN9PZX2gVkfSss5cT1xBWBb68c5h5y1KZsxPz8O5ZnQWqi0cr/dxZ6nn5hhVqqLvjvtS0tzYSwZ6bKZ1sN4bY5i1pBHjH5l9nV5uNRFjzM3/N7d8KVdG72zOWD1amSsR0y5mY5b9S1P9pO5NR70GE+7boTZdlrspcvBYuD8Zd0vrlPvmmeTYhos6uO6H6X72/5W5ktBikc75R5EohKsWp0NV845UTfN0cGwV8y0lex3neteQT0zqaQ9zwfrhEZr0xPOq7LDbmf6fWJy04HkDTVuLt+O0S1eF31IPgfZbpk6khL4ozPtVdktvGa7tcJex6fQ7gw3Mjc7hmx7VrneeN7L+d0qGPQHs07JlZJgh8ElGCX2LDrvRv0r7Z120lWuN8nImofsJGxvR8PBirf6Cjt3kMa5+p5O3aNZryt7ezrZSPXrUW2pm6mv8nd5keyn2u0amcm9M62n42lE64ORrV+rqL9SJUM46FI/XXRG29i3tMLYWCUdFNqhpy2XYnvD3M7bcFEd9i1xMtwvttc6XE7Txd7Rj+fWxl3N8nvb5bfqfattTlxnur1PNy17qY0u21bvsmitOklb1g+XlEXnkWrLO+GMhMNNmWzrnL0oDnuem8pou5FHuVIcaQEd3JYC0r2cXdTBaRdfJ2aV+9tkBJpDSeOp0LbmI6ev6MfRYdca6nK2C5AfjXxzwhXBwunL3VNfl1rzVDZPea9IovVcVVyPKRnUmQ5nO3fp+cqKPvrueaouU9VKjNrrHuo132mV2u1U+ZK0vA494xyvpUC91rvOpt/eJEytdixrcTkvjZMk2ohb3te7SJfKS7XLdO60YwBIG6ekLzlzmV/W1jYeS8ZtnsjLyXELXaYjLa7HWtok8dXaLA7DQpWXu6G9Sa52Ze1b/kDKlkezDM3LSJmpF2+zDFxpztGFdBn7SDpckySogdS1YIdiq8PuLl3RLvfrU8eb+8wNdWl3cBf6spDuVEWg9QsfKZP5ddJ2t+Zmf0u1O5KzRbvszNQlJyCt3uuSuGBp7qgmmrs7852sKwTROpVSY6V3ljPNWIjd6VXfzcaq356ft0v/dKGV+bh1vQlJfzqP4/PBnqnThF/pfM4civNePdNoo6mBfx6m81zrTeoizgqZ7qwW6TUZS+0bOg2vo0lp5Y7OzBWGX7Y0Ke8Yzi23ArGCWMedbNEd15dpxXVGmRAv5X3m9/jDpsyFkeyofmwcNjO7ZyG/O0ZT18y2rdlpXMRc1OOHK0lSd8i9+Vybnhhbeh6dK20A5MRNWGl67dI3Y5ZcdsHsXJWxcIm7kVfLysZYd4PoWA31/KD4I36XzPvMsbPLpUN3OubOY2XbYqeToPSq0UJaLmc9Xj9b0bbeuAUdTQQtG7rbWbLf0zEdq2M756W+oEqH3ezojg0LPGkdeb6vzuflcTKpR/Kp9HZzd9LaTI1dn7b7Xpbwex4KG7Oxze6ps8+8wN4gdllflyDstO60u0vvjHtbFwu/w/UKyeia+vguMVLGzvqDUcvu39bOgFYHI97NplrSn7SPt8m+iDUpPnInjb0s2scaJfUpG49PILAydsuahpvnodLtO6BnzhevpU25M61X7omTQ9Vj53I3uA3NOFhX+jAbcpNWEiriGdl+T9dtZGjiQrP7XNkWpu323e+7u/n2kMz2F8WvN56qSLODLaeXKhsfh6wxX6w0xzbY002xVx1d9rBy9bx0ym54drfJtVPZthPGycf70vZ67tan1+vizMe3ULrxO/q4tZ1Q1Q6ZNTu2ir494eJ8I81a5iyfuf7EXu7S1gZx7prbp5J0lxXX6MqXub8X5as2mK/kG++coO0trKpIpgULGtoyQ89uO/2rs0I1KrnhvIpKvnVvRcF8eh0utK2sLXsyaDKmENfezWl7wbXsKYuO2O56ZxtNe3NTbPc240tnjqJ2pzIXdBHtYieam4xruJ0liOSRIMZqd+HP1xKHNm7LPIc8XWWanCdX/9a9gNDu3GKpRorZctQlG5ublrkeVtzCuvG2OLiwh3E10JDkjEQj64yP1/hQRLUY33a91sWYSdIsFFtJLlyZfj4eLOfCrL/oTDaVJEqLIBZG7npZbG+dqbwtBOdYg4cWy8mtnEvdbMa05yoXtpTTUbAPRzZOZZSIuspNg3N+b/mlP6gl/xpEKUqSSNKlg5YEJ9qlvamJisH9WC3p6kgHRjwD8e8NjtfhuD7XSz9UTb+tSLtqXmvSJdgsrj1tc6blaKFx95q5j+mJmyy6m5Y43+qOa7mTktVPXXOTX4Mlf94bpXACWyv5rtHB+NBddORgsG3t2etqc+oN78veaKXO5IwFdXTv74zFSMpmbdQ5tXr7djsY8PvDbGyUbNhx166bTLOtTG/uh4BTjy1py3Zni4tattar9SpKV1aP1m8rYDLGU6Iub0crd3up2peb4J03+d2JtG6nuHvxLr2OhDWTzq3SEflFu+WbnujIFuqPudluoRdma+AtRmttdcpEJPd641t5sAQjVNun/Lq3gmurxY4zJ5wl3T7NppPAgRiEbritV5Vx1s7GrjMQq9EsvwhXNCm1WpFldqtd9xU0K+Wmx+2gGRMOeXE5j/lYXO9Fpzx6rH0esutT3OlZtcF1DE0b388ihKqzCfYlF7TOfJ+bbnrycbxczG0r7IhdUGx3W6ZZ3tXlg8nezNtV2x01Z9GVMtqS5P4mvfZba3Njt24tY8cvZLm/VMxl67JkBzvZWXT6e3UqLjbqHel0NgmWpRhN1dPKMxW9tT2cBqzoM4epluVTkUk9ZeYPh7e5P1c2VdU+no9tdBRGarhSZtDoncNTvIitwXLSzeJ7EM76fTFan+XdIAnX7MxSVfYylDvdab7XlxtaPM31PM2trmCdt/oBoFRUMfBnfMpH/HYsDZXCzbc9XzSvo/E14Vm1cxFXV+N2zgovqzZI42OuXhRO76i7njK8Z8be77VXPiqVepLMNkfLuWbH0Wq9dtM1J6zSOBldNNHeT3qo7N0uZze1h8npWA8lRtk7O6Hnu0t3trnlF7SfJMhNIlPa7nReLj2f89qeFydmf262xlUoddlUPRx2Gu8d7selUAuexpf+TJ+7m6s+22gRMz076ZiZ3WxLSSe7C93eo3AojLrhdTlsmfT9uDvQYbpZt+8FLxirjnBsuWFXK+jzXJavCq335c1+t1/B9vlYvOnnYT4d6Jon1JCjPWWXxqvZSI9Y1maHXS1LaxYa3m1v1lrfvamyvfeW/XSWJYWt0sV0queD694eptpl7e2qY792l/N8MbpK7YjJ7jdBMGWo7a6aTm7Hq94tynMPGQL8F4/nCdNm0uPO6wl7T2zfhsOOvCgqIVjotxotaR0+LNdrBRqwJOJ3XjS6W3XdW8qtWt0b8h7kj3OIl8v80jWiRNHrWdyZ990o694OGX9G2j0poLMyK3dxGnD+vTtLOoK3pbfD8UwYXM+7tZNE06kV7OSldd4L28soDHzDXRsiTU/sa2IUy2Jvr8p+2PZP5WKuDHl2vuZo7dpfXdxWfmndQ7PaeWg4vLM7lI1MYENvhdpqbg4Kdb9on9vzvp+2PHt+Fyetk3tJemdtta7VahW0FF6b67uFINqn4D4UV21I58oKlPON9aCazgfSZKbW6WUzvoW1U4szwaTjs+P3Fmx4PFn1LSvC7Lhy6MFtkYa031NiZjBkoyDUjcNcvJr+bS7t1Z0eMhuVR6m5unu3o7LTRH5WlI6sZp3+yHJu3l2WhvJiURyHk1OxGdlD89watfiLXlkqUOzZ7zL7VLTvV8uJfdmaj3k14OX7oQdt/dDwb9Fqs06rQSJ2hLnSVQ5dZuj69SU7Rct2PuiPgupKt6GerZ1D3lofhY5xk5YTwRfsxMiS2XziTrT+rX+c0sawYDvK2Q4m88XxqEnSwL5nQ8fdK/rB0ZSr3J6NW1t3mSsCdsdMFlbXyXWuXYTTlruo0bakOREUZSioR/aSrk/MOCyPw6pT1PLS2Br61Yz6oNVVETHyrN3p8FO/t1xL42111u79CdQW5tS+SLzGrxxjc91y7cDyPC3uBBCMQ6viD/edPV1lHg/lPBBltOMH3XI9Fg+7HhM4WtGKFskIMn4uBslqG1TKYBeNMh5aEmiaN9HioO1coAN1UHaX6nE+FGaLmo9s7cwn8jkx9gPAcegHwWR8PB9YpLUmSuuwD/RZz1X7oiLbWp9dzw5ethAy9TyqxEV0yfrd87YzWvDj6OIczvvZxRive/c0CSrVuV57qNhs+BQtCqWMZ7tTbyOIiHZao1772BuehUO9PUy59X7qStLL2wv+G8vnfHYOafER2nA18wy2y8M1WrAMm3Zs0XF6XK+LbIehe47FOQKPWJo1ug7DCxyHOI7rIOhFbIPhaJMXEWKdXpezXv6XjGfjEv+lkgW7/NcLfg/6gwxpf/yyoxVHJUrz5ov3P8lE+uW/315SywczmA8aWxUULvzy/Mt8Mu7Gl8mLyn89/gbvOXTODffxP0E9/jS3WQYW+t//Czxvn/d3NgAA