html.ha (67907B)
1 // License: GPL-3.0 2 // (c) 2021-2022 Alexey Yerin <yyp@disroot.org> 3 // (c) 2022 Byron Torres <b@torresjrjr.com> 4 // (c) 2021-2022 Drew DeVault <sir@cmpwn.com> 5 // (c) 2021 Eyal Sawady <ecs@d2evs.net> 6 // (c) 2021 Thomas Bracht Laumann Jespersen <t@laumann.xyz> 7 // (c) 2022 Umar Getagazov <umar@handlerug.me> 8 9 // Note: ast::ident should never have to be escaped 10 use bufio; 11 use encoding::utf8; 12 use fmt; 13 use hare::ast; 14 use hare::ast::{variadism}; 15 use hare::lex; 16 use hare::module; 17 use hare::unparse; 18 use io; 19 use net::ip; 20 use net::uri; 21 use os; 22 use path; 23 use strings; 24 use strio; 25 26 // Prints a string to an output handle, escaping any of HTML's reserved 27 // characters. 28 fn html_escape(out: io::handle, in: str) (size | io::error) = { 29 let z = 0z; 30 let iter = strings::iter(in); 31 for (true) { 32 match (strings::next(&iter)) { 33 case void => break; 34 case let rn: rune => 35 z += fmt::fprint(out, switch (rn) { 36 case '&' => 37 yield "&"; 38 case '<' => 39 yield "<"; 40 case '>' => 41 yield ">"; 42 case '"' => 43 yield """; 44 case '\'' => 45 yield "'"; 46 case => 47 yield strings::fromutf8(utf8::encoderune(rn)); 48 })?; 49 }; 50 }; 51 return z; 52 }; 53 54 @test fn html_escape() void = { 55 let sink = strio::dynamic(); 56 defer io::close(&sink)!; 57 html_escape(&sink, "hello world!")!; 58 assert(strio::string(&sink) == "hello world!"); 59 60 let sink = strio::dynamic(); 61 defer io::close(&sink)!; 62 html_escape(&sink, "\"hello world!\"")!; 63 assert(strio::string(&sink) == ""hello world!""); 64 65 let sink = strio::dynamic(); 66 defer io::close(&sink)!; 67 html_escape(&sink, "<hello & 'world'!>")!; 68 assert(strio::string(&sink) == "<hello & 'world'!>"); 69 }; 70 71 // Formats output as HTML 72 fn emit_html(ctx: *context) (void | error) = { 73 const decls = ctx.summary; 74 const ident = unparse::identstr(ctx.ident); 75 defer free(ident); 76 77 if (ctx.template) head(ctx.ident)?; 78 79 if (len(ident) == 0) { 80 fmt::fprintf(ctx.out, "<h2>The Hare standard library <span class='heading-extra'>")?; 81 } else { 82 fmt::fprintf(ctx.out, "<h2>{} <span class='heading-extra'>", ident)?; 83 }; 84 for (let i = 0z; i < len(ctx.tags); i += 1) { 85 const mode = switch (ctx.tags[i].mode) { 86 case module::tag_mode::INCLUSIVE => 87 yield '+'; 88 case module::tag_mode::EXCLUSIVE => 89 yield '-'; 90 }; 91 fmt::fprintf(ctx.out, "{}{} ", mode, ctx.tags[i].name)?; 92 }; 93 fmt::fprintln(ctx.out, "</span></h2>")?; 94 95 match (ctx.readme) { 96 case void => void; 97 case let f: io::file => 98 fmt::fprintln(ctx.out, "<div class='readme'>")?; 99 markup_html(ctx, f)?; 100 fmt::fprintln(ctx.out, "</div>")?; 101 }; 102 103 let identpath = module::identpath(ctx.ident); 104 defer free(identpath); 105 106 let submodules: []str = []; 107 defer free(submodules); 108 109 for (let i = 0z; i < len(ctx.version.subdirs); i += 1) { 110 let dir = ctx.version.subdirs[i]; 111 // XXX: the list of reserved directory names is not yet 112 // finalized. See https://todo.sr.ht/~sircmpwn/hare/516 113 if (dir == "contrib") continue; 114 if (dir == "cmd") continue; 115 if (dir == "docs") continue; 116 if (dir == "ext") continue; 117 if (dir == "vendor") continue; 118 if (dir == "scripts") continue; 119 120 let submod = [identpath, dir]: ast::ident; 121 if (module::lookup(ctx.mctx, submod) is module::error) { 122 continue; 123 }; 124 125 append(submodules, dir); 126 }; 127 128 if (len(submodules) != 0) { 129 if (len(ctx.ident) == 0) { 130 fmt::fprintln(ctx.out, "<h3>Modules</h3>")?; 131 } else { 132 fmt::fprintln(ctx.out, "<h3>Submodules</h3>")?; 133 }; 134 fmt::fprintln(ctx.out, "<ul class='submodules'>")?; 135 for (let i = 0z; i < len(submodules); i += 1) { 136 let submodule = submodules[i]; 137 let path = path::join("/", identpath, submodule); 138 defer free(path); 139 140 fmt::fprintf(ctx.out, "<li><a href='")?; 141 html_escape(ctx.out, path)?; 142 fmt::fprintf(ctx.out, "'>")?; 143 html_escape(ctx.out, submodule)?; 144 fmt::fprintfln(ctx.out, "</a></li>")?; 145 }; 146 fmt::fprintln(ctx.out, "</ul>")?; 147 }; 148 149 if (len(decls.types) == 0 150 && len(decls.errors) == 0 151 && len(decls.constants) == 0 152 && len(decls.globals) == 0 153 && len(decls.funcs) == 0) { 154 return; 155 }; 156 157 fmt::fprintln(ctx.out, "<h3>Index</h3>")?; 158 tocentries(ctx.out, decls.types, "Types", "types")?; 159 tocentries(ctx.out, decls.errors, "Errors", "Errors")?; 160 tocentries(ctx.out, decls.constants, "Constants", "constants")?; 161 tocentries(ctx.out, decls.globals, "Globals", "globals")?; 162 tocentries(ctx.out, decls.funcs, "Functions", "functions")?; 163 164 if (len(decls.types) != 0) { 165 fmt::fprintln(ctx.out, "<h3>Types</h3>")?; 166 for (let i = 0z; i < len(decls.types); i += 1) { 167 details(ctx, decls.types[i])?; 168 }; 169 }; 170 171 if (len(decls.errors) != 0) { 172 fmt::fprintln(ctx.out, "<h3>Errors</h3>")?; 173 for (let i = 0z; i < len(decls.errors); i += 1) { 174 details(ctx, decls.errors[i])?; 175 }; 176 }; 177 178 if (len(decls.constants) != 0) { 179 fmt::fprintln(ctx.out, "<h3>Constants</h3>")?; 180 for (let i = 0z; i < len(decls.constants); i += 1) { 181 details(ctx, decls.constants[i])?; 182 }; 183 }; 184 185 if (len(decls.globals) != 0) { 186 fmt::fprintln(ctx.out, "<h3>Globals</h3>")?; 187 for (let i = 0z; i < len(decls.globals); i += 1) { 188 details(ctx, decls.globals[i])?; 189 }; 190 }; 191 192 if (len(decls.funcs) != 0) { 193 fmt::fprintln(ctx.out, "<h3>Functions</h3>")?; 194 for (let i = 0z; i < len(decls.funcs); i += 1) { 195 details(ctx, decls.funcs[i])?; 196 }; 197 }; 198 }; 199 200 fn comment_html(out: io::handle, s: str) (size | io::error) = { 201 // TODO: handle [[references]] 202 let z = fmt::fprint(out, "<span class='comment'>//")?; 203 z += html_escape(out, s)?; 204 z += fmt::fprint(out, "</span><br>")?; 205 return z; 206 }; 207 208 fn docs_html(out: io::handle, s: str, indent: size) (size | io::error) = { 209 const iter = strings::tokenize(s, "\n"); 210 let z = 0z; 211 for (true) match (strings::next_token(&iter)) { 212 case let s: str => 213 if (!(strings::peek_token(&iter) is void)) { 214 z += comment_html(out, s)?; 215 for (let i = 0z; i < indent; i += 1) { 216 z += fmt::fprint(out, "\t")?; 217 }; 218 }; 219 case void => break; 220 }; 221 222 return z; 223 }; 224 225 fn tocentries( 226 out: io::handle, 227 decls: []ast::decl, 228 name: str, 229 lname: str, 230 ) (void | error) = { 231 if (len(decls) == 0) { 232 return; 233 }; 234 fmt::fprintfln(out, "<h4>{}</h4>", name)?; 235 fmt::fprintln(out, "<pre>")?; 236 let undoc = false; 237 for (let i = 0z; i < len(decls); i += 1) { 238 if (!undoc && decls[i].docs == "") { 239 fmt::fprintfln( 240 out, 241 "{}<span class='comment'>// Undocumented {}:</span>", 242 if (i == 0) "" else "\n", 243 lname)?; 244 undoc = true; 245 }; 246 tocentry(out, decls[i])?; 247 }; 248 fmt::fprint(out, "</pre>")?; 249 return; 250 }; 251 252 fn tocentry(out: io::handle, decl: ast::decl) (void | error) = { 253 fmt::fprintf(out, "{} ", 254 match (decl.decl) { 255 case ast::decl_func => 256 yield "fn"; 257 case []ast::decl_type => 258 yield "type"; 259 case []ast::decl_const => 260 yield "const"; 261 case []ast::decl_global => 262 yield "let"; 263 })?; 264 fmt::fprintf(out, "<a href='#")?; 265 unparse::ident(out, decl_ident(decl))?; 266 fmt::fprintf(out, "'>")?; 267 unparse::ident(out, decl_ident(decl))?; 268 fmt::fprint(out, "</a>")?; 269 270 match (decl.decl) { 271 case let t: []ast::decl_type => void; 272 case let g: []ast::decl_global => 273 let g = g[0]; 274 fmt::fprint(out, ": ")?; 275 type_html(out, 0, g._type, true)?; 276 case let c: []ast::decl_const => 277 let c = c[0]; 278 fmt::fprint(out, ": ")?; 279 type_html(out, 0, c._type, true)?; 280 case let f: ast::decl_func => 281 prototype_html(out, 0, 282 f.prototype.repr as ast::func_type, 283 true)?; 284 }; 285 fmt::fprintln(out, ";")?; 286 return; 287 }; 288 289 fn details(ctx: *context, decl: ast::decl) (void | error) = { 290 fmt::fprintln(ctx.out, "<section class='member'>")?; 291 fmt::fprint(ctx.out, "<h4 id='")?; 292 unparse::ident(ctx.out, decl_ident(decl))?; 293 fmt::fprint(ctx.out, "'>")?; 294 fmt::fprintf(ctx.out, "{} ", match (decl.decl) { 295 case ast::decl_func => 296 yield "fn"; 297 case []ast::decl_type => 298 yield "type"; 299 case []ast::decl_const => 300 yield "def"; 301 case []ast::decl_global => 302 yield "let"; 303 })?; 304 unparse::ident(ctx.out, decl_ident(decl))?; 305 // TODO: Add source URL 306 fmt::fprint(ctx.out, "<span class='heading-extra'><a href='#")?; 307 unparse::ident(ctx.out, decl_ident(decl))?; 308 fmt::fprint(ctx.out, "'>[link]</a> 309 </span>")?; 310 fmt::fprintln(ctx.out, "</h4>")?; 311 312 if (len(decl.docs) == 0) { 313 fmt::fprintln(ctx.out, "<details>")?; 314 fmt::fprintln(ctx.out, "<summary>Show undocumented member</summary>")?; 315 }; 316 317 fmt::fprintln(ctx.out, "<pre class='decl'>")?; 318 unparse_html(ctx.out, decl)?; 319 fmt::fprintln(ctx.out, "</pre>")?; 320 321 if (len(decl.docs) != 0) { 322 const trimmed = trim_comment(decl.docs); 323 defer free(trimmed); 324 const buf = strings::toutf8(trimmed); 325 markup_html(ctx, &bufio::fixed(buf, io::mode::READ))?; 326 } else { 327 fmt::fprintln(ctx.out, "</details>")?; 328 }; 329 330 fmt::fprintln(ctx.out, "</section>")?; 331 return; 332 }; 333 334 fn htmlref(ctx: *context, ref: ast::ident) (void | io::error) = { 335 const ik = 336 match (resolve(ctx, ref)) { 337 case let ik: (ast::ident, symkind) => 338 yield ik; 339 case void => 340 const ident = unparse::identstr(ref); 341 fmt::errorfln("Warning: Unresolved reference: {}", ident)?; 342 fmt::fprintf(ctx.out, "<a href='#' " 343 "class='ref invalid' " 344 "title='This reference could not be found'>{}</a>", 345 ident)?; 346 free(ident); 347 return; 348 }; 349 350 // TODO: The reference is not necessarily in the stdlib 351 const kind = ik.1, id = ik.0; 352 const ident = unparse::identstr(id); 353 switch (kind) { 354 case symkind::LOCAL => 355 fmt::fprintf(ctx.out, "<a href='#{0}' class='ref'>{0}</a>", ident)?; 356 case symkind::MODULE => 357 let ipath = module::identpath(id); 358 defer free(ipath); 359 fmt::fprintf(ctx.out, "<a href='/{}' class='ref'>{}</a>", 360 ipath, ident)?; 361 case symkind::SYMBOL => 362 let ipath = module::identpath(id[..len(id) - 1]); 363 defer free(ipath); 364 fmt::fprintf(ctx.out, "<a href='/{}#{}' class='ref'>{}</a>", 365 ipath, id[len(id) - 1], ident)?; 366 case symkind::ENUM_LOCAL => 367 fmt::fprintf(ctx.out, "<a href='#{}' class='ref'>{}</a>", 368 id[len(id) - 2], ident)?; 369 case symkind::ENUM_REMOTE => 370 let ipath = module::identpath(id[..len(id) - 2]); 371 defer free(ipath); 372 fmt::fprintf(ctx.out, "<a href='/{}#{}' class='ref'>{}</a>", 373 ipath, id[len(id) - 2], ident)?; 374 }; 375 free(ident); 376 }; 377 378 fn markup_html(ctx: *context, in: io::handle) (void | io::error) = { 379 let parser = parsedoc(in); 380 let waslist = false; 381 for (true) { 382 const tok = match (scandoc(&parser)) { 383 case void => 384 if (waslist) { 385 fmt::fprintln(ctx.out, "</ul>")?; 386 }; 387 break; 388 case let tok: token => 389 yield tok; 390 }; 391 match (tok) { 392 case paragraph => 393 if (waslist) { 394 fmt::fprintln(ctx.out, "</ul>")?; 395 waslist = false; 396 }; 397 fmt::fprintln(ctx.out)?; 398 fmt::fprint(ctx.out, "<p>")?; 399 case let tx: text => 400 defer free(tx); 401 match (uri::parse(strings::trim(tx))) { 402 case let uri: uri::uri => 403 defer uri::finish(&uri); 404 if (uri.host is net::ip::addr || len(uri.host as str) > 0) { 405 fmt::fprint(ctx.out, "<a rel='nofollow noopener' href='")?; 406 uri::fmt(ctx.out, &uri)?; 407 fmt::fprint(ctx.out, "'>")?; 408 html_escape(ctx.out, tx)?; 409 fmt::fprint(ctx.out, "</a>")?; 410 } else { 411 html_escape(ctx.out, tx)?; 412 }; 413 case uri::invalid => 414 html_escape(ctx.out, tx)?; 415 }; 416 case let re: reference => 417 htmlref(ctx, re)?; 418 case let sa: sample => 419 if (waslist) { 420 fmt::fprintln(ctx.out, "</ul>")?; 421 waslist = false; 422 }; 423 fmt::fprint(ctx.out, "<pre class='sample'>")?; 424 html_escape(ctx.out, sa)?; 425 fmt::fprint(ctx.out, "</pre>")?; 426 free(sa); 427 case listitem => 428 if (!waslist) { 429 fmt::fprintln(ctx.out, "<ul>")?; 430 waslist = true; 431 }; 432 fmt::fprint(ctx.out, "<li>")?; 433 }; 434 }; 435 fmt::fprintln(ctx.out)?; 436 return; 437 }; 438 439 // Forked from [[hare::unparse]] 440 fn unparse_html(out: io::handle, d: ast::decl) (size | io::error) = { 441 let n = 0z; 442 match (d.decl) { 443 case let c: []ast::decl_const => 444 n += fmt::fprintf(out, "<span class='keyword'>def</span> ")?; 445 for (let i = 0z; i < len(c); i += 1) { 446 n += unparse::ident(out, c[i].ident)?; 447 n += fmt::fprint(out, ": ")?; 448 n += type_html(out, 0, c[i]._type, false)?; 449 if (i + 1 < len(c)) { 450 n += fmt::fprint(out, ", ")?; 451 }; 452 }; 453 case let g: []ast::decl_global => 454 n += fmt::fprintf(out, "<span class='keyword'>{}</span>", 455 if (g[0].is_const) "const " else "let ")?; 456 for (let i = 0z; i < len(g); i += 1) { 457 n += unparse::ident(out, g[i].ident)?; 458 n += fmt::fprint(out, ": ")?; 459 n += type_html(out, 0, g[i]._type, false)?; 460 if (i + 1 < len(g)) { 461 n += fmt::fprint(out, ", ")?; 462 }; 463 }; 464 case let t: []ast::decl_type => 465 n += fmt::fprint(out, "<span class='keyword'>type</span> ")?; 466 for (let i = 0z; i < len(t); i += 1) { 467 n += unparse::ident(out, t[i].ident)?; 468 n += fmt::fprint(out, " = ")?; 469 n += type_html(out, 0, t[i]._type, false)?; 470 if (i + 1 < len(t)) { 471 n += fmt::fprint(out, ", ")?; 472 }; 473 }; 474 case let f: ast::decl_func => 475 n += fmt::fprint(out, switch (f.attrs) { 476 case ast::fndecl_attrs::NONE => 477 yield ""; 478 case ast::fndecl_attrs::FINI => 479 yield "@fini "; 480 case ast::fndecl_attrs::INIT => 481 yield "@init "; 482 case ast::fndecl_attrs::TEST => 483 yield "@test "; 484 })?; 485 let p = f.prototype.repr as ast::func_type; 486 if (p.attrs & ast::func_attrs::NORETURN != 0) { 487 n += fmt::fprint(out, "@noreturn ")?; 488 }; 489 n += fmt::fprint(out, "<span class='keyword'>fn</span> ")?; 490 n += unparse::ident(out, f.ident)?; 491 n += prototype_html(out, 0, 492 f.prototype.repr as ast::func_type, 493 false)?; 494 }; 495 n += fmt::fprint(out, ";")?; 496 return n; 497 }; 498 499 fn enum_html( 500 out: io::handle, 501 indent: size, 502 t: ast::enum_type 503 ) (size | io::error) = { 504 let z = 0z; 505 506 z += fmt::fprint(out, "<span class='type'>enum</span> ")?; 507 if (t.storage != ast::builtin_type::INT) { 508 z += fmt::fprintf(out, "<span class='type'>{}</span> ", 509 unparse::builtin_type(t.storage))?; 510 }; 511 z += fmt::fprintln(out, "{")?; 512 indent += 1; 513 for (let i = 0z; i < len(t.values); i += 1) { 514 for (let i = 0z; i < indent; i += 1) { 515 z += fmt::fprint(out, "\t")?; 516 }; 517 const val = t.values[i]; 518 let wrotedocs = false; 519 if (val.docs != "") { 520 // Check if comment should go above or next to field 521 if (multiline_comment(val.docs)) { 522 z += docs_html(out, val.docs, indent)?; 523 wrotedocs = true; 524 }; 525 }; 526 527 z += fmt::fprint(out, val.name)?; 528 529 match (val.value) { 530 case null => void; 531 case let expr: *ast::expr => 532 z += fmt::fprint(out, " = ")?; 533 z += unparse::expr(out, indent, *expr)?; 534 }; 535 536 z += fmt::fprint(out, ",")?; 537 538 if (val.docs != "" && !wrotedocs) { 539 z += fmt::fprint(out, " ")?; 540 z += docs_html(out, val.docs, 0)?; 541 } else { 542 z += fmt::fprintln(out)?; 543 }; 544 }; 545 indent -= 1; 546 for (let i = 0z; i < indent; i += 1) { 547 z += fmt::fprint(out, "\t")?; 548 }; 549 z += newline(out, indent)?; 550 z += fmt::fprint(out, "}")?; 551 return z; 552 }; 553 554 fn struct_union_html( 555 out: io::handle, 556 indent: size, 557 t: ast::_type, 558 brief: bool, 559 ) (size | io::error) = { 560 let z = 0z; 561 let members = match (t.repr) { 562 case let t: ast::struct_type => 563 z += fmt::fprint(out, "<span class='keyword'>struct</span> {")?; 564 yield t: []ast::struct_member; 565 case let t: ast::union_type => 566 z += fmt::fprint(out, "<span class='keyword'>union</span> {")?; 567 yield t: []ast::struct_member; 568 }; 569 570 indent += 1; 571 for (let i = 0z; i < len(members); i += 1) { 572 const member = members[i]; 573 574 z += newline(out, indent)?; 575 if (member.docs != "" && !brief) { 576 z += docs_html(out, member.docs, indent)?; 577 }; 578 match (member._offset) { 579 case null => void; 580 case let expr: *ast::expr => 581 z += fmt::fprint(out, "@offset(")?; 582 z += unparse::expr(out, indent, *expr)?; 583 z += fmt::fprint(out, ") ")?; 584 }; 585 586 match (member.member) { 587 case let f: ast::struct_field => 588 z += fmt::fprintf(out, "{}: ", f.name)?; 589 z += type_html(out, indent, *f._type, brief)?; 590 case let embed: ast::struct_embedded => 591 z += type_html(out, indent, *embed, brief)?; 592 case let indent: ast::struct_alias => 593 z += unparse::ident(out, indent)?; 594 }; 595 z += fmt::fprint(out, ",")?; 596 }; 597 598 indent -= 1; 599 z += newline(out, indent)?; 600 z += fmt::fprint(out, "}")?; 601 602 return z; 603 }; 604 605 fn type_html( 606 out: io::handle, 607 indent: size, 608 _type: ast::_type, 609 brief: bool, 610 ) (size | io::error) = { 611 if (brief) { 612 let buf = strio::dynamic(); 613 defer io::close(&buf)!; 614 unparse::_type(&buf, indent, _type)?; 615 return html_escape(out, strio::string(&buf))?; 616 }; 617 618 // TODO: More detailed formatter which can find aliases nested deeper in 619 // other types and highlight more keywords, like const 620 let z = 0z; 621 622 if (_type.flags & ast::type_flags::CONST != 0 623 && !(_type.repr is ast::func_type)) { 624 z += fmt::fprint(out, "<span class='keyword'>const</span> ")?; 625 }; 626 627 if (_type.flags & ast::type_flags::ERROR != 0) { 628 if (_type.repr is ast::builtin_type) { 629 z += fmt::fprint(out, "<span class='type'>!</span>")?; 630 } else { 631 z += fmt::fprint(out, "!")?; 632 }; 633 }; 634 635 match (_type.repr) { 636 case let a: ast::alias_type => 637 if (a.unwrap) { 638 z += fmt::fprint(out, "...")?; 639 }; 640 z += unparse::ident(out, a.ident)?; 641 case let t: ast::builtin_type => 642 z += fmt::fprintf(out, "<span class='type'>{}</span>", 643 unparse::builtin_type(t))?; 644 case let t: ast::tagged_type => 645 // rough estimate of current line length 646 let linelen: size = z + (indent + 1) * 8; 647 z = 0; 648 linelen += fmt::fprint(out, "(")?; 649 for (let i = 0z; i < len(t); i += 1) { 650 linelen += type_html(out, indent, *t[i], brief)?; 651 if (i + 1 == len(t)) break; 652 linelen += fmt::fprint(out, " |")?; 653 // use 72 instead of 80 to give a bit of leeway for long 654 // type names 655 if (linelen > 72) { 656 z += linelen; 657 linelen = (indent + 1) * 8; 658 z += fmt::fprintln(out)?; 659 for (let i = 0z; i < indent; i += 1) { 660 z += fmt::fprint(out, "\t")?; 661 }; 662 } else { 663 linelen += fmt::fprint(out, " ")?; 664 }; 665 }; 666 z += linelen; 667 z += fmt::fprint(out, ")")?; 668 case let t: ast::tuple_type => 669 // rough estimate of current line length 670 let linelen: size = z + (indent + 1) * 8; 671 z = 0; 672 linelen += fmt::fprint(out, "(")?; 673 for (let i = 0z; i < len(t); i += 1) { 674 linelen += type_html(out, indent, *t[i], brief)?; 675 if (i + 1 == len(t)) break; 676 linelen += fmt::fprint(out, ",")?; 677 // use 72 instead of 80 to give a bit of leeway for long 678 // type names 679 if (linelen > 72) { 680 z += linelen; 681 linelen = (indent + 1) * 8; 682 z += fmt::fprintln(out)?; 683 for (let i = 0z; i < indent; i += 1) { 684 z += fmt::fprint(out, "\t")?; 685 }; 686 } else { 687 linelen += fmt::fprint(out, " ")?; 688 }; 689 }; 690 z += linelen; 691 z += fmt::fprint(out, ")")?; 692 case let t: ast::pointer_type => 693 if (t.flags & ast::pointer_flags::NULLABLE != 0) { 694 z += fmt::fprint(out, "<span class='type'>nullable</span> ")?; 695 }; 696 z += fmt::fprint(out, "*")?; 697 z += type_html(out, indent, *t.referent, brief)?; 698 case let t: ast::func_type => 699 if (t.attrs & ast::func_attrs::NORETURN == ast::func_attrs::NORETURN) { 700 z += fmt::fprint(out, "@noreturn ")?; 701 }; 702 703 z += fmt::fprint(out, "<span class='keyword'>fn</span>(")?; 704 for (let i = 0z; i < len(t.params); i += 1) { 705 const param = t.params[i]; 706 z += fmt::fprintf(out, "{}: ", 707 if (len(param.name) == 0) "_" else param.name)?; 708 z += type_html(out, indent, *param._type, brief)?; 709 710 if (i + 1 == len(t.params) 711 && t.variadism == ast::variadism::HARE) { 712 // TODO: Highlight that as well 713 z += fmt::fprint(out, "...")?; 714 }; 715 if (i + 1 < len(t.params)) { 716 z += fmt::fprint(out, ", ")?; 717 }; 718 }; 719 if (t.variadism == ast::variadism::C) { 720 z += fmt::fprint(out, ", ...")?; 721 }; 722 z += fmt::fprint(out, ") ")?; 723 z += type_html(out, indent, *t.result, brief)?; 724 case let t: ast::enum_type => 725 z += enum_html(out, indent, t)?; 726 case let t: ast::list_type => 727 z += fmt::fprint(out, "[")?; 728 match (t.length) { 729 case let expr: *ast::expr => 730 z += unparse::expr(out, indent, *expr)?; 731 case ast::len_slice => 732 z += 0; 733 case ast::len_unbounded => 734 z += fmt::fprintf(out, "*")?; 735 case ast::len_contextual => 736 z += fmt::fprintf(out, "_")?; 737 }; 738 z += fmt::fprint(out, "]")?; 739 740 z += type_html(out, indent, *t.members, brief)?; 741 case let t: ast::struct_type => 742 z += struct_union_html(out, indent, _type, brief)?; 743 case let t: ast::union_type => 744 z += struct_union_html(out, indent, _type, brief)?; 745 }; 746 747 return z; 748 }; 749 750 fn prototype_html( 751 out: io::handle, 752 indent: size, 753 t: ast::func_type, 754 brief: bool, 755 ) (size | io::error) = { 756 let n = 0z; 757 n += fmt::fprint(out, "(")?; 758 759 // estimate length of prototype to determine if it should span multiple 760 // lines 761 const linelen = if (len(t.params) == 0 || brief) { 762 yield 0z; // If no parameters or brief, only use one line. 763 } else { 764 let linelen = indent * 8 + 5; 765 linelen += if (len(t.params) != 0) len(t.params) * 3 - 1 else 0; 766 for (let i = 0z; i < len(t.params); i += 1) { 767 const param = t.params[i]; 768 linelen += unparse::_type(io::empty, indent, 769 *param._type)?; 770 linelen += if (param.name == "") 1 else len(param.name); 771 }; 772 switch (t.variadism) { 773 case variadism::NONE => void; 774 case variadism::HARE => 775 linelen += 3; 776 case variadism::C => 777 linelen += 5; 778 }; 779 linelen += unparse::_type(io::empty, indent, *t.result)?; 780 yield linelen; 781 }; 782 783 // use 72 instead of 80 to give a bit of leeway for preceding text 784 if (linelen > 72) { 785 indent += 1; 786 for (let i = 0z; i < len(t.params); i += 1) { 787 const param = t.params[i]; 788 n += newline(out, indent)?; 789 n += fmt::fprintf(out, "{}: ", 790 if (param.name == "") "_" else param.name)?; 791 n += type_html(out, indent, *param._type, brief)?; 792 if (i + 1 == len(t.params) 793 && t.variadism == variadism::HARE) { 794 n += fmt::fprint(out, "...")?; 795 } else { 796 n += fmt::fprint(out, ",")?; 797 }; 798 }; 799 if (t.variadism == variadism::C) { 800 n += newline(out, indent)?; 801 n += fmt::fprint(out, "...")?; 802 }; 803 indent -= 1; 804 n += newline(out, indent)?; 805 } else for (let i = 0z; i < len(t.params); i += 1) { 806 const param = t.params[i]; 807 if (!brief) { 808 n += fmt::fprintf(out, "{}: ", 809 if (param.name == "") "_" else param.name)?; 810 }; 811 n += type_html(out, indent, *param._type, brief)?; 812 if (i + 1 == len(t.params)) { 813 switch (t.variadism) { 814 case variadism::NONE => void; 815 case variadism::HARE => 816 n += fmt::fprint(out, "...")?; 817 case variadism::C => 818 n += fmt::fprint(out, ", ...")?; 819 }; 820 } else { 821 n += fmt::fprint(out, ", ")?; 822 }; 823 }; 824 825 n += fmt::fprint(out, ") ")?; 826 n += type_html(out, indent, *t.result, brief)?; 827 return n; 828 }; 829 830 fn breadcrumb(ident: ast::ident) str = { 831 if (len(ident) == 0) { 832 return ""; 833 }; 834 let buf = strio::dynamic(); 835 fmt::fprintf(&buf, "<a href='/'>stdlib</a> » ")!; 836 for (let i = 0z; i < len(ident) - 1; i += 1) { 837 let ipath = module::identpath(ident[..i+1]); 838 defer free(ipath); 839 fmt::fprintf(&buf, "<a href='/{}'>{}</a>::", ipath, ident[i])!; 840 }; 841 fmt::fprint(&buf, ident[len(ident) - 1])!; 842 return strio::string(&buf); 843 }; 844 845 fn head(ident: ast::ident) (void | error) = { 846 const id = unparse::identstr(ident); 847 defer free(id); 848 849 let breadcrumb = breadcrumb(ident); 850 defer free(breadcrumb); 851 852 const title = 853 if (len(id) == 0) 854 fmt::asprintf("Hare documentation") 855 else 856 fmt::asprintf("{} — Hare documentation", id); 857 defer free(title); 858 859 // TODO: Move bits to +embed? 860 fmt::printfln("<!doctype html> 861 <html lang='en'> 862 <meta charset='utf-8' /> 863 <meta name='viewport' content='width=device-width, initial-scale=1' /> 864 <title>{}</title>", title)?; 865 fmt::println("<style> 866 body { 867 font-family: sans-serif; 868 line-height: 1.3; 869 margin: 0 auto; 870 padding: 0 1rem; 871 } 872 873 nav:not(#TableOfContents) { 874 max-width: calc(800px + 128px + 128px); 875 margin: 1rem auto 0; 876 display: grid; 877 grid-template-rows: auto auto 1fr; 878 grid-template-columns: auto 1fr; 879 grid-template-areas: 880 'logo header' 881 'logo nav' 882 'logo none'; 883 } 884 885 nav:not(#TableOfContents) img { 886 grid-area: logo; 887 } 888 889 nav:not(#TableOfContents) h1 { 890 grid-area: header; 891 margin: 0; 892 padding: 0; 893 } 894 895 nav:not(#TableOfContents) ul { 896 grid-area: nav; 897 margin: 0.5rem 0 0 0; 898 padding: 0; 899 list-style: none; 900 display: flex; 901 flex-direction: row; 902 justify-content: left; 903 flex-wrap: wrap; 904 } 905 906 nav:not(#TableOfContents) li:not(:first-child) { 907 margin-left: 2rem; 908 } 909 910 #TableOfContents { 911 font-size: 1.1rem; 912 } 913 914 main { 915 padding: 0 128px; 916 max-width: 800px; 917 margin: 0 auto; 918 919 } 920 921 pre { 922 background-color: #eee; 923 padding: 0.25rem 1rem; 924 margin: 0 -1rem 1rem; 925 font-size: 1.2rem; 926 max-width: calc(100% + 1rem); 927 overflow-x: auto; 928 } 929 930 pre .keyword { 931 color: #008; 932 } 933 934 pre .type { 935 color: #44F; 936 } 937 938 ol { 939 padding-left: 0; 940 list-style: none; 941 } 942 943 ol li { 944 padding-left: 0; 945 } 946 947 h2, h3, h4 { 948 display: flex; 949 } 950 951 h3 { 952 border-bottom: 1px solid #ccc; 953 padding-bottom: 0.25rem; 954 } 955 956 .invalid { 957 color: red; 958 } 959 960 .heading-extra { 961 align-self: flex-end; 962 flex-grow: 1; 963 text-align: right; 964 font-size: 0.8rem; 965 color: #444; 966 } 967 968 h4:target + pre { 969 background: #ddf; 970 } 971 972 details { 973 background: #eee; 974 margin: 1rem -1rem 1rem; 975 } 976 977 summary { 978 cursor: pointer; 979 padding: 0.5rem 1rem; 980 } 981 982 details pre { 983 margin: 0; 984 } 985 986 .comment { 987 color: #000; 988 font-weight: bold; 989 } 990 991 @media(max-width: 1000px) { 992 main { 993 padding: 0; 994 } 995 } 996 997 @media(prefers-color-scheme: dark) { 998 body { 999 background: #121415; 1000 color: #e1dfdc; 1001 } 1002 1003 img.mascot { 1004 filter: invert(.92); 1005 } 1006 1007 a { 1008 color: #78bef8; 1009 } 1010 1011 a:visited { 1012 color: #48a7f5; 1013 } 1014 1015 summary { 1016 background: #16191c; 1017 } 1018 1019 h3 { 1020 border-bottom: solid #16191c; 1021 } 1022 1023 h4:target + pre { 1024 background: #162329; 1025 } 1026 1027 pre { 1028 background-color: #16191c; 1029 } 1030 1031 pre .keyword { 1032 color: #69f; 1033 } 1034 1035 pre .type { 1036 color: #3cf; 1037 } 1038 1039 .comment { 1040 color: #fff; 1041 } 1042 1043 .heading-extra { 1044 color: #9b9997; 1045 } 1046 } 1047 </style> 1048 <nav> 1049 <img 1050 src='data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAQAAAAEACAAAAAB5Gfe6AAAACXBIWXMAAAsSAAALEgHS3X78AAAAB3RJTUUH5gMYEyIEYHvIjwAAAcJ6VFh0UmF3IHByb2ZpbGUgdHlwZSBpY2MAADiNpVNbjhwhDPznFDmC8bM5Tg80Uu5/gRgM89rZSJtYatGUsV3YRfpda/o1TA0TDMMTtCppMwKmCWnTy9hQkI0RQQ4pciKAXexuAcjqn//nMtakWcnIgLO4lyv8g3WvOhjlDTTCdmf2Q0s/PN+UVYw0CmVcMEPyi4GhcTh0OUjNvEOw8XIEntn5Ht6OhZ+rFViTt3O2MRztEfCCX/WO2xO+CY1meyL2yQRVzLwqgAd8xr85nwZVQ22xp+1g74ULYF3B2b3gvHHbV/Px+5xM9H1Ke5JVRS8RoR2w3J7AWwjsGuI2ZJXiojqU5iJTd6gfGk3GtvZXnBmSEFwJ8J1A+juDfD4YCKxiGMVmEYoizJ5I+3gQ/uUHA3g8iScbCoY3AbumlIjwWZAZKkektKsPI5S5tzIZ9lZg4rczz7WtStTqTFSdxScG2uNmdPRISOUjU+TSg1E/5jRuWvljQiw2/XbMNR/NAc0um/s1R6LdeVS3mRdPiyZImYEUMoNTbi+6C6OdCE5qM1A4BMa1zoOllHNViMRd6ne6281+GzvsN/dFeP+R6FWI6Q/o4R/5iWZdFAAAAAJiS0dEAP+Hj8y/AAAxjElEQVQYGeTB4YIcx5Ueyq+qumcAyfv+r3m9IqarMvOcuA0uScmiZQ6GFPhDEfEfLv7DxX+4+A8X/+HiP1z8h4v/cPEn66J6UTSLRfu7i9NQShVF6/ZHiT9d92I1/+2iT1UsP2mTpZrmTZum5Y8Sf7LL08Bk+WpRflGXc2hG+1IuY5n+OPFnazUxPDXN5Gy/KKrKjy6KovxB4k9WVjHaXM1DXdTUflJYdHP5qpUe/ijxZ3vDYm0vST7l5UiVR/vJoKwpR2577snd0+mPEn+yaY0qeU3PcqXHtudeftHTZSWmMZDEMv1B4k9WuuToapQsLsnmJ0NNxm4J1ReOLf4o8aeZUytLkjZNdDeKxFKM1gZJbCPCwC1BtfY7xZ/l4vJU2aZBPGhmlVz2MC+ay8Mhi0nba5j2XPji94o/zxdVZl7bpT31Mj1VnNuxLyZrsqQ3q3VNKVP1p1yW3y3+JLU8tf1+aVwLhZrWS5myU4W3QWxoT/Fmsm6hht8p/jyPZSXK6VpclKdl0i/qFtZyMbz2NusLzWKsttzj94s/SXcxe1ss2pycrFku3ZWHtXV7WlxZh8kXl5qYy3rcKL9T/FkernIfrYe+FtfQWjgtTPY3Bk1kTpeJ4ovyFL9b/FkWMjiZnk5Oi2qWmriOvbS2kt6bqY1iWZYlh98rvrfuNny1cu/2s+42PFVRVqPSaCu3iv/TXHToYikfFN/ZdKKnWvvh76YTPU2u6elLk7sv1pJiWrSftK/26Gsa7aPiexv6b55KrPaLof+GUhPTsmmhOWNOlr+roV11v5jt4+J7u0z91nMenoafXaZ+6+WpTh7qxD4ul3DOLsrfTSq3+sJcPiq+s+Fp4Lj3sC8/GZ4Gy8NJcXr11qEebvozy98t5aFtGD4uvrdelmvKVf5RL8s1MXX1wH+z9njK6Fx0+T8MlWUwfVR8d12etjBrtV90eeqLuDAxiLXWjRvT8nfX1EWYX0wfFN9ZazUlvjD9orWaIjpEFKWOk7mVqNJ+0b4aHeV3iO9tddObjqmLIq3TLLH2eai974lSYqqQxRu+eFp+cVhl+aj4zpantad4KIY1ZVt1NydpkSnJbWey7WXdp6jiatNaXX4yZ/we8b0NT0Eb01JY95YWMlUdJbJnLbztprAxPE3d/tHOWD4qvrOpTwlvlFYXS1TUXivEZiTZ9sVqn5ghFrP6vspj+FmPmLQPiu+tlZRhWrxxxXXw2jJljVdhr9fEVyODfVtZri66TP8oUZYPiu9ttNxNyzCWoullRgyfajhaVrbwsMaLIVkvogwPtUb52UmYPiq+s2q27cGqYk0dF7E+n4faahLZ51/ycrKIJfG3PgbWzWK2Xzw+XT4uvrvqFNqqpco+qa3rNrW0qr1DnCztuFQyrDKRtsTPmpjLR8X3N2NwWYvolHO9stauUo61Se9hUSX7lER7WutW1vniF9M2Vfmg+M4Kt1ZtstWo+mzxt75INyuOtRE2J+tlqz6i6FM7PaX8pGsE7YPiuzulBuXNK0a62tNy7eYSO6l9SzCcIfvlqzaPy7L7B4nTR8V3Nix7G1o7l9Zbd0cosf9w8zj6Lnk5lkd138hhqlWWXU09/KRn738Zpg+K725Il6ppkiox95vO6SG3ViL2JJ5apmRaZeoOs/xiqUfm9FHxnV3Mvd5Mj0tsppD0vOkusfY6EtuebW/rul7JLkuvE7N1+cXik/JR8b3VEK8T43qptZQ5EmtfgzJ7b1vykiOfxom0ZB6l79rEdPrJhbxZPii+s16k05Zycr/8cBchWomaFbkl97D0Zu4RXaHVYvm7YbN8VHxvo0WYTUgvQzwtKxzdxrYfyS1pT9lXdkGaYsn0i0toHxTf2Wq5m6YuUSZN1Vr3U5pMZcuW5LNVHrJe0mUyaRfxs2K+Xm8+Kr6zZdRuoPS+VIa1TDrYY5tabtnz1C4ztlvjZPa6LJl+tmpsXD4ovrM2hVrLJOxdnk5WPHJMtx/Klsfn5DW+2kQZy5uvqqf/Q8XwQfG9Pbhfiwd17cTT9OmNqNu+BiGyHYlhdl5uGZyKuiyq/KyL+LD4zlZ1BRdN1oVqhuW+zPnJOMy6ObLncxnWnpeYUq7G4M3PiimmD4o/QVqZpjFezcIP7WBOMVt2Ys+R6OZTsof4wqV6lL9r+mW0D4rvrA0xLTSpZSR0ullZ2GNE9uS+Wk9bcnSHjqXVbD8bWnxYfG+r5xZrYbA1Vrqyx7WTLdZtz63zlacam3kbFSXF6UIvSmtsPiy+tybx9GDMXfe0Extq5mVa2ZMceTlSc7nkFLZhxWKxmhlPjc2HxXdW6K1XLZOHLt0jbBciR6YcWz5nS3a0c+/ek90PqPXlxWm67AaNzYfFd7ac6rChit5qN9zq8SnakVviOnIk+3bLPttTSLp49KD3MnXJUhqbD4s/wQqXWqbeh6duK6uItZG5vSZ7XqPM5WZud4LuEk2XLKWx+bD43h6m/aJ5RMdKn24ny+x9p9axbbndsyXBktjfhrDM7n0a02U3aGw+LL6zC2szV42Tzf7F//gyhQR9lZfkduQFVfJalrmmXk0szYynxubD4ntrwxFfrcoeU1itKO7pQ79ecc9Tueh1mCpaYVH0orTG5sPiOytP8za7rZaE0DE/1WIdcV8ix5bcg8bGIRTVZpdfNDYfFt9b6y+iKLP212xFH5QOIX9N7G/325HXk8ZGejPC1M30s8bmw+K7W6x96jVOkvuewRkdInHPkXvkKzQ2InHURflHjc2HxXdX5tpSp6+uueUQVIe9bea13bKv3G7ZQ2Njd4+9XEyr/ayx+bD43kpbYj7MntxeIrknty0z1jZIjmRLsofGZt2GvaOUa2k/a2w+LL6zZaCCQcfKVkdyO5JjiXk77clx5PWehMZG1EY6fapVftbYfFh8b4MvLTEYMt1CXvKSPTpli+xJ/pJ8yk5jI1NUTNuYyy8amw+L760V1z2oJa5tz/maW7YtEWfv2bNl37InB41NsgkHo5TlZ43Nh8X30lYt5WxPHctAuhN5esntPmS550f7Ldk3wyC35Mg92UMa7aK02UT7oPheVhVrehqGrS01PCUen5PckymfZb8luSW37LMsHNn2vCbHvls8jOXeq3y15j58VHwvyzCWHxhY2S1llZH/Fdm35J7bSpzbliP5S/KSw8V0O7Ln6XMyXW82hLqth6e4fFB8J8O0eOOLrkXK8j8S89i3zJfc5EXu2fOSPcmOVonkc55uy1P6FITzfxsxfVB8L2+UVieXpzRdb2rNe1r2bHmS5CXJkSNiM3VxsCW3iPPTFNwva59F9334qPhu2piWtcoyR25W0W3e97TcsudIj5cjtyPJvvXtTKupV9awHfMuXBFVg47loeLD4jspHopiqWF9ztSrzVJHVH70cpPcc2RPxVdl6Xp1c20VR2zxeTRVMmi26aPie+mYupyS/RZrt2iHJcktecltS/p2ZEticupl0FLJlrqPxF6K1axdFYkPi3+XqZaJRZWW7Dk2ueUl2dniUlJtS45sSbYje7Y90eFYD4puWXlNXpbc0jYVgmGpmIyi27eKf5PSw5say8OepK9sW47ctuR1S1Ze3pjCJYnIPcmeLfst0ldYZ7la3yXHjM0IucR5c/lqhGsuQ1m+UfybtNYKQ+cl2V6Sv+6rE4av0pZiDLdse0rymtuxH1uOtRkvY6Ise+S2bS8rrsO8Wy+k9tXLJZenbl2+Vfz7rEmvznZKjhx7vviquQwzL1dpb3T27I7OPfdI8poyraVreEqsmL6aWmcOxNpcR7hMhvat4t+kfZUXRJfeEgxGKU99TzdNG8c9t+SW17zMg8Rc2tMkyldFeWDSnGsjvW/Zg5p6+Fbx75KXNNnP7uFp2lLLshy5ZbUOzu5ZJC+55dgTJV7QLpJsuUWXC+2pHhpL17xb6dp0BrNcvlH8mwxzCxJFr9XNcUyXsTxVy3EtiiGS/ZYtn9P6rczlUCpH56/X0ErpWpen0qVPLrpFDpdq5RvFv0sXBh21uCurbZrSFra0LktpuSWSFSflq0S1bGEpg+Vp9mymp9al7dIshm8Vf5B2sZQTj9tWdLOo3vfSwsWSTWkMKYaTC9lSIYanju51i980GfY2D235RvEHKd0Dy2xkH1brezyNI9PcDhfzyBG9RtijLKau67jf40ed0canlOU9hnWV+yiXbxV/oOWUfZQfLVkuSTHleL081ChPE1mVo7VxuuqQN3Et1eRWarzeht90KSeSat8u/iirJqryv5IcOS7kwEwOgzSKsoZ1uqe9pKoowm75avWbvFaZftsb57LaPF+2nss3ij/KxUi4kmyR6EdJDEbSOPVlWo32t3vkU7NQ97WKVaspjz7dYnX5TcUXT3lZyzeLP8zoHxzJbds/By856LJi0s72o8bwSMwm5lKM/NdUfjRV0yfdfktPTGtI3K/LN4o/SA9cZE9iWdR9O12s5dKcnFZ5MMmmzCPLZTZxWdMPXKj15gvKb9mNpj0lvln8UbZjMbbsObaWozA+h4milkWjqoclq5n7YJahGKo9iqXKSZXfEuvoboYtavlG8bstT6uJJbdsCSuvplWkNF0spXSraa5WqiX08s3a8FTpLWg1NmuxDO3d4ncqqmaOQm9H4pIMe6xW/sf0VGNOS6Nx1mQ6PFqXb7S4nHaiLMOPCpMfvFf8Tstg7Nny9JK5eUqmpA01HkxPdXlq3UtjYTolzOUDFqslDn1xnYxZ66KUd4rf63Kyqh2MZVmWY+fkzdPkMluba9VUtFLrBy7rUzxN32gqTE9RS0/2LZ5OpbxT/G69pqdK8npkz8kw6zIwq8wvnmZfLkc+s2r4qtry/x3O5dtdHqha5+tSejhzbGnTMrxX/F7F2J32bEceVv6yJqs9XawuZlmqVde1Li7T2SYtKMs36kU9TPZ9lZNh+0Haj9o7xe/V45Tck0/Jy7ap8y9Xaee8heZ0Uk6+cKH4b22pPL2sk1W+WQ3N7BgvTPWIIae1vF/8MXIknxLZ9Nq0p0VbTK26sJa2rGbRCqsp367bUkuprGJxXGxRyrvFRxVtkduaSLYsw7bFojWly7+w9DQoZVFOJlM1pmWWVk3xpq1Sy6+VrWnmoVeiKO8VH7aWtuSwOJdh0Y059Mr+RSn/UnnTpzlH4cFJ++pvylgYtKaNunzV/llJxKyWhX3QyjvFBw1PvbSTmZsuTXmYmEuzhn9p6n3L0Z6uwg/EFBcLE7f8yP+4hl+ppnsrVLzpIyjvFR821TSr1Nl9HCeXxuBE1ZiW/4ezjm2rtabWa9Jrz+XwpqpIsr9syWtyVFUv7dfmLIlhya6z5bRM7xQf1ItycnVeyxrWG1UPBs2iSvtXEpIcLldPlJg+zTdVln5J7klekuMlx8ajdfknw1NMp+u2bckRqr1XfFgvtSWbZIsj2e+F2c66DB5c/pXV5hWqS5eljMrRHYNp7fm8Z9+Sly0/ujxK+WePWQl1MZJsybWY3ik+6PLUOTjpKr1WEsPlfmwJ5pv/h/J0XXzhxKQrNQ5O7jmS3HIc2XP7lPM1lF9pLCbzkiPJEf7be8VH9bKo0nqqi25SqieLqZn+hWQcW7AWqrt1EFNRyT17suVIjiRkx/JP2mA+1DQlR+5Jl8s7xUcNqyhlFcWgtT6S6GrahZ7WqbSLXvpi2VqypZmuNoslnmpN5Cdb9txyU+TV5f+iW+FSyZbcbpf3i4+6kG0jt2PLFrUmVYsl1S795TVzMSg9GK62nOxp637y0Cht4ZUHw5CfHduRl7GolVj+yfVmNb247LdkS9rwXvFRRU+tLrV0nu5BO6fF6lYWlsKgFBazGrV442Q1tZgzswdl5B/saevBtrdfm0Yv++y2ktfkv5TpneKjLk9t+R+NWguNOT2tmjy4qPK4bXENnCR7Sud+OYo6q82mdy5T52f3JDfjcjrjV8a6eqkOltc9+WtGebf4oCbJ5Msybsexz6VLXfnqrieW1hOT0qO/KuYIladSszcsPfliiq/yk5fkU1LU5Nj9Snt6vJBlruyv2W6m94oPulz7f52y/Vfum5k9n16WN08XmnVOl2B6Wp2XhLXKV0NicHHpojw8VXsslV9s90QXRrbyT6qnpxibB1u2vKa1d4qP6s5pusraXXgr3W2WOkuXnwxK8pfM6ramaj+4ZWdZwyyXcvnqKv8jP9myHTnSg9z2W/snzdUuwlHe7nlS3is+KLklLK3rSLIdqyfNSbeihtVLL83D0564TKpNJBbj8FR60CaG/OyWLclm9JFs7Z+Upsxi6Elu2bX3im/V3Qa+YGgMhkWXUh5Mv5L9ODKNZlEWyx5OXy0XpvaTZE+ybblnyx7ayHaPp6rlV8qhUFue2jvFN5pO9FzWwDLpbc+epctE9tWXX3lgUnq1yZJt9tRm+Wosy8+yZ8+e7DnykqTldiQZg2b6tdRLs9z2/K94p/hWQ/8NK0nbDqr6yJ7sJFvyKdOvdfuB3OOpdC35vPQR3KZhcPq7JPcct+y5bTm8XJIjNyaXX1tKBmt0Eu8V3+oy9VsfsawjD1Xbltu++6G7mIvqyz/L6xGTS5epjbp6Zbt1r5Y7F1V+Un/Ja55ec2TLLdmy35JtWJ6Gf1KoItTrPd4rvtHwNFinp2qmp4cLrYaal+WfrZrmhUuXSS30lsK1XKsMy89qT257jmTLkX37lKdbolwuvzacB1vrtXK0d4pv1ctyTdZKbvH00Fg9enFiefi1yy3iqbTpOkknsyxKteUX18ue5HjZt+zZksjT7ajpi57+2R3DUExHvFN8sy5Py4PqaT6sZT8unJ6WYfpn842TVnq1udgy3LMpb5LpqYafTDmSz0mOPbd923N/ST6Hqzn9SvRwxwPZvFN8o9ZqSnZrKUW2o9fiao/DV0v7tUY1i+LaPCXe6Olp+Ect2y3HkWTPkezZ92RbGLR/Migu3aaK94pv1wOLPVuOI1t4yL6aWBh0qzYxOP2oSiXZjm4XgykGFtWqDX9Xe27Z8rQdOXLcct8S/1LoqZspN+8U3+hkcFHn6mqX3HPkCL746mpOVYpkcGrWbOKppjWt084wbSGhpqn9rNly5MieZM+Wpy3+leU+i+YHJN4pvlWr5VKFdpnHnj25bW/lmn3U9EVPPzinp8sy/GSN1e10NTkXLZtHaW/b7boMP5vWy5Gnbc+W5Jb9dRr+lUmmKN0rN+8U32iYunPEtZpmS7ajHobpqVwuHhZdovFQy+rB57xkLV+VMrM1w8Ci/Gyqk+SWI9mzZ8vkzb+yJmrV5ER5p/iAx8vLpXu75bKceU0+vWjrYliehpo6uaFdTvS+y2k0Za2S6ZYEU7fB9IsLC2/Jsd9TZfb0r02zFVsbLd4pvlWdzGnNl0xPy56XLdf0VM3kosnEic4Nkx6+SrLQh5Htv8pQpejWfnLRuDCnN+rydPkXqig1Zxq3eKf4VmX40ckyJzkVi7aMQTNbsdRr+sFDm6Ulxy2eBtYlOYcfZdu2aflJY1xUNW+abrX8S8vwdN+6rPZe8Y2WpZctWzr3oNfn3JO0mvd4qlo0OrtJoSmFMSm1nM24BYmmFeUn7WprUZpeTrWUf22qVlGK6Z3iG7VF7q0XOa5S2fZIKEVjWUqiPK1F+UUNtjgVTctW3UYzPA3dTbelljVZejHN9luOpVp32lP5LfGNuiWz5xdOqzlJ7nnN5FIoqlmaISjlJ8v9fs9SZtuOJqnSg1nM2ThNamgMxck8Xbr9huXph5fwMDn9hviAhZdsiV4ussfA6GPLzmNimGfbYl6m8rMy2mVNEr3E45Y2dQxPf2tDL+phFg9LaUzvMAehpy6/Kb5RW2xJXJJs7W/kSLYtLTHveeXh6ZZmUbRfTE8JX7io+7LF00mtfmvTxeWB4ngZLdFM8Q7XVNl89eY3xLca5kxeXqbXHF2L9inZ+W9Kcsu2Rc2+PK1+oZdfLMmR6qLIsceeHnGWHw1PYypMkuXcd5UQv+Wisceabfkt8a3GciRHXj32pV9yG063JJ8zr+PYkyMP3TymtR++MPzsnpTGVfzvT65k25JPmdTDNS/Lak+L1bG41xQkw29ZihlaLw+/Ib7RdI/c0xqPBP1S2fNSSycvCaKd5LOnbuVnky8MimNNtj25h7aUr6pZXE77bJ2TmGe8wzkMTxeG3xTfasTasmVLcmRPj+3Ilma62HNYtxylSkzFpPzdm6kt1cWS3BOylZKYpXUbngqLodhY7Te01nVLbj2b8hviGy3mPTcLOWLcjoi5LIvKkRyh9PKgmSwUS1gS1YpLtXvu2csRSxkv+zSW92rV3Zia6aurJarKb4tvtZZ5S+5JjmV9Sgbl07S2WZL7bfpin7yxXKNLke5O6BNdtxjVzcjns+9bYm73h16np4f3mixXl2tN5jTyydCXp9NviW+X1+Te5r5tOeIpt2RLMGVySrReE8Wyiom5mJcSxZwuhuxJ1hFOT1/q8l6nU5LPvviq9V+TbbL0pf2W+Fa5ZY/ZnS1HEjNbjp1YpsHs3EI3Vp+uiXaZpmrFlb14UEiOuR/J7m/U1EzfIvfkMGpVu44kskrTym+Ib9SGfLXvOW65dW5bjH3PVjiZ26cg9NtQB6Yo6gclUQ8mK+g6jmRt2VJTUgzD5b0eXdmO5N4Y63YkvrS++uz2m+IbDb0+JS+3PXvS2V9Cy96sIE9q3y/VVHjI1tZV6LwQs+g6PHTumow9bY+v2vBewzS2ZEs8Jbntl+OtlTam3xDfqiSfkrRbSH6waso9vV49vFGfkxeKJR6X7Lp89ZC0DD2H9IX9Iq6XWDlKd2mW9yrl7bjlntvo3O+JxT25poffFN9qbffkxZHse7hRbnlJcj8lOslmrFi6LNZt0XoojhLCzHGZtVr2kEi0mJb2bpNFtty23JLcSpFj6mb5DfFe3dRwy2bP05FsS9enfMrTkV1FzT0vk2SbrVm+yr1YSsU87KHd3iiyWTmwb7GluDTdhq/GcKli6Na6uzA8TT/LkbzmyfA0vFO801KGNcPKy+048rSF3BLjlv1ar6enmpLtFlZVVBl7CjXmxFIhLr7QtZVjm/I5655sqweFpbk8mKpdLFZrFMr0D5I92W/LFO8X71WtGwNbsiWf9tyzbUUlud2DEZVbXrdkXcTQflSXpy50xu120sx22VIvRy+S19eHLejJUujyYFr6jX3qeFoulp/V59yOLSe15PXNO8V7tcGU3JPbbcuR7Hk9EnJ8SjKWthW3PG3ompxYztbmWmXVRFoeGk2cWyFfyUvixOBkeGr62g4zMe53EuXh9Is8HcukfIr3ivcabRZ5zfaaT9myHznOiGx5+sQcn8rwls+5VasHTS3dzL5cDopLVqhYS1U7stfakk85tuRTPIWLyeOk+OtcgpeYe1i2mH4y9pfc/CjLFu8U73SpyUiOmdtrOKcjr5Fjs+XTkdspt07xKZqlJz/8VaGWatV1ralc9uYIoiW36i3k6Z6n0flrr6IULh5NSmURekqbfpHcs3Sz6+W94p1Kl8txH5Iw3ZOXN3syh2TbNo6E0RdtrqZ8jmt5OvnChZOWcm20/XR62dmdtn3v637Poe8xt/SSUi5NF84So+y08ovkZevuRdIu7xTvNVh0tu12Hkm2JFs6iWTPnuwjNz0xW26MKVGHLl1Yiy4WpfbboBQyJWTLVpIjW7ZVtiaH6mZZmIvZBleZrf0s97Rxu8W2Ke8V73WxWn50JLdsR7Y92fM5u7kfSe7L0yI3TOZufUoTD+LSRpgs0boVrUQnOcw9zpfkvuYRar/6JYvBYKKZLKr1olvpbLEk+36+mN4r3q0W2z2y5cg9uX95ST695p5yyS3HMa82ZW0vczE9tcR5CyOfh64gpXAmSlvKLXpPonfbnu3I5y23tY4YiRFOFpZlzqrLcjGmNrnnvmRLxSyXd4r36qubyEuethw5jny1MfbsyUua4X7L8cUeZRkeuMco6baMUhQP/aIqxs2qlNz2W87PufZI7jnyKUcM95gvejO7apT1N5SnpTedsjyOLflL9kNM7Z3iWzT2vCR/yZE9eRlyn9YtR/Jpy+r/vzx4W5LjOBYsut0jMqsb1Dnz/78pEl2VGRG+J5sCQI00MCtcjHzgWtMJKFXO8ncDPJxglVNXXx9zOOV0hfcPx+nStb9FUw7zYUKQJF1P9occssQySz+e1lrFZiXnKwuNHrSgJVvzafikqulySAMaEMH/AiFs1PIFdFnJ3rmcvsTpujvcvYCXRzmb5nSusgzPHG4412KnzYYgbFw6l5cNXH2J58tQXKc6Xb4wbM1ACIhkz8Q6avokfNJwDZdOhLo1Ojd4IWGjDNgBCzq2yO5YeteHdSzPpGqExnBW6Dz0bpzyjwcd2lQ3TCQrIaNvBHsCLYtGKLqagry5Ed0i7rTfGjs7G7Dht8BnPbzMMujZINiBbOzBKhp0dqZ0inc6PCSdDkdDJ9sI1LfXt+Wrbx4qR+IGL+sNaAhKNEgIglZkJ6JDRjpvD28Eig0XW7zQgL3BoNPBKp+ET1o6LbVIdhKC6BBAdEftQAk4upAPPRuweXp3OSdRo7mGrpLp1EPCDkGisAOJvIskGtBo0Ah6EghWEAhJRIMGGdFOOiSBluWT8FnD4TvogQFkI7lsZ3NBkkLQQyFmCDew1IdKOBOHLqeKtRSzZocOdTZaBNJpLdiAWI1AGp8lPSBbgL1DkKTZkEsETOf0Wfik0prePV7aOZS+A79AAhF0GklsQOSDl+AGG+DaOHTV2g8lT6fVhyPUdViWBA3Q5HIrPnDJbeOGQMq/C7I1dtokoREgvAxubS3Y6qMun4RPm7ocgovs7LwzyEYDxx4We7o97AuSjYvgv6yys7yrlHp4D+vwLrwS3bfMxwa0oNNpsAcz4wNG8FlX2HkBhE5GbLSWWI3NgE3X6ZPwSfVwzSovnYROdm5Ig+SFqbAljJBO34iApjjlHL5ZoAun+Js6AqdT10EHZZm9bcDGZe+Nl8Xi9ejBF32x0dmCRrBtEFA01sZGIw6nT8MnLcfSY3kuPiANkmjBDq2dCFvxP8Fexbxx6bw4+V+Luy4VHzNfhrXWjm+VPlxOLyMdUsHlFgGxwY2dvdMg+CJZv9D7RiadDvwPrbPxIo2MF9K5fBY+qU7Lh542SjZ60NkQCJW05J0IPXhd4b3HOTNchB/LZcM5HZKC1hq69JTy48skko07GmQjCKBz4w83Jg3YhY3WOpD8riGENb37LPwG07McWjfY6FFEg84NCB/yOmS/t7PfICEfNxSmEQ/3sZwMldIlp4doQZWzdK5XeAH3CQ06NHaS+cJnDY2gwcqdG5DbDjf+D9AbkKnLZ+GzBkl2sAZEBgGNwBlsmUjk6Wi0EKJoqaSgoBNdU4dELR3hXfQ0UBy6JJKIhREbogTBLjufNQQikqABO/ABEjYgIUY5fBZ+xdLpcinTpS4vNR1FIEHnEkE2CEj6PF2AkEvAo0ow0NUpc3rBQ11neloKilat2eg0NKy5M9gONsgEkoREYXVoCRtEEEnjknSI0qll+ST8unWO4bJ0+Tbn0o8uH4JyiR1sOzM3cidP97HcIzsoGejkxZO0DBRdj3VbruXlPmWKw+4wluERZfS3qbQW0ZMOwdbhJXYcq9G5ZN7oNC4BZDTw7B5W+fBp+DXr8FIPffP03VrenUsb3IiE5EYpLbk00AASD2RzoIdLT2kO8USpQ3nolK4o5/Tss1A827I/tDqXFh0aENCCd7E3YCODRpC3j+ICokPvQ33zWfgVZTnmXPqmjuEbtNyID4RcBHpDq0PS6XGUxPZCBpFjcfR9mKcXWKXj3PFX9EzLtfTu0AcuE9f2T9PBEleZQCdpQIugQ3S2ALLxSmfLaHQc/yDtybYEHcun4deMOjxsczXoLsu5XM5jCtucCb8EziCis9GwpDOHhLHdf3lZcSrOeQ5e1I86VDRYdqyhUw/n0rVWylCMdke5IW7ElgR7Br3zbidocCYEG2FAHzTwk+Wz8Cumq1y1HE7H8F251PIlT6EBZULj0mmSULqUd9NtKrq6Uh770tKY6zaWaHEe1nKUa6h54sfaD4SVARVLkgZBcoPbRg+SPUBbJEGHHYStQ67yPH0afs1DP+pRruVwOVxVrgXDt95asLNLciM2gg3Y6PhRz7jltrNxyC+/nRlEablyDN9anygvVW4qLl3Jgtaap5rHZmGng50bGZncoMNOLxq8dFzwSoMOG7SgdR+HpdMn4VfUUufU6SgTIohGI5cKZOAK6FwSCILAYcN8DGigqDtJnpZOXdZwKC5BWYqXFTlgGNOEJbDxLxvQE4jkFSwiETRoZEDSoXcY+nD6NPyKslxDymVZ1vIyHHpajaQd8odGBuzl6PRpSWa4ROV3mk7LOrVqOjQdFctA0znD2TIoS5wtO9A6dIhIRkhk0DFIemc3Gtlgn2RwI8Cly+WT8Ktq+W45PS0FkujE/rGko2zJv9v51fLG0JQVLIs5Z7vt5EY/9SQaN7DKdaCglICyJHHiuSuDuMVgIzIaGz1IIHmBLODGpUFruAho045nPXwafk1Np8c4XJZ3vftuqlVW4ybQ+KwlLi+w9UGcXupsbdm4JwQ4MtdsCW26phmn6Xmki0wS7fOm6EcvDXCDTC4RXBq9E5BEkHtEJheVjXRqTS2fhV9xejnVw3L58DLWkCB8mDGTnp3PgnaoR5A0PqAvb6NkWnmrjRYvZKKLV2jtFBg+WOcvHDOhk57IQ6Z6lmw7qx4b3GhcMhtBwisB2bhkEltwSTwdpcMqn4Rfczistxo6vdTRW0SgteaUBjuw89nGBtwgNqCOV1RY3nEhsLE5lq9kYwnNS1ueum0m6WxB2lhBYwsgLBvvtmAjeIVGZ4MG8T808gYkjdhwOIZVh8/CrzmtX313Fgk+PL2s02Wd8qHxgT9sBJ3k3d5QrBw9OT3r9WG8QKOU8GPXne4S2ZYKQxg2LsGNywbSFDZwI5K9Q9vYaMB2Cy6dTWBPEHzo4fJp+BXDh1pjrvJUH556BpFA9yMw6BF80RsZtGCHHOBiZAk2FGVrjyBcOhYkmga15s5Lo6zBDcQMIPkFgscNEnjlBcjeIDPpQHyg0RJHuwXpoeXQw7V8En5NVXmqpbVcTt9Npy6HlS0a/6YTdDp70GJ1XKRDuqAr1wxyI8GlBNFOYyY2aAQpJheNh7RIEnKREJ0gkk7SMgm4NQKiAWGDjelDy8saPgufNJylDmdZ03kKvPBfGhLQoxJcpENaJdMGDW7I6KilWJhAQm9AEAneBaGNDNnilACC5LMgIQLYidVpUC6X3wif9XB5+u6hUw+B5L+4kh74FtTZQCUDDzrBRTMTHNbhrFaDttEh+UALIKewTVqcSXJ5hda4NP5wyw5JNHpwuZ1OvxU+6e6pnp6uguChLSD5D9lhCd46An2s3It9roB92G7FRdSx1L6qgbRoG+8igX6DDCTZ4xfJoCU9+H+9wgYvsKmgD78RPqnoQHRabzqWc62z8f8TjvABLqJH7WASdgIPMF8g2pJdH2IlmAlnbxt7sjcCts67XZBgYwOCT1qybxHQuez4q0T5zfBZszz18O7juNEpixc6/2lrzWhj65wSIyFRCOgENyVWBQ8Zc23coLW2xJg4uGw0okFkix2k3VjsdEm+2Li8JEmQL7h0uvxG+KR7ZULG/FDROURt/LdOrsUOKPtD8tag6EHSbCgu2aw9x84rNHDqKp3eMmEjO1vy7hfedaFh8ll2pPNui/Y4M+pt+e3wecvl9BjlqdZBLDv/6RbH1pDmAEkCXkmIFsCqLbTaPHs8hOCV3jaWS+r0pJQebHT+EcBGRocdAhpfNIhXkgB0NktPvxU+qwpJoMPGpQcm/6244YACRwS4scEe0IgIcAUKTgIal5Ao5u0UL9AmkUBKT2gkRBB81ogW7CRIW2rV6fQb4bd5qIcuV+mSTCJpBBs32IlDokmyBbbYUBLIDkkmlwwafJA++USgL6DXYZFWUxtKwkYGRGMHMiGIhBY0dmbD74XPWi5PdU69exnL0imXRtKgE2FurLM1uLFTY4u+ERlAdi57I2nnLSBSPpEXYGtgG+sDnlaJ6/gHezRg6xA0NshIgmjwCrSyTb8TPuvU0zk8hRZctqBKYb8RBP3GntxAG7RGAzoJCcgNggBigxuQQeeTtRNBJ3BTbmwzpx9mFxpkAxqvCdsGSWdnB2LK9nD5nfB5B8Fta5B5qOf08lFaQstMSIiAD7DRaEDjAwHtFTbomS15l8SNTvBZBjsbxA0Okw4p24FuxAYqbA92kA9wI0la+CZafid80jxdTudvanmZWnNsL2zACwEJZBCNvEF+COhcWufdMrgEfesZ8QLsvPDFRpJBJo7o9IbQcq4hC12TJHeyf4TYgc4HQD1Ovxc+K/YGGXJJ3jUaTGct6fRGQIdXaFySG7kRwI0Np42dYAfuApl0PuudwQaNS8BGQCa5FApKA4LW2SRhI2sNXn3zB+CTlvMcOiz1VNcG3JAIYpWNnR5EJ4Nt6x2SSzR6Qhy0h0KwJTvQCdj5IuVda2EBkfFCC8J7TyDZMulJawHJzdVr+ooOHX4nfFaVrtK1iPMGwY2NFiSJrg16sAVBa1wCIoNOBntkBJdkAxpJg+QPyQZB0sGGSoNhRyEhdqBDJ/gAnRKt01oOy++ETyo91enpUJfD5XLW0OXh4neN6EQneVIQCQlJhwQyxg5WQh+CGkCjQSOjQXCxXDrLtXT5nfBZD63Dy0PH0ln+6l09JBJ2pfO7pPO0TtKADSEzOhmAsvUmgQtekn/Q2bgkO4mNOv2X8je/Fz5plB8dq+1kzZZAtJegcSOgUYcSyE7PRuMb7EHfiU523mX2NlfjcoNo/G7nsn0gbmz45mXp8M3L9Dvh0w4Pl3Oqw8vhOct3w39hcwgRvPKshJ13QWcnerI9Ojhp7LyLDm0L9k4DgomXGhKw7dPD74ZPOr1Mz+W4ay1dukRo0EmCHZRuwMazOoTSSS495PJLcIkMuDWSF0gIaLwyxQJejrs+fFg+/F74tEOHeqh3nQKdVNfpaXlqXXbfevANtuRussHWE+h5g0waDdoNXskgaTcuCepw6ljedfju7nfCJw0tPU+tdc65XHroOJynx+Joq0FA8go2nhRceiMhiE7uwI2kwQbJpUPSuHQOuavD6dLhu7fld8NnzbV8d3hJIiFhT3oMl55OKaWhnjyrBQ06dBoEnUw2aEAQtAZJNIaCTssqlzq0SofD8jvhd6vptPyKJJIp0Bo0Img03rWAgCAICBKiJexJJ4gGJI3e6cBO4IxlCS4dSCPCmv4w/F7/1OXXbaNa3oUdggCCHZIWvOsk7A0SXoDkRiN2SCCJIGDhhh6aeLoxfXd3KlPn8AfhdxoeeszDrzgVpYENOo1gC26RsEXCK+86bJA9YZHKtg4JTzo9Ukfhmg5wWer5sHScvpv+KPxe55r6ytc08HAZEOw0MtiCTzYuvcVGg9gDXAanYNXLqTu0NX2celpl+TZ1WTrR4Sr1XP4g/E7L0uWor9Cpd9e06Oxs5I3UeEXf6LzUPC2OfwBF+psNZelbraVOH17GdMqcHz8EDQjoLB8etYY/DL9bOav8mrGc01Gey3IZuZblAOfQKepa+qtbqeWYztPhb16mh5fpOvXUpWt6+C8Pp/fS5eEPwu9Vajn9ih36LYHYAiKI3nCq06Hl0mGt8my41vCVNp1O61FBBBvQ9gCHLsvL4XG6XC7XsPxh+J2GY1nl18xyONXlobWculy1dAlBAg1o0CCDS0Pn0JpepmXNspWj1KkPp56upVNLlz8If9ByWNPhKj9aeuqpy2VpzVlaLnU61elwlZdh1dThdOiyTp1rarnUUpe1IhlaflZOfyL8Qcu6u3S6lrqmLh2uVfpmlW9aa1kuD09r6ek89U2nTp0+lh4eajldXIKkA5vDWn5Rlg+XPwn+qKm/6aN06l3rdFhTHcM3fXMMtZRGv0GHxpbwSouBa1rq0JOFj3Jo+VDL0zpKq/ys9OHyZ8EfVEtd6pvL0+nS08s96LnDnp24e3noOfThZQ6dPvzdUcvlWH4yl+NwWR469XBanzjE8uFPgj/s8XA6PM/ODZKGp0NdZWlZy8uhHuqpx1Cnc6qnQ0/L4dLj0HrToasceurhTflD6PSnwR90rFvQ8N2s5buptdTp0OFU13Qtl0NPy7dZU6fnUOewAiKhb7AlvAIdh95/eTiW5RenTh/+JPiDptOpx1E1PDzPslyly1Kr1HLpuap8OJ2+a7zrnaFvemotl4ceLl3q4RqnhzqGn92tpYc/C/6oqa6pTnWpNbVq6dRDD526ptIh6a6aw+FlOcu1XFrLWpajXM6yLN8tHaXLz2ZZ5fQnwZ+tTl1e1nJ5GRCow1PXsnSWn5XDoeUnpcNh+cnUqUvndNb0Z8Of7FEudUgPzLVKPa2hh+9Wedfyi/Xmf3hb/uE3yxqerrWc/mz4szHH1FOH01OHczl06q/T8u7lGH5y993wi+G7u18Mg06wLU+XPxn+ZOuhD4eWwzfX0nKpZ+nyUO+6/OJh+fBRnzx8WD7kD/XQ8jJd/mz4k5V3tc7Tdw91WbqGa06HY5ZO6zM9nPvGF9s+PbQ+0ellWqeXhz8Z/mSnfrTU8pye5XBNh7qWZZVn0sn4ZHp5c/jJ8M3L9JO7l6Wnc6zDnw5/tlF+dM5x6FHO8lRrTXY2SD+qD61P/M3yP5S/+cU656Hn1LIe/mz4k00vy9IaupSA4e+m09JTnX6ydC1r+sks19LlJ6eXpZZj+vPhX66m09KqocOH1nL5J8G/2j91qYdz+XG6XDqd/knwLzY89JiHDz29HEncaP5J8K92rqmv0OPGziwvsw7/JPgXW5YuRw3v/m7VWf5p8C9XzirfPdaypq5V/lnwr1ZqOWuVl9OHUx3+SfAvNhzLKl3lw/JSOv2z4N8c/s3h3xz+zeHfHP7N4d8c/s39X94qWM2zY6CnAABEiGVYSWZJSSoACAAAAAYAGgEFAAEAAABWAAAAGwEFAAEAAABeAAAAKAEDAAEAAAACAAAAMQECAA0AAABmAAAAMgECABQAAAB0AAAAaYcEAAEAAACIAAAAmgAAAEgAAAABAAAASAAAAAEAAABHSU1QIDIuMTAuMTgAADIwMjA6MDU6MjIgMTY6MjY6MDUAAQABoAMAAQAAAAEAAAAAAAAACAAAAQQAAQAAAAABAAABAQQAAQAAAAABAAACAQMAAwAAAAABAAADAQMAAQAAAAYAAAAGAQMAAQAAAAYAAAAVAQMAAQAAAAMAAAABAgQAAQAAAAYBAAACAgQAAQAAAIJDAAAAAAAACAAIAAgA/9j/4AAQSkZJRgABAQAAAQABAAD/2wBDAAgGBgcGBQgHBwcJCQgKDBQNDAsLDBkSEw8UHRofHh0aHBwgJC4nICIsIxwcKDcpLDAxNDQ0Hyc5PTgyPC4zNDL/2wBDAQkJCQwLDBgNDRgyIRwhMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjL/wAARCAEAAQADASIAAhEBAxEB/8QAHwAAAQUBAQEBAQEAAAAAAAAAAAECAwQFBgcICQoL/8QAtRAAAgEDAwIEAwUFBAQAAAF9AQIDAAQRBRIhMUEGE1FhByJxFDKBkaEII0KxwRVS0fAkM2JyggkKFhcYGRolJicoKSo0NTY3ODk6Q0RFRkdISUpTVFVWV1hZWmNkZWZnaGlqc3R1dnd4eXqDhIWGh4iJipKTlJWWl5iZmqKjpKWmp6ipqrKztLW2t7i5usLDxMXGx8jJytLT1NXW19jZ2uHi4+Tl5ufo6erx8vP09fb3+Pn6/8QAHwEAAwEBAQEBAQEBAQAAAAAAAAECAwQFBgcICQoL/8QAtREAAgECBAQDBAcFBAQAAQJ3AAECAxEEBSExBhJBUQdhcRMiMoEIFEKRobHBCSMzUvAVYnLRChYkNOEl8RcYGRomJygpKjU2Nzg5OkNERUZHSElKU1RVVldYWVpjZGVmZ2hpanN0dXZ3eHl6goOEhYaHiImKkpOUlZaXmJmaoqOkpaanqKmqsrO0tba3uLm6wsPExcbHyMnK0tPU1dbX2Nna4uPk5ebn6Onq8vP09fb3+Pn6/9oADAMBAAIRAxEAPwD3+iiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKp6lqtjpFus9/cxwI7iOMNy0rkEhEUcu5wcKoJPYGufufG8ltpd1qjeFPEH9n2ySyPO8cERMcecv5ckqyAYUkAqCRjjmgDrKK5f/AITzS7SfyNct77QZDL5StqcOyFzs3jE6FoeRnjfnKkYzXUUAFFV7++t9M065v7yTy7W1ieaZ9pO1FBLHA5OAD0rn7bxfd3e0ReEdc8wxJMYXks0kRHztLI1wGXO1hyBypHUGgDqKK5+x8Y6XcSx2195+j30kphjtNUTyHlcMVxESdk2Tj/Vs33l9RXQUAFFFFABRRRQAUUUUAFFFFABRRRQAUUUUAFFFFABRRRQAUUUUAFFFFABRRRQAVn6zqf8AZWnPNHD9pu3zHaWgba1zNglYwcHGcElsYVQzHCqSLk88Nrby3FxLHDBEheSSRgqooGSSTwABzmuP0CM+Jr1fGktlG77zb6Ok0kirFZ78NOFZPlllXc2QOUES5GWJALnh7wn9kvDruvPBqPiWbl7vZ8lquCBDbg8pGAzDP3nyS3XA6SGFYEKIZCC7P88jOcsxY8sScZPA6AYAwABUlRzzw2tvLcXEscMESF5JJGCqigZJJPAAHOaAM++sl1sWmZZFtIbiUXNtLCwW6Ty5YWjdWxlNzBgSCG2gjIINcn4UXUfBMWk6NrNzjSL2KOKxN7cK89ndFQTZs6gLIpw+xwBjaU7pnsJNc0uKXy5L+Bf3U8xcv8ipAypMWf7q7GYA5Ixz6HFPVdMh8TWtxZteSPp86bDJa3IR7a4hlyrRlVzvDg5y2FMSjactQBX+IM8Nt8OfEjzyxxIdMuEDOwUFmjKqOe5YgAdyQKp+ENC0eTw/NE+lWLRpqGoQKht0IWMXdygQDH3QskigdMOw6E1T1G/bxL8OLCXVbGNJ5dTsbW/tXVWTzUv4opkxlgU3K4HJyMZrqNAvIb7TpZoLSO1Rb27iMaYwWS4kRn4A5ZlLn3Y8nqQAOiQ3Q1SHVPL1GzvrhZVtbqMPHEqxxrsCtkEboy/QcseM8nn9KSbwPqlvol1exv4bvH8nSZLmU+bazdRaEn76FQxjYnI27DklM9pWX4j0VfEPh+80tp5Ld5kBiuIywaCVSGjkG0g5V1VsZGcUAalFZfhzUptW8P2d3dLGl4UMd3HGCFjuEJSZBknhZFdc5IOMgkc1qUAFFFFABRRRQAUUUUAFFFFABRRRQAUUUUAFFFFABRRRQAUUUUAFFFFAHH+N3fVLzRvCKJOIdZld76WNWwtpCA0iFlZSnmExx56YkbvgHrI4IYXmeKKNHmffKyqAXbaFy3qdqqMnsAO1c3rF9b6f480Sa6k8uNtPu4QdpOXkubKNBx6syj2zzxVzxOrNaW6pYXeoOXmC2UTKsNwfs837u4LcCJumTxvMeaAM/wATSwX9vcXIuI4E8OXtveS3IklVoigEk6lVX5gbaQgYLBvMIIGM1zd+14mj+J9DaXybGG01w3lw0ZaFJJWiuISWVS3EV02QBklXwG2g1c8T6u3h/S/EuoafZ2msQavb21zZW7OsovJZNlq4VFyXiC/ZTgD5jIRu+YbdT/kZZ72SL7DPd2O6O33/ADW+oWNwkcmGX5v3b42eYufngLAFd0RAOX8aI9pPq9zcWfkSatomoCCCINLM8sqafAiOqlh5hkwnyZXG05zk1X+C+k3+meJvHj3cM5hk1ARxXTxyBLgpLOrlWcsWweuWYjPJJ5qv4l/tG10mfxB9hnu9Xk8p7hbONXhtrqSOKJUiIc+ZJFe2FvuX5sLIQVbOaxPhZ47af4r3GgW91I3h2V75dItYIVjijDSmcMVwpxtRgMgld2AACaAOv8TXq+GvCfjO8iikmg07xHaXiW7TNjJazuHVSc7Q0ju3AwC54rtPC6XFlHe6bdWc8UiXd1diVgDG6TXdwyBWB5YKFYjsHXPJwPN/izY29ppXxBmgj2SXen6PNOdxO9xdSxg89PlRRx6eua9Q03WNL+x2cNsn2WF7ubTbWARbRvgMqlVC5CriByOnAHQnFAFiz1S3msWuZL2BoxdyWwk2GJd4maIR4Y8sGATP8TcgAECtCsOHQmn0c2OovGCNTa+U2qqgwt2biIH5QM4CBjjJO45JO6tygDm9CM1n4s8SaW0ca25eDUbbY5wqzKyOu3ACnzYJZDgnJlJPJNdJXLvDcW3xThmW6/0W/wBEkSS38scPbzoVfd16XTjHHTvxjqKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigDl9Rsbef4kaRJNH5u7Srs7JGLIDHcWjowQ/KGDHO4DPC8/KMWPF3+i6daayP+YPdpevn7qw4aOdiOp2wySsAOdyrwfunP8AGVvbp4g8IaiZYLe+j1Ca1trickohmtJgFK7l3bnSPjIJxgEZrY8T3ml2mhzJrgxpN1/ol1Kz7EjSX5Mu2QQpLBcjpuBOACwAI7GO2sbW00bVptN8+S4lawtQEUGKOUvCsaYGTHGIug+UrnPeuf1+W51HSdQ1OO4jitE0ydp5Wkd4LG/spt0bIu0MwEglLHYd4gTjHDWLK9u/EWg6LqFz5a6n9nttZs0tkQF8xqJ4kV5fmJWR03NtVRcR8llzWenhq58HeFdYtdEt7T7bb3EuqaT5Ng8uUjSNRE46CVk3Q7lIZ1Jfly5oAr3Fk39mw+C9clj+2+KLe4DebCrRw3MUQ82aIJ8pDuEnVSEOTIxYOQleEeF428NfFvwsunTSKZX05mZwrHFzDEZV6YxiVwO4GOcjNdxN4Lk1D4MWOkaPqVpqSSanHqMDReRBKscsLxxrMrSAbzcbovvueMDO3YPL/DEl9D8QfDkt3Ddz3CXtk0cTnEjoDH5arvIGCmwLkgY28gUAe3/H+aHTotOuZdLkngv7eSwuriEiNlUT286r5m1hkiKUKD03McHBB9MsdY8P3f7yBIEtba0j1lLqSJY40S48796CcFWIWUsSBw5yeTVfxhdfYL7wreNbzywprccUhhTd5fnQzQKzei75UBPv3OAef8EeF72y0ePRvErfbbq80RLTUYhcxhbSBGdYIQqKrHckkwL5PzRNhjwaAO81PTYdVtUt52kVEuILgFCAd0UqyqOQeNyAH2z061crLnmvl8VafBGJP7PeyuXnIjyvmq8Ajy2ODtaXAzzz1xxHc/bP+Ey0zZ5/2H+z7vzdufL8zzLbZu7bseZjPON2O9AFfWf9G8VeGrxOZJpbjT2B6CN4WnJH+1utYwD0wW4yQR0Fc/4h/wCQ54T/AOwrJ/6RXVdBQAUUUUAFFFFABRRRQAUUUUAFFFFABRRRQAUUUUAFFFFABRRRQAUUVHHPDM8yRSxu8L7JVVgSjbQ2G9DtZTg9iD3oA5/x8Jl8Eand28kaT6eiajH5iF1Zrd1nCkAg4Yx7evGc0eJJtF1z4c6leXgkudFuNMe6LRRje0Xl7w6BxgOBhlyOCB0xWhqXiXQdGuFt9U1vTbGdkDrHdXSRMVyRkBiDjIIz7Gsf4ezMnh+40aQXe/Q72bTFa6jVGeKM5hYYAyPJaL5sDPJ75IB5AmrX3w+HjfQb1I9f0+xe2tntrm72T/2bLHKqhZMB8KZbdSFBVTI20Dduq34b+L0uv6jfkQf2d9jtItRZjcoZLtrcgXOQsaCWSS2yApG1TEpG3AZdz4jabo1p4l8P6jK0aeG9Qt5fDWomAweVbrk+TtDDCFJQzFh9zyRwCMN4JpWrXHgfxQb3TpoLjUtOuysVzFIJLaVAHRxjGWVwRhgVwM9yCoB6R8QYk8EaZZ2unaxfWut6TdwW6Wo2xwXVosk9xbz7AgWZlYhWbBAkVsjJDN5emvfZPEenazYWUFvJYfZXSEjKPJCiAs2MffZCx7/MeSea2PH9zEl5ZaPG32qPTItllqLSuz3FjKFmtldWAwyLIRwB94LjCgnU8JfCfxRrdkNWhspINqJc2i3FujJcKUmZT+8IUgvFGm0g8TKxG3qAfTfjL/kB23/YV03/ANLYa8zs9QaK8vda0rWo5bDZf3V3FaspJSz1b7QcODyXguZAF4BDjJwwI7z4qaZ/a/wv8Q23neVstDc7tu7PkkS7cZHXZjPbOeelfOmo/DKEeOJdH0nXbS508XCxmYsGngzdR2zJJEMHeryg5O1XUblPYAH1nb3XnyyRNbzwyR8kSJwV3MqkMMqc7N2M7gGXcFJxVivK/CniZbjwt4ctNCtZJbz+zNLFxdwWzMViS6WCWOQlMAAeeVIJ4WVvlADN1mqvqmjwahdi8yt3rdgLcZ3+XA72sMiYYYXJ808f385BPABY8Q/8hzwn/wBhWT/0iuq6Cub8Rzwr4k8IW7Sxid9TldIyw3Mq2dwGIHUgFlBPbcPWukoAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiisPVfEIttLuL/AEqO01RLK48q+RL6OIwKv+t+ZvkDoDkq7JxnkcZANyufufEGo+bqVnZeHL57+1i863W6ZYoLxdxXCTrvVW4yFfa3IyAMkeMaV8RNd8f6je+Fo10q+8PeVJPd3+vWoikitQQWeQRSqm5CQAU28hW+Xkj0Nde1JfDVkupPHpWLcxNdSXDTaffR4AEiXiOZICwC7JJSD+9PyysAQAWNRs9V+IOjXK2GvXegRB4JLcwRSQXtrKFbzYblN4yNrIy4K9QfmABbzhPhi134lTWPH2rSaroot4vsuqafGpS5QH5TcyIN6jy1BaQ5GCMzDaM+l3HhnWLqKMyCC6a04gS9mdJ4yyruFvfwkSpGPukvGZH2MGJDAjc0Xw62lX97e3GqXd/cXL8SS7Y/k2IMOkYWN3ynEmwNtwucKKAOH1D4ReELK4muJPC+s+IZ724knkkGoKGhyQdpLzRlhkkgnc3XcelbEEMHhf4sxQIY0t/EemBFMkkss8lzaccsxOAYX6k5JTnk/N0kPhfSbfxHc6/DDPHqV1t+0Ol3KEl2psXdGG2NhemV469ea8/1n/hJNftda1bSPPjm0jUEv7WwuvMS5guoYlSS2ZE3LLDLCS6mNxuMuOQxIAOg+Ing+31f4Z6zpdlbfvl82/t1WIzOZ97TNsBOQzkuvHTzCAMcV8uaq7Jpdxodx4fjj1TS7jN3fRbd0YX9yyMI1C7MiHDEk7953HzcD7TsL631PTra/s5PMtbqJJoX2kbkYAqcHkZBHWuD8LeCYb+/tvF+t293F4gkSJb2OcBd00KeU25VJjaIvHHMmFBDKrBsEKoB5Bo/wV1rUNC03WtGvpIdQKBipzH5FylyUdWLbHjMa4PCuS0cmCPk3e9pa6PoetQKlxPJqaxX0trZs6K119om8+VYy21XZWjHAb5VILfeDVqanpDXOlyW2l3kmk3Id5obi2RSElbcSzRn5ZASzEhhyTnIYBhlw+FvtF5cpqUUD2Eu157VH8y2vpCNzs1tKjCDEmXHlvlidzkmgDl7zxifiDLeeB9PsNV0W7vdPkkubi9ghL2sW5VIeHzNw3qWXnDDejAFW3C5a/CDSrbxPquvJqupR3d9cTzo0Plo0BljdG2vsLggyyMMED7mQxTJ9EooA5uHwXpunEvo6R2DpetqEESQqII5jbG3/wBWu3KbTuIBBLZ+YZqODw3L4fbTp9GknmjtLSCyuYHZC9xb28U4jVSQAJDJKhJJUfL1AyD1FFAHm+p6t4k0XxVpOsa7ZaVHpsNpJYyzRXMmSzQpdXE6qEY+WotnRUOGJGScMMegWF19u062vPs89v58SS+TcJskj3AHa69mGcEdjVe3vtL16zkiikgvLeaLLxOuRJExZQxU/ejfa+GxtcDIJHNcnpupXemfFTUtIu1kmTUUWe2kYJNMY1QkklCPIt42HlqrqS0krMGOWoA7yiiigAooooAKKKKACiiigAooooAKKKKACiis/W9V/sTR59R+wX1/5O3/AEawh82Z8sF+VcjOM5PsDQBl+Obm0t/DUiX91rNjaTOBLfaQrmW1VQZC5KBiqfu9pOD97nAJI8IvfiHbeIPE97pkl/rOo6Szn/SnmSz+0W0UbMyTi2tWlaI5mOOAFfJCkE16+ltqtobux0Hw1qWix6u73s2prc208ltePJhi8LyMpTaoY7GPBwAG5EmjahpnhjZFc+D59A8+INcX0GnQpbMyYyZDbySeUo3swMhCgbvm4NAGP4d8MWBs9KGjQQeG/ENjEDBdQeXcxanaAqpd2TYLmNwEY52OjMrYXcpbsPDOkad4UgHhvTmvjbp5l1Ak0LNHAjuSY1lCBThiSFZmfBycjFSF9D8IW6W9ppUlrBO7P5el6VLIu4AAlhBGQDjAycZx7VoabDBHbtPbm7KXbm5IupJSylgDgLIcxj/YwAvPA5oAsQwQ2yFIIo4kLs5VFCgszFmPHcsSSe5JNE5mW3la3jjknCExpI5RWbHALAEgZ74OPQ1JRQBXsXvJLONr+CCC6Od8cExlReTjDFVJ4x/CPTnrUepanBpVus9xHdujOEAtbSW4bOCeVjViBx1xjp6irleb+J9b17XItOtfBvifQ7PU7m7k8hY76G4S4tAr/vSGjLbg8ZXEYYD5sk4JUA3Ph9YzWGiXybZItPk1O5l063lszavBbs5IQxkAqN/mFc8lWU4X7q9ZUcBma3ia4jjjnKAyJG5dVbHIDEAkZ74GfQVh+J9Q1Gz+ypph/fHfK+yNZ3CLgMxg3K8kYD5PlsHDeWArhiKAOgorH8N31xqGnSXFzJvLSloyFBQIwDDZIuFmj+bKSADKlQw3q9eEeNP2g9Um1G6s/CSwW9guEjvpod0zkHJdVb5VU9AGUnHPBOFAPo+ivlDRvj3420/UUm1G6g1S14D280EcWRkElWjUENgEAnIGehr6T8NeJYfENvOj28ljqlk4iv8ATpiDJbSYyORwyMOVccMOR3AANyo54VubeWBzIEkQoxjkZGAIxwykFT7ggjtUlFAHD+HrKDQ/Hes2sUM9vBdeUIN1tEonZYhkJsUEW8EYhRScKHldSWYrix4p1DxBYeIdPi8M6dpV1dXFpNPdrdlo5J4oHjCxRyDgMTO2N4KgsTxzmx4i0i8vPEOi3WnRzxzeasd3fCc7ILVHWZoxH5i/NK8caFgrfLu3cACuf+Kfie88C3mheKobOC8tY/tGn3Fu8pjdvOCSKVYAgYNvySD1xjnIAO80rVbHXNLt9T0y5jubO4TfFKnRh/MEHIIPIIIOCKuV5P8AAXxN/bvhfVLWQwRTWuoSSpaW8Plx28Mx3qqcfd3+bgZJAGOmK9YoAKKKKACiiigAooooAKKKKACiiigArg7rxTY+KPEraBpfl6nZ21l/aEt1peu+RKXy6CJFjZS5JC53OqjcC2Dtz3E88Nrby3FxLHDBEheSSRgqooGSSTwABzmuHnl8RS+GJZdG1+71u71By0Oo6ZbWLW9oFk5VEkkXcCuU+Z5CCpOQeoBn+KNUWB3vbzRdZ06eVGdTqPiZtPtZCigeWjQzuiytxhSFDAO275TWh8Prm61ayhuv7a1maC0RYZIri80+7ikfZyvnQKXYrlTlipOVJByRUnxCtn1qK10ay8af8I/fLuuzDaBnvLhFVuERJFdlwHJAVslRjpzY0TRL3SvA0EN9401V2i3XUmqXEUccixEFtridHKqAcnf8wI6gfKACSbRLmfxKNRfwr4fEguFb+00vnS72KQA2Vtwc7RgpvwRlSSpNdJfWUWoWclrM86RvjJgneFxgg8OhDDp2PPTpWfpmhS2Goy31zrmq6lM8QhVbuRFjjUEkkRxIibiT94gtgAAgZB2KAK/2rZp32ye3nixF5rw7PMkTjJXbHu3MOmF3ZPTNcvdeLriLUYL1LeeHw6m2O7ub6yFp5TscZL3E0TBRuQ8RPnkAknC9hXFx+FJNGvZpdMs9NtEun8hJtC0iC3uraMuG3PJLIyOgC4YCMkkggDFAHSX5fU/D1ydKngkkurRzaTecwjYsh2NvjO4Kcg7lOccg5xXmYtpYjYXR0Xw+lvpFvFb2/iHWbOaxjskWSMCIW87GSR1ABSQuoyxAYHdu9UsPN/s628/z/O8pN/2jZ5m7Azv8v5N2eu35c9OK4/xi2nNPfasZZ72+8O6fNfW9jJGzWUVwqblkkIUAzAFcKXyFbcqjO6gDrDPNBfpHcS2nkXDssGWKSbggIQKciQkLMxIK4CgbTy1GpabDqduscjSRSRuJILiIgSQSAEB0JBGcEggggglWBUkHl/CGp6vqfw+tdSvb+7e8jSWT7W+njbeDDbXWBPnaL5gVAEcj7FOAGwessJXn062llbfI8SMzeQ0OSQCT5bksn+6xyOh5oALP7YIit75DSLtAkhyBJ8o3NtOdnzbsLubgA7snA+CK+/6+KPiH4Yfwj451PS/I8m1EplswNxUwMcphm5bA+Unn5lYZOKALHwsvtL034maJd6zJBFYxysWknXKI5RhGx9MOVO4/dxnIxmvoPxzrukaL8TfBzxSyf29JcLaS28eUE1ncFky77SGCSqrKhPXPHOR8qWF4+n6jbXsQzJbypKo3smSpBHzIQw6dVII7EGtzxf4u1XxhcWN5qt7HPKluFMcTSBUcHaWKMdiuwRWPlgKeOAcigD7boqOCRpreKV4ZIHdAzRSFSyEj7p2kjI6cEj0JqSgCvfzXFvp1zNZ2v2u6jid4bfzBH5rgEqm48Lk4GT0zXn/jLw7eeNvAN5oF3FPLqtn+8sbx4TGLyaFEDyFflWLe7yxhWOCPnXcoBHpFc3cRme9XXLayu4LhHa3ZZJJIzcNE8sMKOio+YC00km/sAjEED5QDxj9nK8m0/wAVeIdBuLSSKeS3WWTzMq0TQuUKFSM5zL7Y29OePouvH/ip4Iia60Pxp5fmX1hd2q6mmnxvHNfKZY0UxBXyJAThRndhgN/yLn2CgAooooAKKKKACiiigAooooAKKKKAMvX59SttLabTJdNgdHDT3OoswighHMj4XG4hQcAsg7lhjB499T8NeIvEFpHqlj4R1OAolqmrXF1bs11NjLR28X7xiAzplWdSPM43dWx/i34yg8OiLUNP02PUtQsb2K2lN/HK9pbOYzMhVC6oZ8EEOgJVcglcqDlp4pu5v7EutT8X+HJ4IbRrq/GryWd41rdx42tbw221i33ihEjHaxyAwAYAwPiJ4c1bwr8RZZ/Dd7/ZGkX8UE0kFpqUWko23KNGjMwVmG0sSFO3zRkcjd7H4bh8PaH8PNNjfUNNk0e0RD9qeeF4FcSZB8xVRGKycB9oJYAn5s15n8Ub3R/Eek6B4qhmg0jWrXF5aW2o3KRTXlr5ZmUjyGZxlkwmWTDFhkMy1ueEJ/EafDe+sLLStS8PGytzLbMmj5aOQN5ksccc9w7zl9xCkqo685wAAesQRtDbxRPNJO6IFaWQKGcgfeO0AZPXgAegFYfiy7eDR7gNHBFar5ZlurvVm06MAseBNGGdWDBBjCghwMnkV5X4M+MWv37ve6pY2kfheB/Kl1O/uljlR9pcjciKsz7VbEccQPKZPVj6pr629jeQ6qZoLSaSJ7Np4dPNxfSAgsiQlcn5SGcqUkBCkkAAmgC5aanNNpdhcJZ3d287rFKy2xtSnUNI0U7K6oCM4+ZsEYDdaj8QJO9rkafBe2kcU7zxSzyrv/dMAnlJG/nK24gqQccEKzACpNAF2NLVby2u4HDnAvbhJZ3zyWk2EopLFsKhKhduNv3F1KAOD8IsumXEsVjoEbJcPGssuneHm0hYgCcNJ9okBlHJI8sMVwcj5hnY8RTtpFlrWoT2UmpWB0y4nnjnnURKIkG2AR4IxIGlJYgnjByNgXLvtIv/ABBeSXEnhzy4ZcJJDrerSSRAgAB/scTSQSKOCAWQlgT8pw52Natbx4tJmNxfT3lvKCLaxc20F1NtODMw3MkK4ZsFiD0IkbapAOb8DS3OseGo7rxbqEkGqeJHNzbW0WqPETAoDIIERlMYC4LBSzEHLsc7V6zT9RiuNcv4FuNVdhjEVzp7xQRbPlby5TEofcTn7756rgV4pq3xDu9E+J88N3pV3a65JqcMVybMpfM1isSbLWAPt4lkJc4CMNw4ZuB7Xp+sQXunDU7i8gtfskTJqNstzFLHazAK0iySDo0eCOoGGJI6YANiuD+I3wu034hJbTS3clhqFshSK5jiVwylgcOOCwGG2gMMFiec4ruIJ4bq3iuLeWOaCVA8ckbBldSMggjggjnNE8y21vLO4kKRoXYRxs7EAZ4VQSx9gCT2oA+bL79m7xJHeSLYazpU9qMbJJzJE7cDOVCsBzn+I+vHSu78Kfs/+HNDuBdazcSa3Oj7o0kj8qBcFSMoCSxyD1YqQ2Cveu0fUPFnlXQTTrFbu6ydNgkL7LZAoy93MuVLbiB5cYPoGZdzpGniLWpkS0g0uOS/mSIxNyhjjZtrXM8LEGJMgskXmNI4BX5Sr7QDrKKKKACs86Skc97NaXM9pJebmmMW1t0pSONZfnVsMqxqAPu9cqxrQooA4fXNnxC+Ft6Y9Mvpob7cba3glWCWdEnzE4aZQEVwiPyDhW4DHGe4rn/FMdnp/gu7USfYbW1iQxJBeiwB2FSkIl4ESuQseRjAbAxVjwrN5/hfTn+06VcYiCb9IGLQbTt2xcn5Vxt6/wAPQdAAbFFFFABRRRQAUUUUAFFFFABRRVe/uvsOnXN59nnuPIieXybdN8km0E7UXuxxgDuaAPAPjRq1x/wnOi6dLqX9pyQymWLTtIgFtd2rk/ucTkSt5jZXIAGdinaCVNcvNrfiXxL40trnQFghmh09ryxtbrUl1Z0CjzDs84yEXDGMYRVVxgZAAZqz9XmvPE2neH9HTTfCml2g2ypd2UxjjtTIGXbcyGRlEjJAHIbMhCgfeytV9L0nVPDXjS0svDviuxuNWm3Ij6Pc5RnwHjjZ5fLjdXYKCNzdCCpOFIB6Pb2+s6L4Ik8RWUuleGrdovt8Wo35S71DWLryWKv+8Zli81Hc7AWZWLgZDHPWfDvxbbTaNHqmqeJJLuLYEUT3yMumwbUH+lSGOIGVpV2gsGY5GzI8xj45rNxZv4V1HWLCy0q9up7u5tb3Wr8hZ71nmL+ZbWzNhMI0W5gu5fN+XG1mrsPhp4m0fQfh1YXSGe51UaqNPjtzCkiWs8+7FwIowJJMxAqCxLnY0aFVY0AW5l0XwN4sm0LwxoMdhqjpO6ajMo1S9BCuRHb20bsYyVkQq0hQFAd4bGT7Jolz5HheCSdp5PssTRuTL9rnPlEqd5jB3zfL86rn59wBbGT5n478A+LdYexg8Kyx6daanbn+2d6QWzvMFY7riSEZlL+YylVBQEE9Dkdp4W0bR9G+Gdppll4g87SreJ2k1SC4RAy72eUiRchFzvGQdyjowYbqANC78R3Fp/Z1o2kTvq+o+aYLNHDLEidXmlHyoo3Rhtu/DPhBJwToXmi2V/Zi0ulnlt/NaVo2uZMSFiSVf5vnjO4jy2ymMDGAAMuKTQPiBokHnwyT2bOl2trcFojIgdhFI8eQWicoWUOMMACRkcdBOZlt5Wt445JwhMaSOUVmxwCwBIGe+Dj0NAHF6P4os/FEFlqU+lQaffPFNNpdzexiVraN3WGJpM7TG0xPyorEOqHDmtTw9crp9xB4WjvJNTuNOslfUb2W4Z5ElYjZvDFjmT964G47AoHRlo8QeE7bUNNi/s23tLXULBN+nP5KeXHKkUqQbhtPyRtKWUAfKRkdwc/QdXa2v9F0p7OSXUL6y86R7h1F3bWUSARtdFvmeVpH6BQA0kgBOwswB5/4y0WbxB4zvhY2em6TqF27/ZTLMRq15NbRSeVLCDlYIC8QG4bCwjyW+YCq/wAMtQ1K1tbFlnk1fU7m4uDY2VrO0MVzGZSJtRvJCC7DOY18xc/IAqFjkdJ8S9NQ+HL/AF6x0m+eae7MVxYiFQby5V1t7aWUNkyQoV3JEARIXQkYLGuI+KVu82k3+pWTQJNpksVlqWqXGptNPdXLRsJLa26ARqJ3LqFjB5AQBCKAPoPTYNNjt2uNLitFgvXN00lqqhZ2cA+YSvDFhg7uc8Vcr548NfFDxF4c8R+EtJ8QQQWHhy40q1iijLRuTGybEuWkyNuWXJBICpn5SRuPr+j+OdO1aJ7gRTx2suqvplhMsbSi9ZVyZE2Ajy8rJ82duIySRyAAdRRVOw1Wx1N7xLG5jnNlcG1uNnISUKrFM9CQGGcdDkHkECnfP4gW8k+xJYm3kxFCHVmMZIBM8jbl+UfMoiVSWO071DNsANiiuLM3jeC4SCIWlw62TW8BuIyizzqQGurhkBEScDZChZm80527T5fQW15qUtxbQ/ZI5IFQrd3j7rfMgLKfKiIZiNy5+ZgNrKVaTnABxfxh1Dxto2h22r+Ebnyre08w6iqQxyvsO3a4DqflXDZx03ZIwCRT8NfHPw5qPg6fVNamjsdSskAuLJDlp27GAE5YMe2fl/iOMMfVK+WPDngXS/Evxf8AFEOoj7H4e0i7up7jy18uFUWYhYi4wI1xk/7qNjHUAHb+Ede8S+Lpdb8c67LPaeFoovITSzCs1tNbbv35ZWI37EDZcDJJIAYKYj7Bod7p2oaHZXWkJs014l+zAQNCBGOF2owBC4AxxgjBHGK4+81r+09asNH8F6lYxTWVpBfQLFLm0vbPzmimgyiske0xoA4DMMlVAG416BQAUUUUAFFFFABRRRQAUUUUAFZ+uaPb+INDvdIu3njt7yJopGglMbgH0I/kcg9CCCQdCse+8WeG9MvJLO/8QaVaXUeN8M97HG65AIypORkEH8aAPjzxjpJ03xVqtrMtpYyW7sEso0k+RVfYkYYxrvJjCyeYfvqdxJdiKx7O5tleCLULeSezjd3ZLd0hlYsoH+tKMcAqpwQQPmxgsTXtHxIsovDI1S/0yXTYNP1l5bqPUZ4Ybm9vnuI38yK2Zc7bcKybmbaRvJUvkK3i+niGG4hvbu2jurOC4j8+2NwI2mUkkqMHcAQpBYA7cjuRkA9I+HOo21vZXNv4fto7bWo0E76xLAl3esdhzBZ2nUkncpbdjZuZ9uVC2Pgl/Zuj/E3UBfw3Ye1t50SS5tFjFoqnLyzEv+4IVdh68yEFh34vSrS+0bWDBP4in8PQtEbu1vvLuUS5wrrE8YVN+1gzAOQMKz9/lPYal4Pi1PzovBmlwR3GtxRNBpA1B5rm3tV/emaUhxHErgW7BJTJkuNpBAFAFzxH8QNa1q4vPEl3pl3c+E5nA0/SblysMhhIUTShUIeJZZE3KWUM7xrucR8ez2niO2g8FWGp+Jrm0/sW+0xZpbjUbhGlkeRS5g8pIlSQbCQNvLYxsPJr54muNMtPha76YsafbXg/tKASSPmXZLFCjESDA3Q3NyQV4Z4FwygkZejaHPq32qXxJqV9b6Tom5tQiMcrzQY8qJI1DDYsjkLGoJGBESwAQAgH0ffaDpPiiKTXtJvcaFrMQn1qWyMrz6gkShY4VAyUXG8OFAc4CYyTivZeJIoPFDa94kjnsri40+RrLTgrySafp8YaSS4uVUlUaRlQYAyCqICxDYz9B8Wf8I/9sa+Sc+XLsu4IH8+G3mPy22l2aLtUzKhXeUUgFSGPzApqeItBsfEUOpyJaSJZl1uPEdlBDvvryWKGKSC1VgSuNpUnY3XAUgsxoA2JDeu+m32m6bJC9+ilXuxKZoZHWWT/AEkBuIolaQCIkgySKoMW0MbF/CuspZ63pBknCOHVbeRrY3pVmWLfLkFrdS8kmAGDAhl3D5XptqmqXEWmxXRgg8TQRXGqNodrcZE8QWSOOF5Puj5pYssRtLoSowMivY6tcJfPObb+xrOxl83XElxcyXN3NDGyQROrFm2+agztySsUcYK5AAOTvfjLFoU0cly0mpwB5APKaGJZ4BN5b3MfJ3DzAyRRKd2yNnkY5DDiPH8egahpPgW7XVbv/hGbl9qtO7NdqWmY300n7ttzljHzuxuDbUYHI9L+IXhDwt4o2eGf7Y/sK7sbQ6n5UMIW2EK7IvNlGFU7ETYvzAqP9niuM8S+BG8JfBq0gv7WSaC2t5r6+jWZUH9oymGGEsQWJEayScIQrGIZ+9yAc/rev23iHRNd1m6EhM1u1zexRagiJJczusdlbsEUeaIIIjMBydwcNtO4V53pPirXdEvNPurDU545NO8z7GHIkSDzAQ+1Hyo3ZOePfrVzQ9F1LxHpDW6X9pb6fYXEkjG4DYjZ4JJXf5EZiNlnjHPIXA5JrHttJ1K8t5Li10+7ngjSR3kihZlVUClySBgBQ6EntuGeooA9Q8P/ABNsY9b8C3epWUlrZ6M95Hc3P2z7TLPLOg8yZ0PzqC7lz1zlguSuK6vw78c9Oi0y3ivb+dJLe00y2YXsDSGWQSFbyUMmSf3ZVhuOSV+6TkHyS51ptXufF2pWmmSKNRt3mvN1yrCAPfRSBl+UEjPlx45OSWyB8o5OgD7H1P4laXoCaldaq++wt9bTSY5rRfM2E26SMZPm/hYyA7RkbQNpOax/EHxhsLK88O2+nGBf7QlsZbx7ySMC2tbgMTkCQMsgUBicFVDDJ+Zc/OGo6fbxeBtB1BbaCO6uLu8iklimLtKiCErvXcQjAyOMYXK7Tg5BNOSeay8PrYLLaSwai8V64jYtJC0RniVG7KSHZsc8FDkZxQB7XdfHO8sdYu4Rf2NxDBd6rEn7gukkaqGsm3J1y4ZMg4K8tzh6801bxdq95qmvz6PDJoen+JUNzc2zTgidU37ysrhSQziX5Vxkkpg9K5fS79tNv1uFMmwo8Mqxsqs0UiFJFBZWCkozDODjOccVuWviK3Wz8PZtLE32j/aVY3tuZoLmAnzY4nT5ssXedchVxvQ7hjcoB7H+z/Pc3tk8ga0ijgd4njXSHBYBIwXFyCEV2xCGTBLCFWI3FnPuleL/ALOAdfCWpr9o8yFrsSBArAROVwwJMYBYhUJ2u/BXIQ/e9ooAKKKKACiiigAooooAKjnMy28rW8cck4QmNJHKKzY4BYAkDPfBx6GpKjnghureW3uIo5oJUKSRyKGV1IwQQeCCOMUAY9zezaNf3N1d22jWOis4e41GW/MUhbYqAuhiC5yEQEydAPZaw77xlZyXkjWHxA8GwWpxsjnUSuvAzlhcqDzn+EenPWuo1PUbqw8r7No19qW/O77I8C+XjGM+bInXPbPQ5xxnl/FOn6hHeXeopp889qNmDB4h1GJ24VeLe3iYDn+7n+8cc0Aed+Obe51xIfFUWtaa9gEm0q/16DTXSK3ti2xwscjSNMWaRlWSHaB84LENlPINE0aHU/EHn2U0lpotk6SXOpX9sJo4FUZ3SIAVy5U7YjnJITLfeP0XbaYNV8Pa74elub6+uNVtGitjf6VqccMUgRyrM908qrhtpBG05UfeO3HzhrOp6j/YdjoTw/YbCxlkV7Msola6GPNkmUANu+bapYfKq7QSVckAPE+raFffZbPw9on9nWNpv/fTSmW5umOBvkbovCKdi/KpZ8da6TwF47tvA2g3V1HdXcuqPcM1vp8UKJAxEewPcy43un7xisanAaMk43Ajzuu08DeMNA8JPHeX3hCPV9UguDNb3b3zRiIbQAPL2spIILBiMgkY6A0AdpeeAL/whLpniBNbsdUvrbGqDQ/skkTpPK0aRmK2VkbaZjGp4jxsUbWxsrQ+HOtxSeO3hsbifTtd1a7t49Tt7pHZ2aGKSa8fy8CNPMlUIMlmTdIQEBCjh9D8c+JdY8c6hcx30FjeeINtvd38dsu6ygBXc6NwUVI0OTu+6u4ncoYetwX1pCNW1rwv4ejHinV7e5k0r7O7iV7V7mNFuJ1k4BeWRplJTb5aBdwC0AEuueDvDPh/RdeltY7PUri41ObRbm4jumVt5cC4nyTI4kTyMltzfONoAHy9J4b8PJY+GdGu9076ncytrE98gW5ha/uIvKJZYyN0f78keXhQseS46twet6FpHxBOgaFpWrSSQW+mJZ6dFJAXe1Mcii4uZHTCOmyJYVKlo3kYhSNpauQ8Da3r/gzVNO0vWNSj0fTdRslvYb+YLcPa2h3SkQKSyoZim0qVJJ2naSBQB7fdS69our3/ANlt5NU1aTR9NtorqW2dLeaYTzRySOUUhQvnLIyA525xwCQXOtW13YapDPPd2SPe2+gQaxbskd7ey7wjlQ0aqAjvKMpnG2VlC4Fed2dn4n8ReIz4p8J+LJ7fwdbagqkajq00gjihQNJJLG0mfLYqflZlYh1yFU7h0Hhfx/8A8J5rkmuTyfZdI0XUIYrPT4YszySXP+jRyzufl2jzJPlQ5GTnO1dwB2h0jRbzVri6gvIw93rEUl2HQD7VLbQjZDG/BIjeJZDtLYaOVT/GBw/jTxLo9kY5NaeTWB9tl1n+zLvTJ4khthbS20SMsittBnCDcQBuk3bQDWBd+JtI034YaNr8eox/2oNHubWzs5WJvftlxLtnvBLvZlG6OVgcDqRuG4KMvTrzUdN8CeJL6fxBBrmi2WlT6TooDKjyRzyxJI5U/vU8vMOUcY+ZQp24JAOz1KG2+Gws5bY2n2SwSxtXnSRI1E8cc8t0/k5K/aJYEjjBbDHzlAfBNeafE4W8HjZljafQGe0mnvrcXRuMX80HmyqArkhZBJFCXwqnDcEKa6Dw34r+zeFYoNL8EX13ot1FfWkljZ3W4XM9xMWWNimXLR20LjeRvwV4VWVm4fx/4007x5eDUYdFg0e8TdLcSG4aZ7xiIo1UEINu1UyAcL97+I/MAcvren2+l6xPaWeowalartaG7gBCyIyhlJB5VsEBlP3WBHao9K1S70XVLfUrB40u7Z98TvEkgVux2uCMjqDjg4I5ArqPiLp/hyHx40Ph6eSHT7pIrlpbiPbFH5480FFRdwiCSJ8u3cMEYPFcml/eR2bWaXc62r53QiQhGyUJyvTkxxk/7i+goA0Ln+3des9S1qbz7q1hu/PvJBjZFNcE5cqOF3mPBIAHCj+6KsWvhO8v/C8+sWj+bNbbpp7LYVkFqDtFymf9ZGHDo237hUE8E4w455oUmSKWREmTZKqsQHXcGw3qNyqcHuAe1SG+uPtk11HJ5M028OYFEQw4IZQq4AUhiNoAGDjGKANDS77RrTR9QS+0j7dqUktubN3ldI4kVmMoYKwLbhtXHYEkEEDOxpOtaJo3i+G4jaePSG+z3UjWdtFJcW86xiTbC06kqqz5Xr8yLyX6nL8PQ31oX8TWBtHfQri3ungmkwxHmYV9mQWQOEVsHI8xfXI9E+FvheXxZ4vbxbceF7GbRBdtby2VsyLDFI0fL+VKW3RruBKgggupQEKVoA+i/DkGp23h+zj1m9kvdQ2FpppII4WJJJClIyyAqCF+UkHbnJzWpVPStLtNF0u302wSRLS2TZEjyvIVXsNzknA6AZ4GAOAKuUAFFFFABRRRQAUUUUAFFFFABXnfiXxZ4h0DVLmKS502O0R1Mck1tboNr7igJk1CMk/I4yUXJRsDAr0SuT1vV/FP2jytG0G7RI3dXlmgtp1mGflZP9MiKjqfmGeRwMUAcfqHjm+nuIbeHxdo2S7A3FrfWNlAqguMyGR7p2J2oVCIuBJ8xzkLwHxeXRvFdxZ6xoxtH1pdMF3q622oQPBbRqQuGcACWUtIEGGzhFAU7hXoes674psfELpqevT2VpbRF5YLG20y38yPeUWYNc3UjKpcqMlQDwMBjXN6r8XPDtq9xZapceINeREy1hdxaXNaTtt3IGkhU8BtpypOCOhwRQB8+UV6J4j8OQeLvG94nhe58P8A2udwkGj6Y8u3MaAPskaGOIj5GfO4A84ySM8Hf2Nxpmo3NheR+XdWsrwzJuB2upIYZHBwQelAHeaHZQ+IdE0211exkv8AULy4t9P0i3sQIbiCzjd3uJlUKI3BLMoeQ8sJCT8jV0EStrmjT30F3HpV34meae5e2iWRdM0O1VkMbBEDqCUVAFwsnlKpIOQfO4fGOqRxXPm+Rc3EunrpkNzcJve0tguwpCM7V3JlSdpPLEEFmJx7O+uLGUyW8m3dtDoyhkkAYOFdDlXXcqnawIOBxQB3F34xfxDpNrBq/n6dY6doj6dpE8CMwNykcXmh2BG7zUBjI5CiVcjqxz7rxZZeIfG0Gsa7pUEmmw2iwjS1uJIYVEcG1Y4igJjUuNyqBgFsE4y1c3e6rfaikcV1cyPBE8jwwD5YoS7bn8uMYVATzhQBW5qXhuzOk2l7p2s6VPdC0Wa/s45xELb92pUK0r5mkYbiyxg7HyuB8ooA7QeG4bjww8Nv4h006b4a0dbvU4owPLu7yeQy/Z2kjcCQERQx7g55RNoz930uXx1ceHtHu7XW7L+0V8OaJp0moRuoeT+0XZditKz4OCEfcqvzk7sqFb5gsbeK7vI4Jr2CyjbOZ5w5RMAnkIrNz04B6+nNWLbW9Rs9RW+tbjyJlu0vQsSKsYmQko3lgbPlLNgYwASAMHFAHYX/AIu0bxlr+gprOnwabY22oXU99cvI8hlgmuDOYj5ab/lDOox3fPy5NdJD8D7F702D+NNNM5uGjEkQ3CMI5jdGXp5u6WzAUupBkcYbaCfG62NVv7zUJb3XJLuCOTWLuf7Ta28hBHzJKdyf88yzDbknJjPdc0AdBbaJ4+8BaZeeIbS3n0+1k83Tbi7heOQpiQo68ElPnjwHGOQMHkZ5+PWNU0ye2E6fNBp8tpBHPFt2wXCSEkYwTkXDOpOfvDqMCuw0LxFqOofCbX/Dn2We4jX7DZ2SQuuBI11LNjYz7mkfJA8tSSIxkADNaifEXxXdpceGtd8Pyalqk97Zzz2B00Ry3KRMZZPMVVyXZUgTlCPLTp3IBwY1R9Ns51c6rHqd5p4tJWkuGjAiJiaNhjBeNoRs8tgVxtYE5CrnzWmnJdapHFqnmw2277FL9nZftmJVUcf8s8oWfn+7t6mvQPiDp2l6vYeH/GVzr05u9e08m4zZ5Q3NtAEcAgqV3SKiAbSBlmztAFc34ksvBFlb6FL4f1PUtTeRN2qxTKIGQgJ8qZQhScyDrIBgcnuAcnUhjUW6SiaMuzspiAbcoAGGPGMHJAwSflOQOM2II7F9LvGlmkjv0eNoFI+SRPmEi8AnfkoRnAwr852g9R4V+F3iPxabNrRbS2gvbea4tp7qbCyrFIsbgBAzAhnHUDPNAGP4X0PUvEOqJpdhdR2iXrravPcSNHAWOZEjdgDyzRfKuDllGOnH1P8AD/wquiH+0NOtrvQ9Pubcx3Ph+4ZpfLu0kKtMsrOcgqu0bQA67W9AMP4Z/DzTotB0rVbnSZ9Omkije8027VixvLeU+VdAth42xvO0fKVkAxgHd6xQAUUUUAFFFFABRRRQAUUUUAFFFFABUc8bTW8sSTSQO6FVljClkJH3huBGR15BHqDUlFAHP31q+maHI1/4xvrSOOUSPqM/2SMqpwoQkw+WFJI/h3ZOM44rg9V8aQWT3EVh401LUHRMxSJqWhxxSttyBlwHUZ4J2djgHjPrlV75LySzkWwnggujjZJPCZUXkZyoZSeM/wAQ9eelAHk9/Z6z4n+0y6d4zn1G10/e27SvEaJJsOSC8dtYkliE4XLc5C55zz/ifwdp914h8PR6joEFjZpdzm7W0OoXVxqBZyWBm+ybnYeVI2C2WQkqVUhq9g+x+MP+g7of/gmm/wDkqj7H4w/6Duh/+Cab/wCSqAPlC78DT3uo3tv4XS+1Vra7uklthZyrJawxk+UZWZVHmOFfCAZyoH3jtHH19v8A2Pxh/wBB3Q//AATTf/JVef6f4b8L2tnfxvBqtrcXmnjS2l0nwxe2wW2zlgVkjl3SP0aRiTgLjBBJAPmCivUNW+EVwssEek3k8sKRYkln0DUoHd9zHJUQyDoVGQV6dM5Jj8JfBXXPEdxEl7NJpCFGeVbrT7lZIwDgY3RrGxJxwJM4JPYigDzOivWP+FF6jZeF/wC09f8AEGlaFfPL5cVrfyqsZ5/imDEBiAxCqG4A5HO2vZ/CjRJ9Haa6+JHhy21IeYBbfaYnjJVmCHzBJnawCtnbkBuRkYoA8/0q0067+2/2jqn2DybSSW3/ANHaX7RMMbYuPu7ufmPAxVMzM1ukBEexHZwRGobLAA5bGSPlGATgc4xk57hvhzY/29e6WnjvwxiO3Fxa3L3eIpwZCu1nAKo4UbiuWPK4yMsvYJ4E+Hd14qu9E0fxDpt2To7w2n2q9kDPqDvmNxIiiJwA6rtUk8H5CQTQB4+88MdlLaQS3bpI8Mp3METcqMGzGM7iGchWyON3Hz4XoPEfjy+1fx9eeLdNWTSrudAiCOXe0Q8kQth8DkrnkAEZ45Ga93m+B/grTLfTby+trueKytyl7HapcSNfSkIokKIzOoB3NtQfxDJwpB5jwx8K/COkX73Ws3HiDWE2MiW//CNXkMeGRlbd+7Yk/MCpUqVK557AHi914j1e88P2Ogz30jaXYu729sAFVWYkknAyxyzYLZxk4xk1GmhaxJZ2t5HpV89rdyiC2mW3cpNISQERsYZsgjA54NfWfhTRPB9pqmoTeG9Ejj1JbhLp1vrCS1e2SX5D5RkiDBCI5SFHGdy5UHg/4RC9sdL0nRINLtNX0/RriO5sLnUtaljnEiZKFhHARhdxVVyRtA47AA8s8C/Aa4vWFx4qintWttQEc9lvCiSARb8q653bnaNflIwFk53Y2+x6Lous6Vpc1lptno2hobgzIiTT6hF8+4uqofJ8obtpAUleW+UZzUj2GsazqMMev+HfDkmmGKSOYNcvdSclGXaHgVdu6NcqepCnPyYOxpOh6XoMU8Wk2EFlDPL50kUCbE37VXIUcLwi9APXqSaAJNNj1KK3ZdUu7S5n3kq9rbNAoXA4KtI5JznnPcccc3KKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigDLm1W8i1QWieH9SmgLqv21JLcRAHGWw0ofAzz8ueDgHjJqU+vRXCrpem6bcwbAWe61B4GDZPAVYXBGMc57njjnUooAz9Mm1iXzf7WsbG1xjy/sl49xu65zuiTHbpnOT0xzXvrbxJJeSNYarpUFqcbI59MkldeBnLCdQec/wAI9OetakMbRIVeaSYl2bc4UEAsSF+UAYAOB3wBkk5Jz49As4r2a7WbUjJK+9lbUrhkB3h/lQvtUZUDAAGMr90kEAjsbbxJHeRtf6rpU9qM744NMkiduDjDGdgOcfwn0461n+JNQ0601GOO88df2DIYgRa+fZpvGT8+Jo2bnkcHHy9M5qx/xR+u+If+YHqGt2H/AFxlubfY/wCLJtc+2CfWpJ/FmnW1xLA9trJeNyjGPRbx1JBxwyxEMPcEg9qAKdjplxqdnHeWHj3Vbu1kzsmgWwkRsEg4YW+Dggj8Ky4NVWG4ilfxF41nRHDNFJ4cYK4B+6dtkDg9OCD6EV1GpareWNwsVv4f1LUEKBjLayW6qDk/KfMlQ54z0xyOeuKf/CQ6p/0Jmuf9/rL/AOSKANSCZk0aKdBd3ji3DqJI1inmO3PKsECufQhQCedvbDvNZ1m5iCReGfEdow3fPDJpxJypUffmYcEhhx1UZyMg7mpSalFbq2l2lpcz7wGS6uWgULg8hljck5xxjueeOcv7Z4w/6AWh/wDg5m/+RaAKepX95qtusFx4Q8ToiuHBtdRt7ds4I5aO6Ukc9M46egqPTPD1rf8Am/abDxXpuzG37X4gnbzM5zjyrp+mO+OoxnnHSabJqUtuzapaWltPvIVLW5adSuByWaNCDnPGOw554y/sfjD/AKDuh/8Agmm/+SqADSNDt9Bguf7E0SC3km855ZLm4PnXEoclDJJiRnVtztuZiyggbckhT7Z4w/6AWh/+Dmb/AORakOla5dW6Ld+JJLedHY79Ls4oldSBgMs/nHIIPII+904rQ02ynsbdorjU7vUHLlhLdLErAYHyjy0QY4z0zyeemACPTH1iXzX1aCxtugjhtJnmx1yxkZU65A2heNpO47sLoUUUAFFFFABRRRQAUUUUAFFFFABRRRQAUUUUAFFFFABRRRQAUUUUAFFFFABRRRQAUUUUAV75LySzkWwnggujjZJPCZUXkZyoZSeM/wAQ9eelZcFr4qW4ia41nRpIA4MiR6TKjMueQGNyQDjvg49DW5RQBj32jX93eSTw+JtVso2xiCCO1KJgAcF4WbnryT19OK2KKKACiiigAooooAKKKKACiiigAooooAKKKKAP/9klSL+dAAAAJXRFWHRkYXRlOmNyZWF0ZQAyMDIwLTExLTE3VDE1OjM3OjUzKzAwOjAwRlDVPgAAACV0RVh0ZGF0ZTptb2RpZnkAMjAyMC0xMS0xN1QxNTozNzo1MyswMDowMDcNbYIAAAARdEVYdGV4aWY6Q29sb3JTcGFjZQAxD5sCSQAAACF0RVh0ZXhpZjpEYXRlVGltZQAyMDIwOjA1OjIyIDE2OjI2OjA1XAa1YAAAABN0RVh0ZXhpZjpFeGlmT2Zmc2V0ADEzNl8Cvn0AAAAadEVYdGV4aWY6U29mdHdhcmUAR0lNUCAyLjEwLjE4I+ZdMwAAACR0RVh0ZXhpZjp0aHVtYm5haWw6Qml0c1BlclNhbXBsZQA4LCA4LCA4IBv0UwAAABx0RVh0ZXhpZjp0aHVtYm5haWw6Q29tcHJlc3Npb24ANvllcFcAAAAedEVYdGV4aWY6dGh1bWJuYWlsOkltYWdlTGVuZ3RoADI1NlBwMAMAAAAddEVYdGV4aWY6dGh1bWJuYWlsOkltYWdlV2lkdGgAMjU2iAb6FAAAACh0RVh0ZXhpZjp0aHVtYm5haWw6SlBFR0ludGVyY2hhbmdlRm9ybWF0ADI2MhK8p+wAAAAwdEVYdGV4aWY6dGh1bWJuYWlsOkpQRUdJbnRlcmNoYW5nZUZvcm1hdExlbmd0aAAxNzI4MivK9VsAAAAqdEVYdGV4aWY6dGh1bWJuYWlsOlBob3RvbWV0cmljSW50ZXJwcmV0YXRpb24ANhIVihoAAAAgdEVYdGV4aWY6dGh1bWJuYWlsOlNhbXBsZXNQZXJQaXhlbAAz4dfNWgAAABt0RVh0aWNjOmNvcHlyaWdodABQdWJsaWMgRG9tYWlutpExWwAAACJ0RVh0aWNjOmRlc2NyaXB0aW9uAEdJTVAgYnVpbHQtaW4gc1JHQkxnQRMAAAAVdEVYdGljYzptYW51ZmFjdHVyZXIAR0lNUEyekMoAAAAOdEVYdGljYzptb2RlbABzUkdCW2BJQwAAAABJRU5ErkJggg==' 1051 class='mascot' 1052 alt='An inked drawing of the Hare mascot, a fuzzy rabbit' 1053 width='128' height='128' /> 1054 <h1>Hare documentation</h1> 1055 <ul> 1056 <li> 1057 <a href='https://harelang.org'>Home</a> 1058 </li>")?; 1059 fmt::printf("<li>{}</li>", breadcrumb)?; 1060 fmt::print("</ul> 1061 </nav> 1062 <main>")?; 1063 return; 1064 };