@theplato/tiro-cli 0.5.0 → 0.6.1

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.
Files changed (3) hide show
  1. package/README.md +56 -4
  2. package/dist/bin/tiro.js +143 -2460
  3. package/package.json +1 -1
package/dist/bin/tiro.js CHANGED
@@ -1,288 +1,14 @@
1
1
  #!/usr/bin/env node
2
-
3
- // src/bin/tiro.ts
4
- import { Command as Command19 } from "commander";
5
-
6
- // src/lib/version.ts
7
- import { readFileSync } from "fs";
8
- import { fileURLToPath } from "url";
9
- import { dirname, resolve } from "path";
10
- var HERE = dirname(fileURLToPath(import.meta.url));
11
- var CANDIDATE_PATHS = [
12
- resolve(HERE, "../../package.json"),
13
- resolve(HERE, "../../../package.json")
14
- ];
15
- function readVersion() {
16
- for (const path of CANDIDATE_PATHS) {
17
- try {
18
- const raw = readFileSync(path, "utf8");
19
- const parsed = JSON.parse(raw);
20
- if (typeof parsed.version === "string" && parsed.version.length > 0) {
21
- return parsed.version;
22
- }
23
- } catch {
24
- }
25
- }
26
- return "0.0.0-unknown";
27
- }
28
- var VERSION = readVersion();
29
-
30
- // src/lib/error.ts
31
- var ExitCode = {
32
- Ok: 0,
33
- Generic: 1,
34
- Usage: 2,
35
- AuthRequired: 4,
36
- ExUsage: 64,
37
- ExDataErr: 65,
38
- ExConfig: 78
39
- };
40
- var TiroError = class extends Error {
41
- code;
42
- suggestion;
43
- errorType;
44
- httpStatus;
45
- requestId;
46
- details;
47
- exitCode;
48
- constructor(payload, exitCode = ExitCode.Generic) {
49
- super(payload.message);
50
- this.name = "TiroError";
51
- this.code = payload.code;
52
- this.suggestion = payload.suggestion;
53
- this.errorType = payload.errorType;
54
- this.httpStatus = payload.httpStatus;
55
- this.requestId = payload.requestId;
56
- this.details = payload.details;
57
- this.exitCode = exitCode;
58
- }
59
- toJSON() {
60
- return {
61
- ok: false,
62
- error: {
63
- code: this.code,
64
- message: this.message,
65
- ...this.suggestion !== void 0 && { suggestion: this.suggestion },
66
- ...this.errorType !== void 0 && { errorType: this.errorType },
67
- ...this.httpStatus !== void 0 && { httpStatus: this.httpStatus },
68
- ...this.requestId !== void 0 && { requestId: this.requestId },
69
- ...this.details !== void 0 && { details: this.details }
70
- }
71
- };
72
- }
73
- };
74
- function authRequired() {
75
- return new TiroError(
76
- {
77
- code: "auth_required",
78
- message: "Not authenticated. Run `tiro auth login` to sign in, or set TIRO_TOKEN env var.",
79
- suggestion: "tiro auth login",
80
- errorType: "auth_required"
81
- },
82
- ExitCode.AuthRequired
83
- );
84
- }
85
-
86
- // src/lib/output/tty.ts
87
- function resolveOutputMode(opts) {
88
- if (opts.json) return "json";
89
- if (opts.pretty) return "pretty";
90
- return process.stdout.isTTY ? "pretty" : "json";
91
- }
92
- function colorEnabled(opts) {
93
- if (opts.noColor) return false;
94
- if (process.env["NO_COLOR"]) return false;
95
- if (process.env["FORCE_COLOR"]) return true;
96
- return process.stdout.isTTY === true;
97
- }
98
- var ANSI = {
99
- reset: "\x1B[0m",
100
- bold: "\x1B[1m",
101
- dim: "\x1B[2m",
102
- red: "\x1B[31m",
103
- green: "\x1B[32m",
104
- yellow: "\x1B[33m",
105
- blue: "\x1B[34m",
106
- magenta: "\x1B[35m",
107
- cyan: "\x1B[36m",
108
- gray: "\x1B[90m"
109
- };
110
- function color(text, style, opts = {}) {
111
- if (!colorEnabled(opts)) return text;
112
- return `${ANSI[style]}${text}${ANSI.reset}`;
113
- }
114
-
115
- // src/lib/output/print.ts
116
- function printOutput(value, opts = {}) {
117
- if (opts.quiet) return;
118
- const mode = resolveOutputMode(opts);
119
- if (mode === "json") {
120
- process.stdout.write(`${JSON.stringify(value)}
121
- `);
122
- } else {
123
- process.stdout.write(`${JSON.stringify(value, null, 2)}
124
- `);
125
- }
126
- }
127
- function printError(value) {
128
- process.stderr.write(`${JSON.stringify(value)}
129
- `);
130
- }
131
- function printNdjson(item) {
132
- process.stdout.write(`${JSON.stringify(item)}
133
- `);
134
- }
135
-
136
- // src/commands/auth/index.ts
137
- import "commander";
138
-
139
- // src/commands/auth/login.ts
140
- import "commander";
141
-
142
- // src/lib/auth/flow.ts
143
- import { z } from "zod";
144
-
145
- // src/lib/auth/pkce.ts
146
- import { createHash, randomBytes, timingSafeEqual } from "crypto";
147
- function generatePkce() {
148
- const codeVerifier = base64url(randomBytes(32));
149
- const codeChallenge = base64url(createHash("sha256").update(codeVerifier).digest());
150
- return { codeVerifier, codeChallenge, method: "S256" };
151
- }
152
- function generateState() {
153
- return base64url(randomBytes(24));
154
- }
155
- function verifyState(received, expected) {
156
- const a = Buffer.from(received, "utf8");
157
- const b = Buffer.from(expected, "utf8");
158
- if (a.length !== b.length) return false;
159
- return timingSafeEqual(a, b);
160
- }
161
- function base64url(buf) {
162
- return buf.toString("base64").replace(/\+/g, "-").replace(/\//g, "_").replace(/=+$/, "");
163
- }
164
-
165
- // src/lib/auth/loopback.ts
166
- import http from "http";
167
-
168
- // src/lib/auth/assets.generated.ts
169
- var TIRO_LOGO_BROWN_DATA_URI = "data:image/png;base64,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AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACA/78dOBAAAAAAELQ/9SIFAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAQAP3ZeKxkxamrQAAAABJRU5ErkJggg==";
170
-
171
- // src/lib/auth/loopback.ts
172
- async function startLoopbackServer() {
173
- let pendingResolve = null;
174
- let pendingReject = null;
175
- const settle = (fn, arg) => {
176
- pendingResolve = null;
177
- pendingReject = null;
178
- fn(arg);
179
- };
180
- let consumed = false;
181
- const server = http.createServer((req, res) => {
182
- res.setHeader("Connection", "close");
183
- res.setHeader("Cache-Control", "no-store");
184
- if (!req.url) {
185
- res.writeHead(400).end();
186
- return;
187
- }
188
- if (req.method !== "GET") {
189
- res.writeHead(405, { "Content-Type": "text/plain", Allow: "GET" }).end("Method not allowed");
190
- return;
191
- }
192
- const url = new URL(req.url, `http://127.0.0.1`);
193
- if (url.pathname !== "/callback") {
194
- res.writeHead(404, { "Content-Type": "text/plain" }).end("Not found");
195
- return;
196
- }
197
- if (consumed) {
198
- res.writeHead(410, { "Content-Type": "text/plain" }).end("Callback already consumed");
199
- return;
200
- }
201
- const code = url.searchParams.get("code");
202
- const state = url.searchParams.get("state");
203
- const error = url.searchParams.get("error");
204
- const errorDesc = url.searchParams.get("error_description") ?? "";
205
- if (error) {
206
- consumed = true;
207
- const detail = errorDesc ? ` \u2014 ${errorDesc}` : "";
208
- respondError(res, 500, `OAuth error: ${error}${detail}`);
209
- if (pendingReject) settle(pendingReject, new Error(`OAuth error: ${error}${detail}`));
210
- return;
211
- }
212
- if (!code || !state) {
213
- respondError(res, 400, "Missing `code` or `state` in callback URL.");
214
- if (pendingReject) settle(pendingReject, new Error("Missing code or state"));
215
- return;
216
- }
217
- consumed = true;
218
- respondSuccess(res);
219
- if (pendingResolve) settle(pendingResolve, { code, state });
220
- });
221
- await new Promise((resolve4) => {
222
- server.listen(0, "127.0.0.1", () => resolve4());
223
- });
224
- const address = server.address();
225
- const port = address.port;
226
- const redirectUri = `http://127.0.0.1:${port}/callback`;
227
- return {
228
- redirectUri,
229
- port,
230
- waitForCallback(timeoutMs) {
231
- return new Promise((resolve4, reject) => {
232
- const timer = setTimeout(() => {
233
- pendingResolve = null;
234
- pendingReject = null;
235
- reject(new Error(`Timed out waiting for OAuth callback (${timeoutMs}ms)`));
236
- }, timeoutMs);
237
- pendingResolve = (r) => {
238
- clearTimeout(timer);
239
- resolve4(r);
240
- };
241
- pendingReject = (e) => {
242
- clearTimeout(timer);
243
- reject(e);
244
- };
245
- });
246
- },
247
- close() {
248
- server.close();
249
- }
250
- };
251
- }
252
- function escapeHtml(s) {
253
- return s.replace(/&/g, "&amp;").replace(/</g, "&lt;").replace(/>/g, "&gt;").replace(/"/g, "&quot;").replace(/'/g, "&#39;");
254
- }
255
- function respondSuccess(res) {
256
- const html = renderPage({
257
- kind: "success",
258
- title: "You're signed in",
259
- body: "You can close this tab and return to your terminal."
260
- });
261
- res.writeHead(200, { "Content-Type": "text/html; charset=utf-8" });
262
- res.end(html);
263
- }
264
- function respondError(res, status, body) {
265
- const html = renderPage({
266
- kind: "error",
267
- title: "Login failed",
268
- body
269
- });
270
- res.writeHead(status, { "Content-Type": "text/html; charset=utf-8" });
271
- res.end(html);
272
- }
273
- function renderPage(p) {
274
- const safeTitle = escapeHtml(p.title);
275
- const safeBody = escapeHtml(p.body);
276
- const titleColor = p.kind === "error" ? "var(--error)" : "var(--brown-800)";
277
- const logoOpacity = p.kind === "error" ? "0.4" : "1";
278
- const closeScript = p.kind === "success" ? `<script>setTimeout(function(){try{window.close();}catch(e){}}, 2000);</script>` : "";
279
- const hint = p.kind === "success" ? `<p class="hint">Closing this tab automatically&hellip;</p>` : "";
280
- return `<!doctype html>
2
+ import{Command as ho}from"commander";import{readFileSync as At}from"fs";import{fileURLToPath as tt}from"url";import{dirname as rt,resolve as we}from"path";var ye=rt(tt(import.meta.url)),ot=[we(ye,"../../package.json"),we(ye,"../../../package.json")];function nt(){for(let e of ot)try{return JSON.parse(At(e,"utf8"))}catch{}return{}}var X=nt(),O=typeof X.version=="string"&&X.version.length>0?X.version:"0.0.0-unknown",S=typeof X.name=="string"&&X.name.length>0?X.name:"@theplato/tiro-cli";var d={Ok:0,Generic:1,Usage:2,AuthRequired:4,ExUsage:64,ExDataErr:65,ExConfig:78},u=class extends Error{code;suggestion;errorType;httpStatus;requestId;details;exitCode;constructor(A,t=d.Generic){super(A.message),this.name="TiroError",this.code=A.code,this.suggestion=A.suggestion,this.errorType=A.errorType,this.httpStatus=A.httpStatus,this.requestId=A.requestId,this.details=A.details,this.exitCode=t}toJSON(){return{ok:!1,error:{code:this.code,message:this.message,...this.suggestion!==void 0&&{suggestion:this.suggestion},...this.errorType!==void 0&&{errorType:this.errorType},...this.httpStatus!==void 0&&{httpStatus:this.httpStatus},...this.requestId!==void 0&&{requestId:this.requestId},...this.details!==void 0&&{details:this.details}}}}};function G(){return new u({code:"auth_required",message:"Not authenticated. Run `tiro auth login` to sign in, or set TIRO_TOKEN env var.",suggestion:"tiro auth login",errorType:"auth_required"},d.AuthRequired)}function b(e){return e.json?"json":e.pretty||process.stdout.isTTY?"pretty":"json"}function it(e){return e.noColor||process.env.NO_COLOR?!1:process.env.FORCE_COLOR?!0:process.stdout.isTTY===!0}var be={reset:"\x1B[0m",bold:"\x1B[1m",dim:"\x1B[2m",red:"\x1B[31m",green:"\x1B[32m",yellow:"\x1B[33m",blue:"\x1B[34m",magenta:"\x1B[35m",cyan:"\x1B[36m",gray:"\x1B[90m"};function a(e,A,t={}){return it(t)?`${be[A]}${e}${be.reset}`:e}function C(e,A={}){if(A.quiet)return;b(A)==="json"?process.stdout.write(`${JSON.stringify(e)}
3
+ `):process.stdout.write(`${JSON.stringify(e,null,2)}
4
+ `)}function ne(e){process.stderr.write(`${JSON.stringify(e)}
5
+ `)}function v(e){process.stdout.write(`${JSON.stringify(e)}
6
+ `)}import"commander";import"commander";import{z as L}from"zod";import{createHash as st,randomBytes as ke,timingSafeEqual as at}from"crypto";function Ce(){let e=ie(ke(32)),A=ie(st("sha256").update(e).digest());return{codeVerifier:e,codeChallenge:A,method:"S256"}}function ve(){return ie(ke(24))}function xe(e,A){let t=Buffer.from(e,"utf8"),r=Buffer.from(A,"utf8");return t.length!==r.length?!1:at(t,r)}function ie(e){return e.toString("base64").replace(/\+/g,"-").replace(/\//g,"_").replace(/=+$/,"")}import ct from"http";var Te="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAACLwAAAOrCAYAAABXsQ1QAAAACXBIWXMAACE4AAAhOAFFljFgAAAAAXNSR0IArs4c6QAAAARnQU1BAACxjwv8YQUAAAAOdEVYdFNvZnR3YXJlAEZpZ21hnrGWYwAArqVJREFUeAHs/T1zVGf6P/peqwWCU/X712gyMT6//yyyk1lkWPaURbYzQ3ayQdnJgGxnFtHZmSHbGfgVmIl27Yh22Qhnll+B19RsG2VbUzUBCNRr37e6xZN50EN3az18PlXtbgkwons93vf3vq4IAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAOAtRUCLrZXlUsTTpfz6RURZxGBpL0ZLk18uA4DTVOX/DCbPo1jYWYy9nWG1XQUAAAAAAACcgMALjbJWLpf5OYdXRulRR7FURJ0e8deD1/WrIEsZALRZVUSxE1HvpGP8TrH/HP88eJ2DMuOQzNlqWFU7AQAAAAAAABMCL8xNDrPsxsJSxN5KDq8M9kMsuSpLDrbUuSpLGQDwflU6Z1TjQEx+rv+9EIOtOkY7Z9LXKscAAAAAAAD0h8ALU5PbC+3G8/JVoKX+ND9H1CshzALAfOyHYmI/EBP/zIGYvSgqVWIAAAAAAAC6ReCFI8vBlhfxdCVNIK4cVGkRagGgBSZhmGJrtB+GqbfOxPktQRgAAAAAAID2EXjhg8ZtiGKtiOJTwRYAOmrSKim+P6gIs1n9thUAAAAAAAA0lsALL+XKLXuxuzaK+sscbKmjWEnPSwEAvVPsFFFv5RDMIGKoEgwAAAAAAECzCLz02JvVW+qroXILALxXOl9uxSQEsxgxHFbbVQAAAAAAAHAqBF56JFdw2Y2nVwVcAGAqciuk4SAG/1iIxaEKMAAAAAAAAPMj8NJxX5TLa6OIL9MHvVanRwAAM5HDL6Mo/lHEYLhZ/bYVAAAAAAAAzIzASwflkEsdxVd1xPWIeikAgHnbr/6SHt/+WG0PAwAAAAAAgKkSeOkIIRcAaCzhFwAAAAAAgCkTeGmxg3ZF6WO8KeQCAK2wH345G3F7WG1XAQAAAAAAwLEIvLTMWlkuPYtn1wdR52ouawEAtFIRxVYd9d3FiKHwCwAAAAAAwNEIvLSElkUA0F3pguy+qi8AAAAAAACHJ/DScOOgS3ytmgsAdF9ud5TO+d9uVtv3AwAAAAAAgPcSeGmg3LZoN57eiP1qLlEGANA3VXrcFnwBAAAAAAB4N4GXBnkVdClualsEAMQ4+HJ/MeJb7Y4AAAAAAABeEXhpAEEXAOAjqhB8AQAAAAAAeEng5RQJugAAR1SFVkcAAAAAAAACL6fls/LCjfTmbwi6AADHUIXgCwAAAAAA0GMCL3P2Rbm8Noq4l16WAQBwMlUIvgAAAAAAAD0k8DInq+UnK0XsfVNHrAUAwFQVDxajvjWstqsAAAAAAADoAYGXGVsry6Xn8ezrOuqbAQAwQ+nC7v7ZiNuCLwAAAAAAQNctBDPzWXnhxij2HkTUawEAMHsrexFX/3vpv/79r53/bAUAAAAAAEBHqfAyA1+Uy2t1xNfaFwEAp6hajLii2gsAAAAAANBFAi9TpH0RANA0RRR3zkZ9V/AFAAAAAADoEi2NpiRXdXkRL/6P9PJ/CQCA5riszREAAAAAANA1KrycUK7qshvP7kXUVwMAoMHShd/9sxG3VXsBAAAAAADaToWXE/hb+ZerL+LFw4h6JQAAmm9FtRcAAAAAAKALVHg5hnFVl6ffpJfXAwCghVR7AQAAAAAA2kzg5Yi+KJfXRhH30ssyAADarRpErP9YbQ8DAAAAAACgRbQ0OqRc1eWTpf/X/7+O+N/Tl0sBANB+S+na5vp/L/1X/GvnP98HAAAAAABAS6jwcgiXy+VyIYrv6qhXAgCgm6rFiCtaHAEAAAAAAG0wCD7os/LCjUEUPwu7AAAdV+6ma5507XMzAAAAAAAAGk6Fl/fILYyex7Ov66hN+gAAvVJEcedsnLs9rKqdAAAAAAAAaCCBl3fILYwGEQ/TyzIAAPpJiyMAAAAAAKCxtDR6y9/Kv1zNLYxC2AUA6Lf9Fkf52igAAAAAAAAaZiF4abVczi2M/vf08nwAAHA+XRv9f/976b/iXzv/+T4AAAAAAAAaQkujZK0sl3bj2b2I2gpmAIB3Kh4sxrn1YVXtBAAAAAAAwCnrfeDlcrlcDiIehhZGAAAfUy1GXBlW21UAAAAAAACcokH02Gr5yYqwCwDAoZW76dopX0MFAAAAAADAKept4OXzcvnvEXs/h7ALAMBRlPka6rPyws0AAAAAAAA4JQvRQ6vl8tfp6U4AAHAsRcT/8t9L/xX/2vnP9wEAAAAAADBnvQu8fF5e+CY9/a8BAMBJrf3Ppf+x9K+d//yfAQAAAAAAMEdF9MRaWS7txtMcdrkeAABMUfFgMc6tD6tqJwAAAAAAAOagF4GXHHZ5Hs8e1lGvBAAAU1dEsXU2zl0RegEAAAAAAOah84GXy+VyOYh4mF6WAQDALFWLEVeG1XYVAAAAAAAAM9TpwIuwCwDA3Am9AAAAAAAAM9fZwIuwCwDAqRF6AQAAAAAAZqqTgRdhFwCAUyf0AgAAAAAAzEznAi/CLgAAjSH0AgAAAAAAzESnAi/CLgAAjSP0AgAAAAAATF1nAi/CLgAAjSX0AgAAAAAATFUnAi/CLgAAjSf0AgAAAAAATE3rAy/CLgAArSH0AgAAAAAATEWrAy9rZbm0G09/DmEXAIC2qBbj/KVhVe0EAAAAAADAMQ2ipXLY5Xk8U9kFAKBdynwNl6/lAgAAAAAA4JhaG3jZjWf36qhXAgCAVsnXcM/j6TcBAAAAAABwTAvRQp+XF9IESX09AABoq5X/ufQ/lv6185//MwAAAAAAAI6odYGX1XL56/T0vwYAAG13+b+X/iv+tfOf7wMAAAAAAOAIWhV4+ay8cKOI+N8CAICuWPufS/9V/WvnP78EAAAAAADAIRXREqvlJysRez8HAAAdtHBps/ptKwAAAAAAAA5hEC1wuVwuI/a+CwAAOmr0cG3/mg8AAAAAAODjGh94WSvLpfRDPkwvywAAoKPqpd10zZev/QIAAAAAAOAjGh942Y1n90LYBQCgD8rJtR8AAAAAAMAHLUSDrZbLX6en/18AANAX/5//Xvqv+NfOf74PAAAAAACA9yiiof5W/uXqXoy+CwAAemchBtd+qH5/EAAAAAAAAO/QyMDL5XK5HETxc0S9FAAA9FCxsxj1pWG1XQUAAAAAAMBbBtEwa2W5lH6oh8IuAAB9Vi/tpmvCfG0YAAAAAAAAb2lc4OV5PPs6PZUBAEDflZNrQwAAAAAAgDcsRIN8Vl64EVFvBAAAjF3+fy/9j3//Xzv/+SkAAAAAAAAmimiIy+VyOYjiZ62MAAB4U7GzGPWlYbVdBQAAAAAAQDSopVH6QR4KuwAA8Ef10vMovlsrS9eKAAAAAADAvkYEXlbL5a/TUxkAAPAOddQrz+PZ1wEAAAAAABANaGn0Rbm8Ntqv7gIAAB82iLjyY7U9DAAAAAAAoNdONfByuVwux62MVHcBAOBQqsU4f2lYVTsBAAAAAAD01qm2NEp/uVZGAAAcRbkbz+4FAAAAAADQa6cWeFktl6+np+sBAABHUl/9W/mXqwEAAAAAAPTWqbQ00soIAICTKXYW49xFrY0AAAAAAKCfTqXCi1ZGAACcTL2ktREAAAAAAPTX3Cu8TFoZmZwAAODEBhFXfqy2hwEAAAAAAPTKXAMvWhkBADBl1WKcv6S1EQAAAAAA9MtcWxotRHEjhF0AAJie8nk8+zoAAAAAAIBemVuFl0l1l18DAACmTGsjAAAAAADol7lVeJm0MgIAgKmrI1R5AQAAAACAHplLhZfVcvl6eroXAAAwI3UUtx5XT+4EAADwQWvlcvkiohwdov38IKIaxcLOYpythlW1EwAAAA0x88DLpJVRru5SBgAAzEyRBuHPXTQIDwBAn62V5VLE06UXk/HYSailTAPBf03XzCv1/tf1UhxLsVNEvZWet+qof4lY2NqsftsKAACAUzDzwMtquZwru1wPAACYsSKKO4+qJ7cCAAB64otyeW0U8WUOs0TU6TH3hYdVGmQepse3P1bbwwAAAJiTmQZeJtVdfg0AAJiTdP15xUA7AABdlkMudRRf1fsLDY9brWUm9sMvZyNuD6vtKgAAAGZopoGX1fLCd+mG62oAAMCc5AH2R9X2lQAAgI5ZLZevp+vdv9cRa9Fw6ee8L/gCAADM0swCL/nmKz3dCwAAmDNVXgAA6JK/lX+5uhejb2L+7YpOTPAFAACYlVkGXnIrozIAAGD+qs1q+2IAAECLrZafrBSx900bKrp8jOALAAAwbTMJvKjuAgDAaaujuPW4enInAAA6bq1cLl//ejcWlgaxt3TwdRGDpb0Yvfw6XSctFVEvfeB/WeX/DNLzKBZ2NqvftoK5S2OsX6enjeiWKj1ub1bb9wMAAOCEZhV4Ud0FAIBTVuwsxrmLw6raCaAT1soyTc4+/dAE7R8meT/k7QngIyjjhIoo/hQfnmyeikNManM6quiIOuKf0RFpf9lJ+8tUrhsOs++97zjwrj9b//G4U8b8VWkgsUo/y/cLMdhaiMWh66zZuFwulwtRfFdHvRIdpdoLAAAwDVMPvKjuAgBAg+TVoxsBfNDbQZIXr02kvicUUr7+xQfCG+Ufv1Us1e+dBC6WQjgDoDXSwOKwjvh2MT0LLkzH38q/XN2L+l5PzofVQgxu/VD9/iAAAACOYaqBl7z6YBDxMFR3ATiEYicNYO0U49Wd+ZFX8v073rGiMP2ev75a5bc/SdTZVV4A06XKC/2R21nkoMro1f1Y+VYQZf/7b1UJKAMApqJ4MIj67o/V9jA4lo62MDqMjc1q+3YAAAAc0VQDLz2+KQP4oDTZtJWml7ZGUfyykJ7PRFQnXf2WV2K/iKcre1GspP/3yiCKTwVhAN5JlRc6J18H7MbTGzG5DgjBFQAaIld9ORuxruLL0aRx1Vwx+3r0VvFgMc6tC6oDAABHMbXAi+ouAK+MyzoXvwyifnAmzm/Na8DmIAQziuJq+hm+FIAByFR5oVu+KJfX0rn+O61/AGg4VTsOId/HP4+n39XpZVAtRlwRlgIAAA5raoEX1V2AvsshlzT59I9zce5+UyZVJ2HEtfSz/d3gGdBzqrzQCe67AGiTXO30bNTXBBjebRx2efbQYpU3VBEL1zar37YCAADgI6YZePk1VHcB+qdKj28X4/ydplcOOAi/pJd5oqwMgF5R5YX2E3YBoKVU7XgHYZcPKdI1++CK0AsAAPAxUwm8pIHX6+npXgD0RK7mkh63f6y2h9FCk1YINyLqqwHQH6q80FqflRduFFHfCQBop2oxzl8SPh4TdjmcNO5y/VG1/W0AAAC8x7QCL6q7AL2QDpr30+PbtgZd3parvqR/z0ZueRQA3VdtVtsXA1pmUqXt1wCAVisebFZPrkXPCbscTboGutKVMRgAAGD6BnFCk+ouZQB0WK7okgdZHlXb610aaPmp2q4eV9vXRxEX6wirpoCuK3OFq4CWSdcgDwMAWq++OhlH7LXn8fQ7YZfDG0Xx3Wr5ifcLAAB4pxMHXlQFALrstaBLp1cUHQRf8r81fVkFQEfVEV8HtEiaGMzbbBkA0AnFN7nCSfRUOq/fS9eja8ER1Gl72fturVwuAwAA4C0nammktDbQXcVOGoS6/bh6cid66PPyws066hthgg3oIGXRaQv3WwB01O3NansjemYSYt0IjqWIYutsnLsyrKqdAAAAmDhRhZeBFbJAB+WqLotRX+pr2CV7lP7tozQhrM0R0EWjKK4GtID7LQC6qbjRtyovwi4nl9tAPY9nro0AAIA3HLvCi9WGQPf0u6rL+4yrveQJt7q3ZaeBril2FuPcRatDaTL3WwB0WR3Frb7ce39RLq+NIh4GU6FaIwAA8LpjV3gZ6DcLdEvV96ou7zOu9lJfSi+rAOiEeulZPLse0GCquwDQZYOov4oeyAHWUcS9YGry+9m3CkEAAMD7HTvwUkRxIwA6ILftWYzzl4bVdhW800/pvcnvUTr63w2ADujLJAutthYA0FHpPnxttfxkJTpuMK7sUgbTVO7G05sBAAAQxwy85NUJuW9qALTf7cfV9nVtLT4uv0eb1ZM8qHQ7AFouT7Lk8vIBDbRaLl8Pk2MAdN7e1eiwdD7P1drKYAaKG6q8AAAA2bECL8prAx2xvlltbwRHkt+zIopbAdByIxU0aKgi4u8BAN3X2fPdJFi9EcxIvaTKCwAAkB23pdFaALRWsROxcGmz2r4fHMuj6smd/B6O30uAttKik+YZV9N0vwVAL5Rr6bwXHTSKuBfMmCovAADAMQIvkxUKZQC0Ug5oDK5sVr9tBScyfg8HV4RegPaql7Q1omkGwi4A9MizKDrX1uiz8kIOVZfBjO1Xeel0WywAAODjjhx4GSmvDbSWsMu0Cb0AbTfq4CQL7aadEQB9Moj6q+iYImqtdubEdRMAAHCclkZrAdA6wi6zIvQCtJxBchpDOyMA+qaOYiU6ZLVcvh6qu8xN3n60NQIAgH47UuBFOyOgrRaiWBd2mZ383ub3OABaR1sjmkM7IwD6p1vXYiqOzFu99CKedio0BQAAHM2RAi/aGQEtdfuH6vcHwUzl97iI4lYAtIy2RjTIlwEAPbPXkSovudKISm3z51oeAAD67agtjdYCoF1ub1bbG8FcPKqe3Iko7gZAuwh10xRrAQA9U3Tk/Pc0nmqtczrKAAAAeuvQgZfV8pO82qIMgJZIg2ZDYZf526ye3MzvfQC0hrZGnD73WwD0WCcqnA1iQeDlVNSfBgAA0FuHDrzUMVoLgPaozkasB6dib/zeVwHQEiOVNTh1e51o5wAAR1cvrZXLZbTcIPYEXk5F4X0HAIAeO3TgZRD1VwHQEungtj6stqvgVPyU3vuBwBHQIkVHVhbTZoX7LQB661kMBD85plrgBQAAeuxQgZe1slyqrXoF2uP2j9X2MDhV48+guBsALZCvdfM1b8ApKbQzAqDX6jIAAADgiA4VeNmL3bUAaIdqs9reCBphMc5thNZGQEvsxtOrAadgvMCgtrIdgN4aRP1ptFwRA+HpU9KFllgAAMDxHDLwMlJeG2iJhWtBYwyrakdrI6A9CoEDTsWLeGrbA6DXulBZ+oUqNafmhUp5AADQW4cKvIR2RkALFBH3N6vftoJG0doIaI9ayJtTsSdsBQBltJz2hKdn5L0HAIDe+mjg5fK4JGQZAM1WnY24HTTSuLVRsRMAzVYqh85pSBNkXwYA9Fzbr8OKDrRlarEyAACAXhoc4jesBUDzfTustqugkXJro4halReg8XZd+3IKrAgHgIhnMWh1xbPa+fzUpGupvwYAANBLh2lpZLUh0HTVZrW9ETTaYpy/o8oL0HxayzB/ddS2OwCIuox2K4PTUgYAANBLHw28FAb9gebTyqgFcpWXwmcFNF79VcAcrZafuN8CgMiDlFoCcTyq6wAAQH99MPCyVpZLVhsCDZeru9wPWuFR9USVF6DpynwNHDAnC+1fzQ4AU1FH8eeA4ykDAADopQ8GXl7EU2EXoOlUDGmd+m4ANNiz2F0LmJO9GLnnAoB9KrxwfGvlchkAAEDvfDDwMkr3CgHQXNVinH8QtEr6zFR5ARqtiHotYG4Kk3sAMFYGAAAAHMEHAy9FxJcB0FDpGDUcVpXgRMtMPrNvA6ChCquLmaO0vWmhBQATqnQAAABwFB8MvNRRKK8NNNZZ7YxabHA/ABrKNTDzZHsDgFd2Y0EQFAAAgEN7b+BltfwkDbxabQg007i6y3YVtNJm9dtW/gwDoJHqJauLmYe1slxyzwUAr9RRlwEAAACH9N7Ay4IbTKDBai1xWm8UxT8CoKF2I9YCZmw3npcBALxUxEgQlGModiyKAgCAfnpv4GUvRkprA421qDpI652Lc/cDoLG0mWH2LDIAgD8oA46oiHorAACAXnpv4KWI+DIAGkg7o24YVtWOtkZAg5UBM/ZC4AUA3pDuEf8acER1FL8EAADQS2fe9wu1QX6gobTC6Y78WRZRrwVA49SfBsxY4Z4L6IaqiGInJhUW0njSP/P38uvB5HkUCzuLsbfz6o+c38kB+Hf9z9bKcini6R/a2rx47ZhZxGBp71Xrm3L8vfhrmvReSvcX6fvFUr3/7DjbNukz/HO0VxW2uVNRT441AABA/7wz8JIHF3bjaRkADZQGN4dBJ6RB6AdpYPqbAGieMl8Tv28yDqbEKvZO2p/43z92FG9OwFXv+xNpgvffB38mxhP2f3rr1yeT+G8sTikD5qbYGW/P9dYoil/ORFEtxGhrFpU3J+fed51/qziG8RjX83IQe0t7UaxMAjGf5ud6v4VhvRQ0iXMjR7agpREAAPTWOwMvL+LpSgA0U7VZ/WYgoyN+SgPkq+WFHYPMQBNNromHATMynmyl+Q4CLMVW+sx2cvWKen/yv97J1SteVa54f8WKWXl9In80DsCU44n8KOuo3ddzAvvb+IMcbskLDtp8DzbZLw9+/uHbv573o3zOH1eNqdfSv/tTQZjT1N73PVc6qsOZ/TScifPGiQAAoKfeGXiZrHgJgObRl7lr0oDgP9KkzN8DoGH29ie7BF6YHW1km2R/cj9PllUH1SvSMaBajLNVkys9vTWR/wer5ScrC1GXrybxYy3gPdI1+XDccrTdAZejmuxHw8mXDw6+fxCEGaWX6b35UghmXorWvseTtjrChnNX7KjKCAAA/fXOwIte8kBT1SYeO6hIg+m1wAvQOK6JmYMyOA3VZGL/l9wCIa8K7+pE2SS0kB8vJ/G/KJfX0r/96ngCXxWYvivStXgOoC/G+TsmjN/0WhBmePC9HCKrY7QfgIn9AJkAzPS1+j39ZzB3hXZGAADQa+8JvOyv/AJoHH2ZuyevIM11FAAaqAyYkXErmqfB7OVwS70fbimGC7E47Puk/o/V9jAmE/iXy+Wy2A+/1DfCMa9X8n6RHrd/rJ4Mg0N7LUR2J3+dA2TpTub6JABTBlOxlo5Nw2q7ipapx4FK5q8KAACgt94ZeFFaG2iqyQA9HZJbBewKvACNVH8aMCNP4+nSIJiNIgdavh1E/aDL1Vum4afxhHKeuL/z2sS9ynudVjxYjPpWG8METfR6gEz4ZXp2Y6GVVV4s5jgddRT/DgAAoLf+EHiZrDQsA6BxCtVdOihPQq2Wy1UYFAaap8zXxibLmYV0I1aOgunJIZf67iBdWqhYcTwHE/eXy+WNNGG/IfjSLSq6zN7r4Zd0f7MfHqv32x5xVIPYa2XgZbyYY7Sj1dW81a7VAQCgx/6wqHA3npcB0Ez6YXdUGgj+PgAayLUxs1LEwGTYieWQS5FDLlc2qyd/3qy2N1QDPLlc9eVxtX19FHExVwMJWq7YqaO49ajavmL/mJ90PLqf3/O8H6V7nW+DIxm1dDFEDkkX2jDPXR0D7zkAAPTYHwIvC1GXAdBIBo66qhi3HgBooL2VgBnYi5HAy7HtXzfcXoxzFzerJzdN4s9GDr6k9/daerkertXaqkrDPlceV0/uBKfi9QCZ4Es/WMwxf+diZKwIAAB67A+BlzTwalAfaKTaQHuHCTMBzZTOPUIJzEoZHFWVHusH1Vy0G5uPXKliFPWlGL//tEQRxdZinL+0Wf3mOrsBBF+Opt3XXwsqY81VsTVM+1cAAAC99YfAS23gFWioBaGIzlqIgQkroJEGUX8awCkbV3TZrLYv5vBFMHd5sj6HJ7Q4aoviwdk4d0UorHkOgi+5FVsIkb1XEXVrAy85ZFZEDIO5ECADAAAG7/jGXwMA5mgviioAGqiO4s8BM2ChwWEVd8eti7Y3glOVwxO5xZHJxWYbV3Y5ty7s0my5FVsO8aWXt4N3aHeFPW2N5udc1IKYAADQcyq8AK1xxgq4zhrFngF5oKFUeGE20qT0n4L3Gq+OX7i0WT25aeK+WXJ1CtULGqs6G/U1+0x75DBfbnMU7nXfUETd6nPkYpy/E1oyz1w6F93XzggAABi843tlADTSeQNGAMxbGTADbW7XMFvFTh3FrUfV9pXcFiJopLNx/lqYoG+cxYgrJn/bJ7c5Uu2lWyahM9WwZuysfQYAAIi3Ai+Xy+UyABrKSsXu+snAPNBga66RmYl2t2uYhVw1ZDHqS4+rJ3eCRsvX5WkwYT1oktvCLu02ad22rjJIN1pKjqJ2Lpsh1V0AAIADbwRezljBCgAAb9iNBcEEpq5W4eUtxd1c1cXkVXv8WG0P8+cWNEE1bqFC221W2/dHUV+KnldQantLo2y8qMMxckYq1V0AAIADbwReihgYdAUAgDfsrQRMnQovE1W6Kb2yWT25GbTOYpzbUI2iEW6rhtkdOSgxSsfFXPUqaDXHyNmoo7grIAsAABx4I/CyFyOD+QAA8JpaMIGZUOGliGJrMU3qjiuF0EaTkMW3wSkqdhbj/IOgU3LoJVe96muFkLojFajzMbJQiWSqcisjrQ8BAIDXDd780mA+AAC8rtD2E2YgtzB6cskK7fYbRC1scYqK9P6r7tJdk+pXAhMtls51d3LAM5gGrYwAAIA/eCvwEn8NgIZaK5fLoJPWylLgEmiyMmCKLrumua2FUXfkCj1ar5yeUQz+EXTaZrW9ESb5W62OwXpwQrmaVVwRlAUAAN72RuClUFYbgFPwNJ46/wBNJhQO07M+mbylQ+qI74NTcS4Wh0Hn9S/00q0K1JvVb1tFFLeCY1uIYl3YBQAAeJc3Ai9d6ZELdNNuLAhFdNQZ5x+g0YTCma5BL69pip1083klTdreDzpnoMLLKSm2tDPqj36FXrp37ZVbG6V9Vgu441n/ofrdewcAALzT2y2NygBoqDrqMgBg/sqAKRrEXs8CL0WakB9cya1vgk46E+e3gtPwz6BXtDdqt8U4l1sbVcFRrAvLAgAAH/Iy8LJWllauAo1WxMhxqqP2olgJgAZbK5fLAI5hHHbJ7RyCzspVRooofMZzVqus00tCL+2Vj5WjiCvjcyOHIOwCAAB81MvAy248LwOg0YQiuqrQLgQAOkjYpU9GUf8SzNVC1Patnsqhlzri2+iwri7M+6narvK5UejlQ4qdhRhcE3YBAAAOY/DqRd/KagNtU0T9p6Cjik8DoMFeaGvEFBUx6MG9l7BL/6jwMm9ntEbptcfV9vVuV1Z62tlz5fjcWN8K3qXK1w8/VL8/CAAAgEN4GXgZGcQHGq6OWAs6qXAOAhrOtTLTtNeDNo2DqK8Ju/TLmSiqYI6KneF+pQj67GycuxKCT600qV6yHryUA1yLEcKyAADAkbwMvNRRqPACNF3Z1bLGfVdHrV0V0GiuleHw0v5y68dqexj0yvMYmaCcryrovWFV7YwitMdpqXHoZeGSz29/gdO3OcAlyAcAABzVy8BLEbVBfKDxduN5GXTKF+XyWgA0nGtlOLTbj6snd4LeOR/nTbjP1z8Dkp+q7SpX1QpaKVczGUV9KXocYstB2dyiKwe4AgAA4Iheq/CiTDvQfHWM1oJO2YtCdReg8YqIvwZMTxmdVNzdrLY3gl6aTFRWwbxUARO5qlYRxa2glXJoaVypp3f7dZUGpq8IygIAACfxWoWX4k8B0HCDqD8NOiVNIn8ZAA1XR/HnAN4r3U9ubVZPbga9VmjLMTe1wAtvebQfGigeBK2UQy+LcT63N7obvVA8yP9eLRABAICT0tIIaJU04Xg16JhahReg8dK1snA4vF91VjsNklHUvwRzUlQBb1mMc+vRkTDUix5Wos6VsnJ4tNvVeoqd3MIo/TuvaWEEAABMw+DVy0LgBWiBemmtXC6DTlgtP8lhlzIAGk77T3i/dFO5Pqy2q6D3VHiZn4UYea/5g3GAYEEAseVytZ5RxMXoWCWnIuL+Ypy7qIURAAAwTS8DL7UKL0BLPFPlpTPqGK0FANBmt7Uj4IA2O/NzJs5vBbzDZvXbVrcrhPRDbnG0WW3n0MvtaLkiYpgGoK88qrbXVXUBAACm7bUKL1atAu0wiPqroBN8lkCLlAG8IU9gpcm4jYCJImoTmXNi0pgPyRVC8jE6aL18ns3VXuqIb6NlXgu6XBGOBQAAZmUQAC2TBnrW1spSVaqWu1wul/mzDICWcO5hejrRTrY6G7Ee8Jo0wFAF81AFfMTe/jFam7EuyNVeHlfb19sSfBF0AQAA5mk/8JInHQOgRZ7Fs+tBqw2EXYDWeSrwwlR0pJ3s7WGagAt4zQtBjLkovM8cQg5JLEQhmNgh7wi+VNEcVey3X1q4JOgCAADM05n8n0EsLO2v/QBoiUkrnDtBa6WB+r/XAQC0TTqH30+TWfcD3nI+zu/sxtMAmuGH6vcHn5XL3+Z7r6AzfhoHTq/n11+Uy2ujiLX0GX9ZR7EScwnV5spB9U6u5DKK4pdzUT8QggUAAE7LJPCytzQKgPbIrXBWy09WNqvftoLW0c4IaKMXEWVYVQ+5ldHtgHcYVtXOanlhJ7pRxajJqoBDOhfnb+7Gs6/sl900qaQyfP17a5NK3vnatYjB0l6MVsaBmP1r2YncXvFd20SxM64iVW/VUfw7/ZnqTBTVQoxejr0MqydVAAAANMSZAGit0fX0n5tB6wwivg6AltlLEwYBaGXER9Q76T+OlzOUJqD/GXBIOYj2t/Iv63tRfxf0wmvn6YPnB+/6fbk6zMHrM/u/9/xO3l4CAACgRfYDL6M3Ev4ArfH3tbLcMCDTLukzW9qNp2sB0DJFjEzg0mtaGXEYRRQ7dWhcOUv1fjsROLzc2mi1vPAgbT1XAyYm1WEAAABabRAArVXn4IQKLy2TPrM8yFoGANAmWhlxKLV2OzNXjKvowJGMor4VwlIAAAB0zEHgpQyAVipuBG2jnRHQVmVAT9VR3NXKiMOoo/53MFMDoSKO4ad0DC8EFwEAAOgYFV6AlquXPisvqPLSEqvl8vUwYQwArZImSIePqyd3Ag6hUEECGutROpbnY3oAAABAR+wHXmqTj0CLpQG7r9fKciloA9VdgNZK55u/BvROsXM2Yj3g0LTbmbUzKrxwAqq8AAAA0CUqvAAdUC/txlNVXhputVzOYZcyAIAWqbUy4qiqYMbOCxVxbD9W28OI4m4AAABAB+wHXooo/hQArVbcUOWluS6Xy2V6uh4AQJtUm9X2RgCNMqwqgRdOZDHObUTD24+NYsF2DgAAwEdNAi+1SWKg5eql5/FMu5yGGoxbGZUB0G5lQI8sRlwJOKKFGJiknq0q4IRyaKrprY0WY8+xBAAAgI/S0gjojDrqm1+Uy2tBo6yWn6yE6i4A0Da3tTLiOOoYmaSGFnhUPblTRAwDAAAAWmwSeClUeAE6YRRxT2ujptn7LgA6oFbhhf7Qyohje6ECyUwV3l+mqNlVXs4LzwEAAPBR+4GXWksjoDtKrY2aY7Vc1soIAFpGKyOAfvix2h5GFHejgXLbpQAAAICP0NII6BytjZph8hlsBADQJloZcSI/2X5mrQqYosU4txG2KwAAAFrqIPBSBkCHjFsbLZfBqbic3vv8GQRAt5QB3aaVEUDP5EoqaXBwPZqlCgAAADgEFV6AriqfC1ycmoUovgsTwwDQKloZMUVVMBN1xD8DpqxprY0KxxAAAAAOSeAF6Kw0GLz2eXnhm2CuVsvlr+uoVwIAaBOtjAB6TGsjAAAA2miwVpZLAdBRddQ3Pysv3AzmIodd0tNGAHSUa2e6qIgYamUE7VBHsRMwAw1rbVQFAAAAHMLgaTw1aA90WhH1N38r/3I1mKnJe7wRAJ3m2pmuKXbONmeCk47QjmR20r2NwAszM25tFLfjlGndBQAAwGFpaQT0wl7U91bLT7TZmZH83ub3OACAVqm1MoJWqWMg8MJM5YpfufJXnKK0nW8FAAAAHMJgEAtWqQI9UKdj3eih0Mv0jd/T0cPxewwAfEzRkJYkaULz/uPqyZ2AKRupzjAzCzESeGHm9saVv6o4JbZzAAAADmswiD0TlEBPCL1Mm7AL0DcvIsqAE2tES5LqbAPaVgDQPD9V29XgFNvdnYnzKrwAAABwKFoaAT0j9DItwi4AcDx1Myq8aGXEzDSlilEXnTnFqhv0y4/V9jDty7di/qphVTmGAAAAcCgCL0AP5YDG3s+flRduBsfyebn89/weCrsAwNGdiaKKU1Xc3ay27wfMTCOqGAEn9Gi/7V1xN+aq+CUAAADgkARegN4qov5mtVz+OjiS/J7VEfcDoIf2YiDox4k9j9FptmqoFuPcRgAtdV6YiLnarJ7cTPd/38bc1NoZAQAAcGiDUUQZAP218Xm5fG+tLE1gfkR+j1bTe5VebgRATxUxcr7gxH46xVZCixFXtIpg1hrStquT7L+chnNx/mYRxVyCKIO0mQcAAAAckgovQO/VEdd34+nPa+VyGbzT5fTe5PcovbweAMCJzWvi8C23h6cYtqE/Ci2NoFNy0OpsnLsy+3NXsfNjtT0MAAAAOCSBF4CxcjeKnz8rL9wM3pDekxuD9N6EimAAMDV1xPcxR0War9ystjcCaLMq4JTMKfQy13MjAAAA7SfwAvBSvVRE/c24xZFqL7mqS3ovHqb35E5+bwIAmJpB1A9ifqqzEesBc7IQAxVeoINmH3qZ67kRAACADhjUUZjEBHjNuMVRPOxztZeDqi7pvVgLAF5y7cy0jFs2FHMJBSzE4JZWRsxTHSOBF+ioHHp5VD25lM5hd2O6qs1q+34AAADAEQwKq/YB3qXM1V5Wy+VfvyiX16In8r9VVReA93PtzHTV054sfJfbP1S/WzEPHVBoaUSDbFZP8gKR2zE93wYAAAAckZZGAB9WjiIedr3N0UHQJf9bVXUBgPlYjPN3ZlnlJbec2Ky2NwLm7IVgBvRCPseke8iLcfJ9vhqfEwEAAOBoBF4ADmHS5ujXrgVfctBlNf2bBF0AYP5yW4gZVnmpzkZ9LQBghn6qtnNY5VKcrNrL7fE5EQAAAI5G4AXgCA6CL6vlhe/a3Oro9You6cvrAQCcismK9iqmbuHaME1CBtAlVUAD5bDKQbWX+uitiW6nP3s/AAAA4BgEXgCOpb6awyKr5fKv6XG9DVVf1spyKf2sX+efWUUXAGiG8Yr2halWYqmjuLVZ/bYVcErOx3mVGqCHcrWXx9X29XHwpbiVW+u9/3fvt/Rb13oPAACAkyg+K5fvFxF/DwBOJB1Lh3k122J6bsqK6hxyeRbPrg+i/krABeDk0rH+/qNqez1gynKANj3di5O7bfKQJkjbdB1MlXMQbZTvSV/E05W9KFaKqJfy9wbpnvlMnN/SxggAAICTOhMATMUkULK2m/7zeXkhr2QbpgG9f8xzIO9gMLGO4qv0E63sxtO1YvyzAQANlts5/K38y85ejL5JX5ZxDDl4+1jYBTor7eP/DGiZyb3wcPIAAACAqRJ4AZiBOuqV9LSSBqVv7sbTSQCm3hpF8ctCep5GCCa3UXqRJsTySrlB1J9Gek5/18rBTwAAtMsP1e8PLpfLW0XExlGrcOZKc5vV9vUAAAAAAOgJgReAOTgIwBTp1Si9yCGY1XI5xj3N6506ip1i//mPqzbT7/lTTEo/J2W9v+q7WNqdfC//P+vJ3wIAtNtP47aI178ol++PoriRzu9XP/Znxi0Vz98MaJYqjlmtCAAAAAAOQ+AF4BRNgjDjV+//Pe/8LgDQXT9W28P0NLxcLpeDiLXcOjE9/7WOYuVVELbYSa/vamME/VDv7/MAAAAAHBB4AQAAaKhJxZf7kwfQY7kiZAAAAADw0mDcKgMAAAAAAAAAANphULwshw0AAHxEGQB8VBFRBQAAAADM0CAAAAAAaLSBEBEAAADAGwReAAAAAAAAAABoFYEXAAAAYKrqKHYCAAAAAGZI4AUAAACYqjrqfwcAAAAAzJDACwAAAEDDnYmoAgAAAICXBF4AAAAAAAAAAGgVgRcAAAAAAAAAAFpF4AUAAACYqiKKnQAAAACAGRqkYailAAAAPqqOKAOAQ6gFXqZsWG1XAQAAAMBLgzpqgRcAAAAAAAAAAFpDSyMAAAAAAAAAAFpF4AUAAAAAAAAAgFYReAEAAACmrQqmqNgJAAAAAN4g8AIAAADQaLXACwAAAMBbBF4AAAAAAAAAAGgVgRcAAAAAAAAAAFpF4AUAAAAAAAAAgFYReAEAAACmaiEGO8EUFd5PAAAAgLcIvAAAAABTVcdIQGOKiqi9nwAAAABvEXgBAAAAAAAAAKBVBF4AAAAAAAAAAGgVgRcAAAAAAAAAAFpF4AUAAAAAAAAAgFYReAEAAACm6kVEFUxTFQAAAAC8YRBRLAUAAAAAAAAAALTEIKIWeAEAgMMpAwAAAAAAOHVaGgEAAAAAAAAA0CpnAoBTUUSxVUd8nx7VmSiqhRht5e8Pq+3q9d+3Vi6Xu7GwNIi9pb0oVoqIsoj60/Tn1gIAAAAAAACghwReAOam2En/+XYQ9YMzcX5rWFU7h/lTbwVghgcv1spy6UU8XdmLuF5EfBnabAAAQCfVUfw7AAAAAHiDwAvATBU7RdQPiohvf6yeDGOKJoGZ4eQRX5TLa5Pwy98DAABO0fk4v7MbT4NpqQ8VlgcAAADok0EAMAP71VxuL8a5i4+q7fUfq+1hzFj+Ox5X29dHERfz350eVQAAwCk4bDVDAAAAADguFV4Api8HXe6c1iD/T+MWSBuXy+X7gyhuRtQ3AgAAAAAAAKBDBF4ApqSIGJ6NWB+OAyenbhJ8uXm5XL6zEHGvjlgLAAAAAAAADmWtXC7z84uIcpQe+XUdxVIR9VJ+XUTxp5i8nr1ip4763wdfpZ9jJ/0cOwsxSN8f7S/CTpP/VVPmqWAeBF4ApiBdVNzarJ7ciQaaBF+urJbLG+n56wAAAAAAAOi5tbJc2o3nZcTeSg6xDKL+dBxmibIeh1jK3Xf8uSLNCh2oX3s9e/U7f469GL38Xv5503xQ/tWd9Pt30r+lGgdjokq/658LUW+NYmFns/ptK6ADBF4ATqaKWLj2uAUXBpvV9qTNUTyMSQoZAAAAAACgy3Kw5UU8XdmLYiWHWiI91/thlqcvK7MUL6Mr842wzM5+YGep3p8PGv+bivQYR2P2JqGYqIr9ea5i6yAMcybObw2raiegJQReAI6tuLsY5zbadOLP1V7Shd2l3Xi2kS5wbgQAANAGVQAAAPBROdyyF7trL6Iui4gv01zIym48LfOvvR5qYV85CcSsHYRh0nuVwzDVuDJMfL8Qg62FWBwKwdBUAi8AR1bsLESx/kP1+4NooclFyc10wZKr0uQWR2UAAAAAAAC0zFq5XD6L4uq4HVGsvQq3cAKTIEys5XZJe5MQTK4EE1H/I2JhS0skmkLgBeAI0gXS8GzU68PqSRUtt1lt379cLg8XIu7li8AAAIDpqkK4GmCm8grmiKdLu7GwNIi9pdGr4+7+cxrH+Otrv/3g16L+w/G5WJqUvT+iYmdcBr/Oi2uqURS/KIUPAMzSmwGX4upuuoYpOtOGqNHKdM2XHnF13BLpQr7WG+YAzGJ6HlbbVcApKFbLZfs/wCGkC6dbj6snd6KD0rlgI8bVXgD4iM1q2wIRgENI15i/hsDLtKznwHoAvZEncnKIJU0mrKTxiKXBfnBlP5BS1m+FWpqq2F8BHMM0AfWPH6vtYQAAHMNBi6JR1F/WUV8N95lNldsgDQcx+EdbOyTQTgIvAB9XRSxc63p5tstpMC0NoD0MF4sAHyTwAnA4Ai9TJfACHZMnbnbjeZkDLenLclKJ5SDMUkb3VOlx2+pf2iwH0Q5eH1RVOvi6iEGajB0dukrSYLxP5BL8lX0C4I9eq+LylQr1bVU8UP2FeRB4Afig4u5inNvoSxne8YDbs410EXIjAHgngReAwxF4mSqBF2ipg2BLHaO1SZWWlQ6HWg6jSo/76Zh2O+CUHLQCe5H2w9F+0KzIrTCWXmsBVuY2X/WrNl9lzFiuiFSP24P9ko4VQ23BgD76olxeS8flL9Mx8Wo6Bq8EnZErv6Tz3LfCL8yCwAvAOxU7C1Gs97XsWjo3XI9xi6MyAHiDwAvA4Qi8TJXAC7RAnkR/EU9X9qJYGUT96WQ1chm8S5UmPK6Y8GAWclWAvRisTCqutLaCUp4cHEXxj3NRP7Cv9MfhAlkR9Xu25SKNa6df3anHz78sxGArnZeqrlcvp70OQi7p5fVw3dQT48ov7nGZFoEXgLfkm8mzaUC57zeSucXRQsQ95QIB3iTwAnA4Ai/TM0iTwj9W28MAGiVPqu+mp3Rx+KVwy/GkCdlbj6sndwKO4dU+WHw6nvzP1QCKpXhVmaUzDlbGmxzsjoNg1ouoyxySTJ/yyqSqUBkzIkRFU4wr4D29kbbJNfMPvVaNz28Ld4XyOAmBF4DXGGj5o3Se2IhxtRcAQuAF4LAEXqZH4AWaYTI5c1XAZeo2tDjiY1bLT1bGrcFeBgP62uqiSo/bgi/t8no4a9zarlg57WDWuI1WfVd7EeYlX0c9i2fX03H8KyEX3vbqmHT+gZZ+HJXAC8BYFbFwTYr03XK1lzTI/jAM5gEIvAAcksDL9Ai8wOk5KLOfBuGv9niCfeYsQOJ1B+3B0nbxVVPCAQ2kLViDvR7QStvv1aZvv2mQ4/7ZiNu2J2YhX0vl43m937LIsZyPKXaKqB84JnEUAi8AUdxdjHMbUqMfNl7J9mwjXZTeCIAeE3gBOJzPyws/mxyeDoEXmC8TM6fDsa7fXoXLtLc4IhWSGuDNCmDND7i8j+AL06KaC9OQ2x2lx23Xh3yMwAvQY8XOQhTrP1S/PwgOLZ03rse4xVEZAD0k8AJwOJ+Xyw8Nbk6HSWCYPSGXRqgW4/wlC5L64VUVl/h7mwMCDaHayynIbYqepW23gxP6VWibxTG5nmJGqnBc4gMEXoBeysnQsxHrbgSPJ7c4Woi4ZwID6COBF4DDEXiZHoEXmA2rjxspT2ZsBJ01ngwVcpkBoZc5mFRyudGHSkTGzzks11PMURWCL7yDwAvQO/pCT086h2zEuNoLQG8IvAAcjsDL9Ai8wHRZfdxkxc5inLuoyku32OfmRuhlBvo9mV+kY3F9y+Qy73IQAEvbyU3HduasCsEXXiPwAvRJFbFwbbP6bSuYmlztJQ3APwwtjoCeEHgBOByBl+kReIHpmFSW+NqxqdksVOoO+9ypEHqZEtWIXimiuPOoenIrIMb7xijtG2Hf4PRVIfhCCLwAvVHcXYxzG1YIzcY4zf1sI13g3giAjhN4ATgcgZfpEXiBkzHp3i65jcajavtK0EqvVvznai4WR52SajHOXzIOenSvqrnkoEu9ErxURLF1NuprwlT95XqKBqtC8KXXBF6Ajit2FqJY/6H6/UEwc+mccj3GLY7KAOgogReAwxF4mZ7FiIsmF+DoTMy0V5qs/7PJ+vZJ40Jfa23RDCpyHE2uYJ3GkG9ou/VRKgj1kOspWqQaRKxbLNI/gwDoqLwiaDHqS8Iu85MTtKN005Pf+wAAAIBTkCcuV8sL36X7U8G7ltqNp1eD1vhb+Zerq+Xyr+nlhrBAM9RR38yfS/BBeSI/h7TTRNmv+T2z/X5UuZvOrWvpPBt03sH+4XqKFinz9pq223uOU/0i8AJ0Uu73nMvfSpvP30/pPZ+UHr4dAAAAMEeflRduDKL4OY0MmOhttUIrkRbI4bI8GboXo+9Ctd/G2Yv6Xm7RE/yBifwTEXrpOPsHbZerdaXj1K/jynP0gcAL0DVVxMKlx9WTO8Gp2qy2N9JF8cUY908EAACAmTmYeC+ivmOFfvulz/FPQaPlSaRxVQyToc1VL+3G05vBSybyp0bopYPsH3TQRq5Alx7Xg04TeAE6pLi7GOcvbVa/bQWNkKu95M8kfzYBAECvpIHSfwbAHOSwy8DkTNeUQSONw2UXfo799kU0X3FDlRcT+TMi9NIRB6Fh+wcdVabHPW2Ouk3gBeiAYmchBtc2qyc3h1W1EzRK/kzyZ5NerodqLwAAAEzRQdglBCQ6pfZ5NlKaLPp7bhlWR63lVGv0u8qLoMvMlc+j+E6oqp3y5/Z5eeEb1brog3Gbo+JnbY66SeAFaLUiYrgY9aUfqt8fBI22WW3fTzeXV/JnFgAAAHBCwi4wP3mCKE0W3dcyrI36V+Ulnx/SNntP0GX2cgDueTz9JmiVz8oLN3bj2a/p89P2jB7Zv4bZb3Ok2ku3CLwArVVHcetRtX1lWG1XQSvkFkf5M0svbwcAAACcQBrYzCs0y6CLyqAxJquhN4KW6k+VlxzsydtrrkSUvrwezEWunKBqQjuMqx5d+LmI+o4AIz2WW7L96rjVHQIvQBtVEQuXHldP7gSttFltb4wiLoYWRwAAABxDnrAJk5kwc8IuXdH9Ki9pW72eK1bE/vZqIv8UbEzOzTTQJAw2qXqkLR1MqPbSEQIvQMsUdxfj/KXN6retoNVytZf8WebPNAAAgA84vxPAG+pxdRc6rG8tWJro8ngCaCPogO5WeVktP1n5vFzO7e3uCbqcrlH6DBy7m+egfVEICsO77Fd7SfuJ9l4tJvACtESxsxCDa5vVk5vDqjLY2xH5s8yfaXq5Hqq9AADAO7kHgjflSfg6Yi3ouKcmTU/Zwn6AgO7oVpWXg/ZFEXs/Oyc0Rpo4fua40RD5eimHwbQvgo9L+8k3q+WF71R7aSeBF6DxijS+uxj1pR+q3x8EnbRZbd8fRVzJn3UAAADABwxMbMLMCZZ1UXeqvOTWOenf8nOoQNRA9VWtjU5fruoyiEIYDI6kvrob8fBv5V+uBq0i8AI0Wh3FrUfV9pVhtV0FnZZbHOXPOr28HQAAAPBexUoAM3Umogw6qN1VXvLP/nl54ZtRmpAM22hjaW10elR1gRMr92L03biCGG0h8AI0VRWxcOlx9eRO0Cub1fZGuim6GFocAQAA8A5pEufToPNemMw+VS+My3RUe6u8HFR1qaPuRJWajiu7Uk2oTVR1gana+Ly88LMWR+1wJgAap7i7GOc29Knvr1ztZa0sL+3Gs410I34jAAAAAJib83F+J43L7KgQ0EX7VV7utGXsNVcKeR7Pvh4JurRMu7azNstVXRYi7tVRrwXTVqVteSs9/7NOr4uodwbpeRQLO4ux93LbPmyHgnHlo6cvz6sH4d7R+Dk9iqVxsLtYSp+nioanLH8GucXRF+Xy+o/V9jBoLIEXoEGKnYUo1n+ofn8Q9N7kZujmarmcLyhz+bgyAAAAAJi5PC7zeRqTUSmgi15WedmIhptUdbkXxgVbqD3bWZvlfWQUxXe1cOKJFVHkc973adtN8xELW5vVb1sxZZM5j9dDYNWHfv9q+cnKQtTlXtRrOQjjnHwqytxGL81TbWxW27eDRirSB1QHwCkr0rn+bMT6YZOw9MurlLoLOuD0pZubIgD4qM/K5fvpgPn34MSce+BNji+9sZ6Of/eDUzOeSI2HQQcVO4tx7mKTq298Xl74Rvuitmv+dtZm9pGTOQi4DKJ+cCbOb7VlO83n5r0oVtLP/ZX5kvlK28yds3HutmNa86jwApy6Oopbm9WTOwHv8dM4CHUlp2hjXO0FAICGKz6yWg3g+HJp+VrgBWYsl+//vFwemlDrouZW3xgvfNuvWKGdR+vVS8/i2fX0wtj/FNlHji8vvB5F8Y9zUT8YVk+qaKFJa538uJNbJKVj+dX0L/sq7W9Xg5nKAbP8fq+Vy1cs3m+WQQCcnipi4dJjYRcOabPa3hhFXAyTJwAAAL11Ls7dz6vGA5i5NDmofH9nFTfyZGk0yGflhRuDKH42kd8duQpFMDW5uod95Kj2rxlvL8b5Pz+qtq/k+aiuhBVypZFcDW+zenIt//vSt9aLcRiG2Sl391scfWIfbBCBF+CUFHfTCfjSLPog0m252kvedvI2FAAAAPTOuIx47Z4Q5mCyklzopZNeVnk5dTl4k9uzFFHfyT9X0Bm5QlQOaQQntloufz1uM2cfOYwc/EiT4Fc2qyd/zgtpu96G5iD8kkM9edFw2ve+DQuHZ6WM2Pv5s/KClmINIfACzFmxsxCDa+ki46Y+dxzX+OLtSb6YWA8XbQAAAL2zGOdztdgqgJnLE4VpTO9B0EG5ystyGacot2fZjae5YoWJw44aaYt2IjkQtlou34sGtiBroiLifu4skIMfk9Bm7+RFw4+r7evp/J2r5ZtDmZEi6m9yEC04dQIvwNzkRO1i1Jd+qH53g8xU5MRyumG6okwfAABAv4wX0Sxc09qo08qgMRbj3HoRhUrNnVMvPY84tcm6z8vlv+f2LGF/77hCW6NjyoGw5/HsYXp5PfiI/a4CuW3Rus4Cr4xbHgm+zNBGrlAWnCqBF2Au6ihu5URtV3oj0hw5rZy3rVBeFwCAbqoCeKfxZMYg3w9WAcxUDpmdjXNXhF66p04T6afRciaviq/3KzFoz9J99UquUhIcyWr5yUqaxH1Yp/cveK9c0WUx4qKuAh8m+DI7uULZannhO8e50yPwAsxalcvHPa6e3AmYoVxeN/emDBdrAAAAvZFDL7nyZ7gXhJkTeumueo5VXvKE4Oflcq5YsRH0xm48vRocWq5+FDHK+0kZvFOu+p4mua/kii4WWh/ea8EXC4inqr6aqzGddpvAvhJ4AWZov4TcJeXjmJdc7SVvc3nbCwAAAHrBvSDMTw69PKqe2N86po5Ym0eVl/x37MbTn/PfF/RMoUrJIX1WXrih+tGHFDsHHQV+rLaHwbEcLCBO29q3wVTkaky7EUIvp0DgBZiBYmchBteUkOM05G0ub3uhNB8AAEBvHNwLqvwJ8zEZe7E6vEPS8fNezFCexE9/h4oV/fVl8FG51VcRtWr571U8WIxzF3UUmI4cGn9cbV8PcynTVAq9zJ/ACzBVuYzcYtSXfqh+fxBwinJpvlzWOm+TAQAAQC/kgftJmfZ1bVfarrCyveHy6vDcyjxMknVFmSbbN2LKLqdJv9zCyCR+75XBB+WwS2j19R4vF1lfs8h6+g7mUlR7mRqhlzkTeAGm5qCMnH6JNEUe6MzbZFhxBAAA0Ct54D63XRkYvG+tNDn+p6Dxcitzk2RdUtyY5gRdruoyiEILIyK35zH5+36r5XKusLQR/MF4kfW5ixZZz5ZqL1O3H3pZLT/Rzm0OBF6Aaajyag5l5Giqg36U4UINAACgV36stod58H5yT7iuCihMn0myLqmXnk+htdEX5fLa5+WFn8dVXWrVmti3Gwu2hXeYhF2uB3/wapG1qi7z8qpyvkqJU1BGjIRe5kDgBTih4u5inL+UV3MENFgefMnbat5mAwAAgF6ZtDq6nydNDsIv6f7wQS6RH8BUaInQDbkay9/Kv1yNY8jti/LkfdoOHtZRm+DjDWmbKIM3CLu8V2WR9ekZV85/klsWqpx/Yjn0KfQyawIvwDG97Jl4U7qWtsjbat5mw4ojAACA3joIv6T7wzyu8efc9igvjrCSFU5OtZdu2Iv63lHazxwEXdLx9Ncwec97FDFS4eU1wi7vNm5hFFcssj59uXJ+uj6+JSB+UkIvsybwAhzZ+IKjvqRnIm31qiyfUtYAAAB9l9se5cUReSVrrv6Sy+e7X4STyWMv40q7Voe3U25tVHy3VpbvDSjkXxu3Llp+KOgCRyPs8j7F3XELo+0qaIR0fXxnlOYDQ4j1hIReZkngBTiSVz0TXXDQbuOyfNtXwsALAAAAE+PqFE/uHLQ+qvdXtRrgh+MYV9rd3pi0EauCVsktiZ7Hs4cHlV5ywCVP1H1WXrj5eZqs341nv45bF8VawOGUgbDL+92eVGenYfL18Wi/IqJz+cnk0Mved0epoMbhCLwAh1XpmUgXGXgBAADgXQ7CL+m+8WJue5Qmdb8N5qaO4s9BJ0zaiOWxF4uOWiaHXnYjfk0T9PVuPP2/00Tdz0XU39T7k/W19jRwRJ+XF74JYZd3Wc/j9EFj5XN5rtymBeiJlem8+lDoZboEXoBDKO7mE5meiXTVwcVa3tYDAAAA3pLbHj2utq9PFkysh0UTM5cm1f8UdIpFR9BvdRQ70WOr5fLXddQqmLyh2Mmh4twGL2i8XLkttwAVAj8xoZcpE3gBPqDYWYjBtVxGLp/IAjpsXGZ3v2SigUsAgCno+4A20E2TShX3J9Uq3D/CEb1qi1A8CKBXiqh7e3+Qwy7paSN4Tb5fHFzJoeKgVXIIXOjlxMrnUXyX2wUGJybwArxTETFcjPrSD9Xvbj7plTxwmQde8j4QAAAcW58HtIF+EHyB4xkHx55cCy2OgB74rLxwI4Rd3lblsIuuAu0l9HJyuW3g83j6TXBiAi/AH9RR3HpUbV8ZppvPgB7KAy95HwgDLwAAAHxEDr6M2+S6h4SjyC2Own4DvTHoYTh0tfxkpYj6TvC6anG/jZGwS9sJvZxcev+uTypAcQICL8DrqoiFS4+rJy7AIPSWBgAA4HDGbXLdQ8JRTUIv6wHQMZfL5TJi77vgNcVODrtYbN0dQi9TsfFZeeFmcGwCL8BEcTevRpKqhTflai/jlXrF3QAAgLkrtIaCFhm3atlvc6RqBRxSrpIUQi/QeWfifG/mHnLYJU3APkwvy2Ai39cMhF06KIdeiohhcGxF1N/kilDBsQi8QO8VOwsxuLZZPbmZVyMF8AfjlXpPcsJWX3YAAOYqDXy5T4MWylUriihuBXAoOfRin4EuK3b6NP+wEEWu7FIGLw2ivmbBdXedjfPX0nnc53sie9+t7VeG4qgEXqDHcuJyMepLP1S/Pwjgo/LgyyjiirQyAAAAH/OoenInLzJSqel46iiWgl55NG6zrjoSdFARdW8mwlfL5a/rqFVqeE06p9/6sdoeBp2VA217UafrXguGT6B8HnEvODKBF+ipfIHxqNpWPg6OKJenzvtOGIABAADgI/Iio4UotGo5llrgpYdydSRtpaF70nzEv6MHPisv3EhPG8Hrbj8eBxrpuDx3khcMC3sfXx2x9nl54ZvgSAReoH+qiIVLLjDgZPIATLp4y33ZqwAAAID3yKEXrVrg8Bbj3Ia2CNAtdQ8qZl8ul8siavMub7o9DjLSFzn0MhhXeuGY6qhv/q38y9Xg0AReoFeKu4tx/pI+iTAd+eIt71NWHgEAAPAh41YthZbScAiv2iJYIQ5dUcRgGB2Wwy5pwvVh8FKRDufCLv2U21cJe59Mug66t5aOK8GhCLxALxQ7uWf0ZvXkZr5hDGBq8j6V9630MpeorgIAAADeYRT1LRP4cDh5kZF2YNAVxU7XF+EOosgtSMrgQHV2PF5OT03C3hYKH1u99DziXnAoAi/QcTlFuxj1pVw+N4CZ2ay27+f+lEUPynMCAABwdHkCPw1eG/iHQxqPZ6qMBB3wfXTYarn8dTq/az/yUrGzmMbJh/vXPfRZXiisReHx1RFrn5UXbgYfdSaAzqqjuLW5n6IE5mE8eBlX0k3ORnr+OgAAAOA1i3H+zm48db8Ih7QY59Z349laXukccHJVMa7QXKWx83+n7eoPVbfSr/81/dpSkba59Lxi25uGurPBtdXyk7SN7G0Er6lvCbtwILcoHETxs2Pp8aRz0TfpODPsepWskxJ4gW6qIhauPXYAhFORe5NeLpfvT/q2lgEAAAAxbov7ebk8zCs2A/io8T5z4XbaZ74JOJocbsnH2+/TWPnWYpyt8vYUR7RWlksv4unKKL1M/78vhWCObjHOdzLwksZ/yzSd/13wutu5EnrARF4k/EW5fG00nivhWPa+S+eiS8c5h/WFwAt0TnF3Mc5tOPDB6coXcvkiZDeebaSb4BsBAAAAsV894LbACxzeo+rJnc/L5a/sN3xMDriMovjHuagfTKvCxGScfRivtTFPk7dr6e+5msb8vgqL3T4ofSb3uzpXMRhX+C6Dfbl1TTpebwS85cdqe7haXrhrnuTYyufxLB9vbgXvNAigI4qdhRhcyz3xhF2gGfK+mPfJ9HI9xuVSAQAA6LkzcX4rj+MEcGg5KBbwTvvH09uLERcfVdtXHldP7sy6nUqevM1jfpvV9sWIhUt1xLdh7O+divF70zmr5fL19HQ9OFCdjfpawHvkY2YORQXHUkd9M4ctg3cSeIEOyMn1xagv/VD93tlemNBmuYzjKOJK8dpKEAAAAPrptWoBwCHlgIFxFd5S1VHcWoxzF3N78VmHXN5ns/pt63G1fX0cfol12+nriq2870bHjFsZ7Vd34ZXbp7UP0h57+6Eooe/jSnNM93KbveAPBF6g5fJFfU6uu5iAZsstjvK+GlYkAQAA9F4d8X3wEYUBfd6gygtj+5Ol6zlgMq7m0pxq53nRWx7/S5OSF+uOVjY5mvpudNBCmnQOrYxeU9zN237AR+Q5EufyEyl34+nN4A8EXqC9qlwuMV/UB9AaecVJvukNZU4BAAB6q45ald6PqgVeeIMqL3130Lpov6LL/WiwPKmbq770OfiSW5d0MQTxWXnhRvpM14IDVdonNwIO6VGa03QuP5Gv18ZVpniNwAu0UnF3Mc5fyuUSA2idfNOb9+G8LwcAAAC989N+pV4l3eGorAzvpzw5uhj1pXHrouZUdPmYPgdfzu63LumW3MoobYsbwUuLEVfatE/SDHsR666Dj+/5uMoUrxF4gVYpdhZicG2zenLTRQS0W96H874c+xd3qr0AAAD00DCAI8lVXkyS9UmxU0dxK7cJGu4HBdvpIPiSJuRyu/MqOq+42+bP633S5/e16mNvuN3Fz5nZ09roZHKVqdVy+XrwksALtMRBiv2H6nclb6FDcmnPUbrZVcYPAACgd/4ZwDHUKub2Q5WmsK48rp7ciY7Iga00FnixiOJWdDf40skWN5PJ5evBgSpXXAo4Jq2NTqr4Zq0sBfAmBF6gBbqQYgfeLyea8z4eUs0AAAA9UmtVDccwirgfdFzxILcD36x+6+RxMk/05gVwXWxz1MUWN7mVUexXd+HA4rhaEZyI1kYnUS89j2eOSxMCL9BsVcTCpS6l2IH3y6n43NM3tDgCAADogQWBFziGSSuEYdBVtzerJ9e6Fpp420Gbo+hQu/O8cLe7rYyiDA5oZcRU/LS/Hanadlx11DfXxoG83hN4gcYq7nY5xQ68W77Iy6VNQ7UXAACATluMs1UAx1JHfB90Tg5M9K1NykG78zwfEO12u4sLd1fLT1ZCK6PXaWXEVKV50HzcqIJjeR5xLxB4geYpdtKOeWWzenKz6yl24P3yjcNCDK6Fiz0AAIBOmoz7VAEcmbZGnbTe10rn4wVwT27mys9FFG1cAHu7uyGIve+C11mkyVTl6+HBuNIVx1BHrH1RLq9Fzwm8QLNUi1Ff+rHaHgbQez9Uvz8Yr/AwAAoAANBFaWLTYic4hnEbBOMlHbKeK51Ez+Xt+lH15FK0q81RZ8Mun5UXboRWRi8VEfftp8xCnhPVqvD46nHbtV4TeIGGyMnt3MJI70PgdflGN4deWrq6AwAAgA8YRf1LAMdU/CPoAmGXt+T3Y9LyvMHBl/3A5npXwy6Xy+WyiPpm8NJZ1V2Yob39450g+HHkKi+r5fL16DGBF2iAPJF9Ns5d0cIIeJccesnHCKEXAACAblHhBU6iNk7SfsIuH9DU4Mt48W59qcuf3WBcMaEMJoq7FmszS+PKbfXd4Li+XivLpegpgRc4ZcIuwGHkY4TQCwAAQLfUWrLAsY20P2i728Iuh/P/sHf33nFdZ7rg311Fggi6l+AMtMaj42wyUxlNycvFbCYyHU5E6C8gnc1EIrPJRGaTicomM5XdTOXbEqVMcHYzH7VbLWQNreuABIXacw4KlPkBgKhCfZyP328tGhQlS0Sx6tSuvZ/zvM0JvhyFNO/XY5e6HH6o212qLzvBC+VG5AcBS7YRmw+0vMytOIinvW2lEniB9SovR/6jsAtwHi9CL2FDFAAAoBNSZHtCMKfp3eAOxlrqfldH4SzTi+BLdbB3M0d8FiuUIh4dt7rci44bRnwa/Cxrd2FF6vOPZHTWBaQ7fW15EXiBtUn7G9XC1EIBmEW96JtU1w4bOgAAAO03cEMDXEgy1qiF0mNhl4v5stwbf13u7VR7hEetL2lpbUfTRpfqHOPXX5V7H/XhLONGsb2TI0bBC+XX5Q/aXViZr6bPtzKYQ97qa8uLwAusTf6TsAswj/oOpmGkjwIAAIBWm8TQzQxnGE3HSsCpcqS/Bm1SbsQVe1oLUu8R1q0vX5V7N1+EX+rmlwuORC8j0sO6Rab6s/p1HU7q2TnGx8HLtG2wcoPp+Dbm0s+Wl0sBrEF6+KT84VEAzOnfyv98fKO4+rDa2rkTAAAAtNIkDvfdkQjzqw73yxS0Q914nm/W7cXBwk1HfMWj4x9RH3j+FE+vHUa6Vr1GihT5neqXi9f+b2WO9GP9OroUqRzGZLfPN+nW7S7x5mPUZ0eBqoAVq1usPii2x9qW5vFzy8u96BGBF1i9OsV+LwAuqL6WVIuXP4QPYgAAAK20GZv71ee6AOZTH9If1rEXWkDj+SodB4vGsbRxR52k3eVV2l1Ym1Q9/wRe5nXU8vKgTwFTNxDA6t2XYgcWob6WqPcDAABoL3tEcDHPY3KR0S2sTN14rimC5rpRbNdhlyJ4odyIzccBa1K3vCSBvTn93PLSGwIvsELVxfmRhT2wSBZ+AAAAQF9Nx7gkwbFmK5+UP/Tq4I12uV5sF9WXneBnKdJjoVzWLWkZuoCjlpet6AmBF1ihyy7OwBJY+AEAALRaGcAFZIeyDbYRcTOgwaqD0tuh3eUVlyM/DFgzN/teRN56Fs92oicEXmBF6nYXM0qBZbDwAwAAAPorGWvUXPftidNk2l3e5CyLJnGz7/xS5DvREwIvsCI5hhKxwNJY+AEAAAB9lCP/GDRR+aTcuxfQYNpd3uQsiyZxs++FFB8W26PoAYEXWIH6Yvyk/N6dBsDSWPgBAAAAfZSMBWsko4xoOu0uJ0m7zrJomhzxWTCX6rH7OHpA4AVWwMUYWIVJpM8DAACAVnFYDxdWBk1jlBGNp93lJFm7C42zEZuPqxXzfjCz6nx61IeWF4EXWIHpxRhgua7ElUcWfgAAAECfDGNgL6RZymo//EFAg2l3OUnad5ZFE43Lcl8Ya36TSHei4wReYOnS59OLMcBy1deaFFnlJAAAANAbz2NiL6RZ7tsPp+mqw9FRaHd5RbWv/Nhrl6aaBind7DuffGtUFFvRYZcCWLIsEcuZ6jeag3heRBxeO/6l4rV/pKzvVMkx2b8Um7sWnZylHmtUfTgZBQAAAEAPbMbm/kE8DZogPX5S/vAooPk+Dl6RIj4LaKj6XOy3xXZ19nE0iowZVeuku9WXe9FRAi+wZBvVdTjgJfW8vEnE76slZB1wGVVvNG9NVh7G5Ohr/eH9RnH1qMUjR/xlUD2/viz3xgHHcuTH1aLvkwAAAADogfoQ7EaxHazfRuQ/BTRcdb3YCe0uryudM9B0w4hHE4GXOaU7o6J40NUb6gVeYLnKcblXBr1Xh1xypD/kiJ1J5OOAS4755K08rVysgzMfVwv0MlWf7esEtkUp31TXnPo5ET60AQAAAP1Rhr2Qtar2Jh/ZC6cltLu8IX0e0HD1+dcHxfb4+HyMmeStZ3Ewqn7SyakkAi+wVOmvQW9NRxU9vVM9D+5OQy7zBlzeqqiDNPWP46DD/bpZyAfMPku71fOtCAAAAIAeSJH28/L23jiHy9WeZEDDaXc52UbkBwEtMIn0eYo8CmY2iEl1XtnNwMsggCXKu0Hv1EGXauH88UE8+1sczcTLbx1ZtEBF9ePTg4gv6t/DqNgugh7KwnYAAAAtkauD+gAuKHsdrdd9N9/RBsk4lBOkXa9f2uJKXHkU1s5zqZtx6mkU0UECL7BEOQYCLz3z2+LqnTUFXV5X1L+H4+DLTtA3ZQAAANAKOfKPAVzIJOK7YF3KjYhHAQ13o3j3mlEob6oek88CWmJclnXYxXN2TpNIt6KDBF5giYYxkTLsievFdvFBsf1FOqr+W2vQ5XVF9ePT+vem7aVPhsJ2AAAAQG8kd3uv02faIWiHwzvBG1IMxgEtMojcybE8K3K7nlIRHSPwAkt0SctCL9StLoNI3zY5HV7/3g6q32P1e70bdN4kDm3yAAAAAD1ipNGaaHehFa5PbwbdCV5XPim/d/MkrfJluTc21mheeetZHIyiYwReYKk2XXA77oPi6icNbHU5Rd6qfq+f1L/noNM2XXsAAABaQzMFLEQZrIN2F1ph2NExHheXPg9opfwwmMsgJp1ruxJ4gSU6niVHB9WVX/WYoBy5dY0p9e/5g+Lqt12sLWPKtQcAAKBNNFMAraTdhdao9sSNMzqB0TC01cT7z9zqiRBdOx8UeAGYUV1/eBBPGz3C6G2qBf61+nsYTascAQAAAKC1Bhpe1kG7C61wo9jeqb4UwWvS/nQ0DLTPN9X7T4oYB3OpzgdbdzP/WQReAGZQh12qC+cX0Y0FcnFQfS9CLwAAAEAT/eSAEhpLuwttUR2K3w5O8peAFsuewxeQOtV6JfACS2RkTLfUf57DSH+Obm22FM+r78lzFQAAANamDOBCfvI6WqkU8Ui7C21Q38Da5qb25TLOiHbbiM0HwZzy1ofF9ig6QuAFluqpEEGHHMSzT+tRQNEx9ff0PJ5+EnTGda09AAAAACzJ5Yj7AS1QHYJ+HJxowzgYWm5clvvGGs1vEulWdITACyzRQQwFXjriRrFdLYxzZy7+r8sRO9PvkS64pPIZAAAA6JFvtI2sjHYXWmYUnCDteh3TBcYaXcjtrkx/EHiBpTrsXBtIHx3Xet2L7rvXpQqzPksxELYDAAAAYOFSxGcBLfC74pf1DaxF8IYUeTegAyYRj4I55a1ncTCKDhB4geUqglar043VG+an0RP199qVRGefHcZE2A4AAKAlqg3aMoBFKINlK78s98YBLVDtkf4hONEkBp8HdMBxw1sZzGUQkzvRAQIvsEQp4r2g1Z7Hs3rMTxH9URx/z7Ra+k0AAAAAwGLdD2iB68V2UX3ZCU50JSYaXuiQJMA1pxzpWhdughd4gSXK5kO2Wr0ozpHvRs/U37PRRm2XNbwAAAAAvZIi7QdLlPY3YvNxQAsMnM2cIe2Op60Y0AmDyN6b5pa3DuLprWg5gRdYrmI0TRLTQsMejTJ6XY7Q8tJSx3cvFAEAAEArTGLokB4WInstLVGqDhTHZekxphVSxO3gRNVrWbsLnTIdtSf0Oq8uXC8FXmDJDiSJW6luOOlzQ0/9vWt5aSd3LwAAALTLJA5t0MMCZIddS1UdiH0W0ALT5nZ7pKepHpu/BHTPOJhLF8YaCbzAkkkSt5OGE49Be6U/BAAAAEDP5Mg/BstSTu+gh+ZzQ+DbDDW80DmCXBfR/rFGAi+wZF1IxvWNBPiUlpf2mV5rcuvnLQIAAADQJOnzgJZIke4Ep0j7T8rvBV7onBz5cTC3FPH7aDGBF1i6vPUsnu0ErTHQbPKzSSThiRZpewoXAAAAYF7JSKMlGjwKaIHpzaz5WnCiFFnYhU76ptwrqy9lMJfc8rNAgRdYgUFkI0baZRS8YCRXixihBgAA0D7HG/TAhWWBl+UoNULQFskNnGcy9oVu00Y2v7zV5okPAi+wAkbDtMfxn1MRHGv3m1yfGMUFAAAAwKKliHFAS7j5+Gw5BsJrdJgGo4to88QHgRdYkWxMTitMNGS8wVijdjCKCwAAAOizbKTRUqSIzwJawA2Bb3clJgIBdNZGbD4OLqC9gUGBF1iReqE1qhZcQdONgtdIxTfd9em1ZScAAABoKQf1cFHJSKMlSPtflnvjgBYY2Nt/i7Q/NkaRDhuXZb0OKIN5FW09xxZ4gRV6roGh0Y5DA0Xwuta+yfWFdhcAAIC2c1APNNJfAloiaW8/UzLuhR7I3rcu5FlLJz4IvMAKVRfanVFRbAWNdDkG14ITPfPYNJZ2FwAAAICIYQwExxYuGw9BK9TnLsYZnS1H+mtAx6WIcTC31NLrqMALrNhBPL0bNNJhTIQ6TpE8No2l3QUAAACgPsydCLws2IaDQ1riMA5GwZlypHFAx028b13U76OFBF5g5dIdLS9NlX4TnChFvBc0jnYXAACAbkiRHNQDTVOOy70yoAUOY/KH4ExDoUB64Juj9y3r6vnlrQ+L7VG0jMALrFze0vLSTKn6swlOlCNpeGkg7S4AAABdkW3MwwVNYuh1tEDGQtAyo+BMl2JzN6AHqrM+z/ULOGzheaDAC6yFlpcmyhFFcAphoKY5bncZBQBAQ+VI1pAAwMpM4lDgZYGqvdK/BLTAjeLd+nC2CM6Qdsdl6RpJL1R7EX8N5jaI3LrGLIEXWAstL81kQ/50Hpumqd7Ab4cPcgBAg2lQBABorw0NL7REjskoOFPSJEePDCONg7m1ceKDwAusjZaX5rEhfzqPTQPtBAAAAJ0wifguAJqjHJd7ZUALtLGNYNU0XtAnz2NipNGF5K3j5qzWEHiBtdHyAsznRrG9E9pdAAAAAH62GZsaDBbG4TjtkY19f6vqMSoDeuKbo8Bmsia4gLY1Zwm8wFppeQHm8nEAAAAA8LNxWTrcWpBsnBEt8WGxPQreahhZ4wV9Mw7mNoj8m2gRgRdYq7z1LJ7tBA0h8Xk6j01TaHcBAAAAYJkcjtMWk0i3greaxND+Pn1jXOgFtK05S+AF1ixFvhM0RLboO5XHpkG0uwAAAACwNJdiU+CFVkgtayFYlyfl917T9Izg5gUVbZpQIvAC61ccNzawZkmLyamSGZ+NoN0FAAAAgOVKu8ZD0RZtayFYj+Tgnx4aet5f0LM4GEVLCLxAIyQtLw0wifzX4EQ50o9BE2h3AQAAADhdGVyUMRC0wofF9ih4q6S9nR7aiMtlcCHVtWMULSHwAo2Qr1mcrZ8Wk7Oof1s37S4AAAAALFuOGAe0wES7y3mVAT1z3FRWBhdRREsIvEBDZM0NazeMgVDHKbLHpglcIwAAAABYqqEb32iJFPH74K2y1iZ6yzivC2rNNVbgBRqinjWp5WW9nsfEm98prnhs1ur42lAEAAAAACzRpdi0D0gr5EjXgvMoA/pJ2OtC8tao2C6iBQReoEG0vKzXN+VeGRZ/JynH08eGNXFtAAAAAGD50v7xGAhotBvFu9fqw9jgrQbOPOgtjWUX9SwGrQgWCrxAg2h5aYL0efCKZG7vWtXXhGweLQAAAMBbJQe7F5IcDtISw8hFcC6TGAqx0VND72kX1o5rrcALNIwmh/UaRH4cvKLaKPgsWBvXBAAAAABWIUf6a0ALHEYeBeeyEZfLgB6axKGw1wVVZ6a/iRYQeIGG0fKyXl+We+O6ujN4oZw+JqzD9WK70O4CAAAAwCpkDTm0RGrJIez6GVNGf31T7pXO+y4mRzLSCJiPRoe102hyzDij9Rq4FgAAAACwIkMjjWiJthzCrl922E/PeQ1cUBEtIPACDaTlZb2MNfqnyxH3g7Wo212qLzsBAAAAACtwScMLLXCjePdadYqyFbxV8pqm95Ig54XkrdH0rKrRBF6goXLE7WAt6hE+mk2m7S7jo8o31kG7CwAAAMBsJhHfBXOqR5/YC6T5hpGL4FxypB8D+s264IKexaDxjVoCL9BQOWKnDam5rkqaTTwGa6TdBQAAAIAVKwNa4DAmxhmdXxnQY9lrYAGaHzIUeIEGO4h0N1iLvre81N97/RgEa6HdBQDohqRmfAGyxxEAWA13wdMS6TfBOeX9gB5LXgMXVp0XFtFwAi/QbLdHRWFzc0363HByOeKjYC20uwAAXZEj+yyzEB5HAGAlyoAWaMPha1PkSA776bnhbnBRRTScwAs0Wt46iKdaXtZk2nCSHkbvpIfm9a6PdhcAAAAAVs3YB9oiRzbS6NxSGdBjkzgU+rqw3PhWLYEXaLx0R8vL+mzElXvRrw975fH3zBpodwEAAABgHYaR3QVP490o3hV2mcEwJg776bVv3Ny9AM0fsyzwAo2n5WWdxmW5P+jReJ/6e62/52Atqsf/dgAAAADAik1iaE+QxhtGLgJgNmVwAXmr6cUMAi/QClpe1mk62ijuR/fdP/5eWQPtLgAAAAAXkxxqze1J+b2GFxrvMCYaXmZwyTURqrVBEui8sKcCL8BFaXlZtyfl3r0c8Vl0Vnpcf4/B2lRvyKPqSxEAAAAAsFIOA2mHbP90Rpte2/ReFvy6sGcxaHTYUOAFWkPLy7pdic27KVLn7nSov6eNuNKbsU0N9nEAAAAAwIqlyNpdaIXqUPO94NzGZSnwQu/lyD8GF5JiouEFWAQtL+tWLw4PI/8xupUGLS9X35OF73rdKLZ3wt0JAAAAAKxBjuQwkFbQ8DILzU1QM9JoIYpoMIEXaJV0J1irb8q9chJxM7oReik3qu9lXH1PwbppdwEAAABgXcqAdiiCc8oO+eGI18LFJQ0vwKLkreMmCNaoDr1sxOb7bR5vlCLG9fcg7LJ+2l0AAACo9hjeCYC1cRhI810vtosAmF0ZXEiK3OjPKgIv0D6aIBqgHgH0VfnD+9Vl/mG0Tnr4Vbl30xijxvCaBgAA6LlqE7nRd00CnVcGNNwlNw3OJHldA4tTRIMJvED7FFpemuNJ+cPdFOlP7ZiHmfZz9Xutf89BI2h3AQAAAGDdBg7GaYEUA+FQYGbe4y4uG2kELFqKuB00xlflDw8mkd+PZr9pltUl/+bX1e81aBLtLgBAZxnPAQDQDpMYaoKm8X6KXATAjLzHLUKz2ygFXqCFcsTow2J7FDTGN+VeOYm4WW3q70bD1L+njer39qT8vnG/tz7T7gIAdJ3xHACzaPZdk9AiZTCzjbhcBjRcspc6qzKAmMShwMuFaXgBliBrhmicOvRyOa7crP5sPouGqH8v9e9pXP3egkZJke4EAAAARP35XUgQWJ9xWToMpPG8VwLz2IxN73EXpuEFWAItL81Ufzj8utzbaULopf491L8XH1ibp37tVh/QrgUAAAAArFcZ0ALVgeZ7ATAjZ2SLMSqKxoZeBF6gxbS8NNe6Qy8vwi5BI3ntAgAAANAESeCF1jD+bxbVHvR3AbAwTwVegMXT8tJsV2Lzboq0GytW/zfr/3bQSNN2lxgFAAAA/MwhHgCcxUgj4ALKoLMEXqDlNEU0V12Tdhj5j7HaN9LycvXfVNHWXJOI2wEAAACvcIgHrE0Z0A5FALAWBzHU8AIsh5aXZvum3CurC+1HsTLDP46r/2bQSNeL7aL6shMAAAAA0AA50o8BAHCGQRwKvADLo+Wl2b4s98YR6WEs3/0n5fcrH6HE+Q28VgEAAABolKwpmsYbFYUmNGBuSZtZpwm8QAfULS+jaXMEDbURV+7Fct9Qyyfl3r2gsbS7AAAwn2RzHwBYpjKg4Z7GU2viGeVIwmxALwi8QEc81xzRaOOy3F/yaKP7QaNpdwEAYD7Z5j4AsDQ5Bg7FabxBDK2JZ5S0NwE9IfACHZEjdtT6NVs92ihFjGPx6naXR0FjaXcBAAAAoImGMXEoTuMN4tDZBwAnEniBDjmIp3eDRptE+jwWT7tLw2l3AQD6KEcUAQAAALBGk4jvgs4SeIFOSXe0vDTblbjyKBY8O3MjNh8HjaXdBQAAAICmuhRRBgBASwm8QKfkLS0vzTYuy/0UeTcWJn1e/zuDxtLuAgAAAEBzbdpbpPFSDNzoC8CJBF6gc7S8NN0ixxrliHHQWMftLqMAAAAAYOmGMRDemJGb6WiDw5g48wDgRAIv0DlaXpouxWAcCzJcaFsMi1a9yd6uvhQBAAAAwNLlmAhvzCR5vACAVhN4gU7S8tJkkzhc2AdJM3YbbycAAAAAoJGywAsA0GoCL9BJWl6a7Jtyr4wFGS/w38Vi3Si2d0K7CwAAAACNpeEFAGg3gRfoLC0vsGYfBwAAAAA0VNLwAgC0nMALdFbeehbPdgJYOe0uAAC1JIAPAAAAwNIIvECHpch3AlgH7S4AAJEFXgDO4XqxXQQnmriZBJYqR/oxAABaTOAFuq04bpoAVkS7CwAAAABtkCL/VwCdlDVuAj0h8ALdp2kCVstrDgAAAACAtUkaN4GeEHiB7is+LLZHASyddhcAAJZhVBQ2q6HDBjH0GgfWIkd8F0AnpYj3AqAHBF6gB7LGCVgVrzUAAJbgqcNw6LBBHHqNAwALlSP9IgB6QOAFeiBHjLS8wHL9rvjlrdDuAgAAAADAmqXI7wRADwi8QE9oeYHlmsTkTgAAAABAe5QBANBiAi/QE1peYHnq11b9GgsAAI6MisJ4DgAAAACWSuAFekTLCyyH1xYAwKuexlOBF4BzmhiPCwAAMBeBF+gRLS+weNeL7UK7CwAAAABtk2OwHwAALSbwAj2jiQIWa+A1BQAAAEALDWMi8AIAtJrAC/SMlhdYnLrdpfqyEwAAAAAAAMBKCbxAD+WI2wFcmHYXAAAAAACapjoHKgKgBwReoIeqhc7OaNpMAcxJuwsAAAAAAACsj8AL9NRBpLsBzE27CwDA6S65mxAAoPGqNVsZAAAtJvAC/XV7VBRbAcxMuwsAAAAAAACsl8AL9FbeOoinWl5gDtpdAABYpZ805gAAAAC8QeAFei3d0fICs9HuAgAAAABAsyVnP8DCTGK4Hw0l8AK9puUFZlW9cd4OAAAAAABorCzwAizMRhwKvABNpeUFzku7CwAAAADdsdnYwysAgPMQeIHe0/IC51W9aY6qL0UAAHCmFAOhegCAhhuXpcALrTCMgefqHNzsDCzKuNwro6EEXoDQ8gLn9nEAAPBWhzHx+QIAAFiIHBOBl7k89bkM6DyBFyC0vMDb3Si2d0K7CwAAAAAAAP1RRoMJvADH0p0AzqLdBQAAAACAVjiIoYYXYAFSo1u2BF6AY3nruMECeI12FwAAAACA9fip4e0CTTWIQ4EX4MJSZIEXoDU0WMDJvDYAAFibwxjYqAYAAGbicwSwCDnSj9FgAi/Ay4rfFr+8FcDPtLsAAMylCBYmxcRGNQCcQ3K4C520GZuNbhdoKp8jgEVIkf8rGkzgBXjFICZ3AniZdhcAAABYgxzJQR0zOXS4C500LkuBlzl4HwUWIUd8Fw0m8AK8orpojT4stkcBaHcBAACANUqRHdQBcCwJvczI+yhMDSLeCy6ijAYTeAHekDVawJEUSeMRAAAAAMDaZYGXmWl4AS5uIPACtI2WF4ioXwM58rUAAAAAAGCtkoaXmaXI7wTABU1i2Ojrr8ALcCItL/Sd1wAAwEW4kxAAAFic3PCGgSbKkX4RABe0EZfLaDCBF+BEWl7os2m7S4wCAIC5ZLPiAWZRBABwpuozxo/BrN4LINyUcxFpf1yWGl6AdtJwQV9NIm4HAAAAAACNkDS8zMGNCFBzU86FlNFwdeClDIATaHmhj64X20X1ZScATmReNABrUQQAAPRbGcxIqwVwYd9Fw2l4Ac6k5YW+GXjOA2fKAi8AAAAAKzaMgT2ZmeWtUVEIvYDw10WU0XACL8CZ6paX0bTxAjpPuwsAwGIMzIoHAAAW6DBSGczhqYN+MNJoblngBeiC5xov6AntLgAAAAAAzbMRl8tgZgcxdNAPzG0YeTcaTuAFeKscsaP2jq7T7gIAAAAA0EzjstyPSMYazezwWkCPXTfF4kIuxabAC9ANB/H0bkCHaXcBAAAAAGiyLPAyoxzJzcz02kDL0QWk/WnYsNkEXoBzSne0vNBV2l0AABbNpioAsBZFAB2WGt800DTJdZGeG8Sh/Yk5pRaMM6oJvADnlLe0vNBV2l0AABYrV58fggUSIAIAgMp3wUyqA+t3AmAOOdJfowUEXoAZaHmhe47bXUYBAAANZZMa6KsU8V4AwLEcUQazKgJ6bOI1MLe2XHMFXoAZaHmhe6o3wtthwQMAAAAA0GiXIpXBTLK9byiCuQyNNAK6ScsLnbMTAAAsmBE8AADAYj2PSSsOXxumCIA5XIpNgRegi7S80B03iu2dsOAHAFiCLPACAAAs1DflXhmR9oOZjIrtIqCntBzNK+2Oy7IV11uBF2AOWl7ojI8DAAAA1korFgCcV4oog5n85MCfHhtEvBfM47toCYEXYA5561k82wloMe0uAAAANEHWigUA5zaJ/NdgJhP74PSacPk8csQ4WkLgBZhLinwnoN20uwAALMF1ddkLlyP9IgAAgKjHbASzKgJ6ykij+Qwjt+ZaK/ACzKs4bsiA1tHuAgBAm6TI7wQA8FYOtWYzElSmhS5FKoOZJCNd6DVtivO4FJsCL0AvaMigrTx3gTml/QAAAABgLYaxMQ5mkiNdC+ghDbTzSrvjsmzNPvggRZQBMJ/iw2J7FNAi2l2Ai0iRBV4A3mIQQ3dPAQAASzE9hHVD0oyKgB665Lk/r79Ei2h4AS4ka8qgfTxnAQCWaBCHAi8AAMAyjYMZ5C0jzOijFAP7E3PIkcbRIgIvwIXkiJGWF9rid8Uvb4VELwAAALRCtdn+iwCAN30XzORZDIw1oncOY+J5P4crMdmNFhF4AS5MywttMYnJnQAAgJbJQttAT6XI7wQAvGbYsvaBZshFQO8kDS8zS7vjcq+MFhF4AS5MywttUD9H6+dqAACwVBPhDICZpEhCHbAg1YHHewF03vOWtQ80wSDybwJ6Jnnez6x6zFp3fRV4ARZCywtN5zkKAABAE1Wbyu48BdbiJ0FlWuqbo/aBtB+cW45ktAs9pOFlVpMYfB4tI/ACLISWF5rserFdaHcBAAAAAOiMcTCLIqBncmRBrxldaWGDlsALsDAaNGiqgecmAMAqFQEAALBE1XnEX4IZ5K1RsV0E9MSN4l1hl5ml3fFRg1a7CLwAC6PlhSa6Pl3E7wQAALSWGmYAAHjZMHLrWgjW7VkMBADojUEc+hw9u1YGCQeTiO8CYEFyxO2ABtHuAixSjvRjAMDKZRt1AMDCHcbAGoPWuhSbuxFpP5hBLgJ64jCSgNeMBpEfRwtpeAEWKkfsqMWjKbS7AIuWIv9XAHCmbKQRAAuSNVwxI+uQ2aSYeI3RWuOy3E9aXmaSIkYBPZGsCWb2Zbk3jhYSeAEW7iDS3YAG0O4CAAAAbabhCoDT5Uh/DWaQfxPQE8nzfSYpYhwtJfACLMPtUVHYkGCttLsAAKxHivROAHBuGikAYD5tHb+xRoWzG/oiG2k0k+ozyWfRUgIvwBLkrYN4quWFtdLuAgCwHsnd+EthdCwAsGjGhtF2l2LTSKMZPYuDUUDH3SjevaYpcDYbGl4AXpfuSAqzLtpdAAAAAPpIgGMWgsq03bgs99s8hmMdqtf9KKDjBnHo/W0maXdc7pXRUgIvwJJoeWF9qje32wEAwJo4aAIA1kWAA/omR/prcG4p8m8COm4SMQpm8ZdosUGKKANgKbS8sHraXYBlyhHfBQBnyg6aAABaQlCZ9htEfhycW450LaDzkmDXTAaPosU0vABLpOWF1RtGulV9KQIAAABawYEzsB4p8jsBLXcpNnerZ/N+cE5560bxrtALnZacEc2ifFJ+vxstJvACLJmWF1YrR74TAACsUxEs3E8eV+gwzVhnKALOyR4k9NO4LPdT5FYf1q5ajskooKPq9UB1TiTUdU6puoxGywm8AEum5YXVuVFs74TNMAAAAIDeeRpPBV6gpyaRPg/ObRDZuBc666d4KuwygxTxWbScwAuwAknjBqvycQAAsDburAYAaJUioANSDMbBueVItwI6alJtTQTnVX5Z7o2j5QbZXDtg6eqZkEfNG7A02l2AVbB2BjibO6uX5zAGHlsAADjBk/L73bBnM4O8NSq2i4AOShG/D86lC+OMaoMU2RsAsAqaN1g2zzFg6aydAc42iKFQxpKkmHhsoYM0Y8HiXHIj1Myyx4xuaf1YjlV6puWFjsqRjDQ6pxzDh9EBRhoBq1JoeWFZtLsAADTDIA4d3ALMQDMWACzGIPLj4NySsS900I3i3Wt1g1FwHuW0Hav9BF6AlakWULcDlkO7CwAAAHSQFhwAzuNSbBprNBtjX+igQ+0u55QjdaLdpSbwAqxMrvYoPiy2RwELpN0FAKA5JtZlS1NtRjnwBXpKCw7nk2LguTK7IqAjxmW5nyJ3oq1gNfKW8xo6SJDrnK50qBVrMIyBtCOwMlkTBwuWIt0JgBUZRJQBwKmEMpYnqWUGgDMdxsR7JfTcJNLnwblNjDWie0bBW6WI8bjcK6MjBjkmAi/Aymh5YZHq51KOrKIOAKAhhDIAZnNJuwKwZqNiuwjoiCtx5VFwbkkbBh1yffp+VgRvVZ3VfhYdYqQRsHJaXlgUzyUAgKbR8LI8HlsAOIumOWA61ijGwbnUNyiPisK1k04YaHc5p7S/EZudGWdUE3gBVk7LC4swbXexgAEAaJKs4WVpUuR3AgA4laa5+fzkbng6ptoz/ktwbs/i2U5AJ6Q/BG9VrZce1+HA6JBBtZgpA2DFNHNwUZOI2wGwYpMYGgcKcIZBxHsBAAvkMB6W6zAGgkJ0SrVv/Cg4t0FkIQG6YhS8VerYOKOahhdgLbS8cBHHsxh3AmDFNuJQ4AUAgIWZCHPAwmSvp7mkmAi80CnflHulsUbnlyNdM9aItpueN2p6O4fyy3JvHB0j8AKsjZYX5jXw3AEAaKhkg2l5igAAWLBs/UYHGWs0i7x1EE9vBbTYRLvLed2PDhpsxqa7VIG1qFteRtOmDjg37S7Aelk7A5zFndUAwLqkSO8EM0vuiKeDjDWaTYr4fUCLeQ6fz0ZH268G47K0aQ+szXNNHcxIuwuwTtbOAG/jwGRZ3H0N3eS1/XaHMfAYcS6CG/OpDgnfC+gYY41mU61HbhlrRFvVN0lnDS9vVV0TH42ra2N0kJFGwFpVb0I7FlKcl3YXAIDmsq5fNod40EUO6N8uxcRjBMDMjDWaRd56FgejgBYaCLucS4r4LDpK4AVYu4N4ejfgHLS7AAA010E8LwIAYE2MVpxbEdBBG7H5IDi3QUzuBLRQirgdvE35Zbk3jo56EXgpA2Bt0h13g/I22l2ABigDgFMN4tCafqmMPQEAFk9QiK6qx1Iba3R+OdI15zS0Tf2cNc7oXO5Hh2l4ARogb2l54W20uwAANFuKgc3RpTL2BLrIQTMsVBHMQaiW7ppE+jw4p3qs0bOdgBapzhZvBW9TPin3HkWHCbwADaHlhdMdt7uMAmCt0n4AcKqfIhcBAItXBLBEQrV015W48sh+zvkNIv8hoFWS5+xb9KHp6ijwktSzA2un5YXTDaYzGIsAWKMU2QYJwBmSw5KlG02D4ECHpEjvBHBhbqS7GGsMuqoea1R9+Sw4l3o0zI3i3WsBLTC9UTpreHmLyx0fZ1TT8AI0iJYX3nT8nNgJAAAazVgOgNkJC8JiPI2nXksXcBBDjx+dNYj8OJjBoQABrTAwFeCtUsSjcblXRscdBV4mEd8FwNppeeFNxzMYiwBYsxzpxwDgVNUGw3vBUjmMAoCTXbJ3dCHZaEo67Mtyb5wi7Qbn5MZk2iFNJwNwhj60u9Q0vAANYzHFGz4OgAZIkf8rADhDso5fskEceoyhc1w73yYJVMIKCLzQbTny58E55a1ncTAKaLB6nFHW8PIW6fM+tLvUBF6AhqkXU892Aio3iu2dcIcOAEArGGm0fBOPMXRONtIIFiLFwGvpApI1Bh23EZsPqmf6fnAug5jcCWiwFMnorbcYRH4QPXEUeKkWM2UANESKbDHFC9pdgMbIxoACnGra0ujQFgBYj580lFxItR/7TkCHjcuyDrt8FpxL3ZzxYbE9Cmgo54hnS9Vlrx7nFj2h4QVoouK42YMe0+4CANAeP8XTa8HSZaNPoIuKAC4sCd5eSLXGsJaj8waRHwfnNtGgQUMdh7GK4FSTGDyMHnkReCkDoFk0e+A5ADRNGQCcyBiB1XCYB/RUEfBWQqEXY41B99VtB3XrQXBet6dNntAsk+q5GZyl/Lr8z14F/DS8AE1VqMzrL+0uAADtchgTdwWvQLVB/14AneEQCRYnC2xcVOGaRB8MetZ6cDF56yCe3g1okOvFdlF92QnOcj965ijwMozBfgA0TNbw0Wf+7IHGGWh4AThD+k0AMJOn8dThMizIQCh0AVyT6L5/O2o9SM5Ezy3dEYajSar3+1FwlvJJufcoeuYo8JJj4uIONE6u3ri0vPTP74pf1rNBiwAAoDWM2lmZIoDOGMTQtfMcsmsf52Kk0UU9i4HGPnoia3k5Ny0vNI6bpc8wjMGfooeOAi8/uVsVaCgtL/0zicmdAGigSQyFxAFOkSM5IFkBh77QLYM4dEAPC+I9chFyEdADG7H5QMvLTG4HNMCNYnsnvN+fKkWMpy1W/TMIgAbT8tIv9Z91VkkHNNRGHNoMATjBjeLda6HhBQBYK2uRixpENqKSXhiX5b6Wl5kUx0EDWKskfHWm6vG5Hz11FHjZjE2b90BjaXnpD3/WQJONy70yAHjD0N3Aq1QE0BkTr+nzKgLOcL3YLoIL09hHn0xbXpiBfXvWys3SZ0sRj74s98bRU0eBl2maEaCZtLz0Q705YcECANA+h5FHwcqMHOpBZ1SHyxopYAEuCUUtShHQE/W5aLUX/VlwXlpeWKuJdpczXe5xu0vt5ZFGZQA0lOaP7hv4MwaarQwATpQifh+szEEMHZBDRyQjWM5tVBQeK06VYuD5sRB5S7CWPqnOHO4Fs/jY+zHrcNzkthOcqG536Xsz+SAAWkDLS7dZsADNlzQiApyg3vDMkdXfr1A2Qgo6RMPL+T31WHGqn7w3LsyzGFjX0RvfVAfEWl5mUhzE07sBK+Zm6TOVfW93qf0ceEnuWgUaLqss6ywLFqDpUmSBF4ATHMbBKFgxh3rQIe8FcGHakhYnGVVJz2h5mVW6o+WFVXKz9Ft91vd2l9rPgZfsrlWg4arF545aze6xYAHaoFor/xgAvOEwJn8IVipFFAF0gkP68zPOjbOl3wSLUgT0iJaXWeUtLS+skpulz1Q+KffuBS8HXrJNfKDxDiJZTHWMBQvQBtVhxH8FACcZBStVvSc51IPOMNLovAZx6LHiVMJjC/X7gJ7R8jKruuXFjcksn5ul36r3o4xeMNIIaJvbKvO6w4IFaItq8+O7AOAVHxbbo3AX8MrlSNcC6ITskP7cDmPgseJU3hsXKW85yKZvtLzMKm89j/g0YMncLH26FPHoSbn3KDhipBHQMirzusSCBWgLa2WAN00i3QrWwEEUdEgRnEuKicALJ5reGCc8tkjPrPHooWnLi72f86oer9HxDRCwFG6WPttl7S6veKnhJbuQAy1RV+ZpeWk7CxagTayVAU6S/xCsxYFRUtB69jVmk41/4hQ/xVPtLgs2MD6RHqpbXqp3m4fBuU0iPrWeYVmGWoTOcn98dM3ihcFLPykDoBW0vHRB9b5zOwBawloZ4FXGGa2b0Q3QdgfxvAjOLWnw4BTJuKuFyxpe6KmN2Hyg5WUmhXMaluFGsb2T3eRxmvJJuXcveMXPgZefbOIDraLlpc20uwBtM4mhDQ+Al0yEl9ft9wG02iAO7WnMRMMLJzuMiRDowuUto0roo3FZ7mt5mVV9TmPcKgv3cXCiQcRHwRsGAdBKWl7abDi9U6QIgJbYiMtlAHBEeLkJ8jU3AEC7TXwmnkmK/E7AiZLxO0sw0fJCTx03J5TBOeWt50bPsEC/La7eCevkE6WIR1+We+PgDT8HXr4x6wloHS0vbZUj3wmAFpne5QNAbaBauBEO4qmDKGi3Iji3HOkXASfKGl6WQ5sfvaVBYTb16JnfFlfdnMyF1TfXpMieSycrL0fcD070esNLGQCtoeWljer5i2FjD2iXMgB4mXrhBkjGGkGrZZ+LZ6LhhZMct84VwRIYa0R/1Q0K1Vp7HJxb9Xh9bLQRFzWY7jUUwUnuj5WXnOqVwEuK5M5VoGWSppD2cUACtEoSeAH4mfByc2SjBqDVqk3Z94JzExDiJJdjoN1libI9PHrs8KjlxZnp+RltxMUchyx3gjfUo4yelHuPglO9EnjJNvOB1slbx5vutIADEqCNqgPFHwOAFxx8NIY7r6HdkhHNcEGHkUfB0tRjSm4U7woV0UvfHDUp5IfBudXXjA+Kq58EzGEiMHUao4zO4fWRRt8FQPvYdG8Pf1ZAG5UBgPByA020vEBr5cgOkWdTBLzGeL/lS3Ho8Jre2ojNB2FPaCbV+uauUD6zqvYajDI6xSDiI6OM3k7DC9AFhZaX5nNAArRXVmELMCW83Dy3A2gdjQnzGRXbRcCx69XzQXBs+erGBofX9NW4LPcHR6ONmEXd1DEqCk12nMv16fruXnCS+1+We+PgrV4JvCSb+UBLJRu9beCABGilHIPdAOi53xZX74TwcgMZawRtNIxcBDM7iKHDM36WtJytTI6k5YXemh42J6ONZlM8j6d/DjiHQcQXwUnKJ+XeveBcXhtpNLSZD7SSuw2aTbsL0GbDmAiFA71W33GVIt8NGikLlkPrHMZEK8UcsqAQL6nWJneClaibdH5bXLUWpLc24sq9MCFjJvV5zfGYGjiVUUanSfsbETeDc3sl8DKJQ5v5QGvZ6G2uFMkmBNBal2xqAD03mK6zi6CR6s1kleHQNuk3wcxSTFzrOHJ801sRrEyq1oPGitFXRhvN7d7vil9q4+JExyM+7wVvqD7j3x+Xe2Vwbq8EXr7x4AEtpuWlmeo/EzOVgTbzAQPos+Omvp2g0Q7iqbuuoV1GwRySvQWOTIw2X4O89Tzi04CeMtpoPoeRPxWW43XXj54Th8ZenSg9/Lr84UEwk8EJv1YGQEtpeWkefyZAy5UB0FPTTShruXZId7S8QDtM72bNXq9zSJHfCXrveH2yE6xcfbPhB8XVTwJ6ymijeeStg4gvhF54mRbZU5XH1xlmdELgJe0GQEtpeWmWabuLO9eA9ko2MoAeswnVJvVGspYXaIMck1Ewl6zhhfh5fcKa5Mh37b3SV0Ybza14HunPAvrUbhTb9fv4TvCatL8RcbO+zgQzeyPwUi1YfgyAFtMo0hwqZoEOKAOgh2xCtZGWF2iDQeQ/BPMqgl7T7tIMk6ODa20N9NN0tFHcD2ZSnT1fex5PNUT13LTpMO4FJ8h/Gpd7ZTAXDS9A52h5aQabEEAXVO8p3wVAz9iEaistL9B09edkLagXkbccsvebdpemeDGiRNCWfnpS7t1LEeNgJtUaaMdYtP6anhcd/jk4yf3quvIomNsbgZcUWVUO0HpaXtbPJgTQBTkGwuBAr9iEajstL9BkA2GXCzvwGPbWcSB3J2iK4nk8E3qhtw6PRhsl56kzqseiHbeJ0jPDSPU+QxG8Jj2uQ3TBhZzQ8DK0qQ+0Xn3HlLt+1ke7C9AVKVIZAD1RH1hUmwRfhE2oFstbqsKh0RzwXFAyOrnHBHKbph5RchDPPg3ooW/KvXIQ+Y/BPO4JvfRL3exTv2cErys34spHwYW9EXjZiMtlAHTAcxtJa6PdBegKa2OgL+qwS32Xbgi7tF5dFW7EKzRPdbCzE66xF5YjXdMo0T/HB6NF0ED51gfFttALvfRluTeuvtwP5iH00hP1n3Pd7BO8rtyIuDkuS01RC/BG4OX4gS0DoOXqjV6bIKun3QXokNKHDqAv6rtz3XHVHZOIT30WgsZxqLMQeetZPNsJeuN4n+le0Fj1HqzQC301HUWSHgfzEHrpuN8WV++E9/BTDP84LvfKYCEGJ/9yMtYI6ISDeCo5umLaXYCuSELgQE/cODqgyLeCLimexzPrcmgI7S6LlSLfCXqhDrscj1uk4aahl6vfCtzSR8cjScpgHkIvHfVBsX27WrM9CE7y0ZPye1mMBTol8BLfBUAnpDs+aK2OdhegS3KkvwZAh9Xr5PpgIqzfOqmujf5d8UtBJmgGBzmLVRyHiOi4QaRPQlisNeq2wIN4+u1ouj8IvVG3A08ibobQy7yEXjrmRvHutWpfVdjlZPeflHuPgoU6MfCSXZSBzshbWl5WR7sL0CXWxECX1UHl5/HsC2OMuu0w8qcOnWC9jg9wimDRPnaDU7dNXzsa6FqoOIj4wvqDvvnmaDTJ8I/BvO59UFz9JGi9OuwSMfmiPpsLXnd/OgaNRTsx8DKMrEYH6BAtL6tw3O4yCoCOsCYGuurFeABhlz6obwCoD518HoJ1OP6cfC9YhsINTt312+JqPbbqXtBW1eszfauJib45HlHyUTCXuqHyRnH1zz67tJewy1nSQ2GX5Tkx8HIpNm3uAx2i5WUVqjeU2+GuNaBDrImBLqrnaA+qA4iwbuuT4nk8/XMAK1Uf1tThwmCZPp4erNAl9VolRTYGofWODjs/NaaEvjkeVXI/mFO+ZTRaOwm7nC5HfPak/MEZ5RKdGHip582FCnegU7S8LNPxY7sTAN1RHq+JATqhXq/VFdHVRssjG1D9U/25j6oDxE8DWJnn8cwoo5U4dCd4h9SHZdO1Ch1y70ax/TeH1/TJcYuD0Mv8jkajCbW2Rx1WrdZk39preFOKtPt1ubcTLNXg9L+V3NEKdIiWl2WqHtt6pnIRAB2RhL+BDqlHalQHr/UII+vhHqsOEHfq0FMAS1c3Grjmrkx1KPZMoK8DpodlE61I3WTEEb1Th17qVodgXkUdoPhtcdV6quHqMYTCqierwy6X48rNYOnOCLzEdwHQKVpelkg9KdAp1Qe1vwRAB9SbT/UIo+rg1d1xRH0Ar+kFlqu+7lZf7gUrlG8J9LVbHXbRQtd10xFH9TpE2wt9Ubc6CL1cTIr8iff45qpD3sYQnuxF2EWD+GqcEXjJGl6Ajslbz+LZTrBQx3dnFAHQITkG1sJAq31YbI+qjcFvp5tPDo/4p7rp5UZx1QgQWIL60N6m/3rUgb760CVonWkjkjvD+6Jeh0xHlWh7oR+EXi7u+D3eaLQGqT9L1p8pQ8j7RMIuq3dq4GUSMQ6Ajqk2nu4Ei2ZDCeic6oNJGQAtVG881XfAVZ/pv9DqwunyrYN4+q1NY1icfzZUsEb3hF7a48WaJRyW9VFR/fjUATZ9IfSyEEajNUQ9Mrn+LFl/pgzeIOyyHqcGXr4p98rqj8UfBtA1hUXR4mh3Abop7T8pv9fwArTK9A6r7Y8P4tnf6jvgAt6ucIc1LIaGika5Z/RB89WHZc/j2RfWLL1Xr0X+ZswRfSD0sghGo61bHfCuRyaHM6ETCbusz+Csv5mMNQK6yd0+i+OxBDrHGhhok5eDLnF0h7TxRcykCJvGcCEaKpqnDlHUY/1c15rpd8Uvb9WHZZroeGE65uioueFjIxfpMqGXxTAabfVetLJNA972HE5Sv7aFXdbnzMBLjvTXAOie4sNiexRciHYXoKuqDyh/CYAW+G1x9Y6gC4twvGn8N6NA4PzqhooPim0NFQ1Vhynqw7A6XBE0wovDssOY/Nm6hTcdPSfu1WMyHGLTZUIvC1OE4P5K1Gdp9bXZmvd09Wu6fm0Lu6zPmYGXYaRxAHRQ1kyyCB5DoJOqBfI4ABqs3nCqDgL+liI/cGDEgt2rn1sOmuBs/2yoiFHQZEUdrhDmWz+HZcygqH58aj1Cl9UH49WX+8GFvWh7+W1x1fvLgr0Iqk6qxzfc+HyW+8evadYonfU36ydztRD9rwDooOpA8+aX5d441qD6wJZjAZ6UeynWoN7cm96RA9A9G7H5C4l8oInqw6I6uO2AldVIu4PIf1rXZyZoonqv9Hk8+9ihfSuV1T7QR65pq3V8vlCP/doJmE+5Ue3hjsu9MqBjqjOCe+Gm0kUqqx/3qzOTR8GFHJ//1O/fRXCW+vl2L1i7tx6U1kna8IQGOqi6AI6/Kvduxhq0PfAyrW120AJ0Udp9Uv7wfgA0iMMi1qn6wPHocrWR56CJvqvHyCUj5FrPNW11ps066a7XDIuQIj24HFfuuzmFrhF6Wbz63Kd6r//Ie/3s3GQzk4+Eq5rjHIGXq3VF8p0A6KB1tby0OfBSL3qOa+wAOqfeAP+q3PsoABrCAStN4ZCYvrLx31n3NiI+c01bvON9o0/DTbQsXjmMwZ/+rfzPxwEdcjy+69NgoXx+Ob/rxXYxmAavdoK3SPvVyeLNJ+X3u0FjDN7+j2R/YEBnZenpmXnMgC6rrnF/CYAGqA+LPiiufpsiPxB2oQmq98idg4i/fVBsfzqqNkQDOm56Hd7+or7hQ9ilk+5V17Qvfltcveuathj1YdmL10wIu7AcRT1ifdoeBN0xbYkY1m3DZbAwL31++aJe1wVvqN+7q2vqp4PqcQphl/MoNyK/L+zSPG9tBjhOdf0tADpqHS0vbW148Z4AdN1GxK/d+QGsUz2+6Hk8+zhHvhvQYO6YpKs0uvRSWf14pPFlfhrpWIPq0DFues3SJcd770KDy1NWP+5vxObjvo9Hs96d3XRU1uYfjdZrpnMdlFYHs/XhZhEAHVS/UX1V7t2MFWpr4KVO+4akL9BdZXVd/XUArMmN4t1rEYd/Dp+/aRHBF7rCxj8117TZ1Iezw4hPvW5YkzJi+Ed32tMl0+tq+nOOfC1YkrSfIj+u3vM/W/WN0OtU31zzLJ7tDCL/wfv2zO5Xe8b3gsY6Z+Dlal2hfCcAOmrVLS9tDLxodwG6rt7c/qrc+ygA1mB6Z3Q9vgjaySExbSXowknqm6Oq58Rn7gI/nVYXmiJH+tPX5Q/W0XSKc9mVKVOkxzkGn3UxPFeHXH6Kp9eqNc3t6lp5y3v2rFK1Bsx/mo4do8nO2/CyU335NAA6atWHnG0MvGh3Abqu+nD7x6/L/3wcACtUb0AdxLNqnZVvBXSA4AttIejCOZXTCnvXtResXWioe9U+6f2ADqn24+9VXz4OVuUo/JIif97m5pfp+/TTW9X65fdCLhdidF6LnOug9PjF8V8B0GHVm9evV/Xm1bbAi3YXoA82YvMX7t4EVsmMdrpM8IWmqsfHpTj8RNCFWdXBl+rH/T6NP3idtQsNJ/RC59QB3cm0kKAIVuho7NHuJNLnw+prk9/76zP8wzionif59/VfGoe1COnhRly5Z5+4Pc59UPpBsf2FD4JAt6WHT8of7sYKtC3wot0F6Lp68/qrcu9mAKxIfeAaMfnC3VZ021EF9AOHTzRBfRjwPJ59XB0CrORzP51WVj/u963efnromv5s7UKTVZ/td6rP9p8FdIiwYTPUe4fV/+5OIr6rQzCXYnN3lYGIaTnF8yLi8FqK9Jt89Hw4CrcUwYKk/epxvW9MXvuc+6BUdRbQfWl/I678ehWLlDYFXrS7AH1g5jewSsIu9FBZfab4qM+tCKyXu6NZkjJ6Enz5oNi+XW1kPQpovDpsO7j5pPx+N6BjbhRXq32rfCdokLoJJso8HYFYfc0/xvSzT1n/3UkMqzOnwzfOmw5iuDWMXBzGZKvak9xKL+0NpEjvvLRXUEyDLWnL/sFyVY/77uXIf9RQ2k7nPig9/mD4RQB0W71RcS+WrE2BF+0uQD8M37chBqyCsAt9Vm0iPrgcV+6rhmaVPiiufqLVhSUro8PBF2EXWqjciM33rTfoomqvfqdaVX/i8yQs0uqmP7AcMx2U3iiu/peLKNBtq2l5aUvgRbsL0BNldT39dQAsmSpqOFIdQsVNd86xbPU1dxjxqRHtrE56vBH5T126vrkJlraqQ7ZflT/8KaCDfK6EhdFE2hGD2f7xMPsQ6Li8dRBPJTmPVW8StwOg46YzeAGWz6YkHCkOIn37u+KXtwKW5MVBkLALq5VvHUT87Uax/XF0QP06Oh4FBq1TN3vVga2ADvqm3Htx49b9AOaUHtZtYMIu3TBT4GUQ+XEAdF66MyqK3rdZ1RsbYZQR0ANJqBtYgWn1tLALTOWtw5j8uR6TEbBg7nqmAe59UFz9djTdV2mt4TTsUgS0VI7oRPgMTvOk3LtXrXluxnS0HnA+davLzXqEkdF33TFT4GWackr+8IGO0/JSG0zvhCsCoNtKSX5gRWy4w2uqg6hH7r5mkYRdaIoc+dpB9Vy8Ubx7LVqoDupqSKLt6uewdQZdV+9pTarD++xmLjgHrS5dNetIo5qLJtAD/W55OW53cSgDdJ5xRsAqHI9uKQJ4wyTSn9vegkBzCLvQMEV1lWtr6MWeEJ1QrTOMUKTz6hFHX5d7O9VPPwptL/CGFGlXq0u3zRx4MdYI6Id+t7xUbw51tXgRAB1nnBGwCoeRRwGcov7slT4JuKAbxXZ9QF8ENEreqkMvbQr2HQd0ioBuMD6R3nhS7j3S9gIvS/s50p++Kn/Q6tJxMwdejDUC+qNueenfnYbH7S73AqD7jDMCViIfHXYBp8u3+tywycX5HEuz5a3nEZ9GS+SYjAI6I2+1dbQYzEPbC0yliEcbceXXX5c/PAg6b56RRpX8MAA6r10bEosyUFsL9IRxRsCqJDeNwFsdxFMjB5ibz7E0XY4YfVhsj6IFkqAunXMo8ELv1G0vG7H5fnVVd55Lr9T7vfX4oq/KvY+ML+qPuQIvA4cDQE/UGxK/La72ZrTRjWJ7p/qyEwA9cDnifgCsRN4N4G2KgPmNAhpu4nkKa5IEXuil+rD/SfnD3er959cpks+kdF1Z/fjoq3Lvpkbv/pkr8FI/UdwRC/RFdb37uA+jjY4roN0VB/RE2h2Xe2UArMBGbD42GhjeqgyYw/GoiiKg4ar9pfeiHcqADkmR3wnosXrM0VflD++HMUd00tFey/260ahuNgp6ac6RRnUiPX0eAL1QjzZKf+76TPnqDeGLsEkI9IYRncDq1HfWJa1ScKYcA6Ew5jKMXASwMNOgLgBd888xRz6b0gUvgi5Xfl09t+8ZX9RvcwdersSVR+5QA/oiR772PJ5+Eh31QXG1/t6KAOiJDW2FwIp9Vf7wIEd8FsCJUqQyYA6HMen0zSmwasdB3XEA0DnTMUd79+oxRz6f0k6CLrxp7sDL8RPIxRDojWoBuHOj2O7cyJ/6e8qR7wZAT1Sbt4+MMwLW4etyb6e6CmmYgjekauP9+90AoBE009El1Z7uXwJ4RT3mqP58KvhCewi6cLq5Ay/T/3NWbwj0zb0uhV6Ov5d7AdAjOYYOm4G1eVL+cDdF+pPGVHiFgyjmVm1ulgEtkCP9GC3xZbk3DqEXuqHU8AqnexF8qdZTN7V70UyCLrzdhQIv9cLXBRDooU6EXoRdgD6q167uIAfWrR5vNIn8vjvp4AU3VDG/S7FpbUdL5FYd0NSHStYqtF2O9FDDK7xdfd77Vbl3U/CF5hB04fwuFHipqTcEeureB8XVT6Kljn/v9wKgZ2zYAk2hQhp+VlYbmI8C5nS8+V0GNNyghQeI03GM9v9prftflz88CODcBF9YtxRpN0f6k6ALs0ixADeK7b9VX4oA6Jn6zfdy5D/OeqdAdd3MsQDVG/5M1/HrxXYxjPTnHPlaAPRPfaD26wBooHqdVq0tb6XId8Lna3qk3kw/Hp0Bc6s+Y9+rvnRm/DCd1OrPItVrbCemr7EioAXqw1JhF7i46efUuFf9uB2wRHXAqi7Z8NmQeVy44eWYu9GAXqqDIwcRXxx/8G+03xW/vDWI9K2wC9Bj7kwEGmva+PLDg+lh2PD9arvnYR2uDug2G5osxCTiUUBjpf2NiJvRYnUT12T6PdSfqcqAhpo2UgzfF3aBxXizmTRp22CBpmOL6ut23SzksyHzWkjDy6gotg7i2d+qo9+tAOip6oL66HL15nyetpdVNrwcX6M/ra7RtwKgv7S7AK1U31E3qJZ01eJxNIj0G+FluqLeMD8elQELcaO4Wh1uHrVkQYPUBzmDm0/K7zsTYn2xNgmNLzSIZgBYDe8BLEJ9zZ5E+vxKXHlkZBGLsJDAS011KMCRsvrxqDpUPbNFYBWBl2nQ5Wm12ZfuCiQCxP167msAtFy9xvspnl6bHG0ypt9Ui8FCCIYW8r7Mwh1/Bv42HL7QEPVhzuWIj2Ydg90mHxbbo8OInep7/X147bF6ZRw1TgwfdylUBm3x0nuAcUecQx0Czg9ds1mGhQVetLwAvKKsftzfiM3HJyVUlxl4EXQBeENZV4h3eaMZ6LcXIZgUg63DmFybBmHyVo50zXqQhikH1eGvu69ZluO7jr8IB++sUV+bJm4U717LMRkdh19G1iAsXtqv1ri7dSvAsPpqPQHNoPWF002v2xq4WLaFBV5qWl4A3lDWGx05hg9fTq0uI/BSJ6qrQ40/VP/iHZsKAK9wFznQW9Mw9PNqA/Jw6zDStToIUy0g34vjjcg8/VoELNX0br6N2HygspplE3phPerrXHw2iPzYgc5U/Vq8HINr/wzj1q109evSnhXnVh6PvfhrHXC5FJu71hHQbJq/qBlZxKotNPCi5QXgTNWHtPS4OmT4fDLdfLuwahPv5jTkkm+FBSTASbS7AJxD/Xk+4unWT8drysk/15ZHX49DMlGtPbfSz5/501Z+6ef2AnhdvdE5iMHDYWyMbXSySvU17Vk8faBinyX6+SD+SuTHPm+c38vNdD9FLk4J40bY5+qLer+0DsbuVn/238VRa/ZwdyMul9YO0G7/DL+kP/is2H1CLqzTQgMvNS0vAAA0RXUw+6evyx8eBAArNyq2i5N+/acZD7CORzW9sUH6avjmlf9H/evvnP+ff+Vw7XWn/TpvqOuqo6wey78MI42FXGiCumFiGPFpntbswwyODuCPrmsxvbY5iF+TF6HcF399EMOturnubf+/09YPLynizP//NOz7wumhX2uF15T1/0zXBEejLParrz/Wr6f67w1jsH8YqdyIw31BMegPzS/dJORCUyw88KLlBQCAhiiflHu/DgBYsFnDPKsI7azCaQdXw5jsOrSiyergS7UJes8hS2eV9f8ct0Tsv7hW1b9WB1Ve/uuX1devHJOjX5/EcL8+gK9/7nrGPF4O5ry8Hph04Jrz8mvlhUvHr7upzX0HncB51eGXSaRb9bosR74WtMjRCMdxtcL6fCM2H7v20xQLD7zUPiiu3q0uUp8EAACsz0dPyr1HAQAAx24U716rDm5H9SFL9aPox0HLNAjyyq+8clh95JW/finYtlCnhU8Gb/5+XgmhvE4oBQDarw4lD46a+I7GHtVrsiJomrL68/l8EPnxpdjcFXKhiZYSeKndKLb/Fi5MAACsh3YXAADOpQ7B1CNSjpsY6h9vjDNZlePROS8rX/6L15sWTgqFCIMAAG30cjBZAGZdjsLJj+tRtVpcaIulBV6mlVTxRQAAwOppdwEAAACAlqoDMMPIxWHkUYr8m3zUBsOClSliPA24xFhwmjZaWuCl9kGx/YWLDwAAq1R/SPuq3LsZAAAAAEBn1CGYiMPqR7o2DcGk6ud5KziHesxljKsf3w0jjYexMdbgQhcsNfCi5QUAgFXbiPi1uxEAAAAAoPtGRbH1Uzy9dngUgomiDsJUR+BbeToWqa+Omlsmkf56KVI5jMmu/VK6aqmBl9qN4uqDiHwnAABgyarF7aOvyr2PAgAAAADotVGxXfx0FIIZbB3GpG6Gqdtg3kuRt3L169O/bmNDTN3Wkqsfabf6XvYFW+izpQde6lTdQTz7mzopAACWrNyIuOlDHQAAAABwXnUw5iCGW4M4PDrPnhyFYarT7Uhb6bUz7upw/b0T/hXF8d+tm2W2zh+keRFcefHvnv519d/dT9OvPx7//XIYg/3DSNX+5+XSKCL4p6UHXmofFFfvVi/uTwIAAJbnoyfl3qMAAAAAAAA6byWBl9oHxfYXOWIUAACweOWTcu/XAQAAAAAA9MIgViRF3A8AAFiCepRRAAAAAAAAvTGMFfn3/X+Uv9r6119UP70eAACwMOnhv5V7/18AAAAAAAC9sbKGl9pGXLlXfSkDAAAWo9yI/CAAAAAAAIBeWWngZVyW+9V/8KMAAIDFuD8u98oAAAAAAAB6ZaWBl9qX5d44Ij0OAAC4gBTx6Em59ygAAAAAAIDeWXngpbYRVz6qjij2AwAA5lNejrgfAAAAAABAL60l8FKPNhpGMtoIAIB5GWUEAAAAAAA9Now1+ff9//k/frX1r9eqn/5vAQAA53Q8yki7CwAAAAAA9NhaGl5emI42ijIAAOB8jDICAAAAAADqG2TX68NiezSJ+CIAAOAtBhE3vyz3xgEAAAAAAPTa2kYavfDv+/8of7X1r7+ofno9AADgdPe/KvceBQAAAAAA0Htrb3ipjYpi63k8+yJHvhYAAPCm8km59+sAAAAAAACIo1b49RuX5f5h5D9GpP0AAIBXpP2NiJsBAAAAAABwbO0jjV74j/1/7P+vW//6rPrp/x4AAHAsR/q/vyz3/lsAAAAAAAAca0zgpfb3/X9886utf/1F9dPrAQAAkR5+Xf5wLwAAAAAAAF7SiJFGL9uIK/eqL2UAANB35fHaEAAAAAAA4BUpGuh6sV0MIn0bkbcCAIAeSvsbkd8fl3tlAAAAAAAAvKZxDS+1b6qDjWGkjwIAgF6q14LCLgAAAAAAwGmG0VD/vv8//8evtv6lbqAZBQAAfXL/q/KH/zcAAAAAAABO0ciRRi+7UVz9c0S+FQAA9EB6/KT84Y8BAAAAAABwhkaONHrZRlypRxuVAQBA15XHaz8AAAAAAIAzNb7hpXa92C4Gkb6NyFsBAEAXlRsRN8flXhkAAAAAAABv0YrAS+1G8e61iMNvAwCADhq+/6T8fjcAAAAAAADOofEjjV44PgBRcQ8A0DE50p+EXQAAAAAAgFkMo0X+vv+P3V9t/UvdSjMKAAC64P7X5d7/EwAAAAAAADNoVeCl9vf9f4x/tfWvv6h+ej0AAGix9PBJufd/BQAAAAAAwIxaF3ip/X3/H//tf9n6l1+niGsBAEALpcdPyh+MqwQAAAAAAOYyiJa6Ept3U6TdAACgVeo13EZcEXYBAAAAAADmlqLFRkWxdRBPv61+WgQAAG1QbsTm++Oy3A8AAAAAAIA5tbbhpVYflEwiblY/LQMAgKYrN6q1m7ALAAAAAABwUa1ueHnherFdDCK+CE0vAABNdRx22SsDAAAAAADggjoReKkJvQAANJawCwAAAAAAsFCdCbzUhF4AABpH2AUAAAAAAFi4TgVeakIvAACNIewCAAAAAAAsRecCLzWhFwCAtRN2AQAAAAAAlqaTgZea0AsAwNoIuwAAAAAAAEvV2cBLTegFAGDlhF0AAAAAAICl63TgpSb0AgCwMsIuAAAAAADASgyi476pDlw2YvP9FGk3AABYinqtVa+5hF0AAAAAAIBV6HzgpTYuy/3LceVmdRTzOAAAWKgc8Vm91qrXXAEAAAAAALACnR9p9LobxdUH1bHMnQAAYAHSwyflD3cDAAAAAABghYbRM3/f/8d/+9XWv9RBn1EAAHAR95+Ue/9XAAAAAAAArFjvAi+1v+//Y/y/bv3rj9VP//cAAGAeHz0p9x4EAAAAAADAGvRupNHLbhTvXos4/HP10yIAADiHtB8xuPmk/H43AAAAAAAA1qTXgZfa9WK7GER8EUIvAABvU25E3ByXe2UAAAAAAACs0SB67pvqwGYjNt+PSI8DAIBTpMf1mknYBQAAAAAAaILeN7y87Eaxfa/68nEAAPCy+0/KvXsBAAAAAADQEAIvr/ld8ctbh5E/jchbAQDQa2l/GOmjfyv/UxMeAAAAAADQKAIvJ7hebBeDiC+qnxYBANBP5UbETSOMAAAAAACAJhoEb/imOtjZiM33I9LDAADonfSwXgsJuwAAAAAAAE2l4eUtPiiu3s0RHxtxBAB0X9qv1j33vy5/eBAAAAAAAAANJvByDkYcAQBdlyLtXo78R60uAAAAAABAGwyDt/qP/X/s/33/Hw9/tfUvdUBoFAAAnVKPMLry0bj8j70AAAAAAABoAQ0vM/qw2B5NIj4NbS8AQPuVg4iPviz3xgEAAAAAANAiGl5m9O/7/yjf3fqXz6uf/iJFXAsAgFZKjzdi8//47+V//I8AAAAAAABoGQ0vF3Cj2N6pvnwc2l4AgNZI+8NIH/1b+Z+PAwAAAAAAoKU0vFzA3/f/savtBQBoj7rV5crN/17+fTcAAAAAAABaTMPLgmh7AQAarBxEfPRluTcOAAAAAACADtDwsiAv2l5SpDpEdD0AABohPdyIzf/zv5f/8T8CAAAAAACgIzS8LMH1YrsYRHwR2l4AgDWpFnnj6sd9rS4AAAAAAEAXCbwskTFHAMDqpf0ccf/r8ocHAQAAAAAA0FFGGi3RizFH1U9/kSKuBQDAUtXji6788cvyP8YBAAAAAADQYRpeVqQeczSM+DRHjAIAYIGMLwIAAAAAAPpG4GXFjDkCABaoHER8JOgCAAAAAAD0jcDLmgi+AADzS/s54v7X5Q8PAgAAAAAAoIcEXtbsg+Lq3Rz5Tgi+AABvlfYj8sON2HwwLsv9AAAAAAAA6CmBlwa4XmwXg4id6qe3Q/AFAHiDoAsAAAAAAMDLBF4aRPAFAHiVoAsAAAAAAMBJBF4a6kaxvVN9+TgEXwCghwRdAAAAAAAAziLw0nB18KX6Q7qdI0YBAHRa9Z4/rn7c/7LcGwcAAAAAAACnEnhpiRvFu9dyHN5N03FHAEBn1G0u8dkg8mNBFwAAAAAAgPMReGmZ68V2MYgYpUh3cuRrAQC0Ut3mMon0+ZW48sjYIgAAAAAAgNkIvLRYHX6p/gDvVT9+X/1lEQBAw9VtLvnhIGKszQUAAAAAAGB+Ai8d8WGxPTqM2BF+AYCmMbIIAAAAAABg0QReOkj4BQDWTcgFAAAAAABgmQReOu5G8e61HJNRdeD2hxwxCgBgKapF1bh6r/2LcUUAAAAAAADLJ/DSI6Oi2DqMg9FPMbml/QUALqysllKfR+Tdjdh8PC7L/QAAAAAAAGAlBF567HqxXQwiRnXzyyDSb3LkawEAnKb8Z8AlxuNyrwwAAAAAAADWQuCFn9UNMD/F02uT6qd1A0yOdK061NsKAOidtJ8i71bvhX8dRhoPY2OswQUAAAAAAKA5BF44043i3WvDyMVhTK5NQzBHY5CKAIDuKKsl0W719TvtLQAAAAAAAO0g8MLMXjTBHEaqQzBFivwbQRgAWqB8EWyp3rfKYeTdS7G5q7kFAAAAAACgfQReWJg6CHMQz4uXGmHeq365EIYBYIXKOtSSIu9PIv21/hox3N2Iy6VgCwAAAAAAQHcIvLAyo2K7+OmoEWawVQdiqqffVvXL71WHkVtCMQCcQ5ki7eejUMu0peWfgZbDfWOIAAAAAAAA+kPghUZ50RIziMOtyVE7TNqqAzF1W8yLn9dBmXz0VUAGoOXK+n+qa3xZXeP36/BKPgqyTH8+qH790vE/I8wCAAAAAADAywReaL26OeYghlt1SKb+68k/gzBHX49HK8U/AzNHv/oiNPPzPwfAuZUvfpL++fOff60Orbz8a8MY7OeY7F/6+Z/Z3DdeCAAAAAAAgIsQeIGX1A0zEU+PgjAvh2hemLwWjnk1RPNPL0I2rzvtn3/TK4GcOdTjoi7y/wcWpIwLSuf7d5z6z7wUPnnp16YNKi//2otQyou/vvTKv1NABQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACA/78dOBAAAAAAELQ/9SIFAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAQAP3ZeKxkxamrQAAAABJRU5ErkJggg==";async function Re(){let e=null,A=null,t=(l,p)=>{e=null,A=null,l(p)},r=!1,o=ct.createServer((l,p)=>{if(p.setHeader("Connection","close"),p.setHeader("Cache-Control","no-store"),!l.url){p.writeHead(400).end();return}if(l.method!=="GET"){p.writeHead(405,{"Content-Type":"text/plain",Allow:"GET"}).end("Method not allowed");return}let m=new URL(l.url,"http://127.0.0.1");if(m.pathname!=="/callback"){p.writeHead(404,{"Content-Type":"text/plain"}).end("Not found");return}if(r){p.writeHead(410,{"Content-Type":"text/plain"}).end("Callback already consumed");return}let w=m.searchParams.get("code"),y=m.searchParams.get("state"),h=m.searchParams.get("error"),x=m.searchParams.get("error_description")??"";if(h){r=!0;let N=x?` \u2014 ${x}`:"";Be(p,500,`OAuth error: ${h}${N}`),A&&t(A,new Error(`OAuth error: ${h}${N}`));return}if(!w||!y){Be(p,400,"Missing `code` or `state` in callback URL."),A&&t(A,new Error("Missing code or state"));return}r=!0,pt(p),e&&t(e,{code:w,state:y})});await new Promise(l=>{o.listen(0,"127.0.0.1",()=>l())});let s=o.address().port;return{redirectUri:`http://127.0.0.1:${s}/callback`,port:s,waitForCallback(l){return new Promise((p,m)=>{let w=setTimeout(()=>{e=null,A=null,m(new Error(`Timed out waiting for OAuth callback (${l}ms)`))},l);e=y=>{clearTimeout(w),p(y)},A=y=>{clearTimeout(w),m(y)}})},close(){o.close()}}}function Le(e){return e.replace(/&/g,"&amp;").replace(/</g,"&lt;").replace(/>/g,"&gt;").replace(/"/g,"&quot;").replace(/'/g,"&#39;")}function pt(e){let A=Ee({kind:"success",title:"You're signed in",body:"You can close this tab and return to your terminal."});e.writeHead(200,{"Content-Type":"text/html; charset=utf-8"}),e.end(A)}function Be(e,A,t){let r=Ee({kind:"error",title:"Login failed",body:t});e.writeHead(A,{"Content-Type":"text/html; charset=utf-8"}),e.end(r)}function Ee(e){let A=Le(e.title),t=Le(e.body),r=e.kind==="error"?"var(--error)":"var(--brown-800)",o=e.kind==="error"?"0.4":"1",i=e.kind==="success"?"<script>setTimeout(function(){try{window.close();}catch(e){}}, 2000);</script>":"",s=e.kind==="success"?'<p class="hint">Closing this tab automatically&hellip;</p>':"";return`<!doctype html>
281
7
  <html lang="en">
282
8
  <head>
283
9
  <meta charset="utf-8">
284
10
  <meta name="viewport" content="width=device-width, initial-scale=1">
285
- <title>Tiro \u2014 ${safeTitle}</title>
11
+ <title>Tiro \u2014 ${A}</title>
286
12
  <link rel="preconnect" href="https://fonts.googleapis.com">
287
13
  <link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
288
14
  <link href="https://fonts.googleapis.com/css2?family=Averia+Serif+Libre:wght@300;400;700&display=swap" rel="stylesheet">
@@ -322,14 +48,14 @@ function renderPage(p) {
322
48
  height: auto;
323
49
  margin-bottom: 1.5rem;
324
50
  object-fit: contain;
325
- opacity: ${logoOpacity};
51
+ opacity: ${o};
326
52
  }
327
53
  h1 {
328
54
  font-family: 'Averia Serif Libre', Georgia, 'Times New Roman', serif;
329
55
  font-size: 36px;
330
56
  line-height: 42px;
331
57
  font-weight: 400;
332
- color: ${titleColor};
58
+ color: ${r};
333
59
  }
334
60
  .body {
335
61
  margin-top: 1.5rem;
@@ -358,999 +84,35 @@ function renderPage(p) {
358
84
  <body>
359
85
  <div class="top-spacer"></div>
360
86
  <main>
361
- <img class="logo" src="${TIRO_LOGO_BROWN_DATA_URI}" alt="Tiro">
362
- <h1>${safeTitle}</h1>
363
- <p class="body">${safeBody}</p>
364
- ${hint}
87
+ <img class="logo" src="${Te}" alt="Tiro">
88
+ <h1>${A}</h1>
89
+ <p class="body">${t}</p>
90
+ ${s}
365
91
  </main>
366
92
  <footer>&copy; 2026 <a href="https://tiro.ooo">The Plato Inc.</a> &mdash; All rights reserved.</footer>
367
- ${closeScript}
93
+ ${i}
368
94
  </body>
369
- </html>`;
370
- }
371
-
372
- // src/lib/auth/browser.ts
373
- import open from "open";
374
- async function openBrowser(url) {
375
- try {
376
- await open(url, { wait: false });
377
- } catch {
378
- }
379
- }
380
-
381
- // src/lib/auth/keychain.ts
382
- import { Entry } from "@napi-rs/keyring";
383
- var SERVICE = "io.tiro.cli";
384
- var ACCOUNT = "default";
385
- function saveToken(token) {
386
- const entry = new Entry(SERVICE, ACCOUNT);
387
- try {
388
- entry.setPassword(JSON.stringify(token));
389
- } catch (err) {
390
- throw new TiroError(
391
- {
392
- code: "keychain_write_failed",
393
- message: `Failed to write to OS keychain: ${err.message}`,
394
- errorType: "internal_error",
395
- suggestion: process.platform === "linux" ? "Linux requires a Secret Service daemon (gnome-keyring or kwallet). Or set TIRO_TOKEN env var." : "Check OS keychain permissions, or set TIRO_TOKEN env var."
396
- },
397
- ExitCode.Generic
398
- );
399
- }
400
- }
401
- function loadToken() {
402
- const entry = new Entry(SERVICE, ACCOUNT);
403
- let raw;
404
- try {
405
- raw = entry.getPassword();
406
- } catch {
407
- return null;
408
- }
409
- if (!raw) return null;
410
- try {
411
- return JSON.parse(raw);
412
- } catch {
413
- return null;
414
- }
415
- }
416
- function deleteToken() {
417
- const entry = new Entry(SERVICE, ACCOUNT);
418
- try {
419
- return entry.deletePassword();
420
- } catch {
421
- return false;
422
- }
423
- }
424
-
425
- // src/lib/auth/token.ts
426
- function resolveToken() {
427
- const envToken = process.env["TIRO_TOKEN"];
428
- if (envToken) {
429
- return { accessToken: envToken, source: "env" };
430
- }
431
- const stored = loadToken();
432
- if (stored) {
433
- return {
434
- accessToken: stored.accessToken,
435
- source: "keychain",
436
- hostname: stored.hostname,
437
- expiresAt: stored.expiresAt,
438
- ...stored.userId !== void 0 && { userId: stored.userId }
439
- };
440
- }
441
- return null;
442
- }
443
- function decodeJwtPayload(token) {
444
- const parts = token.split(".");
445
- if (parts.length !== 3) return null;
446
- try {
447
- const payload = parts[1];
448
- if (!payload) return null;
449
- const json = Buffer.from(payload, "base64url").toString("utf8");
450
- return JSON.parse(json);
451
- } catch {
452
- return null;
453
- }
454
- }
455
-
456
- // src/lib/config.ts
457
- import Conf from "conf";
458
- var DEFAULT_HOSTNAME = "https://api.tiro.ooo";
459
- var LOOPBACK_HOSTS = /* @__PURE__ */ new Set(["localhost", "127.0.0.1", "[::1]", "::1"]);
460
- var config = new Conf({
461
- projectName: "tiro",
462
- defaults: {
463
- hostname: DEFAULT_HOSTNAME,
464
- oauthClientId: null,
465
- oauthClientIdRegisteredAt: null,
466
- oauthClientHostname: null,
467
- oauthClientRedirectUri: null,
468
- defaultOutputDir: null
469
- }
470
- });
471
- function validateHostname(input) {
472
- const trimmed = input.trim();
473
- if (trimmed === "") {
474
- throw hostnameError("empty hostname", input);
475
- }
476
- let url;
477
- try {
478
- url = new URL(trimmed);
479
- } catch {
480
- throw hostnameError("not a valid URL", input);
481
- }
482
- if (url.protocol === "https:") {
483
- } else if (url.protocol === "http:" && isLoopback(url.hostname)) {
484
- } else {
485
- throw hostnameError(
486
- `disallowed scheme "${url.protocol}" \u2014 only https:// or http://localhost is permitted`,
487
- input
488
- );
489
- }
490
- if (url.username !== "" || url.password !== "") {
491
- throw hostnameError("URL must not embed credentials", input);
492
- }
493
- if (url.search !== "" || url.hash !== "") {
494
- throw hostnameError("URL must not include query or fragment", input);
495
- }
496
- if (url.pathname !== "" && url.pathname !== "/") {
497
- throw hostnameError("URL must be host root (no path segment)", input);
498
- }
499
- const origin = url.origin;
500
- return stripTrailingSlash(origin);
501
- }
502
- function isLoopback(host) {
503
- if (host.startsWith("[") && host.endsWith("]")) {
504
- host = host.slice(1, -1);
505
- }
506
- return LOOPBACK_HOSTS.has(host);
507
- }
508
- function hostnameError(reason, input) {
509
- return new TiroError(
510
- {
511
- code: "invalid_hostname",
512
- message: `Refusing to use hostname "${input}": ${reason}.`,
513
- errorType: "bad_request",
514
- suggestion: "Use https://<host> (or http://localhost for local dev). If TIRO_HOSTNAME is set in your environment, unset it."
515
- },
516
- ExitCode.Usage
517
- );
518
- }
519
- function getHostname(override) {
520
- if (override !== void 0) return validateHostname(override);
521
- const env = process.env["TIRO_HOSTNAME"];
522
- if (env) return validateHostname(env);
523
- return validateHostname(config.get("hostname"));
524
- }
525
- function getOauthClientId(hostname, currentRedirectUri) {
526
- const id = config.get("oauthClientId");
527
- const registeredAt = config.get("oauthClientIdRegisteredAt");
528
- const cachedHostname = config.get("oauthClientHostname");
529
- const cachedRedirectUri = config.get("oauthClientRedirectUri");
530
- if (!id || !registeredAt) return null;
531
- if (cachedHostname !== hostname) return null;
532
- if (!cachedRedirectUri) return null;
533
- if (!sameRedirectTarget(cachedRedirectUri, currentRedirectUri)) return null;
534
- const ttlMs = 29 * 24 * 60 * 60 * 1e3;
535
- if (Date.now() - registeredAt > ttlMs) return null;
536
- return id;
537
- }
538
- function setOauthClientId(clientId, hostname, redirectUri) {
539
- config.set("oauthClientId", clientId);
540
- config.set("oauthClientIdRegisteredAt", Date.now());
541
- config.set("oauthClientHostname", hostname);
542
- config.set("oauthClientRedirectUri", redirectUri);
543
- }
544
- function clearOauthClientId() {
545
- config.set("oauthClientId", null);
546
- config.set("oauthClientIdRegisteredAt", null);
547
- config.set("oauthClientHostname", null);
548
- config.set("oauthClientRedirectUri", null);
549
- }
550
- function sameRedirectTarget(a, b) {
551
- let pa, pb;
552
- try {
553
- pa = new URL(a);
554
- pb = new URL(b);
555
- } catch {
556
- return false;
557
- }
558
- return pa.protocol === pb.protocol && pa.hostname === pb.hostname && pa.pathname === pb.pathname;
559
- }
560
- function stripTrailingSlash(s) {
561
- return s.endsWith("/") ? s.slice(0, -1) : s;
562
- }
563
-
564
- // src/lib/auth/flow.ts
565
- var RegisterResponseSchema = z.object({
566
- client_id: z.string(),
567
- client_secret: z.string().optional()
568
- });
569
- var TokenResponseSchema = z.object({
570
- access_token: z.string(),
571
- token_type: z.string(),
572
- expires_in: z.number().optional(),
573
- scope: z.string().optional()
574
- });
575
- var CALLBACK_TIMEOUT_MS = 5 * 60 * 1e3;
576
- var DEFAULT_SCOPE = "mcp:notes:read";
577
- async function performLogin(options = {}) {
578
- const hostname = getHostname(options.hostname);
579
- const onPrompt = options.onPrompt ?? ((msg) => process.stderr.write(`${msg}
580
- `));
581
- const loopback = await startLoopbackServer();
582
- try {
583
- const clientId = await ensureOauthClient(hostname, loopback.redirectUri);
584
- const { codeVerifier, codeChallenge } = generatePkce();
585
- const state = generateState();
586
- const authorizeUrl = buildAuthorizeUrl({
587
- hostname,
588
- clientId,
589
- redirectUri: loopback.redirectUri,
590
- state,
591
- codeChallenge,
592
- scope: options.scope ?? DEFAULT_SCOPE
593
- });
594
- if (options.noBrowser) {
595
- onPrompt(`Open this URL in your browser:
596
- ${authorizeUrl}`);
597
- } else {
598
- onPrompt(`Opening browser for sign-in...`);
599
- onPrompt(`If the browser does not open, visit:
600
- ${authorizeUrl}`);
601
- await openBrowser(authorizeUrl);
602
- }
603
- const callback = await loopback.waitForCallback(CALLBACK_TIMEOUT_MS);
604
- if (!verifyState(callback.state, state)) {
605
- throw new TiroError(
606
- {
607
- code: "auth_state_mismatch",
608
- message: "OAuth state mismatch \u2014 possible CSRF. Aborting.",
609
- errorType: "unauthorized"
610
- },
611
- ExitCode.Generic
612
- );
613
- }
614
- const tokenRes = await exchangeToken({
615
- hostname,
616
- clientId,
617
- code: callback.code,
618
- redirectUri: loopback.redirectUri,
619
- codeVerifier
620
- });
621
- const expiresAt = computeExpiry(tokenRes.expires_in);
622
- const payload = decodeJwtPayload(tokenRes.access_token);
623
- const userId = typeof payload?.["sub"] === "string" ? payload["sub"] : void 0;
624
- const stored = {
625
- accessToken: tokenRes.access_token,
626
- tokenType: tokenRes.token_type,
627
- expiresAt,
628
- hostname,
629
- ...tokenRes.scope !== void 0 && { scope: tokenRes.scope },
630
- ...userId !== void 0 && { userId }
631
- };
632
- saveToken(stored);
633
- return { hostname, userId, expiresAt };
634
- } finally {
635
- loopback.close();
636
- }
637
- }
638
- async function ensureOauthClient(hostname, redirectUri) {
639
- const cached = getOauthClientId(hostname, redirectUri);
640
- if (cached) return cached;
641
- const url = `${hostname}/v1/mcp/oauth/register`;
642
- let res;
643
- try {
644
- res = await fetch(url, {
645
- method: "POST",
646
- headers: { "Content-Type": "application/json" },
647
- body: JSON.stringify({
648
- client_name: "tiro-cli",
649
- redirect_uris: [redirectUri],
650
- grant_types: ["authorization_code"],
651
- response_types: ["code"],
652
- token_endpoint_auth_method: "none",
653
- scope: DEFAULT_SCOPE
654
- })
655
- });
656
- } catch (err) {
657
- throw new TiroError(
658
- {
659
- code: "network_error",
660
- message: `Failed to reach ${hostname}: ${err.message}`,
661
- errorType: "network_error",
662
- suggestion: "Check your network connection or --hostname."
663
- },
664
- ExitCode.Generic
665
- );
666
- }
667
- if (!res.ok) {
668
- const detail = await safeText(res);
669
- throw new TiroError(
670
- {
671
- code: "oauth_register_failed",
672
- message: `Dynamic Client Registration failed: HTTP ${res.status}`,
673
- errorType: "internal_error",
674
- httpStatus: res.status,
675
- ...detail !== "" && { suggestion: detail.slice(0, 200) }
676
- },
677
- ExitCode.Generic
678
- );
679
- }
680
- const json = await res.json();
681
- const parsed = RegisterResponseSchema.safeParse(json);
682
- if (!parsed.success) {
683
- throw new TiroError(
684
- {
685
- code: "oauth_register_invalid",
686
- message: "Registration response did not match expected shape.",
687
- errorType: "internal_error"
688
- },
689
- ExitCode.Generic
690
- );
691
- }
692
- setOauthClientId(parsed.data.client_id, hostname, redirectUri);
693
- return parsed.data.client_id;
694
- }
695
- function buildAuthorizeUrl(input) {
696
- const u = new URL(`${input.hostname}/v1/mcp/oauth/authorize`);
697
- u.searchParams.set("response_type", "code");
698
- u.searchParams.set("client_id", input.clientId);
699
- u.searchParams.set("redirect_uri", input.redirectUri);
700
- u.searchParams.set("state", input.state);
701
- u.searchParams.set("code_challenge", input.codeChallenge);
702
- u.searchParams.set("code_challenge_method", "S256");
703
- u.searchParams.set("scope", input.scope);
704
- return u.toString();
705
- }
706
- async function exchangeToken(input) {
707
- const url = `${input.hostname}/v1/mcp/oauth/token`;
708
- const body = new URLSearchParams({
709
- grant_type: "authorization_code",
710
- code: input.code,
711
- redirect_uri: input.redirectUri,
712
- client_id: input.clientId,
713
- code_verifier: input.codeVerifier
714
- });
715
- let res;
716
- try {
717
- res = await fetch(url, {
718
- method: "POST",
719
- headers: { "Content-Type": "application/x-www-form-urlencoded" },
720
- body: body.toString()
721
- });
722
- } catch (err) {
723
- throw new TiroError(
724
- {
725
- code: "network_error",
726
- message: `Failed to reach ${input.hostname}: ${err.message}`,
727
- errorType: "network_error"
728
- },
729
- ExitCode.Generic
730
- );
731
- }
732
- if (!res.ok) {
733
- if (res.status === 400 || res.status === 401) {
734
- clearOauthClientId();
735
- }
736
- const detail = await safeText(res);
737
- throw new TiroError(
738
- {
739
- code: "oauth_token_failed",
740
- message: `Token exchange failed: HTTP ${res.status}`,
741
- errorType: "unauthorized",
742
- httpStatus: res.status,
743
- ...detail !== "" && { suggestion: detail.slice(0, 200) }
744
- },
745
- ExitCode.AuthRequired
746
- );
747
- }
748
- const json = await res.json();
749
- const parsed = TokenResponseSchema.safeParse(json);
750
- if (!parsed.success) {
751
- throw new TiroError(
752
- {
753
- code: "oauth_token_invalid",
754
- message: "Token response did not match expected shape.",
755
- errorType: "internal_error"
756
- },
757
- ExitCode.Generic
758
- );
759
- }
760
- return parsed.data;
761
- }
762
- function computeExpiry(expiresIn) {
763
- const fallbackSeconds = 180 * 24 * 60 * 60;
764
- const seconds = expiresIn ?? fallbackSeconds;
765
- return Date.now() + seconds * 1e3;
766
- }
767
- async function safeText(res) {
768
- try {
769
- return await res.text();
770
- } catch {
771
- return "";
772
- }
773
- }
774
-
775
- // src/commands/auth/login.ts
776
- function registerAuthLogin(parent) {
777
- parent.command("login").description("Sign in to Tiro via OAuth (browser-based, PKCE)").option("--hostname <url>", "API base URL (overrides config / TIRO_HOSTNAME)").option("--no-browser", "Print the URL instead of opening a browser").action(async (opts, cmd) => {
778
- const globalOpts = cmd.optsWithGlobals();
779
- const result = await performLogin({
780
- ...opts.hostname !== void 0 && { hostname: opts.hostname },
781
- noBrowser: opts.noBrowser === true,
782
- onPrompt: (msg) => {
783
- if (globalOpts.quiet) return;
784
- process.stderr.write(`${color(msg, "cyan", globalOpts)}
785
- `);
786
- }
787
- });
788
- const hostname = getHostname(opts.hostname);
789
- const expiresIso = new Date(result.expiresAt).toISOString();
790
- if (globalOpts.json) {
791
- printOutput(
792
- {
793
- ok: true,
794
- data: {
795
- signedIn: true,
796
- hostname,
797
- userId: result.userId ?? null,
798
- expiresAt: expiresIso
799
- }
800
- },
801
- globalOpts
802
- );
803
- } else if (!globalOpts.quiet) {
804
- process.stderr.write(`${color("\u2713", "green", globalOpts)} Signed in to ${hostname}
805
- `);
806
- if (result.userId) {
807
- process.stderr.write(` user: ${result.userId}
808
- `);
809
- }
810
- process.stderr.write(` token expires: ${expiresIso}
811
- `);
812
- }
813
- });
814
- }
815
-
816
- // src/commands/auth/status.ts
817
- import "commander";
818
- function registerAuthStatus(parent) {
819
- parent.command("status").description("Show current authenticated account and scopes").action(async (_opts, cmd) => {
820
- const globalOpts = cmd.optsWithGlobals();
821
- const t = resolveToken();
822
- if (!t) {
823
- throw authRequired();
824
- }
825
- const payload = decodeJwtPayload(t.accessToken);
826
- const sub = typeof payload?.["sub"] === "string" ? payload["sub"] : null;
827
- const exp = typeof payload?.["exp"] === "number" ? payload["exp"] * 1e3 : null;
828
- const scope = typeof payload?.["scope"] === "string" ? payload["scope"] : null;
829
- const expMs = exp ?? t.expiresAt ?? null;
830
- const expired = expMs !== null && Date.now() >= expMs;
831
- const report = {
832
- signedIn: true,
833
- source: t.source,
834
- hostname: t.hostname ?? null,
835
- userId: t.userId ?? sub,
836
- scope,
837
- expiresAt: expMs ? new Date(expMs).toISOString() : null,
838
- expired,
839
- tokenPrefix: `${t.accessToken.slice(0, 4)}...***`
840
- };
841
- if (globalOpts.json || !process.stdout.isTTY) {
842
- printOutput({ ok: true, data: report }, globalOpts);
843
- } else {
844
- const headIcon = expired ? color("!", "yellow", globalOpts) : color("\u2713", "green", globalOpts);
845
- const headText = expired ? "Token expired" : "Signed in";
846
- process.stdout.write(`${headIcon} ${headText}
847
- `);
848
- process.stdout.write(` source: ${report.source}
849
- `);
850
- if (report.hostname) process.stdout.write(` hostname: ${report.hostname}
851
- `);
852
- if (report.userId) process.stdout.write(` user: ${report.userId}
853
- `);
854
- if (report.scope) process.stdout.write(` scope: ${report.scope}
855
- `);
856
- if (report.expiresAt) {
857
- const tag = expired ? color(" (expired)", "red", globalOpts) : "";
858
- process.stdout.write(` expires at: ${report.expiresAt}${tag}
859
- `);
860
- }
861
- process.stdout.write(` token: ${report.tokenPrefix}
862
- `);
863
- if (expired) {
864
- process.stdout.write(
865
- `
866
- ${color("\u2192", "gray", globalOpts)} Run \`tiro auth login\` to refresh.
867
- `
868
- );
869
- }
870
- }
871
- });
872
- }
873
-
874
- // src/commands/auth/logout.ts
875
- import "commander";
876
- function registerAuthLogout(parent) {
877
- parent.command("logout").description("Sign out and clear the stored token").action(async (_opts, cmd) => {
878
- const globalOpts = cmd.optsWithGlobals();
879
- const removed = deleteToken();
880
- clearOauthClientId();
881
- if (globalOpts.json) {
882
- printOutput({ ok: true, data: { signedOut: true, hadToken: removed } }, globalOpts);
883
- } else if (!globalOpts.quiet) {
884
- if (removed) {
885
- process.stderr.write(`${color("\u2713", "green", globalOpts)} Signed out
886
- `);
887
- } else {
888
- process.stderr.write(`${color("\u2022", "gray", globalOpts)} No token was stored
889
- `);
890
- }
891
- }
892
- });
893
- }
894
-
895
- // src/commands/auth/index.ts
896
- function registerAuth(program) {
897
- const auth = program.command("auth").description("Manage authentication");
898
- registerAuthLogin(auth);
899
- registerAuthStatus(auth);
900
- registerAuthLogout(auth);
901
- }
902
-
903
- // src/commands/notes/index.ts
904
- import "commander";
905
-
906
- // src/commands/notes/list.ts
907
- import "commander";
908
-
909
- // src/lib/api/client.ts
910
- import "zod";
911
-
912
- // src/lib/api/types.ts
913
- import { z as z2 } from "zod";
914
- var CollaboratorSchema = z2.object({
915
- guid: z2.string(),
916
- name: z2.string(),
917
- email: z2.string(),
918
- role: z2.enum(["OWNER", "EDITOR", "VIEWER"])
919
- });
920
- var ParticipantSchema = z2.object({
921
- name: z2.string().nullable().optional(),
922
- email: z2.string().nullable().optional()
923
- });
924
- var NoteSchema = z2.object({
925
- guid: z2.string(),
926
- title: z2.string(),
927
- createdAt: z2.string(),
928
- updatedAt: z2.string(),
929
- sourceType: z2.string(),
930
- recordingDurationSeconds: z2.number(),
931
- collaborators: z2.array(CollaboratorSchema).optional().default([]),
932
- participants: z2.array(ParticipantSchema).optional().default([]),
933
- webUrl: z2.string(),
934
- recordingStartAt: z2.string().nullable().optional(),
935
- recordingEndAt: z2.string().nullable().optional()
936
- }).passthrough();
937
- var TextObjectSchema = z2.object({
938
- type: z2.string(),
939
- content: z2.string()
940
- });
941
- var SpeakerInfoSchema = z2.object({
942
- label: z2.string(),
943
- personName: z2.string().nullable().optional()
944
- });
945
- var DiarizedSegmentSchema = z2.object({
946
- content: z2.string(),
947
- speaker: SpeakerInfoSchema
948
- });
949
- var ParagraphSchema = z2.object({
950
- uuid: z2.string(),
951
- transcribeLocale: z2.string().nullable().optional(),
952
- transcript: TextObjectSchema.nullable().optional(),
953
- diarizedSegments: z2.array(DiarizedSegmentSchema).nullable().optional(),
954
- timeFrom: z2.string().nullable().optional(),
955
- timeTo: z2.string().nullable().optional(),
956
- locked: z2.boolean().optional()
957
- }).passthrough();
958
- var McpSegmentSchema = z2.object({
959
- content: z2.string(),
960
- speaker: z2.object({
961
- label: z2.string(),
962
- name: z2.string().nullable()
963
- }).nullable()
964
- });
965
- var McpParagraphSchema = z2.object({
966
- timeFrom: z2.string().nullable(),
967
- timeTo: z2.string().nullable(),
968
- segments: z2.array(McpSegmentSchema)
969
- });
970
- var McpTranscriptSchema = z2.object({
971
- noteGuid: z2.string(),
972
- title: z2.string(),
973
- participants: z2.array(z2.string()),
974
- createdAt: z2.string(),
975
- recordingDurationSeconds: z2.number(),
976
- paragraphs: z2.array(McpParagraphSchema)
977
- });
978
- var PageCursorResponseSchema = (item) => z2.object({
979
- content: z2.array(item),
980
- nextCursor: z2.string().nullable()
981
- });
982
- var SimpleListResponseSchema = (item) => z2.object({
983
- content: z2.array(item)
984
- });
985
- var ApiErrorSchema = z2.object({
986
- error: z2.object({
987
- code: z2.number(),
988
- errorType: z2.string(),
989
- message: z2.string(),
990
- detail: z2.string().nullable().optional()
991
- })
992
- });
993
- var WorkspaceMeSchema = z2.object({
994
- guid: z2.string()
995
- }).passthrough();
996
- var WorkspaceItemSchema = z2.object({
997
- guid: z2.string(),
998
- name: z2.string(),
999
- isWikiEnabled: z2.boolean()
1000
- }).passthrough();
1001
- var WorkspacesListSchema = z2.object({
1002
- workspaces: z2.array(WorkspaceItemSchema)
1003
- }).passthrough();
1004
- var WikiSearchPageSchema = z2.object({
1005
- guid: z2.string(),
1006
- wikiId: z2.number(),
1007
- canonicalName: z2.string(),
1008
- pageType: z2.string(),
1009
- entitySubtype: z2.string().nullable().optional(),
1010
- score: z2.number()
1011
- }).passthrough();
1012
- var WikiSearchPagesResponseSchema = z2.object({
1013
- items: z2.array(WikiSearchPageSchema)
1014
- }).passthrough();
1015
- var WikiMentionSchema = z2.object({
1016
- guid: z2.string(),
1017
- noteId: z2.number(),
1018
- paragraphId: z2.number().nullable().optional(),
1019
- paragraphUuid: z2.string().nullable().optional(),
1020
- kind: z2.string(),
1021
- sourceUserId: z2.number(),
1022
- extractedText: z2.string(),
1023
- confidence: z2.number().nullable().optional(),
1024
- createdAt: z2.string()
1025
- }).passthrough();
1026
- var WikiAliasSchema = z2.object({
1027
- guid: z2.string(),
1028
- alias: z2.string(),
1029
- source: z2.string(),
1030
- sourceMentionGuid: z2.string().nullable().optional(),
1031
- sourceUserId: z2.number().nullable().optional(),
1032
- createdAt: z2.string()
1033
- }).passthrough();
1034
- var WikiLinkSchema = z2.object({
1035
- guid: z2.string(),
1036
- sourcePageGuid: z2.string(),
1037
- sourcePageName: z2.string().nullable().optional(),
1038
- targetPageGuid: z2.string(),
1039
- targetPageName: z2.string().nullable().optional(),
1040
- linkType: z2.string(),
1041
- linkTypeDisplayKo: z2.string().optional(),
1042
- linkTypeDisplayEn: z2.string().optional(),
1043
- isDirectional: z2.boolean(),
1044
- source: z2.string().optional(),
1045
- creatorUserId: z2.number().nullable().optional(),
1046
- createdAt: z2.string().optional(),
1047
- updatedAt: z2.string().optional()
1048
- }).passthrough();
1049
- var WikiPageDetailSchema = z2.object({
1050
- guid: z2.string(),
1051
- wikiId: z2.number(),
1052
- canonicalName: z2.string(),
1053
- description: z2.string().nullable().optional(),
1054
- descriptionStatus: z2.string().nullable().optional(),
1055
- regenerationAvailable: z2.boolean().nullable().optional(),
1056
- pageType: z2.string(),
1057
- entitySubtype: z2.string().nullable().optional(),
1058
- extractionStatus: z2.string(),
1059
- mentionCountVisible: z2.number(),
1060
- mentions: z2.array(WikiMentionSchema),
1061
- aliases: z2.array(WikiAliasSchema),
1062
- links: z2.array(WikiLinkSchema),
1063
- lastUpdatedVisible: z2.string().nullable().optional(),
1064
- createdAt: z2.string(),
1065
- updatedAt: z2.string()
1066
- }).passthrough();
1067
- var WikiMentionListResponseSchema = z2.object({
1068
- items: z2.array(WikiMentionSchema),
1069
- nextCursorCreatedAt: z2.string().nullable(),
1070
- nextCursorId: z2.number().nullable()
1071
- }).passthrough();
1072
- var WikiGraphNodeSchema = z2.object({
1073
- guid: z2.string(),
1074
- canonicalName: z2.string(),
1075
- pageType: z2.string(),
1076
- entitySubtype: z2.string().nullable().optional(),
1077
- extractionStatus: z2.string(),
1078
- mentionCountVisible: z2.number()
1079
- }).passthrough();
1080
- var WikiGraphEdgeSchema = z2.object({
1081
- guid: z2.string(),
1082
- sourcePageGuid: z2.string(),
1083
- targetPageGuid: z2.string(),
1084
- linkType: z2.string(),
1085
- linkTypeDisplayKo: z2.string().optional(),
1086
- linkTypeDisplayEn: z2.string().optional(),
1087
- isDirectional: z2.boolean()
1088
- }).passthrough();
1089
- var WikiGraphResponseSchema = z2.object({
1090
- nodes: z2.array(WikiGraphNodeSchema),
1091
- edges: z2.array(WikiGraphEdgeSchema)
1092
- }).passthrough();
1093
- var WikiPlanRequiredSchema = z2.object({
1094
- // Two gate kinds, relayed verbatim:
1095
- // WIKI_PLAN_REQUIRED → plan ineligible (upsell; required_plans set)
1096
- // WIKI_NOT_ACTIVATED → eligible plan, wiki not activated by an admin (required_plans null)
1097
- error_code: z2.enum(["WIKI_PLAN_REQUIRED", "WIKI_NOT_ACTIVATED"]),
1098
- message: z2.string(),
1099
- current_plan: z2.string().nullable().optional(),
1100
- required_plans: z2.array(z2.string()).nullable().optional(),
1101
- action_url: z2.string().nullable().optional()
1102
- }).passthrough();
1103
-
1104
- // src/lib/api/client.ts
1105
- var TiroApiClient = class {
1106
- constructor(hostname, token) {
1107
- this.hostname = hostname;
1108
- this.token = token;
1109
- }
1110
- hostname;
1111
- token;
1112
- async getJson(path, schema, params) {
1113
- const url = this.buildUrl(path, params);
1114
- const res = await this.fetch(url, { method: "GET" });
1115
- return this.parseJson(res, schema, "GET", path);
1116
- }
1117
- async postJson(path, schema, body) {
1118
- const url = this.buildUrl(path);
1119
- const res = await this.fetch(url, {
1120
- method: "POST",
1121
- headers: { "Content-Type": "application/json" },
1122
- body: JSON.stringify(body)
1123
- });
1124
- return this.parseJson(res, schema, "POST", path);
1125
- }
1126
- async putJson(path, schema, body) {
1127
- const url = this.buildUrl(path);
1128
- const res = await this.fetch(url, {
1129
- method: "PUT",
1130
- headers: { "Content-Type": "application/json" },
1131
- body: JSON.stringify(body)
1132
- });
1133
- return this.parseJson(res, schema, "PUT", path);
1134
- }
1135
- async deleteVoid(path) {
1136
- const url = this.buildUrl(path);
1137
- const res = await this.fetch(url, { method: "DELETE" });
1138
- if (!res.ok) throw await mapHttpError(res, "DELETE", path);
1139
- }
1140
- buildUrl(path, params) {
1141
- return buildApiUrl(this.hostname, path, params);
1142
- }
1143
- async fetch(url, init) {
1144
- const headers = new Headers(init.headers);
1145
- headers.set("Authorization", `Bearer ${this.token}`);
1146
- headers.set("Accept", "application/json");
1147
- try {
1148
- return await fetch(url, { ...init, headers });
1149
- } catch (err) {
1150
- throw new TiroError(
1151
- {
1152
- code: "network_error",
1153
- message: `Network error reaching ${this.hostname}: ${err.message}`,
1154
- errorType: "network_error",
1155
- suggestion: "Check your network or --hostname."
1156
- },
1157
- ExitCode.Generic
1158
- );
1159
- }
1160
- }
1161
- async parseJson(res, schema, method, path) {
1162
- if (!res.ok) throw await mapHttpError(res, method, path);
1163
- let json;
1164
- try {
1165
- json = await res.json();
1166
- } catch (err) {
1167
- throw new TiroError(
1168
- {
1169
- code: "invalid_response",
1170
- message: `Failed to parse JSON from ${method} ${path}: ${err.message}`,
1171
- errorType: "internal_error"
1172
- },
1173
- ExitCode.Generic
1174
- );
1175
- }
1176
- const parsed = schema.safeParse(json);
1177
- if (!parsed.success) {
1178
- throw new TiroError(
1179
- {
1180
- code: "schema_mismatch",
1181
- message: `Response shape did not match expected schema (${method} ${path}).`,
1182
- errorType: "internal_error",
1183
- suggestion: parsed.error.issues.slice(0, 3).map((i) => `${i.path.join(".") || "(root)"}: ${i.message}`).join("; ")
1184
- },
1185
- ExitCode.Generic
1186
- );
1187
- }
1188
- return parsed.data;
1189
- }
1190
- };
1191
- async function mapHttpError(res, method, path) {
1192
- const requestId = res.headers.get("x-request-id") ?? void 0;
1193
- const exitCode = res.status === 401 ? ExitCode.AuthRequired : ExitCode.Generic;
1194
- if (res.status === 402) {
1195
- const gate = await tryParsePlanGate(res);
1196
- if (gate) return planGateError(gate, requestId);
1197
- }
1198
- const apiError = await tryParseApiError(res);
1199
- if (apiError) {
1200
- return new TiroError(
1201
- {
1202
- code: `${apiError.error.errorType}`,
1203
- message: apiError.error.message,
1204
- errorType: apiError.error.errorType,
1205
- httpStatus: res.status,
1206
- ...requestId !== void 0 && { requestId },
1207
- ...res.status === 401 && {
1208
- suggestion: "Run `tiro auth login` to refresh."
1209
- }
1210
- },
1211
- exitCode
1212
- );
1213
- }
1214
- return new TiroError(
1215
- {
1216
- code: "http_error",
1217
- message: `${method} ${path} failed: HTTP ${res.status} ${res.statusText}`,
1218
- errorType: httpStatusToErrorType(res.status),
1219
- httpStatus: res.status,
1220
- ...requestId !== void 0 && { requestId }
1221
- },
1222
- exitCode
1223
- );
1224
- }
1225
- function httpStatusToErrorType(status) {
1226
- if (status === 400) return "bad_request";
1227
- if (status === 401) return "unauthorized";
1228
- if (status === 402) return "payment_required";
1229
- if (status === 403) return "forbidden";
1230
- if (status === 404) return "not_found";
1231
- if (status === 409) return "conflict";
1232
- if (status === 413) return "payload_too_large";
1233
- if (status === 422) return "unprocessable_entity";
1234
- if (status === 429) return "too_many_requests";
1235
- return "internal_error";
1236
- }
1237
- async function tryParseApiError(res) {
1238
- try {
1239
- const json = await res.clone().json();
1240
- const parsed = ApiErrorSchema.safeParse(json);
1241
- return parsed.success ? parsed.data : null;
1242
- } catch {
1243
- return null;
1244
- }
1245
- }
1246
- async function tryParsePlanGate(res) {
1247
- try {
1248
- const json = await res.clone().json();
1249
- const parsed = WikiPlanRequiredSchema.safeParse(json);
1250
- return parsed.success ? parsed.data : null;
1251
- } catch {
1252
- return null;
1253
- }
1254
- }
1255
- function planGateError(gate, requestId) {
1256
- const actionUrl = gate.action_url ?? null;
1257
- return new TiroError(
1258
- {
1259
- // Relay the backend's discriminator (WIKI_PLAN_REQUIRED / WIKI_NOT_ACTIVATED) verbatim.
1260
- code: gate.error_code,
1261
- message: gate.message,
1262
- errorType: "payment_required",
1263
- httpStatus: 402,
1264
- ...actionUrl ? { suggestion: `Upgrade: ${actionUrl}` } : {},
1265
- ...requestId !== void 0 && { requestId },
1266
- details: { ...gate }
1267
- },
1268
- ExitCode.Generic
1269
- );
1270
- }
1271
- function buildApiUrl(hostname, path, params) {
1272
- if (!path.startsWith("/") || path.startsWith("//") || path.startsWith("/\\")) {
1273
- throw new TiroError(
1274
- {
1275
- code: "internal_error",
1276
- message: `API path must start with a single "/": got ${JSON.stringify(path)}`,
1277
- errorType: "internal_error"
1278
- },
1279
- ExitCode.Generic
1280
- );
1281
- }
1282
- const u = new URL(`${hostname}${path}`);
1283
- if (params) {
1284
- for (const [k, v] of Object.entries(params)) {
1285
- if (v !== void 0 && v !== null && v !== "") {
1286
- u.searchParams.set(k, String(v));
1287
- }
1288
- }
1289
- }
1290
- return u.toString();
1291
- }
1292
- function createApiClient(opts = {}) {
1293
- if (opts.tokenOverride) {
1294
- return new TiroApiClient(getHostname(opts.hostnameOverride), opts.tokenOverride);
1295
- }
1296
- const t = resolveToken();
1297
- if (!t) throw authRequired();
1298
- const hostname = getHostname(opts.hostnameOverride ?? t.hostname);
1299
- return new TiroApiClient(hostname, t.accessToken);
1300
- }
1301
-
1302
- // src/lib/util/parseDate.ts
1303
- var RELATIVE_RE = /^(\d+)([smhdw])$/i;
1304
- var UNIT_MS = {
1305
- s: 1e3,
1306
- m: 6e4,
1307
- h: 36e5,
1308
- d: 864e5,
1309
- w: 6048e5
1310
- };
1311
- function parseDate(input) {
1312
- const trimmed = input.trim();
1313
- const rel = trimmed.match(RELATIVE_RE);
1314
- if (rel) {
1315
- const num = parseInt(rel[1] ?? "", 10);
1316
- const unit = (rel[2] ?? "").toLowerCase();
1317
- const factor = UNIT_MS[unit];
1318
- if (!factor || !Number.isFinite(num)) {
1319
- throw invalidDate(input);
1320
- }
1321
- return new Date(Date.now() - num * factor).toISOString();
1322
- }
1323
- const d = new Date(trimmed);
1324
- if (Number.isNaN(d.getTime())) throw invalidDate(input);
1325
- return d.toISOString();
1326
- }
1327
- function invalidDate(input) {
1328
- return new TiroError(
1329
- {
1330
- code: "invalid_date",
1331
- message: `Invalid date: "${input}". Use ISO-8601 (e.g. 2026-04-01T10:00:00Z) or relative (e.g. 7d, 24h, 30m).`,
1332
- errorType: "bad_request"
1333
- },
1334
- ExitCode.Usage
1335
- );
1336
- }
1337
-
1338
- // src/lib/util/noteFilter.ts
1339
- var PLACEHOLDER_TITLE = "Untitled";
1340
- var PLACEHOLDER_SOURCE_TYPES = /* @__PURE__ */ new Set(["onboarding"]);
1341
- function isVisibleNote(note) {
1342
- if (note.title === PLACEHOLDER_TITLE) return false;
1343
- if (note.sourceType !== null && note.sourceType !== void 0 && PLACEHOLDER_SOURCE_TYPES.has(note.sourceType)) {
1344
- return false;
1345
- }
1346
- return true;
1347
- }
1348
-
1349
- // src/commands/notes/list.ts
1350
- var ListResponseSchema = PageCursorResponseSchema(NoteSchema);
1351
- var DEFAULT_PAGE_SIZE = 100;
1352
- var MAX_PAGE_SIZE = 1e3;
1353
- var HELP_AFTER = `
95
+ </html>`}import dt from"open";async function Ie(e){try{await dt(e,{wait:!1})}catch{}}import{Entry as se}from"@napi-rs/keyring";var ae="io.tiro.cli",ce="default";function Oe(e){let A=new se(ae,ce);try{A.setPassword(JSON.stringify(e))}catch(t){throw new u({code:"keychain_write_failed",message:`Failed to write to OS keychain: ${t.message}`,errorType:"internal_error",suggestion:process.platform==="linux"?"Linux requires a Secret Service daemon (gnome-keyring or kwallet). Or set TIRO_TOKEN env var.":"Check OS keychain permissions, or set TIRO_TOKEN env var."},d.Generic)}}function Pe(){let e=new se(ae,ce),A;try{A=e.getPassword()}catch{return null}if(!A)return null;try{return JSON.parse(A)}catch{return null}}function Xe(){let e=new se(ae,ce);try{return e.deletePassword()}catch{return!1}}function K(){let e=process.env.TIRO_TOKEN;if(e)return{accessToken:e,source:"env"};let A=Pe();return A?{accessToken:A.accessToken,source:"keychain",hostname:A.hostname,expiresAt:A.expiresAt,...A.userId!==void 0&&{userId:A.userId}}:null}function Z(e){let A=e.split(".");if(A.length!==3)return null;try{let t=A[1];if(!t)return null;let r=Buffer.from(t,"base64url").toString("utf8");return JSON.parse(r)}catch{return null}}import ut from"conf";var lt="https://api.tiro.ooo",mt=new Set(["localhost","127.0.0.1","[::1]","::1"]),T=new ut({projectName:"tiro",defaults:{hostname:lt,oauthClientId:null,oauthClientIdRegisteredAt:null,oauthClientHostname:null,oauthClientRedirectUri:null,defaultOutputDir:null}});function pe(e){let A=e.trim();if(A==="")throw F("empty hostname",e);let t;try{t=new URL(A)}catch{throw F("not a valid URL",e)}if(t.protocol!=="https:"){if(!(t.protocol==="http:"&&gt(t.hostname)))throw F(`disallowed scheme "${t.protocol}" \u2014 only https:// or http://localhost is permitted`,e)}if(t.username!==""||t.password!=="")throw F("URL must not embed credentials",e);if(t.search!==""||t.hash!=="")throw F("URL must not include query or fragment",e);if(t.pathname!==""&&t.pathname!=="/")throw F("URL must be host root (no path segment)",e);let r=t.origin;return ht(r)}function gt(e){return e.startsWith("[")&&e.endsWith("]")&&(e=e.slice(1,-1)),mt.has(e)}function F(e,A){return new u({code:"invalid_hostname",message:`Refusing to use hostname "${A}": ${e}.`,errorType:"bad_request",suggestion:"Use https://<host> (or http://localhost for local dev). If TIRO_HOSTNAME is set in your environment, unset it."},d.Usage)}function P(e){if(e!==void 0)return pe(e);let A=process.env.TIRO_HOSTNAME;return pe(A||T.get("hostname"))}function Se(e,A){let t=T.get("oauthClientId"),r=T.get("oauthClientIdRegisteredAt"),o=T.get("oauthClientHostname"),i=T.get("oauthClientRedirectUri");if(!t||!r||o!==e||!i||!ft(i,A))return null;let s=696*60*60*1e3;return Date.now()-r>s?null:t}function Fe(e,A,t){T.set("oauthClientId",e),T.set("oauthClientIdRegisteredAt",Date.now()),T.set("oauthClientHostname",A),T.set("oauthClientRedirectUri",t)}function J(){T.set("oauthClientId",null),T.set("oauthClientIdRegisteredAt",null),T.set("oauthClientHostname",null),T.set("oauthClientRedirectUri",null)}function ft(e,A){let t,r;try{t=new URL(e),r=new URL(A)}catch{return!1}return t.protocol===r.protocol&&t.hostname===r.hostname&&t.pathname===r.pathname}function ht(e){return e.endsWith("/")?e.slice(0,-1):e}var wt=L.object({client_id:L.string(),client_secret:L.string().optional()}),yt=L.object({access_token:L.string(),token_type:L.string(),expires_in:L.number().optional(),scope:L.string().optional()}),bt=300*1e3,De="mcp:notes:read";async function qe(e={}){let A=P(e.hostname),t=e.onPrompt??(o=>process.stderr.write(`${o}
96
+ `)),r=await Re();try{let o=await kt(A,r.redirectUri),{codeVerifier:i,codeChallenge:s}=Ce(),c=ve(),l=Ct({hostname:A,clientId:o,redirectUri:r.redirectUri,state:c,codeChallenge:s,scope:e.scope??De});e.noBrowser?t(`Open this URL in your browser:
97
+ ${l}`):(t("Opening browser for sign-in..."),t(`If the browser does not open, visit:
98
+ ${l}`),await Ie(l));let p=await r.waitForCallback(bt);if(!xe(p.state,c))throw new u({code:"auth_state_mismatch",message:"OAuth state mismatch \u2014 possible CSRF. Aborting.",errorType:"unauthorized"},d.Generic);let m=await vt({hostname:A,clientId:o,code:p.code,redirectUri:r.redirectUri,codeVerifier:i}),w=xt(m.expires_in),y=Z(m.access_token),h=typeof y?.sub=="string"?y.sub:void 0,x={accessToken:m.access_token,tokenType:m.token_type,expiresAt:w,hostname:A,...m.scope!==void 0&&{scope:m.scope},...h!==void 0&&{userId:h}};return Oe(x),{hostname:A,userId:h,expiresAt:w}}finally{r.close()}}async function kt(e,A){let t=Se(e,A);if(t)return t;let r=`${e}/v1/mcp/oauth/register`,o;try{o=await fetch(r,{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify({client_name:"tiro-cli",redirect_uris:[A],grant_types:["authorization_code"],response_types:["code"],token_endpoint_auth_method:"none",scope:De})})}catch(c){throw new u({code:"network_error",message:`Failed to reach ${e}: ${c.message}`,errorType:"network_error",suggestion:"Check your network connection or --hostname."},d.Generic)}if(!o.ok){let c=await Me(o);throw new u({code:"oauth_register_failed",message:`Dynamic Client Registration failed: HTTP ${o.status}`,errorType:"internal_error",httpStatus:o.status,...c!==""&&{suggestion:c.slice(0,200)}},d.Generic)}let i=await o.json(),s=wt.safeParse(i);if(!s.success)throw new u({code:"oauth_register_invalid",message:"Registration response did not match expected shape.",errorType:"internal_error"},d.Generic);return Fe(s.data.client_id,e,A),s.data.client_id}function Ct(e){let A=new URL(`${e.hostname}/v1/mcp/oauth/authorize`);return A.searchParams.set("response_type","code"),A.searchParams.set("client_id",e.clientId),A.searchParams.set("redirect_uri",e.redirectUri),A.searchParams.set("state",e.state),A.searchParams.set("code_challenge",e.codeChallenge),A.searchParams.set("code_challenge_method","S256"),A.searchParams.set("scope",e.scope),A.toString()}async function vt(e){let A=`${e.hostname}/v1/mcp/oauth/token`,t=new URLSearchParams({grant_type:"authorization_code",code:e.code,redirect_uri:e.redirectUri,client_id:e.clientId,code_verifier:e.codeVerifier}),r;try{r=await fetch(A,{method:"POST",headers:{"Content-Type":"application/x-www-form-urlencoded"},body:t.toString()})}catch(s){throw new u({code:"network_error",message:`Failed to reach ${e.hostname}: ${s.message}`,errorType:"network_error"},d.Generic)}if(!r.ok){(r.status===400||r.status===401)&&J();let s=await Me(r);throw new u({code:"oauth_token_failed",message:`Token exchange failed: HTTP ${r.status}`,errorType:"unauthorized",httpStatus:r.status,...s!==""&&{suggestion:s.slice(0,200)}},d.AuthRequired)}let o=await r.json(),i=yt.safeParse(o);if(!i.success)throw new u({code:"oauth_token_invalid",message:"Token response did not match expected shape.",errorType:"internal_error"},d.Generic);return i.data}function xt(e){let t=e??15552e3;return Date.now()+t*1e3}async function Me(e){try{return await e.text()}catch{return""}}function He(e){e.command("login").description("Sign in to Tiro via OAuth (browser-based, PKCE)").option("--hostname <url>","API base URL (overrides config / TIRO_HOSTNAME)").option("--no-browser","Print the URL instead of opening a browser").action(async(A,t)=>{let r=t.optsWithGlobals(),o=await qe({...A.hostname!==void 0&&{hostname:A.hostname},noBrowser:A.noBrowser===!0,onPrompt:c=>{r.quiet||process.stderr.write(`${a(c,"cyan",r)}
99
+ `)}}),i=P(A.hostname),s=new Date(o.expiresAt).toISOString();r.json?C({ok:!0,data:{signedIn:!0,hostname:i,userId:o.userId??null,expiresAt:s}},r):r.quiet||(process.stderr.write(`${a("\u2713","green",r)} Signed in to ${i}
100
+ `),o.userId&&process.stderr.write(` user: ${o.userId}
101
+ `),process.stderr.write(` token expires: ${s}
102
+ `))})}import"commander";import"zod";import{z as n}from"zod";var Tt=n.object({guid:n.string(),name:n.string(),email:n.string(),role:n.enum(["OWNER","EDITOR","VIEWER"])}),Lt=n.object({name:n.string().nullable().optional(),email:n.string().nullable().optional()}),B=n.object({guid:n.string(),title:n.string(),createdAt:n.string(),updatedAt:n.string(),sourceType:n.string(),recordingDurationSeconds:n.number(),collaborators:n.array(Tt).optional().default([]),participants:n.array(Lt).optional().default([]),webUrl:n.string(),recordingStartAt:n.string().nullable().optional(),recordingEndAt:n.string().nullable().optional()}).passthrough(),Bt=n.object({type:n.string(),content:n.string()}),Rt=n.object({label:n.string(),personName:n.string().nullable().optional()}),Et=n.object({content:n.string(),speaker:Rt}),D=n.object({uuid:n.string(),transcribeLocale:n.string().nullable().optional(),transcript:Bt.nullable().optional(),diarizedSegments:n.array(Et).nullable().optional(),timeFrom:n.string().nullable().optional(),timeTo:n.string().nullable().optional(),locked:n.boolean().optional()}).passthrough(),It=n.object({content:n.string(),speaker:n.object({label:n.string(),name:n.string().nullable()}).nullable()}),Ot=n.object({timeFrom:n.string().nullable(),timeTo:n.string().nullable(),segments:n.array(It)}),xn=n.object({noteGuid:n.string(),title:n.string(),participants:n.array(n.string()),createdAt:n.string(),recordingDurationSeconds:n.number(),paragraphs:n.array(Ot)}),R=e=>n.object({content:n.array(e),nextCursor:n.string().nullable()}),q=e=>n.object({content:n.array(e)}),We=n.object({error:n.object({code:n.number(),errorType:n.string(),message:n.string(),detail:n.string().nullable().optional()})}),Ne=n.object({guid:n.string()}).passthrough(),Pt=n.object({guid:n.string(),name:n.string(),isWikiEnabled:n.boolean()}).passthrough(),Ge=n.object({workspaces:n.array(Pt)}).passthrough(),Ve=n.object({workspaceGuid:n.string().nullable(),userId:n.number().nullable().optional(),apiKeyName:n.string().nullable().optional()}).passthrough(),Xt=n.object({guid:n.string(),wikiId:n.number(),canonicalName:n.string(),pageType:n.string(),entitySubtype:n.string().nullable().optional(),score:n.number()}).passthrough(),Ue=n.object({items:n.array(Xt)}).passthrough(),je=n.object({guid:n.string(),noteId:n.number(),paragraphId:n.number().nullable().optional(),paragraphUuid:n.string().nullable().optional(),kind:n.string(),sourceUserId:n.number(),extractedText:n.string(),confidence:n.number().nullable().optional(),createdAt:n.string()}).passthrough(),St=n.object({guid:n.string(),alias:n.string(),source:n.string(),sourceMentionGuid:n.string().nullable().optional(),sourceUserId:n.number().nullable().optional(),createdAt:n.string()}).passthrough(),Ft=n.object({guid:n.string(),sourcePageGuid:n.string(),sourcePageName:n.string().nullable().optional(),targetPageGuid:n.string(),targetPageName:n.string().nullable().optional(),linkType:n.string(),linkTypeDisplayKo:n.string().optional(),linkTypeDisplayEn:n.string().optional(),isDirectional:n.boolean(),source:n.string().optional(),creatorUserId:n.number().nullable().optional(),createdAt:n.string().optional(),updatedAt:n.string().optional()}).passthrough(),Qe=n.object({guid:n.string(),wikiId:n.number(),canonicalName:n.string(),description:n.string().nullable().optional(),descriptionStatus:n.string().nullable().optional(),regenerationAvailable:n.boolean().nullable().optional(),pageType:n.string(),entitySubtype:n.string().nullable().optional(),extractionStatus:n.string(),mentionCountVisible:n.number(),mentions:n.array(je),aliases:n.array(St),links:n.array(Ft),lastUpdatedVisible:n.string().nullable().optional(),createdAt:n.string(),updatedAt:n.string()}).passthrough(),ze=n.object({items:n.array(je),nextCursorCreatedAt:n.string().nullable(),nextCursorId:n.number().nullable()}).passthrough(),Dt=n.object({guid:n.string(),canonicalName:n.string(),pageType:n.string(),entitySubtype:n.string().nullable().optional(),extractionStatus:n.string(),mentionCountVisible:n.number()}).passthrough(),qt=n.object({guid:n.string(),sourcePageGuid:n.string(),targetPageGuid:n.string(),linkType:n.string(),linkTypeDisplayKo:n.string().optional(),linkTypeDisplayEn:n.string().optional(),isDirectional:n.boolean()}).passthrough(),V=n.object({nodes:n.array(Dt),edges:n.array(qt)}).passthrough(),Ye=n.object({error_code:n.enum(["WIKI_PLAN_REQUIRED","WIKI_NOT_ACTIVATED"]),message:n.string(),current_plan:n.string().nullable().optional(),required_plans:n.array(n.string()).nullable().optional(),action_url:n.string().nullable().optional()}).passthrough(),Ke=n.object({id:n.string(),workspaceGuid:n.string(),title:n.string(),description:n.string(),color:n.string(),sharingType:n.string(),parentId:n.string().nullable().optional(),isTeamFolder:n.boolean(),createdAt:n.string(),updatedAt:n.string()}).passthrough(),de=n.lazy(()=>n.object({id:n.string(),title:n.string(),parentId:n.string().nullable().optional(),depth:n.number(),isAccessible:n.boolean(),children:n.array(de)})),Ze=n.object({id:n.number(),entry:n.string(),createdAt:n.string()}).passthrough();var $=class{constructor(A,t){this.hostname=A;this.token=t}hostname;token;async getJson(A,t,r){let o=this.buildUrl(A,r),i=await this.fetch(o,{method:"GET"});return this.parseJson(i,t,"GET",A)}async postJson(A,t,r){let o=this.buildUrl(A),i=await this.fetch(o,{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify(r)});return this.parseJson(i,t,"POST",A)}async putJson(A,t,r){let o=this.buildUrl(A),i=await this.fetch(o,{method:"PUT",headers:{"Content-Type":"application/json"},body:JSON.stringify(r)});return this.parseJson(i,t,"PUT",A)}async deleteVoid(A){let t=this.buildUrl(A),r=await this.fetch(t,{method:"DELETE"});if(!r.ok)throw await Je(r,"DELETE",A)}buildUrl(A,t){return Gt(this.hostname,A,t)}async fetch(A,t){let r=new Headers(t.headers);r.set("Authorization",`Bearer ${this.token}`),r.set("Accept","application/json");try{return await fetch(A,{...t,headers:r})}catch(o){throw new u({code:"network_error",message:`Network error reaching ${this.hostname}: ${o.message}`,errorType:"network_error",suggestion:"Check your network or --hostname."},d.Generic)}}async parseJson(A,t,r,o){if(!A.ok)throw await Je(A,r,o);let i;try{i=await A.json()}catch(c){throw new u({code:"invalid_response",message:`Failed to parse JSON from ${r} ${o}: ${c.message}`,errorType:"internal_error"},d.Generic)}let s=t.safeParse(i);if(!s.success)throw new u({code:"schema_mismatch",message:`Response shape did not match expected schema (${r} ${o}).`,errorType:"internal_error",suggestion:s.error.issues.slice(0,3).map(c=>`${c.path.join(".")||"(root)"}: ${c.message}`).join("; ")},d.Generic);return s.data}};async function Je(e,A,t){let r=e.headers.get("x-request-id")??void 0,o=e.status===401?d.AuthRequired:d.Generic;if(e.status===402){let s=await Wt(e);if(s)return Nt(s,r)}let i=await Ht(e);return i?new u({code:`${i.error.errorType}`,message:i.error.message,errorType:i.error.errorType,httpStatus:e.status,...r!==void 0&&{requestId:r},...e.status===401&&{suggestion:"Run `tiro auth login` to refresh."}},o):new u({code:"http_error",message:`${A} ${t} failed: HTTP ${e.status} ${e.statusText}`,errorType:Mt(e.status),httpStatus:e.status,...r!==void 0&&{requestId:r}},o)}function Mt(e){return e===400?"bad_request":e===401?"unauthorized":e===402?"payment_required":e===403?"forbidden":e===404?"not_found":e===409?"conflict":e===413?"payload_too_large":e===422?"unprocessable_entity":e===429?"too_many_requests":"internal_error"}async function Ht(e){try{let A=await e.clone().json(),t=We.safeParse(A);return t.success?t.data:null}catch{return null}}async function Wt(e){try{let A=await e.clone().json(),t=Ye.safeParse(A);return t.success?t.data:null}catch{return null}}function Nt(e,A){let t=e.action_url??null;return new u({code:e.error_code,message:e.message,errorType:"payment_required",httpStatus:402,...t?{suggestion:`Upgrade: ${t}`}:{},...A!==void 0&&{requestId:A},details:{...e}},d.Generic)}function Gt(e,A,t){if(!A.startsWith("/")||A.startsWith("//")||A.startsWith("/\\"))throw new u({code:"internal_error",message:`API path must start with a single "/": got ${JSON.stringify(A)}`,errorType:"internal_error"},d.Generic);let r=new URL(`${e}${A}`);if(t)for(let[o,i]of Object.entries(t))i!=null&&i!==""&&r.searchParams.set(o,String(i));return r.toString()}function k(e={}){if(e.tokenOverride)return new $(P(e.hostnameOverride),e.tokenOverride);let A=K();if(!A)throw G();let t=P(e.hostnameOverride??A.hostname);return new $(t,A.accessToken)}var $e=new WeakMap;async function E(e){let A=$e.get(e);if(A)return A;let t=e.getJson("/v1/external/workspaces/me",Ne).then(r=>r.guid);return $e.set(e,t),t}async function _e(e){return(await e.getJson("/v1/external/workspaces",Ge)).workspaces}async function ue(e){return e.getJson("/v1/external/auth/me",Ve)}async function U(e,A){return A||(await ue(e)).workspaceGuid}var _="Credential is not bound to a workspace; listing across all your workspaces. Pass --workspace <guid> (see `tiro wiki workspaces`) or use a workspace-scoped API key to target one.";async function M(e,A){let t=await U(e,A);if(!t)throw new u({code:"workspace_required",message:"This command targets a single workspace, but your credential is not bound to one.",errorType:"bad_request",suggestion:"Pass --workspace <guid> (run `tiro wiki workspaces` for guids) or use a workspace-scoped API key."},d.Usage);return t}function eA(e){e.command("status").description("Show current authenticated account and scopes").action(async(A,t)=>{let r=t.optsWithGlobals(),o=K();if(!o)throw G();let i=Z(o.accessToken),s=typeof i?.sub=="string"?i.sub:null,c=typeof i?.exp=="number"?i.exp*1e3:null,l=typeof i?.scope=="string"?i.scope:null,p=c??o.expiresAt??null,m=p!==null&&Date.now()>=p,w=null,y=!1;if(!m)try{let x=k({tokenOverride:o.accessToken,hostnameOverride:r.hostname??o.hostname??void 0});w=(await ue(x)).workspaceGuid,y=!0}catch{}let h={signedIn:!0,source:o.source,hostname:o.hostname??null,userId:o.userId??s,scope:l,...y&&{workspace:w},expiresAt:p?new Date(p).toISOString():null,expired:m,tokenPrefix:`${o.accessToken.slice(0,4)}...***`};if(r.json||!process.stdout.isTTY)C({ok:!0,data:h},r);else{let x=m?a("!","yellow",r):a("\u2713","green",r),N=m?"Token expired":"Signed in";if(process.stdout.write(`${x} ${N}
103
+ `),process.stdout.write(` source: ${h.source}
104
+ `),h.hostname&&process.stdout.write(` hostname: ${h.hostname}
105
+ `),h.userId&&process.stdout.write(` user: ${h.userId}
106
+ `),h.scope&&process.stdout.write(` scope: ${h.scope}
107
+ `),y?process.stdout.write(` workspace: ${w??a("(unbound \u2014 across all workspaces)","gray",r)}
108
+ `):m||process.stdout.write(` workspace: ${a("(unable to verify)","yellow",r)}
109
+ `),h.expiresAt){let oe=m?a(" (expired)","red",r):"";process.stdout.write(` expires at: ${h.expiresAt}${oe}
110
+ `)}process.stdout.write(` token: ${h.tokenPrefix}
111
+ `),m&&process.stdout.write(`
112
+ ${a("\u2192","gray",r)} Run \`tiro auth login\` to refresh.
113
+ `)}})}import"commander";function AA(e){e.command("logout").description("Sign out and clear the stored token").action(async(A,t)=>{let r=t.optsWithGlobals(),o=Xe();J(),r.json?C({ok:!0,data:{signedOut:!0,hadToken:o}},r):r.quiet||(o?process.stderr.write(`${a("\u2713","green",r)} Signed out
114
+ `):process.stderr.write(`${a("\u2022","gray",r)} No token was stored
115
+ `))})}function tA(e){let A=e.command("auth").description("Manage authentication");He(A),eA(A),AA(A)}import"commander";import"commander";var Vt=/^(\d+)([smhdw])$/i,Ut={s:1e3,m:6e4,h:36e5,d:864e5,w:6048e5};function I(e){let A=e.trim(),t=A.match(Vt);if(t){let o=parseInt(t[1]??"",10),i=(t[2]??"").toLowerCase(),s=Ut[i];if(!s||!Number.isFinite(o))throw rA(e);return new Date(Date.now()-o*s).toISOString()}let r=new Date(A);if(Number.isNaN(r.getTime()))throw rA(e);return r.toISOString()}function rA(e){return new u({code:"invalid_date",message:`Invalid date: "${e}". Use ISO-8601 (e.g. 2026-04-01T10:00:00Z) or relative (e.g. 7d, 24h, 30m).`,errorType:"bad_request"},d.Usage)}var jt="Untitled",Qt=new Set(["onboarding"]);function ee(e){return!(e.title===jt||e.sourceType!==null&&e.sourceType!==void 0&&Qt.has(e.sourceType))}var zt=R(B),oA=100,nA=200,Yt=`
1354
116
  Examples:
1355
117
  tiro notes list --since 7d
1356
118
  tiro notes list --keyword "OKR" --since 30d --json
@@ -1366,101 +128,12 @@ Keyword matching:
1366
128
  Note: placeholder notes (title='Untitled' or sourceType='onboarding') are
1367
129
  filtered out by default. A page of N may return fewer than N visible notes \u2014
1368
130
  keep paginating to fetch more, or pass --include-untitled to surface them.
1369
- `;
1370
- function registerNotesList(parent) {
1371
- parent.command("list").description("List notes (lightweight metadata).").option("--keyword <text>", 'Reorder by full-text relevance for this keyword (e.g. "OKR")').option("--folder <id>", "Restrict to a folder and its descendants").option(
1372
- "--since <date>",
1373
- "Inclusive lower bound on createdAt (ISO-8601 or relative: 7d, 24h, 30m)"
1374
- ).option("--until <date>", "Exclusive upper bound on createdAt").option(
1375
- "--limit <n>",
1376
- `Max results per page (default ${DEFAULT_PAGE_SIZE}, max ${MAX_PAGE_SIZE})`
1377
- ).option("--cursor <token>", "Continue a previous page").option(
1378
- "--include-untitled",
1379
- "Include placeholder notes (title='Untitled' or sourceType='onboarding'). Default: hidden",
1380
- false
1381
- ).addHelpText("after", HELP_AFTER).action(async (opts, cmd) => {
1382
- const globalOpts = cmd.optsWithGlobals();
1383
- const client = createApiClient({
1384
- ...globalOpts.hostname !== void 0 && { hostnameOverride: globalOpts.hostname }
1385
- });
1386
- const params = {};
1387
- if (opts.keyword) params["keyword"] = opts.keyword;
1388
- if (opts.folder) params["folderId"] = opts.folder;
1389
- if (opts.since) params["createdAtFrom"] = parseDate(opts.since);
1390
- if (opts.until) params["createdAtTo"] = parseDate(opts.until);
1391
- const size = clampLimit(opts.limit);
1392
- if (size !== void 0) params["size"] = size;
1393
- if (opts.cursor) params["cursor"] = opts.cursor;
1394
- const res = await client.getJson("/v1/external/notes", ListResponseSchema, params);
1395
- const visible = opts.includeUntitled === true ? res.content : res.content.filter(isVisibleNote);
1396
- const mode = resolveOutputMode(globalOpts);
1397
- if (mode === "json") {
1398
- for (const note of visible) printNdjson(note);
1399
- if (res.nextCursor) printNdjson({ _cursor: res.nextCursor });
1400
- } else {
1401
- printPretty(visible, res.nextCursor, globalOpts);
1402
- }
1403
- });
1404
- }
1405
- function clampLimit(raw) {
1406
- if (!raw) return void 0;
1407
- const n = parseInt(raw, 10);
1408
- if (!Number.isFinite(n) || n <= 0) return DEFAULT_PAGE_SIZE;
1409
- return Math.min(n, MAX_PAGE_SIZE);
1410
- }
1411
- function printPretty(notes, nextCursor2, opts) {
1412
- if (notes.length === 0) {
1413
- process.stdout.write(`${color("(no notes)", "gray", opts)}
1414
- `);
1415
- return;
1416
- }
1417
- const titleWidth = computeTitleWidth();
1418
- for (const n of notes) {
1419
- const date = n.createdAt.slice(0, 10);
1420
- const dur = formatDuration(n.recordingDurationSeconds);
1421
- const title = truncate(n.title, titleWidth);
1422
- process.stdout.write(
1423
- `${color(date, "gray", opts)} ${color(n.guid, "dim", opts)} ${color(dur, "cyan", opts)} ${title}
1424
- `
1425
- );
1426
- }
1427
- if (nextCursor2) {
1428
- process.stdout.write(
1429
- `${color(`
1430
- next: --cursor ${nextCursor2}`, "gray", opts)}
1431
- `
1432
- );
1433
- }
1434
- }
1435
- function computeTitleWidth() {
1436
- const cols = process.stdout.columns;
1437
- if (!cols || cols < 60) return 40;
1438
- return Math.max(20, cols - 60);
1439
- }
1440
- function truncate(s, max) {
1441
- if (s.length <= max) return s;
1442
- return s.slice(0, Math.max(0, max - 1)) + "\u2026";
1443
- }
1444
- function formatDuration(sec) {
1445
- if (!sec || sec <= 0) return "\u2014";
1446
- const m = Math.floor(sec / 60);
1447
- const s = Math.floor(sec % 60);
1448
- if (m > 0) return `${m}m${s.toString().padStart(2, "0")}s`;
1449
- return `${s}s`;
1450
- }
1451
-
1452
- // src/commands/notes/search.ts
1453
- import "commander";
1454
- import { z as z4 } from "zod";
1455
- var SearchResponseSchema = z4.object({
1456
- notes: z4.array(NoteSchema),
1457
- nextCursor: z4.string().nullable(),
1458
- degraded: z4.boolean().optional(),
1459
- degradedReason: z4.string().nullable().optional()
1460
- }).passthrough();
1461
- var DEFAULT_PAGE_SIZE2 = 100;
1462
- var MAX_PAGE_SIZE2 = 1e3;
1463
- var HELP_AFTER2 = `
131
+ `;function iA(e){e.command("list").description("List notes (lightweight metadata).").option("--keyword <text>",'Reorder by full-text relevance for this keyword (e.g. "OKR")').option("--folder <id>","Restrict to a folder and its descendants").option("--since <date>","Inclusive lower bound on createdAt (ISO-8601 or relative: 7d, 24h, 30m)").option("--until <date>","Exclusive upper bound on createdAt").option("--limit <n>",`Max results per page (default ${oA}, max ${nA})`).option("--cursor <token>","Continue a previous page").option("--workspace <guid>","List within one workspace (see `tiro wiki workspaces`). Default: the workspace your API key is bound to, else across all your workspaces").option("--include-untitled","Include placeholder notes (title='Untitled' or sourceType='onboarding'). Default: hidden",!1).addHelpText("after",Yt).action(async(A,t)=>{let r=t.optsWithGlobals(),o=k({...r.hostname!==void 0&&{hostnameOverride:r.hostname}}),i={};A.keyword&&(i.keyword=A.keyword),A.folder&&(i.folderId=A.folder),A.since&&(i.createdAtFrom=I(A.since)),A.until&&(i.createdAtTo=I(A.until));let s=Kt(A.limit);s!==void 0&&(i.size=s),A.cursor&&(i.cursor=A.cursor);let c=await U(o,A.workspace);!c&&r.quiet!==!0&&process.stderr.write(`${a("\u26A0","yellow",r)} ${_}
132
+ `);let l=c?`/v1/external/workspaces/${encodeURIComponent(c)}/notes`:"/v1/external/notes",p=await o.getJson(l,zt,i),m=A.includeUntitled===!0?p.content:p.content.filter(ee);if(b(r)==="json"){for(let y of m)v(y);p.nextCursor&&v({_cursor:p.nextCursor})}else Zt(m,p.nextCursor,r)})}function Kt(e){if(!e)return;let A=parseInt(e,10);return!Number.isFinite(A)||A<=0?oA:Math.min(A,nA)}function Zt(e,A,t){if(e.length===0){process.stdout.write(`${a("(no notes)","gray",t)}
133
+ `);return}let r=Jt();for(let o of e){let i=o.createdAt.slice(0,10),s=_t(o.recordingDurationSeconds),c=$t(o.title,r);process.stdout.write(`${a(i,"gray",t)} ${a(o.guid,"dim",t)} ${a(s,"cyan",t)} ${c}
134
+ `)}A&&process.stdout.write(`${a(`
135
+ next: --cursor ${A}`,"gray",t)}
136
+ `)}function Jt(){let e=process.stdout.columns;return!e||e<60?40:Math.max(20,e-60)}function $t(e,A){return e.length<=A?e:e.slice(0,Math.max(0,A-1))+"\u2026"}function _t(e){if(!e||e<=0)return"\u2014";let A=Math.floor(e/60),t=Math.floor(e%60);return A>0?`${A}m${t.toString().padStart(2,"0")}s`:`${t}s`}import"commander";import{z as j}from"zod";var er=j.object({notes:j.array(B),nextCursor:j.string().nullable(),degraded:j.boolean().optional(),degradedReason:j.string().nullable().optional()}).passthrough(),sA=100,aA=200,Ar=`
1464
137
  Examples:
1465
138
  tiro notes search "Q3 Planning"
1466
139
  tiro notes search "Acme Corp" --since 7d --json
@@ -1480,344 +153,25 @@ Ordering:
1480
153
 
1481
154
  Note: placeholder notes (title='Untitled' or sourceType='onboarding') are
1482
155
  filtered out by default. Pass --include-untitled to surface them.
1483
- `;
1484
- function registerNotesSearch(parent) {
1485
- parent.command("search [keyword]").description("Deep keyword search \u2014 returns notes hydrated with their primary documents.").option(
1486
- "--keyword <text>",
1487
- 'Alternative to positional keyword (e.g. --keyword "Q3 Planning")'
1488
- ).option("--folder <id>", "Restrict hits to a folder and its descendants").option(
1489
- "--since <date>",
1490
- "Inclusive lower bound on createdAt (ISO-8601 or relative: 7d, 24h, 30m)"
1491
- ).option("--until <date>", "Exclusive upper bound on createdAt").option(
1492
- "--limit <n>",
1493
- `Max results per page (default ${DEFAULT_PAGE_SIZE2}, max ${MAX_PAGE_SIZE2})`
1494
- ).option(
1495
- "--cursor <token>",
1496
- "Continue a previous page (reserved \u2014 backend currently always null)"
1497
- ).option(
1498
- "--include-untitled",
1499
- "Include placeholder notes. Default: hidden",
1500
- false
1501
- ).addHelpText("after", HELP_AFTER2).action(async (positional, opts, cmd) => {
1502
- const globalOpts = cmd.optsWithGlobals();
1503
- const keyword = (positional ?? opts.keyword ?? "").trim();
1504
- if (!keyword) {
1505
- throw new TiroError(
1506
- {
1507
- code: "missing_keyword",
1508
- message: "search requires a keyword (positional or --keyword).",
1509
- errorType: "bad_request",
1510
- suggestion: 'tiro notes search "OKR"'
1511
- },
1512
- ExitCode.Usage
1513
- );
1514
- }
1515
- const filter = {};
1516
- if (opts.folder) filter["folderId"] = opts.folder;
1517
- if (opts.since) filter["createdAtFrom"] = parseDate(opts.since);
1518
- if (opts.until) filter["createdAtTo"] = parseDate(opts.until);
1519
- const pagination = {};
1520
- const size = clampLimit2(opts.limit);
1521
- if (size !== void 0) pagination["size"] = size;
1522
- if (opts.cursor) pagination["cursor"] = opts.cursor;
1523
- const body = { keyword };
1524
- if (Object.keys(filter).length > 0) body["filter"] = filter;
1525
- if (Object.keys(pagination).length > 0) body["pagination"] = pagination;
1526
- const client = createApiClient({
1527
- ...globalOpts.hostname !== void 0 && { hostnameOverride: globalOpts.hostname }
1528
- });
1529
- const res = await client.postJson(
1530
- "/v1/external/notes/search",
1531
- SearchResponseSchema,
1532
- body
1533
- );
1534
- const visible = opts.includeUntitled === true ? res.notes : res.notes.filter(isVisibleNote);
1535
- const mode = resolveOutputMode(globalOpts);
1536
- if (mode === "json") {
1537
- for (const note of visible) printNdjson(note);
1538
- if (res.nextCursor) printNdjson({ _cursor: res.nextCursor });
1539
- if (res.degraded === true) {
1540
- printNdjson({ _degraded: true, _degradedReason: res.degradedReason ?? null });
1541
- }
1542
- } else {
1543
- printPretty2(visible, res.nextCursor, globalOpts);
1544
- if (res.degraded === true && globalOpts.quiet !== true) {
1545
- process.stderr.write(
1546
- `${color("\u26A0", "yellow", globalOpts)} search results are partial${res.degradedReason ? ` (${res.degradedReason})` : ""}
1547
- `
1548
- );
1549
- }
1550
- }
1551
- });
1552
- }
1553
- function clampLimit2(raw) {
1554
- if (!raw) return void 0;
1555
- const n = parseInt(raw, 10);
1556
- if (!Number.isFinite(n) || n <= 0) return DEFAULT_PAGE_SIZE2;
1557
- return Math.min(n, MAX_PAGE_SIZE2);
1558
- }
1559
- function printPretty2(notes, nextCursor2, opts) {
1560
- if (notes.length === 0) {
1561
- process.stdout.write(`${color("(no matches)", "gray", opts)}
1562
- `);
1563
- return;
1564
- }
1565
- for (const n of notes) {
1566
- const date = n.createdAt.slice(0, 10);
1567
- process.stdout.write(
1568
- `${color(date, "gray", opts)} ${color(n.guid, "dim", opts)} ${n.title}
1569
- `
1570
- );
1571
- }
1572
- if (nextCursor2) {
1573
- process.stdout.write(
1574
- `${color(`
1575
- next: --cursor ${nextCursor2}`, "gray", opts)}
1576
- `
1577
- );
1578
- }
1579
- }
1580
-
1581
- // src/commands/notes/get.ts
1582
- import "commander";
1583
-
1584
- // src/lib/output/file.ts
1585
- import { mkdir, rename, stat, writeFile, access } from "fs/promises";
1586
- import { dirname as dirname2, resolve as resolve2, sep } from "path";
1587
- function assertSafeOutputPath(input) {
1588
- if (input.trim() === "") {
1589
- throw outputError("output path is empty", input);
1590
- }
1591
- const segments = input.split(/[\\/]/);
1592
- for (const seg of segments) {
1593
- if (seg === "..") {
1594
- throw outputError("path traversal segment '..' is not allowed", input);
1595
- }
1596
- }
1597
- }
1598
- function outputError(reason, input) {
1599
- return new TiroError(
1600
- {
1601
- code: "unsafe_output_path",
1602
- message: `Refusing to write to ${JSON.stringify(input)}: ${reason}.`,
1603
- errorType: "bad_request",
1604
- suggestion: "Use a path without '..' segments, or pass --force if you really mean it."
1605
- },
1606
- ExitCode.Usage
1607
- );
1608
- }
1609
- async function writeFileAtomic(filepath, content, opts = {}) {
1610
- if (!opts.force) {
1611
- assertSafeOutputPath(filepath);
1612
- }
1613
- const absPath = resolve2(filepath);
1614
- await mkdir(dirname2(absPath), { recursive: true });
1615
- if (!opts.force) {
1616
- const exists = await fileExists(absPath);
1617
- if (exists) {
1618
- throw new TiroError(
1619
- {
1620
- code: "file_exists",
1621
- message: `File already exists: ${absPath}`,
1622
- errorType: "conflict",
1623
- suggestion: "Use --force to overwrite, or pick a different --output."
1624
- },
1625
- ExitCode.Generic
1626
- );
1627
- }
1628
- }
1629
- const tmp = `${absPath}.tmp.${process.pid}.${Date.now()}`;
1630
- await writeFile(tmp, content, "utf8");
1631
- await rename(tmp, absPath);
1632
- const s = await stat(absPath);
1633
- return { path: absPath, size: s.size };
1634
- }
1635
- async function fileExists(p) {
1636
- try {
1637
- await access(p);
1638
- return true;
1639
- } catch {
1640
- return false;
1641
- }
1642
- }
1643
-
1644
- // src/lib/output/transcript.ts
1645
- function buildMcpTranscript(note, paragraphs) {
1646
- return {
1647
- noteGuid: note.guid,
1648
- title: note.title,
1649
- participants: note.participants?.map((p) => p.name || p.email || "").filter((s) => typeof s === "string" && s.length > 0) ?? [],
1650
- createdAt: note.createdAt,
1651
- recordingDurationSeconds: note.recordingDurationSeconds,
1652
- paragraphs: paragraphsToMcp(paragraphs)
1653
- };
1654
- }
1655
- function paragraphsToMcp(paragraphs) {
1656
- return paragraphs.map((p) => ({
1657
- timeFrom: p.timeFrom ?? null,
1658
- timeTo: p.timeTo ?? null,
1659
- segments: paragraphToSegments(p)
1660
- })).filter((p) => p.segments.length > 0);
1661
- }
1662
- function paragraphToSegments(p) {
1663
- const ds = p.diarizedSegments;
1664
- if (ds && ds.length > 0) {
1665
- return ds.map((s) => ({
1666
- content: stripHtml(s.content),
1667
- speaker: {
1668
- label: s.speaker.label,
1669
- name: s.speaker.personName ? stripHtml(s.speaker.personName) : null
1670
- }
1671
- })).filter((s) => s.content.length > 0);
1672
- }
1673
- const plain = stripHtml(p.transcript?.content ?? "");
1674
- return plain ? [{ content: plain, speaker: null }] : [];
1675
- }
1676
- function renderTranscriptJson(t) {
1677
- return `${JSON.stringify(t, null, 2)}
1678
- `;
1679
- }
1680
- function renderTranscriptMarkdown(t, opts = {}) {
1681
- const showTs = opts.timestamps !== false;
1682
- const anchor = showTs ? anchorTime(t) : null;
1683
- const lines = [];
1684
- lines.push(`# ${t.title}`, "");
1685
- if (t.participants.length > 0) {
1686
- lines.push(`**Participants**: ${t.participants.join(", ")}`, "");
1687
- }
1688
- lines.push("## Transcript", "");
1689
- for (const p of t.paragraphs) {
1690
- if (showTs) {
1691
- const ts = elapsed(p.timeFrom, anchor);
1692
- if (ts) lines.push(`### ${ts}`, "");
1693
- }
1694
- for (const s of p.segments) {
1695
- const who = s.speaker?.name ?? s.speaker?.label ?? "Unknown";
1696
- lines.push(`**${who}**: ${s.content}`);
1697
- }
1698
- lines.push("");
1699
- }
1700
- return `${lines.join("\n").trimEnd()}
1701
- `;
1702
- }
1703
- function renderTranscriptText(t) {
1704
- const lines = [];
1705
- for (const p of t.paragraphs) {
1706
- for (const s of p.segments) {
1707
- const who = s.speaker?.name ?? s.speaker?.label ?? "Unknown";
1708
- lines.push(`[${who}] ${s.content}`);
1709
- }
1710
- }
1711
- return `${lines.join("\n")}
1712
- `;
1713
- }
1714
- function anchorTime(t) {
1715
- for (const p of t.paragraphs) {
1716
- if (p.timeFrom) return p.timeFrom;
1717
- }
1718
- return null;
1719
- }
1720
- function elapsed(currentIso, anchorIso) {
1721
- if (!currentIso || !anchorIso) return "";
1722
- const cur = Date.parse(currentIso);
1723
- const anc = Date.parse(anchorIso);
1724
- if (!Number.isFinite(cur) || !Number.isFinite(anc)) return "";
1725
- const seconds = Math.max(0, Math.floor((cur - anc) / 1e3));
1726
- const h = Math.floor(seconds / 3600);
1727
- const m = Math.floor(seconds % 3600 / 60);
1728
- const s = seconds % 60;
1729
- if (h > 0) return `${pad(h)}:${pad(m)}:${pad(s)}`;
1730
- return `${pad(m)}:${pad(s)}`;
1731
- }
1732
- function pad(n) {
1733
- return n.toString().padStart(2, "0");
1734
- }
1735
- function stripHtml(s) {
1736
- return s.replace(/<[^>]*>/g, "").replace(/&nbsp;/g, " ").replace(/&amp;/g, "&").replace(/&lt;/g, "<").replace(/&gt;/g, ">").replace(/&quot;/g, '"').replace(/&#39;/g, "'").trim();
1737
- }
1738
-
1739
- // src/lib/output/format.ts
1740
- function formatNote(note, format, opts = {}) {
1741
- switch (format) {
1742
- case "md":
1743
- return formatMarkdown(note, opts);
1744
- case "json":
1745
- return formatJson(note, opts);
1746
- case "txt":
1747
- return formatText(note, opts);
1748
- }
1749
- }
1750
- function formatMarkdown(note, opts) {
1751
- const fm = [
1752
- "---",
1753
- `guid: ${escapeYaml(note.guid)}`,
1754
- `title: ${escapeYaml(note.title)}`,
1755
- `createdAt: ${note.createdAt}`,
1756
- `updatedAt: ${note.updatedAt}`,
1757
- `sourceType: ${note.sourceType}`,
1758
- `recordingDurationSeconds: ${note.recordingDurationSeconds}`,
1759
- `webUrl: ${note.webUrl}`
1760
- ];
1761
- if (note.recordingStartAt) fm.push(`recordingStartAt: ${note.recordingStartAt}`);
1762
- if (note.recordingEndAt) fm.push(`recordingEndAt: ${note.recordingEndAt}`);
1763
- fm.push("---", "");
1764
- const parts = [fm.join("\n"), `# ${note.title}`, ""];
1765
- if (note.participants && note.participants.length > 0) {
1766
- parts.push("## Participants", "");
1767
- for (const p of note.participants) {
1768
- const name = p.name ?? "(no name)";
1769
- const email = p.email ? ` <${p.email}>` : "";
1770
- parts.push(`- ${name}${email}`);
1771
- }
1772
- parts.push("");
1773
- }
1774
- if (opts.includeTranscript && opts.paragraphs && opts.paragraphs.length > 0) {
1775
- const mcp = buildMcpTranscript(note, opts.paragraphs);
1776
- const transcriptBody = renderTranscriptMarkdown(mcp);
1777
- const startsWithHeader = transcriptBody.startsWith(`# ${note.title}`);
1778
- const trimmed = startsWithHeader ? transcriptBody.slice(transcriptBody.indexOf("\n") + 1) : transcriptBody;
1779
- parts.push(trimmed.replace(/^\s*\n+/, ""));
1780
- }
1781
- return `${parts.join("\n").trimEnd()}
1782
- `;
1783
- }
1784
- function formatJson(note, opts) {
1785
- const out = { ...note };
1786
- if (opts.includeTranscript && opts.paragraphs) {
1787
- out["transcript"] = { paragraphs: paragraphsToMcp(opts.paragraphs) };
1788
- }
1789
- return `${JSON.stringify(out, null, 2)}
1790
- `;
1791
- }
1792
- function formatText(note, opts) {
1793
- if (!opts.paragraphs || opts.paragraphs.length === 0) {
1794
- return `${note.title}
1795
- ${note.webUrl}
1796
- `;
1797
- }
1798
- const mcp = buildMcpTranscript(note, opts.paragraphs);
1799
- return renderTranscriptText(mcp);
1800
- }
1801
- function escapeYaml(s) {
1802
- if (/[:#\n"']/.test(s)) {
1803
- return JSON.stringify(s);
1804
- }
1805
- return s;
1806
- }
1807
-
1808
- // src/commands/notes/get.ts
1809
- var ALLOWED_INCLUDES = /* @__PURE__ */ new Set(["transcript"]);
1810
- var ParagraphsListSchema = SimpleListResponseSchema(ParagraphSchema);
1811
- var ParagraphsCursorSchema = PageCursorResponseSchema(ParagraphSchema);
1812
- function registerNotesGet(parent) {
1813
- parent.command("get <guid>").description("Get a single note. Outputs to stdout, or saves to a file with --output.").option("--output <path>", "Write to file (stdout becomes a single metadata line)").option(
1814
- "--format <md|json|txt>",
1815
- "Output format (default: md for TTY, json when piped)"
1816
- ).option(
1817
- "--include <items>",
1818
- "Comma-separated extras (v0.2 supports: transcript)",
1819
- ""
1820
- ).option("--force", "Overwrite existing file at --output path").addHelpText("after", `
156
+ `;function cA(e){e.command("search [keyword]").description("Deep keyword search \u2014 returns notes hydrated with their primary documents.").option("--keyword <text>",'Alternative to positional keyword (e.g. --keyword "Q3 Planning")').option("--folder <id>","Restrict hits to a folder and its descendants").option("--since <date>","Inclusive lower bound on createdAt (ISO-8601 or relative: 7d, 24h, 30m)").option("--until <date>","Exclusive upper bound on createdAt").option("--limit <n>",`Max results per page (default ${sA}, max ${aA})`).option("--cursor <token>","Continue a previous page (reserved \u2014 backend currently always null)").option("--workspace <guid>","Search within one workspace (see `tiro wiki workspaces`). Default: the workspace your API key is bound to, else across all your workspaces").option("--include-untitled","Include placeholder notes. Default: hidden",!1).addHelpText("after",Ar).action(async(A,t,r)=>{let o=r.optsWithGlobals(),i=(A??t.keyword??"").trim();if(!i)throw new u({code:"missing_keyword",message:"search requires a keyword (positional or --keyword).",errorType:"bad_request",suggestion:'tiro notes search "OKR"'},d.Usage);let s={};t.folder&&(s.folderId=t.folder),t.since&&(s.createdAtFrom=I(t.since)),t.until&&(s.createdAtTo=I(t.until));let c={},l=tr(t.limit);l!==void 0&&(c.size=l),t.cursor&&(c.cursor=t.cursor);let p={keyword:i};Object.keys(s).length>0&&(p.filter=s),Object.keys(c).length>0&&(p.pagination=c);let m=k({...o.hostname!==void 0&&{hostnameOverride:o.hostname}}),w=await U(m,t.workspace);!w&&o.quiet!==!0&&process.stderr.write(`${a("\u26A0","yellow",o)} ${_}
157
+ `);let y=w?`/v1/external/workspaces/${encodeURIComponent(w)}/notes/search`:"/v1/external/notes/search",h=await m.postJson(y,er,p),x=t.includeUntitled===!0?h.notes:h.notes.filter(ee);if(b(o)==="json"){for(let oe of x)v(oe);h.nextCursor&&v({_cursor:h.nextCursor}),h.degraded===!0&&v({_degraded:!0,_degradedReason:h.degradedReason??null})}else rr(x,h.nextCursor,o),h.degraded===!0&&o.quiet!==!0&&process.stderr.write(`${a("\u26A0","yellow",o)} search results are partial${h.degradedReason?` (${h.degradedReason})`:""}
158
+ `)})}function tr(e){if(!e)return;let A=parseInt(e,10);return!Number.isFinite(A)||A<=0?sA:Math.min(A,aA)}function rr(e,A,t){if(e.length===0){process.stdout.write(`${a("(no matches)","gray",t)}
159
+ `);return}for(let r of e){let o=r.createdAt.slice(0,10);process.stdout.write(`${a(o,"gray",t)} ${a(r.guid,"dim",t)} ${r.title}
160
+ `)}A&&process.stdout.write(`${a(`
161
+ next: --cursor ${A}`,"gray",t)}
162
+ `)}import"commander";import{mkdir as or,rename as nr,stat as ir,writeFile as sr,access as ar}from"fs/promises";import{dirname as cr,resolve as pr,sep as Gi}from"path";function dr(e){if(e.trim()==="")throw pA("output path is empty",e);let A=e.split(/[\\/]/);for(let t of A)if(t==="..")throw pA("path traversal segment '..' is not allowed",e)}function pA(e,A){return new u({code:"unsafe_output_path",message:`Refusing to write to ${JSON.stringify(A)}: ${e}.`,errorType:"bad_request",suggestion:"Use a path without '..' segments, or pass --force if you really mean it."},d.Usage)}async function Ae(e,A,t={}){t.force||dr(e);let r=pr(e);if(await or(cr(r),{recursive:!0}),!t.force&&await ur(r))throw new u({code:"file_exists",message:`File already exists: ${r}`,errorType:"conflict",suggestion:"Use --force to overwrite, or pick a different --output."},d.Generic);let o=`${r}.tmp.${process.pid}.${Date.now()}`;await sr(o,A,"utf8"),await nr(o,r);let i=await ir(r);return{path:r,size:i.size}}async function ur(e){try{return await ar(e),!0}catch{return!1}}function z(e,A){return{noteGuid:e.guid,title:e.title,participants:e.participants?.map(t=>t.name||t.email||"").filter(t=>typeof t=="string"&&t.length>0)??[],createdAt:e.createdAt,recordingDurationSeconds:e.recordingDurationSeconds,paragraphs:Y(A)}}function Y(e){return e.map(A=>({timeFrom:A.timeFrom??null,timeTo:A.timeTo??null,segments:lr(A)})).filter(A=>A.segments.length>0)}function lr(e){let A=e.diarizedSegments;if(A&&A.length>0)return A.map(r=>({content:le(r.content),speaker:{label:r.speaker.label,name:r.speaker.personName?le(r.speaker.personName):null}})).filter(r=>r.content.length>0);let t=le(e.transcript?.content??"");return t?[{content:t,speaker:null}]:[]}function me(e){return`${JSON.stringify(e,null,2)}
163
+ `}function te(e,A={}){let t=A.timestamps!==!1,r=t?mr(e):null,o=[];o.push(`# ${e.title}`,""),e.participants.length>0&&o.push(`**Participants**: ${e.participants.join(", ")}`,""),o.push("## Transcript","");for(let i of e.paragraphs){if(t){let s=gr(i.timeFrom,r);s&&o.push(`### ${s}`,"")}for(let s of i.segments){let c=s.speaker?.name??s.speaker?.label??"Unknown";o.push(`**${c}**: ${s.content}`)}o.push("")}return`${o.join(`
164
+ `).trimEnd()}
165
+ `}function re(e){let A=[];for(let t of e.paragraphs)for(let r of t.segments){let o=r.speaker?.name??r.speaker?.label??"Unknown";A.push(`[${o}] ${r.content}`)}return`${A.join(`
166
+ `)}
167
+ `}function mr(e){for(let A of e.paragraphs)if(A.timeFrom)return A.timeFrom;return null}function gr(e,A){if(!e||!A)return"";let t=Date.parse(e),r=Date.parse(A);if(!Number.isFinite(t)||!Number.isFinite(r))return"";let o=Math.max(0,Math.floor((t-r)/1e3)),i=Math.floor(o/3600),s=Math.floor(o%3600/60),c=o%60;return i>0?`${Q(i)}:${Q(s)}:${Q(c)}`:`${Q(s)}:${Q(c)}`}function Q(e){return e.toString().padStart(2,"0")}function le(e){return e.replace(/<[^>]*>/g,"").replace(/&nbsp;/g," ").replace(/&amp;/g,"&").replace(/&lt;/g,"<").replace(/&gt;/g,">").replace(/&quot;/g,'"').replace(/&#39;/g,"'").trim()}function uA(e,A,t={}){switch(A){case"md":return fr(e,t);case"json":return hr(e,t);case"txt":return wr(e,t)}}function fr(e,A){let t=["---",`guid: ${dA(e.guid)}`,`title: ${dA(e.title)}`,`createdAt: ${e.createdAt}`,`updatedAt: ${e.updatedAt}`,`sourceType: ${e.sourceType}`,`recordingDurationSeconds: ${e.recordingDurationSeconds}`,`webUrl: ${e.webUrl}`];e.recordingStartAt&&t.push(`recordingStartAt: ${e.recordingStartAt}`),e.recordingEndAt&&t.push(`recordingEndAt: ${e.recordingEndAt}`),t.push("---","");let r=[t.join(`
168
+ `),`# ${e.title}`,""];if(e.participants&&e.participants.length>0){r.push("## Participants","");for(let o of e.participants){let i=o.name??"(no name)",s=o.email?` <${o.email}>`:"";r.push(`- ${i}${s}`)}r.push("")}if(A.includeTranscript&&A.paragraphs&&A.paragraphs.length>0){let o=z(e,A.paragraphs),i=te(o),c=i.startsWith(`# ${e.title}`)?i.slice(i.indexOf(`
169
+ `)+1):i;r.push(c.replace(/^\s*\n+/,""))}return`${r.join(`
170
+ `).trimEnd()}
171
+ `}function hr(e,A){let t={...e};return A.includeTranscript&&A.paragraphs&&(t.transcript={paragraphs:Y(A.paragraphs)}),`${JSON.stringify(t,null,2)}
172
+ `}function wr(e,A){if(!A.paragraphs||A.paragraphs.length===0)return`${e.title}
173
+ ${e.webUrl}
174
+ `;let t=z(e,A.paragraphs);return re(t)}function dA(e){return/[:#\n"']/.test(e)?JSON.stringify(e):e}var yr=new Set(["transcript"]),br=q(D),lA=R(D);function mA(e){e.command("get <guid>").description("Get a single note. Outputs to stdout, or saves to a file with --output.").option("--output <path>","Write to file (stdout becomes a single metadata line)").option("--format <md|json|txt>","Output format (default: md for TTY, json when piped)").option("--include <items>","Comma-separated extras (v0.2 supports: transcript)","").option("--force","Overwrite existing file at --output path").addHelpText("after",`
1821
175
  Examples:
1822
176
  tiro notes get <guid> # markdown to stdout
1823
177
  tiro notes get <guid> --include transcript # add speaker-attributed paragraphs
@@ -1827,142 +181,10 @@ Examples:
1827
181
  Tip for agents: prefer --output <path>. The actual content goes to disk
1828
182
  and stdout collapses to a single metadata line, keeping your context
1829
183
  window light.
1830
- `).action(async (guid, opts, cmd) => {
1831
- const globalOpts = cmd.optsWithGlobals();
1832
- const includes = parseIncludes(opts.include);
1833
- validateIncludes(includes);
1834
- const format = pickFormat(opts.format, opts.output);
1835
- const client = createApiClient({
1836
- ...globalOpts.hostname !== void 0 && { hostnameOverride: globalOpts.hostname }
1837
- });
1838
- const note = await client.getJson(`/v1/external/notes/${guid}`, NoteSchema);
1839
- let paragraphs;
1840
- if (includes.has("transcript") || format === "txt") {
1841
- paragraphs = await fetchAllParagraphs(client, guid);
1842
- }
1843
- const content = formatNote(note, format, {
1844
- includeTranscript: includes.has("transcript"),
1845
- ...paragraphs !== void 0 && { paragraphs }
1846
- });
1847
- if (opts.output) {
1848
- const result = await writeFileAtomic(opts.output, content, {
1849
- ...opts.force === true && { force: true }
1850
- });
1851
- printOutput(
1852
- {
1853
- ok: true,
1854
- data: {
1855
- saved: result.path,
1856
- size: result.size,
1857
- format,
1858
- guid: note.guid,
1859
- title: note.title
1860
- }
1861
- },
1862
- globalOpts
1863
- );
1864
- return;
1865
- }
1866
- const mode = resolveOutputMode(globalOpts);
1867
- if (mode === "json" && format !== "json") {
1868
- printOutput(
1869
- {
1870
- ok: true,
1871
- data: {
1872
- ...note,
1873
- ...paragraphs && { transcript: { paragraphs: paragraphsToMcp(paragraphs) } }
1874
- }
1875
- },
1876
- globalOpts
1877
- );
1878
- } else if (format === "json") {
1879
- process.stdout.write(content);
1880
- } else {
1881
- if (process.stdout.isTTY && format === "txt") {
1882
- process.stdout.write(`${color(`# ${note.title}`, "bold", globalOpts)}
184
+ `).action(async(A,t,r)=>{let o=r.optsWithGlobals(),i=Cr(t.include);vr(i);let s=xr(t.format,t.output),c=k({...o.hostname!==void 0&&{hostnameOverride:o.hostname}}),l=await c.getJson(`/v1/external/notes/${A}`,B),p;(i.has("transcript")||s==="txt")&&(p=await kr(c,A));let m=uA(l,s,{includeTranscript:i.has("transcript"),...p!==void 0&&{paragraphs:p}});if(t.output){let y=await Ae(t.output,m,{...t.force===!0&&{force:!0}});C({ok:!0,data:{saved:y.path,size:y.size,format:s,guid:l.guid,title:l.title}},o);return}b(o)==="json"&&s!=="json"?C({ok:!0,data:{...l,...p&&{transcript:{paragraphs:Y(p)}}}},o):(s==="json"||process.stdout.isTTY&&s==="txt"&&process.stdout.write(`${a(`# ${l.title}`,"bold",o)}
1883
185
 
1884
- `);
1885
- }
1886
- process.stdout.write(content);
1887
- }
1888
- });
1889
- }
1890
- async function fetchAllParagraphs(client, guid) {
1891
- const first = await client.getJson(
1892
- `/v1/external/notes/${guid}/paragraphs`,
1893
- ParagraphsCursorSchema.or(ParagraphsListSchema)
1894
- );
1895
- const all = [...first.content];
1896
- if ("nextCursor" in first) {
1897
- let cursor = first.nextCursor;
1898
- while (cursor) {
1899
- const next = await client.getJson(
1900
- `/v1/external/notes/${guid}/paragraphs`,
1901
- ParagraphsCursorSchema,
1902
- { cursor }
1903
- );
1904
- all.push(...next.content);
1905
- cursor = next.nextCursor;
1906
- }
1907
- }
1908
- return all;
1909
- }
1910
- function parseIncludes(raw) {
1911
- if (!raw) return /* @__PURE__ */ new Set();
1912
- return new Set(
1913
- raw.split(",").map((s) => s.trim().toLowerCase()).filter((s) => s.length > 0)
1914
- );
1915
- }
1916
- function validateIncludes(includes) {
1917
- for (const inc of includes) {
1918
- if (!ALLOWED_INCLUDES.has(inc)) {
1919
- throw new TiroError(
1920
- {
1921
- code: "invalid_include",
1922
- message: `Invalid --include "${inc}". v0.2.0 supports: transcript.`,
1923
- errorType: "bad_request",
1924
- suggestion: "Use --include transcript"
1925
- },
1926
- ExitCode.Usage
1927
- );
1928
- }
1929
- }
1930
- }
1931
- function pickFormat(format, output) {
1932
- const allowed = ["md", "json", "txt"];
1933
- if (format) {
1934
- const f = format.toLowerCase();
1935
- if (!allowed.includes(f)) {
1936
- throw new TiroError(
1937
- {
1938
- code: "invalid_format",
1939
- message: `Invalid --format "${format}". Allowed: md, json, txt.`,
1940
- errorType: "bad_request"
1941
- },
1942
- ExitCode.Usage
1943
- );
1944
- }
1945
- return f;
1946
- }
1947
- if (output) {
1948
- if (output.endsWith(".json")) return "json";
1949
- if (output.endsWith(".txt")) return "txt";
1950
- return "md";
1951
- }
1952
- return process.stdout.isTTY ? "md" : "json";
1953
- }
1954
-
1955
- // src/commands/notes/transcript.ts
1956
- import "commander";
1957
- var ParagraphsListSchema2 = SimpleListResponseSchema(ParagraphSchema);
1958
- var ParagraphsCursorSchema2 = PageCursorResponseSchema(ParagraphSchema);
1959
- function registerNotesTranscript(parent) {
1960
- parent.command("transcript <guid>").description(
1961
- "Get the full transcript of a note as speaker-attributed paragraphs.\nJSON output matches MCP get_note_transcript shape exactly."
1962
- ).option("--output <path>", "Write to file (stdout = single metadata line)").option(
1963
- "--format <md|json|txt>",
1964
- "Output format (default: md if TTY, txt when piped; json mirrors MCP)"
1965
- ).option("--force", "Overwrite existing file at --output path").option("--no-timestamps", "Omit paragraph timestamp headers (md format only)").addHelpText("after", `
186
+ `),process.stdout.write(m))})}async function kr(e,A){let t=await e.getJson(`/v1/external/notes/${A}/paragraphs`,lA.or(br)),r=[...t.content];if("nextCursor"in t){let o=t.nextCursor;for(;o;){let i=await e.getJson(`/v1/external/notes/${A}/paragraphs`,lA,{cursor:o});r.push(...i.content),o=i.nextCursor}}return r}function Cr(e){return e?new Set(e.split(",").map(A=>A.trim().toLowerCase()).filter(A=>A.length>0)):new Set}function vr(e){for(let A of e)if(!yr.has(A))throw new u({code:"invalid_include",message:`Invalid --include "${A}". v0.2.0 supports: transcript.`,errorType:"bad_request",suggestion:"Use --include transcript"},d.Usage)}function xr(e,A){let t=["md","json","txt"];if(e){let r=e.toLowerCase();if(!t.includes(r))throw new u({code:"invalid_format",message:`Invalid --format "${e}". Allowed: md, json, txt.`,errorType:"bad_request"},d.Usage);return r}return A?A.endsWith(".json")?"json":A.endsWith(".txt")?"txt":"md":process.stdout.isTTY?"md":"json"}import"commander";var Tr=q(D),gA=R(D);function fA(e){e.command("transcript <guid>").description(`Get the full transcript of a note as speaker-attributed paragraphs.
187
+ JSON output matches MCP get_note_transcript shape exactly.`).option("--output <path>","Write to file (stdout = single metadata line)").option("--format <md|json|txt>","Output format (default: md if TTY, txt when piped; json mirrors MCP)").option("--force","Overwrite existing file at --output path").option("--no-timestamps","Omit paragraph timestamp headers (md format only)").addHelpText("after",`
1966
188
  Examples:
1967
189
  tiro notes transcript <guid> # md in TTY, txt in pipe
1968
190
  tiro notes transcript <guid> --format md --output ./t.md
@@ -1972,124 +194,39 @@ Examples:
1972
194
 
1973
195
  The --format json output is byte-for-byte identical to MCP's
1974
196
  get_note_transcript so agents can swap surfaces without changing parsers.
1975
- `).action(async (guid, opts, cmd) => {
1976
- const globalOpts = cmd.optsWithGlobals();
1977
- const format = pickFormat2(opts.format, opts.output, globalOpts);
1978
- const client = createApiClient({
1979
- ...globalOpts.hostname !== void 0 && { hostnameOverride: globalOpts.hostname }
1980
- });
1981
- const note = await client.getJson(`/v1/external/notes/${guid}`, NoteSchema);
1982
- const paragraphs = await fetchAllParagraphs2(client, guid);
1983
- const mcp = buildMcpTranscript(note, paragraphs);
1984
- const content = format === "json" ? renderTranscriptJson(mcp) : format === "md" ? renderTranscriptMarkdown(mcp, { timestamps: opts.timestamps !== false }) : renderTranscriptText(mcp);
1985
- if (opts.output) {
1986
- const result = await writeFileAtomic(opts.output, content, {
1987
- ...opts.force === true && { force: true }
1988
- });
1989
- printOutput(
1990
- {
1991
- ok: true,
1992
- data: {
1993
- saved: result.path,
1994
- size: result.size,
1995
- format,
1996
- guid: note.guid,
1997
- paragraphCount: mcp.paragraphs.length,
1998
- segmentCount: mcp.paragraphs.reduce((sum, p) => sum + p.segments.length, 0)
1999
- }
2000
- },
2001
- globalOpts
2002
- );
2003
- return;
2004
- }
2005
- const mode = resolveOutputMode(globalOpts);
2006
- if (mode === "json" && format !== "json") {
2007
- printOutput({ ok: true, data: mcp }, globalOpts);
2008
- } else {
2009
- process.stdout.write(content);
2010
- }
2011
- });
2012
- }
2013
- async function fetchAllParagraphs2(client, guid) {
2014
- const first = await client.getJson(
2015
- `/v1/external/notes/${guid}/paragraphs`,
2016
- ParagraphsCursorSchema2.or(ParagraphsListSchema2)
2017
- );
2018
- const all = [...first.content];
2019
- if ("nextCursor" in first) {
2020
- let cursor = first.nextCursor;
2021
- while (cursor) {
2022
- const next = await client.getJson(
2023
- `/v1/external/notes/${guid}/paragraphs`,
2024
- ParagraphsCursorSchema2,
2025
- { cursor }
2026
- );
2027
- all.push(...next.content);
2028
- cursor = next.nextCursor;
2029
- }
2030
- }
2031
- return all;
2032
- }
2033
- function pickFormat2(format, output, globalOpts) {
2034
- const allowed = ["md", "json", "txt"];
2035
- if (format) {
2036
- const f = format.toLowerCase();
2037
- if (!allowed.includes(f)) {
2038
- throw new TiroError(
2039
- {
2040
- code: "invalid_format",
2041
- message: `Invalid --format "${format}". Allowed: md, json, txt.`,
2042
- errorType: "bad_request"
2043
- },
2044
- ExitCode.Usage
2045
- );
2046
- }
2047
- return f;
2048
- }
2049
- if (output) {
2050
- if (output.endsWith(".json")) return "json";
2051
- if (output.endsWith(".md")) return "md";
2052
- if (output.endsWith(".txt")) return "txt";
2053
- return "md";
2054
- }
2055
- if (globalOpts.json) return "json";
2056
- if (globalOpts.pretty) return "md";
2057
- return process.stdout.isTTY ? "md" : "txt";
2058
- }
2059
-
2060
- // src/commands/notes/index.ts
2061
- function registerNotes(program) {
2062
- const notes = program.command("notes").description("List, search, and download notes");
2063
- registerNotesList(notes);
2064
- registerNotesSearch(notes);
2065
- registerNotesGet(notes);
2066
- registerNotesTranscript(notes);
2067
- }
2068
-
2069
- // src/commands/wiki/index.ts
2070
- import "commander";
2071
-
2072
- // src/commands/wiki/search.ts
2073
- import "commander";
2074
-
2075
- // src/lib/api/workspace.ts
2076
- var cache = /* @__PURE__ */ new WeakMap();
2077
- async function resolveWorkspaceGuid(client) {
2078
- const cached = cache.get(client);
2079
- if (cached) return cached;
2080
- const promise = client.getJson("/v1/external/workspaces/me", WorkspaceMeSchema).then((res) => res.guid);
2081
- cache.set(client, promise);
2082
- return promise;
2083
- }
2084
- async function listWorkspaces(client) {
2085
- const res = await client.getJson("/v1/external/workspaces", WorkspacesListSchema);
2086
- return res.workspaces;
2087
- }
2088
-
2089
- // src/commands/wiki/search.ts
2090
- var MAX_SIZE = 100;
2091
- var MAX_QUERY_LENGTH = 500;
2092
- var HELP_AFTER3 = `
197
+ `).action(async(A,t,r)=>{let o=r.optsWithGlobals(),i=Br(t.format,t.output,o),s=k({...o.hostname!==void 0&&{hostnameOverride:o.hostname}}),c=await s.getJson(`/v1/external/notes/${A}`,B),l=await Lr(s,A),p=z(c,l),m=i==="json"?me(p):i==="md"?te(p,{timestamps:t.timestamps!==!1}):re(p);if(t.output){let y=await Ae(t.output,m,{...t.force===!0&&{force:!0}});C({ok:!0,data:{saved:y.path,size:y.size,format:i,guid:c.guid,paragraphCount:p.paragraphs.length,segmentCount:p.paragraphs.reduce((h,x)=>h+x.segments.length,0)}},o);return}b(o)==="json"&&i!=="json"?C({ok:!0,data:p},o):process.stdout.write(m)})}async function Lr(e,A){let t=await e.getJson(`/v1/external/notes/${A}/paragraphs`,gA.or(Tr)),r=[...t.content];if("nextCursor"in t){let o=t.nextCursor;for(;o;){let i=await e.getJson(`/v1/external/notes/${A}/paragraphs`,gA,{cursor:o});r.push(...i.content),o=i.nextCursor}}return r}function Br(e,A,t){let r=["md","json","txt"];if(e){let o=e.toLowerCase();if(!r.includes(o))throw new u({code:"invalid_format",message:`Invalid --format "${e}". Allowed: md, json, txt.`,errorType:"bad_request"},d.Usage);return o}return A?A.endsWith(".json")?"json":A.endsWith(".md")?"md":A.endsWith(".txt")?"txt":"md":t.json?"json":t.pretty||process.stdout.isTTY?"md":"txt"}function hA(e){let A=e.command("notes").description("List, search, and download notes");iA(A),cA(A),mA(A),fA(A)}import"commander";import"commander";import{z as Rr}from"zod";var Er=Rr.array(Ke),Ir=`
198
+ Examples:
199
+ tiro folders list
200
+ tiro folders list --workspace <guid> --json
201
+
202
+ Lists the folders in a workspace (flat). sharingType is PRIVATE / ALL_MEMBER_VIEWER
203
+ / ALL_MEMBER_EDITOR / LIMITED. Pass a folder id to 'tiro notes list --folder <id>'.
204
+ The workspace resolves from --workspace, else your API key's bound workspace; an
205
+ unbound credential must pass --workspace (run 'tiro wiki workspaces' for guids).
206
+ `;function wA(e){e.command("list").description("List folders in a workspace.").option("--workspace <guid>","Workspace to list folders from (see `tiro wiki workspaces`). Default: your API key's bound workspace").addHelpText("after",Ir).action(async(A,t)=>{let r=t.optsWithGlobals(),o=k({...r.hostname!==void 0&&{hostnameOverride:r.hostname}}),i=await M(o,A.workspace),s=await o.getJson(`/v1/external/workspaces/${encodeURIComponent(i)}/folders`,Er);if(b(r)==="json")for(let l of s)v(l);else Or(s,r)})}function Or(e,A){if(e.length===0){process.stdout.write(`${a("(no folders)","gray",A)}
207
+ `);return}for(let t of e)process.stdout.write(`${a(t.id,"dim",A)} ${a(t.sharingType,"gray",A)} ${t.title}
208
+ `)}import"commander";var Pr=q(de),Xr=`
209
+ Examples:
210
+ tiro folders tree
211
+ tiro folders tree --workspace <guid> --json
212
+
213
+ Returns the folder hierarchy for a workspace. In JSON mode each root folder is one
214
+ NDJSON line with nested children; in pretty mode the tree is indented by depth.
215
+ `;function yA(e){e.command("tree").description("Show the folder hierarchy of a workspace.").option("--workspace <guid>","Workspace to read the tree from (see `tiro wiki workspaces`). Default: your API key's bound workspace").addHelpText("after",Xr).action(async(A,t)=>{let r=t.optsWithGlobals(),o=k({...r.hostname!==void 0&&{hostnameOverride:r.hostname}}),i=await M(o,A.workspace),s=await o.getJson(`/v1/external/workspaces/${encodeURIComponent(i)}/folders/tree`,Pr);if(b(r)==="json")for(let l of s.content)v(l);else Sr(s.content,r)})}function Sr(e,A){if(e.length===0){process.stdout.write(`${a("(no folders)","gray",A)}
216
+ `);return}for(let t of e)bA(t,A)}function bA(e,A){let t=" ".repeat(e.depth),r=e.isAccessible?e.title:a(`${e.title} (no access)`,"gray",A);process.stdout.write(`${t}${a(e.id,"dim",A)} ${r}
217
+ `);for(let o of e.children)bA(o,A)}function kA(e){let A=e.command("folders").description("List workspace folders (flat or as a tree) to scope note queries");wA(A),yA(A)}import"commander";import"commander";var Fr=R(Ze),CA=1e3,Dr=`
218
+ Examples:
219
+ tiro word-memories list
220
+ tiro word-memories list --workspace <guid> --json
221
+
222
+ Lists a workspace's custom word memories (vocabulary that biases transcription).
223
+ The workspace resolves from --workspace, else your API key's bound workspace; an
224
+ unbound credential must pass --workspace (run 'tiro wiki workspaces' for guids).
225
+ `;function vA(e){e.command("list").description("List a workspace's custom word memories.").option("--workspace <guid>","Workspace to list from (see `tiro wiki workspaces`). Default: your API key's bound workspace").option("--limit <n>",`Max results per page (max ${CA})`).option("--cursor <token>","Continue a previous page").addHelpText("after",Dr).action(async(A,t)=>{let r=t.optsWithGlobals(),o=k({...r.hostname!==void 0&&{hostnameOverride:r.hostname}}),i=await M(o,A.workspace),s={},c=qr(A.limit);c!==void 0&&(s.size=c),A.cursor&&(s.cursor=A.cursor);let l=await o.getJson(`/v1/external/workspaces/${encodeURIComponent(i)}/word-memories`,Fr,s);if(b(r)==="json"){for(let m of l.content)v(m);l.nextCursor&&v({_cursor:l.nextCursor})}else Mr(l.content,l.nextCursor,r)})}function qr(e){if(!e)return;let A=parseInt(e,10);if(!(!Number.isFinite(A)||A<=0))return Math.min(A,CA)}function Mr(e,A,t){if(e.length===0){process.stdout.write(`${a("(no word memories)","gray",t)}
226
+ `);return}for(let r of e)process.stdout.write(`${a(String(r.id),"dim",t)} ${r.entry}
227
+ `);A&&process.stdout.write(`${a(`
228
+ next: --cursor ${A}`,"gray",t)}
229
+ `)}function xA(e){let A=e.command("word-memories").description("List a workspace's custom word memories (transcription vocabulary)");vA(A)}import"commander";import"commander";var LA=100,TA=500,Hr=`
2093
230
  Examples:
2094
231
  tiro wiki search "onboarding"
2095
232
  tiro wiki search "payment gateway" --size 50 --json
@@ -2099,68 +236,9 @@ The workspace defaults to the one implicit in your API key. Pass --workspace
2099
236
  to target a specific workspace (get guids from 'tiro wiki workspaces').
2100
237
  Results are ranked wiki pages (pageGuid, name, type, relevance). Pass a
2101
238
  pageGuid to 'tiro wiki page', 'tiro wiki mentions', or 'tiro wiki graph'.
2102
- `;
2103
- function registerWikiSearch(parent) {
2104
- parent.command("search <query>").description("Search the workspace wiki for pages matching a keyword.").option("--size <n>", `Max results (default: backend default, max ${MAX_SIZE})`).option("--workspace <guid>", "Target a specific workspace (from `tiro wiki workspaces`); defaults to your default workspace").addHelpText("after", HELP_AFTER3).action(async (query, opts, cmd) => {
2105
- const globalOpts = cmd.optsWithGlobals();
2106
- const keyword = query.trim();
2107
- if (!keyword) {
2108
- throw new TiroError(
2109
- {
2110
- code: "missing_query",
2111
- message: "wiki search requires a query.",
2112
- errorType: "bad_request",
2113
- suggestion: 'tiro wiki search "onboarding"'
2114
- },
2115
- ExitCode.Usage
2116
- );
2117
- }
2118
- const client = createApiClient({
2119
- ...globalOpts.hostname !== void 0 && { hostnameOverride: globalOpts.hostname }
2120
- });
2121
- const workspaceGuid = opts.workspace ?? await resolveWorkspaceGuid(client);
2122
- const clampedKeyword = keyword.length > MAX_QUERY_LENGTH ? keyword.slice(0, MAX_QUERY_LENGTH) : keyword;
2123
- const params = { q: clampedKeyword };
2124
- const size = clampSize(opts.size);
2125
- if (size !== void 0) params["size"] = size;
2126
- const res = await client.getJson(
2127
- // Fix 1: encode workspaceGuid so path-traversal sequences (../, ?, #) are neutralised.
2128
- `/v1/external/workspaces/${encodeURIComponent(workspaceGuid)}/wiki/search/pages`,
2129
- WikiSearchPagesResponseSchema,
2130
- params
2131
- );
2132
- const mode = resolveOutputMode(globalOpts);
2133
- if (mode === "json") {
2134
- for (const item of res.items) printNdjson(item);
2135
- } else {
2136
- printPretty3(res.items, globalOpts);
2137
- }
2138
- });
2139
- }
2140
- function clampSize(raw) {
2141
- if (!raw) return void 0;
2142
- const n = parseInt(raw, 10);
2143
- if (!Number.isFinite(n) || n <= 0) return void 0;
2144
- return Math.min(n, MAX_SIZE);
2145
- }
2146
- function printPretty3(items, opts) {
2147
- if (items.length === 0) {
2148
- process.stdout.write(`${color("(no matches)", "gray", opts)}
2149
- `);
2150
- return;
2151
- }
2152
- for (const it of items) {
2153
- const score = it.score.toFixed(2);
2154
- process.stdout.write(
2155
- `${color(score, "cyan", opts)} ${color(it.guid, "dim", opts)} ${color(it.pageType, "gray", opts)} ${it.canonicalName}
2156
- `
2157
- );
2158
- }
2159
- }
2160
-
2161
- // src/commands/wiki/page.ts
2162
- import "commander";
2163
- var HELP_AFTER4 = `
239
+ `;function BA(e){e.command("search <query>").description("Search the workspace wiki for pages matching a keyword.").option("--size <n>",`Max results (default: backend default, max ${LA})`).option("--workspace <guid>","Target a specific workspace (from `tiro wiki workspaces`); defaults to your default workspace").addHelpText("after",Hr).action(async(A,t,r)=>{let o=r.optsWithGlobals(),i=A.trim();if(!i)throw new u({code:"missing_query",message:"wiki search requires a query.",errorType:"bad_request",suggestion:'tiro wiki search "onboarding"'},d.Usage);let s=k({...o.hostname!==void 0&&{hostnameOverride:o.hostname}}),c=t.workspace??await E(s),p={q:i.length>TA?i.slice(0,TA):i},m=Wr(t.size);m!==void 0&&(p.size=m);let w=await s.getJson(`/v1/external/workspaces/${encodeURIComponent(c)}/wiki/search/pages`,Ue,p);if(b(o)==="json")for(let h of w.items)v(h);else Nr(w.items,o)})}function Wr(e){if(!e)return;let A=parseInt(e,10);if(!(!Number.isFinite(A)||A<=0))return Math.min(A,LA)}function Nr(e,A){if(e.length===0){process.stdout.write(`${a("(no matches)","gray",A)}
240
+ `);return}for(let t of e){let r=t.score.toFixed(2);process.stdout.write(`${a(r,"cyan",A)} ${a(t.guid,"dim",A)} ${a(t.pageType,"gray",A)} ${t.canonicalName}
241
+ `)}}import"commander";var Gr=`
2164
242
  Examples:
2165
243
  tiro wiki page <pageGuid>
2166
244
  tiro wiki page <pageGuid> --json
@@ -2169,53 +247,15 @@ Examples:
2169
247
  Returns the page body (per-user description) plus metadata, mentions,
2170
248
  aliases, and links. The workspace defaults to the one implicit in your API
2171
249
  key; pass --workspace to target a specific workspace (from 'tiro wiki workspaces').
2172
- `;
2173
- function registerWikiPage(parent) {
2174
- parent.command("page <pageGuid>").description("Get a single wiki page: body, metadata, mentions, aliases, and links.").option("--workspace <guid>", "Target a specific workspace (from `tiro wiki workspaces`); defaults to your default workspace").addHelpText("after", HELP_AFTER4).action(async (pageGuid, opts, cmd) => {
2175
- const globalOpts = cmd.optsWithGlobals();
2176
- const client = createApiClient({
2177
- ...globalOpts.hostname !== void 0 && { hostnameOverride: globalOpts.hostname }
2178
- });
2179
- const workspaceGuid = opts.workspace ?? await resolveWorkspaceGuid(client);
2180
- const page = await client.getJson(
2181
- `/v1/external/workspaces/${encodeURIComponent(workspaceGuid)}/wiki/pages/${encodeURIComponent(pageGuid)}`,
2182
- WikiPageDetailSchema
2183
- );
2184
- const mode = resolveOutputMode(globalOpts);
2185
- if (mode === "json") {
2186
- printOutput({ ok: true, data: page }, globalOpts);
2187
- } else {
2188
- printPretty4(page, globalOpts);
2189
- }
2190
- });
2191
- }
2192
- function printPretty4(page, opts) {
2193
- const w = process.stdout.write.bind(process.stdout);
2194
- w(`${color(page.canonicalName, "bold", opts)} ${color(`(${page.pageType})`, "gray", opts)}
2195
- `);
2196
- w(`${color(page.guid, "dim", opts)}
250
+ `;function RA(e){e.command("page <pageGuid>").description("Get a single wiki page: body, metadata, mentions, aliases, and links.").option("--workspace <guid>","Target a specific workspace (from `tiro wiki workspaces`); defaults to your default workspace").addHelpText("after",Gr).action(async(A,t,r)=>{let o=r.optsWithGlobals(),i=k({...o.hostname!==void 0&&{hostnameOverride:o.hostname}}),s=t.workspace??await E(i),c=await i.getJson(`/v1/external/workspaces/${encodeURIComponent(s)}/wiki/pages/${encodeURIComponent(A)}`,Qe);b(o)==="json"?C({ok:!0,data:c},o):Vr(c,o)})}function Vr(e,A){let t=process.stdout.write.bind(process.stdout);if(t(`${a(e.canonicalName,"bold",A)} ${a(`(${e.pageType})`,"gray",A)}
251
+ `),t(`${a(e.guid,"dim",A)}
2197
252
 
2198
- `);
2199
- if (page.description) {
2200
- w(`${page.description}
253
+ `),e.description)t(`${e.description}
2201
254
 
2202
- `);
2203
- } else {
2204
- const status = page.descriptionStatus ?? "none";
2205
- w(`${color(`(no description \u2014 status: ${status})`, "gray", opts)}
255
+ `);else{let r=e.descriptionStatus??"none";t(`${a(`(no description \u2014 status: ${r})`,"gray",A)}
2206
256
 
2207
- `);
2208
- }
2209
- w(
2210
- `${color("mentions", "gray", opts)} ${page.mentionCountVisible} ${color("aliases", "gray", opts)} ${page.aliases.length} ${color("links", "gray", opts)} ${page.links.length}
2211
- `
2212
- );
2213
- }
2214
-
2215
- // src/commands/wiki/mentions.ts
2216
- import "commander";
2217
- var MAX_LIMIT = 200;
2218
- var HELP_AFTER5 = `
257
+ `)}t(`${a("mentions","gray",A)} ${e.mentionCountVisible} ${a("aliases","gray",A)} ${e.aliases.length} ${a("links","gray",A)} ${e.links.length}
258
+ `)}import"commander";var EA=200,Ur=`
2219
259
  Examples:
2220
260
  tiro wiki mentions <pageGuid>
2221
261
  tiro wiki mentions <pageGuid> --limit 100 --json
@@ -2226,66 +266,9 @@ Lists the note paragraphs that reference a wiki page. In JSON mode a trailing
2226
266
  cursor token back via --cursor to fetch the next page. The workspace defaults
2227
267
  to the one implicit in your API key; pass --workspace to target a specific
2228
268
  workspace (from 'tiro wiki workspaces').
2229
- `;
2230
- function registerWikiMentions(parent) {
2231
- parent.command("mentions <pageGuid>").description("List the note mentions that reference a single wiki page.").option("--limit <n>", `Max mentions per page (max ${MAX_LIMIT})`).option("--cursor <token>", "Continue from a previous page's cursor token.").option("--workspace <guid>", "Target a specific workspace (from `tiro wiki workspaces`); defaults to your default workspace").addHelpText("after", HELP_AFTER5).action(async (pageGuid, opts, cmd) => {
2232
- const globalOpts = cmd.optsWithGlobals();
2233
- const client = createApiClient({
2234
- ...globalOpts.hostname !== void 0 && { hostnameOverride: globalOpts.hostname }
2235
- });
2236
- const workspaceGuid = opts.workspace ?? await resolveWorkspaceGuid(client);
2237
- const params = {};
2238
- const limit = clampLimit3(opts.limit);
2239
- if (limit !== void 0) params["limit"] = limit;
2240
- if (opts.cursor) params["cursor"] = opts.cursor;
2241
- const res = await client.getJson(
2242
- `/v1/external/workspaces/${encodeURIComponent(workspaceGuid)}/wiki/pages/${encodeURIComponent(pageGuid)}/mentions`,
2243
- WikiMentionListResponseSchema,
2244
- params
2245
- );
2246
- const mode = resolveOutputMode(globalOpts);
2247
- if (mode === "json") {
2248
- for (const item of res.items) printNdjson(item);
2249
- const next = nextCursor(res.nextCursorCreatedAt, res.nextCursorId);
2250
- if (next) printNdjson({ _cursor: next });
2251
- } else {
2252
- printPretty5(res.items, globalOpts);
2253
- }
2254
- });
2255
- }
2256
- function clampLimit3(raw) {
2257
- if (!raw) return void 0;
2258
- const n = parseInt(raw, 10);
2259
- if (!Number.isFinite(n) || n <= 0) return void 0;
2260
- return Math.min(n, MAX_LIMIT);
2261
- }
2262
- function nextCursor(createdAt, id) {
2263
- if (createdAt === null || id === null) return null;
2264
- const millis = Date.parse(createdAt);
2265
- if (Number.isNaN(millis)) return null;
2266
- return `${millis}_${id}`;
2267
- }
2268
- function printPretty5(items, opts) {
2269
- if (items.length === 0) {
2270
- process.stdout.write(`${color("(no mentions)", "gray", opts)}
2271
- `);
2272
- return;
2273
- }
2274
- for (const m of items) {
2275
- const date = m.createdAt.slice(0, 10);
2276
- process.stdout.write(
2277
- `${color(date, "gray", opts)} ${color(m.kind, "cyan", opts)} ${m.extractedText}
2278
- `
2279
- );
2280
- }
2281
- }
2282
-
2283
- // src/commands/wiki/graph.ts
2284
- import "commander";
2285
- var MODES = ["seed", "expand", "around", "links"];
2286
- var MAX_QUERY_LENGTH2 = 500;
2287
- var GRAPH_CAP_DEFAULT = 50;
2288
- var HELP_AFTER6 = `
269
+ `;function IA(e){e.command("mentions <pageGuid>").description("List the note mentions that reference a single wiki page.").option("--limit <n>",`Max mentions per page (max ${EA})`).option("--cursor <token>","Continue from a previous page's cursor token.").option("--workspace <guid>","Target a specific workspace (from `tiro wiki workspaces`); defaults to your default workspace").addHelpText("after",Ur).action(async(A,t,r)=>{let o=r.optsWithGlobals(),i=k({...o.hostname!==void 0&&{hostnameOverride:o.hostname}}),s=t.workspace??await E(i),c={},l=jr(t.limit);l!==void 0&&(c.limit=l),t.cursor&&(c.cursor=t.cursor);let p=await i.getJson(`/v1/external/workspaces/${encodeURIComponent(s)}/wiki/pages/${encodeURIComponent(A)}/mentions`,ze,c);if(b(o)==="json"){for(let y of p.items)v(y);let w=Qr(p.nextCursorCreatedAt,p.nextCursorId);w&&v({_cursor:w})}else zr(p.items,o)})}function jr(e){if(!e)return;let A=parseInt(e,10);if(!(!Number.isFinite(A)||A<=0))return Math.min(A,EA)}function Qr(e,A){if(e===null||A===null)return null;let t=Date.parse(e);return Number.isNaN(t)?null:`${t}_${A}`}function zr(e,A){if(e.length===0){process.stdout.write(`${a("(no mentions)","gray",A)}
270
+ `);return}for(let t of e){let r=t.createdAt.slice(0,10);process.stdout.write(`${a(r,"gray",A)} ${a(t.kind,"cyan",A)} ${t.extractedText}
271
+ `)}}import"commander";var ge=["seed","expand","around","links"],OA=500,Yr=50,Kr=`
2289
272
  Modes (--mode, default: around):
2290
273
  around Neighborhood around <pageGuid> (--radius hops, default 2)
2291
274
  expand Outward expansion from <pageGuid> (--depth hops, default 1)
@@ -2302,292 +285,40 @@ Examples:
2302
285
  Returns a node+edge slice of the workspace wiki graph. The workspace defaults
2303
286
  to the one implicit in your API key; pass --workspace to target a specific
2304
287
  workspace (from 'tiro wiki workspaces').
2305
- `;
2306
- function registerWikiGraph(parent) {
2307
- parent.command("graph [pageGuid]").description("Get a node+edge slice of the wiki link graph around a page.").option("--mode <mode>", `Graph mode: ${MODES.join(" | ")} (default: around)`).option("--depth <n>", "expand mode: link-hops to traverse outward (default 1)").option("--radius <n>", "around mode: neighborhood radius in hops (default 2)").option("--limit <n>", "Max nodes to return (max 200)").option("--page <guid>", "links mode: additional page guid (repeatable)", collect, []).option("--type <type>", "seed mode: restrict to a page type (CONCEPT|DECISION|ENTITY)").option("--since <date>", "seed mode: only pages updated at/after this date").option("--query <keyword>", "seed mode: keyword to seed the overview graph").option("--workspace <guid>", "Target a specific workspace (from `tiro wiki workspaces`); defaults to your default workspace").addHelpText("after", HELP_AFTER6).action(async (pageGuid, opts, cmd) => {
2308
- const globalOpts = cmd.optsWithGlobals();
2309
- const mode = parseMode(opts.mode);
2310
- if ((mode === "expand" || mode === "around") && !pageGuid) {
2311
- throw new TiroError(
2312
- {
2313
- code: "missing_page_guid",
2314
- message: `--mode ${mode} requires a <pageGuid> positional argument.`,
2315
- errorType: "bad_request",
2316
- suggestion: `tiro wiki graph <pageGuid> --mode ${mode}`
2317
- },
2318
- ExitCode.Usage
2319
- );
2320
- }
2321
- const client = createApiClient({
2322
- ...globalOpts.hostname !== void 0 && { hostnameOverride: globalOpts.hostname }
2323
- });
2324
- const workspaceGuid = opts.workspace ?? await resolveWorkspaceGuid(client);
2325
- const effectiveLimit = mode === "links" ? void 0 : clampInt(opts.limit, 200) ?? GRAPH_CAP_DEFAULT;
2326
- const raw = await fetchGraph(client, workspaceGuid, mode, pageGuid ?? "", opts, effectiveLimit);
2327
- const res = applyGraphCap(raw, effectiveLimit ?? raw.nodes.length);
2328
- const mode2 = resolveOutputMode(globalOpts);
2329
- if (mode2 === "json") {
2330
- printOutput({ ok: true, data: res }, globalOpts);
2331
- } else {
2332
- printPretty6(res, globalOpts);
2333
- }
2334
- });
2335
- }
2336
- async function fetchGraph(client, workspaceGuid, mode, pageGuid, opts, limit) {
2337
- const base = `/v1/external/workspaces/${encodeURIComponent(workspaceGuid)}/wiki/graph`;
2338
- if (mode === "expand") {
2339
- return client.getJson(`${base}/expand`, WikiGraphResponseSchema, {
2340
- pageGuid,
2341
- depth: clampInt(opts.depth, 200),
2342
- limit
2343
- });
2344
- }
2345
- if (mode === "around") {
2346
- return client.getJson(`${base}/around`, WikiGraphResponseSchema, {
2347
- pageGuid,
2348
- radius: clampInt(opts.radius, 200),
2349
- limit
2350
- });
2351
- }
2352
- if (mode === "links") {
2353
- const guids = [pageGuid, ...opts.page ?? []].filter((g) => g && g.length > 0);
2354
- return client.getJson(`${base}/links`, WikiGraphResponseSchema, {
2355
- pageGuids: guids.join(",")
2356
- });
2357
- }
2358
- const rawQuery = opts.query;
2359
- const clampedQuery = rawQuery && rawQuery.length > MAX_QUERY_LENGTH2 ? rawQuery.slice(0, MAX_QUERY_LENGTH2) : rawQuery;
2360
- return client.getJson(`${base}/seed`, WikiGraphResponseSchema, {
2361
- type: opts.type,
2362
- since: opts.since ? parseDate(opts.since) : void 0,
2363
- q: clampedQuery,
2364
- limit
2365
- });
2366
- }
2367
- function parseMode(raw) {
2368
- if (!raw) return "around";
2369
- const m = raw.toLowerCase();
2370
- if (MODES.includes(m)) return m;
2371
- throw new TiroError(
2372
- {
2373
- code: "invalid_mode",
2374
- message: `Invalid --mode "${raw}". Allowed: ${MODES.join(", ")}.`,
2375
- errorType: "bad_request",
2376
- suggestion: "tiro wiki graph <pageGuid> --mode around"
2377
- },
2378
- ExitCode.Usage
2379
- );
2380
- }
2381
- function clampInt(raw, max) {
2382
- if (!raw) return void 0;
2383
- const n = parseInt(raw, 10);
2384
- if (!Number.isFinite(n) || n <= 0) return void 0;
2385
- return Math.min(n, max);
2386
- }
2387
- function collect(value, prev) {
2388
- return [...prev, value];
2389
- }
2390
- function applyGraphCap(graph, limit) {
2391
- const keptNodes = graph.nodes.slice(0, limit);
2392
- const keptGuids = new Set(keptNodes.map((n) => n.guid));
2393
- const keptEdges = graph.edges.filter(
2394
- (e) => keptGuids.has(e.sourcePageGuid) && keptGuids.has(e.targetPageGuid)
2395
- );
2396
- const truncated = graph.nodes.length > limit || keptEdges.length < graph.edges.length;
2397
- return { ...graph, nodes: keptNodes, edges: keptEdges, truncated };
2398
- }
2399
- function printPretty6(res, opts) {
2400
- const w = process.stdout.write.bind(process.stdout);
2401
- w(
2402
- `${color("nodes", "gray", opts)} ${res.nodes.length} ${color("edges", "gray", opts)} ${res.edges.length}
2403
- `
2404
- );
2405
- if (res.truncated) {
2406
- w(
2407
- `${color(`(truncated \u2014 showing first ${res.nodes.length} nodes; narrow with --query / --type / smaller --radius)`, "gray", opts)}
2408
- `
2409
- );
2410
- }
2411
- w("\n");
2412
- for (const n of res.nodes) {
2413
- w(`${color("\u25CF", "cyan", opts)} ${color(n.guid, "dim", opts)} ${n.canonicalName}
2414
- `);
2415
- }
2416
- if (res.edges.length > 0) w("\n");
2417
- for (const e of res.edges) {
2418
- const arrow = e.isDirectional ? "\u2192" : "\u2014";
2419
- w(
2420
- `${color(e.sourcePageGuid, "dim", opts)} ${arrow} ${color(e.targetPageGuid, "dim", opts)} ${color(e.linkType, "gray", opts)}
2421
- `
2422
- );
2423
- }
2424
- }
2425
-
2426
- // src/commands/wiki/workspaces.ts
2427
- import "commander";
2428
- var HELP_AFTER7 = `
288
+ `;function PA(e){e.command("graph [pageGuid]").description("Get a node+edge slice of the wiki link graph around a page.").option("--mode <mode>",`Graph mode: ${ge.join(" | ")} (default: around)`).option("--depth <n>","expand mode: link-hops to traverse outward (default 1)").option("--radius <n>","around mode: neighborhood radius in hops (default 2)").option("--limit <n>","Max nodes to return (max 200)").option("--page <guid>","links mode: additional page guid (repeatable)",$r,[]).option("--type <type>","seed mode: restrict to a page type (CONCEPT|DECISION|ENTITY)").option("--since <date>","seed mode: only pages updated at/after this date").option("--query <keyword>","seed mode: keyword to seed the overview graph").option("--workspace <guid>","Target a specific workspace (from `tiro wiki workspaces`); defaults to your default workspace").addHelpText("after",Kr).action(async(A,t,r)=>{let o=r.optsWithGlobals(),i=Jr(t.mode);if((i==="expand"||i==="around")&&!A)throw new u({code:"missing_page_guid",message:`--mode ${i} requires a <pageGuid> positional argument.`,errorType:"bad_request",suggestion:`tiro wiki graph <pageGuid> --mode ${i}`},d.Usage);let s=k({...o.hostname!==void 0&&{hostnameOverride:o.hostname}}),c=t.workspace??await E(s),l=i==="links"?void 0:fe(t.limit,200)??Yr,p=await Zr(s,c,i,A??"",t,l),m=_r(p,l??p.nodes.length);b(o)==="json"?C({ok:!0,data:m},o):eo(m,o)})}async function Zr(e,A,t,r,o,i){let s=`/v1/external/workspaces/${encodeURIComponent(A)}/wiki/graph`;if(t==="expand")return e.getJson(`${s}/expand`,V,{pageGuid:r,depth:fe(o.depth,200),limit:i});if(t==="around")return e.getJson(`${s}/around`,V,{pageGuid:r,radius:fe(o.radius,200),limit:i});if(t==="links"){let p=[r,...o.page??[]].filter(m=>m&&m.length>0);return e.getJson(`${s}/links`,V,{pageGuids:p.join(",")})}let c=o.query,l=c&&c.length>OA?c.slice(0,OA):c;return e.getJson(`${s}/seed`,V,{type:o.type,since:o.since?I(o.since):void 0,q:l,limit:i})}function Jr(e){if(!e)return"around";let A=e.toLowerCase();if(ge.includes(A))return A;throw new u({code:"invalid_mode",message:`Invalid --mode "${e}". Allowed: ${ge.join(", ")}.`,errorType:"bad_request",suggestion:"tiro wiki graph <pageGuid> --mode around"},d.Usage)}function fe(e,A){if(!e)return;let t=parseInt(e,10);if(!(!Number.isFinite(t)||t<=0))return Math.min(t,A)}function $r(e,A){return[...A,e]}function _r(e,A){let t=e.nodes.slice(0,A),r=new Set(t.map(s=>s.guid)),o=e.edges.filter(s=>r.has(s.sourcePageGuid)&&r.has(s.targetPageGuid)),i=e.nodes.length>A||o.length<e.edges.length;return{...e,nodes:t,edges:o,truncated:i}}function eo(e,A){let t=process.stdout.write.bind(process.stdout);t(`${a("nodes","gray",A)} ${e.nodes.length} ${a("edges","gray",A)} ${e.edges.length}
289
+ `),e.truncated&&t(`${a(`(truncated \u2014 showing first ${e.nodes.length} nodes; narrow with --query / --type / smaller --radius)`,"gray",A)}
290
+ `),t(`
291
+ `);for(let r of e.nodes)t(`${a("\u25CF","cyan",A)} ${a(r.guid,"dim",A)} ${r.canonicalName}
292
+ `);e.edges.length>0&&t(`
293
+ `);for(let r of e.edges){let o=r.isDirectional?"\u2192":"\u2014";t(`${a(r.sourcePageGuid,"dim",A)} ${o} ${a(r.targetPageGuid,"dim",A)} ${a(r.linkType,"gray",A)}
294
+ `)}}import"commander";var Ao=`
2429
295
  Examples:
2430
296
  tiro wiki workspaces
2431
297
  tiro wiki workspaces --json
2432
298
 
2433
299
  Lists all workspaces you are a member of. Use the guid with --workspace on
2434
300
  any other wiki command to target a non-default workspace.
2435
- `;
2436
- function registerWikiWorkspaces(parent) {
2437
- parent.command("workspaces").description("List all workspaces you are a member of (use guid with --workspace).").addHelpText("after", HELP_AFTER7).action(async (_opts, cmd) => {
2438
- const globalOpts = cmd.optsWithGlobals();
2439
- const client = createApiClient({
2440
- ...globalOpts.hostname !== void 0 && { hostnameOverride: globalOpts.hostname }
2441
- });
2442
- const workspaces = await listWorkspaces(client);
2443
- const mode = resolveOutputMode(globalOpts);
2444
- if (mode === "json") {
2445
- for (const ws of workspaces) printNdjson(ws);
2446
- } else {
2447
- printPretty7(workspaces, globalOpts);
2448
- }
2449
- });
2450
- }
2451
- function printPretty7(workspaces, opts) {
2452
- if (workspaces.length === 0) {
2453
- process.stdout.write(`${color("(no workspaces)", "gray", opts)}
2454
- `);
2455
- return;
2456
- }
2457
- for (const ws of workspaces) {
2458
- const wikiStatus = ws.isWikiEnabled ? color("wiki:on", "green", opts) : color("wiki:off", "gray", opts);
2459
- process.stdout.write(
2460
- `${color(ws.guid, "dim", opts)} ${wikiStatus} ${ws.name}
2461
- `
2462
- );
2463
- }
2464
- }
2465
-
2466
- // src/commands/wiki/index.ts
2467
- function registerWiki(program) {
2468
- const wiki = program.command("wiki").description("Search and explore the workspace wiki (pages, mentions, link graph)");
2469
- registerWikiSearch(wiki);
2470
- registerWikiPage(wiki);
2471
- registerWikiMentions(wiki);
2472
- registerWikiGraph(wiki);
2473
- registerWikiWorkspaces(wiki);
2474
- }
2475
-
2476
- // src/commands/mcp/index.ts
2477
- import "commander";
2478
-
2479
- // src/commands/mcp/info.ts
2480
- import "commander";
2481
- function registerMcpInfo(parent) {
2482
- parent.command("info").description("Show Tiro MCP endpoint and connection instructions").action((_opts, cmd) => {
2483
- const globalOpts = cmd.optsWithGlobals();
2484
- printOutput(
2485
- {
2486
- ok: true,
2487
- data: {
2488
- name: HOSTED_MCP_NAME,
2489
- transport: "http",
2490
- url: HOSTED_MCP_URL,
2491
- docs: HOSTED_MCP_DOCS,
2492
- install: {
2493
- claudeCode: `claude mcp add --transport http ${HOSTED_MCP_NAME} ${HOSTED_MCP_URL}`
2494
- }
2495
- }
2496
- },
2497
- globalOpts
2498
- );
2499
- });
2500
- }
2501
-
2502
- // src/commands/mcp/install.ts
2503
- import "commander";
2504
- function registerMcpInstall(parent) {
2505
- parent.command("install").description("Print the one-line command to add Tiro MCP to Claude Code").option(
2506
- "--print",
2507
- "Print the raw `claude mcp add ...` command to stdout (default behavior)"
2508
- ).action((opts, cmd) => {
2509
- const globalOpts = cmd.optsWithGlobals();
2510
- const command = `claude mcp add --transport http ${HOSTED_MCP_NAME} ${HOSTED_MCP_URL}`;
2511
- if (globalOpts.json) {
2512
- printOutput(
2513
- { ok: true, data: { command, name: HOSTED_MCP_NAME, url: HOSTED_MCP_URL } },
2514
- globalOpts
2515
- );
2516
- return;
2517
- }
2518
- if (process.stdout.isTTY && opts.print !== true) {
2519
- process.stderr.write(
2520
- "Run this in your terminal to register Tiro MCP with Claude Code:\n\n"
2521
- );
2522
- }
2523
- process.stdout.write(`${command}
2524
- `);
2525
- });
2526
- }
301
+ `;function XA(e){e.command("workspaces").description("List all workspaces you are a member of (use guid with --workspace).").addHelpText("after",Ao).action(async(A,t)=>{let r=t.optsWithGlobals(),o=k({...r.hostname!==void 0&&{hostnameOverride:r.hostname}}),i=await _e(o);if(b(r)==="json")for(let c of i)v(c);else to(i,r)})}function to(e,A){if(e.length===0){process.stdout.write(`${a("(no workspaces)","gray",A)}
302
+ `);return}for(let t of e){let r=t.isWikiEnabled?a("wiki:on","green",A):a("wiki:off","gray",A);process.stdout.write(`${a(t.guid,"dim",A)} ${r} ${t.name}
303
+ `)}}function SA(e){let A=e.command("wiki").description("Search and explore the workspace wiki (pages, mentions, link graph)");BA(A),RA(A),IA(A),PA(A),XA(A)}import"commander";import"commander";function FA(e){e.command("info").description("Show Tiro MCP endpoint and connection instructions").action((A,t)=>{let r=t.optsWithGlobals();C({ok:!0,data:{name:W,transport:"http",url:H,docs:DA,install:{claudeCode:`claude mcp add --transport http ${W} ${H}`}}},r)})}import"commander";function qA(e){e.command("install").description("Print the one-line command to add Tiro MCP to Claude Code").option("--print","Print the raw `claude mcp add ...` command to stdout (default behavior)").action((A,t)=>{let r=t.optsWithGlobals(),o=`claude mcp add --transport http ${W} ${H}`;if(r.json){C({ok:!0,data:{command:o,name:W,url:H}},r);return}process.stdout.isTTY&&A.print!==!0&&process.stderr.write(`Run this in your terminal to register Tiro MCP with Claude Code:
2527
304
 
2528
- // src/commands/mcp/index.ts
2529
- var HOSTED_MCP_URL = "https://mcp.tiro.ooo/mcp";
2530
- var HOSTED_MCP_NAME = "tiro";
2531
- var HOSTED_MCP_DOCS = "https://api-docs.tiro.ooo/mcp";
2532
- function registerMcp(program) {
2533
- const mcp = program.command("mcp").description("Connect Tiro MCP from agent clients (Claude Code, etc.)");
2534
- registerMcpInfo(mcp);
2535
- registerMcpInstall(mcp);
2536
- }
2537
-
2538
- // src/lib/updateCheck.ts
2539
- import updateNotifier from "update-notifier";
2540
- import { readFile } from "fs/promises";
2541
- import { fileURLToPath as fileURLToPath2 } from "url";
2542
- import { dirname as dirname3, resolve as resolve3 } from "path";
2543
- var HERE2 = dirname3(fileURLToPath2(import.meta.url));
2544
- var CANDIDATE_PATHS2 = [
2545
- resolve3(HERE2, "../../package.json"),
2546
- resolve3(HERE2, "../../../package.json")
2547
- ];
2548
- var ONE_DAY_MS = 24 * 60 * 60 * 1e3;
2549
- async function startUpdateCheck() {
2550
- if (process.env["NO_UPDATE_NOTIFIER"] === "1") return null;
2551
- if (process.env["CI"]) return null;
2552
- if (process.stdout.isTTY !== true) return null;
2553
- const pkg = await loadPkg();
2554
- if (!pkg) return null;
2555
- try {
2556
- const factory = updateNotifier;
2557
- return factory({
2558
- pkg,
2559
- updateCheckInterval: ONE_DAY_MS,
2560
- shouldNotifyInNpmScript: false
2561
- });
2562
- } catch {
2563
- return null;
2564
- }
2565
- }
2566
- function emitUpdateBanner(notifier) {
2567
- if (!notifier) return;
2568
- if (!notifier.update) return;
2569
- notifier.notify({
2570
- isGlobal: true,
2571
- defer: false,
2572
- message: "Update available {currentVersion} \u2192 {latestVersion}\nRun npm install -g {packageName} to update\n\nChangelog: https://www.npmjs.com/package/{packageName}?activeTab=versions"
2573
- });
2574
- }
2575
- async function loadPkg() {
2576
- for (const path of CANDIDATE_PATHS2) {
2577
- try {
2578
- const raw = await readFile(path, "utf8");
2579
- const parsed = JSON.parse(raw);
2580
- if (typeof parsed.name === "string" && typeof parsed.version === "string" && parsed.name.length > 0 && parsed.version.length > 0) {
2581
- return { name: parsed.name, version: parsed.version };
2582
- }
2583
- } catch {
2584
- }
2585
- }
2586
- return null;
2587
- }
2588
-
2589
- // src/bin/tiro.ts
2590
- var EXAMPLES = `
305
+ `),process.stdout.write(`${o}
306
+ `)})}var H="https://mcp.tiro.ooo/mcp",W="tiro",DA="https://api-docs.tiro.ooo/mcp";function MA(e){let A=e.command("mcp").description("Connect Tiro MCP from agent clients (Claude Code, etc.)");FA(A),qA(A)}import"commander";import{spawn as no}from"child_process";import{z as HA}from"zod";var ro="https://registry.npmjs.org",oo=HA.object({version:HA.string().min(1)}).passthrough();async function GA(e){let A=`${ro}/${e}/latest`,t;try{t=await fetch(A,{headers:{accept:"application/json"}})}catch(o){throw WA(`Could not reach the npm registry: ${o.message}`)}if(!t.ok)throw WA(`npm registry returned ${t.status} for ${e}`,t.status);let r=oo.safeParse(await t.json().catch(()=>null));if(!r.success)throw new u({code:"internal_error",message:"Unexpected npm registry response shape",errorType:"internal_error"},d.Generic);return r.data.version}function WA(e,A){return new u({code:"registry_unreachable",message:e,errorType:"network_error",...A!==void 0&&{httpStatus:A},suggestion:"Check your network and retry, or upgrade manually with your package manager."},d.Generic)}function VA(e,A){let t=NA(e),r=NA(A);return t[0]!==r[0]?t[0]>r[0]:t[1]!==r[1]?t[1]>r[1]:t[2]>r[2]}function NA(e){let t=(e.trim().replace(/^v/,"").split(/[-+]/)[0]??"").split(".");return[he(t[0]),he(t[1]),he(t[2])]}function he(e){let A=Number.parseInt(e??"",10);return Number.isFinite(A)?A:0}var UA=["npm","pnpm","yarn","bun"];function jA(e){if(e!==void 0){if(UA.includes(e))return e;throw new u({code:"bad_request",message:`Unknown package manager '${e}'.`,suggestion:`Use one of: ${UA.join(", ")}.`,errorType:"bad_request"},d.Usage)}}function QA(e=process.argv[1]??"",A=process.env.npm_config_user_agent??""){let t=A.toLowerCase().split("/")[0];if(t==="pnpm"||t==="yarn"||t==="bun")return t;let r=e.toLowerCase().split(/[\\/]/);for(let o of["pnpm","yarn","bun"])if(r.includes(o)||r.includes(`.${o}`))return o;return"npm"}function zA(e,A){let t=`${A}@latest`,o={npm:["install","-g",t],pnpm:["add","-g",t],yarn:["global","add",t],bun:["add","-g",t]}[e];return{cmd:e,args:o,display:`${e} ${o.join(" ")}`}}async function YA(e,A){let t=jA(e.pm)??QA(),r=zA(t,S),o=await GA(S),i=VA(o,O),s={name:S,current:O,latest:o};if(e.check){C({ok:!0,data:{...s,updateAvailable:i,command:r.display}},A);return}if(!i){C({ok:!0,data:{...s,updateAvailable:!1,message:"Already up to date."}},A);return}if(e.dryRun){C({ok:!0,data:{...s,command:r.display,dryRun:!0}},A);return}await io(r,o,A)}async function io(e,A,t){t.quiet!==!0&&process.stderr.write(`${a("\u27F3","cyan",t)} Updating ${S} ${O} \u2192 ${A} via ${e.cmd}\u2026
307
+ `);let r=await so(e);if(r!==0)throw KA(e,`${e.cmd} exited with code ${r}.`);C({ok:!0,data:{updated:!0,name:S,from:O,to:A}},t)}function so(e){return new Promise((A,t)=>{let r=no(e.cmd,e.args,{stdio:["ignore",2,2],shell:!1});r.on("error",o=>t(KA(e,`Could not launch ${e.cmd}: ${o.message}`))),r.on("close",o=>A(o??1))})}function KA(e,A){return new u({code:"update_failed",message:A,suggestion:`Run it manually: ${e.display}`,errorType:"internal_error"},d.Generic)}var ao=`
308
+ Examples:
309
+ tiro update # upgrade to the latest published version
310
+ tiro update --check # report current vs latest (JSON for agents/CI)
311
+ tiro update --check --json
312
+ tiro update --dry-run # print the upgrade command without running it
313
+ tiro update --pm pnpm # force a package manager
314
+
315
+ Self-updates by running your global package manager \u2014 auto-detected (npm, pnpm,
316
+ yarn, bun), or forced with --pm. '--check' never installs: it exits 0 and reports
317
+ 'updateAvailable', so agents and CI can detect a new version without a TTY banner.
318
+ `;function ZA(e){e.command("update").description("Upgrade tiro to the latest published version (self-update).").option("--check","Report whether a newer version exists; do not install").option("--dry-run","Print the upgrade command without running it").option("--pm <manager>","Force package manager: npm | pnpm | yarn | bun").addHelpText("after",ao).action(async(A,t)=>{let r=t.optsWithGlobals();await YA(A,r)})}import co from"update-notifier";import{readFile as po}from"fs/promises";import{fileURLToPath as uo}from"url";import{dirname as lo,resolve as JA}from"path";var $A=lo(uo(import.meta.url)),mo=[JA($A,"../../package.json"),JA($A,"../../../package.json")],go=1440*60*1e3;async function _A(){if(process.env.NO_UPDATE_NOTIFIER==="1"||process.env.CI||process.stdout.isTTY!==!0)return null;let e=await fo();if(!e)return null;try{return co({pkg:e,updateCheckInterval:go,shouldNotifyInNpmScript:!1})}catch{return null}}function et(e){e&&e.update&&e.notify({isGlobal:!0,defer:!1,message:`Update available {currentVersion} \u2192 {latestVersion}
319
+ Run \`tiro update\` to upgrade
320
+
321
+ Changelog: https://www.npmjs.com/package/{packageName}?activeTab=versions`})}async function fo(){for(let e of mo)try{let A=await po(e,"utf8"),t=JSON.parse(A);if(typeof t.name=="string"&&typeof t.version=="string"&&t.name.length>0&&t.version.length>0)return{name:t.name,version:t.version}}catch{}return null}var wo=`
2591
322
  EXAMPLES
2592
323
  $ tiro auth login
2593
324
  $ tiro notes list --since 7d
@@ -2595,9 +326,12 @@ EXAMPLES
2595
326
  $ tiro notes get <guid> --output ./meeting.md --include transcript
2596
327
  $ tiro notes transcript <guid> --format md --output ./transcript.md
2597
328
  $ tiro notes transcript <guid> --format md --no-timestamps --output ./clean.md
329
+ $ tiro folders list --workspace <guid>
2598
330
  $ tiro wiki search "onboarding" --json
2599
331
  $ tiro wiki graph <pageGuid> --mode around --radius 2
2600
332
  $ tiro mcp install # one-line setup for Claude Code
333
+ $ tiro update --check # is a newer version available?
334
+ $ tiro update # self-update to the latest version
2601
335
 
2602
336
  ENVIRONMENT
2603
337
  TIRO_TOKEN Bearer token (overrides keychain \u2014 for CI / agents)
@@ -2607,60 +341,9 @@ ENVIRONMENT
2607
341
 
2608
342
  DOCS
2609
343
  https://api-docs.tiro.ooo/cli
2610
- `;
2611
- function buildProgram() {
2612
- const program = new Command19();
2613
- program.name("tiro").description("Tiro AI notes & transcripts \u2014 agent-first command line").version(VERSION, "-v, --version", "Print version").option("--hostname <url>", "API base URL (default: https://api.tiro.ooo)").option("--json", "Force JSON output").option("--pretty", "Force pretty (human) output").option("--quiet", "Suppress non-error output").option("--verbose", "Verbose logging to stderr").option("--no-color", "Disable ANSI colors").addHelpText("after", EXAMPLES);
2614
- program.showHelpAfterError("(run `tiro --help` for available commands)");
2615
- registerAuth(program);
2616
- registerNotes(program);
2617
- registerWiki(program);
2618
- registerMcp(program);
2619
- return program;
2620
- }
2621
- async function main() {
2622
- const program = buildProgram();
2623
- const notifier = await startUpdateCheck();
2624
- try {
2625
- await program.parseAsync(process.argv);
2626
- emitUpdateBanner(notifier);
2627
- } catch (err) {
2628
- handleError(err, program);
2629
- }
2630
- }
2631
- function handleError(err, program) {
2632
- const opts = program.opts();
2633
- if (err instanceof TiroError) {
2634
- if (opts.json) {
2635
- printError(err.toJSON());
2636
- } else if (!opts.quiet) {
2637
- process.stderr.write(`${color("\u2717", "red", opts)} ${err.message}
2638
- `);
2639
- if (err.suggestion) {
2640
- process.stderr.write(` ${color("\u2192", "gray", opts)} ${err.suggestion}
2641
- `);
2642
- }
2643
- }
2644
- process.exit(err.exitCode);
2645
- }
2646
- if (err instanceof Error) {
2647
- if (opts.json) {
2648
- printError({
2649
- ok: false,
2650
- error: { code: "internal_error", message: err.message, errorType: "internal_error" }
2651
- });
2652
- } else if (!opts.quiet) {
2653
- process.stderr.write(`${color("\u2717", "red", opts)} ${err.message}
2654
- `);
2655
- }
2656
- process.exit(ExitCode.Generic);
2657
- }
2658
- process.stderr.write(`Unknown error: ${String(err)}
2659
- `);
2660
- process.exit(ExitCode.Generic);
2661
- }
2662
- main().catch((err) => {
2663
- process.stderr.write(`Fatal: ${String(err)}
2664
- `);
2665
- process.exit(ExitCode.Generic);
2666
- });
344
+ `;function yo(){let e=new ho;return e.name("tiro").description("Tiro AI notes & transcripts \u2014 agent-first command line").version(O,"-v, --version","Print version").option("--hostname <url>","API base URL (default: https://api.tiro.ooo)").option("--json","Force JSON output").option("--pretty","Force pretty (human) output").option("--quiet","Suppress non-error output").option("--verbose","Verbose logging to stderr").option("--no-color","Disable ANSI colors").addHelpText("after",wo),e.showHelpAfterError("(run `tiro --help` for available commands)"),tA(e),hA(e),kA(e),xA(e),SA(e),MA(e),ZA(e),e}async function bo(){let e=yo(),A=await _A();try{await e.parseAsync(process.argv),et(A)}catch(t){ko(t,e)}}function ko(e,A){let t=A.opts();e instanceof u&&(t.json?ne(e.toJSON()):t.quiet||(process.stderr.write(`${a("\u2717","red",t)} ${e.message}
345
+ `),e.suggestion&&process.stderr.write(` ${a("\u2192","gray",t)} ${e.suggestion}
346
+ `)),process.exit(e.exitCode)),e instanceof Error&&(t.json?ne({ok:!1,error:{code:"internal_error",message:e.message,errorType:"internal_error"}}):t.quiet||process.stderr.write(`${a("\u2717","red",t)} ${e.message}
347
+ `),process.exit(d.Generic)),process.stderr.write(`Unknown error: ${String(e)}
348
+ `),process.exit(d.Generic)}bo().catch(e=>{process.stderr.write(`Fatal: ${String(e)}
349
+ `),process.exit(d.Generic)});