From cb814b353bfd039cf6b2661118432a16f9a07087 Mon Sep 17 00:00:00 2001
From: Berkus Decker <berkus+github@metta.systems>
Date: Mon, 3 Aug 2020 02:32:13 +0300
Subject: [PATCH] Add Raspberry Pi target configuration

* Use rlibc for memset/memcpy
* Create linker script for raspberry pi 3
* Add aarch64 target file inspired by Robigalia
* Force bitcode embedding for LTO
---
 .cargo/config.toml                |  13 +++++
 .gitignore                        |   2 +
 Cargo.lock                        |  17 +++++++
 Justfile                          |   2 +-
 Makefile.toml                     |  52 +++++++++++++++++++
 linker/aarch64.ld                 |  80 ++++++++++++++++++++++++++++++
 nucleus/Cargo.toml                |   2 +
 nucleus/Makefile.toml             |  24 +++++++++
 nucleus/src/main.rs               |  13 ++++-
 targets/README.md                 |  25 ++++++++++
 targets/aarch64-vesper-metta.json |  22 ++++++++
 targets/bcm2710-rpi-3-b-plus.dtb  | Bin 0 -> 27082 bytes
 12 files changed, 249 insertions(+), 3 deletions(-)
 create mode 100644 .cargo/config.toml
 create mode 100644 Makefile.toml
 create mode 100644 linker/aarch64.ld
 create mode 100644 nucleus/Makefile.toml
 create mode 100644 targets/README.md
 create mode 100644 targets/aarch64-vesper-metta.json
 create mode 100644 targets/bcm2710-rpi-3-b-plus.dtb

diff --git a/.cargo/config.toml b/.cargo/config.toml
new file mode 100644
index 0000000..0a6e1fa
--- /dev/null
+++ b/.cargo/config.toml
@@ -0,0 +1,13 @@
+[build]
+# https://internals.rust-lang.org/t/evaluating-pipelined-rustc-compilation/10199/12
+pipelining = true
+
+[target.aarch64-vesper-metta]
+rustflags = [
+  "-C", "target-feature=-fp-armv8",
+  "-C", "target-cpu=cortex-a53",
+  "-C", "embed-bitcode=yes",
+]
+
+[unstable]
+build-std = ["core", "compiler_builtins", "alloc"]
diff --git a/.gitignore b/.gitignore
index 4bfa550..7c0ef8c 100644
--- a/.gitignore
+++ b/.gitignore
@@ -1,3 +1,5 @@
 .idea/
 *.iml
 target/
+kernel8*
+.gdb_history
diff --git a/Cargo.lock b/Cargo.lock
index af43cfc..e89c0f1 100644
--- a/Cargo.lock
+++ b/Cargo.lock
@@ -1,6 +1,23 @@
 # This file is automatically @generated by Cargo.
 # It is not intended for manual editing.
+[[package]]
+name = "r0"
+version = "0.2.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+
+[[package]]
+name = "rlibc"
+version = "1.0.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+
 [[package]]
 name = "vesper"
 version = "0.0.1"
+dependencies = [
+ "r0 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)",
+ "rlibc 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)",
+]
 
+[metadata]
+"checksum r0 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)" = "e2a38df5b15c8d5c7e8654189744d8e396bddc18ad48041a500ce52d6948941f"
+"checksum rlibc 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)" = "fc874b127765f014d792f16763a81245ab80500e2ad921ed4ee9e82481ee08fe"
diff --git a/Justfile b/Justfile
index a560f8b..06476c6 100644
--- a/Justfile
+++ b/Justfile
@@ -2,4 +2,4 @@ qemu:
     @echo No QEMU support
 
 device:
-    cargo build
+    cargo make sdcard
diff --git a/Makefile.toml b/Makefile.toml
new file mode 100644
index 0000000..b881152
--- /dev/null
+++ b/Makefile.toml
@@ -0,0 +1,52 @@
+#
+# SPDX-License-Identifier: BlueOak-1.0.0
+#
+# Copyright (c) Berkus Decker <berkus+github@metta.systems>
+#
+[config]
+min_version = "0.24.0"
+default_to_workspace = true
+
+[env]
+CARGO_MAKE_EXTEND_WORKSPACE_MAKEFILE = "false"
+
+DEFAULT_TARGET = "aarch64-vesper-metta"
+
+DEVICE_FEATURES = "noserial"
+
+OBJCOPY = "cargo objcopy"
+OBJCOPY_PARAMS = "-- --strip-all -O binary"
+
+UTILS_CONTAINER = "andrerichter/raspi3-utils"
+DOCKER_CMD = "docker run -it --rm -v ${PWD}:/work -w /work -p 5900:5900"
+
+TARGET_JSON = "${CARGO_MAKE_WORKSPACE_WORKING_DIRECTORY}/targets/${DEFAULT_TARGET}.json"
+
+KERNEL_ELF = "${CARGO_MAKE_WORKSPACE_WORKING_DIRECTORY}/kernel8"
+KERNEL_BIN = "${CARGO_MAKE_WORKSPACE_WORKING_DIRECTORY}/kernel8.img"
+
+[tasks.default]
+alias = "all"
+
+[tasks.modules]
+command = "cargo"
+args = ["modules", "tree"]
+
+[tasks.all]
+dependencies = ["kernel-binary"]
+
+[tasks.kernel-binary] # Forward build to vesper/Makefile.toml
+env = { "CARGO_MAKE_MEMBER_TASK" = "kernel-binary" }
+run_task = "do-on-members"
+
+[tasks.build] # Forward build to vesper/Makefile.toml
+env = { "CARGO_MAKE_MEMBER_TASK" = "build" }
+run_task = "do-on-members"
+
+[tasks.sdcard]
+env = { "CARGO_MAKE_MEMBER_TASK" = "sdcard" }
+run_task = "do-on-members"
+
+[tasks.sdeject]
+env = { "CARGO_MAKE_MEMBER_TASK" = "sdeject" }
+run_task = "do-on-members"
diff --git a/linker/aarch64.ld b/linker/aarch64.ld
new file mode 100644
index 0000000..923ee1b
--- /dev/null
+++ b/linker/aarch64.ld
@@ -0,0 +1,80 @@
+/*
+ * SPDX-License-Identifier: MIT OR BlueOak-1.0.0
+ * Copyright (c) 2018 Andre Richter <andre.o.richter@gmail.com>
+ * Original code distributed under MIT, additional changes are under BlueOak-1.0.0
+ */
+
+ENTRY(_boot_cores);
+
+/* Symbols between __boot_start and __boot_end should be dropped after init is complete.
+   Symbols between __ro_start and __ro_end are the kernel code.
+   Symbols between __bss_start and __bss_end must be initialized to zero by r0 code in kernel.
+*/
+SECTIONS
+{
+    . = 0x80000; /* AArch64 boot address is 0x80000, 4K-aligned */
+    __boot_start = .;
+    .text :
+    {
+        KEEP(*(.text.boot))
+        . = ALIGN(4096);
+        KEEP(*(.data.boot))
+        . = ALIGN(4096); /* Here boot code ends */
+        __boot_end = .; // __boot_end must be 4KiB aligned
+        __ro_start = .;
+        *(.text .text.*)
+    }
+
+    .vectors ALIGN(2048):
+    {
+        *(.vectors)
+    }
+
+    .rodata ALIGN(4):
+    {
+        *(.rodata .rodata.*)
+        FILL(0x00)
+    }
+    . = ALIGN(4096); /* Fill up to 4KiB */
+    __ro_end = .; /* __ro_end must be 4KiB aligned */
+    __data_start = .; /* __data_start must be 4KiB aligned */
+
+    .data : /* @todo align data to 4K -- it's already aligned up to __ro_end marker now */
+    {
+        *(.data .data.*)
+        FILL(0x00)
+    }
+
+    /* @todo could insert .data.boot here with proper alignment */
+
+    .bss ALIGN(8):
+    {
+        __bss_start = .;
+        *(.bss .bss.*)
+        *(COMMON)
+        . = ALIGN(4096); /* Align up to 4KiB */
+        __bss_end = .;
+    }
+
+    /DISCARD/ : { *(.comment) *(.gnu*) *(.note*) *(.eh_frame*) }
+}
+
+PROVIDE(current_el0_synchronous   = default_exception_handler);
+PROVIDE(current_el0_irq           = default_exception_handler);
+PROVIDE(current_el0_fiq           = default_exception_handler);
+PROVIDE(current_el0_serror        = default_exception_handler);
+
+PROVIDE(current_elx_synchronous   = default_exception_handler);
+PROVIDE(current_elx_irq           = default_exception_handler);
+PROVIDE(current_elx_fiq           = default_exception_handler);
+PROVIDE(current_elx_serror        = default_exception_handler);
+
+PROVIDE(lower_aarch64_synchronous = default_exception_handler);
+PROVIDE(lower_aarch64_irq         = default_exception_handler);
+PROVIDE(lower_aarch64_fiq         = default_exception_handler);
+PROVIDE(lower_aarch64_serror      = default_exception_handler);
+
+PROVIDE(lower_aarch32_synchronous = default_exception_handler);
+PROVIDE(lower_aarch32_irq         = default_exception_handler);
+PROVIDE(lower_aarch32_fiq         = default_exception_handler);
+PROVIDE(lower_aarch32_serror      = default_exception_handler);
diff --git a/nucleus/Cargo.toml b/nucleus/Cargo.toml
index e048a41..9caf908 100644
--- a/nucleus/Cargo.toml
+++ b/nucleus/Cargo.toml
@@ -16,3 +16,5 @@ edition = "2018"
 maintenance = { status = "experimental" }
 
 [dependencies]
+r0 = "0.2"
+rlibc = "1.0"
diff --git a/nucleus/Makefile.toml b/nucleus/Makefile.toml
new file mode 100644
index 0000000..e59109e
--- /dev/null
+++ b/nucleus/Makefile.toml
@@ -0,0 +1,24 @@
+#
+# SPDX-License-Identifier: BlueOak-1.0.0
+#
+# Copyright (c) Berkus Decker <berkus+github@metta.systems>
+#
+[tasks.kernel-binary]
+script = [
+    "cp ${CARGO_MAKE_WORKSPACE_WORKING_DIRECTORY}/target/${DEFAULT_TARGET}/release/vesper ${KERNEL_ELF}",
+    "${OBJCOPY} ${OBJCOPY_PARAMS} ${CARGO_MAKE_WORKSPACE_WORKING_DIRECTORY}/target/${DEFAULT_TARGET}/release/vesper ${KERNEL_BIN}"
+]
+
+[tasks.build]
+env = { "TARGET_FEATURES" = "" }
+args = ["build", "-Zbuild-std=core,compiler_builtins,alloc", "--target=${TARGET_JSON}", "--release", "--features=${TARGET_FEATURES}"]
+
+[tasks.sdcard]
+dependencies = ["build", "kernel-binary"]
+command = "cp"
+args = ["${KERNEL_BIN}", "/Volumes/BOOT/"]
+
+[tasks.sdeject]
+dependencies = ["sdcard"]
+command = "diskutil"
+args = ["unmount", "/Volumes/BOOT/"]
diff --git a/nucleus/src/main.rs b/nucleus/src/main.rs
index e7a11a9..f964b35 100644
--- a/nucleus/src/main.rs
+++ b/nucleus/src/main.rs
@@ -1,3 +1,12 @@
-fn main() {
-    println!("Hello, world!");
+#![no_std]
+#![no_main]
+
+#[no_mangle]
+pub extern "C" fn _boot_cores() -> ! {
+    loop {}
+}
+
+#[panic_handler]
+fn panicked(_info: &core::panic::PanicInfo) -> ! {
+    loop {}
 }
diff --git a/targets/README.md b/targets/README.md
new file mode 100644
index 0000000..0c97e63
--- /dev/null
+++ b/targets/README.md
@@ -0,0 +1,25 @@
+# vesper-targets
+
+These are [target
+specifications](https://github.com/rust-lang/rfcs/blob/master/text/0131-target-specification.md)
+suitable for cross-compiling Rust crates for Vesper.
+
+They are very much based on Robigalia's [sel4-targets](https://gitlab.com/robigalia/sel4-targets).
+
+## Status
+
+Complete for aarch64. Untested for anything else.
+
+## Generating target specifications:
+
+See [description in rust docs](https://doc.rust-lang.org/rustc/targets/custom.html).
+
+To generate a target specification json template, run
+
+```
+rustc +nightly -Z unstable-options --target=<your target name> --print target-spec-json
+```
+
+### To do
+
+"panic-strategy": "abort" is ok for baremetal targets, but not for -metta, right? Will rework for userspace targets when we have unwinding.
diff --git a/targets/aarch64-vesper-metta.json b/targets/aarch64-vesper-metta.json
new file mode 100644
index 0000000..363679e
--- /dev/null
+++ b/targets/aarch64-vesper-metta.json
@@ -0,0 +1,22 @@
+{
+  "llvm-target": "aarch64-unknown-none",
+  "data-layout": "e-m:e-i8:8:32-i16:16:32-i64:64-i128:128-n32:64-S128",
+  "arch": "aarch64",
+  "os": "vesper",
+  "vendor": "metta",
+  "env": "",
+  "executables": true,
+  "panic-strategy": "abort",
+  "linker-flavor": "ld.lld",
+  "linker": "rust-lld",
+  "pre-link-args": {
+    "ld.lld": [
+      "--script=linker/aarch64.ld",
+      "--print-gc-sections"
+    ]
+  },
+  "disable-redzone": true,
+  "target-endian": "little",
+  "target-c-int-width": "32",
+  "target-pointer-width": "64"
+}
diff --git a/targets/bcm2710-rpi-3-b-plus.dtb b/targets/bcm2710-rpi-3-b-plus.dtb
new file mode 100644
index 0000000000000000000000000000000000000000..bdc7e43f05cfe1f2d4001627672783f06ed9a155
GIT binary patch
literal 27082
zcmd5_eT*bWb?@2T+q*r-;jquxI0nz%9=^lA_Rh@i-t8G2HW18*F*(cy3<Tz8XL@(X
zHy`ck*^hIQ%_$L}NJN1s5D-MMNF)*|C;<@?DM-1<N&c`Dh=LMD5kmaKM}i`ehzKGA
z<oA13ue!RYXLfCam6m$C>eZ`P@4b5Us=BJH<{xhS!G8on`>7xZUK<4UNANs@`}w$!
z;l_1z0Jsesh)dF_d6sN+8c)&)28|?Miw1+Mar^9I*zLEXPPi7vovkET8#KFT*P7kh
z%HnyVGS6+eZ+KYqlrOf+i{*!ysr<@&6lVqj^2V~5hw+oSc-6*BjZV9fL<ypTdkdcT
zFC_iuLJ|$yjn3-%s8(IBELDhri}Z-|>Ksm`TB-OrHvs1$!D(!@+I_@K-kb1zvxV<k
z;+m1PneVNJc7LnaLd@hlgy%a67f4F0A-Jt>1GFlY^NtD9n#UbUdb>A-inron*zEU)
zgMOzI4J5-_%@$7lTX8=s_&beZbF<ao01oByaL9imID?)^UeaXI%?ptJxTJR*?ao@C
zGFB>UD=StxEazt2zbZHzak~!$Frh@4PW`@D($hM~>z91|hAF4p6cQu?ATH8i`fu-(
z{t-!U*AmIUIFkQ&4G(c!(z9}s{>N>8Q~q)$KV|rY$v@VPNaK@!889?oPfY)GF1?wP
z@y{i_D>|SAz7CEf|6gi)j}@L`sE)2ndb>s$R$%6SewP2Yne?oTOn*w!w~{sFzp#=m
ze-`PVU+6?FX<epXjsW&W$+NzOptG5O7T9nz8gy-=%hu<O!2Pn|G<Mr@G+1Y5T$E!G
z_t!@FSO8OD+#d{At9~$I8NCQlW)G%tmztaXB<e|=^iJUZR<jShs5h*~{eI{E>O<v~
z+H&RI-k`qK7z~s9O>UdtvK>C&?-@@*n(<a>;UrAD^h5u{2re5hJrBWec<~n@OrDqy
zU6sNg{_y)>3ua$;*}_1hbRWVs+@&U1Yxg$7ZX>oTmb}a_a#?plTJ$SH((cBcC|rYY
z<)u8GMA-M0>KmC3e_MLx9s;khNUM1Aw*H+sKLMQAT_*?^@o-t%!Yk{iG~A70A{EcX
z1n2og_8k3k2t>kgkp^{eY0s2c_F(LT$TQ_4-W;OMRy%2|!QK$(<@2zFxaefmRgU2U
zh(aa92U$av8Q3+HseBv*jQmg@KG`<-yxBh478$2s;FErmPx@Rw*{|{WLi@bkK7VST
z=N(9=oONV>6f9Q){8af<<If_0miV*GpL6^<&z}|kT;NaDWRW~o$yAkGRmm16n~g!#
z3LBjcN=bG4IKt#tb^Pui_?2ZZP8&UnTXbIBok-qOz{%Es+|9?soz{?OTGmGq_RIbg
zFOGVEy|6Zd((%3E2?kgO^OgbooDH)c2xEKWll8zS>xEC+{gc~^tpL8JU2k_A8&R-X
zJGT_H6WV~_;8FU54QsnRgSg1tjN!?8F!`$Mx=5FHkd@CM63lec`8u8|pRxaA6sU|_
zaA3<K2XF(93wZI#Jbbcz`d(gq63!>#TE@2#KJ3L=UrZC;N4s`O8*QsVL>^wuYk6H|
zoD3_BZG?1H*Q%?RT6n2=s37^-j<WjdVo*U~N+15=FRmfJ>cLnhFV!Q<{JsGRUFCu8
zOJp7$ii|0rh=!2LcWJLIfY0EUFvu=`fpn=eJ}C#&a81EiDGyU@?@ZUUmw0Kc6HS9|
zryguY>y53>5Ma$O{*?}?)Qa16vQ}ZLNsp1|Z6+#uP+Dp?v<cb(Xw!d6d!;{xKM&a7
z{v>YFW?fPa%0Pd195>q!+X~wa+KTwC+wr76DGSP&YU0T<Y+QJyk02kV2xAsuxK=|{
za6m`+JqX>r?VcN<ySS96dlG<o+^29;&v)TIjoar}>5`Ynkj9Jr=5Jr7^EN$|X=#P|
zh@&#GTB^7yEc-(;=lM&~m6olxskTwth?|`&715Rmg}ll$>zDPZ@n$wIIwv!tbD>ie
zIxL%)<|7^Y4viPlxq$RMoh7NgG#}~Qy$>C=Ya^H8XUPht<&)0YedxRl=_x-ok&AY~
z%ctYnpy=7tm+0r^z|YfJVkP17>D=SRbNX?%V)2FU{lFKx7+#y&GmVotY|oUDm*=Aj
z`TJ?$Wa-qLeJLG|13dp)NQXnSEFGhDpC9Tx#BJpeI-XsKT&o@(Q+vh;d^#+Lai30J
z?>{p_=V1JJ^(p+kQt3Q8Y-~IWpW^W=bYG=(<7QXLRz>Y16MUl7-%Y^rec~i}e>P9g
zRAYvo*5iwTdnaz6US953J9;}^V_z7*d3k7G^yNN{d>uT1bg_xp(Qvi}TqmPXL+cjl
zqNmr4&@j^_numOx*@utUdNhnpVHE1+Ar1CPO0$V@UY6GZrm|QX7XWg3NP~6d)5y#6
zdZcG*EYWSdJfy*Ki%%oZ$Ad`E(GYj5c}OGQ#_}}Ypfr*eUQUN%ex_G3W#4A&<{<q_
zo;Le<;V+5X#%|by8M?<UUG_!rEtzqF^4|nJPxB$bvNRW+%t~_}IHz!r>wEJw-{{e_
z^(pS1e5m|rhlOJkpI3%$T<rDdJi4aWNbObW(q385?91r)i~M4q?nU5<4md?%8>HV~
zL!Z)~bX?{0n3w%cSz66uf>{USgq#kPp6bA-mmf<!JeJ-fO-S^k^oo3s(jyMXMU<15
zuh%yto|Avk^bA@0W#FAi^GY9+r;lWz<<q}pVWm{Ri++Ev{Hu-m`pEmvpU=|r^t<T%
zpVGSvxTkSXqW2b`o;B8k);)FR%lXzUEswYAf$Ba_?~yD$z9k&EUh=f)yIdVt>mF|h
zv!gt{w`b{*x6E9-*1;Lz<^67+);qGaJl@PGl{!{>+OGXN&C~k@rHAobJ?S*IBYzZN
z>I`kq^^xPo0czW5<KlnbsdU|V#aIe?Id19EA8_17yJa7q@B8w+z6&^n$$MaRWvy+x
z4A-_{1Hvazek|{Tz8>>!4Rce5H`Z={Ye*gxpZ4V8i!boT!=kUtz!BLRouLS1^JA<e
zGO4bpXVmY3`>cl2m3}a8_YwebkvHgEXwM;h6gT@!<++J4%d~Ofk@X`y3aw^RPss_M
z+8z1x?4eLz_76gf?+pm^Vp&RqaZg7=BhL@)($SCs4B|cw(r4VtP)Gx|s5C?~#0A}b
z?LE&6?bqlAD`B2uNKgCQlL*h_K81VS_(1i>JnVybk#7FBGD*E~PD09F!%V)dVVf>;
zuy5CR6Jd{cSB6iI_8|03AEYERx-A3ene=b84M)4`*cIALVp}0ExTL-`OkMaq(hmt8
zS$fRUQ5!k~oV-8vWEb7>U4(RmR>4vn%cTCY^K)^hQmqD!LHDc|8nnAnGxFw;!3XAP
z%W9^oKR0joLXahWAh<bO%0(FMlF#QO?Mc=HW=DcXyjJHl3E;e#4tb`2F*tP$coN5B
z>bGo|ddSbG5%vkB<0(FbG~k1=%yOl16=7bMuIPt#EV?nvZ?#IgWF>gyGpidjm?xNY
ztPaWuvN=1L_Sdj;2m722tL)_UQ-B>Ur+owb=+tKiyI4U%0<LlVGjCpY>WZ@8VDmA4
z9br6$4&zTD%**Ov>PrZFen@n}epPfbx~wYsSQlBH0Ff|Uo=z%^pYmWTzrGXG4~hK1
zVR`h?%+Fi&03{4OJ)qr=TOXSGCi3vI<&V`3{TOke3z2mmVbeB7mWTy!R918j$ivH)
z#Wt{tD9JdO*8dAUn98s9&w4qD+tYtgMVuFDkCWHe8~a`AP5o+--imC6Fxm?HJoZ&A
z54Jk>zj$)K80o?n!=&x;D0*YPmY|AOw7n`7jW}r#H!yI91V&w7l9-E6lpFZdhYlxi
zTlMmDzHtpVm8|9Zx|&q3$NMuXw`t3jvduDkt&%RIi;Sao0z~BFMZG|uw3CYnl8l3?
zo!sKVepGf+RPWHO)H`fQ>t_1ap!A+6(zw(w`)`pqZtq5&?M7!i!a7*3a?XBTK$+;@
zvwk2&_HDw-ei_)TiV@j$Ts+R+X+Nz07VaXR^oyDOc=GMV@)Uz)Ay3*S_Twp1p0IW!
z3gY(@fbk+fqjmvANlo<tySPTs`*1T4>c;h#>MPFLH2C(?lg<7h3Pjg{nmo|aMBCm^
zj&<Z0-L?`V$AzpMH?g418b1)Npyb)=^Zi7l%T}1$H~AxMKR%J3Sv!SKa=Iv68VmNx
z`Xo*0xb$Sac{PZVW+V1BW709FK7E?(*4M5Mqd-Ef)&T3|gdqePye!Ytv^CZnZ_BgT
zAI1?zM~$ugXJ5)kPDemQ9$rf4>j<kqGCDhPk?9C)`A%M~d+LNdu@0n;(s7*otc~>9
z*JSGm<%b+xF(IXYY460vRm6E)ncX)Ky8b}k=!c}<End+$3V37tS{>^t|0hAm@Ne3R
z_o<ZdK_58Ee^GyX;^H-+uHrrj|Ell(Y;V6dvVrn){Ab?no(})lL2DKFLHK8x#Cx{<
zZ-R#Kk97j^Rn2T0r@d$O4@AOnDWC9F*BL+K!L+~PoTJ5?eyt5F47^W25`6eW*DRcI
z(pK5_(>;Br@V>dtPyP6j+dh64h{(e$<$aaW%luK8`X{xK{rGqkd4&)74)DRQC&P!d
zm%N{>vc$B^OM9`z)!(BHxpyXSd^*veLw{ra<h(75?wNAd>=X5SAU|1kezHpMD1K5x
zpu>wa$LR^OIR8mq5SP5te{rlTx@(H=<V!>H$cuRNcUk+}>b08<F+rvu1D#8I*NAl_
z*t=F{0JJ5quS1qYe8SW=Lkk1E^km2ApE%5a61Ubr<F>jS@4nAIh}>QsiriN~Gb4BI
zJL3b&4e^cK<grL@j)C)X-)mvdh1@sVvcQ|j-9fy>uQ&1JRf>A8xR39cO;mZEW*<rY
zQ%C+?GGlH3lUB(y>Zgjv+SgV=jyltFTpN3?$J(r4YiosL?YodJ_M!4Vqj!sI7eVGZ
zlNWVdC<}EfvTR4@b7XyCusRs6J0K#Bm)b7c_+>;hvS>TTc+lag@7C{?4$?NYji`-k
zA5=<TUEtPN+*kPIY0`TReJd}I_ZU%{vx6z0I=?ZFPvxnHyrRR+R+pX31#eP{<&5?*
zL}ZDkOehY1^8IB*XW=KW;pzBcn(_nxDCK}3;gxmzYY1!mAg<~iVZqTkJ$Vl?uOO~)
zs{=Qu!@4F6^rt>6^O&Jd=P0~zKF9AvIOZk|_|)n5;>r1lJ8*mcT6|3(FwxoQXY7(c
zYj@`>D<Ke(hZpG^oqZS~P~HnJ8&H}?ov}>niskTPKIm-U{)0Nyc_7yDll|caK$?I0
z0|@gQJkkUG=?{UmTF4g~b6I%lQL>!$*Yo~U-&eHXV;O|SxJ$@mzn~Xlq{aRz0DP&o
zbhfsPZ-jAKS!ABZ)9qN<er$Ae-}dMEJ&#et1b#*C$AD1k>W&>J+jv>DOzM2KO7eyJ
zAoz(iZThn?1=@wx-SpohOxs|bHvDxwsmpx5uumpl(T(rvwvZ$=vNpT2xEyXbrLt@~
zY^AXMX#Edt8KwQV4oP{pv0!iPdM?BYKyx_ggzYAitX%Ld!KV?GW<VIjFToGPD0_;w
zr+PqK-lIud^HXQ^JxsHCq~542<|`F%ArV~qCZEUi{ss*sX&HFOEh8%BC`^5s_7^CB
z`g=seMVzAdTi^(9T301}PY##NH>b?FpJN}x7wRbFN9X3!vM=pjCxC9$@kl*TX6+Yz
zzo)SM>X`31qO(rF+33_!)6G@$a+J1{yw1*rooYx-<mKgfT$LzU5*Qu_u2<C)>sk02
z-OeO5Pm#E1W6L2Bvj8lxG}}aTeC<h-cYHxlt`F1qOTx5%*+1C4t}jA=B`~zbk@Xeu
zo>><er*o7scCJJFMbf&CvhbAh@D%&G2XWO)ZX1{2okDt64gdf20uE>Blc?LGwlYaS
zx7&Qs$JBL%@yzJwEaIY{_4c5<gY7C;x_r;)=rPmII6sxyZ#szEq2>vZiRrjf+qukW
zq3y6S5)Zu0a7{|bhU4lVcv6?_e}&gXhG!!@j{0pNA`h>p!<TQ<cc*#X+={}$*YqRa
zdI{^{Q^2PWQ9T#g{eE(?BN92i?Rw-t?@yLP4*}`Kfo|DPd>Fw}u=kZ~^2CqTcj?;*
zA5`BVa5J`nI4{yV!+^j4*z7f4b~cgQFlWn`u>iAbyvhhJ8=qmBUOyrAPJT<#Zp=?$
z6qk0LDc{+mVi}si8oOtts4c0jkuS<F^2hz1h@Cnv@;Oqr%AUg`EnnY^e-!!ID6G69
zAMIAk$?oOJe9LtgaC|>?4r7wd_G3PX!xVz#B7NF1_xG$K{Bqn1WB<pCW%_(<TNuVd
z?S41v5{K!dcIP2j98*>qG1J$IJZ77!(2x$;^*?+MNcXVj^)#toc2I!O-fkwsAmZdv
z-W7}NF^Bhb%G%Yk(rxHc7U$Qqicb-&K4&;ygiZv1Tzg0Q*nUm>Qu2Er=$ytaawl$U
z`$XEBkMA<fCwZF~tXwgkntZZv&NWk^iM->->_TI8ky%MY-f7mcR@n+AMd2*}lEtw)
zk$F=uefo4iY5MV7OQ*i;#YJxNlJdSvwH~Nk<{Mvb_C4^{J3h9ebjdgM&G$y9H~UIR
zdR(96J6zc7$Kh@>YO~ScvSrOYV4@lqT71V888EC5<1XF1q|1B)KlZ`8;xO6`8|O9E
z(JLIo!=9vn5t>7M9pw2YX=kK~dmDpvO||@G=#?R>`U2{Ue#z6D@T_qry$L_2E@Hb2
zI_2}E&9CLqfAV4+{%z(RuI;ZZo(q$1EU7NP=;?95xc6H>Y*3xH0V6u&oQIGPq*Q0i
zVv0`Rv^ieHg?-Pw1It*waLBFA4vuy=BLo5Y7mKU)&T)>)XkST{_RQ1eL;d_g`1neW
z500-LA2md9JyU&<&O!C@jkFx86OPXuA4b*Bm=E%BP(Hqu<D+c(5MJu_{x;6!z(+7i
zy^aK2q>F3jJ^0b^2fgs`dErmmFl>JYa|ywV#B+t~gXpoXsMoxDUj@M6#f8v23!&vg
zsPgewwmkaV_u@X03>!o5909^Vf%{|u{3C$RkHTlZ0Qjj<c<^z+Us3?S4)|T8@R=_H
zeoGDx-#7Dbq*ExB(JyhnLz<Iu4xuj(Zkd2X*&o7vI>!UykK#U408apaX%2oHUX5-B
z{BH3xG!Ikga>djp>*6?Y$_{6}KWIiFMmnzmNNna7q=zmYDPgDGZ4V6riv$02i2Z{p
zrxmSjZ6Idy!)y+{3gLUk@NjkvoV-!qFXIk#a$zid=wZO`?Y5hPKE`+P*(i#_s3(Ut
z2<yT-{MMnjWbuZ(VFxd1(gkE>xE;97EG`aykn@8QMI=we>x{#bp4iA;1|I#X$78F%
z(@Qqn>%*|Ij^lIEIyeU0Ul-iQZkWVT)JoGZmN@h~NL%3WGP%$1>ks`w3SU7`WF~)X
zzY93XV{7-U-QgV$2kngwzfUCHzXM*SfG+Ld!ZUQgO85l2;)gIs?hiP^GW;Ayn?Qe?
zfuXN)-{28X@}<YRh#Y)h49HuUCQ$#{C;cMArABi|G{VuQ4*fS!#Z7sz?_G(am`J!R
z-s~KvGkiSgV(N!TXFn?M^cGjkT0mTQjCW*I;g{$4>9E(?In{WdD<`H*rB7U;W8q4l
zybvyFGHx718(W>mus^6TZZ9Im&^g9{OTt?vMwprgTC;arWUHsydxP5Bp8$f!AMoM;
z&%P^7lYZ@&5HI3kdE01<boS-JB5RrV25)$9H7#fM0WS{l2oJvupzu(yCs%PaL&x@J
zq=$AtJ6OmZj<b+E7Dwy2=xnRmJ#!||$iXqBeG~3UXJ2u=y5Ct=@Rg;{Nf`x)bs)c%
zGwHl5@G)!7vKl=!gZa_NJnQqYVB@pz5kA?#FtcUO%UZ}C`5^q>3EcM=;O357aJV0v
zglmpaaJYXs3D<5;rOajU@R<VK{4oZK``6=e%|5zikQ5$HfbQof<LYq)4*yI0;M*=h
z@X7bTkHhzl7a-r{<vWvc^#}o>jj{0ILk0L)w)c+)5M0#Z;bW6<y?x`vy<-xtJy?M}
zlZP|KxJJ`8AmJh|=`K#f_2?4!6$Q9%dz(4p!|CC{0^Hmddx!g$3Ak1bj$h*svTY>Y
z)^3DT*}6q^vs>UD-K&#u?F^UFeRnag-4UAh4b<5OCgNVm)P*^VZbUXi*KARD{Ql7-
zx=YfW1Q#}Z_|FP(3$~m){Gzrx4xje+g(CXdZRd{ff1QMDwv#(tbKYB4A9zi+dOnxY
z-G3F+^|yWt-7@(7K>=>M-8fzEK8>ld8^+>#TTjiFU7^oBcOE2<*-EQC9Vu#uDNklA
zFYOQfA6XqspSm*JrHM;k%=wgA9U8hG|7JV1<E5yLF^^Te8}E{SZwxP)ZNr{^$bZ4P
zkP9jOR94de&4bX->GJo-=Aj-;V^;nA=~!G(KeoqVo>SoIZwm6j$B%3uCO+E7k$)<{
zcYf1$PQ;xD?pF$MIR?mW_m#TB*z3r*3h*hV-GVE4c;`Iw-2yz_YRj@Q{y6ge0vxor
zO1ity^c!V-hH`iuuD30gbW!%)@d8}-iAYxd=3ZQkBSU%8!B}suxL-?1M(99>xoQEO
zB)cV5bvO620$gtkso<gh=3Z5RXWEe48tQQ0I0o0->gjObR)Cw^&MCMU!~RIlN`01R
zq0SgT4~vlDY4#jZ*y3DE<nhxN5J`7{u^x%n8H;D$+=$1q|D>~5UkExwp_BPAFWrEI
z{G>y?YejgvDahiXyt(%Y-snah%g>w{bDIylYn5~ZjPm<t$v?XJgXyfp=isc^xeppy
zM?T<J8H^2#ek8ByW(+d=@w%p)IvM>yThon<nx1~hY}12hc^2*5AB%jWACHng>)QD9
zj7_8;YudWL8F=QMaP$L8<?|^i2MZ{$_57K)7~##CF_NF|A3)267kezNemmxUH})Fj
zAEm!<{sn%rwxINK-=blyW$qt^XZwMem31D^NZ|W_<VD%}F1z13y=*H6XY^wytp_vC
z8}reT<&AW{D!h$;45an2&)LUw-_-oMk7k%3^KNthDe1cCKKjv!EoaX3eWM?2F#Sf{
z<IW|<I$P=6nKFQki}|3-qoqvRg7<ZR!NL60(K*3M7v(kY^8{YJ*iIbG*^QjDj5)fa
zw@AKpL7BLmw>4wI>>4oPMQ4#?PU-0F3o<vIm`A#n%CwW&G&d&1oZr#A7qZ``&H`5D
ztdQxdMK_p#J9<uF{4pzO<dg81rEu5(6TX_lYe02$UY)|xGz}bOj+{$P-Mn7Ts$Q_O
zlm?gZhYj4$CK~v0z~8=5Jo!gnnZBM+w{vYecR1JVcjLye&2>FF_&!M6VT{k1u-Re0
zflV|~l7u`wA;Bt2`|-$z%|^aTV4gT}LC%@yu0gZB&cmN^yf0}s13iHkpPTer{cd0l
zM`mmT8LtHPYyz2U<(_<w?gAN#$@rV`Dt~GLzb?aFWvcwtxSAZu#4o;x&{MDV!yffY
zm0+#kA2tRXNf6@%dLCSjbNd@t!?=+o?QQJ6^r1>7#L3)Ae~<*tezd;cZnmKo5ZHtq
zP#eVAz>(XKGqgd>x29@@6lR$!Rcx=(MTU9iFgle54T*wg5C1;UZ6sHMd1-PXbk)Gx
ztJOYgBEk{+QWeJh1G7S7h$dH)VT9Fjere+!v>(hHB$H3wO)$@cY%MX4$}>3(KnhA(
zPtWcT<~^ujVYDe<+Zs+pCK-TAXnhNbZOm{R_!iFL;PQH`r*ecm<T&1Jw*tJ_gwZxs
z9Pac7R~iHPP(x|ULD5FpwwSFX+-bLln})EzVr7fc^(R;^NrkOOTlJTO6jJOAD&I|)
zF0D@8Ql^dLttH+XhNfh{c9MYhv(eMfH}Y{<#*kHxsUTZ+t1)bZodyqUZ?&4iX56y8
zz&FvhuG&%x*Q<gQ>aR|D;M~HImx3l@mZ*YxofbFdZ5iwJd*J|!FWa)#Z|cr|(-_cP
zz_6)8iek)_f`MUUT#e37<7yJ3rp@A7*hS;(w*ri_+s&vxyow#poPi%ioe2MW5z@N^
z*d<p9<DC}F9N%lFQ4=D|DI77HPMwv5^yX$%M?;S4^h<OObP2V3`%16Bv$F};)@@<W
z78)dHIoIH!SQX+nGO=13OIornE-eNwsV*y=c**QDf(MGjawa2Y-BRA)oZ$snR}6-`
zb*vfI&1WN!zYeA=feln8;A*HYOM3!?4c28bFF*&tJaX8VivS28)#>jzh_2D0Ur5n4
zlA<d_(L0T`sDm1jqnu@_Gzy9r>C&Ym8ojrY)P+kDE8OnmH0TtK&8P^TnguGquKt+^
z?ehTdbQ!^4ByeFY0=O_H`7@LFnFEEr2qs1R*pi9q6uKnY*|$Yw8*~Mxw-K#lW>-vx
zU`#Z#pE2+>2(X(c!Tho}f2=_e@n?V2um{J458!t4YS9Z{NW++2bvT$kwX>b#U9&Tv
z>@kJS^U`@r5Yv|II3<j!F7}@iM!{y9fFfdA(L}s?B_NN$Fqf5P!d#daDZ*Y61UEBB
z?EKW5fsqGGE`wmpGZZYx83fcb>Lxq6<!S~0ACQ}zVmX|AlF22}meC^hrgKA5?*f)u
zw;_9;S~^>!b1_B*f@Nfppf^*3V&MHSOp+(6(w#|ys&`@h`vII6&vam22i*USNHxIA
zYK1@5fLjey{8}J8*K}wj4uk_+ZnEJ9j`Zb*_JS=57%%k(fp-4<)|}sU>yY1!@6D&L
zGB(FSR&{<^$S22ExJh2d$@l?J@fNs?w`%-ZRG$Rq#TNzJtrnM}>l_U+jFG2={|{mJ
B18)ET

literal 0
HcmV?d00001