@sns-myagent/cli 0.3.0 → 0.3.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -145,32 +145,35 @@ function createStrategy(name: string, options: Record<string, unknown>): Ensembl
145
145
  }
146
146
 
147
147
  function createResilientExecutor(
148
- config: ReturnType<typeof getAgentsConfig>["config"],
149
- options: EnsembleOptions,
148
+ config: ReturnType<typeof getAgentsConfig>["config"],
149
+ options: EnsembleOptions,
150
150
  ) {
151
- return async (role: string, prompt: string): Promise<AgentResponse> => {
152
- const agentConfig = config.agents[role];
153
- const modelKey = agentConfig?.model ?? "default";
154
-
155
- const breaker = resilience.getCircuitBreaker(modelKey);
156
-
157
- return resilience.withRetry(
158
- async () => {
159
- return resilience.withTimeout(
160
- async () => {
161
- // This will be replaced by actual agent execution via the wrapper
162
- throw new Error("executeAgent must be provided by caller");
163
- },
164
- options.taskTimeoutMs ?? config.task_timeout_ms ?? 120_000,
165
- `ensemble:${role}`,
166
- );
167
- },
168
- {
169
- maxAttempts: config.retry_attempts ?? 3,
170
- baseDelayMs: 1000,
171
- },
172
- );
173
- };
151
+ return async (role: string, prompt: string): Promise<AgentResponse> => {
152
+ const agentConfig = config.agents[role];
153
+ const modelKey = agentConfig?.model ?? "default";
154
+
155
+ const breaker = resilience.getCircuitBreaker(modelKey);
156
+
157
+ const result = await resilience.withRetry(
158
+ async () => {
159
+ return resilience.withTimeout(
160
+ async () => {
161
+ // This will be replaced by actual agent execution via the wrapper
162
+ throw new Error("executeAgent must be provided by caller");
163
+ },
164
+ options.taskTimeoutMs ?? config.task_timeout_ms ?? 120_000,
165
+ `ensemble:${role}`,
166
+ );
167
+ },
168
+ {
169
+ maxAttempts: config.retry_attempts ?? 3,
170
+ baseDelayMs: 1000,
171
+ },
172
+ );
173
+ if (!result.success) throw result.error ?? new Error("resilient executor failed");
174
+ // Type guard: caller must inject a real AgentResponse executor.
175
+ return result.result as unknown as AgentResponse;
176
+ };
174
177
  }
175
178
 
176
179
  function buildCostBreakdown(
@@ -201,23 +204,26 @@ function buildCostBreakdown(
201
204
  * Convenience wrapper for non-ensemble usage.
202
205
  */
203
206
  export async function executeAgentTask(
204
- role: string,
205
- prompt: string,
206
- executeAgent: (role: string, prompt: string) => Promise<AgentResponse>,
207
- options: { timeoutMs?: number; retries?: number } = {},
207
+ role: string,
208
+ prompt: string,
209
+ executeAgent: (role: string, prompt: string) => Promise<AgentResponse>,
210
+ options: { timeoutMs?: number; retries?: number } = {},
208
211
  ): Promise<AgentResponse> {
209
- const config = getAgentsConfig().config;
210
- const timeoutMs = options.timeoutMs ?? config.task_timeout_ms ?? 120_000;
211
- const retries = options.retries ?? config.retry_attempts ?? 3;
212
-
213
- return resilience.withRetry(
214
- async () => resilience.withTimeout(
215
- () => executeAgent(role, prompt),
216
- timeoutMs,
217
- `agent:${role}`,
218
- ),
219
- { maxAttempts: retries },
220
- );
212
+ const config = getAgentsConfig().config;
213
+ const timeoutMs = options.timeoutMs ?? config.task_timeout_ms ?? 120_000;
214
+ const retries = options.retries ?? config.retry_attempts ?? 3;
215
+
216
+ const result = await resilience.withRetry(
217
+ async () =>
218
+ resilience.withTimeout(
219
+ () => executeAgent(role, prompt),
220
+ timeoutMs,
221
+ `agent:${role}`,
222
+ ),
223
+ { maxAttempts: retries },
224
+ );
225
+ if (!result.success) throw result.error ?? new Error("agent task failed");
226
+ return result.result as unknown as AgentResponse;
221
227
  }
222
228
 
223
229
  export { getAgentsConfig } from "./config.js";
@@ -54,16 +54,15 @@ export class ConsensusStrategy implements EnsembleStrategy {
54
54
  const { winner, agreement } = this.#findConsensus(candidates);
55
55
 
56
56
  return {
57
- final: winner.content,
58
- responses: allResponses,
59
- strategy: this.name,
60
- rounds: 1,
61
- totalTimeMs: Date.now() - startTime,
62
- totalTokens: aggregateTokens(allResponses),
63
- winner: winner.role,
64
- metadata: { agreement, threshold: this.#threshold, met: agreement >= this.#threshold },
65
- };
66
- }
57
+ final: winner.content,
58
+ responses: allResponses,
59
+ strategy: this.name,
60
+ rounds: 1,
61
+ totalTimeMs: Date.now() - startTime,
62
+ totalTokens: aggregateTokens(allResponses),
63
+ winner: winner.role,
64
+ };
65
+ }
67
66
 
68
67
  #findConsensus(candidates: AgentResponse[]): { winner: AgentResponse; agreement: number } {
69
68
  if (candidates.length === 1) return { winner: candidates[0], agreement: 1 };
@@ -0,0 +1,12 @@
1
+ /**
2
+ * Ensemble strategies — barrel export
3
+ */
4
+
5
+ export { ConsensusStrategy } from "./consensus.js";
6
+ export type { ConsensusOptions } from "./consensus.js";
7
+ export { CriticStrategy } from "./critic.js";
8
+ export type { CriticOptions } from "./critic.js";
9
+ export { BestOfNStrategy } from "./best-of-n.js";
10
+ export type { BestOfNOptions } from "./best-of-n.js";
11
+ export type { AgentResponse, EnsembleResult, EnsembleStrategy } from "./types.js";
12
+ export { aggregateTokens } from "./types.js";
package/src/cli/index.ts CHANGED
@@ -34,7 +34,11 @@ import { fileURLToPath } from "node:url";
34
34
  function readPackageVersion(): string {
35
35
  const fromDefine = process.env.PKG_VERSION;
36
36
  if (typeof fromDefine === "string" && fromDefine.length > 0) {
37
- return fromDefine;
37
+ // Bun's --define injects the literal value as written. When the value
38
+ // is a JSON string (e.g. --define process.env.PKG_VERSION='"0.3.0"'),
39
+ // the surrounding quotes leak into process.env. Strip them.
40
+ const stripped = fromDefine.replace(/^["']|["']$/g, "");
41
+ if (stripped.length > 0) return stripped;
38
42
  }
39
43
  try {
40
44
  const here = dirname(fileURLToPath(import.meta.url));
@@ -329,13 +333,17 @@ function setByPath(obj: Record<string, unknown>, path: string, value: unknown):
329
333
 
330
334
  // ---------- router ----------
331
335
 
332
- const HELP = `Usage: snscoder <command> [options]
336
+ const HELP = `Usage: snscoder [command] [options]
337
+
338
+ If no command is given, starts the full agent interactive mode.
333
339
 
334
340
  Commands:
341
+ (none) start full agent interactive mode (default)
342
+ agent alias for default
335
343
  version print package version
336
344
  init create .sns-myagent/config.json (defaults)
337
345
  chat [--stub] start interactive chat (stub for Phase 2B)
338
- launch start full agent interactive mode
346
+ launch alias for default
339
347
  config show print current config
340
348
  config get <key> read a dot-path value (e.g. model.provider)
341
349
  config set <key> <value> update a dot-path value
@@ -348,6 +356,10 @@ export async function runCliAsync(argv: string[]): Promise<number> {
348
356
  const [cmd, ...rest] = argv;
349
357
  switch (cmd) {
350
358
  case undefined:
359
+ case "agent":
360
+ case "launch":
361
+ // No-arg `snscoder` (or explicit `agent`/`launch`) → start full agent mode.
362
+ return cmdLaunch(rest);
351
363
  case "help":
352
364
  case "--help":
353
365
  case "-h":
@@ -1,2 +0,0 @@
1
- ["configuration.md","faq.md","installation.md","memory.md","tbm.md","terminal-ui.md","troubleshooting.md"]
2
- H4sIAAAAAAACA9V963IjR5beq6S7pW2AxIW3brUwUs/w1mqueBuCLVkWFUQBKBIlAlU1VQWSGNOKjYnYjf2xEd71Ktb+MY6JcDj8AvtG/QR+BH/fOZl1AcBW256QZluXBqryevLkuX6Z+PbJU7MbhVfB9TTxsiAKzZl/5Sd+OPAvwovw6VNzGA3kBb8+mNfB2DcP5nSaxFGKT3jWlD/2L35iuV6rPZBmWzNvMu6xShJ97w+y5ti/9cdGXxot+0O7lYZpczLzrv0wm6/4NvWTaq3alTce973BTd020PLDWxbdD2+DJAonaMXcekng9cd+yjIX4WkSREmQzTpuIK6xV9JB8W15G6/Mnn/lTcdZysYwS0ud19Px2BKwSrler8cJoJB59+Pf4F9zeHjEvm+DoZ+k9uEv/u9FGLshdS5CY6LYD71APhrjxcHljQ+SffQfT073j7cPLrdPDy6/3P/mP+n7STT0xx1zHWfNrYiTRpUwGyVRHAwWm9g+Pn9zdnJ6sLu8lcHYmw79ZhqFoY/2mhtrG8/Xnq9vabuDaZpFE9to30v9y2mCSqMsizvt9hg8Oh5FadZZX9/a3GrfrqPUU3MyHnsTzwx15Sq9yZvNuTGGUahc75bMrrlxNDK/9GLZqVy6AXXsglVGfR5F478YBnt8LhmHKSua+ckkCL2x45nxOLrzh5eDaDLxwmFqHxvTNOO0+AyxVHy5Dkpf+tOw+BLPslEUbpbqgXMsH4FvbpZ3lExMM7ky7eJJOppmw+jOtpz4v5sGiX/pxVwKDN1kydQ3wnbb6Y3p+1dR4hv/3h9MsyC8Vi7uJ9EdhI3tZ+R7Q8iWVOtqiTu/f5n6XjIY2ULFSg+ngxv+dx3pkJ6aCE/7iXfrNwxajcHHFT448idRMjN/2VwwkUHKZMHIkLVDRw7ucyxPiAeTEKXiwJT+PM0fPuindBZSM6G9Nfw1HkzYwrB/GXvZqGPmVIz22hr2WWji3V/eRckNlukSL5PAx5I8XxNxNs2iy3QK9kiC3/vFQuU07t4E47/wzXYRpjJIofEQTDvISHHTauvzfJ7jyAOtv/3OVP88dZPke39oYCOkmZdk07jKbbunf+kyJ+e5QSzEwKa5peLDnPn1qdm/9ybx2O/ot6YJvQkW/Qo2TzpLM3+iz6GNVGBAY8T37pmXXLOliyfN2cWThrl48htRNbArMv8+wzbOokE0bmufzVKbUrhNNr148l2FpLuwQ8y/BYIOMNBlW7g0l7cH/za4Q+YzVQsoG/lc/6GX3BizsCvkMSRNcD0S3ZNmie9Bj10XAmwADrgcoYAUKp5DnNxQl1zCXBTZvkCu8wiSz+xMh9d+Zo68EGIrMbXTsQfraGje/c2P5nQEK8hs1s3/0wyfmqw/cUZvGGVmhn4CMj8NX3/4K2wO3wyjQdpGwdZkaKDPYEmlwXVosPsxLLFxq9Zw2Xb+ytnO6ji4r2Xnwe23khsx50rMORVVK5QW/wnMn+0DgycGJhwe9D6bRdOkqWZRE89e9ayTsGB/sv62s1cXm8hN2Uor3ePu5dHJ3v6h9I6tnEA7OxNTrUs28Zg1W27m9Ozkq4O9/bOlLeUmJwrnIynX3j05fn3wxeXp9vkbNrArBrJbUYoXQ5HC6m0/G7Sh/eYcq2I6+0cnZ99c7u2U2lEFCR7PPFrbRVt8Io3lKrSnDlbBBXCHKFbFa/TGVfeSRb6JpuCs8FlmQh/MnEXGHwa5PwbBOoUFOGuZcx++FfagEZ3dkU7MysUTbzgUbVPIUGHO9iia+O0pBGw7VhcvvXiyYuukd0E2GLlpoUsYR2ul1z7UmYnUX0DRkXMQ8hLsNF8HLVJZYylZ7Qy9WNdI3527qZgRlMeYVsbQjykBwsHMBCG0Kib87u/+iyPFNAa1ffckxIzooGd+mhWlkonQtXURPmnAl39NwxRdjGc0Q0Hd305RHAVSuzhf+KGfeGP99tS8ie5MkILK+N8wuBIHNjNXCVjgNDDbHO2vWTYawXZqwtqqucfGH0RK/Tpb8MwEbBs047GXYTUmdqZXCVQojSsl2cbaKtYgTb1ryElMOfOvlS/SBoXLTRbFcMfihrmNgoEv26kBsg/NC5JqHM1EtFi7MG0ZsK85mul4IH+DOKX3gOl4GV6iD2wDckQj9zFgvoxnDbuAVUYdVOIglLE585Er8SE1QZYaCG4jDNMyp+NpulRWtz6AwBGaT2z7u4cHqRD6CF5s6Rnp3TDRJK47l8NukOpoq5Rwr3S8/vjKkG+n19UZywxTLI/xMKd8fTnDaazKrN6ALwVZpAK72Z8GkEzca6mQtknSFpTFt3zau15oDvgEIxBiR2jHilhM6gphk5kRt70u0/7GTxc2/E9szJY5yNyuSa2v38BY+Y2NiCxulInBp06utsxJkssaLidktoi+XiF6pb9eJTzQa1Vl3YH2n8s2zv1rcB/MQV9HEYTBZDoxaewPdIWb5mz7qGM2zBc74ANo2doWPq5ifWlWUhwM6yy1F6Q39EPWzNGOqW0sLbN7+rYDHTaTySYhv/PxSbdjDoNwet/AFAcn3Yb5OghhcIDyX3cPN+pupHsRFskJYSeAjtFU63sd63HUAmOHysG+Y8GhSaZhFkx8LBmeuorpABuwtCSsSMeCEmogZA6uQI+UzGNqrz43663N1vpWfY5pEvaX0c2wg3YMAqkQeIYTMLUyIeAHw1LPAkQIZ7pmp4gfJN0R2Gluud5C8vjFOmEzcmoTVXSQIPDZh79Wg2WPT2CsiOKbD3OK8rRhvyXBTr613vdieLOqOB8QYL1OlxQb43Hb6tbjyA6Qu5v68h6bjlvOejB4MPBBeoYYuclI7XSOrFRgmKgIL/Hnin23i70OPdODmddTrYpFND0t1u5BuIBLv1Uv8Ltaq9U+29/eO9pH8adapl4Rd0NyldWBeXQRCz9sphD92CjSc6+d77PP6GfBwqJg8WZVDZrrXO74RekiSocmZNFRGvChF/rRNB3PpK8ThAa8ATnEcGsa5d2uHSLcMevQmVqv2XQt9YSxSsNuFdtGJKtJp3EcJVlh+WODpDGUmV8i7r66RKY/y227Wm8atObchV5Bw69HQWGqWF2H8FM0HQ911laMrKzYEMjKiqnZtuuICFFKN4OwYX7vJ1FTJGjDdH97GGCNV82t+P/Gn/T94RDdp3gGJRyPWqU2GUxhq2P/2oNt4o0DL0XToi3GQeiDRRsQ5bFqA1AP9mHQD8YIsNtmaF+trGA0fgZelWJx4gLk7SusBrk48dSmEX1YVk7Y7FbYpFVuh1lgezjcPZrrYBxhCexipeZOtrf1vyEXKEucIMNT0N+DASJUt5zgQZCSNTrvsxhbFTEfLFf/skLnO0d8X9LMz9J8ddAiq/lXV8EgEANQjSnRagNvMMLEIUchOd0UGkJnECSlKkPw1ECnxlM8Z2AmtbsacrM59MnMajhZbk7NpkQtpmGg6RzRGLSgED5MzYu15su1j7Hr0Z6OTERAhaAtaIaKzQIHVOwaKx84XTqM39XUY6zPyV4ViNUtTO6GfodcEjoHduPAsYTXMUJgIX40cocXWts+an5UE2t59eNvPp58jN4Z3LMeatGhfy87ttLbbiR7N41oR72mMonuSOx4Jrxid07uCmkIbTyryLzJFLxC/YFRggogqWUct13PZ7FVgutrzXVV6rIpwPGRtZ5MjXZSylC0ia7yQc4TsouYMlNZrv+DkgbjuoCNhfetBm8s1Q7kaLq5hX00LNlG21DnOgFnQCk3USmJaSOmW06BbTzJjbvUu9Kuv5RvolPJTP7SxBpI0CsrT3AZUn0iUyYBdraYJojuQ2i28BfCD2ivh8ZAvAGUP2xwDztCihU6IGITb87PT7ti71cURwo3MRKFMABnk3Re7uachGqlYN1n4O/bvJSjFsypEeSf7IUEBMpciQa4xqpj+QjDB7aqN8M4aGBhgLWy0SzagMGUuvPcypak+WKKeXBAryDo9mCjNq3F5XSOP2xBPp8Ggxu1amml0OvBADORHTJatDi4gQWHXStFIEuxiGIisZaI8x52F+NUSc/0YcaDZdG/1O59JMGFltpDagiZHXqfZFxmdH2R0Sm3x7JMcPljbjWtrMAupG6pmHAPaq+athqs+Bt2nki+JIALEiU0kWhQ5majsa1ZcxU1wniCdh9yW5eExrrsHrR398i+M66680XY1oOzdaXVl67FLiYP55OSeigNHlFR4D9pTr0Efbs4qFXzBXj1wZmbYSAabexW19QwyIb4qM5RTsUa/xouMmX3crNdN59Yvm781FXsuoggtCqSE/3khnnz2vymkmAfB7lopAHfg3eX2cI9M4qiG+w2tebT9hWiR6OmskZr8n0Ks4ihS9U54uGQ4yhAc9cfSkpdRctQoF5k2XRwgyFADfbwCtZtno6QCQ5GUEpiWWnejBJCXYx0FEy0juNWrFrP1O7EVOpxsjBLbnoi36kfoZoKxq7D+/LuQh2uHRP7w2DvvISqMxsGEdbOv5c41FD92IMrLuabaR87fexT9Pdu11rrrbUeVR/jV30fKjye9sdBOsIORwy1ofMs6AliYPqMj6CrkGRiz+woNWviguteK61XD+MJ6E9NIVl8hjnOfO5/LaS0haEewZCyC+DYMx+LGv8rK68pJJu0u8ScLqYfkXMkh7GyssA3tosFpimyjlIKIyozR0nbIupEyZQz/VnFbVVRDJu8OZZB15ZsffVRCzsAOVvTvEohE5jyT5HzT7w7KoTRtM99LjYSrDn00z7zAwTYsuxFu2I4gEJtS+FWSlGmTdtBH5S91pJzSm1gBfhqWVZej6O+hCndfFjvC3no5l2ZQZ/OMFww7EXXSHkPhiRnp1JjoRh7QTP3oCcac4LATgmcVZ/v8H6xq5I5pmGkfI32iLCJYqrnfI3KEt7G8feKiCUEow1uPJjSCjOIPPKx/NWo/vK4fvlbRT2s1KhkhA85NYphJ/fNoScxUPjMpGqzSRkLrdmbUwl5K+RWqj9t5WWLCeKNjda9OTzvspUQ5Zc0g80v4n9DKhSd0hpZLA0Dz++KzJRKz9H8g3kh/8coh3QBGb7oDf3bnIYw7qyHv525mArlgcZkVlb8gOY22iNzraxE/OhUFkUHEzd9KPcWMUxSiNPtlXhtfgv3GmJoshEt+xN6olexHmBgAYHgLzUerAud7wfHWDtTCYyVo0g60YZTBza4KkHaVOgQ8gvlpFIOBqlrjUKvo7KtKjVqkXhS4Gg7Gz+pz8u2JVIEHUAYOLkwLxTgDWvjb2Az9hP/bqFJPszpJ7iTvGoeciuiUaXqMR+mfAgIVv7ZNAdIBiOob6oDa8XpOgYX+PcXTyry4KAatLMMTyoXTG912SxPu4hh62qsv1xVxUX3NbCh6W+5Jb5PW1Fy/V3N0ap41q5DaGPvzEfhyOCesTvDLWvnPZRcTkd29JuNjRItda1r4e1krp4uadT8ALWAyk1QFH+1oca31lqby9RBqsYfvE5+TwbQiLfFDuGg+J17qDRACQfY5T5w7AcbqrR6vbqztkpEyyvBbPEThgEkXZHK4q0umBJWd6sy1/0vm96FZTtLeIu89P+lKgvOK5uMNtaLpQ6uIMXK3NTgDk5/WrK4+IQ1j3JRUpat2v7A5jjo6ZleE7IOs+5RM5OnvTECaUPrromYsSswlA7uPMZMR/pK/CS+R43CKRzTMfgrFICyqexuSvqBvHXspWR8nHYtAaINhqb0TJV/4IwCfqHtpDZWCVBgpSvzRKmQiAStiax1pFEOqBfGwQIqQTBh9AuKNipsWlLz5iga+gtGSiJOxa229rUnMTApx5cioF1XZ+5BOqUHWIu9hGQff75VX2JvlC2ELpMhak8g+IKIKUfzqDlRNSMetSJUDSO3oko7T688GM2v2AJMq6iG1iCMFl01IjhtDG3VRW/2duquHlIrUq2abWH1Vei+RHHGLHjSlXLvy78Q1QxyZlOaIWtbq7aYWd/Kh3nsZ0ybSlNnLu0iwdZxNB1KLAe+ZwIvrE8uT6oE07U+jqzZZgOyOiM0eU0cogZJNBTusHQ1DXbVTfYB4SoXh2UoSLNtNLlqmomrqw3DEIfsYElJT4iJxAqZ2svm+gshu/qv9ItsTHJct+3ahZqmElKTYuIhpxU0mviN5awmApJ0KOdiZoxOMR7l8AcyOIRL6Ncx1+QLRXOwZe6kxNLmescCTSq7xcYSq6CUzy+eLCBQ5nS2bXSjU6BPlrW7gFfJm64iU5a3vtkxujD5elBhIGrlcC7q1PyUfaSZ15YXVHUlS9ukLBOuOZy67NBk/1fZ3Lnhb3UcEsWtiVjJ2Hu6EE2Xcxhr5LF2i/VraHOtQRznoTisajebwr1HGDQbtHLXhkcGJNclEWCXAJNzBIhVWgCJSaIoc1oV0cHqSi+uc7i4ZktXbFE6fkVFN1tIJ+dL89T6VFYzpiqOc03pRHLut5Y0RFHoqZHwhQLNzq2tXXY08RReTAcmKI0H4FYEZ6LRfpuA0gzXcMkUEOx6xO9loBS6ueL6srMzfc7I9UVoEdfVcL80JOFRK766FoeJnE0Z+qFB0RSSvpo2g8C1oq1RoIQbAhJuECMMgIPmeQSatgwlMSdHckFpjwbU1bexOZ25nB0EJiE4CvawAIvWh2TizH9A5s7YzF0YLWTA0lLkHbG3DA0hgG/X5N2P//CzYyb/kd3+oWSIHB0DVIZ9ufgH5Vj4jz/7GP+nHePXCvV2HCUjQk5FklxNsGeMJXOjRPH9OEijIdJwrjyfApmbpi4vbMrFu4yqZXPFT7kBU1rdFRqg+JfINcFShYb7giuvxc98lQCIegLQVC7+lbJMV04I2JbMfsFA5dZ//Nkp/N8qiug8wKzVyONHaI0uiSumEVwYhjrkcBeSMktPki3PI1jzyC6imEe700RAVW45HtxqGpEAMNk09Z95OJjBnKrPSMMkznPDtk230tpoZYUfykv4UEE4OoOD4QxIVJjX9GdcKsFyw083+RqZcMT5ixw5v3hMbYdpYdHt2pMqltBtmH10rz4D5i+ZvVrA7TteXDUEXDVlsnq6BHWtsGKg6DPm419V6zJvh8K2hYlN3rpaiDJnSzDRh3yMQYnorpRtNjMyge9201MeJcw0E8Y3RfEBbLJkseldeWzPaSyMB6KW8YvPguGrciWrYQi+ohW6LAzKrD7VSXWmap0sk9Bz0IUCFFLgE+lXWc7nx8KCnyhvYBnTbHnGbA5iBLeD5j7NasAiW9RbsMXqwtODCB4EBlQAl18Lmmx97cu66O2P1j9tbmx92p5EBTuOr5o8J+dLk3s8/pSwNf3UAHAqza4THypqNb62s3ftbsdEJTAamvtEhwGOHyUzttWLgzh39zlOL+ix5VM5ftVwpNzbce25Jmiklt2GB3dsbxUmDzSnp1UKwGCxG/Lp4JMcR/kwx11HJ3+Jq84P9lwGTtgJJQRqQYw6zNUmjJ2Jd4PUCYxBokZictZATEYELoYADxSrMAc5iD0BxQRkh2axH3UPInNMiWA8l2y3xV7/JDiGpfbRUjaTtJecL2vCosOY4YJjA3pw0uzTja3c0pBcfG4a8aUqHcvytWM/2vpeDxck0ap6mg3G9cSPTgvmya3owwBJ+mJMVueRCQAz5tSuuMU312DjEfb5w9anHzNfDtQqUUUQRlhPX5CMdL9KaGgKb8x3BvjlcFir9wS0sDDiz81HlsFRXh3j2tKxFvsdqCHELj2RurtW/uuw6xYLohCbYa4dEp9PUF7FvQMaMSMn+bwcH1PCFRLeQxeZI/6K06hCk7BHAYSGzRamCuNcACl5JYiSgEELvDxGMwgIfVMaqAqYQ4iITcvB7eSLbZXyEhPX8uwrsxzytOyFNYOr+r5oGmiO0gno0hG/4kQfj+l90CG+BYktwMzqqfQ/E1ZTJM0vBdd8LyDHYkSWnwoC8Eq9+z09ngNhPp2IBlb8SBecO8VhA3d6qOaODhFCci7AdFuDmBQEdvsWK1057iOMj64IfcEiRQKSQSzaywRb3UdU8U6gQaVTREws2G2hcLn9e9gChMxBHojW1Wg7fUKFk91FiF5yekhawwim92R7EDd8vcW8XARSKnxOy0rYqZcmg/Y1XqVth07OAFbomH2oLcMXoLMA9xlsluqXWr2nBxGYZpKtqxEnrpFvIQ5arqGtpEJOgDa9EHlR2c9Yup4d9pgS0Ud6noEpz5SfcjknsWAGg5DhBV9j0BucVHfaVz9bDnBApc1PjdZrW3ERUWKn1o2uMsGvpvO1pUOB9kaKty6mYTunjIF8RNwhlBNgcCt/RZG83np+Xy5tM3bG64uHDQd14At8H66zN77VkxwI/WbMvSkisWVjQGAyB4MnCkvXrGnbzTnH5hAEI5YW/DDneDvmfe2q1RDdNAcFr+X5lauI58cFaZHM8XAqTGzZX5AlM6KVmUb1yZkcgsJDhz6xfkWKwAroPR/IYuh1Ea4ONoBcAreDKAmJZJI8ufpQNUZZz1Pa4VBJccfdgLBDeA0mMF0FetL4D5DmsoealF0agvWENwBBICq/rvBQCV/mEGq5H+NXZjgDlJoGxvRKWlJT3B65oUtRwo3WLVoQ25+zAjl0n6feLU3dzlJQqCp0zgaM4qhzJCd/zvw0Gk9FRzpync5w/CeQIOMhwrU5TQgt5YAxIJ8mgJdpAFgIQyyEhVGb3wGiQCtniOCZSgAIYLkK5EE7Ed/pXMf2oNu3lC9YkisoKwXqmANLVe39wfzAYDc8SJFi5rd/ta1SnzmwVWAAwCObOTlZ/LkU51gQ71cLQSpsSAV48v6tFxaAU+mhsZZXAjWIwuDmtk7jZrWijXaj2kZejUO7L9fZkjpyF4n1RmVotsKe78fCnWJ05tbzoff7mR7tNlycnKEl8CndyvnnVClT+2EDjSkX1BXRpZytXNqSNpTzta5NMxZ4ZLe0OjHHbjia/0nesLlNkZbhsFeZ3aNhrGH+nNV4t4U5Ef4125CETWew2UADXxOwd++0JJYSkhriffaIwzUfW+i580w9myPKHHedQwwOBGKsZ80Qoe8e2HOUTEFeMpzMWi/LtQRS6mYt4Hm7aD3e9WDNfNZStsjrdd2tA+LcOWpqTV1K6Y8AEhjY5WHiDN0x15u31Vi2LscPCgj4op+aH8gt9tR7IjSL26qwt5CMxaLTUNqZXgsaFtjq4L6j48S8Y/OZCN7PPm/1hL2VVftTQI1/J/AxbHmd7zFAhZ4cq30Nn5eoEJ4dVIgtxAsQIsDWESmokPr7OGAYQeLlkk2/S2h9I/YERoDulO5eSHdeQJHD44nSEUz1vp5Mlr2ElqB1lFbuwKDIL9HtYzHqGFlKW62WbOznAhTyFejXEDS80t4eMBAAUJtZLshwIZAceuEhKWwShnElHMI41UB3uR6oUDuO6TygH8zZ+ZfibzeT7AbpB5g64BKiHMVvSH3mYTNfT6+3ce4+Hk+hpPW4HFCxobOssIWXHQko6bwiyHUeTfoQLKGVEm7XIZczLMQhHQOmcMUFdWGslvCWNb4E15i/w9yDa261tEDZFXLh5fOPSz4YMuOVcMuZUxFUxpLEAe8OLP4Z5IGOH9UkLFYHZbhgRSxLi+RRHZ4YCsYeIfW452mt9elzoMqlWUhT9E1iIp0eE80tVorankP00I+AHy0JJz7fc8/1lJPuyxwfxTzKXcltxLUueoSzoYq2rcq5bXW81iYIn7FF0G8i4UvJelZGOH9GQJW42bdVCEPSnJa1lLDD/cEoDEAiChtbPNcupMWHJd6de7VoHxH/pibEg3mDCxCsrzVvLFgjgXn6teYLKX2EA+HEAeQi3Ur8XKZvrjWfS8lDOB3qli1oM7z9dO3j1XKhx1haJH3zk4W+q0xGGb2GMjXQvF5uFlE6tAXJrnDxlRWdtnyhX/agO7iwiGO3FM7YaogonCBuQ7+v6mLB8Gbw2q1WOu9k5c6hO4eLLW89QTnhW0q5vXJJVYTtBCqQn90tAZBoIiO51rTJNWd/j4JxlEbxSPy2PLmYN3D0tnsOm94n4NmfgII6pWseNw8GLb1kjbnStKjDIGUA1MIwAIdCEN+EhCXIUWn86/rQhrxQjx4RVYSD0WLIOtfyqyAVKKs15QoBNqa1jwhTRnjK+c6eEITSFViga5moEAK7CyVTuy/OIlGAWvtBj4y+Jz1hOQD3y000FAqWRU8SKEDSmZc8ybkB7ckfuyCwVkMYF19Ltd6420JQhbE9Gv4M62W0HgKcenE1haAiMqR27+nW693N158AFC/VcbnV1K/b6/NyzxP+ycCToK7t3jqNyua2of01/pM3BI9vJhFnKSvbXGVUHlUWd8VW/uTlp2uf7qLyZEr+dpW1TMkRsbGkkBCVvKGpHKWxLb14sbPzYhstISDth2zkvFCMmsNhLCEmKMxlhVTz2gZev97+ZOMFGkBQFH4WW7AFeLqQUl295Dz/kySCsBUavH6++Zw0SPR0irxDtStYDNMS2OdomtldjwGv8x/UkZth3MzPC4/L1AbEPsSILtZJgcyTMFFunSH5HkkCeJZDDvKNpicPzLKE6t/9o3kjXGZqfehjJpGEF5Wt6y4jnF8+qGCWM4xpDj/Glnaie4oljXGgvXuQ3iYfj5Ze1OdeapDPZbdrWxvG3qVVd8lIiFPg9FoV+fHKPPaHgynzbs2TrZJPqjhsAHmXo8jyQOe6eNW8pQoxUAKKc5Iac3l5We7Jfpl7Ko9Quo0XD/oS/+HjAz/KU/uw/IY1Li7w9eICRfT/tDef8TNK2JqVd/IE9Vi9zcr6/wY6aOHzA1qWNlGo8tI+471xljseyiv7ML9S5iFfpWJ1UJmYD9ye4o9jd5pXcowN04YdbgOYQem6H7Pd3T3AgXJglBD1jMjVwOIMEKnYaj63Hg7uVKvb4LdYOatFqGLV3pKTg+w0kSUBRFbRsyMynJGNfsP2PTnXHCbik5AG2HGi2zKmFWz3buURTttldOUAyjFBts5f3EyvaIN6khNRJwLAS+I/JGZv/vrrc3ftn+XEfzJl5mvk6lNZk+2/++P/sgLyvX/I1Bqoo2sNSx8XIczv1gKhgEu1ZHzt7+8yRPzmG7J+glherPbuX/7+A/79p/xf8+KTjxeHN8hhV9di4fe9RK8mfCu30QwRoBC/095P+O6P/2wYnnxknLZREeHqkvHuq7Rat/DhpJlWNvceYEQ/1VfDlm5xY75V7vnOnjDtyHE/mz9PuYaKb3Rm9gCn2hh/keEgXJqN/bIOmhNKl5XMBkOFJSu0tqtSnOCzes5c7/70r0TEhnKin1ZKCSs7R400DiiRiPBms2QFnZMV1MVdNdrhh2MwdAWdkindOaCtA4my3e2afMFaHKMld/Vtya2eKyO4sS4RvykvMYnl9K2+/PFnuZxN+eI8V/7MaOBYkFgDDez+TcSnylyn1zeKSq2skeSI5ZTxkiUKaeZwdezCoMdddyIZm7I/WN/Y3FqyeVQU2ehLhYm2Wtb1UTHxVeDfFbwD6XGS8NxuJiGK90gPYvONxcYZsYgI1xPoujnbhw3OhNKqtY1W7a1JhIjqEhF2Zf73n/70P6y02gbOchFHXhDvc2PTnG75H7UC7OtTKzc65v0iCEGyj22l0sje/fFv7cB2OrLESyyUodzSWx3Ntc/AQ3Oj9ZzXd+Rvz2QZOsaxR4Vb/1AwrXn3n//V9rvbIUT+JF6QtndekFk6mKJfe/WxPHN5Nly5NVVkLdBjuhOxUyZmc0vDc5lLX6Hs+kZji1eNlhjlecu2BMMFJh2OX0Eel+TMLwDv+zPDBOftEj7baGxuSRCzDMcjfSbywBkuzyXg8Ysh3P78SLkmo6KazOnLSovbbxWAYCrEWBJz4cEFeady4QH9ZMnEPCwEkzSHTuUGcgk0Q7U3YPOIVzpOe9FSv4ZXTTG6VZJH/1XfIHt6fLJ/fN6R2w14x4XcLPisUCDpMyta4MvL5fB3SCghuofxSoQxtw3ge/r3tA6C0IldK0Zd9e70+lovq+u4q+/U9ZXM4FI7obP5iDFQGqAhBGz5WEqrcMY1ECNP4w1IS1FnNAU8GMkdPiCAG6C8YNS2ZEIwhuni/I7Cn7QctgDB2/wkU5oTemHcF08qZkxxqFRSDgO9YRK4bFMxZOhrlhpTSIg255DsEgi/DTJ3fQM/UJw9KZkllcaMa23TuQoapyYuJRoHags+pqWGQQm5wWgW0NG45SgNeFe1RgbE3BVU1IhRH0mIkneUEm03B4HHIHTcB/nBXghQDfNYvMBMlNAvWw4baa20ZUZ/W91asQTU0spfWof3zyLeviow+fz6mOOeo3qdX27LP+KcF+VVIrhnC9J0sbwDOluo86KHXi3fzWHNUn7dqq5Hx29TRUV5qjSVUUvL2+ukXfmX7ijPY+2LYi7KH0AGmMfp+eMvK88ZxkGolip8cONuTtFjzuWbb7tM7FUC7A+PAEBxaCTS+KRGCZ1voM8kc/bljo3VMSALTAGBBeObHKWJ8JdU7arboTnoNVSy7yXIIyVs8EcvGtX0dlEMcmGICHHWpCSyQbYv7DMNC9YYDmDM64eXRTWcQWzKTR6bOohsxpOZmf1pDibNirL0Df1h06k/e/mK3pUsiRc3+bkZ6Iiad8EwG0klnEXhvm56VBZGnjtKueP6NMOkLGdpXzBCfkhC3vn8P+5BGgIBpK9LNySmXDwmxI/4WMw5yVm5K9yQjJjxaoY8v/rU/VJIvnr5fW0/v1VnpZQLGUoIZ9UKwPqS/fdzjesP82dIHvOCXMlde8+mB8QMkLRweumQLyv5wW3+zHO1dn6fdv6VmIFqA9Z/KZlWPcGxa73ZGrDdvPhfoxFt3KhUV7XuhFCtnMHu/TvYHIzj44rDIeq0gvT8/Jueq2KDH2KUAtQlu5q+tr0rXMoIsILIoFixWAV8FfYV5NAEMUe57ArvXLtZkf4Ss9mJDd5IhHMUFg0tJiq+Ip+neRiNeCIhLz8GoqNyoS8CEjk2NUbT4spXAAxK6FMLOhGAI6QEcHKJzQwuvQXLCXaYCQPocSSzRAydlgJuchtyfpzA2iY55j7kQQhXjcciQku9hq6HBTDmBwhoHoiXrxU4zLf/vgIFI2ZOU6Z5HiVWhUCiNAmFG+a3DbpENg4RT+NSpdfBdXt74v0elsNvpfJByFhwyWrmPVZT/gyCZnA0XejuysJZWNwe7U681La/OjnYU+y2efff/8GcgVP6IGuBqZM77tzrLwLmx4rAdG0xFC3FNB1pejZHDOBGT83JMCpCqa7HO/PX3ZNjYZHRlGiWyJqWWkAkulyxRjDoQG9NpfneRGyZhPElaeSK71iovk2hIfQchtFMb4QKJgWInmWPIsFNostNt8eK+0sj+YkpLVjhmvxOIEhCf9zO56PpYSwXmQTXe7kfpCnORdv8Vm40W+fvIMRP2yA1746Y6C2e1lp9pidfn+Uig/Ce8jHmwSgyH1XPzOZlT5Jl54N5it2Cn+0PGzV4P5/rHv7ukrPVK3MHesQ6JjhUwELzU9LXzyRw80wzy7fI6Yl/99PTs6giX6EmhWfO63LLsPKO3MIsJ5U7uDBIokS48EI/NeG096Oe+JD5z2W95ycDlF6d99wsX4LJUgqq+b7nh0TV1nKbg3KqPk8P5zU9SyZKjpjFGeasTpzHxAhzFjBqywnb1vxvNfXUvdcbIyO7yMUCS3H+uJItvzD+3eKee/ycmvgQNT3HLgu3MHx7L77Zx88hHJ/tv37b3d+DB/JJaw3/rOvPgT3GoPYcuoDy7eH3R35PDFeAA399nZbY1/Kr/BKOPdG+yIr2WIG7OfRQfm5qfgrwxw7O9y933na/6RS3jAa84UCLV5bBwiDEFCVaw4Zny/OKBQXTvCpBP0Dxx441NO9A3EdfpqNlRzBK95lIRjydP6suZ/UGisxiYaRDFK6UTPKT3rzl51Izb6lcd8T59ucuS1nousTgKl559EcvYzPLzp+X73AgJFpugcnbSKvXUOZ3L+y8Pb48OO6ebx8e4taFj96cHO3jQiAcln+SF+HdmHxXKtoGBqgjl2ZqwL181YMjF6+0BiAxEI1tEd+V2+FwUBKBkux9V7edsn9usnFAHH+NP4Zhj5bUl94awODKM4YN3UkAzuAiHKeINTYD0wF+dI2lvyTjMNWrHPSp+ez0YG/ZdQVdvaAww8+R/dqey9Ce7IWJB2k6ZX7oQ6/NaQdSQc5CUGwi/8JjUHgmOq2ja+3gIw3DK1W4kvZmgwZPMsQCQORpLblGB2rvu/8DnmO3Qd5yAAA=