ntpd-1.1.2/.cargo_vcs_info.json0000644000000001420000000000100117770ustar { "git": { "sha1": "6751bef01a2469c0824f1db8710b7a3418b824a8" }, "path_in_vcs": "ntpd" }ntpd-1.1.2/CHANGELOG.md000064400000000000000000000162421046102023000124100ustar 00000000000000# Changelog ## [1.1.2] - 2024-02-01 ### Fixed - Fixed tests in ntp-proto to also work outside the repository. ## [1.1.1] - 2024-01-24 ### Added - A work in progress implementation for experimental NTS pools was added ### Changed - Updated dependencies ### Fixed - Fixed missing newline at the end of the prometheus metrics export - Fixed error handling on NTS key exchange sessions - Small fixes to the experimental NTPv5 draft support ## [1.1.0] - 2023-11-23 ### Added - Server can now be run without permission to change the system clock so long as no time sources are configured. - Experimental NTPv5 draft support was added behind a feature flag (disabled by default) ### Changed - The sources section can be left out of the configuration now. - When no sources are configured, the daemon will merely state it won't change system time, rather than warn - The MSRV was raised to 1.67 ## [1.0.0] - 2023-10-05 ### Added - Man pages have been added to the built packages. - `ntp-ctl` now has human-friendly output - Added metrics for NTS packets processed in the server - Exposed root dispersion and root delay reported by time source as metrics. - Added `ntp_uptime_seconds` metric, which also includes the software version ### Changed - Peers have been renamed to sources. - The configuration has been completely reworked, please check the documentation for details. Configuration will not automatically migrate. - The metrics for observation have been completely reworked. - Several changes have been made to reduce the number of dependencies. - Send software timestamping is now enabled by default. - Hardware timestamping can now only be configured if ntpd-rs is built with the `hardware-timestamping` feature (off by default). - The default observation socket path was changed to `/var/run/ntpd-rs/observe`. - Upgraded dependencies. - The command line interface for `ntp-ctl` and `ntp-metrics-exporter` has changed. - The copyright from the project changed from 'Internet Security Research Group and Contributors' to 'Tweede Golf and Contributors' - The `/etc/ntpd-rs/ntp.toml` file in the deb and rpm packages provided by us is now managed by their respective package managers. This may result in your config file being overwritten initially, but future upgrades should be handled gracefully. - Added actual ip address of ntp server to observable data. The address field has been renamed for this. ### Fixed - Fix bug around handling of leap second indicators. - Fixed bug around handling of accumulated step thresholds. - Fixed incorrect reference id being used by server. - Fixed user creation in packages. - Fixed peer trying to request more cookies than it can encode in it's packet buffer. - Fixed server not sending nts naks when receiving nts packets it can't decrypt. - Fixed source poll interval not being updated in stats. ### Removed - Removed support for the RFC5905 algorithm. - Sources and servers can no longer be configured via the command line. - Logging can now only be configured via a log level, no other filtering is possible. - The daemon control socket has been removed, the daemon can no longer be reconfigured at runtime. ## [0.3.7] - 2023-08-23 ### Changed - Upgraded dependencies. ### Removed - Removed sentry support. ### Fixed - Upgraded webpki to deal with denial of service security issue during startup. ## [0.3.6] - 2023-06-30 ### Major Changes - Restructured configuration. See CONFIGURATION.md. ### Minor Changes - Additional example configuration for freeBSD. - Slight improvements to clock algorithm. - Upgraded dependencies. - Clock now synchronizes faster on startup. - Added support for listening for NTS-KE on multiple ip/port combinations. ### Bug fixes - Fixed bug that caused ntp-ctl validate to not print warnings on the configuration, only parsing errors. - Fixed bug in nts parsing that caused NTS to be entirely inoperable. ## [0.3.5] - 2023-06-15 No changes compared with 0.3.4, needed due to technical difficulties in release process. ## [0.3.4] - 2023-06-15 ### Minor Changes - Fixed bug that caused nts-providing servers to fail after key rotation (which by default happens daily). - Upgraded dependencies. - Fix bug in package installers that caused us to overwrite configuration on update. - Removed dependency on Axum in prometheus exporter. - Improved measurement code to deal better with external programs changing the clock. - Removed some spurious warnings around server strata. ## [0.3.3] - 2023-05-25 ### Major Changes - Compilation with musl libc on linux (thanks @sanmai-NL) - Compilation support for macos (thanks @andrewaylett) - Compilation support for freebsd (thanks @valpackett) ### Minor Changes - Fix for invalid NTS cookie decoding that could cause a server panic - Improved mechanism for waiting on timestamps arriving the error queue - Added security policy - Upgraded dependencies - Remove exitcode dependency - Remove direct prometheus dependency from ntp-daemon ## [0.3.2] - 2023-04-17 ### Minor Changes - Updated readme and documentation ## [0.3.1] - 2023-04-17 ### Major Changes - Our new and improved clock algorithm is now the default - Implemented (de)serialization of NTP extension fields - Implemented NTS Key Exchange - Implemented NTS client functionality and configuration - Implemented NTS server functionality and configuration - Changed format of timedata reported for peers to ensure compatibility with different algorithms. ### Minor Changes - Upgraded dependencies - Refactored internal structure of the code. ## [0.2.1] - 2022-12-01 ### Major Changes - Pool support. - Prometheus exporter. ### Minor Changes - Upgraded dependencies - Refactored internal structure of the code. ## [0.2.0] - 2022-07-29 ### Major Changes - Implemented support for running an NTP server. - Renamed `ntp-client` binary to `ntp-ctl`. ### Minor Changes - Made poll interval range and initial value configurable. - Minor improvements to timestamping of received and sent packets. - Minor improvements to log output, particularly around attribution of events to specific peers. - Upgraded dependencies ### Bugfixes - Fixed a number of bugs around poll interval adjustment. - Fixed a bug in peer dispersion calculation which resulted in overly pessimistic dispersion estimates. [1.1.2]: https://github.com/pendulum-project/ntpd-rs/compare/v1.1.1...v1.1.2 [1.1.1]: https://github.com/pendulum-project/ntpd-rs/compare/v1.1.0...v1.1.1 [1.1.0]: https://github.com/pendulum-project/ntpd-rs/compare/v1.0.0...v1.1.0 [1.0.0]: https://github.com/pendulum-project/ntpd-rs/compare/v0.3.7...v1.0.0 [0.3.7]: https://github.com/pendulum-project/ntpd-rs/compare/v0.3.6...v0.3.7 [0.3.6]: https://github.com/pendulum-project/ntpd-rs/compare/v0.3.5...v0.3.6 [0.3.5]: https://github.com/pendulum-project/ntpd-rs/compare/v0.3.3...v0.3.5 [0.3.4]: https://github.com/pendulum-project/ntpd-rs/compare/v0.3.3...v0.3.4 [0.3.3]: https://github.com/pendulum-project/ntpd-rs/compare/v0.3.2...v0.3.3 [0.3.2]: https://github.com/pendulum-project/ntpd-rs/compare/v0.3.1...v0.3.2 [0.3.1]: https://github.com/pendulum-project/ntpd-rs/compare/v0.2.1...v0.3.1 [0.2.1]: https://github.com/pendulum-project/ntpd-rs/compare/v0.2.0...v0.2.1 [0.2.0]: https://github.com/pendulum-project/ntpd-rs/releases/tag/v0.2.0 ntpd-1.1.2/COPYING000064400000000000000000000005111046102023000116220ustar 00000000000000Copyright (c) 2022-2023 Tweede Golf and Contributors Except as otherwise noted (below and/or in individual files), ntpd-rs is licensed under the Apache License, Version 2.0 or or the MIT license or , at your option. ntpd-1.1.2/Cargo.lock0000644000000645430000000000100077710ustar # This file is automatically @generated by Cargo. # It is not intended for manual editing. version = 3 [[package]] name = "addr2line" version = "0.21.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8a30b2e23b9e17a9f90641c7ab1549cd9b44f296d3ccbf309d2863cfe398a0cb" dependencies = [ "gimli", ] [[package]] name = "adler" version = "1.0.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f26201604c87b1e01bd3d98f8d5d9a8fcbb815e8cedb41ffccbeb4bf593a35fe" [[package]] name = "aead" version = "0.5.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d122413f284cf2d62fb1b7db97e02edb8cda96d769b16e443a4f6195e35662b0" dependencies = [ "crypto-common", "generic-array", ] [[package]] name = "aes" version = "0.8.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ac1f845298e95f983ff1944b728ae08b8cebab80d684f0a832ed0fc74dfa27e2" dependencies = [ "cfg-if", "cipher", "cpufeatures", ] [[package]] name = "aes-siv" version = "0.7.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7e08d0cdb774acd1e4dac11478b1a0c0d203134b2aab0ba25eb430de9b18f8b9" dependencies = [ "aead", "aes", "cipher", "cmac", "ctr", "dbl", "digest", "zeroize", ] [[package]] name = "async-trait" version = "0.1.77" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c980ee35e870bd1a4d2c8294d4c04d0499e67bca1e4b5cefcc693c2fa00caea9" dependencies = [ "proc-macro2", "quote", "syn", ] [[package]] name = "backtrace" version = "0.3.69" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "2089b7e3f35b9dd2d0ed921ead4f6d318c27680d4a5bd167b3ee120edb105837" dependencies = [ "addr2line", "cc", "cfg-if", "libc", "miniz_oxide", "object", "rustc-demangle", ] [[package]] name = "base64" version = "0.21.7" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9d297deb1925b89f2ccc13d7635fa0714f12c87adce1c75356b39ca9b7178567" [[package]] name = "bitflags" version = "1.3.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a" [[package]] name = "block-buffer" version = "0.10.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3078c7629b62d3f0439517fa394996acacc5cbc91c5a20d8c658e77abd503a71" dependencies = [ "generic-array", ] [[package]] name = "bytes" version = "1.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a2bd12c1caf447e69cd4528f47f94d203fd2582878ecb9e9465484c4148a8223" [[package]] name = "cc" version = "1.0.83" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f1174fb0b6ec23863f8b971027804a42614e347eafb0a95bf0b12cdae21fc4d0" dependencies = [ "libc", ] [[package]] name = "cfg-if" version = "1.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd" [[package]] name = "cipher" version = "0.4.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "773f3b9af64447d2ce9850330c473515014aa235e6a783b02db81ff39e4a3dad" dependencies = [ "crypto-common", "inout", ] [[package]] name = "cmac" version = "0.7.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8543454e3c3f5126effff9cd44d562af4e31fb8ce1cc0d3dcd8f084515dbc1aa" dependencies = [ "cipher", "dbl", "digest", ] [[package]] name = "core-foundation" version = "0.9.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "91e195e091a93c46f7102ec7818a2aa394e1e1771c3ab4825963fa03e45afb8f" dependencies = [ "core-foundation-sys", "libc", ] [[package]] name = "core-foundation-sys" version = "0.8.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "06ea2b9bc92be3c2baa9334a323ebca2d6f074ff852cd1d7b11064035cd3868f" [[package]] name = "cpufeatures" version = "0.2.12" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "53fe5e26ff1b7aef8bca9c6080520cfb8d9333c7568e1829cef191a9723e5504" dependencies = [ "libc", ] [[package]] name = "crypto-common" version = "0.1.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1bfb12502f3fc46cca1bb51ac28df9d618d813cdc3d2f25b9fe775a34af26bb3" dependencies = [ "generic-array", "rand_core", "typenum", ] [[package]] name = "ctr" version = "0.9.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0369ee1ad671834580515889b80f2ea915f23b8be8d0daa4bbaf2ac5c7590835" dependencies = [ "cipher", ] [[package]] name = "dbl" version = "0.3.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "bd2735a791158376708f9347fe8faba9667589d82427ef3aed6794a8981de3d9" dependencies = [ "generic-array", ] [[package]] name = "digest" version = "0.10.7" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9ed9a281f7bc9b7576e61468ba615a66a5c8cfdff42420a70aa82701a3b1e292" dependencies = [ "block-buffer", "crypto-common", "subtle", ] [[package]] name = "equivalent" version = "1.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "5443807d6dff69373d433ab9ef5378ad8df50ca6298caf15de6e52e24aaf54d5" [[package]] name = "generic-array" version = "0.14.7" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "85649ca51fd72272d7821adaf274ad91c288277713d9c18820d8499a7ff69e9a" dependencies = [ "typenum", "version_check", ] [[package]] name = "getrandom" version = "0.2.12" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "190092ea657667030ac6a35e305e62fc4dd69fd98ac98631e5d3a2b1575a12b5" dependencies = [ "cfg-if", "libc", "wasi", ] [[package]] name = "gimli" version = "0.28.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "4271d37baee1b8c7e4b708028c57d816cf9d2434acb33a549475f78c181f6253" [[package]] name = "hashbrown" version = "0.14.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "290f1a1d9242c78d09ce40a5e87e7554ee637af1351968159f4952f028f75604" [[package]] name = "hermit-abi" version = "0.3.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "5d3d0e0f38255e7fa3cf31335b3a56f05febd18025f4db5ef7a0cfb4f8da651f" [[package]] name = "indexmap" version = "2.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d530e1a18b1cb4c484e6e34556a0d948706958449fca0cab753d649f2bce3d1f" dependencies = [ "equivalent", "hashbrown", ] [[package]] name = "inout" version = "0.1.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a0c10553d664a4d0bcff9f4215d0aac67a639cc68ef660840afe309b807bc9f5" dependencies = [ "generic-array", ] [[package]] name = "itoa" version = "1.0.10" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b1a46d1a171d865aa5f83f92695765caa047a9b4cbae2cbf37dbd613a793fd4c" [[package]] name = "lazy_static" version = "1.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e2abad23fbc42b3700f2f279844dc832adb2b2eb069b2df918f455c4e18cc646" [[package]] name = "libc" version = "0.2.152" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "13e3bf6590cbc649f4d1a3eefc9d5d6eb746f5200ffb04e5e142700b8faa56e7" [[package]] name = "log" version = "0.4.20" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b5e6163cb8c49088c2c36f57875e58ccd8c87c7427f7fbd50ea6710b2f3f2e8f" [[package]] name = "md-5" version = "0.10.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d89e7ee0cfbedfc4da3340218492196241d89eefb6dab27de5df917a6d2e78cf" dependencies = [ "cfg-if", "digest", ] [[package]] name = "memchr" version = "2.7.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "523dc4f511e55ab87b694dc30d0f820d60906ef06413f93d4d7a1385599cc149" [[package]] name = "miniz_oxide" version = "0.7.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e7810e0be55b428ada41041c41f32c9f1a42817901b4ccf45fa3d4b6561e74c7" dependencies = [ "adler", ] [[package]] name = "mio" version = "0.8.10" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8f3d0b296e374a4e6f3c7b0a1f5a51d748a0d34c85e7dc48fc3fa9a87657fe09" dependencies = [ "libc", "wasi", "windows-sys 0.48.0", ] [[package]] name = "ntp-os-clock" version = "1.1.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c26db8f5c0571b5620d5bed8057490b7a24ec654e82ef8e082bf83e07bcae5d6" dependencies = [ "libc", "ntp-proto", "tracing", ] [[package]] name = "ntp-proto" version = "1.1.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9214eb29a1ddd45fc6653ff5fe623a54f20931af2ca4a8016c65b22aa20c5e56" dependencies = [ "aead", "aes-siv", "md-5", "rand", "rustls", "serde", "thiserror", "tracing", "zeroize", ] [[package]] name = "ntp-udp" version = "1.1.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "28ce3a405f86dfd4b21bbb95e246ae96607b9100925adc334951413b7b53a307" dependencies = [ "libc", "ntp-proto", "serde", "tokio", "tracing", ] [[package]] name = "ntpd" version = "1.1.2" dependencies = [ "async-trait", "libc", "ntp-os-clock", "ntp-proto", "ntp-udp", "rand", "rustls", "rustls-native-certs", "rustls-pemfile", "serde", "serde_json", "thiserror", "tokio", "tokio-rustls", "toml", "tracing", "tracing-subscriber", ] [[package]] name = "nu-ansi-term" version = "0.46.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "77a8165726e8236064dbb45459242600304b42a5ea24ee2948e18e023bf7ba84" dependencies = [ "overload", "winapi", ] [[package]] name = "num_cpus" version = "1.16.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "4161fcb6d602d4d2081af7c3a45852d875a03dd337a6bfdd6e06407b61342a43" dependencies = [ "hermit-abi", "libc", ] [[package]] name = "object" version = "0.32.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a6a622008b6e321afc04970976f62ee297fdbaa6f95318ca343e3eebb9648441" dependencies = [ "memchr", ] [[package]] name = "once_cell" version = "1.19.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3fdb12b2476b595f9358c5161aa467c2438859caa136dec86c26fdd2efe17b92" [[package]] name = "openssl-probe" version = "0.1.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ff011a302c396a5197692431fc1948019154afc178baf7d8e37367442a4601cf" [[package]] name = "overload" version = "0.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b15813163c1d831bf4a13c3610c05c0d03b39feb07f7e09fa234dac9b15aaf39" [[package]] name = "pin-project-lite" version = "0.2.13" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8afb450f006bf6385ca15ef45d71d2288452bc3683ce2e2cacc0d18e4be60b58" [[package]] name = "ppv-lite86" version = "0.2.17" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "5b40af805b3121feab8a3c29f04d8ad262fa8e0561883e7653e024ae4479e6de" [[package]] name = "proc-macro2" version = "1.0.76" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "95fc56cda0b5c3325f5fbbd7ff9fda9e02bb00bb3dac51252d2f1bfa1cb8cc8c" dependencies = [ "unicode-ident", ] [[package]] name = "quote" version = "1.0.35" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "291ec9ab5efd934aaf503a6466c5d5251535d108ee747472c3977cc5acc868ef" dependencies = [ "proc-macro2", ] [[package]] name = "rand" version = "0.8.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "34af8d1a0e25924bc5b7c43c079c942339d8f0a8b57c39049bef581b46327404" dependencies = [ "libc", "rand_chacha", "rand_core", ] [[package]] name = "rand_chacha" version = "0.3.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e6c10a63a0fa32252be49d21e7709d4d4baf8d231c2dbce1eaa8141b9b127d88" dependencies = [ "ppv-lite86", "rand_core", ] [[package]] name = "rand_core" version = "0.6.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ec0be4795e2f6a28069bec0b5ff3e2ac9bafc99e6a9a7dc3547996c5c816922c" dependencies = [ "getrandom", ] [[package]] name = "ring" version = "0.17.7" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "688c63d65483050968b2a8937f7995f443e27041a0f7700aa59b0822aedebb74" dependencies = [ "cc", "getrandom", "libc", "spin", "untrusted", "windows-sys 0.48.0", ] [[package]] name = "rustc-demangle" version = "0.1.23" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d626bb9dae77e28219937af045c257c28bfd3f69333c512553507f5f9798cb76" [[package]] name = "rustls" version = "0.21.10" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f9d5a6813c0759e4609cd494e8e725babae6a2ca7b62a5536a13daaec6fcb7ba" dependencies = [ "log", "ring", "rustls-webpki", "sct", ] [[package]] name = "rustls-native-certs" version = "0.6.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a9aace74cb666635c918e9c12bc0d348266037aa8eb599b5cba565709a8dff00" dependencies = [ "openssl-probe", "rustls-pemfile", "schannel", "security-framework", ] [[package]] name = "rustls-pemfile" version = "1.0.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1c74cae0a4cf6ccbbf5f359f08efdf8ee7e1dc532573bf0db71968cb56b1448c" dependencies = [ "base64", ] [[package]] name = "rustls-webpki" version = "0.101.7" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8b6275d1ee7a1cd780b64aca7726599a1dbc893b1e64144529e55c3c2f745765" dependencies = [ "ring", "untrusted", ] [[package]] name = "ryu" version = "1.0.16" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f98d2aa92eebf49b69786be48e4477826b256916e84a57ff2a4f21923b48eb4c" [[package]] name = "schannel" version = "0.1.23" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "fbc91545643bcf3a0bbb6569265615222618bdf33ce4ffbbd13c4bbd4c093534" dependencies = [ "windows-sys 0.52.0", ] [[package]] name = "sct" version = "0.7.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "da046153aa2352493d6cb7da4b6e5c0c057d8a1d0a9aa8560baffdd945acd414" dependencies = [ "ring", "untrusted", ] [[package]] name = "security-framework" version = "2.9.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "05b64fb303737d99b81884b2c63433e9ae28abebe5eb5045dcdd175dc2ecf4de" dependencies = [ "bitflags", "core-foundation", "core-foundation-sys", "libc", "security-framework-sys", ] [[package]] name = "security-framework-sys" version = "2.9.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e932934257d3b408ed8f30db49d85ea163bfe74961f017f405b025af298f0c7a" dependencies = [ "core-foundation-sys", "libc", ] [[package]] name = "serde" version = "1.0.195" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "63261df402c67811e9ac6def069e4786148c4563f4b50fd4bf30aa370d626b02" dependencies = [ "serde_derive", ] [[package]] name = "serde_derive" version = "1.0.195" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "46fe8f8603d81ba86327b23a2e9cdf49e1255fb94a4c5f297f6ee0547178ea2c" dependencies = [ "proc-macro2", "quote", "syn", ] [[package]] name = "serde_json" version = "1.0.111" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "176e46fa42316f18edd598015a5166857fc835ec732f5215eac6b7bdbf0a84f4" dependencies = [ "itoa", "ryu", "serde", ] [[package]] name = "serde_spanned" version = "0.6.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "eb3622f419d1296904700073ea6cc23ad690adbd66f13ea683df73298736f0c1" dependencies = [ "serde", ] [[package]] name = "sharded-slab" version = "0.1.7" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f40ca3c46823713e0d4209592e8d6e826aa57e928f09752619fc696c499637f6" dependencies = [ "lazy_static", ] [[package]] name = "socket2" version = "0.5.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7b5fac59a5cb5dd637972e5fca70daf0523c9067fcdc4842f053dae04a18f8e9" dependencies = [ "libc", "windows-sys 0.48.0", ] [[package]] name = "spin" version = "0.9.8" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "6980e8d7511241f8acf4aebddbb1ff938df5eebe98691418c4468d0b72a96a67" [[package]] name = "subtle" version = "2.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "81cdd64d312baedb58e21336b31bc043b77e01cc99033ce76ef539f78e965ebc" [[package]] name = "syn" version = "2.0.48" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0f3531638e407dfc0814761abb7c00a5b54992b849452a0646b7f65c9f770f3f" dependencies = [ "proc-macro2", "quote", "unicode-ident", ] [[package]] name = "thiserror" version = "1.0.56" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d54378c645627613241d077a3a79db965db602882668f9136ac42af9ecb730ad" dependencies = [ "thiserror-impl", ] [[package]] name = "thiserror-impl" version = "1.0.56" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "fa0faa943b50f3db30a20aa7e265dbc66076993efed8463e8de414e5d06d3471" dependencies = [ "proc-macro2", "quote", "syn", ] [[package]] name = "thread_local" version = "1.1.7" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3fdd6f064ccff2d6567adcb3873ca630700f00b5ad3f060c25b5dcfd9a4ce152" dependencies = [ "cfg-if", "once_cell", ] [[package]] name = "tokio" version = "1.35.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c89b4efa943be685f629b149f53829423f8f5531ea21249408e8e2f8671ec104" dependencies = [ "backtrace", "bytes", "libc", "mio", "num_cpus", "pin-project-lite", "socket2", "tokio-macros", "windows-sys 0.48.0", ] [[package]] name = "tokio-macros" version = "2.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "5b8a1e28f2deaa14e508979454cb3a223b10b938b45af148bc0986de36f1923b" dependencies = [ "proc-macro2", "quote", "syn", ] [[package]] name = "tokio-rustls" version = "0.24.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c28327cf380ac148141087fbfb9de9d7bd4e84ab5d2c28fbc911d753de8a7081" dependencies = [ "rustls", "tokio", ] [[package]] name = "toml" version = "0.8.8" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a1a195ec8c9da26928f773888e0742ca3ca1040c6cd859c919c9f59c1954ab35" dependencies = [ "serde", "serde_spanned", "toml_datetime", "toml_edit", ] [[package]] name = "toml_datetime" version = "0.6.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3550f4e9685620ac18a50ed434eb3aec30db8ba93b0287467bca5826ea25baf1" dependencies = [ "serde", ] [[package]] name = "toml_edit" version = "0.21.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d34d383cd00a163b4a5b85053df514d45bc330f6de7737edfe0a93311d1eaa03" dependencies = [ "indexmap", "serde", "serde_spanned", "toml_datetime", "winnow", ] [[package]] name = "tracing" version = "0.1.40" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c3523ab5a71916ccf420eebdf5521fcef02141234bbc0b8a49f2fdc4544364ef" dependencies = [ "pin-project-lite", "tracing-attributes", "tracing-core", ] [[package]] name = "tracing-attributes" version = "0.1.27" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "34704c8d6ebcbc939824180af020566b01a7c01f80641264eba0999f6c2b6be7" dependencies = [ "proc-macro2", "quote", "syn", ] [[package]] name = "tracing-core" version = "0.1.32" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c06d3da6113f116aaee68e4d601191614c9053067f9ab7f6edbcb161237daa54" dependencies = [ "once_cell", ] [[package]] name = "tracing-subscriber" version = "0.3.18" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ad0f048c97dbd9faa9b7df56362b8ebcaa52adb06b498c050d2f4e32f90a7a8b" dependencies = [ "nu-ansi-term", "sharded-slab", "thread_local", "tracing-core", ] [[package]] name = "typenum" version = "1.17.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "42ff0bf0c66b8238c6f3b578df37d0b7848e55df8577b3f74f92a69acceeb825" [[package]] name = "unicode-ident" version = "1.0.12" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3354b9ac3fae1ff6755cb6db53683adb661634f67557942dea4facebec0fee4b" [[package]] name = "untrusted" version = "0.9.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8ecb6da28b8a351d773b68d5825ac39017e680750f980f3a1a85cd8dd28a47c1" [[package]] name = "version_check" version = "0.9.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "49874b5167b65d7193b8aba1567f5c7d93d001cafc34600cee003eda787e483f" [[package]] name = "wasi" version = "0.11.0+wasi-snapshot-preview1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9c8d87e72b64a3b4db28d11ce29237c246188f4f51057d65a7eab63b7987e423" [[package]] name = "winapi" version = "0.3.9" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "5c839a674fcd7a98952e593242ea400abe93992746761e38641405d28b00f419" dependencies = [ "winapi-i686-pc-windows-gnu", "winapi-x86_64-pc-windows-gnu", ] [[package]] name = "winapi-i686-pc-windows-gnu" version = "0.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6" [[package]] name = "winapi-x86_64-pc-windows-gnu" version = "0.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f" [[package]] name = "windows-sys" version = "0.48.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "677d2418bec65e3338edb076e806bc1ec15693c5d0104683f2efe857f61056a9" dependencies = [ "windows-targets 0.48.5", ] [[package]] name = "windows-sys" version = "0.52.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "282be5f36a8ce781fad8c8ae18fa3f9beff57ec1b52cb3de0789201425d9a33d" dependencies = [ "windows-targets 0.52.0", ] [[package]] name = "windows-targets" version = "0.48.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9a2fa6e2155d7247be68c096456083145c183cbbbc2764150dda45a87197940c" dependencies = [ "windows_aarch64_gnullvm 0.48.5", "windows_aarch64_msvc 0.48.5", "windows_i686_gnu 0.48.5", "windows_i686_msvc 0.48.5", "windows_x86_64_gnu 0.48.5", "windows_x86_64_gnullvm 0.48.5", "windows_x86_64_msvc 0.48.5", ] [[package]] name = "windows-targets" version = "0.52.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8a18201040b24831fbb9e4eb208f8892e1f50a37feb53cc7ff887feb8f50e7cd" dependencies = [ "windows_aarch64_gnullvm 0.52.0", "windows_aarch64_msvc 0.52.0", "windows_i686_gnu 0.52.0", "windows_i686_msvc 0.52.0", "windows_x86_64_gnu 0.52.0", "windows_x86_64_gnullvm 0.52.0", "windows_x86_64_msvc 0.52.0", ] [[package]] name = "windows_aarch64_gnullvm" version = "0.48.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "2b38e32f0abccf9987a4e3079dfb67dcd799fb61361e53e2882c3cbaf0d905d8" [[package]] name = "windows_aarch64_gnullvm" version = "0.52.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "cb7764e35d4db8a7921e09562a0304bf2f93e0a51bfccee0bd0bb0b666b015ea" [[package]] name = "windows_aarch64_msvc" version = "0.48.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "dc35310971f3b2dbbf3f0690a219f40e2d9afcf64f9ab7cc1be722937c26b4bc" [[package]] name = "windows_aarch64_msvc" version = "0.52.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "bbaa0368d4f1d2aaefc55b6fcfee13f41544ddf36801e793edbbfd7d7df075ef" [[package]] name = "windows_i686_gnu" version = "0.48.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a75915e7def60c94dcef72200b9a8e58e5091744960da64ec734a6c6e9b3743e" [[package]] name = "windows_i686_gnu" version = "0.52.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a28637cb1fa3560a16915793afb20081aba2c92ee8af57b4d5f28e4b3e7df313" [[package]] name = "windows_i686_msvc" version = "0.48.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8f55c233f70c4b27f66c523580f78f1004e8b5a8b659e05a4eb49d4166cca406" [[package]] name = "windows_i686_msvc" version = "0.52.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ffe5e8e31046ce6230cc7215707b816e339ff4d4d67c65dffa206fd0f7aa7b9a" [[package]] name = "windows_x86_64_gnu" version = "0.48.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "53d40abd2583d23e4718fddf1ebec84dbff8381c07cae67ff7768bbf19c6718e" [[package]] name = "windows_x86_64_gnu" version = "0.52.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3d6fa32db2bc4a2f5abeacf2b69f7992cd09dca97498da74a151a3132c26befd" [[package]] name = "windows_x86_64_gnullvm" version = "0.48.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0b7b52767868a23d5bab768e390dc5f5c55825b6d30b86c844ff2dc7414044cc" [[package]] name = "windows_x86_64_gnullvm" version = "0.52.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1a657e1e9d3f514745a572a6846d3c7aa7dbe1658c056ed9c3344c4109a6949e" [[package]] name = "windows_x86_64_msvc" version = "0.48.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ed94fce61571a4006852b7389a063ab983c02eb1bb37b47f8272ce92d06d9538" [[package]] name = "windows_x86_64_msvc" version = "0.52.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "dff9641d1cd4be8d1a070daf9e3773c5f67e78b4d9d42263020c057706765c04" [[package]] name = "winnow" version = "0.5.34" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b7cf47b659b318dccbd69cc4797a39ae128f533dce7902a1096044d1967b9c16" dependencies = [ "memchr", ] [[package]] name = "zeroize" version = "1.7.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "525b4ec142c6b68a2d10f01f7bbf6755599ca3f81ea53b8431b7dd348f5fdb2d" ntpd-1.1.2/Cargo.toml0000644000000152270000000000100100070ustar # THIS FILE IS AUTOMATICALLY GENERATED BY CARGO # # When uploading crates to the registry Cargo will automatically # "normalize" Cargo.toml files for maximal compatibility # with all versions of Cargo and also rewrite `path` dependencies # to registry (e.g., crates.io) dependencies. # # If you are reading this file be aware that the original Cargo.toml # will likely look very different (and much more reasonable). # See Cargo.toml.orig for the original contents. [package] edition = "2021" rust-version = "1.67" name = "ntpd" version = "1.1.2" build = "build.rs" publish = true description = "Full-featured implementation of NTP with NTS support" homepage = "https://github.com/pendulum-project/ntpd-rs" readme = "README.md" license = "Apache-2.0 OR MIT" repository = "https://github.com/pendulum-project/ntpd-rs" [package.metadata.deb] assets = [ [ "target/release/ntp-daemon", "/usr/bin/ntp-daemon", "755", ], [ "target/release/ntp-ctl", "/usr/bin/ntp-ctl", "755", ], [ "target/release/ntp-metrics-exporter", "/usr/bin/ntp-metrics-exporter", "755", ], [ "docs/precompiled/man/ntp-ctl.8", "/usr/share/man/man8/ntp-ctl.8", "644", ], [ "docs/precompiled/man/ntp-daemon.8", "/usr/share/man/man8/ntp-daemon.8", "644", ], [ "docs/precompiled/man/ntp-metrics-exporter.8", "/usr/share/man/man8/ntp-metrics-exporter.8", "644", ], [ "docs/precompiled/man/ntp.toml.5", "/usr/share/man/man5/ntp.toml.5", "644", ], [ "docs/examples/conf/ntp.toml.default", "/usr/share/doc/ntpd-rs/ntp.toml.default", "644", ], [ "docs/examples/conf/ntp.toml.default", "/etc/ntpd-rs/ntp.toml", "644", ], [ "docs/examples/conf/ntpd-rs.preset", "/lib/systemd/system-preset/50-ntpd-rs.preset", "644", ], [ "docs/examples/conf/ntpd-rs.service", "/lib/systemd/system/ntpd-rs.service", "644", ], [ "docs/examples/conf/ntpd-rs-metrics.service", "/lib/systemd/system/ntpd-rs-metrics.service", "644", ], [ "../COPYING", "/usr/share/doc/ntpd-rs/COPYING", "644", ], [ "../LICENSE-APACHE", "/usr/share/doc/ntpd-rs/LICENSE-APACHE", "644", ], [ "../LICENSE-MIT", "/usr/share/doc/ntpd-rs/LICENSE-MIT", "644", ], [ "../CHANGELOG.md", "/usr/share/doc/ntpd-rs/CHANGELOG.md", "644", ], [ "../README.md", "/usr/share/doc/ntpd-rs/README.md", "644", ], ] conf-files = ["/etc/ntpd-rs/ntp.toml"] copyright = "Copyright (c) 2022-2023 Tweede Golf and Contributors" license-file = "../pkg/deb/COPYRIGHT-debian" maintainer = "NTPD-rs Maintainers " maintainer-scripts = "../pkg/deb/" name = "ntpd-rs" priority = "optional" section = "net" [package.metadata.generate-rpm] license = "MIT or ASL 2.0" name = "ntpd-rs" [[package.metadata.generate-rpm.assets]] dest = "/usr/bin/ntp-daemon" mode = "755" source = "target/release/ntp-daemon" [[package.metadata.generate-rpm.assets]] dest = "/usr/bin/ntp-ctl" mode = "755" source = "target/release/ntp-ctl" [[package.metadata.generate-rpm.assets]] dest = "/usr/bin/ntp-metrics-exporter" mode = "755" source = "target/release/ntp-metrics-exporter" [[package.metadata.generate-rpm.assets]] dest = "/usr/share/man/man8/ntp-ctl.8" doc = true mode = "644" source = "docs/precompiled/man/ntp-ctl.8" [[package.metadata.generate-rpm.assets]] dest = "/usr/share/man/man8/ntp-daemon.8" doc = true mode = "644" source = "docs/precompiled/man/ntp-daemon.8" [[package.metadata.generate-rpm.assets]] dest = "/usr/share/man/man8/ntp-metrics-exporter.8" doc = true mode = "644" source = "docs/precompiled/man/ntp-metrics-exporter.8" [[package.metadata.generate-rpm.assets]] dest = "/usr/share/man/man5/ntp-toml.5" doc = true mode = "644" source = "docs/precompiled/man/ntp.toml.5" [[package.metadata.generate-rpm.assets]] dest = "/usr/share/doc/ntpd-rs/ntp.toml.default" doc = true mode = "644" source = "docs/examples/conf/ntp.toml.default" [[package.metadata.generate-rpm.assets]] config = true dest = "/etc/ntpd-rs/ntp.toml" mode = "644" source = "docs/examples/conf/ntp.toml.default" [[package.metadata.generate-rpm.assets]] dest = "/lib/systemd/system/ntpd-rs.service" mode = "644" source = "docs/examples/conf/ntpd-rs.service" [[package.metadata.generate-rpm.assets]] dest = "/lib/systemd/system/ntpd-rs-metrics.service" mode = "644" source = "docs/examples/conf/ntpd-rs-metrics.service" [[package.metadata.generate-rpm.assets]] dest = "/lib/systemd/system-preset/50-ntpd-rs.preset" mode = "644" source = "docs/examples/conf/ntpd-rs.preset" [[package.metadata.generate-rpm.assets]] dest = "/usr/share/doc/ntpd-rs/COPYING" doc = true mode = "644" source = "../COPYING" [[package.metadata.generate-rpm.assets]] dest = "/usr/share/doc/ntpd-rs/LICENSE-APACHE" doc = true mode = "644" source = "../LICENSE-APACHE" [[package.metadata.generate-rpm.assets]] dest = "/usr/share/doc/ntpd-rs/LICENSE-MIT" doc = true mode = "644" source = "../LICENSE-MIT" [[package.metadata.generate-rpm.assets]] dest = "/usr/share/doc/ntpd-rs/CHANGELOG.md" doc = true mode = "644" source = "../CHANGELOG.md" [[package.metadata.generate-rpm.assets]] dest = "/usr/share/doc/ntpd-rs/README.md" doc = true mode = "644" source = "../README.md" [lib] name = "ntpd" path = "src/lib.rs" [[bin]] name = "ntp-daemon" path = "bin/ntp-daemon.rs" [[bin]] name = "ntp-ctl" path = "bin/ntp-ctl.rs" [[bin]] name = "ntp-metrics-exporter" path = "bin/ntp-metrics-exporter.rs" [dependencies.async-trait] version = "0.1.22" [dependencies.libc] version = "0.2.145" [dependencies.ntp-os-clock] version = "1.1.2" [dependencies.ntp-proto] version = "1.1.2" features = ["__internal-api"] [dependencies.ntp-udp] version = "1.1.2" [dependencies.rand] version = "0.8.0" [dependencies.rustls] version = "0.21.0" [dependencies.rustls-native-certs] version = "0.6.0" [dependencies.rustls-pemfile] version = "1.0" [dependencies.serde] version = "1.0.145" features = ["derive"] [dependencies.serde_json] version = "1.0" [dependencies.thiserror] version = "1.0.10" [dependencies.tokio] version = "1.32" features = [ "rt-multi-thread", "io-util", "io-std", "fs", "sync", "net", "macros", ] [dependencies.toml] version = ">=0.5.0,<0.9.0" [dependencies.tracing] version = "0.1.21" [dependencies.tracing-subscriber] version = "0.3.0" features = [ "std", "fmt", "ansi", ] default-features = false [dev-dependencies.ntp-proto] version = "1.1.2" features = [ "__internal-api", "__internal-test", ] [dev-dependencies.tokio-rustls] version = "0.24.1" [features] __internal-fuzz = [] default = [] hardware-timestamping = [] unstable_ntpv5 = ["ntp-proto/ntpv5"] unstable_nts-pool = ["ntp-proto/nts-pool"] ntpd-1.1.2/Cargo.toml.orig000064400000000000000000000117141046102023000134650ustar 00000000000000[package] name = "ntpd" readme = "README.md" description.workspace = true version.workspace = true edition.workspace = true license.workspace = true repository.workspace = true homepage.workspace = true publish.workspace = true rust-version.workspace = true build = "build.rs" [dependencies] ntp-proto.workspace = true ntp-os-clock.workspace = true ntp-udp.workspace = true tokio = { workspace = true, features = ["rt-multi-thread", "io-util", "io-std", "fs", "sync", "net", "macros"] } tracing.workspace = true tracing-subscriber.workspace = true toml.workspace = true thiserror.workspace = true rand.workspace = true libc.workspace = true async-trait.workspace = true serde.workspace = true serde_json.workspace = true rustls.workspace = true rustls-native-certs.workspace = true rustls-pemfile.workspace = true [dev-dependencies] ntp-proto = { workspace = true, features = ["__internal-test",] } tokio-rustls.workspace = true [features] default = [] hardware-timestamping = [] __internal-fuzz = [] unstable_ntpv5 = ["ntp-proto/ntpv5"] unstable_nts-pool = [ "ntp-proto/nts-pool" ] [lib] name = "ntpd" path = "src/lib.rs" [[bin]] name = "ntp-daemon" path = "bin/ntp-daemon.rs" [[bin]] name = "ntp-ctl" path = "bin/ntp-ctl.rs" [[bin]] name = "ntp-metrics-exporter" path = "bin/ntp-metrics-exporter.rs" [package.metadata.deb] name = "ntpd-rs" priority = "optional" section = "net" copyright = "Copyright (c) 2022-2023 Tweede Golf and Contributors" license-file = "../pkg/deb/COPYRIGHT-debian" maintainer = "NTPD-rs Maintainers " maintainer-scripts = "../pkg/deb/" assets = [ ["target/release/ntp-daemon", "/usr/bin/ntp-daemon", "755"], ["target/release/ntp-ctl", "/usr/bin/ntp-ctl", "755"], ["target/release/ntp-metrics-exporter", "/usr/bin/ntp-metrics-exporter", "755"], ["docs/precompiled/man/ntp-ctl.8", "/usr/share/man/man8/ntp-ctl.8", "644"], ["docs/precompiled/man/ntp-daemon.8", "/usr/share/man/man8/ntp-daemon.8", "644"], ["docs/precompiled/man/ntp-metrics-exporter.8", "/usr/share/man/man8/ntp-metrics-exporter.8", "644"], ["docs/precompiled/man/ntp.toml.5", "/usr/share/man/man5/ntp.toml.5", "644"], ["docs/examples/conf/ntp.toml.default", "/usr/share/doc/ntpd-rs/ntp.toml.default", "644"], ["docs/examples/conf/ntp.toml.default", "/etc/ntpd-rs/ntp.toml", "644"], ["docs/examples/conf/ntpd-rs.preset", "/lib/systemd/system-preset/50-ntpd-rs.preset", "644"], ["docs/examples/conf/ntpd-rs.service", "/lib/systemd/system/ntpd-rs.service", "644"], ["docs/examples/conf/ntpd-rs-metrics.service", "/lib/systemd/system/ntpd-rs-metrics.service", "644"], ["../COPYING", "/usr/share/doc/ntpd-rs/COPYING", "644"], ["../LICENSE-APACHE", "/usr/share/doc/ntpd-rs/LICENSE-APACHE", "644"], ["../LICENSE-MIT", "/usr/share/doc/ntpd-rs/LICENSE-MIT", "644"], ["../CHANGELOG.md", "/usr/share/doc/ntpd-rs/CHANGELOG.md", "644"], ["../README.md", "/usr/share/doc/ntpd-rs/README.md", "644"], ] conf-files = [ "/etc/ntpd-rs/ntp.toml", ] [package.metadata.generate-rpm] name = "ntpd-rs" # See: https://fedoraproject.org/wiki/Licensing:Main?rd=Licensing#Good_Licenses license = "MIT or ASL 2.0" assets = [ { source = "target/release/ntp-daemon", dest = "/usr/bin/ntp-daemon", mode = "755" }, { source = "target/release/ntp-ctl", dest = "/usr/bin/ntp-ctl", mode = "755" }, { source = "target/release/ntp-metrics-exporter", dest = "/usr/bin/ntp-metrics-exporter", mode = "755" }, { source = "docs/precompiled/man/ntp-ctl.8", dest = "/usr/share/man/man8/ntp-ctl.8", mode = "644", doc = true }, { source = "docs/precompiled/man/ntp-daemon.8", dest = "/usr/share/man/man8/ntp-daemon.8", mode = "644", doc = true }, { source = "docs/precompiled/man/ntp-metrics-exporter.8", dest = "/usr/share/man/man8/ntp-metrics-exporter.8", mode = "644", doc = true }, { source = "docs/precompiled/man/ntp.toml.5", dest = "/usr/share/man/man5/ntp-toml.5", mode = "644", doc = true }, { source = "docs/examples/conf/ntp.toml.default", dest = "/usr/share/doc/ntpd-rs/ntp.toml.default", mode = "644", doc = true }, { source = "docs/examples/conf/ntp.toml.default", dest = "/etc/ntpd-rs/ntp.toml", mode = "644", config = true }, { source = "docs/examples/conf/ntpd-rs.service", dest = "/lib/systemd/system/ntpd-rs.service", mode = "644" }, { source = "docs/examples/conf/ntpd-rs-metrics.service", dest = "/lib/systemd/system/ntpd-rs-metrics.service", mode = "644" }, { source = "docs/examples/conf/ntpd-rs.preset", dest = "/lib/systemd/system-preset/50-ntpd-rs.preset", mode = "644" }, { source = "../COPYING", dest = "/usr/share/doc/ntpd-rs/COPYING", mode = "644", doc = true }, { source = "../LICENSE-APACHE", dest = "/usr/share/doc/ntpd-rs/LICENSE-APACHE", mode = "644", doc = true }, { source = "../LICENSE-MIT", dest = "/usr/share/doc/ntpd-rs/LICENSE-MIT", mode = "644", doc = true }, { source = "../CHANGELOG.md", dest = "/usr/share/doc/ntpd-rs/CHANGELOG.md", mode = "644", doc = true }, { source = "../README.md", dest = "/usr/share/doc/ntpd-rs/README.md", mode = "644", doc = true }, ] ntpd-1.1.2/LICENSE-APACHE000064400000000000000000000227731046102023000125310ustar 00000000000000 Apache License Version 2.0, January 2004 http://www.apache.org/licenses/ TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION 1. Definitions. "License" shall mean the terms and conditions for use, reproduction, and distribution as defined by Sections 1 through 9 of this document. "Licensor" shall mean the copyright owner or entity authorized by the copyright owner that is granting the License. "Legal Entity" shall mean the union of the acting entity and all other entities that control, are controlled by, or are under common control with that entity. For the purposes of this definition, "control" means (i) the power, direct or indirect, to cause the direction or management of such entity, whether by contract or otherwise, or (ii) ownership of fifty percent (50%) or more of the outstanding shares, or (iii) beneficial ownership of such entity. "You" (or "Your") shall mean an individual or Legal Entity exercising permissions granted by this License. "Source" form shall mean the preferred form for making modifications, including but not limited to software source code, documentation source, and configuration files. "Object" form shall mean any form resulting from mechanical transformation or translation of a Source form, including but not limited to compiled object code, generated documentation, and conversions to other media types. "Work" shall mean the work of authorship, whether in Source or Object form, made available under the License, as indicated by a copyright notice that is included in or attached to the work (an example is provided in the Appendix below). "Derivative Works" shall mean any work, whether in Source or Object form, that is based on (or derived from) the Work and for which the editorial revisions, annotations, elaborations, or other modifications represent, as a whole, an original work of authorship. For the purposes of this License, Derivative Works shall not include works that remain separable from, or merely link (or bind by name) to the interfaces of, the Work and Derivative Works thereof. "Contribution" shall mean any work of authorship, including the original version of the Work and any modifications or additions to that Work or Derivative Works thereof, that is intentionally submitted to Licensor for inclusion in the Work by the copyright owner or by an individual or Legal Entity authorized to submit on behalf of the copyright owner. For the purposes of this definition, "submitted" means any form of electronic, verbal, or written communication sent to the Licensor or its representatives, including but not limited to communication on electronic mailing lists, source code control systems, and issue tracking systems that are managed by, or on behalf of, the Licensor for the purpose of discussing and improving the Work, but excluding communication that is conspicuously marked or otherwise designated in writing by the copyright owner as "Not a Contribution." "Contributor" shall mean Licensor and any individual or Legal Entity on behalf of whom a Contribution has been received by Licensor and subsequently incorporated within the Work. 2. Grant of Copyright License. Subject to the terms and conditions of this License, each Contributor hereby grants to You a perpetual, worldwide, non-exclusive, no-charge, royalty-free, irrevocable copyright license to reproduce, prepare Derivative Works of, publicly display, publicly perform, sublicense, and distribute the Work and such Derivative Works in Source or Object form. 3. Grant of Patent License. Subject to the terms and conditions of this License, each Contributor hereby grants to You a perpetual, worldwide, non-exclusive, no-charge, royalty-free, irrevocable (except as stated in this section) patent license to make, have made, use, offer to sell, sell, import, and otherwise transfer the Work, where such license applies only to those patent claims licensable by such Contributor that are necessarily infringed by their Contribution(s) alone or by combination of their Contribution(s) with the Work to which such Contribution(s) was submitted. If You institute patent litigation against any entity (including a cross-claim or counterclaim in a lawsuit) alleging that the Work or a Contribution incorporated within the Work constitutes direct or contributory patent infringement, then any patent licenses granted to You under this License for that Work shall terminate as of the date such litigation is filed. 4. Redistribution. You may reproduce and distribute copies of the Work or Derivative Works thereof in any medium, with or without modifications, and in Source or Object form, provided that You meet the following conditions: (a) You must give any other recipients of the Work or Derivative Works a copy of this License; and (b) You must cause any modified files to carry prominent notices stating that You changed the files; and (c) You must retain, in the Source form of any Derivative Works that You distribute, all copyright, patent, trademark, and attribution notices from the Source form of the Work, excluding those notices that do not pertain to any part of the Derivative Works; and (d) If the Work includes a "NOTICE" text file as part of its distribution, then any Derivative Works that You distribute must include a readable copy of the attribution notices contained within such NOTICE file, excluding those notices that do not pertain to any part of the Derivative Works, in at least one of the following places: within a NOTICE text file distributed as part of the Derivative Works; within the Source form or documentation, if provided along with the Derivative Works; or, within a display generated by the Derivative Works, if and wherever such third-party notices normally appear. The contents of the NOTICE file are for informational purposes only and do not modify the License. You may add Your own attribution notices within Derivative Works that You distribute, alongside or as an addendum to the NOTICE text from the Work, provided that such additional attribution notices cannot be construed as modifying the License. You may add Your own copyright statement to Your modifications and may provide additional or different license terms and conditions for use, reproduction, or distribution of Your modifications, or for any such Derivative Works as a whole, provided Your use, reproduction, and distribution of the Work otherwise complies with the conditions stated in this License. 5. Submission of Contributions. Unless You explicitly state otherwise, any Contribution intentionally submitted for inclusion in the Work by You to the Licensor shall be under the terms and conditions of this License, without any additional terms or conditions. Notwithstanding the above, nothing herein shall supersede or modify the terms of any separate license agreement you may have executed with Licensor regarding such Contributions. 6. Trademarks. This License does not grant permission to use the trade names, trademarks, service marks, or product names of the Licensor, except as required for reasonable and customary use in describing the origin of the Work and reproducing the content of the NOTICE file. 7. Disclaimer of Warranty. Unless required by applicable law or agreed to in writing, Licensor provides the Work (and each Contributor provides its Contributions) on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied, including, without limitation, any warranties or conditions of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A PARTICULAR PURPOSE. You are solely responsible for determining the appropriateness of using or redistributing the Work and assume any risks associated with Your exercise of permissions under this License. 8. Limitation of Liability. In no event and under no legal theory, whether in tort (including negligence), contract, or otherwise, unless required by applicable law (such as deliberate and grossly negligent acts) or agreed to in writing, shall any Contributor be liable to You for damages, including any direct, indirect, special, incidental, or consequential damages of any character arising as a result of this License or out of the use or inability to use the Work (including but not limited to damages for loss of goodwill, work stoppage, computer failure or malfunction, or any and all other commercial damages or losses), even if such Contributor has been advised of the possibility of such damages. 9. Accepting Warranty or Additional Liability. While redistributing the Work or Derivative Works thereof, You may choose to offer, and charge a fee for, acceptance of support, warranty, indemnity, or other liability obligations and/or rights consistent with this License. However, in accepting such obligations, You may act only on Your own behalf and on Your sole responsibility, not on behalf of any other Contributor, and only if You agree to indemnify, defend, and hold each Contributor harmless for any liability incurred by, or claims asserted against, such Contributor by reason of your accepting any such warranty or additional liability. END OF TERMS AND CONDITIONS ntpd-1.1.2/LICENSE-MIT000064400000000000000000000020651046102023000122310ustar 00000000000000Copyright (c) 2022-2023 Tweede Golf and Contributors Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. ntpd-1.1.2/README.md000064400000000000000000000115341046102023000120550ustar 00000000000000![checks](https://github.com/pendulum-project/ntpd-rs/actions/workflows/checks.yaml/badge.svg?branch=main) [![codecov](https://codecov.io/gh/pendulum-project/ntpd-rs/branch/main/graph/badge.svg?token=WES1JIYUJH)](https://codecov.io/gh/pendulum-project/ntpd-rs) [![Crates.io](https://img.shields.io/crates/v/ntpd.svg)](https://crates.io/crates/ntpd) [![Docs](https://img.shields.io/badge/ntpd--rs-blue?label=docs)](https://docs.ntpd-rs.pendulum-project.org/) [![OpenSSF Best Practices](https://www.bestpractices.dev/projects/8054/badge)](https://www.bestpractices.dev/projects/8054) [![OpenSSF Scorecard](https://api.securityscorecards.dev/projects/github.com/pendulum-project/ntpd-rs/badge)](https://securityscorecards.dev/viewer/?uri=github.com/pendulum-project/ntpd-rs) # ntpd-rs nptd-rs is a tool for synchronizing your computer's clock, implementing the NTP and NTS protocols. It is written in Rust, with a focus on security and stability. It includes both client and server support. If a feature you need is missing please let us know by opening an issue. ## Documentation Be sure to check out the [documentation website] as it includes guides on getting started, installation and migration, as well as a high-level overview of the code structure. ## Usage You can install the packages from the [releases page]. These packages configure ntpd-rs to synchronize your computers clock to servers from the [NTP pool]. After installation, check the status of the ntpd-rs daemon with ```console $ sudo systemctl status ntpd-rs ``` If ntpd-rs was not started automatically, you can do so now with ```console $ sudo systemctl start ntpd-rs ``` You should now be able to check the synchronization status with ```console $ ntp-ctl status Synchronization status: Dispersion: 0.000299s, Delay: 0.007637s Desired poll interval: 16s Stratum: 4 Sources: ntpd-rs.pool.ntp.org:123/77.171.247.180:123 (1): +0.000024±0.000137(±0.016886)s poll interval: 16s, missing polls: 0 root dispersion: 0.005905s, root delay:0.016190s ntpd-rs.pool.ntp.org:123/45.137.101.154:123 (2): +0.000022±0.000081(±0.007414)s poll interval: 16s, missing polls: 0 root dispersion: 0.004517s, root delay:0.005051s ntpd-rs.pool.ntp.org:123/178.215.228.24:123 (3): +0.000117±0.000091(±0.009162)s poll interval: 16s, missing polls: 0 root dispersion: 0.000549s, root delay:0.004318s ntpd-rs.pool.ntp.org:123/162.159.200.123:123 (4): +0.000111±0.000076(±0.004066)s poll interval: 16s, missing polls: 0 root dispersion: 0.000351s, root delay:0.003571s Servers: ``` The top part shows the overal quality of the time synchronization, and the time sources section shows which servers are used as well as offsets and uncertainties of those individual servers. For more details on how to install and use ntpd-rs, see our [documentation website]. ## Roadmap In Q1 2023 we completed our work on NTS. Our implementation is now full-featured, it supports NTP client and server with NTS. Our roadmap for 2023-2024: * Q3 2023: Stable release * Q4 2023: Experimental features, NTS pool, NTPv5 * Q4 2023 / Q1 2024: Packaging for Linux distributions * Q1-Q4 2024: Packaging and industry adoption, maintenance & community work We seek sponsorship for features and maintenance to continue our work. Contact us via pendulum@tweedegolf.com if you are interested! ## History ### 2022 The project originates from ISRG's project [Prossimo], as part of their mission to achieve memory safety for the Internet's most critical infrastructure. Prossimo Prossimo funded the initial development of the NTP client and server, and NTS support. The [NTP initiative page] on Prossimo's website tells the story. ### 2023 After completion of the initial development, the project's ownership moved from Prossimo to Tweede golf in April 2023. See the [NTP announcement] for more information. Tweede golf is the long-term maintainer of ntpd-rs, that is now part of Tweede golf's [Project Pendulum]. Pendulum is building modern, open-source implementations of the Network Time Protocol (ntpd-rs) and the Precision Time Protocol (Statime). In July of 2023 the [Sovereign Tech Fund] invested in Pendulum, securing ntpd-rs development and maintenance in 2023, and maintenance and adoption work in 2024. ![STF](https://tweedegolf.nl/images/logo-stf-blank.png) [releases page]: https://github.com/pendulum-project/ntpd-rs/releases [NTP pool]: https://www.ntppool.org [documentation website]: https://docs.ntpd-rs.pendulum-project.org/ [Prossimo]: https://www.memorysafety.org [NTP initiative page]: https://www.memorysafety.org/initiative/ntp [NTP announcement]: https://www.memorysafety.org/blog/ntp-and-nts-have-arrived/ [Project Pendulum]: https://github.com/pendulum-project [Sovereign Tech Fund]: https://sovereigntechfund.de/en/ ntpd-1.1.2/bin/ntp-ctl.rs000064400000000000000000000002021046102023000132630ustar 00000000000000#![forbid(unsafe_code)] #[tokio::main] async fn main() -> std::io::Result { ntpd::ctl_main().await } ntpd-1.1.2/bin/ntp-daemon.rs000064400000000000000000000002621046102023000137520ustar 00000000000000#![forbid(unsafe_code)] use std::process; #[tokio::main] async fn main() { let result = ntpd::daemon_main().await; process::exit(if result.is_ok() { 0 } else { 1 }); } ntpd-1.1.2/bin/ntp-metrics-exporter.rs000064400000000000000000000002161046102023000160220ustar 00000000000000#![forbid(unsafe_code)] #[tokio::main] async fn main() -> Result<(), Box> { ntpd::metrics_exporter_main().await } ntpd-1.1.2/build.rs000064400000000000000000000046761046102023000122540ustar 00000000000000use std::process::{Command, ExitStatus}; fn main() { // check if the repository is dirty (if there is any) let is_dirty = if let Ok(status) = Command::new("git") .args(["diff-index", "--quiet", "HEAD", "--"]) .status() { !status.success() } else { false }; // use environment variable for the git commit rev if set let git_rev = std::env::var("NTPD_RS_GIT_REV").ok(); // allow usage of the GITHUB_SHA environment variable during CI let git_rev = if let Some(gr) = git_rev { Some(gr) } else { std::env::var("GITHUB_SHA").ok() }; // determine the git commit (if there is any) let git_rev = if let Some(gr) = git_rev { Some(gr) } else { run_command_out("git", &["rev-parse", "HEAD"]) .ok() .map(|rev| { if is_dirty { format!("{}-dirty", rev) } else { rev } }) }; // use environment variable for the git commit date if set let git_date = std::env::var("NTPD_RS_GIT_DATE").ok(); // determine the date of the git commit (if there is any) let git_date = if let Some(gd) = git_date { Some(gd) } else if let Some(hash) = &git_rev { if is_dirty { run_command_out("date", &["-u", "+%Y-%m-%d"]).ok() } else { run_command_out( "git", &[ "show", "-s", "--date=format:%Y-%m-%d", "--format=%cd", hash, "--", ], ) .ok() } } else { None }; println!( "cargo:rustc-env=NTPD_RS_GIT_REV={}", git_rev.unwrap_or("-".to_owned()) ); println!( "cargo:rustc-env=NTPD_RS_GIT_DATE={}", git_date.unwrap_or("-".to_owned()) ); println!("cargo:rustc-rerun-if-changed=.git/HEAD"); } fn run_command(cmd: &str, args: &[&str]) -> std::io::Result<(String, ExitStatus)> { let res = Command::new(cmd).args(args).output()?; match String::from_utf8(res.stdout) { Ok(data) => Ok((data.trim().to_owned(), res.status)), Err(e) => Err(std::io::Error::new(std::io::ErrorKind::InvalidData, e)), } } fn run_command_out(cmd: &str, args: &[&str]) -> std::io::Result { run_command(cmd, args).map(|(out, _)| out) } ntpd-1.1.2/docs/algorithm/.gitignore000064400000000000000000000000541046102023000154770ustar 00000000000000*.aux *.fdb_latexmk *.fls *.log *.blg *.bbl ntpd-1.1.2/docs/algorithm/algorithm.aux000064400000000000000000000051511046102023000162170ustar 00000000000000\relax \citation{giada2015} \citation{rfc5905} \@writefile{toc}{\contentsline {section}{\numberline {1}Prerequisites and notation}{1}{}\protected@file@percent } \@writefile{toc}{\contentsline {section}{\numberline {2}Global architecture}{2}{}\protected@file@percent } \@writefile{lof}{\contentsline {figure}{\numberline {1}{\ignorespaces Diagram with the parts of the ntpd-rs clock control filter. The arrows on the left represent the measurements from the (in this case) 4 time sources coming in.}}{2}{}\protected@file@percent } \@writefile{toc}{\contentsline {section}{\numberline {3}Kalman filter}{3}{}\protected@file@percent } \newlabel{sec:Kalmanfilter}{{3}{3}} \@writefile{toc}{\contentsline {section}{\numberline {4}Process noise}{4}{}\protected@file@percent } \newlabel{sec:processnoise}{{4}{4}} \@writefile{toc}{\contentsline {subsection}{\numberline {4.1}Estimating process noise}{5}{}\protected@file@percent } \@writefile{toc}{\contentsline {subsubsection}{\numberline {4.1.1}Calculation details for $p$}{6}{}\protected@file@percent } \@writefile{toc}{\contentsline {section}{\numberline {5}Measurement Noise}{6}{}\protected@file@percent } \newlabel{sec:measnoise}{{5}{6}} \@writefile{lof}{\contentsline {figure}{\numberline {2}{\ignorespaces Schematic diagram of an NTP measurement.}}{6}{}\protected@file@percent } \newlabel{fig:measurement}{{2}{6}} \@writefile{toc}{\contentsline {section}{\numberline {6}Additional filtering and checks}{7}{}\protected@file@percent } \newlabel{sec:additionalchecks}{{6}{7}} \@writefile{toc}{\contentsline {section}{\numberline {7}Selection}{7}{}\protected@file@percent } \newlabel{sec:selection}{{7}{7}} \@writefile{toc}{\contentsline {section}{\numberline {8}Averaging}{8}{}\protected@file@percent } \newlabel{sec:averaging}{{8}{8}} \@writefile{toc}{\contentsline {section}{\numberline {9}Clock steering}{8}{}\protected@file@percent } \newlabel{sec:steering}{{9}{8}} \@writefile{toc}{\contentsline {section}{\numberline {10}Poll interval selection}{9}{}\protected@file@percent } \bibstyle{plain} \bibdata{algorithm} \bibcite{giada2015}{1} \@writefile{toc}{\contentsline {section}{\numberline {11}Performance}{10}{}\protected@file@percent } \@writefile{lof}{\contentsline {figure}{\numberline {3}{\ignorespaces Offset of the Raspberry Pi running ntpd-rs (left) and chrony (right) over a time period of 1 hour, compared to the server they were synchronizing to.}}{10}{}\protected@file@percent } \newlabel{fig:offset-time}{{3}{10}} \bibcite{rfc5905}{2} \@writefile{toc}{\contentsline {section}{\numberline {A}Random walk noise}{11}{}\protected@file@percent } \newlabel{sec:randomwalk}{{A}{11}} \gdef \@abspage@last{11} ntpd-1.1.2/docs/algorithm/algorithm.bbl000064400000000000000000000006211046102023000161560ustar 00000000000000\begin{thebibliography}{1} \bibitem{giada2015} Giada Giorgi. \newblock An event-based kalman filter for clock synchronization. \newblock {\em IEEE Transactions on Instrumentation and Measurement}, 64:449--457, 02 2015. \bibitem{rfc5905} David Mills, J~Burbank, and W~Kasch. \newblock Rfc 5905: Network time protocol version 4: Protocol and algorithms specification, 2010. \end{thebibliography} ntpd-1.1.2/docs/algorithm/algorithm.bib000064400000000000000000000007371046102023000161630ustar 00000000000000@article{giada2015, author = {Giorgi, Giada}, year = {2015}, month = {02}, pages = {449-457}, title = {An Event-Based Kalman Filter for Clock Synchronization}, volume = {64}, journal = {IEEE Transactions on Instrumentation and Measurement}, doi = {10.1109/TIM.2014.2340631} } @misc{rfc5905, title={RFC 5905: Network time protocol version 4: Protocol and algorithms specification}, author={Mills, David and Burbank, J and Kasch, W}, year={2010}, publisher={RFC Editor} } ntpd-1.1.2/docs/algorithm/algorithm.blg000064400000000000000000000015641046102023000161720ustar 00000000000000This is BibTeX, Version 0.99d (TeX Live 2022/dev/Debian) Capacity: max_strings=200000, hash_size=200000, hash_prime=170003 The top-level auxiliary file: algorithm.aux The style file: plain.bst Database file #1: algorithm.bib You've used 2 entries, 2118 wiz_defined-function locations, 509 strings with 4275 characters, and the built_in function-call counts, 570 in all, are: = -- 51 > -- 25 < -- 0 + -- 11 - -- 8 * -- 37 := -- 101 add.period$ -- 5 call.type$ -- 2 change.case$ -- 10 chr.to.int$ -- 0 cite$ -- 2 duplicate$ -- 18 empty$ -- 49 format.name$ -- 8 if$ -- 116 int.to.chr$ -- 0 int.to.str$ -- 2 missing$ -- 1 newline$ -- 12 num.names$ -- 4 pop$ -- 13 preamble$ -- 1 purify$ -- 8 quote$ -- 0 skip$ -- 15 stack$ -- 0 substring$ -- 32 swap$ -- 2 text.length$ -- 0 text.prefix$ -- 0 top$ -- 0 type$ -- 8 warning$ -- 0 while$ -- 5 width$ -- 3 write$ -- 21 ntpd-1.1.2/docs/algorithm/algorithm.fdb_latexmk000064400000000000000000000423311046102023000177030ustar 00000000000000# Fdb version 3 ["bibtex algorithm"] 1703071169 "algorithm.aux" "algorithm.bbl" "algorithm" 1703149511 "/usr/share/texlive/texmf-dist/bibtex/bst/base/plain.bst" 1292289607 20613 bd3fbfa9f64872b81ac57a0dd2ed855f "" "algorithm.aux" 1703149511 2665 fc13e8743194ac0fb0979b7a5253871d "pdflatex" "algorithm.bib" 1703058009 479 4929ab22735aad041896d268d2ab5e94 "" (generated) "algorithm.bbl" "algorithm.blg" ["pdflatex"] 1703149511 "algorithm.tex" "algorithm.pdf" "algorithm" 1703149511 "/etc/texmf/web2c/texmf.cnf" 1701849454 475 c0e671620eb5563b2130f56340a5fde8 "" "/usr/share/texlive/texmf-dist/fonts/map/fontname/texfonts.map" 1577235249 3524 cb3e574dea2d1052e39280babc910dc8 "" "/usr/share/texlive/texmf-dist/fonts/tfm/public/amsfonts/cmextra/cmex7.tfm" 1246382020 1004 54797486969f23fa377b128694d548df "" "/usr/share/texlive/texmf-dist/fonts/tfm/public/amsfonts/cmextra/cmex8.tfm" 1246382020 988 bdf658c3bfc2d96d3c8b02cfc1c94c20 "" "/usr/share/texlive/texmf-dist/fonts/tfm/public/amsfonts/symbols/msam10.tfm" 1246382020 916 f87d7c45f9c908e672703b83b72241a3 "" "/usr/share/texlive/texmf-dist/fonts/tfm/public/amsfonts/symbols/msam5.tfm" 1246382020 924 9904cf1d39e9767e7a3622f2a125a565 "" "/usr/share/texlive/texmf-dist/fonts/tfm/public/amsfonts/symbols/msam7.tfm" 1246382020 928 2dc8d444221b7a635bb58038579b861a "" "/usr/share/texlive/texmf-dist/fonts/tfm/public/amsfonts/symbols/msbm10.tfm" 1246382020 908 2921f8a10601f252058503cc6570e581 "" "/usr/share/texlive/texmf-dist/fonts/tfm/public/amsfonts/symbols/msbm5.tfm" 1246382020 940 75ac932a52f80982a9f8ea75d03a34cf "" "/usr/share/texlive/texmf-dist/fonts/tfm/public/amsfonts/symbols/msbm7.tfm" 1246382020 940 228d6584342e91276bf566bcf9716b83 "" "/usr/share/texlive/texmf-dist/fonts/tfm/public/cm/cmbx10.tfm" 1136768653 1328 c834bbb027764024c09d3d2bf908b5f0 "" "/usr/share/texlive/texmf-dist/fonts/tfm/public/cm/cmbx12.tfm" 1136768653 1324 c910af8c371558dc20f2d7822f66fe64 "" "/usr/share/texlive/texmf-dist/fonts/tfm/public/cm/cmex10.tfm" 1136768653 992 662f679a0b3d2d53c1b94050fdaa3f50 "" "/usr/share/texlive/texmf-dist/fonts/tfm/public/cm/cmmi12.tfm" 1136768653 1524 4414a8315f39513458b80dfc63bff03a "" "/usr/share/texlive/texmf-dist/fonts/tfm/public/cm/cmmi6.tfm" 1136768653 1512 f21f83efb36853c0b70002322c1ab3ad "" "/usr/share/texlive/texmf-dist/fonts/tfm/public/cm/cmmi8.tfm" 1136768653 1520 eccf95517727cb11801f4f1aee3a21b4 "" "/usr/share/texlive/texmf-dist/fonts/tfm/public/cm/cmr12.tfm" 1136768653 1288 655e228510b4c2a1abe905c368440826 "" "/usr/share/texlive/texmf-dist/fonts/tfm/public/cm/cmr17.tfm" 1136768653 1292 296a67155bdbfc32aa9c636f21e91433 "" "/usr/share/texlive/texmf-dist/fonts/tfm/public/cm/cmr6.tfm" 1136768653 1300 b62933e007d01cfd073f79b963c01526 "" "/usr/share/texlive/texmf-dist/fonts/tfm/public/cm/cmr8.tfm" 1136768653 1292 21c1c5bfeaebccffdb478fd231a0997d "" "/usr/share/texlive/texmf-dist/fonts/tfm/public/cm/cmsy10.tfm" 1136768653 1124 6c73e740cf17375f03eec0ee63599741 "" "/usr/share/texlive/texmf-dist/fonts/tfm/public/cm/cmsy6.tfm" 1136768653 1116 933a60c408fc0a863a92debe84b2d294 "" "/usr/share/texlive/texmf-dist/fonts/tfm/public/cm/cmsy8.tfm" 1136768653 1120 8b7d695260f3cff42e636090a8002094 "" "/usr/share/texlive/texmf-dist/fonts/tfm/public/cm/cmti10.tfm" 1136768653 1480 aa8e34af0eb6a2941b776984cf1dfdc4 "" "/usr/share/texlive/texmf-dist/fonts/type1/public/amsfonts/cm/cmbx10.pfb" 1248133631 34811 78b52f49e893bcba91bd7581cdc144c0 "" "/usr/share/texlive/texmf-dist/fonts/type1/public/amsfonts/cm/cmbx12.pfb" 1248133631 32080 340ef9bf63678554ee606688e7b5339d "" "/usr/share/texlive/texmf-dist/fonts/type1/public/amsfonts/cm/cmex10.pfb" 1248133631 30251 6afa5cb1d0204815a708a080681d4674 "" "/usr/share/texlive/texmf-dist/fonts/type1/public/amsfonts/cm/cmmi10.pfb" 1248133631 36299 5f9df58c2139e7edcf37c8fca4bd384d "" "/usr/share/texlive/texmf-dist/fonts/type1/public/amsfonts/cm/cmmi5.pfb" 1248133631 37912 77d683123f92148345f3fc36a38d9ab1 "" "/usr/share/texlive/texmf-dist/fonts/type1/public/amsfonts/cm/cmmi7.pfb" 1248133631 36281 c355509802a035cadc5f15869451dcee "" "/usr/share/texlive/texmf-dist/fonts/type1/public/amsfonts/cm/cmr10.pfb" 1248133631 35752 024fb6c41858982481f6968b5fc26508 "" "/usr/share/texlive/texmf-dist/fonts/type1/public/amsfonts/cm/cmr12.pfb" 1248133631 32722 d7379af29a190c3f453aba36302ff5a9 "" "/usr/share/texlive/texmf-dist/fonts/type1/public/amsfonts/cm/cmr17.pfb" 1248133631 32362 179c33bbf43f19adbb3825bb4e36e57a "" "/usr/share/texlive/texmf-dist/fonts/type1/public/amsfonts/cm/cmr5.pfb" 1248133631 31809 8670ca339bf94e56da1fc21c80635e2a "" "/usr/share/texlive/texmf-dist/fonts/type1/public/amsfonts/cm/cmr6.pfb" 1248133631 32734 69e00a6b65cedb993666e42eedb3d48f "" "/usr/share/texlive/texmf-dist/fonts/type1/public/amsfonts/cm/cmr7.pfb" 1248133631 32762 224316ccc9ad3ca0423a14971cfa7fc1 "" "/usr/share/texlive/texmf-dist/fonts/type1/public/amsfonts/cm/cmr8.pfb" 1248133631 32726 0a1aea6fcd6468ee2cf64d891f5c43c8 "" "/usr/share/texlive/texmf-dist/fonts/type1/public/amsfonts/cm/cmsy10.pfb" 1248133631 32569 5e5ddc8df908dea60932f3c484a54c0d "" "/usr/share/texlive/texmf-dist/fonts/type1/public/amsfonts/cm/cmsy5.pfb" 1248133631 32915 7bf7720c61a5b3a7ff25b0964421c9b6 "" "/usr/share/texlive/texmf-dist/fonts/type1/public/amsfonts/cm/cmsy7.pfb" 1248133631 32716 08e384dc442464e7285e891af9f45947 "" "/usr/share/texlive/texmf-dist/fonts/type1/public/amsfonts/cm/cmti10.pfb" 1248133631 37944 359e864bd06cde3b1cf57bb20757fb06 "" "/usr/share/texlive/texmf-dist/tex/context/base/mkii/supp-pdf.mkii" 1461363279 71627 94eb9990bed73c364d7f53f960cc8c5b "" "/usr/share/texlive/texmf-dist/tex/generic/pgf/basiclayer/pgfcore.code.tex" 1601326656 992 855ff26741653ab54814101ca36e153c "" "/usr/share/texlive/texmf-dist/tex/generic/pgf/basiclayer/pgfcorearrows.code.tex" 1601326656 43820 1fef971b75380574ab35a0d37fd92608 "" "/usr/share/texlive/texmf-dist/tex/generic/pgf/basiclayer/pgfcoreexternal.code.tex" 1601326656 19324 f4e4c6403dd0f1605fd20ed22fa79dea "" "/usr/share/texlive/texmf-dist/tex/generic/pgf/basiclayer/pgfcoregraphicstate.code.tex" 1601326656 6038 ccb406740cc3f03bbfb58ad504fe8c27 "" "/usr/share/texlive/texmf-dist/tex/generic/pgf/basiclayer/pgfcoreimage.code.tex" 1601326656 6944 e12f8f7a7364ddf66f93ba30fb3a3742 "" "/usr/share/texlive/texmf-dist/tex/generic/pgf/basiclayer/pgfcorelayers.code.tex" 1601326656 4883 42daaf41e27c3735286e23e48d2d7af9 "" "/usr/share/texlive/texmf-dist/tex/generic/pgf/basiclayer/pgfcoreobjects.code.tex" 1601326656 2544 8c06d2a7f0f469616ac9e13db6d2f842 "" "/usr/share/texlive/texmf-dist/tex/generic/pgf/basiclayer/pgfcorepathconstruct.code.tex" 1601326656 44195 5e390c414de027626ca5e2df888fa68d "" "/usr/share/texlive/texmf-dist/tex/generic/pgf/basiclayer/pgfcorepathprocessing.code.tex" 1601326656 17311 2ef6b2e29e2fc6a2fc8d6d652176e257 "" "/usr/share/texlive/texmf-dist/tex/generic/pgf/basiclayer/pgfcorepathusage.code.tex" 1601326656 21302 788a79944eb22192a4929e46963a3067 "" "/usr/share/texlive/texmf-dist/tex/generic/pgf/basiclayer/pgfcorepatterns.code.tex" 1601326656 9690 01feb7cde25d4293ef36eef45123eb80 "" "/usr/share/texlive/texmf-dist/tex/generic/pgf/basiclayer/pgfcorepoints.code.tex" 1601326656 33335 dd1fa4814d4e51f18be97d88bf0da60c "" "/usr/share/texlive/texmf-dist/tex/generic/pgf/basiclayer/pgfcorequick.code.tex" 1601326656 2965 4c2b1f4e0826925746439038172e5d6f "" "/usr/share/texlive/texmf-dist/tex/generic/pgf/basiclayer/pgfcorerdf.code.tex" 1601326656 5196 2cc249e0ee7e03da5f5f6589257b1e5b "" "/usr/share/texlive/texmf-dist/tex/generic/pgf/basiclayer/pgfcorescopes.code.tex" 1601326656 20726 d4c8db1e2e53b72721d29916314a22ea "" "/usr/share/texlive/texmf-dist/tex/generic/pgf/basiclayer/pgfcoreshade.code.tex" 1601326656 35249 abd4adf948f960299a4b3d27c5dddf46 "" "/usr/share/texlive/texmf-dist/tex/generic/pgf/basiclayer/pgfcoretransformations.code.tex" 1601326656 21989 fdc867d05d228316de137a9fc5ec3bbe "" "/usr/share/texlive/texmf-dist/tex/generic/pgf/basiclayer/pgfcoretransparency.code.tex" 1601326656 8893 e851de2175338fdf7c17f3e091d94618 "" "/usr/share/texlive/texmf-dist/tex/generic/pgf/frontendlayer/tikz/libraries/tikzlibrarytopaths.code.tex" 1608933718 11518 738408f795261b70ce8dd47459171309 "" "/usr/share/texlive/texmf-dist/tex/generic/pgf/frontendlayer/tikz/tikz.code.tex" 1621110968 186007 6e7dfe0bd57520fd5f91641aa72dcac8 "" "/usr/share/texlive/texmf-dist/tex/generic/pgf/libraries/pgflibraryplothandlers.code.tex" 1601326656 32995 ac577023e12c0e4bd8aa420b2e852d1a "" "/usr/share/texlive/texmf-dist/tex/generic/pgf/math/pgfint.code.tex" 1557692582 3063 8c415c68a0f3394e45cfeca0b65f6ee6 "" "/usr/share/texlive/texmf-dist/tex/generic/pgf/math/pgfmath.code.tex" 1601326656 521 8e224a7af69b7fee4451d1bf76b46654 "" "/usr/share/texlive/texmf-dist/tex/generic/pgf/math/pgfmathcalc.code.tex" 1601326656 13391 84d29568c13bdce4133ab4a214711112 "" "/usr/share/texlive/texmf-dist/tex/generic/pgf/math/pgfmathfloat.code.tex" 1601326656 104935 184ed87524e76d4957860df4ce0cd1c3 "" "/usr/share/texlive/texmf-dist/tex/generic/pgf/math/pgfmathfunctions.base.code.tex" 1601326656 10165 cec5fa73d49da442e56efc2d605ef154 "" "/usr/share/texlive/texmf-dist/tex/generic/pgf/math/pgfmathfunctions.basic.code.tex" 1601326656 28178 41c17713108e0795aac6fef3d275fbca "" "/usr/share/texlive/texmf-dist/tex/generic/pgf/math/pgfmathfunctions.code.tex" 1601326656 9989 c55967bf45126ff9b061fa2ca0c4694f "" "/usr/share/texlive/texmf-dist/tex/generic/pgf/math/pgfmathfunctions.comparison.code.tex" 1601326656 3865 ac538ab80c5cf82b345016e474786549 "" "/usr/share/texlive/texmf-dist/tex/generic/pgf/math/pgfmathfunctions.integerarithmetics.code.tex" 1557692582 3177 27d85c44fbfe09ff3b2cf2879e3ea434 "" "/usr/share/texlive/texmf-dist/tex/generic/pgf/math/pgfmathfunctions.misc.code.tex" 1621110968 11024 0179538121bc2dba172013a3ef89519f "" "/usr/share/texlive/texmf-dist/tex/generic/pgf/math/pgfmathfunctions.random.code.tex" 1608933718 7854 4176998eeefd8745ac6d2d4bd9c98451 "" "/usr/share/texlive/texmf-dist/tex/generic/pgf/math/pgfmathfunctions.round.code.tex" 1601326656 3379 781797a101f647bab82741a99944a229 "" "/usr/share/texlive/texmf-dist/tex/generic/pgf/math/pgfmathfunctions.trigonometric.code.tex" 1601326656 92405 f515f31275db273f97b9d8f52e1b0736 "" "/usr/share/texlive/texmf-dist/tex/generic/pgf/math/pgfmathparser.code.tex" 1601326656 37376 11cd75aac3da1c1b152b2848f30adc14 "" "/usr/share/texlive/texmf-dist/tex/generic/pgf/math/pgfmathutil.code.tex" 1601326656 8471 c2883569d03f69e8e1cabfef4999cfd7 "" "/usr/share/texlive/texmf-dist/tex/generic/pgf/modules/pgfmodulematrix.code.tex" 1601326656 21201 08d231a2386e2b61d64641c50dc15abd "" "/usr/share/texlive/texmf-dist/tex/generic/pgf/modules/pgfmoduleplot.code.tex" 1601326656 16121 346f9013d34804439f7436ff6786cef7 "" "/usr/share/texlive/texmf-dist/tex/generic/pgf/modules/pgfmoduleshapes.code.tex" 1621110968 44784 cedaa399d15f95e68e22906e2cc09ef8 "" "/usr/share/texlive/texmf-dist/tex/generic/pgf/pgf.revision.tex" 1621110968 465 d68603f8b820ea4a08cce534944db581 "" "/usr/share/texlive/texmf-dist/tex/generic/pgf/systemlayer/pgf.cfg" 1601326656 926 2963ea0dcf6cc6c0a770b69ec46a477b "" "/usr/share/texlive/texmf-dist/tex/generic/pgf/systemlayer/pgfsys-common-pdf.def" 1601326656 5546 f3f24d7898386cb7daac70bdd2c4d6dc "" "/usr/share/texlive/texmf-dist/tex/generic/pgf/systemlayer/pgfsys-pdftex.def" 1601326656 12601 4786e597516eddd82097506db7cfa098 "" "/usr/share/texlive/texmf-dist/tex/generic/pgf/systemlayer/pgfsys.code.tex" 1621110968 61163 9b2eefc24e021323e0fc140e9826d016 "" "/usr/share/texlive/texmf-dist/tex/generic/pgf/systemlayer/pgfsysprotocol.code.tex" 1601326656 1896 b8e0ca0ac371d74c0ca05583f6313c91 "" "/usr/share/texlive/texmf-dist/tex/generic/pgf/systemlayer/pgfsyssoftpath.code.tex" 1601326656 7778 53c8b5623d80238f6a20aa1df1868e63 "" "/usr/share/texlive/texmf-dist/tex/generic/pgf/utilities/pgffor.code.tex" 1606168878 23997 a4bed72405fa644418bea7eac2887006 "" "/usr/share/texlive/texmf-dist/tex/generic/pgf/utilities/pgfkeys.code.tex" 1621110968 37060 797782f0eb50075c9bc952374d9a659a "" "/usr/share/texlive/texmf-dist/tex/generic/pgf/utilities/pgfkeysfiltered.code.tex" 1601326656 37431 9abe862035de1b29c7a677f3205e3d9f "" "/usr/share/texlive/texmf-dist/tex/generic/pgf/utilities/pgfrcs.code.tex" 1601326656 4494 af17fb7efeafe423710479858e42fa7e "" "/usr/share/texlive/texmf-dist/tex/generic/pgf/utilities/pgfutil-common-lists.tex" 1601326656 7251 fb18c67117e09c64de82267e12cd8aa4 "" "/usr/share/texlive/texmf-dist/tex/generic/pgf/utilities/pgfutil-common.tex" 1621110968 29274 e15c5b7157d21523bd9c9f1dfa146b8e "" "/usr/share/texlive/texmf-dist/tex/generic/pgf/utilities/pgfutil-latex.def" 1621110968 6825 a2b0ea5b539dda0625e99dd15785ab59 "" "/usr/share/texlive/texmf-dist/tex/latex/amsfonts/amsfonts.sty" 1359763108 5949 3f3fd50a8cc94c3d4cbf4fc66cd3df1c "" "/usr/share/texlive/texmf-dist/tex/latex/amsfonts/amssymb.sty" 1359763108 13829 94730e64147574077f8ecfea9bb69af4 "" "/usr/share/texlive/texmf-dist/tex/latex/amsfonts/umsa.fd" 1359763108 961 6518c6525a34feb5e8250ffa91731cff "" "/usr/share/texlive/texmf-dist/tex/latex/amsfonts/umsb.fd" 1359763108 961 d02606146ba5601b5645f987c92e6193 "" "/usr/share/texlive/texmf-dist/tex/latex/amsmath/amsbsy.sty" 1622667781 2222 da905dc1db75412efd2d8f67739f0596 "" "/usr/share/texlive/texmf-dist/tex/latex/amsmath/amsgen.sty" 1622667781 4173 bc0410bcccdff806d6132d3c1ef35481 "" "/usr/share/texlive/texmf-dist/tex/latex/amsmath/amsmath.sty" 1636758526 87648 07fbb6e9169e00cb2a2f40b31b2dbf3c "" "/usr/share/texlive/texmf-dist/tex/latex/amsmath/amsopn.sty" 1636758526 4128 8eea906621b6639f7ba476a472036bbe "" "/usr/share/texlive/texmf-dist/tex/latex/amsmath/amstext.sty" 1636758526 2444 926f379cc60fcf0c6e3fee2223b4370d "" "/usr/share/texlive/texmf-dist/tex/latex/base/article.cls" 1636758526 20144 8a7de377ae7a11ee924a7499611f5a9d "" "/usr/share/texlive/texmf-dist/tex/latex/base/size10.clo" 1636758526 8448 96f18c76bf608a36ee6fbf021ac1dd32 "" "/usr/share/texlive/texmf-dist/tex/latex/epstopdf-pkg/epstopdf-base.sty" 1579991033 13886 d1306dcf79a944f6988e688c1785f9ce "" "/usr/share/texlive/texmf-dist/tex/latex/graphics-cfg/color.cfg" 1459978653 1213 620bba36b25224fa9b7e1ccb4ecb76fd "" "/usr/share/texlive/texmf-dist/tex/latex/graphics-cfg/graphics.cfg" 1465944070 1224 978390e9c2234eab29404bc21b268d1e "" "/usr/share/texlive/texmf-dist/tex/latex/graphics-def/pdftex.def" 1601931164 19103 48d29b6e2a64cb717117ef65f107b404 "" "/usr/share/texlive/texmf-dist/tex/latex/graphics/graphics.sty" 1622581934 18399 7e40f80366dffb22c0e7b70517db5cb4 "" "/usr/share/texlive/texmf-dist/tex/latex/graphics/graphicx.sty" 1636758526 7996 a8fb260d598dcaf305a7ae7b9c3e3229 "" "/usr/share/texlive/texmf-dist/tex/latex/graphics/keyval.sty" 1622581934 2671 4de6781a30211fe0ea4c672e4a2a8166 "" "/usr/share/texlive/texmf-dist/tex/latex/graphics/trig.sty" 1636758526 4009 187ea2dc3194cd5a76cd99a8d7a6c4d0 "" "/usr/share/texlive/texmf-dist/tex/latex/l3backend/l3backend-pdftex.def" 1642022539 29921 f0f4f870357ebfb8fe58ed9ed4ee9b92 "" "/usr/share/texlive/texmf-dist/tex/latex/latexconfig/epstopdf-sys.cfg" 1279039959 678 4792914a8f45be57bb98413425e4c7af "" "/usr/share/texlive/texmf-dist/tex/latex/pgf/basiclayer/pgf.sty" 1601326656 1090 bae35ef70b3168089ef166db3e66f5b2 "" "/usr/share/texlive/texmf-dist/tex/latex/pgf/basiclayer/pgfcore.sty" 1601326656 410 615550c46f918fcbee37641b02a862d9 "" "/usr/share/texlive/texmf-dist/tex/latex/pgf/compatibility/pgfcomp-version-0-65.sty" 1601326656 21013 f4ff83d25bb56552493b030f27c075ae "" "/usr/share/texlive/texmf-dist/tex/latex/pgf/compatibility/pgfcomp-version-1-18.sty" 1601326656 989 c49c8ae06d96f8b15869da7428047b1e "" "/usr/share/texlive/texmf-dist/tex/latex/pgf/frontendlayer/tikz.sty" 1601326656 339 c2e180022e3afdb99c7d0ea5ce469b7d "" "/usr/share/texlive/texmf-dist/tex/latex/pgf/math/pgfmath.sty" 1601326656 306 c56a323ca5bf9242f54474ced10fca71 "" "/usr/share/texlive/texmf-dist/tex/latex/pgf/systemlayer/pgfsys.sty" 1601326656 443 8c872229db56122037e86bcda49e14f3 "" "/usr/share/texlive/texmf-dist/tex/latex/pgf/utilities/pgffor.sty" 1601326656 348 ee405e64380c11319f0e249fed57e6c5 "" "/usr/share/texlive/texmf-dist/tex/latex/pgf/utilities/pgfkeys.sty" 1601326656 274 5ae372b7df79135d240456a1c6f2cf9a "" "/usr/share/texlive/texmf-dist/tex/latex/pgf/utilities/pgfrcs.sty" 1601326656 325 f9f16d12354225b7dd52a3321f085955 "" "/usr/share/texlive/texmf-dist/tex/latex/xcolor/xcolor.sty" 1635798903 56029 3f7889dab51d620aa43177c391b7b190 "" "/usr/share/texlive/texmf-dist/web2c/texmf.cnf" 1644012257 39432 7155514e09a3d69036fac785183a21c2 "" "/usr/share/texmf/web2c/texmf.cnf" 1644012257 39432 7155514e09a3d69036fac785183a21c2 "" "/var/lib/texmf/fonts/map/pdftex/updmap/pdftex.map" 1702549560 4379155 98693266ff65f58d9f98aff394de12d2 "" "/var/lib/texmf/web2c/pdftex/pdflatex.fmt" 1702549584 2800280 7da595064f191bb4353f50567c5e9499 "" "algorithm.aux" 1703149511 2665 fc13e8743194ac0fb0979b7a5253871d "pdflatex" "algorithm.bbl" 1703071169 401 27f2762b3e7dd909da2b98402eeaaffd "bibtex algorithm" "algorithm.tex" 1703149507 26057 147ff5a72be62fc43685f72e4843b641 "" "measurement.png" 1703058009 23204 142d04ef0738ee0aa68f592eb16d2d84 "" "offset-chrony.png" 1703058009 35554 9dfacf1f4a1a1848ab0c36f2e1a72895 "" "offset-ntpd-rs.png" 1703058009 18840 5da577aea6a145fbf4d023da44393319 "" (generated) "algorithm.aux" "algorithm.log" "algorithm.pdf" ntpd-1.1.2/docs/algorithm/algorithm.fls000064400000000000000000001027121046102023000162070ustar 00000000000000PWD /home/david/ntpd-rs/docs/algorithm INPUT /etc/texmf/web2c/texmf.cnf INPUT /usr/share/texmf/web2c/texmf.cnf INPUT /usr/share/texlive/texmf-dist/web2c/texmf.cnf INPUT /var/lib/texmf/web2c/pdftex/pdflatex.fmt INPUT algorithm.tex OUTPUT algorithm.log INPUT /usr/share/texlive/texmf-dist/tex/latex/base/article.cls INPUT /usr/share/texlive/texmf-dist/tex/latex/base/article.cls INPUT /usr/share/texlive/texmf-dist/tex/latex/base/article.cls INPUT /usr/share/texlive/texmf-dist/tex/latex/base/article.cls INPUT /usr/share/texlive/texmf-dist/tex/latex/base/article.cls INPUT /usr/share/texlive/texmf-dist/tex/latex/base/article.cls INPUT /usr/share/texlive/texmf-dist/tex/latex/base/article.cls INPUT /usr/share/texlive/texmf-dist/tex/latex/base/article.cls INPUT /usr/share/texlive/texmf-dist/tex/latex/base/article.cls INPUT /usr/share/texlive/texmf-dist/tex/latex/base/article.cls INPUT /usr/share/texlive/texmf-dist/tex/latex/base/article.cls INPUT /usr/share/texlive/texmf-dist/tex/latex/base/size10.clo INPUT /usr/share/texlive/texmf-dist/tex/latex/base/size10.clo INPUT /usr/share/texlive/texmf-dist/tex/latex/base/size10.clo INPUT /usr/share/texlive/texmf-dist/tex/latex/base/size10.clo INPUT /usr/share/texlive/texmf-dist/tex/latex/amsmath/amsmath.sty INPUT /usr/share/texlive/texmf-dist/tex/latex/amsmath/amsmath.sty INPUT /usr/share/texlive/texmf-dist/tex/latex/amsmath/amsmath.sty INPUT /usr/share/texlive/texmf-dist/tex/latex/amsmath/amsmath.sty INPUT /usr/share/texlive/texmf-dist/tex/latex/amsmath/amsmath.sty INPUT /usr/share/texlive/texmf-dist/tex/latex/amsmath/amsmath.sty INPUT /usr/share/texlive/texmf-dist/tex/latex/amsmath/amsmath.sty INPUT /usr/share/texlive/texmf-dist/tex/latex/amsmath/amsmath.sty INPUT /usr/share/texlive/texmf-dist/tex/latex/amsmath/amsmath.sty INPUT /usr/share/texlive/texmf-dist/tex/latex/amsmath/amsmath.sty INPUT /usr/share/texlive/texmf-dist/tex/latex/amsmath/amsmath.sty INPUT /usr/share/texlive/texmf-dist/tex/latex/amsmath/amsopn.sty INPUT /usr/share/texlive/texmf-dist/tex/latex/amsmath/amsopn.sty INPUT /usr/share/texlive/texmf-dist/tex/latex/amsmath/amstext.sty INPUT /usr/share/texlive/texmf-dist/tex/latex/amsmath/amstext.sty INPUT /usr/share/texlive/texmf-dist/tex/latex/amsmath/amstext.sty INPUT /usr/share/texlive/texmf-dist/tex/latex/amsmath/amstext.sty INPUT /usr/share/texlive/texmf-dist/tex/latex/amsmath/amstext.sty INPUT /usr/share/texlive/texmf-dist/tex/latex/amsmath/amstext.sty INPUT /usr/share/texlive/texmf-dist/tex/latex/amsmath/amstext.sty INPUT /usr/share/texlive/texmf-dist/tex/latex/amsmath/amstext.sty INPUT /usr/share/texlive/texmf-dist/tex/latex/amsmath/amstext.sty INPUT /usr/share/texlive/texmf-dist/tex/latex/amsmath/amstext.sty INPUT /usr/share/texlive/texmf-dist/tex/latex/amsmath/amstext.sty INPUT /usr/share/texlive/texmf-dist/tex/latex/amsmath/amsgen.sty INPUT /usr/share/texlive/texmf-dist/tex/latex/amsmath/amsgen.sty INPUT /usr/share/texlive/texmf-dist/tex/latex/amsmath/amsgen.sty INPUT /usr/share/texlive/texmf-dist/tex/latex/amsmath/amsgen.sty INPUT /usr/share/texlive/texmf-dist/tex/latex/amsmath/amsgen.sty INPUT /usr/share/texlive/texmf-dist/tex/latex/amsmath/amsgen.sty INPUT /usr/share/texlive/texmf-dist/tex/latex/amsmath/amsgen.sty INPUT /usr/share/texlive/texmf-dist/tex/latex/amsmath/amsgen.sty INPUT /usr/share/texlive/texmf-dist/tex/latex/amsmath/amsgen.sty INPUT /usr/share/texlive/texmf-dist/tex/latex/amsmath/amsgen.sty INPUT /usr/share/texlive/texmf-dist/tex/latex/amsmath/amsgen.sty INPUT /usr/share/texlive/texmf-dist/tex/latex/amsmath/amsbsy.sty INPUT /usr/share/texlive/texmf-dist/tex/latex/amsmath/amsbsy.sty INPUT /usr/share/texlive/texmf-dist/tex/latex/amsmath/amsbsy.sty INPUT /usr/share/texlive/texmf-dist/tex/latex/amsmath/amsbsy.sty INPUT /usr/share/texlive/texmf-dist/tex/latex/amsmath/amsbsy.sty INPUT /usr/share/texlive/texmf-dist/tex/latex/amsmath/amsbsy.sty INPUT /usr/share/texlive/texmf-dist/tex/latex/amsmath/amsbsy.sty INPUT /usr/share/texlive/texmf-dist/tex/latex/amsmath/amsbsy.sty INPUT /usr/share/texlive/texmf-dist/tex/latex/amsmath/amsbsy.sty INPUT /usr/share/texlive/texmf-dist/tex/latex/amsmath/amsbsy.sty INPUT /usr/share/texlive/texmf-dist/tex/latex/amsmath/amsbsy.sty INPUT /usr/share/texlive/texmf-dist/tex/latex/amsmath/amsgen.sty INPUT /usr/share/texlive/texmf-dist/tex/latex/amsmath/amsopn.sty INPUT /usr/share/texlive/texmf-dist/tex/latex/amsmath/amsopn.sty INPUT /usr/share/texlive/texmf-dist/tex/latex/amsmath/amsopn.sty INPUT /usr/share/texlive/texmf-dist/tex/latex/amsmath/amsopn.sty INPUT /usr/share/texlive/texmf-dist/tex/latex/amsmath/amsopn.sty INPUT /usr/share/texlive/texmf-dist/tex/latex/amsmath/amsopn.sty INPUT /usr/share/texlive/texmf-dist/tex/latex/amsmath/amsopn.sty INPUT /usr/share/texlive/texmf-dist/tex/latex/amsmath/amsopn.sty INPUT /usr/share/texlive/texmf-dist/tex/latex/amsmath/amsopn.sty INPUT /usr/share/texlive/texmf-dist/tex/latex/amsmath/amsopn.sty INPUT /usr/share/texlive/texmf-dist/tex/latex/amsmath/amsopn.sty INPUT /usr/share/texlive/texmf-dist/tex/latex/amsmath/amsgen.sty INPUT /usr/share/texlive/texmf-dist/tex/latex/amsfonts/amssymb.sty INPUT /usr/share/texlive/texmf-dist/tex/latex/amsfonts/amssymb.sty INPUT /usr/share/texlive/texmf-dist/tex/latex/amsfonts/amssymb.sty INPUT /usr/share/texlive/texmf-dist/tex/latex/amsfonts/amssymb.sty INPUT /usr/share/texlive/texmf-dist/tex/latex/amsfonts/amssymb.sty INPUT /usr/share/texlive/texmf-dist/tex/latex/amsfonts/amssymb.sty INPUT /usr/share/texlive/texmf-dist/tex/latex/amsfonts/amssymb.sty INPUT /usr/share/texlive/texmf-dist/tex/latex/amsfonts/amssymb.sty INPUT /usr/share/texlive/texmf-dist/tex/latex/amsfonts/amssymb.sty INPUT /usr/share/texlive/texmf-dist/tex/latex/amsfonts/amssymb.sty INPUT /usr/share/texlive/texmf-dist/tex/latex/amsfonts/amssymb.sty INPUT /usr/share/texlive/texmf-dist/tex/latex/amsfonts/amsfonts.sty INPUT /usr/share/texlive/texmf-dist/tex/latex/amsfonts/amsfonts.sty INPUT /usr/share/texlive/texmf-dist/tex/latex/amsfonts/amsfonts.sty INPUT /usr/share/texlive/texmf-dist/tex/latex/amsfonts/amsfonts.sty INPUT /usr/share/texlive/texmf-dist/tex/latex/amsfonts/amsfonts.sty INPUT /usr/share/texlive/texmf-dist/tex/latex/amsfonts/amsfonts.sty INPUT /usr/share/texlive/texmf-dist/tex/latex/amsfonts/amsfonts.sty INPUT /usr/share/texlive/texmf-dist/tex/latex/amsfonts/amsfonts.sty INPUT /usr/share/texlive/texmf-dist/tex/latex/amsfonts/amsfonts.sty INPUT /usr/share/texlive/texmf-dist/tex/latex/amsfonts/amsfonts.sty INPUT /usr/share/texlive/texmf-dist/tex/latex/amsfonts/amsfonts.sty INPUT /usr/share/texlive/texmf-dist/tex/latex/graphics/graphicx.sty INPUT /usr/share/texlive/texmf-dist/tex/latex/graphics/graphicx.sty INPUT /usr/share/texlive/texmf-dist/tex/latex/graphics/graphicx.sty INPUT /usr/share/texlive/texmf-dist/tex/latex/graphics/graphicx.sty INPUT /usr/share/texlive/texmf-dist/tex/latex/graphics/graphicx.sty INPUT /usr/share/texlive/texmf-dist/tex/latex/graphics/graphicx.sty INPUT /usr/share/texlive/texmf-dist/tex/latex/graphics/graphicx.sty INPUT /usr/share/texlive/texmf-dist/tex/latex/graphics/graphicx.sty INPUT /usr/share/texlive/texmf-dist/tex/latex/graphics/graphicx.sty INPUT /usr/share/texlive/texmf-dist/tex/latex/graphics/graphicx.sty INPUT /usr/share/texlive/texmf-dist/tex/latex/graphics/graphicx.sty INPUT /usr/share/texlive/texmf-dist/tex/latex/graphics/keyval.sty INPUT /usr/share/texlive/texmf-dist/tex/latex/graphics/keyval.sty INPUT /usr/share/texlive/texmf-dist/tex/latex/graphics/keyval.sty INPUT /usr/share/texlive/texmf-dist/tex/latex/graphics/keyval.sty INPUT /usr/share/texlive/texmf-dist/tex/latex/graphics/keyval.sty INPUT /usr/share/texlive/texmf-dist/tex/latex/graphics/keyval.sty INPUT /usr/share/texlive/texmf-dist/tex/latex/graphics/keyval.sty INPUT /usr/share/texlive/texmf-dist/tex/latex/graphics/keyval.sty INPUT /usr/share/texlive/texmf-dist/tex/latex/graphics/keyval.sty INPUT /usr/share/texlive/texmf-dist/tex/latex/graphics/keyval.sty INPUT /usr/share/texlive/texmf-dist/tex/latex/graphics/keyval.sty INPUT /usr/share/texlive/texmf-dist/tex/latex/graphics/graphics.sty INPUT /usr/share/texlive/texmf-dist/tex/latex/graphics/graphics.sty INPUT /usr/share/texlive/texmf-dist/tex/latex/graphics/graphics.sty INPUT /usr/share/texlive/texmf-dist/tex/latex/graphics/graphics.sty INPUT /usr/share/texlive/texmf-dist/tex/latex/graphics/graphics.sty INPUT /usr/share/texlive/texmf-dist/tex/latex/graphics/graphics.sty INPUT /usr/share/texlive/texmf-dist/tex/latex/graphics/graphics.sty INPUT /usr/share/texlive/texmf-dist/tex/latex/graphics/graphics.sty INPUT /usr/share/texlive/texmf-dist/tex/latex/graphics/graphics.sty INPUT /usr/share/texlive/texmf-dist/tex/latex/graphics/graphics.sty INPUT /usr/share/texlive/texmf-dist/tex/latex/graphics/graphics.sty INPUT /usr/share/texlive/texmf-dist/tex/latex/graphics/trig.sty INPUT /usr/share/texlive/texmf-dist/tex/latex/graphics/trig.sty INPUT /usr/share/texlive/texmf-dist/tex/latex/graphics/trig.sty INPUT /usr/share/texlive/texmf-dist/tex/latex/graphics/trig.sty INPUT /usr/share/texlive/texmf-dist/tex/latex/graphics/trig.sty INPUT /usr/share/texlive/texmf-dist/tex/latex/graphics/trig.sty INPUT /usr/share/texlive/texmf-dist/tex/latex/graphics/trig.sty INPUT /usr/share/texlive/texmf-dist/tex/latex/graphics/trig.sty INPUT /usr/share/texlive/texmf-dist/tex/latex/graphics/trig.sty INPUT /usr/share/texlive/texmf-dist/tex/latex/graphics/trig.sty INPUT /usr/share/texlive/texmf-dist/tex/latex/graphics/trig.sty INPUT /usr/share/texlive/texmf-dist/tex/latex/graphics-cfg/graphics.cfg INPUT /usr/share/texlive/texmf-dist/tex/latex/graphics-cfg/graphics.cfg INPUT /usr/share/texlive/texmf-dist/tex/latex/graphics-cfg/graphics.cfg INPUT /usr/share/texlive/texmf-dist/tex/latex/graphics-cfg/graphics.cfg INPUT /usr/share/texlive/texmf-dist/tex/latex/graphics-def/pdftex.def INPUT /usr/share/texlive/texmf-dist/tex/latex/graphics-def/pdftex.def INPUT /usr/share/texlive/texmf-dist/tex/latex/graphics-def/pdftex.def INPUT /usr/share/texlive/texmf-dist/tex/latex/graphics-def/pdftex.def INPUT /usr/share/texlive/texmf-dist/tex/latex/pgf/frontendlayer/tikz.sty INPUT /usr/share/texlive/texmf-dist/tex/latex/pgf/frontendlayer/tikz.sty INPUT /usr/share/texlive/texmf-dist/tex/latex/pgf/frontendlayer/tikz.sty INPUT /usr/share/texlive/texmf-dist/tex/latex/pgf/frontendlayer/tikz.sty INPUT /usr/share/texlive/texmf-dist/tex/latex/pgf/frontendlayer/tikz.sty INPUT /usr/share/texlive/texmf-dist/tex/latex/pgf/frontendlayer/tikz.sty INPUT /usr/share/texlive/texmf-dist/tex/latex/pgf/frontendlayer/tikz.sty INPUT /usr/share/texlive/texmf-dist/tex/latex/pgf/frontendlayer/tikz.sty INPUT /usr/share/texlive/texmf-dist/tex/latex/pgf/frontendlayer/tikz.sty INPUT /usr/share/texlive/texmf-dist/tex/latex/pgf/frontendlayer/tikz.sty INPUT /usr/share/texlive/texmf-dist/tex/latex/pgf/frontendlayer/tikz.sty INPUT /usr/share/texlive/texmf-dist/tex/latex/pgf/basiclayer/pgf.sty INPUT /usr/share/texlive/texmf-dist/tex/latex/pgf/basiclayer/pgf.sty INPUT /usr/share/texlive/texmf-dist/tex/latex/pgf/basiclayer/pgf.sty INPUT /usr/share/texlive/texmf-dist/tex/latex/pgf/basiclayer/pgf.sty INPUT /usr/share/texlive/texmf-dist/tex/latex/pgf/basiclayer/pgf.sty INPUT /usr/share/texlive/texmf-dist/tex/latex/pgf/basiclayer/pgf.sty INPUT /usr/share/texlive/texmf-dist/tex/latex/pgf/basiclayer/pgf.sty INPUT /usr/share/texlive/texmf-dist/tex/latex/pgf/basiclayer/pgf.sty INPUT /usr/share/texlive/texmf-dist/tex/latex/pgf/basiclayer/pgf.sty INPUT /usr/share/texlive/texmf-dist/tex/latex/pgf/basiclayer/pgf.sty INPUT /usr/share/texlive/texmf-dist/tex/latex/pgf/basiclayer/pgf.sty INPUT /usr/share/texlive/texmf-dist/tex/latex/pgf/utilities/pgfrcs.sty INPUT /usr/share/texlive/texmf-dist/tex/latex/pgf/utilities/pgfrcs.sty INPUT /usr/share/texlive/texmf-dist/tex/latex/pgf/utilities/pgfrcs.sty INPUT /usr/share/texlive/texmf-dist/tex/latex/pgf/utilities/pgfrcs.sty INPUT /usr/share/texlive/texmf-dist/tex/latex/pgf/utilities/pgfrcs.sty INPUT /usr/share/texlive/texmf-dist/tex/latex/pgf/utilities/pgfrcs.sty INPUT /usr/share/texlive/texmf-dist/tex/latex/pgf/utilities/pgfrcs.sty INPUT /usr/share/texlive/texmf-dist/tex/latex/pgf/utilities/pgfrcs.sty INPUT /usr/share/texlive/texmf-dist/tex/latex/pgf/utilities/pgfrcs.sty INPUT /usr/share/texlive/texmf-dist/tex/latex/pgf/utilities/pgfrcs.sty INPUT /usr/share/texlive/texmf-dist/tex/latex/pgf/utilities/pgfrcs.sty INPUT /usr/share/texlive/texmf-dist/tex/generic/pgf/utilities/pgfutil-common.tex INPUT /usr/share/texlive/texmf-dist/tex/generic/pgf/utilities/pgfutil-common-lists.tex INPUT /usr/share/texlive/texmf-dist/tex/generic/pgf/utilities/pgfutil-latex.def INPUT /usr/share/texlive/texmf-dist/tex/generic/pgf/utilities/pgfrcs.code.tex INPUT /usr/share/texlive/texmf-dist/tex/generic/pgf/utilities/pgfrcs.code.tex INPUT /usr/share/texlive/texmf-dist/tex/generic/pgf/utilities/pgfrcs.code.tex INPUT /usr/share/texlive/texmf-dist/tex/generic/pgf/utilities/pgfrcs.code.tex INPUT /usr/share/texlive/texmf-dist/tex/generic/pgf/pgf.revision.tex INPUT /usr/share/texlive/texmf-dist/tex/generic/pgf/pgf.revision.tex INPUT /usr/share/texlive/texmf-dist/tex/latex/pgf/basiclayer/pgfcore.sty INPUT /usr/share/texlive/texmf-dist/tex/latex/pgf/basiclayer/pgfcore.sty INPUT /usr/share/texlive/texmf-dist/tex/latex/pgf/basiclayer/pgfcore.sty INPUT /usr/share/texlive/texmf-dist/tex/latex/pgf/basiclayer/pgfcore.sty INPUT /usr/share/texlive/texmf-dist/tex/latex/pgf/basiclayer/pgfcore.sty INPUT /usr/share/texlive/texmf-dist/tex/latex/pgf/basiclayer/pgfcore.sty INPUT /usr/share/texlive/texmf-dist/tex/latex/pgf/basiclayer/pgfcore.sty INPUT /usr/share/texlive/texmf-dist/tex/latex/pgf/basiclayer/pgfcore.sty INPUT /usr/share/texlive/texmf-dist/tex/latex/pgf/basiclayer/pgfcore.sty INPUT /usr/share/texlive/texmf-dist/tex/latex/pgf/basiclayer/pgfcore.sty INPUT /usr/share/texlive/texmf-dist/tex/latex/pgf/basiclayer/pgfcore.sty INPUT /usr/share/texlive/texmf-dist/tex/latex/graphics/graphicx.sty INPUT /usr/share/texlive/texmf-dist/tex/latex/pgf/systemlayer/pgfsys.sty INPUT /usr/share/texlive/texmf-dist/tex/latex/pgf/systemlayer/pgfsys.sty INPUT /usr/share/texlive/texmf-dist/tex/latex/pgf/systemlayer/pgfsys.sty INPUT /usr/share/texlive/texmf-dist/tex/latex/pgf/systemlayer/pgfsys.sty INPUT /usr/share/texlive/texmf-dist/tex/latex/pgf/systemlayer/pgfsys.sty INPUT /usr/share/texlive/texmf-dist/tex/latex/pgf/systemlayer/pgfsys.sty INPUT /usr/share/texlive/texmf-dist/tex/latex/pgf/systemlayer/pgfsys.sty INPUT /usr/share/texlive/texmf-dist/tex/latex/pgf/systemlayer/pgfsys.sty INPUT /usr/share/texlive/texmf-dist/tex/latex/pgf/systemlayer/pgfsys.sty INPUT /usr/share/texlive/texmf-dist/tex/latex/pgf/systemlayer/pgfsys.sty INPUT /usr/share/texlive/texmf-dist/tex/latex/pgf/systemlayer/pgfsys.sty INPUT /usr/share/texlive/texmf-dist/tex/latex/pgf/utilities/pgfrcs.sty INPUT /usr/share/texlive/texmf-dist/tex/generic/pgf/systemlayer/pgfsys.code.tex INPUT /usr/share/texlive/texmf-dist/tex/generic/pgf/systemlayer/pgfsys.code.tex INPUT /usr/share/texlive/texmf-dist/tex/generic/pgf/systemlayer/pgfsys.code.tex INPUT /usr/share/texlive/texmf-dist/tex/generic/pgf/systemlayer/pgfsys.code.tex INPUT /usr/share/texlive/texmf-dist/tex/generic/pgf/utilities/pgfkeys.code.tex INPUT /usr/share/texlive/texmf-dist/tex/generic/pgf/utilities/pgfkeysfiltered.code.tex INPUT /usr/share/texlive/texmf-dist/tex/generic/pgf/systemlayer/pgf.cfg INPUT /usr/share/texlive/texmf-dist/tex/generic/pgf/systemlayer/pgfsys-pdftex.def INPUT /usr/share/texlive/texmf-dist/tex/generic/pgf/systemlayer/pgfsys-pdftex.def INPUT /usr/share/texlive/texmf-dist/tex/generic/pgf/systemlayer/pgfsys-common-pdf.def INPUT /usr/share/texlive/texmf-dist/tex/generic/pgf/systemlayer/pgfsyssoftpath.code.tex INPUT /usr/share/texlive/texmf-dist/tex/generic/pgf/systemlayer/pgfsyssoftpath.code.tex INPUT /usr/share/texlive/texmf-dist/tex/generic/pgf/systemlayer/pgfsyssoftpath.code.tex INPUT /usr/share/texlive/texmf-dist/tex/generic/pgf/systemlayer/pgfsyssoftpath.code.tex INPUT /usr/share/texlive/texmf-dist/tex/generic/pgf/systemlayer/pgfsysprotocol.code.tex INPUT /usr/share/texlive/texmf-dist/tex/generic/pgf/systemlayer/pgfsysprotocol.code.tex INPUT /usr/share/texlive/texmf-dist/tex/generic/pgf/systemlayer/pgfsysprotocol.code.tex INPUT /usr/share/texlive/texmf-dist/tex/generic/pgf/systemlayer/pgfsysprotocol.code.tex INPUT /usr/share/texlive/texmf-dist/tex/latex/graphics/keyval.sty INPUT /usr/share/texlive/texmf-dist/tex/latex/xcolor/xcolor.sty INPUT /usr/share/texlive/texmf-dist/tex/latex/xcolor/xcolor.sty INPUT /usr/share/texlive/texmf-dist/tex/latex/xcolor/xcolor.sty INPUT /usr/share/texlive/texmf-dist/tex/latex/xcolor/xcolor.sty INPUT /usr/share/texlive/texmf-dist/tex/latex/xcolor/xcolor.sty INPUT /usr/share/texlive/texmf-dist/tex/latex/xcolor/xcolor.sty INPUT /usr/share/texlive/texmf-dist/tex/latex/xcolor/xcolor.sty INPUT /usr/share/texlive/texmf-dist/tex/latex/xcolor/xcolor.sty INPUT /usr/share/texlive/texmf-dist/tex/latex/xcolor/xcolor.sty INPUT /usr/share/texlive/texmf-dist/tex/latex/xcolor/xcolor.sty INPUT /usr/share/texlive/texmf-dist/tex/latex/xcolor/xcolor.sty INPUT /usr/share/texlive/texmf-dist/tex/latex/graphics-cfg/color.cfg INPUT /usr/share/texlive/texmf-dist/tex/latex/graphics-cfg/color.cfg INPUT /usr/share/texlive/texmf-dist/tex/latex/graphics-cfg/color.cfg INPUT /usr/share/texlive/texmf-dist/tex/latex/graphics-cfg/color.cfg INPUT /usr/share/texlive/texmf-dist/tex/generic/pgf/basiclayer/pgfcore.code.tex INPUT /usr/share/texlive/texmf-dist/tex/generic/pgf/basiclayer/pgfcore.code.tex INPUT /usr/share/texlive/texmf-dist/tex/generic/pgf/basiclayer/pgfcore.code.tex INPUT /usr/share/texlive/texmf-dist/tex/generic/pgf/basiclayer/pgfcore.code.tex INPUT /usr/share/texlive/texmf-dist/tex/generic/pgf/math/pgfmath.code.tex INPUT /usr/share/texlive/texmf-dist/tex/generic/pgf/math/pgfmathcalc.code.tex INPUT /usr/share/texlive/texmf-dist/tex/generic/pgf/math/pgfmathutil.code.tex INPUT /usr/share/texlive/texmf-dist/tex/generic/pgf/math/pgfmathparser.code.tex INPUT /usr/share/texlive/texmf-dist/tex/generic/pgf/math/pgfmathfunctions.code.tex INPUT /usr/share/texlive/texmf-dist/tex/generic/pgf/math/pgfmathfunctions.basic.code.tex INPUT /usr/share/texlive/texmf-dist/tex/generic/pgf/math/pgfmathfunctions.trigonometric.code.tex INPUT /usr/share/texlive/texmf-dist/tex/generic/pgf/math/pgfmathfunctions.random.code.tex INPUT /usr/share/texlive/texmf-dist/tex/generic/pgf/math/pgfmathfunctions.comparison.code.tex INPUT /usr/share/texlive/texmf-dist/tex/generic/pgf/math/pgfmathfunctions.base.code.tex INPUT /usr/share/texlive/texmf-dist/tex/generic/pgf/math/pgfmathfunctions.round.code.tex INPUT /usr/share/texlive/texmf-dist/tex/generic/pgf/math/pgfmathfunctions.misc.code.tex INPUT /usr/share/texlive/texmf-dist/tex/generic/pgf/math/pgfmathfunctions.integerarithmetics.code.tex INPUT /usr/share/texlive/texmf-dist/tex/generic/pgf/math/pgfmathfloat.code.tex INPUT /usr/share/texlive/texmf-dist/tex/generic/pgf/math/pgfint.code.tex INPUT /usr/share/texlive/texmf-dist/tex/generic/pgf/basiclayer/pgfcorepoints.code.tex INPUT /usr/share/texlive/texmf-dist/tex/generic/pgf/basiclayer/pgfcorepathconstruct.code.tex INPUT /usr/share/texlive/texmf-dist/tex/generic/pgf/basiclayer/pgfcorepathusage.code.tex INPUT /usr/share/texlive/texmf-dist/tex/generic/pgf/basiclayer/pgfcorescopes.code.tex INPUT /usr/share/texlive/texmf-dist/tex/generic/pgf/basiclayer/pgfcoregraphicstate.code.tex INPUT /usr/share/texlive/texmf-dist/tex/generic/pgf/basiclayer/pgfcoretransformations.code.tex INPUT /usr/share/texlive/texmf-dist/tex/generic/pgf/basiclayer/pgfcorequick.code.tex INPUT /usr/share/texlive/texmf-dist/tex/generic/pgf/basiclayer/pgfcoreobjects.code.tex INPUT /usr/share/texlive/texmf-dist/tex/generic/pgf/basiclayer/pgfcorepathprocessing.code.tex INPUT /usr/share/texlive/texmf-dist/tex/generic/pgf/basiclayer/pgfcorearrows.code.tex INPUT /usr/share/texlive/texmf-dist/tex/generic/pgf/basiclayer/pgfcoreshade.code.tex INPUT /usr/share/texlive/texmf-dist/tex/generic/pgf/basiclayer/pgfcoreimage.code.tex INPUT /usr/share/texlive/texmf-dist/tex/generic/pgf/basiclayer/pgfcoreexternal.code.tex INPUT /usr/share/texlive/texmf-dist/tex/generic/pgf/basiclayer/pgfcorelayers.code.tex INPUT /usr/share/texlive/texmf-dist/tex/generic/pgf/basiclayer/pgfcoretransparency.code.tex INPUT /usr/share/texlive/texmf-dist/tex/generic/pgf/basiclayer/pgfcorepatterns.code.tex INPUT /usr/share/texlive/texmf-dist/tex/generic/pgf/basiclayer/pgfcorerdf.code.tex INPUT /usr/share/texlive/texmf-dist/tex/generic/pgf/modules/pgfmoduleshapes.code.tex INPUT /usr/share/texlive/texmf-dist/tex/generic/pgf/modules/pgfmoduleplot.code.tex INPUT /usr/share/texlive/texmf-dist/tex/latex/pgf/compatibility/pgfcomp-version-0-65.sty INPUT /usr/share/texlive/texmf-dist/tex/latex/pgf/compatibility/pgfcomp-version-0-65.sty INPUT /usr/share/texlive/texmf-dist/tex/latex/pgf/compatibility/pgfcomp-version-0-65.sty INPUT /usr/share/texlive/texmf-dist/tex/latex/pgf/compatibility/pgfcomp-version-0-65.sty INPUT /usr/share/texlive/texmf-dist/tex/latex/pgf/compatibility/pgfcomp-version-0-65.sty INPUT /usr/share/texlive/texmf-dist/tex/latex/pgf/compatibility/pgfcomp-version-0-65.sty INPUT /usr/share/texlive/texmf-dist/tex/latex/pgf/compatibility/pgfcomp-version-0-65.sty INPUT /usr/share/texlive/texmf-dist/tex/latex/pgf/compatibility/pgfcomp-version-0-65.sty INPUT /usr/share/texlive/texmf-dist/tex/latex/pgf/compatibility/pgfcomp-version-0-65.sty INPUT /usr/share/texlive/texmf-dist/tex/latex/pgf/compatibility/pgfcomp-version-0-65.sty INPUT /usr/share/texlive/texmf-dist/tex/latex/pgf/compatibility/pgfcomp-version-0-65.sty INPUT /usr/share/texlive/texmf-dist/tex/latex/pgf/utilities/pgfrcs.sty INPUT /usr/share/texlive/texmf-dist/tex/latex/pgf/compatibility/pgfcomp-version-1-18.sty INPUT /usr/share/texlive/texmf-dist/tex/latex/pgf/compatibility/pgfcomp-version-1-18.sty INPUT /usr/share/texlive/texmf-dist/tex/latex/pgf/compatibility/pgfcomp-version-1-18.sty INPUT /usr/share/texlive/texmf-dist/tex/latex/pgf/compatibility/pgfcomp-version-1-18.sty INPUT /usr/share/texlive/texmf-dist/tex/latex/pgf/compatibility/pgfcomp-version-1-18.sty INPUT /usr/share/texlive/texmf-dist/tex/latex/pgf/compatibility/pgfcomp-version-1-18.sty INPUT /usr/share/texlive/texmf-dist/tex/latex/pgf/compatibility/pgfcomp-version-1-18.sty INPUT /usr/share/texlive/texmf-dist/tex/latex/pgf/compatibility/pgfcomp-version-1-18.sty INPUT /usr/share/texlive/texmf-dist/tex/latex/pgf/compatibility/pgfcomp-version-1-18.sty INPUT /usr/share/texlive/texmf-dist/tex/latex/pgf/compatibility/pgfcomp-version-1-18.sty INPUT /usr/share/texlive/texmf-dist/tex/latex/pgf/compatibility/pgfcomp-version-1-18.sty INPUT /usr/share/texlive/texmf-dist/tex/latex/pgf/utilities/pgfrcs.sty INPUT /usr/share/texlive/texmf-dist/tex/latex/pgf/utilities/pgffor.sty INPUT /usr/share/texlive/texmf-dist/tex/latex/pgf/utilities/pgffor.sty INPUT /usr/share/texlive/texmf-dist/tex/latex/pgf/utilities/pgffor.sty INPUT /usr/share/texlive/texmf-dist/tex/latex/pgf/utilities/pgffor.sty INPUT /usr/share/texlive/texmf-dist/tex/latex/pgf/utilities/pgffor.sty INPUT /usr/share/texlive/texmf-dist/tex/latex/pgf/utilities/pgffor.sty INPUT /usr/share/texlive/texmf-dist/tex/latex/pgf/utilities/pgffor.sty INPUT /usr/share/texlive/texmf-dist/tex/latex/pgf/utilities/pgffor.sty INPUT /usr/share/texlive/texmf-dist/tex/latex/pgf/utilities/pgffor.sty INPUT /usr/share/texlive/texmf-dist/tex/latex/pgf/utilities/pgffor.sty INPUT /usr/share/texlive/texmf-dist/tex/latex/pgf/utilities/pgffor.sty INPUT /usr/share/texlive/texmf-dist/tex/latex/pgf/utilities/pgfrcs.sty INPUT /usr/share/texlive/texmf-dist/tex/latex/pgf/utilities/pgfkeys.sty INPUT /usr/share/texlive/texmf-dist/tex/latex/pgf/utilities/pgfkeys.sty INPUT /usr/share/texlive/texmf-dist/tex/latex/pgf/utilities/pgfkeys.sty INPUT /usr/share/texlive/texmf-dist/tex/latex/pgf/utilities/pgfkeys.sty INPUT /usr/share/texlive/texmf-dist/tex/latex/pgf/utilities/pgfkeys.sty INPUT /usr/share/texlive/texmf-dist/tex/latex/pgf/utilities/pgfkeys.sty INPUT /usr/share/texlive/texmf-dist/tex/latex/pgf/utilities/pgfkeys.sty INPUT /usr/share/texlive/texmf-dist/tex/latex/pgf/utilities/pgfkeys.sty INPUT /usr/share/texlive/texmf-dist/tex/latex/pgf/utilities/pgfkeys.sty INPUT /usr/share/texlive/texmf-dist/tex/latex/pgf/utilities/pgfkeys.sty INPUT /usr/share/texlive/texmf-dist/tex/latex/pgf/utilities/pgfkeys.sty INPUT /usr/share/texlive/texmf-dist/tex/generic/pgf/utilities/pgfkeys.code.tex INPUT /usr/share/texlive/texmf-dist/tex/generic/pgf/utilities/pgfkeys.code.tex INPUT /usr/share/texlive/texmf-dist/tex/generic/pgf/utilities/pgfkeys.code.tex INPUT /usr/share/texlive/texmf-dist/tex/generic/pgf/utilities/pgfkeys.code.tex INPUT /usr/share/texlive/texmf-dist/tex/latex/pgf/math/pgfmath.sty INPUT /usr/share/texlive/texmf-dist/tex/latex/pgf/math/pgfmath.sty INPUT /usr/share/texlive/texmf-dist/tex/latex/pgf/math/pgfmath.sty INPUT /usr/share/texlive/texmf-dist/tex/latex/pgf/math/pgfmath.sty INPUT /usr/share/texlive/texmf-dist/tex/latex/pgf/math/pgfmath.sty INPUT /usr/share/texlive/texmf-dist/tex/latex/pgf/math/pgfmath.sty INPUT /usr/share/texlive/texmf-dist/tex/latex/pgf/math/pgfmath.sty INPUT /usr/share/texlive/texmf-dist/tex/latex/pgf/math/pgfmath.sty INPUT /usr/share/texlive/texmf-dist/tex/latex/pgf/math/pgfmath.sty INPUT /usr/share/texlive/texmf-dist/tex/latex/pgf/math/pgfmath.sty INPUT /usr/share/texlive/texmf-dist/tex/latex/pgf/math/pgfmath.sty INPUT /usr/share/texlive/texmf-dist/tex/latex/pgf/utilities/pgfrcs.sty INPUT /usr/share/texlive/texmf-dist/tex/latex/pgf/utilities/pgfkeys.sty INPUT /usr/share/texlive/texmf-dist/tex/generic/pgf/math/pgfmath.code.tex INPUT /usr/share/texlive/texmf-dist/tex/generic/pgf/math/pgfmath.code.tex INPUT /usr/share/texlive/texmf-dist/tex/generic/pgf/math/pgfmath.code.tex INPUT /usr/share/texlive/texmf-dist/tex/generic/pgf/math/pgfmath.code.tex INPUT /usr/share/texlive/texmf-dist/tex/generic/pgf/utilities/pgffor.code.tex INPUT /usr/share/texlive/texmf-dist/tex/generic/pgf/utilities/pgffor.code.tex INPUT /usr/share/texlive/texmf-dist/tex/generic/pgf/utilities/pgffor.code.tex INPUT /usr/share/texlive/texmf-dist/tex/generic/pgf/utilities/pgffor.code.tex INPUT /usr/share/texlive/texmf-dist/tex/generic/pgf/math/pgfmath.code.tex INPUT /usr/share/texlive/texmf-dist/tex/generic/pgf/frontendlayer/tikz/tikz.code.tex INPUT /usr/share/texlive/texmf-dist/tex/generic/pgf/frontendlayer/tikz/tikz.code.tex INPUT /usr/share/texlive/texmf-dist/tex/generic/pgf/frontendlayer/tikz/tikz.code.tex INPUT /usr/share/texlive/texmf-dist/tex/generic/pgf/frontendlayer/tikz/tikz.code.tex INPUT /usr/share/texlive/texmf-dist/tex/generic/pgf/libraries/pgflibraryplothandlers.code.tex INPUT /usr/share/texlive/texmf-dist/tex/generic/pgf/libraries/pgflibraryplothandlers.code.tex INPUT /usr/share/texlive/texmf-dist/tex/generic/pgf/modules/pgfmodulematrix.code.tex INPUT /usr/share/texlive/texmf-dist/tex/generic/pgf/frontendlayer/tikz/libraries/tikzlibrarytopaths.code.tex INPUT /usr/share/texlive/texmf-dist/tex/generic/pgf/frontendlayer/tikz/libraries/tikzlibrarytopaths.code.tex INPUT /usr/share/texlive/texmf-dist/tex/latex/l3backend/l3backend-pdftex.def INPUT /usr/share/texlive/texmf-dist/tex/latex/l3backend/l3backend-pdftex.def INPUT /usr/share/texlive/texmf-dist/tex/latex/l3backend/l3backend-pdftex.def INPUT /usr/share/texlive/texmf-dist/tex/latex/l3backend/l3backend-pdftex.def INPUT /usr/share/texlive/texmf-dist/tex/latex/l3backend/l3backend-pdftex.def INPUT /usr/share/texlive/texmf-dist/tex/latex/l3backend/l3backend-pdftex.def INPUT /usr/share/texlive/texmf-dist/tex/latex/l3backend/l3backend-pdftex.def INPUT /usr/share/texlive/texmf-dist/tex/latex/l3backend/l3backend-pdftex.def INPUT /usr/share/texlive/texmf-dist/tex/latex/l3backend/l3backend-pdftex.def INPUT /usr/share/texlive/texmf-dist/tex/latex/l3backend/l3backend-pdftex.def INPUT /usr/share/texlive/texmf-dist/tex/latex/l3backend/l3backend-pdftex.def INPUT ./algorithm.aux INPUT algorithm.aux INPUT algorithm.aux OUTPUT algorithm.aux INPUT /usr/share/texlive/texmf-dist/tex/context/base/mkii/supp-pdf.mkii INPUT /usr/share/texlive/texmf-dist/tex/context/base/mkii/supp-pdf.mkii INPUT /usr/share/texlive/texmf-dist/tex/context/base/mkii/supp-pdf.mkii INPUT /usr/share/texlive/texmf-dist/tex/context/base/mkii/supp-pdf.mkii INPUT /usr/share/texlive/texmf-dist/tex/latex/epstopdf-pkg/epstopdf-base.sty INPUT /usr/share/texlive/texmf-dist/tex/latex/epstopdf-pkg/epstopdf-base.sty INPUT /usr/share/texlive/texmf-dist/tex/latex/epstopdf-pkg/epstopdf-base.sty INPUT /usr/share/texlive/texmf-dist/tex/latex/epstopdf-pkg/epstopdf-base.sty INPUT /usr/share/texlive/texmf-dist/tex/latex/epstopdf-pkg/epstopdf-base.sty INPUT /usr/share/texlive/texmf-dist/tex/latex/epstopdf-pkg/epstopdf-base.sty INPUT /usr/share/texlive/texmf-dist/tex/latex/epstopdf-pkg/epstopdf-base.sty INPUT /usr/share/texlive/texmf-dist/tex/latex/epstopdf-pkg/epstopdf-base.sty INPUT /usr/share/texlive/texmf-dist/tex/latex/epstopdf-pkg/epstopdf-base.sty INPUT /usr/share/texlive/texmf-dist/tex/latex/epstopdf-pkg/epstopdf-base.sty INPUT /usr/share/texlive/texmf-dist/tex/latex/epstopdf-pkg/epstopdf-base.sty INPUT /usr/share/texlive/texmf-dist/tex/latex/latexconfig/epstopdf-sys.cfg INPUT /usr/share/texlive/texmf-dist/tex/latex/latexconfig/epstopdf-sys.cfg INPUT /usr/share/texlive/texmf-dist/tex/latex/latexconfig/epstopdf-sys.cfg INPUT /usr/share/texlive/texmf-dist/tex/latex/latexconfig/epstopdf-sys.cfg INPUT /usr/share/texlive/texmf-dist/fonts/map/fontname/texfonts.map INPUT /usr/share/texlive/texmf-dist/fonts/tfm/public/cm/cmr17.tfm INPUT /usr/share/texlive/texmf-dist/fonts/tfm/public/cm/cmr12.tfm INPUT /usr/share/texlive/texmf-dist/fonts/tfm/public/cm/cmr8.tfm INPUT /usr/share/texlive/texmf-dist/fonts/tfm/public/cm/cmr6.tfm INPUT /usr/share/texlive/texmf-dist/fonts/tfm/public/cm/cmmi12.tfm INPUT /usr/share/texlive/texmf-dist/fonts/tfm/public/cm/cmmi8.tfm INPUT /usr/share/texlive/texmf-dist/fonts/tfm/public/cm/cmmi6.tfm INPUT /usr/share/texlive/texmf-dist/fonts/tfm/public/cm/cmsy10.tfm INPUT /usr/share/texlive/texmf-dist/fonts/tfm/public/cm/cmsy8.tfm INPUT /usr/share/texlive/texmf-dist/fonts/tfm/public/cm/cmsy6.tfm INPUT /usr/share/texlive/texmf-dist/fonts/tfm/public/cm/cmex10.tfm INPUT /usr/share/texlive/texmf-dist/fonts/tfm/public/amsfonts/cmextra/cmex8.tfm INPUT /usr/share/texlive/texmf-dist/fonts/tfm/public/amsfonts/cmextra/cmex7.tfm INPUT /usr/share/texlive/texmf-dist/tex/latex/amsfonts/umsa.fd INPUT /usr/share/texlive/texmf-dist/tex/latex/amsfonts/umsa.fd INPUT /usr/share/texlive/texmf-dist/tex/latex/amsfonts/umsa.fd INPUT /usr/share/texlive/texmf-dist/tex/latex/amsfonts/umsa.fd INPUT /usr/share/texlive/texmf-dist/fonts/tfm/public/amsfonts/symbols/msam10.tfm INPUT /usr/share/texlive/texmf-dist/fonts/tfm/public/amsfonts/symbols/msam10.tfm INPUT /usr/share/texlive/texmf-dist/fonts/tfm/public/amsfonts/symbols/msam7.tfm INPUT /usr/share/texlive/texmf-dist/tex/latex/amsfonts/umsb.fd INPUT /usr/share/texlive/texmf-dist/tex/latex/amsfonts/umsb.fd INPUT /usr/share/texlive/texmf-dist/tex/latex/amsfonts/umsb.fd INPUT /usr/share/texlive/texmf-dist/tex/latex/amsfonts/umsb.fd INPUT /usr/share/texlive/texmf-dist/fonts/tfm/public/amsfonts/symbols/msbm10.tfm INPUT /usr/share/texlive/texmf-dist/fonts/tfm/public/amsfonts/symbols/msbm10.tfm INPUT /usr/share/texlive/texmf-dist/fonts/tfm/public/amsfonts/symbols/msbm7.tfm INPUT /usr/share/texlive/texmf-dist/fonts/tfm/public/cm/cmr12.tfm INPUT /usr/share/texlive/texmf-dist/fonts/tfm/public/cm/cmbx12.tfm INPUT /usr/share/texlive/texmf-dist/fonts/tfm/public/amsfonts/cmextra/cmex7.tfm INPUT /usr/share/texlive/texmf-dist/fonts/tfm/public/amsfonts/cmextra/cmex7.tfm INPUT /usr/share/texlive/texmf-dist/fonts/tfm/public/amsfonts/symbols/msam10.tfm INPUT /usr/share/texlive/texmf-dist/fonts/tfm/public/amsfonts/symbols/msam7.tfm INPUT /usr/share/texlive/texmf-dist/fonts/tfm/public/amsfonts/symbols/msam5.tfm INPUT /usr/share/texlive/texmf-dist/fonts/tfm/public/amsfonts/symbols/msbm10.tfm INPUT /usr/share/texlive/texmf-dist/fonts/tfm/public/amsfonts/symbols/msbm7.tfm INPUT /usr/share/texlive/texmf-dist/fonts/tfm/public/amsfonts/symbols/msbm5.tfm OUTPUT algorithm.pdf INPUT /var/lib/texmf/fonts/map/pdftex/updmap/pdftex.map INPUT /usr/share/texlive/texmf-dist/fonts/tfm/public/cm/cmbx12.tfm INPUT /usr/share/texlive/texmf-dist/fonts/tfm/public/cm/cmbx10.tfm INPUT ./measurement.png INPUT ./measurement.png INPUT measurement.png INPUT ./measurement.png INPUT ./measurement.png INPUT ./offset-ntpd-rs.png INPUT ./offset-ntpd-rs.png INPUT offset-ntpd-rs.png INPUT ./offset-ntpd-rs.png INPUT ./offset-ntpd-rs.png INPUT ./offset-chrony.png INPUT ./offset-chrony.png INPUT offset-chrony.png INPUT ./offset-chrony.png INPUT ./offset-chrony.png INPUT ./algorithm.bbl INPUT algorithm.bbl INPUT ./algorithm.bbl INPUT algorithm.bbl INPUT /usr/share/texlive/texmf-dist/fonts/tfm/public/cm/cmti10.tfm INPUT algorithm.aux INPUT /usr/share/texlive/texmf-dist/fonts/type1/public/amsfonts/cm/cmbx10.pfb INPUT /usr/share/texlive/texmf-dist/fonts/type1/public/amsfonts/cm/cmbx12.pfb INPUT /usr/share/texlive/texmf-dist/fonts/type1/public/amsfonts/cm/cmex10.pfb INPUT /usr/share/texlive/texmf-dist/fonts/type1/public/amsfonts/cm/cmmi10.pfb INPUT /usr/share/texlive/texmf-dist/fonts/type1/public/amsfonts/cm/cmmi5.pfb INPUT /usr/share/texlive/texmf-dist/fonts/type1/public/amsfonts/cm/cmmi7.pfb INPUT /usr/share/texlive/texmf-dist/fonts/type1/public/amsfonts/cm/cmr10.pfb INPUT /usr/share/texlive/texmf-dist/fonts/type1/public/amsfonts/cm/cmr12.pfb INPUT /usr/share/texlive/texmf-dist/fonts/type1/public/amsfonts/cm/cmr17.pfb INPUT /usr/share/texlive/texmf-dist/fonts/type1/public/amsfonts/cm/cmr5.pfb INPUT /usr/share/texlive/texmf-dist/fonts/type1/public/amsfonts/cm/cmr6.pfb INPUT /usr/share/texlive/texmf-dist/fonts/type1/public/amsfonts/cm/cmr7.pfb INPUT /usr/share/texlive/texmf-dist/fonts/type1/public/amsfonts/cm/cmr8.pfb INPUT /usr/share/texlive/texmf-dist/fonts/type1/public/amsfonts/cm/cmsy10.pfb INPUT /usr/share/texlive/texmf-dist/fonts/type1/public/amsfonts/cm/cmsy5.pfb INPUT /usr/share/texlive/texmf-dist/fonts/type1/public/amsfonts/cm/cmsy7.pfb INPUT /usr/share/texlive/texmf-dist/fonts/type1/public/amsfonts/cm/cmti10.pfb ntpd-1.1.2/docs/algorithm/algorithm.log000064400000000000000000000466021046102023000162110ustar 00000000000000This is pdfTeX, Version 3.141592653-2.6-1.40.22 (TeX Live 2022/dev/Debian) (preloaded format=pdflatex 2023.12.14) 21 DEC 2023 10:05 entering extended mode restricted \write18 enabled. %&-line parsing enabled. **algorithm.tex (./algorithm.tex LaTeX2e <2021-11-15> patch level 1 L3 programming layer <2022-01-21> (/usr/share/texlive/texmf-dist/tex/latex/base/article.cls Document Class: article 2021/10/04 v1.4n Standard LaTeX document class (/usr/share/texlive/texmf-dist/tex/latex/base/size10.clo File: size10.clo 2021/10/04 v1.4n Standard LaTeX file (size option) ) \c@part=\count185 \c@section=\count186 \c@subsection=\count187 \c@subsubsection=\count188 \c@paragraph=\count189 \c@subparagraph=\count190 \c@figure=\count191 \c@table=\count192 \abovecaptionskip=\skip47 \belowcaptionskip=\skip48 \bibindent=\dimen138 ) (/usr/share/texlive/texmf-dist/tex/latex/amsmath/amsmath.sty Package: amsmath 2021/10/15 v2.17l AMS math features \@mathmargin=\skip49 For additional information on amsmath, use the `?' option. (/usr/share/texlive/texmf-dist/tex/latex/amsmath/amstext.sty Package: amstext 2021/08/26 v2.01 AMS text (/usr/share/texlive/texmf-dist/tex/latex/amsmath/amsgen.sty File: amsgen.sty 1999/11/30 v2.0 generic functions \@emptytoks=\toks16 \ex@=\dimen139 )) (/usr/share/texlive/texmf-dist/tex/latex/amsmath/amsbsy.sty Package: amsbsy 1999/11/29 v1.2d Bold Symbols \pmbraise@=\dimen140 ) (/usr/share/texlive/texmf-dist/tex/latex/amsmath/amsopn.sty Package: amsopn 2021/08/26 v2.02 operator names ) \inf@bad=\count193 LaTeX Info: Redefining \frac on input line 234. \uproot@=\count194 \leftroot@=\count195 LaTeX Info: Redefining \overline on input line 399. \classnum@=\count196 \DOTSCASE@=\count197 LaTeX Info: Redefining \ldots on input line 496. LaTeX Info: Redefining \dots on input line 499. LaTeX Info: Redefining \cdots on input line 620. \Mathstrutbox@=\box50 \strutbox@=\box51 \big@size=\dimen141 LaTeX Font Info: Redeclaring font encoding OML on input line 743. LaTeX Font Info: Redeclaring font encoding OMS on input line 744. \macc@depth=\count198 \c@MaxMatrixCols=\count199 \dotsspace@=\muskip16 \c@parentequation=\count266 \dspbrk@lvl=\count267 \tag@help=\toks17 \row@=\count268 \column@=\count269 \maxfields@=\count270 \andhelp@=\toks18 \eqnshift@=\dimen142 \alignsep@=\dimen143 \tagshift@=\dimen144 \tagwidth@=\dimen145 \totwidth@=\dimen146 \lineht@=\dimen147 \@envbody=\toks19 \multlinegap=\skip50 \multlinetaggap=\skip51 \mathdisplay@stack=\toks20 LaTeX Info: Redefining \[ on input line 2938. LaTeX Info: Redefining \] on input line 2939. ) (/usr/share/texlive/texmf-dist/tex/latex/amsfonts/amssymb.sty Package: amssymb 2013/01/14 v3.01 AMS font symbols (/usr/share/texlive/texmf-dist/tex/latex/amsfonts/amsfonts.sty Package: amsfonts 2013/01/14 v3.01 Basic AMSFonts support \symAMSa=\mathgroup4 \symAMSb=\mathgroup5 LaTeX Font Info: Redeclaring math symbol \hbar on input line 98. LaTeX Font Info: Overwriting math alphabet `\mathfrak' in version `bold' (Font) U/euf/m/n --> U/euf/b/n on input line 106. )) (/usr/share/texlive/texmf-dist/tex/latex/graphics/graphicx.sty Package: graphicx 2021/09/16 v1.2d Enhanced LaTeX Graphics (DPC,SPQR) (/usr/share/texlive/texmf-dist/tex/latex/graphics/keyval.sty Package: keyval 2014/10/28 v1.15 key=value parser (DPC) \KV@toks@=\toks21 ) (/usr/share/texlive/texmf-dist/tex/latex/graphics/graphics.sty Package: graphics 2021/03/04 v1.4d Standard LaTeX Graphics (DPC,SPQR) (/usr/share/texlive/texmf-dist/tex/latex/graphics/trig.sty Package: trig 2021/08/11 v1.11 sin cos tan (DPC) ) (/usr/share/texlive/texmf-dist/tex/latex/graphics-cfg/graphics.cfg File: graphics.cfg 2016/06/04 v1.11 sample graphics configuration ) Package graphics Info: Driver file: pdftex.def on input line 107. (/usr/share/texlive/texmf-dist/tex/latex/graphics-def/pdftex.def File: pdftex.def 2020/10/05 v1.2a Graphics/color driver for pdftex )) \Gin@req@height=\dimen148 \Gin@req@width=\dimen149 ) (/usr/share/texlive/texmf-dist/tex/latex/pgf/frontendlayer/tikz.sty (/usr/share/texlive/texmf-dist/tex/latex/pgf/basiclayer/pgf.sty (/usr/share/texlive/texmf-dist/tex/latex/pgf/utilities/pgfrcs.sty (/usr/share/texlive/texmf-dist/tex/generic/pgf/utilities/pgfutil-common.tex \pgfutil@everybye=\toks22 \pgfutil@tempdima=\dimen150 \pgfutil@tempdimb=\dimen151 (/usr/share/texlive/texmf-dist/tex/generic/pgf/utilities/pgfutil-common-lists.t ex)) (/usr/share/texlive/texmf-dist/tex/generic/pgf/utilities/pgfutil-latex.def \pgfutil@abb=\box52 ) (/usr/share/texlive/texmf-dist/tex/generic/pgf/utilities/pgfrcs.code.tex (/usr/share/texlive/texmf-dist/tex/generic/pgf/pgf.revision.tex) Package: pgfrcs 2021/05/15 v3.1.9a (3.1.9a) )) Package: pgf 2021/05/15 v3.1.9a (3.1.9a) (/usr/share/texlive/texmf-dist/tex/latex/pgf/basiclayer/pgfcore.sty (/usr/share/texlive/texmf-dist/tex/latex/pgf/systemlayer/pgfsys.sty (/usr/share/texlive/texmf-dist/tex/generic/pgf/systemlayer/pgfsys.code.tex Package: pgfsys 2021/05/15 v3.1.9a (3.1.9a) (/usr/share/texlive/texmf-dist/tex/generic/pgf/utilities/pgfkeys.code.tex \pgfkeys@pathtoks=\toks23 \pgfkeys@temptoks=\toks24 (/usr/share/texlive/texmf-dist/tex/generic/pgf/utilities/pgfkeysfiltered.code.t ex \pgfkeys@tmptoks=\toks25 )) \pgf@x=\dimen152 \pgf@y=\dimen153 \pgf@xa=\dimen154 \pgf@ya=\dimen155 \pgf@xb=\dimen156 \pgf@yb=\dimen157 \pgf@xc=\dimen158 \pgf@yc=\dimen159 \pgf@xd=\dimen160 \pgf@yd=\dimen161 \w@pgf@writea=\write3 \r@pgf@reada=\read2 \c@pgf@counta=\count271 \c@pgf@countb=\count272 \c@pgf@countc=\count273 \c@pgf@countd=\count274 \t@pgf@toka=\toks26 \t@pgf@tokb=\toks27 \t@pgf@tokc=\toks28 \pgf@sys@id@count=\count275 (/usr/share/texlive/texmf-dist/tex/generic/pgf/systemlayer/pgf.cfg File: pgf.cfg 2021/05/15 v3.1.9a (3.1.9a) ) Driver file for pgf: pgfsys-pdftex.def (/usr/share/texlive/texmf-dist/tex/generic/pgf/systemlayer/pgfsys-pdftex.def File: pgfsys-pdftex.def 2021/05/15 v3.1.9a (3.1.9a) (/usr/share/texlive/texmf-dist/tex/generic/pgf/systemlayer/pgfsys-common-pdf.de f File: pgfsys-common-pdf.def 2021/05/15 v3.1.9a (3.1.9a) ))) (/usr/share/texlive/texmf-dist/tex/generic/pgf/systemlayer/pgfsyssoftpath.code. tex File: pgfsyssoftpath.code.tex 2021/05/15 v3.1.9a (3.1.9a) \pgfsyssoftpath@smallbuffer@items=\count276 \pgfsyssoftpath@bigbuffer@items=\count277 ) (/usr/share/texlive/texmf-dist/tex/generic/pgf/systemlayer/pgfsysprotocol.code. tex File: pgfsysprotocol.code.tex 2021/05/15 v3.1.9a (3.1.9a) )) (/usr/share/texlive/texmf-dist/tex/latex/xcolor/xcolor.sty Package: xcolor 2021/10/31 v2.13 LaTeX color extensions (UK) (/usr/share/texlive/texmf-dist/tex/latex/graphics-cfg/color.cfg File: color.cfg 2016/01/02 v1.6 sample color configuration ) Package xcolor Info: Driver file: pdftex.def on input line 227. Package xcolor Info: Model `cmy' substituted by `cmy0' on input line 1352. Package xcolor Info: Model `hsb' substituted by `rgb' on input line 1356. Package xcolor Info: Model `RGB' extended on input line 1368. Package xcolor Info: Model `HTML' substituted by `rgb' on input line 1370. Package xcolor Info: Model `Hsb' substituted by `hsb' on input line 1371. Package xcolor Info: Model `tHsb' substituted by `hsb' on input line 1372. Package xcolor Info: Model `HSB' substituted by `hsb' on input line 1373. Package xcolor Info: Model `Gray' substituted by `gray' on input line 1374. Package xcolor Info: Model `wave' substituted by `hsb' on input line 1375. ) (/usr/share/texlive/texmf-dist/tex/generic/pgf/basiclayer/pgfcore.code.tex Package: pgfcore 2021/05/15 v3.1.9a (3.1.9a) (/usr/share/texlive/texmf-dist/tex/generic/pgf/math/pgfmath.code.tex (/usr/share/texlive/texmf-dist/tex/generic/pgf/math/pgfmathcalc.code.tex (/usr/share/texlive/texmf-dist/tex/generic/pgf/math/pgfmathutil.code.tex) (/usr/share/texlive/texmf-dist/tex/generic/pgf/math/pgfmathparser.code.tex \pgfmath@dimen=\dimen162 \pgfmath@count=\count278 \pgfmath@box=\box53 \pgfmath@toks=\toks29 \pgfmath@stack@operand=\toks30 \pgfmath@stack@operation=\toks31 ) (/usr/share/texlive/texmf-dist/tex/generic/pgf/math/pgfmathfunctions.code.tex (/usr/share/texlive/texmf-dist/tex/generic/pgf/math/pgfmathfunctions.basic.code .tex) (/usr/share/texlive/texmf-dist/tex/generic/pgf/math/pgfmathfunctions.trigonomet ric.code.tex) (/usr/share/texlive/texmf-dist/tex/generic/pgf/math/pgfmathfunctions.random.cod e.tex) (/usr/share/texlive/texmf-dist/tex/generic/pgf/math/pgfmathfunctions.comparison .code.tex) (/usr/share/texlive/texmf-dist/tex/generic/pgf/math/pgfmathfunctions.base.code. tex) (/usr/share/texlive/texmf-dist/tex/generic/pgf/math/pgfmathfunctions.round.code .tex) (/usr/share/texlive/texmf-dist/tex/generic/pgf/math/pgfmathfunctions.misc.code. tex) (/usr/share/texlive/texmf-dist/tex/generic/pgf/math/pgfmathfunctions.integerari thmetics.code.tex))) (/usr/share/texlive/texmf-dist/tex/generic/pgf/math/pgfmathfloat.code.tex \c@pgfmathroundto@lastzeros=\count279 )) (/usr/share/texlive/texmf-dist/tex/generic/pgf/math/pgfint.code.tex) (/usr/share/texlive/texmf-dist/tex/generic/pgf/basiclayer/pgfcorepoints.code.te x File: pgfcorepoints.code.tex 2021/05/15 v3.1.9a (3.1.9a) \pgf@picminx=\dimen163 \pgf@picmaxx=\dimen164 \pgf@picminy=\dimen165 \pgf@picmaxy=\dimen166 \pgf@pathminx=\dimen167 \pgf@pathmaxx=\dimen168 \pgf@pathminy=\dimen169 \pgf@pathmaxy=\dimen170 \pgf@xx=\dimen171 \pgf@xy=\dimen172 \pgf@yx=\dimen173 \pgf@yy=\dimen174 \pgf@zx=\dimen175 \pgf@zy=\dimen176 ) (/usr/share/texlive/texmf-dist/tex/generic/pgf/basiclayer/pgfcorepathconstruct. code.tex File: pgfcorepathconstruct.code.tex 2021/05/15 v3.1.9a (3.1.9a) \pgf@path@lastx=\dimen177 \pgf@path@lasty=\dimen178 ) (/usr/share/texlive/texmf-dist/tex/generic/pgf/basiclayer/pgfcorepathusage.code .tex File: pgfcorepathusage.code.tex 2021/05/15 v3.1.9a (3.1.9a) \pgf@shorten@end@additional=\dimen179 \pgf@shorten@start@additional=\dimen180 ) (/usr/share/texlive/texmf-dist/tex/generic/pgf/basiclayer/pgfcorescopes.code.te x File: pgfcorescopes.code.tex 2021/05/15 v3.1.9a (3.1.9a) \pgfpic=\box54 \pgf@hbox=\box55 \pgf@layerbox@main=\box56 \pgf@picture@serial@count=\count280 ) (/usr/share/texlive/texmf-dist/tex/generic/pgf/basiclayer/pgfcoregraphicstate.c ode.tex File: pgfcoregraphicstate.code.tex 2021/05/15 v3.1.9a (3.1.9a) \pgflinewidth=\dimen181 ) (/usr/share/texlive/texmf-dist/tex/generic/pgf/basiclayer/pgfcoretransformation s.code.tex File: pgfcoretransformations.code.tex 2021/05/15 v3.1.9a (3.1.9a) \pgf@pt@x=\dimen182 \pgf@pt@y=\dimen183 \pgf@pt@temp=\dimen184 ) (/usr/share/texlive/texmf-dist/tex/generic/pgf/basiclayer/pgfcorequick.code.tex File: pgfcorequick.code.tex 2021/05/15 v3.1.9a (3.1.9a) ) (/usr/share/texlive/texmf-dist/tex/generic/pgf/basiclayer/pgfcoreobjects.code.t ex File: pgfcoreobjects.code.tex 2021/05/15 v3.1.9a (3.1.9a) ) (/usr/share/texlive/texmf-dist/tex/generic/pgf/basiclayer/pgfcorepathprocessing .code.tex File: pgfcorepathprocessing.code.tex 2021/05/15 v3.1.9a (3.1.9a) ) (/usr/share/texlive/texmf-dist/tex/generic/pgf/basiclayer/pgfcorearrows.code.te x File: pgfcorearrows.code.tex 2021/05/15 v3.1.9a (3.1.9a) \pgfarrowsep=\dimen185 ) (/usr/share/texlive/texmf-dist/tex/generic/pgf/basiclayer/pgfcoreshade.code.tex File: pgfcoreshade.code.tex 2021/05/15 v3.1.9a (3.1.9a) \pgf@max=\dimen186 \pgf@sys@shading@range@num=\count281 \pgf@shadingcount=\count282 ) (/usr/share/texlive/texmf-dist/tex/generic/pgf/basiclayer/pgfcoreimage.code.tex File: pgfcoreimage.code.tex 2021/05/15 v3.1.9a (3.1.9a) (/usr/share/texlive/texmf-dist/tex/generic/pgf/basiclayer/pgfcoreexternal.code. tex File: pgfcoreexternal.code.tex 2021/05/15 v3.1.9a (3.1.9a) \pgfexternal@startupbox=\box57 )) (/usr/share/texlive/texmf-dist/tex/generic/pgf/basiclayer/pgfcorelayers.code.te x File: pgfcorelayers.code.tex 2021/05/15 v3.1.9a (3.1.9a) ) (/usr/share/texlive/texmf-dist/tex/generic/pgf/basiclayer/pgfcoretransparency.c ode.tex File: pgfcoretransparency.code.tex 2021/05/15 v3.1.9a (3.1.9a) ) (/usr/share/texlive/texmf-dist/tex/generic/pgf/basiclayer/pgfcorepatterns.code. tex File: pgfcorepatterns.code.tex 2021/05/15 v3.1.9a (3.1.9a) ) (/usr/share/texlive/texmf-dist/tex/generic/pgf/basiclayer/pgfcorerdf.code.tex File: pgfcorerdf.code.tex 2021/05/15 v3.1.9a (3.1.9a) ))) (/usr/share/texlive/texmf-dist/tex/generic/pgf/modules/pgfmoduleshapes.code.tex File: pgfmoduleshapes.code.tex 2021/05/15 v3.1.9a (3.1.9a) \pgfnodeparttextbox=\box58 ) (/usr/share/texlive/texmf-dist/tex/generic/pgf/modules/pgfmoduleplot.code.tex File: pgfmoduleplot.code.tex 2021/05/15 v3.1.9a (3.1.9a) ) (/usr/share/texlive/texmf-dist/tex/latex/pgf/compatibility/pgfcomp-version-0-65 .sty Package: pgfcomp-version-0-65 2021/05/15 v3.1.9a (3.1.9a) \pgf@nodesepstart=\dimen187 \pgf@nodesepend=\dimen188 ) (/usr/share/texlive/texmf-dist/tex/latex/pgf/compatibility/pgfcomp-version-1-18 .sty Package: pgfcomp-version-1-18 2021/05/15 v3.1.9a (3.1.9a) )) (/usr/share/texlive/texmf-dist/tex/latex/pgf/utilities/pgffor.sty (/usr/share/texlive/texmf-dist/tex/latex/pgf/utilities/pgfkeys.sty (/usr/share/texlive/texmf-dist/tex/generic/pgf/utilities/pgfkeys.code.tex)) (/usr/share/texlive/texmf-dist/tex/latex/pgf/math/pgfmath.sty (/usr/share/texlive/texmf-dist/tex/generic/pgf/math/pgfmath.code.tex)) (/usr/share/texlive/texmf-dist/tex/generic/pgf/utilities/pgffor.code.tex Package: pgffor 2021/05/15 v3.1.9a (3.1.9a) (/usr/share/texlive/texmf-dist/tex/generic/pgf/math/pgfmath.code.tex) \pgffor@iter=\dimen189 \pgffor@skip=\dimen190 \pgffor@stack=\toks32 \pgffor@toks=\toks33 )) (/usr/share/texlive/texmf-dist/tex/generic/pgf/frontendlayer/tikz/tikz.code.tex Package: tikz 2021/05/15 v3.1.9a (3.1.9a) (/usr/share/texlive/texmf-dist/tex/generic/pgf/libraries/pgflibraryplothandlers .code.tex File: pgflibraryplothandlers.code.tex 2021/05/15 v3.1.9a (3.1.9a) \pgf@plot@mark@count=\count283 \pgfplotmarksize=\dimen191 ) \tikz@lastx=\dimen192 \tikz@lasty=\dimen193 \tikz@lastxsaved=\dimen194 \tikz@lastysaved=\dimen195 \tikz@lastmovetox=\dimen196 \tikz@lastmovetoy=\dimen197 \tikzleveldistance=\dimen198 \tikzsiblingdistance=\dimen199 \tikz@figbox=\box59 \tikz@figbox@bg=\box60 \tikz@tempbox=\box61 \tikz@tempbox@bg=\box62 \tikztreelevel=\count284 \tikznumberofchildren=\count285 \tikznumberofcurrentchild=\count286 \tikz@fig@count=\count287 (/usr/share/texlive/texmf-dist/tex/generic/pgf/modules/pgfmodulematrix.code.tex File: pgfmodulematrix.code.tex 2021/05/15 v3.1.9a (3.1.9a) \pgfmatrixcurrentrow=\count288 \pgfmatrixcurrentcolumn=\count289 \pgf@matrix@numberofcolumns=\count290 ) \tikz@expandcount=\count291 (/usr/share/texlive/texmf-dist/tex/generic/pgf/frontendlayer/tikz/libraries/tik zlibrarytopaths.code.tex File: tikzlibrarytopaths.code.tex 2021/05/15 v3.1.9a (3.1.9a) ))) (/usr/share/texlive/texmf-dist/tex/latex/l3backend/l3backend-pdftex.def File: l3backend-pdftex.def 2022-01-12 L3 backend support: PDF output (pdfTeX) \l__color_backend_stack_int=\count292 \l__pdf_internal_box=\box63 ) (./algorithm.aux) \openout1 = `algorithm.aux'. LaTeX Font Info: Checking defaults for OML/cmm/m/it on input line 15. LaTeX Font Info: ... okay on input line 15. LaTeX Font Info: Checking defaults for OMS/cmsy/m/n on input line 15. LaTeX Font Info: ... okay on input line 15. LaTeX Font Info: Checking defaults for OT1/cmr/m/n on input line 15. LaTeX Font Info: ... okay on input line 15. LaTeX Font Info: Checking defaults for T1/cmr/m/n on input line 15. LaTeX Font Info: ... okay on input line 15. LaTeX Font Info: Checking defaults for TS1/cmr/m/n on input line 15. LaTeX Font Info: ... okay on input line 15. LaTeX Font Info: Checking defaults for OMX/cmex/m/n on input line 15. LaTeX Font Info: ... okay on input line 15. LaTeX Font Info: Checking defaults for U/cmr/m/n on input line 15. LaTeX Font Info: ... okay on input line 15. (/usr/share/texlive/texmf-dist/tex/context/base/mkii/supp-pdf.mkii [Loading MPS to PDF converter (version 2006.09.02).] \scratchcounter=\count293 \scratchdimen=\dimen256 \scratchbox=\box64 \nofMPsegments=\count294 \nofMParguments=\count295 \everyMPshowfont=\toks34 \MPscratchCnt=\count296 \MPscratchDim=\dimen257 \MPnumerator=\count297 \makeMPintoPDFobject=\count298 \everyMPtoPDFconversion=\toks35 ) (/usr/share/texlive/texmf-dist/tex/latex/epstopdf-pkg/epstopdf-base.sty Package: epstopdf-base 2020-01-24 v2.11 Base part for package epstopdf Package epstopdf-base Info: Redefining graphics rule for `.eps' on input line 4 85. (/usr/share/texlive/texmf-dist/tex/latex/latexconfig/epstopdf-sys.cfg File: epstopdf-sys.cfg 2010/07/13 v1.3 Configuration of (r)epstopdf for TeX Liv e )) LaTeX Font Info: Trying to load font information for U+msa on input line 17. (/usr/share/texlive/texmf-dist/tex/latex/amsfonts/umsa.fd File: umsa.fd 2013/01/14 v3.01 AMS symbols A ) LaTeX Font Info: Trying to load font information for U+msb on input line 17. (/usr/share/texlive/texmf-dist/tex/latex/amsfonts/umsb.fd File: umsb.fd 2013/01/14 v3.01 AMS symbols B ) LaTeX Warning: No \author given. [1 {/var/lib/texmf/fonts/map/pdftex/updmap/pdftex.map}] [2] [3] [4] [5] File: measurement.png Graphic file (type png) Package pdftex.def Info: measurement.png used on input line 250. (pdftex.def) Requested size: 276.00105pt x 141.45561pt. [6 <./measurement.png>] [7] [8] [9] File: offset-ntpd-rs.png Graphic file (type png) Package pdftex.def Info: offset-ntpd-rs.png used on input line 364. (pdftex.def) Requested size: 172.5pt x 129.37462pt. File: offset-chrony.png Graphic file (type png) Package pdftex.def Info: offset-chrony.png used on input line 364. (pdftex.def) Requested size: 172.5pt x 129.37462pt. (./algorithm.bbl [10 <./offset-ntpd-rs.png (PNG copy)> <./offset-chrony.png (P NG copy)>]) [11] (./algorithm.aux) ) Here is how much of TeX's memory you used: 13067 strings out of 478287 263580 string characters out of 5849288 531159 words of memory out of 5000000 31042 multiletter control sequences out of 15000+600000 477468 words of font info for 60 fonts, out of 8000000 for 9000 1141 hyphenation exceptions out of 8191 84i,14n,89p,607b,703s stack positions out of 5000i,500n,10000p,200000b,80000s Output written on algorithm.pdf (11 pages, 293302 bytes). PDF statistics: 133 PDF objects out of 1000 (max. 8388607) 81 compressed objects within 1 object stream 0 named destinations out of 1000 (max. 500000) 28 words of extra memory for PDF output out of 10000 (max. 10000000) ntpd-1.1.2/docs/algorithm/algorithm.pdf000064400000000000000000010746661046102023000162150ustar 00000000000000%PDF-1.5 % 6 0 obj << /Length 2264 /Filter /FlateDecode >> stream xڝYKoϯ-`ld3$9I3sDMSMR2=b?ӆo>b# "՛FJ/6H*f|J~mNfINqڡN4;zvH1>znp/AHSG(Ä6]*RNl&9&R$KE$dv,zS˳ P"MUrG3[VxfuPQK:El˔H>lsjkVdDz]K Qg.ᬃ {v +T>I$[Eg`\XXI%QP !f*9$4%n!t?<6%.<͊vhJ,@N)Lvv~x )(؆ pΘ{@|R4m?`dy5怒f,-cO;n?,M[pQo_~lH\OeCBѤ<4vm $Sk!EqF%B È0 mU_MZd+AxWɻ8/w4zo fpaCQƌiT s`< ] >'U{:¨&ҙA!%!B `$8XljWޮ&D 6^ŗm=pRȍo<`2PJJ. %=Mc \= uH R`J_JdE Ka>6եV)&P%4Ȃ`@ܪϝ"7B d VC?q i*PJmTg,[+Pͷ/3lZ4=[] >^-|_Lp.& o_xvFKoC:HKO5$ĠC5y5)h*Sٵ 8\yWLsfx-% U AEtmX$@z!ؿM9"0K0z"y,-l)g3gi"kFYcxm<(6+ʑ0X&Bfᗍ2Q0nnZ5|=d2G~[eJblbJ \b8tGT,)lKWDk)ǒY)}po@P2ody˛kϙPcɯAu^ \EDJ~̬'9+f-_fJȒ?SjT)!P @rn=wR7H.,׼`XQ1h78Ko#dZ܇ʋXaa䬥]y3fho۟t | oۯ+W!h> stream xZ[ܶ~?Bo˛$2E_.R !̓+*݋#icwCv{6pșqO O^qݟKXf Y$o+ yɤʓMSfI ?u}\eZ;hOwNt>[e%WQ%~WCuxIt~Fr 5~[EZMu\{+o^[|= lm8W) GTocY.Dɒ)-i^oΊY_ICF.DhƵ!s)#`*d3qbqqT&yĘ\}rʩ P?)-LS`@r)Amnj n!&1$[Yea`< ɫeܽ$GsUqGէL eTB V*Az xSUl.ކ+x=d0&apB0fOf%\PB MPM2gD5S D VPrjܳbz׭c)-ٽYTdrʈR(gE|p/ MHx'wb=уyx g\ς 8!Rq̿8ԥP{Oh=уyZ^bר0ϙ^;. ,=_ eS_ J(q.PLj' 2x>gwZB><^CEt TDwVPMAhES~.櫨+-7cyS1e[@Hqm&4y*% lzY4[e"mzFW?^v!iOH`1a֪mO,F_X*Z:o{uZ*=U18"ßaֺjz:w7?;u]/PMs҃\sd:XMxIbH4H|?? ucP:KPqOǮ]Mub.yi{cOc +*߽ Rݺm5~*ڐAC(c% LtV )jB 1j?q\;l=vZn۶u]q ,U5yK\i/AcWE[56jXyv(Zza~^;t>3ĹX7#BjMpvk>$ۈXmBSSikxu'0;mpOAG*e3~+mpӦ[$B-LmaKM@{z;ux\` ΐeU[a*0^ X endstream endobj 22 0 obj << /Length 2803 /Filter /FlateDecode >> stream x˒>_)[0Iy󰽓-qF1IytAMv\$n]Ƴxg/t ͔2̈́R.`RfTm^䯸Лg/$JVZiq-`N Z}sT*m5e6Q}=X[QmWw7aM׵5aMsV;WgWorcȗS,k0a:Q&|:WA0f}s@װiζ=`SӜ]/,a4{BӡzI`Gsx8^ #==t{$6oo݄㹀8>*xM@ھ+[j[qdYI`^`wˡiwxjC 1u252ak̲P(f 3]*ƍfODۚpxh6SdcO"\RS2nv];de|٭%}E?#x/DY&ۘP`;'V״]W$" pP Z9.>%tsB?)~LrNC/h"1\)Áq|x^ xD@*&MYi>׀ESd9*N'Y zj7[\3æ IJj*%,h7(sb u HHio{2Оipׄc !VDH%<ɪ7o/4^?񧥎LJp!5(JZ-a/b''_P.>UBqE9N~V宗{>!a߂iMHƫ.,ZȨ,ku>SBƄsqFs@SEa/T}\X802/1gٹocMP–z6ɓqfŒD3-LȒR.΋eƔ-7݃t-LMMlaS1DtByIA_Ɠ$Ǵwf |^)p!c1*p] 8u ]N֜R1+LL9N f5|?J."D^+xf f @۫ !}` n3HM9GmWQ{J &Q+Jp}j%d ݼ3ऄә RNs,-.UR-2EUآ *TH|D *!J?b)cvǬ֟Fzy#*%G#_[ >9s!}Kvbcc! x%07̖_$HQ$"Epu\O"%e2d qo"sVĩGU@ͳhJi'^LYīF6'3 K(!~̑(N13דO0q@oL޺vLOeۯ2jhQU#zlQYHM9|5 Gx `S|4t`pOy7 آ=\քȌ1zPߘVn7[Hl]J9W9ZaduLk]*BLQ1%b%c+Hڋ|;s, ?e eť?q%@ofE(oBNvh -#vVgzBDDz\)dW3?03氏K֮fvgkW @O#λx`{?AA(`='dfb,=$q6듧j)%V+H N 96e"jkURk"۔.@uz(}n\뾧]XT,D =+%Ȓ0$Xջ6҇?0PۼOY ]6x]x*:_a~ Œ~{jmDDym~ºS'G$3HgFu/R,bNgC@YƠ)Pm=x~3P _z|v !> #Kg<ͱe{9I"<9yybVHtdylpgFT<뮥=Agqpz@;zW"ٌOP D*sj2061ڎblQux؃:qr=·XXZR_K`` u6KU7->9 cC/׃G ~Y$0\xs*fEUE7jDs wƌH=!}jdx3(˖^PihXvanƫ~Bph->,{ ow؈_W$^07SӘs{}4ԤiALLKqpf;Ɋ gFX0xjQ*,\fKxtuͯ%NYtLѳǨ'@~fv|IES9a!HY7c! oZ$=4ޝ vpϹTzD[2s5p(s@ə.WIxazVCƧ9 ua~=@ND"YJOIkrt(yz0DD%-56͒TQ6.Ut?>j7c0bzVѤ/o3 z endstream endobj 29 0 obj << /Length 2278 /Filter /FlateDecode >> stream x[Ks8WHD \j!9쁑h;RF/%VM.&H6߀Nn'o/p_t3p)5nbeB|kaQήKWS)U/~h^&pT~{w5+䛂m5F ,gc 2+Y&q.( DC4FLbkLsȌcY8-뫩=H?Gf:eVԿ: ȼS L27<,8:C d[F(iu/IF{ DŽC2ׯ[abN9J"suYN8&޵f(f!܍Tz1\/-6/zp<6tUͶ.V'kt #f>.OV.?Lrjy =)ME"%Y-7x״<-K+6xM~S(MU`A #ȩNqK9?.L1sz\ ^"[S6)(*䎡ahnďAYbA9V0`c:@;s!c؄`1/g-(tbc;r[ Gc`=BNu2}n)tQ-㨼T?x5o!,tY~'I0I5@Z'SRPɉ ڴ7PesՕFu Rɿ0mހAobff ) e&*/54_,m?C`'(cg!݉O?Z4@Dvp<Ewhێzx+w%{_BZtb3R׮𯳮$:{|q.O]A~2; ܣncMl*ag/~o.nݲ9kYnA?Ӣ#4Q~+rΓy~]r_VkOb1Î$r/6>G`0WDV`VXZBz].1`j\ީN0%[# m"+O܃eҶ ftNxc^y-DS{z| :?Be@F1(Ƿb?ROӝIL?Y;82}UT(#'/ݜ/"vl ըg<KO1#ٻKG{b[ʤ B)3SN/쩛rE&\P%Kg' *RW!\y•f•@W 5:K+Gm> stream xZKsﯘ㨲bćM٩<\VU 3Ԓ]ߧciV%'lt$FlJ˛W|Ħ,Jn#. g}7?lڏյ.vS56qx}umDt6B+=S8=ǺN]o :"q[U/xU,0p޲a}Ճ,C_kAH4JW) µ]GM{DmR;"A׼Bjglڛ3ndd^Pm356|OU 6gpP g[zu]BΡ-4g`s h=/ tRTp9 ep"gc{OHj:]Tپ f{;t}t "I  :ր>]xG 6\vPEH~ZӶt$z}IaT bI7NṂwVhJ|ς }uMO5JV1c|d9EAz?Sr'NW͂%,ch=Gc5JиjZFQB-t0 RiΉx#3!`NZFMYe+dyx;F!;P@NxAN<ۏN8˔zs!(;A`RdzK O~**"ᡜsLM fhHU{&1w#}q-F$$]8?Ga}Dh H赐ez]Bi@ݶY~BDgf 5&H픃b]~zoD]cxA(Xy%''c=UЀ;6cŦ9[)ӱm(c09#O$6fKp^){tu48J*CŪHdJd*wqfQE͌tQBPqvصS:*lO9,M 4p5#EBXDX8gqMEep7$k,GЀ6D6;4Fq^ȵvxS}}W\k^+S.$*O6Vʒee70c#DHwRS6Io)EUTő@iྚ>K(Q.YaEMAb}Dm*La0s[6P.K\*)!{릮 (WwH@\%΃.pU1$:<AO pa& ~#0zKnyyrU΄S[RyٸפIͣa\8·qv72\X]7PZiXm6Uȹ ˰ :eX^̯w55ro_`C"3~'8|l\$[Q$cMvYv_u]ڟ۠rVAY?SLbA]w@6RPW3E܇ee].d+ cZOESTiBpn휷GM.JuG޿:^?/%\?)v=:Raf vĔ$4H%dQ*e\6oHDG?,@,eϕF3Ld=9$SO5|͔~كÑ*%~ΨP ]@ oӢ1۷Pڰ(̩ͪxզgpy cSA6໋ D .zSV6(' m J,'Rb/u?t 碶M_pbNL`×pgπE"zM>Hfvϼ -[tq^:BXc#vBPL1 6 _פBIqCǜgߝn[Է?8+r(eYve/8AL18mMD`2<Ѕ(I O4p,3e.~&e:9`<{@:0OƽH{XKY"=) ,X}B_ 1SOjM-CVǤZ+`p[ 8vP.}̒P9vy S`ɗ-8R?H Q endstream endobj 39 0 obj << /Length 2226 /Filter /FlateDecode >> stream xڭYKϯ`NV/Ň'$;@hSvv}jR$ ԏbUu=nE1?D/Oޫ(D8x:RkiD(m")|~Tiqg8>dp%+{r-IBd7oF³=NysET̺n8ݖǝV i|ʉ'gb(]FWEo5g֭!I,Ey36"IE4˖D𷧇zE T4AHe?6Y831J:#BJe"Xfa #̌7ņ*&+^+kP~ڟ<)R@#~J)ֻ3 Wb?FDsH8ڶwQS:R-c LwZkE0kϴFns2k"I=AZPj_,uG7ŵwtT7'6m|/]\g?{8դ"`DM[%ۦd/'xFËd2矾:6ϑ4 ѓH ' ݆..iװ0C^ڙX+4ג*To{ Le&9K1GJpwnb> @gdJň5OuL K;iQ\F[Pyi8r.r#YA.eWx l#۽t-lpe !1JƤ E-eWj T6UZ&N6G6Lu{+]aD M7QxWM?yBBpEDŽ"qxyWSFD,8F(h4mUڷg>M?F 4[!rFa2 %la jkHZhA61Z,@+|#| CSSx_xZ7<`Kn4S9횙-/q%KVP,AL:ò} XTu([vJ-z}8RAe;qb}"F7Fjv] ^QYo<" CV{4VHf}Xw@kߔ> eGI+U"):5oF?<1e}:bQ"e;Y;m&rq?2kLq0ߍw3H: %.zGT}Klܝpk筢ʏ#7}ݷ8E !au'0 ` endstream endobj 35 0 obj << /Type /XObject /Subtype /Image /Width 640 /Height 328 /BitsPerComponent 8 /ColorSpace /DeviceRGB /SMask 41 0 R /Length 15769 /Filter /FlateDecode >> stream xTp+6T { XQ]%"]؍]&{ RiKn޳%˞9,ywvN whB-͎O h@Gϟ={#ƌ}xgoXXhww pFر±cm4>##cZZZjJlmmܹv&==ɩUV JLL {r)7Z @233)g̙rJgjj*믿H##-Z*UYF4@J*qFEEQn4 ;rg.\7l՚ v1_611@9{, 4 %QTZUYxEvss,tttDH'Ç R~}u{{{}||ڝ0aMݻiJyqQV [nРAfff8FFF>|8UZ,Yd\\Emffftttٲev%@:s ,/?_till\D;wRd2ۛqwwG&ZO><~xg uy hzuh@)zSrԩSAAAIIIO> NLLzꚚEr C8x طo!5 --mϞ= ,c޽ |r.ߨuׯ7lؐ3zȎիG XbEJ[Qgdd0&&Fź7nDH_~]n\qh4.]ZX1"_Q&''שSB ٶ ЫӧOѣGɒ% /vZD0p8/W~zyիW;vʖ-sNXd2-oll,aVVV4g"##n ^O#CAy voʷ7rpPҷoߨ(4G:&&֭[իWZ… tzҳgO#62HΝ۶m[4lpAz4\h)bcǎ)C}TtMIMM6,[ltt4^U[V2ڷoߖc4HUBBZnJ.j*@@ +- 5j3f̅ 9 v ۵kסC-[QKKJյkן~)>>~Ȑ!܁vSu|ƍcSM6͍/飬H"_~A׿T#… k={w g͚DϞ=OJʆjd6_t)ttt()m yM6M2|\ P.ڵk9)L%ye,.fO՜o > ݻG 2rQF]~#F>|8 Gf=z4~,hl2223vXjɓ'V谰I&P]Lkz2q`4HVZZZڵy/ $А~>Wݼ?.+?T$055N_~M)&:{֭㻖аM69P7n?… wEܜᐐ`?<Yf|"9uA>"PYN''-[c$D_re>48q;vnܸ8dzɒ%<1/%&?Ύ\> jX>TnݺhRT?Xܘ1c-ҡCxV111C呓&M;y܈k(ԬY?WWWOҜ T7o5jU"v"L/&MBq#ؾ}D)ʇ9Q'& Ν-'Nqx][Ogiiɟ;xl3YjOO-o_f;ֿ&/r-P;FefF-9'-ZCCC)^9ڬ{ݣG={ҰO>Zѡ!չèD)Fc0\R O`cc@#uՋ/\>ի޽{߾}6mʟK+D8 ,;w,^oM[K\xqS~}lN8WJϧ*U?e<ٳg9O?47_]۷Dw29uVGGG*xϝ;'n-&x>LS+J* 6l[ׯ+W+۴i|}}(Օ"Xl7޿?OyehYV-e0`\>ι:t(V|1_ T]6))I__>}|gCs>iƍyMշdGPP|qJKOKLMJ!G2 S鑌GjrbJ2/y$/Q>VWWrʊl%''׬Y Iѣ4O&e˖ ߾}`YfӘ`]vy%ӧO9b1Ajj*%\w>Gw%;wٳg̘\|Hχ "6t/O!Ǽ'k=[ |u F[^C3ߗu{ʌ+BK>oܸӇ۷)Tr5e9޼ys۷8*Ok׮^fs.nAiӦQ߀o,U*3{W?36M}%v5*Y=-cF K=xi1@|cZ3jtzhC<>YRZ!QP?yc8ՈPSSSCCC[4{hٲxںW^}riAȼ̌IQرcekkKPl |,@A_n]666=z077#w%?4+xgmMonxsU~^zӋo*۸bˑv?.ChOl?>Ж㿜[E+gЌx|c}!Uc/0;wT>7' P8,22+'''eZTM'0|噌9RF=W^^;grqs+[K;#7ܽ{M6m۶/O`RNׯרQ^>.ϼl*U17)߂DԿ*nJy-D0-Ydɒ5V*daJ"55TRD@FFƣG={l2###,* 4CK`WWWq}D0(DŽ͈#MMM)֭+2"&&xԩ_}q甿\<x̙/_D(4h8y,--SRR>ϟ?]hJ`̙3TPtٳy%W9t҉h [hakk37ݻٴi|{M #AwܹRJ Dӧ'Bv.^HC 8ؼy}BVQP(ȰpB9.G Pȋ_*~ϟ?/ǁ!̒_(f͚ae^X/#Æ Pի2?z(BݺuPBFF{UZ5 ci޽5}葆͛/t]f hBwvv.SLRRЕO; ]t)VTڵ[nv(\;o<?wݫWe˦AnݺժU f޹swdkhhlݺUx6mի\:::ZZZ)N:E%> /^.]Tm^ׯ߶m[4Onddw[@#؞={~:zb_ۛ7o ]\\LVb'_777--0rlٲE[[;88M5pԦ,Yﶀym׮]H| jݺuÇ6233Uw[g7=t׮]*.K̄S몲I&͛7G+~WbW=ū2l`%LC???*~/n}b'A !!!'իWuYpaJJ "@ i=`({VSSp rkѢEj9_x^i8y.qppi,--x[4,rΧ1wѡ&&&/ڵ+h=Gd':t TB5/پ};Ң?~;;; թS◆T*U=ѹsgk׮=<--ŅSrժU<%lРEPp?{y4 *ܺu';Ҙ%KFGG||RX`Ppʔ)FFF AG.l~mmȌTyDOO>{zmAj>}7℄z۷oi28,,C>xl2uuumA_zJu26663f_Woߞ&\2u͇Ν;/_&wZXX >D H߾}yoDDJ%/֭۲eK*~U m۶nPLڙLtttOΧ Hݴi?~W }+.cERD7N]]_9s&U 8HoJ8?'N8:: &@ʨBZjϞ=Vmݺ({_.i-'"۵k+O``z۷o+Z[[AAA @x~mA+_>۪U+>zʔ)9HAgBC_3f\++e h˕+$mڴi-RQe˖ȴ+VPnKK#G=zפIU֨Q˗Ȕ-4ZjQ.]̙34۔5khiiQ:88l xϝ;GYZʱYxSIh1PWWdkٲ%'2'4)RҥK\ކӧO666III<si ڵ+U(ۂ70((};vٚSSꊣnܸAE1OCsx5)^X7ʱ2F ӧ> LHHx,/BCC }iAz@.Ԣ%m͚5*lٲ(:zZld4{b7St/^ڵ+$nm(AYR -X*8Fɼy茉166n֬Ydd"m>bL,o ~244D>WRR҅ pgE (&zkhѢ"ExB# %N/_>$$$}`jjWjjj%ƏY_^]]ɓ'(~!ߗ.lZȕL&Zj^zŋSLL̙3غT8p@MMիX=BSL)^8Pfoo-W-õ=<<(~ǏNJj6\rIIIhZ;vSNǞݻw}v9vsn X%^:wlkk`}8`KKK6>^|}}w ,o aHHQ7[7nܪU+/Hĉ ͖S |m@oTTTѢEqIӫTҽ{w 2_ѡja*qSx333ggg%%%7j(,~ \n]VSS3((|xɒ%E ґVj޽{){ f͚SzW\Aq9tqq166EDq&w,utts@勎gϊ-`|1bDkk߾}ڵ ݗƻw磌o۶ AP՝ AAX&;udkkU~.]:%% dOqDPK>|8c(,zxxhkk?y+.(K;-ɡXd*U߿?VYPx;2/^ dسg3f(Q":: \ 7ov߰0===777PSNAb;2@_SQ[vm Jo۶ J(7nP{n@t֭VZX`=z(_|ZZ_PKpk(cZAyzzb*7iҤQFrl4fSSD4d |qa^|=L(8`@UsRF;s100B ;v޽{`(޼ycff6~x@d2KK#F`QPzxxhii=~+%Pxʕ:::!!!XJOO۷/VG %J>}:x޽{Ԯ]Hd={ILL  >"VZ[FDyFDD-ZtX{'O◆rvR`'''++T4|PӦMk׮*$P?Bh%+Wn [nիW% xӽ{rʥc½˗/S1+G[[/H ڬY˳6;S_qޚghl/?pႸ ɓ'r _'|Š-pBg@K2U־}{I᫥u}Կw֬Y/_D>|~ &&&Ꚛ]@o\\ل  ڳg'OhѢe˖-\xT+hkkGDD &իWS'?00 / zRH '~Ҭ5 Hڵk 8pճ_Qǯ_5 H-[8}tr8s)|522ƯҕrјY[r Dwӧ-Z&|򉉉h:1+ /{4Gm#GFf5?'<$HH5CRrҘcw++xz5C+ӃY×\_~M6b~=zΝ;J ٢X|yxx88P4oboov̌ߊ+5?7oLTJ?SL̕O_~{AO;NI_Տ2C&J)#HS9N?'c'RUrӧO+F1:yw-q5߿S--qqq!!!aaaiii9C-Zj/E|}*ǕU4 Mw|P^U1"NN:q>RՃ}>OܫW/⪪4իWy|jj*_퍏ZdϞ={ęS6l MLL8).]Wlx@r)ʁ`hhYy̘1\DFFʳ?s 266ݻw+E/^l2WWWuW_Q|='ΝTFFFNNN{xƍ|"EO͛'ڻݛf‘ʞROGGRFb 9&Md={䳟 Iӣ˗y4tvv\\ܒ>oIg- MU\yԩ&?EWXAk``iLnܸQ~*UL4I;x>]v)S#LYƛaWT(/cefynm)f|1 Q^pA4|pQSUVy)9ŀ+WpzGӜ9s‚ @?___nǎ)ڴiÕnŠ>aaa3gάSNbx-[mllիWfM9sT^F֮]_tc{Q:Ss5M7oNѬ<h 4۷oתUfN/m RxvQfkk?ܹsP "^6mZNě \v~&}͹"={6L_R,W\ݻT<9rϞ=˶)%==/)uT}||rΙhsK09o ɓW>)W\޽y+ m[055* 5ɓ&Mj֬mbeeELE-;vLKK*:B|e{ԿѮ]^ I$pt^xWPwRfM;:::;;ӐwR @gbookϟ?5kM-~=x ԗ奯O+m߻w/dc kU[ju-|iE""y֑b;_d뒑-[Zdɒ_ڵk$3f̠1jTE޾}pKZo?=_ܹszzzMѣo$Qd[h MW`LF+VH*fid'\Ғ%Jܼyf_-۶m \~1 ={&VTAG@E݉۷;;tq$ߠܹ#Ϻ.GW^6l'_g򺸸[楈j]]]!λ^JmNm۰aCK#H{۟{YI4|/|Q?\C9u1^Dk޽[l~T۟)( )),1W/=Q_%O֭[w%?? Jd᳐TCjjMΚ w㯨Uߍ7]frW䯷wο-!!۷t?5/WzӶ?MVVV<_qJp’%Ku]\!J<~;n8Ao[B={4R5222gsg/E,X ӧ} ??ɓ'WW_^*׿Gv__uuu_Q#)4˗uڵkw|8:55k׮ʟkbb֥K UdX "(&LPD q49rԬY׹":uR>j^q +V>PIo1447R;;;L T˱TZDDą Ν;{EwӧOxL&HF޺u#244ɓ'={&Ϻ=yѩShV47oȕn/ȯ.[lԨQ#͛wV[=y_~4{NaFo'n+Wb%h<":o4r bna endstream endobj 41 0 obj << /Type /XObject /Subtype /Image /Width 640 /Height 328 /BitsPerComponent 8 /ColorSpace /DeviceGray /Length 226 /Filter /FlateDecode >> stream x  o7x0t endstream endobj 44 0 obj << /Length 2890 /Filter /FlateDecode >> stream xڵ˒>_#UENI:Uy$>x}k%R ;|}Ej0/oj.ɓ?_~yReU6aRg%Iʌ \7FlEUXV2ze]&GS5GH] 0oqԩ >o6\w;̊\mFBaURdU)4LU:ٲLV'|$i~G:9ݑ2rdQ-) g{U*yoBw ש[I8yaشs&5,y[63Ƹ̊LÍm=9.'9b=bAGea<ڗ+P\.O;ؙ7h:0݉UW|-2sPQ|%YQ]_ˢE+MK̴ډBd7,mLzil7h-ٷNp 'cRGM`Тd[ʌZN?`'4bci;%디e `m Nd:|ib^"5HHHBWH*gywJ _ХG#3D_g_ FٲԻD9S\v&֯(#М ߂R)Rqc6Z g(jf_dDVJ2%[N+*{Q@D*ia^Sz8'ﯯ>^p~PDU Wy2ڿq ‹D+_Y΃P8(!:o ( ?Z<@"VA4%@!_8x -1KGyD!X$uXJ!^,2|^KHalO8@g2kO80IP])nևٍ@p7`(z\#+:o\Szsgm21eap^r?jx5<> c"׿2 P}M1 Q_^6isnxBeRO;5U&qy~F`( YRͤ+{K֢\Xh⹔g+$y=o#Yyh%[2bP!ttiعmeL{lǁ ǞPlR~2Ǒ3- $+U:|+|fvk1A/]q2G2qV1PYZyh`s (-q5 R2¥LZl5n]˜5 vL};b{R@N5 d?9=Z6TohTk\C혗Yu=:{r#i.yNv;0 !X=nȽriU W=hiSͦx[x!ޒ$+Hr(C=/$t7י@ϸJ4M6%(K D: Td,7|"oA:w[|B<`rSۻVܲ*hvq[OXy4g=E\u#@sVEo^ ]pJ 퉶Zt~2vZ~  |׌W^ʔCdoAwQj"t]/F:z~ݙ': $^%oKF*gSMo3h&'/-]ڦsm(X=;\.ʫ,3SS-N$ O6j{Ȃ t4]44Am~5'% 7͌ELx[&B_ @6s[CFMP0^n߹#bi̿w(ZQni)Bк b9<J 3KKMųNzd>Cz7N51z{}&֞ xgt"&#EjGևSN'9*EHUڙŗ&vt.Ss+uc.Xͮ0sSSSZ5 D+&:.}&|JljL W]5/9BnGzLL= VHEVt%t5'4 耠 +?5pR\2)6[bAWt@i S۝/eKJ8 /ִϪpK^ +p(.5V`^EG~ | endstream endobj 49 0 obj << /Length 2658 /Filter /FlateDecode >> stream xڵrH>_֪z-%Xjn%c{|ZQ \UYYYYa.}^'2.3vq.KXtw3zSo)X0It#(#O~F{Ȼ y6tS_yFq ]{H2X/7-X6ͿS6._qr i]T42dRoR{4pSC3bFA:"SM!gx77*dV0 $kQ_\sr$MboFc3 ir=,k3g: j܍0%э>&~66! ,-?_ǃw}xYج!q#C|//1ܡn ȸ"nYIT`Hd{3~*]W+blZωTK^OG/[3Hh^xt_ᗲAU iW߸[vJs2?kʜ~$ ,„X_d1'aB,"fqfkDUHڅKNaeg60Ebrv1#W/Yh/1lS6`ԲYLʭv ]2=X6onWɔ~@9etDJyQē;u& H8OxeǀlVHw-!R6 U,+Q$Y@ZV~Xw-CIKꃜ?'\tsZ Oak)(}ّ<km %V4Fdty|K|JTLQoQv1ߠ8Ig@D5pΔ@^ A^)/m:][{:ϐxQ$Tx\Txx:y?0%Ž~ebe0'!hIŞZ9W״P @\DKƍCf`lv=W81g_x `#0 #06u^#7.ܩ<6˦ o+q}ȯzI CﲸMi'c ?WoyHe$< AQ -B9˜]P1Q+bP-B:Հ6ڠ:Q[Vl[G R_YHph!`6NaSޖi~b,FOc[TB* <ܮ7Z$qZA{)Q(wY״'C8# ͉a0t5͵$H׻<,KzBonx!<:ZP5ӰRHpr'a#|ߪ:yRZ/Lҗivф$C}ܷ@u를'JsnE_X0ݣP|XD/= VgCɶ37Nh EDr-+`٩Ǿi"z,oWz/¨"~rqUY\wƬ6E\e=y (.̷I`0[9,Ƞ &kߵU%"KpoYV .-0U L1b@_YXKraxᾢr-d1ko&ukүκfM]ɾjM+֔1_̘[ɾjLS-My՘T4.teMٚ `=}C@r>Q`>AtpErTUL+5sbY2I `=@XԱ*.I.u[̑o&꧶=7-W(+(WŸ˦sk_R5y%}>m@@H V\EdIRB8-H䈿߆ɐGTbWPHTe(wzInQPP]eJ@ ß6 R]znCxN7()F$P7N>Hi| s~;7Ή-lbdu9sw #d&ة0+(Bkwx< endstream endobj 52 0 obj << /Length 2700 /Filter /FlateDecode >> stream xڅYM -rմWߒd2SU9ds`˴ʹ,uDiz&>x(b w%sc.CiVOFW;S#3HvhOi޻ 73axEs%rhYȀ{kkpqqy;SyNp,TAOEDE|BL˛NXI,k[mw'OҷIQ[t~l3uF~oBp+߫J&%]ڞ6E?&TQW2dMҘ-뺾2 V890^X^ѝW*45J ML7ZëeEbI|Y~u F^W,i 8ݛnDNqf٧heu"lC&^iOY,+wv*qB/4j%&Y,ZN{ ќns~H6`~ VYNǬF.J0š),fc$) $+ }^ /c'4aRU\cKwbUdsa3Ф[| j<ˎh Щtn{WEuCiHŖTBeT5<U9{AcƏVymgiƢYFPi9YEt5B#)cNA$48;0@žГ"Mylpު `ZsYiݐ:r 3i'ˑ@- <3V4|L2CȺڷl fL~)_Y/$N 47~Ӣb['ED1KA5plCJ[heL6Atd-JTrdsXP0JSNU,C]sz$O0CLm~g3VpkA$}W16S%7r SàeXXȳz=YY+➜~w. v'Bt><\ u9Oz 6#\B5B.29Q8"h}询ٜ?`ƒ8]}Q$T<_Ð%B!0 Q 7CTↆs}-d4v(0AB6ÞݩNݢW>cz?S?ǪJUG.(U_~i1HpD#yoj_|nC&(IwMMdHu)RVNzܵRȁPOer}jyp,%ITܫ#DN/NXQy_^ 5(֐L-2PߓP*3)<9?ULf@e)V :IV>derU PwgRm5X[MC=BSs ߺْ^{ '}Oz6 RyEYJcl3 cm,b*kJ'l>* kKt1,G}9*A$REQiV7|%+1%709q@b(. oBV$0; :hKzdg@~X~e"%T~1Rͽ)FiBe)Ҥbc`(gj_&}F/#u'טyVsy 1W瑟lf:FE X1H/F4 "tWGg6_uq-!9PL*"Yxoyg- &k5 I* P>9Zkꅚqj3.J'HN"F>RgpJj>|e'a9Dp=ݍ Tvwx(y+_j9K9屌F/͝|ѓxbGdjnH6a\ )WYQʏ*[Fg_gxm~ u݆> stream xڝ]6~ז!Xn u:I:vfw"89(EQI!w1vwoDQ<$UQ ϊH,6q۱'7I=2FšVQ)_P%%sn6w0B\"{PweG'း"ļZqf*|ب4:G32gwﺦ:P_x~d /k |2F<M/㳱mur>]H(c lXwarp~4_hMwh,a"=;Lw5!wCR$< Lvs<ΨT1yjfM^./eӚ2@~{,RpUZ80K=; 5 WLz"p9[5D:6.f%?"H*c?.˒ҷ-m ȲP31 -x XZd.BrK&4I8ED `k}cǾFgԖjrꍃ9WwgmX΁4F(יq`RJqUӄ{)5|UBҁ/ݜ+kE_ a&, y=G})wUC/@@Ez6 obd9xq5m3[kvrW X-Zx=]M$Lј!B,*έ,,3'$LPfYon"̀\[1 m6 ]![}ytFLN1X ~kiYyD(f/qyoώC"tv:>C8`c$: Qj f tv5i転]*o5.n^kU|_ @Q7N_b mx$:LR vO9:ji[k+q,xu5W'+R$JUB*t-qG=B aکn<_,wkϭJ#3yzY$@7B`(J} њ/NT?k? 1Zy d,")|;k ܧ endstream endobj 53 0 obj << /Type /XObject /Subtype /Image /Width 640 /Height 480 /BitsPerComponent 8 /ColorSpace /DeviceRGB /Length 18738 /Filter/FlateDecode /DecodeParms<> >> stream xy|e?gJ$\-g'rڔr-P( KЦpA\waR}:!eڴiCZ|yzzd0f W\:w\=~ᇔꐐBHlls=7| @׀}ÇуRVVֻwo.} !eeeR";{w?rթjCaaaOy7nhPh4 /fԔʶTٶSS"XYd{NIIqywpQQѥK}Q[n}ƍoܸѭ[7˅,mM&˲aaa um-UԔʶ/rʓ'O;ߞ6mJ3AAA>+00[n,ez=x]۩)iKm;5%mmʦy*(5w~ᇖ}uΝ]v]~===]P'jѣKd2Ynn """zypi @D}B֭[ձcǧzۄS644pO?uyyEB~qƅؖSFFټysBB?޾}{󔍿[PPеk!G_r+tmӦM ߿˯kkkjkk\ޔMӥ.w=C+W\RUUE9y$˲۷?}4k׮ǏgYɓ ˲/^dYvݺu)))׮]}c=j*QRiw۸q#{GT*nGfX^^NyYmiiYpGn#oFZZ˲7nh߾}NNNss#Gڷo=ݻw[ZZ\{1Je)JO8SNK>BQ]]BQ___RR6nةS`^G/CIIŋz}vFgwa},KٻwoFF!>4h̙3rȑ#kWXT*_xKvּ׀С-ܸqC|O۲eϜ93iҤm۶TsrB˲---"p.]pFGG.QV޻wo:~g}Fp?˭srwYd8qbvK'L6g3fMMM%999Z6..NYϟ?Ν3gΜ9sٳUUU2L&|K.W^5k׮3NL6cƌ &pLMM=_.]zg?[---UJRTAo@зxbR裏;wd2ٳg@7ӧO;vYRT*uɒ%<̥K!W^?IСCSS˗m7ұcGaÆƢ؅=裏cc=vќ#G\pWξ蚚O>O?5LݻwԖ= @J*,,h4Çj[nݽ{ܹsr~:""k׮wy!zLIIQTG.++#? h4?F,XP\\>{l\駟uq۷o]ۣAWVVN4[jܹSv_w/'Ng3LE 4LE *!(@P @0`  (@P @0`  (@P @0`  (@P @0`  (@P @0`  (@P^!??v)`={vVVxvƸ&BH``Si "јp]߬#G1n<g`СC{nlldYeJEs̡Xe٩h4ۜeGEH$Q5*((soٳ#F /,,$ h43vy\\!:tH&eeeO>0TJZ{ ݻÓ&M {2.}m,mRpUUոqMf4  Diii6mСC/_n2$( ׯTNƎ˲GyDb !==}ܹ 듒heFO>JY/"l2qgyk׮{2d!jzҥZv|2 #ea!z*}9hb4&Og>zVkdddHY/w}7dȐK.1bǎݻw/++ݻwHHNrrrYYsM&djmt)))YnCjz„ R\vM2dQ ZZZ?xry(>|rIeeFqgR_|w}뭷.]t}͚5RWWV넅}:khSFc@@ߣ Tpܹcwڵk%./UX.;v,0K(?ۍ!7H3ࠠI&q~z}tttMMMhh[DFF>Wфz fv1#IO?Uĉ4v(Nyy4q{guOPPPKKcKt:%ngV,znIII >m֭[ӷȅͦĸ[uvVwE{/^,̙3w.Ma\uVKZm2'x"''~Æ #Gh4澜wٵk%( X:tpsY6n0Ç+++z=0ǎsl|z E+Ulb֭^Phhh#0WX=k.]jɓ/^-<}aÔJesy[\+i @Q^^`x[&qvGòoiTaaa.l/ *vlٲEdTYR*xbXДʲU3`0 !r<00TIJâ"NLT*ϝ;mk `FPk\RR"fMR`7,,p?04&Ԕ7"֬Y%\5 v裏:(a޽}q]#5k֜9sͮjz~Ϟ=?e2YEEEKKKRRA(0Y]]]~~ĉZC+\p90L2EQggN(..\ y !uuuvݻW⒈t!b桇Zb&??g*\1H`0{ ,**޽hTSN}j vwkXR¼eّ#G҉m ۅO>%c֭"w…---?>3?Þ={!g ?IjΝj1`}o߾-t6 0Ov?.gY|stpn)AhwWܹs{l[^+;ۛ߿vD̡CSݻ788S`(..2dAwyzA{OyyJbF&T %"{^^NС/\`^Q~iiiv7T*t_-[lAppvqQgKS_B`+y衇nAAAn*##CV[naݻw߂n=a6bGXyyyvz؝~ۅ FFFV`5ii,Lfcl9<2{ur58>rܶ.dվe]pxBL&S(aaa*۝: >|-\O%%%y|_V_ ôkoyyy;w zBCC> rRTSs_\n|۞ HU*J҅*JLm lMo|]\;@;Sh9M<;1L"ɼt w.yyyvރ]+Un+**K!_>}DѼ5Bhu`0̙ýsnXY|7H&jadϤgG(u6m;8 YFČD"s\r{ݿ~?AϞ9Wo͚5b.s6iwr|v?>wݻw;8mnH;qjb:E2Lt+ylfY6//1qWۖV Qf*`0v(&1&Yj>wr,=~ L|3Сȋ@.[~}VpQlG?[:\fI8{-ƶwF|IF ):t {_t_;;W%47… ] gX6rc* wx2j5DzT^jd&~{Μ9?J3__}eɃ_S`*** ,S67K]^|حgG|I`0ؽ0sLgS-[lڄ9s>>luV}=ݩgӗL&aFO_HP3ꉼ̀;֬YcSiy^;{ѣG{XyEDً~aw!jwzA%$$$&&J܂m~g̘IP Ŵq\.s.<)Am?T|h9r ;`wjS_ ;;zF[nȯZZg_I[ċ8zhl׮e]#|=1=n 5O<ŷ}m o Z_۹qGOmPT%r9sv޿O{|=U3_sӍC%pҬ볳1t4rH~%9Ӱaִh m7ǹr^~etL6gΜUVL/R",0Rh`xcn5ًst mw8a6 yD{P(Dz{ \j*PM PŠ9S]/Dph,?g|X<@:Eb<.[b.;CZ>\{"$`&_(Pb=N"T_f̘a,75+/5<>E| H6ي  (my> ʈ0pZ>-]ͩN@`gjw'F[ڵ+##C/[b w6tPv;Cd;G}&: ^ 3ʅFit8ŋGfnk8l{*(jV+prOݻ-NiLX"󽉞%<=p;Yڨ¦N㩯$/1gS ω? B;kuP(Æ 2_;Ʒ ᏚpuƪieժUNl+15uӲ?*%p1MĕJ.$vNoǾ}Bd^duuS׀zĨQ.&\7_Vc8xҫ&n7F) N\;Rbb$v`KLLqkpٳs-Z'&&:|7=B̐ {fkxꩧ7kY ©mg52e~;c(fqwZ)~O0`Sg=vDwGjm9m 0_+}@߫)SقSm"˅_d?}F: 񠐐.l \|HOs#e:a9k׮v1/@Ivwr1c~@`u}~*0WK+n?YLuJСC3ɖf˄m-wB]mwwb/0ܘ|^*ֶ2{lipx`5dÇK_}wp-7aaaξ$ rk; 2jMaÆٞ㻸+pqz퇍k# TNݯWBfEk],p.ŪCpBNh~~ -'J.槓 fp܊t|7h7#, ^mf͚%}7[ /,E|SΙ3ucx]`7njǏ{gy$y"g=iP!|!rYhh.{W9ciLrJt7^AHѸSZ `ɡibpƫ@e??I8zhMhwS2, s0)]={xGN7ڵtXUȵAVrW^O/BeMriaVؒS-ܝфofk?sK޾z5 %>c#ͺ+V0 G~{lm9R|?ò2[oɓ'O<988Rx5kְ<+|͡CV [rICCC~~>ٳOF>0 z'ƍi7O :uj`DʲÇŬԩ?.;S~EEw]ԏ駟\(CX1kjׯ{ yg^{5:u{.l2!!μa`7vO4jG1b]0aaNœ]]'N\v-kRSrĄs[ZZ\z1%8kҗ;rNQ0۶mCov8))ZnZ຺:g2rcǎIP+'ND-7s|$ॗ^mٲί]qv^*Xc ނVA.:x+Om ͝;W֭9ڵk߿aXeffyf/,0 O9 &xpt0!dȑPwnVR1O>}:ߩV\)0d޽./**^r҄Wԩ˲Z 0[|9Cmytka4Ŭ,f~ Ν{.7nܢEy󒀀(U9s|L&oݽ{vˀk]0LKKdNXߋwߍ]_p\65k2L>xӧm*@k1}tn;0v-[K~L=`ivDNKK;~8713JKKI0L&=d8%::Ν;]ַoߓ'O.8!::k3ׯ_ll,V*gϞEs6)bꚚ CQ*V3Bs ĉ)0\&hIEEE9\޶l2srr)0\v!f5ɺ5r$M`'ݼR``d|qx{r$~lwۦ&,!ݚ^`?h"sss,8 4n-G%5qDS@BN3YfנA!---ӦM:thUU[ K,0zhez)Z%9r$˲z>;;eСJbHt3Lh!!!K._KSieff."u6dȐ۷s(++ݻwHHBrrrYY4N3QFvĉ˗/gfٲeuuujڼNXXXmmsM&dQRRR^nB!V7>h4lS.Bzu圜e˖޺u˼NMMMddݧ,kuD"$"nD׀ڵkw=BH\\h "?v}F%.'NtK `)FoٴiSzz:!d111YYYwٵk׹mgGYr͛7uhѢkBd2Ynn """zyp  ʲեo܏'LE @0`  (@P @0`  (@P @0`  (@P @0`  (@P @×/_/N0`ɓO8!e) %KVZ(J卍}aa\.~ o;vvM:uԩ^+C', /_L^jիo޼3{T~qoݺߊgyp:Gcbb.\πe˖/ 9ਨfz˥sݻMA_* xx͵v}++.mnnn۷ѣu:]߾}U*Umms ꫅ b$xxݺuO?7oj4 &FRNXjzҥK.4m(@P ]߻wo o>{# %+ uwߵZk.oST[ZZM6tЪ˗L&g J9_|jɳ> WرCכ?>;;j6Z/^?#˲ϟW*rܩ<3ׯW%eee{ MNN.++sjPO>d;kN/v?nuuuyfw-d2,tಂÇ[.tsJ $,[lǎ.qʕZz-555v%g@6ax;̌Fclll!ͿV!:_ "g?SSSY:xr|;BBwWWW?^bbb._]RR2iҤ'Oo^.dee999ׯ_OOOw^_WX1hРBJZ~Nվ}{BHNd2YnnnaaaDDīzpк8nٳ_~٣G3gΰ,.٘]4Ar?߾}SNJ"&u: /LaYVקy`q'/ӦMk߾}CCCΝcbb0eV=vXiiieeedddRRL{(q?~ˉÇw֮]{M Jy󚚚!k֬)//_z) 9nvZLLLssΞ=ѥK JpppϜ9ӣGV{޽F J… xwnذ?x`77msBO>e\D }7+ ?❊2<<ݗ LE >ȋwC_xq~nݺkY=rJa\+@~;;GWXpor'aD/hSxπzܹ'|M. >_?x;w]`euVBȼyy ߌ q$Go߿&55u޽ 9>RSS,X0w܌ / 9>za2ʛExȐ!ӟ !/_0 zSLپ}{׮]^z}8p@1ܫW~ĉW\ܹ Q}(۷gϞ1bD```|||aa%RA>˗/=z2++2mڴCVUU-_<==d2IP_ E'$$?"""**JFBHqq糳jҥKZ%( /PHΟ?d2|焐޽{p+$''>d2L&LӥHPlBHAAÇ-TVVj4w)Q8qܹs999QQQ:Zm^!,,sYeYjWK `6a$Q+Ν;wܹz|Mhh[+DFF>Qфzi `Kt:%nÐX=Bv͛ϟ?{}뭷!---ӦM:thUUM&RK/4n8V>#}!jzҥZvHz e.!!RVVֻw䲲2) @Bʝeff,pBBH]]Z6?V[[kd2,toSPPpa%ƝmJ[n  !n2?ZSSi,˚mxlF믿}N:qKFc}}}PP!dOh4aaaz^rt:rIAA,57xcӦM:t{nSS!d111YYYwٵk%( /"lrڵ~M:"rss #""^}KP_ Eh<66oSQP @0`  (@P @0`  (@P @0`  (@P @0`  (@P @0`  (@P @0`  (@P @0`  (@P]L&˲K!eu:x]۩)iKm;5%mmD"}ÇԔʶTٶSS"ye @7ߤT^zY.?{# %( "CBB-ZK/Y.lii6mСC/_n2$( /"ٳgGEEY.,..>|vvZ^tVݿ:a;$$799vwVWWX.h4FRJRPP@ ^vjJReNMI[l۩)dj~zll;uuujoXXXmmj=ƍ:B,]5VJ۩)iKm;5%mmD˵Zm uߚHV\rJ  jÐFc}}=oIII\\HLnii{nSS˲wmll$ <8&&&++Ν;v~zzzR4Ar 4X&.X ""gϞ0i#|  @0` ZA] 5 _'O6/߰aCǎj%Kuuu!!!]tپ};";g…{ffϞ=˝g}֫Wq]rE fc[ުkZQQ1cƌΝ;괴?m嫩_cǎرcppWSo+ݻ׿իWرCܼyvVVVV_____-ܷoV-))tRBBBff&|ɒ%>`UUѣGU*7|Cm߾믿ׯ{g^T/\o߾7oΛ7/%%B5D[m۶͚5ZZZ孺~ƍO>}ŋwޝ|5˷񫯾rJuu}Y|[jJm[oQ-[-0a /ŲlssJ:t|͓IJJ%*yQFq \0LEEtEwUMm6{lu_~r֯V'NdV˚}[} Z] [sƌF[RVV|…/Z.ow+wҥcǎ֭ې!Coβ,!ğjZTTt}uԉjYSo1cڷo?`I&%$$}[mkJ$Ȼ.;v0`@CC֭[ǎ'$$IJaaa:B[}*XWWgywUQFvĉ˗/gfٲe~SK.-_/L&#~Zԏ>d2} }[mkJmy%##رw}fYӚBHhh(w[nEDDpU*R˩ ھﭨ ի˗srr-[JZM]6f̘իWϚ5[omMmm߾}׮]omM龭w-dr޽{RnyIIITTThhhU*[}*hoܸJ+ޮ];VUU͝;w~ڭ%z[-,{yo%sM-Qx[ݹ,>{;wj4~vrԩ/ƍ/_~駵ZdbY6''sΧNvڀ/^odyjo߾r_wmӦMʭk׮/o+_Mm?裫W^vmÆ Jٳ?|5z,{aÆ).?hƎ{ CYYY۷WT-2O9sfpppNQ*sRRR,>snSwf oo߾rٳgرZS=z??f޸q#)) 2Vs`;wn|+w}80@?] :::11X4AܹwݢET*UlllIIN:u>^UU5s̎;FEEmٲvaȑ2&dggwEӧ[j0-@hze˖RGSLIOO7?,YHyG:w|…G޽V[(--۷/wIIΝ;Om΀Z ZgEFFTSN9s̙3ϟϬILLӧODDo޼iN߾}{_Bn߾OGDDtΝ;/!>a"_ǎ_~G׭[׾}իWK\*M (@PIOu endstream endobj 54 0 obj << /Type /XObject /Subtype /Image /Width 640 /Height 480 /BitsPerComponent 8 /ColorSpace /DeviceRGB /Length 35428 /Filter/FlateDecode /DecodeParms<> >> stream x{|?Kv7W "h(UX(PjEZբ#7},Ԋ5V\"T% ^%P @BIqs33;|dv̙3s窛Y|^7# @ <0x` 2!'M 6 Oƍ=lذM6e%AȄ~ךs9\r%O>}ر馛MVWW@G@d1?SOO ;L8믿F 2g͚d?0`iv8p 9r׮]l x?7{g~_744?׳?yG-ZM,(((((HkS=)Qt'պv'պv'դ[WWIWX1qDǷ˜~e9rchѢC|A4d㺺:4nH>Ou>Ou>OI;_}m;]+O;tD"5M۹sɓ_egg|{X;=4x <^pI'TPP0hР~[Ӵd2SOիל9s5M⋛wލo?yտ:MwyC YjN;&Ç9sfϞ=qo&嗚&L(,,>|믿N8ѣG~sԨQ#Fp|4bvl&M4qD[^?nw\P(Ľ5\h"ﶶaÆu][lE7¨߱FӴ WȓO>y9瘦yС={Zu={ǎkoow֙UUUPtP0 gW^<{O<<}ע;wz6O=ԢENmł`ss3>=e7Ls=wڵdYjU޽*5\m۶={=zt…HG/'|>p'tI'} {۷;jq|+bժUV2e ׯ__|꼼P( 󫫫]^0믿> ]ve~i]]s=7_G[hz 7߿_Ӵ/W^4NH&}{^z% ~miiyWZtRZZ /=ǧk֬y饗N9T]9M6?ݻ>lٲZ[nG}=zw߭iZ<O~2qܳ>{׮]E"3(((ȋ̞={ǎeeeYYY/oݫWYf=cgu;=p޽SNEGz}ɒ%{>ߵBXj1l(S<0x` @ <0x` @ <0x` @ <0x` @ <0x` @ <0x` 2$w1a„p8ܧO'|Oƍ=lذM6e%Ȅ>xy7}D"iӦѣGk>}c|_~o x \&M4i$ƍ] L쀋u]'9tD"ԄܹsСh t2!UVUWW755?~|AAgٿʣG.]ӦM@c# yWQQ1eʔ'+W4⋳gѣuf1;CSIIix{(@ <0x` @ <0x` @ <0x` @ ~z[@7uĨQZZZ4M EEE^7 `;2jԨz#F>|&40 }1͠ À+H nǠApvv)Sj@cԨQi^]]a{螀8 ~^n `{`: o* F, 0  dϓ`TWW1YӴl0 ;=ażn*'(**:|u]/^V$_@t% ]Ϸ(8auV:i>E@tޭduuu^^^( B@TНDβD>P/XxNL' !}xN;t1:]%܉4w 2t6NidiN*-h\__?b[t_`܉k; H ' 4Ψc߀tgrmR7=t(`Ykyo}:o)]ozݐH^^Vj_WWa{: o@: ;1w^W@Gp'{[j 7!n0$`ϭiڱc  t]"[ZZ Ʉ~衇t;v|ɸq㲳 iӦ T`aСj:ѣ5Mkoo>}رc-8 zހD7)'ǎӎ1I7DkaD`MӴC&p8iΝ;'O̞_PP3N Mx^t=eȑdr\4iҤI#7nt)3'ÇMiڙgٿʣG.]8е :/K,|c2!7o<~^z͙3뮻;4M|/Mz?qݺuh 9yyy@ gp B' :)7t{"Ȅ G}GC ٺukt(Z[[ަ= 膖K=ap*D^u2(Ld21b'͈b?u:D` e@SSssssssf&@F9!gD"//K.>}z^^޽{3uy3ڹk<!Qt]g2 .醁B!T(իM!w'l())1M :5>ug l%\Bͤk֬VDVvXD^^tM2S%v߯{*h AE X>vtL=;(d (AP`r ,\-}#f=;(d(!a?p7ʨc@4رchbbO\s|,>WӴX,L&#d 7d;n*y嗑D4]_y啌ݚ<'xbJ:miiAO`0؉: 32Q/KvZ9M w>" ./0MӜNG74%70 *giC=4{Ce֝nz1ctPdvIw4%7~oiiDKi֚zu#GrssL6Cu͚5/R]])u:ݡӸƔ*7XDZwU<\M?CBȢU~!:/(>t)y2>e:r_Uu.w.'x"MPekЇ.-|􎴭-]sŢ(u71O ]@a䉣Jk%52ɩ`u5i~!q'O1@ǡ;OU:ݳ֒%K$ɚw.}^H]Siڮ]qM0UtP`t:Z\_ /DqqqkkK S4N-X@@0HfnIYuDZaʲ2~M$ Kt,}ar]Vb1VW;=JRLu,粞Ou~~W_[_4=K(GQ.,,x힊Dp܈^]]=bUhe555DYx\uMMM˦jZߟYW˗sSH}erチ'KT$څL)++4hPEEE]tGqq16٥6lpWVVav$Vzeee6lXp!{|ѢE\sMZ]Vu.$E-+W>ﭷL3: HiiGM&d2&0~z(4xee?7u)tM̵.!n6!Snli&LH\CV\x J\IM6l|ֈ\3&O5UкI@\$:77!Rv.ζ6jEk^+N:=dРA۽\&!2bmmmd2yiGȍiǏ'5;6&M8qRo߾TKP~w|jkk ʫroFMMMnn.jFnnnmmkv= Ø1chKM;x\.5t],H@ 6#wdOB*חW` mmm.5i]:wY칫m&GdYѰ_ÍsT_Ro4ȒtG0 M8D"Ux} Uru5^qCZO7rzH x,5L{Dq!O&P HgYdbH$BFn}0د:$MQiӦiu ג 6Q+ذ nfD"=h n@ P]]HTԔ"W]Vs(D+NJfp)Ǚrz.Ǐ_LELji|md'r$𪫮R;;hRjwb@}T”)4mݺurRTTT__oFeeXˑ#G|A[-W `Mz!H͛Gv25GH_ V'\?ڻ nu6>lNXv9NQTT$Qj2VP8NŅP(&w}W'|RFXlf:|0wq)WDwYH$nfx=^b*bnHt,*X{AT$0t[nu8)v x!qajQ0 !^s97x#Kji톮C4:)6xR=(vpҎ*x()믿D)ņ B2~]m%0a|Up`]2Wӫ{@;<묳C;tY70EQ*775@nkQrTQiӦsέ(//2eJ=NIT#O?4~ih8'-nQ'`Xc pf~?r_|9zeiu*0Р\m3a w7pܹsyjq7oڴ)R wv[۷3&.r,YBW@!L|D2P\ޥbcyuvh1H$ ;Yqs`9o2aM>5}rG5nC(b2j&zMGu]GjsLҿV3jVRRbRH `Md"e3Nӕl4U o2<!+++UPSSCߎFlG'x 2ǖ-[soh=]2 7w-[Pjy[4hɌ/ Ǹ#b1jYZ-믾ݛ~'+e$h|ǏooogeiCUFz衇~nW1W)RPP$u0U2!ڴٱqW9A i5hoo饗P^zn-O裏⁝޲"SNիSO=emFF#Veeeqޕ`ྣ, ==i w*vٲe\Ej(bg[E ܁V~ip^SS#RJ+qX5Z\^tsΕl3/kvuס#๏"0(Gcǎ9kg,s0)4~7Av7*r%eߔ w (kkk+2pΝ;UPDlv=EZ[[g̘ $~5g,SRFy7p\,SM$R 阁`0FcSSO<z6Xf /0\J\so\zg?1tF8#[ D.cƶ@ P^^.ۗѣTӴh4I@nAEGhvi0 I8k%W]L:WA͟?vܹsT1HjjI4?EXSSC^=M$U8*pW˗+p-YYYަpщ"yaR'1*h#&^m{߳gϴiR&󰙢,AmYS|曤S֭[qH$"!C(mi5 9~̷zK?xVVVvvQPnǦ2<+ɗ555\yƞy}qlg*S-<&Myvڬd*ɡEeZ<wg җ~3fv*|&;f} oA~!lݔAA0ȗq 2r)+eeeԙ+VsDy[nG\ %x&lŪD"7 = .^ljVV $:NX_}Ձ۷oɒ%1d'44M5M۰a[ZZ\Cd+d8qTXCKSS7#hH$=\_/|+pKWS\E$OUVV&KL&m)b1jL&v&_~I)۷oRr'9rdܟ <D>\ǏOkJJJ~f{ѣnsQ?k׮e@S67zvUʍ\"(..3": e'//o„ ׿|D@ sRSAnZ]Z<"}څmLUrW.ځ1BV7?0>,ykHꊸ1İ{p8}4H|%]yF XUU%MI9p/ p.уx|ƌ}RRKn8`+ި3(,UQ"ј>yЭ?EsuUUUiidv7ID?.z1y,\]c(\ͅ٦ .$\$_*9ܪbIӖsDd7F=ˬm*O^JV΅$Kވ^$k)?X~DG3ΫZ7'dE4wjH= 䳭r_xYY{5%mkkSWq(Y%H$lʕxQI\sF.k*"a4+@O9ɳ%5f*&ELH򗿴lv|#onިQPxi5Ѥܼcn3K$緵_}&!К,:öa.H4ƍ_Kvv˄ {ӧOYYO?iӦ{oӦMK,9sf>},Xf߭nhu\RqcYH_S֪DJZVS'oXIe' 1DZXvCuT8$}4r]ϺWTT:0f 0QR*~\pq(2/T2Ju]' :䰝Tl{ͳH)1OF DӐ~א,=#̓0Ç??뗓s'b?O~[*&DZeE>waO.يPa2&R{ E<g9/f7JR'*SXޝBd5MD"'r}g~\m!f„ g[BLzG;"//ҽ+&7-`8k[UU`_&dʒEFQ6/aH ͷN~kCqe4~rTssJ}ْK)X2 qnyGYtD Z_|98DMM WTZR/I"AE\$gۮzX2<P(n\jr|9X^^n5TP& 5-8[JZFWXwY',ĦM#OYJƎka7G6t+⮻?]b!.oEI8V]YYYgu[OܩbJd2cvw_K/Ğ㰹I=Ɔ"M)Vl^QQt3MjT$Fw.;rHHnučqy9!cwTav|?a?<ްa[re[[uZ4ٟ)StM4W i`jkkV]8/זJFr~ĥVZf'rI%GL&Sm)fҮ衇&Lvϛ7z]UUU@B^xqJJJ6 ck[|eE}%[D{ɛX~?)AJ-OP1.{ﶼBӐ58H_($ Rpg=u4-''GihTZ&T;9؇蒴'$zFWQ^^W轋"ٳvi(D}̞=0 %U;`k|ꩧRGzb a,mۖЀ;x`؎aJS-QEpG=wBF qrHQ4aK2;՞b_ s~lo%+0ϣ(4իWs[\\L?cXeqۏ\I) QL8sL $8BJ4JӴ+VkST@tG Un Qm%čd .]J~(Dǵ}Νm[\؋"]tO-[ƞ^qz;oާO?I'd6_~>}v,-[6|p|W\qwpg pP 摠b^WZZV3)i,i9p7'8mYyReiEWh9~G55y2l0'ĿpC)w3*Y(kɢ0 \\4dRbբ4]؁G8j+- 6"[P|OEg[=:Sp5R_-4M=L>S훕8=z_W[xP)yqs믿hO?ma,h ){nuWHeee˖E"nx\+HH m!ԎCBq)T]}´iKQF1䋖iayJ~[t)^xAI9X^{e_d w:>,RKT-#F ֒n"DhVKU656*..fb_JطƳ8pOIII</**rYz_ O;;w*;`y 1nFvjbEͶᇂkꐇEHf[IJwu\\~htӦMB*+wɊDbPLtek!}w 7^bDٵ$P(4 K)XPקc˩픭lݺUq-0 jfw*ܣ׾kP\OIWՍ)V1iGN9sETT&D)..f=\8 aHȓw޽{ٳi{޶m۶mѣGiC ڀ{ !WBQgeA㾗%|SVVVYYy"I)*u-(w~'lZ pgag[:W2bȐ!Ꝡi̙3JCݸWuJ'7 \0;U,^X42H@@9w{A-GQ#]mmJɗ(-9It! LX5\s}W^yE_W_/QO?׿ucc%K v7ʕxrP*ڳ:S#,-c4NeW#?TO^Ru]X=&W6L74C] 1 h%YWqߝQ\Q ˗/g/.r Nq͝WZZSnL%A\Mu?AdDS(.r\P7Vqޝ*6E~9[p<y=Hi}я~P(toܸ-*V"|␤VDV\F:ılQO!jgᒕNH̞;x($ٷƈ{ɷ('ap'AޕLl2Ir."%m$q}!gGxĮ9??_w: ; P@HQRc7e)̓KX~=I~~+43# 41&M`4gާ@r\Ξ=[WV9Au-vEesΥz}j*z =4M,.gZ%8r,pxVrpc~Dp;nXjq M:.nU0(nr,*BN =7(̌ݻwccy\766-m1iҤu!..%'xt2?Ho*CW!BFqdJ!Ghg'")!h?[^s1{h<EW$HyЀO↥Ν;|*&_Wtw< rss}>;%Vyy_IWfu 򎕫i̛7O1c0LDe"3!y%򗿼ꪫ&M޴u?#CzaE6^%ߛ\u1.rC)lR ,3bNrc_E$DHv )|~FV)E`JTФpyAb@ iE;N| y_)jǃe'z5"O$6" FlEH0d^2 ?ٳgϽ{g͋/v<ΠUrF7Ք&5 ʚ\g̘pcjbN u5Q `0].ҷ뢻T1b PO<_njb17W TFdZf 'j/Ȉ#`p۶m"<#Psj6;J$dggw- ,gF"ILd2ڃG,!:/ƛa*Y+ q"0 +0JJJf̘ATy 7h yQrvH;|4??_3 /10!ھB]HVVBug3r]6Ι3b 63GI77V6|aK1iZaa!d;㫬?TH4mm E_[~JbIE8ю[Q0mHM~?)(5|>F$όDjjjwpq苳t{zǹ|0%?E<4#$~ƌ<0ѨO2~woCnrnP `}7|S>W7}lE2qPDaiu&eY$ŤJ|,xGA6XK㦸7 m'uHTu]Ҩ%YS24X|ȳWn#G!OVkݧIOmiAF4'Ŵ_R'"OAC}+2!O;={yWbӧ- X47I9dIϙ׏cz!zH$*U\GaÆUVqOR@͔ofUL~ʕ*Iz!D?q\ҏF޴iOwjkQuD6bf:z m~iNQ#y/YR'`"M***}뺥z5P傢5~ĈtEڪʕ+mۆ%rOb1".s饗:8SzSOm6m!cs wfi#?rcR+c$"P,6+e@]$IE"BӨV0X*~¯L qSWqR$bThRr[~*՜8/Wd5M y"Qmp BѾM#VUUJf.Ɍ" |VR"Ypa'b_.\UΗ4z [[hj/dTx-uMMM8Q4c")]~dZijkN [ztäй[68;NF+YP: (//wvy|hQ;+K㱨#bY ?~u]x nF/r&JTF=D*B4T1F( ˼)48VjlAY ٵ7P(Rdj!CLNNW'oRܶSZ0]K%23UEVަB8+_$>19B_̟?,\t(w1*:A$$22E0z~ٕZTHHd7//O$|vpW}ar"܏T7DyX-WXi) ƈTw" d6y:y7rW -xdp@)M^ nn6[KSzg,g5(B? #UZ2Y\Tp߾}ngqDtK * bn%'Rw*=:6bHE]DMܥ;ASYB&>[<7s3&m"ƽ e!eG,׶~I>3J7p|XW! 7o $™v#頾^WjrO-/4A[%exbvcڷoJ%ySQh%1NKNcY#{hѢ^Cjcfkk-[Ygŕ=z+ sc '?=5jϞ=(:+++??>bOߚYVVFpp iKDw1MSӴʩcru]29k›BrbTZZZ{9%K@lKX/6|kk+#erFnnnuuu,wӱga 2- @$bԙ>oӦMT $~gϞO3t0~o -UܤrI$+N N]a(h؜;9//OhSV1v!X>x~~>w+7 "wvઑIݢ~_d?sAAZ[,n?ME̴ҍv5RG$,ʢfƌ8_#٥D!&,ED1 P=H I)%l SG(;o޼K.$OcȤ xĉ.+Q1tE>;&9 f$sA)vA H&_&~iDU5дi0nCqT^ԳR^AAPv"QfFQ:"DL! ͜9Sc S ŕKǽdAYu+wf9| ti5pG.MTW_}㫻 `򖍯PLGWJhRjS<>UYLY8`76ueJ冥.HaCBqrMƫ1 7u[zhp}(hS:q틒E;"Z&l`H\["uH3)|>z#M-2 <j󠼼{MM0k6dE"O"T %IQ-G܄7C$a$Μ +DѪ%/f+EN#e|8J!ArH gZEcCPha9ˈ*{&ۼyL˼ \[=I)3^ܓ岉CRD2ɱb> f' T%{qW]u߾c7s\_Mr>|ITvTP\V9(c`W&2-Dpg4g{&r!W=Y|ZFZIJ)X}n5OTUUq᮱"QZ|q~kh(:-jIK Yklnn9H}sBa{AnS9"hJ6幹;J޸QXə={o9svsK[W^M>6V)WJs9䭲`ۃұ^|E,`4˒h4vdKAfgSq *++E&åK*rXUJ2VpݣP_MMM0DY("Ul8ng%vVd]t2e&w]Vز*3K> 83 ٫؅Dq>:xСugqYYg ,T)iWұ N4U?QK%܊hoˀ4dџB-Xd -/Eo8FhBʌoW{FFԖS1IoʳPJQE\Uơ(uٚ0*M8 PnnV{|aM_͍lK}KA2*$;}ʀ8Z655&IuVJ`0,taXJ=e6]P \Wh(p2T2s 0*++I'SCW*l}B""*W]X&_<w6B&[qh {qӅҏF(GR+XRɺ"QCb%l˭!uKI,v,F*E,}Q V 0 wЇ*Ou1cVMZ[[ߍ5J3K/}J#Gljjbu]Eoܸ;-X!/֦zQQÇ׬YK/՝r)/i/Ec-hb p[x)@^ZF^}dh4Jرcp8 eg6o׮]n:ܙbϟ/?㬞6 j1M_&1O:9G/hnnnjj˲C3n8no^\[h*-b…T<(9eƌGGD"H67o2a~'Ź׹ꪫ f3** Uu-n+WejN4hX蚚N;pذa=zl$Giں}kn۶-L]Tk ZD[/*:I(?aMqGyXwm@f0VkĚp#&ps,]VT"IX)meE%olabsG-yNxPVU"kW\elVVֲe;t~?WU.ZJ ^`3]בGWOX4]}@>/wK φt ː't+Գ 믋 mQJe=a- +|//G%dH^r_)TlY CY-/b+ϝ;ۊeeev}.L2#Vq"r*ot]Gc#۪P.J O"Tvʺ q_<#w<>2@-LZhYe`FA: }ʒ_qb%LH#x&Us9|Z̮m#ra=lUr~ZjXب#h M"UUV~vKCN˖-SѐEjuaTw ^ȅ@W4IY@`4͚˹ƒIs0".bi؟q,rG%5";raTի{@% 9URv&7hTvJp#3uTpBRqEacyU2L&%ʊP:Τ߯[.5FNNJr\R+r72IHlb4.K55p,2"8r/:9E;IT(++-L产">?t]g'H$ZdSSf}hR^zlX,&l^4ݻw/vdE'C;ES^sskc.袼{kZx---?q'{d2)4?){4Ͷo3f {PES%Uh}'-ǒL&ǹأDћ2On`YΒ(L&b1Ѽ'mi %}^G)>ݻw٘D"hnn>tbc\Fzg%F<|% C dg7\k7,p@h[}*06#CI$`mA8R̫*6w!wdw߭(QGR)E^ =+5b]`|S˰~zntl/UUUr| ͈;TIBQ6 (wpp]$d^QQJF6vÞ!Kc묅*}THỳZYT.(u|R$}(7Ī6=lK93JVpMRHVB ZF4]pÇN˓/ܴ{2P׮]mҐc=9={0++kʔ)'Nd=rDclLD"ձXL}ͮM7ݤ*V ܄U]ԩSQj[o?qǘD"!o?bԨQKiSsnvvv{{X;KK;Lؽ{#[5X)S$K.d餵f)$777''yi,scDzlĮ]Hݻw4 6KI>a$H$rSOzss3u4MI&o{)gT `%U,?SҞO?{K.1W6(rJ||ƒO<=x=h. yV;c\hw'RR6^-hM\lp8V&L $-d*ZQSs~~>Fdrʔ)EEE{ ȉ *]W. |Taرtl6> s21a~"JݻwΝA9R__ϦECrrY`{o,q;Ўf[n7yr(@`?ewH$ $w~PrQFw2nq}*{|j ì#얜 ZFu&ʤOcVdKܹs%&"[o(|=Nu&WEL+F`nYCaõ_ [|J(?[Y %&[DBBj!y\XP(,+ :죡PQ A lH̵@Y`6M02KG-PvZq\r>\VboȻtժUAp~ɒ%`0Obd0ݻw#pC1%3W5Lp/.H ~a*}Mmg̘&YR.[DWFUM Ο1cċ[vTja72Ոt2ٵisM MU4ZW ؓsUs Aed֟ Es,Upr{ 7VL,)>LԃJ PA"7C>hr"x|GIϳEubP? >µ~գT)'LʓV $u[\˞)JL cy| 7ݣF,n$hA p#e^@ r Q QȲ]QY_RGʣ]e-7 PA"DvLL( GFSw(ƌ#MgH(B]l٢FNyV766@I@?(ۧr^{=MR'u֬Y? =zTkk8GؚԼ"RK4.Cb àTX2/X{{ʽ1{ՉCJy%Qj:Zb@BFrNrYgQ$:Kx@A9/??XICU Φya$5I iԔ:̽#-5HLӬ[r;:,#F4Cib@]I(l{1gnFn4F>:MӬU4m׮]la/*iXLӴX,MY>#2N tMVް~4 R^~crRC= ܄)ȧKa$aĨQл@eꢢ"?a|he7 *`- kd]j%& W-vc3ȣ@,D~T܎hDD JOQ6G*_Ҏ+3r6.]};W*xiGE=#XnS&C?-,uƍb\1Pmw`*l^Lӆ- HF]k\d\^SSk<]|_`KK .e1`nzoD+j"Hcc;k(Rގʗm&kZ&{֛oɌ Bo_644(F%^#hu!C>H0(I2tB}6HK'II*KTr=n8Ijp#3@v8Y_{z1Ů)ryHh[oYfȒx2ncҫvc@%5\+rAϙ3k[[?˚v{}QΘ1nSyX)/q6x[60`yve;Bʵ#*EEEogqFrԋy0:8o[CC8'd˕L&M^Vf {./(i*24rDamdD,$%pHd,4-4BP/,WO>*W[?I"mhʞF|֭)m!ڀٳ&ٱ7hH䎐سˎ;XeRrAw0BaXeRB$U ZsI["TϑM%Z}wL8Atc6Fx<^^^kk*f0XKL6 VWmU,{egdF̦ %KRKw!i:_fq!cu]Sxq lzpQ[_ω1Ί4)8D*䑝a,_YSVH jL)Qr{Mmuۅz#uQY)UWzOl1 ¦yԸ[љhS"7g:lTk: r$f7VH@paq}3B#$B]oq`M" ^PyiG]o6`m[?l[]w-2K8r)**jlltWWWB!߯j{+$Qk~ XkGeӭ$`"Yx1ۘ7ɘMȑ#+V$N'ܗ+/51yr>qU' M;`nTDU[=r̽{Dmm-*qJ7 )[lNfQv=X }ogӡ-gʷ/QWx0Q`UUU)HQ#Sb\fEոB18.RIUwQM@BB|vӣE Yw|_O_ B~^49(-1X<zOC Q\\dɒ!?Q3rg j2p7g~GuF SBx^;666ےYtkn@܉l&:iՉekP#` ԩS%%% ,hnnV׳Ül8UAAo5*fyL0Liiih g=츁SA:J_&L:\_H8 rJw&:|PWW L!L\Z6cH曌O  0 ä!0!s8೜ORL<[sw}7pdjllzҥ>g{Vc.K~Fvv;>w Œž111w(w. 4MKg Z|vFEEUVVs"4Gcz^Ȝ)/C>``V/B%>j%! 1^n"yUŧۖT#c!.h=-di |܇/z*_~ȌOߗ}lsEOOOzr{*؝/g/wK\ܹNW/LgV.tVWW{N򷫱gڃ!##Cӊ.h ,--[``vܹj*G_toNn$/B>:VSS g+***6lrZm]]n^79BAdQӧ\e˖4o>)O?9G^ggs=_*YVyqߖ?@tPG6D`Za0<*F”gtȹ 8jH,oYiV,C8 M*Bp<žbY'رesZ1 N>yH w^!lE.aK8q#=;Y0cpկ~u 6;w.Wmy,aOتWwoɽI*E޻wozz^OLL|:::򆆆iӦdffVWWKP`E}$r:fL~&ɽB^F3W`N`=Ll5>Sl6ۢEnu:¡]%oF͕f`{lQwBh؟%:B.yX,VW^}WKOO/**jkk0<>]+YUۮ]a3*dA -XڣoYWt766zv{7U > cLǛ4M+p;ŋ'?a111i̘1{>X\;ڵk>-[6v61ϯT͠ 9ß>% Oਿ?! p7e@8ބ!Sxxhɓ'WXaۣ;FQjMKKsl}n^fKPm9aW*--]x񗣑+ cSs嬬,6w;g`4M{.ܢ(;@Bqqq]j= !?Vy`ht:.y̪3gx477f!O-Q5kŋ^zdr!>>;bb)xJs/ ^R婧k:&3BY(JǏϚ5)L&uJ}mlww{ y<ɍD`$9|̙3ٽ{ .ܸq#A5NGJtE*SZZʽgV <KxY\p, [0LSSEQ6+6##Cʨ͐!C.hW! ,@Fg1naམ㓊2(̞gǎ^%3} 'wBɇ]3fHNNnhh(..={6EQ'O>|xiioq;wJP5+**1 q>;C4)yauAumGwejwwwVV{cPJJJt^A.ŪF8Δҫ:tPV+<|-:uNKOOXtA_g/&Bv+D_pX>C;2X>3\b,~斏;V1EN#;/eo{bb1)=B8Oرcq4MsGhMQڵkWX!RQ7x6N8NޞE2!@'BZg kDj2AA+͛7}^9a{{{ vB*bX a(|fiׯ4M yBa?`IMM#|?1&X.I׷ѣ_B;Og}y-(J yu!x OVD`/ez'O \8'W*3[^^}-[}Ꞟq 9&EXEZZZJ%( t I6>6աWSS'3(|fW\=M6=0a`pVB%$"gTx{k__Mz|f+++5K`BJ5"<% X-S!T Q:ܓ]7{b`o%<M^+].c:uJѸil6p4Mk4޿@\;lNQCJ܂(U.˭NSȗX^^gz{{Eٵ'\y,iT}%=euӂ8Z3 ;q|yW_II wyG z kx"DO"u _0QV\镴2q>?r }{<5B1`)kʰQ0R(4vmttWytt,޴Jk؝EϾiӦX\\MBzȳD9rRQL&{Q)EQRNS/[ssWʐ/}D<fM0WH%QssY&I\բ@:i UVhè/mDx _>/٤IN2D%:`:దbuDx@ho,⫪$SvYE7.%1)`n#u7g>H)/l܉# HJd=-]*5{Yz^ݤȾi*++])sQiNM"ᴣG:5G_eħ>{=wA^=u6H|fxh4Rpﻚ WF"UX= Y R~vv+wOX,^ LIHdhYԔή9kRTTTXB +$Uc|Rd_|vzCGxx0F#'@wTS544z 0DC81bDSSX1X<J&T_26;0LFFhRiy0 @bzn(J˃ DKNjzchAuH ^%a\ jC,EZ:γD eI0-0Ր T(L,I,hP\b)-(OAZ >a)-(R~YJ H=WXJ _FJ 2~Y"z)3 2Y <(,{ ґ/!A´w P6{wwwwVVV[[* -L?{k@eg`ha٫_Ju+LIՐ @I"W~*4/!haH!Yf1 s2L&xu!gcܗ4M@ "$ )iy}? cH W $,:TGK@^A@4 ?`P/'YC4  @0H'Nh0RRR6oN0mڴj j!---oVSSӾ}~ٳ(5)Sܽ{wݺuؐCe˖gy&11駟^`s(ijj*++3L/Rbb⧟~*Ae"c Ü;wnEYִ4ޔmZ A,..f_(pL&M܇v^ZZY8s̜pUUUuϒf,wy磏>(*..Ç[ڒ}>a-wIX (H:))-Ȱl]]]E>i 5s̙3gzTUU Rܹ7|xժU 9rѣG/Ae@vl6ۤIzzz(j%55t"l6cǎo$ڤIV @8VYY^uww/"M< "ZAAV,'U CX,&ItxBF"4@RSSN8A4}@1A HW@L `@ `@ `@ `@ `@ `@ `@ `@ `@ `@ `@ `@ `HW1v;0k!*afΜI"aRjjzZJi)%yc#ș3gTFWOK)55V=-X @_QFy744L6-&&&33ZD)`Xz-[< ].Lruv * .]YXSSTVVf2^zO?TDbVkZZ``ζZܻ=zuចfl6KQKi577SUUUE"aRjjzZJi)vݫΝ;cǎt0L۹w/uV (rjlVjӼRjjzZJl,<11qBX{߶d6lذa  bː222l6[WWommmFFHLr=zt:yQOOEQ'O>|xiiigg~xΝB * 肮5kwllO>YSSh>jժ9ѣ2V:@DA*J@ `dklG?| &iڵN-t8K,1 .//'Tiii4M߿߳<~gF}gnݺ%ix;vjjjrYڵk .4hd={˗7)k"OkWWW^^^BB^8q'7)k)D ҕ*>>jvuuuuuJLLy㋋k>wꫯF_~I>}zܸqsׯ:t˗/! |t//Ŗ˺|֭[o߾f͚aÆRiRE֞onjmm=tPLLLkk+ꯥdOk81cٳhDUi&0 k4O:ŖYfUT,ϰTz3fnݢiڵkU=H^-ݾ}ҥKSu-Fѧߖ*^xQ2J?-%{Z# 箅ώ9r…6-Zׯ_w87nhoo,oj }nM4m)箅d{&$$;wnٞ-mkk(*..-Ç `ˍF#Z T]F '?Fw))'Tx;v[T=:bN7gΜ7oh>[nݺDV;bĈ^βn}~_pIa_KyZ/]`0LS033sر7nloow\ϟO~~wv]b}}_k4Fctt4{|  @FrssGi>rHkkѣ bŊxg̘1iiiO(c 2dHggM(jmmpOSrH믿.))/|8HZ(0 `?;ɚ endstream endobj 60 0 obj << /Length 2236 /Filter /FlateDecode >> stream xڽ]۶~ 7t'$:7Ig~IЉ=/bAQv?}!o.O['B3LwP9%8&IM|V|+yJ[yeRЦiܬ 黲% dr&&Ykۢ[Z_ա"ȅzꮉM| [ETAmS/DLn7o VV\3gZ(si2"-p2Y_w}{<W"Vaow gxD#fRX4JVum\KZ\6Z^.#7rQI(%ҘDz:B @PEnE\ t}mh|Z'ӟ|xDڷhߗ=#O`zw:0x4 j4566n3zEӰiSc )B2Ct5 eR! d)t;=b(wLh3>K`Y8@LF X;!FR8LbJdv T6ꉄ뎇8At٠Ha1pGnwAA4_p;1ZOL̎ۂ4w'Hǣ!C3q[b<unUvT] qr|Xfʺ|bH%AU`_Ȱ,]q!UjˢDȯhPE4.`"Xtdr%H, aS~ A: 5 b\b栘Ϫ|}yd0:^I3LR1,j\ Ii/PPԋHrpX/j_4/ܘE!"=̻PVEK[B/-:Oۅ\XT]~/!?|-Aۧ!T[ߞ˅^K>E3,~ ;h endstream endobj 79 0 obj << /Length1 1614 /Length2 10159 /Length3 0 /Length 11205 /Filter /FlateDecode >> stream xڍP- A0[ $;A\9vϽ_^M7{w՛\UI $abcfH(벱XY9YYّ5m H #,$ E& *99l6n~6~VV;++߆N`~$ wr"QK89{m!/y>hl||<@`s#@ 9d44m@ A+h 8xxx0\Vt5@ ,[(@ƌD дqSd A9dh)TA+ik86f;@ss'gPVdxB@G߆@{W;hbG@_m!̮6{deRN G+$m {uvN>#KG mX9h9ڸ$y!GfXYYyy ܚwM/gJ|/ml,A/H>@wv[ `aclE ?`B?6?'Y89{+fWҕaN&.n;+r8@r_wqw,e!!+ˇw+"i7{?@{,^y%]p_SП+do:9e'Bbn']k^4{G?2{y>\_8 VȃigBhzG'gu ]MvJ,ecyKRt稭ux{ZǽIN7' I4Ew}]|^AwS绸~l,_{7[íP>mT,gD@uj+oL>8G=v{Rݵ@%4~<75on{GV3wFgG,EzT܄ AZR)?F+ӢN3K>l(l^oxs-)J.=cO[M @rihZ/R? bG5g\12> ߜ3 ?6*pmN݃OC$ /}ecwjg+VDRh SsHJ4ϒKCbEȃ9lJa'TI<x{V;IP6Qjڴ3c\|c9١Q0]-Xx$z;NGL--vZcKw2*Ru"nvSՒ9:ynp(0.~iSu|0~ K |%Pmxڐު#*miuD:ckr[^Cw]ȇFFz'| CX0&]u*,2,XCJtSr6|3.EIyBr/&zd^31egʧj$ BĔ hGM}VQjL1N}%0yge<\Y]A}3ޱxc[s0d> t 6skԖ DP@G8K"K//_YwZoǀOJ$p(P]'KھLwO KOD wOT E{$Iƥ5|EY8.+LdB[[IP8`O ؆0̫#1)Q(Ssi'#ѣ-Ep] ^d\Hwft'51<V6|9Eg]Eln"&7 1|hb 5) $K0q8ķ^Q̞3 hJS v#d9wxVD(9=K"e״Y? 1{SIbtQLY>3]EXƒQ 5{bOtk hQ RD7=!J7FȪ~8Q5y濣i]aΩz0KA}"49;sN{Zt?$_ :6™P"!h BlWSeqaOUls| 1jqf&)7짏\H#:&Yv1c۹ JQ1O0Z{Z4Q~.#HG& ub=k~OgECJ6t q3hU"'bH!릲fᘻB[ ;l5^D (Ԟ4AD%HU'֛Bҍ( یfD R4{=z< 1M 5D[m|DB| ߘ ( f๎L96Oa4O{sb| `1;7}mYR"CGB P IEN㇎w?D9ĹPdA, lVeK+*U|5otvP=ҳ4q^eG睴O Yw}z*}Kw6Q/5SPjt%R_í/=.svw\K L0^63rr!tf5tL?^;m# - rV tq.í־G+Ӱ ּ8#%" Ϝ~p c#cWG2] ?S5&5`\ڄaR.HTeD^*7Opг*\n <.n}U-dE1Cu{neU!.è>+011IrF ^ւ+Gkz? 3x۸hwd6ΖDx ;y=WaE^" UP,Ixd+ZKlw&;W?z Ŷ%̝3x{D{9?ڶS@(OQyvPWTOS@0ˢ ~mb^Q//5#QI]\o6 1UnQSQ B`|:]_!)c:^+K\ vGG7+ m1tp #S[6\ψj||MiOs_Q?'TZ+`,-C?~XwD#[@oK) fX*';L優Š,G4Z)MWhT? gY!oAC0upI0 e 3|lI%*aڈKg^[%T 8Ϩqfe`bԔIfTwƻaA7$l$%tYʎ/q@3jRrN[+YxhVpbtAJ`I&KD(߯eTb=Ӵ^=zc*7 ng[L`5/ >X NmW<"Ulham {W+׻Y\6d\,pnhK){Unow3.#Ɉ\lsݚyP9֝Sx1%]>wܬp(\l@Y'{[5QN%p$%XW`^D+T{0|-R-WrIˇJ٢ٳkEFSB7U3™*#='w \Bt8GCX#$/{p9BkY+(zHBo>U&N|N!y*Ӹ%/M0|on$j \U')l7ԑeVʮvu9'j%9ˇ.$++>K$CmzzKs*HڷGjh.t@43D+),S^wN_Ϝ19!{(o9,zw6dM{.FPjS Ǭ}BBkbԚZ힢]av =(k-5ѡ3jMhI➊x؍ħ+HV,0.i(So.~nǑN|[c #}c/x6>"]'.G\ΒaDr(u Ng~ _<%șG12h♁){oMORNJ9ZU-t-0!-ík{y,l\$ZT:1TTn{yBf-/15&&7etж];PD D |̗Wc| [ޢwϊQ{(VB `7fz,|@FѷMʟ󌵼:3&Uۺ b}Ѐ\8,~\׼0B"t:H !x-tB A24oKzQs͋AodBn~Kĝ̜{mLJAP+SH֛_T|*Q)>R-f0+OϛKˌ(,xIi1Q術#Pir6LnN1 8>]1Bu7w*yсu^mM$Czde ؠ;`򻷼=ծDV>^pţ"".#;dw\>#(~4-KCt#|jȪ6UvPmTrfkHV@M rOwzZxl\M[M>Mזk5xngo@E?CCy|;.R72"VHR4ɍJ02Qz[{]ޝݼ6YNkF þ}͡{S:ۏ z9 5s߽[R*ͫU:2Wo|#1d䎗T_øH#,LBZikS*2C|yPmۑ) aM]* ,# fqWW+ϾyШ>i~,~8AuvgQa&(rkcLV'uhC`±ٝ8Q,DY?P?\k_$ϸVV¼Wʖ*l}%BB/V 4eRzYAG3&qpn Cv|X ѧ?zLϡ-l[r82D.(fH=HqVRN 6Zk3 >jLi~>C̦'@ $O:h=&vi$nyF䳤-K.mHVkvxJU&G!_xBZK4,M-rvC) $#Ѹ%$<&7 d"瘏9[Gk*@~]#̤ᴷzLS ,_Cl| kƺiоgV qr,lG6+NiL&(Q>J-A{h*@s2qB~߀}Z^{J$LusrQ4;yw Uƻ%wla"aŏlqFH!MaE2yXE/hk%yLqƠhVQ&U33[|ҵ٢[o IϓeD}ӢoQ';'>cxdf).CR fwx+bNZIHW?tuݯ}F<[1&w,mZu5?GP15 -jgf#+, m 8?a0}JtӣSO>jw+6Іcǂhqd)Lt]?Eib5ܱ~Ρ;d.*Aiihjt?ZCEٓK < ?O_It=?Zgd&ӾmZ>s*\50bOLS;xSC@q"=4i ])I(fψcp9ͼ4 &H+e$Qkc,Pni򮻉mx\;8$@:dž}E74AH'UK~߯FKI]JnvL\XTx'OE5)>u6k4- %lL; TtdiSS \8]d8dCs"ܭ!M$ m٧1edbT,x.j )TM#*Lٱ.KWc5Ṿ;wi8[s 0rƌ׏oAWkT=B~ش)jL GN}Jr 48Ó7*սK5mM8Ey#R9w{yk4W$&ec|)sC_.- em)4EroS;rUag iEnbE:g8䍞+wSOEڛeA5\V$t endstream endobj 81 0 obj << /Length1 2026 /Length2 13956 /Length3 0 /Length 15185 /Filter /FlateDecode >> stream xڍP[ Cpw Ҹwwhqw n \[p;\Μə~kDIA$ao ba03123SPY؀#99[B ty] 266 '/ /33?Nq)@ corwt4pyG _[  tپg4TM,A.Łݝhhd.HCptANn S_ @[п1S,,Vڛ@w xP(:6ۀXY3hiig0%]<\@;ӿ 6@7 _";s6qtpqft#_aTd W}N {2p,Lang ͻ`ff  y:dK`Ncizv.N *L-M\ sK;? ;YztǏOfjog_G$)-NoU{8 ,63(-]_i;3{?%{ 4`> Ac`6yb:E-$]\+YhFh0$؎td!\/=0 +Eٞ 5Qޢ:QEϮ*~a1̃wV{$or3ކ(Zc?l?is/w>O"qn7Ąl$pł$$SsZcIYњuN/䷟ G&ABˆ6v\MKuAS1iV2v#Odպߎ2DхFk\*aEwJS%_LDM?OINHG,di&u3N^u0bs.T6;R+`e&!n 6XuZ5ХW]l?ד9(V@1wK jVDչD>T#Lճxsxm+CL`\C&ٞ N]P9d -T%15֜JG' }pXM\PmX]Ýl`a]n g bnG~j=q\ޥδgrsIR•+(ΥO8}#/Pn0>mCv{!&7 qYe$*9jwGu,X_I|\A{PQ+ӝ}0-t#8&l}l#x}džP'6X{"vq[N"T,SIKT'yFNrWy7*:|7^M71Hx |`%Kn+wS0S`v`@adpO|+ ||i yp$0 &fàYl,w3XjKuNGׄ&bƸtmlAJSi_8[>~S&`P3.T>hǔc?wM$QK,mLYG⬾V&nKQ}e я C\?Zu2|lnn#[MSYx$+>9t0teH2~"GPpnwVLNs߃tPiث 8tcUt-Sډ/ؕD0[wI=Y~ lE)=KT''y¤pP 4mHH(]RuLo*e̘cv%PϽ#&V;MYd!L$"(A!oۗ,6T0AAfH @`֞œV6RRIn[Əꥣ@nnYP1-אb۸ߘ ܋X?EsQQi)Wl ^UnOE@e\l7#FPDYD<̼}6=_mZ q֍5FQ2AϞzho'48rf([jz*z[_Vԥ+JYg ` F T 7'.W:Lzӛ ?JLduyCv4#h[,N̮$fF٣HWD]oqҡ׾0:a?'aρ/H 8b/uƈc C(r T 'LJ#W$} Җsb ?NgSe3__pWTwIQR ЮtZRy}:ůB4h"9`nl2TD,J6G(jL uY+@e jM,ՐUVR=yOlg趀5GÚ+579 ÔsVeۍ&!B)<y,Io, i|X'J +1$]wE&0LyT !=+ebKܐ,tZ>ҽ$kb,ppv$ Y}۝ˊO 7m4` duͪմfCL°#`!YpqOynmZ:ݤ+]ǐ! g{\n޵ћYZT}=2"mv,vSf:;p뻸Tw@R5wegt)?Cg@E|iKbqll)|*pjNgD& a94bw\ZWʴ9M$ܪ'Afﷁx~"iIIYG%f@h%l_jA_-ʟkn[oAP4aZ{,  %,P[n,+nB{u\R_H^_r 1:Wv]r$.=/wvn.(ϼܕut"ds5o #mѯ[}2FE(V$RFIW){ːEߛ/JRڇ /qG xkͯ4ؓ,CdMaRiFI}ÃAjq҈HLyJ W0,r|L6\@g s^QY~HiɏpH@"'?q6ʔ.i3& Bꍎw`5b`\F1C )o_lّzW%mnBFh-4`tj Fybd;/ F4{+a7C&IS$AH8N_?9_a J6m]7)+ʷCS˒02Дġ^q%BL٥ɻhG;SEo%EhqMD,߹*3Kk@Wm R5JC_ӶST͑srNNy)#k>N.?I#(t3])RP_úa^}L袳 헢$}ө0NN蔓ŮfO=`sfE\Zو0T2"O72Lgb1$[>Hu"M:xH_`VJ(FFa'4)Y`.5Yցs.s};VB߽~Hzq;zKYԠ LOpJ] 13}ꫜ(<-A1hr X5`AfFJY拧tb5%rEmO8"Q.s{Hڂng0m|Dp/LaWpj?ޣ0PhLfk/^L.4zu )! %} [$[vU/##9r#MF } F9NQ#Ia%J еqsl$;Խ%u+FxzzmepaH ռq{DFfkm"P!{B-gݯl;|j'\)Bې$_ I-Aw{R z7ۅK*NJJDh(LؗV.Vs}`|J%&: Ps;O}{H,`I^Ecvyz>`mڳ:aLfWPḻ̌OjAςiql`6/ϊ>E/πK8xAG˯#/~ tЬjm wl35-`s=7c7p CޓmV> J_ZjdI܏`Vp)ْ4B ;E_`1Z HG ïK/'" ]Yl7sxN5z_oe QX$*Do7᮳ g%=";FJX!JH .dT"uvU˖a9Pu"a `~~>qq>lS*J%U.3ɸV&+)h`іfW,]6 JF(J<*3sFI2YBH^v]@]Kz^X>U9 FJyA]䢅=S`#@;JWzvRLo._`ƃ٪$q6 ]̄=~x\a`Jڶ2tɠdپe)'ć81 /贲_(ĦKzy0Z[dVFMKb+*)N^d?&LѲVv]J)eH9XdrEx/v /DҜ1صQFaU^GGH<5r I- {΂] ( #X{Nt Oڻ "?OSG9i0@an ׃gqܡmDEo/Rw;O3!Ud ;<l 8)9D_ZhW\SFK`fسx^o@6mZT w7J+X/ćb]=S\ԢhVPaB.<]*j,vV!`v?Anƫgt.0(ƍ]zAWm?|g1]VqOġށp)0.5vރ`TՆQ퉁 +z ޕw4)UX|_3Y6V-,#S)Ik\Xg}5b\/ j"ua^8,%?Woj|tMxs/#DO+ԤPT4UT;o}SX?MO`ƢԠjl*3A머b&;{YV?dM<諓F}w-ѐ;B~Q6-ܗnW.OҾ)nN* +w_o-h6kN 7s7q`2Lv tSQx %y+JcЄn:<᝻"UDHz SXALP9I"?("58ѕL5l[ao%[QXzWrP v'1,H lKe ?x6y$/*bx/y.wFq1H~@3RtAHB"Fs"kU^`yĽVKh6#5o.S-fڨ(brQBҡ@p֝;OvҶOmx`P"-x^uf6#e7bj'@CS4YeiJ=1?+^~Eb>K*;ZZ^^JyJs$({ `,RPdUMpkLnoK61뷲椖yq3^{}#l|n6jj+&PĀMF$D~6.@q au’Mn^yplvM'^Aҽ%Bx~mJ2϶ l!E~rN,fNl/$xE#s[suhƸ:I5R ir~z@^2V/d2R5,C0ozkuf*B?.zK-0\z4̋,Z#rCDBJ0V9n wPab?FX$8h$l: > );W2BY7m3"q?釢D%E@HB >}:,fGcV'. "Hnc:mZ_ܚ5r+"L/.jŒa9\2ͯ.ŶCg0Ezi\ 4j8w5(:[D\T,uЇ$adg }z> ƥDBBpjfHek#Nl屄\^ QjR4"jeqD-u$eF)s܏hH1#ɇFâQ}s+-/ pU? Au ϰ/E(Yt{SP' ď8ᛊ6ec:^FQg!x _|dןHU7 9!'B>ȕCX|h*nd=Ir>z8,rݦb~_玧 x;@'hdn_Tz}T58oYy#=cl{qBTd(ipO'*):PӪN\[l5"| QLoŏD2&5 0o/)wb{̤ /]!q ;1V؄ 󤥽ri\ `{<.6;ذy9֬(7TYRYe\q}OOH {m7]H:@j'e}\7<ʵW~M˭.o$2wlOyȟqMyPYXԞ jjx#3)}&p/|V3๊S۳Ld؇M(lgZ6TǖcJY'de4nں9Y`EwZL8d-HCJgiTC$Su7uL~0PY++ 9 6\ qEx{jw ѷG3*nV0"_G"k 'ey4$JXEOßP^OXcL^K <{hF#g&x^_11/8ݥRh@jڎ>„dbE[i#,dgO1dhnq%ٳ J6qS7cx<‹IjV=ŇKM9P33k:[[ q$Vk3Va~5gO }h@z4Jyd o͍Z76JbGW2Tr{+8ga r L>S aY *MJ#^VzBJ9i.?&J-0mگ롽ktek&ˍw| Ο24^f}Tx <]FAGaBqt5좛JئtM*)%Jh->W U/o&ϟ3)B4k/]^?bh]b!Ll6 m:jvi܈`e+s28#"Sr՚BLdX+Q֥vwE-G795 "RDCCm%ءOb"m2UB}^$OEP9Иʭ\=).,4٩|GQ߮ehM>Ĕdz!RkbGS\ad4,y|<{OOD#"}'U-l&ɹ)y{: zT=IGV8[c19"mX0׎63jGN,?d :l>/֌ܰ6 ƃߙDֹ_:l=kЈ0VeȌkcGj3Qn'_9vB|a.(jM6уu}A2^j{xNZ^,&Mʪ:D4H^ie)<`OwCA,s('myA /a~jA2ijCBx(5A ߰tFa?VC)kK`Un(@#Td,c}d޲o 1Qu?£(>9qZb<݂֗Y7r3CC `UbҢ<_N[^=wmzIX~1Ej6ʸ<.0W$&06RQKbl9Ch*0B ZjeBJ asy2hnظ֪!y4T=(`[=Df'''VlW}f .0Ωy/ѩ qfX$rF] ggj15SYkuIX*cHOU$21+ePC=s 9FGD; C,ا C֣/ ֢W- ĝ%ϔ9Gt1QP7U\eb&/f?s*ҿDF}uqW(Gh?7}޽_k\ U-/*ZtA'o`vhZeߋ,a*ڣ=?GEÑIɂ:\iR:dm:.Hz0cJ[b%nigA4%r\ _Gqt. UhK D@9cOCɁ9'Q$7m4ޒ̼E;5.7 ~ {}IxR` Opdob'g\'瑚XdOfTu>*Ts}Hȁn&)̍0>ƴC@LKzJOLhqץT)m %y]z%8%>a^OagR00 O̎ҊBLb4Bͫ&{(-dLKQ\xWGr.3FnyWwf5 ՒNGq:<*"g2%$4Qq0Wx-[ۯE'^"iwQKh9=,7G=Tn2=!!SIOaJL70aDNl3+ w{Mt. \7B| ҾCɐ>2~=k,ÏO3 \1;qT~ Ʉ@z]Y,aOhkSH5Wk 7f(;в7ff@Jƒҁ]v9gghF1_oyXPChv)$ )Awa#/9)x+0H޶ؿ NN^ܢÑW*7j&>X&?r*|aX@;=:O>aeDkM8aO|WN*Q5ݨJѾhvh;$ej«h OjgC%"r=DP $ƫB͆DxgEGy[}$^@] =c&'j} }rGs>FөӶ@P,Iu4zx~ϘKթ[o ! ζV%qV0T{ >-Lq׽uh4Aqzχ2UagX%ףqZ1B,]Dtlj"@]ÿa` MQXx6/ f( H-WHpA'$v$5~xvaQzt;ޡ$ pHBh(J6*`KJ!1S!V$gHC<ѵϋ~ endstream endobj 83 0 obj << /Length1 1588 /Length2 7145 /Length3 0 /Length 8166 /Filter /FlateDecode >> stream xڍTj-Lww 1twww C0 ")J#HK)҂"us_5k仟Є_QÐ@!i%P $$" $$La EzBc'0 |p?*ykS!ozp@ťBBa!!i* ha_wꆼ.07(%%A@ @txf<&p0 W.Y7$[ZP0 @+GsH718~ yA&@0u] pk!0[?30xC`u" 7_ 0 Aa'`+ D@0_D/zn Kԕ F@P_= s;f5 COo$r=`?'(W~ނf0DKD I K >H MW oo|C( pm u|A E8CH #;@Э_U37 h[i2< K b a@ Af?"!܀҇J[BbB/W"u?O8_zaJyze/A~^j!As @! vK1~'1B.~` }A|oeϿSp_&,&! k=Pۍt2@PG޺n TD }jbY1QT0Edžg8 $<=HQE>/A^H9zE8|*xTط.5){(\mTeғI4 3HcN1"Cۈ@;=eP{s8ޡLoE*z:w0Zq$^k-F>H/_b !',xE9CBMD@Ú[GdVpCrK?G})sq?\M'W]PX(,O`gZ2,ya( W,[AǽI+"/ͩ]s-+9{V;)K/ؙ;?N_SwvЈ-==ҨŀԪ Kt6po5{2QW d4V184%3YgZ?(J^F6s/9i=!Wuqr79.u ji^9U8&~n3I8UfIp OxkoplM!qH]렖Vj!Eoa-w5kǝh׺>6=zKy鷺6 χnB?Js#OԴ2lHvM]*m:wQ 2i.cgAjs+saX遫뜽2jXNE//~[YyƳs،OYTgMKyۅ&ˮ~ky_X;kQ~˅\=kT pB>B]CSjGC4ݧgkx4EFVw9ԫ"(C=Ō > ТiP҈u2jyzGX,v] a/qTZ"eLz,m)^ c;9]x>a2/Tb &͈T/nWsR. 7(L/RT 2r%`? BN#Fq;(& }sQ;GɠТc'XTtX|w\dԄ4w]*F4qi,R2JG|ßΥ-$C &6w!>eS.0"\3Bh/IEUu@yje; I8?92sQSA0/٤ jg6 ׽_ HmaӾU;~ orUh٩>zYs뙪F N݉otS1]7_~ԇnwNVhXǵ VQ yk?לMv&vHVY,쑔DqQT!qSN5ana2ypxlG*<-T:ՋFGMyO6\[X@f{]]i<"ALf3"l=άD* ˩^AO-Dz/P )oﲡQ0nX]U9BGzi1Zu BgAݐ59ܦ*]_r'=؞aZ7*M'2sL T8CKM#Qz1yq,(=/t+M>a:PS+k3 L[Y{ķiMʳN*kkOsd@E?R* Es1$2O a7a(?KؽfA{~Bʊ?$5)p`k0P֭4[_7e>O"4~;u|¿:\ʸN4R#1E`$L'Xʖ`0NTVDbL/Y0$Io@mg+cг޿Gnue*C|) 5(RByfFvٚZmI3}_O.ܮQ:9ݭ&٧|,S.{-jolkoJle7ܐwН3d@9MYа㪁nj'!y;_'E+GI}w輺:_@R+~,kGKmm'&ư7{j4B|fcCϛGrvV<ӦFV 1g+zRa }dD z6+j8-b.g&7Z٠t9^ֈO2.|UשC@&<~)Юj&Q萶c8(xTj3sL0 ,)Q~7zz}#dD@&Aˋėz:!,SjKg>iR1H`|K"H*-_a6W3L@e%% c't!ԇS (/׶g.)Vv1t+Zb"s'nIw_f&m1JLSZXoh}oг\eU]On6o8ES N:y˂r䍍ɥYrtYRfSMtY¹W/5).LpG5tuHåslQ157nRHE3fer{?o''$-7vZv[?E>7*ShSUk -d0Q ,&U7H_] FlXdaG,՚9u=S U7ԖM^CSsF$ѽ?%p "sCb{zTB1iYǠ-F'W~6>;2yaR!`ƊdF cs tTӓ1kPg Xu*ر]+k(Tb1,eT4Zm]GsɺJ|\}*_c8"hwaǧtTr)j<DZ+Ft'kW+P)Q:'/7e^ЋGCB#qB hvdχcQLLVyylW#[F7j9zr$?s]l?9/aH#^Y=5IyQ"haIcNRk׃t npIpHؑ6qWqأnxo1MS1{KTF-lzlf"Xuө[=EYOt+-f@$2QBK[LJ Q{# 65Z=,b!3i >qRe{-oSn3Lb&VU'su{apg?`(X&]Vg=X{V炃wX?=_{~Ln2MA9CSJٷ[`{a" J`)H8}ꠢCςwFg 7@#^udP)Fwi$B-U^'gs!fIK#NA|N%Avka/=ķe"mh@ $LJԦ4hν$]}XʴW.]ndN ̎/K'`19l4Zfw 5]v"r8E܅ DR|L0)(9Lf ?P{P?ltd 1B(|dqvm\Ah谅%r3^H5nG{s9GOe_CpNJ+R'K";`_m׽BTh$7>][y%oew}jR :np$Gvz[/~/8ɒIn|t4=چ/oZ}kÝ|lr;<34 TM<˱:fMwʺ֊l'6=|2[+I.u8g*?Bj8^ tTŦ\Ku`^IQ*W1.~c!tns5 h,H\g/;mNuZ)Vb %.MVȲ& eˬDә F -k.4 FcU#GKѰT]/~3qxǎp\'1d0R>/?')ywjbЬDMmޯX yf*2-}voH2hb"ȺAN(*+.Ӑ#6x65]ZzTk?(sQu;eh6'kӥXb6׸~1QNF8tWYT*qAxS7vjyT\ H_(Kw~91ty N3Z` zY]T 8:qv/*MoC}S4\9NzP)ekp> stream xڍP\ր$X=Ɲ=H=Xpw d{*X1i %Uza;#- *//`bbe`bbAPY#G::YBhz l2fV33'?v<1C <@@!jghafzG15ow  o2ڼg46[Aadtuue0qbs4Z*@' WC@[8Kjg r5t@[wg[#=;@UZhܿ >3@;ں[ؚL-E 9`hk򗡡ݻѻߥ$?'cG {_=2mMDll 'p;/?djakbW&@iۼ̀ ;'+;3@/{ޞv6?N.@O330Y". }LI}Ll}Ō nJ;7'=+ |8JҶvUAfտ7G3:LL￘?.(+p[O/-Gv`M5]yJ A}%pp(Y56p@%;'^1^LLGeV}@__ |_Cca::#_;<tl@.v]4;Q/ѿ(8 (_d0J!b0J =z_z=zϠj=zϧi!n{Wm1&@k? 3[{[u`g4G&^#'?{N@s{3_Ύ}@71✝1oemP}0+8Yڽ x_|J3A5;kI\bYBϲSA>gmsޝ햞Xbߌ(n|&t,_3EıL0 ^Ĭ_SmB+%VLpBGWui6 hHmSMlvNxB,_Bk zawK9y]w@ Jc9(HSȤ:u}¥. URAi! Hc^^rN(1dӠ@❓FoT-B+`YɍggT/_+v(ڣ]LC Z?UbgQz [gRh|J3oS꧅ʊbV{kUGCUm4FF݊WFQ3z(QW[*M]Abm6'1Qv<✲Έh\p}a7Dq&` yX\J<^ 2 Jx5:8 !.ZSdlF_TXZh<;h [w07-w'( {c.S `)$F o\FROϜ 1p:f5xŏBCNùF@l&) Ncvfφ偝b#[yh\۪\mtGh QM`v=>0, aJcᴏ+Q* s` ՜L5Ux/ЏrBO*zG$/R[UeXsM 9ܻI1ć*ޅdhGZVmK`M ӑ~TY~t2M/,Zб3b [? 5:t y<.IrlYn 3pIlu4<5SYe:+:lE>d p|H8jQW~o v%Nbr w~R=v(<׀5+vsG'0hWȶQIq}B̍J|m!H4;!DCT]1Ggէ4w!w~mvT5u>$u|;us`-*!y759OT8ʿ'/T՚pƢXW̓KE(%P_R]᭺[:hp2p2ˉZ|ujOtjcHٖ BULj}f#i`~kHUDNv9ΊYQ?ss}% Mͥ3,Z0-qeDpiԉCwW2Vк cLW|HbY`8obĸs0d9;6}\%In?hIg:X?7 .y&MG㐹# I <1woJNI!ݯ~V̥ qiZCAd?.,EB Fo({Sn}J,~| Gu$[gY7(EXи$\o"8:a<2:9+'*_ſ7ireEw3]-TGx,X2eϜrwv@G_vMPaO?3*Q|ۜ=kg @ɰd^J*&w4a݂-S|_=0d.Z*-w"٧[: :cW3>ö kk C߉bJ l:{d*SwɤVd By^2oR:P0XtIS.b|~#)gE/E?*$'ѻ2o7#2 :r 8>@C@ǃ1ǹ, ar[sqhx3$}}=8U)CjínvƄE` Ү@r\5La^;&v$A)nŭБK _^hSwCGqu7PCZP Y  +#,K̵Xb'W}H÷/Wjti ^N 2jCB{B'[00])vɏnW74gRq]Z떭fSMSbjM49wU6\ %ayWn90NEOmqa1NU!iY8XI,-{ƚ^JA@)]Y( ak4-Bv,BqBkMP>{aja>\,7'r6|Ӽ諍РՠsO=|!?pYi \IG6Kx䌸k2:$7oso'(.wUiJXZ؝  .RaqJׂ׫%i T$K7z^gGͶcL!l!_:QM*ZOd0!7;׋t5 } 8 <@{8 rqO$M:z.boѲalkM/ѻ҃Xt@N6G"S LA e)24H/(HcA:tƢFufXFCN4bwS+tFs({cwqfukBU~dt2#و%Z$, :IG` ȐF֬葶kbQ$#LKVBpHe,}HJv?سi=߭73TzF\S"s}Pvq?jZ'pwt-!oF PFA?e =ˮQF'E:|$FMJsy E[p>A}T]J̇N(t.K"C!=g֜ ~FɡL/ê7Y96 3@rCm&WXFcz *ſSt ZJ*8bk\U_fNGeo2&, 1a?揱ZyE(yXTƯTUaW+6DH)JԲcTMKf+\*u}aE; ^F9uQ勹ksm!HI|*n)]l?Ce64;?P{_4'GE |/xs]_; [ t;ɱ|/ċ'*䰉;8Ӕ,MLZi$=0ɦuhO+ y׭06t/𡴗(WZ5 0 'ȍ-1 vfpYv@^.yԺ.`н1@A!PjD+1'j:}˖T'v (ɩbr*-{u:WSVeH_+7"]k i  9Z(/@*d7fib½AtrR`MUмYiP519ދTkyQP8sEvAaBO"4WXtc/uW!kޜ> kڂ*Wx9ׯH};ڇ}nKWbS!)[;m"[sb,lܴσhZ"\}gP1<&{CYH, V7*p2ayq~Ŭ<2ǶGI!KڷoM1l=]΃0O:PIL-$6xgϏ{䎈YF$F`)<+-;71xsTPXDW֎4vͤ6m=h.d*)alsJJTN7Lm=GM%ZtRr[d^W.C;uy)7M)+qYD`e2͹lɸҏiRfV؅_&I1Db?U?7'_p ]*/7jOؗf*d#]vʯP3f2~:ÅkI3A!4s mI2W֒v*2\+^޸` YWj4s&HnѪ^ʂ h-^,{6/4vo">e(ԕMaGk8"6r[-R7vq0(sa$Ǐ! h%Ly 9wmQ_yD|'{GhiмKFL)آ?)R˛gtORE!Jn!!W^0>SAN {+.9+ m=7p0> p#Fl5t[y=sfcq=+~ɾ > !JI@=K\r]S}Itڳ?IOm`qʱ7 0Lv$Df~= I'(TݐPL|oUZ`|I8P~ڽ<2#k.5[glP,7kFHN]d&סS)B /f=tTx F65_,GxzA3 {Od爽Ky)63[}͍t4UoT F^E<+McԾӻ$DU[7i:fw\ޫoXӁlbcY~\s]v>tk1WBH8R\W[u EKL9r9eS$E/0UU3%݉jBQ D rF6'5j-R,"\UxrD,w`QSa.Duq<˜qL!Wbh1;g%(RO$Yi(YohN(4QW"Ftgv>OwjNjG(̓Mgh! ȎJL::>׶묺566S18& tMсt|Z4xEXwtJ ǔv nՀ*TOxc6ږF^CQA4vYw[EqտOxr/vx0_S"iܵUrvɡ_._kGTnQ̡N!5y㥦aiŪwo:l!?rԹyG[X[y*|c?0,L0X[#W7|98{epP6g=yI}u+6+/˞μ7ֽ |Udg4{MH%1zN\= ,$"DfQ.TmDkvEVkqEfˆݨ@G7\i)]tz3SLL^ϐ7l aR(T` kV]$dvE?wy&+۝,q馇-q/HPQJDWT^\ۆ稑66ƠPT}jY5ΌbWTUP :!ŧ ,k^EjGD345O(wgwU=b:?C%ݮ ԿI |1yG%W\NҾO:z~'MY&ܡO^1n4|mDLo3O}cCb[{(ug]M0k9't Fq5G&Y#:qď RAP;a rZ͜&Ztr{Xb$xWn#8MQP7&L RpѴ7HX`>*q&ǕINLe(>C+N%W+|X _;`ZAʓ/֑yU"E9>o u~<%H\o\GE!GÓ~ۿJG;Wb.$h:Qm K`yFOJ#l-C5,5\KaJkDo tr~ܴ%^ĜZ.!&+ƚ|ѮMVU t0FQ`Er{ATOZUtXtd@`_i_g̎ܶjޚ_jB&M:߰y~kҊ,qw6lWQ0{Sn׽1y1QJwU3欹%]R׆-``ƭ *`T}yrNHX{} 3;PbVIVڬ~)\2Wk>7U75QTS }RRe#<ߨu+%=cbv;Ihꎣ٩j7g$ڮVN֓m 1n?V-2.HuՔte }kſt .)xa%dpA1e~W?'gz?'I7@ b%PƗt?ToЧMϞ+ؒg&9q[3igݦ<%+0} e684B8Asw4/ >-tGUkMv,Pl%Or8h%T,܉+_贈ۢP86Wx6_!𕑝.Eou~7 rcyXүwR?FU{GØ׃TMݎqQ)*66`"Av}km b( ?G&Y~j9X^\5QP=|n`]5#nAkǯys ka,O 0 :*蛈e* azƨ.yG +OIGV^`T'g>9  2J-GΚ\1(:z c⒱@_6N$iS@B& bdWGK !6D 84;kDƶD4>̯VԹ6WNp)弅kDhlFwz? $b>fXv@y}O=i@Ay Oa#M4Vr.f<_ IQ҉m CikϜEoN';8~M"h?(W$X&aiz9XOF|x~$, 2.e_3[~dǐ_dL7Ne 1F4BHh-LsHs~U#,Ig\Ƨk73QIn'q"dRl6R7hZas3@T0> # vU ) jR?d׉~P0޹Nҕj~oT^R$pZNmd,(*2z ֱ护`X[B*mV憙%/EWEpmi^4O \0I[Fm ')*-yk~G8rf>gї%4_K)p6~+mE%;zϱ/1HM aŹjNY$S-Iԑ/(FⳂţ_K ^de@NT H@Varn!nm_>1/?)ޫmlw*|sMӦD ٙ.+G}Y|;sef,xT$[9d ౸{XFugι`q{ÛGqb":PD9* (ݾuȚ?^v@>"}f+: endstream endobj 87 0 obj << /Length1 1385 /Length2 5981 /Length3 0 /Length 6932 /Filter /FlateDecode >> stream xڍwT.RJ H 2 14ҝJ -J#) q޵]o5 rp0DCp ZZjB P'`f6" 7w(& nS!P8-8  ~ P_@8@ h0; j@G ;OLLw:@Z u `B>(&@zyyyn\/(qyBlh!&!`:@ v/r8Am 0wT@0P@`\wwٿ AaA66pg A eM7 |'; Ԁsq yܡNFUuJ0[3p'՟" bv?u`~ ;(.F0DM/"EED+m w5A `~AP SQwź(>~Ds~yM8L<' *(A=. R`vpOkWǞ WӆX @! So UEnHwwN>(z PЂdo h P!@(!Qd Cݕ[](e~I ݡ-, b(}8(^ QbC^/?Pm_HrsV~|(B3#P);5EN|k:7P-nbC07 }Zچ>@>)C(?YM6x=FyOmyW륙o~u>s$Mhy&it%n=hcH?0vͦx*iX]I@x>o!5sBZETv&Kd*ҕ1=7#Ȕ$( V/_xeܓݳ)_fOCj:Y2pvn/TI~?,;T-b"D7A606~%(ALχxEǤGy%`6AܗuUgȢ]ñ'" ;[o'לMLH%XƁK^"?GwuKue"ru?ba"௳ U[8-Pz-&2Z-pB|6=N;T!f`ZD'ؘL#Ϯ NxX˻!=]q 7{~D;xcb4/Xr$J*8YUwG>el,jl4πQz'npooD}bi] >26*mQݾf7/^R!6FcuFi)#)&?Uf>~ãOckRtB'b:aJ(5Nl,KF8yOQT)ZH׮yBɦdxk-LN04UtS֔ƴy-A3_LK[ӹHt=K˩)|{hQevDZ/\Oo t]lXQPC":9<E zC}Ҹ-QQ|O׏ÂYKW tbfcU4HWvh `ҵqB>^Iی7u$E(G^Z 9e$'nalȍMtX#\v5?g1ީŴG]/7qO}\'yx_uwqnѼYL"x)+'+W;-OAQl&k:>AKzb<9I̫2,A,/W>[ybLjLgO \IzV|.Hprc:or <٬<a]iYt~Z6s}sriF?\COKUAsܨc;E,E[QեsQEBj峝tqkVT!}+}´xljF|):xGclȧ(sdJÉ  ]wCw޳w. ]"Q zߒt\.j clv0zHp-@w?=c' ҙ,V Ʊ[xeh8>s@7N#Wh.NO Gf(ľh>48OݠѼ7I*?Ah}o}e+]!zy9~=f DŽus'"½ ia7 nv 샮D=rq<ʢ/%#+v&^UA)U,}E5Xk,ЋA0@1=-߅^" ֣\pS0%u9'5jTust: .wm޾($$R^Ujvz){1{֜31TV?vHL(|4cJ-MyFd(+<ßtk),$2,)D* #~47' 䞁1 ! nZHlעou_ɕ$hrimJ}k\ u!lgnUNN <;¹ qJ9$TbxHdDHejV1ߏwg,D>Rȉݟn@Y#}~T ֆ7-oe*~P2" kc0`Ėٕ؜?o(U,<n&v겫er7к7LU[xϵo1Z%SJD~ƃHP~p UB!CwY̹yMƝ:s(߃| (89uFbodƏYӎsfe44b0Y /1]P5dTmg=\:vi<K`/""c3075#-z ̣Ca;bmw9UcM[x/A>0= uB-1v}(򙵙 Y2_&Je8K_uE]`z|1ț h439N{|,s~&杈)5XwcΧ_("԰: 4re&^s/^iߪ >>;u⯉k~+5ۍPL.q_8=&+2mxs"#6m>cjKV8~ _-=hƟVuW'CyHQ>?J c:le1xC}lyESkC $pE ou My=&N=zTJNp9laǒ1T:R>S/lV'Ji{$`+%]:__T1sb=5vs<)tg,e{]y{,u`:%Nl)il/]*N<躒3\U%x۳i:ICT]}樶/pgs37 JT;1jGt\9~dL$׊6bFW{ͫ:2-/)['ӽVyGm~rBܴP\.bu rbDtBBFف2 j뉝Sù8nz[30^G: '2Y2 e^X7x̲fY cI-/5 E3R6%ٝl<)5Od& (({:wN$NL唠kɑ' K+}.JCU]M!I#~Dܗn4K잃S@cû.K9y$mˇ yaß]H{T|`,I|H[]yo8BRzVkr_챤+:Ds0 &-.EOd}<6|`,???O#$BY܂h&$0m_#s*1'.,[Eu„Z!6e˞Yt Uf-Ooͨ+Ў{r&SuT?>nuͽ'iXxVQQroq#dE:{Yi6%01? #əZJ #Uc4hN$9{bggOJ4nn9ě&$uCwmkvOrOca )d_4AQ`pR3 Ϻ +A?=ytH)W鴸y%ps?yc fZsLw60"Hyq:śC?U@w&]W xpT f[U%WpRl}YlbT\/h e\wo]9Dj&q<4ŻްȾv(Yũ01kRzg1/Q𮏻 ay22R`Ąs!y SB]+BVb3A-LoRw~J>X)j # 4fӽx]`q=D: rKAw~!7N BlJʦzUC(HF7R~^M"GpX\]\khYuOTGg[l9GK% (GcA3E͚@kmZ؆!g+ŗ!^/ -4/5D/ѹDILv?obk;?w1qB MmϚv8ʺGx*S sLv ˗^WII\)+܆R-OiyfMd`_Eɥ61ii 2nY:pKƍ?MKrb_ɚFcoIix-R#NyKS^;f;]A,5nڴ\u,oQʏww&xЯWQdV?>6 endstream endobj 89 0 obj << /Length1 1517 /Length2 7892 /Length3 0 /Length 8907 /Filter /FlateDecode >> stream xڍTk6LJH 3tItt 0PC -!"- *!!=-k}g_}퇞ZM],8B)eey~rkA`:`W#TR.`3cL X(@_p)ttHC,G(^bm{|L ?o:@0`6`7Z4- `׿Z0`NBf.֢lv-Tql ⚎V0301`C]nPK My%XO௳8@mW#7 Z `0Z*4wu|䛹A ~OnP= K %WSZJ9:80W_IC\fPjiK61w `g†W{-/'$WQQb~j\~>L@K `@[^P{/IJ:z|Av.^ E P+Ggc`kMnZ<_]o&߁d~?i3_u=.@Tgi7AjhfvO* [A`6,'k!P+׷Oq,2s}\6k9d`bxz\PKog89G Q5 8~#G_$/y@>?#oz>r]!Kˣߖ|{-f-lZ.+$<7FES.GsQa2&dz@ƶ*Η͝WSxS2}8N iMwS|ځ&fiݫIX=_ ˯ܢQQA\PgoMhޯ{F̘{ax{E+x+}_p{(:#7B`2<(:_o3w?1')l0ɜP֫Z>v-[nA5|8NLՇ?oTW|Q8z$F xS}$r/DH^nS ^#y  G抦.,GnrȰGmhP*:kUnD{-K"?p[~zRCaYM9OL7r !kSa[eWYb-hLJrm{_z)i]&ru? k| E;\ r2]%3&wGaֆ3>@tE6S2>% rkOp*9GIG@8'->FYӹ[rNWpNϠ)(&W=rJ>>%mqm2cwgƀQrSě\ᗩ%kIp6Cڦ*ˤ7DZ">럯^Gs&?#@ xs+53OY;5ݢPik-aeeYkC,GB5_hJpmS2'[N{ԾϤ7G W˪U)uxRAP~_ʠG]#,P ;Nzp7Սi Cu-M Fn/kG:q8ڰeV&YR],NiiyC[;Ciuo Cwz˲tXH?1 Scr|^3N5vN*=dN#H_HK Qߑ~[Zw]3a=J:{Ԡ̧Td\*]_>ko\vd5;ʭ1. xyɉp Lfuj?럱k@™|;^ASmq*,$JV?l:D$>Q&nY{&*rv)%ӏq^A2E<*Â}CxtɘsOFRx$Dz &OK_})-1pʹ/o1d.Gm+a'={^BHrN vda.%atuX6BֺrOTUY -TnjG}WNZbz[r=By[8'^ Ցq+映,h=FJvJ' Ptt~txS-^e8Py9~%YkPf6bk_09Gc|q0Z7$g9-43ܻǠ2(\^o! @Y"Ԡ,=-#xz"1(֜9eRk"fi!0k-.Yn@3I̭zdMW8Fs!@oO.5*>͸;aJ5z7lJWܜ7"~k<@]4|.e83!"P(uɛ1=q3uh^+cNHh9ᇙy)\ 2˴a95:7y:wߏ!E-K"Z#I箢F: ^YG_6F^;UXsR$S2 'i/$>󟕥 n[DC2ʮAus{OiIPv3⚕苜6'<= cVkv⡅JpU?xm'mc=qƓ cm[BX(GU=;:1:/;$!(s\:JoW_VZ-pƸ]&h"':{ؿ;D,y/ƈi=Oh_Uzyil!}Dlij`c=(y٦CQ2+j#9OSRO_U7mϨFOzIŴ.~Xc "Õy:񖁽 Li̎ ~=9#qFdeB$rD<ZQd. 94Ebet#z lap]:sdisTm#- Bbv]fRSvW5qHﷇ[dkf&R*$f{31UҨ]7'uf7V_w*[A RzlfQEόTcq$=Cꮏ4K:={}Y,5^ae$':0@VbL[@?nV3Ow:jPZ\iXE2&eOӸU}Mذ9(}MvKQ/ɴ=+}4V|hT@JKC]iv'艦~ ژ9O81greLIeR϶TӛsnHy;mWg&Bxa/+4q -a!-3%$4f_Lto:'SLV߉XclfWܑkyK *=af>6N*HibY9ZѹW=E^We abFȈ3 6DV (2 Y#=?{L̵J?bZhr‚8Jg y4/BPZ"Ri7&`a2junԪ3c=+֤ϸ(JgD,A]e! Ɨ{Agm+m8PE#:K^wMk7놭ƚJaw88[Uz~]}W]-A[1њI5G#"V3[Ֆ}\=hC.^Qrt GLcexd+:ɉ%mp}EjIh rp57r_~ L54bd чnOMA*dcv$o9C,ژVQ󑮂Ϥ ln6Wd׬|kN!>?FwMǚRxkd;,NiF2 <(CV-\Ennڢsq K>t='0 2Sd.B׻)WKg1X!9դ͑Vv^0=sWJL`Iq?k4e,1fjA=N=R7kJg{܌a7v6 dB{2uG꒒܃lKhwrOՅ>RcK) >e: һxU\S}KcWc6aVJG5*?zD. Mˈ] Ĥ| êJON$-+t^kԔm) ca}l?YpLFd^>_H ,N1"a2C_W2BxDdg|E(@,/_)*݁ysKJ gB"[B~p]kxT |tf~3#")ƜI%RrNJJB[ƱY0hul!9~AnvYD߿o_a ōXy/m6,[ՙnOREiTWl^|8:.C`o IcJ 9 aL$ѵ9uHRP(x? :g-Z'ۥݖ qC kȪėҁ%fA0ڑS9\ITPM=@`mɋy/zƗ[e\ /z 7#"&Kޤak13ӤOU l%rqؾټG;ђ'XBԖTpe9%O$='kĽxFhYXZЊS_{Yk]]&=KmC>YsM>o H Z7Bfie*Ә pȩh˦'TIUbo|]}hԹM0lbXwףH]ڈ8+Dwi'yO!)n.!lG"zVR[ a~nya~b4lDIJxlϙĠ7:%/5aC4~֏׫^}uFO'A F~7!\űZxٹ-WHPo1$u̗o:4.z{iRcЧoh >P~B$L|l۪=YX !i7u-0Y'GR)_IۮqHz斏4jFqfkbI[Psh`Oy_,|ȲO_m;Hr_(mll,#젧OPF:? qfMlU+Coؠ;ϡWn&~iGܤ N˞u{֠rC]VV\"ȶzlWkSdCYd!/n̤cS+kŽҜ*ڧ}t.:L"x1u-saIFxhu2ܔT:PuMy'pɜVN-}4g3ׂ3U gƾoؔ.G̓1'mrOP04U2*B14\ߎs62. i@8:~2߷93VyN=R! K6LncX>`44$tvo0cBkSʣ7s3r|3zw]M<{ƫ&c0pӄUa$KV:3IM6Paz`BI>R#^LZ ȧjna˝MO鶦f=FK+%-[:V)M΀O}eh٧Y_'/%t'cSȝҋ=)ts#Y)hZIJHWl`X5P{ToӜ D-ydM2 !h18zemK&>.59"\g6uBҟ+q`MX?8 ߖ<1,,lIzzs2CW̳tz͠ мBoݽZIJR5w$sAiqӾMt33g2d9;5cI|S6ijz{VlQtޚ*B;&):}KfcZrhc:Hksu jS-ԻcK` Yz: =j<,9 rK1qRJMwti#02w#eQV?VTX5gW4{e}s1{I{;dN7+FUCbצ*L s`%O2\2.5.noMC҃*&A:{ҟA"aP58 ~8GWprpi p#Kq$9'AJm ZD/N)50dw){DǟZoƓ!3|$\\=DxzE>M@>BtF3[ھ<)$~ CDʐ>@JxF-auf'At}S;v]s{[OH2Ϸ8`)%3Q$ Z86q1'Fԩ"XCXT;doWF`iSD_34HіG:ݕȴ2Xy駧0Q_\&";bt#?1mp28Jљ-kbsn jSFxF2BOԃx(\))Np&owo-lvʢ8 47-ug T!xN]v;h=Lꦈť#x!OnǡBZX7)RېL}sR z$3󷏠̤iJl\L%cW5`*茩aA+v&Sq@0LʛUû!4v~-<fb9$R?3_K??{Ii+(xdzQ_튕UtRQ x}F/orc٪h^Bb~zi<&fOY~*=e?J H >[5^ \`j"ũ6Kc1GQeU">#ZP SikEqh-T@dS|}QN@mV5˷6G,o4[ ^\ dՍuXCCl8@M' zp9ϻ\tCh^pVٻ(fF.;f䞹Y;iu`jw)ߒ!+@N7MEK[ʹ-|_b?گ瓛H5H5PYR^p7GrVD&|Cn|yiP i+A(~ ZyA=3uw:sL"MpW ˇWdvnpbq=D]卩[E%Km< OJ endstream endobj 91 0 obj << /Length1 2557 /Length2 22090 /Length3 0 /Length 23555 /Filter /FlateDecode >> stream xڌP.wwwwwwwqw  n]vf7սEU>k,o7%:Pѝ `aagbaa԰qG Otuqr+$0u):9<V.>Vn> :$L=m,L9'G<;<hi :]mM@GsS{ (hݝLܘ\h^65h0@wfL kN^@H`octtp@ eg 0S+?t9æNΦ>6VK{ @YJ۝`h t dW)QU)(fjfc;E4*K:Z;98'a 4݇9:y9X8ZXNÙY(+ daae]@osk>Š $6@?x?7SO o#xVV; he$ZAw賀f'CxY891ZgNL`dd2nCӨ'ut-L?A o.%'4܀<,!IyKQ:4Pt6@ u7-?eqZظ[=-5o#P`@en:@# ڜv)hd{8>&'@ᅥ:trQ.No߈ ,q ?Լf7 YYKAlf?,q Pp(8? NŢŢA ȻkA ^S ^P,f(w3WSs; bGG  "3wH88~K8=7 ? 偕 4InhЀ*e ,9~Cqz9os'yX Dj5_ ٿҴ_T? 뿊 A@N#hO| >R(AdΠ׬MP"ΠOG9@qp?HdwpZMWYA=URN(?t˛:y / _:/gl zAP}T t]࿾p@s'sp/^{Ss{~ˮ]0iksB7]oE?HY!y;iklOQx6NR_t"0HGȨ!bUŃYk@ڻabu"baOuKcfAH n{jtYbHom .&b֏Y[&JW> ѣ DeX_#>'=wW. ¸̾_^~³f4ɉ)̖.HV6͇U0_nUc3I($os.] SpJ-֌>3kUkv$r2N6ཱུ8ܾ3:rzC;0[-8M9SZ4n{?'CKdOC%uɲ@DI?ޗ`_-l]4`9(sW!ɍF[^5}MPWq 92!퓨Hw7ib^-cZ74DW燀#Pb0],BS2O9 %o )y۾"$ 5nW SlJGi?s}-]8\IkSKG8 SvSDKg^'-lG;5H}Bڕ d!i8#_5(J-ӻzq)09 0~?nD:x 2 RcǐȤ8Sԣ(kBTfMrYYa3:.[r6F/7 7a|3N;F0(x[E;ѵ ?Wf[kS8;,Fٹ[\@sbJM`}eORl;/ XC,D?uY&<6qS .YdxwtqGi{pLĤ|Vic#ٔYkdU((쟎ZSp{pO恓xTlVfwrx NUlə\tYtH}Ho_>o ˧bO0w.0=pqՕIQ`d ޚijEvaZD͛DžT[I.s܈H)Krnp0@Q,? *75/²(bR8|MȰKi#>\w=+") ?OI=Nޥx}Vzl\UF gB*xwzgTC5Bxz0 Ң=SÚ%r;G”f_]*l|Zb yśw5~=4K:`c2yԖz4phv/!D_1ҵ6_ |v߸+ ꌺLH`EYO sHR}3wQg^!}㤂+*jPKZb bZPk#6x !ejح%]RÐ]*L] PPS:ZQh87H*o< c ί+aA))Wq&~w@ջDcK.v|MSY_[殘}_'m=}˃)*+Η@@%ﶋVIkD C#oR/,Lu'B<_<h1%EaJݱܼ 6T)KV?|#~ 흨L~R *;;^wozy L{ef/%Dlg,OgxWT{>;8OuwVQ\Dgi&}b%63Tzs{s% >5D: Y&)qn%?='/oWX}S^0_sԒ_é-$"Жa9FD8})ٴ/0*)cMjI3TĩE~#X?4RZ+}PhPjNW\8w-~5q ["D,[ҍTyה,:~"G]$*2"NYӣ{z1Hz~մYZ5h~3#B!6,M|AL|uTꥑ]Fq Bm!'BA(t ͵" Wѷs}C?6!2;~]:ec%, 2i5^8"l9rSɰ`5ϦRp ފbs4:Lo953qoXd~ |',4u~pbRV#qIaatE| CdV?;-Uz<H"o>KnGZޫxs˼/?~n_&^D c\~޿!c@6W}Ϛ6yfΩt[,-!r ylEsSʀ._3"6GFkȅISCkӄ9zdw9Va@M̈HMwqn._=bY-*E Ƈj&O̶o .lHPiT.Q@lL~ δKx%U隆j|sԭ.Q1-6]U+<x/3g"7.ͽk$IB_U"+h{"sJ~2èQ#u9lajZUuP>jAvʟ'Bิn Κ3OwIZpV";*NCXH PgD`KS\ hOs5DKUcvpV~.mȤUorxk|8 %Oxz @:. ;y.OмD)[PlyB֐ X@~=׎f<`]˸c PTѕ.>O OhU> ^38y}s>'I!?eTB6u +{- ~Ohefp.f~*\`%O`"쮔oIppю9 Uۻs(#FHT(V]i(O=f9i廴Piׅ̖i';dihԖn0$:ښ/ϷM-MF󋔶ä22oHc#~%m˵z"ׇS,TR[ pf uIͅ2j f 28woT RFj8gjoITcN-k_UG\kNo/Z6Bp!dD$<{ggGxs~z^@җu﹏=Ț 6|2? C_]f<~\ ϖ3L<\#F1 Vnmfĭ9tKfc#YYK {kUc:IQЂ,uhprg4I 0EzS|ɠUe1&o@~M>WakvJ.,4VvC䪵҇m Sv"0>өUpFA35MyAjOɛa 3% 7uu:*-.6)U Z#w^Z%fojt|o/;7/4I 4In A\@E0 ?Xz2~^K'=d@淄{;t5+c 9/cQ<(Ϛ%9^5V1X.|[%mkXQ0.%9nNHm" ;d3{nC7cĔ[V|w,eHXTG`KZohYJy1Xk&&m~=m:;-zU3[7! OGlF ^>BЕUas[ʭ:351uNވ<C]#rAXUz: @t!-VL\{#L%R~]*t~Q Yq樐xF[8Oy|yFu= i쁵GolK32*ܽ8gڣR蒊IY#b`WlmہF?w&N Y:{͆<8Lj9p^ aD7i:U5UKb>h+sU0Y !=XL?5¯9GYot_Xxn_UIth7%#Fn6O( x$J)T'VͮĒx D.>8\`>M5}3,1&qmvłXy\GJ!QZEy[~4XO&q*<_E=Z2 &Jҿc yf r:^o(hB[BD:WZ~t9r2|-ZO#>ėO9_ #F#}Ԙ:քe9km@]<`+ŁO2&bP@@ +kja ~p_wvn,c AbA&??\.ea% ģ.PؖWU\ԣ{G8DM-|nd 8i/\l.~- e,nnFz;˰ z퀂h:OK"ekH?C\Db-QUY|Q ;!^V?uJȧZwM[4s_1SSFN)l}=|X {:k0& ~J'DuFIY(B/-rwx7_ˆz$5?{ƪ{M-l+%\|H(&nZ /\?*~@7U./F!HIH\tK/ӊڬm$~.p/qc)ӪTtf*[wj*/gQBkgTH.e*ώS)j9'cE PLR#!>>e}w8S_ѯi*5h^MU*hz5a-.9F@)M 0nV#3:$ԋU^ZX"`QB( ?I:J׎|V"y>%XN(G!fGێ̮Pl5H1F;ʘ]wFo_W0Wzq0I[JccI͞~zgPcd2._UH)xߦV%VqZF\8]tn .L!x@{4eR S*ÛjrDckIS$bNKAd[e [BuYt{,,7 f{hJ¼!ӫW T${㥱+=*$1ww1;Ϊr]1[`tJ+D3 BXR,^7 sn0|n(gnAy%_ P>hN Jn>|7kDSE}3`"M:Z'dq}b7CpS.f£ U|auo͏Ta 8,n)p*CLxqkQ^45t=1`%%uB6 e5b|=[*krP1"9).+8! 犷ǞV&9IWKz4.{r-+u^[$SzA+Œb6(]:HVeHyWxhH˄ Mt:!{Ӻ*qhXXǦMO|o?l(G([~L u/ìoK2 }_沙3 23 +Z_}G})c'>Ƚb!'Ẑ //z)ZhӬ Yfl0Ip qb--x3"#ptSKIg<˭4FdMgl5* ' F =z.4"_(}_mt_ă +1:]/֗ 71u1K+31)\-jIvL*ĩxe̹-́uS1(son]='vB$U=AvΨF> 9:tKIOЊ헂  G~$}L(Ro+NYFzZI}H+(kDg4WM zYSI+Y-"iO`?ֆCKWuA-g\=$3e`@ԻR0F$" y] d;%ԝn~iI'Hآj:ls5BQH6H{Dq?S^6: LSAîZu"Nm ӭ4E+jBi!5*!.bZt9QQlO5oXŲ݀qC Gh3Q]Q9&)%!\iXx^ Qӈc)94gO8 ;֗u Vjf΋=1|X{ $)㐌ܥƧ{l 'ӱLϙp6{F4Ƥpl#|[;59~F>]ch;sE\+1?Ľ_Qڱ20J 똗a&U1٭|޷l}QY-^3\==7mI@Qv#(Wnq a)'lx^oU1lۡ,@)ٗ.^g䑪ld9@?I(R!̙%Vރ xr MCuM{Obw x%U 0W;*1TMo p&G;ܟBS.:ħ1oC/WJP)՜:fќcr9'C8KkR;3{z=Fv+AW$uꤓv*DH > P|'MD9y4og *?}YX:Eփ~vM'|Y朄/;#<ȃVp(zB %T!I+;,6XafABz@1mh#?S0M7-M|Jlp[TIp\,Zj_uR -Jha.Mb-2 ΁pkE ,t[P;=um/.2Ð1j1-GCոJ{E.EHra !K3f*~Z_IvIFH-OҋCĞ׀D!~rVK P x-&t)x:.=3YKo`l@&7JAA}}8dh ;:1rK}Zwv=פsC?\()Ta/Oҋ촄ڨ,9|JMZI\WA`g>AwTvlz !'y=׆}.f|g3=b.CRzy.A:{zi|\a[G%l~Nꖲ@DppF8WՓ_{wԹ;ATp=ev[llH-oN4c}nvړuⓜϗ=QD} N>m7*G0>cr@ikSQt E9{:BGf<w}򳰒4qsZ)gycdxi fa=Ǖe`#<0aQ,Лha/ɫ;F֤ :Uj>VpĸKtH@U8q܌`q[v &0<>IDh]|2Foɇfso^kC.hϘy/5^;EV)_߭FȋMحv+ K/{c|XlksP|*yU͵2x{cvnQH0<~UuQ+aP8 9#GuyXR|`Usmx'Qr5G7Fv!VAcgۓU=AGDh̢"V4 *w 𷖇5դdQ.pդ%kj~H6DEf;ut+/ (FoL;VF'385ZdȁJim遯VC1K]J}{ vjBt ~-Ϯw؉y3OqS"WLpWf 2M+\z&x;+z{m;TڐPr:tytBպ?6aR)T?ahmSێzFK6PsRvs"lॖi6@Һ?Ny +B$匱f9W|k60ĘޗYpa NS6N27X(=:m1DHcMWc5ruaAY[4wR]l_V+4ڡIJ;3"$Ƨ6t L,&EtمHlNqhUp 'QsST?SDC"I!* Ԣuo58SAkQ26~y!WzM=((j{nT% xo(Clm<^C':n+jbxo M\A^ݔkָ:fEnm7።Kn4bƢ>kYug>ӡī2n-*b *l՘ !dYES4|$!R#k,ͬ:UtE^Xֻ阫 ycl]sr` kɏPHAm> if<eNMZFefAzKcV9 .&Ye{/\1kϷU`rGG|O-v0jn\V~y\_ 5P N҇4HhY2'?+*-a S~%S[4n \iBL*c>9  x]&}aUT)6RYm[יSPȓh>0::2|Q|EkT 6:? $8}sۦU>C1#M2U;)ڥ&x찘Q|qA ,i3,G2òie(/bmQ!>kec3~Z~&=ӫ#_9$5LU0.`kQvʼnWا"Ui@gDi|bQ5m> eEebj.Ge jH䞗ZCp*5=ʣ1 9T 0X`qRXvDeBеUtO4c iy d{Z`Nִ)&_H W IC D)|uBYɌLr_BN %sK-?F R2CΘz$m0f ''QZCݛDOjE\^߀?{g8|k.ۯg`OHA#5JYD#"'IܤLP۩0Ky9%vP#0> X7+h|억7Y67\]lf`_Gl"wSi,\{%JsK^ـ &xK[?h횯L;[\3i3#1+5\[MMN/@};X4b< ٍ>baaj #ex URYW-#j*s ē3$)_?Lq=gG0Vbw*IiŐ{lX$OtBpӓ'B뼛QDQ$iQB dUHHKyl^XZ̜&OHmJ,k)&VLϠ o߈.ul>$RH }}ء)y(ʛZ(U'x A8ic![sgUHV9,}-;JΠ02PHdI_pA+.9Ebjаڑu M~P?l_"R ]aU[ 8m[0[c](4 XP Y=>͏?:9q< xDa:P#p/SM%ss/x$3sYͰ@ K* 3=u#Eh_Ȳ8Id$20ң̙#Zѐ1J2uP8KϝOw3%P$2|<q<1ŗPHQû+uHe*LQ*> ٵ?u2ɡy sQԕeH? :̇q+YywI.=OרXӹex(4|7,d#P2.E8,$3R1i/Q^5?*K]&ܲtz{ibФL6C$h)pS\nf$k;]ޥSN4\` eJXQU f>ַM [ Y+*ژ-AǺUWym9ƚlprRd&!5&0G$m*e!71*Zf,1Γ/3v{㾁ޚ6Bs YBɞĵ4I_DOV$iل'^q3:Q ־ ;{^`I氎f{H)j+ȇcɢ"#.WԊ`z.2K,H` 2ZidUH~Fn[B-i2HjwxdAe:k"8 !nb.K~5psQ לE3ӑ!o"w%:d8EȲaV+,Q)ܺ*PZM#Cpɕx@3KI4rAsGHS4 .IUhM^:L8gUƣ\̰ M5>iqWDMJ㾔^ B =a7t_Д.%au,zn]Xu;#JCsJ(5%1\~ !Zhn~T/^$! 9{sR9 d~r8T=k7i}X6Nrԃyh0ms9+z;^Ԕ"?aH5_Tڣ)!m߾cv2JN2 FL#X1L鶼4=rB(G8gHU)ӡ+|GCyH *ƭƀLpEYlRZЫ .*ɺ"Qli?)3Ԛ}JP"uTX fPHkƻ H2Oi̜|EIז}.y?&-}M)eoY錟Ѵ)Wh9d@ؚY [C:\O/Z(^^-CFČ6]7H[2% 7hvwhTT³q @\w1w1cݰ5QnyIyt=1ȟSxwQ"kX;s:jjz0WU,щ#G* !aKE$v1'|,WJ :R֚}B$>K`]E~CgfY*'G^)6* n97*th p.MWC|JqQ"/XzqgH&xq+ ^}L:Ѝ(dj*?;=bJi0)d(Rh\#Hp::6_JBPF Ӏ !QHelMA= ʙI)5oou܋(Ok⚩ t+썧3纻^%?ߠ\.Bt55&4B H"#ܪI$d3[1Rw nxѢT44M^T"8L*R? b^ǜ Q6z}ZZ3$ ]llĥ"q4$X_W4B>!Ə%'!Q;3X> d}c6pG5uH@LGq*-u#6cD8' j~V]d=eE6j*(- PHFg~m=;x4h ?ݷCtBQ܉ ?$4Q0iTXI0 PqF_g)>uI^fi+cAT- ֳSuwxrm )<˾JG`^ˇ\_Z5Vܕ.;:83 J`E{' p)]oҍl9ýa`Lu-YvB+3A-!@TĞuI}bto #OK>lo rA6jr >R^kGCsc(+)ȉ-8h9t{a=W+bbbͰ6c?'t Xvnq  " ;CBl҉\͏tH2_.tи޴ܮ$ ۵M2jSᥔէHՈJ謜:CyO}.8T@n?fwS1~VdH4/h*Ӽ;]l6bDBvF 52ŷ!hk^@@: ^ 'gfKHԟaC݈c-fj#cE,;*Ryҵ& a1F-4Ape+%ވ^j|Ccgt6< Tc!|-Q>p!hv E?Cvoj{풵a nEDal:BTP_T(2 {UQSՄ UkW[15gwGAh24˨0gHXjv!+W&UUKD3αI91ޔ{ly bQy!]{(2jƹ]2)/hL˶TgNK}=pM.VYZTk-:m _A6|WlFؖxdmR.";/qiݤ$A-$:FDN 1َL.*Jl' >MNja͆b+L5ԐlO&-@x#I-Sˑ~pʣ'nQWy̙(ƣ7O YmPI3Nh$bcϱ?Dg: Z6\d8/sK=]X[W ǡd-AsSA{2' 6M&|Xھ6ƫ)S^hh|0qqx{տ(ƒݚ䝗A7G_AY~gܖ٭VW#l dN κ'GCY2-quEr%*ο276u6'4ϭՕ6\wx{d2L_|시`Ʀ=8rxߏ?s}s!n(-vm5v(`3W0&pPG~~[tj:L ]MTW59qs2f9l٩ H8}y(KQ)]ڧ~> &':<" VE H5ydв}ܐנs ."=م3/3]7Pat7PFwW=C&aܯe{L :Gb,-ܒgw}H]TWDs[|$pG+ f2FʙAK &~ӐRό| nbj4Ɗ9L:QqOs.YGt.ْV0T%ܳClPA Ű5"& k.ZǗ1ѧBV1,hd,QhՐ_hː\vo$as3b`Ue.R nB] WN"44!*P]Pk݄#OP5VÿKV{l<(P܃Q -֣X`WVjl"ah탠n1C d߂(>昺T1^(ӯPVk˲5+s$YlQ#T 1n}7DHVRO g ЖÕ,W9\{;y*>t]ʺ0bϬG#CZv{}sl/,!TUWsp۷({)ēV.N`(C0Cm%#3{ɢǞ_<ȓKOƉZb%g2IjU+/JP'h!#Y # X) !~|YI7>-9ٻƩ"|b I|RpӉOC$SDM9tG}叜LzV~Sr[<=hӹc0&t"U[nѱARH+Pd_U- endstream endobj 93 0 obj << /Length1 1520 /Length2 7553 /Length3 0 /Length 8573 /Filter /FlateDecode >> stream xڍvTk6! -2HCKt 3 10%t ݍt TD:DFykz֚kk8 0uWJPD(P5bB@('  LiC]2Q*"1 CtETp(@W튀qy#(2@x"ҒJ.0$Ft( fE` PJ#B {yy ]܅\/8`s!=aPz`؟ qLڍ]P^`$ 18!0;&!Z:}7OΟ_{;_ѿ G0 _D+& ;m1ߕJ0s n(w!wC܉~է G md^߿MR1c ()-=_M`"̘}\v&`p;EPHvp ` #Ɏ1ĘGрG@D__VyA] cu?;ۧ EA"i))$w0*j!\٥5sňG㏁ #!7.pgz0uL⿩?gV{W ́m0qS,M 33puU"@0qEv0%W IH$؛("a `ع"~@X7 4@7 ̼`( _wA[&o0 iQOL1>0䟆5 @"1c[}`hh~"X~^%y:<㒌 *+xy2CsKK=ADka'F[mDs_}Qg!#hYn v6gS)2s> t]h̖vIXӘAӜYnQ}GONQ߰j'+\\n"h{B5:嫼M?[RM@1BygK{h9. KB̛YEtyԴF"O*&A|ENuuȸk#󊞣GV@9R{cer=Ԗ9 :Sq fk^k|x~ԉCo|{ 3j9?w8_Rk -zwEIe- NPͷ6 poj> 26yݵR >f}=s 7zNf N",0w4+'f<@,Ś׹I''s؆H{БgacLEF_1mUTlɺǬrM1<L9ˉh?r_~7~fQݻGgȏ?IN4Š}%*kf7@E6~EA ElqAIzd zIK4ɥt.Lq>˾i޴WLQ.}sZ`-n,{ƒ e+TIR$bw ͦRi .;s<jxm$Bt|ʆvNLR.oλG}m4,Qy2Nh^|o65=k>P's eN@i(F 9ٖYp4ua홮~U`s~;_>!jO(Df'p5WHj^-G̜7'ڲR"|Gw^ZLi2VZC6\g(Wt7~S{Gg<]s;1"7K6/ӧd{mBSd oe3KۤJ>z6%8fH#F~6^` 9v2L!:`*ښpgM_qhDgfOK 3j+@xw"E3yI_LA(ŭRD?yW7@g!+f%j(4ԌS\3>k]T.A. MC!:Y~ȷ8hNZ7#Ki *zoƒ{X؞ڧZߢ+(I҆@\cbG"O .ie烃;\vY3 T$,m/Q.bެnut{FO`ӦL| iz\rl%RrGa=,%#@5 =x1"T.? pΙs ~d6-^l^4")azznJQVwcud>Ŝ Ӗ/TQRolA_ 8ڴI7J9RS RhP0͜Ӑ, UUJ3_]{_;J >{vt\wdz+uU.X˥e<*t#/RE ^#6 !nj׋;a1I1Fx5*j$ ߄X7-+Ԡ&fm:2';3+MO˟D79l^|誳&K޲{v}wy[^h+};[F˦Xw>\g uh8)b5enqh\ҭL1%PN[iTU#074-mW̦Z=5ɹb}73/aeX ?w?YvmϧGyEmv, |^P+7kE7Fh'A[JG%T u[''F.7!qy56 8k8QA[6ڕ>S䆭77*F>oݸ{sdNl`uF|zmo}q>qmgzF+{&?01t™&^ƒ G宭.t+6;{ 7Z@K(!RyMe av2a7H.FV5[Mx_F_{`^f tʼȼ ؉pΪT8=T/ldcSkl{7ߐj(s \pjGNayr s  /^ZN|qqW ;"&8v2N؀Ͻ?O׿ wuӤLR`ݺ/y3f9fˤƆX3MtLJ&ce n1e*uyOeq0єJ nD~6 ͕ͽ9@SbRםF#vQJ[e\Fdyo-9bm>aZ,/DB_}R T;Iz/DnRO/XemL+Aυ@</i Cۼ?(ЮeǽWC',6W1)Q/يޜ"%ge^0֊=N!CRTW2 гȜxȖ33^ dG\lҬW\χ3xx{ 9a!/o 5{JU;(xwx8CqAPq>"yGt l[|"yZp7`]|s2mHM5ލ`G)sP}B5ՐM ̸tRw]TLd Qُ*-WK(2mZѻnn]L*ɠQ¯Wl!*9}6[óFHo@\+oD 9KdL]N@⒯ ŚʽnFb7):,Ӂ.=H"tw} `6.G*H끑~`tJW@.X6=֭ ʐHDXGa=Q`tLOn-I"xx#wTN2 y;w Fhqߣ\ێv'ΚA},T?J~I6!k[^WvkDD R3'R'$Zdr>_I$$~.>7 0]rc|T$q\aR"YOF+YD;i@^\}&EPb >[ṛELLUzƏ&}h?e[߅Xի[K(S[cTYCi|REmܵOVL:?½ͩFkPgʟ9Vr$z")G w JZHɛ=^d58㓗.~P;7R<4y1k&~@P:FgtSmҤ^qf SU<[Z/%f@*.oʥu|ϴWI)pw+_ ޷&bNkXWnUʒ-N0paW;Nn'=YOfY죗ʌʮ*"_qyjU>‹*cdSfa]Z VA8E3f ꦵuz".2QWgg_ǽ ;49Hڷc."aCZIvޚ-=e@>9hj2dnysX eBcV=ֈ8j`dк&7p@?Xվ%'"Dp"{{g8ɡdp3dHL\=C'3 O% Bn{~럦vfuf~+90]5kc 9#:.$m}}dWqh6=XJ!H7'[\O?LBxqTˤELߘø"BT[2'[J^5=wCQ}ҒBsnf1`׎/ºb~Vlw4uq@Kgsff5u{Te9^^hZVY6þң m#wQ| bXwdzkN J5S=2B )vދf{NتY#3S?l26_xG{!S#,ƛ-SA?{)NX#V~ICK*jW'$Vy û?L;*EN1Tr|=uUQ|>7='9niƏT^\U'qdQ&b%WM r a'$fꭃ^Dc.o)L6)_Bn|g9r endstream endobj 95 0 obj << /Length1 1575 /Length2 8342 /Length3 0 /Length 9375 /Filter /FlateDecode >> stream xڍT6L134Cww7 03tHw**)tJ4HwLJs=Z߷f-f{ &: mIk%Tw U 'čĤsw-a҃pHB!2*Ppp@ 7!U YT9J8 I sHf+, uYAU!A}+ qrDڊ`v-j 0@ 3N&/6 <aVPۃ xHVT;Ce{6.Nw 3 #.BOb`r@NRyhܬ\ann0-y,ZO zu#w@]8(Ƀ?2[; P;3_g3 ?]=T7XìP[?P¼Ơq@?e@/k?%WII!<<n>;w*m_>L_{ c!H 0& >gq#(7oAr5 g=xCYU5=:{0797ZneY^2Gp*.tep9G}XN) BX0n>~z 7a8 r.6W//JA`0ho? m Xq{8xr9 \#@? 7 >$rõA 9MP7 gv a%f_Rҋc}Xti]?wֵ  Kې%37}ķs۟j1#4nFכqftߖƦБu v@ܪCO#«S޻`ԺF2MK8 \ˬI2z wj,Voӳqœ{Z6<|_]NX(vk#g$7"F=%}+D:[1s;V)t'gFl=諯r;r3ohDy? ҵXMNT'V(Fg~J$0ˠǃ/b^=uM%a3.~=ˁmlWW:)'x[KoHپ*fku0SEܔއBUӣ>F-Vqt:+.,Bҝ$ e@Iߨ K┎gk[gޫvcx#R'dNnzf*pބ -DV}gYizȮS3IkكeٯcAJQ $!Rmkya߳>L 9jPN`Kk *'5ndx2%)ƨ;Jdg 8a;Wq ;mK+pIPʩ<7j ՁO&LK'k~SUoӱNw71lˆ>z;7+ a.crQ]{M#qWM7Ϗ u? ;>Jz^t=քh>sT LwOGFZv!E瘈+#] , Hb +Tޫs~tE75PizvyE'h5;T-Hy@&B'f.Ld~ Pm2XPuGmd9k+|W{'>'obIU Ki;35/` j!', 0.f]NR|`$;}nS=]97>EB,nZ8p\b8HTE#u8VԱuJ{[DDGM [( v͕`qtm҂W]Hoz;zىԹ_nRBl$Zi |GݞHF@:FO`\H֝Ҁ (r]op/ӨiF&V czOnB.[6i6XK-7%{M$1,}Yn}g9uAGSLJU_U⣵])g,m&2tR%oŦpғ rSFƪj_y_hL~>뺠_ep@oK\j2s+VL>zA :{[]'BUIrjfl"Bo4Ñm~snUQ}gʁ~ߦs4!ժB >>;hhDkB38s8eAjLįtEOͤtB%q/"'!L;OzyùގB0aC?IѸU7˴BE rƱdȠ%ڥ+LjhWҤtX.ي0 rl:3Z.Z|CLɱ6gV0Aܐ*.^c1}֐0c[`n!F;sB1E6Ɠ AHb3x޹1P:ܞP].ATWц~혏SE"3I-φ{,v霑0GG_%~AyԗU7bs5Y?N QOLՐ$Zϓ)$7a{>Nc)%f%dJn_0jyͱ咯Q=-U{n%NmZo;E>ÞI U\< {(>CǨ)"vRC]1P]mP{A>wA?dп:İ5&3֩l>wiGC732!{E?|4+ zѯz5Gt餷%>w(IV)vYMܯcQr ޡvzJlU*iQ"y~Hq)Dm(xݧeG̲Աur""ݪ +~qt; .V(z*ңTmf$}"1;d2cA$}B~xUN^k' ɝb> F0T'EB%U;fn4? lHi8S. +ø^Y=9Oxttf0z8m6hvP\~l.\꣫?3LH?y.H(.]+CIf#5Ȕ>Usv=ኙj0mNA}8Z): W*Х-!߆w5d7 …N龻`Fs!҂VEb/=}g,hZ<.-=-+d2.\.裁>tu׮#?av;!G:i:cLZ2nw4&14s3PKKgZ&f%\!:7c+;[մjǾ+CzZ ,VS[+VP4S`IVM*- ّS~e[ љ;ĒXh9ݦpX#LE u޷z{CC,>ƹ4K3ɡ1-:]7!γV/h%y^Nx*L=UُN,h&x{x2} N֐>cۧPk h%7th$P8?6;+Km.XTѮ"qK̟E`1S>YVN'bΝ}\UPӏt$\0'$rڟ{ַ*g4FsK?fI 'm>Q>aԆzqh?3.mg`ZVR.؜ YcfqW񥖙n1wY㜰h:uFFmgy)E% { >iN64|a]V 1W@C %*[ƅCEѳ`Wm8WX# fUHEk@i\ #A-|zrsP'V4D%-`Ja BٔdQhPҗDž ٮK݌[Q: R>H`X*]ڵ^!|*q*0ώr.Laih=O|?vE|>vnTU,\ZMzPXbJ2&|ƌ: 䣆\\7Zo*S,"zBJȴ]wiђʃϵm%T4<9SF!cd,SGrĠx r+'=֑dB2͟q% ;(BewI9 [K 8,le~)9Rx>U]]lsGgm5T{UPf%_Q`O6y3Y,W!Qn2"Ų-Y n8:C^.WfxJ隞|߶}sU(?Ҳۭ-ш-Y:6TyVgLURWk|OWfX*?NEs ET-[8s1{3c{DFQqnrɯtk5jMu2 gί'pI3<nqMyw=EAVd4i-a׀u 2B[7knzuɅ:j!q ui1&V| qWlvh\4}9(Ȉ߇Zڡ{n:g<%~M,vcj|ǁe~# Zl湜"8j[(E ]1zjww_q=<-=c_SxViՒ7^Ϥh&mBAڭ`L]庳F4}ǣax)P#8T9Ȗ2w(qHɛ#=!g]x}Rp J3xi:V~KȌzYe:_;hIaIAlBl+Տk!8+8p.G5`e 'PԽ?^^Y/:t=J_Vͻ$;' 3d~EA @`z%e6<-9BHBz0)xc ){jx3&6mQ,bHzc3N`WHBed"16ՒK]sMFS ! ifi.)HL-jbuʷHfn|T^ID X0]:}o3&ơ>>۬ %Yւ2.ڬ# B=!sm+U1ź=S \дT/P`NLZUi eLy5<.VȳJoZ| %΋H[w1!zg*rRO !65 x Jhm]r9lӽD \W9-Y5ȩ0$` V "6AYGGF'Oe}FS&-q6gjG,(P~> stream xڍvT.!RCҍtH# 3 tH4ҍt !%J+]sֽܻk֚ywyװ3)!l*8O( x/@!BvvC(솄" BuJ Mh;b@ @#M8IuUupr%$x``7- `-`QH% A\$<==A0$?A EA`$l=. 3?!;E6@أ2MPWUsm_ _멬XtU4[DU ;7NwQbE |)Z+/{0 ן@Oܽ0yݣ4FBA伛8磣QCQ%0u_ "zY<lu&gG:pk5Q?:FQQanTxu+Jb⤑DIFtewhay- kHRCN9?x;9ڏ(g ~%~ׂ+H{.evb?( :zyLWl]@:csUY ?]r o/pp 4O6Ȳ/V|g97"{mF^}}9!D S:X76ODI3FSY)g)UIL<ߙ$ZWSw8˼oTУ?=~7dp|zv6U_o\Kg쮭9"/!xxZ2%:R 4VME=Smi-Kdc`0C̑R5|JONdr}s/)߀4cFqLMB `roҡ[ T k5!wFNxVfy8ZUIpN5b[%|W54 C:λ O\%Fમ0b}'޹]c;+[?=)yjio[/n!]7n=b;I ,wiYޘvzDajrW19Òi=v>P>D{y;z;SY 9.X=zܢ2 _h) ˸H=a$>N3+a e#QX1w_4XZƹFjD?{tyRvnk#Am#+bcu'^gM(iTUHipT* 7^E@]rSrݵ7CYe*0nK;%d?]yS2G彚'4Y>ء2!QGbɼ .HDi쯡>e8K=)sXW2\-70bԾuWMҲY 1OEȊ̘P b i7,[in2Il3(=vaP@`Rܕ4VUz{Ma_V<[IBx]e#h:@f̞y6VI%ݡپ5\:qB>^ބSh<:Me*/hH&75uGd#v|T(lŋIQbiLQrLڟ<՗Գ:{Qx9yn }_=A'i~sHX=#yUľ / Ԧ7ꫝ~E%9,ܻA Ӊ޿`X#I/e#qF\_:y]X)Q$9I|jX/J}0+?3(9k0 "~'+e2-O~cSS4)ג,Md'V ?,*F->W٢~Qt;*0te W.p֟.\V *h<XDEF\PʏrsTZkq#n)޲fI ǻzм3 4e5߁i mm| .UAzƖ{2r>)D{S5Z8&h"G̉էBd3|lIϞO-Ѽ['R ?5AX&4MZ<5tpʺlD4ʂލoq2V?̐.joXZ5mدN(8eu~)C/p BtvsPpEKbf>fb0DU7g ?e1BDywa˟l_ kĦUM+Ip_D!%\PqVOqT{to]S{sQ^,0x=Vezsw= E CMr :a5d8Ě;luΜpRoN]qKjrגt|R%Cul8cڹ~m8i"dQݧRG2xM٤nfx~_ltw{G}t=9\S8m.V597n?59w rvfN̠,w+]][̫*(G cwiM =2۾L\ʢk]:ɋ  InZx~iG rʔd˵?edPjPNWyL1C65q?RY噵"K!"jLd ,6TیPȲ4:Vd?50>dN CXzZD!{횣a䷧|jپf]q1]јE!ZKxLef(Dc's X-|#e f%-4273fka>i|Κ{¼%k(J8Z[#$:g} AK}UKNSKS^UTUc'q.fH~Řcؚ-rS ^RmI5ޭ 0F)~mLW!=8Uom>r+ZI2'i<̅ܙf&iVZHd^.l┼~6Vk})s.$pz/%y[#KIQ6JTo bb| endstream endobj 99 0 obj << /Length1 1357 /Length2 5945 /Length3 0 /Length 6875 /Filter /FlateDecode >> stream xڍWTlS@$T1:6QBc66CB@B 4P@N}w9=Ͽ{LHD"B`a,@T @@9#ZP^p$BP0'SqfH@ %eR @!% P]$ETCz`Qpg4.˿^(,##%Cv2B!n3$CcW{ #QΊ|_8` |`_ !ߍ S.p?b3p789x#a(.7LG`C1c k40 Bp8`#M}a4- Bܼ8q.T1@p՝@{ {~u(+ nG5; U:⦎VWG8:jCeQ-s HJZ0P_ͱJ/1@ ,P{A|`4QG8 p9GljaNͣ <0[Ho1UWUH _H`1(_UA8!2M_}޿g,C$0I/]7t?vsZ; Wo4HijCW#?:h*g h["3Fz=(!0:G *4L"KTBA X ܊q7 ?GCG7"$pB(~S\ {~ )Bh{0 A)f&Pmǵ*7|ƀVgPOIjQU^_{4˟gɦ#/)6UE~S\y%32ԕC-Mm\HwV ]쇨eI=ʳQxq`C Z= kyCl[ bK'~^\L}W]K׽>x!c'T߲1j]n,/3!N\bv{){ xޜ"FTQ Mr}ŁŕA EjRi۾b#ȴ-|Z8w6rS"gɱ/$u=٬J]*R쏦YX\ژ}ВJTEO^Nkn'UH~Y?]-V+H?<5+*ɐEɖ I+j"y X~%]y6Amo^^gHxF`^UH!5}R@AUxvV#kR%+HDᆩ(L۾ZHې_X^=Qy5\gBSV{x:zQU+^4Fa VV1a%?OiMv\u3@`%J;x\ZNu^W? KJTwBZ\Π]=s B)E;K3VR&,7S*EW׭<_!\ȥ'{12{{Nq~U;{/ˈ هI1u}.T. ]5͔H9vz/[h"/I:]H";mvX=L^hf\ .\p:V+zmLR1N9Ujp;[),x,w5!stjh\󺘹|mktI:5J;o^"-cJ5yZmߨn>$IOxLRz\G"nr$4B0$o5 !,*h2U\;"p:v17H`duu%K`Pv "sޛ] 6|g @"tQ:糙X  CgL` *n1L)& Iv%[w"֮`vrxL=1#J}fFG3oK4ǠkZyw}|mؘHhcwNE=Ԗq9aA}e#l-}DH1t{fE1SZN6_f9} dzD.HGKͰseQˢ"6f|.˨Kҕ*cWwؗV:y {) jZ\ʎ3]uMA}*`0X=xْ3k۫=ݲ+A_{:29^8l\3fffrzAW]&6*$ V>g]p_tO/*uu0V~jeʷVן!+%e NλpfSI#;TTp6p#uRaގ NbUjx @O?eHiƶܤWM<)(ِJ!|rї#U\}Bfuy#i!X}yv7ъntHtu:_Z__'_ȖfoF%o`I'sS}wJ0&[ 6m--5^?XLJiar@^ R-4,2f;Ӿ;@ʩ8,}Uڒux\n T:>Oms< m.wlrlH)biK k U{^t{jec%QAu+ f0Dտ,&K 0XR滏L߱l,8ڜbpVgWrS8T m I35UX6?*'QPByΔ;[E:W1(Tԗr]^@/ݰ6qV'tk'LYY>+ۓ$ ԕK]vccg J9 Ɋeh&W'4To㍩a}Eeq7P: 3,9Z-RUr&x348uxTk\+ife#^6Y0FVr%" ;aýqם"15KR*o#m1T(d Rtv~ȉPu1WC)͊7LLdFh.b:mwuj$".㒉ğvM(GeŔggcIޡ6o^9|H)M GCS+Ff*dUvV@Ny셼2GKEѮwl '_|"2')*W6XNWÚd1nzn CXK~)vWܸTlOH9{ g'/ۏ)ƅXӍp iNh wWxž{Ծ$bv[3zۤSݟTxE?,z&?hepD촎2ҋu%'}L> T'T98c7SQ`+ħn0vy}7'4!,} S4%=IũS} _j@{p㐋fvkpCِȠ8o[/ Ր=N0Y9;q=MJ$|.{١>5^}l G7c.ۓ}A Cjb6a9}Ssi* KToOŎJp*Vː{kG>(1[cgws7#ԷK/\XbXއZ oj֎ r6(TTT!+s\rzv<pZiRrг|P<:ewm [/`#(=/Ŗo=4cx۞z :dLdNqNqp85zSM!R-Ya\6Ƚ)KM7fA8p(3zgKk޹d̷g5">& rlZ @SZn۲=Mo/Vzcps s{wdL,g.֤G6x~-ܹ&zXav|ՒQ+{C9HD*a{VDMA#CO"-%&X6oLWWPGJf3*Tk@JpN5ϲt;_T,'J5T>|ޛԞn矇 ~#S~ۀv-ѼnۛwD6a:oU So¶D4Ts&}B+<%و1x@Pl@gF!tⶳEk5Q_4+)>#9SLyGXf$q¯ګ,h06#u5JXCf4Dtf[\G&Nsw`7;Mʫ33S!V #7P[u</-LҞuU\Aji_!6td_p:aܞmxV59/yi cLVUMx]ndk1&7A {3aOy`@`7EB\Qܓ9|5jړU)X"W4Ͱ/C9 endstream endobj 101 0 obj << /Length1 1490 /Length2 7225 /Length3 0 /Length 8229 /Filter /FlateDecode >> stream xڍTl7NI%6n0`1:iABQDB PRJo>9wvv_++~}ih"vkQ(Xg, E`1/)x>4Jp(A1X3=4 !Rri90(-T!z@4 UE{z#\\1[sYYi@e$zP+a8&_!ob0r (#vQ#0@cU.P.L 4uEM7<08r{wMupc?ZB@og( FzBQ hb0@(!APGġ@ e# [_Qǯ A`rRE#p+?57z XQhT3'_O V \$ ^@x+i' :cK"@xC[o 0 @d;`, @'[,(t@JwTT`1i$G1"6 ,KIGc Cp$?EhHG_z,_}1X롱_S uՃ;!|@;r Dׂy PpC׃nh`[.ͿTGNKLR #J`v   [^( 5O [Ap/_ HAh_i Mo@BB,%26&_`,' :7v[ 'Ѱ^k9VfY] n= Jx9}>EyYPi"x QLSQYȹ}f(ۑg5l$"J!^!wqux |e( hV̾\1Z})uHYqB'\6bAã1+!@fxqÓb>La+E}Z7 Ʉ4CpH10B5mŢݖr1c'BsVmD87$!QrBq!JTr'=mgbCGNmzx{.َ(ӄ)¦P{oT/|՜袧e0Y8Jt-4-?ubTh.0Өr:]1;(Σ;|PFD&ud<}+wSKl.k΋yWrThI/t`xenWa/8u`!JPp/Sg:'H9|ݐOJNjamjUe#ɟ7RyZAb  mO?ibrnb"FjP %Ty=jDP;HSzlWCůswϧH5L)״ꃗ~[xoN(̨vUoH~ J;/JvB7S<ƏABX(eXdP ՙE$F8@}ks9+>8e*+j\,/zzQѫ0'_pO[猵l>FY]  ! ?W?q8'yyx;Ln%m77o <6 lWeΝ;/L{^"enwc8<)g3.bJMޯ==m*nk-&Y6vWτmx|ni3Dp!YEݧ OZ.)+wbVڦ$6 E*%ߡМ (ꗔ}.Y = :+8zu%O~jn;ͧRSY_8N\LJ_Q+ueծ\W!ܜ Q?4@K05ϯ4zN*gWmqjWxo扳=/0[s$-Jnp%>eQGgZvh66uX6 iD5U_ܤ͡ЁC.`-RGrkw~Pokh!WěQhN*i˽֫GFru&jWI>2kmJ3rHQhW&oP%BnmWƞJq;ekZ_-/MlkM{8=ᦍ̎o9!MB\T1,$S2Fd$dh$9+$_]aCEhQ`8 rWs59I}jccn.Zi}-{.* Lm z Fa wF"c}1z"=ml^n8\WG>h#)'kig3mgUcPs56Vd}'+/xPR_MdpPZx`ZEh+q :'Yeȹ\pm-m\G*d{k4C2涜@] *j#{O'(U^~UlG$-TB,Ă ҽV JKýX/>s*}:,"R*;i/<-_n}8@>Zk꛹(e1N.Xj@pXO/Q ~$T&B2DA('<o|^wq#Uz(@,b?ZtCav`([ tȎb={- /n.ClOHth ?R`AƜhhEߎOO֍Uֳ~!:SHgB@)$a;$!;JJaԱ+nx䜆Р8\~WcKJn>A?,^s;.Qp5"_,M(0O4|2AmnUFT2'7\иBP2yV8'\.8aMTse |i!^&HGd5LSnW;o>^yy8ہV?3=Q홮:bxgOl8(ʸ'|Vy+RPsnޝfqSKgnwizuftwr^d5T6X+a`0yuxwohXJuG&kI:yCL\"ͮ&45 b=_ &=(S~Pns~/a1ۗ]NS{ ֯$jW]y>rkIet mOw|IV4ϸh,BFT[d>"dPos+7Fnm; i+\ڏZ2޽ >B{>,sҒދt8?:VARwd6mT.~ѵVݸbj8)Q^>@.x)7=4p7u˨TRqG0vnh=텯4U` ډ]Ըo KnZH8Kѕ'{gxq 1K GJɏ=Dx(hk-|ufdJC $+/7s㠗UoC+z6.gSf<#)GDTq)%+]an~Q 2JQ_!w=^jkd萞3sh8B<&!շ.|FHjqrpʦ$8QL2_dzCxGH-62xʮsvҘ cNi*bt6]mI!_Q@xwY9 =Ҙ չqbVZ Tiɚ<:=㩙  i %̷/}aFTO&ҕ$>>)xGdl'eל,w&&e*Dv( !9oA8zfD|exH)=kŐTt]di Lg3?Oz)l<,8ߤ5H2uǽBCZjb;']tfcԵ `(ě:zVOKi4z^B5jlU+Q-7b&t> =i]RQBeY#U$mZWez*|Fn$Z=IiںF牅eHerARb98ͼˡ)!+f}?nprϓ}lTn4Y~CxnChQ}!M[ɵn3IβeHd *~FTYkNO)Dp0+] 5;V16Ik/6fQVg'~d /gn'ĭM;8܏Q'[IX*uDa2s-}؈7۞j8ߛH;/۠{6JҡI$B! s/3gʭw޾&=(g͕ =g*OT㒇KrEzP6uGoCTZCN NzHCϫbYcmeX-+K8}5#iH"ͻ*E *䮺 ZLH:2s5_ŝ2GyEVe4Fp,Ew(ٴ%o*tXTɊQF쯭z$KB[!_TWe3؏&|zֵ&B9F^t:rzI$|Aҡz}XN lZXLSVS)kgZ$0^[^x~u`U Z,kv'S dV //jIwxUx*6yd7|RX]ʉпEM0Y"0PfnWVɤM*TY.5Ua'xF}Ue5׳_hx, ͉{I5͕%*"jF>fnd O_r0K'>l0&p0-xw{&=zX qJ>y`[lMɦZt݋>{6ypU4w=pE9 wg_T48UL/S15DU>k jxla.}C6EP+hbdۤbh'R˂@yB]pNY$^2 ůAڠfowtӮM)IJ#5`h狮)J .lN\Q4eϽIV}$$LD-\9ঘ_iOIe̬.1~ul Cuzd~r|ô!q)ZqEQxdooBEMm Rv[{g O=E|6{M÷9= :1vd}ؼӬy# /|&K=o# uӵ5ay~DdcРĬbb?ǽ81NsZFawzЛyx-&Ŝ.B,h-KnUPoP3^P歗FRrA K g~wno_{@ϓ0oQ f!ᳯaI&{P3wG8K>9Kef63\)+fSpCW^Eyjb]uKR$ghދ!P۰JǾ#gKwzY.fqYZp@)0%Qz`V[ﵥ" Zk"+d < /(p9th8K47D/)n7<1jQژ||/>{\YjMV b1r ܲ >]ihKm³.ǽV=LiCOSȔw3";S6ُι|w*u?u=CD=kOP݅|3(Rk!kT{e endstream endobj 103 0 obj << /Length1 1644 /Length2 9453 /Length3 0 /Length 10515 /Filter /FlateDecode >> stream xڍP.;8ipZ\[q{)^]  ťP)/{Ϲgޛ$[֞ &9H cs 5윜\ttZ`Nv C/ 2=ɤ`OfP+B.NN:8 evA' =eh qH؃fPd t`Qspwwg7wawp~ pl ]=Oct-_bM+3$-@P'W%PuA2Vˀف /߁?ffPO0`J0+ j of?) +0{_ݹX8a..`9~yd= s]4dtjupzuC-~`ȡ ;e$[f x999aa;#~_oGGS _ 9|o,09 ;d~3`D< ?''nY:@!.,˟txqظx9@N~NU߾ P+_>ҿ vLXorrZ<}iݿ_ȺB =/_]aOWvx Kj`fO; .`faUk^0 Rsp~Pl@N=mӣ?*wJ9;yb< Okh `;xj`{|O-!$0 8,xx]=? pX>>p@R OO9]'z"?*>v|r=%-\^?{4?Oq~g[V̝mkTtn{&696d̷+Ƀ7d_{556'ܙkLl`|'+ܓ@'gw ClPurQǿr+_R߮{yW>eX2MgFƌwlb /gb< ~4w*W7J-.NRZR} s zoɝEYҢoDm#kI@זƕ/cz1!FRDȨfE_M. GUID6>nԀԆ*_Gkbw\ #_~^Ȓ_wˣ 3zīq &=*2ybLR0JցLbJX]%1Rr~AVI&xX B Ɔg2k J=\73؏Wmԡt*- hr(=ɝ_,WUgqfAI.{ׂd B5ܛnWtr*}Ĭm~T((6#mVÿfG^jp~c{P `#6k%_Q ͝ITLJmOxC^7tߖ_܇rLՐS"5zqScothrUgpTȆ RtxgU@#}QjAV#b*6̈́,&*?\p R)׮{+ ~V=ڭ l`wksAۘT,WDc E8Mǁ6NO}sL۹mŠ]P#F9\pXvoysD[?}c7֣~!rAC.d*ۯH(`J(:G(ٗkn Z]Me1E 6wBBӱ.|xպ0 &~6W)TʹdЫ`{3Qz"=#ȷ L@p5(i'ux*a@;pD%dHrLrCI?AJS)"p8\g+В/ʇD)̿Jb˽k.&(j(O &BսՉHQP /~gD;؆Gm<4RS W`-!ؼ8N(xan>힄պv;zt<:[]s}i}VNd'>>BkHa\XRֱVr/uAWOzxtG|3* OK66֡LL` 778mm]ub)?c8Ŀ닝_~g=mvYћyHm|`˿ŝ)M%-)_[XQT7ӷ5G4Ib4ʝXWmtL溊5"a :0t3FXy.l7I?]?i9EKJ_>} rOU#N {EvLxLY]4zN-M *^Z| UAlcDtus^UʈOv=8.jEѽhO/hD o4Z!OaeБ?71Jʜ%|Aȷoz'Gv>&Cf:t n\1T%v6byLy/KpXW,j:3d^MgCBiZ$z;铣0 YDB(_J?b ?؀Ա ]&IڽeEpe]<*S (/yx+7;jDtx1۳|_R9LCdfи j›갑=O=Yfi~ܕ\! t!3+*A;}?}hzHןu). ̭ Δ՞|[su r:Wp-eUA% U,;/u@ҳ (dgU)~tՏez45v&*Mx0n1B@'wX]=3 .7}-]d ٗ[41mY.uo5p ݺVVQK~5V<4"-=ylKnluHlx5MӍÂL"ϋ˕Qw>3S5H,ZssxGO w$Qdn c*~n863Ym#&i ;t{U]32I:QA>%U4O'V@+c(ڐVKTՔ&U ]گ&ҵ (y?դ̐*`>J wTOv\MVZJ<B z*;c冏 X+6dJ~6 J+y! 4qV1^-35Rv Vxh[J˧N[RW~!cQ<峋7' yKG-Bׇ\w[o.%t=@42V\%X_pϦ -}Y4sfR,MywY҈wAؕJ 矉fc:Pg \jzc5}u2YnqnN6CN:HrzD}l6H)ޣ+'xn[i,Mo?{}X?^jEukK~H*@4m Ҥ c˛} A@z- @6)vya'lU.i%2Y0xwkƏ[}a䟌e(?0bY)zoSbf40$ס!4pĆk%3ߘwvO45alك-8űw63֦eGD$(Xv?*7+e!Sqri+s|t gs4z'B+fqRK$5}E$Lk\c'7f2V *i\}v|]А0f۳hvJRh"5.> gn1#")޽>KAblχK4xlM*qkb JIFG*iOcL!mszʙ}BqHQ:{ /q45d pvz'TɢMOjG RNjC&"R?%[df/۲1@")JUG{nLqQZ'mS^IEKWaΡo/ab "NkSz A,AœP&,w..,2U@Z-av~lI:*Rvퟛxsj]dŶ(IBKqV/ 쎼M 6oaяEZܨe|XTXD%Õp/ݭP/_ޮ=FQTĶ+(F2zI@hmi)y_ZZrpf)9#eX~?395~i-[+y·=r)7Y\'*TUA]lN^4{~S.\pQ*Rs)Y -,QWP\WլC[H+ARGAl4Ef`غ`٠3qMGCsA}Z{~WgI;ȕB3j8^)с95b&W _ō|Ǧxa|X2OgAʰ^BՁ%v [;N 30ɓQj"3=]Hj͝ cn ˓s@ɕ.M* 73Q V>ikYpLFșxH;UUm;6 }$_>)\~Y(,k_F莙d:XkÚ#BcAB˓yۡMz2zf[N?6s;촕XWYW&K-K@E\Ms3B*~}vIׂA<~#5 2IĐ͋╥kIA,>3z߃aY ^gNV 5Uf:@up|v@ >rȨ{kʯt(}Ө˧t:ҧeᕑ1!MTaœD%e/?'d[\D*IM0<}EncEԋ%U4M[Ɇldg]AVvPZ9px֝*mT:n 9;`*0~GGAR[no8C!K{MqJ!I¾]4mS U?RzpPTÕ(h-q^WKٞ>XW/g/ k#/lH w7}q VAm/}c!F^hKO=W)D\}Ai .WԌ[%Ꝼ%N@b@0F/Gqr7ܕ2`yڧޤU/kxIGĿg짬w˄vʳ'!w =R{Ǫ^\_z֟y*GPYV 9++ eYpM0 ,bU9 UR$u{j]lNs~CYA c;LJHP{s>=;?Mz%~}J] =-tkz4 Z5azK9jZZ*8eͦ?gM =_y=J*ކ\fN`Y6C:lͱؚNY[35HiVU|dYv7Z6"k5iK5)U{1S|GBa\.Dλ!{-^aY4EuųP׈zq@lōl4""qwl}6pÅ޸~pG*5 ;ݝ)V?, a5xy)^ Cª7oOP͖߬E:i/ZQaN4 qPRhav wW@*_5L9X2.Fi7djM ,Hzkv-ThGoƗ1CWUox:yfu+{i;Vij jT?N .W9# iVpE;mŵDDũN$܏VGqIɛ>`*喡<9f+$ 50Sss sꥂN&u,Np=W6- ? /U~ǥ̛ek+5ZaU'ݘ=ke-; PU-ub1W*þ{m`ԥ'|S;^{wvݑ۠ƭzmmmL{nC=F[vy[м9vkHwnX "Qšiv xMKP|wɪGM&%phxio/vR2gY, tܩd GE0VLvℐ~/6k| 9T5R^@}RMlulEF\ҋXk~V3.7}iA+i?jMޔo'Bc^5ZSZ E3S˗ +o!9X~| MtJz)[ۡA>S2c͓VGJ߽npNl[dLU򳫪m89Hv?}=gU;XP☞;!\0UNpsw`ϟPeօV/+qJ'- ~< Zΰf{>5Ukx|{|zLK婉]RX]iWNZm)lh)ZrǞ"ƨol?9_OzU[j U]s~wR:YGKGj1+p4Nz؞j9$*X{2YKoԚ^F+/dihw(:bχz\! ̊ @̋wp2k3V^j?H 'j2l ^gJ8:M>4Ff.ym?N9N"fliO hx]&5(_ʁPp,x; ҋɋխZ5Vcp6ƞn=1 /=,2-T#>S QF+Al,ڑ2o+Eh\fBhUf[SݕGJLVz+S¬̙(ɦ,(-&RPj:+Ϊԋ#0e+8u S~_6" f)\Wn*jۘ+Cڢ nzC'G<ҋI* 1zzUcDSm´HDE%nyf>ga1JM}"|-P z M5mM1%aC!M*))b,J(`F5͞W#UsMH!wnIJ`G\.i%2'l$~7HY72`l"k|`qGZj)9ߋм,NGs= <5# p:i9T۽%xnƯ>;֚ㆽ@]ٻ~Azsy]_JqHVS:=vsViseaZ2q4*ct6gcd_<^c<E0s ŷZG,~-FKXE=2ȳZQ7K<ۣjee|X5[vZ.\}`V Fn<)&')a +x+еG8՚@U!dZbYC}~&Y'Am;o *\)KV ݩ\>?P`u01:ɉxKz>ctCGYj|Ĺ%P9V|tb,w7B5ӲDűJRѠ_UO~%v#ε0}V%64?ݹҕ:lm"rU΍ywqPZuU. paw|`mDq+uVT8֒&Ej b v5Z1No&kBd`Qt=xԻ{55 Wr;" c@ka <^[Ֆ6t|>7#v}nfggYXjU β|1's7رY 8gk/aɍXH G 42eoPfn1}`r{Υ2=CiۇXx츷X2/D6 ~y"D)8ءƥ̍V&D+p2 ˨%澢o뺩h|q_?,A桁'Zt.LyW=Uزj#-F@^g|5'Gwt2x߾([ j;'u|ɢI\_+ta@P!gh,MN„`(9sٌZG%~Ggz4\(dGv}fa'Nْ|FDž3<=bs ȋYy%sC^zv9L+Zͤq+fI׻_rL*;?˝F>*y[,E KaA]n)HM} GZq>!}OCG,J@SoPS2eqL亟7ݗc$B|GxÌݭL) ̮Q픦 >d뾗>X#q*_]O5twWlv*6cEb!7cE|J2%ux9t{*ڋ*_o(OO,Nq//ufl8i]s&`-6027L/Puv+\ud6ktYMN}Qxtkx.nkjJš>YXl{Vh D]?j$W38h䋶XٰZ:?"> endstream endobj 105 0 obj << /Length1 1443 /Length2 6198 /Length3 0 /Length 7189 /Filter /FlateDecode >> stream xڍxT6"J5IMJHB$t*Mzt" Eқ4 H^D/z?|P~,--%Pv{"q;B!H E~'zȈ@1"hOg~!u7*Ї&B 0LNX'H\P0'0 <ਿȺ?E W 3 E{@P~3@ ]/V`$xCH#;ul@pDx`1"WYSEQX p(D4 ArB`Nʀyywj88ߘ3 H%%%.peNpi ^4sE 0 8(Gpָ{"|N~`'[`h-57T5S**h_ @XL`0XjЀ_hπ)[w@ ( oE_ix!|;) =4nPM5zpXnQ8E on#0_8p_Dh ˆ2?UGAѰ_&&! @<=!~^V@70o1"(4j О I_o#P^7Q-AB0.b'{dčo {N}Pҹi4T6yDi20b{LUOgQ.q]k g#ǧYvOG| *, ;| gG,S%Q:ZLߗ_{E;fZz pJ82X[8VwhaO;lUZ#:qԦ,{.AVVxd*ܼ!oǃz9]JS=#)f1A˚JOS$cLWn9D~F%QU Dh=9K1L{x5fGHn( +kI%}ps:U\>F̉Wo~ƾ3%[(Z]pϗto3T6R> >3~v%@!Erً;av3\/xVlo!W^`y""^&--gsv@vBL8 eϽLbH%$Uyg.h-Az1kE(K%!(j%n#js"][⡃ h9]-:3yK~Y\s^o(AXDcNt{;Z;v\5)B SXkIOHn~MߢՎƬܺJP]Ɔ[.wSvbT |mxq#@pLF-O# hSy_;MA^֌c6-}s-xv䜡jdY6.qAmP1U\`Z JԗXͲ*TgwMފz@ _ǵ=&us]1j{o S~[x42[5*-FUD׽YdmR^Ik~݆E׎h]bF?KJ|E]c?K%"8Ǻ¸@l?B+441kz{;`?]LC>?\d[::|7%嗫Ѫ{-=Kl;z=G]vti}] [D :k!AY4 GmrcVm Dpm)E\Thč/O  \?4;sE {`6B]}B=A$.PͲm)}M5[F`x^ 8K:*+@ursWfN'{F^9!ewWPǣWL[Ө,P;ذSC]ؔ`>4ur|7: ˸AMp2f ÐGiwQzڥПKF*GՋZ\I*y>)%O5v';ndl+U,}>?Hy}X'IcgN^:6)μSCssB0 J4Q6F.l#TڃþԨ˙ =eï\miP vBO_jsDetS%حO{9Z$OTYj>}BƒD{B?P'ti1Z|qͅ{e{spTxVMR"C`xCHGFbE=/5>b5Mۮ1~ǔ2uJj-"wY|Pe(CV/ w-CL/r,Sqn$bLNG;KE~7TPr犂x0 GNk*USl tXsq=c6 SSيW0gPlNNq iv1gm˪/f^hcӹ^hP3SuDCcذ;'Kw2Z< ȵM]_;|SpUO.n7Ocª>^5+ 2Zsj@P8iyك_N 9_DF VNXåhA|$ Knk>+m8óSkHd=Zbs6, h 3f"}ĥQ6CKmYoa3<˰ξ^(BMYC{6M!$ NW֮Mfŝ^rVVOmXd|2]%}17"!붔x^0ffQ{\yqřro2LtדSe^\r=JL%mᢶbh@ 6ʳqW/R$_ņxa#CU ّa{X=k =%燗oHa^:7dz˾ܨ=`6U^b)f"5 5"#:F &΁q/p_mř !sI"AC[EKuU/:g3Äe?.[[N%6-S8t^2#ꦒJzXKr/fDzޫ |hNmŵ"q_1igD˹L7lvluw|2Z˴Y7u{֟tQ*VScN^@#OEo"sSc(yB.oI\L\sdV w*KD , PGW5d;iID&f#^ W1UwOR ngnEmռwJr);J迿PSE)e`a1LK KdnĹ7F1]Br& ?*uFGza"h!SΜΩ*yq#=s G*vF:Tׅ{^pXY`o@z&׫ aiz#U:xH͉KT.+%W.6^nVoɍg RmcY;+jlFskn(7Pz­6A-i& ,˒U:t ^G99+:g vlۊk|`Tҷd=Q(vɛlմil4q%є).B8۔C_}$~ + gk~J{~6-KKK/(UMlٿTv/DVHke^0g^݁@zA]]xa\c0}&Fe\YOf}zQɑXRΙ dlsm˯7c<<^()uy^=ODv `MN>wszϽ&EO8잫Z26~mhISs $11{3Q͇,OWv| I, 7cD ކz"3l6'6ޤyIad(xM-"ЦCWhZ‡QM-)4kYǧo7%P 颹CYHsӖ:`\:p)'u#ϊoG}_l |^]}Y7VL9 E4!L6k#O>ޛJ<.7#onxODGw|ɤq$-A_ޏ3SL6R>z3m+5r!bv@x.燕|tYG)tVKYĦBrLx{]*1)U7:RmقG=;ט [T]|] ~'h.5Dcr+ z02RpHunmd17J<|cZ)hJDvq _̜7.l `x-e{Fv!q=ueSctɨ҇߅0וUe49وl>rMB馚3}GiMl"/(l +Э sBޤbfs48jز F`-_׏Yf6jo48.(i endstream endobj 107 0 obj << /Length1 1371 /Length2 5926 /Length3 0 /Length 6871 /Filter /FlateDecode >> stream xڍvTݶ-H D>CEQz IPJ)MT7Qz"R+H"As㽑1Z{^.] H J]d%-q`" ^^C4 CEPrCqxL@ %d%e`0@&(=H@ h`1(w mgo?BNQnhhq(g`EQ8\dpgw(B};~ hÝQ&xC{k󂻡P|]X U(.?_NsBcPXwG > ^G/!=W"LD\}@0D?a(B,g ln_׊W?>4 o;P($q#ܡ&J bkTIw8o*Yڨ54G& ywd̥t/+n_{2f7,L-QLcmFlv5h,BStbُV5SM(+Wۤ^V,W|J) WX YKΝ4%zi+PxFB_%3aPi ' S() 譤Q)19J+ -4"=@{O)և-=J6 ҼiγA Y^)Xy8tzԻ%m%D;&FԻFf3^uVrYj˭/ߘ|N*cҏmxPTcآs_^081`ʴRBrVȨ:uk)Ac&[34U<ĦRnw;G^JndSf'֮@+yŪyPtX&:l :^p'y;~7&üd'swZa:AmxMxnۍ3Fzqb\ɱ_0@(_`)va9ax例J#6 #QO[9)˭9R#ېvUf;S+[iD-g)){0{ubX ~g=,C#l-* =ԙVlTN=Iֿ/1* lA{ L|18)C~('.g#Y $VEeqYy~* ԻM%VR< QlCSc0'G#E믤tw+v4Qz.crcu="{Ō>{g[^ VxEpiYaRō:*_ 03Gbf (Nρ6Jïզ.W^Hٰy{d?b>|ypOVi^[3่Z{EXٖX#VUyj jtЬcAۈYsUuUoIB˜eNƁ!I uhfI6'#H_[OO#s璓z*ω!H#@33H~;bx^2LrD^l$[?,α&\|:6DNezoIj.o](\ٟ}cΡėtk.a>C:4M_ԎWqe;O=#̛^u xHQ.?/K( TMT&5XOb[shHvZOl\N)݋#I'U$ұd c~;Pa;Аi8v 'j\ߐJ=) E,ʭɞVUQr.*)~*(ZiO FY_֘ |SBzL6}zmN3N[WpqaޑG>Vҭcɫ>sNݰ}VҫgC|7CUHE*# Fm3Lzbuu1\D;,Υx@L,iG`eEbS]Ibսީ5.5"i9-1wUYSϓeg b;}5*4wfABzcĒ\3mG$:f'A__֨U,M'-M!mAa:\D7[9 Qm = VƏ޹|%3y 9@:]=#A2>J,C? MVQ^/ꝳLQ{9 + n*{'҈y1E0Lč쀩8ΖrzX`4ֶm9y? fۭ!Roa7j?6b+ w=nG$EYټfk!!6bjHv+@n#ͥ0Z54Ǹ>fzJӴqoAք (GTFJ(! PQt _\Mk.yjIZH t2+Y_#Yʠ"#l.d&ԄS$tfɢϋld Y'(OOlȷy0C|b!]FF3%haHꤡO8ۏ/HĪ Jw_ L> a67 !'tz4;'u \T)#).ᄈӔ.2~Juy/Mvbr?ʌKtY4x]qkv^ep'Nn˫KW{>tM4N.e:K23QHF/+:QAqweiVmò Xʀ*SqlBO}(G>{Gt˾NV儹| e9߼g0jC+]?+]<Nt ϴ>TJ%lxSr̾2eQgLLm5O敇vTTdz!H"ͫLyԢmByh'_Y=KffhKM:#j^1Znn:w.8-L4bJ宝ݲ UH`Ӎ D89^|dgJQӨAu pGaKy'ʒCD XwIp*|^{!L(00`͊= To1yp=+bgGSD;+dzZ`yl΍rVN3y5EqG^쭗/{2t9$S,u-_{J祋C۫mEޟoEo7}("dkHpp(kC1t=^X-e-J Ñe6vg`E= 9wgHd`.GȡLIWaLx(ug#yql͡ɶr;G׌ˎW4D&yޤYSͧ~UZcw߉#I nE 4EsTx|ccRjg5Y@,J`k!_"~@cDt ed~b'"v5+.).԰6L1th,u&zR|n2 򱫤{W;g,=3X2?aGPU'2-÷)1$D/tڔP]Wk'REt{ZY&ڳ$:o hBEkh h"]C8ղC[JیMFzNd5z[0mcl}`r@3EjH7m{U RU MRP9rq w|/&O Ʈ)J+9xdVdrd#E|+͙pW49\mrY=8NT]~|e&߅YjW"7vj!fK9& +{JJ2B]w3 IKM(3"ewے7 T滚J>QiէmԮb2Tr|{Wk B-.,9~/sZ*+M-G_xde 6E,<=:^GF Q2hrhrw0vVQa;ct'ߞ_ "2< endstream endobj 109 0 obj << /Length1 1412 /Length2 6138 /Length3 0 /Length 7108 /Filter /FlateDecode >> stream xڍtT.(0"! -8  1HIHH )!)-Ht "H8޵]7gw}MKOiSD"| ~q(@@@_@@CI8a(g8!r(!h O@B8HT\@ ( _D$J q[H̙C聂[۠1<; C@9`vBH(G . 4Qtss88#QRnp @ C,h@`&'H+`{8pd ,a(fs@CVC{6?f*GN@HGXaME5~;>E;#1Wb!P@0;F*9e@;OA1sv 5# SK@$ahXCmy8~A`>^HGf #rh "p(`#HSì1L0~#/K$? S7PS3cHw {@ e m'Wa<-ձ_p574\Xy;_U_"]~0n cu$Vf wq 1 #f>0wYjP??e5{8t`+pw?U@@|&@P(FN`0 1%@~I`fX!Q$UHd!\&KQp1BXR0k0; J25> nQ&u`ayQG89F0MiIeɭd/oBG&x~ ~ORFc)t}d cD2Z&?_܏f^Eh&u@w $&tLV6NȔ" e⢧d's*pb;7םّ,tq[HI(5*[V_|m\j3,ܛ;  ffv@!m <;ySua_[Ӄ^&- /nz55>W0: 1bό:շ%=ot|CC{O"f}4f˻&f!GwpήxZ B'T' d}XoI )pD< Dm3XyzIGP1!ql `p{jF zmyĉ"Z.~ohǃLΖlF72ܺ]N7g `QE4Wf+piMl% Fn1H/ߨEvvҎ[%t1EL/*p@@3bS -&>+߿|޳}}tv{(dm=MĭV"N&]7:a6⥁**CBT:yRb6 M L"W1b YJQυӣMC}o# bnd B 4Rj?,\4DC}9^x _I?/sco|N^#Efr(ljzS:ƹ=R(d%=aitηy_6w%m6skUJCn%2FNRes:)byO?%4]e39"+ ~Mh-B?Jm4(%2̶mH[;!ETPfFVǠaw'n"C%n;rȕ5 8{D&(\ \:ҿ*cm'_*u9mz=\NQ>k؍z=w'qk-+_eۄ[Ժ;:8IfFSyx&jc@}Ӄ ?'롽B)'bXQt{߾?#C)yb2) [ӈrn˩IjPnmsSm7UxiRQ`R_Bd{R坆üAJkӠ[(;,29֞^ alGT9M"{עnDf¥&6U2yD/xUQKx"̞#ρvu|oӉHYTVuY!"Yv qDNC)=['jo gbP^hhm 0 z$3~Bg8ns$|s+D34=o3T\nL͏R."k-mN+;Ǩpܲ3!Z1 mIyu(Yu(8Zfm_E)Ϗ3K'r6!p,=}{=rxQh6lY>6ow뾊{MQ\ 12zFop3y}wB6MEq63.( V)fjW82Ւ`ϟ=cZ4@? &OjAQi@D[%)XN98瓈"ш ӛXt!~~*jWoT>0)^;j$ޯk_A_1YTP?`8l|}DŲ/k4IE6UPW:g"ySX!*?-`PS_ƌ?讝,ZgMR'١];MXCK dpJ3uH l0ڂ|iG7;pu&ccGJ*f>;} 4*W8$kaRl|"8La\ ;8$Wv~6E;@fL=Qo- tzDI@v\P R]f5Q?])*#I/A+ñ,#K}vBpĸ(.zw}7&V r/!Rgtia7%fpx:妇 F! _x5m(.aR툻]-+D:j"7D᧰|d'ZfػGw^O6r3Sg`2\HsPfE־uk!T2h;h[᣺(VǸNr/ .Y4(SC!^bR8GF909MXKPXA &iU*ȭL| S#=K;bF&f;TU^Xz_99ݦLiuXpp ?_Pק=G%b9iX4W8|J#<NЬGˁ@J㣪Y ARnk{w!`VqvL&cor$U[ʞohrWN9T)g^u`??#g`1g<$}úHb@)s7r|tL**{g zp>h0]CcIe~'h )n{](dTT l͞ !Ī D:N=q r'bwN$h,m|{Ty_%]s]͟YO XH;ZT`17k 2e7 ZXU .LD9v>3;PB._#S#DI*'5EuSnVs~}ЎVzZ6ʑ=8 (>Kʌ*YR[i j syxt]Æ؂75:^$. r> ƽ endstream endobj 111 0 obj << /Length1 1596 /Length2 10178 /Length3 0 /Length 11220 /Filter /FlateDecode >> stream xڍT-!%gAfݝKp  8r=ZYUw54jB`<ܢ5]%n77'77/:.fABDqÞmgPvxEyD""BEn` @ \d`k>Z-Y<""B@`Ks@frx`Ysrww4wp:[K06hn5Nt / n < s+r<QRh8 U">'ϿG"0`sKK9 XA yUN`A4w>Ǜ- n?ww.`G H|r Q,d|\_CVtu҃\AJsMY`nnna^a c]OGПN?=z;BVm|V?tos7 :,@`?AVw{r?ˏ+g{b.mYU=u[kO+ =/|;9:D*U`{@XK\?B-m!*#U[~oƳr]aS}R @vu_y!ϊv{`_ˮǼك! M 9|Cfi<.? `.?s,T..?s:2KWgOm?D_Zֆ_WKSs<:a%G涭$#~sƗ =+fΐd'=Zxbg_vEՕJW3>КYivY ͕W6GL91cQI0B::*_HOt*ѻ?H߽I1THrT9ړ+Hb6 f#g:o dpՑVښE tA> "\;v&/\p5dC}`HBDzosL7UZGsDTbWqf oˉ<&(D\H^J73$=|yᕘ'/Ͱ*.'7 WBG ޑˡ"ww kI `BW%5o߁JhVrc=>^ ҏ S:~ X;f6. Ҵu 8 ciS6mO qBB6t9)t騺Q0L$U3|y˾jf  Ul su"t`[߄O[XC]I |cDL3Qk -댂msTzBxY,r%"prޞZ\'SEr֌|FAA8)\g:ަ 8P483΁nğjc{%1IFǷ6b ˧bTg]-b l -lbDNqS{fLEOB1Vn ol9odI%]rzdMhV<Kʪo]\dCHa/(QU(g, ?4~\QbzԖYiB{Iq<u;)2$JF!^`v]֘O -T%ݢ`mp馆aNvͷTD}q;DP N9n}}F iS0j.Gan϶=.iko͇ ߻foL4-CcPY튾dA uީ7o*\M|a,vܹyM}?X<.Bnr/qZjw׿: w++BD]T>wAdfܺ.`PuAiuXAPɌH;T.?k{'&H# ER(' [S^hGyhpϬ? R3h3|X^- DMv8"lpz1"!C5撪4$Xqs60-Phynu\v'وRѲdZR Qr^T%`q_d13jm@kf/ld1pLy 6GdAxwrc|Ki؅Ey)y) 4@ c#/¨D0XKTĺ2o7OcNpL&mw%{j0Qk;lA{|sĵ0 6*u~HI~Hq6 Ǯ"_ߨk:`V!_?lm!ܯ.ŮIz @9Ƀ?ֿЊwnRiqfe4]բLV=ŤUt)a)) -حSt)7d&%qm$C[&/ϪaQZ͍K~Mv8o?b 2gbqʇזDŽ޶NcaL잃P$n~ }zh晉ŵhB-y 7 Gྲnڂiw+]F8{uF@Iu:@'98 K+[Y_0n ] `=9#nozc0Aإ%9>{ܽ貍mӺjʫ«2>o(!+@C- _ݣ~3XsRXXWa#u^necD!TřrE1nclj@l^[R m<ڠNIƱ?%cg-ԇ^uZ?gF`<8u(nteSY["šQJ{K[Wrc?[ϮggOQIi.b3Spjn+P1rǫOe^_ڧ׉'@W/W-%/̷nfIR/nq'L`/ oR Z ܫFg]jf}>'t&s Shț03b@M.0+;Ma+I򝳊QO]8.wXkTi3Q 5:XY"iA> cI35)(sZ+%YI␁LI֯Vo臈|="96;#j=;}#ŹEjMS9vJbJӪӻ=c8cʼnVIsl"ryuQG?hyV7KP9}u F"\z*Ibl1$Vx/Ï"q&}{ݦ\fgm.p#ie'||{Hg>(SBJ~s&sA]o*Dv k@P[9Z3[mp)];JDLSQ/k刳t$f"1S|S'z-]f3E')`+Ie_ÖHתAKHP-~;rvm? I䯢Q|[MnUIL' 9ihY`+|WG|Sp}+ȪajvlTޤȖ]~e/N7=a8^Ǝ['ƥrJ&NUpد_e&$Ǐ{o&<b<(̦$ndFR!G;ApUzG-K*XP{>8(56ɶ}ΣuHzž`C_! $5'8'iٿ.K$s}L4uҘBZ0Q_XZ09Y博 EܕǙS6-W*.)cF{m͠lɬN̤G2w cI{ʌaymF٥l-vq$SPKrǘ Df?mO ~uk I?`[Zac6kkе"X dGq"Pnou7B{x:B.)01%)/~8dcR5vԧXN^N?)qʿR!jO Y`ܛ}W-s԰hȓoѠ/^b3+aZok!|"EW7tWY1427b錃9]J muYO`oӂՌW;:]QZ:~qg0w ΖO!ʅ~\Jnc$a`}! ԭ}/SfBB>M}e 3#q裆׋0ot,.tHijfR"~zNpt:>&ĒxK H}BNP[Ŋ55BX'|4 w9$xyIb- F3 s$1]d1/kcdRepP$61)I"}(,N : KWhe8j`nvB)v_nMB9^zS EOǵ/,Ao*d> 'Bb?Gz肇Hˍ@\ij.2ػU$ppд  +D/4'\Dħ2Fiϰ~A7< HO[!캔!{X e-!'ixƵ o7&Ub-'4Z_Gt^z\#\,PӖst_I7&7p5S\'c1 qOĬbOx@ˍwr+)YH*=)mR+ y$ w->.QM[s@F~ sYa52.nXQ`5])} »]L;k> _vVe#u œj&F,KH9\`yiV(&opn)Z/7BVm~ObRn/[!,$O7ozL=T NjAM#oM.Տ9'%XG%%:`rq/$5vg>5NFnܾUF;ڪ=Å"T^ӈPPCY;t"e c/HIȺ685F<^M0ӆW|fCHiXy ؎|fqшYseCbޑ -R<:UjtK? Ԡ4GG >tg3V,kU(?N21mL̓ASBmF ; މ1莨]Τϋ_uUUgӶ2HTU6`bvb}P9It)GqxӨ l|msf?uCR`=rl GHzg{s^9(Ô`P_|v{S/_Š\W5-[Brn•'V>C+$}h}%1 W;3\楾T},?7Z{Ɯu b 嚤*Rihٵ݉58*#M)?"rC6<܋}wq򌜁.IEe:Շ9mrTVo*.xu$:*jy-cɪ Qp9%j_WX 9%<贞t~8p uLmIv EI] >q <"{ut729Cհ`Nә8߆&qS+}kgj+{SNT8gW! woᅪ) ?q֔Q\wVIbTi`ms]Ke!evCo7}wos5By&op1Qķ%V{2p٢yJ.ک-ֳON^jZ*PhL/ Tыr.ß' =LTSFs/ebQM^WꛅI=q[t14![MZ]ayP3jiKmґP3/Lpۃ1;\]ބu7`Ttb_,"*Yya'l%D~~{"Zc,y=D\'c7q͂˶|9ڬ^7yDn@*C _@]GRDV<&̵% .1YB(`)* 'sal5>z"έOo҂.̧/X٬?OuHl'%|2D%#{SY!I{DD; ITxtB} )/sx٢:s"d872?8TVh!6HC|Aōߌy͢}s@1!jyW1ybz1(ß q:u (Tg.zq1L"pwq9FCk"DY[rD_EW>댛efh%y7*u|a1%?#Ӆ<Ԙ/Bm|t endstream endobj 113 0 obj << /Length 741 /Filter /FlateDecode >> stream xmUMo0WxvHB!qmU^!1H__myݷDULG^͹t߷.k4c*S'ҵ>]g,yݔKeF$mS3&qGRp`I_3[dE4ݹn'&9綐7UaL)l:M z!YU0rўo>ν9},lj'}4>2]ݼ[ivjs92V+Vh ~y8&X-MmM|ŖE LS7Њ~& U 2X(pm XX(W8X&LR4=zukTGEm7h8Kc`Iu(!a <#G >n-tJ!]O2`̏S#',<ؓL%qO8\π: 3ht ,+9ugCwËpD|ORɉ#ɇW m藒1NwH=8! 4DCp&q"pBCT/9!ɨ~B }Rq҉TFIܨύ|nTs|neEA;~<6OIystg>O:yұϓN|I/|yI>O:yҹϓ.|R T<띹_mKz}K=W7"V{/@̪X endstream endobj 114 0 obj << /Length 741 /Filter /FlateDecode >> stream xmUMo0WxvHB!qmU^!1H__myݷDULG^͹t߷.k4c*S'ҵ>]g,yݔKeF$mS3&qGRp`I_3[dE4ݹn'&9綐7UaL)l:M z!YU0rўo>ν9},lj'}4>2]ݼ[ivjs92V+Vh ~y8&X-MmM|ŖE LS7Њ~& U 2X(pm XX(W8X&LR4=zukTGEm7h8Kc`Iu(!a <#G >n-tJ!]O2`̏S#',<ؓL%qO8\π: 3ht ,+9ugCwËpD|ORɉ#ɇW m藒1NwH=8! 4DCp&q"pBCT/9!ɨ~B }Rq҉TFIܨύ|nTs|neEA;~<6OIystg>O:yұϓN|I/|yI>O:yҹϓ.|R T<띹_mKz}K=W7"V{/znb endstream endobj 115 0 obj << /Length 494 /Filter /FlateDecode >> stream xmMo0 !Rz|UAa۪V&$E 6~=HUAgɯ~uo$ƛLD- t @ZcNt=YNk`T=Ro æeCڕ(>Պ AiZsn[6uc^0Xah\je?0bprOY[AKS|dۙoF)MZ}4W@{YmG;<9`;K (EytbabisbgEjq(po$}Idon-p!J m-O[L endstream endobj 116 0 obj << /Length 696 /Filter /FlateDecode >> stream xmTMo0Wx$ ! 8l[jWHL7IPV=M̼ su;Uٛ=w]yil;<[[j<=?׾+v`&ߴț<^*;~&Q>MS >_P{=s@dkx;`VY`s4JaQܡn.Uu9\Y6><ٴ.Z.4>Dӗ}~r:-d0VWk,8yLһʮӮђ[*mLr?q 5F8@=@)& 8Rx uD\j2HV0CzL] bctI g$`htы0\F0s jd< I6zg W qȐ+#k .bsrbmXK7ǵH7Gnb>&jؐu1VljOu$՟qWS/%1{\xB!K(hHTЖ枃Jρϯv=k2UKς_:~$/ ~E+7ˢ/ l(/} -+ZXukoԝE?ZKq endstream endobj 117 0 obj << /Length 695 /Filter /FlateDecode >> stream xmTMo0Wx$ ! 8l[jWHL7IPV=M̼ su;Uٛ=w]yil;<[[j<=?׾+v`&ߴț<^*;~&Q>MSǓ>u;q~:fc_0F)lGιmu f8Gӫ6b"!YUe.`M{My?IC4}+̝l/Bj*{pϻƲO('$ *{>J-9_eQ"V$)MP:^9 ^` br @ {@(\,RH&ti m+3ԅ ,;F$БzFFieD(0A1a8yΠFpnù[w6p@ )9r9b_ia|F-(:(nQHY^`nA|n(戥K}s\}sԑoA&vqc⠦ YK^ʛ!_my_)=^ ^{TGRw1RDž'xJzImi9j'pͽܳ/-_Z,N_: ~iyY2q,nЪ5QN Y58.] endstream endobj 118 0 obj << /Length 695 /Filter /FlateDecode >> stream xmTMo0Wx$ ! 8l[jWHL7IPV=M̼ su;Uٛ=w]yil;<[[j<=?׾+v`&ߴț<^*;~&Q>MS>u;q~:fc_0F)lGιmu f8Gӫ6b"!YUe.`M{My?IC4}+̝l/Bj*{pϻƲO('$ *{>J-9_eQ"V$)MP:^9 ^` br @ {@(\,RH&ti m+3ԅ ,;F$БzFFieD(0A1a8yΠFpnù[w6p@ )9r9b_ia|F-(:(nQHY^`nA|n(戥K}s\}sԑoA&vqc⠦ YK^ʛ!_my_)=^ ^{TGRw1RDž'xJzImi9j'pͽܳ/-_Z,N_: ~iyY2q,nЪ5QN Y58.] endstream endobj 119 0 obj << /Length 739 /Filter /FlateDecode >> stream xmUMo0WxvHUdCmU^!1H#x?gx]OTm$|͜s_Iss :L;<Sz==׾f`*_`ɫڟk3'iѴ}=M;7rfnj-eSӵOLg~8 )ok A8 $`I\3`Af<Z]! xNky"7 _㓧q H`nḱRONH=CpB:# =%888QA~!*zƜАT?!~> tw8y*sύ }nFE>7*QύR>7G];~<6OIyktg>O:yұϓN|I/|yIg>O:y҅ϓ.}2 L> stream xmUMo0WxvHUdCmU^!1H#x?gx]OTm$|͜s_Iss :L;<Sz==׾f`*_`ɫڟk3'iѴ}=M;7rfnj-eSӵOLg~8 )ok A8 $`I\3`Af<Z]! xNky"7 _㓧q H`nḱRONH=CpB:# =%888QA~!*zƜАT?!~> tw8y*sύ }nFE>7*QύR>7G];~<6OIyktg>O:yұϓN|I/|yIg>O:y҅ϓ.}2 L> stream xmUMo0WxvH UdCmU^!1HDI8߯-@=ۙڽ١=?w]pwdV^ڑݧl#oxdGa0NiqF?Sր'YNR}{f{x2A! u xk={Exo"}Rɑ#x۠_J B C쩁b8!=%p&r"D9 Qg̑Tu+gGNN8O-(7ZRntH ʍ(7:hEњr1+w(O:͓.ndm'#Ʉ'> stream xmTMo0+J!m$d!mT&t@32U1~3~˻rr\i$^ںQg|6'oxdG2: lic$Pߛ)? _CtPRJ(:Nps0I֡iDAWj~:ytM{47xO_ M! K2XE?iڝ]]TʵHrS0QOKx&Z=1>bqb0q&d'H1[Q/c0&տp*I(kÆ2$l/#A cΘ :X"^fF~NK rJ_dP !@+MTH`ԩ3NE7kfBqxIA2Gs6AEYe/O3рI?kM'WGff@$%~S s셑(wr͂n"&}7dXz s)d?X~`5`?؈`cMv~+5k6c?؜` -d?diCNa\`͡2 ~DSim@]Yd8|pJ endstream endobj 123 0 obj << /Length 739 /Filter /FlateDecode >> stream xmUMo0WxvHUdC۪TBb A!Gp?gxYOTm$|՜s_Iss :L;268{zb/}WUjWm?fd}Oi=7gRx=7i'Էf[7̖s ~ts[(:0p l:5m_-tB}W{X8 jw]lj'OC=6}Ӿ|< D0,6;96ݕq4L MUWqS~Ӿ |Ҳ\Khv7RKs|*Z -1 b[d08A  i$C#.CZ\wF|TT<\`Gc)y ,<$g v1a粳[ RHדL1>g~8 䔷5 B{ $.  3qdAEBu7js"ܨF)EYQУ.?yRmTy'oOz>OZOyʄS&}/6>zչ{ZkZs}=?Fey endstream endobj 124 0 obj << /Length 740 /Filter /FlateDecode >> stream xmUMo0WxvH UdC۪TBb B8߯{ .@=/ۙڽs{K;K.k6/k+[M'ҷ>dyӔKe'$cS`vfSfK}fƁVGGf\bu<19w|擬CTAW $rG]IyMsh$aW7y̟u? sK-`θtJ!'c83?NaO<Dg!;IX 0z)rЃ@kpBQ]^Z7! / U <ɉ#W m/%]cX! gȀhID8QN~ACT/sQQRs 穅ύ>7: F+}n4eE=zG~<6OɈy2kLd>O&y2ϓQ>OfdV>OF<dR'<>O)yJS*}𗏿tx>z{O->tՍ]*3>cC~ endstream endobj 125 0 obj << /Length 739 /Filter /FlateDecode >> stream xmUMo0WxvHUdC۪TBb A!Gp?gxYOTm$|՜s_Iss :L;268{zb/}WUjWm?fd}Oi=7gRd{nCN8oͰof-%6'&9Pu`L/"tkں(a[ duS $xqa MN{}m}gىx` tw8y*sύ }nFE>7*QύR>7G];~<6OIyktg>O:yұϓN|I/|yIg>O:y҅ϓ.}2 L> stream xmUMo:W5?$R. d9M eCkmCp;;w~>|3E_?O]5߶w]Occ]=~?}Oyh9%?۹׬B|Ɯ>);vw%g43>\ 6 EJ78 1{~`W(-;]%=xe_,b+-O;q\L}UI--=BKE1p[! Mߊyu>.N5K)Wb٬8i[_uʕMzQ)V(Txޢjy!Z2P="Zd0\ÃGR\).2*Шa!U,H`+j.5Nα@VK-x%3%AYӀzΚ>kP#5m0Woþj.ZT$X/)n)#Wo(oRZ $Kp4Z-b\1ܰJ P"GXQi/8k^Zq:Zs9dB )sL-7xJ`aɽ)f$1 dъcCZC<73JgznHȰYɚTa,_-O87}KԴܗLloK+gJ.GZyVc48Wt]:P~`rZq.n1] S/Pu7Ue:?&?!d&1yHn5)yғBx#1ޞ]Go׏M?X endstream endobj 127 0 obj << /Length 898 /Filter /FlateDecode >> stream xmUMo:W5?$R. d9M eCkmCp;;w~>|3E_?O]5߶w]Occ]=~?}Oyh9%?۹׬B|Ɯ>);vj|N8}No)e0&h?q:P_ X}ac1+a  jҢ~]ߏ{_r)4i_px`!dZ>i]<U_cr%ͪcךv[\٤ժX*be-@E-X@-꩖xkM PY@ ,#bEA 5rEqIb>,彐A$ G#e"&c D`%rE*s(Ǩ5ثCI*=ǔ^pk+ ܛbVLbX+@8:13Jp3<|6 ^ΜANVjRy9cpסAM}Ė)|֪,+pp70h8J+NK}Eլk)5t7Og:|CUd2Wf{ :?PfY6#r率ltiJ/ VRx{vw_?6F endstream endobj 128 0 obj << /Length 900 /Filter /FlateDecode >> stream xmUMo:W5?$R. d9M eCkmCp;;w~>|3E_?O]5߶w]Occ]=~?}Oyh9%?۹׬B|Ɯ>);vw7{>oaI> ѲH8U/RǾ0ñ_x0ӅxBiE.͏S=/b_ixމbc4fi|8EXD_R4.GRQhV̪xvqڎXJfUıkM;rͭSlҏ֋jU,N2@ ",   T[<5 1"àcvG@mg K | +T|5flxZ1YP^ꠦdb}[ה_Q>kUbw88]k|'%Ǿjց{ g䈏rsqk:n87xIue.Aft0!?4ɳ4mFtӔ^z1?z .~lP}L endstream endobj 129 0 obj << /Length 750 /Filter /FlateDecode >> stream xmUMo0Wx$*B!qض*jn$H$3Ch<~3~~~ngjv9{C{K;K.k6㳵ችm#O7٦4\ =؏8ݿ߳4ւ8͌>sIvdXC6OLx9im$l6Dl_7ڞhz*{pɲ2kAʶC+mk>lpfIQTT?LA>J e .1PbpqH I$\kL8Hb،Shąr =z51XQg_s2Ē+ sC:CQ}.'c-BbOEu+Xg~:?aj B.U $,ĨAA 2A%%" 19hM_)ELN 1sR3fg =傸aCYjV^w&L= 3nqFyDŽϠOL5'pZx?i^x?IGO:~I4ϼt~3][gF~Qgf}fB3y,h3cL}f23{,g>KYN0`^ay{7)q W7:*ሟS`R̯ endstream endobj 132 0 obj << /Producer (pdfTeX-1.40.22) /Creator (TeX) /CreationDate (D:20231221100511+01'00') /ModDate (D:20231221100511+01'00') /Trapped /False /PTEX.Fullbanner (This is pdfTeX, Version 3.141592653-2.6-1.40.22 (TeX Live 2022/dev/Debian) kpathsea version 6.3.4/dev) >> endobj 15 0 obj << /Type /ObjStm /N 81 /First 673 /Length 4304 /Filter /FlateDecode >> stream x\[o9~ׯ98 0X ěN ȃbwؖGg2O]jZm[1;bbWŏE*'"I!Ih%BK:I%aP2ya`qdP&8l4€5 +a5wFXA:+,HR 6 ' y# ́Qi`\V(1# GI#<<*g'L0Ѹ0?tGarlI3& DQAטFS`o40Ih %`'2"H &D@IXK8$E`G lSP@(Ta,Ԓ1]+]5·0BG7< LSG>b;tT" JWije߀IP> S`7|zp Nb#=q,ث9b= 1:30 cKPC#AUp_~U'Ԣz7GzQ_/Cz>scjx]Oƻä` @]Ng7" ^4E=8g?ϏE 4"u\g\ !u[ÊR#TwqAQ?KV}=(*_K @itk\-zh-r;^YFt /\G"mEDIit Ro=-[azcfɔQ?0).1(1EI|6` M۫d6࠳?j}rV=աXn!',rv9g<:{omo2J{4^ip/)f-[zm =}:E 1/b 8vM[Q\|]|;هCw"fNd"&rtڱpJ3(eJ(lf8NB0e'~۶cU;"ֱ^ܯ1/L;x,"?KB\rK#-Q!R{8`4,1p2f9 eK Ϙ4-CXWHG tD77ݶ RcA,0O&c)"ň 9+\m%.I$D@:"FR3X(".F%^ .2b}N/4UQv,D%Z]AI-;L% jAPb#x <%<$虌p9Uq .+(v/7hrh#VGtѐrudHڀLȜK̲ؔ x[)ih)WFIcTLm?[emee/-%,]a'`s'I%"XP,u(t#%:[:T@QئugJvNSs 7̥hJPA=Ҳ(%[ 4%(FQWk) *>BXuV[kjXs`e1#s ܃LՔsY(ɳ3a9O1扴)a#Eh?ลҳhIҘOq@0HzR9eObuS.[TxvyjI"ŧ6Yh!6 KN8d2 vH0%ēof  FHc %ךy}:PFV!B&7_rRor= > %%dk36vR Eڸ?U" c&w6&,*z4x2Awk_" ʥp"g) ';¿z’[+4nٗ[zXw(q4O7̙ˍWbsa_((eR:>'A =r_o鋧ikerbcwzR`Ie.AxuVZL4z~6,3f yv^* /.sa.}yD#(o;3Q7yQO.c wO<\/'gO/.kL(FiKd|quVWu6U겺ndz^ͪyn<쐊/[5߳zhF!ܤ1ZAϪuzWU  A8&5rQ}h~p 1jPp׿|[|ucZVWTgĨ6śӷ@Lo&mQQB< Fҿl-v'I!?PnqٵyfߴՋj~{u5^L ~f#>} p?ʓ6 | 1 zç.~uP/Ɠ}:>aTN~r1 wuYߢQY^PrkA2!cdlz$cIĒ7'{_%aUóA=%Q Z=a5ض~w M(˟rӒ |7)@A@?'+ 뷙d1?@`#~~MXlz9^}x_"=/[w`aj|60UADrÚv}N i#}yz|:Odqد B "h잩W^d!S)M,6t~y ֎1ы/Zu4,U#|*|ױf#VxxzṛDh4wYӱd#}yr'd t/Ò0엓֐˜fp)<==8@{zk2DZ߱eo`sz=mӚ5[%6ftOysO(mV[Z2;|Ϫ5/אab;č-]S7gOI ),EYLpzCݰofkF\ss2g(s`qK Q?x6o_#-I>R㠅 k{ d Lr\s4_ wiOp}}WȎ:UGq[rd^Q౥>Zq\:>ԄO6g'wѲGՉ[=6IkrYѦr詓:+uzl]GߪvO+"76 o͕&]egwic[[r71_զƶ\Uf JͫBoAɫB-5%;e FN}u`䕔qE%Bf lAȫݪ:Xi(Yk8K3bj\|_#/wwC-Ų<̥* ge2ň.5>P endstream endobj 133 0 obj << /Type /XRef /Index [0 134] /Size 134 /W [1 3 1] /Root 131 0 R /Info 132 0 R /ID [<0603187FD3CBB9B2ED82142FA2C3E1EF> <0603187FD3CBB9B2ED82142FA2C3E1EF>] /Length 390 /Filter /FlateDecode >> stream x%=LSa%-E!V>(KUA, 6wW!؜IwL:sX~&\;"VFD@Xs$C$IR$O4K@b".yNY@fsRC![zBt̒$YֱxH Z Gg%i$>ȗ5=h"w!_SwC#͐+`㛎N:HI'"ݤ< ! G2s!rhEj Y}5g(rH L_k fhX+ kìlj`J0?0QL5Zp#;D-/ԉ%ےq-ٸ%R(ZyuŲmyO,E 38"7A endstream endobj startxref 292656 %%EOF ntpd-1.1.2/docs/algorithm/algorithm.tex000064400000000000000000000627111046102023000162270ustar 00000000000000\documentclass{article} \usepackage{amsmath} \usepackage{amssymb} \usepackage{graphicx} \usepackage{tikz} \DeclareMathOperator{\erf}{erf} \DeclareMathOperator{\Var}{Var} \DeclareMathOperator{\Cov}{Cov} \DeclareMathOperator{\E}{E} \title{Clock steering in ntpd-rs} \begin{document} \maketitle In NTP, each message sent to an NTP server gives a single response. For this round trip, the server reports back at what time it received the request and when it sent the response. These timestamps, together with when the client actually sent the request and response, give a measure of the offset between the clock of the client and the server, and of how long the network delay between them was. Packet switching networks such as the internet or local Ethernet networks do introduce a lot of noise into these measurements though. Furthermore, a client may want to utilize the time from multiple servers so as to be able to deal with a server being either malicious or broken. To ensure network noise doesn't affect the local clock too badly, and to handle multiple servers, processing of the measurements is needed before the clock can be steered. This paper describes the approach used in ntpd-rs to go from the raw measurements all the way to steering of the system clock. The main idea is to use a Kalman filter to filter the samples similar to what is proposed in \cite{giada2015}, combined with a selection approach and pop filter inspired by the filter specified in \cite{rfc5905}. \section{Prerequisites and notation} The rest of this paper assumes a comfort level with linear algebra to at least the level of calculating with matrices and vectors. We also assume some knowledge of probability theory. In terms of notation, if $X$ is a random variable, we will denote its expectation value with $\E(X)$. We will denote the variance with $\Var(X) = \E((X-\E(X))^2)$, and if $Y$ is a second random variable, the covariance between $X$ and $Y$ will be denoted with $\Cov(X,Y) = \E((X-\E(X))(Y-\E(Y)))$. We will also see random vectors. For an example, we call a 2-dimensional vector \begin{align} W &= \begin{pmatrix} W_1\\ W_2 \end{pmatrix} \end{align} a random vector when its components $W_1$ and $W_2$ are random variables. For a random vector we define its covariance matrix as the matrix of the covariances between its components. For the example vector W, its covariance matrix is given by \begin{align} U &= \begin{pmatrix} \Cov(W_1, W_1) & \Cov(W_1, W_2)\\ \Cov(W_2, W_1) & \Cov(W_2, W_2) \end{pmatrix}\\ &= \begin{pmatrix} \Var(W_1) & \Cov(W_1, W_2)\\ \Cov(W_1, W_2) & \Var(W_2) \end{pmatrix}. \end{align} \section{Global architecture} \begin{figure}[h] \center{ \begin{tikzpicture} \draw[->] (0, 0.5) -- (1, 0.5); \draw[->] (0, 2) -- (1, 2); \draw[->] (0, 3.5) -- (1, 3.5); \draw[->] (0, 5) -- (1, 5); \draw (1,0) rectangle (3.5, 1) node[pos = .5] {Kalman filter}; \draw (1,1.5) rectangle (3.5, 2.5) node[pos = .5] {Kalman filter}; \draw (1,3) rectangle (3.5, 4) node[pos = .5] {Kalman filter}; \draw (1,4.5) rectangle (3.5, 5.5) node[pos = .5] {Kalman filter}; \draw[->] (3.5, 0.5) -- (4.5, 0.5); \draw[->] (3.5, 2) -- (4.5, 2); \draw[->] (3.5, 3.5) -- (4.5, 3.5); \draw[->] (3.5, 5) -- (4.5, 5); \draw (4.5, 0) rectangle (5.5, 5.5) node[pos = .5, rotate=-90] {selection}; \draw[->] (5.5, 0.5) -- (6.5, 0.5); \draw[->] (5.5, 3.5) -- (6.5, 3.5); \draw[->] (5.5, 5) -- (6.5, 5); \draw (6.5, 0) rectangle (7.5, 5.5) node[pos = .5, rotate=-90] {combine}; \draw[->] (7.5, 2.75) -- (8.5, 2.75); \draw (8.5, 2) rectangle (11.5, 3.5) node[pos = .5] {steer}; \end{tikzpicture} } \caption{Diagram with the parts of the ntpd-rs clock control filter. The arrows on the left represent the measurements from the (in this case) 4 time sources coming in.} \end{figure} The clock control filter of ntpd-rs consists of 4 stages. First, on a per time source basis, a Kalman filter is used to estimate the offset and frequency error as compared to that specific time source. During this stage, the remote clock is treated as ground truth and any uncertainty with respect to UTC it reports is ignored. Sections~\ref{sec:Kalmanfilter}-\ref{sec:additionalchecks} describe this Kalman filter. Next, we compare all time sources and see which subset of them is in agreement. We also check for each time source whether it is of sufficient quality to use. Selection criteria, as well as the used algorithm, are detailed in Section~\ref{sec:selection}. Having selected which sources to use, these sources' measurements are averaged to produce an estimate of the clock offset. The procedure for the averaging is described in Section~\ref{sec:averaging}. Finally this clock offset, and the error bounds on it, are used to steer the system clock to bring it in closer agreement with the remote time sources. We steer primarily using frequency adjustment, the exact procedure used is described in Section \ref{sec:steering}. \section{Kalman filter}\label{sec:Kalmanfilter} To estimate offset and frequency error with regard to a remote clock, we use a Kalman filter to interpret the measurements. Although we regard the remote clock as ground truth for this filter, we choose to parameterize the state as a function of local time $t_l$. We will use $t_r$ to denote the time indicated by the remote clock. The remote time corresponding to local time $t_l$ is denoted as $t_r(t_l)$. For convenience we will use the same symbols as Wikipedia for the equations for a Kalman filter given below. Our state model consists of two parameters: The offset $\Delta$ and the frequency error $\omega$ with respect to the remote clock. These are defined such that \begin{align} \Delta(t_l) &= t_r(t_l) - t_l, \\ \omega(t_l) &= \lim_{t_l' \rightarrow t_l}\frac{t_r(t_l') - t_r(t_l)}{t_l' - t_l} - 1 = \frac{\mathrm{d} t_r}{\mathrm{d} t_l}(t_l) - 1. \end{align} Combined, these form our state vector \begin{align} x(t_l) &= \begin{pmatrix} \Delta(t_l)\\ \omega(t_l) \end{pmatrix}. \end{align} We will use the symbol $P$ to refer to the covariance matrix for this state. Given these definitions, the update matrix for when a local timespan $\delta$ has passed is given by \begin{align} F(\delta) &= \begin{pmatrix} 1 & \delta\\ 0 & 1 \end{pmatrix}. \end{align} Updating the Kalman filter's state from $t_l$ to $t_l+\delta$ is then given by \begin{align} x(t_l+\delta) &= F(\delta)x(t_l),\\ P(t_l+\delta) &= F(\delta)P(t_l)F(\delta)^\mathrm{T} + Q(\delta). \end{align} Here we will keep the process noise matrix $Q(\delta)$ general, stating only that we require two update steps of sizes $\delta_1$ and $\delta_2$ to give the same result as a single update step of size $\delta_1 + \delta_2$ when no measurement is done in between. A detailed treatment of our noise model is given in Section~\ref{sec:processnoise}. Measurements from the NTP protocol give us an immediate estimate of $\Delta$. Letting $z$ be the (1-element) vector with this measurement, and $R$ its covariance matrix (which in this case is simply an estimate of the variance of the measurement). This corresponds to a measurement matrix of the form \begin{align} H &= \begin{pmatrix} 1 & 0 \end{pmatrix}. \end{align} Such a measurement can be incorporated into the filter by first calculating \begin{align} y &= z - Hx,\\ S &= H P H^\mathrm{T} + R,\\ K &= P H S^{-1}, \end{align} which allows us to update the state through \begin{align} x' &= x + Ky,\\ P' &= (I - K H)P, \end{align} where $x'$ and $P'$ denote the post-measurement state and covariance matrix, and $I$ is the identity matrix. The intermediate matrices $S$ and $K$ do have intuitive interpretations. $S$ gives an estimate for how $y$ is expected to be distributed, giving the covariance matrix of the vector $y$, which is expected to have a mean of $0$. The matrix $K$, also known as the Kalman gain, gives a measure for how much each part of the state should be affected by each part of the difference between measurement and prediction. We will use the symbols given here for the various matrices involved in the Kalman filter throughout the rest of this paper. \section{Process noise}\label{sec:processnoise} For our Kalman filter we need estimates for the process noise $Q$ and measurement noise $R$. Let us start by first considering the process noise. Working out the requirement that a single large step should give the same as two smaller steps, we find that for all $x$, (symmetric) $P$, $\delta_1$ and $\delta_2$ we should have \begin{align} F(\delta_1 + \delta_2)x = F(\delta_2)F(\delta_1)x,\\ F(\delta_1 + \delta_2)PF(\delta_1 + \delta_2)^\mathrm{T} + Q(\delta_1+\delta_2) =\nonumber\\ F(\delta_2)(F(\delta_1)PF(\delta_1)^\mathrm{T} + Q(\delta_1))F(\delta_2)^\mathrm{T} + Q(\delta_2). \end{align} The first follows trivially from the identity \begin{align} F(\delta_1 + \delta_2) = F(\delta_2)F(\delta_1). \end{align} This same identity can also be used to simplify the second requirement to \begin{align} Q(\delta_1+\delta_2) = F(\delta_2)Q(\delta_1)F(\delta_2)^\mathrm{T}+Q(\delta_2). \end{align} Writing out this equation in the components $q_{ij}(\delta_t)$ (using that $Q$ is symmetric) gives \begin{align} q_{11}(\delta_1+\delta_2) &= q_{11}(\delta_1) + q_{11}(\delta_2) + 2\delta_2q_{12}(\delta_1)+\delta_2^2q_{22}(\delta_1),\\ q_{12}(\delta_1+\delta_2) &= q_{12}(\delta_1) + q_{12}(\delta_2) + \delta_2q_{22}(\delta_1),\\ q_{22}(\delta_1+\delta_2) &= q_{22}(\delta_1) + q_{22}(\delta_2). \end{align} Solving these equations, we find that there need to be constants $A$, $B$ and $C$ such that \begin{align} q_{11}(\delta) &= \frac{A}{3}\delta^3 + B\delta^2 + C\delta,\\ q_{12}(\delta) &= \frac{A}{2}\delta^2 + B\delta,\\ q_{22}(\delta) &= A\delta. \end{align} The $A$ contribution to $Q$ corresponds with a random walk noise of the frequency with infinitesimal steps. Similarly, the $C$ contribution is a random walk noise of the phase, without any underlying frequency change. \footnote{For an explanation of the names of these noise components, see Appendix~\ref{sec:randomwalk}.} The $B$ contribution to the noise is somewhat harder to interpret. It corresponds to a form of correlation between the infinitesimal steps of the frequency and phase random walk noise. As such, its maximum amplitude is actually limited by $|B| < \sqrt{AC}$. Furthermore, it has no effect on the expectations for Allan deviation and modified Allan deviation. This makes it tricky to see whether it even corresponds to an actual noise component in the real world. For our implementation, we assume process noise is purely made up from the $A$ component. Doing this will enable our implementation to dynamically estimate its own process noise. Our assumption is reasonable for NTP as for modern computer oscillators, the phase random walk noise is dwarfed by channel noise until frequency random walk becomes dominant. We assume the $B$ component to be irrelevant based on the observations in the previous section. \subsection{Estimating process noise} The process noise for our Kalman filter will depend both on characteristics of the remote clock as well as those of the local oscillator. As such, although we can estimate a reasonable value as a starting point, it is unlikely that all computers will perform at their best with a single estimate for the frequency random walk noise. To solve this, we dynamically determine the process noise at runtime. The filter is started with an initial estimate of the wander noise, by default $A=10^{-16}$. Then, as each measurement comes in, we calculate the probability $p$ of getting a measurement that close, or closer, to our state estimate. Based on the distribution of $p$ we can then determine whether our estimate of the noise is low (if $p$ consistently is large) or high (if $p$ consistently is small) and adjust $A$ accordingly. Concretely, we keep a counter $M$ with a starting value of $0$. If $p$ is smaller than $\frac{1}{3}$, we subtract one from $M$. Conversely, if $p$ is larger than $\frac{2}{3}$, we add one to $M$. Finally, if $p$ is between $\frac{1}{3}$ and $\frac{2}{3}$, we move $M$ one towards $0$. If $M$ gets above $16$, we reset $C$ to $0$ and multiply $A$ by four (doubling the standard deviation of the noise). Similarly, if $M$ gets below $-16$, we divide $A$ by four. Waiting for multiple measurements before adjusting our uncertainty estimates ensures that our estimate doesn't keep changing. This is further helped by having the region between $\frac{1}{3}$ and $\frac{2}{3}$ push $M$ towards $0$, as this works to keep $|M|$ small. Of course, $p$ shows problems with the process noise only when it is a significant fraction of the total measurement noise. As such, if the measurement noise is more than $\frac{9}{10}$ the total noise of the difference between measurement and prediction, a $p$ smaller than $\frac{1}{3}$ no longer lowers $M$, instead also pushing it towards $|M|$, to avoid becoming overly optimistic on process noise if the measurement noise estimate is somewhat pessimistic. \subsubsection{Calculation details for $p$} To find $p$, first note that $S$ is effectively the covariance matrix of the difference $y$ between the prediction from the filter for the measurement and the actual measured value. This implies that $y S y^\mathrm{T}$ is distributed according to a chi-squared distribution with one degree of freedom. The cumulative density function for the chi-squared distribution with one degree of freedom is given by $1-\erf\left(\sqrt{\frac{x}{2}}\right)$, where $\erf(x)$ denotes the error function. Combining this with the above, we find \begin{align} p = 1 - \erf\left(\sqrt{\frac{y S y^\mathrm{T}}{2}}\right). \end{align} \section{Measurement Noise}\label{sec:measnoise} To complete the parameters for our filter, we also need an estimate of the measurement noise. We will construct this using the variance in the delay in the NTP measurements. \begin{figure}[h] \center{\includegraphics[width=0.8\textwidth]{measurement.png}} \caption{Schematic diagram of an NTP measurement.}\label{fig:measurement} \end{figure} To start, each NTP measurement consists of $4$ timestamps, $t_1$ through $t_4$. These give two time differences, the forward offset $r_1 = t_2 - t_1$ and the backward offset $r_2 = t_4 - t_3$. The primary assumption behind NTP is that when the client and server clocks are synchronized, $r_1 = r_2$. Hence, these two time differences give rise to two estimates: the offset $\Delta = \frac{r_1 - r_2}{2}$ and the delay $d = r_1 + r_2$. We now make two crucial assumptions: First, the forward and backward offsets are independent random variables (i.e. $\Cov(r_1, r_2) = 0$) And second, the mean value of the delay $d$ is constant over multiple measurements. The first assumption allows us to relate the variance of the offset to that of the delay: \begin{align} \Var\left(\frac{r_1-r_2}{2}\right) = \frac{1}{4}\left(\Var(r_1) + \Var(r_2)\right) = \frac{1}{4}\Var(r_1+r_2). \end{align} Then, the third assumption permits us to estimate the variation of the delay from the sample variance over multiple measurements. We implement this in ntpd-rs by keeping a ring buffer with the last 8 values for the delay. A quarter of the sample variance of these 8 measurements is then used as the estimate for the variance in the matrix $R$ when incorporating a measurement. \section{Additional filtering and checks}\label{sec:additionalchecks} In the previous section we described the main Kalman filter used to estimate clock differences from the measurements. There are a few additional minor checks done in the Kalman filter stage as well. First, at each measurement the filter checks the relationship between the local wall time clock and the local monotonic clock. It can estimate what their difference should be based on how the clock has been steered by ntpd-rs. As such, any unexpected differences are indications that some other process has modified the local clock. Upon detecting such differences, the filter is reset to a startup state to ensure more rapid recovery from unexpected clock changes. Second, before each measurement is fully processed, the delay is checked against the buffer of previous delays. If it is far larger than expected (five standard deviations above the mean with the default configuration) it is ignored. Only if a second sample in a row has a delay much larger than expected then this second sample is actually processed. This simple pop filter allows ignoring of one-time upsets in the network which would otherwise degrade precision estimates for quite a long time. \section{Selection}\label{sec:selection} The Kalman filter stage gives us for each time source an offset and frequency error. We now need to make a choice which of these sources to actually use to synchronize the clock. For this, we first construct for each source a range in which we estimate its actual offset to be. This by default consists of twice the output uncertainty of the Kalman filter, plus a quarter of the mean delay to that time source. If this Next we search for the largest set of agreeing sources. We consider two sources to be in agreement when their likely ranges of offsets overlap, and consider a set of sources to be in agreement if all possible pairs in the set are in agreement. This set is located by first creating a list of all the endpoints of the likely offset ranges of all the sources. Next, this list of endpoints is sorted in order of offset. By going over the list in this order with a sweepline algorithm we can find an offset within the intersection of the ranges of a maximum set of sources. Once we have one such offset, we then go over the list of sources a second time, selecting all sources whose range contain that offset for synchronization. If a majority of all sources passing the range size criteria, and be of sufficient size (by default 3), then this set is flagged as actually usable for steering the clock. If there is no majority agreeing on the current time, or if that majority is too small, the next stages (averaging and steering) are not executed. In such cases, the clock is not steered until a sufficient number of time sources again agree on the current time. \section{Averaging}\label{sec:averaging} Having a group of time sources that can agree on an offset for the clock, we next need to calculate which offset (and frequency error) they actually agree on. For this, we use the error estimates produced by the Kalman filter, to which we add the time sources own estimate of its error. This gives for each time source $i$ a vector $x_i = \begin{pmatrix}\Delta_i\\\omega_i\end{pmatrix}$ with its estimate of the offset and frequency error, and a covariance matrix $P_i$ giving the uncertainty of that estimate. The formulas for combining the estimates and uncertainties of two time sources are similar to those for incorporating a measurement in the Kalman filter: \begin{align} \bar{x} &= x_i + P_i(P_i+P_j)^{-1}(x_j - x_i),\\ \bar{P} &= P_i(P_i+P_j)^{-1}(x_j - x_i). \end{align} To combine all the measurements, these formulas are repeatedly applied to incorporate each measurement into a running average. \section{Clock steering}\label{sec:steering} Having combined all selected measurements, the result can now be used to steer the clock. For this, we extract the offset and frequency error, and their respective uncertainties. The correlation in the uncertainty between offset and frequency error is currently not used. There are then three possible scenarios. First, if there is a very large offset observed (greater than 10 milliseconds), it will be corrected with a step in the local clock. Step corrections are limited by both the step limit and the accumulated step limit, which limit the maximum one-time step change in the clock as well as the accumulated steps over time. If either of these limits is exceeded, the software will exit with an error to alert the system administrator that there may be a potential security problem. If the offset is not so large, but still larger than twice the uncertainty in the offset, we correct the offset by running the clock a bit slower or a bit faster for at least 8 seconds, or for however long is needed to correct the offset with a maximum frequency deviation of 200ppm. However, to deal with the fact that the threshold actually makes it somewhat more likely that we are looking at an extreme value of the distribution, we don't correct the entire offset, but by default leave an offset of the same size as the uncertainty after the change, in the same direction as the original offset. During both of the above offset steering steps, the entire frequency error is corrected for. This is done either separately when doing a step, or as part of the frequency changes for the continuous clock change. However, if neither is needed after doing a measurement, a separate correction for the frequency is done. With the standard settings, this corrects away the entire observed frequency error. In ntpd-rs, all the numbers named above can be configured to have different values, and for frequency a similar threshold-leftover scheme can be used as for offset. The defaults for the latter are just both set to 0. \section{Poll interval selection} There is one final thing we haven't touched on yet, and that is how ntpd-rs chooses how often to ask each server for the time. This is done in two stages. First, the algorithm selects a desired poll interval for all time sources. Then, on a per time source basis, this is adapted to deal with server-indicated limits on how often we may ask, and backoffs that kick in on failures. Here, we will focus only on the selection of a desired poll interval. For this, first a desired poll interval is selected for each time source such that the measurement noise is between 40 and 60 percent of the total uncertainty on the difference between prediction and measurement. This is again done with a counter mechanism similar to the process noise estimation. This time, any measurement for which less than 40 percent of the difference uncertainty is measurement is a vote for a longer poll interval, anything where it is more than 60 percent is a vote for a shorter poll interval and anything in between pushes the counter back to 0. Then the overall desired poll interval is the minimum of the desired poll intervals of all the time sources. This is currently done as a global indicator primarily because of limitations in the architecture of ntpd-rs. In the future, this may change to a desired poll interval that is different for each peer. Note also that, as in the case of process noise estimation, the specific numbers mentioned above are configurable. The values above are the current default values used by ntpd-rs. \section{Performance} We evaluated the performance of the new algorithm against the default settings of chrony version 4.0, another NTP client. For this, we connected a Raspberry Pi 4 via a switch to a local GPS-connected NTP server (an Endrun Ninja). Both the Raspberry Pi and the NTP server were configured to produce pulse per second outputs. For each test, the NTP client under test was started on the Raspberry Pi with a fixed poll interval of 1 second and allowed to stabilize over a period of at least half an hour. Then, the offset between the pulse per second signals of the Raspberry Pi were measured for one hour. The results of these measurements are shown in Figure~\ref{fig:offset-time}. Both chrony and ntpd-rs were configured to use the local server as only time source, but otherwise used their default configuration. \begin{figure}[h] \includegraphics[width=0.5\textwidth]{offset-ntpd-rs.png}\includegraphics[width=0.5\textwidth]{offset-chrony.png} \caption{Offset of the Raspberry Pi running ntpd-rs (left) and chrony (right) over a time period of 1 hour, compared to the server they were synchronizing to.}\label{fig:offset-time} \end{figure} We haven't corrected in any way for asymmetries in the setup on the network layer, so any difference between the average offset to the server and the Raspberry Pi cannot be interpreted as significant advantages for either ntpd-rs or chrony. However, the deviation from this mean does provide a clear indication of synchronization quality. For chrony, the deviation is $3.6$ microseconds. For ntpd-rs it is $1.8$ microseconds. From this we conclude that ntpd-rs is at least on par with chrony, and likely slightly better. \bibliographystyle{plain} \bibliography{algorithm} \appendix \section{Random walk noise}\label{sec:randomwalk} In the analysis of the process noise we identified two of the three components of the process noise as phase and frequency random walk noise respectively. In this appendix, we discuss where this term comes from, and the intuitive model behind it. Consider the following process: We start at 0 and at each timestep $i$ we make a random step $X_i$. We assume that the steps are independent ($\Cov(X_i, X_j) = 0$ if $i \ne j$) and all have the same variance $\Var(X_i) = s$. If each timestep has length $D$, then after a timespan $T = ND$ the result $X(T) = \sum_{i=1}^N X_i$ has a variance $\Var(X) = Ns = \frac{T}{D} s$. If we now make the timesteps smaller, but keep $b = \frac{s}{D}$ constant the variance of $X(T)$ also stays constant. In the limit where the timesteps length goes to $0$, we still get the same form for the variance of $X$ over time: $\Var(X(T)) = bT$, which is the form we see coming back in the variance of the phase and frequency respectively in Section~\ref{sec:processnoise}. There is one further detail to further discuss, which is the contribution of frequency noise to the phase noise. Because the phase is effectively the integral of the frequency, any frequency noise also shows up as variance in the phase. Going back to a model with steps of a finite duration the variance of the phase as a consequence of frequency noise can be calculated similar to above. We leave the actual calculation as an exercise for the reader. \end{document} ntpd-1.1.2/docs/algorithm/measurement.png000064400000000000000000000552441046102023000165550ustar 00000000000000PNG  IHDRHOgsBIT|dtEXtSoftwaregnome-screenshot>)tEXtCreation Timevr 08 dec 2023 09:25:53 CETn]n IDATxw|u&!A@ UT;M=*$ )z"(X X"]z䀄"!fL(Vd#p&;=oömf """"KPDDD$(D@("""aEDDD"HQ0 """"FPDDD$(D@("""aEDDD"HQ0 """"FPDDD$(D@("""aEDDD"HQ0 """"FPDDD$(D@("""aEDDD"HQ0 """"FPDDD$(D@("""aEDDD"HQ0P7@DB,:100 #_c6mg{LH2X0`ï}Or>+G@ Kah"Gtt4 4e˖.\8͓q޽{ٰaW^y%-[r!n*"0yd>G-, 0׏1cN:7ڵk裏DR=z4 t?9s{l+QѣGZ."I ","uV͛Ǽyعs'@L _歷"PP!7nLRXn;wȑ#!M"eYddd0|ϟϜ9s ݻ֭w4MnV^/?={d{HxP\xz,YǃDx^bbb8to^%J0}t,Xe˨S͛7W_ 94M ,HѢEx<\z饔,Y)Sp|>/"gf֬Y 24 L0!ĿMPDr3~k׮7˲,7|]W_rJRSS }4nܘ@ _, 4ٱc&=z4]ta׮]Xر#ݻw̝;۶)Z(z¶m ]vtҘ3aRDƒ&HpƋ߿'KtRWNŊ)Rz깁)R$]ϟ'|O8ԩS4hݻw^zTX… !~ĉXEŊ."I "RSSY~=&L`ܸqI ͛7B *U`&(Pٶm Rn]yfo΀HJJ.cȑ)Rz>733iӦ}v{=vMŊ6mjRX #H*Z(M4a͚5nSzJ*e{ʕ+ݻ7[lnݺضêWNC iӦ\޽{kl&--L,rv̸>׋i(PҺukJ,Izz:0s"" `GVέt 4MLtam<?ݻw/lٲ 2N:ݑ0 <O|~YC#66?lڴ͛gz).J.CD @  4M "0a{owwͪU€-b\uUԪU^z 8hF\{'XnKuWDB+W+NUoʕ|X{bY jժԭ[-[R|l8\ٶMzz:iEff&s֭2j(222xmڴ>!9gy_~9vlٲ̜9ڵk #9!C0h q=p7b6?_|>ŋsןCCx>Yլϱ,+~{]yYyίMpe(/lܸ>`;wf֭X$r>\<6h6I |g,\ *3~?=Ç*. SWC>%q*--cǎPpawhDONqvCo>lSD ڵkeY~w`ٲeٳ'zcY͛Yt))))x^*UDÆ )W9m  EXp!Ŋ;pg+)S]4d~?^Y]nK,᧟~"::Tds/33wt"E(Z(e1o<,YBJ{"fή;Us]x;ʺ5.̎ (`'&&ڇ[jeivŊN:  *d(P7nm۶ ڹs]hQ;..Ύ^9m۫W5kfGEEӾ2eCu'57ncccK..Pkv&Ml0lS/g#"rXKDW/c6$$$pa^/׏3gҲeKիG5L2icVM6ݻ?СCl߾'W餥pqzVi֬~!O૯[nne0o;**t+f>pm۶9x`uǞ8qbsQkuK,i߿߶m޵k]hQ= ئi lb9rNIIm۶~a0 ڦiӦMsDž ۆa؆a]vu׷o_^]@{ڗlWP6M6MӮQ} ۶m{nWӾ{vRR}aV,Wmgweʔ ðĄ{˖-mvZZ]vm7$5m?O>qC"`O03+4~g_} ðy{SLm۶j+Wm_.]ozk7mڵkPxl0QFȯ˕[ywIMMeҥ̝;˗qFw cy͛ǡCزeEsNڷoO0tc^j&^M6Ŋwg9 àA$$$}v,X'(T3gt/_ gfݻ]p͚5gYQQQeC `˖-vmn  RbE^wֲ16"""WJte]hѢhт-Z ٴi_~%cƌaI .dڵ*T@ ?3gVw2B +Ve$Mپ};^$֯_ 7 36nfJ*e֐ew _k_ àJ*2&\4yP+pܸq,]X;8 "{<j׮MڵiӦ M6%99ٝeqFnf7 ٶMʕiРmܛxEz0hݺ5oaYbp-lѢhwK0f͚\s5Z˲ܪ`ff&\sۦe/^CF{[~UZ&M0a7L>}bŊGZZmsUW1nܸݖ j ?NjР*Ubǎ̛7Ͻő{M7߸qcFT-r*e3 1 -+ʴaF6 J\gP'ϕ `Æ 0a111MF^Z珕ƚ5kܱpmSlYS˖-0 -[Ƒ#G(V;N4MN> e˖Zjlٲ0X``lÁ5j[ Zjfm_N?yGWʿ;=Ӭ +h%@"<'ʋ3Lİg&ɶmbc p_;)6\htB]V?Ɂ|ٳoR~}.R233ټy3#GdӦMDEEIBBugɒ%DGGLbb"ÇH"}x衇t۴iСC-T.yeC.]4hlڴA˽5޽{ѣsTRWېcdI? 3ۻ7ǩ8eV d%kwj|؆KJqէ{P7w eY3b:to>H"dddpI7Ƕm^&NȂ b,Z 4YlĐ+Bʕܱ^׭]\j֬ƍ1~`e˺?g-ٓSvZ:t(f͢f͚~7l0άe$uVrN)Sci?"olO (\Ť%*4N9~fP+a`a&dkU*nݖSGOb&(Kmh `? w>~;b7n7_C`mY:yo_mns=w{#s쫯7ömmڵk}Cv9,;h[eWHmٶbvڵm~烶ev6_vnqgKf͚!o/+rm۶ԩ;𫯾bǎ:t}NѢETr =zrt.]Yf1zh>cnK+y֭Xnvw3 g.]@{ͶmUƜ9sx뭷>}:۶mԩSkצw޴nWP!nw}:udkGN04NG„47n`8vu;۶O0ct.w|Hd;+öe6E`6wȑ#|> ||s III8q۶FeddsNN:a+V+m"ę$ yꩧxW_tܙI&8X8u]aŊ "a.W .sk˲-r\=.=Oά=O[bO$qr}_xܰ i۶-~i*yΘ1oF)\Y9Amoz?,Q>PYr%ݻwgDEE507t . u3,o/_9sz+Bzi3GcǎQFl޼L[6JTz)Νڵk"~T\OBQ5jԠjժ]vrc $ϭcǎ*UCE"kE$טIVX~=Wf,[￟B 0 ~gv78ߟO>$UE”KjըX"eʔxжm[/%Bb#*`݉c!n\*gV m~Gy+ǻ# {,ˢXbՋwy;_$ *"ʙ x0 !Ck@ w?O> `䄽z:gj*|IY׿ڵ+)))!nQΘ *ЩS'z-w1| !]PD">\&M8vk׮=9eA p> 6PvmƎ|$mLTBÆ {ӥ8gפIHMMo߾!n&۶O>!))]0ZDBC@@jժQ^=&N P:z( tܙ7xCۀH("9ʩ}ܹ<-PmK/|qqAUEBHPDrSy饗hڴ)W_}*?W^ "* "c,0 Ν˺ux#S+_<;wfȑ>}ZEBDcE$8oӧOrJ@}TeW;Ã>;gn/-ZhM6m6<. DrD߾}{6nȦMt`ԫW>6m@$)E焿[RF F<l 6$--իW t$3bJ(AΝMp?Xv-~-aKHSPDrIHH駟駟VOm˲UKfΜ9ZH$h,"sM9j(|>> =ζm<?;w.VRP$("݉'\2]veСeddPjU4hɓUEq7'Nرc;-pfY׏O>$N$("U J*4hЀ'#lTZN:ohET>SvEbbb[$Ω-Z￟qq!?\("34mڔ:uꨒ##|8Jcǎ 8{k2|N$("SINN&!!'EڵgܹnH%cǎ%&&=z_TȼyXj%D.6UEO;y$+V[n :TKEW^ 7)SB|G"9U?B IDATs1zI~bYӇO?$@U@I@S~?W\q7fҤIElK$$$p2|pmc"*"8h裏HIIaРA!n7-#<»ÇES?ĹG/N5TӳgOF ,r(ٺu+׿s}e˖[n1ӧOkE1"5jԈ /_H>)}vVʨQի֚Ewqy-[F>}:wyNƒu֬Y;w^".ΉM6lݺ7xB, krWұcG]xE "yfjԨq֭N’+q?~UVC/ґ[D~7xӶm[@}){9֭[Ǽy=."*"KJJ < 0@KHmkbŊ1{P7G$O廈*qDEEѽ{w?Uea̙3իW SNqӵkW^uU$dN>M5[.'Oֶ('("TWƎˉ'ׯ_[$̶m (@~:u*?n''("*## *pm1~xU\$?Nʕر##Glt?A{S裏8p qDT .#<{O?iA "r^a2d͛7+t⋄ZϞ=mQFZFRs8Ao<3n;ttڕ#G? X@n@ ҥK5O†-ر*U0rH}QE$h"n&K5kg{l׮+V`ǎĄY"yWVYv*a ׯN:|tQ*"M]6w%,9mƑ#Gu";2ID\N1beʔ} 'NbYsf{\D.L@~߿+3p@uIسm뮻bŊ7߄9"y"oATT=zT\<̞=+Wl"r~رc/_~W^yE?3222^:_=SLѸUߠ# x9}4=<3|ڵKۮoPpmxHOOW^SN+WN}<ömlۦ]v4k֌ 5pN7q޽;[loED1@! RF *U̙35~J,]>P7@DB9Y~lݺ(Jt:.f;̸X(lۦADEE*Iذ, `ib}ڶeY miͺ=g}}ր{? \H@T-ZIJe˘9s&Ꞔ 5y<طo>/0ugݦ{j"::`0ԩS ̘1{b+W]v$&&R@@E"sڲe jwޡG:IXpB^Oc֭.]˲z<3}}"E9s& 4 zݮެYf̝;rʱrJmLO~ر#&M:{X$/T) _{5J*E-,4MLg `&^ /ge_~eƍǝwމرc 0 Lt״z/Pqqqng}z4k֌/ӧsc&|֠H^ ONNfҤI <8-!aѣqI;wrIJ.ɓx<{9=C Xz5;vÔ)S`0mBȑ#G8~8iii~vA||<|+V &Pxq7n e˸[sO"rh/a믿Ntt4=z."śoIٲeꫯHKKn+`ƍٳǽ`i׮@t];A ~đ@ a >:Ē%K0MX .}mkC,^ ,Hf͈'..cǒALL mzٻw/ Op7Eb$W_}{nʕ+>#)Q;K|裏ݷ 7@ζެY3k)R9o>zɦMKxٳ.$OӖ+AL$==^{nݺQ\9wH,3~Z' ꫯ[פI mfYC0wxD  33`0H0dŊu۶k.N>'y^&Mā4h.H3 >LzMYv-ʾ}뮻hР,]ZׯQQQ!\ 5k֤Yf&Hrݣ>w|>@w^VZn:{ؙ ݷ111voY ^zضMZZɤ#ЧO^/Noa…~ .oMͳu#5ZP$s|7oF7nݺ'yΝ;RdIۗm3Ilʕ#&&}ѧOOO?D||ޟml۶ 8S5P7o… 9|~r ˗?"yH>,Tۭ[7ϟ϶mۈ uD~sTX%Kp-p3m4~οeVLP$rN{+`Ȑ!<{)Y;{1z!55ʕ+SfM>#J.m8LVij|A@D)6|px|ݬ_|AݺuzϜu"*"RSS)W{W^QO"c_3220MV"s]7zh?8|8ۿ3;x̙TRݻwW$?SɇLĉt֍RJE"s3yTf͚Ŷmx'Df`bŊѳgOFͱc ,CE ł BTƓX"Æ S\".uD w߱tR 'r!΂e˖SN 6YO"*"Sh޼9)))^317l@ڵ8q"]tњ)N۴i5kdܸqtM'1ZlIrr2Vœ{:3#/2ʕ}~#Ϻu3g(9ՋݻwSbE^yUlۦ~2o."ٓ(~m@KH(93 mFbb"_KիF"55U]h Hue"rq83\2/,.iDpB/_ze"3lٲtԉ7|4?WTc*DfطoVY"mذ:u0~x^|CP$zR]6'NK.~բE RRRXzŸڒEz_tҴm_o `ݺuX[ @@<©F$%%QJ^u.)fY 6$:: ."yskQpaw'l4M ~˪UܥbD2UERB|I^xUDrzTV3fhߓ /`֭*i9gщ'HHH}$233)W-ZSP4m"yĤI8r} uSD"eYDEE1p@&L@JJ ig)90^]v$$$'˜G1rH@ߖKP$9'ӧsNH$293)?رc9r䈪gi HmuR`Aw!Z}N}Ϟ=TR^zDU%ORP$L93 ;{=."0 lۦ|t҅7|ӧO+I Hr M6e_fD4gܸq#uatE3%Q CIfݺu\uUL 7 {(F:oCJ޽{Z*KXSP$ĜܹsYjO=TE$9Urq2rHN>'aM@s7ѣ[N'<ƙ ejԨ{-@rNV?cǎ:iaZdݺuڏ%l)SkӦ k׮e۶m|>UE mҥ4hЀYfqwN’H8o۶mTV7|޽{d!9u,˗k2%eDBl/^nݺ(aNMgeŊ,[ 04KŽ*"!TCժUyygUj͚5˙5kvt czy衇UD'=S|lܸQ H;v*UpwoB ddd￯}\Š "̹8q"G qDb,h2e wVPŠH.3 iӦ UVUe@$qsw},X~;-NP$93MƏ?Hbbb[$"9Ų, .?رc9r.$lh H.rvڵkSD ΝH>)))TR^xDT%easeƍ 8@cD)g_2eҥ #F ==]O‚*"Ĺoذ!'Od͚5H>7oF?]s*@rH.pN˗/^z|tQ ?Dgoժ;vpTؓPR u֬];vzu΅޲e˨_>3gΤy0صk\s5nDDrs߼y3ӧOgРA|>ib6o~tԉݻw+Ers>|8tmD"sϲzj/^ 9>Ӈ˗SF 13Hr~˔)SxLjUO$8@ @&MV/a[o1zh^/Vܡ( Fa<n241M׋?-bС<qJn"S;z(cǎ{\veZV$L:3fPD |dddœO> LK/%w('M}:Ç?{8`g{攬D !iɫJIHHЁ]$3eFEr}_˲4OrHp}'ٳE" mcYz?/'33VErCX-(g˹2rv,+I}_HNpԩC%;w"9ܹxo |@ *qFJ(r9Y-9'̬AgAp=|lڼ}e[H$3SREfΚO<1c|4,IJ-],aa`7>WnIII̚5e˖̉'(\0ժUI&j]Cc(PL:t@ٲe3gׯ'** ۶i׮eʔU"K10XdI""ah<:tJ*&I i rǎ_wԩSP>e<Ȍ3x{ذa<9Nm3YF4LO&y3!` IJ%{iF|m."Y؇lbkr|6~1ɟbukL틢_Δ(fϵ iĉmۖ+WE  33xj׮M8x}>eϒ@eỲڬԩÁ" RX1m=1g;ݯ4ٴi/td r_={6 6tiMdɒ%<3,YJvԪU^z-Zd[fҤIۗh-bӦM 4d{F1vXx'㏳K/1d 5jcmt)""r1e`r=:cܖ.]ꎍ3 ֭[Spa7\em裏3f/233l,ӭ[7 6вeKFMϞ=;c333|L:m_p!ݻwgrl? Ovp0l"""rqd cعs'pf̜sp1  cM- 9! s^/Wk׮dffb%KCT\;v0eRSS1 >}puqWmSNxhтXV^͊+0M˒%KXd M6m۶TZ۷3c =6mJݺuȠRJXr5:ѣضM0Rti]Ygk۽ IS ! /m1U(`m0a"eqFZM[Ƕढ c2qR4 TJ! &뒻 k1nrGl瞃[-22RSSsxw}p\pxs>zRzzz-Q| ͛G}}vpB=] SdDשgR@gu_t;v {fa K,l(//GccD=܃4ǃu0M]]]>r:0MgH8fAuӟz/ zgvvv.ݻwNK'VPU8tƏ/8i2/bUQOxZVicƌ 7܀ vU믿.W͈SO=%\bfkFuu3 w+=gy:n0s{Z20:u*e(,//aΟ'e/?WJ'B[rr2v}Z ÀiPUϳOZM-GDDDʰkɱu~!vލyɖ6ihooGii)4Mipʒ %0}Gʕ+q6 W_!4M wbY%}o=aPsw#%%E`8xo*4Mʕ+q (ۍh̛7OJ`JJ ƌ#h}.V''N`x饗PXXgƕ^ck+>6]Zȟ]KR4M0 v'ODVV~###!!!hjj֭[QYY UUe8[|9&M$޽0&B7|3233sNvaӦM͕GAMM `x駇="h `Ν2e l6=s|0ddd 44t/SoѣGqQcܹKfX_7w\+x'`ގ"3梵?OQXX(_GUUeX8z(bcc^сl}}O>l9sP]]3fAWհ@R7~+DFFbժUhhhDhŢE]|*Fshdb>C~\.q9sv 4l AibѢE3g6n܈2:u rDLL z@7„ pm!44nr[\\]ex999ċ/_hnn3""SNŪUVqLL )k-HNNnGOO>0j({Akk}{>mxx8:::p8|BÇo??Ox<a@(0{Dxx8E],ڵk{n("'IZEt(SPOO Á馛Μz>]۬o:7664 &MBRRRz j\͟StO4rJ>|UUUp݈Ejj*&MB!??sQ[['2ӉŁ:&NYf!!!k׮R<;v,#88UUU>}7V "-&|\ºo`Q__/[ߎ#G?k&?111a$ HNNƗ_~1{lݻԩS3gyf?~ׯGHH>#@ꆵ m*[KXخ9㹬8EAII <tuu!++ /\z̙9s|NVVx& @aaaxg<3p\HOOGaa!4Mk梡?0.]'|隺npd($b( bbbⳟu?AD8TUEbb\w"** ӦMwCEE}V8y2]D_ֱl#"=[{(صk^z%DDDW_Ř1cx|zzzzXrhY[kX"TϢ[ zKbĉx7p 7 @# vX_ X?0n躎sHLıcp1`):@x/\Чp!(z!r-zaQ\\={nz+1WE4+ l6ƽދiӦaڵ}ZUUi>u"y' ͆}!''fիyN¾}*!7x0 ~u--->hD̙3a eee?!*0p9躎y8cHtm6رwo#!!QQQrBÁ]va8r 37]p80n8/Y l$Bb0Њ1֥XË(p]=}=* """ 0 DDDD(0@"""HDDD`  Qa$""" 0 DDDD(0@"""HDDD`  Qa$""" 0 DDDD(0@"""HDDD`  Qц+^/E(  ED,1w E7 _ 0dXTzHDtogZlc… 0MIIIx7e(d$ EiBUUDii)4Mƍ4a`&<6@OOހhqnwx= EbÇQYY)z_ x(GǿUJG H5 ] &C(uibbbPRR7<( Ð2TU9alPk4M٪5<Կwy. K,n HufoPPn˰GiK888 @*t]8 4}aWWahP !$eHOv$%%ٳrl?UUxЀ[oU%%%>?'Oƅ ֭Ccc#6lxϗIQVVoY^hhh@^^ϟ"DEEwBNܗ %''fe" ;QQQ9^we-m&bccQTToi"33K,Aaa!v;n7f͚իWc`۶mؿ? prO?pEUU>Sl6Xt)n݊cǎD^c*/6 Au۷pwbGI#  YW3@ip։v]Κz[D>>&Ooa@uh &~3 #>} . zs㧤ĉu]#55~)?ǹs(imۆKBUUe ++ \hQUbvYп刌!Sm p)`5'TR.ئ( c^yyyXQtww7nyv;t]+"_W3Ċ+pU]; D#L\)BV;5 :9@3ى}D럪عs'Xr%rrrcL# .5$Y$< VoתŹǏ7bʔ) J.=g QU===Xf [Dcȏ1k.gA9!44gwv٪p8.zG:#221Hp""?"܉IMMMl ګMdɂV֭CBBdY$Љ--- 2Y ~(NDt~\ `>]*\l2 TUUCyy9jjjw^X֭CSSp= ((,nY`.`"DȺa*T__zb˖-}fZÃ6=}꺎UV`ǎرcƎ־,[ 8CڽO"rrrO"**'|r-ar r4}9>az>}\.ǧ.88۷oG~~ؾv;y[PUU.#G@ǵЀz!\.twwZ 4 s<(3vXq>L|8~8t:nI4EQ_૯NEX/PRRǏVƉ''? f̘`D.%Qz}W`(X'60 j7ǒ`f?F4M'ZDHoqށItK(00N!""" 0 DDDDl//l9IENDB`ntpd-1.1.2/docs/algorithm/offset-chrony.dat000064400000000000000000000431201046102023000167700ustar 000000000000004186 4188 4185 4138 4126 4127 4181 4200 4196 4213 4171 4109 4037 3989 3998 3993 4007 3999 4004 3997 3990 3964 3933 3894 3843 3783 3759 3731 3709 3701 3690 3701 3679 3688 3690 3686 3693 3693 3676 3679 3667 3668 3664 3686 3727 3732 3753 3845 3967 3971 3983 3982 3992 4012 4052 4042 4011 3977 3950 3940 3946 3949 3944 3926 3937 3916 3918 3917 3914 3915 3916 3929 4035 4042 4045 4043 4038 3962 3939 3907 3902 3902 3888 3860 3870 3844 3798 3794 3482 3464 3455 3591 3602 3596 3597 3585 3595 3558 3561 3542 3527 3532 3544 3526 3513 3514 3499 3486 3494 3524 3538 3527 3515 3511 3531 3569 3576 3592 3641 3691 3718 3734 3713 3723 3749 3775 3774 3821 3896 4156 4380 4375 4413 4575 4741 4753 4767 4751 4678 4623 4633 4590 4501 4466 4228 3630 3618 3625 3568 3515 3590 3663 3677 3870 3868 3858 3848 3844 3812 3797 3776 3759 3719 3657 3554 3460 3435 3405 3390 3387 3371 3346 3333 3468 3494 3485 3448 3431 3404 3390 3370 3356 3352 3321 3306 3297 3301 3335 3335 3354 3362 3374 3378 3422 3458 3475 3490 3494 3486 3471 3464 3495 3550 3566 3585 3598 3604 3623 3637 3655 3652 3639 3658 3654 3675 3704 3714 3724 3729 3753 3788 3791 3755 3661 3637 3596 3612 3596 3582 3566 3580 3607 3656 3762 3801 3802 3834 3825 3839 3837 3840 3837 3826 3834 3832 3827 3857 3879 4046 4059 4074 4090 4113 4108 4117 4126 4167 4169 4180 4169 4165 4141 4120 4066 4037 3994 3999 4028 4031 4041 4029 4018 3999 3987 3977 3961 3944 3938 3949 3958 3969 3980 4017 4017 4065 4087 4081 4069 4082 4081 4078 4083 4099 4095 4096 4094 4093 4093 4105 4114 4104 4099 4120 4112 4089 4030 4032 4009 4013 4013 4019 4016 4017 4030 4026 4008 4028 4024 4020 4013 4005 3964 3930 3846 3832 3820 3779 3746 3711 3690 3671 3675 3752 3784 3797 3789 3781 3776 3756 3709 3709 3696 3707 3706 3703 3710 3698 3710 3708 3704 3682 3662 3691 3690 3713 3721 3698 3693 3693 3673 3635 3605 3595 3599 3598 3582 3573 3566 3577 3577 3586 3587 3583 3566 3566 3579 3586 3588 3580 3594 3637 3682 3702 3703 3730 3731 3723 3684 3673 3616 3572 3512 3491 3479 3461 3453 3438 3435 3443 3491 3499 3503 3494 3493 3498 3493 3483 3479 3576 3670 3761 3763 3774 3788 3796 3815 3878 3888 3902 3892 3891 3901 3908 3901 3888 3900 3896 3886 3851 3812 3804 3814 3810 3830 3875 3921 3955 3949 3942 3924 3936 3951 3958 3970 3949 3940 3953 3983 3996 4016 4010 4011 4002 3973 3959 3933 3924 3929 3931 3929 3933 3924 3923 3946 3952 4022 4068 4073 4101 4108 4146 4158 4177 4181 4182 4168 4156 4154 4210 4214 4217 4228 4236 4246 4274 4239 4227 4236 4235 4210 4189 4186 4199 4191 4167 4144 4050 4010 3990 3990 3981 3976 3969 3694 3571 3552 3516 3522 3492 3490 3499 3526 3549 3598 3631 3665 3679 3714 3751 3774 3852 3902 3928 3931 3939 3926 3924 3909 3895 3903 3873 3889 3895 3879 3866 3842 3811 3792 3827 3819 3839 3835 3836 3853 3833 3803 3800 3777 3797 3787 3783 3792 3783 3787 3789 3792 3809 3822 3812 3808 3808 3822 3817 3806 3799 3777 3770 3755 3734 3727 3656 3597 3507 3445 3436 3457 3523 3539 3602 3653 3684 3711 3773 3779 3787 3798 3791 3802 3807 3824 3811 3827 3816 3811 3798 3797 3784 3788 3781 3800 3782 3780 3774 3768 3779 3773 3782 3777 3769 3762 3736 3712 3714 3721 3769 4446 5292 5175 4546 3746 3757 3781 4063 4483 4348 4123 3978 3962 3890 3718 3599 3358 3374 3480 3598 3594 3586 3574 3577 3634 3700 3717 3732 3819 3819 3804 3761 3971 3974 3970 3963 3910 3894 3891 3874 3882 3880 3815 3772 3751 3747 3718 3704 3724 3739 3738 3742 3763 3769 3778 3888 3944 3929 3896 3847 3806 3783 3751 3756 3750 3759 3749 3743 3725 3705 3708 3689 3702 3702 3679 3653 3655 3672 3664 3688 3695 3688 3692 3710 3723 3741 3738 3756 3755 3761 3762 3769 3894 4054 4123 4125 4129 4116 4115 4120 4106 4041 3726 3539 2941 2823 2764 2706 2714 2860 2829 3011 2990 2977 2940 2965 3362 3345 3708 3728 3718 3724 3734 3735 3716 3684 3627 3590 3564 3558 3561 3535 3500 3446 3420 3402 3406 3400 3405 3386 3408 3477 3533 3564 3564 3572 3561 3582 3572 3581 3584 3591 3597 3690 3769 3806 3855 3879 3889 3913 3922 3937 3939 3954 3978 3988 4090 4287 4299 4318 4297 4256 4224 4209 4218 4236 4227 4213 4119 4147 4197 4204 4193 4171 4121 4080 4074 4031 4001 3982 3949 3916 3470 3477 3480 3455 3476 3640 3666 4346 4297 4193 4225 4206 4108 4088 4064 4080 4086 4080 4046 4026 3925 3888 3861 3861 3854 3869 3873 3892 3881 3887 3895 3873 3874 3854 3833 3839 3829 3841 3870 3872 3880 3918 3920 3932 3925 3929 3949 3946 3926 3927 3894 3867 3795 3714 3680 3657 3632 3600 3667 3882 3869 3851 3825 3821 3855 3862 3884 3893 3890 3852 3768 3815 3815 3789 3779 3748 3749 3751 3876 3876 3878 3883 3858 3849 3844 3845 3854 3860 3846 3791 3784 3759 3716 3709 3686 3639 3634 3627 3633 3626 3611 3606 3596 3625 3656 3664 3667 3660 3654 3650 3604 3575 3629 3670 3677 3657 3667 3681 3667 3694 3689 3689 3703 3682 3699 3740 3765 3804 3826 3840 3841 3838 3843 3837 3851 3905 3962 3997 4010 3997 3981 3968 3925 3830 3814 3781 3733 3731 3728 3741 3717 3725 3693 3674 3628 3631 3626 3624 3627 3631 3660 3658 3657 3669 3639 3619 3527 3465 3436 3402 3368 3341 3355 3370 3461 3475 3477 3479 3448 3425 3394 3359 3368 3370 3383 3391 3416 3435 3437 3430 3436 3435 3458 3472 3506 4399 5330 5226 4976 4851 4888 4780 4586 4479 4329 4282 4267 4200 4151 4135 4101 4021 3962 3933 3883 3841 3811 3875 3928 4048 4151 4162 4122 4086 4099 4071 3963 3798 3777 3682 3389 2891 2976 3065 3103 3124 3085 3090 3132 3136 3094 3060 3036 3008 3033 3022 3137 3243 3546 3576 3581 3576 3569 3560 3609 3668 3683 3678 3709 3735 3738 3745 3693 3646 3636 3631 3641 3632 3650 3645 3675 3720 3759 3860 3917 3924 3939 3924 3935 3976 4008 4019 4019 4001 3967 3923 3895 3651 3362 3292 3237 3170 3452 4059 4236 3893 3025 2300 1918 2752 3213 3309 3385 3620 3719 3749 3890 4128 4278 4351 4354 4467 4517 4527 4388 4001 3963 3681 3269 3561 3628 3885 4005 4059 4107 4134 3879 3873 3894 3888 3906 3926 3944 3973 4000 4004 3995 4047 4045 4027 3926 3873 3851 3827 3751 3492 3320 3242 3147 3080 3127 3133 3459 3625 3610 3638 3316 3069 3397 3689 3735 3726 3356 3491 3891 3854 3871 3911 3924 3904 3918 4009 4120 4171 4188 4193 4130 4037 4016 3949 3877 3807 3778 3778 3761 3735 3690 3702 3702 3721 3723 3733 3729 3746 3724 3771 3867 3936 3938 3939 3984 3982 3966 3896 3864 3801 3722 3655 3621 3543 3516 3479 3413 3371 3305 3289 3265 3268 3267 3282 3260 3251 3241 3258 3245 3239 3246 3266 3331 3380 3380 3369 3360 3357 3365 3398 3420 3434 3441 3469 3495 3552 3584 3960 4272 4186 4087 4023 3995 3904 3800 3758 3747 3839 3866 3797 3662 3409 3465 3723 3722 4031 4781 4741 4449 4313 3768 3000 3343 3318 3402 3916 4344 4972 5179 5403 5458 4867 4620 3261 2477 2232 2308 2652 3134 3195 4040 4300 4471 4520 3952 3915 3797 3595 3807 3851 3883 3922 3646 3550 3288 3182 3246 3247 3278 3260 3393 3442 3447 3461 3444 3430 3577 3661 3644 3627 3617 3629 3638 3642 3634 3635 3650 3682 3750 3833 3834 3836 3847 3839 3816 3732 3717 3732 3741 3739 3746 3764 3742 3761 3761 3779 3802 3818 3831 3829 3835 3828 3833 3853 3897 3902 3937 4019 4120 4134 4177 4207 4224 4215 4236 4243 4259 4288 4283 4220 4147 4058 4036 4055 4049 4031 4038 4059 4098 4104 4106 4100 4097 4093 4070 4033 3731 3705 3839 3846 3783 3645 3512 3426 3390 3492 3527 3534 3512 3464 3330 3327 3752 3959 4010 4071 4110 4055 3949 3871 3787 3720 3685 3682 3629 3593 3607 3644 3721 3804 3831 3846 3862 3864 3875 3875 3880 3896 3902 3906 3888 3904 3897 3912 3904 3907 3893 3895 3886 3885 3886 3887 3880 3885 3874 3871 3838 3847 3829 3804 3782 3755 3779 3746 3725 3678 3624 3606 3579 3516 3493 3456 3437 3384 3286 3161 3129 3145 3156 3123 3121 3126 3162 3163 3253 3278 3344 3366 3362 3366 3373 3348 3332 3314 3335 3351 3398 3437 3480 3756 3863 3830 3805 3797 3910 4016 4106 4197 4277 4328 4363 4393 4418 4411 4443 4466 4492 4493 4464 4449 4304 4125 4130 4119 4097 4057 3845 3420 3365 3421 3647 3658 3701 3720 3734 3757 3743 3754 3809 3807 3803 3782 3792 3785 3814 3887 4095 4104 4091 4090 4109 4131 4121 4117 4165 4153 4161 4132 4100 4115 4122 4084 4077 4047 4018 3998 4002 3989 3970 3955 3945 3932 3931 3923 3869 3858 3842 3819 3787 3750 3736 3725 3726 3686 3658 3632 3603 3579 3555 3530 3514 3480 3463 3437 3412 3373 3357 3329 3324 3330 3363 3399 3408 3459 3451 3457 3448 3442 3448 3434 3462 3456 3462 3547 3576 3570 3566 3562 3569 3639 3657 3691 3723 3737 3733 3765 3786 3812 3842 3838 3854 4078 4079 4070 4091 4099 4110 4137 4145 4132 4089 4049 4044 4033 4023 4022 4017 3986 3981 3986 3967 3976 3915 3913 3900 3878 3869 3859 3826 3797 3798 3771 3788 3794 3790 3800 3790 3780 3758 3769 3766 3765 3786 3794 3787 3800 3799 3830 3897 3929 3935 3948 3955 3951 3956 3962 3961 3960 3976 4002 4007 4013 4010 4012 4006 4005 4018 4069 4072 4068 4079 4077 4083 4090 4082 4057 3985 3990 3980 3964 3904 3894 3872 3817 3175 3155 3185 3143 3118 3065 3270 3300 3326 3331 3334 3335 3358 3372 3391 3413 3412 3400 3401 3394 3400 3438 3505 3525 3535 3541 3778 3923 3911 3883 3861 3860 3858 3849 3865 3841 3802 3748 3710 3727 3732 3744 3721 3734 3724 3731 3752 3787 3807 3817 3794 3767 3815 4048 4358 4403 4410 4363 4017 3171 2902 2655 2500 2752 3462 3520 3498 3508 3710 3712 3891 3941 3957 4280 4376 4407 4385 4287 4296 4282 4192 4142 4165 4164 4107 4045 3981 3944 3921 3907 3878 3844 3673 3619 3633 3586 3558 3536 3513 3500 3487 3466 3426 3414 3378 3389 3367 3356 3340 3326 3308 3298 3331 3326 3329 3310 3272 3263 3239 3220 3172 3160 3157 3141 3113 3056 3060 3124 3272 3320 3353 3346 3347 3358 3401 3390 3403 3424 3470 3524 3584 3575 3576 3598 3771 3771 3774 3773 3797 3800 3801 3808 3820 3820 3823 3820 3816 3838 3840 3846 3844 3858 3930 3933 3945 3936 3877 3853 3851 3826 3784 3769 3725 3702 3659 3641 3609 3626 3607 3644 3614 3626 3605 3557 3517 3506 3492 3485 3589 3691 3713 3825 3918 3980 3985 4010 4344 4791 4817 4780 4611 4467 4340 4252 4225 4177 4151 4149 4155 4164 4177 4155 4073 3999 3844 3798 3786 3745 3699 3668 3658 3616 3567 3546 3539 3579 4495 4489 4529 4566 4568 3767 3450 3398 3317 3382 3239 3127 3021 2983 2951 2921 2998 3355 4297 4535 4682 4828 4770 4699 3963 3727 3691 3689 3727 3768 3785 3706 4037 4196 4044 3934 3837 3735 3633 3559 3479 3394 3329 3320 4197 5055 5079 5032 4340 3444 3157 3161 3405 3398 3330 3364 3456 3476 3445 3373 3312 3378 3561 3497 3433 3407 3384 3364 3468 3549 3537 3500 3487 3455 3425 3387 3343 3338 3335 3307 3299 3319 3333 3331 3400 3531 3559 3695 3691 3712 3745 3748 3729 3680 3632 2958 2824 2756 3462 3675 3746 3776 3841 3879 3658 3556 3571 3605 3638 3645 3634 3635 3647 3634 3659 3678 3715 3790 3847 3843 3805 3788 3810 3814 3798 3772 3816 3883 3920 3998 4032 4081 4100 4145 4185 4206 4185 4158 4131 4144 4163 4177 4177 4189 4203 4219 4211 4213 4215 4198 4159 4100 4104 4103 4114 4131 4128 4100 4105 4084 4084 4087 4048 4052 4063 4070 4066 4036 4045 4036 3990 3957 3940 3915 3862 3822 3749 3663 3607 3588 3526 3481 3448 3413 3395 3383 3394 3455 3502 3497 3485 3475 3476 3465 3442 3439 3427 3404 3384 3313 3275 3341 3438 3520 3506 3514 3512 3504 3503 3499 3496 3498 3525 3539 3602 3731 3746 3831 4036 4053 4080 4103 4125 4137 4158 4169 4201 4273 4320 4342 4342 4274 4227 4184 4202 4203 4211 4125 4032 2807 2623 3292 4265 4473 4540 3821 3741 3568 3492 3332 3118 3047 3032 2970 2889 2909 2898 2858 2806 2760 2824 2868 2962 3070 3120 3240 3301 3527 3682 3706 3712 3712 3774 3882 3937 3966 3964 3953 3956 3969 3970 3993 4002 4027 4026 4012 3998 3990 3978 3981 3985 3984 4000 4008 4009 4003 4007 4003 4020 4083 4121 4137 4176 4200 4206 4226 4227 4254 4269 4314 4334 4355 4369 4354 4099 4108 3371 3386 3381 3368 3333 3278 3233 3182 4172 4260 4167 4010 3930 3844 3714 3596 3574 3589 3582 3594 3639 3657 3678 3702 3750 3754 3737 3657 3636 3679 3709 3729 3806 3870 3903 3941 4015 4078 4083 4094 4097 4082 4022 3962 3927 3917 3914 3902 3912 3882 3882 3829 3799 3792 3764 3750 3745 3748 3741 3732 3718 3720 3747 3804 3861 3882 3899 3914 3909 3893 3855 3839 3834 3877 3885 3880 3896 3891 3883 3830 3779 3739 3751 3734 3774 3801 3833 3844 3842 4006 4039 4045 4062 4070 4034 3977 3943 3911 3882 3853 3797 3079 2934 3441 3588 3590 3512 3465 3359 3296 3273 3282 3299 3311 4811 5211 4400 4078 4015 3972 3919 3851 3834 3797 3839 3872 3934 3989 4021 4016 4014 4023 4094 4163 4184 4243 4315 4317 4333 4300 4261 4252 4282 4301 4317 4314 4304 4287 4267 4258 4232 4210 4176 4157 4138 4127 4128 4144 4174 4177 4175 4175 4199 4202 4208 4225 4226 4231 4226 4219 4224 4207 4196 4168 4103 4079 4037 4003 3990 3996 4000 3989 3976 3925 3808 3756 3746 3708 3717 3747 3740 3751 3748 3751 3754 3752 3756 3643 3562 3533 3513 3494 3477 3898 4167 4182 4209 4228 4241 4269 4287 4323 4333 4347 4368 4357 4298 4221 4149 4095 4067 3967 3915 3867 3809 3790 3775 3741 3735 3736 3790 3929 3941 3984 3994 4007 3988 3985 3799 3324 3348 3737 4889 4917 4937 4947 4662 3773 3427 3008 3075 3771 3752 3806 3760 3742 3711 3716 3703 3683 3672 3912 3920 4047 4068 4075 4097 4122 4160 4193 4206 4228 4243 4238 4227 4223 4205 4292 4314 4306 4242 4206 4182 4181 4041 3965 3900 3810 3751 3660 3620 3549 3549 3551 3545 3548 3505 3408 3334 3310 3281 3256 3251 3259 3282 3304 3304 3299 3350 3399 3439 3486 3466 3485 3456 3460 3472 3492 3476 3472 3461 3449 3451 3462 3448 3445 3429 3425 3423 3392 3372 3364 3368 3357 3414 3598 3642 3815 3831 3847 3857 3870 3868 3877 3883 3860 3866 3815 3746 3701 3645 3634 3621 3622 3599 3607 3610 3587 3537 3522 3491 3535 3560 3553 3551 3570 3598 3601 3617 3647 3650 3655 3652 3654 3665 3672 3666 3657 3656 3648 3626 3619 3586 3554 3525 3525 3506 3497 3520 3530 3529 3530 3545 3586 3592 3623 3629 3637 3647 3650 3658 3667 3650 3674 3671 3664 3682 3671 3641 3638 3657 3710 3761 3769 3827 3856 3864 3884 3894 3895 3882 3875 3851 3867 3856 3870 3889 3910 3949 3972 3999 3995 3995 4000 4011 4030 4022 4042 4080 4078 4089 4092 4109 4105 4089 4066 4043 3980 3969 3577 3457 3422 3389 3336 3348 3414 3452 3489 3484 3453 3421 3477 3529 3547 3529 3514 3509 3470 3407 3394 3399 3444 3476 3489 3483 3488 3513 3737 3888 3883 3866 3845 3847 3857 3871 3860 3873 3853 3855 3839 3817 3806 3830 3861 3910 3942 3971 3999 4033 4073 4098 4128 4129 4119 4124 4133 4135 4149 4165 4162 4158 4160 4135 4104 4044 4036 4061 4056 4058 4077 4108 4108 4087 4082 4043 4046 4058 4066 4053 4039 4011 4021 4016 3999 3997 3840 3828 3824 3806 3814 3835 3847 3847 3830 3783 3765 3763 3707 3608 3532 3494 3486 3494 3512 3491 3490 3414 3363 3311 3393 3453 3438 3458 3476 3466 3447 3459 3468 3539 3830 4077 4117 4197 4317 4391 4421 4457 4453 4433 4459 4437 4437 4572 4579 4589 4536 4462 4336 4174 4139 4123 4118 4095 4106 4107 4114 4098 4070 4042 3964 3972 3963 3961 3947 3956 3952 3916 3899 3899 3892 3894 3888 3903 3966 3970 3969 3955 3955 3917 3899 3881 3850 3794 3804 3809 3787 3798 3796 3763 3747 3740 3865 3896 3925 3947 3948 3955 3959 3993 4004 3992 3958 3922 3887 3894 3869 3844 3814 3784 3781 3795 3776 3773 3755 3757 3743 3752 3719 3721 3696 3680 3648 3599 3559 3544 3525 3510 3504 3493 3543 3657 3643 3659 3666 3650 3649 3670 3688 3688 3714 3704 3707 3692 3707 3694 3698 3705 3695 3691 3685 3665 3656 3638 3617 3619 3616 3623 3875 3897 3895 3883 3879 3857 3851 3830 3829 3789 3773 3779 3788 3794 3785 3785 3775 3766 3772 3785 3781 3758 3699 3672 3708 3700 3711 3736 3749 3764 3755 3742 3746 3798 3864 3914 3945 3996 4052 4065 4256 4522 4559 4565 4574 4575 4545 4501 4446 4437 4422 4390 4377 4344 4308 4296 4270 4286 4259 4097 3690 3771 3814 3797 3759 3663 3630 3497 3450 3449 3525 4579 4668 4806 4851 4689 4512 4470 3362 3298 4083 3991 4003 4117 4190 4221 3963 3907 3928 3992 4042 4045 3893 3821 3781 3496 3364 3225 3004 2776 2668 2654 2690 2896 2970 3196 3364 3346 3350 3349 3359 3346 3358 3388 3405 3477 3558 3603 3595 3598 3598 3599 3587 3582 3575 3568 3545 3531 3509 3523 3513 3501 3553 3594 3606 3604 3637 3624 3632 3631 3639 3630 3625 3664 3678 3716 3742 3798 4054 4094 4143 4242 4323 4348 4395 4432 4440 4427 4416 4455 4476 4496 4510 4505 4469 4427 4387 4344 4318 4267 4278 4278 4249 4252 4232 4200 4163 4122 3358 3055 2996 2978 2936 2900 2905 2924 2929 2913 2872 2841 2828 2804 2902 3063 3161 3169 3279 3446 3827 4159 4192 4134 4049 4087 4132 4156 4123 4098 4146 4178 4183 4145 4115 4156 4169 4191 4170 4151 4037 3933 3884 3820 3815 3789 3761 3723 3643 3606 3586 3637 4018 4044 4040 4065 4066 4080 4020 3999 3973 3915 3955 3968 3993 4005 4005 3957 3938 3831 3827 3833 3761 3705 3644 3673 3777 3794 3820 3790 3762 3751 3746 3738 3703 3661 3659 3659 3668 3644 3628 3604 3577 3569 3594 3633 3664 3675 3675 3671 3675 3678 3680 3666 3661 3704 3732 3764 3761 3770 3776 3787 3783 3782 3778 3740 3707 3675 3696 3694 3690 3726 3721 3745 3768 3777 3763 3775 3783 3792 3779 3768 3755 3752 3758 3762 3783 3768 3788 3795 3787 3799 3802 3786 3762 3757 3747 3756 3752 3753 3756 3763 3761 3738 3746 3786 3811 3825 3813 3852 3890 4364 4440 4460 4476 4501 4485 4504 4548 4595 4631 4650 4593 4549 3329 2577 2337 3407 4204 4531 4354 3964 3730 3430 3575 3236 2890 2759 2655 2542 2482 2527 2710 2789 2787 2835 3026 3209 3546 3924 3926 3949 3940 3961 3992 4013 4012 4009 4019 4073 4126 4139 4141 4158 4157 4189 4215 4233 4267 4317 4418 4430 4450 4463 4445 4470 4487 4464 4453 4466 4447 4435 4408 4386 4387 4402 4398 4396 4402 4418 4412 4460 4483 4490 4512 4538 4549 4544 4529 4504 3305 3831 3911 3899 3772 3681 3925 3987 3963 3923 3875 3763 3612 3473 3419 3431 3441 3538 3583 3612 3661 3665 3599 3517 3424 3262 3151 3210 3307 3539 3710 3740 3744 3770 3794 3814 3829 3843 3863 3849 3856 3869 3841 3821 3822 3812 3804 3801 3806 3808 3825 3835 3864 3892 3931 3949 3956 3962 3972 3981 3978 3963 3920 3891 3883 3897 3919 3927 3925 3906 3926 3933 3949 3928 3942 3955 3944 3936 3934 3947 3956 3984 3994 3996 4007 4016 4010 3998 3973 3972 3953 3928 3932 3932 3951 3968 3988 3998 3992 4000 3991 3982 3978 3979 3976 3933 3614 2785 2785 3102 3238 3396 3431 3683 4094 4363 4526 4569 4582 4537 3515 2513 2863 3018 3771 4621 4625 4108 3474 3080 3295 3925 3915 4168 4742 4895 4779 4673 4713 4569 4524 4372 4264 4140 3987 3836 3821 3804 3792 3759 3780 3813 3835 4236 4345 4406 4449 4468 4443 4430 4418 4416 4425 4440 4444 4432 4416 4388 4368 4372 4404 4421 4422 4438 4406 4361 4289 4255 4221 4163 4118 4069 4070 4043 4021 4004 3977 3952 3903 3873 3844 3787 3720 3690 3666 3714 3794 3800 3795 3776 3759 3736 3721 3724 3704 3717 3709 3687 3632 3626 3629 3632 3675 3686 3706 3742 3755 3773 3758 3756 3762 3767 3771 3798 3805 3794 ntpd-1.1.2/docs/algorithm/offset-chrony.gnuplot000064400000000000000000000002421046102023000177060ustar 00000000000000set yrange [10:70] set xrange [0:3600] set xlabel "time (s)" set ylabel "offset (us)" plot 'offset-chrony.dat' using ($1/100) pt 7 black title "Offset to server" ntpd-1.1.2/docs/algorithm/offset-chrony.png000064400000000000000000001053421046102023000170110ustar 00000000000000PNG  IHDRK pHYs+ IDATx{|?Kv7W "h(UX(PjEZբ#7},Ԋ5V\"T% ^%P @BIqs33;|dv̙3s窛Y|^7# @ <0x` 2!'M 6 Oƍ=lذM6e%AȄ~ךs9\r%O>}ر馛MVWW@G@d1?SOO ;L8믿F 2g͚d?0`iv8p 9r׮]l x?7{g~_744?׳?yG-ZM,(((((HkS=)Qt'պv'պv'դ[WWIWX1qDǷ˜~e9rchѢC|A4d㺺:4nH>Ou>Ou>OI;_}m;]+O;tD"5M۹sɓ_egg|{X;=4x <^pI'TPP0hР~[Ӵd2SOիל9s5M⋛wލo?yտ:MwyC YjN;&Ç9sfϞ=qo&嗚&L(,,>|믿N8ѣG~sԨQ#Fp|4bvl&M4qD[^?nw\P(Ľ5\h"ﶶaÆu][lE7¨߱FӴ WȓO>y9瘦yС={Zu={ǎkoow֙UUUPtP0 gW^<{O<<}ע;wz6O=ԢENmł`ss3>=e7Ls=wڵdYjU޽*5\m۶={=zt…HG/'|>p'tI'} {۷;jq|+bժUV2e ׯ__|꼼P( 󫫫]^0믿> ]ve~i]]s=7_G[hz 7߿_Ӵ/W^4NH&}{^z% ~miiyWZtRZZ /=ǧk֬y饗N9T]9M6?ݻ>lٲZ[nG}=zw߭iZ<O~2qܳ>{׮]E"3(((ȋ̞={ǎeeeYYY/oݫWYf=cgu;=p޽SNEGz}ɒ%{>ߵBXj1l(S<0x` @ <0x` @ <0x` @ <0x` @ <0x` @ <0x` 2$w1a„p8ܧO'|Oƍ=lذM6e%Ȅ>xy7}D"iӦѣGk>}c|_~o x \&M4i$ƍ] L쀋u]'9tD"ԄܹsСh t2!UVUWW755?~|AAgٿʣG.]ӦM@c# yWQQ1eʔ'+W4⋳gѣuf1;CSIIix{(@ <0x` @ <0x` @ <0x` @ ~z[@7uĨQZZZ4M EEE^7 `;2jԨz#F>|&40 }1͠ À+H nǠApvv)Sj@cԨQi^]]a{螀8 ~^n `{`: o* F, 0  dϓ`TWW1YӴl0 ;=ażn*'(**:|u]/^V$_@t% ]Ϸ(8auV:i>E@tޭduuu^^^( B@TНDβD>P/XxNL' !}xN;t1:]%܉4w 2t6NidiN*-h\__?b[t_`܉k; H ' 4Ψc߀tgrmR7=t(`Ykyo}:o)]ozݐH^^Vj_WWa{: o@: ;1w^W@Gp'{[j 7!n0$`ϭiڱc  t]"[ZZ Ʉ~衇t;v|ɸq㲳 iӦ T`aСj:ѣ5Mkoo>}رc-8 zހD7)'ǎӎ1I7DkaD`MӴC&p8iΝ;'O̞_PP3N Mx^t=eȑdr\4iҤI#7nt)3'ÇMiڙgٿʣG.]8е :/K,|c2!7o<~^z͙3뮻;4M|/Mz?qݺuh 9yyy@ gp B' :)7t{"Ȅ G}GC ٺukt(Z[[ަ= 膖K=ap*D^u2(Ld21b'͈b?u:D` e@SSssssssf&@F9!gD"//K.>}z^^޽{3uy3ڹk<!Qt]g2 .醁B!T(իM!w'l())1M :5>ug l%\Bͤk֬VDVvXD^^tM2S%v߯{*h AE X>vtL=;(d (AP`r ,\-}#f=;(d(!a?p7ʨc@4رchbbO\s|,>WӴX,L&#d 7d;n*y嗑D4]_y啌ݚ<'xbJ:miiAO`0؉: 32Q/KvZ9M w>" ./0MӜNG74%70 *giC=4{Ce֝nz1ctPdvIw4%7~oiiDKi֚zu#GrssL6Cu͚5/R]])u:ݡӸƔ*7XDZwU<\M?CBȢU~!:/(>t)y2>e:r_Uu.w.'x"MPekЇ.-|􎴭-]sŢ(u71O ]@a䉣Jk%52ɩ`u5i~!q'O1@ǡ;OU:ݳ֒%K$ɚw.}^H]Siڮ]qM0UtP`t:Z\_ /DqqqkkK S4N-X@@0HfnIYuDZaʲ2~M$ Kt,}ar]Vb1VW;=JRLu,粞Ou~~W_[_4=K(GQ.,,x힊Dp܈^]]=bUhe555DYx\uMMM˦jZߟYW˗sSH}erチ'KT$څL)++4hPEEE]tGqq16٥6lpWVVav$Vzeee6lXp!{|ѢE\sMZ]Vu.$E-+W>ﭷL3: HiiGM&d2&0~z(4xee?7u)tM̵.!n6!Snli&LH\CV\x J\IM6l|ֈ\3&O5UкI@\$:77!Rv.ζ6jEk^+N:=dРA۽\&!2bmmmd2yiGȍiǏ'5;6&M8qRo߾TKP~w|jkk ʫroFMMMnn.jFnnnmmkv= Ø1chKM;x\.5t],H@ 6#wdOB*חW` mmm.5i]:wY칫m&GdYѰ_ÍsT_Ro4ȒtG0 M8D"Ux} Uru5^qCZO7rzH x,5L{Dq!O&P HgYdbH$BFn}0د:$MQiӦiu ג 6Q+ذ nfD"=h n@ P]]HTԔ"W]Vs(D+NJfp)Ǚrz.Ǐ_LELji|md'r$𪫮R;;hRjwb@}T”)4mݺurRTTT__oFeeXˑ#G|A[-W `Mz!H͛Gv25GH_ V'\?ڻ nu6>lNXv9NQTT$Qj2VP8NŅP(&w}W'|RFXlf:|0wq)WDwYH$nfx=^b*bnHt,*X{AT$0t[nu8)v x!qajQ0 !^s97x#Kji톮C4:)6xR=(vpҎ*x()믿D)ņ B2~]m%0a|Up`]2Wӫ{@;<묳C;tY70EQ*775@nkQrTQiӦsέ(//2eJ=NIT#O?4~ih8'嬑 IDAT-nQ'`Xc pf~?r_|9zeiu*0Р\m3a w7pܹsyjq7oڴ)R wv[۷3&.r,YBW@!L|D2P\ޥbcyuvh1H$ ;Yqs`9o2aM>5}rG5nC(b2j&zMGu]GjsLҿV3jVRRbRH `Md"e3Nӕl4U o2<!+++UPSSCߎFlG'x 2ǖ-[soh=]2 7w-[Pjy[4hɌ/ Ǹ#b1jYZ-믾ݛ~'+e$h|ǏooogeiCUFz衇~nW1W)RPP$u0U2!ڴٱqW9A i5hoo饗P^zn-O裏⁝޲"SNիSO=emFF#Veeeqޕ`ྣ, ==i w*vٲe\Ej(bg[E ܁V~ip^SS#RJ+qX5Z\^tsΕl3/kvuס#๏"0(Gcǎ9kg,s0)4~7Av7*r%eߔ w (kkk+2pΝ;UPDlv=EZ[[g̘ $~5g,SRFy7p\,SM$R 阁`0FcSSO<z6Xf /0\J\so\zg?1tF8#[ D.cƶ@ P^^.ۗѣTӴh4I@nAEGhvi0 I8k%W]L:WA͟?vܹsT1HjjI4?EXSSC^=M$U8*pW˗+p-YYYަpщ"yaR'1*h#&^m{߳gϴiR&󰙢,AmYS|曤S֭[qH$"!C(mi5 9~̷zK?xVVVvvQPnǦ2<+ɗ555\yƞy}qlg*S-<&Myvڬd*ɡEeZ<wg җ~3fv*|&;f} oA~!lݔAA0ȗq 2r)+eeeԙ+VsDy[nG\ %x&lŪD"7 = .^ljVV $:NX_}Ձ۷oɒ%1d'44M5M۰a[ZZ\Cd+d8qTXCKSS7#hH$=\_/|+pKWS\E$OUVV&KL&m)b1jL&v&_~I)۷oRr'9rdܟ <D>\ǏOkJJJ~f{ѣnsQ?k׮e@S67zvUʍ\"(..3": e'//o„ ׿|D@ sRSAnZ]Z<"}څmLUrW.ځ1BV7?0>,ykHꊸ1İ{p8}4H|%]yF XUU%MI9p/ p.уx|ƌ}RRKn8`+ި3(,UQ"ј>yЭ?EsuUUUiidv7ID?.z1y,\]c(\ͅ٦ .$\$_*9ܪbIӖsDd7F=ˬm*O^JV΅$Kވ^$k)?X~DG3ΫZ7'dE4wjH= 䳭r_xYY{5%mkkSWq(Y%H$lʕxQI\sF.k*"a4+@O9ɳ%5f*&ELH򗿴lv|#onިQPxi5Ѥܼcn3K$緵_}&!К,:öa.H4ƍ_Kvv˄ {ӧOYYO?iӦ{oӦMK,9sf>},Xf߭nhu\RqcYH_S֪DJZVS'oXIe' 1DZXvCuT8$}4r]ϺWTT:0f 0QR*~\pq(2/T2Ju]' :䰝Tl{ͳH)1OF DӐ~א,=#̓0Ç??뗓s'b?O~[*&DZeE>waO.يPa2&R{ E<g9/f7JR'*SXޝBd5MD"'r}g~\m!f„ g[BLzG;"//ҽ+&7-`8k[UU`_&dʒEFQ6/aH ͷN~kCqe4~rTssJ}ْK)X2 qnyGYtD Z_|98DMM WTZR/I"AE\$gۮzX2<P(n\jr|9X^^n5TP& 5-8[JZFWXwY',ĦM#OYJƎka7G6t+⮻?]b!.oEI8V]YYYgu[OܩbJd2cvw_K/Ğ㰹I=Ɔ"M)Vl^QQt3MjT$Fw.;rHHnučqy9!cwTav|?a?<ްa[re[[uZ4ٟ)StM4W i`jkkV]8/זJFr~ĥVZf'rI%GL&Sm)fҮ衇&Lvϛ7z]UUU@B^xqJJJ6 ck[|eE}%[D{ɛX~?)AJ-OP1.{ﶼBӐ58H_($ Rpg=u4-''GihTZ&T;9؇蒴'$zFWQ^^W轋"ٳvi(D}̞=0 %U;`k|ꩧRGzb a,mۖЀ;x`؎aJS-QEpG=wBF qrHQ4aK2;՞b_ s~lo%+0ϣ(4իWs[\\L?cXeqۏ\I) QL8sL $8BJ4JӴ+VkST@tG Un Qm%čd .]J~(Dǵ}Νm[\؋"]tO-[ƞ^qz;oާO?I'd6_~>}v,-[6|p|W\qwpg pP 摠b^WZZV3)i,i9p7'8mYyReiEWh9~G55y2l0'ĿpC)w3*Y(kɢ0 \\4dRbբ4]؁G8j+- 6"[P|OEg[=:Sp5R_-4M=L>S훕8=z_W[xP)yqs믿hO?ma,h ){nuWHeee˖E"nx\+HH m!ԎCBq)T]}´iKQF1䋖iayJ~[t)^xAI9X^{e_d w:>,RKT-#F ֒n"DhVKU656*..fb_JطƳ8pOIII</**rYz_ O;;w*;`y 1nFvjbEͶᇂkꐇEHf[IJwu\\~htӦMB*+wɊDbPLtek!}w 7^bDٵ$P(4 K)XPקc˩픭lݺUq-0 jfw*ܣ׾kP\OIWՍ)V1iGN9sETT&D)..f=\8 aHȓw޽{ٳi{޶m۶mѣGiC ڀ{ !WBQgeA㾗%|SVVVYYy"I)*u-(w~'lZ pgag[:W2bȐ!Ꝡi̙3JCݸWuJ'7 \0;U,^X42H@@9w{A-GQ#]mmJɗ(-9It! LX5\s}W^yE_W_/QO?׿ucc%K v7ʕxrP*ڳ:S#,-c4NeW#?TO^Ru]X=&W6L74C] 1 h%YWqߝQ\Q ˗/g/.r Nq͝WZZSnL%A\Mu?AdDS(.r\P7Vqޝ*6E~9[p<y=Hi}я~P(toܸ-*V"|␤VDV\F:ılQO!jgᒕNH̞;x($ٷƈ{ɷ('ap'AޕLl2Ir."%m$q}!gGxĮ9??_w: ; P@HQRc7e)̓KX~=I~~+43# 41&M`4gާ@r\Ξ=[WV9Au-vEesΥz}j*z =4M,.gZ%8r,pxVrpc~Dp;nXjq M:.nU0(nr,*BN =7(̌ݻwccy\766-m1iҤu!..%'xt2?Ho*CW!BFqdJ!Ghg'")!h?[^s1{h<EW$HyЀO↥Ν;|*&_Wtw< rss}>;%Vyy_IWfu 򎕫i̛7O1c0LDe"3!y%򗿼ꪫ&M޴u?#CzaE6^%ߛ\u1.rC)lR ,3bNrc_E$DHv )|~FV)E`JTФpyAb@ iE;N| y_)jǃe'z5"O$6" FlEH0d^2 ?ٳgϽ{g͋/v<ΠUrF7Ք&5 ʚ\g̘pcjbN u5Q `0].ҷ뢻T1b PO<_njb17W TFdZf 'j/Ȉ#`p۶m"<#Psj6;J$dggw- , IDATgF"ILd2ڃG,!:/ƛa*Y+ q"0 +0JJJf̘ATy 7h yQrvH;|4??_3 /10!ھB]HVVBug3r]6Ι3b 63GI77V6|aK1iZaa!d;㫬?TH4mm E_[~JbIE8ю[Q0mHM~?)(5|>F$όDjjjwpq苳t{zǹ|0%?E<4#$~ƌ<0ѨO2~woCnrnP `}7|S>W7}lE2qPDaiu&eY$ŤJ|,xGA6XK㦸7 m'uHTu]Ҩ%YS24X|ȳWn#G!OVkݧIOmiAF4'Ŵ_R'"OAC}+2!O;={yWbӧ- X47I9dIϙ׏cz!zH$*U\GaÆUVqOR@͔ofUL~ʕ*Iz!D?q\ҏF޴iOwjkQuD6bf:z m~iNQ#y/YR'`"M***}뺥z5P傢5~ĈtEڪʕ+mۆ%rOb1".s饗:8SzSOm6m!cs wfi#?rcR+c$"P,6+e@]$IE"BӨV0X*~¯L qSWqR$bThRr[~*՜8/Wd5M y"Qmp BѾM#VUUJf.Ɍ" |VR"Ypa'b_.\UΗ4z [[hj/dTx-uMMM8Q4c")]~dZijkN [ztäй[68;NF+YP: (//wvy|hQ;+K㱨#bY ?~u]x nF/r&JTF=D*B4T1F( ˼)48VjlAY ٵ7P(Rdj!CLNNW'oRܶSZ0]K%23UEVަB8+_$>19B_̟?,\t(w1*:A$$22E0z~ٕZTHHd7//O$|vpW}ar"܏T7DyX-WXi) ƈTw" d6y:y7rW -xdp@)M^ nn6[KSzg,g5(B? #UZ2Y\Tp߾}ngqDtK * bn%'Rw*=:6bHE]DMܥ;ASYB&>[<7s3&m"ƽ e!eG,׶~I>3J7p|XW! 7o $™v#頾^WjrO-/4A[%exbvcڷoJ%ySQh%1NKNcY#{hѢ^Cjcfkk-[Ygŕ=z+ sc '?=5jϞ=(:+++??>bOߚYVVFpp iKDw1MSӴʩcru]29k›BrbTZZZ{9%K@lKX/6|kk+#erFnnnuuu,wӱga 2- @$bԙ>oӦMT $~gϞO3t0~o -UܤrI$+N N]a(h؜;9//OhSV1v!X>x~~>w+7 "wvઑIݢ~_d?sAAZ[,n?ME̴ҍv5RG$,ʢfƌ8_#٥D!&,ED1 P=H I)%l SG(;o޼K.$OcȤ xĉ.+Q1tE>;&9 f$sA)vA H&_&~iDU5дi0nCqT^ԳR^AAPv"QfFQ:"DL! ͜9Sc S ŕKǽdAYu+wf9| ti5pG.MTW_}㫻 `򖍯PLGWJhRjS<>UYLY8`76ueJ冥.HaCBqrMƫ1 7u[zhp}(hS:q틒E;"Z&l`H\["uH3)|>z#M-2 <j󠼼{MM0k6dE"O"T %IQ-G܄7C$a$Μ +DѪ%/f+EN#e|8J!ArH gZEcCPha9ˈ*{&ۼyL˼ \[=I)3^ܓ岉CRD2ɱb> f' T%{qW]u߾c7s\_Mr>|ITvTP\V9(c`W&2-Dpg4g{&r!W=Y|ZFZIJ)X}n5OTUUq᮱"QZ|q~kh(:-jIK Yklnn9H}sBa{AnS9"hJ6幹;J޸QXə={o9svsK[W^M>6V)WJs9䭲`ۃұ^|E,`4˒h4vdKAfgSq *++E&åK*rXUJ2VpݣP_MMM0DY("Ul8ng%vVd]t2e&w]Vز*3K> 83 ٫؅Dq>:xСugqYYg ,T)iWұ N4U?QK%܊hoˀ4dџB-Xd -/Eo8FhBʌoW{FFԖS1IoʳPJQE\Uơ(uٚ0*M8 PnnV{|aM_͍lK}KA2*$;}ʀ8Z655&IuVJ`0,taXJ=e6]P \Wh(p2T2s 0*++I'SCW*l}B""*W]X&_<w6B&[qh {qӅҏF(GR+XRɺ"QCb%l˭!uKI,v,F*E,}Q V 0 wЇ*Ou1cVMZ[[ߍ5J3K/}J#Gljjbu]Eoܸ;-X!/֦zQQÇ׬YK/՝r)/i/Ec-hb p[x)@^ZF^}dh4Jرcp8 eg6o׮]n:ܙbϟ/?㬞6 j1M_&1O:9G/hnnnjj˲C3n8no^\[h*-b…T<(9eƌGGD"H67o2a~'Ź׹ꪫ f3** Uu-n+WejN4hX蚚N;pذa=zl$Giں}kn۶-L]Tk ZD[/*:I(?aMqGyXwm@f0VkĚp#&ps,]VT"IX)meE%olabsG-yNxPVU"kW\elVVֲe;t~?WU.ZJ ^`3]בGWOX4]}@>/wK φt ː't+Գ 믋 mQJe=a- +|//G%dH^r_)TlY CY-/b+ϝ;ۊeeev}.L2#Vq"r*ot]Gc#۪P.J O"Tvʺ q_<#w<>2@-LZhYe`FA: }ʒ_qb%LH#x&Us9|Z̮m#ra=lUr~ZjXب#h M"UUV~vKCN˖-SѐEjuaTw ^ȅ@W4IY@`4͚˹ƒIs0".bi؟q,rG%5";raTի{@% 9URv&7hTvJp#3uTpBRqEacyU2L&%ʊP:Τ߯[.5FNNJr\R+r72IHlb4.K55p,2"8r/:9E;IT(++-L产">?t]g'H$ZdSSf}hR^zlX,&l^4ݻw/vdE'C;ES^sskc.袼{kZx---?q'{d2)4?){4Ͷo3f {PES%Uh}'-ǒL&ǹأDћ2On`YΒ(L&b1Ѽ'mi %}^G)>ݻw٘D"hnn>tbc\Fzg%F<|% C dg7\k7,p@h[}*06#CI$`mA8R̫*6w!wdw߭(QGR)E^ =+5b]`|S˰~zntl/UUUr| ͈;TIBQ6 (wpp]$d^QQJF6vÞ!Kc묅*}THỳZYT.(u|R$}(7Ī6=lK93JVpMRHVB ZF4]pÇN˓/ܴ{2P׮]mҐc=9={0++kʔ)'Nd=rDclLD"ձXL}ͮM7ݤ*V ܄U]ԩSQj[o?qǘD"!o?bԨQKiSsnvvv{{X;KK;Lؽ{#[5X)S$K.d餵f)$777''yi,scDzlĮ]Hݻw4 6KI>a$H$rSOzss3u4MI&o{)gT `%U,?SҞO?{K.1W6(rJ||ƒO<=x=h. yV;c\hw'RR6^-hM\lp8V&L $-d*ZQSs~~>Fdrʔ)EEE{ ȉ *]W. |Taرtl6> s21a~"JݻwΝA9R__ϦECrrY`{o,q;Ўf[n7yr(@`?ewH$ $w~PrQFw2nq}*{|j ì#얜 ZFu&ʤOcVdKܹs%&"[o(|=Nu&WEL+F`nYCaõ_ [|J(?[Y %&[DBBj!y\XP(,+ :죡PQ A lH̵@Y`6M02KG-PvZq\r>\VboȻtժUAp~ɒ%`0Obd0ݻw#pC1%3W5Lp/.H ~a*}Mmg̘&YR.[DWFUM Ο1cċ[vTja72Ոt2ٵisM MU4ZW ؓsUs Aed֟ Es,Upr{ 7VL,)>LԃJ PA"7C>hr"x|GIϳEubP? >µ~գT)'LʓV $u[\˞)JL cy| 7ݣF,n$hA p#e^@ r Q QȲ]QY_RGʣ]e-7 PA"DvLL( GFSw(ƌ#MgH(B]l٢FNyV766@I@?(ۧr^{=MR'u֬Y? =zTkk8GؚԼ"RK4.Cb àTX2/X{{ʽ1{ՉCJy%Qj:Zb@BFrNrYgQ$:Kx@A9/??XICU Φya$5I iԔ:̽#-5HLӬ[r;:,#F4Cib@]I(l{1gnFn4F>:MӬU4m׮]la/*iXLӴX,MY>#2N tMVް~4 R^~crRC= ܄)ȧKa$aĨQл@eꢢ"?a|he7 *`- kd]j%& W-vc3ȣ@,D~T܎hDD JOQ6G*_Ҏ+3r6.]};W*xiGE=#XnS&C?-,uƍb\1Pmw`*l^Lӆ- HF]k\d\^SSk<]|_`KK .e1`nzoD+j"Hcc;k(Rގʗm&kZ&{֛oɌ Bo_644(F%^#hu!C>H0(I2tB}6HK'II*KTr=n8Ijp#3@v8Y_{z1Ů)ryHh[oYfȒx2ncҫvc@%5\+rAϙ3k[[?˚v{}QΘ1nSyX)/q6x[60`yve;Bʵ#*EEEogqFrԋy0:8o[CC8'd˕L&M^Vf {./(i*24rDamdD,$%pHd,4-4BP/,WO>*W[?I"mhʞF|֭)m!ڀٳ&ٱ7hH䎐سˎ;XeRrAw0BaXeRB$U ZsI["TϑM%Z}wL8Atc6Fx<^^^kk*f0XKL6 VWmU,{egdF̦ %KRKw!i:_fq!cu]Sxq lzpQ[_ω1Ί4)8D*䑝a,_YSVH jL)Qr{Mmuۅz#uQY)UWzOl1 ¦yԸ[љhS"7g:lTk: r$f7VH@paq}3B#$B]oq`M" ^PyiG]o6`m[?l[]w-2K8r)**jlltWWWB!߯j{+$Qk~ XkGeӭ$`"Yx1ۘ7ɘMȑ#+V$N'ܗ+/51yr>qU' M;`nTDU[=r̽{Dmm-*qJ7 )[lNfQv=X }ogӡ-gʷ/QWx0Q`UUU)HQ#Sb\fEոB18.RIUwQM@BB|vӣE Yw|_O_ B~^49(-1X<zOC Q\\dɒ!?Q3rg j2p7g~GuF SBx^;666ےYtkn@܉l&:iՉekP#` ԩS%%% ,hnnV׳Ül8UAAo5*fyL0Liiih g=츁SA:J_&L:\_H8 rJw&:|PWW L!L\Z6cH曌O  0 ä!0!s8೜ORL<[sw}7pdjllzҥ>g{Vc.K~Fvv;>w Œž111w(w. 4MKg Z|vFEEUVVs"4Gcz^Ȝ)/C>``V/B%>j%! 1^n"yUŧۖT#c!.h=-di |܇/z*_~ȌOߗ}lsEOOOzr{*؝/g/wK\ܹNW/LgV.tVWW{N򷫱gڃ!##Cӊ.h ,--[``vܹj*G_toNn$/B>:VSS g+***6lrZm]]n^79BAdQӧ\e˖4o>)O?9G^ggs=_*YVyqߖ?@tPG6D`Za0<*F”gtȹ 8jH,oYiV,C8 M*Bp<žbY'رesZ1 N>yH w^!lE.aK8q#=;Y0cpկ~u 6;w.Wmy,aOتWwoɽI*E޻wozz^OLL|:::򆆆iӦdffVWWKP`E}$r:fL~&ɽB^F3W`N`=Ll5>Sl6ۢEnu:¡]%oF͕f`{lQwBh؟%:B.yX,VW^}WKOO/**jkk0<>]+YUۮ]a3*dA -XڣoYWt766zv{7U > cLǛ4M+p;ŋ'?a111i̘1{>X\;ڵk>-[6v61ϯT͠ 9ß>% Oਿ?! p7e@8ބ!Sxxhɓ'WXaۣ;FQjMKKsl}n^fKPm9aW*--]x񗣑+ cSs嬬,6w;g`4M{.ܢ(;@Bqqq]j= !?Vy`ht:.y̪3gx477f!O-Q5kŋ^zdr!>>;bb)xJs/ ^R婧k:&3BY(JǏϚ5)L&uJ}mlww{ y<ɍD`$9|̙3ٽ{ .ܸq#A5NGJtE*SZZʽgV <KxY\p, [0LSSEQ6+6##Cʨ͐!C.hW! ,@Fg1naམ㓊2(̞gǎ^%3} 'wBɇ]3fHNNnhh(..={6EQ'O>|xiioq;wJP5+**1 q>;C4)yauAumGwejwwwVV{cPJJJt^A.ŪF8Δҫ:tPV+<|-:uNKOOXtA_g/&Bv+D_pX>C;2X>3\b,~斏;V1EN#;/eo{bb1)=B8Oرcq4MsGhMQڵkWX!RQ7x6N8NޞE2!@'BZg kDj2AA+͛7}^9a{{{ vB*bX a(|fiׯ4M yBa?`IMM#|?1&X.I׷ѣ_B;Og}y-(J yu!x OVD`/ez'O \8'W*3[^^}-[}Ꞟq 9&EXEZZZJ%( t I6>6աWSS'3(|fW\=M6=0a`pVB%$"gTx{k__Mz|f+++5K`BJ5"<% X-S!T Q:ܓ]7{b`o%<M^+].c:uJѸil6p4Mk4޿@\;lNQCJ܂(U.˭NSȗX^^gz{{Eٵ'\y,iT}%=euӂ8Z3 ;q|yW_II wyG z kx"DO"u _0QV\镴2q>?r }{<5B1`)kʰQ0R(4vmttWytt,޴Jk؝EϾiӦX\\MBzȳD9rRQL&{Q)EQRNS/[ssWʐ/}D<fM0WH%QssY&I\բ@:i UVhè/mDx _>/٤IN2D%:`:దbuDx@ho,⫪$SvYE7.%1)`n#u7g>H)/l܉# HJd=-]*5{Yz^ݤȾi*++])sQiNM"ᴣG:5G_eħ>{=wA^=u6H|fxh4Rpﻚ WF"UX= Y R~vv+wOX,^ LIHdhYԔή9kRTTTXB +$Uc|Rd_|vzCGxx0F#'@wTS544z 0DC81bDSSX1X<J&T_26;0LFFhRiy0 @bzn(J˃ DKNjzchAuH ^%a\ jC,EZ:γD eI0-0Ր T(L,I,hP\b)-(OAZ >a)-(R~YJ H=WXJ _FJ 2~Y"z)3 2Y <(,{ ґ/!A´w P6{wwwwVVV[[* -L?{k@eg`ha٫_Ju+LIՐ @I"W~*4/!haH!Yf1 s2L&xu!gcܗ4M@ "$ )iy}? cH W $,:TGK@^A@4 ?`P/'YC4  @0H'Nh0RRR6oN0mڴj j!---oVSSӾ}~ٳ(5)Sܽ{wݺuؐCe˖gy&11駟^`s(ijj*++3L/Rbb⧟~*Ae"c Ü;wnEYִ4ޔmZ A,..f_(pL&M܇v^ZZY8s̜pUUUuϒf,wy磏>(*..Ç[ڒ}>a-wIX (H:))-Ȱl]]]E>i 5s̙3gzTUU Rܹ7|xժU 9rѣG/Ae@vl6ۤIzzz(j%55t"l6cǎo$ڤIV @8VYY^uww/"M< "ZAAV,'U CX,&ItxBF"4@RSSN8A4}@1A HW@L `@ `@ `@ `@ `@ `@ `@ `@ `@ `@ `@ `@ `HW1v;0k!*afΜI"aRjjzZJi)%yc#ș3gTFWOK)55V=-X @_QFy744L6-&&&33ZD)`Xz-[< ].Lruv * .]YXSSTVVf2^zO?TDbVkZZ``ζZܻ=zuចfl6KQKi577SUUUE"aRjjzZJi)vݫΝ;cǎt0L۹ws dIDAT/uV (rjlVjӼRjjzZJl,<11qBX{߶d6lذa  bː222l6[WWommmFFHLr=zt:yQOOEQ'O>|xiiigg~xΝB * 肮5kwllO>YSSh>jժ9ѣ2V:@DA*J@ `dklG?| &iڵN-t8K,1 .//'Tiii4M߿߳<~gF}gnݺ%ix;vjjjrYڵk .4hd={˗7)k"OkWWW^^^BB^8q'7)k)D ҕ*>>jvuuuuuJLLy㋋k>wꫯF_~I>}zܸqsׯ:t˗/! |t//Ŗ˺|֭[o߾f͚aÆRiRE֞onjmm=tPLLLkk+ꯥdOk81cٳhDUi&0 k4O:ŖYfUT,ϰTz3fnݢiڵkU=H^-ݾ}ҥKSu-Fѧߖ*^xQ2J?-%{Z# 箅ώ9r…6-Zׯ_w87nhoo,oj }nM4m)箅d{&$$;wnٞ-mkk(*..-Ç `ˍF#Z T]F '?Fw))'Tx;v[T=:bN7gΜ7oh>[nݺDV;bĈ^βn}~_pIa_KyZ/]`0LS033sر7nloow\ϟO~~wv]b}}_k4Fctt4{|  @FrssGi>rHkkѣ bŊxg̘1iiiO(c 2dHggM(jmmpOSrH믿.))/|8HZ(0 `?;ɚifIENDB`ntpd-1.1.2/docs/algorithm/offset-ntpd-rs.dat000064400000000000000000000431201046102023000170550ustar 000000000000005506 5519 5517 5516 5502 5506 5517 5492 5515 5500 5505 5489 5494 5485 5500 5484 5488 5479 5483 5469 5473 5474 5473 5462 5486 5494 5467 5490 5475 5490 5471 5484 5490 5491 5484 5494 5496 5492 5482 5476 5474 5469 5475 5471 5473 5475 5469 5478 5477 5469 5474 5457 5460 5463 5465 5466 5460 5463 5454 5448 5446 5443 5452 5452 5433 5428 5430 5430 5442 5426 5414 5415 5414 5407 5414 5399 5403 5400 5390 5386 5405 5386 5381 5379 5402 5397 5387 5395 5392 5396 5394 5385 5387 5393 5381 5373 5392 5392 5388 5380 5390 5379 5388 5378 5385 5375 5389 5378 5383 5368 5378 5365 5367 5376 5362 5371 5359 5355 5369 5366 5363 5348 5351 5361 5354 5357 5349 5341 5346 5338 5337 5338 5325 5338 5334 5329 5328 5323 5313 5317 5317 5304 5317 5294 5320 5324 5320 5333 5320 5329 5338 5333 5342 5339 5330 5344 5352 5360 5358 5354 5345 5354 5351 5359 5351 5353 5368 5353 5354 5368 5365 5373 5366 5369 5358 5376 5377 5364 5367 5356 5366 5354 5383 5367 5356 5376 5381 5367 5362 5377 5383 5367 5362 5368 5360 5356 5370 5350 5354 5356 5357 5368 5372 5353 5359 5380 5379 5365 5364 5379 5367 5377 5371 5374 5375 5380 5382 5383 5372 5372 5379 5374 5382 5365 5366 5367 5372 5374 5379 5367 5365 5357 5363 5371 5376 5373 5369 5358 5367 5359 5356 5353 5364 5346 5346 5343 5355 5341 5339 5350 5343 5341 5328 5334 5322 5330 5325 5327 5327 5330 5306 5326 5312 5315 5336 5327 5319 5325 5324 5333 5330 5329 5316 5327 5314 5324 5320 5328 5321 5306 5325 5320 5333 5313 5309 5306 5313 5308 5321 5297 5303 5307 5316 5297 5294 5296 5302 5296 5283 5279 5287 5276 5279 5278 5266 5270 5262 5260 5266 5247 5243 5249 5229 5222 5225 5210 5204 5196 5197 5189 5188 5176 5180 5163 5178 5166 5177 5179 5167 5162 5161 5163 5163 5153 5158 5150 5146 5149 5153 5144 5142 5133 5135 5123 5121 5116 5121 5109 5117 5096 5101 5095 5093 5096 5180 5282 5293 5285 5301 5284 5286 5306 5301 5299 5298 5304 5301 5295 5316 5313 5303 5307 5309 5313 5319 5309 5326 5311 5330 5327 5327 5332 5340 5324 5340 5351 5346 5350 5355 5359 5359 5373 5376 5378 5382 5384 5392 5380 5389 5397 5392 5399 5410 5411 5408 5420 5415 5409 5427 5424 5412 5435 5427 5433 5437 5434 5426 5438 5449 5440 5436 5449 5438 5448 5448 5464 5466 5459 5471 5453 5468 5478 5464 5473 5474 5471 5466 5475 5486 5483 5492 5487 5491 5480 5517 5504 5504 5515 5520 5513 5537 5532 5543 5541 5551 5552 5552 5561 5550 5566 5573 5568 5585 5571 5581 5586 5585 5582 5588 5594 5591 5601 5604 5606 5609 5609 5611 5621 5631 5619 5619 5622 5640 5633 5637 5646 5639 5641 5642 5634 5639 5641 5651 5633 5635 5625 5628 5633 5632 5637 5618 5626 5612 5621 5641 5632 5628 5640 5640 5639 5638 5632 5644 5646 5627 5644 5634 5648 5638 5636 5637 5636 5645 5632 5630 5630 5642 5634 5626 5634 5622 5636 5642 5629 5623 5628 5625 5626 5631 5631 5627 5617 5621 5632 5612 5621 5620 5607 5619 5610 5604 5597 5601 5613 5594 5601 5607 5575 5615 5587 5604 5606 5601 5581 5602 5608 5603 5603 5604 5607 5612 5607 5608 5616 5619 5622 5604 5611 5613 5614 5603 5607 5603 5617 5620 5613 5611 5609 5599 5600 5601 5598 5608 5598 5601 5594 5604 5598 5584 5607 5597 5596 5594 5597 5587 5593 5591 5578 5594 5585 5586 5586 5361 5302 5289 5284 5279 5257 5251 5248 5228 5240 5220 5197 5221 5203 5185 5190 5183 5179 5168 5151 5151 5136 5137 5110 5113 5119 5106 5102 5093 5098 5263 5292 5302 5293 5308 5301 5315 5310 5311 5300 5300 5319 5316 5317 5325 5303 5316 5314 5323 5312 5307 5318 5308 5316 5540 5536 5543 5546 5554 5553 5571 5571 5579 5572 5587 5585 5591 5608 5597 5601 5616 5588 5625 5629 5623 5635 5634 5638 5638 5638 5647 5648 5650 5643 5660 5661 5662 5675 5678 5667 5670 5681 5683 5677 5681 5685 5694 5691 5683 5686 5712 5688 5705 5696 5719 5705 5718 5702 5717 5700 5721 5716 5723 5720 5735 5723 5721 5729 5726 5726 5737 5741 5731 5740 5735 5744 5746 5741 5757 5744 5761 5752 5761 5758 5778 5773 5777 5789 5794 5797 5795 5815 5800 5567 5573 5567 5567 5575 5565 5554 5558 5565 5563 5560 5559 5547 5543 5551 5548 5546 5541 5531 5548 5533 5532 5531 5523 5530 5520 5528 5511 5517 5502 5513 5500 5497 5501 5503 5493 5499 5478 5476 5492 5483 5476 5471 5463 5469 5470 5453 5452 5456 5480 5471 5477 5462 5480 5471 5461 5474 5466 5469 5475 5459 5462 5456 5460 5458 5463 5466 5465 5460 5459 5460 5455 5458 5464 5459 5452 5441 5438 5453 5442 5435 5432 5447 5432 5436 5421 5438 5433 5432 5442 5429 5436 5414 5412 5433 5420 5412 5429 5407 5413 5407 5415 5404 5405 5394 5412 5402 5391 5381 5413 5424 5424 5427 5426 5435 5439 5447 5449 5446 5463 5450 5454 5470 5465 5479 5478 5484 5477 5483 5497 5496 5494 5502 5508 5516 5508 5521 5525 5523 5534 5519 5530 5535 5529 5530 5532 5534 5535 5545 5563 5544 5551 5560 5571 5556 5574 5557 5570 5584 5585 5581 5575 5571 5597 5592 5595 5589 5601 5577 5603 5625 5624 5619 5628 5632 5645 5641 5648 5646 5649 5658 5661 5658 5673 5682 5674 5679 5679 5685 5687 5685 5687 5698 5687 5699 5701 5699 5697 5717 5707 5722 5713 5730 5727 5730 5736 5733 5720 5729 5732 5743 5728 5727 5742 5751 5753 5742 5753 5745 5746 5747 5755 5666 5552 5545 5532 5542 5546 5521 5536 5536 5537 5530 5513 5521 5520 5518 5517 5517 5516 5523 5529 5535 5531 5525 5522 5523 5530 5525 5536 5535 5530 5518 5523 5523 5531 5523 5534 5510 5520 5529 5522 5528 5525 5515 5522 5517 5509 5516 5513 5507 5511 5502 5505 5510 5511 5507 5505 5505 5504 5503 5489 5497 5488 5497 5489 5498 5488 5484 5500 5493 5488 5514 5495 5513 5499 5506 5514 5509 5514 5511 5509 5519 5515 5518 5521 5517 5521 5522 5514 5517 5516 5530 5517 5521 5525 5527 5526 5528 5532 5499 5547 5536 5523 5526 5522 5520 5531 5527 5530 5520 5524 5536 5535 5532 5519 5521 5532 5534 5530 5525 5525 5530 5531 5534 5523 5519 5528 5507 5550 5531 5545 5534 5532 5543 5549 5549 5555 5558 5549 5550 5551 5550 5548 5554 5564 5556 5558 5555 5568 5558 5565 5569 5558 5573 5568 5577 5577 5559 5573 5575 5565 5570 5558 5573 5579 5574 5568 5564 5569 5583 5574 5578 5580 5568 5578 5560 5579 5560 5567 5580 5565 5569 5567 5559 5560 5572 5563 5561 5594 5591 5584 5583 5583 5588 5594 5605 5598 5595 5598 5591 5610 5602 5600 5604 5609 5604 5612 5616 5599 5599 5612 5622 5617 5617 5619 5612 5614 5616 5619 5627 5613 5622 5617 5615 5624 5615 5618 5626 5621 5629 5618 5616 5621 5615 5621 5616 5622 5621 5614 5619 5616 5609 5612 5606 5624 5619 5608 5609 5640 5632 5628 5633 5632 5630 5634 5637 5640 5639 5640 5653 5640 5651 5658 5646 5648 5660 5647 5644 5654 5649 5650 5655 5653 5663 5654 5648 5652 5662 5655 5658 5645 5656 5659 5645 5647 5663 5663 5663 5655 5660 5665 5662 5650 5668 5653 5660 5650 5654 5660 5655 5648 5658 5653 5652 5653 5664 5647 5644 5659 5666 5659 5669 5672 5672 5667 5667 5671 5666 5680 5671 5685 5671 5681 5678 5676 5671 5683 5686 5676 5677 5672 5677 5688 5678 5670 5687 5681 5677 5691 5693 5676 5682 5688 5681 5687 5690 5691 5686 5685 5682 5674 5681 5691 5678 5680 5682 5683 5670 5686 5686 5677 5679 5675 5668 5657 5669 5682 5666 5700 5695 5691 5686 5692 5700 5705 5710 5696 5709 5711 5699 5719 5707 5720 5711 5707 5719 5708 5707 5703 5715 5724 5717 5727 5718 5715 5710 5728 5728 5724 5728 5723 5732 5721 5723 5732 5721 5716 5728 5725 5725 5732 5735 5733 5715 5712 5731 5728 5734 5710 5727 5721 5718 5711 5731 5724 5721 5710 5712 5748 5738 5742 5734 5749 5742 5736 5742 5735 5743 5757 5761 5743 5764 5759 5627 5555 5562 5552 5551 5548 5535 5525 5517 5517 5512 5516 5499 5493 5500 5484 5479 5479 5471 5452 5465 5443 5437 5428 5430 5422 5417 5426 5403 5404 5403 5380 5381 5362 5370 5358 5355 5341 5336 5337 5322 5326 5305 5314 5290 5302 5303 5290 5292 5283 5290 5278 5274 5279 5260 5269 5271 5270 5273 5277 5264 5278 5268 5266 5265 5261 5266 5357 5499 5516 5515 5508 5525 5525 5530 5536 5550 5551 5548 5563 5571 5564 5568 5577 5587 5596 5594 5597 5593 5615 5621 5632 5629 5631 5633 5639 5655 5650 5652 5660 5654 5666 5669 5671 5673 5704 5710 5726 5708 5745 5742 5747 5751 5765 5762 5778 5773 5790 5800 5798 5805 5822 5814 5831 5827 5833 5845 5838 5853 5845 5863 5869 5870 5867 5866 5868 5866 5853 5849 5873 5862 5856 5869 5859 5858 5869 5869 5855 5864 5871 5859 5863 5855 5868 5863 5873 5868 5855 5868 5860 5866 5851 5866 5863 5852 5884 5869 5782 5626 5623 5618 5622 5608 5614 5599 5600 5602 5595 5583 5577 5585 5578 5579 5560 5551 5559 5548 5550 5554 5541 5533 5529 5512 5516 5510 5498 5509 5487 5490 5478 5477 5479 5459 5466 5463 5451 5444 5439 5434 5428 5417 5419 5403 5414 5400 5392 5391 5391 5382 5362 5357 5362 5366 5368 5347 5362 5366 5377 5375 5371 5380 5368 5364 5365 5374 5365 5368 5380 5359 5362 5372 5518 5531 5535 5528 5527 5542 5528 5536 5531 5537 5536 5536 5538 5548 5544 5536 5551 5551 5546 5555 5551 5550 5550 5550 5566 5565 5562 5568 5554 5548 5560 5563 5556 5554 5567 5576 5575 5569 5578 5560 5561 5564 5569 5561 5581 5597 5593 5603 5596 5612 5608 5616 5619 5634 5637 5638 5643 5641 5653 5647 5649 5658 5652 5658 5667 5674 5667 5682 5672 5680 5680 5687 5693 5680 5697 5699 5693 5699 5703 5702 5703 5702 5701 5693 5705 5712 5714 5708 5710 5734 5713 5730 5708 5712 5718 5711 5712 5704 5710 5703 5694 5713 5708 5694 5723 5733 5717 5721 5725 5724 5731 5727 5730 5735 5731 5740 5743 5731 5755 5756 5752 5758 5769 5763 5755 5755 5756 5783 5778 5769 5765 5768 5772 5772 5772 5770 5775 5789 5793 5794 5786 5794 5792 5781 5785 5794 5783 5786 5786 5804 5799 5800 5793 5791 5794 5787 5804 5801 5803 5809 5791 5805 5800 5795 5819 5833 5829 5833 5829 5828 5834 5837 5840 5845 5851 5853 5843 5853 5860 5875 5869 5864 5863 5867 5878 5877 5873 5876 5881 5901 5885 5900 5906 5894 5912 5910 5912 5912 5903 5924 5923 5930 5930 5917 5916 5940 5929 5927 5932 5946 5930 5942 5944 5954 5944 5951 5947 5951 5955 5963 5960 5945 5961 5957 5974 5969 5988 5983 5990 5987 5999 5991 6010 6001 6001 6005 6011 6014 6032 6021 6029 6023 6032 6030 6038 6034 6031 6034 5837 5832 5811 5809 5816 5812 5800 5801 5781 5791 5796 5779 5779 5768 5772 5768 5764 5772 5751 5767 5754 5744 5756 5728 5743 5731 5725 5730 5724 5720 5703 5707 5693 5709 5692 5685 5708 5711 5701 5696 5706 5694 5695 5693 5699 5679 5694 5696 5674 5680 5678 5683 5675 5669 5676 5666 5674 5658 5659 5643 5658 5646 5644 5652 5639 5648 5624 5643 5637 5624 5620 5608 5614 5606 5617 5616 5607 5609 5601 5598 5592 5593 5582 5573 5582 5589 5572 5580 5581 5587 5572 5575 5587 5576 5574 5745 5783 5799 5794 5809 5814 5813 5826 5832 5841 5846 5862 5872 5865 5866 5887 5886 5874 5887 5891 5891 5892 5893 5895 5896 5908 5892 5902 5915 5920 5912 5899 5913 5912 5760 5716 5723 5714 5699 5700 5709 5699 5685 5683 5671 5663 5664 5669 5648 5661 5642 5640 5641 5639 5616 5614 5603 5610 5588 5601 5579 5596 5596 5591 5589 5583 5582 5590 5573 5563 5574 5559 5577 5572 5575 5569 5561 5562 5564 5573 5559 5573 5561 5570 5557 5561 5562 5554 5560 5563 5570 5562 5558 5553 5555 5542 5560 5545 5558 5560 5546 5554 5546 5544 5543 5552 5532 5550 5535 5534 5543 5527 5534 5525 5528 5519 5530 5532 5517 5519 5505 5535 5530 5518 5532 5530 5529 5535 5542 5530 5527 5534 5544 5529 5541 5550 5548 5531 5533 5543 5544 5536 5542 5535 5533 5531 5529 5531 5530 5535 5537 5528 5536 5543 5532 5522 5520 5538 5515 5527 5514 5518 5515 5513 5524 5521 5502 5515 5481 5588 5748 5771 5762 5757 5829 5813 5817 5836 5840 5842 5844 5866 5889 5900 5900 5914 5921 5937 5953 5953 5959 5972 5976 5994 5992 6010 6014 6013 6018 6011 6001 5960 5830 5837 5831 5830 5822 5824 5821 5809 5819 5798 5806 5807 5792 5791 5784 5784 5796 5783 5788 5777 5760 5774 5762 5751 5629 5579 5582 5582 5559 5566 5552 5549 5549 5526 5518 5519 5512 5495 5481 5512 5509 5488 5493 5491 5486 5486 5478 5466 5626 5617 5639 5642 5646 5637 5664 5665 5654 5653 5659 5676 5674 5681 5672 5699 5676 5701 5688 5701 5695 5698 5698 5704 5718 5710 5727 5712 5714 5730 5738 5727 5734 5737 5739 5742 5749 5759 5754 5752 5759 5761 5751 5771 5765 5772 5774 5770 5774 5785 5752 5790 5797 5794 5784 5791 5791 5814 5819 5826 5804 5816 5828 5832 5827 5830 5838 5848 5839 5835 5844 5848 5851 5847 5844 5857 5851 5849 5845 5849 5841 5833 5824 5842 5827 5829 5820 5819 5826 5812 5806 5808 5818 5805 5801 5809 5810 5797 5797 5793 5783 5787 5783 5773 5784 5684 5574 5574 5575 5580 5556 5583 5563 5570 5563 5550 5547 5552 5542 5538 5526 5536 5527 5525 5513 5521 5505 5500 5495 5484 5486 5482 5466 5472 5460 5468 5463 5435 5452 5444 5431 5420 5414 5397 5402 5398 5406 5374 5390 5386 5367 5371 5360 5354 5342 5348 5327 5320 5327 5322 5305 5309 5292 5305 5297 5290 5292 5285 5282 5283 5262 5293 5286 5290 5288 5286 5294 5302 5289 5291 5278 5294 5287 5287 5292 5277 5279 5297 5280 5276 5266 5282 5274 5280 5269 5270 5274 5272 5276 5260 5269 5257 5265 5266 5382 5472 5465 5478 5465 5475 5480 5473 5489 5487 5485 5482 5493 5486 5492 5502 5494 5501 5496 5505 5498 5506 5502 5502 5495 5511 5507 5545 5533 5538 5535 5550 5559 5549 5574 5555 5566 5564 5574 5569 5589 5598 5577 5598 5598 5586 5601 5589 5597 5593 5590 5590 5590 5583 5582 5582 5589 5586 5574 5575 5570 5567 5580 5569 5584 5562 5577 5556 5555 5548 5563 5560 5547 5542 5545 5538 5546 5555 5545 5534 5536 5533 5537 5529 5530 5518 5502 5536 5543 5529 5538 5523 5534 5540 5534 5534 5526 5522 5526 5539 5533 5539 5523 5537 5528 5521 5519 5517 5525 5524 5523 5526 5524 5516 5524 5528 5505 5518 5508 5518 5498 5512 5501 5505 5502 5499 5505 5497 5492 5492 5495 5495 5497 5494 5487 5489 5491 5487 5483 5489 5484 5475 5475 5454 5479 5477 5456 5487 5494 5481 5479 5485 5484 5480 5473 5475 5477 5477 5491 5488 5472 5490 5469 5475 5487 5478 5481 5488 5475 5470 5480 5471 5479 5478 5465 5471 5476 5474 5458 5464 5469 5469 5460 5459 5454 5453 5460 5454 5458 5453 5462 5463 5442 5463 5443 5435 5455 5436 5447 5423 5441 5434 5430 5433 5420 5437 5426 5442 5439 5438 5438 5428 5430 5439 5439 5439 5445 5432 5436 5432 5440 5431 5449 5442 5437 5430 5439 5425 5446 5442 5433 5438 5435 5428 5433 5425 5432 5419 5414 5425 5422 5429 5431 5421 5415 5427 5404 5404 5409 5405 5414 5408 5418 5409 5397 5398 5394 5397 5398 5386 5403 5376 5378 5386 5397 5367 5403 5400 5393 5380 5389 5398 5409 5404 5404 5391 5415 5399 5407 5405 5409 5404 5404 5411 5381 5395 5379 5390 5382 5442 5478 5492 5500 5491 5503 5498 5484 5501 5502 5485 5498 5503 5494 5486 5501 5504 5495 5496 5491 5672 5676 5662 5684 5678 5689 5693 5702 5702 5708 5719 5705 5717 5728 5720 5741 5728 5778 5761 5773 5789 5795 5792 5813 5821 5814 5832 5837 5845 5846 5844 5849 5862 5873 5863 5877 5896 5894 5902 5913 5915 5928 5931 5924 5940 5942 5948 5946 5951 5957 5958 5966 5952 5963 5970 5959 5961 5981 5965 5972 5972 5976 5982 5985 5988 5966 5987 5971 5990 5973 5987 5983 5991 5967 5980 5996 5963 5999 6010 6010 5994 6002 6016 6010 5786 5762 5777 5769 5761 5767 5762 5764 5751 5747 5741 5731 5731 5734 5719 5720 5717 5710 5699 5703 5686 5690 5692 5692 5678 5671 5667 5663 5653 5650 5670 5655 5646 5651 5666 5656 5652 5649 5640 5643 5641 5634 5636 5652 5650 5650 5626 5640 5638 5638 5640 5628 5623 5634 5653 5639 5651 5646 5660 5652 5660 5642 5656 5649 5662 5666 5649 5662 5658 5651 5659 5665 5659 5649 5656 5663 5670 5653 5661 5670 5648 5657 5663 5668 5655 5648 5657 5649 5649 5662 5642 5645 5638 5645 5652 5637 5646 5627 5635 5623 5637 5638 5630 5624 5631 5619 5613 5613 5618 5621 5628 5609 5595 5621 5625 5633 5629 5627 5630 5623 5624 5622 5627 5634 5625 5620 5623 5619 5629 5615 5637 5629 5612 5620 5629 5619 5619 5629 5618 5621 5617 5622 5608 5629 5624 5621 5611 5613 5612 5617 5611 5608 5598 5603 5606 5596 5586 5592 5596 5578 5585 5585 5593 5578 5581 5579 5582 5565 5566 5556 5560 5577 5555 5575 5586 5572 5586 5582 5585 5584 5580 5588 5590 5589 5582 5589 5579 5587 5578 5589 5588 5583 5580 5591 5590 5581 5585 5583 5575 5571 5577 5580 5568 5576 5574 5567 5573 5563 5570 5570 5558 5560 5565 5569 5561 5556 5560 5560 5563 5557 5557 5560 5567 5552 5545 5550 5538 5534 5547 5540 5542 5537 5532 5545 5534 5551 5547 5541 5548 5556 5555 5547 5544 5550 5541 5563 5554 5540 5551 5556 5550 5552 5542 5540 5547 5533 5543 5546 5543 5543 5541 5531 5538 5531 5537 5537 5535 5520 5538 5527 5532 5535 5526 5528 5540 5525 5529 5514 5528 5520 5508 5590 5691 5692 5699 5702 5710 5715 5723 5722 5715 5732 5738 5753 5749 5754 5754 5761 5777 5770 5774 5781 5798 5809 5800 5816 5806 5824 5819 5820 5826 5836 5834 5828 5842 5838 5830 5846 5841 5850 5839 5837 5850 5844 5849 5839 5841 5854 5845 5858 5847 5851 5849 5850 5850 5861 5858 5867 5867 5858 5865 5866 5859 5876 5870 5862 5865 5865 5868 5871 5858 5854 5843 5886 5873 5881 5887 5896 5896 5893 5891 5901 5900 5913 5904 5897 5918 5916 5915 5917 5915 5925 5926 5927 5924 5930 5922 5930 5943 5936 5937 5925 5947 5949 5930 5948 5929 5945 5957 5948 5947 5948 5949 5953 5946 5954 5948 5959 5955 5962 5959 5960 5948 5964 5967 5960 5967 5961 5960 5970 5952 5963 5962 5970 5984 5971 5990 5979 5983 6001 6009 5996 6003 6002 6000 6001 6004 6020 6008 6012 6021 6026 6032 6025 6020 6021 6022 6030 6037 6039 6031 6037 5937 5828 5824 5816 5829 5815 5808 5798 5794 5788 5796 5790 5780 5784 5766 5765 5771 5753 5750 5755 5745 5747 5736 5740 5738 5734 5724 5718 5720 5710 5693 5718 5704 5710 5703 5710 5710 5701 5709 5688 5686 5702 5691 5688 5679 5685 5684 5677 5665 5662 5656 5653 5650 5656 5659 5636 5639 5636 5631 5629 5628 5631 5628 5613 5600 5613 5596 5606 5587 5594 5588 5592 5581 5570 5577 5581 5562 5558 5561 5547 5536 5554 5546 5536 5544 5524 5533 5527 5506 5520 5503 5535 5516 5521 5509 5505 5504 5515 5516 5505 5506 5508 5497 5495 5493 5574 5686 5700 5698 5701 5710 5716 5716 5719 5707 5723 5733 5721 5745 5743 5730 5730 5728 5743 5748 5732 5745 5733 5738 5743 5745 5739 5746 5750 5736 5750 5747 5740 5742 5738 5744 5756 5748 5748 5735 5745 5736 5733 5753 5746 5731 5762 5753 5767 5775 5767 5776 5768 5774 5772 5775 5778 5777 5790 5789 5781 5792 5799 5795 5795 5801 5799 5790 5793 5804 5788 5791 5804 5788 5794 5798 5796 5794 5800 5787 5799 5809 5806 5795 5797 5801 5794 5806 5809 5803 5795 5806 5798 5782 5794 5789 5786 5806 5783 5785 5705 5626 5614 5618 5594 5591 5613 5596 5607 5591 5596 5584 5572 5588 5587 5574 5569 5577 5571 5583 5579 5567 5570 5560 5566 5570 5561 5571 5563 5560 5554 5546 5563 5556 5549 5552 5556 5540 5551 5546 5545 5543 5538 5548 5527 5543 5533 5535 5539 5528 5530 5524 5525 5511 5521 5505 5504 5495 5491 5499 5483 5485 5495 5484 5481 5465 5494 5488 5495 5480 5475 5485 5487 5476 5464 5482 5475 5478 5479 5475 5467 5459 5467 5450 5699 5690 5690 5705 5710 5706 5711 5723 5719 5721 5727 5717 5740 5734 5725 5747 5730 5745 5734 ntpd-1.1.2/docs/algorithm/offset-ntpd-rs.gnuplot000064400000000000000000000002431046102023000177740ustar 00000000000000set yrange [10:70] set xrange [0:3600] set xlabel "time (s)" set ylabel "offset (us)" plot 'offset-ntpd-rs.dat' using ($1/100) pt 7 black title "Offset to server" ntpd-1.1.2/docs/algorithm/offset-ntpd-rs.png000064400000000000000000000446301046102023000171000ustar 00000000000000PNG  IHDRK pHYs+ IDATxy|e?gJ$\-g'rڔr-P( KЦpA\waR}:!eڴiCZ|yzzd0f W\:w\=~ᇔꐐBHlls=7| @׀}ÇуRVVֻwo.} !eeeR";{w?rթjCaaaOy7nhPh4 /fԔʶTٶSS"XYd{NIIqywpQQѥK}Q[n}ƍoܸѭ[7˅,mM&˲aaa um-UԔʶ/rʓ'O;ߞ6mJ3AAA>+00[n,ez=x]۩)iKm;5%mmʦy*(5w~ᇖ}uΝ]v]~===]P'jѣKd2Ynn """zypi @D}B֭[ձcǧzۄS644pO?uyyEB~qƅؖSFFټysBB?޾}{󔍿[PPеk!G_r+tmӦM ߿˯kkkjkk\ޔMӥ.w=C+W\RUUE9y$˲۷?}4k׮ǏgYɓ ˲/^dYvݺu)))׮]}c=j*QRiw۸q#{GT*nGfX^^NyYmiiYpGn#oFZZ˲7nh߾}NNNss#Gڷo=ݻw[ZZ\{1Je)JO8SNK>BQ]]BQ___RR6nةS`^G/CIIŋz}vFgwa},KٻwoFF!>4h̙3rȑ#kWXT*_xKvּ׀С-ܸqC|O۲eϜ93iҤm۶TsrB˲---"p.]pFGG.QV޻wo:~g}Fp?˭srwYd8qbvK'L6g3fMMM%999Z6..NYϟ?Ν3gΜ9sٳUUU2L&|K.W^5k׮3NL6cƌ &pLMM=_.]zg?[---UJRTAo@зxbR裏;wd2ٳg@7ӧO;vYRT*uɒ%<̥K!W^?IСCSS˗m7ұcGaÆƢ؅=裏cc=vќ#G\pWξ蚚O>O?5LݻwԖ= @J*,,h4Çj[nݽ{ܹsr~:""k׮wy!zLIIQTG.++#? h4?F,XP\\>{l\駟uq۷o]ۣAWVVN4[jܹSv_w/'Ng3LE 4LE *!(@P @0`  (@P @0`  (@P @0`  (@P @0`  (@P @0`  (@P^!??v)`={vVVxvƸ&BH``Si "јp]߬#G1n<g`СC{nlldYeJEs̡Xe٩h4ۜeGEH$Q5*((soٳ#F /,,$ h43vy\\!:tH&eeeO>0TJZ{ ݻÓ&M {2.}m,mRpUUոqMf4  Diii6mСC/_n2$( ׯTNƎ˲GyDb !==}ܹ 듒heFO>JY/"l2qgyk׮{2d!jzҥZv|2 #ea!z*}9hb4&Og>zVkdddHY/w}7dȐK.1bǎݻw/++ݻwHHNrrrYYsM&djmt)))YnCjz„ R\vM2dQ ZZZ?xry(>|rIeeFqgR_|w}뭷.]t}͚5RWWV넅}:khSFc@@ߣ Tpܹcwڵk%./UX.;v,0K(?ۍ!7H3ࠠI&q~z}tttMMMhh[DFF>Wфz fv1#IO?Uĉ4v(Nyy4q{guOPPPKKcKt:%ngV,znIII >m֭[ӷȅͦĸ[uvVwE{/^,̙3w.Ma\uVKZm2'x"''~Æ #Gh4澜wٵk%( X:tpsY6n0Ç+++z=0ǎsl|z E+Ulb֭^Phhh#0WX=k.]jɓ/^-<}aÔJesy[\+i @Q^^`x[&qvGòoiTaaa.l/ *vlٲEdTYR*xbXДʲU3`0 !r<00TIJâ"NLT*ϝ;mk `FPk\RR"fMR`7,,p?04&Ԕ7"֬Y%\5 v裏:(a޽}q]#5k֜9sͮjz~Ϟ=?e2YEEEKKKRRA(0Y]]]~~ĉZC+\p90L2EQggN(..\ y !uuuvݻW⒈t!b桇Zb&??g*\1H`0{ ,**޽hTSN}j vwkXR¼eّ#G҉m ۅO>%c֭"w…---?>3?Þ={!g ?IjΝj1`}o߾-t6 0Ov?.gY|stpn)AhwWܹs{l[^+;ۛ߿vD̡CSݻ788S`(..2dAwyzA{OyyJbF&T %"{^^NС/\`^Q~iiiv7T*t_-[lAppvqQgKS_B`+y衇nAAAn*##CV[naݻw߂n=a6bGXyyyvz؝~ۅ FFFV`5ii,Lfcl9<2{ur58>rܶ.dվe]pxBL&S(aaa*۝: >|-\O%%%y|_V_ ôkoyyy;w zBCC> rRTSs_\n|۞ HU*J҅*JLm lMo|]\;@;Sh9M<;1L"ɼt w.yyyvރ]+Un+**K!_>}DѼ5Bhu`0̙ýsnXY|7H&jadϤgG(u6m;8 YFČD"s\r{ݿ~?AϞ9Wo͚5b.s6iwr|v?>wݻw;8mnH;qjb:E2Lt+ylfY6//1qWۖV Qf*`0v(&1&Yj>wr,=~ L|3Сȋ@.[~}VpQlG?[:\fI8{-ƶwF|IF ):t {_t_;;W%47… ] gX6rc* wx2j5DzT^jd&~{Μ9?J3__}eɃ_S`*** ,S67K]^|حgG|I`0ؽ0sLgS-[lڄ9s>>luV}=ݩgӗL&aFO_HP3ꉼ̀;֬YcSiy^;{ѣG{XyEDً~aw!jwzA%$$$&&J܂m~g̘IP Ŵq\.s.<)Am?T|h9r ;`wjS_ ;;zF[nȯZZg_I[ċ8zhl׮e]#|=1=n 5O<ŷ}m o Z_۹qGOmPT%r9sv޿O{|=U3_sӍC%pҬ볳1t4rH~%9Ӱaִh m7ǹr^~etL6gΜUVL/R",0Rh`xcn5ًst mw8a6 yD{P(Dz{ \j*PM PŠ9S]/Dph,?g|X<@:Eb<.[b.;CZ>\{"$`&_(Pb=N"T_f̘a,75+/5<>E| H6ي  (my> ʈ0pZ>-]ͩN@`gjw'F[ڵ+##C/[b w6tPv;Cd;G}&: ^ 3ʅFit8ŋGfnk8l{*(jV+prOݻ-NiLX"󽉞%<=p;Yڨ¦N㩯$/1gS ω? B;kuP(Æ 2_;Ʒ ᏚpuƪieժUNl+15uӲ?*%p1MĕJ.$vNoǾ}Bd^duuS׀zĨQ.&\7_Vc8xҫ&n7F) N\;Rbb$v`KLLqkpٳs-Z'&&:|7=B̐ {fkxꩧ7kY ©mg52e~;c(fqwZ)~O0`Sg=vDwGjm9m 0_+}@߫)SقSm"˅_d?}F: 񠐐.l \|HOs#e:傌 IDATa9k׮v1/@Ivwr1c~@`u}~*0WK+n?YLuJСC3ɖf˄m-wB]mwwb/0ܘ|^*ֶ2{lipx`5dÇK_}wp-7aaaξ$ rk; 2jMaÆٞ㻸+pqz퇍k# TNݯWBfEk],p.ŪCpBNh~~ -'J.槓 fp܊t|7h7#, ^mf͚%}7[ /,E|SΙ3ucx]`7njǏ{gy$y"g=iP!|!rYhh.{W9ciLrJt7^AHѸSZ `ɡibpƫ@e??I8zhMhwS2, s0)]={xGN7ڵtXUȵAVrW^O/BeMriaVؒS-ܝфofk?sK޾z5 %>c#ͺ+V0 G~{lm9R|?ò2[oɓ'O<988Rx5kְ<+|͡CV [rICCC~~>ٳOF>0 z'ƍi7O :uj`DʲÇŬԩ?.;S~EEw]ԏ駟\(CX1kjׯ{ yg^{5:u{.l2!!μa`7vO4jG1b]0aaNœ]]'N\v-kRSrĄs[ZZ\z1%8kҗ;rNQ0۶mCov8))ZnZ຺:g2rcǎIP+'ND-7s|$ॗ^mٲί]qv^*Xc ނVA.:x+Om ͝;W֭9ڵk߿aXeffyf/,0 O9 &xpt0!dȑPwnVR1O>}:ߩV\)0d޽./**^r҄Wԩ˲Z 0[|9Cmytka4Ŭ,f~ Ν{.7nܢEy󒀀(U9s|L&oݽ{vˀk]0LKKdNXߋwߍ]_p\65k2L>xӧm*@k1}tn;0v-[K~L=`ivDNKK;~8713JKKI0L&=d8%::Ν;]ַoߓ'O.8!::k3ׯ_ll,V*gϞEs6)bꚚ CQ*V3Bs ĉ)0\&hIEEE9\޶l2srr)0\v!f5ɺ5r$M`'ݼR``d|qx{r$~lwۦ&,!ݚ^`?h"sss,8 4n-G%5qDS@BN3YfנA!---ӦM:thUU[ K,0zhez)Z%9r$˲z>;;eСJbHt3Lh!!!K._KSieff."u6dȐ۷s(++ݻwHHBrrrYY4N3QFvĉ˗/gfٲeuuujڼNXXXmmsM&dQRRR^nB!V7>h4lS.Bzu圜e˖޺u˼NMMMddݧ,kuD"$"nD׀ڵkw=BH\\h "?v}F%.'NtK `)FoٴiSzz:!d111YYYwٵk׹mgGYr͛7uhѢkBd2Ynn """zyp  ʲեo܏'LE @0`  (@P @0`  (@P @0`  (@P @0`  (@P @×/_/N0`ɓO8!e) %KVZ(J卍}aa\.~ o;vvM:uԩ^+C', /_L^jիo޼3{T~qoݺߊgyp:Gcbb.\πe˖/ 9ਨfz˥sݻMA_* xx͵v}++.mnnn۷ѣu:]߾}U*Umms ꫅ b$xxݺuO?7oj4 &FRNXjzҥK.4m(@P ]߻wo o>{# %+ uwߵZk.oST[ZZM6tЪ˗L&g J9_|jɳ> WرCכ?>;;j6Z/^?#˲ϟW*rܩ<3ׯW%eee{ MNN.++sjPO>d;kN/v?nuuuyfw-d2,tಂÇ[.tsJ $,[lǎ.qʕZz-555v%g@6ax;̌Fclll!ͿV!:_ "g?SSSY:xr|;BBwWWW?^bbb._]RR2iҤ'Oo^.dee999ׯ_OOOw^_WX1hРBJZ~Nվ}{BHNd2YnnnaaaDDīzpк8nٳ_~٣G3gΰ,.٘]4Ar?߾}SNJ"&u: /LaYVקy`q'/ӦMk߾}CCCΝcbb0eV=vXiiieeedddRRL{(q?~ˉÇw֮]{M Jy󚚚!k֬)//_z) 9nvZLLLssΞ=ѥK JpppϜ9ӣGV{޽F J… xwnذ?x`77msBO>e\D }7+ ?❊2<<ݗ LE >ȋwC_xq~nݺkY=rJa\+@~;;GWXpor'aD/hSxπzܹ'|M. >_?x;w]`euVBȼyy ߌ q$Go߿&55u޽ 9>RSS,X0w܌ / 9>za2ʛExȐ!ӟ !/_0 zSLپ}{׮]^z}8p@1ܫW~ĉW\ܹ Q}(۷gϞ1bD```|||aa%RA>˗/=z2++2mڴCVUU-_<==d2IP_ E'$$?"""**JFBHqq糳jҥKZ%( /PHΟ?d2|焐޽{p+$''>d2L&LӥHPlBHAAÇ-TVVj4w)Q8qܹs999QQQ:Zm^!,,sYeYjWK `6a$Q+Ν;wܹz|Mhh[+DFF>Qфzi `Kt:%nÐX=Bv͛ϟ?{}뭷!---ӦM:thUUM&RK/4n8V>#}!jzҥZvHz e.!!RVVֻw䲲2) @Bʝeff,pBBH]]Z6?V[[kd2,toSPPpa%ƝmJ[n  !n2?ZSSi,˚mxlF믿}N:qKFc}}}PP!dOh4aaaz^rt:rIAA,57xcӦM:t{nSS!d111YYYwٵk%( /"lrڵ~M:"rss #""^}KP_ Eh<66oSQP @0`  (@P @0`  (@P @0`  (@P @0`  (@P @0`  (@P @0`  (@P @0`  (@P]L&˲K!eu:x]۩)iKm;5%mmD"}ÇԔʶTٶSS"ye @7ߤT^zY.?{# %( "CBB-ZK/Y.lii6mСC/_n2$( /"ٳgGEEY.,..>|vvZ^tVݿ:a;$$799vwVWWX.h4FRJRPP@ ^vjJReNMI[l۩)dj~zll;uuujoXXXmmj=ƍ:B,]5VJ۩)iKm;5%mmD˵Zm uߚHV\rJ  jÐFc}}=oIII\\HLnii{nSS˲wmll$ <8&&&++Ν;v~zzzR4Ar 4X&.X ""gϞ0i#|  @0` ZA] 5 _'O6/߰aCǎj%Kuuu!!!]tپ};";g…{ffϞ=˝g}֫Wq3g 2IDAT]rE fc[ުkZQQ1cƌΝ;괴?m嫩_cǎرcppWSo+ݻ׿իWرCܼyvVVVV_____-ܷoV-))tRBBBff&|ɒ%>`UUѣGU*7|Cm߾믿ׯ{g^T/\o߾7oΛ7/%%B5D[m۶͚5ZZZ孺~ƍO>}ŋwޝ|5˷񫯾rJuu}Y|[jJm[oQ-[-0a /ŲlssJ:t|͓IJJ%*yQFq \0LEEtEwUMm6{lu_~r֯V'NdV˚}[} Z] [sƌF[RVV|…/Z.ow+wҥcǎ֭ې!Coβ,!ğjZTTt}uԉjYSo1cڷo?`I&%$$}[mkJ$Ȼ.;v0`@CC֭[ǎ'$$IJaaa:B[}*XWWgywUQFvĉ˗/gfٲe~SK.-_/L&#~Zԏ>d2} }[mkJmy%##رw}fYӚBHhh(w[nEDDpU*R˩ ھﭨ ի˗srr-[JZM]6f̘իWϚ5[omMmm߾}׮]omM龭w-dr޽{RnyIIITTThhhU*[}*hoܸJ+ޮ];VUU͝;w~ڭ%z[-,{yo%sM-Qx[ݹ,>{;wj4~vrԩ/ƍ/_~駵ZdbY6''sΧNvڀ/^odyjo߾r_wmӦMʭk׮/o+_Mm?裫W^vmÆ Jٳ?|5z,{aÆ).?hƎ{ CYYY۷WT-2O9sfpppNQ*sRRR,>snSwf oo߾rٳgرZS=z??f޸q#)) 2Vs`;wn|+w}80@?] :::11X4AܹwݢET*UlllIIN:u>^UU5s̎;FEEmٲvaȑ2&dggwEӧ[j0-@hze˖RGSLIOO7?,YHyG:w|…G޽V[(--۷/wIIΝ;Om΀Z ZgEFFTSN9s̙3ϟϬILLӧODDo޼iN߾}{_Bn߾OGDDtΝ;/!>a"_ǎ_~G׭[׾}իWK\*M (@PIOu$9IENDB`ntpd-1.1.2/docs/audits/report-ntpd-rs-v11-final.pdf000064400000000000000000020232671046102023000201160ustar 00000000000000%PDF-1.5 % 1 0 obj << /Creator (LpD06/9+Պm\\[gtr\(bP:kz) /Producer (LpD06/9+Պm\\[gtr\(bP:kz) /CreationDate (LpDze/K+c}=[%t4\() >> endobj 2 0 obj << /N 3 /Length 3 0 R /Filter /FlateDecode >> stream my Խ2P)yD.qϋ%^H#xuߋ)Z;VJ\g*YN9Lv?LХfJ[X3\xiउA0qdC^JD"itvoǕ[[}3Q}Sq 641\ ̮Xw|Ngx2Fee&O1gr;DĪԘ@CzԪT>o cO>>14nXH_k qBʱƷB7p9#)z$ɇH<67o,-n~ٛmikҵ^m^2WX6mG&,l-+ ӵ>0$'#*/zg_+==un`]7f  (q0p ;DŃCɚ:=͌0xbOې!RbU&ki $ M8#<97u9`"͔S oNgww}ĹOc@^Q4bT6΂]-䍪cuUAa06h1|w}X|oUϦk f s=D`eκ6@]CSƇ ;#ҁpsxu ;$ypXSzsÐXP֞ҎN! _+z|%G S]v>I?D):'0JE$ICI$x2NO//69[۲2K,[G{5l^'ud :qf+dRbL'. ZMjԞ$"o_ɕ='ŀXC9f ѳ0{-gW饠6/x7Rp4[4-AGe p4fؔsnQ*{*^@Rզ0@qYLJS „r[ԱPRZޏwb}XAuhV *Zҗ2 [jZ\zjNe`uqӼ]/Sa P7Bɓ{9!_Juf^ ^Nm صRta/9# 0zQk78%.PU8'X@ 3] ܓDџ>7wkmͮHa/D{K!eZmtr#̓<y8غN G9%cL!|#J|Ұ(>ڟ QݕkWip{hn FVڣ7,PڬGtA`;{èw/M鳱 /b `ڸi$m{Eq~NO*V>ggW)7}](^КR ."`_ |RR/aN˘JϟtL||A9@7u0aХZxz٘8v-&:ÿ \㫩ݧA/5ه݂. L˻^icݠ]#׺w^.y0Jwg*ŋq~Ö$]_[r/IS6҉՝#[gߕ=&\Ga4j5(n>7k-38zk1ÌpJL1{lDá22w L|J#jD5 z\=HB9u- Ւ endstream endobj 3 0 obj 2472 endobj 4 0 obj [/ICCBased 2 0 R] endobj 5 0 obj << /Type /Metadata /Subtype /XML /Length 6 0 R >> stream }^yZed:I@ R{?}q}9V |qoQ–Tq)ນ.ŶbɺVuSŶ^Q,hL䓄: xo $ hJɊ15$';NqL1nc_@-o޶01a֫ѵQegҭ2w!aW{.$ 1~*Ym&4tF\ -dϼ\)teMX"=PT2yDOp1hX(4P$.Yp#258r \yI$(NKcmʭL ?}n6L($lYBQ5I18z~=A|I']` ^||̦U^ذ<q1.hȜq~e_YAhdFE7\ޛQS `X9է1i;΢j,cjav22wAB+A?C!3G`>dDpvait)Cͨ|4Tr_>?)< ӈP"XY4@sp3Y0| 3Ψq~`)N mu  Q0"B.gy.Iv:%<9PG=t@88["Y9(]7pml:ozV , 0 < ݽ'g;9gyQUUI4Uif5ap1Е :jYqV,uCHֆU2iӘuBnW|@`kN7L!ÃqEp endstream endobj 6 0 obj 850 endobj 7 0 obj << /Name /Im1 /Type /XObject /Length 8 0 R /Filter /DCTDecode /Subtype /Image /Width 826 /Height 1169 /BitsPerComponent 8 /ColorSpace /DeviceRGB >> stream -1"&vbma ;3cHsI` mj7|^tEa_*CJ.>jMZZYf)ʂ̡| %wVػ#O-h}<˷3K.nh'EaGer"#m쫁tAKA e"r6cU$/$6]LчCHRƨÈnD]-Wv Ԉ_}(٨BBd!Rlka\MLyi鿼Ejyze>Z7(˼Ā #1%H¼UX-g.&>ZI eu O]`:?ֈԍ"+,(hmIu d-L=8r./234>P 63~>I=,G\~vifjK!:k+,$7bl.N:|ee6 L0_a1J)N*G]:_YN<+ڣiȖAЂܔhH4BE  JE76/vY^4 B@Iwl$ a>jgR a'!Xc")!ZRy|%fAZ۾\-dcw2EsSK  |&tDcc*u[d<^_Wѳ==^" "pη{gg ɰХ}o#_\̓1D(G,߬{12 ΈBbP"?հ{7W!爸>aw g?gxOs4UEVZxT6l\2Ur*za&p71;`}.7S3aLҟǜFO@!X86Y@٥h,̺ˏK<#AtQU7ٜtOLX^= ,di|Z-*0,6]N=xRE7A\= z]dd *-m/ܫݦk].g{.ˣV_+^X#yN 8M4MXYw#r͵0:tX5۶ӆ>f-F* %mBͅgyLr[1)ĩ6.z* m Ω?R kZ7 ?~M}wC+ph8ZԠ =NI4}(K)s1- DO '"DM6ҽݠ1_(FwN9B뒱[:TX20$oY_^91&(7Bhn2Uۑ$QQJlOsBj|G*m_cF :d:3#Rir\={ţv,!w1R$9\1It+8gP>(M&Ⰾ+շ 5Wp:.}eBAI`bkƴa}l8Mz!o\1EcKјJ)DLǫi/f~^%**إfL7R`گ`x7aޑfiCCF^4a6Tltx}Xh:J62N2>v+lj#)d[֫7iK'sh+=%E&F0*_ UC:N6SLSr< 0OGC5[=f+ˮR*HNqY fqf'1}$s㴖MX)Ȳ9}y O?lrc"Cg zGCMtcXkph^Zht$f,uPܑ4BAEUE>̏ۡ]ˌ$[Ƨd;; , *c7ǮL׺ӬM&87֬aY::"?L 3]րz/31Y;;tXsx^2[f~H(QO5SuN3D%SVZrJJy:Ctt܍qZu2X}!|z A5Iwv Lי f=L. ;6\ɗW22?Mkә9w()=tڕL7Ҁ#rda[s+K L8z$`-qk&=l$ؖ†" _C~,X2Yp$p ʢ~VQq3OY{";O"-d'~Lț\ãK#O~g\^Hs:sEZ8ʐwj8"k˙,F~ˠEQ14O]V*V&#X;w"mF23\cg.2|2 ]~;:.&~ G\$CՏE*5TJ5n@ZN98b{!}FX ARbCԅۣyhd>7'͹d@UKOHl_7):Fw j1ME? }*qSMdJBC a ղu=v}zmfi悳O.GPUEAMw20 C͖t؉ $wʰTR<3b'N%ֱ<0LxN V5~ A0?`_UV?~" k/J,w(E"aްf: BAWqR3Zӽ^;gEqL+e}ZfS 0d]cz`T quցBbCQbA}Dyk UkeB%];E.x <5Mqo{4"zO4>;(tFc0wF+[zƳOf㹶SzS0 l8נU'_pHs&_ hs/AdC"Fbbmv0Sj[$Ĝ#QTWAԩ2Wt)ywcN3\>Ǔ?Lbo'jK_k$j+Q,\K7/yL$^ֆ)iZ[#Q,5On)>:s~p~5ZxT_C|T>oU(]w!UI"Hҽ:=0^&tk,(c7Rּwt>i y)Ϡ֩$1tMl zmLEO$leOߍG>w*m ?ɳmv E{Nt.&d_U0 g#gn852F 4nz4ǬXa22o[Cd]${,3Dr(洀B>'_ۛ4:Y!p!YGtIĶ筪lu]JlBX3P8r03op^"ټn1>D ډ£CǦAxJ0dI^K&o_hFNe]D_Z B[ToZ8&A[!,,!wi8FTM*QP/lVl>M]ϝR:o8 fTcN(2-dѐק8xA?iHg==NCV;q[pيg<Pmlʎm#&cԳ7hBsT%CW $lobѠ~4[2^-Ju~bȏgNaHˣ=D+-LL%70I̙@`>|=kfCs:w[S{d2Mk BRDh %E U쯿ҹG"7(wĴ0_E9bs(땟>}QL}((QIa 2 F$j^^@ pbkڬ-8j?^I'p )*(j3dpΝGݞE1,J L RUf9|hUT]n'CAZ䙀Z`9$DWΙ''whU~$+;#|޺6P :%}fp[[m b^d|pI9$7 lWuzIL!;lb6:= 8jk$6y{hd8di;8a"AH'bla Ppf1fy$=B?= 7B9oy@XG: +"!y0uҺƿ{`ul -p >θlM9 7Of2 64+„ZΗ|+7 ~~-d]&F3PDEz߰l7?Hq -D.CVRL+n3G[-7:-X: N?}tm38/u2jQU0 Fߤ)uz/$k'd^e(W#"2U˪6Kr>.}p~R*;@@?i.ȎCydglL?ڹ4{$<ܑC+Oׅ͚Gцe5J) bAIicSs"+ܺPdQ{r0YǽհOXoV$KD2züE ¼2w;1KI|XRaVd 9Xv[i'uDA΃m@1/W{޿ 0UޔdA|Y~rARrB'%HINvRLCRA^ۘiHl% Q5 lfd:6"0LSdk&gKoc, _>=1(W̺! Z3=B gNMdA4VGzirV\|!ˈg;RN{!Er|cEߘe@Iơe8k΀u; E:p79/#rphs!S7v&q/h |{(r9A]eY5 jϓ&?!uܳd:ԣ'w#npāڮ9ks$5ɖًDղgmt"fKL9䤃ްR -E1OO ȿ+boNJ:)!gm`-=j yqǩHΘhfU;\;iЈ)L#b/_FjKFS^SPeOS#F#J0S5@ 8Cs? i}ם-ϣ՟Ue[oџr~&h*@5K 8 ]d8U8SZٚbX[fOwdUBM\,4!gҪ'%K|[R t1dȍAo\d 3OWeO>dq#1JT DҰYIth%*ldLT2Ad8 L)`M_lnN ][xI~[m u&e`-0ߑGR"gZ d{ccl^Re:q^{Q.>7;Y=\08ԑobX},\'Fl욙з/dr '*(o.|hD1Q+D^OIl{L597ei0\ٚD8e:HHWg)f;:brphN;z9 d&>%[UF%G֌a{v)¶c\A3)k=ϫbwIXHX٭t9,|y١|gM:B4V#5YdŅ>^rJ,_e+_>+ j]N ٔҩQĵQcer Dr%^m9LD`?۠^X_`Vh!É:څ _}ر*ZT'lfח[+('VnȀAq)! VKUk15!F2hOd+c|ƾ?ռvV LV\`l:S+)vNL/Q?j_,D3,$} ۹J:-;IBp4 ˦ #hYfC,W'ȆBON`N&lX1H=GcCLȑFKMscVE>̦볐0-UKrfߠ tӺ]\'OaȁnT۰RnJ1C8bw<`:31)92$4 }kaBԫO0/b  ^%i [e*Ah9~SA|xg=( ʣsڌ6G?AR|ڴH豱x<>*XCN.i#N_%}_Du(g=uw.i`9^<pB? |"oo>rCmr듟j[fAg 8]1V.XO`(>:sWiņV;9~ lvߒWV;Gi,p=F_KȈ]Ynvʰ-m0@ɖ@θU_o0;,U=%$*c("qiS{z(a_XDž~4rv”;i77Wșg =p NŖ&.gLHCf|ND= '98 n{B*ږsIz,n9s=}L\mS#~1ʍ_ll4U>@zn MDm~@=]\cM;6&!CLΌVrû`yAŦK||˩QWK|=sԎE<Ɉ~ԓThHd[1~`~ %2#\yd௞^Vĺ7'=X+|{f+Ff.r}]Q\illdih[;ɶ9-JI9/\^G%O>ch3nd9OY4d&nNGri{ujp>'O9&VN2 %rG>5X-VY|A¸?%hG\< w w+@&3IA󒊊bHDzGpz'LH~U>#@#NRs&ѿf޿%-<(sh_ JPVW .Q.tv3Pƹ `ʋ|z؁5^%Ѫ[73_3BYK=䨛YplCU*qyqkJ9|YWB0>`c=+<.&6S͙`kQe5)G=: ߀@Y>C qnLO)9bd (]EUNy.* `m~ nyHny&*AWWjDԝN h/*YZA9V SV#J8͚(5b?7@%t צ':8 L|oYgZbk]T|[GMq:3eLN@03\9d[~7Kő0Ϣ_G)t 8զm]JLm6\i*]ub%2e(e?_T4[iڧo-ybD 3OĿAquZ1ޔDY AalxN*m] NRu %߹6Q">L_ҐW7κtZQ fx`0HzbWo.(;Tm-d- Y޳&mJԅh{ZXUMC Ij'Ǵ3J4|\ʅ8-\C wtHW::AV9=fᆹ7&![bny*udՀ-|~~Bi׬I&Ԁ%b4p&chö7,C'_^S,QhΏ0޴ܝ; R 3f1P܀U/7~tmd{\|qĢuѪ (\)ՖmմJ5}]=YUNxa?p@ Gcrr8UU!/ν5^Z?86@DnO3|,BGX̛׏W$y䄜ɨ$ D&>wh`=s9OWkxPI ʆ]"[{_oEej<>Ꞧ&eW4seqWE8Yiluӄ߮Mp-dHBQ%w;li\rNv FwK<)+8򜑎@ѐ%]$8yTdY+F6)L҃=jumzSY' hX;lQcݝ@)SJ~c-IJ4!j,yok 8X⑥ "vrG!T`Kn5tT*jbbv<y S0NP֒$@\U{G))x4g<`߄V棥=Z;reY] HM:c>JZN.ptsUz=odp5k+$TO% Mh7)X/3M^nRq[v(6MeW?4T~ˑ}ƷʣUNWf5Dʝ-kUBˁt G8'xlC+ULh8YWVtol+8M/{^Fo7h!]+*V(װ1ڷg`+ PbjY,ҬR,( w,DzZe"a#rte g4Qמˉogg7UuM/^lRjz MZD;P#׸qxiq&e"RfhLT6Sg/LYѭF~}67V)h,T@8s:c\O#~Rѿ[ ˨^ kbVy6CգjrxJxxkTZnԲԋ;ڃJBxA!T+{ GZnr@F̐r 3 B׍(B;.o^'f#1AȨFh׈"R/sk_I]t%Qir{Z5:J}R|]sh7h u # J2wZH<0 ~N* ٗk$0%x=b)ܘT|Wm%v{̹/ơWj:͝P١h!ا}?֎/ R*s, 7 v_-0{Kҟtc=#[llb{^Rs-"1P PIeM u].{ڻ﹛y*tm#UM~pg&X)Gm$3mX UkO?P=ĶdvE +6;mY40]*n &J1>ZMY{ i4ӈЉTJ ;JNwx'xĴaa2T|(#Y `xyOLvj+7H՚ x"˴Ρ;n_U-R+ L㣃TNDU*.$a>4@q),yc>xe{l~#^ܠ0k%2n,3 8Pz ĝc{i-Ib;YLemʒԑ<I,#yqY}.=z$ص׶})LQ3+ (ꎚ1uIJe\[ڱEshp/2o6fGl9Y|n# [_߲RDZ_WtnT~t鷊n@"t R+Lأ/9LxcZIDа+5?;'b0Zd6j8]5 c)' {GX1xrMl J0i :7W_QD(^`Tp}R•f8wSp(QTc ڍC.^܅;h.~5z`Z#u%iQOO&~"vZ28=fM|n%RV:?uFWi4(0ށKBSo:5ēe#2N:ܯW"&գb_ߚ^QVNbVKW^~|2G:Ooj+ -s@kWW¨b:8pҞh@3L&3tTVi#!ydZ RpgGM`BTݎD1p-,˴"B0S G[q"~z^A"2ڰ S;i CRc#}ӯlq'$$xͯ4h,|\!ťuhx9,ně0Hj:u3h^VąY|b ^p''Da_~|ޔoÅlI}ڮx pHxf(p+sX?)GŶ&s72G+MNW@v~]:Rx 5V|$:$O[M՘މ!=1,b]̋M:=:B6S(r8.КYDetwKT@6@V6ozg@)ې퓥{Ro?MHbft9*1HmL(єZXX?0 laNjEOe m.܀Kzl ua'E Ӻ GLH_eF $ED oEJ'h$(f[)qﲯz ]K¤'tk,]D9<]WI#ыI97CcKqJTG,fl00QҮI/DVR=MOKTe4Tt# SW n4;$ɖM8E 9@O>6EgXpJM f #^ -oδSsv,SwB=n("A i@#>,S]C3uEw]c e*{Dg+S帱;Jmɿ@o @SktĞ(4*'i[ 7>$W©@S G5!fg"6Ake3Ob&V0#0b <E-F,)LLN2@z/ xYJl*|?M#d<N,.?]FTwgGɍkxf14;mN9.zi(rmt/y-;WOyA8ٲ2MAKǧ|3S,z: xbE7Q"$s}Y1xP ֘-r9aVSwD"Лown az1o%vS-V1-6ȁ$7:DWqθWjֻ& f"8:UistbKlƼ:~ _YPiRݦ_sp=GRN ڀ܇<쮽w*Xn;R{-)L2M!elu (I$~.$)L,45hfZ*?(c"Y`XsKF&bU~c(Dk!Ĥ kde[bh]g0/q!ȇ9|VCB7V0/>{Ulr 7MA?؁+|s7r#SF .pKbjފ!:kث"$k:qjbiƩ'l` %VR{e#1ZP8aP܊ܥDTǍTq{7l`Goǽ֞5\RÑ5ap9T{af8Y) TRyƿd&BcY+]Q=: {u.Arv?-zDd;f >ޡtzPC*s F"45qCB!5 "=c-D yW}j%%10_dNq d9R D_˘P"'nyM,U\w" *`[F~6ٿ6^gpv5pWY!j蠀yZ 7VpdA+~_"ȞN6QO ^>ihGQ2fa0*wՉgI= & Y$pybVL=xUđfًi#C'XZ eAihNopg(j@>. + _;uV]X(I0q'g" xpOywȔT:gH{XxL)7K4}nݬђqW.4#ƀ{{ww׊r–K#z= N2.w&æ&]mbn RC̜{*b7߲J|_@a͋3R^ukر ŸRB _vh_[ǘ@s=W[U1E,|܉RIokҞCW$wRNSM>܉EInX";s-\ZLй>zl$ ^>TSHTn~4t0za_s [TՍK_G{dNBFGj-ZIS#aETkjK)4~` q81;`f}zcz9wx8eC5½ư&dD&ú 66 EMH+Hf/\a hݽg(\~fqn7y1r"D@6FSP![j+qx 9/:q uW 1$$nz]q I!u|7ZLKb %Vt*3ѣ}o1zbFxq ߟVzWPj*ⰺV9j3qw2{[ˢ h=2'i`_ǵMB?#jrHӓ<$YP )#^Z!Qd^~g?Tê#YĂpY#K ,ŭOˆ8d ֌-Am!yլ>l-K>!ubrw2<;$&)<;l9}yY*_I^^1ϮZ/ }`X$8Kp %9}HN3Өc;e,#_ rW!LΉ0-dʁ\@+ bN߹ȩ7^p&FeO1,X3\hk8E)ŽKeB- y}Z#0(0D'fm8%~/I5N'@]~V: ˞ݸ&n%f)m*ûyNJ~.ds + Ɏ18\6zҦ ֠<7 2}M Sa(Ys*Y:6eܖv4=sHa $DE-"4x+^,v 1'+}osѥp\RU7'@Y5Ɔz$$7dAE~r1F(&p87eߐcAT,.9d/tzS# a^?S0=bi10W@27.|e,?!!A[k\Ca$;s!ЊڍQ,KY; Œ0}E|A[V6"D(%R#gFlȝ,W'Fo`˪ZN (>H_?fiu'`-IUH#c'`d=m0qE348A﷾mzMM>v9;qI+Y2Z=Ce/N1Fע#M%[nWQ$4>Z4ݛV)W.WɆͳObqq5tKwmrZ [K^~:#cQUZyqLj66Q~EސKҟ o:L0."@Hlh">'4smUizIhXf)˨ _%qYMUT/t䅴~b5PU?} [*ieu\1ٴ|I|,a8ſ~NoqyHewUuY] l=O;LZU:ÄJ^M豓8j0_ʎ/UΆ? І Osώzf̩턕:{!_ƈp'1$#?@VFESG>915׀ 9]ҠpsgS9AJs0⺉0p7Ob̻r+ۦqDO!#j=quvDu}Ӊxw/wdO9wX/aϛLu(Vrʻl5, ,ߚ:n枳@"zЊԑ>_--2# fv$?wq}]EYЧDE7J #zyWzpQ` 50:fwa6(7ŗmU%"T񟺗j1cv{ʹS6!S|d>#{m'R%߻ͱbdtIѲO,)]C&"Ewn"Mr1gWXL.°7~9*;-GD|~)۽[ `$o//+6^F8Pj Cˀϫ{pqjQkAYm z|#Lr`X-PR pv) 3É3,TdmnSgv:cJ9S|f0J;6poPs;R}!G \"V ?ew)b.&lo>ifQ^}F"xdNy}22qc艌B!v%xhE."]5hiå&4' fM"0$'mBR5:B "*|L(^7Q:0 {n0@cu]4<[|ze.4P_ I_>f)0hE!=3=8Ol<<+@c dT8n(Z7,Ap@@1)qv-% IFvOjXXq!ՊwcmPhyھaM Mm7Rs|T(|Q"Rܥ9 mX +ޅ޲Yk!>}DfC=q%ɪ}bϞ2jJf'#izU;zzچ~w\9_߆.lǙK&L=rkK\-Q@_߳_&SLn }MZÏXz SCƸҹnp9v 7/!$l \khjҶ8F>8\x}򁀎kH+RHCHx1"S 9CD;SmpEdX>zZ_J=>湀M0>cݦ FخjX{p%X7X7W،E\ eD,HD 2^3^ioJM:sK6݈92 Z-|HTLx!\o-7tѻw։3ү+GkkKP>Ύ ߧ >`9Y{PG@$z!rUq{lak~w.ȼȞDuSeȊTTc=ŐתĶS.cQyZmn~%Ƈa1jj#ǑgE4Mp*Ǹga kWaO4QlQT{_XT&:”x̀I?84HWxH OUi BBd9EY:rMN(x=nI G*=.~7?X ~~7AՊV`l>%ocI%aJ}mE]1j¹i|4>2[mD13[a XѶt>Er.2`ْ[*O`ot͖Xw{'21=5AGd:aNn>Kxq $K,;>EY@!, }ч[=0S5U8k(SfΚ&/:֩O +Y1[mp4 :h샋dVSk"w| '7~+lM k?T0!AK@k6.sӘCiˎxQ ձgd ?|PO y$ ,9ӯ[f;Z:<L@Lt*UȻ8>^LE.E4ƢqeZM볦#9lV(L-t$ UcJ!s$-$^0c}Tm ZG]=AO̱^8@KDȋY|`F5tvİlw*7zkxIަrpO+/($o[5a)L_=U prW!l&जH,I,>&\Ek,*nuִ) 0(@1t*Zn6 7/[\"í<^44ԵI|½/C!ѧH-0ꁲVz^j!zP Cŗ)Q87x9Ղ2(ҹ|nZA%E9w,QJv'wܪ=<۫Q?F<}A6^m9A06D!衞D\D73px|-;Mψ@ *R29汊u\57XА׏2%!נ8z UJ+W[UhdQ<[QEL(((AlSҴ~V8>;agG~kN&]SdJLv:+aˢ6aIăގ+b*Zw/}K_ ݟڶm/uǢ9-6(d[F>Zʃ(Bozd3ymry1Ķq\XRz,T|w7Ec-x$;G?Q;h;rS@^OWJL=ؚ+1(\}m\9戊 #}cg\-^&nN uA<KyO ŬÚ&kh&nQ -|@ ~E!>nB2eHxмAo3)djBʜ0&yv*Z06i)JM͍[HNI14?ӂ04mRa^6//⠨^@?mw@/MoEGSY"TFo:M$ 5|iSr\F3/yK֯4O:yT9y*XMP&lFp@||9Aݚ]u'Qe7VK~5o1{ Sd]Nvd6íʬؠ":~_h'!Fj܌l>H /&rqCE&jpv[j//}Zb4ʋΙ8EL`~q-hۺ \O1Cn"=b J$1C,z8.DeA{tU[A'NUk{LlX#_-LTlr{8?c*ݻx# 9T|}W4X d%%0PxC& majW9j>s}YY w)E 7(<89!.Q:JUnBT3P{@cuwe~f1>Ʀ;'Op>a/R:~5 4v| |E$Bd?P Xn.o=\_)X%x^88)U1GP> >_:z{شPn9u"F[aGAc QI,@{{t4Q{1 GQ+3F"L4@05$EChE1r 3["\_94L`_kLB~4-{m# 1]$DR?)h^e<`@Ny|teO5R5My 04t m{ U+BWXKi MMGkОCCż( ZY7D<2,y(`}KF=0Ӧ~OcR 45|Ci80x^WmvCGDvwǙ>ah0/_":5nY!D(wZ=Es$UpRt`[./JٮaEAВaV˄e&  z%-jQg{7VNʂw6SR%s#-],ZIo0}6X 9 2*XN.SCxKbqq\Q اAhZX1` a8zvn@[::Ɛ[P 5T7=5nZ9;RJIG/W9b9sL wN~+6AP]!%-5m̦ĝ 86B7t] G["PҾW}(0[ b/W*?< |KSvM+ 'xl$d_T6m`hj0b+ c\= ;Ko{ ?W;AQ)AO9Ĵ*)y$Ӓ;/!wH/n',{)Pi-߆%Sq)gJsGǍ,hXy4G C\&kpTbx_GܗEi{w41ڶ6־-1RZYhǗ ~v8&?ruysHY)&$h燸^lwd* ¿=~qMX5k@Wye|uWzeOw+Ը,39Xt7E&m\{ҏ4ih ]c=6>Kp¨ ]#eA:g3+geoQXr3F?Ѣtu6yIw sMk"kƂqhAHvp/|%z%bn"#C?8j5&и9'Z=Ȫ"T(}ߴ73}j 򁂋ػwS̏Z ZnnC3;F u22AaM~$y E[M&N)튬SgH.o)efZvuX}>2nWa^.D]&Q VLp4p!sP(u=>(3^̮@\xJӤ {։ jE-$.5,mNW{B,; NX uST=)Nb|{=i-۔jҔXqTbɥ9E}vF>X: cSS 9PzQc[{!~WCt=iֹXDAħ䍽6S;GRu :4=aI7!i#_;TY2p1l~jl/xf^/atpKiӢhܼ6{54}p.wFܑ-;zdXыGvu} $k/rjh)JO` TV34eοAop8 3×w$8ꘒ$ HkݏjKo+`*#`O~n& %cAM:+ρ;Z77\ƀSϧ`X9S=+4RY;Pզe{<g sT3z?Fqe}piY9JLE.w R WW=*x%5dz6Ƈe8CPٸzB ~܂Qk&E K"uW E}vVWV^ qPu7nL{ c*7j'U' g-Tt"gu~@3K +3m>kb1l! Y/RTz5DY4R.8x#p^J2s.>dNp/q?CÉh+]RT!S_$㪏ld xw8q^!MqPf54jRȶ\XɫLW |"0!ߟ}JԞR[l %бrghecd!A Y-!xzGgƸגtpVmʳ^j#30Zlt8RlEnD1| &WT)Ǥ$-B'*> WN6u2QV:)fHt$26@:UrhH P#PzL|3d@oR'া({NzQkV##PIٚg2wb6l*0M/ăe(crve3M*\B 5c^#n.UЌ<0uzpx> RM G r-)UU / `]SK=?vt+*0sS1Z2oTObs5rayV}}dfYp}KFШ#Mq64x -Ю,zRDjoIB3jkj } *;BּV"-hIjBIDrxXkYŚ5k҅N \:Lt |o[?f6ca}rB60]PqAKmF uɄq \x|I,n M2"}y`4Y0s/Ft tRp]1r4ѰWZHf:zⷡY8LoU: pq|So ˟͓ǐv(p;=àx8'YLk"3\ۀfw*Y$3׆.8q`CXS=c}&Kz0=1 $1 4?k<9mt{ ' 2'B1PW.)gFEV{T: ARY[H? Dvh|<Jڠ_hA)l !)k$PkNaK;Mg%\ÿ)֘ǽBjI0( yZ9\Q\eYMW{w$]4{k:j1AuZD#ΪrӐkֹad~g9mJB= g86\-;J9R cmԘp:;HSNqbߡ-G*KjϪs)464 7$3?w(VYȊc3 1kO݄Ao;ĉfx`&yr@DlOo-E0'56YݦAYL| \9DIcޡ+3k*$h oVo]!,l%WEhHF0i ^G|_Š# ~Ck,G WOI@JZ/ChXLO=ŗF&zyjaE"[|ti!TM!4(zX x 5ê+A\1sbWgqY*(3jc4|þ$ILMD1.YWeBZut] q0<yL7Xп2=v)VI€Uղ1gGa9{PC0` cv 8K1JN7IQS{ tV(ٱ> 9~;hހgE`(AFd΍3ʟ,VGk*ID3ؚa +JL'3vmYy7w*RˏԮ61K}Me.ßU!ɻI?3~*o݌5Q?OĆ(]P2}{&5;=!U1̹cљyf^V hZ?eOJ!l-̲Awҩ hqKgre{5%30x7ͤ̅ᨆXsX;qY%K)4CGLBو `:7iI?CƂ(KCt8PӉ;`!uF;w3 ehlI%> ĭ `a?}x>ATUE,ghѯb[h8Yk$`d5J"L#&^aZ?*TU05 w9z ybЅt* ?tzނ-zyKshI  λyh]Ad xPRK9e#: HU~/aF&RWS魹aoYD:WuTfkuL$z%e2 F/7$KC;kv{zFsê_9\W yrɠ1%ػWm23$)9;& BU.&(vV¢! Ɠ3H2Ϣ njaEGdyh|f(.$d5kF|},[2-dT5s!jֳ]f)8D%!ԤrjzE瘢0vYe:*hϡ=#xnLӠeK0pO~$Q+i'4#hCZj.!tf1*41ƈ|$<_Y<Xgh{[hxkPy`tj%p~F4fbogX !6Xh_g8Re)tH=;} (&GnPa;NvሯwP|~sUd`i1pI K +q-ڏ2p{V(w ,qB1aݠ& f?p*O?6dVl?^YQW:ݟTȟqqz X[L1bjR8nEP)a2͸72U݃v\ԓ^LnDi/TaA1eXg% En HD9F{su{T=Y 7jBNX3/099*T C5] $A,FH9!G ǐY! ,sDgzوW?JmZ'ص6(t"hW1|i*UȂ[A%Ѩ_,nh~o*GZhi0T qY\44,ģLSL@v4rBׇwa 05;ǕC ʽ#ndW+~|\ :\ߥ)EPt'q!z܅%.GCE2_EbĎ#Ѡ 4҉ \f~?/կSi"Q8G9 ((h@;:J%]`[\PxE*Rٳt,#cdb{K*E쓰vn~@+4̱CuSQGY%a߭|T` >Kl_b;B+Zyzp#K-ܙJ&FR@C=%OW2}f?7_RPedZme ΝC^yE[jD,)-?I/āTgsܤbX7 +-.0TV?fsbNÒl"hzQY }GZO$ P}3r V@4 85AjijVr/Ia*T~~wΫY5^ƧO*K5J0C}(oHysxHO +ւ*@8hZP4xŎjSxk@o[Α*WhJ# +3?Jwb-.\ʍ^_>w>ZIi;pʪ69G_4Tg<"g`[9c.1*`?ɜ2|p,#\)Rv#h wgDJϞ ZNIg=Ua!O>~09wO|H毜at4Rx<' w]l(^ z._~ac./4[Ge-ّ9c$y^2R W3WF*]Y Uez/sʨ(ޏzŠSlwZoGF"XLZ %˗A_V5|'XV~M7X)hpZ#ojȱl* ?hHe//㐣  la fjYH^,* x!sn|^(xԸ]6 js"CץsM-K#n#B, D"LlUgPdiKZɰ ?&R]nm^ŸM^n:)ladd;0=e@{12I=cCPhmQ!y"Q%i"0PS)@$dϺc"I QA03 Y$&ngkzi3+n6#b]ϛ(Ak4[NW_wl:}A:ʫ pL3ߤyjܞG_Jq-|M1]?q\Ĺ0H̷=@?M ocl83Zĸ;Z;~9Fi} _{^j{ڳT||kz 3*PXVCd剶qpv~-/bڝgLx`þ|?azs4[dK@ %Ed dB/H8'!jc (L*",ߦ x5B)4Sͷ*|_Ne eQTH/.X,vDcA€,pߓ? 91DDPi*Āf\$Z/^Mī@={ uBUIoLC JV hkX"\_Ky$BKğ)`*7 dԮ+W|`}+PMH|`"K=c{oKjK") ]Fu(HPb$,kMOz-%w'fa<:ԇ>ً(DpS^:t`V=]wƲ&?E| y3CȪr(;A/0,,/5ԥN>C꺙śJ6By:R5._J ck~~ЉuMt5`-rf` i} -͔Q{g`MDAѲ,٣DPЉ'cӚxо"9^>ہXwAHʮ ~*p-bx!B(@tͳ|paSÐhcg aptj9NZje3O}ěR%{ =Ѯ 25%OXqߌRe{S//",\Qmn}wsD3&]ٷ1y婬A;M;a5:︬f-\oHd_ԣ]$cD׸L<Dk_e)1]\͓G؛y|G3#gc3)Q&M\%nJqC DȜ@9LHshާo_@S1)١|TMX5.vfP Ue" a[lR>* 00YŒ7z+vX'rǃNB6 a|DOjǢՊ N:lR3ҿ͉-`9<33t[8`jq%3=BpM (OD8Z5dg=x^݇,n遆v5 :a?ahuR ڼ:;_X} <貥aٲJ̖T)&cDK[E4zzǧ6= ,EE,tJ[),%KLJK^oQR6TR7a'^0#>GFϳ!l޺"ӐMMtc-`Wl4ȣ}AQ: l}xNkMJv{MY7r#BlM/y>$KBEqk&^lpY 7{co6 Lf+@Dbѥf˂j>e\tT%p{.ULoX0E&R @vP6bn2p[ 4'wDip~c8}n/ԨNiv +oX#HY<SBx@( tmHG 3/3@xdC0^o2;HL/o,Ŵl$sV6J=&qm'*uJdz}t2ђP7w(u;D(CZ-We`M:܍n$8alshCNO9%D\s ~ȲK.*w_޹b-v<HuĴ\V|6U# r L:a5?~*z45oA笊FbR{1IgnҍG}VbāP/w^!>L"_55fdžy'2TBݣDI'!l~֘=ypgéKpG'|pOl/2 ئ}q mKuOhPl70a cMZs*+H^P6<6-d[0Fa9vD3HJknwGһbPQDsMRXD>b{LHU7>j̻rr̟4Qs&J~y;l+7-- qF2r58B A:޿׹c oxqb'(yW?GΩY|W4hMZ]rAK X]V^r VP"OSyJ6KqSsLtACTlA5ԩK ,Pֲ!酊 GB'YkCh&WnԖ~: ixKuG0ONi%b/B>6:=3| y-sz x+=m!D Ȁ̦tE8/ӻ8aspݎV}K=Ḻn\=_ G"!pM Pv΁oiU2sG=j<~}YgiiB8{c#XEpSPDJ{C3ɒ8#Avc*N%p0- #S uUkܝy`gxFe7y![\Vҏ&w :dfKDvmWTy's6D :8$y#3Ya mA5ST]fɴ9Á&?r(5dCbRk\6?fq2p*\ldT8 9ڃYmP )rEYmhZCȤNH3R.DC bgqQ!heRa,}J1]T}F] #s\a {/Fwy>4Co_v)ĶU<>GT/FZՄ*`aG(Xи>.=`]-O!'WQAmF.a `\]pn _( f%U$] xhRb1ZVͲJiT1bIg%z#w;IȔ6u%2*`BAwf ݏ_G _@·O-%) 1_Z5{X~: ola2{æ ]Rp P2NT:̮BV7 1OX?4XWMN,5u!WTğZ&Q՘o1í xyz-M=s&8KXNDж8 4K}^Zs8y"⺤șW3j!{/ԍi[&TlRgIVM̈́*&8ɀ'߆Ge0dQjfPY<(Gh jZgXG*7k0ӼxJG_gߗuD}~xz&*rFem+K_SPKAո~.hHZ@ Ciі?dI Gd5S8>1̠zrݙAMS1 nw9O-@J)gG|G>0Ù;U@8׊ cC%aR8/R_6:plt`O_xs29H 0f٭ozz(A4I3.A|F/DWO$Qln^,`PLHJ[ }SJ؍o=2}x_I?x\M#U%&' "}Nz) ?( 34?>'쾜嘼L,qUdҥxc7Չ2U%sX!}}!FhzxN;xI𔽋jQ- 1+ٽ>BwrXKqNK`sv Oh*,H\ݷ>ЉE9Vr`[$*H4qdv&(-xEFpA_@R9uz1޼,B%`1[#CZ`g-QeYz0وgb%6жKMepF^3cSXrH쮌`6u)2KŊ1.4Wu2%ͲzxzTD y Ll%z<_c t5/t!.jPLB͇mR9QzCT 1(,Xf]{:2hQ) ڢNWo(8wҶk,_ .DMl ?(-ʹZwG`\M{kĒmBE96VCj9'`"0E8qkXLOJ7MD3,8e--%'q ]j͠'!< N=`k ?D3XOrϵPf+J0IyfsvYsc'Ug<ڎ|B1J.s Ћ<f "^iP9ߑ>8 qIJ!|4qg3Em)=dgʍa9עsB^qbj A!] hWO,n^^n-dJsXwa|1%w}D! Ȅ0~BuB4D3ߛҹFȡ6m>bN.!C_礦 RFi@E2t&i7hԢiAmpB;w!&T/5PΨLkn\- v 3݇XsC2XZŽZ*)zeW(1H[yϑu8!C{܍7&9G35z c&%u<ʿWMH޳ςbiwiVp>{KLO&s[ttQVƸ`O5=G]w&`J$ۉNŎR/Riû^ugQn7iN-m2Fagql4*J~eY[ qLf|/g P!W4JWo9b V;0pu~&S8H K'k3g-萛ݙՙ?antsFB7ǴCIV # :FӅusN/t*,ou6hg#{s?0vDy[:"IA.l'. س!?@ e l@\PNKSBffGj _ٓ3D!߯Lqt<5dRb#)ٛl{/6ck.S|#Y 6c]IιFˌ;%+B'*#O{fC)OjcbDv7'1WA6jLlz4oy hBѹ_gYJbNR8h`GU(8xrmZnFkiJI3E'Ĝ*hN5y^Y%0S5.C]}\.Q#l&vնW!}_F̰-8hQX%tD*ԁR)f1ےآN|xg t|34*kݽm] &"W"Z;ua$"" }ClQwԇSbkEΨTkm}ऱ0ͽFׅ?NF#a0 E: Qs]`/ HC\YyHrC6%=wCi6YD.QJMgуFMd_h-ӳȂ!  p0$Q r35i$O𲱒㫍 Pp4e/tU!Ū}VIhff. f7:8St_L~bCx.b{ٴ{ӹlۺo9-MYs^)XbJIEeYA2FFa n*BE-;ny!GWF|I{ݘ>i]zon%3'u`R*f{'<oCDEx $gž8,ɢ"q2>c7WCN(MC\,kW8GS( 'A,!kin+]d/t&d;@R+C/p>E2Q{pN%P N/UaC6OKizJq.YԖJ۾[z{:U) 6/_:*:GĻvۿG HvE'nA~Í޳ (>"Kc_$)gG%4mO:H!Tf+F%~>5 (X2i9*`-L6}ˍ|@1)hqfWly+ՏTR\kFAߕ~cu7>q5))2Iq3Zœ`uQO/w* %mp2s-pif`vϘn3#̍|2Zݫ3Vd4!|4҄{93͌@e@vVQ3uo0{0qLR3I"<ӟlR.h]``)=06Õ, ru4.l0{.zyEeVtl)Km=i2&MYz"cPtc^Qf{w{ݯVw"rOhi6ޓB8ĩF6gAoVOM+*r2NgX1(hq{.V赤St6=2㏖QB|5xC2a書`iRYm(0g5">g2x<~V5]|Θ?=3pRI7x2UÒGTTHAkXv (@4 27l*p-~x+$݋YAmB '\=T9E_GM r $ `^ HQ#]_ hcsI]`ɠUHpEiUj ho 75+@+]i:y^RW-'읊w^*5CI!K3Q5:yhG p˙C?W LÔfl[b(*Cd5@0kCzCs^aIǛ냷&,kfjEYDYeWL^27)[xˈ? 2;1UUM㾎x~@m (J׀O˜)VTy`2ESDY |+vb! =q_WD}p3]<jIgG?ZѣbjT٢;Aw݁쯿)e;_(o͵1nbGe]m m\k2c+E!<<iT$Ũ=cUnuaN\ Đ0?kb!^Uq--dLX+(wMJXGqAff nqǵla`O@*~fώ/L!:Dsqr퇤.ƽSo-C1׶'w'⅒J&6:u;W[nns u<z,}r Ur)8C*lzcUr1Jr(Qݽ[$KY,HS@9N&'~A'WY5p9ƙp I3~-Iǵ2镇7$ۭUg~R< f[Spl67IF^f*7q>g6WJ0w#rKe/2whn[Cy8PuTRE$ owG8wz3OUkb]tP528섗ZwZVY\>;4%cW#NRGq$ (" mΛ@rg-9nX5L1NOA#o+p sNx5Bꤶ}5Eyݧ,Ns[Lݏ}&6% =T5PDc&XXVRӯ'_d5e`$5f^DK^N]rhhZ* 'y h \^ 2K Zڨ34ϸ51 dj3sW:OoDk<]3]QOFd# Ppp~uI0 Gͪj9>֠Ş.n23. ,fE8E>w\n`&!Yj#~Է\qgh[Qj= }o2~@~`sqbolj;+ZUl^O3pO偞ܯy;K>-TE,["TX$ҟqFlA `jxs@a&̦O̫Fʞ5 !h^ gۥAL;&7I37<}sY_0:, h#h,T[ UA^Ȧ!L>xݎj /)dT@я΋m{7ܾGb}~jAzէo*#N!hWޑ BL|d'Yo!L\/lHacHQD`4g)ewtbs_JtÎ}KW~}*\$'ṿUЕw; iccwbsb9D|R(2h&#QB*?b5o/ s Bj,N |{baHBvk %8W yeY.s8 N˺v7p$V\I^v'y\yּ)ya`FҪ+T?|¼s.y'=8TBuҙ{j*9#*Wy۠;Y,jލ*cPPJZ7P&Y*Un[Cefyf;.nl( ug#?_am`^[Uăf]<лP;(^ rPXy: !sǺBMK8!l8ce2ɪD~NΜ@PXJ$Fbvq%pI.) 3Bv]qѭ8j`G`6nu F1y%ߚ$uOxoug 5$'w~ewpF6ʨ:Ȕ F>}Z'T[kY4Sלh1 b@Fw(W]:[/#;sߩ(b&-,UeV0's(vھ=u޵m"u1J'V~N5n @E+ R|RlpT*_rȬ'4̙Orj.O-bnm-wkdCvENmROsYʀ [﹪`/ԕay(;gE6}v؋fc{?[7Gy_qO0dI=*-S)dw~Y5G:8YrU$fxOQ֑g88 NI * a/=eͯgo^l6krĝ~SN10zTS/Lf%\R~ÞXD|keiy/CP}gM ԝbܵ;,7ӹ ,o5Q@yE<D_{ԿBOIt&?׏}"Ua{$zVU,맸%ɀ;omy (い?ebaa t0Yz&tfE1#jƹ@gqGvltcl.ꄇw5]D?tbVK aM눟o 4,b+SC"&SC~MS5ƫwUUNaf m>@QnҎh+ ƫ",|Ƃ_cMJu+0&=AanԫK8m?ivqSyWKiP$#YU3HFq=5h,Wu:*/͐'5 "cwJ %281]{٬eu4D0wwC49s5<< q[d(SF "btG`EB46L4 ϥ-a^kegZ#Fy~C#WZpXzt  mR0\xx,{֮ %}lg1#G0#{Hڸm&H] f`Y $t"(a?P'CaA?`fwF[p%k(%h>*GI.AE|!D!vFr_BbmPp>w5sPLy<,l chB&j'L5pk^挶Ƨ(F,ejgSR&.-Uue4IЯט}d>GGl6 ܌k l'jGm\`,9Gͩ>O iGbQnfVʃ%Ȳ2H)!ngV:XN6L152p^Vַ! -u=2v*3/u7ziU+9밥t|3촥^yËM&3-6Ov- FDE SK$$dmGܖ@G@~,f0 j9sY*cfC3;UDž.tvYYJUX=-'vdڌʀRT7A =T)w;d25]y48n Qm\Ȃv00͐S~t@bFlQy4(UXic{Q%sQh odr;8|HgJqɲMRX mϡE\~go*w;89*O0ÑӮe$%oT(-hmHRQh;NjHNN Q b[WoOSq.\5GOnݸ,L3Zz>?|QF82D7UWc6u {U/7?e\"њq\$`|Sn'6F1u^Q+m64u9 GdѰrh%Isk*bM cVVw = FBrI\Y[2dl* ]& ѸDJm|\rocEYnn9( xnnQ+vXsGJ(ѻx'4S ?6_/apRYŁ7HQՁ, ۪&F?e!zhq<&~WW=T8Er婜!Ӂ N~e=eET4*a / (&+"SUq]4^Mktf~@ݧf[uNR<⩨vd3W7H ktCf?l֜lP5&qC0]YeL4O]U ]~w4-~w[YS㫫bN/[/Kq% uC jD`e6ntHt]NrhnMUXmm 1-}_ _<-vno ,Y 6ρZĮCXBeԢԩǬf04 M/|5Yk4DKH\$a2a #fw袆 [Qqłuքbl"}јbH%ڽɈbnn7͂v ygOaON֫$ڄ4JZ2 9wYk6^a-{{BV5rzh ճмmms0)P~q6iUa^yN -c8z4Ri5܁',W3V(KJ9M܇lW6';-Ѧ.I}? 436裤C[|՗r bkeO%18Ucm2ZRuth/TDxoͶvq ި3*G)!Tϻ F֖/7S5`bap`2o*a8ؠW/.xm.OM VPF;;{+نw+e̫{7kg|ݗj[;}ydO}(2UF"Id'P ަR/؟8yYѿDWi܅H{[![bF?5˾mq V(Mk@#䔌cJfk4VH 9#I,%VU-lk !C [U ƠYHe&Oa ~ʁpx>"`k&ñr:Nsb/fg>Ng[GQC}|+3ZcWHH)N27pˁY2|ϛF5¹Sn׋uڲMzK% qxpX%O>{鿩i23<A몱/@ 3֛!틴;Ucq=w)d${ib4aY+sAa dq.=zC/瀠l˼®n0M*̄q{ HLLT|sa)ơnv_4Yb\uwZ9= y1V Θ )!,З@+]1WddÅa("MȆ$sHA/|@PD+zmfz&RM{jZ-O%mDӍqJ/妒꫁hbu%NJՊ~莾Wrd$9lzVy!㤸5*Iw^XJVSUݰ&P5՜iqQ2|a~ZK{dz7; (U  )ݟA&-:H*{Y4D%iD;I) :1lYbǐ:_c@Iz#plC(ߝzq~*oZ[*"M:xy`prMkOSR ^cɧGALj FfNZgލBh'iO-ck'>!@Ϩ&kX0Qs :rQGD$B_=iK*GW>ZVV1om`"p K<YTz6dQ,|F--+ja]7>$펟e PȡSbo[n_Rx(=׼Z$[XLo$98d- [HZlQf]gtk+$'\!9 /odX,HMoN>T~?VͺfkO4VF`fX*8oJ]M(Awﱄֿ/048LꝌ +IIViRʚ+uE~A/ԹըgunjR<~xȠX"xXqVXip*ChZhؕa0e]=/gVLtE0jA{Q2)pRچ.!1|gb FKz VV pH !VI(jޙV62X2}ɑ2x|XՐ.&d_ZNٚzt7|w΅9* s Ed_G>fvZ~FR;}0ϽJ=}cHZ̈́o谇q|YlVWZ'b'T3PI~As?= I bHW0=rڂ[쒓 A~·ko?*w$Zp"dz@AoYۼ2Œiwx6RQ>ݍoaҢ% Hd5sp|b%Hg]Dz8`C .W":(rVG} k(6nOD(h8@BGs0N^e"䇉(U>.@hm[iQ[._ND t~Ap2axQR]On9ܭS"7hZq@ Klr<=[aQ{!|]tSA2W?5,-"b4ǣ<%cr̀zc g2>fy0L"SőR*ZHԎXN$ft=jק Qg`NIv@UT~WڢR!gy : }}u׫۷.? &=Vb/{2D9Nՠ<mz;A#\cdKRe@g`4t"GgKJ\!`gcwx}a]\\K6OLv4SOEVU3ka#ꌝd0~Jqy ( S>UÞª$e[)I蕀V`Ht\K nU 0v1iX +VVBݽk[jK3zf_'qo`vx@"'JyVoqQSB`a\ ַT짥ݼa"%_ę/AʐJvu#9,/L/\BfWF+`3͢kI'T~~A;gscXQZhtK]#cވΒ"Si7M s(\Ga?Ʊv8 ȲEݕ}UzuO0Ratҩ.]\쀵vh)lި AP~HqJ<¬gKWg. 7/C'Cdk^8B 0n%Gpŕ~Ê;U:Xc6%]UjITw…K$cGamꁉ1>"D8`O7fh*ROޕFAeo\'螁Mе}=’ԋ~Fl-魿Q"JPf3~!FR19'xdC+_*A#)I+Ism6E6K7rtU\@#GcnNwYH9'^ BS?^hEQ`αpAtH[l>K 0lYinOP>KcS N\ S QX#@cqV٪稾d&_Fl u;kFˬns(cY[i>wѩP/ERABBh5f5== d)g -J)fJ}ur?{jmd&`UWɁMJNxVi!80uުNc +}̴}n7uNG^ݚ-uYC_3wBԴNT|\h7q9~_,q!@'zə /M+VUo'jTo+q`}#^1poi̜>L@zmɷ<"KCl.*l A\ߦ wU}qn8U1ͦ,24ȳ~Q# g݅\{S}7mfd .㉍@+ #6-9`,|$˹T?${Hc^@g"~ 5)AN`b~v3 9aN"j+U+7FT%x+)ϟ~Eƒy S 9 IE4~&}٘'fϊv Z!hPlIja E6vD_Y>t?lԂdrtYӣ3@~SAپRZIggGD; xQ9%fĭ 4qPl)K?1:1ZBk鿏^@3%YQ\+eIԣ("VA!*j /JKpcǙykS !l}=V2A PD,N4ҒY0Oլ H &ii^Pc~oDؙZ 8\wmMMpٳ!^hnO7` ;!v8'QD3̦@)*wXe/J T?Oܭ[Rڨ;hɨ T%Jc H*] EJvTS4#{o~kGK;Eb=S*t$X"PG;Hk[n{I- [JVj,,4R7 uO(3au1K^ Ah)h(-˯|Գhv qϦ&T+ j*aiK8g'I L%?M՜V.WEfL&ӬBVSZ碱KHmLzۦ̛ƃo蒹(ЉyKu@x Vyyt*j_3ftN~@Epo]N+㹙jT"ӨcJ""'"68 M(~6ua5ŃL9DK&LgS2qTgȒ]PMMB &ba:^3ඁ>2eqW7/pr*H?pE9eO?fNfſN!VO pVdp [eAYP]{?N4@-JAj 9Hj2NDCn9>GD;a) ~;G[nx;WLgMd"!Бn6 9蔥Vz1@ "AG{3{_5Oq'Uӣ#w}+}.* tdIU*y޺D `Xb)fhbL9 \+<}ojْݫI}B^.6@{ z0^+شΌ!Ŵ_eÂ362>`.]6dkԹă%Q5q$C@{omד{W`GZ pB5v "dVFUL,Ob:%겿KQ& $:¼opC-3vzzVBVJ/mZ?!?64\'j&5L ״4=, ztœ<fu\)' zhn@\GFh|`Ftڄ{ JIS@ #5j 3VF1Q1zKʄ r&<)ڥX[,(ĬZd^3{V:D J_rD tv < pmڃto&`:^R|<<)z}%LU6v,x6dCJФ#.-(a@yRU`Դ4ݕ!eسš<87󲑖HN{e<вerf㝫˕_'5d8k/@gw@Y=>^N{'tWVI3SH-ۻ7+YO-  B亦3d!kKbrKG!?"]I (ΌdfݲK^V3jhs˅7+4Q؏ygz Zs-HSPܤ,ga!YJ7|=re-AD'T5oersȵd IT kTRQ< jSiԪY%/JF|[܉)wD<#v᧙D?Z&C9] In^IkzQy nat2$Ȧ6NN_5giC:*v_/urW>y='!vJ~o _[Z*$/>n;19̒+q)˞t%Nߎq+y+zuqhG0ˇ@A؀y!bhG, x_%4mcM]u\ ZeiӀ2"!yEoduVmݤJ};)U\s\1³a;6Kp &o5QG݋ܿ0L"b%gD`u>6-5$ 3{1xHXHS8+>s`a s'8PQVXIK^<)['ٹW &5~̵7F%q~Ƭ]{̄G?i"~2,7e]]¼XK9_)=z*Ff9jo|m.Z, j5pk;cz&Z6D#OzJԿ{F\xNgcRBɓ1{P^ˮN zF]*F6e*B%WPdlq?RSvLY0VIҾIB,%#`?2A hBsE|ؔ^Y.G5GV NL!`4JE]3uڤ?Gx#P(2XV~LߥJRɲ ֿu!_$UTWηz|:I"=[6!! =՟}a2s .][J3c 2/l$p8\v=zEJᆢ{<2xHKX?M ?-[+Ձ޳D:7seëM(i ZLd x{q|XWMG#T8rfۨ7`@rETN.'= pN*~#f77Igv "j]#_oeY'/?NZe9 M)j:t"H{}b=BBn\\D nk-;lFDF Sل7jS5^=e)qZ|[?/Y>pFў)U(BeD{QH :C 58<Ә}qs谡[ hu+)tA"GfL`P0m}N~Jy''o/,&,Hyeg!;bpꁻX tU޽?lWa & 7Лǝm$hj(-J5_;*!{ATs |z~գ|9 8'ۈ"97Kt7kt!Nm EKLW`NZrNguAj/RS }ۺDTލ_YU]_C`rxE+ DLnpZbie_Ky%{QlMTCYC" zq@vd8dZ =?8J*.leM]u=xd }YF 4f*ؾpe^Z06#N4?elJS{Bn@Q(?Za=;tgW7-JoVj;(\솯F!wCƳb?eXu8pc7oi7PC$/oC k4q;?ynSʠğߟ{D렂ge rۮ>貈#ah 1 J=5Eq6CrWw!f&?سJV@VVs϶iZ!-<34LNѸAz.Zfݻ\՜nB49 HT<;~i}evgCqG ㅳTI*+QG^M ՘< 6-|` ,spc>M?,tB=es(ys{! "U33tb+jJgG'@3uUQ=̡=ji5 $qV,DU{'L'n6(HtGS x*[oRDzԴk]7cS2@ۅ">a)ęZ_3}ʠuC>c-^bpH yD/uXƣew5=-97QL>K hL{r 7AXYU M&4S(IS9 < ~עPAZkp]{][A,u?+-.OLS`gn샾R t$V}/?JD=v~1eKRЅ73pvi-~Et06]~-f3k$+ɝk.sFfԷ= ;+ /M}O<'vHfW^Y5^K6r~SaH<{1lA2 M "yBK7y͌SCdZA*Ӝ]y.DR]cc#&ԑgF~>@ 0i6| yKvd#Ͻv'1޻] TTtk%QpTȌ6tw;"n! \e5A5B񬹗OɆuYtIcU=Rv5 (+So:dXԒI89`;e82}-:(kz̮^J(#:v;xT+BC5qџ$!'(rp':-Yźi=/Ѕ:XX-kAr̀j8iFIM%2/]@ND"ţ> ϼ"2qH"i\cjZ?Z/v*|N~2?D2\#od 9#%MSM@hCHyA7.^hO.m|N9(Q:^JU8KK+Mo MqlXWklGquq*Bbljk-^B݋QFLs.fqf_e7E .'m, -.X=-\K̄5`Af\P& e pC;Y"N,ӎӶ SɃk씓Mt»Õ6nx}ߍj_hqR^ZX򯕰' ug:P=$MVјl4f"BGV<_0t|p_}4fk6puWK}V̬dD]C;i = n锖w{0=i@B専d1|" .&Q@)-U-i)441(r=P62,FkjsOb>囥VBi%G?#3)f6O>`$[^|2A'; )VD(65[v99wU]Tt X+*ܦy꛼Kwa8ǓG>Vy3Rlnq#99_e66;{0>Ћ웪cwrLJT>rI2 JsAŻ+w\@83Wb.Yri4[$k@!|@#,ݲ[B0e(gP'f3|Z;W^d\6]8о1gJ'#:\ap 5seV{dqLʐc~i}X*JP+Yw̫h_[Qs4EܮORe^}b 邼. sZp;@x̺$L*=oZŒ:!v`{ۻQN*Ҩ@ M'WZmXBszDz,|+! !,!,l,! |]n]k*i'q?5ZGji3Uӹ)$ Y/R?-ɔ^{La.CIij}FXr ]!hPJQXg,VhUX,_ R]K4=nHAkMHRsl\XPsoI䷲a,ƒ$r @,uXVC /_GKd'"n-G'] F$"S3} G/J%r JsƖe[mW)YL1Q)# vzb&hWO!dD$G h >|*oCi HYRCDewU=0-H&, .Fc*Gy,ׯ%t!(S E6 '[훡)ɲNk :C/M}_qk7EQc&_h`$4M*r7 /[zKA QG}mDu:߫CӠTpPeˇE|̝s8=A0ݯyїr, \nya ,=3P{s6{[f{-Y婩TBO= (_X#P.}A. MR@į}$HD6GmPI!Gk"?9 2a1QHɢZ G^f M,Ș£levHd逧$w(o1, D~ =N1Y:]y%CK$% E|cI r%Y[ yzCP~H:S5kO͚vKNHYS]f6Vκ82$ɇkU|<4c@}-GŌڴ6UAm;S4%.8\&[MViqSB:G#;=c9H&E>i?mz]>&ժ 4:VOm;Yr3V+QIb^$MӳLKT|ژTVUj[iU/nͯ x ⷬpz-P qc3.TҢ&gۇU7j#ŧ^=nXsm,2D6%.`("~z Qx%J+,Z ܉л؁hY?茔CJ,{X( $^ xWsGYs8})wߗ3 [(TzKytNd!@D01-;: q|.m&lKR6݇&|I@I9gЪz OnleaֈjOLt{sƬȶ92ځ**NoFvNsQ 6cZT0]J+ ?0=(f%y_yR<`\wzs(f9ǔdzlpZX7'y`zQoyR@[4D_ ǽ#dnBއD>d+څc)Dm|fTf0]KXfw$jiZh5'αlU<~s3 ~xcGo"}>jLj )VZ[Smq9E"R;S7^Q>/x&r5Q~U[_eu2khx dʱt7==`Tkj$Ɇ"fʷf9)6TB+(_J'iX]/jKh$Xse!Z:51N)Fh(7d[*$<AF>lr\dNI};aЕ I++闊ӀʛQL1bh|+x$X> C'PYX 6U0[i6.Ƶ;iDmlfYeF{#TK `uGTK+"$fƑAfTSA:uA el%vM C:(ciCޙ 0O+)x)o'cpHl5Vr:0TW';{;+Vx`gee1{<=`Z!{ǯE+WZΑQފGq[*j}J Oݪ8}c:cX~Tv4m=x붴ͭ4LqިBGZWn6dJ< CFbvdUZ}ɌEfyܡ$ϝ~r_ :JǴF:)ay{e^6k2` I!`"m<Ӌq/,srDJn\0/v4yI ( ^rCObuǽ!QO]^ 1xXw1_&K qGRdjN  bگH:_so4? Svs@i]b2_8{ >Q= C*یIi,IuYuFs Yq0_ F(z};ըp(b.Y%3#r#X[B@urOƁw&x5<~LA2Ph؈T[e{lyiun_ 3TSk v1\T.FJ"{!t5]p1Yb ʕB7.y\/t4' 9D|~[~r'B7>2&պħ HJ'&m.uxYpV),(wI$.l@=RApਥO>&qvZ>ʶ1ɚC[64PE#Ht+"G,ʞ{@ef eETLˇzz xk4?kIYkaKK#d%{bt(.,JfN͑vAn^'XpDvIai>A1Yp&!AP<ޞ~3j+4zl*0WyCUS $T ܵgu'(0M1)S :5zc3ynYÅD4q:UzTuʕ7EL5}3;SͰSrl? ™XL~ V@b7%ZeXkXYϟ9>}0ѴQQ/ ڍ_{2M? T2e/֦Z)ZvvBs3iLRifTsDډF0%Z'ی@=&|2#W7\[mss" .fc V{.fPorh-]w ޡN!12+(Yyc2; ~lNMufؖ [~5f[eY3m٭=g$Š;\HV% oȰ͇Әq\^a'dy'ϣl/6֩+cR>s AI1w 2Q:'8T[/;c Ր"!]zmvH%Ki75!?oM\ax茱ڡcb\6:,/,Hڀ:c4NV cSCɓݵvU(K( K'  X=S$VoZu_!<?B1LCa406!S.JŽ^ ؄0 # 5>3g%( !ekM"ٸ]JtI7:j0܍w#׼R(%]rD7*BZZDcmG_IB[ٰ5ZpC7`wt J߅ s(stɜt*/:\}LrdϻGMtji*(}S*yv@:Na!aJd hE_uD>;ZvwPo޵{OŸ Mgr hlL Bh]]Vw\,tGLH*#eِ~&v@TP*J=;e9:ugLY$WCq^ԭ&],JpH&W~Yle)k8L}D돌jZTQIeP3tzWImyANӥ1R&9K-i(q2b1睓^ذ!SC2 ]2@̾Fݒum˨Wo k4S8cZA%co2pVekC*njPŋtvJ$ gO{;d^j{O(T/NA=X]jg}3v)p\kҖB 鵔BPS_90,M d@W5$Xg uy{% +‰!f:`_UcyJboK!h&LeDӘX)(Sh}x2E yP iWgn>xO SI,r[˶1F/`s}琅I, \ܼT>aZEKl6t|=֩o}C]M= ܁0a,R "~wPv\yL*zez=Vn<,e8n!h#Y Dɑ]S/HMmmcm_$cg9kd3 nCEF ݱ)`4+m`7}}])tV)m1ɞOK/I;yy!JyYDTG7YH X ;8;6^|ԌDFBZ3"U}TC YzB\; T\#/v+$Q?OcDʥuk~@rb`قΎ*CKq  w1xl;!P.A_-l!!fxV)4Nj{ `ZKis18wд)g+ag}"1RIe0ƕ_%% IV!I.RF/P,yGfKsE|۷IYȂ4xZqQZM@}⼁PMgoK[K{<ԫɂ..CQ_ V "VDC|BF/]2O4o.ԶM%0(^'v!=4y&PKo.p/yF4WNt^[tJFgf%\Ip5 2 ;iS*)lu +oLaZh[D=2aak4E'u)]7 Vzk{tUYͨm%&J΀9D+&Lq +`613d_Hd#>"y<@#O , ߐ#l(2io2ЌRiWڬq)~AoۅI_wlvM 55y2-R֫Zld_A?&Q,64SaR+Uさݾ}g&#}+S%s,|YKaqFK(hwy J5C&dkD-B$'тw^& E]/,3.OR26 ;U ?2I:bηߔ~!YLX'DhBZoެ% t,Z(FXo$Fk-ѥa(9bƔ*S;+C$jw0!äFtç^ʩg7;ԍa&JȼOvVcYѳ%XAVegέ;-N:)@ xY19X<%t3alf[z&cJ neznIvlK ?RhZ RkPѕ!Sխ==oaZLFu(Lhcr9q"Pw =/ft k)$̓G2֗.JݡAm !h1kQF6ˆldEcJ^\ te5+ Iwi"FC'ф8ӄwgeB( ̦Akm;B SD]ziPǀ1mŗa s&wzZ^IvJ܉Z:v~yWOpu#(P H85LQrmH:M6Rr4䱼Y9 ƹ=p,wS^ `3H̋C>c&*6"^enW0yC}M h8 .2K9~sֲëIk+X,6-\Qj_9/ qL<W; 4} CEZ#'l 1S/\yB |̅O7ZdvLKEz0$ňK{i(Ç~5qWƆY>ǰUª!3ݟ,$ <|5I{JfSTo;=BRJd қ\?d75w'V?O;s5ʭSZw:W(HS{IB^H,W;\|_P4 H iBϰ'hʵ4`:9\~soF,e&nJ۠!rOl}ڪrh2 Bte(8%[8> DDfyBL&b SlOYmHn0W\hT,O}^1jXE~Tȱ;iHZ O1 !ћ5 X֧"%*4уV:O(iQMVQ\5#-nd3!CȠ.HkI<$x"ԌQF8"׶#طI!ZU詂|ZbTgHNA$] _X9BA+AԼ?GE|V!2t${ῲvRum/,YoxA0 ebH1l;} yqpDX;#qm_J[TemŚ##XOϋ>dgX ~e.*{vOdA<F ܫԔ*2eE@(pOcXʯUH<6He D{<ϻ\NyT `4$οK#[o}~S3WM_r[+95Jv(nʸ;6EUuןILo 45_8ÙV:2k7 ?.dlpkѫY f7h,һ1& 8d.-w:ת4䙠lU?a`I )_ܥl$LvUdz)pZ"geDSb'exUZ22j (+494ӻ<&KA30w_|#K&'; EaC >C_${1.`s0RLZ1w$a VK>m6+Dh.:kԮZeV+޸Ikf|񕩻JuSKI;h` ߪCR9c&#{GQk[7d?XW &?yq9O@u-y)JoV|4;/رc}Pgf-G-njv1}r=vr2h! z[* @<1xMstK.1WŅ~#ݬN)V"[ɚAX~A\H+F5ݤuIUTAH:cz:\?>͐>3"r=%&,WC9O!Z80ƢËՀ!j3A `i@AI̓`=E5Q}ĖJ,]a$ TI"x[A?^ҽY[/J}џ7h5OEHΑ&stTKbsB$ujɳ·wÏiDo-ds$%=ҺO8 k C2*].t_YwSdxd BЋIwi A3FN1Q[ :`x䪟w2`a?:f>nVP3Ax[Ʃ;|:p>I7j,SZ ^Y;9~?>L7j3uӐc2pю;!3EbS,XBwH5Bb|acH6YA{Xi@QiR&ܵWkx#/Z>-R?5Ģ7 e?MWM9%]OTf'َč4QAPOğLdNMeH6?2 1U菇he>H@A cΦtӍXSaZ4~Mߵ+`%Tޭ~\ސor?MwnDz9ٜё˹DI?e.@jJWXHiI27wk^TxYXΛ*؇fqؾQٴ/xYsjZ@ , K[Qԙ$z,5U >,MC[UڄU܊F,AAZ9q~MwjR*OE?6=~brFʄ:T ʇc'sޞ*@a#Ύn/TWhT r#=Z[xIwj шSۯsP*~^EÐvNPioYlGf?2\Ֆ-N)VE i0PxhH$[T']a H%㪞8R8)\0Tw??  r%Pfmg c{C:R|-ڔMjYu,*IM8+ dlY*8C%)MdA6R&"dP=_mӼԉ1\K e`ΥZѤ6(7 {AC{m}>.L~'ܿQp  h ?:(`=YNC+p\ҙ=ގ_[ܲ@O^礑mwX pXbwHS ]I8>>y;IF,tZB6;y,dA@"rزLWR!#Ju-2$(DYo{Ŧc>H`g]>_&^I\Iz"[{}| Ix3{PvkNHٍI R5hض< [fpMd>ogW'P-eܚ!¡6 .+ Ifs X8F[1i78l6#^mg46nswcWREwlca7K0_)t*. Ϳ[ɗNLI|+V3my6 E|ZB+4Qn&DNJi^S0J14N%Vlu\,dSiui\]Brf!q]Y73.`Yn[xF?!:8S3>׉e|/8&3@ݟWN\~K(,W1Rz2.B˾_PuX=lDFChxƫxSdjg4R>-ly^)qU`8ѝdYҵXwMc) 31/_޳J;`]]i.r$IE!Ə czI9<| WIh<$Xv#CXlt-+o՝!Rsحax6zYsnWU\&J 6w)oW$<_38cf*z! i'd6%i/ fKki:@OB?o7^:@~6Q *UFGÀH!s#qazO餴BESP'}sFY"{N/.6e4A-Lŗ]F$e|Wavt2`HHlᒳȒFC!L[}n]a[<έ㬸+L]UZ\FUnp"A܃lZU%0[rcgW5d |i[iMiZ6[P~8H?d-l!9 n_2d^2Z?h䊸(܎'uu/HC{EQKSyYd) 92߆zO-7k{K5v4ˢizcX=&3ݜkOUT.ٌOp:}nߎ5N1~Ze݁t!K*G Bo?7CiAS@wctܮ!/zΆ?ۥ;dCWWխȓ E6Lۋn2CLlɖN*9P.݁oӤ4+x[7~ _ၜZa66<}( szQe߾ d]D6&-nV $M9g(e$7u^7#)B&.]r-WZpTI"0蓣tt5?ұ5hF'ԡ$țB0\չ4e"L3tV0%Enߎ;]ڋy37.*WMr´ެ$MLb~M2aSmnqZ>o~J'2;s6UeCr gw+Lϵ9ymc^BhT; jid~di=T'nv K?eOy^M@I'iay˄(Ca@#jBg >2 iq6"@ؐR}NzcrZx[9\#d5Ay b,.@GݧX'4M9ɽ\>h!:̉}K[lγWM! gTTCHry><ۊ^C-6EI;Ʒ=mg®ǺY.H8}sr+E҈B$dSr4vmYzUʫe+dA#>6c 7N1:c GK*b|Sr#S_l:%sٔ>j^tڊ"B%"OB:%~ ,tۏe(.LVKjag@9M=*.Qތ1JYi*%oOu=]a)55nÀF~DAɆdmBT] KF7g8"aڊgU*R>tN^KMcH CڅN ") āz{.@"WtGCqy{ N[21"cXCy n "4wxpk%3C F[52F&46.҈m!Xj7+s.?KtD$ROFiD̬3u/auL9|?.˞e ܎ =e\Ū @ʇTWHGs49G/F܅4cm8-&.-2Ӎ?oeb(θ>Ty 0ݥM^.6byk,Rl|YjwE*VIdjD%goMy86fEoEЩ#300}@nd7A)y>څěQժKIz&Sj6; xYCH@a%3(h6-VJ4vkpriג&iKj{&Q謰KQh*^!nmt@t;2tǡ ZvQR/̰R;:*}t:/K`@x H}!@@*dyRvckڋ0ڇهB([3|{Fs,ۊPh525i.KB$EF tO _6)\t'3p/ZUdf\[2XW0#)TIA_,?k]ہ^BvKT7'ȥgZ3xAӷf{c Tl1]bkSlɱVs/;_I>\ᇹ_9U9mRySU2,`VXEHy͘d]Pɕ/JzcI_2sZ/x"Z'1ں@z|Si"{ #<hD!7z2G< c$"E1Ԁ:풇Iw/u'6G5p|koh-<1cn9|9|.PF LFw"XMxʿjOWgq7^w=-A; G6$Ӂv{ 9v66 k{nBy}J\B-ň2L)Dmh,mG>a߿E &lzF H^a/RA9ks`6V[A W7#ܝ0ѾA|ϊ:-m)qowD?b)i%-**~M O 5X)<#,{ӉhC|8U-,<_pBu5sh6$&M瘣rh[m>V?uH5b($.t6`_X򢈯u~hpG! uQoP`𣾕Y%jϕLpthdu./ν.YdARl'jm}Xul \OpwM^>"C(p ed)5C`PKĩE`uq0}P,aIR; d`SvS`٦F랞gX J&>W!&(l1~\1Ιgvok0)2^MG7Dqq[𣽎EO-^;)'m`,0؍y#WVK}+2; VКJ/-#_,9"+QXG{AlӌbNa8.-]o&"P*z롓&a ±m?q\ A@F~}Wp'.hKQIp}ugB!#[v7iE+"nB$.oȞ9n'ۢk~A֗f~dO%6j e7r]Qb9`Z#嬔-ջy}RaSJdK3/Xɀ''ck?JRR70fS ZsgK„odtQY]0>+EU8jʊnD8CF /;; &/hh%sﶧ$++' >YA(jS[;tԔ$BZZ,|H倂Hot˔=08=v{: kXX3,`uW4HZʢ=4pأg BbPG`"VD*Ք|0heKhJ< @&>lBc[3*iib1._P3ګi@H/!xRuAdgWEha2V y\ -]dAAnm0Zyi[+WS6˙0'S^RsQå FnJ2/50ľr$"E8ZyLz7Ҏ4 /"}s <~|~<;t]PӳøBHܚ40=GW3:vylu=܎OTȅMB2^ñrO>3{?pK0Йiy2HK|hxcħ#'D]J߰#W6N|L՞i%yA[~A\,'t%ݝiE/2DPwsxF9-vH2P_!u|8"'ZmDm*L .[}u "pD/DpҏKx6y5xSsH ų^^9$ Tw/#]P.-SƝ x檤y8detOANO0K&'Y >\ۧJRHJa:TmFwHQa7(bDi? > T$=vG!N//)v>H0sf*/d3jּH;hDiUv[.++TȐƠ';U]j8;\HaCa6 W Wsc6%/Zґ!Bm S{D.oer54&!r'@veIZCy SI&Xao%%rߗu0H2+)^)^MFMm:Ɗ)ó|ɐhk,X8 @%Qn4.|-Do-3gF1 l~f|G]p 5]߰ܖ;idWW  ]unƲ endstream endobj 8 0 obj 83681 endobj 9 0 obj << /Name /Im2 /Type /XObject /Length 10 0 R /Filter /FlateDecode /Subtype /Image /Width 2085 /Height 1259 /BitsPerComponent 8 /ColorSpace /DeviceGray >> stream 2\OԢR qQ63USSntf>\_zk*0iPeTal2Dn.tBR?6hYS,/t\D>;$T$%VSImhB)SAm/d'2VHotB  6~G6!cHp%uNaz\.o鴻UxXեc-|'+&g쿷FɐILv/7#sj??ooQXfFPB*7:Kw1]6a'#77HN""'γЬH$`X{|t" Z$R|Oqst'1`|EF{ʗ\ @lOv:8Stꐊ8jCa[H\+ҙrzn/tE5*D:(DSu_w !mz۟ڸ%ZFWszBVvTX4UPCpM\TuA'0B&t D+emj?ޚ/v8'' >lUT)C EWِ:]t05ůquqs,De]wΌfryb%E.0^ OL&9XA]+#LԎzbUGOF>Q/(S#Ͳa @ Ë3j z0@. pҩ$Qejaq'0d-3"9ߪqԢ_ eF+ l T|ΉM`gA&~ wNuz\np`g1qypm09TφLz2ܣ&'!y_9!~sҧLVH6D0;-_ALDf<CV3Zjzbؠ]%=ߦ k!V &tcCTzSPo!V>{b'xl1׌w_K'HF=fրr8qIBq|!ӥ}xBqfWdUA9Иqy[* ٫ F `Myg| |v]oS$crwCzY<+CBzIZ*U2mzrm-SF"RxS6S?}L3d'_ǂE#3!A&l>qSZK~ D,@bc"Oú: XHDp9"B;FT8rJ_/\g\n 㥞?Y,=}9!BxyEM*8jq/gebXP7)z--.WugG* pORIH` _~hZLi6OM.Hg`35=p7 RTg f j)\Ns_`<*HۢS98镈sRrxח4^t~WsyNSC 5brQlKep9i+ {ǩm}v=d|VnbFLY-9a{F<^ϸdJ^6#wa}Ş&# H]ϩo7rlBrL lMAš II0Qf΢fU j w {5h U+D| / ǫOY8GvF%.DIdP+^w1jTb, 77nQN녇:,c:u]!. ę$Bk& ڡq:FD #өESa%ȸeI]L?$B>'$Iq6lkdim#g>LfNXϏd{BGK*5)M|xo{&yҒ5ǰv|籑Ěx }M~|$Z{`StU-htQ 6V"s%< ќҵ-.+碖<P+y 'y9q%XT﹅/Xʁt+y$!%ȡq;؏2p%cîKu(@}0ZkcuyYVT흨nR cqF."3Khy(#?˟3\ƤI%?>ZiLZh)ҿ: gb 1 te7m t݅km:dYXC Vj$ @bvص1s@b;SJ걧gp`a^J[!Ye~ҩ|ah‘Nr|^Bbҿi9 B}WhRX"y(s=#ͫ_hpK$U(, VW,b7PN+IJMŁ QkSfa@.GnZ̵Qy (|’%Ö\+;5({3#7[~ߙmaSE^ldW37N((-c{Ph &mA_fϷ{@Qf? &AIj Ί/ڱ 2>!2B'N 5}7Bg kׁU-dD=gl(o-˃ {txm)IbzEYn`2T~\?µ;}ūL'aL H.etqh6Ѿ]ǴX u֮.qq"C8.֥@Y"'M* -V~&b"$d @ahzA*_[LەWR+78zA3ID*wv e%)-~8ր!FD QG#~%$'-PU1Ca3j2s#sYs{4QPn*;Bv- ${6TM1gS&d* .Iӥ( lh۳VbBc}VgdD3MЬʽ<*Z.l!-O{9j>t$<ϭ|q3neX0BMr?!](yqbg"<{_{{\W+sF8P0= _;Ւ*D;A6a֟pϣ<|Wm=V7<ԏQF)N?fZ'hvˢ7+^mr5xj^Ca7 G.FY ,qBLW^pۗ8_!0hp2"]@b`zBPzedu_x^ԇyڣyvpUa{8'y=?u'ଟfTvab$\4>}Kă_Fea,.QSŽ[ނZH"kQb6"/̞\N Dz% b:TӺeGK(\vPX\K[Ii W.ʐAr-ݺ :>),G&Ca,,X#S<7HL:2ʩA/m.)׀BfĜ(t"?&3i9P׸5KUJwc͗Zr*3R߀):ugCX#c9O*k}s󩰨N=V$vE)c%F[KJx Of4}qO"GMs"S)(cp"0kK%VXn.D:߰{TfadF;F4&[d ŐH2"QJZodt|;mlN.A&={ ҅G&M+)fM=$&p*\VW'Y39As㲘ք~#[b! *'3gzmԩ'H0Cay+1 ҝ]UI"rN䞒oԂRpml}nEKVԓZ*Di4dl@凮b_@ߌDןA{xk2mRvfAu9IejАaH76'L]mV!&oOP@jo^rI9oٟ!.dg&߲@#V*t`=ijk3+}.`#Gw7a~?l؇ajDY~+XB__yc#Vr WO`,4{0=HBKsPer [ݺoQ )rb..bO-1Oߜ^G 7GqW&A.L0K&Ίو2礏Y'殮qW2L}X6o.hH? Qr5Q1aR_QXasS AFq ]6 ٭GU8x?8਺H k}#RDtjy97num{bC7T^>mx g-ŮFU~Nr. -0n;K5 !E 9x_NBCCa6нCx}aJ0[En8*9C,MA2hdO& VÆݱ"RG: R~ǥo!O6ņxM '|~x7:`oލz+ 6zфo{WoتGGb߉qoa smaz9:$5ڤ4P%eݏyǽG\1rwjWD PL_wSHxp~sV݌.f<|w`|-TPLE.RO]a1MTMA)b)v!?^a̹8wAB7&$-hYDDr &}5bx$ncR gl_4)=?kFkOl1o`j+w^up\ nH2\NAkp^U^R DŽ~V? A*UhDYoJ4- |R.䯿ȫԥ5{W YOjq#_L | ݢv3Y3{G:Ò>S㘒rUj"[9U5OAQ#6}I=Lrwo8E 7zTL_)G# Y,OZOW׊5}2)bVzۡMFNd}p_6یՌLHmlpp@=>cL$$!pp,Aƪh,Qo96 oFӒ3rA=,[h"xJ y{*7*6/IR-(pȕw:O}^OV[=[ QDld\B>odq1$ M苦s: BoYD#ʝI e!QZ\%7 At=څZ]^n.r/pBX}\W o>pU`?{hqw/⨀`vOq!w):{<&H JZ>8,R>f STeјHm${Y$9/,eH=)wi Až&=!WĒ_=9a|EwfGBM9n W'G/N|Gcз'<]AmL"YVƗӒU3bCՌK:If:vZͤ+e -XdWYge%D}3&mM]ەn%[ =3nǁglDn rys\P7*EKukbiRg;q ͡`jؖV\vSàS h& <' `)<ąXr'CT|GxOQd7Hxj#ϸ3WhWl^"9"eM#M| ;wE,6g#;.Wb%^?cy*S>ha=E9z/߆ =(r:n1/Y[! `((H:>/Fa+/?r4mKq.4'ϯo*ϮxTjA*3/ypL?Ԃ}DK,0 X8ydw3eUf_6ٹPTC} {=UT~;E[͜^Tg[ RzZh`H\)mLSw>r~8t3*{%#1O;P_8oo"IC ДU3]K*'ffQ{wN]`Y0' ǫH\$ZX 6u}Ÿ0N.? ;wW+( EbΆp3Ife]K[恤c}y /+nT@Q4 W6%GP| -SF"Hpb|f)<1!,biָM#kG1o=[iI&4 Cm&MlxfQGbVF(sBmBwnl03A󒡠eyCbb4sYWTګ':nn qmbYh/ v|8b3ŪrR A7 e4 I&x)@xO4 ik.5hN9j2׎MLv^v):X uҲ ҡ 鿴Mo;rʆXzARݒSӺ8Jo *:ix- h^|-86KHׄ >:߻oz+.0@mW6 ~6^jW[ jGBצWiݱ̺-lNlׅӑћZY"h-p#39yڸnED12S.R7ѷAk/?AF#nQ!w'+[PܐV5 Hhn3qCE){/8#&AܧWkGq\5FUJ^g莳"ɷ)+%P3Sxw+ H&:8D2\QY' XNd'Vk}7ԫAЁYj#U9 : ho1r,$TXqHѦ`6_q-\]Nhhlȃvz1yS`s` {b#mG=/Gi*D 7КXd Ӑa굽TwʽKօ;` [K$.O;oGgYR&>ŞRoT~?2Y2S*)+BxgBE|_=cQ0ФըZB KA{}kxvyC6yrm*VmD"]q⸥Ev6T2pP2),+iDepJ?iSR@ۣ-/A!;X9ls~C;HW^~*#>p8}@kApy((z!0hf򕣴h%,"Q )m_%~@q2V@E>-B8 }HCq'#`{\1Wgx_>A\DErO&*j!R1q^Jg`UK*f<؉ˈ[{?rK8鏇ɊR.Ke+c?^ԃ/?yS5_PTi i)Ub| ,fFGV -gR=9:n"zdϮ=zHrd/QCj/T~kN3in1X'/W |c`5[sN)AF :Zrd+$zřTxjr o&$Ƈ=ZJAe``ЍTb=B bAPNl14Pb费fk*וQ.mwܯ* Ldfk'Zy??*l3p4ic-;EޟNPH2SRQҴ8 D|Zب9 g$wMh><"ˢwX)y{f1}C&_GOCܙ|pD7SE@j͑fKWFf&Aq%>M '`]?W H?zLi;=֢A\V&]K`WCz D G:Eb%ʹc i/sU onI僸4yuƎ#X(zwэ^7Wuj(!tR)asM^֮[9ϓu#Rz`(TOAٻ줄tthA90z?G$k "ȶmVlGTFyt@t%[T+rp7ÀɃe>a&PPRUz琎v.Vq<,w+X(J[lmdKg;MVX7S0[ NrrB-%NT aNier SX x(\OiT0 D<%K1 K#y%T/u]8;?.ъFAq!u5}<d"*'TQϒQWӣ0>"^= @^qğLqQTƬwaF3Wjݓ͸I"4,PJ.³ځ자{" &9ATEPnԔeںaQ2~sJG&/*h]ÈѪ&c'bX j6܏4pHD=0# ,%L@Q4,%zG9>ț/Ha&F~ Z"UUt0`P~A$?U9nwGZhJ;>f)`V7+]1Iy*VV1ǟPe% 8ƆgDz'=Idyq@mK4Ѕs)( !O9M>˞tn S[rG3`ׂU%o1K!PB\ݠ Bh-a@]A,,&_ā< o𱜘O\84b:?^zbg@8 [gP+T|rB'4#;Gx1)PPChH@x+M+46=0<-Q+ii iPкܱ)̂8,6N-n*AIxIpQ[@yJB*74:vpW.\7+ѷ5> 0\l,ƫF%Ԟ.m.~.7񱺁/ 4'<7(gۍ>J]tYʴ)YWW4g $X-Є/k46GvW/rp錞ߕ/+6179uM_伍0#lN|UFq[0lnl:f(%qXTa!hr  1EVÿv X9ireUV[~ n $vA]D*tQrsLuiJLa jdH(&bJzfce)KL;o߻JcsQAˋ @q¥uXYhO$OCG֖[[%ϘWaAH詞z5ء" __qk(} 8fEqOŒ,7,̓3TkC' +ԟMS5W)\47Vws=2\'8yk*uZҪt YLa6p5V*pk;囧n3%+mѢA 0Gtr~ykaF:\pf52Ex2Ms>crAZ)_CQN?mYRr[ bz*>w/ʙG LK0F~>l[-Я cG,F^V){&:u z7OW3T8%*WYH AS>UlDYkp Paem_4];ԷTCLbr#vs5ߑ%fzu@E#-x|Dkp g0͎"w/3;Pԯb#^^$>8ey 4AsB+0mc.O9>~q=ۼ j&CVemŔVy,揄u Bf0e!erVh-dcqwɮ_dzʀ jz469oE҅|>hx n_`$m^pDzBǮ:mt >{Dͪ ,"(`f1m+]27/{>$a.n;h%|7!z71ZEtn+N33? $b26×e"B.w14Ϣ!^>O] "Ic$ow"wrv%'01Q2*-Un?B8H]O79$K#K< @u}Ve??ݎ ěcۼCXTCM96Af8D˴5lP,`lPꆋkPu SD<a+;:Ug:"Zf=3EBbYiyk_G=|ӶJE,Xo"Ì{ ]66ȟBz9qY(C]X:ZexdK*B/.]2b>F=GTZT({xj٦p>Zbj ),lt т[]a*+7)}F4/6?zN_a;j6[/$F^!'۠um~ |&74HnTwpwadϿK2@7ȒsxǏ-@|O NʽV-XJ"u(z.F4g9PQ-ːߪ<^KGA?/^72g,2i.$zk{J _snY9}̏Ӧ-/`[ajp*{~YשϹ0(`) j 3+zgxIQKinXtGw[;bW2!yl=6뚹u_8x*2T;~ΥU_ƥΧGiնƛ vd9,Q:w` ==/+g9Tp+4daCK9jXWOMWeJ88LX5[¿z 8虧֡Fw*Nr٤rEd U“>*8:Ji db.nV{y6-H/$@I(;# II˩\to!d33º#"벎f4/f~ \̖H0ӽ'Q4EC078&,$ F2wm+$N7p?>y%yJ Oϳ V|F9!ڀ@ wQB߬ÒWz!}&;&$JZ b'hBdvƚKsĔ[ +ΛBSnjps~*[Z-kv'1D|!@Wc'8Kͅ^Qc"TZ5>9@f;Fa&ř$C{! *bڍ nrK(cg ]ٲ5?M\zsJ4^HGEjX+INi>JvAs ife]Ḥ\2`;{1ٚu>Lx>S8ȫdg3 4eZ\`!)(()V3KB+=509sCa&aNwӎ[2,96VXűE#`z$_ o4qRzn 7AS~MS,JwQ#: ~ENuB/YqCeZu%L*{>'O{l@iŮCQc$Ӭ/d)&o)T9eВiil~g;L$*BJral}:*FUG֢yvY!?!Y[WN#QRRFǃk+{{>`Nʮm8=?yRT:j&\%3_ UӎHĭJLw^C]|^3qؚKbeDSjZMgȰdSuDVH)6oOFRbu  \Md3]!+]YOXҒ8{3]m'kZ{eHZ.{],\poJ3T(Tc'qw3{`2s88nIvjW#ȳgCrP&6/M}b(.maK,xvc6h 8&DHSD}`TՇKWC`G>~6}f3..-k>u<ׄUy*Z U?CQX$j 3oї 4 M9,,Q.sE۟ޤ ۑm]OrM/*1kmu hMkMXfƄSzʳjIeV*/wZs &¥;ZD- >9ƔOq]rڱGo0ayr-|ͪ$M,|<ԒN1|ϡ;ZEIsf:lȡ p. "_֕1LyL OF+R%G^$~Z{~U\po{mx;=Gz+~mz,'-c(+(@S^ u.N(x-2xS܁ɞ𕄩N;mؽ{NĴ8fhj tq _ ]DW T >*֒;Љs=g. 6;)޹֊Hm9]E d@`U] D P'J_P]zXĹ#YvS0IX |RJRBe8& R ,u1]Uà tԫ[9 H9!# P㮜Ow"f4f-^<Bȴ ny9+90ɜ̾󺕼JG]Jݾ\R)usfEڦ XQaw8NqK4Fh<Ь!S{;wy*=IP`UT<%JTy'(؛Cj Q6kfj6d픻'=bV^ \#WDkP%Oq̨ =45$*cT da<]X/𛡕jy?VV(8Ogʣk.4u-]MIyαY~3a0* CXa$6:慻<46fm0Y(f~{vzB zzfRɳ. ^Ga~wQU…aHTbR=wj&XQ ˱i܄}an=;#=' y%ko&p]`%nϱ-?d9/6ѝ)7=ȗvq2l{ߖAzJir }p0W.O<2t$E/y/?f߯O$t$_önvX%)Y^s3F7QIZNg@ ~d4dE0 ]A,;焙vÕX&8.mgr@DA<*b}Z/]kǤk"OjevNBp`k(;3^)w 9[v8Z*XPrhŲ`: 2$~vCLSGs{YqnO)k u1h%őZ`+7A6jS "bCE)'9#cx(!ވ\tys+Eq_N)1",D`ȓZ "[\kJEVל` /pk+.kk&ج!郫G?)KG"5++6CJs"9=1zbg0~aZgCKRׁ%?8/勖K}$e ˪ Mw("D '@ b2bρI$P)hvÕm`}0)I'ԴO ~&>ap6i{qigYzDB%ڗ6mWչԀ7BB60}8uqr$*6dvjĺ>F,Y"gC>=n| NK WdŘ*Eå^RP Dt/$xZW+t ,:tO^ J!9+_{V!}ݨl| ZcSKӞ9͓6ZӪ~#YLP1yǚ᳢u:CF1kVBѡI24#8Eŗ+TNp3S~G3ꤹ&,S*`Tg1ܱ&AZЋ_??*qg,jKI%]4y Y`Z:9NzpEUw14lX[/OT!c`$C l򃊢b[%qfs1*Z(˷+/:k=Td :kIE,/pױzc=nH1v6z뭇:fSCuQ) 짰6TS(/Su+?Wih=oI't`h5G__7iLtֻ6/D4l}u5s?d# '.&Mͥ>ME: %Dj CNs-|]Idm֣qaX;Ë{a >K Inp_R(GY;\%(&g3\B/F¤ѽyupz2+U1Wefd̽~*$yxMmgI[qP\7_9o-SD6V +&S/Gۄcds'Z\PXa!S=k#yYldX o P<ܚryf9hQ >w7;ky ;j>`Q3ק& D LNjN.Z ~+foۅڮן E[OEd޹7h61zUHd}B@b P)ȢM ’!<<;H?'N"wY[ʩݑs)+V޼a(,X\G OGE ey[s2e0c HkKj(X R&`˂够<%i 7c#o{GICm9 ȬpXb$8j]=9&ixe|xh889p:>/ (䭚])LM/:pOI"|C;>/o)/B|:OMh'GoϘ{\_:ic |I/V-`EsYN?34~|͇l6K0)o=M%f9+^/f8qYt1$f= U^֡ª"i+=hT~IŚ勯Al< }IevXrÊכֳɾ \|:~+)|A4ݬc/{ޠˊ5ˎ@zlSYrJ-:ho9 x-AO{gޗQ|b%Y|cڨ8:hḜ΋d OFQ,L1ˎnrUЈNzuWi`?Hf'7N&*^kCŽvռnײSNRjolB3 Ǝ] x!G/:Rlez_t8FRqDb$3DQQ URʌAeG3r7+&]{]f^OWRT^7V3EI2P$1X?epz f:xytƖ^Koz|xΣBu6!EZϻk`>'&9lS\xPOFLPMaYLm[g&So>"G<2N̯ZE;[BPcni`k ׄ 鑦&oJ%n9rs5{okcQ(C{ե}NӅ=n+uP80ŝpcg5t.XX;2ڄ;pfhlAdMbNm)ROڽ/_vd?Զ][ $'Cv ux99P<3C7;RKsюmITD$vO00׳s̹zDs!ɣxBc5̍Wv%P(fT^>2-t 8,1;SрSA硛3P#%9Q{RiH*XiG{oت?rC~~JD͏ajCl4]vՉ;)܌C}'(*"4BF][E0!zXH*oF: %KxrB.x FoAc>47~Y&lذSk$P!<|aFK,#KM \N/.]I8N"?2lN]V.ݣ`G\[KyS3~X\e39GrAWMNc;@a U÷6"qbfD hb574@۩G` 2"}aM@P$Ljj#<Ɵ:ḰeH 1'-qa.]Z.slVR</ 4 -l8Q ۬=!SC21ͲtHۨ;$p>0Ըp`Obҳ,ڇDL<ʭ0#μMOՓ][v UO@wھ@lfc/lDۙx+ vFi2Vx& ʏ9eCZ^ HӔ)nM[p,4Ԃ:f f\LxDI<*W c-l'殮[ΕwmyΎզqPTb'ACO G#tӵ1 }&nHYh ])huu4ZO]̭uMHd,491Mܳ67'\whQRC8-`{1u@ibղw~9bcD'Gwx, @a_P#TʏL=OVTk<*X!˲:ye6ಛZS̟E iX% t bLxX\]d4?)߭_So TN=AG/Kz`8eYX:_b>G3i84ZDj+H 9=63MʯܻݤU[%M8`>mT`?q}k>ВiԴcEeY-IlAz͙ԅcOv0kk}UIhܼ \MEZ3m%>IN }t5#j& :4A}ӿ`ۉ}3/"ӗ&r,n nkY&+%w:}IU)KK&DV+gU%4@5, P!|dPr゙[0%avuMn Yaz~8~yZZ.R2.psX4iNoƋԖZOӁ߲~ϕPj#\x?y3S)05"tOe븉:-N*Q'}ʟJ[M":^^YV?4]2Bt"!@eߝ6L^"=o;Pгfջ~ %a^ҕ٧툍Ըe!Z")RReM4J/RZw\!C~#"VfUŗNviȑED琩HnxNۣsie؋yvOkf LyV":b28##=J&fU):gdrql!-\Rh2&Z KxcAA?UJ^֏ӂhAƉ'U3)Z8_`@z/zħ̴M+]GBeď8Lel-K>!fmOh Jȧ즯\htgRMVg j6FkwPz.hӬٸ<5dj&Vk{"JV"! 9ʂgZ"-$Ohldzi U*ty>dӿ/H:/y1BŽ0hń5+a S 41S {}].Kٜ`6:wY蠥\J <3bJv>9+f>ϗR;i'va+ =7tr&<:#٦$m Y?\E>^$澉#WS2$v"5 E nVFy۟C9dl$ܵ Tq(r^ǯKlEKcs=ǀ`l .Puʊ,؍x uoSJ絬x5Iwkgjzq]4;EVHF3ቢַL_髝>0<݀vQB4ob P,=:J5WE-BӌrELݯ%t"(ESKKpd̕H.d}`/'S9Fdwd6-гD>˰WV&h*3W}#.+}rV*٭rD:杋Zo} 8Έ5& Rxڗ7翉 \\N~ȿsމϞH?=z'y`& n=H܎0@B?Fި$չf)qsJpb/n_T| 4 N -\BPTq-M"l7 :z DYBZ|w6($#`Eρpgu Q l˯aOp&] XCmB 7(=Wpb"2˷orsQ5#Fϔ-Gl*.BdP v0'sWP'0+f&||j߂#~7r=s1M*6ȊhVڲ{r>pqgd2nls$S( M6]n#؂ÜzGX*ײ.|3F=[gB%ɮD`{LI;"4=ο,=-eGu>-Z<1}x^ed>,sdGmi+#As0uQ7sR|,- Ȏ'h 1?\16FDp9Ou<V|GAݣņBy`A9!A]B=M7\@L=\ d3ZF 掁=;Mw!hՙ5m=5880#Q: 끈\hߖk]$]/#_L jYa?p4e8XK6J9A<;Uc3 6cx멟⚞<0iV? ö̑?A#BSwA(\Sa/Wl4OJruҜ̮o.7Hz pm 3"ޤ|dzaȄI%plR̵D:')Qh_G{w‚{aӋFPh!.Զ\<+VlLM{.ʁ(qVvʈ`cEbL QIJ|&DX$NDBS?jc>=rVQz _a.;sP 4m.; ;Kp6 3:kTG$119P z3i^,m_/yG\<*>{Ϻ5E2ڔ$b.7B7i %L;\P/ޛ ql7'G(EG#Ik=an׿1|Fle 6#?b }ڠ|E61G\$&p!b#Hʬ'f9r2hĨH B]uZL"lCH,D%D,.VV/SU?6,J%9M"L8, ̒V!dYY_P^p\;ZBi {.RŲ! Pq^o>Ald04h p˰ \r/ĝ1ֈfiX\&+K_5QùT&vl`~ –Vߏvˠ ^3 *$xw5t$6`i2 NI6%'.>5Jvl|Qq%4[r͆G&| U\z7lue-C:$Bd 'sSyq lZRӎnαZ&1қOiK?MUsQVFz+@vvb2(M/)*s[%t]#r3[`nS=(C`gx30^oJJb7Qǭ F x<)"ؠp]>(Ԏ0v) (uclLӇjHc+xVca8nMQ{* [hWꗡOnm 3ls5'+gC6~ܮBI *œuǮu)zB&6>@ ߬ߖel/N ,1E2) ۉ,`P8qL~OɈ=;dOl. h h)∋ 9kYK/fDPS+>,sļ-@l*,ˮ[amk 9kȨ\FYc+3Y ä)[+7||Vʳ} [ Fk/m(P~ߺ#KsԴ@7 t0C7'L'J*2s&(P g6U*eM!Bl~C#/64BXCuRJڀwp=VACfv}/Ї[ x8EjcOK+A(RLבxCF9f "/x1 !ԏ(M6V p&"^sWYUIO}ugYCi~BM =0r3.4_|PXa]" 73uaɿDKK5yg4քD"dPXjM\xtM=8/ë9 ?!~kh=Wي="ɇHgydČ=ձi%l9Ϛq  {*>Wn<9i("ƔwKC>Q.LD%\ljkŐ) rm.*"!q0NTi )>ZXּ'+3W ( b RJa$]o%t2bN=_[MmNrwXj|5P٠z" H:SiW0eM3R->2ԁfͽ, ؆od%\r>w/V7} C5%nHcn1YaNqY˒PZXiytcoo@ҏs uZni&;aZIgOo/{:70 9SKM!'kOrן.9 sަ$|ZJ Ļ@\6fh­1H8078K1nGcs?FߏS D  A~E)*~q5;?JH]%(!(k4N5E7)2kd3ӋKҗ^*NMG;&caW .'zV.fM2m҄T\3(,a~bVE9W _Wq9xήq/m-TGeŠ,(nQYѫ R!m#f- .{l#6yYnܨpHP崹G84)OYQD(xRsGꍘjS6KO]C;ѓ") [TiOw4qsf!N׌^l[LFy BIZ#umxھ gH'pA9 6 PϡSk.@7p^'y:۝g,jG ҏz UNxFSySvx_'QX_ThFx ݂Odžd$!@C~ gѽ#(k>"D&섁\&"zǟyk];'yzBpDRsx6@rwC}\>Q0fD=(WStÞr@C`.ѰdJjs AjnNO'@}E&.2/rw'3 Xۜ}~{fyՉ9:qv%bͤb{~NTˊӸeE&HUB>ˎd\h14Trٸ'7ulϰ.s@CQB+ 7Ώd=!/,-j7T-5^˳o}jQ=LB}6ӥ5bZ@pWgH3=*~e_D˝QK&.WV##OȠ6c%6P^XkmV6kIÿ7{1E5n< Zҝ̌H (!]MkKύ 4P~H[kjߨeBjjY?GJFW, uZѢM7ۉ"dhʣ,qG?]c)67tg'3C5ivq?.a-YٍLQDjٞב }v3;jy"WH) |{q9X%J[0I7h6TD-7@f1\B/i7|2e 潥<,|bݠH_hxaFSz# J3 jEց nI-|]F5xyW~tKDسв&a"d:@[+G!lSp%>Ɗ7U{.449 }ƶ+Z,R9bGleVPU |<V^^I \H$OJyDM50;\Lّ]q\@6yiTF`zZC A9g2cZ*U3'\fku,q:7s&am&9!Q(إNvS~A~#ƬR~Ufk1/ꃂv{eŸɱI&^YW34UXco$7f>+M#Rqb.iR8]4袄 >iȾʾѳ/<;`b39o}x)ɕM2vHޡ ,ȮX7Z3e{qFot;߂Ph uƟ˩NeynWJ0DQ9np+k_ÈU}h\YGsnuE2Ă"%/a8싅Q͟Dz,9[k/~6/e56~Ҵ"y&m2{1t93y襈c.s;Uu~i>RV,p~ޣt(pF4۟c5uhwT!۔Sr`y) ,A#fX!c$c#gZܜ Iֹ$"cu bѭU5d?58bO& qr`/"8;ZRN(yel t]qڻdLa¿:{\iO۶&/ow݆ ^bb&r qZ|Lj:2¼ Z)eB iC AJE @%/,n$,Gǹ͕YOq*y틳s,d=8=oA'WAqŤ>>LI؄#s*T`8Ogp"EI++4I50]3~1갎o|B ?"T9TtVC @.oLU'JţmV2\T`V~w>a14`3u8{bϣ!/RhSt\y$7}ps .D)83: ];,0[EO])MpTׂ*[@By ![Sǜ}ubpʟM3A2 1b821[+.f.z$E[ /%A<;Dpg0fO1= ,m?D\J3a KP0(o@CK(T86s&!uHVٓXu?Lpk07.]>;$cBEY5ᐒLKZ *PӲdl'u; sCޜrjDdq.֢dղ%5åb jk]j{ WJ#ڻX0MWJtHR&.%ߒ?(t32Cf&&Rݔ=QEjH_ͰSA+lʔ̢[ZW ОX!o>'4H,Wa+V^ra!M^>kB9)oCInWJ:8z;9{]F?%n^z/#ׇJ,:eL;p4#ì_&>4l)(EK5|;~re#`sOٝ3ջ!@vF975YKǒwF9sfNSJ#@Kw4& hc\5HN\|9(e7\N.9_ձs9}koz>V 6wsVa3edKqw1/- |yEkHq~1p@8 LQ2kjuayj ߖWX'%O`G_Q>5VH])6 >(K3=^="pާZ) D"i{v]l6?#R,?@P E(26dQVd79k ,1͎^"1s͐)ɛJb!DyR%s}1ZXY ~q0ي :.J?V2=@-#\p \6"ҬRqL_~J].*< X.zCch(5̂IР} <|LxlѴU#*,盒Tpœjd0b . 2MɁa59k%jwmwÔ鈭L:x~?'ėY|\6WHown&#ؾy ZH-p6ou=Q[Dg롂 Bb7G9V3nwGFe5 Qi.RmE:`_A p2cڙt0%5Xנ9:π1MOZ{'-394 0*T˧*F'5]QL]'6 HoTݳúNn ܟƳI,of nb"T7oeܚV=ysgU>QB~aΦm ?WCbp鮪(F?<$A!i~)IBqhM\21* X9 äc,TBe+,2 0F8U_ Y6@+G˱qn| C~NQ#Q3c3sLfT) [(!)T遤~E*Hxn2]. 4<(g*;v l }`O 8{ַzsh~ǻn ^Ӂ(]*&i=@ \]z)hv1L3ZPa@R` +ZeQg?&~s=i&eDY5(6톔gK& qQc>PD7{ ؽQk:|R'zP5o34H'1rs00B|>oGe !D6'̾`Ir?6rںuBZ0#$Wm gBbe윚[*ydO:Q;l胥5(IP9 yA,V}Z$r袆]u3VPs xF 6;Q#&_}{.`X(@N O?p w VUur',Q ~u'V3 ypѥ4=JMӍhq~k9+[ U7U|ٽEЫNJ3ϪjToY b4!<OClE{+c ܫ0aoI?_UU&kjo|ڣg"b§UrJH< 65yіw))ӘӯXnD:kHyg]}p\DHC?*+n${‰^}_85|\t*YQDH2{W٥?*Λb5RRw  S|/8W[4W=&j,Kښ &x2=W |􇛹ϤjVOK۔w N¬mC!Z P`*o-W7<` =H:M I -l1 ;^>N:rsNnZ'Wd ۶`e6}DxAMzZ yVG$s أ6bVk}cĶh NR-|v/j{qfE#/|ı.c,ɑʶ]Pw5(>|︾I >w;@#z/jdN^p h.CxX|o\"<ҢRUi?6@\5%E󣕮6?ݠf^^u5 90`<|o"wz@:`΀~û~tCYL޿jSJ*2qަM,m/_ArGf£7'ģgvTq'm )kqmEHm&6smF;49Yʙ;!j{|Neӭv9OAL_BN7oBEZN+ uYM. +a1?Q#y!es6ORl6X BMy,PyS>?Eu9$͜].*ȘrutPxO 喇0|su9ٿan5Ȗ"9G *DxmIM-jIԞw _O=xh@K3Ds}ڶIғ.Q ^[sXn[.ר"/| U4z GX]Lq'1>8Ƹ:}.7b& rMpr7']s$wF#38?N99skw1h9^OhCCFN?L* ǖvJhpX N3GB}];#PU^^O~edjHtUo>["jK/ D?y{P"7]I $Qvl@T*FR̓#<",ˈYku]%ءA(^re0,a&,a0:?C~~ \?]sb)r(QnLե3@(?xF^ L>R oJ*v,!̎}Eڐ(q>f3KN2f'룫tfKN( jq\ZX+y(b֛Ǔ'qf %ڠX ~]7 DzAMb]9GxkKvCAOh+ږOǥ//֚ IȞzMM pC/·8ϛy [5DL; bxT/L>; 6I4zS|(J~~Q5_̄tifi{ vH}Ae '$ Cz!Y5l C=Z)vi7/5#!Lv`dj:zC![̥.cz- R]}Ѐʌj!::=0E" 0I۸L0dҐ}uaus]SZO?$Eaq eTj=4.-J`Z] h;}V |m_ܲ>]< z`1kbc}'W<`Xch8D_ϔ/kz$})?8OFc% ||`.kĦPzX2xSMgh`/Ȓ9Љ T ^Hg,ݘ~'1Χnt2S4gf2{Jn" Gx/A;6gWZ6GDFoOeK ["=]B"p=:"/=Rru+e&iz l`]R&#)q'WR]jpfj;/js8"σ^k_jBs63u 7ͥlT{y8/j:6 ׼- 4}N ^r>p:W05 !Hh:Mӎh[֪Gn=#^W4~A31s{ox-aL7:Md-F֚_G}Zu-_E7?;Xq!:| LzWH1,qQQH#ޑx˜^6b>. `SA8ՂΆΗdxmZW xZnTb9ukж셐_'>]r;fFnUtKK+mXGdfݩt]w4ig(6Ӄ _2MJzLQ2c= _)  A=/Exꁍ6~>+f4;,mE|̜Bz[h3ګhc&R\@NrgxlUHtf%a6`nj{<>_5;ǝ? *7Pג'gׇ* ft/6'R"a ^"ȩR_Br_+:HT`1 P;=d:Á9[R{nt m#wչM x,8I@X] @bcrQP%u|CMREMuIxX LB8~3ԮX'*SM-Ǵ6|jdd=uSTi{6z:ɰITd4uc̘(xb弥ˮn@f]3ْ$~S6}gz ]ٟ. ,C-ZKTLi6a֡&߾&e1u[☦.n7\'uU%ɏحP9sPrD'ɾȂ}R ǩzu'pftoopM֠D?GbJќS9S hjn2N39;4WʬOnԃu!BWzf:!">iE+,8 %]vRڋί6_?eGƤ9"t;o3:C{r-eP!3?By: HzL^piS ˡ{ 9Uy-4U,r"ųյYi^,fYI"_hR\,̈́"!5nKRrAY9AJk0h ifK +~pmI%t@V&O9!cB封{4 u'`*l}c¶I|FP-hUָ@:*QxX*Zvbt{@峈 G{5\,nV&p[[0d@J0)iD歍!bR;ONd~s>hI$ iWk?`Lgt7rc=^oh\G)@ i-~P`ro}dRF@cs77/Eø`2#+9j6{3ϑ 1!nJjΛ/Pd.2i?۲։߉1DzZ&X*{8nc()kEIl),:ŴwD~ҏJYC%ȵvmxpsIA~zc9873UDÍއ*CY3 45J1iC&×FMל YlGF#@s=?RR9?dt}|Ga?hC>mkbuQ0twN ,A [ƪ6ΰ:3AEHtWA~j==b-#;>g8.zkg O1XcD;",pxVD3xA!j)CfEhC8녵bUZȍ,]]xΤJc%9pGTiǜ,Vi'9"&_&)UBJpҬ9>-RiܕF07p Mտ'o M430˫g~u/dnZN(haق)G/DB eh]"YV"t76]~+پb1$ZLy]3wF@-Al/{DvIxga 03%[8x#h@"3 jK $)({>ЂPi`; rݙ @7'r({Fg^/o)G۾ I>A7}00qU8q> :lw0Jd)7?#)KI;v ZD7&s&J怏dAeˎ̶ejgܣ  "b;ROZ.5:;[Уx*S{-*7jXمCH  ڝW滝o@7A=Q td0%,1(Pc\]N.H/vVEH'0 : ̮Š Ky$˕\`,D} t+U#{bWTkEz.R>N*&zWD,펢l!Ml_3pX٥S=+u s- }D+^WБRA5g~}bQzdxmƋ½cd^kiApU PM^[Iw_|RN&p{&'on?\)LrW%£4">ڮx Oԓ[ntgB1Ѳ%kOΓdZ o*CrǂM>cnֽ\Hesb7)xiuٴւu8l%5q)ZWL ,'?<.1V`s ؒ(]͓L"xx-i0T5die;/0* l&҂[Ž>L>B% 5QH+*?aGR~O`E`]t6@W.#Y3FAh4\qzC%2g@}mo&=nZ~~雲Kq)ҠB5}^3q,or. ^Q҉ 6lG~_`f⨀TmU=2{69kCy(P/ս66;$q@ t ZlA T/)zDn1H)x5-lj"ݬP!+:ݸܗ  C,:_{"\K)*6t]sͿ;d-m.^b z@)K/}֬<SͦKdi@u߫_kz1E9qc^`TS-ɐ3Wھ )w!7~ S0}ԇ@B~>I7) ~zf9pv;6~HqZ O<` a lG*Zž!>42%w  !N_TkoRj[xIwY8,Bބ ok.ЉK2 `,q'‰(\'.& N?M(vjgoM$u ) c{7j1잫7Sr{z %gfd>b8HD\!666!!o58Q6MJb6Ws1 Ѩ :̆g֛#~k2܍΢ٺQ@"ih&Xbc_Z>: uҝ;<6k%35ڑ;0oK̰9&%)`fX^$lbXi”bIMMn0WI^Iҳ#jL|%dKWVKFﮖ>, k54* 8g {

UwթD-K;Qm4^i[:>Qb)DKԮЬ5}_'zHqZ5!?Q{`'O֥\BTIc@.iāeF:0h=Bb'!+JCJMuq7]0dKU6_ ~u+զkZHՙcA7Pon%R\(8w[.X%ǃ"tGזxv& B wKnQZRDn#S( eM27p[_Ys <|,}ZY[)+{fh1\$ :wJ&Sȼre7f0 dA~EOiI,hf/Hhwz>Ed= ɬVm@Ru][l@WFP}4 pDEf>JfUV ?[$:mz0h;[6ݠ+?iO>_;XBK8_ x-:Y!E>}bG:]473aL4yV_q #.ΗAq8|,[4/ U˗c毕`/M7{#Bgx'6VQ c9~Ԏ7R\v==ߔ{H 7#9% 9Ubu^QGTyDf ~(5[WV5JJN5iTI4g`Lrd+c,š B( ՘Ǫl?:N6R7 0AS >m}.Qemn*1k -%hRScUN&~_J E=[?FFf-q/m$)($k0(5(x/ Jzx;i+9b@By ]tm\e*yé.M$lY}(f{0 %c+>YWW+cCvpD𰶉p0&R2D1$K|٤t9T+h<#r_#FmiEQh)RfEKX=5pDfG|umN9 lRsӋ]ev)99>`Pnkny"iow&6ƶ.3+5]s0&´B u5% <]R۲"IYьHJ1Ӿ77k7t1MNgg9":~Ww$NY= "=_+/[k2#Ҿs,W\8PЧR5J&! kﺑ" h5cǒB~\+c&yIo_.&w^rW4rjǩyVpBX*O–]9fycj:+mHgϺ(eM~H-a)&T= ̖@WoЬ}H1X2^4lDbHLS['3F.U8#{rqk94 ǚ0aJlB1_<'6L6V&of"|yV F_=񈆉 {31ք EpݾBVk/TsS= zIA(L˛ݫPOfCۜm A<@E)<'^k5:u3*$D3UK1`1 DzO tr%{n`PXXM/2>&;ه3 i'ֽ:@|gd“7U:CBXʤP5v+3&y?%i 旅 !:Nq'vgg䁇6'#֪fփ-c5 ^=#J{meP%Z|P x1sr!+a)t_|JZԀe~ w;xSxd*zK(aANwtᙐ? )C p-B*cBmg@&'{g M VXuKBk Kt'$l;.}㩇d&#R.F -YvIndi LV ڴ"31cX/c(f! \@ hupsI.,.\DڳA0\]*}z9ިV0[}A,ΪaeegИ`ZaȱO TE\%* Cqꍏ`M/8/y b010s!L .+3UIwX1yIq"eQR%Dǖ8dö)"۔O˓GE"ɿ6K 1s.z,TR]A0tGns-J#`@qqH ٙhSRRR5Y5r{ޚh!w ,N)VoWhl]j?.W܋Y(wX5 ^K|l?9%ژlټUk}m짜n-8p>! yҡ۞Z-H˒ag: τ:vgSX endstream endobj 10 0 obj 46401 endobj 11 0 obj << /Name /Im3 /Type /XObject /Length 12 0 R /Filter /FlateDecode /Subtype /Image /Width 2085 /Height 1259 /BitsPerComponent 4 /ColorSpace [/Indexed /DeviceRGB 15 ] /SMask 9 0 R /Mask [0 0] >> stream Ҹjo| oV5| E5ο\u ; ^|;%'ͨۦ7MdY^20C%rhXBE'jV 3Cp- pj^ngϼb-E]{Re`T*0{ٔ)@_ 35 -iHH2@HhV艕3[Vz8R`aV(%_܏cJYDir |Ӓ'~bZV[Y{ق.Y4SX2U;cRmOJddЫtl(J 9'}n-8?0-}Ѫ(>CUfקD޷Ph<@ EHi$*;Vd)&8QNy՟hR3ׅـ+E̠;nGQIl -K$=4O.rpT_GӤ˫(R@Spzaٶ \U_E/R}/mof"ΊۙѦ "s-za1Yq3-pVbɫ!? ~} ec(JeuB]vl2)Nssoo~]&=[ x9ydǎHr$zR(ftU% v${H^̣N9ʴcNxJ巙[FԇgjUx2Ӌ}tq̎ 5Ib>t%Hv>_ XnFl!DzY҅ξcR)gAざ"k@ôO{hCxzV?; Dl6M8FNRnߛ5UNVXF-Ү8|rV4'Fg=xթDQwV/F/TCa/x`e:TC[2VNyҐ H%6h_8L`ŸH '̽ग3T ,b?H˚Hp`$΀ޠYT')&(nT'L5[Ȱw$anDvPVFpA)͟+=XmCF(<{H 1f\!>K\C'7=HoPIؓ(x5T÷Xw,, ~/ hH߇i5]':BE|EcMG OȸvSaE-?tI'c`hU.gzwL͏{7LL[d4eE1?ɷ-a𺆦YCdG3:_žPiHR£o}8a23&cki)+41F"QaOO ohY#]);<6;K[Ez٘0ʔ5E"4M%eEP(B>1R~C"x{!P9r!~Z9b`T=gu(GZ~&Ʈ\`UG(߰FQ?z)k)9i聂cxBWj_Ӫ5Ad剢.- 9Սm:{[(d ɢʐhqL=:;sx*dh"6vA끔ͫP{1(`7rrG,g- c0鋙 , %]D#a*ʁ0P$+Kt=% a<^ޝZ%蜰qCANU|oG/(f a4M,45det|Tku턥ç!J\ Ȫ$xQS0Ǥ 7T ^|xK/xߦs5vy[,R:&2 (iFۧl_$_zDs5oEPoj%lv3ո)G1 }݉)!S 289Ut8Xgd[aZ AԬ o'¶:Ԫ qhÇaj=aѬx[VȏTMLrț~\\5c.K>{9a0=AHD(gv^ƹUרǞ6i.I2 xa^I 1ˤq6l4Y|dž:sȇd~r|Pea5 \|q2]TPu\T (o47xS f4l l'!%\cd/0lZQ% ٤jW.6%дlҋV=VDܺ;팁ݩCzXo=SQw40>kj~,@]k #R Yy~̔Z|>Oco,M(9SSk%Skmϙ5녪m=kA t& /|"WzIWۻZErXp1};O?q\DC74!m+γKu*ɣoO hwi8 D$.J1qDZXPOi^'^QZ'l(&xgQZ <tTo"^Dǫ)fk:.I/N `%ˊR(@O'W^key @vH۪^ZL=$tW|9ڎcN ^ ah߻AXZKpf~Vi!ƂFG:Q(CgM†ÓD^_!w(GkgЬRȷɋW"wc8)?x{i0 #&ghCJ|gX?~ѺɆOUӰaifrnA9hJإICh\s=Q|f8wC s:T# =':f'lkkb}dpqSoS_R7 J~csO QUREa$e|"Wg͖8ZA ,C-gFJ$iw\Q-%U Q2!hE-S. f QIӬRV]e1/ Sa%W Ŀan|9kJdnK$$PAOxzSAuO JtE`y6W \$?pP5aZP?\`rg\0Sa""fg-).DٰbҎ6xNtdع% Tjl7طok*EPI_PRevMAKڞllw6 wI",6(Vl>" a 7sbӉ_G{ʥY6mx1;|OP+=d  ҞL7ycXF=oE|)9AFTB_]]b0YeM ;,T)JMm#I؄TTН%d?s-\5# sªY,", k5Iώh루 He\u)IpBΦ[N嚰8U`ɓ5Fmi)gV9Bs^Eh?[WLV/\sXt:-)/5}\b9dh69 ƅk裴`dE-E)^DJ;0&pm& bF<@>jQUF,OJyktAR7\Vhnx4l.ta6]A G MzhSGО \|٥;a yKZ5˓T>`AT nچSj1`RդQ.(إ7Kia_ױGA ӠIv kTX I2X6- IūIȋ*b{bfӠ7Z:"kFC)%:VuM@F$ Қ;SZu! L\,Ra8w$bN,?IpuA5{Y#oP08NݬZ1] op6B7_ eq:$7hF:(;Zi"ooVIxnYLCeޟ!S9ZX) -Wm==8Pf9rrģ׏* B2THuE`N04hF^#Lqz Rx `ϕUnLvLMsmM+]r/GGgliJjS=9qIo_e{9OO0_F`A1 $32`l4[no%g痐*4,pѮdN)LjhpC2]yjm;̓)FD %~Ga52oFQdC' rc 'i]d@B0:i 3p0qϲ{`}0dK99f6i$H!MaHg{c/[q  #N3*fC`gKB1]:Fz ick?Oc7)dLxǑ.A'p)a̸A8.$FcɦG**U@C>+Ca+FkΈ>1\f//CZ>nᕣN?wM/u񨓌p**_}G Zr>:$Rm7oH$P2@ΎeHsQsjLpdeN8?$ƪQj='ˮaRb-M,c>3|yt8ſKwz2[.{+s%(Č8RyKv!HZ! <+>ln_%f& ~˩WVі^AzwR`:\l+tWha-k_$U2.e/*9)L=l&2+m ~ Ry9T}Y ֭;aX D>GQO4漏Wo@ L;Z~r8&Հu\u&I*Dr)H`ZZH%)aƵJ9wqf=ds!K' ?kpb{fRv%Q,OXKLU7>8$evТK}U83 ^[w&QU 1 . 4cZ\Zbl{Tѹ~+ȃ T?tqQ~3Sc!s< >4 b<%,nNp!c0W`w4+fldx3jsXt[kzAʢk8;{ z҄OrI2uEuҦ"[2]uGK9vƐ"Enm k/Z˴Ԇ#c.b/p{.< yA(&ZYEAa~6b} j+5f܌,`F%qk^v0rFK yo~Y4݊NGAF7uD=|%ݹwh%⣥"1M \9:OuC:$= el1:,]mI@Ozuml`]JLO/5Rep|Bc:‹A%KpH1[ CGB8jG51t,N' Z~.?3nO:wHJJn  HTU0_R}ʬ %o "jNK^p}"RC̖f!5 EWx aDtB?O#aʷ*7܊!UT 4܌Ju$hBŰ3cTr2`ljl܏Qs546QNrcw8d|M^Is: i`Uϟ_0 )o.ݬ/Y /;$vY#k%SIRa'0{u/i?4{OȎ ;GZS5S%Bow[g^C͜B6gESԚ$hY;DYyN fH8^>ԴFSc\'ϻ 'cKpe_@@,*oױ&/aon= @9h~)q>Y[+UL8+r^C3&pLG7pO~p8B`~^[CEU!QOoxɻFil^^k"-Gq -Xz7l{^"7R0CjX[B-o$zFwV7kc6۔2_u15|ʃ6s[59gN vƛwK M@r8wPg{!曦`ޖBa,{%yyCbiR.{/ATTvM Byh(!dd vNùzwH;v221l>9 S=V IK3C0iue sʐ']:Nh:H 5ѪίN$˖+b>$pZB/b۔'Čh&w@TFMB[Aj$䯌u &^LθLnędJ TXY$~.U}&n7-hB0"ҭCy.;XEo2@N`wĈVnϊ#&>=a8vRh֮3̶#kFdCI-F $m9'&Kx̂p@ Ĥꇴ&Eub1X~h=0Iy0H4Wl_bB>}[5Vg^W?˛,\ڄ|g陃 xE䩬II=yʉHߞd%AViWnnS\:J”O rx"/GK\vHyFɹ Á$+[vg8OWi*dQYY  |^k3!"X: u2 ޑ9/`I&@qq?J9<"Zn CX1 ڹzK<'wdy<=݂2$va.WZZ6U01I 2G4oA⃡DnS$Oe"qCIe'2yuacG񌒳6{͒~+C/JZ7`gS#Dw#OOhQD6~]FKp2E:tb;fjm B}9O&fvٔOF6ޥ3Su^=\rx=d@byxDGI% Y|;(]t v4>DŒyQR4(#^8V̭U(| 3\BVdbwDIT"roxザU:=YN)5fNLvt*1 M%{VRx2QXG[MŎ ލj+-R.=KԺ).cu4TtZW1A-W!(H?J7 XF "NqpP)a%wZak^3@BYd>Z!DL-d"}Ç\r%ML:lY$+*2J] \OI2zǟw+?L*G@YnbS!_1䋭:2엔f׈}>##͹رɔGȘ=N'#wf{˜VUÜ-M?$k+s[wQ_C`+J`{8 U:N !hb?$5a)ld:Y)t/]E'hn+]9MmPNH\o3ȫ e`, {ft`{zzyuoFJw I޳P ӳi/=#)4ؖX.Yf?YiG{ @K"ey԰q1- ȎRo8J{ Uyk*6ڛvD/ 4eJ-ul:)? C9m+n҉YW'YN&Z;]NJ-::/$S'7zʅ'xNcPʕ!Cf˻9,HÇGq78,tpHH5K$9woQyvM=D,NmNiDuqLAOMi'@gֻծ2+6)"kprno_H=oA,(aq-ו[u/kpSdf_)'Hy)PӴ6 W=I3w5I|h&2eB̿n]eԙ__OuDwݾV^&y.Ƨf[5@1g~T|aaq P92'E hO_:J,ֳ-nzIKwA v;T0͢ϩyzq/޳˙gaW"Oo]~BNEF2j0 T t~_þwXe:Jrޕ^Yps5*N\?-6Mܕnl%?v&\𔁦g W@.nz Y^VboZi"%d Wf!aQH h=O0EA*9:eȸ/Cu[߭j)ku>}AWzdwQPR_j<\+3MfMދP.nu!01\,?#`aI[?v-%xz$8vjpYFۖj=@\9δOEjD iË ߿$}'Y7\<=Df/j̀ M2.#.ro6{Ā#/g8ݻ6-<0yqILM54PI=^f }ic0qվ@R _ ѹkcQrQ9wL6N#3@/ Ҍ`Mz~ME&u1ktk6hHN0ϱ_EShzy@f=T8"?R= $j~U".ł0MF~yWG3rBG1*>mxas @$] B:T׉h(D(wV~R~G\j퐾] bի}l. !VVq{&L9ҦuËnVx8pt|ZV菔v}-O)u @q6*+bSDGԮ.$*jiݟ? = ϹϞ&VŸ S>p⒔l t,Ɍ G 7 _r*)rGCC.9XU /3CͪmˋMA,$(42]VZ ƒCU5A@Fd/y̓?v2jިPݴ+Wer+ķ|4zHy#$-Ӿ>:Սa?.]g"*5RS/.̇!<@C ^x?y[5x7sCF&w ,dEҧp?غe_23~*ȉx<8Ƌy| ~j)uM1%$Eca!33%DtbMM}>g$]K?7v 1H7\&U;z@j-F.0"'gi#r"J rdbY|ex|Y-J!FI%:0%>';Q lJF$Թ 66ehip [CS븤wRF!\迏^rP(//9jU(&_:O1ڗQ%O:C٫"iSBuQ-z#<]W'׍2Wozkه.cAɮǤ 0a,Ӵ 6 FҮa֤A& ؾ1|8Fl@@{,2۴;k(ilƸҞܡ­و)o{DAcycLnX@Ҫ-5GˣT-jMg5Am/Rz:+y"2l{\^uLNGJ2~zXQSZɛT-Y oLz[}GstJ*]3ǎwzt2Dĕ ?J$;0Ul"U?v{9뉁݅x[u49 E A** Jz4>:T/Sڥou ZAaU.|ƉҔ^|Eь+֐\ƮT t+pY9\_Tr1T{XҮM3d`8A?FH'W2.saSE-X(iԩiz R Sº,pjܜD]s8>3)8{]bWFOqUs*B R@?cgKMWyPsK#]eW(ī 6:'4$,mu~%co=O+ Q>}&Rs?.ƍH_l͎rgȃ?&vc-嵻?J`^ސ8a1E6FJ?vru!|͜N'Qr.a:式iC03O.J_7gRKW}rPwT/l W B0G^ ԰Hf``Gھ{a.߻_%Cj&w'8sPPB_`vJF1AIa@'ըw,=j֒v '0@c!f}SE'166/op}@bH cN/4DȮe#q_Qg1AsmPy~J>eGN5j;?f\#ɑ͕8S Fq3X| esrK26C .V5,+{a Hc74`>x4o/n1CADTJ8FzKS^^*#ǸP!uƒmz'bT0cpZTOR6n\f/ :=.;G^ R/!i !9<<91i?ZNmߕ̢(2[݊$;׀&٭z)iz2CyXrLgG|)x_O] sK F&ʄ^?' 2マ+-PעtP۶5UreIz]n %olu M|7. #C ,kՖcwLJBݣz{%mz;{=H^ŞRp|o/~[-fJ=xhhOD6`SN̢ߨsIRM;&36`!L?D(LC ソs71Y3VAQr-z϶R~KT<0NZUG$rUVuQ8)p.A:Z@p`?s-.ӧ+J%)&:w,:Z?%k{zSFp̚R]YAQEq(* {'uXN4z{Ep2})ikj?A-~z- OlWGUKZI}+AS’< @_^K#hMH=Q%&pشXՔ'QJ4Lek5kezm C !sj[Дf7S&'"Esr:iPl$wYRɗLh]+  l=+y~bIuFv ^Z-"54픹JA&Bʞy5Ko%(l GVvdwެsP4v6|v!??bnwi^+!ߚvپ^sL_Rq5I_[N/TMl0B1NH!nN8oWUWTAR).+9bg~6ܯg4#:0A_y2>B67p]H`|xEMvX29p''^bpg;̝*d ̰8 u=hNh˱a'l~_Oo/ egǀ;\p'R1<'J-l>ã8 `FYc4Vo"84m( "5t C$F(# k&|ВqK|T޳ A-݈TuMwc7RbR? bRiOm飶P0̊KVD`-br4ߚ0Jx LZnR-˫,Y~jz_rd22E'NO4rL!YVDUSP\W^OS2*9`ZZD!B4i䈢!+*;. ={&᪜˥B|jhƑ0)GQ$;-!@0}ٝcxΛ\eԘJ.R~أ%R<]v^Nur[}[i~"^R¬1+w`ͮ<8d;5_L滎uD+q4Q@+nX'-OƁt;طz 4͊ T83g 4u1K&Gbu!s瀒z̀IU[잁 ׎: <]QPoqi6\|UyS0MJTQrq(_K-Ot^`V$i|5AO /WZLJw6U#V)[ UJgkL]Byp6"ڦ# H`"-7?IdRck\*mJ//†8Xaeou[$M%H.4CN9bQUwU\k_}.̐hzTD#qǾ*7 o\AHE;-=]}+g*F79Ykp\"!n t^gMm,?ZkZ*mA :E4QL)!G֟cv|!(ѱFQ鑶AOyg`VnS9yؾ̵L:ü~>(h AMnqPw|i#IOG}2#ϐPwE5'H}.||;y/q(-u7o>E ܪO ]SzK8N0p¯TAt?v?* 9sZ X&MEO+{FS@ɰ0٣k/BǮ$䇡\5[.n$!5RI+Y=bh_`z6 0EL?K:č򱰯ص 5X6Ҏ5CŮY_+Yn':C>zXTܯR) _琅[*J)A&ȗ~'\$=ɋo;2މ9`,^֓ Lsω!=xʆ{̄g}b]!Y8ӏ$ѧŻwJͫƃGC~2Hs±5|41#fRbZ!-F~`rOϛ/>fQbҕ&U2{#yyN"$ʞ,I2VV)2V V Q}ߵDQ!LsCIҡєKn%Щ4jg{ۇR! qmHE&k,H;.8[qw5KyqF^QɰUĚvx8Lo ᦍTS< 訓ϒZu뽽gw_* rTN{9ZwsrCb¬˿_kK{#r"zh9Sq dlI{xhA?NTd@-ɗPKE$ 1򿯼uPVܳ^hĮ I" {.e-TNNqIvd0y'?m'Č%*J؋ƎfIUO12NUS&Z$۵CwKK׶gy8-7[ֿʻUvO_ٷ/6H:WC[J|$Kn]4wl22Xf7x:C$vn^5AZ $GTf~iXzi yvxJư,[Ca2_g$x EL>%"|W, a*:mzWP4{Fbt}P#绩xz.Ҫ}TړtL?(eMP<웜f bXeQ\}Zo'5YІR&cV*CVpeiS⓪ ڮ\N҃se ;3 gJIGBZ=Өą0qhQWŬ iT|ތ!iWq=cRm҂=YgD Z`nxpѥ#²1ӏ N/z!X.Jf^ E}6.mfT袏h)"Gx5TqS1d_\%wT죗m>Ih19\IVXS-B"|kGA>֒BF%|&}S RTdq6[.J9|dluv+H4 &s,1AvޘU5}hEG*%B?"ycG;n>Bcy&Ԭ*vHO[NPص2.#S5NБQD!{CP:fwMwOXi_f\RlN>>bٯJQm~m-~`s\Ơ :X^0,M#eq5( (o4V爓x7触Uї\vn^5nC#ֿ?1#Nx}% +-3|2 A"[+SzUU<)fhe&uU1J=vY(&Uj Z@K{ D~DfHx$%^x!mFGEo+qO6=W7ڡ)Xn6>0UXe%1ղEtvo pnSAIYwK>:+ݹF ZaQ\6˲_G-47._ ggC5kĄY08sߖV|%ÄO t5J&_0Nz5 4z&:0wHTZh-e٬d-yJF J!hv GS'~w LWZ*} g <Njtڻ')ǦE+ YԚRVQ>ňXj5wA *JuF/9c}ѹU/9;rD-=@&0/n3$RywF휝>2X CvA)y)3]:- Fb'ߵTVpm?T X!CH12F5V_rx~t8P=R>Q)\~w2NPM><ý %J;.VYp:3v4ʗ?YL8m ,r>qF:Yhyp[+WI#u!xl#G2.dw>hTw9XnEv?>ue ܜw(Xrҝ`$b1Fpg>xdBW:{k_W]a8Ο '׏!E#ұCl{%Sy';!ͦuP5(ˉJ[h j~' VBQu[$ &mX/EwT+ՁQRc3&i7-tzT.|,OZ! 55Y28:u8Cq۷^# *2K_6ˌ5g >)(P:Zf^ "^Q;)CHV3>S{yr LNyezEu*ldx=k[Jz~ +iз#JaJ/ŒXoA`j t eh1wԍ |u+@,8XDͥ)MN-/9gYx,O+z߮TcTVI J}`\e`5HC^:IܪKIsc3 \Lj7}$ΡɞNyOnXYIuJ;_O|ƥi8'C§XՐݮw7Se@0n؉R;(m"`g8_ֆRUߚIF5FqHWp-$9eS@IzLjyr>*[xojJ`>(6 T^Cq X*~-`eə'St$oNW3zs9 j)kz_Cgj87tA p4v;΅IscRc!fɃI@Y*aKK 0˿T%ey0~$J,vn>";k~[pIgmjVD69zoİr[UzXj~Hz3Ygf-5ܵ|bxEE^Lj:ګUf9S\?=C |*1iFz:mjd@WigK ,SѽJVyEjD[ܪ̿myFrþIMD9Z8/뛪Z!K5ӐCS "y3aJԮ_ߟwKLUVOXasZ)'a<&P왰x(Sa~Z!r"H{C"ܦsG cRt3Tn1*⮶y@xWc0Cj ZjˋM06,e Fњ&?ΡE($;I0\ Z߯)&Mh%\ =`wZ o˸L#D/R+{UϻNjưTtA4v 5rp#zcatL 9s`"IeEi>e[ Q*.9!k_廄[wE918@$RPmFH\mJ{ ep:d@ 'lg,/d{_x e[}4  rBs;4 z[&:)'KKF{BmsְV+Կ,InrBQD0&v`"ǀAĖi8lXJ]=&W 0'L5n3oRA}2I<Jw9Ԯr)Zb!ܧzX^SY PCcuF ҧ5a_'q |׷R¶n3Y&1g2lEi(Z$'K؆]|.^PQ.'#y*1omZaeV(kFto̻T@ pÌJ[-֗lodxrsP7!Nlf[f<\k3RX"H)]dj JuSIܙG搷RI"isY.eT  s6 2m5RA #Y)ɲ5<v/.!rˇU!)+3T獝2Y]tOhXgɟh-E}1'W\=mMzrijg6"r`){%HaU+bC;*m3e h}m5^0=lnS(hvS|Bw0ݩ4rkE/GIA L V"3 u783#㨺fZS] Bu{cm1J |ƌ w"r%B(\Y؞gM)e:ILrq7Xw9-MKI -POEpr^7'2ڑ7=GR yAW(:Bǐ[]ZgN@?%rn <`LW1]0Pno#R_q\Ga^~\Vv )4"+c`7kJWQj!=V o J1yE6+WU'd=s{ 7äX8t`Vk clNwu҃5,L+ɍ蝷3 (" h)umra2Uίp Ik#m)r`T܉A̟`ۊZ2-L#dª I*v[@_XilKfWԼ<>%e eӑ☾ɝr&<$ܵqN '(@-Ҿ~[Kּf=`tp nq;ndWr1@Wxܟŧܰ!B+!) C|52,GT-Pj,<5A 20r`aR:t!UzVB8#Vמ"b3ĸb %gEDebsptA :Yx@:KppqbIX1P u- hor1rGyrVWࡑK,q%dhBo_'"ߙs=y)ӧ79(D T,pg!c"$ TvuF󝠂N ~ KŘ|0)ڠ}Tig۞Ud$D}a],s.n"\<AftJ==4(C?ow5T%f'A ^q?yвalʟ!ObϬnmmF}5C:Ѳ8BTբ7Tj ]vEЉ_xLk]>h8?Turlu)>įM[aQjdF}6[;V"R ` 'AzNe DVpšKm|W Z!0̃Rtx@ h] )wg-w`mb$q^ئw|⇐zEU:/`~HjO2UrI*y7ܩ.Mzݮ/;+$~6`TJ,R+Jv>Ϛ: \RgkڅD\l)<,5|r8|bY>v7\wn\;t)l(\W"~%@7\R[s[s Caca&ZDĂꏇM@*v6Da"xCfLAoQAsOL-Ƙ!lMk}*ck<N)\$Z}*62v01=nmWm$'ݞbЩ,b[-҆CLm> ?mr45 (pWХ@*4~EIh:v_oՓ(>wO}T@xSXke%|=!cCvpnw6þU!LksO09nS>l?B^3x2yRM0:5k4EK]9pZGg$:\ [JU3¤n,iP3]Mt)(ӗ2w NEz]",0S[t7L 6B`{=|_-~>)ZP@ցxtƩ&%~b͔ᨮM?7պ|ͫ]ZCvk yXX {- ,:PԊW6$d>V{;s4~D2r杴Gc5BvoL2hVgͩ˗x$3yGsF!43٨׷} -3$pB7kVq-6Qt0ߺ7Tϡ悻6an0ͽj-\9/i+AYd:ڏH>n1r~ $*jOy:Z, 5tdZW@A*6ZB);nu}p@WaѰPoMՎۗprw(4:xqv07=-Xg%DzhzQ4̒1AB|^!Bzh;iؙ| ,y4-όxT$%@cnsVǦ idk%|a0DMQ}D@a5c`A("?/ZC?*gڒ1(U z Up=$ZM'18ȟ'x9'3ߒDaAP}M,QmSl#0Vce*VQ'ロt*x uFt>@~.4X&V-by3Et1>qj2o&m(+:P6r{F[΀WK)OWug$tŅNtKddKkYc:(4~?I5KoUˆHGVOx:o;"ec!ͮVUT+qب΄:u+\C29ݨcyzKEh$tW]Ma~;!_ )2G? x 7T;ߎ  9ɞ$wG*c_^aWOT-+J\Ǧ-!#+ ʨoV7eQ+&;r,$6ָ_P{4$w*zrB+6nKm/B#ѨU˂;^ν_cK;\@R.Rsg*DZU2=t 1_a(3dB>qծA(CK| N$^5<' F |"SM4>-rCfQ}:y$}Ȇ_Rsߔh悀J ͜.j)suOqLEHΥRןnS xv-h2S_c衜Apѧ"Ygd)pLk-IW[+W{Q/ E(kֿm9φ8K,6g 4/MAP jG+_O *?!Y![!Q L7L%6p?1w䷍>O4pT&7䰏HdsFXٯs‡Y.;xPYTD:T~0Zc_䨃M0#Sޮ2 *F0548I(8 (ވ\EKH`t.|BEL9d"R  [BYgc| u/iٞb'3lLdZh8q|q ./ؕY7PPVL.Y5q5j5E: )T[{[54Z_A2iWcyフ 9"sy,e"#ZP2i)QCAͅx=sܳ3o?8*װ8*F4M\*b5@~Al!_d{_'Ⱥ>yFO 1{,m$r zAё̑RgQ&hV)Iy_&WY EdA[Wk?vvu2קIAً\&=MISωl'oPE=<,Ž6f#FSy hIP#ze)2?20%#v{E)X .^M xHMY/'9yG"VLz~ aU"T@UdJxcHc~~uZ*By~LL_rމ$&!S{D= ͜X'E.Om\twP @tV]"̌"*Dc3 T MA<˛cm;b8⅌sy;b}ײ`a{0. CnOPpɎߝϳ,LwT Ia[I1 |T_ sVr_ a :Pڻ)N.d  E?@0i#ady3D˪R;Zusafw/? _ &S8:x(s|QeQ < 25B8|I, fyvErf4 )rʼ(rk*Ed( %8*=_bשpY7y(L fwA+} #~).WyTR-kgHYm#R;[盺</InQlwe}ĶFz,|P566 P(M.P:S ޼k0܂d#:S:t@0^c&܏oWfh[B,(x(]b}3}45nGuN@aXG'e,)Ð.<EeS+ =Ң2qLJ5o>m=NU+Ucdψ(!$,/2H*^&Qܞ/3pdno^Lܑd#KcHB_n '1\42j%-[Ƽ_d,#|\,1%>SQ#k:l0ܰNi%%Ckt:!G/++Pr$L$売( k~ -(ʪBa6J4bH M2\V H ΐ–`puO1ͼK,&Z Kk gNtwb(uόa`0'CT?ˎ>Ȩ%'XQXj,;ib|w//+~}< $R>oH}qĠ{f qcixM)lvᕬ,4΃2ڰ5Q2Grb؏%`B< BzX\@i/'EzpY ^QEKIQfʕl$V83K݊fD?и3ρL_|:,h\i8__֌u %epRaHO Η YMS宧pKq~fGRdl80 "&ai⍖ŽI#ӭnq:|>$|n">*! {(c#@)HsTY_钰mʽQ>69Uvp[ZMzjPԔNH<}^~NVsQH[ BϟZ񧫒ƛÊ/e#\WŽ%LɩR>wޤ/$5dGL.<ڐeИᥗGy*Lq\K$1~2; r o̮CUbHB-zƭ3-e)F Y-5;0K\NstRBcP!KQS W2R?ĥlY}]NV"D3FӰ%G?*z4|wl(sń}"^N,^ʗkͬ/1jRs)ǚQo%vңȪA#WW*h gB>#0bqlӎG(BP 3B{# ؓlG#ak .үq7̅`9QG a fE}gDy*pg}gJ ce4y~ 3c1 }֛xNFMUwuRG!K,& #jq!EZ q3_zvn7Z#g3BW ,ďL|9PR$-@UW# 5)eHz${Z|vQZǠ̪`;ksAj1$?%\&^+.Y=ڕmoW1 !p1ca&dg ў@l0߿gUx1xثUGk>51ѪAd1\ YKlMLo14J!tNƢatBxBIԈ*jRnT@ 8`r=~@C18?/t8%wOo.Q}Χ}&Ÿ>_-z 1Uro.8Eͧhmjxi6Zo:c IE w;v2c[ơuPF} ~cmI˫ᷰ_XXJp!b_%^"!.HKM1Mrm"=e/{} ㉠ԑ?<;$[ tґYc-!/:LHjg:QRˆR8 Ea`Ѥ, hfn[ٖ\ ϓ#8ɳլު93` *I T: FFsuFV樲%I _0 w_ 0i: u{ pa 3"Q.X55J-m&RTa_-[da ɝ, n^ <޾'nWP@4l2x+jY52w=ߌFtH$7c$>L'4Za{;k{9jWB]It6 #`eeI %гcb4%:? (ɠJ9ru%{gEEt|NHDN,0͢Tho2/HIŊi*W*EU/%K7<3'obk œ3Y5Z)M˱$'TLJakbxoS!w>cz@bQ:5w(톃Mb|X ZNSFKt$xr=YaD+#upol i+F2d?pD*VHa94rK\ @q):r/5ӄǙ^濃јmoL5D3FK1|2.x΀Mu JI>U> S_I_bGGӰXҧM/ZUO~2(10 cM vp D׆({ 4QHM X|ƢM`]/1űj}p6w:ke(E؂LX'mtaW"QA  28H\p[~h&DkYMU4 LV7/6GhH.-m`kTn)8 pFu+1D_NE|s5;D f_#A?qA#(G^)uͦ4z ?u7k~1] kQ_yX.}B 2@nUQMDJD32y:3X{ɩ Y6 I(s>C>w!?DI.2ᄷVāH?* p5[; 'z`Z>@A c^N16#+m"ϑJ+h6IA;Q9e^@/*6Zg=@=PLS1EYٺN+T{L+"Z yT!)#0` REC$I[Z`) ~n&MFoMi-NCϯ285@ge F&U͓RkXdElä|L iH޿#9Vay21G,>\?˘Gi牍Mi"TIe%=^w6t\%&D$ǘ\*P-vjX{ [WCvk:|!YEryl.9qʅTۀVɃqQCn<~~E>%Nad׌5JNJ׎~뫮_Oٯ?ӂqn=$bʤpVb+sx(]\] vqDM~h e9E&9v/ yGA=R1W Ҋg\~09>>@kK)l:N5LG|{ ^5<XㄉYM6"쎥$%2 hGG^ԩH aVOD)m=*1_i!("eay/f@WEC)HcĈA1bfg>1pZĺ*f~i\f6]JPW~qt/ꚲ$gm0hoާs$u +*}XD ^U(L0CIӱO rabHᕠ@oq5->-U04~@@:_nV݄in[qlyz[! 4oO_2BF9> _rj(\~8KpE ˤa kU2M#Ah| f$1UtYEU6J fC%5b(.]nL5 %&hKF[w(rrd, 9jڢI9sK f^> F4 S,9V¯/dMA!֡H鹻\^s޳ub[j7o^E rK[10 \]/62ɔ)r!r# #nGettX&ΪLSGzG(Wj2g?J VsdU8/fAHWTrS+ ]ُ"0$,4nN7<2TQ)IsItkc tg`u+); L.; YWr+^{^Qe /-""2~Hr@6͘|jb,O?g 8^Q]ʣNC{u9E< P[+aߟ:T)#:#t2=x?@sH)yE bR1Gv(8{g5xM8pT?ib[s;A쇭lo]Q;eݪ1qQ)AKE Hjewÿ8$K-p nN!GY=%뷏lPvJ"ybHɱ|[c~0?I7f˺~j쾬]Bga(s̟wX-YZqVQ>#"w]߇[ǰp #Wc+EQ{ۨ(pA0e@i[{um\7=Ȝm K&8a _E{ q: mi.wz| t]{tPKd;j҄g eӹשq$L .I{@0?KF{pGD!pN$G"g?g}7&ac()1ߠ{k`zIm1_Sg9P4{# P;A>{Zӫ0,L.lbAp]Mc=Wy%t#ȰJF0Q]B.r7 _I^fQW\leլywxtE(NBsI}cAUlxU3w/y6 9_2.J6\IJ8]mng[RbbB9ӾcЙzKQ2B-|bkB5f;C+ay>?Ç-;`kӿU)*6 P=,@Q7'kS[ m^65F#kN:) Th(DIy-djy2L%iLnğ|eھ. B-gmnHt iEj(K~#TjmR ISޯlh c>XzYLs& z` ZiKT=KIf~39#w3|֡(S5;\W2\`5k6w4n}T;YYcwgGɩ8CzwsExcrips$:; N{I';oLk@&DS^sY!+5}~' sěT԰Ȣ~оj$92 JD/4 <jS@ec>?M9QⓖmEq\Uk=u׮*Ҙ^F3=ȴ%D-etX( :aF7#"qPTuU!uH4 E1njq;2܋ႃ5;* y\&@7ןXd޺Y(E(iihGVvŒo9S3 eۈPf-B ?HiF1~*R !vt>@bjXf-_\ lv޻@w-`M^SpPy~QH"{YW`-o.&'oiYyA]¢qZ -x ӥ/+OٰJJ>.1_drQg i{xìBT< u'_[04؉B;0<1ձϐ&P+:&oA6Ljd"q7? qfȃr" ʏDyo'Rwdρ r6!T5 ey(/-j755B IiۂRwK oY4oo]{0}\پɮ7I2'!t۽X.gñ{+;k<||1r5Lc`\f]O\f4eS  e!,= TRTp/R"J!3jz ƥT2^9L)K!a13eۚ.Bq@B. l@ʩEI9Rwelֽ@ݐ̆+b'Pٔ0UwXc3o't?{ ',&7q5.8_?g."|(0c:dU*%;V~?iӀ.d'^lQLmiSdM c\'vމziX>)u7mk W&U.~;8Amm)Q0`J}Q$]ڔ6m& h82i\ y_rZgD=E;S )>RD>dotKμ#0} |y>l%dDִ]4wܫ>ug'DТ걮#E'Dj_q4 pڴ _xSuX5Y||Y1Bcc'>pr'CH n׾ N\/pt-QZ0ׅJJ!oa}i>] `jzRo? ުҎ}"vefy e(|"+H w_3iW<02iz='(} T 7ʊ;VA?0pq1NBnyJ'&!kh躢R`x.AY_|fJdʭt㷧\F0y*Sȩf@$z KSۚ Oq-ucڕAU;1bW8-f]=/@1`꟭Isdn3res?+T.R5ܐ`~&j.aQyG2_hH, cOerB[q (>ӘQF' ; xeѿONlI7{Ι5J^.0(O4Wբ?ǚ{/\$ekNf$&Z>88uzdeK#Z([Ĝw^% 88O˹h(,f/\ȚwԼa> PGLl{rY7dD̤yИ%bYЍGaxu7)0s ǥ$󥖲^CZNE<@蓧}h=6 ᴦ]}veXȊcm?e-7 c$%B )[ʖR h\"Pp\S:!WcA.;!Wv H.݌aPd*}Ȅ"rXUfvrJT<O鷓HDS{LWSRz&K1$ NskK+K7OW}'gaq ڠ٪R- (\ag ,X6Xl-t`]BoHclkLGE) B\g퐓Dee(N]V*[!,Tz0h]> stream 3llqGZ>ҷ a@i{-Qaь^Ѡ%@WÕ˰CMƁIv-qΫq?-Z=/Jp+&籍 BFUz_@LfXG7~h=oң<(߿2R1>? s~Ԋ\"Ɋt1H%i3" PW23Xe7*bR=; v5FRT]R+5O~/,~* jp Vrd2@p(]0zl9(p࿾> endobj 18 0 obj << /Length 19 0 R /Filter /FlateDecode >> stream Vᣬ tByHj~n4b& $[6⃓*=mx6햘&!X:9Ԙ e!Q뢼ll6b 8CB–|~n)zu@!Chi.R">{>QY'bt(SOGQR/=RHz@%>KHf{lwq 3'XK+}qkZ(%ڑH`<4ԎQ[O0k|S dQv2{oƆc@K%F:ՔG^) M5z}5 1j]Tp],ۊ !yn.LtoXwZj2}t'%bTS=[$#!{sV1uސE)h]G_ ~L,0i?٣DX[Nn# y'\V]Ōf 1\JS6pj(Bu-+D_]9sϳs\ X֎mc:Uyp/]_22r5:z2s<'|{M9;7G|l1&&.avE9A\M):ժIzpN/I 2+S0L1\'_+ (C!,a|yl {k_6G $>QN~ M*vU 3X'UɤQ4Z8+˺Q^ȵ#*.+{}QB 9U 5iP$؏F3}qFegL# e j[D=ׂ֟q~@fF(>lVf4a%Š8}Grׄ~0/FnbĠEģpY q2_V͟++UFS4&jbbl£Y/`)t4JKEHb\B?(ϒC 񵭾+X>AUF968wf̘+1P(SNsST=;|@}齳za݃{ʕo{YbۻB# ZzbH 0ސ8^:H&z/WFM;&+Gn-22|t'uld7:DwC`UBM (p}S8mu0pJ+O&#hA亂\ [:L} &\yqD$F[ #s`tZy5c^0R&6Vgm1苙4rG/TTɮhVSzi t{+smB]I[, p w0ڂiS`~“/AKo)7TiEqM D`qym\v\5YRƎJRq&<~bh(tIr+!=KcYZ wj{HjvLmE"W<Т(z>M| .@doFѫvo3]CjUu%E<<{8s7FAl7 @-m˅9HKE!vFIq)#U'H~}|$V|5qHM Ա,HhiV TNt>|Y"Vks|Z|GE/l: B1!՟Hw@r.lon:NCQU2ы0L=X{긞Ma-V#%Z;|hd^uZWǒ>yf?ńD܉k endstream endobj 19 0 obj 3037 endobj 20 0 obj << /Resources 16 0 R /Type /Page /MediaBox [0 0 595.275 841.889] /CropBox [0 0 595.275 841.889] /BleedBox [0 0 595.275 841.889] /TrimBox [0 0 595.275 841.889] /Parent 17 0 R /Contents 18 0 R >> endobj 21 0 obj << /Name /Im4 /Type /XObject /Length 22 0 R /Filter /FlateDecode /Subtype /Image /Width 51 /Height 51 /BitsPerComponent 8 /ColorSpace /DeviceGray >> stream ܑIgbNkX(F|:sG,Jc{wL2:jJOP^=fYyw641" IL8]ܬG`TDr^5=bVo<7K[cqFTa=ɂD&VNFYq0"B]-Vq  ua5PB- u=JA tala j$Oe" q (ơa[ByPRym1k6 럣gTyk[D<ɵpf9F5Z, kj @]ۚnhUJ~v~AUB, ayVQr@ԯ6F ^%p(*Esr:hϠgP͗5CO(3mJ%"b3XFؕT 8 eu<.`ٍRSx8NN YB?f 6RІ#v%Av֬g2!D_+Z`1>ۍ~tNJ3KX#=|5S^U0aqop`:Df|ߒ{g2[Eh)(YpOĖ"Vrg&"W!fAI*67~NdGl*% J5k>G;R~ ĜUJO 02D{@${|\$?-:NV\ ESr^t.KF.( u [t2}ˆټ ˤ"(S#7f|աkڍ> stream &݀lf½RF3: oJyG5kB;C'dha= Yz&D.ܨj18k:u G q`Tg5k9@<컬/أMq +wCd/|We8,$qƾ"{)arL??u' AX_w~sR򤏁FZ'd1$8(t91trӢabVA SzvMH0ǹ;,چ-s@Aةh3`xߖ?? "<;Cf*G$`cA Wm.CM4S~b`'ٿ3R;C{ 4F?>q"Nժ Z4Yu :,yѹst:/KaNM׍%[tsBǓ xQϲΫt;1?5{O;IMtG6>=ᕹP-5>eՈҤLi~ ?WXGq*Rs6okG_jE]MgF%m`\5 ]/WR=Γ2cx6.*cŰ'`=š0%{\3Gzτ'0"z 6Ǧ;w%:^b72J=_uH%3w*GF\ԙի!œޑ1%Ndjey@`3rifdDy/ƹcW })$A"S]m(BPjnIm('.C,8';$vn_qؑ)CN0 Qk_`SKځZC_p+X+LpLȣSgKBP[ 5gdW2 , endstream endobj 24 0 obj 1484 endobj 25 0 obj << /URI <1282D2AF42EF998E74992BD0D61CE4BDCDEF9923B899F4FB34F588E1AF1EF8F406EA827ECF9188F6E3F0CA> /S /URI >> endobj 26 0 obj << /Type /Annot /Subtype /Link /Rect [ 74.732 458.315 102.782 468.633 ] /C [ 0 0 0 ] /Border [ 0 0 0 ] /A 25 0 R /H /I >> endobj 27 0 obj << /URI /S /URI >> endobj 28 0 obj << /Type /Annot /Subtype /Link /Rect [ 263.668 458.315 450.228 468.633 ] /C [ 0 0 0 ] /Border [ 0 0 0 ] /A 27 0 R /H /I >> endobj 29 0 obj << /Type /Annot /Subtype /Link /Rect [ 131.206 441.308 159.256 451.626 ] /C [ 0 0 0 ] /Border [ 0 0 0 ] /A 25 0 R /H /I >> endobj 30 0 obj << /URI /S /URI >> endobj 31 0 obj << /Type /Annot /Subtype /Link /Rect [ 263.514 441.308 458.632 451.626 ] /C [ 0 0 0 ] /Border [ 0 0 0 ] /A 30 0 R /H /I >> endobj 32 0 obj << /Length 33 0 R /Filter /FlateDecode >> stream l `(i-[0jM([RipstFC*'P AwvtL-=N0C:c{{:Vk\~esqaLutRwyNo|TfLX3^(37nk_BK'A3"oj;啔ޭ>> iЯNԓx<1j!ѯ&(Ad4JKѠ8ȗ;& #MT0^?=okPR(ljpe>]SjΣq;y|t"n<$ߏ4B˜z`*\,Fp4/Gp ˾}q*~3Pi)xIAkvMAΫw ) 9> a%vGl]$K)_(IjlNR\J1#&_䆛 3FҠC;pHpz/v tGSq^zG$lx[ 'G*zM|DjZBcJY 7dCd7"P7w ;LxJ62DgOy_McUsv֘4{ٞY>(d7w< O:Ius[1dIAI: C2N9CF?F\q $U:u|jH'7)Jki8O?χkF:16t7J ,, آ^<<4 ~*κDSS"H_ADsMg*?VYvzt7xN/=2oJmh4q|)Zi|ߺhK.̿վzb8*w}H|#Y-f 36,]YQ#Vɝ^$$,(I`?ywdIa!څx牴*~d~\Ǝ{9O, )iϾx j3ZxD#ITҐwϑ?? 4"ZW0+`)&Bˁpt6چ.['Z7TP枒-.f53#KNϯ쇶E.Od7 0!EmL1 57ߧW6O@D%+ƹz2w{lVb'. ZL*f)7 {2i@Q^fO`ӁBqҨZ ɆkW{!TipU B]Ĩ1[l{ABӌo|lp!j} $kygsLh#V~uGplg} 9PBxwUr]H{zo,{Z3i=U0ND@Bjd(H͜u$߃m;7i#PJp[s\u5MQԧOt|kngRݢu{GS\nNl[VyrңpÊŬVﻝB jYk߻O"Wx'#'w=)n}qpJUQ_ \*esc u{%0#˫'~YMڭ:\̌F*O ӟKrSa+>*a:-3bc9vs.Z;L0ܻZ47g&LLv@}ۖ«`r!L;%^}D > endobj 36 0 obj << /Length 37 0 R /Filter /FlateDecode >> stream : UNs(#e1IyXV\@QQ] Q{ճPN~_^L+*hNyU&7LL_1cVRNȸ=KΟ/k49] Ҏ;aFO;C*PIw`^A΋pOrg~4 Xfᘼ3JqIZEP 4k x`9!g};nxB6/0>Sfi⁞Qq r]6T^;_d’"n{-٥eg{|Z@[u﵂"s~B˰<"Cj _[c-vHoaV"3,uڒp2R* MV?+/@REXgc J?"f@V?Œ=]̭!@6<ڌf~3~(@ ~|̵ ` _ U4gCxw.f }Eۭvf<:' ==P\uWV#|?֞EJMEʴ^s{Zv"'܀^E" g(OʲK珩P!φe'`m~:bfeA[fX;b*ū+:[Z@bcgįJ%d7~]Z39r֏ݪ;?q8W_Q;[j(U':o67'1;jnaM{%hM}bu6 kFݨ"`3!!'<ǏII++EZ$ib S}鳜+a9)psmldtC/~$wQ2g.+QF-$|, V3:(ūw;Sz@¥ɑd_62ʼegI(؎u? (FHWVXPg;ޢp`A*I.̍Da䗂}T^D^CI02H'L^tSTł6a-2/w8^oXhP* tR.?j \ sEKƆ06 aָ#ru"ڛnO)vwOndvHy=T}6k%&h}$+Qi*$p5Έ62!;\7妁Σ;K밣h6 endstream endobj 37 0 obj 1393 endobj 38 0 obj << /Resources 16 0 R /Type /Page /MediaBox [0 0 595.275 841.889] /CropBox [0 0 595.275 841.889] /BleedBox [0 0 595.275 841.889] /TrimBox [0 0 595.275 841.889] /Parent 17 0 R /Contents 36 0 R >> endobj 39 0 obj << /Type /Annot /Subtype /Link /Rect [ 408.282 722.519 413.298 732.837 ] /C [ 0 0 0 ] /Border [ 0 0 0 ] /A 40 0 R /H /I >> endobj 41 0 obj << /Type /Annot /Subtype /Link /Rect [ 411.285 700.52 416.301 710.838 ] /C [ 0 0 0 ] /Border [ 0 0 0 ] /A 42 0 R /H /I >> endobj 43 0 obj << /Type /Annot /Subtype /Link /Rect [ 389.725 678.521 399.757 688.839 ] /C [ 0 0 0 ] /Border [ 0 0 0 ] /A 44 0 R /H /I >> endobj 45 0 obj << /Type /Annot /Subtype /Link /Rect [ 388.207 656.522 393.223 666.84 ] /C [ 0 0 0 ] /Border [ 0 0 0 ] /A 46 0 R /H /I >> endobj 47 0 obj << /Length 48 0 R /Filter /FlateDecode >> stream :.xAKvLkX)imok)(U3ζQ$cmůl&Bd Uo#_Ea d>J9ÿ^DaG#tЃ[o91T/ļmjZYRhA16cw..$kT$뉭fyH? ]FeV$YS8G%B+U_j5o|!iw&.jƖK &B|m_gf/>Cd)Od<%8MMK<~k ;Nά?d ڀ* }H3#qc(752`Cx3}-=vo{ Dnn:Cg1vn٭_MM;]7vom(о0g6,Hۮ3(t%^ǁ7s3G=zt",_5?z2yB{ ށGG bDDMu*Q': j}!\:3M uc=̓0[EP?~kD`<_BHkIФֲc^iasS5bI%ޜ/*ƃ+i\X4U0!F+H03|Ԧ^nLu.iB*/FZAިxMV.؟s6DcSH cmD"hP]O}r<& ;xv+*x.ԡ^Lצ?&k#6Kzx5D bH/WENf$SWåTt$7u?gt~v[ xn~P%-^!t];tƛUjAg=5@MU.~pp a.o@@SRȖz]Zx[FEqLTsxúoZ)rDY |PԃN )#l5|]"Z4 Nie6Uj/w!eBvi&vz)`1;^OF '̀BA.{rdj  $ waqykI?~ .XCdT[s;#Bu{\ҵ2,vg]Y@=еb:́UhϏKMS[ Gn&s1>Nܠ5^ pJJ 3&ֱ&j6 @Кsu838PI*Pׇ|ta6\՗ͣOݯ 1Q n?BqńɃ2{<OW4 rJۚ endstream endobj 48 0 obj 1546 endobj 49 0 obj [ 39 0 R 41 0 R 43 0 R 45 0 R ] endobj 50 0 obj << /Resources 16 0 R /Type /Page /MediaBox [0 0 595.275 841.889] /CropBox [0 0 595.275 841.889] /BleedBox [0 0 595.275 841.889] /TrimBox [0 0 595.275 841.889] /Parent 17 0 R /Annots 49 0 R /Contents 47 0 R >> endobj 51 0 obj << /Length 52 0 R /Filter /FlateDecode >> stream Eg%2.N"R=X?[ed"\,G~9>+ձ/7d=B9E@ XBIյp?4kQSLP54r~@̢R29RdXb CgAtI g\> 'aAjHk{dۑ2`Po+gSqhB8p?M;ݳ*bbdK5#VzT[]nDf^MnU:.d2cUHOG/-Vq5=WnM0Dh=yMpTQnp1k@07JNEJ7͂D)u-JGeOޑ0fK]0ma% f@y>~\Hum؊ j ugYKfr^@>>{,KoM4S9? *b 6Z_ᩉXK? zY~!͓7nbn d8 tD>YX-|RpW_Fx"/%ǐɠvgt=o(k9[{COa E1x搵-RlGucPNoZ8 q+T%uu493׌]@]TwkEŚJE`*Eͦo/'OSf?l|4֞ѣg4:˚;S EN=w+ُNs6&kS"D 7|hWV%$|u̚jK_3I0ѧBc+DNF2"m(UXE:Js`_xo˵d1^^Fѷ^|q8'5K{uw[&f%=8z \gʦFkF:ZG&f$&_'vt'USB[?'!.%l+$tDZ#͔1nbXqNx6Dz~G )8;x\ WsA~>Ն:r?yT"JZܰ}X\km {i}o~BtrTY!vv0c[u{Yc5ɨqʫ҈>0R-ZEIN zq/scSg"^x*_b"Q[tY@/z'wa׿u+ Cw/֫6#VeOT/I:ÊE:~%C<@ o&;27w0Zn0(4doj). \OvS~`&s"aEe2Wϛ=9C0Nɼm!d1nm8Y⼺(Vex(I0pyG7EM ?YOS0&Z{ڦTU\4P3k'Sz8B`5t~9k*Z`>`cPgr98akeLdZ +HE]z >\'}t@4K~A/τn~ɎHKXw\#>2f)l@NJ Xt} *<D9ʘEک؈06|FK’N4=R⽍,t k#1R{sҽd+pm9~S8=>z3]*xB`;C"fEWGW5gͪ!\PU&fӲN\PͲ3M~ݹ1ϖ] 'h.G\!!o9ARF xFcͥ hzAKY85GJJ_~1tOa%:/s;x<\-I5 vU% ([owU nuA{ĥ8nȞ*2+Qw\(ʕEWI_vLA[/Ҙ_HNmJiKAzg/~ rLu&6fWRFQN?-JTS)Hj( ?e)yڿo?i]kxrƒbؕMb w`wtFbe}~?SsLym5{ɪTd75y)~hRaٓӷ1bP/.yr"J>ʛJdGwt `t3 W `Ă?Cxl $ Ip jhb15iyό'nP&O=D*@RDZz D#yZ.1!/8RNb$3U;J-]7Rubs*$mQwbQ"?r73SZˤC2x8#Y \ׁqv@s>Yqra_=X{Tꌏ7ӏ$.'9lH )z.>g2]'hv ,t , u P8l,Le&#GAsHփm35K{q+Zy {._];S]{ˣ% UTD.t}@/L=u~ IDǟ^ rI)F&D-hfOLtEH\WvL{>m:ɯq:'I߁`Q0TTy'D.KMSf_8qG@Ր)[b(*S$Hh My9-0(OVc?0p0UUlaQDɛa_F׌ .=n/J c&@wp`RR/ `tR)UFKpQ:S~ɞ`X~lXi&˂O:~=zV r[ucf0P7ӣrF:m_O4 w#uމ]AT [SS-dpuwI {WTZKa*d%g {ϗ& Ȋ%g$UV ~NMۭ ZpϵF\8f:h$ 8g}ud.i\:F:%%4Λ(\KĜnX甸>=~UqDH^u3@XğJk M6/й"|Oai_e1Y@Z8aQtQ$8 "ӣȕ>NS84yfbIT|g"x̫mfz I"b%c^}بU&t֌.#Q8Ѩnȁ覶,)ɦ  '=D]Bg |f?Dwϝ㝤gϋqhyȏ!ǘY=RH{ylQh?xB|TW6pEc9/C3MmZd]9)v!zM7:E1޽ID|Bݕ@M¾8dr*3up)8#&u endstream endobj 52 0 obj 3727 endobj 53 0 obj << /Resources 16 0 R /Type /Page /MediaBox [0 0 595.275 841.889] /CropBox [0 0 595.275 841.889] /BleedBox [0 0 595.275 841.889] /TrimBox [0 0 595.275 841.889] /Parent 17 0 R /Contents 51 0 R >> endobj 54 0 obj << /Length 55 0 R /Filter /FlateDecode >> stream ߆࿯Tn؈+AA EZ@Z kFBt웪O't$/Kӆ (MLQ^pG/hk&*tS *8btETu^Abʈ)_rٌ~_D EZ<[vJ:5YL0-"elT0KU}Yd\R:TYZX8|I (36gg]=69R+_WX^G#apҰ~B&Y_*|4tY"o-$$-W օ,(̻䜌pf6ykj{sI˱fjn|uh]!ߡWД :Gܥ'bmUTǛtצW>"w$<w,Yi74Xw U˖Qc>{&oC\gL?ʀpsN )IBZΫ"D0]_yҌ%̮Ŷ ip9תXCdǐ?>ݐ}bMRK; hBm`k֚NBvC:۠x73: ;_jV?OD8tX OfrS6.pW_]/Vu51$#! 4m_%:Oli;-rzG: QCbgĂк{nuYP[+hM+6\u-FWz6q8 zW^z\H'F&ĆIMŹ} Fe/~=@ W¼h-rNҁS?Xp˗5bmԡ>Yr4K Sn4Qa=!nJcB)ٮqA0ݏ8C)J<1:vu8dyJ #]V*· $Ct=9ѷKPcߢokjZpϖAuy9ghAKf39UK&a^`thbK>A>K(4Hq7:r`[mn|;hJu\k2Gc)I[.SYYzSawwZ, qkvx`§61Uޑ<}e~Jd[Uc>)_$AqNNO ۰+@;]=/-YChh=&/WfsuyO8kFIIL"`#:GPJ) 7s>;:b]ZyY;m'ɇrIۀ=?8?uG" -Cʀ썊MKo> A"wی&BׁxiÑN(1-J2"˗bR@ZZq=⇀E,Cǣ;YCݡ/jIimmOx(kko[)xdCg('%) PHJ9ݗ+x28룈ܚ[ dz$y>]#g6(8 30 q1w1xGo tXqoTRSsךŖHk1M4!Q"ƴ˗H0ț8G >åNI#Dĸ#AJ: endstream endobj 55 0 obj 1732 endobj 56 0 obj << /Resources 16 0 R /Type /Page /MediaBox [0 0 595.275 841.889] /CropBox [0 0 595.275 841.889] /BleedBox [0 0 595.275 841.889] /TrimBox [0 0 595.275 841.889] /Parent 17 0 R /Contents 54 0 R >> endobj 57 0 obj << /Type /Annot /Subtype /Link /Rect [ 408.282 722.519 413.298 732.837 ] /C [ 0 0 0 ] /Border [ 0 0 0 ] /A 40 0 R /H /I >> endobj 58 0 obj << /Type /Annot /Subtype /Link /Rect [ 411.285 700.52 416.301 710.838 ] /C [ 0 0 0 ] /Border [ 0 0 0 ] /A 42 0 R /H /I >> endobj 59 0 obj << /Type /Annot /Subtype /Link /Rect [ 389.725 678.521 394.741 688.839 ] /C [ 0 0 0 ] /Border [ 0 0 0 ] /A 44 0 R /H /I >> endobj 60 0 obj << /Type /Annot /Subtype /Link /Rect [ 388.207 656.522 393.223 666.84 ] /C [ 0 0 0 ] /Border [ 0 0 0 ] /A 46 0 R /H /I >> endobj 61 0 obj << /Type /Annot /Subtype /Link /Rect [ 411.285 410.828 416.301 421.146 ] /C [ 0 0 0 ] /Border [ 0 0 0 ] /A 42 0 R /H /I >> endobj 62 0 obj << /Type /Annot /Subtype /Link /Rect [ 389.725 388.829 394.741 399.147 ] /C [ 0 0 0 ] /Border [ 0 0 0 ] /A 44 0 R /H /I >> endobj 63 0 obj << /Type /Annot /Subtype /Link /Rect [ 388.207 366.83 393.223 377.148 ] /C [ 0 0 0 ] /Border [ 0 0 0 ] /A 46 0 R /H /I >> endobj 64 0 obj << /Length 65 0 R /Filter /FlateDecode >> stream wM34RhjIԭ a1^^ o3} a`1XP,jT9 |BS09f_^'9{: lʰzQ  DqF 9OӍ?P]xPn 3ʊ-ю "T^(<g!2=JOfbn57~OL[%\^MNm( rԼ?0|y_khT7 M-sdt'U:pgC/[0+EAM}Hn&ɜWI]ZXWVɥ0>ZQRvlfLTeӻوL O⃱3·x?wxu^O[FT`=?ܼcmg/2Va..L=f'0+$#`1Y [Ȥ64mh+BUĐ|FZ[@C]_M9\5="L"\,ݲ 篑bR> o#YmNŁ`leX礼#^Ϩ|& 1U[fvu*y5Mib4r Y([$Rh Њ**Qs9|,#?@`eKV Ū/jJlYWs \Z|:'.FR\șJ;׺H*k[s"xƑgE(pNKZp b}|%)&->~#H%'ԫCШѬbr.$^>± W'=Pb oWש5` M\> `4LY3E`/Tss x+Ke@eܖ0uCH4Ɵ͆Uյ3C9rKZTXd篯x7QY6u.Y-ܐv˾cAkjipi* oqkOe(k+-je/§9R`B`h&2\λc{ɔ4H773np *e@Ĩ.X%撘L v5,ytaX'R`f}_q̪@p c ~/,ě2ˍj+Sӏ6ڈZ^b"mt{BH+lzjW2!bC9zL'6TTC$St[ϯ&;YzɆ6vpNmQ E~W8 \XeLٵʰliX&+?{JXLClp^rtI΢t}V'Z%cO{ xlQ<5bG2x: iů'ڍ fe Uj.3c hZL#w_pfT) 1E#ׄ"h)sJ+} G"z3l1FJ)9yjsrSuo0xJ* X\Ijjm2Y iE%Ov7i%%RUSU+-NhXԜ4q m=#qϿtd)w4%nu۠ d~uڞ{Gj6_){nCE{LWnN YjOlSF')*y/$o'McwE.7O/4-J߈X(8xeDžOeDVi\( UChnCyѠ 끮Є5t&ZRS)VP"/̧qlT M/\8qEot{>/TIʙT$F{IfZ9 5yCEg5WBV7[ i?Ijh-%^=~N%#4y2\,pU[Z'h(=;}P|6 ٷ? s$Bz鋙D܈U-YoRif(}g@繚H_APFvNak6.}t endstream endobj 65 0 obj 2144 endobj 66 0 obj [ 57 0 R 58 0 R 59 0 R 60 0 R 61 0 R 62 0 R 63 0 R ] endobj 67 0 obj << /Resources 16 0 R /Type /Page /MediaBox [0 0 595.275 841.889] /CropBox [0 0 595.275 841.889] /BleedBox [0 0 595.275 841.889] /TrimBox [0 0 595.275 841.889] /Parent 17 0 R /Annots 66 0 R /Contents 64 0 R >> endobj 68 0 obj << /Length 69 0 R /Filter /FlateDecode >> stream .~ []6Yt%p٫s3#HE^k*JhciVJ1Vθ i£mTlƾG=0({7PAƔE'OYk/ ?c)}Dwї[S.]#G5{N} 0 eTY,4BMl0gd6Xdvl5yӭVri@C+/ʈOfI a{&@ā pF;U^$迹z-fPu$mxXdTsUQ zd \i!0aHتTmXK}ߣD ma m+ U__'Ym וjG@mRnPmLMw@5V%i$w-FY' %L Vε0{ "_4BSӳ7 ksƖ6O+sB5?&rKLH r=83bS?B\$=`I,\_M zjjKZn=lH/-$m,SV :q3;};(6x8^8fekd75砜F>lNpR}#< -ٜgj|JJlU5@ʍt_*:EæVwn# VPwiXEAYsjmЕ]LR2hVuzG$O8۪߾h!%4l[o!DȂˁՇ%{;ЛXa$ˣq-/tlJY>>V)?CPPV0nL$}h!㟸.grOXb$؁@V=/tQ)6*,7uo(MTԾ묲Olcɾu.S^2>C6mh~٥xi!qNj:_!Q:z i2 X /gd%FړpJ n24']UCzB߮tg`ş=%W0ʧ\}z{a : y).ޤ " !NH֛UN2So%y070 }mˈemMcf.<`spgaoņ.P#Xp(Akoiyҕ}t;Jbh)fAΜfyEt.39?2w Uߞ%3MҘ{Fς` 7ytދB@r`H f{]HɈr{( v҈}VĶd (|˸r=3{kDӷ߬?ny/'"=KDK S@=uI_ mŧiEn]cQ|i.mWG`${*sרȊTwRГ>U=UZ1Lȕb]5sufs3gC}'M5NؘE^\@yQSGŵ0,c}bE.k͔<~N4qG ZɩW g4;0@Y:۾a <&QJn"DfFW<42\a"u\VsB՗8a ӧdEEOS2>%e<5[su2+霗[eUK:Ȟ;jaXQXT/S/^%J(m2orJ݈)սwbDCi[#W{ ٭uMU?Op[ vB "Kϼs7̊U(0M#|.ж)mLKbE#7w:HL->O;Z&?aq9:;gmv~L#QY#8}쎿f[o6`='Iΰbt+-j59B9wzF6fkA endstream endobj 69 0 obj 2995 endobj 70 0 obj << /Resources 16 0 R /Type /Page /MediaBox [0 0 595.275 841.889] /CropBox [0 0 595.275 841.889] /BleedBox [0 0 595.275 841.889] /TrimBox [0 0 595.275 841.889] /Parent 17 0 R /Contents 68 0 R >> endobj 71 0 obj << /URI <8D032F9B06D2D8A858B640AE75303671B0986B479636C70F760E013B4A8F0E79DCADC9DBCD8CE1A5C64455A88B76F0886BF0DE> /S /URI >> endobj 72 0 obj << /Type /Annot /Subtype /Link /Rect [ 238.544 605.711 451.57 616.029 ] /C [ 0 0 0 ] /Border [ 0 0 0 ] /A 71 0 R /H /I >> endobj 73 0 obj << /Length 74 0 R /Filter /FlateDecode >> stream ^|9Ԫ#қȹ",La4]"LZ:H7V4Î9Tݪ|ZoټD׆n2ξV@ >_\H1<^sP/JY(d.x8ܻƶ+Az ' LBh4jO`DF,>_LK6}S--6 p{T(GI txnBt)F`e-:?,Ӻϓ{f'.y#b\L;z M#%{F%mloyXhE7Z#24QYt"cQ2Q?2?VC>[5ea  1s nC@(zXHEQ_#<,  /9<3*XɽzQBl`nvݲ,LjBQ(NNևF>̏MQE~@{xۤa9lFr0t2rT1t}:ӕ05p*W _XCG\K;ZӇuNdK݆nN 1NU='MuT"k̪0z~UQϕr~ V#Ks4X n̻k|cPG+ (T2(jCaPtz"N^ڞU29]𩨤?q$s#5Uc4o`"x\8 d[ˈglp{!͏Eyh,_t|,8 <|ftuZ{Gu ^r.vlb Ȧ ºq} Qm",sgvRx:qC])vĜ85MLSQ*wnot5-0(= 6?^t . 8ŚfEC_v,+>Ư]T [Zb@}=Wbg-pJh\"N/oIPؒܗkD;V7'C lw֨cW8h ke^N#,_x+jL/8F҈ oeїJ:UReZcBЋ̤h]]`b,0K3ohMUTM[8xR?B{Fzdl0"V_,V/z1^qAurIЕwYJu1kfg/ظ=X!M@2L }`հ7df|l)y~c[dAa[?>bY񙐂LHvDBV;3~TTQXSy?nJʒyX~qȴfv A% endstream endobj 74 0 obj 1817 endobj 75 0 obj [ 72 0 R ] endobj 76 0 obj << /Resources 16 0 R /Type /Page /MediaBox [0 0 595.275 841.889] /CropBox [0 0 595.275 841.889] /BleedBox [0 0 595.275 841.889] /TrimBox [0 0 595.275 841.889] /Parent 17 0 R /Annots 75 0 R /Contents 73 0 R >> endobj 77 0 obj << /URI /S /URI >> endobj 78 0 obj << /Type /Annot /Subtype /Link /Rect [ 467.597 404.847 510.684 415.165 ] /C [ 0 0 0 ] /Border [ 0 0 0 ] /A 77 0 R /H /I >> endobj 79 0 obj << /Type /Annot /Subtype /Link /Rect [ 56.692 387.84 137.872 398.158 ] /C [ 0 0 0 ] /Border [ 0 0 0 ] /A 77 0 R /H /I >> endobj 80 0 obj << /Length 81 0 R /Filter /FlateDecode >> stream 0!p0%N&:&u2*0.boqvCVXLu>ZÖ 1'Ai$Fί th |y zER D*3 ZռU*{D@`1aG:M=M]LW. \Dž[pGAA6*uYZ]ou}5V~-֌sznBMN"o-%ab-p>3 1[`-ߵ{nA\JbQIޒ=]j_{Sd)iL~Q&QmXe̝J$ 呓Mּ֐FÉMC ǚ6 •8TZF/f0Bc:֞ 6 ?9WܖaBѨ܍A1C 5C \=.BZCnɠ~X< ̂q8wݥng p /uX@7'r,CL+nQoV_2( Ō.D?CQR  C |u^@ucT7? /n#l4>%fMWTBXKYbA*A'ԁ~> s?pR8.[/9[snB""+-x!(zK94P9чؿ8UUppaR|Xe|Yv1 ]T7|urF?΂nS\(]:OkV2Qh0q-}*8LʊYZ>+ ( <9PTUż9GllEJ#v .ϧ },Nf,uoO2Ek}6s"wHq"{ŒOEa#<. o| }[ T LI~b^)A'KcR6 |f7}y@PpÓEdf_Mb'3-9¼kl5IR<Rbo<ΐ{5wfOy14B݇ K,u~KtvN~cv'тh<歪91QoG2kduI[q00^d> ʹE#Nr~S|4?f59qU\`Y 0}Y:'9TR=|}!mF\ٲedUa>r)ɿ~XO#k*t/b|R\ji B!5`UP׋. ;9*̲pRJd0oCVB~M(<"º I. :zV6Yoc&wYœ e428kj>8 О^%Lk/ +X ]7{m~`P)#HLZHq9Uť{!beTfs@|+X3G%g8m]]G_I ˠaScg(Owo@(7R.yBAvo7p .D:XOU~ccʫ)['Jɰꢿ{&- }Rd}.p! 50' \w,U׌)xNUv1rS MAz%|L]eCT?4Ɨ3_7>& |6pq4ȅ21L]\BVmǛ uBugXqU1&#]B5h ( lHemiI8"XLOxd g C.뵕,0.x I*ObZFJ<ZgjX<*p#!Gwzv33d'-H$!RjgG7Vyz\4pG'nBsz0iKk)M@ ؛,h1&rGjs8B(s 6(p'%:\yi(e]_!D*˖K~&eGҮl/Dql}]+YrU&N0u)_N-mZPƽxPDCbv 5[kg@eT+y~iA<۸Icծ8EJfЩ64\ʱ3(A͂_JЫwGF2|kzWD臏PB:GT=7ÿ`* ]gY51"l9c}Pl_#TjHB(۵Rh(NoRw8ɴt8Af[>WKgE Y8/TEWƉuB܈r5rx*Pqip-퐟\% LUEghnCh} 9:c?xs'iҕ ]cL)R]\*hKzEqI~RXهJ endstream endobj 81 0 obj 4377 endobj 82 0 obj [ 78 0 R 79 0 R ] endobj 83 0 obj << /Resources 16 0 R /Type /Page /MediaBox [0 0 595.275 841.889] /CropBox [0 0 595.275 841.889] /BleedBox [0 0 595.275 841.889] /TrimBox [0 0 595.275 841.889] /Parent 17 0 R /Annots 82 0 R /Contents 80 0 R >> endobj 84 0 obj << /URI <88A16B13242E8F4DC598F3AB508DBFC1EA1DB1618E4AA26D25ED0D777914F7440F7BCD2BF69AF58209439F25414089> /S /URI >> endobj 85 0 obj << /Type /Annot /Subtype /Link /Rect [ 462.724 757.361 503.501 767.679 ] /C [ 0 0 0 ] /Border [ 0 0 0 ] /A 84 0 R /H /I >> endobj 86 0 obj << /Type /Annot /Subtype /Link /Rect [ 56.692 740.354 89.263 750.672 ] /C [ 0 0 0 ] /Border [ 0 0 0 ] /A 84 0 R /H /I >> endobj 87 0 obj << /URI <8006E812B662AE445ED1011A33FCB2EFFBD4B52AAE0235CEF189E9A376CEE83CC3C1EE607E1494A72E8D75363749D1D5D836D2F23D9B4E5F7032B39A84A236B8DB86A2F09125708DFAE89ED0A6BCABFCBF87A38E2A05C4877433928A6A9C425D956F9D5A99B9DF6D7814> /S /URI >> endobj 88 0 obj << /Type /Annot /Subtype /Link /Rect [ 302.366 717.678 392.324 727.996 ] /C [ 0 0 0 ] /Border [ 0 0 0 ] /A 87 0 R /H /I >> endobj 89 0 obj << /Length 90 0 R /Filter /FlateDecode >> stream % ϠPv~{K5 6 ?|P#nQ_*6qMx D AZT6m T9e4P!-oX@.n #'\ *o5mҚO>*a/|6LAـszrt!Rӑ*ׇߺ?}Oe+Cf 6@7ZcN~|U@ )#M:;swԮb@ǹ8]D V Gl1P3n r8dHUXV"5=y+0X2J_u6gzRF2/BfD@Jn1.a5ML@09 Q<7&Exع o{}@յF'{މ#8`溍}6֑ I塞@Dlq3l<,lBD._CNg&$쒊P?!:w}5]tǰ7(~ m% m],V,Yf9tϓ1O= -0\pګ@H,ULd'eVAƬjBtMywS8.qF//_G,зFL[b69wHꤥ맜0TDi=a3łmTްdM @;dmlḅd[/-iValbbn̟i1bOWO79_ۣo5ctZ= Rx1qT9}aPڱ[$dP )QG߾s*%Uu}I' fUr](h:5 ҪTIFK$??@t9.Jܒڌ/)uU,cJ@FQ2H(3!5+ 8f__k)B:łzsӜ9UQ7l*S8l$&co]2 dy;tD*d+&P2!iyq5甝\Rqk}k-nޞSIKbGcԙiD\/651EaևVҾuvL]mHyP*ALUc YYXx)w32q9,:ldxi}4^Oʆ P;tMf1?êo0rL_?{,iMvTV]~b&qW SBdrXR%NQ IM3Y읩Ve8ffNZ%"V7o^D&yA!~0fCtPxcPDŽ׃ c2r6nF,9(d'e.dbp= 3,@=5aGE\q.c֧wcAU=T<3ؕCđaZ$ -^q^ @]YY?Wb x}0-5)k==6I3[=ա{fVY . $re(tEٽ;X "W~z\Ybrmjcw7emk<<(%r}L/ip"{&gYkgֺ!G8;RB[_4{ ۡS_2ڛdr㟀vӜx}!ƈ?5Ί2iڙ3)bRzҘ~+?gf@we9{ ~gtV:r!/B@j=\ V G||c%,XO+|>􈔍HtDc& 5Q.%[ fFk=j-mEc SF}#90W1|.-L^?ޱ2Z6 jf Sm7Ò%V Tyq'>$Wmr 7-Ow+IY(A`8PXX{jqkAxR@6 [uHrڬx!u[/tx!x2`VF޾ ( g3@T2*V W[H GHGrs`0Fv moRqAW0A ehQ;Eg`G6hig}{YW_/h\6RL/5NAaa#?Q\*:"mKV"YעDΦiUgM1?8[ pGq)g~Z &# /t0c-Hkwj[)xVNiNyË́ A y$} ^ZYH Mt)9t&^0EJ$ @<=<͢aE4. UUb Nt\v•vT0ء 9`wMp]?\亭PbEطB*s9A#5SΓbqq󆄍L%aL]ory  5o۽&ɶNjy 8b@7&g7c۞?2DܖeP@)G;Oy[]hJ%3,d@{.DHԶAZ%.n.dx%z'Z6BL|ՠu \jPq؉HxMH{l+SW VV< Ǒֲ`V O4j6; V3R8uc)Qr8{r X̾!a^_&I.FYrl?0poMnlK 2%6d\NpVkx;˲G;$O&<(nQ:U<+|D('?Y6Zj])yi}]R%Γ QH^p`yn%{Kt6톎RA>7e$Y%g( ͽӢ-V˛fpj]GßY;S"2G!X۳OKd]hw رʞEZT!]9jl9] (@X(:r-zx|Sѥt0'm  ZdIqE)l)rD7$g4ks&a'*osGY;,urr&ԹD.Ri3>N> e{wrLM ږѽ4ޮ/&$5^Y> endobj 93 0 obj << /URI /S /URI >> endobj 94 0 obj << /Type /Annot /Subtype /Link /Rect [ 400.629 728.788 441.219 739.106 ] /C [ 0 0 0 ] /Border [ 0 0 0 ] /A 93 0 R /H /I >> endobj 95 0 obj << /Length 96 0 R /Filter /FlateDecode >> stream @2> ߫L] Ɔ>7$7a59h˹gMX[O0k:$PoXPZ3 c}z>/ZԹrr^K>F_ͽQdW;G< uN^=ao}}3]$^Hm>$s mW$egyAT̿M3iC _H 5GլQHf1KÆ"nԘbˑps ;T"3t4:k$ݓL/Jn4C X˸9ͣ~QlnN D,9e.&в{boG^+AsX)k1pvA4iτ71^`Y蠾x,VNM߀ /|$'(:k3K ί(TGE4Ѥ@駈SLevTd [O@ h.ks"rCRܐ QTBIb" p1QD:݈;`'4wS} :OPdTU"Ȱ(D*4ΨE7J0>i#R1/oS0c+[ f[a{ʖ1eA0gkڐtۂIVQfmS?6 9zLLq_Ϳ#akՁͰWUwLQ\d<CMK`*vظ釆w%̎1vK&I ?_>lj95ߤFXatD$v]qq/'Q##~ICj;g8 endstream endobj 96 0 obj 2952 endobj 97 0 obj [ 94 0 R ] endobj 98 0 obj << /Resources 16 0 R /Type /Page /MediaBox [0 0 595.275 841.889] /CropBox [0 0 595.275 841.889] /BleedBox [0 0 595.275 841.889] /TrimBox [0 0 595.275 841.889] /Parent 17 0 R /Annots 97 0 R /Contents 95 0 R >> endobj 99 0 obj << /URI <24F078742ABA8AFD2F085010E8927B647A1E450B5EDD91A3A84F64A5EAFE8574C5D26B0DA350771010A9C1C77D23FDDDB5362011> /S /URI >> endobj 100 0 obj << /Type /Annot /Subtype /Link /Rect [ 296.778 667.664 324.333 677.982 ] /C [ 0 0 0 ] /Border [ 0 0 0 ] /A 99 0 R /H /I >> endobj 101 0 obj << /Length 102 0 R /Filter /FlateDecode >> stream {b4QnrD{A$G|$TcJaCfXQb T>>sh{̥#o.$oI`+mֹ6jFwdoa\nO>ߎà0.X q%%`()H,2|.Gߑco+mPÃ?盕i/=^[`*ihⴋ*=(g\`~Wk{s3#Qe."yD=̉TE(F&^iH3L]?aH߷OnU9IQ. M4ce;"R\0 ӱ SJ+ C7Aʳ̫gP ?3 mC1gGWrwѽN+$Œ0a5V͵__ l#oq8Mh5LלڗP [: piyx}-F29X?+ؘX7}S lCa0kF#Nzv :6 j\ipVy+5*O5ۣ]\k_@!` .$VE/뭾wvl5g%5Tߑ"Jp\qZ~OhC@bcU\< I0ڂ:6.l 9y߸5 EW{wFq>>uT˻!~$۷{t{ע0&d 3g -x :^5H o]X=X9Hlӧs]+,Cc~ VRQxsv R-0jeJ?>DNE/7rZ]ߔY|=VGaGQ)V%-'tf"A2sY6l|dk󬝌zUfe\A:Cbh8pXG9 _S8k[6ō/lfyiNָ}[0A?b,ĴBg5NB0(gG*5(@:zJ{`Ksn^YQS> )xPM^$yde}L\=er abpo'nb+ȉ;%Jm/ҼԳO̶ 5KZ)^6 +ʜ]~= <}d;|BţT٭M ?:$Ċ·U% [T׻6>rWeF^nBz} 'KK}`A]\2M7:/%"~U )ߣFjXu;d_t[ Ar) 5hc.%w,Vm:Y4FZ8m[CX323!oS+?yᔒF5CwBʼn[nN8<]fw]oGN>-Q+jtR#$>G;oy{L$L0v'I\|UĴm{`Q Y~Z&o(/#i֬o rMG]/߼׎>܆1,z=nasSkHՈ%(h7Qdz Bp|o:ÁZ'ŸBux*F۔3aBZK!+z3qkbIeLŰ߷U/&I=8g!{;NJ7`^qc+B#enu7/4 0U8?ʼnN!{me4Tifӫ?~q.tfgVl1kSp9\}}a(Z*RVEv5iDp7b/wO&nƳ *[,Dipb)Jf >ʳ7~M:nHMހAسu0/L'ڇ vnG'tyzղ tr*xo^||uMqf!TYPx3E:.vA}榸$4ȅSuNSv-u!Vk A ?yUQKfC i|ݡdg51=}wO'D[ćjd]ǶΦTxSR8d~0]l =,l7FhQ;w=#OXNo6J/K($SSb~oF}4yk Ē = T9r -vG,@eߧ ;g4]6Pq'l+~uYC{33B80as距Xd ܕrg־fG a*TQ?Z00,!.V4JyuϹ1BKᒥV@\@i&g2^ dw&X)(Nr/> endobj 105 0 obj << /Length 106 0 R /Filter /FlateDecode >> stream L1;FĽs#Xǎ1UUULyCML?06B1)8ϢsjNz*K[ۉByXm19,L*hVFwyMmgd7qʣ8W/H\S /e+ 歌.ڝW@PX bl F[O\q$>{=/M@MHےlB'9).R#k8Ro;;2}3O[(5|F~{RwB3 h6oӾbU5ٿ1FM#xzd&ʓiA 렛vHne!Tk 4KޢeKƩ#OiE&X{\};wo%5 q>pfb-&|8Nf1 b:2cz{jd*+9ALLo ng^Ҩyxu\~-Ʀa2$DUլɝjm+V)"PqvRx5-xJR$a2kHAۜRjArBwj/ܒ|<0n7x@N [EOۍQuPku.J~II2#W\H- T|I(;'aAZTGhѢy's SyN'ms (50+޶f.m'ڡZKxn@h;{L}Mw=u' 8P]3T}ėxo{*GGN8rC ۺ$xst-\vMcx~Y- >[GRȑl1/hb t&]jy7xxXj}c*u-W.\-@_@a\>q O%R_84l@kF*E}]y@NT+e{e(10'MLyp@1FK%{H[שVfV;cM]86pͼb*Wn/[MaJU&>9s1.w' HcmAZbB(3Qp:_bƌ؉~zn@O*gh^ޯ2h>+=Ρ@'RIB*Ӻu=y6w~K ?_O8 C: 🦑E /nv?byqVcQ*J`ILu~ N~Y!&㢂E 𼮼O)J1ھm-&*1Sk<>yDmHJ`{]0l/8S3gxUA^ԋ}e>, Dk\"z4Rk?`-hn. 'h# ݥV?H78ZLJ%d++Mt)WW7*hFDٜ\LL\BQij"%:o/EQ*3+}=umfeFo8M- !Nq)XK~!sLpߔ`LyFHag [*%?D;[(q KC <Ѥ`w8!T;XNK3aw1wuwO _ J ղp9WŁH!> endobj 108 0 obj << /URI /S /URI >> endobj 109 0 obj << /Type /Annot /Subtype /Link /Rect [ 291.74 575.96 319.295 586.278 ] /C [ 0 0 0 ] /Border [ 0 0 0 ] /A 108 0 R /H /I >> endobj 110 0 obj << /Length 111 0 R /Filter /FlateDecode >> stream q& 잨7v~:G4J4nnE^-AVv +G.?Y{ VRs|'CX&%hD B7E'J]58Ss;kxa5Ezn-k:|98D~V^, JPl{ϑ<_lyޛ r[z,0eZT3? yDVcίnʕO/en(% _l" DOP|r_FJ +7P*֤1fyG3[޿ LEPw Պ`.Tb c@rcL0b VZ~MnykR:T05{lk TW#cJYĸт*G^C;2tޑd GJ`eq3>77߳4竫)nzHueOަvȚdY ]tgV47ʚ+A АϳcKQՏ-y$ D}o$YtjBT si"#I9ƴ#@FV Dy|=CۚQ?@NX` ~lqxh?n(,m2Z\@,1H!NQVyar%CM=oSk3>&:`dAF&٣"P>':rRE3$(`7hV,>[\/eERJ^C]A 0%.JoLK  F\0IW*E:0w#2aitU5F=DcתSsoo'J'tTx *?\9:|"ZSSM?ACX O/tZ †0i}AYvfYaf lЎkD{"`Wӂ ׵\8Er@ǻ6ᦳ`Q W4r'lK-L}v0k=:D8`vPb9Z5$/PcxxAq)F_4d n <^Sq$01LPt"Vj7lmcC(]cə(sa9;QzV_Jh-s.nYcBG x;Of[3v5R{s" Jm7Bx|w&1+1Ea)SnjL(_YIz\ҋ?̳ +盠K&1ow*ccۼk=@YϪs[|[#D{r~+eY]y6?=zBL(/+ ?ZWH\eGrM;ulrcn)ۆ@ "٢=|OdAP=2cg T3}n]AhKl8?-[L4fSݥTx4)]>4  < MLz9 ~}QzZ9{LJg0uRZX1'@6 x79Hv˪yx( hh9l3ĮAߟIJ"=)+[5M +Y1b6O؈ O$@טyq`u6P=ӉF ASF("8Yv5Dr ke`m Gx!<㐃ErH6W.9,#8dB]KOOqtA-V'0䳤z:y#|/SHđ)G׺M4nyBH~"߼d-ŝpI&t r uN%*3G0cB ѤeDZ˨;i7tETI[7v%(Smf$(ӕJ]I"vݒ(a-wNzT)6F"~{2qo72a\ՄxD73`6ENZ\柹=m{TkG%DZ^7:1JqȲRRM> Mk+=RvUiLL^⃳Ԉcx9 V{9Y/HA-@4 ekoRdT'tBmԒ?xS]| CAo҄eb*z6>>X-qms0,S#I5IsXJ5Ffy~&fDT1@LLEx)*zl{gj ;7M_szV\U)!k"Dq#DHg"6No9~l)63o{YI.a8,dCs!p;0#R,?;Ё+&Dg]ΑX1y+Q^\:/ H9&@ZtQ@rKѴ4i7QU_Ap~عD,H7 M$db:fVS wյ{yXQ%Е&̨/( 3.H)*E-aQ+f ;e,BR6eWE,ZD;Le endstream endobj 111 0 obj 2844 endobj 112 0 obj [ 109 0 R ] endobj 113 0 obj << /Resources 16 0 R /Type /Page /MediaBox [0 0 595.275 841.889] /CropBox [0 0 595.275 841.889] /BleedBox [0 0 595.275 841.889] /TrimBox [0 0 595.275 841.889] /Parent 17 0 R /Annots 112 0 R /Contents 110 0 R >> endobj 114 0 obj << /URI <95B1BC3056B181C4808429D088F12F631E7E7FF529D15CFE441F87E791D8FCC9302CB4787E784F585BC9660E181ACFE219BC118C727A724C3B056D3F7753E0C6B97FA0D28554A5DE5740616740F7B920DDA41DF5096F4C15788B3AD0E4E054434B80131C9C1082> /S /URI >> endobj 115 0 obj << /Type /Annot /Subtype /Link /Rect [ 92.86 728.788 108.392 739.106 ] /C [ 0 0 0 ] /Border [ 0 0 0 ] /A 114 0 R /H /I >> endobj 116 0 obj << /URI <557CB913209B7B5638949F81424160038B00C9D2727CD89A4AA3D824AFCC3FDCB02FF94B846795B026EA11> /S /URI >> endobj 117 0 obj << /Type /Annot /Subtype /Link /Rect [ 56.692 711.781 141.414 722.099 ] /C [ 0 0 0 ] /Border [ 0 0 0 ] /A 116 0 R /H /I >> endobj 118 0 obj << /URI <8059DD19DC9CA5A93C1C9FA44EA257F9DF7A46281C2DDC9C54F05E8924337CA151FDA89161CD23AD76054D9D5677856A0D67BBB86F8C6F4143BA721DB3F6A5E0ED6630591C154C79F2> /S /URI >> endobj 119 0 obj << /Type /Annot /Subtype /Link /Rect [ 358.391 526.599 439.604 536.917 ] /C [ 0 0 0 ] /Border [ 0 0 0 ] /A 118 0 R /H /I >> endobj 120 0 obj << /URI <0F3029CB07C5ED3056E4F54883FD40BEFFB8FD77AE53C102C3DE137BBD4C95503AD14A> /S /URI >> endobj 121 0 obj << /Type /Annot /Subtype /Link /Rect [ 100.243 418.657 136.807 428.975 ] /C [ 0 0 0 ] /Border [ 0 0 0 ] /A 120 0 R /H /I >> endobj 122 0 obj << /Length 123 0 R /Filter /FlateDecode >> stream f~|_/rO)T'V&;!t46GYYšgp@z O>3 `$l37r{P~8"R>4?,HVᶬ:A{q,6̣Ǝs#w FT X ;RL$͡1#l, IuN958w1,wJvaO>q5NUXN#3=!_jhY# ѫשژDC/NQAZ0f>rI!ٓѮPM-}Q4^߬C&"8)lm?ZwF@c(ҋUL)\Of̚ަ2$°[%i0.|2\A|냋m#gh~T&ٿXͭD/;0gŬ8 Hc$%$N8|_eL=g( 1JQxЗ}k4h =2WD. ex%q 7-H&IC%{W@STsg#7C*DYӝλUD9v2 X"^ kwp4~= aoVbY2jim,~M1{BE$KWOc$ڸDS9>48Ykc 3'܀j}'@J?_g)Ƶy{Dx|x oBwH$d`hPng%R{*-irzLϮ'zn~ԯYcjD"Ն7놝7~+b;CňfH wC*>;fUF*b踦*<#4~ln~ zFr%K,,JK[+>8;/Gr-f/>b6l"]ȭ L\D ԑ?*1uO@p 5Ӱ$7g{qw)D nvk`AiFfdqlWvq UbGuyRn,ֽ$g $G<[-Ԅ3,g -Td4 Q'(S.gD3%'ck[$쐣dcV.q;ʔX`fcn1v5Φ^#[ڜIߨhYGT.O='3ˬ(LEy|إvrx>`ăUڴڔ|_'J$P`fQ?$IQEm r\YTB({sq?F\ҥɟPr~ADD˅ bkqm!W~*܈L4܎7 *nugx-9tlI';bG>P*AmE᷿j6^|jЀ?b9\ t eи$12C|2DbJO8\Nw,U5JZ4!Nks "tnbllʒboz4 Mt?ia0бKЀnŌNWlwzWGer檵o_o endstream endobj 123 0 obj 2962 endobj 124 0 obj [ 115 0 R 117 0 R 119 0 R 121 0 R ] endobj 125 0 obj << /Resources 16 0 R /Type /Page /MediaBox [0 0 595.275 841.889] /CropBox [0 0 595.275 841.889] /BleedBox [0 0 595.275 841.889] /TrimBox [0 0 595.275 841.889] /Parent 17 0 R /Annots 124 0 R /Contents 122 0 R >> endobj 126 0 obj << /URI <31913AF254181799F8062B5DE4127AAE048D11F76E7484EA97A2DD2BA260A49366FA1EDAC50261B8A88301E879A18E52A9D66850> /S /URI >> endobj 127 0 obj << /Type /Annot /Subtype /Link /Rect [ 311.331 320.2 338.886 330.518 ] /C [ 0 0 0 ] /Border [ 0 0 0 ] /A 126 0 R /H /I >> endobj 128 0 obj << /Length 129 0 R /Filter /FlateDecode >> stream #,^谡\MGi_b- 2 FF qߍ_biX* aZ;QkN( ݍMU#Z,L ]am|QLnHpOWp|a'2%xQ5;į#Ip u R-\M2b߈bdRY"/\$jILWlX TDG0Z"~4R1O,lHe $ m[ rU:!sjKNHG Y5F5.^ Bd!;>kƯ?Tva"a3c$~=K2nylh ˷F#IdVyruk{, O?:09fdg&T475"u'`0^kgڌ];JJvQf C%P\LO@dF=SZ"ng o?c~:/?m"5FƓ GZt?XlmÎɇV׀(GCuPljfo$HE]\Xa&`|jp!T}:EsEG.ABlQ|ߐSH+7 ̮Ĭ)ЊB:* m7>ܡF+~zF,#C_/!oeAܬ1uλL飭CK4Θ\FN'Ĩ8fYz>J8ȣ%yz8sT=a]t.l0=yeYӯ{")g"myܘ GHcJᩇ]:P;˛?7ȯM֊ ! sO֋ަH".jMuilKu88n*AZfո=U|Y; Ic|3 F>f)O H{q3Ch8!9q o .T\ɡڭ߽φD'LY07B!CߺEEp8i/--n;%Ϸ1H=N ղ$&= Bk:>;Ld!lcm}N\KdHwFtm)ep! ծnx2qxߔ ysȗk&u=Ѽ5eՊQ{G/$Ȼ7[eYQ륨#Kq7L#B{7SAvn뗋> %d,UQ qM!Qi.ρ`ys ¯znj .3bRΛQ1. i#"6!=nhVv/BSB5<ݬ^ U{DE &FSȘ+M+VEɡ8 ?LV6ꗔ9յ/2By~,Zs$=cަZ篅gOMh53_Pls㌽i _A-*]u p[5*Yn--I%//)'VTmXVlo]W1%pbRUQ*aaTU~wɺfOQߋ,3 ZW=3$w?>S[4mDq7Nnഖ[,jPJyg73hn/oSCMwKhvpRpuI%\fK);٤+=uo'U B:-oǙ{0Qo˨S [=NM]-wk UV#jKlYww5V#!har}ٜI I1բDטXjs  qu H(ݒgdT:o§X@,QkmHϗÎ>$"+%`EddzdcNg(6)0E7$l(꾅cwU;ZWL5 endstream endobj 129 0 obj 2837 endobj 130 0 obj [ 127 0 R ] endobj 131 0 obj << /Resources 16 0 R /Type /Page /MediaBox [0 0 595.275 841.889] /CropBox [0 0 595.275 841.889] /BleedBox [0 0 595.275 841.889] /TrimBox [0 0 595.275 841.889] /Parent 17 0 R /Annots 130 0 R /Contents 128 0 R >> endobj 132 0 obj << /URI /S /URI >> endobj 133 0 obj << /Type /Annot /Subtype /Link /Rect [ 341.361 617.312 368.916 627.63 ] /C [ 0 0 0 ] /Border [ 0 0 0 ] /A 132 0 R /H /I >> endobj 134 0 obj << /Length 135 0 R /Filter /FlateDecode >> stream Ga<F>~x;f"jˡDRfլ}/`T d FyS$^%}˨< W |-`u3n&2ՙZId\$oBÒI})Y۷=v5w5Dߧh$,c&M{@=Ie4ÉR z[oۦnb`4Unϣ2S J>.mvlN1+YX l ;']FKs3!8vI<d1QVi${5@wK_&'p7̭V3]?- ueY<1e1̤P(H$.ho>"j*˨zB>*{ąj_g8 W$82h%˂ oo4uҒWE&(PPboL[<ܞ+R8_ݛ&lv R(_4uynythEy~R#]P=lȌg 5?6{ڛ@D55on2dѤy 4-:Aq?nTRycW2=@(opQLI@Y?e9,d~֓WU-ia9M O!DJ C7>@D`* uhSavjWhxS@x%' |V|w"jV'/&Y 7XDXs)/W7*F"|*n8OՊCͯ#Z AOIHIL;0]L:%'$4O&BATyrh#VM Tv:5bXP :}1xq\Eud+ fxI@ɩ U?9Kibo;FY SǸ,s \߈M'xgEQьA+UysV@I3~du͐w0u2Ktl@GʻjVy%Ά'u2J S9Z]|)2(Km.[7 p8T 7٬L89PvJTY|y]F<ʗfǼf;ol~5(0<zt$A~2 pmC48H[C^Q %Hg"Y4)>IZi [;t@\qFyar]-('f}w%:jܤ8WtVHzX8ܞy J@h-D6G&ܐr *͏YRkGqR+N `FrFu}o/1˶xWho {*UF^h.A34AO5oZ/|;Ѕu&d<5O.bѥ%ښO"N7´ r"bffZ8HߍD@K_$#ýDz@ކ6f&j2v5n=3i j= CShɇnV7xGT{]\`T\jxII NBu .C2%.PO_%&* sbPY%Σ0Zތv;tQYv΄],x\BϞf#⎃ja\&ܬ;ȋ#HtG.)-tR "ĞW#7_6ʣ" ";Vw3bS4.^!ov~I mF."Yi[&XZL+97c65 N[C36ٞ 9wwnG cɠmwј6 V% 6 F68Exul*RPT(v;MT/m]G[`3 hiHQ9p dIE+`L Ջ5ʼnr?a#=YAk܇7<%)`*jwAoÖbP7e5pdDK&cNdOb:FQ4sYk*VI rR@\'_E_ Bw햬hƄyH_7> endobj 138 0 obj << /URI /S /URI >> endobj 139 0 obj << /Type /Annot /Subtype /Link /Rect [ 400.519 245.491 428.074 255.809 ] /C [ 0 0 0 ] /Border [ 0 0 0 ] /A 138 0 R /H /I >> endobj 140 0 obj << /Length 141 0 R /Filter /FlateDecode >> stream 3$jRZh':``cIKYR7:iVʡud"ג f-_&kMu"yrfgl@_}aGgY5¶hx훋ދ&mMl$]KOz-->k vH"2JK]wRYdD{~N=1d⛥kp:(>9a9]{Ej`a LLO5X-)?Ma{ Ca!3TcɾK#{v(m'KY˫j$V^"mB|ii58DfӐJKY48$w2·Iat)ef@p< *%or+l2sXPhyAQPϖT 8>!7 >^c:oaS ogN/_+{, "Y -ғZT*Oi|*\-ɐ,06 ^ Ы8QU_;:d:xe@J2y]]tDŽ\z5։=[㘉>ۃ~" n%ɰƒ XW;`La)**̗]R_#SwJ 3wtkҿm7+v3d}.x`cmև=QΗT~Rs>cq@*kJvr VY]ڷ˱C"!i+}ʇc&z}lg .rH5ݎXE'REV+y|} r{_܋?Fp]Jjhy<[y o$$ء6+2iZ_]wbk<Ė(`g؄~$vg&Quo/ NZaQ"g7dD&OVNvL2NtZ .2s0Ɠ J;kQeLYdfoC'xcp֨FK0XhA\}[ʿf:ֆ U.8xn(81S̖:h2认=1%Da!)'EQxgMs`;dWMCsu7\OM@}rIO[X>r (mFZzi{ [>yZ&I wG܇r%TJnұXh+ Kp,4o^șMmim~^HAYA8=IS%{'O2%䄘!MNDtXV# 8e{BL?b< JX,CQ3U渖TŨ۳\l9F!}gjϠxKhzۘgҕB6˩p:EфGtPpNlA}*$0qņI~0֭_7[ &1LmlqPa>Dk3Tn:@!sqo(j*jf6CO kE$_s5_*«(uIb?cz&~u7U/&G6lsS.恧Ov5D`UEpNM3+, d)s+SOoQ@ 3eaRtp2/ Im1~,ûkSPP'gm8#j\$sbcf<$ I(SVFaas պsvg$F<-[{0ꐇXLB=?.'eiB>Tfa/F>;Ko񇟀MZ񪐸9Iٖݟl 4b41KAm~1:+RTB?l 7Gp (tO+2kE7 xw@=عMXw!Ϲ \J&&^0!.<{ {-",E̘> ҧ!2U1鸛չLĦR1NFkThĵetf^r@]&[g4^ۇ*N6Xpc)*Xd=J_@YS+E;auҁ2Ey8zu/.gqC=~yegY!K{]xNE|M:1DJO/hf*lZ8LF鵬U .X7x }ݺN{7k,O|k\U׸QF{S0lc{U`Sd~Y{p8cIȉ5-aaQ_oO/#WbI]Airђ~sk$}]N1񽵠tfӂ7kJ.CNvώT0J7Y7Vya?~" jrwj5fK8)݅qAeWM6CفWBȳD)iIx @(C#LpM}5;+ %`tX^ر/bRBDtqtG?gJNyW?`{}x!NQ瓂I!@5~u3ԬlxL #4UI^L_R}`t qenߛ 2eH/cޫ6ӆ1xcҮbz=_y endstream endobj 141 0 obj 3369 endobj 142 0 obj [ 139 0 R ] endobj 143 0 obj << /Resources 16 0 R /Type /Page /MediaBox [0 0 595.275 841.889] /CropBox [0 0 595.275 841.889] /BleedBox [0 0 595.275 841.889] /TrimBox [0 0 595.275 841.889] /Parent 17 0 R /Annots 142 0 R /Contents 140 0 R >> endobj 144 0 obj << /URI <10F2279F36CB0A626F3D3006AEBA93790339428300CC7EB8F77FFEBFEEE62064A35E36711809E75DFA9346BA91A3A97C9FABB37B> /S /URI >> endobj 145 0 obj << /Type /Annot /Subtype /Link /Rect [ 327.336 194.451 354.891 204.769 ] /C [ 0 0 0 ] /Border [ 0 0 0 ] /A 144 0 R /H /I >> endobj 146 0 obj << /Length 147 0 R /Filter /FlateDecode >> stream }^~y\ Sy a𻪎 U@/͚Ƣ $#PYF!QR,Q"+rO'*A;! lPXF'V[ y<{D\MMcu<X]bX兟"d%гykf Lf&PNU Qfѻx:vnp.]]mta[ /?Pfrb .qҧO\R=>TW}Cf}-1_ypf[\֥P0jƓߦ#uGCoO ^qeԃ3*ԁ+"@}A㐄6%ooPcp[Jt zz9ŁvU(s?}Nc;JU8M/ H6Ket(TJM:0=੽'Rvagi %ewJa(7uDx/ꁢ i[ Xb)ng~XJmW_&,)/#p ]ʿtR1JUɭNd5V+gEs#ݠ)pkV] Y_ =_Ɔ Tla gWl%WPI"YQ꠮`p #~:&ü k?yH[r aADadV|F`btv{Auݧjxv!Zcb(&aX.I}@ilLLb@ڀP^g'/ vw)aqHhi@QOe&Cx*"D;zzHɫCRNWUB EEC"H,De&%|P2^(Jz)Y$'_Mټ+/I14$|ҕ4/DԼt_P9T%yWu&"촕Ȏu%k<&xL w+WkɕVLPSK09+WrƋϳlPuǤ0am߽tkF3FpFvyjɵʇ5ݗKkx!B[wНz&eN|#$ڎT̝.?)Om8gͺѤ@30k:mk]]ujH^ӆ3 Ye^(#FYB]r41ܘ7 >@R8߫FV'?6Uǻr85G\%K))g *umDtvNLs|R%;餍YFWp emR(;4-wBG^g7|z))/PcŽ+X(K)^a!C(8}|d@iC0'9~kq&fY!ŬN8(H#mFu*V/+I&B-`FhPJ~GЗ1hN8{]Jd~R:{ 靴xZQҢbĤ ; 9.Q )"Q@}1pZU")N ix TM|&gGZ4g"V.lUEbmeT~ēB 7]%8x`ײ+(f約2.IBp~I *W%h]$A߼*!b/fmE_*iǣ+R?Np?]fu QєnFwKc,6)a*VخHz—LarK:ZF%{QZ Rr4F9>WrܺeC?ey&o|ƁAЂuF9錄s1҈z)g=yM]16{[YQ~2`y_ ]@p[E`1[s.º |> endobj 150 0 obj << /Length 151 0 R /Filter /FlateDecode >> stream 2nM?kOzI>hy(?5|c|0a=Gi0C9COfgH7Rr|Vtq۝#,Q!ӭr dX;{J@gRpc#$UdҤFk2Ο5` >;hɄ%%xI'AEY)D|3s8=K5,,IiYbgD? 5ыWΪZ@W6n;FB77pJQ}!,/q >28&ʙ+׫▲ܓPnq1kv Ð玛4CSwL]$@bN,%X+'2#Z_܌ _-`%d{x2`!&H]L-XDilFm8Nwt3ae7'xZ3 AO{_8I # 2CsϹN!ݵW(| BI֟)꺥;1"-a>V#A[n;lrv2[I;GN^696MPŚJ٧w4Ձ]{PYJr!ie" kD:xT@oY̩Ț[@#?"ږi:_1+Z΃&Nܰr7FI Px I=f1 "#;QLe\B@?F !]N>F|G\YW2¤7.<9+t'ֱ{ҕU)L"qgcM+5^؟溷(T=CrO^}Gf"oX#o^wi&4A}~epX5'3k09\J!k0OiBmf|-^όƳÂ{G/=+QPsɂ\eX%&f0ea` u2%r E\p?XU[>>~Y}B\-̚$/T[qE-sJʨTnߩZw3oґRdH:4nn$}xq.rq^I*>/BXg/JwYt9*Dže85^ M=g1+ ?ӡյ$g:o=r02GPF=RN3ڷ>(` eS:bҾG ۶vo,VA \0_~R'%<G[ V4ׯµY‡,dz9)C:+im{UnFckiS[nۻΩG))49[(TW"ytӰYΞ>GCElvNK+"&K< BդGۍ]ee:ZI9୊Ti訏SwVeV:;Ǵ?m!}&7C[gZ3bթ'*3䡡m endstream endobj 151 0 obj 3295 endobj 152 0 obj << /Resources 16 0 R /Type /Page /MediaBox [0 0 595.275 841.889] /CropBox [0 0 595.275 841.889] /BleedBox [0 0 595.275 841.889] /TrimBox [0 0 595.275 841.889] /Parent 17 0 R /Contents 150 0 R >> endobj 153 0 obj << /Length 154 0 R /Filter /FlateDecode >> stream RQ$bvfN>/`dM*.fr5Xy9,Ӑw#写ma*+"t"{Q]&#H T4Qa.ѱl ?% ,i7@)7bhQ6:A/ٯlM~'ML |.Vgˤ8&%K#rJ);ͧ:U8]eb˜pJ+s% e9E4'ہM([33`#bos "i5=A{Cȵ@>[)bhIe$z9A e;㤵q6m E1fp?'t<7Sy{Ԉ 4z?5 Gqv} g &ڽ.t6WTDkA،z,`-gdCvX(EaZރB1ށ:a%,_ߚ_ 6q]gbN@H-Rq,ҕ8g*$4f/n̛@\&ɴqytDb2SqFD]sVo訶:2W)ߞHݸ1<TPKG``} jMg1ʠ%j0.lW$Er|jV my6 SvP[(ί!9+/ߺQ>m%x ư3ʾCl:σ) WG er4 U׀ҡ(ǀ2%>YVHkeN0T[Fw$0kbbX,C}W73*',a3 C먹ˮ e-b6"i0HІGYm1anvU7SkOyK&lCYqa%4T&Y N߳Jobz$IĸIf,K,|LѻP=5?yqW䷊F J0:j-[O-]{ngqz:)(  #e(Kq[}a?±EI*VЬK5W`/l;-*uF "c\|F+Ap(=jN)'6BgFAa/lWΔ㢪"MUft`4SSG4T!h jV%CL>.mfoz1 I@҅tWvo"f OgUj@g6kEПŊg{{yT6?#€W2{jjțl4nZHѿ7~Q9Q{trHb3كO'-*0 d! y]Z fZpj_+W_K 4ɢa`fHIk/J|ć8?^IODNMdҚ1=`gj =`zc$Mfb= IVQ .9$ʰ"|If> endobj 156 0 obj << /URI <55F1D26237DB5D5E134A7FE591B5E6C30A79F836348C3178FFA656755102C4977A6756F163AD893A6A017486C4D584CE1B324F87> /S /URI >> endobj 157 0 obj << /Type /Annot /Subtype /Link /Rect [ 240.106 365.445 267.661 375.763 ] /C [ 0 0 0 ] /Border [ 0 0 0 ] /A 156 0 R /H /I >> endobj 158 0 obj << /Length 159 0 R /Filter /FlateDecode >> stream Qc '9/tŚ Wb̐@f|ȣW tyiWȳl(иI;dރсTx]@GXYD1|Ƽ2uaDVV2.n;qwk$l^o} 2eٱUu1be]sMNGpbm;FkMn̨c1H {wuKڬOӪF@m.6x-xV=Aa֗3>/|&6DZӦk6,-V9ryr`PX3pq[ $?6aL_g*lfPњ%vObңB*DXJ,ѹSqU `H]\6${01O$n)=x~brsݽc0BӔgcxr%^`efwl &fdkJtyur}8 lGp=;{Q; QiC|h$_cBja JDJҧ)g{JP0jq!_.5ɻpE`=:%$?1 -YT GdBZ+[S M:EjOV(Wx h1#'|n']+02A 8N:ѐ1? ;- o!C@iWٮfSL~1eobl@t;\"p|>, }f5mG.# Si3ƿZWq'iPꊨ7q9Κ_6Gx'GOK҆̔t6I6X5'дNqHm]G0u.s7+6eNFɗJǯAabE?*~gux1D(lɗ>j=n1b:hu,8ԣYfŦf:3S-ev}G^.Oдy4. +G.< @$0FmBF[.FqxggӄơD;mntg~ n\+2 ^)"D| >yy0 -:3 UX5߀Q,CzAozDKxHỵBg:ضB`66i9`S}R$R,1EE0-׋^T|dP! F)D6,YS{2Uj7<]U78#_'&f ee ZhծV8Nz ,QF{_dػ0QвgP5ow Y:+{Wv2#8{@I06u%cpb0>s :cnNc_{NURY0N'UE9+O J+t=)[;Ӥ̐cEzҢ'k=^D[)`-(;|G5Og?1HB2IͿLIH`kjU(H'5OR4`OgyChv_KGл$WqHl/[5]?1f@2 CC1. zT}. 9F2Ds d(up5,nާ8Mdm;b+^htP k\R/=eCss$d&ybaZ^Xؤ,a+Te9WuD>4X4 (eýψq҅ اʴ0MlZ~ /%]'8J!63GY[=2AkrgWze փΑ!}_j7٬s.]jCDg<9IicL"{{eYnQMF,{jk&\S-E&h-z?)SvzN-lv:.H=uNWז벪V#KE:6I(\oM}!ͩ"Su2Zzͬl\ŏoa +Z[$hAWwyY~8QӮlxN`&x#Ρ,[/؅FFy[DĖv=]h]B}fsN":f{}9ؽϬ{| 7 d|~uR8phf1{~TLt5ˏ/:|Ho'F{(̆2)< Ɖ?:%!MqLߋ_e8]; endstream endobj 159 0 obj 2872 endobj 160 0 obj [ 157 0 R ] endobj 161 0 obj << /Resources 16 0 R /Type /Page /MediaBox [0 0 595.275 841.889] /CropBox [0 0 595.275 841.889] /BleedBox [0 0 595.275 841.889] /TrimBox [0 0 595.275 841.889] /Parent 17 0 R /Annots 160 0 R /Contents 158 0 R >> endobj 162 0 obj << /Type /Action /S /GoTo /D [163 0 R /XYZ 56.692 701.575 null] >> endobj 164 0 obj << /Type /Annot /Subtype /Link /Rect [ 184.437 756.652 220.484 766.97 ] /C [ 0 0 0 ] /Border [ 0 0 0 ] /A 162 0 R /H /I >> endobj 165 0 obj << /URI /S /URI >> endobj 166 0 obj << /Type /Annot /Subtype /Link /Rect [ 56.692 445.947 98.767 456.265 ] /C [ 0 0 0 ] /Border [ 0 0 0 ] /A 165 0 R /H /I >> endobj 167 0 obj << /URI /S /URI >> endobj 168 0 obj << /Type /Annot /Subtype /Link /Rect [ 276.23 241.863 325.829 252.181 ] /C [ 0 0 0 ] /Border [ 0 0 0 ] /A 167 0 R /H /I >> endobj 169 0 obj << /Length 170 0 R /Filter /FlateDecode >> stream O'vXh6Crx8vG ^ U0&5`k.Aؤ}MݶCngę39q-M i Vcr.2Nt;MaF JHBɠD| 'ޓ *sǸySU|o&}O"^q?PIfabRrǫuݞ%D6U /p)Ï:s웚?Щ+ ttT1[**)oib5Vga#Sh]( u{v>%#ݛ­̹ MN6` V8gJs$!4rݨY$pqd0v{ F _|И\Uo925(?Z[P&6ɕUhn)|A,ۼ57 NILW+O=2қI3({Fr ﲍO31K/h8k:^0Ѱ2F(&5%-==rnr,ٍrLjyZ[h8dHq !Y<nyyc:qEh׸D AAl.bB>\Zbw)}IzNv E?&j~(@QN')! 4Lz99ѧ vqtzx~wղF%X^g "=kR >aZؙVQZ@ 3N eGU74:x"5D=a(fيjO_ǍBd4FOEݍAܝŰ͹w VUc!qnSWZDz/oniPMJQ7 8?7unK8U{r6 X (+\w77 Id r卶9i.Hto[Vb WwsbB>v4IUh y(J q&eG@*O$("2{BknFFq (?M]@~;RB}un'?)jAClX8o.%D_40 ɬM%nUaoۺ^0!Lԙ ZɐHktqvgI[˿Dy%_*8HqOY!DNkC_$1vvf=~MQ|kpOrL6~>t9XD͍[ZvI <ݍ[a6#o}Y/(Q|5G!4lc.RT㚤33ɣMGT-W^7o%3!|[pYI?EkeORyhIb =@SQ~t??b?ΫN;wCL8P2a-=Z'p)PKxx* m*A WbG]9/$[!Id</afeC6)yiM?<Ī3$aRyXYR&;VTntKM=`Y(&~EʴD71d`qk+~VP㓎RUC :'A*R0Br5r"BS]ϓʷ. ;F_a,S QV3>@'J/ٕ1Bwf58{s*RvCUGs]‚cNf~| |4wkc0O'‡&Fݮmf˨t( %2>#?~2O2}L[l^'H+.e[^8m,:ٸ荺9 0*;z4x{ 6Dc$r[ `:/Sp6`̍~y*J&-7wE<3&@&fUc~' 5}44G!3# 1w]Y7*AZtNUL`yQ z{j˰K pE΅쬲SKThy1.{/5R*l։N ]FqěLio2i8-sJݛAߗQ7v"b;Va>Rvփ^%MirC[ͧb-2E$%A:0LWEF:I>rTQ*MƲ Y.h[,Tߜ/l 5wr-}oSQd{ .s~J ȽlE.JzcG-ͧ{7hǢFg_+|J R,nwפthgD5"\j4h^lXPҍ%EVV ^#U*Ix'ٶ]fİ:H8v~8s02_~xq`%;"V6-=cڧ4b:n慀銹`Fɉ kKh@o|xvagǢ$CB~YNAmt}.t? 8UCCӭm ^BmCTq4+F#+P@W 2/[W"nūEb|ͼРx;E*gEB > endobj 172 0 obj << /Type /Action /S /GoTo /D [83 0 R /XYZ 56.692 680.317 null] >> endobj 173 0 obj << /Type /Annot /Subtype /Link /Rect [ 61.192 699.716 97.239 710.034 ] /C [ 0 0 0 ] /Border [ 0 0 0 ] /A 172 0 R /H /I >> endobj 174 0 obj << /Type /Action /S /GoTo /D [92 0 R /XYZ 56.692 268.77 null] >> endobj 175 0 obj << /Type /Annot /Subtype /Link /Rect [ 61.192 574.916 97.239 585.234 ] /C [ 0 0 0 ] /Border [ 0 0 0 ] /A 174 0 R /H /I >> endobj 176 0 obj << /Type /Action /S /GoTo /D [104 0 R /XYZ 56.692 350.564 null] >> endobj 177 0 obj << /Type /Annot /Subtype /Link /Rect [ 61.192 542.516 97.239 552.834 ] /C [ 0 0 0 ] /Border [ 0 0 0 ] /A 176 0 R /H /I >> endobj 178 0 obj << /Type /Action /S /GoTo /D [113 0 R /XYZ 56.692 304.292 null] >> endobj 179 0 obj << /Type /Annot /Subtype /Link /Rect [ 61.192 510.116 97.239 520.434 ] /C [ 0 0 0 ] /Border [ 0 0 0 ] /A 178 0 R /H /I >> endobj 180 0 obj << /Type /Annot /Subtype /Link /Rect [ 268.555 496.916 305.119 507.234 ] /C [ 0 0 0 ] /Border [ 0 0 0 ] /A 120 0 R /H /I >> endobj 181 0 obj << /Type /Action /S /GoTo /D [125 0 R /XYZ 56.692 363.58 null] >> endobj 182 0 obj << /Type /Annot /Subtype /Link /Rect [ 61.192 477.716 97.239 488.034 ] /C [ 0 0 0 ] /Border [ 0 0 0 ] /A 181 0 R /H /I >> endobj 183 0 obj << /Type /Annot /Subtype /Link /Rect [ 61.192 418.916 97.239 429.234 ] /C [ 0 0 0 ] /Border [ 0 0 0 ] /A 184 0 R /H /I >> endobj 185 0 obj << /Type /Action /S /GoTo /D [137 0 R /XYZ 56.692 379.658 null] >> endobj 186 0 obj << /Type /Annot /Subtype /Link /Rect [ 61.192 373.316 97.239 383.634 ] /C [ 0 0 0 ] /Border [ 0 0 0 ] /A 185 0 R /H /I >> endobj 187 0 obj << /Type /Action /S /GoTo /D [149 0 R /XYZ 56.692 556.783 null] >> endobj 188 0 obj << /Type /Annot /Subtype /Link /Rect [ 61.192 288.116 97.239 298.434 ] /C [ 0 0 0 ] /Border [ 0 0 0 ] /A 187 0 R /H /I >> endobj 189 0 obj << /Type /Action /S /GoTo /D [152 0 R /XYZ 56.692 453.763 null] >> endobj 190 0 obj << /Type /Annot /Subtype /Link /Rect [ 61.192 229.316 97.239 239.634 ] /C [ 0 0 0 ] /Border [ 0 0 0 ] /A 189 0 R /H /I >> endobj 191 0 obj << /Type /Annot /Subtype /Link /Rect [ 352.749 150.116 388.796 160.434 ] /C [ 0 0 0 ] /Border [ 0 0 0 ] /A 162 0 R /H /I >> endobj 192 0 obj << /Type /Annot /Subtype /Link /Rect [ 61.192 130.916 97.239 141.234 ] /C [ 0 0 0 ] /Border [ 0 0 0 ] /A 162 0 R /H /I >> endobj 193 0 obj << /Length 194 0 R /Filter /FlateDecode >> stream >{km]i=Jbp,6AĆˡa3x;ԫw{at)C> P,(7Qxf|) T!UW|F73ň 2OP-NaIq?v ^.X& 8es-TI!}S jkbΜ#$Aٛ2~^BqS!Sgˉ.(^nGyƙ뭯K޹ q-*2ۛ%ȯ gKC .jmm$pl\WӮ?rF  fe Mǁ.3Ty3}/H T)Uuflvi61@8!]\@s7O"W,%0;1߆b%l e^?%qث (.uw ]ȁ2}`ӨީQP!ܲQسS=рzlmwf}/  q':[Ltd5fϬ{ N^q"eيmD6Hk%[/2κ %ND⭏eؤyaEx-FqaPݷJ. lsӁG[=AMFrTI2;.BHԫm04> }i =L8*ŦM\`ZJN)-q"DʙҽzKGX{veZq8'J; ɳ\n 3v3߆ ~(IȞôIXKu>VQ'`g PSd}؅bR!cd߹Q̀Ѵ JMDyq5~*;eC#Q>?368ԴTآQA x-Dr8=N gxoFlʊ[ԇ.H(/=˲+ΰo悔]SvK_ciڡ=bmItHJ<0ZKyDHa&17H.M` Z'Öz¸uDV;g'<6ELJ1/\5UqXm_E>Y5]a\uv5㞎JYY՛|HhpXDwCyQr0qư^%t03$UPnO_ݶ@+3jő @$_,R|XMo@<6k)#bID+YHUȣ)n;N#giiV8,z4xHv>p2oVtt7w!'"`@r4墯 p0a8cY oN~NY7n+W_v0c༣<跴$=CCr,< J?u{Hm60z)o-<@@LJ1(іQo3!'aD jWg'ctP@ { j X}(*?,ftɊJΗ)hjܽ _dTGdbԡ8rxnР5kIJ%?4}<s9gxyi58sjsŕ!Zy6 8 */7`?JX)!,<֑8ZᚲSYk>|ț0r`.࿃ W\1k o@%GRTܣH?Etl8Xaj_C+-2< N ɇk K-){jJEwjxZ$X_8}Cv_/,jF2qC_j"}зŸW!?tqI9k\F9+,IT`BPTgigf{Dsj`Шg:ܷ/M˃   B¹MktmATDp*l,ezlS:-PS0A10;CŲfSA?⥃B8>̮+v6ߏ;>=6t_ZKKӬab-F+S=*4cY+bz4SCGMC25Z \yCex(-%uƆfvTA}2 <2^D|{D@[(6VX[9Qv~͇Ow0ÐDEw/C$ōL&̸[!. l˔x=5)2׾o˶/pc/>φ4 Vp8D 'f Qwäy즊k|A4YP[; icC|L^n=0,yFAtޟU"I|vxKIpZBTrSA?=Ze*0yٝd~u8a-`lGI D/׫@Joj{ԉsfPi["8?"Т/Pw5Oae~Q;5 YHZ/ D.C,JeA`]PVt.DmNTh:]B+f-Cy[ yh_en . AR+[6twjTU;g|%BGDFq)rbܽz^"ĵm wk&;;&81ג#\` C͏=X3&\Cҿ Ўx*;E:`|sI ޣ7wjI8UAG =C-M(>%}:C{ήJSO,T;J/L*xZ,:Hi-H&,yBbDσN OERGOꖩbB Nʉ'߉MY:DǧPiՋܑFb΂Ք`{w V{0%8m'93'cuQeƓFs"P8Qy|Hiرx˿Y鷘 Q֕%w Y%@>tuf/@$QNs.j9[]?avRC{;'H3_'|\inhպ|諃xy\]vaVWIq8K˛z~ƪ\,xpfYUY0v/N/"n <9d|($Z 83Vykό)"MU'&CW+-1TFt.(|Y`C/ؖaR懲WlNN>2XJc]@3jLdÅbܵuy+xU+/>O$e!G%^?Az & .J'wy\k1T PAx`bUhp,ZAB4)x^ף@!.vЗu+g{] ڦ=ɧxM#wjA5 {$ʜ#f \6fD䳩*I`B?4OCtvYt$r@1֥rѣ-Wy@ G}Ĩ ȣ ɸaK#\Q)%;_o;B}(;eê&ԕAY dBҭd2tWNNB@KzkXS9YèS>B& {~m/L(jPܚcYJIm)i*>lYQ7ASm" Uc Ll2%Z*`גJ4c+N@$ݙ\H3ܴ8 mV3yFKL)YsqSJaPҝӟt\qtҹ+]\ o!&73$ۢP`rC Ţ ?s~=fy'ijzj#LMbb$:s)9:]^_=}Yy9t/Qd(Wü4+B},*,*VyZ  ,21ķ*Mċx[ Dh#<s;}ڋ WyL@ϼթh  T]v;(QUOFЎ-Vnc5Ld c.)Ut/'j9PdO 1Eం81 dF!+>Krr &/ bva@0c'ӢA`Z&+>N-{9ϓ@( endstream endobj 194 0 obj 4632 endobj 195 0 obj [ 173 0 R 175 0 R 177 0 R 179 0 R 180 0 R 182 0 R 183 0 R 186 0 R 188 0 R 190 0 R 191 0 R 192 0 R ] endobj 196 0 obj << /Resources 16 0 R /Type /Page /MediaBox [0 0 595.275 841.889] /CropBox [0 0 595.275 841.889] /BleedBox [0 0 595.275 841.889] /TrimBox [0 0 595.275 841.889] /Parent 17 0 R /Annots 195 0 R /Contents 193 0 R >> endobj 197 0 obj << /URI /S /URI >> endobj 198 0 obj << /Type /Annot /Subtype /Link /Rect [ 82.203 106.053 242.11 116.371 ] /C [ 0 0 0 ] /Border [ 0 0 0 ] /A 197 0 R /H /I >> endobj 199 0 obj << /URI <3F7079EE9F55971E7FA33FB8379DF9296CBC49A778993FD4EF8AEE51B32DA6EB07290D148A6D2EB7AC098DF6DF25> /S /URI >> endobj 200 0 obj << /Type /Annot /Subtype /Link /Rect [ 82.203 87.628 268.686 97.946 ] /C [ 0 0 0 ] /Border [ 0 0 0 ] /A 199 0 R /H /I >> endobj 201 0 obj << /Length 202 0 R /Filter /FlateDecode >> stream 'y-zk5a社;!2.=oBT־eG7*b䅉P;U%ǝS<wKD8u4TZFKdlݿv f%=}KC9ĩ`v3@%*EZ*ŊH,G6vFd?&ǃ鷶K4pJj!릥Hz" Mf5pƷ#D1n%Md ~HBW3΀>rsE t,P X&m+h`(r@B_~ҔT|޹OaTh\4l(#lT]j1c-)}J;y[hX4 .p R R7jtt91-3zs9!+rBbLeUVqh(C%Y: ԩtkX ("mC4͇pB%pFc 48`BvU&Fܮx|%Ӣ{쫲bQ(D_~DsCUtB(| P v3sg(L C?`^p L]hǏ^FRSQ'NẊGʊ$r#.+ 8&.=x\\t eN _Y=5uŬ0,Њø2*% M<re=DTY?_ ˆmdRFFNBy44X&VFeX  94#Ul: ^$ 1g,Cj(2wvʞ%d9Gvn8/[洭DL G.k_]>XCT!fup(aoB8R+Aj)7ڽW*-z3EJ,k!Կ  3^w2>]m߼`#;PhmczdfďOio 8䴔n ~f7wŹUB f0AV Agb^7U?StK3Cw$d}4<*4̤@#dZhT J[RbZwz;G^=U=**9(*R J[AX`4?&cRx)ha {d6XޅWnfyG7@^K&%09S06YӘXzZ {%XWw|bW łE\k+ZT;Ep'<@Bgxq~|!+7$_.@JJFy2NcNkS0yAQ>w:N [*^4zBւTHx9:()cޗ f2hR:H> endobj 205 0 obj << /URI <19C1B65F002894AB54784492EEEA77C84AEAC07B46FF5679D89FCCF06A1BA9904C78036D95C04FFB1A6B17> /S /URI >> endobj 206 0 obj << /Type /Annot /Subtype /Link /Rect [ 82.203 756.652 247.126 766.97 ] /C [ 0 0 0 ] /Border [ 0 0 0 ] /A 205 0 R /H /I >> endobj 207 0 obj << /URI /S /URI >> endobj 208 0 obj << /Type /Annot /Subtype /Link /Rect [ 82.203 738.227 266.706 748.545 ] /C [ 0 0 0 ] /Border [ 0 0 0 ] /A 207 0 R /H /I >> endobj 209 0 obj << /Type /Annot /Subtype /Link /Rect [ 422.838 683.662 456.432 693.98 ] /C [ 0 0 0 ] /Border [ 0 0 0 ] /A 197 0 R /H /I >> endobj 210 0 obj << /Length 211 0 R /Filter /FlateDecode >> stream vъa79r YY\&0o;5' ZFXw84K>BGdtE!AHmg(vOϫsI8߅\< Er'V[aS7^d| C3G+"[p ò(7t^ޅh3w5c⡲*HԫArbH?{mtikRɘ3D71>L'@KjemX3TA=qPw,#cLL*4&A<#*qLQt Z=+%Z-"{7sfPQ,hO$ѓƉl8 Z9n2v@*pvXѩsxb}wF8,2ha[:#Qe?K p')lf_yXΩt/cFF_7yKT`4R4e۸kc6JY܅ky@W.#Q$ a|f.ȷV=8'+yL I0G.J#±EDG2S7LTgCfv`RWRLْ߫$Ah`SX]՛E/Z@ьBX~M :Ǡ -z 2c"1"U<0>/ø؊q9*Hpֳ2V{-G eQX=2!OSD'~^w('R. H;WKlYy j}7%3|n)3>=Vy/9iaKԗq-2b7\&9DDP"vWаd[za(=ٸ:zF|= {XF.:fsng zyQ 9/",!Gխ*je#:tĖ:c?U0H,XZQx]e:G/PDVp y.?3aE>W ZNIx|qiw h0V*-0z8QQ2?oΦ'dwyZM/ m%t|a Ad׮9HoqifMh.@ gV0 jO~(NWSh8qc~?:H0W.'XGe3~v0i:+BF C55-S=^*)t?$8wcz] T9vUr!f*cϾK%iJ}$/vL%ׄ ʷ J~aPc ;|V!OrKG{(7ynhKܠro .̞Hsy3]oc4"OA6Jo;;% s6f#7ޟSL̼L`db4,,t"f [Ca Sz-mJt[L/ vX+ʄy^4^L.&c-Cv}W&—TE2*ĦhMơPYSۣcBv!uP7:I^2_L^g%{FUYp-Ay|1; 9dv1W&~qebC 9RAdj4qCvrL_aKܔVczSy7vg8FƏ_ \`GݐC`:=6ez$,|AçܛƚD1ب脻cM2קk$:)"`(lўIX^fCKG6ZG)'_Mbv-:%;qxftKar~%ҲIb P8qfR$;;Bd-HWQC@_L-ۮp"NCA2scm3eͣ/|>v^~rAͮ]Hb Cݷ)HLiL&G& Tj%UI96],lǃe! qp+@q)9JAE>S2g#ujp0veNW׌́>nЖ1oݭg;+ѬB4p!1Wb2*V׋[t *Vv!&2o5R!#E3y&m8DFbuT>lrL8iI.jĽ,zrDcA5 XDVYILs )ˤe'!hSbTqB/1vNm@ endstream endobj 211 0 obj 3243 endobj 212 0 obj [ 206 0 R 208 0 R 209 0 R ] endobj 213 0 obj << /Resources 16 0 R /Type /Page /MediaBox [0 0 595.275 841.889] /CropBox [0 0 595.275 841.889] /BleedBox [0 0 595.275 841.889] /TrimBox [0 0 595.275 841.889] /Parent 17 0 R /Annots 212 0 R /Contents 210 0 R >> endobj 214 0 obj << /URI <8B92351745D8AD040CE6A9D4238CEEFBEF22A22CF60740E0DBC4F612030D29905631232B3CAC17E00345480E9CE106E9AA917A9ECC61987231085854E6C7A569A435454208ECAE30503E2CBC522B457364E69B4FCD1321E3EB07FEBDBFA74170240CBF7D75A8E159D6ED3ABC08932F00D194812DFC9CC745A0DE83F294EE97046E1376BD0BFEE5A95E5C4026A886A931F05E> /S /URI >> endobj 215 0 obj << /Type /Annot /Subtype /Link /Rect [ 90.286 581.165 180.244 591.483 ] /C [ 0 0 0 ] /Border [ 0 0 0 ] /A 214 0 R /H /I >> endobj 216 0 obj << /URI <3916FF15AF9AE7F03FF58535B94DD4D470E29C800C8B48F29938AE2E26DBEBB11B7222C05F21ADB169D414F5170AF7FF40BD07A6> /S /URI >> endobj 217 0 obj << /Type /Annot /Subtype /Link /Rect [ 316.996 495.799 344.551 506.117 ] /C [ 0 0 0 ] /Border [ 0 0 0 ] /A 216 0 R /H /I >> endobj 218 0 obj << /Length 219 0 R /Filter /FlateDecode >> stream 3 ו᬴ۭgAH},7_̒R5}" CRS7W&4L-"#*]j?bglQ˴4_PvƆmwޱA9e o{[ʏ2f>矩};2mAdJ~ޥ s~ʓƍrF&|r*yU>]yw5L0+0pI{Xnm$[/`hu_M.d/DFAތ^QȑOP}8-md (6+_.;|oN.rُX>ƤGG7wJXۜ2XLrI^A˝#C^f}\OtnT8Oߎ9PA׹>\L0X\t_ ;9aRVfaF'R4Ha^8QE3 /( S,O7dQ.OήGtZ$Gl:*,)r!3/fF/R) C'n?}#;aP̱޼[kEpPULV=;p셉&02C|p~AXQ:K0jknцY;0m"li9|PI^8dӋ}~A0^J .RzƻC?)*c ӝ3SlNyपVH-i*曇nu 0yuG4$*߄a%r^^#ȫbI?_n?*7\qsH/}3F~=,`;v/NM2%(\W^C7?ь oYMk b˲?czyUkKVYY-+7f*#dpm(u9Yh$?% gWC!Qq ->b5/V͙]BV/;DzEX8Mu %T{Ii*XK2ILӾBOVB3} M:WH :8InhceaoGpxTUd 8v~"ěPX _ +i6;7qeW"rdܗVlϾ3W,b6o x{T,mߕLn=Ꙁm#'*U8c&+a]DTtP8n-c͸\!1lTs_zW%-1GsjJJRGwSA8/sm 2 *h"Ԡ)"(X%^Hx}3 "O6`S=KY{NԭLCo0D]P|;HqdOsLJng<ߠ0V:A?լӲQ):*ػ#E0^4E4P>AcME#PU7l8'EΊ6ȳP&}/ut Wbz&OoI =zfs=Ռrؒ4gPӑ0 $PʞV7@j=?X_ikʸ-pv<&4TIsۊ.$s7ZWVu S2Ls:V[zY&_yUAQx8VX:vbs)[M]MkӬ%At? @h%0;Hs?DڙTcdl7+Ognug.ux`Wp"@DU/2ėq"JF&@Ƕ;r%LͶɐoFGB99XV J%kWjO`{e3֍L]^K,=%tZcK#T?od=6];8*OIt/f(#,be$JSE0 31* ^s}@ÀC , "84g37s`}ol1ew# endstream endobj 219 0 obj 2690 endobj 220 0 obj [ 215 0 R 217 0 R ] endobj 221 0 obj << /Resources 16 0 R /Type /Page /MediaBox [0 0 595.275 841.889] /CropBox [0 0 595.275 841.889] /BleedBox [0 0 595.275 841.889] /TrimBox [0 0 595.275 841.889] /Parent 17 0 R /Annots 220 0 R /Contents 218 0 R >> endobj 222 0 obj << /Length 223 0 R /Filter /FlateDecode >> stream @.˱$-ivs70 A(۽ HO]&:s) KIN/>QG- ] ]kaYQ^#!CJqZJ]}j8cÞf@Bsi6h#xܰa8SvWl(ZwH9u+PCA[Q[,$123 T-T>,1юiyxvzꃪ' |83!JD|_>G^uЉ'5pHɸ^%k@䑮̺A.ݦ $lPmpY9m| [R#I inUuҙ}H6~gY)%t4o?ѬK!K;Ɣ6lRjqT8hJ|qY$T/ANIe]GJݫWoZ0d[T'@j$\N]/C[Ї1rS:1M>hAT}x\w67`sEPn工3:TpPH_1,_q$4j {T MrerQr8S $TYE=xD2ng?4:f!`ƙ  @]@Bel|OFFR<Uݰ2&qf`NHĿgwXUK2:$& W.kLoW}s)%Cƫ7 `bk2棍e"kr!g^!xe2wr/3${x!?^ftͪ~4Ml$0Xd(*0@Z(@@zz2w@aIyje'π!{ʸ;/H[%9:T d6WoVQǓ+L멸083`2@Z@rn܄&|hmb y)$Ub4>"F??Xr+ -)SP8 kLo(93Q i'WBtCL FyP`5c aQ~>ʵһAj}{}F:( _|N0+9]=|_ljԂ<`ui|TG'ݘNZKсc#q"Lm|jih#HfPxvcϟcR:"=!9"0ΙjDpMT+Z)Y8a|o}CGKn1cN endstream endobj 223 0 obj 3601 endobj 224 0 obj << /Resources 16 0 R /Type /Page /MediaBox [0 0 595.275 841.889] /CropBox [0 0 595.275 841.889] /BleedBox [0 0 595.275 841.889] /TrimBox [0 0 595.275 841.889] /Parent 17 0 R /Contents 222 0 R >> endobj 225 0 obj << /URI /S /URI >> endobj 226 0 obj << /Type /Annot /Subtype /Link /Rect [ 125.849 187.775 153.404 198.093 ] /C [ 0 0 0 ] /Border [ 0 0 0 ] /A 225 0 R /H /I >> endobj 227 0 obj << /Length 228 0 R /Filter /FlateDecode >> stream U fR{W@iEZ~kIl)>* } eu5IlS_"dÐJN{?yef2JTQ,$2.~AbEk/> [A`6KHs4שEиCRy8CbPtGwaN]-ԼVyTqFn1/Fd4@s|-_60sH+Rh=׮ ;k>ջt,is%#& q91i(s?ໄd;1qOńK$G͙A*fۑE LßΥ+er|Hj%,qAd~|hB%:@[_~&?9c `}t{Fk2c Ka%gqaxъU/k7 %*ٰX0E-Q2zNBޤ>?1>Yn lwMX/~M*]Z(<2./,P+B4a4`5XMP\ud`Ɉ?~4 wUlN6]DAmnDe%zyȩmh7`lb-"-@y"s]rƽ0خн&GF J:GIMnor+m'.Q&\c(_H*_;I?w^`3_$qcwDڙa }P-++괛!R\N\^䛢}&53nP3g2G[ 7(Dzrd(۪O}^{dLfZ(fyǏ^TeZޣ@1E1.v24Uͧ0TXpER}kƒtDr@Ðz4M=s&miE{%sO7ŪXC[PSMkKh3N8oQfkF3ҟ [DmTƎ0bVR]$IT~]|3{ǥE L^IN3CVm,9qM-PQ Q^] 3LhQjrB@v·#!,_6j tšFuLVY:q^=?рj_Fdr_?#tꏹ{#8.I#H~mMe'Q%г/[!|z *|s@T?zFYpic9~P6)+ӛC_ Ek_QY@&UaFGoDwWK!=J_+;n* d}Aݵ{>_xۆO5 Z̓tb r.yS&[qP6<: /=&Ԛw~g2$n5>Mjg"GI1MM^̰'h=Ӵڥ']QxDN`GBC9'xF/2K|/%' K~{UU05d.wx-KE KU` S͕(9ѩe 4r4 a0LP2B$s3lFJ٨#6Q1ߊNe~ B_ߦ9"m:;|ռ[c8"׭'ߏqT!)4Bv|4iOņoͯDOHӾNkKCj# V^ijlKI\1M(: \+v>؍XHlw կ THWUc@u%YRŧ\Kf+{v:w.zE7_]LN<+&YN=@kcb ;Ѿ\x[Oq2QɰS}X"^uQ}li"klEdZN*hK,c *:T}# 1W &pdҧԮb_WqWb@߆Cv4A?Awd ]`*neDZMC٬!XC 9Y6-\7N AFEZ춎-~`A+gE+ڳU+u^Hgd^/[2s#$S@lq02T{MMtrL$ڨD`bRԸ)fge}Lͯ!mqE{U=/N/0dAg(m4baP/WKm%g OMFW k4h |(Uj#]#Lj[ Q6Rz^Λb,?s/yvC1ܟ:r-p7t7 ];:G ]? Xgb: Md1,ZI˰C&@gZ"[`1q6Ю"eM_*K |SYcwb(sD\ 6:xr01 |~>96q{z#RmQp <5ӣ&78%ج}?_PZEQMFx,RwIl܄_8c;JUrgG%?a.U^͎Ut'H7QlZLr;77 xhƩh~-)N"GĹ.A|%2ξ]%‹^etܛ~mMsթWv3 -֪D#,WaZ"cSo=.Xk(/QI׸["ݏ"84B qk>~)-yT?p~6RiobV9E?Rz]a`[@`sh|ٔSLCJcs8$jN؜!3b͞{DgOW1għG[πX3CzHGE+ɯd!p~vG]M;à7b0g\D!oPc‼xYلZFrXJ7g u~=t}ߜuڢV{]#lBT$fm$}-T%KCZ/kLԌ?V3)BW:NF,?'(A3p> endobj 231 0 obj << /Type /Action /S /GoTo /D [232 0 R /XYZ 56.692 593.633 null] >> endobj 233 0 obj << /Type /Annot /Subtype /Link /Rect [ 266.673 756.652 302.72 766.97 ] /C [ 0 0 0 ] /Border [ 0 0 0 ] /A 231 0 R /H /I >> endobj 234 0 obj << /Type /Action /S /GoTo /D [224 0 R /XYZ 56.692 771.023 null] >> endobj 235 0 obj << /Type /Annot /Subtype /Link /Rect [ 366.894 648.71 402.941 659.028 ] /C [ 0 0 0 ] /Border [ 0 0 0 ] /A 234 0 R /H /I >> endobj 236 0 obj << /URI <0764A6958BCBEA7904B634650369987982FFE29D689B0FEA66BBAAC5034AB6F742311C3F8B> /S /URI >> endobj 237 0 obj << /Type /Annot /Subtype /Link /Rect [ 56.692 210.452 90.759 220.77 ] /C [ 0 0 0 ] /Border [ 0 0 0 ] /A 236 0 R /H /I >> endobj 238 0 obj << /Length 239 0 R /Filter /FlateDecode >> stream _qJ3| 6_9 gnޱ?1mmA~36̓c"G&$ 1HÂ*LІOʙ8=4;SsMM$w\*J7 ;iJFߤ0|^B Hg/Be^qf(~XG?ݘlp PZCdo.鸁Fd`ʬ^`x>= [>J'$:YT??Q{MPz2+]izMFkޠ/[(t1>u<Ԇm0FԱ%{$m*I3Ha`& v5r1^8Qs4CE_IX-F姝 TDq(71kFYTK1-k`> D+XS(Yj -ş<`ƹ0ؿyx`jI^LԕaӮٓAFAHκN#םڴK܁ **"@$%bqu#)\#qa[x%~?#EIRݻGJ|羶RDچ_G.3Rns+Z ՔzKV2Bcmen(;6@5sߨA>]`AҎ<5HHAS`y7  H0~ KFHP d;H`#ľ};5[Z=h(=Z0BIN}]ea"n`vi:2mhR=/sO3wR! }9FOT*bjėza*4@tƺ "B-QMl*{ /W{,r(O>&雨cx#]2-yo])Z+}0"&tw`d; Oq^y:iF'}Ap$>+-A4)3oDir臄+/a$lc kng}##bFy˫#xCk@~8^,P:L1A)ɪ6U(׀yFNSך} ҥQ]&Rz~bC7o=^XXkȭ}+Hd~$۽"j)wg ("KPBu@W͔ ,}O8a]\N.Y,YШ#1&B\ǫ-ei:!zڹ][4%?5mKONOsiZ'5Aw_LLT#RQHӈۑX{|z='\펠+w'KD6@*s\g-R +l O9=Cm$<q7~-kFQFDY7C3X!yh?-B2))sfԔܯv2?ݞ]R%XlFFbt82s2ͶMZݓZl[Ŝ=`9<)C9dK s<{,ci '(:u0D3꣙VH;`sK)N_㊿ $I(\9 _QD|ۙ<3+m2d\Z7\1y~b8>>w"PJxE^%kͥ"ntKi,YZB;]x"T0 5Fmg1=Ы܄zCPFbݶw.7+;Mh! VZ@ : uuCcl͉ASwP"35g^+)zrs-$ ⁠WSgJW@8 /Q 犰C;S;ҫ$)9#d洞OXR]UY a"])Jf%brHtHUY$d= {A ꣐WR' ʝ(A0n/hl#h_V[8DYY~1xU[[5g)R@iWYV y? O@bWV9Z 6k❲/Jz?,'@ZAnT xīK/܂R{}dM]G/Av^>+M&W*m> endobj 40 0 obj << /Type /Action /S /GoTo /D [241 0 R /XYZ 61.192 711.475 null] >> endobj 42 0 obj << /Type /Action /S /GoTo /D [241 0 R /XYZ 61.192 665.875 null] >> endobj 44 0 obj << /Type /Action /S /GoTo /D [241 0 R /XYZ 61.192 391.075 null] >> endobj 242 0 obj << /Type /Annot /Subtype /Link /Rect [ 61.192 699.716 97.239 710.034 ] /C [ 0 0 0 ] /Border [ 0 0 0 ] /A 185 0 R /H /I >> endobj 243 0 obj << /Type /Annot /Subtype /Link /Rect [ 61.192 654.116 97.239 664.434 ] /C [ 0 0 0 ] /Border [ 0 0 0 ] /A 189 0 R /H /I >> endobj 244 0 obj << /Type /Annot /Subtype /Link /Rect [ 61.192 595.316 97.239 605.634 ] /C [ 0 0 0 ] /Border [ 0 0 0 ] /A 234 0 R /H /I >> endobj 245 0 obj << /Type /Action /S /GoTo /D [230 0 R /XYZ 56.692 556.783 null] >> endobj 246 0 obj << /Type /Annot /Subtype /Link /Rect [ 61.192 523.316 97.239 533.634 ] /C [ 0 0 0 ] /Border [ 0 0 0 ] /A 245 0 R /H /I >> endobj 247 0 obj << /Type /Annot /Subtype /Link /Rect [ 61.192 451.316 97.239 461.634 ] /C [ 0 0 0 ] /Border [ 0 0 0 ] /A 231 0 R /H /I >> endobj 248 0 obj << /Type /Annot /Subtype /Link /Rect [ 61.192 379.316 97.239 389.634 ] /C [ 0 0 0 ] /Border [ 0 0 0 ] /A 172 0 R /H /I >> endobj 249 0 obj << /Type /Annot /Subtype /Link /Rect [ 61.192 320.516 97.239 330.834 ] /C [ 0 0 0 ] /Border [ 0 0 0 ] /A 174 0 R /H /I >> endobj 250 0 obj << /Type /Annot /Subtype /Link /Rect [ 61.192 288.116 97.239 298.434 ] /C [ 0 0 0 ] /Border [ 0 0 0 ] /A 176 0 R /H /I >> endobj 251 0 obj << /Type /Annot /Subtype /Link /Rect [ 61.192 242.516 97.239 252.834 ] /C [ 0 0 0 ] /Border [ 0 0 0 ] /A 178 0 R /H /I >> endobj 252 0 obj << /Type /Annot /Subtype /Link /Rect [ 61.192 183.716 97.239 194.034 ] /C [ 0 0 0 ] /Border [ 0 0 0 ] /A 184 0 R /H /I >> endobj 253 0 obj << /Type /Annot /Subtype /Link /Rect [ 61.192 124.916 97.239 135.234 ] /C [ 0 0 0 ] /Border [ 0 0 0 ] /A 187 0 R /H /I >> endobj 254 0 obj << /Length 255 0 R /Filter /FlateDecode >> stream _5zk]I:kgZdIV ]ÓZ],KSG+\tG}൓ 6o`:B+\AzV0bwmF._ pe~oY JTDƖ:u ʝ1J^@g@p7}c= fJ6U[jPQ2(s2fٸ^vi_Sj$LDž5+&T,N ; ʋG9'ά#|;djaL_ O3m~sX~W 藂EdN5d*Da#Ƒv݄JtYCAUV3VJ3ûr1K7|R"T<e&c\oc2sĤ |:chԘ+#k2Z.n!B͸k8rcԲҁ €ިB>d=ܴA mVjEk ?`ΉҔJ?!~:ޱ팷R܆4NDlrz|lox5:jd-Ԭ|+]ew;C9 9>0'E|TJgb r}3ai1#y},%nσ$y"m?<ȸ9+! F_ 3SOγT1ƣ?_V.tabop=6xǶ@R_nْ{Iy~f!RƓ%_XDfQZ%s*Y7Ư;0s5p'mO2c2梵j_W8g/uRp)S ~SHBK麈 }P(H6.YJҠIƺ@DGKO҃p@|=Ţ8 rz ,99gFNpmsvr2vN7!y)pG[/7KJ]R=㟊qHf6ES"X~-pjYj:Z8A cKj>]A ;v7_5q,ɬ_ Z/;%&x8qLHy%wpZ[J_wVJx&FCΆAǼy n)%KձEi^bhz>%k,!vg'MzLuֿ\Ǩt5h6o1(e+O?_Xl 3dtsx UO P\7w,&)CQI'z䝳3kB>aqD>|PFM6%HA>Xfl*D*ie>~0Oe7iVJEkTbç)EW]1aU3 vլQoTo1Y$A-˞d[u R@5_̭hv0VeJI/dL'FXё;FU=bqڅKoD|h(Q>g`x|TƫZ"+E,-02 4KJތ&fX!ۘ3ed(mE)$C81j-y-`nwR#%_0%ypNB5{}-1uKeu1Im#QYkUDc_MsU Zi]Y?Kᦜ&?d5`?-!:VG( _5DО?/N:sy[pN`Uw೨|8 &ѴAKjHm0I{|eba[,I\4Lm~߹0:IV:Shϐgb${Z;d}(:H ݓߢ?j {dj" XI1Oȅ`L@;@הM JG#(Tċ'7־:hvimTu=e/4(JK쾓rk-ڭKYSF}# .Ng\5dA\p -N[и3$ UK-b%쏭ոU~6V(ǎ':" ºʁ2s PZD~7 ws! jqؼ٠,yMvcGC(BŷQ6b5TEKE1t&nC$ӁU!%ϐoݛ&Έ\%WAs5(͠;Q0uVSDpYbD.$B>A̪yq6*d;jK,ok'`N` q4l[ '?V;zJDH 2&nxN0xD腴(1tLB\[60W-!.&&[abq2]|O>Uvo>eN*r8%0!hJ/('e: 5/(^fZ$Pji̋4a4ìm p[8gUOAkwqڭ[~."!ZA|?.t'>g~0"*]mzkƺ4hxG ٵ`GA1{?Bسyo^A(-'ixf9m-}@^/Gy̥{'.{"ۙ?ߓO~:o@ƨX-<, [~Lc 1I endstream endobj 255 0 obj 4590 endobj 256 0 obj [ 242 0 R 243 0 R 244 0 R 246 0 R 247 0 R 248 0 R 249 0 R 250 0 R 251 0 R 252 0 R 253 0 R ] endobj 241 0 obj << /Resources 16 0 R /Type /Page /MediaBox [0 0 595.275 841.889] /CropBox [0 0 595.275 841.889] /BleedBox [0 0 595.275 841.889] /TrimBox [0 0 595.275 841.889] /Parent 17 0 R /Annots 256 0 R /Contents 254 0 R >> endobj 257 0 obj << /Type /Annot /Subtype /Link /Rect [ 401.08 401.622 437.127 411.94 ] /C [ 0 0 0 ] /Border [ 0 0 0 ] /A 245 0 R /H /I >> endobj 258 0 obj << /URI <0378EC2F6C014E79C2CC04F470405410B760782504C557B2A17BEEAD4818B1DA2D33D11DF3C7A0E415784C201835> /S /URI >> endobj 259 0 obj << /Type /Annot /Subtype /Link /Rect [ 166.329 261.235 233.484 271.553 ] /C [ 0 0 0 ] /Border [ 0 0 0 ] /A 258 0 R /H /I >> endobj 260 0 obj << /Type /Annot /Subtype /Link /Rect [ 301.893 187.538 329.448 197.856 ] /C [ 0 0 0 ] /Border [ 0 0 0 ] /A 225 0 R /H /I >> endobj 261 0 obj << /Length 262 0 R /Filter /FlateDecode >> stream ]ԧn4;ԆvTXD5 j֕RN ,XM;#?xhYA#j%^`91Sc_ͫtjM!R[ 2nUtrh2ti]qhic5G|7(k׵4݋$6݈zӨs#DuI+ե~M)i+JBvB=8=WQ;ߟ'FٟR}I-jEdI!5ŇBu(&I f$ҤCroAi}O@ =c60"<ܣC7` ʹz}>z&[4Kˁ:6(ݾF i /ufNi~5. i;IyxLE{+JRfXJp `^ZFV̺r >[4 W9Ԏ&i[6jsMڔK|}MG`p>.b  BgݠI<ٿA@Hi 9JjwH*G2|qL: QzNYI,\8C@Z] *Pަ^f~ԇ@'֐D`# *|%ST t7r37S> iLg/`RZ 8t>S'ZC Eh6|svzwti?`k<*ް|,(<;-p֭`ɗsVz>m|z"6ϫ~Ӫ {AiqSy6As>d\&%h(@d2Lc} Z y'>\:yR,5X7fSۇR>gI#nHdjHnloX Xn@ϔ74nT*Ǐ,_H:\ owgQ$"8Le5pG:bu~=ez/ijz[ ۑ X>qRzp)/ўںEV24JTݣ3'g#k-όj!Ye=vp jn1Cms=TC$#YFh"ɻ҆䋢JWD8zQMy.񻦿0Dq_;~H7ij<r_^.@^!&t~<+R*cN+36ګ$Ku) ӖPPz A C# >1  (Z:Ojط$ ӠruK}M7Sd,\M-m6bgorr8fWA,KQxk)~c2t[l>TJӢJ~#/^xkB!UU;W|ٶ9Sv1gaJA5[8CWl1nN?Y͂|'dDl-E}GkZ$V21uxE>6b,'|ϟ󐜬8lP%$ʰvVt*'*խϲHmٝKдE.]}mKg[w_d e\ =XSmқ5-Q;Y&?#n뭀zz37.,āGbbcd~+)T)e>l[Ҍ)S{>rۺɇO,h{Jv]VϔԾ58l,Ɖ~#4EE5ew[Ѩ\'#T5z<AU3+-x2o>ͥɃBS~E0MpdiZ#> S`YmyeQ?dA+}Z##SllAb -8x9I=*a(vZL=pQ/N+!&v`J6_ F1E]ê9HҽRP8433uҜbf$>n_ ߪI Y,0vKt 5Gp6fpm~-,x\k+LXO~U9@tt[j3|h5 ^J{Lcj.aA).iy= ^f' r۠w7 O$.dwУCcLJ=7O r8uG+N0ڸvh *p*WbxC5a-JV?dG̣t `yl2Zy{+L_{Dl; D9. Z, s}&ĹcP?>TPÁ}zHJx;QMqbvCvǣ3fNSvn&|u.-iO jҔ_WmI^N?BNYBncSs{bӋ譚<\kD^4 ì\{Zrk-j^t[zAU,'캐,M3cMM(<l,8rv+*?XWWtު$Z5dˤ"9ii~[V>ƵgEaU1}§:4T>Zs8e oQ5yrr6솢Ornj+QN/;&1")Nѩ)WFy:]$6[)eM5#-\#rV0KA[,DZOA0CpwBaZh_tdHeV$'tّsiȷvb jģ-*wdh|z<܈cj M4P^WbAHV(zyz2If{A"W,"3 zD%&`z#0&>Rho쓚F$Q:t#\8ZzT`&Nh ~2[d#-NqX jOx =ʴG9n]\)t,lFv,{GV8-p#?@HW`,%ύzXŘ8~Y Do`U'tD\Nm_lb˄'@0=Lv(-gT}Lfqf~+ h` ʻ. 5N4 3M_ͺ3hd\+GnH"w1΍k!Gzr}s˪֢#p]Y0xm3Tw/ ^QOOZ1&Hx>_rKNaf”c ?*n+׶QtwmdYsbi ZwʹY=i.ҿ=W_0FKYp.2ŠZg&D#-9*cGJ1| oJfC+ Lk=†Z]܀ Ջ~Y7wg@Pg%M}5%wBT ?4RiZOw A!k2# c3rlKy\MnL&:,)_aB}vFőϧ7kn۱GiCipScN t0-'PV7V8![dsa ,d:&Y%zuX n& 5&z7wl{ю8hם " 1HqKW C endstream endobj 262 0 obj 4439 endobj 263 0 obj [ 257 0 R 259 0 R 260 0 R ] endobj 264 0 obj << /Resources 16 0 R /Type /Page /MediaBox [0 0 595.275 841.889] /CropBox [0 0 595.275 841.889] /BleedBox [0 0 595.275 841.889] /TrimBox [0 0 595.275 841.889] /Parent 17 0 R /Annots 263 0 R /Contents 261 0 R >> endobj 265 0 obj << /Length 266 0 R /Filter /FlateDecode >> stream >oIJlrhZzu e+6z2XsBjzR"I^U\t8!S|KnKm.ഠns* `z'mgntjM2S>(=]Bc:/x] B$h=feMP5쿋V|ũё J,|&I9|Pmyb)Ӷ磎0 1mJC]?wa\7x')x. ?瘐:m6y-A/$JH R@{TܞFP;טۜ,@) gc]yfٕD;vPKL r=% X'KPng?!_⑂qb#RBƨM}0-YIӹGldRiLJ :/>Y7).5m_3#qqjG­8f*6uV 18&Y. SB/iMoWMF "~zOm|VT@pP6u$ZnkfBnU4JEwvz4E:˄ت'-G>0'P]E+ pd3}'UH4"&i/IMDkO ukM JkK|t)e7ZzCd"=ivQlJtes dV+?0[xM;j]#!q{Hơ~} !IhPOYDDhr7HÂ@4&NW^6@n2Bnr .H%AiO*hJc$WNm=R@PM#$fOS\2}v׵A+LCc)̧4P m & md{vi4e$tfXt\L6T z p]:ϰ7<Y;k%Rt,5 i8:T_M6չdvX}R~/_-/ IhY1u|YYai]0' 8/siSMOxкŻ0̜KxoC=+:\sGWNz^-yDl۠6L܌ⰳQ\W0Hτ<ꎖG/beܷ!rgr\\\:eQ4MSK &"H*j9/ti4 SPLQ"G! oNY:C׆"Dew9b+sxX5eGWs>PU~ F_ݦSB,yo' V(;82unBݍ0Ï6ٵ TImJzJw/V_>9]7T|oFnAfVvwglч't Xɂ=f21ڼt’t j>"9RfȿHF{i ou`YlSUER뷯(հt4:^g1P¹4s3Aw̕=v@z#(JBb^m D"UnojmZ*ofBpTSu;R{TS1ee]q1U]ERSX3^Z˳%scS۱*IVP+0 󡆮!' yVﶣ9)0h=ޤAjcE_92ƌ Bşx9<}ówǾ+K iJpu؎ ʝ dROx*Is`@':ku r}0OsIQv=Rړ A~> endobj 184 0 obj << /Type /Action /S /GoTo /D [268 0 R /XYZ 56.692 593.633 null] >> endobj 269 0 obj << /Type /Action /S /GoTo /D [267 0 R /XYZ 56.692 429.0 null] >> endobj 270 0 obj << /Type /Annot /Subtype /Link /Rect [ 106.271 756.652 142.318 766.97 ] /C [ 0 0 0 ] /Border [ 0 0 0 ] /A 269 0 R /H /I >> endobj 271 0 obj << /Length 272 0 R /Filter /FlateDecode >> stream $xJ+5$M5Oq/٨]d w_J8bR ^;`ǧ+Mhӣ=NRM.w $=ƁOs'.7db N>8ˑvE;J[r{0Q_CPA 9u|KT|,~7DK42i?h_ ϊlٺi0>="n({:dXz67tqwhWHH4zjU:≡nO$OU؀FseǪ> S.1MʓX5 xɁj~*mByP~<Ë@D4g#9_Vד)1L/Ϡ  ͈ |!.݉i gcR!b^ `^f Kd*(N[QMq10 |x 1tJ}oЊ v;g)ہbTبg=Zks@AN9a tMP#IaO'@t#%ZŖ=KwD{$Ga5,N$ BR`o 8*ԙ*dSUfĄ) έt'Oਛ5K> dUJXaŇ[8k7!X;(F5DŽa'H/Vc0)Zh۫S5h ᇙJgR;4,a l̓~lr"wsojy0C8"* 8@oy\ױ~tt=x;@CK!oRC纮oľ"Y'No:M+u w\قCN~YC*Uci 8ÞINC dfm3t>~-74'[uT O$,kʽ|Qn7{+2c \n蔉~[ߟ9Հ-mWՁQ'O0`D/X:&.\<=av ! G8Ǫ#WqkB:L$ad]OaR\gPT@)BB+ r#z&8?pV~Vu҈L| k٘WTCBj mw_bN耨B^ܜTp̄:%qB@α4UoT"%o%{Q+#]Ž}yh/ v\"mOXSi&.{*"TSս;LJVlw&|8O9PO (U%)NR^|Şcit~%Τ5y"@eIK@F&<,sa,ZC!/*3x>ڰ@'.ۆ &iYkE <5/Cp2,c&W[C EEV3}.׈X̺e dqgDB2um~(HZ6('G$]F-oMBorٍufq Ejd h$[|R:^T]m0x=3 g"Kמw QǝREZk0Z-hxDj‹w$Ru Dakg r_/ZqiLQ!!!3͛;Pǎxu??T~ȽP ׾aZ<%s#KkK $`O,%! ]}{|s`ss['XˤB >[u岉ß[ֶRXMHuTT v@LhQ|q 1]DC&Ҁ9ž4'A}]pF+k%C-5ܷA%8 ?)jx6 UAvG'F9U^f@(8҅)N=(~;[d[.FHPu:/`fA ՑX`Tnۿ;rt߶|2iYmUrwȁ6l@wUr#r &Л`" 6EӲa7a1}R/ñy7E/L}Y־)2/Y/X8ŕOhY E'U$Sr҃͹ r![A$)L qq&ɴTHÜ2?f$MϭEs"A?'g M֌M\5 . ': Q˲An&:iywc['Wm 4')6d`WX(@ޯ^6EX68WPy1\6I^8FEa2p=m_:'Q0.q#օ7\{`Pv@G^Y[~a¯Tqǯt |DD]@ jCА.S_å&,f$g9GՁbS/w3f>"2z̿]P9[dc|O;ꌎMDK_fU'"vԓ^ İ:X[ endstream endobj 272 0 obj 3275 endobj 273 0 obj [ 270 0 R ] endobj 268 0 obj << /Resources 16 0 R /Type /Page /MediaBox [0 0 595.275 841.889] /CropBox [0 0 595.275 841.889] /BleedBox [0 0 595.275 841.889] /TrimBox [0 0 595.275 841.889] /Parent 17 0 R /Annots 273 0 R /Contents 271 0 R >> endobj 274 0 obj << /URI /S /URI >> endobj 275 0 obj << /Type /Annot /Subtype /Link /Rect [ 257.156 694.671 284.711 704.989 ] /C [ 0 0 0 ] /Border [ 0 0 0 ] /A 274 0 R /H /I >> endobj 276 0 obj << /Length 277 0 R /Filter /FlateDecode >> stream ^SH5[CLͮ%.DwQ$ 2RN󐠀$r&>ԻF=_EWOҜ ]%10 R2&cӔF+Kp}~iθBql`ewjRZty}pI#l{>x;9Xά{)Z{!*d2/_f [[ $h4(Yϴ8C݊ApmAi&$jA} mEA]DDAe ܝ4pD+'1sh %bOG/4}O\!87 vrw44:B2ǡ;2~2/MC,@$7p7\plZA4* Ĥ4eE0?oO&M,ȳ>/&z "X"FB@oѓWg̍uI3-D[ 2S|!--XR>J"w2_ M 3VA@^;H4 1&!N"4J*W$:7Rw#\BP)^롲S nʏ]j0 і׭ZJ5~Vy걄T}8E=UDYs>yOp("(kZy uewKڿlnW VH+# YT9wn8{8œ<<|aaʮE>D9 ,Lwa'qk:8woKy&j6%F3^,1m>P*g\mnXm6-? fq޷GZD)Y=Xq>VV>BoU85m!6PMh|4Ӣ0|Od1~Jū4Cq TFJ]Ɲu˜[*J'vk|iT$-_"&XFP0+hcq~{4=XMD :Kʼn֌=^ D$.o;(~I#޵y}yMٱdZx~SDL\+ڀf7o8CTRnF* L{Fumẕ D5nʫ?<0j0C+~{Jd|9nLѻS@']l(6nWi7#E9 u;0{(5S^a~21j[?wy06N|fot&pCw=+ƅxĘ(~<.勡P^<\[K3Ӻi7X3젨 (i| QpknIo/|6Or Y'9%fp% tn,Pfڲ$DI7~P*:W]e=DesuL=8z:Zַh| z꙳fQ%/1A:pu졵j.C5CT=ˆZTMuRͷ(Q&}̖}+͌iQoF'^Iς˜$qA㱯uk{ּۗJmP E*S<c>`cEf8!%B0~KԎV¢TdE6OTH5RCupEbFWrC >ʺ-(ⓣ.̶5'pk=4VF]NjY+c&? vϒT@M hapPg7=5uzqd8'*ST?Q!ST"/C8ӖA[ b*D,UzQ/WDЦ%U V%Q"m.JDE;HbGp@ ?;[V3)N':΍hF)uK$hӶmSrڎ\/nL{]ly޻օ(*=l QcP5!̠Mq,]PۛSr# "nMb\~`8PCΊZq_2?]0\5ǥ9f&W<=1lR2 N.RXh!>Q@ά.Θ㾨6X/;R6&SM @,E* kf}:{H7Ӝ|X!o…2Gds/ogRO\Sb'`^n8ݮ c)r0tw]ތwŷr} .'琠[4|Tua,PCR6hS9 ܊$森{VS~nɄ7g4:?,ߢ*9:{MN%UT}yh5Ĩ+$^ -iy3tmtOɥ_GdA(J0!`m[-Aޘ&aTh=jpT]/!wOdj6%[ۼ FQ<}͛pޣĶuG\=($ƶVeZޑp>~>P^ ˫3҉?H-av #/b}%!%AdSDDR`]-z SliwCu&.qjepvq"#tkV!}B8a99Pv#3]h]ʛ<; endstream endobj 277 0 obj 3454 endobj 278 0 obj [ 275 0 R ] endobj 279 0 obj << /Resources 16 0 R /Type /Page /MediaBox [0 0 595.275 841.889] /CropBox [0 0 595.275 841.889] /BleedBox [0 0 595.275 841.889] /TrimBox [0 0 595.275 841.889] /Parent 17 0 R /Annots 278 0 R /Contents 276 0 R >> endobj 280 0 obj << /Type /Action /S /GoTo /D [35 0 R /XYZ 56.692 771.023 null] >> endobj 281 0 obj << /Type /Annot /Subtype /Link /Rect [ 56.692 706.484 61.708 716.802 ] /C [ 0 0 0 ] /Border [ 0 0 0 ] /A 280 0 R /H /I >> endobj 282 0 obj << /Type /Annot /Subtype /Link /Rect [ 124.144 706.484 209.812 716.802 ] /C [ 0 0 0 ] /Border [ 0 0 0 ] /A 280 0 R /H /I >> endobj 283 0 obj << /Type /Annot /Subtype /Link /Rect [ 530.476 706.484 535.492 716.802 ] /C [ 0 0 0 ] /Border [ 0 0 0 ] /A 280 0 R /H /I >> endobj 284 0 obj << /Type /Action /S /GoTo /D [35 0 R /XYZ 56.692 734.174 null] >> endobj 285 0 obj << /Type /Annot /Subtype /Link /Rect [ 56.692 689.033 69.232 699.351 ] /C [ 0 0 0 ] /Border [ 0 0 0 ] /A 284 0 R /H /I >> endobj 286 0 obj << /Type /Annot /Subtype /Link /Rect [ 124.144 689.033 171.268 699.351 ] /C [ 0 0 0 ] /Border [ 0 0 0 ] /A 284 0 R /H /I >> endobj 287 0 obj << /Type /Annot /Subtype /Link /Rect [ 530.476 689.033 535.492 699.351 ] /C [ 0 0 0 ] /Border [ 0 0 0 ] /A 284 0 R /H /I >> endobj 288 0 obj << /Type /Action /S /GoTo /D [35 0 R /XYZ 56.692 634.965 null] >> endobj 289 0 obj << /Type /Annot /Subtype /Link /Rect [ 56.692 671.582 69.232 681.9 ] /C [ 0 0 0 ] /Border [ 0 0 0 ] /A 288 0 R /H /I >> endobj 290 0 obj << /Type /Annot /Subtype /Link /Rect [ 124.144 671.582 181.267 681.9 ] /C [ 0 0 0 ] /Border [ 0 0 0 ] /A 288 0 R /H /I >> endobj 291 0 obj << /Type /Annot /Subtype /Link /Rect [ 530.476 671.582 535.492 681.9 ] /C [ 0 0 0 ] /Border [ 0 0 0 ] /A 288 0 R /H /I >> endobj 292 0 obj << /Type /Action /S /GoTo /D [35 0 R /XYZ 56.692 316.076 null] >> endobj 293 0 obj << /Type /Annot /Subtype /Link /Rect [ 56.692 654.131 69.232 664.449 ] /C [ 0 0 0 ] /Border [ 0 0 0 ] /A 292 0 R /H /I >> endobj 294 0 obj << /Type /Annot /Subtype /Link /Rect [ 124.144 654.131 194.808 664.449 ] /C [ 0 0 0 ] /Border [ 0 0 0 ] /A 292 0 R /H /I >> endobj 295 0 obj << /Type /Annot /Subtype /Link /Rect [ 530.476 654.131 535.492 664.449 ] /C [ 0 0 0 ] /Border [ 0 0 0 ] /A 292 0 R /H /I >> endobj 296 0 obj << /Type /Action /S /GoTo /D [35 0 R /XYZ 56.692 199.86 null] >> endobj 297 0 obj << /Type /Annot /Subtype /Link /Rect [ 56.692 636.68 69.232 646.998 ] /C [ 0 0 0 ] /Border [ 0 0 0 ] /A 296 0 R /H /I >> endobj 298 0 obj << /Type /Annot /Subtype /Link /Rect [ 124.144 636.68 158.013 646.998 ] /C [ 0 0 0 ] /Border [ 0 0 0 ] /A 296 0 R /H /I >> endobj 299 0 obj << /Type /Annot /Subtype /Link /Rect [ 530.476 636.68 535.492 646.998 ] /C [ 0 0 0 ] /Border [ 0 0 0 ] /A 296 0 R /H /I >> endobj 300 0 obj << /Type /Action /S /GoTo /D [38 0 R /XYZ 56.692 771.023 null] >> endobj 301 0 obj << /Type /Annot /Subtype /Link /Rect [ 56.692 619.229 69.232 629.547 ] /C [ 0 0 0 ] /Border [ 0 0 0 ] /A 300 0 R /H /I >> endobj 302 0 obj << /Type /Annot /Subtype /Link /Rect [ 124.144 619.229 207.832 629.547 ] /C [ 0 0 0 ] /Border [ 0 0 0 ] /A 300 0 R /H /I >> endobj 303 0 obj << /Type /Annot /Subtype /Link /Rect [ 530.476 619.229 535.492 629.547 ] /C [ 0 0 0 ] /Border [ 0 0 0 ] /A 300 0 R /H /I >> endobj 304 0 obj << /Type /Action /S /GoTo /D [241 0 R /XYZ 56.692 771.023 null] >> endobj 305 0 obj << /Type /Annot /Subtype /Link /Rect [ 56.692 601.778 69.232 612.096 ] /C [ 0 0 0 ] /Border [ 0 0 0 ] /A 304 0 R /H /I >> endobj 306 0 obj << /Type /Annot /Subtype /Link /Rect [ 124.144 601.778 209.328 612.096 ] /C [ 0 0 0 ] /Border [ 0 0 0 ] /A 304 0 R /H /I >> endobj 307 0 obj << /Type /Annot /Subtype /Link /Rect [ 530.476 601.778 535.492 612.096 ] /C [ 0 0 0 ] /Border [ 0 0 0 ] /A 304 0 R /H /I >> endobj 308 0 obj << /Type /Action /S /GoTo /D [50 0 R /XYZ 56.692 771.023 null] >> endobj 309 0 obj << /Type /Annot /Subtype /Link /Rect [ 56.692 584.327 76.756 594.645 ] /C [ 0 0 0 ] /Border [ 0 0 0 ] /A 308 0 R /H /I >> endobj 310 0 obj << /Type /Annot /Subtype /Link /Rect [ 124.144 584.327 222.88 594.645 ] /C [ 0 0 0 ] /Border [ 0 0 0 ] /A 308 0 R /H /I >> endobj 311 0 obj << /Type /Annot /Subtype /Link /Rect [ 530.476 584.327 535.492 594.645 ] /C [ 0 0 0 ] /Border [ 0 0 0 ] /A 308 0 R /H /I >> endobj 312 0 obj << /Type /Action /S /GoTo /D [53 0 R /XYZ 56.692 771.023 null] >> endobj 313 0 obj << /Type /Annot /Subtype /Link /Rect [ 56.692 566.876 76.756 577.194 ] /C [ 0 0 0 ] /Border [ 0 0 0 ] /A 312 0 R /H /I >> endobj 314 0 obj << /Type /Annot /Subtype /Link /Rect [ 124.144 566.876 192.322 577.194 ] /C [ 0 0 0 ] /Border [ 0 0 0 ] /A 312 0 R /H /I >> endobj 315 0 obj << /Type /Annot /Subtype /Link /Rect [ 525.46 566.876 535.492 577.194 ] /C [ 0 0 0 ] /Border [ 0 0 0 ] /A 312 0 R /H /I >> endobj 316 0 obj << /Type /Action /S /GoTo /D [196 0 R /XYZ 56.692 771.023 null] >> endobj 317 0 obj << /Type /Annot /Subtype /Link /Rect [ 56.692 549.425 69.232 559.743 ] /C [ 0 0 0 ] /Border [ 0 0 0 ] /A 316 0 R /H /I >> endobj 318 0 obj << /Type /Annot /Subtype /Link /Rect [ 124.144 549.425 250.435 559.743 ] /C [ 0 0 0 ] /Border [ 0 0 0 ] /A 316 0 R /H /I >> endobj 319 0 obj << /Type /Annot /Subtype /Link /Rect [ 525.46 549.425 535.492 559.743 ] /C [ 0 0 0 ] /Border [ 0 0 0 ] /A 316 0 R /H /I >> endobj 320 0 obj << /Type /Action /S /GoTo /D [56 0 R /XYZ 56.692 703.773 null] >> endobj 321 0 obj << /Type /Annot /Subtype /Link /Rect [ 56.692 531.974 69.232 542.292 ] /C [ 0 0 0 ] /Border [ 0 0 0 ] /A 320 0 R /H /I >> endobj 322 0 obj << /Type /Annot /Subtype /Link /Rect [ 124.144 531.974 201.309 542.292 ] /C [ 0 0 0 ] /Border [ 0 0 0 ] /A 320 0 R /H /I >> endobj 323 0 obj << /Type /Annot /Subtype /Link /Rect [ 525.46 531.974 535.492 542.292 ] /C [ 0 0 0 ] /Border [ 0 0 0 ] /A 320 0 R /H /I >> endobj 324 0 obj << /Type /Action /S /GoTo /D [56 0 R /XYZ 56.692 621.571 null] >> endobj 325 0 obj << /Type /Annot /Subtype /Link /Rect [ 56.692 514.523 76.756 524.841 ] /C [ 0 0 0 ] /Border [ 0 0 0 ] /A 324 0 R /H /I >> endobj 326 0 obj << /Type /Annot /Subtype /Link /Rect [ 124.144 514.523 209.339 524.841 ] /C [ 0 0 0 ] /Border [ 0 0 0 ] /A 324 0 R /H /I >> endobj 327 0 obj << /Type /Annot /Subtype /Link /Rect [ 525.46 514.523 535.492 524.841 ] /C [ 0 0 0 ] /Border [ 0 0 0 ] /A 324 0 R /H /I >> endobj 328 0 obj << /Type /Action /S /GoTo /D [67 0 R /XYZ 56.692 771.023 null] >> endobj 329 0 obj << /Type /Annot /Subtype /Link /Rect [ 56.692 497.072 76.756 507.39 ] /C [ 0 0 0 ] /Border [ 0 0 0 ] /A 328 0 R /H /I >> endobj 330 0 obj << /Type /Annot /Subtype /Link /Rect [ 124.144 497.072 295.524 507.39 ] /C [ 0 0 0 ] /Border [ 0 0 0 ] /A 328 0 R /H /I >> endobj 331 0 obj << /Type /Annot /Subtype /Link /Rect [ 525.46 497.072 535.492 507.39 ] /C [ 0 0 0 ] /Border [ 0 0 0 ] /A 328 0 R /H /I >> endobj 332 0 obj << /Type /Action /S /GoTo /D [67 0 R /XYZ 56.692 459.332 null] >> endobj 333 0 obj << /Type /Annot /Subtype /Link /Rect [ 56.692 479.621 76.756 489.939 ] /C [ 0 0 0 ] /Border [ 0 0 0 ] /A 332 0 R /H /I >> endobj 334 0 obj << /Type /Annot /Subtype /Link /Rect [ 124.144 479.621 303.532 489.939 ] /C [ 0 0 0 ] /Border [ 0 0 0 ] /A 332 0 R /H /I >> endobj 335 0 obj << /Type /Annot /Subtype /Link /Rect [ 525.46 479.621 535.492 489.939 ] /C [ 0 0 0 ] /Border [ 0 0 0 ] /A 332 0 R /H /I >> endobj 336 0 obj << /Type /Action /S /GoTo /D [70 0 R /XYZ 56.692 771.023 null] >> endobj 337 0 obj << /Type /Annot /Subtype /Link /Rect [ 56.692 450.832 61.708 461.15 ] /C [ 0 0 0 ] /Border [ 0 0 0 ] /A 336 0 R /H /I >> endobj 338 0 obj << /Type /Annot /Subtype /Link /Rect [ 124.144 450.832 180.189 461.15 ] /C [ 0 0 0 ] /Border [ 0 0 0 ] /A 336 0 R /H /I >> endobj 339 0 obj << /Type /Annot /Subtype /Link /Rect [ 525.46 450.832 535.492 461.15 ] /C [ 0 0 0 ] /Border [ 0 0 0 ] /A 336 0 R /H /I >> endobj 340 0 obj << /Type /Action /S /GoTo /D [70 0 R /XYZ 56.692 734.174 null] >> endobj 341 0 obj << /Type /Annot /Subtype /Link /Rect [ 56.692 433.381 69.232 443.699 ] /C [ 0 0 0 ] /Border [ 0 0 0 ] /A 340 0 R /H /I >> endobj 342 0 obj << /Type /Annot /Subtype /Link /Rect [ 124.144 433.381 168.749 443.699 ] /C [ 0 0 0 ] /Border [ 0 0 0 ] /A 340 0 R /H /I >> endobj 343 0 obj << /Type /Annot /Subtype /Link /Rect [ 525.46 433.381 535.492 443.699 ] /C [ 0 0 0 ] /Border [ 0 0 0 ] /A 340 0 R /H /I >> endobj 344 0 obj << /Type /Action /S /GoTo /D [76 0 R /XYZ 56.692 664.725 null] >> endobj 345 0 obj << /Type /Annot /Subtype /Link /Rect [ 56.692 415.93 69.232 426.248 ] /C [ 0 0 0 ] /Border [ 0 0 0 ] /A 344 0 R /H /I >> endobj 346 0 obj << /Type /Annot /Subtype /Link /Rect [ 124.144 415.93 197.294 426.248 ] /C [ 0 0 0 ] /Border [ 0 0 0 ] /A 344 0 R /H /I >> endobj 347 0 obj << /Type /Annot /Subtype /Link /Rect [ 525.46 415.93 535.492 426.248 ] /C [ 0 0 0 ] /Border [ 0 0 0 ] /A 344 0 R /H /I >> endobj 348 0 obj << /Type /Action /S /GoTo /D [83 0 R /XYZ 56.692 771.023 null] >> endobj 349 0 obj << /Type /Annot /Subtype /Link /Rect [ 56.692 387.141 61.708 397.459 ] /C [ 0 0 0 ] /Border [ 0 0 0 ] /A 348 0 R /H /I >> endobj 350 0 obj << /Type /Annot /Subtype /Link /Rect [ 124.144 387.141 161.676 397.459 ] /C [ 0 0 0 ] /Border [ 0 0 0 ] /A 348 0 R /H /I >> endobj 351 0 obj << /Type /Annot /Subtype /Link /Rect [ 525.46 387.141 535.492 397.459 ] /C [ 0 0 0 ] /Border [ 0 0 0 ] /A 348 0 R /H /I >> endobj 352 0 obj << /Type /Annot /Subtype /Link /Rect [ 56.692 369.69 69.232 380.008 ] /C [ 0 0 0 ] /Border [ 0 0 0 ] /A 172 0 R /H /I >> endobj 353 0 obj << /Type /Annot /Subtype /Link /Rect [ 124.144 369.69 440.812 380.008 ] /C [ 0 0 0 ] /Border [ 0 0 0 ] /A 172 0 R /H /I >> endobj 354 0 obj << /Type /Annot /Subtype /Link /Rect [ 525.46 369.69 535.492 380.008 ] /C [ 0 0 0 ] /Border [ 0 0 0 ] /A 172 0 R /H /I >> endobj 355 0 obj << /Type /Annot /Subtype /Link /Rect [ 56.692 352.239 69.232 362.557 ] /C [ 0 0 0 ] /Border [ 0 0 0 ] /A 174 0 R /H /I >> endobj 356 0 obj << /Type /Annot /Subtype /Link /Rect [ 124.144 352.239 390.553 362.557 ] /C [ 0 0 0 ] /Border [ 0 0 0 ] /A 174 0 R /H /I >> endobj 357 0 obj << /Type /Annot /Subtype /Link /Rect [ 525.46 352.239 535.492 362.557 ] /C [ 0 0 0 ] /Border [ 0 0 0 ] /A 174 0 R /H /I >> endobj 358 0 obj << /Type /Annot /Subtype /Link /Rect [ 56.692 334.788 69.232 345.106 ] /C [ 0 0 0 ] /Border [ 0 0 0 ] /A 176 0 R /H /I >> endobj 359 0 obj << /Type /Annot /Subtype /Link /Rect [ 124.144 334.788 254.934 345.106 ] /C [ 0 0 0 ] /Border [ 0 0 0 ] /A 176 0 R /H /I >> endobj 360 0 obj << /Type /Annot /Subtype /Link /Rect [ 525.46 334.788 535.492 345.106 ] /C [ 0 0 0 ] /Border [ 0 0 0 ] /A 176 0 R /H /I >> endobj 361 0 obj << /Type /Annot /Subtype /Link /Rect [ 56.692 317.337 69.232 327.655 ] /C [ 0 0 0 ] /Border [ 0 0 0 ] /A 178 0 R /H /I >> endobj 362 0 obj << /Type /Annot /Subtype /Link /Rect [ 124.144 317.337 320.395 327.655 ] /C [ 0 0 0 ] /Border [ 0 0 0 ] /A 178 0 R /H /I >> endobj 363 0 obj << /Type /Annot /Subtype /Link /Rect [ 525.46 317.337 535.492 327.655 ] /C [ 0 0 0 ] /Border [ 0 0 0 ] /A 178 0 R /H /I >> endobj 364 0 obj << /Type /Annot /Subtype /Link /Rect [ 56.692 299.886 69.232 310.204 ] /C [ 0 0 0 ] /Border [ 0 0 0 ] /A 181 0 R /H /I >> endobj 365 0 obj << /Type /Annot /Subtype /Link /Rect [ 124.144 299.886 361.623 310.204 ] /C [ 0 0 0 ] /Border [ 0 0 0 ] /A 181 0 R /H /I >> endobj 366 0 obj << /Type /Annot /Subtype /Link /Rect [ 525.46 299.886 535.492 310.204 ] /C [ 0 0 0 ] /Border [ 0 0 0 ] /A 181 0 R /H /I >> endobj 367 0 obj << /Type /Annot /Subtype /Link /Rect [ 56.692 282.435 69.232 292.753 ] /C [ 0 0 0 ] /Border [ 0 0 0 ] /A 184 0 R /H /I >> endobj 368 0 obj << /Type /Annot /Subtype /Link /Rect [ 124.144 282.435 394.667 292.753 ] /C [ 0 0 0 ] /Border [ 0 0 0 ] /A 184 0 R /H /I >> endobj 369 0 obj << /Type /Annot /Subtype /Link /Rect [ 525.46 282.435 535.492 292.753 ] /C [ 0 0 0 ] /Border [ 0 0 0 ] /A 184 0 R /H /I >> endobj 370 0 obj << /Type /Annot /Subtype /Link /Rect [ 56.692 264.984 69.232 275.302 ] /C [ 0 0 0 ] /Border [ 0 0 0 ] /A 185 0 R /H /I >> endobj 371 0 obj << /Type /Annot /Subtype /Link /Rect [ 124.144 264.984 344.1 275.302 ] /C [ 0 0 0 ] /Border [ 0 0 0 ] /A 185 0 R /H /I >> endobj 372 0 obj << /Type /Annot /Subtype /Link /Rect [ 525.46 264.984 535.492 275.302 ] /C [ 0 0 0 ] /Border [ 0 0 0 ] /A 185 0 R /H /I >> endobj 373 0 obj << /Type /Annot /Subtype /Link /Rect [ 56.692 247.533 69.232 257.851 ] /C [ 0 0 0 ] /Border [ 0 0 0 ] /A 187 0 R /H /I >> endobj 374 0 obj << /Type /Annot /Subtype /Link /Rect [ 124.144 247.533 385.658 257.851 ] /C [ 0 0 0 ] /Border [ 0 0 0 ] /A 187 0 R /H /I >> endobj 375 0 obj << /Type /Annot /Subtype /Link /Rect [ 525.46 247.533 535.492 257.851 ] /C [ 0 0 0 ] /Border [ 0 0 0 ] /A 187 0 R /H /I >> endobj 376 0 obj << /Type /Annot /Subtype /Link /Rect [ 56.692 230.082 69.232 240.4 ] /C [ 0 0 0 ] /Border [ 0 0 0 ] /A 189 0 R /H /I >> endobj 377 0 obj << /Type /Annot /Subtype /Link /Rect [ 124.144 230.082 360.611 240.4 ] /C [ 0 0 0 ] /Border [ 0 0 0 ] /A 189 0 R /H /I >> endobj 378 0 obj << /Type /Annot /Subtype /Link /Rect [ 525.46 230.082 535.492 240.4 ] /C [ 0 0 0 ] /Border [ 0 0 0 ] /A 189 0 R /H /I >> endobj 379 0 obj << /Type /Annot /Subtype /Link /Rect [ 56.692 212.631 74.248 222.949 ] /C [ 0 0 0 ] /Border [ 0 0 0 ] /A 162 0 R /H /I >> endobj 380 0 obj << /Type /Annot /Subtype /Link /Rect [ 124.144 212.631 386.186 222.949 ] /C [ 0 0 0 ] /Border [ 0 0 0 ] /A 162 0 R /H /I >> endobj 381 0 obj << /Type /Annot /Subtype /Link /Rect [ 525.46 212.631 535.492 222.949 ] /C [ 0 0 0 ] /Border [ 0 0 0 ] /A 162 0 R /H /I >> endobj 382 0 obj << /Type /Action /S /GoTo /D [204 0 R /XYZ 56.692 447.425 null] >> endobj 383 0 obj << /Type /Annot /Subtype /Link /Rect [ 56.692 195.18 73.588 205.498 ] /C [ 0 0 0 ] /Border [ 0 0 0 ] /A 382 0 R /H /I >> endobj 384 0 obj << /Type /Annot /Subtype /Link /Rect [ 124.144 195.18 341.075 205.498 ] /C [ 0 0 0 ] /Border [ 0 0 0 ] /A 382 0 R /H /I >> endobj 385 0 obj << /Type /Annot /Subtype /Link /Rect [ 525.46 195.18 535.492 205.498 ] /C [ 0 0 0 ] /Border [ 0 0 0 ] /A 382 0 R /H /I >> endobj 386 0 obj << /Type /Action /S /GoTo /D [213 0 R /XYZ 56.692 243.339 null] >> endobj 387 0 obj << /Type /Annot /Subtype /Link /Rect [ 56.692 177.729 74.248 188.047 ] /C [ 0 0 0 ] /Border [ 0 0 0 ] /A 386 0 R /H /I >> endobj 388 0 obj << /Type /Annot /Subtype /Link /Rect [ 124.144 177.729 345.09 188.047 ] /C [ 0 0 0 ] /Border [ 0 0 0 ] /A 386 0 R /H /I >> endobj 389 0 obj << /Type /Annot /Subtype /Link /Rect [ 525.46 177.729 535.492 188.047 ] /C [ 0 0 0 ] /Border [ 0 0 0 ] /A 386 0 R /H /I >> endobj 390 0 obj << /Type /Annot /Subtype /Link /Rect [ 56.692 160.278 74.248 170.596 ] /C [ 0 0 0 ] /Border [ 0 0 0 ] /A 234 0 R /H /I >> endobj 391 0 obj << /Type /Annot /Subtype /Link /Rect [ 124.144 160.278 317.898 170.596 ] /C [ 0 0 0 ] /Border [ 0 0 0 ] /A 234 0 R /H /I >> endobj 392 0 obj << /Type /Annot /Subtype /Link /Rect [ 525.46 160.278 535.492 170.596 ] /C [ 0 0 0 ] /Border [ 0 0 0 ] /A 234 0 R /H /I >> endobj 393 0 obj << /Type /Annot /Subtype /Link /Rect [ 56.692 142.827 74.248 153.145 ] /C [ 0 0 0 ] /Border [ 0 0 0 ] /A 245 0 R /H /I >> endobj 394 0 obj << /Type /Annot /Subtype /Link /Rect [ 124.144 142.827 404.094 153.145 ] /C [ 0 0 0 ] /Border [ 0 0 0 ] /A 245 0 R /H /I >> endobj 395 0 obj << /Type /Annot /Subtype /Link /Rect [ 525.46 142.827 535.492 153.145 ] /C [ 0 0 0 ] /Border [ 0 0 0 ] /A 245 0 R /H /I >> endobj 396 0 obj << /Type /Annot /Subtype /Link /Rect [ 56.692 125.376 74.248 135.694 ] /C [ 0 0 0 ] /Border [ 0 0 0 ] /A 231 0 R /H /I >> endobj 397 0 obj << /Type /Annot /Subtype /Link /Rect [ 124.144 125.376 488.211 135.694 ] /C [ 0 0 0 ] /Border [ 0 0 0 ] /A 231 0 R /H /I >> endobj 398 0 obj << /Type /Annot /Subtype /Link /Rect [ 525.46 125.376 535.492 135.694 ] /C [ 0 0 0 ] /Border [ 0 0 0 ] /A 231 0 R /H /I >> endobj 399 0 obj << /Type /Annot /Subtype /Link /Rect [ 56.692 107.925 74.248 118.243 ] /C [ 0 0 0 ] /Border [ 0 0 0 ] /A 269 0 R /H /I >> endobj 400 0 obj << /Type /Annot /Subtype /Link /Rect [ 124.144 107.925 344.1 118.243 ] /C [ 0 0 0 ] /Border [ 0 0 0 ] /A 269 0 R /H /I >> endobj 401 0 obj << /Type /Annot /Subtype /Link /Rect [ 525.46 107.925 535.492 118.243 ] /C [ 0 0 0 ] /Border [ 0 0 0 ] /A 269 0 R /H /I >> endobj 402 0 obj << /Type /Action /S /GoTo /D [279 0 R /XYZ 56.692 440.01 null] >> endobj 403 0 obj << /Type /Annot /Subtype /Link /Rect [ 56.692 90.474 74.248 100.792 ] /C [ 0 0 0 ] /Border [ 0 0 0 ] /A 402 0 R /H /I >> endobj 404 0 obj << /Type /Annot /Subtype /Link /Rect [ 124.144 90.474 406.712 100.792 ] /C [ 0 0 0 ] /Border [ 0 0 0 ] /A 402 0 R /H /I >> endobj 405 0 obj << /Type /Annot /Subtype /Link /Rect [ 525.46 90.474 535.492 100.792 ] /C [ 0 0 0 ] /Border [ 0 0 0 ] /A 402 0 R /H /I >> endobj 406 0 obj << /Length 407 0 R /Filter /FlateDecode >> stream )XTEA|.{=4g}*q|X YP}?Y$5$)(:@*q\F)G!l C#>';ۯFoXUjڹ$7TX$iV2,*?{i ͷ`?PFvO7,D<z&Lr/= Z嚤~*g3`f; jI@q?YF}Bjץd´Iu] D3u*˽&zl9b@nd3! ol$Q?wEc`:0)cټ+k2?Eb֓pw[Aj&Du_h^~' @PuMexJ7zٟ5zovip BO ܕ0t!q uF$PSd5|:T-G p&nlNYM>:YY)q+Y;! V}Hvp+wäͥCD[mwK|%Ƈ35Hô?]Mv\,K}Mg={9Bo'3C/k[[>%WM3\ Gť-ȀKJt躠U&r rHZ(VV(s֪Y$t&&)ǝ e+b{e=FȌɑYfU1ouTbt]YI$0X32pIvZ3x%k /? -)-ՕI_\*XCT~k5X7 (|[9m_Vk0e|Ύ.r0F{7ab7r{-jC4[k|3vďD,Uֳ/__}OFbSgpC3|`m(džv,3:jlWޥ]̜6u.B0Ά1x]9slWfeDL;h'<%&3gn;s])(Ork{E (AH)GTe<&VH2g]7#xM cx4Smy vJ+8F^)و|/'UGH{PtA-_Qlk'\>tQ9a̩1&"D\`o=ɤH-Y;gʞp[5H>܄fT`+8(_n 6r7GJ!! ^eGQޡGV]D~G(BԌ. d8Dһ J-ŤmU {BX\\c[nL,r]S2,R?,"2수 b:8] bt-8kGaJoބ22(QX;Gbmh] 'TuEjH~i6eXBʴ>PǪnw?cB )2Xmz kUI ䷢m㼸xU֎[ C0`(4CmxnCF.*ָt|)Ep0q!B\9̴*i- G-xjp'nW ]Wfn Jh:|wt6SB Aj<#ugմz̅,۽J(*Mط8y[[~S(1*/Z9}k.*l7F|,+zTd`;4atR.[/3:X6R@3&'U4 M!Rz_aԸJ1l6iQ [dylfR?ܸ BV(OAM~)Q˫rfgcBx:aaRG1qku;:R 5]K0L gD}?_HoZppKj=aՔ]eCC[T>A`5 F q\ =.|š\̢B;[l[lx޼?{X[3#FTQH*&n QQCg{~EV6+?|ʢ"VE. +wDGuj㣁/Rǚ Ӫr!=LĄfP|mNdqs R:i>fEC80ݵIiAP9U>E`։5@V DwҩNqy$O*نXGEW3(iP :ȼ,n%c"~;Kௐ(tz {U:()LԹ`-> endobj 410 0 obj << /Length 411 0 R /Filter /FlateDecode >> stream >~ܭyÄ ;'soMBiRHrI3AuVRMS0zI=\=s J$H|#U( zLiڠ9P;ێ O\6 F[K229a&-ye{8Uil= Cmj=7t$*'攇7}AȆ *6B^/ J?.rY@ zSBXL%1!@ԓt'ǑkGKJ5ŋÃAiVR^QL'Ă_7l4?ĭ[:E+-5?B^l%rv4# =洬=8VʐGhü'0XXZFC?Q4[wrMI-e-%N! FUMo78m^UƵHrS*{yQ޸<0ô5ȊKdו_:laQ+Woߏlu=iU1k/gA #jzjx?W$ U?>fNif棠WQ%]'\X9&o7;TT0Uq_h||o}CWnqj7v\R5zKv$JLiǽHNVZSRǻ a۩h+!Y."`O -M lF^k6ra;͋puqyl+pO1qVEcv` Zzbԛ#J=8h_eȰ^[IuYr]A6 {|D:-4]=S1FdQ`[x |X <IbROTf?FF^u$rP"R?;[OJGY;&]H_Kx8b} /UPrG鞞9Yhb iRus㓈FjHI9Menؤe>Ľm釗:,U=UwY0Fqv -ԣ 9~'GJy}0+zNiSa@*aR/F82t7}Â<[K6( ?Y[V ࠐS,\_CՈ%IAnJ f]ퟣ,lꀕXu @B2$Ыo 4 TvTB0;>tg>, ͥ2Q>T|6Q0 >-.csy꡶1˪|##poz ZY[G'T/9vs5\̈GJrLR qS|b^<!ʻ!;88/iq Ɂ-)m3@DE)Wų?Q}1~EY{+`)xY]˛3ahm铏t6%bPiU fz<H}x~A S!5U2]:fA*4gpVPMHb6!KN`[dtTL<銓,Nb6.Yi?> T':yĶ}++wO 0S"_|/P6ȣ?QvXe*uFᴬ /b|# Րi!tQ3ISP96{,m7'9]ί2xR'u]n&$92Tg@dC,_Yqi3ot M (e8(/, $sd@,: 7AS_Y ~u|;>|[2_ k!:G*̙Xh.@Ge.Íux,|L'CAA|2H.Ahk4աyvL 9X("$NNsMY-wk`ielYlW-b*Q~SǯeӊX@v^.'uO\ }WP۴WP4j/Fha wG}v]' h2nC rPY9/('3U 0ʈ:(w n}Â=%ޜ O0-==V7B\}EEEh$(>ߢ- )9CpL>DH_㤉W#_Ѡ[XeWxtpoo lBmvPg{<}od^M$Ga`> endobj 413 0 obj << /URI /S /URI >> endobj 414 0 obj << /Type /Annot /Subtype /Link /Rect [ 98.47 660.531 117.522 670.849 ] /C [ 0 0 0 ] /Border [ 0 0 0 ] /A 413 0 R /H /I >> endobj 415 0 obj << /URI /S /URI >> endobj 416 0 obj << /Type /Annot /Subtype /Link /Rect [ 489.357 608.801 521.917 619.119 ] /C [ 0 0 0 ] /Border [ 0 0 0 ] /A 415 0 R /H /I >> endobj 417 0 obj << /Type /Annot /Subtype /Link /Rect [ 82.203 590.376 247.566 600.694 ] /C [ 0 0 0 ] /Border [ 0 0 0 ] /A 415 0 R /H /I >> endobj 418 0 obj << /URI <106FBEA6A42398B9F1CA332E13A8AE12A83932FE9514195777AD0770293FF0626074AF475AB74D4F701D93E214BCA2E20518DF094E161682292B6F176E997140631E14DBD775B08D17AC63C363B1D9D6D2F786427B45A8AAEC8C26CB6790ED597A55BABD47727FDD1A413F8656> /S /URI >> endobj 419 0 obj << /Type /Annot /Subtype /Link /Rect [ 381.062 571.951 474.771 582.269 ] /C [ 0 0 0 ] /Border [ 0 0 0 ] /A 418 0 R /H /I >> endobj 420 0 obj << /URI <3AD298E6B4A7A869B8A9650EA724B1622B4370F6DC58656B7AB4CD98819084BA99B8065F4410F502> /S /URI >> endobj 421 0 obj << /Type /Annot /Subtype /Link /Rect [ 304.502 553.526 381.656 563.844 ] /C [ 0 0 0 ] /Border [ 0 0 0 ] /A 420 0 R /H /I >> endobj 422 0 obj << /URI /S /URI >> endobj 423 0 obj << /Type /Annot /Subtype /Link /Rect [ 407.295 436.271 434.85 446.589 ] /C [ 0 0 0 ] /Border [ 0 0 0 ] /A 422 0 R /H /I >> endobj 424 0 obj << /URI /S /URI >> endobj 425 0 obj << /Type /Annot /Subtype /Link /Rect [ 280.806 419.264 477.42 429.582 ] /C [ 0 0 0 ] /Border [ 0 0 0 ] /A 424 0 R /H /I >> endobj 426 0 obj << /Length 427 0 R /Filter /FlateDecode >> stream #i ##_!i3~WӥrX1;*(͒({(f.|-p3[ :>1UlؙrsQ+í(¸FC1'?:a;{[mP]D;}jK93$?S+W$& xd+ b Nrd=dSBximtջQ^VY8rZ⑮'>[kِo{/swQ['?Xr(Mg Z68 NKEt7>n<2H.)O}2MxozljF%GaF?wkxгK *GU%_*\\6nl)EaO,3;BtX2 Bu=[M:V,:\^x3TX ~@x]e=+\.ka1U\CSgqJMPdV̰u'^u: i\ՄH͏=iid@u0'٤c^),p=Q,&Y8#S[کM^x{މrF\ luL2ܿ ӸQ賺3AwId5Pt?cՖp8ث$]Kp@3wcz-'#t,*$7Xz[l@iUTsH֞9&N1[pK~Kx[x Z*#VFGtEPG:xH5*tӢۧa;Tsgfȱ^ QQBQi Q&d$TȲDJ{׈dSCY>2`=%W[-Y|PK$v˘/Ayu9xiA6ao|-`aVೌ4&x^zJɐ8-(>ܢeEE`H1 눨q ;na]Fqo|{l'p Ą$;_&c{0 Jz>f&&^<WeH@,XV,9Re;ӻA(n0GABl3$NCt8Әuo!eƛXvi!ciu?)~!ΥW-p\/'۱y ߜx0r~wMDfƪ8x\Չ6 (su Z2.%?.6v.842u @1=RtuF,K\JirSEZcɫ:ŏp}M f[Q-کƪq-6_(ٵq@2ZX53ι3vwOѬ)`w$:Fgr)mzUx7XF"HzGlP&ށ{Gơ6;k) *Q}k9l7aaE]:Z+%CgT`  މ4N]<8_BS 1sdldq)z M4~>F srΆa]Ǎq7y7No0>҅HrƕK`Y#usƻ~bѰE\Zc\Jej@MHVzJ 3jʦ,OwqʦA?\q >o~a`cGGG1^A+Jf ӃPN>8)Q"$h׵5l @Z.M%&w{[lʀQ0i /ZQ >c|B:)X6mഢ؜-YWEb6Puv>0ۜl'ˆc%pq.y#GL4?#KwQ U[뀥moHݮtgތ}yBIES$e`In={Hz,-R+[c-E,E`S΍9ZP&Yhڲu]~k9$Hdu;/]R]xΘYzbU;A_&Q%5~Dݏi^)d 4 iXb|+CxM1-9 srE] 4()|ϙ{=/y?Ez7̉p9NQH"1Ha3SpPM|jeX3V|!_mbnga|3O>\;ղvI߫8&ksD̜Q9:xWWNK'n j .U쥜]2Ȅʇ)-cEHv %bzFs'ⵚd\ÚbOa o[H (,Ma~̸*F5s#pL { $0\ͳIJd[:3VYӘ[Ccw' #`F}>CѺ?`iWNNZ}Wrub%5E{S~!r%4jc`8 ФnQ՞;e?n6Sl:^=ÓYy8زx3~Ɀ;̴V poMb튽~V+_ʏNB98+Zp^Ă\Q.ZgX_W_5\,9 %iy^}VgpJgw)c \qvMyĭ2d%v ^ZtUh,W(oq?_GXXL>=՜-SHErZF7dY' b8YqjkVMRk(yc YV CyEI j_&uJ&1*2f6 &R袬M//reG9CU:A)A+vm MPtKOf~k&IXm/&n-rdVmǡe:;4ndޔI?JbC*n KG~_V2_}&IKoz:i ,ZgCt Y?L4#Amn|17/겳m3-])Q_MhMF5DPJlSid[Ua+tnM"$Gw70֋f#4TLOTs]㢵39XFЈG):Ͻ{||+T/ӳD3h4!˚DK:zƋ.ʠ#ӟ.C~`5X2_߫!Ҝx诠 26Ƚ& endstream endobj 427 0 obj 3660 endobj 428 0 obj [ 414 0 R 416 0 R 417 0 R 419 0 R 421 0 R 423 0 R 425 0 R ] endobj 429 0 obj << /Resources 16 0 R /Type /Page /MediaBox [0 0 595.275 841.889] /CropBox [0 0 595.275 841.889] /BleedBox [0 0 595.275 841.889] /TrimBox [0 0 595.275 841.889] /Parent 17 0 R /Annots 428 0 R /Contents 426 0 R >> endobj 430 0 obj << /URI /S /URI >> endobj 431 0 obj << /Type /Annot /Subtype /Link /Rect [ 143.57 363.747 182.686 374.065 ] /C [ 0 0 0 ] /Border [ 0 0 0 ] /A 430 0 R /H /I >> endobj 432 0 obj << /URI <4F36E79658F3684245FF7283C5DD413CF2931D9A1E1F7C1D6F6EC5B7FD5498F455D4F78D26C5C88734D052DD5935F6A6A2D9E9B5> /S /URI >> endobj 433 0 obj << /Type /Annot /Subtype /Link /Rect [ 436.786 363.747 464.341 374.065 ] /C [ 0 0 0 ] /Border [ 0 0 0 ] /A 432 0 R /H /I >> endobj 434 0 obj << /URI <7380D53FE65729B6499E255BF475BF0BA100EB8B9C0ED098799572C8049663054949F32BFDD9E3ADBED2D826DAFC47D6B1646CC0D9C27A5603> /S /URI >> endobj 435 0 obj << /Type /Annot /Subtype /Link /Rect [ 82.203 238.32 315.304 248.638 ] /C [ 0 0 0 ] /Border [ 0 0 0 ] /A 434 0 R /H /I >> endobj 436 0 obj << /Length 437 0 R /Filter /FlateDecode >> stream 0YƯBz:ya~ʗN%cz/Ҧf$>%"gf{^y RR\UMK@ DȞS{"gP 8:ͪ"$poQφuŔ~`PqbMu~+{ ?jdƙ'=>cR6%ot5E}n{Bi# %ǿ| Qp&+Vx3RWgk%9Y9Ect_-iRfb:# !qUԗUNH;,\`yQ.u)H.vj*q]~7/Jك >>)ȹPO8R5|tF_.+N n]79&_RHZzW3JD^L\kŰks%nUwD>$RV}P91& jxP2Nx\PEgw1}KS NEy[MD >L<ң\8r7(jBzL(<4>5J`9 3h 0.K8/4\pm3ɑ0PΙfw 0NltVj]ةB=_xce'c<֦->\h @|TycgTbFݤG^D2S[&G0&AVAq$t}(jkU.;Açv~؆`{bUkU8[|҈ [eWyٛҽ'waɺ8cr20ރ (g`DҔm.Bq Ndt5ޚh,x[MRo˴14)SJm_,Le8v}^HDI?,7ڒ[R?`'w-1a.1C Hh$` -{YE- pJ B\S j:Q]>3xi #TY,1˩ENX{VY80ph=UP=K[@;Aɬબ9a0=9/;q) i1%]Kd=ȵEá:;x6wXWPSrCdӾHq<`qHOm#o8 ઐH,Є ʶ58 _upp~ǡ [C͸yVK,Ψ$ݻO{`CEy.*mV*\~!qMQr*56gYرaꆽ ,qVZ_[ŋsAC }y\KWLyR&imAM!Hp̆b_SAUŘ6Pĩ"xzΠiAg"xO8>@MդXI jNi~mQ S8T P"HGR!ȜxYœ>!t׶n V`_ A "cNh&D#uSd51=y?LS&H"3(O+[m.PkIi7뱫I88r8k]"W W'\@Hzt([pQTz oD>)m|esT5-kÓnTKRp>S8,a`2' Dqȕ))X{1mH3ع˿USL=Qg* ~!a̪g,?߲rNh |Nju5486V`c92KG~W|63Z)1{;Iaxwbzqndm8e%c{e]*:djZ~_6́vU˅MI1H} :*^gZ`οkYSO|L{/+"9Z*1.+TЭӶ][s_FVJ!0! ;+&R1DGbbtcbE@rt=? x}\u]"U- =Ot( G-Z^qqcNIS{&XhE:"r|*| /OYqP#@xӍ=FNrY%;zFKut|n2m}~ųOv `~;q+;VXtME$#MC0ωLn5[QCj1*fFv*E]kT?{wU k2tݪV2ԭCj,2ǔʊ]lS4/;^ihN0lb&1æٻ};]B[+c!DAÊ9sɬkMnLt/=['AٜAԺD:ѹ0"jP,먛u ȫζJ,48p rDt*2z[.hiL~f?&"7BK{Tr_ ;qj{{էt 0`U+ ߰:--&-.T1l|9잶[iZ[8U|H77|qTw 4:BPux*C{AZ> s(W4/iF~k2p). r7Lkl3XKK+lU$%E-a6tfhFo-GhJII*jÅ?w&> endobj 440 0 obj << /URI <7080777B3EBB5B2303B2C9D2624AE51C310544AF173A6E641B9D5DCC60125B822CC11533E4D037CCF67CBB899D129C8D3D> /S /URI >> endobj 441 0 obj << /Type /Annot /Subtype /Link /Rect [ 82.203 368.478 288.629 378.796 ] /C [ 0 0 0 ] /Border [ 0 0 0 ] /A 440 0 R /H /I >> endobj 442 0 obj << /URI <723AADD538B0F389BCE24477F640A8EA3D73F86700C5F8BFB968A01096A31E699B69780DE8A4520DA032> /S /URI >> endobj 443 0 obj << /Type /Annot /Subtype /Link /Rect [ 82.203 350.053 262.141 360.371 ] /C [ 0 0 0 ] /Border [ 0 0 0 ] /A 442 0 R /H /I >> endobj 444 0 obj << /URI /S /URI >> endobj 445 0 obj << /Type /Annot /Subtype /Link /Rect [ 376.651 331.628 488.906 341.946 ] /C [ 0 0 0 ] /Border [ 0 0 0 ] /A 444 0 R /H /I >> endobj 446 0 obj << /Length 447 0 R /Filter /FlateDecode >> stream b!#ch@;vPi멚R&eFo V]A Y!p%5@7;ܙ N-Ö?ygPx=9; LhթS߽O6m4 e?Wfr1@L;e>ɦq |vceYvGgGŇjEȜkYmfiﱳ7w/9h ۦIYD^aVD&vcge_׷xٽOtHGM-sÃϿK*EvӤ۠jk8y᢬vuqTl~;UKbhj>;@ ?=y-tk]G]ض>_+9X^ԛ+h@^ %c~:#B ۾h`.aFKb5MjxsՈ/HR Ӽ&"]IxLWuĴ7վz1ЍO*z/˕Ys],.X݅tTÈx-}[ۻfB:#gsENS^\?Pn{'`}r80$@{Rp=$W?l$ '=UҴ2^= yE_:ߎMnj0ADu we3"!<)c]?t5-Hy1{kxTɻ[LyDhsxq*V:03@O屔\dn-0_g{>9ٓ8Q?"\ʱS ʝ}7t6[kSS#2nᷮABh7Ĝ4hnk@ZUE9˟\td놝ӭ q`K]Qhg  ,(4maliqwo"~2(I<A-;$Y"Xf褃;hMo)5LbWfS!2{zŷ-o/fy5]:C橂6pT.a嗳q ŽX_ ]vlrxX S?,y|$y]$'eJ&2t`i ә9i#yLZ>WcidxXFie: !aPQAyE|T%sMI=rh\OhmkzzZ$֔MQX^B; _-M_G #|Nm=@9e *~/>|AG,PL/ ؐ_"bg4+sޜ^j;mn8L⛿M߶S E_3D~*6Gml m'T]6$KQvEX e2~3s}S8A@~m^DH&cwpzj_9M:eC|џ8U4mp푦jk}Fe>.~ߤWz 4;P큮k 7BDhaQ&.~9цo "jA: +4R4Ol]FȠ#+Nz=c](K=d?ѡ^z  CoMq'/^G+s>S{ELa?7#(W#Aydo$nmM |PypRj%9%c8љpT|&J/}> F;WWDpf]Ҝu'|"&@Df6}M;΋}jMV:HFjq}_f q{_؁&/U-J#AsrWUf<D>^! 既jW)$+5}CC~MOqtB@b|. Y:mߘ,K#9 'sDt;=ڟڠl+dOTƆ=VxJj<@wV5o5Lm> BsM8-S?;쭁$#r’qrM_U{d;j&dgMp1ъ> endobj 46 0 obj << /Type /Action /S /GoTo /D [450 0 R /XYZ 61.192 454.323 null] >> endobj 451 0 obj << /Type /Annot /Subtype /Link /Rect [ 61.192 755.764 97.239 766.082 ] /C [ 0 0 0 ] /Border [ 0 0 0 ] /A 162 0 R /H /I >> endobj 452 0 obj << /Type /Annot /Subtype /Link /Rect [ 61.192 696.964 97.239 707.282 ] /C [ 0 0 0 ] /Border [ 0 0 0 ] /A 382 0 R /H /I >> endobj 453 0 obj << /Type /Annot /Subtype /Link /Rect [ 61.192 651.364 97.239 661.682 ] /C [ 0 0 0 ] /Border [ 0 0 0 ] /A 386 0 R /H /I >> endobj 454 0 obj << /Type /Annot /Subtype /Link /Rect [ 61.192 618.964 97.239 629.282 ] /C [ 0 0 0 ] /Border [ 0 0 0 ] /A 269 0 R /H /I >> endobj 455 0 obj << /Type /Action /S /GoTo /D [412 0 R /XYZ 56.692 265.938 null] >> endobj 456 0 obj << /Type /Annot /Subtype /Link /Rect [ 61.192 546.964 97.239 557.282 ] /C [ 0 0 0 ] /Border [ 0 0 0 ] /A 455 0 R /H /I >> endobj 457 0 obj << /Type /Action /S /GoTo /D [439 0 R /XYZ 56.692 771.023 null] >> endobj 458 0 obj << /Type /Annot /Subtype /Link /Rect [ 61.192 501.364 97.239 511.682 ] /C [ 0 0 0 ] /Border [ 0 0 0 ] /A 457 0 R /H /I >> endobj 459 0 obj << /Type /Annot /Subtype /Link /Rect [ 61.192 442.564 97.239 452.882 ] /C [ 0 0 0 ] /Border [ 0 0 0 ] /A 181 0 R /H /I >> endobj 460 0 obj << /Type /Annot /Subtype /Link /Rect [ 61.192 396.964 97.239 407.282 ] /C [ 0 0 0 ] /Border [ 0 0 0 ] /A 402 0 R /H /I >> endobj 461 0 obj << /Type /Action /S /GoTo /D [449 0 R /XYZ 56.692 667.333 null] >> endobj 462 0 obj << /Type /Annot /Subtype /Link /Rect [ 61.192 351.364 97.239 361.682 ] /C [ 0 0 0 ] /Border [ 0 0 0 ] /A 461 0 R /H /I >> endobj 463 0 obj << /Length 464 0 R /Filter /FlateDecode >> stream Vkw=|,ͱ&jgHw>`$1Z mT͢ALVmJ85Ͼhm1X3A 3bj?!O"n/ԈFШ:&v׳Y#vex]29QhP]RV<<BYIsp':w {1nĬP̗f'`msΚAgdsjȽijږ!qLfYyG& SSO]NxvU#mN_phB0v!rDс?ym? ?MXDq!~{+~p~ l&yd@G"/B3NK1Kpaφ?w/I)>2JgODwͺYvMʟ)6 ϹٍQ4G~o=La?d;E8f:HgnZpcVNS*yZBټ>"ctٰfx4$ij/lv-(m-vP>mNMe*`IQ]D0'fn NI 9Ae{E֜^>?JNyM:k%sی/5gϗksE,*!qq>G\ˇ-vԔ87Ei[*Dd}P(0q7>\H OxZN>;Q̟c$)w]AښQD 0Wh\ ܯgΗ7aoFש| |aꜙg2ɩE=,R)O6rneRO NooT3v&3;6#pcP }xN@Gâ]VG34NA"-TYYaa5cUk̩[^WɌpZZyژÍ91Qka[n􇫄K+4+]OW3x `a"5miM}bB_25bb^')31r/EZ)w1 .*tf% (|j}t2,U4;kpN1b<* 㩰bz؏zVe AIqWhGL->ji7[CToo㜦BޒG]cp gZ_9+=ɟ4B9kVQ0%#>Dfπ+oY헯 QI=3'ݯǑM'OP=K;#9\;i(4Mf͋{LH(Hr'Qؚ{^Ta!%igWI(6❬%.oPZ),˓_[(0\Jz$ohϝ|{ZbjܛSs.ΚW0rc":i L@K#p K!'4I !cm O]}냱r_g[ K*S0|o_/p-CԤS`y{}kw.nebPhg%"@ӊۯX\t$6[X9p ][jk~Ǟ~Eu|WJCPQJ{&u kD=^@x̟MQ(W>:-ev~Sĝ (2Ip-#dhvLPN+x U涻XuOT 5l֎IÉgooSbUC9(p2̊$f]1Z_OP~I|~=xϭhƿc"e1#S7oE(bWXr% A87~hVPrݺ45,A]@P51M0rf?#s%=a;#hDe>=ؖK_a2$vV J`:De,LkYS !$ۗ&<ȶeZt !&`ĉJ|-Y=.Y:5tnGy&H:YWD v.f)&${7#AaHM_{)G=4ޔ /eOE`VP7|c}^m Q%z;.6:51<`O3 ٞ>A"De0W~I $9@k] #'0;כMY*T5nIL- {TwFzp+g COXA˗~R]t"͋T3AyHCT[z{sB%Ro q~./3r}>q$Ts:|d{)鵉K,i\@e-%g [bK&f`ˀ`@DpZ[R-ZE"Y3D׸x3=sz\Gp'uSckxfﻍN D^fD1wJ0JP`1ymOnmL,FYTzQ+k0q#H0S? '׋Jjyy!sP?_2S$ VoKlRWHrxIL]v* + l/$\ɱsmήB*'2ie򲥚"70íR/Wd~ԕ m9RbɲiYQt,F9i. ~ 좱S]6uKeCqsX2pެAM C᚜(囀C:t=iOYیf8 mٗZ !@[9@ endstream endobj 464 0 obj 3777 endobj 465 0 obj [ 451 0 R 452 0 R 453 0 R 454 0 R 456 0 R 458 0 R 459 0 R 460 0 R 462 0 R ] endobj 450 0 obj << /Resources 16 0 R /Type /Page /MediaBox [0 0 595.275 841.889] /CropBox [0 0 595.275 841.889] /BleedBox [0 0 595.275 841.889] /TrimBox [0 0 595.275 841.889] /Parent 17 0 R /Annots 465 0 R /Contents 463 0 R >> endobj 466 0 obj << /Type /Annot /Subtype /Link /Rect [ 61.192 726.364 97.239 736.682 ] /C [ 0 0 0 ] /Border [ 0 0 0 ] /A 382 0 R /H /I >> endobj 467 0 obj << /Type /Annot /Subtype /Link /Rect [ 61.192 680.764 97.239 691.082 ] /C [ 0 0 0 ] /Border [ 0 0 0 ] /A 386 0 R /H /I >> endobj 468 0 obj << /Type /Annot /Subtype /Link /Rect [ 61.192 635.164 97.239 645.482 ] /C [ 0 0 0 ] /Border [ 0 0 0 ] /A 234 0 R /H /I >> endobj 469 0 obj << /Type /Annot /Subtype /Link /Rect [ 61.192 497.164 97.239 507.482 ] /C [ 0 0 0 ] /Border [ 0 0 0 ] /A 245 0 R /H /I >> endobj 470 0 obj << /Type /Annot /Subtype /Link /Rect [ 250.515 457.564 286.562 467.882 ] /C [ 0 0 0 ] /Border [ 0 0 0 ] /A 234 0 R /H /I >> endobj 471 0 obj << /Type /Annot /Subtype /Link /Rect [ 61.192 438.364 97.239 448.682 ] /C [ 0 0 0 ] /Border [ 0 0 0 ] /A 231 0 R /H /I >> endobj 472 0 obj << /Type /Annot /Subtype /Link /Rect [ 61.192 313.564 97.239 323.882 ] /C [ 0 0 0 ] /Border [ 0 0 0 ] /A 269 0 R /H /I >> endobj 473 0 obj << /Type /Annot /Subtype /Link /Rect [ 61.192 267.964 97.239 278.282 ] /C [ 0 0 0 ] /Border [ 0 0 0 ] /A 402 0 R /H /I >> endobj 474 0 obj << /Type /Annot /Subtype /Link /Rect [ 61.192 235.564 97.239 245.882 ] /C [ 0 0 0 ] /Border [ 0 0 0 ] /A 455 0 R /H /I >> endobj 475 0 obj << /Type /Annot /Subtype /Link /Rect [ 61.192 176.764 97.239 187.082 ] /C [ 0 0 0 ] /Border [ 0 0 0 ] /A 457 0 R /H /I >> endobj 476 0 obj << /Type /Annot /Subtype /Link /Rect [ 61.192 144.364 97.239 154.682 ] /C [ 0 0 0 ] /Border [ 0 0 0 ] /A 461 0 R /H /I >> endobj 477 0 obj << /Length 478 0 R /Filter /FlateDecode >> stream )G-ee d?}Q.4Hp lN-(4H/* &c%`v$4á'𾐂*C70jD`ȃkJ k/ji*wX9Iy2~ہ윚W"6k_:LY7b[sx8[9Zݧ@iIR+Wm}8_ϐi7i(%˽>-Di?Vu/_|{fo$hblr ;]l`{[/v!ry=W{z~39ƒjU Q :^&d+ ,hxUjA/BQQ2%?erIb^yU,zp9ܩۦd&3siߋ"svGYT`%M Ra!z}o٦+QBu+wc7ٻ8(VVKO$er J+k7 |%s(T|}J,F,|t{/F!w鏛^VFlB:ܝ~Ac7Y=]m:Ԛ!?ȅ$]Y,6P;p_LVaP [4E DBylb [EҼ_gK UvGɹfD)3d:2`hlx?^ཾO"s嫸ex::'݀VڜHPUc4?+?ZQYV!>e 9/=kCIߥ\ʾ _Պh;J>Zmdcbo''ޅF,cB*`Ual&wצl8~ۦw"yk|NCmݢ=}A!fT/D!|&x7LgO7u+&Wi`ϟ廩"ϱ@ELj)w5ZDwYonQhnꥁ<)IbMdVCZb_ЄPq`h0?u}xA )|9G R05ǟȮ  ڠܛۍ3`SֺL3SΪ5Ǖtا1`d4af ~b%A̒1;Ü<@Zl36^u"jiHr]];6rwW(kl~4R epI%qPA0`,ᣏ^ҰفL7&KOi6OC9,s[nEhb0F93{Xk;m^w?oo d:Oʿ7?DZ:~/RS#:`Ptj>sC5H`4EUU``5 ->iLU ,u9K&_M*H0vD&c 9|gLGQ !& U/ҼC y7FW6p 搘}vvY8T̼HȤb=2 fKa,D  Ӑ4{t"ԗX9+xi@x0f2j1nCiJ@ 8QC˓y4<!F@o+-{Nc:]pRPrY y+P0(}ؘIa}LlKJe{?mł(.ʡb;X68Gg*P.ڽ~'NjO,nfW/n,`UÜy7஠4;;s[YM>ts a˅>Du~ CT=& 1jN%d :UcF (rT=]ukE%A-303 NCםcn,D|9_갞,/{ 9CÔrv3'£O\zVks`8kn訔K3[k=|P/4Dȧ0WY|029QTDP]zʾMUq7̗h!dORk4Vо N^l0M:O%!00id[΅PsiuVG }?g  ݠb!:*'7:/E?62s Eu6Xg$ypt<;Wj'kx>],0>#y1)N򘋇8ɢy7.=o^l6DvvB g^*bt${f|+ EIӾ"j,!ww/]6pUi""2Ws.-qK @7AQyt2?X3Jc5ACRКv+*Mm^%=7B]tE7ըYKJ\=I!#t\mfg0ыSn ge"ءO40Wi1n U#XݎG!4)AJZ莌ų_W+G2@bO8f)M uɓ)`?e\VfGSP 8|3Rw1=랩G3=֊;u ߵz |lZ27N]t6^=bD}f7ߎ> }iS=oBҔgh\5S ~QN`t@BA RH vxK#VEm!?^\YGz,g2G` }6AX`Pl $:LB9c򛂯Mڔ]WjuOSN-J94ywΟ}m?<@&%ohᇳSPoϭAY~AYX> endobj 481 0 obj << /Length 482 0 R /Filter /FlateDecode >> stream c>Au.qAi[SJ ZJ+=z:9 5.=N7Z ylt%+ flc͝Zy}V =/ЬnΌ cVE}b` ]d\vŮϴ*fЯ!}Ynwe}Ho0vx'4 j[J@aZcO+*_Չ?ђ֑ \| {1NPm{ n* KJ-\oLNd#腢iPF[92,}-w }v3OF$%^(_Y.Zjk֧v{Χib57.{kMnLh:Q{xtϢe>$rW$d\/Ӭ|^F,A;l#* L(H2Rc5k;[0 ڊ1KCs@}Gpy5nƄ,/Ѿ**WMxĤ{|u}ج_0Nf7[.Yy2s,}هGWtMOOs3#-%@CQoնG nYmărOv1Jnv#- p}` endstream endobj 482 0 obj 655 endobj 483 0 obj << /Resources 16 0 R /Type /Page /MediaBox [0 0 595.275 841.889] /CropBox [0 0 595.275 841.889] /BleedBox [0 0 595.275 841.889] /TrimBox [0 0 595.275 841.889] /Parent 17 0 R /Contents 481 0 R >> endobj 484 0 obj << /Length 485 0 R /Filter /FlateDecode >> stream 7oTm] R@Ʈao6/CDQ(M[=8pTG az!MWHpϸ0YgaL9k=D k O8tE}ut؈Kz%|Ugda ڏ%Ȃc i U뻀=F^Gb|BDVkhM"& ¨éhnmSD37R:ԮȳI;‰UT/2:]LjPpΦ/a{e̿ 'Ӷ4p'!M2VaG2eU"шiPcB4[] BkP{U(SrƇ* c`rw؀f4vdb|ѕ<ĥ{U;VT`-h6 v/6ŝ2wkgjÖGZUST(ze YeZ619,g? +ateR%g)'6ɮ[IliOYٴ!H'CqmTD'[Me!o]CVًM@S˰@,TY[?_ny1Ex^+2$?gdE\03]Cin'_Is@ͧ?xB~Bx5`CA8Bě8:Lte@+.=rCbJpY(eg?c _uMi)HvsAHCFOl(-y>]~"Zh(N4*td1jsF/<>*&eTI/=^!]C?Q+zy9^\̱H!Я)]zJFɘN k <9EW34mA}iC.(q@2;AC,KŎ RT-OPZ4 zi9qsAk9Q)>RId򫷊r,)L;7ohnse,1b ,Bcc^LA=u =#fib*3BGp#d)|cu J\l3PYYoijoc.-L}v-DT#c(  5JmLǂNZRAP"?rlj<6LD$*Cпk0eƜ3$y> , Y'k2{._ xޡi@,ۃQ@<ٳ0nvD2t<*Ѓ[^%G褬b{W<f\ Y~xJ}Ŝ*'&Z <3TA#qn ]p ?F }(c+XG)})zKg(_d9LwvnrO53qKET!rnC5X\9z,☜Ks {be5}h#OtGM\Kl#vD))(1DkŻaL%1 ,!%Ԣz-Gmh|L@19_㝴u.aATOdI9N\g4&pCN0=,:ƫ;v-_if>](8q4B%Js-vn$pU2Y&ŽhGMpdx 9kџcŦ%=ˁ$#'"*:!Ԩm`ZYM(߂TF2C$vCl$tS#aim9S˼Db@$ Ék䰗Օ0)P_ȝJVa;5 ٟGx^7w5kdb +"_8AR"˦b Ff$;3I_=qّ`KiU(H]@2G'PB4dи1 _nLj sGKXF;MP^Bdyk&! Z8P唏B: FWC4 k̘+n"%׷.UdǗ!\Œ-!"LL| MUs9 LȀ.TErݠ"ѿ1}HTr&o k~SHe#*GC9a0vřX/֚ 1 ^ ͰB]s'Ij! H y^1t#XMosHA9: o¡L4#!+6}C0֔2bN?ţϟ 5,7VvL)Y%ʢEwԽ'3\t0UݝT_P6a;~>/_G577BP$2cmߣ+­}ÀПטhWx#x;2N& #A[{ _OsV-iQ]e(tj'l&rݐKEVd endstream endobj 485 0 obj 3541 endobj 486 0 obj << /Resources 16 0 R /Type /Page /MediaBox [0 0 595.275 841.889] /CropBox [0 0 595.275 841.889] /BleedBox [0 0 595.275 841.889] /TrimBox [0 0 595.275 841.889] /Parent 17 0 R /Contents 484 0 R >> endobj 487 0 obj << /URI <77A5DF8F4510B4D156D780590FDA7DFD643301F0CA54AAC91C0404AE8135D7B74AC5197AD9F3E0329906CE182B923BB3517FD991> /S /URI >> endobj 488 0 obj << /Type /Annot /Subtype /Link /Rect [ 406.019 757.361 433.574 767.679 ] /C [ 0 0 0 ] /Border [ 0 0 0 ] /A 487 0 R /H /I >> endobj 489 0 obj << /URI /S /URI >> endobj 490 0 obj << /Type /Annot /Subtype /Link /Rect [ 74.732 675.159 133.901 685.477 ] /C [ 0 0 0 ] /Border [ 0 0 0 ] /A 489 0 R /H /I >> endobj 491 0 obj << /URI <37752AB9DC20DC2EFBAB6FC60A3FDEBB7B0F044CCE859F13903E1EC913E39B8E5E728F718212EB36E77F6E251110CA55579C2C52> /S /URI >> endobj 492 0 obj << /Type /Annot /Subtype /Link /Rect [ 387.517 499.42 415.072 509.738 ] /C [ 0 0 0 ] /Border [ 0 0 0 ] /A 491 0 R /H /I >> endobj 493 0 obj << /URI <52EA1E36FAFED107FB763C62F6AE9A87F4474BB0193CE6B82C4732A598802ECFD4D373D24A4B2B4DCF> /S /URI >> endobj 494 0 obj << /Type /Annot /Subtype /Link /Rect [ 194.533 166.284 246.376 176.602 ] /C [ 0 0 0 ] /Border [ 0 0 0 ] /A 493 0 R /H /I >> endobj 495 0 obj << /Length 496 0 R /Filter /FlateDecode >> stream )2m;IyBdTX;?l%U/v 'r$_~B!LudwI[Fj ɥ#}QyE0gc+ޑ^Դ:AZe~~J廣6J^=璇>yxڛ{7Ŝ]xsw Vn’'_F|?8^ qH*g[8RT$J_w@ RQO,UɤOϓ\D6P(ZaP]zf-9@BgV`l<甥tH8+`B'4W)ÐHMפ|[! GdT1`2K-!ͥۀR{Nm8ڣJz"6=7ȋCg3e{;}Yk)bhԶG2rX^~m]g(.n92Os_;_0 j)0 z!P@ȕS~',Ru_TJ+TlK/n09RMe,- }Dddhx \B`\I^GمMoN#;*5b.lCMC!ӔV*EW D'Pl $xߚ:9`/TT6G<}*FR?`)lB1gP$w?T2y(õ[exaML0@dc\WSӹ}/˛H[z5^a'[B^Kljs_CCF K-nsʩT R5[ȍϨ,PTo GxtwA{[HoZ֒z<'mKm(houwТtaUD@U[Nd'[lI+F $zXo)z5MFT9Pv j VND4ҳ\Z!u $̇Gc0F,p3djJn VYH2($Gx}3EߧT| 3:ybd;hF~olJ )K=%>}!>~N0:gh<<,X^XTFt͟v11M[¶/s4< nȣŭwrSa;/@0;VGjͅ^xQI~B7v1.#);фg=Ȧp(. Zz*I&!-uaY!?nm<|1:bȥُrh/> )t@$/l!Ɏ1\l̆!e1i%'|QV}| _ UEU~JҵVѳXgݓvX^O Fja] &fV[=<;ao6 d5-Sv(UiɹD "ׅ՘DǮNGطAfcm5p%qX߳O20gPRӼN"󝔰 /UO2WX>gR3("K`<\ f$ ix-l6o^8YUU`ƫ?ժ![С&K?///o5!0Es`LT%  jddM*1sPױE߬c᪎H"A~u]秡_9BbLŏω&SR"^ϳe |/IPB} OK2yf*) _6p௻E_?p-f"iq@ߪXM'Wk}5nk2[ppF W+ χ*RC`C-aX6sX9K "amAu @!"wZ=F Bq+խiH5(%zo_l@co\t7%^vYB2MٯU DzՍ y*:!G 6G2{H-Z#$f ?ό*}Q=(yX$1؅KU,ϞMm{Xb%wRKAIN.`]+~' @CY#4Vax1$#X>bF A֍]J܅cfG !I#rQ-0_m%!Ѱg wΫCuĺ +{2-W*}m3{!NU*\udd%~hz\"a}&U]n3ƛ~Lɗ1Ze1 I[ϛ]\|!aW{}yj 9H=ͯOS.r9>o@~567JM&pPM/٬^Qc6G!Oլ Lex<^͝W{KP1͍[wWmjcTmRɝ#p'j 95؎cg[[K:pV=8{UYox5+ltS&mPK:-09?ZmYgqѤ/EEK?μ lXREP r+~Sĭks1HQ2϶LIyh,H4U [{\:nH./P%OZ@ 2Thxԑ`5[A33'uhd'}8&Éd'fKn\|r+)gV$/jgߦɋ|>IcFحߟ; eRiX/9mJ %qP|rOMNQۺՋnzAu{A_SY~(ҁbvK_<@sEvܨO&xOas=s`JFs/Ep#N@LWevM" !s`۬#4-FK.:?u$،&x!hVJ&PdlTס/ވ<ء;:Rbh k)FU^R>ޏo# n]OܵDg[U?Y S? jN -$}MQ޸[Jq!&ް?;KqT|~F?:}D4C./@L&a@Ci endstream endobj 496 0 obj 4023 endobj 497 0 obj [ 488 0 R 490 0 R 492 0 R 494 0 R ] endobj 498 0 obj << /Resources 16 0 R /Type /Page /MediaBox [0 0 595.275 841.889] /CropBox [0 0 595.275 841.889] /BleedBox [0 0 595.275 841.889] /TrimBox [0 0 595.275 841.889] /Parent 17 0 R /Annots 497 0 R /Contents 495 0 R >> endobj 499 0 obj << /URI <3BBCA56E17E4A851A88E27EA7D3CF50D37A46C0D3DBBF3917AAF02B543FF26DE53356775> /S /URI >> endobj 500 0 obj << /Type /Annot /Subtype /Link /Rect [ 90.286 740.354 124.826 750.672 ] /C [ 0 0 0 ] /Border [ 0 0 0 ] /A 499 0 R /H /I >> endobj 501 0 obj << /URI <71581C7CA4FC1145C3E4C00D230E16C48B983EF6D38AA3DB> /S /URI >> endobj 502 0 obj << /Type /Annot /Subtype /Link /Rect [ 457.081 639.65 484.647 649.968 ] /C [ 0 0 0 ] /Border [ 0 0 0 ] /A 501 0 R /H /I >> endobj 503 0 obj << /URI <5EEA68118D2AA04B307EAFA80F4949ACA479B8BCD63B9EC526A25865EDEF14864F92738B76E7237493252DABE3354C397797E88EAE9ECEC22B63271A7EA5078C7188EAEBDE9341CB32F7CBAA627C2B1865EFC4B2D9258C4CC87350D0CD94BE6022F1531A48167AF1651C351DE00EFF09CEBE90C867D47BB2C340FD3633BA00C421F139> /S /URI >> endobj 504 0 obj << /Type /Annot /Subtype /Link /Rect [ 391.468 477.371 497.233 487.689 ] /C [ 0 0 0 ] /Border [ 0 0 0 ] /A 503 0 R /H /I >> endobj 505 0 obj << /URI <4274B2145136985639C5C7448B7BCEEB30A571930CA9E640E18F014B36E6E3C2EC01AF9D476E5B614CF3741DA117DE99E02A4CEB> /S /URI >> endobj 506 0 obj << /Type /Annot /Subtype /Link /Rect [ 319.185 366.113 346.74 376.431 ] /C [ 0 0 0 ] /Border [ 0 0 0 ] /A 505 0 R /H /I >> endobj 507 0 obj << /URI /S /URI >> endobj 508 0 obj << /Type /Annot /Subtype /Link /Rect [ 178.187 264.069 193.719 274.387 ] /C [ 0 0 0 ] /Border [ 0 0 0 ] /A 507 0 R /H /I >> endobj 509 0 obj << /Length 510 0 R /Filter /FlateDecode >> stream &*<%%0Sr2y[ur߃0jvpYٿӸ]aIU-n]a,He]IpfTgͤ }:64'3 0pcPH(H$mQNcW4N.Έ?Ed55j&7+oxnؼ:8µ7cډ#x;k)Z'cnض.damI#=p@g!=8m**eP+p²c}Oѩ E >N-dۚYCg,d{6u+$W:>Wj37k/<h}96 " AH΁fL&2$N-}_הR ⼟~җǘI׸?PQg5MObhIwXÔ굿H7VYAil)⍶D4+!j+zA|q* _[8A^aؑv $rsVn>I"z.ݲ끬̛pƍﴫ/RQ<ߌ&(wWPsb7"aYd G Ř4#<5_K `{0TC`6wEV< f)e'{%ȖzZ̟* i8k>5ۼ Uesa,/IODn6@K gDXkF qf{:w@/ٶ $ќQ| eV,}M( %&rzU6Q/y06G~ZtWJӮR. .f(jS f ֬nIs `I.Ťe?ܣO>&@qKbh@CS[ĝWV-v҉5AWα5<^hZuc#]t܏Ia"uͽ5H?~m~xQ\NK-+.wX܉Ƭ'#;xhQb)ٙf |#2^/!Mq9t2I?Cibps|R:"z<v0r7ZVm+ gԾX 8Jaz'fLr'aU I'tp:Y|_gM }l͘ -!"=s MbTmkZ`JLֻpB6@d:ϻP+iT|wEm]?KϢ{uvBBGJQ\M,- 6i*{aļ72.Q6h4+ʹ£C^dvSWuPam1sO[Ȓys 0~G+Ef|om9o-@ٳY'ő/vm.mpi)~a7G 6PD+\ecIʻ–BZYa9ߩIc̥]2M)8^FB>NS)1}bِ֑UiLiH]HuET:?jNJ65cX+늩"cb1XlݻۀѸwX}YuVaضy&m>_$4x)zУ@L-wM5"y+@Mya@$$|YS|:jJp0dwِP;a}YCv78~g,0eSd3"ԎI?,w/  Y@ÿ]q)Q}S9cMfl\?4x#;jO?6˱5AT.Eh Bmj-Џ MذMZ5.SU%_pgz3W͟89tz+;鷻?|'seT>o;Q=N0K\U!N ɴ;5X( &ufUoJ`1ܞURay:[# R9CG݈tQev5gbȕ=b_yŦzO_ \LOc4}sgr`}rl RϋT:erCl*goQ6W3 Fջ-32#7>A\=b*[e4~t^q2p[C?jQ\*jKܡvda!6 *ONx>?b6*a?^:]I|ɹND?WP+(dW;%yi#Vcf͛m[z -{M58ױD_[6"1߰6D*Z19w˾ʋ4Gf܉sհExnyA|ثg&Rl0x9f"L!e\`zaA}O?   y45#lqqR gi#n!u@O(Xp69 ݟCK|vUI=<֫VuՒޖ;3mG1 zp8J^ er`.rGd&,ͦ/*zK_R9͸ܢ Z@|OLR" ۛ8܌lT gGPoQvrbuCg"?뽙=562@o" s}ω6 -,v-fwX!s:q1l<5z--'>z74BM47; Fq"7\ [_;0-W2:X_f/De cc~H#I`o@d:U!Z ;ݞx ]~쵵2Yڎ=0Yq\Y Y9c>q%s@i4}74Sf޼=t򓷱`m[NB X w۬{9iXY4kZwK+hb Sq%5W_"ř9$L,o$RCH G endstream endobj 510 0 obj 3651 endobj 511 0 obj [ 500 0 R 502 0 R 504 0 R 506 0 R 508 0 R ] endobj 512 0 obj << /Resources 16 0 R /Type /Page /MediaBox [0 0 595.275 841.889] /CropBox [0 0 595.275 841.889] /BleedBox [0 0 595.275 841.889] /TrimBox [0 0 595.275 841.889] /Parent 17 0 R /Annots 511 0 R /Contents 509 0 R >> endobj 513 0 obj << /Length 514 0 R /Filter /FlateDecode >> stream {z-SM,THޖP=Ga~/zl3W:'na]' .KO.<0Ω!FC(TM4^&~UOA_74(yW\>o_JH j-#Ǻ#$K3M_3WH}Xiqj)NzxOH=NAU4X5_~gX1:6͚L-T^PQ9z&' hMS27,Q ҷ1y@>VԢ^f;s=𕛸8HCDbsUD=@ˆ3뇦sroIJ% 5N)z{MmUp'ngs!|Ax)nWQXa%5yb9hIX `ŕҀ܂{1ӸvEETg{J;J;'2 `\恨yׁ첑"If~Zli>Сׄ_wL6o=]1ׯ߲+J-…6yKjF;|h/~ӱL5k;an~-+chNNʧtݭO&lh4N/.#n`\WsӤ!|f~pr&$R&&s,GlRL6 nAG.{q>#=!sf2> i7+"#X̏-\RoMf/Jy #d*B@1!~!z#[QX7/7 , ӓҖFQvDCE= fO~^o_Jt2B7V?L]?o"K^W&639OsJwBݑyjg0N td/-UҝӘJUl;AC{$'%t.`LƉrKNɰ6j4@sLgI ͉pN1cWo 3(K*p-9z3z+>υ˃e(nLfS`5r0n*4X' cr[FGP$m@J CSzK>^P"a RgHh 6z i`6~[\9ѐh>mXA( ('r{>*V(ir.*c' ulG+S&[ >fFyEİC~"Ѧ-4ob"*)Bb[IXD gB)(jWV(PY)+DV˦K鮡C&b7C[[*{~|*avw|d0vg{tUͩ{&=㧤HyLָ[)|5z+9 `U׹E~S䲪/r~tr7Vp& s&\ݖCtdCTZ<m%.L ?rmulE ȘijCA;\]ĻisMBs=zCL}B<2C97$C=Z*IuzCEΛ+*Osh;l aNM =^zͽIԀx (W0#I ԊvwP-I1#Q$?cyxM H%zBNSF3ZKBE5.U%Φi ϚظzbOS&ZWfv|bD"85 v͢./t0 12)t;!!AbέQ 1NQ]a)K6А^7>hW֌M'|u!9*yE8ґ_:3?rz<bR{hiGFz4 c2AC` endstream endobj 514 0 obj 3506 endobj 515 0 obj << /Resources 16 0 R /Type /Page /MediaBox [0 0 595.275 841.889] /CropBox [0 0 595.275 841.889] /BleedBox [0 0 595.275 841.889] /TrimBox [0 0 595.275 841.889] /Parent 17 0 R /Contents 513 0 R >> endobj 516 0 obj << /Type /Annot /Subtype /Link /Rect [ 338.358 595.789 365.913 606.107 ] /C [ 0 0 0 ] /Border [ 0 0 0 ] /A 274 0 R /H /I >> endobj 517 0 obj << /URI /S /URI >> endobj 518 0 obj << /Type /Annot /Subtype /Link /Rect [ 179.815 155.018 261.05 165.336 ] /C [ 0 0 0 ] /Border [ 0 0 0 ] /A 517 0 R /H /I >> endobj 519 0 obj << /Length 520 0 R /Filter /FlateDecode >> stream l*ϴֱt0Y+a, m3 1m&3f`w ;NM&fQp%wFy{ o|lSPcg~-S2ne(x\YdX3TT7b T΃.״Ӭn~T`X|:+Ԏ E vw c^}iUjH̀]كEil椨R>y(YI8G[WŠ)@pCJ=%}u"Pn$$:9 }/yA|ĵe51LHB a#a*>ZT;m+?xt PxPے(+Xý"ɅőQYy=Ӗo.={r4KP44Q/ɥ`! F̫xq^m+ڙ䷃ 6nK߽6l"#G b=vYP౒%xIU֌WG%/nR=GoĮЉd,L\?-C ֠Y/AL%?FK-=- rs<zpK8LBSoi,WZw>F\9Nb̽$K+fgSCY!vFLTh㍍,Gx\Xn1MIx1lAd .Zq3Ruᣵ֣ ~44p{>]JQc\WI- RY4kǁ&g^tv(O8y#>+OvGRDIyvHQn{&,;GbH#I$> PmB?7+X+UVðB'Ԉ[{QRv \L vqadVU͇JGPv\&QȾv͇.:VkGfD8Á-N&%C;kxH)8!(vյ0J_VBȚ*\/C#"kfz$ GFX.*\+:\gZY:l]>L| Ff;5BK,PS ݎy방QoL'9* sX$;xޖandp'm_w8b|1#d*H߭o[hCDj! 22bz[̺^Gpoi̴=亟X[9:߱˚ٷcH+(!)U)c'Z`bPaFd iӵ5$ V:ַ!C=9󘳷W1 +\`1 6*_аy30tt!qOzxfd/`|ti,n% \H , :arEPb'*~z9rN:xO&T,ՂZ*z;(zXeF.bw#t;M!q6 頠bDD3fzU NrDpΌ:]Bӈ|Q;uCj(L ӊiľp}ܜWYٱFtt?sVӲha&%4 &ubjEqK@tCB}ecJI {4AX,b}߲KpdED; #c592Ż-p%&GX$Z!L{[&'h!?b &ϞVN>Dʱ!roydHc= i5# QŤ܎0~5pGKmMfOvm vE%_$K:yd8L%8]Х[gWb0_~RV0>kVӦ[4E2=2U lp ,{f7-J=74m0_qpS4#d[cW/6jkRf}TЍnJ M9T@f[w؜CBV(J;z#PU*yJ`F=S;X;쮼g|&^Mrb/X\t<B&\)$qv1TUN5̄-CZ6MW<}ړ>PGxc5CC3NB2NKܨQ-,ĄM IuX/Ǐpjx cdb[ ɪF bW~j8>Mp8?R@;$x1KR6~pA59HY;űp3pa(GxP4aŊHĪL|{9z\Xd;z] ]LS'ڑծr;ݴm&M!*ND"c:FiTy{ޡ mߦB b#7IoSLN9'e}HwQ3{뺯 ؝&wL2apBaW{csp $7-G{5 Zm*Ns[|B~7-^Z>#qZf;M]k?d5^[Ǝ?), Eʕ=?gT xgԂ]AP&"_ |e&]C& endstream endobj 520 0 obj 3641 endobj 521 0 obj [ 516 0 R 518 0 R ] endobj 522 0 obj << /Resources 16 0 R /Type /Page /MediaBox [0 0 595.275 841.889] /CropBox [0 0 595.275 841.889] /BleedBox [0 0 595.275 841.889] /TrimBox [0 0 595.275 841.889] /Parent 17 0 R /Annots 521 0 R /Contents 519 0 R >> endobj 523 0 obj << /URI <037AB9B5D4B0C206FDCDE9C80122197986A92041519D21381425A4F4E713846CBB> /S /URI >> endobj 524 0 obj << /Type /Annot /Subtype /Link /Rect [ 257.145 675.828 286.218 686.146 ] /C [ 0 0 0 ] /Border [ 0 0 0 ] /A 523 0 R /H /I >> endobj 525 0 obj << /URI <3C0B6DD3C38B61871A72D6EB1EF6142580DFBF6FCCB9C5EDE462D8A1F40EA9416F421FD5446D927984408F778546E53B5903E971465553152A8280E32F4078D679FE4FF47B769C29CD0C056DE92FD2D2422CCE04513E203F00567CCCE250C7535B48F7356FC8458B> /S /URI >> endobj 526 0 obj << /Type /Annot /Subtype /Link /Rect [ 207.931 553.943 290.376 564.261 ] /C [ 0 0 0 ] /Border [ 0 0 0 ] /A 525 0 R /H /I >> endobj 527 0 obj << /URI <11FF37BC1E1C0FDAD9DFF6C530B91F35AC6E8B8F85F4BD1DFC> /S /URI >> endobj 528 0 obj << /Type /Annot /Subtype /Link /Rect [ 348.28 376.781 374.801 387.099 ] /C [ 0 0 0 ] /Border [ 0 0 0 ] /A 527 0 R /H /I >> endobj 529 0 obj << /URI <3730C6CC89C1235F52E0BE7DEBF0178AD25BE056528038E8B9FA15A2F95BDFCB41A06EF21CDB2B44022BFB70AC8ADB3884C88FB3622C> /S /URI >> endobj 530 0 obj << /Type /Annot /Subtype /Link /Rect [ 224.937 337.098 263.547 347.416 ] /C [ 0 0 0 ] /Border [ 0 0 0 ] /A 529 0 R /H /I >> endobj 531 0 obj << /URI <21E1830BB13621EB1EBCB765631DF23C2B> /S /URI >> endobj 532 0 obj << /Type /Annot /Subtype /Link /Rect [ 100.243 230.093 133.661 240.411 ] /C [ 0 0 0 ] /Border [ 0 0 0 ] /A 531 0 R /H /I >> endobj 533 0 obj << /Length 534 0 R /Filter /FlateDecode >> stream Ai,̫;XVs!9ޔ3PbAqΏkS) ЩlIg''{L>GM"l୨n>u疴(Uo!%#OՓPf|}2bOJ)YmA$IX/gAkwz_M%Ƃ|C61sV-I-a3RqԾ$Nq܂ecPдۺQ;+֣o)v =˗na J݄J0Ƕh`ceQ 1l)lj;=-zm-"9]]+a/?dmZ* L*}sgW! +Ю͞<8zڪ/RP6w!f؈`B{ttxEěEk/lƾ6Uy"S1%eU1-]"G ~Gu&]w1VFszf(4AiɷM@)ت??^ ߐ 5fUC:hLsj(E)`h~dg潽 ˢ`/ Ծ#kZd+)TGqAx۩SfQƍF|5-DP2N . - f/Nw[$L5:L=o ȥkn@bӫǐݨn{(lԐ>;`4qrc(ԎGwmo>>U{]T$ ^6+(;7:Tޅ2ºcSRCӠv(|{zLpAٺ'G\O+jҭcH7-i?ɤN-Xo}R柭WbFj7񸽴:>89;ߗ_HZJ8qJ9]~1ʿyrLQ@7q >A{v ԝI IL枟YJgA g52PoMƤY̌7,=<{n [p @Rq Wngi$e$8d-oniO.Two8e8Y贮z3|zhnT$<]kbbŤa4x9t^>@qe Qƚ9/Od;:TI`xsi!f(5U+M*z%ZHB==n\F?BfZkX˗ʃb׿hosloUzK)}QfߘFFOS6E?^ݫ>gfVm^91,3yEr> գm!0sC{ˊ\kmbF}zRyBԃu7Ju<Ί U$B` 1dwpTh&Rv$ei9Ho 59/nQӠYM%k|N=J;k: !}B~GľNw(vԭBҏ$2nrQ%%׏J|OhO޼&*ioszB)J7+6Kp'Nw6].FG܄3o4Hd7WLWlj6bY~(3PVJx,7C(Zol,z2 9T[<@B:^(t YxWF^ߋd1I乮d1xP.5擁'뱂sw:?"m[M=*@}AoL@|.oBdr٥1i6-L랈bh. #d/+c$k~o@4Dž(&`FG W/ D-vƒuVzS{;{`bF2+_gUHH[7euu_%$o2C?3pT3v@%NU& q׹5F'3} K᱕wL}bn ;5GYDOa1ydI]l~lF,d Yc~ox?(8:P2,2u`iZMKۇ,0bmM[Y+oF}\CK1M (#7T9 Nd0zoUpwd7m[X:9yLGI`pRYh7gjUM,d]Nguz};Ct/!8] k+,Sg5zʭ sZy,]_]$e'a>? e&۠"vy&Er=F|vݮWt^P9gAi9¼fF|2N2ѤSINc`h&N 8s],4/oˬu1e;v|QHJ5GRn~ xgz?^Gksg#_# 0oNDIk* _Y ٠Zuwxء3x`%Z LZGTL"%(n=}ѭܕn{y_VhHD?-x , 5 OE^!/BC=@'e7;7t0^̬{ofꏺp'Tlb[M X@}LCe j [&-A!k(Ӭ]wPяo##ٛ'XzӡOhMz+AWeo*lj1_FhfIy^ӣN5 M60Egl?Q(2k9"_Ms3yǼ}Љ@ia_p2}x6p/dA)$H?@Y nv*H+=nc{ :O n?Lîtnj> endobj 537 0 obj << /URI <59A2CA1C05957ECEB4CBE2F3E7841EF1949443DA4F7A0C565777D389C85CE62EA1C4E38FF90D3405E1DECE5754402EBFD6FED6E2616A5C00E7BFE7697E46FB081F29EDC99765AC54B351DBACE8675739ACB54777E90E7E2ED7687BA4E4EEBDE2328BD0456989347911CDF17832FBDC5DDCA5316D6B5D057F7D00824E> /S /URI >> endobj 538 0 obj << /Type /Annot /Subtype /Link /Rect [ 178.431 587.995 301.202 598.313 ] /C [ 0 0 0 ] /Border [ 0 0 0 ] /A 537 0 R /H /I >> endobj 539 0 obj << /URI <5040725AB32FA2C43665026E9149161E40B80EE9E3816D15D7616B0D72FC466386BCBD24F44132D97C47BB38E492475FB31D7DAC5BE62BEBADB09874EC4BD287A8942AA55E5882362B98AA2AF63A31FCFF27712E42A235612E14B9D1850DDBD6FD89ADD72008CB85CE928D931C78EE185EF1969C79C5E3BE3E5257> /S /URI >> endobj 540 0 obj << /Type /Annot /Subtype /Link /Rect [ 187.462 569.57 299.717 579.888 ] /C [ 0 0 0 ] /Border [ 0 0 0 ] /A 539 0 R /H /I >> endobj 541 0 obj << /URI <26CEAE8E1F65FDEE680B24EF67B16FE8B5FC067782D04B87FB56A1B690B249980A69BFCE64C142D891E895C5195EA2BC76EBEAB16A21602869D54FE5D4314D92EAD640B2A9539D3EC789F5F4A2EE912CB2048962A5F69AB43C22C306E58F325F1766CBE8C5DA594698644D9B> /S /URI >> endobj 542 0 obj << /Type /Annot /Subtype /Link /Rect [ 130.37 254.226 174.458 264.544 ] /C [ 0 0 0 ] /Border [ 0 0 0 ] /A 541 0 R /H /I >> endobj 543 0 obj << /Length 544 0 R /Filter /FlateDecode >> stream ;]H wv((2eݡg84ÜB :r_^gCߚŐSPg|ڧY촽ߛcb%-^ՓU^BqgEͯrUp3c-Cy"}"}! Da^,l}CJC,Mr *DE&]\ ͻ4<"[ZTy [I{C&0+_c6R,b7k3Y q#CKֽdd6L G%yj՚ftw$mItr*#WC]N3R*67ؖfV<<$&oNT.X_NlHJ3)vHZ2֗T^ҋaf$mТcĕ$FI+Dq/gW]sM0(xOONcP!+ց$Yv;߬Tc޳u~Th[ΕU ALgEBG0Sj=c6tMGN6U\Ypr \2EcI >hoJD"0 c*(K{aӜ ~2րBra߱"Q#Gg4 RTJ'\~9wLI4$v0{B,Cvk)Hj`>@gb gNZ 1H-?GS3flJ2jOyDȯ V=lcenmtT\BlnX J +V vȽTXO)3oU"U]i>,@,ge]T=ړxh/(m|EfhUDAV kGJ׉RU"kFHWHvTjl|FG5^?UT&$W]A~w+dvB L|xU:ߎdCFQ'rQRCj= ZKCsDRVTـdT*^ &=c!KوWÒDr $s;aq!ޕ~0[ZhLUŏ,A$8Ádú$FР2{Vi~fCoGnH`[ WZcⵦx>{3Ķt$4a0xA3UkIiBn^Tf kR۴ǰocKSb\XyooE?q6z'e?0l~׊TT2)0?sib-}#GP`\1殎Mf̎NO陓)7RMl30 i=N68}4qwcACo)Tڐ71~Pb{\Q6Ut[oYLaY^qWܜQW7VӐL?зS,J)Ӛ'^0B4rU6lML Ĝ*ͱ2_` aUf3%BDo>8VxPOR%\신6X 6?[gS17?= kr%]>㳚1@io:X.- /y|i63!6ucCm##D&cRpU>h+Wa}c*,x7WBf\&OUr9 ܀=~M߉1L=ᗧ>( s>Dv+&(tebr+esSYBٵǐ3.~LH뮌53<_FA<>%\0 aRjs&i+Ǵ_&/ (IRp+BXsTUD98\ ÁMę `u+yBŴb5c$1 ULlUq/!}A' :ɭ#Zϗ&[ع{#_>wD,.C`A/#&uW<Hvk+PGc}U{tFߧ8zZ!SR66+6Qw^X5T_]:8 ?;n r8$}Kԅ!ꒃurTWqSqi8R endstream endobj 544 0 obj 2938 endobj 545 0 obj [ 538 0 R 540 0 R 542 0 R ] endobj 546 0 obj << /Resources 16 0 R /Type /Page /MediaBox [0 0 595.275 841.889] /CropBox [0 0 595.275 841.889] /BleedBox [0 0 595.275 841.889] /TrimBox [0 0 595.275 841.889] /Parent 17 0 R /Annots 545 0 R /Contents 543 0 R >> endobj 547 0 obj << /URI /S /URI >> endobj 548 0 obj << /Type /Annot /Subtype /Link /Rect [ 165.902 597.919 210.991 608.237 ] /C [ 0 0 0 ] /Border [ 0 0 0 ] /A 547 0 R /H /I >> endobj 549 0 obj << /URI <6974A6ADAD0AC7B2177E7D52FB58D91E4A1473D84CF74FEB0843EC1F84B44E8C88EC452D74B80D7B7BC5EBAFC79FA769E7B4D7A6DF19> /S /URI >> endobj 550 0 obj << /Type /Annot /Subtype /Link /Rect [ 216.007 597.919 245.564 608.237 ] /C [ 0 0 0 ] /Border [ 0 0 0 ] /A 549 0 R /H /I >> endobj 551 0 obj << /URI <6C94B7A3A441044A8F2F526FD2A5B48ED46129744967C7D7A5FB9B2E9F3F4712DFB7DE8085F95EA19C24FE39A912372D149C670B868D44C58561CD5C7A399A4A44> /S /URI >> endobj 552 0 obj << /Type /Annot /Subtype /Link /Rect [ 108.81 381.629 129.842 391.947 ] /C [ 0 0 0 ] /Border [ 0 0 0 ] /A 551 0 R /H /I >> endobj 553 0 obj << /URI <398AABF7AEBAACB7C8BA157B670873561B6574FEA90BFFC994906BF685B9B65576CD18227CDDC4D91FAAAF3E82F72292A2FA7183F0DFE95F43DE5DB1F070ED3D4850> /S /URI >> endobj 554 0 obj << /Type /Annot /Subtype /Link /Rect [ 153.448 364.622 167.946 374.94 ] /C [ 0 0 0 ] /Border [ 0 0 0 ] /A 553 0 R /H /I >> endobj 555 0 obj << /URI /S /URI >> endobj 556 0 obj << /Type /Annot /Subtype /Link /Rect [ 431.583 242.737 505.294 253.055 ] /C [ 0 0 0 ] /Border [ 0 0 0 ] /A 555 0 R /H /I >> endobj 557 0 obj << /Type /Annot /Subtype /Link /Rect [ 56.692 225.73 170.916 236.048 ] /C [ 0 0 0 ] /Border [ 0 0 0 ] /A 555 0 R /H /I >> endobj 558 0 obj << /URI <001A080B308F691CC126E7CBA075EF251883DC30CC6FE6E9081C4A3A1AA6EAC352D90F119F5E63688F71A35760> /S /URI >> endobj 559 0 obj << /Type /Annot /Subtype /Link /Rect [ 190.98 225.73 365.913 236.048 ] /C [ 0 0 0 ] /Border [ 0 0 0 ] /A 558 0 R /H /I >> endobj 560 0 obj << /URI /S /URI >> endobj 561 0 obj << /Type /Annot /Subtype /Link /Rect [ 56.692 208.723 119.854 219.041 ] /C [ 0 0 0 ] /Border [ 0 0 0 ] /A 560 0 R /H /I >> endobj 562 0 obj << /URI <3FE5E02783C9EE917828F85D88F991998711FF2840EA57904388E8AAC6766D5B01451E7A9362BE89A8FA47E7031E79ECDD0DCCFF3D86> /S /URI >> endobj 563 0 obj << /Type /Annot /Subtype /Link /Rect [ 428.305 186.047 502.016 196.365 ] /C [ 0 0 0 ] /Border [ 0 0 0 ] /A 562 0 R /H /I >> endobj 564 0 obj << /Type /Annot /Subtype /Link /Rect [ 56.692 169.04 202.541 179.358 ] /C [ 0 0 0 ] /Border [ 0 0 0 ] /A 562 0 R /H /I >> endobj 565 0 obj << /URI <0C707B2C35EADBB2AB8A58CCF5873B7370ED5EA784A7AC1264DAB2A14AFC824C5EB5C30EC8C5> /S /URI >> endobj 566 0 obj << /Type /Annot /Subtype /Link /Rect [ 110.295 129.357 147.893 139.675 ] /C [ 0 0 0 ] /Border [ 0 0 0 ] /A 565 0 R /H /I >> endobj 567 0 obj << /Length 568 0 R /Filter /FlateDecode >> stream R<>9UXGxfĭ ޅ<^JY!!>7+|+VLٺ= ;J>{D[ f)"4;mJ ;+1 %TE"w+5fW46,HT3^g_0+4LK#R.ԝfA5&e0C'aՕwGSj)YqՇU{誩Lx3&VZgЏi#t[,{zRbP>[Q.NNS1m 7O;f1czOҔ֛c' 8 9I7k5lrYxY." |P֫ _1 ʝ`@fJˊ<$gBH`̩4Ḫޡ~Q?0pZ~a? \JrrPy\5|:(h`9_>0!F?9yk\wZ-,PjYw `y=Q$/n: 25(WLbx̞7KNA@P mGR2<3HߔP /.Q/JCtIfRLo\|)6r. 9y) G Хw?,Xp #T>+( HO lkDHV =,2 8%5#G`N.Zy3Lս>7_D/7pO;&P0=Ҟ5@c`yd`1pH[KvV:5Q/.~[yU IyF0 M#\aUm$];T]F>mRa[k,[bEP/UV]W귌 ggSTz%my$k)wPwڂgjPosݛq9&H߭$H9a*Q$1K:v–.fhD U+Ն+‚qZK $O]0bjBW$Zhݣh}DˡGAa,EP*>Ƥj5g*KYCN!.րB ;yJ{8ှtptw7mН6Yy:[3 ,);צŰIǴ0Zk}VLwc :^guzǐ^~+}'fCvi"1  ƹdE1n g'iI;;fIrHQ<rAScd>9i9O4Z,.̢Svd#L4卶z=+3O F9ۘKUf=)n4? =ʮKh@؞Zqc2vkLَZbdi*zZ|zUWn=lZ͢bByd@ ZZ-گ55 !\]츿ln8z9)aQ޵Y v@=2R( W۸ߒ*x;e" ?xEo򪪅뤈Yd}GL'?>5zO77в n+\nbbUsNJzE6bUԬW}Iw.vU;B`[G𘕍 %hKʦEcG&!cgO5.x3X̸-h vªfl24Avަ$QO/;ڵpm8T_*i,~7j(aMeHv=Wkgb8n$ B/l U* ͷN8,O܁ǠrKh|ܿ+.;od𨋳kFdJK{S7!ɭ;VjBg$fuk;kՌoCqH#0&5VlAW.MJ)Wnj[ũz5O ݌J|ua<=23!<8"e]>kȱŔ0R0&h?͠|vH8[[aUVZR rI$OZ^^M"qKǺmr)kq?dKM!=Njdr?Ć$;Zk Ÿp\˛k"ZYiwƪCdz3js5Կsx2 \/2f86XkVs\v|+->{,,ph|M͐86&Z[ڻ>rWWuWKrZ.>r1rn~'՜]JQjV2tP^*S:&{G:l#R9${ʎJ)tWO1r׊N[r/e?S#ԥ]: wԣdO?GX/z3NlHGox]n8f-ݵC*Gъ" 3hE!NJp BjQK2Dp;]'bίL9&gBTRz&|:-ȢlG 1@1UԠ\R8T @\K{SOq#?e DB̃ wutx&.=G0jںFq)հ߅ݷ)n5x\cfCVQ됙/jwt0fA#3F756w1-VYø !V/~иtlelv;3i: ua 9U)}Jc2c Ck*CQKO@}E2 4򢤮;MTt+]@^A_#?e&:c~Г %@y[Uhu&ITU8 `ז"t5S;tpb<7?ŦR%9͟I]!K wj6] He*6:?gsx [~:E b5cD>Eh)t`Ӎ*Hg#=]|+8ξP,ʛ"ry粞J"ck7XAUMTK?KfMS u(ZlooWMoZљt%d/r@Hܝru,Z|/|'/&mQhĠJZ|;jYۤxz=8ʩF endstream endobj 568 0 obj 4290 endobj 569 0 obj [ 548 0 R 550 0 R 552 0 R 554 0 R 556 0 R 557 0 R 559 0 R 561 0 R 563 0 R 564 0 R 566 0 R ] endobj 570 0 obj << /Resources 16 0 R /Type /Page /MediaBox [0 0 595.275 841.889] /CropBox [0 0 595.275 841.889] /BleedBox [0 0 595.275 841.889] /TrimBox [0 0 595.275 841.889] /Parent 17 0 R /Annots 569 0 R /Contents 567 0 R >> endobj 571 0 obj << /URI /S /URI >> endobj 572 0 obj << /Type /Annot /Subtype /Link /Rect [ 232.131 131.604 270.697 141.922 ] /C [ 0 0 0 ] /Border [ 0 0 0 ] /A 571 0 R /H /I >> endobj 573 0 obj << /URI <8BEF56565637E4AFCD99BD3592BEEC30917E82B6FC4791369EDFC4604343A0CA14101703E5624530A4BC82BA97> /S /URI >> endobj 574 0 obj << /Type /Annot /Subtype /Link /Rect [ 321.803 131.604 360.369 141.922 ] /C [ 0 0 0 ] /Border [ 0 0 0 ] /A 573 0 R /H /I >> endobj 575 0 obj << /Length 576 0 R /Filter /FlateDecode >> stream i.EAR|,piH+rvF~|]S%H+TC ̵5X(ӣujzѺnJaDqԟ(D$is n!3{)ŦF$@?") ]SJ,ǥl4xR\]bZR\Z=WrPWx Sx*zb|-|ԣ%]y$:3BzR,A!t&t/F )px$&G? 2?O4rBK(^A\WM߃rA*Q`gi%53}/N5}κs$kwdt\"o07lŇl9RXԽWfBD6٘1E 2)ᰮpC[Ǖf1Px28n8l?ak;ԐE<.tBBCp >~7 nظx&K7nu'w-)3XnVL蓵1v@,, sz*C?GR~a6![TwC{`nQWZzh>bSêqkuadNh)biL݄]{Q ʟ[bmr<ői[]=Y.)}%(MRp`K Dr84yE6H8a.%yN ضγ*f ;40 vCc<޶X^cи! \D *lѝeSݠjLY4!|U4!.MO՗g^vVhnk u!SAc%DLMY9LvR-z$RvJX^pηf"$\-!D*X_NJb̹f0}$/+ApD0ȕ!_n:x7?"Sd >4 ,h-<V(Aⰼ>Q-Ne";AX29V+-2^4-iҲ$[i ,ݦO $0D4h3JugQW kɘbv΅)n@ʲˤ212G6rߴ$Ajd)r,r+ >Z:B6DžNuy6S5C_v)ĀR_\4lIq) gTfOMԢ7z1Ƌ/GuHU4XW7dr+3oeк͗bFSȦ͐q s̖ON(x@kb]V[A2f0jjkк SnI )ΪH27·;s$s)o`⢥+C?r0\y?$Y<]!`&ZTtb=#o漬Qd+]%ARTF/eC;9VEvP!vܪb){- UUmCkfҐ{E?0h_U:#ށղ?zN/rYCZsҡe }c]6\5zipd `LjZA6!%]cxbNUNG%ZghHQ h/EY6SspSQ <1exuN/Gtq;QR2cvT`3IImЀ<'tw+zq "ӣFt5ሒ(9 "?iq]0-L>[1Br١/=#'l5@ s:S; zRCw£" qSq2K=iX1<UcBwQʃdNzc室Fk{ [|<&?@ -.?1[_?%J׋/o8"{SZ?wIYJLNMG\7B6Gg?@?Ѫ2Lx^P;J,Dѹu-]C8|mWC zܱw`/1LW'4A'fKF>9NÈ l?H51EX,JA{2C$Ώ:rcT endstream endobj 576 0 obj 3420 endobj 577 0 obj [ 572 0 R 574 0 R ] endobj 578 0 obj << /Resources 16 0 R /Type /Page /MediaBox [0 0 595.275 841.889] /CropBox [0 0 595.275 841.889] /BleedBox [0 0 595.275 841.889] /TrimBox [0 0 595.275 841.889] /Parent 17 0 R /Annots 577 0 R /Contents 575 0 R >> endobj 579 0 obj << /URI <2692A5AC63A6BE8F5C8824CDFC21F4AFC8522C61F7BC087FA9E7385555FD5F6B72FB039C3E47C230271A70CDAA71F42B82FCB6779579> /S /URI >> endobj 580 0 obj << /Type /Annot /Subtype /Link /Rect [ 169.453 488.082 208.063 498.4 ] /C [ 0 0 0 ] /Border [ 0 0 0 ] /A 579 0 R /H /I >> endobj 581 0 obj << /Length 582 0 R /Filter /FlateDecode >> stream RR?hVkif/ 2jEcnƽ۫iHV $RB|}QX{U-<'&%xb`3+rQdj9¤?$ y.lBK&SR]Ⰱ5<:!qc۴?8 Sv{` uSL5;8ԵcDY3HmfY5;Y[|=dJn) Ư@'oґ|RMn0ǍBӟzd.yƊlgNFT,56""kicEo1x#x$Γ_hJo\+u4ɔ2w2jm( r+1mAPY0inOÃii0<>ȉ;*_l1_=DJqD͎w,U;R8Ǩ/Qhw$PJ%pjp3P(.+RrN}FSQwU]V'i7a/W*ƭ(Z.3T8 oaEA2+ rrԿd= W= m N "7ՐKCU$fW \HeM)El 7"BM8u ǰ|8V&[: (CKZB!UG]C5_Xxz@.V*y=}n@fGgOСOzKx~QfP`A7bQN=eb<~_h?F>bx(+1QTxj#ƈvAg'ƍX)MJ*|eqE:La(bR51y%Өw?'Y[6܅FRîT lG,{O+bO8#c i2Ckܣ M[+΢LS4?{ğfLKM͛l- 'Ի`Wy 26#q<߭4f_|nq9Cs&ƣV/Mn»#֜3wIԊDB@N?&9 c "UŎfP%>e:/f8)5pP4ҡ5w 8@q`z].ej+x3Z"auxO|cql _ΈDi%K]|`||#l5~9ĵds,Xe.cͰu.zvm|؇x̀zPg#H ʋF.Fz*#j/K]2' ?WLj.9>GtxŠ#fQ,P eqW|cUk֠Eqt%EZqNT7"K8j\q- xhd }!sهz3=yyC4rTpCdd/bԜf&uF6oZ=Zx]_щXkKUG/* [;T~@*>ҝ>XeP}&19hmq͕/q^aPtD)`q?8oTFI#i@!lC ޫ\tz>G{wyH gڋյi} x/f)ڞ-v\Q ;i7˾,WR"53B^f8gl/1릟,5 4aosW$^Hڊ1 rXa^23|{pkDI@5BLf'6͋ ޲ *S6­J\b\T9~ :#9ǜԝi ΋ b-̓ݲ4 endstream endobj 582 0 obj 2322 endobj 583 0 obj [ 580 0 R ] endobj 584 0 obj << /Resources 16 0 R /Type /Page /MediaBox [0 0 595.275 841.889] /CropBox [0 0 595.275 841.889] /BleedBox [0 0 595.275 841.889] /TrimBox [0 0 595.275 841.889] /Parent 17 0 R /Annots 583 0 R /Contents 581 0 R >> endobj 585 0 obj << /URI <513F1EA19CCF3F0018C184EBA48AA175515D3C1DD46A95D7> /S /URI >> endobj 586 0 obj << /Type /Annot /Subtype /Link /Rect [ 192.456 566.734 240.086 577.052 ] /C [ 0 0 0 ] /Border [ 0 0 0 ] /A 585 0 R /H /I >> endobj 587 0 obj << /Length 588 0 R /Filter /FlateDecode >> stream A51pP{qCCͱtK|χ8$ȫowi߿2A _l9NJ=Ԧp[741["kR,Xj ō-R'_j^T3x.rLIw&?N}8#~,W&V4cl=p)O~8(~BHG&:ɔ ˕YQ@ҧ :x="6]-r%K:Ju,COd3l ~=]F"<.'HSKlg.u2NjwpXgSy #n%-jOze!/Z Vm8c$2n5C*uzspgG% y3̽c6l@D mqdpXiRĥl΋_ꍔK"MS$ss&2 b2%XdS VJ(%~?md1@ޅDlfɮ`_Drpy\oa,ngC}hYjkM2{{*4'oOⵜKN@#( ˚qc( k|0ַn<"$]fedž#&5ҟUoERyؤ酑.J0ޕvGzX7<0XLbz@YRDILs Mvr"_ĸ:~>z27.HC'uE˦@SHQٴq@s5kt_ÍtH^0N2#c~x>3R.NNV09p?%~7QZ¬ vC>2fZYmR+5NZgvXvпpL􆘣rPpP\N ^mvZvoG(F|Ƹ/kzpL4)L,d1>Jb ,l-ڛ޾GFCۆ6E*'d 'f 1wy9±У*Ksȇ=o.H#~{_!7m XH4HxMS~/j=(o#jΐ4 SGEULn8,*d 0amEtB9U;h8-Fc5L ُ~ZĻyгGvF3_^DQ ZI!VnU/"3ȴ4+# ICn4[%W>'AjnS%مTeiIӹ2B6G\i̯2m\\}-aMz2;6ͱqd4@?V\]TquGghKFzhv<_'[V)B\vfi[!(z/:R[u6?B`^EH{ j Wfd6C1X+ɭ"cAvXQ/7:.u9?oNpC4Ψx4xR.񘰈+/X 霤=n|!UB^Mтg8J4DJXH:_td~:PݓF<-2 ˘A%fᶚ+B/pk e*V|j>;/ʫkӧ~ע0N3U%6wr5ݴ1O9_d7m)2Q,J it0ٚ\K Fy meI?t}ܚv?j󩍗mHbE^`i͢Ϫ00JB̭ܻ@0H'#y+SwGxwNG1y6ad9JdvHyp =w%sˎ 6.q{Z"3Je"=ҋBϭZ)#N'3f B8z}:>et,2KVGaa)JEǔsPBGw?w<槌]7[$j֥#rS*KCˡ0|w0=mbn~KkZw" A]Q<p$2L5@U# qIAE\-Fb`FsŵCydiK7DBmt+@'5!D'Sb+=xFhs?a9xaQ*ڒ5P'3TŀOb>[L5mǭ+QPJ'[`^'bo>nb욯h,q$#)GAl7' jO) ړmZjޒܩ^ڦm͍܉޲{&o\W+Q yFH'm̸]RyIl`NZq; Nʈ0'Q{ XG-zÝh7~kÈR-cKr Pі?[dDOc os܉'\y%2[3]5Rխ%8}'꺰y4&)^:ׂ~6;_8RWA ,l?H~Pi$bp"'x>oJoJ΅4GZFG.&%Rs}c2[uy|rb2_N)k#Ve ,wAo2_Xeb&'א^#`Ɗ]L#JH6^A)ٕN^3RPrt+`SK+/04fFZؓk~>B˔^2䈒O+ަ4A˧η tQ~,I} V[Oy  ϖD P|sc?O|>m> =/= endstream endobj 588 0 obj 3738 endobj 589 0 obj [ 586 0 R ] endobj 590 0 obj << /Resources 16 0 R /Type /Page /MediaBox [0 0 595.275 841.889] /CropBox [0 0 595.275 841.889] /BleedBox [0 0 595.275 841.889] /TrimBox [0 0 595.275 841.889] /Parent 17 0 R /Annots 589 0 R /Contents 587 0 R >> endobj 591 0 obj << /Length 592 0 R /Filter /FlateDecode >> stream bnES_0bp\wS0ח-L퀇 gu*!}|`(uPm;hF9G@HCdjTz͵`@&]Š,vۧ"Zb8HU|9(]ף0<"1hDQ?` pI[9Uw\ՑOM. +Ho@-Y\HID<ŒÿvIK^;fY퇈(H?CzTeaƎڀ ao* f37o`B7,7{[ay&k d;. %i-⛐r;Y<&-: E8;o"N<5Y今ߗE]|cwofl^'Bv2œѝP} _/B}izسTpt rSΡn$XoWv) GJG$=-1'u˭h E@z endstream endobj 592 0 obj 665 endobj 593 0 obj << /Resources 16 0 R /Type /Page /MediaBox [0 0 595.275 841.889] /CropBox [0 0 595.275 841.889] /BleedBox [0 0 595.275 841.889] /TrimBox [0 0 595.275 841.889] /Parent 17 0 R /Contents 591 0 R >> endobj 594 0 obj << /Length 595 0 R /Filter /FlateDecode >> stream Iz8> oFv84_B OP\-!t^tzRJ+WPD}1g#Q} J 1<įK,uqLwƤg9;.5DTNpn Sg1 r&6KH/ibkFکa#+ Ab_@'M:2 S i_?,ak'oY2, ZPї#w<(wRMV~BWpzUZ@?$T(Ukv49;UgHY> tA21enzA_`P@Xp(Қ~ڿZ |&*CF<*6֗2+)`# >D1 G~]_JRhFR s0<,m%t"ē6 -J_o4 H!J_X2Rt*ũ&9)2K>C(J$+cEW.U)N Z 퓭 :^(ַCCf5ޤ^}G0|_NTeNt~'ߒKi)F;G,J#lxBK{䌋VKj&Id.EEV#=yIIZ1mjr8 iɠ8<`hY;\3&G%B~IkL`eƳw֘Ww{.5²o:q/~TOvbZ$)x+}f*Xpvڎ§y Gň鮋 @Δ܏$`[uk8$EF]'QH gYeSd@Oj#V,2t;q2(y_#S 54"kw*1xu82ΞWIYӷJ;X>2Fڗt ~pZ>CF:y$|ۍu 3L=:/IE' y|~;nsP$ΖJSzbzSc벆,q[Y+~8CK<8 ~rWjH½Epr :_MVt'b&S99i!G+xqE<3ESx¿y2nJ"pzG+RQP&>}bC]m6j Dw|9DۭG :,9cv/pnzFj*Ypv]z~q % w S #zD,l;r0qRm_@fZK.K> ab\T:9*siXvQ u)19aOg8L'߯EN/jL%n2 >$j^S2)@6k28 K 1 C ]/,13GD{S6ӄÂ1}%޺C+r9}>#WFR"ꭈGo'm#3Dg@nAg63hs(H5N2;]QPlET!|0iQiy+,(nG6J {fR;hcnt>hbA rhKBT>cq`+8.Sz Jn|9!eFX9LmcxfT/%,{(ftƿZ#=~Y džnCҳ3c f+2. t1(xA' e$ZH8dszk6 I^O:8DXv#6B\P (zb/`[Čy? 33^}_fZ~ hdjY ;jon[K$ɉl街l|̈́YZ9+=(׼ִ "1P\K6DTt B)foLh9Վioa֌Iulh"^9(0ʫKZH_FMD&\@~Y|[3^״kArvݩ8q1<`8DJC:DPi(F)x\[ž +ũe0Pe傼U`Z:mFi7]ϢS-И': PhQiLI⾇DJ2tE@HSdq2PT@wsyH%-^.FKof"j=}t{j\0d)Ġ;^v:{JJb [}d;| Ց66D5aNHMn2I.#mUE06)KkܪoAc5SCz['|DM7\JolBʋT1o6 7:tiv#D `[O$c ^Wԕ.!_J%{.ʠ@Z4DJKk537o 4PEw٘5ƟD >L,k=H>w~Gy HAŶ u @=APruxCsw.1Ne+ЍO>u"ǒLaB"@Dw(z x\*9x>p'h:+S&_8Kqg~rk=4I#&^eBƃ@+"Gš6aJә Շ}I0<4l&|UµpM4OFw=)˦;u6Pg 6^5OMP^ G*43fΖW.^;kHԫ{+kR!2]naebe^z3Nj;[u1ldb?q\x ^P9ځ/1\R $7L¥×soi=:v 9w&eӞSze{љC7'dߢlM5u.CVaqF D9^6Sh_0f҃ LH=;_aAiDp ~8p[fV>>E6lf ɞ%%W_ /x+5C\%FxvxNmT4x/䐖g -PSۜZ6+@1%py5xk `mN&ś2ʹa:'2;+8aOF#?vy!ε{]&!=L憄$oEZp{N6[]U-|~Y{rQ~&f @П!Vk0KhCqx`DiðGBVRz6)1h+}kmW{xKYm{ȯ&+#,>Auzg]m$}Dqǖ-T OD iƐɈlv,h:7/=빶m#p#4 fj]Uv-+rU6l2+V::շZH^Х~dNKp.oX:J`#F`5u#nqqwl#z/MB y4_9Cnt,>c^u( ۔Dr_oeU3u*HYS[ RE01f+9-I?XnF@ŝ~6/6 endstream endobj 595 0 obj 4493 endobj 596 0 obj << /Resources 16 0 R /Type /Page /MediaBox [0 0 595.275 841.889] /CropBox [0 0 595.275 841.889] /BleedBox [0 0 595.275 841.889] /TrimBox [0 0 595.275 841.889] /Parent 17 0 R /Contents 594 0 R >> endobj 597 0 obj << /Length 598 0 R /Filter /FlateDecode >> stream y8I@jL@ -ay4I$cnu|^cə93tsIFUpLny{@{J*9g}]W'j>.2Ta[Bղ%r2?pOtjHY O]0g߫7ce:KП}!Ե2_gILLƝeUݟPxω^=kیfpC{&yKM,Wn^l~xWxESQ'̺ܧV1"l T.-$[8zXY&^YWemb %js MH{mtC>Y'Ȭ`( *Z[#~+RP8O& !֬8jMS@GbW"/Um9IfΝp͂]lIGD>3>R5aJd(ɉי1 gCY< OlƦ!ڞS{SJ( Xk?l|y#R$Le^0@>L\/ II)AQӔ՘C``xb XM\dr "Z&e!5Zyf1V%*ǛSD`Ȱơ@4zs3'sno߻ WބFߐOFRP<Èt#asӑFbDMfM6)Q&_к=d(MMm$ڱ¤{fэ򷹓?u5V{H~]1GG^Dc6E(9&b=m)[  Gw )Si,dOjx[1p/fnm\ZyR;ߐYTLi.3f|ҡs?0\\<023tǒhH*}Js*[Ƃӱ)T{]sOTgHb*a`d VPDFTbslP-fKeBM9q~r!>9 x3X=,T^\ '^`~)I׆ߌ.~#.TtZbI;x0-V+hc_BMp:U&}|fwM0gzd?3ѩ w?pF|]mdSR;x԰#>D{l^ TD@p#c4gr:Fn:0n^ x ~D˸rR3ldo[@wtQгn`?"!{rtq#U<%K Kͳ}QD2gVQ,.z)`ڲdsҎ^P qt0qԖ8^<D{ ql`:٦>lS[^=t)MdbrʦZxYB~HYY:=/ 6E#MU< SZ۶lƅ[ u-v! endstream endobj 598 0 obj 2017 endobj 599 0 obj << /Resources 16 0 R /Type /Page /MediaBox [0 0 595.275 841.889] /CropBox [0 0 595.275 841.889] /BleedBox [0 0 595.275 841.889] /TrimBox [0 0 595.275 841.889] /Parent 17 0 R /Contents 597 0 R >> endobj 600 0 obj << /Type /Annot /Subtype /Link /Rect [ 56.692 759.264 74.248 769.582 ] /C [ 0 0 0 ] /Border [ 0 0 0 ] /A 455 0 R /H /I >> endobj 601 0 obj << /Type /Annot /Subtype /Link /Rect [ 124.144 759.264 449.392 769.582 ] /C [ 0 0 0 ] /Border [ 0 0 0 ] /A 455 0 R /H /I >> endobj 602 0 obj << /Type /Annot /Subtype /Link /Rect [ 525.46 759.264 535.492 769.582 ] /C [ 0 0 0 ] /Border [ 0 0 0 ] /A 455 0 R /H /I >> endobj 603 0 obj << /Type /Annot /Subtype /Link /Rect [ 56.692 741.813 74.248 752.131 ] /C [ 0 0 0 ] /Border [ 0 0 0 ] /A 457 0 R /H /I >> endobj 604 0 obj << /Type /Annot /Subtype /Link /Rect [ 124.144 741.813 400.2 752.131 ] /C [ 0 0 0 ] /Border [ 0 0 0 ] /A 457 0 R /H /I >> endobj 605 0 obj << /Type /Annot /Subtype /Link /Rect [ 525.46 741.813 535.492 752.131 ] /C [ 0 0 0 ] /Border [ 0 0 0 ] /A 457 0 R /H /I >> endobj 606 0 obj << /Type /Annot /Subtype /Link /Rect [ 56.692 724.362 74.248 734.68 ] /C [ 0 0 0 ] /Border [ 0 0 0 ] /A 461 0 R /H /I >> endobj 607 0 obj << /Type /Annot /Subtype /Link /Rect [ 124.144 724.362 432.947 734.68 ] /C [ 0 0 0 ] /Border [ 0 0 0 ] /A 461 0 R /H /I >> endobj 608 0 obj << /Type /Annot /Subtype /Link /Rect [ 525.46 724.362 535.492 734.68 ] /C [ 0 0 0 ] /Border [ 0 0 0 ] /A 461 0 R /H /I >> endobj 609 0 obj << /Type /Action /S /GoTo /D [486 0 R /XYZ 56.692 771.023 null] >> endobj 610 0 obj << /Type /Annot /Subtype /Link /Rect [ 56.692 695.573 61.708 705.891 ] /C [ 0 0 0 ] /Border [ 0 0 0 ] /A 609 0 R /H /I >> endobj 611 0 obj << /Type /Annot /Subtype /Link /Rect [ 124.144 695.573 182.169 705.891 ] /C [ 0 0 0 ] /Border [ 0 0 0 ] /A 609 0 R /H /I >> endobj 612 0 obj << /Type /Annot /Subtype /Link /Rect [ 525.46 695.573 535.492 705.891 ] /C [ 0 0 0 ] /Border [ 0 0 0 ] /A 609 0 R /H /I >> endobj 613 0 obj << /Type /Action /S /GoTo /D [486 0 R /XYZ 56.692 663.31 null] >> endobj 614 0 obj << /Type /Annot /Subtype /Link /Rect [ 56.692 678.122 69.232 688.44 ] /C [ 0 0 0 ] /Border [ 0 0 0 ] /A 613 0 R /H /I >> endobj 615 0 obj << /Type /Annot /Subtype /Link /Rect [ 124.144 678.122 401.388 688.44 ] /C [ 0 0 0 ] /Border [ 0 0 0 ] /A 613 0 R /H /I >> endobj 616 0 obj << /Type /Annot /Subtype /Link /Rect [ 525.46 678.122 535.492 688.44 ] /C [ 0 0 0 ] /Border [ 0 0 0 ] /A 613 0 R /H /I >> endobj 617 0 obj << /Type /Action /S /GoTo /D [498 0 R /XYZ 56.692 717.166 null] >> endobj 618 0 obj << /Type /Annot /Subtype /Link /Rect [ 56.692 660.671 69.232 670.989 ] /C [ 0 0 0 ] /Border [ 0 0 0 ] /A 617 0 R /H /I >> endobj 619 0 obj << /Type /Annot /Subtype /Link /Rect [ 124.144 660.671 368.124 670.989 ] /C [ 0 0 0 ] /Border [ 0 0 0 ] /A 617 0 R /H /I >> endobj 620 0 obj << /Type /Annot /Subtype /Link /Rect [ 525.46 660.671 535.492 670.989 ] /C [ 0 0 0 ] /Border [ 0 0 0 ] /A 617 0 R /H /I >> endobj 621 0 obj << /Type /Action /S /GoTo /D [498 0 R /XYZ 56.692 459.225 null] >> endobj 622 0 obj << /Type /Annot /Subtype /Link /Rect [ 56.692 643.22 69.232 653.538 ] /C [ 0 0 0 ] /Border [ 0 0 0 ] /A 621 0 R /H /I >> endobj 623 0 obj << /Type /Annot /Subtype /Link /Rect [ 124.144 643.22 412.828 653.538 ] /C [ 0 0 0 ] /Border [ 0 0 0 ] /A 621 0 R /H /I >> endobj 624 0 obj << /Type /Annot /Subtype /Link /Rect [ 525.46 643.22 535.492 653.538 ] /C [ 0 0 0 ] /Border [ 0 0 0 ] /A 621 0 R /H /I >> endobj 625 0 obj << /Type /Action /S /GoTo /D [498 0 R /XYZ 56.692 242.305 null] >> endobj 626 0 obj << /Type /Annot /Subtype /Link /Rect [ 56.692 625.769 69.232 636.087 ] /C [ 0 0 0 ] /Border [ 0 0 0 ] /A 625 0 R /H /I >> endobj 627 0 obj << /Type /Annot /Subtype /Link /Rect [ 124.144 625.769 423.267 636.087 ] /C [ 0 0 0 ] /Border [ 0 0 0 ] /A 625 0 R /H /I >> endobj 628 0 obj << /Type /Annot /Subtype /Link /Rect [ 525.46 625.769 535.492 636.087 ] /C [ 0 0 0 ] /Border [ 0 0 0 ] /A 625 0 R /H /I >> endobj 629 0 obj << /Type /Action /S /GoTo /D [512 0 R /XYZ 56.692 582.448 null] >> endobj 630 0 obj << /Type /Annot /Subtype /Link /Rect [ 56.692 608.318 69.232 618.636 ] /C [ 0 0 0 ] /Border [ 0 0 0 ] /A 629 0 R /H /I >> endobj 631 0 obj << /Type /Annot /Subtype /Link /Rect [ 124.144 608.318 425.852 618.636 ] /C [ 0 0 0 ] /Border [ 0 0 0 ] /A 629 0 R /H /I >> endobj 632 0 obj << /Type /Annot /Subtype /Link /Rect [ 525.46 608.318 535.492 618.636 ] /C [ 0 0 0 ] /Border [ 0 0 0 ] /A 629 0 R /H /I >> endobj 633 0 obj << /Type /Action /S /GoTo /D [512 0 R /XYZ 56.692 325.918 null] >> endobj 634 0 obj << /Type /Annot /Subtype /Link /Rect [ 56.692 590.867 69.232 601.185 ] /C [ 0 0 0 ] /Border [ 0 0 0 ] /A 633 0 R /H /I >> endobj 635 0 obj << /Type /Annot /Subtype /Link /Rect [ 124.144 590.867 441.626 601.185 ] /C [ 0 0 0 ] /Border [ 0 0 0 ] /A 633 0 R /H /I >> endobj 636 0 obj << /Type /Annot /Subtype /Link /Rect [ 525.46 590.867 535.492 601.185 ] /C [ 0 0 0 ] /Border [ 0 0 0 ] /A 633 0 R /H /I >> endobj 637 0 obj << /Type /Action /S /GoTo /D [515 0 R /XYZ 56.692 771.023 null] >> endobj 638 0 obj << /Type /Annot /Subtype /Link /Rect [ 56.692 573.416 69.232 583.734 ] /C [ 0 0 0 ] /Border [ 0 0 0 ] /A 637 0 R /H /I >> endobj 639 0 obj << /Type /Annot /Subtype /Link /Rect [ 124.144 573.416 417.129 583.734 ] /C [ 0 0 0 ] /Border [ 0 0 0 ] /A 637 0 R /H /I >> endobj 640 0 obj << /Type /Annot /Subtype /Link /Rect [ 525.46 573.416 535.492 583.734 ] /C [ 0 0 0 ] /Border [ 0 0 0 ] /A 637 0 R /H /I >> endobj 641 0 obj << /Type /Action /S /GoTo /D [515 0 R /XYZ 56.692 135.506 null] >> endobj 642 0 obj << /Type /Annot /Subtype /Link /Rect [ 56.692 555.965 69.232 566.283 ] /C [ 0 0 0 ] /Border [ 0 0 0 ] /A 641 0 R /H /I >> endobj 643 0 obj << /Type /Annot /Subtype /Link /Rect [ 124.144 555.965 390.245 566.283 ] /C [ 0 0 0 ] /Border [ 0 0 0 ] /A 641 0 R /H /I >> endobj 644 0 obj << /Type /Annot /Subtype /Link /Rect [ 525.46 555.965 535.492 566.283 ] /C [ 0 0 0 ] /Border [ 0 0 0 ] /A 641 0 R /H /I >> endobj 645 0 obj << /Type /Action /S /GoTo /D [522 0 R /XYZ 56.692 555.594 null] >> endobj 646 0 obj << /Type /Annot /Subtype /Link /Rect [ 56.692 538.514 69.232 548.832 ] /C [ 0 0 0 ] /Border [ 0 0 0 ] /A 645 0 R /H /I >> endobj 647 0 obj << /Type /Annot /Subtype /Link /Rect [ 124.144 538.514 422.31 548.832 ] /C [ 0 0 0 ] /Border [ 0 0 0 ] /A 645 0 R /H /I >> endobj 648 0 obj << /Type /Annot /Subtype /Link /Rect [ 525.46 538.514 535.492 548.832 ] /C [ 0 0 0 ] /Border [ 0 0 0 ] /A 645 0 R /H /I >> endobj 649 0 obj << /Type /Action /S /GoTo /D [522 0 R /XYZ 56.692 323.163 null] >> endobj 650 0 obj << /Type /Annot /Subtype /Link /Rect [ 56.692 521.063 74.248 531.381 ] /C [ 0 0 0 ] /Border [ 0 0 0 ] /A 649 0 R /H /I >> endobj 651 0 obj << /Type /Annot /Subtype /Link /Rect [ 124.144 521.063 392.225 531.381 ] /C [ 0 0 0 ] /Border [ 0 0 0 ] /A 649 0 R /H /I >> endobj 652 0 obj << /Type /Annot /Subtype /Link /Rect [ 525.46 521.063 535.492 531.381 ] /C [ 0 0 0 ] /Border [ 0 0 0 ] /A 649 0 R /H /I >> endobj 653 0 obj << /Type /Action /S /GoTo /D [536 0 R /XYZ 56.692 717.835 null] >> endobj 654 0 obj << /Type /Annot /Subtype /Link /Rect [ 56.692 503.612 73.588 513.93 ] /C [ 0 0 0 ] /Border [ 0 0 0 ] /A 653 0 R /H /I >> endobj 655 0 obj << /Type /Annot /Subtype /Link /Rect [ 124.144 503.612 352.614 513.93 ] /C [ 0 0 0 ] /Border [ 0 0 0 ] /A 653 0 R /H /I >> endobj 656 0 obj << /Type /Annot /Subtype /Link /Rect [ 525.46 503.612 535.492 513.93 ] /C [ 0 0 0 ] /Border [ 0 0 0 ] /A 653 0 R /H /I >> endobj 657 0 obj << /Type /Action /S /GoTo /D [536 0 R /XYZ 56.692 595.95 null] >> endobj 658 0 obj << /Type /Annot /Subtype /Link /Rect [ 56.692 486.161 74.248 496.479 ] /C [ 0 0 0 ] /Border [ 0 0 0 ] /A 657 0 R /H /I >> endobj 659 0 obj << /Type /Annot /Subtype /Link /Rect [ 124.144 486.161 346.63 496.479 ] /C [ 0 0 0 ] /Border [ 0 0 0 ] /A 657 0 R /H /I >> endobj 660 0 obj << /Type /Annot /Subtype /Link /Rect [ 525.46 486.161 535.492 496.479 ] /C [ 0 0 0 ] /Border [ 0 0 0 ] /A 657 0 R /H /I >> endobj 661 0 obj << /Type /Action /S /GoTo /D [536 0 R /XYZ 56.692 296.903 null] >> endobj 662 0 obj << /Type /Annot /Subtype /Link /Rect [ 56.692 468.71 74.248 479.028 ] /C [ 0 0 0 ] /Border [ 0 0 0 ] /A 661 0 R /H /I >> endobj 663 0 obj << /Type /Annot /Subtype /Link /Rect [ 124.144 468.71 332.583 479.028 ] /C [ 0 0 0 ] /Border [ 0 0 0 ] /A 661 0 R /H /I >> endobj 664 0 obj << /Type /Annot /Subtype /Link /Rect [ 525.46 468.71 535.492 479.028 ] /C [ 0 0 0 ] /Border [ 0 0 0 ] /A 661 0 R /H /I >> endobj 665 0 obj << /Type /Action /S /GoTo /D [546 0 R /XYZ 56.692 659.056 null] >> endobj 666 0 obj << /Type /Annot /Subtype /Link /Rect [ 56.692 451.259 74.248 461.577 ] /C [ 0 0 0 ] /Border [ 0 0 0 ] /A 665 0 R /H /I >> endobj 667 0 obj << /Type /Annot /Subtype /Link /Rect [ 124.144 451.259 353.703 461.577 ] /C [ 0 0 0 ] /Border [ 0 0 0 ] /A 665 0 R /H /I >> endobj 668 0 obj << /Type /Annot /Subtype /Link /Rect [ 525.46 451.259 535.492 461.577 ] /C [ 0 0 0 ] /Border [ 0 0 0 ] /A 665 0 R /H /I >> endobj 669 0 obj << /Type /Action /S /GoTo /D [546 0 R /XYZ 56.692 335.916 null] >> endobj 670 0 obj << /Type /Annot /Subtype /Link /Rect [ 56.692 433.808 74.248 444.126 ] /C [ 0 0 0 ] /Border [ 0 0 0 ] /A 669 0 R /H /I >> endobj 671 0 obj << /Type /Annot /Subtype /Link /Rect [ 124.144 433.808 268.948 444.126 ] /C [ 0 0 0 ] /Border [ 0 0 0 ] /A 669 0 R /H /I >> endobj 672 0 obj << /Type /Annot /Subtype /Link /Rect [ 525.46 433.808 535.492 444.126 ] /C [ 0 0 0 ] /Border [ 0 0 0 ] /A 669 0 R /H /I >> endobj 673 0 obj << /Type /Action /S /GoTo /D [570 0 R /XYZ 56.692 771.023 null] >> endobj 674 0 obj << /Type /Annot /Subtype /Link /Rect [ 56.692 416.357 74.248 426.675 ] /C [ 0 0 0 ] /Border [ 0 0 0 ] /A 673 0 R /H /I >> endobj 675 0 obj << /Type /Annot /Subtype /Link /Rect [ 124.144 416.357 361.667 426.675 ] /C [ 0 0 0 ] /Border [ 0 0 0 ] /A 673 0 R /H /I >> endobj 676 0 obj << /Type /Annot /Subtype /Link /Rect [ 525.46 416.357 535.492 426.675 ] /C [ 0 0 0 ] /Border [ 0 0 0 ] /A 673 0 R /H /I >> endobj 677 0 obj << /Type /Action /S /GoTo /D [570 0 R /XYZ 56.692 324.427 null] >> endobj 678 0 obj << /Type /Annot /Subtype /Link /Rect [ 56.692 398.906 74.248 409.224 ] /C [ 0 0 0 ] /Border [ 0 0 0 ] /A 677 0 R /H /I >> endobj 679 0 obj << /Type /Annot /Subtype /Link /Rect [ 124.144 398.906 327.039 409.224 ] /C [ 0 0 0 ] /Border [ 0 0 0 ] /A 677 0 R /H /I >> endobj 680 0 obj << /Type /Annot /Subtype /Link /Rect [ 525.46 398.906 535.492 409.224 ] /C [ 0 0 0 ] /Border [ 0 0 0 ] /A 677 0 R /H /I >> endobj 681 0 obj << /Type /Action /S /GoTo /D [578 0 R /XYZ 56.692 230.301 null] >> endobj 682 0 obj << /Type /Annot /Subtype /Link /Rect [ 56.692 381.455 74.248 391.773 ] /C [ 0 0 0 ] /Border [ 0 0 0 ] /A 681 0 R /H /I >> endobj 683 0 obj << /Type /Annot /Subtype /Link /Rect [ 124.144 381.455 403.786 391.773 ] /C [ 0 0 0 ] /Border [ 0 0 0 ] /A 681 0 R /H /I >> endobj 684 0 obj << /Type /Annot /Subtype /Link /Rect [ 525.46 381.455 535.492 391.773 ] /C [ 0 0 0 ] /Border [ 0 0 0 ] /A 681 0 R /H /I >> endobj 685 0 obj << /Type /Action /S /GoTo /D [584 0 R /XYZ 56.692 660.476 null] >> endobj 686 0 obj << /Type /Annot /Subtype /Link /Rect [ 56.692 364.004 74.248 374.322 ] /C [ 0 0 0 ] /Border [ 0 0 0 ] /A 685 0 R /H /I >> endobj 687 0 obj << /Type /Annot /Subtype /Link /Rect [ 124.144 364.004 296.954 374.322 ] /C [ 0 0 0 ] /Border [ 0 0 0 ] /A 685 0 R /H /I >> endobj 688 0 obj << /Type /Annot /Subtype /Link /Rect [ 525.46 364.004 535.492 374.322 ] /C [ 0 0 0 ] /Border [ 0 0 0 ] /A 685 0 R /H /I >> endobj 689 0 obj << /Type /Action /S /GoTo /D [590 0 R /XYZ 56.692 771.023 null] >> endobj 690 0 obj << /Type /Annot /Subtype /Link /Rect [ 56.692 335.215 61.708 345.533 ] /C [ 0 0 0 ] /Border [ 0 0 0 ] /A 689 0 R /H /I >> endobj 691 0 obj << /Type /Annot /Subtype /Link /Rect [ 124.144 335.215 177.021 345.533 ] /C [ 0 0 0 ] /Border [ 0 0 0 ] /A 689 0 R /H /I >> endobj 692 0 obj << /Type /Annot /Subtype /Link /Rect [ 525.46 335.215 535.492 345.533 ] /C [ 0 0 0 ] /Border [ 0 0 0 ] /A 689 0 R /H /I >> endobj 693 0 obj << /Type /Action /S /GoTo /D [596 0 R /XYZ 56.692 771.023 null] >> endobj 694 0 obj << /Type /Annot /Subtype /Link /Rect [ 56.692 306.426 61.708 316.744 ] /C [ 0 0 0 ] /Border [ 0 0 0 ] /A 693 0 R /H /I >> endobj 695 0 obj << /Type /Annot /Subtype /Link /Rect [ 124.144 306.426 173.193 316.744 ] /C [ 0 0 0 ] /Border [ 0 0 0 ] /A 693 0 R /H /I >> endobj 696 0 obj << /Type /Annot /Subtype /Link /Rect [ 525.46 306.426 535.492 316.744 ] /C [ 0 0 0 ] /Border [ 0 0 0 ] /A 693 0 R /H /I >> endobj 697 0 obj << /Type /Action /S /GoTo /D [599 0 R /XYZ 56.692 771.023 null] >> endobj 698 0 obj << /Type /Annot /Subtype /Link /Rect [ 56.692 277.637 105.257 287.955 ] /C [ 0 0 0 ] /Border [ 0 0 0 ] /A 697 0 R /H /I >> endobj 699 0 obj << /Type /Annot /Subtype /Link /Rect [ 124.144 277.637 179.067 287.955 ] /C [ 0 0 0 ] /Border [ 0 0 0 ] /A 697 0 R /H /I >> endobj 700 0 obj << /Type /Annot /Subtype /Link /Rect [ 525.46 277.637 535.492 287.955 ] /C [ 0 0 0 ] /Border [ 0 0 0 ] /A 697 0 R /H /I >> endobj 701 0 obj << /Length 702 0 R /Filter /FlateDecode >> stream #C6Ę}B2i ;]mǪTv\sm$)g"8j>N*Ò ֽt2RW>bN}oH:ʻX5Ж/®Ty:SWsLY"&ہһn kh7=pBl$(pbJ/Ďj+dYc2۸u+AaFAJp@A {i>m{4<l[p;Vп|*t WlmK!I8Z@"̶H+y)onK LY@z}˻.QO@ذIduXvASH%-G .BwBXfi+ۓ5$8JfVэhaR Ѓ6롗Kd+6fk:9&(ǡqI?G~tL@2GVb,S/gFZ^ Y̧LYf!BnrDV723 `S`{p~\:64G G+v-@ ϐZ;ҙoA6iЇLng^è*r ;*~ hN*mF 癘9C@j áI[-_ѿ?} i03R(외WxC)01ajs9Ssȝʮ nҨ+ `TM{3o'5!'D5~-Gu̴SJ-x qHr>tbLk|:[&X ֕ % GL[D>4,f ׍/Hq~RnuRA̘*왙BA['U65 X,sLwAIlrs aVQɞ.jNpH|]Ĺy8j3o0?ڟVT~Iw ?:E&MtMDlw`SA2% $vQZQÃg#w '2G; *u0?iNrb@W2O)?1?*j&Ih $Ar O4nX? \vrPש<0wN;M1<ZS 3M:uφVjMx}z i~ r\MK'~:[:̆D0Ju.&Fi0jĆa >nP t.:+04#W0#X'xZZIQ/2|݌ʹ7b?/I q;jGzZB:}!"\Z|Y"+?hQ N ߳YNFXDa3;7,K&tPLPM>< -C[9V>Ղ"ͩĊ.`,2"EQb,(E뿗pO*W5ɏX?B.ޣfy7E|4 }ކ]:#b><敹FyV;%ʷ~m)1 endstream endobj 702 0 obj 2402 endobj 703 0 obj [ 600 0 R 601 0 R 602 0 R 603 0 R 604 0 R 605 0 R 606 0 R 607 0 R 608 0 R 610 0 R 611 0 R 612 0 R 614 0 R 615 0 R 616 0 R 618 0 R 619 0 R 620 0 R 622 0 R 623 0 R 624 0 R 626 0 R 627 0 R 628 0 R 630 0 R 631 0 R 632 0 R 634 0 R 635 0 R 636 0 R 638 0 R 639 0 R 640 0 R 642 0 R 643 0 R 644 0 R 646 0 R 647 0 R 648 0 R 650 0 R 651 0 R 652 0 R 654 0 R 655 0 R 656 0 R 658 0 R 659 0 R 660 0 R 662 0 R 663 0 R 664 0 R 666 0 R 667 0 R 668 0 R 670 0 R 671 0 R 672 0 R 674 0 R 675 0 R 676 0 R 678 0 R 679 0 R 680 0 R 682 0 R 683 0 R 684 0 R 686 0 R 687 0 R 688 0 R 690 0 R 691 0 R 692 0 R 694 0 R 695 0 R 696 0 R 698 0 R 699 0 R 700 0 R ] endobj 704 0 obj << /Resources 16 0 R /Type /Page /MediaBox [0 0 595.275 841.889] /CropBox [0 0 595.275 841.889] /BleedBox [0 0 595.275 841.889] /TrimBox [0 0 595.275 841.889] /Parent 17 0 R /Annots 703 0 R /Contents 701 0 R >> endobj 705 0 obj << /Type /FontDescriptor /FontName /EAAAAA+OpenSans /FontBBox [-549 -270 1204 1047] /Flags 33 /CapHeight 713 /Ascent 1047 /Descent -270 /ItalicAngle 0 /StemV 0 /MissingWidth 500 /FontFile2 706 0 R /CIDSet 707 0 R >> endobj 706 0 obj << /Length1 12916 /Length 708 0 R /Filter /FlateDecode >> stream % cV%ғ$͒+!Z6G׀o@ >ډ.m5Qڬܧd}xox|ǔH_yĆiK1~{2}8.!XP>zc=UZ)R:WT! v$/1} xfrLx_<bj#~Ç~6ne*v Z&}"ZHULaNӿxMlβϞ]\Mb(FWWE\UKۨTU.-EʁY#~@`NGG?xL*Pcyh:|EAjDWj535FH(k*.3YD7 D {=z̽!Tv㭨$V Zݪjs0FtQkt#lw{̠MP+JHV'&&1u\b}B q63O[R|ˡ G,\#'&kD/c^;}rE'Ѽ%Ԓ\8G; R/"l=2zI_  2tb([ }I{39c<24^:C_C,@q,n4ĉJ폤b2T)?XoHYۛ!L+X%O $=GkW t0'仕Ak󮑊k3wFRZc+KAFS FH;"D$LPldar nYD3VC:UwNw]?5᪮/CXnejn^ŊNdz2-3yO9%C8[ ذB la=54p Zy և'z'-h] %oK3ۓ>Ha Ld/IX$c%}56;Mc .܂N;1%d)PEhTMWS}yX*5qRUw@!!&͏Lɶgw;[?Hp~s?c3!MxMNة g[½娋yx3MZo{~$qTYNELe'49I(wSeMܸUD˄kNCco{s ;kX+~D2FCO]Q䝣6j[`~\ޏfdh4 1#JuBb!ne-K gn0Q5/!: Fqx{gڮxf`nŭtm%[x/V sJ}©~^@k+XJvqQ+wzf7JunUa nf$נ+(0>jA+Rnw~ Nw)oE-$:lt]-iBm6@JzJ}./TdAD`ڜӟ_DpaA#9 >x/B}΋d$Ǜ5 \ԙdwCke'`a9q{Rp ^)2B>*7P@r;=MđrWߠ4BlTCřY5D7ͥn\3&x"2( }:lI[[֙;|C)7ޙOn̽y_\ENYmnw`A֣F ^;Z1 꾣@ąs?C_d M":hi;xʕI|AAb(AĄE-w',.{hN+{wQ, T.{$ӊVTX@U<=&ʩ>;دk_z-y 9BV:Km0ޒ~Ņ]%F6F:) K )}#mЯfך#']i 4AG`V9S;3.M8vnՆ @&|]o!*_G_V~9F(508'KF#U746>9Cf__u1L ~)W4L$C}*ϫ8 >tE⇺i&"Rýrtx7#_wwrҍe*c؆; W0y&/h /#i常CCVx~C ,f-=zDYu`6~kxcD][+tSBGUzYDr}K+(ӢjZ*ZꢟM5J{PiV7f B|kFCf I;J迀lrb[Է|BO9WF?@EF~ N-\djV>ާ([h(},R+vT#r-ڞG^*'T#qpK qMEHAp={ ;+P'~.95u=UiAR~Cs{TGlB,ּ):GѿE3i uTdr'.bmoLȗd-ۯ-]xy{Fm]g`o}*kʾOWb n#ưȻ4si{KߡCɂh*w " SK:fkoM"1v~S5dmmj -T@ȞQE(4=I|_n <&o&batc:z~̻xP +R=}}HݼQS[+a,M>#=eJ6|wѤ.2yQnsF׻/OՆzh !:iedbWv&xMXtk^<(2qT*6sD3l ̯n8 6,FΎA) nGI\O4%t`\78B^͐>V.)Z\BpWqE&x\о%NZ="_%PtsNzG8iqH)2~Snh0{g2^/q7W)Pݻ\<1ZQ G4nU @=z܋`g>r(ʱ7h-6l^:76aIUt"D,2K$@XN"%kL͗Օ9pU+mhl3bHb[K{Ik߱C.o(bz~(,3V|iLDќ/%OusCĥJq;ՆHŗS5i8$߲o28sG>jp=޲ISPbNm<hPHN 3]6Πy"Q+$<$w=fq\]ڰ4W.jLQ6D>%q݇Оñj+~BXlHL12ENkUtq]v@ohZffAղDlY]҉v.[_XMMYЊa\QDӔqkiO<>[q|f耼w-u{Sx/D Lk( A^6Kߐ#K8=(Z#ї'lÜcy.K̍ Oޱ3Aߧl賡$9%l.%{5 F"FT(*Vf6ð\Z3CjM7RadNF+T(%[y\j"㟾pO>ˢW(3T{Sqs `w =QUv4T]@CPC$Xͭmqɀ}%-Š3r5 -*ie,d٧`о>~`qȟNmū3A2'ayp $6frCVĘ߼MSp32>`}k}/²LΈ9yn’'T9ίkܥUL*;4t:osxs?cy  ֜1> zOVYB2CFEB~Q~w%,?KVP}WS , k ђJ4 +QA(;N ȩ Pdx;NR2Ǖ|B\ o+g?*>.G;Jۅ ZN/FNx"NLUOFeI>kL{O^4Hc# hPl9A"$\xFYs֖|]Hb#=?pJ{z,GSD/m"c" Xޙx?lYHg &Ӳe=:._d3\ĦMjx`&4ܯLQؤ2pIE©aZ NIY[Q(NO#s2.pE#C E@'gDK*KJBLh4#| c2"^sN"wx~Vvؔ 4fnoZs%L΅۹l9x8ئ+%NDlj[3/F|F8OEDaNZEqn;#%[VЃ)T"xBd۱6{1#8⊖NOlX9 #^_@ȻvȊhnc{zA^T'e6U'_7TYXq.,:z18#) 0nntfYf'&}C-/ ajwUj%c r{tc)6qH!S+$C:W<[MOhW4F{حyΤҪLOH}V87ՙ &J4ٺGz25ޝ~{]ia&l/F2˾THr;F5cveVvL(lT}ܩ~ .|P$xy_!D4 'wsqp'luQ97%7 ם,e̢aO9+9#-J/˓*D 3 kGe=txBHƈYpUL1crC]?2fa]6?*k~\e< 17_?lWq^koչw؝Ԡ_7ݸvktۇ%]݉Ȧ09L-:rL6"ԯ,F DX<51P=^iU+$qNn1l]XNDs ҷp`NI 5C@jJWcwI+  QzIfjy"`*+2bm:E2VS5gZybh`4a%CJE$w/ =!S9gTr~LN$#W=:}orK eC*A!ډȮf4mM M ? Pzt"f,^[8Z ȶw@7FΉ)ki((R_|"o&F\]֟H~(Yah'FQS L l4Zy*2*%Q0 ;F52UX0ߐio+9ˀK;&p@h8{#Sk>=R}XۘWyj(X4j= !HvPbgNZj$qkNz)̄}=cI›`% #U..o5urYB |L1NxۜtprOcU}6!09}^de쒿]>kvR^~ qyҊ Uf*, @u e?V$D9C&$h"n YW,Q(D{2*#P@!j0`'x ҇d-OG4Jk \i hUnIm]_J-/o}#V&ϣKd,;nS=ЄVw},ՂL')IC9gE}ΉiUO2,kC~ǟ[څgd)$TLpBϹ@k%CÃ䢽h³[k[URɡ%[W\B;8n<5wPVf뙀g!a[n> stream R:'8XZ+$pl8ixߚ U endstream endobj 709 0 obj 34 endobj 710 0 obj << /Type /Font /Subtype /Type0 /BaseFont /EAAAAA+OpenSans /Encoding /Identity-H /ToUnicode 711 0 R /DescendantFonts [712 0 R] >> endobj 712 0 obj << /Type /Font /BaseFont /EAAAAA+OpenSans /CIDToGIDMap /Identity /Subtype /CIDFontType2 /CIDSystemInfo << /Registry (XP\(tM) /Ordering (XP\(H) /Supplement 0 >> /FontDescriptor 705 0 R /DW 0 /W [ 0 [600 259 321 753 252 613 561 353 728 278 618 500 252 777 548 476 613 408 503 556 556 604 602 612 930 252 612 477 729 595 630 553 612 338 571 523 266 571 524 571 571 571 632 613 571 516 547 519 571 571 778 728 902 591 571 1000 266 932 737 448 295 295 571 647 925 467 613 612 259 ] ] >> endobj 711 0 obj << /Length 713 0 R /Filter /FlateDecode >> stream r*!HP.t4KҫfK1 Rʛ~se 3"SxwdyCNm2Ao-| N7TAtZhT);ScKN VAjnD%=[%7'_7N$j0Fg-ݬ IUlN iuPmN1SILuՖO9خeb?o"a((65NF[㛀H&;oa+Ls'D==z+㰋]u\c躮\OKD Yw2ګ GrD4]goDŽskhŅ&:q ȡ p><=)?*.I9Rua-8.qIWsEE mfZ#lCWzFHRC#0%ʔ'J'od_Gl1{(EF|Na|.? Q;lXkzݼ@b~o8]SrD!z Vtײˇ1 endstream endobj 713 0 obj 532 endobj 714 0 obj << /Type /FontDescriptor /FontName /EAAAAB+LiberationSansNarrow /FontBBox [-166 -303 1000 910] /Flags 33 /CapHeight 687 /Ascent 910 /Descent -303 /ItalicAngle 0 /StemV 0 /MissingWidth 500 /FontFile2 715 0 R /CIDSet 716 0 R >> endobj 715 0 obj << /Length1 21228 /Length 717 0 R /Filter /FlateDecode >> stream :ؠLrR@gJӵ'l c54*j0&Ёѝɗ;_yr"_<}DBSQݿ0/rg2|jTD c#{\c!rwnsA<,wE.Lv\|Otat$ \5 1#tϪ*n _pt]>cF)|Rk*wc$LI!mJ'JOVh hF,%3IIcFPQxa,- '2ͷ1.FS@ aO@&͕ }b ̷߰s6 ,2\2U܉C SfhP+AܚP,Kjq7[~V(D\E1"D8wm]}3813$CW_F"=kz<;!)0s؄S}w&z9-Gq^ʎF\w3bNWMcB6߿MXaA$ܼXQ]<_vh^oyTnF rKZ8%QlX/0/&Q*awtDžoNNl&Z 17.GݺQ~^^Ӗm + "KEWbN [IRGSxh%HhaVoȱExB&65pmI0 YjH\nHWV`aØQEzhސn ׇ 4q$&]D#DJI-:Ճyum*u k` ELw|Nn;1[J@}9,}ʬb,i)4n(^^. VdD yp&eI|lGĘld ; $z9%p& 1!AjSsCTE֞Em.V8:zLoe7a,mID:| ա`E.xĭͫ{t`qx'AxDy>B*qϊ`֭!;I 3C;M^ 2yZ o]#9ޱ3+^J|G1i]!ٝS/AC?X2d\iv? ʤf9 ;,x0?}!#B&, 0/WL 9-rgNPe(;JO*$H"76O}Rq'FKUT,H+ݳ#8"qۑᤜZTW-0?(g++[[N9V[W:^33Au3O42x$}\hC+}\?.GЌͲE4nӿ_ ܟ[F&aφmZcRC. D 蜁?//8 'BplagyDsϋSAeP$7y# )60R :<)EU%܍d~ߥkn5I#^9 &.‹_4I L XBCR+$~h 6p =ן+gb;pv%|`sj-ܡ\5A :xľsn;O 7SP.mSWWAIt=(sؘ.wCXOS0::ó*y^= 7.]1޾GcٹE"q?E+LnֲC| tc X1԰i׽DnoEOxT$6Ͱ:Vb䌕wt!㈨\Ѫ_d@x'Mf՛.~ C?hc*>ח=VdC F9:J1oqXS-u=w-tonv9tU+A^gE_mZ Z&:ѦPFK82*30Dhh^^ʬأ921w0)5jA=?%$ $k-ngc]L?%vTxLI o:8ZfZ TfH;F2'49'@@tW5'`Arb ƀ]sA3T@ņ97Dt=4JZ{B% R׬*Cy:ӉMDQ AM Ǵs龳&phiH 0]U1<8J.JF>% ]5ڨ)5䕃I}wV1 yÞBAX41YDeX]EE^D?_L,dVբCśK7&u1ȸ3!C)V3݄['#csb2M,t~!7^ʍ{{sJh?D4~la1+H }g9i ~qD1"."2 }XK \|ѸooϲvGs1,X~ǨfEi:C$ЌZ3x*FgXKm%T(_yߥrNw\+Vn\iY/r ^w,Q zE$! u<ض_;ma* X(z5駖D\KRsGW=[@I?nPT snLlǡF_A\CON#c7vJ5&Mu*ULIrsx\~l0yUߍP-UCyёC1װp@{,;  <%^Y._嶼+1L]CYjCcRvoLH$)M'y̭T Jڒ$'|E<6ʦ>=[M(-CC>!k[EV~ɘ,XH>FQ3J#겝L.;+?)3ٛшobO _xa3\BܺWS_Y ETkin^r/r. DF5Rh&Y<'l#‼ߒ"2 &y(A9^@ƞVEew)k/*nFG wv م(ދKq-?Aơ3Q#xI N.a'/zN5ˀ$y|C*vXWq>Ir$)mYp:(q>m:j$/ӕ s曜H[n6RqbU@Sl]{2ksΦZcZw<'V#mc(1b; G31Ea4NIo1?8@six~D(ZVN|̝Ϟ`Tq/61j\'MjyIʙ8v#ࡠUguGU6Q5d{%"@s俋S%r F[p2gDxCB/U$40uJz}p ׼{59v?: J֠UH~`p=x-)lL ,ϩpB5;KoG|Wp/!Կ88(XYPs!2OT2+^r9j-gzaٍ!'c.\KZz.f$՗AREu?3-˙;Nt;%ӭo%w3nt1 ^}Nr{  N K9 =wu,˥e < r!.pH뭪<"0kb&`Yc7>?5?uKNrR! =wOg@M+ ߛ RWOͨ}=_ԣP$8ϟ٠$Cۮ՟HNkdXdׁ[xzu}W\Ke-1&u6C}K>8sώE>ewQʴ]mFvc/]̬)@Cٓȑ=(")!v~W~+2E,S9Q["qm|CuP,8IbիuZU,3R|M9 ijVevr@ɸ4cG$bE{iQb/LxL4h1sNX:fM|u; zp ڷE_-M| K P)d-6reF]{飛yjK siK,o~nӦTI#O4ihgDUFG@̠#@JR&-Rڿ߹} SX9i}f#oa, "".p_%VO8f,Y/KnʪA>ig4W+߶Gg2 R9aNٺgnJϺOSB4 })+"Ez4Pfg\˟xmkHnW^-rI=Wnhv|)F6D[݁CѠ.$KH`[|IZ`>9@ĤTTcrBW%#GDyFjUy^zFKb\FͧNn-sld~T_BMAg{;DܹY^v49ƙ / k; 04z~S_eƇ-&#I[IF132pP 2ܼZj;c~ILOGl5-؏!>2ue*R]\y)ome 7WXw;gN辵߷, #ZG՟f6E 3;Je<`aWlrib3d9ѡՐb >am-igҦgٱAQc:ᄲB5H_(}XB5Åns bB2u%' x>)j>|7ފNoe8F|VCʐu9`IJO8[xL ZwJ2*R"H zw2 M}ohgW}Tծ堿+-c?֤Al$j!q2&N=j_u-)\>%IsixXxwbw VSAUss)/mtWM}~[/D բMr퐛X NYCUb8u 2D/;5Nf^Qt*I%"9sU"C1 b U9>H{CV2-!0HEnPWL (^^B!֛A2RChBG0=h!ÝTH)PvWGOiHMnz\pj#D- ε@sEY?R_-'si3 Ǧ0Յ=1EwYZV=4<`W ]4CU3GA5r(vtLy?cj'aUMƦ$TN=h6u$o/Õ{]?)NC~3X䭗Pin[$_msUqR\#闀lWE@U=\U!㉷,T=F"KzrJfߙJC:AdbA Н C=/?:,Ь^_}Gp,01 G?SQR[Ct+V(\&XMtu^'J'eGsr(kט}pysH;=PrOxdb`PH$/Z:VZ=AIߛ>`ˬ=-X!WgݓRs:"+[5f;a3ۜvk} 50f4i_ST,;$gri.|ɥzQ D뀟: :U.Fro ң>y̎ ˶^˹ce se,Hg'C>(ϸG%۠TX-DC@u<* ]y6NLtP($C?Deq'N \;HJ JWkC>š!A>oc&y]!+f>#fOXx 0Q%3̓ `_6N|us&S~T#ߓt\@qM}dN'⛐}j>/kᛙ;RGћcBS 8RROo+yӻ`G|Ԩ:gĜ {_ȻEG6(MTv3kvzyIWCU~;Y0&򍏛!iY D{?ԈOI.غg M%zS"">'~D~jaXɑ$d$1 u4* gxű >~jV\i[UR"nyͩwӑ\clJ<2DL&;#,7p_#_wz R0=&ԚCAZۘ*>m=;%[Nڌ̓ɪ~"fWFѬ$*/6t7Ig;-?[ g]L:& k@PK]p.t= KMJ;POa'^1Ns'^ص x19f6ʂ1;n%johy*5'U{o|',WoNͲv[Ph݉ i'Iw Qf ˿ƐIL뚍[-G5T$uQ75yJA QaA1r M{XY}a~&j}5 c\g!CoAgVa#fFxmLULp6AWzaZr\z=Hi"SRbP/Af+*; 7$}hsx$@3V#<աEY3l'2m0#K4gm Ҭodsxݘ4@qF4ڹKD/bQ35ñcEL#fIKtZ זX4d<3[AXY#iyO;v2wGpSh|O:U-7 M~]z4܊3ZtG Wv5e'],k*sM`)"tJ.l ~]7Ûԅ5Qw2^΃}uz+Kotvu\im:C3,nNkž}ߎ,r";Wig%u# V}u5F#LrpF"{CG؏k-n'򪡳*?\٫2'/YW=hܨ o >ޏYpxSJ.Y_*sAyvi1\&J]9x^,D7޸d3s };iQ >c#&'ڔf@>*p٩c2:j+D>4baaY$' w->+P9{u8!Ipv`Xw%4vV|4w`jz 2VըgpȳVܒ}kC5df*(F2h:#UU5 K>C~|%BFτ{~ #RjMο9a\CxɘS2j;ROnk}OLL'{R0)GIډϮumvY ṵcSMYy6]=&tCקo4YKz#'8JB;ܚ$ }*y$v,%.FɦNiԈBPd~-m11JTO d 4qM{"+`J]L7X?-aTDq[iLͼ8S{\bUI㏝6G(0w[œC"'#U@FkYa2&uwC Tz7NC[Ӱ$"q{.4z$|tT}A"I[ u' 71/zNWyuq,!7v"W_B= ڻfAxۋ˼(EYF>Xo_pazB<[-OhQ"P>&jiߐyKK(u+ endstream endobj 717 0 obj 13857 endobj 716 0 obj << /Length 718 0 R /Filter /FlateDecode >> stream wCmk)f-~ni2 endstream endobj 718 0 obj 27 endobj 719 0 obj << /Type /Font /Subtype /Type0 /BaseFont /EAAAAB+LiberationSansNarrow /Encoding /Identity-H /ToUnicode 720 0 R /DescendantFonts [721 0 R] >> endobj 721 0 obj << /Type /Font /BaseFont /EAAAAB+LiberationSansNarrow /CIDToGIDMap /Identity /Subtype /CIDFontType2 /CIDSystemInfo << /Registry (#UF[ŗ) /Ordering (#UF|) /Supplement 0 >> /FontDescriptor 714 0 R /DW 0 /W [ 0 [228 228 272 546 456 228 546 683 410 228 456 272 456 456 228 456 182 182 456 456 456 456 456 546 591 546 456 228 591 456 456 456 182 410 500 591 638 591 410 591 546 410 546 456 228 228 228 456 683 591 410 410 410 500 638 456 456 456 546 591 479 272 272 456 832 456 819 456 773 546 456 287 157 729 410 546 228 291 546 228 456 479 456 ] ] >> endobj 720 0 obj << /Length 722 0 R /Filter /FlateDecode >> stream Y4[݇$IEthZuشltee%.H| u׳7~T;nvUC*Co9X0,7a{2)vн3Rs kr5q+e$S WlCbil+H [2O_JV ; -SכEĢFuq&G Mna}VҎ理t@I~D]8_(}_SԼRR&i[:&O!fU PoxM^+, 8<KhEW &'X(ŖU"wK_PM7}-[qJ5l&c$R:zKW}I]y6V \W}ҽZ\] endstream endobj 722 0 obj 583 endobj 723 0 obj << /Type /FontDescriptor /FontName /EAAAAC+LiberationSansNarrow-Bold /FontBBox [-151 -303 1000 1033] /Flags 33 /CapHeight 687 /Ascent 1033 /Descent -303 /ItalicAngle 0 /StemV 0 /MissingWidth 500 /FontFile2 724 0 R /CIDSet 725 0 R >> endobj 724 0 obj << /Length1 15712 /Length 726 0 R /Filter /FlateDecode >> stream 1Aʸ\e=UNQb'+%{'<_6ە z]Rgnh8 w3 55/zU 7@|@L7",_Lʳ 9w-̘ @-Ubo^ &Õ ɷۃJP0ۄK&lCCzTأk}Y]7 w'VQFhܪC]!5ޡQ]r;щI`q=N7H\Dvt dʔ\xAC^U,#,ڲ$.A }nŅʸiXr'1pP"  .薄"TP~’9;wkϝ⑧%S=4ax aj,u[|C 5ZDz4b[>yaԑK Ce%Xq 7e W[憻JBQs)AOQ:5@EnC&R3)Jr-\Oب7`q!/6eTSOu/th # k㦴|!"N*ƔہSkhkzAE!t|(ګᯛ{‹HˍR*hb Hw]X'V^H:o!E%69MNNQBnOuԩ ݴ3ũ ǕEWaq9pUbDh!Xխqƙӧd;Kv=K!)gl}oY ˚`9<ٶ k23s:)!΋HQT2 _ b'^ePCǞyJfg(tD|g/ ea  ֛v\ѣdڸIv:yQA2P/Y@'eiUu-/:~IL.&SK3U>V; HOk!i,C"10\Iërn7*C\}=ԏF\[%YQgCriq]͈:_ :+Xqd} (h{z5e:io$XфzvH)4DBlR%¸_t"?*5H8$We4;aEӒ@Ji@L(RraH؛Z+)\CI /Bt4?j[ |K8X{(chvnHy9?$٭J(ͨ_Q(էKf6OY-˪*&@ #10%eSR%LܴW/$o(1롭ZUj-g!65t~iD':*Giߝ#m\ׯ}ΧR:^X9;=ŚeXc n;LǤuʥaYJdqecv{bȾaddEْ*7٤p ?P]/0ge5( η.ӃBr\vA (=qSIKkDwW*O'wm`ym,/WU㭖\~2{0oN5m؃~*(Gh`-e*p +4;/`҈],fZhq qW˗.R /_aBO WkDb_jC!v8 bmsqs ei[pRܐ[q2_ɞ~$g+e0eJի?tn!#ڢ ޅNQO ȁ.t5S$ޗN5*]v8xj5%g\{uj ]7`g~kh,Q4,UZ>s'h1H=0# .hGIxu4-]sdH+قd3I*Y8Y%=.fˠc3nŮ(^W*ҧ9㑽)fxϳ,A=bGG`mɷ"*;4ci^UN=-C A-D^YEy-Ֆ*htu4.cFsWЏePbJL&r$Z ~>qG=_#!|{UK#2\6iq Ez4ưE )gi1&Hd.r>]Qm΃x@3%5kj(K\@=]ors:R9#%({/R*pVf0'ͬ0-(, b4L׮h(71ʭOQ)zT*~ z< p:;}." mp?DV N$eNc~9鮛J'3{jJ=oWg-ZlT/qv[w`u!o‡ƄTքJ8I 8~4&3BskKi,^DM;6n CU{ii-%:ŃsڲEs0Ѿ L@^k\4[P6hccd$nAmܸ6PWU+G$Q5\ &k?pywt\$P움7ƺ&Vfgs\G>z Հ-8:8}P^8ܣ o}67b0V펒:G.'t!CP-gD#Uܞe.=(_m$"#~cĶ,r6Kx6Zy qdr2iqxlWp3TO{Q+Ѭ͛. \~a~5n@@ҜmO8yShV%EŸyUxZĉ 34(3ui>խ+ %!@M6'8WmMk%S%ξ5YH4( pT?w6huZZ7t9bUcw) >Ȥ.Ț7+Bs^̗™ͤeLN4jsO puP˜2kdG~&vd*W(z6cQѲfk8Q#j Bs@nJ,sVSHL XS1/6:ZD{93;,^]PZdZKk6Er`9n{!=VayP|!Vg7jy)g# JqGb^d;S$jO䱚ΆAsuvu9^EOC.- b~r?VLR7P L~%Y%\-i|+ՔTba4:PSkмܽ3xېm{0{t^=IbM.7 PT ߾ir yuw9RSI"ru<_{%)ɁQ-]$Q礌7UiA@S?~M0wŖ|2dfbpS;h/v^f`+_DWb^Z^rȈ9G@b'>Uq sʼnx[f G,ID/-+ԥX*t!E?r@FF+ߣfE\w+;F|iAh _)te0pCb_[ھ[ X̐D01 >SynKn%*HY0c}Y\{Y8Y\mvD4OX`ك`[ZQd '-h3+P&5z 8b$gהbuq^GSfSpbuG*s٢K0*E7Ed>'T @pN|7CުUL::+!O/8U~g> H5iDpsEnm:)M;Fj NgD˭ # ;}kb)?( [5n];w:'BSDoY>XP'~b$gR.AnrtZ4?f1l;CB4f y)7 Jt<@7SlF1FߟJ< N,=)*Q$rȴѐ] ->>SA'̼h5wa jEi)]D[S0Ff`p+`$UYBƩGFd<15xl 8M Kf0c_R_oD.qNm+;?G11SGDۦ4ҫҽ +:]9 @YJC"MZ,$K}{Aּ\f[[=Y;,sbݒ U#2De _|/,vKS4t[ZDn5o]2K{lޞ&dT5PRy x⡇]"IYqH7GTbH*9tlWM|,P9,^4ZoЕ<`5+ ) 62t*,4$A w7w:k@(AM }ģok tg\l?C,i3v]blKCyJjX(NVjLUt!ьuNml,җ"+Kje:T?b? Tf L6v$m$hN^'~Nr4[-5w3X8e; 1{]HpGмПhpʯW0ToMaݭ{p1S7o-19J>B?[fǎ]ڻ>tb6 V}SN5>GIJxmL3z'/,('*XIiZyFWkUR_2:}!hߢn  S].&lSƇ)IӪhk_Ý6G-kʥE;e j1oIǿ3QLF#~ 5":_xuZ9^^3cKMvqW@;Payc/8?\ߏ|@I“N-\"#2%yń*QhE5(;7C70k=yܴ { 'b6YD L@0]iӕrJSm̖UE§H`TV+4,\őlg/1e88pGZQ"|,#<ۖ aH%mi_0رx>5*Xά#3FVyAmW sQ%@^H|*b>4}mU߱ɵ@z2\qW{4>j00Wi(\)qW5!AU7$[mY0I_gZ, %tlןK٤ ϖvhݩ!䪺,2mV.jJFNKpr.VߧTt|?e0(+: `*/Y#S<_"L۱#jHaJ礍?[ MNH!*Gnii:yaDbFa߾UzXR9^o2Z)O4BB-_7mU-'OظҖMF\(͖8 O/zx+pCz;w}G{{yF͝w*p.cY9ultmM._?o9Q?ǘH˙pW:^oXm޾4X~6[(C"y՗saC#&C8! l,AbGsO=j'hg zB])pǧoŽ#~Æ(~\`kWRd1'%yč>լ\l3K!s7UG^ށQ'.?=eg jpv _wYř5s +HϝվR[eWZ,K<떱3ׁg3ɳHe^Ss*'x{4&8Qbg'{ܖ2{LxA[ClMQ`Á:~v/^/7I1cK'=lI@zs}[*E{i,M#>$)`[T3N;\~׼1o\X@d)E4 W磫6Um^Rf' ߅spoO_`1H)ĨCI4TaDAlgpێ0חIHX ٠+?zְ8 l_b?dxLia_dg idz0ry_7)İLiXz~%I_ j9RWґT)yZW8nW;MRbhc35\x%}?hPT%cԦ'!WKߕ΁ rc6TR?MũU*ok]?x ^쐪E@z> stream U 3B,I@9 endstream endobj 727 0 obj 21 endobj 728 0 obj << /Type /Font /Subtype /Type0 /BaseFont /EAAAAC+LiberationSansNarrow-Bold /Encoding /Identity-H /ToUnicode 729 0 R /DescendantFonts [730 0 R] >> endobj 730 0 obj << /Type /Font /BaseFont /EAAAAC+LiberationSansNarrow-Bold /CIDToGIDMap /Identity /Subtype /CIDFontType2 /CIDSystemInfo << /Registry (%;C") /Ordering () /Supplement 0 >> /FontDescriptor 723 0 R /DW 0 /W [ 0 [228 228 272 456 546 456 456 456 500 272 228 456 546 729 456 318 456 683 456 500 500 500 228 500 456 500 500 456 456 591 456 773 456 456 591 591 500 500 272 272 456 591 410 591 500 638 228 546 500 228 546 228 591 638 456 591 591 456 ] ] >> endobj 729 0 obj << /Length 731 0 R /Filter /FlateDecode >> stream dPX`4 (+[8*@MDtJ'y0 E0 t3S#rBjW'[@* Bƛ@/gYteSi'akBqև ]\*^>{jiF @1_Z=В @[Z t$u$N2i_dޥdS\k +3GɆM~7☇0US֌"p'r)+TBqWݕ\PT2mO`J , wB2K|"V/d'|'Z,NȕӾ,7lboI+[wL1L³cM#w tcWlswBQ{/4,͉ UG . ŘZ|ԾRS}+y PbӍjc h'Ph&Ǻ2i[3P,k,ˬ?V`#(AYU_M endstream endobj 731 0 obj 477 endobj 732 0 obj << /Type /FontDescriptor /FontName /EAAAAD+LiberationMono /FontBBox [-481 -300 742 980] /Flags 35 /CapHeight 658 /Ascent 980 /Descent -300 /ItalicAngle 0 /StemV 0 /MissingWidth 500 /FontFile2 733 0 R /CIDSet 734 0 R >> endobj 733 0 obj << /Length1 20968 /Length 735 0 R /Filter /FlateDecode >> stream H#|@Ixb0+I4,;8L' U] EBÜgԔ 0=> 'I2hk?1)yMc0q\mwum5vvuD1:kn}\7.l3X#S}ٖ!XJғ9..jBl?vNz}(f4?b8c ٱ@pʉ1i؛F]a5_hOR,9]lw١z~4{pj_&Oc2Le Z9D8j.zx h.! :Pa21 mdݭ)GPs8byi:j\4, kbE(rŦxrc"1؋"u(T+ثz ]Z$|'K4'%ϿBe<#Z94JW3٘xʃCP|MTBK̚ DZy©PLT"Yi$*^ 㽯ְ;OF$;$䋒2c [1:B8(>` ۄG|f%Wbo=S{e~F6 -tV{7[|g_ٝӟZo 3䛇<,ӽmA E`kZY`.D_M^8R@/F DC.#-݇%T7qu)"(oyr)FW0:Ә:aGEc 0 fפ{i36 .`Pפ4Sy;z4 4>"HyBJ=U/'!=+&!2~~O_\w1m*hGQ<}CrnZCϜ~б\IBSJәt;η4Hccr5[œ۱$g㫟;5TX"q۲FN&}ԕٜ Pd<1?[EfFm,$( b4Di%#PrKی X1Xj)NH?yDD!Jt{=3Hw54~0巕E2 ^*;Ŀ5KP,v>CYʙ-" ?`LD\a0uJ] rS*]u 'cF2ӗe[ Ӹ."@다Y?*]3WG;o4̞ެHglMt`>E)Hm)*թiU3M PhsEx 978o"M_aYabw5ϙD-0/ VH}0 ol%9)VH,sd /|=G^(Fu6brcReP th{?an0tj+xI$οS<-IYxZ䨄lb)]]G3y0j}۴~IB UDCs>#`KE0 BLn ՜D %C^tFb+_Dn:THC(?+Vx$9U2Q9>i GI%.p ~/fݙw_Pp܇vZ:+;@ԩ§uD؄AiCϨfӪp-SfXflap-:l^{7iw5bXໃQ?,xX`x\GUmZ{[I1~7C=G &F-JBRϐG?+ R9{CbT^-y=偌2_Ylubvk||KNpml"ؘ_\?`o+Z!JMgg&ZNs%B0l>j5_ٞg_LUck$,&(Ǟ̏ΧmP鵆ʡMbxnhrl,H|TL# ` 0b2ƁU aKO2O,ZHL *FJaePL$;QQa)m 7uL.hu@9ߕL )4O3p~Gkq!ʞ#?p!6*6\ڇr'mMdpbޝtŮ_č%!ޠiƈ3O7.?Jyq*] $)!+cs+ 4#d zZ!aW .q.Xa)qĨh28.fHϝ$ןR"q|c~ƌz, ^60OcװBk9x83_e^rMJipRPJc\}&(,L.Ը "őg'ة :f8Qøxc$8\GhƙIJ0e,;V2N-ں.0HqD߮>4@i@+/X0 -xYv ԥ2X_Ԇأlϩ = wH8 Tߒv{\Y)ħpD"L)k/oޛ\B(.b(faMX#cn`\.EA>azؼ"f71Ճ0|u9 (!7z5E3ې -lͽ﨎YF0%]?{  t '+Ük rsP,(^̻ͤ6E0q1B.q`h}ĿmD"k;.y_^p gwdm/kWOюe%)BzAwwSIdOuNlHsBC>=8-@'XK6eX%s|FTDEo' L9I6ӕ+ˑT_R#lC]?x?ջӸmBmE8/IcϢ%ҷ@1QF_ DL(Jl>n mlH.l"k^냎Qp KaA7L:+!wD<3H)@u T0?Χ30j>9H )wCʂ)74D#6(8뛌sD01,r'.Ž#)Z@oXF!mP^%+Nl9MgяNis{BNj ;$=傲dƽ-t@SsuYvGJ~s~{{U?3$dod!~Ob,yܫ-S4Tk*TALh$G5<)5-]^ðjf֪p>XK(eXɼeT\cdW7kʜz%B"j5h!bŨ9DΠ+5$v-]-@dD!2֡ HHccdrK:p'^)k F\ N8jxevk0*)$]НgxFת9shzԲ.DŽNc.iDV~@[Ȱ Pl⌳ 0^ 7+G *V)5xc5y!x[6S.Ӹg>J0<>xyt\9!ɮzjgl9%S.1 |GQ*v6`Ru䢵ly" WE*^ !3 ?Ygy-ȋW lT_l/i\RT[YFRg#x?\9;2bWij̨xg|-LY+hm`_GGsan"ܹC$)AJf~ Qܪ>,[$MzvNʀ3K&/@tq}g 0v@,䍴tUm3$5Y jNրeuvrИ#NNDj0'X* 'huTݯ6]hMgM ԚɃ97Y`I31gfؠZ{#4K_u(\UIXe A$yQ%p IKFUQ!%|ZJW̿Sǒ+_^q`H܂tɚ|Q (ם!x 'JͰil/aJ[,ґw>+>{ڋ2;O|Bs'Ix&/7'P2G >͍t{##=.1W)iƖFa %O T^ɳ ۼAeqQ=g2mŃl@JO{5S:?m_hÞTi9S]±1CAoFX9I,3ZؕmRk*+^D'`|Gkґ/#Nzͼ4E|X6i¨œK&z?uumW1O965ݭ4W{ oY̟N;)nl'k2*uT:CQl9Nxv_r{wOx/E'P ovl7tP4tu`\R}aO{XXR_yIipzyO/dA V!js#9~[sTJ:n(94[LagEQq&ي؍AK52=!@;fQPIkDSP> PĈ} :8j̩/vzY,1\nZ7 c-U k.H,5b0ZwG!J,~;h`Gǣ5̂f 159YdQdp3PZn d韗<&9y+*A2QQ㕋{9uǶ%i\,Q}wƬGlC mo]ܙJ&%;2C\=]|Z:}UPм2ܪĬnAxZ<$FgO1dZP5%'\UGҫA[L}ܬ*.kJŞᅑ{Q e̐7I? f_esb)fڃGiAgʄJޒr- ka +k ƙp \=] y誶՗ϴK'g"A,,T_M2 _}'(cŃ.ľfi6D(H2ȸ,v_i,:U4.'Qfo>j,O!pycyPr;5}Y7 9 j"76<׍qH&?7X[>/"8d0ȼ:xeam SfUM%Y+LW%*^о Vz$2>.Jwv;(1 58u8غ~TB8v\lE1QPNt;`~YEWi 0DC$R8(Lb)o(>jLyK +qEyn^$Db;{`CxV?Vm4nԻ2o#2l54ƨWyid32s)vIvBM [L%EB)ިi RT*R$o 5v^\6L=bbRaV"Eb=Zlqj~ Q$5fNVڸh}cEmn1 NkbX"JPE<\>, qbUEscd}rَ<^!ӉdZJ.:;b i^* s׮< >4d@B[-YB;ua9Z#m>\|Iv"kXE [3nx54C1RM+u#'Tc|m~/An^LQL:/P*T7LIdP3w k&fNI,[}&_UKsN|j]:PZxdz [YIr^H0'NУ p"P3EEMcg[3]ܥ꒗d7k/eF;}p #HbE@_?VMLmZK tU_~c1o}e,%f-J`Xx³5*RɆ8p|'L¸)4$ QOQlI~(v @- K}*P&r2xCrjrߦ(W^ך,F`/`;gP ӑY?6;Qxk D]C7p5ŋ 6e>bygdPŭTϯv9e,CTڗ+9L7WH)v iE fzcCF˙>S1_:F{>HYM}BC=$y M01_N.}_zԻvױ4>@B ׯ .˽,Wj@4oDBJfʢlV}eN2 (,lHy)%` V>V,n qFb/d 7ňC2*Nc;`g8==g'?-pjsLJlLZ6υqM!'mqqyDUb@s>@n і)>@ƀEl߅SIh&[69^+h#^VQY Ky:6Q4d*VD\$3G2Tk~*]I#b vVDlfAXn^RI5g cF wk* kiw^K0*"ĆOnX+*+EQQpRvvqDEsNnSc1jKuئDpn7{-SmpNG 4 5M$R5p&@b:M{ H~`8Z8pR1_[6InS%pH@87]^y͓Nۗ)|y@rhf_STJXq( ԑ:򔇉v_CuuEv蚗QM18d^DήUv{WUܖy Ms͝hXOI53`i E "yL. knP!QRBpZ8 # Hwycy֩dK`شfF&jc#QM$%vH,rٴ^.֊e@b\xrzw\V- 06FV*45X~R)_ n''˦%g5V_{}(W;b)E.D*`ƮW_Uzo7 4H H:F vݽhb*el i.}$vT7L=Nq>n8zkXV[5ljbe!NԵ۩h DYVYhjD;)܌xaLW_ChdN0zJ|c| ՅTc9f[: 2HZ囋j)J _2C1CYrFՙ2vUgeD;ɕ%>{W*A"'%(+b_S9ߊrC'NbթRL1tKÞs32SiR7?.MժnmjY *} 3;4JakĶU0iD.4#[@̀d XGΩ&𫀣֧ނ>\C\P˔>~&x]/dw}6 /*a@hZ fԑFoDޅ;v{99Uk7S%5CoB=n?y@nE,iÆ0y-N  K"MQO4ӉXPO5|VBIO13 g12#Jc,R#kLoߚ5ej +l뼉n |FԼvIl_2uZ_z}Ha#u4x{aG9@18H]CxKa;;΋2|\E.!d/֢ +gf}:&yX|Jy2v+PAMֽ4,a zRPڈ/v,XMݗ9{ ]FJ&][>gG4M şC~byRJs8U5PjQG>Q($]*Y#c͘,]$('Бph*V؅>p.igێΈP@]ihSm <5ˀyȒr{/͋wxp+Aucex/diˆ-\M!}[HL1ZLQȰ F%zxEFeKW'W'н?]Yw]64=˸B6pJ@=0VWE8B%+,I']*+e4-P j'OӄOEఔמs>sTCJOS1cB?,׎(%&,f׾X{HG bvfG:b"' W-;V̲p3$B=U1ePm^FĔ'Biw$W|ZOY%l,ܕ<-m.!1;q`!UgM#إ? QܛsR Z"Iᰱ|4.89vhc&$o7-dtJrON*j(UkOJ^4C.ZQsx!D F\/x/Pi^<1"sb鋿ñmO=SKuI|09X>gܡ>kee-|{>7z*6gNP;aA%_*Ab̒920u3l;ChkU[GZ}iwuEdct]G%%K%qWi^O[X>Wi>j%Wߤ» O p ќ)N ZH"[H`+y9eTFJZIe]?LEsRP;G -b,aT@E'=(pʂYVҊf)( k%&4CiߊUe;='mqKfPS%= zǞ&xyDQ?=< 7QUP(Lx9XGtNEs12pnEzQ{ۼA/St)͘`Q]6!S6wpiӻ[zV.0Xf72.+~*kFiDSRFWw3S(IƢ۝\%;Pk-}~L;fhS-Z[^Cq`M nh{Ѩ ߹mצP P%˄C -W*EX1[Sn[W!H5Au1DĨ`'HK88 򔡖7P|+M64~(X-5:*[CjQj@ت?l [HakNR~ {Vk@3 QK/ ?FeO"d6] -0woi/ 6X3Ut;]W f* G?$|3\GJKnsx>"',i<_mى4("ҡ9iL^ue+Y8ofwv*bl؛>$ (*T\DbT˟-MAʹkItת=U9c4)l;Q8ܪ7֬^wj&߸翕fm-L;,*QA+]6rwO֠( 5H]D22I{vR|;8^TdID};2[؂J A;AN=p ~ ?AܸnaaZ4+^ W_SgKwRk ytU$s+8'ݱ̼[oZkZ4U#W/8J+7$K8*ȶkiђF'M_IFG% rg[OewxWVrzfBjgACWغ84Av)ДKr/Ic?'w GBg>oy"8C} .xm*3:vL^|o&SbK>@z3?RJK0;[a8A;7;|5b)_Qan_o/~]IE(s>1l=%E?26EGl "! %[{|a> stream 7>2VfV7A; endstream endobj 736 0 obj 17 endobj 737 0 obj << /Type /Font /Subtype /Type0 /BaseFont /EAAAAD+LiberationMono /Encoding /Identity-H /ToUnicode 738 0 R /DescendantFonts [739 0 R] >> endobj 739 0 obj << /Type /Font /BaseFont /EAAAAD+LiberationMono /CIDToGIDMap /Identity /Subtype /CIDFontType2 /CIDSystemInfo << /Registry (u\\A) /Ordering (a\\-) /Supplement 0 >> /FontDescriptor 732 0 R /DW 0 /W [ 0 [600 600 600 600 600 600 600 600 600 600 600 600 600 600 600 600 600 600 600 600 600 600 600 600 600 600 600 600 600 600 600 600 600 600 600 600 600 600 600 600 600 600 600 600 600 600 600 600 600 600 600 600 600 600 600 600 600 600 600 600 600 600 600 600 600 600 600 600 600 600 600 600 600 600 600 600 600 600 600 600 600 600 600 600 600 600 600 600 600 600 600 600 600 ] ] >> endobj 738 0 obj << /Length 740 0 R /Filter /FlateDecode >> stream Aհշ#-K,oLZly2yzM1:L=r/:f: AH{Qi+YbLkylz#~ 0׭^% 01Yx=zӻ 5m>f]B«J9f[S 3dV",I$^ 7nzkBE{^ :Gc[v=ҳ6H/b٬Qj`i4R)@"J_ن=W@uc(c&g?̹#BŮ N\&amW\_pn%iGL6ߚ{W~nՃ#ξ _"bNww_̪D_l5zme$s̋@ p6;*@шˀTaN%$QBœie/Fޮ*ƕ8r13WGvɰWb׆C mSi?+ߋHɔTjrԟr4@p1YHp}ElRlVeGϯ&>*xDR2!1S~>D k endstream endobj 740 0 obj 626 endobj 741 0 obj << /Type /FontDescriptor /FontName /EAAAAE+LiberationMono-Bold /FontBBox [-481 -376 696 988] /Flags 35 /CapHeight 658 /Ascent 988 /Descent -376 /ItalicAngle 0 /StemV 0 /MissingWidth 500 /FontFile2 742 0 R /CIDSet 743 0 R >> endobj 742 0 obj << /Length1 9920 /Length 744 0 R /Filter /FlateDecode >> stream WNt[~pC wzj #щ(0gPnl|yb/~l mpWX"3pV3>(5 _t?]l3^R“ "#Sy; Dl74\B:- DA?M{Ӵ|32}üLLXO~ȕ@m~$&{ڊߋѡ!=<BZ&br8U<[:]rS::WMru-ڞϢhV3KzJ7N}ʵ/?R^Bk@JGGoo3#`W4-TۻϗH_ڒMRzR >H{83*f5OJ_Fb.%V|(剪(;WRyـeQ5禡RC:;8Iqd_-CF C2PY%eVfj#L,N*R9GlBlno;/k@1<HKSыbO (ҬZ`Z[tлoh,2Y$u;i"äJA^?,pe#Qߵ3FY 3Ptnw5\,gԏlIz& SYц{,"AQ(R1|ҁ 63ev4V5=WIVvcB]cx|4Nb<0Kʓ@'TH"5V'~l]-TPy|_c 7qZ':aK [ؔ:$ˇD4-qb*>G bAmC"Na1Z AhynGn)n]eb.=/,+pX)hsN(SG>zB+Z6`6)6_bQ7t_Z,%E;[$iLFdbg lKdT-'j399Idќ b\}n *YKvyS I\:)@#8U˙gf쇴Cd aE:hc-( VTQ67\Cr}%/ ~BK~ ν`0^'O>kqCZdC%ׄSHىir3|}]oSqt)>Q, pe,IYl*KMu.Ɣ>\ bY Z^lG֫"N hb>qtGfNumKMӦ܃,;k>)E`3/ˌp&"B`(t⋓tdU]`-ŪE';RĴl/#RJ5hwelIH:Y8S -abjdTgJ@:Et`ڧ>q1L2E:DIGDi)-C &"̟KU3pvm&V!Ɔ Tc>a6`{B|CH<: `G ㉜f^[9EƺM}? 8,Aҿ*7F˧D-!m4zSP.oRj5* SK7+d䳌M{M316X _4%iFUOX}1~m_~;Ӡ(-Vo%*˄J-bB?o苬ll,ͮe_ W!j3 Js.YU-͐6rY{RYnfԪԯ+PQk ֘|]ŏMg,C٘Oyf:;A`^V; b]C.NvPSb|kߤ:9ݤ`<9vY`y$X KQ(9?woӨ=ےDD.kx>_&d΍..c 6hbdH̙:6w"W\ @8%jiX^iGyq/I3ʴDO?e9zJy'ҒKDX+X5'O >jj-s=b?Ȱ# +LH:f~I"*4J|0Tl[OTSٲrV _->s=_|CF-]uϏ uyڌWfЫ wO̷H;zto8([9~_T1ӣ`&¹d3gmL47~ŻJ5Z/|H("pu?" |z[?U!T!6faAlx1S4\Xߠ)"1 Y[ƄaC фk3tdb➖ɬl^z t5.#A)|G~t+bB;A<2oU5 hn 1@Rٝ Qyw2WlH{d<]Blq<Sjj 90=u'AQu3L@KF[V~&F9sl0}G]n XP31`j젮7gs6p${T}/Gq1Cst&/briCR^~[m\Kl _[N\4#/?Zixh2C_J08]\(f]׫Mgo]b]}([j@cWci$Ɖ.4[p)t&.B֓ow{]/u3o\z$Jw9eE sF`ܥlO[/o`i>NMD}O CeCdAލxP6kBd"5#H:C/eY6vpEuኲ~J:7>y4Wh*RcE͎5̧sޱ bf`* b {ZTC;m[?cڮr,?^R߹*têFn?xzY[W8.VIvRtr]93Ԣ(dž(D,eSMLDPVSBcS7`W1Vz$ui2g?.3_&!%&iaxw{1;ƂĉN`n'h&X[6 1P9DҦ'EJ'cwPn.C[zMUV^ 1Q޵=FU|cm_h8WQ,VL2fC~\`Upr: cw{9p@*MmP{Dm14]%tJ% (|VЂR.y*ҫd!"'PZΨG %=Pu"T(eoek+H^XB@(zV9]XnN8UCgwj][Nzd<-Fӛ.s:J" }JݔAl0|>rp'-YИޓ)m5ghghk%Y+TZ=WZ Lk۱޷р,ٛ/ L9H9; h;֩-a B#W!e/,`0'/b_(O(RTWZO-Wj{* 3q0N,^{\}!Ul@3=hXd{d ȺXuV\S(jd &X(.0ġ@n=QU~ztMX*+Ejp+@ MXoO PKϚH+ِS'r=QgQ;q36Ŋv!Id͝K R@%gxC&ObAn3B Xj"GQYGܧWMPG@҄?r3rN <W9;q0P]͟gy5H|9@[ȼNBrio;`$ENKŻ擜Vf*d^@LB;42vpcף罛&,-$Z=96Ϳ'0JDY8hvh@tdsv9Un h ۈ 2~ВIRO`B-v#ͭ&#]t<)J 3\"0#nb{ 4gu#ʯO .F5<֨&3H׎snGƆV)%2ߪ^VOۻ)!oՌTRMø)4Ztpnm Vu`E/jSb'|D.VoY啎Bv Mȅ!v,7!9w#>6&y&Y "vV̷6JQ5ԍm飶rBC(X.9'b%`f48T]?*`> _8Ӎ\bS D8J\63 l‡o2Kyxbhm5 (qgUxqr)Y q QX8:-ډSacU[N,v~!'87GX$H {WBĶ3PHx$vJt1# m c;lO(S[`]식:whX> {?~::X1h\epl|hFKIKіlj܆ ]\-z ,ᓵ58? #'1A(s4 Q 9Oab+@+Ɣv>7rr;xP(Fq6N!O"g OWت#tY1PGL4yT7g _(G U Ò\` >;k zyǩoʑr7?{ 3(eοիD$1#{6bzY ӕqj,NӦ%L:Pmж4J$@+;l1w?UlZff.8TvVay@"q!xkZk>NwfRk_f"+Od2}5ym3Fh:#Nìfc}D ,ԢuL_0zlr2Ă0oyk!/Ȋ8o Kxq}=5x]wEGmIBKUʫQP!#RSa's@3 IQ5|T9*(5~{C5|zc>l\E JqP>jV&w[׸C4q ^6(c[oþ=ogꑾg3j>eW ٹ&;p vxŮ/>[If߆^Q%xe(0 dz%a.Tb/2 폄bs4aK~;$r=lT'i"8li\S`|˚ըm^,yb?b`k6u6OBCJ coQhPOsq~.yxJQ*9M ֙1ɹX16.E9>ԥH*l ׭1KRe2;f&՛;[a.ry* IwG_AI̩8e@g"8eT*6a= { endstream endobj 744 0 obj 6282 endobj 743 0 obj << /Length 745 0 R /Filter /FlateDecode >> stream 5L/I3ܖG endstream endobj 745 0 obj 17 endobj 746 0 obj << /Type /Font /Subtype /Type0 /BaseFont /EAAAAE+LiberationMono-Bold /Encoding /Identity-H /ToUnicode 747 0 R /DescendantFonts [748 0 R] >> endobj 748 0 obj << /Type /Font /BaseFont /EAAAAE+LiberationMono-Bold /CIDToGIDMap /Identity /Subtype /CIDFontType2 /CIDSystemInfo << /Registry (vAYy) /Ordering (bAe) /Supplement 0 >> /FontDescriptor 741 0 R /DW 0 /W [ 0 [600 600 600 600 600 600 600 600 600 600 600 600 600 600 600 600 ] ] >> endobj 747 0 obj << /Length 749 0 R /Filter /FlateDecode >> stream q6' ڙV4TR{6X ]*<.p3Ě!s!fn)':Mq/id׮fJ+=NX]8^[}'3Xp12=>dH[H{i_O29ɌCݟE@fӼ&e9;$Qv+o$֦A,.D"4eKL\%0zEtgW;VT+1\FO*SË8c3ѥRq&r۳"IHτfԝ-eCLm@?7 & endstream endobj 749 0 obj 297 endobj 17 0 obj << /Type /Pages /Count 60 /Kids [15 0 R 20 0 R 409 0 R 704 0 R 35 0 R 38 0 R 241 0 R 450 0 R 50 0 R 53 0 R 196 0 R 480 0 R 56 0 R 67 0 R 70 0 R 76 0 R 83 0 R 92 0 R 98 0 R 104 0 R 107 0 R 113 0 R 125 0 R 131 0 R 268 0 R 137 0 R 143 0 R 149 0 R 152 0 R 155 0 R 161 0 R 163 0 R 204 0 R 213 0 R 221 0 R 224 0 R 230 0 R 232 0 R 264 0 R 267 0 R 279 0 R 412 0 R 429 0 R 439 0 R 449 0 R 483 0 R 486 0 R 498 0 R 512 0 R 515 0 R 522 0 R 536 0 R 546 0 R 570 0 R 578 0 R 584 0 R 590 0 R 593 0 R 596 0 R 599 0 R ] >> endobj 750 0 obj << /Type /Catalog /Pages 17 0 R /Lang (s\\&6tÅvV0̤) /Metadata 5 0 R /PageLabels 751 0 R >> endobj 16 0 obj << /Font << /F52 710 0 R /F43 719 0 R /F44 728 0 R /F47 737 0 R /F48 746 0 R >> /ProcSet [/PDF /ImageB /ImageC /Text] /XObject << /Im1 7 0 R /Im2 9 0 R /Im3 11 0 R /Im4 21 0 R /Im5 23 0 R >> /ColorSpace << /DefaultRGB 4 0 R >> >> endobj 752 0 obj << /Filter /Standard /V 2 /R 3 /Length 128 /P -1036 /O <36451BD39D753B7C1D10922C28E6665AA4F3353FB0348B536893E3B1DB5C579B> /U >> endobj 751 0 obj << /Nums [0 << /S /D >> 2 << /S /D /St 3 >> 3 << /S /D /St 4 >> 4 << /S /D /St 5 >> 6 << /S /D /St 7 >> 7 << /S /D /St 8 >> 8 << /S /D /St 9 >> 10 << /S /D /St 11 >> 11 << /S /D /St 12 >> 12 << /S /D /St 13 >> 24 << /S /D /St 25 >> 25 << /S /D /St 26 >> 32 << /S /D /St 33 >> 38 << /S /D /St 39 >> 40 << /S /D /St 41 >> 41 << /S /D /St 42 >> 45 << /S /D /St 46 >>] >> endobj xref 0 753 0000000000 65535 f 0000000015 00000 n 0000000211 00000 n 0000002768 00000 n 0000002788 00000 n 0000002821 00000 n 0000003760 00000 n 0000003779 00000 n 0000087659 00000 n 0000087680 00000 n 0000134285 00000 n 0000134307 00000 n 0000178277 00000 n 0000178299 00000 n 0000179103 00000 n 0000179123 00000 n 0000518081 00000 n 0000517432 00000 n 0000179349 00000 n 0000182462 00000 n 0000182483 00000 n 0000182709 00000 n 0000183928 00000 n 0000183949 00000 n 0000185656 00000 n 0000185677 00000 n 0000185801 00000 n 0000185940 00000 n 0000186160 00000 n 0000186300 00000 n 0000186440 00000 n 0000186660 00000 n 0000186800 00000 n 0000189356 00000 n 0000189377 00000 n 0000189425 00000 n 0000189668 00000 n 0000191137 00000 n 0000191158 00000 n 0000191384 00000 n 0000300126 00000 n 0000191524 00000 n 0000300209 00000 n 0000191663 00000 n 0000300292 00000 n 0000191803 00000 n 0000363705 00000 n 0000191942 00000 n 0000193564 00000 n 0000193585 00000 n 0000193633 00000 n 0000193876 00000 n 0000197679 00000 n 0000197700 00000 n 0000197926 00000 n 0000199734 00000 n 0000199755 00000 n 0000199981 00000 n 0000200121 00000 n 0000200260 00000 n 0000200400 00000 n 0000200539 00000 n 0000200679 00000 n 0000200819 00000 n 0000200958 00000 n 0000203178 00000 n 0000203199 00000 n 0000203268 00000 n 0000203511 00000 n 0000206582 00000 n 0000206603 00000 n 0000206829 00000 n 0000206969 00000 n 0000207108 00000 n 0000209001 00000 n 0000209022 00000 n 0000209049 00000 n 0000209292 00000 n 0000209396 00000 n 0000209536 00000 n 0000209674 00000 n 0000214127 00000 n 0000214148 00000 n 0000214182 00000 n 0000214425 00000 n 0000214557 00000 n 0000214697 00000 n 0000214835 00000 n 0000215085 00000 n 0000215225 00000 n 0000218680 00000 n 0000218701 00000 n 0000218742 00000 n 0000218985 00000 n 0000219261 00000 n 0000219401 00000 n 0000222429 00000 n 0000222450 00000 n 0000222477 00000 n 0000222720 00000 n 0000222862 00000 n 0000223003 00000 n 0000225850 00000 n 0000225872 00000 n 0000225901 00000 n 0000226147 00000 n 0000228845 00000 n 0000228867 00000 n 0000229095 00000 n 0000229238 00000 n 0000229378 00000 n 0000232300 00000 n 0000232322 00000 n 0000232351 00000 n 0000232597 00000 n 0000232842 00000 n 0000232982 00000 n 0000233107 00000 n 0000233248 00000 n 0000233433 00000 n 0000233575 00000 n 0000233684 00000 n 0000233826 00000 n 0000236866 00000 n 0000236888 00000 n 0000236941 00000 n 0000237187 00000 n 0000237330 00000 n 0000237470 00000 n 0000240385 00000 n 0000240407 00000 n 0000240436 00000 n 0000240682 00000 n 0000240825 00000 n 0000240966 00000 n 0000243745 00000 n 0000243767 00000 n 0000243796 00000 n 0000244042 00000 n 0000244185 00000 n 0000244327 00000 n 0000247774 00000 n 0000247796 00000 n 0000247825 00000 n 0000248071 00000 n 0000248214 00000 n 0000248356 00000 n 0000251486 00000 n 0000251508 00000 n 0000251537 00000 n 0000251783 00000 n 0000255156 00000 n 0000255178 00000 n 0000255406 00000 n 0000258359 00000 n 0000258381 00000 n 0000258609 00000 n 0000258752 00000 n 0000258894 00000 n 0000261844 00000 n 0000261866 00000 n 0000261895 00000 n 0000262141 00000 n 0000267135 00000 n 0000262225 00000 n 0000262366 00000 n 0000262481 00000 n 0000262621 00000 n 0000262750 00000 n 0000262891 00000 n 0000267068 00000 n 0000267090 00000 n 0000267381 00000 n 0000267464 00000 n 0000267604 00000 n 0000267686 00000 n 0000267826 00000 n 0000267910 00000 n 0000268050 00000 n 0000268134 00000 n 0000268274 00000 n 0000268416 00000 n 0000268499 00000 n 0000268639 00000 n 0000316449 00000 n 0000268779 00000 n 0000268863 00000 n 0000269003 00000 n 0000269087 00000 n 0000269227 00000 n 0000269311 00000 n 0000269451 00000 n 0000269593 00000 n 0000269733 00000 n 0000274443 00000 n 0000274465 00000 n 0000274582 00000 n 0000274828 00000 n 0000274951 00000 n 0000275091 00000 n 0000275222 00000 n 0000275361 00000 n 0000278299 00000 n 0000278321 00000 n 0000278358 00000 n 0000278604 00000 n 0000278729 00000 n 0000278869 00000 n 0000279000 00000 n 0000279141 00000 n 0000279282 00000 n 0000282603 00000 n 0000282625 00000 n 0000282670 00000 n 0000282916 00000 n 0000283247 00000 n 0000283388 00000 n 0000283531 00000 n 0000283673 00000 n 0000286441 00000 n 0000286463 00000 n 0000286500 00000 n 0000286746 00000 n 0000290425 00000 n 0000290447 00000 n 0000290675 00000 n 0000290818 00000 n 0000290960 00000 n 0000294920 00000 n 0000294942 00000 n 0000294971 00000 n 0000295217 00000 n 0000299880 00000 n 0000295301 00000 n 0000295441 00000 n 0000295525 00000 n 0000295666 00000 n 0000295779 00000 n 0000295918 00000 n 0000299813 00000 n 0000299835 00000 n 0000306798 00000 n 0000300375 00000 n 0000300515 00000 n 0000300655 00000 n 0000300795 00000 n 0000300879 00000 n 0000301019 00000 n 0000301159 00000 n 0000301299 00000 n 0000301439 00000 n 0000301579 00000 n 0000301719 00000 n 0000301859 00000 n 0000301999 00000 n 0000306667 00000 n 0000306689 00000 n 0000307044 00000 n 0000307184 00000 n 0000307315 00000 n 0000307457 00000 n 0000307599 00000 n 0000312116 00000 n 0000312138 00000 n 0000312183 00000 n 0000312429 00000 n 0000316199 00000 n 0000316221 00000 n 0000320160 00000 n 0000316533 00000 n 0000316615 00000 n 0000316756 00000 n 0000320109 00000 n 0000320131 00000 n 0000320406 00000 n 0000320549 00000 n 0000320691 00000 n 0000324223 00000 n 0000324245 00000 n 0000324274 00000 n 0000324520 00000 n 0000324603 00000 n 0000324743 00000 n 0000324885 00000 n 0000325027 00000 n 0000325110 00000 n 0000325250 00000 n 0000325392 00000 n 0000325534 00000 n 0000325617 00000 n 0000325755 00000 n 0000325895 00000 n 0000326035 00000 n 0000326118 00000 n 0000326258 00000 n 0000326400 00000 n 0000326542 00000 n 0000326624 00000 n 0000326763 00000 n 0000326904 00000 n 0000327045 00000 n 0000327128 00000 n 0000327268 00000 n 0000327410 00000 n 0000327552 00000 n 0000327636 00000 n 0000327776 00000 n 0000327918 00000 n 0000328060 00000 n 0000328143 00000 n 0000328283 00000 n 0000328424 00000 n 0000328566 00000 n 0000328649 00000 n 0000328789 00000 n 0000328931 00000 n 0000329072 00000 n 0000329156 00000 n 0000329296 00000 n 0000329438 00000 n 0000329579 00000 n 0000329662 00000 n 0000329802 00000 n 0000329944 00000 n 0000330085 00000 n 0000330168 00000 n 0000330308 00000 n 0000330450 00000 n 0000330591 00000 n 0000330674 00000 n 0000330813 00000 n 0000330954 00000 n 0000331094 00000 n 0000331177 00000 n 0000331317 00000 n 0000331459 00000 n 0000331600 00000 n 0000331683 00000 n 0000331822 00000 n 0000331963 00000 n 0000332103 00000 n 0000332186 00000 n 0000332326 00000 n 0000332468 00000 n 0000332609 00000 n 0000332692 00000 n 0000332831 00000 n 0000332972 00000 n 0000333112 00000 n 0000333195 00000 n 0000333335 00000 n 0000333477 00000 n 0000333618 00000 n 0000333757 00000 n 0000333898 00000 n 0000334038 00000 n 0000334178 00000 n 0000334320 00000 n 0000334461 00000 n 0000334601 00000 n 0000334743 00000 n 0000334884 00000 n 0000335024 00000 n 0000335166 00000 n 0000335307 00000 n 0000335447 00000 n 0000335589 00000 n 0000335730 00000 n 0000335870 00000 n 0000336012 00000 n 0000336153 00000 n 0000336293 00000 n 0000336433 00000 n 0000336574 00000 n 0000336714 00000 n 0000336856 00000 n 0000336997 00000 n 0000337135 00000 n 0000337275 00000 n 0000337414 00000 n 0000337554 00000 n 0000337696 00000 n 0000337837 00000 n 0000337921 00000 n 0000338060 00000 n 0000338201 00000 n 0000338341 00000 n 0000338425 00000 n 0000338565 00000 n 0000338706 00000 n 0000338847 00000 n 0000338987 00000 n 0000339129 00000 n 0000339270 00000 n 0000339410 00000 n 0000339552 00000 n 0000339693 00000 n 0000339833 00000 n 0000339975 00000 n 0000340116 00000 n 0000340256 00000 n 0000340396 00000 n 0000340537 00000 n 0000340620 00000 n 0000340759 00000 n 0000340900 00000 n 0000341040 00000 n 0000343774 00000 n 0000343796 00000 n 0000344657 00000 n 0000344903 00000 n 0000347973 00000 n 0000347995 00000 n 0000348223 00000 n 0000348470 00000 n 0000348610 00000 n 0000348735 00000 n 0000348877 00000 n 0000349018 00000 n 0000349275 00000 n 0000349417 00000 n 0000349536 00000 n 0000349678 00000 n 0000349821 00000 n 0000349962 00000 n 0000350183 00000 n 0000350324 00000 n 0000354062 00000 n 0000354084 00000 n 0000354161 00000 n 0000354407 00000 n 0000354554 00000 n 0000354695 00000 n 0000354838 00000 n 0000354980 00000 n 0000355133 00000 n 0000355273 00000 n 0000358715 00000 n 0000358737 00000 n 0000358782 00000 n 0000359028 00000 n 0000359165 00000 n 0000359306 00000 n 0000359429 00000 n 0000359570 00000 n 0000359853 00000 n 0000359995 00000 n 0000363392 00000 n 0000363414 00000 n 0000363459 00000 n 0000369270 00000 n 0000363788 00000 n 0000363928 00000 n 0000364068 00000 n 0000364208 00000 n 0000364348 00000 n 0000364432 00000 n 0000364572 00000 n 0000364656 00000 n 0000364796 00000 n 0000364936 00000 n 0000365076 00000 n 0000365160 00000 n 0000365300 00000 n 0000369155 00000 n 0000369177 00000 n 0000369516 00000 n 0000369656 00000 n 0000369796 00000 n 0000369936 00000 n 0000370076 00000 n 0000370218 00000 n 0000370358 00000 n 0000370498 00000 n 0000370638 00000 n 0000370778 00000 n 0000370918 00000 n 0000371058 00000 n 0000376199 00000 n 0000376221 00000 n 0000376330 00000 n 0000376576 00000 n 0000377309 00000 n 0000377330 00000 n 0000377558 00000 n 0000381177 00000 n 0000381199 00000 n 0000381427 00000 n 0000381570 00000 n 0000381712 00000 n 0000382005 00000 n 0000382146 00000 n 0000382289 00000 n 0000382430 00000 n 0000382551 00000 n 0000382693 00000 n 0000386794 00000 n 0000386816 00000 n 0000386869 00000 n 0000387115 00000 n 0000387226 00000 n 0000387367 00000 n 0000387454 00000 n 0000387595 00000 n 0000387896 00000 n 0000388038 00000 n 0000388181 00000 n 0000388322 00000 n 0000388583 00000 n 0000388725 00000 n 0000392454 00000 n 0000392476 00000 n 0000392537 00000 n 0000392783 00000 n 0000396367 00000 n 0000396389 00000 n 0000396617 00000 n 0000396759 00000 n 0000397058 00000 n 0000397199 00000 n 0000400918 00000 n 0000400940 00000 n 0000400977 00000 n 0000401223 00000 n 0000401328 00000 n 0000401470 00000 n 0000401717 00000 n 0000401859 00000 n 0000401948 00000 n 0000402089 00000 n 0000402236 00000 n 0000402378 00000 n 0000402451 00000 n 0000402593 00000 n 0000406414 00000 n 0000406436 00000 n 0000406497 00000 n 0000406743 00000 n 0000407030 00000 n 0000407172 00000 n 0000407457 00000 n 0000407598 00000 n 0000407853 00000 n 0000407994 00000 n 0000411010 00000 n 0000411032 00000 n 0000411077 00000 n 0000411323 00000 n 0000411478 00000 n 0000411620 00000 n 0000411767 00000 n 0000411909 00000 n 0000412078 00000 n 0000412219 00000 n 0000412390 00000 n 0000412531 00000 n 0000412668 00000 n 0000412810 00000 n 0000412950 00000 n 0000413079 00000 n 0000413219 00000 n 0000413516 00000 n 0000413657 00000 n 0000413804 00000 n 0000413946 00000 n 0000414086 00000 n 0000414201 00000 n 0000414343 00000 n 0000418711 00000 n 0000418733 00000 n 0000418842 00000 n 0000419088 00000 n 0000419217 00000 n 0000419359 00000 n 0000419488 00000 n 0000419630 00000 n 0000423128 00000 n 0000423150 00000 n 0000423187 00000 n 0000423433 00000 n 0000423580 00000 n 0000423720 00000 n 0000426120 00000 n 0000426142 00000 n 0000426171 00000 n 0000426417 00000 n 0000426504 00000 n 0000426646 00000 n 0000430462 00000 n 0000430484 00000 n 0000430513 00000 n 0000430759 00000 n 0000431502 00000 n 0000431523 00000 n 0000431751 00000 n 0000436322 00000 n 0000436344 00000 n 0000436572 00000 n 0000438667 00000 n 0000438689 00000 n 0000438917 00000 n 0000439057 00000 n 0000439199 00000 n 0000439340 00000 n 0000439480 00000 n 0000439620 00000 n 0000439761 00000 n 0000439900 00000 n 0000440041 00000 n 0000440181 00000 n 0000440265 00000 n 0000440405 00000 n 0000440547 00000 n 0000440688 00000 n 0000440771 00000 n 0000440910 00000 n 0000441051 00000 n 0000441191 00000 n 0000441275 00000 n 0000441415 00000 n 0000441557 00000 n 0000441698 00000 n 0000441782 00000 n 0000441921 00000 n 0000442062 00000 n 0000442202 00000 n 0000442286 00000 n 0000442426 00000 n 0000442568 00000 n 0000442709 00000 n 0000442793 00000 n 0000442933 00000 n 0000443075 00000 n 0000443216 00000 n 0000443300 00000 n 0000443440 00000 n 0000443582 00000 n 0000443723 00000 n 0000443807 00000 n 0000443947 00000 n 0000444089 00000 n 0000444230 00000 n 0000444314 00000 n 0000444454 00000 n 0000444596 00000 n 0000444737 00000 n 0000444821 00000 n 0000444961 00000 n 0000445102 00000 n 0000445243 00000 n 0000445327 00000 n 0000445467 00000 n 0000445609 00000 n 0000445750 00000 n 0000445834 00000 n 0000445973 00000 n 0000446114 00000 n 0000446254 00000 n 0000446337 00000 n 0000446477 00000 n 0000446618 00000 n 0000446759 00000 n 0000446843 00000 n 0000446982 00000 n 0000447123 00000 n 0000447263 00000 n 0000447347 00000 n 0000447487 00000 n 0000447629 00000 n 0000447770 00000 n 0000447854 00000 n 0000447994 00000 n 0000448136 00000 n 0000448277 00000 n 0000448361 00000 n 0000448501 00000 n 0000448643 00000 n 0000448784 00000 n 0000448868 00000 n 0000449008 00000 n 0000449150 00000 n 0000449291 00000 n 0000449375 00000 n 0000449515 00000 n 0000449657 00000 n 0000449798 00000 n 0000449882 00000 n 0000450022 00000 n 0000450164 00000 n 0000450305 00000 n 0000450389 00000 n 0000450529 00000 n 0000450671 00000 n 0000450812 00000 n 0000450896 00000 n 0000451036 00000 n 0000451178 00000 n 0000451319 00000 n 0000451403 00000 n 0000451544 00000 n 0000451686 00000 n 0000451827 00000 n 0000454307 00000 n 0000454329 00000 n 0000454974 00000 n 0000455220 00000 n 0000455477 00000 n 0000464378 00000 n 0000464356 00000 n 0000464490 00000 n 0000464510 00000 n 0000465180 00000 n 0000464668 00000 n 0000465790 00000 n 0000465811 00000 n 0000466078 00000 n 0000480057 00000 n 0000480034 00000 n 0000480162 00000 n 0000480182 00000 n 0000480929 00000 n 0000480352 00000 n 0000481590 00000 n 0000481611 00000 n 0000481885 00000 n 0000492298 00000 n 0000492275 00000 n 0000492397 00000 n 0000492417 00000 n 0000493074 00000 n 0000492592 00000 n 0000493629 00000 n 0000493650 00000 n 0000493910 00000 n 0000508160 00000 n 0000508137 00000 n 0000508255 00000 n 0000508275 00000 n 0000509052 00000 n 0000508439 00000 n 0000509756 00000 n 0000509777 00000 n 0000510042 00000 n 0000516444 00000 n 0000516422 00000 n 0000516539 00000 n 0000516559 00000 n 0000517036 00000 n 0000516728 00000 n 0000517411 00000 n 0000517953 00000 n 0000518567 00000 n 0000518355 00000 n trailer << /Root 750 0 R /Info 1 0 R /ID [ ] /Encrypt 752 0 R /Size 753 >> startxref 518952 %%EOF ntpd-1.1.2/docs/development/audits.md000064400000000000000000000002311046102023000156530ustar 00000000000000# Audits ## NLnet NGI Review Security Evaluation by Radically Open Security Date: 2023-04 \ Report: [download](../audits/report-ntpd-rs-v11-final.pdf) ntpd-1.1.2/docs/development/ca.md000064400000000000000000000135451046102023000147610ustar 00000000000000# Private CA and certificate !!! Danger Setting up your own CA is not recommended except for development purposes and setting up internal-only networks. For all other purposes, we would recommend to use a widely trusted CA for issueing certificates. See the [NTS guide](../guide/nts.md) for more information. Setting up NTS-KE when your server has no public domain name is still possible by creating your own certificate authority (CA). To setup a CA and the certificate for our server we will use the OpenSSL command line tools. They are available through most package managers as the `openssl` package. ## Root certificate We will start by generating a CA root key and certificate. To start, create a directory where we will store all our certificate data: ```sh mkdir "/path/to/some/ca-data" cd "/path/to/some/ca-data" ``` To generate the root key, use this OpenSSL command: ```sh openssl genrsa -des3 -out ca.key 2048 ``` This will ask for a password for the root key. It is recommended that you set one, as this will prevent others from directly using your CA key should it ever leak. However, for development purposes you may opt to omit a password by removing the `-des3` CLI flag. Once the key is generated, we can generate a CA root certificate by using this command: ```sh openssl req -x509 -new -nodes -key ca.key -sha256 -days 1825 -out ca.pem ``` Here, `-days` is the number of days that this certificate is valid, the value in the command here results in a validity of five years. OpenSSL will ask for several pieces of information during the setup of the root certificate. The ntpd-rs daemon does not impose particular requirements to the information in your root certificate, so feel free to leave things empty. Note that this command bases the certificate validity based on the current system time, so make sure that it is reasonably accurate. ## Server certificate Once our CA root is setup, we can continue generating the server key and certificate. First, we start by generating a private key for the server: ```sh openssl genrsa -out ntpd-rs.test.key 2048 ``` This time we omit the `-des3` CLI flag, so the private key is not protected with a password. The ntpd-rs daemon does not support password encrypted private keys, so we cannot password protect our private key. Once the private key is generated, we need to create a certificate signing request. We again can use openssl to do this for us: ```sh openssl req -new -key ntpd-rs.test.key -out ntpd-rs.test.csr ``` OpenSSL will once again ask for some information, but ntpd-rs once again does not impose any requirements on the information requested, so feel free to leave things empty once again. With the certificate signing request generated, we now only need a little bit of configuration to tell the CA root how the generated certificate will be used, to do this, create a file called `ntpd-rs.ext` with the following contents, replacing the `ntpd-rs.test` domain name with your own domain name. ```ini title="/path/to/some/ca-data/ntpd-rs.ext" authorityKeyIdentifier=keyid,issuer basicConstraints=CA:FALSE keyUsage = keyEncipherment subjectAltName = @alt_names [alt_names] DNS.1 = ntpd-rs.test ``` Note that the domain name does not actually have to exist, but it will be the domain name that clients somehow have to connect to (e.g. by setting an `/etc/hosts` entry). We now have enough information to generate a certificate: ```sh openssl x509 -req -in ntpd-rs.test.csr -CA ca.pem -CAkey ca.key -CAcreateserial -out ntpd-rs.test.crt -days 1825 -sha256 -extfile ntpd-rs.ext ``` The above command gives the certificate a period validity of 5 years. If a different lifetime is desired, change the number following the `-days` argument to the number of days the certificate should be valid. The generated certificate should be concattenated together with the CA certificate, as ntpd-rs needs the full certificate chain in order to operate. We can use a simple command to do this: ```sh cat ntpd-rs.test.crt ca.pem > ntpd-rs.test.chain.pem ``` ## Using the generated certificate We are now ready to configure the key exchange part of NTS with our generated certificate. Simply update your `/etc/ntpd-rs/ntp.toml` configuration with the following `[[nts-ke-server]]` section (or update an existing section): ```toml title="/etc/ntpd-rs/ntp.toml" # ... [[nts-ke-server]] listen = "[::]:4460" certificate-chain-path = "/path/to/some/ca-data/ntpd-rs.test.chain.pem" private-key-path = "/path/to/some/ca-data/ntpd-rs.test.key" # ... ``` Finally, restart your ntpd-rs daemon by running `systemctl restart ntpd-rs`. Your server should now be ready to handle NTS! !!! Danger When configured as above, it is important to ensure that the TLS private key can only be read by ntpdaemon and trusted system administrators. An attacker can use this key material to compromise all connections to clients. ## Client setup Once your server was setup, you will need to distribute the certificate authority root certificate to clients that will be using the NTS server. Note that you should only ever share the `ca.pem` file and never the `ca.key` file! In your client, now you will need to make sure that the domain name under which you reach the server is the same as the domain name for which you configured the server certificate. In our example above we used the domain name `ntpd-rs.test`. If we wanted the server to be able to reach itself, we can simply add a `/etc/hosts` entry for this, like such: ```txt title="/etc/hosts" hl_lines="3" ... 127.0.0.1 localhost 127.0.0.1 ntpd-rs.test ... ``` Now in your client configuration, you can setup a NTS source with our private CA root certificate: ```toml title="/etc/ntpd-rs/ntp.toml" # ... [[source]] mode = "nts" address = "ntpd-rs.test" certificate-authority = "/path/to/some/ca-data/ca.pem" # ... ``` Of course, if you are setting up another client, do not forget to copy the `ca.pem` file to that client! ntpd-1.1.2/docs/development/code-structure.md000064400000000000000000000141771046102023000173500ustar 00000000000000# Code structure This document gives a high-level overview of the structure of ntpd-rs. ## Crates ntpd-rs is split into several crates with three goals in mind: - Split the logic of protocol handling from the details around asynchronous network handling - Split custom servers needed purely for integration testing from the main codebase - Limit the scopes where we use unsafe code, ensuring that it is more straightforward to verify. The main `ntp-proto` and `ntpd` crates are setup such that neither contains any unsafe code. Unsafe code is limited to the `ntp-udp` and `ntp-clock` crates, which are purposefully kept small and only offer a safe API. ### ntp-proto The `ntp-proto` crate contains the main NTP protocol implementation. It implements: - Serialization and deserialization of the on-wire protocol. - Packet handling decision logic of the source. - Measurement logic of the source, including the per-source filtering. - Clock selection, combination and steering algorithms. This crate only implements the decision and processing logic. It does not perform the actual communication, nor does it do any of the handling needed to ensure that source and steering logic is regularly called. ### ntp-udp The `ntp-udp` crate provides an async interface to the Linux kernel's kernel-level network timestamping functionality. It wraps the system calls for configuring kernel-level timestamping and for retrieving the actual timestamps. Touching the network layer uses `libc` and is inherently unsafe. ### ntp-clock The `ntp-clock` crate wraps the system calls needed for controlling the system clock. Touching the system clock uses `libc` and is inherently unsafe. ### ntpd The `ntpd` crate contains the code for all three end-user binaries that our project produces. This includes - `ntp-daemon` (in `ntpd/src/daemon`) - `ntp-ctl` (in `ntpd/src/ctl.rs`) - `ntp-metrics-exporter` (in `ntpd/src/metrics`) Each of these should mostly contain the actual execution code that calls each of the previously mentioned crates when required. ### test-binaries The `test-binaries` crate contains several binaries that are useful for doing integration tests. This includes, among other things - A local test server that always replies with a `DENY` kiss code - A local test server that enforces a stricter-than-typical rate limit from the client. If you need an additional program to aid in (manual) integration testing, this is the crate to add it to. ## NTP daemon startup and operating sequence. This section provides a high-level overview of the operation of the ntp daemon, and how its various tasks are setup, configured and communicate. Upon startup, the daemon first parses any given command line arguments and uses these arguments to setup an initial logging system. This early setup of logging is done to ensure that during reading and parsing of the configuration files the logging system is available to expose information on errors. Immediately after, further configuration is read from file and used to generate the definitive logging system. At this point, the main configuration steps are completed, and the combined command line and file base configuration is used to setup at least these kinds of tasks: - The main clock steering task. - One source task per configured source (remote server). - One server task per configured interface on which to serve time. - One task for exposing state for observability. - One task for dynamic configuration changes. ### Source tasks The daemon runs a single source task per configured source. This task is responsible for managing the network connection with that specific source, sending the poll message to start a clock difference measurement, handling the response, and doing an initial filtering step over the measurements. The main loop of the source waits on 3 futures concurrently: - A timer, which triggers sending a new poll message. - The network socket, receiving a packet here triggers packet processing and measurement filtering. - A configuration channel, receiving configuration changes. Should any of these events happen, after handling it the source task then sends an updated version of the sections of its state needed for clock steering to the main clock steering task. ### Server task The daemon runs a single task per interface on which ntp packets are served (where the any (0.0.0.0) interface counts as a single interface). This task is responsible for managing the socket for that interface, reading messages and providing the proper server responses. The main loop of the server waits on 2 futures concurrently: - The network socket - A channel providing synchronization state updates ### Clock steering task The clock steering task listens for the messages from the sources with their updated state. It keeps a local copy of the last received state from each source, and also the state of the clock steering algorithm. Some (but not all) updates from a source indicate that it now has some new measurement data available. If this happens, the clock steering task triggers a clock algorithm update. ### Observability task The observability task is responsible for handling external requests for insight into the daemon's state. It creates and manages a UNIX socket which can be queried for information on the state of the daemon. Once an external program opens a connection to the UNIX socket, the observation daemon makes a copy of the state of all the sources and of the clock steering algorithm (it has access to these through a `RwLock` shared with the clock steering task). It then uses this to generate a JSON bytestream with information, which it then writes to the connection. Immediately afterwards, the entire connection is closed. Note that it never reads from any opened connection on the socket. This is on purpose, as it limits the amount of attack surface exposed by this task. ### Configuration task The configuration task changes configuration dynamically at runtime. The task listens to a socket for new configuration changes. The `ntp-ctl` executable is an example of how to interact with this socket. Because this task reads from its socket, it is advised to restrict the permissions on this socket. ntpd-1.1.2/docs/development/flowdiagram.svg000064400000000000000000000266061046102023000170730ustar 00000000000000
clock
clock
ntpd-rs
ntpd-rs
System admin
System admin
System user
System user
Reference source
Reference source
External client
External client
Text is not SVG - cannot display
ntpd-1.1.2/docs/development/threat-model.md000064400000000000000000000354161046102023000167640ustar 00000000000000# Threat model This document a threat model, based on the methodology presented by Eleanor Saitta, that we as developers use as a guide in our development process. It may not contain all the context needed to fully understand it, if clarifications are needed please ask us. The used methodology is entirely manual, but is derived from [Trike](https://www.octotrike.org/). ## Actors, Assets & Actions ### Actors We model the following actors: - System Admin: Administrator of the system running ntpd-rs - System User: Non-administrator user of the system running ntpd-rs - Reference Source: A remote time server we use as a source for our time. - External Client: A remote user that is allowed to use this instance of ntpd-rs to receive time. - Anonymous: Any other party ### Assets We model the following assets: - Clock: The system clock - Source configuration: The configuration on which sources to use, including some metadata on the current status of those sources - Server configuration: The configuration on which interfaces to provide an NTP server on, and who can use those, including some metadata on the current server status. - Request nonce: The random nonce a client uses for a specific request to the server to match the response to the request. - Client NTS keys: The keys a client uses to communicate with a server. - Client NTS cookies: The cookies a client uses to communicate with the server. - Server NTS keys: The keys a server uses to communicate with a client (ephemeral). - Server NTS cookies: The cookies a server is about to send to a client (ephemeral). - NTS Cookie keys: The keys a server uses to encrypt cookies. ### Actions
Clock Source Configuration Server Configuration Request Nonce Client NTS Keys Client NTS Cookies Server NTS Keys Server NTS Cookies NTS Cookie keys
System admin Create - N/A Read - Always Create - Always Read - Always Create - Always Read - Always Create - N/A Read - Always Create - N/A Read - Always Create - N/A Read - Always Create - N/A Read - Always Create - Always Read - Always Create - Always Read - Always
Update - Always Delete - N/A Update - Always Delete - N/A Update - Always Delete - N/A Update - N/A Delete - N/A Update - N/A Delete - N/A Update - N/A Delete - N/A Update - N/A Delete - N/A Update - N/A Delete - N/A Update - Always Delete - Always
System user Create - N/A Read - Always Create - Never Read - Sometimes Create - Never Read - Sometimes Create - N/A Read - Sometimes Create - N/A Read - Sometimes Create - N/A Read - Sometimes Create - N/A Read - Sometimes Create - Sometimes Read - Sometimes Create - Sometimes Read - Sometimes
Update - Never Delete - N/A Update - Never Delete - N/A Update - Never Delete - N/A Update - N/A Delete - N/A Update - N/A Delete - N/A Update - N/A Delete - N/A Update - N/A Delete - N/A Update - N/A Delete - N/A Update - Sometimes Delete - Sometimes
Reference source Create - N/A Read - Never Create - Never Read - Never Create - Never Read - Never Create - N/A Read - Sometimes Create - N/A Read - Sometimes Create - N/A Read - Sometimes Create - N/A Read - Never Create - Never Read - Never Create - Never Read - Never
Update - Sometimes Delete - N/A Update - Never Delete - N/A Update - Never Delete - N/A Update - N/A Delete - N/A Update - N/A Delete - N/A Update - N/A Delete - N/A Update - N/A Delete - N/A Update - N/A Delete - N/A Update - Never Delete - Never
External client Create - N/A Read - Always Create - Never Read - Always Create - Never Read - Never Create - N/A Read - Never Create - N/A Read - Never Create - N/A Read - Never Create - N/A Read - Someitmes Create - Sometimes Read - Sometimes Create - Never Read - Never
Update - Never Delete - N/A Update - Never Delete - N/A Update - Never Delete - N/A Update - N/A Delete - N/A Update - N/A Delete - N/A Update - N/A Delete - N/A Update - N/A Delete - N/A Update - N/A Delete - N/A Update - Never Delete - Never
Anonymous Create - N/A Read - Never Create - Never Read - Never Create - Never Read - Never Create - N/A Read - Never Create - N/A Read - Never Create - N/A Read - Never Create - N/A Read - Never Create - Never Read - Never Create - Never Read - Never
Update - Never Delete - N/A Update - Never Delete - N/A Update - Never Delete - N/A Update - N/A Delete - N/A Update - N/A Delete - N/A Update - N/A Delete - N/A Update - N/A Delete - N/A Update - N/A Delete - N/A Update - Never Delete - Never
- Reference sources may update the Clock only when sufficiently many agree and don't exceed configured adjustment limits. - Reference sources may only know request information related to requests to them. - System users may read configuration (both types) only when allowed by system admin. - External clients may know key material and cookies related to their session. ## Failure cases
Escalation of Privilege Denial of Service
Clock Create - NA Read - Low Create - NA Read - Medium
Update - Critical Delete - N/A Update - Medium Delete - N/A
Source configuration Create - Critical Read - Medium Create - N/A Read - Low
Update - Critical Delete - N/A Update - Low Delete - N/A
Server configuration Create - Medium Read - Low Create - N/A Read - Low
Update - Medium Delete - N/A Update - Low Delete - N/A
Request nonce Create - N/A Read - Low Create - N/A Read - N/A
Update - N/A Delete - N/A Update - N/A Delete - N/A
Client NTS keys Create - N/A Read - Critical Create - N/A Read - N/A
Update - N/A Delete - N/A Update - N/A Delete - N/A
Client NTS cookies Create - N/A Read - Low Create - N/A Read - N/A
Update - N/A Delete - N/A Update - N/A Delete - N/A
Server NTS keys Create - N/A Read - Critical Create - N/A Read - N/A
Update - N/A Delete - N/A Update - N/A Delete - N/A
Server NTS cookies Create - N/A Read - Low Create - N/A Read - N/A
Update - N/A Delete - N/A Update - N/A Delete - N/A
NTS Cookie keys Create - Critical Read - Critical Create - N/A Read - N/A
Update - Critical Delete - Medium Update - N/A Delete - N/A
- Request nonce: The random nonce a client uses for a specific request to the server to match the response to the request. - Client NTS keys: The keys a client uses to communicate with a server. - Client NTS cookies: The cookies a client uses to communicate with the server. - Server NTS keys: The keys a server uses to communicate with a client (ephemeral). - Server NTS cookies: The cookies a server is about to send to a client (ephemeral). - NTS Cookie keys: The keys a server uses to encrypt cookies. ## Security strategy - If any actor tries to read the clock, the system will not respond with a valid time if the IP address is not on the configured allowlist - If any actor tries to update the clock, the system tries to verify consensus among multiple reference sources - If any actor tries to update the clock, the system refuses updates beyond a configured limit - If the configuration file (used to create the configuration) is world-writable, the system will emit a warning - If the configuration socket (used to update the configuration) is world-writable, the system will emit a warning - The observability socket (used to read the configuration/status) is a unix socket, which is unreachable over the network by default - If any actor tries to read the clock too often, the system will stop responding a valid time to them - If the nts cookie key storage file is world-readable, the system will emit a warning. The system will never create this file with permissions other than `0600`. ## Data flow diagram ![](flowdiagram.svg) - The security boundaries between the admin and system users and ntpd-rs run through the unix sockets used for communication. - The security boundaries for reference sources and external clients run through the network sockets used for communication. ntpd-1.1.2/docs/development-process.md000064400000000000000000000056471046102023000160560ustar 00000000000000# Development processes ## Releasing New releases are created by starting at either the most recent commit on main, or by backporting fixes on top of an existing tag. Some things to take note of before starting the release process: - Have all dependencies recently been updated using `cargo update`? - Does the changelog contain all recent additions, removals, changes and fixes? - Are there still any open issues in any related milestone on GitHub? To determine what version to release we keep to semantic versioning: - If there are any (major) breaking changes, we always release a new major version. - Patch versions are generally only released for tiny fix-only releases. - Minor versions are released when large fixes or new features are introduced. - At any time a new dev release can be made, if unknown what version the next release will be you should always assume a patch version change and only increase minor or major versions if any new features or breaking changes are happening respectively. - Before big releases or if testing is required, a beta or release candidate can be released. ### Checklist - [ ] Run `utils/update-version.sh [version]` - [ ] Update `CHANGELOG.md` with the new version, remove any `Unreleased` section in the changelog. - [ ] `git switch -c release/[version]` - [ ] `git commit -a -S -m "Release [version]"` - [ ] `git push -u origin release/[version]` - [ ] Wait for all actions to finish and succeed, make sure both the checks and the packaging workflow succeed. - [ ] Either create a PR and let someone review the release, or directly merge into the target branch (for most releases this will be `main`). - [ ] On the merged commit, create a new (signed) tag: `git tag -a -s -m "Version [version]" v[version]` - [ ] Push the tag to GitHub: `git push origin v[version]` - [ ] Release on crates.io by running `utils/release.sh` - [ ] Download the artifacts by running `utils/prepare-artifacts.sh --api-token [github-api-token] --run-id [run-id] --download-artifacts --delete-zips --reset` The run id can be extracted from the URL by going to the `Actions` page on GitHub and clicking through to the specific packaging run. A GitHub API token can be generated by going to your personal settings (via your profile picture), clicking on `Developer settings` (at the bottom) and generating a new 'Fine grained personal access token'. Easiest way here is to select 'All repositories' and then enabling the Actions 'Read-only' permission. - [ ] Create a new release on GitHub: https://github.com/pendulum-project/ntpd-rs/releases/new - [ ] Pick the tag just pushed. - [ ] Set the title to `Version [version]`. - [ ] Add the contents of the changelog specific to this version to the body of the release. You may add any additional text at the top of the release text. - [ ] Upload all the files in the `target/pkg` directory. - [ ] Publish the release. ntpd-1.1.2/docs/examples/conf/ntp.toml.default000064400000000000000000000041361046102023000174120ustar 00000000000000[observability] # You can configure ntpd-rs with different output levels of logging information # Basic values for this are `trace`, `debug`, `info`, `warn` and `error`. log-level = "info" ## Using the observe socket you can retrieve statistical information about the ## daemon while it is running. You can use the `ntp-ctl` or prometheus based ## `ntp-metrics-exporter` binaries for some default options to read from the ## observe socket. observation-path = "/var/run/ntpd-rs/observe" ## The sources section allows configuring sources, you may configure multiple of ## these blocks to add more sources to your configuration. ## Our default configuration spawns a pool of sources (by default this attempts ## to discover 4 distinct sources). [[source]] mode = "pool" address = "ntpd-rs.pool.ntp.org" count = 4 ## If you have an NTS server, you can configure a source that connects using NTS ## by adding a configuration such as the one below #[[source]] #mode = "nts" # NTS service from NETNOD: https://www.netnod.se/nts/network-time-security #address = "nts.netnod.se" ## A source in server mode will only create a single source in contrast to the ## multiple sources of a pool. This is the recommended source mode if you only ## have an IP address for your source. #[[source]] #mode = "server" #address = "ntpd-rs.pool.ntp.org" ## If you want to provide time to other machines, the configuration below ## enables serving time on port 123 of all network interfaces. #[[server]] #listen = "[::]:123" ## Below are configured various thresholds beyond which ntpd-rs will not ## change the system clock. CHANGE THESE TO MATCH YOUR SECURITY NEEDS! [synchronization] # The maximum step size (in seconds) of a single step during normal operation single-step-panic-threshold = 1800 # On startup a larger jump may occur, this sets limits for that initial jump startup-step-panic-threshold = { forward="inf", backward = 86400 } # If, during the lifetime of the ntp-daemon the combined time of time jumps # exceeds this value, then the NTP daemon will stop, this is disabled by default #accumulated-threshold = 1800 #minimum-agreeing-sources = 3 ntpd-1.1.2/docs/examples/conf/ntpd-rs-metrics.service000064400000000000000000000005311046102023000207010ustar 00000000000000[Unit] Description=Network Time Service (ntpd-rs) metrics exporter Documentation=https://github.com/pendulum-project/ntpd-rs [Service] Type=simple Restart=always ExecStart=/usr/bin/ntp-metrics-exporter Environment="RUST_LOG=info" RuntimeDirectory=ntpd-rs-observe User=ntpd-rs-observe Group=ntpd-rs-observe [Install] WantedBy=multi-user.target ntpd-1.1.2/docs/examples/conf/ntpd-rs.preset000064400000000000000000000000671046102023000171030ustar 00000000000000enable ntpd-rs.service disable ntpd-rs-metrics.service ntpd-1.1.2/docs/examples/conf/ntpd-rs.service000064400000000000000000000007171046102023000172430ustar 00000000000000[Unit] Description=Network Time Service (ntpd-rs) Documentation=https://github.com/pendulum-project/ntpd-rs After=network-online.target Wants=network-online.target Conflicts=systemd-timesyncd.service ntp.service chrony.service [Service] Type=simple Restart=no ExecStart=/usr/bin/ntp-daemon Environment="RUST_LOG=info" RuntimeDirectory=ntpd-rs User=ntpd-rs Group=ntpd-rs AmbientCapabilities=CAP_SYS_TIME CAP_NET_BIND_SERVICE [Install] WantedBy=multi-user.target ntpd-1.1.2/docs/guide/exporting-metrics.md000064400000000000000000000027701046102023000166320ustar 00000000000000# Exporting metrics Ntpd-rs supports exporting key operational metrics to an external [prometheus](https://prometheus.io/) instance. ## Installed from package If ntpd-rs was installed from the packages distributed by us, the default configuration will already have enabled the observation socket. Furthermore, these packages contain a systemd unit file that enables the metrics exporter with a reasonable configuration. This can be enabled with ```sh sudo systemctl enable --now ntpd-rs-metrics ``` After enabling the metrics exporter, a prometheus metrics dataset will be served on `127.0.0.1:9975/metrics` ## Installed through cargo or from source When installed through cargo or from source, two things need to be configured manually: - Enable the observability socket in the ntpd-rs configuration. - Configure the system to run ntp-metrics-exporter as a service. The observability socket can be enabled by adding the following to the configuration: ```toml [observability] observation-path = "/var/run/ntpd-rs/observe" ``` Next, configure your system to run the ntp-metrics-exporter binary as a service. For systemd based systems, an example is provided below. ```ini [Unit] Description=Network Time Service (ntpd-rs) metrics exporter Documentation=https://github.com/pendulum-project/ntpd-rs [Service] Type=simple Restart=yes ExecStart=/usr/bin/ntp-metrics-exporter Environment="RUST_LOG=info" RuntimeDirectory=ntpd-rs-observe User=ntpd-rs-observe Group=ntpd-rs-observe [Install] WantedBy=multi-user.target ``` ntpd-1.1.2/docs/guide/getting-started.md000064400000000000000000000123751046102023000162560ustar 00000000000000# Getting started Ntpd-rs is an implementation of the NTP protocol. It aims to synchronize your system's clock to time received from the internet. It can also, when [configured as server](server-setup.md), provide time to other machines on the network. ## Installation Installation instructions for your system can be found in the [installation guide](installation.md). For first time users, we strongly recommend using either your OS package repository packages, or the packages we provide. If you have installed ntpd-rs from source, and you have installed files in different locations than the default, you may need to modify the instructions below. ## Checking the synchronization. The default configuration for ntpd-rs sets it up to synchronize with four servers chosen from [the NTP pool](https://www.ntppool.org). We can check its synchronization status using: ```sh ntp-ctl status ``` If everything is installed and working correctly this will display information looking like: ``` Synchronization status: Dispersion: 0.000104s, Delay: 0.005740s Desired poll interval: 16s Stratum: 3 Sources: ntpd-rs.pool.ntp.org:123/20.101.57.9:123 (1): -0.022944±0.000218(±0.004720)s poll interval: 16s, missing polls: 0 root dispersion: 0.103531s, root delay:0.001434s ntpd-rs.pool.ntp.org:123/35.204.193.221:123 (2): +0.000564±0.000138(±0.007323)s poll interval: 16s, missing polls: 0 root dispersion: 0.000000s, root delay:0.007538s ntpd-rs.pool.ntp.org:123/94.198.159.15:123 (3): +0.000140±0.000202(±0.005725)s poll interval: 16s, missing polls: 0 root dispersion: 0.000015s, root delay:0.000015s ntpd-rs.pool.ntp.org:123/95.211.123.72:123 (4): +0.000052±0.000189(±0.005118)s poll interval: 16s, missing polls: 0 root dispersion: 0.039536s, root delay:0.021667s Servers: ``` The first section gives some general information on the time synchronization. The dispersion is a measure for how precise it thinks the local time is, and the delay is a measure of how long the communication delay to the best (most precise) server is. Desired poll interval indicates how often it currently wants to know the time from downstream servers, and stratum indicates how many servers are between us and a reference source of time such as an atomic clock or GPS receiver. Stratum will always be at least 2 when configured as a client using only sources from across the internet. Next, we get information on each of the time sources, showing the measured offset and the uncertainty on that, as well as (between brackets) the delay to the server. We also show the poll interval used for that particular source. This can be different from the desired poll interval if a server requests us to do fewer queries. Finally, missing polls gives an indication of how many times we have tried to poll the server since last getting a time measurement for it. The final section is empty, but if we were running a server, it would show statistics on how often the server is used. ## Configuring a custom time source The sources ntpd-rs uses to get the current time can be configured in the `/etc/ntpd-rs/ntp.toml` configuration file. Suppose that, in addition to the sources from the NTP pool, we also always want to use two sources from the [time.nl](https://time.nl) pool. To do this, we add the following lines to the configuration file: ```toml [[source]] mode = "pool" address = "ntp.time.nl" count = 2 ``` After restarting the daemon (using `sudo systemctl restart ntpd-rs` if you are using Linux) and waiting a bit for it to synchronize, the status now looks like ``` Synchronization status: Dispersion: 0.000123s, Delay: 0.005496s Desired poll interval: 16s Stratum: 2 Sources: ntp.time.nl:123/94.198.159.10:123 (1): +0.000380±0.000249(±0.005496)s poll interval: 16s, missing polls: 0 root dispersion: 0.000122s, root delay:0.000000s ntp.time.nl:123/94.198.159.14:123 (2): -0.000046±0.000154(±0.005520)s poll interval: 16s, missing polls: 0 root dispersion: 0.000122s, root delay:0.000000s ntpd-rs.pool.ntp.org:123/84.245.9.254:123 (3): -0.000288±0.000698(±0.008572)s poll interval: 16s, missing polls: 0 root dispersion: 0.000305s, root delay:0.006226s ntpd-rs.pool.ntp.org:123/83.98.155.30:123 (4): +0.000000±0.000163(±0.005186)s poll interval: 16s, missing polls: 0 root dispersion: 0.005020s, root delay:0.004898s ntpd-rs.pool.ntp.org:123/162.159.200.123:123 (5): -0.000380±0.000140(±0.004535)s poll interval: 16s, missing polls: 0 root dispersion: 0.000259s, root delay:0.003662s ntpd-rs.pool.ntp.org:123/5.255.99.180:123 (6): +0.000193±0.000203(±0.005414)s poll interval: 16s, missing polls: 0 root dispersion: 0.008499s, root delay:0.005661s Servers: ``` where we see the two servers from `time.nl` added to the list of sources. ## Where to go from here You now have a working NTP client, can check its status, and if desired modify the sources it uses for time. There are multiple directions to go from here. If you want more certainty around the authenticity of your time sources, you can take a look at [using NTS](nts.md). Setting up your own time server is explained in our [server setup guide](server-setup.md). When operating ntpd-rs as part of a larger critical system, you may also be interested in our [guidance on hardening ntpd-rs](security-guidance.md). ntpd-1.1.2/docs/guide/installation.md000064400000000000000000000144341046102023000156500ustar 00000000000000# Installation ## Installers & Packages The recommended way of installing ntpd-rs is through an installer or package manager for your system. ### Linux We recommend the packages from our [release page](https://github.com/pendulum-project/ntpd-rs/releases). The package takes care of putting the configuration in the right place and setting up the recommended users and permissions. The default configuration file is located at `/etc/ntpd-rs/ntp.toml` On a debian based linux, the `.deb` package can be installed with ```console $ sudo dpkg -i /path/to/deb/file.deb ``` On a red hat based linux, the `.rpm` package can be installed with ```console $ sudo rpm -ivh /path/to/rpm/file.rpm $ sudo systemctl start ntpd-rs ``` ### FreeBSD The ntpd-rs binary is available on [ports](https://www.freshports.org/net/ntpd-rs/). The default configuration file is located at `%%ETCDIR%%/ntp.toml`, which typically resolves to `/usr/local/etc/ntpd-rs/ntp.toml`. ### macOS There is no package or installer for macOS at the moment. ## Install From Source On platforms without an installer or package, building from source is an option. ntpd-rs is written in rust. We strongly recommend using [rustup] to install a rust toolchain, because the version provided by system package managers tends to be out of date. Be sure to use a recent version of the rust compiler. To build ntpd-rs run ```sh cargo build --release ``` This produces a `ntp-daemon` binary at `target/release/ntp-daemon`, which is the main NTP daemon. Running it from the command line to test it should provide output like: ``` > sudo target/release/ntp-daemon -c pkg/common/ntp.toml.default 2023-09-04T12:01:44.055104Z WARN ntpd::daemon::observer: Abnormal termination of the state observer: Could not create observe socket at "/run/ntpd-rs/observe" because its parent directory does not exist 2023-09-04T12:01:44.055183Z WARN ntpd::daemon::observer: The state observer will not be available 2023-09-04T12:01:44.071353Z INFO ntpd::daemon::system: new peer source_id=PeerId(1) addr=185.172.91.110:123 spawner=SpawnerId(1) 2023-09-04T12:01:44.071735Z INFO ntpd::daemon::system: new peer source_id=PeerId(2) addr=162.159.200.1:123 spawner=SpawnerId(1) 2023-09-04T12:01:44.071944Z INFO ntpd::daemon::system: new peer source_id=PeerId(3) addr=45.138.55.62:123 spawner=SpawnerId(1) 2023-09-04T12:01:44.072150Z INFO ntpd::daemon::system: new peer source_id=PeerId(4) addr=213.154.236.182:123 spawner=SpawnerId(1) 2023-09-04T12:01:44.084626Z INFO ntp_proto::algorithm::kalman: No concensus cluster found 2023-09-04T12:01:44.085422Z INFO ntp_proto::algorithm::kalman: No concensus cluster found 2023-09-04T12:01:44.086879Z INFO ntp_proto::algorithm::kalman: Offset: 2.3686082232975885+-72.6249392570874ms, frequency: 0+-5773502.691896258ppm 2023-09-04T12:01:44.087846Z INFO ntp_proto::algorithm::kalman: Offset: 2.7204471636925773+-61.339759726948046ms, frequency: 0+-5000000.000000001ppm ``` To use this binary as your system NTP daemon, you must also: - move the `ntp-daemon` binary to an appropriate location (e.g. `/usr/bin`), - set up a configuration in `/etc/ntpd-rs/ntp.toml` (we suggest copying the configuration under `docs/examples/ntp.toml.default`), - set permissions for the binary and config file for the binary to be able to run and read the configuration, - configure the binary to be run as a system service. ### Running as a system service It is by far the easiest to have your operating system and standard tools take care of the details like: - ensure that no competing NTP daemon is running - ensure that the daemon is started on startup - handling the ntpd-rs logs Below are configurations for linux (using `SystemD`) and FreeBSD (using a .rc file). #### Linux + SystemD This is the SystemD configuration used by the ntpd-rs linux installer. ```ini [Unit] Description=Rust Network Time Service Documentation=https://github.com/pendulum-project/ntpd-rs After=network-online.target Wants=network-online.target Conflicts=systemd-timesyncd.service ntp.service chrony.service [Service] Type=simple Restart=no ExecStart=/usr/local/bin/ntp-daemon Environment="RUST_LOG=info" RuntimeDirectory=ntpd-rs User=ntpd-rs Group=ntpd-rs AmbientCapabilities=CAP_SYS_TIME # Note: when running a server on the default port 123, permissions to bind to # low (<1024) ports is also needed, which can be given with # AmbientCapabilities=CAP_SYS_TIME CAP_NET_BIND_SERVICE [Install] WantedBy=multi-user.target ``` Note that this requires an ntpd-rs user to be present on the system, which can be created with ```sh sudo adduser --system --home /var/lib/ntpd-rs/ --group ntpd-rs ``` or if your system doesn't have adduser ```sh sudo useradd --home-dir /var/lib/ntpd-rs --system --create-home --user-group ntpd-rs ``` This user must have access to the configuration folder: ```sh sudo chown ntpd-rs:ntpd-rs /etc/ntpd-rs/ntp.toml sudo chmod 0644 /etc/ntpd-rs/ntp.toml ``` #### FreeBSD This is the [rc script](https://github.com/freebsd/freebsd-ports/blob/main/net/ntpd-rs/files/ntp_daemon.in) used by the [ntpd-rs package on freshports](https://www.freshports.org/net/ntpd-rs/). ```sh #!/bin/sh # PROVIDE: ntp_daemon # REQUIRE: DAEMON FILESYSTEMS devfs # BEFORE: LOGIN # KEYWORD: nojail resume shutdown # . /etc/rc.subr name=ntp_daemon rcvar=ntp_daemon_enable load_rc_config $name ntp_daemon_enable=${ntp_daemon_enable-"NO"} ntp_daemon_config=${ntp_daemon_config-"%%ETCDIR%%/ntp.toml"} ntp_daemon_socket=${ntp_daemon_socket-"/var/run/ntpd-rs"} command="/usr/bin/true" procname="/usr/sbin/daemon" pidfile="/var/run/${name}.pid" start_cmd="ntp_daemon_start" stop_cmd="ntp_daemon_stop" is_process_running() { [ -f ${pidfile} ] && procstat $(cat ${pidfile}) >/dev/null 2>&1 } ntp_daemon_start() { [ -d "${ntp_daemon_socket}" ] || /bin/mkdir "${ntp_daemon_socket}" /usr/sbin/chown _ntp:_ntp "${ntp_daemon_socket}" /usr/sbin/daemon -P ${pidfile} -r -f -o /var/log/ntp_daemon.log -H %%PREFIX%%/bin/ntp-daemon --config "${ntp_daemon_config}" if is_process_running; then echo "Started ntp-daemon (pid=$(cat ${pidfile}))" else echo "Failed to start ntp-daemon" fi } ntp_daemon_stop() { if is_process_running; then /bin/rm -rf "${ntp_daemon_socket}" local pid=$(cat ${pidfile}) echo "Stopping ntp-daemon (pid=${pid})" kill -- -${pid} else echo "ntp-daemon isn't running" fi } run_rc_command "$1" ``` [rustup]: https://rustup.rs ntpd-1.1.2/docs/guide/migrating-chrony.md000064400000000000000000000251051046102023000164250ustar 00000000000000# Migrating from chrony Both chrony and ntpd-rs can serve a similar role on Unix systems. This guide aims to help those migrating machines currently running chrony to ntpd-rs. We assume some experience with the [chrony configuration format](https://chrony-project.org/doc/4.3/chrony.conf.html). A user with no or little chrony experience may be better off following our [getting started guide](getting-started.md). Before we start with the specifics on how to convert individual directives, first a few notes. In contrast with the chrony configuration format, which acts like a list of commands to the client, the ntpd-rs configuration is a [TOML](https://toml.io/) file. In particular, this means configuration is done by giving values for properties. As such, fields cannot be repeated unless they are part of a list, such as with the `[[source]]` sections and `[[server]]` sections. Comments can be added by starting them with a `#`. The remainder of the line is then ignored. Please note that for some of the settings below, ntpd-rs and chrony use different defaults. When converting a configuration, please pay particular attention to `minsources`/`minimum-agreeing-sources`, `maxstep` and the corresponding `-panic-thresholds`, and any settings for NTS server functionality. Validation of the resulting ntpd-rs configuration can be done with `ntp-ctl validate -c `, which should at least catch the most egregious errors. This guide does not go into detail on all of chrony's configuration directives, but rather focusses on those most important for successful migration. If a directive is not mentioned here, there may still be ntpd-rs options in the [configuration reference](../man/ntp.toml.5.md) that achieve the desired effect. Note that not all functionality of chrony is currently supported, a short overview of major differences is given [at the end of this document](#non-supported-features) ## Time sources ### Server directives Client-server connections need to be migrated in one of two ways: - As a server source, if no authentication is used. - As an NTS source, if NTS is enabled (i.e. the NTS option is present in the server directive). For server directives with no authentication, these can be converted to ```toml [[source]] mode="server" address="

" ``` where the address is the same as that given in the server directive. For server directives with NTS, these can be converted to ```toml [[source]] mode="nts" address="
" ``` If the server directive contains poll limits (`maxpoll` or `minpoll`), these cannot be specified on a per-server basis in ntpd-rs. The best approach is to determine values acceptable for all time sources and apply these via source defaults: ```toml [source-defaults] poll-interval-limits = { min = , max = } initial-poll-interval = ``` There is no support for bursting in ntpd-rs yet. When any bursting directive (`burst` or `iburst`) is present, these usually can be ignored, although if custom poll limits are in place, these may need to be rethought. For NTS, if a custom certificate set is configured for a source via the `certset` directive, these can be provided via the ntpd-rs `certificate_authority` option. This expects a path to a file containing all the accepted root certificates for the source accepted in addition to the system certificates. ### Pool directives Pools configured via the pool directive can be added to the ntpd-rs configuration via ```toml [[pool]] mode="pool" address="
" ``` If the pool directive specifies `maxsources`, this value can be configured in ntpd-rs via the `count` property. The default (4) is the same between ntpd-rs and chrony. If the pool directive contains poll limits (`maxpoll` or `minpoll`), these cannot be specified on a per-server basis in ntpd-rs. The best approach is to determine values acceptable for all time sources and apply these via source defaults: ```toml [source-defaults] poll-interval-limits = { min = , max = } initial-poll-interval = ``` There is currently no support for bursting in ntpd-rs. When any bursting option (`burst` or `iburst`) is present, these usually can be ignored, although if custom poll limits are in place, these may need to be relaxed. ### Peer directives Symmetric peer modes are not supported in ntpd-rs, and are unlikely to be supported in the future. When migrating a configuration with symmetric peer connections, we recommend replacing these with client-server mode connections on both clients (see also [Server directives](#server-directives) above). ### Refclock directives The current version of ntpd-rs does not yet support local reference clocks, but this feature is on our roadmap. If you are interested in migrating a configuration using local reference clocks, we would be interested in hearing the details. This information can help guide our implementation effort. ## Time synchronization options The minimum number of sources needed for time synchronization in ntpd-rs is configured through `minimum-agreeing-sources`: ```toml [synchronization] mininum-agreeing-sources = ``` Note that although the effect of this option is the same as chrony's `minsources`, the default in ntpd-rs is 3, rather than the default 1 source required by chrony. Although 3 is recommended for security, it may not be appropriate for all configurations, particularly configurations where few remote sources are configured. Chrony can limit the maximum time change with the `maxchange` directive. ntpd-rs allows similar restrictions to be enforced through a number of panic thresholds. Steps at startup are controlled through the `startup-panic-threshold`, whilst steps during normal operation are controlled with `single-step-panic-threshold` and `accumulated-step-panic-threshold`. In contrast to chrony, these do not allow ignoring of the first few occurrences, and more importantly, have finite default values: ```toml [synchronization] single-step-panic-threshold = 1000 startup-step-panic-threshold = { forward="inf", backward = 86400 } accumulated-step-panic-threshold = "inf" ``` Chrony and ntpd-rs use different algorithms for synchronizing the time. This means that options for tuning filtering of the time differ significantly, and we cannot offer precise guidance on how to translate the chrony parameters to values for ntpd-rs. When migrating a configuration that tunes chrony's algorithm, one should take the intent of the tuning and use that as guidance when choosing which [time synchronization options](../man/ntp.toml.5.md#synchronization) to change. When tuning the synchronization algorithm, it is important to note a major philosophical difference between chrony and ntpd-rs. For chrony, the majority of the algorithm tuning parameters are set on an individual time source. Within ntpd-rs, all control of the filtering is done via global parameters. Although we do not expect this to be the case, should there be specific parameters you would wish to configure on a per-source basis, please let us know so we can consider this for future releases. ## Server configuration Server configuration in ntpd-rs works quite a bit differently from chrony. Rather than enabling time server functionality by `allow`ing remote connections to the server, one or more serving instances can be individually configured. Each of these comes with its own allow and deny list. The subnets to allow or deny must be specified in CIDR notation (an IP address followed by a slash and the number of masked bits, for example `127.0.0.1/8` or `192.168.1.1/24`) ```toml [[server]] listen=":" [server.allowlist] filter = [ "", "", ] action = "ignore" [server.denylist] filter = [ "", "", ] action = "deny" ``` The allow and deny list configuration is optional in ntpd-rs. By default, a server accepts traffic from anywhere. When configuring both allow and deny lists, ntpd-rs will first check if a remote is on the deny list. Only if this is not the case will the allow list be considered. This ordering needs to be taken into account when translating interleaved combinations of chrony's `allow` and `deny` commands. NTS can be enabled for a server by configuring an NTS key exchange server: ```toml [[nts-ke-server]] listen = ":4460" certificate-chain-path = private-key-path = ``` Here the names of the corresponding chrony directives are used on the right hand side of the assignment. Note that unlike chrony, ntpd-rs does not have a default IP address on which it listens for nts-ke traffic: this need to be provided explicitly. The port is optional however and defaults to the standard value 4460. The keys used to encrypt the cookies are ephemeral by default. If these should be kept across reboots of the server, the path for storing these can be configured: ```toml [keyset] key-storage-path = ``` Note that in contrast to chrony's `ntsdumpdir` directive, here the full path needs to be specified, and there is no default path. The default key rotation interval is daily, and one full week's worth of old keys is retained for serving clients with older cookies. With these defaults, cookies for the server are only valid for slightly more than one week. This is much less than chrony's default of 3 weeks. These settings can be configured with the `key-rotation-interval` and `stale-key-count` parameters: ```toml [keyset] stale-key-count = key-rotation-interval = ``` Sharing the keys with which the NTS cookies are encrypted between multiple ntpd-rs servers is not yet supported. If a local stratum for the server is configured through `local stratum`, this can be configured in ntpd-rs through the `local-stratum` key: ```toml [synchronization] local-stratum = ``` Broadcast mode is not supported in ntpd-rs. If this is used in your current setup, configuring the NTP server via DHCP instead may be an alternative. Note that using broadcast mode may leave you more vulnerable to security issues. ## Non-supported features Not all functionality in chrony currently has an equivalent in ntpd-rs. In particular, the following major features currently don't have good alternatives in ntpd-rs: - Local hardware devices as time sources. - Support for ntp mac authentication. - Marking subsets of sources as more trusted than others. - Acting as a source of leap second data. If any of these features are critical for your use case, ntpd-rs might not be an option for you yet. Please let us know if you miss these features or want to sponsor any of them, as this helps us prioritise our work. ntpd-1.1.2/docs/guide/migrating-ntpd.md000064400000000000000000000162131046102023000160700ustar 00000000000000# Migrating from ntpd Both [ntpd](https://www.ntp.org/), the NTP reference implementation, and ntpd-rs can serve a similar role on Unix systems. This is a guide for converting a ntpd configuration into a ntpd-rs configuration. We assume some experience with the [ntpd configuration format](https://www.ntp.org/documentation/4.2.8-series/comdex/). A user with no or little ntpd experience may be better of following our [getting started guide](getting-started.md). Configuration for ntpd uses a custom format that functions as a list of commands. In contrast, ntpd-rs uses a configuration file in the `.toml` format that gives values to properties. That means that in most cases fields cannot be repeated. Comments can be added by starting them with a `#`. The remainder of the line is then ignored. An `ntpd-rs` configuration can be validated with `ntp-ctl validate -c `. This will check all field names, and in some cases validates that a value is within the range of valid values for that property. This guide will not go into detail on all of ntpd's configuration directives, but rather focus on those most important for successful migration. If a particular directive is not mentioned here, there may still be ntpd-rs options in the [configuration reference](../man/ntp.toml.5.md) that achieve the desired effect. Note that not all functionality of ntpd is currently supported, a short overview of major differences is given [at the end of this document](#unsupported-features). ## Time sources The `server` and `pool` commands have a direct equivalent in ntpd-rs: ```toml # ntpd server 0.pool.ntp.org server 1.pool.ntp.org pool pool.ntp.org # ntpd-rs [[source]] mode = "server" address = "0.pool.ntp.org" [[source]] mode = "server" address = "1.pool.ntp.org" [[source]] mode = "pool" address = "pool.ntp.org" count = 4 ``` A source in `pool` mode must explicitly define an integer `count`, the maximum number of connections from this pool. The ntpd-rs daemon will actively try to keep the pool "filled": new connections will be spun up if a source from the pool is unreachable. The symmetric and broadcasting association modes are deliberately not supported in ntpd-rs because these modes have security issues. The `peer` command can be substituted with a standard `server` source. For the `broadcast` command, configuring the NTP server via DHCP instead may be an alternative There is no direct equivalent of ntpd's `maxpoll` and `minpoll` flags that can be configured on a per-source basis. Instead ntpd-rs defines poll interval bounds globally for all time sources: ```toml [source-defaults] poll-interval-limits = { min = , max = } initial-poll-interval = ``` There is no support for bursting in ntpd-rs yet, but the ntpd-rs algorithm is able to synchronize much more quickly (with fewer measurements) than ntpd's algorithm. Therefore, if any bursting directive (`burst` or `iburst`) is present, these usually can be ignored when translating configurations. In some cases, if strict custom poll limits are in place, these may need to be relaxed. ### Reference clocks The current version of ntpd-rs does not yet support local reference clocks, but this feature is on our roadmap. If you are interested in migrating a configuration using local reference clocks, we would be interested in hearing the details. This information will help guide our implementation effort. ## Time synchronization options The minimum number of time sources needed for time synchronization in ntpd-rs is configured through `minimum-agreeing-sources`: ```toml [synchronization] mininum-agreeing-sources = ``` If fewer agreeing source are available, no synchronization is performed and the clock will drift. This option is a combination of ntpd's `minclock` and `minsane`. Its default value is 3, the recommended value from a security perspective. In ntpd, a default of 3 is used for `minclock` and 1 for `minsane`. Through the `tinker` command's `step` and `stepout` flags, ntpd allows limiting of the maximum change in time made. Although not entirely the same in functionality, ntpd-rs allows similar restrictions to be enforced through a number of panic thresholds. Steps at startup are controlled through the `startup-panic-threshold`, whilst steps during normal operation are controlled with `single-step-panic-threshold` and `accumulated-step-panic-threshold`. ```toml [synchronization] single-step-panic-threshold = 1000 startup-step-panic-threshold = { forward="inf", backward = 86400 } accumulated-step-panic-threshold = "inf" ``` ntpd and ntpd-rs use different algorithms for synchronizing the time. This means that options for tuning filtering of the time differ significantly, and we cannot offer precise guidance on how to translate the ntpd parameters to values for ntpd-rs. When migrating a configuration that tunes ntpd's algorithm, one should take the intent of the tuning and use that as guidance when choosing which of ntpd-rs's [time synchronization options](../man/ntp.toml.5.md#synchronization) to change. ## Server Configuration & Access Control The [`restrict` command](https://www.ntp.org/documentation/4.2.8-series/accopt/) is used in ntpd to deny requests from a client. In ntpd this is a global setting. A flag configures what happens with connections from this client. For instance, `ignore` will silently ignore the request, while `kod` sends a response to the client that notifies it that its request is denied. This logic is expressed differently in ntpd-rs. A specific server can be configured to have a `denylist` and an `allowlist`. The subnets to allow or deny must be specified in CIDR notation (an IP address followed by a slash and the number of masked bits, for example `127.0.0.1/8` or `192.168.1.1/24`) ```toml [[server]] listen=":" [server.allowlist] filter = [ "", "", ] action = "ignore" [server.denylist] filter = [ "", "", ] action = "deny" ``` The allow and deny list configuration is optional in ntpd-rs. By default, if a server is configured it will accept traffic from anywhere. When configuring both allow and deny lists, ntpd-rs will first check if a remote is on the deny list. Only if this is not the case will the allow list be considered. The `allowlist.action` and `denylist.action` properties can have two values: - `ignore` corresponds to ntpd's `ignore` and silently ignores the request - `deny` corresponds to ntpd's `kod` and sends a deny kiss-o'-death packet The stratum can can be configured in ntpd-rs with the `local-stratum` key: ```toml [synchronization] local-stratum = ``` ## Unsupported features Not all functionality in ntpd currently has an equivalent in ntpd-rs. In particular, the following major features currently don't have good alternatives in ntpd-rs: - Local hardware devices as time sources. - Support for ntp mac authentication. - Marking subsets of sources as more trusted than others - protocol modes beside server and client - bursting If any of these features are critical for your use case, ntpd-rs might not be an option for you yet. Please let us know if you miss these features or want to sponsor any of them, as this helps us prioritise our work. ntpd-1.1.2/docs/guide/migrating-ntpsec.md000064400000000000000000000217071046102023000164230ustar 00000000000000# Migrating from NTPsec Both ntpsec and ntpd-rs can serve a similar role on Unix systems. This guide is aimed to help those migrating machines currently running ntpsec to ntpd-rs. We assume some experience with the [ntpsec configuration format](https://docs.ntpsec.org/latest/ntp_conf.html). A user with no or little ntpsec experience may be better of following our [getting started guide](getting-started.md). Configuration for ntpsec uses a custom format that functions as a list of commands. In contrast, ntpd-rs uses a configuration file in the `.toml` format that gives values to properties. That means that in most cases fields cannot be repeated. Comments can be added by starting them with a `#`. The remainder of the line is then ignored. An `ntpd-rs` configuration can be validated with `ntp-ctl validate -c `. This will check all field names, and in some cases validates that a value is within the range of valid values for that property. This guide will not go into detail on all of ntpsec's configuration directives, but rather focus on those most important for successful migration. If a particular directive is not mentioned here, there may still be ntpd-rs options in the [configuration reference](../man/ntp.toml.5.md) that achieve the desired effect. Note that not all functionality of ntpsec is currently supported, a short overview of major differences is given [at the end of this document](#unsupported-features) ## Time sources ### Server entries The `server` and `pool` commands have a direct equivalent in ntpd-rs: ```toml # ntpsec server 0.pool.ntp.org server 1.pool.ntp.org pool pool.ntp.org # ntpd-rs [[source]] mode = "server" address = "0.pool.ntp.org" [[source]] mode = "server" address = "1.pool.ntp.org" [[source]] mode = "pool" address = "pool.ntp.org" count = 4 ``` A source in `pool` mode must explicitly define an integer `count`, the maximum number of connections from this pool. The ntpd-rs daemon will actively try to keep the pool "filled": new connections will be spun up if a source from the pool is unreachable. For server directives with NTS, these can be converted to ```toml # ntpsec server ntp.time.nl nts server ntp.example.com nts ca path/to/certificate/authority.pem # ntpd-rs [[source]] mode="nts" address="ntp.time.nl" [[source]] mode="nts" address="ntp.example.com" certificate_authority = "path/to/certificate/authority.pem" ``` There is no direct equivalent of ntpsec's `maxpoll` and `minpoll` flags that can be configured on a per-source basis. Instead ntpd-rs defines poll interval bounds globally for all time sources: ```toml [source-defaults] poll-interval-limits = { min = , max = } initial-poll-interval = ``` There is no support for bursting in ntpd-rs yet, but the ntpd-rs algorithm is able to synchronize much more quickly (with fewer measurements) than ntpsec's algorithm. Therefore, if any bursting directive (`burst` or `iburst`) is present, these usually can be ignored when translating configurations. In some cases, if strict custom poll limits are in place, these may need to be relaxed. ### Reference clocks The current version of ntpd-rs does not yet support local reference clocks, but this feature is on our roadmap. If you are interested in migrating a configuration using local reference clocks, we would be interested in hearing the details. This information will help guide our implementation effort. ## Time synchronization options The minimum number of time sources needed for time synchronization in ntpd-rs is configured through `minimum-agreeing-sources`: ```toml [synchronization] mininum-agreeing-sources = ``` If fewer agreeing source are available, no synchronization is performed and the clock will drift. This option is a combination of ntpd's `minclock` and `minsane`. Its default value is 3, the recommended value from a security perspective. In ntpd, a default of 3 is used for `minclock` and 1 for `minsane`. Through the `tinker` command's `step` and `stepout` flags, ntpsec allows limiting of the maximum change in time made. Although not entirely the same in functionality, ntpd-rs allows similar restrictions to be enforced through a number of panic thresholds. Steps at startup are controlled through the `startup-panic-threshold`, whilst steps during normal operation are controlled with `single-step-panic-threshold` and `accumulated-step-panic-threshold`. ```toml [synchronization] single-step-panic-threshold = 1000 startup-step-panic-threshold = { forward="inf", backward = 86400 } accumulated-step-panic-threshold = "inf" ``` ntpsec and ntpd-rs use different algorithms for synchronizing the time. This means that options for tuning filtering of the time differ significantly, and we cannot offer precise guidance on how to translate the ntpsec parameters to values for ntpd-rs. When migrating a configuration that tunes ntpsec's algorithm, one should take the intent of the tuning and use that as guidance when choosing which of ntpd-rs's [time synchronization options](../man/ntp.toml.5.md#synchronization) to change. ## Server Configuration & Access Control The `restrict` command is used in ntpsec to deny requests from a client. In ntpsec this is a global setting. A flag configures what happens with connections from this client. For instance, `ignore` will silently ignore the request, while `kod` sends a response to the client that notifies it that its request is denied. This logic is expressed differently in ntpd-rs. A specific server can be configured to have a `denylist` and an `allowlist`. The subnets to allow or deny must be specified in CIDR notation (an IP address followed by a slash and the number of masked bits, for example `127.0.0.1/8` or `192.168.1.1/24`) ```toml [[server]] listen=":" [server.allowlist] filter = [ "", "", ] action = "ignore" [server.denylist] filter = [ "", "", ] action = "deny" ``` The allow and deny list configuration is optional in ntpd-rs. By default, if a server is configured it will accept traffic from anywhere. When configuring both allow and deny lists, ntpd-rs will first check if a remote is on the deny list. Only if this is not the case will the allow list be considered. The `allowlist.action` and `denylist.action` properties can have two values: - `ignore` corresponds to ntpsec's `ignore` and silently ignores the request - `deny` corresponds to ntpsec's `kod` and sends a deny kiss-o'-death packet The stratum can can be configured in ntpd-rs with the `local-stratum` key: ```toml [synchronization] local-stratum = ``` ### NTS NTS can be enabled for a server by configuring an NTS key exchange server: ```toml # ntpsec nts key /etc/letsencrypt/live/ntp.example.com/privkey.pem nts cert /etc/letsencrypt/live/ntp.example.com/fullchain.pem # ntpd-rs [[nts-ke-server]] listen = ": certificate-chain-path = "/etc/letsencrypt/live/ntp.example.com/fullchain.pem" private-key-path = "/etc/letsencrypt/live/ntp.example.com/privkey.pem" ``` Note that unlike ntpsec, ntpd-rs does not have a default ip address on which it listens for nts-ke traffic: it needs to be provided explicitly. The port is optional and defaults to the standard value 4460. The keys used to sign the cookies is kept in memory, but can additionally be stored to a file (so they are preserved after a restart). ```toml # ntpsec nts cookie /var/lib/ntp/nts-keys # ntpd-rs [keyset] key_storage_path = "/var/lib/ntp/nts-keys" ``` The `key_storage_path` requires a full path to a file, and there is no default path. Keys are rotated to limit the damage when a key is leaked. By default, this occurs every 24 hours. At most 7 older keys are remembered to serve clients with older cookies. These numbers can be configured with the `key-rotation-interval` and `stale-key-count` parameters: ```toml [keyset] stale-key-count = key-rotation-interval = ``` Note that the defaults for these settings mean that cookies for the server are only valid for slightly more than 1 week. Sharing the keys with which the nts cookies are encrypted between multiple ntpd-rs servers is not yet supported. ## Unsupported features Not all functionality in ntpsec currently has an equivalent in ntpd-rs. In particular, the following major features currently don't have good alternatives in ntpd-rs: - Local hardware devices as time sources. - Support for ntp mac authentication. - Marking subsets of sources as more trusted than others. - bursting If any of these features are critical for your use case, ntpd-rs might not be an option for you yet. Please let us know if you miss these features or want to sponsor any of them, as this helps us prioritise our work. ntpd-1.1.2/docs/guide/nts.md000064400000000000000000000240561046102023000137540ustar 00000000000000# Network Time Security Network Time Security (NTS) is an extension to the NTP protocol aimed at securing the communication between NTP clients and servers. It's most important goals are: * Verification of the server identity to make sure you receive time from the source you expected to receive time information from. * Making sure that time packets are authentic, i.e. they were not modified in transit. * Preventing the replay of previously sent time packets and verification that time packets were sent in response to a request by a client. Although NTS has the capability to encrypt parts of the message, the time information itself is considered public information and as such is not encrypted. Third parties can thus see what the exchanged time information was, but they cannot modify it. ## Using an NTS source You can use existing public NTS servers with ntpd-rs by simply adding a source with mode `nts`. For example, [netnod] has public NTS servers, to use them you simply configure a source like this: [netnod]: https://www.netnod.se/nts/network-time-security ```toml [[source]] mode = "nts" address = "nts.netnod.se" ``` The certificate of the NTS server is verified by using the installed system certificates on your machine. However, some NTS servers use a custom or private certificate authority (CA) that is unknown by your system to sign their certificates, in such cases you will also need to specify the additional certificate authority by setting a `certificate-authority` option: ```toml [[source]] mode = "nts" address = "my.private.server.example.com" certificate-authority = "/path/to/certificate/authority.pem" ``` !!! Warning The ntpd-rs daemon does not support self-signed certificates. Servers that only have a self-signed certificate cannot be used. Either setup a private certificate authority and use that CA to sign the certificate for the server, or choose an alternative NTS server. ## NTS protocol When using NTS, both the client and server sign and partially encrypt the NTP messages they exchange using symmetric key cryptography. For this, the client and server first need to exchange the keys they will use. NTS solves this problem with a separate key exchange. For the key exchange, the client first contacts the server over a TCP connection secured with TLS, the same protocol also used for secure web browsing. Over this connection, they then decide on which keys to use. Finally, the server provides the client with eight cookies. These cookies are used by the client to tell the server which keys are in use for the session. The client uses each cookie only once to ensure that a third party cannot track its connection, and it receives a new cookie with each server response. These cookies are an opaque bag of bytes for the client, and the server can put in them whatever it finds usefull for identifying the proper keys for that particular client. Cookies do however have to be unique, a cookie cannot be reused once a message with it was sent. If the client ever runs out of cookies (a cookie is lost whenever an NTP message or the response to that message got lost) or if the server somehow no longer understands the cookies it receives from clients, the server and client will have to redo the key exchange. ## Setting up an NTS server Setting up an NTS server involves several steps. Before you get started, make sure you already have a [working NTP server](./server-setup.md). For the key exchange part of NTS, we need to setup a specific key exchange server in the daemon. NTS-KE servers by default run on TCP port 4460. Note the difference here, where the NTP server uses UDP versus the key exchange protocol running on TCP. To do this, we add a `[[nts-ke-server]]` section to our configuration: ```toml [[nts-ke-server]] listen = "[::]:4460" certificate-chain-path = "/path/to/certificate/chain.pem" private-key-path = "/path/to/private.key" ``` !!! Note The ntpd-rs daemon currently does not support running an NTS server without an associated domain name through which its clients reach it. If you are setting up your own private CA, you can however setup a local domain name (e.g. `example-nts.local`), such as one configured through `/etc/hosts`. Raw IPv4 or IPv6 addresses such as `192.168.1.1` are unsupported. Once the NTS-KE server is setup the NTP server you have setup in your configuration will automatically start responding to valid NTS messages, there is no additional setup required. Getting a certificate for your server can be a quite involved proces. We would recommend you use a [Let's Encrypt][1] ACME client for setting up a TLS certificate (similarly to how you would set this up for a webserver). Below you will find some examples using some popular clients. [1]: https://letsencrypt.org/ !!! Note For development purposes (or in very specific networking scenarios) it might be useful to setup your own CA that allows you to setup a private certificate for your NTS server. This is not recommended for general usage, but we have a guide for [setting up your own CA](../development/ca.md). ### Configuring key storage After having enabled an NTS-KE server you will have a working configuration for an NTS server. However, every time we reboot our server, all of its clients will need to go through the key exchange process again. To ensure that clients don't experience any negative consequences on server reboots, we can configure the server to store key materials it generates to disk. We can do this by adding an addition `[keyset]` section, and setting the `key-storage-path` within it: ```toml [keyset] key-storage-path="/path/to/store/key/material" ``` Note that, like with the TLS private key, an attacker having access to the file specified under `key-storage-path` can compromise all connections to clients. ### Certificates using certbot Let's encrypt recommends using certbot for managing certificates on your server. To get started, you should follow the [certbot installation instructions][2]. You can follow the instructions for *'Other'* software for your specific OS. Once you've installed certbot, verify that it is working as intended: [2]: https://certbot.eff.org/instructions ```sh certbot --version ``` Once you've installed certbot, you can run a simple command to get a certificate for your domain, replacing the email address and domain name with your own: ```sh certbot certonly --standalone -n --email "[you@example.com]" --agree-tos -d "[time.example.com]" --deploy-hook "systemctl restart ntpd-rs" ``` The command above assumes that traffic from TCP port 80 can be received from the internet by your server and that there is no other software (such as another webserver) running on that port. When you have an existing webserver already listening on port 80 you can use that as well. Or if http traffic is not possible you can also use DNS based verification, but those go beyond this guide. Please read the [certbot documentation][3] for more details. Certbot automatically sets up a task that renews these certificates, because Let's Encrypt certificates are valid for only 90 days. The `--deploy-hook` argument tells cerbot to restart the ntpd-rs daemon whenever a new certificate is issued, because ntpd-rs does not automatically reload the certificate files. We can now update our configuration with the paths of the generated certificate files (replacing the domain name with the domain name for which you requested a certificate): ```toml [[nts-ke-server]] listen = "[::]:4460" certificate-chain-path = "/etc/letsencrypt/live/[time.example.com]/fullchain.pem" private-key-path = "/etc/letsencrypt/live/[time.example.com]/privkey.pem" ``` Finally, restart the ntpd-rs daemon using `systemctl restart ntpd-rs`. Your server should now be able to handle NTS traffic! [3]: https://eff-certbot.readthedocs.io/en/stable/using.html ### Certificates using lego Lego is an alternative Let's Encrypt client implementation. On many OSses it can be installed from the package repository by searching for a `lego` package. If it is not available from your OS vendor, you can also find a download from the [lego github page][4]. To generate a new certificate, you can issue the following command, replacing the email address and domain name with your own: ```sh lego --email "[you@example.com]" --http --domains "[time.example.com]" --accept-tos --path /var/lib/lego run ``` Lego does not automatically renew certificates when they expire, but we can setup a crontab entry to automate the renewal process. The lego renew command only renews when a certificate is due to expire. To do this, place an executable shell script in `/etc/cron.daily` (replacing the email address and domain name with your own as before): ```sh cat <<'EOF' > /etc/cron.daily/renew-certificate #!/usr/bin/env bash lego --email "[you@example.com]" --http --domains "[time.example.com]" --accept-tos --path /var/lib/lego renew --renew-hook "systemctl restart ntpd-rs EOF chmod +x /etc/cron.daily/renew-certificate ``` Because the ntpd-rs daemon does not automatically restart whenever the certificates are updated, we instruct lego to restart our daemon using the `--renew-hook` argument. The commands above assume that traffic from TCP port 80 can be received from the internet by your server and that there is no other software (such as another webserver) running on that port. When you have an existing webserver already listening on port 80 you can use that as well. Or if http traffic is not possible you can also use DNS based verification, but those go beyond this guide. Please read the [lego documentation][5] for more details. We can now update our configuration with the paths of the generated certificate files (replacing the domain name with the domain name for which you requested a certificate): ```toml [[nts-ke-server]] listen = "[::]:4460" certificate-chain-path = "/var/lib/lego/certificates/[time.example.com].crt" private-key-path = "/var/lib/lego/certificates/[time.example.com].key" ``` Finally, restart the ntpd-rs daemon using `systemctl restart ntpd-rs`. Your server should now be able to handle NTS traffic! [4]: https://github.com/go-acme/lego [5]: https://go-acme.github.io/lego/ ntpd-1.1.2/docs/guide/security-guidance.md000064400000000000000000000202131046102023000165630ustar 00000000000000# Hardening ntpd-rs A correct system clock is critical for both security and the proper functioning of software. For instance, determining the validity of a TLS certificate relies on the system time. Running and debugging a distributed system is much easier, and in some cases only feasible, when the machines are all synchronized. This guide provides some guidance on what to think about when hardening ntpd-rs for your setup. ## The Availability - Correctness tradeoff When hardening ntpd-rs, one of the larger challenges is a fundamental tradeoff between: - availability of synchronization: ntpd-rs should actively and continually synchronize with external sources - risk of missteering: ntpd-rs should not blindly follow external sources: they may be compromised Many of the measures against missteering increase the risk of unavailability and vice versa. You must decide what the correct balance is for your use case. For instance, the risk of missteering is large if your system deals with public key cryptography. The security of the current web certificate system hinges on having a rough (<1day) consensus on what time it is. Similarly, the security and functioning of your applications may also be affected. A tradeoff that limits the risk of missteering is probably the correct choice. On the other hand, a lack of synchronization can cause issues in a distributed system. Such systems require a small upper bound on the time difference between the machines they run on. When time synchronization fails the clocks can quickly drift outside of these bounds and the system may fail. Furthermore it may be most important that the machines are synchronized with each other, not necesarilly that they use the true time. Configuring ntpd-rs for maximum availability seems the best approach for this scenario. Since there is no universally best solution to this tradeoff, you as the end user will have to consider which of these factors weighs more heavily, and adjust your configuration accordingly. ## Limiting incorrect steering Ntpd-rs can query multiple remote time servers for the current time. This allows it to detect and discard outliers that provide an incorrect time. The synchronization algorithm always requires a strict majority of the reachable servers (those that it is able to actively communicate with) to agree on the current time before making adjustments to the clock. Furthermore, to prevent an attacker to just reduce the available servers to only its own through denial of service attacks, the minimum number of agreeing servers can also be configured through `minimum-agreeing-sources`. In its operation, ntpd-rs influences the clock in two ways: * **frequency adjustment:** ntdp-rs can adjust the clock frequency to compensate for hardware inaccuracies and to slowly correct small offsets to the system clock. This process can change the clock by in the worst case at most $1000$ microseconds every second, meaning that any incorrect steering of frequency will need at least 1000 days to reach an offset of 1 day. * **step adjustment** the second method of steering is stepping the clock. This allows for compensation of larger errors, but also provides more opportunity to an attacker for introducing large errors to the system clock. Frequency adjustments are essentially impossible to exploit by an attacker. The threat lies in big step adjustments. To prevent incorrect step adjustments, ntpd-rs allows the configuration of step limits. When these limits are exceeded, the daemon assumes that an unrecoverable problem has occurred and aborts. That means no synchronization will occur and the system's time will drift. The step limits come in three variants: - `single-step-panic-threshold` sets limits on any individual step during operations. Use of this can limit the maximum change to the clock induced in one operation. - `startup-step-panic-threshold` is applied instead of the `single-step-panic-threshold` during the first clock correction after startup. Its main use is to allow systems with a poor or no real time clock to still properly synchronize their time on startup, even when a very strict `single-step-panic-threshold` is in place. - `accumulated-step-panic-threshold` limits the maximum adjustment made through all clock steps combined over the time the daemon is running. It can be used to provide protection against circumvention of the step panic threshold through repeated steps just below the `single-step-panic-threshold`. What values to choose for these thresholds depends on what the expected maximum offset of the system clock will be during normal operations and startup. Again, note that the thresholds are enforced through ntpd-rs aborting when they are exceeded. Hence, strict values for these will limit the daemons ability to automatically adjust to sudden changes to the clock, potentially decreasing availability of the time synchronization. ### The risks of rebooting ntpd-rs Because the `startup-step-panic-threshold` is typically higher than the `single-step-panic-threshold`, rebooting ntpd-rs makes bigger step adjustments possible. Furthermore, rebooting clears the total accumulated step, and repeated reboots can allow an attacker to bypass the protections offered by `accumulated-step-panic-threshold`. For these reasons we recommend to not automatically restart ntpd-rs. Rather, an administrator should check on a stopped ntpd-rs process to determine whether a restart is benign at the current point in time or if it could worsen an ongoing attack. In the latter case, the attack must first be mitigated before allowing the ntpd-rs daemon to restart. ## Increasing availability The best way to increase availability of time synchronization is to increase the number of servers ntpd-rs queries for the current time. When combined with a (relatively) small value for `minimum-agreeing-sources`, this will allow ntpd-rs to keep synchronizing the local time even if multiple upstream servers fail. For servers being completely unavailable, this is the difference between the number of configured time sources and `minimum-agreeing-sources`. However, note that at most half the servers can fail with incorrect time information before impacting time synchronization. The downside of a large number of upstream time servers is that an attacker aimed at missteering your local clock is provided with more avenues to do so, because they will need to compromise a smaller fraction of upstream servers to gain clock control. The attacker can then ensure synchronization with that subset through denial of service attacks on the other upstream servers. ## Configuration, logs and observability There are more aspects of ntpd-rs besides clock steering that must be considered for secure operations. The clock steering is based on the ntpd-rs configuration file. If an attacker can modify this configuration file, all protections configured in it are meaningless. We recommend that operating system facilities (e.g. permissions) be used to restrict who can edit the configuration and, depending on what threats are expected, who can read it. Similarly, for logs it is recommended to restrict who can read the logs. It is also strongly advisable to configure log rotation and limits on the maximum size of the log through the systems logging facilities, to prevent logs from accidentally becoming so large as to impede normal system operation. When configured with a `log-level` of info or higher, the daemon should not log in direct response to random network traffic. However, log output is proportional to the number of remote time sources configured. Furthermore, the ntpd-rs daemon can be configured to expose two sockets: - The observe socket is read-only and exposes some of the source and clock algorithm state. - The configuration socket accepts commands and allows changing of some of the configuration settings. When enabled, these sockets are by default exposed with quite generous permissions (`0o666` for observation and `0o660` for configuration). For a hardened setup, it may be desirable to further restrict access to these sockets, or to leave them disabled. The configuration allows stricter permissions for these sockets to be configured through the `observation-permissions` and `configure-permissions` options. ntpd-1.1.2/docs/guide/server-setup.md000064400000000000000000000031221046102023000156030ustar 00000000000000# Setting up an NTP server By default, ntpd-rs only acts as an ntp client, and doesn't serve time on any network interface. To enable nptd-rs as a server, the following can be added to the configuration: ```toml [[server]] listen = "0.0.0.0:123" ``` This will cause ntpd-rs to listen on all network interfaces on udp port 123 for ntp client requests. If you only want to listen on a specific network interface, change `0.0.0.0` to the ip address of that interface. You can now configure a different machine to use your new server by adding to its configuration: ```toml [[source]] mode = "server" address = ":123" ``` ## Limiting access If you only want specific ip addresses to be able to access the server, you can configure a list of allowed clients through the allowlist mechanism. For this, edit the server configuration to look like: ```toml [[server]] listen = "0.0.0.0:123" [server.allowlist] filter = ["/32", "/32", "/128"] action = "ignore" ``` When configured this way, your server will only respond to the listed ip addresses. You can allow entire subnets at a time by specifying the size of the subnet instead of 32 or 128 after the slash. ## Adding your server to the NTP pool If your ntp server has a public IP address, you can consider making it available as part of the [NTP pool](https://www.ntppool.org). Please note that this can have significant long-term impact in terms of NTP traffic to that particular IP address. Please read [the join instructions](https://www.ntppool.org/en/join.html) carefully before joining the pool. ntpd-1.1.2/docs/includes/glossary.md000064400000000000000000000004161046102023000155160ustar 00000000000000*[NTS-KE]: NTS Key Exchange *[NTP]: Network Time Protocol *[NTS]: Network Time Security *[TLS]: Transport Layer Security *[TCP]: Transmission Control Protocol *[UDP]: User Datagram Protocol *[CA]: Certificate Authority *[OS]: Operating System *[DNS]: Domain Name System ntpd-1.1.2/docs/index.md000064400000000000000000000013041046102023000131510ustar 00000000000000# ntpd-rs Welcome to ntpd-rs, a full-featured NTP server and client implementation, including NTS support. The documentation is divided into several sections. For new users of ntpd-rs we recommend to start with the [getting started guide][1]. If you already have experience with other NTP software, you may want to start with one of the specific migration guides in the *Guide* section of the documentation. If you are looking for a reference level explanation of functions in ntpd-rs we recommend looking at the *Man Pages* section. Finally, if you are looking at how ntpd-rs development is organized, please take a look at the *Development* section of the documentation. [1]: ./guide/getting-started.md ntpd-1.1.2/docs/man/ntp-ctl.8.md000064400000000000000000000026441046102023000143540ustar 00000000000000 # NAME `ntp-ctl` - management client for the ntpd-rs ntp-daemon process # SYNOPSIS `ntp-ctl` validate [`-c` *path*] \ `ntp-ctl` status [`-f` *format*] [`-c` *path*] \ `ntp-ctl` `-h` \ `ntp-ctl` `-v` # DESCRIPTION The `ntp-ctl` management client allows management of some aspects of the ntpd-rs daemon. Currently the management client only allows displaying the current status of the daemon and validating a configuration file for usage with the daemon. # OPTIONS `-c` *path*, `--config`=*path* : Path to the configuration file from which the observation socket address will be retrieved. If not specified this defaults to `/etc/ntpd-rs/ntp.toml`. `-f` *format*, `--format`=*format* : The output format for the status command. If not specified this defaults to *plain*. Alternatively the format *prometheus* is available to display the output in an OpenMetrics/Prometheus compatible format. `-h`, `--help` : Display usage instructions. `-v`, `--version` : Display version information. # COMMANDS `validate` : Checks if the configuration specified (or `/etc/ntpd-rs/ntp.toml` by default) is valid. `status` : Returns status information about the current state of the ntp-daemon that the client connects to. # SEE ALSO [ntp-daemon(8)](ntp-daemon.8.md), [ntp-metrics-exporter(8)](ntp-metrics-exporter.8.md), [ntp.toml(5)](ntp.toml.5.md) ntpd-1.1.2/docs/man/ntp-daemon.8.md000064400000000000000000000026651046102023000150400ustar 00000000000000 # NAME `ntp-daemon` - ntpd-rs Network Time Protocol service daemon # SYNOPSIS `ntp-daemon` [`-c` *path*] [`-l` *loglevel*] \ `ntp-daemon` `-h` \ `ntp-daemon` `-v` # DESCRIPTION `ntp-daemon` is the Network Time Protocol (NTP) service daemon for ntpd-rs, an NTP implementation with a focus on security and stability. The `ntp-deamon` can be configured as both an NTP client and an NTP server. The daemon also works with the Network Time Security (NTS) protocol. Details of the configuration of the daemon and implementation details can be found in ntp.toml(5), where several concepts of the ntp-daemon are also explained. # OPTIONS `-c` *path*, `--config`=*path* : The configuration file path for the ntp-daemon where settings for the configuration of ntpd-rs are stored. If not specified the default configuration file is `/etc/ntpd-rs/ntp.toml`. `-h`, `--help` : Display usage instructions. `-l` *loglevel*, `--log-level`=*loglevel* : Change which log messages are logged to stdout. Available log levels are *trace*, *debug*, *info*, *warn* and *error* (from lower to higher priority). Only messages with the given priority and higher will be displayed. The default log level is *info*. `-v`, `--version` : Display version information. # SEE ALSO [ntp-ctl(8)](ntp-ctl.8.md), [ntp-metrics-exporter(8)](ntp-metrics-exporter.8.md), [ntp.toml(5)](ntp.toml.5.md) ntpd-1.1.2/docs/man/ntp-metrics-exporter.8.md000064400000000000000000000014601046102023000171010ustar 00000000000000 # NAME `ntp-metrics-exporter` - Prometheus/OpenMetrics exporter for the ntpd-rs daemon # SYNOPSIS `ntp-metrics-exporter` [`-c` *path*] \ `ntp-metrics-exporter` `-h` \ `ntp-metrics-exporter` `-v` # DESCRIPTION Exports the status metrics from the ntpd-rs daemon as Prometheus/OpenMetrics via an HTTP socket. # OPTIONS `-c` *path*, `--config`=*path* : Path to the configuration file where the observation socket path for connecting with the ntp-daemon is specified. This defaults to `/etc/ntpd-rs/ntp.toml` if not specified. `-h`, `--help` : Display usage instructions. `-v`, `--version` : Display version information. # SEE ALSO [ntp-daemon(8)](ntp-daemon.8.md), [ntp-ctl(8)](ntp-ctl.8.md), [ntp.toml(5)](ntp.toml.5.md) ntpd-1.1.2/docs/man/ntp.toml.5.md000064400000000000000000000467561046102023000145570ustar 00000000000000 # NAME `ntp.toml` - configuration file for the ntpd-rs ntp-daemon # DESCRIPTION Configuration of ntpd-rs happens in the `ntp.toml` configuration format. The toml format is in lots of ways similar to a simple ini with several extensions allowing a json-like syntax. The ntpd-rs configuration file consists of several sections, each of which configuring a separate part of the ntp-daemon process. Each of the secions is described in the rest of this document. Many settings will have defaults, which will be indicated by each configuration setting shown. The ntp daemon only supports unicast client-server connections. Most NTP traffic, especially across the public internet, almost exclusively uses this mode, so it is not considered a practical limitation for most scenarios. # SOURCE MODES Different types of sources (see the section below for details) are supported by the ntp daemon. To set the type of the source, you can configure the mode field with any of these options: `server` : A server source connects to a single specific NTP server. If a connection is lost, attempts will be made to reconnect to the source. `pool` : A pool source retrieves multiple NTP servers by resolving a hostname via DNS. It then attempts to connect to multiple of these servers at the same time. If a connection is lost, a new server will be retrieved from the pool. `nts` : Connect to a single Network Time Security (NTS) source. The NTS protocol uses a TLS handshake to exchange secrets with a server to allow verifying that NTP messages have not been tampered with. Note that the TLS protocol requires that both the client and server have a rough idea of the current time. # CONFIGURATION ## `[source-defaults]` Some values are shared between all sources in the daemon. You can configure these in the `[source-defaults]` section. `poll-interval-limits` = { `min` = *min*, `max` = *max* } (**{ min = 4, max = 10}**) : Specifies the limit on how often a source is queried for a new time. For most instances the defaults will be adequate. The min and max are given as the log2 of the number of seconds (i.e. two to the power of the interval). An interval of 4 equates to 32 seconds, 10 results in an interval of 1024 seconds. If specified, both min and max must be specified. `initial-poll-interval` = *interval* (**4**) : Initial poll interval used on startup. The value is given as the log2 of the number of seconds (i.e. two to the power of the interval). The default value of 4 results in an interval of 32 seconds. ## `[[source]]` Each `[[source]]` is a set of one or more time sources for the daemon to retrieve time information from. Any number of sources can be configured by repeating a `[[source]]` section (note the double brackets) for as many times as required. Each source can be configured to connect to a specific remote location. Multiple modes for connecting to sources are supported. If less than `minimum-agreeing-sources` time sources have been configured, no time will be synchronized to the local clock. Note that a pool counts as multiple time sources. `mode` = *mode* : Specify one of the source modes that ntpd-rs supports: `server`, `pool` or `nts`. For a description of the different source modes, see the *SOURCE MODES* section. `address` = *address* : Specify the remote address of the source. For server sources this will be the remote address of the NTP server. For pools, this will be the DNS address of the NTP pool and for nts this will be the address of the key exchange server. The server address may include a port number by appending a colon (`:`) followed by a port number. If not specified the daemon will connect to `server` and `pool` servers via port *123*, for `nts` sources the default port is *4460*. `certificate-authority` = *cert* : Can only be set on sources with the `nts` mode. Path to a certificate for an additional certificate authority to use, aside from the certificate authorities specified by the system configuration. Note that this cannot be used to specify a self signed certificate. `count` = *number* (**4**) : Can only be set on sources with the `pool` mode. Specifies the maximum number of servers that the daemon will attempt to connect to from a pool. The daemon will keep retrying to get more sources from the pool when connections are lost, up to the maximum specified by this configuration value. ## `[[server]]` The NTP daemon can be configured to distribute time via any number of `[[server]]` sections. If no such sections have been defined, the daemon runs in a client only mode. Any number of servers can be configured by repeating the `[[server]]` section (note the double brackets) for as many times as required. Each server can serve a specific socket address or listen on all available network interfaces on a specific port. Servers always serve the system clock time. `listen` = *socketaddr* : Address of a UDP socket on which the server should listen for incoming NTP requests. Specified as an interface IP address, a colon and a port number. The standard port number for NTP is UDP port 123. Both IPv4 and IPv6 are supported. For example to listen on localhost port 123 in IPv4 you can use `127.0.0.1:123`. You can listen on all available network interfaces at once using `0.0.0.0:123` for IPv4 or `[::]:123` for IPv6. `rate-limiting-cache-size` = *size* (**0**) : Number of elements in the rate limiting cache. At most *size* elements are kept in the cache. This means that if more than *size* different clients attempt to connect to the server too frequently, the cache size will have reduced functionality, as rate limiting information gets lost when new clients connect to the server. If set to zero, the cache is unused, this is the default. `rate-limiting-cutoff-ms` = *cutoff* (**0**) : Minimum time between two requests from the same client, if a request was sent sooner than the cutoff time, the client will be asked to slow down their requests by the server responding with a packet with the NTP `RATE` kiss code. No actual time measurement will be returned to the client in that case. If set to zero, no rate limiting is applied, this is the default. `allowlist` = { filter = [ *subnet*, .. ], action = `"deny"` | `"ignore"` } (**unset**) : Only allow any number of filtered *subnets* to connect to the daemon. Any IP that matches one of the subnets specified is allowed to contact this server. The subnets must be specified in CIDR notation (an IP address followed by a slash and the number of masked bits, for example `127.0.0.1/8` or `192.168.1.1/24`). The action determines what measure is taken for IP addresses not in any of the specified subnets. When `deny`, an explicit packet with the NTP `DENY` kiss code is returned to the sender indicating that they are not allowed to do so. When `ignore` is specified, messages are discarded with no response sent. The default value is equivalent to allowing any IP address, and would be equivalent to setting the filter to `["0.0.0.0/0", "::/0"]`, with either action. `denylist` = { filter = [ *subnet*, .. ], action = `"deny"` | `"ignore"` } (**unset**) : Do not allow any number of filtered *subnets* to connect to the daemon. Any IP that matches one of the subnets specified is not allowed to contact this server. The subnets must be specified in CIDR notation (an IP address followed by a slash and the number of masked bits, for example `127.0.0.1/8` or `192.168.1.1/24`). The action determines what measure is taken for IP addresses in any of the specified subnets. When `deny`, an explicit packet with the NTP `DENY` kiss code is returned to the sender indicating that they are not allowed to do so. When `ignore` is specified, messages are discarded with no response sent. The default value is equivalent to allowing any IP address, and would be equivalent to setting the filter to `[]`, with either action. ## `[observability]` Settings in this section configure how you can observe the behavior of the daemon. Currently the daemon can be observed either through the logs or by retrieving several key metrics either through ntp-ctl(8) or through ntp-metrics-exporter(8). `log-level` = `"trace"` | `"debug"` | `"info"` | `"warn"` | `"error"` (**unset**) : Set the logging level for messages printed to stdout. The lowest level `trace` gives very detailed information about anything going on in the daemon, whereas the highest level `error` only logs error conditions in the daemon. Levels higher than the given log level are logged as well. If not set (the default), then logging will be completely disabled. `observation-path` = *path* (**unset**) : Path where the daemon will create an observation unix domain socket. This socket is used by `ntp-ctl` and `ntp-metrics-exporter` to read the current status of the daemon. If not set (the default) no observation socket will be created and it is not possible to use `ntp-ctl` or `ntp-metrics-exporter` to observe the daemon. `observation-permissions` = *mode* (**0o666**) : The file system permissions with which the observation socket should be created. Warning: You should always write this number with the octal prefix `0o`, otherwise your permissions might be interpreted wrongly. The default should be ok for most applications however. `metrics-exporter-listen` = *socketaddr* (**127.0.0.1:9975**) : The listen address that is used for the ntp-metrics-exporter(8). ## `[keyset]` The keyset configures the internal key infrastructure for NTS packets. Note that this is separate from the TLS certificate and private key, for those see the relevant configuration in the `[[nts-ke-server]]` section. `stale-key-count` = *count* (**7**) : Maximum number of old keys to retain in the cache. Whenever keys are rotated the old keys will become invalid, but clients may still have NTS cookies encrypted with any of the old keys. `key-rotation-interval` = *seconds* (**86400**) : Time between key rotation events. Every time *seconds* elapses, a new internal key will be generated for creating NTS cookies. By default this is set to a day. `key-storage-path` = *path* (**unset**) : If set, stores the internal NTS keys in the file indicated by *path*. This allows keys to survive a server reboot. If not set, clients using NTS may need to redo a key exchange operation to get new NTS cookies. ## `[[nts-ke-server]]` The daemon can be configured to operate as an NTS key exchange server by repeating any number of `[[nts-ke-server]]` sections. If no such sections have been defined, the daemon will offer no NTS key exchange services. All NTS-KE servers make use of the shared keyset. It is the purpose of the key exchange server to distribute cookies to clients in a safe way. These cookies can then be used in NTP packets with the normal server to validate that the traffic was untampered with. `listen` = *socket* : Address of a TCP socket on which the server should listen for incoming NTS key exchange requests. Specified as an interface IP address, a colon and a port number. The standard port number for an NTS key exchange server is TCP port 4460. Both IPv4 and IPv6 are supported. For example to listen on localhost port 4460 in IPv4 you can use `127.0.0.1:4460`. You can listen on all available network interfaces at once using `0.0.0.0:4460` for IPv4 or `[::]:4460` for IPv6. `certificate-chain-path` = *path* : Path to a certificate chain for the public certificate that the server offers to clients. `private-key-path` = *path* : Path to the private key associated with the server certificate in the certificate chain. `key-exchange-timeout-ms` = *timeout* (**1000**) : Timeout in milliseconds for how long a key exchange may take. If the timeout is exceeded the connection will be dropped. `ntp-port` = *port* Port number the key exchange server should instruct clients to use. Should be used when the port number of the NTP server is not the default. `ntp-server` = *server-name* Server address (either as ip or as domain name) where clients can find the NTP server. Should be used when this name does not match the name of the NTS key exchange server. ## `[synchronization]` This section of the configuration focusses on how the time information from the time sources is gathered and applied to the system clock. `minimum-agreeing-sources` = *count* (**3**) : The minimum number of sources that should agree on the current time before the daemon does any steering operation on the clock. Note that if you have configured fewer than this amount of sources, this may result in the daemon never updating the clock. `single-step-panic-threshold` = *seconds* | { `forward` = *forward*, `backward` = *backward* } (**1000**) : The threshold in seconds at which the daemon will completely exit (i.e. panic) when a single non-startup step occurs. Generally during normal operation the clock on your system should run somewhat close to the time it is synchronized to. As such, it is highly unlikely that such a large step will take place, and the daemon will exit to prevent any accidental mistakes. If set to the value `"inf"`, any step will be allowed. May either be configured as one number of seconds for both forward and backward steps, or separate values for forward and backward steps. `startup-step-panic-threshold` = *seconds* | { `forward` = *forward*, `backward` = *backward* } (**{ forward = "inf", backward = "86400" }**) : The threshold in seconds at which the daemon will completely exit (i.e. panic) when a step occurs at startup. The default allows any forward step, but prevents backward steps larger than a single day. Generally computer clocks that are not synchronized will run behind the true time, instead of running ahead. If a computer is running ahead and steps back a large time this generally indicates a problem. If set to the value `"inf"`, any step will be allowed. May either be configured as one number of seconds for both forward and backward steps, or separate values for forward and backward steps. `accumulated-step-panic-threshold` = *seconds* (**unset**) : Every time the daemon steps the time instead of slowly adjusting the clock by using frequency changes, this counter is increased by the absolute value of the step (i.e. both forward and backward steps are counted). When this threshold is reached, the daemon will exit immediately (i.e. panic). During normal operation steps are unlikely to occur, and as such, steps may indicate that someone or something is triggering illicit steps. By default however this panic mechanism is disabled. Is disabled if left unset or if set to the value `0`. `local-stratum` = *stratum* (**16**) : Sets the NTP clock stratum of the system clock when no NTP time sources have been configured, or when the time has not yet been synchronized from an NTP time source. Can be used in servers to indicate that there are external mechanisms synchronizing the clock. ## `[synchronization.algorithm]` Warning: the algorithm section contains mostly internal algorithm tweaks that generally do not need to be changed. However, they are offered here for specific use cases. These settings are considered implementation details however, and as such may change in future ntpd-rs versions. `precision-low-probability` = *probability* (**1/3**) : Probability bound below which we start moving towards decreasing our precision estimate. Unit: probability, 0-1 `precision-high-probability` = *probability* (**2/3**) : Probability bound above which we start moving towards increasing our precision estimate. Unit: probability, 0-1 `precision-hysteresis` = *hysteresis* (**16**) : Amount of hysteresis in changing the precision estimate. Unit: count, 1+ `precision-minimum-weight` = *weight* (**0.1**) : Lower bound on the amount of effect our precision estimate has on the total noise estimate before we allow decreasing of the precision estimate. Unit: weight, 0-1 `poll-interval-low-weight` = *weight* (**0.4**) : Amount which a measurement contributes to the state, below which we start increasing the poll interval. Unit: weight, 0-1 `poll-interval-high-weight` = *weight* (**0.6**) : Amount which a measurement contributes to the state, above which we start decreasing the poll-interval interval. Unit: weight, 0-1 `poll-interval-hysteresis` = *hysteresis* (**16**) : Amount of hysteresis in changing the poll interval. Unit: count, 1+ `poll-interval-step-threshold` = *threshold* (**1e-6**) : Probability threshold for when a measurement is considered a significant enough outlier that we decide something weird is going on and we need to do more measurements. Unit: probability, 0-1 `delay-outlier-threshold` = *threshold* (**5.0**) : Threshold (in number of standard deviations) above which measurements with a significantly larger network delay are rejected. Unit: standard deviations, 0+ `initial-wander` = *wander* (**1e-8**) : Initial estimate of the clock wander of the combination of our local clock and that of the source. Unit: s/s^2 `initial-frequency-uncertainty` = *uncertainty* (**100e-6**) : Initial uncertainty of the frequency difference between our clock and that of the source. Unit: s/s `maximum-source-uncertainty` = *uncertainty* (**0.25**) : Maximum source uncertainty before we start disregarding it. Note that this is combined uncertainty due to noise and possible assymetry error (see also weights below). Unit: seconds `range-statistical-weight` = *weight* (**2.0**) : Weight of statistical uncertainty when constructing overlap ranges. Unit: standard deviations, 0+ `range-delay-weight` = *weight* (**0.25**) : Weight of delay uncertainty when constructing overlap ranges. Unit: weight, 0-1 `steer-offset-threshold` = *threshold* (**2.0**) : How far from 0 (in multiples of the uncertainty) should the offset be before we correct. Unit: standard deviations, 0+ `steer-offset-leftover` = *stddev* (**1.0**) : How many standard deviations do we leave after offset correction? Unit: standard deviations, 0+ `steer-frequency-threshold` = *threshold* (**0.0**) : How far from 0 (in multiples of the uncertainty) should the frequency estimate be before we correct. Unit: standard deviations, 0+ `steer-frequency-leftover` = *stddev* (**0.0**) : How many standard deviations do we leave after frequency correction? Unit: standard deviations, 0+ `step-threshold` = *threshold* (**0.010**) : From what offset should we step the clock instead of trying to adjust gradually? Unit: seconds, 0+ `slew-maximum-frequency-offset` = *offset* (**200e-6**) : What is the maximum frequency offset during a slew. Unit: s/s `slew-minimum-duration` = *duration* (**495e-6**) : What is the minimum duration of a slew. Unit: seconds `maximum-frequency-steer` = *frequency* (**8.0**) : Absolute maximum frequency correction. Unit: s/s `ignore-server-dispersion` = *bool* (**false**) : Ignore a servers advertised dispersion when synchronizing. Can improve synchronization quality with servers reporting overly conservative root dispersion. `meddling-threshold` = *threshold* (**5.0**) : Threshold for detecting external clock meddling. Unit: seconds # SEE ALSO [ntp-daemon(8)](ntp-daemon.8.md), [ntp-ctl(8)](ntp-ctl.8.md), [ntp-metrics-exporter(8)](ntp-metrics-exporter.8.md) ntpd-1.1.2/docs/precompiled/man/ntp-ctl.8000064400000000000000000000036221046102023000162550ustar 00000000000000.\" Automatically generated by Pandoc 3.1.1 .\" .\" Define V font for inline verbatim, using C font in formats .\" that render this, and otherwise B font. .ie "\f[CB]x\f[]"x" \{\ . ftr V B . ftr VI BI . ftr VB B . ftr VBI BI .\} .el \{\ . ftr V CR . ftr VI CI . ftr VB CB . ftr VBI CBI .\} .TH "NTP-CTL" "8" "" "ntpd-rs 1.1.2" "ntpd-rs" .hy .SH NAME .PP \f[V]ntp-ctl\f[R] - management client for the ntpd-rs ntp-daemon process .SH SYNOPSIS .PP \f[V]ntp-ctl\f[R] validate [\f[V]-c\f[R] \f[I]path\f[R]] .PD 0 .P .PD \f[V]ntp-ctl\f[R] status [\f[V]-f\f[R] \f[I]format\f[R]] [\f[V]-c\f[R] \f[I]path\f[R]] .PD 0 .P .PD \f[V]ntp-ctl\f[R] \f[V]-h\f[R] .PD 0 .P .PD \f[V]ntp-ctl\f[R] \f[V]-v\f[R] .SH DESCRIPTION .PP The \f[V]ntp-ctl\f[R] management client allows management of some aspects of the ntpd-rs daemon. Currently the management client only allows displaying the current status of the daemon and validating a configuration file for usage with the daemon. .SH OPTIONS .TP \f[V]-c\f[R] \f[I]path\f[R], \f[V]--config\f[R]=\f[I]path\f[R] Path to the configuration file from which the observation socket address will be retrieved. If not specified this defaults to \f[V]/etc/ntpd-rs/ntp.toml\f[R]. .TP \f[V]-f\f[R] \f[I]format\f[R], \f[V]--format\f[R]=\f[I]format\f[R] The output format for the status command. If not specified this defaults to \f[I]plain\f[R]. Alternatively the format \f[I]prometheus\f[R] is available to display the output in an OpenMetrics/Prometheus compatible format. .TP \f[V]-h\f[R], \f[V]--help\f[R] Display usage instructions. .TP \f[V]-v\f[R], \f[V]--version\f[R] Display version information. .SH COMMANDS .TP \f[V]validate\f[R] Checks if the configuration specified (or \f[V]/etc/ntpd-rs/ntp.toml\f[R] by default) is valid. .TP \f[V]status\f[R] Returns status information about the current state of the ntp-daemon that the client connects to. .SH SEE ALSO .PP ntp-daemon(8), ntp-metrics-exporter(8), ntp.toml(5) ntpd-1.1.2/docs/precompiled/man/ntp-daemon.8000064400000000000000000000036301046102023000167350ustar 00000000000000.\" Automatically generated by Pandoc 3.1.1 .\" .\" Define V font for inline verbatim, using C font in formats .\" that render this, and otherwise B font. .ie "\f[CB]x\f[]"x" \{\ . ftr V B . ftr VI BI . ftr VB B . ftr VBI BI .\} .el \{\ . ftr V CR . ftr VI CI . ftr VB CB . ftr VBI CBI .\} .TH "NTP-DAEMON" "8" "" "ntpd-rs 1.1.2" "ntpd-rs" .hy .SH NAME .PP \f[V]ntp-daemon\f[R] - ntpd-rs Network Time Protocol service daemon .SH SYNOPSIS .PP \f[V]ntp-daemon\f[R] [\f[V]-c\f[R] \f[I]path\f[R]] [\f[V]-l\f[R] \f[I]loglevel\f[R]] .PD 0 .P .PD \f[V]ntp-daemon\f[R] \f[V]-h\f[R] .PD 0 .P .PD \f[V]ntp-daemon\f[R] \f[V]-v\f[R] .SH DESCRIPTION .PP \f[V]ntp-daemon\f[R] is the Network Time Protocol (NTP) service daemon for ntpd-rs, an NTP implementation with a focus on security and stability. The \f[V]ntp-deamon\f[R] can be configured as both an NTP client and an NTP server. The daemon also works with the Network Time Security (NTS) protocol. Details of the configuration of the daemon and implementation details can be found in ntp.toml(5), where several concepts of the ntp-daemon are also explained. .SH OPTIONS .TP \f[V]-c\f[R] \f[I]path\f[R], \f[V]--config\f[R]=\f[I]path\f[R] The configuration file path for the ntp-daemon where settings for the configuration of ntpd-rs are stored. If not specified the default configuration file is \f[V]/etc/ntpd-rs/ntp.toml\f[R]. .TP \f[V]-h\f[R], \f[V]--help\f[R] Display usage instructions. .TP \f[V]-l\f[R] \f[I]loglevel\f[R], \f[V]--log-level\f[R]=\f[I]loglevel\f[R] Change which log messages are logged to stdout. Available log levels are \f[I]trace\f[R], \f[I]debug\f[R], \f[I]info\f[R], \f[I]warn\f[R] and \f[I]error\f[R] (from lower to higher priority). Only messages with the given priority and higher will be displayed. The default log level is \f[I]info\f[R]. .TP \f[V]-v\f[R], \f[V]--version\f[R] Display version information. .SH SEE ALSO .PP ntp-ctl(8), ntp-metrics-exporter(8), ntp.toml(5) ntpd-1.1.2/docs/precompiled/man/ntp-metrics-exporter.8000064400000000000000000000022721046102023000210070ustar 00000000000000.\" Automatically generated by Pandoc 3.1.1 .\" .\" Define V font for inline verbatim, using C font in formats .\" that render this, and otherwise B font. .ie "\f[CB]x\f[]"x" \{\ . ftr V B . ftr VI BI . ftr VB B . ftr VBI BI .\} .el \{\ . ftr V CR . ftr VI CI . ftr VB CB . ftr VBI CBI .\} .TH "NTP-METRICS-EXPORTER" "8" "" "ntpd-rs 1.1.2" "ntpd-rs" .hy .SH NAME .PP \f[V]ntp-metrics-exporter\f[R] - Prometheus/OpenMetrics exporter for the ntpd-rs daemon .SH SYNOPSIS .PP \f[V]ntp-metrics-exporter\f[R] [\f[V]-c\f[R] \f[I]path\f[R]] .PD 0 .P .PD \f[V]ntp-metrics-exporter\f[R] \f[V]-h\f[R] .PD 0 .P .PD \f[V]ntp-metrics-exporter\f[R] \f[V]-v\f[R] .SH DESCRIPTION .PP Exports the status metrics from the ntpd-rs daemon as Prometheus/OpenMetrics via an HTTP socket. .SH OPTIONS .TP \f[V]-c\f[R] \f[I]path\f[R], \f[V]--config\f[R]=\f[I]path\f[R] Path to the configuration file where the observation socket path for connecting with the ntp-daemon is specified. This defaults to \f[V]/etc/ntpd-rs/ntp.toml\f[R] if not specified. .TP \f[V]-h\f[R], \f[V]--help\f[R] Display usage instructions. .TP \f[V]-v\f[R], \f[V]--version\f[R] Display version information. .SH SEE ALSO .PP ntp-daemon(8), ntp-ctl(8), ntp.toml(5) ntpd-1.1.2/docs/precompiled/man/ntp.toml.5000064400000000000000000000520401046102023000164420ustar 00000000000000.\" Automatically generated by Pandoc 3.1.1 .\" .\" Define V font for inline verbatim, using C font in formats .\" that render this, and otherwise B font. .ie "\f[CB]x\f[]"x" \{\ . ftr V B . ftr VI BI . ftr VB B . ftr VBI BI .\} .el \{\ . ftr V CR . ftr VI CI . ftr VB CB . ftr VBI CBI .\} .TH "NTP.TOML" "5" "" "ntpd-rs 1.1.2" "ntpd-rs" .hy .SH NAME .PP \f[V]ntp.toml\f[R] - configuration file for the ntpd-rs ntp-daemon .SH DESCRIPTION .PP Configuration of ntpd-rs happens in the \f[V]ntp.toml\f[R] configuration format. The toml format is in lots of ways similar to a simple ini with several extensions allowing a json-like syntax. .PP The ntpd-rs configuration file consists of several sections, each of which configuring a separate part of the ntp-daemon process. Each of the secions is described in the rest of this document. Many settings will have defaults, which will be indicated by each configuration setting shown. .PP The ntp daemon only supports unicast client-server connections. Most NTP traffic, especially across the public internet, almost exclusively uses this mode, so it is not considered a practical limitation for most scenarios. .SH SOURCE MODES .PP Different types of sources (see the section below for details) are supported by the ntp daemon. To set the type of the source, you can configure the mode field with any of these options: .TP \f[V]server\f[R] A server source connects to a single specific NTP server. If a connection is lost, attempts will be made to reconnect to the source. .TP \f[V]pool\f[R] A pool source retrieves multiple NTP servers by resolving a hostname via DNS. It then attempts to connect to multiple of these servers at the same time. If a connection is lost, a new server will be retrieved from the pool. .TP \f[V]nts\f[R] Connect to a single Network Time Security (NTS) source. The NTS protocol uses a TLS handshake to exchange secrets with a server to allow verifying that NTP messages have not been tampered with. Note that the TLS protocol requires that both the client and server have a rough idea of the current time. .SH CONFIGURATION .SS \f[V][source-defaults]\f[R] .PP Some values are shared between all sources in the daemon. You can configure these in the \f[V][source-defaults]\f[R] section. .TP \f[V]poll-interval-limits\f[R] = { \f[V]min\f[R] = \f[I]min\f[R], \f[V]max\f[R] = \f[I]max\f[R] } (\f[B]{ min = 4, max = 10}\f[R]) Specifies the limit on how often a source is queried for a new time. For most instances the defaults will be adequate. The min and max are given as the log2 of the number of seconds (i.e.\ two to the power of the interval). An interval of 4 equates to 32 seconds, 10 results in an interval of 1024 seconds. If specified, both min and max must be specified. .TP \f[V]initial-poll-interval\f[R] = \f[I]interval\f[R] (\f[B]4\f[R]) Initial poll interval used on startup. The value is given as the log2 of the number of seconds (i.e.\ two to the power of the interval). The default value of 4 results in an interval of 32 seconds. .SS \f[V][[source]]\f[R] .PP Each \f[V][[source]]\f[R] is a set of one or more time sources for the daemon to retrieve time information from. Any number of sources can be configured by repeating a \f[V][[source]]\f[R] section (note the double brackets) for as many times as required. Each source can be configured to connect to a specific remote location. Multiple modes for connecting to sources are supported. If less than \f[V]minimum-agreeing-sources\f[R] time sources have been configured, no time will be synchronized to the local clock. Note that a pool counts as multiple time sources. .TP \f[V]mode\f[R] = \f[I]mode\f[R] Specify one of the source modes that ntpd-rs supports: \f[V]server\f[R], \f[V]pool\f[R] or \f[V]nts\f[R]. For a description of the different source modes, see the \f[I]SOURCE MODES\f[R] section. .TP \f[V]address\f[R] = \f[I]address\f[R] Specify the remote address of the source. For server sources this will be the remote address of the NTP server. For pools, this will be the DNS address of the NTP pool and for nts this will be the address of the key exchange server. The server address may include a port number by appending a colon (\f[V]:\f[R]) followed by a port number. If not specified the daemon will connect to \f[V]server\f[R] and \f[V]pool\f[R] servers via port \f[I]123\f[R], for \f[V]nts\f[R] sources the default port is \f[I]4460\f[R]. .TP \f[V]certificate-authority\f[R] = \f[I]cert\f[R] Can only be set on sources with the \f[V]nts\f[R] mode. Path to a certificate for an additional certificate authority to use, aside from the certificate authorities specified by the system configuration. Note that this cannot be used to specify a self signed certificate. .TP \f[V]count\f[R] = \f[I]number\f[R] (\f[B]4\f[R]) Can only be set on sources with the \f[V]pool\f[R] mode. Specifies the maximum number of servers that the daemon will attempt to connect to from a pool. The daemon will keep retrying to get more sources from the pool when connections are lost, up to the maximum specified by this configuration value. .SS \f[V][[server]]\f[R] .PP The NTP daemon can be configured to distribute time via any number of \f[V][[server]]\f[R] sections. If no such sections have been defined, the daemon runs in a client only mode. Any number of servers can be configured by repeating the \f[V][[server]]\f[R] section (note the double brackets) for as many times as required. Each server can serve a specific socket address or listen on all available network interfaces on a specific port. Servers always serve the system clock time. .TP \f[V]listen\f[R] = \f[I]socketaddr\f[R] Address of a UDP socket on which the server should listen for incoming NTP requests. Specified as an interface IP address, a colon and a port number. The standard port number for NTP is UDP port 123. Both IPv4 and IPv6 are supported. For example to listen on localhost port 123 in IPv4 you can use \f[V]127.0.0.1:123\f[R]. You can listen on all available network interfaces at once using \f[V]0.0.0.0:123\f[R] for IPv4 or \f[V][::]:123\f[R] for IPv6. .TP \f[V]rate-limiting-cache-size\f[R] = \f[I]size\f[R] (\f[B]0\f[R]) Number of elements in the rate limiting cache. At most \f[I]size\f[R] elements are kept in the cache. This means that if more than \f[I]size\f[R] different clients attempt to connect to the server too frequently, the cache size will have reduced functionality, as rate limiting information gets lost when new clients connect to the server. If set to zero, the cache is unused, this is the default. .TP \f[V]rate-limiting-cutoff-ms\f[R] = \f[I]cutoff\f[R] (\f[B]0\f[R]) Minimum time between two requests from the same client, if a request was sent sooner than the cutoff time, the client will be asked to slow down their requests by the server responding with a packet with the NTP \f[V]RATE\f[R] kiss code. No actual time measurement will be returned to the client in that case. If set to zero, no rate limiting is applied, this is the default. .TP \f[V]allowlist\f[R] = { filter = [ \f[I]subnet\f[R], .. ], action = \f[V]\[dq]deny\[dq]\f[R] | \f[V]\[dq]ignore\[dq]\f[R] } (\f[B]unset\f[R]) Only allow any number of filtered \f[I]subnets\f[R] to connect to the daemon. Any IP that matches one of the subnets specified is allowed to contact this server. The subnets must be specified in CIDR notation (an IP address followed by a slash and the number of masked bits, for example \f[V]127.0.0.1/8\f[R] or \f[V]192.168.1.1/24\f[R]). The action determines what measure is taken for IP addresses not in any of the specified subnets. When \f[V]deny\f[R], an explicit packet with the NTP \f[V]DENY\f[R] kiss code is returned to the sender indicating that they are not allowed to do so. When \f[V]ignore\f[R] is specified, messages are discarded with no response sent. The default value is equivalent to allowing any IP address, and would be equivalent to setting the filter to \f[V][\[dq]0.0.0.0/0\[dq], \[dq]::/0\[dq]]\f[R], with either action. .TP \f[V]denylist\f[R] = { filter = [ \f[I]subnet\f[R], .. ], action = \f[V]\[dq]deny\[dq]\f[R] | \f[V]\[dq]ignore\[dq]\f[R] } (\f[B]unset\f[R]) Do not allow any number of filtered \f[I]subnets\f[R] to connect to the daemon. Any IP that matches one of the subnets specified is not allowed to contact this server. The subnets must be specified in CIDR notation (an IP address followed by a slash and the number of masked bits, for example \f[V]127.0.0.1/8\f[R] or \f[V]192.168.1.1/24\f[R]). The action determines what measure is taken for IP addresses in any of the specified subnets. When \f[V]deny\f[R], an explicit packet with the NTP \f[V]DENY\f[R] kiss code is returned to the sender indicating that they are not allowed to do so. When \f[V]ignore\f[R] is specified, messages are discarded with no response sent. The default value is equivalent to allowing any IP address, and would be equivalent to setting the filter to \f[V][]\f[R], with either action. .SS \f[V][observability]\f[R] .PP Settings in this section configure how you can observe the behavior of the daemon. Currently the daemon can be observed either through the logs or by retrieving several key metrics either through ntp-ctl(8) or through ntp-metrics-exporter(8). .TP \f[V]log-level\f[R] = \f[V]\[dq]trace\[dq]\f[R] | \f[V]\[dq]debug\[dq]\f[R] | \f[V]\[dq]info\[dq]\f[R] | \f[V]\[dq]warn\[dq]\f[R] | \f[V]\[dq]error\[dq]\f[R] (\f[B]unset\f[R]) Set the logging level for messages printed to stdout. The lowest level \f[V]trace\f[R] gives very detailed information about anything going on in the daemon, whereas the highest level \f[V]error\f[R] only logs error conditions in the daemon. Levels higher than the given log level are logged as well. If not set (the default), then logging will be completely disabled. .TP \f[V]observation-path\f[R] = \f[I]path\f[R] (\f[B]unset\f[R]) Path where the daemon will create an observation unix domain socket. This socket is used by \f[V]ntp-ctl\f[R] and \f[V]ntp-metrics-exporter\f[R] to read the current status of the daemon. If not set (the default) no observation socket will be created and it is not possible to use \f[V]ntp-ctl\f[R] or \f[V]ntp-metrics-exporter\f[R] to observe the daemon. .TP \f[V]observation-permissions\f[R] = \f[I]mode\f[R] (\f[B]0o666\f[R]) The file system permissions with which the observation socket should be created. Warning: You should always write this number with the octal prefix \f[V]0o\f[R], otherwise your permissions might be interpreted wrongly. The default should be ok for most applications however. .TP \f[V]metrics-exporter-listen\f[R] = \f[I]socketaddr\f[R] (\f[B]127.0.0.1:9975\f[R]) The listen address that is used for the ntp-metrics-exporter(8). .SS \f[V][keyset]\f[R] .PP The keyset configures the internal key infrastructure for NTS packets. Note that this is separate from the TLS certificate and private key, for those see the relevant configuration in the \f[V][[nts-ke-server]]\f[R] section. .TP \f[V]stale-key-count\f[R] = \f[I]count\f[R] (\f[B]7\f[R]) Maximum number of old keys to retain in the cache. Whenever keys are rotated the old keys will become invalid, but clients may still have NTS cookies encrypted with any of the old keys. .TP \f[V]key-rotation-interval\f[R] = \f[I]seconds\f[R] (\f[B]86400\f[R]) Time between key rotation events. Every time \f[I]seconds\f[R] elapses, a new internal key will be generated for creating NTS cookies. By default this is set to a day. .TP \f[V]key-storage-path\f[R] = \f[I]path\f[R] (\f[B]unset\f[R]) If set, stores the internal NTS keys in the file indicated by \f[I]path\f[R]. This allows keys to survive a server reboot. If not set, clients using NTS may need to redo a key exchange operation to get new NTS cookies. .SS \f[V][[nts-ke-server]]\f[R] .PP The daemon can be configured to operate as an NTS key exchange server by repeating any number of \f[V][[nts-ke-server]]\f[R] sections. If no such sections have been defined, the daemon will offer no NTS key exchange services. All NTS-KE servers make use of the shared keyset. It is the purpose of the key exchange server to distribute cookies to clients in a safe way. These cookies can then be used in NTP packets with the normal server to validate that the traffic was untampered with. .TP \f[V]listen\f[R] = \f[I]socket\f[R] Address of a TCP socket on which the server should listen for incoming NTS key exchange requests. Specified as an interface IP address, a colon and a port number. The standard port number for an NTS key exchange server is TCP port 4460. Both IPv4 and IPv6 are supported. For example to listen on localhost port 4460 in IPv4 you can use \f[V]127.0.0.1:4460\f[R]. You can listen on all available network interfaces at once using \f[V]0.0.0.0:4460\f[R] for IPv4 or \f[V][::]:4460\f[R] for IPv6. .TP \f[V]certificate-chain-path\f[R] = \f[I]path\f[R] Path to a certificate chain for the public certificate that the server offers to clients. .TP \f[V]private-key-path\f[R] = \f[I]path\f[R] Path to the private key associated with the server certificate in the certificate chain. .TP \f[V]key-exchange-timeout-ms\f[R] = \f[I]timeout\f[R] (\f[B]1000\f[R]) Timeout in milliseconds for how long a key exchange may take. If the timeout is exceeded the connection will be dropped. .PP \f[V]ntp-port\f[R] = \f[I]port\f[R] Port number the key exchange server should instruct clients to use. Should be used when the port number of the NTP server is not the default. .PP \f[V]ntp-server\f[R] = \f[I]server-name\f[R] Server address (either as ip or as domain name) where clients can find the NTP server. Should be used when this name does not match the name of the NTS key exchange server. .SS \f[V][synchronization]\f[R] .PP This section of the configuration focusses on how the time information from the time sources is gathered and applied to the system clock. .TP \f[V]minimum-agreeing-sources\f[R] = \f[I]count\f[R] (\f[B]3\f[R]) The minimum number of sources that should agree on the current time before the daemon does any steering operation on the clock. Note that if you have configured fewer than this amount of sources, this may result in the daemon never updating the clock. .TP \f[V]single-step-panic-threshold\f[R] = \f[I]seconds\f[R] | { \f[V]forward\f[R] = \f[I]forward\f[R], \f[V]backward\f[R] = \f[I]backward\f[R] } (\f[B]1000\f[R]) The threshold in seconds at which the daemon will completely exit (i.e. panic) when a single non-startup step occurs. Generally during normal operation the clock on your system should run somewhat close to the time it is synchronized to. As such, it is highly unlikely that such a large step will take place, and the daemon will exit to prevent any accidental mistakes. If set to the value \f[V]\[dq]inf\[dq]\f[R], any step will be allowed. May either be configured as one number of seconds for both forward and backward steps, or separate values for forward and backward steps. .TP \f[V]startup-step-panic-threshold\f[R] = \f[I]seconds\f[R] | { \f[V]forward\f[R] = \f[I]forward\f[R], \f[V]backward\f[R] = \f[I]backward\f[R] } (\f[B]{ forward = \[lq]inf\[rq], backward = \[lq]86400\[rq] }\f[R]) The threshold in seconds at which the daemon will completely exit (i.e. panic) when a step occurs at startup. The default allows any forward step, but prevents backward steps larger than a single day. Generally computer clocks that are not synchronized will run behind the true time, instead of running ahead. If a computer is running ahead and steps back a large time this generally indicates a problem. If set to the value \f[V]\[dq]inf\[dq]\f[R], any step will be allowed. May either be configured as one number of seconds for both forward and backward steps, or separate values for forward and backward steps. .TP \f[V]accumulated-step-panic-threshold\f[R] = \f[I]seconds\f[R] (\f[B]unset\f[R]) Every time the daemon steps the time instead of slowly adjusting the clock by using frequency changes, this counter is increased by the absolute value of the step (i.e.\ both forward and backward steps are counted). When this threshold is reached, the daemon will exit immediately (i.e.\ panic). During normal operation steps are unlikely to occur, and as such, steps may indicate that someone or something is triggering illicit steps. By default however this panic mechanism is disabled. Is disabled if left unset or if set to the value \f[V]0\f[R]. .TP \f[V]local-stratum\f[R] = \f[I]stratum\f[R] (\f[B]16\f[R]) Sets the NTP clock stratum of the system clock when no NTP time sources have been configured, or when the time has not yet been synchronized from an NTP time source. Can be used in servers to indicate that there are external mechanisms synchronizing the clock. .SS \f[V][synchronization.algorithm]\f[R] .PP Warning: the algorithm section contains mostly internal algorithm tweaks that generally do not need to be changed. However, they are offered here for specific use cases. These settings are considered implementation details however, and as such may change in future ntpd-rs versions. .TP \f[V]precision-low-probability\f[R] = \f[I]probability\f[R] (\f[B]1/3\f[R]) Probability bound below which we start moving towards decreasing our precision estimate. Unit: probability, 0-1 .TP \f[V]precision-high-probability\f[R] = \f[I]probability\f[R] (\f[B]2/3\f[R]) Probability bound above which we start moving towards increasing our precision estimate. Unit: probability, 0-1 .TP \f[V]precision-hysteresis\f[R] = \f[I]hysteresis\f[R] (\f[B]16\f[R]) Amount of hysteresis in changing the precision estimate. Unit: count, 1+ .TP \f[V]precision-minimum-weight\f[R] = \f[I]weight\f[R] (\f[B]0.1\f[R]) Lower bound on the amount of effect our precision estimate has on the total noise estimate before we allow decreasing of the precision estimate. Unit: weight, 0-1 .TP \f[V]poll-interval-low-weight\f[R] = \f[I]weight\f[R] (\f[B]0.4\f[R]) Amount which a measurement contributes to the state, below which we start increasing the poll interval. Unit: weight, 0-1 .TP \f[V]poll-interval-high-weight\f[R] = \f[I]weight\f[R] (\f[B]0.6\f[R]) Amount which a measurement contributes to the state, above which we start decreasing the poll-interval interval. Unit: weight, 0-1 .TP \f[V]poll-interval-hysteresis\f[R] = \f[I]hysteresis\f[R] (\f[B]16\f[R]) Amount of hysteresis in changing the poll interval. Unit: count, 1+ .TP \f[V]poll-interval-step-threshold\f[R] = \f[I]threshold\f[R] (\f[B]1e-6\f[R]) Probability threshold for when a measurement is considered a significant enough outlier that we decide something weird is going on and we need to do more measurements. Unit: probability, 0-1 .TP \f[V]delay-outlier-threshold\f[R] = \f[I]threshold\f[R] (\f[B]5.0\f[R]) Threshold (in number of standard deviations) above which measurements with a significantly larger network delay are rejected. Unit: standard deviations, 0+ .TP \f[V]initial-wander\f[R] = \f[I]wander\f[R] (\f[B]1e-8\f[R]) Initial estimate of the clock wander of the combination of our local clock and that of the source. Unit: s/s\[ha]2 .TP \f[V]initial-frequency-uncertainty\f[R] = \f[I]uncertainty\f[R] (\f[B]100e-6\f[R]) Initial uncertainty of the frequency difference between our clock and that of the source. Unit: s/s .TP \f[V]maximum-source-uncertainty\f[R] = \f[I]uncertainty\f[R] (\f[B]0.25\f[R]) Maximum source uncertainty before we start disregarding it. Note that this is combined uncertainty due to noise and possible assymetry error (see also weights below). Unit: seconds .TP \f[V]range-statistical-weight\f[R] = \f[I]weight\f[R] (\f[B]2.0\f[R]) Weight of statistical uncertainty when constructing overlap ranges. Unit: standard deviations, 0+ .TP \f[V]range-delay-weight\f[R] = \f[I]weight\f[R] (\f[B]0.25\f[R]) Weight of delay uncertainty when constructing overlap ranges. Unit: weight, 0-1 .TP \f[V]steer-offset-threshold\f[R] = \f[I]threshold\f[R] (\f[B]2.0\f[R]) How far from 0 (in multiples of the uncertainty) should the offset be before we correct. Unit: standard deviations, 0+ .TP \f[V]steer-offset-leftover\f[R] = \f[I]stddev\f[R] (\f[B]1.0\f[R]) How many standard deviations do we leave after offset correction? Unit: standard deviations, 0+ .TP \f[V]steer-frequency-threshold\f[R] = \f[I]threshold\f[R] (\f[B]0.0\f[R]) How far from 0 (in multiples of the uncertainty) should the frequency estimate be before we correct. Unit: standard deviations, 0+ .TP \f[V]steer-frequency-leftover\f[R] = \f[I]stddev\f[R] (\f[B]0.0\f[R]) How many standard deviations do we leave after frequency correction? Unit: standard deviations, 0+ .TP \f[V]step-threshold\f[R] = \f[I]threshold\f[R] (\f[B]0.010\f[R]) From what offset should we step the clock instead of trying to adjust gradually? Unit: seconds, 0+ .TP \f[V]slew-maximum-frequency-offset\f[R] = \f[I]offset\f[R] (\f[B]200e-6\f[R]) What is the maximum frequency offset during a slew. Unit: s/s .TP \f[V]slew-minimum-duration\f[R] = \f[I]duration\f[R] (\f[B]495e-6\f[R]) What is the minimum duration of a slew. Unit: seconds .TP \f[V]maximum-frequency-steer\f[R] = \f[I]frequency\f[R] (\f[B]8.0\f[R]) Absolute maximum frequency correction. Unit: s/s .TP \f[V]ignore-server-dispersion\f[R] = \f[I]bool\f[R] (\f[B]false\f[R]) Ignore a servers advertised dispersion when synchronizing. Can improve synchronization quality with servers reporting overly conservative root dispersion. .TP \f[V]meddling-threshold\f[R] = \f[I]threshold\f[R] (\f[B]5.0\f[R]) Threshold for detecting external clock meddling. Unit: seconds .SH SEE ALSO .PP ntp-daemon(8), ntp-ctl(8), ntp-metrics-exporter(8) ntpd-1.1.2/src/ctl.rs000064400000000000000000000365051046102023000125220ustar 00000000000000use std::{path::PathBuf, process::ExitCode}; use crate::daemon::{config::CliArg, tracing::LogLevel, Config, ObservableState}; use tracing_subscriber::util::SubscriberInitExt; const USAGE_MSG: &str = "\ usage: ntp-ctl validate [-c PATH] ntp-ctl status [-f FORMAT] [-c PATH] ntp-ctl -h | ntp-ctl -v"; const DESCRIPTOR: &str = "ntp-ctl - ntp-daemon monitoring"; const HELP_MSG: &str = "Options: -f, --format=FORMAT which format to use for printing statistics [plain, prometheus] -c, --config=CONFIG which configuration file to read the socket paths from -h, --help display this help text -v, --version display version information"; pub fn long_help_message() -> String { format!("{DESCRIPTOR}\n\n{USAGE_MSG}\n\n{HELP_MSG}") } #[derive(Debug, Default, PartialEq, Eq)] enum Format { #[default] Plain, Prometheus, } #[derive(Debug, Default, PartialEq, Eq)] pub enum NtpCtlAction { #[default] Help, Version, Validate, Status, } #[derive(Debug, Default)] pub(crate) struct NtpCtlOptions { config: Option, format: Format, help: bool, version: bool, validate: bool, status: bool, action: NtpCtlAction, } impl NtpCtlOptions { const TAKES_ARGUMENT: &'static [&'static str] = &["--config", "--format"]; const TAKES_ARGUMENT_SHORT: &'static [char] = &['c', 'f']; /// parse an iterator over command line arguments pub fn try_parse_from(iter: I) -> Result where I: IntoIterator, T: AsRef + Clone, { let mut options = NtpCtlOptions::default(); let it = iter.into_iter().map(|x| x.as_ref().to_string()); let arg_iter = CliArg::normalize_arguments(Self::TAKES_ARGUMENT, Self::TAKES_ARGUMENT_SHORT, it)? .into_iter() .peekable(); for arg in arg_iter { match arg { CliArg::Flag(flag) => match flag.as_str() { "-h" | "--help" => { options.help = true; } "-v" | "--version" => { options.version = true; } option => { Err(format!("invalid option provided: {option}"))?; } }, CliArg::Argument(option, value) => match option.as_str() { "-c" | "--config" => { options.config = Some(PathBuf::from(value)); } "-f" | "--format" => match value.as_str() { "plain" => options.format = Format::Plain, "prometheus" => options.format = Format::Prometheus, _ => Err(format!("invalid format option provided: {value}"))?, }, option => { Err(format!("invalid option provided: {option}"))?; } }, CliArg::Rest(rest) => { if rest.len() > 1 { eprintln!("Warning: Too many commands provided.") } for command in rest { match command.as_str() { "validate" => { options.validate = true; } "status" => { options.status = true; } unknown => { eprintln!("Warning: Unknown command {unknown}"); } } } } } } options.resolve_action(); // nothing to validate at the moment Ok(options) } /// from the arguments resolve which action should be performed fn resolve_action(&mut self) { if self.help { self.action = NtpCtlAction::Help; } else if self.version { self.action = NtpCtlAction::Version; } else if self.validate { self.action = NtpCtlAction::Validate; } else if self.status { self.action = NtpCtlAction::Status; } else { self.action = NtpCtlAction::Help; } } } async fn validate(config: Option) -> std::io::Result { // Late completion not needed, so ignore result. crate::daemon::tracing::tracing_init(LogLevel::Info).init(); match Config::from_args(config, vec![], vec![]).await { Ok(config) => { if config.check() { eprintln!("Config looks good"); Ok(ExitCode::SUCCESS) } else { Ok(ExitCode::FAILURE) } } Err(e) => { eprintln!("Error: Could not load configuration: {e}"); Ok(ExitCode::FAILURE) } } } const VERSION: &str = env!("CARGO_PKG_VERSION"); pub async fn main() -> std::io::Result { let options = match NtpCtlOptions::try_parse_from(std::env::args()) { Ok(options) => options, Err(msg) => return Err(std::io::Error::new(std::io::ErrorKind::InvalidInput, msg)), }; match options.action { NtpCtlAction::Help => { println!("{}", long_help_message()); Ok(ExitCode::SUCCESS) } NtpCtlAction::Version => { eprintln!("ntp-ctl {VERSION}"); Ok(ExitCode::SUCCESS) } NtpCtlAction::Validate => validate(options.config).await, NtpCtlAction::Status => { let config = Config::from_args(options.config, vec![], vec![]).await; if let Err(ref e) = config { println!("Warning: Unable to load configuration file: {e}"); } let config = config.unwrap_or_default(); let observation = config .observability .observation_path .unwrap_or_else(|| PathBuf::from("/var/run/ntpd-rs/observe")); match options.format { Format::Plain => print_state(Format::Plain, observation).await, Format::Prometheus => print_state(Format::Prometheus, observation).await, } } } } async fn print_state(print: Format, observe_socket: PathBuf) -> Result { let mut stream = match tokio::net::UnixStream::connect(&observe_socket).await { Ok(stream) => stream, Err(e) => { eprintln!("Could not open socket at {}: {e}", observe_socket.display(),); return Ok(ExitCode::FAILURE); } }; let mut msg = Vec::with_capacity(16 * 1024); let mut output = match crate::daemon::sockets::read_json::(&mut stream, &mut msg).await { Ok(output) => output, Err(e) => { eprintln!("Failed to read state from observation socket: {e}"); return Ok(ExitCode::FAILURE); } }; match print { Format::Plain => { // Sort peers by address and then id (to deal with pools), servers just by address output.sources.sort_by_key(|p| match p { crate::daemon::ObservablePeerState::Nothing => None, crate::daemon::ObservablePeerState::Observable(s) => Some((s.name.clone(), s.id)), }); output.servers.sort_by_key(|s| s.address); println!("Synchronization status:"); println!( "Dispersion: {:.6}s, Delay: {:.6}s", output.system.time_snapshot.root_dispersion.to_seconds(), output.system.time_snapshot.root_delay.to_seconds() ); println!( "Desired poll interval: {:.0}s", output .system .time_snapshot .poll_interval .as_duration() .to_seconds() ); println!("Stratum: {}", output.system.stratum); println!(); println!("Sources:"); for peer in &output.sources { match peer { crate::daemon::ObservablePeerState::Nothing => {} crate::daemon::ObservablePeerState::Observable( crate::daemon::ObservedPeerState { timedata, unanswered_polls, poll_interval, name: address, address: ip, id, }, ) => { println!( concat!( "{}/{} ({}): {:+.6}±{:.6}(±{:.6})s\n", " poll interval: {:.0}s, missing polls: {}\n", " root dispersion: {:.6}s, root delay:{:.6}s" ), address, ip, id, timedata.offset.to_seconds(), timedata.uncertainty.to_seconds(), timedata.delay.to_seconds(), poll_interval.as_duration().to_seconds(), unanswered_polls, timedata.remote_uncertainty.to_seconds(), timedata.remote_delay.to_seconds(), ); } } } let in_startup = output .sources .iter() .filter(|peer| matches!(peer, crate::daemon::ObservablePeerState::Nothing)) .count(); match in_startup { 0 => {} // no peers in startup, so no line for that 1 => println!("1 source still in startup"), _ => println!("{} sources still in startup", in_startup), } println!(); println!("Servers:"); for server in &output.servers { println!( "{}: received {}, accepted {}, errors {}", server.address, server.stats.received_packets.get(), server.stats.accepted_packets.get(), server.stats.response_send_errors.get() ); println!( " denied {}, nts nak {}, rate limited {}, ignored {}", server.stats.denied_packets.get(), server.stats.nts_nak_packets.get(), server.stats.rate_limited_packets.get(), server.stats.ignored_packets.get() ); } } Format::Prometheus => { let mut buf = String::new(); if let Err(e) = crate::metrics::format_state(&mut buf, &output) { eprintln!("Failed to encode prometheus data: {e}"); return Ok(ExitCode::FAILURE); } println!("{buf}"); } } Ok(ExitCode::SUCCESS) } #[cfg(test)] mod tests { use std::os::unix::prelude::PermissionsExt; use std::path::Path; use crate::daemon::{ config::ObservabilityConfig, sockets::{create_unix_socket_with_permissions, write_json}, }; use super::*; async fn write_socket_helper( command: Format, socket_name: &str, ) -> std::io::Result> { let config: ObservabilityConfig = Default::default(); // be careful with copying: tests run concurrently and should use a unique socket name! let path = std::env::temp_dir().join(socket_name); if path.exists() { std::fs::remove_file(&path).unwrap(); } let permissions: std::fs::Permissions = PermissionsExt::from_mode(config.observation_permissions); let peers_listener = create_unix_socket_with_permissions(&path, permissions)?; let fut = super::print_state(command, path); let handle = tokio::spawn(fut); let value = ObservableState { program: Default::default(), system: Default::default(), sources: vec![], servers: vec![], }; let (mut stream, _addr) = peers_listener.accept().await?; write_json(&mut stream, &value).await?; let result = handle.await.unwrap(); Ok(result) } #[tokio::test] async fn test_control_socket_peer() -> std::io::Result<()> { // be careful with copying: tests run concurrently and should use a unique socket name! let result = write_socket_helper(Format::Plain, "ntp-test-stream-6").await?; assert_eq!( format!("{:?}", result.unwrap()), format!("{:?}", ExitCode::SUCCESS) ); Ok(()) } #[tokio::test] async fn test_control_socket_prometheus() -> std::io::Result<()> { // be careful with copying: tests run concurrently and should use a unique socket name! let result = write_socket_helper(Format::Prometheus, "ntp-test-stream-8").await?; assert_eq!( format!("{:?}", result.unwrap()), format!("{:?}", ExitCode::SUCCESS) ); Ok(()) } #[tokio::test] async fn test_control_socket_peer_invalid_input() -> std::io::Result<()> { let config: ObservabilityConfig = Default::default(); // be careful with copying: tests run concurrently and should use a unique socket name! let path = std::env::temp_dir().join("ntp-test-stream-10"); if path.exists() { std::fs::remove_file(&path).unwrap(); } let permissions: std::fs::Permissions = PermissionsExt::from_mode(config.observation_permissions); let peers_listener = create_unix_socket_with_permissions(&path, permissions)?; let fut = super::print_state(Format::Plain, path); let handle = tokio::spawn(fut); let value = 42u32; let (mut stream, _addr) = peers_listener.accept().await?; write_json(&mut stream, &value).await?; let result = handle.await.unwrap(); assert_eq!( format!("{:?}", result.unwrap()), format!("{:?}", ExitCode::FAILURE) ); Ok(()) } const BINARY: &str = "/usr/bin/ntp-ctl"; #[test] fn cli_config() { let config_str = "/foo/bar/ntp.toml"; let config = Path::new(config_str); let arguments = &[BINARY, "-c", config_str]; let options = NtpCtlOptions::try_parse_from(arguments).unwrap(); assert_eq!(options.config.unwrap().as_path(), config); } #[test] fn cli_format() { let arguments = &[BINARY, "-f", "plain"]; let options = NtpCtlOptions::try_parse_from(arguments).unwrap(); assert_eq!(options.format, Format::Plain); let arguments = &[BINARY, "-f", "prometheus"]; let options = NtpCtlOptions::try_parse_from(arguments).unwrap(); assert_eq!(options.format, Format::Prometheus); let arguments = &[BINARY, "-f", "yaml"]; let err = NtpCtlOptions::try_parse_from(arguments).unwrap_err(); assert_eq!(err, "invalid format option provided: yaml"); } } ntpd-1.1.2/src/daemon/config/mod.rs000064400000000000000000000545221046102023000152260ustar 00000000000000mod peer; mod server; pub mod subnet; use ntp_os_clock::DefaultNtpClock; use ntp_proto::{SourceDefaultsConfig, SynchronizationConfig}; use ntp_udp::{EnableTimestamps, InterfaceName}; pub use peer::*; use serde::{Deserialize, Deserializer}; pub use server::*; use std::{ io::ErrorKind, net::SocketAddr, os::unix::fs::PermissionsExt, path::{Path, PathBuf}, str::FromStr, }; use thiserror::Error; use tokio::{fs::read_to_string, io}; use tracing::{info, warn}; use super::tracing::LogLevel; const USAGE_MSG: &str = "\ usage: ntp-daemon [-c PATH] [-l LOG_LEVEL] ntp-daemon -h ntp-daemon -v"; const DESCRIPTOR: &str = "ntp-daemon - synchronize system time"; const HELP_MSG: &str = "Options: -c, --config=PATH change the config .toml file -l, --log-level=LOG_LEVEL change the log level -h, --help display this help text -v, --version display version information"; pub fn long_help_message() -> String { format!("{DESCRIPTOR}\n\n{USAGE_MSG}\n\n{HELP_MSG}") } #[derive(Debug, Default)] pub(crate) struct NtpDaemonOptions { /// Path of the configuration file pub config: Option, /// Level for messages to display in logs pub log_level: Option, help: bool, version: bool, pub action: NtpDaemonAction, } pub enum CliArg { Flag(String), Argument(String, String), Rest(Vec), } impl CliArg { pub fn normalize_arguments( takes_argument: &[&str], takes_argument_short: &[char], iter: I, ) -> Result, String> where I: IntoIterator, { // the first argument is the ntp-daemon command - so we can skip it let mut arg_iter = iter.into_iter().skip(1); let mut processed = vec![]; let mut rest = vec![]; while let Some(arg) = arg_iter.next() { match arg.as_str() { "--" => { rest.extend(arg_iter); break; } long_arg if long_arg.starts_with("--") => { // --config=/path/to/config.toml let invalid = Err(format!("invalid option: '{long_arg}'")); if let Some((key, value)) = long_arg.split_once('=') { if takes_argument.contains(&key) { processed.push(CliArg::Argument(key.to_string(), value.to_string())) } else { invalid? } } else if takes_argument.contains(&long_arg) { if let Some(next) = arg_iter.next() { processed.push(CliArg::Argument(long_arg.to_string(), next)) } else { Err(format!("'{}' expects an argument", &long_arg))?; } } else { processed.push(CliArg::Flag(arg)); } } short_arg if short_arg.starts_with('-') => { // split combined shorthand options for (n, char) in short_arg.trim_start_matches('-').chars().enumerate() { let flag = format!("-{char}"); // convert option argument to seperate segment if takes_argument_short.contains(&char) { let rest = short_arg[(n + 2)..].trim().to_string(); // assignment syntax is not accepted for shorthand arguments if rest.starts_with('=') { Err("invalid option '='")?; } if !rest.is_empty() { processed.push(CliArg::Argument(flag, rest)); } else if let Some(next) = arg_iter.next() { processed.push(CliArg::Argument(flag, next)); } else if char == 'h' { // short version of --help has no arguments processed.push(CliArg::Flag(flag)); } else { Err(format!("'-{}' expects an argument", char))?; } break; } else { processed.push(CliArg::Flag(flag)); } } } _argument => rest.push(arg), } } if !rest.is_empty() { processed.push(CliArg::Rest(rest)); } Ok(processed) } } #[derive(Debug, Default, PartialEq, Eq)] pub enum NtpDaemonAction { #[default] Help, Version, Run, } impl NtpDaemonOptions { const TAKES_ARGUMENT: &'static [&'static str] = &["--config", "--log-level"]; const TAKES_ARGUMENT_SHORT: &'static [char] = &['c', 'l']; /// parse an iterator over command line arguments pub fn try_parse_from(iter: I) -> Result where I: IntoIterator, T: AsRef + Clone, { let mut options = NtpDaemonOptions::default(); let arg_iter = CliArg::normalize_arguments( Self::TAKES_ARGUMENT, Self::TAKES_ARGUMENT_SHORT, iter.into_iter().map(|x| x.as_ref().to_string()), )? .into_iter() .peekable(); for arg in arg_iter { match arg { CliArg::Flag(flag) => match flag.as_str() { "-h" | "--help" => { options.help = true; } "-v" | "--version" => { options.version = true; } option => { Err(format!("invalid option provided: {option}"))?; } }, CliArg::Argument(option, value) => match option.as_str() { "-c" | "--config" => { options.config = Some(PathBuf::from(value)); } "-l" | "--log-level" => match LogLevel::from_str(&value) { Ok(level) => options.log_level = Some(level), Err(_) => return Err("invalid log level".into()), }, option => { Err(format!("invalid option provided: {option}"))?; } }, CliArg::Rest(_rest) => { /* do nothing, drop remaining arguments */ } } } options.resolve_action(); // nothing to validate at the moment Ok(options) } /// from the arguments resolve which action should be performed fn resolve_action(&mut self) { if self.help { self.action = NtpDaemonAction::Help; } else if self.version { self.action = NtpDaemonAction::Version; } else { self.action = NtpDaemonAction::Run; } } } fn deserialize_ntp_clock<'de, D>(deserializer: D) -> Result where D: Deserializer<'de>, { let data: Option = Deserialize::deserialize(deserializer)?; if let Some(path) = data { tracing::info!("using custom clock {path:?}"); DefaultNtpClock::from_path(&path).map_err(|e| serde::de::Error::custom(e.to_string())) } else { tracing::debug!("using REALTIME clock"); Ok(DefaultNtpClock::realtime()) } } fn deserialize_interface<'de, D>(deserializer: D) -> Result, D::Error> where D: Deserializer<'de>, { let opt_interface_name: Option = Deserialize::deserialize(deserializer)?; if let Some(interface_name) = opt_interface_name { tracing::info!("using custom interface {}", interface_name); } else { tracing::info!("using default interface"); } Ok(opt_interface_name) } #[derive(Deserialize, Debug, Copy, Clone, Default)] #[serde(rename_all = "kebab-case", deny_unknown_fields)] pub struct ClockConfig { #[serde(deserialize_with = "deserialize_ntp_clock", default)] pub clock: DefaultNtpClock, #[serde(deserialize_with = "deserialize_interface", default)] pub interface: Option, pub enable_timestamps: EnableTimestamps, } #[derive(Deserialize, Debug, Clone)] #[serde(rename_all = "kebab-case", deny_unknown_fields)] pub struct ObservabilityConfig { #[serde(default)] pub log_level: Option, #[serde(default)] pub observation_path: Option, #[serde(default = "default_observation_permissions")] pub observation_permissions: u32, #[serde(default = "default_metrics_exporter_listen")] pub metrics_exporter_listen: SocketAddr, } impl Default for ObservabilityConfig { fn default() -> Self { Self { log_level: Default::default(), observation_path: Default::default(), observation_permissions: default_observation_permissions(), metrics_exporter_listen: default_metrics_exporter_listen(), } } } const fn default_observation_permissions() -> u32 { 0o666 } fn default_metrics_exporter_listen() -> SocketAddr { "127.0.0.1:9975".parse().unwrap() } #[derive(Deserialize, Debug, Default)] #[serde(rename_all = "kebab-case", deny_unknown_fields)] pub struct Config { #[serde(rename = "source", default)] pub sources: Vec, #[serde(rename = "server", default)] pub servers: Vec, #[serde(rename = "nts-ke-server", default)] pub nts_ke: Vec, #[serde(default)] pub synchronization: SynchronizationConfig, #[serde(default)] pub source_defaults: SourceDefaultsConfig, #[serde(default)] pub observability: ObservabilityConfig, #[serde(default)] pub keyset: KeysetConfig, #[serde(default)] #[cfg(feature = "hardware-timestamping")] pub clock: ClockConfig, } impl Config { async fn from_file(file: impl AsRef) -> Result { let meta = std::fs::metadata(&file)?; let perm = meta.permissions(); if perm.mode() as libc::mode_t & libc::S_IWOTH != 0 { warn!("Unrestricted config file permissions: Others can write."); } let contents = read_to_string(file).await?; Ok(toml::de::from_str(&contents)?) } async fn from_first_file(file: Option>) -> Result { // if an explicit file is given, always use that one if let Some(f) = file { let path: &Path = f.as_ref(); info!(?path, "using config file"); return Config::from_file(f).await; } // for the global file we also ignore it when there are permission errors let global_path = Path::new("/etc/ntpd-rs/ntp.toml"); if global_path.exists() { info!("using config file at default location `{:?}`", global_path); match Config::from_file(global_path).await { Err(ConfigError::Io(e)) if e.kind() == ErrorKind::PermissionDenied => { info!("permission denied on global config file! using default config ..."); } other => { return other; } } } Ok(Config::default()) } pub async fn from_args( file: Option>, peers: Vec, servers: Vec, ) -> Result { let mut config = Config::from_first_file(file.as_ref()).await?; if !peers.is_empty() { if !config.sources.is_empty() { info!("overriding peers from configuration"); } config.sources = peers; } if !servers.is_empty() { if !config.servers.is_empty() { info!("overriding servers from configuration"); } config.servers = servers; } Ok(config) } /// Count potential number of peers in configuration fn count_peers(&self) -> usize { let mut count = 0; for peer in &self.sources { match peer { PeerConfig::Standard(_) => count += 1, PeerConfig::Nts(_) => count += 1, PeerConfig::Pool(config) => count += config.max_peers, #[cfg(feature = "unstable_nts-pool")] PeerConfig::NtsPool(config) => count += config.max_peers, } } count } /// Check that the config is reasonable. This function may panic if the /// configuration is egregious, although it doesn't do so currently. pub fn check(&self) -> bool { let mut ok = true; // Note: since we only check once logging is fully configured, // using those fields should always work. This is also // probably a good policy in general (config should always work // but we may panic here to protect the user from themselves) if self.sources.is_empty() { info!("No sources configured. Daemon will not change system time."); } if !self.sources.is_empty() && self.count_peers() < self.synchronization.minimum_agreeing_sources { warn!("Fewer sources configured than are required to agree on the current time. Daemon will not change system time."); ok = false; } ok } } #[derive(Error, Debug)] pub enum ConfigError { #[error("io error while reading config: {0}")] Io(#[from] io::Error), #[error("config toml parsing error: {0}")] Toml(#[from] toml::de::Error), } #[cfg(test)] mod tests { use std::str::FromStr; use ntp_proto::{NtpDuration, StepThreshold}; use super::*; #[test] fn test_config() { let config: Config = toml::from_str("[[source]]\nmode = \"server\"\naddress = \"example.com\"").unwrap(); assert_eq!( config.sources, vec![PeerConfig::Standard(StandardPeerConfig { address: NormalizedAddress::new_unchecked("example.com", 123).into(), })] ); assert!(config.observability.log_level.is_none()); let config: Config = toml::from_str( "[observability]\nlog-level = \"info\"\n[[source]]\nmode = \"server\"\naddress = \"example.com\"", ) .unwrap(); assert_eq!(config.observability.log_level, Some(LogLevel::Info)); assert_eq!( config.sources, vec![PeerConfig::Standard(StandardPeerConfig { address: NormalizedAddress::new_unchecked("example.com", 123).into(), })] ); let config: Config = toml::from_str( "[[source]]\nmode = \"server\"\naddress = \"example.com\"\n[synchronization]\nsingle-step-panic-threshold = 0", ) .unwrap(); assert_eq!( config.sources, vec![PeerConfig::Standard(StandardPeerConfig { address: NormalizedAddress::new_unchecked("example.com", 123).into(), })] ); assert_eq!( config.synchronization.single_step_panic_threshold.forward, Some(NtpDuration::from_seconds(0.)) ); assert_eq!( config.synchronization.single_step_panic_threshold.backward, Some(NtpDuration::from_seconds(0.)) ); let config: Config = toml::from_str( "[[source]]\nmode = \"server\"\naddress = \"example.com\"\n[synchronization]\nsingle-step-panic-threshold = \"inf\"", ) .unwrap(); assert_eq!( config.sources, vec![PeerConfig::Standard(StandardPeerConfig { address: NormalizedAddress::new_unchecked("example.com", 123).into(), })] ); assert!(config .synchronization .single_step_panic_threshold .forward .is_none()); assert!(config .synchronization .single_step_panic_threshold .backward .is_none()); let config: Config = toml::from_str( r#" [[source]] mode = "server" address = "example.com" [source-defaults] poll-interval-limits = { min = 5, max = 9 } initial-poll-interval = 5 [observability] log-level = "info" observation-path = "/foo/bar/observe" observation-permissions = 0o567 "#, ) .unwrap(); assert!(config.observability.log_level.is_some()); assert_eq!( config.observability.observation_path, Some(PathBuf::from("/foo/bar/observe")) ); assert_eq!(config.observability.observation_permissions, 0o567); assert_eq!( config.sources, vec![PeerConfig::Standard(StandardPeerConfig { address: NormalizedAddress::new_unchecked("example.com", 123).into(), })] ); let poll_interval_limits = config.source_defaults.poll_interval_limits; assert_eq!(poll_interval_limits.min.as_log(), 5); assert_eq!(poll_interval_limits.max.as_log(), 9); assert_eq!(config.source_defaults.initial_poll_interval.as_log(), 5); } #[test] fn cli_no_arguments() { let arguments: [String; 0] = []; let parsed_empty = NtpDaemonOptions::try_parse_from(arguments).unwrap(); assert!(parsed_empty.config.is_none()); assert!(parsed_empty.log_level.is_none()); assert_eq!(parsed_empty.action, NtpDaemonAction::Run); } #[test] fn cli_external_config() { let arguments = &["/usr/bin/ntp-daemon", "--config", "other.toml"]; let parsed_empty = NtpDaemonOptions::try_parse_from(arguments).unwrap(); assert_eq!(parsed_empty.config, Some("other.toml".into())); assert!(parsed_empty.log_level.is_none()); assert_eq!(parsed_empty.action, NtpDaemonAction::Run); let arguments = &["/usr/bin/ntp-daemon", "-c", "other.toml"]; let parsed_empty = NtpDaemonOptions::try_parse_from(arguments).unwrap(); assert_eq!(parsed_empty.config, Some("other.toml".into())); assert!(parsed_empty.log_level.is_none()); assert_eq!(parsed_empty.action, NtpDaemonAction::Run); } #[test] fn cli_log_level() { let arguments = &["/usr/bin/ntp-daemon", "--log-level", "debug"]; let parsed_empty = NtpDaemonOptions::try_parse_from(arguments).unwrap(); assert!(parsed_empty.config.is_none()); assert_eq!(parsed_empty.log_level.unwrap(), LogLevel::Debug); let arguments = &["/usr/bin/ntp-daemon", "-l", "debug"]; let parsed_empty = NtpDaemonOptions::try_parse_from(arguments).unwrap(); assert!(parsed_empty.config.is_none()); assert_eq!(parsed_empty.log_level.unwrap(), LogLevel::Debug); } #[test] fn toml_peers_invalid() { let config: Result = toml::from_str( r#" [[source]] mode = "server" address = ":invalid:ipv6:123" "#, ); assert!(config.is_err()); } #[test] fn toml_allow_no_peers() { let config: Result = toml::from_str( r#" [[server]] listen = "[::]:123" "#, ); assert!(config.is_ok()); assert!(config.unwrap().check()); } #[test] fn system_config_accumulated_threshold() { let config: Result = toml::from_str( r#" accumulated-step-panic-threshold = 0 "#, ); let config = config.unwrap(); assert!(config.accumulated_step_panic_threshold.is_none()); let config: Result = toml::from_str( r#" accumulated-step-panic-threshold = 1000 "#, ); let config = config.unwrap(); assert_eq!( config.accumulated_step_panic_threshold, Some(NtpDuration::from_seconds(1000.0)) ); } #[test] fn system_config_startup_panic_threshold() { let config: Result = toml::from_str( r#" startup-step-panic-threshold = { forward = 10, backward = 20 } "#, ); let config = config.unwrap(); assert_eq!( config.startup_step_panic_threshold.forward, Some(NtpDuration::from_seconds(10.0)) ); assert_eq!( config.startup_step_panic_threshold.backward, Some(NtpDuration::from_seconds(20.0)) ); } #[test] fn duration_not_nan() { #[derive(Debug, Deserialize)] struct Helper { #[allow(unused)] duration: NtpDuration, } let result: Result = toml::from_str( r#" duration = nan "#, ); let error = result.unwrap_err(); assert!(error.to_string().contains("expected a valid number")); } #[test] fn step_threshold_not_nan() { #[derive(Debug, Deserialize)] struct Helper { #[allow(unused)] threshold: StepThreshold, } let result: Result = toml::from_str( r#" threshold = nan "#, ); let error = result.unwrap_err(); assert!(error.to_string().contains("expected a positive number")); } #[test] fn deny_unknown_fields() { let config: Result = toml::from_str( r#" unknown-field = 42 "#, ); let error = config.unwrap_err(); assert!(error.to_string().contains("unknown field")); } #[test] fn clock_config() { let config: Result = toml::from_str( r#" interface = "enp0s31f6" enable-timestamps.rx-hardware = true enable-timestamps.tx-software = true "#, ); let config = config.unwrap(); let expected = InterfaceName::from_str("enp0s31f6").unwrap(); assert_eq!(config.interface, Some(expected)); assert!(config.enable_timestamps.rx_software); assert!(config.enable_timestamps.tx_software); } } ntpd-1.1.2/src/daemon/config/peer.rs000064400000000000000000000351111046102023000153730ustar 00000000000000use std::{ fmt, net::SocketAddr, ops::Deref, path::PathBuf, sync::{Arc, Mutex}, }; use rustls::Certificate; use serde::{de, Deserialize, Deserializer}; use super::super::keyexchange::certificates_from_file; #[derive(Deserialize, Debug, PartialEq, Eq, Clone)] #[serde(deny_unknown_fields)] pub struct StandardPeerConfig { pub address: NtpAddress, } #[derive(Debug, Deserialize, PartialEq, Eq, Clone)] #[serde(deny_unknown_fields)] pub struct NtsPeerConfig { pub address: NtsKeAddress, #[serde( deserialize_with = "deserialize_certificate_authorities", default = "default_certificate_authorities", rename = "certificate-authority" )] pub certificate_authorities: Arc<[Certificate]>, } fn deserialize_certificate_authorities<'de, D>( deserializer: D, ) -> Result, D::Error> where D: Deserializer<'de>, { let certificate_path: PathBuf = PathBuf::deserialize(deserializer)?; match certificates_from_file(&certificate_path) { Ok(certificates) => Ok(Arc::from(certificates)), Err(io_error) => { let msg = format!("error while parsing certificate file {certificate_path:?}: {io_error:?}"); Err(de::Error::custom(msg)) } } } fn default_certificate_authorities() -> Arc<[Certificate]> { Arc::from([]) } #[derive(Deserialize, Debug, PartialEq, Eq, Clone)] #[serde(deny_unknown_fields)] pub struct PoolPeerConfig { #[serde(rename = "address")] pub addr: NtpAddress, #[serde(rename = "count", default = "max_peers_default")] pub max_peers: usize, } fn max_peers_default() -> usize { 4 } #[cfg(feature = "unstable_nts-pool")] #[derive(Deserialize, Debug, PartialEq, Eq, Clone)] #[serde(deny_unknown_fields)] pub struct NtsPoolPeerConfig { #[serde(rename = "address")] pub addr: NtsKeAddress, #[serde( deserialize_with = "deserialize_certificate_authorities", default = "default_certificate_authorities", rename = "certificate-authority" )] pub certificate_authorities: Arc<[Certificate]>, #[serde(rename = "count", default = "max_peers_default")] pub max_peers: usize, } #[derive(Debug, Deserialize, PartialEq, Eq, Clone)] #[serde(tag = "mode")] pub enum PeerConfig { #[serde(rename = "server")] Standard(StandardPeerConfig), #[serde(rename = "nts")] Nts(NtsPeerConfig), #[serde(rename = "pool")] Pool(PoolPeerConfig), // Consul(ConsulPeerConfig), #[cfg(feature = "unstable_nts-pool")] #[serde(rename = "nts-pool")] NtsPool(NtsPoolPeerConfig), } /// A normalized address has a host and a port part. However, the host may be /// invalid, we didn't yet perform a DNS lookup. #[derive(Deserialize, Debug, Clone)] #[serde(rename_all = "kebab-case", deny_unknown_fields)] pub struct NormalizedAddress { pub(crate) server_name: String, pub(crate) port: u16, /// Used to inject socket addrs into the DNS lookup result #[cfg(test)] hardcoded_dns_resolve: HardcodedDnsResolve, } impl Eq for NormalizedAddress {} impl PartialEq for NormalizedAddress { fn eq(&self, other: &Self) -> bool { self.server_name == other.server_name && self.port == other.port } } #[derive(Deserialize, Debug, Clone, Default)] struct HardcodedDnsResolve { #[cfg_attr(not(test), allow(unused))] #[serde(skip)] addresses: Arc>>, } impl From> for HardcodedDnsResolve { fn from(value: Vec) -> Self { Self { addresses: Arc::new(Mutex::new(value)), } } } #[derive(Debug, Clone, PartialEq, Eq)] pub struct NtpAddress(pub NormalizedAddress); #[derive(Debug, Clone, PartialEq, Eq)] pub struct NtsKeAddress(pub NormalizedAddress); impl<'de> Deserialize<'de> for NtpAddress { fn deserialize(deserializer: D) -> Result where D: Deserializer<'de>, { let s = String::deserialize(deserializer)?; Ok(NormalizedAddress::from_string_ntp(s) .map_err(serde::de::Error::custom)? .into()) } } impl<'de> Deserialize<'de> for NtsKeAddress { fn deserialize(deserializer: D) -> Result where D: Deserializer<'de>, { let s = String::deserialize(deserializer)?; Ok(NtsKeAddress( NormalizedAddress::from_string_nts_ke(s).map_err(serde::de::Error::custom)?, )) } } impl From for NtpAddress { fn from(addr: NormalizedAddress) -> Self { Self(addr) } } impl From for NtsKeAddress { fn from(addr: NormalizedAddress) -> Self { Self(addr) } } impl Deref for NtsKeAddress { type Target = NormalizedAddress; fn deref(&self) -> &Self::Target { &self.0 } } impl Deref for NtpAddress { type Target = NormalizedAddress; fn deref(&self) -> &Self::Target { &self.0 } } impl NormalizedAddress { const NTP_DEFAULT_PORT: u16 = 123; const NTS_KE_DEFAULT_PORT: u16 = 4460; /// Specifically, this adds the `:123` port if no port is specified pub(crate) fn from_string_ntp(address: String) -> std::io::Result { let (server_name, port) = Self::from_string_help(address, Self::NTP_DEFAULT_PORT)?; Ok(Self { server_name, port, #[cfg(test)] hardcoded_dns_resolve: HardcodedDnsResolve::default(), }) } /// Specifically, this adds the `:4460` port if no port is specified fn from_string_nts_ke(address: String) -> std::io::Result { let (server_name, port) = Self::from_string_help(address, Self::NTS_KE_DEFAULT_PORT)?; Ok(Self { server_name, port, #[cfg(test)] hardcoded_dns_resolve: HardcodedDnsResolve::default(), }) } fn from_string_help(address: String, default_port: u16) -> std::io::Result<(String, u16)> { if address.split(':').count() > 2 { // IPv6, try to parse it as such match address.parse::() { Ok(socket_addr) => { // strip off the port let (server_name, _) = address.rsplit_once(':').unwrap(); Ok((server_name.to_string(), socket_addr.port())) } Err(e) => { // Could be because of no port, add one and see let address_with_port = format!("[{address}]:{default_port}"); if address_with_port.parse::().is_ok() { Ok((format!("[{address}]"), default_port)) } else { Err(std::io::Error::new(std::io::ErrorKind::Other, e)) } } } } else if let Some((server_name, port)) = address.split_once(':') { // Not ipv6, and we seem to have a port. We cant reasonably // check whether the host is valid, but at least check that // the port is. match port.parse::() { Ok(port) => Ok((server_name.to_string(), port)), Err(e) => Err(std::io::Error::new(std::io::ErrorKind::Other, e)), } } else { // Not ipv6 and no port. As we cant reasonably check host // so just append a port Ok((address, default_port)) } } #[cfg(test)] pub(crate) fn new_unchecked(server_name: &str, port: u16) -> Self { Self { server_name: server_name.to_string(), port, #[cfg(test)] hardcoded_dns_resolve: HardcodedDnsResolve::default(), } } #[cfg(test)] pub(crate) fn with_hardcoded_dns( server_name: &str, port: u16, hardcoded_dns_resolve: Vec, ) -> Self { Self { server_name: server_name.to_string(), port, hardcoded_dns_resolve: HardcodedDnsResolve::from(hardcoded_dns_resolve), } } #[cfg(not(test))] pub async fn lookup_host(&self) -> std::io::Result + '_> { tokio::net::lookup_host((self.server_name.as_str(), self.port)).await } #[cfg(test)] pub async fn lookup_host(&self) -> std::io::Result + '_> { // We don't want to spam a real DNS server during testing. This is an attempt to randomize // the returned addresses somewhat. let mut addresses = self.hardcoded_dns_resolve.addresses.lock().unwrap(); if let Some(last) = addresses.pop() { addresses.insert(0, last); } let addresses = addresses.to_vec(); Ok(addresses.into_iter()) } } impl std::fmt::Display for NormalizedAddress { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { write!(f, "{}:{}", self.server_name, self.port) } } impl TryFrom<&str> for StandardPeerConfig { type Error = std::io::Error; fn try_from(value: &str) -> Result { Ok(Self { address: NormalizedAddress::from_string_ntp(value.to_string())?.into(), }) } } impl<'a> TryFrom<&'a str> for PeerConfig { type Error = std::io::Error; fn try_from(value: &'a str) -> Result { StandardPeerConfig::try_from(value).map(Self::Standard) } } #[cfg(test)] mod tests { use super::*; fn peer_addr(config: &PeerConfig) -> String { match config { PeerConfig::Standard(c) => c.address.to_string(), PeerConfig::Nts(c) => c.address.to_string(), PeerConfig::Pool(c) => c.addr.to_string(), #[cfg(feature = "unstable_nts-pool")] PeerConfig::NtsPool(c) => c.addr.to_string(), } } #[test] fn test_deserialize_peer() { #[derive(Deserialize, Debug)] struct TestConfig { peer: PeerConfig, } let test: TestConfig = toml::from_str( r#" [peer] mode = "server" address = "example.com" "#, ) .unwrap(); assert_eq!(peer_addr(&test.peer), "example.com:123"); assert!(matches!(test.peer, PeerConfig::Standard(_))); let test: TestConfig = toml::from_str( r#" [peer] mode = "server" address = "example.com:5678" "#, ) .unwrap(); assert_eq!(peer_addr(&test.peer), "example.com:5678"); assert!(matches!(test.peer, PeerConfig::Standard(_))); let test: TestConfig = toml::from_str( r#" [peer] mode = "server" address = "example.com" "#, ) .unwrap(); assert_eq!(peer_addr(&test.peer), "example.com:123"); assert!(matches!(test.peer, PeerConfig::Standard(_))); let test: TestConfig = toml::from_str( r#" [peer] address = "example.com" mode = "pool" "#, ) .unwrap(); assert!(matches!(test.peer, PeerConfig::Pool(_))); if let PeerConfig::Pool(config) = test.peer { assert_eq!(config.addr.to_string(), "example.com:123"); assert_eq!(config.max_peers, 4); } let test: TestConfig = toml::from_str( r#" [peer] address = "example.com" mode = "pool" count = 42 "#, ) .unwrap(); assert!(matches!(test.peer, PeerConfig::Pool(_))); if let PeerConfig::Pool(config) = test.peer { assert_eq!(config.addr.to_string(), "example.com:123"); assert_eq!(config.max_peers, 42); } let test: TestConfig = toml::from_str( r#" [peer] address = "example.com" mode = "nts" "#, ) .unwrap(); assert!(matches!(test.peer, PeerConfig::Nts(_))); if let PeerConfig::Nts(config) = test.peer { assert_eq!(config.address.to_string(), "example.com:4460"); } #[cfg(feature = "unstable_nts-pool")] { let test: TestConfig = toml::from_str( r#" [peer] address = "example.com" mode = "nts-pool" "#, ) .unwrap(); assert!(matches!(test.peer, PeerConfig::NtsPool(_))); if let PeerConfig::Nts(config) = test.peer { assert_eq!(config.address.to_string(), "example.com:4460"); } } } #[test] fn test_deserialize_peer_pem_certificate() { let contents = include_bytes!("../../../testdata/certificates/nos-nl.pem"); let path = std::env::temp_dir().join("nos-nl.pem"); std::fs::write(&path, contents).unwrap(); #[derive(Deserialize, Debug)] struct TestConfig { peer: PeerConfig, } let test: TestConfig = toml::from_str(&format!( r#" [peer] address = "example.com" certificate-authority = "{}" mode = "nts" "#, path.display() )) .unwrap(); assert!(matches!(test.peer, PeerConfig::Nts(_))); if let PeerConfig::Nts(config) = test.peer { assert_eq!(config.address.to_string(), "example.com:4460"); } } #[test] fn test_peer_from_string() { let peer = PeerConfig::try_from("example.com").unwrap(); assert_eq!(peer_addr(&peer), "example.com:123"); assert!(matches!(peer, PeerConfig::Standard(_))); let peer = PeerConfig::try_from("example.com:5678").unwrap(); assert_eq!(peer_addr(&peer), "example.com:5678"); assert!(matches!(peer, PeerConfig::Standard(_))); } #[test] fn test_normalize_addr() { let addr = NormalizedAddress::from_string_ntp("[::1]:456".into()).unwrap(); assert_eq!(addr.to_string(), "[::1]:456"); let addr = NormalizedAddress::from_string_ntp("::1".into()).unwrap(); assert_eq!(addr.to_string(), "[::1]:123"); assert!(NormalizedAddress::from_string_ntp(":some:invalid:1".into()).is_err()); let addr = NormalizedAddress::from_string_ntp("127.0.0.1:456".into()).unwrap(); assert_eq!(addr.to_string(), "127.0.0.1:456"); let addr = NormalizedAddress::from_string_ntp("127.0.0.1".into()).unwrap(); assert_eq!(addr.to_string(), "127.0.0.1:123"); let addr = NormalizedAddress::from_string_ntp("1234567890.example.com".into()).unwrap(); assert_eq!(addr.to_string(), "1234567890.example.com:123"); } } ntpd-1.1.2/src/daemon/config/server.rs000064400000000000000000000200441046102023000157450ustar 00000000000000use std::{ net::{AddrParseError, SocketAddr}, path::PathBuf, str::FromStr, time::Duration, }; use serde::{Deserialize, Deserializer}; use super::super::ipfilter::IpFilter; #[derive(Debug, PartialEq, Eq, Clone, Deserialize)] #[serde(rename_all = "kebab-case", deny_unknown_fields)] pub struct KeysetConfig { /// Number of old keys to keep around #[serde(default = "default_stale_key_count")] pub stale_key_count: usize, /// How often to rotate keys (seconds between rotations) #[serde(default = "default_key_rotation_interval")] pub key_rotation_interval: usize, #[serde(default)] pub key_storage_path: Option, } impl Default for KeysetConfig { fn default() -> Self { Self { stale_key_count: default_stale_key_count(), key_rotation_interval: default_key_rotation_interval(), key_storage_path: None, } } } fn default_key_rotation_interval() -> usize { // 1 day in seconds 86400 } fn default_stale_key_count() -> usize { // 1 weeks worth at 1 key per day 7 } #[derive(Debug, PartialEq, Eq, Copy, Clone, Deserialize)] #[serde(rename_all = "lowercase")] pub enum FilterAction { Ignore, Deny, } #[derive(Debug, PartialEq, Eq, Clone, Deserialize)] pub struct FilterList { pub filter: IpFilter, pub action: FilterAction, } impl FilterList { #[cfg(test)] pub fn new(subnets: &[super::subnet::IpSubnet], action: FilterAction) -> Self { Self { filter: IpFilter::new(subnets), action, } } pub fn all(action: FilterAction) -> Self { Self { filter: IpFilter::all(), action, } } pub fn none(action: FilterAction) -> Self { Self { filter: IpFilter::none(), action, } } pub fn default_denylist() -> Self { Self::none(FilterAction::Ignore) } pub fn default_allowlist() -> Self { Self::all(FilterAction::Ignore) } } #[derive(Debug, PartialEq, Eq, Clone, Deserialize)] #[serde(rename_all = "kebab-case", deny_unknown_fields)] pub struct ServerConfig { pub listen: SocketAddr, #[serde(default = "FilterList::default_denylist")] pub denylist: FilterList, #[serde(default = "FilterList::default_allowlist")] pub allowlist: FilterList, #[serde(default)] pub rate_limiting_cache_size: usize, #[serde( default, rename = "rate-limiting-cutoff-ms", deserialize_with = "deserialize_rate_limiting_cutoff" )] pub rate_limiting_cutoff: Duration, } fn deserialize_rate_limiting_cutoff<'de, D: Deserializer<'de>>( deserializer: D, ) -> Result { Ok(Duration::from_millis(u64::deserialize(deserializer)?)) } impl TryFrom<&str> for ServerConfig { type Error = AddrParseError; fn try_from(value: &str) -> Result { Ok(ServerConfig { listen: SocketAddr::from_str(value)?, denylist: FilterList::default_denylist(), allowlist: FilterList::default_allowlist(), rate_limiting_cache_size: Default::default(), rate_limiting_cutoff: Default::default(), }) } } #[derive(Debug, PartialEq, Eq, Clone, Deserialize)] #[serde(rename_all = "kebab-case", deny_unknown_fields)] pub struct NtsKeConfig { pub certificate_chain_path: PathBuf, pub private_key_path: PathBuf, #[serde(default)] #[cfg(feature = "unstable_nts-pool")] pub authorized_pool_server_certificates: Vec, #[serde(default = "default_nts_ke_timeout")] pub key_exchange_timeout_ms: u64, pub listen: SocketAddr, pub ntp_port: Option, pub ntp_server: Option, } fn default_nts_ke_timeout() -> u64 { 1000 } #[cfg(test)] mod tests { use super::*; #[test] fn test_deserialize_server() { #[derive(Deserialize, Debug)] struct TestConfig { server: ServerConfig, } let test: TestConfig = toml::from_str( r#" [server] listen = "0.0.0.0:123" "#, ) .unwrap(); assert_eq!(test.server.listen, "0.0.0.0:123".parse().unwrap()); // Defaults assert_eq!(test.server.allowlist.filter, IpFilter::all()); assert_eq!(test.server.allowlist.action, FilterAction::Ignore); assert_eq!(test.server.denylist.filter, IpFilter::none()); assert_eq!(test.server.denylist.action, FilterAction::Ignore); let test: TestConfig = toml::from_str( r#" [server] listen = "127.0.0.1:123" rate-limiting-cutoff-ms = 1000 rate-limiting-cache-size = 32 "#, ) .unwrap(); assert_eq!(test.server.listen, "127.0.0.1:123".parse().unwrap()); assert_eq!(test.server.rate_limiting_cache_size, 32); assert_eq!( test.server.rate_limiting_cutoff, Duration::from_millis(1000) ); let test: TestConfig = toml::from_str( r#" [server] listen = "127.0.0.1:123" [server.denylist] filter = ["192.168.33.34/24"] action = "deny" "#, ) .unwrap(); assert_eq!(test.server.listen, "127.0.0.1:123".parse().unwrap()); assert_eq!(test.server.denylist.action, FilterAction::Deny); let test = toml::from_str::( r#" [server] listen = "127.0.0.1:123" [server.allowlist] filter = ["192.168.33.34/24"] "#, ); assert!(test.is_err()); let test = toml::from_str::( r#" [server] listen = "127.0.0.1:123" [server.denylist] action = "deny" "#, ); assert!(test.is_err()); } #[test] fn test_deserialize_keyset() { #[derive(Deserialize, Debug)] #[serde(rename_all = "kebab-case", deny_unknown_fields)] struct TestConfig { keyset: KeysetConfig, } let test: TestConfig = toml::from_str( r#" [keyset] stale-key-count = 5 key-rotation-interval = 500 key-storage-path = "key/storage/path.key" "#, ) .unwrap(); assert_ne!(test.keyset, KeysetConfig::default()) } #[test] fn test_deserialize_nts_ke() { #[derive(Deserialize, Debug)] #[serde(rename_all = "kebab-case", deny_unknown_fields)] struct TestConfig { nts_ke_server: NtsKeConfig, } let test: TestConfig = toml::from_str( r#" [nts-ke-server] listen = "0.0.0.0:4460" certificate-chain-path = "/foo/bar/baz.pem" private-key-path = "spam.der" "#, ) .unwrap(); let pem = PathBuf::from("/foo/bar/baz.pem"); assert_eq!(test.nts_ke_server.certificate_chain_path, pem); assert_eq!( test.nts_ke_server.private_key_path, PathBuf::from("spam.der") ); assert_eq!(test.nts_ke_server.key_exchange_timeout_ms, 1000,); assert_eq!(test.nts_ke_server.listen, "0.0.0.0:4460".parse().unwrap(),); } #[cfg(feature = "unstable_nts-pool")] #[test] fn test_deserialize_nts_ke_pool_member() { #[derive(Deserialize, Debug)] #[serde(rename_all = "kebab-case", deny_unknown_fields)] struct TestConfig { nts_ke_server: NtsKeConfig, } let test: TestConfig = toml::from_str( r#" [nts-ke-server] listen = "0.0.0.0:4460" certificate-chain-path = "/foo/bar/baz.pem" private-key-path = "spam.der" authorized-pool-server-certificates = [ "foo.pem", "bar.pem" ] "#, ) .unwrap(); assert_eq!( test.nts_ke_server.authorized_pool_server_certificates, vec![PathBuf::from("foo.pem"), PathBuf::from("bar.pem")] ); } } ntpd-1.1.2/src/daemon/config/subnet.rs000064400000000000000000000027061046102023000157440ustar 00000000000000use serde::{de, Deserialize, Deserializer}; use std::net::{AddrParseError, IpAddr}; use thiserror::Error; #[derive(Debug, Clone, PartialEq, Eq)] pub struct IpSubnet { pub addr: IpAddr, pub mask: u8, } #[derive(Debug, Clone, PartialEq, Eq, Error)] pub enum SubnetParseError { #[error("Invalid subnet syntax")] Subnet, #[error("{0} in subnet")] Ip(#[from] AddrParseError), #[error("Invalid subnet mask")] Mask, } impl std::str::FromStr for IpSubnet { type Err = SubnetParseError; fn from_str(s: &str) -> Result { let (addr, mask) = s.split_once('/').ok_or(SubnetParseError::Subnet)?; let addr: IpAddr = addr.parse()?; let mask: u8 = mask.parse().map_err(|_| SubnetParseError::Mask)?; let max_mask = match addr { IpAddr::V4(_) => 32, IpAddr::V6(_) => 128, }; if mask > max_mask { return Err(SubnetParseError::Mask); } Ok(IpSubnet { addr, mask }) } } impl<'de> Deserialize<'de> for IpSubnet { fn deserialize(deserializer: D) -> Result where D: Deserializer<'de>, { let s = String::deserialize(deserializer)?; std::str::FromStr::from_str(&s).map_err(de::Error::custom) } } #[cfg(test)] mod tests { use super::*; #[test] fn test_subnet_parsing() { let a = "0.0.0.0/0".parse::().unwrap(); assert_eq!(a.mask, 0); } } ntpd-1.1.2/src/daemon/ipfilter.rs000064400000000000000000000273251046102023000150210ustar 00000000000000use std::net::{IpAddr, Ipv4Addr, Ipv6Addr}; use serde::{Deserialize, Deserializer}; use super::config::subnet::IpSubnet; /// One part of a `BitTree` #[derive(Debug, Copy, Clone, Default, PartialEq, Eq)] struct TreeNode { // Where in the array the child nodes of this // node are located. A child node is only // generated if the symbol cannot be used to // make a final decision at this level child_offset: u32, inset: u16, outset: u16, } #[derive(Debug, Clone, PartialEq, Eq)] /// `BitTree` is a Trie on 128 bit integers encoding /// which integers are part of the set. /// /// It matches the integer a 4-bit segment at a time /// recording at each level whether for a given symbol /// all integers with the prefix extended with that /// symbol are either in or outside of the set. struct BitTree { nodes: Vec, } const fn top_nibble(v: u128) -> u8 { ((v >> 124) & 0xF) as u8 } /// retain only the top `128 - len` bits const fn apply_mask(val: u128, len: u8) -> u128 { match u128::MAX.checked_shl((128 - len) as u32) { Some(mask) => val & mask, None => 0, } } impl BitTree { /// Lookup whether a given value is in the set encoded in this `BitTree` /// Complexity is O(log(l)), where l is the length of the longest /// prefix in the set. fn lookup(&self, mut val: u128) -> bool { let mut node = &self.nodes[0]; loop { // extract the current symbol as bit and see if we know the answer immediately. // (example: symbol 1 maps to 0x2, symbol 5 maps to 0x10) let cur = 1 << top_nibble(val); if node.inset & cur != 0 { return true; } if node.outset & cur != 0 { return false; } // no decision, shift to next symbol val <<= 4; // To calculate the child index we need to know how many symbols smaller // than our symbol are not decided here. We do this by generating the bitmap // of symbols neither in in or out, then masking out all symbols >=cur // and finaly counting how many are left. let next_idx = node.child_offset + (!(node.inset | node.outset) & (cur - 1)).count_ones(); node = &self.nodes[next_idx as usize]; } } /// Create a `BitTree` from the given prefixes. Complexity is O(n*log(l)), /// where n is the number of prefixes, and l the length of the longest /// prefix. fn create(data: &mut [(u128, u8)]) -> Self { // Ensure values only have 1s in significant positions for (val, len) in data.iter_mut() { *val = apply_mask(*val, *len); } // Ensure values are sorted by value and then by length data.sort(); let mut result = BitTree { nodes: vec![TreeNode::default()], }; result.fill_node(data, 0); result } /// Create the substructure for a node, recursively. /// Max recursion depth is maximum value of data[i].1/4 /// for any i fn fill_node(&mut self, mut data: &mut [(u128, u8)], node_index: usize) { // distribute the data into 16 4-bit buckets let mut counts = [0; 16]; for (val, _) in data.iter() { counts[top_nibble(*val) as usize] += 1; } // Actually split into the relevant subsegments, relies on the input being sorted. let mut subsegments: [&mut [(u128, u8)]; 16] = Default::default(); for (i, start) in counts.iter().enumerate() { (subsegments[i], data) = data.split_at_mut(*start); } // Fill in node let child_offset = self.nodes.len(); let node = &mut self.nodes[node_index]; node.child_offset = child_offset as u32; for (i, segment) in subsegments.iter().enumerate() { match segment.first().copied() { // Probably empty, unless covered earlier, but we fix that later None => node.outset |= 1 << i, // Definetly covered, mark all that is needed // Note that due to sorting order, len here // is guaranteed to be largest amongst all // parts of the segment Some((_, len)) if len <= 4 => { // mark ALL parts of node covered by the segment as in the set. for j in 0..(1 << (4 - len)) { node.inset |= 1 << (i + j as usize); } } // May be covered by a the union of all its parts, we need to check // for that. Otherwise it is undecided Some(_) => { let offset = (i as u128) << 124; let mut last = 0; for part in segment.iter() { if part.0 - offset <= last { last = u128::max(last, part.0 - offset + (1_u128 << (128 - part.1))); } } if last >= (1 << 124) { // All parts together cover the segment, so mark as in node.inset |= 1 << i; } } } } // the outset should not contain anything that is included in the inset // (this can happen due to overcoverage) node.outset &= !node.inset; // bitmap of subsegments for which we have a decision let known_bitmap = node.inset | node.outset; // allocate additional empty nodes let unknown_count = known_bitmap.count_zeros() as usize; self.nodes .extend(std::iter::repeat(TreeNode::default()).take(unknown_count)); // Create children for segments undecided at this level. let mut child_offset = child_offset; for (i, segment) in subsegments.iter_mut().enumerate() { if known_bitmap & (1 << i) != 0 { continue; // no child needed } // we've taken care of the top nibble, // so shift everything over and do a recursive call for (val, len) in segment.iter_mut() { *val <<= 4; *len -= 4; } self.fill_node(segment, child_offset); child_offset += 1; } } } #[derive(Debug, Clone, PartialEq, Eq)] pub struct IpFilter { ipv4_filter: BitTree, ipv6_filter: BitTree, } impl IpFilter { /// Create a filter from a list of subnets /// Complexity: O(n) with n length of list pub fn new(subnets: &[IpSubnet]) -> Self { let mut ipv4list = Vec::new(); let mut ipv6list = Vec::new(); for subnet in subnets { match subnet.addr { IpAddr::V4(addr) => ipv4list.push(( (u32::from_be_bytes(addr.octets()) as u128) << 96, subnet.mask, )), IpAddr::V6(addr) => { ipv6list.push((u128::from_be_bytes(addr.octets()), subnet.mask)); } } } IpFilter { ipv4_filter: BitTree::create(ipv4list.as_mut_slice()), ipv6_filter: BitTree::create(ipv6list.as_mut_slice()), } } pub fn all() -> Self { let mut temp_v4 = [(0, 0)]; let mut temp_v6 = [(0, 0)]; IpFilter { ipv4_filter: BitTree::create(&mut temp_v4), ipv6_filter: BitTree::create(&mut temp_v6), } } pub fn none() -> Self { let mut temp_v4 = []; let mut temp_v6 = []; IpFilter { ipv4_filter: BitTree::create(&mut temp_v4), ipv6_filter: BitTree::create(&mut temp_v6), } } /// Check whether a given ip address is contained in the filter. /// Complexity: O(1) pub fn is_in(&self, addr: &IpAddr) -> bool { match addr { IpAddr::V4(addr) => self.is_in4(addr), IpAddr::V6(addr) => self.is_in6(addr), } } fn is_in4(&self, addr: &Ipv4Addr) -> bool { self.ipv4_filter .lookup((u32::from_be_bytes(addr.octets()) as u128) << 96) } fn is_in6(&self, addr: &Ipv6Addr) -> bool { self.ipv6_filter.lookup(u128::from_be_bytes(addr.octets())) } } impl<'de> Deserialize<'de> for IpFilter { fn deserialize>(deserializer: D) -> Result { let data = Vec::::deserialize(deserializer)?; Ok(IpFilter::new(&data)) } } #[cfg(feature = "__internal-fuzz")] pub mod fuzz { use super::*; fn contains(subnet: &IpSubnet, addr: &IpAddr) -> bool { match (subnet.addr, addr) { (IpAddr::V4(net), IpAddr::V4(addr)) => { let net = u32::from_be_bytes(net.octets()); let addr = u32::from_be_bytes(addr.octets()); let mask = 0xFFFFFFFF_u32 .checked_shl((32 - subnet.mask) as u32) .unwrap_or(0); (net & mask) == (addr & mask) } (IpAddr::V6(net), IpAddr::V6(addr)) => { let net = u128::from_be_bytes(net.octets()); let addr = u128::from_be_bytes(addr.octets()); let mask = 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF_u128 .checked_shl((128 - subnet.mask) as u32) .unwrap_or(0); (net & mask) == (addr & mask) } _ => false, } } fn any_contains(subnets: &[IpSubnet], addr: &IpAddr) -> bool { for net in subnets { if contains(net, addr) { return true; } } false } pub fn fuzz_ipfilter(nets: &[IpSubnet], addr: &[IpAddr]) { let filter = IpFilter::new(nets); for addr in addr { assert_eq!(filter.is_in(addr), any_contains(nets, addr)); } } } #[cfg(test)] mod tests { use super::*; #[test] fn test_bittree() { let mut data = [ (0x10 << 120, 4), (0x20 << 120, 3), (0x43 << 120, 8), (0x82 << 120, 7), ]; let tree = BitTree::create(&mut data); assert!(tree.lookup(0x11 << 120)); assert!(!tree.lookup(0x40 << 120)); assert!(tree.lookup(0x30 << 120)); assert!(tree.lookup(0x43 << 120)); assert!(!tree.lookup(0xC4 << 120)); assert!(tree.lookup(0x82 << 120)); assert!(tree.lookup(0x83 << 120)); assert!(!tree.lookup(0x81 << 120)); } #[test] fn test_filter() { let filter = IpFilter::new(&[ "127.0.0.0/24".parse().unwrap(), "::FFFF:0000:0000/96".parse().unwrap(), ]); assert!(filter.is_in(&"127.0.0.1".parse().unwrap())); assert!(!filter.is_in(&"192.168.1.1".parse().unwrap())); assert!(filter.is_in(&"::FFFF:ABCD:0123".parse().unwrap())); assert!(!filter.is_in(&"::FEEF:ABCD:0123".parse().unwrap())); } #[test] fn test_subnet_edgecases() { let filter = IpFilter::new(&["0.0.0.0/0".parse().unwrap(), "::/0".parse().unwrap()]); assert!(filter.is_in(&"0.0.0.0".parse().unwrap())); assert!(filter.is_in(&"255.255.255.255".parse().unwrap())); assert!(filter.is_in(&"::".parse().unwrap())); assert!(filter.is_in(&"FFFF:FFFF:FFFF:FFFF:FFFF:FFFF:FFFF:FFFF".parse().unwrap())); let filter = IpFilter::new(&[ "1.2.3.4/32".parse().unwrap(), "10:32:54:76:98:BA:DC:FE/128".parse().unwrap(), ]); assert!(filter.is_in(&"1.2.3.4".parse().unwrap())); assert!(!filter.is_in(&"1.2.3.5".parse().unwrap())); assert!(filter.is_in(&"10:32:54:76:98:BA:DC:FE".parse().unwrap())); assert!(!filter.is_in(&"10:32:54:76:98:BA:DC:FF".parse().unwrap())); } } ntpd-1.1.2/src/daemon/keyexchange.rs000064400000000000000000001067151046102023000154770ustar 00000000000000use std::{ future::Future, io::{BufRead, BufReader, IoSlice, Read, Write}, ops::ControlFlow, path::Path, pin::Pin, sync::Arc, task::{Context, Poll}, }; use ntp_proto::{ KeyExchangeClient, KeyExchangeError, KeyExchangeResult, KeyExchangeServer, KeySet, }; use rustls::{Certificate, PrivateKey}; use tokio::{ io::{AsyncRead, AsyncWrite, ReadBuf}, net::TcpListener, task::JoinHandle, }; use super::config::NtsKeConfig; use super::exitcode; fn build_client_config( extra_certificates: &[Certificate], ) -> Result { let mut roots = rustls::RootCertStore::empty(); for cert in rustls_native_certs::load_native_certs()? { let cert = rustls::Certificate(cert.0); roots.add(&cert).map_err(KeyExchangeError::Certificate)?; } for cert in extra_certificates { roots.add(cert).map_err(KeyExchangeError::Certificate)?; } Ok(rustls::ClientConfig::builder() .with_safe_defaults() .with_root_certificates(roots) .with_no_client_auth()) } pub(crate) async fn key_exchange_client( server_name: String, port: u16, extra_certificates: &[Certificate], ) -> Result { let socket = tokio::net::TcpStream::connect((server_name.as_str(), port)).await?; let config = build_client_config(extra_certificates)?; BoundKeyExchangeClient::new(socket, server_name, config, Vec::new())?.await } #[cfg(feature = "unstable_nts-pool")] pub(crate) async fn key_exchange_client_with_denied_servers( server_name: String, port: u16, extra_certificates: &[Certificate], denied_servers: impl IntoIterator, ) -> Result { let socket = tokio::net::TcpStream::connect((server_name.as_str(), port)).await?; let config = build_client_config(extra_certificates)?; BoundKeyExchangeClient::new(socket, server_name, config, denied_servers)?.await } pub fn spawn( nts_ke_config: NtsKeConfig, keyset: tokio::sync::watch::Receiver>, ) -> JoinHandle> { tokio::spawn(async move { let result = run_nts_ke(nts_ke_config, keyset).await; match result { Ok(v) => Ok(v), Err(e) => { tracing::error!("Abnormal termination of NTS KE server: {e}"); std::process::exit(exitcode::SOFTWARE) } } }) } fn io_error(msg: &str) -> std::io::Error { std::io::Error::new(std::io::ErrorKind::Other, msg) } async fn run_nts_ke( nts_ke_config: NtsKeConfig, keyset: tokio::sync::watch::Receiver>, ) -> std::io::Result<()> { let certificate_chain_file = std::fs::File::open(&nts_ke_config.certificate_chain_path) .map_err(|e| { io_error(&format!( "error reading certificate_chain_path at `{:?}`: {:?}", nts_ke_config.certificate_chain_path, e )) })?; let private_key_file = std::fs::File::open(&nts_ke_config.private_key_path).map_err(|e| { io_error(&format!( "error reading key_der_path at `{:?}`: {:?}", nts_ke_config.private_key_path, e )) })?; let cert_chain: Vec = rustls_pemfile::certs(&mut std::io::BufReader::new(certificate_chain_file))? .into_iter() .map(rustls::Certificate) .collect(); #[cfg_attr(not(feature = "unstable_nts-pool"), allow(unused_mut))] let mut pool_certs: Vec = Vec::new(); #[cfg(feature = "unstable_nts-pool")] for client_cert in &nts_ke_config.authorized_pool_server_certificates { let pool_certificate_file = std::fs::File::open(client_cert).map_err(|e| { io_error(&format!( "error reading authorized-pool-server-certificate at `{:?}`: {:?}", client_cert, e )) })?; let mut certs = rustls_pemfile::certs(&mut std::io::BufReader::new(pool_certificate_file))?; // forbid certificate chains at this point if certs.len() == 1 { pool_certs.push(rustls::Certificate(certs.pop().unwrap())) } else { return Err(io_error(&format!( "pool certificate file at `{:?}` should contain exactly one certificate", client_cert ))); } } let private_key = private_key_from_bufread(&mut std::io::BufReader::new(private_key_file))? .ok_or(io_error("could not parse private key"))?; key_exchange_server(keyset, nts_ke_config, cert_chain, pool_certs, private_key).await } fn build_server_config( certificate_chain: Vec, private_key: PrivateKey, ) -> std::io::Result> { let mut config = rustls::ServerConfig::builder() .with_safe_defaults() .with_client_cert_verifier(Arc::new( #[cfg(not(feature = "unstable_nts-pool"))] rustls::server::NoClientAuth, #[cfg(feature = "unstable_nts-pool")] ntp_proto::tls_utils::AllowAnyAnonymousOrCertificateBearingClient, )) .with_single_cert(certificate_chain, private_key) .map_err(|err| std::io::Error::new(std::io::ErrorKind::InvalidInput, err))?; config.alpn_protocols.clear(); config.alpn_protocols.push(b"ntske/1".to_vec()); Ok(Arc::new(config)) } async fn key_exchange_server( keyset: tokio::sync::watch::Receiver>, ke_config: NtsKeConfig, certificate_chain: Vec, pool_certs: Vec, private_key: PrivateKey, ) -> std::io::Result<()> { let listener = TcpListener::bind(&ke_config.listen).await?; let config = build_server_config(certificate_chain, private_key)?; let pool_certs = Arc::<[_]>::from(pool_certs); loop { let (stream, peer_addr) = listener.accept().await?; let config = config.clone(); let keyset = keyset.borrow().clone(); let pool_certs = pool_certs.clone(); let ntp_port = ke_config.ntp_port; let ntp_server = ke_config.ntp_server.clone(); let timeout_ms = ke_config.key_exchange_timeout_ms; let fut = async move { BoundKeyExchangeServer::run( stream, config, keyset, ntp_port, ntp_server.clone(), pool_certs, ) .await .map_err(|ke_error| std::io::Error::new(std::io::ErrorKind::Other, ke_error)) }; tokio::spawn(async move { let timeout = std::time::Duration::from_millis(timeout_ms); match tokio::time::timeout(timeout, fut).await { Err(_) => tracing::debug!(?peer_addr, "NTS KE timed out"), Ok(Err(err)) => tracing::debug!(?err, ?peer_addr, "NTS KE failed"), Ok(Ok(())) => tracing::debug!(?peer_addr, "NTS KE completed"), } }); } } pub(crate) struct BoundKeyExchangeClient where IO: AsyncRead + AsyncWrite + Unpin, { inner: Option>, } impl BoundKeyExchangeClient where IO: AsyncRead + AsyncWrite + Unpin, { pub fn new( io: IO, server_name: String, config: rustls::ClientConfig, denied_servers: impl IntoIterator, ) -> Result { Ok(Self { inner: Some(BoundKeyExchangeClientData { io, client: KeyExchangeClient::new(server_name, config, denied_servers)?, need_flush: false, }), }) } } struct BoundKeyExchangeClientData { io: IO, client: KeyExchangeClient, need_flush: bool, } // IO approach taken from tokio impl BoundKeyExchangeClientData where IO: AsyncRead + AsyncWrite + Unpin, { fn do_write(&mut self, cx: &mut Context<'_>) -> Poll> { let mut writer = WriterAdapter { io: &mut self.io, cx, }; match self.client.write_socket(&mut writer) { Err(ref err) if err.kind() == std::io::ErrorKind::WouldBlock => Poll::Pending, result => Poll::Ready(result), } } fn do_read(&mut self, cx: &mut Context<'_>) -> Poll> { let mut reader = ReaderAdapter { io: &mut self.io, cx, }; match self.client.read_socket(&mut reader) { Err(ref err) if err.kind() == std::io::ErrorKind::WouldBlock => Poll::Pending, result => Poll::Ready(result), } } } impl Future for BoundKeyExchangeClient where IO: AsyncRead + AsyncWrite + Unpin, { type Output = Result; fn poll( self: std::pin::Pin<&mut Self>, cx: &mut std::task::Context<'_>, ) -> std::task::Poll { let outer = self.get_mut(); let mut this = outer.inner.take().unwrap(); let mut write_blocks = false; let mut read_blocks = false; loop { while !write_blocks && this.client.wants_write() { match this.do_write(cx) { Poll::Ready(Ok(_)) => { this.need_flush = true; } Poll::Ready(Err(e)) => return Poll::Ready(Err(e.into())), Poll::Pending => { write_blocks = true; break; } } } if !write_blocks && this.need_flush { match Pin::new(&mut this.io).poll_flush(cx) { Poll::Ready(Ok(())) => { this.need_flush = false; } Poll::Ready(Err(e)) => return Poll::Ready(Err(e.into())), Poll::Pending => { write_blocks = true; } } } while !read_blocks && this.client.wants_read() { match this.do_read(cx) { Poll::Ready(Ok(_)) => { this.client = match this.client.progress() { ControlFlow::Continue(client) => client, ControlFlow::Break(result) => return Poll::Ready(result), } } Poll::Ready(Err(e)) => return Poll::Ready(Err(e.into())), Poll::Pending => { read_blocks = true; break; } } } let no_write = write_blocks || !this.client.wants_write(); let no_read = read_blocks || !this.client.wants_read(); if no_write && no_read { outer.inner = Some(this); return Poll::Pending; } } } } pub(crate) struct BoundKeyExchangeServer where IO: AsyncRead + AsyncWrite + Unpin, { inner: Option>, } impl BoundKeyExchangeServer where IO: AsyncRead + AsyncWrite + Unpin, { pub fn new( io: IO, config: Arc, keyset: Arc, ntp_port: Option, ntp_server: Option, pool_certs: Arc<[rustls::Certificate]>, ) -> Result { let data = BoundKeyExchangeServerData { io, server: KeyExchangeServer::new(config, keyset, ntp_port, ntp_server, pool_certs)?, need_flush: false, }; Ok(Self { inner: Some(data) }) } pub async fn run( io: IO, config: Arc, keyset: Arc, ntp_port: Option, ntp_server: Option, pool_certs: Arc<[rustls::Certificate]>, ) -> Result<(), KeyExchangeError> { let this = Self::new(io, config, keyset, ntp_port, ntp_server, pool_certs)?; this.await } } struct BoundKeyExchangeServerData { io: IO, server: KeyExchangeServer, need_flush: bool, } // IO approach taken from tokio impl BoundKeyExchangeServerData where IO: AsyncRead + AsyncWrite + Unpin, { fn do_write(&mut self, cx: &mut Context<'_>) -> Poll> { let mut writer = WriterAdapter { io: &mut self.io, cx, }; match self.server.write_socket(&mut writer) { Err(ref err) if err.kind() == std::io::ErrorKind::WouldBlock => Poll::Pending, result => Poll::Ready(result), } } fn do_read(&mut self, cx: &mut Context<'_>) -> Poll> { let mut reader = ReaderAdapter { io: &mut self.io, cx, }; match self.server.read_socket(&mut reader) { Err(ref err) if err.kind() == std::io::ErrorKind::WouldBlock => Poll::Pending, result => Poll::Ready(result), } } } impl Future for BoundKeyExchangeServer where IO: AsyncRead + AsyncWrite + Unpin, { type Output = Result<(), KeyExchangeError>; fn poll( self: std::pin::Pin<&mut Self>, cx: &mut std::task::Context<'_>, ) -> std::task::Poll { let outer = self.get_mut(); let mut this = outer.inner.take().unwrap(); let mut write_blocks = false; let mut read_blocks = false; loop { while !write_blocks && this.server.wants_write() { match this.do_write(cx) { Poll::Ready(Ok(_)) => { this.need_flush = true; } Poll::Ready(Err(e)) => return Poll::Ready(Err(e.into())), Poll::Pending => { write_blocks = true; break; } } } if !write_blocks && this.need_flush { match Pin::new(&mut this.io).poll_flush(cx) { Poll::Ready(Ok(())) => { this.need_flush = false; } Poll::Ready(Err(e)) => return Poll::Ready(Err(e.into())), Poll::Pending => { write_blocks = true; } } } while !read_blocks && this.server.wants_read() { match this.do_read(cx) { Poll::Ready(Ok(_)) => { this.server = match this.server.progress() { ControlFlow::Continue(client) => client, ControlFlow::Break(Err(e)) => return Poll::Ready(Err(e)), ControlFlow::Break(Ok(_)) => return Poll::Ready(Ok(())), } } Poll::Ready(Err(e)) => return Poll::Ready(Err(e.into())), Poll::Pending => { read_blocks = true; break; } } } let no_write = write_blocks || !this.server.wants_write(); let no_read = read_blocks || !this.server.wants_read(); if no_write && no_read { outer.inner = Some(this); return Poll::Pending; } } } } /// adapter between `AsyncWrite` and `std::io::Write` struct WriterAdapter<'a, 'b, T> { io: &'a mut T, cx: &'a mut Context<'b>, } impl<'a, 'b, T: AsyncWrite + Unpin> Write for WriterAdapter<'a, 'b, T> { #[inline] fn write(&mut self, buf: &[u8]) -> std::io::Result { match Pin::<&mut T>::new(self.io).poll_write(self.cx, buf) { Poll::Ready(result) => result, Poll::Pending => Err(std::io::ErrorKind::WouldBlock.into()), } } #[inline] fn write_vectored(&mut self, bufs: &[IoSlice<'_>]) -> std::io::Result { match Pin::<&mut T>::new(self.io).poll_write_vectored(self.cx, bufs) { Poll::Ready(result) => result, Poll::Pending => Err(std::io::ErrorKind::WouldBlock.into()), } } fn flush(&mut self) -> std::io::Result<()> { match Pin::<&mut T>::new(self.io).poll_flush(self.cx) { Poll::Ready(result) => result, Poll::Pending => Err(std::io::ErrorKind::WouldBlock.into()), } } } /// adapter between `AsyncRead` and `std::io::Read` struct ReaderAdapter<'a, 'b, T> { io: &'a mut T, cx: &'a mut Context<'b>, } impl<'a, 'b, T: AsyncRead + Unpin> Read for ReaderAdapter<'a, 'b, T> { fn read(&mut self, buf: &mut [u8]) -> Result { let mut buf = ReadBuf::new(buf); match Pin::<&mut T>::new(self.io).poll_read(self.cx, &mut buf) { Poll::Ready(Ok(())) => Ok(buf.filled().len()), Poll::Ready(Err(e)) => Err(e), Poll::Pending => Err(std::io::ErrorKind::WouldBlock.into()), } } } pub(crate) fn certificates_from_file(path: &Path) -> std::io::Result> { let file = std::fs::File::open(path)?; let reader = BufReader::new(file); Ok(certificates_from_bufread(reader)) } fn certificates_from_bufread(mut reader: impl BufRead) -> Vec { rustls_pemfile::certs(&mut reader) .unwrap() .iter() .map(|v| rustls::Certificate(v.clone())) .collect() } fn private_key_from_bufread( mut reader: impl BufRead, ) -> std::io::Result> { use rustls_pemfile::Item; loop { match rustls_pemfile::read_one(&mut reader)? { Some(Item::RSAKey(key)) => return Ok(Some(rustls::PrivateKey(key))), Some(Item::PKCS8Key(key)) => return Ok(Some(rustls::PrivateKey(key))), Some(Item::ECKey(key)) => return Ok(Some(rustls::PrivateKey(key))), None => break, _ => {} } } Ok(None) } #[cfg(test)] mod tests { use std::{io::Cursor, path::PathBuf}; use ntp_proto::{KeySetProvider, NtsRecord}; use tokio::io::{AsyncReadExt, AsyncWriteExt}; use super::*; #[test] fn nos_nl_pem() { let input = include_bytes!("../../testdata/certificates/nos-nl.pem"); let certificates = certificates_from_bufread(input.as_slice()); assert_eq!(certificates.len(), 1); } #[test] fn nos_nl_chain_pem() { let input = include_bytes!("../../testdata/certificates/nos-nl-chain.pem"); let certificates = certificates_from_bufread(input.as_slice()); assert_eq!(certificates.len(), 3); } #[test] fn parse_private_keys() { let input = include_bytes!("../../test-keys/end.key"); let _ = private_key_from_bufread(input.as_slice()).unwrap().unwrap(); let input = include_bytes!("../../test-keys/testca.key"); let _ = private_key_from_bufread(input.as_slice()).unwrap().unwrap(); // openssl does no longer seem to want to generate this format // so we use https://github.com/rustls/pemfile/blob/main/tests/data/rsa1024.pkcs1.pem let input = include_bytes!("../../test-keys/rsa_key.pem"); let _ = private_key_from_bufread(input.as_slice()).unwrap().unwrap(); // openssl ecparam -name prime256v1 -genkey -noout -out ec_key.pem let input = include_bytes!("../../test-keys/ec_key.pem"); let _ = private_key_from_bufread(input.as_slice()).unwrap().unwrap(); // openssl genpkey -algorithm EC -out pkcs8_key.pem -pkeyopt ec_paramgen_curve:prime256v1 let input = include_bytes!("../../test-keys/pkcs8_key.pem"); let _ = private_key_from_bufread(input.as_slice()).unwrap().unwrap(); } #[tokio::test] async fn key_exchange_roundtrip() { let provider = KeySetProvider::new(1); let keyset = provider.get(); #[cfg(feature = "unstable_nts-pool")] let pool_certs = ["testdata/certificates/nos-nl.pem"]; let (_sender, keyset) = tokio::sync::watch::channel(keyset); let nts_ke_config = NtsKeConfig { certificate_chain_path: PathBuf::from("test-keys/end.fullchain.pem"), private_key_path: PathBuf::from("test-keys/end.key"), #[cfg(feature = "unstable_nts-pool")] authorized_pool_server_certificates: pool_certs.iter().map(PathBuf::from).collect(), key_exchange_timeout_ms: 1000, listen: "0.0.0.0:5431".parse().unwrap(), ntp_port: None, ntp_server: None, }; let _join_handle = spawn(nts_ke_config, keyset); // give the server some time to make the port available tokio::time::sleep(std::time::Duration::from_millis(20)).await; let ca = include_bytes!("../../test-keys/testca.pem"); let result = key_exchange_client( "localhost".to_string(), 5431, &certificates_from_bufread(BufReader::new(Cursor::new(ca))), ) .await .unwrap(); assert_eq!(result.remote, "localhost"); assert_eq!(result.port, 123); } #[tokio::test] async fn key_exchange_roundtrip_with_port_server() { let provider = KeySetProvider::new(1); let keyset = provider.get(); #[cfg(feature = "unstable_nts-pool")] let pool_certs = ["testdata/certificates/nos-nl.pem"]; let (_sender, keyset) = tokio::sync::watch::channel(keyset); let nts_ke_config = NtsKeConfig { certificate_chain_path: PathBuf::from("test-keys/end.fullchain.pem"), private_key_path: PathBuf::from("test-keys/end.key"), #[cfg(feature = "unstable_nts-pool")] authorized_pool_server_certificates: pool_certs.iter().map(PathBuf::from).collect(), key_exchange_timeout_ms: 1000, listen: "0.0.0.0:5432".parse().unwrap(), ntp_port: Some(568), ntp_server: Some("jantje".into()), }; let _join_handle = spawn(nts_ke_config, keyset); // give the server some time to make the port available tokio::time::sleep(std::time::Duration::from_millis(20)).await; let ca = include_bytes!("../../test-keys/testca.pem"); let result = key_exchange_client( "localhost".to_string(), 5432, &certificates_from_bufread(BufReader::new(Cursor::new(ca))), ) .await .unwrap(); assert_eq!(result.remote, "jantje"); assert_eq!(result.port, 568); } #[cfg(feature = "unstable_nts-pool")] #[tokio::test] async fn key_exchange_refusal_due_to_invalid_config() { let cert_path = "testdata/certificates/nos-nl-chain.pem"; let certs = [cert_path]; let provider = KeySetProvider::new(1); let keyset = provider.get(); let (_sender, keyset) = tokio::sync::watch::channel(keyset); let nts_ke_config = NtsKeConfig { certificate_chain_path: PathBuf::from("test-keys/end.fullchain.pem"), private_key_path: PathBuf::from("test-keys/end.key"), authorized_pool_server_certificates: certs.iter().map(PathBuf::from).collect(), key_exchange_timeout_ms: 1000, listen: "0.0.0.0:5433".parse().unwrap(), ntp_port: None, ntp_server: None, }; let Err(io_error) = run_nts_ke(nts_ke_config, keyset).await else { panic!("nts server started normally, this should not happen"); }; let expected_error_msg = format!( "pool certificate file at `\"{cert_path}\"` should contain exactly one certificate" ); assert_eq!(io_error.to_string(), expected_error_msg); } #[tokio::test] async fn client_connection_refused() { let result = key_exchange_client("localhost".to_string(), 5434, &[]).await; let error = result.unwrap_err(); match error { KeyExchangeError::Io(error) => { assert_eq!(error.kind(), std::io::ErrorKind::ConnectionRefused); } _ => panic!(), } } fn client_key_exchange_message_length() -> usize { let mut buffer = Vec::with_capacity(1024); for record in ntp_proto::NtsRecord::client_key_exchange_records(vec![]).iter() { record.write(&mut buffer).unwrap(); } buffer.len() } async fn send_records_to_client( records: Vec, ) -> Result { let listener = tokio::net::TcpListener::bind(("localhost", 0)) .await .unwrap(); let port = listener.local_addr()?.port(); tokio::spawn(async move { let cc = include_bytes!("../../test-keys/end.fullchain.pem"); let certificate_chain = certificates_from_bufread(BufReader::new(Cursor::new(cc))); let pk = include_bytes!("../../test-keys/end.key"); let private_key = private_key_from_bufread(pk.as_slice()).unwrap().unwrap(); let config = build_server_config(certificate_chain, private_key).unwrap(); let (stream, _) = listener.accept().await.unwrap(); let acceptor = tokio_rustls::TlsAcceptor::from(config); let mut stream = acceptor.accept(stream).await.unwrap(); // so that we could in theory handle multiple write calls let mut buf = vec![0; client_key_exchange_message_length()]; stream.read_exact(&mut buf).await.unwrap(); for record in records { let mut buffer = Vec::with_capacity(1024); record.write(&mut buffer).unwrap(); stream.write_all(&buffer).await.unwrap(); } }); let ca = include_bytes!("../../test-keys/testca.pem"); let extra_certificates = &certificates_from_bufread(BufReader::new(Cursor::new(ca))); key_exchange_client("localhost".to_string(), port, extra_certificates).await } async fn run_server(listener: tokio::net::TcpListener) -> Result<(), KeyExchangeError> { let cc = include_bytes!("../../test-keys/end.fullchain.pem"); let certificate_chain = certificates_from_bufread(BufReader::new(Cursor::new(cc))); let pk = include_bytes!("../../test-keys/end.key"); let private_key = private_key_from_bufread(pk.as_slice()).unwrap().unwrap(); let config = build_server_config(certificate_chain, private_key).unwrap(); let pool_certs = Arc::<[_]>::from(vec![]); let (stream, _) = listener.accept().await.unwrap(); let provider = KeySetProvider::new(0); let keyset = provider.get(); BoundKeyExchangeServer::run(stream, config, keyset, None, None, pool_certs).await } async fn client_tls_stream( server_name: &str, port: u16, ) -> tokio_rustls::client::TlsStream { let stream = tokio::net::TcpStream::connect((server_name, port)) .await .unwrap(); let ca = include_bytes!("../../test-keys/testca.pem"); let extra_certificates = &certificates_from_bufread(BufReader::new(Cursor::new(ca))); let config = build_client_config(extra_certificates).unwrap(); let domain = rustls::ServerName::try_from(server_name) .map_err(|_| std::io::Error::new(std::io::ErrorKind::InvalidInput, "invalid dnsname")) .unwrap(); let connector = tokio_rustls::TlsConnector::from(Arc::new(config)); connector.connect(domain, stream).await.unwrap() } async fn send_records_to_server(records: Vec) -> Result<(), KeyExchangeError> { let listener = TcpListener::bind(&("localhost", 0)).await?; let port = listener.local_addr()?.port(); tokio::spawn(async move { let mut stream = client_tls_stream("localhost", port).await; for record in records { let mut buffer = Vec::with_capacity(1024); record.write(&mut buffer).unwrap(); stream.write_all(&buffer).await.unwrap(); } let mut buf = [0; 1024]; loop { match stream.read(&mut buf).await.unwrap() { 0 => break, _ => continue, } } }); run_server(listener).await } #[tokio::test] async fn receive_cookies() { let result = send_records_to_client(vec![ NtsRecord::NextProtocol { protocol_ids: vec![0], }, NtsRecord::AeadAlgorithm { critical: false, algorithm_ids: vec![15], }, NtsRecord::NewCookie { cookie_data: vec![1, 2, 3], }, NtsRecord::EndOfMessage, ]) .await; assert!(result.is_ok()); } #[tokio::test] async fn records_after_end_are_ignored() { let result = send_records_to_client(vec![ NtsRecord::NextProtocol { protocol_ids: vec![0], }, NtsRecord::AeadAlgorithm { critical: false, algorithm_ids: vec![15], }, NtsRecord::NewCookie { cookie_data: vec![1, 2, 3], }, NtsRecord::EndOfMessage, NtsRecord::NewCookie { cookie_data: vec![1, 2, 3], }, ]) .await; assert!(result.is_ok()); } #[tokio::test] async fn no_cookies() { let result = send_records_to_client(vec![ NtsRecord::NextProtocol { protocol_ids: vec![0], }, NtsRecord::AeadAlgorithm { critical: false, algorithm_ids: vec![15], }, NtsRecord::EndOfMessage, ]) .await; let error = result.unwrap_err(); assert!(matches!(error, KeyExchangeError::NoCookies)); } async fn client_error_record(errorcode: u16) -> KeyExchangeError { let result = send_records_to_client(vec![ NtsRecord::Error { errorcode }, NtsRecord::EndOfMessage, ]) .await; result.unwrap_err() } #[tokio::test] async fn client_receives_error_record() { use KeyExchangeError as KEE; let error = client_error_record(NtsRecord::UNRECOGNIZED_CRITICAL_RECORD).await; assert!(matches!(error, KEE::UnrecognizedCriticalRecord)); let error = client_error_record(NtsRecord::BAD_REQUEST).await; assert!(matches!(error, KEE::BadRequest)); let error = client_error_record(NtsRecord::INTERNAL_SERVER_ERROR).await; assert!(matches!(error, KEE::InternalServerError)); } #[tokio::test] async fn server_expected_client_records() { let records = NtsRecord::client_key_exchange_records(vec![]).to_vec(); let result = send_records_to_server(records).await; assert!(result.is_ok()); } #[tokio::test] async fn immediate_end_of_message() { let records = vec![NtsRecord::EndOfMessage]; let result = send_records_to_server(records).await; assert!(matches!(result, Err(KeyExchangeError::NoValidProtocol))); } #[tokio::test] async fn double_next_protocol() { let records = vec![ NtsRecord::NextProtocol { protocol_ids: vec![0], }, NtsRecord::NextProtocol { protocol_ids: vec![0], }, NtsRecord::EndOfMessage, ]; let result = send_records_to_server(records).await; assert!(matches!(result, Err(KeyExchangeError::BadRequest))); } #[tokio::test] async fn records_after_end_of_message() { let records = vec![ NtsRecord::NextProtocol { protocol_ids: vec![0], }, NtsRecord::AeadAlgorithm { critical: false, algorithm_ids: vec![15], }, NtsRecord::EndOfMessage, NtsRecord::EndOfMessage, ]; let result = send_records_to_server(records).await; // records after the first EndOfMessage are ignored assert!(result.is_ok()); } #[tokio::test] async fn client_no_valid_algorithm() { let records = vec![ NtsRecord::NextProtocol { protocol_ids: vec![0], }, NtsRecord::AeadAlgorithm { critical: false, algorithm_ids: vec![], }, NtsRecord::EndOfMessage, ]; let result = send_records_to_server(records).await; assert!(matches!(result, Err(KeyExchangeError::NoValidAlgorithm))); } #[tokio::test] async fn client_no_valid_protocol() { let records = vec![ NtsRecord::NextProtocol { protocol_ids: vec![], }, NtsRecord::AeadAlgorithm { critical: false, algorithm_ids: vec![15], }, NtsRecord::EndOfMessage, ]; let result = send_records_to_server(records).await; assert!(matches!(result, Err(KeyExchangeError::NoValidProtocol))); } #[tokio::test] async fn unrecognized_critical_record() { let records = vec![ NtsRecord::Unknown { record_type: 1234, critical: true, data: vec![], }, NtsRecord::EndOfMessage, ]; let result = send_records_to_server(records).await; assert!(matches!( result, Err(KeyExchangeError::UnrecognizedCriticalRecord) )); } #[tokio::test] async fn client_sends_no_records_clean_shutdown() { let listener = TcpListener::bind(&("localhost", 0)).await.unwrap(); let port = listener.local_addr().unwrap().port(); tokio::spawn(async move { // give the server some time to make the port available tokio::time::sleep(std::time::Duration::from_millis(20)).await; // create the stream, then shut it down without sending anything let mut stream = client_tls_stream("localhost", port).await; stream.shutdown().await.unwrap(); }); let result = run_server(listener).await; assert!(matches!(result, Err(KeyExchangeError::IncompleteResponse))); } #[tokio::test] async fn client_sends_no_records_dirty_shutdown() { let listener = TcpListener::bind(&("localhost", 0)).await.unwrap(); let port = listener.local_addr().unwrap().port(); tokio::spawn(async move { // create the stream, then shut it down without sending anything let stream = client_tls_stream("localhost", port).await; stream.into_inner().0.shutdown().await.unwrap(); }); let result = run_server(listener).await; assert!(matches!(result, Err(KeyExchangeError::IncompleteResponse))); } async fn server_error_record(errorcode: u16) -> KeyExchangeError { let result = send_records_to_server(vec![ NtsRecord::Error { errorcode }, NtsRecord::EndOfMessage, ]) .await; result.unwrap_err() } #[tokio::test] async fn server_receives_error_record() { use KeyExchangeError as KEE; let error = server_error_record(NtsRecord::UNRECOGNIZED_CRITICAL_RECORD).await; assert!(matches!(error, KEE::UnrecognizedCriticalRecord)); let error = server_error_record(NtsRecord::BAD_REQUEST).await; assert!(matches!(error, KEE::BadRequest)); let error = server_error_record(NtsRecord::INTERNAL_SERVER_ERROR).await; assert!(matches!(error, KEE::InternalServerError)); } } ntpd-1.1.2/src/daemon/mod.rs000064400000000000000000000104301046102023000137470ustar 00000000000000pub mod config; mod ipfilter; pub mod keyexchange; pub mod nts_key_provider; pub mod observer; mod peer; mod server; pub mod sockets; pub mod spawn; mod system; pub mod tracing; use std::{error::Error, path::PathBuf}; use ::tracing::info; pub use config::Config; #[cfg(feature = "__internal-fuzz")] pub use ipfilter::fuzz::fuzz_ipfilter; pub use observer::{ObservablePeerState, ObservableState, ObservedPeerState}; pub use system::spawn; use tracing_subscriber::util::SubscriberInitExt; use config::NtpDaemonOptions; use self::tracing::LogLevel; const VERSION: &str = env!("CARGO_PKG_VERSION"); pub async fn main() -> Result<(), Box> { let options = NtpDaemonOptions::try_parse_from(std::env::args())?; match options.action { config::NtpDaemonAction::Help => { println!("{}", config::long_help_message()); } config::NtpDaemonAction::Version => { eprintln!("ntp-daemon {VERSION}"); } config::NtpDaemonAction::Run => run(options).await?, } Ok(()) } // initializes the logger so that logs during config parsing are reported. Then it overrides the // log level based on the config if required. pub(crate) async fn initialize_logging_parse_config( initial_log_level: Option, config_path: Option, ) -> Config { let mut log_level = initial_log_level.unwrap_or_default(); let config_tracing = crate::daemon::tracing::tracing_init(log_level); let config = ::tracing::subscriber::with_default(config_tracing, || { async { match Config::from_args(config_path, vec![], vec![]).await { Ok(c) => c, Err(e) => { // print to stderr because tracing is not yet setup eprintln!("There was an error loading the config: {e}"); std::process::exit(exitcode::CONFIG); } } } }) .await; if let Some(config_log_level) = config.observability.log_level { if initial_log_level.is_none() { log_level = config_log_level; } } // set a default global subscriber from now on let tracing_inst = self::tracing::tracing_init(log_level); tracing_inst.init(); config } async fn run(options: NtpDaemonOptions) -> Result<(), Box> { let config = initialize_logging_parse_config(options.log_level, options.config).await; // give the user a warning that we use the command line option if config.observability.log_level.is_some() && options.log_level.is_some() { info!("Log level override from command line arguments is active"); } // Warn/error if the config is unreasonable. We do this after finishing // tracing setup to ensure logging is fully configured. config.check(); // we always generate the keyset (even if NTS is not used) let keyset = nts_key_provider::spawn(config.keyset).await; #[cfg(feature = "hardware-timestamping")] let clock_config = config.clock; #[cfg(not(feature = "hardware-timestamping"))] let clock_config = config::ClockConfig::default(); ::tracing::debug!("Configuration loaded, spawning daemon jobs"); let (main_loop_handle, channels) = spawn( config.synchronization, config.source_defaults, clock_config, &config.sources, &config.servers, keyset.clone(), ) .await?; for nts_ke_config in config.nts_ke { let _join_handle = keyexchange::spawn(nts_ke_config, keyset.clone()); } observer::spawn( &config.observability, channels.peer_snapshots_receiver, channels.server_data_receiver, channels.system_snapshot_receiver, ) .await; Ok(main_loop_handle.await??) } pub(crate) mod exitcode { /// An internal software error has been detected. This /// should be limited to non-operating system related /// errors as possible. pub const SOFTWARE: i32 = 70; /// You did not have sufficient permission to perform /// the operation. This is not intended for file system /// problems, which should use `NOINPUT` or `CANTCREAT`, /// but rather for higher level permissions. pub const NOPERM: i32 = 77; /// Something was found in an unconfigured or misconfigured state. pub const CONFIG: i32 = 78; } ntpd-1.1.2/src/daemon/nts_key_provider.rs000064400000000000000000000055561046102023000165730ustar 00000000000000use std::{ fs::{File, OpenOptions}, os::unix::prelude::{OpenOptionsExt, PermissionsExt}, sync::Arc, }; use ntp_proto::{KeySet, KeySetProvider}; use tokio::sync::watch; use tracing::warn; use super::config::KeysetConfig; pub async fn spawn(config: KeysetConfig) -> watch::Receiver> { let (mut provider, mut next_interval) = match &config.key_storage_path { Some(path) => { let path = path.to_owned(); if let Ok(meta) = std::fs::metadata(&path) { let perm = meta.permissions(); if perm.mode() as libc::mode_t & (libc::S_IWOTH | libc::S_IROTH | libc::S_IXOTH) != 0 { warn!("Keyset file permissions: Others can interact with it. This is a potential security issue."); } } let (provider, time) = tokio::task::spawn_blocking( move || -> std::io::Result<(KeySetProvider, std::time::SystemTime)> { let mut input = File::open(path)?; KeySetProvider::load(&mut input, config.stale_key_count) }, ) .await .unwrap_or_else(|e| Err(std::io::Error::new(std::io::ErrorKind::Other, e))) .unwrap_or_else(|e| { warn!(error = ?e, "Could not load nts server keys, starting with new set"); ( KeySetProvider::new(config.stale_key_count), std::time::SystemTime::now(), ) }); ( provider, std::time::Duration::from_secs(config.key_rotation_interval as _).saturating_sub( std::time::SystemTime::now() .duration_since(time) .unwrap_or(std::time::Duration::from_secs(0)), ), ) } None => ( KeySetProvider::new(config.stale_key_count), std::time::Duration::from_secs(config.key_rotation_interval as _), ), }; let (tx, rx) = watch::channel(provider.get()); tokio::task::spawn_blocking(move || loop { std::thread::sleep(next_interval); next_interval = std::time::Duration::from_secs(config.key_rotation_interval as _); provider.rotate(); if let Some(path) = &config.key_storage_path { if let Err(e) = (|| -> std::io::Result<()> { let mut output = OpenOptions::new() .create(true) .truncate(true) .write(true) .mode(0o600) .open(path)?; provider.store(&mut output) })() { warn!(error = ?e, "Could not store nts server keys"); } } if tx.send(provider.get()).is_err() { break; } }); rx } ntpd-1.1.2/src/daemon/observer.rs000064400000000000000000000260051046102023000150240ustar 00000000000000use super::server::ServerStats; use super::sockets::create_unix_socket_with_permissions; use super::spawn::PeerId; use super::system::ServerData; use ntp_proto::{ObservablePeerTimedata, PollInterval, SystemSnapshot}; use std::os::unix::fs::PermissionsExt; use std::{net::SocketAddr, time::Instant}; use tokio::task::JoinHandle; use tracing::warn; use serde::{Deserialize, Serialize}; #[derive(Debug, Serialize, Deserialize)] pub struct ObservableState { pub program: ProgramData, pub system: SystemSnapshot, pub sources: Vec, pub servers: Vec, } #[derive(Debug, Serialize, Deserialize)] pub struct ProgramData { pub version: String, pub build_commit: String, pub build_commit_date: String, pub uptime_seconds: f64, } impl ProgramData { pub fn with_uptime(uptime_seconds: f64) -> ProgramData { ProgramData { uptime_seconds, ..Default::default() } } } impl Default for ProgramData { fn default() -> Self { Self { version: env!("CARGO_PKG_VERSION").to_owned(), build_commit: env!("NTPD_RS_GIT_REV").to_owned(), build_commit_date: env!("NTPD_RS_GIT_DATE").to_owned(), uptime_seconds: 0.0, } } } #[derive(Debug, Serialize, Deserialize)] pub struct ObservableServerState { pub address: SocketAddr, pub stats: ServerStats, } impl From<&ServerData> for ObservableServerState { fn from(data: &ServerData) -> Self { ObservableServerState { address: data.config.listen, stats: data.stats.clone(), } } } #[derive(Debug, Serialize, Deserialize, Clone)] pub enum ObservablePeerState { Nothing, Observable(ObservedPeerState), } #[derive(Debug, Serialize, Deserialize, Clone)] pub struct ObservedPeerState { #[serde(flatten)] pub timedata: ObservablePeerTimedata, pub unanswered_polls: u32, pub poll_interval: PollInterval, pub name: String, pub address: String, pub id: PeerId, } pub async fn spawn( config: &super::config::ObservabilityConfig, peers_reader: tokio::sync::watch::Receiver>, server_reader: tokio::sync::watch::Receiver>, system_reader: tokio::sync::watch::Receiver, ) -> JoinHandle> { let config = config.clone(); tokio::spawn(async move { let result = observer(config, peers_reader, server_reader, system_reader).await; if let Err(ref e) = result { warn!("Abnormal termination of the state observer: {e}"); warn!("The state observer will not be available"); } result }) } async fn observer( config: super::config::ObservabilityConfig, peers_reader: tokio::sync::watch::Receiver>, server_reader: tokio::sync::watch::Receiver>, system_reader: tokio::sync::watch::Receiver, ) -> std::io::Result<()> { let start_time = Instant::now(); let path = match config.observation_path { Some(path) => path, None => return Ok(()), }; // this binary needs to run as root to be able to adjust the system clock. // by default, the socket inherits root permissions, but the client should not need // elevated permissions to read from the socket. So we explicitly set the permissions let permissions: std::fs::Permissions = PermissionsExt::from_mode(config.observation_permissions); let peers_listener = create_unix_socket_with_permissions(&path, permissions)?; loop { let (mut stream, _addr) = peers_listener.accept().await?; let observe = ObservableState { program: ProgramData::with_uptime(start_time.elapsed().as_secs_f64()), sources: peers_reader.borrow().to_owned(), system: *system_reader.borrow(), servers: server_reader.borrow().iter().map(|s| s.into()).collect(), }; super::sockets::write_json(&mut stream, &observe).await?; } } #[cfg(test)] mod tests { #[cfg(feature = "unstable_ntpv5")] use rand::thread_rng; use std::{borrow::BorrowMut, time::Duration}; #[cfg(feature = "unstable_ntpv5")] use ntp_proto::v5::{BloomFilter, ServerId}; use ntp_proto::{ NtpClock, NtpDuration, NtpLeapIndicator, NtpTimestamp, PollInterval, PollIntervalLimits, Reach, ReferenceId, TimeSnapshot, }; use tokio::{io::AsyncReadExt, net::UnixStream}; use super::*; #[derive(Debug, Clone, Default)] struct TestClock {} impl NtpClock for TestClock { type Error = std::io::Error; fn now(&self) -> std::result::Result { Err(std::io::Error::from(std::io::ErrorKind::Unsupported)) } fn set_frequency(&self, _freq: f64) -> Result { Ok(NtpTimestamp::default()) } fn step_clock(&self, _offset: NtpDuration) -> Result { Ok(NtpTimestamp::default()) } fn enable_ntp_algorithm(&self) -> Result<(), Self::Error> { Ok(()) } fn disable_ntp_algorithm(&self) -> Result<(), Self::Error> { Ok(()) } fn ntp_algorithm_update( &self, _offset: NtpDuration, _poll_interval: PollInterval, ) -> Result<(), Self::Error> { Ok(()) } fn error_estimate_update( &self, _est_error: NtpDuration, _max_error: NtpDuration, ) -> Result<(), Self::Error> { Ok(()) } fn status_update(&self, _leap_status: NtpLeapIndicator) -> Result<(), Self::Error> { Ok(()) } } #[tokio::test] async fn test_observation() { // be careful with copying: tests run concurrently and should use a unique socket name! let path = std::env::temp_dir().join("ntp-test-stream-2"); let config = super::super::config::ObservabilityConfig { log_level: None, observation_path: Some(path.clone()), observation_permissions: 0o700, ..Default::default() }; let (_, peers_reader) = tokio::sync::watch::channel(vec![ ObservablePeerState::Nothing, ObservablePeerState::Nothing, ObservablePeerState::Observable(ObservedPeerState { timedata: Default::default(), unanswered_polls: Reach::default().unanswered_polls(), poll_interval: PollIntervalLimits::default().min, name: "127.0.0.3:123".into(), address: "127.0.0.3:123".into(), id: PeerId::new(), }), ]); let (_, servers_reader) = tokio::sync::watch::channel(vec![]); let (_, system_reader) = tokio::sync::watch::channel(SystemSnapshot { stratum: 1, reference_id: ReferenceId::NONE, accumulated_steps_threshold: None, time_snapshot: TimeSnapshot { poll_interval: PollIntervalLimits::default().min, precision: NtpDuration::from_seconds(1e-3), root_delay: NtpDuration::ZERO, root_dispersion: NtpDuration::ZERO, leap_indicator: NtpLeapIndicator::Leap59, accumulated_steps: NtpDuration::ZERO, }, #[cfg(feature = "unstable_ntpv5")] bloom_filter: BloomFilter::new(), #[cfg(feature = "unstable_ntpv5")] server_id: ServerId::new(&mut thread_rng()), }); let handle = tokio::spawn(async move { observer(config, peers_reader, servers_reader, system_reader) .await .unwrap(); }); tokio::time::sleep(Duration::from_millis(10)).await; let mut reader = UnixStream::connect(path).await.unwrap(); let mut buf = vec![]; while reader.read_buf(&mut buf).await.unwrap() != 0 {} let result: ObservableState = serde_json::from_slice(&buf).unwrap(); // Deal with randomized order let mut count = 0; for peer in &result.sources { if matches!(peer, ObservablePeerState::Observable { .. }) { count += 1; } } assert_eq!(count, 1); handle.abort(); } #[tokio::test] async fn test_block_during_read() { // be careful with copying: tests run concurrently and should use a unique socket name! let path = std::env::temp_dir().join("ntp-test-stream-3"); let config = super::super::config::ObservabilityConfig { log_level: None, observation_path: Some(path.clone()), observation_permissions: 0o700, ..Default::default() }; let (mut peers_writer, peers_reader) = tokio::sync::watch::channel(vec![ ObservablePeerState::Nothing, ObservablePeerState::Nothing, ObservablePeerState::Observable(ObservedPeerState { timedata: Default::default(), unanswered_polls: Reach::default().unanswered_polls(), poll_interval: PollIntervalLimits::default().min, name: "127.0.0.3:123".into(), address: "127.0.0.3:123".into(), id: PeerId::new(), }), ]); let (mut server_writer, servers_reader) = tokio::sync::watch::channel(vec![]); let (mut system_writer, system_reader) = tokio::sync::watch::channel(SystemSnapshot { stratum: 1, reference_id: ReferenceId::NONE, accumulated_steps_threshold: None, time_snapshot: TimeSnapshot { poll_interval: PollIntervalLimits::default().min, precision: NtpDuration::from_seconds(1e-3), root_delay: NtpDuration::ZERO, root_dispersion: NtpDuration::ZERO, leap_indicator: NtpLeapIndicator::Leap59, accumulated_steps: NtpDuration::ZERO, }, #[cfg(feature = "unstable_ntpv5")] bloom_filter: BloomFilter::new(), #[cfg(feature = "unstable_ntpv5")] server_id: ServerId::new(&mut thread_rng()), }); let handle = tokio::spawn(async move { observer(config, peers_reader, servers_reader, system_reader) .await .unwrap(); }); tokio::time::sleep(Duration::from_millis(10)).await; let mut reader = UnixStream::connect(path).await.unwrap(); // We do a small partial read of the data to test that whatever // happens, the observer doesnt keep a lock alive on either of // of the RwLocks. let mut buf = [0_u8; 12]; let mut bufref: &mut [u8] = &mut buf; reader.read_buf(&mut bufref).await.unwrap(); // Ensure none of the locks is held long term let _ = system_writer.borrow_mut(); let _ = peers_writer.borrow_mut(); let _ = server_writer.borrow_mut(); handle.abort(); } } ntpd-1.1.2/src/daemon/peer.rs000064400000000000000000000602721046102023000141340ustar 00000000000000use std::{ future::Future, marker::PhantomData, net::{Ipv4Addr, Ipv6Addr, SocketAddr}, pin::Pin, }; use ntp_proto::{ IgnoreReason, Measurement, NtpClock, NtpInstant, NtpTimestamp, Peer, PeerNtsData, PeerSnapshot, PollError, ProtocolVersion, SourceDefaultsConfig, SynchronizationConfig, SystemSnapshot, Update, }; use ntp_udp::{EnableTimestamps, InterfaceName, UdpSocket}; use rand::{thread_rng, Rng}; use tracing::{debug, error, info, instrument, warn, Instrument, Span}; use tokio::time::{Instant, Sleep}; use super::{exitcode, spawn::PeerId}; /// Trait needed to allow injecting of futures other than `tokio::time::Sleep` for testing pub trait Wait: Future { fn reset(self: Pin<&mut Self>, deadline: Instant); } impl Wait for Sleep { fn reset(self: Pin<&mut Self>, deadline: Instant) { self.reset(deadline); } } #[derive(Debug, Clone)] pub enum MsgForSystem { /// Received a Kiss-o'-Death and must demobilize MustDemobilize(PeerId), /// Experienced a network issue and must be restarted NetworkIssue(PeerId), /// Source is unreachable, and should be restarted with new resolved addr. Unreachable(PeerId), /// Received an acceptable packet and made a new peer snapshot /// A new measurement should try to trigger a clock select NewMeasurement(PeerId, PeerSnapshot, Measurement), /// A snapshot may have been updated, but this should not /// trigger a clock select in System UpdatedSnapshot(PeerId, PeerSnapshot), } #[derive(Debug, Clone)] pub struct PeerChannels { pub msg_for_system_sender: tokio::sync::mpsc::Sender, pub system_snapshot_receiver: tokio::sync::watch::Receiver, pub synchronization_config_receiver: tokio::sync::watch::Receiver, pub source_defaults_config_receiver: tokio::sync::watch::Receiver, } pub(crate) struct PeerTask { _wait: PhantomData, index: PeerId, clock: C, socket: UdpSocket, channels: PeerChannels, peer: Peer, // we don't store the real origin timestamp in the packet, because that would leak our // system time to the network (and could make attacks easier). So instead there is some // garbage data in the origin_timestamp field, and we need to track and pass along the // actual origin timestamp ourselves. /// Timestamp of the last packet that we sent last_send_timestamp: Option, /// Instant last poll message was sent (used for timing the wait) last_poll_sent: Instant, } #[derive(Debug)] enum PollResult { Ok, NetworkGone, Unreachable, } #[derive(Debug)] enum PacketResult { Ok, Demobilize, } impl PeerTask where C: 'static + NtpClock + Send, T: Wait, { /// Set the next deadline for the poll interval based on current state fn update_poll_wait(&self, poll_wait: &mut Pin<&mut T>, system_snapshot: SystemSnapshot) { let poll_interval = self .peer .current_poll_interval(system_snapshot) .as_system_duration(); // randomize the poll interval a little to make it harder to predict poll requests let poll_interval = poll_interval.mul_f64(thread_rng().gen_range(1.01..=1.05)); poll_wait .as_mut() .reset(self.last_poll_sent + poll_interval); } async fn handle_poll(&mut self, poll_wait: &mut Pin<&mut T>) -> PollResult { let system_snapshot = *self.channels.system_snapshot_receiver.borrow(); let peer_defaults_snapshot_system = *self .channels .source_defaults_config_receiver .borrow_and_update(); let mut buf = [0; 1024]; let packet = match self.peer.generate_poll_message( &mut buf, system_snapshot, &peer_defaults_snapshot_system, ) { Ok(packet) => packet, Err(PollError::Io(e)) => { warn!(error = ?e, "Could not generate poll message"); // not exactly a network gone situation, but needs the same response return PollResult::NetworkGone; } Err(PollError::PeerUnreachable) => { warn!("Peer is no longer reachable over network, restarting"); return PollResult::Unreachable; } }; // Sent a poll, so update waiting to match deadline of next self.last_poll_sent = Instant::now(); self.update_poll_wait(poll_wait, system_snapshot); // the last_send_timestamp is only None at startup let is_first_snapshot = self.last_send_timestamp.is_none(); // The first snapshot does not contain useful data (stratum is invalid) // Skipping the message prevents confusing log messages from being emitted. if !is_first_snapshot { // NOTE: fitness check is not performed here, but by System let snapshot = PeerSnapshot::from_peer(&self.peer); let msg = MsgForSystem::UpdatedSnapshot(self.index, snapshot); self.channels.msg_for_system_sender.send(msg).await.ok(); } match self.clock.now() { Err(e) => { // we cannot determine the origin_timestamp error!(error = ?e, "There was an error retrieving the current time"); // report as no permissions, since this seems the most likely std::process::exit(exitcode::NOPERM); } Ok(ts) => { self.last_send_timestamp = Some(ts); } } match self.socket.send(packet).await { Err(error) => { warn!(?error, "poll message could not be sent"); match error.raw_os_error() { Some(libc::EHOSTDOWN) | Some(libc::EHOSTUNREACH) | Some(libc::ENETDOWN) | Some(libc::ENETUNREACH) => return PollResult::NetworkGone, _ => {} } } Ok((_written, opt_send_timestamp)) => { // update the last_send_timestamp with the one given by the kernel, if available self.last_send_timestamp = opt_send_timestamp.or(self.last_send_timestamp); } } PollResult::Ok } async fn handle_packet<'a>( &mut self, poll_wait: &mut Pin<&mut T>, packet: &'a [u8], send_timestamp: NtpTimestamp, recv_timestamp: NtpTimestamp, ) -> PacketResult { let ntp_instant = NtpInstant::now(); let system_snapshot = *self.channels.system_snapshot_receiver.borrow(); let result = self.peer.handle_incoming( system_snapshot, packet, ntp_instant, send_timestamp, recv_timestamp, ); // Handle incoming may have changed poll interval based on message, respect that change self.update_poll_wait(poll_wait, system_snapshot); match result { Ok(update) => { debug!("packet accepted"); // NOTE: fitness check is not performed here, but by System let msg = match update { Update::BareUpdate(update) => MsgForSystem::UpdatedSnapshot(self.index, update), Update::NewMeasurement(update, measurement) => { MsgForSystem::NewMeasurement(self.index, update, measurement) } }; self.channels.msg_for_system_sender.send(msg).await.ok(); } Err(IgnoreReason::KissDemobilize) => { info!("Demobilizing peer connection on request of remote."); let msg = MsgForSystem::MustDemobilize(self.index); self.channels.msg_for_system_sender.send(msg).await.ok(); return PacketResult::Demobilize; } Err(ignore_reason) => { debug!(?ignore_reason, "packet ignored"); } } PacketResult::Ok } async fn run(&mut self, mut poll_wait: Pin<&mut T>) { loop { let mut buf = [0_u8; 1024]; tokio::select! { () = &mut poll_wait => { tracing::debug!("wait completed"); match self.handle_poll(&mut poll_wait).await { PollResult::Ok => {}, PollResult::NetworkGone => { self.channels.msg_for_system_sender.send(MsgForSystem::NetworkIssue(self.index)).await.ok(); break; } PollResult::Unreachable => { self.channels.msg_for_system_sender.send(MsgForSystem::Unreachable(self.index)).await.ok(); break; } } }, result = self.socket.recv(&mut buf) => { tracing::debug!("accept packet"); match accept_packet(result, &buf) { AcceptResult::Accept(packet, recv_timestamp) => { let send_timestamp = match self.last_send_timestamp { Some(ts) => ts, None => { debug!("we received a message without having sent one; discarding"); continue; } }; match self.handle_packet(&mut poll_wait, packet, send_timestamp, recv_timestamp).await { PacketResult::Ok => {}, PacketResult::Demobilize => break, } }, AcceptResult::NetworkGone => { self.channels.msg_for_system_sender.send(MsgForSystem::NetworkIssue(self.index)).await.ok(); break; }, AcceptResult::Ignore => {}, } }, _ = self.channels.synchronization_config_receiver.changed(), if self.channels.synchronization_config_receiver.has_changed().is_ok() => { self.peer.update_config(*self.channels.source_defaults_config_receiver.borrow_and_update()); }, } } } } impl PeerTask where C: 'static + NtpClock + Send, { #[allow(clippy::too_many_arguments)] #[instrument(skip(clock, channels))] pub fn spawn( index: PeerId, addr: SocketAddr, interface: Option, clock: C, enable_timestamps: EnableTimestamps, network_wait_period: std::time::Duration, mut channels: PeerChannels, protocol_version: ProtocolVersion, nts: Option>, ) -> tokio::task::JoinHandle<()> { tokio::spawn( (async move { let socket_fut = UdpSocket::client_with_timestamping( unspecified_for(addr), addr, interface, enable_timestamps, ); let socket = match socket_fut.await { Ok(socket) => socket, Err(error) => { warn!(?error, "Could not open socket"); tokio::time::sleep(network_wait_period).await; channels .msg_for_system_sender .send(MsgForSystem::NetworkIssue(index)) .await .ok(); return; } }; // Unwrap should be safe because we know the socket was bound to a local addres just before let our_addr = socket.as_ref().local_addr().unwrap(); // Unwrap should be safe because we know the socket was connected to a remote peer just before let source_addr = socket.as_ref().peer_addr().unwrap(); let local_clock_time = NtpInstant::now(); let config_snapshot = *channels.source_defaults_config_receiver.borrow_and_update(); let peer = if let Some(nts) = nts { Peer::new_nts( our_addr, source_addr, local_clock_time, config_snapshot, protocol_version, nts, ) } else { Peer::new( our_addr, source_addr, local_clock_time, config_snapshot, protocol_version, ) }; let poll_wait = tokio::time::sleep(std::time::Duration::default()); tokio::pin!(poll_wait); let mut process = PeerTask { _wait: PhantomData, index, clock, channels, socket, peer, last_send_timestamp: None, last_poll_sent: Instant::now(), }; process.run(poll_wait).await; }) .instrument(Span::current()), ) } } #[derive(Debug)] enum AcceptResult<'a> { Accept(&'a [u8], NtpTimestamp), Ignore, NetworkGone, } fn unspecified_for(addr: SocketAddr) -> SocketAddr { match addr { SocketAddr::V4(_) => SocketAddr::from((Ipv4Addr::UNSPECIFIED, 0)), SocketAddr::V6(_) => SocketAddr::from((Ipv6Addr::UNSPECIFIED, 0)), } } fn accept_packet( result: Result<(usize, SocketAddr, Option), std::io::Error>, buf: &[u8], ) -> AcceptResult { match result { Ok((size, _, Some(recv_timestamp))) => { // Note: packets are allowed to be bigger when including extensions. // we don't expect them, but the server may still send them. The // extra bytes are guaranteed safe to ignore. `recv` truncates the messages. // Messages of fewer than 48 bytes are skipped entirely if size < 48 { debug!(expected = 48, actual = size, "received packet is too small"); AcceptResult::Ignore } else { AcceptResult::Accept(&buf[0..size], recv_timestamp) } } Ok((size, _, None)) => { warn!(?size, "received a packet without a timestamp"); AcceptResult::Ignore } Err(receive_error) => { warn!(?receive_error, "could not receive packet"); match receive_error.raw_os_error() { Some(libc::EHOSTDOWN) | Some(libc::EHOSTUNREACH) | Some(libc::ENETDOWN) | Some(libc::ENETUNREACH) => AcceptResult::NetworkGone, _ => AcceptResult::Ignore, } } } } #[cfg(test)] mod tests { use std::{io::Cursor, sync::Arc, time::Duration}; use ntp_proto::{ NoCipher, NtpDuration, NtpLeapIndicator, NtpPacket, PollInterval, TimeSnapshot, }; use tokio::sync::mpsc; use super::*; struct TestWaitSender { state: Arc>, } impl TestWaitSender { fn notify(&self) { let mut state = self.state.lock().unwrap(); state.pending = true; if let Some(waker) = state.waker.take() { waker.wake(); } } } struct TestWait { state: Arc>, } struct TestWaitState { waker: Option, pending: bool, } impl Future for TestWait { type Output = (); fn poll( self: Pin<&mut Self>, cx: &mut std::task::Context<'_>, ) -> std::task::Poll { let mut state = self.state.lock().unwrap(); if state.pending { state.pending = false; state.waker = None; std::task::Poll::Ready(()) } else { state.waker = Some(cx.waker().clone()); std::task::Poll::Pending } } } impl Wait for TestWait { fn reset(self: Pin<&mut Self>, _deadline: Instant) {} } impl Drop for TestWait { fn drop(&mut self) { self.state.lock().unwrap().waker = None; } } impl TestWait { fn new() -> (TestWait, TestWaitSender) { let state = Arc::new(std::sync::Mutex::new(TestWaitState { waker: None, pending: false, })); ( TestWait { state: state.clone(), }, TestWaitSender { state }, ) } } const EPOCH_OFFSET: u32 = (70 * 365 + 17) * 86400; #[derive(Debug, Clone, Default)] struct TestClock {} impl NtpClock for TestClock { type Error = std::time::SystemTimeError; fn now(&self) -> std::result::Result { let cur = std::time::SystemTime::now().duration_since(std::time::SystemTime::UNIX_EPOCH)?; Ok(NtpTimestamp::from_seconds_nanos_since_ntp_era( EPOCH_OFFSET.wrapping_add(cur.as_secs() as u32), cur.subsec_nanos(), )) } fn set_frequency(&self, _freq: f64) -> Result { panic!("Shouldn't be called by peer"); } fn step_clock(&self, _offset: NtpDuration) -> Result { panic!("Shouldn't be called by peer"); } fn enable_ntp_algorithm(&self) -> Result<(), Self::Error> { panic!("Shouldn't be called by peer"); } fn disable_ntp_algorithm(&self) -> Result<(), Self::Error> { panic!("Shouldn't be called by peer"); } fn ntp_algorithm_update( &self, _offset: NtpDuration, _poll_interval: PollInterval, ) -> Result<(), Self::Error> { panic!("Shouldn't be called by peer"); } fn error_estimate_update( &self, _est_error: NtpDuration, _max_error: NtpDuration, ) -> Result<(), Self::Error> { panic!("Shouldn't be called by peer"); } fn status_update(&self, _leap_status: NtpLeapIndicator) -> Result<(), Self::Error> { panic!("Shouldn't be called by peer"); } } async fn test_startup( port_base: u16, ) -> ( PeerTask, UdpSocket, mpsc::Receiver, ) { // Note: Ports must be unique among tests to deal with parallelism, hence // port_base let socket = UdpSocket::client( SocketAddr::from((Ipv4Addr::LOCALHOST, port_base)), SocketAddr::from((Ipv4Addr::LOCALHOST, port_base + 1)), ) .await .unwrap(); let test_socket = UdpSocket::client( SocketAddr::from((Ipv4Addr::LOCALHOST, port_base + 1)), SocketAddr::from((Ipv4Addr::LOCALHOST, port_base)), ) .await .unwrap(); let our_addr = socket.as_ref().local_addr().unwrap(); let source_addr = socket.as_ref().peer_addr().unwrap(); let (_, system_snapshot_receiver) = tokio::sync::watch::channel(SystemSnapshot::default()); let (_, synchronization_config_receiver) = tokio::sync::watch::channel(SynchronizationConfig::default()); let (_, mut peer_defaults_config_receiver) = tokio::sync::watch::channel(SourceDefaultsConfig::default()); let (msg_for_system_sender, msg_for_system_receiver) = mpsc::channel(1); let local_clock_time = NtpInstant::now(); let peer = Peer::new( our_addr, source_addr, local_clock_time, *peer_defaults_config_receiver.borrow_and_update(), ProtocolVersion::default(), ); let process = PeerTask { _wait: PhantomData, index: PeerId::new(), clock: TestClock {}, channels: PeerChannels { msg_for_system_sender, system_snapshot_receiver, synchronization_config_receiver, source_defaults_config_receiver: peer_defaults_config_receiver, }, socket, peer, last_send_timestamp: None, last_poll_sent: Instant::now(), }; (process, test_socket, msg_for_system_receiver) } #[tokio::test] async fn test_poll_sends_state_update_and_packet() { // Note: Ports must be unique among tests to deal with parallelism let (mut process, socket, _) = test_startup(8006).await; let (poll_wait, poll_send) = TestWait::new(); let handle = tokio::spawn(async move { tokio::pin!(poll_wait); process.run(poll_wait).await; }); poll_send.notify(); let mut buf = [0; 48]; let network = socket.recv(&mut buf).await.unwrap(); assert_eq!(network.0, 48); handle.abort(); } fn serialize_packet_unencryped(send_packet: &NtpPacket) -> [u8; 48] { let mut buf = [0; 48]; let mut cursor = Cursor::new(buf.as_mut_slice()); send_packet.serialize(&mut cursor, &NoCipher, None).unwrap(); assert_eq!(cursor.position(), 48); buf } #[tokio::test] async fn test_timeroundtrip() { // Note: Ports must be unique among tests to deal with parallelism let (mut process, mut socket, mut msg_recv) = test_startup(8008).await; let system = SystemSnapshot { time_snapshot: TimeSnapshot { leap_indicator: NtpLeapIndicator::NoWarning, ..Default::default() }, ..Default::default() }; let (poll_wait, poll_send) = TestWait::new(); let clock = TestClock {}; let handle = tokio::spawn(async move { tokio::pin!(poll_wait); process.run(poll_wait).await; }); poll_send.notify(); let mut buf = [0; 48]; let (size, _, timestamp) = socket.recv(&mut buf).await.unwrap(); assert_eq!(size, 48); let timestamp = timestamp.unwrap(); let rec_packet = NtpPacket::deserialize(&buf, &NoCipher).unwrap().0; let send_packet = NtpPacket::timestamp_response(&system, rec_packet, timestamp, &clock); let serialized = serialize_packet_unencryped(&send_packet); socket.send(&serialized).await.unwrap(); let msg = msg_recv.recv().await.unwrap(); assert!(matches!(msg, MsgForSystem::NewMeasurement(_, _, _))); handle.abort(); } #[tokio::test] async fn test_deny_stops_poll() { // Note: Ports must be unique among tests to deal with parallelism let (mut process, mut socket, mut msg_recv) = test_startup(8010).await; let (poll_wait, poll_send) = TestWait::new(); let handle = tokio::spawn(async move { tokio::pin!(poll_wait); process.run(poll_wait).await; }); poll_send.notify(); let mut buf = [0; 48]; let (size, _, timestamp) = socket.recv(&mut buf).await.unwrap(); assert_eq!(size, 48); assert!(timestamp.is_some()); let rec_packet = NtpPacket::deserialize(&buf, &NoCipher).unwrap().0; let send_packet = NtpPacket::deny_response(rec_packet); let serialized = serialize_packet_unencryped(&send_packet); socket.send(&serialized).await.unwrap(); let msg = msg_recv.recv().await.unwrap(); assert!(matches!(msg, MsgForSystem::MustDemobilize(_))); poll_send.notify(); tokio::select! { _ = tokio::time::sleep(Duration::from_millis(10)) => {/*expected */}, _ = socket.recv(&mut buf) => { unreachable!("should not receive anything") } } handle.abort(); } } ntpd-1.1.2/src/daemon/server.rs000064400000000000000000001260401046102023000145030ustar 00000000000000use std::{ collections::hash_map::RandomState, hash::BuildHasher, io::Cursor, net::{IpAddr, SocketAddr}, sync::{ atomic::{AtomicU64, Ordering}, Arc, }, time::{Duration, Instant}, }; use ntp_proto::{ Cipher, DecodedServerCookie, KeySet, NoCipher, NtpAssociationMode, NtpClock, NtpPacket, NtpTimestamp, PacketParsingError, SystemSnapshot, }; use ntp_udp::{InterfaceName, UdpSocket}; use serde::{Deserialize, Deserializer, Serialize, Serializer}; use tokio::task::JoinHandle; use tracing::{debug, instrument, trace, warn}; use super::config::{FilterAction, ServerConfig}; // Maximum size of udp packet we handle const MAX_PACKET_SIZE: usize = 1024; #[derive(Default, Debug, Clone, Serialize, Deserialize)] pub struct ServerStats { pub received_packets: Counter, pub accepted_packets: Counter, pub denied_packets: Counter, pub ignored_packets: Counter, pub rate_limited_packets: Counter, pub response_send_errors: Counter, pub nts_received_packets: Counter, pub nts_accepted_packets: Counter, pub nts_denied_packets: Counter, pub nts_rate_limited_packets: Counter, pub nts_nak_packets: Counter, } impl ServerStats { fn update_from(&self, accept_result: &AcceptResult<'_>) { use AcceptResult::{Accept, CryptoNak, Deny, Ignore, RateLimit}; self.received_packets.inc(); match accept_result { Accept { .. } => self.accepted_packets.inc(), Ignore => self.ignored_packets.inc(), Deny { .. } => self.denied_packets.inc(), RateLimit { .. } => self.rate_limited_packets.inc(), CryptoNak { .. } => self.nts_nak_packets.inc(), }; if accept_result.is_nts() { self.nts_received_packets.inc(); match accept_result { Accept { .. } => self.nts_accepted_packets.inc(), Deny { .. } => self.nts_denied_packets.inc(), RateLimit { .. } => self.nts_rate_limited_packets.inc(), CryptoNak { .. } | Ignore => { /* counted above */ } }; } } } #[derive(Debug, Clone, Default)] pub struct Counter { value: Arc, } impl Counter { fn inc(&self) { self.value.fetch_add(1, Ordering::Relaxed); } pub fn get(&self) -> u64 { self.value.as_ref().load(Ordering::Relaxed) } } impl Serialize for Counter { fn serialize(&self, serializer: S) -> Result where S: Serializer, { serializer.serialize_u64(self.get()) } } impl<'de> Deserialize<'de> for Counter { fn deserialize(deserializer: D) -> Result where D: Deserializer<'de>, { let value = Arc::new(Deserialize::deserialize(deserializer)?); Ok(Counter { value }) } } pub struct ServerTask { config: ServerConfig, network_wait_period: std::time::Duration, system_receiver: tokio::sync::watch::Receiver, keyset: tokio::sync::watch::Receiver>, system: SystemSnapshot, client_cache: TimestampedCache, clock: C, interface: Option, stats: ServerStats, } #[derive(Debug)] enum AcceptResult<'a> { Accept { packet: NtpPacket<'a>, decoded_cookie: Option, recv_timestamp: NtpTimestamp, }, Ignore, Deny { packet: NtpPacket<'a>, decoded_cookie: Option, }, RateLimit { packet: NtpPacket<'a>, decoded_cookie: Option, }, CryptoNak { packet: NtpPacket<'a>, }, } impl AcceptResult<'_> { fn apply_deny(self) -> Self { // We should send deny messages only to reasonable requests // otherwise two servers could end up in a loop of sending // deny's to each other. match self { AcceptResult::Accept { packet, decoded_cookie, .. } => AcceptResult::Deny { packet, decoded_cookie, }, other => other, } } fn apply_rate_limit(self) -> Self { match self { AcceptResult::Accept { packet, decoded_cookie, .. } => AcceptResult::RateLimit { packet, decoded_cookie, }, other => other, } } fn is_nts(&self) -> bool { match self { AcceptResult::Accept { decoded_cookie, .. } | AcceptResult::Deny { decoded_cookie, .. } | AcceptResult::RateLimit { decoded_cookie, .. } => decoded_cookie.is_some(), AcceptResult::CryptoNak { .. } => true, AcceptResult::Ignore => false, } } fn kind_name(&self) -> &'static str { match self { AcceptResult::Accept { .. } => "Accept", AcceptResult::Ignore => "Ignore", AcceptResult::Deny { .. } => "Deny", AcceptResult::RateLimit { .. } => "RateLimit", AcceptResult::CryptoNak { .. } => "CryptoNak", } } } #[must_use] #[derive(Debug, Clone, Copy)] enum SocketConnection { KeepAlive, Reconnect, } enum FilterReason { Deny, Ignore, RateLimit, } impl ServerTask { pub fn spawn( config: ServerConfig, stats: ServerStats, mut system_receiver: tokio::sync::watch::Receiver, keyset: tokio::sync::watch::Receiver>, clock: C, interface: Option, network_wait_period: Duration, ) -> JoinHandle<()> { tokio::spawn(async move { let rate_limiting_cache_size = config.rate_limiting_cache_size; let system: SystemSnapshot = *system_receiver.borrow_and_update(); let mut process = ServerTask { config, network_wait_period, system, system_receiver, keyset, clock, interface, client_cache: TimestampedCache::new(rate_limiting_cache_size), stats, }; process.serve().await; }) } fn filter(&self, addr: &IpAddr) -> Option { if self.config.denylist.filter.is_in(addr) { // First apply denylist Some(self.config.denylist.action) } else if !self.config.allowlist.filter.is_in(addr) { // Then allowlist Some(self.config.allowlist.action) } else { None } } #[instrument(level = "debug", skip(self), fields( addr = debug(self.config.listen), ))] async fn serve(&mut self) { let mut cur_socket = None; loop { // open socket if it is not already open let socket = match &cur_socket { Some(socket) => socket, None => { let new_socket = loop { match UdpSocket::server(self.config.listen, self.interface).await { Ok(socket) => break socket, Err(error) => { warn!(?error, ?self.config.listen, ?self.interface, "Could not open server socket"); tokio::time::sleep(self.network_wait_period).await; } } }; // system may now be wildly out of date, ensure it is always updated. self.system = *self.system_receiver.borrow_and_update(); cur_socket.insert(new_socket) } }; let mut buf = [0_u8; MAX_PACKET_SIZE]; tokio::select! { recv_res = socket.recv(&mut buf) => { match self.handle_receive(socket, &buf, recv_res).await { SocketConnection::KeepAlive => { /* do nothing */ } SocketConnection::Reconnect => { cur_socket = None } } }, _ = self.system_receiver.changed(), if self.system_receiver.has_changed().is_ok() => { self.system = *self.system_receiver.borrow_and_update(); } } } } /// Checks if the address of the sender is on the allow or deny list and if the address already /// did perform a request within the last `cutoff` interval fn check_and_update_filters( &mut self, peer_addr: SocketAddr, cutoff: Duration, ) -> Result<(), FilterReason> { match self.filter(&peer_addr.ip()) { Some(FilterAction::Deny) => Err(FilterReason::Deny), Some(FilterAction::Ignore) => Err(FilterReason::Ignore), None => { let now = Instant::now(); if self.client_cache.is_allowed(peer_addr.ip(), now, cutoff) { Ok(()) } else { Err(FilterReason::RateLimit) } } } } /// Handle the result of the `recv` call /// - decide if an IO error warrants reopening the socket /// - check if the sender address matches any of the allow, deny, or rate-limit filters /// /// -> call [`Self::generate_response`] to further process the packet async fn handle_receive( &mut self, socket: &ntp_udp::UdpSocket, buf: &[u8], recv_res: std::io::Result<(usize, SocketAddr, Option)>, ) -> SocketConnection { match recv_res { Err(receive_error) => { warn!(?receive_error, "could not receive packet"); // For a server, we only trigger NetworkGone restarts // on ENETDOWN. ENETUNREACH, EHOSTDOWN and EHOSTUNREACH // do not signal restart-worthy conditions for the a // server (they essentially indicate problems with the // remote network/host, which is not relevant for a server). // Furthermore, they can conceivably be triggered by a // malicious third party, and triggering restart on them // would then result in a denial-of-service. match receive_error.raw_os_error() { Some(libc::ENETDOWN) => SocketConnection::Reconnect, _ => { self.stats.ignored_packets.inc(); SocketConnection::KeepAlive } } } Ok((length, peer_addr, opt_timestamp)) => { let Some(request_buf) = buf.get(..length) else { warn!("length from socket is out of bounds. This is a bug!"); return SocketConnection::Reconnect; }; // The response buffer gets the same size as the request was so we can never send // a response that is longer than the request let mut response_buf = [0; MAX_PACKET_SIZE]; let response_buf = &mut response_buf[..length]; let Some(response) = self.handle_packet(request_buf, response_buf, peer_addr, opt_timestamp) else { return SocketConnection::KeepAlive; }; if let Err(send_err) = socket.send_to(response, peer_addr).await { self.stats.response_send_errors.inc(); debug!(error=?send_err, "Could not send response packet"); } SocketConnection::KeepAlive } } } #[instrument(level = "debug", skip_all, fields(peer_addr, size = request_buf.len(), opt_timestamp))] fn handle_packet<'buf>( &mut self, request_buf: &[u8], response_buf: &'buf mut [u8], peer_addr: SocketAddr, opt_timestamp: Option, ) -> Option<&'buf [u8]> { let Some(timestamp) = opt_timestamp else { debug!("received a packet without a timestamp"); self.stats.update_from(&AcceptResult::Ignore); return None; }; // Note: packets are allowed to be bigger when including extensions. // we don't expect many, but the client may still send them. We try // to see if the message still makes sense with some bytes dropped. // Messages of fewer than 48 bytes are skipped entirely if request_buf.len() < 48 { debug!("received packet is too small"); self.stats.update_from(&AcceptResult::Ignore); return None; } let filter_result = self.check_and_update_filters(peer_addr, self.config.rate_limiting_cutoff); if let Err(FilterReason::Ignore) = filter_result { debug!("filters decided to ignore"); self.stats.update_from(&AcceptResult::Ignore); return None; } // actually parse the packet. KeySet is cloned to not take a lock let keyset = self.keyset.borrow().clone(); let accept_result = Self::accept_data(request_buf, keyset.as_ref(), timestamp); // apply filters let accept_result = match filter_result { Ok(_) => accept_result, Err(FilterReason::Ignore) => AcceptResult::Ignore, Err(FilterReason::Deny) => accept_result.apply_deny(), Err(FilterReason::RateLimit) => accept_result.apply_rate_limit(), }; // update statistics self.stats.update_from(&accept_result); debug!(kind = accept_result.kind_name(), "Decided response"); let (packet, opt_cipher) = self.generate_response(accept_result)?; let response_buf = Self::serialize_response(response_buf, packet, opt_cipher)?; debug!(response_size = response_buf.len(), "Generated response"); Some(response_buf) } fn generate_response<'a>( &self, accept_result: AcceptResult<'a>, ) -> Option<(NtpPacket<'a>, Option>)> { let (packet, cipher) = match accept_result { AcceptResult::Ignore => { return None; } AcceptResult::Accept { packet, decoded_cookie, recv_timestamp, } => match decoded_cookie { Some(cookie) => { let keyset = self.keyset.borrow().clone(); let response = NtpPacket::nts_timestamp_response( &self.system, packet, recv_timestamp, &self.clock, &cookie, &keyset, ); (response, Some(cookie.s2c)) } None => ( NtpPacket::timestamp_response( &self.system, packet, recv_timestamp, &self.clock, ), None, ), }, AcceptResult::CryptoNak { packet } => (NtpPacket::nts_nak_response(packet), None), AcceptResult::Deny { packet, decoded_cookie, } => match decoded_cookie { Some(cookie) => (NtpPacket::nts_deny_response(packet), Some(cookie.s2c)), None => (NtpPacket::deny_response(packet), None), }, AcceptResult::RateLimit { packet, decoded_cookie, } => match decoded_cookie { Some(cookie) => (NtpPacket::nts_rate_limit_response(packet), Some(cookie.s2c)), None => (NtpPacket::rate_limit_response(packet), None), }, }; Some((packet, cipher)) } /// Build a response to the given packet fn serialize_response<'buf>( response_buf: &'buf mut [u8], packet: NtpPacket<'_>, opt_cipher: Option>, ) -> Option<&'buf [u8]> { let desired_size = match packet.version() { 5 => Some(response_buf.len()), _ => None, }; let mut cursor = Cursor::new(response_buf); let serialize_result = match opt_cipher { Some(cipher) => packet.serialize(&mut cursor, cipher.as_ref(), desired_size), None => packet.serialize(&mut cursor, &NoCipher, desired_size), }; if let Err(serialize_err) = serialize_result { warn!(error=?serialize_err, "Could not serialize response"); return None; } let end = usize::try_from(cursor.position()).expect(concat!( "cursor.position() is always less then usize::MAX, ", "since &[u8] can be at most usize::MAX bytes", )); let response_buf = cursor.into_inner(); Some(&response_buf[..end]) } /// Deserialize the packet and decide what our response should be /// - check if the packet can even be deserialized /// - check if it was successfully decrypted (and authenticated) /// - check if it was a request packet (`Client` prior to NTPv5) fn accept_data<'a>( buf: &'a [u8], keyset: &KeySet, recv_timestamp: NtpTimestamp, ) -> AcceptResult<'a> { match NtpPacket::deserialize(buf, keyset) { Ok((packet, decoded_cookie)) => match packet.mode() { NtpAssociationMode::Client => { trace!("NTP client request accepted"); AcceptResult::Accept { packet, decoded_cookie, recv_timestamp, } } _ => { trace!("NTP packet with unknown mode {:?} ignored", packet.mode()); AcceptResult::Ignore } }, Err(PacketParsingError::DecryptError(packet)) => { debug!("received packet with invalid nts cookie"); AcceptResult::CryptoNak { packet } } Err(e) => { debug!("received invalid packet: {e}"); AcceptResult::Ignore } } } } /// A size-bounded cache where each entry is timestamped. /// /// The planned use is in rate limiting: we keep track of when a peer last checked in. If it checks /// in too often, we issue a rate limiting KISS code. /// /// For this use case we want fast /// /// - lookups: for each incomming IP we must check when it last checked in /// - inserts: for each incomming IP we store that its most recent checkin is now /// /// Hence, this data structure is a vector, and we use a simple hash function to turn the incomming /// address into an index. Lookups and inserts are therefore O(1). /// /// The likelyhood of hash collisions can be controlled by changing the size of the cache. Hash collisions /// will happen, so this cache should not be relied on if perfect alerting is deemed critical. #[derive(Debug)] struct TimestampedCache { randomstate: RandomState, elements: Vec>, } impl TimestampedCache { fn new(length: usize) -> Self { Self { // looks a bit odd, but prevents a `Clone` constraint elements: std::iter::repeat_with(|| None).take(length).collect(), randomstate: RandomState::new(), } } fn index(&self, item: &T) -> usize { use std::hash::Hasher; let mut hasher = self.randomstate.build_hasher(); item.hash(&mut hasher); hasher.finish() as usize % self.elements.len() } fn is_allowed(&mut self, item: T, timestamp: Instant, cutoff: Duration) -> bool { if self.elements.is_empty() { // cache disabled, always OK return true; } let index = self.index(&item); // check if the current occupant of this slot is actually the same item let timestamp_if_same = self.elements[index] .as_ref() .and_then(|(v, t)| (&item == v).then_some(t)) .copied(); self.elements[index] = Some((item, timestamp)); if let Some(old_timestamp) = timestamp_if_same { // old and new are the same; check the time timestamp.duration_since(old_timestamp) >= cutoff } else { // old and new are different; this is always OK true } } } #[cfg(test)] mod tests { use std::time::Duration; use ntp_proto::{ KeySetProvider, NoCipher, NtpDuration, NtpLeapIndicator, PollInterval, PollIntervalLimits, ReferenceId, }; use crate::daemon::config::FilterList; use super::*; const EPOCH_OFFSET: u32 = (70 * 365 + 17) * 86400; #[derive(Debug, Clone, Default)] struct TestClock {} impl NtpClock for TestClock { type Error = std::time::SystemTimeError; fn now(&self) -> std::result::Result { let cur = std::time::SystemTime::now().duration_since(std::time::SystemTime::UNIX_EPOCH)?; Ok(NtpTimestamp::from_seconds_nanos_since_ntp_era( EPOCH_OFFSET.wrapping_add(cur.as_secs() as u32), cur.subsec_nanos(), )) } fn set_frequency(&self, _freq: f64) -> Result { panic!("Shouldn't be called by peer"); } fn step_clock(&self, _offset: NtpDuration) -> Result { panic!("Shouldn't be called by peer"); } fn enable_ntp_algorithm(&self) -> Result<(), Self::Error> { panic!("Shouldn't be called by peer"); } fn disable_ntp_algorithm(&self) -> Result<(), Self::Error> { panic!("Shouldn't be called by peer"); } fn ntp_algorithm_update( &self, _offset: NtpDuration, _poll_interval: PollInterval, ) -> Result<(), Self::Error> { panic!("Shouldn't be called by peer"); } fn error_estimate_update( &self, _est_error: NtpDuration, _max_error: NtpDuration, ) -> Result<(), Self::Error> { panic!("Shouldn't be called by peer"); } fn status_update(&self, _leap_status: NtpLeapIndicator) -> Result<(), Self::Error> { panic!("Shouldn't be called by peer"); } } fn serialize_packet_unencryped(send_packet: &NtpPacket) -> Vec { let mut buf = vec![0; MAX_PACKET_SIZE]; let mut cursor = Cursor::new(buf.as_mut_slice()); send_packet.serialize(&mut cursor, &NoCipher, None).unwrap(); let end = cursor.position() as usize; buf.truncate(end); buf } fn default_server_task() -> ServerTask { let config = ServerConfig { listen: "127.0.0.1:9000".parse().unwrap(), denylist: FilterList::default_denylist(), allowlist: FilterList::default_allowlist(), rate_limiting_cutoff: Duration::from_secs(0), rate_limiting_cache_size: 32, }; let (_, mut system_snapshots) = tokio::sync::watch::channel(SystemSnapshot::default()); let clock = TestClock {}; let (_, keyset) = tokio::sync::watch::channel(KeySetProvider::new(1).get()); let rate_limiting_cache_size = config.rate_limiting_cache_size; let system: SystemSnapshot = *system_snapshots.borrow_and_update(); ServerTask { config, network_wait_period: Default::default(), keyset, system, system_receiver: system_snapshots, client_cache: TimestampedCache::new(rate_limiting_cache_size), clock, interface: InterfaceName::DEFAULT, stats: Default::default(), } } #[tokio::test] async fn test_server_filter_allow_ok() { let config = ServerConfig { listen: "127.0.0.1:9000".parse().unwrap(), denylist: FilterList::default_denylist(), allowlist: FilterList::new(&["127.0.0.0/24".parse().unwrap()], FilterAction::Ignore), rate_limiting_cutoff: Duration::from_secs(1), rate_limiting_cache_size: 32, }; let (_, system_snapshots) = tokio::sync::watch::channel(SystemSnapshot::default()); let clock = TestClock {}; let (_, keyset) = tokio::sync::watch::channel(KeySetProvider::new(1).get()); let server = ServerTask::spawn( config, Default::default(), system_snapshots, keyset, clock, InterfaceName::DEFAULT, Duration::from_secs(1), ); let mut socket = UdpSocket::client( "127.0.0.1:9001".parse().unwrap(), "127.0.0.1:9000".parse().unwrap(), ) .await .unwrap(); let (packet, id) = NtpPacket::poll_message(PollIntervalLimits::default().min); let serialized = serialize_packet_unencryped(&packet); socket.send(&serialized).await.unwrap(); let mut buf = [0; 48]; tokio::time::timeout(Duration::from_millis(10), socket.recv(&mut buf)) .await .unwrap() .unwrap(); let packet = NtpPacket::deserialize(&buf, &NoCipher).unwrap().0; assert_ne!(packet.stratum(), 0); assert!(packet.valid_server_response(id, false)); server.abort(); } #[tokio::test] async fn test_server_filter_allow_deny() { let config = ServerConfig { listen: "127.0.0.1:9002".parse().unwrap(), denylist: FilterList::default_denylist(), allowlist: FilterList::new(&["128.0.0.0/24".parse().unwrap()], FilterAction::Deny), rate_limiting_cutoff: Duration::from_secs(1), rate_limiting_cache_size: 32, }; let (_, system_snapshots) = tokio::sync::watch::channel(SystemSnapshot::default()); let clock = TestClock {}; let (_, keyset) = tokio::sync::watch::channel(KeySetProvider::new(1).get()); let server = ServerTask::spawn( config, Default::default(), system_snapshots, keyset, clock, InterfaceName::DEFAULT, Duration::from_secs(1), ); let mut socket = UdpSocket::client( "127.0.0.1:9003".parse().unwrap(), "127.0.0.1:9002".parse().unwrap(), ) .await .unwrap(); let (packet, id) = NtpPacket::poll_message(PollIntervalLimits::default().min); let serialized = serialize_packet_unencryped(&packet); socket.send(&serialized).await.unwrap(); let mut buf = [0; 48]; tokio::time::timeout(Duration::from_millis(10), socket.recv(&mut buf)) .await .unwrap() .unwrap(); let packet = NtpPacket::deserialize(&buf, &NoCipher).unwrap().0; assert_eq!(packet.stratum(), 0); assert_eq!(packet.reference_id(), ReferenceId::KISS_DENY); assert!(packet.valid_server_response(id, false)); server.abort(); } #[tokio::test] async fn test_server_filter_allow_ignore() { let config = ServerConfig { listen: "127.0.0.1:9004".parse().unwrap(), denylist: FilterList::default_denylist(), allowlist: FilterList::new(&["128.0.0.0/24".parse().unwrap()], FilterAction::Ignore), rate_limiting_cutoff: Duration::from_secs(1), rate_limiting_cache_size: 32, }; let (_, system_snapshots) = tokio::sync::watch::channel(SystemSnapshot::default()); let clock = TestClock {}; let (_, keyset) = tokio::sync::watch::channel(KeySetProvider::new(1).get()); let server = ServerTask::spawn( config, Default::default(), system_snapshots, keyset, clock, InterfaceName::DEFAULT, Duration::from_secs(1), ); let mut socket = UdpSocket::client( "127.0.0.1:9005".parse().unwrap(), "127.0.0.1:9004".parse().unwrap(), ) .await .unwrap(); let (packet, _) = NtpPacket::poll_message(PollIntervalLimits::default().min); let serialized = serialize_packet_unencryped(&packet); socket.send(&serialized).await.unwrap(); let mut buf = [0; 48]; let res = tokio::time::timeout(Duration::from_millis(10), socket.recv(&mut buf)).await; assert!(res.is_err()); server.abort(); } #[tokio::test] async fn test_server_filter_deny_ok() { let config = ServerConfig { listen: "127.0.0.1:9006".parse().unwrap(), denylist: FilterList::new(&["192.168.0.0/16".parse().unwrap()], FilterAction::Ignore), allowlist: FilterList::default_allowlist(), rate_limiting_cutoff: Duration::from_secs(1), rate_limiting_cache_size: 32, }; let (_, system_snapshots) = tokio::sync::watch::channel(SystemSnapshot::default()); let clock = TestClock {}; let (_, keyset) = tokio::sync::watch::channel(KeySetProvider::new(1).get()); let server = ServerTask::spawn( config, Default::default(), system_snapshots, keyset, clock, InterfaceName::DEFAULT, Duration::from_secs(1), ); let mut socket = UdpSocket::client( "127.0.0.1:9007".parse().unwrap(), "127.0.0.1:9006".parse().unwrap(), ) .await .unwrap(); let (packet, id) = NtpPacket::poll_message(PollIntervalLimits::default().min); let serialized = serialize_packet_unencryped(&packet); socket.send(&serialized).await.unwrap(); let mut buf = [0; 48]; tokio::time::timeout(Duration::from_millis(10), socket.recv(&mut buf)) .await .unwrap() .unwrap(); let packet = NtpPacket::deserialize(&buf, &NoCipher).unwrap().0; assert_ne!(packet.stratum(), 0); assert!(packet.valid_server_response(id, false)); server.abort(); } #[tokio::test] async fn test_server_filter_deny_deny() { let config = ServerConfig { listen: "127.0.0.1:9008".parse().unwrap(), denylist: FilterList::new(&["127.0.0.0/24".parse().unwrap()], FilterAction::Deny), allowlist: FilterList::default_allowlist(), rate_limiting_cutoff: Duration::from_secs(1), rate_limiting_cache_size: 32, }; let (_, system_snapshots) = tokio::sync::watch::channel(SystemSnapshot::default()); let clock = TestClock {}; let (_, keyset) = tokio::sync::watch::channel(KeySetProvider::new(1).get()); let server = ServerTask::spawn( config, Default::default(), system_snapshots, keyset, clock, InterfaceName::DEFAULT, Duration::from_secs(1), ); let mut socket = UdpSocket::client( "127.0.0.1:9009".parse().unwrap(), "127.0.0.1:9008".parse().unwrap(), ) .await .unwrap(); let (packet, id) = NtpPacket::poll_message(PollIntervalLimits::default().min); let serialized = serialize_packet_unencryped(&packet); socket.send(&serialized).await.unwrap(); let mut buf = [0; 48]; tokio::time::timeout(Duration::from_millis(10), socket.recv(&mut buf)) .await .unwrap() .unwrap(); let packet = NtpPacket::deserialize(&buf, &NoCipher).unwrap().0; assert_eq!(packet.stratum(), 0); assert_eq!(packet.reference_id(), ReferenceId::KISS_DENY); assert!(packet.valid_server_response(id, false)); server.abort(); } #[tokio::test] async fn test_server_filter_deny_ignore() { let config = ServerConfig { listen: "127.0.0.1:9010".parse().unwrap(), denylist: FilterList::new(&["127.0.0.0/24".parse().unwrap()], FilterAction::Ignore), allowlist: FilterList::default_allowlist(), rate_limiting_cutoff: Duration::from_secs(1), rate_limiting_cache_size: 32, }; let (_, system_snapshots) = tokio::sync::watch::channel(SystemSnapshot::default()); let clock = TestClock {}; let (_, keyset) = tokio::sync::watch::channel(KeySetProvider::new(1).get()); let server = ServerTask::spawn( config, Default::default(), system_snapshots, keyset, clock, InterfaceName::DEFAULT, Duration::from_secs(1), ); let mut socket = UdpSocket::client( "127.0.0.1:9011".parse().unwrap(), "127.0.0.1:9010".parse().unwrap(), ) .await .unwrap(); let (packet, _) = NtpPacket::poll_message(PollIntervalLimits::default().min); let serialized = serialize_packet_unencryped(&packet); socket.send(&serialized).await.unwrap(); let mut buf = [0; 48]; let res = tokio::time::timeout(Duration::from_millis(10), socket.recv(&mut buf)).await; assert!(res.is_err()); server.abort(); } #[tokio::test] async fn test_server_rate_limit() { let config = ServerConfig { listen: "127.0.0.1:9012".parse().unwrap(), denylist: FilterList::default_denylist(), allowlist: FilterList::default_allowlist(), rate_limiting_cutoff: Duration::from_millis(100), rate_limiting_cache_size: 32, }; let (_, system_snapshots) = tokio::sync::watch::channel(SystemSnapshot::default()); let clock = TestClock {}; let (_, keyset) = tokio::sync::watch::channel(KeySetProvider::new(1).get()); let server = ServerTask::spawn( config, Default::default(), system_snapshots, keyset, clock, InterfaceName::DEFAULT, Duration::from_secs(1), ); let mut socket = UdpSocket::client( "127.0.0.1:9013".parse().unwrap(), "127.0.0.1:9012".parse().unwrap(), ) .await .unwrap(); let (packet, id) = NtpPacket::poll_message(PollIntervalLimits::default().min); let serialized = serialize_packet_unencryped(&packet); socket.send(&serialized).await.unwrap(); let mut buf = [0; 48]; tokio::time::timeout(Duration::from_millis(10), socket.recv(&mut buf)) .await .unwrap() .unwrap(); let packet = NtpPacket::deserialize(&buf, &NoCipher).unwrap().0; assert_ne!(packet.stratum(), 0); assert!(packet.valid_server_response(id, false)); tokio::time::sleep(std::time::Duration::from_millis(120)).await; let (packet, id) = NtpPacket::poll_message(PollIntervalLimits::default().min); let serialized = serialize_packet_unencryped(&packet); socket.send(&serialized).await.unwrap(); let mut buf = [0; 48]; tokio::time::timeout(Duration::from_millis(10), socket.recv(&mut buf)) .await .unwrap() .unwrap(); let packet = NtpPacket::deserialize(&buf, &NoCipher).unwrap().0; assert_ne!(packet.stratum(), 0); assert!(packet.valid_server_response(id, false)); let (packet, id) = NtpPacket::poll_message(PollIntervalLimits::default().min); let serialized = serialize_packet_unencryped(&packet); socket.send(&serialized).await.unwrap(); let mut buf = [0; 48]; tokio::time::timeout(Duration::from_millis(10), socket.recv(&mut buf)) .await .unwrap() .unwrap(); let packet = NtpPacket::deserialize(&buf, &NoCipher).unwrap().0; assert_eq!(packet.stratum(), 0); assert_eq!(packet.reference_id(), ReferenceId::KISS_RATE); assert!(packet.valid_server_response(id, false)); server.abort(); } #[tokio::test] async fn test_server_rate_limit_defaults() { let config = ServerConfig { listen: "127.0.0.1:9014".parse().unwrap(), denylist: FilterList::default_denylist(), allowlist: FilterList::default_allowlist(), rate_limiting_cutoff: Duration::default(), rate_limiting_cache_size: Default::default(), }; let (_, system_snapshots) = tokio::sync::watch::channel(SystemSnapshot::default()); let clock = TestClock {}; let (_, keyset) = tokio::sync::watch::channel(KeySetProvider::new(1).get()); let server = ServerTask::spawn( config, Default::default(), system_snapshots, keyset, clock, InterfaceName::DEFAULT, Duration::from_secs(1), ); let mut socket = UdpSocket::client( "127.0.0.1:9015".parse().unwrap(), "127.0.0.1:9014".parse().unwrap(), ) .await .unwrap(); let (packet, id) = NtpPacket::poll_message(PollIntervalLimits::default().min); let serialized = serialize_packet_unencryped(&packet); socket.send(&serialized).await.unwrap(); let mut buf = [0; 48]; tokio::time::timeout(Duration::from_millis(10), socket.recv(&mut buf)) .await .unwrap() .unwrap(); let packet = NtpPacket::deserialize(&buf, &NoCipher).unwrap().0; assert_ne!(packet.stratum(), 0); assert!(packet.valid_server_response(id, false)); server.abort(); } #[test] fn test_handle_v4_packet() { let mut server = default_server_task(); let mut response_buf = [0; MAX_PACKET_SIZE]; let timestamp = NtpTimestamp::from_seconds_nanos_since_ntp_era(1, 0); let (packet, id) = NtpPacket::poll_message(PollIntervalLimits::default().min); let serialized = serialize_packet_unencryped(&packet); let response = server .handle_packet( &serialized, response_buf.as_mut_slice(), "127.0.0.1:9001".parse().unwrap(), Some(timestamp), ) .unwrap(); let response = NtpPacket::deserialize(response, &NoCipher).unwrap().0; assert_eq!(response.version(), 4); assert_eq!(response.stratum(), 16); assert!(response.valid_server_response(id, false)); assert!(response.transmit_timestamp() != NtpTimestamp::default()); assert_eq!(response.receive_timestamp(), timestamp); let (packet, _id) = NtpPacket::poll_message(PollIntervalLimits::default().min); let mut serialized = serialize_packet_unencryped(&packet); // corrupt the package serialized[0] = 42; let response = server.handle_packet( &serialized, response_buf.as_mut_slice(), "127.0.0.1:9001".parse().unwrap(), Some(timestamp), ); assert_eq!(response, None); } #[cfg(feature = "unstable_ntpv5")] #[test] fn test_handle_v5_packet() { let mut server = default_server_task(); let mut response_buf = [0; MAX_PACKET_SIZE]; let timestamp = NtpTimestamp::from_seconds_nanos_since_ntp_era(1, 0); let (packet, id) = NtpPacket::poll_message_v5(PollIntervalLimits::default().min); let serialized = serialize_packet_unencryped(&packet); let response = server .handle_packet( &serialized, &mut response_buf[..serialized.len()], "127.0.0.1:9001".parse().unwrap(), Some(timestamp), ) .unwrap(); let response = NtpPacket::deserialize(response, &NoCipher).unwrap().0; assert_eq!(response.version(), 5); assert_eq!(response.stratum(), 16); assert!(response.valid_server_response(id, false)); assert!(response.transmit_timestamp() != NtpTimestamp::default()); assert_eq!(response.receive_timestamp(), timestamp); let (packet, _id) = NtpPacket::poll_message_v5(PollIntervalLimits::default().min); let mut serialized = serialize_packet_unencryped(&packet); // corrupt the package serialized[0] = 42; let response = server.handle_packet( &serialized, response_buf.as_mut_slice(), "127.0.0.1:9001".parse().unwrap(), Some(timestamp), ); assert_eq!(response, None); } #[test] fn early_fails() { let mut s = default_server_task(); let mut resp_buf = [0; MAX_PACKET_SIZE]; let (req, _) = NtpPacket::poll_message(PollInterval::default()); let req = serialize_packet_unencryped(&req); // No timestamp s.stats = ServerStats::default(); assert_eq!( s.handle_packet( req.as_slice(), &mut resp_buf, "127.0.0.1:1337".parse().unwrap(), None, ), None ); assert_eq!(s.stats.ignored_packets.get(), 1); assert_eq!(s.stats.received_packets.get(), 1); // Too short s.stats = ServerStats::default(); assert!(s .handle_packet( &[0; 23], &mut resp_buf, "127.0.0.1:1337".parse().unwrap(), Some(NtpTimestamp::default()), ) .is_none()); assert_eq!(s.stats.ignored_packets.get(), 1); assert_eq!(s.stats.received_packets.get(), 1); } #[test] fn invalid_packet() { let mut s = default_server_task(); let mut resp_buf = [0; MAX_PACKET_SIZE]; let (req, _) = NtpPacket::poll_message(PollInterval::default()); let mut req = serialize_packet_unencryped(&req); req[0] = 0; assert!(s .handle_packet( &req, &mut resp_buf, "127.0.0.1:1337".parse().unwrap(), Some(NtpTimestamp::default()), ) .is_none()); assert_eq!(s.stats.ignored_packets.get(), 1); assert_eq!(s.stats.received_packets.get(), 1); } } #[cfg(test)] mod timestamped_cache { use std::time::{Duration, Instant}; use super::*; #[test] fn timestamped_cache() { let length = 8u8; let mut cache: TimestampedCache = TimestampedCache::new(length as usize); let second = Duration::from_secs(1); let instant = Instant::now(); assert!(cache.is_allowed(0, instant, second)); assert!(!cache.is_allowed(0, instant, second)); let later = instant + 2 * second; assert!(cache.is_allowed(0, later, second)); // simulate a hash collision let even_later = later + 2 * second; assert!(cache.is_allowed(length, even_later, second)); } #[test] fn timestamped_cache_size_0() { let mut cache = TimestampedCache::new(0); let second = Duration::from_secs(1); let instant = Instant::now(); assert!(cache.is_allowed(0, instant, second)); } } ntpd-1.1.2/src/daemon/sockets.rs000064400000000000000000000101571046102023000146510ustar 00000000000000use std::fs::Permissions; use std::path::Path; use tokio::io::{AsyncReadExt, AsyncWriteExt}; use tokio::net::UnixStream; pub async fn write_json(stream: &mut UnixStream, value: &T) -> std::io::Result<()> where T: serde::Serialize, { let bytes = serde_json::to_vec(value).unwrap(); stream.write_all(&bytes).await } pub async fn read_json<'a, T>( stream: &mut UnixStream, buffer: &'a mut Vec, ) -> std::io::Result where T: serde::Deserialize<'a>, { buffer.clear(); let n = stream.read_buf(buffer).await?; buffer.truncate(n); serde_json::from_slice(buffer) .map_err(|e| std::io::Error::new(std::io::ErrorKind::InvalidInput, e)) } fn other_error(msg: String) -> std::io::Result { use std::io::{Error, ErrorKind}; Err(Error::new(ErrorKind::Other, msg)) } pub fn create_unix_socket_with_permissions( path: &Path, permissions: Permissions, ) -> std::io::Result { let listener = create_unix_socket(path)?; std::fs::set_permissions(path, permissions)?; Ok(listener) } fn create_unix_socket(path: &Path) -> std::io::Result { // must unlink path before the bind below (otherwise we get "address already in use") if path.exists() { use std::os::unix::fs::FileTypeExt; let meta = std::fs::metadata(path)?; if !meta.file_type().is_socket() { return other_error(format!("path {path:?} exists but is not a socket")); } std::fs::remove_file(path)?; } // OS errors are terrible; let's try to do better let error = match tokio::net::UnixListener::bind(path) { Ok(listener) => return Ok(listener), Err(e) => e, }; // we don create parent directories if let Some(parent) = path.parent() { if !parent.exists() { let msg = format!( r"Could not create observe socket at {:?} because its parent directory does not exist", &path ); return other_error(msg); } } // otherwise, just forward the OS error let msg = format!( "Could not create observe socket at {:?}: {:?}", &path, error ); other_error(msg) } #[cfg(test)] mod tests { use tokio::net::UnixListener; use super::*; #[tokio::test] async fn write_then_read_is_identity() { // be careful with copying: tests run concurrently and should use a unique socket name! let path = std::env::temp_dir().join("ntp-test-stream-1"); if path.exists() { std::fs::remove_file(&path).unwrap(); } let listener = UnixListener::bind(&path).unwrap(); let mut writer = UnixStream::connect(&path).await.unwrap(); let (mut reader, _) = listener.accept().await.unwrap(); let object = vec![0usize, 10]; write_json(&mut writer, &object).await.unwrap(); let mut buf = Vec::new(); let output = read_json::>(&mut reader, &mut buf) .await .unwrap(); assert_eq!(object, output); // the logic will automatically grow the buffer to the required size assert!(!buf.is_empty()); } #[tokio::test] async fn invalid_input_is_io_error() { // be careful with copying: tests run concurrently and should use a unique socket name! let path = std::env::temp_dir().join("ntp-test-stream-5"); if path.exists() { std::fs::remove_file(&path).unwrap(); } let listener = UnixListener::bind(&path).unwrap(); let mut writer = UnixStream::connect(&path).await.unwrap(); let (mut reader, _) = listener.accept().await.unwrap(); // write data that cannot be parsed let data = [0; 24]; writer.write_all(&data).await.unwrap(); let mut buf = Vec::new(); let output = read_json::>(&mut reader, &mut buf) .await .unwrap_err(); assert_eq!(output.kind(), std::io::ErrorKind::InvalidInput); // the logic will automatically grow the buffer to the required size assert!(!buf.is_empty()); } } ntpd-1.1.2/src/daemon/spawn/dummy.rs000064400000000000000000000043761046102023000154670ustar 00000000000000use std::net::SocketAddr; use super::{ BasicSpawner, PeerCreateParameters, PeerRemovedEvent, SpawnAction, SpawnEvent, SpawnerId, }; use tokio::sync::mpsc; pub struct DummySpawner { id: SpawnerId, to_spawn: Vec, to_activate: isize, } #[derive(Debug, thiserror::Error)] pub enum DummySpawnerError {} impl DummySpawner { pub fn new(to_spawn: Vec, keep_active: usize) -> DummySpawner { DummySpawner { id: SpawnerId::new(), to_spawn, to_activate: keep_active as isize, } } pub fn simple(addr: Vec, keep_active: usize) -> DummySpawner { let to_spawn = addr .into_iter() .map(PeerCreateParameters::from_new_addr) .collect(); Self::new(to_spawn, keep_active) } pub fn empty() -> DummySpawner { Self::simple(vec![], 0) } async fn spawn( &mut self, action_tx: &mpsc::Sender, ) -> Result<(), DummySpawnerError> { while self.to_activate > 0 { if self.to_spawn.is_empty() { return Ok(()); } else { let first = self.to_spawn.remove(0); action_tx .send(SpawnEvent { id: self.id, action: SpawnAction::Create(first), }) .await .expect("Channel was closed unexpectedly"); self.to_activate -= 1; } } Ok(()) } } #[async_trait::async_trait] impl BasicSpawner for DummySpawner { type Error = DummySpawnerError; async fn handle_init( &mut self, action_tx: &mpsc::Sender, ) -> Result<(), DummySpawnerError> { self.spawn(action_tx).await } async fn handle_peer_removed( &mut self, _removed_peer: PeerRemovedEvent, action_tx: &mpsc::Sender, ) -> Result<(), DummySpawnerError> { self.spawn(action_tx).await } fn get_id(&self) -> SpawnerId { self.id } fn get_addr_description(&self) -> String { "dummy".into() } fn get_description(&self) -> &str { "dummy" } } ntpd-1.1.2/src/daemon/spawn/mod.rs000064400000000000000000000220011046102023000150740ustar 00000000000000use std::{net::SocketAddr, sync::atomic::AtomicU64}; use ntp_proto::{PeerNtsData, ProtocolVersion}; use serde::{Deserialize, Serialize}; use tokio::sync::mpsc; use super::config::NormalizedAddress; #[cfg(test)] pub mod dummy; pub mod nts; #[cfg(feature = "unstable_nts-pool")] pub mod nts_pool; pub mod pool; pub mod standard; /// Unique identifier for a spawner. /// This is used to identify which spawner was used to create a peer #[derive(Copy, Clone, PartialEq, Eq, Debug, Hash)] pub struct SpawnerId(u64); impl SpawnerId { pub fn new() -> SpawnerId { static COUNTER: AtomicU64 = AtomicU64::new(1); SpawnerId(COUNTER.fetch_add(1, std::sync::atomic::Ordering::Relaxed)) } } impl Default for SpawnerId { fn default() -> Self { Self::new() } } /// Unique identifier for a peer. /// This peer id makes sure that even if the network address is the same /// that we always know which specific spawned peer we are talking about. #[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Debug, Hash, Serialize, Deserialize)] pub struct PeerId(u64); impl PeerId { pub fn new() -> PeerId { static COUNTER: AtomicU64 = AtomicU64::new(1); PeerId(COUNTER.fetch_add(1, std::sync::atomic::Ordering::Relaxed)) } } impl Default for PeerId { fn default() -> Self { Self::new() } } impl std::fmt::Display for PeerId { fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { write!(f, "{}", self.0) } } /// A `SpawnEvent` is an event created by the spawner for the system /// /// The action that the system should execute is encoded in the `action` field. /// The spawner should make sure that it only ever sends events with its own /// spawner id. #[derive(Debug)] pub struct SpawnEvent { pub id: SpawnerId, pub action: SpawnAction, } impl SpawnEvent { pub fn new(id: SpawnerId, action: SpawnAction) -> SpawnEvent { SpawnEvent { id, action } } } /// Events coming from the system are encoded in this enum #[derive(Debug)] pub enum SystemEvent { PeerRemoved(PeerRemovedEvent), PeerRegistered(PeerCreateParameters), Idle, } impl SystemEvent { pub fn peer_removed(id: PeerId, reason: PeerRemovalReason) -> SystemEvent { SystemEvent::PeerRemoved(PeerRemovedEvent { id, reason }) } } #[derive(Debug)] pub struct PeerRemovedEvent { pub id: PeerId, pub reason: PeerRemovalReason, } /// This indicates what the reason was that a peer was removed. #[derive(Debug, PartialEq, Eq)] pub enum PeerRemovalReason { Demobilized, NetworkIssue, Unreachable, } /// The kind of action that the spawner requests to the system. /// Currently a spawner can only create peers #[derive(Debug)] pub enum SpawnAction { Create(PeerCreateParameters), // Remove(()), } impl SpawnAction { pub fn create( id: PeerId, addr: SocketAddr, normalized_addr: NormalizedAddress, protocol_version: ProtocolVersion, nts: Option>, ) -> SpawnAction { SpawnAction::Create(PeerCreateParameters { id, addr, normalized_addr, protocol_version, nts, }) } } #[derive(Debug)] pub struct PeerCreateParameters { pub id: PeerId, pub addr: SocketAddr, pub normalized_addr: NormalizedAddress, pub protocol_version: ProtocolVersion, pub nts: Option>, } #[cfg(test)] impl PeerCreateParameters { pub fn from_new_addr(addr: SocketAddr) -> PeerCreateParameters { Self::from_addr(PeerId::new(), addr) } pub fn from_addr(id: PeerId, addr: SocketAddr) -> PeerCreateParameters { PeerCreateParameters { id, addr, normalized_addr: NormalizedAddress::from_string_ntp(format!( "{}:{}", addr.ip(), addr.port() )) .unwrap(), protocol_version: ProtocolVersion::default(), nts: None, } } pub fn from_ip_and_port(id: PeerId, ip: impl Into, port: u16) -> PeerCreateParameters { Self::from_addr( id, SocketAddr::new( ip.into().parse().expect("Invalid ip address specified"), port, ), ) } pub fn from_new_ip_and_port(ip: impl Into, port: u16) -> PeerCreateParameters { Self::from_ip_and_port(PeerId::new(), ip, port) } } #[async_trait::async_trait] pub trait Spawner { type Error: std::error::Error + Send; /// Run a spawner /// /// Actions that the system has to execute can be sent through the /// `action_tx` channel and event coming in from the system that the spawner /// should know about will be sent through the `system_notify` channel. async fn run( self, action_tx: mpsc::Sender, system_notify: mpsc::Receiver, ) -> Result<(), Self::Error>; /// Returns the id of this spawner fn get_id(&self) -> SpawnerId; /// Get a description of the address that this spawner is connected to fn get_addr_description(&self) -> String; /// Get a description of the type of spawner fn get_description(&self) -> &str; } #[async_trait::async_trait] pub trait BasicSpawner { type Error: std::error::Error + Send; /// Handle initial spawning. /// /// This is called on startup of the spawner and is meant to setup the /// initial set of peers when nothing else would have been spawned by this /// spawner. Once this function completes the system should be aware of at /// least one peer for this spawner, otherwise no events will ever be sent /// to the spawner and nothing will ever happen. async fn handle_init( &mut self, action_tx: &mpsc::Sender, ) -> Result<(), Self::Error>; /// Function that can be called at regular intervals (once every minute) /// to perform "long" tasks that we do not want to block the main Spawner::run /// function for. async fn handle_idle( &mut self, _action_tx: &mpsc::Sender, ) -> Result<(), Self::Error> { Ok(()) } /// Event handler for when a peer is removed. /// /// This is called each time the system notifies this spawner that one of /// the spawned peers was removed from the system. The spawner can then add /// additional peers or do nothing, depending on its configuration and /// algorithm. async fn handle_peer_removed( &mut self, event: PeerRemovedEvent, action_tx: &mpsc::Sender, ) -> Result<(), Self::Error>; /// Event handler for when a peer is succesfully registered in the system /// /// Every time the spawner sends a peer to the system this handler will /// eventually be called when the system has sucessfully registered the peer /// and will start polling it for ntp packets. async fn handle_registered( &mut self, _event: PeerCreateParameters, _action_tx: &mpsc::Sender, ) -> Result<(), Self::Error> { Ok(()) } /// Get the id of the spawner fn get_id(&self) -> SpawnerId; /// Get a description of the address this spawner is connected to fn get_addr_description(&self) -> String; /// Get a description of the type of spawner fn get_description(&self) -> &str; } #[async_trait::async_trait] impl Spawner for T where T: BasicSpawner + Send + 'static, E: std::error::Error + Send + 'static, { type Error = E; async fn run( mut self, action_tx: mpsc::Sender, mut system_notify: mpsc::Receiver, ) -> Result<(), E> { use tokio::time::{timeout, Duration}; // basic event loop where init is called on startup and then wait for // events from the system before doing anything self.handle_init(&action_tx).await?; while let Some(event) = timeout(Duration::from_secs(60), system_notify.recv()) .await .unwrap_or(Some(SystemEvent::Idle)) { match event { SystemEvent::PeerRegistered(peer_params) => { self.handle_registered(peer_params, &action_tx).await?; } SystemEvent::PeerRemoved(removed_peer) => { self.handle_peer_removed(removed_peer, &action_tx).await?; } SystemEvent::Idle => { self.handle_idle(&action_tx).await?; } } } Ok(()) } fn get_id(&self) -> SpawnerId { self.get_id() } fn get_addr_description(&self) -> String { self.get_addr_description() } fn get_description(&self) -> &str { self.get_description() } } #[cfg(test)] mod tests { use super::{PeerCreateParameters, SpawnAction, SpawnEvent}; pub fn get_create_params(res: SpawnEvent) -> PeerCreateParameters { let SpawnAction::Create(params) = res.action; params } } ntpd-1.1.2/src/daemon/spawn/nts.rs000064400000000000000000000100551046102023000151270ustar 00000000000000use std::net::SocketAddr; use std::ops::Deref; use thiserror::Error; use tokio::sync::mpsc; use tracing::warn; use super::super::{config::NtsPeerConfig, keyexchange::key_exchange_client}; use super::{BasicSpawner, PeerId, PeerRemovedEvent, SpawnAction, SpawnEvent, SpawnerId}; pub struct NtsSpawner { config: NtsPeerConfig, network_wait_period: std::time::Duration, id: SpawnerId, } #[derive(Error, Debug)] pub enum NtsSpawnError { #[error("Channel send error: {0}")] SendError(#[from] mpsc::error::SendError), } pub(super) async fn resolve_addr( mut network_wait: std::time::Duration, address: (&str, u16), ) -> Option { const MAX_RETRIES: usize = 5; const BACKOFF_FACTOR: u32 = 2; for i in 0..MAX_RETRIES { if i != 0 { // Ensure we dont spam dns tokio::time::sleep(network_wait).await; network_wait *= BACKOFF_FACTOR; } match tokio::net::lookup_host(address).await { Ok(mut addresses) => match addresses.next() { Some(address) => return Some(address), None => { warn!("received unknown domain name from NTS-ke"); return None; } }, Err(e) => { warn!(error = ?e, "error while resolving peer address, retrying"); } } } warn!("Could not resolve peer address, restarting NTS initialization"); None } impl NtsSpawner { pub fn new(config: NtsPeerConfig, network_wait_period: std::time::Duration) -> NtsSpawner { NtsSpawner { config, network_wait_period, id: Default::default(), } } async fn spawn(&mut self, action_tx: &mpsc::Sender) -> Result<(), NtsSpawnError> { const MAX_BACKOFF: u32 = 64; const BACKOFF_FACTOR: u32 = 2; let mut network_wait = self.network_wait_period; loop { match key_exchange_client( self.config.address.server_name.clone(), self.config.address.port, &self.config.certificate_authorities, ) .await { Ok(ke) => { if let Some(address) = resolve_addr(self.network_wait_period, (ke.remote.as_str(), ke.port)).await { action_tx .send(SpawnEvent::new( self.id, SpawnAction::create( PeerId::new(), address, self.config.address.deref().clone(), ke.protocol_version, Some(ke.nts), ), )) .await?; return Ok(()); } } Err(e) => { warn!(error = ?e, "error while attempting key exchange"); } }; tokio::time::sleep(network_wait).await; network_wait = std::cmp::min( network_wait * BACKOFF_FACTOR, self.network_wait_period * MAX_BACKOFF, ); } } } #[async_trait::async_trait] impl BasicSpawner for NtsSpawner { type Error = NtsSpawnError; async fn handle_init( &mut self, action_tx: &mpsc::Sender, ) -> Result<(), NtsSpawnError> { self.spawn(action_tx).await } async fn handle_peer_removed( &mut self, _removed_peer: PeerRemovedEvent, action_tx: &mpsc::Sender, ) -> Result<(), NtsSpawnError> { self.handle_init(action_tx).await } fn get_id(&self) -> SpawnerId { self.id } fn get_addr_description(&self) -> String { self.config.address.to_string() } fn get_description(&self) -> &str { "nts" } } ntpd-1.1.2/src/daemon/spawn/nts_pool.rs000064400000000000000000000125371046102023000161670ustar 00000000000000use std::ops::Deref; use thiserror::Error; use tokio::sync::mpsc; use tracing::warn; use super::super::{ config::NtsPoolPeerConfig, keyexchange::key_exchange_client_with_denied_servers, }; use super::{BasicSpawner, PeerId, PeerRemovedEvent, SpawnAction, SpawnEvent, SpawnerId}; use super::nts::resolve_addr; struct PoolPeer { id: PeerId, remote: String, } pub struct NtsPoolSpawner { config: NtsPoolPeerConfig, network_wait_period: std::time::Duration, id: SpawnerId, current_peers: Vec, } #[derive(Error, Debug)] pub enum NtsPoolSpawnError { #[error("Channel send error: {0}")] SendError(#[from] mpsc::error::SendError), } impl NtsPoolSpawner { pub fn new( config: NtsPoolPeerConfig, network_wait_period: std::time::Duration, ) -> NtsPoolSpawner { NtsPoolSpawner { config, network_wait_period, id: Default::default(), current_peers: Default::default(), //known_ips: Default::default(), } } fn contains_peer(&self, domain: &str) -> bool { self.current_peers.iter().any(|peer| peer.remote == domain) } pub async fn try_fill_pool( &mut self, action_tx: &mpsc::Sender, ) -> Result<(), NtsPoolSpawnError> { let mut wait_period = self.network_wait_period; // early return if there is nothing to do if self.current_peers.len() >= self.config.max_peers { return Ok(()); } loop { // Try and add peers to our pool while self.current_peers.len() < self.config.max_peers { match key_exchange_client_with_denied_servers( self.config.addr.server_name.clone(), self.config.addr.port, &self.config.certificate_authorities, self.current_peers.iter().map(|peer| peer.remote.clone()), ) .await { Ok(ke) if !self.contains_peer(&ke.remote) => { if let Some(address) = resolve_addr(self.network_wait_period, (ke.remote.as_str(), ke.port)) .await { let id = PeerId::new(); self.current_peers.push(PoolPeer { id, remote: ke.remote, }); action_tx .send(SpawnEvent::new( self.id, SpawnAction::create( id, address, self.config.addr.deref().clone(), ke.protocol_version, Some(ke.nts), ), )) .await?; } } Ok(_) => { warn!("received an address from pool-ke that we already had, ignoring"); break; } Err(e) => { warn!(error = ?e, "error while attempting key exchange"); break; } }; } let wait_period_max = if cfg!(test) { std::time::Duration::default() } else { std::time::Duration::from_secs(60) }; let peers_needed = self.config.max_peers - self.current_peers.len(); if peers_needed > 0 { if wait_period > wait_period_max { warn!(peers_needed, "could not fully fill pool, giving up"); //NOTE: maybe we want to communicate this up the call chain? return Ok(()); } else { warn!(peers_needed, "could not fully fill pool, waiting"); } tokio::time::sleep(wait_period).await; wait_period *= 2; } else { return Ok(()); } } } } #[async_trait::async_trait] impl BasicSpawner for NtsPoolSpawner { type Error = NtsPoolSpawnError; async fn handle_init( &mut self, action_tx: &mpsc::Sender, ) -> Result<(), NtsPoolSpawnError> { self.handle_idle(action_tx).await?; Ok(()) } async fn handle_idle( &mut self, action_tx: &mpsc::Sender, ) -> Result<(), NtsPoolSpawnError> { self.try_fill_pool(action_tx).await?; Ok(()) } async fn handle_peer_removed( &mut self, removed_peer: PeerRemovedEvent, action_tx: &mpsc::Sender, ) -> Result<(), NtsPoolSpawnError> { self.current_peers.retain(|p| p.id != removed_peer.id); self.try_fill_pool(action_tx).await?; Ok(()) } fn get_id(&self) -> SpawnerId { self.id } fn get_addr_description(&self) -> String { format!("{} ({})", self.config.addr.deref(), self.config.max_peers) } fn get_description(&self) -> &str { "nts-pool" } } ntpd-1.1.2/src/daemon/spawn/pool.rs000064400000000000000000000220721046102023000152760ustar 00000000000000use std::{net::SocketAddr, ops::Deref}; use ntp_proto::ProtocolVersion; use thiserror::Error; use tokio::sync::mpsc; use tracing::warn; use super::super::config::PoolPeerConfig; use super::{BasicSpawner, PeerId, PeerRemovedEvent, SpawnAction, SpawnEvent, SpawnerId}; struct PoolPeer { id: PeerId, addr: SocketAddr, } pub struct PoolSpawner { config: PoolPeerConfig, network_wait_period: std::time::Duration, id: SpawnerId, current_peers: Vec, known_ips: Vec, } #[derive(Error, Debug)] pub enum PoolSpawnError {} impl PoolSpawner { pub fn new(config: PoolPeerConfig, network_wait_period: std::time::Duration) -> PoolSpawner { PoolSpawner { config, network_wait_period, id: Default::default(), current_peers: Default::default(), known_ips: Default::default(), } } pub async fn fill_pool( &mut self, action_tx: &mpsc::Sender, ) -> Result<(), PoolSpawnError> { let mut wait_period = self.network_wait_period; // early return if there is nothing to do if self.current_peers.len() >= self.config.max_peers { return Ok(()); } loop { if self.known_ips.len() < self.config.max_peers - self.current_peers.len() { match self.config.addr.lookup_host().await { Ok(addresses) => { // add the addresses looked up to our list of known ips self.known_ips.append(&mut addresses.collect()); // remove known ips that we are already connected to self.known_ips .retain(|ip| !self.current_peers.iter().any(|p| p.addr == *ip)); } Err(e) => { warn!(error = ?e, "error while resolving peer address, retrying"); tokio::time::sleep(wait_period).await; continue; } } } // Try and add peers to our pool while self.current_peers.len() < self.config.max_peers { if let Some(addr) = self.known_ips.pop() { let id = PeerId::new(); self.current_peers.push(PoolPeer { id, addr }); let action = SpawnAction::create( id, addr, self.config.addr.deref().clone(), ProtocolVersion::default(), None, ); tracing::debug!(?action, "intending to spawn new pool peer at"); action_tx .send(SpawnEvent::new(self.id, action)) .await .expect("Channel was no longer connected"); } else { break; } } let wait_period_max = if cfg!(test) { std::time::Duration::default() } else { std::time::Duration::from_secs(60) }; let peers_needed = self.config.max_peers - self.current_peers.len(); if peers_needed > 0 { wait_period *= 2; if wait_period > wait_period_max { warn!(peers_needed, "could not fully fill pool, giving up"); //NOTE: maybe we want to communicate this up the call chain? return Ok(()); } else { warn!(peers_needed, "could not fully fill pool, waiting"); } tokio::time::sleep(wait_period).await; } else { return Ok(()); } } } } #[async_trait::async_trait] impl BasicSpawner for PoolSpawner { type Error = PoolSpawnError; async fn handle_init( &mut self, action_tx: &mpsc::Sender, ) -> Result<(), PoolSpawnError> { self.fill_pool(action_tx).await?; Ok(()) } async fn handle_idle( &mut self, action_tx: &mpsc::Sender, ) -> Result<(), PoolSpawnError> { self.fill_pool(action_tx).await?; Ok(()) } async fn handle_peer_removed( &mut self, removed_peer: PeerRemovedEvent, action_tx: &mpsc::Sender, ) -> Result<(), PoolSpawnError> { self.current_peers.retain(|p| p.id != removed_peer.id); self.fill_pool(action_tx).await?; Ok(()) } fn get_id(&self) -> SpawnerId { self.id } fn get_addr_description(&self) -> String { format!("{} ({})", self.config.addr.deref(), self.config.max_peers) } fn get_description(&self) -> &str { "pool" } } #[cfg(test)] mod tests { use std::time::Duration; use tokio::sync::mpsc::{self, error::TryRecvError}; use crate::daemon::{ config::{NormalizedAddress, PoolPeerConfig}, spawn::{ pool::PoolSpawner, tests::get_create_params, PeerRemovalReason, Spawner, SystemEvent, }, system::{MESSAGE_BUFFER_SIZE, NETWORK_WAIT_PERIOD}, }; #[tokio::test] async fn creates_multiple_peers() { let address_strings = ["127.0.0.1:123", "127.0.0.2:123", "127.0.0.3:123"]; let addresses = address_strings.map(|addr| addr.parse().unwrap()); let pool = PoolSpawner::new( PoolPeerConfig { addr: NormalizedAddress::with_hardcoded_dns("example.com", 123, addresses.to_vec()) .into(), max_peers: 2, }, NETWORK_WAIT_PERIOD, ); let spawner_id = pool.get_id(); let (action_tx, mut action_rx) = mpsc::channel(MESSAGE_BUFFER_SIZE); let (_notify_tx, notify_rx) = mpsc::channel(MESSAGE_BUFFER_SIZE); tokio::spawn(async move { pool.run(action_tx, notify_rx).await }); tokio::time::sleep(Duration::from_millis(10)).await; let res = action_rx.try_recv().unwrap(); assert_eq!(spawner_id, res.id); let params = get_create_params(res); let addr1 = params.addr; tokio::time::sleep(Duration::from_millis(10)).await; let res = action_rx.try_recv().unwrap(); assert_eq!(spawner_id, res.id); let params = get_create_params(res); let addr2 = params.addr; assert_ne!(addr1, addr2); assert!(addresses.contains(&addr1)); assert!(addresses.contains(&addr2)); tokio::time::sleep(Duration::from_millis(10)).await; let res = action_rx.try_recv().unwrap_err(); assert_eq!(res, TryRecvError::Empty); } #[tokio::test] async fn refills_peers_upto_limit() { let address_strings = ["127.0.0.1:123", "127.0.0.2:123", "127.0.0.3:123"]; let addresses = address_strings.map(|addr| addr.parse().unwrap()); let pool = PoolSpawner::new( PoolPeerConfig { addr: NormalizedAddress::with_hardcoded_dns("example.com", 123, addresses.to_vec()) .into(), max_peers: 2, }, NETWORK_WAIT_PERIOD, ); let (action_tx, mut action_rx) = mpsc::channel(MESSAGE_BUFFER_SIZE); let (notify_tx, notify_rx) = mpsc::channel(MESSAGE_BUFFER_SIZE); tokio::spawn(async move { pool.run(action_tx, notify_rx).await }); tokio::time::sleep(Duration::from_millis(10)).await; let res = action_rx.try_recv().unwrap(); let params = get_create_params(res); let addr1 = params.addr; tokio::time::sleep(Duration::from_millis(10)).await; let res = action_rx.try_recv().unwrap(); let params = get_create_params(res); let addr2 = params.addr; tokio::time::sleep(Duration::from_millis(10)).await; notify_tx .send(SystemEvent::peer_removed( params.id, PeerRemovalReason::NetworkIssue, )) .await .unwrap(); tokio::time::sleep(Duration::from_millis(10)).await; let res = action_rx.try_recv().unwrap(); let params = get_create_params(res); let addr3 = params.addr; // no duplicates! assert_ne!(addr1, addr2); assert_ne!(addr2, addr3); assert_ne!(addr3, addr1); assert!(addresses.contains(&addr3)); } #[tokio::test] async fn works_if_address_does_not_resolve() { let pool = PoolSpawner::new( PoolPeerConfig { addr: NormalizedAddress::with_hardcoded_dns("does.not.resolve", 123, vec![]).into(), max_peers: 2, }, NETWORK_WAIT_PERIOD, ); let (action_tx, mut action_rx) = mpsc::channel(MESSAGE_BUFFER_SIZE); let (_notify_tx, notify_rx) = mpsc::channel(MESSAGE_BUFFER_SIZE); tokio::spawn(async move { pool.run(action_tx, notify_rx).await }); tokio::time::sleep(Duration::from_millis(1000)).await; let res = action_rx.try_recv().unwrap_err(); assert_eq!(res, TryRecvError::Empty); } } ntpd-1.1.2/src/daemon/spawn/standard.rs000064400000000000000000000216301046102023000161240ustar 00000000000000use std::{net::SocketAddr, ops::Deref}; use ntp_proto::ProtocolVersion; use thiserror::Error; use tokio::sync::mpsc; use tracing::warn; use super::super::config::StandardPeerConfig; use super::{ BasicSpawner, PeerId, PeerRemovalReason, PeerRemovedEvent, SpawnAction, SpawnEvent, SpawnerId, }; pub struct StandardSpawner { id: SpawnerId, config: StandardPeerConfig, network_wait_period: std::time::Duration, resolved: Option, } #[derive(Error, Debug)] pub enum StandardSpawnError { #[error("Channel send error: {0}")] SendError(#[from] mpsc::error::SendError), } impl StandardSpawner { pub fn new( config: StandardPeerConfig, network_wait_period: std::time::Duration, ) -> StandardSpawner { StandardSpawner { id: Default::default(), config, network_wait_period, resolved: None, } } async fn do_resolve(&mut self, force_resolve: bool) -> SocketAddr { if let (false, Some(addr)) = (force_resolve, self.resolved) { addr } else { let addr = loop { match self.config.address.lookup_host().await { Ok(mut addresses) => match addresses.next() { None => { warn!("Could not resolve peer address, retrying"); tokio::time::sleep(self.network_wait_period).await; } Some(first) => { break first; } }, Err(e) => { warn!(error = ?e, "error while resolving peer address, retrying"); tokio::time::sleep(self.network_wait_period).await; } } }; self.resolved = Some(addr); addr } } async fn spawn( &mut self, action_tx: &mpsc::Sender, ) -> Result<(), StandardSpawnError> { let addr = self.do_resolve(false).await; action_tx .send(SpawnEvent::new( self.id, SpawnAction::create( PeerId::new(), addr, self.config.address.deref().clone(), ProtocolVersion::default(), None, ), )) .await?; Ok(()) } } #[async_trait::async_trait] impl BasicSpawner for StandardSpawner { type Error = StandardSpawnError; async fn handle_init( &mut self, action_tx: &mpsc::Sender, ) -> Result<(), StandardSpawnError> { self.spawn(action_tx).await } async fn handle_peer_removed( &mut self, removed_peer: PeerRemovedEvent, action_tx: &mpsc::Sender, ) -> Result<(), StandardSpawnError> { if removed_peer.reason == PeerRemovalReason::Unreachable { // force new resolution self.resolved = None; } if removed_peer.reason != PeerRemovalReason::Demobilized { self.spawn(action_tx).await } else { Ok(()) } } fn get_id(&self) -> SpawnerId { self.id } fn get_addr_description(&self) -> String { self.config.address.to_string() } fn get_description(&self) -> &str { "standard" } } #[cfg(test)] mod tests { use std::time::Duration; use tokio::sync::mpsc::{self, error::TryRecvError}; use crate::daemon::{ config::{NormalizedAddress, StandardPeerConfig}, spawn::{ standard::StandardSpawner, tests::get_create_params, PeerRemovalReason, Spawner, SystemEvent, }, system::{MESSAGE_BUFFER_SIZE, NETWORK_WAIT_PERIOD}, }; #[tokio::test] async fn creates_a_peer() { let spawner = StandardSpawner::new( StandardPeerConfig { address: NormalizedAddress::with_hardcoded_dns( "example.com", 123, vec!["127.0.0.1:123".parse().unwrap()], ) .into(), }, NETWORK_WAIT_PERIOD, ); let spawner_id = spawner.get_id(); let (action_tx, mut action_rx) = mpsc::channel(MESSAGE_BUFFER_SIZE); let (_notify_tx, notify_rx) = mpsc::channel(MESSAGE_BUFFER_SIZE); tokio::spawn(async move { spawner.run(action_tx, notify_rx).await }); tokio::time::sleep(Duration::from_millis(10)).await; let res = action_rx.try_recv().unwrap(); assert_eq!(res.id, spawner_id); let params = get_create_params(res); assert_eq!(params.addr.to_string(), "127.0.0.1:123"); // and now we should no longer receive anything tokio::time::sleep(Duration::from_millis(10)).await; let res = action_rx.try_recv().unwrap_err(); assert_eq!(res, TryRecvError::Empty); } #[tokio::test] async fn recreates_a_peer() { let spawner = StandardSpawner::new( StandardPeerConfig { address: NormalizedAddress::with_hardcoded_dns( "example.com", 123, vec!["127.0.0.1:123".parse().unwrap()], ) .into(), }, NETWORK_WAIT_PERIOD, ); let (action_tx, mut action_rx) = mpsc::channel(MESSAGE_BUFFER_SIZE); let (notify_tx, notify_rx) = mpsc::channel(MESSAGE_BUFFER_SIZE); tokio::spawn(async move { spawner.run(action_tx, notify_rx).await }); tokio::time::sleep(Duration::from_millis(10)).await; let res = action_rx.try_recv().unwrap(); let params = get_create_params(res); notify_tx .send(SystemEvent::peer_removed( params.id, PeerRemovalReason::NetworkIssue, )) .await .unwrap(); tokio::time::sleep(Duration::from_millis(10)).await; let res = action_rx.try_recv().unwrap(); let params = get_create_params(res); assert_eq!(params.addr.to_string(), "127.0.0.1:123"); } #[tokio::test] async fn reresolves_on_unreachable() { let address_strings = ["127.0.0.1:123", "127.0.0.2:123", "127.0.0.3:123"]; let addresses = address_strings.map(|addr| addr.parse().unwrap()); let spawner = StandardSpawner::new( StandardPeerConfig { address: NormalizedAddress::with_hardcoded_dns( "europe.pool.ntp.org", 123, addresses.to_vec(), ) .into(), }, NETWORK_WAIT_PERIOD, ); let (action_tx, mut action_rx) = mpsc::channel(MESSAGE_BUFFER_SIZE); let (notify_tx, notify_rx) = mpsc::channel(MESSAGE_BUFFER_SIZE); tokio::spawn(async move { spawner.run(action_tx, notify_rx).await }); let res = action_rx.recv().await.unwrap(); let params = get_create_params(res); let initial_addr = params.addr; // We repeat multiple times and check at least one is different to be less // sensitive to dns resolver giving the same pool ip. let mut seen_addresses = vec![]; for _ in 0..5 { notify_tx .send(SystemEvent::peer_removed( params.id, PeerRemovalReason::Unreachable, )) .await .unwrap(); let res = action_rx.recv().await.unwrap(); let params = get_create_params(res); seen_addresses.push(params.addr); } let seen_addresses = seen_addresses; for addr in seen_addresses.iter() { assert!( addresses.contains(addr), "{:?} should have been drawn from {:?}", addr, addresses ); } assert!( seen_addresses.iter().any(|seen| seen != &initial_addr), "Re-resolved\n\n\t{:?}\n\n should contain at least one address that isn't the original\n\n\t{:?}", seen_addresses, initial_addr, ); } #[tokio::test] async fn works_if_address_does_not_resolve() { let spawner = StandardSpawner::new( StandardPeerConfig { address: NormalizedAddress::with_hardcoded_dns("does.not.resolve", 123, vec![]) .into(), }, NETWORK_WAIT_PERIOD, ); let (action_tx, mut action_rx) = mpsc::channel(MESSAGE_BUFFER_SIZE); let (_notify_tx, notify_rx) = mpsc::channel(MESSAGE_BUFFER_SIZE); tokio::spawn(async move { spawner.run(action_tx, notify_rx).await }); tokio::time::sleep(Duration::from_millis(1000)).await; let res = action_rx.try_recv().unwrap_err(); assert_eq!(res, TryRecvError::Empty); } } ntpd-1.1.2/src/daemon/system.rs000064400000000000000000000733701046102023000145300ustar 00000000000000#[cfg(feature = "unstable_nts-pool")] use super::spawn::nts_pool::NtsPoolSpawner; use super::{ config::{ClockConfig, NormalizedAddress, PeerConfig, ServerConfig}, peer::{MsgForSystem, PeerChannels}, peer::{PeerTask, Wait}, server::{ServerStats, ServerTask}, spawn::{ nts::NtsSpawner, pool::PoolSpawner, standard::StandardSpawner, PeerCreateParameters, PeerId, PeerRemovalReason, SpawnAction, SpawnEvent, Spawner, SpawnerId, SystemEvent, }, ObservablePeerState, ObservedPeerState, }; use std::{collections::HashMap, future::Future, marker::PhantomData, pin::Pin, sync::Arc}; use ntp_proto::{ KalmanClockController, KeySet, NtpClock, NtpDuration, NtpLeapIndicator, PeerSnapshot, SourceDefaultsConfig, SynchronizationConfig, SystemSnapshot, TimeSyncController, }; use ntp_udp::{EnableTimestamps, InterfaceName}; use tokio::{sync::mpsc, task::JoinHandle}; use tracing::{debug, info}; pub const NETWORK_WAIT_PERIOD: std::time::Duration = std::time::Duration::from_secs(1); pub const MESSAGE_BUFFER_SIZE: usize = 32; struct SingleshotSleep { enabled: bool, sleep: Pin>, } impl SingleshotSleep { fn new_disabled(t: T) -> Self { SingleshotSleep { enabled: false, sleep: Box::pin(t), } } } impl Future for SingleshotSleep { type Output = (); fn poll( self: Pin<&mut Self>, cx: &mut std::task::Context<'_>, ) -> std::task::Poll { let this = self.get_mut(); if !this.enabled { return std::task::Poll::Pending; } match this.sleep.as_mut().poll(cx) { std::task::Poll::Ready(v) => { this.enabled = false; std::task::Poll::Ready(v) } u => u, } } } impl Wait for SingleshotSleep { fn reset(self: Pin<&mut Self>, deadline: tokio::time::Instant) { let this = self.get_mut(); this.enabled = true; this.sleep.as_mut().reset(deadline); } } pub struct DaemonChannels { pub synchronization_config_receiver: tokio::sync::watch::Receiver, pub synchronization_config_sender: tokio::sync::watch::Sender, pub peer_defaults_config_receiver: tokio::sync::watch::Receiver, pub peer_defaults_config_sender: tokio::sync::watch::Sender, pub peer_snapshots_receiver: tokio::sync::watch::Receiver>, pub server_data_receiver: tokio::sync::watch::Receiver>, pub system_snapshot_receiver: tokio::sync::watch::Receiver, pub keyset: tokio::sync::watch::Receiver>, } /// Spawn the NTP daemon pub async fn spawn( synchronization_config: SynchronizationConfig, peer_defaults_config: SourceDefaultsConfig, clock_config: ClockConfig, peer_configs: &[PeerConfig], server_configs: &[ServerConfig], keyset: tokio::sync::watch::Receiver>, ) -> std::io::Result<(JoinHandle>, DaemonChannels)> { let (mut system, channels) = System::new( clock_config.clock, clock_config.interface, clock_config.enable_timestamps, synchronization_config, peer_defaults_config, keyset, ); for peer_config in peer_configs { // Force early clock controller initialization when peers are configured system.clock_controller().map_err(|e| { tracing::error!("Could not start clock controller: {}", e); std::io::Error::new(std::io::ErrorKind::Other, e) })?; match peer_config { PeerConfig::Standard(cfg) => { system .add_spawner(StandardSpawner::new(cfg.clone(), NETWORK_WAIT_PERIOD)) .map_err(|e| { tracing::error!("Could not spawn peer: {}", e); std::io::Error::new(std::io::ErrorKind::Other, e) })?; } PeerConfig::Nts(cfg) => { system .add_spawner(NtsSpawner::new(cfg.clone(), NETWORK_WAIT_PERIOD)) .map_err(|e| { tracing::error!("Could not spawn peer: {}", e); std::io::Error::new(std::io::ErrorKind::Other, e) })?; } PeerConfig::Pool(cfg) => { system .add_spawner(PoolSpawner::new(cfg.clone(), NETWORK_WAIT_PERIOD)) .map_err(|e| { tracing::error!("Could not spawn peer: {}", e); std::io::Error::new(std::io::ErrorKind::Other, e) })?; } #[cfg(feature = "unstable_nts-pool")] PeerConfig::NtsPool(cfg) => { system .add_spawner(NtsPoolSpawner::new(cfg.clone(), NETWORK_WAIT_PERIOD)) .map_err(|e| { tracing::error!("Could not spawn peer: {}", e); std::io::Error::new(std::io::ErrorKind::Other, e) })?; } } } for server_config in server_configs.iter() { system.add_server(server_config.to_owned()).await; } let handle = tokio::spawn(async move { let sleep = SingleshotSleep::new_disabled(tokio::time::sleep_until(tokio::time::Instant::now())); tokio::pin!(sleep); system.run(sleep).await }); Ok((handle, channels)) } struct SystemSpawnerData { id: SpawnerId, notify_tx: mpsc::Sender, } struct System { _wait: PhantomData>, synchronization_config: SynchronizationConfig, peer_defaults_config: SourceDefaultsConfig, system: SystemSnapshot, synchronization_config_receiver: tokio::sync::watch::Receiver, peer_defaults_config_receiver: tokio::sync::watch::Receiver, system_snapshot_sender: tokio::sync::watch::Sender, peer_snapshots_sender: tokio::sync::watch::Sender>, server_data_sender: tokio::sync::watch::Sender>, keyset: tokio::sync::watch::Receiver>, msg_for_system_rx: mpsc::Receiver, spawn_tx: mpsc::Sender, spawn_rx: mpsc::Receiver, peers: HashMap, servers: Vec, spawners: Vec, peer_channels: PeerChannels, clock: C, controller: Option>, // which timestamps to use (this is a hint, OS or hardware may ignore) enable_timestamps: EnableTimestamps, // bind the socket to a specific interface. This is relevant for hardware timestamping, // because the interface determines which clock is used to produce the timestamps. interface: Option, } impl System { fn new( clock: C, interface: Option, enable_timestamps: EnableTimestamps, synchronization_config: SynchronizationConfig, peer_defaults_config: SourceDefaultsConfig, keyset: tokio::sync::watch::Receiver>, ) -> (Self, DaemonChannels) { // Setup system snapshot let mut system = SystemSnapshot { stratum: synchronization_config.local_stratum, ..Default::default() }; if synchronization_config.local_stratum == 1 { // We are a stratum 1 server so mark our selves synchronized. system.time_snapshot.leap_indicator = NtpLeapIndicator::NoWarning; } // Create communication channels let (synchronization_config_sender, synchronization_config_receiver) = tokio::sync::watch::channel(synchronization_config); let (peer_defaults_config_sender, peer_defaults_config_receiver) = tokio::sync::watch::channel(peer_defaults_config); let (system_snapshot_sender, system_snapshot_receiver) = tokio::sync::watch::channel(system); let (peer_snapshots_sender, peer_snapshots_receiver) = tokio::sync::watch::channel(vec![]); let (server_data_sender, server_data_receiver) = tokio::sync::watch::channel(vec![]); let (msg_for_system_sender, msg_for_system_receiver) = tokio::sync::mpsc::channel(MESSAGE_BUFFER_SIZE); let (spawn_tx, spawn_rx) = mpsc::channel(MESSAGE_BUFFER_SIZE); // Build System and its channels ( System { _wait: PhantomData, synchronization_config, peer_defaults_config, system, synchronization_config_receiver: synchronization_config_receiver.clone(), peer_defaults_config_receiver: peer_defaults_config_receiver.clone(), system_snapshot_sender, peer_snapshots_sender, server_data_sender, keyset: keyset.clone(), msg_for_system_rx: msg_for_system_receiver, spawn_rx, spawn_tx, peers: Default::default(), servers: Default::default(), spawners: Default::default(), peer_channels: PeerChannels { msg_for_system_sender, system_snapshot_receiver: system_snapshot_receiver.clone(), synchronization_config_receiver: synchronization_config_receiver.clone(), source_defaults_config_receiver: peer_defaults_config_receiver.clone(), }, clock, controller: None, enable_timestamps, interface, }, DaemonChannels { synchronization_config_receiver, synchronization_config_sender, peer_defaults_config_receiver, peer_defaults_config_sender, peer_snapshots_receiver, server_data_receiver, system_snapshot_receiver, keyset, }, ) } fn clock_controller(&mut self) -> Result<&mut KalmanClockController, C::Error> { let controller = match self.controller.take() { Some(controller) => controller, None => KalmanClockController::new( self.clock.clone(), self.synchronization_config, self.peer_defaults_config, self.synchronization_config.algorithm, )?, }; Ok(self.controller.insert(controller)) } fn add_spawner( &mut self, spawner: impl Spawner + Send + Sync + 'static, ) -> Result { let (notify_tx, notify_rx) = mpsc::channel(MESSAGE_BUFFER_SIZE); let id = spawner.get_id(); let spawner_data = SystemSpawnerData { id, notify_tx }; debug!(id=?spawner_data.id, ty=spawner.get_description(), addr=spawner.get_addr_description(), "Running spawner"); self.spawners.push(spawner_data); let spawn_tx = self.spawn_tx.clone(); tokio::spawn(async move { spawner.run(spawn_tx, notify_rx).await }); Ok(id) } async fn run(&mut self, mut wait: Pin<&mut SingleshotSleep>) -> std::io::Result<()> { loop { tokio::select! { opt_msg_for_system = self.msg_for_system_rx.recv() => { match opt_msg_for_system { None => { // the channel closed and has no more messages in it break } Some(msg_for_system) => { self.handle_peer_update(msg_for_system, &mut wait) .await?; } } } opt_spawn_event = self.spawn_rx.recv() => { match opt_spawn_event { None => { let msg = "the spawn channel closed unexpectedly. ntpd-rs is likely in an invalid state!"; tracing::warn!(msg); } Some(spawn_event) => { if let Err(e) = self.handle_spawn_event(spawn_event).await { tracing::error!("Could not spawn peer: {}", e); } } } } () = &mut wait => { self.handle_timer(&mut wait); } _ = self.synchronization_config_receiver.changed(), if self.synchronization_config_receiver.has_changed().is_ok() => { self.handle_config_update(); } } } // the channel closed and has no more messages in it Ok(()) } fn handle_config_update(&mut self) { let synchronization_config = *self.synchronization_config_receiver.borrow_and_update(); let peer_defaults_config = *self.peer_defaults_config_receiver.borrow_and_update(); if let Some(controller) = self.controller.as_mut() { controller.update_config( synchronization_config, peer_defaults_config, synchronization_config.algorithm, ); } self.synchronization_config = synchronization_config; self.peer_defaults_config = peer_defaults_config; } fn handle_timer(&mut self, wait: &mut Pin<&mut SingleshotSleep>) { tracing::debug!("Timer expired"); // note: local needed for borrow checker if let Some(controller) = self.controller.as_mut() { let update = controller.time_update(); self.handle_algorithm_state_update(update, wait); } } async fn handle_peer_update( &mut self, msg: MsgForSystem, wait: &mut Pin<&mut SingleshotSleep>, ) -> std::io::Result<()> { tracing::debug!(?msg, "updating peer"); match msg { MsgForSystem::MustDemobilize(index) => { if let Err(e) = self.handle_peer_demobilize(index).await { unreachable!("Could not demobilize peer: {}", e); }; } MsgForSystem::NewMeasurement(index, snapshot, measurement) => { if let Err(e) = self.handle_peer_measurement(index, snapshot, measurement, wait) { unreachable!("Could not process peer measurement: {}", e); } } MsgForSystem::UpdatedSnapshot(index, snapshot) => { if let Err(e) = self.handle_peer_snapshot(index, snapshot) { unreachable!("Could not update peer snapshot: {}", e); } } MsgForSystem::NetworkIssue(index) => { self.handle_peer_network_issue(index).await?; } MsgForSystem::Unreachable(index) => { self.handle_peer_unreachable(index).await?; } } // Don't care if there is no receiver for peer snapshots (which might happen if // we don't enable observing in the configuration) let _ = self .peer_snapshots_sender .send(self.observe_peers().collect()); Ok(()) } async fn handle_peer_network_issue(&mut self, index: PeerId) -> std::io::Result<()> { self.clock_controller() .map_err(|e| std::io::Error::new(std::io::ErrorKind::Other, e))? .peer_remove(index); // Restart the peer reusing its configuration. let state = self.peers.remove(&index).unwrap(); let spawner_id = state.spawner_id; let source_id = state.source_id; let opt_spawner = self.spawners.iter().find(|s| s.id == spawner_id); if let Some(spawner) = opt_spawner { spawner .notify_tx .send(SystemEvent::peer_removed( source_id, PeerRemovalReason::NetworkIssue, )) .await .expect("Could not notify spawner"); } Ok(()) } async fn handle_peer_unreachable(&mut self, index: PeerId) -> std::io::Result<()> { self.clock_controller() .map_err(|e| std::io::Error::new(std::io::ErrorKind::Other, e))? .peer_remove(index); // Restart the peer reusing its configuration. let state = self.peers.remove(&index).unwrap(); let spawner_id = state.spawner_id; let source_id = state.source_id; let opt_spawner = self.spawners.iter().find(|s| s.id == spawner_id); if let Some(spawner) = opt_spawner { spawner .notify_tx .send(SystemEvent::peer_removed( source_id, PeerRemovalReason::Unreachable, )) .await .expect("Could not notify spawner"); } Ok(()) } fn handle_peer_snapshot( &mut self, index: PeerId, snapshot: PeerSnapshot, ) -> Result<(), C::Error> { let usable = snapshot .accept_synchronization(self.synchronization_config.local_stratum, &self.system) .is_ok(); self.clock_controller()?.peer_update(index, usable); self.peers.get_mut(&index).unwrap().snapshot = Some(snapshot); Ok(()) } fn handle_peer_measurement( &mut self, index: PeerId, snapshot: PeerSnapshot, measurement: ntp_proto::Measurement, wait: &mut Pin<&mut SingleshotSleep>, ) -> Result<(), C::Error> { if let Err(e) = self.handle_peer_snapshot(index, snapshot) { panic!("Could not handle peer snapshot: {}", e); } // note: local needed for borrow checker let update = self .clock_controller()? .peer_measurement(index, measurement); self.handle_algorithm_state_update(update, wait); Ok(()) } fn handle_algorithm_state_update( &mut self, update: ntp_proto::StateUpdate, wait: &mut Pin<&mut SingleshotSleep>, ) { if let Some(ref used_peers) = update.used_peers { self.system.update_used_peers(used_peers.iter().map(|v| { self.peers.get(v).and_then(|data| data.snapshot).expect( "Critical error: Peer used for synchronization that is not known to system", ) })); } if let Some(time_snapshot) = update.time_snapshot { self.system .update_timedata(time_snapshot, &self.synchronization_config); } if let Some(timestamp) = update.next_update { let duration = timestamp - self.clock.now().expect("Could not get current time"); let duration = std::time::Duration::from_secs_f64(duration.max(NtpDuration::ZERO).to_seconds()); wait.as_mut().reset(tokio::time::Instant::now() + duration); } if update.used_peers.is_some() || update.time_snapshot.is_some() { // Don't care if there is no receiver. let _ = self.system_snapshot_sender.send(self.system); } } async fn handle_peer_demobilize(&mut self, index: PeerId) -> Result<(), C::Error> { self.clock_controller()?.peer_remove(index); let state = self.peers.remove(&index).unwrap(); // Restart the peer reusing its configuration. let spawner_id = state.spawner_id; let source_id = state.source_id; let opt_spawner = self.spawners.iter().find(|s| s.id == spawner_id); if let Some(spawner) = opt_spawner { spawner .notify_tx .send(SystemEvent::peer_removed( source_id, PeerRemovalReason::Demobilized, )) .await .expect("Could not notify spawner"); } Ok(()) } async fn create_peer( &mut self, spawner_id: SpawnerId, mut params: PeerCreateParameters, ) -> Result { let source_id = params.id; info!(source_id=?source_id, addr=?params.addr, spawner=?spawner_id, "new peer"); self.peers.insert( source_id, PeerState { snapshot: None, peer_address: params.normalized_addr.clone(), source_id, spawner_id, }, ); self.clock_controller()?.peer_add(source_id); PeerTask::spawn( source_id, params.addr, self.interface, self.clock.clone(), self.enable_timestamps, NETWORK_WAIT_PERIOD, self.peer_channels.clone(), params.protocol_version, params.nts.take(), ); // Don't care if there is no receiver let _ = self .peer_snapshots_sender .send(self.observe_peers().collect()); // Try and find a related spawner and notify that spawner. // This makes sure that the spawner that initially sent the create event // is now aware that the peer was added to the system. if let Some(s) = self.spawners.iter().find(|s| s.id == spawner_id) { let _ = s.notify_tx.send(SystemEvent::PeerRegistered(params)).await; } Ok(source_id) } async fn handle_spawn_event(&mut self, event: SpawnEvent) -> Result<(), C::Error> { match event.action { SpawnAction::Create(params) => { self.create_peer(event.id, params).await?; } } Ok(()) } async fn add_server(&mut self, config: ServerConfig) { let stats = ServerStats::default(); self.servers.push(ServerData { stats: stats.clone(), config: config.clone(), }); ServerTask::spawn( config, stats, self.peer_channels.system_snapshot_receiver.clone(), self.keyset.clone(), self.clock.clone(), self.interface, NETWORK_WAIT_PERIOD, ); let _ = self.server_data_sender.send(self.servers.clone()); } fn observe_peers(&self) -> impl Iterator + '_ { self.peers.iter().map(|(index, data)| { data.snapshot .map(|snapshot| { if let Some(timedata) = self .controller .as_ref() .and_then(|c| c.peer_snapshot(*index)) { ObservablePeerState::Observable(ObservedPeerState { timedata, unanswered_polls: snapshot.reach.unanswered_polls(), poll_interval: snapshot.poll_interval, name: data.peer_address.to_string(), address: snapshot.source_addr.to_string(), id: data.source_id, }) } else { ObservablePeerState::Nothing } }) .unwrap_or(ObservablePeerState::Nothing) }) } } #[derive(Debug)] struct PeerState { snapshot: Option, peer_address: NormalizedAddress, spawner_id: SpawnerId, source_id: PeerId, } #[derive(Debug, Clone)] pub struct ServerData { pub stats: ServerStats, pub config: ServerConfig, } #[cfg(test)] mod tests { use ntp_proto::{ peer_snapshot, KeySetProvider, Measurement, NtpDuration, NtpInstant, NtpLeapIndicator, NtpTimestamp, PollInterval, }; use super::super::spawn::dummy::DummySpawner; use super::*; #[derive(Debug, Clone, Default)] struct TestClock {} impl NtpClock for TestClock { type Error = std::io::Error; fn now(&self) -> std::result::Result { // Err(std::io::Error::from(std::io::ErrorKind::Unsupported)) Ok(NtpTimestamp::default()) } fn set_frequency(&self, _freq: f64) -> Result { Ok(NtpTimestamp::default()) } fn step_clock(&self, _offset: NtpDuration) -> Result { Ok(NtpTimestamp::default()) } fn enable_ntp_algorithm(&self) -> Result<(), Self::Error> { Ok(()) } fn disable_ntp_algorithm(&self) -> Result<(), Self::Error> { Ok(()) } fn ntp_algorithm_update( &self, _offset: NtpDuration, _poll_interval: PollInterval, ) -> Result<(), Self::Error> { Ok(()) } fn error_estimate_update( &self, _est_error: NtpDuration, _max_error: NtpDuration, ) -> Result<(), Self::Error> { Ok(()) } fn status_update(&self, _leap_status: NtpLeapIndicator) -> Result<(), Self::Error> { Ok(()) } } #[tokio::test] async fn test_peers() { // we always generate the keyset (even if NTS is not used) let (_, keyset) = tokio::sync::watch::channel(KeySetProvider::new(1).get()); let (mut system, _) = System::new( TestClock {}, InterfaceName::DEFAULT, EnableTimestamps::default(), SynchronizationConfig::default(), SourceDefaultsConfig::default(), keyset, ); let wait = SingleshotSleep::new_disabled(tokio::time::sleep(std::time::Duration::from_secs(0))); tokio::pin!(wait); let id = system.add_spawner(DummySpawner::empty()).unwrap(); let mut indices = vec![]; for i in 0..4 { indices.push( system .create_peer( id, PeerCreateParameters::from_new_ip_and_port(format!("127.0.0.{i}"), 123), ) .await .unwrap(), ); } let base = NtpInstant::now(); assert_eq!( system .peers .values() .map(|v| match v.snapshot { Some(_) => 1, None => 0, }) .sum::(), 0 ); system .handle_peer_update( MsgForSystem::NewMeasurement( indices[0], peer_snapshot(), Measurement { delay: NtpDuration::from_seconds(0.1), offset: NtpDuration::from_seconds(0.), transmit_timestamp: NtpTimestamp::default(), receive_timestamp: NtpTimestamp::default(), localtime: NtpTimestamp::from_seconds_nanos_since_ntp_era(0, 0), monotime: base, stratum: 0, root_delay: NtpDuration::default(), root_dispersion: NtpDuration::default(), leap: NtpLeapIndicator::NoWarning, precision: 0, }, ), &mut wait, ) .await .unwrap(); assert_eq!( system .peers .values() .map(|v| match v.snapshot { Some(_) => 1, None => 0, }) .sum::(), 1 ); system .handle_peer_update( MsgForSystem::NewMeasurement( indices[0], peer_snapshot(), Measurement { delay: NtpDuration::from_seconds(0.1), offset: NtpDuration::from_seconds(0.), transmit_timestamp: NtpTimestamp::default(), receive_timestamp: NtpTimestamp::default(), localtime: NtpTimestamp::from_seconds_nanos_since_ntp_era(0, 0), monotime: base, stratum: 0, root_delay: NtpDuration::default(), root_dispersion: NtpDuration::default(), leap: NtpLeapIndicator::NoWarning, precision: 0, }, ), &mut wait, ) .await .unwrap(); assert_eq!( system .peers .values() .map(|v| match v.snapshot { Some(_) => 1, None => 0, }) .sum::(), 1 ); system .handle_peer_update( MsgForSystem::UpdatedSnapshot(indices[1], peer_snapshot()), &mut wait, ) .await .unwrap(); assert_eq!( system .peers .values() .map(|v| match v.snapshot { Some(_) => 1, None => 0, }) .sum::(), 2 ); system .handle_peer_update(MsgForSystem::MustDemobilize(indices[1]), &mut wait) .await .unwrap(); assert_eq!( system .peers .values() .map(|v| match v.snapshot { Some(_) => 1, None => 0, }) .sum::(), 1 ); } } ntpd-1.1.2/src/daemon/tracing.rs000064400000000000000000000034401046102023000146220ustar 00000000000000use std::str::FromStr; use serde::Deserialize; use tracing::metadata::LevelFilter; #[derive(Debug, Default, Copy, Clone, Deserialize, PartialEq, Eq)] #[serde(rename_all = "lowercase")] pub enum LogLevel { /// The "trace" level. /// /// Designates very low priority, often extremely verbose, information. Trace = 0, /// The "debug" level. /// /// Designates lower priority information. Debug = 1, /// The "info" level. /// /// Designates useful information. #[default] Info = 2, /// The "warn" level. /// /// Designates hazardous situations. Warn = 3, /// The "error" level. /// /// Designates very serious errors. Error = 4, } pub struct UnknownLogLevel; impl FromStr for LogLevel { type Err = UnknownLogLevel; fn from_str(s: &str) -> Result { match s { "trace" => Ok(LogLevel::Trace), "debug" => Ok(LogLevel::Debug), "info" => Ok(LogLevel::Info), "warn" => Ok(LogLevel::Warn), "error" => Ok(LogLevel::Error), _ => Err(UnknownLogLevel), } } } impl From for tracing::Level { fn from(value: LogLevel) -> Self { match value { LogLevel::Trace => tracing::Level::TRACE, LogLevel::Debug => tracing::Level::DEBUG, LogLevel::Info => tracing::Level::INFO, LogLevel::Warn => tracing::Level::WARN, LogLevel::Error => tracing::Level::ERROR, } } } impl From for LevelFilter { fn from(value: LogLevel) -> Self { LevelFilter::from_level(value.into()) } } pub fn tracing_init(level: impl Into) -> tracing_subscriber::fmt::Subscriber { tracing_subscriber::fmt().with_max_level(level).finish() } ntpd-1.1.2/src/lib.rs000064400000000000000000000005171046102023000125000ustar 00000000000000#![forbid(unsafe_code)] mod ctl; mod daemon; mod metrics; pub use ctl::main as ctl_main; pub use daemon::main as daemon_main; pub use metrics::exporter::main as metrics_exporter_main; #[cfg(feature = "__internal-fuzz")] pub mod fuzz { pub use super::daemon::config::subnet::IpSubnet; pub use super::daemon::fuzz_ipfilter; } ntpd-1.1.2/src/metrics/exporter.rs000064400000000000000000000145761046102023000152620ustar 00000000000000use tokio::io::AsyncWriteExt; use tokio::net::TcpListener; use std::{ fmt::Write, path::{Path, PathBuf}, }; use crate::daemon::{config::CliArg, initialize_logging_parse_config, ObservableState}; const VERSION: &str = env!("CARGO_PKG_VERSION"); const USAGE_MSG: &str = "\ usage: ntp-metrics-exporter [-c PATH] ntp-metrics-exporter -h | ntp-metrics-exporter -v"; const DESCRIPTOR: &str = "ntp-metrics-exporter - serve ntpd-rs openmetrics via http"; const HELP_MSG: &str = "Options: -c, --config=CONFIG ntpd-rs configuration file (default: /etc/ntpd-rs/ntp.toml) -h, --help display this help text -v, --version display version information"; pub fn long_help_message() -> String { format!("{DESCRIPTOR}\n\n{USAGE_MSG}\n\n{HELP_MSG}") } #[derive(Debug, Default, PartialEq, Eq)] pub enum MetricsAction { #[default] Help, Version, Run, } #[derive(Debug, Default)] pub(crate) struct NtpMetricsExporterOptions { config: Option, help: bool, version: bool, action: MetricsAction, } impl NtpMetricsExporterOptions { const TAKES_ARGUMENT: &'static [&'static str] = &["--config"]; const TAKES_ARGUMENT_SHORT: &'static [char] = &['c']; /// parse an iterator over command line arguments pub fn try_parse_from(iter: I) -> Result where I: IntoIterator, T: AsRef + Clone, { let mut options = NtpMetricsExporterOptions::default(); let arg_iter = CliArg::normalize_arguments( Self::TAKES_ARGUMENT, Self::TAKES_ARGUMENT_SHORT, iter.into_iter().map(|x| x.as_ref().to_string()), )? .into_iter() .peekable(); for arg in arg_iter { match arg { CliArg::Flag(flag) => match flag.as_str() { "-h" | "--help" => { options.help = true; } "-v" | "--version" => { options.version = true; } option => { Err(format!("invalid option provided: {option}"))?; } }, CliArg::Argument(option, value) => match option.as_str() { "-c" | "--config" => { options.config = Some(PathBuf::from(value)); } option => { Err(format!("invalid option provided: {option}"))?; } }, CliArg::Rest(_rest) => { /* do nothing, drop remaining arguments */ } } } options.resolve_action(); // nothing to validate at the moment Ok(options) } /// from the arguments resolve which action should be performed fn resolve_action(&mut self) { if self.help { self.action = MetricsAction::Help; } else if self.version { self.action = MetricsAction::Version; } else { self.action = MetricsAction::Run; } } } pub async fn main() -> Result<(), Box> { let options = NtpMetricsExporterOptions::try_parse_from(std::env::args())?; match options.action { MetricsAction::Help => { println!("{}", long_help_message()); Ok(()) } MetricsAction::Version => { eprintln!("ntp-metrics-exporter {VERSION}"); Ok(()) } MetricsAction::Run => run(options).await, } } async fn run(options: NtpMetricsExporterOptions) -> Result<(), Box> { let config = initialize_logging_parse_config(None, options.config).await; let observation_socket_path = match config.observability.observation_path { Some(path) => path, None => { eprintln!("An observation socket path must be configured using the observation-path option in the [observability] section of the configuration"); std::process::exit(1); } }; println!( "starting ntp-metrics-exporter on {}", &config.observability.metrics_exporter_listen ); let listener = TcpListener::bind(&config.observability.metrics_exporter_listen).await?; let mut buf = String::with_capacity(4 * 1024); loop { let (mut tcp_stream, _) = listener.accept().await?; buf.clear(); match handler(&mut buf, &observation_socket_path).await { Ok(()) => { tcp_stream.write_all(buf.as_bytes()).await?; } Err(e) => { tracing::warn!("hit an error: {e}"); const ERROR_REPONSE: &str = concat!( "HTTP/1.1 500 Internal Server Error\r\n", "content-type: text/plain\r\n", "content-length: 0\r\n\r\n", ); tcp_stream.write_all(ERROR_REPONSE.as_bytes()).await?; } } } } async fn handler(buf: &mut String, observation_socket_path: &Path) -> std::io::Result<()> { let mut stream = tokio::net::UnixStream::connect(observation_socket_path).await?; let mut msg = Vec::with_capacity(16 * 1024); let observable_state: ObservableState = crate::daemon::sockets::read_json(&mut stream, &mut msg).await?; format_response(buf, &observable_state) .map_err(|_| std::io::Error::new(std::io::ErrorKind::Other, "formatting error")) } fn format_response(buf: &mut String, state: &ObservableState) -> std::fmt::Result { let mut content = String::with_capacity(4 * 1024); crate::metrics::format_state(&mut content, state)?; // headers buf.push_str("HTTP/1.1 200 OK\r\n"); buf.push_str("content-type: text/plain\r\n"); buf.write_fmt(format_args!("content-length: {}\r\n\r\n", content.len()))?; // actual content buf.write_str(&content)?; Ok(()) } #[cfg(test)] mod tests { use std::path::Path; use super::*; const BINARY: &str = "/usr/bin/ntp-metrics-exporter"; #[test] fn cli_config() { let config_str = "/foo/bar/ntp.toml"; let config = Path::new(config_str); let arguments = &[BINARY, "-c", config_str]; let options = NtpMetricsExporterOptions::try_parse_from(arguments).unwrap(); assert_eq!(options.config.unwrap().as_path(), config); } } ntpd-1.1.2/src/metrics/mod.rs000064400000000000000000000237471046102023000141710ustar 00000000000000pub mod exporter; use crate::daemon::{ObservablePeerState, ObservableState}; struct Measurement { labels: Vec<(&'static str, String)>, value: T, } impl Measurement { fn simple(value: T) -> Vec> { vec![Measurement { labels: Default::default(), value, }] } } #[derive(PartialEq, Eq, Clone, Copy)] enum Unit { Seconds, } impl Unit { fn as_str(&self) -> &str { "seconds" } } enum MetricType { Gauge, Counter, } impl MetricType { fn as_str(&self) -> &str { match self { MetricType::Gauge => "gauge", MetricType::Counter => "counter", } } } fn format_metric( w: &mut impl std::fmt::Write, name: &str, help: &str, metric_type: MetricType, unit: Option, measurements: Vec>, ) -> std::fmt::Result { let name = if let Some(unit) = unit { format!("{}_{}", name, unit.as_str()) } else { name.to_owned() }; // write help text writeln!(w, "# HELP {name} {help}.")?; // write type writeln!(w, "# TYPE {name} {}", metric_type.as_str())?; // write unit if let Some(unit) = unit { writeln!(w, "# UNIT {name} {}", unit.as_str())?; } // write all the measurements for measurement in measurements { w.write_str(&name)?; if !measurement.labels.is_empty() { w.write_str("{")?; for (offset, (label, value)) in measurement.labels.iter().enumerate() { let value = value .replace('\\', "\\\\") .replace('"', "\\\"") .replace('\n', "\\n"); write!(w, "{label}=\"{value}\"")?; if offset < measurement.labels.len() - 1 { w.write_str(",")?; } } w.write_str("}")?; } w.write_str(" ")?; write!(w, "{}", measurement.value)?; w.write_str("\n")?; } Ok(()) } macro_rules! collect_sources { ($from: expr, |$ident: ident| $value: expr $(,)?) => {{ let mut data = vec![]; for tmp in &$from.sources { if let crate::metrics::ObservablePeerState::Observable($ident) = tmp { let labels = vec![ ("name", $ident.name.clone()), ("address", $ident.address.clone()), ("id", format!("{}", $ident.id)), ]; let value = $value; data.push(Measurement { labels, value }); } } data }}; } macro_rules! collect_servers { ($from: expr, |$ident: ident| $value: expr $(,)?) => {{ let mut data = vec![]; for $ident in &$from.servers { let labels = vec![("listen_address", format!("{}", $ident.address))]; let value = $value; data.push(Measurement { labels, value }) } data }}; } pub fn format_state(w: &mut impl std::fmt::Write, state: &ObservableState) -> std::fmt::Result { format_metric( w, "ntp_uptime", "Time that the ntp daemon is running", MetricType::Gauge, Some(Unit::Seconds), vec![Measurement { labels: vec![ ("version", state.program.version.clone()), ("build_commit", state.program.build_commit.clone()), ("build_commit_date", state.program.build_commit_date.clone()), ], value: state.program.uptime_seconds, }], )?; format_metric( w, "ntp_system_poll_interval", "Time between polls of the system", MetricType::Gauge, Some(Unit::Seconds), Measurement::simple( state .system .time_snapshot .poll_interval .as_duration() .to_seconds(), ), )?; format_metric( w, "ntp_system_accumulated_steps", "Accumulated amount of seconds that the system needed to jump the time", MetricType::Gauge, Some(Unit::Seconds), Measurement::simple(state.system.time_snapshot.accumulated_steps.to_seconds()), )?; format_metric( w, "ntp_system_accumulated_steps_threshold", "Threshold for the accumulated step amount at which the NTP daemon will exit (or -1 if no threshold was set)", MetricType::Gauge, Some(Unit::Seconds), Measurement::simple(state.system .accumulated_steps_threshold .map(|v| v.to_seconds()) .unwrap_or(-1.0)), )?; format_metric( w, "ntp_system_leap_indicator", "Indicates that a leap second will take place", MetricType::Gauge, None, Measurement::simple(state.system.time_snapshot.leap_indicator as i64), )?; format_metric( w, "ntp_system_root_delay", "Distance to the closest root time source", MetricType::Gauge, Some(Unit::Seconds), Measurement::simple(state.system.time_snapshot.root_delay.to_seconds()), )?; format_metric( w, "ntp_system_root_dispersion", "Estimate of how precise our time is", MetricType::Gauge, Some(Unit::Seconds), Measurement::simple(state.system.time_snapshot.root_dispersion.to_seconds()), )?; format_metric( w, "ntp_system_stratum", "Stratum of our clock", MetricType::Gauge, None, Measurement::simple(state.system.stratum), )?; format_metric( w, "ntp_source_poll_interval", "Time between polls of the source", MetricType::Gauge, Some(Unit::Seconds), collect_sources!(state, |p| p.poll_interval.as_duration().to_seconds()), )?; format_metric( w, "ntp_source_unanswered_polls", "Number of polls since the last succesful poll with a maximum of eight", MetricType::Gauge, None, collect_sources!(state, |p| p.unanswered_polls), )?; format_metric( w, "ntp_source_offset", "Offset between the upstream source and system time", MetricType::Gauge, Some(Unit::Seconds), collect_sources!(state, |p| p.timedata.offset.to_seconds()), )?; format_metric( w, "ntp_source_delay", "Current round-trip delay to the upstream source", MetricType::Gauge, Some(Unit::Seconds), collect_sources!(state, |p| p.timedata.delay.to_seconds()), )?; format_metric( w, "ntp_source_uncertainty", "Estimated error of the source clock", MetricType::Gauge, Some(Unit::Seconds), collect_sources!(state, |p| p.timedata.uncertainty.to_seconds()), )?; format_metric( w, "ntp_source_root_delay", "Root delay reported by the time source", MetricType::Gauge, Some(Unit::Seconds), collect_sources!(state, |p| p.timedata.remote_delay.to_seconds()), )?; format_metric( w, "ntp_source_root_dispersion", "Uncertainty reported by the time source", MetricType::Gauge, Some(Unit::Seconds), collect_sources!(state, |p| p.timedata.remote_uncertainty.to_seconds()), )?; format_metric( w, "ntp_server_received_packets_total", "Number of incoming packets", MetricType::Counter, None, collect_servers!(state, |s| s.stats.received_packets.get()), )?; format_metric( w, "ntp_server_accepted_packets_total", "Number of packets accepted", MetricType::Counter, None, collect_servers!(state, |s| s.stats.accepted_packets.get()), )?; format_metric( w, "ntp_server_denied_packets_total", "Number of denied packets", MetricType::Counter, None, collect_servers!(state, |s| s.stats.denied_packets.get()), )?; format_metric( w, "ntp_server_ignored_packets_total", "Number of packets ignored", MetricType::Counter, None, collect_servers!(state, |s| s.stats.ignored_packets.get()), )?; format_metric( w, "ntp_server_rate_limited_packets_total", "Number of rate limited packets", MetricType::Counter, None, collect_servers!(state, |s| s.stats.rate_limited_packets.get()), )?; format_metric( w, "ntp_server_response_send_errors_total", "Number of packets where there was an error responding", MetricType::Counter, None, collect_servers!(state, |s| s.stats.response_send_errors.get()), )?; format_metric( w, "ntp_server_nts_received_packets_total", "Number of incoming NTS packets", MetricType::Counter, None, collect_servers!(state, |s| s.stats.nts_received_packets.get()), )?; format_metric( w, "ntp_server_nts_accepted_packets_total", "Number of NTS packets accepted", MetricType::Counter, None, collect_servers!(state, |s| s.stats.nts_accepted_packets.get()), )?; format_metric( w, "ntp_server_nts_denied_packets_total", "Number of denied NTS packets", MetricType::Counter, None, collect_servers!(state, |s| s.stats.nts_denied_packets.get()), )?; format_metric( w, "ntp_server_nts_rate_limited_packets_total", "Number of rate limited NTS packets", MetricType::Counter, None, collect_servers!(state, |s| s.stats.nts_rate_limited_packets.get()), )?; format_metric( w, "ntp_server_nts_nak_packets_total", "Number of NTS nak responses to packets", MetricType::Counter, None, collect_servers!(state, |s| s.stats.nts_nak_packets.get()), )?; w.write_str("# EOF\n")?; Ok(()) } ntpd-1.1.2/test-keys/ec_key.pem000064400000000000000000000003431046102023000144640ustar 00000000000000-----BEGIN EC PRIVATE KEY----- MHcCAQEEIB+uHkwPd9WSCTR9m1ITVFwL8UPGaKWnreDdtMBsk8c7oAoGCCqGSM49 AwEHoUQDQgAEW9lR99aS5JMx8ZI5FsJPLOhfSggg+vngirYItXGB8F2y8CblgQfw PTYuxatX/a49ea2ENluguEDKcDaL2+6iHw== -----END EC PRIVATE KEY----- ntpd-1.1.2/test-keys/end.fullchain.pem000064400000000000000000000051141046102023000157400ustar 00000000000000-----BEGIN CERTIFICATE----- MIIDsDCCApigAwIBAgIUeLa0dWVwCQr2akxP7Zrw3RDLAF8wDQYJKoZIhvcNAQEL BQAwVzELMAkGA1UEBhMCQVUxEzARBgNVBAgMClNvbWUtU3RhdGUxITAfBgNVBAoM GEludGVybmV0IFdpZGdpdHMgUHR5IEx0ZDEQMA4GA1UEAwwHVGVzdCBDQTAgFw0y MzAxMjAwOTQ3MzhaGA80NzYwMTIxNzA5NDczOFowWTELMAkGA1UEBhMCQVUxEzAR BgNVBAgMClNvbWUtU3RhdGUxITAfBgNVBAoMGEludGVybmV0IFdpZGdpdHMgUHR5 IEx0ZDESMBAGA1UEAwwJbG9jYWxob3N0MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8A MIIBCgKCAQEAsZmqWOnowHpN+nsLk0gqvsmZWPuwMBrnJrlDihyUmMXmf28CDXJL /aYDC/3a4EKIAz0uUnH6tCTK6jbmJhouGKnRpo9nS3ee3n0AENgPzcCaBgAoNYMM IT7en4a8olRviwKrMCX91fIorbuaUb0VFQ7BgfJhEvXVJinXcxkdTZJ4fztGE5Cy iqDGuJ1+EEABmDBrWCOr/gpF5HpAl9m6vbdhEWg3UvM02PAcBAn3z0Eno7O11vEK WDjZu6XWRLznY+cFEI0LvF8gLfilC15QgJdtb4+bh5jJsLHCCobBgARBdk50yhbj eQBwDOVMm2OJl5/BUl2OYbD/nK9dSUbT6wIDAQABo3AwbjAfBgNVHSMEGDAWgBR3 Va6VsK3920NVj7trkQittchtpTAJBgNVHRMEAjAAMAsGA1UdDwQEAwIE8DAUBgNV HREEDTALgglsb2NhbGhvc3QwHQYDVR0OBBYEFGWx6Z2EPXqL6pb+65eD/Dl4do/l MA0GCSqGSIb3DQEBCwUAA4IBAQCUEyM1M6EfDOkv9MHL3q1U72JvrKFx6lPDMTWd n/tWTILyQejETXWLmCxhle4JwIC+EQfAS6o/EFumgGvKp2xKuM4lS0ccaIBCCkjf bKkB5WxLppHPznxpv33f1DcU4WRNewBDra3FqJSGYGVjuHAPu4dZbPmU2bqhA22g 0tdwFZyDC3b32CY40m8gbR7VvcymMufyOeLWImR6GVCm5N6SUVpYEPbL2PFHkvnq Z6SALFAeH/Um/uPsWemBPfxMXjq5dDKWaaigiC4wxdfpPqAfORrYbRWcCOoYQv2U 9BO4LkL8OYBtG0IFuWU9eKpchFZgXbDjeoHFqBHz40yQ2yhk -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIDkTCCAnmgAwIBAgIUSJ4RLbU532cpXBrIPM0dgLjFoRowDQYJKoZIhvcNAQEL BQAwVzELMAkGA1UEBhMCQVUxEzARBgNVBAgMClNvbWUtU3RhdGUxITAfBgNVBAoM GEludGVybmV0IFdpZGdpdHMgUHR5IEx0ZDEQMA4GA1UEAwwHVGVzdCBDQTAgFw0y MzAxMjAwOTQzMzdaGA80NzYwMTIxNzA5NDMzN1owVzELMAkGA1UEBhMCQVUxEzAR BgNVBAgMClNvbWUtU3RhdGUxITAfBgNVBAoMGEludGVybmV0IFdpZGdpdHMgUHR5 IEx0ZDEQMA4GA1UEAwwHVGVzdCBDQTCCASIwDQYJKoZIhvcNAQEBBQADggEPADCC AQoCggEBALzqkvECUcCFlg4cldjWKD1/X2e+FPrMBesmUCDExAtGYIjJy2YFovFL 20eNFa4K3QK61MfsmnbhC97Q3Nrm2tFiDXdM1XjnnbGk/GKtTH/cS/v5FQt+8kbj YPKkxfwo02Nhgf8r0Ttsg439tuT+qpw3CymVzEZDllhYFL0EDq5JHAx9Sz5RiXm4 1+4E0ahWpWbTagiG/Ldgk/sXCTZvxsCw7gbULKSVEbaN+cW+pXqkD3YSvrnYCPtk /8OK7llBCtDC9puDIntrd5z6tIxCbj3jnfb9Ek/Pb/AmK04NF5OPw+eUgEwteSde lNInFgNnlEPikNrkDAmBydLuEX7yCO8CAwEAAaNTMFEwHQYDVR0OBBYEFHdVrpWw rf3bQ1WPu2uRCK21yG2lMB8GA1UdIwQYMBaAFHdVrpWwrf3bQ1WPu2uRCK21yG2l MA8GA1UdEwEB/wQFMAMBAf8wDQYJKoZIhvcNAQELBQADggEBAFHWNTDdy9BbCoX5 RRvP0S4V0g8HcaWohYuI7uNsDwW/xvOsJ7u+1rjv/Hx3lOCtnEHCAS5peJQenf6Y uQSXbt2BVX7U01TzGKC9y47yxgovpdKJDiJodWSGs6sZP/4x3M5AbGmhmdfSBFAZ /fchAzZPWd5FdYBEaT5J1nnXDCe3G5Aa43zvZzN8i/YCJ376yB7Vt6qUW8L70o9X ++snpnom2bvIKwkO4Z9jBY6njrpYjE212N1OY+eYRLknOdJlFuy6kGO2ipEoPKt/ +vur95a6fTo8WiU2kYQc649XiPNW53v1epWNFJCRoOFietIVrKANWuqQB7xVYuIG Yo0A3Sw= -----END CERTIFICATE----- ntpd-1.1.2/test-keys/end.key000064400000000000000000000032541046102023000140060ustar 00000000000000-----BEGIN PRIVATE KEY----- MIIEvwIBADANBgkqhkiG9w0BAQEFAASCBKkwggSlAgEAAoIBAQCxmapY6ejAek36 ewuTSCq+yZlY+7AwGucmuUOKHJSYxeZ/bwINckv9pgML/drgQogDPS5Scfq0JMrq NuYmGi4YqdGmj2dLd57efQAQ2A/NwJoGACg1gwwhPt6fhryiVG+LAqswJf3V8iit u5pRvRUVDsGB8mES9dUmKddzGR1Nknh/O0YTkLKKoMa4nX4QQAGYMGtYI6v+CkXk ekCX2bq9t2ERaDdS8zTY8BwECffPQSejs7XW8QpYONm7pdZEvOdj5wUQjQu8XyAt +KULXlCAl21vj5uHmMmwscIKhsGABEF2TnTKFuN5AHAM5UybY4mXn8FSXY5hsP+c r11JRtPrAgMBAAECggEASD/QKe22bx8SO/T0h40TPpw60xVI3rkDEiDKFhR8aw4P MAZT2m6F9YEkuisicJsAQ/kOsCGIMOLK3a9Jv3RlDkl/bXfnOK9IJRDLBw8ulrBk uE42DVbrh1bRMCqa8JrS6cVDKQo7kl66J7srE1eNjQx8skWNMi5p8OWSrVMpNZXT 1jGXFHpHkZz4i5TSeovSKMPRHEpXB3QQRIV7izysxtyQiBgHyCgmxwva5vjRZGQN BZyZzDcxpRTVR8B8JvUoxKpNSFatPD2+d0JT/g8a26uLymJbwI+K6bDzTY900xR6 ufH0pcw0nCgryAHp1Zt8+1hC43nblnnOxJwAJ6ad0QKBgQDgCCvcrlNO5AxsgkmT CRaSSIoaUF8+QZIhXXUL6wsdGKba5vND8Rjzdow4Ewy4vO/KGH7vvj9sv1mtV2bu kkHk5y6uA2FjUnbGHBxnHzv/mbNa3+q8sYFVF/QqTektqRXdLo98ButOZhTQX6I5 6EIWHvLDeOlgczDcNPBJ5ZdziQKBgQDK8Vt3goNSCqWTsb+4OFS+KsS6Ncakxu9E rdWM2m8TSx5z71Jzp3Lj28rVmPrI5bFhwLFxWcHfipRP+xE1uo2Ga8CqXy6UuvVp 1hbvzltwecAPeEzPD5hs7pWK7DmKLL3iUnl537CREP4UVwKCrHkt4xLZCaiTv5wn m2D36WVK0wKBgQCO0Ua8+TjMmx68cdZbcLi96pZ3rfL5qi1xLbX3MhC0rMl51S8R ifphAprjCGncvz2SNUl+pmaied2+XnCU+BIfzaz5a9hCzAhBxRvqNYQ3LpGjBgoL 3pDXYVzbNy3GWPtCNHNuGq8ZHIR6Te0KQ2EV3wbdzA/i16w3RVxFj6KcGQKBgQCG 7PjW+Bq/DP0QuPiyTiFpXZ31/5LWMr0ZeEmmoAOBXEwe4Fp9MjMccyDj6hWyQ6Qv TaGrrvVK3iPFGTNT+XfmivVJUIbzs2k+uGv/e78nhIrAvkay07ePlQAvoOaQizaj phnFgYcuq5GBjGfK4UifzXzWd6lwsc/sNU2/BZmmqQKBgQCD2PevU6thArwydWc3 ALP+1VvS37n6XOp1ywqECNhUI2rJ8ShbIlF/kbB9ylPnei14cnn4oP04HP9ZFXkR yx+OWiTAepvQUFjIXDst+CIUVmeFhE5RcHpOyHioDA6eQ88fzE6sTOC0SvZFF04u +O3oaJs+4jqY2DpsCuqYZjBEug== -----END PRIVATE KEY----- ntpd-1.1.2/test-keys/end.pem000064400000000000000000000024721046102023000140000ustar 00000000000000-----BEGIN CERTIFICATE----- MIIDsDCCApigAwIBAgIUeLa0dWVwCQr2akxP7Zrw3RDLAF8wDQYJKoZIhvcNAQEL BQAwVzELMAkGA1UEBhMCQVUxEzARBgNVBAgMClNvbWUtU3RhdGUxITAfBgNVBAoM GEludGVybmV0IFdpZGdpdHMgUHR5IEx0ZDEQMA4GA1UEAwwHVGVzdCBDQTAgFw0y MzAxMjAwOTQ3MzhaGA80NzYwMTIxNzA5NDczOFowWTELMAkGA1UEBhMCQVUxEzAR BgNVBAgMClNvbWUtU3RhdGUxITAfBgNVBAoMGEludGVybmV0IFdpZGdpdHMgUHR5 IEx0ZDESMBAGA1UEAwwJbG9jYWxob3N0MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8A MIIBCgKCAQEAsZmqWOnowHpN+nsLk0gqvsmZWPuwMBrnJrlDihyUmMXmf28CDXJL /aYDC/3a4EKIAz0uUnH6tCTK6jbmJhouGKnRpo9nS3ee3n0AENgPzcCaBgAoNYMM IT7en4a8olRviwKrMCX91fIorbuaUb0VFQ7BgfJhEvXVJinXcxkdTZJ4fztGE5Cy iqDGuJ1+EEABmDBrWCOr/gpF5HpAl9m6vbdhEWg3UvM02PAcBAn3z0Eno7O11vEK WDjZu6XWRLznY+cFEI0LvF8gLfilC15QgJdtb4+bh5jJsLHCCobBgARBdk50yhbj eQBwDOVMm2OJl5/BUl2OYbD/nK9dSUbT6wIDAQABo3AwbjAfBgNVHSMEGDAWgBR3 Va6VsK3920NVj7trkQittchtpTAJBgNVHRMEAjAAMAsGA1UdDwQEAwIE8DAUBgNV HREEDTALgglsb2NhbGhvc3QwHQYDVR0OBBYEFGWx6Z2EPXqL6pb+65eD/Dl4do/l MA0GCSqGSIb3DQEBCwUAA4IBAQCUEyM1M6EfDOkv9MHL3q1U72JvrKFx6lPDMTWd n/tWTILyQejETXWLmCxhle4JwIC+EQfAS6o/EFumgGvKp2xKuM4lS0ccaIBCCkjf bKkB5WxLppHPznxpv33f1DcU4WRNewBDra3FqJSGYGVjuHAPu4dZbPmU2bqhA22g 0tdwFZyDC3b32CY40m8gbR7VvcymMufyOeLWImR6GVCm5N6SUVpYEPbL2PFHkvnq Z6SALFAeH/Um/uPsWemBPfxMXjq5dDKWaaigiC4wxdfpPqAfORrYbRWcCOoYQv2U 9BO4LkL8OYBtG0IFuWU9eKpchFZgXbDjeoHFqBHz40yQ2yhk -----END CERTIFICATE----- ntpd-1.1.2/test-keys/gen-cert.sh000075500000000000000000000026771046102023000146010ustar 00000000000000#! /bin/sh # This script generates a private key/certificate for a server, and signs it with the provided CA key # based on https://docs.ntpd-rs.pendulum-project.org/development/ca/ # Because this script generate keys without passwords set, they should only be used in a development setting. if [ -z "$1" ]; then echo "usage: gen-cert.sh name-of-server [ca-name]" echo echo "This will generate a name-of-server.key, name-of-server.pem and name-of-server.chain.pem file" echo "containing the private key, public certificate, and full certificate chain (respectively)" echo echo "The second argument denotes the name of the CA be used (found in the files ca-name.key and ca-name.pem)" echo "If this is omitted, the name 'testca' will be used." exit fi NAME="${1:-ntpd-rs.test}" CA="${2:-testca}" # generate a key openssl genrsa -out "$NAME".key 2048 # generate a certificate signing request openssl req -batch -new -key "$NAME".key -out "$NAME".csr # generate an ext file cat >> "$NAME".ext < "$NAME".chain.pem # cleanup rm "$NAME".csr ntpd-1.1.2/test-keys/pkcs8_key.pem000064400000000000000000000003611046102023000151250ustar 00000000000000-----BEGIN PRIVATE KEY----- MIGHAgEAMBMGByqGSM49AgEGCCqGSM49AwEHBG0wawIBAQQgDi/ejEuJATtM3Y1u zzdOIYXvP0FoKUDD2b0dJD+A1PChRANCAAQVage65def6DD2jTzZ7hu+sNaw9zeQ SbSlApUWht98YHRhVM/hyN3lJ0or0qVyjcW49uSzHyuDm2BtwlcLQjOh -----END PRIVATE KEY----- ntpd-1.1.2/test-keys/rsa_key.pem000064400000000000000000000015671046102023000146730ustar 00000000000000-----BEGIN RSA PRIVATE KEY----- MIICXAIBAAKBgQC1Dt8tFmGS76ciuNXvk/QRrV8wCcArWxvl7Ku0aSQXgcFBAav6 P5RD8b+dC9DihSu/r+6OOfjsAZ6oKCq3OTUfmoUhLpoBomxPczJgLyyLD+nQkp5q B1Q3WB6ACL/HJRRjJEIn7lc5u1FVBGbiCAHKMiaP4BDSym8oqimKC6uiaQIDAQAB AoGAGKmY7sxQqDIqwwkIYyT1Jv9FqwZ4/a7gYvZVATMdLnKHP3KZ2XGVoZepcRvt 7R0Us3ykcw0kgglKcj9eaizJtnSuoDPPwt53mDypPN2sU3hZgyk2tPgr49DB3MIp fjoqw4RL/p60ksgGXbDEqBuXqOtH5i61khWlMj+BWL9VDq0CQQDaELWPQGjgs+7X /QyWMJwOF4FXE4jecH/CcPVDB9K1ukllyC1HqTNe44Sp2bIDuSXXWb8yEixrEWBE ci2CSSjXAkEA1I4W9IzwEmAeLtL6VBip9ks52O0JKu373/Xv1F2GYdhnQaFw7IC6 1lSzcYMKGTmDuM8Cj26caldyv19Q0SPmvwJAdRHjZzS9GWWAJJTF3Rvbq/USix0B renXrRvXkFTy2n1YSjxdkstTuO2Mm2M0HquXlTWpX8hB8HkzpYtmwztjoQJAECKl LXVReCOhxu4vIJkqtc6qGoSL8J1WRH8X8KgU3nKeDAZkWx++jyyo3pIS/y01iZ71 U8wSxaPTyyFCMk4mYwJBALjg7g8yDy1Lg9GFfOZvAVzPjqD28jZh/VJsDz9IhYoG z89iHWHkllOisbOm+SeynVC8CoFXmJPc26U65GcjI18= -----END RSA PRIVATE KEY----- ntpd-1.1.2/test-keys/testca.key000064400000000000000000000032501046102023000145170ustar 00000000000000-----BEGIN PRIVATE KEY----- MIIEvgIBADANBgkqhkiG9w0BAQEFAASCBKgwggSkAgEAAoIBAQC86pLxAlHAhZYO HJXY1ig9f19nvhT6zAXrJlAgxMQLRmCIyctmBaLxS9tHjRWuCt0CutTH7Jp24Qve 0Nza5trRYg13TNV4552xpPxirUx/3Ev7+RULfvJG42DypMX8KNNjYYH/K9E7bION /bbk/qqcNwsplcxGQ5ZYWBS9BA6uSRwMfUs+UYl5uNfuBNGoVqVm02oIhvy3YJP7 Fwk2b8bAsO4G1CyklRG2jfnFvqV6pA92Er652Aj7ZP/Diu5ZQQrQwvabgyJ7a3ec +rSMQm494532/RJPz2/wJitODReTj8PnlIBMLXknXpTSJxYDZ5RD4pDa5AwJgcnS 7hF+8gjvAgMBAAECggEAAZrFvgbSoSHLqN7lSP7ZLtfkTwpuA7RZeIUQNQmgGW0P 3BFQZA0v8kaImiM8gdb2TC7dKJSGBKImQTW4CXmejxSX7l1H7bsYWHBgHKsYifQw q95QccSuZHJ0zYIGtcMA8e2Zk4Qa/GVzbT7+0QMb1IKuh+mRrbN9hLWsXJTTuYvf GppDVqMdDPy5NibudiZPKdpnMyDCJ/Wxl1+1PX18anifzBHw/G8ZPnLU3OKDqL2T OtEivvk9ZFDiRKKEsHksr+aLcUGhXFswk0zEQJwMj6rFwcDEExTQkMar+xaxshpf qo6AC88SDT9qEffSHHGJzTi73NIGgLNPO1aON4/pwQKBgQDUPo+ZJymo9IunaXWi HywqLLVZJSvqo2x9SrlqqYe3Yz0bROGBoHSMaGQzxiDApeOabdyg24wrU1P24jrC jPt94TWdu8bZKAkZAGOUPvdSGA/5yQkxVSMUK5zZwQxyLWfb77+B+WSvzhxI17Bt bX6od5pcdFSC5OczJ64DjLeHlQKBgQDj3NjsbLnxFu88A121kPD4AdpoMAtgrA5R AWwc7mWzKvL1RZlZCn861QMaRoUThQW4+dxTdoOoL68PXK3L8zuU3imKOBOe33lh j7B+M0gjdWnkcTag5q56qk1VA4YZ0R30LhUw44JxFHXhtuTR00CattI1pOQr6OdK By3kj4NdcwKBgQChOxko1eg+0e6Y8XMMAjQxoZ7tpmAzMYxDrZUm4rwXYsrTwUKx jyuaUd70uai90AcTlCuLAtz7OKTLIlZS3nhZytBJD5Fh+5jVpkb/IcoNUfwo20Ah erRYKT1Q6ebDgZypJfpMCSEksCUqbLc4mXojDiBz5WchvDOp15XIWog89QKBgE3c Vxtig58IETNWixzRrCVyrKjRUfH0mOfBLqosJAA2+tIouB+e4J6/ztGZqztiRvRQ HKNAafh8YrtDFfgM4x0ZVORwCPROtHFL4ikdaNcE9ewja2FLse8kZkxYaehEdpHL dV5BP39YWHeKQWIZZ4f2VJoUAAupB+9ZyKrDB0ZVAoGBALJ0KzHlAizbZyXRtfk+ ThnegTgjbTd6drMTsRlyHdL1Zet0tdx2nhn2keMQVSDep5KEwTvm+Wy41s9EmzZx RyehNaq9hMljLGR6mtr4Em5RtxtkPTwoJcOttHXQXnTgplDbePb8zQ8N084fScek 0dIjCbVBt5X7akmgHaaizIDl -----END PRIVATE KEY----- ntpd-1.1.2/test-keys/testca.pem000064400000000000000000000024221046102023000145100ustar 00000000000000-----BEGIN CERTIFICATE----- MIIDkTCCAnmgAwIBAgIUSJ4RLbU532cpXBrIPM0dgLjFoRowDQYJKoZIhvcNAQEL BQAwVzELMAkGA1UEBhMCQVUxEzARBgNVBAgMClNvbWUtU3RhdGUxITAfBgNVBAoM GEludGVybmV0IFdpZGdpdHMgUHR5IEx0ZDEQMA4GA1UEAwwHVGVzdCBDQTAgFw0y MzAxMjAwOTQzMzdaGA80NzYwMTIxNzA5NDMzN1owVzELMAkGA1UEBhMCQVUxEzAR BgNVBAgMClNvbWUtU3RhdGUxITAfBgNVBAoMGEludGVybmV0IFdpZGdpdHMgUHR5 IEx0ZDEQMA4GA1UEAwwHVGVzdCBDQTCCASIwDQYJKoZIhvcNAQEBBQADggEPADCC AQoCggEBALzqkvECUcCFlg4cldjWKD1/X2e+FPrMBesmUCDExAtGYIjJy2YFovFL 20eNFa4K3QK61MfsmnbhC97Q3Nrm2tFiDXdM1XjnnbGk/GKtTH/cS/v5FQt+8kbj YPKkxfwo02Nhgf8r0Ttsg439tuT+qpw3CymVzEZDllhYFL0EDq5JHAx9Sz5RiXm4 1+4E0ahWpWbTagiG/Ldgk/sXCTZvxsCw7gbULKSVEbaN+cW+pXqkD3YSvrnYCPtk /8OK7llBCtDC9puDIntrd5z6tIxCbj3jnfb9Ek/Pb/AmK04NF5OPw+eUgEwteSde lNInFgNnlEPikNrkDAmBydLuEX7yCO8CAwEAAaNTMFEwHQYDVR0OBBYEFHdVrpWw rf3bQ1WPu2uRCK21yG2lMB8GA1UdIwQYMBaAFHdVrpWwrf3bQ1WPu2uRCK21yG2l MA8GA1UdEwEB/wQFMAMBAf8wDQYJKoZIhvcNAQELBQADggEBAFHWNTDdy9BbCoX5 RRvP0S4V0g8HcaWohYuI7uNsDwW/xvOsJ7u+1rjv/Hx3lOCtnEHCAS5peJQenf6Y uQSXbt2BVX7U01TzGKC9y47yxgovpdKJDiJodWSGs6sZP/4x3M5AbGmhmdfSBFAZ /fchAzZPWd5FdYBEaT5J1nnXDCe3G5Aa43zvZzN8i/YCJ376yB7Vt6qUW8L70o9X ++snpnom2bvIKwkO4Z9jBY6njrpYjE212N1OY+eYRLknOdJlFuy6kGO2ipEoPKt/ +vur95a6fTo8WiU2kYQc649XiPNW53v1epWNFJCRoOFietIVrKANWuqQB7xVYuIG Yo0A3Sw= -----END CERTIFICATE----- ntpd-1.1.2/test-keys/unsafe.nts.client.toml000064400000000000000000000007461046102023000167670ustar 00000000000000[observability] # Other values include trace, debug, warn and error log-level = "info" observation-path = "/var/run/ntpd-rs/observe" # uses an unsecure certificate! [[source]] mode = "nts" address = "localhost:4460" certificate-authority = "ntp-proto/test-keys/testca.pem" # System parameters used in filtering and steering the clock: [synchronization] minimum-agreeing-sources = 1 single-step-panic-threshold = 10 startup-step-panic-threshold = { forward = "inf", backward = 86400 } ntpd-1.1.2/test-keys/unsafe.nts.server.toml000064400000000000000000000014121046102023000170060ustar 00000000000000[observability] # Other values include trace, debug, warn and error log-level = "info" observation-path = "/var/run/ntpd-rs/observe" # the server will get its time from the NTP pool [[source]] mode = "pool" address = "pool.ntp.org" count = 4 [[server]] listen = "0.0.0.0:123" # System parameters used in filtering and steering the clock: [synchronization] minimum-agreeing-sources = 1 single-step-panic-threshold = 10 startup-step-panic-threshold = { forward = 0, backward = 86400 } # to function as an NTS server, we must also provide key exchange # uses an unsecure certificate chain! [[nts-ke-server]] listen = "0.0.0.0:4460" certificate-chain-path = "ntp-proto/test-keys/end.fullchain.pem" private-key-path = "ntp-proto/test-keys/end.key" key-exchange-timeout-ms = 1000 ntpd-1.1.2/testdata/certificates/nos-nl-chain.pem000064400000000000000000000124221046102023000200420ustar 00000000000000-----BEGIN CERTIFICATE----- MIIHCTCCBfGgAwIBAgIMTdpv32aw4nga60ZTMA0GCSqGSIb3DQEBCwUAMGIxCzAJ BgNVBAYTAkJFMRkwFwYDVQQKExBHbG9iYWxTaWduIG52LXNhMTgwNgYDVQQDEy9H bG9iYWxTaWduIEV4dGVuZGVkIFZhbGlkYXRpb24gQ0EgLSBTSEEyNTYgLSBHMzAe Fw0yMjA1MTMwODMwMjFaFw0yMzA2MTQwODMwMjBaMIHSMR0wGwYDVQQPDBRQcml2 YXRlIE9yZ2FuaXphdGlvbjERMA8GA1UEBRMIMzIxNDIxNTcxEzARBgsrBgEEAYI3 PAIBAxMCTkwxCzAJBgNVBAYTAk5MMRYwFAYDVQQIDA1Ob29yZC1Ib2xsYW5kMRIw EAYDVQQHDAlIaWx2ZXJzdW0xGDAWBgNVBAkTD0pvdXJuYWFscGxlaW4gMTElMCMG A1UECgwcTmVkZXJsYW5kc2UgT21yb2VwIFN0aWNodGluZzEPMA0GA1UEAwwGbm9z Lm5sMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAuTH3TymFYol1moZf mpd+aU5BvXhu0/upYNfG/Pdeb+hDhNqh6PBy4GpjFUlUM9ZTmaLBrCcw1h8UfqUX lMK8CFMZ2WTPvLn7ye5Lz5h573fY9weB3zQXpW76XWChUs9pkutFYS8ib6pJJ4Ry 81hMpORi3eXkA4KcSKZjzoMYj/7qXr0zg5D3HvaVwr5bO60gp8+kTmV05SAgm1Si mi8j9L5hvzCu76VoOxe2YQ62vGnc/gbFFri5tb2BQzOi/0bqdGp/3CSmFpWSBFgp tkNBIoNIZkA2TSrvDLI+nWb8tKbQcInWsxpjNkI2R1d3H7YEQ2D4PslaIp4R2pOL XhjGgwIDAQABo4IDTDCCA0gwDgYDVR0PAQH/BAQDAgWgMIGWBggrBgEFBQcBAQSB iTCBhjBHBggrBgEFBQcwAoY7aHR0cDovL3NlY3VyZS5nbG9iYWxzaWduLmNvbS9j YWNlcnQvZ3NleHRlbmR2YWxzaGEyZzNyMy5jcnQwOwYIKwYBBQUHMAGGL2h0dHA6 Ly9vY3NwMi5nbG9iYWxzaWduLmNvbS9nc2V4dGVuZHZhbHNoYTJnM3IzMFUGA1Ud IAROMEwwQQYJKwYBBAGgMgEBMDQwMgYIKwYBBQUHAgEWJmh0dHBzOi8vd3d3Lmds b2JhbHNpZ24uY29tL3JlcG9zaXRvcnkvMAcGBWeBDAEBMAkGA1UdEwQCMAAwRQYD VR0fBD4wPDA6oDigNoY0aHR0cDovL2NybC5nbG9iYWxzaWduLmNvbS9ncy9nc2V4 dGVuZHZhbHNoYTJnM3IzLmNybDARBgNVHREECjAIggZub3MubmwwHQYDVR0lBBYw FAYIKwYBBQUHAwEGCCsGAQUFBwMCMB8GA1UdIwQYMBaAFN2z522oLujFTm7PdOZ1 PJQVzugdMB0GA1UdDgQWBBRwAeiFlr/vJwBoNAcRwcfv6fGcjDCCAYAGCisGAQQB 1nkCBAIEggFwBIIBbAFqAHcA6D7Q2j71BjUy51covIlryQPTy9ERa+zraeF3fW0G vW4AAAGAvIpOYwAABAMASDBGAiEA34Pweig2mO0zRSShk8wOiNhZjXZeIYN+RoGp 3cIZ9uICIQDG6+LKsYyDYJ/a5y++PWvB4naUG9I7rLk+nutTAc2qdAB3AG9Tdqwx 8DEZ2JkApFEV/3cVHBHZAsEAKQaNsgiaN9kTAAABgLyKTk8AAAQDAEgwRgIhAOy9 TFYU2Ha00+55nikglOYb5EwIV+Bo8gwWw6v0KEqOAiEAv9dfDzlsroqmwzWBHZ9c zk5khSjX7f7uOtmKJPzx+k0AdgCzc3cH4YRQ+GOG1gWp3BEJSnktsWcMC4fc8AMO eTalmgAAAYC8ik56AAAEAwBHMEUCIQCcW8UV1T6fubzmyf/GsudPVmVG/vMUDL1m Qsr5BX3fwwIgBfAo4On+NVAeTocK4YpTBq4U5ZYM03AnhSbLkl1vGpUwDQYJKoZI hvcNAQELBQADggEBAHVqGqbSpa6rnWZY/zJrfe4EGiMA+U6fQS+e1FR04KJPEEVl D2w00a7yeqKdklxWnABhQBKL9k7cn7MBIXwzcApJIrAhk1WV1thlia3+5oP+5H4i sc6bshjYd9O2aQQ4bAA7CFIgioew9pU8oNKR/ocNQsWKAfJHszgngS3sD0Wzn0Kz mM+KfxwKlxfv8Ruf/H8j0GVMN3PIisvaynjTSBA2EKrvkBCMA3hn6kpdykrN6H9p 5ZGAJz2+jAxpIxRTnknC9IL/pDZ1dHz9fknyJihqv+9M701J2GQVtSzvZksE6zJA wzlqekvHQpgxHT42k+gVSk6tNYstvAJuugxiz6g= -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIEYTCCA0mgAwIBAgIOSKQC3SeSDaIINJ3RmXswDQYJKoZIhvcNAQELBQAwTDEg MB4GA1UECxMXR2xvYmFsU2lnbiBSb290IENBIC0gUjMxEzARBgNVBAoTCkdsb2Jh bFNpZ24xEzARBgNVBAMTCkdsb2JhbFNpZ24wHhcNMTYwOTIxMDAwMDAwWhcNMjYw OTIxMDAwMDAwWjBiMQswCQYDVQQGEwJCRTEZMBcGA1UEChMQR2xvYmFsU2lnbiBu di1zYTE4MDYGA1UEAxMvR2xvYmFsU2lnbiBFeHRlbmRlZCBWYWxpZGF0aW9uIENB IC0gU0hBMjU2IC0gRzMwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQCr awNnVNXcEfvFohPBjBkn3BB04mGDPfqO24+lD+SpvkY/Ar5EpAkcJjOfR0iBFYhW N80HzpXYy2tIA7mbXpKu2JpmYdU1xcoQpQK0ujE/we+vEDyjyjmtf76LLqbOfuq3 xZbSqUqAY+MOvA67nnpdawvkHgJBFVPnxui45XH4BwTwbtDucx+Mo7EK4mS0Ti+P 1NzARxFNCUFM8Wxc32wxXKff6WU4TbqUx/UJm485ttkFqu0Ox4wTUUbn0uuzK7yV 3Y986EtGzhKBraMH36MekSYlE473GqHetRi9qbNG5pM++Sa+WjR9E1e0Yws16CGq smVKwAqg4uc43eBTFUhVAgMBAAGjggEpMIIBJTAOBgNVHQ8BAf8EBAMCAQYwEgYD VR0TAQH/BAgwBgEB/wIBADAdBgNVHQ4EFgQU3bPnbagu6MVObs905nU8lBXO6B0w HwYDVR0jBBgwFoAUj/BLf6guRSSuTVD6Y5qL3uLdG7wwPgYIKwYBBQUHAQEEMjAw MC4GCCsGAQUFBzABhiJodHRwOi8vb2NzcDIuZ2xvYmFsc2lnbi5jb20vcm9vdHIz MDYGA1UdHwQvMC0wK6ApoCeGJWh0dHA6Ly9jcmwuZ2xvYmFsc2lnbi5jb20vcm9v dC1yMy5jcmwwRwYDVR0gBEAwPjA8BgRVHSAAMDQwMgYIKwYBBQUHAgEWJmh0dHBz Oi8vd3d3Lmdsb2JhbHNpZ24uY29tL3JlcG9zaXRvcnkvMA0GCSqGSIb3DQEBCwUA A4IBAQBVaJzl0J/i0zUV38iMXIQ+Q/yht+JZZ5DW1otGL5OYV0LZ6ZE6xh+WuvWJ J4hrDbhfo6khUEaFtRUnurqzutvVyWgW8msnoP0gtMZO11cwPUMUuUV8iGyIOuIB 0flo6G+XbV74SZuR5v5RAgqgGXucYUPZWvv9AfzMMQhRQkr/MO/WR2XSdiBrXHoD L2xk4DmjA4K6iPI+1+qMhyrkUM/2ZEdA8ldqwl8nQDkKS7vq6sUZ5LPVdfpxJZZu 5JBj4y7FNFTVW1OMlCUvwt5H8aFgBMLFik9xqK6JFHpYxYmf4t2sLLxN0LlCthJE abvp10ZlOtfu8hL5gCXcxnwGxzSb -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIDXzCCAkegAwIBAgILBAAAAAABIVhTCKIwDQYJKoZIhvcNAQELBQAwTDEgMB4G A1UECxMXR2xvYmFsU2lnbiBSb290IENBIC0gUjMxEzARBgNVBAoTCkdsb2JhbFNp Z24xEzARBgNVBAMTCkdsb2JhbFNpZ24wHhcNMDkwMzE4MTAwMDAwWhcNMjkwMzE4 MTAwMDAwWjBMMSAwHgYDVQQLExdHbG9iYWxTaWduIFJvb3QgQ0EgLSBSMzETMBEG A1UEChMKR2xvYmFsU2lnbjETMBEGA1UEAxMKR2xvYmFsU2lnbjCCASIwDQYJKoZI hvcNAQEBBQADggEPADCCAQoCggEBAMwldpB5BngiFvXAg7aEyiie/QV2EcWtiHL8 RgJDx7KKnQRfJMsuS+FggkbhUqsMgUdwbN1k0ev1LKMPgj0MK66X17YUhhB5uzsT gHeMCOFJ0mpiLx9e+pZo34knlTifBtc+ycsmWQ1z3rDI6SYOgxXG71uL0gRgykmm KPZpO/bLyCiR5Z2KYVc3rHQU3HTgOu5yLy6c+9C7v/U9AOEGM+iCK65TpjoWc4zd QQ4gOsC0p6Hpsk+QLjJg6VfLuQSSaGjlOCZgdbKfd/+RFO+uIEn8rUAVSNECMWEZ XriX7613t2Saer9fwRPvm2L7DWzgVGkWqQPabumDk3F2xmmFghcCAwEAAaNCMEAw DgYDVR0PAQH/BAQDAgEGMA8GA1UdEwEB/wQFMAMBAf8wHQYDVR0OBBYEFI/wS3+o LkUkrk1Q+mOai97i3Ru8MA0GCSqGSIb3DQEBCwUAA4IBAQBLQNvAUKr+yAzv95ZU RUm7lgAJQayzE4aGKAczymvmdLm6AC2upArT9fHxD4q/c2dKg8dEe3jgr25sbwMp jjM5RcOO5LlXbKr8EpbsU8Yt5CRsuZRj+9xTaGdWPoO4zzUhw8lo/s7awlOqzJCK 6fBdRoyV3XpYKBovHd7NADdBj+1EbddTKJd+82cEHhXXipa0095MJ6RMG3NzdvQX mcIfeg7jLQitChws/zyrVQ4PkX4268NXSb7hLi18YIvDQVETI53O9zJrlAGomecs Mx86OyXShkDOOyyGeMlhLxS67ttVb9+E7gUJTb0o2HLO02JQZR7rkpeDMdmztcpH WD9f -----END CERTIFICATE----- ntpd-1.1.2/testdata/certificates/nos-nl.pem000064400000000000000000000031041046102023000167570ustar 00000000000000-----BEGIN CERTIFICATE----- MIIEYTCCA0mgAwIBAgIOSKQC3SeSDaIINJ3RmXswDQYJKoZIhvcNAQELBQAwTDEg MB4GA1UECxMXR2xvYmFsU2lnbiBSb290IENBIC0gUjMxEzARBgNVBAoTCkdsb2Jh bFNpZ24xEzARBgNVBAMTCkdsb2JhbFNpZ24wHhcNMTYwOTIxMDAwMDAwWhcNMjYw OTIxMDAwMDAwWjBiMQswCQYDVQQGEwJCRTEZMBcGA1UEChMQR2xvYmFsU2lnbiBu di1zYTE4MDYGA1UEAxMvR2xvYmFsU2lnbiBFeHRlbmRlZCBWYWxpZGF0aW9uIENB IC0gU0hBMjU2IC0gRzMwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQCr awNnVNXcEfvFohPBjBkn3BB04mGDPfqO24+lD+SpvkY/Ar5EpAkcJjOfR0iBFYhW N80HzpXYy2tIA7mbXpKu2JpmYdU1xcoQpQK0ujE/we+vEDyjyjmtf76LLqbOfuq3 xZbSqUqAY+MOvA67nnpdawvkHgJBFVPnxui45XH4BwTwbtDucx+Mo7EK4mS0Ti+P 1NzARxFNCUFM8Wxc32wxXKff6WU4TbqUx/UJm485ttkFqu0Ox4wTUUbn0uuzK7yV 3Y986EtGzhKBraMH36MekSYlE473GqHetRi9qbNG5pM++Sa+WjR9E1e0Yws16CGq smVKwAqg4uc43eBTFUhVAgMBAAGjggEpMIIBJTAOBgNVHQ8BAf8EBAMCAQYwEgYD VR0TAQH/BAgwBgEB/wIBADAdBgNVHQ4EFgQU3bPnbagu6MVObs905nU8lBXO6B0w HwYDVR0jBBgwFoAUj/BLf6guRSSuTVD6Y5qL3uLdG7wwPgYIKwYBBQUHAQEEMjAw MC4GCCsGAQUFBzABhiJodHRwOi8vb2NzcDIuZ2xvYmFsc2lnbi5jb20vcm9vdHIz MDYGA1UdHwQvMC0wK6ApoCeGJWh0dHA6Ly9jcmwuZ2xvYmFsc2lnbi5jb20vcm9v dC1yMy5jcmwwRwYDVR0gBEAwPjA8BgRVHSAAMDQwMgYIKwYBBQUHAgEWJmh0dHBz Oi8vd3d3Lmdsb2JhbHNpZ24uY29tL3JlcG9zaXRvcnkvMA0GCSqGSIb3DQEBCwUA A4IBAQBVaJzl0J/i0zUV38iMXIQ+Q/yht+JZZ5DW1otGL5OYV0LZ6ZE6xh+WuvWJ J4hrDbhfo6khUEaFtRUnurqzutvVyWgW8msnoP0gtMZO11cwPUMUuUV8iGyIOuIB 0flo6G+XbV74SZuR5v5RAgqgGXucYUPZWvv9AfzMMQhRQkr/MO/WR2XSdiBrXHoD L2xk4DmjA4K6iPI+1+qMhyrkUM/2ZEdA8ldqwl8nQDkKS7vq6sUZ5LPVdfpxJZZu 5JBj4y7FNFTVW1OMlCUvwt5H8aFgBMLFik9xqK6JFHpYxYmf4t2sLLxN0LlCthJE abvp10ZlOtfu8hL5gCXcxnwGxzSb -----END CERTIFICATE----- ntpd-1.1.2/testdata/config/invalid.toml000064400000000000000000000001661046102023000161760ustar 00000000000000[[source]] mode = "server" address = "example.com" [synchronization] does-not-exist = 5 minimum-agreeing-sources = 2 ntpd-1.1.2/tests/ctl.rs000064400000000000000000000107111046102023000130640ustar 00000000000000use std::{ io::Write, os::unix::net::UnixListener, process::{Command, Output}, thread::spawn, }; fn contains_bytes(mut haystack: &[u8], needle: &[u8]) -> bool { while haystack.len() >= needle.len() { if haystack.starts_with(needle) { return true; } haystack = &haystack[1..]; } false } fn test_ntp_ctl_output(args: &[&str]) -> Output { Command::new(env!("CARGO_BIN_EXE_ntp-ctl")) .args(args) .output() .unwrap() } const CARGO_MANIFEST_DIR: &str = env!("CARGO_MANIFEST_DIR"); const CARGO_TARGET_TMPDIR: &str = env!("CARGO_TARGET_TMPDIR"); #[test] fn test_validate_bad() { let result = test_ntp_ctl_output(&[ "validate", "-c", &format!("{CARGO_MANIFEST_DIR}/testdata/config/invalid.toml",), ]); assert!(contains_bytes( &result.stderr, b"unknown field `does-not-exist`" )); assert_eq!(result.status.code(), Some(1)); } #[test] fn test_validate_good() { let result = test_ntp_ctl_output(&[ "validate", "-c", &format!("{CARGO_MANIFEST_DIR}/../ntp.toml"), ]); assert!(contains_bytes(&result.stderr, b"good")); assert_eq!(result.status.code(), Some(0)); } const EXAMPLE_SOCKET_OUTPUT: &str = r#"{"program":{"version":"1.0.0","build_commit":"test","build_commit_date":"2000-01-01","uptime_seconds":0.12345},"system":{"stratum":3,"reference_id":3243240718,"accumulated_steps_threshold":null,"poll_interval":4,"precision":3.814697266513178e-6,"root_delay":0.004877627828362777,"root_dispersion":0.0004254912492878482,"leap_indicator":"Unknown","accumulated_steps":0.002842015820285775},"sources":[{"Observable":{"offset":0.00031014974236259,"uncertainty":0.000050753355038062054,"delay":0.0036874422812106654,"remote_delay":0.0011901855471521117,"remote_uncertainty":0.019378662113886946,"last_update":{"timestamp":16760961381687937893},"unanswered_polls":0,"poll_interval":4,"address":"1.2.3.4:123","name":"ntpd-rs.pool.ntp.org:123","id":3}},{"Observable":{"offset":0.0003928544466367118,"uncertainty":0.00005519413390550626,"delay":0.004574143328837618,"remote_delay":0.001602172851935535,"remote_uncertainty":0.0004425048829155287,"last_update":{"timestamp":16760961379467247810},"unanswered_polls":0,"poll_interval":4,"address":"5.6.7.8:123","name":"ntpd-rs.pool.ntp.org:123","id":1}},{"Observable":{"offset":0.00043044891218432433,"uncertainty":0.00005691661500765863,"delay":0.004752595444385101,"remote_delay":0.001602172851935535,"remote_uncertainty":0.03733825684463099,"last_update":{"timestamp":16760961371126323413},"unanswered_polls":0,"poll_interval":4,"address":"9.10.11.12:123","name":"ntpd-rs.pool.ntp.org:123","id":2}},{"Observable":{"offset":-0.0019038764298669707,"uncertainty":0.00016540312212086355,"delay":0.007399475902179134,"remote_delay":0.01371765137038139,"remote_uncertainty":0.0014495849612750078,"last_update":{"timestamp":16760961373841849724},"unanswered_polls":0,"poll_interval":4,"address":"13.14.15.16:123","name":"ntpd-rs.pool.ntp.org:123","id":4}}],"servers":[]}"#; #[test] fn test_status() { let _ = std::fs::remove_file(format!("{CARGO_TARGET_TMPDIR}/status_test_socket")); let socket = UnixListener::bind(format!("{CARGO_TARGET_TMPDIR}/status_test_socket")).unwrap(); spawn(move || { let (mut stream, _) = socket.accept().unwrap(); stream.write_all(EXAMPLE_SOCKET_OUTPUT.as_bytes()).unwrap(); }); let test_config_contents = format!( r#"[observability] observation-path = "{CARGO_TARGET_TMPDIR}/status_test_socket" [[source]] mode = "pool" address = "ntpd-rs.pool.ntp.org" count = 4 "# ); let test_config_path = format!("{CARGO_TARGET_TMPDIR}/status_test_config"); std::fs::write(&test_config_path, test_config_contents.as_bytes()).unwrap(); let result = test_ntp_ctl_output(&["status", "-c", &test_config_path]); assert!(contains_bytes(&result.stdout, b"ntpd-rs.pool.ntp.org")); assert!(contains_bytes( &result.stdout, "0.000310±0.000051(±0.003687)s".as_bytes() )); assert_eq!(result.status.code(), Some(0)); } #[test] fn test_version() { let result = test_ntp_ctl_output(&["-v"]); assert!(contains_bytes( &result.stderr, env!("CARGO_PKG_VERSION").as_bytes() )); assert_eq!(result.status.code(), Some(0)); } #[test] fn test_help() { let result = test_ntp_ctl_output(&["-h"]); assert!(contains_bytes(&result.stdout, b"usage")); assert_eq!(result.status.code(), Some(0)); }