fontdb-0.22.0/.cargo_vcs_info.json0000644000000001360000000000100123710ustar { "git": { "sha1": "47295abbe2b8d5c9d1b4ad336e00e8e4477f2dac" }, "path_in_vcs": "" }fontdb-0.22.0/.github/workflows/main.yml000064400000000000000000000037101046102023000162260ustar 00000000000000name: Rust on: [push, pull_request] env: CARGO_TERM_COLOR: always jobs: build-linux: runs-on: ubuntu-latest strategy: matrix: rust: - 1.60.0 - stable steps: - name: Checkout uses: actions/checkout@v3 - name: Install toolchain uses: actions-rs/toolchain@v1 with: profile: minimal toolchain: ${{ matrix.rust }} override: true - name: Build without default features run: cargo build --no-default-features - name: Build with fs run: cargo build --no-default-features --features fs - name: Build with memmap run: cargo build --no-default-features --features memmap - name: Build with fontconfig run: cargo build --no-default-features --features fontconfig - name: Run tests run: cargo test build-windows: runs-on: windows-latest steps: - name: Checkout uses: actions/checkout@v3 - name: Install toolchain uses: actions-rs/toolchain@v1 with: profile: minimal toolchain: stable override: true - name: Build without default features run: cargo build --no-default-features - name: Build with fs run: cargo build --no-default-features --features fs - name: Build with memmap run: cargo build --no-default-features --features memmap - name: Run tests run: cargo test build-mac: runs-on: macos-latest steps: - name: Checkout uses: actions/checkout@v3 - name: Install toolchain uses: actions-rs/toolchain@v1 with: profile: minimal toolchain: stable override: true - name: Build without default features run: cargo build --no-default-features - name: Build with fs run: cargo build --no-default-features --features fs - name: Build with memmap run: cargo build --no-default-features --features memmap - name: Run tests run: cargo test fontdb-0.22.0/.gitignore000064400000000000000000000000351046102023000131470ustar 00000000000000/target Cargo.lock .DS_Store fontdb-0.22.0/CHANGELOG.md000064400000000000000000000206461046102023000130020ustar 00000000000000# Change Log All notable changes to this project will be documented in this file. The format is based on [Keep a Changelog](http://keepachangelog.com/) and this project adheres to [Semantic Versioning](http://semver.org/). ## [Unreleased] ## [0.22.0] - 2024-09-09 ### Changed - Fallback to known font dirs if none were loaded via fontconfig. Linux-only. [@MoSal](https://github.com/@MoSal) ## [0.21.0] - 2024-08-06 ### Added - Symlinked files and directories will now be included when loading system fonts. [@jcdickinson](https://github.com/@jcdickinson) ## [0.20.0] - 2024-07-02 ### Changed - `ttf-parser` updated. ## [0.19.0] - 2024-07-02 ### Changed - `ttf-parser` updated. ## [0.18.0] - 2024-06-01 ### Changed - `Database::push_face_info` returns an `ID` now. [@laurmaedje](https://github.com/@laurmaedje) ## [0.17.0] - 2024-05-10 ### Added - Up to 10% faster `Database::load_system_fonts`. [@qarmin](https://github.com/@qarmin) and [@y5](https://github.com/@y5) ### Changed - Latest `ttf-parser`. ## [0.16.2] - 2024-02-19 ### Fixed - System fonts loading on Windows when the system drive is not `C:\\`. [@tronical](https://github.com/@tronical) ## [0.16.1] - 2024-02-09 ### Fixed - Treat fonts with non-zero italic angle as italic. ## [0.16.0] - 2023-10-31 ### Changed - `ttf-parser` and `memmap2` dependencies update. ## [0.15.0] - 2023-10-01 ### Changed - Enable the `fontconfig` feature by default. Linux-only. - MSRV bumped to 1.60 due to `log`. ### Fixed - Fix fontconfig alias matching order. [@declantsien](https://github.com/@declantsien) ## [0.14.1] - 2023-05-10 ### Fixed - Return valid IDs from `Database::load_font_source()`. [@notgull](https://github.com/notgull) ## [0.14.0] - 2023-05-09 ### Changed - `Database::load_font_source()` returns a list of loaded face IDs now. [@notgull](https://github.com/notgull) - `ttf-parser` and `memmap2` dependencies update. ## [0.13.1] - 2023-04-23 ### Added - Load system fonts on RedoxOS. [@FloVanGH](https://github.com/FloVanGH) ### Fixed - Improve missing `XDG_CONFIG_HOME` environment variable handling. Linux only. [@7sDream](https://github.com/7sDream) - Improve downloadable fonts detection on macOS. [@messense](https://github.com/messense) ## [0.13.0] - 2023-02-21 ### Added - `Database::default()`. [@7sDream](https://github.com/7sDream) ### Changed - Database uses `slotmap::SlotMap` instead of `Vec` as an internal storage now. This allows us to have O(1) indexing by `ID` by sacrificing faces iteration speed a bit. [@7sDream](https://github.com/7sDream) - `Database::remove_face` no longer returns `bool`. - `Database::faces` returns an Iterator and not a slice now. - MSRV bumped to 1.49 ## [0.12.0] - 2023-02-05 ### Fixed - Face weight matching. ## [0.11.2] - 2023-01-10 ### Added - Implement `Display` trait for `ID`. [@7sDream](https://github.com/7sDream) ## [0.11.1] - 2022-12-26 ### Fixed - Always prefer _Typographic Family_ to _Family Name_ when available. [@CryZe](https://github.com/CryZe) - Prevent duplicated family names. ## [0.11.0] - 2022-12-25 ### Added - Support localized family names. - Improve fontconfig support. [@declantsien](https://github.com/declantsien) ### Changed - `FaceInfo::family` was replaced with `FaceInfo::families` and contains a list of family names now. ### Fixed - Improve family name detection in variable fonts. ## [0.10.0] - 2022-11-08 ### Added - `no_std` support. [@jackpot51](https://github.com/jackpot51) ## [0.9.3] - 2022-10-26 ### Added - `Database::family_name` is public now. ## [0.9.2] - 2022-10-22 ### Added - `Database::push_face_info` - `ID::dummy` ### Fixed - Expand home path `~` prefix during fontconfig paths resolving. [@snoyer](https://github.com/snoyer) ## [0.9.1] - 2022-02-21 ### Changed - Reduce binary size by 10% using less generic code. - Simplify Database::query implementation. ## [0.9.0] - 2022-02-20 ### Added - Way faster fonts scanning by using a more low-level `ttf-parser` API which allows us to parse only required TrueType tables. On my hardware, `load_system_fonts()` loaded 898 fonts in 9ms instead of 11ms in the release mode and in 35ms instead of 52ms in debug. Currently, we're parsing only `name`, `OS/2` and `post` tables. ## [0.8.0] - 2022-02-12 ### Added - Load user fonts on Windows. - `fontconfig` feature to allow retrieving font dirs from the fontconfig config file instead of using hardcoded paths. Linux-only. [@Riey](https://github.com/Riey) ## [0.7.0] - 2021-10-04 ### Changed - The `Source` enum has a new variant `SharedFile`, used for unsafe persistent memory mappings. - `FaceInfo` stores `Source` directly now, not anymore in an `Arc`. Instead `Source::Binary` now stores an `Arc` of the data. ## [0.6.2] - 2021-09-04 ### Fixed - Fix compilation without the `fs` feature. ## [0.6.1] - 2021-09-04 ### Changed - Split the `fs` build feature into `fs` and `memmap`. [@neinseg](https://github.com/neinseg) ## [0.6.0] - 2021-08-21 ### Added - Search in `$HOME/.fonts` on Linux. [@Linus789](https://github.com/Linus789) ### Changed - Generic font families are preset by default instead of being set to `None`. ## [0.5.4] - 2021-05-25 ### Added - Implement `Eq`, `Hash` for `Query`, `Family`, `Weight` and `Style`. [@dhardy](https://github.com/dhardy) ### Changed - Update `ttf-parser` ## [0.5.3] - 2021-05-19 ### Changed - Update `ttf-parser` ## [0.5.2] - 2021-05-19 ### Changed - Update `memmap2` - Add additional search dir for macOS. ## [0.5.1] - 2020-12-20 ### Fixed - Compilation on Windows. ## [0.5.0] - 2020-12-20 ### Added - `FaceInfo::post_script_name` - `FaceInfo::monospaced` - `Database::load_system_fonts` ## [0.4.0] - 2020-12-06 ### Changed - Use a simple `u32` for ID instead of UUID. ## [0.3.0] - 2020-12-05 ### Changed - `ttf-parser` updated. ## [0.2.0] - 2020-07-21 ### Changed - `ttf-parser` updated. ### Fixed - Stretch processing. `ttf-parser` was incorrectly parsing this property. [Unreleased]: https://github.com/RazrFalcon/fontdb/compare/v0.22.0...HEAD [0.22.0]: https://github.com/RazrFalcon/fontdb/compare/v0.21.0...v0.22.0 [0.21.0]: https://github.com/RazrFalcon/fontdb/compare/v0.20.0...v0.21.0 [0.20.0]: https://github.com/RazrFalcon/fontdb/compare/v0.19.0...v0.20.0 [0.19.0]: https://github.com/RazrFalcon/fontdb/compare/v0.18.0...v0.19.0 [0.18.0]: https://github.com/RazrFalcon/fontdb/compare/v0.17.0...v0.18.0 [0.17.0]: https://github.com/RazrFalcon/fontdb/compare/v0.16.2...v0.17.0 [0.16.2]: https://github.com/RazrFalcon/fontdb/compare/v0.16.1...v0.16.2 [0.16.1]: https://github.com/RazrFalcon/fontdb/compare/v0.16.0...v0.16.1 [0.16.0]: https://github.com/RazrFalcon/fontdb/compare/v0.15.0...v0.16.0 [0.15.0]: https://github.com/RazrFalcon/fontdb/compare/v0.14.1...v0.15.0 [0.14.1]: https://github.com/RazrFalcon/fontdb/compare/v0.14.0...v0.14.1 [0.14.0]: https://github.com/RazrFalcon/fontdb/compare/v0.13.1...v0.14.0 [0.13.1]: https://github.com/RazrFalcon/fontdb/compare/v0.13.0...v0.13.1 [0.13.0]: https://github.com/RazrFalcon/fontdb/compare/v0.12.0...v0.13.0 [0.12.0]: https://github.com/RazrFalcon/fontdb/compare/v0.11.2...v0.12.0 [0.11.2]: https://github.com/RazrFalcon/fontdb/compare/v0.11.1...v0.11.2 [0.11.1]: https://github.com/RazrFalcon/fontdb/compare/v0.11.0...v0.11.1 [0.11.0]: https://github.com/RazrFalcon/fontdb/compare/v0.10.0...v0.11.0 [0.10.0]: https://github.com/RazrFalcon/fontdb/compare/v0.9.3...v0.10.0 [0.9.3]: https://github.com/RazrFalcon/fontdb/compare/v0.9.2...v0.9.3 [0.9.2]: https://github.com/RazrFalcon/fontdb/compare/v0.9.1...v0.9.2 [0.9.1]: https://github.com/RazrFalcon/fontdb/compare/v0.9.0...v0.9.1 [0.9.0]: https://github.com/RazrFalcon/fontdb/compare/v0.8.0...v0.9.0 [0.8.0]: https://github.com/RazrFalcon/fontdb/compare/v0.7.0...v0.8.0 [0.7.0]: https://github.com/RazrFalcon/fontdb/compare/v0.6.2...v0.7.0 [0.6.2]: https://github.com/RazrFalcon/fontdb/compare/v0.6.1...v0.6.2 [0.6.1]: https://github.com/RazrFalcon/fontdb/compare/v0.6.0...v0.6.1 [0.6.0]: https://github.com/RazrFalcon/fontdb/compare/v0.5.4...v0.6.0 [0.5.4]: https://github.com/RazrFalcon/fontdb/compare/v0.5.3...v0.5.4 [0.5.3]: https://github.com/RazrFalcon/fontdb/compare/v0.5.2...v0.5.3 [0.5.2]: https://github.com/RazrFalcon/fontdb/compare/v0.5.1...v0.5.2 [0.5.1]: https://github.com/RazrFalcon/fontdb/compare/v0.5.0...v0.5.1 [0.5.0]: https://github.com/RazrFalcon/fontdb/compare/v0.4.0...v0.5.0 [0.4.0]: https://github.com/RazrFalcon/fontdb/compare/v0.3.0...v0.4.0 [0.3.0]: https://github.com/RazrFalcon/fontdb/compare/v0.2.0...v0.3.0 [0.2.0]: https://github.com/RazrFalcon/fontdb/compare/v0.1.0...v0.2.0 fontdb-0.22.0/Cargo.lock0000644000000056740000000000100103600ustar # This file is automatically @generated by Cargo. # It is not intended for manual editing. version = 3 [[package]] name = "core_maths" version = "0.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e3b02505ccb8c50b0aa21ace0fc08c3e53adebd4e58caa18a36152803c7709a3" dependencies = [ "libm", ] [[package]] name = "env_logger" version = "0.10.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "4cd405aab171cb85d6735e5c8d9db038c17d3ca007a4d2c25f337935c3d90580" dependencies = [ "log", ] [[package]] name = "fontconfig-parser" version = "0.5.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "6a595cb550439a117696039dfc69830492058211b771a2a165379f2a1a53d84d" dependencies = [ "roxmltree", ] [[package]] name = "fontdb" version = "0.22.0" dependencies = [ "env_logger", "fontconfig-parser", "log", "memmap2", "slotmap", "tinyvec", "ttf-parser", ] [[package]] name = "libc" version = "0.2.155" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "97b3888a4aecf77e811145cadf6eef5901f4782c53886191b2f693f24761847c" [[package]] name = "libm" version = "0.2.8" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "4ec2a862134d2a7d32d7983ddcdd1c4923530833c9f2ea1a44fc5fa473989058" [[package]] name = "log" version = "0.4.21" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "90ed8c1e510134f979dbc4f070f87d4313098b704861a105fe34231c70a3901c" [[package]] name = "memmap2" version = "0.9.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "fe751422e4a8caa417e13c3ea66452215d7d63e19e604f4980461212f3ae1322" dependencies = [ "libc", ] [[package]] name = "roxmltree" version = "0.19.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3cd14fd5e3b777a7422cca79358c57a8f6e3a703d9ac187448d0daf220c2407f" [[package]] name = "slotmap" version = "1.0.7" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "dbff4acf519f630b3a3ddcfaea6c06b42174d9a44bc70c620e9ed1649d58b82a" dependencies = [ "version_check", ] [[package]] name = "tinyvec" version = "1.6.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "87cc5ceb3875bb20c2890005a4e226a4651264a5c75edb2421b52861a0a0cb50" dependencies = [ "tinyvec_macros", ] [[package]] name = "tinyvec_macros" version = "0.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1f3ccbac311fea05f86f61904b462b55fb3df8837a366dfc601a0161d0532f20" [[package]] name = "ttf-parser" version = "0.24.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8686b91785aff82828ed725225925b33b4fde44c4bb15876e5f7c832724c420a" dependencies = [ "core_maths", ] [[package]] name = "version_check" version = "0.9.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "49874b5167b65d7193b8aba1567f5c7d93d001cafc34600cee003eda787e483f" fontdb-0.22.0/Cargo.toml0000644000000033640000000000100103750ustar # 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 = "2018" rust-version = "1.60" name = "fontdb" version = "0.22.0" authors = ["Yevhenii Reizner "] description = "A simple, in-memory font database with CSS-like queries." documentation = "https://docs.rs/fontdb/" readme = "README.md" keywords = [ "font", "db", "css", "truetype", "ttf", ] categories = ["text-processing"] license = "MIT" repository = "https://github.com/RazrFalcon/fontdb" [dependencies.log] version = "0.4" [dependencies.memmap2] version = "0.9" optional = true [dependencies.slotmap] version = "1.0.6" default-features = false [dependencies.tinyvec] version = "1.6.0" features = ["alloc"] [dependencies.ttf-parser] version = "0.24" features = [ "opentype-layout", "apple-layout", "variable-fonts", "glyph-names", "no-std-float", ] default-features = false [dev-dependencies.env_logger] version = "0.10" default-features = false [features] default = [ "std", "fs", "memmap", "fontconfig", ] fontconfig = [ "fontconfig-parser", "fs", ] fs = ["std"] memmap = [ "fs", "memmap2", ] std = ["ttf-parser/std"] [target."cfg(all(unix, not(any(target_os = \"macos\", target_os = \"android\"))))".dependencies.fontconfig-parser] version = "0.5" optional = true default-features = false fontdb-0.22.0/Cargo.toml.orig000064400000000000000000000026131046102023000140520ustar 00000000000000[package] name = "fontdb" version = "0.22.0" authors = ["Yevhenii Reizner "] edition = "2018" description = "A simple, in-memory font database with CSS-like queries." documentation = "https://docs.rs/fontdb/" readme = "README.md" repository = "https://github.com/RazrFalcon/fontdb" license = "MIT" keywords = ["font", "db", "css", "truetype", "ttf"] categories = ["text-processing"] rust-version = "1.60" [dependencies] log = "0.4" memmap2 = { version = "0.9", optional = true } slotmap = { version = "1.0.6", default-features = false } tinyvec = { version = "1.6.0", features = ["alloc"] } [dependencies.ttf-parser] version = "0.24" default-features = false features = ["opentype-layout", "apple-layout", "variable-fonts", "glyph-names", "no-std-float"] [target.'cfg(all(unix, not(any(target_os = "macos", target_os = "android"))))'.dependencies] fontconfig-parser = { version = "0.5", optional = true, default-features = false } [dev-dependencies] env_logger = { version = "0.10", default-features = false } [features] default = ["std", "fs", "memmap", "fontconfig"] std = ["ttf-parser/std"] # Allows local filesystem interactions. fs = ["std"] # Allows font files memory mapping, greatly improves performance. memmap = ["fs", "memmap2"] # Enables minimal fontconfig support on Linux. # Must be enabled for NixOS, otherwise no fonts will be loaded. fontconfig = ["fontconfig-parser", "fs"] fontdb-0.22.0/LICENSE000064400000000000000000000020731046102023000121700ustar 00000000000000The MIT License (MIT) Copyright (c) 2020 Yevhenii Reizner 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. fontdb-0.22.0/README.md000064400000000000000000000045161046102023000124460ustar 00000000000000# fontdb ![Build Status](https://github.com/RazrFalcon/fontdb/workflows/Rust/badge.svg) [![Crates.io](https://img.shields.io/crates/v/fontdb.svg)](https://crates.io/crates/fontdb) [![Documentation](https://docs.rs/fontdb/badge.svg)](https://docs.rs/fontdb) [![Rust 1.60+](https://img.shields.io/badge/rust-1.60+-orange.svg)](https://www.rust-lang.org) `fontdb` is a simple, in-memory font database with CSS-like queries. ## Features - The database can load fonts from files, directories and raw data (`Vec`). - The database can match a font using CSS-like queries. See `Database::query`. - The database can try to load system fonts. Currently, this is implemented by scanning predefined directories. The library does not interact with the system API. - Provides a unique ID for each font face. ## Non-goals - Advanced font properties querying.
The database provides only storage and matching capabilities. For font properties querying you can use [ttf-parser]. - A font fallback mechanism.
This library can be used to implement a font fallback mechanism, but it doesn't implement one. - Application's global database.
The database doesn't use `static`, therefore it's up to the caller where it should be stored. - Font types support other than TrueType. ## Font vs Face A font is a collection of font faces. Therefore, a font face is a subset of a font. A simple font (\*.ttf/\*.otf) usually contains a single font face, but a font collection (\*.ttc) can contain multiple font faces. `fontdb` stores and matches font faces, not fonts. Therefore, after loading a font collection with 5 faces (for example), the database will be populated with 5 `FaceInfo` objects, all of which will be pointing to the same file or binary data. ## Performance The database performance is largely limited by the storage itself. We are using [ttf-parser], so the parsing should not be a bottleneck. For example, on Mac Book Pro 14 with M1 Pro, it takes just ~24ms to load 1361 font faces. ## Safety The library relies on memory-mapped files, which is inherently unsafe. But since we do not keep the files open it should be perfectly safe. If you would like to use a persistent memory mapping of the font files, then you can use the unsafe `Database::make_shared_face_data` function. ## License MIT [ttf-parser]: https://github.com/RazrFalcon/ttf-parser fontdb-0.22.0/examples/find-system-font.rs000064400000000000000000000024501046102023000165540ustar 00000000000000fn main() { std::env::set_var("RUST_LOG", "fontdb=trace"); env_logger::init(); let mut db = fontdb::Database::new(); let now = std::time::Instant::now(); db.load_system_fonts(); db.set_serif_family("Times New Roman"); db.set_sans_serif_family("Arial"); db.set_cursive_family("Comic Sans MS"); db.set_fantasy_family("Impact"); db.set_monospace_family("Courier New"); println!( "Loaded {} font faces in {}ms.", db.len(), now.elapsed().as_millis() ); const FAMILY_NAME: &str = "Times New Roman"; let query = fontdb::Query { families: &[fontdb::Family::Name(FAMILY_NAME), fontdb::Family::SansSerif], weight: fontdb::Weight::BOLD, ..fontdb::Query::default() }; let now = std::time::Instant::now(); match db.query(&query) { Some(id) => { let (src, index) = db.face_source(id).unwrap(); if let fontdb::Source::File(ref path) = &src { println!( "Font '{}':{} found in {}ms.", path.display(), index, now.elapsed().as_micros() as f64 / 1000.0 ); } } None => { println!("Error: '{}' not found.", FAMILY_NAME); } } } fontdb-0.22.0/src/lib.rs000064400000000000000000001360761046102023000131010ustar 00000000000000/*! `fontdb` is a simple, in-memory font database with CSS-like queries. # Features - The database can load fonts from files, directories and raw data (`Vec`). - The database can match a font using CSS-like queries. See `Database::query`. - The database can try to load system fonts. Currently, this is implemented by scanning predefined directories. The library does not interact with the system API. - Provides a unique ID for each font face. # Non-goals - Advanced font properties querying.
The database provides only storage and matching capabilities. For font properties querying you can use [ttf-parser]. - A font fallback mechanism.
This library can be used to implement a font fallback mechanism, but it doesn't implement one. - Application's global database.
The database doesn't use `static`, therefore it's up to the caller where it should be stored. - Font types support other than TrueType. # Font vs Face A font is a collection of font faces. Therefore, a font face is a subset of a font. A simple font (\*.ttf/\*.otf) usually contains a single font face, but a font collection (\*.ttc) can contain multiple font faces. `fontdb` stores and matches font faces, not fonts. Therefore, after loading a font collection with 5 faces (for example), the database will be populated with 5 `FaceInfo` objects, all of which will be pointing to the same file or binary data. # Performance The database performance is largely limited by the storage itself. We are using [ttf-parser], so the parsing should not be a bottleneck. On my machine with Samsung SSD 860 and Gentoo Linux, it takes ~20ms to load 1906 font faces (most of them are from Google Noto collection) with a hot disk cache and ~860ms with a cold one. On Mac Mini M1 it takes just 9ms to load 898 fonts. # Safety The library relies on memory-mapped files, which is inherently unsafe. But since we do not keep the files open it should be perfectly safe. If you would like to use a persistent memory mapping of the font files, then you can use the unsafe [`Database::make_shared_face_data`] function. [ttf-parser]: https://github.com/RazrFalcon/ttf-parser */ #![cfg_attr(not(feature = "std"), no_std)] #![warn(missing_docs)] #![warn(missing_debug_implementations)] #![warn(missing_copy_implementations)] extern crate alloc; #[cfg(not(feature = "std"))] use alloc::{ string::{String, ToString}, vec::Vec, }; pub use ttf_parser::Language; pub use ttf_parser::Width as Stretch; use slotmap::SlotMap; use tinyvec::TinyVec; /// A unique per database face ID. /// /// Since `Database` is not global/unique, we cannot guarantee that a specific ID /// is actually from the same db instance. This is up to the caller. /// /// ID overflow will cause a panic, but it's highly unlikely that someone would /// load more than 4 billion font faces. /// /// Because the internal representation of ID is private, The `Display` trait /// implementation for this type only promise that unequal IDs will be displayed /// as different strings, but does not make any guarantees about format or /// content of the strings. /// /// [`KeyData`]: https://docs.rs/slotmap/latest/slotmap/struct.KeyData.html #[derive(Clone, Copy, Eq, Hash, Ord, PartialEq, PartialOrd, Debug, Default)] pub struct ID(InnerId); slotmap::new_key_type! { /// Internal ID type. struct InnerId; } impl ID { /// Creates a dummy ID. /// /// Should be used in tandem with [`Database::push_face_info`]. #[inline] pub fn dummy() -> Self { Self(InnerId::from(slotmap::KeyData::from_ffi(core::u64::MAX))) } } impl core::fmt::Display for ID { fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result { write!(f, "{}", (self.0).0.as_ffi()) } } /// A list of possible font loading errors. #[derive(Debug)] enum LoadError { /// A malformed font. /// /// Typically means that [ttf-parser](https://github.com/RazrFalcon/ttf-parser) /// wasn't able to parse it. MalformedFont, /// A valid TrueType font without a valid *Family Name*. UnnamedFont, /// A file IO related error. #[cfg(feature = "std")] IoError(std::io::Error), } #[cfg(feature = "std")] impl From for LoadError { #[inline] fn from(e: std::io::Error) -> Self { LoadError::IoError(e) } } impl core::fmt::Display for LoadError { fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result { match self { LoadError::MalformedFont => write!(f, "malformed font"), LoadError::UnnamedFont => write!(f, "font doesn't have a family name"), #[cfg(feature = "std")] LoadError::IoError(ref e) => write!(f, "{}", e), } } } /// A font database. #[derive(Clone, Debug)] pub struct Database { faces: SlotMap, family_serif: String, family_sans_serif: String, family_cursive: String, family_fantasy: String, family_monospace: String, } impl Default for Database { fn default() -> Self { Self::new() } } impl Database { /// Create a new, empty `Database`. /// /// Generic font families would be set to: /// /// - `serif` - Times New Roman /// - `sans-serif` - Arial /// - `cursive` - Comic Sans MS /// - `fantasy` - Impact (Papyrus on macOS) /// - `monospace` - Courier New #[inline] pub fn new() -> Self { Database { faces: SlotMap::with_key(), family_serif: "Times New Roman".to_string(), family_sans_serif: "Arial".to_string(), family_cursive: "Comic Sans MS".to_string(), #[cfg(not(target_os = "macos"))] family_fantasy: "Impact".to_string(), #[cfg(target_os = "macos")] family_fantasy: "Papyrus".to_string(), family_monospace: "Courier New".to_string(), } } /// Loads a font data into the `Database`. /// /// Will load all font faces in case of a font collection. pub fn load_font_data(&mut self, data: Vec) { self.load_font_source(Source::Binary(alloc::sync::Arc::new(data))); } /// Loads a font from the given source into the `Database` and returns /// the ID of the loaded font. /// /// Will load all font faces in case of a font collection. pub fn load_font_source(&mut self, source: Source) -> TinyVec<[ID; 8]> { let ids = source.with_data(|data| { let n = ttf_parser::fonts_in_collection(data).unwrap_or(1); let mut ids = TinyVec::with_capacity(n as usize); for index in 0..n { match parse_face_info(source.clone(), data, index) { Ok(mut info) => { let id = self.faces.insert_with_key(|k| { info.id = ID(k); info }); ids.push(ID(id)); } Err(e) => log::warn!( "Failed to load a font face {} from source cause {}.", index, e ), } } ids }); ids.unwrap_or_default() } /// Backend function used by load_font_file to load font files. #[cfg(feature = "fs")] fn load_fonts_from_file(&mut self, path: &std::path::Path, data: &[u8]) { let source = Source::File(path.into()); let n = ttf_parser::fonts_in_collection(data).unwrap_or(1); for index in 0..n { match parse_face_info(source.clone(), data, index) { Ok(info) => { self.push_face_info(info); } Err(e) => { log::warn!( "Failed to load a font face {} from '{}' cause {}.", index, path.display(), e ) } } } } /// Loads a font file into the `Database`. /// /// Will load all font faces in case of a font collection. #[cfg(all(feature = "fs", feature = "memmap"))] pub fn load_font_file>( &mut self, path: P, ) -> Result<(), std::io::Error> { self.load_font_file_impl(path.as_ref()) } // A non-generic version. #[cfg(all(feature = "fs", feature = "memmap"))] fn load_font_file_impl(&mut self, path: &std::path::Path) -> Result<(), std::io::Error> { let file = std::fs::File::open(path)?; let data: &[u8] = unsafe { &memmap2::MmapOptions::new().map(&file)? }; self.load_fonts_from_file(path, data); Ok(()) } /// Loads a font file into the `Database`. /// /// Will load all font faces in case of a font collection. #[cfg(all(feature = "fs", not(feature = "memmap")))] pub fn load_font_file>( &mut self, path: P, ) -> Result<(), std::io::Error> { self.load_font_file_impl(path.as_ref()) } // A non-generic version. #[cfg(all(feature = "fs", not(feature = "memmap")))] fn load_font_file_impl(&mut self, path: &std::path::Path) -> Result<(), std::io::Error> { let data = std::fs::read(path)?; self.load_fonts_from_file(path, &data); Ok(()) } /// Loads font files from the selected directory into the `Database`. /// /// This method will scan directories recursively. /// /// Will load `ttf`, `otf`, `ttc` and `otc` fonts. /// /// Unlike other `load_*` methods, this one doesn't return an error. /// It will simply skip malformed fonts and will print a warning into the log for each of them. #[cfg(feature = "fs")] pub fn load_fonts_dir>(&mut self, dir: P) { self.load_fonts_dir_impl(dir.as_ref(), &mut Default::default()) } #[cfg(feature = "fs")] fn canonicalize( &self, path: std::path::PathBuf, entry: std::fs::DirEntry, seen: &mut std::collections::HashSet, ) -> Option<(std::path::PathBuf, std::fs::FileType)> { let file_type = entry.file_type().ok()?; if !file_type.is_symlink() { if !seen.is_empty() { if seen.contains(&path) { return None; } seen.insert(path.clone()); } return Some((path, file_type)); } if seen.is_empty() && file_type.is_dir() { seen.reserve(8192 / std::mem::size_of::()); for (_, info) in self.faces.iter() { let path = match &info.source { Source::Binary(_) => continue, Source::File(path) => path.to_path_buf(), #[cfg(feature = "memmap")] Source::SharedFile(path, _) => path.to_path_buf(), }; seen.insert(path); } } let stat = std::fs::metadata(&path).ok()?; if stat.is_symlink() { return None; } let canon = std::fs::canonicalize(path).ok()?; if seen.contains(&canon) { return None; } seen.insert(canon.clone()); Some((canon, stat.file_type())) } // A non-generic version. #[cfg(feature = "fs")] fn load_fonts_dir_impl( &mut self, dir: &std::path::Path, seen: &mut std::collections::HashSet, ) { let fonts_dir = match std::fs::read_dir(dir) { Ok(dir) => dir, Err(_) => return, }; for entry in fonts_dir.flatten() { let (path, file_type) = match self.canonicalize(entry.path(), entry, seen) { Some(v) => v, None => continue, }; if file_type.is_file() { match path.extension().and_then(|e| e.to_str()) { #[rustfmt::skip] // keep extensions match as is Some("ttf") | Some("ttc") | Some("TTF") | Some("TTC") | Some("otf") | Some("otc") | Some("OTF") | Some("OTC") => { if let Err(e) = self.load_font_file(&path) { log::warn!("Failed to load '{}' cause {}.", path.display(), e); } }, _ => {} } } else if file_type.is_dir() { self.load_fonts_dir_impl(&path, seen); } } } /// Attempts to load system fonts. /// /// Supports Windows, Linux and macOS. /// /// System fonts loading is a surprisingly complicated task, /// mostly unsolvable without interacting with system libraries. /// And since `fontdb` tries to be small and portable, this method /// will simply scan some predefined directories. /// Which means that fonts that are not in those directories must /// be added manually. #[cfg(feature = "fs")] pub fn load_system_fonts(&mut self) { #[cfg(target_os = "windows")] { let mut seen = Default::default(); if let Some(ref system_root) = std::env::var_os("SYSTEMROOT") { let system_root_path = std::path::Path::new(system_root); self.load_fonts_dir_impl(&system_root_path.join("Fonts"), &mut seen); } else { self.load_fonts_dir_impl("C:\\Windows\\Fonts\\".as_ref(), &mut seen); } if let Ok(ref home) = std::env::var("USERPROFILE") { let home_path = std::path::Path::new(home); self.load_fonts_dir_impl( &home_path.join("AppData\\Local\\Microsoft\\Windows\\Fonts"), &mut seen, ); self.load_fonts_dir_impl( &home_path.join("AppData\\Roaming\\Microsoft\\Windows\\Fonts"), &mut seen, ); } } #[cfg(target_os = "macos")] { let mut seen = Default::default(); self.load_fonts_dir_impl("/Library/Fonts".as_ref(), &mut seen); self.load_fonts_dir_impl("/System/Library/Fonts".as_ref(), &mut seen); // Downloadable fonts, location varies on major macOS releases if let Ok(dir) = std::fs::read_dir("/System/Library/AssetsV2") { for entry in dir { let entry = match entry { Ok(entry) => entry, Err(_) => continue, }; if entry .file_name() .to_string_lossy() .starts_with("com_apple_MobileAsset_Font") { self.load_fonts_dir_impl(&entry.path(), &mut seen); } } } self.load_fonts_dir_impl("/Network/Library/Fonts".as_ref(), &mut seen); if let Ok(ref home) = std::env::var("HOME") { let home_path = std::path::Path::new(home); self.load_fonts_dir_impl(&home_path.join("Library/Fonts"), &mut seen); } } // Redox OS. #[cfg(target_os = "redox")] { let mut seen = Default::default(); self.load_fonts_dir_impl("/ui/fonts".as_ref(), &mut seen); } // Linux. #[cfg(all(unix, not(any(target_os = "macos", target_os = "android"))))] { #[cfg(feature = "fontconfig")] { if !self.load_fontconfig() { log::warn!("Fallback to loading from known font dir paths."); self.load_no_fontconfig(); } } #[cfg(not(feature = "fontconfig"))] { self.load_no_fontconfig(); } } } // Linux. #[cfg(all( unix, feature = "fs", not(any(target_os = "macos", target_os = "android")) ))] fn load_no_fontconfig(&mut self) { let mut seen = Default::default(); self.load_fonts_dir_impl("/usr/share/fonts/".as_ref(), &mut seen); self.load_fonts_dir_impl("/usr/local/share/fonts/".as_ref(), &mut seen); if let Ok(ref home) = std::env::var("HOME") { let home_path = std::path::Path::new(home); self.load_fonts_dir_impl(&home_path.join(".fonts"), &mut seen); self.load_fonts_dir_impl(&home_path.join(".local/share/fonts"), &mut seen); } } // Linux. #[cfg(all( unix, feature = "fontconfig", not(any(target_os = "macos", target_os = "android")) ))] fn load_fontconfig(&mut self) -> bool { use std::path::Path; let mut fontconfig = fontconfig_parser::FontConfig::default(); let home = std::env::var("HOME"); if let Ok(ref config_file) = std::env::var("FONTCONFIG_FILE") { let _ = fontconfig.merge_config(Path::new(config_file)); } else { let xdg_config_home = if let Ok(val) = std::env::var("XDG_CONFIG_HOME") { Some(val.into()) } else if let Ok(ref home) = home { // according to https://specifications.freedesktop.org/basedir-spec/basedir-spec-latest.html // $XDG_CONFIG_HOME should default to $HOME/.config if not set Some(Path::new(home).join(".config")) } else { None }; let read_global = match xdg_config_home { Some(p) => fontconfig .merge_config(&p.join("fontconfig/fonts.conf")) .is_err(), None => true, }; if read_global { let _ = fontconfig.merge_config(Path::new("/etc/fonts/local.conf")); } let _ = fontconfig.merge_config(Path::new("/etc/fonts/fonts.conf")); } for fontconfig_parser::Alias { alias, default, prefer, accept, } in fontconfig.aliases { let name = prefer .get(0) .or_else(|| accept.get(0)) .or_else(|| default.get(0)); if let Some(name) = name { match alias.to_lowercase().as_str() { "serif" => self.set_serif_family(name), "sans-serif" => self.set_sans_serif_family(name), "sans serif" => self.set_sans_serif_family(name), "monospace" => self.set_monospace_family(name), "cursive" => self.set_cursive_family(name), "fantasy" => self.set_fantasy_family(name), _ => {} } } } if fontconfig.dirs.is_empty() { return false; } let mut seen = Default::default(); for dir in fontconfig.dirs { let path = if dir.path.starts_with("~") { if let Ok(ref home) = home { Path::new(home).join(dir.path.strip_prefix("~").unwrap()) } else { continue; } } else { dir.path }; self.load_fonts_dir_impl(&path, &mut seen); } true } /// Pushes a user-provided `FaceInfo` to the database. /// /// In some cases, a caller might want to ignore the font's metadata and provide their own. /// This method doesn't parse the `source` font. /// /// The `id` field should be set to [`ID::dummy()`] and will be then overwritten by this method. pub fn push_face_info(&mut self, mut info: FaceInfo) -> ID { ID(self.faces.insert_with_key(|k| { info.id = ID(k); info })) } /// Removes a font face by `id` from the database. /// /// Returns `false` while attempting to remove a non-existing font face. /// /// Useful when you want to ignore some specific font face(s) /// after loading a large directory with fonts. /// Or a specific face from a font. pub fn remove_face(&mut self, id: ID) { self.faces.remove(id.0); } /// Returns `true` if the `Database` contains no font faces. #[inline] pub fn is_empty(&self) -> bool { self.faces.is_empty() } /// Returns the number of font faces in the `Database`. /// /// Note that `Database` stores font faces, not fonts. /// For example, if a caller will try to load a font collection (`*.ttc`) that contains 5 faces, /// then the `Database` will load 5 font faces and this method will return 5, not 1. #[inline] pub fn len(&self) -> usize { self.faces.len() } /// Sets the family that will be used by `Family::Serif`. pub fn set_serif_family>(&mut self, family: S) { self.family_serif = family.into(); } /// Sets the family that will be used by `Family::SansSerif`. pub fn set_sans_serif_family>(&mut self, family: S) { self.family_sans_serif = family.into(); } /// Sets the family that will be used by `Family::Cursive`. pub fn set_cursive_family>(&mut self, family: S) { self.family_cursive = family.into(); } /// Sets the family that will be used by `Family::Fantasy`. pub fn set_fantasy_family>(&mut self, family: S) { self.family_fantasy = family.into(); } /// Sets the family that will be used by `Family::Monospace`. pub fn set_monospace_family>(&mut self, family: S) { self.family_monospace = family.into(); } /// Returns the generic family name or the `Family::Name` itself. /// /// Generic family names should be set via `Database::set_*_family` methods. pub fn family_name<'a>(&'a self, family: &'a Family) -> &'a str { match family { Family::Name(name) => name, Family::Serif => self.family_serif.as_str(), Family::SansSerif => self.family_sans_serif.as_str(), Family::Cursive => self.family_cursive.as_str(), Family::Fantasy => self.family_fantasy.as_str(), Family::Monospace => self.family_monospace.as_str(), } } /// Performs a CSS-like query and returns the best matched font face. pub fn query(&self, query: &Query) -> Option { for family in query.families { let name = self.family_name(family); let candidates: Vec<_> = self .faces .iter() .filter(|(_, face)| face.families.iter().any(|family| family.0 == name)) .map(|(_, info)| info) .collect(); if !candidates.is_empty() { if let Some(index) = find_best_match(&candidates, query) { return Some(candidates[index].id); } } } None } /// Returns an iterator over the internal storage. /// /// This can be used for manual font matching. #[inline] pub fn faces(&self) -> impl Iterator + '_ { self.faces.iter().map(|(_, info)| info) } /// Selects a `FaceInfo` by `id`. /// /// Returns `None` if a face with such ID was already removed, /// or this ID belong to the other `Database`. pub fn face(&self, id: ID) -> Option<&FaceInfo> { self.faces.get(id.0) } /// Returns font face storage and the face index by `ID`. pub fn face_source(&self, id: ID) -> Option<(Source, u32)> { self.face(id).map(|info| (info.source.clone(), info.index)) } /// Executes a closure with a font's data. /// /// We can't return a reference to a font binary data because of lifetimes. /// So instead, you can use this method to process font's data. /// /// The closure accepts raw font data and font face index. /// /// In case of `Source::File`, the font file will be memory mapped. /// /// Returns `None` when font file loading failed. /// /// # Example /// /// ```ignore /// let is_variable = db.with_face_data(id, |font_data, face_index| { /// let font = ttf_parser::Face::from_slice(font_data, face_index).unwrap(); /// font.is_variable() /// })?; /// ``` pub fn with_face_data(&self, id: ID, p: P) -> Option where P: FnOnce(&[u8], u32) -> T, { let (src, face_index) = self.face_source(id)?; src.with_data(|data| p(data, face_index)) } /// Makes the font data that backs the specified face id shared so that the application can /// hold a reference to it. /// /// # Safety /// /// If the face originates from a file from disk, then the file is mapped from disk. This is unsafe as /// another process may make changes to the file on disk, which may become visible in this process' /// mapping and possibly cause crashes. /// /// If the underlying font provides multiple faces, then all faces are updated to participate in /// the data sharing. If the face was previously marked for data sharing, then this function will /// return a clone of the existing reference. #[cfg(all(feature = "fs", feature = "memmap"))] pub unsafe fn make_shared_face_data( &mut self, id: ID, ) -> Option<(std::sync::Arc + Send + Sync>, u32)> { let face_info = self.faces.get(id.0)?; let face_index = face_info.index; let old_source = face_info.source.clone(); let (path, shared_data) = match &old_source { Source::Binary(data) => { return Some((data.clone(), face_index)); } Source::File(ref path) => { let file = std::fs::File::open(path).ok()?; let shared_data = std::sync::Arc::new(memmap2::MmapOptions::new().map(&file).ok()?) as std::sync::Arc + Send + Sync>; (path.clone(), shared_data) } Source::SharedFile(_, data) => { return Some((data.clone(), face_index)); } }; let shared_source = Source::SharedFile(path.clone(), shared_data.clone()); self.faces.iter_mut().for_each(|(_, face)| { if matches!(&face.source, Source::File(old_path) if old_path == &path) { face.source = shared_source.clone(); } }); Some((shared_data, face_index)) } /// Transfers ownership of shared font data back to the font database. This is the reverse operation /// of [`Self::make_shared_face_data`]. If the font data belonging to the specified face is mapped /// from a file on disk, then that mapping is closed and the data becomes private to the process again. #[cfg(all(feature = "fs", feature = "memmap"))] pub fn make_face_data_unshared(&mut self, id: ID) { let face_info = match self.faces.get(id.0) { Some(face_info) => face_info, None => return, }; let old_source = face_info.source.clone(); let shared_path = match old_source { #[cfg(all(feature = "fs", feature = "memmap"))] Source::SharedFile(path, _) => path, _ => return, }; let new_source = Source::File(shared_path.clone()); self.faces.iter_mut().for_each(|(_, face)| { if matches!(&face.source, Source::SharedFile(path, ..) if path == &shared_path) { face.source = new_source.clone(); } }); } } /// A single font face info. /// /// A font can have multiple faces. /// /// A single item of the `Database`. #[derive(Clone, Debug)] pub struct FaceInfo { /// An unique ID. pub id: ID, /// A font source. /// /// Note that multiple `FaceInfo` objects can reference the same data in case of /// font collections, which means that they'll use the same Source. pub source: Source, /// A face index in the `source`. pub index: u32, /// A list of family names. /// /// Contains pairs of Name + Language. Where the first family is always English US, /// unless it's missing from the font. /// /// Corresponds to a *Typographic Family* (ID 16) or a *Font Family* (ID 1) [name ID] /// in a TrueType font. /// /// This is not an *Extended Typographic Family* or a *Full Name*. /// Meaning it will contain _Arial_ and not _Arial Bold_. /// /// [name ID]: https://docs.microsoft.com/en-us/typography/opentype/spec/name#name-ids pub families: Vec<(String, Language)>, /// A PostScript name. /// /// Corresponds to a *PostScript name* (6) [name ID] in a TrueType font. /// /// [name ID]: https://docs.microsoft.com/en-us/typography/opentype/spec/name#name-ids pub post_script_name: String, /// A font face style. pub style: Style, /// A font face weight. pub weight: Weight, /// A font face stretch. pub stretch: Stretch, /// Indicates that the font face is monospaced. pub monospaced: bool, } /// A font source. /// /// Either a raw binary data or a file path. /// /// Stores the whole font and not just a single face. #[derive(Clone)] pub enum Source { /// A font's raw data, typically backed by a Vec. Binary(alloc::sync::Arc + Sync + Send>), /// A font's path. #[cfg(feature = "fs")] File(std::path::PathBuf), /// A font's raw data originating from a shared file mapping. #[cfg(all(feature = "fs", feature = "memmap"))] SharedFile( std::path::PathBuf, std::sync::Arc + Sync + Send>, ), } impl core::fmt::Debug for Source { fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result { match self { Self::Binary(arg0) => f .debug_tuple("SharedBinary") .field(&arg0.as_ref().as_ref()) .finish(), #[cfg(feature = "fs")] Self::File(arg0) => f.debug_tuple("File").field(arg0).finish(), #[cfg(all(feature = "fs", feature = "memmap"))] Self::SharedFile(arg0, arg1) => f .debug_tuple("SharedFile") .field(arg0) .field(&arg1.as_ref().as_ref()) .finish(), } } } impl Source { fn with_data(&self, p: P) -> Option where P: FnOnce(&[u8]) -> T, { match &self { #[cfg(all(feature = "fs", not(feature = "memmap")))] Source::File(ref path) => { let data = std::fs::read(path).ok()?; Some(p(&data)) } #[cfg(all(feature = "fs", feature = "memmap"))] Source::File(ref path) => { let file = std::fs::File::open(path).ok()?; let data = unsafe { &memmap2::MmapOptions::new().map(&file).ok()? }; Some(p(data)) } Source::Binary(ref data) => Some(p(data.as_ref().as_ref())), #[cfg(all(feature = "fs", feature = "memmap"))] Source::SharedFile(_, ref data) => Some(p(data.as_ref().as_ref())), } } } /// A database query. /// /// Mainly used by `Database::query()`. #[derive(Clone, Copy, Default, Debug, Eq, PartialEq, Hash)] pub struct Query<'a> { /// A prioritized list of font family names or generic family names. /// /// [font-family](https://www.w3.org/TR/2018/REC-css-fonts-3-20180920/#propdef-font-family) in CSS. pub families: &'a [Family<'a>], /// Specifies the weight of glyphs in the font, their degree of blackness or stroke thickness. /// /// [font-weight](https://www.w3.org/TR/2018/REC-css-fonts-3-20180920/#font-weight-prop) in CSS. pub weight: Weight, /// Selects a normal, condensed, or expanded face from a font family. /// /// [font-stretch](https://www.w3.org/TR/2018/REC-css-fonts-3-20180920/#font-stretch-prop) in CSS. pub stretch: Stretch, /// Allows italic or oblique faces to be selected. /// /// [font-style](https://www.w3.org/TR/2018/REC-css-fonts-3-20180920/#font-style-prop) in CSS. pub style: Style, } // Enum value descriptions are from the CSS spec. /// A [font family](https://www.w3.org/TR/2018/REC-css-fonts-3-20180920/#propdef-font-family). #[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)] pub enum Family<'a> { /// The name of a font family of choice. /// /// This must be a *Typographic Family* (ID 16) or a *Family Name* (ID 1) in terms of TrueType. /// Meaning you have to pass a family without any additional suffixes like _Bold_, _Italic_, /// _Regular_, etc. /// /// Localized names are allowed. Name(&'a str), /// Serif fonts represent the formal text style for a script. Serif, /// Glyphs in sans-serif fonts, as the term is used in CSS, are generally low contrast /// and have stroke endings that are plain — without any flaring, cross stroke, /// or other ornamentation. SansSerif, /// Glyphs in cursive fonts generally use a more informal script style, /// and the result looks more like handwritten pen or brush writing than printed letterwork. Cursive, /// Fantasy fonts are primarily decorative or expressive fonts that /// contain decorative or expressive representations of characters. Fantasy, /// The sole criterion of a monospace font is that all glyphs have the same fixed width. Monospace, } /// Specifies the weight of glyphs in the font, their degree of blackness or stroke thickness. #[derive(Clone, Copy, PartialOrd, Ord, PartialEq, Eq, Debug, Hash)] pub struct Weight(pub u16); impl Default for Weight { #[inline] fn default() -> Weight { Weight::NORMAL } } impl Weight { /// Thin weight (100), the thinnest value. pub const THIN: Weight = Weight(100); /// Extra light weight (200). pub const EXTRA_LIGHT: Weight = Weight(200); /// Light weight (300). pub const LIGHT: Weight = Weight(300); /// Normal (400). pub const NORMAL: Weight = Weight(400); /// Medium weight (500, higher than normal). pub const MEDIUM: Weight = Weight(500); /// Semibold weight (600). pub const SEMIBOLD: Weight = Weight(600); /// Bold weight (700). pub const BOLD: Weight = Weight(700); /// Extra-bold weight (800). pub const EXTRA_BOLD: Weight = Weight(800); /// Black weight (900), the thickest value. pub const BLACK: Weight = Weight(900); } /// Allows italic or oblique faces to be selected. #[derive(Clone, Copy, PartialEq, Eq, Debug, Hash)] pub enum Style { /// A face that is neither italic not obliqued. Normal, /// A form that is generally cursive in nature. Italic, /// A typically-sloped version of the regular face. Oblique, } impl Default for Style { #[inline] fn default() -> Style { Style::Normal } } fn parse_face_info(source: Source, data: &[u8], index: u32) -> Result { let raw_face = ttf_parser::RawFace::parse(data, index).map_err(|_| LoadError::MalformedFont)?; let (families, post_script_name) = parse_names(&raw_face).ok_or(LoadError::UnnamedFont)?; let (mut style, weight, stretch) = parse_os2(&raw_face); let (monospaced, italic) = parse_post(&raw_face); if style == Style::Normal && italic { style = Style::Italic; } Ok(FaceInfo { id: ID::dummy(), source, index, families, post_script_name, style, weight, stretch, monospaced, }) } fn parse_names(raw_face: &ttf_parser::RawFace) -> Option<(Vec<(String, Language)>, String)> { const NAME_TAG: ttf_parser::Tag = ttf_parser::Tag::from_bytes(b"name"); let name_data = raw_face.table(NAME_TAG)?; let name_table = ttf_parser::name::Table::parse(name_data)?; let mut families = collect_families(ttf_parser::name_id::TYPOGRAPHIC_FAMILY, &name_table.names); // We have to fallback to Family Name when no Typographic Family Name was set. if families.is_empty() { families = collect_families(ttf_parser::name_id::FAMILY, &name_table.names); } // Make English US the first one. if families.len() > 1 { if let Some(index) = families .iter() .position(|f| f.1 == Language::English_UnitedStates) { if index != 0 { families.swap(0, index); } } } if families.is_empty() { return None; } let post_script_name = name_table .names .into_iter() .find(|name| { name.name_id == ttf_parser::name_id::POST_SCRIPT_NAME && name.is_supported_encoding() }) .and_then(|name| name_to_unicode(&name))?; Some((families, post_script_name)) } fn collect_families(name_id: u16, names: &ttf_parser::name::Names) -> Vec<(String, Language)> { let mut families = Vec::new(); for name in names.into_iter() { if name.name_id == name_id && name.is_unicode() { if let Some(family) = name_to_unicode(&name) { families.push((family, name.language())); } } } // If no Unicode English US family name was found then look for English MacRoman as well. if !families .iter() .any(|f| f.1 == Language::English_UnitedStates) { for name in names.into_iter() { if name.name_id == name_id && name.is_mac_roman() { if let Some(family) = name_to_unicode(&name) { families.push((family, name.language())); break; } } } } families } fn name_to_unicode(name: &ttf_parser::name::Name) -> Option { if name.is_unicode() { let mut raw_data: Vec = Vec::new(); for c in ttf_parser::LazyArray16::::new(name.name) { raw_data.push(c); } String::from_utf16(&raw_data).ok() } else if name.is_mac_roman() { // We support only MacRoman encoding here, which should be enough in most cases. let mut raw_data = Vec::with_capacity(name.name.len()); for b in name.name { raw_data.push(MAC_ROMAN[*b as usize]); } String::from_utf16(&raw_data).ok() } else { None } } fn parse_os2(raw_face: &ttf_parser::RawFace) -> (Style, Weight, Stretch) { const OS2_TAG: ttf_parser::Tag = ttf_parser::Tag::from_bytes(b"OS/2"); let table = match raw_face .table(OS2_TAG) .and_then(ttf_parser::os2::Table::parse) { Some(table) => table, None => return (Style::Normal, Weight::NORMAL, Stretch::Normal), }; let style = match table.style() { ttf_parser::Style::Normal => Style::Normal, ttf_parser::Style::Italic => Style::Italic, ttf_parser::Style::Oblique => Style::Oblique, }; let weight = table.weight(); let stretch = table.width(); (style, Weight(weight.to_number()), stretch) } fn parse_post(raw_face: &ttf_parser::RawFace) -> (bool, bool) { // We need just a single value from the `post` table, while ttf-parser will parse all. // Therefore we have a custom parser. const POST_TAG: ttf_parser::Tag = ttf_parser::Tag::from_bytes(b"post"); let data = match raw_face.table(POST_TAG) { Some(v) => v, None => return (false, false), }; // All we care about, it that u32 at offset 12 is non-zero. let monospaced = data.get(12..16) != Some(&[0, 0, 0, 0]); // Italic angle as f16.16. let italic = data.get(4..8) != Some(&[0, 0, 0, 0]); (monospaced, italic) } trait NameExt { fn is_mac_roman(&self) -> bool; fn is_supported_encoding(&self) -> bool; } impl NameExt for ttf_parser::name::Name<'_> { #[inline] fn is_mac_roman(&self) -> bool { use ttf_parser::PlatformId::Macintosh; // https://docs.microsoft.com/en-us/typography/opentype/spec/name#macintosh-encoding-ids-script-manager-codes const MACINTOSH_ROMAN_ENCODING_ID: u16 = 0; self.platform_id == Macintosh && self.encoding_id == MACINTOSH_ROMAN_ENCODING_ID } #[inline] fn is_supported_encoding(&self) -> bool { self.is_unicode() || self.is_mac_roman() } } // https://www.w3.org/TR/2018/REC-css-fonts-3-20180920/#font-style-matching // Based on https://github.com/servo/font-kit #[inline(never)] fn find_best_match(candidates: &[&FaceInfo], query: &Query) -> Option { debug_assert!(!candidates.is_empty()); // Step 4. let mut matching_set: Vec = (0..candidates.len()).collect(); // Step 4a (`font-stretch`). let matches = matching_set .iter() .any(|&index| candidates[index].stretch == query.stretch); let matching_stretch = if matches { // Exact match. query.stretch } else if query.stretch <= Stretch::Normal { // Closest stretch, first checking narrower values and then wider values. let stretch = matching_set .iter() .filter(|&&index| candidates[index].stretch < query.stretch) .min_by_key(|&&index| { query.stretch.to_number() - candidates[index].stretch.to_number() }); match stretch { Some(&matching_index) => candidates[matching_index].stretch, None => { let matching_index = *matching_set.iter().min_by_key(|&&index| { candidates[index].stretch.to_number() - query.stretch.to_number() })?; candidates[matching_index].stretch } } } else { // Closest stretch, first checking wider values and then narrower values. let stretch = matching_set .iter() .filter(|&&index| candidates[index].stretch > query.stretch) .min_by_key(|&&index| { candidates[index].stretch.to_number() - query.stretch.to_number() }); match stretch { Some(&matching_index) => candidates[matching_index].stretch, None => { let matching_index = *matching_set.iter().min_by_key(|&&index| { query.stretch.to_number() - candidates[index].stretch.to_number() })?; candidates[matching_index].stretch } } }; matching_set.retain(|&index| candidates[index].stretch == matching_stretch); // Step 4b (`font-style`). let style_preference = match query.style { Style::Italic => [Style::Italic, Style::Oblique, Style::Normal], Style::Oblique => [Style::Oblique, Style::Italic, Style::Normal], Style::Normal => [Style::Normal, Style::Oblique, Style::Italic], }; let matching_style = *style_preference.iter().find(|&query_style| { matching_set .iter() .any(|&index| candidates[index].style == *query_style) })?; matching_set.retain(|&index| candidates[index].style == matching_style); // Step 4c (`font-weight`). // // The spec doesn't say what to do if the weight is between 400 and 500 exclusive, so we // just use 450 as the cutoff. let weight = query.weight.0; let matching_weight = if matching_set .iter() .any(|&index| candidates[index].weight.0 == weight) { Weight(weight) } else if (400..450).contains(&weight) && matching_set .iter() .any(|&index| candidates[index].weight.0 == 500) { // Check 500 first. Weight::MEDIUM } else if (450..=500).contains(&weight) && matching_set .iter() .any(|&index| candidates[index].weight.0 == 400) { // Check 400 first. Weight::NORMAL } else if weight <= 500 { // Closest weight, first checking thinner values and then fatter ones. let idx = matching_set .iter() .filter(|&&index| candidates[index].weight.0 <= weight) .min_by_key(|&&index| weight - candidates[index].weight.0); match idx { Some(&matching_index) => candidates[matching_index].weight, None => { let matching_index = *matching_set .iter() .min_by_key(|&&index| candidates[index].weight.0 - weight)?; candidates[matching_index].weight } } } else { // Closest weight, first checking fatter values and then thinner ones. let idx = matching_set .iter() .filter(|&&index| candidates[index].weight.0 >= weight) .min_by_key(|&&index| candidates[index].weight.0 - weight); match idx { Some(&matching_index) => candidates[matching_index].weight, None => { let matching_index = *matching_set .iter() .min_by_key(|&&index| weight - candidates[index].weight.0)?; candidates[matching_index].weight } } }; matching_set.retain(|&index| candidates[index].weight == matching_weight); // Ignore step 4d (`font-size`). // Return the result. matching_set.into_iter().next() } /// Macintosh Roman to UTF-16 encoding table. /// /// https://en.wikipedia.org/wiki/Mac_OS_Roman #[rustfmt::skip] const MAC_ROMAN: &[u16; 256] = &[ 0x0000, 0x0001, 0x0002, 0x0003, 0x0004, 0x0005, 0x0006, 0x0007, 0x0008, 0x0009, 0x000A, 0x000B, 0x000C, 0x000D, 0x000E, 0x000F, 0x0010, 0x2318, 0x21E7, 0x2325, 0x2303, 0x0015, 0x0016, 0x0017, 0x0018, 0x0019, 0x001A, 0x001B, 0x001C, 0x001D, 0x001E, 0x001F, 0x0020, 0x0021, 0x0022, 0x0023, 0x0024, 0x0025, 0x0026, 0x0027, 0x0028, 0x0029, 0x002A, 0x002B, 0x002C, 0x002D, 0x002E, 0x002F, 0x0030, 0x0031, 0x0032, 0x0033, 0x0034, 0x0035, 0x0036, 0x0037, 0x0038, 0x0039, 0x003A, 0x003B, 0x003C, 0x003D, 0x003E, 0x003F, 0x0040, 0x0041, 0x0042, 0x0043, 0x0044, 0x0045, 0x0046, 0x0047, 0x0048, 0x0049, 0x004A, 0x004B, 0x004C, 0x004D, 0x004E, 0x004F, 0x0050, 0x0051, 0x0052, 0x0053, 0x0054, 0x0055, 0x0056, 0x0057, 0x0058, 0x0059, 0x005A, 0x005B, 0x005C, 0x005D, 0x005E, 0x005F, 0x0060, 0x0061, 0x0062, 0x0063, 0x0064, 0x0065, 0x0066, 0x0067, 0x0068, 0x0069, 0x006A, 0x006B, 0x006C, 0x006D, 0x006E, 0x006F, 0x0070, 0x0071, 0x0072, 0x0073, 0x0074, 0x0075, 0x0076, 0x0077, 0x0078, 0x0079, 0x007A, 0x007B, 0x007C, 0x007D, 0x007E, 0x007F, 0x00C4, 0x00C5, 0x00C7, 0x00C9, 0x00D1, 0x00D6, 0x00DC, 0x00E1, 0x00E0, 0x00E2, 0x00E4, 0x00E3, 0x00E5, 0x00E7, 0x00E9, 0x00E8, 0x00EA, 0x00EB, 0x00ED, 0x00EC, 0x00EE, 0x00EF, 0x00F1, 0x00F3, 0x00F2, 0x00F4, 0x00F6, 0x00F5, 0x00FA, 0x00F9, 0x00FB, 0x00FC, 0x2020, 0x00B0, 0x00A2, 0x00A3, 0x00A7, 0x2022, 0x00B6, 0x00DF, 0x00AE, 0x00A9, 0x2122, 0x00B4, 0x00A8, 0x2260, 0x00C6, 0x00D8, 0x221E, 0x00B1, 0x2264, 0x2265, 0x00A5, 0x00B5, 0x2202, 0x2211, 0x220F, 0x03C0, 0x222B, 0x00AA, 0x00BA, 0x03A9, 0x00E6, 0x00F8, 0x00BF, 0x00A1, 0x00AC, 0x221A, 0x0192, 0x2248, 0x2206, 0x00AB, 0x00BB, 0x2026, 0x00A0, 0x00C0, 0x00C3, 0x00D5, 0x0152, 0x0153, 0x2013, 0x2014, 0x201C, 0x201D, 0x2018, 0x2019, 0x00F7, 0x25CA, 0x00FF, 0x0178, 0x2044, 0x20AC, 0x2039, 0x203A, 0xFB01, 0xFB02, 0x2021, 0x00B7, 0x201A, 0x201E, 0x2030, 0x00C2, 0x00CA, 0x00C1, 0x00CB, 0x00C8, 0x00CD, 0x00CE, 0x00CF, 0x00CC, 0x00D3, 0x00D4, 0xF8FF, 0x00D2, 0x00DA, 0x00DB, 0x00D9, 0x0131, 0x02C6, 0x02DC, 0x00AF, 0x02D8, 0x02D9, 0x02DA, 0x00B8, 0x02DD, 0x02DB, 0x02C7, ]; fontdb-0.22.0/tests/add_fonts.rs000064400000000000000000000006741046102023000146410ustar 00000000000000const DEMO_TTF: &[u8] = include_bytes!("./fonts/Tuffy.ttf"); use std::sync::Arc; #[test] fn add_fonts_and_get_ids_back() { env_logger::init(); let mut font_db = fontdb::Database::new(); let ids = font_db.load_font_source(fontdb::Source::Binary(Arc::new(DEMO_TTF))); assert_eq!(ids.len(), 1); let id = ids[0]; let font = font_db.face(id).unwrap(); assert!(font.families.iter().any(|(name, _)| name == "Tuffy")); } fontdb-0.22.0/tests/fonts/LICENSE.txt000075500000000000000000000006241046102023000153040ustar 00000000000000We, the copyright holders of this work, hereby release it into the public domain. This applies worldwide. In case this is not legally possible, We grant any entity the right to use this work for any purpose, without any conditions, unless such conditions are required by law. Thatcher Ulrich http://tulrich.com Karoly Barta bartakarcsi@gmail.com Michael Evans http://www.evertype.com fontdb-0.22.0/tests/fonts/Tuffy.ttf000075500000000000000000005204441046102023000153040ustar 00000000000000FFTMW6[OS/2' `cmap% (l Jcvt e%feat@gaspglyf aP=<head6hhea T$hmtx+ˑrkern2Q0N4locaܷ%|maxp2x morx;gXname ]P ;postn^Z?propJ'GGJv_< 8x D 8e D @.A33f R PfEd = - Dhg5zhd~$)Z!~Ngbmg(pdppmfqpXpppophpqqKTBX\9X)HydyvyzySdytqyQyyy5\KyZ\My7-XyP(TJL-dr+~X&<TLIb}I((fI`f(xR^D5(xZZp}?5\5(P`TX?VJ1Z+L)mh;m^V1D3&<~yu1.b00/@@ R R R RlSxvyvyzzb 5\5\1f1f1fAl`yyL1\TT ^ ^ ^ ^TVblllxsRff&p&p$pwVx((x(@T@T@TdLdEdLdFyIbjvybvybvybvybvybSdISdISdISdIy*uuI{tqyz$yQwQyQyQyqQyyy$gnl5\f5\f5\f\fMyMyrMy 7-`7-`7-X7-`XfXfX4yxyxyxyxyyf(T^DLxL-dZ-dZ-dZ\^7-`Xf00jZZebbzb8essIR ((~(~p4=Xpnplibf70d:ppbb`Vff(22R^DRYZZZ$999e5\\ebf)7y`99ftff}"LBy%%&bL u?1A8byyygeeeq!LH_5:])NpHyKyxvy-dy5\y{yyn5\nKynXB_JrpNBZ(vpvZoRZi(vpdpZ(J(vR3Z(ZZZ(xv7JZ7_vZv7yopdT6 ~2Q5\Zd2ezyH([(v~N**Ky((s7-7-Zm4 2QZepdee1dyy dddJXJ8J?87-tq>EIyyE:HJ^JCJ\OJXLfqyyyxTyy5\yKydX_Jyby y(yKyd}yjZ\<^b^a(z(zyEbfZ(yeR(J0d5y(}}z 3eaubb(<^e`vH|X(y(z(J(yy(zKyKyJ\<^Jmg7c& /@"9T9Tg~y q>?Zd%dd01D3A0r02:-NF|Pj@<3jB01D3A0r02:-NF|Pj@<3T?T'Z*4B  u@Dd4*~nO$JA+)+L+9"yKyMyN1RH^L^3^A"2502X{D{\{Z{,JJ"JQydyyyyyyRHRRlRy555~e>y&dedBy&z0xxx4444xxxxxxxxxxxxxHH4xZoxxxxxJxxxxx U U HRvy^xxvvm|:nnz@DIb6OOyy\?B?Bhmhm|:|:p_pdpd^^"RR9fd99~zys:fe}}}d }}}}ppLppjpVpopvpTpTpvZZZZZZZZZZL&E(E("*wb>Lk*||www^N"xhtH^==R=d22cl}R`o vyB"4Bt-dNn4q,"O)"&#(TJx____,$ @, $z %(.1qv~_%+;IWcoEMWY[]}   ' 3 : = ? D I O S V [ ^ !!!!!!"!&!.!5!!!!""" " """" "+"4"<"E"H"a"e""""""#!#*%ʧG!Yh P #'.1pvz $*4@VZj HPY[]_    0 9 < ? B G K R V X ] p !!!!!!"!&!.!5!S!!!"""" """" "'"4"<"E"H"`"d""""""# #)%ʧFPha-WSPKJIHb\XVTRPONMLJIHFECB>;65-('&$"! pjc`5430/+)(" @9ߚ^$$e$\#.#    cBCEPK  #%'(..11pqvvz~_  $%"*+$4;&@I.VW8Zc:joDJPRSTVXn EtHMPWYY[[]]_}"58  A D  F  'M 0 3] 9 :a < =c ? ?e B Df G Ii K Ol R Sq V Vs X [t ] ^x p z   !!!!!!!!!!!"!"!&!&!.!.!5!5!S!!!!!!!0""5""6"" 8" " ="">""B""C" " H"'"+I"4"4N"<"<O"E"EP"H"HQ"`"aR"d"eT""V""Y""[""\""]""^# #!`#)#*b%%dFGegi!tPY~hh             !"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\]^_`abUrdeiWxpkvjRGsTUgw6@>Ml|cnCBQ9m}[IJQRMNd:habVyOS]qz!yDXXXX8\(4l <t\  H ` x l @p Ph@lX`$xLxt\(h DhxPh  "|"##|$ $`$%4%&L&'$'D'X(4(P(()*P*++++,,,-..///4/L/d/|///00,0D0\0t0001$1<1T1l11112|222223L4404H4`4x445566606H677D78x8888899|::0:H:`:x:;;,;D;\;t;;;;;<<<4d>|>>>>>? ?$?<?T?l??????@@,@D@AA,AABBB4BLBdB|BCCCDDDDEEE0EHEF0FHF`FFFGG(G@GXGpGH0HHHII,IDI\JKK,KDK\KtKKKKKLMlNNNOXOOPlPPQ Q$Q<QTQlQQQQQQRR,RDR\RtRRRRRSSSxST@U`V<WW(W8XXYZ Z[l\\]^_(_`xa,abcxceefghh|i,j jjkkl4lm0mntoXoppq\rTs0stt`tu(uvvxvwLxlxyz,{{D{||}@}h}}~~t`0hx\Dd< 4PXHXll $T(P|P4,x`$ @lHt $$$d`4Ld((X0LH d8xl@(8LX4p@ňżƸHȠɔtˤ̤ͼΌ\lP,Ҩph 88p$ܴݘݨݸ(d $TpH P@h88xP D08hx|Dp@pPTpttL\tH`x@p|l| ,<L\l ,<L\0`   $ 4 D T d t   d t  T    0   d 40pHH$<T(@P`L\ 8Phx     !"""""#X#$$ $h$% %t%&X&&&&'d($()$)*(*d**++,<,-..l../0001H112<2T2l22223,34`455 5l5566 6@6`6666677(7H7`777778808P8h888899909P9p9999:: :@:`:::::;;0;P;p;;;;<< <@<`<<<<<==(=H=h=====>>0>H>h>>>>?? ?@?`?????@@0@P@p@@@@AA A@A`AxAAAAABB B8BPBhBBBBBCC C@C`CCCCCDD0DPDpDDDDE EHEpEEEEFF0FPFpFFFFGG G@GXGxGGGGHH@HhHHHHHII,IDI\ItIIIIJ0JJKhL\L|LLLLMMM4MPMhMMMMMMNN,NLNdN|NNOXOPPQQ$QDQ\QtQQQQQRR,RSSTT T8TPThTTTTTU<UUUUUUUUUVV$V@VhV|VVVVVVWW8WWWXXY,Yp[]]l]^^@__````blcdeef$fXfglghijkklmxnn0noopq qDr rrss@sst@ttuvxvwLwx xyyyzzLz{ {|P|}$}h}~,~ Dt(<hdPp,htL LL`d@h(x\|DP p@$XXph 4\$P|XT0` <l,<4 ,LlT”TÔ@ĄdŜƀưǔX\Ʉɨʰ ̘̼pXϔ(8|Ѱ|X(\֠LtטTؤL$ܰ݀߸dd0LpT0H`P$pPP|PDpHplhldHpp @     X        t   L  Lx ,h8xDdU./<2<2/<2<23!%!!D $hUDgB #.546324632#"&'&#");'(=@,':?,':"!'77%-?1$,?0% ;&46;2#"&'4&%46;2#"&'&+'"+)"Dv$(v$( 5{!#!#!5!!5!3!3!!!\\Vii#RaaR{{e/8?3.' #5.'7.5467>54&ŁВ}#wKL'D%7$ ӴQ~fL- ;5O-S|k9ԝ]t7.54>32+'n_c[eaw|!Jg[ZL6RY(Ro_t3LLgiv4su]:Hy^P]; #u`lc46;2#"&'&+)"Dv$( ) &5473n{suTIUZ #654'3 tjyTJ]!y7#"'&54?"&5463'&547632763272#'#"'q+& 0*" (*om*( "*0 &+( (#)!)& (( &)!)#( (NB !3!!#!N34̍7Ɏ7g#>%'65"&'&54632>!8H':@,':^%M:?#*gK/% -?1$m3!!m[g>74632#"&'&g@,':?,':^-?1$,?0% T3#3͞d&4>32#"'&732>54'.#"dByo.mܓ."mPI&!kPL(ך|ڈ ڄxpms#73#F\Pm/'6$32!!4>7>54&#"'AxlP/*@:M3C *b`?u4PypG ?"=#-kdV7 GeY3bOO8>#,\ny/^\2*0%96F%q /?32654.+532654&+"'>32#"&q&S9_s=Nba_Py 5{euBN'&TM3}/RhIwK(}pdUI@i^mRM @]GX 3##!;!`^ }ts#V&"'!!632#"&'732654'.\!;1%$^B[# kч.T߄ ' KT7¤?>݉Ţ,'r)4'.#"326632#"&'&54>73oqiEI@! Bse /";N%gu!f~ɛ+3N~N͓*-:snDd Ho7 #!57նPh/@%2654'.#"32654'.#"2#"$'&54>7&'&546Fs`oewU# 3SQ) q" n&oVbqQa -n'l((w͠4,NY9V'0*32654'.#"#"&'&54>32#%qiI@! )PmQ 1A#fv"fɛ2->~pW3Γ,+:rr>mqH'  q#H&  T% 3 PdXBfbb!!!!B  \%# 3#eZ9&6#54>7>54&#"'>324632#"&'&=6(E,|RHV~K`6,@,':?,':-O7<#93(A'|Z|92`aG,W.-?1$,?0% )FV%# &54$32#"&'#"&'&5463232654'.#"32632654'.#"M^7`Ј6Tb-7x(,OzȎv R38f osc.[]uKZmqBTfWRP_]wC@K^89+54'.#32>54'.#"&'!2#2#!?FqK4S}F+ %HU˱vo? WHvK- *KcZ#!7KR,#^ud'!0C9#<9!4Ye:*#u5X^3$$"BWKL5!d)#".54>32.+"3267Lp_wȋa-.awLbN1hhi87#!!2*JcUi0ODOAs[4jTχpzy !!!!!!y0gy !!!!#y0\d-".54>32.#"32>5!5!#P-bwI:jgi99igFvP53#"&'&q o\Fͥ&45}ggGy 33 ##yxϼsy3!!yeݍy 33 3##yϙTT!P\Ly 333#y䝑wPZ\34'.#"32>%4>32#".'&H=^V]\==^U]\>&Z{yƆV'Z{xƆVvmStAPVokRq@MzUeΞc\ltmdʚ`Zkjy 3 4'.+';2+# ,SbΞ BՊΞ#)E?#-(WsB\94'.#"3267'764>32'#".'&PAaVde5=a[6{"Xg ([yb|b=U?ZLnd}b=rjVuAi{mdRvC)"teΞc?hVokRyu54&+ ##;2^R2Sמ3Ʀ"5LF(|wx- 9732654.'.54632.#"#"&-s,G>Y7S,=S73)ps..O8b0JaF@!ۋGWr)L::&+ 1:Ld<êHq|^)C5''& &;FYrBTX!!#!XD7##y3#"$'&5332>5-#zKe9g+rV?~ЇP3#3GBPT 333# #T+P3J 3 3 # #Jjc;˾^)'JLd3 3#LddBX<d!!!!Pliݍ#!!#3u`Z\!31 53#5!`@}5#'#35}VX5!XB獍<.#"'%&'&54767632       TbB )"32654&'254&#"'632#=#"&546ol`{h uEz"NۋgFcgcfm1`+"hm{1Χ">32#".'#&"320Fd>e\..\f>dF-蠠ts-GA#]poŤ`#@E-LlF.#"32>7#"&54>32xF+O6! z6qu(PmTr6)2c#60MZ~Vj=zaI 3#5#".54>3232654&"*we\..\e>dF0stRat`npš]#AG-pbF"!.#"3267#".>32 pLw<[e I }##5354>32.#"3;X`':M+m((9V325332654&"FsM[e<\h-Fd>RZ>.\e>dF0Lstck;Agt8Wu!-E@#@lXpš]#AG-p!#3>32#4.#"qɗ32>32#4.#"V+K3ژ/1L.tm+A+#HnrK/a1&/@$ihs;^dH<gN!#3>32#4.#"qɗ32#".732>54.#"f9kia_Ɍa BoJIoB 7ab7wʗUZyDDyZyuuTN">32#".'#&"320Fd>e\..\f>dF-蠠ts1-GA#]poŤ`#@E-"I? N *3"&=#".54>325332654&"4BEON0d[..\e>dF0Lst=5u͸?V-anpš]#AG-pN&#"#3>32P1>Y{5qR*xw1Yy`HJ:.54672&#" #"&'732654.+ȔQR0 6Pu")( ?"?%6!&ؗ&h\et&G? :Ab;-JG%zOG$  " .0="pCH`U(@-fP+#53533#;#"&5􎎗uFFx-uox13#5#"332>5qɗ=#"332>53L{MՖjg1^R2qɗ&67>7&#"327.'&'&'&Z@T! ,:F'+Z <.<"Y,'F:, (f}w"  P-M+>   " '@W} 33}R=532676=4>7&'&=4'&'.#"5@T! ,:F',Y <.?"Z+'F:, 'i|"  T+Q-9  " %R?3\&>3232>7#"."?%&&800:&-92 *% ?403,'-8 -, ,(  -- 0\I\#5476767676767>7>?>767>767>767654&#"'6763247632#"'&'&4'&'&'&'&#"3276767676%47676767632#"'&'&'&'&n $ lW;/12f VVvQEF,.- | 0.FCX^//!0.GFT^IK-- ! ,+C@ge{zbdBA-,,/?CefzxcbDA-+%cf       W` V(sNN@BYD42-  spOIC<9" P@?UTUrhKJA;9 '(;753&#"327#}k 8]`4cdZPkU~pPRZ< w,9L|M. W_Pz[!&S]jZ`4T''#5332.#"!!!>7!>7j^I: g ^.PF62 ; TBTktFdQ}N! s ' *?w-w132654'.#""'#53&'&547#536253#3# cAKi bALidPP+;yPPy&B>QjK>Qj779F$gQ{77{4B%hWJu!5!3 33!!!#!5!DX1Ϙ7D6ׇLZ#53鏏{z+h,;632#"&'7;26754"#"&'&54>32.+"4'.#";2& ];S Ga - " N[avFF^!Q% Ö0,Wd #pX 7:nxH\S{QL4!4632#"'&'&%4632#"'&'&#8&"28& )8&"28& &8*! '8!&8*! '8!)7(8#"&'&54632&"327%32654'.#"432#"&'&uCSJqyV[;N"L84!.sssu bC\GUy;R8& ,D%o'nŖ2)Ŗ+mm 2"3264'&#"'&547632&'&#"'7632#L0:0(:;Y;:<=V:+0AI\[=54'.#"4>32#".'&%32>54&5.+'32#'# Qlv;DtH Vpu5EtGu?gE& kʡ 3"/0]KRRq -dAR2,JuG$5aZ.(KzH&1^_ftR&߰96}U{8q "N:> ,a)!![)j1=32654'.#"4632#"&'& N4=S N4=Svm^m^3AW?3BXBktY ltY'HPDPB'767632!!5476767676?>?4&#"ʆ JIX&D !.   ( _ !. <&( #5O87:,-0 ,#406 '!"!5<.3S>7327654'&'&'&+5327654&+"'767632#"&'3 < 8&% JT"4"  9:H885##QRtHs+!(!!6($2 > >%%65A1)'&$-rIJXJ<.%632#"'&'&5476L      ufh%#332>53#5#".) $.N5%.u:+'" #J+6L8'@QQ&b9D$yu,23"3"&#.'&54>;0GM*$)A/%=^^A0 s  !!6O2!5!   ,7O1*)b`3neE'{uqJ>54'.'7u' @8*J  "  #8>H 81,1@#73#{a.(:-&327654'&'&#"47632#"'&'& ('4<** ('4<**vLLn_LNl_GF/1"!+,?2"!,+ClKKtYlKL:9Zb;^ #!#^"#"#0 %3##5!335#73##3v^^Wc{a) W6N0BHL%'767632!!5476767676?>?4&#"#73##3N JIX&D !.   ( _ !. <&( #g{a)5O87:,-0 ,#406 '!"!5<. /=GJN732654'&'&'&+5327654&+"'767632#"&'3##5!335#3/ < 9J JT"4"  9:H885##QRtH7^^Wc)s+!(B6($2 > >%%65A1)'&$-rIJXJW6}"{@&$C@&$vRq'A$ RJ'a$ R'j$ R'rf1$ Sg!#!!!!!!53OFF{JxX'z&y&(Cy&(vZ'A( 'j( 7&,CTH&, vhIf'A, 9'jZ, #53!2+324'.+!F}82⛝(,bhE^S5'a+1 \&2C\&2vfs'A2 fJ'a32 f'j2 lJ7,-c,`,9%#7&'&54>3273#"'32>54'&' &#"J|/6[xczaE55\wc5VoYZ=#OIXYZ<)FokRvD2EmtRsB;LzTtod`&O}Txdy&8Cy&8vw'A8 'j8 Ld&<v 2>54'&!3 ##/WlC.E7gc&;b@&(SX>!\]F>32!"'732>54'.+"5;2>54'&#" #67,DXQ'+^eNPj[ ( ?d_?&$*Y)JsO3!  +, 8cF:" ,GnA'h5{ $;`@o;xJ'%#CP7bzY Tb=&DCTb=&DvO^l&AD ^l'ayLD ^l'j^D ^lV'rD T`F`j"32654'.>32!32>7>7#".' #"&'&546326&74'&#"'>32!&'&#"i_"\mf:zd!aV!.'8m'@5$, %'3 ȘWR$ "AP'N& %'"0^t /:X/Zl1$h(Ob4_Y^} - IG]~+&7nk 9 %*% 7035,6+&'f  YsG9BmuV]vF'z F b=&HCzl=&H vcl&A5H l'jH /=3##"'%&'&54767632     11  ;=3#%632#"'&'&5476    11  s# 3##'#31^Vb%3#4632#"'&'&%4632#"'&'&8&"28& )8&"28& 1&8*! '8!&8*! '8!R>32654'.#"#"&'&54324'.''7&#"'6327 Iqg;h9C ݠ)G/30 h8cGY)J7`.2u׆%sjMo$!B&ҸHP$. !(^1dFm'aXQ f<&RCRf=&Rvp&A3R p'a/R p'jR w[#4632#"&'&4632#"&'&!!X@,':?,':@,':?,':[-?1$,?0% 3-?1$,?0% VJ 1 32>54'&'&#"7&'&54>3273#"'ATEj< ZASAh>! s7__1q9_c0DNNVD2?L{LWG+%YwZVKOZuQ\NNx=&XCe=&X*v&A1/X 'jX x?=&\v\,!#3>32#"./4'.#"326/DU4":[^.S6( fD5hU5Jr)54ȢXeZkA,+]Rp3232654&" '2(e*we\..\e>dF0st$#$ Q>& # Rat`npš]#AG-pj##53!2+324'&'&+! |ݝ2KL⚝(ts+ia˥_`F^SooR:327654'&"33##5#"'&'.'&547>32#53MLtuOPPOLL"#2/BPEB.,@ ^f?15 &vttvtsrq˅e*&"  75PTUne`\$ $,%y'q[(b)&qHy.&(b'|Hy'(b'DHy'(bF'HyB&b(b'HdB'*I?'Jd.&*I?'xJd'*I?'dJd?'*I?1'lgJyJB&O+B&K*3!33##!##53!!y88kOO3kf7^ff*!##5353!!67632#4'&'.#"ccPQsRBE02fDF23"[;323276767"'&'&'&'&#"F% # !1 !#B"$B1W  &   /'q,C(3#!![1(j.'S,&F|uq&,uq&LC&;,#13#1!%#"'&'&'&=33276767653٘3rRBE0/fDF23"Yg'ZOy'65"&'&547632%3!! '2(e$#$ Q>& #ݍ&'65"&'&5476323"&'&53 '2(dq$#$ Q>& #. KJY% y'y/'y8O ?37!!g}~eh ~}e?373"&'&5ldqmy  KJY#"y'v1:'vDQ y?'v1?N'BQyB&t1'Qg1'gQn6%276=4'&'.#"#367632#0#6gJIfD*b<`w1yqySBC14$HAAPA/JI!_FL:;B"9HKz\F0!"BGhl:DD< l?N3276=4'&'.#"#367632+6gJIfDF25 PQsRBE02#JA@PAJI!ZKO7;B"$9>IKX1[;CE= \'q2f,&qR\.&2f'R\&2f='jR\"=47676767632!!!!!!#"'&'&'&'&.'&#"327\,+C@ge{'<4_T^xcbDA-+ CX^//!0.GFTfAgehfdRO21'--NK_[lm/ P@?UTUrhKJA;9 'fvFJR2?&'&54767&#"476767632632!32767#"'#"'&'&%!.#" 977115Qc@A47STib^_QO214d::MJEF 4gju|_bef00t pKx<\JO:;#"".={>(#:;[_vychIM)*FF.-KJc 1_QO66&'<7d:;GGMN}~lyP'v5='vUy?P'65r?N' UyPB&5 'hU - 'vl6`H='v#V- B&6`J'V-] Zw732654'&'&'&'&'&'&/&'&'&'&'&'&'&547632&'&#"#"'&6767>54'&'&'7-s#$!*0>8!.+  zyyz(USqs * 5>!'2* $!DEmn|z? ' '(GWr)&+  #$%)+5baUVH98|^$   ($'%j6Z[**ba4 876767654'&'&'7C#'4/""deQ)/ 6P;: '( (  lk\_%44\dt"%!  ? -'$#.1;KL,&,$%z''H&    )ZYCEnC$$`U+"   "8& # -uoX!!!!#!5!!XD7YD#:[4+#53533#3#;#"'&5#53􎎗uFF;<u78gyF'8x'\Xy'qt8x'&q Xy.&8x'vXy'8x0'$Xy&8<'X*y'8f1'QXTB':D1'ZLdB&=<x?'\Ld&<jd'v=Z='v]]d'=Z'b]dB'=Z']5476767632&'&'&#"#,+1/(:'%,m ':1>34#")i 4- ##737676767632&/"3V11)-83A.().\(32@1VA@E50  ('&.\r!!!#!!!!!!53\EQGGWzJ^l7V_!!"327654'&'&6763 !32767#"'&'#"'&'&54762'4'&#"'67632!&'&#"]"|6m PX4= P-R- P`3DU+7D_ ]< "jHMU&;PeC .37",*}9B"## 3"cxDHGI.5)gCbD2:43pNJ <2.GgF I6H-  P'65"&'&54632732654.'.54632.#"#"&~!8H':@,':s,G>Y7S,=S73)ps..O8b0JaF@!ۋ%M:?#*gK/% -?1$Wr)L::&+ 1:Ld<êHq|^)C5''& &;FYrBT`HJQ'65"&'&54632.54672&#" #"&'732654.A!8H':@,':l+ȔQR0 6Pu")( ?"?%6!&ؗ&h\et&G?%M:?#*gK/% -?1$ :Ab;-JG%zOG$  " .0="pCH`U(@-X,$fP+%0 qF676767654'&'&'&#"57>54'&#"'6767632ucm^P/-;&M`_I:D M=<5bdw$"?8Z::!"%.?6&F)Vju0Cr8C$7674654'&'&'&#"5767654'&#"'6767632w& /-; #M`^HGI8FM=<5bdw$"?8Y;:!!&.06%L>6;&(@7  ~YXqd=. 76O)tRSRQmTNM.6 9K90 p\YjxB52654'&#""'&'32767#"&=3676767632pHGm`FGIJzhLL tD>=#Nڋ%!537hjmkߊdgDCEEdgCD653`#hm{"ghkjZxB-7&/054763253#5#"32765&'&#"knf !537X@B`HF=?vF36!=YqtmWFϜ!ORFE`:LN!LZxB-%#"'&'&'&'#36320&'&'&#"32765 w735!#fm=!63Fv?=GH_B?Yv 1FWmsˑL!NL`EFRN7G"'&55476767632#.#"67>7632#4'&#"3276wm##94NHM]LP20 \iB42>QEB., /-dMLtuOPPOutLMvqbTS62  "20>99Xt!'(%< 74LJPTTmecQO^8srstvttveF/'67632#"'&'&'&'732654&#"5VUsTJH86)(;:jh=57)2 z +'+E=<)B`>=74HFRSTML '%(Mõ22ZF<J&'&#"67672>32#"'&''67&'&5476767676323276=&'&#<=E5S.9M + 7"`[\72 TI327654'&"33?#"'&'&'&'&5#"'&'.'&547>32MLtuOPPOLLfk$#$*"("(#"#2/BPEB.,@ ^f?15 &vttvtsrql{ f"  $ 24?C*&"  75PTUne`\$ $,I327654'&"/"#5#"'&'.'&547>3247676767632MLtuOPPOLLkf"#2/BPEB.,@ ^f?15 &#("("*$#vttvtsrqf {*&"  75PTUne`\$ $,S?42 $  bF-.#"!546546767632#"'&'7327676rNIFG4gju_`0112_aaOM42͑hi65PN_j'';7d:;LL{~IJ-,NK]_c!0b`F'96327#"'&'&'&54&='&#"3276767654'&ju_rl# 012_aaOM42$9NIFn FGoK<;! ;LdF6 {~IJ-,NK]_c!005'1hi65PUR>_kJ=%#"&547676?&'&'&54767632.+";#"3267k+fee%;T(*- -3CINcMO)d`:A&H=;IH9/("+(IKg?xf==/1"7* &F33247676767632/" MLtuOPPOutLM#":8JFO[NP21 [i##2/AQEB.,@ ^f>25 &#&%) *$#$kfvttvtsrs bTQ75!"21<99Vv!*&"  75PTUne`\$ $,S?42 #  "f {s?N;K#"'&'&'&'3326=#"'&'.'&547>3253327654'&#"#":8JFO[NP21 [i##2/AQEB.,@ ^f>25 &LMLtuOPPOutLMbTQ75!"21<99Vv!*&"  75PTUne`\$ $,vttvtsrsICE"'&'&'&547676767632&'&#"32767676765!5!+hSV57%&03IHXvIH7e*1.PJ?<)&%&97L.61+ .(tA.0LObekOJKKN48""++UW:*(GAQP&ROR?A  )K.%o93=.6,('"(R102I0+&#"&"'&'.'&'&'&'&'&'&5476=673 3'&'32676750)(5      Rbw67    Y07 3C !1n,"X . B TE %276547#"&#&'&576733C8 $!  _ '*2 o'Oqor 1 !$3%U38i0F,#JN!3##"'&'&'&53327676765$rSBC14fDE27NP4Zx!"BGhl_FL:;B"%8:MPS~9!#5476767632#.#"67632#4'&'.#"#";5LHM^42\hOA PQsRBE02fDF23"1bTQ82 @42<99XtI;b[;46    f  {ZKO7;B"#:AFKX4632#"'&'&33###53y8&!8&!5&8! &8!:4V#533?#"'&'&'&'&5Sfk$#$* )%&${ f"  #!13@=2 3!53#5!7Y]]Sꎎ+.3276?#"';#"'&5/"56767632:%$<2 !""!uFF;<0$! *!#%#+.& u78 !X&1%3"&'&5#"'&'&=476736767'3dq$ -8!<ڗ)-mHS7W'%# KJY#"26P7/&_`;(:+(*(h33276767#"'&'&'&5:' m/"%<&14(,-4 i, #43>ntL 3%3"&'&53!5!#"'&'7327654'&'&'dqT$!/7&}~8%POS_`019 KJY#"9  C.BAHāLK/Q54UVJ;:&'N53323#5#"'&'#"&5332 ,H5ژ ($0tJKm *B+NN1=37N.&϶+! DEih;/6+8$<N63323#5#"'&'#"&5332 ,H5ژ ($0tJKm *B+NN1=37N.&5+! DEih;/6+8$<TNN!#4'&'.#"#3>7676767632>32#"'&'&'72=4'&'&'.#"V ,H5ژ ($0tJKm#&%) *$#$kf *B+#N1=37N.a1*! DEihs?42 #  "f {;/6+8$<g>IN5!#3>32#4'&'&'&#"+6726=sRBC1443CF25 $H?CP@f1Zx!"BGhl_FO7:"!"$9>IPS%A :ED; |!l?N6%330#"'&'&'&5054'&'.#"#367632IJgAPAAH#fDF25 PQsRBE02BB!IJ| 
ZKO7;B"$9>IKX1[;(#:;[_vychIM)*FF.-KJc 1_QO66&'<7d:;GGMN}~l7H$H%#"'&5476763!2#"'&'&'&"2767653367675&'&'&#a ! 3/7`112_a a_210`6/3 !Kx<?8!B& } &A!8?:X>=QSpR$<;^]wϵ[;<?32767653#5#"P1>X>=QSpR$<;^]w3[;<UF*?327676533?#"'&'&'&'&5#"P1>X>9fk  $*!"('#!QSpR$<7bQ{  f    64>\[;<N&#"#367632P1>X>=QSpR*<;^]wg[;<TO.&#"3?#"'&'&'&'&=367632P1>X><fk$#$* )%&#QToR+<:_W}{ f"  # 24?"Z;=V747676767632/"3!5"!*) !*$  kfxt?35   f  {V%3!534#'6767632xtxfk  $*!"('# {  f    65=bN'3276767>54&+ ##;2b@93 bpHG{=5 4[h@3'lQP'bN' 327654&'&'&'&#3+33bDC 35DG|FHpqpu54[4 5'OQlOP'4`THJe&'&'&'&'&547672&#" #"'3?#"'&'&'&'&='7327654'&'&'&>'*2/""deR), 6Qt  112-+$lkXfk$#$*"("(#45[e::"'$#.1;KL,&)$%zNH& !'/6AZY3{ f"  $ 24? C$$00U)" h,476767632&'&'&#"#"&'732765,+1/(:'%,m ':<+(41&;J-m (>34#")i 4-32:' m/"%<&14(,( m+N9(/1V<$,-4 i, #43>. i(*DjVh7H476767632&'&'&#"2632&##"'&'&'&5476767673276=,+1/(:'%,m ':# _p<+(41&;%U+; 5=>K*(vX=>34#")i 4-wHPS2D2#5!326767654'&/5!# &'&54767գ~ $A"!nKIn!"#9D~)1`de014!;[_v\JL=o% 26P &uE/ ,bt2& !5!#"'&'7327654'&'&'KT$!/7&}~8%POS_a035l9  C.BCFāLK/Q54UVH=:&($27F !5!&'#"'&'&5054767632654'&'&'327&'&#"HT$!/7&bCYHVNa(!!5- M9V4019OStWrr "'$l9  C.BAHtCb`gSbL"C: P65 -g IhJ;:&'42$ +*)# .,!&}EDZ|9oo^`aIP9..>96/&'&'&5467676324'&'&#" # &1=(:)%J@>OLXyy$$FER~KM 56 S>..9PIab1/oo9>=.-DE}&!,. #&*+94#"'&'732765/ &'&'&'&53= $2>(;(%L|OLX{y$$S|MM 47 T=-09OIb`^po:=>ZEE|&!--)*+ekF@&'&#"327676767#"'&'&'05<&454767676767632<=EZXRX+'+ z 2)75=hj:/ ()68HJTsUV5)122xt* `nvM(%' LMiD[JA;RFH47=>`\%M_4'&'&'&'&#"3276767676%47676767632#"'&'&'&'&%"'&547>32H 0.FCX^//!0.GFT^IK-- ! ,+C@ge{zbdBA-,,/?CefzxcbDA-+6776Z..,+spOIC<9" P@?UTUrhKJA;9 '(;L756($.!/1ZZxZD>+,V43W-%  eJ'J%#0#"&547676?&'&'&54767632;#"32767654'&#"h%;U(*- -3CINMSH86)(;:=;IH9/("+*fAT(&C3X[ZE=/L/1"7* "J346    f  {x7:('56PQf03) 9K4632#"'&&'#"'&'&'&'&=476763232=&'&#"8&&8&&Hg#("("*$#$5!!5- M9 Y'f); "'$5&8(&8o`^2 $  "/P0P65 PAK {F  47b1 373##3{jgh{RhybF3!!yKFG`?O327654'&"3"'&=#"'&'&'&547>32567676767632/"MLtuOPPOLLBFE4KIebPM.0^f?15 &#("("*$#$kfvttvtsrqV;;:͸w0.1/SV^elne`\$ $,$2 $  "f {}9;!5!54767676? 4'&#"'67632!!#? 74 MK~SHyzXLO|L%): >2$ _(C+*)# .,!&}EDZ|9oo^`aIP9..>S?9>#!5!5/&'&'&5467676324'&'&#" !=_ &1=$:)%J@>OLXyy$$FER~KM 56 ?((?S>..9PIab1/oo9>=.-DE}&!,. #&*+C;327654'&"3!5!!!+5#"'&'.'&547>32MLtuOPPOLL {"#2/BPEB.,@ ^f?15 &vttvtsrqt\*&"  75PTUne`\$ $,tY327654'&"3!#"'&'7327654'&'&/!#5#"'&'.'&547>32MLtuOPPOLL$!/7&}~8%POS_a035T/"#2/BPEB.,@ ^f?15 &vttvtsrq  C.BCFāLK/Q54UVH=:&(9[*&"  75PTUne`\$ $,lR^327654'&"3!5!3676767632!'7+5#"'&'.'&547>32!6=&'&#MLtuOPPOLL'e@'E9M -8!o% 26P2T!8\`4*&"  75PTUne`\$ $,53 ,bf+6T#5353!672&#" #!"'&52767654'&'&'&'&'&'&'&'&547#􎎗BTR), 6Qt  112-+$lkӕ;<A^:"'/&?*2/""_,&)$%zNH& !'/6AZY78q.i)"  $#.1;I8-pfhK@#535335476767632&'&'&#"#"&'732765#;#"'&5􎎗,+1/(:'%,m ':<+(41&;J-m (uFF;<>34#")i 4-32&'&#"67672632#"'&'#"'&53276505&'&#􎎗uF(P:(*48UrUW5<=EZ[7;E?G+ 8!32+67276=4'&'.#"#,+1/(:'%,m ':[rSBC14#JA@PAgJIfDE27V>34#")i 4-Zx!"BGhl >CE= |JI!_FL:;B"%8:MPSO337327654'&'&'&'&'&'&'&'&547672&#" #"'&'45[e::"'/>'*2/""deR), 6Qt  112-+$lk\P'+C$$00U)" $#.1;KL,&)$%zNH& !'/6AZYC9Y 33!!d\ B #333##333#Xrqs\Xrqs\z$ciz%ciyJ!#!#!#!#yўkўkvv%N@6767632#32767676=53#5#"'&'&'&=354#%$#$*"("(# fDF23"PQsRBE00f"  $ 24?09O7;B"#:AFKX`=+[;323276767#"'&'&'&'&#"?F% 8 " !1 !"" "$B  &   p+632#"'&'&54%632#"'&'&54$$;:!  :!  Ax"&54763#"'Q "! "8j632#"'&547&# !. GA/167676763223276?+"'&'&'&#"#1 $&(2 #",, 7  %/#&"AT t'  #! *F  8)q3276?3#"&'&'I Ll;23)6KMbX94"!s;:Z6M)*HH@b^b47632#"/&9>:>> 8 >7=d#47632#"/&%47632#"/&9>9>(:?:>> 8 >7> 8 >7)32765054'&'&#"47632#"'&'&LW(OW(uoFQN"oFRL"TN'! RN#(N/o.0L/o.0jQ$&h?&#5b^47632#"/&9>:>>7 > 8=^#47632#"/&%47632#"/&9>9>(:?:>>7 > 8 >7 > 8x})32765054'&'&#"47632#"'&'&LW(OW(uoFQN"oFRL"TN'! RN#)N/o.0M/o.0J654'&'7^4@DE$I8>G \U)J&'&'&54?^4?D3E$I8>H  \U)bt676730"'&'&=37#;EPB#ECCE#BQ1N&*z Do9(&&(9oD p4u!!]y3 30!0!#y^y32 30!0!#y2>y !##33Zwg>74632#"'&'&g@,' ,'^,@$ , $ eF/'67632#"'&'&'&'732654#"e5VUsTJH86)(;:jh=57)2 z +'+~`27H#`>=74HFRSTML '%(Mö)+eF/B&'&#"327676767#"'&'&5476767676324632#"'&'& 72`~İ+'+ z 2)75=hj:;()68HJTsUV5R@,( ,'H9+)M(%' LMTSRFH47=>`,@$ , $ eF'qRH)676#0#&'0'&47632#"'&'& 0   -&<@+'y)   - 2# +@$ w67632+&'0'&  0 )   Lv&jOH %!!#3#67632+&/&%    0 P)   _w6N4632#"'&'&_@,' ,',@$ , $ v &!!!!!!67632+&/&0g  0 )    &3!3#!#67632+&/&۞k  0  P^)   }3367632+&/&  0  P)   :%Mh4'&'&'&'&#"3276767676%47676767632#"'&'&'&'&67632+&/&H 0.FCX^//!0.GFT^IK-- ! ,+C@ge{zbdBA-,,/?CefzxcbDA-+"  0 spOIC<9" P@?UTUrhKJA;9 '(;4HA<63$$9;JLL,! ,-A?hfzycdX  ,.@C{wBA-+ #>  /-HFT\-,! <  0-GCX^II/0 J 3 3 # #Jjc;˾^)'Jp/367676767653#&'&'&'&'&5!0-H$,8*J.- ! ,/?CeEVJGbDA-+rhLJA;7!Q '=L<'fA\JL=;!"'#632767654'&#" 2327676767654'&'&+"1} g{|!%).')&+//25%%DY 4*\W[@A*#z)2"H (5*73|~$'RT-* :03!% #%54D)h'_<32#4'&'&'&#"sRBC1443CF25 1Zx!"BGhlW_FO7:"!"$9>IPSd'647>7632#"'&'&%!32767676%!&'&'&#"d!!x]\orr.76nnts/"IImO@A#% t!FGkNB@&( כ?>؋̭jiڂOd[dc89Z]hA`bab:9]bf=V233?#"'&'&'&'&5fk$#$* )%&$2{ f"  #!13@Z5 33 ##Z0H0PkJ 3'&#'67676303# Rl^3k$#$, + )%& Þ1 f"  # nvu2#%#3303276767653#5#"'&'&'& '4! ,=;u,<=J+lL8@)&#/(&b8#" R^!374# H86)(1wj74HFRST3tD%27630320#&'&#0#"547676767&'&'&54767#5!#;#"jG`B122vyZF1326767654'&'&#"47676763!# &'&"!nKIn!"A@bd@A48QTj 3 1`de01\JL=Lyo#\32767654'&#"327654'&'&+567>;"##"'&'&'4&46 4*\W[@A*#z))z#*A?\ZY* !1} g{|!%).')&&&)'.)% |{g ~XY1" 8<7632#"'&'&%!32767676%!&'&'&#"d!!x]\orr.76nnts/"IImO@A#% t!FGkNB@&( כ?>؋̭jiڂOd[dc89Z]hA`bab:9]bf=2 #&#'67676303 676767032/"5k$#$, +,J$$J,+ ,$#$k8& f"  08680  "f 6'>p&jJ~t )#&'&54767367654'&~zz/:voTpoSjTppQbؘ|~z֘z /DTpoS(RppQH$H%#"'&54767#5!2#"'&'&'&!"2767653367675&'&'&a ! 3/7`11!/a_210`6/3 !}Kx<?8!B& } &A!8?:<*$#{Q8JI~{#$*lZ_QO6*s$%(%$t)6OQ_ZNO56Qt3654'&'&'&'503;2#&'�#"'&'#( 3MHE!\.+'BI9uZKnyl{%N WRӁ<fM <#t#X5n\t*P47676767632#&'&'&'&'&%4'&'&'&'&#"3276767676\,+C@ge{zbdBA-,,/?CeKSO@bDA-+ 0.FCX^//!0.GFT^IK-- ! gehfdRO21./NLa]ltmbghbiIM0# t -NK_[lmlspOIC<9" P@?UTUrhKJA;9 '(;`y !!!!#y0\tA/"!!#"'&/5327676765#534767>321*+2G+, (67f  (4%L<9%%*+j  =BBMtJadBCB p32NPftK\`JLB [#C!5654/#'67670320!3?0#"'&'&'&'&50547[ CA"!%!  " CA"!%!  ":.%? %&3* d%? %&3* dv1 !'!5  \Ȏ0َ 02VQ'676767632#"'&'&'732767674654'&'#6767&/&'&'&#"#O34?do%IBa\\KI=:HgQT.,(H<@1kKn XMU// oX.iP9ktz[i2134$:=>TRiekRPa32&#"3276<##2/AfNO./^f>2-8ItLMMLtuOP#d*&" 01QSbelne`\+rsvttvTL!#"'&'&/"'67>323276=4'&'.#"#367632#"!i:S*$#$0!F%F%05O8ffDF23"PQsRBE02?42   " !  ,&+PZKO7;B"#:AFKX[;323276=4'3276?&'&#"3,1263BK@*7 SfJLx5i#"!i:S*$#$0!F%F%05O8fD#8> '.+*5;%)6.;Opt:= ,42=v?42   " !  ,&+P ;5 \A>C6W +v#- U#"'&'&5467>767676?6767676767654&#"'676323267 ;y|nmEEB #&2'!CC(* sqSU)yyyz  V)7F-.$ ȎsG`b**[\:b)'H  $^|89HVUab1/1"#2    )#,rW- B]#"'&'&5467>76767&'&=67632326736767676767654&#" ;y|nmEEB #& (NB)yyyz  V)7F-.$ ȎsI1OP0'* sqSUG`b**[\:b)'H"B VUab1/1"#2    )#,rW+WI1  $^|89A%!7!&/'>76763223767676?263632/X2G a 6W& 4 *B@@B* 4 &W6jf  w   >;;>   w  /A%!7!&/'>7676322376767673>3632/nF a 6W&0*B@@B*0&W6R|V&  w   >;;>   w  Z^326767654'&'&#"25/7+"67632 &'&=47676763237:32"!nKIn!"A@bd@A{  f   <64>gLK.1Tjde01`de01#":8JI<  S\JL=73'676767654'&'#.CV*&(.1:C/]35 6 S4RO #"'&';2A@db@A"!nIKn!"VOFJ8:"#10ed`10edjT1.i?42-v_[;::;[_v\JL=`TfMd'647>7632#"'&'&%!32767676%!&'&'&#"d!!x]\orr.76nnts/"IImO@A#% t!FGkNB@&( כ?>؋̭jiڂOd[dc89Z]hA`bab:9]bf=eF4&'&#"!!327676767#"'&'&547676767632<=EZGLGX+'+ z 2)75=hj:;()68HJTsUV5)122x]_vM(%' LMTSRFH47=>`eF4'67632#"'&'&'&'732767!5!&'&#"5VUsTJH86)(;:jh=57)2 z +'+XGLGZE=<)B`>=74HFRSTML '%(Mv_]x22#:!#3676767632#"'&'&/4'&'&#"3276$"#)(7Z[" -+LG`73034C543+,4DFIsCD3 deVgZNPIL64" ZUpBC67`SFGIqs#27676767654'&!3 ##/\GQGR17 "/E62B=YWQNi13>(&TB@.+ d@#"'&'&'&'&547676767632&'&+"32767&$:5SO`ufdEG/21/HFdcxIGB21'(VSihTV4365URdkZ[ %@742.)(HJ^eikxtqmeaKI++(*()))Y9768XWrmyxonVS53AB\y 33 3##yϙTT#PQyt 33##y׺ϙt7632&'&+"!!32767b&$:5SP^vfdEG/130dcyHGC21'%VSiiTU43X65URdjZ]%@742.)(HJ^amkmjhc++('+)))Y9767YWrLYOKnVS53AC[- 67,3'jT,q33276765!5!#"'&'&q o[HI"#ͥtv%27?@[^f qsDE-<!###"'&'&'727!32#'32767676765!#y #("("*$#$kWjl"!fDG+) #\2 $  "f {!!rKIX+*ZX #!*#I)!!#3!332+32767676765! jl"!fDG+) Y}!!rKIX+*ZX #!*#j&!#!5!!67632#4'&'.#"ǘPQsRBE02fDF23""Z[;?327654&'&'&+5327654'&+"'67632#"'&q%POS_a:/17:=NbaHGIJ_Qx 4ed{d\Y<;!!'(&$,')&|~/Q54UVGz%&}JHreFGTJ@hA@/-[YmRGF'( !1-DCFMLy 33##y둝ZPwyX!676730"'&'&=333##7#;EPB#ECCE#BQ1N&1둝*z Do9(&&(9oD p4ZPwy 33 ##yxϼsT$!###"'&'&'727З #&%) *$#$kWP#\2 #  "f {y 33 3##yϙTT!P\LyJ 3!3#!#ykP^\%M4'&'&'&'&#"3276767676%47676767632#"'&'&'&'&H 0.FCX^//!0.GFT^IK-- ! ,+C@ge{zbdBA-,,/?CefzxcbDA-+spOIC<9" P@?UTUrhKJA;9 '(;4HA<63$$9;JLL,! ,-A?hfzycdX  ,.@C{wBA-+ #>  /-HFT\-,! <  0-GCX^II/0 J 3 3 # #Jjc;˾^)'Jy0< %#5!3!3<˞#b"3##"'&'&'&53327676765sRBC1443CF25 P Zx!"BGhpEZKO7:"!"$9>IPSy%!3!;3Ş##y0%#5!3!;3a##($!#5!332+32767676765!o Ίjl"!fDG+) "!!rKIX%0ZX #!*#yK&!332767676765!332+gDG+' jjA@"!P %!*#V!!99KIX+*YXy"32767676765!332+gDG+' ΋jjA@"! %!*#V!!99KIX%0YXd?7327676767!5!&'&'&'&+"'67676767632#"'&'&'&d [ZkcST58X45STijSU %'11DGHxcd03.^GDu_PS5:$&%)\BA34TYkKOYLoZ[5678Z)$.+'(++chjqtsJGR.247},R3336767676762#"'&'&'&'&'#4'&'&'&'&#"3276767676}a *(;9]\XY<<'0 '):;onXY<<'%_*'B>MVACR -)KV@C)( GN5bleQN22./OP\rWedeiagKM`--NM]XoSN\܂mQGD;7#!()|VhNmmNH?=8@&'=:ULXSyP#"3#&'&54$;##Ǻ ('\Jdc2Ξ|)"(!&"nnPwjwB5"327654'&'254&#"'632#=#"&5476lHFGIj`HFIJ{fNL ~vB@;#Nڋ !537lmFFEcgCDFEcgCD761`#hm{!ΧkkZA326767654'&'&#"&#"67632 &'&5476767632"!nKIn!"A@bd@AP[i.1Tjde01`de01#":8JFO[NP2\JL=L756($.!/1ZZxZD>+,V43W-%  ^2!#!V2*P2 %3#5!#367!3#^LFlhdj^ q0V|abF 1!.#"32767#"'&'&54767632 pL<:<:LIEH3ijtac/012_a_QN23\65ON_QN76&(;7d:;MO|{~IJ.,LM\_c/!^~2!#5333##\\q:wUXaAJ??327654'&'&'&+5327654'&+"'67632#"'&aux>gKI)!,(/9GI3467D:-*e)PMbOIF/. %$'$T$#pqdef&6B76[0&' }/0HA-.24S64#"BAQ<542! 3/6^_==z2 33##z2",z!676730"'&'&=333##$7#;EPB#ECCE#BQ1N&,*z Do9(&&(9oD p4",y5 33 ##y0H0PkE}2!###"'&'&'727M #("("*$#$kZ 2|U2 $  "f {b42 33 3##bPO2`$$f03 3%'!#ff2)-ZF0476767632 &'&7326767654'&'&#"Z48QTjde01`de01"!nKIn!"A@bd@AvfhIM)*KL{LM~\JL=f^/.ONfA/2##MLtuOPPOutLM1,$ $\`enlebSQ10 "&*srstvttveF/&'&#"327676767#"'&'&547676767632<=E+'+ z 2)75=hj:;()68HJTsUV5)122M(%' LMTSRFH47=>`R2!!#!R92[J1 3 30#"'&'&'72?R=!*) ' ,$  k3^1n   f  dt %.&'6767054&'&5'476730Lim~[H2dqVoP`iKgꦂdS5Elכ] Vt޺P$5f1 !# # 33f:ȪHNy02 %#5!3!3c2[\2!3##"'&'&'&=3327676765$rSBC14fDE2724Zx!"BGhl_FL:;B"%8:MPS}3 )3;33Z[}/3%#5%3;33Z[[ 52&3#5!32+327676767654'&!zjl@$2+猌fDG+) 6!!,K?2/&ZXM@ #!*3k2*3#3320+327676767654'&!ԗ_jl@"3+茌gDG+' 622!!,L?2 &&YXM@ %!*1%3320+327>767654'&!jl@"3+茌cHKN 62!!,L?2 &&YXM@:%!+eF4'67632#"'&'&'&'732767!5!&'&#"5VUsTJH86)(;:jh=57)2 z +'+XGGZE=<)B`>=74HFRSTML '%(Mv_]x22ayQ.U33367676767632#"'&'&'&'&'#4'&'.'&#"3276767676aa **9;PTCB*) ,+>7`O:51V..?jK:OP85/+)**?7@<uK2 "'#&'&5476!3#`0dM.LM::!.IgeJb<'Cp}b'jr}tD!##5353!!67632#"'&'&'72=34'&'.#"?PQsRBE02#("("*$#$kffDF23"[;``HJI&'&'&'&'&547672&#" #"'&'7327654'&'&'&>'*2/""deR), 6Qt 112-+$lk\_%45[e::"'$#.1;KL,&)$%zNH&  !'/6AZYCEnC$$00U)" ?L#O'jD\TfMH.20A!320+##"'&'&'727327676767654'&!#jl@"3+!茞M #&%) *$#$kZ 1gDG+' 62!!,L?2 $(VX|U2 #  "f {u %!*X62.!#373320+327676767654'&!jl@"3+!gDG+' 6S2V!!,L?2 $(VXM@ %!*-!#534'&'.#"##5353!!67632fDF23"?PQsRBE02ZKO7;B"#:AFKX[;767654'&!jl@"3+茌cHKN 62!!,L?2 &&YXM@:%!+y"3 4'&'&'&'&+';2+# '+GDgΞ艋!"@AjkΞ#*!% XY0%WJK99!!TN"2676767632#"'&'&'&'#4'&#"3276& 52>f^/.ONfA/2##MLtuOPPOutLM1,$ $\`enlebSQ10 "&*srstvttv\!67632+&'0'&%!!#  0  e )   ^!67632+&'0'&!#!  0   g*   V2 !!!!##53\ *֞fo0 !!!##53!\?6276=4'&'.#"+!!>32+6gJIfDE27 rSBC14#JA@PAJI!_FL:;B"%8:MPSYZx!"BGhl >CE= ^2{Ln^^~2~q _aAJyby5yby5yby5yby5yJef03y3!!!+!#y ^f3 3%!!'!#ff2)׈U.yJgy2dieFdieFXjR2BZ3 3#BddBX<x?16#"'732767676=#"'&'&'&533276767653&$?`?LLn.&O^^~'W~y33 52>5#yx-(.hQU 0 /$ϼs?Na!&( %<'y5!52>5#33 /3.hQU 0 /$Ha*&( %<'k0PT$!7##"'&'&'727\З #&%) *$#$kWP#\2 #  "f {E*}2!7##"'&'&'727]M #("("*$#$kZ 2|U2 $  "f {yO%52>5!#3!3O-(.hQU 2'6)*k?Na!&( $;'^Pf83!52>5!#3%8-(.hQU 5%8',f?Na!&( &<'-2)yJ 3!3!#ypkP^f*03 3%7!#fDf2)-b%3#53#"'&'&'&53327676765G4sRBC1443CF25 P Zx!"BGhpEZKO7:"!"$9>IPS 2$3#53#"'&'&'&=3327676765$<1rSBC14fDE2724Zx!"BGhl_FL:;B"%8:MPSy 33 37#yaTT!P\Lb42 33 3#bPOj2`$$7,H.&Xjw'cxH"%-4632#"'&'&%4632#"'&'&!!#3#8&"28& )8&!8& P%  n&8*! '8!&8! '8!]Pjw"2X4632#"'&'&%4632#"'&'&"327654'&'254&#"'632#=#"&54768&!8& )8&"28& HlHFGIj`HFIJ{fNL ~vB@;#Nڋ !537lmN&8! '8!&8*! '8!FEcgCDFEcgCD761`#hm{!ΧkkSg!#!!!!!!53OFF{JT`Fx"327654'&'&67632!3267676767>7>767#"'&'&'&'&'.'#"'&'&5476326'&74'&#"'676767632!&'&#"h00"\6742<;!32>!4'&'&'&+"'67676767632#"'&'&'&'&5465 ҩrZL55STijSU %'11DGHxcd03.^GDu_PS5:$[!Ovlj\[5678Z)$.+'(++chjqtsJGR.24:%bF 0!3276767.#"'67632#"'&'&'&54&= FGoK<;>rNIFG4gju_`0112_aaOM42͑hi65PN_j'';7d:;LL{~IJ-,NK]_c!0'jb'jXLn'jD^^~'jX~q 'j_aA'j.q _aAJy !!33##8[둝jZPwz+ !!33##[X+j",y'j`z ,33##4632#"'&'&%4632#"'&'&z*8&"28& )8&!8& 2",N&8*! '8!&8! '8!\&2jf&Rj{\'<P47676767632#"'&'&'&'&%!3276767676%!&'&'&'&'&#"\,+C@ge{zbdBA-,,/?CefzxcbDA-+!0.GFT^IK-- ! @  0.FCX^// gehfdRO21./NLa]ltmbghbiIM00--NK_[lm4SOKJA;9 '(;OIC<9" P@?UTT+bF"/ #5"'&'&54767!.#"27676?!a_210/caac/012_# pL<:<:<FJI~{|OMMO|{~I`65ON65ONZ _QN7\'<Pas47676767632#"'&'&'&'&%!3276767676%!&'&'&'&'&#"4632#"'&'&%4632#"'&'&\,+C@ge{zbdBA-,,/?CefzxcbDA-+!0.GFT^IK-- ! @  0.FCX^// ,8&"28& )8&!8& gehfdRO21./NLa]ltmbghbiIM00--NK_[lm4SOKJA;9 '(;OIC<9" P@?UTT+B&8*! '8!&8! '8!b"/AR #5"'&'&54767!.#"27676?!4632#"'&'&%4632#"'&'&a_210/caac/012_# pL<:<:<8&!8& )8&"28& FJI~{|OMMO|{~I`65ON65ONZ _QN7&8! '8!&8*! '8!d?Qb7327676767!5!&'&'&'&+"'67676767632#"'&'&'&4632#"'&'&%4632#"'&'&d [ZkcST58X45STijSU %'11DGHxcd03.^GDu_PS5:$&U8&!8& )8&"28& %)\BA34TYkKOYLoZ[5678Z)$.+'(++chjqtsJGR.247&8! '8!&8*! '8!e4FW'67632#"'&'&'&'732767!5!&'&#"4632#"'&'&%4632#"'&'&5VUsTJH86)(;:jh=57)2 z +'+XGGZE=<O8&!8& )8&"28& )B`>=74HFRSTML '%(Mv_]x22&8! '8!&8*! '8!#!!3 3#"'&'&'727x[dd  &%) + ,$#$k3RjX #  "f MJ)#!!3 3#"'&'&'72?[j=!*) ' ,$  k3^)jn   f  'j=kJ'ju&kJ='b&jho'j\[^2{yK'js3k*<M3#3320+327676767654'&!4632#"'&'&%4632#"'&'&ԗ_jl@"3+茌gDG+' 6f8&!8& )8&"28& 22!!,L?2 &&YXM@ %!*&8! '8!&8*! '8!y='e%'eEy'w'I'G!84&'&'&#!!2>767#!!247632#"'&'&@<:QPc ax! --QPpmWySS21>E=F؆PN++iVliba98d\[E > F > 8O3#5+"'.547676763232767>54'&'&'&#"47632#"'&'&I>?OLCDf<21DE[l ().<13'(,'%52@0'(>E=FPn)*$$ҎsjcLJ**gKT5:!";<\ZIJ;8#!73RHE > F > y(&'I(&Gy')}' IU !3!3#!#476320#"'&'&ju>E>F~N^E >  E > 2!#36767>32##"47632#"'&'&#-$#"#:*532*(>E>E8"!n-+)788xE >E >ytJ&+t&ńK!!33 ##]Ctb:D g!! ##33]G-h5A 3!!47632#"'&'&c6=F>EۍF > E >  %3"'&5347632#"'&'&8vCB>E>Ei:9u\E >E >  !!3!!47632#"'&'&f\c6=F>E}ۍF > E >  $!!3"'&5347632#"'&'&B]zvCB>E>Ei:9u\E >E >  !!3!!]ucۍq %3"'&53!!8vCBVi:9uňy'h0'_P #33 3##47632#"'&'&ϚTT>E=FN[KE > F > I+B!#4'&#"#3>32>32#4&#"47632#"'&'&a**K4-/%$.?zNIHTJIVI4-/%$.=F>EML('n?l2cLo^mkr('n?xF > E > 47632#"'&'&33#29>9>Q䞒>7 > 8 uNYb047632#"'&'&#3632#4'&'"9>9>}P 77Q252-(> 8 >7 2A"%$'nJK+&96< 333#47632#"'&'&䞒>E=FuNYE > F > I2!#3632#4'&'"476320#"'&'&#}P 77Q252-(>E>F2A"%$'nJK+&96  E >  !!33#o]䞒uNYI !!#3632#4'&'"]+}P 77Q252-(2A"%$'nJK+&96<y'k3T'tS[23 4'&+ ##!2476320#"'&'&!bcSמmvegHJ(*a`v>E>EBCw35KOaml!vE >  E >qM0&#"#367676763247632#"'&'&DG/++!"!%!tY=F>E**(<:H|2&#7F > E > [ 6!!3 4'&+ ##!2476320#"'&'&])bcSמmvegHJ(*a`v>E>EBCw35KOaml!vE >  E >R74!!&#"#367676763247632#"'&'&R]LDG/++!"!%!tY=F>E7**(<:H|2&#7F > E > [ !!3 4'&+ ##!2])bcSמmvegHJ(*a`BCw35KOaml!vM&#"#3676767632!!DG/++!"!%!tY=}**(<:H|2&#7_- '6`H'3VL>?V7327>7654'&/$47676763 &'&#"&$47632#"'&'&LZZYnF<=Z^Zn#">?RS` %}2WVp<64*'.ϐNX/2%&BA\\jH>E=FP:9R56BaJG7lRKI674OW10$!`:S34%*,/:8ZYMO98##E > F > kSKD[&'&'&'&54767676732&#"# '7327676765447632#"'&'&k>F%'/,AEL:>:02 (%$(+dKD.*32PE!.$'=E=F# $#$,+/:84*((*6y #g3%($+'/03?>:-,6"!-{hF > F > X'7fP'Wb!!#!476320#"'&'&bE7">E>E$E >  E >q[,)#53533#;#"&547632#"'&'&uEEv=F>E,uzv9F > E > b !!!!#!a\E7"Î$q[,#53533#;#"&5!!uEEv,uzvT'C:D1='C&ZT'v:D1='v,ZT'j:D1'j$ZVp47632#"/&3 3#9>9>QeeA>7 > 8Y:?bD47632#"/&73276=#"'&'&'&533276767653#"':?:>i>26GoHH%DEOGFE64"!>?o2,+$ 64NJY> 8 >7TGJJH01 ;8VRizQS+&;9A^KM;8$"!!#36767>32##"\9-$#"#:*532*(8"!n-+)788+!5276767654'&/!"#47>Njm@X02L\\jB?>--^Ro%&*(-/:8[Wp#"()54DbHA.+' ~XLd'C<x?<'C\\~'!5!3"'&'&53dqAEP#<K%(V#"@!!3"&'&533"&'&53@dqtdqj" KJY#"! KJY#"Zw<'lIZw='@TJZw<'I'CZw<'@I'CZw='I'vZw<'@I'vZw'')Zw''@/H'H'@[&'C\|['C`|[&'v\|['v\|['&|['&|k='IJk;'@323276767#"'&'&'&'&#"1F% 8 " !1 !"" "$B  &   9"Q4632#"'&'&%4632#"'&'&67676323276767#"'&'.'&'&#"8&"28& )8&!8&  !#%#0%$/ 1 !"""$! *I&8*! '8!&8! '8!W-$ &   !vt:'0'CutN'-tt','v32#'&'&'&'&   u<&- )H8    [ #2 - $Kg$&+(0dL2%632'&'&7476%47>32#'&'&'&'&  <&- )H8    #2 - $Kg$&+(01y+F67>323276767#"'&'&'&'&#"4767632#'&'&'&'&1F% 8 " !1 !#! "$BD',@'H8    &   N $@, #Jh"+'+v' v &q v'Cl['j*[ v'v['j+^ Zt<'AI Zt<'@GI v<'[ v'E'j,[ BZ.&BZ'q=}'C\'v\&@<(9'%&'&547676324632#"'&'&%4632#"'&'&   l8&"28& )8&"28&   n&8*! '8!&8*! '8!P):%632'&'&74764632#"'&'&%4632#"&'&  8& 8&!)8& 8&"2   &8 '8"&8 '8*"<#"'%&'&54767632       7'Cb7tH&7t<'v67;'7t;'6v'C\'v['C\x5'v\t5&<%632#"'&'&5476L      dL;47>32#'&'&'&'&d<&- )H8   #2 - $Kg$&+(0v:!!v;Ȏv:!!v;Ȏ!!X!!R!!:!!ȎE2###222SD*_>6c4:NjDAMQDr'MHMa>'NJNq2R[>|Q * #!5!3!)uuU*!!#!5!!5!3!)v1ώ;eHi47632#"'&'&;oDTM nDTM gN/n,3M/n,3 2F kF\33"&54767632,@$ ->( @,(>-( \#3"&54767632!"&54767632,@$ ->( D,@% ->)@,(>-( @,&>,) \#5!"&54767632!"&54767632!"&54767632d,@$ ->( X,@$ ->( D,@% ->)@,(>-( @,(>-( @,&>,) D I47632#"'&'&MLm_GFMNk^GFGlKK:8[lKL::YsiE <\i2654'&#"32654'&#"#3476767632#"'&'&'&476767632#"'&'&'&2654'&#"476767632#"'&'&'&()xX+,=3Zl''A3/4#(()xX+,=3Z%$23<122&(0%&10>3/4#(uI()RHB**NyH()RGB**N M501&%$"#dB7.0%% %/1501&%"#21C7.0%& %/2I()RHB**NH501&%"#dB7.0%% %/1 si DE <\i2654'&#"32654'&#"#3476767632#"'&'&'&476767632#"'&'&'&2654'&#"476767632#"'&'&'&%2654'&#"476767632#"'&'&'&()xX+,=3Zl''A3/4#(()xX+,=3Z%$23<122&(0%&10>3/4#(()xX+,=3Z%$23<122&(0%&10>3/4#(uI()RHB**NyH()RGB**N M501&%$"#dB7.0%% %/1501&%"#21C7.0%& %/2I()RHB**NH501&%"#dB7.0%% %/1CI()RHB**NH501&%"#dB7.0%% %/1'476;2#"'&'& $ ,,'46;2#"'&'&%'476;2#"'&'&,  $( $ FD3##mD###g"3F#&'&546324632#"'&'&#&'&5476324632#"'&'&V)<&(@,(>-()')<@,' ,'(6%,@$ ->$ f)6&,@$ , $ 7F%4632#"'&'&? 4'&#"'67632#54632@,(>-( 4 MK~SHyzXLO|L%&= >2$ <&(^,@$ ->$  ,!&}EDZ|9oo^`aIK>..>S8(6%c%#"'&'5!2767cٲרn@@>>rJJt ZR ''!!''!!''!!TTTTTT6TTT/'7'7'77'd8RR88RRR88RR88R"m?#3)9$%4632#"'&'&%4632#"'&'&#54767676? 4'&#"'676326732#54767676? 4'&#"@,(>-(@,' ,' 74 MK~SHyzXL9,MENO>@%&&):$=1& 65 MK~C< &%&= >2$^,@$ ->$ ,@$ , $ +*)# .,!&}EDZ|9oo@/1MOJP9..>S+*&# .,!&}EDO`aIK>..>91CVi67032#54767676? 4'&#"#&'&5476324632#"'&'&%4632#"'&'&9MENO|L%):$=2%  65 MK~C<@)'(@,' ,'@,( ,(@^`aIP9..>S+*)# .,!&}ED)%,@$ , $ ,@$ , $ g 2EVi67032#54767676? 4'&#"4632#"'&'&#&'&5476324632#"'&'&~MENO>@%&&):$=1&  65 MK~C<@,' ,')')<@,' ,'@/1MOJP9..>S+*&# .,!&}ED1,@$ , $ f)6&,@$ , $ yu$<"&#27636767676767654'&'&'&"#!32 dP* &'#'"KZhŌywfc9:  /)5 L ;  "2')#u10NOb&-/)+ 3'#'&'&'&54%6;N! o y 6n->(*oL732#'37 !N Lo*(>-n6   Z ''!!`TTTZq#H,74767632#'&'&'&'&47632#"'&'&q(,@(H8  -&<@+'^ $@, #Jh"+'+- 2# +@$ >'%)%"'&5467632"&54767632#3A- 2# , ( ^,@$ , ( %ѐ -&< ,' @,' ,' D?3\+67>323276767#"'&'&'&'&#"?F% 8 " !1 !"" "$B  &   m?%72#"'&547676#"'&'&54632#"'&'&54632, $ - * >-&@,( >-&@,(  -( ,( .>" +@) Y.>" +@) m'9K2#"'&547676!2#"'&547676#"'&'&54632#"'&'&54632, $ - * , $ - * )>-&@,( >-&@,(  -( ,(  -( ,( .>" +@) Y.>" +@) m%8J\2#"'&5476762#"'&5476762#"'&547676#"&'&54632#"&'&54632!- 2# , ( - 2# , ( - 2# , ( ' -&<@+'  -&<@+'  -&< ,( d -&< ,' N -&< ,( - 2# +@( Y- 2# +@( d;+##"'&'&54632#"'&'&54632:@,&>,) >-(@,& ,@% ->)[.>" +@( %+':N2#"'&547676%2#"'&547676#"'&'&547632#"'&'&547632- # , ) - $ , '/@,& ,)  -( ,&  ,( -(  -& +( ,@$ , * ^- # , ' d<s%8#"'&'&547632#"'&'&547632#"'&'&547632;@,( ,' @,( ,' @,& -) ,@$ , ( Y,@$ , ( E,@# , +dm<+#5H#"'&'&54632#"&'&54632#"&'&54632#"'&'&54632:@,&>,)  -&<@+'  -&<@+'  -(@,& ,@% ->)- 2# +@( Y- 2# +@( E- " +@(0Q167>32#"'&'&54326767654'&'&#"B!!lBd~XcCA &0 % I;;HwHMqX\xLJwFJRR:>I('*('214D=E)'*+091@#73#{aDPB'767632!!5476767676?>?4&#"ʆ JIX&D !.   ( _ !. <&( #5O87:,-0 ,#406 '!"!5<.3S>7327654'&'&'&+5327654&+"'767632#"&'3 < 8&% JT"4"  9:H885##QRtHs+!(!!6($2 > >%%65A1)'&$-rIJXJA 3##5!335$^^WcW60H2'!!632#"'&/732654'.#"-    o7)&_CE>;PbFH "V2> >"N9} 9:\ &I?=*(9:Z%cJA.:0714'&'&#"3262#"'&'&54767676?3  +1  (3Bv_FI h8bBE  ("#-&B.9;Y .,0"#.;>S '*52l #!5lЧ:c%6I#"'&'&5476767&'&5463232654'.#"27654'&'&#"AA ! LA@JaLK-fY#)2.&-.Z5'& #%-9F "$0O^= !?Lx#";;\/'& *>`~.(".%$3)@7 *-4:327654'&'&#""'&'&547676767632#  +2  !'2" u^GH  ,*.`ED  ("#, (" ::Z&$&<;V! " -F  533##5#53P4(!!P(@g!!!!@**C<lr&5476?3#'&]! ? &~#"9& <Doxgrlc7egcT7^3rh#767654'&/3%= !#$7% 9"# >r7[dd_ehkP7Zotqmon_B&!#3632#4'&'&'&#"Ԓ2D/*'   _$)%>@I1+! #+0Q1767>32#"'&'&54326767654'&'&#"B!!lBd~XcCA &0 % I;;HwHMqX\xLJwFJQQ:>I('*('214D=E)'*+091@#73#{aDPB7'767632!!5476767676?>?4&#"ʆ JIX&D !.   ( _ !. <&( #5O87:,-0 ,#406 '!"!5<.3S>7327654'&'&'&+5327654&+"'767632#"&'3 < 8&% JT"4"  9:H885##QRtH+!(!!6($2 > >%%65A1)'&$-rIJXJA %3##5!335$^^Wc W60H3%'!!632#"'&/732654'.#"-    o7)&_CE>;PbFH "V2> >"Z9} 9:\ &I?=*(9:Z%cJA.:0714'&'&#"3262#"'&'&54767676?3  +1  (3Bv_FI h8bBE J ("#-&B.9;Y!.,0"#.;>S '*52l #!5lЧ:c%6I#"'&'&5476767&'&5463232654'.#"27654'&'&#"AA ! LA@JaLK-fY#)2.&-.Z5'& #%-9F "$0O^= !?Lx#";;\/'& *=`~.(".%$3)@7 *-4:7327654'&'&#""'&'&547676767632#  +2  !'2" u^GH  ,*.`ED  ("#, (" ::Z&$&<;V"" -F 7533##5#5?P447!!P4@s3!!!!@**C~7Zed_ehkP7Zotqmon_?  ,"327654&#"'&547632&'&#"'762#,(22( 44!!^@?ABZ;% + SKĂ$2"$0#$0 >>b_?@ o>t' 0 273&'&#"3276?#"&'&54767632!µ&   zDMr:8M:/16<$%!6";DZGFWUGE-+T50;#*%0/76767632#"'&'&543276767654'&'&": 31=Rt:;RR:; $  F0o8,*VGEGF----GIT==(#& &,7'(*N4G #'#373Gc_`_0.1 5#327676'&'&#"'767632#"'&'&'&5050=!&b&   =>CL:9;:K:/0HR$%"6";"#.-GITSID-,+*50:$D I47632#"'&'&MLm_GFMNk^GFGlKK:8[lKL::YD I47632#"'&'&MLm_GFMNk^GFGlKK:8[lKL::Y*)!&'&5476767632&#"!!!!!mFE/.EDQYB}JV*'%4,:MU,8u$ 39@#"'&'#7&'#&'&54767>?3273&'326?&#$T^`# )N4 37^'# %3M?w& Q+%* !d<<}567m!Qpl{ouTZ|2`;#6;3 *#Ckb@YJ#"'&'&5476767632&'&+"3676767632&#"2767؁^ilwolTR`,*RPnofiM.SP]]OQ9< '$65<"!%!tYBDG.,+! *ZFI.%C;=21cali<<;=sBB0.12TWqpkWYMI::##7|**)xEBDU3#535#53!!!!!!wwww..y؇S;؇d6/37632&'&#"!!!!!2?!76767#537#d k!d9'io~"7+P-y+;T  i6 q`>OF32673;2$++J- ͝j**L3-/%$.?zMI-0iHILKnEdML('n?l2cLE09kk#&)##!##535#533!33#)'!35!%35#wwwwwykwwU55yy؇SS؇HRnTel%#53533#303%276767654'&'&'&'&54767676;2&#"#!"'&32!#3 !Un.$)k>C'(.,BAO9>;02 ($$(+hJC.+32Qb;:yfcIG)(88؇,u ##+~E# #$%+)1=67)'(*6y #g3"'$,*.,8A<:-,6=;[42NLgop$ ^hz#"&'&'&'##!23276767654&'&'&'.5476767632&'&#"4'&'&'&+32767>^%'66JHBLDJ>=0؞m[h^SPb01C>P~I9(Z0289A&,')#T?T4H@?T4/BAB4;823!# =?@"H *&C2VFB>+*#"86FBGL?G57D)K;?)*.-G20pRCE01# oP9@ &$->N$$$fUG;6'$ *,9F$8" '%:9S54 j? 4 7!?#!'#!7###!##53'#53333333#3xNP-+2A.->19RP>0 A-WX&p]GGO)T8vciv.(330#53>32.#"!!!!3267#"&'#53&54'}q}M`2XQ<_,"i0E\>`<9[7&:K`3+ZJ MW+Da/!!!###53333!!ucwwLwfgzz+p!%%#5%55%!5!p755˞NN"E$mmmmwwww| +#324+32 3 !0IHF|MNFFW f1 +h<;77o`X &Gd3276767654'&'&'&#"2#"&'&'&54767676324'&'&'&'&'&#"'63>!!0.BA43'",+=;B5),=&V#,$:92Z55OOpm31/1FF_4*'B / -(9:<)%%-& 7<=45"! 4-C=<>?>..$'1585 &>6FMDUY2_c`PO21LB@[XgQVUAC** $ , >SERH;<)r',7!323#3#+##535#535!2&+4'&'!!676>'qFFq<~Ϟwwwwm_PLWPч    k:;Ws67mLL  s  ,8#5&'&'&'&54767676753&'6767#53+*CARQDG1410GDXU#DFT64\/'&~gXYDB/-+-EJ`a}l\_LJ64x5B_QO9B'&84GCM!#!##537!5!3!!3# '!2@@1up;+)䇇8Ȉo+n\!327676767#"'&'&'&54767#5367676767!5!654'&'&'&#"'6767676323#!n 8/0;<@E67-,') V]Y\CE++Du1,;.AH<()53;i5}/-/63D>P3X,B;$Dn'(#"032P68NOe &" =H!":@SY]_:;# "'&5!##533!33#3 B@@www:9u_66piLOju#5#"'#5&'#&'.'&'&54656767667632>32676767654%'$476767632&'&#"4#"37'54#"'54'&#"OlKOTTK4gG>T  $!T8$E<4,. "n#">?QRbkmG%}3UUq=63*),34hy]W0/-(?@-(+- QFGn&( =5H^!L  " $1)V0&Z\q"#,.492eoRKI68./e4OX00$#^:F9:%3,*'.,?Sg#"'&'&'&'&547676767632&'&+"32767;27654'&'&#"47632#"'&'&".-L_PQ76.8' 09;RO`=67&## xDCTFBG.1#(/luNIH{!&"'@4167KB208>4206))HDcxUTTGgEG-+,)'*))Z879=QXpmyzn~LB?^I (+L45)(?K55)'@"]+#"'&'&'&'732767654'&'4!5]c;6:jh<5;'. z )',X:.fj+YmUxML$ %(MvNp FZx>y+5!!327654'&'&#"47632#"'&'&33# v ('4<** ('4<**vLLn_GFLNl_GEf:71"!+,?2"!,+ClKK:8[lKL:9Z>P2y"3 4'&'&'&'&+';2+# '+GDgΞ艋!"@AjkΞ#*!% XY0%WJK99!!yP32676767654&+ ##;2\'( Sמcd"&$%,|wlmnnxw* 33##!###+sĉt_ bwM>7cP5K%&'&'&547676767632!!5676767654'&'&'&'&#"3!7 ?,+,+C@ge{zbdBA-,,-HK9;!  0.FCX^//!79EI^[lmlgehfdRO21./NLa]ltmbghbeK(@BRUORUspOIC<9" P@?UTUrhKJE9: 10+B327673#"'&'&54767632!"%4'&'&#"3!276 20FHOmacBmpk?7ه{ f  $!15>/R K R K &>DH7327654'&'&'&+5327654&+"'767632#"&'#73#'[ < 8&% JT"4"  9:H885##QRtH{a+!(!!6($2 > >%%65A1)'&$-rIJXJ 9A7H5B'767632!!5476767676?>?4&#"732654'&'&'&+5327654&+"'767632#"&''Ά JIX&D !.   ( _ &. <&( # < 9J JT"4"  9:H885##QRtHË5O87:,-0 ,#404!'!'!6<.+!(B6($2 > >%%65A1)'&$-rIJXJ]9A739=%'!!632#"'&/732654'.#"#73#'M    o7)&_CE>;PbFH "V2> >"W{aZ9} 9:\ &I?=*(9:Z%cJA.: 9A7L-Bvz'767632!!5476767676?>?4&#"'!!632#"'&/732654'.#"'҆ JIX&D !.   ( _ &. <&( #    o7)&_CE>;PbFH "V2> >"S5O87:,-0 ,#404!'!'!6<.j9} 9:\ &I?=*(9:Z%cJA.:]9A73->rv7327654'&'&'&+5327654&+"'767632#"&''!!632#"'&/732654'.#"'3 < 8&% JT"4"  9:H885##QRtH    o7)&_CE>;PbFH "V2> >"Ss+!(!!6($2 > >%%65A1)'&$-rIJXJ 9} 9:\ &I?=*(9:Z%cJA.:]9A7A- @D3##5!335'!!632#"'&/732654'.#"'$^^Wc7    o7)&_CE>;PbFH "V2> >"SW69} 9:\ &I?=*(9:Z%cJA.:]9A717;4'&'&#"3262#"'&'&54767676?3#73#'  +1  (3Bv_FI h8bBE {aJ ("#-&B.9;Y!.,0"#.;>S '*5$ 9A722Edh'!!632#"'&/732654'&'&#4'&'&#"3262#"'&'&54767676?3'6   n6)&`CE>;PaGH #U3> #  +1  (3Bv_FI h8bBE O9} 9:\ &GA=*(9:Z%cJA /g ("#-&B.9;Y!.,0"#.;>S '*5,9A7%6IOS#"'&'&5476767&'&5463232654'.#"27654'&'&#"#73#'AA ! LA@JaLK-fY#)2.&-.Z5'& #%-9F "$s{a0O^= !?Lx#";;\/'& *=`~.(".%$3)@7 * 9A75>du7327654'&'.+5327654'&+"'767632#"&'#"'&'&5476767&'&5463232654'.#"27654'&'&#"'5 < 8%& 0JT"! ;:H885##QRtHAA ! LA@JaLK-fY#)2.&-.Z5'& #%-9F "$os+!(!!6($ > >%%65A/+)('*rIJXJ{0O^= !?Lx#";;\/'& *=`~.(".%$3)@7 *r9A702Xi|'!!632#"'&/732654'.#"#"'&'&5476767&'&5463232654'.#"27654'&'&#"'-    o7)&_CE>;PbFH "V2> >"AA ! LA@JaLK-fY#)2.&-.Z5'& #%-9F "$oN9} 9:\ &I?=*(9:Z%cJA.:{0O^= !?Lx#";;\/'& *=`~.(".%$3)@7 *r9A72+<OS #!5#"'&'&5476767&'&5463232654'.#"27654'&'&#"'lЧAA ! LA@JaLK-fY#)2.&-.Z5'& #%-9F "$o0O^= !?Lx#";;\/'& *=`~.(".%$3)@7 *r9A7 #73#'{a 9A7733P\!3!3>PP !3!3!3>>PPP 3#33mGBPP{3#3)GBP{ !33#3U7GBPP{!3!33#3z>7GBPPP{!3!33#3z>7GBPPP 3 3 # # 3jc;˾^)'J'PJ 3 3 # #Jjc;˾^)'JJ!33 3 # #jc;˾P^)'JJ!3!33 3 # #6>jc;˾PP^)'Jy3!!yeݍd@#"'&'&'&'&547676767632&'&+"32767&$:5SO`ufdEG/21/HFdcxIGB21'(VSihTV4365URdkZ[ %@742.)(HJ^eikxtqmeaKI++(*()))Y9768XWrmyxonVS53AB\y)4'&'&'&'&'&+327676767#!!2 %*,2HIS~\[55''JIprDpqIK&'E=F?D8@(.j**PQfhdc78=>ehy 33 3##yϙTT!P\Ly54632#"'&'&3#y8&!8&!5&8! &8!yZ&*4632#"&'&3#4632#"'&'&3#8&"8&"28&!8&!5&8" &8*!5&8! &8!y&*<@4632#"'&'&3#4632#"&'&3#4632#"'&'&3#8&!8&!8&"8&"28&!8&!5&8! &8!5&8" &8*!5&8! &8!y54632#"'&'&3#y8&!8&!5&8! &8!R1!3 31nR4632#"'&'&3#!3 3B8&" 8&"i5&8' &8 1nRH%);?F4632#"&'&3#4632#"'&'&3#4632#"'&'&3#!3 38&"8&"28&"28&!8&" 8&"i5&8" &8*!5&8*! &8!5&8' &8 1nR#&*14632#"'&'&3#4632#"'&'&3#!3 3g8&"28&!8&" 8&"i5&8*! &8!5&8' &8 1ny !!# # 33 4632#"'&'&3#:Ȫ8&!8&!HN&8! &8!5f1 !# # 33f:ȪHN5!4632#"'&'&3+ # 338&!8&!:Ȫ5&8! &8!HN5&*64632#"&'&3#4632#"'&'&3+ # 338&"8&"28&!8&!:Ȫ5&8" &8*!5&8! &8!HN~ %3"&'&53dq KJY#"eF/&'&#"327676767#"'&'&547676767632<=E+'+ z 2)75=hj:;()68HJTsUV5)122M(%' LMTSRFH47=>`#23#5#"'&'.'&547>32327654'&"6"#2/BPEB.,@ ^f?15 &MLtuOPPOLLR*&"  75PTUne`\$ $,vttvtsrqN5!#4'&'.#"#3>7676767632>32#4'&'&'.#"V ,H5ژ ($0tJKm *B+#N1=37N.a1*! DEihs;/6+8$<g>.E_#!5#"&'&'&'&5476767676325!23276767654'&'&'&'&'&#&'&+"3276('qrD6FP`tDG/11/HFdcwIGB2 pq'([[55 %*,3FITn MSjhTU4585TRdlZDח88?*RGJ^ampsovmeaKI++ 5=>ʃj**PQfgE=?FD8@(.pQ3767YZomyxokYT43A0y)4'&'&'&'&'&+327676767#!!2 %*,2HIS~\[55''JIprDpqIK&'E=F?D8@(.j**PQfhdc78=>eh&'>O4'&'&'&'&'&+327676767#!!2;#"47>763!!"'.'&. %).3EIT\[54('qrDpq'(55[[TIF3,*% ('qpDrq'(E=F?D8>*/j**PNig88=>ʃhfQP**.(@8DF?=E>=P88ąd<73276767654'&'&'&+"'67676767632#"'&'&'&d [ZkcST5845STijSU %'11DGHxcd03.^GDu_PS5:$&%)\BA34TYkoxymoZ[5678Z)$.+'(++chjqtsJGR.247eF/'67632#"'&'&'&'732654&#"5VUsTJH86)(;:jh=57)2 z +'+E=<)B`>=74HFRSTML '%(Mõ22d@#"'&'&'&'&547676767632&'&+"32767&$:5SO`ufdEG/21/HFdcxIGB21'(VSihTV4365URdkZ[ %@742.)(HJ^eikxtqmeaKI++(*()))Y9768XWrmyxonVS53AB\BA 7%{eg,{f*hy)4'&'&'&'&'&+327676767#!!2 %*,2HIS~\[55''JIprDpqIK&'E=F?D8@(.j**PQfhdc78=>eh&'>O4'&'&'&'&'&+327676767#!!2;#"47>763!!"'.'&. %).3EIT\[54('qrDpq'(55[[TIF3,*% ('qpDrq'(E=F?D8>*/j**PNig88=>ʃhfQP**.(@8DF?=E>=P88ą01pt67>32#"'&'&54326767654'&'&#"7327654'&'&'&+5327654&+"'767632#"&'#3B!!lBd~XcCA &0 % . < 8&% JT"4"  9:H885##QRtHѐI;;HwHMqX\xLJwFJRR:>I('*('214D=E)'*+09+!(!!6($2 > >%%65A1)'&$-rIJXJ.x% !!x@& '#@&x!5!' R&@%37 (@x  !' 78@@@@ %7  ':@@@@4X4jn\tlZZn4X%''lZZnZn4X 77!ZnZn\4X !n\rn\ZjxXh! !3!!#H@@llx^jHxXh!' 7!#!5!3@@jjl HH%327632'&#"#&/,^^PMfaG7p@J,`^^^^L,OBp, 2N"$#"'763232?'8[`]/H@p6HafKP^^N1 ,pBO,L^x 37!!'# 8"@8@"@  '#75 :"@8@"@x #7!5!'3' R"@8@"@ %5'377 "@8@"@x< ! !73#$@@였Ȁx< 7#'3!' 7!Ȁ@@x 53#5! @@f@@  %3!53 '8@@@@@x 53#5! @@f@@  #5!#7 Z@@f@@xt 7!!7  'xddd@@v@@x^! %#Z@@&X&|!#' 7!&@@Zx^3! !ހ@@(|!' 7!3@@ڀ@x5!7 xT*@@Vx3! !@@(HB &'&'&'0#"767676303GJ U+d^R4l ˩ZWΡXZHMIO:\T_ZmlHB 6767670327'&'&'�#HWZ ƥl4R^d+U JIşlmZ_T\:OIMHZX4X !!!4jn\Z$jZ\n,x  !!3!5!' 3@DdF@0dȀZ`/3276767654'&'&'!#"'&'&5ghkl3+:)i5CXRO= 1G:;~ /36%ddrk/*A/`<7M98yz ,A@9?o0`/#"'&'&'&5476767'!'3276767650 ~;:G1 =ORXC5i):+3lkhg?9A, zy89M7<`/A*/krdd%63/x `!x@@ @x !f@ @ '#@@f@ #@Z@fx^5!'x@@x !5!f37h@@3fBx  !!!5!' x@&&@ ʀJ@ '#37 J@&&@x %!5!' !!R&@f@&x6 !!-!!->,:8.8 #%#j,:8.8x6  7!5! 7!5!:,:8.  3% 3:,:8.x 7!=!@f@@@x !=!'f@@@@ b '!!!!eh""nTZHHU!  #7#!#UnTZHH@lh"" b '%5!5%!5e""fZHHHHHU! 33!3ZHHeh""  '%5 '!!!!eeh""fZnTZHHH %!'!3#3a%QPRK327654'&'&#"#"&'&5476324'&'&/&#"'632 KLHpVV_]h:53:>FB|{ no+"(   548tE[%N$.1/uDDlm'rOM53F{sp$!5H=K&㙗HPć   !(^ih2VFy )5!!5!!5!g0^X&$7H47>76763273#"/#7&'&'&7&'&#"%3267>54'&'&^ dECFCGmY;_% JKtrld ]'P u '" 97BFB<9%#zm:*"Y}8>2,L8#/.OLf 420Z.(L<4x33%!xFE#n`Bx!# x>`B";#"'&'&57676;#"!!SRVresssseuSQSgf$-;;-&dgm<!&.#&57676?33#!!;#"'&'# x\ss`}AAS|COVrecd@;QS;-]EE+%_ &dg:^Bq 5! #!5!276767!5!&'&'&'&#:f?ssefvRSAk @>hfСƀ-$\I_?42n@!#!#nҞjPn@33!3nP@:y %5 5% %(lP0<D:!!DDȎIH(;#"/#"&57#"'&54?'&547632'46327632@ ') *' (( '* )' }q"*& *" (+om+( "* &3#!5!]ۯڡ3'uC&~DCC3276767654'&'&#"&'0'5#".54767676326763"30/BA/07:ST:7 A($&&$>54'&#"dbPr@AbVn+"kk NQ'0jk"+VbA@rPblxdFGo`ۼܚvu , uvi`oGFdx63h%!!!mh8O! #3߀OKPO3#3{!Py4'&'&'&#"#476763243?BIz\]"-gfg@? STSugeuty3#"'&'&53327676765졊ŀ-"]\zL?=54òsteguSTSA@gfT )%547676767032&'#"/7>54#;DB&(16]&D#;DB&(19]&DAOPF= $ j1AOPF= $ j1\-?#"'&'&5476767632"&54767632!"&54767632P, !+ !t,@$ ->( D,@% ->)3& $% $ @,(>-( @,&>,) ?3Z\&6767632276?#"'&/"?,.,- %">;-),) ,& -*.&Bb>&*.67>32276?#"'&/"!!!!E,X. %";CH(*#*L9 ,*+('%#>>;.)*)    ,& -# .&a?\/[676763203276767#"'&'.'&'&#"67>323276767#"'&'&'&'&#"?!#%#0%$/ 1 !"""$! *F% 8 " !1 !"" "$B-$ &   !  &   p7##537!5!33!!!̙ϐ NTBb !!!!!!B   Xm> 5 !!hZg[/uѴm> 5-5!5yZ[u:^Bq!"3!!"'&'&5476)Bfh>@>RTOyfess?f24~K{[^"-:^Bq5! #!5!2767654&'&'&#:f?ssefyOTR>@>hfСƀ-"^[{K~42_%!0#3!!"'#7&'&547673G`t`AJUsOKR#1i7oH5\F 'LgoZ  %Khb9)d%!5!"3!!"'&'&5476)Kji7oHIVrgst?%Khb9:$ghond7!!5! #!5!2767654'&'&#dK>hsUIHo7ijtnoĞ$:9bhK%^X'1>H47>767632#"'&'&'&67676767!%4&5&'&'&'&'!^ dECFCG% JKtrldeQP y''86;%&B=:$ E*+86<!B<9% 1eWVt)(<3uw?>**\Y}8 L89%$>20L/5L<=$#5 /.O*6^X%0;E47>767632#"'&'&'&77'32767'67654'&/&'&#"^ dECFCG% JKtrldeQP u # #6;:**\Y}8>2,C7La$$LZ.(L< G"^%!!5!3OP"RT4632#"'&'&RL51!# L5.#$ E7J* 5L+ RDTF47632#"'&'&R&(31!# L5.#$ 7%&* 4L+ f !547676767032&'g +23$'FЏ# 59- 0#"/7676= +22%)F 0# 79-9% 3 UagX97# 3aaeZ #3o(ک0~S 3!!%~:e'%3"'&'&5"'&'&53;&crADrADc K%'W#"%'W#"Ky!!!33#;#"'&5!#yuFF;32;3276767653#"'732767676=#"'&'&'&5# MLtuOPPOutLM#":8JFO[NP21 [i##2/AQEB.,@ ^fW5: fDE26&#A>JHQՖjh4,3%)QRqSBC14vttvtsrs bTQ75!"21<99Vv!*&"  75PTUne`\ _FL:;B"$:;KPSaUO96U{!76GY<=!"BFjl&7<)$f@+H#5353%3276767653#"'732767676=#"'&'&'&5%;#"'&5􎎗fDF23"&%>8RKMՖjg2.3%)PQsRBE02uFF;<ZKO7;B"#:AFKX`UT61!U{!76F[;34# ,i 4-V}xE4632#"'&'&#53476767632#"'&'&5654'4'&'&!#!#F8&" 8& ,(41& /)'8&   %ėҘK&8" '8 b6>34# TQG '8& 2$-V}cz0#5354767676320'&'&'&#"#!#,(41&<%!.   ':—Ԙ6>34# +  / 4-Vdx"<##53476767632&'&'&#"!#%632#"'&'&5476+(41&;J-m (—K    V6=45" (*i .G  }x#DK0#"3###53547676767673##!5!476767632&'&'&#"3%#'#3.',/2Ę,4&D@c`혘!+(41&;J-m ( &%"V.C4.6$V6=45" (*i .V}w9KW#!##5354767676767632#"'&'&5654'4'&'&!#4632#"'&'&%!47fҘ,E {&*/)'8&"  %ėx8&  8&"\'42,UV.C4.F5=%TQG '8' 1$-&8! '8!H &%"60}) 2!7#!##53547676767%'#h'42,Ҙ,(2O7Td  — &%"}UV.C4.*!6dSS   }x :T!47#!##5354767676767632&'&'&#"0!#%632#"'&'&5476h'42,Ҙ,E {<%"/m ' —O     &%"61VV.C4.G4=% ,i  1G  436767632#"'&'&543276767654'&'&#".-ACQxSP"''l|RS!ZA0&' ,+@0&) \ON+-_\g_xw_a^`iiXQj|"#;=DLBY]f>=#%;>FKL%1 !53#5!#3LٞMF'767632!!5476767676?>76?4&#"o_`s1-.(-# * '(T.(,+1 ! fC@865iGH #'87C(H$%'"%G?D/.3,$##  $(0Zf)(Njx2?7327654'.'&+5327654'&+"'67632#"'&j%ORPa`^:8?Nb`IGIK^Oz5edzd\[;: !'%)%+%+&|~z-O13RQH8:FxGFmaCERF=e>=--VUiRAC&# 1,@>F{|JIV/ 3##!;!]^ ~$ts#Voe23"'!!632#"&'7327654'&'&D   ^B[tv" j҇.T߄RQ PP    KT7ab=@ڊơa`,'pLKv54'&'&#"3276632#"&'&547676767673dQRrRTRQiUUFH@|}! ! :8YWf N!hCCZ\s!f??WVde%9NNL@>('Β/(;9=3"7&.*HT2 #!5ն2PT%L%27654'&'&#"327654'&'&#"2#"$'&547676767&'&5462bb]ZuDC_oGFAAewBCSKLDCqo" *,&)( q]]" mCA(oU21A@rQ10BC0m&KLj+%kj<;Ο2.LEB-/U+,ve2532654'&'&#"#"'&'&54767>7632# sRPjUVH@} '+fMKOvt " |"gw'eA@XYef/0>?A6;Rge+,7<7;5#84ZxB-7&/054763253#5#"32765&'&#"knf !537X@B`HF=?vF36!=YqtmWFϜ!ORFE`:LN!LZx='Ca~Zx;'v~Zx'bn~Zx'Z~Zx'~Zx'jb~ZB'*~Zx<'~Zx)&q~&&2@4'&#"'6763267632&'&#"327#"'&5"#"'&'7327656>F(?V!Jr?)VnLV=&J>*:9;^JVH<9AI_?=9>u %^6uG -5MN_XLM94"ϚTT>7 >7 %7J++$$H@bN[K*V47632#"'&'&327673#"'&'&'#4'&#"#3>32>32#4&#"9>:>y %^5uH +5NLaWML94"˘**K4-/%$.?zNIHTJIVI4-/%$.7>7 > 8 Q 7J++$$H@b+B!#4'&#"#3>32>32#4&#"327673#"'&'&'a**K4-/%$.?zNIHTJIVI4-/%$. %^5uH +5NLaWML94"ML('n?l2cLo^mkr('n?I 7J++HH@b3!#3632#4'&'"327673#"'&'&'#}P 77Q252-( $1/5uH-6aWML94"2A"%$'nJK+&96<I"5 o 1S=LT$$H@b[\43 4'&+ ##!2 327673#"'&'&'!bcSמmvegHJ(*a` %/.7uG -5MN_XLM94"BCw35KOaml!v\7n(R>J++$$H@b0&#"#3676767632327673#"'&'&'DG/++!"!%!tY %^5uH -6LMaWML94"**(<:H|2&#7 79>)9>9>$>7 > 8 >7 > 8>,$6#53533#;#"&547632#"/&%47632#"/&uEEv9>:>)9>9>,uzv->7 > 8 >7 > 8L>?Qc7327>7654'&/$47676763 &'&#"&$47632#"/&%47632#"/&LZZYnF<=Z^Zn#">?RS` %}2WVp<64*'.ϐNX/2%&BA\\j49>9>(:>9>P:9R56BaJG7lRKI674OW10$!`:S34%*,/:8ZYMO98##>7 > 8 >7 > 8kSKDVh&'&'&'&54767676732&#"# '7327676765447632#"/&%47632#"/&k>F%'/,AEL:>:02 (%$(+dKD.*32PE!.$'L:?:>)9>9># $#$,+/:84*((*6y #g3%($+'/03?>:-,6"!-{\>7 > 8 >7 > 8U /3!3#!#47632#"/&%47632#"/&jv9>9>(9>:>~N^>7 > 8 >7 > 8-?!#36767>32##"47632#"/&%47632#"/&#-$#"#:*532*(9>9>(9>:>8"!n-+)788l>7 > 8 >7 > 8U 3!3#!#!!j]~N^ -3!!327654'&'&#"47632#"'&'&c LW(OW(uoDSM oDTM ۍSN"& TN!+N/n.1N/n,3# 1%3"'&53327654'&'&#"47632#"'&'&8vCBLW(NV)tnDTM nDTM i:9u3SN ( TN#)M/n,3M/n,3  1!!3!!327654'&'&#"47632#"'&'&f\c LW(OW(uoDSM oDTM }ۍSN"& TN!+N/n.1N/n,3# !5!!3"'&53327654'&'&#"47632#"'&'&B]zvCBLW(NV)tnDTM nDTM i:9u3SN ( TN#)M/n,3M/n,3[0D3 4'&+ ##!2 327650'&'&#"47632#"'&'&!bcSמmvegHJ(*a`QLV)NV)tnDTM nDTM BCw35KOaml!vSN"&!TN#)M/n,3M/n,3M-A&#"#3676767632327654'&'&#"47632#"'&'&DG/++!"!%!tYlLW(OV)uoDSM oDTM **(<:H|2&#7SN"& TN!+N/n,3N/n,3[ 4H!!3 4'&+ ##!2 327650'&'&#"47632#"'&'&])bcSמmvegHJ(*a`QLV)NV)tnDTM nDTM BCw35KOaml!vSN"&!TN#)M/n,3M/n,371E!!&#"#3676767632327654'&'&#"47632#"'&'&R]LDG/++!"!%!tYlLW(OV)uoDSM oDTM 7**(<:H|2&#7SN"& TN!+N/n,3N/n,3TT1 732=3#"'&'&wk   f#("("*$#f  {1ϋ?42 $  e #!#3#3)#'#7'373 ! %! !D`\G~}D^]D}*S\888խ jJwE6 !!EED62^X +G!#3##3267>54'&'&'&'&#"47>767632#"'&'&'&LQ ''86;:**\[{8!#!#FP@b)7R"327654'&$'&'53254'&5476322654'&#"&%&#" '&547676^BC][CBAAֿGHzeehHy{^AA^^BC,_0yfffffHz}^^AAAA^]CB+zSjgffM%&^]CB^^AAr-zSlggggfL&'X67654'&'&#"32463227#"&5454&#"#"'&'&54767632254'&FL H'%#$L H(%$-޲llFb@|nbIJ%2t86>9q.1u68KG.rH'$#$KH$(%!KmnzVFvxnؿLM};HE@bj VAr,0v57=;p,( Hl5T7!!&'&'&547676767632!!5676767654'&'&'&'&'&#"3!7#H3-+C?hgyzD2<< ;,IK99!! .%(,HEV^IJ.1!!89E`)~YIn2LMgdRM32\P;qp&I)dL(@AAB2;1 bM28"!()>'mJM'9hM629: ">j=;53'5#"'&'5#"#'&+"#4'36763267632J>XX67.9@C< (WXr$YZB>::)_`J<((lzrr__rjn~~842mn NZ[[`_}tddQPx!5!##'!5!f dVVh1923632#"'#536&#"04'&'5267>327&'"h('jvJJFGv,==vf08$MGDCOP%+-(xNZ~ [_]^cRSihtnؿ`mnYX@h6$(S32263227632&#"#"'&#"#"'&"#'322632327632&#"#"'&#"#"'&#"#'hBr, n76rU**zl^?^3:S98;7SU78lV4@t*n7697U+)|l^?]1=U79:6TU7878S4 (FFFF$24LJNDFHFGb &FFFF"25LLMCFFGF`!5!37!!'/"Ҥ"- ~S'*PE3צ4Btb6 2bfh8HyOFP&#"3#6767654'&&'&'&'&'&5476767>;767676732#"' #"W&.x~:$8+($   " f?3-/462 DHA)7QPGTQP(.'Av ,~uHbA>B7Wp&  $*!"(%%#0;&(6-;OqrqP)P6F,^X&Hd7!!3254'&'&'&'&+';2+#3267>54'&'&'&'&#"47>767632#"'&'&'&_N  !NWWNV68  ()4NW ''86;:**\[{8=>3=> `=>3=> ` 0#''73\ xb$RT4632#"'&'&RL51!# L5.#$ E7J* 5L+  $'6630 \3x$b>#!5p=>3=> `>!5!3D=>p !54'&/76303kF'%22+ -95 #>IMT<2p2 p2>2p2!p >c(B77#"'&'&54767262;254/'7032767654'&'&#"1_[; qrjZrmA"Ds/[K "BGNnKH  rQLg%W Pm}i`5-,:嗗\O_gw63Wmm #}34#" jY-u78ׇ. (<`#s'&54767676323#;#"'&5#5354'&'"&#" #"'&'7327654'&'&'&'&'&'&'&'&547632/5@K !uFF;<``"3 *:6Qt$ !  112-+$lk\_%45[e::"'/&?*2/""dg^# **.*4 jY-u78ׇ*4"zNH&  !'/6AZYCEnC$$00U)"  $#.1;KM%#5553% @N++㯭 y  !5!5N2@jP+  <!#' i3h #55#nEy #55%5%50P=J}JJJBZ3 3#BddBX<"^ !!!5!!5^OPlB 73!#5!57!!5!!B z{{(pg<(   $   6 327$~~<..9cc..c҅(~~$c-k-.ӅPccd !!!!5!!Plzݍ:[.6 !''%8p2pp1 p4!O!!OJ,0'654/ 7FԮ . FDŽ5{{J9wOiElJA"p'}8@0Y[) )3!!!!!!#!5!5!5!5!5!ɘ``````˜b".   $  zRh"" zh"&-<'!2'67654!"ĞǮnmJۗkh5PSRIE898:#S %%RV Qhէ2/{d!&'&543267654&%ňB䡢ΐ]_:"˽(^_a|~;;4 #  WT 333# #T+P3J 3 3 # #Jjc;˾^)'J733Px"!#!x8Wr 7%5%/ S$!6ї5zuY '7s`Ũbki`ŨbkX!3!3BPPx !3!3!3۝CBPPP_"647632#"'&'&_ -&<@+'- 2# +@$ _"647632#"'&'&_ -&<@+'- 2# +@$ _"647632#"'&'&_ -&<@+'- 2# +@$ _"647632#"'&'&_ -&<@+'- 2# +@$ iq$&$7$9+$Y\$Z$$$$(5)*7.22$273$w7$7Xy9$ 9(9H:$:H<$B<D??qDYHWIDIQIRIWIXI\JMuMMPR[TMUH\Mu2RY29RY29RYl lm37+%  1x   @O  # Ah  5T! U km#|  4      J3      b & & "Created by Thatcher Ulrich (http://tulrich.com), Karoly Barta (bartakarcsi@gmail.com) and Michael Everson with FontForge (http://fontforge.sf.net) This font, including hint instructions, has been donated to the Public Domain. Do whatever you want with it. Created by Thatcher Ulrich (http://tulrich.com), Karoly Barta (bartakarcsi@gmail.com) and Michael Everson with FontForge (http://fontforge.sf.net) This font, including hint instructions, has been donated to the Public Domain. Do whatever you want with it. TuffyTuffyRegularRegularFontForge : Tuffy Regular : 14-6-2012FontForge : Tuffy Regular : 14-6-2012Tuffy RegularTuffy RegularVersion 001.280 Version 001.280 TuffyTuffyThatcher Ulrich, Karoly Barta and Michael EversonThatcher Ulrich, Karoly Barta and Michael Eversonhttp://tulrich.com http://tulrich.com http://tulrich.com http://tulrich.com Public Domain Public Domain All Typographic FeaturesFonctions typographiquesAlle typografischen MglichkeitenFunzioni TipograficheAlle typografische kenmerkenLigaturesLigaturesLigaturenLegatureLigaturenFractionsFractionsBreukenAll Type FeaturesToutes fonctions typographiquesAlle AuszeichnungsartenTutte le FunzioniAlle typekenmerkenCommon LigaturesLigatures UsuellesNormale LigaturenLegature pi ComuniGemeenschappelijke LigaturenNo FractionsPas de FractionsKein BrucheNessuna FrazioneGeen breukenDiagonal FractionsFractions en DiagonaleDiagonaler BruchFrazioni DiagonaliDiagonale breuken2  !"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\]^_`abcdefghjikmlnoqprsutvwxzy{}|~      !"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\]^_`abcdefghijklmnopqrstuvwxyz{|}~      !"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\]^_`abcdefghijklmnopqrstuvwxyz{|}~      !"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\]^_`abcdefghijklmnopqrstuvwxyz{|}~      !"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\]^_`abcdefghijklmnopqrstuvwxyz{|}~      !"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\]^_`abcdefghijklmnopqrstuvwxyz{|}~uni007F softhyphenuni00B5AmacronamacronAbreveabreveAogonekaogonek Ccircumflex ccircumflex Cdotaccent cdotaccentDcarondcaronDcroatEmacronemacronEbreveebreve Edotaccent edotaccentEogonekeogonekEcaronecaron Gcircumflex gcircumflex Gdotaccent gdotaccent Gcommaaccent gcommaaccent Hcircumflex hcircumflexHbarhbarItildeitildeImacronimacronIbreveibreveIogonekiogonekIJij Jcircumflex jcircumflex Kcommaaccent kcommaaccent kgreenlandicLacutelacute Lcommaaccent lcommaaccentLcaronlcaronLdotldotNacutenacute Ncommaaccent ncommaaccentNcaronncaron napostropheEngengOmacronomacronObreveobreve Ohungarumlaut ohungarumlautRacuteracute Rcommaaccent rcommaaccentRcaronrcaronSacutesacute Scircumflex scircumflex Tcommaaccent tcommaaccentTcarontcaronTbartbarUtildeutildeUmacronumacronUbreveubreveUringuring Uhungarumlaut uhungarumlautUogonekuogonek Wcircumflex wcircumflex Ycircumflex ycircumflexZacutezacute Zdotaccent zdotaccentlongsuni01E2uni01E3 Scommaaccent scommaaccentuni021Auni021Buni021Cuni021Duni0250uni0251uni0252uni0253uni0254uni0255uni0256uni0257uni0258uni0259uni025Auni025Buni025Cuni025Duni025Euni025Funi0260uni0261uni0262uni0263uni0264uni0265uni0266uni0267uni0268uni0269uni026Auni026Buni026Cuni026Duni026Euni026Funi0270uni0271uni0272uni0273uni0274uni0275uni0276uni0277uni0278uni0279uni027Auni027Buni027Cuni027Duni027Euni027Funi0280uni0281uni0282uni0283uni0284uni0285uni0286uni0287uni0288uni0289uni028Auni028Buni028Cuni028Duni028Euni028Funi0290uni0291uni0292uni0293uni0294uni0295uni0296uni0297uni0298uni0299uni029Auni029Buni029Cuni029Duni029Euni029Funi02A0uni02A1uni02A2uni02A3uni02A4uni02A5uni02A6uni02A7uni02A8uni02A9uni02AAuni02ABuni02ACuni02ADuni02AEuni02AF macronsub gravecomb acutecombuni0302 tildecombuni0304uni0306uni0307uni0308uni030Auni030Buni030Cuni0310 dotbelowcombuni0324uni0325uni0327uni0328 brevesubnospuni0331uni0370uni0371uni0376uni037Auni037Buni037Cuni037Duni037Etonos dieresistonos Alphatonos anoteleia EpsilontonosEtatonos Iotatonos Omicrontonos Upsilontonos OmegatonosiotadieresistonosAlphaBetaGammaEpsilonZetaEtaThetaIotaKappaLambdaMuNuXiOmicronPiRhoSigmaTauUpsilonPhiChiPsi IotadieresisUpsilondieresis alphatonos epsilontonosetatonos iotatonosupsilondieresistonosalphabetagammadeltaepsilonzetaetathetaiotakappalambdanuxiomicronrhosigma1sigmatauupsilonphichipsiomega iotadieresisupsilondieresis omicrontonos upsilontonos omegatonosuni03CFuni03D0theta1Upsilon1Upsilonhooktonosuni03D4phi1omega1uni03D7uni03D8uni03D9uni03DAuni03DBuni03DCuni03DDuni03DEuni03DFuni03E0uni03E1uni03E2uni03E3uni03E4uni03E5uni03E6uni03E7uni03E8uni03E9uni03EAuni03EBuni03ECuni03EDuni03EEuni03EF kappascriptuni03F1uni03F2uni03F3uni03F4uni03F5uni03F6uni03F7uni03F8uni03F9uni03FAuni03FBuni03FCuni03FDuni03FEuni03FFuni0400 afii10023 afii10051 afii10052 afii10053 afii10054 afii10055 afii10056 afii10057 afii10058 afii10059 afii10060 afii10061uni040D afii10062 afii10145 afii10017 afii10018 afii10019 afii10020 afii10021 afii10022 afii10024 afii10025 afii10026 afii10027 afii10028 afii10029 afii10030 afii10031 afii10032 afii10033 afii10034 afii10035 afii10036 afii10037 afii10038 afii10039 afii10040 afii10041 afii10042 afii10043 afii10044 afii10045 afii10046 afii10047 afii10048 afii10049 afii10065 afii10066 afii10067 afii10068 afii10069 afii10070 afii10072 afii10073 afii10074 afii10075 afii10076 afii10077 afii10078 afii10079 afii10080 afii10081 afii10082 afii10083 afii10084 afii10085 afii10086 afii10087 afii10088 afii10089 afii10090 afii10091 afii10092 afii10093 afii10094 afii10095 afii10096 afii10097uni0450 afii10071 afii10099 afii10100 afii10101 afii10102 afii10103 afii10104 afii10105 afii10106 afii10107 afii10108 afii10109uni045D afii10110 afii10193uni048Auni048Buni048Cuni048Duni048Euni048FGheupturncyrillicgheupturncyrillicGhestrokecyrillicghestrokecyrillicGhemiddlehookcyrillicghemiddlehookcyrillicZhedescendercyrilliczhedescendercyrillicZedescendercyrilliczedescendercyrillicKadescendercyrillickadescendercyrillicKaverticalstrokecyrillickaverticalstrokecyrillicKastrokecyrillickastrokecyrillicKabashkircyrillickabashkircyrillicEndescendercyrillicendescendercyrillic Enghecyrillic enghecyrillicPemiddlehookcyrillicpemiddlehookcyrillicHaabkhasiancyrillichaabkhasiancyrillicEsdescendercyrillicesdescendercyrillicTedescendercyrillictedescendercyrillicUstraightcyrillicustraightcyrillicUstraightstrokecyrillicustraightstrokecyrillicHadescendercyrillichadescendercyrillic Tetsecyrillic tetsecyrillicChedescendercyrillicchedescendercyrillicCheverticalstrokecyrilliccheverticalstrokecyrillic Shhacyrillic shhacyrillicCheabkhasiancyrilliccheabkhasiancyrillicChedescenderabkhasiancyrillicchedescenderabkhasiancyrillicpalochkacyrillicZhebrevecyrilliczhebrevecyrillicKahookcyrillickahookcyrillicuni04C5uni04C6Enhookcyrillicenhookcyrillicuni04C9uni04CAChekhakassiancyrillicchekhakassiancyrillicuni04CDuni04CEuni04CFAbrevecyrillicabrevecyrillicAdieresiscyrillicadieresiscyrillic Aiecyrillic aiecyrillicIebrevecyrilliciebrevecyrillic Schwacyrillic schwacyrillicSchwadieresiscyrillicschwadieresiscyrillicZhedieresiscyrilliczhedieresiscyrillicZedieresiscyrilliczedieresiscyrillicDzeabkhasiancyrillicdzeabkhasiancyrillicImacroncyrillicimacroncyrillicIdieresiscyrillicidieresiscyrillicOdieresiscyrillicodieresiscyrillicObarredcyrillicobarredcyrillicObarreddieresiscyrillicobarreddieresiscyrillicuni04ECuni04EDUmacroncyrillicumacroncyrillicUdieresiscyrillicudieresiscyrillicUhungarumlautcyrillicuhungarumlautcyrillicChedieresiscyrillicchedieresiscyrillicuni04F6uni04F7Yerudieresiscyrillicyerudieresiscyrillic Bdotaccent bdotaccent Ddotaccent ddotaccentuni1E0Cuni1E0Duni1E0Euni1E0F Fdotaccent fdotaccentuni1E24uni1E25uni1E2Auni1E2Buni1E34uni1E35uni1E36uni1E37uni1E38uni1E39uni1E3Auni1E3B Mdotaccent mdotaccentuni1E42uni1E43uni1E44uni1E45uni1E46uni1E47uni1E48uni1E49 Pdotaccent pdotaccentuni1E5Auni1E5Buni1E5Cuni1E5Duni1E5Euni1E5F Sdotaccent sdotaccentuni1E62uni1E63 Tdotaccent tdotaccentuni1E6Cuni1E6Duni1E6Euni1E6FWgravewgraveWacutewacute Wdieresis wdieresisuni1E8Euni1E8Funi1E96uni1E9EYgraveygraveuni1EFAuni1EFB alphalenis alphaasperalphalenisgravealphaaspergravealphalenisacutealphaasperacutealphalenistildealphaaspertilde Alphalenis AlphaasperAlphalenisgraveAlphaaspergraveAlphalenisacuteAlphaasperacuteAlphalenistildeAlphaaspertilde epsilonlenis epsilonasperepsilonlenisgraveepsilonaspergraveepsilonlenisacuteepsilonasperacute Epsilonlenis EpsilonasperEpsilonlenisgraveEpsilonaspergraveEpsilonlenisacuteEpsilonasperacuteetalenisetaasper etalenisgrave etaaspergrave etalenisacute etaasperacute etalenistilde etaaspertildeEtalenisEtaasper Etalenisgrave Etaaspergrave Etalenisacute Etaasperacute Etalenistilde Etaaspertilde iotalenis iotaasperiotalenisgraveiotaaspergraveiotalenisacuteiotaasperacuteiotalenistildeiotaaspertilde Iotalenis IotaasperIotalenisgraveIotaaspergraveIotalenisacuteIotaasperacuteIotalenistildeIotaaspertilde omicronlenis omicronasperomicronlenisgraveomicronaspergraveomicronlenisacuteomicronasperacute Omicronlenis OmicronasperOmicronlenisgraveOmicronaspergraveOmicronlenisacuteOmicronasperacute upsilonlenis upsilonasperupsilonlenisgraveupsilonaspergraveupsilonlenisacuteupsilonasperacuteupsilonlenistildeupsilonaspertilde UpsilonasperUpsilonaspergraveUpsilonasperacuteUpsilonaspertilde omegalenis omegaasperomegalenisgraveomegaaspergraveomegalenisacuteomegaasperacuteomegalenistildeomegaaspertilde Omegalenis OmegaasperOmegalenisgraveOmegaaspergraveOmegalenisacuteOmegaasperacuteOmegalenistildeOmegaaspertilde alphagrave alphaacute epsilongrave epsilonacuteetagraveetaacute iotagrave iotaacute omicrongrave omicronacute upsilongrave upsilonacute omegagrave omegaacutealphaiotasublenisalphaiotasubasperalphaiotasublenisgravealphaiotasubaspergravealphaiotasublenisacutealphaiotasubasperacutealphaiotasublenistildealphaiotasubaspertildeAlphaiotasublenisAlphaiotasubasperAlphaiotasublenisgraveAlphaiotasubaspergraveAlphaiotasublenisacuteAlphaiotasubasperacuteAlphaiotasublenistildeAlphaiotasubaspertildeetaiotasublenisetaiotasubasperetaiotasublenisgraveetaiotasubaspergraveetaiotasublenisacuteetaiotasubasperacuteetaiotasublenistildeetaiotasubaspertildeEtaiotasublenisEtaiotasubasperEtaiotasublenisgraveEtaiotasubaspergraveEtaiotasublenisacuteEtaiotasubasperacuteEtaiotasublenistildeEtaiotasubaspertildeomegaiotasublenisomegaiotasubasperomegaiotasublenisgraveomegaiotasubaspergraveomegaiotasublenisacuteomegaiotasubasperacuteomegaiotasublenistildeomegaiotasubaspertildeOmegaiotasublenisOmegaiotasubasperOmegaiotasublenisgraveOmegaiotasubaspergraveOmegaiotasublenisacuteOmegaiotasubasperacuteOmegaiotasublenistildeOmegaiotasubaspertilde alphabreve alphamacronalphaiotasubgrave alphaiotasubalphaiotasubacute alphatildealphaiotasubtilde Alphabreve Alphamacron Alphagrave Alphaacute Alphaiotasublenis iotasubscriptpsili perispomenidialytika_perispomenietaiotasubgrave etaiotasubetaiotasubacuteetatildeetaiotasubtilde Epsilongrave EpsilonacuteEtagraveEtaacute Etaiotasub psili_varia psili_oxiapsili_perispomeni iotabreve iotamacroniotadieresisgraveiotadieresisacute iotatildeiotadieresistilde Iotabreve Iotamacron Iotagrave Iotaacute dasia_varia dasia_oxiadasia_perispomeni upsilonbreve upsilonmacronupsilondieresisgraveupsilondieresisacuterholenisrhoasper upsilontildeupsilondieresistilde Upsilonbreve Upsilonmacron Upsilongrave UpsilonacuteRhoasperdialytika_variadialytika_oxiavariaomegaiotasubgrave omegaiotasubomegaiotasubacute omegatildeomegaiotasubtilde Omicrongrave Omicronacute Omegagrave Omegaacute Omegaiotasuboxiaasperemspacethreeperemspacefourperemspace thinspace hairspace hyphentwo hyphennobreak figuredash horizontalbaruni2016 quotereverseduni201Funi2023onedotenleadertwodotenleaderuni2027uni2031minutesecond exclamdbluni203Duni203Funi2042uni2043uni2047uni2048uni2049uni204Buni204Cuni204Duni204Euni204Funi2052uni2053uni2056uni2058uni2059uni205Auni205Buni205Duni205Euni2070uni2071uni2072uni2073 foursuperioruni2075uni2076uni2077uni2078uni2079uni207Auni207Buni207Cuni207Duni207Euni207Funi2080uni2081uni2082uni2083uni2084uni2085uni2086uni2087uni2088uni2089uni208Auni208Buni208Cuni208Duni208Euni2090uni2091uni2092uni2093uni2094uni2098uni2099uni20A0 colonmonetaryuni20A2lirauni20A5uni20A6pesetauni20A8uni20A9 afii57636dongEurouni20ADuni20AEuni20AFuni20B0uni20B1uni20B2uni20B3uni20B4uni20B5uni20B6uni20B7uni20B8uni20B9 centigradeIfraktur afii61352 weierstrassRfrakturuni2126 estimatedalephonethird twothirdsuni2155uni2156uni2157uni2158uni2159uni215A oneeighth threeeighths fiveeighths seveneighthsuni215Funi2160uni2161uni2162uni2163uni2164uni2165uni2166uni2167uni2168uni2169uni216Auni216Buni216Cuni216Duni216Euni216Funi2170uni2171uni2172uni2173uni2174uni2175uni2176uni2177uni2178uni2179uni217Auni217Buni217Cuni217Duni217Euni217Funi2180uni2181uni2182uni2183uni2184uni2185uni2186uni2187uni2188uni2189 arrowleftarrowup arrowright arrowdown arrowboth arrowupdnuni2196uni2197uni2198uni2199uni219Auni219Buni219Cuni219Duni219Euni219Funi21A0uni21A1uni21A2uni21A3uni21A4uni21A5uni21A6uni21A7 arrowupdnbseuni21B0uni21B1uni21B2uni21B3uni21B4carriagereturnuni21B6uni21B7uni21B8uni21B9uni21BAuni21BBuni21BCuni21BDuni21BEuni21BFuni21C0uni21C1uni21C2uni21C3uni21C4uni21C5uni21C6uni21C7uni21C8uni21C9uni21CAuni21CBuni21CC arrowdblleft arrowdblup arrowdblright arrowdbldown arrowdblboth universal existentialemptysetuni2206gradientelement notelementuni220Duni2210 asteriskmathuni221Buni221C proportionalangle logicaland logicalor intersectionunion thereforesimilar congruent equivalence propersubsetpropersuperset notsubset reflexsubsetreflexsuperset circlepluscirclemultiply perpendicularuni22C4dotmath integraltp integralbt angleleft anglerightuniA746uniA747forintbrevealtg_yt_yc_t f_icircumflex f_idieresisf_igravef_iacutef_f_icircumflex f_f_idieresis f_f_igrave f_f_iacuteuniE118uniE119uniE11AuniE11BuniE11CuniE11DuniE11EuniE11FuniE120uniE121aalt agravealt aacutealt abrevealt atildealtacircumflexalt adieresisalt aogonekaltaringalt amacronaltxaltuniEFA0uniEFA1uniEFA2uniEFA3uniEFA4uniEFA5uniEFA6uniEFA7uniEFA8uniEFA9uniEFAAuniEFABuniEFACuniEFADuniEFB0uniEFB1uniEFB2uniEFB3uniEFB4uniEFB5uniEFB6uniEFB7uniEFB8 j.dotlessuniF8E5uniF8E6uniF8E7uniF8E8uniF8E9uniF8EAuniF8EBuniF8ECuniF8EDuniF8EEuniF8EFuniF8F0uniF8F1uniF8F2uniF8F3uniF8F4uniF8F5uniF8F6uniF8F7uniF8F8bracketrighttpbracketrightexbracketrightbt bracerighttpuniF8FDuniF8FEuniF8FFlongs_ts_tu10900u10901u10902u10903u10904u10905u10906u10907u10908u10909u1090Au1090Bu1090Cu1090Du1090Eu1090Fu10910u10911u10912u10913u10914u10915u10916u10917u10918u10919u1091Au1091Bu1091Fu1091Eu1091Du1091CU~       !! #" >> ?? @@ CA ^^ __ `` ca gdkh qm srutvv zx {{}    ƀ   >>     $" 42 @? EA \F `]aa bb gc hhyi zz}| ~          @ AAaB bb cc dd   04 8 F~ JJ$WW&\\(??ij( D hh&??????~d DF II   ?R?S?T?U?Z??\?ÿ?^?ƿ?`?ɿnolmrspqɉo1p