diff --git a/.cargo/config b/.cargo/config new file mode 100644 index 000000000..35049cbcb --- /dev/null +++ b/.cargo/config @@ -0,0 +1,2 @@ +[alias] +xtask = "run --package xtask --" diff --git a/.editorconfig b/.editorconfig new file mode 100644 index 000000000..ea56350fe --- /dev/null +++ b/.editorconfig @@ -0,0 +1,16 @@ +root = true + +[*] +charset = utf-8 +end_of_line = lf + +insert_final_newline = true +trim_trailing_whitespace = true + +[*.{rs,py}] +indent_style = space +indent_size = 4 + +[*.{md,json}] +indent_style = space +indent_size = 2 diff --git a/.gitattributes b/.gitattributes new file mode 100644 index 000000000..6313b56c5 --- /dev/null +++ b/.gitattributes @@ -0,0 +1 @@ +* text=auto eol=lf diff --git a/.github/PULL_REQUEST_TEMPLATE.md b/.github/PULL_REQUEST_TEMPLATE.md new file mode 100644 index 000000000..f68fd3e79 --- /dev/null +++ b/.github/PULL_REQUEST_TEMPLATE.md @@ -0,0 +1,7 @@ +*Descriptive summary of your bugfix, feature, or refactoring.* + +## Checklist +- [ ] Sensible git history (for example, squash "typo" or "fix" commits): See the + [Rewriting History](https://git-scm.com/book/en/v2/Git-Tools-Rewriting-History) guide for + help. +- [ ] Update the changelog (if necessary) diff --git a/.github/dependabot.yml b/.github/dependabot.yml new file mode 100644 index 000000000..5cde1657c --- /dev/null +++ b/.github/dependabot.yml @@ -0,0 +1,7 @@ +version: 2 +updates: +- package-ecosystem: cargo + directory: "/" + schedule: + interval: daily + open-pull-requests-limit: 10 diff --git a/.github/workflows/book.yml b/.github/workflows/book.yml new file mode 100644 index 000000000..988569003 --- /dev/null +++ b/.github/workflows/book.yml @@ -0,0 +1,43 @@ +name: Book + +on: + push: + branches: [ main ] + +# Adapted from: +# https://github.com/rust-lang/mdBook/wiki/Automated-Deployment%3A-GitHub-Actions#github-pages-deploy +jobs: + deploy: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v3 + with: + fetch-depth: 0 + - name: Install mdbook + run: | + mkdir mdbook + curl -sSL https://github.com/rust-lang/mdBook/releases/download/v0.4.21/mdbook-v0.4.21-x86_64-unknown-linux-gnu.tar.gz | tar -xz --directory=./mdbook + echo `pwd`/mdbook >> $GITHUB_PATH + - name: Deploy GitHub Pages + run: | + cd book + mdbook build + git worktree add gh-pages gh-pages + git config user.name "Deploy from CI" + git config user.email "" + cd gh-pages + # Delete the ref to avoid keeping history. + git update-ref -d refs/heads/gh-pages + # Place the book under a "HEAD" directory so that we can later + # add other versions (e.g. "stable" or "v0.17") without breaking + # URLs. + rm -rf HEAD + mv ../book HEAD + git add HEAD + # Add an index in the root to redirect to HEAD. If we eventually + # serve multiple versions, this can be changed to a real index. + cp ../head_redirect.html index.html + git add index.html + # Commit and push. + git commit -m "Deploy $GITHUB_SHA to gh-pages" + git push --force diff --git a/.github/workflows/msrv_toolchain.toml b/.github/workflows/msrv_toolchain.toml new file mode 100644 index 000000000..640fc4616 --- /dev/null +++ b/.github/workflows/msrv_toolchain.toml @@ -0,0 +1,4 @@ +[toolchain] +# Oldest nightly that currently works with `cargo xtask build`. +channel = "nightly-2022-04-18" +components = ["rust-src"] diff --git a/.github/workflows/rust.yml b/.github/workflows/rust.yml new file mode 100644 index 000000000..253e34377 --- /dev/null +++ b/.github/workflows/rust.yml @@ -0,0 +1,177 @@ +name: Rust + +on: + push: + branches: + - main + - version-* + pull_request: + branches: + - main + - version-* + schedule: + - cron: '0 0 * * 0-6' + +jobs: + test_aarch64: + name: Build and run tests on AArch64 + runs-on: ubuntu-latest + steps: + - name: Checkout sources + uses: actions/checkout@v2 + + - name: Install qemu and OVMF + run: | + # Ubuntu 20.04 provides qemu 4.2, which crashes on exit in this + # test. Add a PPA to provide a more recent version of qemu. + sudo add-apt-repository ppa:canonical-server/server-backports + sudo apt-get update + sudo apt-get install qemu-system-arm qemu-efi-aarch64 -y + + - name: Build + run: cargo xtask build --target aarch64 + + - name: Run VM tests + run: cargo xtask run --target aarch64 --headless --ci + timeout-minutes: 2 + + test_x86_64: + name: Build and run tests on x86_64 + runs-on: ubuntu-latest + steps: + - name: Checkout sources + uses: actions/checkout@v2 + + - name: Install qemu and OVMF + run: | + sudo apt-get update + sudo apt-get install qemu-system-x86 ovmf -y + + - name: Build + run: cargo xtask build --target x86_64 + + - name: Run VM tests + run: cargo xtask run --target x86_64 --headless --ci + timeout-minutes: 2 + + test_ia32: + name: Build and run tests on IA32 + runs-on: ubuntu-latest + steps: + - name: Checkout sources + uses: actions/checkout@v2 + + - name: Install qemu + run: | + # Ubuntu 20.04 provides qemu 4.2, which crashes on exit in this + # test. Add a PPA to provide a more recent version of qemu. + sudo add-apt-repository ppa:canonical-server/server-backports + sudo apt-get update + sudo apt-get install qemu-system-x86 -y + + # Starting in ubuntu 21.04 there's an `ovmf-ia32` package, but the + # github runners are on ubuntu 20.04. For now, install the OVMF + # files from a repo that provides unofficial nightly builds: + # https://github.com/retrage/edk2-nightly + - name: Install OVMF + env: + # Pin to a specific commit in the retrage/edk2-nightly repo to + # guard against external changes breaking the CI. + EDK2_NIGHTLY_COMMIT: 'ebb83e5475d49418afc32857f66111949928bcdc' + run: | + curl -o OVMF32_CODE.fd https://raw.githubusercontent.com/retrage/edk2-nightly/${EDK2_NIGHTLY_COMMIT}/bin/RELEASEIa32_OVMF_CODE.fd + curl -o OVMF32_VARS.fd https://raw.githubusercontent.com/retrage/edk2-nightly/${EDK2_NIGHTLY_COMMIT}/bin/RELEASEIa32_OVMF_VARS.fd + + - name: Build + run: cargo xtask build --target ia32 + + - name: Run VM tests + run: cargo xtask run --target ia32 --headless --ci --ovmf-code OVMF32_CODE.fd --ovmf-vars OVMF32_VARS.fd + timeout-minutes: 2 + + test: + name: Run tests and documentation tests + runs-on: ubuntu-latest + steps: + - name: Checkout sources + uses: actions/checkout@v2 + + - name: Run cargo test + run: cargo xtask test + + lints: + name: Lints + runs-on: ubuntu-latest + steps: + - name: Checkout sources + uses: actions/checkout@v2 + + - name: Run cargo fmt + run: | + rustup component add rustfmt + cargo fmt --all -- --check + + - name: Run clippy + run: | + rustup component add clippy + cargo xtask clippy --warnings-as-errors + + - name: Run cargo doc + run: cargo xtask doc --warnings-as-errors + + miri: + name: Run unit tests and doctests under Miri + runs-on: ubuntu-latest + steps: + - name: Checkout sources + uses: actions/checkout@v2 + + - name: Run miri + run: | + rustup component add miri + cargo xtask miri + + # This job tests that the template app builds successfully with the + # released versions of the libraries on crates.io. + # + # Since a nightly toolchain is currently required to build uefi-rs, + # the released versions can suddenly stop building when a new nightly + # compiler with a breaking change is released. This job provides an + # alert when this situation occurs. + test_latest_release: + name: Build the template against the released version of uefi-rs + runs-on: ubuntu-latest + steps: + - name: Checkout sources + uses: actions/checkout@v2 + + - name: Build + run: cargo xtask test-latest-release + + windows: + name: Check that the build works on a Windows target + runs-on: windows-latest + steps: + - name: Checkout sources + uses: actions/checkout@v2 + + - name: Build + run: cargo xtask build + + # Run the build with our current nightly MSRV (specified in + # ./msrv_toolchain.toml). This serves to check that we don't + # accidentally start relying on a new feature without intending + # to. Having a test for this makes it easier for us to be intentional + # about making changes that require a newer version. + build_msrv: + name: Check that the build works on our nightly MSRV + runs-on: ubuntu-latest + steps: + - name: Checkout sources + uses: actions/checkout@v2 + + - name: Set toolchain + run: cp .github/workflows/msrv_toolchain.toml rust-toolchain.toml + + - name: Build + run: cargo xtask build diff --git a/.gitignore b/.gitignore new file mode 100644 index 000000000..26cfda81e --- /dev/null +++ b/.gitignore @@ -0,0 +1,8 @@ +# Cargo places all built files here. +/target/ + +# Libraries should not commit their .lock files. +Cargo.lock + +# Files generated by mdBook. +/book/book/ diff --git a/BUILDING.md b/BUILDING.md new file mode 100644 index 000000000..6819adba9 --- /dev/null +++ b/BUILDING.md @@ -0,0 +1,61 @@ +# Building and running UEFI applications + +## UEFI binaries + +UEFI applications are simple COFF (Windows) executables, with the special +`EFI_Application` subsystem, and some limitations (such as no dynamic linking). + +The Rust compiler supports building UEFI applications for the +[`aarch64-unknown-uefi`], [`i686-unknown-uefi`], and [`x86_64-unknown-uefi`] +targets. + +[`aarch64-unknown-uefi`]: https://github.com/rust-lang/rust/blob/HEAD/compiler/rustc_target/src/spec/aarch64_unknown_uefi.rs +[`i686-unknown-uefi`]: https://github.com/rust-lang/rust/blob/HEAD/compiler/rustc_target/src/spec/i686_unknown_uefi.rs +[`x86_64-unknown-uefi`]: https://github.com/rust-lang/rust/blob/HEAD/compiler/rustc_target/src/spec/x86_64_unknown_uefi.rs + +## Building for a UEFI target + +For instructions on building the `uefi-rs` crates, see the +[README](README.md). This section is for building your own crates, +outside of the `uefi-rs` repo. + +- Install a `nightly` version of the Rust [toolchain] and include the + `rust-src` [component]. The easiest way to do this is with a + `rust-toolchain.toml` file, for example: + + ```toml + [toolchain] + channel = "nightly" + components = ["rust-src"] + ``` + +- Build the crate: + + `cargo build --target x86_64-unknown-uefi`. + +- The `target` directory will contain a `x86_64-unknown-uefi` subdirectory, + where you will find a `.efi` file - a normal UEFI executable. + +[toolchain]: https://rust-lang.github.io/rustup/concepts/toolchains.html +[component]: https://rust-lang.github.io/rustup/concepts/components.html + +## Running + +- To run an `.efi` executable on a real computer: + - Find a USB drive which is FAT12 / FAT16 / FAT32 formatted + - Copy the file to the USB drive, to `/EFI/Boot/Bootx64.efi` + - In the UEFI BIOS, choose "Boot from USB" or similar + +- To run this in QEMU: + - You will need a recent version of QEMU as well as OVMF to provide UEFI support + - Check the [`qemu.rs`](xtask/src/qemu.rs) module for an idea of + what arguments to pass to QEMU. + + In principle, you need to replicate the file structure described above for an USB drive, + then [mount the directory as if it were a FAT drive][qemu-vvfat]. + +[qemu-vvfat]: https://en.wikibooks.org/wiki/QEMU/Devices/Storage#Virtual_FAT_filesystem_(VVFAT) + +## Template + +The [template](template) provides a quick way to get started building UEFI applications. diff --git a/CHANGELOG.md b/CHANGELOG.md new file mode 100644 index 000000000..00dabe59c --- /dev/null +++ b/CHANGELOG.md @@ -0,0 +1,267 @@ +# Changelog + +## uefi - [Unreleased] + +### Added + +- Added `PhysicalAddress` and `VirtualAddress` type aliases. + +### Changed + +- Fixed the definition of `AllocateType` so that `MaxAddress` and + `Address` always take a 64-bit value, regardless of target platform. +- The conversion methods on `DevicePathToText` and `DevicePathFromText` + now return a `uefi::Result` instead of an `Option`. + +## uefi-macros - [Unreleased] + +## uefi-services - [Unreleased] + +## uefi - 0.17.0 + +### Added + +- Added `Deref` and `DerefMut` trait implementations to `ScopedProtocol`. + This eliminates the need to explicitly access the `interface` field, + which is now marked as deprecated. +- Implemented `core::fmt::Write` for the `Serial` protocol. +- Added the `MemoryProtection` protocol. +- Added `BootServices::get_handle_for_protocol`. +- Added trait `EqStrUntilNul` and implemented it for `CStr8`, `CStr16`, and `CString16` + (CString8 doesn't exist yet). Now you can compare everything that is `AsRef` + (such as `String` and `str` from the standard library) to UEFI strings. Please head to the + documentation of `EqStrUntilNul` to find out limitations and further information. +- Added `BootServices::image_handle` to get the handle of the executing + image. The image is set automatically by the `#[entry]` macro; if a + program does not use that macro then it should call + `BootServices::set_image_handle`. +- Added `BootServices::open_protocol_exclusive`. This provides a safe + and convenient subset of `open_protocol` that can be used whenever a + resource doesn't need to be shared. In same cases sharing is useful + (e.g. you might want to draw to the screen using the graphics + protocol, but still allow stdout output to go to the screen as + well), and in those cases `open_protocol` can still be used. +- Added `DiskIo` and `DiskIo2` protocols. +- Added `HardDriveMediaDevicePath` and related types. +- Added `PartialOrd` and `Ord` to the traits derived by `Guid`. +- The `File` trait now knows the methods `is_regular_file` and `is_directory`. + Developers profit from this on the struct `FileHandle`, for example. + +### Changed + +- Marked `BootServices::handle_protocol` as `unsafe`. (This method is + also deprecated -- use `open_protocol_exclusive` or `open_protocol` instead.) +- Deprecated `BootServices::locate_protocol` and marked it `unsafe`. Use + `BootServices::get_handle_for_protocol` and + `BootServices::open_protocol_exclusive` (or + `BootServices::open_protocol`) instead. +- Renamed feature `ignore-logger-errors` to `panic-on-logger-errors` so that it is + additive. It is now a default feature. +- Corrected the name of `BlockIOMedia::is_media_preset` to `is_media_present`. + +### Removed + +- Removed the `exts::allocate_buffer` function. This function could + cause undefined behavior when called with a `Layout` with an alignment + other than 1. A safe alternative is to use + [`Vec::into_boxed_slice`](https://doc.rust-lang.org/std/vec/struct.Vec.html#method.into_boxed_slice). +- Removed `From` conversions from `ucs2::Error` to `Status` and `Error`. +- Removed use of the unstable `try_trait_v2` feature, which allowed `?` + to be used with `Status` in a function returning `uefi::Result`. This + can be replaced by calling `status.into()`, or `Result::from(status)` + in cases where the compiler needs a type hint. + +## uefi-macros - 0.8.0 + +### Changed + +- The `#[entry]` macro now calls `BootServices::set_image_handle` to set + the global image handle. Due to this change, the two arguments to main + must both be named (e.g. `image: Handle` and `_image: Handle` are both + OK, but not `_: Handle`). + +## uefi-services - 0.14.0 + +### Added + +- Added `print!` and `println!` macros. + +### Changed + +- The `no_panic_handler` feature has been replaced with an additive + `panic_handler` feature. The new feature is enabled by default. + +## uefi - 0.16.1 + +### Added + +- Added EFI revision constants to `Revision`. + +### Fixed + +- The table `Header` struct's `Debug` impl now prints the correct signature. +- The `BootServices::create_event_ex` and + `RuntimeServices::query_variable_info` methods now check the table + version to make sure it's 2.0 or higher before calling the associated + function pointers. This prevents potential invalid pointer access. +- Fixed an incorrect pointer cast in the `Rng` protocol that could cause + undefined behavior. + +### Changed + +- Relaxed the version requirements for the `bitflags` and `log` + dependencies to allow earlier patch versions. +- Enabled `doc_auto_cfg` on docs.rs to show badges on items that are + gated behind a feature. + +## uefi-macros - 0.7.1 + +### Changed + +- Relaxed the version requirements for the `proc-macro2`, `quote`, and + `sync` dependencies to allow earlier patch versions. + +## uefi-services - 0.13.1 + +### Changed + +- Relaxed the version requirements for the `log` dependency to allow + earlier patch versions. + +## uefi - 0.16.0 + +### Added + +- Added `FileHandle::into_directory` and `FileHandle::into_regular_file`. +- Added `TimeParams`, `Time::invalid`, and `Time::is_invalid`. +- Added `RuntimeServices::query_variable_info` and `VariableStorageInfo`. +- Added `DevicePathToText` and `DevicePathFromText`. +- Added `LoadedImage::file_path` +- Implemented `TryFrom> for CString16`. +- Added `UnalignedCStr16`. +- Added `FilePathMediaDevicePath`. +- Added `DevicePath::as_acpi_device_path` and + `DevicePath::as_file_path_media_device_path`. +- Included `cstr8` and `cstr16` macros from `uefi-macros` in the prelude. +- Added `DevicePathInstance`, `DevicePathNode`, and `FfiDevicePath`. + +### Changed + +- `Time::new` now takes a single `TimeParams` argument so that date and + time fields can be explicitly named at the call site. +- The file info types now derive `PartialEq` and `Eq`. +- The `FileAttributes` type is now `repr(transparent)`. +- `DevicePath` is now a DST that represents an entire device path. The + `DevicePathInstance` and `DevicePathNode` provide views of path + instances and nodes, respectively. +- The methods of `Revision` are now `const`. + +### Fixed + +- Fixed undefined behavior in `proto::media::file::File::get_boxed_info`. + +## uefi-macros - 0.7.0 + +### Added + +- Added `cstr8` and `cstr16` macros for creating `CStr8`/`CStr16` string literals + at compile time. + +## uefi-services - 0.13.0 + +### Changed + +- Bumped `uefi` dependency to latest version. + +## uefi - 0.15.2 + +### Added + +- Added `PartialEq` impls for `CStr16 == CStr16`, `&CStr16 == CString`, + and `CString == &CStr16`. +- Added `Display` impl for `CString16`. +- Added `Handle::from_ptr` and `SystemTable::from_ptr`, which are + `unsafe` methods for initializing from a raw pointer. +- Added `CStr16::as_slice_with_nul` to provide immutable access to the + underlying slice. +- Added `LoadedImage::load_options_as_bytes` and + `LoadedImage::load_options_as_cstr16`. +- Added `Align::offset_up_to_alignment`, `Align::round_up_to_alignment`, + and `Align::align_buf`. +- Added `BootServices::connect_controller` and + `BootServices::disconnect_controller`. +- Added `BootServices::load_image` and `LoadImageSource`. Together these + replace `BootServices::load_image_from_buffer` and also allow an image + to be loaded via the `SimpleFileSystem` protocol. +- Added `Rng` protocol. +- Added `GptPartitionAttributes` struct and associated constants. +- Added `Output::output_string_lossy`. +- Added `ResultExt::handle_warning`. + +### Changed + +- Updated to the 2021 edition. +- `File::open` now takes the filename as `&CStr16` instead of `&str`, + avoiding an implicit string conversion. +- `FileInfo::new`, `FileSystemInfo::new`, and + `FileSystemVolumeLabel::new` now take their `name` parameter as + `&CStr16` instead of `&str`, avoiding an implicit string + conversion. Additionally, an unaligned storage buffer is now allowed + as long as it is big enough to provide an aligned subslice. +- `LoadImage::set_load_options` now takes a `u8` pointer instead of + `Char16`. +- The `Error` type is now public. +- The type of `GptPartitionEntry.attributes` is now + `GptPartitionAttributes`. +- The `uefi::Result` type now treats UEFI warnings as errors by + default. The `uefi::Result::Ok` variant no longer contains a + `Completion`, so the type behaves more like a regular Rust `Result` + type. + +### Removed + +- Removed `CStr16::as_string` method. Use + [`ToString`](https://doc.rust-lang.org/alloc/string/trait.ToString.html) + instead. +- Removed `FileInfoCreationError::InvalidChar`. This error type is no + longer needed due to the removal of implicit string conversions in + file info types. +- Removed `LoadedImage::load_options`, use + `LoadedImage::load_options_as_bytes` or + `LoadedImage::load_options_as_cstr16` instead. +- Removed `NamedFileProtocolInfo`, `FileInfoHeader`, + `FileSystemInfoHeader`, and `FileSystemVolumeLabelHeader`. Use + `FileInfo`, `FileSystemInfo`, and `FileSystemVolumeLabel` instead. +- Removed `BootServices::load_image_from_buffer`. Use + `BootServices::load_image` instead. +- Removed `Completion` type. Warnings are now treated as errors. +- Removed many `ResultExt` methods, for most of them the standard + `Result` methods can be used instead. Use `unwrap` instead of + `unwrap_success`, `expect` instead of `expect_success`, `expect_err` + instead of `expect_error`, and `map` instead of `map_inner`. The + `log_warning` method has also been removed, use the new + `ResultExt::handle_warning` method instead. + +### Fixed + +- Fixed compilation with Rust 1.60 by no longer enabling the + `vec_spare_capacity` feature, which has been stabilized. +- Fixed the header size calculated by `FileInfo::new` and + `FileSystemInfo::new`. +- Fixed incorrect alignment of the volume label field in + `FileSystemInfo`. This caused the beginning of the string to be + truncated and could result in out-of-bounds reads. +- Fixed size check for file info types so that alignment padding is + taken into account. This fixes potential out-of-bounds writes. + +## uefi-macros - 0.6.1 + +### Changed + +- Updated to the 2021 edition. + +## uefi-services - 0.12.1 + +### Changed + +- Updated to the 2021 edition. diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md new file mode 100644 index 000000000..899e28e7b --- /dev/null +++ b/CONTRIBUTING.md @@ -0,0 +1,130 @@ +# How to contribute to uefi-rs + +Pull requests, issues and suggestions are welcome! + +The UEFI spec is huge, so there might be some omissions or some missing features. +You should follow the existing project structure when adding new items. + +See the top-level [README](../README.md) for details of using `cargo xtask` to +build and test the project. + +Make some changes in your favourite editor / IDE: +I use [VS Code][code] with the [RLS][rls] extension. + +Test your changes: + +```shell +cargo xtask run +``` + +The line above will open a QEMU window where the test harness will run some tests. + +Any contributions are also expected to pass [Clippy][clippy]'s static analysis, +which you can run as follows: + +```shell +cargo xtask clippy +``` + +[clippy]: https://github.com/rust-lang-nursery/rust-clippy +[code]: https://code.visualstudio.com/ +[rls]: https://github.com/rust-lang-nursery/rls-vscode + +## Style guide + +This repository follows Rust's [standard style][style], the same one imposed by `rustfmt`. + +You can apply the standard style to the whole package by running `cargo fmt --all`. + +[style]: https://github.com/rust-lang-nursery/fmt-rfcs/blob/master/guide/guide.md + +## UEFI pitfalls + +Interfacing with a foreign and unsafe API is a difficult exercise in general, and +UEFI is certainly no exception. This section lists some common pain points that +you should keep in mind while working on UEFI interfaces. + +### Enums + +Rust and C enums differ in many way. One safety-critical difference is that the +Rust compiler assumes that all variants of Rust enums are known at compile-time. +UEFI, on the other hand, features many C enums which can be freely extended by +implementations or future versions of the spec. + +These enums must not be interfaced as Rust enums, as that could lead to undefined +behavior. Instead, integer newtypes with associated constants should be used. The +`newtype_enum` macro is provided by this crate to ease this exercise. + +### Pointers + +Pointer parameters in UEFI APIs come with many safety conditions. Some of these +are usually expected by unsafe Rust code, while others are more specific to the +low-level environment that UEFI operates in: + +- Pointers must reference physical memory (no memory-mapped hardware) +- Pointers must be properly aligned for their target type +- Pointers may only be NULL where UEFI explicitly allows for it +- When an UEFI function fails, nothing can be assumed about the state of data + behind `*mut` pointers. + +## Adding new protocols + +You should start by [forking this repository][fork] and cloning it. + +UEFI protocols are represented in memory as tables of function pointers, +each of which takes the protocol itself as first parameter. + +In `uefi-rs`, protocols are simply `struct`s containing `extern "efiapi" fn`s. +It's imperative to add `#[repr(C)]` to ensure the functions are laid out in memory +in the order the UEFI spec requires. + +Each protocol also has a Globally Unique Identifier (in the C API, they're usually +found in a `EFI_*_PROTOCOL_GUID` define). In Rust, we store the GUID as an associated +constant, by implementing the unsafe trait `uefi::proto::Identify`. For convenience, +this is done through the `unsafe_guid` macro. + +Finally, you should derive the `Protocol` trait. This is a marker trait, +extending `Identify`, which is used as a generic bound in the functions which retrieve +protocol implementations. + +An example protocol declaration: + +```rust +/// Protocol which does something. +#[repr(C)] +#[unsafe_guid("abcdefgh-1234-5678-9012-123456789abc")] +#[derive(Protocol)] +pub struct NewProtocol { + some_entry_point: extern "efiapi" fn( + this: *const NewProtocol, + some_parameter: SomeType, + some_other_parameter: SomeOtherType, + ) -> Status, + some_other_entry_point: extern "efiapi" fn( + this: *mut NewProtocol, + another_parameter: AnotherType, + ) -> SomeOtherResult, + // ... +} +``` + +There should also be an `impl` block providing safe access to the functions: + +```rust +impl NewProtocol { + /// This function does something. + pub fn do_something(&self, a: SomeType, b: SomeOtherType) -> Result { + // Call the wrapped function + let status = unsafe { (self.some_entry_point)(self, a, b) }; + // `Status` provides a helper function for converting to `Result` + status.into() + } +} +``` + +[fork]: https://docs.github.com/en/free-pro-team@latest/github/getting-started-with-github/fork-a-repo + +## Publishing new versions of the crates + +Maintainers of this repository might also be interested in [the guidelines](PUBLISHING.md) +for publishing new versions of the uefi-rs crates. diff --git a/Cargo.toml b/Cargo.toml new file mode 100644 index 000000000..209ab5f04 --- /dev/null +++ b/Cargo.toml @@ -0,0 +1,53 @@ +[package] +name = "uefi" +version = "0.17.0" +authors = ["Gabriel Majeri "] +readme = "README.md" +edition = "2021" +exclude = [ + ".cargo/**", + "template/**", + "uefi-macros/**", + "uefi-services/**", + "uefi-test-runner/**", + "xtask/**", +] +description = "Safe and easy-to-use wrapper for building UEFI apps" +repository = "https://github.com/rust-osdev/uefi-rs" +keywords = ["uefi", "efi"] +categories = ["embedded", "no-std", "api-bindings"] +license = "MPL-2.0" + +[features] +default = ["panic-on-logger-errors"] +alloc = [] +exts = [] +logger = [] +# Ignore text output errors in logger as a workaround for firmware issues that +# were observed on the VirtualBox UEFI implementation (see uefi-rs#121). +# In those cases, this feature can be excluded by removing the default features. +panic-on-logger-errors = [] + +[dependencies] +bitflags = "1.3.1" +log = { version = "0.4.5", default-features = false } +ucs2 = "0.3.2" +uefi-macros = "0.8.0" + +[workspace] +members = [ + "template", + "uefi-macros", + "uefi-services", + "uefi-test-runner", + "xtask", +] + +[patch.crates-io] +uefi-macros = { path = "uefi-macros" } +uefi-services = { path = "uefi-services" } +uefi = { path = "." } + +[package.metadata.docs.rs] +all-features = true +rustdoc-args = ["--cfg", "docsrs"] diff --git a/HEAD/.nojekyll b/HEAD/.nojekyll new file mode 100644 index 000000000..f17311098 --- /dev/null +++ b/HEAD/.nojekyll @@ -0,0 +1 @@ +This file makes sure that Github Pages doesn't process mdBook's output. diff --git a/HEAD/404.html b/HEAD/404.html new file mode 100644 index 000000000..1f07e5e85 --- /dev/null +++ b/HEAD/404.html @@ -0,0 +1,167 @@ + + + + + + Page not found - Rust UEFI Book + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ +
+ + + + + + + +
+
+

Document not found (404)

+

This URL is invalid, sorry. Please use the navigation bar or search to continue.

+ +
+ + +
+
+ + + +
+ + + + + + + + + + + + diff --git a/HEAD/FontAwesome/css/font-awesome.css b/HEAD/FontAwesome/css/font-awesome.css new file mode 100644 index 000000000..540440ce8 --- /dev/null +++ b/HEAD/FontAwesome/css/font-awesome.css @@ -0,0 +1,4 @@ +/*! + * Font Awesome 4.7.0 by @davegandy - http://fontawesome.io - @fontawesome + * License - http://fontawesome.io/license (Font: SIL OFL 1.1, CSS: MIT License) + */@font-face{font-family:'FontAwesome';src:url('../fonts/fontawesome-webfont.eot?v=4.7.0');src:url('../fonts/fontawesome-webfont.eot?#iefix&v=4.7.0') format('embedded-opentype'),url('../fonts/fontawesome-webfont.woff2?v=4.7.0') format('woff2'),url('../fonts/fontawesome-webfont.woff?v=4.7.0') format('woff'),url('../fonts/fontawesome-webfont.ttf?v=4.7.0') format('truetype'),url('../fonts/fontawesome-webfont.svg?v=4.7.0#fontawesomeregular') format('svg');font-weight:normal;font-style:normal}.fa{display:inline-block;font:normal normal normal 14px/1 FontAwesome;font-size:inherit;text-rendering:auto;-webkit-font-smoothing:antialiased;-moz-osx-font-smoothing:grayscale}.fa-lg{font-size:1.33333333em;line-height:.75em;vertical-align:-15%}.fa-2x{font-size:2em}.fa-3x{font-size:3em}.fa-4x{font-size:4em}.fa-5x{font-size:5em}.fa-fw{width:1.28571429em;text-align:center}.fa-ul{padding-left:0;margin-left:2.14285714em;list-style-type:none}.fa-ul>li{position:relative}.fa-li{position:absolute;left:-2.14285714em;width:2.14285714em;top:.14285714em;text-align:center}.fa-li.fa-lg{left:-1.85714286em}.fa-border{padding:.2em .25em .15em;border:solid .08em #eee;border-radius:.1em}.fa-pull-left{float:left}.fa-pull-right{float:right}.fa.fa-pull-left{margin-right:.3em}.fa.fa-pull-right{margin-left:.3em}.pull-right{float:right}.pull-left{float:left}.fa.pull-left{margin-right:.3em}.fa.pull-right{margin-left:.3em}.fa-spin{-webkit-animation:fa-spin 2s infinite linear;animation:fa-spin 2s infinite linear}.fa-pulse{-webkit-animation:fa-spin 1s infinite steps(8);animation:fa-spin 1s infinite steps(8)}@-webkit-keyframes fa-spin{0%{-webkit-transform:rotate(0deg);transform:rotate(0deg)}100%{-webkit-transform:rotate(359deg);transform:rotate(359deg)}}@keyframes fa-spin{0%{-webkit-transform:rotate(0deg);transform:rotate(0deg)}100%{-webkit-transform:rotate(359deg);transform:rotate(359deg)}}.fa-rotate-90{-ms-filter:"progid:DXImageTransform.Microsoft.BasicImage(rotation=1)";-webkit-transform:rotate(90deg);-ms-transform:rotate(90deg);transform:rotate(90deg)}.fa-rotate-180{-ms-filter:"progid:DXImageTransform.Microsoft.BasicImage(rotation=2)";-webkit-transform:rotate(180deg);-ms-transform:rotate(180deg);transform:rotate(180deg)}.fa-rotate-270{-ms-filter:"progid:DXImageTransform.Microsoft.BasicImage(rotation=3)";-webkit-transform:rotate(270deg);-ms-transform:rotate(270deg);transform:rotate(270deg)}.fa-flip-horizontal{-ms-filter:"progid:DXImageTransform.Microsoft.BasicImage(rotation=0, mirror=1)";-webkit-transform:scale(-1, 1);-ms-transform:scale(-1, 1);transform:scale(-1, 1)}.fa-flip-vertical{-ms-filter:"progid:DXImageTransform.Microsoft.BasicImage(rotation=2, mirror=1)";-webkit-transform:scale(1, -1);-ms-transform:scale(1, -1);transform:scale(1, -1)}:root .fa-rotate-90,:root .fa-rotate-180,:root .fa-rotate-270,:root .fa-flip-horizontal,:root .fa-flip-vertical{filter:none}.fa-stack{position:relative;display:inline-block;width:2em;height:2em;line-height:2em;vertical-align:middle}.fa-stack-1x,.fa-stack-2x{position:absolute;left:0;width:100%;text-align:center}.fa-stack-1x{line-height:inherit}.fa-stack-2x{font-size:2em}.fa-inverse{color:#fff}.fa-glass:before{content:"\f000"}.fa-music:before{content:"\f001"}.fa-search:before{content:"\f002"}.fa-envelope-o:before{content:"\f003"}.fa-heart:before{content:"\f004"}.fa-star:before{content:"\f005"}.fa-star-o:before{content:"\f006"}.fa-user:before{content:"\f007"}.fa-film:before{content:"\f008"}.fa-th-large:before{content:"\f009"}.fa-th:before{content:"\f00a"}.fa-th-list:before{content:"\f00b"}.fa-check:before{content:"\f00c"}.fa-remove:before,.fa-close:before,.fa-times:before{content:"\f00d"}.fa-search-plus:before{content:"\f00e"}.fa-search-minus:before{content:"\f010"}.fa-power-off:before{content:"\f011"}.fa-signal:before{content:"\f012"}.fa-gear:before,.fa-cog:before{content:"\f013"}.fa-trash-o:before{content:"\f014"}.fa-home:before{content:"\f015"}.fa-file-o:before{content:"\f016"}.fa-clock-o:before{content:"\f017"}.fa-road:before{content:"\f018"}.fa-download:before{content:"\f019"}.fa-arrow-circle-o-down:before{content:"\f01a"}.fa-arrow-circle-o-up:before{content:"\f01b"}.fa-inbox:before{content:"\f01c"}.fa-play-circle-o:before{content:"\f01d"}.fa-rotate-right:before,.fa-repeat:before{content:"\f01e"}.fa-refresh:before{content:"\f021"}.fa-list-alt:before{content:"\f022"}.fa-lock:before{content:"\f023"}.fa-flag:before{content:"\f024"}.fa-headphones:before{content:"\f025"}.fa-volume-off:before{content:"\f026"}.fa-volume-down:before{content:"\f027"}.fa-volume-up:before{content:"\f028"}.fa-qrcode:before{content:"\f029"}.fa-barcode:before{content:"\f02a"}.fa-tag:before{content:"\f02b"}.fa-tags:before{content:"\f02c"}.fa-book:before{content:"\f02d"}.fa-bookmark:before{content:"\f02e"}.fa-print:before{content:"\f02f"}.fa-camera:before{content:"\f030"}.fa-font:before{content:"\f031"}.fa-bold:before{content:"\f032"}.fa-italic:before{content:"\f033"}.fa-text-height:before{content:"\f034"}.fa-text-width:before{content:"\f035"}.fa-align-left:before{content:"\f036"}.fa-align-center:before{content:"\f037"}.fa-align-right:before{content:"\f038"}.fa-align-justify:before{content:"\f039"}.fa-list:before{content:"\f03a"}.fa-dedent:before,.fa-outdent:before{content:"\f03b"}.fa-indent:before{content:"\f03c"}.fa-video-camera:before{content:"\f03d"}.fa-photo:before,.fa-image:before,.fa-picture-o:before{content:"\f03e"}.fa-pencil:before{content:"\f040"}.fa-map-marker:before{content:"\f041"}.fa-adjust:before{content:"\f042"}.fa-tint:before{content:"\f043"}.fa-edit:before,.fa-pencil-square-o:before{content:"\f044"}.fa-share-square-o:before{content:"\f045"}.fa-check-square-o:before{content:"\f046"}.fa-arrows:before{content:"\f047"}.fa-step-backward:before{content:"\f048"}.fa-fast-backward:before{content:"\f049"}.fa-backward:before{content:"\f04a"}.fa-play:before{content:"\f04b"}.fa-pause:before{content:"\f04c"}.fa-stop:before{content:"\f04d"}.fa-forward:before{content:"\f04e"}.fa-fast-forward:before{content:"\f050"}.fa-step-forward:before{content:"\f051"}.fa-eject:before{content:"\f052"}.fa-chevron-left:before{content:"\f053"}.fa-chevron-right:before{content:"\f054"}.fa-plus-circle:before{content:"\f055"}.fa-minus-circle:before{content:"\f056"}.fa-times-circle:before{content:"\f057"}.fa-check-circle:before{content:"\f058"}.fa-question-circle:before{content:"\f059"}.fa-info-circle:before{content:"\f05a"}.fa-crosshairs:before{content:"\f05b"}.fa-times-circle-o:before{content:"\f05c"}.fa-check-circle-o:before{content:"\f05d"}.fa-ban:before{content:"\f05e"}.fa-arrow-left:before{content:"\f060"}.fa-arrow-right:before{content:"\f061"}.fa-arrow-up:before{content:"\f062"}.fa-arrow-down:before{content:"\f063"}.fa-mail-forward:before,.fa-share:before{content:"\f064"}.fa-expand:before{content:"\f065"}.fa-compress:before{content:"\f066"}.fa-plus:before{content:"\f067"}.fa-minus:before{content:"\f068"}.fa-asterisk:before{content:"\f069"}.fa-exclamation-circle:before{content:"\f06a"}.fa-gift:before{content:"\f06b"}.fa-leaf:before{content:"\f06c"}.fa-fire:before{content:"\f06d"}.fa-eye:before{content:"\f06e"}.fa-eye-slash:before{content:"\f070"}.fa-warning:before,.fa-exclamation-triangle:before{content:"\f071"}.fa-plane:before{content:"\f072"}.fa-calendar:before{content:"\f073"}.fa-random:before{content:"\f074"}.fa-comment:before{content:"\f075"}.fa-magnet:before{content:"\f076"}.fa-chevron-up:before{content:"\f077"}.fa-chevron-down:before{content:"\f078"}.fa-retweet:before{content:"\f079"}.fa-shopping-cart:before{content:"\f07a"}.fa-folder:before{content:"\f07b"}.fa-folder-open:before{content:"\f07c"}.fa-arrows-v:before{content:"\f07d"}.fa-arrows-h:before{content:"\f07e"}.fa-bar-chart-o:before,.fa-bar-chart:before{content:"\f080"}.fa-twitter-square:before{content:"\f081"}.fa-facebook-square:before{content:"\f082"}.fa-camera-retro:before{content:"\f083"}.fa-key:before{content:"\f084"}.fa-gears:before,.fa-cogs:before{content:"\f085"}.fa-comments:before{content:"\f086"}.fa-thumbs-o-up:before{content:"\f087"}.fa-thumbs-o-down:before{content:"\f088"}.fa-star-half:before{content:"\f089"}.fa-heart-o:before{content:"\f08a"}.fa-sign-out:before{content:"\f08b"}.fa-linkedin-square:before{content:"\f08c"}.fa-thumb-tack:before{content:"\f08d"}.fa-external-link:before{content:"\f08e"}.fa-sign-in:before{content:"\f090"}.fa-trophy:before{content:"\f091"}.fa-github-square:before{content:"\f092"}.fa-upload:before{content:"\f093"}.fa-lemon-o:before{content:"\f094"}.fa-phone:before{content:"\f095"}.fa-square-o:before{content:"\f096"}.fa-bookmark-o:before{content:"\f097"}.fa-phone-square:before{content:"\f098"}.fa-twitter:before{content:"\f099"}.fa-facebook-f:before,.fa-facebook:before{content:"\f09a"}.fa-github:before{content:"\f09b"}.fa-unlock:before{content:"\f09c"}.fa-credit-card:before{content:"\f09d"}.fa-feed:before,.fa-rss:before{content:"\f09e"}.fa-hdd-o:before{content:"\f0a0"}.fa-bullhorn:before{content:"\f0a1"}.fa-bell:before{content:"\f0f3"}.fa-certificate:before{content:"\f0a3"}.fa-hand-o-right:before{content:"\f0a4"}.fa-hand-o-left:before{content:"\f0a5"}.fa-hand-o-up:before{content:"\f0a6"}.fa-hand-o-down:before{content:"\f0a7"}.fa-arrow-circle-left:before{content:"\f0a8"}.fa-arrow-circle-right:before{content:"\f0a9"}.fa-arrow-circle-up:before{content:"\f0aa"}.fa-arrow-circle-down:before{content:"\f0ab"}.fa-globe:before{content:"\f0ac"}.fa-wrench:before{content:"\f0ad"}.fa-tasks:before{content:"\f0ae"}.fa-filter:before{content:"\f0b0"}.fa-briefcase:before{content:"\f0b1"}.fa-arrows-alt:before{content:"\f0b2"}.fa-group:before,.fa-users:before{content:"\f0c0"}.fa-chain:before,.fa-link:before{content:"\f0c1"}.fa-cloud:before{content:"\f0c2"}.fa-flask:before{content:"\f0c3"}.fa-cut:before,.fa-scissors:before{content:"\f0c4"}.fa-copy:before,.fa-files-o:before{content:"\f0c5"}.fa-paperclip:before{content:"\f0c6"}.fa-save:before,.fa-floppy-o:before{content:"\f0c7"}.fa-square:before{content:"\f0c8"}.fa-navicon:before,.fa-reorder:before,.fa-bars:before{content:"\f0c9"}.fa-list-ul:before{content:"\f0ca"}.fa-list-ol:before{content:"\f0cb"}.fa-strikethrough:before{content:"\f0cc"}.fa-underline:before{content:"\f0cd"}.fa-table:before{content:"\f0ce"}.fa-magic:before{content:"\f0d0"}.fa-truck:before{content:"\f0d1"}.fa-pinterest:before{content:"\f0d2"}.fa-pinterest-square:before{content:"\f0d3"}.fa-google-plus-square:before{content:"\f0d4"}.fa-google-plus:before{content:"\f0d5"}.fa-money:before{content:"\f0d6"}.fa-caret-down:before{content:"\f0d7"}.fa-caret-up:before{content:"\f0d8"}.fa-caret-left:before{content:"\f0d9"}.fa-caret-right:before{content:"\f0da"}.fa-columns:before{content:"\f0db"}.fa-unsorted:before,.fa-sort:before{content:"\f0dc"}.fa-sort-down:before,.fa-sort-desc:before{content:"\f0dd"}.fa-sort-up:before,.fa-sort-asc:before{content:"\f0de"}.fa-envelope:before{content:"\f0e0"}.fa-linkedin:before{content:"\f0e1"}.fa-rotate-left:before,.fa-undo:before{content:"\f0e2"}.fa-legal:before,.fa-gavel:before{content:"\f0e3"}.fa-dashboard:before,.fa-tachometer:before{content:"\f0e4"}.fa-comment-o:before{content:"\f0e5"}.fa-comments-o:before{content:"\f0e6"}.fa-flash:before,.fa-bolt:before{content:"\f0e7"}.fa-sitemap:before{content:"\f0e8"}.fa-umbrella:before{content:"\f0e9"}.fa-paste:before,.fa-clipboard:before{content:"\f0ea"}.fa-lightbulb-o:before{content:"\f0eb"}.fa-exchange:before{content:"\f0ec"}.fa-cloud-download:before{content:"\f0ed"}.fa-cloud-upload:before{content:"\f0ee"}.fa-user-md:before{content:"\f0f0"}.fa-stethoscope:before{content:"\f0f1"}.fa-suitcase:before{content:"\f0f2"}.fa-bell-o:before{content:"\f0a2"}.fa-coffee:before{content:"\f0f4"}.fa-cutlery:before{content:"\f0f5"}.fa-file-text-o:before{content:"\f0f6"}.fa-building-o:before{content:"\f0f7"}.fa-hospital-o:before{content:"\f0f8"}.fa-ambulance:before{content:"\f0f9"}.fa-medkit:before{content:"\f0fa"}.fa-fighter-jet:before{content:"\f0fb"}.fa-beer:before{content:"\f0fc"}.fa-h-square:before{content:"\f0fd"}.fa-plus-square:before{content:"\f0fe"}.fa-angle-double-left:before{content:"\f100"}.fa-angle-double-right:before{content:"\f101"}.fa-angle-double-up:before{content:"\f102"}.fa-angle-double-down:before{content:"\f103"}.fa-angle-left:before{content:"\f104"}.fa-angle-right:before{content:"\f105"}.fa-angle-up:before{content:"\f106"}.fa-angle-down:before{content:"\f107"}.fa-desktop:before{content:"\f108"}.fa-laptop:before{content:"\f109"}.fa-tablet:before{content:"\f10a"}.fa-mobile-phone:before,.fa-mobile:before{content:"\f10b"}.fa-circle-o:before{content:"\f10c"}.fa-quote-left:before{content:"\f10d"}.fa-quote-right:before{content:"\f10e"}.fa-spinner:before{content:"\f110"}.fa-circle:before{content:"\f111"}.fa-mail-reply:before,.fa-reply:before{content:"\f112"}.fa-github-alt:before{content:"\f113"}.fa-folder-o:before{content:"\f114"}.fa-folder-open-o:before{content:"\f115"}.fa-smile-o:before{content:"\f118"}.fa-frown-o:before{content:"\f119"}.fa-meh-o:before{content:"\f11a"}.fa-gamepad:before{content:"\f11b"}.fa-keyboard-o:before{content:"\f11c"}.fa-flag-o:before{content:"\f11d"}.fa-flag-checkered:before{content:"\f11e"}.fa-terminal:before{content:"\f120"}.fa-code:before{content:"\f121"}.fa-mail-reply-all:before,.fa-reply-all:before{content:"\f122"}.fa-star-half-empty:before,.fa-star-half-full:before,.fa-star-half-o:before{content:"\f123"}.fa-location-arrow:before{content:"\f124"}.fa-crop:before{content:"\f125"}.fa-code-fork:before{content:"\f126"}.fa-unlink:before,.fa-chain-broken:before{content:"\f127"}.fa-question:before{content:"\f128"}.fa-info:before{content:"\f129"}.fa-exclamation:before{content:"\f12a"}.fa-superscript:before{content:"\f12b"}.fa-subscript:before{content:"\f12c"}.fa-eraser:before{content:"\f12d"}.fa-puzzle-piece:before{content:"\f12e"}.fa-microphone:before{content:"\f130"}.fa-microphone-slash:before{content:"\f131"}.fa-shield:before{content:"\f132"}.fa-calendar-o:before{content:"\f133"}.fa-fire-extinguisher:before{content:"\f134"}.fa-rocket:before{content:"\f135"}.fa-maxcdn:before{content:"\f136"}.fa-chevron-circle-left:before{content:"\f137"}.fa-chevron-circle-right:before{content:"\f138"}.fa-chevron-circle-up:before{content:"\f139"}.fa-chevron-circle-down:before{content:"\f13a"}.fa-html5:before{content:"\f13b"}.fa-css3:before{content:"\f13c"}.fa-anchor:before{content:"\f13d"}.fa-unlock-alt:before{content:"\f13e"}.fa-bullseye:before{content:"\f140"}.fa-ellipsis-h:before{content:"\f141"}.fa-ellipsis-v:before{content:"\f142"}.fa-rss-square:before{content:"\f143"}.fa-play-circle:before{content:"\f144"}.fa-ticket:before{content:"\f145"}.fa-minus-square:before{content:"\f146"}.fa-minus-square-o:before{content:"\f147"}.fa-level-up:before{content:"\f148"}.fa-level-down:before{content:"\f149"}.fa-check-square:before{content:"\f14a"}.fa-pencil-square:before{content:"\f14b"}.fa-external-link-square:before{content:"\f14c"}.fa-share-square:before{content:"\f14d"}.fa-compass:before{content:"\f14e"}.fa-toggle-down:before,.fa-caret-square-o-down:before{content:"\f150"}.fa-toggle-up:before,.fa-caret-square-o-up:before{content:"\f151"}.fa-toggle-right:before,.fa-caret-square-o-right:before{content:"\f152"}.fa-euro:before,.fa-eur:before{content:"\f153"}.fa-gbp:before{content:"\f154"}.fa-dollar:before,.fa-usd:before{content:"\f155"}.fa-rupee:before,.fa-inr:before{content:"\f156"}.fa-cny:before,.fa-rmb:before,.fa-yen:before,.fa-jpy:before{content:"\f157"}.fa-ruble:before,.fa-rouble:before,.fa-rub:before{content:"\f158"}.fa-won:before,.fa-krw:before{content:"\f159"}.fa-bitcoin:before,.fa-btc:before{content:"\f15a"}.fa-file:before{content:"\f15b"}.fa-file-text:before{content:"\f15c"}.fa-sort-alpha-asc:before{content:"\f15d"}.fa-sort-alpha-desc:before{content:"\f15e"}.fa-sort-amount-asc:before{content:"\f160"}.fa-sort-amount-desc:before{content:"\f161"}.fa-sort-numeric-asc:before{content:"\f162"}.fa-sort-numeric-desc:before{content:"\f163"}.fa-thumbs-up:before{content:"\f164"}.fa-thumbs-down:before{content:"\f165"}.fa-youtube-square:before{content:"\f166"}.fa-youtube:before{content:"\f167"}.fa-xing:before{content:"\f168"}.fa-xing-square:before{content:"\f169"}.fa-youtube-play:before{content:"\f16a"}.fa-dropbox:before{content:"\f16b"}.fa-stack-overflow:before{content:"\f16c"}.fa-instagram:before{content:"\f16d"}.fa-flickr:before{content:"\f16e"}.fa-adn:before{content:"\f170"}.fa-bitbucket:before{content:"\f171"}.fa-bitbucket-square:before{content:"\f172"}.fa-tumblr:before{content:"\f173"}.fa-tumblr-square:before{content:"\f174"}.fa-long-arrow-down:before{content:"\f175"}.fa-long-arrow-up:before{content:"\f176"}.fa-long-arrow-left:before{content:"\f177"}.fa-long-arrow-right:before{content:"\f178"}.fa-apple:before{content:"\f179"}.fa-windows:before{content:"\f17a"}.fa-android:before{content:"\f17b"}.fa-linux:before{content:"\f17c"}.fa-dribbble:before{content:"\f17d"}.fa-skype:before{content:"\f17e"}.fa-foursquare:before{content:"\f180"}.fa-trello:before{content:"\f181"}.fa-female:before{content:"\f182"}.fa-male:before{content:"\f183"}.fa-gittip:before,.fa-gratipay:before{content:"\f184"}.fa-sun-o:before{content:"\f185"}.fa-moon-o:before{content:"\f186"}.fa-archive:before{content:"\f187"}.fa-bug:before{content:"\f188"}.fa-vk:before{content:"\f189"}.fa-weibo:before{content:"\f18a"}.fa-renren:before{content:"\f18b"}.fa-pagelines:before{content:"\f18c"}.fa-stack-exchange:before{content:"\f18d"}.fa-arrow-circle-o-right:before{content:"\f18e"}.fa-arrow-circle-o-left:before{content:"\f190"}.fa-toggle-left:before,.fa-caret-square-o-left:before{content:"\f191"}.fa-dot-circle-o:before{content:"\f192"}.fa-wheelchair:before{content:"\f193"}.fa-vimeo-square:before{content:"\f194"}.fa-turkish-lira:before,.fa-try:before{content:"\f195"}.fa-plus-square-o:before{content:"\f196"}.fa-space-shuttle:before{content:"\f197"}.fa-slack:before{content:"\f198"}.fa-envelope-square:before{content:"\f199"}.fa-wordpress:before{content:"\f19a"}.fa-openid:before{content:"\f19b"}.fa-institution:before,.fa-bank:before,.fa-university:before{content:"\f19c"}.fa-mortar-board:before,.fa-graduation-cap:before{content:"\f19d"}.fa-yahoo:before{content:"\f19e"}.fa-google:before{content:"\f1a0"}.fa-reddit:before{content:"\f1a1"}.fa-reddit-square:before{content:"\f1a2"}.fa-stumbleupon-circle:before{content:"\f1a3"}.fa-stumbleupon:before{content:"\f1a4"}.fa-delicious:before{content:"\f1a5"}.fa-digg:before{content:"\f1a6"}.fa-pied-piper-pp:before{content:"\f1a7"}.fa-pied-piper-alt:before{content:"\f1a8"}.fa-drupal:before{content:"\f1a9"}.fa-joomla:before{content:"\f1aa"}.fa-language:before{content:"\f1ab"}.fa-fax:before{content:"\f1ac"}.fa-building:before{content:"\f1ad"}.fa-child:before{content:"\f1ae"}.fa-paw:before{content:"\f1b0"}.fa-spoon:before{content:"\f1b1"}.fa-cube:before{content:"\f1b2"}.fa-cubes:before{content:"\f1b3"}.fa-behance:before{content:"\f1b4"}.fa-behance-square:before{content:"\f1b5"}.fa-steam:before{content:"\f1b6"}.fa-steam-square:before{content:"\f1b7"}.fa-recycle:before{content:"\f1b8"}.fa-automobile:before,.fa-car:before{content:"\f1b9"}.fa-cab:before,.fa-taxi:before{content:"\f1ba"}.fa-tree:before{content:"\f1bb"}.fa-spotify:before{content:"\f1bc"}.fa-deviantart:before{content:"\f1bd"}.fa-soundcloud:before{content:"\f1be"}.fa-database:before{content:"\f1c0"}.fa-file-pdf-o:before{content:"\f1c1"}.fa-file-word-o:before{content:"\f1c2"}.fa-file-excel-o:before{content:"\f1c3"}.fa-file-powerpoint-o:before{content:"\f1c4"}.fa-file-photo-o:before,.fa-file-picture-o:before,.fa-file-image-o:before{content:"\f1c5"}.fa-file-zip-o:before,.fa-file-archive-o:before{content:"\f1c6"}.fa-file-sound-o:before,.fa-file-audio-o:before{content:"\f1c7"}.fa-file-movie-o:before,.fa-file-video-o:before{content:"\f1c8"}.fa-file-code-o:before{content:"\f1c9"}.fa-vine:before{content:"\f1ca"}.fa-codepen:before{content:"\f1cb"}.fa-jsfiddle:before{content:"\f1cc"}.fa-life-bouy:before,.fa-life-buoy:before,.fa-life-saver:before,.fa-support:before,.fa-life-ring:before{content:"\f1cd"}.fa-circle-o-notch:before{content:"\f1ce"}.fa-ra:before,.fa-resistance:before,.fa-rebel:before{content:"\f1d0"}.fa-ge:before,.fa-empire:before{content:"\f1d1"}.fa-git-square:before{content:"\f1d2"}.fa-git:before{content:"\f1d3"}.fa-y-combinator-square:before,.fa-yc-square:before,.fa-hacker-news:before{content:"\f1d4"}.fa-tencent-weibo:before{content:"\f1d5"}.fa-qq:before{content:"\f1d6"}.fa-wechat:before,.fa-weixin:before{content:"\f1d7"}.fa-send:before,.fa-paper-plane:before{content:"\f1d8"}.fa-send-o:before,.fa-paper-plane-o:before{content:"\f1d9"}.fa-history:before{content:"\f1da"}.fa-circle-thin:before{content:"\f1db"}.fa-header:before{content:"\f1dc"}.fa-paragraph:before{content:"\f1dd"}.fa-sliders:before{content:"\f1de"}.fa-share-alt:before{content:"\f1e0"}.fa-share-alt-square:before{content:"\f1e1"}.fa-bomb:before{content:"\f1e2"}.fa-soccer-ball-o:before,.fa-futbol-o:before{content:"\f1e3"}.fa-tty:before{content:"\f1e4"}.fa-binoculars:before{content:"\f1e5"}.fa-plug:before{content:"\f1e6"}.fa-slideshare:before{content:"\f1e7"}.fa-twitch:before{content:"\f1e8"}.fa-yelp:before{content:"\f1e9"}.fa-newspaper-o:before{content:"\f1ea"}.fa-wifi:before{content:"\f1eb"}.fa-calculator:before{content:"\f1ec"}.fa-paypal:before{content:"\f1ed"}.fa-google-wallet:before{content:"\f1ee"}.fa-cc-visa:before{content:"\f1f0"}.fa-cc-mastercard:before{content:"\f1f1"}.fa-cc-discover:before{content:"\f1f2"}.fa-cc-amex:before{content:"\f1f3"}.fa-cc-paypal:before{content:"\f1f4"}.fa-cc-stripe:before{content:"\f1f5"}.fa-bell-slash:before{content:"\f1f6"}.fa-bell-slash-o:before{content:"\f1f7"}.fa-trash:before{content:"\f1f8"}.fa-copyright:before{content:"\f1f9"}.fa-at:before{content:"\f1fa"}.fa-eyedropper:before{content:"\f1fb"}.fa-paint-brush:before{content:"\f1fc"}.fa-birthday-cake:before{content:"\f1fd"}.fa-area-chart:before{content:"\f1fe"}.fa-pie-chart:before{content:"\f200"}.fa-line-chart:before{content:"\f201"}.fa-lastfm:before{content:"\f202"}.fa-lastfm-square:before{content:"\f203"}.fa-toggle-off:before{content:"\f204"}.fa-toggle-on:before{content:"\f205"}.fa-bicycle:before{content:"\f206"}.fa-bus:before{content:"\f207"}.fa-ioxhost:before{content:"\f208"}.fa-angellist:before{content:"\f209"}.fa-cc:before{content:"\f20a"}.fa-shekel:before,.fa-sheqel:before,.fa-ils:before{content:"\f20b"}.fa-meanpath:before{content:"\f20c"}.fa-buysellads:before{content:"\f20d"}.fa-connectdevelop:before{content:"\f20e"}.fa-dashcube:before{content:"\f210"}.fa-forumbee:before{content:"\f211"}.fa-leanpub:before{content:"\f212"}.fa-sellsy:before{content:"\f213"}.fa-shirtsinbulk:before{content:"\f214"}.fa-simplybuilt:before{content:"\f215"}.fa-skyatlas:before{content:"\f216"}.fa-cart-plus:before{content:"\f217"}.fa-cart-arrow-down:before{content:"\f218"}.fa-diamond:before{content:"\f219"}.fa-ship:before{content:"\f21a"}.fa-user-secret:before{content:"\f21b"}.fa-motorcycle:before{content:"\f21c"}.fa-street-view:before{content:"\f21d"}.fa-heartbeat:before{content:"\f21e"}.fa-venus:before{content:"\f221"}.fa-mars:before{content:"\f222"}.fa-mercury:before{content:"\f223"}.fa-intersex:before,.fa-transgender:before{content:"\f224"}.fa-transgender-alt:before{content:"\f225"}.fa-venus-double:before{content:"\f226"}.fa-mars-double:before{content:"\f227"}.fa-venus-mars:before{content:"\f228"}.fa-mars-stroke:before{content:"\f229"}.fa-mars-stroke-v:before{content:"\f22a"}.fa-mars-stroke-h:before{content:"\f22b"}.fa-neuter:before{content:"\f22c"}.fa-genderless:before{content:"\f22d"}.fa-facebook-official:before{content:"\f230"}.fa-pinterest-p:before{content:"\f231"}.fa-whatsapp:before{content:"\f232"}.fa-server:before{content:"\f233"}.fa-user-plus:before{content:"\f234"}.fa-user-times:before{content:"\f235"}.fa-hotel:before,.fa-bed:before{content:"\f236"}.fa-viacoin:before{content:"\f237"}.fa-train:before{content:"\f238"}.fa-subway:before{content:"\f239"}.fa-medium:before{content:"\f23a"}.fa-yc:before,.fa-y-combinator:before{content:"\f23b"}.fa-optin-monster:before{content:"\f23c"}.fa-opencart:before{content:"\f23d"}.fa-expeditedssl:before{content:"\f23e"}.fa-battery-4:before,.fa-battery:before,.fa-battery-full:before{content:"\f240"}.fa-battery-3:before,.fa-battery-three-quarters:before{content:"\f241"}.fa-battery-2:before,.fa-battery-half:before{content:"\f242"}.fa-battery-1:before,.fa-battery-quarter:before{content:"\f243"}.fa-battery-0:before,.fa-battery-empty:before{content:"\f244"}.fa-mouse-pointer:before{content:"\f245"}.fa-i-cursor:before{content:"\f246"}.fa-object-group:before{content:"\f247"}.fa-object-ungroup:before{content:"\f248"}.fa-sticky-note:before{content:"\f249"}.fa-sticky-note-o:before{content:"\f24a"}.fa-cc-jcb:before{content:"\f24b"}.fa-cc-diners-club:before{content:"\f24c"}.fa-clone:before{content:"\f24d"}.fa-balance-scale:before{content:"\f24e"}.fa-hourglass-o:before{content:"\f250"}.fa-hourglass-1:before,.fa-hourglass-start:before{content:"\f251"}.fa-hourglass-2:before,.fa-hourglass-half:before{content:"\f252"}.fa-hourglass-3:before,.fa-hourglass-end:before{content:"\f253"}.fa-hourglass:before{content:"\f254"}.fa-hand-grab-o:before,.fa-hand-rock-o:before{content:"\f255"}.fa-hand-stop-o:before,.fa-hand-paper-o:before{content:"\f256"}.fa-hand-scissors-o:before{content:"\f257"}.fa-hand-lizard-o:before{content:"\f258"}.fa-hand-spock-o:before{content:"\f259"}.fa-hand-pointer-o:before{content:"\f25a"}.fa-hand-peace-o:before{content:"\f25b"}.fa-trademark:before{content:"\f25c"}.fa-registered:before{content:"\f25d"}.fa-creative-commons:before{content:"\f25e"}.fa-gg:before{content:"\f260"}.fa-gg-circle:before{content:"\f261"}.fa-tripadvisor:before{content:"\f262"}.fa-odnoklassniki:before{content:"\f263"}.fa-odnoklassniki-square:before{content:"\f264"}.fa-get-pocket:before{content:"\f265"}.fa-wikipedia-w:before{content:"\f266"}.fa-safari:before{content:"\f267"}.fa-chrome:before{content:"\f268"}.fa-firefox:before{content:"\f269"}.fa-opera:before{content:"\f26a"}.fa-internet-explorer:before{content:"\f26b"}.fa-tv:before,.fa-television:before{content:"\f26c"}.fa-contao:before{content:"\f26d"}.fa-500px:before{content:"\f26e"}.fa-amazon:before{content:"\f270"}.fa-calendar-plus-o:before{content:"\f271"}.fa-calendar-minus-o:before{content:"\f272"}.fa-calendar-times-o:before{content:"\f273"}.fa-calendar-check-o:before{content:"\f274"}.fa-industry:before{content:"\f275"}.fa-map-pin:before{content:"\f276"}.fa-map-signs:before{content:"\f277"}.fa-map-o:before{content:"\f278"}.fa-map:before{content:"\f279"}.fa-commenting:before{content:"\f27a"}.fa-commenting-o:before{content:"\f27b"}.fa-houzz:before{content:"\f27c"}.fa-vimeo:before{content:"\f27d"}.fa-black-tie:before{content:"\f27e"}.fa-fonticons:before{content:"\f280"}.fa-reddit-alien:before{content:"\f281"}.fa-edge:before{content:"\f282"}.fa-credit-card-alt:before{content:"\f283"}.fa-codiepie:before{content:"\f284"}.fa-modx:before{content:"\f285"}.fa-fort-awesome:before{content:"\f286"}.fa-usb:before{content:"\f287"}.fa-product-hunt:before{content:"\f288"}.fa-mixcloud:before{content:"\f289"}.fa-scribd:before{content:"\f28a"}.fa-pause-circle:before{content:"\f28b"}.fa-pause-circle-o:before{content:"\f28c"}.fa-stop-circle:before{content:"\f28d"}.fa-stop-circle-o:before{content:"\f28e"}.fa-shopping-bag:before{content:"\f290"}.fa-shopping-basket:before{content:"\f291"}.fa-hashtag:before{content:"\f292"}.fa-bluetooth:before{content:"\f293"}.fa-bluetooth-b:before{content:"\f294"}.fa-percent:before{content:"\f295"}.fa-gitlab:before{content:"\f296"}.fa-wpbeginner:before{content:"\f297"}.fa-wpforms:before{content:"\f298"}.fa-envira:before{content:"\f299"}.fa-universal-access:before{content:"\f29a"}.fa-wheelchair-alt:before{content:"\f29b"}.fa-question-circle-o:before{content:"\f29c"}.fa-blind:before{content:"\f29d"}.fa-audio-description:before{content:"\f29e"}.fa-volume-control-phone:before{content:"\f2a0"}.fa-braille:before{content:"\f2a1"}.fa-assistive-listening-systems:before{content:"\f2a2"}.fa-asl-interpreting:before,.fa-american-sign-language-interpreting:before{content:"\f2a3"}.fa-deafness:before,.fa-hard-of-hearing:before,.fa-deaf:before{content:"\f2a4"}.fa-glide:before{content:"\f2a5"}.fa-glide-g:before{content:"\f2a6"}.fa-signing:before,.fa-sign-language:before{content:"\f2a7"}.fa-low-vision:before{content:"\f2a8"}.fa-viadeo:before{content:"\f2a9"}.fa-viadeo-square:before{content:"\f2aa"}.fa-snapchat:before{content:"\f2ab"}.fa-snapchat-ghost:before{content:"\f2ac"}.fa-snapchat-square:before{content:"\f2ad"}.fa-pied-piper:before{content:"\f2ae"}.fa-first-order:before{content:"\f2b0"}.fa-yoast:before{content:"\f2b1"}.fa-themeisle:before{content:"\f2b2"}.fa-google-plus-circle:before,.fa-google-plus-official:before{content:"\f2b3"}.fa-fa:before,.fa-font-awesome:before{content:"\f2b4"}.fa-handshake-o:before{content:"\f2b5"}.fa-envelope-open:before{content:"\f2b6"}.fa-envelope-open-o:before{content:"\f2b7"}.fa-linode:before{content:"\f2b8"}.fa-address-book:before{content:"\f2b9"}.fa-address-book-o:before{content:"\f2ba"}.fa-vcard:before,.fa-address-card:before{content:"\f2bb"}.fa-vcard-o:before,.fa-address-card-o:before{content:"\f2bc"}.fa-user-circle:before{content:"\f2bd"}.fa-user-circle-o:before{content:"\f2be"}.fa-user-o:before{content:"\f2c0"}.fa-id-badge:before{content:"\f2c1"}.fa-drivers-license:before,.fa-id-card:before{content:"\f2c2"}.fa-drivers-license-o:before,.fa-id-card-o:before{content:"\f2c3"}.fa-quora:before{content:"\f2c4"}.fa-free-code-camp:before{content:"\f2c5"}.fa-telegram:before{content:"\f2c6"}.fa-thermometer-4:before,.fa-thermometer:before,.fa-thermometer-full:before{content:"\f2c7"}.fa-thermometer-3:before,.fa-thermometer-three-quarters:before{content:"\f2c8"}.fa-thermometer-2:before,.fa-thermometer-half:before{content:"\f2c9"}.fa-thermometer-1:before,.fa-thermometer-quarter:before{content:"\f2ca"}.fa-thermometer-0:before,.fa-thermometer-empty:before{content:"\f2cb"}.fa-shower:before{content:"\f2cc"}.fa-bathtub:before,.fa-s15:before,.fa-bath:before{content:"\f2cd"}.fa-podcast:before{content:"\f2ce"}.fa-window-maximize:before{content:"\f2d0"}.fa-window-minimize:before{content:"\f2d1"}.fa-window-restore:before{content:"\f2d2"}.fa-times-rectangle:before,.fa-window-close:before{content:"\f2d3"}.fa-times-rectangle-o:before,.fa-window-close-o:before{content:"\f2d4"}.fa-bandcamp:before{content:"\f2d5"}.fa-grav:before{content:"\f2d6"}.fa-etsy:before{content:"\f2d7"}.fa-imdb:before{content:"\f2d8"}.fa-ravelry:before{content:"\f2d9"}.fa-eercast:before{content:"\f2da"}.fa-microchip:before{content:"\f2db"}.fa-snowflake-o:before{content:"\f2dc"}.fa-superpowers:before{content:"\f2dd"}.fa-wpexplorer:before{content:"\f2de"}.fa-meetup:before{content:"\f2e0"}.sr-only{position:absolute;width:1px;height:1px;padding:0;margin:-1px;overflow:hidden;clip:rect(0, 0, 0, 0);border:0}.sr-only-focusable:active,.sr-only-focusable:focus{position:static;width:auto;height:auto;margin:0;overflow:visible;clip:auto} diff --git a/HEAD/FontAwesome/fonts/FontAwesome.ttf b/HEAD/FontAwesome/fonts/FontAwesome.ttf new file mode 100644 index 000000000..35acda2fa Binary files /dev/null and b/HEAD/FontAwesome/fonts/FontAwesome.ttf differ diff --git a/HEAD/FontAwesome/fonts/fontawesome-webfont.eot b/HEAD/FontAwesome/fonts/fontawesome-webfont.eot new file mode 100644 index 000000000..e9f60ca95 Binary files /dev/null and b/HEAD/FontAwesome/fonts/fontawesome-webfont.eot differ diff --git a/HEAD/FontAwesome/fonts/fontawesome-webfont.svg b/HEAD/FontAwesome/fonts/fontawesome-webfont.svg new file mode 100644 index 000000000..855c845e5 --- /dev/null +++ b/HEAD/FontAwesome/fonts/fontawesome-webfont.svg @@ -0,0 +1,2671 @@ + + + + +Created by FontForge 20120731 at Mon Oct 24 17:37:40 2016 + By ,,, +Copyright Dave Gandy 2016. All rights reserved. + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/HEAD/FontAwesome/fonts/fontawesome-webfont.ttf b/HEAD/FontAwesome/fonts/fontawesome-webfont.ttf new file mode 100644 index 000000000..35acda2fa Binary files /dev/null and b/HEAD/FontAwesome/fonts/fontawesome-webfont.ttf differ diff --git a/HEAD/FontAwesome/fonts/fontawesome-webfont.woff b/HEAD/FontAwesome/fonts/fontawesome-webfont.woff new file mode 100644 index 000000000..400014a4b Binary files /dev/null and b/HEAD/FontAwesome/fonts/fontawesome-webfont.woff differ diff --git a/HEAD/FontAwesome/fonts/fontawesome-webfont.woff2 b/HEAD/FontAwesome/fonts/fontawesome-webfont.woff2 new file mode 100644 index 000000000..4d13fc604 Binary files /dev/null and b/HEAD/FontAwesome/fonts/fontawesome-webfont.woff2 differ diff --git a/HEAD/ayu-highlight.css b/HEAD/ayu-highlight.css new file mode 100644 index 000000000..32c943222 --- /dev/null +++ b/HEAD/ayu-highlight.css @@ -0,0 +1,78 @@ +/* +Based off of the Ayu theme +Original by Dempfi (https://github.com/dempfi/ayu) +*/ + +.hljs { + display: block; + overflow-x: auto; + background: #191f26; + color: #e6e1cf; +} + +.hljs-comment, +.hljs-quote { + color: #5c6773; + font-style: italic; +} + +.hljs-variable, +.hljs-template-variable, +.hljs-attribute, +.hljs-attr, +.hljs-regexp, +.hljs-link, +.hljs-selector-id, +.hljs-selector-class { + color: #ff7733; +} + +.hljs-number, +.hljs-meta, +.hljs-builtin-name, +.hljs-literal, +.hljs-type, +.hljs-params { + color: #ffee99; +} + +.hljs-string, +.hljs-bullet { + color: #b8cc52; +} + +.hljs-title, +.hljs-built_in, +.hljs-section { + color: #ffb454; +} + +.hljs-keyword, +.hljs-selector-tag, +.hljs-symbol { + color: #ff7733; +} + +.hljs-name { + color: #36a3d9; +} + +.hljs-tag { + color: #00568d; +} + +.hljs-emphasis { + font-style: italic; +} + +.hljs-strong { + font-weight: bold; +} + +.hljs-addition { + color: #91b362; +} + +.hljs-deletion { + color: #d96c75; +} diff --git a/HEAD/book.js b/HEAD/book.js new file mode 100644 index 000000000..d40440c72 --- /dev/null +++ b/HEAD/book.js @@ -0,0 +1,679 @@ +"use strict"; + +// Fix back button cache problem +window.onunload = function () { }; + +// Global variable, shared between modules +function playground_text(playground) { + let code_block = playground.querySelector("code"); + + if (window.ace && code_block.classList.contains("editable")) { + let editor = window.ace.edit(code_block); + return editor.getValue(); + } else { + return code_block.textContent; + } +} + +(function codeSnippets() { + function fetch_with_timeout(url, options, timeout = 6000) { + return Promise.race([ + fetch(url, options), + new Promise((_, reject) => setTimeout(() => reject(new Error('timeout')), timeout)) + ]); + } + + var playgrounds = Array.from(document.querySelectorAll(".playground")); + if (playgrounds.length > 0) { + fetch_with_timeout("https://play.rust-lang.org/meta/crates", { + headers: { + 'Content-Type': "application/json", + }, + method: 'POST', + mode: 'cors', + }) + .then(response => response.json()) + .then(response => { + // get list of crates available in the rust playground + let playground_crates = response.crates.map(item => item["id"]); + playgrounds.forEach(block => handle_crate_list_update(block, playground_crates)); + }); + } + + function handle_crate_list_update(playground_block, playground_crates) { + // update the play buttons after receiving the response + update_play_button(playground_block, playground_crates); + + // and install on change listener to dynamically update ACE editors + if (window.ace) { + let code_block = playground_block.querySelector("code"); + if (code_block.classList.contains("editable")) { + let editor = window.ace.edit(code_block); + editor.addEventListener("change", function (e) { + update_play_button(playground_block, playground_crates); + }); + // add Ctrl-Enter command to execute rust code + editor.commands.addCommand({ + name: "run", + bindKey: { + win: "Ctrl-Enter", + mac: "Ctrl-Enter" + }, + exec: _editor => run_rust_code(playground_block) + }); + } + } + } + + // updates the visibility of play button based on `no_run` class and + // used crates vs ones available on http://play.rust-lang.org + function update_play_button(pre_block, playground_crates) { + var play_button = pre_block.querySelector(".play-button"); + + // skip if code is `no_run` + if (pre_block.querySelector('code').classList.contains("no_run")) { + play_button.classList.add("hidden"); + return; + } + + // get list of `extern crate`'s from snippet + var txt = playground_text(pre_block); + var re = /extern\s+crate\s+([a-zA-Z_0-9]+)\s*;/g; + var snippet_crates = []; + var item; + while (item = re.exec(txt)) { + snippet_crates.push(item[1]); + } + + // check if all used crates are available on play.rust-lang.org + var all_available = snippet_crates.every(function (elem) { + return playground_crates.indexOf(elem) > -1; + }); + + if (all_available) { + play_button.classList.remove("hidden"); + } else { + play_button.classList.add("hidden"); + } + } + + function run_rust_code(code_block) { + var result_block = code_block.querySelector(".result"); + if (!result_block) { + result_block = document.createElement('code'); + result_block.className = 'result hljs language-bash'; + + code_block.append(result_block); + } + + let text = playground_text(code_block); + let classes = code_block.querySelector('code').classList; + let edition = "2015"; + if(classes.contains("edition2018")) { + edition = "2018"; + } else if(classes.contains("edition2021")) { + edition = "2021"; + } + var params = { + version: "stable", + optimize: "0", + code: text, + edition: edition + }; + + if (text.indexOf("#![feature") !== -1) { + params.version = "nightly"; + } + + result_block.innerText = "Running..."; + + fetch_with_timeout("https://play.rust-lang.org/evaluate.json", { + headers: { + 'Content-Type': "application/json", + }, + method: 'POST', + mode: 'cors', + body: JSON.stringify(params) + }) + .then(response => response.json()) + .then(response => { + if (response.result.trim() === '') { + result_block.innerText = "No output"; + result_block.classList.add("result-no-output"); + } else { + result_block.innerText = response.result; + result_block.classList.remove("result-no-output"); + } + }) + .catch(error => result_block.innerText = "Playground Communication: " + error.message); + } + + // Syntax highlighting Configuration + hljs.configure({ + tabReplace: ' ', // 4 spaces + languages: [], // Languages used for auto-detection + }); + + let code_nodes = Array + .from(document.querySelectorAll('code')) + // Don't highlight `inline code` blocks in headers. + .filter(function (node) {return !node.parentElement.classList.contains("header"); }); + + if (window.ace) { + // language-rust class needs to be removed for editable + // blocks or highlightjs will capture events + code_nodes + .filter(function (node) {return node.classList.contains("editable"); }) + .forEach(function (block) { block.classList.remove('language-rust'); }); + + Array + code_nodes + .filter(function (node) {return !node.classList.contains("editable"); }) + .forEach(function (block) { hljs.highlightBlock(block); }); + } else { + code_nodes.forEach(function (block) { hljs.highlightBlock(block); }); + } + + // Adding the hljs class gives code blocks the color css + // even if highlighting doesn't apply + code_nodes.forEach(function (block) { block.classList.add('hljs'); }); + + Array.from(document.querySelectorAll("code.language-rust")).forEach(function (block) { + + var lines = Array.from(block.querySelectorAll('.boring')); + // If no lines were hidden, return + if (!lines.length) { return; } + block.classList.add("hide-boring"); + + var buttons = document.createElement('div'); + buttons.className = 'buttons'; + buttons.innerHTML = ""; + + // add expand button + var pre_block = block.parentNode; + pre_block.insertBefore(buttons, pre_block.firstChild); + + pre_block.querySelector('.buttons').addEventListener('click', function (e) { + if (e.target.classList.contains('fa-eye')) { + e.target.classList.remove('fa-eye'); + e.target.classList.add('fa-eye-slash'); + e.target.title = 'Hide lines'; + e.target.setAttribute('aria-label', e.target.title); + + block.classList.remove('hide-boring'); + } else if (e.target.classList.contains('fa-eye-slash')) { + e.target.classList.remove('fa-eye-slash'); + e.target.classList.add('fa-eye'); + e.target.title = 'Show hidden lines'; + e.target.setAttribute('aria-label', e.target.title); + + block.classList.add('hide-boring'); + } + }); + }); + + if (window.playground_copyable) { + Array.from(document.querySelectorAll('pre code')).forEach(function (block) { + var pre_block = block.parentNode; + if (!pre_block.classList.contains('playground')) { + var buttons = pre_block.querySelector(".buttons"); + if (!buttons) { + buttons = document.createElement('div'); + buttons.className = 'buttons'; + pre_block.insertBefore(buttons, pre_block.firstChild); + } + + var clipButton = document.createElement('button'); + clipButton.className = 'fa fa-copy clip-button'; + clipButton.title = 'Copy to clipboard'; + clipButton.setAttribute('aria-label', clipButton.title); + clipButton.innerHTML = ''; + + buttons.insertBefore(clipButton, buttons.firstChild); + } + }); + } + + // Process playground code blocks + Array.from(document.querySelectorAll(".playground")).forEach(function (pre_block) { + // Add play button + var buttons = pre_block.querySelector(".buttons"); + if (!buttons) { + buttons = document.createElement('div'); + buttons.className = 'buttons'; + pre_block.insertBefore(buttons, pre_block.firstChild); + } + + var runCodeButton = document.createElement('button'); + runCodeButton.className = 'fa fa-play play-button'; + runCodeButton.hidden = true; + runCodeButton.title = 'Run this code'; + runCodeButton.setAttribute('aria-label', runCodeButton.title); + + buttons.insertBefore(runCodeButton, buttons.firstChild); + runCodeButton.addEventListener('click', function (e) { + run_rust_code(pre_block); + }); + + if (window.playground_copyable) { + var copyCodeClipboardButton = document.createElement('button'); + copyCodeClipboardButton.className = 'fa fa-copy clip-button'; + copyCodeClipboardButton.innerHTML = ''; + copyCodeClipboardButton.title = 'Copy to clipboard'; + copyCodeClipboardButton.setAttribute('aria-label', copyCodeClipboardButton.title); + + buttons.insertBefore(copyCodeClipboardButton, buttons.firstChild); + } + + let code_block = pre_block.querySelector("code"); + if (window.ace && code_block.classList.contains("editable")) { + var undoChangesButton = document.createElement('button'); + undoChangesButton.className = 'fa fa-history reset-button'; + undoChangesButton.title = 'Undo changes'; + undoChangesButton.setAttribute('aria-label', undoChangesButton.title); + + buttons.insertBefore(undoChangesButton, buttons.firstChild); + + undoChangesButton.addEventListener('click', function () { + let editor = window.ace.edit(code_block); + editor.setValue(editor.originalCode); + editor.clearSelection(); + }); + } + }); +})(); + +(function themes() { + var html = document.querySelector('html'); + var themeToggleButton = document.getElementById('theme-toggle'); + var themePopup = document.getElementById('theme-list'); + var themeColorMetaTag = document.querySelector('meta[name="theme-color"]'); + var stylesheets = { + ayuHighlight: document.querySelector("[href$='ayu-highlight.css']"), + tomorrowNight: document.querySelector("[href$='tomorrow-night.css']"), + highlight: document.querySelector("[href$='highlight.css']"), + }; + + function showThemes() { + themePopup.style.display = 'block'; + themeToggleButton.setAttribute('aria-expanded', true); + themePopup.querySelector("button#" + get_theme()).focus(); + } + + function hideThemes() { + themePopup.style.display = 'none'; + themeToggleButton.setAttribute('aria-expanded', false); + themeToggleButton.focus(); + } + + function get_theme() { + var theme; + try { theme = localStorage.getItem('mdbook-theme'); } catch (e) { } + if (theme === null || theme === undefined) { + return default_theme; + } else { + return theme; + } + } + + function set_theme(theme, store = true) { + let ace_theme; + + if (theme == 'coal' || theme == 'navy') { + stylesheets.ayuHighlight.disabled = true; + stylesheets.tomorrowNight.disabled = false; + stylesheets.highlight.disabled = true; + + ace_theme = "ace/theme/tomorrow_night"; + } else if (theme == 'ayu') { + stylesheets.ayuHighlight.disabled = false; + stylesheets.tomorrowNight.disabled = true; + stylesheets.highlight.disabled = true; + ace_theme = "ace/theme/tomorrow_night"; + } else { + stylesheets.ayuHighlight.disabled = true; + stylesheets.tomorrowNight.disabled = true; + stylesheets.highlight.disabled = false; + ace_theme = "ace/theme/dawn"; + } + + setTimeout(function () { + themeColorMetaTag.content = getComputedStyle(document.body).backgroundColor; + }, 1); + + if (window.ace && window.editors) { + window.editors.forEach(function (editor) { + editor.setTheme(ace_theme); + }); + } + + var previousTheme = get_theme(); + + if (store) { + try { localStorage.setItem('mdbook-theme', theme); } catch (e) { } + } + + html.classList.remove(previousTheme); + html.classList.add(theme); + } + + // Set theme + var theme = get_theme(); + + set_theme(theme, false); + + themeToggleButton.addEventListener('click', function () { + if (themePopup.style.display === 'block') { + hideThemes(); + } else { + showThemes(); + } + }); + + themePopup.addEventListener('click', function (e) { + var theme; + if (e.target.className === "theme") { + theme = e.target.id; + } else if (e.target.parentElement.className === "theme") { + theme = e.target.parentElement.id; + } else { + return; + } + set_theme(theme); + }); + + themePopup.addEventListener('focusout', function(e) { + // e.relatedTarget is null in Safari and Firefox on macOS (see workaround below) + if (!!e.relatedTarget && !themeToggleButton.contains(e.relatedTarget) && !themePopup.contains(e.relatedTarget)) { + hideThemes(); + } + }); + + // Should not be needed, but it works around an issue on macOS & iOS: https://github.com/rust-lang/mdBook/issues/628 + document.addEventListener('click', function(e) { + if (themePopup.style.display === 'block' && !themeToggleButton.contains(e.target) && !themePopup.contains(e.target)) { + hideThemes(); + } + }); + + document.addEventListener('keydown', function (e) { + if (e.altKey || e.ctrlKey || e.metaKey || e.shiftKey) { return; } + if (!themePopup.contains(e.target)) { return; } + + switch (e.key) { + case 'Escape': + e.preventDefault(); + hideThemes(); + break; + case 'ArrowUp': + e.preventDefault(); + var li = document.activeElement.parentElement; + if (li && li.previousElementSibling) { + li.previousElementSibling.querySelector('button').focus(); + } + break; + case 'ArrowDown': + e.preventDefault(); + var li = document.activeElement.parentElement; + if (li && li.nextElementSibling) { + li.nextElementSibling.querySelector('button').focus(); + } + break; + case 'Home': + e.preventDefault(); + themePopup.querySelector('li:first-child button').focus(); + break; + case 'End': + e.preventDefault(); + themePopup.querySelector('li:last-child button').focus(); + break; + } + }); +})(); + +(function sidebar() { + var html = document.querySelector("html"); + var sidebar = document.getElementById("sidebar"); + var sidebarLinks = document.querySelectorAll('#sidebar a'); + var sidebarToggleButton = document.getElementById("sidebar-toggle"); + var sidebarResizeHandle = document.getElementById("sidebar-resize-handle"); + var firstContact = null; + + function showSidebar() { + html.classList.remove('sidebar-hidden') + html.classList.add('sidebar-visible'); + Array.from(sidebarLinks).forEach(function (link) { + link.setAttribute('tabIndex', 0); + }); + sidebarToggleButton.setAttribute('aria-expanded', true); + sidebar.setAttribute('aria-hidden', false); + try { localStorage.setItem('mdbook-sidebar', 'visible'); } catch (e) { } + } + + + var sidebarAnchorToggles = document.querySelectorAll('#sidebar a.toggle'); + + function toggleSection(ev) { + ev.currentTarget.parentElement.classList.toggle('expanded'); + } + + Array.from(sidebarAnchorToggles).forEach(function (el) { + el.addEventListener('click', toggleSection); + }); + + function hideSidebar() { + html.classList.remove('sidebar-visible') + html.classList.add('sidebar-hidden'); + Array.from(sidebarLinks).forEach(function (link) { + link.setAttribute('tabIndex', -1); + }); + sidebarToggleButton.setAttribute('aria-expanded', false); + sidebar.setAttribute('aria-hidden', true); + try { localStorage.setItem('mdbook-sidebar', 'hidden'); } catch (e) { } + } + + // Toggle sidebar + sidebarToggleButton.addEventListener('click', function sidebarToggle() { + if (html.classList.contains("sidebar-hidden")) { + var current_width = parseInt( + document.documentElement.style.getPropertyValue('--sidebar-width'), 10); + if (current_width < 150) { + document.documentElement.style.setProperty('--sidebar-width', '150px'); + } + showSidebar(); + } else if (html.classList.contains("sidebar-visible")) { + hideSidebar(); + } else { + if (getComputedStyle(sidebar)['transform'] === 'none') { + hideSidebar(); + } else { + showSidebar(); + } + } + }); + + sidebarResizeHandle.addEventListener('mousedown', initResize, false); + + function initResize(e) { + window.addEventListener('mousemove', resize, false); + window.addEventListener('mouseup', stopResize, false); + html.classList.add('sidebar-resizing'); + } + function resize(e) { + var pos = (e.clientX - sidebar.offsetLeft); + if (pos < 20) { + hideSidebar(); + } else { + if (html.classList.contains("sidebar-hidden")) { + showSidebar(); + } + pos = Math.min(pos, window.innerWidth - 100); + document.documentElement.style.setProperty('--sidebar-width', pos + 'px'); + } + } + //on mouseup remove windows functions mousemove & mouseup + function stopResize(e) { + html.classList.remove('sidebar-resizing'); + window.removeEventListener('mousemove', resize, false); + window.removeEventListener('mouseup', stopResize, false); + } + + document.addEventListener('touchstart', function (e) { + firstContact = { + x: e.touches[0].clientX, + time: Date.now() + }; + }, { passive: true }); + + document.addEventListener('touchmove', function (e) { + if (!firstContact) + return; + + var curX = e.touches[0].clientX; + var xDiff = curX - firstContact.x, + tDiff = Date.now() - firstContact.time; + + if (tDiff < 250 && Math.abs(xDiff) >= 150) { + if (xDiff >= 0 && firstContact.x < Math.min(document.body.clientWidth * 0.25, 300)) + showSidebar(); + else if (xDiff < 0 && curX < 300) + hideSidebar(); + + firstContact = null; + } + }, { passive: true }); + + // Scroll sidebar to current active section + var activeSection = document.getElementById("sidebar").querySelector(".active"); + if (activeSection) { + // https://developer.mozilla.org/en-US/docs/Web/API/Element/scrollIntoView + activeSection.scrollIntoView({ block: 'center' }); + } +})(); + +(function chapterNavigation() { + document.addEventListener('keydown', function (e) { + if (e.altKey || e.ctrlKey || e.metaKey || e.shiftKey) { return; } + if (window.search && window.search.hasFocus()) { return; } + + switch (e.key) { + case 'ArrowRight': + e.preventDefault(); + var nextButton = document.querySelector('.nav-chapters.next'); + if (nextButton) { + window.location.href = nextButton.href; + } + break; + case 'ArrowLeft': + e.preventDefault(); + var previousButton = document.querySelector('.nav-chapters.previous'); + if (previousButton) { + window.location.href = previousButton.href; + } + break; + } + }); +})(); + +(function clipboard() { + var clipButtons = document.querySelectorAll('.clip-button'); + + function hideTooltip(elem) { + elem.firstChild.innerText = ""; + elem.className = 'fa fa-copy clip-button'; + } + + function showTooltip(elem, msg) { + elem.firstChild.innerText = msg; + elem.className = 'fa fa-copy tooltipped'; + } + + var clipboardSnippets = new ClipboardJS('.clip-button', { + text: function (trigger) { + hideTooltip(trigger); + let playground = trigger.closest("pre"); + return playground_text(playground); + } + }); + + Array.from(clipButtons).forEach(function (clipButton) { + clipButton.addEventListener('mouseout', function (e) { + hideTooltip(e.currentTarget); + }); + }); + + clipboardSnippets.on('success', function (e) { + e.clearSelection(); + showTooltip(e.trigger, "Copied!"); + }); + + clipboardSnippets.on('error', function (e) { + showTooltip(e.trigger, "Clipboard error!"); + }); +})(); + +(function scrollToTop () { + var menuTitle = document.querySelector('.menu-title'); + + menuTitle.addEventListener('click', function () { + document.scrollingElement.scrollTo({ top: 0, behavior: 'smooth' }); + }); +})(); + +(function controllMenu() { + var menu = document.getElementById('menu-bar'); + + (function controllPosition() { + var scrollTop = document.scrollingElement.scrollTop; + var prevScrollTop = scrollTop; + var minMenuY = -menu.clientHeight - 50; + // When the script loads, the page can be at any scroll (e.g. if you reforesh it). + menu.style.top = scrollTop + 'px'; + // Same as parseInt(menu.style.top.slice(0, -2), but faster + var topCache = menu.style.top.slice(0, -2); + menu.classList.remove('sticky'); + var stickyCache = false; // Same as menu.classList.contains('sticky'), but faster + document.addEventListener('scroll', function () { + scrollTop = Math.max(document.scrollingElement.scrollTop, 0); + // `null` means that it doesn't need to be updated + var nextSticky = null; + var nextTop = null; + var scrollDown = scrollTop > prevScrollTop; + var menuPosAbsoluteY = topCache - scrollTop; + if (scrollDown) { + nextSticky = false; + if (menuPosAbsoluteY > 0) { + nextTop = prevScrollTop; + } + } else { + if (menuPosAbsoluteY > 0) { + nextSticky = true; + } else if (menuPosAbsoluteY < minMenuY) { + nextTop = prevScrollTop + minMenuY; + } + } + if (nextSticky === true && stickyCache === false) { + menu.classList.add('sticky'); + stickyCache = true; + } else if (nextSticky === false && stickyCache === true) { + menu.classList.remove('sticky'); + stickyCache = false; + } + if (nextTop !== null) { + menu.style.top = nextTop + 'px'; + topCache = nextTop; + } + prevScrollTop = scrollTop; + }, { passive: true }); + })(); + (function controllBorder() { + menu.classList.remove('bordered'); + document.addEventListener('scroll', function () { + if (menu.offsetTop === 0) { + menu.classList.remove('bordered'); + } else { + menu.classList.add('bordered'); + } + }, { passive: true }); + })(); +})(); diff --git a/HEAD/clipboard.min.js b/HEAD/clipboard.min.js new file mode 100644 index 000000000..02c549e35 --- /dev/null +++ b/HEAD/clipboard.min.js @@ -0,0 +1,7 @@ +/*! + * clipboard.js v2.0.4 + * https://zenorocha.github.io/clipboard.js + * + * Licensed MIT © Zeno Rocha + */ +!function(t,e){"object"==typeof exports&&"object"==typeof module?module.exports=e():"function"==typeof define&&define.amd?define([],e):"object"==typeof exports?exports.ClipboardJS=e():t.ClipboardJS=e()}(this,function(){return function(n){var o={};function r(t){if(o[t])return o[t].exports;var e=o[t]={i:t,l:!1,exports:{}};return n[t].call(e.exports,e,e.exports,r),e.l=!0,e.exports}return r.m=n,r.c=o,r.d=function(t,e,n){r.o(t,e)||Object.defineProperty(t,e,{enumerable:!0,get:n})},r.r=function(t){"undefined"!=typeof Symbol&&Symbol.toStringTag&&Object.defineProperty(t,Symbol.toStringTag,{value:"Module"}),Object.defineProperty(t,"__esModule",{value:!0})},r.t=function(e,t){if(1&t&&(e=r(e)),8&t)return e;if(4&t&&"object"==typeof e&&e&&e.__esModule)return e;var n=Object.create(null);if(r.r(n),Object.defineProperty(n,"default",{enumerable:!0,value:e}),2&t&&"string"!=typeof e)for(var o in e)r.d(n,o,function(t){return e[t]}.bind(null,o));return n},r.n=function(t){var e=t&&t.__esModule?function(){return t.default}:function(){return t};return r.d(e,"a",e),e},r.o=function(t,e){return Object.prototype.hasOwnProperty.call(t,e)},r.p="",r(r.s=0)}([function(t,e,n){"use strict";var r="function"==typeof Symbol&&"symbol"==typeof Symbol.iterator?function(t){return typeof t}:function(t){return t&&"function"==typeof Symbol&&t.constructor===Symbol&&t!==Symbol.prototype?"symbol":typeof t},i=function(){function o(t,e){for(var n=0;n + + + + + Boot Stages - Rust UEFI Book + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ +
+ + + + + + + +
+
+

Boot Stages

+

A UEFI system goes through several distinct phases during the boot process.

+
    +
  1. Platform Initialization. This early-boot phase is mostly outside +the scope of uefi-rs. It is described by the UEFI Platform +Initialization Specification, which is separate from the main UEFI +Specification.
  2. +
  3. Boot Services. This is when UEFI drivers and applications are +loaded. Both the BootServices and RuntimeServices tables are +accessible. This stage typically culminates in running a bootloader +that loads an operating system. The stage ends when +SystemTable::exit_boot_services is called, putting the system in +Runtime mode.
  4. +
  5. Runtime. This stage is typically active when running an operating +system such as Linux or Windows. UEFI functionality is much more +limited in the Runtime mode. The BootServices table is no longer +accessible, but the RuntimeServices table is still +available. Once the system is in Runtime mode, it cannot return to +the Boot Services stage until after a system reset.
  6. +
+ +
+ + +
+
+ + + +
+ + + + + + + + + + + + diff --git a/HEAD/concepts/device_paths.html b/HEAD/concepts/device_paths.html new file mode 100644 index 000000000..39746ccf7 --- /dev/null +++ b/HEAD/concepts/device_paths.html @@ -0,0 +1,191 @@ + + + + + + Device Paths - Rust UEFI Book + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ +
+ + + + + + + +
+
+

Device Paths

+

A device path is a very flexible packed data structure for storing paths +to many kinds of device. Note that these device paths are not the same +thing as file system paths, although they can include file system +paths. Like handles, device paths can be used to uniquely identify +resources such as consoles, mice, disks, partitions, and more. Unlike +handles, which are essentially opaque pointers, device paths are +variable-length structures that contain parseable information.

+

The uefi::proto::device_path module documentation describes the +details of how device paths are encoded.

+

Device paths can also be converted to and from human-readable text +representations that look like this:

+
PciRoot(0x0)/Pci(0x1F,0x2)/Sata(0x0,0xFFFF,0x0)/HD(1,MBR,0xBE1AFDFA,0x3F,0xFBFC1)
+
+

See uefi::proto::device_path::text for details.

+ +
+ + +
+
+ + + +
+ + + + + + + + + + + + diff --git a/HEAD/concepts/gpt.html b/HEAD/concepts/gpt.html new file mode 100644 index 000000000..a687866ef --- /dev/null +++ b/HEAD/concepts/gpt.html @@ -0,0 +1,215 @@ + + + + + + GPT - Rust UEFI Book + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ +
+ + + + + + + +
+
+

GPT

+

GPT is short for GUID Partition Table. It's a more modern +alternative to MBR (master boot record) partition tables. Although it's +defined in the UEFI specification, it often gets used on non-UEFI +systems too. There are a couple big advantages of using GPT over MBR:

+
    +
  • It has a relatively clear and precise standard, unlike MBR where +implementations often just try to match what other implementations do.
  • +
  • It supports very large disks and very large numbers of partitions.
  • +
+

A GPT disk contains a primary header near the beginning of the disk, +followed by a partition entry array. The header and partition entry +array have a secondary copy at the end of the disk for redundancy. The +partition entry arrays contain structures that describe each partition, +including a GUID to identify the individual partition, a partition type +GUID to indicate the purpose of the partition, and start/end block +addresses. In between the entry arrays is the actual partition data.

+

System partition

+

The system partition is UEFI's version of a bootable partition. The +system partition is sometimes called the ESP, or EFI System +Partition. It is identified by a partition type of +c12a7328-f81f-11d2-ba4b-00a0c93ec93b. The system partition always +contains a FAT file system. There are various standardized paths that +can exist within the file system, and of particular importance are the +boot files. These are the files that UEFI will try to boot from by +default (in the absence of a different boot configuration set through +special UEFI variables).

+

Boot files are under \EFI\BOOT, and are named BOOT<ARCH>.efi, where +<ARCH> is a short architecture name.

+
+ + + + + + + + +
ArchitectureFile name
Intel 32-bitBOOTIA32.EFI
X86_64BOOTX64.EFI
ItaniumBOOTIA64.EFI
AArch32BOOTARM.EFI
AArch64BOOTAA64.EFI
RISC-V 32-bitBOOTRISCV32.EFI
RISC-V 64-bitBOOTRISCV64.EFI
RISC-V 128-bitBOOTRISCV128.EFI
+
+
+ + +
+
+ + + +
+ + + + + + + + + + + + diff --git a/HEAD/concepts/guid.html b/HEAD/concepts/guid.html new file mode 100644 index 000000000..ffa61eda0 --- /dev/null +++ b/HEAD/concepts/guid.html @@ -0,0 +1,187 @@ + + + + + + GUID - Rust UEFI Book + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ +
+ + + + + + + +
+
+

GUID

+

GUID is short for Globally Unique Identifier. A GUID is always 16 bytes, +and has a standard string representation format that looks like this: +313b0d7c-fed4-4de7-99ed-2fe48874a410. The details of the GUID format +aren't too important, but be aware that the actual byte representation +is not in the same order as the string representation because the first +three fields are little-endian. For the most part you can treat GUIDs as +opaque identifiers.

+

The UEFI specification uses GUIDs all over the place. GUIDs are used to +identify protocols, disk partitions, variable groupings, and much +more. In uefi-rs, GUIDs are represented by the Guid type.

+ +
+ + +
+
+ + + +
+ + + + + + + + + + + + diff --git a/HEAD/concepts/handles_and_protocols.html b/HEAD/concepts/handles_and_protocols.html new file mode 100644 index 000000000..41eb0e0d1 --- /dev/null +++ b/HEAD/concepts/handles_and_protocols.html @@ -0,0 +1,201 @@ + + + + + + Handles and Protocols - Rust UEFI Book + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ +
+ + + + + + + +
+
+

Handles and Protocols

+

Handles and protocols are at the core of what makes UEFI +extensible. Together they are the mechanism by which UEFI can adapt to a +wide array of hardware and boot conditions, while still providing a +consistent interface to drivers and applications.

+

Handles

+

Handles represent resources. A resource might be a physical device such +as a disk drive or USB device, or something less tangible like a loaded +executable.

+

A Handle is an opaque pointer, so you can't do anything with it +directly. To operate on a handle you have to open a protocol.

+

Protocols

+

Protocols are interfaces that provide functions to interact with a +resource. For example, the BlockIO protocol provides functions to read +and write to block IO devices.

+

Protocols are only available during the Boot Services stage; you can't +access them during the Runtime stage.

+

The UEFI Specification defines a very large number of protocols. Because +protocols are inherently very diverse, the best place to learn about +individual protocols is the UEFI Specification. There are many +chapters covering various protocols. Not all of these protocols are +wrapped by uefi-rs yet (contributions welcome!) but many of the most +commonly useful ones are.

+

See the Using Protocols how-to for details of the uefi-rs API for +interacting with protocols.

+ +
+ + +
+
+ + + +
+ + + + + + + + + + + + diff --git a/HEAD/concepts/introduction.html b/HEAD/concepts/introduction.html new file mode 100644 index 000000000..762dda7f0 --- /dev/null +++ b/HEAD/concepts/introduction.html @@ -0,0 +1,183 @@ + + + + + + Concepts - Rust UEFI Book + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ +
+ + + + + + + +
+
+

Concepts

+

The canonical source of information about UEFI is the UEFI specification. +The specification is huge (currently nearly 2500 pages). Much of that +content relates to optional services, understanding of which is not +critical to understanding UEFI as a whole. This chapter summarizes some +of the more important UEFI concepts and links to the relevant uefi-rs +documentation.

+ +
+ + +
+
+ + + +
+ + + + + + + + + + + + diff --git a/HEAD/concepts/tables.html b/HEAD/concepts/tables.html new file mode 100644 index 000000000..427b38d1e --- /dev/null +++ b/HEAD/concepts/tables.html @@ -0,0 +1,198 @@ + + + + + + Tables - Rust UEFI Book + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ +
+ + + + + + + +
+
+

Tables

+

UEFI has a few table structures. These tables are how you get access to +UEFI services.

+

SystemTable (EFI_SYSTEM_TABLE in the specification) is the +top-level table that provides access to the other tables.

+

BootServices (EFI_BOOT_SERVICES in the specification) provides +access to a wide array of services such as memory allocation, executable +loading, and optional extension interfaces called protocols. This table +is only accessible while in the Boot Services stage.

+

RuntimeServices (EFI_RUNTIME_SERVICES in the specification) +provides access to a fairly limited set of services, including variable +storage, system time, and virtual-memory mapping. This table is +accessible during both the Boot Services and Runtime stages.

+

When writing a UEFI application, you get access to the system table from +one of the arguments to the main entry point:

+
fn main(handle: Handle, mut system_table: SystemTable<Boot>) -> Status;
+
+

Then use SystemTable::boot_services and +SystemTable::runtime_services to get access to the other +tables. Once SystemTable::exit_boot_services is called, the original +system table is consumed and a new system table is returned that only +provides access to the RuntimeServices table.

+ +
+ + +
+
+ + + +
+ + + + + + + + + + + + diff --git a/HEAD/concepts/variables.html b/HEAD/concepts/variables.html new file mode 100644 index 000000000..4bc977e51 --- /dev/null +++ b/HEAD/concepts/variables.html @@ -0,0 +1,203 @@ + + + + + + Variables - Rust UEFI Book + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ +
+ + + + + + + +
+
+

Variables

+

UEFI provides fairly flexible key/value variable storage.

+

Each variable is identified by a key consisting of a UCS-2 +null-terminated name plus a vendor GUID. The vendor GUID serves as a +namespace for variables so that different vendors don't accidentally +overwrite or misinterpret another vendor's variable if they happen to +have the same name.

+

The data stored in each variable is an arbitrary byte array.

+

Attributes

+

Each variable has attributes (represented as bit flags) associated with +it that affect how it is stored and how it can be accessed.

+

If the BOOTSERVICE_ACCESS and RUNTIME_ACCESS bits are set, the +variable can be accessed during both the Boot Services and Runtime +stages. If only BOOTSERVICE_ACCESS is set then the variable can +neither be read nor written to after exiting boot services.

+

Another important attribute is the NON_VOLATILE bit. If this bit is +not set, the variable will be stored in normal memory and will not +persist across a power cycle. If this bit is set, the variable will be +stored in special non-volatile memory. You should be careful about +writing variables of this type, because the non-volatile storage can be +very limited in size. There have been cases where a vendor's poor UEFI +implementation caused the machine not too boot once the storage became +too full. Even figuring out how much space is in use can be tricky due +to deletion being implemented via garbage collection. Matthew Garret's +article "Dealing with UEFI non-volatile memory quirks" has more details.

+

Most of the other attributes relate to authenticated variables, which +can be used to prevent changes to a variable by unauthorized programs.

+ +
+ + +
+
+ + + +
+ + + + + + + + + + + + diff --git a/HEAD/css/chrome.css b/HEAD/css/chrome.css new file mode 100644 index 000000000..10fa4b365 --- /dev/null +++ b/HEAD/css/chrome.css @@ -0,0 +1,534 @@ +/* CSS for UI elements (a.k.a. chrome) */ + +@import 'variables.css'; + +::-webkit-scrollbar { + background: var(--bg); +} +::-webkit-scrollbar-thumb { + background: var(--scrollbar); +} +html { + scrollbar-color: var(--scrollbar) var(--bg); +} +#searchresults a, +.content a:link, +a:visited, +a > .hljs { + color: var(--links); +} + +/* Menu Bar */ + +#menu-bar, +#menu-bar-hover-placeholder { + z-index: 101; + margin: auto calc(0px - var(--page-padding)); +} +#menu-bar { + position: relative; + display: flex; + flex-wrap: wrap; + background-color: var(--bg); + border-bottom-color: var(--bg); + border-bottom-width: 1px; + border-bottom-style: solid; +} +#menu-bar.sticky, +.js #menu-bar-hover-placeholder:hover + #menu-bar, +.js #menu-bar:hover, +.js.sidebar-visible #menu-bar { + position: -webkit-sticky; + position: sticky; + top: 0 !important; +} +#menu-bar-hover-placeholder { + position: sticky; + position: -webkit-sticky; + top: 0; + height: var(--menu-bar-height); +} +#menu-bar.bordered { + border-bottom-color: var(--table-border-color); +} +#menu-bar i, #menu-bar .icon-button { + position: relative; + padding: 0 8px; + z-index: 10; + line-height: var(--menu-bar-height); + cursor: pointer; + transition: color 0.5s; +} +@media only screen and (max-width: 420px) { + #menu-bar i, #menu-bar .icon-button { + padding: 0 5px; + } +} + +.icon-button { + border: none; + background: none; + padding: 0; + color: inherit; +} +.icon-button i { + margin: 0; +} + +.right-buttons { + margin: 0 15px; +} +.right-buttons a { + text-decoration: none; +} + +.left-buttons { + display: flex; + margin: 0 5px; +} +.no-js .left-buttons { + display: none; +} + +.menu-title { + display: inline-block; + font-weight: 200; + font-size: 2.4rem; + line-height: var(--menu-bar-height); + text-align: center; + margin: 0; + flex: 1; + white-space: nowrap; + overflow: hidden; + text-overflow: ellipsis; +} +.js .menu-title { + cursor: pointer; +} + +.menu-bar, +.menu-bar:visited, +.nav-chapters, +.nav-chapters:visited, +.mobile-nav-chapters, +.mobile-nav-chapters:visited, +.menu-bar .icon-button, +.menu-bar a i { + color: var(--icons); +} + +.menu-bar i:hover, +.menu-bar .icon-button:hover, +.nav-chapters:hover, +.mobile-nav-chapters i:hover { + color: var(--icons-hover); +} + +/* Nav Icons */ + +.nav-chapters { + font-size: 2.5em; + text-align: center; + text-decoration: none; + + position: fixed; + top: 0; + bottom: 0; + margin: 0; + max-width: 150px; + min-width: 90px; + + display: flex; + justify-content: center; + align-content: center; + flex-direction: column; + + transition: color 0.5s, background-color 0.5s; +} + +.nav-chapters:hover { + text-decoration: none; + background-color: var(--theme-hover); + transition: background-color 0.15s, color 0.15s; +} + +.nav-wrapper { + margin-top: 50px; + display: none; +} + +.mobile-nav-chapters { + font-size: 2.5em; + text-align: center; + text-decoration: none; + width: 90px; + border-radius: 5px; + background-color: var(--sidebar-bg); +} + +.previous { + float: left; +} + +.next { + float: right; + right: var(--page-padding); +} + +@media only screen and (max-width: 1080px) { + .nav-wide-wrapper { display: none; } + .nav-wrapper { display: block; } +} + +@media only screen and (max-width: 1380px) { + .sidebar-visible .nav-wide-wrapper { display: none; } + .sidebar-visible .nav-wrapper { display: block; } +} + +/* Inline code */ + +:not(pre) > .hljs { + display: inline; + padding: 0.1em 0.3em; + border-radius: 3px; +} + +:not(pre):not(a) > .hljs { + color: var(--inline-code-color); + overflow-x: initial; +} + +a:hover > .hljs { + text-decoration: underline; +} + +pre { + position: relative; +} +pre > .buttons { + position: absolute; + z-index: 100; + right: 0px; + top: 2px; + margin: 0px; + padding: 2px 0px; + + color: var(--sidebar-fg); + cursor: pointer; + visibility: hidden; + opacity: 0; + transition: visibility 0.1s linear, opacity 0.1s linear; +} +pre:hover > .buttons { + visibility: visible; + opacity: 1 +} +pre > .buttons :hover { + color: var(--sidebar-active); + border-color: var(--icons-hover); + background-color: var(--theme-hover); +} +pre > .buttons i { + margin-left: 8px; +} +pre > .buttons button { + cursor: inherit; + margin: 0px 5px; + padding: 3px 5px; + font-size: 14px; + + border-style: solid; + border-width: 1px; + border-radius: 4px; + border-color: var(--icons); + background-color: var(--theme-popup-bg); + transition: 100ms; + transition-property: color,border-color,background-color; + color: var(--icons); +} +@media (pointer: coarse) { + pre > .buttons button { + /* On mobile, make it easier to tap buttons. */ + padding: 0.3rem 1rem; + } +} +pre > code { + padding: 1rem; +} + +/* FIXME: ACE editors overlap their buttons because ACE does absolute + positioning within the code block which breaks padding. The only solution I + can think of is to move the padding to the outer pre tag (or insert a div + wrapper), but that would require fixing a whole bunch of CSS rules. +*/ +.hljs.ace_editor { + padding: 0rem 0rem; +} + +pre > .result { + margin-top: 10px; +} + +/* Search */ + +#searchresults a { + text-decoration: none; +} + +mark { + border-radius: 2px; + padding: 0 3px 1px 3px; + margin: 0 -3px -1px -3px; + background-color: var(--search-mark-bg); + transition: background-color 300ms linear; + cursor: pointer; +} + +mark.fade-out { + background-color: rgba(0,0,0,0) !important; + cursor: auto; +} + +.searchbar-outer { + margin-left: auto; + margin-right: auto; + max-width: var(--content-max-width); +} + +#searchbar { + width: 100%; + margin: 5px auto 0px auto; + padding: 10px 16px; + transition: box-shadow 300ms ease-in-out; + border: 1px solid var(--searchbar-border-color); + border-radius: 3px; + background-color: var(--searchbar-bg); + color: var(--searchbar-fg); +} +#searchbar:focus, +#searchbar.active { + box-shadow: 0 0 3px var(--searchbar-shadow-color); +} + +.searchresults-header { + font-weight: bold; + font-size: 1em; + padding: 18px 0 0 5px; + color: var(--searchresults-header-fg); +} + +.searchresults-outer { + margin-left: auto; + margin-right: auto; + max-width: var(--content-max-width); + border-bottom: 1px dashed var(--searchresults-border-color); +} + +ul#searchresults { + list-style: none; + padding-left: 20px; +} +ul#searchresults li { + margin: 10px 0px; + padding: 2px; + border-radius: 2px; +} +ul#searchresults li.focus { + background-color: var(--searchresults-li-bg); +} +ul#searchresults span.teaser { + display: block; + clear: both; + margin: 5px 0 0 20px; + font-size: 0.8em; +} +ul#searchresults span.teaser em { + font-weight: bold; + font-style: normal; +} + +/* Sidebar */ + +.sidebar { + position: fixed; + left: 0; + top: 0; + bottom: 0; + width: var(--sidebar-width); + font-size: 0.875em; + box-sizing: border-box; + -webkit-overflow-scrolling: touch; + overscroll-behavior-y: contain; + background-color: var(--sidebar-bg); + color: var(--sidebar-fg); +} +.sidebar-resizing { + -moz-user-select: none; + -webkit-user-select: none; + -ms-user-select: none; + user-select: none; +} +.js:not(.sidebar-resizing) .sidebar { + transition: transform 0.3s; /* Animation: slide away */ +} +.sidebar code { + line-height: 2em; +} +.sidebar .sidebar-scrollbox { + overflow-y: auto; + position: absolute; + top: 0; + bottom: 0; + left: 0; + right: 0; + padding: 10px 10px; +} +.sidebar .sidebar-resize-handle { + position: absolute; + cursor: col-resize; + width: 0; + right: 0; + top: 0; + bottom: 0; +} +.js .sidebar .sidebar-resize-handle { + cursor: col-resize; + width: 5px; +} +.sidebar-hidden .sidebar { + transform: translateX(calc(0px - var(--sidebar-width))); +} +.sidebar::-webkit-scrollbar { + background: var(--sidebar-bg); +} +.sidebar::-webkit-scrollbar-thumb { + background: var(--scrollbar); +} + +.sidebar-visible .page-wrapper { + transform: translateX(var(--sidebar-width)); +} +@media only screen and (min-width: 620px) { + .sidebar-visible .page-wrapper { + transform: none; + margin-left: var(--sidebar-width); + } +} + +.chapter { + list-style: none outside none; + padding-left: 0; + line-height: 2.2em; +} + +.chapter ol { + width: 100%; +} + +.chapter li { + display: flex; + color: var(--sidebar-non-existant); +} +.chapter li a { + display: block; + padding: 0; + text-decoration: none; + color: var(--sidebar-fg); +} + +.chapter li a:hover { + color: var(--sidebar-active); +} + +.chapter li a.active { + color: var(--sidebar-active); +} + +.chapter li > a.toggle { + cursor: pointer; + display: block; + margin-left: auto; + padding: 0 10px; + user-select: none; + opacity: 0.68; +} + +.chapter li > a.toggle div { + transition: transform 0.5s; +} + +/* collapse the section */ +.chapter li:not(.expanded) + li > ol { + display: none; +} + +.chapter li.chapter-item { + line-height: 1.5em; + margin-top: 0.6em; +} + +.chapter li.expanded > a.toggle div { + transform: rotate(90deg); +} + +.spacer { + width: 100%; + height: 3px; + margin: 5px 0px; +} +.chapter .spacer { + background-color: var(--sidebar-spacer); +} + +@media (-moz-touch-enabled: 1), (pointer: coarse) { + .chapter li a { padding: 5px 0; } + .spacer { margin: 10px 0; } +} + +.section { + list-style: none outside none; + padding-left: 20px; + line-height: 1.9em; +} + +/* Theme Menu Popup */ + +.theme-popup { + position: absolute; + left: 10px; + top: var(--menu-bar-height); + z-index: 1000; + border-radius: 4px; + font-size: 0.7em; + color: var(--fg); + background: var(--theme-popup-bg); + border: 1px solid var(--theme-popup-border); + margin: 0; + padding: 0; + list-style: none; + display: none; +} +.theme-popup .default { + color: var(--icons); +} +.theme-popup .theme { + width: 100%; + border: 0; + margin: 0; + padding: 2px 10px; + line-height: 25px; + white-space: nowrap; + text-align: left; + cursor: pointer; + color: inherit; + background: inherit; + font-size: inherit; +} +.theme-popup .theme:hover { + background-color: var(--theme-hover); +} +.theme-popup .theme:hover:first-child, +.theme-popup .theme:hover:last-child { + border-top-left-radius: inherit; + border-top-right-radius: inherit; +} diff --git a/HEAD/css/general.css b/HEAD/css/general.css new file mode 100644 index 000000000..0e4f07a50 --- /dev/null +++ b/HEAD/css/general.css @@ -0,0 +1,191 @@ +/* Base styles and content styles */ + +@import 'variables.css'; + +:root { + /* Browser default font-size is 16px, this way 1 rem = 10px */ + font-size: 62.5%; +} + +html { + font-family: "Open Sans", sans-serif; + color: var(--fg); + background-color: var(--bg); + text-size-adjust: none; + -webkit-text-size-adjust: none; +} + +body { + margin: 0; + font-size: 1.6rem; + overflow-x: hidden; +} + +code { + font-family: "Source Code Pro", Consolas, "Ubuntu Mono", Menlo, "DejaVu Sans Mono", monospace, monospace !important; + font-size: 0.875em; /* please adjust the ace font size accordingly in editor.js */ +} + +/* make long words/inline code not x overflow */ +main { + overflow-wrap: break-word; +} + +/* make wide tables scroll if they overflow */ +.table-wrapper { + overflow-x: auto; +} + +/* Don't change font size in headers. */ +h1 code, h2 code, h3 code, h4 code, h5 code, h6 code { + font-size: unset; +} + +.left { float: left; } +.right { float: right; } +.boring { opacity: 0.6; } +.hide-boring .boring { display: none; } +.hidden { display: none !important; } + +h2, h3 { margin-top: 2.5em; } +h4, h5 { margin-top: 2em; } + +.header + .header h3, +.header + .header h4, +.header + .header h5 { + margin-top: 1em; +} + +h1:target::before, +h2:target::before, +h3:target::before, +h4:target::before, +h5:target::before, +h6:target::before { + display: inline-block; + content: "»"; + margin-left: -30px; + width: 30px; +} + +/* This is broken on Safari as of version 14, but is fixed + in Safari Technology Preview 117 which I think will be Safari 14.2. + https://bugs.webkit.org/show_bug.cgi?id=218076 +*/ +:target { + scroll-margin-top: calc(var(--menu-bar-height) + 0.5em); +} + +.page { + outline: 0; + padding: 0 var(--page-padding); + margin-top: calc(0px - var(--menu-bar-height)); /* Compensate for the #menu-bar-hover-placeholder */ +} +.page-wrapper { + box-sizing: border-box; +} +.js:not(.sidebar-resizing) .page-wrapper { + transition: margin-left 0.3s ease, transform 0.3s ease; /* Animation: slide away */ +} + +.content { + overflow-y: auto; + padding: 0 5px 50px 5px; +} +.content main { + margin-left: auto; + margin-right: auto; + max-width: var(--content-max-width); +} +.content p { line-height: 1.45em; } +.content ol { line-height: 1.45em; } +.content ul { line-height: 1.45em; } +.content a { text-decoration: none; } +.content a:hover { text-decoration: underline; } +.content img, .content video { max-width: 100%; } +.content .header:link, +.content .header:visited { + color: var(--fg); +} +.content .header:link, +.content .header:visited:hover { + text-decoration: none; +} + +table { + margin: 0 auto; + border-collapse: collapse; +} +table td { + padding: 3px 20px; + border: 1px var(--table-border-color) solid; +} +table thead { + background: var(--table-header-bg); +} +table thead td { + font-weight: 700; + border: none; +} +table thead th { + padding: 3px 20px; +} +table thead tr { + border: 1px var(--table-header-bg) solid; +} +/* Alternate background colors for rows */ +table tbody tr:nth-child(2n) { + background: var(--table-alternate-bg); +} + + +blockquote { + margin: 20px 0; + padding: 0 20px; + color: var(--fg); + background-color: var(--quote-bg); + border-top: .1em solid var(--quote-border); + border-bottom: .1em solid var(--quote-border); +} + + +:not(.footnote-definition) + .footnote-definition, +.footnote-definition + :not(.footnote-definition) { + margin-top: 2em; +} +.footnote-definition { + font-size: 0.9em; + margin: 0.5em 0; +} +.footnote-definition p { + display: inline; +} + +.tooltiptext { + position: absolute; + visibility: hidden; + color: #fff; + background-color: #333; + transform: translateX(-50%); /* Center by moving tooltip 50% of its width left */ + left: -8px; /* Half of the width of the icon */ + top: -35px; + font-size: 0.8em; + text-align: center; + border-radius: 6px; + padding: 5px 8px; + margin: 5px; + z-index: 1000; +} +.tooltipped .tooltiptext { + visibility: visible; +} + +.chapter li.part-title { + color: var(--sidebar-fg); + margin: 5px 0px; + font-weight: bold; +} + +.result-no-output { + font-style: italic; +} diff --git a/HEAD/css/print.css b/HEAD/css/print.css new file mode 100644 index 000000000..5e690f755 --- /dev/null +++ b/HEAD/css/print.css @@ -0,0 +1,54 @@ + +#sidebar, +#menu-bar, +.nav-chapters, +.mobile-nav-chapters { + display: none; +} + +#page-wrapper.page-wrapper { + transform: none; + margin-left: 0px; + overflow-y: initial; +} + +#content { + max-width: none; + margin: 0; + padding: 0; +} + +.page { + overflow-y: initial; +} + +code { + background-color: #666666; + border-radius: 5px; + + /* Force background to be printed in Chrome */ + -webkit-print-color-adjust: exact; +} + +pre > .buttons { + z-index: 2; +} + +a, a:visited, a:active, a:hover { + color: #4183c4; + text-decoration: none; +} + +h1, h2, h3, h4, h5, h6 { + page-break-inside: avoid; + page-break-after: avoid; +} + +pre, code { + page-break-inside: avoid; + white-space: pre-wrap; +} + +.fa { + display: none !important; +} diff --git a/HEAD/css/variables.css b/HEAD/css/variables.css new file mode 100644 index 000000000..56b634bc3 --- /dev/null +++ b/HEAD/css/variables.css @@ -0,0 +1,253 @@ + +/* Globals */ + +:root { + --sidebar-width: 300px; + --page-padding: 15px; + --content-max-width: 750px; + --menu-bar-height: 50px; +} + +/* Themes */ + +.ayu { + --bg: hsl(210, 25%, 8%); + --fg: #c5c5c5; + + --sidebar-bg: #14191f; + --sidebar-fg: #c8c9db; + --sidebar-non-existant: #5c6773; + --sidebar-active: #ffb454; + --sidebar-spacer: #2d334f; + + --scrollbar: var(--sidebar-fg); + + --icons: #737480; + --icons-hover: #b7b9cc; + + --links: #0096cf; + + --inline-code-color: #ffb454; + + --theme-popup-bg: #14191f; + --theme-popup-border: #5c6773; + --theme-hover: #191f26; + + --quote-bg: hsl(226, 15%, 17%); + --quote-border: hsl(226, 15%, 22%); + + --table-border-color: hsl(210, 25%, 13%); + --table-header-bg: hsl(210, 25%, 28%); + --table-alternate-bg: hsl(210, 25%, 11%); + + --searchbar-border-color: #848484; + --searchbar-bg: #424242; + --searchbar-fg: #fff; + --searchbar-shadow-color: #d4c89f; + --searchresults-header-fg: #666; + --searchresults-border-color: #888; + --searchresults-li-bg: #252932; + --search-mark-bg: #e3b171; +} + +.coal { + --bg: hsl(200, 7%, 8%); + --fg: #98a3ad; + + --sidebar-bg: #292c2f; + --sidebar-fg: #a1adb8; + --sidebar-non-existant: #505254; + --sidebar-active: #3473ad; + --sidebar-spacer: #393939; + + --scrollbar: var(--sidebar-fg); + + --icons: #43484d; + --icons-hover: #b3c0cc; + + --links: #2b79a2; + + --inline-code-color: #c5c8c6; + + --theme-popup-bg: #141617; + --theme-popup-border: #43484d; + --theme-hover: #1f2124; + + --quote-bg: hsl(234, 21%, 18%); + --quote-border: hsl(234, 21%, 23%); + + --table-border-color: hsl(200, 7%, 13%); + --table-header-bg: hsl(200, 7%, 28%); + --table-alternate-bg: hsl(200, 7%, 11%); + + --searchbar-border-color: #aaa; + --searchbar-bg: #b7b7b7; + --searchbar-fg: #000; + --searchbar-shadow-color: #aaa; + --searchresults-header-fg: #666; + --searchresults-border-color: #98a3ad; + --searchresults-li-bg: #2b2b2f; + --search-mark-bg: #355c7d; +} + +.light { + --bg: hsl(0, 0%, 100%); + --fg: hsl(0, 0%, 0%); + + --sidebar-bg: #fafafa; + --sidebar-fg: hsl(0, 0%, 0%); + --sidebar-non-existant: #aaaaaa; + --sidebar-active: #1f1fff; + --sidebar-spacer: #f4f4f4; + + --scrollbar: #8F8F8F; + + --icons: #747474; + --icons-hover: #000000; + + --links: #20609f; + + --inline-code-color: #301900; + + --theme-popup-bg: #fafafa; + --theme-popup-border: #cccccc; + --theme-hover: #e6e6e6; + + --quote-bg: hsl(197, 37%, 96%); + --quote-border: hsl(197, 37%, 91%); + + --table-border-color: hsl(0, 0%, 95%); + --table-header-bg: hsl(0, 0%, 80%); + --table-alternate-bg: hsl(0, 0%, 97%); + + --searchbar-border-color: #aaa; + --searchbar-bg: #fafafa; + --searchbar-fg: #000; + --searchbar-shadow-color: #aaa; + --searchresults-header-fg: #666; + --searchresults-border-color: #888; + --searchresults-li-bg: #e4f2fe; + --search-mark-bg: #a2cff5; +} + +.navy { + --bg: hsl(226, 23%, 11%); + --fg: #bcbdd0; + + --sidebar-bg: #282d3f; + --sidebar-fg: #c8c9db; + --sidebar-non-existant: #505274; + --sidebar-active: #2b79a2; + --sidebar-spacer: #2d334f; + + --scrollbar: var(--sidebar-fg); + + --icons: #737480; + --icons-hover: #b7b9cc; + + --links: #2b79a2; + + --inline-code-color: #c5c8c6; + + --theme-popup-bg: #161923; + --theme-popup-border: #737480; + --theme-hover: #282e40; + + --quote-bg: hsl(226, 15%, 17%); + --quote-border: hsl(226, 15%, 22%); + + --table-border-color: hsl(226, 23%, 16%); + --table-header-bg: hsl(226, 23%, 31%); + --table-alternate-bg: hsl(226, 23%, 14%); + + --searchbar-border-color: #aaa; + --searchbar-bg: #aeaec6; + --searchbar-fg: #000; + --searchbar-shadow-color: #aaa; + --searchresults-header-fg: #5f5f71; + --searchresults-border-color: #5c5c68; + --searchresults-li-bg: #242430; + --search-mark-bg: #a2cff5; +} + +.rust { + --bg: hsl(60, 9%, 87%); + --fg: #262625; + + --sidebar-bg: #3b2e2a; + --sidebar-fg: #c8c9db; + --sidebar-non-existant: #505254; + --sidebar-active: #e69f67; + --sidebar-spacer: #45373a; + + --scrollbar: var(--sidebar-fg); + + --icons: #737480; + --icons-hover: #262625; + + --links: #2b79a2; + + --inline-code-color: #6e6b5e; + + --theme-popup-bg: #e1e1db; + --theme-popup-border: #b38f6b; + --theme-hover: #99908a; + + --quote-bg: hsl(60, 5%, 75%); + --quote-border: hsl(60, 5%, 70%); + + --table-border-color: hsl(60, 9%, 82%); + --table-header-bg: #b3a497; + --table-alternate-bg: hsl(60, 9%, 84%); + + --searchbar-border-color: #aaa; + --searchbar-bg: #fafafa; + --searchbar-fg: #000; + --searchbar-shadow-color: #aaa; + --searchresults-header-fg: #666; + --searchresults-border-color: #888; + --searchresults-li-bg: #dec2a2; + --search-mark-bg: #e69f67; +} + +@media (prefers-color-scheme: dark) { + .light.no-js { + --bg: hsl(200, 7%, 8%); + --fg: #98a3ad; + + --sidebar-bg: #292c2f; + --sidebar-fg: #a1adb8; + --sidebar-non-existant: #505254; + --sidebar-active: #3473ad; + --sidebar-spacer: #393939; + + --scrollbar: var(--sidebar-fg); + + --icons: #43484d; + --icons-hover: #b3c0cc; + + --links: #2b79a2; + + --inline-code-color: #c5c8c6; + + --theme-popup-bg: #141617; + --theme-popup-border: #43484d; + --theme-hover: #1f2124; + + --quote-bg: hsl(234, 21%, 18%); + --quote-border: hsl(234, 21%, 23%); + + --table-border-color: hsl(200, 7%, 13%); + --table-header-bg: hsl(200, 7%, 28%); + --table-alternate-bg: hsl(200, 7%, 11%); + + --searchbar-border-color: #aaa; + --searchbar-bg: #b7b7b7; + --searchbar-fg: #000; + --searchbar-shadow-color: #aaa; + --searchresults-header-fg: #666; + --searchresults-border-color: #98a3ad; + --searchresults-li-bg: #2b2b2f; + --search-mark-bg: #355c7d; + } +} diff --git a/HEAD/elasticlunr.min.js b/HEAD/elasticlunr.min.js new file mode 100644 index 000000000..94b20dd2e --- /dev/null +++ b/HEAD/elasticlunr.min.js @@ -0,0 +1,10 @@ +/** + * elasticlunr - http://weixsong.github.io + * Lightweight full-text search engine in Javascript for browser search and offline search. - 0.9.5 + * + * Copyright (C) 2017 Oliver Nightingale + * Copyright (C) 2017 Wei Song + * MIT Licensed + * @license + */ +!function(){function e(e){if(null===e||"object"!=typeof e)return e;var t=e.constructor();for(var n in e)e.hasOwnProperty(n)&&(t[n]=e[n]);return t}var t=function(e){var n=new t.Index;return n.pipeline.add(t.trimmer,t.stopWordFilter,t.stemmer),e&&e.call(n,n),n};t.version="0.9.5",lunr=t,t.utils={},t.utils.warn=function(e){return function(t){e.console&&console.warn&&console.warn(t)}}(this),t.utils.toString=function(e){return void 0===e||null===e?"":e.toString()},t.EventEmitter=function(){this.events={}},t.EventEmitter.prototype.addListener=function(){var e=Array.prototype.slice.call(arguments),t=e.pop(),n=e;if("function"!=typeof t)throw new TypeError("last argument must be a function");n.forEach(function(e){this.hasHandler(e)||(this.events[e]=[]),this.events[e].push(t)},this)},t.EventEmitter.prototype.removeListener=function(e,t){if(this.hasHandler(e)){var n=this.events[e].indexOf(t);-1!==n&&(this.events[e].splice(n,1),0==this.events[e].length&&delete this.events[e])}},t.EventEmitter.prototype.emit=function(e){if(this.hasHandler(e)){var t=Array.prototype.slice.call(arguments,1);this.events[e].forEach(function(e){e.apply(void 0,t)},this)}},t.EventEmitter.prototype.hasHandler=function(e){return e in this.events},t.tokenizer=function(e){if(!arguments.length||null===e||void 0===e)return[];if(Array.isArray(e)){var n=e.filter(function(e){return null===e||void 0===e?!1:!0});n=n.map(function(e){return t.utils.toString(e).toLowerCase()});var i=[];return n.forEach(function(e){var n=e.split(t.tokenizer.seperator);i=i.concat(n)},this),i}return e.toString().trim().toLowerCase().split(t.tokenizer.seperator)},t.tokenizer.defaultSeperator=/[\s\-]+/,t.tokenizer.seperator=t.tokenizer.defaultSeperator,t.tokenizer.setSeperator=function(e){null!==e&&void 0!==e&&"object"==typeof e&&(t.tokenizer.seperator=e)},t.tokenizer.resetSeperator=function(){t.tokenizer.seperator=t.tokenizer.defaultSeperator},t.tokenizer.getSeperator=function(){return t.tokenizer.seperator},t.Pipeline=function(){this._queue=[]},t.Pipeline.registeredFunctions={},t.Pipeline.registerFunction=function(e,n){n in t.Pipeline.registeredFunctions&&t.utils.warn("Overwriting existing registered function: "+n),e.label=n,t.Pipeline.registeredFunctions[n]=e},t.Pipeline.getRegisteredFunction=function(e){return e in t.Pipeline.registeredFunctions!=!0?null:t.Pipeline.registeredFunctions[e]},t.Pipeline.warnIfFunctionNotRegistered=function(e){var n=e.label&&e.label in this.registeredFunctions;n||t.utils.warn("Function is not registered with pipeline. This may cause problems when serialising the index.\n",e)},t.Pipeline.load=function(e){var n=new t.Pipeline;return e.forEach(function(e){var i=t.Pipeline.getRegisteredFunction(e);if(!i)throw new Error("Cannot load un-registered function: "+e);n.add(i)}),n},t.Pipeline.prototype.add=function(){var e=Array.prototype.slice.call(arguments);e.forEach(function(e){t.Pipeline.warnIfFunctionNotRegistered(e),this._queue.push(e)},this)},t.Pipeline.prototype.after=function(e,n){t.Pipeline.warnIfFunctionNotRegistered(n);var i=this._queue.indexOf(e);if(-1===i)throw new Error("Cannot find existingFn");this._queue.splice(i+1,0,n)},t.Pipeline.prototype.before=function(e,n){t.Pipeline.warnIfFunctionNotRegistered(n);var i=this._queue.indexOf(e);if(-1===i)throw new Error("Cannot find existingFn");this._queue.splice(i,0,n)},t.Pipeline.prototype.remove=function(e){var t=this._queue.indexOf(e);-1!==t&&this._queue.splice(t,1)},t.Pipeline.prototype.run=function(e){for(var t=[],n=e.length,i=this._queue.length,o=0;n>o;o++){for(var r=e[o],s=0;i>s&&(r=this._queue[s](r,o,e),void 0!==r&&null!==r);s++);void 0!==r&&null!==r&&t.push(r)}return t},t.Pipeline.prototype.reset=function(){this._queue=[]},t.Pipeline.prototype.get=function(){return this._queue},t.Pipeline.prototype.toJSON=function(){return this._queue.map(function(e){return t.Pipeline.warnIfFunctionNotRegistered(e),e.label})},t.Index=function(){this._fields=[],this._ref="id",this.pipeline=new t.Pipeline,this.documentStore=new t.DocumentStore,this.index={},this.eventEmitter=new t.EventEmitter,this._idfCache={},this.on("add","remove","update",function(){this._idfCache={}}.bind(this))},t.Index.prototype.on=function(){var e=Array.prototype.slice.call(arguments);return this.eventEmitter.addListener.apply(this.eventEmitter,e)},t.Index.prototype.off=function(e,t){return this.eventEmitter.removeListener(e,t)},t.Index.load=function(e){e.version!==t.version&&t.utils.warn("version mismatch: current "+t.version+" importing "+e.version);var n=new this;n._fields=e.fields,n._ref=e.ref,n.documentStore=t.DocumentStore.load(e.documentStore),n.pipeline=t.Pipeline.load(e.pipeline),n.index={};for(var i in e.index)n.index[i]=t.InvertedIndex.load(e.index[i]);return n},t.Index.prototype.addField=function(e){return this._fields.push(e),this.index[e]=new t.InvertedIndex,this},t.Index.prototype.setRef=function(e){return this._ref=e,this},t.Index.prototype.saveDocument=function(e){return this.documentStore=new t.DocumentStore(e),this},t.Index.prototype.addDoc=function(e,n){if(e){var n=void 0===n?!0:n,i=e[this._ref];this.documentStore.addDoc(i,e),this._fields.forEach(function(n){var o=this.pipeline.run(t.tokenizer(e[n]));this.documentStore.addFieldLength(i,n,o.length);var r={};o.forEach(function(e){e in r?r[e]+=1:r[e]=1},this);for(var s in r){var u=r[s];u=Math.sqrt(u),this.index[n].addToken(s,{ref:i,tf:u})}},this),n&&this.eventEmitter.emit("add",e,this)}},t.Index.prototype.removeDocByRef=function(e){if(e&&this.documentStore.isDocStored()!==!1&&this.documentStore.hasDoc(e)){var t=this.documentStore.getDoc(e);this.removeDoc(t,!1)}},t.Index.prototype.removeDoc=function(e,n){if(e){var n=void 0===n?!0:n,i=e[this._ref];this.documentStore.hasDoc(i)&&(this.documentStore.removeDoc(i),this._fields.forEach(function(n){var o=this.pipeline.run(t.tokenizer(e[n]));o.forEach(function(e){this.index[n].removeToken(e,i)},this)},this),n&&this.eventEmitter.emit("remove",e,this))}},t.Index.prototype.updateDoc=function(e,t){var t=void 0===t?!0:t;this.removeDocByRef(e[this._ref],!1),this.addDoc(e,!1),t&&this.eventEmitter.emit("update",e,this)},t.Index.prototype.idf=function(e,t){var n="@"+t+"/"+e;if(Object.prototype.hasOwnProperty.call(this._idfCache,n))return this._idfCache[n];var i=this.index[t].getDocFreq(e),o=1+Math.log(this.documentStore.length/(i+1));return this._idfCache[n]=o,o},t.Index.prototype.getFields=function(){return this._fields.slice()},t.Index.prototype.search=function(e,n){if(!e)return[];e="string"==typeof e?{any:e}:JSON.parse(JSON.stringify(e));var i=null;null!=n&&(i=JSON.stringify(n));for(var o=new t.Configuration(i,this.getFields()).get(),r={},s=Object.keys(e),u=0;u0&&t.push(e);for(var i in n)"docs"!==i&&"df"!==i&&this.expandToken(e+i,t,n[i]);return t},t.InvertedIndex.prototype.toJSON=function(){return{root:this.root}},t.Configuration=function(e,n){var e=e||"";if(void 0==n||null==n)throw new Error("fields should not be null");this.config={};var i;try{i=JSON.parse(e),this.buildUserConfig(i,n)}catch(o){t.utils.warn("user configuration parse failed, will use default configuration"),this.buildDefaultConfig(n)}},t.Configuration.prototype.buildDefaultConfig=function(e){this.reset(),e.forEach(function(e){this.config[e]={boost:1,bool:"OR",expand:!1}},this)},t.Configuration.prototype.buildUserConfig=function(e,n){var i="OR",o=!1;if(this.reset(),"bool"in e&&(i=e.bool||i),"expand"in e&&(o=e.expand||o),"fields"in e)for(var r in e.fields)if(n.indexOf(r)>-1){var s=e.fields[r],u=o;void 0!=s.expand&&(u=s.expand),this.config[r]={boost:s.boost||0===s.boost?s.boost:1,bool:s.bool||i,expand:u}}else t.utils.warn("field name in user configuration not found in index instance fields");else this.addAllFields2UserConfig(i,o,n)},t.Configuration.prototype.addAllFields2UserConfig=function(e,t,n){n.forEach(function(n){this.config[n]={boost:1,bool:e,expand:t}},this)},t.Configuration.prototype.get=function(){return this.config},t.Configuration.prototype.reset=function(){this.config={}},lunr.SortedSet=function(){this.length=0,this.elements=[]},lunr.SortedSet.load=function(e){var t=new this;return t.elements=e,t.length=e.length,t},lunr.SortedSet.prototype.add=function(){var e,t;for(e=0;e1;){if(r===e)return o;e>r&&(t=o),r>e&&(n=o),i=n-t,o=t+Math.floor(i/2),r=this.elements[o]}return r===e?o:-1},lunr.SortedSet.prototype.locationFor=function(e){for(var t=0,n=this.elements.length,i=n-t,o=t+Math.floor(i/2),r=this.elements[o];i>1;)e>r&&(t=o),r>e&&(n=o),i=n-t,o=t+Math.floor(i/2),r=this.elements[o];return r>e?o:e>r?o+1:void 0},lunr.SortedSet.prototype.intersect=function(e){for(var t=new lunr.SortedSet,n=0,i=0,o=this.length,r=e.length,s=this.elements,u=e.elements;;){if(n>o-1||i>r-1)break;s[n]!==u[i]?s[n]u[i]&&i++:(t.add(s[n]),n++,i++)}return t},lunr.SortedSet.prototype.clone=function(){var e=new lunr.SortedSet;return e.elements=this.toArray(),e.length=e.elements.length,e},lunr.SortedSet.prototype.union=function(e){var t,n,i;this.length>=e.length?(t=this,n=e):(t=e,n=this),i=t.clone();for(var o=0,r=n.toArray();o + + + + diff --git a/HEAD/fonts/OPEN-SANS-LICENSE.txt b/HEAD/fonts/OPEN-SANS-LICENSE.txt new file mode 100644 index 000000000..d64569567 --- /dev/null +++ b/HEAD/fonts/OPEN-SANS-LICENSE.txt @@ -0,0 +1,202 @@ + + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + + TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + + 1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + + 2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + + 3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + + 4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + + 5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + + 6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + + 7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + + 8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + + 9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + + END OF TERMS AND CONDITIONS + + APPENDIX: How to apply the Apache License to your work. + + To apply the Apache License to your work, attach the following + boilerplate notice, with the fields enclosed by brackets "[]" + replaced with your own identifying information. (Don't include + the brackets!) The text should be enclosed in the appropriate + comment syntax for the file format. We also recommend that a + file or class name and description of purpose be included on the + same "printed page" as the copyright notice for easier + identification within third-party archives. + + Copyright [yyyy] [name of copyright owner] + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. diff --git a/HEAD/fonts/SOURCE-CODE-PRO-LICENSE.txt b/HEAD/fonts/SOURCE-CODE-PRO-LICENSE.txt new file mode 100644 index 000000000..366206f54 --- /dev/null +++ b/HEAD/fonts/SOURCE-CODE-PRO-LICENSE.txt @@ -0,0 +1,93 @@ +Copyright 2010, 2012 Adobe Systems Incorporated (http://www.adobe.com/), with Reserved Font Name 'Source'. All Rights Reserved. Source is a trademark of Adobe Systems Incorporated in the United States and/or other countries. + +This Font Software is licensed under the SIL Open Font License, Version 1.1. +This license is copied below, and is also available with a FAQ at: +http://scripts.sil.org/OFL + + +----------------------------------------------------------- +SIL OPEN FONT LICENSE Version 1.1 - 26 February 2007 +----------------------------------------------------------- + +PREAMBLE +The goals of the Open Font License (OFL) are to stimulate worldwide +development of collaborative font projects, to support the font creation +efforts of academic and linguistic communities, and to provide a free and +open framework in which fonts may be shared and improved in partnership +with others. + +The OFL allows the licensed fonts to be used, studied, modified and +redistributed freely as long as they are not sold by themselves. The +fonts, including any derivative works, can be bundled, embedded, +redistributed and/or sold with any software provided that any reserved +names are not used by derivative works. The fonts and derivatives, +however, cannot be released under any other type of license. The +requirement for fonts to remain under this license does not apply +to any document created using the fonts or their derivatives. + +DEFINITIONS +"Font Software" refers to the set of files released by the Copyright +Holder(s) under this license and clearly marked as such. This may +include source files, build scripts and documentation. + +"Reserved Font Name" refers to any names specified as such after the +copyright statement(s). + +"Original Version" refers to the collection of Font Software components as +distributed by the Copyright Holder(s). + +"Modified Version" refers to any derivative made by adding to, deleting, +or substituting -- in part or in whole -- any of the components of the +Original Version, by changing formats or by porting the Font Software to a +new environment. + +"Author" refers to any designer, engineer, programmer, technical +writer or other person who contributed to the Font Software. + +PERMISSION & CONDITIONS +Permission is hereby granted, free of charge, to any person obtaining +a copy of the Font Software, to use, study, copy, merge, embed, modify, +redistribute, and sell modified and unmodified copies of the Font +Software, subject to the following conditions: + +1) Neither the Font Software nor any of its individual components, +in Original or Modified Versions, may be sold by itself. + +2) Original or Modified Versions of the Font Software may be bundled, +redistributed and/or sold with any software, provided that each copy +contains the above copyright notice and this license. These can be +included either as stand-alone text files, human-readable headers or +in the appropriate machine-readable metadata fields within text or +binary files as long as those fields can be easily viewed by the user. + +3) No Modified Version of the Font Software may use the Reserved Font +Name(s) unless explicit written permission is granted by the corresponding +Copyright Holder. This restriction only applies to the primary font name as +presented to the users. + +4) The name(s) of the Copyright Holder(s) or the Author(s) of the Font +Software shall not be used to promote, endorse or advertise any +Modified Version, except to acknowledge the contribution(s) of the +Copyright Holder(s) and the Author(s) or with their explicit written +permission. + +5) The Font Software, modified or unmodified, in part or in whole, +must be distributed entirely under this license, and must not be +distributed under any other license. The requirement for fonts to +remain under this license does not apply to any document created +using the Font Software. + +TERMINATION +This license becomes null and void if any of the above conditions are +not met. + +DISCLAIMER +THE FONT SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO ANY WARRANTIES OF +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT +OF COPYRIGHT, PATENT, TRADEMARK, OR OTHER RIGHT. IN NO EVENT SHALL THE +COPYRIGHT HOLDER BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, +INCLUDING ANY GENERAL, SPECIAL, INDIRECT, INCIDENTAL, OR CONSEQUENTIAL +DAMAGES, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +FROM, OUT OF THE USE OR INABILITY TO USE THE FONT SOFTWARE OR FROM +OTHER DEALINGS IN THE FONT SOFTWARE. diff --git a/HEAD/fonts/fonts.css b/HEAD/fonts/fonts.css new file mode 100644 index 000000000..858efa598 --- /dev/null +++ b/HEAD/fonts/fonts.css @@ -0,0 +1,100 @@ +/* Open Sans is licensed under the Apache License, Version 2.0. See http://www.apache.org/licenses/LICENSE-2.0 */ +/* Source Code Pro is under the Open Font License. See https://scripts.sil.org/cms/scripts/page.php?site_id=nrsi&id=OFL */ + +/* open-sans-300 - latin_vietnamese_latin-ext_greek-ext_greek_cyrillic-ext_cyrillic */ +@font-face { + font-family: 'Open Sans'; + font-style: normal; + font-weight: 300; + src: local('Open Sans Light'), local('OpenSans-Light'), + url('open-sans-v17-all-charsets-300.woff2') format('woff2'); +} + +/* open-sans-300italic - latin_vietnamese_latin-ext_greek-ext_greek_cyrillic-ext_cyrillic */ +@font-face { + font-family: 'Open Sans'; + font-style: italic; + font-weight: 300; + src: local('Open Sans Light Italic'), local('OpenSans-LightItalic'), + url('open-sans-v17-all-charsets-300italic.woff2') format('woff2'); +} + +/* open-sans-regular - latin_vietnamese_latin-ext_greek-ext_greek_cyrillic-ext_cyrillic */ +@font-face { + font-family: 'Open Sans'; + font-style: normal; + font-weight: 400; + src: local('Open Sans Regular'), local('OpenSans-Regular'), + url('open-sans-v17-all-charsets-regular.woff2') format('woff2'); +} + +/* open-sans-italic - latin_vietnamese_latin-ext_greek-ext_greek_cyrillic-ext_cyrillic */ +@font-face { + font-family: 'Open Sans'; + font-style: italic; + font-weight: 400; + src: local('Open Sans Italic'), local('OpenSans-Italic'), + url('open-sans-v17-all-charsets-italic.woff2') format('woff2'); +} + +/* open-sans-600 - latin_vietnamese_latin-ext_greek-ext_greek_cyrillic-ext_cyrillic */ +@font-face { + font-family: 'Open Sans'; + font-style: normal; + font-weight: 600; + src: local('Open Sans SemiBold'), local('OpenSans-SemiBold'), + url('open-sans-v17-all-charsets-600.woff2') format('woff2'); +} + +/* open-sans-600italic - latin_vietnamese_latin-ext_greek-ext_greek_cyrillic-ext_cyrillic */ +@font-face { + font-family: 'Open Sans'; + font-style: italic; + font-weight: 600; + src: local('Open Sans SemiBold Italic'), local('OpenSans-SemiBoldItalic'), + url('open-sans-v17-all-charsets-600italic.woff2') format('woff2'); +} + +/* open-sans-700 - latin_vietnamese_latin-ext_greek-ext_greek_cyrillic-ext_cyrillic */ +@font-face { + font-family: 'Open Sans'; + font-style: normal; + font-weight: 700; + src: local('Open Sans Bold'), local('OpenSans-Bold'), + url('open-sans-v17-all-charsets-700.woff2') format('woff2'); +} + +/* open-sans-700italic - latin_vietnamese_latin-ext_greek-ext_greek_cyrillic-ext_cyrillic */ +@font-face { + font-family: 'Open Sans'; + font-style: italic; + font-weight: 700; + src: local('Open Sans Bold Italic'), local('OpenSans-BoldItalic'), + url('open-sans-v17-all-charsets-700italic.woff2') format('woff2'); +} + +/* open-sans-800 - latin_vietnamese_latin-ext_greek-ext_greek_cyrillic-ext_cyrillic */ +@font-face { + font-family: 'Open Sans'; + font-style: normal; + font-weight: 800; + src: local('Open Sans ExtraBold'), local('OpenSans-ExtraBold'), + url('open-sans-v17-all-charsets-800.woff2') format('woff2'); +} + +/* open-sans-800italic - latin_vietnamese_latin-ext_greek-ext_greek_cyrillic-ext_cyrillic */ +@font-face { + font-family: 'Open Sans'; + font-style: italic; + font-weight: 800; + src: local('Open Sans ExtraBold Italic'), local('OpenSans-ExtraBoldItalic'), + url('open-sans-v17-all-charsets-800italic.woff2') format('woff2'); +} + +/* source-code-pro-500 - latin_vietnamese_latin-ext_greek_cyrillic-ext_cyrillic */ +@font-face { + font-family: 'Source Code Pro'; + font-style: normal; + font-weight: 500; + src: url('source-code-pro-v11-all-charsets-500.woff2') format('woff2'); +} diff --git a/HEAD/fonts/open-sans-v17-all-charsets-300.woff2 b/HEAD/fonts/open-sans-v17-all-charsets-300.woff2 new file mode 100644 index 000000000..9f51be370 Binary files /dev/null and b/HEAD/fonts/open-sans-v17-all-charsets-300.woff2 differ diff --git a/HEAD/fonts/open-sans-v17-all-charsets-300italic.woff2 b/HEAD/fonts/open-sans-v17-all-charsets-300italic.woff2 new file mode 100644 index 000000000..2f5454484 Binary files /dev/null and b/HEAD/fonts/open-sans-v17-all-charsets-300italic.woff2 differ diff --git a/HEAD/fonts/open-sans-v17-all-charsets-600.woff2 b/HEAD/fonts/open-sans-v17-all-charsets-600.woff2 new file mode 100644 index 000000000..f503d558d Binary files /dev/null and b/HEAD/fonts/open-sans-v17-all-charsets-600.woff2 differ diff --git a/HEAD/fonts/open-sans-v17-all-charsets-600italic.woff2 b/HEAD/fonts/open-sans-v17-all-charsets-600italic.woff2 new file mode 100644 index 000000000..c99aabe80 Binary files /dev/null and b/HEAD/fonts/open-sans-v17-all-charsets-600italic.woff2 differ diff --git a/HEAD/fonts/open-sans-v17-all-charsets-700.woff2 b/HEAD/fonts/open-sans-v17-all-charsets-700.woff2 new file mode 100644 index 000000000..421a1ab25 Binary files /dev/null and b/HEAD/fonts/open-sans-v17-all-charsets-700.woff2 differ diff --git a/HEAD/fonts/open-sans-v17-all-charsets-700italic.woff2 b/HEAD/fonts/open-sans-v17-all-charsets-700italic.woff2 new file mode 100644 index 000000000..12ce3d20d Binary files /dev/null and b/HEAD/fonts/open-sans-v17-all-charsets-700italic.woff2 differ diff --git a/HEAD/fonts/open-sans-v17-all-charsets-800.woff2 b/HEAD/fonts/open-sans-v17-all-charsets-800.woff2 new file mode 100644 index 000000000..c94a223b0 Binary files /dev/null and b/HEAD/fonts/open-sans-v17-all-charsets-800.woff2 differ diff --git a/HEAD/fonts/open-sans-v17-all-charsets-800italic.woff2 b/HEAD/fonts/open-sans-v17-all-charsets-800italic.woff2 new file mode 100644 index 000000000..eed7d3c63 Binary files /dev/null and b/HEAD/fonts/open-sans-v17-all-charsets-800italic.woff2 differ diff --git a/HEAD/fonts/open-sans-v17-all-charsets-italic.woff2 b/HEAD/fonts/open-sans-v17-all-charsets-italic.woff2 new file mode 100644 index 000000000..398b68a08 Binary files /dev/null and b/HEAD/fonts/open-sans-v17-all-charsets-italic.woff2 differ diff --git a/HEAD/fonts/open-sans-v17-all-charsets-regular.woff2 b/HEAD/fonts/open-sans-v17-all-charsets-regular.woff2 new file mode 100644 index 000000000..8383e94c6 Binary files /dev/null and b/HEAD/fonts/open-sans-v17-all-charsets-regular.woff2 differ diff --git a/HEAD/fonts/source-code-pro-v11-all-charsets-500.woff2 b/HEAD/fonts/source-code-pro-v11-all-charsets-500.woff2 new file mode 100644 index 000000000..722245682 Binary files /dev/null and b/HEAD/fonts/source-code-pro-v11-all-charsets-500.woff2 differ diff --git a/HEAD/highlight.css b/HEAD/highlight.css new file mode 100644 index 000000000..ba57b82b2 --- /dev/null +++ b/HEAD/highlight.css @@ -0,0 +1,82 @@ +/* + * An increased contrast highlighting scheme loosely based on the + * "Base16 Atelier Dune Light" theme by Bram de Haan + * (http://atelierbram.github.io/syntax-highlighting/atelier-schemes/dune) + * Original Base16 color scheme by Chris Kempson + * (https://github.com/chriskempson/base16) + */ + +/* Comment */ +.hljs-comment, +.hljs-quote { + color: #575757; +} + +/* Red */ +.hljs-variable, +.hljs-template-variable, +.hljs-attribute, +.hljs-tag, +.hljs-name, +.hljs-regexp, +.hljs-link, +.hljs-name, +.hljs-selector-id, +.hljs-selector-class { + color: #d70025; +} + +/* Orange */ +.hljs-number, +.hljs-meta, +.hljs-built_in, +.hljs-builtin-name, +.hljs-literal, +.hljs-type, +.hljs-params { + color: #b21e00; +} + +/* Green */ +.hljs-string, +.hljs-symbol, +.hljs-bullet { + color: #008200; +} + +/* Blue */ +.hljs-title, +.hljs-section { + color: #0030f2; +} + +/* Purple */ +.hljs-keyword, +.hljs-selector-tag { + color: #9d00ec; +} + +.hljs { + display: block; + overflow-x: auto; + background: #f6f7f6; + color: #000; +} + +.hljs-emphasis { + font-style: italic; +} + +.hljs-strong { + font-weight: bold; +} + +.hljs-addition { + color: #22863a; + background-color: #f0fff4; +} + +.hljs-deletion { + color: #b31d28; + background-color: #ffeef0; +} diff --git a/HEAD/highlight.js b/HEAD/highlight.js new file mode 100644 index 000000000..180385b70 --- /dev/null +++ b/HEAD/highlight.js @@ -0,0 +1,6 @@ +/* + Highlight.js 10.1.1 (93fd0d73) + License: BSD-3-Clause + Copyright (c) 2006-2020, Ivan Sagalaev +*/ +var hljs=function(){"use strict";function e(n){Object.freeze(n);var t="function"==typeof n;return Object.getOwnPropertyNames(n).forEach((function(r){!Object.hasOwnProperty.call(n,r)||null===n[r]||"object"!=typeof n[r]&&"function"!=typeof n[r]||t&&("caller"===r||"callee"===r||"arguments"===r)||Object.isFrozen(n[r])||e(n[r])})),n}class n{constructor(e){void 0===e.data&&(e.data={}),this.data=e.data}ignoreMatch(){this.ignore=!0}}function t(e){return e.replace(/&/g,"&").replace(//g,">").replace(/"/g,""").replace(/'/g,"'")}function r(e,...n){var t={};for(const n in e)t[n]=e[n];return n.forEach((function(e){for(const n in e)t[n]=e[n]})),t}function a(e){return e.nodeName.toLowerCase()}var i=Object.freeze({__proto__:null,escapeHTML:t,inherit:r,nodeStream:function(e){var n=[];return function e(t,r){for(var i=t.firstChild;i;i=i.nextSibling)3===i.nodeType?r+=i.nodeValue.length:1===i.nodeType&&(n.push({event:"start",offset:r,node:i}),r=e(i,r),a(i).match(/br|hr|img|input/)||n.push({event:"stop",offset:r,node:i}));return r}(e,0),n},mergeStreams:function(e,n,r){var i=0,s="",o=[];function l(){return e.length&&n.length?e[0].offset!==n[0].offset?e[0].offset"}function u(e){s+=""}function d(e){("start"===e.event?c:u)(e.node)}for(;e.length||n.length;){var g=l();if(s+=t(r.substring(i,g[0].offset)),i=g[0].offset,g===e){o.reverse().forEach(u);do{d(g.splice(0,1)[0]),g=l()}while(g===e&&g.length&&g[0].offset===i);o.reverse().forEach(c)}else"start"===g[0].event?o.push(g[0].node):o.pop(),d(g.splice(0,1)[0])}return s+t(r.substr(i))}});const s="",o=e=>!!e.kind;class l{constructor(e,n){this.buffer="",this.classPrefix=n.classPrefix,e.walk(this)}addText(e){this.buffer+=t(e)}openNode(e){if(!o(e))return;let n=e.kind;e.sublanguage||(n=`${this.classPrefix}${n}`),this.span(n)}closeNode(e){o(e)&&(this.buffer+=s)}value(){return this.buffer}span(e){this.buffer+=``}}class c{constructor(){this.rootNode={children:[]},this.stack=[this.rootNode]}get top(){return this.stack[this.stack.length-1]}get root(){return this.rootNode}add(e){this.top.children.push(e)}openNode(e){const n={kind:e,children:[]};this.add(n),this.stack.push(n)}closeNode(){if(this.stack.length>1)return this.stack.pop()}closeAllNodes(){for(;this.closeNode(););}toJSON(){return JSON.stringify(this.rootNode,null,4)}walk(e){return this.constructor._walk(e,this.rootNode)}static _walk(e,n){return"string"==typeof n?e.addText(n):n.children&&(e.openNode(n),n.children.forEach(n=>this._walk(e,n)),e.closeNode(n)),e}static _collapse(e){"string"!=typeof e&&e.children&&(e.children.every(e=>"string"==typeof e)?e.children=[e.children.join("")]:e.children.forEach(e=>{c._collapse(e)}))}}class u extends c{constructor(e){super(),this.options=e}addKeyword(e,n){""!==e&&(this.openNode(n),this.addText(e),this.closeNode())}addText(e){""!==e&&this.add(e)}addSublanguage(e,n){const t=e.root;t.kind=n,t.sublanguage=!0,this.add(t)}toHTML(){return new l(this,this.options).value()}finalize(){return!0}}function d(e){return e?"string"==typeof e?e:e.source:null}const g="(-?)(\\b0[xX][a-fA-F0-9]+|(\\b\\d+(\\.\\d*)?|\\.\\d+)([eE][-+]?\\d+)?)",h={begin:"\\\\[\\s\\S]",relevance:0},f={className:"string",begin:"'",end:"'",illegal:"\\n",contains:[h]},p={className:"string",begin:'"',end:'"',illegal:"\\n",contains:[h]},b={begin:/\b(a|an|the|are|I'm|isn't|don't|doesn't|won't|but|just|should|pretty|simply|enough|gonna|going|wtf|so|such|will|you|your|they|like|more)\b/},m=function(e,n,t={}){var a=r({className:"comment",begin:e,end:n,contains:[]},t);return a.contains.push(b),a.contains.push({className:"doctag",begin:"(?:TODO|FIXME|NOTE|BUG|OPTIMIZE|HACK|XXX):",relevance:0}),a},v=m("//","$"),x=m("/\\*","\\*/"),E=m("#","$");var _=Object.freeze({__proto__:null,IDENT_RE:"[a-zA-Z]\\w*",UNDERSCORE_IDENT_RE:"[a-zA-Z_]\\w*",NUMBER_RE:"\\b\\d+(\\.\\d+)?",C_NUMBER_RE:g,BINARY_NUMBER_RE:"\\b(0b[01]+)",RE_STARTERS_RE:"!|!=|!==|%|%=|&|&&|&=|\\*|\\*=|\\+|\\+=|,|-|-=|/=|/|:|;|<<|<<=|<=|<|===|==|=|>>>=|>>=|>=|>>>|>>|>|\\?|\\[|\\{|\\(|\\^|\\^=|\\||\\|=|\\|\\||~",SHEBANG:(e={})=>{const n=/^#![ ]*\//;return e.binary&&(e.begin=function(...e){return e.map(e=>d(e)).join("")}(n,/.*\b/,e.binary,/\b.*/)),r({className:"meta",begin:n,end:/$/,relevance:0,"on:begin":(e,n)=>{0!==e.index&&n.ignoreMatch()}},e)},BACKSLASH_ESCAPE:h,APOS_STRING_MODE:f,QUOTE_STRING_MODE:p,PHRASAL_WORDS_MODE:b,COMMENT:m,C_LINE_COMMENT_MODE:v,C_BLOCK_COMMENT_MODE:x,HASH_COMMENT_MODE:E,NUMBER_MODE:{className:"number",begin:"\\b\\d+(\\.\\d+)?",relevance:0},C_NUMBER_MODE:{className:"number",begin:g,relevance:0},BINARY_NUMBER_MODE:{className:"number",begin:"\\b(0b[01]+)",relevance:0},CSS_NUMBER_MODE:{className:"number",begin:"\\b\\d+(\\.\\d+)?(%|em|ex|ch|rem|vw|vh|vmin|vmax|cm|mm|in|pt|pc|px|deg|grad|rad|turn|s|ms|Hz|kHz|dpi|dpcm|dppx)?",relevance:0},REGEXP_MODE:{begin:/(?=\/[^/\n]*\/)/,contains:[{className:"regexp",begin:/\//,end:/\/[gimuy]*/,illegal:/\n/,contains:[h,{begin:/\[/,end:/\]/,relevance:0,contains:[h]}]}]},TITLE_MODE:{className:"title",begin:"[a-zA-Z]\\w*",relevance:0},UNDERSCORE_TITLE_MODE:{className:"title",begin:"[a-zA-Z_]\\w*",relevance:0},METHOD_GUARD:{begin:"\\.\\s*[a-zA-Z_]\\w*",relevance:0},END_SAME_AS_BEGIN:function(e){return Object.assign(e,{"on:begin":(e,n)=>{n.data._beginMatch=e[1]},"on:end":(e,n)=>{n.data._beginMatch!==e[1]&&n.ignoreMatch()}})}}),N="of and for in not or if then".split(" ");function w(e,n){return n?+n:function(e){return N.includes(e.toLowerCase())}(e)?0:1}const R=t,y=r,{nodeStream:k,mergeStreams:O}=i,M=Symbol("nomatch");return function(t){var a=[],i={},s={},o=[],l=!0,c=/(^(<[^>]+>|\t|)+|\n)/gm,g="Could not find the language '{}', did you forget to load/include a language module?";const h={disableAutodetect:!0,name:"Plain text",contains:[]};var f={noHighlightRe:/^(no-?highlight)$/i,languageDetectRe:/\blang(?:uage)?-([\w-]+)\b/i,classPrefix:"hljs-",tabReplace:null,useBR:!1,languages:null,__emitter:u};function p(e){return f.noHighlightRe.test(e)}function b(e,n,t,r){var a={code:n,language:e};S("before:highlight",a);var i=a.result?a.result:m(a.language,a.code,t,r);return i.code=a.code,S("after:highlight",i),i}function m(e,t,a,s){var o=t;function c(e,n){var t=E.case_insensitive?n[0].toLowerCase():n[0];return Object.prototype.hasOwnProperty.call(e.keywords,t)&&e.keywords[t]}function u(){null!=y.subLanguage?function(){if(""!==A){var e=null;if("string"==typeof y.subLanguage){if(!i[y.subLanguage])return void O.addText(A);e=m(y.subLanguage,A,!0,k[y.subLanguage]),k[y.subLanguage]=e.top}else e=v(A,y.subLanguage.length?y.subLanguage:null);y.relevance>0&&(I+=e.relevance),O.addSublanguage(e.emitter,e.language)}}():function(){if(!y.keywords)return void O.addText(A);let e=0;y.keywordPatternRe.lastIndex=0;let n=y.keywordPatternRe.exec(A),t="";for(;n;){t+=A.substring(e,n.index);const r=c(y,n);if(r){const[e,a]=r;O.addText(t),t="",I+=a,O.addKeyword(n[0],e)}else t+=n[0];e=y.keywordPatternRe.lastIndex,n=y.keywordPatternRe.exec(A)}t+=A.substr(e),O.addText(t)}(),A=""}function h(e){return e.className&&O.openNode(e.className),y=Object.create(e,{parent:{value:y}})}function p(e){return 0===y.matcher.regexIndex?(A+=e[0],1):(L=!0,0)}var b={};function x(t,r){var i=r&&r[0];if(A+=t,null==i)return u(),0;if("begin"===b.type&&"end"===r.type&&b.index===r.index&&""===i){if(A+=o.slice(r.index,r.index+1),!l){const n=Error("0 width match regex");throw n.languageName=e,n.badRule=b.rule,n}return 1}if(b=r,"begin"===r.type)return function(e){var t=e[0],r=e.rule;const a=new n(r),i=[r.__beforeBegin,r["on:begin"]];for(const n of i)if(n&&(n(e,a),a.ignore))return p(t);return r&&r.endSameAsBegin&&(r.endRe=RegExp(t.replace(/[-/\\^$*+?.()|[\]{}]/g,"\\$&"),"m")),r.skip?A+=t:(r.excludeBegin&&(A+=t),u(),r.returnBegin||r.excludeBegin||(A=t)),h(r),r.returnBegin?0:t.length}(r);if("illegal"===r.type&&!a){const e=Error('Illegal lexeme "'+i+'" for mode "'+(y.className||"")+'"');throw e.mode=y,e}if("end"===r.type){var s=function(e){var t=e[0],r=o.substr(e.index),a=function e(t,r,a){let i=function(e,n){var t=e&&e.exec(n);return t&&0===t.index}(t.endRe,a);if(i){if(t["on:end"]){const e=new n(t);t["on:end"](r,e),e.ignore&&(i=!1)}if(i){for(;t.endsParent&&t.parent;)t=t.parent;return t}}if(t.endsWithParent)return e(t.parent,r,a)}(y,e,r);if(!a)return M;var i=y;i.skip?A+=t:(i.returnEnd||i.excludeEnd||(A+=t),u(),i.excludeEnd&&(A=t));do{y.className&&O.closeNode(),y.skip||y.subLanguage||(I+=y.relevance),y=y.parent}while(y!==a.parent);return a.starts&&(a.endSameAsBegin&&(a.starts.endRe=a.endRe),h(a.starts)),i.returnEnd?0:t.length}(r);if(s!==M)return s}if("illegal"===r.type&&""===i)return 1;if(B>1e5&&B>3*r.index)throw Error("potential infinite loop, way more iterations than matches");return A+=i,i.length}var E=T(e);if(!E)throw console.error(g.replace("{}",e)),Error('Unknown language: "'+e+'"');var _=function(e){function n(n,t){return RegExp(d(n),"m"+(e.case_insensitive?"i":"")+(t?"g":""))}class t{constructor(){this.matchIndexes={},this.regexes=[],this.matchAt=1,this.position=0}addRule(e,n){n.position=this.position++,this.matchIndexes[this.matchAt]=n,this.regexes.push([n,e]),this.matchAt+=function(e){return RegExp(e.toString()+"|").exec("").length-1}(e)+1}compile(){0===this.regexes.length&&(this.exec=()=>null);const e=this.regexes.map(e=>e[1]);this.matcherRe=n(function(e,n="|"){for(var t=/\[(?:[^\\\]]|\\.)*\]|\(\??|\\([1-9][0-9]*)|\\./,r=0,a="",i=0;i0&&(a+=n),a+="(";o.length>0;){var l=t.exec(o);if(null==l){a+=o;break}a+=o.substring(0,l.index),o=o.substring(l.index+l[0].length),"\\"===l[0][0]&&l[1]?a+="\\"+(+l[1]+s):(a+=l[0],"("===l[0]&&r++)}a+=")"}return a}(e),!0),this.lastIndex=0}exec(e){this.matcherRe.lastIndex=this.lastIndex;const n=this.matcherRe.exec(e);if(!n)return null;const t=n.findIndex((e,n)=>n>0&&void 0!==e),r=this.matchIndexes[t];return n.splice(0,t),Object.assign(n,r)}}class a{constructor(){this.rules=[],this.multiRegexes=[],this.count=0,this.lastIndex=0,this.regexIndex=0}getMatcher(e){if(this.multiRegexes[e])return this.multiRegexes[e];const n=new t;return this.rules.slice(e).forEach(([e,t])=>n.addRule(e,t)),n.compile(),this.multiRegexes[e]=n,n}considerAll(){this.regexIndex=0}addRule(e,n){this.rules.push([e,n]),"begin"===n.type&&this.count++}exec(e){const n=this.getMatcher(this.regexIndex);n.lastIndex=this.lastIndex;const t=n.exec(e);return t&&(this.regexIndex+=t.position+1,this.regexIndex===this.count&&(this.regexIndex=0)),t}}function i(e,n){const t=e.input[e.index-1],r=e.input[e.index+e[0].length];"."!==t&&"."!==r||n.ignoreMatch()}if(e.contains&&e.contains.includes("self"))throw Error("ERR: contains `self` is not supported at the top-level of a language. See documentation.");return function t(s,o){const l=s;if(s.compiled)return l;s.compiled=!0,s.__beforeBegin=null,s.keywords=s.keywords||s.beginKeywords;let c=null;if("object"==typeof s.keywords&&(c=s.keywords.$pattern,delete s.keywords.$pattern),s.keywords&&(s.keywords=function(e,n){var t={};return"string"==typeof e?r("keyword",e):Object.keys(e).forEach((function(n){r(n,e[n])})),t;function r(e,r){n&&(r=r.toLowerCase()),r.split(" ").forEach((function(n){var r=n.split("|");t[r[0]]=[e,w(r[0],r[1])]}))}}(s.keywords,e.case_insensitive)),s.lexemes&&c)throw Error("ERR: Prefer `keywords.$pattern` to `mode.lexemes`, BOTH are not allowed. (see mode reference) ");return l.keywordPatternRe=n(s.lexemes||c||/\w+/,!0),o&&(s.beginKeywords&&(s.begin="\\b("+s.beginKeywords.split(" ").join("|")+")(?=\\b|\\s)",s.__beforeBegin=i),s.begin||(s.begin=/\B|\b/),l.beginRe=n(s.begin),s.endSameAsBegin&&(s.end=s.begin),s.end||s.endsWithParent||(s.end=/\B|\b/),s.end&&(l.endRe=n(s.end)),l.terminator_end=d(s.end)||"",s.endsWithParent&&o.terminator_end&&(l.terminator_end+=(s.end?"|":"")+o.terminator_end)),s.illegal&&(l.illegalRe=n(s.illegal)),void 0===s.relevance&&(s.relevance=1),s.contains||(s.contains=[]),s.contains=[].concat(...s.contains.map((function(e){return function(e){return e.variants&&!e.cached_variants&&(e.cached_variants=e.variants.map((function(n){return r(e,{variants:null},n)}))),e.cached_variants?e.cached_variants:function e(n){return!!n&&(n.endsWithParent||e(n.starts))}(e)?r(e,{starts:e.starts?r(e.starts):null}):Object.isFrozen(e)?r(e):e}("self"===e?s:e)}))),s.contains.forEach((function(e){t(e,l)})),s.starts&&t(s.starts,o),l.matcher=function(e){const n=new a;return e.contains.forEach(e=>n.addRule(e.begin,{rule:e,type:"begin"})),e.terminator_end&&n.addRule(e.terminator_end,{type:"end"}),e.illegal&&n.addRule(e.illegal,{type:"illegal"}),n}(l),l}(e)}(E),N="",y=s||_,k={},O=new f.__emitter(f);!function(){for(var e=[],n=y;n!==E;n=n.parent)n.className&&e.unshift(n.className);e.forEach(e=>O.openNode(e))}();var A="",I=0,S=0,B=0,L=!1;try{for(y.matcher.considerAll();;){B++,L?L=!1:(y.matcher.lastIndex=S,y.matcher.considerAll());const e=y.matcher.exec(o);if(!e)break;const n=x(o.substring(S,e.index),e);S=e.index+n}return x(o.substr(S)),O.closeAllNodes(),O.finalize(),N=O.toHTML(),{relevance:I,value:N,language:e,illegal:!1,emitter:O,top:y}}catch(n){if(n.message&&n.message.includes("Illegal"))return{illegal:!0,illegalBy:{msg:n.message,context:o.slice(S-100,S+100),mode:n.mode},sofar:N,relevance:0,value:R(o),emitter:O};if(l)return{illegal:!1,relevance:0,value:R(o),emitter:O,language:e,top:y,errorRaised:n};throw n}}function v(e,n){n=n||f.languages||Object.keys(i);var t=function(e){const n={relevance:0,emitter:new f.__emitter(f),value:R(e),illegal:!1,top:h};return n.emitter.addText(e),n}(e),r=t;return n.filter(T).filter(I).forEach((function(n){var a=m(n,e,!1);a.language=n,a.relevance>r.relevance&&(r=a),a.relevance>t.relevance&&(r=t,t=a)})),r.language&&(t.second_best=r),t}function x(e){return f.tabReplace||f.useBR?e.replace(c,e=>"\n"===e?f.useBR?"
":e:f.tabReplace?e.replace(/\t/g,f.tabReplace):e):e}function E(e){let n=null;const t=function(e){var n=e.className+" ";n+=e.parentNode?e.parentNode.className:"";const t=f.languageDetectRe.exec(n);if(t){var r=T(t[1]);return r||(console.warn(g.replace("{}",t[1])),console.warn("Falling back to no-highlight mode for this block.",e)),r?t[1]:"no-highlight"}return n.split(/\s+/).find(e=>p(e)||T(e))}(e);if(p(t))return;S("before:highlightBlock",{block:e,language:t}),f.useBR?(n=document.createElement("div")).innerHTML=e.innerHTML.replace(/\n/g,"").replace(//g,"\n"):n=e;const r=n.textContent,a=t?b(t,r,!0):v(r),i=k(n);if(i.length){const e=document.createElement("div");e.innerHTML=a.value,a.value=O(i,k(e),r)}a.value=x(a.value),S("after:highlightBlock",{block:e,result:a}),e.innerHTML=a.value,e.className=function(e,n,t){var r=n?s[n]:t,a=[e.trim()];return e.match(/\bhljs\b/)||a.push("hljs"),e.includes(r)||a.push(r),a.join(" ").trim()}(e.className,t,a.language),e.result={language:a.language,re:a.relevance,relavance:a.relevance},a.second_best&&(e.second_best={language:a.second_best.language,re:a.second_best.relevance,relavance:a.second_best.relevance})}const N=()=>{if(!N.called){N.called=!0;var e=document.querySelectorAll("pre code");a.forEach.call(e,E)}};function T(e){return e=(e||"").toLowerCase(),i[e]||i[s[e]]}function A(e,{languageName:n}){"string"==typeof e&&(e=[e]),e.forEach(e=>{s[e]=n})}function I(e){var n=T(e);return n&&!n.disableAutodetect}function S(e,n){var t=e;o.forEach((function(e){e[t]&&e[t](n)}))}Object.assign(t,{highlight:b,highlightAuto:v,fixMarkup:x,highlightBlock:E,configure:function(e){f=y(f,e)},initHighlighting:N,initHighlightingOnLoad:function(){window.addEventListener("DOMContentLoaded",N,!1)},registerLanguage:function(e,n){var r=null;try{r=n(t)}catch(n){if(console.error("Language definition for '{}' could not be registered.".replace("{}",e)),!l)throw n;console.error(n),r=h}r.name||(r.name=e),i[e]=r,r.rawDefinition=n.bind(null,t),r.aliases&&A(r.aliases,{languageName:e})},listLanguages:function(){return Object.keys(i)},getLanguage:T,registerAliases:A,requireLanguage:function(e){var n=T(e);if(n)return n;throw Error("The '{}' language is required, but not loaded.".replace("{}",e))},autoDetection:I,inherit:y,addPlugin:function(e){o.push(e)}}),t.debugMode=function(){l=!1},t.safeMode=function(){l=!0},t.versionString="10.1.1";for(const n in _)"object"==typeof _[n]&&e(_[n]);return Object.assign(t,_),t}({})}();"object"==typeof exports&&"undefined"!=typeof module&&(module.exports=hljs);hljs.registerLanguage("php",function(){"use strict";return function(e){var r={begin:"\\$+[a-zA-Z_-ÿ][a-zA-Z0-9_-ÿ]*"},t={className:"meta",variants:[{begin:/<\?php/,relevance:10},{begin:/<\?[=]?/},{begin:/\?>/}]},a={className:"string",contains:[e.BACKSLASH_ESCAPE,t],variants:[{begin:'b"',end:'"'},{begin:"b'",end:"'"},e.inherit(e.APOS_STRING_MODE,{illegal:null}),e.inherit(e.QUOTE_STRING_MODE,{illegal:null})]},n={variants:[e.BINARY_NUMBER_MODE,e.C_NUMBER_MODE]},i={keyword:"__CLASS__ __DIR__ __FILE__ __FUNCTION__ __LINE__ __METHOD__ __NAMESPACE__ __TRAIT__ die echo exit include include_once print require require_once array abstract and as binary bool boolean break callable case catch class clone const continue declare default do double else elseif empty enddeclare endfor endforeach endif endswitch endwhile eval extends final finally float for foreach from global goto if implements instanceof insteadof int integer interface isset iterable list new object or private protected public real return string switch throw trait try unset use var void while xor yield",literal:"false null true",built_in:"Error|0 AppendIterator ArgumentCountError ArithmeticError ArrayIterator ArrayObject AssertionError BadFunctionCallException BadMethodCallException CachingIterator CallbackFilterIterator CompileError Countable DirectoryIterator DivisionByZeroError DomainException EmptyIterator ErrorException Exception FilesystemIterator FilterIterator GlobIterator InfiniteIterator InvalidArgumentException IteratorIterator LengthException LimitIterator LogicException MultipleIterator NoRewindIterator OutOfBoundsException OutOfRangeException OuterIterator OverflowException ParentIterator ParseError RangeException RecursiveArrayIterator RecursiveCachingIterator RecursiveCallbackFilterIterator RecursiveDirectoryIterator RecursiveFilterIterator RecursiveIterator RecursiveIteratorIterator RecursiveRegexIterator RecursiveTreeIterator RegexIterator RuntimeException SeekableIterator SplDoublyLinkedList SplFileInfo SplFileObject SplFixedArray SplHeap SplMaxHeap SplMinHeap SplObjectStorage SplObserver SplObserver SplPriorityQueue SplQueue SplStack SplSubject SplSubject SplTempFileObject TypeError UnderflowException UnexpectedValueException ArrayAccess Closure Generator Iterator IteratorAggregate Serializable Throwable Traversable WeakReference Directory __PHP_Incomplete_Class parent php_user_filter self static stdClass"};return{aliases:["php","php3","php4","php5","php6","php7"],case_insensitive:!0,keywords:i,contains:[e.HASH_COMMENT_MODE,e.COMMENT("//","$",{contains:[t]}),e.COMMENT("/\\*","\\*/",{contains:[{className:"doctag",begin:"@[A-Za-z]+"}]}),e.COMMENT("__halt_compiler.+?;",!1,{endsWithParent:!0,keywords:"__halt_compiler"}),{className:"string",begin:/<<<['"]?\w+['"]?$/,end:/^\w+;?$/,contains:[e.BACKSLASH_ESCAPE,{className:"subst",variants:[{begin:/\$\w+/},{begin:/\{\$/,end:/\}/}]}]},t,{className:"keyword",begin:/\$this\b/},r,{begin:/(::|->)+[a-zA-Z_\x7f-\xff][a-zA-Z0-9_\x7f-\xff]*/},{className:"function",beginKeywords:"fn function",end:/[;{]/,excludeEnd:!0,illegal:"[$%\\[]",contains:[e.UNDERSCORE_TITLE_MODE,{className:"params",begin:"\\(",end:"\\)",excludeBegin:!0,excludeEnd:!0,keywords:i,contains:["self",r,e.C_BLOCK_COMMENT_MODE,a,n]}]},{className:"class",beginKeywords:"class interface",end:"{",excludeEnd:!0,illegal:/[:\(\$"]/,contains:[{beginKeywords:"extends implements"},e.UNDERSCORE_TITLE_MODE]},{beginKeywords:"namespace",end:";",illegal:/[\.']/,contains:[e.UNDERSCORE_TITLE_MODE]},{beginKeywords:"use",end:";",contains:[e.UNDERSCORE_TITLE_MODE]},{begin:"=>"},a,n]}}}());hljs.registerLanguage("nginx",function(){"use strict";return function(e){var n={className:"variable",variants:[{begin:/\$\d+/},{begin:/\$\{/,end:/}/},{begin:"[\\$\\@]"+e.UNDERSCORE_IDENT_RE}]},a={endsWithParent:!0,keywords:{$pattern:"[a-z/_]+",literal:"on off yes no true false none blocked debug info notice warn error crit select break last permanent redirect kqueue rtsig epoll poll /dev/poll"},relevance:0,illegal:"=>",contains:[e.HASH_COMMENT_MODE,{className:"string",contains:[e.BACKSLASH_ESCAPE,n],variants:[{begin:/"/,end:/"/},{begin:/'/,end:/'/}]},{begin:"([a-z]+):/",end:"\\s",endsWithParent:!0,excludeEnd:!0,contains:[n]},{className:"regexp",contains:[e.BACKSLASH_ESCAPE,n],variants:[{begin:"\\s\\^",end:"\\s|{|;",returnEnd:!0},{begin:"~\\*?\\s+",end:"\\s|{|;",returnEnd:!0},{begin:"\\*(\\.[a-z\\-]+)+"},{begin:"([a-z\\-]+\\.)+\\*"}]},{className:"number",begin:"\\b\\d{1,3}\\.\\d{1,3}\\.\\d{1,3}\\.\\d{1,3}(:\\d{1,5})?\\b"},{className:"number",begin:"\\b\\d+[kKmMgGdshdwy]*\\b",relevance:0},n]};return{name:"Nginx config",aliases:["nginxconf"],contains:[e.HASH_COMMENT_MODE,{begin:e.UNDERSCORE_IDENT_RE+"\\s+{",returnBegin:!0,end:"{",contains:[{className:"section",begin:e.UNDERSCORE_IDENT_RE}],relevance:0},{begin:e.UNDERSCORE_IDENT_RE+"\\s",end:";|{",returnBegin:!0,contains:[{className:"attribute",begin:e.UNDERSCORE_IDENT_RE,starts:a}],relevance:0}],illegal:"[^\\s\\}]"}}}());hljs.registerLanguage("csharp",function(){"use strict";return function(e){var n={keyword:"abstract as base bool break byte case catch char checked const continue decimal default delegate do double enum event explicit extern finally fixed float for foreach goto if implicit in int interface internal is lock long object operator out override params private protected public readonly ref sbyte sealed short sizeof stackalloc static string struct switch this try typeof uint ulong unchecked unsafe ushort using virtual void volatile while add alias ascending async await by descending dynamic equals from get global group into join let nameof on orderby partial remove select set value var when where yield",literal:"null false true"},i=e.inherit(e.TITLE_MODE,{begin:"[a-zA-Z](\\.?\\w)*"}),a={className:"number",variants:[{begin:"\\b(0b[01']+)"},{begin:"(-?)\\b([\\d']+(\\.[\\d']*)?|\\.[\\d']+)(u|U|l|L|ul|UL|f|F|b|B)"},{begin:"(-?)(\\b0[xX][a-fA-F0-9']+|(\\b[\\d']+(\\.[\\d']*)?|\\.[\\d']+)([eE][-+]?[\\d']+)?)"}],relevance:0},s={className:"string",begin:'@"',end:'"',contains:[{begin:'""'}]},t=e.inherit(s,{illegal:/\n/}),l={className:"subst",begin:"{",end:"}",keywords:n},r=e.inherit(l,{illegal:/\n/}),c={className:"string",begin:/\$"/,end:'"',illegal:/\n/,contains:[{begin:"{{"},{begin:"}}"},e.BACKSLASH_ESCAPE,r]},o={className:"string",begin:/\$@"/,end:'"',contains:[{begin:"{{"},{begin:"}}"},{begin:'""'},l]},g=e.inherit(o,{illegal:/\n/,contains:[{begin:"{{"},{begin:"}}"},{begin:'""'},r]});l.contains=[o,c,s,e.APOS_STRING_MODE,e.QUOTE_STRING_MODE,a,e.C_BLOCK_COMMENT_MODE],r.contains=[g,c,t,e.APOS_STRING_MODE,e.QUOTE_STRING_MODE,a,e.inherit(e.C_BLOCK_COMMENT_MODE,{illegal:/\n/})];var d={variants:[o,c,s,e.APOS_STRING_MODE,e.QUOTE_STRING_MODE]},E={begin:"<",end:">",contains:[{beginKeywords:"in out"},i]},_=e.IDENT_RE+"(<"+e.IDENT_RE+"(\\s*,\\s*"+e.IDENT_RE+")*>)?(\\[\\])?",b={begin:"@"+e.IDENT_RE,relevance:0};return{name:"C#",aliases:["cs","c#"],keywords:n,illegal:/::/,contains:[e.COMMENT("///","$",{returnBegin:!0,contains:[{className:"doctag",variants:[{begin:"///",relevance:0},{begin:"\x3c!--|--\x3e"},{begin:""}]}]}),e.C_LINE_COMMENT_MODE,e.C_BLOCK_COMMENT_MODE,{className:"meta",begin:"#",end:"$",keywords:{"meta-keyword":"if else elif endif define undef warning error line region endregion pragma checksum"}},d,a,{beginKeywords:"class interface",end:/[{;=]/,illegal:/[^\s:,]/,contains:[{beginKeywords:"where class"},i,E,e.C_LINE_COMMENT_MODE,e.C_BLOCK_COMMENT_MODE]},{beginKeywords:"namespace",end:/[{;=]/,illegal:/[^\s:]/,contains:[i,e.C_LINE_COMMENT_MODE,e.C_BLOCK_COMMENT_MODE]},{className:"meta",begin:"^\\s*\\[",excludeBegin:!0,end:"\\]",excludeEnd:!0,contains:[{className:"meta-string",begin:/"/,end:/"/}]},{beginKeywords:"new return throw await else",relevance:0},{className:"function",begin:"("+_+"\\s+)+"+e.IDENT_RE+"\\s*(\\<.+\\>)?\\s*\\(",returnBegin:!0,end:/\s*[{;=]/,excludeEnd:!0,keywords:n,contains:[{begin:e.IDENT_RE+"\\s*(\\<.+\\>)?\\s*\\(",returnBegin:!0,contains:[e.TITLE_MODE,E],relevance:0},{className:"params",begin:/\(/,end:/\)/,excludeBegin:!0,excludeEnd:!0,keywords:n,relevance:0,contains:[d,a,e.C_BLOCK_COMMENT_MODE]},e.C_LINE_COMMENT_MODE,e.C_BLOCK_COMMENT_MODE]},b]}}}());hljs.registerLanguage("perl",function(){"use strict";return function(e){var n={$pattern:/[\w.]+/,keyword:"getpwent getservent quotemeta msgrcv scalar kill dbmclose undef lc ma syswrite tr send umask sysopen shmwrite vec qx utime local oct semctl localtime readpipe do return format read sprintf dbmopen pop getpgrp not getpwnam rewinddir qq fileno qw endprotoent wait sethostent bless s|0 opendir continue each sleep endgrent shutdown dump chomp connect getsockname die socketpair close flock exists index shmget sub for endpwent redo lstat msgctl setpgrp abs exit select print ref gethostbyaddr unshift fcntl syscall goto getnetbyaddr join gmtime symlink semget splice x|0 getpeername recv log setsockopt cos last reverse gethostbyname getgrnam study formline endhostent times chop length gethostent getnetent pack getprotoent getservbyname rand mkdir pos chmod y|0 substr endnetent printf next open msgsnd readdir use unlink getsockopt getpriority rindex wantarray hex system getservbyport endservent int chr untie rmdir prototype tell listen fork shmread ucfirst setprotoent else sysseek link getgrgid shmctl waitpid unpack getnetbyname reset chdir grep split require caller lcfirst until warn while values shift telldir getpwuid my getprotobynumber delete and sort uc defined srand accept package seekdir getprotobyname semop our rename seek if q|0 chroot sysread setpwent no crypt getc chown sqrt write setnetent setpriority foreach tie sin msgget map stat getlogin unless elsif truncate exec keys glob tied closedir ioctl socket readlink eval xor readline binmode setservent eof ord bind alarm pipe atan2 getgrent exp time push setgrent gt lt or ne m|0 break given say state when"},t={className:"subst",begin:"[$@]\\{",end:"\\}",keywords:n},s={begin:"->{",end:"}"},r={variants:[{begin:/\$\d/},{begin:/[\$%@](\^\w\b|#\w+(::\w+)*|{\w+}|\w+(::\w*)*)/},{begin:/[\$%@][^\s\w{]/,relevance:0}]},i=[e.BACKSLASH_ESCAPE,t,r],a=[r,e.HASH_COMMENT_MODE,e.COMMENT("^\\=\\w","\\=cut",{endsWithParent:!0}),s,{className:"string",contains:i,variants:[{begin:"q[qwxr]?\\s*\\(",end:"\\)",relevance:5},{begin:"q[qwxr]?\\s*\\[",end:"\\]",relevance:5},{begin:"q[qwxr]?\\s*\\{",end:"\\}",relevance:5},{begin:"q[qwxr]?\\s*\\|",end:"\\|",relevance:5},{begin:"q[qwxr]?\\s*\\<",end:"\\>",relevance:5},{begin:"qw\\s+q",end:"q",relevance:5},{begin:"'",end:"'",contains:[e.BACKSLASH_ESCAPE]},{begin:'"',end:'"'},{begin:"`",end:"`",contains:[e.BACKSLASH_ESCAPE]},{begin:"{\\w+}",contains:[],relevance:0},{begin:"-?\\w+\\s*\\=\\>",contains:[],relevance:0}]},{className:"number",begin:"(\\b0[0-7_]+)|(\\b0x[0-9a-fA-F_]+)|(\\b[1-9][0-9_]*(\\.[0-9_]+)?)|[0_]\\b",relevance:0},{begin:"(\\/\\/|"+e.RE_STARTERS_RE+"|\\b(split|return|print|reverse|grep)\\b)\\s*",keywords:"split return print reverse grep",relevance:0,contains:[e.HASH_COMMENT_MODE,{className:"regexp",begin:"(s|tr|y)/(\\\\.|[^/])*/(\\\\.|[^/])*/[a-z]*",relevance:10},{className:"regexp",begin:"(m|qr)?/",end:"/[a-z]*",contains:[e.BACKSLASH_ESCAPE],relevance:0}]},{className:"function",beginKeywords:"sub",end:"(\\s*\\(.*?\\))?[;{]",excludeEnd:!0,relevance:5,contains:[e.TITLE_MODE]},{begin:"-\\w\\b",relevance:0},{begin:"^__DATA__$",end:"^__END__$",subLanguage:"mojolicious",contains:[{begin:"^@@.*",end:"$",className:"comment"}]}];return t.contains=a,s.contains=a,{name:"Perl",aliases:["pl","pm"],keywords:n,contains:a}}}());hljs.registerLanguage("swift",function(){"use strict";return function(e){var i={keyword:"#available #colorLiteral #column #else #elseif #endif #file #fileLiteral #function #if #imageLiteral #line #selector #sourceLocation _ __COLUMN__ __FILE__ __FUNCTION__ __LINE__ Any as as! as? associatedtype associativity break case catch class continue convenience default defer deinit didSet do dynamic dynamicType else enum extension fallthrough false fileprivate final for func get guard if import in indirect infix init inout internal is lazy left let mutating nil none nonmutating open operator optional override postfix precedence prefix private protocol Protocol public repeat required rethrows return right self Self set static struct subscript super switch throw throws true try try! try? Type typealias unowned var weak where while willSet",literal:"true false nil",built_in:"abs advance alignof alignofValue anyGenerator assert assertionFailure bridgeFromObjectiveC bridgeFromObjectiveCUnconditional bridgeToObjectiveC bridgeToObjectiveCUnconditional c compactMap contains count countElements countLeadingZeros debugPrint debugPrintln distance dropFirst dropLast dump encodeBitsAsWords enumerate equal fatalError filter find getBridgedObjectiveCType getVaList indices insertionSort isBridgedToObjectiveC isBridgedVerbatimToObjectiveC isUniquelyReferenced isUniquelyReferencedNonObjC join lazy lexicographicalCompare map max maxElement min minElement numericCast overlaps partition posix precondition preconditionFailure print println quickSort readLine reduce reflect reinterpretCast reverse roundUpToAlignment sizeof sizeofValue sort split startsWith stride strideof strideofValue swap toString transcode underestimateCount unsafeAddressOf unsafeBitCast unsafeDowncast unsafeUnwrap unsafeReflect withExtendedLifetime withObjectAtPlusZero withUnsafePointer withUnsafePointerToObject withUnsafeMutablePointer withUnsafeMutablePointers withUnsafePointer withUnsafePointers withVaList zip"},n=e.COMMENT("/\\*","\\*/",{contains:["self"]}),t={className:"subst",begin:/\\\(/,end:"\\)",keywords:i,contains:[]},a={className:"string",contains:[e.BACKSLASH_ESCAPE,t],variants:[{begin:/"""/,end:/"""/},{begin:/"/,end:/"/}]},r={className:"number",begin:"\\b([\\d_]+(\\.[\\deE_]+)?|0x[a-fA-F0-9_]+(\\.[a-fA-F0-9p_]+)?|0b[01_]+|0o[0-7_]+)\\b",relevance:0};return t.contains=[r],{name:"Swift",keywords:i,contains:[a,e.C_LINE_COMMENT_MODE,n,{className:"type",begin:"\\b[A-Z][\\wÀ-ʸ']*[!?]"},{className:"type",begin:"\\b[A-Z][\\wÀ-ʸ']*",relevance:0},r,{className:"function",beginKeywords:"func",end:"{",excludeEnd:!0,contains:[e.inherit(e.TITLE_MODE,{begin:/[A-Za-z$_][0-9A-Za-z$_]*/}),{begin://},{className:"params",begin:/\(/,end:/\)/,endsParent:!0,keywords:i,contains:["self",r,a,e.C_BLOCK_COMMENT_MODE,{begin:":"}],illegal:/["']/}],illegal:/\[|%/},{className:"class",beginKeywords:"struct protocol class extension enum",keywords:i,end:"\\{",excludeEnd:!0,contains:[e.inherit(e.TITLE_MODE,{begin:/[A-Za-z$_][\u00C0-\u02B80-9A-Za-z$_]*/})]},{className:"meta",begin:"(@discardableResult|@warn_unused_result|@exported|@lazy|@noescape|@NSCopying|@NSManaged|@objc|@objcMembers|@convention|@required|@noreturn|@IBAction|@IBDesignable|@IBInspectable|@IBOutlet|@infix|@prefix|@postfix|@autoclosure|@testable|@available|@nonobjc|@NSApplicationMain|@UIApplicationMain|@dynamicMemberLookup|@propertyWrapper)\\b"},{beginKeywords:"import",end:/$/,contains:[e.C_LINE_COMMENT_MODE,n]}]}}}());hljs.registerLanguage("makefile",function(){"use strict";return function(e){var i={className:"variable",variants:[{begin:"\\$\\("+e.UNDERSCORE_IDENT_RE+"\\)",contains:[e.BACKSLASH_ESCAPE]},{begin:/\$[@%`]+/}]}]}]};return{name:"HTML, XML",aliases:["html","xhtml","rss","atom","xjb","xsd","xsl","plist","wsf","svg"],case_insensitive:!0,contains:[{className:"meta",begin:"",relevance:10,contains:[a,i,t,s,{begin:"\\[",end:"\\]",contains:[{className:"meta",begin:"",contains:[a,s,i,t]}]}]},e.COMMENT("\x3c!--","--\x3e",{relevance:10}),{begin:"<\\!\\[CDATA\\[",end:"\\]\\]>",relevance:10},n,{className:"meta",begin:/<\?xml/,end:/\?>/,relevance:10},{className:"tag",begin:")",end:">",keywords:{name:"style"},contains:[c],starts:{end:"",returnEnd:!0,subLanguage:["css","xml"]}},{className:"tag",begin:")",end:">",keywords:{name:"script"},contains:[c],starts:{end:"<\/script>",returnEnd:!0,subLanguage:["javascript","handlebars","xml"]}},{className:"tag",begin:"",contains:[{className:"name",begin:/[^\/><\s]+/,relevance:0},c]}]}}}());hljs.registerLanguage("bash",function(){"use strict";return function(e){const s={};Object.assign(s,{className:"variable",variants:[{begin:/\$[\w\d#@][\w\d_]*/},{begin:/\$\{/,end:/\}/,contains:[{begin:/:-/,contains:[s]}]}]});const t={className:"subst",begin:/\$\(/,end:/\)/,contains:[e.BACKSLASH_ESCAPE]},n={className:"string",begin:/"/,end:/"/,contains:[e.BACKSLASH_ESCAPE,s,t]};t.contains.push(n);const a={begin:/\$\(\(/,end:/\)\)/,contains:[{begin:/\d+#[0-9a-f]+/,className:"number"},e.NUMBER_MODE,s]},i=e.SHEBANG({binary:"(fish|bash|zsh|sh|csh|ksh|tcsh|dash|scsh)",relevance:10}),c={className:"function",begin:/\w[\w\d_]*\s*\(\s*\)\s*\{/,returnBegin:!0,contains:[e.inherit(e.TITLE_MODE,{begin:/\w[\w\d_]*/})],relevance:0};return{name:"Bash",aliases:["sh","zsh"],keywords:{$pattern:/\b-?[a-z\._]+\b/,keyword:"if then else elif fi for while in do done case esac function",literal:"true false",built_in:"break cd continue eval exec exit export getopts hash pwd readonly return shift test times trap umask unset alias bind builtin caller command declare echo enable help let local logout mapfile printf read readarray source type typeset ulimit unalias set shopt autoload bg bindkey bye cap chdir clone comparguments compcall compctl compdescribe compfiles compgroups compquote comptags comptry compvalues dirs disable disown echotc echoti emulate fc fg float functions getcap getln history integer jobs kill limit log noglob popd print pushd pushln rehash sched setcap setopt stat suspend ttyctl unfunction unhash unlimit unsetopt vared wait whence where which zcompile zformat zftp zle zmodload zparseopts zprof zpty zregexparse zsocket zstyle ztcp",_:"-ne -eq -lt -gt -f -d -e -s -l -a"},contains:[i,e.SHEBANG(),c,a,e.HASH_COMMENT_MODE,n,{className:"",begin:/\\"/},{className:"string",begin:/'/,end:/'/},s]}}}());hljs.registerLanguage("c-like",function(){"use strict";return function(e){function t(e){return"(?:"+e+")?"}var n="(decltype\\(auto\\)|"+t("[a-zA-Z_]\\w*::")+"[a-zA-Z_]\\w*"+t("<.*?>")+")",r={className:"keyword",begin:"\\b[a-z\\d_]*_t\\b"},a={className:"string",variants:[{begin:'(u8?|U|L)?"',end:'"',illegal:"\\n",contains:[e.BACKSLASH_ESCAPE]},{begin:"(u8?|U|L)?'(\\\\(x[0-9A-Fa-f]{2}|u[0-9A-Fa-f]{4,8}|[0-7]{3}|\\S)|.)",end:"'",illegal:"."},e.END_SAME_AS_BEGIN({begin:/(?:u8?|U|L)?R"([^()\\ ]{0,16})\(/,end:/\)([^()\\ ]{0,16})"/})]},i={className:"number",variants:[{begin:"\\b(0b[01']+)"},{begin:"(-?)\\b([\\d']+(\\.[\\d']*)?|\\.[\\d']+)(u|U|l|L|ul|UL|f|F|b|B)"},{begin:"(-?)(\\b0[xX][a-fA-F0-9']+|(\\b[\\d']+(\\.[\\d']*)?|\\.[\\d']+)([eE][-+]?[\\d']+)?)"}],relevance:0},s={className:"meta",begin:/#\s*[a-z]+\b/,end:/$/,keywords:{"meta-keyword":"if else elif endif define undef warning error line pragma _Pragma ifdef ifndef include"},contains:[{begin:/\\\n/,relevance:0},e.inherit(a,{className:"meta-string"}),{className:"meta-string",begin:/<.*?>/,end:/$/,illegal:"\\n"},e.C_LINE_COMMENT_MODE,e.C_BLOCK_COMMENT_MODE]},o={className:"title",begin:t("[a-zA-Z_]\\w*::")+e.IDENT_RE,relevance:0},c=t("[a-zA-Z_]\\w*::")+e.IDENT_RE+"\\s*\\(",l={keyword:"int float while private char char8_t char16_t char32_t catch import module export virtual operator sizeof dynamic_cast|10 typedef const_cast|10 const for static_cast|10 union namespace unsigned long volatile static protected bool template mutable if public friend do goto auto void enum else break extern using asm case typeid wchar_t short reinterpret_cast|10 default double register explicit signed typename try this switch continue inline delete alignas alignof constexpr consteval constinit decltype concept co_await co_return co_yield requires noexcept static_assert thread_local restrict final override atomic_bool atomic_char atomic_schar atomic_uchar atomic_short atomic_ushort atomic_int atomic_uint atomic_long atomic_ulong atomic_llong atomic_ullong new throw return and and_eq bitand bitor compl not not_eq or or_eq xor xor_eq",built_in:"std string wstring cin cout cerr clog stdin stdout stderr stringstream istringstream ostringstream auto_ptr deque list queue stack vector map set pair bitset multiset multimap unordered_set unordered_map unordered_multiset unordered_multimap priority_queue make_pair array shared_ptr abort terminate abs acos asin atan2 atan calloc ceil cosh cos exit exp fabs floor fmod fprintf fputs free frexp fscanf future isalnum isalpha iscntrl isdigit isgraph islower isprint ispunct isspace isupper isxdigit tolower toupper labs ldexp log10 log malloc realloc memchr memcmp memcpy memset modf pow printf putchar puts scanf sinh sin snprintf sprintf sqrt sscanf strcat strchr strcmp strcpy strcspn strlen strncat strncmp strncpy strpbrk strrchr strspn strstr tanh tan vfprintf vprintf vsprintf endl initializer_list unique_ptr _Bool complex _Complex imaginary _Imaginary",literal:"true false nullptr NULL"},d=[r,e.C_LINE_COMMENT_MODE,e.C_BLOCK_COMMENT_MODE,i,a],_={variants:[{begin:/=/,end:/;/},{begin:/\(/,end:/\)/},{beginKeywords:"new throw return else",end:/;/}],keywords:l,contains:d.concat([{begin:/\(/,end:/\)/,keywords:l,contains:d.concat(["self"]),relevance:0}]),relevance:0},u={className:"function",begin:"("+n+"[\\*&\\s]+)+"+c,returnBegin:!0,end:/[{;=]/,excludeEnd:!0,keywords:l,illegal:/[^\w\s\*&:<>]/,contains:[{begin:"decltype\\(auto\\)",keywords:l,relevance:0},{begin:c,returnBegin:!0,contains:[o],relevance:0},{className:"params",begin:/\(/,end:/\)/,keywords:l,relevance:0,contains:[e.C_LINE_COMMENT_MODE,e.C_BLOCK_COMMENT_MODE,a,i,r,{begin:/\(/,end:/\)/,keywords:l,relevance:0,contains:["self",e.C_LINE_COMMENT_MODE,e.C_BLOCK_COMMENT_MODE,a,i,r]}]},r,e.C_LINE_COMMENT_MODE,e.C_BLOCK_COMMENT_MODE,s]};return{aliases:["c","cc","h","c++","h++","hpp","hh","hxx","cxx"],keywords:l,disableAutodetect:!0,illegal:"",keywords:l,contains:["self",r]},{begin:e.IDENT_RE+"::",keywords:l},{className:"class",beginKeywords:"class struct",end:/[{;:]/,contains:[{begin://,contains:["self"]},e.TITLE_MODE]}]),exports:{preprocessor:s,strings:a,keywords:l}}}}());hljs.registerLanguage("coffeescript",function(){"use strict";const e=["as","in","of","if","for","while","finally","var","new","function","do","return","void","else","break","catch","instanceof","with","throw","case","default","try","switch","continue","typeof","delete","let","yield","const","class","debugger","async","await","static","import","from","export","extends"],n=["true","false","null","undefined","NaN","Infinity"],a=[].concat(["setInterval","setTimeout","clearInterval","clearTimeout","require","exports","eval","isFinite","isNaN","parseFloat","parseInt","decodeURI","decodeURIComponent","encodeURI","encodeURIComponent","escape","unescape"],["arguments","this","super","console","window","document","localStorage","module","global"],["Intl","DataView","Number","Math","Date","String","RegExp","Object","Function","Boolean","Error","Symbol","Set","Map","WeakSet","WeakMap","Proxy","Reflect","JSON","Promise","Float64Array","Int16Array","Int32Array","Int8Array","Uint16Array","Uint32Array","Float32Array","Array","Uint8Array","Uint8ClampedArray","ArrayBuffer"],["EvalError","InternalError","RangeError","ReferenceError","SyntaxError","TypeError","URIError"]);return function(r){var t={keyword:e.concat(["then","unless","until","loop","by","when","and","or","is","isnt","not"]).filter((e=>n=>!e.includes(n))(["var","const","let","function","static"])).join(" "),literal:n.concat(["yes","no","on","off"]).join(" "),built_in:a.concat(["npm","print"]).join(" ")},i="[A-Za-z$_][0-9A-Za-z$_]*",s={className:"subst",begin:/#\{/,end:/}/,keywords:t},o=[r.BINARY_NUMBER_MODE,r.inherit(r.C_NUMBER_MODE,{starts:{end:"(\\s*/)?",relevance:0}}),{className:"string",variants:[{begin:/'''/,end:/'''/,contains:[r.BACKSLASH_ESCAPE]},{begin:/'/,end:/'/,contains:[r.BACKSLASH_ESCAPE]},{begin:/"""/,end:/"""/,contains:[r.BACKSLASH_ESCAPE,s]},{begin:/"/,end:/"/,contains:[r.BACKSLASH_ESCAPE,s]}]},{className:"regexp",variants:[{begin:"///",end:"///",contains:[s,r.HASH_COMMENT_MODE]},{begin:"//[gim]{0,3}(?=\\W)",relevance:0},{begin:/\/(?![ *]).*?(?![\\]).\/[gim]{0,3}(?=\W)/}]},{begin:"@"+i},{subLanguage:"javascript",excludeBegin:!0,excludeEnd:!0,variants:[{begin:"```",end:"```"},{begin:"`",end:"`"}]}];s.contains=o;var c=r.inherit(r.TITLE_MODE,{begin:i}),l={className:"params",begin:"\\([^\\(]",returnBegin:!0,contains:[{begin:/\(/,end:/\)/,keywords:t,contains:["self"].concat(o)}]};return{name:"CoffeeScript",aliases:["coffee","cson","iced"],keywords:t,illegal:/\/\*/,contains:o.concat([r.COMMENT("###","###"),r.HASH_COMMENT_MODE,{className:"function",begin:"^\\s*"+i+"\\s*=\\s*(\\(.*\\))?\\s*\\B[-=]>",end:"[-=]>",returnBegin:!0,contains:[c,l]},{begin:/[:\(,=]\s*/,relevance:0,contains:[{className:"function",begin:"(\\(.*\\))?\\s*\\B[-=]>",end:"[-=]>",returnBegin:!0,contains:[l]}]},{className:"class",beginKeywords:"class",end:"$",illegal:/[:="\[\]]/,contains:[{beginKeywords:"extends",endsWithParent:!0,illegal:/[:="\[\]]/,contains:[c]},c]},{begin:i+":",end:":",returnBegin:!0,returnEnd:!0,relevance:0}])}}}());hljs.registerLanguage("ruby",function(){"use strict";return function(e){var n="[a-zA-Z_]\\w*[!?=]?|[-+~]\\@|<<|>>|=~|===?|<=>|[<>]=?|\\*\\*|[-/+%^&*~`|]|\\[\\]=?",a={keyword:"and then defined module in return redo if BEGIN retry end for self when next until do begin unless END rescue else break undef not super class case require yield alias while ensure elsif or include attr_reader attr_writer attr_accessor",literal:"true false nil"},s={className:"doctag",begin:"@[A-Za-z]+"},i={begin:"#<",end:">"},r=[e.COMMENT("#","$",{contains:[s]}),e.COMMENT("^\\=begin","^\\=end",{contains:[s],relevance:10}),e.COMMENT("^__END__","\\n$")],c={className:"subst",begin:"#\\{",end:"}",keywords:a},t={className:"string",contains:[e.BACKSLASH_ESCAPE,c],variants:[{begin:/'/,end:/'/},{begin:/"/,end:/"/},{begin:/`/,end:/`/},{begin:"%[qQwWx]?\\(",end:"\\)"},{begin:"%[qQwWx]?\\[",end:"\\]"},{begin:"%[qQwWx]?{",end:"}"},{begin:"%[qQwWx]?<",end:">"},{begin:"%[qQwWx]?/",end:"/"},{begin:"%[qQwWx]?%",end:"%"},{begin:"%[qQwWx]?-",end:"-"},{begin:"%[qQwWx]?\\|",end:"\\|"},{begin:/\B\?(\\\d{1,3}|\\x[A-Fa-f0-9]{1,2}|\\u[A-Fa-f0-9]{4}|\\?\S)\b/},{begin:/<<[-~]?'?(\w+)(?:.|\n)*?\n\s*\1\b/,returnBegin:!0,contains:[{begin:/<<[-~]?'?/},e.END_SAME_AS_BEGIN({begin:/(\w+)/,end:/(\w+)/,contains:[e.BACKSLASH_ESCAPE,c]})]}]},b={className:"params",begin:"\\(",end:"\\)",endsParent:!0,keywords:a},d=[t,i,{className:"class",beginKeywords:"class module",end:"$|;",illegal:/=/,contains:[e.inherit(e.TITLE_MODE,{begin:"[A-Za-z_]\\w*(::\\w+)*(\\?|\\!)?"}),{begin:"<\\s*",contains:[{begin:"("+e.IDENT_RE+"::)?"+e.IDENT_RE}]}].concat(r)},{className:"function",beginKeywords:"def",end:"$|;",contains:[e.inherit(e.TITLE_MODE,{begin:n}),b].concat(r)},{begin:e.IDENT_RE+"::"},{className:"symbol",begin:e.UNDERSCORE_IDENT_RE+"(\\!|\\?)?:",relevance:0},{className:"symbol",begin:":(?!\\s)",contains:[t,{begin:n}],relevance:0},{className:"number",begin:"(\\b0[0-7_]+)|(\\b0x[0-9a-fA-F_]+)|(\\b[1-9][0-9_]*(\\.[0-9_]+)?)|[0_]\\b",relevance:0},{begin:"(\\$\\W)|((\\$|\\@\\@?)(\\w+))"},{className:"params",begin:/\|/,end:/\|/,keywords:a},{begin:"("+e.RE_STARTERS_RE+"|unless)\\s*",keywords:"unless",contains:[i,{className:"regexp",contains:[e.BACKSLASH_ESCAPE,c],illegal:/\n/,variants:[{begin:"/",end:"/[a-z]*"},{begin:"%r{",end:"}[a-z]*"},{begin:"%r\\(",end:"\\)[a-z]*"},{begin:"%r!",end:"![a-z]*"},{begin:"%r\\[",end:"\\][a-z]*"}]}].concat(r),relevance:0}].concat(r);c.contains=d,b.contains=d;var g=[{begin:/^\s*=>/,starts:{end:"$",contains:d}},{className:"meta",begin:"^([>?]>|[\\w#]+\\(\\w+\\):\\d+:\\d+>|(\\w+-)?\\d+\\.\\d+\\.\\d(p\\d+)?[^>]+>)",starts:{end:"$",contains:d}}];return{name:"Ruby",aliases:["rb","gemspec","podspec","thor","irb"],keywords:a,illegal:/\/\*/,contains:r.concat(g).concat(d)}}}());hljs.registerLanguage("yaml",function(){"use strict";return function(e){var n="true false yes no null",a="[\\w#;/?:@&=+$,.~*\\'()[\\]]+",s={className:"string",relevance:0,variants:[{begin:/'/,end:/'/},{begin:/"/,end:/"/},{begin:/\S+/}],contains:[e.BACKSLASH_ESCAPE,{className:"template-variable",variants:[{begin:"{{",end:"}}"},{begin:"%{",end:"}"}]}]},i=e.inherit(s,{variants:[{begin:/'/,end:/'/},{begin:/"/,end:/"/},{begin:/[^\s,{}[\]]+/}]}),l={end:",",endsWithParent:!0,excludeEnd:!0,contains:[],keywords:n,relevance:0},t={begin:"{",end:"}",contains:[l],illegal:"\\n",relevance:0},g={begin:"\\[",end:"\\]",contains:[l],illegal:"\\n",relevance:0},b=[{className:"attr",variants:[{begin:"\\w[\\w :\\/.-]*:(?=[ \t]|$)"},{begin:'"\\w[\\w :\\/.-]*":(?=[ \t]|$)'},{begin:"'\\w[\\w :\\/.-]*':(?=[ \t]|$)"}]},{className:"meta",begin:"^---s*$",relevance:10},{className:"string",begin:"[\\|>]([0-9]?[+-])?[ ]*\\n( *)[\\S ]+\\n(\\2[\\S ]+\\n?)*"},{begin:"<%[%=-]?",end:"[%-]?%>",subLanguage:"ruby",excludeBegin:!0,excludeEnd:!0,relevance:0},{className:"type",begin:"!\\w+!"+a},{className:"type",begin:"!<"+a+">"},{className:"type",begin:"!"+a},{className:"type",begin:"!!"+a},{className:"meta",begin:"&"+e.UNDERSCORE_IDENT_RE+"$"},{className:"meta",begin:"\\*"+e.UNDERSCORE_IDENT_RE+"$"},{className:"bullet",begin:"\\-(?=[ ]|$)",relevance:0},e.HASH_COMMENT_MODE,{beginKeywords:n,keywords:{literal:n}},{className:"number",begin:"\\b[0-9]{4}(-[0-9][0-9]){0,2}([Tt \\t][0-9][0-9]?(:[0-9][0-9]){2})?(\\.[0-9]*)?([ \\t])*(Z|[-+][0-9][0-9]?(:[0-9][0-9])?)?\\b"},{className:"number",begin:e.C_NUMBER_RE+"\\b"},t,g,s],c=[...b];return c.pop(),c.push(i),l.contains=c,{name:"YAML",case_insensitive:!0,aliases:["yml","YAML"],contains:b}}}());hljs.registerLanguage("d",function(){"use strict";return function(e){var a={$pattern:e.UNDERSCORE_IDENT_RE,keyword:"abstract alias align asm assert auto body break byte case cast catch class const continue debug default delete deprecated do else enum export extern final finally for foreach foreach_reverse|10 goto if immutable import in inout int interface invariant is lazy macro mixin module new nothrow out override package pragma private protected public pure ref return scope shared static struct super switch synchronized template this throw try typedef typeid typeof union unittest version void volatile while with __FILE__ __LINE__ __gshared|10 __thread __traits __DATE__ __EOF__ __TIME__ __TIMESTAMP__ __VENDOR__ __VERSION__",built_in:"bool cdouble cent cfloat char creal dchar delegate double dstring float function idouble ifloat ireal long real short string ubyte ucent uint ulong ushort wchar wstring",literal:"false null true"},d="((0|[1-9][\\d_]*)|0[bB][01_]+|0[xX]([\\da-fA-F][\\da-fA-F_]*|_[\\da-fA-F][\\da-fA-F_]*))",n="\\\\(['\"\\?\\\\abfnrtv]|u[\\dA-Fa-f]{4}|[0-7]{1,3}|x[\\dA-Fa-f]{2}|U[\\dA-Fa-f]{8})|&[a-zA-Z\\d]{2,};",t={className:"number",begin:"\\b"+d+"(L|u|U|Lu|LU|uL|UL)?",relevance:0},_={className:"number",begin:"\\b(((0[xX](([\\da-fA-F][\\da-fA-F_]*|_[\\da-fA-F][\\da-fA-F_]*)\\.([\\da-fA-F][\\da-fA-F_]*|_[\\da-fA-F][\\da-fA-F_]*)|\\.?([\\da-fA-F][\\da-fA-F_]*|_[\\da-fA-F][\\da-fA-F_]*))[pP][+-]?(0|[1-9][\\d_]*|\\d[\\d_]*|[\\d_]+?\\d))|((0|[1-9][\\d_]*|\\d[\\d_]*|[\\d_]+?\\d)(\\.\\d*|([eE][+-]?(0|[1-9][\\d_]*|\\d[\\d_]*|[\\d_]+?\\d)))|\\d+\\.(0|[1-9][\\d_]*|\\d[\\d_]*|[\\d_]+?\\d)(0|[1-9][\\d_]*|\\d[\\d_]*|[\\d_]+?\\d)|\\.(0|[1-9][\\d_]*)([eE][+-]?(0|[1-9][\\d_]*|\\d[\\d_]*|[\\d_]+?\\d))?))([fF]|L|i|[fF]i|Li)?|"+d+"(i|[fF]i|Li))",relevance:0},r={className:"string",begin:"'("+n+"|.)",end:"'",illegal:"."},i={className:"string",begin:'"',contains:[{begin:n,relevance:0}],end:'"[cwd]?'},s=e.COMMENT("\\/\\+","\\+\\/",{contains:["self"],relevance:10});return{name:"D",keywords:a,contains:[e.C_LINE_COMMENT_MODE,e.C_BLOCK_COMMENT_MODE,s,{className:"string",begin:'x"[\\da-fA-F\\s\\n\\r]*"[cwd]?',relevance:10},i,{className:"string",begin:'[rq]"',end:'"[cwd]?',relevance:5},{className:"string",begin:"`",end:"`[cwd]?"},{className:"string",begin:'q"\\{',end:'\\}"'},_,t,r,{className:"meta",begin:"^#!",end:"$",relevance:5},{className:"meta",begin:"#(line)",end:"$",relevance:5},{className:"keyword",begin:"@[a-zA-Z_][a-zA-Z_\\d]*"}]}}}());hljs.registerLanguage("properties",function(){"use strict";return function(e){var n="[ \\t\\f]*",t="("+n+"[:=]"+n+"|[ \\t\\f]+)",a="([^\\\\:= \\t\\f\\n]|\\\\.)+",s={end:t,relevance:0,starts:{className:"string",end:/$/,relevance:0,contains:[{begin:"\\\\\\n"}]}};return{name:".properties",case_insensitive:!0,illegal:/\S/,contains:[e.COMMENT("^\\s*[!#]","$"),{begin:"([^\\\\\\W:= \\t\\f\\n]|\\\\.)+"+t,returnBegin:!0,contains:[{className:"attr",begin:"([^\\\\\\W:= \\t\\f\\n]|\\\\.)+",endsParent:!0,relevance:0}],starts:s},{begin:a+t,returnBegin:!0,relevance:0,contains:[{className:"meta",begin:a,endsParent:!0,relevance:0}],starts:s},{className:"attr",relevance:0,begin:a+n+"$"}]}}}());hljs.registerLanguage("http",function(){"use strict";return function(e){var n="HTTP/[0-9\\.]+";return{name:"HTTP",aliases:["https"],illegal:"\\S",contains:[{begin:"^"+n,end:"$",contains:[{className:"number",begin:"\\b\\d{3}\\b"}]},{begin:"^[A-Z]+ (.*?) "+n+"$",returnBegin:!0,end:"$",contains:[{className:"string",begin:" ",end:" ",excludeBegin:!0,excludeEnd:!0},{begin:n},{className:"keyword",begin:"[A-Z]+"}]},{className:"attribute",begin:"^\\w",end:": ",excludeEnd:!0,illegal:"\\n|\\s|=",starts:{end:"$",relevance:0}},{begin:"\\n\\n",starts:{subLanguage:[],endsWithParent:!0}}]}}}());hljs.registerLanguage("haskell",function(){"use strict";return function(e){var n={variants:[e.COMMENT("--","$"),e.COMMENT("{-","-}",{contains:["self"]})]},i={className:"meta",begin:"{-#",end:"#-}"},a={className:"meta",begin:"^#",end:"$"},s={className:"type",begin:"\\b[A-Z][\\w']*",relevance:0},l={begin:"\\(",end:"\\)",illegal:'"',contains:[i,a,{className:"type",begin:"\\b[A-Z][\\w]*(\\((\\.\\.|,|\\w+)\\))?"},e.inherit(e.TITLE_MODE,{begin:"[_a-z][\\w']*"}),n]};return{name:"Haskell",aliases:["hs"],keywords:"let in if then else case of where do module import hiding qualified type data newtype deriving class instance as default infix infixl infixr foreign export ccall stdcall cplusplus jvm dotnet safe unsafe family forall mdo proc rec",contains:[{beginKeywords:"module",end:"where",keywords:"module where",contains:[l,n],illegal:"\\W\\.|;"},{begin:"\\bimport\\b",end:"$",keywords:"import qualified as hiding",contains:[l,n],illegal:"\\W\\.|;"},{className:"class",begin:"^(\\s*)?(class|instance)\\b",end:"where",keywords:"class family instance where",contains:[s,l,n]},{className:"class",begin:"\\b(data|(new)?type)\\b",end:"$",keywords:"data family type newtype deriving",contains:[i,s,l,{begin:"{",end:"}",contains:l.contains},n]},{beginKeywords:"default",end:"$",contains:[s,l,n]},{beginKeywords:"infix infixl infixr",end:"$",contains:[e.C_NUMBER_MODE,n]},{begin:"\\bforeign\\b",end:"$",keywords:"foreign import export ccall stdcall cplusplus jvm dotnet safe unsafe",contains:[s,e.QUOTE_STRING_MODE,n]},{className:"meta",begin:"#!\\/usr\\/bin\\/env runhaskell",end:"$"},i,a,e.QUOTE_STRING_MODE,e.C_NUMBER_MODE,s,e.inherit(e.TITLE_MODE,{begin:"^[_a-z][\\w']*"}),n,{begin:"->|<-"}]}}}());hljs.registerLanguage("handlebars",function(){"use strict";function e(...e){return e.map(e=>(function(e){return e?"string"==typeof e?e:e.source:null})(e)).join("")}return function(n){const a={"builtin-name":"action bindattr collection component concat debugger each each-in get hash if in input link-to loc log lookup mut outlet partial query-params render template textarea unbound unless view with yield"},t=/\[.*?\]/,s=/[^\s!"#%&'()*+,.\/;<=>@\[\\\]^`{|}~]+/,i=e("(",/'.*?'/,"|",/".*?"/,"|",t,"|",s,"|",/\.|\//,")+"),r=e("(",t,"|",s,")(?==)"),l={begin:i,lexemes:/[\w.\/]+/},c=n.inherit(l,{keywords:{literal:"true false undefined null"}}),o={begin:/\(/,end:/\)/},m={className:"attr",begin:r,relevance:0,starts:{begin:/=/,end:/=/,starts:{contains:[n.NUMBER_MODE,n.QUOTE_STRING_MODE,n.APOS_STRING_MODE,c,o]}}},d={contains:[n.NUMBER_MODE,n.QUOTE_STRING_MODE,n.APOS_STRING_MODE,{begin:/as\s+\|/,keywords:{keyword:"as"},end:/\|/,contains:[{begin:/\w+/}]},m,c,o],returnEnd:!0},g=n.inherit(l,{className:"name",keywords:a,starts:n.inherit(d,{end:/\)/})});o.contains=[g];const u=n.inherit(l,{keywords:a,className:"name",starts:n.inherit(d,{end:/}}/})}),b=n.inherit(l,{keywords:a,className:"name"}),h=n.inherit(l,{className:"name",keywords:a,starts:n.inherit(d,{end:/}}/})});return{name:"Handlebars",aliases:["hbs","html.hbs","html.handlebars","htmlbars"],case_insensitive:!0,subLanguage:"xml",contains:[{begin:/\\\{\{/,skip:!0},{begin:/\\\\(?=\{\{)/,skip:!0},n.COMMENT(/\{\{!--/,/--\}\}/),n.COMMENT(/\{\{!/,/\}\}/),{className:"template-tag",begin:/\{\{\{\{(?!\/)/,end:/\}\}\}\}/,contains:[u],starts:{end:/\{\{\{\{\//,returnEnd:!0,subLanguage:"xml"}},{className:"template-tag",begin:/\{\{\{\{\//,end:/\}\}\}\}/,contains:[b]},{className:"template-tag",begin:/\{\{#/,end:/\}\}/,contains:[u]},{className:"template-tag",begin:/\{\{(?=else\}\})/,end:/\}\}/,keywords:"else"},{className:"template-tag",begin:/\{\{\//,end:/\}\}/,contains:[b]},{className:"template-variable",begin:/\{\{\{/,end:/\}\}\}/,contains:[h]},{className:"template-variable",begin:/\{\{/,end:/\}\}/,contains:[h]}]}}}());hljs.registerLanguage("rust",function(){"use strict";return function(e){var n="([ui](8|16|32|64|128|size)|f(32|64))?",t="drop i8 i16 i32 i64 i128 isize u8 u16 u32 u64 u128 usize f32 f64 str char bool Box Option Result String Vec Copy Send Sized Sync Drop Fn FnMut FnOnce ToOwned Clone Debug PartialEq PartialOrd Eq Ord AsRef AsMut Into From Default Iterator Extend IntoIterator DoubleEndedIterator ExactSizeIterator SliceConcatExt ToString assert! assert_eq! bitflags! bytes! cfg! col! concat! concat_idents! debug_assert! debug_assert_eq! env! panic! file! format! format_args! include_bin! include_str! line! local_data_key! module_path! option_env! print! println! select! stringify! try! unimplemented! unreachable! vec! write! writeln! macro_rules! assert_ne! debug_assert_ne!";return{name:"Rust",aliases:["rs"],keywords:{$pattern:e.IDENT_RE+"!?",keyword:"abstract as async await become box break const continue crate do dyn else enum extern false final fn for if impl in let loop macro match mod move mut override priv pub ref return self Self static struct super trait true try type typeof unsafe unsized use virtual where while yield",literal:"true false Some None Ok Err",built_in:t},illegal:""}]}}}());hljs.registerLanguage("cpp",function(){"use strict";return function(e){var t=e.getLanguage("c-like").rawDefinition();return t.disableAutodetect=!1,t.name="C++",t.aliases=["cc","c++","h++","hpp","hh","hxx","cxx"],t}}());hljs.registerLanguage("ini",function(){"use strict";function e(e){return e?"string"==typeof e?e:e.source:null}function n(...n){return n.map(n=>e(n)).join("")}return function(a){var s={className:"number",relevance:0,variants:[{begin:/([\+\-]+)?[\d]+_[\d_]+/},{begin:a.NUMBER_RE}]},i=a.COMMENT();i.variants=[{begin:/;/,end:/$/},{begin:/#/,end:/$/}];var t={className:"variable",variants:[{begin:/\$[\w\d"][\w\d_]*/},{begin:/\$\{(.*?)}/}]},r={className:"literal",begin:/\bon|off|true|false|yes|no\b/},l={className:"string",contains:[a.BACKSLASH_ESCAPE],variants:[{begin:"'''",end:"'''",relevance:10},{begin:'"""',end:'"""',relevance:10},{begin:'"',end:'"'},{begin:"'",end:"'"}]},c={begin:/\[/,end:/\]/,contains:[i,r,t,l,s,"self"],relevance:0},g="("+[/[A-Za-z0-9_-]+/,/"(\\"|[^"])*"/,/'[^']*'/].map(n=>e(n)).join("|")+")";return{name:"TOML, also INI",aliases:["toml"],case_insensitive:!0,illegal:/\S/,contains:[i,{className:"section",begin:/\[+/,end:/\]+/},{begin:n(g,"(\\s*\\.\\s*",g,")*",n("(?=",/\s*=\s*[^#\s]/,")")),className:"attr",starts:{end:/$/,contains:[i,c,r,t,l,s]}}]}}}());hljs.registerLanguage("objectivec",function(){"use strict";return function(e){var n=/[a-zA-Z@][a-zA-Z0-9_]*/,_={$pattern:n,keyword:"@interface @class @protocol @implementation"};return{name:"Objective-C",aliases:["mm","objc","obj-c"],keywords:{$pattern:n,keyword:"int float while char export sizeof typedef const struct for union unsigned long volatile static bool mutable if do return goto void enum else break extern asm case short default double register explicit signed typename this switch continue wchar_t inline readonly assign readwrite self @synchronized id typeof nonatomic super unichar IBOutlet IBAction strong weak copy in out inout bycopy byref oneway __strong __weak __block __autoreleasing @private @protected @public @try @property @end @throw @catch @finally @autoreleasepool @synthesize @dynamic @selector @optional @required @encode @package @import @defs @compatibility_alias __bridge __bridge_transfer __bridge_retained __bridge_retain __covariant __contravariant __kindof _Nonnull _Nullable _Null_unspecified __FUNCTION__ __PRETTY_FUNCTION__ __attribute__ getter setter retain unsafe_unretained nonnull nullable null_unspecified null_resettable class instancetype NS_DESIGNATED_INITIALIZER NS_UNAVAILABLE NS_REQUIRES_SUPER NS_RETURNS_INNER_POINTER NS_INLINE NS_AVAILABLE NS_DEPRECATED NS_ENUM NS_OPTIONS NS_SWIFT_UNAVAILABLE NS_ASSUME_NONNULL_BEGIN NS_ASSUME_NONNULL_END NS_REFINED_FOR_SWIFT NS_SWIFT_NAME NS_SWIFT_NOTHROW NS_DURING NS_HANDLER NS_ENDHANDLER NS_VALUERETURN NS_VOIDRETURN",literal:"false true FALSE TRUE nil YES NO NULL",built_in:"BOOL dispatch_once_t dispatch_queue_t dispatch_sync dispatch_async dispatch_once"},illegal:"/,end:/$/,illegal:"\\n"},e.C_LINE_COMMENT_MODE,e.C_BLOCK_COMMENT_MODE]},{className:"class",begin:"("+_.keyword.split(" ").join("|")+")\\b",end:"({|$)",excludeEnd:!0,keywords:_,contains:[e.UNDERSCORE_TITLE_MODE]},{begin:"\\."+e.UNDERSCORE_IDENT_RE,relevance:0}]}}}());hljs.registerLanguage("apache",function(){"use strict";return function(e){var n={className:"number",begin:"\\d{1,3}\\.\\d{1,3}\\.\\d{1,3}\\.\\d{1,3}(:\\d{1,5})?"};return{name:"Apache config",aliases:["apacheconf"],case_insensitive:!0,contains:[e.HASH_COMMENT_MODE,{className:"section",begin:"",contains:[n,{className:"number",begin:":\\d{1,5}"},e.inherit(e.QUOTE_STRING_MODE,{relevance:0})]},{className:"attribute",begin:/\w+/,relevance:0,keywords:{nomarkup:"order deny allow setenv rewriterule rewriteengine rewritecond documentroot sethandler errordocument loadmodule options header listen serverroot servername"},starts:{end:/$/,relevance:0,keywords:{literal:"on off all deny allow"},contains:[{className:"meta",begin:"\\s\\[",end:"\\]$"},{className:"variable",begin:"[\\$%]\\{",end:"\\}",contains:["self",{className:"number",begin:"[\\$%]\\d+"}]},n,{className:"number",begin:"\\d+"},e.QUOTE_STRING_MODE]}}],illegal:/\S/}}}());hljs.registerLanguage("java",function(){"use strict";function e(e){return e?"string"==typeof e?e:e.source:null}function n(e){return a("(",e,")?")}function a(...n){return n.map(n=>e(n)).join("")}function s(...n){return"("+n.map(n=>e(n)).join("|")+")"}return function(e){var t="false synchronized int abstract float private char boolean var static null if const for true while long strictfp finally protected import native final void enum else break transient catch instanceof byte super volatile case assert short package default double public try this switch continue throws protected public private module requires exports do",i={className:"meta",begin:"@[À-ʸa-zA-Z_$][À-ʸa-zA-Z_$0-9]*",contains:[{begin:/\(/,end:/\)/,contains:["self"]}]},r=e=>a("[",e,"]+([",e,"_]*[",e,"]+)?"),c={className:"number",variants:[{begin:`\\b(0[bB]${r("01")})[lL]?`},{begin:`\\b(0${r("0-7")})[dDfFlL]?`},{begin:a(/\b0[xX]/,s(a(r("a-fA-F0-9"),/\./,r("a-fA-F0-9")),a(r("a-fA-F0-9"),/\.?/),a(/\./,r("a-fA-F0-9"))),/([pP][+-]?(\d+))?/,/[fFdDlL]?/)},{begin:a(/\b/,s(a(/\d*\./,r("\\d")),r("\\d")),/[eE][+-]?[\d]+[dDfF]?/)},{begin:a(/\b/,r(/\d/),n(/\.?/),n(r(/\d/)),/[dDfFlL]?/)}],relevance:0};return{name:"Java",aliases:["jsp"],keywords:t,illegal:/<\/|#/,contains:[e.COMMENT("/\\*\\*","\\*/",{relevance:0,contains:[{begin:/\w+@/,relevance:0},{className:"doctag",begin:"@[A-Za-z]+"}]}),e.C_LINE_COMMENT_MODE,e.C_BLOCK_COMMENT_MODE,e.APOS_STRING_MODE,e.QUOTE_STRING_MODE,{className:"class",beginKeywords:"class interface",end:/[{;=]/,excludeEnd:!0,keywords:"class interface",illegal:/[:"\[\]]/,contains:[{beginKeywords:"extends implements"},e.UNDERSCORE_TITLE_MODE]},{beginKeywords:"new throw return else",relevance:0},{className:"function",begin:"([À-ʸa-zA-Z_$][À-ʸa-zA-Z_$0-9]*(<[À-ʸa-zA-Z_$][À-ʸa-zA-Z_$0-9]*(\\s*,\\s*[À-ʸa-zA-Z_$][À-ʸa-zA-Z_$0-9]*)*>)?\\s+)+"+e.UNDERSCORE_IDENT_RE+"\\s*\\(",returnBegin:!0,end:/[{;=]/,excludeEnd:!0,keywords:t,contains:[{begin:e.UNDERSCORE_IDENT_RE+"\\s*\\(",returnBegin:!0,relevance:0,contains:[e.UNDERSCORE_TITLE_MODE]},{className:"params",begin:/\(/,end:/\)/,keywords:t,relevance:0,contains:[i,e.APOS_STRING_MODE,e.QUOTE_STRING_MODE,e.C_NUMBER_MODE,e.C_BLOCK_COMMENT_MODE]},e.C_LINE_COMMENT_MODE,e.C_BLOCK_COMMENT_MODE]},c,i]}}}());hljs.registerLanguage("x86asm",function(){"use strict";return function(s){return{name:"Intel x86 Assembly",case_insensitive:!0,keywords:{$pattern:"[.%]?"+s.IDENT_RE,keyword:"lock rep repe repz repne repnz xaquire xrelease bnd nobnd aaa aad aam aas adc add and arpl bb0_reset bb1_reset bound bsf bsr bswap bt btc btr bts call cbw cdq cdqe clc cld cli clts cmc cmp cmpsb cmpsd cmpsq cmpsw cmpxchg cmpxchg486 cmpxchg8b cmpxchg16b cpuid cpu_read cpu_write cqo cwd cwde daa das dec div dmint emms enter equ f2xm1 fabs fadd faddp fbld fbstp fchs fclex fcmovb fcmovbe fcmove fcmovnb fcmovnbe fcmovne fcmovnu fcmovu fcom fcomi fcomip fcomp fcompp fcos fdecstp fdisi fdiv fdivp fdivr fdivrp femms feni ffree ffreep fiadd ficom ficomp fidiv fidivr fild fimul fincstp finit fist fistp fisttp fisub fisubr fld fld1 fldcw fldenv fldl2e fldl2t fldlg2 fldln2 fldpi fldz fmul fmulp fnclex fndisi fneni fninit fnop fnsave fnstcw fnstenv fnstsw fpatan fprem fprem1 fptan frndint frstor fsave fscale fsetpm fsin fsincos fsqrt fst fstcw fstenv fstp fstsw fsub fsubp fsubr fsubrp ftst fucom fucomi fucomip fucomp fucompp fxam fxch fxtract fyl2x fyl2xp1 hlt ibts icebp idiv imul in inc incbin insb insd insw int int01 int1 int03 int3 into invd invpcid invlpg invlpga iret iretd iretq iretw jcxz jecxz jrcxz jmp jmpe lahf lar lds lea leave les lfence lfs lgdt lgs lidt lldt lmsw loadall loadall286 lodsb lodsd lodsq lodsw loop loope loopne loopnz loopz lsl lss ltr mfence monitor mov movd movq movsb movsd movsq movsw movsx movsxd movzx mul mwait neg nop not or out outsb outsd outsw packssdw packsswb packuswb paddb paddd paddsb paddsiw paddsw paddusb paddusw paddw pand pandn pause paveb pavgusb pcmpeqb pcmpeqd pcmpeqw pcmpgtb pcmpgtd pcmpgtw pdistib pf2id pfacc pfadd pfcmpeq pfcmpge pfcmpgt pfmax pfmin pfmul pfrcp pfrcpit1 pfrcpit2 pfrsqit1 pfrsqrt pfsub pfsubr pi2fd pmachriw pmaddwd pmagw pmulhriw pmulhrwa pmulhrwc pmulhw pmullw pmvgezb pmvlzb pmvnzb pmvzb pop popa popad popaw popf popfd popfq popfw por prefetch prefetchw pslld psllq psllw psrad psraw psrld psrlq psrlw psubb psubd psubsb psubsiw psubsw psubusb psubusw psubw punpckhbw punpckhdq punpckhwd punpcklbw punpckldq punpcklwd push pusha pushad pushaw pushf pushfd pushfq pushfw pxor rcl rcr rdshr rdmsr rdpmc rdtsc rdtscp ret retf retn rol ror rdm rsdc rsldt rsm rsts sahf sal salc sar sbb scasb scasd scasq scasw sfence sgdt shl shld shr shrd sidt sldt skinit smi smint smintold smsw stc std sti stosb stosd stosq stosw str sub svdc svldt svts swapgs syscall sysenter sysexit sysret test ud0 ud1 ud2b ud2 ud2a umov verr verw fwait wbinvd wrshr wrmsr xadd xbts xchg xlatb xlat xor cmove cmovz cmovne cmovnz cmova cmovnbe cmovae cmovnb cmovb cmovnae cmovbe cmovna cmovg cmovnle cmovge cmovnl cmovl cmovnge cmovle cmovng cmovc cmovnc cmovo cmovno cmovs cmovns cmovp cmovpe cmovnp cmovpo je jz jne jnz ja jnbe jae jnb jb jnae jbe jna jg jnle jge jnl jl jnge jle jng jc jnc jo jno js jns jpo jnp jpe jp sete setz setne setnz seta setnbe setae setnb setnc setb setnae setcset setbe setna setg setnle setge setnl setl setnge setle setng sets setns seto setno setpe setp setpo setnp addps addss andnps andps cmpeqps cmpeqss cmpleps cmpless cmpltps cmpltss cmpneqps cmpneqss cmpnleps cmpnless cmpnltps cmpnltss cmpordps cmpordss cmpunordps cmpunordss cmpps cmpss comiss cvtpi2ps cvtps2pi cvtsi2ss cvtss2si cvttps2pi cvttss2si divps divss ldmxcsr maxps maxss minps minss movaps movhps movlhps movlps movhlps movmskps movntps movss movups mulps mulss orps rcpps rcpss rsqrtps rsqrtss shufps sqrtps sqrtss stmxcsr subps subss ucomiss unpckhps unpcklps xorps fxrstor fxrstor64 fxsave fxsave64 xgetbv xsetbv xsave xsave64 xsaveopt xsaveopt64 xrstor xrstor64 prefetchnta prefetcht0 prefetcht1 prefetcht2 maskmovq movntq pavgb pavgw pextrw pinsrw pmaxsw pmaxub pminsw pminub pmovmskb pmulhuw psadbw pshufw pf2iw pfnacc pfpnacc pi2fw pswapd maskmovdqu clflush movntdq movnti movntpd movdqa movdqu movdq2q movq2dq paddq pmuludq pshufd pshufhw pshuflw pslldq psrldq psubq punpckhqdq punpcklqdq addpd addsd andnpd andpd cmpeqpd cmpeqsd cmplepd cmplesd cmpltpd cmpltsd cmpneqpd cmpneqsd cmpnlepd cmpnlesd cmpnltpd cmpnltsd cmpordpd cmpordsd cmpunordpd cmpunordsd cmppd comisd cvtdq2pd cvtdq2ps cvtpd2dq cvtpd2pi cvtpd2ps cvtpi2pd cvtps2dq cvtps2pd cvtsd2si cvtsd2ss cvtsi2sd cvtss2sd cvttpd2pi cvttpd2dq cvttps2dq cvttsd2si divpd divsd maxpd maxsd minpd minsd movapd movhpd movlpd movmskpd movupd mulpd mulsd orpd shufpd sqrtpd sqrtsd subpd subsd ucomisd unpckhpd unpcklpd xorpd addsubpd addsubps haddpd haddps hsubpd hsubps lddqu movddup movshdup movsldup clgi stgi vmcall vmclear vmfunc vmlaunch vmload vmmcall vmptrld vmptrst vmread vmresume vmrun vmsave vmwrite vmxoff vmxon invept invvpid pabsb pabsw pabsd palignr phaddw phaddd phaddsw phsubw phsubd phsubsw pmaddubsw pmulhrsw pshufb psignb psignw psignd extrq insertq movntsd movntss lzcnt blendpd blendps blendvpd blendvps dppd dpps extractps insertps movntdqa mpsadbw packusdw pblendvb pblendw pcmpeqq pextrb pextrd pextrq phminposuw pinsrb pinsrd pinsrq pmaxsb pmaxsd pmaxud pmaxuw pminsb pminsd pminud pminuw pmovsxbw pmovsxbd pmovsxbq pmovsxwd pmovsxwq pmovsxdq pmovzxbw pmovzxbd pmovzxbq pmovzxwd pmovzxwq pmovzxdq pmuldq pmulld ptest roundpd roundps roundsd roundss crc32 pcmpestri pcmpestrm pcmpistri pcmpistrm pcmpgtq popcnt getsec pfrcpv pfrsqrtv movbe aesenc aesenclast aesdec aesdeclast aesimc aeskeygenassist vaesenc vaesenclast vaesdec vaesdeclast vaesimc vaeskeygenassist vaddpd vaddps vaddsd vaddss vaddsubpd vaddsubps vandpd vandps vandnpd vandnps vblendpd vblendps vblendvpd vblendvps vbroadcastss vbroadcastsd vbroadcastf128 vcmpeq_ospd vcmpeqpd vcmplt_ospd vcmpltpd vcmple_ospd vcmplepd vcmpunord_qpd vcmpunordpd vcmpneq_uqpd vcmpneqpd vcmpnlt_uspd vcmpnltpd vcmpnle_uspd vcmpnlepd vcmpord_qpd vcmpordpd vcmpeq_uqpd vcmpnge_uspd vcmpngepd vcmpngt_uspd vcmpngtpd vcmpfalse_oqpd vcmpfalsepd vcmpneq_oqpd vcmpge_ospd vcmpgepd vcmpgt_ospd vcmpgtpd vcmptrue_uqpd vcmptruepd vcmplt_oqpd vcmple_oqpd vcmpunord_spd vcmpneq_uspd vcmpnlt_uqpd vcmpnle_uqpd vcmpord_spd vcmpeq_uspd vcmpnge_uqpd vcmpngt_uqpd vcmpfalse_ospd vcmpneq_ospd vcmpge_oqpd vcmpgt_oqpd vcmptrue_uspd vcmppd vcmpeq_osps vcmpeqps vcmplt_osps vcmpltps vcmple_osps vcmpleps vcmpunord_qps vcmpunordps vcmpneq_uqps vcmpneqps vcmpnlt_usps vcmpnltps vcmpnle_usps vcmpnleps vcmpord_qps vcmpordps vcmpeq_uqps vcmpnge_usps vcmpngeps vcmpngt_usps vcmpngtps vcmpfalse_oqps vcmpfalseps vcmpneq_oqps vcmpge_osps vcmpgeps vcmpgt_osps vcmpgtps vcmptrue_uqps vcmptrueps vcmplt_oqps vcmple_oqps vcmpunord_sps vcmpneq_usps vcmpnlt_uqps vcmpnle_uqps vcmpord_sps vcmpeq_usps vcmpnge_uqps vcmpngt_uqps vcmpfalse_osps vcmpneq_osps vcmpge_oqps vcmpgt_oqps vcmptrue_usps vcmpps vcmpeq_ossd vcmpeqsd vcmplt_ossd vcmpltsd vcmple_ossd vcmplesd vcmpunord_qsd vcmpunordsd vcmpneq_uqsd vcmpneqsd vcmpnlt_ussd vcmpnltsd vcmpnle_ussd vcmpnlesd vcmpord_qsd vcmpordsd vcmpeq_uqsd vcmpnge_ussd vcmpngesd vcmpngt_ussd vcmpngtsd vcmpfalse_oqsd vcmpfalsesd vcmpneq_oqsd vcmpge_ossd vcmpgesd vcmpgt_ossd vcmpgtsd vcmptrue_uqsd vcmptruesd vcmplt_oqsd vcmple_oqsd vcmpunord_ssd vcmpneq_ussd vcmpnlt_uqsd vcmpnle_uqsd vcmpord_ssd vcmpeq_ussd vcmpnge_uqsd vcmpngt_uqsd vcmpfalse_ossd vcmpneq_ossd vcmpge_oqsd vcmpgt_oqsd vcmptrue_ussd vcmpsd vcmpeq_osss vcmpeqss vcmplt_osss vcmpltss vcmple_osss vcmpless vcmpunord_qss vcmpunordss vcmpneq_uqss vcmpneqss vcmpnlt_usss vcmpnltss vcmpnle_usss vcmpnless vcmpord_qss vcmpordss vcmpeq_uqss vcmpnge_usss vcmpngess vcmpngt_usss vcmpngtss vcmpfalse_oqss vcmpfalsess vcmpneq_oqss vcmpge_osss vcmpgess vcmpgt_osss vcmpgtss vcmptrue_uqss vcmptruess vcmplt_oqss vcmple_oqss vcmpunord_sss vcmpneq_usss vcmpnlt_uqss vcmpnle_uqss vcmpord_sss vcmpeq_usss vcmpnge_uqss vcmpngt_uqss vcmpfalse_osss vcmpneq_osss vcmpge_oqss vcmpgt_oqss vcmptrue_usss vcmpss vcomisd vcomiss vcvtdq2pd vcvtdq2ps vcvtpd2dq vcvtpd2ps vcvtps2dq vcvtps2pd vcvtsd2si vcvtsd2ss vcvtsi2sd vcvtsi2ss vcvtss2sd vcvtss2si vcvttpd2dq vcvttps2dq vcvttsd2si vcvttss2si vdivpd vdivps vdivsd vdivss vdppd vdpps vextractf128 vextractps vhaddpd vhaddps vhsubpd vhsubps vinsertf128 vinsertps vlddqu vldqqu vldmxcsr vmaskmovdqu vmaskmovps vmaskmovpd vmaxpd vmaxps vmaxsd vmaxss vminpd vminps vminsd vminss vmovapd vmovaps vmovd vmovq vmovddup vmovdqa vmovqqa vmovdqu vmovqqu vmovhlps vmovhpd vmovhps vmovlhps vmovlpd vmovlps vmovmskpd vmovmskps vmovntdq vmovntqq vmovntdqa vmovntpd vmovntps vmovsd vmovshdup vmovsldup vmovss vmovupd vmovups vmpsadbw vmulpd vmulps vmulsd vmulss vorpd vorps vpabsb vpabsw vpabsd vpacksswb vpackssdw vpackuswb vpackusdw vpaddb vpaddw vpaddd vpaddq vpaddsb vpaddsw vpaddusb vpaddusw vpalignr vpand vpandn vpavgb vpavgw vpblendvb vpblendw vpcmpestri vpcmpestrm vpcmpistri vpcmpistrm vpcmpeqb vpcmpeqw vpcmpeqd vpcmpeqq vpcmpgtb vpcmpgtw vpcmpgtd vpcmpgtq vpermilpd vpermilps vperm2f128 vpextrb vpextrw vpextrd vpextrq vphaddw vphaddd vphaddsw vphminposuw vphsubw vphsubd vphsubsw vpinsrb vpinsrw vpinsrd vpinsrq vpmaddwd vpmaddubsw vpmaxsb vpmaxsw vpmaxsd vpmaxub vpmaxuw vpmaxud vpminsb vpminsw vpminsd vpminub vpminuw vpminud vpmovmskb vpmovsxbw vpmovsxbd vpmovsxbq vpmovsxwd vpmovsxwq vpmovsxdq vpmovzxbw vpmovzxbd vpmovzxbq vpmovzxwd vpmovzxwq vpmovzxdq vpmulhuw vpmulhrsw vpmulhw vpmullw vpmulld vpmuludq vpmuldq vpor vpsadbw vpshufb vpshufd vpshufhw vpshuflw vpsignb vpsignw vpsignd vpslldq vpsrldq vpsllw vpslld vpsllq vpsraw vpsrad vpsrlw vpsrld vpsrlq vptest vpsubb vpsubw vpsubd vpsubq vpsubsb vpsubsw vpsubusb vpsubusw vpunpckhbw vpunpckhwd vpunpckhdq vpunpckhqdq vpunpcklbw vpunpcklwd vpunpckldq vpunpcklqdq vpxor vrcpps vrcpss vrsqrtps vrsqrtss vroundpd vroundps vroundsd vroundss vshufpd vshufps vsqrtpd vsqrtps vsqrtsd vsqrtss vstmxcsr vsubpd vsubps vsubsd vsubss vtestps vtestpd vucomisd vucomiss vunpckhpd vunpckhps vunpcklpd vunpcklps vxorpd vxorps vzeroall vzeroupper pclmullqlqdq pclmulhqlqdq pclmullqhqdq pclmulhqhqdq pclmulqdq vpclmullqlqdq vpclmulhqlqdq vpclmullqhqdq vpclmulhqhqdq vpclmulqdq vfmadd132ps vfmadd132pd vfmadd312ps vfmadd312pd vfmadd213ps vfmadd213pd vfmadd123ps vfmadd123pd vfmadd231ps vfmadd231pd vfmadd321ps vfmadd321pd vfmaddsub132ps vfmaddsub132pd vfmaddsub312ps vfmaddsub312pd vfmaddsub213ps vfmaddsub213pd vfmaddsub123ps vfmaddsub123pd vfmaddsub231ps vfmaddsub231pd vfmaddsub321ps vfmaddsub321pd vfmsub132ps vfmsub132pd vfmsub312ps vfmsub312pd vfmsub213ps vfmsub213pd vfmsub123ps vfmsub123pd vfmsub231ps vfmsub231pd vfmsub321ps vfmsub321pd vfmsubadd132ps vfmsubadd132pd vfmsubadd312ps vfmsubadd312pd vfmsubadd213ps vfmsubadd213pd vfmsubadd123ps vfmsubadd123pd vfmsubadd231ps vfmsubadd231pd vfmsubadd321ps vfmsubadd321pd vfnmadd132ps vfnmadd132pd vfnmadd312ps vfnmadd312pd vfnmadd213ps vfnmadd213pd vfnmadd123ps vfnmadd123pd vfnmadd231ps vfnmadd231pd vfnmadd321ps vfnmadd321pd vfnmsub132ps vfnmsub132pd vfnmsub312ps vfnmsub312pd vfnmsub213ps vfnmsub213pd vfnmsub123ps vfnmsub123pd vfnmsub231ps vfnmsub231pd vfnmsub321ps vfnmsub321pd vfmadd132ss vfmadd132sd vfmadd312ss vfmadd312sd vfmadd213ss vfmadd213sd vfmadd123ss vfmadd123sd vfmadd231ss vfmadd231sd vfmadd321ss vfmadd321sd vfmsub132ss vfmsub132sd vfmsub312ss vfmsub312sd vfmsub213ss vfmsub213sd vfmsub123ss vfmsub123sd vfmsub231ss vfmsub231sd vfmsub321ss vfmsub321sd vfnmadd132ss vfnmadd132sd vfnmadd312ss vfnmadd312sd vfnmadd213ss vfnmadd213sd vfnmadd123ss vfnmadd123sd vfnmadd231ss vfnmadd231sd vfnmadd321ss vfnmadd321sd vfnmsub132ss vfnmsub132sd vfnmsub312ss vfnmsub312sd vfnmsub213ss vfnmsub213sd vfnmsub123ss vfnmsub123sd vfnmsub231ss vfnmsub231sd vfnmsub321ss vfnmsub321sd rdfsbase rdgsbase rdrand wrfsbase wrgsbase vcvtph2ps vcvtps2ph adcx adox rdseed clac stac xstore xcryptecb xcryptcbc xcryptctr xcryptcfb xcryptofb montmul xsha1 xsha256 llwpcb slwpcb lwpval lwpins vfmaddpd vfmaddps vfmaddsd vfmaddss vfmaddsubpd vfmaddsubps vfmsubaddpd vfmsubaddps vfmsubpd vfmsubps vfmsubsd vfmsubss vfnmaddpd vfnmaddps vfnmaddsd vfnmaddss vfnmsubpd vfnmsubps vfnmsubsd vfnmsubss vfrczpd vfrczps vfrczsd vfrczss vpcmov vpcomb vpcomd vpcomq vpcomub vpcomud vpcomuq vpcomuw vpcomw vphaddbd vphaddbq vphaddbw vphadddq vphaddubd vphaddubq vphaddubw vphaddudq vphadduwd vphadduwq vphaddwd vphaddwq vphsubbw vphsubdq vphsubwd vpmacsdd vpmacsdqh vpmacsdql vpmacssdd vpmacssdqh vpmacssdql vpmacsswd vpmacssww vpmacswd vpmacsww vpmadcsswd vpmadcswd vpperm vprotb vprotd vprotq vprotw vpshab vpshad vpshaq vpshaw vpshlb vpshld vpshlq vpshlw vbroadcasti128 vpblendd vpbroadcastb vpbroadcastw vpbroadcastd vpbroadcastq vpermd vpermpd vpermps vpermq vperm2i128 vextracti128 vinserti128 vpmaskmovd vpmaskmovq vpsllvd vpsllvq vpsravd vpsrlvd vpsrlvq vgatherdpd vgatherqpd vgatherdps vgatherqps vpgatherdd vpgatherqd vpgatherdq vpgatherqq xabort xbegin xend xtest andn bextr blci blcic blsi blsic blcfill blsfill blcmsk blsmsk blsr blcs bzhi mulx pdep pext rorx sarx shlx shrx tzcnt tzmsk t1mskc valignd valignq vblendmpd vblendmps vbroadcastf32x4 vbroadcastf64x4 vbroadcasti32x4 vbroadcasti64x4 vcompresspd vcompressps vcvtpd2udq vcvtps2udq vcvtsd2usi vcvtss2usi vcvttpd2udq vcvttps2udq vcvttsd2usi vcvttss2usi vcvtudq2pd vcvtudq2ps vcvtusi2sd vcvtusi2ss vexpandpd vexpandps vextractf32x4 vextractf64x4 vextracti32x4 vextracti64x4 vfixupimmpd vfixupimmps vfixupimmsd vfixupimmss vgetexppd vgetexpps vgetexpsd vgetexpss vgetmantpd vgetmantps vgetmantsd vgetmantss vinsertf32x4 vinsertf64x4 vinserti32x4 vinserti64x4 vmovdqa32 vmovdqa64 vmovdqu32 vmovdqu64 vpabsq vpandd vpandnd vpandnq vpandq vpblendmd vpblendmq vpcmpltd vpcmpled vpcmpneqd vpcmpnltd vpcmpnled vpcmpd vpcmpltq vpcmpleq vpcmpneqq vpcmpnltq vpcmpnleq vpcmpq vpcmpequd vpcmpltud vpcmpleud vpcmpnequd vpcmpnltud vpcmpnleud vpcmpud vpcmpequq vpcmpltuq vpcmpleuq vpcmpnequq vpcmpnltuq vpcmpnleuq vpcmpuq vpcompressd vpcompressq vpermi2d vpermi2pd vpermi2ps vpermi2q vpermt2d vpermt2pd vpermt2ps vpermt2q vpexpandd vpexpandq vpmaxsq vpmaxuq vpminsq vpminuq vpmovdb vpmovdw vpmovqb vpmovqd vpmovqw vpmovsdb vpmovsdw vpmovsqb vpmovsqd vpmovsqw vpmovusdb vpmovusdw vpmovusqb vpmovusqd vpmovusqw vpord vporq vprold vprolq vprolvd vprolvq vprord vprorq vprorvd vprorvq vpscatterdd vpscatterdq vpscatterqd vpscatterqq vpsraq vpsravq vpternlogd vpternlogq vptestmd vptestmq vptestnmd vptestnmq vpxord vpxorq vrcp14pd vrcp14ps vrcp14sd vrcp14ss vrndscalepd vrndscaleps vrndscalesd vrndscaless vrsqrt14pd vrsqrt14ps vrsqrt14sd vrsqrt14ss vscalefpd vscalefps vscalefsd vscalefss vscatterdpd vscatterdps vscatterqpd vscatterqps vshuff32x4 vshuff64x2 vshufi32x4 vshufi64x2 kandnw kandw kmovw knotw kortestw korw kshiftlw kshiftrw kunpckbw kxnorw kxorw vpbroadcastmb2q vpbroadcastmw2d vpconflictd vpconflictq vplzcntd vplzcntq vexp2pd vexp2ps vrcp28pd vrcp28ps vrcp28sd vrcp28ss vrsqrt28pd vrsqrt28ps vrsqrt28sd vrsqrt28ss vgatherpf0dpd vgatherpf0dps vgatherpf0qpd vgatherpf0qps vgatherpf1dpd vgatherpf1dps vgatherpf1qpd vgatherpf1qps vscatterpf0dpd vscatterpf0dps vscatterpf0qpd vscatterpf0qps vscatterpf1dpd vscatterpf1dps vscatterpf1qpd vscatterpf1qps prefetchwt1 bndmk bndcl bndcu bndcn bndmov bndldx bndstx sha1rnds4 sha1nexte sha1msg1 sha1msg2 sha256rnds2 sha256msg1 sha256msg2 hint_nop0 hint_nop1 hint_nop2 hint_nop3 hint_nop4 hint_nop5 hint_nop6 hint_nop7 hint_nop8 hint_nop9 hint_nop10 hint_nop11 hint_nop12 hint_nop13 hint_nop14 hint_nop15 hint_nop16 hint_nop17 hint_nop18 hint_nop19 hint_nop20 hint_nop21 hint_nop22 hint_nop23 hint_nop24 hint_nop25 hint_nop26 hint_nop27 hint_nop28 hint_nop29 hint_nop30 hint_nop31 hint_nop32 hint_nop33 hint_nop34 hint_nop35 hint_nop36 hint_nop37 hint_nop38 hint_nop39 hint_nop40 hint_nop41 hint_nop42 hint_nop43 hint_nop44 hint_nop45 hint_nop46 hint_nop47 hint_nop48 hint_nop49 hint_nop50 hint_nop51 hint_nop52 hint_nop53 hint_nop54 hint_nop55 hint_nop56 hint_nop57 hint_nop58 hint_nop59 hint_nop60 hint_nop61 hint_nop62 hint_nop63",built_in:"ip eip rip al ah bl bh cl ch dl dh sil dil bpl spl r8b r9b r10b r11b r12b r13b r14b r15b ax bx cx dx si di bp sp r8w r9w r10w r11w r12w r13w r14w r15w eax ebx ecx edx esi edi ebp esp eip r8d r9d r10d r11d r12d r13d r14d r15d rax rbx rcx rdx rsi rdi rbp rsp r8 r9 r10 r11 r12 r13 r14 r15 cs ds es fs gs ss st st0 st1 st2 st3 st4 st5 st6 st7 mm0 mm1 mm2 mm3 mm4 mm5 mm6 mm7 xmm0 xmm1 xmm2 xmm3 xmm4 xmm5 xmm6 xmm7 xmm8 xmm9 xmm10 xmm11 xmm12 xmm13 xmm14 xmm15 xmm16 xmm17 xmm18 xmm19 xmm20 xmm21 xmm22 xmm23 xmm24 xmm25 xmm26 xmm27 xmm28 xmm29 xmm30 xmm31 ymm0 ymm1 ymm2 ymm3 ymm4 ymm5 ymm6 ymm7 ymm8 ymm9 ymm10 ymm11 ymm12 ymm13 ymm14 ymm15 ymm16 ymm17 ymm18 ymm19 ymm20 ymm21 ymm22 ymm23 ymm24 ymm25 ymm26 ymm27 ymm28 ymm29 ymm30 ymm31 zmm0 zmm1 zmm2 zmm3 zmm4 zmm5 zmm6 zmm7 zmm8 zmm9 zmm10 zmm11 zmm12 zmm13 zmm14 zmm15 zmm16 zmm17 zmm18 zmm19 zmm20 zmm21 zmm22 zmm23 zmm24 zmm25 zmm26 zmm27 zmm28 zmm29 zmm30 zmm31 k0 k1 k2 k3 k4 k5 k6 k7 bnd0 bnd1 bnd2 bnd3 cr0 cr1 cr2 cr3 cr4 cr8 dr0 dr1 dr2 dr3 dr8 tr3 tr4 tr5 tr6 tr7 r0 r1 r2 r3 r4 r5 r6 r7 r0b r1b r2b r3b r4b r5b r6b r7b r0w r1w r2w r3w r4w r5w r6w r7w r0d r1d r2d r3d r4d r5d r6d r7d r0h r1h r2h r3h r0l r1l r2l r3l r4l r5l r6l r7l r8l r9l r10l r11l r12l r13l r14l r15l db dw dd dq dt ddq do dy dz resb resw resd resq rest resdq reso resy resz incbin equ times byte word dword qword nosplit rel abs seg wrt strict near far a32 ptr",meta:"%define %xdefine %+ %undef %defstr %deftok %assign %strcat %strlen %substr %rotate %elif %else %endif %if %ifmacro %ifctx %ifidn %ifidni %ifid %ifnum %ifstr %iftoken %ifempty %ifenv %error %warning %fatal %rep %endrep %include %push %pop %repl %pathsearch %depend %use %arg %stacksize %local %line %comment %endcomment .nolist __FILE__ __LINE__ __SECT__ __BITS__ __OUTPUT_FORMAT__ __DATE__ __TIME__ __DATE_NUM__ __TIME_NUM__ __UTC_DATE__ __UTC_TIME__ __UTC_DATE_NUM__ __UTC_TIME_NUM__ __PASS__ struc endstruc istruc at iend align alignb sectalign daz nodaz up down zero default option assume public bits use16 use32 use64 default section segment absolute extern global common cpu float __utf16__ __utf16le__ __utf16be__ __utf32__ __utf32le__ __utf32be__ __float8__ __float16__ __float32__ __float64__ __float80m__ __float80e__ __float128l__ __float128h__ __Infinity__ __QNaN__ __SNaN__ Inf NaN QNaN SNaN float8 float16 float32 float64 float80m float80e float128l float128h __FLOAT_DAZ__ __FLOAT_ROUND__ __FLOAT__"},contains:[s.COMMENT(";","$",{relevance:0}),{className:"number",variants:[{begin:"\\b(?:([0-9][0-9_]*)?\\.[0-9_]*(?:[eE][+-]?[0-9_]+)?|(0[Xx])?[0-9][0-9_]*\\.?[0-9_]*(?:[pP](?:[+-]?[0-9_]+)?)?)\\b",relevance:0},{begin:"\\$[0-9][0-9A-Fa-f]*",relevance:0},{begin:"\\b(?:[0-9A-Fa-f][0-9A-Fa-f_]*[Hh]|[0-9][0-9_]*[DdTt]?|[0-7][0-7_]*[QqOo]|[0-1][0-1_]*[BbYy])\\b"},{begin:"\\b(?:0[Xx][0-9A-Fa-f_]+|0[DdTt][0-9_]+|0[QqOo][0-7_]+|0[BbYy][0-1_]+)\\b"}]},s.QUOTE_STRING_MODE,{className:"string",variants:[{begin:"'",end:"[^\\\\]'"},{begin:"`",end:"[^\\\\]`"}],relevance:0},{className:"symbol",variants:[{begin:"^\\s*[A-Za-z._?][A-Za-z0-9_$#@~.?]*(:|\\s+label)"},{begin:"^\\s*%%[A-Za-z0-9_$#@~.?]*:"}],relevance:0},{className:"subst",begin:"%[0-9]+",relevance:0},{className:"subst",begin:"%!S+",relevance:0},{className:"meta",begin:/^\s*\.[\w_-]+/}]}}}());hljs.registerLanguage("kotlin",function(){"use strict";return function(e){var n={keyword:"abstract as val var vararg get set class object open private protected public noinline crossinline dynamic final enum if else do while for when throw try catch finally import package is in fun override companion reified inline lateinit init interface annotation data sealed internal infix operator out by constructor super tailrec where const inner suspend typealias external expect actual trait volatile transient native default",built_in:"Byte Short Char Int Long Boolean Float Double Void Unit Nothing",literal:"true false null"},a={className:"symbol",begin:e.UNDERSCORE_IDENT_RE+"@"},i={className:"subst",begin:"\\${",end:"}",contains:[e.C_NUMBER_MODE]},s={className:"variable",begin:"\\$"+e.UNDERSCORE_IDENT_RE},t={className:"string",variants:[{begin:'"""',end:'"""(?=[^"])',contains:[s,i]},{begin:"'",end:"'",illegal:/\n/,contains:[e.BACKSLASH_ESCAPE]},{begin:'"',end:'"',illegal:/\n/,contains:[e.BACKSLASH_ESCAPE,s,i]}]};i.contains.push(t);var r={className:"meta",begin:"@(?:file|property|field|get|set|receiver|param|setparam|delegate)\\s*:(?:\\s*"+e.UNDERSCORE_IDENT_RE+")?"},l={className:"meta",begin:"@"+e.UNDERSCORE_IDENT_RE,contains:[{begin:/\(/,end:/\)/,contains:[e.inherit(t,{className:"meta-string"})]}]},c=e.COMMENT("/\\*","\\*/",{contains:[e.C_BLOCK_COMMENT_MODE]}),o={variants:[{className:"type",begin:e.UNDERSCORE_IDENT_RE},{begin:/\(/,end:/\)/,contains:[]}]},d=o;return d.variants[1].contains=[o],o.variants[1].contains=[d],{name:"Kotlin",aliases:["kt"],keywords:n,contains:[e.COMMENT("/\\*\\*","\\*/",{relevance:0,contains:[{className:"doctag",begin:"@[A-Za-z]+"}]}),e.C_LINE_COMMENT_MODE,c,{className:"keyword",begin:/\b(break|continue|return|this)\b/,starts:{contains:[{className:"symbol",begin:/@\w+/}]}},a,r,l,{className:"function",beginKeywords:"fun",end:"[(]|$",returnBegin:!0,excludeEnd:!0,keywords:n,illegal:/fun\s+(<.*>)?[^\s\(]+(\s+[^\s\(]+)\s*=/,relevance:5,contains:[{begin:e.UNDERSCORE_IDENT_RE+"\\s*\\(",returnBegin:!0,relevance:0,contains:[e.UNDERSCORE_TITLE_MODE]},{className:"type",begin://,keywords:"reified",relevance:0},{className:"params",begin:/\(/,end:/\)/,endsParent:!0,keywords:n,relevance:0,contains:[{begin:/:/,end:/[=,\/]/,endsWithParent:!0,contains:[o,e.C_LINE_COMMENT_MODE,c],relevance:0},e.C_LINE_COMMENT_MODE,c,r,l,t,e.C_NUMBER_MODE]},c]},{className:"class",beginKeywords:"class interface trait",end:/[:\{(]|$/,excludeEnd:!0,illegal:"extends implements",contains:[{beginKeywords:"public protected internal private constructor"},e.UNDERSCORE_TITLE_MODE,{className:"type",begin://,excludeBegin:!0,excludeEnd:!0,relevance:0},{className:"type",begin:/[,:]\s*/,end:/[<\(,]|$/,excludeBegin:!0,returnEnd:!0},r,l]},t,{className:"meta",begin:"^#!/usr/bin/env",end:"$",illegal:"\n"},{className:"number",begin:"\\b(0[bB]([01]+[01_]+[01]+|[01]+)|0[xX]([a-fA-F0-9]+[a-fA-F0-9_]+[a-fA-F0-9]+|[a-fA-F0-9]+)|(([\\d]+[\\d_]+[\\d]+|[\\d]+)(\\.([\\d]+[\\d_]+[\\d]+|[\\d]+))?|\\.([\\d]+[\\d_]+[\\d]+|[\\d]+))([eE][-+]?\\d+)?)[lLfF]?",relevance:0}]}}}());hljs.registerLanguage("armasm",function(){"use strict";return function(s){const e={variants:[s.COMMENT("^[ \\t]*(?=#)","$",{relevance:0,excludeBegin:!0}),s.COMMENT("[;@]","$",{relevance:0}),s.C_LINE_COMMENT_MODE,s.C_BLOCK_COMMENT_MODE]};return{name:"ARM Assembly",case_insensitive:!0,aliases:["arm"],keywords:{$pattern:"\\.?"+s.IDENT_RE,meta:".2byte .4byte .align .ascii .asciz .balign .byte .code .data .else .end .endif .endm .endr .equ .err .exitm .extern .global .hword .if .ifdef .ifndef .include .irp .long .macro .rept .req .section .set .skip .space .text .word .arm .thumb .code16 .code32 .force_thumb .thumb_func .ltorg ALIAS ALIGN ARM AREA ASSERT ATTR CN CODE CODE16 CODE32 COMMON CP DATA DCB DCD DCDU DCDO DCFD DCFDU DCI DCQ DCQU DCW DCWU DN ELIF ELSE END ENDFUNC ENDIF ENDP ENTRY EQU EXPORT EXPORTAS EXTERN FIELD FILL FUNCTION GBLA GBLL GBLS GET GLOBAL IF IMPORT INCBIN INCLUDE INFO KEEP LCLA LCLL LCLS LTORG MACRO MAP MEND MEXIT NOFP OPT PRESERVE8 PROC QN READONLY RELOC REQUIRE REQUIRE8 RLIST FN ROUT SETA SETL SETS SN SPACE SUBT THUMB THUMBX TTL WHILE WEND ",built_in:"r0 r1 r2 r3 r4 r5 r6 r7 r8 r9 r10 r11 r12 r13 r14 r15 pc lr sp ip sl sb fp a1 a2 a3 a4 v1 v2 v3 v4 v5 v6 v7 v8 f0 f1 f2 f3 f4 f5 f6 f7 p0 p1 p2 p3 p4 p5 p6 p7 p8 p9 p10 p11 p12 p13 p14 p15 c0 c1 c2 c3 c4 c5 c6 c7 c8 c9 c10 c11 c12 c13 c14 c15 q0 q1 q2 q3 q4 q5 q6 q7 q8 q9 q10 q11 q12 q13 q14 q15 cpsr_c cpsr_x cpsr_s cpsr_f cpsr_cx cpsr_cxs cpsr_xs cpsr_xsf cpsr_sf cpsr_cxsf spsr_c spsr_x spsr_s spsr_f spsr_cx spsr_cxs spsr_xs spsr_xsf spsr_sf spsr_cxsf s0 s1 s2 s3 s4 s5 s6 s7 s8 s9 s10 s11 s12 s13 s14 s15 s16 s17 s18 s19 s20 s21 s22 s23 s24 s25 s26 s27 s28 s29 s30 s31 d0 d1 d2 d3 d4 d5 d6 d7 d8 d9 d10 d11 d12 d13 d14 d15 d16 d17 d18 d19 d20 d21 d22 d23 d24 d25 d26 d27 d28 d29 d30 d31 {PC} {VAR} {TRUE} {FALSE} {OPT} {CONFIG} {ENDIAN} {CODESIZE} {CPU} {FPU} {ARCHITECTURE} {PCSTOREOFFSET} {ARMASM_VERSION} {INTER} {ROPI} {RWPI} {SWST} {NOSWST} . @"},contains:[{className:"keyword",begin:"\\b(adc|(qd?|sh?|u[qh]?)?add(8|16)?|usada?8|(q|sh?|u[qh]?)?(as|sa)x|and|adrl?|sbc|rs[bc]|asr|b[lx]?|blx|bxj|cbn?z|tb[bh]|bic|bfc|bfi|[su]bfx|bkpt|cdp2?|clz|clrex|cmp|cmn|cpsi[ed]|cps|setend|dbg|dmb|dsb|eor|isb|it[te]{0,3}|lsl|lsr|ror|rrx|ldm(([id][ab])|f[ds])?|ldr((s|ex)?[bhd])?|movt?|mvn|mra|mar|mul|[us]mull|smul[bwt][bt]|smu[as]d|smmul|smmla|mla|umlaal|smlal?([wbt][bt]|d)|mls|smlsl?[ds]|smc|svc|sev|mia([bt]{2}|ph)?|mrr?c2?|mcrr2?|mrs|msr|orr|orn|pkh(tb|bt)|rbit|rev(16|sh)?|sel|[su]sat(16)?|nop|pop|push|rfe([id][ab])?|stm([id][ab])?|str(ex)?[bhd]?|(qd?)?sub|(sh?|q|u[qh]?)?sub(8|16)|[su]xt(a?h|a?b(16)?)|srs([id][ab])?|swpb?|swi|smi|tst|teq|wfe|wfi|yield)(eq|ne|cs|cc|mi|pl|vs|vc|hi|ls|ge|lt|gt|le|al|hs|lo)?[sptrx]?(?=\\s)"},e,s.QUOTE_STRING_MODE,{className:"string",begin:"'",end:"[^\\\\]'",relevance:0},{className:"title",begin:"\\|",end:"\\|",illegal:"\\n",relevance:0},{className:"number",variants:[{begin:"[#$=]?0x[0-9a-f]+"},{begin:"[#$=]?0b[01]+"},{begin:"[#$=]\\d+"},{begin:"\\b\\d+"}],relevance:0},{className:"symbol",variants:[{begin:"^[ \\t]*[a-z_\\.\\$][a-z0-9_\\.\\$]+:"},{begin:"^[a-z_\\.\\$][a-z0-9_\\.\\$]+"},{begin:"[=#]\\w+"}],relevance:0}]}}}());hljs.registerLanguage("go",function(){"use strict";return function(e){var n={keyword:"break default func interface select case map struct chan else goto package switch const fallthrough if range type continue for import return var go defer bool byte complex64 complex128 float32 float64 int8 int16 int32 int64 string uint8 uint16 uint32 uint64 int uint uintptr rune",literal:"true false iota nil",built_in:"append cap close complex copy imag len make new panic print println real recover delete"};return{name:"Go",aliases:["golang"],keywords:n,illegal:">>|\.\.\.) /},i={className:"subst",begin:/\{/,end:/\}/,keywords:n,illegal:/#/},s={begin:/\{\{/,relevance:0},r={className:"string",contains:[e.BACKSLASH_ESCAPE],variants:[{begin:/(u|b)?r?'''/,end:/'''/,contains:[e.BACKSLASH_ESCAPE,a],relevance:10},{begin:/(u|b)?r?"""/,end:/"""/,contains:[e.BACKSLASH_ESCAPE,a],relevance:10},{begin:/(fr|rf|f)'''/,end:/'''/,contains:[e.BACKSLASH_ESCAPE,a,s,i]},{begin:/(fr|rf|f)"""/,end:/"""/,contains:[e.BACKSLASH_ESCAPE,a,s,i]},{begin:/(u|r|ur)'/,end:/'/,relevance:10},{begin:/(u|r|ur)"/,end:/"/,relevance:10},{begin:/(b|br)'/,end:/'/},{begin:/(b|br)"/,end:/"/},{begin:/(fr|rf|f)'/,end:/'/,contains:[e.BACKSLASH_ESCAPE,s,i]},{begin:/(fr|rf|f)"/,end:/"/,contains:[e.BACKSLASH_ESCAPE,s,i]},e.APOS_STRING_MODE,e.QUOTE_STRING_MODE]},l={className:"number",relevance:0,variants:[{begin:e.BINARY_NUMBER_RE+"[lLjJ]?"},{begin:"\\b(0o[0-7]+)[lLjJ]?"},{begin:e.C_NUMBER_RE+"[lLjJ]?"}]},t={className:"params",variants:[{begin:/\(\s*\)/,skip:!0,className:null},{begin:/\(/,end:/\)/,excludeBegin:!0,excludeEnd:!0,contains:["self",a,l,r,e.HASH_COMMENT_MODE]}]};return i.contains=[r,l,a],{name:"Python",aliases:["py","gyp","ipython"],keywords:n,illegal:/(<\/|->|\?)|=>/,contains:[a,l,{beginKeywords:"if",relevance:0},r,e.HASH_COMMENT_MODE,{variants:[{className:"function",beginKeywords:"def"},{className:"class",beginKeywords:"class"}],end:/:/,illegal:/[${=;\n,]/,contains:[e.UNDERSCORE_TITLE_MODE,t,{begin:/->/,endsWithParent:!0,keywords:"None"}]},{className:"meta",begin:/^[\t ]*@/,end:/$/},{begin:/\b(print|exec)\(/}]}}}());hljs.registerLanguage("shell",function(){"use strict";return function(s){return{name:"Shell Session",aliases:["console"],contains:[{className:"meta",begin:"^\\s{0,3}[/\\w\\d\\[\\]()@-]*[>%$#]",starts:{end:"$",subLanguage:"bash"}}]}}}());hljs.registerLanguage("scala",function(){"use strict";return function(e){var n={className:"subst",variants:[{begin:"\\$[A-Za-z0-9_]+"},{begin:"\\${",end:"}"}]},a={className:"string",variants:[{begin:'"',end:'"',illegal:"\\n",contains:[e.BACKSLASH_ESCAPE]},{begin:'"""',end:'"""',relevance:10},{begin:'[a-z]+"',end:'"',illegal:"\\n",contains:[e.BACKSLASH_ESCAPE,n]},{className:"string",begin:'[a-z]+"""',end:'"""',contains:[n],relevance:10}]},s={className:"type",begin:"\\b[A-Z][A-Za-z0-9_]*",relevance:0},t={className:"title",begin:/[^0-9\n\t "'(),.`{}\[\]:;][^\n\t "'(),.`{}\[\]:;]+|[^0-9\n\t "'(),.`{}\[\]:;=]/,relevance:0},i={className:"class",beginKeywords:"class object trait type",end:/[:={\[\n;]/,excludeEnd:!0,contains:[{beginKeywords:"extends with",relevance:10},{begin:/\[/,end:/\]/,excludeBegin:!0,excludeEnd:!0,relevance:0,contains:[s]},{className:"params",begin:/\(/,end:/\)/,excludeBegin:!0,excludeEnd:!0,relevance:0,contains:[s]},t]},l={className:"function",beginKeywords:"def",end:/[:={\[(\n;]/,excludeEnd:!0,contains:[t]};return{name:"Scala",keywords:{literal:"true false null",keyword:"type yield lazy override def with val var sealed abstract private trait object if forSome for while throw finally protected extends import final return else break new catch super class case package default try this match continue throws implicit"},contains:[e.C_LINE_COMMENT_MODE,e.C_BLOCK_COMMENT_MODE,a,{className:"symbol",begin:"'\\w[\\w\\d_]*(?!')"},s,l,i,e.C_NUMBER_MODE,{className:"meta",begin:"@[A-Za-z]+"}]}}}());hljs.registerLanguage("julia",function(){"use strict";return function(e){var r="[A-Za-z_\\u00A1-\\uFFFF][A-Za-z_0-9\\u00A1-\\uFFFF]*",t={$pattern:r,keyword:"in isa where baremodule begin break catch ccall const continue do else elseif end export false finally for function global if import importall let local macro module quote return true try using while type immutable abstract bitstype typealias ",literal:"true false ARGS C_NULL DevNull ENDIAN_BOM ENV I Inf Inf16 Inf32 Inf64 InsertionSort JULIA_HOME LOAD_PATH MergeSort NaN NaN16 NaN32 NaN64 PROGRAM_FILE QuickSort RoundDown RoundFromZero RoundNearest RoundNearestTiesAway RoundNearestTiesUp RoundToZero RoundUp STDERR STDIN STDOUT VERSION catalan e|0 eu|0 eulergamma golden im nothing pi γ π φ ",built_in:"ANY AbstractArray AbstractChannel AbstractFloat AbstractMatrix AbstractRNG AbstractSerializer AbstractSet AbstractSparseArray AbstractSparseMatrix AbstractSparseVector AbstractString AbstractUnitRange AbstractVecOrMat AbstractVector Any ArgumentError Array AssertionError Associative Base64DecodePipe Base64EncodePipe Bidiagonal BigFloat BigInt BitArray BitMatrix BitVector Bool BoundsError BufferStream CachingPool CapturedException CartesianIndex CartesianRange Cchar Cdouble Cfloat Channel Char Cint Cintmax_t Clong Clonglong ClusterManager Cmd CodeInfo Colon Complex Complex128 Complex32 Complex64 CompositeException Condition ConjArray ConjMatrix ConjVector Cptrdiff_t Cshort Csize_t Cssize_t Cstring Cuchar Cuint Cuintmax_t Culong Culonglong Cushort Cwchar_t Cwstring DataType Date DateFormat DateTime DenseArray DenseMatrix DenseVecOrMat DenseVector Diagonal Dict DimensionMismatch Dims DirectIndexString Display DivideError DomainError EOFError EachLine Enum Enumerate ErrorException Exception ExponentialBackOff Expr Factorization FileMonitor Float16 Float32 Float64 Function Future GlobalRef GotoNode HTML Hermitian IO IOBuffer IOContext IOStream IPAddr IPv4 IPv6 IndexCartesian IndexLinear IndexStyle InexactError InitError Int Int128 Int16 Int32 Int64 Int8 IntSet Integer InterruptException InvalidStateException Irrational KeyError LabelNode LinSpace LineNumberNode LoadError LowerTriangular MIME Matrix MersenneTwister Method MethodError MethodTable Module NTuple NewvarNode NullException Nullable Number ObjectIdDict OrdinalRange OutOfMemoryError OverflowError Pair ParseError PartialQuickSort PermutedDimsArray Pipe PollingFileWatcher ProcessExitedException Ptr QuoteNode RandomDevice Range RangeIndex Rational RawFD ReadOnlyMemoryError Real ReentrantLock Ref Regex RegexMatch RemoteChannel RemoteException RevString RoundingMode RowVector SSAValue SegmentationFault SerializationState Set SharedArray SharedMatrix SharedVector Signed SimpleVector Slot SlotNumber SparseMatrixCSC SparseVector StackFrame StackOverflowError StackTrace StepRange StepRangeLen StridedArray StridedMatrix StridedVecOrMat StridedVector String SubArray SubString SymTridiagonal Symbol Symmetric SystemError TCPSocket Task Text TextDisplay Timer Tridiagonal Tuple Type TypeError TypeMapEntry TypeMapLevel TypeName TypeVar TypedSlot UDPSocket UInt UInt128 UInt16 UInt32 UInt64 UInt8 UndefRefError UndefVarError UnicodeError UniformScaling Union UnionAll UnitRange Unsigned UpperTriangular Val Vararg VecElement VecOrMat Vector VersionNumber Void WeakKeyDict WeakRef WorkerConfig WorkerPool "},a={keywords:t,illegal:/<\//},n={className:"subst",begin:/\$\(/,end:/\)/,keywords:t},o={className:"variable",begin:"\\$"+r},i={className:"string",contains:[e.BACKSLASH_ESCAPE,n,o],variants:[{begin:/\w*"""/,end:/"""\w*/,relevance:10},{begin:/\w*"/,end:/"\w*/}]},l={className:"string",contains:[e.BACKSLASH_ESCAPE,n,o],begin:"`",end:"`"},s={className:"meta",begin:"@"+r};return a.name="Julia",a.contains=[{className:"number",begin:/(\b0x[\d_]*(\.[\d_]*)?|0x\.\d[\d_]*)p[-+]?\d+|\b0[box][a-fA-F0-9][a-fA-F0-9_]*|(\b\d[\d_]*(\.[\d_]*)?|\.\d[\d_]*)([eEfF][-+]?\d+)?/,relevance:0},{className:"string",begin:/'(.|\\[xXuU][a-zA-Z0-9]+)'/},i,l,s,{className:"comment",variants:[{begin:"#=",end:"=#",relevance:10},{begin:"#",end:"$"}]},e.HASH_COMMENT_MODE,{className:"keyword",begin:"\\b(((abstract|primitive)\\s+)type|(mutable\\s+)?struct)\\b"},{begin:/<:/}],n.contains=a.contains,a}}());hljs.registerLanguage("php-template",function(){"use strict";return function(n){return{name:"PHP template",subLanguage:"xml",contains:[{begin:/<\?(php|=)?/,end:/\?>/,subLanguage:"php",contains:[{begin:"/\\*",end:"\\*/",skip:!0},{begin:'b"',end:'"',skip:!0},{begin:"b'",end:"'",skip:!0},n.inherit(n.APOS_STRING_MODE,{illegal:null,className:null,contains:null,skip:!0}),n.inherit(n.QUOTE_STRING_MODE,{illegal:null,className:null,contains:null,skip:!0})]}]}}}());hljs.registerLanguage("scss",function(){"use strict";return function(e){var t={className:"variable",begin:"(\\$[a-zA-Z-][a-zA-Z0-9_-]*)\\b"},i={className:"number",begin:"#[0-9A-Fa-f]+"};return e.CSS_NUMBER_MODE,e.QUOTE_STRING_MODE,e.APOS_STRING_MODE,e.C_BLOCK_COMMENT_MODE,{name:"SCSS",case_insensitive:!0,illegal:"[=/|']",contains:[e.C_LINE_COMMENT_MODE,e.C_BLOCK_COMMENT_MODE,{className:"selector-id",begin:"\\#[A-Za-z0-9_-]+",relevance:0},{className:"selector-class",begin:"\\.[A-Za-z0-9_-]+",relevance:0},{className:"selector-attr",begin:"\\[",end:"\\]",illegal:"$"},{className:"selector-tag",begin:"\\b(a|abbr|acronym|address|area|article|aside|audio|b|base|big|blockquote|body|br|button|canvas|caption|cite|code|col|colgroup|command|datalist|dd|del|details|dfn|div|dl|dt|em|embed|fieldset|figcaption|figure|footer|form|frame|frameset|(h[1-6])|head|header|hgroup|hr|html|i|iframe|img|input|ins|kbd|keygen|label|legend|li|link|map|mark|meta|meter|nav|noframes|noscript|object|ol|optgroup|option|output|p|param|pre|progress|q|rp|rt|ruby|samp|script|section|select|small|span|strike|strong|style|sub|sup|table|tbody|td|textarea|tfoot|th|thead|time|title|tr|tt|ul|var|video)\\b",relevance:0},{className:"selector-pseudo",begin:":(visited|valid|root|right|required|read-write|read-only|out-range|optional|only-of-type|only-child|nth-of-type|nth-last-of-type|nth-last-child|nth-child|not|link|left|last-of-type|last-child|lang|invalid|indeterminate|in-range|hover|focus|first-of-type|first-line|first-letter|first-child|first|enabled|empty|disabled|default|checked|before|after|active)"},{className:"selector-pseudo",begin:"::(after|before|choices|first-letter|first-line|repeat-index|repeat-item|selection|value)"},t,{className:"attribute",begin:"\\b(src|z-index|word-wrap|word-spacing|word-break|width|widows|white-space|visibility|vertical-align|unicode-bidi|transition-timing-function|transition-property|transition-duration|transition-delay|transition|transform-style|transform-origin|transform|top|text-underline-position|text-transform|text-shadow|text-rendering|text-overflow|text-indent|text-decoration-style|text-decoration-line|text-decoration-color|text-decoration|text-align-last|text-align|tab-size|table-layout|right|resize|quotes|position|pointer-events|perspective-origin|perspective|page-break-inside|page-break-before|page-break-after|padding-top|padding-right|padding-left|padding-bottom|padding|overflow-y|overflow-x|overflow-wrap|overflow|outline-width|outline-style|outline-offset|outline-color|outline|orphans|order|opacity|object-position|object-fit|normal|none|nav-up|nav-right|nav-left|nav-index|nav-down|min-width|min-height|max-width|max-height|mask|marks|margin-top|margin-right|margin-left|margin-bottom|margin|list-style-type|list-style-position|list-style-image|list-style|line-height|letter-spacing|left|justify-content|initial|inherit|ime-mode|image-orientation|image-resolution|image-rendering|icon|hyphens|height|font-weight|font-variant-ligatures|font-variant|font-style|font-stretch|font-size-adjust|font-size|font-language-override|font-kerning|font-feature-settings|font-family|font|float|flex-wrap|flex-shrink|flex-grow|flex-flow|flex-direction|flex-basis|flex|filter|empty-cells|display|direction|cursor|counter-reset|counter-increment|content|column-width|column-span|column-rule-width|column-rule-style|column-rule-color|column-rule|column-gap|column-fill|column-count|columns|color|clip-path|clip|clear|caption-side|break-inside|break-before|break-after|box-sizing|box-shadow|box-decoration-break|bottom|border-width|border-top-width|border-top-style|border-top-right-radius|border-top-left-radius|border-top-color|border-top|border-style|border-spacing|border-right-width|border-right-style|border-right-color|border-right|border-radius|border-left-width|border-left-style|border-left-color|border-left|border-image-width|border-image-source|border-image-slice|border-image-repeat|border-image-outset|border-image|border-color|border-collapse|border-bottom-width|border-bottom-style|border-bottom-right-radius|border-bottom-left-radius|border-bottom-color|border-bottom|border|background-size|background-repeat|background-position|background-origin|background-image|background-color|background-clip|background-attachment|background-blend-mode|background|backface-visibility|auto|animation-timing-function|animation-play-state|animation-name|animation-iteration-count|animation-fill-mode|animation-duration|animation-direction|animation-delay|animation|align-self|align-items|align-content)\\b",illegal:"[^\\s]"},{begin:"\\b(whitespace|wait|w-resize|visible|vertical-text|vertical-ideographic|uppercase|upper-roman|upper-alpha|underline|transparent|top|thin|thick|text|text-top|text-bottom|tb-rl|table-header-group|table-footer-group|sw-resize|super|strict|static|square|solid|small-caps|separate|se-resize|scroll|s-resize|rtl|row-resize|ridge|right|repeat|repeat-y|repeat-x|relative|progress|pointer|overline|outside|outset|oblique|nowrap|not-allowed|normal|none|nw-resize|no-repeat|no-drop|newspaper|ne-resize|n-resize|move|middle|medium|ltr|lr-tb|lowercase|lower-roman|lower-alpha|loose|list-item|line|line-through|line-edge|lighter|left|keep-all|justify|italic|inter-word|inter-ideograph|inside|inset|inline|inline-block|inherit|inactive|ideograph-space|ideograph-parenthesis|ideograph-numeric|ideograph-alpha|horizontal|hidden|help|hand|groove|fixed|ellipsis|e-resize|double|dotted|distribute|distribute-space|distribute-letter|distribute-all-lines|disc|disabled|default|decimal|dashed|crosshair|collapse|col-resize|circle|char|center|capitalize|break-word|break-all|bottom|both|bolder|bold|block|bidi-override|below|baseline|auto|always|all-scroll|absolute|table|table-cell)\\b"},{begin:":",end:";",contains:[t,i,e.CSS_NUMBER_MODE,e.QUOTE_STRING_MODE,e.APOS_STRING_MODE,{className:"meta",begin:"!important"}]},{begin:"@(page|font-face)",lexemes:"@[a-z-]+",keywords:"@page @font-face"},{begin:"@",end:"[{;]",returnBegin:!0,keywords:"and or not only",contains:[{begin:"@[a-z-]+",className:"keyword"},t,e.QUOTE_STRING_MODE,e.APOS_STRING_MODE,i,e.CSS_NUMBER_MODE]}]}}}());hljs.registerLanguage("r",function(){"use strict";return function(e){var n="([a-zA-Z]|\\.[a-zA-Z.])[a-zA-Z0-9._]*";return{name:"R",contains:[e.HASH_COMMENT_MODE,{begin:n,keywords:{$pattern:n,keyword:"function if in break next repeat else for return switch while try tryCatch stop warning require library attach detach source setMethod setGeneric setGroupGeneric setClass ...",literal:"NULL NA TRUE FALSE T F Inf NaN NA_integer_|10 NA_real_|10 NA_character_|10 NA_complex_|10"},relevance:0},{className:"number",begin:"0[xX][0-9a-fA-F]+[Li]?\\b",relevance:0},{className:"number",begin:"\\d+(?:[eE][+\\-]?\\d*)?L\\b",relevance:0},{className:"number",begin:"\\d+\\.(?!\\d)(?:i\\b)?",relevance:0},{className:"number",begin:"\\d+(?:\\.\\d*)?(?:[eE][+\\-]?\\d*)?i?\\b",relevance:0},{className:"number",begin:"\\.\\d+(?:[eE][+\\-]?\\d*)?i?\\b",relevance:0},{begin:"`",end:"`",relevance:0},{className:"string",contains:[e.BACKSLASH_ESCAPE],variants:[{begin:'"',end:'"'},{begin:"'",end:"'"}]}]}}}());hljs.registerLanguage("sql",function(){"use strict";return function(e){var t=e.COMMENT("--","$");return{name:"SQL",case_insensitive:!0,illegal:/[<>{}*]/,contains:[{beginKeywords:"begin end start commit rollback savepoint lock alter create drop rename call delete do handler insert load replace select truncate update set show pragma grant merge describe use explain help declare prepare execute deallocate release unlock purge reset change stop analyze cache flush optimize repair kill install uninstall checksum restore check backup revoke comment values with",end:/;/,endsWithParent:!0,keywords:{$pattern:/[\w\.]+/,keyword:"as abort abs absolute acc acce accep accept access accessed accessible account acos action activate add addtime admin administer advanced advise aes_decrypt aes_encrypt after agent aggregate ali alia alias all allocate allow alter always analyze ancillary and anti any anydata anydataset anyschema anytype apply archive archived archivelog are as asc ascii asin assembly assertion associate asynchronous at atan atn2 attr attri attrib attribu attribut attribute attributes audit authenticated authentication authid authors auto autoallocate autodblink autoextend automatic availability avg backup badfile basicfile before begin beginning benchmark between bfile bfile_base big bigfile bin binary_double binary_float binlog bit_and bit_count bit_length bit_or bit_xor bitmap blob_base block blocksize body both bound bucket buffer_cache buffer_pool build bulk by byte byteordermark bytes cache caching call calling cancel capacity cascade cascaded case cast catalog category ceil ceiling chain change changed char_base char_length character_length characters characterset charindex charset charsetform charsetid check checksum checksum_agg child choose chr chunk class cleanup clear client clob clob_base clone close cluster_id cluster_probability cluster_set clustering coalesce coercibility col collate collation collect colu colum column column_value columns columns_updated comment commit compact compatibility compiled complete composite_limit compound compress compute concat concat_ws concurrent confirm conn connec connect connect_by_iscycle connect_by_isleaf connect_by_root connect_time connection consider consistent constant constraint constraints constructor container content contents context contributors controlfile conv convert convert_tz corr corr_k corr_s corresponding corruption cos cost count count_big counted covar_pop covar_samp cpu_per_call cpu_per_session crc32 create creation critical cross cube cume_dist curdate current current_date current_time current_timestamp current_user cursor curtime customdatum cycle data database databases datafile datafiles datalength date_add date_cache date_format date_sub dateadd datediff datefromparts datename datepart datetime2fromparts day day_to_second dayname dayofmonth dayofweek dayofyear days db_role_change dbtimezone ddl deallocate declare decode decompose decrement decrypt deduplicate def defa defau defaul default defaults deferred defi defin define degrees delayed delegate delete delete_all delimited demand dense_rank depth dequeue des_decrypt des_encrypt des_key_file desc descr descri describ describe descriptor deterministic diagnostics difference dimension direct_load directory disable disable_all disallow disassociate discardfile disconnect diskgroup distinct distinctrow distribute distributed div do document domain dotnet double downgrade drop dumpfile duplicate duration each edition editionable editions element ellipsis else elsif elt empty enable enable_all enclosed encode encoding encrypt end end-exec endian enforced engine engines enqueue enterprise entityescaping eomonth error errors escaped evalname evaluate event eventdata events except exception exceptions exchange exclude excluding execu execut execute exempt exists exit exp expire explain explode export export_set extended extent external external_1 external_2 externally extract failed failed_login_attempts failover failure far fast feature_set feature_value fetch field fields file file_name_convert filesystem_like_logging final finish first first_value fixed flash_cache flashback floor flush following follows for forall force foreign form forma format found found_rows freelist freelists freepools fresh from from_base64 from_days ftp full function general generated get get_format get_lock getdate getutcdate global global_name globally go goto grant grants greatest group group_concat group_id grouping grouping_id groups gtid_subtract guarantee guard handler hash hashkeys having hea head headi headin heading heap help hex hierarchy high high_priority hosts hour hours http id ident_current ident_incr ident_seed identified identity idle_time if ifnull ignore iif ilike ilm immediate import in include including increment index indexes indexing indextype indicator indices inet6_aton inet6_ntoa inet_aton inet_ntoa infile initial initialized initially initrans inmemory inner innodb input insert install instance instantiable instr interface interleaved intersect into invalidate invisible is is_free_lock is_ipv4 is_ipv4_compat is_not is_not_null is_used_lock isdate isnull isolation iterate java join json json_exists keep keep_duplicates key keys kill language large last last_day last_insert_id last_value lateral lax lcase lead leading least leaves left len lenght length less level levels library like like2 like4 likec limit lines link list listagg little ln load load_file lob lobs local localtime localtimestamp locate locator lock locked log log10 log2 logfile logfiles logging logical logical_reads_per_call logoff logon logs long loop low low_priority lower lpad lrtrim ltrim main make_set makedate maketime managed management manual map mapping mask master master_pos_wait match matched materialized max maxextents maximize maxinstances maxlen maxlogfiles maxloghistory maxlogmembers maxsize maxtrans md5 measures median medium member memcompress memory merge microsecond mid migration min minextents minimum mining minus minute minutes minvalue missing mod mode model modification modify module monitoring month months mount move movement multiset mutex name name_const names nan national native natural nav nchar nclob nested never new newline next nextval no no_write_to_binlog noarchivelog noaudit nobadfile nocheck nocompress nocopy nocycle nodelay nodiscardfile noentityescaping noguarantee nokeep nologfile nomapping nomaxvalue nominimize nominvalue nomonitoring none noneditionable nonschema noorder nopr nopro noprom nopromp noprompt norely noresetlogs noreverse normal norowdependencies noschemacheck noswitch not nothing notice notnull notrim novalidate now nowait nth_value nullif nulls num numb numbe nvarchar nvarchar2 object ocicoll ocidate ocidatetime ociduration ociinterval ociloblocator ocinumber ociref ocirefcursor ocirowid ocistring ocitype oct octet_length of off offline offset oid oidindex old on online only opaque open operations operator optimal optimize option optionally or oracle oracle_date oradata ord ordaudio orddicom orddoc order ordimage ordinality ordvideo organization orlany orlvary out outer outfile outline output over overflow overriding package pad parallel parallel_enable parameters parent parse partial partition partitions pascal passing password password_grace_time password_lock_time password_reuse_max password_reuse_time password_verify_function patch path patindex pctincrease pctthreshold pctused pctversion percent percent_rank percentile_cont percentile_disc performance period period_add period_diff permanent physical pi pipe pipelined pivot pluggable plugin policy position post_transaction pow power pragma prebuilt precedes preceding precision prediction prediction_cost prediction_details prediction_probability prediction_set prepare present preserve prior priority private private_sga privileges procedural procedure procedure_analyze processlist profiles project prompt protection public publishingservername purge quarter query quick quiesce quota quotename radians raise rand range rank raw read reads readsize rebuild record records recover recovery recursive recycle redo reduced ref reference referenced references referencing refresh regexp_like register regr_avgx regr_avgy regr_count regr_intercept regr_r2 regr_slope regr_sxx regr_sxy reject rekey relational relative relaylog release release_lock relies_on relocate rely rem remainder rename repair repeat replace replicate replication required reset resetlogs resize resource respect restore restricted result result_cache resumable resume retention return returning returns reuse reverse revoke right rlike role roles rollback rolling rollup round row row_count rowdependencies rowid rownum rows rtrim rules safe salt sample save savepoint sb1 sb2 sb4 scan schema schemacheck scn scope scroll sdo_georaster sdo_topo_geometry search sec_to_time second seconds section securefile security seed segment select self semi sequence sequential serializable server servererror session session_user sessions_per_user set sets settings sha sha1 sha2 share shared shared_pool short show shrink shutdown si_averagecolor si_colorhistogram si_featurelist si_positionalcolor si_stillimage si_texture siblings sid sign sin size size_t sizes skip slave sleep smalldatetimefromparts smallfile snapshot some soname sort soundex source space sparse spfile split sql sql_big_result sql_buffer_result sql_cache sql_calc_found_rows sql_small_result sql_variant_property sqlcode sqldata sqlerror sqlname sqlstate sqrt square standalone standby start starting startup statement static statistics stats_binomial_test stats_crosstab stats_ks_test stats_mode stats_mw_test stats_one_way_anova stats_t_test_ stats_t_test_indep stats_t_test_one stats_t_test_paired stats_wsr_test status std stddev stddev_pop stddev_samp stdev stop storage store stored str str_to_date straight_join strcmp strict string struct stuff style subdate subpartition subpartitions substitutable substr substring subtime subtring_index subtype success sum suspend switch switchoffset switchover sync synchronous synonym sys sys_xmlagg sysasm sysaux sysdate sysdatetimeoffset sysdba sysoper system system_user sysutcdatetime table tables tablespace tablesample tan tdo template temporary terminated tertiary_weights test than then thread through tier ties time time_format time_zone timediff timefromparts timeout timestamp timestampadd timestampdiff timezone_abbr timezone_minute timezone_region to to_base64 to_date to_days to_seconds todatetimeoffset trace tracking transaction transactional translate translation treat trigger trigger_nestlevel triggers trim truncate try_cast try_convert try_parse type ub1 ub2 ub4 ucase unarchived unbounded uncompress under undo unhex unicode uniform uninstall union unique unix_timestamp unknown unlimited unlock unnest unpivot unrecoverable unsafe unsigned until untrusted unusable unused update updated upgrade upped upper upsert url urowid usable usage use use_stored_outlines user user_data user_resources users using utc_date utc_timestamp uuid uuid_short validate validate_password_strength validation valist value values var var_samp varcharc vari varia variab variabl variable variables variance varp varraw varrawc varray verify version versions view virtual visible void wait wallet warning warnings week weekday weekofyear wellformed when whene whenev wheneve whenever where while whitespace window with within without work wrapped xdb xml xmlagg xmlattributes xmlcast xmlcolattval xmlelement xmlexists xmlforest xmlindex xmlnamespaces xmlpi xmlquery xmlroot xmlschema xmlserialize xmltable xmltype xor year year_to_month years yearweek",literal:"true false null unknown",built_in:"array bigint binary bit blob bool boolean char character date dec decimal float int int8 integer interval number numeric real record serial serial8 smallint text time timestamp tinyint varchar varchar2 varying void"},contains:[{className:"string",begin:"'",end:"'",contains:[{begin:"''"}]},{className:"string",begin:'"',end:'"',contains:[{begin:'""'}]},{className:"string",begin:"`",end:"`"},e.C_NUMBER_MODE,e.C_BLOCK_COMMENT_MODE,t,e.HASH_COMMENT_MODE]},e.C_BLOCK_COMMENT_MODE,t,e.HASH_COMMENT_MODE]}}}());hljs.registerLanguage("c",function(){"use strict";return function(e){var n=e.getLanguage("c-like").rawDefinition();return n.name="C",n.aliases=["c","h"],n}}());hljs.registerLanguage("json",function(){"use strict";return function(n){var e={literal:"true false null"},i=[n.C_LINE_COMMENT_MODE,n.C_BLOCK_COMMENT_MODE],t=[n.QUOTE_STRING_MODE,n.C_NUMBER_MODE],a={end:",",endsWithParent:!0,excludeEnd:!0,contains:t,keywords:e},l={begin:"{",end:"}",contains:[{className:"attr",begin:/"/,end:/"/,contains:[n.BACKSLASH_ESCAPE],illegal:"\\n"},n.inherit(a,{begin:/:/})].concat(i),illegal:"\\S"},s={begin:"\\[",end:"\\]",contains:[n.inherit(a)],illegal:"\\S"};return t.push(l,s),i.forEach((function(n){t.push(n)})),{name:"JSON",contains:t,keywords:e,illegal:"\\S"}}}());hljs.registerLanguage("python-repl",function(){"use strict";return function(n){return{aliases:["pycon"],contains:[{className:"meta",starts:{end:/ |$/,starts:{end:"$",subLanguage:"python"}},variants:[{begin:/^>>>(?=[ ]|$)/},{begin:/^\.\.\.(?=[ ]|$)/}]}]}}}());hljs.registerLanguage("markdown",function(){"use strict";return function(n){const e={begin:"<",end:">",subLanguage:"xml",relevance:0},a={begin:"\\[.+?\\][\\(\\[].*?[\\)\\]]",returnBegin:!0,contains:[{className:"string",begin:"\\[",end:"\\]",excludeBegin:!0,returnEnd:!0,relevance:0},{className:"link",begin:"\\]\\(",end:"\\)",excludeBegin:!0,excludeEnd:!0},{className:"symbol",begin:"\\]\\[",end:"\\]",excludeBegin:!0,excludeEnd:!0}],relevance:10},i={className:"strong",contains:[],variants:[{begin:/_{2}/,end:/_{2}/},{begin:/\*{2}/,end:/\*{2}/}]},s={className:"emphasis",contains:[],variants:[{begin:/\*(?!\*)/,end:/\*/},{begin:/_(?!_)/,end:/_/,relevance:0}]};i.contains.push(s),s.contains.push(i);var c=[e,a];return i.contains=i.contains.concat(c),s.contains=s.contains.concat(c),{name:"Markdown",aliases:["md","mkdown","mkd"],contains:[{className:"section",variants:[{begin:"^#{1,6}",end:"$",contains:c=c.concat(i,s)},{begin:"(?=^.+?\\n[=-]{2,}$)",contains:[{begin:"^[=-]*$"},{begin:"^",end:"\\n",contains:c}]}]},e,{className:"bullet",begin:"^[ \t]*([*+-]|(\\d+\\.))(?=\\s+)",end:"\\s+",excludeEnd:!0},i,s,{className:"quote",begin:"^>\\s+",contains:c,end:"$"},{className:"code",variants:[{begin:"(`{3,})(.|\\n)*?\\1`*[ ]*"},{begin:"(~{3,})(.|\\n)*?\\1~*[ ]*"},{begin:"```",end:"```+[ ]*$"},{begin:"~~~",end:"~~~+[ ]*$"},{begin:"`.+?`"},{begin:"(?=^( {4}|\\t))",contains:[{begin:"^( {4}|\\t)",end:"(\\n)$"}],relevance:0}]},{begin:"^[-\\*]{3,}",end:"$"},a,{begin:/^\[[^\n]+\]:/,returnBegin:!0,contains:[{className:"symbol",begin:/\[/,end:/\]/,excludeBegin:!0,excludeEnd:!0},{className:"link",begin:/:\s*/,end:/$/,excludeBegin:!0}]}]}}}());hljs.registerLanguage("javascript",function(){"use strict";const e=["as","in","of","if","for","while","finally","var","new","function","do","return","void","else","break","catch","instanceof","with","throw","case","default","try","switch","continue","typeof","delete","let","yield","const","class","debugger","async","await","static","import","from","export","extends"],n=["true","false","null","undefined","NaN","Infinity"],a=[].concat(["setInterval","setTimeout","clearInterval","clearTimeout","require","exports","eval","isFinite","isNaN","parseFloat","parseInt","decodeURI","decodeURIComponent","encodeURI","encodeURIComponent","escape","unescape"],["arguments","this","super","console","window","document","localStorage","module","global"],["Intl","DataView","Number","Math","Date","String","RegExp","Object","Function","Boolean","Error","Symbol","Set","Map","WeakSet","WeakMap","Proxy","Reflect","JSON","Promise","Float64Array","Int16Array","Int32Array","Int8Array","Uint16Array","Uint32Array","Float32Array","Array","Uint8Array","Uint8ClampedArray","ArrayBuffer"],["EvalError","InternalError","RangeError","ReferenceError","SyntaxError","TypeError","URIError"]);function s(e){return r("(?=",e,")")}function r(...e){return e.map(e=>(function(e){return e?"string"==typeof e?e:e.source:null})(e)).join("")}return function(t){var i="[A-Za-z$_][0-9A-Za-z$_]*",c={begin:/<[A-Za-z0-9\\._:-]+/,end:/\/[A-Za-z0-9\\._:-]+>|\/>/},o={$pattern:"[A-Za-z$_][0-9A-Za-z$_]*",keyword:e.join(" "),literal:n.join(" "),built_in:a.join(" ")},l={className:"number",variants:[{begin:"\\b(0[bB][01]+)n?"},{begin:"\\b(0[oO][0-7]+)n?"},{begin:t.C_NUMBER_RE+"n?"}],relevance:0},E={className:"subst",begin:"\\$\\{",end:"\\}",keywords:o,contains:[]},d={begin:"html`",end:"",starts:{end:"`",returnEnd:!1,contains:[t.BACKSLASH_ESCAPE,E],subLanguage:"xml"}},g={begin:"css`",end:"",starts:{end:"`",returnEnd:!1,contains:[t.BACKSLASH_ESCAPE,E],subLanguage:"css"}},u={className:"string",begin:"`",end:"`",contains:[t.BACKSLASH_ESCAPE,E]};E.contains=[t.APOS_STRING_MODE,t.QUOTE_STRING_MODE,d,g,u,l,t.REGEXP_MODE];var b=E.contains.concat([{begin:/\(/,end:/\)/,contains:["self"].concat(E.contains,[t.C_BLOCK_COMMENT_MODE,t.C_LINE_COMMENT_MODE])},t.C_BLOCK_COMMENT_MODE,t.C_LINE_COMMENT_MODE]),_={className:"params",begin:/\(/,end:/\)/,excludeBegin:!0,excludeEnd:!0,contains:b};return{name:"JavaScript",aliases:["js","jsx","mjs","cjs"],keywords:o,contains:[t.SHEBANG({binary:"node",relevance:5}),{className:"meta",relevance:10,begin:/^\s*['"]use (strict|asm)['"]/},t.APOS_STRING_MODE,t.QUOTE_STRING_MODE,d,g,u,t.C_LINE_COMMENT_MODE,t.COMMENT("/\\*\\*","\\*/",{relevance:0,contains:[{className:"doctag",begin:"@[A-Za-z]+",contains:[{className:"type",begin:"\\{",end:"\\}",relevance:0},{className:"variable",begin:i+"(?=\\s*(-)|$)",endsParent:!0,relevance:0},{begin:/(?=[^\n])\s/,relevance:0}]}]}),t.C_BLOCK_COMMENT_MODE,l,{begin:r(/[{,\n]\s*/,s(r(/(((\/\/.*)|(\/\*(.|\n)*\*\/))\s*)*/,i+"\\s*:"))),relevance:0,contains:[{className:"attr",begin:i+s("\\s*:"),relevance:0}]},{begin:"("+t.RE_STARTERS_RE+"|\\b(case|return|throw)\\b)\\s*",keywords:"return throw case",contains:[t.C_LINE_COMMENT_MODE,t.C_BLOCK_COMMENT_MODE,t.REGEXP_MODE,{className:"function",begin:"(\\([^(]*(\\([^(]*(\\([^(]*\\))?\\))?\\)|"+t.UNDERSCORE_IDENT_RE+")\\s*=>",returnBegin:!0,end:"\\s*=>",contains:[{className:"params",variants:[{begin:t.UNDERSCORE_IDENT_RE},{className:null,begin:/\(\s*\)/,skip:!0},{begin:/\(/,end:/\)/,excludeBegin:!0,excludeEnd:!0,keywords:o,contains:b}]}]},{begin:/,/,relevance:0},{className:"",begin:/\s/,end:/\s*/,skip:!0},{variants:[{begin:"<>",end:""},{begin:c.begin,end:c.end}],subLanguage:"xml",contains:[{begin:c.begin,end:c.end,skip:!0,contains:["self"]}]}],relevance:0},{className:"function",beginKeywords:"function",end:/\{/,excludeEnd:!0,contains:[t.inherit(t.TITLE_MODE,{begin:i}),_],illegal:/\[|%/},{begin:/\$[(.]/},t.METHOD_GUARD,{className:"class",beginKeywords:"class",end:/[{;=]/,excludeEnd:!0,illegal:/[:"\[\]]/,contains:[{beginKeywords:"extends"},t.UNDERSCORE_TITLE_MODE]},{beginKeywords:"constructor",end:/\{/,excludeEnd:!0},{begin:"(get|set)\\s+(?="+i+"\\()",end:/{/,keywords:"get set",contains:[t.inherit(t.TITLE_MODE,{begin:i}),{begin:/\(\)/},_]}],illegal:/#(?!!)/}}}());hljs.registerLanguage("typescript",function(){"use strict";const e=["as","in","of","if","for","while","finally","var","new","function","do","return","void","else","break","catch","instanceof","with","throw","case","default","try","switch","continue","typeof","delete","let","yield","const","class","debugger","async","await","static","import","from","export","extends"],n=["true","false","null","undefined","NaN","Infinity"],a=[].concat(["setInterval","setTimeout","clearInterval","clearTimeout","require","exports","eval","isFinite","isNaN","parseFloat","parseInt","decodeURI","decodeURIComponent","encodeURI","encodeURIComponent","escape","unescape"],["arguments","this","super","console","window","document","localStorage","module","global"],["Intl","DataView","Number","Math","Date","String","RegExp","Object","Function","Boolean","Error","Symbol","Set","Map","WeakSet","WeakMap","Proxy","Reflect","JSON","Promise","Float64Array","Int16Array","Int32Array","Int8Array","Uint16Array","Uint32Array","Float32Array","Array","Uint8Array","Uint8ClampedArray","ArrayBuffer"],["EvalError","InternalError","RangeError","ReferenceError","SyntaxError","TypeError","URIError"]);return function(r){var t={$pattern:"[A-Za-z$_][0-9A-Za-z$_]*",keyword:e.concat(["type","namespace","typedef","interface","public","private","protected","implements","declare","abstract","readonly"]).join(" "),literal:n.join(" "),built_in:a.concat(["any","void","number","boolean","string","object","never","enum"]).join(" ")},s={className:"meta",begin:"@[A-Za-z$_][0-9A-Za-z$_]*"},i={className:"number",variants:[{begin:"\\b(0[bB][01]+)n?"},{begin:"\\b(0[oO][0-7]+)n?"},{begin:r.C_NUMBER_RE+"n?"}],relevance:0},o={className:"subst",begin:"\\$\\{",end:"\\}",keywords:t,contains:[]},c={begin:"html`",end:"",starts:{end:"`",returnEnd:!1,contains:[r.BACKSLASH_ESCAPE,o],subLanguage:"xml"}},l={begin:"css`",end:"",starts:{end:"`",returnEnd:!1,contains:[r.BACKSLASH_ESCAPE,o],subLanguage:"css"}},E={className:"string",begin:"`",end:"`",contains:[r.BACKSLASH_ESCAPE,o]};o.contains=[r.APOS_STRING_MODE,r.QUOTE_STRING_MODE,c,l,E,i,r.REGEXP_MODE];var d={begin:"\\(",end:/\)/,keywords:t,contains:["self",r.QUOTE_STRING_MODE,r.APOS_STRING_MODE,r.NUMBER_MODE]},u={className:"params",begin:/\(/,end:/\)/,excludeBegin:!0,excludeEnd:!0,keywords:t,contains:[r.C_LINE_COMMENT_MODE,r.C_BLOCK_COMMENT_MODE,s,d]};return{name:"TypeScript",aliases:["ts"],keywords:t,contains:[r.SHEBANG(),{className:"meta",begin:/^\s*['"]use strict['"]/},r.APOS_STRING_MODE,r.QUOTE_STRING_MODE,c,l,E,r.C_LINE_COMMENT_MODE,r.C_BLOCK_COMMENT_MODE,i,{begin:"("+r.RE_STARTERS_RE+"|\\b(case|return|throw)\\b)\\s*",keywords:"return throw case",contains:[r.C_LINE_COMMENT_MODE,r.C_BLOCK_COMMENT_MODE,r.REGEXP_MODE,{className:"function",begin:"(\\([^(]*(\\([^(]*(\\([^(]*\\))?\\))?\\)|"+r.UNDERSCORE_IDENT_RE+")\\s*=>",returnBegin:!0,end:"\\s*=>",contains:[{className:"params",variants:[{begin:r.UNDERSCORE_IDENT_RE},{className:null,begin:/\(\s*\)/,skip:!0},{begin:/\(/,end:/\)/,excludeBegin:!0,excludeEnd:!0,keywords:t,contains:d.contains}]}]}],relevance:0},{className:"function",beginKeywords:"function",end:/[\{;]/,excludeEnd:!0,keywords:t,contains:["self",r.inherit(r.TITLE_MODE,{begin:"[A-Za-z$_][0-9A-Za-z$_]*"}),u],illegal:/%/,relevance:0},{beginKeywords:"constructor",end:/[\{;]/,excludeEnd:!0,contains:["self",u]},{begin:/module\./,keywords:{built_in:"module"},relevance:0},{beginKeywords:"module",end:/\{/,excludeEnd:!0},{beginKeywords:"interface",end:/\{/,excludeEnd:!0,keywords:"interface extends"},{begin:/\$[(.]/},{begin:"\\."+r.IDENT_RE,relevance:0},s,d]}}}());hljs.registerLanguage("plaintext",function(){"use strict";return function(t){return{name:"Plain text",aliases:["text","txt"],disableAutodetect:!0}}}());hljs.registerLanguage("less",function(){"use strict";return function(e){var n="([\\w-]+|@{[\\w-]+})",a=[],s=[],t=function(e){return{className:"string",begin:"~?"+e+".*?"+e}},r=function(e,n,a){return{className:e,begin:n,relevance:a}},i={begin:"\\(",end:"\\)",contains:s,relevance:0};s.push(e.C_LINE_COMMENT_MODE,e.C_BLOCK_COMMENT_MODE,t("'"),t('"'),e.CSS_NUMBER_MODE,{begin:"(url|data-uri)\\(",starts:{className:"string",end:"[\\)\\n]",excludeEnd:!0}},r("number","#[0-9A-Fa-f]+\\b"),i,r("variable","@@?[\\w-]+",10),r("variable","@{[\\w-]+}"),r("built_in","~?`[^`]*?`"),{className:"attribute",begin:"[\\w-]+\\s*:",end:":",returnBegin:!0,excludeEnd:!0},{className:"meta",begin:"!important"});var c=s.concat({begin:"{",end:"}",contains:a}),l={beginKeywords:"when",endsWithParent:!0,contains:[{beginKeywords:"and not"}].concat(s)},o={begin:n+"\\s*:",returnBegin:!0,end:"[;}]",relevance:0,contains:[{className:"attribute",begin:n,end:":",excludeEnd:!0,starts:{endsWithParent:!0,illegal:"[<=$]",relevance:0,contains:s}}]},g={className:"keyword",begin:"@(import|media|charset|font-face|(-[a-z]+-)?keyframes|supports|document|namespace|page|viewport|host)\\b",starts:{end:"[;{}]",returnEnd:!0,contains:s,relevance:0}},d={className:"variable",variants:[{begin:"@[\\w-]+\\s*:",relevance:15},{begin:"@[\\w-]+"}],starts:{end:"[;}]",returnEnd:!0,contains:c}},b={variants:[{begin:"[\\.#:&\\[>]",end:"[;{}]"},{begin:n,end:"{"}],returnBegin:!0,returnEnd:!0,illegal:"[<='$\"]",relevance:0,contains:[e.C_LINE_COMMENT_MODE,e.C_BLOCK_COMMENT_MODE,l,r("keyword","all\\b"),r("variable","@{[\\w-]+}"),r("selector-tag",n+"%?",0),r("selector-id","#"+n),r("selector-class","\\."+n,0),r("selector-tag","&",0),{className:"selector-attr",begin:"\\[",end:"\\]"},{className:"selector-pseudo",begin:/:(:)?[a-zA-Z0-9\_\-\+\(\)"'.]+/},{begin:"\\(",end:"\\)",contains:c},{begin:"!important"}]};return a.push(e.C_LINE_COMMENT_MODE,e.C_BLOCK_COMMENT_MODE,g,d,o,b),{name:"Less",case_insensitive:!0,illegal:"[=>'/<($\"]",contains:a}}}());hljs.registerLanguage("lua",function(){"use strict";return function(e){var t={begin:"\\[=*\\[",end:"\\]=*\\]",contains:["self"]},a=[e.COMMENT("--(?!\\[=*\\[)","$"),e.COMMENT("--\\[=*\\[","\\]=*\\]",{contains:[t],relevance:10})];return{name:"Lua",keywords:{$pattern:e.UNDERSCORE_IDENT_RE,literal:"true false nil",keyword:"and break do else elseif end for goto if in local not or repeat return then until while",built_in:"_G _ENV _VERSION __index __newindex __mode __call __metatable __tostring __len __gc __add __sub __mul __div __mod __pow __concat __unm __eq __lt __le assert collectgarbage dofile error getfenv getmetatable ipairs load loadfile loadstring module next pairs pcall print rawequal rawget rawset require select setfenv setmetatable tonumber tostring type unpack xpcall arg self coroutine resume yield status wrap create running debug getupvalue debug sethook getmetatable gethook setmetatable setlocal traceback setfenv getinfo setupvalue getlocal getregistry getfenv io lines write close flush open output type read stderr stdin input stdout popen tmpfile math log max acos huge ldexp pi cos tanh pow deg tan cosh sinh random randomseed frexp ceil floor rad abs sqrt modf asin min mod fmod log10 atan2 exp sin atan os exit setlocale date getenv difftime remove time clock tmpname rename execute package preload loadlib loaded loaders cpath config path seeall string sub upper len gfind rep find match char dump gmatch reverse byte format gsub lower table setn insert getn foreachi maxn foreach concat sort remove"},contains:a.concat([{className:"function",beginKeywords:"function",end:"\\)",contains:[e.inherit(e.TITLE_MODE,{begin:"([_a-zA-Z]\\w*\\.)*([_a-zA-Z]\\w*:)?[_a-zA-Z]\\w*"}),{className:"params",begin:"\\(",endsWithParent:!0,contains:a}].concat(a)},e.C_NUMBER_MODE,e.APOS_STRING_MODE,e.QUOTE_STRING_MODE,{className:"string",begin:"\\[=*\\[",end:"\\]=*\\]",contains:[t],relevance:5}])}}}()); diff --git a/HEAD/how_to/building_drivers.html b/HEAD/how_to/building_drivers.html new file mode 100644 index 000000000..99f059466 --- /dev/null +++ b/HEAD/how_to/building_drivers.html @@ -0,0 +1,191 @@ + + + + + + Building drivers - Rust UEFI Book + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ +
+ + + + + + + +
+
+

Building drivers

+

There are three types of UEFI images:

+
    +
  • Application
  • +
  • Boot service driver
  • +
  • Runtime driver
  • +
+

By default, Rust's UEFI targets produce applications. This can be +changed by passing a subsystem linker flag in rustflags and setting the +value to efi_boot_service_driver or efi_runtime_driver.

+

Example:

+
# In .cargo/config.toml:
+[build]
+rustflags = ["-C", "link-args=/subsystem:efi_runtime_driver"]
+
+ +
+ + +
+
+ + + +
+ + + + + + + + + + + + diff --git a/HEAD/how_to/drawing.html b/HEAD/how_to/drawing.html new file mode 100644 index 000000000..9a945d0ba --- /dev/null +++ b/HEAD/how_to/drawing.html @@ -0,0 +1,359 @@ + + + + + + Drawing to the Screen - Rust UEFI Book + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ +
+ + + + + + + +
+
+

Drawing to the Screen

+

This example shows how to draw to the screen using the graphics output protocol. +The code will a Sierpiński triangle using the "chaos game" method.

+

screenshot

+

The core abstraction used here is a linear buffer:

+
#![allow(unused)]
+fn main() {
+struct Buffer {
+    width: usize,
+    height: usize,
+    pixels: Vec<BltPixel>,
+}
+
+impl Buffer {
+    /// Create a new `Buffer`.
+    fn new(width: usize, height: usize) -> Self {
+        Buffer {
+            width,
+            height,
+            pixels: vec![BltPixel::new(0, 0, 0); width * height],
+        }
+    }
+
+    /// Get a single pixel.
+    fn pixel(&mut self, x: usize, y: usize) -> Option<&mut BltPixel> {
+        self.pixels.get_mut(y * self.width + x)
+    }
+
+    /// Blit the buffer to the framebuffer.
+    fn blit(&self, gop: &mut GraphicsOutput) -> Result {
+        gop.blt(BltOp::BufferToVideo {
+            buffer: &self.pixels,
+            src: BltRegion::Full,
+            dest: (0, 0),
+            dims: (self.width, self.height),
+        })
+    }
+}
+}
+
+

This Buffer type stores a Vec of BltPixels, which are BGRX +32-bit pixels (8 bites each for blue, green, and red, followed by 8 +unused bits of padding). We use the pixel method to alter a single +pixel at a time. This is often not an efficient method; for more complex +graphics you could use a crate like embedded-graphics.

+

The Buffer::blit method calls the graphics output protocol's blt +method to copy the buffer to the screen.

+

Most of the rest of the code is just implementing the algorithm for +drawing the fractal. Here's the full example:

+
#![no_main]
+#![no_std]
+
+extern crate alloc;
+
+use alloc::vec;
+use alloc::vec::Vec;
+use core::mem;
+use uefi::prelude::*;
+use uefi::proto::console::gop::{BltOp, BltPixel, BltRegion, GraphicsOutput};
+use uefi::proto::rng::Rng;
+use uefi::table::boot::BootServices;
+use uefi::Result;
+
+#[derive(Clone, Copy)]
+struct Point {
+    x: f32,
+    y: f32,
+}
+
+impl Point {
+    fn new(x: f32, y: f32) -> Self {
+        Self { x, y }
+    }
+}
+
+struct Buffer {
+    width: usize,
+    height: usize,
+    pixels: Vec<BltPixel>,
+}
+
+impl Buffer {
+    /// Create a new `Buffer`.
+    fn new(width: usize, height: usize) -> Self {
+        Buffer {
+            width,
+            height,
+            pixels: vec![BltPixel::new(0, 0, 0); width * height],
+        }
+    }
+
+    /// Get a single pixel.
+    fn pixel(&mut self, x: usize, y: usize) -> Option<&mut BltPixel> {
+        self.pixels.get_mut(y * self.width + x)
+    }
+
+    /// Blit the buffer to the framebuffer.
+    fn blit(&self, gop: &mut GraphicsOutput) -> Result {
+        gop.blt(BltOp::BufferToVideo {
+            buffer: &self.pixels,
+            src: BltRegion::Full,
+            dest: (0, 0),
+            dims: (self.width, self.height),
+        })
+    }
+}
+
+/// Get a random `usize` value.
+fn get_random_usize(rng: &mut Rng) -> usize {
+    let mut buf = [0; mem::size_of::<usize>()];
+    rng.get_rng(None, &mut buf).expect("get_rng failed");
+    usize::from_le_bytes(buf)
+}
+
+fn draw_sierpinski(bt: &BootServices) -> Result {
+    // Open graphics output protocol.
+    let gop_handle = bt.get_handle_for_protocol::<GraphicsOutput>()?;
+    let mut gop = bt.open_protocol_exclusive::<GraphicsOutput>(gop_handle)?;
+
+    // Open random number generator protocol.
+    let rng_handle = bt.get_handle_for_protocol::<Rng>()?;
+    let mut rng = bt.open_protocol_exclusive::<Rng>(rng_handle)?;
+
+    // Create a buffer to draw into.
+    let (width, height) = gop.current_mode_info().resolution();
+    let mut buffer = Buffer::new(width, height);
+
+    // Initialize the buffer with a simple gradient background.
+    for y in 0..height {
+        let r = ((y as f32) / ((height - 1) as f32)) * 255.0;
+        for x in 0..width {
+            let g = ((x as f32) / ((width - 1) as f32)) * 255.0;
+            let pixel = buffer.pixel(x, y).unwrap();
+            pixel.red = r as u8;
+            pixel.green = g as u8;
+            pixel.blue = 255;
+        }
+    }
+
+    let size = Point::new(width as f32, height as f32);
+
+    // Define the vertices of a big triangle.
+    let border = 20.0;
+    let triangle = [
+        Point::new(size.x / 2.0, border),
+        Point::new(border, size.y - border),
+        Point::new(size.x - border, size.y - border),
+    ];
+
+    // `p` is the point to draw. Start at the center of the triangle.
+    let mut p = Point::new(size.x / 2.0, size.y / 2.0);
+
+    // Loop forever, drawing the frame after each new point is changed.
+    loop {
+        // Choose one of the triangle's vertices at random.
+        let v = triangle[get_random_usize(&mut rng) % 3];
+
+        // Move `p` halfway to the chosen vertex.
+        p.x = (p.x + v.x) * 0.5;
+        p.y = (p.y + v.y) * 0.5;
+
+        // Set `p` to black.
+        let pixel = buffer.pixel(p.x as usize, p.y as usize).unwrap();
+        pixel.red = 0;
+        pixel.green = 100;
+        pixel.blue = 0;
+
+        // Draw the buffer to the screen.
+        buffer.blit(&mut gop)?;
+    }
+}
+
+#[entry]
+fn main(_handle: Handle, mut system_table: SystemTable<Boot>) -> Status {
+    uefi_services::init(&mut system_table).unwrap();
+    let bt = system_table.boot_services();
+    draw_sierpinski(bt).unwrap();
+    Status::SUCCESS
+}
+
+

You can run this example from the uefi-rs repository with:

+
cargo xtask run --example sierpinski
+
+ +
+ + +
+
+ + + +
+ + + + + + + + + + + + diff --git a/HEAD/how_to/introduction.html b/HEAD/how_to/introduction.html new file mode 100644 index 000000000..449c310dc --- /dev/null +++ b/HEAD/how_to/introduction.html @@ -0,0 +1,178 @@ + + + + + + How-to - Rust UEFI Book + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ +
+ + + + + + + +
+
+

How-to

+

This chapter contains practical how-to guides.

+ +
+ + +
+
+ + + +
+ + + + + + + + + + + + diff --git a/HEAD/how_to/protocols.html b/HEAD/how_to/protocols.html new file mode 100644 index 000000000..7c93250f2 --- /dev/null +++ b/HEAD/how_to/protocols.html @@ -0,0 +1,329 @@ + + + + + + Using Protocols - Rust UEFI Book + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ +
+ + + + + + + +
+
+

Using Protocols

+

The open a protocol, you must first get a handle, then open a protocol +on that handle. See Handles and Protocols for an overview of what +these terms mean.

+

To get a handle you can use:

+ +

Once you have obtained a handle, use +BootServices::open_protocol_exclusive to open a protocol on that +handle. This returns a ScopedProtocol, which automatically closes +the protocol when dropped.

+

Using BootServices::open_protocol_exclusive is the safest way to +open a protocol, but in some cases a protocol cannot be opened in +exclusive mode. The unsafe BootServices::open_protocol can be used +in that case.

+

Example

+

For this example we'll look at a program that opens a couple different +protocols. This program opens the LoadedImage protocol to get +information about an executable (the currently-running program in this +case). It also opens the DevicePathToText protocol to get the file +system path that the program was launched from.

+

We'll walk through the details of this program shortly, but first here's +the whole thing:

+
#![no_main]
+#![no_std]
+
+use log::info;
+use uefi::prelude::*;
+use uefi::proto::device_path::text::{
+    AllowShortcuts, DevicePathToText, DisplayOnly,
+};
+use uefi::proto::loaded_image::LoadedImage;
+use uefi::table::boot::SearchType;
+use uefi::{Identify, Result};
+
+#[entry]
+fn main(image_handle: Handle, mut system_table: SystemTable<Boot>) -> Status {
+    uefi_services::init(&mut system_table).unwrap();
+    let boot_services = system_table.boot_services();
+
+    print_image_path(boot_services).unwrap();
+
+    boot_services.stall(10_000_000);
+    Status::SUCCESS
+}
+
+fn print_image_path(boot_services: &BootServices) -> Result {
+    let loaded_image = boot_services
+        .open_protocol_exclusive::<LoadedImage>(boot_services.image_handle())?;
+
+    let device_path_to_text_handle = *boot_services
+        .locate_handle_buffer(SearchType::ByProtocol(&DevicePathToText::GUID))?
+        .first()
+        .expect("DevicePathToText is missing");
+
+    let device_path_to_text = boot_services
+        .open_protocol_exclusive::<DevicePathToText>(
+            device_path_to_text_handle,
+        )?;
+
+    let image_device_path =
+        loaded_image.file_path().expect("File path is not set");
+    let image_device_path_text = device_path_to_text
+        .convert_device_path_to_text(
+            boot_services,
+            image_device_path,
+            DisplayOnly(true),
+            AllowShortcuts(false),
+        )
+        .expect("convert_device_path_to_text failed");
+
+    info!("Image path: {}", &*image_device_path_text);
+    Ok(())
+}
+
+

When the program is run it will print something like this:

+
[ INFO]: example.rs@058: Image path: \EFI\BOOT\BOOTX64.EFI
+
+

Walkthrough

+

The main function looks much like the "Hello world!" example. It +sets up logging, calls print_image_path, and pauses for ten seconds to +give you time to read the output. Let's look at print_image_path:

+
#![allow(unused)]
+fn main() {
+fn print_image_path(boot_services: &BootServices) -> Result {
+}
+
+

The return type is a uefi::Result, which is a Result alias that +combines uefi::Status with the error data. Both the success and +error data types are () by default.

+

The function starts by opening the LoadedImage protocol:

+
#![allow(unused)]
+fn main() {
+    let loaded_image = boot_services
+        .open_protocol_exclusive::<LoadedImage>(boot_services.image_handle())?;
+}
+
+

The open_protocol_exclusive method takes a type parameter, which is +the type of Protocol you want to open (LoadedImage in this +case). It also takes one regular argument of type Handle. For this +example we want the handle of the currently-running image, which was +passed in as the first argument to main. The handle is conveniently +accessible through BootServices::image_handle, so we use that here.

+

Next the program opens the DevicePathToText protocol:

+
#![allow(unused)]
+fn main() {
+    let device_path_to_text_handle = *boot_services
+        .locate_handle_buffer(SearchType::ByProtocol(&DevicePathToText::GUID))?
+        .first()
+        .expect("DevicePathToText is missing");
+
+    let device_path_to_text = boot_services
+        .open_protocol_exclusive::<DevicePathToText>(
+            device_path_to_text_handle,
+        )?;
+}
+
+

This protocol isn't available for the image_handle, so we start by +using locate_handle_buffer to find all handles that support +DevicePathToText. We only need one handle though, so we call first() +and discard the rest. Then we call open_protocol_exclusive again. It +looks more or less like the previous time, but with DevicePathToText +as the type parameter and device_path_to_text_handle as the handle.

+

Now that we have both protocols open, we can use them together to get +the program's path and convert it to text:

+
#![allow(unused)]
+fn main() {
+    let image_device_path =
+        loaded_image.file_path().expect("File path is not set");
+    let image_device_path_text = device_path_to_text
+        .convert_device_path_to_text(
+            boot_services,
+            image_device_path,
+            DisplayOnly(true),
+            AllowShortcuts(false),
+        )
+        .expect("convert_device_path_to_text failed");
+
+    info!("Image path: {}", &*image_device_path_text);
+    Ok(())
+}
+}
+
+

Since protocols do a wide range of different things, the methods +available to call are very specific to each individual protocol. The +best places to find out what each protocol can do are the uefi-rs +reference documentation and the UEFI Specification.

+ +
+ + +
+
+ + + +
+ + + + + + + + + + + + diff --git a/HEAD/index.html b/HEAD/index.html new file mode 100644 index 000000000..f812cb381 --- /dev/null +++ b/HEAD/index.html @@ -0,0 +1,174 @@ + + + + + + Introduction - Rust UEFI Book + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ +
+ + + + + + + +
+
+

Introduction

+

Welcome to the Rust UEFI Book. The focus of this book is how to use +uefi-rs to build UEFI applications in Rust, but it also describes +some general UEFI concepts, as well as relevant tools such as QEMU.

+ +
+ + +
+
+ + + +
+ + + + + + + + + + + + diff --git a/HEAD/introduction.html b/HEAD/introduction.html new file mode 100644 index 000000000..f812cb381 --- /dev/null +++ b/HEAD/introduction.html @@ -0,0 +1,174 @@ + + + + + + Introduction - Rust UEFI Book + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ +
+ + + + + + + +
+
+

Introduction

+

Welcome to the Rust UEFI Book. The focus of this book is how to use +uefi-rs to build UEFI applications in Rust, but it also describes +some general UEFI concepts, as well as relevant tools such as QEMU.

+ +
+ + +
+
+ + + +
+ + + + + + + + + + + + diff --git a/HEAD/mark.min.js b/HEAD/mark.min.js new file mode 100644 index 000000000..163623188 --- /dev/null +++ b/HEAD/mark.min.js @@ -0,0 +1,7 @@ +/*!*************************************************** +* mark.js v8.11.1 +* https://markjs.io/ +* Copyright (c) 2014–2018, Julian Kühnel +* Released under the MIT license https://git.io/vwTVl +*****************************************************/ +!function(e,t){"object"==typeof exports&&"undefined"!=typeof module?module.exports=t():"function"==typeof define&&define.amd?define(t):e.Mark=t()}(this,function(){"use strict";var e="function"==typeof Symbol&&"symbol"==typeof Symbol.iterator?function(e){return typeof e}:function(e){return e&&"function"==typeof Symbol&&e.constructor===Symbol&&e!==Symbol.prototype?"symbol":typeof e},t=function(e,t){if(!(e instanceof t))throw new TypeError("Cannot call a class as a function")},n=function(){function e(e,t){for(var n=0;n1&&void 0!==arguments[1])||arguments[1],i=arguments.length>2&&void 0!==arguments[2]?arguments[2]:[],o=arguments.length>3&&void 0!==arguments[3]?arguments[3]:5e3;t(this,e),this.ctx=n,this.iframes=r,this.exclude=i,this.iframesTimeout=o}return n(e,[{key:"getContexts",value:function(){var e=[];return(void 0!==this.ctx&&this.ctx?NodeList.prototype.isPrototypeOf(this.ctx)?Array.prototype.slice.call(this.ctx):Array.isArray(this.ctx)?this.ctx:"string"==typeof this.ctx?Array.prototype.slice.call(document.querySelectorAll(this.ctx)):[this.ctx]:[]).forEach(function(t){var n=e.filter(function(e){return e.contains(t)}).length>0;-1!==e.indexOf(t)||n||e.push(t)}),e}},{key:"getIframeContents",value:function(e,t){var n=arguments.length>2&&void 0!==arguments[2]?arguments[2]:function(){},r=void 0;try{var i=e.contentWindow;if(r=i.document,!i||!r)throw new Error("iframe inaccessible")}catch(e){n()}r&&t(r)}},{key:"isIframeBlank",value:function(e){var t="about:blank",n=e.getAttribute("src").trim();return e.contentWindow.location.href===t&&n!==t&&n}},{key:"observeIframeLoad",value:function(e,t,n){var r=this,i=!1,o=null,a=function a(){if(!i){i=!0,clearTimeout(o);try{r.isIframeBlank(e)||(e.removeEventListener("load",a),r.getIframeContents(e,t,n))}catch(e){n()}}};e.addEventListener("load",a),o=setTimeout(a,this.iframesTimeout)}},{key:"onIframeReady",value:function(e,t,n){try{"complete"===e.contentWindow.document.readyState?this.isIframeBlank(e)?this.observeIframeLoad(e,t,n):this.getIframeContents(e,t,n):this.observeIframeLoad(e,t,n)}catch(e){n()}}},{key:"waitForIframes",value:function(e,t){var n=this,r=0;this.forEachIframe(e,function(){return!0},function(e){r++,n.waitForIframes(e.querySelector("html"),function(){--r||t()})},function(e){e||t()})}},{key:"forEachIframe",value:function(t,n,r){var i=this,o=arguments.length>3&&void 0!==arguments[3]?arguments[3]:function(){},a=t.querySelectorAll("iframe"),s=a.length,c=0;a=Array.prototype.slice.call(a);var u=function(){--s<=0&&o(c)};s||u(),a.forEach(function(t){e.matches(t,i.exclude)?u():i.onIframeReady(t,function(e){n(t)&&(c++,r(e)),u()},u)})}},{key:"createIterator",value:function(e,t,n){return document.createNodeIterator(e,t,n,!1)}},{key:"createInstanceOnIframe",value:function(t){return new e(t.querySelector("html"),this.iframes)}},{key:"compareNodeIframe",value:function(e,t,n){if(e.compareDocumentPosition(n)&Node.DOCUMENT_POSITION_PRECEDING){if(null===t)return!0;if(t.compareDocumentPosition(n)&Node.DOCUMENT_POSITION_FOLLOWING)return!0}return!1}},{key:"getIteratorNode",value:function(e){var t=e.previousNode();return{prevNode:t,node:null===t?e.nextNode():e.nextNode()&&e.nextNode()}}},{key:"checkIframeFilter",value:function(e,t,n,r){var i=!1,o=!1;return r.forEach(function(e,t){e.val===n&&(i=t,o=e.handled)}),this.compareNodeIframe(e,t,n)?(!1!==i||o?!1===i||o||(r[i].handled=!0):r.push({val:n,handled:!0}),!0):(!1===i&&r.push({val:n,handled:!1}),!1)}},{key:"handleOpenIframes",value:function(e,t,n,r){var i=this;e.forEach(function(e){e.handled||i.getIframeContents(e.val,function(e){i.createInstanceOnIframe(e).forEachNode(t,n,r)})})}},{key:"iterateThroughNodes",value:function(e,t,n,r,i){for(var o,a=this,s=this.createIterator(t,e,r),c=[],u=[],l=void 0,h=void 0;void 0,o=a.getIteratorNode(s),h=o.prevNode,l=o.node;)this.iframes&&this.forEachIframe(t,function(e){return a.checkIframeFilter(l,h,e,c)},function(t){a.createInstanceOnIframe(t).forEachNode(e,function(e){return u.push(e)},r)}),u.push(l);u.forEach(function(e){n(e)}),this.iframes&&this.handleOpenIframes(c,e,n,r),i()}},{key:"forEachNode",value:function(e,t,n){var r=this,i=arguments.length>3&&void 0!==arguments[3]?arguments[3]:function(){},o=this.getContexts(),a=o.length;a||i(),o.forEach(function(o){var s=function(){r.iterateThroughNodes(e,o,t,n,function(){--a<=0&&i()})};r.iframes?r.waitForIframes(o,s):s()})}}],[{key:"matches",value:function(e,t){var n="string"==typeof t?[t]:t,r=e.matches||e.matchesSelector||e.msMatchesSelector||e.mozMatchesSelector||e.oMatchesSelector||e.webkitMatchesSelector;if(r){var i=!1;return n.every(function(t){return!r.call(e,t)||(i=!0,!1)}),i}return!1}}]),e}(),o=function(){function e(n){t(this,e),this.opt=r({},{diacritics:!0,synonyms:{},accuracy:"partially",caseSensitive:!1,ignoreJoiners:!1,ignorePunctuation:[],wildcards:"disabled"},n)}return n(e,[{key:"create",value:function(e){return"disabled"!==this.opt.wildcards&&(e=this.setupWildcardsRegExp(e)),e=this.escapeStr(e),Object.keys(this.opt.synonyms).length&&(e=this.createSynonymsRegExp(e)),(this.opt.ignoreJoiners||this.opt.ignorePunctuation.length)&&(e=this.setupIgnoreJoinersRegExp(e)),this.opt.diacritics&&(e=this.createDiacriticsRegExp(e)),e=this.createMergedBlanksRegExp(e),(this.opt.ignoreJoiners||this.opt.ignorePunctuation.length)&&(e=this.createJoinersRegExp(e)),"disabled"!==this.opt.wildcards&&(e=this.createWildcardsRegExp(e)),e=this.createAccuracyRegExp(e),new RegExp(e,"gm"+(this.opt.caseSensitive?"":"i"))}},{key:"escapeStr",value:function(e){return e.replace(/[\-\[\]\/\{\}\(\)\*\+\?\.\\\^\$\|]/g,"\\$&")}},{key:"createSynonymsRegExp",value:function(e){var t=this.opt.synonyms,n=this.opt.caseSensitive?"":"i",r=this.opt.ignoreJoiners||this.opt.ignorePunctuation.length?"\0":"";for(var i in t)if(t.hasOwnProperty(i)){var o=t[i],a="disabled"!==this.opt.wildcards?this.setupWildcardsRegExp(i):this.escapeStr(i),s="disabled"!==this.opt.wildcards?this.setupWildcardsRegExp(o):this.escapeStr(o);""!==a&&""!==s&&(e=e.replace(new RegExp("("+this.escapeStr(a)+"|"+this.escapeStr(s)+")","gm"+n),r+"("+this.processSynonyms(a)+"|"+this.processSynonyms(s)+")"+r))}return e}},{key:"processSynonyms",value:function(e){return(this.opt.ignoreJoiners||this.opt.ignorePunctuation.length)&&(e=this.setupIgnoreJoinersRegExp(e)),e}},{key:"setupWildcardsRegExp",value:function(e){return(e=e.replace(/(?:\\)*\?/g,function(e){return"\\"===e.charAt(0)?"?":""})).replace(/(?:\\)*\*/g,function(e){return"\\"===e.charAt(0)?"*":""})}},{key:"createWildcardsRegExp",value:function(e){var t="withSpaces"===this.opt.wildcards;return e.replace(/\u0001/g,t?"[\\S\\s]?":"\\S?").replace(/\u0002/g,t?"[\\S\\s]*?":"\\S*")}},{key:"setupIgnoreJoinersRegExp",value:function(e){return e.replace(/[^(|)\\]/g,function(e,t,n){var r=n.charAt(t+1);return/[(|)\\]/.test(r)||""===r?e:e+"\0"})}},{key:"createJoinersRegExp",value:function(e){var t=[],n=this.opt.ignorePunctuation;return Array.isArray(n)&&n.length&&t.push(this.escapeStr(n.join(""))),this.opt.ignoreJoiners&&t.push("\\u00ad\\u200b\\u200c\\u200d"),t.length?e.split(/\u0000+/).join("["+t.join("")+"]*"):e}},{key:"createDiacriticsRegExp",value:function(e){var t=this.opt.caseSensitive?"":"i",n=this.opt.caseSensitive?["aàáảãạăằắẳẵặâầấẩẫậäåÄÄ…","AÀÃẢÃẠĂẰẮẲẴẶÂẦẤẨẪẬÄÅĀĄ","cçćÄ","CÇĆČ","dÄ‘Ä","DÄÄŽ","eèéẻẽẹêá»áº¿á»ƒá»…ệëěēę","EÈÉẺẼẸÊỀẾỂỄỆËĚĒĘ","iìíỉĩịîïī","IÃŒÃỈĨỊÎÃĪ","lÅ‚","LÅ","nñňń","NÑŇŃ","oòóá»Ãµá»Ã´á»“ốổỗộơởỡớá»á»£Ã¶Ã¸Å","OÒÓỎÕỌÔỒá»á»”ỖỘƠỞỠỚỜỢÖØŌ","rÅ™","RŘ","sšśșş","SŠŚȘŞ","tťțţ","TŤȚŢ","uùúủũụưừứửữựûüůū","UÙÚỦŨỤƯỪỨỬỮỰÛÜŮŪ","yýỳỷỹỵÿ","YÃỲỶỸỴŸ","zžżź","ZŽŻŹ"]:["aàáảãạăằắẳẵặâầấẩẫậäåÄÄ…AÀÃẢÃẠĂẰẮẲẴẶÂẦẤẨẪẬÄÅĀĄ","cçćÄCÇĆČ","dÄ‘ÄDÄÄŽ","eèéẻẽẹêá»áº¿á»ƒá»…ệëěēęEÈÉẺẼẸÊỀẾỂỄỆËĚĒĘ","iìíỉĩịîïīIÃŒÃỈĨỊÎÃĪ","lÅ‚LÅ","nñňńNÑŇŃ","oòóá»Ãµá»Ã´á»“ốổỗộơởỡớá»á»£Ã¶Ã¸ÅOÒÓỎÕỌÔỒá»á»”ỖỘƠỞỠỚỜỢÖØŌ","rÅ™RŘ","sšśșşSŠŚȘŞ","tťțţTŤȚŢ","uùúủũụưừứửữựûüůūUÙÚỦŨỤƯỪỨỬỮỰÛÜŮŪ","yýỳỷỹỵÿYÃỲỶỸỴŸ","zžżźZŽŻŹ"],r=[];return e.split("").forEach(function(i){n.every(function(n){if(-1!==n.indexOf(i)){if(r.indexOf(n)>-1)return!1;e=e.replace(new RegExp("["+n+"]","gm"+t),"["+n+"]"),r.push(n)}return!0})}),e}},{key:"createMergedBlanksRegExp",value:function(e){return e.replace(/[\s]+/gim,"[\\s]+")}},{key:"createAccuracyRegExp",value:function(e){var t=this,n=this.opt.accuracy,r="string"==typeof n?n:n.value,i="";switch(("string"==typeof n?[]:n.limiters).forEach(function(e){i+="|"+t.escapeStr(e)}),r){case"partially":default:return"()("+e+")";case"complementary":return"()([^"+(i="\\s"+(i||this.escapeStr("!\"#$%&'()*+,-./:;<=>?@[\\]^_`{|}~¡¿")))+"]*"+e+"[^"+i+"]*)";case"exactly":return"(^|\\s"+i+")("+e+")(?=$|\\s"+i+")"}}}]),e}(),a=function(){function a(e){t(this,a),this.ctx=e,this.ie=!1;var n=window.navigator.userAgent;(n.indexOf("MSIE")>-1||n.indexOf("Trident")>-1)&&(this.ie=!0)}return n(a,[{key:"log",value:function(t){var n=arguments.length>1&&void 0!==arguments[1]?arguments[1]:"debug",r=this.opt.log;this.opt.debug&&"object"===(void 0===r?"undefined":e(r))&&"function"==typeof r[n]&&r[n]("mark.js: "+t)}},{key:"getSeparatedKeywords",value:function(e){var t=this,n=[];return e.forEach(function(e){t.opt.separateWordSearch?e.split(" ").forEach(function(e){e.trim()&&-1===n.indexOf(e)&&n.push(e)}):e.trim()&&-1===n.indexOf(e)&&n.push(e)}),{keywords:n.sort(function(e,t){return t.length-e.length}),length:n.length}}},{key:"isNumeric",value:function(e){return Number(parseFloat(e))==e}},{key:"checkRanges",value:function(e){var t=this;if(!Array.isArray(e)||"[object Object]"!==Object.prototype.toString.call(e[0]))return this.log("markRanges() will only accept an array of objects"),this.opt.noMatch(e),[];var n=[],r=0;return e.sort(function(e,t){return e.start-t.start}).forEach(function(e){var i=t.callNoMatchOnInvalidRanges(e,r),o=i.start,a=i.end;i.valid&&(e.start=o,e.length=a-o,n.push(e),r=a)}),n}},{key:"callNoMatchOnInvalidRanges",value:function(e,t){var n=void 0,r=void 0,i=!1;return e&&void 0!==e.start?(r=(n=parseInt(e.start,10))+parseInt(e.length,10),this.isNumeric(e.start)&&this.isNumeric(e.length)&&r-t>0&&r-n>0?i=!0:(this.log("Ignoring invalid or overlapping range: "+JSON.stringify(e)),this.opt.noMatch(e))):(this.log("Ignoring invalid range: "+JSON.stringify(e)),this.opt.noMatch(e)),{start:n,end:r,valid:i}}},{key:"checkWhitespaceRanges",value:function(e,t,n){var r=void 0,i=!0,o=n.length,a=t-o,s=parseInt(e.start,10)-a;return(r=(s=s>o?o:s)+parseInt(e.length,10))>o&&(r=o,this.log("End range automatically set to the max value of "+o)),s<0||r-s<0||s>o||r>o?(i=!1,this.log("Invalid range: "+JSON.stringify(e)),this.opt.noMatch(e)):""===n.substring(s,r).replace(/\s+/g,"")&&(i=!1,this.log("Skipping whitespace only range: "+JSON.stringify(e)),this.opt.noMatch(e)),{start:s,end:r,valid:i}}},{key:"getTextNodes",value:function(e){var t=this,n="",r=[];this.iterator.forEachNode(NodeFilter.SHOW_TEXT,function(e){r.push({start:n.length,end:(n+=e.textContent).length,node:e})},function(e){return t.matchesExclude(e.parentNode)?NodeFilter.FILTER_REJECT:NodeFilter.FILTER_ACCEPT},function(){e({value:n,nodes:r})})}},{key:"matchesExclude",value:function(e){return i.matches(e,this.opt.exclude.concat(["script","style","title","head","html"]))}},{key:"wrapRangeInTextNode",value:function(e,t,n){var r=this.opt.element?this.opt.element:"mark",i=e.splitText(t),o=i.splitText(n-t),a=document.createElement(r);return a.setAttribute("data-markjs","true"),this.opt.className&&a.setAttribute("class",this.opt.className),a.textContent=i.textContent,i.parentNode.replaceChild(a,i),o}},{key:"wrapRangeInMappedTextNode",value:function(e,t,n,r,i){var o=this;e.nodes.every(function(a,s){var c=e.nodes[s+1];if(void 0===c||c.start>t){if(!r(a.node))return!1;var u=t-a.start,l=(n>a.end?a.end:n)-a.start,h=e.value.substr(0,a.start),f=e.value.substr(l+a.start);if(a.node=o.wrapRangeInTextNode(a.node,u,l),e.value=h+f,e.nodes.forEach(function(t,n){n>=s&&(e.nodes[n].start>0&&n!==s&&(e.nodes[n].start-=l),e.nodes[n].end-=l)}),n-=l,i(a.node.previousSibling,a.start),!(n>a.end))return!1;t=a.end}return!0})}},{key:"wrapGroups",value:function(e,t,n,r){return r((e=this.wrapRangeInTextNode(e,t,t+n)).previousSibling),e}},{key:"separateGroups",value:function(e,t,n,r,i){for(var o=t.length,a=1;a-1&&r(t[a],e)&&(e=this.wrapGroups(e,s,t[a].length,i))}return e}},{key:"wrapMatches",value:function(e,t,n,r,i){var o=this,a=0===t?0:t+1;this.getTextNodes(function(t){t.nodes.forEach(function(t){t=t.node;for(var i=void 0;null!==(i=e.exec(t.textContent))&&""!==i[a];){if(o.opt.separateGroups)t=o.separateGroups(t,i,a,n,r);else{if(!n(i[a],t))continue;var s=i.index;if(0!==a)for(var c=1;c + + + + + Rust UEFI Book + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ +
+ + + + + + + +
+
+

Introduction

+

Welcome to the Rust UEFI Book. The focus of this book is how to use +uefi-rs to build UEFI applications in Rust, but it also describes +some general UEFI concepts, as well as relevant tools such as QEMU.

+

Tutorial

+

This tutorial describes the process of creating and running a simple +x86_64 UEFI application in Rust. The application will print "Hello +World", pause for 10 seconds, then exit.

+

Creating a UEFI application

+

Install dependencies

+

Follow the Rust installation instructions to set up Rust.

+

Create a minimal application

+

Create an empty application and change to that directory:

+
cargo new my-uefi-app
+cd my-uefi-app
+
+

Add a few dependencies:

+
cargo add log uefi uefi-services
+
+

Replace the contents of src/main.rs with this:

+
#![no_main]
+#![no_std]
+
+use log::info;
+use uefi::prelude::*;
+
+#[entry]
+fn main(_image_handle: Handle, mut system_table: SystemTable<Boot>) -> Status {
+    uefi_services::init(&mut system_table).unwrap();
+    info!("Hello world!");
+    system_table.boot_services().stall(10_000_000);
+    Status::SUCCESS
+}
+
+

Walkthrough

+

Let's look a quick look at what each part of the program is doing, +starting with the #![...] lines at the top:

+
#![allow(unused)]
+#![no_main]
+#![no_std]
+fn main() {
+}
+
+

This is some boilerplate that all Rust UEFI applications will +need. no_main is needed because the UEFI application entry point is +different from the standard Rust main function. no_std is needed to +turn off the std library; the core and alloc crates can still be +used.

+

Next up are some use lines. Nothing too exciting here; the +uefi::prelude module is intended to be glob-imported, and exports a +number of commonly-used types.

+
#![allow(unused)]
+fn main() {
+use log::info;
+use uefi::prelude::*;
+}
+
+

Now we get to the UEFI application main function, and here things look +a little different from a standard Rust program.

+
#[entry]
+fn main(_image_handle: Handle, mut system_table: SystemTable<Boot>) -> Status {
+
+

The main function in a Uefi application always takes two arguments, +the image handle and the system table. The image handle represents the +currently-running executable, and the system table provides access to +many different UEFI services. The main function returns a Status, +which is essentially a numeric error (or success) code defined by UEFI.

+

The first thing we do inside of main is initialize uefi_services:

+
#![allow(unused)]
+fn main() {
+    uefi_services::init(&mut system_table).unwrap();
+}
+
+

The uefi_services crate is not strictly required to make a UEFI +application with the uefi crate, but it makes things much simpler by +setting a simple memory allocator, initializing the logger, and +providing a panic handler.

+

Next we use the standard log crate to output "Hello world!". Then we +call stall to make the system pause for 10 seconds. This just ensures +you have enough time to see the output.

+
#![allow(unused)]
+fn main() {
+    info!("Hello world!");
+    system_table.boot_services().stall(10_000_000);
+}
+
+

Finally we return Status::SUCCESS indicating that everything completed +successfully:

+
#![allow(unused)]
+fn main() {
+    Status::SUCCESS
+}
+}
+
+

Building

+

Toolchain

+

In order to compile for UEFI, an appropriate target must be installed. The +easiest way to set this up is using a rustup toolchain file. In the root of +your repository, add rust-toolchain.toml:

+
[toolchain]
+targets = ["aarch64-unknown-uefi", "i686-unknown-uefi", "x86_64-unknown-uefi"]
+
+

Here we have specified all three of the currently-supported UEFI targets; you +can remove some if you don't need them.

+

Build the application

+

Run this command to build the application:

+
cargo build --target x86_64-unknown-uefi
+
+

This will produce an x86-64 executable: +target/x86_64-unknown-uefi/debug/my-uefi-app.efi.

+

Running in a VM

+

Install dependencies

+

Two dependencies are needed: QEMU, which implements the virtual +machine itself, and OVMF, which provides UEFI firmware that QEMU can +run.

+

The details of how to install QEMU and OVMF will vary depending on your +operating system.

+

Debian/Ubuntu:

+
sudo apt-get install qemu ovmf
+
+

Fedora:

+
sudo dnf install qemu-kvm edk2-ovmf
+
+

Firmware files

+

The OVMF package provides two firmware files, one for the executable +code and one for variable storage. (The package may provide multiple +variations of these files; refer to the package's documentation for +details of the files it includes.)

+

For ease of access we'll copy the OVMF code and vars files to the +project directory. The location where OVMF is installed depends on your +operating system; for Debian, Ubuntu and Fedora the files are under +/usr/share/OVMF.

+

Copy the files to your project directory:

+
cp /usr/share/OVMF/OVMF_CODE.fd .
+cp /usr/share/OVMF/OVMF_VARS.fd .
+
+

System partition

+

Now create a directory structure containing the executable to imitate a +UEFI System Partition:

+
mkdir -p esp/efi/boot
+cp target/x86_64-unknown-uefi/debug/my-uefi-app.efi esp/efi/boot/bootx64.efi
+
+

Launch the VM

+

Now we can launch QEMU, using VVFAT to access the esp directory created above.

+
qemu-system-x86_64 -enable-kvm \
+    -drive if=pflash,format=raw,readonly=on,file=OVMF_CODE.fd \
+    -drive if=pflash,format=raw,readonly=on,file=OVMF_VARS.fd \
+    -drive format=raw,file=fat:rw:esp
+
+

A QEMU window should appear, and after a few seconds you should see the +log message:

+
[ INFO]:  src/main.rs@011: Hello world!
+
+

Running on Hardware

+

To run on real hardware you'll need a specially-prepared USB drive.

+

Preparation

+

The general steps to prepare the drive are:

+
    +
  1. Partition the drive using GPT.
  2. +
  3. Create a partition.
  4. +
  5. Set the partition type GUID to +C12A7328-F81F-11D2-BA4B-00A0C93EC93B. That marks it as an EFI +System partition. (On many UEFI implementations this is not strictly +necessary, see note below.)
  6. +
  7. Format the partition as FAT.
  8. +
  9. Mount the partition.
  10. +
  11. Create the directory path EFI/BOOT on the partition. (FAT is case +insensitive, so capitalization doesn't matter.)
  12. +
  13. Copy your EFI application to a file under EFI/BOOT. The file name +is specific to the architecture. For example, on x86_64 the file name +must be BOOTX64.EFI. See the boot files table for other +architectures.
  14. +
+

The details of exactly how to do these steps will vary depending on your OS.

+

Note that most UEFI implementations do not strictly require GPT +partitioning or the EFI System partition GUID; they will look for any +FAT partition with the appropriate directory structure. This is not +required however; the UEFI Specification says "UEFI implementations may +allow the use of conforming FAT partitions which do not use the ESP +GUID."

+

Example on Linux

+

Warning: these operations are destructive! Do not run these commands +on a disk if you care about the data it contains.

+
# Create the GPT, create a 9MB partition starting at 1MB, and set the
+# partition type to EFI System.
+sgdisk \
+    --clear \
+    --new=1:1M:10M \
+    --typecode=1:C12A7328-F81F-11D2-BA4B-00A0C93EC93B \
+    /path/to/disk
+
+# Format the partition as FAT.
+mkfs.fat /path/to/disk_partition
+
+# Mount the partition.
+mkdir esp
+mount /path/to/disk_partition esp
+
+# Create the boot directory.
+mkdir esp/EFI/BOOT
+
+# Copy in the boot executable.
+cp /path/to/your-executable.efi esp/EFI/BOOT/BOOTX64.EFI
+
+

Booting the USB

+

Insert the USB into the target computer. Reboot the machine, then press +the one-time boot key. Which key to press depends on the vendor. For +example, Dell uses F12, HP uses F9, and on Macs you hold down the Option +key.

+

Once the one-time boot menu appears, select your USB drive and press enter.

+

How-to

+

This chapter contains practical how-to guides.

+

Using Protocols

+

The open a protocol, you must first get a handle, then open a protocol +on that handle. See Handles and Protocols for an overview of what +these terms mean.

+

To get a handle you can use:

+ +

Once you have obtained a handle, use +BootServices::open_protocol_exclusive to open a protocol on that +handle. This returns a ScopedProtocol, which automatically closes +the protocol when dropped.

+

Using BootServices::open_protocol_exclusive is the safest way to +open a protocol, but in some cases a protocol cannot be opened in +exclusive mode. The unsafe BootServices::open_protocol can be used +in that case.

+

Example

+

For this example we'll look at a program that opens a couple different +protocols. This program opens the LoadedImage protocol to get +information about an executable (the currently-running program in this +case). It also opens the DevicePathToText protocol to get the file +system path that the program was launched from.

+

We'll walk through the details of this program shortly, but first here's +the whole thing:

+
#![no_main]
+#![no_std]
+
+use log::info;
+use uefi::prelude::*;
+use uefi::proto::device_path::text::{
+    AllowShortcuts, DevicePathToText, DisplayOnly,
+};
+use uefi::proto::loaded_image::LoadedImage;
+use uefi::table::boot::SearchType;
+use uefi::{Identify, Result};
+
+#[entry]
+fn main(image_handle: Handle, mut system_table: SystemTable<Boot>) -> Status {
+    uefi_services::init(&mut system_table).unwrap();
+    let boot_services = system_table.boot_services();
+
+    print_image_path(boot_services).unwrap();
+
+    boot_services.stall(10_000_000);
+    Status::SUCCESS
+}
+
+fn print_image_path(boot_services: &BootServices) -> Result {
+    let loaded_image = boot_services
+        .open_protocol_exclusive::<LoadedImage>(boot_services.image_handle())?;
+
+    let device_path_to_text_handle = *boot_services
+        .locate_handle_buffer(SearchType::ByProtocol(&DevicePathToText::GUID))?
+        .first()
+        .expect("DevicePathToText is missing");
+
+    let device_path_to_text = boot_services
+        .open_protocol_exclusive::<DevicePathToText>(
+            device_path_to_text_handle,
+        )?;
+
+    let image_device_path =
+        loaded_image.file_path().expect("File path is not set");
+    let image_device_path_text = device_path_to_text
+        .convert_device_path_to_text(
+            boot_services,
+            image_device_path,
+            DisplayOnly(true),
+            AllowShortcuts(false),
+        )
+        .expect("convert_device_path_to_text failed");
+
+    info!("Image path: {}", &*image_device_path_text);
+    Ok(())
+}
+
+

When the program is run it will print something like this:

+
[ INFO]: example.rs@058: Image path: \EFI\BOOT\BOOTX64.EFI
+
+

Walkthrough

+

The main function looks much like the "Hello world!" example. It +sets up logging, calls print_image_path, and pauses for ten seconds to +give you time to read the output. Let's look at print_image_path:

+
#![allow(unused)]
+fn main() {
+fn print_image_path(boot_services: &BootServices) -> Result {
+}
+
+

The return type is a uefi::Result, which is a Result alias that +combines uefi::Status with the error data. Both the success and +error data types are () by default.

+

The function starts by opening the LoadedImage protocol:

+
#![allow(unused)]
+fn main() {
+    let loaded_image = boot_services
+        .open_protocol_exclusive::<LoadedImage>(boot_services.image_handle())?;
+}
+
+

The open_protocol_exclusive method takes a type parameter, which is +the type of Protocol you want to open (LoadedImage in this +case). It also takes one regular argument of type Handle. For this +example we want the handle of the currently-running image, which was +passed in as the first argument to main. The handle is conveniently +accessible through BootServices::image_handle, so we use that here.

+

Next the program opens the DevicePathToText protocol:

+
#![allow(unused)]
+fn main() {
+    let device_path_to_text_handle = *boot_services
+        .locate_handle_buffer(SearchType::ByProtocol(&DevicePathToText::GUID))?
+        .first()
+        .expect("DevicePathToText is missing");
+
+    let device_path_to_text = boot_services
+        .open_protocol_exclusive::<DevicePathToText>(
+            device_path_to_text_handle,
+        )?;
+}
+
+

This protocol isn't available for the image_handle, so we start by +using locate_handle_buffer to find all handles that support +DevicePathToText. We only need one handle though, so we call first() +and discard the rest. Then we call open_protocol_exclusive again. It +looks more or less like the previous time, but with DevicePathToText +as the type parameter and device_path_to_text_handle as the handle.

+

Now that we have both protocols open, we can use them together to get +the program's path and convert it to text:

+
#![allow(unused)]
+fn main() {
+    let image_device_path =
+        loaded_image.file_path().expect("File path is not set");
+    let image_device_path_text = device_path_to_text
+        .convert_device_path_to_text(
+            boot_services,
+            image_device_path,
+            DisplayOnly(true),
+            AllowShortcuts(false),
+        )
+        .expect("convert_device_path_to_text failed");
+
+    info!("Image path: {}", &*image_device_path_text);
+    Ok(())
+}
+}
+
+

Since protocols do a wide range of different things, the methods +available to call are very specific to each individual protocol. The +best places to find out what each protocol can do are the uefi-rs +reference documentation and the UEFI Specification.

+

Drawing to the Screen

+

This example shows how to draw to the screen using the graphics output protocol. +The code will a Sierpiński triangle using the "chaos game" method.

+

screenshot

+

The core abstraction used here is a linear buffer:

+
#![allow(unused)]
+fn main() {
+struct Buffer {
+    width: usize,
+    height: usize,
+    pixels: Vec<BltPixel>,
+}
+
+impl Buffer {
+    /// Create a new `Buffer`.
+    fn new(width: usize, height: usize) -> Self {
+        Buffer {
+            width,
+            height,
+            pixels: vec![BltPixel::new(0, 0, 0); width * height],
+        }
+    }
+
+    /// Get a single pixel.
+    fn pixel(&mut self, x: usize, y: usize) -> Option<&mut BltPixel> {
+        self.pixels.get_mut(y * self.width + x)
+    }
+
+    /// Blit the buffer to the framebuffer.
+    fn blit(&self, gop: &mut GraphicsOutput) -> Result {
+        gop.blt(BltOp::BufferToVideo {
+            buffer: &self.pixels,
+            src: BltRegion::Full,
+            dest: (0, 0),
+            dims: (self.width, self.height),
+        })
+    }
+}
+}
+
+

This Buffer type stores a Vec of BltPixels, which are BGRX +32-bit pixels (8 bites each for blue, green, and red, followed by 8 +unused bits of padding). We use the pixel method to alter a single +pixel at a time. This is often not an efficient method; for more complex +graphics you could use a crate like embedded-graphics.

+

The Buffer::blit method calls the graphics output protocol's blt +method to copy the buffer to the screen.

+

Most of the rest of the code is just implementing the algorithm for +drawing the fractal. Here's the full example:

+
#![no_main]
+#![no_std]
+
+extern crate alloc;
+
+use alloc::vec;
+use alloc::vec::Vec;
+use core::mem;
+use uefi::prelude::*;
+use uefi::proto::console::gop::{BltOp, BltPixel, BltRegion, GraphicsOutput};
+use uefi::proto::rng::Rng;
+use uefi::table::boot::BootServices;
+use uefi::Result;
+
+#[derive(Clone, Copy)]
+struct Point {
+    x: f32,
+    y: f32,
+}
+
+impl Point {
+    fn new(x: f32, y: f32) -> Self {
+        Self { x, y }
+    }
+}
+
+struct Buffer {
+    width: usize,
+    height: usize,
+    pixels: Vec<BltPixel>,
+}
+
+impl Buffer {
+    /// Create a new `Buffer`.
+    fn new(width: usize, height: usize) -> Self {
+        Buffer {
+            width,
+            height,
+            pixels: vec![BltPixel::new(0, 0, 0); width * height],
+        }
+    }
+
+    /// Get a single pixel.
+    fn pixel(&mut self, x: usize, y: usize) -> Option<&mut BltPixel> {
+        self.pixels.get_mut(y * self.width + x)
+    }
+
+    /// Blit the buffer to the framebuffer.
+    fn blit(&self, gop: &mut GraphicsOutput) -> Result {
+        gop.blt(BltOp::BufferToVideo {
+            buffer: &self.pixels,
+            src: BltRegion::Full,
+            dest: (0, 0),
+            dims: (self.width, self.height),
+        })
+    }
+}
+
+/// Get a random `usize` value.
+fn get_random_usize(rng: &mut Rng) -> usize {
+    let mut buf = [0; mem::size_of::<usize>()];
+    rng.get_rng(None, &mut buf).expect("get_rng failed");
+    usize::from_le_bytes(buf)
+}
+
+fn draw_sierpinski(bt: &BootServices) -> Result {
+    // Open graphics output protocol.
+    let gop_handle = bt.get_handle_for_protocol::<GraphicsOutput>()?;
+    let mut gop = bt.open_protocol_exclusive::<GraphicsOutput>(gop_handle)?;
+
+    // Open random number generator protocol.
+    let rng_handle = bt.get_handle_for_protocol::<Rng>()?;
+    let mut rng = bt.open_protocol_exclusive::<Rng>(rng_handle)?;
+
+    // Create a buffer to draw into.
+    let (width, height) = gop.current_mode_info().resolution();
+    let mut buffer = Buffer::new(width, height);
+
+    // Initialize the buffer with a simple gradient background.
+    for y in 0..height {
+        let r = ((y as f32) / ((height - 1) as f32)) * 255.0;
+        for x in 0..width {
+            let g = ((x as f32) / ((width - 1) as f32)) * 255.0;
+            let pixel = buffer.pixel(x, y).unwrap();
+            pixel.red = r as u8;
+            pixel.green = g as u8;
+            pixel.blue = 255;
+        }
+    }
+
+    let size = Point::new(width as f32, height as f32);
+
+    // Define the vertices of a big triangle.
+    let border = 20.0;
+    let triangle = [
+        Point::new(size.x / 2.0, border),
+        Point::new(border, size.y - border),
+        Point::new(size.x - border, size.y - border),
+    ];
+
+    // `p` is the point to draw. Start at the center of the triangle.
+    let mut p = Point::new(size.x / 2.0, size.y / 2.0);
+
+    // Loop forever, drawing the frame after each new point is changed.
+    loop {
+        // Choose one of the triangle's vertices at random.
+        let v = triangle[get_random_usize(&mut rng) % 3];
+
+        // Move `p` halfway to the chosen vertex.
+        p.x = (p.x + v.x) * 0.5;
+        p.y = (p.y + v.y) * 0.5;
+
+        // Set `p` to black.
+        let pixel = buffer.pixel(p.x as usize, p.y as usize).unwrap();
+        pixel.red = 0;
+        pixel.green = 100;
+        pixel.blue = 0;
+
+        // Draw the buffer to the screen.
+        buffer.blit(&mut gop)?;
+    }
+}
+
+#[entry]
+fn main(_handle: Handle, mut system_table: SystemTable<Boot>) -> Status {
+    uefi_services::init(&mut system_table).unwrap();
+    let bt = system_table.boot_services();
+    draw_sierpinski(bt).unwrap();
+    Status::SUCCESS
+}
+
+

You can run this example from the uefi-rs repository with:

+
cargo xtask run --example sierpinski
+
+

Building drivers

+

There are three types of UEFI images:

+
    +
  • Application
  • +
  • Boot service driver
  • +
  • Runtime driver
  • +
+

By default, Rust's UEFI targets produce applications. This can be +changed by passing a subsystem linker flag in rustflags and setting the +value to efi_boot_service_driver or efi_runtime_driver.

+

Example:

+
# In .cargo/config.toml:
+[build]
+rustflags = ["-C", "link-args=/subsystem:efi_runtime_driver"]
+
+

Concepts

+

The canonical source of information about UEFI is the UEFI specification. +The specification is huge (currently nearly 2500 pages). Much of that +content relates to optional services, understanding of which is not +critical to understanding UEFI as a whole. This chapter summarizes some +of the more important UEFI concepts and links to the relevant uefi-rs +documentation.

+

Boot Stages

+

A UEFI system goes through several distinct phases during the boot process.

+
    +
  1. Platform Initialization. This early-boot phase is mostly outside +the scope of uefi-rs. It is described by the UEFI Platform +Initialization Specification, which is separate from the main UEFI +Specification.
  2. +
  3. Boot Services. This is when UEFI drivers and applications are +loaded. Both the BootServices and RuntimeServices tables are +accessible. This stage typically culminates in running a bootloader +that loads an operating system. The stage ends when +SystemTable::exit_boot_services is called, putting the system in +Runtime mode.
  4. +
  5. Runtime. This stage is typically active when running an operating +system such as Linux or Windows. UEFI functionality is much more +limited in the Runtime mode. The BootServices table is no longer +accessible, but the RuntimeServices table is still +available. Once the system is in Runtime mode, it cannot return to +the Boot Services stage until after a system reset.
  6. +
+

Tables

+

UEFI has a few table structures. These tables are how you get access to +UEFI services.

+

SystemTable (EFI_SYSTEM_TABLE in the specification) is the +top-level table that provides access to the other tables.

+

BootServices (EFI_BOOT_SERVICES in the specification) provides +access to a wide array of services such as memory allocation, executable +loading, and optional extension interfaces called protocols. This table +is only accessible while in the Boot Services stage.

+

RuntimeServices (EFI_RUNTIME_SERVICES in the specification) +provides access to a fairly limited set of services, including variable +storage, system time, and virtual-memory mapping. This table is +accessible during both the Boot Services and Runtime stages.

+

When writing a UEFI application, you get access to the system table from +one of the arguments to the main entry point:

+
fn main(handle: Handle, mut system_table: SystemTable<Boot>) -> Status;
+
+

Then use SystemTable::boot_services and +SystemTable::runtime_services to get access to the other +tables. Once SystemTable::exit_boot_services is called, the original +system table is consumed and a new system table is returned that only +provides access to the RuntimeServices table.

+

GUID

+

GUID is short for Globally Unique Identifier. A GUID is always 16 bytes, +and has a standard string representation format that looks like this: +313b0d7c-fed4-4de7-99ed-2fe48874a410. The details of the GUID format +aren't too important, but be aware that the actual byte representation +is not in the same order as the string representation because the first +three fields are little-endian. For the most part you can treat GUIDs as +opaque identifiers.

+

The UEFI specification uses GUIDs all over the place. GUIDs are used to +identify protocols, disk partitions, variable groupings, and much +more. In uefi-rs, GUIDs are represented by the Guid type.

+

Handles and Protocols

+

Handles and protocols are at the core of what makes UEFI +extensible. Together they are the mechanism by which UEFI can adapt to a +wide array of hardware and boot conditions, while still providing a +consistent interface to drivers and applications.

+

Handles

+

Handles represent resources. A resource might be a physical device such +as a disk drive or USB device, or something less tangible like a loaded +executable.

+

A Handle is an opaque pointer, so you can't do anything with it +directly. To operate on a handle you have to open a protocol.

+

Protocols

+

Protocols are interfaces that provide functions to interact with a +resource. For example, the BlockIO protocol provides functions to read +and write to block IO devices.

+

Protocols are only available during the Boot Services stage; you can't +access them during the Runtime stage.

+

The UEFI Specification defines a very large number of protocols. Because +protocols are inherently very diverse, the best place to learn about +individual protocols is the UEFI Specification. There are many +chapters covering various protocols. Not all of these protocols are +wrapped by uefi-rs yet (contributions welcome!) but many of the most +commonly useful ones are.

+

See the Using Protocols how-to for details of the uefi-rs API for +interacting with protocols.

+

Device Paths

+

A device path is a very flexible packed data structure for storing paths +to many kinds of device. Note that these device paths are not the same +thing as file system paths, although they can include file system +paths. Like handles, device paths can be used to uniquely identify +resources such as consoles, mice, disks, partitions, and more. Unlike +handles, which are essentially opaque pointers, device paths are +variable-length structures that contain parseable information.

+

The uefi::proto::device_path module documentation describes the +details of how device paths are encoded.

+

Device paths can also be converted to and from human-readable text +representations that look like this:

+
PciRoot(0x0)/Pci(0x1F,0x2)/Sata(0x0,0xFFFF,0x0)/HD(1,MBR,0xBE1AFDFA,0x3F,0xFBFC1)
+
+

See uefi::proto::device_path::text for details.

+

Variables

+

UEFI provides fairly flexible key/value variable storage.

+

Each variable is identified by a key consisting of a UCS-2 +null-terminated name plus a vendor GUID. The vendor GUID serves as a +namespace for variables so that different vendors don't accidentally +overwrite or misinterpret another vendor's variable if they happen to +have the same name.

+

The data stored in each variable is an arbitrary byte array.

+

Attributes

+

Each variable has attributes (represented as bit flags) associated with +it that affect how it is stored and how it can be accessed.

+

If the BOOTSERVICE_ACCESS and RUNTIME_ACCESS bits are set, the +variable can be accessed during both the Boot Services and Runtime +stages. If only BOOTSERVICE_ACCESS is set then the variable can +neither be read nor written to after exiting boot services.

+

Another important attribute is the NON_VOLATILE bit. If this bit is +not set, the variable will be stored in normal memory and will not +persist across a power cycle. If this bit is set, the variable will be +stored in special non-volatile memory. You should be careful about +writing variables of this type, because the non-volatile storage can be +very limited in size. There have been cases where a vendor's poor UEFI +implementation caused the machine not too boot once the storage became +too full. Even figuring out how much space is in use can be tricky due +to deletion being implemented via garbage collection. Matthew Garret's +article "Dealing with UEFI non-volatile memory quirks" has more details.

+

Most of the other attributes relate to authenticated variables, which +can be used to prevent changes to a variable by unauthorized programs.

+

GPT

+

GPT is short for GUID Partition Table. It's a more modern +alternative to MBR (master boot record) partition tables. Although it's +defined in the UEFI specification, it often gets used on non-UEFI +systems too. There are a couple big advantages of using GPT over MBR:

+
    +
  • It has a relatively clear and precise standard, unlike MBR where +implementations often just try to match what other implementations do.
  • +
  • It supports very large disks and very large numbers of partitions.
  • +
+

A GPT disk contains a primary header near the beginning of the disk, +followed by a partition entry array. The header and partition entry +array have a secondary copy at the end of the disk for redundancy. The +partition entry arrays contain structures that describe each partition, +including a GUID to identify the individual partition, a partition type +GUID to indicate the purpose of the partition, and start/end block +addresses. In between the entry arrays is the actual partition data.

+

System partition

+

The system partition is UEFI's version of a bootable partition. The +system partition is sometimes called the ESP, or EFI System +Partition. It is identified by a partition type of +c12a7328-f81f-11d2-ba4b-00a0c93ec93b. The system partition always +contains a FAT file system. There are various standardized paths that +can exist within the file system, and of particular importance are the +boot files. These are the files that UEFI will try to boot from by +default (in the absence of a different boot configuration set through +special UEFI variables).

+

Boot files are under \EFI\BOOT, and are named BOOT<ARCH>.efi, where +<ARCH> is a short architecture name.

+
+ + + + + + + + +
ArchitectureFile name
Intel 32-bitBOOTIA32.EFI
X86_64BOOTX64.EFI
ItaniumBOOTIA64.EFI
AArch32BOOTARM.EFI
AArch64BOOTAA64.EFI
RISC-V 32-bitBOOTRISCV32.EFI
RISC-V 64-bitBOOTRISCV64.EFI
RISC-V 128-bitBOOTRISCV128.EFI
+

Reference

+ + +
+ + +
+
+ + + +
+ + + + + + + + + + + + + diff --git a/HEAD/reference.html b/HEAD/reference.html new file mode 100644 index 000000000..4e5c2fe5e --- /dev/null +++ b/HEAD/reference.html @@ -0,0 +1,179 @@ + + + + + + Reference - Rust UEFI Book + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ +
+ + + + + + + + +
+ + + +
+ + + + + + + + + + + + diff --git a/HEAD/searcher.js b/HEAD/searcher.js new file mode 100644 index 000000000..d2b0aeed3 --- /dev/null +++ b/HEAD/searcher.js @@ -0,0 +1,483 @@ +"use strict"; +window.search = window.search || {}; +(function search(search) { + // Search functionality + // + // You can use !hasFocus() to prevent keyhandling in your key + // event handlers while the user is typing their search. + + if (!Mark || !elasticlunr) { + return; + } + + //IE 11 Compatibility from https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/String/startsWith + if (!String.prototype.startsWith) { + String.prototype.startsWith = function(search, pos) { + return this.substr(!pos || pos < 0 ? 0 : +pos, search.length) === search; + }; + } + + var search_wrap = document.getElementById('search-wrapper'), + searchbar = document.getElementById('searchbar'), + searchbar_outer = document.getElementById('searchbar-outer'), + searchresults = document.getElementById('searchresults'), + searchresults_outer = document.getElementById('searchresults-outer'), + searchresults_header = document.getElementById('searchresults-header'), + searchicon = document.getElementById('search-toggle'), + content = document.getElementById('content'), + + searchindex = null, + doc_urls = [], + results_options = { + teaser_word_count: 30, + limit_results: 30, + }, + search_options = { + bool: "AND", + expand: true, + fields: { + title: {boost: 1}, + body: {boost: 1}, + breadcrumbs: {boost: 0} + } + }, + mark_exclude = [], + marker = new Mark(content), + current_searchterm = "", + URL_SEARCH_PARAM = 'search', + URL_MARK_PARAM = 'highlight', + teaser_count = 0, + + SEARCH_HOTKEY_KEYCODE = 83, + ESCAPE_KEYCODE = 27, + DOWN_KEYCODE = 40, + UP_KEYCODE = 38, + SELECT_KEYCODE = 13; + + function hasFocus() { + return searchbar === document.activeElement; + } + + function removeChildren(elem) { + while (elem.firstChild) { + elem.removeChild(elem.firstChild); + } + } + + // Helper to parse a url into its building blocks. + function parseURL(url) { + var a = document.createElement('a'); + a.href = url; + return { + source: url, + protocol: a.protocol.replace(':',''), + host: a.hostname, + port: a.port, + params: (function(){ + var ret = {}; + var seg = a.search.replace(/^\?/,'').split('&'); + var len = seg.length, i = 0, s; + for (;i': '>', + '"': '"', + "'": ''' + }; + var repl = function(c) { return MAP[c]; }; + return function(s) { + return s.replace(/[&<>'"]/g, repl); + }; + })(); + + function formatSearchMetric(count, searchterm) { + if (count == 1) { + return count + " search result for '" + searchterm + "':"; + } else if (count == 0) { + return "No search results for '" + searchterm + "'."; + } else { + return count + " search results for '" + searchterm + "':"; + } + } + + function formatSearchResult(result, searchterms) { + var teaser = makeTeaser(escapeHTML(result.doc.body), searchterms); + teaser_count++; + + // The ?URL_MARK_PARAM= parameter belongs inbetween the page and the #heading-anchor + var url = doc_urls[result.ref].split("#"); + if (url.length == 1) { // no anchor found + url.push(""); + } + + // encodeURIComponent escapes all chars that could allow an XSS except + // for '. Due to that we also manually replace ' with its url-encoded + // representation (%27). + var searchterms = encodeURIComponent(searchterms.join(" ")).replace(/\'/g, "%27"); + + return '' + result.doc.breadcrumbs + '' + + '' + + teaser + ''; + } + + function makeTeaser(body, searchterms) { + // The strategy is as follows: + // First, assign a value to each word in the document: + // Words that correspond to search terms (stemmer aware): 40 + // Normal words: 2 + // First word in a sentence: 8 + // Then use a sliding window with a constant number of words and count the + // sum of the values of the words within the window. Then use the window that got the + // maximum sum. If there are multiple maximas, then get the last one. + // Enclose the terms in . + var stemmed_searchterms = searchterms.map(function(w) { + return elasticlunr.stemmer(w.toLowerCase()); + }); + var searchterm_weight = 40; + var weighted = []; // contains elements of ["word", weight, index_in_document] + // split in sentences, then words + var sentences = body.toLowerCase().split('. '); + var index = 0; + var value = 0; + var searchterm_found = false; + for (var sentenceindex in sentences) { + var words = sentences[sentenceindex].split(' '); + value = 8; + for (var wordindex in words) { + var word = words[wordindex]; + if (word.length > 0) { + for (var searchtermindex in stemmed_searchterms) { + if (elasticlunr.stemmer(word).startsWith(stemmed_searchterms[searchtermindex])) { + value = searchterm_weight; + searchterm_found = true; + } + }; + weighted.push([word, value, index]); + value = 2; + } + index += word.length; + index += 1; // ' ' or '.' if last word in sentence + }; + index += 1; // because we split at a two-char boundary '. ' + }; + + if (weighted.length == 0) { + return body; + } + + var window_weight = []; + var window_size = Math.min(weighted.length, results_options.teaser_word_count); + + var cur_sum = 0; + for (var wordindex = 0; wordindex < window_size; wordindex++) { + cur_sum += weighted[wordindex][1]; + }; + window_weight.push(cur_sum); + for (var wordindex = 0; wordindex < weighted.length - window_size; wordindex++) { + cur_sum -= weighted[wordindex][1]; + cur_sum += weighted[wordindex + window_size][1]; + window_weight.push(cur_sum); + }; + + if (searchterm_found) { + var max_sum = 0; + var max_sum_window_index = 0; + // backwards + for (var i = window_weight.length - 1; i >= 0; i--) { + if (window_weight[i] > max_sum) { + max_sum = window_weight[i]; + max_sum_window_index = i; + } + }; + } else { + max_sum_window_index = 0; + } + + // add around searchterms + var teaser_split = []; + var index = weighted[max_sum_window_index][2]; + for (var i = max_sum_window_index; i < max_sum_window_index+window_size; i++) { + var word = weighted[i]; + if (index < word[2]) { + // missing text from index to start of `word` + teaser_split.push(body.substring(index, word[2])); + index = word[2]; + } + if (word[1] == searchterm_weight) { + teaser_split.push("") + } + index = word[2] + word[0].length; + teaser_split.push(body.substring(word[2], index)); + if (word[1] == searchterm_weight) { + teaser_split.push("") + } + }; + + return teaser_split.join(''); + } + + function init(config) { + results_options = config.results_options; + search_options = config.search_options; + searchbar_outer = config.searchbar_outer; + doc_urls = config.doc_urls; + searchindex = elasticlunr.Index.load(config.index); + + // Set up events + searchicon.addEventListener('click', function(e) { searchIconClickHandler(); }, false); + searchbar.addEventListener('keyup', function(e) { searchbarKeyUpHandler(); }, false); + document.addEventListener('keydown', function(e) { globalKeyHandler(e); }, false); + // If the user uses the browser buttons, do the same as if a reload happened + window.onpopstate = function(e) { doSearchOrMarkFromUrl(); }; + // Suppress "submit" events so the page doesn't reload when the user presses Enter + document.addEventListener('submit', function(e) { e.preventDefault(); }, false); + + // If reloaded, do the search or mark again, depending on the current url parameters + doSearchOrMarkFromUrl(); + } + + function unfocusSearchbar() { + // hacky, but just focusing a div only works once + var tmp = document.createElement('input'); + tmp.setAttribute('style', 'position: absolute; opacity: 0;'); + searchicon.appendChild(tmp); + tmp.focus(); + tmp.remove(); + } + + // On reload or browser history backwards/forwards events, parse the url and do search or mark + function doSearchOrMarkFromUrl() { + // Check current URL for search request + var url = parseURL(window.location.href); + if (url.params.hasOwnProperty(URL_SEARCH_PARAM) + && url.params[URL_SEARCH_PARAM] != "") { + showSearch(true); + searchbar.value = decodeURIComponent( + (url.params[URL_SEARCH_PARAM]+'').replace(/\+/g, '%20')); + searchbarKeyUpHandler(); // -> doSearch() + } else { + showSearch(false); + } + + if (url.params.hasOwnProperty(URL_MARK_PARAM)) { + var words = decodeURIComponent(url.params[URL_MARK_PARAM]).split(' '); + marker.mark(words, { + exclude: mark_exclude + }); + + var markers = document.querySelectorAll("mark"); + function hide() { + for (var i = 0; i < markers.length; i++) { + markers[i].classList.add("fade-out"); + window.setTimeout(function(e) { marker.unmark(); }, 300); + } + } + for (var i = 0; i < markers.length; i++) { + markers[i].addEventListener('click', hide); + } + } + } + + // Eventhandler for keyevents on `document` + function globalKeyHandler(e) { + if (e.altKey || e.ctrlKey || e.metaKey || e.shiftKey || e.target.type === 'textarea' || e.target.type === 'text') { return; } + + if (e.keyCode === ESCAPE_KEYCODE) { + e.preventDefault(); + searchbar.classList.remove("active"); + setSearchUrlParameters("", + (searchbar.value.trim() !== "") ? "push" : "replace"); + if (hasFocus()) { + unfocusSearchbar(); + } + showSearch(false); + marker.unmark(); + } else if (!hasFocus() && e.keyCode === SEARCH_HOTKEY_KEYCODE) { + e.preventDefault(); + showSearch(true); + window.scrollTo(0, 0); + searchbar.select(); + } else if (hasFocus() && e.keyCode === DOWN_KEYCODE) { + e.preventDefault(); + unfocusSearchbar(); + searchresults.firstElementChild.classList.add("focus"); + } else if (!hasFocus() && (e.keyCode === DOWN_KEYCODE + || e.keyCode === UP_KEYCODE + || e.keyCode === SELECT_KEYCODE)) { + // not `:focus` because browser does annoying scrolling + var focused = searchresults.querySelector("li.focus"); + if (!focused) return; + e.preventDefault(); + if (e.keyCode === DOWN_KEYCODE) { + var next = focused.nextElementSibling; + if (next) { + focused.classList.remove("focus"); + next.classList.add("focus"); + } + } else if (e.keyCode === UP_KEYCODE) { + focused.classList.remove("focus"); + var prev = focused.previousElementSibling; + if (prev) { + prev.classList.add("focus"); + } else { + searchbar.select(); + } + } else { // SELECT_KEYCODE + window.location.assign(focused.querySelector('a')); + } + } + } + + function showSearch(yes) { + if (yes) { + search_wrap.classList.remove('hidden'); + searchicon.setAttribute('aria-expanded', 'true'); + } else { + search_wrap.classList.add('hidden'); + searchicon.setAttribute('aria-expanded', 'false'); + var results = searchresults.children; + for (var i = 0; i < results.length; i++) { + results[i].classList.remove("focus"); + } + } + } + + function showResults(yes) { + if (yes) { + searchresults_outer.classList.remove('hidden'); + } else { + searchresults_outer.classList.add('hidden'); + } + } + + // Eventhandler for search icon + function searchIconClickHandler() { + if (search_wrap.classList.contains('hidden')) { + showSearch(true); + window.scrollTo(0, 0); + searchbar.select(); + } else { + showSearch(false); + } + } + + // Eventhandler for keyevents while the searchbar is focused + function searchbarKeyUpHandler() { + var searchterm = searchbar.value.trim(); + if (searchterm != "") { + searchbar.classList.add("active"); + doSearch(searchterm); + } else { + searchbar.classList.remove("active"); + showResults(false); + removeChildren(searchresults); + } + + setSearchUrlParameters(searchterm, "push_if_new_search_else_replace"); + + // Remove marks + marker.unmark(); + } + + // Update current url with ?URL_SEARCH_PARAM= parameter, remove ?URL_MARK_PARAM and #heading-anchor . + // `action` can be one of "push", "replace", "push_if_new_search_else_replace" + // and replaces or pushes a new browser history item. + // "push_if_new_search_else_replace" pushes if there is no `?URL_SEARCH_PARAM=abc` yet. + function setSearchUrlParameters(searchterm, action) { + var url = parseURL(window.location.href); + var first_search = ! url.params.hasOwnProperty(URL_SEARCH_PARAM); + if (searchterm != "" || action == "push_if_new_search_else_replace") { + url.params[URL_SEARCH_PARAM] = searchterm; + delete url.params[URL_MARK_PARAM]; + url.hash = ""; + } else { + delete url.params[URL_MARK_PARAM]; + delete url.params[URL_SEARCH_PARAM]; + } + // A new search will also add a new history item, so the user can go back + // to the page prior to searching. A updated search term will only replace + // the url. + if (action == "push" || (action == "push_if_new_search_else_replace" && first_search) ) { + history.pushState({}, document.title, renderURL(url)); + } else if (action == "replace" || (action == "push_if_new_search_else_replace" && !first_search) ) { + history.replaceState({}, document.title, renderURL(url)); + } + } + + function doSearch(searchterm) { + + // Don't search the same twice + if (current_searchterm == searchterm) { return; } + else { current_searchterm = searchterm; } + + if (searchindex == null) { return; } + + // Do the actual search + var results = searchindex.search(searchterm, search_options); + var resultcount = Math.min(results.length, results_options.limit_results); + + // Display search metrics + searchresults_header.innerText = formatSearchMetric(resultcount, searchterm); + + // Clear and insert results + var searchterms = searchterm.split(' '); + removeChildren(searchresults); + for(var i = 0; i < resultcount ; i++){ + var resultElem = document.createElement('li'); + resultElem.innerHTML = formatSearchResult(results[i], searchterms); + searchresults.appendChild(resultElem); + } + + // Display results + showResults(true); + } + + fetch(path_to_root + 'searchindex.json') + .then(response => response.json()) + .then(json => init(json)) + .catch(error => { // Try to load searchindex.js if fetch failed + var script = document.createElement('script'); + script.src = path_to_root + 'searchindex.js'; + script.onload = () => init(window.search); + document.head.appendChild(script); + }); + + // Exported functions + search.hasFocus = hasFocus; +})(window.search); diff --git a/HEAD/searchindex.js b/HEAD/searchindex.js new file mode 100644 index 000000000..d54febb8e --- /dev/null +++ b/HEAD/searchindex.js @@ -0,0 +1 @@ +Object.assign(window.search, {"doc_urls":["introduction.html#introduction","tutorial/introduction.html#tutorial","tutorial/app.html#creating-a-uefi-application","tutorial/app.html#install-dependencies","tutorial/app.html#create-a-minimal-application","tutorial/app.html#walkthrough","tutorial/building.html#building","tutorial/building.html#toolchain","tutorial/building.html#build-the-application","tutorial/vm.html#running-in-a-vm","tutorial/vm.html#install-dependencies","tutorial/vm.html#firmware-files","tutorial/vm.html#system-partition","tutorial/vm.html#launch-the-vm","tutorial/hardware.html#running-on-hardware","tutorial/hardware.html#preparation","tutorial/hardware.html#example-on-linux","tutorial/hardware.html#booting-the-usb","how_to/introduction.html#how-to","how_to/protocols.html#using-protocols","how_to/protocols.html#example","how_to/protocols.html#walkthrough","how_to/drawing.html#drawing-to-the-screen","how_to/building_drivers.html#building-drivers","concepts/introduction.html#concepts","concepts/boot_stages.html#boot-stages","concepts/tables.html#tables","concepts/guid.html#guid","concepts/handles_and_protocols.html#handles-and-protocols","concepts/handles_and_protocols.html#handles","concepts/handles_and_protocols.html#protocols","concepts/device_paths.html#device-paths","concepts/variables.html#variables","concepts/variables.html#attributes","concepts/gpt.html#gpt","concepts/gpt.html#system-partition","reference.html#reference"],"index":{"documentStore":{"docInfo":{"0":{"body":22,"breadcrumbs":2,"title":1},"1":{"body":18,"breadcrumbs":2,"title":1},"10":{"body":36,"breadcrumbs":5,"title":2},"11":{"body":53,"breadcrumbs":5,"title":2},"12":{"body":20,"breadcrumbs":5,"title":2},"13":{"body":33,"breadcrumbs":5,"title":2},"14":{"body":9,"breadcrumbs":5,"title":2},"15":{"body":103,"breadcrumbs":4,"title":1},"16":{"body":54,"breadcrumbs":5,"title":2},"17":{"body":38,"breadcrumbs":5,"title":2},"18":{"body":4,"breadcrumbs":0,"title":0},"19":{"body":64,"breadcrumbs":4,"title":2},"2":{"body":0,"breadcrumbs":7,"title":3},"20":{"body":112,"breadcrumbs":3,"title":1},"21":{"body":182,"breadcrumbs":3,"title":1},"22":{"body":438,"breadcrumbs":4,"title":2},"23":{"body":33,"breadcrumbs":4,"title":2},"24":{"body":33,"breadcrumbs":2,"title":1},"25":{"body":92,"breadcrumbs":5,"title":2},"26":{"body":103,"breadcrumbs":3,"title":1},"27":{"body":64,"breadcrumbs":3,"title":1},"28":{"body":21,"breadcrumbs":5,"title":2},"29":{"body":26,"breadcrumbs":4,"title":1},"3":{"body":7,"breadcrumbs":6,"title":2},"30":{"body":69,"breadcrumbs":4,"title":1},"31":{"body":70,"breadcrumbs":5,"title":2},"32":{"body":44,"breadcrumbs":3,"title":1},"33":{"body":109,"breadcrumbs":3,"title":1},"34":{"body":99,"breadcrumbs":3,"title":1},"35":{"body":94,"breadcrumbs":4,"title":2},"36":{"body":21,"breadcrumbs":2,"title":1},"4":{"body":44,"breadcrumbs":7,"title":3},"5":{"body":179,"breadcrumbs":5,"title":1},"6":{"body":0,"breadcrumbs":3,"title":1},"7":{"body":40,"breadcrumbs":3,"title":1},"8":{"body":19,"breadcrumbs":4,"title":2},"9":{"body":0,"breadcrumbs":5,"title":2}},"docs":{"0":{"body":"Welcome to the Rust UEFI Book. The focus of this book is how to use uefi-rs to build UEFI applications in Rust, but it also describes some general UEFI concepts, as well as relevant tools such as QEMU.","breadcrumbs":"Introduction » Introduction","id":"0","title":"Introduction"},"1":{"body":"This tutorial describes the process of creating and running a simple x86_64 UEFI application in Rust. The application will print \"Hello World\", pause for 10 seconds, then exit.","breadcrumbs":"Tutorial » Tutorial","id":"1","title":"Tutorial"},"10":{"body":"Two dependencies are needed: QEMU , which implements the virtual machine itself, and OVMF , which provides UEFI firmware that QEMU can run. The details of how to install QEMU and OVMF will vary depending on your operating system. Debian/Ubuntu: sudo apt-get install qemu ovmf Fedora: sudo dnf install qemu-kvm edk2-ovmf","breadcrumbs":"Tutorial » Running in a VM » Install dependencies","id":"10","title":"Install dependencies"},"11":{"body":"The OVMF package provides two firmware files, one for the executable code and one for variable storage. (The package may provide multiple variations of these files; refer to the package's documentation for details of the files it includes.) For ease of access we'll copy the OVMF code and vars files to the project directory. The location where OVMF is installed depends on your operating system; for Debian, Ubuntu and Fedora the files are under /usr/share/OVMF. Copy the files to your project directory: cp /usr/share/OVMF/OVMF_CODE.fd .\ncp /usr/share/OVMF/OVMF_VARS.fd .","breadcrumbs":"Tutorial » Running in a VM » Firmware files","id":"11","title":"Firmware files"},"12":{"body":"Now create a directory structure containing the executable to imitate a UEFI System Partition : mkdir -p esp/efi/boot\ncp target/x86_64-unknown-uefi/debug/my-uefi-app.efi esp/efi/boot/bootx64.efi","breadcrumbs":"Tutorial » Running in a VM » System partition","id":"12","title":"System partition"},"13":{"body":"Now we can launch QEMU, using VVFAT to access the esp directory created above. qemu-system-x86_64 -enable-kvm \\ -drive if=pflash,format=raw,readonly=on,file=OVMF_CODE.fd \\ -drive if=pflash,format=raw,readonly=on,file=OVMF_VARS.fd \\ -drive format=raw,file=fat:rw:esp A QEMU window should appear, and after a few seconds you should see the log message: [ INFO]: src/main.rs@011: Hello world!","breadcrumbs":"Tutorial » Running in a VM » Launch the VM","id":"13","title":"Launch the VM"},"14":{"body":"To run on real hardware you'll need a specially-prepared USB drive.","breadcrumbs":"Tutorial » Running on Hardware » Running on Hardware","id":"14","title":"Running on Hardware"},"15":{"body":"The general steps to prepare the drive are: Partition the drive using GPT . Create a partition. Set the partition type GUID to C12A7328-F81F-11D2-BA4B-00A0C93EC93B. That marks it as an EFI System partition. (On many UEFI implementations this is not strictly necessary, see note below.) Format the partition as FAT . Mount the partition. Create the directory path EFI/BOOT on the partition. (FAT is case insensitive, so capitalization doesn't matter.) Copy your EFI application to a file under EFI/BOOT. The file name is specific to the architecture. For example, on x86_64 the file name must be BOOTX64.EFI. See the boot files table for other architectures. The details of exactly how to do these steps will vary depending on your OS. Note that most UEFI implementations do not strictly require GPT partitioning or the EFI System partition GUID; they will look for any FAT partition with the appropriate directory structure. This is not required however; the UEFI Specification says \"UEFI implementations may allow the use of conforming FAT partitions which do not use the ESP GUID.\"","breadcrumbs":"Tutorial » Running on Hardware » Preparation","id":"15","title":"Preparation"},"16":{"body":"Warning: these operations are destructive! Do not run these commands on a disk if you care about the data it contains. # Create the GPT, create a 9MB partition starting at 1MB, and set the\n# partition type to EFI System.\nsgdisk \\ --clear \\ --new=1:1M:10M \\ --typecode=1:C12A7328-F81F-11D2-BA4B-00A0C93EC93B \\ /path/to/disk # Format the partition as FAT.\nmkfs.fat /path/to/disk_partition # Mount the partition.\nmkdir esp\nmount /path/to/disk_partition esp # Create the boot directory.\nmkdir esp/EFI/BOOT # Copy in the boot executable.\ncp /path/to/your-executable.efi esp/EFI/BOOT/BOOTX64.EFI","breadcrumbs":"Tutorial » Running on Hardware » Example on Linux","id":"16","title":"Example on Linux"},"17":{"body":"Insert the USB into the target computer. Reboot the machine, then press the one-time boot key. Which key to press depends on the vendor. For example, Dell uses F12, HP uses F9, and on Macs you hold down the Option key. Once the one-time boot menu appears, select your USB drive and press enter.","breadcrumbs":"Tutorial » Running on Hardware » Booting the USB","id":"17","title":"Booting the USB"},"18":{"body":"This chapter contains practical how-to guides.","breadcrumbs":"How-to » How-to","id":"18","title":"How-to"},"19":{"body":"The open a protocol, you must first get a handle, then open a protocol on that handle. See Handles and Protocols for an overview of what these terms mean. To get a handle you can use: BootServices::locate_handle_buffer : this can be used to get all available handles, or just the handles that support a particular protocol. BootServices::locate_handle : the same as locate_handle_buffer, but you provide the slice that stores the handles. BootServices::locate_device_path : find a handle by Device Path . Once you have obtained a handle, use BootServices::open_protocol_exclusive to open a protocol on that handle. This returns a ScopedProtocol , which automatically closes the protocol when dropped. Using BootServices::open_protocol_exclusive is the safest way to open a protocol, but in some cases a protocol cannot be opened in exclusive mode. The unsafe BootServices::open_protocol can be used in that case.","breadcrumbs":"How-to » Using Protocols » Using Protocols","id":"19","title":"Using Protocols"},"2":{"body":"","breadcrumbs":"Tutorial » Creating a UEFI Application » Creating a UEFI application","id":"2","title":"Creating a UEFI application"},"20":{"body":"For this example we'll look at a program that opens a couple different protocols. This program opens the LoadedImage protocol to get information about an executable (the currently-running program in this case). It also opens the DevicePathToText protocol to get the file system path that the program was launched from. We'll walk through the details of this program shortly, but first here's the whole thing: #![no_main]\n#![no_std] use log::info;\nuse uefi::prelude::*;\nuse uefi::proto::device_path::text::{ AllowShortcuts, DevicePathToText, DisplayOnly,\n};\nuse uefi::proto::loaded_image::LoadedImage;\nuse uefi::table::boot::SearchType;\nuse uefi::{Identify, Result}; #[entry]\nfn main(image_handle: Handle, mut system_table: SystemTable) -> Status { uefi_services::init(&mut system_table).unwrap(); let boot_services = system_table.boot_services(); print_image_path(boot_services).unwrap(); boot_services.stall(10_000_000); Status::SUCCESS\n} fn print_image_path(boot_services: &BootServices) -> Result { let loaded_image = boot_services .open_protocol_exclusive::(boot_services.image_handle())?; let device_path_to_text_handle = *boot_services .locate_handle_buffer(SearchType::ByProtocol(&DevicePathToText::GUID))? .first() .expect(\"DevicePathToText is missing\"); let device_path_to_text = boot_services .open_protocol_exclusive::( device_path_to_text_handle, )?; let image_device_path = loaded_image.file_path().expect(\"File path is not set\"); let image_device_path_text = device_path_to_text .convert_device_path_to_text( boot_services, image_device_path, DisplayOnly(true), AllowShortcuts(false), ) .expect(\"convert_device_path_to_text failed\"); info!(\"Image path: {}\", &*image_device_path_text); Ok(())\n} When the program is run it will print something like this: [ INFO]: example.rs@058: Image path: \\EFI\\BOOT\\BOOTX64.EFI","breadcrumbs":"How-to » Using Protocols » Example","id":"20","title":"Example"},"21":{"body":"The main function looks much like the \"Hello world!\" example . It sets up logging, calls print_image_path, and pauses for ten seconds to give you time to read the output. Let's look at print_image_path: fn print_image_path(boot_services: &BootServices) -> Result { The return type is a uefi::Result , which is a Result alias that combines uefi::Status with the error data. Both the success and error data types are () by default. The function starts by opening the LoadedImage protocol: let loaded_image = boot_services .open_protocol_exclusive::(boot_services.image_handle())?; The open_protocol_exclusive method takes a type parameter, which is the type of Protocol you want to open ( LoadedImage in this case). It also takes one regular argument of type Handle . For this example we want the handle of the currently-running image, which was passed in as the first argument to main. The handle is conveniently accessible through BootServices::image_handle , so we use that here. Next the program opens the DevicePathToText protocol: let device_path_to_text_handle = *boot_services .locate_handle_buffer(SearchType::ByProtocol(&DevicePathToText::GUID))? .first() .expect(\"DevicePathToText is missing\"); let device_path_to_text = boot_services .open_protocol_exclusive::( device_path_to_text_handle, )?; This protocol isn't available for the image_handle, so we start by using locate_handle_buffer to find all handles that support DevicePathToText. We only need one handle though, so we call first() and discard the rest. Then we call open_protocol_exclusive again. It looks more or less like the previous time, but with DevicePathToText as the type parameter and device_path_to_text_handle as the handle. Now that we have both protocols open, we can use them together to get the program's path and convert it to text: let image_device_path = loaded_image.file_path().expect(\"File path is not set\"); let image_device_path_text = device_path_to_text .convert_device_path_to_text( boot_services, image_device_path, DisplayOnly(true), AllowShortcuts(false), ) .expect(\"convert_device_path_to_text failed\"); info!(\"Image path: {}\", &*image_device_path_text); Ok(())\n} Since protocols do a wide range of different things, the methods available to call are very specific to each individual protocol. The best places to find out what each protocol can do are the uefi-rs reference documentation and the UEFI Specification .","breadcrumbs":"How-to » Using Protocols » Walkthrough","id":"21","title":"Walkthrough"},"22":{"body":"This example shows how to draw to the screen using the graphics output protocol . The code will a Sierpiński triangle using the \"chaos game\" method. screenshot The core abstraction used here is a linear buffer: struct Buffer { width: usize, height: usize, pixels: Vec,\n} impl Buffer { /// Create a new `Buffer`. fn new(width: usize, height: usize) -> Self { Buffer { width, height, pixels: vec![BltPixel::new(0, 0, 0); width * height], } } /// Get a single pixel. fn pixel(&mut self, x: usize, y: usize) -> Option<&mut BltPixel> { self.pixels.get_mut(y * self.width + x) } /// Blit the buffer to the framebuffer. fn blit(&self, gop: &mut GraphicsOutput) -> Result { gop.blt(BltOp::BufferToVideo { buffer: &self.pixels, src: BltRegion::Full, dest: (0, 0), dims: (self.width, self.height), }) }\n} This Buffer type stores a Vec of BltPixel s, which are BGRX 32-bit pixels (8 bites each for blue, green, and red, followed by 8 unused bits of padding). We use the pixel method to alter a single pixel at a time. This is often not an efficient method; for more complex graphics you could use a crate like embedded-graphics . The Buffer::blit method calls the graphics output protocol's blt method to copy the buffer to the screen. Most of the rest of the code is just implementing the algorithm for drawing the fractal. Here's the full example: #![no_main]\n#![no_std] extern crate alloc; use alloc::vec;\nuse alloc::vec::Vec;\nuse core::mem;\nuse uefi::prelude::*;\nuse uefi::proto::console::gop::{BltOp, BltPixel, BltRegion, GraphicsOutput};\nuse uefi::proto::rng::Rng;\nuse uefi::table::boot::BootServices;\nuse uefi::Result; #[derive(Clone, Copy)]\nstruct Point { x: f32, y: f32,\n} impl Point { fn new(x: f32, y: f32) -> Self { Self { x, y } }\n} struct Buffer { width: usize, height: usize, pixels: Vec,\n} impl Buffer { /// Create a new `Buffer`. fn new(width: usize, height: usize) -> Self { Buffer { width, height, pixels: vec![BltPixel::new(0, 0, 0); width * height], } } /// Get a single pixel. fn pixel(&mut self, x: usize, y: usize) -> Option<&mut BltPixel> { self.pixels.get_mut(y * self.width + x) } /// Blit the buffer to the framebuffer. fn blit(&self, gop: &mut GraphicsOutput) -> Result { gop.blt(BltOp::BufferToVideo { buffer: &self.pixels, src: BltRegion::Full, dest: (0, 0), dims: (self.width, self.height), }) }\n} /// Get a random `usize` value.\nfn get_random_usize(rng: &mut Rng) -> usize { let mut buf = [0; mem::size_of::()]; rng.get_rng(None, &mut buf).expect(\"get_rng failed\"); usize::from_le_bytes(buf)\n} fn draw_sierpinski(bt: &BootServices) -> Result { // Open graphics output protocol. let gop_handle = bt.get_handle_for_protocol::()?; let mut gop = bt.open_protocol_exclusive::(gop_handle)?; // Open random number generator protocol. let rng_handle = bt.get_handle_for_protocol::()?; let mut rng = bt.open_protocol_exclusive::(rng_handle)?; // Create a buffer to draw into. let (width, height) = gop.current_mode_info().resolution(); let mut buffer = Buffer::new(width, height); // Initialize the buffer with a simple gradient background. for y in 0..height { let r = ((y as f32) / ((height - 1) as f32)) * 255.0; for x in 0..width { let g = ((x as f32) / ((width - 1) as f32)) * 255.0; let pixel = buffer.pixel(x, y).unwrap(); pixel.red = r as u8; pixel.green = g as u8; pixel.blue = 255; } } let size = Point::new(width as f32, height as f32); // Define the vertices of a big triangle. let border = 20.0; let triangle = [ Point::new(size.x / 2.0, border), Point::new(border, size.y - border), Point::new(size.x - border, size.y - border), ]; // `p` is the point to draw. Start at the center of the triangle. let mut p = Point::new(size.x / 2.0, size.y / 2.0); // Loop forever, drawing the frame after each new point is changed. loop { // Choose one of the triangle's vertices at random. let v = triangle[get_random_usize(&mut rng) % 3]; // Move `p` halfway to the chosen vertex. p.x = (p.x + v.x) * 0.5; p.y = (p.y + v.y) * 0.5; // Set `p` to black. let pixel = buffer.pixel(p.x as usize, p.y as usize).unwrap(); pixel.red = 0; pixel.green = 100; pixel.blue = 0; // Draw the buffer to the screen. buffer.blit(&mut gop)?; }\n} #[entry]\nfn main(_handle: Handle, mut system_table: SystemTable) -> Status { uefi_services::init(&mut system_table).unwrap(); let bt = system_table.boot_services(); draw_sierpinski(bt).unwrap(); Status::SUCCESS\n} You can run this example from the uefi-rs repository with: cargo xtask run --example sierpinski","breadcrumbs":"How-to » Drawing to the Screen » Drawing to the Screen","id":"22","title":"Drawing to the Screen"},"23":{"body":"There are three types of UEFI images: Application Boot service driver Runtime driver By default , Rust's UEFI targets produce applications. This can be changed by passing a subsystem linker flag in rustflags and setting the value to efi_boot_service_driver or efi_runtime_driver. Example: # In .cargo/config.toml:\n[build]\nrustflags = [\"-C\", \"link-args=/subsystem:efi_runtime_driver\"]","breadcrumbs":"How-to » Building drivers » Building drivers","id":"23","title":"Building drivers"},"24":{"body":"The canonical source of information about UEFI is the UEFI specification . The specification is huge (currently nearly 2500 pages). Much of that content relates to optional services, understanding of which is not critical to understanding UEFI as a whole. This chapter summarizes some of the more important UEFI concepts and links to the relevant uefi-rs documentation.","breadcrumbs":"Concepts » Concepts","id":"24","title":"Concepts"},"25":{"body":"A UEFI system goes through several distinct phases during the boot process. Platform Initialization. This early-boot phase is mostly outside the scope of uefi-rs. It is described by the UEFI Platform Initialization Specification , which is separate from the main UEFI Specification. Boot Services. This is when UEFI drivers and applications are loaded. Both the BootServices and RuntimeServices tables are accessible. This stage typically culminates in running a bootloader that loads an operating system. The stage ends when SystemTable::exit_boot_services is called, putting the system in Runtime mode. Runtime. This stage is typically active when running an operating system such as Linux or Windows. UEFI functionality is much more limited in the Runtime mode. The BootServices table is no longer accessible, but the RuntimeServices table is still available. Once the system is in Runtime mode, it cannot return to the Boot Services stage until after a system reset.","breadcrumbs":"Concepts » Boot Stages » Boot Stages","id":"25","title":"Boot Stages"},"26":{"body":"UEFI has a few table structures. These tables are how you get access to UEFI services. SystemTable (EFI_SYSTEM_TABLE in the specification) is the top-level table that provides access to the other tables. BootServices (EFI_BOOT_SERVICES in the specification) provides access to a wide array of services such as memory allocation, executable loading, and optional extension interfaces called protocols. This table is only accessible while in the Boot Services stage. RuntimeServices (EFI_RUNTIME_SERVICES in the specification) provides access to a fairly limited set of services, including variable storage, system time, and virtual-memory mapping. This table is accessible during both the Boot Services and Runtime stages. When writing a UEFI application, you get access to the system table from one of the arguments to the main entry point: fn main(handle: Handle, mut system_table: SystemTable) -> Status; Then use SystemTable::boot_services and SystemTable::runtime_services to get access to the other tables. Once SystemTable::exit_boot_services is called, the original system table is consumed and a new system table is returned that only provides access to the RuntimeServices table.","breadcrumbs":"Concepts » Tables » Tables","id":"26","title":"Tables"},"27":{"body":"GUID is short for Globally Unique Identifier. A GUID is always 16 bytes, and has a standard string representation format that looks like this: 313b0d7c-fed4-4de7-99ed-2fe48874a410. The details of the GUID format aren't too important, but be aware that the actual byte representation is not in the same order as the string representation because the first three fields are little-endian. For the most part you can treat GUIDs as opaque identifiers. The UEFI specification uses GUIDs all over the place. GUIDs are used to identify protocols, disk partitions, variable groupings, and much more. In uefi-rs, GUIDs are represented by the Guid type.","breadcrumbs":"Concepts » GUID » GUID","id":"27","title":"GUID"},"28":{"body":"Handles and protocols are at the core of what makes UEFI extensible. Together they are the mechanism by which UEFI can adapt to a wide array of hardware and boot conditions, while still providing a consistent interface to drivers and applications.","breadcrumbs":"Concepts » Handles and Protocols » Handles and Protocols","id":"28","title":"Handles and Protocols"},"29":{"body":"Handles represent resources. A resource might be a physical device such as a disk drive or USB device, or something less tangible like a loaded executable. A Handle is an opaque pointer, so you can't do anything with it directly. To operate on a handle you have to open a protocol.","breadcrumbs":"Concepts » Handles and Protocols » Handles","id":"29","title":"Handles"},"3":{"body":"Follow the Rust installation instructions to set up Rust.","breadcrumbs":"Tutorial » Creating a UEFI Application » Install dependencies","id":"3","title":"Install dependencies"},"30":{"body":"Protocols are interfaces that provide functions to interact with a resource. For example, the BlockIO protocol provides functions to read and write to block IO devices. Protocols are only available during the Boot Services stage ; you can't access them during the Runtime stage. The UEFI Specification defines a very large number of protocols. Because protocols are inherently very diverse, the best place to learn about individual protocols is the UEFI Specification . There are many chapters covering various protocols. Not all of these protocols are wrapped by uefi-rs yet (contributions welcome!) but many of the most commonly useful ones are. See the Using Protocols how-to for details of the uefi-rs API for interacting with protocols.","breadcrumbs":"Concepts » Handles and Protocols » Protocols","id":"30","title":"Protocols"},"31":{"body":"A device path is a very flexible packed data structure for storing paths to many kinds of device. Note that these device paths are not the same thing as file system paths, although they can include file system paths. Like handles , device paths can be used to uniquely identify resources such as consoles, mice, disks, partitions, and more. Unlike handles , which are essentially opaque pointers, device paths are variable-length structures that contain parseable information. The uefi::proto::device_path module documentation describes the details of how device paths are encoded. Device paths can also be converted to and from human-readable text representations that look like this: PciRoot(0x0)/Pci(0x1F,0x2)/Sata(0x0,0xFFFF,0x0)/HD(1,MBR,0xBE1AFDFA,0x3F,0xFBFC1) See uefi::proto::device_path::text for details.","breadcrumbs":"Concepts » Device Paths » Device Paths","id":"31","title":"Device Paths"},"32":{"body":"UEFI provides fairly flexible key/value variable storage. Each variable is identified by a key consisting of a UCS-2 null-terminated name plus a vendor GUID . The vendor GUID serves as a namespace for variables so that different vendors don't accidentally overwrite or misinterpret another vendor's variable if they happen to have the same name. The data stored in each variable is an arbitrary byte array.","breadcrumbs":"Concepts » Variables » Variables","id":"32","title":"Variables"},"33":{"body":"Each variable has attributes (represented as bit flags) associated with it that affect how it is stored and how it can be accessed. If the BOOTSERVICE_ACCESS and RUNTIME_ACCESS bits are set, the variable can be accessed during both the Boot Services and Runtime stages . If only BOOTSERVICE_ACCESS is set then the variable can neither be read nor written to after exiting boot services. Another important attribute is the NON_VOLATILE bit. If this bit is not set, the variable will be stored in normal memory and will not persist across a power cycle. If this bit is set, the variable will be stored in special non-volatile memory. You should be careful about writing variables of this type, because the non-volatile storage can be very limited in size. There have been cases where a vendor's poor UEFI implementation caused the machine not too boot once the storage became too full. Even figuring out how much space is in use can be tricky due to deletion being implemented via garbage collection. Matthew Garret's article \"Dealing with UEFI non-volatile memory quirks\" has more details. Most of the other attributes relate to authenticated variables, which can be used to prevent changes to a variable by unauthorized programs.","breadcrumbs":"Concepts » Variables » Attributes","id":"33","title":"Attributes"},"34":{"body":"GPT is short for GUID Partition Table. It's a more modern alternative to MBR (master boot record) partition tables. Although it's defined in the UEFI specification, it often gets used on non-UEFI systems too. There are a couple big advantages of using GPT over MBR: It has a relatively clear and precise standard, unlike MBR where implementations often just try to match what other implementations do. It supports very large disks and very large numbers of partitions. A GPT disk contains a primary header near the beginning of the disk, followed by a partition entry array. The header and partition entry array have a secondary copy at the end of the disk for redundancy. The partition entry arrays contain structures that describe each partition, including a GUID to identify the individual partition, a partition type GUID to indicate the purpose of the partition, and start/end block addresses. In between the entry arrays is the actual partition data.","breadcrumbs":"Concepts » GPT » GPT","id":"34","title":"GPT"},"35":{"body":"The system partition is UEFI's version of a bootable partition. The system partition is sometimes called the ESP, or EFI System Partition. It is identified by a partition type of c12a7328-f81f-11d2-ba4b-00a0c93ec93b. The system partition always contains a FAT file system. There are various standardized paths that can exist within the file system, and of particular importance are the boot files. These are the files that UEFI will try to boot from by default (in the absence of a different boot configuration set through special UEFI variables ). Boot files are under \\EFI\\BOOT, and are named BOOT.efi, where is a short architecture name. Architecture File name Intel 32-bit BOOTIA32.EFI X86_64 BOOTX64.EFI Itanium BOOTIA64.EFI AArch32 BOOTARM.EFI AArch64 BOOTAA64.EFI RISC-V 32-bit BOOTRISCV32.EFI RISC-V 64-bit BOOTRISCV64.EFI RISC-V 128-bit BOOTRISCV128.EFI","breadcrumbs":"Concepts » GPT » System partition","id":"35","title":"System partition"},"36":{"body":"Rust *-unknown-uefi targets uefi crate reference uefi-macros crate reference uefi-raw crate reference uefi-services crate reference UEFI Specifications","breadcrumbs":"Reference » Reference","id":"36","title":"Reference"},"4":{"body":"Create an empty application and change to that directory: cargo new my-uefi-app\ncd my-uefi-app Add a few dependencies: cargo add log uefi uefi-services Replace the contents of src/main.rs with this: #![no_main]\n#![no_std] use log::info;\nuse uefi::prelude::*; #[entry]\nfn main(_image_handle: Handle, mut system_table: SystemTable) -> Status { uefi_services::init(&mut system_table).unwrap(); info!(\"Hello world!\"); system_table.boot_services().stall(10_000_000); Status::SUCCESS\n}","breadcrumbs":"Tutorial » Creating a UEFI Application » Create a minimal application","id":"4","title":"Create a minimal application"},"5":{"body":"Let's look a quick look at what each part of the program is doing, starting with the #![...] lines at the top: #![no_main]\n#![no_std] This is some boilerplate that all Rust UEFI applications will need. no_main is needed because the UEFI application entry point is different from the standard Rust main function. no_std is needed to turn off the std library; the core and alloc crates can still be used. Next up are some use lines. Nothing too exciting here; the uefi::prelude module is intended to be glob-imported, and exports a number of commonly-used types. use log::info;\nuse uefi::prelude::*; Now we get to the UEFI application main function, and here things look a little different from a standard Rust program. #[entry]\nfn main(_image_handle: Handle, mut system_table: SystemTable) -> Status { The main function in a Uefi application always takes two arguments, the image handle and the system table. The image handle represents the currently-running executable, and the system table provides access to many different UEFI services. The main function returns a Status , which is essentially a numeric error (or success) code defined by UEFI. The first thing we do inside of main is initialize uefi_services: uefi_services::init(&mut system_table).unwrap(); The uefi_services crate is not strictly required to make a UEFI application with the uefi crate, but it makes things much simpler by setting a simple memory allocator, initializing the logger, and providing a panic handler. Next we use the standard log crate to output \"Hello world!\". Then we call stall to make the system pause for 10 seconds. This just ensures you have enough time to see the output. info!(\"Hello world!\"); system_table.boot_services().stall(10_000_000); Finally we return Status::SUCCESS indicating that everything completed successfully: Status::SUCCESS\n}","breadcrumbs":"Tutorial » Creating a UEFI Application » Walkthrough","id":"5","title":"Walkthrough"},"6":{"body":"","breadcrumbs":"Tutorial » Building » Building","id":"6","title":"Building"},"7":{"body":"In order to compile for UEFI, an appropriate target must be installed. The easiest way to set this up is using a rustup toolchain file . In the root of your repository, add rust-toolchain.toml: [toolchain]\ntargets = [\"aarch64-unknown-uefi\", \"i686-unknown-uefi\", \"x86_64-unknown-uefi\"] Here we have specified all three of the currently-supported UEFI targets; you can remove some if you don't need them.","breadcrumbs":"Tutorial » Building » Toolchain","id":"7","title":"Toolchain"},"8":{"body":"Run this command to build the application: cargo build --target x86_64-unknown-uefi This will produce an x86-64 executable: target/x86_64-unknown-uefi/debug/my-uefi-app.efi.","breadcrumbs":"Tutorial » Building » Build the application","id":"8","title":"Build the application"},"9":{"body":"","breadcrumbs":"Tutorial » Running in a VM » Running in a VM","id":"9","title":"Running in a VM"}},"length":37,"save":true},"fields":["title","body","breadcrumbs"],"index":{"body":{"root":{"0":{".":{".":{"df":0,"docs":{},"h":{"df":0,"docs":{},"e":{"df":0,"docs":{},"i":{"df":0,"docs":{},"g":{"df":0,"docs":{},"h":{"df":0,"docs":{},"t":{"df":1,"docs":{"22":{"tf":1.0}}}}}}}},"w":{"df":0,"docs":{},"i":{"d":{"df":0,"docs":{},"t":{"df":0,"docs":{},"h":{"df":1,"docs":{"22":{"tf":1.0}}}}},"df":0,"docs":{}}}},"5":{"df":1,"docs":{"22":{"tf":1.4142135623730951}}},"df":0,"docs":{}},"0":{"a":{"0":{"c":{"9":{"3":{"df":0,"docs":{},"e":{"c":{"9":{"3":{"b":{"df":3,"docs":{"15":{"tf":1.0},"16":{"tf":1.0},"35":{"tf":1.0}}},"df":0,"docs":{}},"df":0,"docs":{}},"df":0,"docs":{}},"df":0,"docs":{}}},"df":0,"docs":{}},"df":0,"docs":{}},"df":0,"docs":{}},"df":0,"docs":{}},"df":0,"docs":{}},"df":1,"docs":{"22":{"tf":3.3166247903554}}},"1":{"0":{"0":{"df":1,"docs":{"22":{"tf":1.0}}},"df":2,"docs":{"1":{"tf":1.0},"5":{"tf":1.0}}},"1":{"d":{"2":{"df":3,"docs":{"15":{"tf":1.0},"16":{"tf":1.0},"35":{"tf":1.0}}},"df":0,"docs":{}},"df":0,"docs":{}},"2":{"8":{"df":1,"docs":{"35":{"tf":1.0}}},"df":0,"docs":{}},"6":{"df":1,"docs":{"27":{"tf":1.0}}},"df":1,"docs":{"22":{"tf":1.4142135623730951}},"m":{"b":{"df":1,"docs":{"16":{"tf":1.0}}},"df":0,"docs":{}}},"2":{".":{"0":{"df":1,"docs":{"22":{"tf":1.7320508075688772}}},"df":0,"docs":{}},"0":{".":{"0":{"df":1,"docs":{"22":{"tf":1.0}}},"df":0,"docs":{}},"df":0,"docs":{}},"5":{"0":{"0":{"df":1,"docs":{"24":{"tf":1.0}}},"df":0,"docs":{}},"5":{".":{"0":{"df":1,"docs":{"22":{"tf":1.4142135623730951}}},"df":0,"docs":{}},"df":1,"docs":{"22":{"tf":1.0}}},"df":0,"docs":{}},"df":1,"docs":{"32":{"tf":1.0}},"f":{"df":0,"docs":{},"e":{"4":{"8":{"8":{"7":{"4":{"a":{"4":{"1":{"0":{"df":1,"docs":{"27":{"tf":1.0}}},"df":0,"docs":{}},"df":0,"docs":{}},"df":0,"docs":{}},"df":0,"docs":{}},"df":0,"docs":{}},"df":0,"docs":{}},"df":0,"docs":{}},"df":0,"docs":{}},"df":0,"docs":{}}}},"3":{"1":{"3":{"b":{"0":{"d":{"7":{"c":{"df":1,"docs":{"27":{"tf":1.0}}},"df":0,"docs":{}},"df":0,"docs":{}},"df":0,"docs":{}},"df":0,"docs":{}},"df":0,"docs":{}},"df":0,"docs":{}},"2":{"df":2,"docs":{"22":{"tf":1.0},"35":{"tf":1.4142135623730951}}},"df":1,"docs":{"22":{"tf":1.0}}},"4":{"d":{"df":0,"docs":{},"e":{"7":{"df":1,"docs":{"27":{"tf":1.0}}},"df":0,"docs":{}}},"df":0,"docs":{}},"6":{"4":{"df":2,"docs":{"35":{"tf":1.0},"8":{"tf":1.0}}},"df":0,"docs":{}},"8":{"df":1,"docs":{"22":{"tf":1.4142135623730951}}},"9":{"9":{"df":0,"docs":{},"e":{"d":{"df":1,"docs":{"27":{"tf":1.0}}},"df":0,"docs":{}}},"df":0,"docs":{},"m":{"b":{"df":1,"docs":{"16":{"tf":1.0}}},"df":0,"docs":{}}},"a":{"a":{"df":0,"docs":{},"r":{"c":{"df":0,"docs":{},"h":{"3":{"2":{"df":1,"docs":{"35":{"tf":1.0}}},"df":0,"docs":{}},"6":{"4":{"df":2,"docs":{"35":{"tf":1.0},"7":{"tf":1.0}}},"df":0,"docs":{}},"df":0,"docs":{}}},"df":0,"docs":{}}},"b":{"df":0,"docs":{},"o":{"df":0,"docs":{},"v":{"df":1,"docs":{"13":{"tf":1.0}}}},"s":{"df":0,"docs":{},"e":{"df":0,"docs":{},"n":{"c":{"df":1,"docs":{"35":{"tf":1.0}}},"df":0,"docs":{}}},"t":{"df":0,"docs":{},"r":{"a":{"c":{"df":0,"docs":{},"t":{"df":1,"docs":{"22":{"tf":1.0}}}},"df":0,"docs":{}},"df":0,"docs":{}}}}},"c":{"c":{"df":0,"docs":{},"e":{"df":0,"docs":{},"s":{"df":0,"docs":{},"s":{"df":8,"docs":{"11":{"tf":1.0},"13":{"tf":1.0},"21":{"tf":1.0},"25":{"tf":1.4142135623730951},"26":{"tf":3.0},"30":{"tf":1.0},"33":{"tf":1.4142135623730951},"5":{"tf":1.0}}}}},"i":{"d":{"df":0,"docs":{},"e":{"df":0,"docs":{},"n":{"df":0,"docs":{},"t":{"df":1,"docs":{"32":{"tf":1.0}}}}}},"df":0,"docs":{}}},"df":0,"docs":{},"t":{"df":0,"docs":{},"i":{"df":0,"docs":{},"v":{"df":1,"docs":{"25":{"tf":1.0}}}},"u":{"a":{"df":0,"docs":{},"l":{"df":2,"docs":{"27":{"tf":1.0},"34":{"tf":1.0}}}},"df":0,"docs":{}}}},"d":{"a":{"df":0,"docs":{},"p":{"df":0,"docs":{},"t":{"df":1,"docs":{"28":{"tf":1.0}}}}},"d":{"df":2,"docs":{"4":{"tf":1.4142135623730951},"7":{"tf":1.0}},"r":{"df":0,"docs":{},"e":{"df":0,"docs":{},"s":{"df":0,"docs":{},"s":{"df":1,"docs":{"34":{"tf":1.0}}}}}}},"df":0,"docs":{},"v":{"a":{"df":0,"docs":{},"n":{"df":0,"docs":{},"t":{"a":{"df":0,"docs":{},"g":{"df":1,"docs":{"34":{"tf":1.0}}}},"df":0,"docs":{}}}},"df":0,"docs":{}}},"df":0,"docs":{},"f":{"df":0,"docs":{},"f":{"df":0,"docs":{},"e":{"c":{"df":0,"docs":{},"t":{"df":1,"docs":{"33":{"tf":1.0}}}},"df":0,"docs":{}}}},"g":{"a":{"df":0,"docs":{},"i":{"df":0,"docs":{},"n":{"df":1,"docs":{"21":{"tf":1.0}}}}},"df":0,"docs":{}},"l":{"df":0,"docs":{},"g":{"df":0,"docs":{},"o":{"df":0,"docs":{},"r":{"df":0,"docs":{},"i":{"df":0,"docs":{},"t":{"df":0,"docs":{},"h":{"df":0,"docs":{},"m":{"df":1,"docs":{"22":{"tf":1.0}}}}}}}}},"i":{"a":{"df":1,"docs":{"21":{"tf":1.0}}},"df":0,"docs":{}},"l":{"df":0,"docs":{},"o":{"c":{":":{":":{"df":0,"docs":{},"v":{"df":0,"docs":{},"e":{"c":{":":{":":{"df":0,"docs":{},"v":{"df":0,"docs":{},"e":{"c":{"df":1,"docs":{"22":{"tf":1.0}}},"df":0,"docs":{}}}},"df":0,"docs":{}},"df":1,"docs":{"22":{"tf":1.0}}},"df":0,"docs":{}}}},"df":0,"docs":{}},"df":3,"docs":{"22":{"tf":1.0},"26":{"tf":1.0},"5":{"tf":1.4142135623730951}}},"df":0,"docs":{},"w":{"df":1,"docs":{"15":{"tf":1.0}},"s":{"df":0,"docs":{},"h":{"df":0,"docs":{},"o":{"df":0,"docs":{},"r":{"df":0,"docs":{},"t":{"c":{"df":0,"docs":{},"u":{"df":0,"docs":{},"t":{"df":1,"docs":{"20":{"tf":1.0}},"s":{"(":{"df":0,"docs":{},"f":{"a":{"df":0,"docs":{},"l":{"df":0,"docs":{},"s":{"df":2,"docs":{"20":{"tf":1.0},"21":{"tf":1.0}}}}},"df":0,"docs":{}}},"df":0,"docs":{}}}}},"df":0,"docs":{}}}}}}}}},"t":{"df":0,"docs":{},"e":{"df":0,"docs":{},"r":{"df":1,"docs":{"22":{"tf":1.0}},"n":{"df":1,"docs":{"34":{"tf":1.0}}}}},"h":{"df":0,"docs":{},"o":{"df":0,"docs":{},"u":{"df":0,"docs":{},"g":{"df":0,"docs":{},"h":{"df":2,"docs":{"31":{"tf":1.0},"34":{"tf":1.0}}}}}}}},"w":{"a":{"df":0,"docs":{},"y":{"df":3,"docs":{"27":{"tf":1.0},"35":{"tf":1.0},"5":{"tf":1.0}}}},"df":0,"docs":{}}},"n":{"df":0,"docs":{},"o":{"df":0,"docs":{},"t":{"df":0,"docs":{},"h":{"df":2,"docs":{"32":{"tf":1.0},"33":{"tf":1.0}}}}},"y":{"df":0,"docs":{},"t":{"df":0,"docs":{},"h":{"df":1,"docs":{"29":{"tf":1.0}}}}}},"p":{"df":0,"docs":{},"i":{"df":1,"docs":{"30":{"tf":1.0}}},"p":{".":{"df":0,"docs":{},"e":{"df":0,"docs":{},"f":{"df":0,"docs":{},"i":{"df":2,"docs":{"12":{"tf":1.0},"8":{"tf":1.0}}}}}},"df":1,"docs":{"4":{"tf":1.4142135623730951}},"e":{"a":{"df":0,"docs":{},"r":{"df":2,"docs":{"13":{"tf":1.0},"17":{"tf":1.0}}}},"df":0,"docs":{}},"l":{"df":0,"docs":{},"i":{"c":{"df":11,"docs":{"0":{"tf":1.0},"1":{"tf":1.4142135623730951},"15":{"tf":1.0},"2":{"tf":1.0},"23":{"tf":1.4142135623730951},"25":{"tf":1.0},"26":{"tf":1.0},"28":{"tf":1.0},"4":{"tf":1.4142135623730951},"5":{"tf":2.23606797749979},"8":{"tf":1.4142135623730951}}},"df":0,"docs":{}}},"r":{"df":0,"docs":{},"o":{"df":0,"docs":{},"p":{"df":0,"docs":{},"r":{"df":0,"docs":{},"i":{"df":2,"docs":{"15":{"tf":1.0},"7":{"tf":1.0}}}}}}}},"t":{"df":1,"docs":{"10":{"tf":1.0}}}},"r":{"b":{"df":0,"docs":{},"i":{"df":0,"docs":{},"t":{"df":0,"docs":{},"r":{"a":{"df":0,"docs":{},"r":{"df":0,"docs":{},"i":{"df":1,"docs":{"32":{"tf":1.0}}}}},"df":0,"docs":{}}}}},"c":{"df":0,"docs":{},"h":{"df":1,"docs":{"35":{"tf":1.0}},"i":{"df":0,"docs":{},"t":{"df":0,"docs":{},"e":{"c":{"df":0,"docs":{},"t":{"df":0,"docs":{},"u":{"df":0,"docs":{},"r":{"df":2,"docs":{"15":{"tf":1.4142135623730951},"35":{"tf":1.4142135623730951}}}}}},"df":0,"docs":{}}}}}},"df":0,"docs":{},"e":{"df":0,"docs":{},"n":{"'":{"df":0,"docs":{},"t":{"df":1,"docs":{"27":{"tf":1.0}}}},"df":0,"docs":{}}},"g":{"df":0,"docs":{},"s":{"=":{"/":{"df":0,"docs":{},"s":{"df":0,"docs":{},"u":{"b":{"df":0,"docs":{},"s":{"df":0,"docs":{},"y":{"df":0,"docs":{},"s":{"df":0,"docs":{},"t":{"df":0,"docs":{},"e":{"df":0,"docs":{},"m":{":":{"df":0,"docs":{},"e":{"df":0,"docs":{},"f":{"df":0,"docs":{},"i":{"_":{"df":0,"docs":{},"r":{"df":0,"docs":{},"u":{"df":0,"docs":{},"n":{"df":0,"docs":{},"t":{"df":0,"docs":{},"i":{"df":0,"docs":{},"m":{"df":0,"docs":{},"e":{"_":{"d":{"df":0,"docs":{},"r":{"df":0,"docs":{},"i":{"df":0,"docs":{},"v":{"df":1,"docs":{"23":{"tf":1.0}}}}}},"df":0,"docs":{}},"df":0,"docs":{}}}}}}}}},"df":0,"docs":{}}}}},"df":0,"docs":{}}}}}}}},"df":0,"docs":{}}}},"df":0,"docs":{}},"df":0,"docs":{}},"u":{"df":0,"docs":{},"m":{"df":0,"docs":{},"e":{"df":0,"docs":{},"n":{"df":0,"docs":{},"t":{"df":3,"docs":{"21":{"tf":1.4142135623730951},"26":{"tf":1.0},"5":{"tf":1.0}}}}}}}},"r":{"a":{"df":0,"docs":{},"y":{"df":4,"docs":{"26":{"tf":1.0},"28":{"tf":1.0},"32":{"tf":1.0},"34":{"tf":2.0}}}},"df":0,"docs":{}},"t":{"df":0,"docs":{},"i":{"c":{"df":0,"docs":{},"l":{"df":1,"docs":{"33":{"tf":1.0}}}},"df":0,"docs":{}}}},"s":{"df":0,"docs":{},"s":{"df":0,"docs":{},"o":{"c":{"df":0,"docs":{},"i":{"df":1,"docs":{"33":{"tf":1.0}}}},"df":0,"docs":{}}}},"t":{"df":0,"docs":{},"t":{"df":0,"docs":{},"r":{"df":0,"docs":{},"i":{"b":{"df":0,"docs":{},"u":{"df":0,"docs":{},"t":{"df":1,"docs":{"33":{"tf":2.0}}}}},"df":0,"docs":{}}}}},"u":{"df":0,"docs":{},"t":{"df":0,"docs":{},"h":{"df":0,"docs":{},"e":{"df":0,"docs":{},"n":{"df":0,"docs":{},"t":{"df":1,"docs":{"33":{"tf":1.0}}}}}},"o":{"df":0,"docs":{},"m":{"a":{"df":0,"docs":{},"t":{"df":1,"docs":{"19":{"tf":1.0}}}},"df":0,"docs":{}}}}},"v":{"a":{"df":0,"docs":{},"i":{"df":0,"docs":{},"l":{"df":4,"docs":{"19":{"tf":1.0},"21":{"tf":1.4142135623730951},"25":{"tf":1.0},"30":{"tf":1.0}}}}},"df":0,"docs":{}},"w":{"a":{"df":0,"docs":{},"r":{"df":1,"docs":{"27":{"tf":1.0}}}},"df":0,"docs":{}}},"b":{"a":{"4":{"b":{"df":3,"docs":{"15":{"tf":1.0},"16":{"tf":1.0},"35":{"tf":1.0}}},"df":0,"docs":{}},"c":{"df":0,"docs":{},"k":{"df":0,"docs":{},"g":{"df":0,"docs":{},"r":{"df":0,"docs":{},"o":{"df":0,"docs":{},"u":{"df":0,"docs":{},"n":{"d":{"df":1,"docs":{"22":{"tf":1.0}}},"df":0,"docs":{}}}}}}}},"df":0,"docs":{}},"df":0,"docs":{},"e":{"c":{"a":{"df":0,"docs":{},"m":{"df":1,"docs":{"33":{"tf":1.0}}}},"df":0,"docs":{}},"df":1,"docs":{"33":{"tf":1.0}},"g":{"df":0,"docs":{},"i":{"df":0,"docs":{},"n":{"df":1,"docs":{"34":{"tf":1.0}}}}},"l":{"df":0,"docs":{},"o":{"df":0,"docs":{},"w":{"df":1,"docs":{"15":{"tf":1.0}}}}},"s":{"df":0,"docs":{},"t":{"df":2,"docs":{"21":{"tf":1.0},"30":{"tf":1.0}}}},"t":{"df":0,"docs":{},"w":{"df":0,"docs":{},"e":{"df":0,"docs":{},"e":{"df":0,"docs":{},"n":{"df":1,"docs":{"34":{"tf":1.0}}}}}}}},"g":{"df":0,"docs":{},"r":{"df":0,"docs":{},"x":{"df":1,"docs":{"22":{"tf":1.0}}}}},"i":{"df":0,"docs":{},"g":{"df":2,"docs":{"22":{"tf":1.0},"34":{"tf":1.0}}},"t":{"df":3,"docs":{"22":{"tf":1.4142135623730951},"33":{"tf":2.23606797749979},"35":{"tf":2.0}},"e":{"df":1,"docs":{"22":{"tf":1.0}}}}},"l":{"a":{"c":{"df":0,"docs":{},"k":{"df":1,"docs":{"22":{"tf":1.0}}}},"df":0,"docs":{}},"df":0,"docs":{},"i":{"df":0,"docs":{},"t":{"(":{"&":{"df":0,"docs":{},"s":{"df":0,"docs":{},"e":{"df":0,"docs":{},"l":{"df":0,"docs":{},"f":{"df":1,"docs":{"22":{"tf":1.4142135623730951}}}}}}},"df":0,"docs":{}},"df":1,"docs":{"22":{"tf":1.4142135623730951}}}},"o":{"c":{"df":0,"docs":{},"k":{"df":2,"docs":{"30":{"tf":1.0},"34":{"tf":1.0}},"i":{"df":0,"docs":{},"o":{"df":1,"docs":{"30":{"tf":1.0}}}}}},"df":0,"docs":{}},"t":{"df":1,"docs":{"22":{"tf":1.0}},"p":{"df":0,"docs":{},"i":{"df":0,"docs":{},"x":{"df":0,"docs":{},"e":{"df":0,"docs":{},"l":{"df":1,"docs":{"22":{"tf":2.0}}}}}}},"r":{"df":0,"docs":{},"e":{"df":0,"docs":{},"g":{"df":0,"docs":{},"i":{"df":0,"docs":{},"o":{"df":0,"docs":{},"n":{":":{":":{"df":0,"docs":{},"f":{"df":0,"docs":{},"u":{"df":0,"docs":{},"l":{"df":1,"docs":{"22":{"tf":1.4142135623730951}}}}}},"df":0,"docs":{}},"df":1,"docs":{"22":{"tf":1.0}}}}}}}}},"u":{"df":0,"docs":{},"e":{"df":1,"docs":{"22":{"tf":1.0}}}}},"o":{"df":0,"docs":{},"i":{"df":0,"docs":{},"l":{"df":0,"docs":{},"e":{"df":0,"docs":{},"r":{"df":0,"docs":{},"p":{"df":0,"docs":{},"l":{"df":1,"docs":{"5":{"tf":1.0}}}}}}}},"o":{"df":0,"docs":{},"k":{"df":1,"docs":{"0":{"tf":1.4142135623730951}}},"t":{"<":{"a":{"df":0,"docs":{},"r":{"c":{"df":0,"docs":{},"h":{">":{".":{"df":0,"docs":{},"e":{"df":0,"docs":{},"f":{"df":0,"docs":{},"i":{"df":1,"docs":{"35":{"tf":1.0}}}}}},"df":0,"docs":{}},"df":0,"docs":{}}},"df":0,"docs":{}}},"df":0,"docs":{}},"_":{"df":0,"docs":{},"s":{"df":0,"docs":{},"e":{"df":0,"docs":{},"r":{"df":0,"docs":{},"v":{"df":0,"docs":{},"i":{"c":{"df":2,"docs":{"20":{"tf":2.23606797749979},"21":{"tf":2.0}},"e":{"df":0,"docs":{},"s":{".":{"df":0,"docs":{},"s":{"df":0,"docs":{},"t":{"a":{"df":0,"docs":{},"l":{"df":0,"docs":{},"l":{"(":{"1":{"0":{"_":{"0":{"0":{"0":{"_":{"0":{"0":{"0":{"df":1,"docs":{"20":{"tf":1.0}}},"df":0,"docs":{}},"df":0,"docs":{}},"df":0,"docs":{}},"df":0,"docs":{}},"df":0,"docs":{}},"df":0,"docs":{}},"df":0,"docs":{}},"df":0,"docs":{}},"df":0,"docs":{}},"df":0,"docs":{}},"df":0,"docs":{}}}},"df":0,"docs":{}}}},"df":0,"docs":{}}}},"df":0,"docs":{}}}}}}},"a":{"a":{"6":{"4":{".":{"df":0,"docs":{},"e":{"df":0,"docs":{},"f":{"df":0,"docs":{},"i":{"df":1,"docs":{"35":{"tf":1.0}}}}}},"df":0,"docs":{}},"df":0,"docs":{}},"df":0,"docs":{}},"b":{"df":0,"docs":{},"l":{"df":1,"docs":{"35":{"tf":1.0}}}},"df":0,"docs":{},"r":{"df":0,"docs":{},"m":{".":{"df":0,"docs":{},"e":{"df":0,"docs":{},"f":{"df":0,"docs":{},"i":{"df":1,"docs":{"35":{"tf":1.0}}}}}},"df":0,"docs":{}}}},"df":11,"docs":{"15":{"tf":1.0},"16":{"tf":1.4142135623730951},"17":{"tf":1.7320508075688772},"23":{"tf":1.0},"25":{"tf":2.23606797749979},"26":{"tf":1.4142135623730951},"28":{"tf":1.0},"30":{"tf":1.0},"33":{"tf":1.7320508075688772},"34":{"tf":1.0},"35":{"tf":2.0}},"i":{"a":{"3":{"2":{".":{"df":0,"docs":{},"e":{"df":0,"docs":{},"f":{"df":0,"docs":{},"i":{"df":1,"docs":{"35":{"tf":1.0}}}}}},"df":0,"docs":{}},"df":0,"docs":{}},"6":{"4":{".":{"df":0,"docs":{},"e":{"df":0,"docs":{},"f":{"df":0,"docs":{},"i":{"df":1,"docs":{"35":{"tf":1.0}}}}}},"df":0,"docs":{}},"df":0,"docs":{}},"df":0,"docs":{}},"df":0,"docs":{}},"l":{"df":0,"docs":{},"o":{"a":{"d":{"df":1,"docs":{"25":{"tf":1.0}}},"df":0,"docs":{}},"df":0,"docs":{}}},"r":{"df":0,"docs":{},"i":{"df":0,"docs":{},"s":{"c":{"df":0,"docs":{},"v":{"1":{"2":{"8":{".":{"df":0,"docs":{},"e":{"df":0,"docs":{},"f":{"df":0,"docs":{},"i":{"df":1,"docs":{"35":{"tf":1.0}}}}}},"df":0,"docs":{}},"df":0,"docs":{}},"df":0,"docs":{}},"3":{"2":{".":{"df":0,"docs":{},"e":{"df":0,"docs":{},"f":{"df":0,"docs":{},"i":{"df":1,"docs":{"35":{"tf":1.0}}}}}},"df":0,"docs":{}},"df":0,"docs":{}},"6":{"4":{".":{"df":0,"docs":{},"e":{"df":0,"docs":{},"f":{"df":0,"docs":{},"i":{"df":1,"docs":{"35":{"tf":1.0}}}}}},"df":0,"docs":{}},"df":0,"docs":{}},"df":0,"docs":{}}},"df":0,"docs":{}}}},"s":{"df":0,"docs":{},"e":{"df":0,"docs":{},"r":{"df":0,"docs":{},"v":{"df":0,"docs":{},"i":{"c":{"df":5,"docs":{"20":{"tf":1.0},"21":{"tf":1.0},"22":{"tf":1.0},"25":{"tf":1.4142135623730951},"26":{"tf":1.0}},"e":{"_":{"a":{"c":{"c":{"df":0,"docs":{},"e":{"df":0,"docs":{},"s":{"df":0,"docs":{},"s":{"df":1,"docs":{"33":{"tf":1.4142135623730951}}}}}},"df":0,"docs":{}},"df":0,"docs":{}},"df":0,"docs":{}},"df":0,"docs":{},"s":{":":{":":{"df":0,"docs":{},"i":{"df":0,"docs":{},"m":{"a":{"df":0,"docs":{},"g":{"df":0,"docs":{},"e":{"_":{"df":0,"docs":{},"h":{"a":{"df":0,"docs":{},"n":{"d":{"df":0,"docs":{},"l":{"df":1,"docs":{"21":{"tf":1.0}}}},"df":0,"docs":{}}},"df":0,"docs":{}}},"df":0,"docs":{}}}},"df":0,"docs":{}}},"l":{"df":0,"docs":{},"o":{"c":{"a":{"df":0,"docs":{},"t":{"df":0,"docs":{},"e":{"_":{"d":{"df":0,"docs":{},"e":{"df":0,"docs":{},"v":{"df":0,"docs":{},"i":{"c":{"df":0,"docs":{},"e":{"_":{"df":0,"docs":{},"p":{"a":{"df":0,"docs":{},"t":{"df":0,"docs":{},"h":{"df":1,"docs":{"19":{"tf":1.0}}}}},"df":0,"docs":{}}},"df":0,"docs":{}}},"df":0,"docs":{}}}}},"df":0,"docs":{},"h":{"a":{"df":0,"docs":{},"n":{"d":{"df":0,"docs":{},"l":{"df":1,"docs":{"19":{"tf":1.0}},"e":{"_":{"b":{"df":0,"docs":{},"u":{"df":0,"docs":{},"f":{"df":0,"docs":{},"f":{"df":1,"docs":{"19":{"tf":1.0}}}}}},"df":0,"docs":{}},"df":0,"docs":{}}}},"df":0,"docs":{}}},"df":0,"docs":{}}},"df":0,"docs":{}}}},"df":0,"docs":{}},"df":0,"docs":{}}},"o":{"df":0,"docs":{},"p":{"df":0,"docs":{},"e":{"df":0,"docs":{},"n":{"_":{"df":0,"docs":{},"p":{"df":0,"docs":{},"r":{"df":0,"docs":{},"o":{"df":0,"docs":{},"t":{"df":0,"docs":{},"o":{"c":{"df":0,"docs":{},"o":{"df":0,"docs":{},"l":{"_":{"df":0,"docs":{},"e":{"df":0,"docs":{},"x":{"c":{"df":0,"docs":{},"l":{"df":0,"docs":{},"u":{"df":0,"docs":{},"s":{"df":1,"docs":{"19":{"tf":1.4142135623730951}}}}}},"df":0,"docs":{}}}},"df":1,"docs":{"19":{"tf":1.0}}}}},"df":0,"docs":{}}}}}}},"df":0,"docs":{}}}}}},"df":0,"docs":{}},"df":0,"docs":{}}}},"df":0,"docs":{}}}}}},"x":{"6":{"4":{".":{"df":0,"docs":{},"e":{"df":0,"docs":{},"f":{"df":0,"docs":{},"i":{"df":2,"docs":{"15":{"tf":1.0},"35":{"tf":1.0}}}}}},"df":0,"docs":{}},"df":0,"docs":{}},"df":0,"docs":{}}}},"r":{"d":{"df":0,"docs":{},"e":{"df":0,"docs":{},"r":{"df":1,"docs":{"22":{"tf":2.23606797749979}}}}},"df":0,"docs":{}},"t":{"df":0,"docs":{},"h":{"df":4,"docs":{"21":{"tf":1.4142135623730951},"25":{"tf":1.0},"26":{"tf":1.0},"33":{"tf":1.0}}}}},"t":{".":{"df":0,"docs":{},"g":{"df":0,"docs":{},"e":{"df":0,"docs":{},"t":{"_":{"df":0,"docs":{},"h":{"a":{"df":0,"docs":{},"n":{"d":{"df":0,"docs":{},"l":{"df":0,"docs":{},"e":{"_":{"df":0,"docs":{},"f":{"df":0,"docs":{},"o":{"df":0,"docs":{},"r":{"_":{"df":0,"docs":{},"p":{"df":0,"docs":{},"r":{"df":0,"docs":{},"o":{"df":0,"docs":{},"t":{"df":0,"docs":{},"o":{"c":{"df":0,"docs":{},"o":{"df":0,"docs":{},"l":{":":{":":{"<":{"df":0,"docs":{},"g":{"df":0,"docs":{},"r":{"a":{"df":0,"docs":{},"p":{"df":0,"docs":{},"h":{"df":0,"docs":{},"i":{"c":{"df":0,"docs":{},"s":{"df":0,"docs":{},"o":{"df":0,"docs":{},"u":{"df":0,"docs":{},"t":{"df":0,"docs":{},"p":{"df":0,"docs":{},"u":{"df":0,"docs":{},"t":{"df":1,"docs":{"22":{"tf":1.0}}}}}}}}}},"df":0,"docs":{}}}}},"df":0,"docs":{}}},"r":{"df":0,"docs":{},"n":{"df":0,"docs":{},"g":{"df":1,"docs":{"22":{"tf":1.0}}}}}},"df":0,"docs":{}},"df":0,"docs":{}},"df":0,"docs":{}}}},"df":0,"docs":{}}}}}}},"df":0,"docs":{}}}}},"df":0,"docs":{}}}},"df":0,"docs":{}}},"df":0,"docs":{}}},"df":0,"docs":{}}}},"o":{"df":0,"docs":{},"p":{"df":0,"docs":{},"e":{"df":0,"docs":{},"n":{"_":{"df":0,"docs":{},"p":{"df":0,"docs":{},"r":{"df":0,"docs":{},"o":{"df":0,"docs":{},"t":{"df":0,"docs":{},"o":{"c":{"df":0,"docs":{},"o":{"df":0,"docs":{},"l":{"_":{"df":0,"docs":{},"e":{"df":0,"docs":{},"x":{"c":{"df":0,"docs":{},"l":{"df":0,"docs":{},"u":{"df":0,"docs":{},"s":{"df":0,"docs":{},"i":{"df":0,"docs":{},"v":{"df":0,"docs":{},"e":{":":{":":{"<":{"df":0,"docs":{},"g":{"df":0,"docs":{},"r":{"a":{"df":0,"docs":{},"p":{"df":0,"docs":{},"h":{"df":0,"docs":{},"i":{"c":{"df":0,"docs":{},"s":{"df":0,"docs":{},"o":{"df":0,"docs":{},"u":{"df":0,"docs":{},"t":{"df":0,"docs":{},"p":{"df":0,"docs":{},"u":{"df":0,"docs":{},"t":{">":{"(":{"df":0,"docs":{},"g":{"df":0,"docs":{},"o":{"df":0,"docs":{},"p":{"_":{"df":0,"docs":{},"h":{"a":{"df":0,"docs":{},"n":{"d":{"df":0,"docs":{},"l":{"df":1,"docs":{"22":{"tf":1.0}}}},"df":0,"docs":{}}},"df":0,"docs":{}}},"df":0,"docs":{}}}}},"df":0,"docs":{}},"df":0,"docs":{}}}}}}}}},"df":0,"docs":{}}}}},"df":0,"docs":{}}},"r":{"df":0,"docs":{},"n":{"df":0,"docs":{},"g":{">":{"(":{"df":0,"docs":{},"r":{"df":0,"docs":{},"n":{"df":0,"docs":{},"g":{"_":{"df":0,"docs":{},"h":{"a":{"df":0,"docs":{},"n":{"d":{"df":0,"docs":{},"l":{"df":1,"docs":{"22":{"tf":1.0}}}},"df":0,"docs":{}}},"df":0,"docs":{}}},"df":0,"docs":{}}}}},"df":0,"docs":{}},"df":0,"docs":{}}}}},"df":0,"docs":{}},"df":0,"docs":{}},"df":0,"docs":{}}}}}}}},"df":0,"docs":{}}}},"df":0,"docs":{}}}},"df":0,"docs":{}}}}}}},"df":0,"docs":{}}}}}},"df":1,"docs":{"22":{"tf":1.0}}},"u":{"df":0,"docs":{},"f":{")":{".":{"df":0,"docs":{},"e":{"df":0,"docs":{},"x":{"df":0,"docs":{},"p":{"df":0,"docs":{},"e":{"c":{"df":0,"docs":{},"t":{"(":{"\"":{"df":0,"docs":{},"g":{"df":0,"docs":{},"e":{"df":0,"docs":{},"t":{"_":{"df":0,"docs":{},"r":{"df":0,"docs":{},"n":{"df":0,"docs":{},"g":{"df":1,"docs":{"22":{"tf":1.0}}}}}},"df":0,"docs":{}}}}},"df":0,"docs":{}},"df":0,"docs":{}}},"df":0,"docs":{}}}}}},"df":0,"docs":{}},"df":1,"docs":{"22":{"tf":1.0}},"f":{"df":0,"docs":{},"e":{"df":0,"docs":{},"r":{".":{"b":{"df":0,"docs":{},"l":{"df":0,"docs":{},"i":{"df":0,"docs":{},"t":{"(":{"&":{"df":0,"docs":{},"m":{"df":0,"docs":{},"u":{"df":0,"docs":{},"t":{"df":1,"docs":{"22":{"tf":1.0}}}}}},"df":0,"docs":{}},"df":0,"docs":{}}}}},"df":0,"docs":{},"p":{"df":0,"docs":{},"i":{"df":0,"docs":{},"x":{"df":0,"docs":{},"e":{"df":0,"docs":{},"l":{"(":{"df":0,"docs":{},"p":{".":{"df":0,"docs":{},"x":{"df":1,"docs":{"22":{"tf":1.0}}}},"df":0,"docs":{}},"x":{"df":1,"docs":{"22":{"tf":1.0}}}},"df":0,"docs":{}}}}}}},":":{":":{"b":{"df":0,"docs":{},"l":{"df":0,"docs":{},"i":{"df":0,"docs":{},"t":{"df":1,"docs":{"22":{"tf":1.0}}}}}},"df":0,"docs":{},"n":{"df":0,"docs":{},"e":{"df":0,"docs":{},"w":{"(":{"df":0,"docs":{},"w":{"df":0,"docs":{},"i":{"d":{"df":0,"docs":{},"t":{"df":0,"docs":{},"h":{"df":1,"docs":{"22":{"tf":1.0}}}}},"df":0,"docs":{}}}},"df":0,"docs":{}}}}},"df":0,"docs":{}},"df":1,"docs":{"22":{"tf":4.358898943540674}}}}}},"i":{"df":0,"docs":{},"l":{"d":{"df":4,"docs":{"0":{"tf":1.0},"23":{"tf":1.4142135623730951},"6":{"tf":1.0},"8":{"tf":1.7320508075688772}}},"df":0,"docs":{}}}},"y":{"df":0,"docs":{},"t":{"df":0,"docs":{},"e":{"df":2,"docs":{"27":{"tf":1.4142135623730951},"32":{"tf":1.0}}}}}},"c":{"1":{"2":{"a":{"7":{"3":{"2":{"8":{"df":2,"docs":{"15":{"tf":1.0},"35":{"tf":1.0}}},"df":0,"docs":{}},"df":0,"docs":{}},"df":0,"docs":{}},"df":0,"docs":{}},"df":0,"docs":{}},"df":0,"docs":{}},"a":{"df":0,"docs":{},"l":{"df":0,"docs":{},"l":{"df":6,"docs":{"21":{"tf":2.0},"22":{"tf":1.0},"25":{"tf":1.0},"26":{"tf":1.4142135623730951},"35":{"tf":1.0},"5":{"tf":1.0}}}},"n":{"'":{"df":0,"docs":{},"t":{"df":2,"docs":{"29":{"tf":1.0},"30":{"tf":1.0}}}},"df":0,"docs":{},"o":{"df":0,"docs":{},"n":{"df":1,"docs":{"24":{"tf":1.0}}}}},"p":{"df":0,"docs":{},"i":{"df":0,"docs":{},"t":{"df":1,"docs":{"15":{"tf":1.0}}}}},"r":{"df":0,"docs":{},"e":{"df":2,"docs":{"16":{"tf":1.0},"33":{"tf":1.0}}},"g":{"df":0,"docs":{},"o":{"/":{"c":{"df":0,"docs":{},"o":{"df":0,"docs":{},"n":{"df":0,"docs":{},"f":{"df":0,"docs":{},"i":{"df":0,"docs":{},"g":{".":{"df":0,"docs":{},"t":{"df":0,"docs":{},"o":{"df":0,"docs":{},"m":{"df":0,"docs":{},"l":{"df":1,"docs":{"23":{"tf":1.0}}}}}}},"df":0,"docs":{}}}}}}},"df":0,"docs":{}},"df":3,"docs":{"22":{"tf":1.0},"4":{"tf":1.4142135623730951},"8":{"tf":1.0}}}}},"s":{"df":0,"docs":{},"e":{"df":5,"docs":{"15":{"tf":1.0},"19":{"tf":1.4142135623730951},"20":{"tf":1.0},"21":{"tf":1.0},"33":{"tf":1.0}}}},"u":{"df":0,"docs":{},"s":{"df":1,"docs":{"33":{"tf":1.0}}}}},"d":{"df":1,"docs":{"4":{"tf":1.0}}},"df":1,"docs":{"23":{"tf":1.0}},"e":{"df":0,"docs":{},"n":{"df":0,"docs":{},"t":{"df":0,"docs":{},"e":{"df":0,"docs":{},"r":{"df":1,"docs":{"22":{"tf":1.0}}}}}}},"h":{"a":{"df":0,"docs":{},"n":{"df":0,"docs":{},"g":{"df":4,"docs":{"22":{"tf":1.0},"23":{"tf":1.0},"33":{"tf":1.0},"4":{"tf":1.0}}}},"o":{"df":1,"docs":{"22":{"tf":1.0}}},"p":{"df":0,"docs":{},"t":{"df":0,"docs":{},"e":{"df":0,"docs":{},"r":{"df":3,"docs":{"18":{"tf":1.0},"24":{"tf":1.0},"30":{"tf":1.0}}}}}}},"df":0,"docs":{},"o":{"df":0,"docs":{},"o":{"df":0,"docs":{},"s":{"df":1,"docs":{"22":{"tf":1.0}}}},"s":{"df":0,"docs":{},"e":{"df":0,"docs":{},"n":{"df":1,"docs":{"22":{"tf":1.0}}}}}}},"l":{"df":0,"docs":{},"e":{"a":{"df":0,"docs":{},"r":{"df":2,"docs":{"16":{"tf":1.0},"34":{"tf":1.0}}}},"df":0,"docs":{}},"o":{"df":0,"docs":{},"s":{"df":0,"docs":{},"e":{"df":1,"docs":{"19":{"tf":1.0}}}}}},"o":{"d":{"df":0,"docs":{},"e":{"df":3,"docs":{"11":{"tf":1.4142135623730951},"22":{"tf":1.4142135623730951},"5":{"tf":1.0}}}},"df":0,"docs":{},"l":{"df":0,"docs":{},"l":{"df":0,"docs":{},"e":{"c":{"df":0,"docs":{},"t":{"df":1,"docs":{"33":{"tf":1.0}}}},"df":0,"docs":{}}}},"m":{"b":{"df":0,"docs":{},"i":{"df":0,"docs":{},"n":{"df":1,"docs":{"21":{"tf":1.0}}}}},"df":0,"docs":{},"m":{"a":{"df":0,"docs":{},"n":{"d":{"df":2,"docs":{"16":{"tf":1.0},"8":{"tf":1.0}}},"df":0,"docs":{}}},"df":0,"docs":{},"o":{"df":0,"docs":{},"n":{"df":0,"docs":{},"l":{"df":0,"docs":{},"i":{"df":2,"docs":{"30":{"tf":1.0},"5":{"tf":1.0}}}}}}},"p":{"df":0,"docs":{},"i":{"df":0,"docs":{},"l":{"df":1,"docs":{"7":{"tf":1.0}}}},"l":{"df":0,"docs":{},"e":{"df":0,"docs":{},"t":{"df":1,"docs":{"5":{"tf":1.0}}},"x":{"df":1,"docs":{"22":{"tf":1.0}}}}},"u":{"df":0,"docs":{},"t":{"df":1,"docs":{"17":{"tf":1.0}}}}}},"n":{"c":{"df":0,"docs":{},"e":{"df":0,"docs":{},"p":{"df":0,"docs":{},"t":{"df":2,"docs":{"0":{"tf":1.0},"24":{"tf":1.4142135623730951}}}}}},"d":{"df":0,"docs":{},"i":{"df":0,"docs":{},"t":{"df":1,"docs":{"28":{"tf":1.0}}}}},"df":0,"docs":{},"f":{"df":0,"docs":{},"i":{"df":0,"docs":{},"g":{"df":0,"docs":{},"u":{"df":0,"docs":{},"r":{"df":1,"docs":{"35":{"tf":1.0}}}}}},"o":{"df":0,"docs":{},"r":{"df":0,"docs":{},"m":{"df":1,"docs":{"15":{"tf":1.0}}}}}},"s":{"df":0,"docs":{},"i":{"df":0,"docs":{},"s":{"df":0,"docs":{},"t":{"df":2,"docs":{"28":{"tf":1.0},"32":{"tf":1.0}}}}},"o":{"df":0,"docs":{},"l":{"df":1,"docs":{"31":{"tf":1.0}}}},"u":{"df":0,"docs":{},"m":{"df":1,"docs":{"26":{"tf":1.0}}}}},"t":{"a":{"df":0,"docs":{},"i":{"df":0,"docs":{},"n":{"df":6,"docs":{"12":{"tf":1.0},"16":{"tf":1.0},"18":{"tf":1.0},"31":{"tf":1.0},"34":{"tf":1.4142135623730951},"35":{"tf":1.0}}}}},"df":0,"docs":{},"e":{"df":0,"docs":{},"n":{"df":0,"docs":{},"t":{"df":2,"docs":{"24":{"tf":1.0},"4":{"tf":1.0}}}}},"r":{"df":0,"docs":{},"i":{"b":{"df":0,"docs":{},"u":{"df":0,"docs":{},"t":{"df":1,"docs":{"30":{"tf":1.0}}}}},"df":0,"docs":{}}}},"v":{"df":0,"docs":{},"e":{"df":0,"docs":{},"n":{"df":0,"docs":{},"i":{"df":1,"docs":{"21":{"tf":1.0}}}},"r":{"df":0,"docs":{},"t":{"_":{"d":{"df":0,"docs":{},"e":{"df":0,"docs":{},"v":{"df":0,"docs":{},"i":{"c":{"df":0,"docs":{},"e":{"_":{"df":0,"docs":{},"p":{"a":{"df":0,"docs":{},"t":{"df":0,"docs":{},"h":{"_":{"df":0,"docs":{},"t":{"df":0,"docs":{},"o":{"_":{"df":0,"docs":{},"t":{"df":0,"docs":{},"e":{"df":0,"docs":{},"x":{"df":0,"docs":{},"t":{"df":2,"docs":{"20":{"tf":1.0},"21":{"tf":1.0}}}}}}},"df":0,"docs":{}}}},"df":0,"docs":{}}}},"df":0,"docs":{}}},"df":0,"docs":{}}},"df":0,"docs":{}}}}},"df":0,"docs":{}},"df":2,"docs":{"21":{"tf":1.0},"31":{"tf":1.0}}}}}}},"p":{"df":0,"docs":{},"i":{"df":5,"docs":{"11":{"tf":1.4142135623730951},"15":{"tf":1.0},"16":{"tf":1.0},"22":{"tf":1.4142135623730951},"34":{"tf":1.0}}}},"r":{"df":0,"docs":{},"e":{":":{":":{"df":0,"docs":{},"m":{"df":0,"docs":{},"e":{"df":0,"docs":{},"m":{"df":1,"docs":{"22":{"tf":1.0}}}}}},"df":0,"docs":{}},"df":3,"docs":{"22":{"tf":1.0},"28":{"tf":1.0},"5":{"tf":1.0}}}},"u":{"df":0,"docs":{},"p":{"df":0,"docs":{},"l":{"df":2,"docs":{"20":{"tf":1.0},"34":{"tf":1.0}}}}},"v":{"df":0,"docs":{},"e":{"df":0,"docs":{},"r":{"df":1,"docs":{"30":{"tf":1.0}}}}}},"p":{"df":3,"docs":{"11":{"tf":1.4142135623730951},"12":{"tf":1.0},"16":{"tf":1.0}}},"r":{"a":{"df":0,"docs":{},"t":{"df":0,"docs":{},"e":{"df":3,"docs":{"22":{"tf":1.4142135623730951},"36":{"tf":2.0},"5":{"tf":2.0}}}}},"df":0,"docs":{},"e":{"a":{"df":0,"docs":{},"t":{"df":8,"docs":{"1":{"tf":1.0},"12":{"tf":1.0},"13":{"tf":1.0},"15":{"tf":1.4142135623730951},"16":{"tf":1.7320508075688772},"2":{"tf":1.0},"22":{"tf":1.7320508075688772},"4":{"tf":1.4142135623730951}}}},"df":0,"docs":{}},"i":{"df":0,"docs":{},"t":{"df":0,"docs":{},"i":{"c":{"df":1,"docs":{"24":{"tf":1.0}}},"df":0,"docs":{}}}}},"u":{"df":0,"docs":{},"l":{"df":0,"docs":{},"m":{"df":0,"docs":{},"i":{"df":0,"docs":{},"n":{"df":1,"docs":{"25":{"tf":1.0}}}}}},"r":{"df":0,"docs":{},"r":{"df":0,"docs":{},"e":{"df":0,"docs":{},"n":{"df":0,"docs":{},"t":{"df":5,"docs":{"20":{"tf":1.0},"21":{"tf":1.0},"24":{"tf":1.0},"5":{"tf":1.0},"7":{"tf":1.0}}}}}}}},"y":{"c":{"df":0,"docs":{},"l":{"df":1,"docs":{"33":{"tf":1.0}}}},"df":0,"docs":{}}},"d":{"a":{"df":0,"docs":{},"t":{"a":{"df":5,"docs":{"16":{"tf":1.0},"21":{"tf":1.4142135623730951},"31":{"tf":1.0},"32":{"tf":1.0},"34":{"tf":1.0}}},"df":0,"docs":{}}},"df":0,"docs":{},"e":{"a":{"df":0,"docs":{},"l":{"df":1,"docs":{"33":{"tf":1.0}}}},"b":{"df":0,"docs":{},"i":{"a":{"df":0,"docs":{},"n":{"/":{"df":0,"docs":{},"u":{"b":{"df":0,"docs":{},"u":{"df":0,"docs":{},"n":{"df":0,"docs":{},"t":{"df":0,"docs":{},"u":{"df":1,"docs":{"10":{"tf":1.0}}}}}}},"df":0,"docs":{}}},"df":1,"docs":{"11":{"tf":1.0}}}},"df":0,"docs":{}}},"df":0,"docs":{},"f":{"a":{"df":0,"docs":{},"u":{"df":0,"docs":{},"l":{"df":0,"docs":{},"t":{"df":3,"docs":{"21":{"tf":1.0},"23":{"tf":1.0},"35":{"tf":1.0}}}}}},"df":0,"docs":{},"i":{"df":0,"docs":{},"n":{"df":4,"docs":{"22":{"tf":1.0},"30":{"tf":1.0},"34":{"tf":1.0},"5":{"tf":1.0}}}}},"l":{"df":0,"docs":{},"e":{"df":0,"docs":{},"t":{"df":1,"docs":{"33":{"tf":1.0}}}},"l":{"df":1,"docs":{"17":{"tf":1.0}}}},"p":{"df":0,"docs":{},"e":{"df":0,"docs":{},"n":{"d":{"df":6,"docs":{"10":{"tf":1.7320508075688772},"11":{"tf":1.0},"15":{"tf":1.0},"17":{"tf":1.0},"3":{"tf":1.0},"4":{"tf":1.0}}},"df":0,"docs":{}}}},"r":{"df":0,"docs":{},"i":{"df":0,"docs":{},"v":{"df":0,"docs":{},"e":{"(":{"c":{"df":0,"docs":{},"l":{"df":0,"docs":{},"o":{"df":0,"docs":{},"n":{"df":1,"docs":{"22":{"tf":1.0}}}}}},"df":0,"docs":{}},"df":0,"docs":{}}}}},"s":{"c":{"df":0,"docs":{},"r":{"df":0,"docs":{},"i":{"b":{"df":5,"docs":{"0":{"tf":1.0},"1":{"tf":1.0},"25":{"tf":1.0},"31":{"tf":1.0},"34":{"tf":1.0}}},"df":0,"docs":{}}}},"df":0,"docs":{},"t":{"df":1,"docs":{"22":{"tf":1.4142135623730951}},"r":{"df":0,"docs":{},"u":{"c":{"df":0,"docs":{},"t":{"df":1,"docs":{"16":{"tf":1.0}}}},"df":0,"docs":{}}}}},"t":{"a":{"df":0,"docs":{},"i":{"df":0,"docs":{},"l":{"df":8,"docs":{"10":{"tf":1.0},"11":{"tf":1.0},"15":{"tf":1.0},"20":{"tf":1.0},"27":{"tf":1.0},"30":{"tf":1.0},"31":{"tf":1.4142135623730951},"33":{"tf":1.0}}}}},"df":0,"docs":{}},"v":{"df":0,"docs":{},"i":{"c":{"df":4,"docs":{"19":{"tf":1.0},"29":{"tf":1.4142135623730951},"30":{"tf":1.0},"31":{"tf":2.8284271247461903}},"e":{"_":{"df":0,"docs":{},"p":{"a":{"df":0,"docs":{},"t":{"df":0,"docs":{},"h":{"_":{"df":0,"docs":{},"t":{"df":0,"docs":{},"o":{"_":{"df":0,"docs":{},"t":{"df":0,"docs":{},"e":{"df":0,"docs":{},"x":{"df":0,"docs":{},"t":{"_":{"df":0,"docs":{},"h":{"a":{"df":0,"docs":{},"n":{"d":{"df":0,"docs":{},"l":{"df":2,"docs":{"20":{"tf":1.4142135623730951},"21":{"tf":1.7320508075688772}}}},"df":0,"docs":{}}},"df":0,"docs":{}}},"df":2,"docs":{"20":{"tf":1.4142135623730951},"21":{"tf":1.4142135623730951}}}}}}},"df":0,"docs":{}}}},"df":0,"docs":{}}}},"df":0,"docs":{}}},"df":0,"docs":{},"p":{"a":{"df":0,"docs":{},"t":{"df":0,"docs":{},"h":{"df":0,"docs":{},"t":{"df":0,"docs":{},"o":{"df":0,"docs":{},"t":{"df":0,"docs":{},"e":{"df":0,"docs":{},"x":{"df":0,"docs":{},"t":{"df":2,"docs":{"20":{"tf":1.4142135623730951},"21":{"tf":1.7320508075688772}}}}}}}}}}},"df":0,"docs":{}}}},"df":0,"docs":{}}}},"i":{"df":0,"docs":{},"f":{"df":0,"docs":{},"f":{"df":0,"docs":{},"e":{"df":0,"docs":{},"r":{"df":5,"docs":{"20":{"tf":1.0},"21":{"tf":1.0},"32":{"tf":1.0},"35":{"tf":1.0},"5":{"tf":1.7320508075688772}}}}}},"m":{"df":1,"docs":{"22":{"tf":1.4142135623730951}}},"r":{"df":0,"docs":{},"e":{"c":{"df":0,"docs":{},"t":{"df":0,"docs":{},"l":{"df":0,"docs":{},"i":{"df":1,"docs":{"29":{"tf":1.0}}}},"o":{"df":0,"docs":{},"r":{"df":0,"docs":{},"i":{"df":6,"docs":{"11":{"tf":1.4142135623730951},"12":{"tf":1.0},"13":{"tf":1.0},"15":{"tf":1.4142135623730951},"16":{"tf":1.0},"4":{"tf":1.0}}}}}}},"df":0,"docs":{}}},"s":{"c":{"a":{"df":0,"docs":{},"r":{"d":{"df":1,"docs":{"21":{"tf":1.0}}},"df":0,"docs":{}}},"df":0,"docs":{}},"df":0,"docs":{},"k":{"df":5,"docs":{"16":{"tf":1.0},"27":{"tf":1.0},"29":{"tf":1.0},"31":{"tf":1.0},"34":{"tf":2.0}}},"p":{"df":0,"docs":{},"l":{"a":{"df":0,"docs":{},"y":{"df":0,"docs":{},"o":{"df":0,"docs":{},"n":{"df":0,"docs":{},"l":{"df":0,"docs":{},"i":{"df":1,"docs":{"20":{"tf":1.0}}},"y":{"(":{"df":0,"docs":{},"t":{"df":0,"docs":{},"r":{"df":0,"docs":{},"u":{"df":2,"docs":{"20":{"tf":1.0},"21":{"tf":1.0}}}}}},"df":0,"docs":{}}}}}}},"df":0,"docs":{}}},"t":{"df":0,"docs":{},"i":{"df":0,"docs":{},"n":{"c":{"df":0,"docs":{},"t":{"df":1,"docs":{"25":{"tf":1.0}}}},"df":0,"docs":{}}}}},"v":{"df":0,"docs":{},"e":{"df":0,"docs":{},"r":{"df":0,"docs":{},"s":{"df":1,"docs":{"30":{"tf":1.0}}}}}}},"n":{"df":0,"docs":{},"f":{"df":1,"docs":{"10":{"tf":1.0}}}},"o":{"c":{"df":0,"docs":{},"u":{"df":0,"docs":{},"m":{"df":0,"docs":{},"e":{"df":0,"docs":{},"n":{"df":0,"docs":{},"t":{"df":4,"docs":{"11":{"tf":1.0},"21":{"tf":1.0},"24":{"tf":1.0},"31":{"tf":1.0}}}}}}}},"df":1,"docs":{"5":{"tf":1.0}},"e":{"df":0,"docs":{},"s":{"df":0,"docs":{},"n":{"'":{"df":0,"docs":{},"t":{"df":1,"docs":{"15":{"tf":1.0}}}},"df":0,"docs":{}}}},"n":{"'":{"df":0,"docs":{},"t":{"df":2,"docs":{"32":{"tf":1.0},"7":{"tf":1.0}}}},"df":0,"docs":{}},"w":{"df":0,"docs":{},"n":{"df":1,"docs":{"17":{"tf":1.0}}}}},"r":{"a":{"df":0,"docs":{},"w":{"_":{"df":0,"docs":{},"s":{"df":0,"docs":{},"i":{"df":0,"docs":{},"e":{"df":0,"docs":{},"r":{"df":0,"docs":{},"p":{"df":0,"docs":{},"i":{"df":0,"docs":{},"n":{"df":0,"docs":{},"s":{"df":0,"docs":{},"k":{"df":0,"docs":{},"i":{"(":{"b":{"df":0,"docs":{},"t":{")":{".":{"df":0,"docs":{},"u":{"df":0,"docs":{},"n":{"df":0,"docs":{},"w":{"df":0,"docs":{},"r":{"a":{"df":0,"docs":{},"p":{"df":1,"docs":{"22":{"tf":1.0}}}},"df":0,"docs":{}}}}}},"df":0,"docs":{}},"df":1,"docs":{"22":{"tf":1.0}}}},"df":0,"docs":{}},"df":0,"docs":{}}}}}}}}}}}},"df":1,"docs":{"22":{"tf":2.6457513110645907}}}},"df":0,"docs":{},"i":{"df":0,"docs":{},"v":{"df":0,"docs":{},"e":{"df":5,"docs":{"13":{"tf":1.7320508075688772},"14":{"tf":1.0},"15":{"tf":1.4142135623730951},"17":{"tf":1.0},"29":{"tf":1.0}},"r":{"df":3,"docs":{"23":{"tf":1.7320508075688772},"25":{"tf":1.0},"28":{"tf":1.0}}}}}},"o":{"df":0,"docs":{},"p":{"df":1,"docs":{"19":{"tf":1.0}}}}},"u":{"df":0,"docs":{},"e":{"df":1,"docs":{"33":{"tf":1.0}}},"r":{"df":0,"docs":{},"e":{"df":4,"docs":{"25":{"tf":1.0},"26":{"tf":1.0},"30":{"tf":1.4142135623730951},"33":{"tf":1.0}}}}}},"df":0,"docs":{},"e":{"a":{"c":{"df":0,"docs":{},"h":{"df":6,"docs":{"21":{"tf":1.4142135623730951},"22":{"tf":1.4142135623730951},"32":{"tf":1.4142135623730951},"33":{"tf":1.0},"34":{"tf":1.0},"5":{"tf":1.0}}}},"df":0,"docs":{},"r":{"df":0,"docs":{},"l":{"df":0,"docs":{},"i":{"df":1,"docs":{"25":{"tf":1.0}}}}},"s":{"df":1,"docs":{"11":{"tf":1.0}},"i":{"df":0,"docs":{},"e":{"df":0,"docs":{},"s":{"df":0,"docs":{},"t":{"df":1,"docs":{"7":{"tf":1.0}}}}}}}},"d":{"df":0,"docs":{},"k":{"2":{"df":1,"docs":{"10":{"tf":1.0}}},"df":0,"docs":{}}},"df":0,"docs":{},"f":{"df":0,"docs":{},"f":{"df":0,"docs":{},"i":{"c":{"df":0,"docs":{},"i":{"df":1,"docs":{"22":{"tf":1.0}}}},"df":0,"docs":{}}},"i":{"/":{"b":{"df":0,"docs":{},"o":{"df":0,"docs":{},"o":{"df":0,"docs":{},"t":{"df":1,"docs":{"15":{"tf":1.4142135623730951}}}}}},"df":0,"docs":{}},"\\":{"b":{"df":0,"docs":{},"o":{"df":0,"docs":{},"o":{"df":0,"docs":{},"t":{"\\":{"b":{"df":0,"docs":{},"o":{"df":0,"docs":{},"o":{"df":0,"docs":{},"t":{"df":0,"docs":{},"x":{"6":{"4":{".":{"df":0,"docs":{},"e":{"df":0,"docs":{},"f":{"df":0,"docs":{},"i":{"df":1,"docs":{"20":{"tf":1.0}}}}}},"df":0,"docs":{}},"df":0,"docs":{}},"df":0,"docs":{}}}}}},"df":0,"docs":{}},"df":1,"docs":{"35":{"tf":1.0}}}}}},"df":0,"docs":{}},"_":{"b":{"df":0,"docs":{},"o":{"df":0,"docs":{},"o":{"df":0,"docs":{},"t":{"_":{"df":0,"docs":{},"s":{"df":0,"docs":{},"e":{"df":0,"docs":{},"r":{"df":0,"docs":{},"v":{"df":0,"docs":{},"i":{"c":{"df":1,"docs":{"26":{"tf":1.0}},"e":{"_":{"d":{"df":0,"docs":{},"r":{"df":0,"docs":{},"i":{"df":0,"docs":{},"v":{"df":1,"docs":{"23":{"tf":1.0}}}}}},"df":0,"docs":{}},"df":0,"docs":{}}},"df":0,"docs":{}}}}}}},"df":0,"docs":{}}}}},"df":0,"docs":{},"r":{"df":0,"docs":{},"u":{"df":0,"docs":{},"n":{"df":0,"docs":{},"t":{"df":0,"docs":{},"i":{"df":0,"docs":{},"m":{"df":0,"docs":{},"e":{"_":{"d":{"df":0,"docs":{},"r":{"df":0,"docs":{},"i":{"df":0,"docs":{},"v":{"df":1,"docs":{"23":{"tf":1.0}}}}}},"df":0,"docs":{},"s":{"df":0,"docs":{},"e":{"df":0,"docs":{},"r":{"df":0,"docs":{},"v":{"df":0,"docs":{},"i":{"c":{"df":1,"docs":{"26":{"tf":1.0}}},"df":0,"docs":{}}}}}}},"df":0,"docs":{}}}}}}}},"s":{"df":0,"docs":{},"y":{"df":0,"docs":{},"s":{"df":0,"docs":{},"t":{"df":0,"docs":{},"e":{"df":0,"docs":{},"m":{"_":{"df":0,"docs":{},"t":{"df":1,"docs":{"26":{"tf":1.0}}}},"df":0,"docs":{}}}}}}}},"df":3,"docs":{"15":{"tf":1.7320508075688772},"16":{"tf":1.0},"35":{"tf":1.0}}}},"m":{"b":{"df":0,"docs":{},"e":{"d":{"df":1,"docs":{"22":{"tf":1.0}}},"df":0,"docs":{}}},"df":0,"docs":{},"p":{"df":0,"docs":{},"t":{"df":0,"docs":{},"i":{"df":1,"docs":{"4":{"tf":1.0}}}}}},"n":{"a":{"b":{"df":0,"docs":{},"l":{"df":1,"docs":{"13":{"tf":1.0}}}},"df":0,"docs":{}},"c":{"df":0,"docs":{},"o":{"d":{"df":1,"docs":{"31":{"tf":1.0}}},"df":0,"docs":{}}},"d":{"df":2,"docs":{"25":{"tf":1.0},"34":{"tf":1.0}},"i":{"a":{"df":0,"docs":{},"n":{"df":1,"docs":{"27":{"tf":1.0}}}},"df":0,"docs":{}}},"df":0,"docs":{},"o":{"df":0,"docs":{},"u":{"df":0,"docs":{},"g":{"df":0,"docs":{},"h":{"df":1,"docs":{"5":{"tf":1.0}}}}}},"s":{"df":0,"docs":{},"u":{"df":0,"docs":{},"r":{"df":1,"docs":{"5":{"tf":1.0}}}}},"t":{"df":0,"docs":{},"e":{"df":0,"docs":{},"r":{"df":1,"docs":{"17":{"tf":1.0}}}},"r":{"df":0,"docs":{},"i":{"df":6,"docs":{"20":{"tf":1.0},"22":{"tf":1.0},"26":{"tf":1.0},"34":{"tf":2.0},"4":{"tf":1.0},"5":{"tf":1.4142135623730951}}}}}},"r":{"df":0,"docs":{},"r":{"df":0,"docs":{},"o":{"df":0,"docs":{},"r":{"df":2,"docs":{"21":{"tf":1.4142135623730951},"5":{"tf":1.0}}}}}},"s":{"df":0,"docs":{},"p":{"/":{"df":0,"docs":{},"e":{"df":0,"docs":{},"f":{"df":0,"docs":{},"i":{"/":{"b":{"df":0,"docs":{},"o":{"df":0,"docs":{},"o":{"df":0,"docs":{},"t":{"/":{"b":{"df":0,"docs":{},"o":{"df":0,"docs":{},"o":{"df":0,"docs":{},"t":{"df":0,"docs":{},"x":{"6":{"4":{".":{"df":0,"docs":{},"e":{"df":0,"docs":{},"f":{"df":0,"docs":{},"i":{"df":2,"docs":{"12":{"tf":1.0},"16":{"tf":1.0}}}}}},"df":0,"docs":{}},"df":0,"docs":{}},"df":0,"docs":{}}}}}},"df":0,"docs":{}},"df":2,"docs":{"12":{"tf":1.0},"16":{"tf":1.0}}}}}},"df":0,"docs":{}},"df":0,"docs":{}}}}},"df":4,"docs":{"13":{"tf":1.0},"15":{"tf":1.0},"16":{"tf":1.4142135623730951},"35":{"tf":1.0}}},"s":{"df":0,"docs":{},"e":{"df":0,"docs":{},"n":{"df":0,"docs":{},"t":{"df":0,"docs":{},"i":{"df":2,"docs":{"31":{"tf":1.0},"5":{"tf":1.0}}}}}}}},"v":{"df":0,"docs":{},"e":{"df":0,"docs":{},"n":{"df":1,"docs":{"33":{"tf":1.0}}},"r":{"df":0,"docs":{},"y":{"df":0,"docs":{},"t":{"df":0,"docs":{},"h":{"df":1,"docs":{"5":{"tf":1.0}}}}}}}},"x":{"a":{"c":{"df":0,"docs":{},"t":{"df":0,"docs":{},"l":{"df":0,"docs":{},"i":{"df":1,"docs":{"15":{"tf":1.0}}}}}},"df":0,"docs":{},"m":{"df":0,"docs":{},"p":{"df":0,"docs":{},"l":{"df":8,"docs":{"15":{"tf":1.0},"16":{"tf":1.0},"17":{"tf":1.0},"20":{"tf":1.4142135623730951},"21":{"tf":1.4142135623730951},"22":{"tf":2.0},"23":{"tf":1.0},"30":{"tf":1.0}},"e":{".":{"df":0,"docs":{},"r":{"df":0,"docs":{},"s":{"@":{"0":{"5":{"8":{"df":1,"docs":{"20":{"tf":1.0}}},"df":0,"docs":{}},"df":0,"docs":{}},"df":0,"docs":{}},"df":0,"docs":{}}}},"df":0,"docs":{}}}}}},"c":{"df":0,"docs":{},"i":{"df":0,"docs":{},"t":{"df":1,"docs":{"5":{"tf":1.0}}}},"l":{"df":0,"docs":{},"u":{"df":0,"docs":{},"s":{"df":1,"docs":{"19":{"tf":1.0}}}}}},"df":0,"docs":{},"e":{"c":{"df":0,"docs":{},"u":{"df":0,"docs":{},"t":{"a":{"b":{"df":0,"docs":{},"l":{"df":0,"docs":{},"e":{".":{"df":0,"docs":{},"e":{"df":0,"docs":{},"f":{"df":0,"docs":{},"i":{"df":1,"docs":{"16":{"tf":1.0}}}}}},"df":0,"docs":{}}}},"df":0,"docs":{}},"df":8,"docs":{"11":{"tf":1.0},"12":{"tf":1.0},"16":{"tf":1.0},"20":{"tf":1.0},"26":{"tf":1.0},"29":{"tf":1.0},"5":{"tf":1.0},"8":{"tf":1.0}}}}},"df":0,"docs":{}},"i":{"df":0,"docs":{},"s":{"df":0,"docs":{},"t":{"df":1,"docs":{"35":{"tf":1.0}}}},"t":{"df":2,"docs":{"1":{"tf":1.0},"33":{"tf":1.0}}}},"p":{"df":0,"docs":{},"e":{"c":{"df":0,"docs":{},"t":{"(":{"\"":{"c":{"df":0,"docs":{},"o":{"df":0,"docs":{},"n":{"df":0,"docs":{},"v":{"df":0,"docs":{},"e":{"df":0,"docs":{},"r":{"df":0,"docs":{},"t":{"_":{"d":{"df":0,"docs":{},"e":{"df":0,"docs":{},"v":{"df":0,"docs":{},"i":{"c":{"df":0,"docs":{},"e":{"_":{"df":0,"docs":{},"p":{"a":{"df":0,"docs":{},"t":{"df":0,"docs":{},"h":{"_":{"df":0,"docs":{},"t":{"df":0,"docs":{},"o":{"_":{"df":0,"docs":{},"t":{"df":0,"docs":{},"e":{"df":0,"docs":{},"x":{"df":0,"docs":{},"t":{"df":2,"docs":{"20":{"tf":1.0},"21":{"tf":1.0}}}}}}},"df":0,"docs":{}}}},"df":0,"docs":{}}}},"df":0,"docs":{}}},"df":0,"docs":{}}},"df":0,"docs":{}}}}},"df":0,"docs":{}},"df":0,"docs":{}}}}}}}},"d":{"df":0,"docs":{},"e":{"df":0,"docs":{},"v":{"df":0,"docs":{},"i":{"c":{"df":0,"docs":{},"e":{"df":0,"docs":{},"p":{"a":{"df":0,"docs":{},"t":{"df":0,"docs":{},"h":{"df":0,"docs":{},"t":{"df":0,"docs":{},"o":{"df":0,"docs":{},"t":{"df":0,"docs":{},"e":{"df":0,"docs":{},"x":{"df":0,"docs":{},"t":{"df":2,"docs":{"20":{"tf":1.0},"21":{"tf":1.0}}}}}}}}}}},"df":0,"docs":{}}}},"df":0,"docs":{}}}}},"df":0,"docs":{}},"df":0,"docs":{}},"df":0,"docs":{}}},"df":0,"docs":{}},"o":{"df":0,"docs":{},"r":{"df":0,"docs":{},"t":{"df":1,"docs":{"5":{"tf":1.0}}}}}},"t":{"df":0,"docs":{},"e":{"df":0,"docs":{},"n":{"df":0,"docs":{},"s":{"df":2,"docs":{"26":{"tf":1.0},"28":{"tf":1.0}}}},"r":{"df":0,"docs":{},"n":{"df":1,"docs":{"22":{"tf":1.0}}}}}}}},"f":{"1":{"2":{"df":1,"docs":{"17":{"tf":1.0}}},"df":0,"docs":{}},"3":{"2":{"df":1,"docs":{"22":{"tf":3.1622776601683795}}},"df":0,"docs":{}},"8":{"1":{"df":0,"docs":{},"f":{"df":3,"docs":{"15":{"tf":1.0},"16":{"tf":1.0},"35":{"tf":1.0}}}},"df":0,"docs":{}},"9":{"df":1,"docs":{"17":{"tf":1.0}}},"a":{"df":0,"docs":{},"i":{"df":0,"docs":{},"l":{"df":3,"docs":{"20":{"tf":1.0},"21":{"tf":1.0},"22":{"tf":1.0}}},"r":{"df":0,"docs":{},"l":{"df":0,"docs":{},"i":{"df":2,"docs":{"26":{"tf":1.0},"32":{"tf":1.0}}}}}},"t":{"df":3,"docs":{"15":{"tf":2.0},"16":{"tf":1.0},"35":{"tf":1.0}}}},"df":0,"docs":{},"e":{"d":{"4":{"df":1,"docs":{"27":{"tf":1.0}}},"df":0,"docs":{},"o":{"df":0,"docs":{},"r":{"a":{"df":2,"docs":{"10":{"tf":1.0},"11":{"tf":1.0}}},"df":0,"docs":{}}}},"df":0,"docs":{},"w":{"df":3,"docs":{"13":{"tf":1.0},"26":{"tf":1.0},"4":{"tf":1.0}}}},"i":{"df":0,"docs":{},"e":{"df":0,"docs":{},"l":{"d":{"df":1,"docs":{"27":{"tf":1.0}}},"df":0,"docs":{}}},"g":{"df":0,"docs":{},"u":{"df":0,"docs":{},"r":{"df":1,"docs":{"33":{"tf":1.0}}}}},"l":{"df":0,"docs":{},"e":{"df":6,"docs":{"11":{"tf":2.6457513110645907},"15":{"tf":2.0},"20":{"tf":1.0},"31":{"tf":1.4142135623730951},"35":{"tf":2.449489742783178},"7":{"tf":1.0}}}},"n":{"a":{"df":0,"docs":{},"l":{"df":1,"docs":{"5":{"tf":1.0}}}},"d":{"df":2,"docs":{"19":{"tf":1.0},"21":{"tf":1.4142135623730951}}},"df":0,"docs":{}},"r":{"df":0,"docs":{},"m":{"df":0,"docs":{},"w":{"a":{"df":0,"docs":{},"r":{"df":2,"docs":{"10":{"tf":1.0},"11":{"tf":1.4142135623730951}}}},"df":0,"docs":{}}},"s":{"df":0,"docs":{},"t":{"df":5,"docs":{"19":{"tf":1.0},"20":{"tf":1.4142135623730951},"21":{"tf":1.7320508075688772},"27":{"tf":1.0},"5":{"tf":1.0}}}}}},"l":{"a":{"df":0,"docs":{},"g":{"df":2,"docs":{"23":{"tf":1.0},"33":{"tf":1.0}}}},"df":0,"docs":{},"e":{"df":0,"docs":{},"x":{"df":0,"docs":{},"i":{"b":{"df":0,"docs":{},"l":{"df":2,"docs":{"31":{"tf":1.0},"32":{"tf":1.0}}}},"df":0,"docs":{}}}}},"n":{"df":6,"docs":{"20":{"tf":1.4142135623730951},"21":{"tf":1.0},"22":{"tf":3.1622776601683795},"26":{"tf":1.0},"4":{"tf":1.0},"5":{"tf":1.0}}},"o":{"c":{"df":0,"docs":{},"u":{"df":1,"docs":{"0":{"tf":1.0}}}},"df":0,"docs":{},"l":{"df":0,"docs":{},"l":{"df":0,"docs":{},"o":{"df":0,"docs":{},"w":{"df":3,"docs":{"22":{"tf":1.0},"3":{"tf":1.0},"34":{"tf":1.0}}}}}},"r":{"df":0,"docs":{},"e":{"df":0,"docs":{},"v":{"df":1,"docs":{"22":{"tf":1.0}}}},"m":{"a":{"df":0,"docs":{},"t":{"=":{"df":0,"docs":{},"r":{"a":{"df":0,"docs":{},"w":{",":{"df":0,"docs":{},"f":{"df":0,"docs":{},"i":{"df":0,"docs":{},"l":{"df":0,"docs":{},"e":{"=":{"df":0,"docs":{},"f":{"a":{"df":0,"docs":{},"t":{":":{"df":0,"docs":{},"r":{"df":0,"docs":{},"w":{":":{"df":0,"docs":{},"e":{"df":0,"docs":{},"s":{"df":0,"docs":{},"p":{"df":1,"docs":{"13":{"tf":1.0}}}}}},"df":0,"docs":{}}}},"df":0,"docs":{}}},"df":0,"docs":{}}},"df":0,"docs":{}}}}}},"df":0,"docs":{}}},"df":0,"docs":{}}},"df":3,"docs":{"15":{"tf":1.0},"16":{"tf":1.0},"27":{"tf":1.4142135623730951}}}},"df":0,"docs":{}}}},"r":{"a":{"c":{"df":0,"docs":{},"t":{"a":{"df":0,"docs":{},"l":{"df":1,"docs":{"22":{"tf":1.0}}}},"df":0,"docs":{}}},"df":0,"docs":{},"m":{"df":0,"docs":{},"e":{"b":{"df":0,"docs":{},"u":{"df":0,"docs":{},"f":{"df":0,"docs":{},"f":{"df":1,"docs":{"22":{"tf":1.4142135623730951}}}}}},"df":1,"docs":{"22":{"tf":1.0}}}}},"df":0,"docs":{}},"u":{"df":0,"docs":{},"l":{"df":0,"docs":{},"l":{"df":2,"docs":{"22":{"tf":1.0},"33":{"tf":1.0}}}},"n":{"c":{"df":0,"docs":{},"t":{"df":0,"docs":{},"i":{"df":0,"docs":{},"o":{"df":0,"docs":{},"n":{"df":4,"docs":{"21":{"tf":1.4142135623730951},"25":{"tf":1.0},"30":{"tf":1.4142135623730951},"5":{"tf":2.0}}}}}}},"df":0,"docs":{}}}},"g":{"a":{"df":0,"docs":{},"m":{"df":0,"docs":{},"e":{"df":1,"docs":{"22":{"tf":1.0}}}},"r":{"b":{"a":{"df":0,"docs":{},"g":{"df":1,"docs":{"33":{"tf":1.0}}}},"df":0,"docs":{}},"df":0,"docs":{},"r":{"df":0,"docs":{},"e":{"df":0,"docs":{},"t":{"'":{"df":1,"docs":{"33":{"tf":1.0}}},"df":0,"docs":{}}}}}},"df":1,"docs":{"22":{"tf":1.4142135623730951}},"e":{"df":0,"docs":{},"n":{"df":0,"docs":{},"e":{"df":0,"docs":{},"r":{"df":3,"docs":{"0":{"tf":1.0},"15":{"tf":1.0},"22":{"tf":1.0}}}}},"t":{"_":{"df":0,"docs":{},"r":{"a":{"df":0,"docs":{},"n":{"d":{"df":0,"docs":{},"o":{"df":0,"docs":{},"m":{"_":{"df":0,"docs":{},"u":{"df":0,"docs":{},"s":{"df":0,"docs":{},"i":{"df":0,"docs":{},"z":{"df":0,"docs":{},"e":{"(":{"df":0,"docs":{},"r":{"df":0,"docs":{},"n":{"df":0,"docs":{},"g":{"df":1,"docs":{"22":{"tf":1.0}}}}}},"df":0,"docs":{}}}}}}},"df":0,"docs":{}}}},"df":0,"docs":{}}},"df":0,"docs":{}}},"df":1,"docs":{"34":{"tf":1.0}}}},"i":{"df":0,"docs":{},"v":{"df":0,"docs":{},"e":{"df":1,"docs":{"21":{"tf":1.0}}}}},"l":{"df":0,"docs":{},"o":{"b":{"a":{"df":0,"docs":{},"l":{"df":1,"docs":{"27":{"tf":1.0}}}},"df":1,"docs":{"5":{"tf":1.0}}},"df":0,"docs":{}}},"o":{"df":0,"docs":{},"e":{"df":1,"docs":{"25":{"tf":1.0}}},"p":{".":{"b":{"df":0,"docs":{},"l":{"df":0,"docs":{},"t":{"(":{"b":{"df":0,"docs":{},"l":{"df":0,"docs":{},"t":{"df":0,"docs":{},"o":{"df":0,"docs":{},"p":{":":{":":{"b":{"df":0,"docs":{},"u":{"df":0,"docs":{},"f":{"df":0,"docs":{},"f":{"df":0,"docs":{},"e":{"df":0,"docs":{},"r":{"df":0,"docs":{},"t":{"df":0,"docs":{},"o":{"df":0,"docs":{},"v":{"df":0,"docs":{},"i":{"d":{"df":0,"docs":{},"e":{"df":0,"docs":{},"o":{"df":1,"docs":{"22":{"tf":1.4142135623730951}}}}},"df":0,"docs":{}}}}}}}}}}},"df":0,"docs":{}},"df":0,"docs":{}},"df":0,"docs":{}}}}}},"df":0,"docs":{}},"df":0,"docs":{}}}},"c":{"df":0,"docs":{},"u":{"df":0,"docs":{},"r":{"df":0,"docs":{},"r":{"df":0,"docs":{},"e":{"df":0,"docs":{},"n":{"df":0,"docs":{},"t":{"_":{"df":0,"docs":{},"m":{"df":0,"docs":{},"o":{"d":{"df":0,"docs":{},"e":{"_":{"df":0,"docs":{},"i":{"df":0,"docs":{},"n":{"df":0,"docs":{},"f":{"df":0,"docs":{},"o":{"(":{")":{".":{"df":0,"docs":{},"r":{"df":0,"docs":{},"e":{"df":0,"docs":{},"s":{"df":0,"docs":{},"o":{"df":0,"docs":{},"l":{"df":0,"docs":{},"u":{"df":0,"docs":{},"t":{"df":1,"docs":{"22":{"tf":1.0}}}}}}}}}},"df":0,"docs":{}},"df":0,"docs":{}},"df":0,"docs":{}}}}}},"df":0,"docs":{}}},"df":0,"docs":{}}}},"df":0,"docs":{}}}}}}}},"df":0,"docs":{}},"_":{"df":0,"docs":{},"h":{"a":{"df":0,"docs":{},"n":{"d":{"df":0,"docs":{},"l":{"df":1,"docs":{"22":{"tf":1.0}}}},"df":0,"docs":{}}},"df":0,"docs":{}}},"df":1,"docs":{"22":{"tf":2.0}}}},"p":{"df":0,"docs":{},"t":{"df":3,"docs":{"15":{"tf":1.4142135623730951},"16":{"tf":1.0},"34":{"tf":2.0}}}},"r":{"a":{"d":{"df":0,"docs":{},"i":{"df":0,"docs":{},"e":{"df":0,"docs":{},"n":{"df":0,"docs":{},"t":{"df":1,"docs":{"22":{"tf":1.0}}}}}}},"df":0,"docs":{},"p":{"df":0,"docs":{},"h":{"df":0,"docs":{},"i":{"c":{"df":1,"docs":{"22":{"tf":2.23606797749979}},"s":{"df":0,"docs":{},"o":{"df":0,"docs":{},"u":{"df":0,"docs":{},"t":{"df":0,"docs":{},"p":{"df":0,"docs":{},"u":{"df":0,"docs":{},"t":{"df":1,"docs":{"22":{"tf":1.7320508075688772}}}}}}}}}},"df":0,"docs":{}}}}},"df":0,"docs":{},"e":{"df":0,"docs":{},"e":{"df":0,"docs":{},"n":{"df":1,"docs":{"22":{"tf":1.0}}}}},"o":{"df":0,"docs":{},"u":{"df":0,"docs":{},"p":{"df":1,"docs":{"27":{"tf":1.0}}}}}},"u":{"df":0,"docs":{},"i":{"d":{"df":5,"docs":{"15":{"tf":1.7320508075688772},"18":{"tf":1.0},"27":{"tf":3.0},"32":{"tf":1.4142135623730951},"34":{"tf":1.7320508075688772}}},"df":0,"docs":{}}}},"h":{"a":{"df":0,"docs":{},"l":{"df":0,"docs":{},"f":{"df":0,"docs":{},"w":{"a":{"df":0,"docs":{},"y":{"df":1,"docs":{"22":{"tf":1.0}}}},"df":0,"docs":{}}}},"n":{"d":{"df":0,"docs":{},"l":{"df":10,"docs":{"19":{"tf":3.1622776601683795},"20":{"tf":1.0},"21":{"tf":2.449489742783178},"22":{"tf":1.0},"26":{"tf":1.0},"28":{"tf":1.4142135623730951},"29":{"tf":2.0},"31":{"tf":1.4142135623730951},"4":{"tf":1.0},"5":{"tf":1.7320508075688772}},"e":{"df":0,"docs":{},"r":{"df":1,"docs":{"5":{"tf":1.0}}}}}},"df":0,"docs":{}},"p":{"df":0,"docs":{},"p":{"df":0,"docs":{},"e":{"df":0,"docs":{},"n":{"df":1,"docs":{"32":{"tf":1.0}}}}}},"r":{"d":{"df":0,"docs":{},"w":{"a":{"df":0,"docs":{},"r":{"df":2,"docs":{"14":{"tf":1.4142135623730951},"28":{"tf":1.0}}}},"df":0,"docs":{}}},"df":0,"docs":{}}},"df":0,"docs":{},"e":{"a":{"d":{"df":0,"docs":{},"e":{"df":0,"docs":{},"r":{"df":1,"docs":{"34":{"tf":1.4142135623730951}}}}},"df":0,"docs":{}},"df":0,"docs":{},"i":{"df":0,"docs":{},"g":{"df":0,"docs":{},"h":{"df":0,"docs":{},"t":{"df":1,"docs":{"22":{"tf":3.4641016151377544}}}}}},"l":{"df":0,"docs":{},"l":{"df":0,"docs":{},"o":{"df":4,"docs":{"1":{"tf":1.0},"13":{"tf":1.0},"21":{"tf":1.0},"5":{"tf":1.0}}}}},"r":{"df":0,"docs":{},"e":{"'":{"df":2,"docs":{"20":{"tf":1.0},"22":{"tf":1.0}}},"df":4,"docs":{"21":{"tf":1.0},"22":{"tf":1.0},"5":{"tf":1.4142135623730951},"7":{"tf":1.0}}}}},"o":{"df":0,"docs":{},"l":{"d":{"df":1,"docs":{"17":{"tf":1.0}}},"df":0,"docs":{}}},"p":{"df":1,"docs":{"17":{"tf":1.0}}},"u":{"df":0,"docs":{},"g":{"df":0,"docs":{},"e":{"df":1,"docs":{"24":{"tf":1.0}}}},"m":{"a":{"df":0,"docs":{},"n":{"df":1,"docs":{"31":{"tf":1.0}}}},"df":0,"docs":{}}}},"i":{"6":{"8":{"6":{"df":1,"docs":{"7":{"tf":1.0}}},"df":0,"docs":{}},"df":0,"docs":{}},"d":{"df":0,"docs":{},"e":{"df":0,"docs":{},"n":{"df":0,"docs":{},"t":{"df":0,"docs":{},"i":{"df":0,"docs":{},"f":{"df":0,"docs":{},"i":{"df":5,"docs":{"27":{"tf":1.7320508075688772},"31":{"tf":1.0},"32":{"tf":1.0},"34":{"tf":1.0},"35":{"tf":1.0}}}}}}}}},"df":0,"docs":{},"f":{"=":{"df":0,"docs":{},"p":{"df":0,"docs":{},"f":{"df":0,"docs":{},"l":{"a":{"df":0,"docs":{},"s":{"df":0,"docs":{},"h":{",":{"df":0,"docs":{},"f":{"df":0,"docs":{},"o":{"df":0,"docs":{},"r":{"df":0,"docs":{},"m":{"a":{"df":0,"docs":{},"t":{"=":{"df":0,"docs":{},"r":{"a":{"df":0,"docs":{},"w":{",":{"df":0,"docs":{},"r":{"df":0,"docs":{},"e":{"a":{"d":{"df":0,"docs":{},"o":{"df":0,"docs":{},"n":{"df":0,"docs":{},"l":{"df":0,"docs":{},"y":{"=":{"df":0,"docs":{},"o":{"df":0,"docs":{},"n":{",":{"df":0,"docs":{},"f":{"df":0,"docs":{},"i":{"df":0,"docs":{},"l":{"df":0,"docs":{},"e":{"=":{"df":0,"docs":{},"o":{"df":0,"docs":{},"v":{"df":0,"docs":{},"m":{"df":0,"docs":{},"f":{"_":{"c":{"df":0,"docs":{},"o":{"d":{"df":0,"docs":{},"e":{".":{"df":0,"docs":{},"f":{"d":{"df":1,"docs":{"13":{"tf":1.0}}},"df":0,"docs":{}}},"df":0,"docs":{}}},"df":0,"docs":{}}},"df":0,"docs":{},"v":{"a":{"df":0,"docs":{},"r":{"df":0,"docs":{},"s":{".":{"df":0,"docs":{},"f":{"d":{"df":1,"docs":{"13":{"tf":1.0}}},"df":0,"docs":{}}},"df":0,"docs":{}}}},"df":0,"docs":{}}},"df":0,"docs":{}}}}}},"df":0,"docs":{}}}}}},"df":0,"docs":{}}}},"df":0,"docs":{}}}}}},"df":0,"docs":{}},"df":0,"docs":{}}}},"df":0,"docs":{}}},"df":0,"docs":{}}},"df":0,"docs":{}}},"df":0,"docs":{}}}}}},"df":0,"docs":{}}}},"df":0,"docs":{}}}}},"df":0,"docs":{}},"m":{"a":{"df":0,"docs":{},"g":{"df":4,"docs":{"20":{"tf":1.0},"21":{"tf":1.0},"23":{"tf":1.0},"5":{"tf":1.4142135623730951}},"e":{"_":{"d":{"df":0,"docs":{},"e":{"df":0,"docs":{},"v":{"df":0,"docs":{},"i":{"c":{"df":0,"docs":{},"e":{"_":{"df":0,"docs":{},"p":{"a":{"df":0,"docs":{},"t":{"df":0,"docs":{},"h":{"_":{"df":0,"docs":{},"t":{"df":0,"docs":{},"e":{"df":0,"docs":{},"x":{"df":0,"docs":{},"t":{"df":2,"docs":{"20":{"tf":1.4142135623730951},"21":{"tf":1.4142135623730951}}}}}}},"df":2,"docs":{"20":{"tf":1.4142135623730951},"21":{"tf":1.4142135623730951}}}}},"df":0,"docs":{}}},"df":0,"docs":{}}},"df":0,"docs":{}}}}},"df":0,"docs":{},"h":{"a":{"df":0,"docs":{},"n":{"d":{"df":0,"docs":{},"l":{"df":1,"docs":{"21":{"tf":1.0}}}},"df":0,"docs":{}}},"df":0,"docs":{}}},"df":0,"docs":{}}}},"df":0,"docs":{},"i":{"df":0,"docs":{},"t":{"df":1,"docs":{"12":{"tf":1.0}}}},"p":{"df":0,"docs":{},"l":{"df":1,"docs":{"22":{"tf":1.7320508075688772}},"e":{"df":0,"docs":{},"m":{"df":0,"docs":{},"e":{"df":0,"docs":{},"n":{"df":0,"docs":{},"t":{"df":5,"docs":{"10":{"tf":1.0},"15":{"tf":1.7320508075688772},"22":{"tf":1.0},"33":{"tf":1.4142135623730951},"34":{"tf":1.4142135623730951}}}}}}}},"o":{"df":0,"docs":{},"r":{"df":0,"docs":{},"t":{"df":5,"docs":{"24":{"tf":1.0},"27":{"tf":1.0},"33":{"tf":1.0},"35":{"tf":1.0},"5":{"tf":1.0}}}}}}},"n":{"c":{"df":0,"docs":{},"l":{"df":0,"docs":{},"u":{"d":{"df":4,"docs":{"11":{"tf":1.0},"26":{"tf":1.0},"31":{"tf":1.0},"34":{"tf":1.0}}},"df":0,"docs":{}}}},"d":{"df":0,"docs":{},"i":{"c":{"df":2,"docs":{"34":{"tf":1.0},"5":{"tf":1.0}}},"df":0,"docs":{},"v":{"df":0,"docs":{},"i":{"d":{"df":0,"docs":{},"u":{"df":3,"docs":{"21":{"tf":1.0},"30":{"tf":1.0},"34":{"tf":1.0}}}},"df":0,"docs":{}}}}},"df":0,"docs":{},"f":{"df":0,"docs":{},"o":{"!":{"(":{"\"":{"df":0,"docs":{},"h":{"df":0,"docs":{},"e":{"df":0,"docs":{},"l":{"df":0,"docs":{},"l":{"df":0,"docs":{},"o":{"df":2,"docs":{"4":{"tf":1.0},"5":{"tf":1.0}}}}}}},"i":{"df":0,"docs":{},"m":{"a":{"df":0,"docs":{},"g":{"df":2,"docs":{"20":{"tf":1.0},"21":{"tf":1.0}}}},"df":0,"docs":{}}}},"df":0,"docs":{}},"df":0,"docs":{}},"df":2,"docs":{"13":{"tf":1.0},"20":{"tf":1.0}},"r":{"df":0,"docs":{},"m":{"df":3,"docs":{"20":{"tf":1.0},"24":{"tf":1.0},"31":{"tf":1.0}}}}}},"h":{"df":0,"docs":{},"e":{"df":0,"docs":{},"r":{"df":1,"docs":{"30":{"tf":1.0}}}}},"i":{"df":0,"docs":{},"t":{"df":0,"docs":{},"i":{"df":3,"docs":{"22":{"tf":1.0},"25":{"tf":1.4142135623730951},"5":{"tf":1.4142135623730951}}}}},"s":{"df":0,"docs":{},"e":{"df":0,"docs":{},"n":{"df":0,"docs":{},"s":{"df":0,"docs":{},"i":{"df":0,"docs":{},"t":{"df":1,"docs":{"15":{"tf":1.0}}}}}},"r":{"df":0,"docs":{},"t":{"df":1,"docs":{"17":{"tf":1.0}}}}},"i":{"d":{"df":1,"docs":{"5":{"tf":1.0}}},"df":0,"docs":{}},"t":{"a":{"df":0,"docs":{},"l":{"df":4,"docs":{"10":{"tf":2.0},"11":{"tf":1.0},"3":{"tf":1.4142135623730951},"7":{"tf":1.0}}}},"df":0,"docs":{},"r":{"df":0,"docs":{},"u":{"c":{"df":0,"docs":{},"t":{"df":1,"docs":{"3":{"tf":1.0}}}},"df":0,"docs":{}}}}},"t":{"df":0,"docs":{},"e":{"df":0,"docs":{},"l":{"df":1,"docs":{"35":{"tf":1.0}}},"n":{"d":{"df":1,"docs":{"5":{"tf":1.0}}},"df":0,"docs":{}},"r":{"a":{"c":{"df":0,"docs":{},"t":{"df":1,"docs":{"30":{"tf":1.4142135623730951}}}},"df":0,"docs":{}},"df":0,"docs":{},"f":{"a":{"c":{"df":3,"docs":{"26":{"tf":1.0},"28":{"tf":1.0},"30":{"tf":1.0}}},"df":0,"docs":{}},"df":0,"docs":{}}}},"r":{"df":0,"docs":{},"o":{"d":{"df":0,"docs":{},"u":{"c":{"df":0,"docs":{},"t":{"df":1,"docs":{"0":{"tf":1.0}}}},"df":0,"docs":{}}},"df":0,"docs":{}}}}},"o":{"df":1,"docs":{"30":{"tf":1.0}}},"s":{"df":0,"docs":{},"n":{"'":{"df":0,"docs":{},"t":{"df":1,"docs":{"21":{"tf":1.0}}}},"df":0,"docs":{}}},"t":{"'":{"df":1,"docs":{"34":{"tf":1.4142135623730951}}},"a":{"df":0,"docs":{},"n":{"df":0,"docs":{},"i":{"df":0,"docs":{},"u":{"df":0,"docs":{},"m":{"df":1,"docs":{"35":{"tf":1.0}}}}}}},"df":0,"docs":{},"s":{"df":0,"docs":{},"e":{"df":0,"docs":{},"l":{"df":0,"docs":{},"f":{"df":1,"docs":{"10":{"tf":1.0}}}}}}}},"k":{"df":0,"docs":{},"e":{"df":0,"docs":{},"y":{"/":{"df":0,"docs":{},"v":{"a":{"df":0,"docs":{},"l":{"df":0,"docs":{},"u":{"df":1,"docs":{"32":{"tf":1.0}}}}},"df":0,"docs":{}}},"df":2,"docs":{"17":{"tf":1.7320508075688772},"32":{"tf":1.0}}}},"i":{"df":0,"docs":{},"n":{"d":{"df":1,"docs":{"31":{"tf":1.0}}},"df":0,"docs":{}}},"v":{"df":0,"docs":{},"m":{"df":2,"docs":{"10":{"tf":1.0},"13":{"tf":1.0}}}}},"l":{"a":{"df":0,"docs":{},"r":{"df":0,"docs":{},"g":{"df":2,"docs":{"30":{"tf":1.0},"34":{"tf":1.4142135623730951}}}},"u":{"df":0,"docs":{},"n":{"c":{"df":0,"docs":{},"h":{"df":2,"docs":{"13":{"tf":1.4142135623730951},"20":{"tf":1.0}}}},"df":0,"docs":{}}}},"df":0,"docs":{},"e":{"a":{"df":0,"docs":{},"r":{"df":0,"docs":{},"n":{"df":1,"docs":{"30":{"tf":1.0}}}}},"df":0,"docs":{},"n":{"df":0,"docs":{},"g":{"df":0,"docs":{},"t":{"df":0,"docs":{},"h":{"df":1,"docs":{"31":{"tf":1.0}}}}}},"s":{"df":0,"docs":{},"s":{"df":2,"docs":{"21":{"tf":1.0},"29":{"tf":1.0}}}},"t":{"'":{"df":2,"docs":{"21":{"tf":1.0},"5":{"tf":1.0}}},"df":0,"docs":{}},"v":{"df":0,"docs":{},"e":{"df":0,"docs":{},"l":{"df":1,"docs":{"26":{"tf":1.0}}}}}},"i":{"b":{"df":0,"docs":{},"r":{"a":{"df":0,"docs":{},"r":{"df":0,"docs":{},"i":{"df":1,"docs":{"5":{"tf":1.0}}}}},"df":0,"docs":{}}},"df":0,"docs":{},"m":{"df":0,"docs":{},"i":{"df":0,"docs":{},"t":{"df":3,"docs":{"25":{"tf":1.0},"26":{"tf":1.0},"33":{"tf":1.0}}}}},"n":{"df":0,"docs":{},"e":{"a":{"df":0,"docs":{},"r":{"df":1,"docs":{"22":{"tf":1.0}}}},"df":1,"docs":{"5":{"tf":1.4142135623730951}}},"k":{"df":2,"docs":{"23":{"tf":1.0},"24":{"tf":1.0}},"e":{"df":0,"docs":{},"r":{"df":1,"docs":{"23":{"tf":1.0}}}}},"u":{"df":0,"docs":{},"x":{"df":2,"docs":{"16":{"tf":1.0},"25":{"tf":1.0}}}}},"t":{"df":0,"docs":{},"t":{"df":0,"docs":{},"l":{"df":2,"docs":{"27":{"tf":1.0},"5":{"tf":1.0}}}}}},"o":{"a":{"d":{"df":3,"docs":{"25":{"tf":1.4142135623730951},"26":{"tf":1.0},"29":{"tf":1.0}},"e":{"d":{"_":{"df":0,"docs":{},"i":{"df":0,"docs":{},"m":{"a":{"df":0,"docs":{},"g":{"df":2,"docs":{"20":{"tf":1.0},"21":{"tf":1.0}},"e":{".":{"df":0,"docs":{},"f":{"df":0,"docs":{},"i":{"df":0,"docs":{},"l":{"df":0,"docs":{},"e":{"_":{"df":0,"docs":{},"p":{"a":{"df":0,"docs":{},"t":{"df":0,"docs":{},"h":{"(":{")":{".":{"df":0,"docs":{},"e":{"df":0,"docs":{},"x":{"df":0,"docs":{},"p":{"df":0,"docs":{},"e":{"c":{"df":0,"docs":{},"t":{"(":{"\"":{"df":0,"docs":{},"f":{"df":0,"docs":{},"i":{"df":0,"docs":{},"l":{"df":2,"docs":{"20":{"tf":1.0},"21":{"tf":1.0}}}}}},"df":0,"docs":{}},"df":0,"docs":{}}},"df":0,"docs":{}}}}}},"df":0,"docs":{}},"df":0,"docs":{}},"df":0,"docs":{}}}},"df":0,"docs":{}}},"df":0,"docs":{}}}}}},"df":0,"docs":{}}}},"df":0,"docs":{}}}},"df":0,"docs":{},"i":{"df":0,"docs":{},"m":{"a":{"df":0,"docs":{},"g":{"df":2,"docs":{"20":{"tf":1.0},"21":{"tf":1.4142135623730951}}}},"df":0,"docs":{}}}},"df":0,"docs":{}}},"df":0,"docs":{}},"c":{"a":{"df":0,"docs":{},"t":{"df":1,"docs":{"11":{"tf":1.0}},"e":{"_":{"df":0,"docs":{},"h":{"a":{"df":0,"docs":{},"n":{"d":{"df":0,"docs":{},"l":{"df":0,"docs":{},"e":{"_":{"b":{"df":0,"docs":{},"u":{"df":0,"docs":{},"f":{"df":0,"docs":{},"f":{"df":2,"docs":{"19":{"tf":1.0},"21":{"tf":1.0}},"e":{"df":0,"docs":{},"r":{"(":{"df":0,"docs":{},"s":{"df":0,"docs":{},"e":{"a":{"df":0,"docs":{},"r":{"c":{"df":0,"docs":{},"h":{"df":0,"docs":{},"t":{"df":0,"docs":{},"y":{"df":0,"docs":{},"p":{"df":0,"docs":{},"e":{":":{":":{"b":{"df":0,"docs":{},"y":{"df":0,"docs":{},"p":{"df":0,"docs":{},"r":{"df":0,"docs":{},"o":{"df":0,"docs":{},"t":{"df":0,"docs":{},"o":{"c":{"df":0,"docs":{},"o":{"df":0,"docs":{},"l":{"(":{"&":{"d":{"df":0,"docs":{},"e":{"df":0,"docs":{},"v":{"df":0,"docs":{},"i":{"c":{"df":0,"docs":{},"e":{"df":0,"docs":{},"p":{"a":{"df":0,"docs":{},"t":{"df":0,"docs":{},"h":{"df":0,"docs":{},"t":{"df":0,"docs":{},"o":{"df":0,"docs":{},"t":{"df":0,"docs":{},"e":{"df":0,"docs":{},"x":{"df":0,"docs":{},"t":{":":{":":{"df":0,"docs":{},"g":{"df":0,"docs":{},"u":{"df":0,"docs":{},"i":{"d":{"df":2,"docs":{"20":{"tf":1.0},"21":{"tf":1.0}}},"df":0,"docs":{}}}}},"df":0,"docs":{}},"df":0,"docs":{}}}}}}}}}},"df":0,"docs":{}}}},"df":0,"docs":{}}}}},"df":0,"docs":{}},"df":0,"docs":{}},"df":0,"docs":{}}}},"df":0,"docs":{}}}}}}}},"df":0,"docs":{}},"df":0,"docs":{}},"df":0,"docs":{}}}}}}},"df":0,"docs":{}}},"df":0,"docs":{}}}},"df":0,"docs":{}}}}}}},"df":0,"docs":{}},"df":0,"docs":{}}}},"df":0,"docs":{}}},"df":0,"docs":{}}},"df":0,"docs":{}}}},"df":0,"docs":{}},"df":0,"docs":{},"g":{":":{":":{"df":0,"docs":{},"i":{"df":0,"docs":{},"n":{"df":0,"docs":{},"f":{"df":0,"docs":{},"o":{"df":3,"docs":{"20":{"tf":1.0},"4":{"tf":1.0},"5":{"tf":1.0}}}}}}},"df":0,"docs":{}},"df":4,"docs":{"13":{"tf":1.0},"21":{"tf":1.0},"4":{"tf":1.0},"5":{"tf":1.0}},"g":{"df":0,"docs":{},"e":{"df":0,"docs":{},"r":{"df":1,"docs":{"5":{"tf":1.0}}}}}},"n":{"df":0,"docs":{},"g":{"df":0,"docs":{},"e":{"df":0,"docs":{},"r":{"df":1,"docs":{"25":{"tf":1.0}}}}}},"o":{"df":0,"docs":{},"k":{"df":6,"docs":{"15":{"tf":1.0},"20":{"tf":1.0},"21":{"tf":1.7320508075688772},"27":{"tf":1.0},"31":{"tf":1.0},"5":{"tf":1.7320508075688772}}},"p":{"df":1,"docs":{"22":{"tf":1.4142135623730951}}}}}},"m":{"a":{"c":{"df":1,"docs":{"17":{"tf":1.0}},"h":{"df":0,"docs":{},"i":{"df":0,"docs":{},"n":{"df":3,"docs":{"10":{"tf":1.0},"17":{"tf":1.0},"33":{"tf":1.0}}}}},"r":{"df":0,"docs":{},"o":{"df":1,"docs":{"36":{"tf":1.0}}}}},"df":0,"docs":{},"i":{"df":0,"docs":{},"n":{"(":{"_":{"df":0,"docs":{},"h":{"a":{"df":0,"docs":{},"n":{"d":{"df":0,"docs":{},"l":{"df":1,"docs":{"22":{"tf":1.0}}}},"df":0,"docs":{}}},"df":0,"docs":{}},"i":{"df":0,"docs":{},"m":{"a":{"df":0,"docs":{},"g":{"df":0,"docs":{},"e":{"_":{"df":0,"docs":{},"h":{"a":{"df":0,"docs":{},"n":{"d":{"df":0,"docs":{},"l":{"df":2,"docs":{"4":{"tf":1.0},"5":{"tf":1.0}}}},"df":0,"docs":{}}},"df":0,"docs":{}}},"df":0,"docs":{}}}},"df":0,"docs":{}}}},"df":0,"docs":{},"h":{"a":{"df":0,"docs":{},"n":{"d":{"df":0,"docs":{},"l":{"df":1,"docs":{"26":{"tf":1.0}}}},"df":0,"docs":{}}},"df":0,"docs":{}},"i":{"df":0,"docs":{},"m":{"a":{"df":0,"docs":{},"g":{"df":0,"docs":{},"e":{"_":{"df":0,"docs":{},"h":{"a":{"df":0,"docs":{},"n":{"d":{"df":0,"docs":{},"l":{"df":1,"docs":{"20":{"tf":1.0}}}},"df":0,"docs":{}}},"df":0,"docs":{}}},"df":0,"docs":{}}}},"df":0,"docs":{}}}},"df":4,"docs":{"21":{"tf":1.4142135623730951},"25":{"tf":1.0},"26":{"tf":1.0},"5":{"tf":2.23606797749979}}}},"k":{"df":0,"docs":{},"e":{"df":2,"docs":{"28":{"tf":1.0},"5":{"tf":1.7320508075688772}}}},"n":{"df":0,"docs":{},"i":{"df":4,"docs":{"15":{"tf":1.0},"30":{"tf":1.4142135623730951},"31":{"tf":1.0},"5":{"tf":1.0}}}},"p":{"df":1,"docs":{"26":{"tf":1.0}}},"r":{"df":0,"docs":{},"k":{"df":1,"docs":{"15":{"tf":1.0}}}},"s":{"df":0,"docs":{},"t":{"df":0,"docs":{},"e":{"df":0,"docs":{},"r":{"df":1,"docs":{"34":{"tf":1.0}}}}}},"t":{"c":{"df":0,"docs":{},"h":{"df":1,"docs":{"34":{"tf":1.0}}}},"df":0,"docs":{},"t":{"df":0,"docs":{},"e":{"df":0,"docs":{},"r":{"df":1,"docs":{"15":{"tf":1.0}}}},"h":{"df":0,"docs":{},"e":{"df":0,"docs":{},"w":{"df":1,"docs":{"33":{"tf":1.0}}}}}}}},"b":{"df":0,"docs":{},"r":{"df":1,"docs":{"34":{"tf":1.7320508075688772}}}},"df":0,"docs":{},"e":{"a":{"df":0,"docs":{},"n":{"df":1,"docs":{"19":{"tf":1.0}}}},"c":{"df":0,"docs":{},"h":{"a":{"df":0,"docs":{},"n":{"df":1,"docs":{"28":{"tf":1.0}}}},"df":0,"docs":{}}},"df":0,"docs":{},"m":{":":{":":{"df":0,"docs":{},"s":{"df":0,"docs":{},"i":{"df":0,"docs":{},"z":{"df":0,"docs":{},"e":{"_":{"df":0,"docs":{},"o":{"df":0,"docs":{},"f":{":":{":":{"<":{"df":0,"docs":{},"u":{"df":0,"docs":{},"s":{"df":1,"docs":{"22":{"tf":1.0}}}}},"df":0,"docs":{}},"df":0,"docs":{}},"df":0,"docs":{}}}},"df":0,"docs":{}}}}}},"df":0,"docs":{}},"df":0,"docs":{},"o":{"df":0,"docs":{},"r":{"df":0,"docs":{},"i":{"df":3,"docs":{"26":{"tf":1.4142135623730951},"33":{"tf":1.7320508075688772},"5":{"tf":1.0}}}}}},"n":{"df":0,"docs":{},"u":{"df":1,"docs":{"17":{"tf":1.0}}}},"s":{"df":0,"docs":{},"s":{"a":{"df":0,"docs":{},"g":{"df":1,"docs":{"13":{"tf":1.0}}}},"df":0,"docs":{}}},"t":{"df":0,"docs":{},"h":{"df":0,"docs":{},"o":{"d":{"df":2,"docs":{"21":{"tf":1.4142135623730951},"22":{"tf":2.23606797749979}}},"df":0,"docs":{}}}}},"i":{"c":{"df":0,"docs":{},"e":{"df":1,"docs":{"31":{"tf":1.0}}}},"df":0,"docs":{},"n":{"df":0,"docs":{},"i":{"df":0,"docs":{},"m":{"df":1,"docs":{"4":{"tf":1.0}}}}},"s":{"df":0,"docs":{},"i":{"df":0,"docs":{},"n":{"df":0,"docs":{},"t":{"df":0,"docs":{},"e":{"df":0,"docs":{},"r":{"df":0,"docs":{},"p":{"df":0,"docs":{},"r":{"df":0,"docs":{},"e":{"df":0,"docs":{},"t":{"df":1,"docs":{"32":{"tf":1.0}}}}}}}}}}},"s":{"df":2,"docs":{"20":{"tf":1.0},"21":{"tf":1.0}}}}},"k":{"d":{"df":0,"docs":{},"i":{"df":0,"docs":{},"r":{"df":2,"docs":{"12":{"tf":1.0},"16":{"tf":1.4142135623730951}}}}},"df":0,"docs":{},"f":{"df":0,"docs":{},"s":{".":{"df":0,"docs":{},"f":{"a":{"df":0,"docs":{},"t":{"df":1,"docs":{"16":{"tf":1.0}}}},"df":0,"docs":{}}},"df":0,"docs":{}}}},"o":{"d":{"df":0,"docs":{},"e":{"df":2,"docs":{"19":{"tf":1.0},"25":{"tf":1.7320508075688772}},"r":{"df":0,"docs":{},"n":{"df":1,"docs":{"34":{"tf":1.0}}}}},"u":{"df":0,"docs":{},"l":{"df":2,"docs":{"31":{"tf":1.0},"5":{"tf":1.0}}}}},"df":0,"docs":{},"r":{"df":0,"docs":{},"e":{"df":8,"docs":{"21":{"tf":1.0},"22":{"tf":1.0},"24":{"tf":1.0},"25":{"tf":1.0},"27":{"tf":1.0},"31":{"tf":1.0},"33":{"tf":1.0},"34":{"tf":1.0}}}},"s":{"df":0,"docs":{},"t":{"df":0,"docs":{},"l":{"df":0,"docs":{},"i":{"df":1,"docs":{"25":{"tf":1.0}}}}}},"u":{"df":0,"docs":{},"n":{"df":0,"docs":{},"t":{"df":2,"docs":{"15":{"tf":1.0},"16":{"tf":1.4142135623730951}}}}},"v":{"df":0,"docs":{},"e":{"df":1,"docs":{"22":{"tf":1.0}}}}},"u":{"c":{"df":0,"docs":{},"h":{"df":6,"docs":{"21":{"tf":1.0},"24":{"tf":1.0},"25":{"tf":1.0},"27":{"tf":1.0},"33":{"tf":1.0},"5":{"tf":1.0}}}},"df":0,"docs":{},"l":{"df":0,"docs":{},"t":{"df":0,"docs":{},"i":{"df":0,"docs":{},"p":{"df":0,"docs":{},"l":{"df":1,"docs":{"11":{"tf":1.0}}}}}}},"t":{"df":5,"docs":{"20":{"tf":1.0},"22":{"tf":3.1622776601683795},"26":{"tf":1.0},"4":{"tf":1.0},"5":{"tf":1.0}}}}},"n":{"a":{"df":0,"docs":{},"m":{"df":0,"docs":{},"e":{"df":3,"docs":{"15":{"tf":1.4142135623730951},"32":{"tf":1.4142135623730951},"35":{"tf":1.7320508075688772}},"s":{"df":0,"docs":{},"p":{"a":{"c":{"df":1,"docs":{"32":{"tf":1.0}}},"df":0,"docs":{}},"df":0,"docs":{}}}}}},"df":0,"docs":{},"e":{"a":{"df":0,"docs":{},"r":{"df":1,"docs":{"34":{"tf":1.0}},"l":{"df":0,"docs":{},"i":{"df":1,"docs":{"24":{"tf":1.0}}}}}},"c":{"df":0,"docs":{},"e":{"df":0,"docs":{},"s":{"df":0,"docs":{},"s":{"a":{"df":0,"docs":{},"r":{"df":0,"docs":{},"i":{"df":1,"docs":{"15":{"tf":1.0}}}}},"df":0,"docs":{}}}}},"df":0,"docs":{},"e":{"d":{"df":5,"docs":{"10":{"tf":1.0},"14":{"tf":1.0},"21":{"tf":1.0},"5":{"tf":1.7320508075688772},"7":{"tf":1.0}}},"df":0,"docs":{}},"w":{"(":{"df":0,"docs":{},"w":{"df":0,"docs":{},"i":{"d":{"df":0,"docs":{},"t":{"df":0,"docs":{},"h":{"df":1,"docs":{"22":{"tf":1.4142135623730951}}}}},"df":0,"docs":{}}},"x":{"df":1,"docs":{"22":{"tf":1.0}}}},"=":{"1":{":":{"1":{"df":0,"docs":{},"m":{":":{"1":{"0":{"df":0,"docs":{},"m":{"df":1,"docs":{"16":{"tf":1.0}}}},"df":0,"docs":{}},"df":0,"docs":{}},"df":0,"docs":{}}},"df":0,"docs":{}},"df":0,"docs":{}},"df":0,"docs":{}},"df":3,"docs":{"22":{"tf":1.7320508075688772},"26":{"tf":1.0},"4":{"tf":1.0}}},"x":{"df":0,"docs":{},"t":{"df":2,"docs":{"21":{"tf":1.0},"5":{"tf":1.4142135623730951}}}}},"o":{"_":{"df":0,"docs":{},"m":{"a":{"df":0,"docs":{},"i":{"df":0,"docs":{},"n":{"df":4,"docs":{"20":{"tf":1.0},"22":{"tf":1.0},"4":{"tf":1.0},"5":{"tf":1.4142135623730951}}}}},"df":0,"docs":{}},"s":{"df":0,"docs":{},"t":{"d":{"df":4,"docs":{"20":{"tf":1.0},"22":{"tf":1.0},"4":{"tf":1.0},"5":{"tf":1.4142135623730951}}},"df":0,"docs":{}}}},"df":0,"docs":{},"n":{"_":{"df":0,"docs":{},"v":{"df":0,"docs":{},"o":{"df":0,"docs":{},"l":{"a":{"df":0,"docs":{},"t":{"df":0,"docs":{},"i":{"df":0,"docs":{},"l":{"df":1,"docs":{"33":{"tf":1.0}}}}}},"df":0,"docs":{}}}}},"df":2,"docs":{"33":{"tf":1.7320508075688772},"34":{"tf":1.0}}},"r":{"df":0,"docs":{},"m":{"a":{"df":0,"docs":{},"l":{"df":1,"docs":{"33":{"tf":1.0}}}},"df":0,"docs":{}}},"t":{"df":0,"docs":{},"e":{"df":2,"docs":{"15":{"tf":1.4142135623730951},"31":{"tf":1.0}}},"h":{"df":1,"docs":{"5":{"tf":1.0}}}},"w":{"df":4,"docs":{"12":{"tf":1.0},"13":{"tf":1.0},"21":{"tf":1.0},"5":{"tf":1.0}}}},"u":{"df":0,"docs":{},"l":{"df":0,"docs":{},"l":{"df":1,"docs":{"32":{"tf":1.0}}}},"m":{"b":{"df":0,"docs":{},"e":{"df":0,"docs":{},"r":{"df":4,"docs":{"22":{"tf":1.0},"30":{"tf":1.0},"34":{"tf":1.0},"5":{"tf":1.0}}}}},"df":0,"docs":{},"e":{"df":0,"docs":{},"r":{"df":1,"docs":{"5":{"tf":1.0}}}}}}},"o":{"b":{"df":0,"docs":{},"t":{"a":{"df":0,"docs":{},"i":{"df":0,"docs":{},"n":{"df":1,"docs":{"19":{"tf":1.0}}}}},"df":0,"docs":{}}},"df":0,"docs":{},"k":{"df":2,"docs":{"20":{"tf":1.0},"21":{"tf":1.0}}},"n":{"c":{"df":5,"docs":{"17":{"tf":1.0},"19":{"tf":1.0},"25":{"tf":1.0},"26":{"tf":1.0},"33":{"tf":1.0}}},"df":6,"docs":{"11":{"tf":1.4142135623730951},"17":{"tf":1.4142135623730951},"21":{"tf":1.4142135623730951},"22":{"tf":1.0},"26":{"tf":1.0},"30":{"tf":1.0}}},"p":{"a":{"df":0,"docs":{},"q":{"df":0,"docs":{},"u":{"df":3,"docs":{"27":{"tf":1.0},"29":{"tf":1.0},"31":{"tf":1.0}}}}},"df":0,"docs":{},"e":{"df":0,"docs":{},"n":{"_":{"df":0,"docs":{},"p":{"df":0,"docs":{},"r":{"df":0,"docs":{},"o":{"df":0,"docs":{},"t":{"df":0,"docs":{},"o":{"c":{"df":0,"docs":{},"o":{"df":0,"docs":{},"l":{"_":{"df":0,"docs":{},"e":{"df":0,"docs":{},"x":{"c":{"df":0,"docs":{},"l":{"df":0,"docs":{},"u":{"df":0,"docs":{},"s":{"df":1,"docs":{"21":{"tf":1.4142135623730951}},"i":{"df":0,"docs":{},"v":{"df":0,"docs":{},"e":{":":{":":{"<":{"d":{"df":0,"docs":{},"e":{"df":0,"docs":{},"v":{"df":0,"docs":{},"i":{"c":{"df":0,"docs":{},"e":{"df":0,"docs":{},"p":{"a":{"df":0,"docs":{},"t":{"df":0,"docs":{},"h":{"df":0,"docs":{},"t":{"df":0,"docs":{},"o":{"df":0,"docs":{},"t":{"df":0,"docs":{},"e":{"df":0,"docs":{},"x":{"df":0,"docs":{},"t":{"df":2,"docs":{"20":{"tf":1.0},"21":{"tf":1.0}}}}}}}}}}},"df":0,"docs":{}}}},"df":0,"docs":{}}}}},"df":0,"docs":{},"l":{"df":0,"docs":{},"o":{"a":{"d":{"df":0,"docs":{},"e":{"d":{"df":0,"docs":{},"i":{"df":0,"docs":{},"m":{"a":{"df":0,"docs":{},"g":{"df":0,"docs":{},"e":{">":{"(":{"b":{"df":0,"docs":{},"o":{"df":0,"docs":{},"o":{"df":0,"docs":{},"t":{"_":{"df":0,"docs":{},"s":{"df":0,"docs":{},"e":{"df":0,"docs":{},"r":{"df":0,"docs":{},"v":{"df":0,"docs":{},"i":{"c":{"df":0,"docs":{},"e":{"df":0,"docs":{},"s":{".":{"df":0,"docs":{},"i":{"df":0,"docs":{},"m":{"a":{"df":0,"docs":{},"g":{"df":0,"docs":{},"e":{"_":{"df":0,"docs":{},"h":{"a":{"df":0,"docs":{},"n":{"d":{"df":0,"docs":{},"l":{"df":2,"docs":{"20":{"tf":1.0},"21":{"tf":1.0}}}},"df":0,"docs":{}}},"df":0,"docs":{}}},"df":0,"docs":{}}}},"df":0,"docs":{}}}},"df":0,"docs":{}}}},"df":0,"docs":{}}}}}}},"df":0,"docs":{}}}}},"df":0,"docs":{}},"df":0,"docs":{}},"df":0,"docs":{}}}},"df":0,"docs":{}}}},"df":0,"docs":{}}},"df":0,"docs":{}},"df":0,"docs":{}}}},"df":0,"docs":{}},"df":0,"docs":{}},"df":0,"docs":{}}}}}}}},"df":0,"docs":{}}}},"df":0,"docs":{}}}},"df":0,"docs":{}}}}}}},"df":5,"docs":{"19":{"tf":2.23606797749979},"20":{"tf":1.7320508075688772},"21":{"tf":2.0},"22":{"tf":1.4142135623730951},"29":{"tf":1.0}}},"r":{"df":5,"docs":{"10":{"tf":1.0},"11":{"tf":1.0},"16":{"tf":1.0},"25":{"tf":1.4142135623730951},"29":{"tf":1.0}}}},"t":{"df":0,"docs":{},"i":{"df":0,"docs":{},"o":{"df":0,"docs":{},"n":{"<":{"&":{"df":0,"docs":{},"m":{"df":0,"docs":{},"u":{"df":0,"docs":{},"t":{"df":1,"docs":{"22":{"tf":1.4142135623730951}}}}}},"df":0,"docs":{}},"df":3,"docs":{"17":{"tf":1.0},"24":{"tf":1.0},"26":{"tf":1.0}}}}}}},"r":{"d":{"df":0,"docs":{},"e":{"df":0,"docs":{},"r":{"df":2,"docs":{"27":{"tf":1.0},"7":{"tf":1.0}}}}},"df":0,"docs":{},"i":{"df":0,"docs":{},"g":{"df":0,"docs":{},"i":{"df":0,"docs":{},"n":{"df":1,"docs":{"26":{"tf":1.0}}}}}}},"s":{"df":1,"docs":{"15":{"tf":1.0}}},"u":{"df":0,"docs":{},"t":{"df":2,"docs":{"21":{"tf":1.0},"33":{"tf":1.0}},"p":{"df":0,"docs":{},"u":{"df":0,"docs":{},"t":{"df":3,"docs":{"21":{"tf":1.0},"22":{"tf":1.7320508075688772},"5":{"tf":1.4142135623730951}}}}},"s":{"df":0,"docs":{},"i":{"d":{"df":1,"docs":{"25":{"tf":1.0}}},"df":0,"docs":{}}}}},"v":{"df":0,"docs":{},"e":{"df":0,"docs":{},"r":{"df":2,"docs":{"27":{"tf":1.0},"34":{"tf":1.0}},"v":{"df":0,"docs":{},"i":{"df":0,"docs":{},"e":{"df":0,"docs":{},"w":{"df":1,"docs":{"19":{"tf":1.0}}}}}},"w":{"df":0,"docs":{},"r":{"df":0,"docs":{},"i":{"df":0,"docs":{},"t":{"df":1,"docs":{"32":{"tf":1.0}}}}}}}},"m":{"df":0,"docs":{},"f":{"df":2,"docs":{"10":{"tf":2.0},"11":{"tf":1.7320508075688772}}}}}},"p":{".":{"df":0,"docs":{},"i":{"df":1,"docs":{"22":{"tf":1.7320508075688772}}},"x":{"df":1,"docs":{"22":{"tf":1.4142135623730951}}}},"a":{"c":{"df":0,"docs":{},"k":{"a":{"df":0,"docs":{},"g":{"df":1,"docs":{"11":{"tf":1.4142135623730951}},"e":{"'":{"df":1,"docs":{"11":{"tf":1.0}}},"df":0,"docs":{}}}},"df":1,"docs":{"31":{"tf":1.0}}}},"d":{"df":1,"docs":{"22":{"tf":1.0}}},"df":0,"docs":{},"g":{"df":0,"docs":{},"e":{"df":1,"docs":{"24":{"tf":1.0}}}},"n":{"df":0,"docs":{},"i":{"c":{"df":1,"docs":{"5":{"tf":1.0}}},"df":0,"docs":{}}},"r":{"a":{"df":0,"docs":{},"m":{"df":0,"docs":{},"e":{"df":0,"docs":{},"t":{"df":1,"docs":{"21":{"tf":1.4142135623730951}}}}}},"df":0,"docs":{},"s":{"df":0,"docs":{},"e":{"a":{"b":{"df":0,"docs":{},"l":{"df":1,"docs":{"31":{"tf":1.0}}}},"df":0,"docs":{}},"df":0,"docs":{}}},"t":{"df":2,"docs":{"27":{"tf":1.0},"5":{"tf":1.0}},"i":{"c":{"df":0,"docs":{},"u":{"df":0,"docs":{},"l":{"a":{"df":0,"docs":{},"r":{"df":2,"docs":{"19":{"tf":1.0},"35":{"tf":1.0}}}},"df":0,"docs":{}}}},"df":0,"docs":{},"t":{"df":7,"docs":{"12":{"tf":1.4142135623730951},"15":{"tf":3.3166247903554},"16":{"tf":2.0},"27":{"tf":1.0},"31":{"tf":1.0},"34":{"tf":3.3166247903554},"35":{"tf":2.6457513110645907}}}}}},"s":{"df":0,"docs":{},"s":{"df":2,"docs":{"21":{"tf":1.0},"23":{"tf":1.0}}}},"t":{"df":0,"docs":{},"h":{"/":{"df":0,"docs":{},"t":{"df":0,"docs":{},"o":{"/":{"d":{"df":0,"docs":{},"i":{"df":0,"docs":{},"s":{"df":0,"docs":{},"k":{"_":{"df":0,"docs":{},"p":{"a":{"df":0,"docs":{},"r":{"df":0,"docs":{},"t":{"df":0,"docs":{},"i":{"df":0,"docs":{},"t":{"df":1,"docs":{"16":{"tf":1.4142135623730951}}}}}}},"df":0,"docs":{}}},"df":1,"docs":{"16":{"tf":1.0}}}}}},"df":0,"docs":{},"y":{"df":0,"docs":{},"o":{"df":0,"docs":{},"u":{"df":0,"docs":{},"r":{"df":1,"docs":{"16":{"tf":1.0}}}}}}},"df":0,"docs":{}}}},"df":6,"docs":{"15":{"tf":1.0},"19":{"tf":1.0},"20":{"tf":2.0},"21":{"tf":1.7320508075688772},"31":{"tf":3.1622776601683795},"35":{"tf":1.0}}}},"u":{"df":0,"docs":{},"s":{"df":3,"docs":{"1":{"tf":1.0},"21":{"tf":1.0},"5":{"tf":1.0}}}}},"df":2,"docs":{"12":{"tf":1.0},"22":{"tf":2.0}},"e":{"df":0,"docs":{},"r":{"df":0,"docs":{},"s":{"df":0,"docs":{},"i":{"df":0,"docs":{},"s":{"df":0,"docs":{},"t":{"df":1,"docs":{"33":{"tf":1.0}}}}}}}},"h":{"a":{"df":0,"docs":{},"s":{"df":0,"docs":{},"e":{"df":1,"docs":{"25":{"tf":1.4142135623730951}}}}},"df":0,"docs":{},"y":{"df":0,"docs":{},"s":{"df":0,"docs":{},"i":{"c":{"df":1,"docs":{"29":{"tf":1.0}}},"df":0,"docs":{}}}}},"i":{"df":0,"docs":{},"x":{"df":0,"docs":{},"e":{"df":0,"docs":{},"l":{"(":{"&":{"df":0,"docs":{},"m":{"df":0,"docs":{},"u":{"df":0,"docs":{},"t":{"df":1,"docs":{"22":{"tf":1.4142135623730951}}}}}},"df":0,"docs":{}},".":{"b":{"df":0,"docs":{},"l":{"df":0,"docs":{},"u":{"df":1,"docs":{"22":{"tf":1.4142135623730951}}}}},"df":0,"docs":{},"g":{"df":0,"docs":{},"r":{"df":0,"docs":{},"e":{"df":0,"docs":{},"e":{"df":0,"docs":{},"n":{"df":1,"docs":{"22":{"tf":1.4142135623730951}}}}}}},"r":{"df":1,"docs":{"22":{"tf":1.4142135623730951}}}},"df":1,"docs":{"22":{"tf":3.3166247903554}}}}}},"l":{"a":{"c":{"df":0,"docs":{},"e":{"df":3,"docs":{"21":{"tf":1.0},"27":{"tf":1.0},"30":{"tf":1.0}}}},"df":0,"docs":{},"t":{"df":0,"docs":{},"f":{"df":0,"docs":{},"o":{"df":0,"docs":{},"r":{"df":0,"docs":{},"m":{"df":1,"docs":{"25":{"tf":1.4142135623730951}}}}}}}},"df":0,"docs":{},"u":{"df":1,"docs":{"32":{"tf":1.0}}}},"o":{"df":0,"docs":{},"i":{"df":0,"docs":{},"n":{"df":0,"docs":{},"t":{":":{":":{"df":0,"docs":{},"n":{"df":0,"docs":{},"e":{"df":0,"docs":{},"w":{"(":{"b":{"df":0,"docs":{},"o":{"df":0,"docs":{},"r":{"d":{"df":1,"docs":{"22":{"tf":1.0}}},"df":0,"docs":{}}}},"df":0,"docs":{},"s":{"df":0,"docs":{},"i":{"df":0,"docs":{},"z":{"df":0,"docs":{},"e":{".":{"df":0,"docs":{},"x":{"df":1,"docs":{"22":{"tf":1.7320508075688772}}}},"df":0,"docs":{}}}}},"w":{"df":0,"docs":{},"i":{"d":{"df":0,"docs":{},"t":{"df":0,"docs":{},"h":{"df":1,"docs":{"22":{"tf":1.0}}}}},"df":0,"docs":{}}}},"df":0,"docs":{}}}}},"df":0,"docs":{}},"df":3,"docs":{"22":{"tf":2.0},"26":{"tf":1.0},"5":{"tf":1.0}},"e":{"df":0,"docs":{},"r":{"df":2,"docs":{"29":{"tf":1.0},"31":{"tf":1.0}}}}}}},"o":{"df":0,"docs":{},"r":{"df":1,"docs":{"33":{"tf":1.0}}}},"w":{"df":0,"docs":{},"e":{"df":0,"docs":{},"r":{"df":1,"docs":{"33":{"tf":1.0}}}}}},"r":{"a":{"c":{"df":0,"docs":{},"t":{"df":0,"docs":{},"i":{"c":{"df":1,"docs":{"18":{"tf":1.0}}},"df":0,"docs":{}}}},"df":0,"docs":{}},"df":0,"docs":{},"e":{"c":{"df":0,"docs":{},"i":{"df":0,"docs":{},"s":{"df":1,"docs":{"34":{"tf":1.0}}}}},"df":0,"docs":{},"p":{"a":{"df":0,"docs":{},"r":{"df":2,"docs":{"14":{"tf":1.0},"15":{"tf":1.4142135623730951}}}},"df":0,"docs":{}},"s":{"df":0,"docs":{},"s":{"df":1,"docs":{"17":{"tf":1.7320508075688772}}}},"v":{"df":0,"docs":{},"e":{"df":0,"docs":{},"n":{"df":0,"docs":{},"t":{"df":1,"docs":{"33":{"tf":1.0}}}}},"i":{"df":0,"docs":{},"o":{"df":0,"docs":{},"u":{"df":1,"docs":{"21":{"tf":1.0}}}}}}},"i":{"df":0,"docs":{},"m":{"a":{"df":0,"docs":{},"r":{"df":0,"docs":{},"i":{"df":1,"docs":{"34":{"tf":1.0}}}}},"df":0,"docs":{}},"n":{"df":0,"docs":{},"t":{"_":{"df":0,"docs":{},"i":{"df":0,"docs":{},"m":{"a":{"df":0,"docs":{},"g":{"df":0,"docs":{},"e":{"_":{"df":0,"docs":{},"p":{"a":{"df":0,"docs":{},"t":{"df":0,"docs":{},"h":{"(":{"b":{"df":0,"docs":{},"o":{"df":0,"docs":{},"o":{"df":0,"docs":{},"t":{"_":{"df":0,"docs":{},"s":{"df":0,"docs":{},"e":{"df":0,"docs":{},"r":{"df":0,"docs":{},"v":{"df":0,"docs":{},"i":{"c":{"df":2,"docs":{"20":{"tf":1.0},"21":{"tf":1.0}},"e":{"df":0,"docs":{},"s":{")":{".":{"df":0,"docs":{},"u":{"df":0,"docs":{},"n":{"df":0,"docs":{},"w":{"df":0,"docs":{},"r":{"a":{"df":0,"docs":{},"p":{"df":1,"docs":{"20":{"tf":1.0}}}},"df":0,"docs":{}}}}}},"df":0,"docs":{}},"df":0,"docs":{}}}},"df":0,"docs":{}}}}}}},"df":0,"docs":{}}}}},"df":0,"docs":{}},"df":1,"docs":{"21":{"tf":1.4142135623730951}}}}},"df":0,"docs":{}}},"df":0,"docs":{}}}},"df":0,"docs":{}}}},"df":2,"docs":{"1":{"tf":1.0},"20":{"tf":1.0}}}}},"o":{"c":{"df":0,"docs":{},"e":{"df":0,"docs":{},"s":{"df":0,"docs":{},"s":{"df":2,"docs":{"1":{"tf":1.0},"25":{"tf":1.0}}}}}},"d":{"df":0,"docs":{},"u":{"c":{"df":2,"docs":{"23":{"tf":1.0},"8":{"tf":1.0}}},"df":0,"docs":{}}},"df":0,"docs":{},"g":{"df":0,"docs":{},"r":{"a":{"df":0,"docs":{},"m":{"'":{"df":1,"docs":{"21":{"tf":1.0}}},"df":4,"docs":{"20":{"tf":2.449489742783178},"21":{"tf":1.0},"33":{"tf":1.0},"5":{"tf":1.4142135623730951}}}},"df":0,"docs":{}}},"j":{"df":0,"docs":{},"e":{"c":{"df":0,"docs":{},"t":{"df":1,"docs":{"11":{"tf":1.4142135623730951}}}},"df":0,"docs":{}}},"t":{"df":0,"docs":{},"o":{"c":{"df":0,"docs":{},"o":{"df":0,"docs":{},"l":{"'":{"df":1,"docs":{"22":{"tf":1.0}}},"df":9,"docs":{"19":{"tf":3.0},"20":{"tf":1.7320508075688772},"21":{"tf":2.8284271247461903},"22":{"tf":1.7320508075688772},"26":{"tf":1.0},"27":{"tf":1.0},"28":{"tf":1.4142135623730951},"29":{"tf":1.0},"30":{"tf":3.3166247903554}}}}},"df":0,"docs":{}}},"v":{"df":0,"docs":{},"i":{"d":{"df":8,"docs":{"10":{"tf":1.0},"11":{"tf":1.4142135623730951},"19":{"tf":1.0},"26":{"tf":2.0},"28":{"tf":1.0},"30":{"tf":1.4142135623730951},"32":{"tf":1.0},"5":{"tf":1.4142135623730951}}},"df":0,"docs":{}}}}},"u":{"df":0,"docs":{},"r":{"df":0,"docs":{},"p":{"df":0,"docs":{},"o":{"df":0,"docs":{},"s":{"df":1,"docs":{"34":{"tf":1.0}}}}}},"t":{"df":1,"docs":{"25":{"tf":1.0}}}}},"q":{"df":0,"docs":{},"e":{"df":0,"docs":{},"m":{"df":0,"docs":{},"u":{"df":3,"docs":{"0":{"tf":1.0},"10":{"tf":2.23606797749979},"13":{"tf":1.7320508075688772}}}}},"u":{"df":0,"docs":{},"i":{"c":{"df":0,"docs":{},"k":{"df":1,"docs":{"5":{"tf":1.0}}}},"df":0,"docs":{},"r":{"df":0,"docs":{},"k":{"df":1,"docs":{"33":{"tf":1.0}}}}}}},"r":{"a":{"df":0,"docs":{},"n":{"d":{"df":0,"docs":{},"o":{"df":0,"docs":{},"m":{"df":1,"docs":{"22":{"tf":1.7320508075688772}}}}},"df":0,"docs":{},"g":{"df":1,"docs":{"21":{"tf":1.0}}}},"w":{"df":1,"docs":{"36":{"tf":1.0}}}},"df":1,"docs":{"22":{"tf":1.4142135623730951}},"e":{"a":{"d":{"a":{"b":{"df":0,"docs":{},"l":{"df":1,"docs":{"31":{"tf":1.0}}}},"df":0,"docs":{}},"df":3,"docs":{"21":{"tf":1.0},"30":{"tf":1.0},"33":{"tf":1.0}}},"df":0,"docs":{},"l":{"df":1,"docs":{"14":{"tf":1.0}}}},"b":{"df":0,"docs":{},"o":{"df":0,"docs":{},"o":{"df":0,"docs":{},"t":{"df":1,"docs":{"17":{"tf":1.0}}}}}},"c":{"df":0,"docs":{},"o":{"df":0,"docs":{},"r":{"d":{"df":1,"docs":{"34":{"tf":1.0}}},"df":0,"docs":{}}}},"d":{"df":1,"docs":{"22":{"tf":1.0}},"u":{"df":0,"docs":{},"n":{"d":{"df":1,"docs":{"34":{"tf":1.0}}},"df":0,"docs":{}}}},"df":0,"docs":{},"f":{"df":0,"docs":{},"e":{"df":0,"docs":{},"r":{"df":3,"docs":{"11":{"tf":1.0},"21":{"tf":1.0},"36":{"tf":2.23606797749979}}}}},"g":{"df":0,"docs":{},"u":{"df":0,"docs":{},"l":{"a":{"df":0,"docs":{},"r":{"df":1,"docs":{"21":{"tf":1.0}}}},"df":0,"docs":{}}}},"l":{"a":{"df":0,"docs":{},"t":{"df":2,"docs":{"24":{"tf":1.0},"33":{"tf":1.0}}}},"df":1,"docs":{"34":{"tf":1.0}},"e":{"df":0,"docs":{},"v":{"df":2,"docs":{"0":{"tf":1.0},"24":{"tf":1.0}}}}},"m":{"df":0,"docs":{},"o":{"df":0,"docs":{},"v":{"df":1,"docs":{"7":{"tf":1.0}}}}},"p":{"df":0,"docs":{},"l":{"a":{"c":{"df":1,"docs":{"4":{"tf":1.0}}},"df":0,"docs":{}},"df":0,"docs":{}},"o":{"df":0,"docs":{},"s":{"df":0,"docs":{},"i":{"df":0,"docs":{},"t":{"df":0,"docs":{},"o":{"df":0,"docs":{},"r":{"df":0,"docs":{},"i":{"df":2,"docs":{"22":{"tf":1.0},"7":{"tf":1.0}}}}}}}}},"r":{"df":0,"docs":{},"e":{"df":0,"docs":{},"s":{"df":4,"docs":{"27":{"tf":1.0},"29":{"tf":1.0},"33":{"tf":1.0},"5":{"tf":1.0}},"e":{"df":0,"docs":{},"n":{"df":0,"docs":{},"t":{"df":2,"docs":{"27":{"tf":1.7320508075688772},"31":{"tf":1.0}}}}}}}}},"q":{"df":0,"docs":{},"u":{"df":0,"docs":{},"i":{"df":0,"docs":{},"r":{"df":2,"docs":{"15":{"tf":1.4142135623730951},"5":{"tf":1.0}}}}}},"s":{"df":0,"docs":{},"e":{"df":0,"docs":{},"t":{"df":1,"docs":{"25":{"tf":1.0}}}},"o":{"df":0,"docs":{},"u":{"df":0,"docs":{},"r":{"c":{"df":3,"docs":{"29":{"tf":1.4142135623730951},"30":{"tf":1.0},"31":{"tf":1.0}}},"df":0,"docs":{}}}},"t":{"df":2,"docs":{"21":{"tf":1.0},"22":{"tf":1.0}}},"u":{"df":0,"docs":{},"l":{"df":0,"docs":{},"t":{"df":3,"docs":{"20":{"tf":1.4142135623730951},"21":{"tf":1.4142135623730951},"22":{"tf":1.7320508075688772}}}}}},"t":{"df":0,"docs":{},"u":{"df":0,"docs":{},"r":{"df":0,"docs":{},"n":{"df":5,"docs":{"19":{"tf":1.0},"21":{"tf":1.0},"25":{"tf":1.0},"26":{"tf":1.0},"5":{"tf":1.4142135623730951}}}}}}},"i":{"df":0,"docs":{},"s":{"c":{"df":1,"docs":{"35":{"tf":1.7320508075688772}}},"df":0,"docs":{}}},"n":{"df":0,"docs":{},"g":{".":{"df":0,"docs":{},"g":{"df":0,"docs":{},"e":{"df":0,"docs":{},"t":{"_":{"df":0,"docs":{},"r":{"df":0,"docs":{},"n":{"df":0,"docs":{},"g":{"(":{"df":0,"docs":{},"n":{"df":0,"docs":{},"o":{"df":0,"docs":{},"n":{"df":1,"docs":{"22":{"tf":1.0}}}}}},"df":0,"docs":{}}}}},"df":0,"docs":{}}}}},"_":{"df":0,"docs":{},"h":{"a":{"df":0,"docs":{},"n":{"d":{"df":0,"docs":{},"l":{"df":1,"docs":{"22":{"tf":1.0}}}},"df":0,"docs":{}}},"df":0,"docs":{}}},"df":1,"docs":{"22":{"tf":1.7320508075688772}}}},"o":{"df":0,"docs":{},"o":{"df":0,"docs":{},"t":{"df":1,"docs":{"7":{"tf":1.0}}}}},"s":{"df":7,"docs":{"0":{"tf":1.0},"21":{"tf":1.0},"22":{"tf":1.0},"24":{"tf":1.0},"25":{"tf":1.0},"27":{"tf":1.0},"30":{"tf":1.4142135623730951}}},"u":{"df":0,"docs":{},"n":{"df":11,"docs":{"1":{"tf":1.0},"10":{"tf":1.0},"14":{"tf":1.4142135623730951},"16":{"tf":1.0},"20":{"tf":1.4142135623730951},"21":{"tf":1.0},"22":{"tf":1.4142135623730951},"25":{"tf":1.4142135623730951},"5":{"tf":1.0},"8":{"tf":1.0},"9":{"tf":1.0}},"t":{"df":0,"docs":{},"i":{"df":0,"docs":{},"m":{"df":5,"docs":{"23":{"tf":1.0},"25":{"tf":2.0},"26":{"tf":1.0},"30":{"tf":1.0},"33":{"tf":1.0}},"e":{"_":{"a":{"c":{"c":{"df":0,"docs":{},"e":{"df":0,"docs":{},"s":{"df":0,"docs":{},"s":{"df":1,"docs":{"33":{"tf":1.0}}}}}},"df":0,"docs":{}},"df":0,"docs":{}},"df":0,"docs":{}},"df":0,"docs":{},"s":{"df":0,"docs":{},"e":{"df":0,"docs":{},"r":{"df":0,"docs":{},"v":{"df":0,"docs":{},"i":{"c":{"df":2,"docs":{"25":{"tf":1.4142135623730951},"26":{"tf":1.4142135623730951}}},"df":0,"docs":{}}}}}}}}}}},"s":{"df":0,"docs":{},"t":{"'":{"df":1,"docs":{"23":{"tf":1.0}}},"df":6,"docs":{"0":{"tf":1.4142135623730951},"1":{"tf":1.0},"3":{"tf":1.4142135623730951},"36":{"tf":1.0},"5":{"tf":1.7320508075688772},"7":{"tf":1.0}},"f":{"df":0,"docs":{},"l":{"a":{"df":0,"docs":{},"g":{"df":1,"docs":{"23":{"tf":1.4142135623730951}}}},"df":0,"docs":{}}},"u":{"df":0,"docs":{},"p":{"df":1,"docs":{"7":{"tf":1.0}}}}}}}},"s":{"a":{"df":0,"docs":{},"f":{"df":0,"docs":{},"e":{"df":0,"docs":{},"s":{"df":0,"docs":{},"t":{"df":1,"docs":{"19":{"tf":1.0}}}}}},"m":{"df":0,"docs":{},"e":{"df":4,"docs":{"19":{"tf":1.0},"27":{"tf":1.0},"31":{"tf":1.0},"32":{"tf":1.0}}}}},"c":{"df":0,"docs":{},"o":{"df":0,"docs":{},"p":{"df":0,"docs":{},"e":{"d":{"df":0,"docs":{},"p":{"df":0,"docs":{},"r":{"df":0,"docs":{},"o":{"df":0,"docs":{},"t":{"df":0,"docs":{},"o":{"c":{"df":0,"docs":{},"o":{"df":0,"docs":{},"l":{"df":1,"docs":{"19":{"tf":1.0}}}}},"df":0,"docs":{}}}}}}},"df":1,"docs":{"25":{"tf":1.0}}}}},"r":{"df":0,"docs":{},"e":{"df":0,"docs":{},"e":{"df":0,"docs":{},"n":{"df":1,"docs":{"22":{"tf":2.0}},"s":{"df":0,"docs":{},"h":{"df":0,"docs":{},"o":{"df":0,"docs":{},"t":{"df":1,"docs":{"22":{"tf":1.0}}}}}}}}}}},"df":1,"docs":{"22":{"tf":1.0}},"e":{"c":{"df":0,"docs":{},"o":{"df":0,"docs":{},"n":{"d":{"a":{"df":0,"docs":{},"r":{"df":0,"docs":{},"i":{"df":1,"docs":{"34":{"tf":1.0}}}}},"df":4,"docs":{"1":{"tf":1.0},"13":{"tf":1.0},"21":{"tf":1.0},"5":{"tf":1.0}}},"df":0,"docs":{}}}},"df":0,"docs":{},"e":{"df":6,"docs":{"13":{"tf":1.0},"15":{"tf":1.4142135623730951},"19":{"tf":1.0},"30":{"tf":1.0},"31":{"tf":1.0},"5":{"tf":1.0}}},"l":{"df":0,"docs":{},"e":{"c":{"df":0,"docs":{},"t":{"df":1,"docs":{"17":{"tf":1.0}}}},"df":0,"docs":{}},"f":{".":{"df":0,"docs":{},"h":{"df":0,"docs":{},"e":{"df":0,"docs":{},"i":{"df":0,"docs":{},"g":{"df":0,"docs":{},"h":{"df":0,"docs":{},"t":{"df":1,"docs":{"22":{"tf":1.4142135623730951}}}}}}}},"p":{"df":0,"docs":{},"i":{"df":0,"docs":{},"x":{"df":0,"docs":{},"e":{"df":0,"docs":{},"l":{"df":1,"docs":{"22":{"tf":1.4142135623730951}},"s":{".":{"df":0,"docs":{},"g":{"df":0,"docs":{},"e":{"df":0,"docs":{},"t":{"_":{"df":0,"docs":{},"m":{"df":0,"docs":{},"u":{"df":0,"docs":{},"t":{"(":{"df":0,"docs":{},"i":{"df":1,"docs":{"22":{"tf":1.4142135623730951}}}},"df":0,"docs":{}}}}},"df":0,"docs":{}}}}},"df":0,"docs":{}}}}}}},"w":{"df":0,"docs":{},"i":{"d":{"df":0,"docs":{},"t":{"df":0,"docs":{},"h":{"df":1,"docs":{"22":{"tf":2.0}}}}},"df":0,"docs":{}}}},"df":1,"docs":{"22":{"tf":2.449489742783178}}}},"p":{"a":{"df":0,"docs":{},"r":{"df":1,"docs":{"25":{"tf":1.0}}}},"df":0,"docs":{}},"r":{"df":0,"docs":{},"v":{"df":1,"docs":{"32":{"tf":1.0}},"i":{"c":{"df":9,"docs":{"23":{"tf":1.0},"24":{"tf":1.0},"25":{"tf":1.4142135623730951},"26":{"tf":2.23606797749979},"30":{"tf":1.0},"33":{"tf":1.4142135623730951},"36":{"tf":1.0},"4":{"tf":1.0},"5":{"tf":1.0}}},"df":0,"docs":{}}}},"t":{"df":12,"docs":{"15":{"tf":1.0},"16":{"tf":1.0},"20":{"tf":1.0},"21":{"tf":1.4142135623730951},"22":{"tf":1.0},"23":{"tf":1.0},"26":{"tf":1.0},"3":{"tf":1.0},"33":{"tf":2.0},"35":{"tf":1.0},"5":{"tf":1.0},"7":{"tf":1.0}}},"v":{"df":0,"docs":{},"e":{"df":0,"docs":{},"r":{"df":1,"docs":{"25":{"tf":1.0}}}}}},"g":{"d":{"df":0,"docs":{},"i":{"df":0,"docs":{},"s":{"df":0,"docs":{},"k":{"df":1,"docs":{"16":{"tf":1.0}}}}}},"df":0,"docs":{}},"h":{"df":0,"docs":{},"o":{"df":0,"docs":{},"r":{"df":0,"docs":{},"t":{"df":3,"docs":{"27":{"tf":1.0},"34":{"tf":1.0},"35":{"tf":1.0}},"l":{"df":0,"docs":{},"i":{"df":1,"docs":{"20":{"tf":1.0}}}}}},"w":{"df":1,"docs":{"22":{"tf":1.0}}}}},"i":{"df":0,"docs":{},"e":{"df":0,"docs":{},"r":{"df":0,"docs":{},"p":{"df":0,"docs":{},"i":{"df":0,"docs":{},"n":{"df":0,"docs":{},"s":{"df":0,"docs":{},"k":{"df":0,"docs":{},"i":{"df":1,"docs":{"22":{"tf":1.0}}}}}},"ń":{"df":0,"docs":{},"s":{"df":0,"docs":{},"k":{"df":0,"docs":{},"i":{"df":1,"docs":{"22":{"tf":1.0}}}}}}}}}},"m":{"df":0,"docs":{},"p":{"df":0,"docs":{},"l":{"df":3,"docs":{"1":{"tf":1.0},"22":{"tf":1.0},"5":{"tf":1.0}},"e":{"df":0,"docs":{},"r":{"df":1,"docs":{"5":{"tf":1.0}}}}}}},"n":{"df":0,"docs":{},"g":{"df":0,"docs":{},"l":{"df":1,"docs":{"22":{"tf":1.7320508075688772}}}}},"z":{"df":0,"docs":{},"e":{".":{"df":0,"docs":{},"i":{"df":1,"docs":{"22":{"tf":1.7320508075688772}}}},"df":2,"docs":{"22":{"tf":1.0},"33":{"tf":1.0}}}}},"l":{"df":0,"docs":{},"i":{"c":{"df":0,"docs":{},"e":{"df":1,"docs":{"19":{"tf":1.0}}}},"df":0,"docs":{}}},"o":{"df":0,"docs":{},"m":{"df":0,"docs":{},"e":{"df":0,"docs":{},"t":{"df":0,"docs":{},"h":{"df":2,"docs":{"20":{"tf":1.0},"29":{"tf":1.0}}},"i":{"df":0,"docs":{},"m":{"df":1,"docs":{"35":{"tf":1.0}}}}}}},"u":{"df":0,"docs":{},"r":{"c":{"df":1,"docs":{"24":{"tf":1.0}}},"df":0,"docs":{}}}},"p":{"a":{"c":{"df":0,"docs":{},"e":{"df":1,"docs":{"33":{"tf":1.0}}}},"df":0,"docs":{}},"df":0,"docs":{},"e":{"c":{"df":0,"docs":{},"i":{"a":{"df":0,"docs":{},"l":{"df":3,"docs":{"14":{"tf":1.0},"33":{"tf":1.0},"35":{"tf":1.0}}}},"df":0,"docs":{},"f":{"df":9,"docs":{"15":{"tf":1.4142135623730951},"21":{"tf":1.4142135623730951},"24":{"tf":1.4142135623730951},"25":{"tf":1.4142135623730951},"26":{"tf":1.7320508075688772},"27":{"tf":1.0},"30":{"tf":1.4142135623730951},"34":{"tf":1.0},"36":{"tf":1.0}},"i":{"df":1,"docs":{"7":{"tf":1.0}}}}}},"df":0,"docs":{}}},"r":{"c":{"/":{"df":0,"docs":{},"m":{"a":{"df":0,"docs":{},"i":{"df":0,"docs":{},"n":{".":{"df":0,"docs":{},"r":{"df":1,"docs":{"4":{"tf":1.0}},"s":{"@":{"0":{"1":{"1":{"df":1,"docs":{"13":{"tf":1.0}}},"df":0,"docs":{}},"df":0,"docs":{}},"df":0,"docs":{}},"df":0,"docs":{}}}},"df":0,"docs":{}}}},"df":0,"docs":{}}},"df":1,"docs":{"22":{"tf":1.4142135623730951}}},"df":0,"docs":{}},"t":{"a":{"df":0,"docs":{},"g":{"df":0,"docs":{},"e":{"df":4,"docs":{"25":{"tf":2.23606797749979},"26":{"tf":1.4142135623730951},"30":{"tf":1.4142135623730951},"33":{"tf":1.0}}}},"l":{"df":0,"docs":{},"l":{"df":1,"docs":{"5":{"tf":1.0}}}},"n":{"d":{"a":{"df":0,"docs":{},"r":{"d":{"df":4,"docs":{"27":{"tf":1.0},"34":{"tf":1.0},"35":{"tf":1.0},"5":{"tf":1.7320508075688772}}},"df":0,"docs":{}}},"df":0,"docs":{}},"df":0,"docs":{}},"r":{"df":0,"docs":{},"t":{"/":{"df":0,"docs":{},"e":{"df":0,"docs":{},"n":{"d":{"df":1,"docs":{"34":{"tf":1.0}}},"df":0,"docs":{}}}},"df":4,"docs":{"16":{"tf":1.0},"21":{"tf":1.4142135623730951},"22":{"tf":1.0},"5":{"tf":1.0}}}},"t":{"df":0,"docs":{},"u":{"df":5,"docs":{"20":{"tf":1.0},"22":{"tf":1.0},"26":{"tf":1.0},"4":{"tf":1.0},"5":{"tf":1.4142135623730951}},"s":{":":{":":{"df":0,"docs":{},"s":{"df":0,"docs":{},"u":{"c":{"c":{"df":0,"docs":{},"e":{"df":0,"docs":{},"s":{"df":0,"docs":{},"s":{"df":4,"docs":{"20":{"tf":1.0},"22":{"tf":1.0},"4":{"tf":1.0},"5":{"tf":1.4142135623730951}}}}}},"df":0,"docs":{}},"df":0,"docs":{}}}},"df":0,"docs":{}},"df":0,"docs":{}}}}},"d":{"df":1,"docs":{"5":{"tf":1.0}}},"df":0,"docs":{},"e":{"df":0,"docs":{},"p":{"df":1,"docs":{"15":{"tf":1.4142135623730951}}}},"i":{"df":0,"docs":{},"l":{"df":0,"docs":{},"l":{"df":3,"docs":{"25":{"tf":1.0},"28":{"tf":1.0},"5":{"tf":1.0}}}}},"o":{"df":0,"docs":{},"r":{"a":{"df":0,"docs":{},"g":{"df":4,"docs":{"11":{"tf":1.0},"26":{"tf":1.0},"32":{"tf":1.0},"33":{"tf":1.4142135623730951}}}},"df":0,"docs":{},"e":{"df":5,"docs":{"19":{"tf":1.0},"22":{"tf":1.0},"31":{"tf":1.0},"32":{"tf":1.0},"33":{"tf":1.7320508075688772}}}}},"r":{"df":0,"docs":{},"i":{"c":{"df":0,"docs":{},"t":{"df":0,"docs":{},"l":{"df":0,"docs":{},"i":{"df":2,"docs":{"15":{"tf":1.4142135623730951},"5":{"tf":1.0}}}}}},"df":0,"docs":{},"n":{"df":0,"docs":{},"g":{"df":1,"docs":{"27":{"tf":1.4142135623730951}}}}},"u":{"c":{"df":0,"docs":{},"t":{"df":1,"docs":{"22":{"tf":1.7320508075688772}},"u":{"df":0,"docs":{},"r":{"df":5,"docs":{"12":{"tf":1.0},"15":{"tf":1.0},"26":{"tf":1.0},"31":{"tf":1.4142135623730951},"34":{"tf":1.0}}}}}},"df":0,"docs":{}}}},"u":{"b":{"df":0,"docs":{},"s":{"df":0,"docs":{},"y":{"df":0,"docs":{},"s":{"df":0,"docs":{},"t":{"df":0,"docs":{},"e":{"df":0,"docs":{},"m":{"df":1,"docs":{"23":{"tf":1.0}}}}}}}}},"c":{"c":{"df":0,"docs":{},"e":{"df":0,"docs":{},"s":{"df":0,"docs":{},"s":{"df":2,"docs":{"21":{"tf":1.0},"5":{"tf":1.0}},"f":{"df":0,"docs":{},"u":{"df":0,"docs":{},"l":{"df":0,"docs":{},"l":{"df":0,"docs":{},"i":{"df":1,"docs":{"5":{"tf":1.0}}}}}}}}}}},"df":0,"docs":{},"h":{"df":5,"docs":{"0":{"tf":1.0},"25":{"tf":1.0},"26":{"tf":1.0},"29":{"tf":1.0},"31":{"tf":1.0}}}},"d":{"df":0,"docs":{},"o":{"df":1,"docs":{"10":{"tf":1.4142135623730951}}}},"df":0,"docs":{},"m":{"df":0,"docs":{},"m":{"a":{"df":0,"docs":{},"r":{"df":1,"docs":{"24":{"tf":1.0}}}},"df":0,"docs":{}}},"p":{"df":0,"docs":{},"p":{"df":0,"docs":{},"o":{"df":0,"docs":{},"r":{"df":0,"docs":{},"t":{"df":4,"docs":{"19":{"tf":1.0},"21":{"tf":1.0},"34":{"tf":1.0},"7":{"tf":1.0}}}}}}}},"y":{"df":0,"docs":{},"s":{"df":0,"docs":{},"t":{"df":0,"docs":{},"e":{"df":0,"docs":{},"m":{"_":{"df":0,"docs":{},"t":{"a":{"b":{"df":0,"docs":{},"l":{"df":0,"docs":{},"e":{")":{".":{"df":0,"docs":{},"u":{"df":0,"docs":{},"n":{"df":0,"docs":{},"w":{"df":0,"docs":{},"r":{"a":{"df":0,"docs":{},"p":{"df":4,"docs":{"20":{"tf":1.0},"22":{"tf":1.0},"4":{"tf":1.0},"5":{"tf":1.0}}}},"df":0,"docs":{}}}}}},"df":0,"docs":{}},".":{"b":{"df":0,"docs":{},"o":{"df":0,"docs":{},"o":{"df":0,"docs":{},"t":{"_":{"df":0,"docs":{},"s":{"df":0,"docs":{},"e":{"df":0,"docs":{},"r":{"df":0,"docs":{},"v":{"df":0,"docs":{},"i":{"c":{"df":2,"docs":{"20":{"tf":1.0},"22":{"tf":1.0}},"e":{"df":0,"docs":{},"s":{"(":{")":{".":{"df":0,"docs":{},"s":{"df":0,"docs":{},"t":{"a":{"df":0,"docs":{},"l":{"df":0,"docs":{},"l":{"(":{"1":{"0":{"_":{"0":{"0":{"0":{"_":{"0":{"0":{"0":{"df":2,"docs":{"4":{"tf":1.0},"5":{"tf":1.0}}},"df":0,"docs":{}},"df":0,"docs":{}},"df":0,"docs":{}},"df":0,"docs":{}},"df":0,"docs":{}},"df":0,"docs":{}},"df":0,"docs":{}},"df":0,"docs":{}},"df":0,"docs":{}},"df":0,"docs":{}},"df":0,"docs":{}}}},"df":0,"docs":{}}}},"df":0,"docs":{}},"df":0,"docs":{}},"df":0,"docs":{}}}},"df":0,"docs":{}}}}}}},"df":0,"docs":{}}}}},"df":0,"docs":{}},"df":0,"docs":{}}}},"df":0,"docs":{}},"df":5,"docs":{"20":{"tf":1.0},"22":{"tf":1.0},"26":{"tf":1.0},"4":{"tf":1.0},"5":{"tf":1.0}}}},"df":13,"docs":{"10":{"tf":1.0},"11":{"tf":1.0},"12":{"tf":1.4142135623730951},"13":{"tf":1.0},"15":{"tf":1.4142135623730951},"16":{"tf":1.0},"20":{"tf":1.0},"25":{"tf":2.449489742783178},"26":{"tf":2.0},"31":{"tf":1.4142135623730951},"34":{"tf":1.0},"35":{"tf":2.6457513110645907},"5":{"tf":1.7320508075688772}},"t":{"a":{"b":{"df":0,"docs":{},"l":{"df":0,"docs":{},"e":{":":{":":{"b":{"df":0,"docs":{},"o":{"df":0,"docs":{},"o":{"df":0,"docs":{},"t":{"_":{"df":0,"docs":{},"s":{"df":0,"docs":{},"e":{"df":0,"docs":{},"r":{"df":0,"docs":{},"v":{"df":0,"docs":{},"i":{"c":{"df":1,"docs":{"26":{"tf":1.0}}},"df":0,"docs":{}}}}}}},"df":0,"docs":{}}}}},"df":0,"docs":{},"e":{"df":0,"docs":{},"x":{"df":0,"docs":{},"i":{"df":0,"docs":{},"t":{"_":{"b":{"df":0,"docs":{},"o":{"df":0,"docs":{},"o":{"df":0,"docs":{},"t":{"_":{"df":0,"docs":{},"s":{"df":0,"docs":{},"e":{"df":0,"docs":{},"r":{"df":0,"docs":{},"v":{"df":0,"docs":{},"i":{"c":{"df":2,"docs":{"25":{"tf":1.0},"26":{"tf":1.0}}},"df":0,"docs":{}}}}}}},"df":0,"docs":{}}}}},"df":0,"docs":{}},"df":0,"docs":{}}}}},"r":{"df":0,"docs":{},"u":{"df":0,"docs":{},"n":{"df":0,"docs":{},"t":{"df":0,"docs":{},"i":{"df":0,"docs":{},"m":{"df":0,"docs":{},"e":{"_":{"df":0,"docs":{},"s":{"df":0,"docs":{},"e":{"df":0,"docs":{},"r":{"df":0,"docs":{},"v":{"df":0,"docs":{},"i":{"c":{"df":1,"docs":{"26":{"tf":1.0}}},"df":0,"docs":{}}}}}}},"df":0,"docs":{}}}}}}}}},"df":0,"docs":{}},"<":{"b":{"df":0,"docs":{},"o":{"df":0,"docs":{},"o":{"df":0,"docs":{},"t":{"df":5,"docs":{"20":{"tf":1.0},"22":{"tf":1.0},"26":{"tf":1.0},"4":{"tf":1.0},"5":{"tf":1.0}}}}}},"df":0,"docs":{}},"df":0,"docs":{}}}},"df":0,"docs":{}},"df":1,"docs":{"26":{"tf":1.0}}}}}}}}},"t":{"a":{"b":{"df":0,"docs":{},"l":{"df":5,"docs":{"15":{"tf":1.0},"25":{"tf":1.7320508075688772},"26":{"tf":3.4641016151377544},"34":{"tf":1.4142135623730951},"5":{"tf":1.4142135623730951}}}},"df":0,"docs":{},"k":{"df":0,"docs":{},"e":{"df":2,"docs":{"21":{"tf":1.4142135623730951},"5":{"tf":1.0}}}},"n":{"df":0,"docs":{},"g":{"df":0,"docs":{},"i":{"b":{"df":0,"docs":{},"l":{"df":1,"docs":{"29":{"tf":1.0}}}},"df":0,"docs":{}}}},"r":{"df":0,"docs":{},"g":{"df":0,"docs":{},"e":{"df":0,"docs":{},"t":{"/":{"df":0,"docs":{},"x":{"8":{"6":{"_":{"6":{"4":{"df":2,"docs":{"12":{"tf":1.0},"8":{"tf":1.0}}},"df":0,"docs":{}},"df":0,"docs":{}},"df":0,"docs":{}},"df":0,"docs":{}},"df":0,"docs":{}}},"df":5,"docs":{"17":{"tf":1.0},"23":{"tf":1.0},"36":{"tf":1.0},"7":{"tf":1.7320508075688772},"8":{"tf":1.0}}}}}}},"df":0,"docs":{},"e":{"df":0,"docs":{},"n":{"df":1,"docs":{"21":{"tf":1.0}}},"r":{"df":0,"docs":{},"m":{"df":1,"docs":{"19":{"tf":1.0}},"i":{"df":0,"docs":{},"n":{"df":1,"docs":{"32":{"tf":1.0}}}}}},"x":{"df":0,"docs":{},"t":{"df":2,"docs":{"21":{"tf":1.0},"31":{"tf":1.0}}}}},"h":{"df":0,"docs":{},"i":{"df":0,"docs":{},"n":{"df":0,"docs":{},"g":{"df":4,"docs":{"20":{"tf":1.0},"21":{"tf":1.0},"31":{"tf":1.0},"5":{"tf":1.7320508075688772}}}}},"o":{"df":0,"docs":{},"u":{"df":0,"docs":{},"g":{"df":0,"docs":{},"h":{"df":1,"docs":{"21":{"tf":1.0}}}}}},"r":{"df":0,"docs":{},"e":{"df":0,"docs":{},"e":{"df":3,"docs":{"23":{"tf":1.0},"27":{"tf":1.0},"7":{"tf":1.0}}}},"o":{"df":0,"docs":{},"u":{"df":0,"docs":{},"g":{"df":0,"docs":{},"h":{"df":4,"docs":{"20":{"tf":1.0},"21":{"tf":1.0},"25":{"tf":1.0},"35":{"tf":1.0}}}}}}}},"i":{"df":0,"docs":{},"m":{"df":0,"docs":{},"e":{"df":5,"docs":{"17":{"tf":1.4142135623730951},"21":{"tf":1.4142135623730951},"22":{"tf":1.0},"26":{"tf":1.0},"5":{"tf":1.0}}}}},"o":{"df":0,"docs":{},"g":{"df":0,"docs":{},"e":{"df":0,"docs":{},"t":{"df":0,"docs":{},"h":{"df":2,"docs":{"21":{"tf":1.0},"28":{"tf":1.0}}}}}},"o":{"df":0,"docs":{},"l":{"c":{"df":0,"docs":{},"h":{"a":{"df":0,"docs":{},"i":{"df":0,"docs":{},"n":{".":{"df":0,"docs":{},"t":{"df":0,"docs":{},"o":{"df":0,"docs":{},"m":{"df":0,"docs":{},"l":{"df":1,"docs":{"7":{"tf":1.0}}}}}}},"df":1,"docs":{"7":{"tf":1.7320508075688772}}}}},"df":0,"docs":{}}},"df":1,"docs":{"0":{"tf":1.0}}}},"p":{"df":2,"docs":{"26":{"tf":1.0},"5":{"tf":1.0}}}},"r":{"df":0,"docs":{},"e":{"a":{"df":0,"docs":{},"t":{"df":1,"docs":{"27":{"tf":1.0}}}},"df":0,"docs":{}},"i":{"a":{"df":0,"docs":{},"n":{"df":0,"docs":{},"g":{"df":0,"docs":{},"l":{"df":1,"docs":{"22":{"tf":2.0}},"e":{"'":{"df":1,"docs":{"22":{"tf":1.0}}},"[":{"df":0,"docs":{},"g":{"df":0,"docs":{},"e":{"df":0,"docs":{},"t":{"_":{"df":0,"docs":{},"r":{"a":{"df":0,"docs":{},"n":{"d":{"df":0,"docs":{},"o":{"df":0,"docs":{},"m":{"_":{"df":0,"docs":{},"u":{"df":0,"docs":{},"s":{"df":0,"docs":{},"i":{"df":0,"docs":{},"z":{"df":0,"docs":{},"e":{"(":{"&":{"df":0,"docs":{},"m":{"df":0,"docs":{},"u":{"df":0,"docs":{},"t":{"df":1,"docs":{"22":{"tf":1.0}}}}}},"df":0,"docs":{}},"df":0,"docs":{}}}}}}},"df":0,"docs":{}}}},"df":0,"docs":{}}},"df":0,"docs":{}}},"df":0,"docs":{}}}}},"df":0,"docs":{}}}}}},"c":{"df":0,"docs":{},"k":{"df":0,"docs":{},"i":{"df":1,"docs":{"33":{"tf":1.0}}}}},"df":2,"docs":{"34":{"tf":1.0},"35":{"tf":1.0}}}},"u":{"df":0,"docs":{},"r":{"df":0,"docs":{},"n":{"df":1,"docs":{"5":{"tf":1.0}}}},"t":{"df":0,"docs":{},"o":{"df":0,"docs":{},"r":{"df":0,"docs":{},"i":{"df":1,"docs":{"1":{"tf":1.4142135623730951}}}}}}},"w":{"df":0,"docs":{},"o":{"df":3,"docs":{"10":{"tf":1.0},"11":{"tf":1.0},"5":{"tf":1.0}}}},"y":{"df":0,"docs":{},"p":{"df":0,"docs":{},"e":{"c":{"df":0,"docs":{},"o":{"d":{"df":0,"docs":{},"e":{"=":{"1":{":":{"c":{"1":{"2":{"a":{"7":{"3":{"2":{"8":{"df":1,"docs":{"16":{"tf":1.0}}},"df":0,"docs":{}},"df":0,"docs":{}},"df":0,"docs":{}},"df":0,"docs":{}},"df":0,"docs":{}},"df":0,"docs":{}},"df":0,"docs":{}},"df":0,"docs":{}},"df":0,"docs":{}},"df":0,"docs":{}},"df":0,"docs":{}}},"df":0,"docs":{}}},"df":10,"docs":{"15":{"tf":1.0},"16":{"tf":1.0},"21":{"tf":2.449489742783178},"22":{"tf":1.0},"23":{"tf":1.0},"27":{"tf":1.0},"33":{"tf":1.0},"34":{"tf":1.0},"35":{"tf":1.0},"5":{"tf":1.0}}},"i":{"c":{"df":1,"docs":{"25":{"tf":1.4142135623730951}}},"df":0,"docs":{}}}}},"u":{"8":{"df":1,"docs":{"22":{"tf":1.4142135623730951}}},"b":{"df":0,"docs":{},"u":{"df":0,"docs":{},"n":{"df":0,"docs":{},"t":{"df":0,"docs":{},"u":{"df":1,"docs":{"11":{"tf":1.0}}}}}}},"c":{"df":1,"docs":{"32":{"tf":1.0}}},"df":0,"docs":{},"e":{"df":0,"docs":{},"f":{"df":0,"docs":{},"i":{"'":{"df":1,"docs":{"35":{"tf":1.0}}},"/":{"d":{"df":0,"docs":{},"e":{"b":{"df":0,"docs":{},"u":{"df":0,"docs":{},"g":{"/":{"df":0,"docs":{},"m":{"df":0,"docs":{},"i":{"df":2,"docs":{"12":{"tf":1.0},"8":{"tf":1.0}}}}},"df":0,"docs":{}}}},"df":0,"docs":{}}},"df":0,"docs":{}},":":{":":{"df":0,"docs":{},"p":{"df":0,"docs":{},"r":{"df":0,"docs":{},"e":{"df":0,"docs":{},"l":{"df":0,"docs":{},"u":{"d":{"df":4,"docs":{"20":{"tf":1.0},"22":{"tf":1.0},"4":{"tf":1.0},"5":{"tf":1.4142135623730951}}},"df":0,"docs":{}}}},"o":{"df":0,"docs":{},"t":{"df":0,"docs":{},"o":{":":{":":{"c":{"df":0,"docs":{},"o":{"df":0,"docs":{},"n":{"df":0,"docs":{},"s":{"df":0,"docs":{},"o":{"df":0,"docs":{},"l":{"df":0,"docs":{},"e":{":":{":":{"df":0,"docs":{},"g":{"df":0,"docs":{},"o":{"df":0,"docs":{},"p":{":":{":":{"df":0,"docs":{},"{":{"b":{"df":0,"docs":{},"l":{"df":0,"docs":{},"t":{"df":0,"docs":{},"o":{"df":0,"docs":{},"p":{"df":1,"docs":{"22":{"tf":1.0}}}}}}},"df":0,"docs":{}}},"df":0,"docs":{}},"df":0,"docs":{}}}}},"df":0,"docs":{}},"df":0,"docs":{}}}}}}}},"d":{"df":0,"docs":{},"e":{"df":0,"docs":{},"v":{"df":0,"docs":{},"i":{"c":{"df":0,"docs":{},"e":{"_":{"df":0,"docs":{},"p":{"a":{"df":0,"docs":{},"t":{"df":0,"docs":{},"h":{":":{":":{"df":0,"docs":{},"t":{"df":0,"docs":{},"e":{"df":0,"docs":{},"x":{"df":0,"docs":{},"t":{"df":2,"docs":{"20":{"tf":1.0},"31":{"tf":1.0}}}}}}},"df":0,"docs":{}},"df":1,"docs":{"31":{"tf":1.0}}}}},"df":0,"docs":{}}},"df":0,"docs":{}}},"df":0,"docs":{}}}}},"df":0,"docs":{},"l":{"df":0,"docs":{},"o":{"a":{"d":{"df":0,"docs":{},"e":{"d":{"_":{"df":0,"docs":{},"i":{"df":0,"docs":{},"m":{"a":{"df":0,"docs":{},"g":{"df":0,"docs":{},"e":{":":{":":{"df":0,"docs":{},"l":{"df":0,"docs":{},"o":{"a":{"d":{"df":0,"docs":{},"e":{"d":{"df":0,"docs":{},"i":{"df":0,"docs":{},"m":{"a":{"df":0,"docs":{},"g":{"df":1,"docs":{"20":{"tf":1.0}}}},"df":0,"docs":{}}}},"df":0,"docs":{}}},"df":0,"docs":{}},"df":0,"docs":{}}}},"df":0,"docs":{}},"df":0,"docs":{}}}},"df":0,"docs":{}}}},"df":0,"docs":{}},"df":0,"docs":{}}},"df":0,"docs":{}},"df":0,"docs":{}}},"r":{"df":0,"docs":{},"n":{"df":0,"docs":{},"g":{":":{":":{"df":0,"docs":{},"r":{"df":0,"docs":{},"n":{"df":0,"docs":{},"g":{"df":1,"docs":{"22":{"tf":1.0}}}}}},"df":0,"docs":{}},"df":0,"docs":{}}}}},"df":0,"docs":{}},"df":0,"docs":{}}}}}},"r":{"df":0,"docs":{},"e":{"df":0,"docs":{},"s":{"df":0,"docs":{},"u":{"df":0,"docs":{},"l":{"df":0,"docs":{},"t":{"df":2,"docs":{"21":{"tf":1.0},"22":{"tf":1.0}}}}}}}},"s":{"df":0,"docs":{},"t":{"a":{"df":0,"docs":{},"t":{"df":0,"docs":{},"u":{"df":1,"docs":{"21":{"tf":1.0}}}}},"df":0,"docs":{}}},"t":{"a":{"b":{"df":0,"docs":{},"l":{"df":0,"docs":{},"e":{":":{":":{"b":{"df":0,"docs":{},"o":{"df":0,"docs":{},"o":{"df":0,"docs":{},"t":{":":{":":{"b":{"df":0,"docs":{},"o":{"df":0,"docs":{},"o":{"df":0,"docs":{},"t":{"df":0,"docs":{},"s":{"df":0,"docs":{},"e":{"df":0,"docs":{},"r":{"df":0,"docs":{},"v":{"df":0,"docs":{},"i":{"c":{"df":1,"docs":{"22":{"tf":1.0}}},"df":0,"docs":{}}}}}}}}}},"df":0,"docs":{},"s":{"df":0,"docs":{},"e":{"a":{"df":0,"docs":{},"r":{"c":{"df":0,"docs":{},"h":{"df":0,"docs":{},"t":{"df":0,"docs":{},"y":{"df":0,"docs":{},"p":{"df":1,"docs":{"20":{"tf":1.0}}}}}}},"df":0,"docs":{}}},"df":0,"docs":{}}}},"df":0,"docs":{}},"df":0,"docs":{}}}}},"df":0,"docs":{}},"df":0,"docs":{}},"df":0,"docs":{}}}},"df":0,"docs":{}},"df":0,"docs":{}},"{":{"df":0,"docs":{},"i":{"d":{"df":0,"docs":{},"e":{"df":0,"docs":{},"n":{"df":0,"docs":{},"t":{"df":0,"docs":{},"i":{"df":0,"docs":{},"f":{"df":0,"docs":{},"i":{"df":1,"docs":{"20":{"tf":1.0}}}}}}}}},"df":0,"docs":{}}}},"df":0,"docs":{}},"_":{"df":0,"docs":{},"s":{"df":0,"docs":{},"e":{"df":0,"docs":{},"r":{"df":0,"docs":{},"v":{"df":0,"docs":{},"i":{"c":{"df":1,"docs":{"5":{"tf":1.4142135623730951}},"e":{"df":0,"docs":{},"s":{":":{":":{"df":0,"docs":{},"i":{"df":0,"docs":{},"n":{"df":0,"docs":{},"i":{"df":0,"docs":{},"t":{"(":{"&":{"df":0,"docs":{},"m":{"df":0,"docs":{},"u":{"df":0,"docs":{},"t":{"df":4,"docs":{"20":{"tf":1.0},"22":{"tf":1.0},"4":{"tf":1.0},"5":{"tf":1.0}}}}}},"df":0,"docs":{}},"df":0,"docs":{}}}}}},"df":0,"docs":{}},"df":0,"docs":{}}}},"df":0,"docs":{}}}}}}},"df":24,"docs":{"0":{"tf":2.0},"1":{"tf":1.0},"10":{"tf":1.0},"12":{"tf":1.4142135623730951},"15":{"tf":2.0},"2":{"tf":1.0},"21":{"tf":1.4142135623730951},"22":{"tf":1.0},"23":{"tf":1.4142135623730951},"24":{"tf":2.23606797749979},"25":{"tf":2.449489742783178},"26":{"tf":1.7320508075688772},"27":{"tf":1.4142135623730951},"28":{"tf":1.4142135623730951},"30":{"tf":2.0},"32":{"tf":1.0},"33":{"tf":1.4142135623730951},"34":{"tf":1.4142135623730951},"35":{"tf":1.4142135623730951},"36":{"tf":2.449489742783178},"4":{"tf":2.0},"5":{"tf":2.8284271247461903},"7":{"tf":2.23606797749979},"8":{"tf":1.4142135623730951}}}}},"n":{"a":{"df":0,"docs":{},"u":{"df":0,"docs":{},"t":{"df":0,"docs":{},"h":{"df":0,"docs":{},"o":{"df":0,"docs":{},"r":{"df":1,"docs":{"33":{"tf":1.0}}}}}}}},"d":{"df":0,"docs":{},"e":{"df":0,"docs":{},"r":{"df":3,"docs":{"11":{"tf":1.0},"15":{"tf":1.0},"35":{"tf":1.0}},"s":{"df":0,"docs":{},"t":{"a":{"df":0,"docs":{},"n":{"d":{"df":1,"docs":{"24":{"tf":1.4142135623730951}}},"df":0,"docs":{}}},"df":0,"docs":{}}}}}},"df":0,"docs":{},"i":{"df":0,"docs":{},"q":{"df":0,"docs":{},"u":{"df":2,"docs":{"27":{"tf":1.0},"31":{"tf":1.0}}}}},"k":{"df":0,"docs":{},"n":{"df":0,"docs":{},"o":{"df":0,"docs":{},"w":{"df":0,"docs":{},"n":{"df":4,"docs":{"12":{"tf":1.0},"36":{"tf":1.0},"7":{"tf":1.7320508075688772},"8":{"tf":1.4142135623730951}}}}}}},"l":{"df":0,"docs":{},"i":{"df":0,"docs":{},"k":{"df":2,"docs":{"31":{"tf":1.0},"34":{"tf":1.0}}}}},"s":{"a":{"df":0,"docs":{},"f":{"df":1,"docs":{"19":{"tf":1.0}}}},"df":0,"docs":{}},"t":{"df":0,"docs":{},"i":{"df":0,"docs":{},"l":{"df":1,"docs":{"25":{"tf":1.0}}}}},"u":{"df":0,"docs":{},"s":{"df":1,"docs":{"22":{"tf":1.0}}}}},"p":{"df":4,"docs":{"21":{"tf":1.0},"3":{"tf":1.0},"5":{"tf":1.0},"7":{"tf":1.0}}},"s":{"b":{"df":3,"docs":{"14":{"tf":1.0},"17":{"tf":1.7320508075688772},"29":{"tf":1.0}}},"df":17,"docs":{"0":{"tf":1.0},"13":{"tf":1.0},"15":{"tf":1.7320508075688772},"17":{"tf":1.4142135623730951},"19":{"tf":2.449489742783178},"20":{"tf":2.449489742783178},"21":{"tf":1.7320508075688772},"22":{"tf":3.605551275463989},"26":{"tf":1.0},"27":{"tf":1.4142135623730951},"30":{"tf":1.4142135623730951},"31":{"tf":1.0},"33":{"tf":1.4142135623730951},"34":{"tf":1.4142135623730951},"4":{"tf":1.4142135623730951},"5":{"tf":2.449489742783178},"7":{"tf":1.0}},"i":{"df":0,"docs":{},"z":{"df":1,"docs":{"22":{"tf":3.872983346207417}},"e":{")":{".":{"df":0,"docs":{},"u":{"df":0,"docs":{},"n":{"df":0,"docs":{},"w":{"df":0,"docs":{},"r":{"a":{"df":0,"docs":{},"p":{"df":1,"docs":{"22":{"tf":1.0}}}},"df":0,"docs":{}}}}}},"df":0,"docs":{}},":":{":":{"df":0,"docs":{},"f":{"df":0,"docs":{},"r":{"df":0,"docs":{},"o":{"df":0,"docs":{},"m":{"_":{"df":0,"docs":{},"l":{"df":0,"docs":{},"e":{"_":{"b":{"df":0,"docs":{},"y":{"df":0,"docs":{},"t":{"df":0,"docs":{},"e":{"df":0,"docs":{},"s":{"(":{"b":{"df":0,"docs":{},"u":{"df":0,"docs":{},"f":{"df":1,"docs":{"22":{"tf":1.0}}}}},"df":0,"docs":{}},"df":0,"docs":{}}}}}},"df":0,"docs":{}},"df":0,"docs":{}}}},"df":0,"docs":{}}}}}},"df":0,"docs":{}},"df":0,"docs":{}}}},"r":{"/":{"df":0,"docs":{},"s":{"df":0,"docs":{},"h":{"a":{"df":0,"docs":{},"r":{"df":0,"docs":{},"e":{"/":{"df":0,"docs":{},"o":{"df":0,"docs":{},"v":{"df":0,"docs":{},"m":{"df":0,"docs":{},"f":{"/":{"df":0,"docs":{},"o":{"df":0,"docs":{},"v":{"df":0,"docs":{},"m":{"df":0,"docs":{},"f":{"_":{"c":{"df":0,"docs":{},"o":{"d":{"df":0,"docs":{},"e":{".":{"df":0,"docs":{},"f":{"d":{"df":1,"docs":{"11":{"tf":1.0}}},"df":0,"docs":{}}},"df":0,"docs":{}}},"df":0,"docs":{}}},"df":0,"docs":{},"v":{"a":{"df":0,"docs":{},"r":{"df":0,"docs":{},"s":{".":{"df":0,"docs":{},"f":{"d":{"df":1,"docs":{"11":{"tf":1.0}}},"df":0,"docs":{}}},"df":0,"docs":{}}}},"df":0,"docs":{}}},"df":0,"docs":{}}}}}},"df":1,"docs":{"11":{"tf":1.0}}}}}}},"df":0,"docs":{}}}},"df":0,"docs":{}}}},"df":0,"docs":{}}}},"v":{".":{"df":0,"docs":{},"i":{"df":1,"docs":{"22":{"tf":1.0}}},"x":{"df":1,"docs":{"22":{"tf":1.0}}}},"a":{"df":0,"docs":{},"l":{"df":0,"docs":{},"u":{"df":2,"docs":{"22":{"tf":1.0},"23":{"tf":1.0}}}},"r":{"df":1,"docs":{"11":{"tf":1.0}},"i":{"a":{"b":{"df":0,"docs":{},"l":{"df":7,"docs":{"11":{"tf":1.0},"26":{"tf":1.0},"27":{"tf":1.0},"31":{"tf":1.0},"32":{"tf":2.449489742783178},"33":{"tf":2.8284271247461903},"35":{"tf":1.0}}}},"df":0,"docs":{},"t":{"df":1,"docs":{"11":{"tf":1.0}}}},"df":2,"docs":{"10":{"tf":1.0},"15":{"tf":1.0}},"o":{"df":0,"docs":{},"u":{"df":2,"docs":{"30":{"tf":1.0},"35":{"tf":1.0}}}}}}},"df":2,"docs":{"22":{"tf":1.0},"35":{"tf":1.7320508075688772}},"e":{"c":{"!":{"[":{"b":{"df":0,"docs":{},"l":{"df":0,"docs":{},"t":{"df":0,"docs":{},"p":{"df":0,"docs":{},"i":{"df":0,"docs":{},"x":{"df":0,"docs":{},"e":{"df":0,"docs":{},"l":{":":{":":{"df":0,"docs":{},"n":{"df":0,"docs":{},"e":{"df":0,"docs":{},"w":{"(":{"0":{"df":1,"docs":{"22":{"tf":1.4142135623730951}}},"df":0,"docs":{}},"df":0,"docs":{}}}}},"df":0,"docs":{}},"df":0,"docs":{}}}}}}}}},"df":0,"docs":{}},"df":0,"docs":{}},"<":{"b":{"df":0,"docs":{},"l":{"df":0,"docs":{},"t":{"df":0,"docs":{},"p":{"df":0,"docs":{},"i":{"df":0,"docs":{},"x":{"df":0,"docs":{},"e":{"df":0,"docs":{},"l":{"df":1,"docs":{"22":{"tf":1.4142135623730951}}}}}}}}}},"df":0,"docs":{}},"df":1,"docs":{"22":{"tf":1.0}}},"df":0,"docs":{},"n":{"d":{"df":0,"docs":{},"o":{"df":0,"docs":{},"r":{"'":{"df":2,"docs":{"32":{"tf":1.0},"33":{"tf":1.0}}},"df":2,"docs":{"17":{"tf":1.0},"32":{"tf":1.7320508075688772}}}}},"df":0,"docs":{}},"r":{"df":0,"docs":{},"i":{"df":5,"docs":{"21":{"tf":1.0},"30":{"tf":1.4142135623730951},"31":{"tf":1.0},"33":{"tf":1.0},"34":{"tf":1.4142135623730951}}},"s":{"df":0,"docs":{},"i":{"df":0,"docs":{},"o":{"df":0,"docs":{},"n":{"df":1,"docs":{"35":{"tf":1.0}}}}}},"t":{"df":0,"docs":{},"e":{"df":0,"docs":{},"x":{"df":1,"docs":{"22":{"tf":1.0}}}},"i":{"c":{"df":1,"docs":{"22":{"tf":1.4142135623730951}}},"df":0,"docs":{}}}}},"i":{"a":{"df":1,"docs":{"33":{"tf":1.0}}},"df":0,"docs":{},"r":{"df":0,"docs":{},"t":{"df":0,"docs":{},"u":{"a":{"df":0,"docs":{},"l":{"df":2,"docs":{"10":{"tf":1.0},"26":{"tf":1.0}}}},"df":0,"docs":{}}}}},"m":{"df":2,"docs":{"13":{"tf":1.0},"9":{"tf":1.0}}},"o":{"df":0,"docs":{},"l":{"a":{"df":0,"docs":{},"t":{"df":0,"docs":{},"i":{"df":0,"docs":{},"l":{"df":1,"docs":{"33":{"tf":1.7320508075688772}}}}}},"df":0,"docs":{}}},"v":{"df":0,"docs":{},"f":{"a":{"df":0,"docs":{},"t":{"df":1,"docs":{"13":{"tf":1.0}}}},"df":0,"docs":{}}}},"w":{"a":{"df":0,"docs":{},"l":{"df":0,"docs":{},"k":{"df":1,"docs":{"20":{"tf":1.0}},"t":{"df":0,"docs":{},"h":{"df":0,"docs":{},"r":{"df":0,"docs":{},"o":{"df":0,"docs":{},"u":{"df":0,"docs":{},"g":{"df":0,"docs":{},"h":{"df":2,"docs":{"21":{"tf":1.0},"5":{"tf":1.0}}}}}}}}}}},"n":{"df":0,"docs":{},"t":{"df":1,"docs":{"21":{"tf":1.4142135623730951}}}},"r":{"df":0,"docs":{},"n":{"df":1,"docs":{"16":{"tf":1.0}}}},"y":{"df":2,"docs":{"19":{"tf":1.0},"7":{"tf":1.0}}}},"df":0,"docs":{},"e":{"'":{"df":0,"docs":{},"l":{"df":0,"docs":{},"l":{"df":2,"docs":{"11":{"tf":1.0},"20":{"tf":1.4142135623730951}}}}},"df":0,"docs":{},"l":{"c":{"df":0,"docs":{},"o":{"df":0,"docs":{},"m":{"df":2,"docs":{"0":{"tf":1.0},"30":{"tf":1.0}}}}},"df":0,"docs":{},"l":{"df":1,"docs":{"0":{"tf":1.0}}}}},"h":{"df":0,"docs":{},"o":{"df":0,"docs":{},"l":{"df":0,"docs":{},"e":{"df":2,"docs":{"20":{"tf":1.0},"24":{"tf":1.0}}}}}},"i":{"d":{"df":0,"docs":{},"e":{"df":3,"docs":{"21":{"tf":1.0},"26":{"tf":1.0},"28":{"tf":1.0}}},"t":{"df":0,"docs":{},"h":{"df":1,"docs":{"22":{"tf":2.8284271247461903}}}}},"df":0,"docs":{},"n":{"d":{"df":0,"docs":{},"o":{"df":0,"docs":{},"w":{"df":2,"docs":{"13":{"tf":1.0},"25":{"tf":1.0}}}}},"df":0,"docs":{}},"t":{"df":0,"docs":{},"h":{"df":0,"docs":{},"i":{"df":0,"docs":{},"n":{"df":1,"docs":{"35":{"tf":1.0}}}}}}},"o":{"df":0,"docs":{},"r":{"df":0,"docs":{},"l":{"d":{"df":5,"docs":{"1":{"tf":1.0},"13":{"tf":1.0},"21":{"tf":1.0},"4":{"tf":1.0},"5":{"tf":1.4142135623730951}}},"df":0,"docs":{}}}},"r":{"a":{"df":0,"docs":{},"p":{"df":1,"docs":{"30":{"tf":1.0}}}},"df":0,"docs":{},"i":{"df":0,"docs":{},"t":{"df":0,"docs":{},"e":{"df":3,"docs":{"26":{"tf":1.0},"30":{"tf":1.0},"33":{"tf":1.0}}},"t":{"df":0,"docs":{},"e":{"df":0,"docs":{},"n":{"df":1,"docs":{"33":{"tf":1.0}}}}}}}}},"x":{"8":{"6":{"_":{"6":{"4":{"df":6,"docs":{"1":{"tf":1.0},"13":{"tf":1.0},"15":{"tf":1.0},"35":{"tf":1.0},"7":{"tf":1.0},"8":{"tf":1.0}}},"df":0,"docs":{}},"df":0,"docs":{}},"df":1,"docs":{"8":{"tf":1.0}}},"df":0,"docs":{}},"df":1,"docs":{"22":{"tf":2.8284271247461903}},"t":{"a":{"df":0,"docs":{},"s":{"df":0,"docs":{},"k":{"df":1,"docs":{"22":{"tf":1.0}}}}},"df":0,"docs":{}}},"y":{")":{".":{"df":0,"docs":{},"u":{"df":0,"docs":{},"n":{"df":0,"docs":{},"w":{"df":0,"docs":{},"r":{"a":{"df":0,"docs":{},"p":{"df":1,"docs":{"22":{"tf":1.0}}}},"df":0,"docs":{}}}}}},"df":0,"docs":{}},"df":1,"docs":{"22":{"tf":2.6457513110645907}},"o":{"df":0,"docs":{},"u":{"'":{"df":0,"docs":{},"l":{"df":0,"docs":{},"l":{"df":1,"docs":{"14":{"tf":1.0}}}}},"df":0,"docs":{}}}}}},"breadcrumbs":{"root":{"0":{".":{".":{"df":0,"docs":{},"h":{"df":0,"docs":{},"e":{"df":0,"docs":{},"i":{"df":0,"docs":{},"g":{"df":0,"docs":{},"h":{"df":0,"docs":{},"t":{"df":1,"docs":{"22":{"tf":1.0}}}}}}}},"w":{"df":0,"docs":{},"i":{"d":{"df":0,"docs":{},"t":{"df":0,"docs":{},"h":{"df":1,"docs":{"22":{"tf":1.0}}}}},"df":0,"docs":{}}}},"5":{"df":1,"docs":{"22":{"tf":1.4142135623730951}}},"df":0,"docs":{}},"0":{"a":{"0":{"c":{"9":{"3":{"df":0,"docs":{},"e":{"c":{"9":{"3":{"b":{"df":3,"docs":{"15":{"tf":1.0},"16":{"tf":1.0},"35":{"tf":1.0}}},"df":0,"docs":{}},"df":0,"docs":{}},"df":0,"docs":{}},"df":0,"docs":{}}},"df":0,"docs":{}},"df":0,"docs":{}},"df":0,"docs":{}},"df":0,"docs":{}},"df":0,"docs":{}},"df":1,"docs":{"22":{"tf":3.3166247903554}}},"1":{"0":{"0":{"df":1,"docs":{"22":{"tf":1.0}}},"df":2,"docs":{"1":{"tf":1.0},"5":{"tf":1.0}}},"1":{"d":{"2":{"df":3,"docs":{"15":{"tf":1.0},"16":{"tf":1.0},"35":{"tf":1.0}}},"df":0,"docs":{}},"df":0,"docs":{}},"2":{"8":{"df":1,"docs":{"35":{"tf":1.0}}},"df":0,"docs":{}},"6":{"df":1,"docs":{"27":{"tf":1.0}}},"df":1,"docs":{"22":{"tf":1.4142135623730951}},"m":{"b":{"df":1,"docs":{"16":{"tf":1.0}}},"df":0,"docs":{}}},"2":{".":{"0":{"df":1,"docs":{"22":{"tf":1.7320508075688772}}},"df":0,"docs":{}},"0":{".":{"0":{"df":1,"docs":{"22":{"tf":1.0}}},"df":0,"docs":{}},"df":0,"docs":{}},"5":{"0":{"0":{"df":1,"docs":{"24":{"tf":1.0}}},"df":0,"docs":{}},"5":{".":{"0":{"df":1,"docs":{"22":{"tf":1.4142135623730951}}},"df":0,"docs":{}},"df":1,"docs":{"22":{"tf":1.0}}},"df":0,"docs":{}},"df":1,"docs":{"32":{"tf":1.0}},"f":{"df":0,"docs":{},"e":{"4":{"8":{"8":{"7":{"4":{"a":{"4":{"1":{"0":{"df":1,"docs":{"27":{"tf":1.0}}},"df":0,"docs":{}},"df":0,"docs":{}},"df":0,"docs":{}},"df":0,"docs":{}},"df":0,"docs":{}},"df":0,"docs":{}},"df":0,"docs":{}},"df":0,"docs":{}},"df":0,"docs":{}}}},"3":{"1":{"3":{"b":{"0":{"d":{"7":{"c":{"df":1,"docs":{"27":{"tf":1.0}}},"df":0,"docs":{}},"df":0,"docs":{}},"df":0,"docs":{}},"df":0,"docs":{}},"df":0,"docs":{}},"df":0,"docs":{}},"2":{"df":2,"docs":{"22":{"tf":1.0},"35":{"tf":1.4142135623730951}}},"df":1,"docs":{"22":{"tf":1.0}}},"4":{"d":{"df":0,"docs":{},"e":{"7":{"df":1,"docs":{"27":{"tf":1.0}}},"df":0,"docs":{}}},"df":0,"docs":{}},"6":{"4":{"df":2,"docs":{"35":{"tf":1.0},"8":{"tf":1.0}}},"df":0,"docs":{}},"8":{"df":1,"docs":{"22":{"tf":1.4142135623730951}}},"9":{"9":{"df":0,"docs":{},"e":{"d":{"df":1,"docs":{"27":{"tf":1.0}}},"df":0,"docs":{}}},"df":0,"docs":{},"m":{"b":{"df":1,"docs":{"16":{"tf":1.0}}},"df":0,"docs":{}}},"a":{"a":{"df":0,"docs":{},"r":{"c":{"df":0,"docs":{},"h":{"3":{"2":{"df":1,"docs":{"35":{"tf":1.0}}},"df":0,"docs":{}},"6":{"4":{"df":2,"docs":{"35":{"tf":1.0},"7":{"tf":1.0}}},"df":0,"docs":{}},"df":0,"docs":{}}},"df":0,"docs":{}}},"b":{"df":0,"docs":{},"o":{"df":0,"docs":{},"v":{"df":1,"docs":{"13":{"tf":1.0}}}},"s":{"df":0,"docs":{},"e":{"df":0,"docs":{},"n":{"c":{"df":1,"docs":{"35":{"tf":1.0}}},"df":0,"docs":{}}},"t":{"df":0,"docs":{},"r":{"a":{"c":{"df":0,"docs":{},"t":{"df":1,"docs":{"22":{"tf":1.0}}}},"df":0,"docs":{}},"df":0,"docs":{}}}}},"c":{"c":{"df":0,"docs":{},"e":{"df":0,"docs":{},"s":{"df":0,"docs":{},"s":{"df":8,"docs":{"11":{"tf":1.0},"13":{"tf":1.0},"21":{"tf":1.0},"25":{"tf":1.4142135623730951},"26":{"tf":3.0},"30":{"tf":1.0},"33":{"tf":1.4142135623730951},"5":{"tf":1.0}}}}},"i":{"d":{"df":0,"docs":{},"e":{"df":0,"docs":{},"n":{"df":0,"docs":{},"t":{"df":1,"docs":{"32":{"tf":1.0}}}}}},"df":0,"docs":{}}},"df":0,"docs":{},"t":{"df":0,"docs":{},"i":{"df":0,"docs":{},"v":{"df":1,"docs":{"25":{"tf":1.0}}}},"u":{"a":{"df":0,"docs":{},"l":{"df":2,"docs":{"27":{"tf":1.0},"34":{"tf":1.0}}}},"df":0,"docs":{}}}},"d":{"a":{"df":0,"docs":{},"p":{"df":0,"docs":{},"t":{"df":1,"docs":{"28":{"tf":1.0}}}}},"d":{"df":2,"docs":{"4":{"tf":1.4142135623730951},"7":{"tf":1.0}},"r":{"df":0,"docs":{},"e":{"df":0,"docs":{},"s":{"df":0,"docs":{},"s":{"df":1,"docs":{"34":{"tf":1.0}}}}}}},"df":0,"docs":{},"v":{"a":{"df":0,"docs":{},"n":{"df":0,"docs":{},"t":{"a":{"df":0,"docs":{},"g":{"df":1,"docs":{"34":{"tf":1.0}}}},"df":0,"docs":{}}}},"df":0,"docs":{}}},"df":0,"docs":{},"f":{"df":0,"docs":{},"f":{"df":0,"docs":{},"e":{"c":{"df":0,"docs":{},"t":{"df":1,"docs":{"33":{"tf":1.0}}}},"df":0,"docs":{}}}},"g":{"a":{"df":0,"docs":{},"i":{"df":0,"docs":{},"n":{"df":1,"docs":{"21":{"tf":1.0}}}}},"df":0,"docs":{}},"l":{"df":0,"docs":{},"g":{"df":0,"docs":{},"o":{"df":0,"docs":{},"r":{"df":0,"docs":{},"i":{"df":0,"docs":{},"t":{"df":0,"docs":{},"h":{"df":0,"docs":{},"m":{"df":1,"docs":{"22":{"tf":1.0}}}}}}}}},"i":{"a":{"df":1,"docs":{"21":{"tf":1.0}}},"df":0,"docs":{}},"l":{"df":0,"docs":{},"o":{"c":{":":{":":{"df":0,"docs":{},"v":{"df":0,"docs":{},"e":{"c":{":":{":":{"df":0,"docs":{},"v":{"df":0,"docs":{},"e":{"c":{"df":1,"docs":{"22":{"tf":1.0}}},"df":0,"docs":{}}}},"df":0,"docs":{}},"df":1,"docs":{"22":{"tf":1.0}}},"df":0,"docs":{}}}},"df":0,"docs":{}},"df":3,"docs":{"22":{"tf":1.0},"26":{"tf":1.0},"5":{"tf":1.4142135623730951}}},"df":0,"docs":{},"w":{"df":1,"docs":{"15":{"tf":1.0}},"s":{"df":0,"docs":{},"h":{"df":0,"docs":{},"o":{"df":0,"docs":{},"r":{"df":0,"docs":{},"t":{"c":{"df":0,"docs":{},"u":{"df":0,"docs":{},"t":{"df":1,"docs":{"20":{"tf":1.0}},"s":{"(":{"df":0,"docs":{},"f":{"a":{"df":0,"docs":{},"l":{"df":0,"docs":{},"s":{"df":2,"docs":{"20":{"tf":1.0},"21":{"tf":1.0}}}}},"df":0,"docs":{}}},"df":0,"docs":{}}}}},"df":0,"docs":{}}}}}}}}},"t":{"df":0,"docs":{},"e":{"df":0,"docs":{},"r":{"df":1,"docs":{"22":{"tf":1.0}},"n":{"df":1,"docs":{"34":{"tf":1.0}}}}},"h":{"df":0,"docs":{},"o":{"df":0,"docs":{},"u":{"df":0,"docs":{},"g":{"df":0,"docs":{},"h":{"df":2,"docs":{"31":{"tf":1.0},"34":{"tf":1.0}}}}}}}},"w":{"a":{"df":0,"docs":{},"y":{"df":3,"docs":{"27":{"tf":1.0},"35":{"tf":1.0},"5":{"tf":1.0}}}},"df":0,"docs":{}}},"n":{"df":0,"docs":{},"o":{"df":0,"docs":{},"t":{"df":0,"docs":{},"h":{"df":2,"docs":{"32":{"tf":1.0},"33":{"tf":1.0}}}}},"y":{"df":0,"docs":{},"t":{"df":0,"docs":{},"h":{"df":1,"docs":{"29":{"tf":1.0}}}}}},"p":{"df":0,"docs":{},"i":{"df":1,"docs":{"30":{"tf":1.0}}},"p":{".":{"df":0,"docs":{},"e":{"df":0,"docs":{},"f":{"df":0,"docs":{},"i":{"df":2,"docs":{"12":{"tf":1.0},"8":{"tf":1.0}}}}}},"df":1,"docs":{"4":{"tf":1.4142135623730951}},"e":{"a":{"df":0,"docs":{},"r":{"df":2,"docs":{"13":{"tf":1.0},"17":{"tf":1.0}}}},"df":0,"docs":{}},"l":{"df":0,"docs":{},"i":{"c":{"df":12,"docs":{"0":{"tf":1.0},"1":{"tf":1.4142135623730951},"15":{"tf":1.0},"2":{"tf":1.7320508075688772},"23":{"tf":1.4142135623730951},"25":{"tf":1.0},"26":{"tf":1.0},"28":{"tf":1.0},"3":{"tf":1.0},"4":{"tf":2.0},"5":{"tf":2.449489742783178},"8":{"tf":1.7320508075688772}}},"df":0,"docs":{}}},"r":{"df":0,"docs":{},"o":{"df":0,"docs":{},"p":{"df":0,"docs":{},"r":{"df":0,"docs":{},"i":{"df":2,"docs":{"15":{"tf":1.0},"7":{"tf":1.0}}}}}}}},"t":{"df":1,"docs":{"10":{"tf":1.0}}}},"r":{"b":{"df":0,"docs":{},"i":{"df":0,"docs":{},"t":{"df":0,"docs":{},"r":{"a":{"df":0,"docs":{},"r":{"df":0,"docs":{},"i":{"df":1,"docs":{"32":{"tf":1.0}}}}},"df":0,"docs":{}}}}},"c":{"df":0,"docs":{},"h":{"df":1,"docs":{"35":{"tf":1.0}},"i":{"df":0,"docs":{},"t":{"df":0,"docs":{},"e":{"c":{"df":0,"docs":{},"t":{"df":0,"docs":{},"u":{"df":0,"docs":{},"r":{"df":2,"docs":{"15":{"tf":1.4142135623730951},"35":{"tf":1.4142135623730951}}}}}},"df":0,"docs":{}}}}}},"df":0,"docs":{},"e":{"df":0,"docs":{},"n":{"'":{"df":0,"docs":{},"t":{"df":1,"docs":{"27":{"tf":1.0}}}},"df":0,"docs":{}}},"g":{"df":0,"docs":{},"s":{"=":{"/":{"df":0,"docs":{},"s":{"df":0,"docs":{},"u":{"b":{"df":0,"docs":{},"s":{"df":0,"docs":{},"y":{"df":0,"docs":{},"s":{"df":0,"docs":{},"t":{"df":0,"docs":{},"e":{"df":0,"docs":{},"m":{":":{"df":0,"docs":{},"e":{"df":0,"docs":{},"f":{"df":0,"docs":{},"i":{"_":{"df":0,"docs":{},"r":{"df":0,"docs":{},"u":{"df":0,"docs":{},"n":{"df":0,"docs":{},"t":{"df":0,"docs":{},"i":{"df":0,"docs":{},"m":{"df":0,"docs":{},"e":{"_":{"d":{"df":0,"docs":{},"r":{"df":0,"docs":{},"i":{"df":0,"docs":{},"v":{"df":1,"docs":{"23":{"tf":1.0}}}}}},"df":0,"docs":{}},"df":0,"docs":{}}}}}}}}},"df":0,"docs":{}}}}},"df":0,"docs":{}}}}}}}},"df":0,"docs":{}}}},"df":0,"docs":{}},"df":0,"docs":{}},"u":{"df":0,"docs":{},"m":{"df":0,"docs":{},"e":{"df":0,"docs":{},"n":{"df":0,"docs":{},"t":{"df":3,"docs":{"21":{"tf":1.4142135623730951},"26":{"tf":1.0},"5":{"tf":1.0}}}}}}}},"r":{"a":{"df":0,"docs":{},"y":{"df":4,"docs":{"26":{"tf":1.0},"28":{"tf":1.0},"32":{"tf":1.0},"34":{"tf":2.0}}}},"df":0,"docs":{}},"t":{"df":0,"docs":{},"i":{"c":{"df":0,"docs":{},"l":{"df":1,"docs":{"33":{"tf":1.0}}}},"df":0,"docs":{}}}},"s":{"df":0,"docs":{},"s":{"df":0,"docs":{},"o":{"c":{"df":0,"docs":{},"i":{"df":1,"docs":{"33":{"tf":1.0}}}},"df":0,"docs":{}}}},"t":{"df":0,"docs":{},"t":{"df":0,"docs":{},"r":{"df":0,"docs":{},"i":{"b":{"df":0,"docs":{},"u":{"df":0,"docs":{},"t":{"df":1,"docs":{"33":{"tf":2.23606797749979}}}}},"df":0,"docs":{}}}}},"u":{"df":0,"docs":{},"t":{"df":0,"docs":{},"h":{"df":0,"docs":{},"e":{"df":0,"docs":{},"n":{"df":0,"docs":{},"t":{"df":1,"docs":{"33":{"tf":1.0}}}}}},"o":{"df":0,"docs":{},"m":{"a":{"df":0,"docs":{},"t":{"df":1,"docs":{"19":{"tf":1.0}}}},"df":0,"docs":{}}}}},"v":{"a":{"df":0,"docs":{},"i":{"df":0,"docs":{},"l":{"df":4,"docs":{"19":{"tf":1.0},"21":{"tf":1.4142135623730951},"25":{"tf":1.0},"30":{"tf":1.0}}}}},"df":0,"docs":{}},"w":{"a":{"df":0,"docs":{},"r":{"df":1,"docs":{"27":{"tf":1.0}}}},"df":0,"docs":{}}},"b":{"a":{"4":{"b":{"df":3,"docs":{"15":{"tf":1.0},"16":{"tf":1.0},"35":{"tf":1.0}}},"df":0,"docs":{}},"c":{"df":0,"docs":{},"k":{"df":0,"docs":{},"g":{"df":0,"docs":{},"r":{"df":0,"docs":{},"o":{"df":0,"docs":{},"u":{"df":0,"docs":{},"n":{"d":{"df":1,"docs":{"22":{"tf":1.0}}},"df":0,"docs":{}}}}}}}},"df":0,"docs":{}},"df":0,"docs":{},"e":{"c":{"a":{"df":0,"docs":{},"m":{"df":1,"docs":{"33":{"tf":1.0}}}},"df":0,"docs":{}},"df":1,"docs":{"33":{"tf":1.0}},"g":{"df":0,"docs":{},"i":{"df":0,"docs":{},"n":{"df":1,"docs":{"34":{"tf":1.0}}}}},"l":{"df":0,"docs":{},"o":{"df":0,"docs":{},"w":{"df":1,"docs":{"15":{"tf":1.0}}}}},"s":{"df":0,"docs":{},"t":{"df":2,"docs":{"21":{"tf":1.0},"30":{"tf":1.0}}}},"t":{"df":0,"docs":{},"w":{"df":0,"docs":{},"e":{"df":0,"docs":{},"e":{"df":0,"docs":{},"n":{"df":1,"docs":{"34":{"tf":1.0}}}}}}}},"g":{"df":0,"docs":{},"r":{"df":0,"docs":{},"x":{"df":1,"docs":{"22":{"tf":1.0}}}}},"i":{"df":0,"docs":{},"g":{"df":2,"docs":{"22":{"tf":1.0},"34":{"tf":1.0}}},"t":{"df":3,"docs":{"22":{"tf":1.4142135623730951},"33":{"tf":2.23606797749979},"35":{"tf":2.0}},"e":{"df":1,"docs":{"22":{"tf":1.0}}}}},"l":{"a":{"c":{"df":0,"docs":{},"k":{"df":1,"docs":{"22":{"tf":1.0}}}},"df":0,"docs":{}},"df":0,"docs":{},"i":{"df":0,"docs":{},"t":{"(":{"&":{"df":0,"docs":{},"s":{"df":0,"docs":{},"e":{"df":0,"docs":{},"l":{"df":0,"docs":{},"f":{"df":1,"docs":{"22":{"tf":1.4142135623730951}}}}}}},"df":0,"docs":{}},"df":1,"docs":{"22":{"tf":1.4142135623730951}}}},"o":{"c":{"df":0,"docs":{},"k":{"df":2,"docs":{"30":{"tf":1.0},"34":{"tf":1.0}},"i":{"df":0,"docs":{},"o":{"df":1,"docs":{"30":{"tf":1.0}}}}}},"df":0,"docs":{}},"t":{"df":1,"docs":{"22":{"tf":1.0}},"p":{"df":0,"docs":{},"i":{"df":0,"docs":{},"x":{"df":0,"docs":{},"e":{"df":0,"docs":{},"l":{"df":1,"docs":{"22":{"tf":2.0}}}}}}},"r":{"df":0,"docs":{},"e":{"df":0,"docs":{},"g":{"df":0,"docs":{},"i":{"df":0,"docs":{},"o":{"df":0,"docs":{},"n":{":":{":":{"df":0,"docs":{},"f":{"df":0,"docs":{},"u":{"df":0,"docs":{},"l":{"df":1,"docs":{"22":{"tf":1.4142135623730951}}}}}},"df":0,"docs":{}},"df":1,"docs":{"22":{"tf":1.0}}}}}}}}},"u":{"df":0,"docs":{},"e":{"df":1,"docs":{"22":{"tf":1.0}}}}},"o":{"df":0,"docs":{},"i":{"df":0,"docs":{},"l":{"df":0,"docs":{},"e":{"df":0,"docs":{},"r":{"df":0,"docs":{},"p":{"df":0,"docs":{},"l":{"df":1,"docs":{"5":{"tf":1.0}}}}}}}},"o":{"df":0,"docs":{},"k":{"df":1,"docs":{"0":{"tf":1.4142135623730951}}},"t":{"<":{"a":{"df":0,"docs":{},"r":{"c":{"df":0,"docs":{},"h":{">":{".":{"df":0,"docs":{},"e":{"df":0,"docs":{},"f":{"df":0,"docs":{},"i":{"df":1,"docs":{"35":{"tf":1.0}}}}}},"df":0,"docs":{}},"df":0,"docs":{}}},"df":0,"docs":{}}},"df":0,"docs":{}},"_":{"df":0,"docs":{},"s":{"df":0,"docs":{},"e":{"df":0,"docs":{},"r":{"df":0,"docs":{},"v":{"df":0,"docs":{},"i":{"c":{"df":2,"docs":{"20":{"tf":2.23606797749979},"21":{"tf":2.0}},"e":{"df":0,"docs":{},"s":{".":{"df":0,"docs":{},"s":{"df":0,"docs":{},"t":{"a":{"df":0,"docs":{},"l":{"df":0,"docs":{},"l":{"(":{"1":{"0":{"_":{"0":{"0":{"0":{"_":{"0":{"0":{"0":{"df":1,"docs":{"20":{"tf":1.0}}},"df":0,"docs":{}},"df":0,"docs":{}},"df":0,"docs":{}},"df":0,"docs":{}},"df":0,"docs":{}},"df":0,"docs":{}},"df":0,"docs":{}},"df":0,"docs":{}},"df":0,"docs":{}},"df":0,"docs":{}},"df":0,"docs":{}}}},"df":0,"docs":{}}}},"df":0,"docs":{}}}},"df":0,"docs":{}}}}}}},"a":{"a":{"6":{"4":{".":{"df":0,"docs":{},"e":{"df":0,"docs":{},"f":{"df":0,"docs":{},"i":{"df":1,"docs":{"35":{"tf":1.0}}}}}},"df":0,"docs":{}},"df":0,"docs":{}},"df":0,"docs":{}},"b":{"df":0,"docs":{},"l":{"df":1,"docs":{"35":{"tf":1.0}}}},"df":0,"docs":{},"r":{"df":0,"docs":{},"m":{".":{"df":0,"docs":{},"e":{"df":0,"docs":{},"f":{"df":0,"docs":{},"i":{"df":1,"docs":{"35":{"tf":1.0}}}}}},"df":0,"docs":{}}}},"df":11,"docs":{"15":{"tf":1.0},"16":{"tf":1.4142135623730951},"17":{"tf":2.0},"23":{"tf":1.0},"25":{"tf":2.6457513110645907},"26":{"tf":1.4142135623730951},"28":{"tf":1.0},"30":{"tf":1.0},"33":{"tf":1.7320508075688772},"34":{"tf":1.0},"35":{"tf":2.0}},"i":{"a":{"3":{"2":{".":{"df":0,"docs":{},"e":{"df":0,"docs":{},"f":{"df":0,"docs":{},"i":{"df":1,"docs":{"35":{"tf":1.0}}}}}},"df":0,"docs":{}},"df":0,"docs":{}},"6":{"4":{".":{"df":0,"docs":{},"e":{"df":0,"docs":{},"f":{"df":0,"docs":{},"i":{"df":1,"docs":{"35":{"tf":1.0}}}}}},"df":0,"docs":{}},"df":0,"docs":{}},"df":0,"docs":{}},"df":0,"docs":{}},"l":{"df":0,"docs":{},"o":{"a":{"d":{"df":1,"docs":{"25":{"tf":1.0}}},"df":0,"docs":{}},"df":0,"docs":{}}},"r":{"df":0,"docs":{},"i":{"df":0,"docs":{},"s":{"c":{"df":0,"docs":{},"v":{"1":{"2":{"8":{".":{"df":0,"docs":{},"e":{"df":0,"docs":{},"f":{"df":0,"docs":{},"i":{"df":1,"docs":{"35":{"tf":1.0}}}}}},"df":0,"docs":{}},"df":0,"docs":{}},"df":0,"docs":{}},"3":{"2":{".":{"df":0,"docs":{},"e":{"df":0,"docs":{},"f":{"df":0,"docs":{},"i":{"df":1,"docs":{"35":{"tf":1.0}}}}}},"df":0,"docs":{}},"df":0,"docs":{}},"6":{"4":{".":{"df":0,"docs":{},"e":{"df":0,"docs":{},"f":{"df":0,"docs":{},"i":{"df":1,"docs":{"35":{"tf":1.0}}}}}},"df":0,"docs":{}},"df":0,"docs":{}},"df":0,"docs":{}}},"df":0,"docs":{}}}},"s":{"df":0,"docs":{},"e":{"df":0,"docs":{},"r":{"df":0,"docs":{},"v":{"df":0,"docs":{},"i":{"c":{"df":5,"docs":{"20":{"tf":1.0},"21":{"tf":1.0},"22":{"tf":1.0},"25":{"tf":1.4142135623730951},"26":{"tf":1.0}},"e":{"_":{"a":{"c":{"c":{"df":0,"docs":{},"e":{"df":0,"docs":{},"s":{"df":0,"docs":{},"s":{"df":1,"docs":{"33":{"tf":1.4142135623730951}}}}}},"df":0,"docs":{}},"df":0,"docs":{}},"df":0,"docs":{}},"df":0,"docs":{},"s":{":":{":":{"df":0,"docs":{},"i":{"df":0,"docs":{},"m":{"a":{"df":0,"docs":{},"g":{"df":0,"docs":{},"e":{"_":{"df":0,"docs":{},"h":{"a":{"df":0,"docs":{},"n":{"d":{"df":0,"docs":{},"l":{"df":1,"docs":{"21":{"tf":1.0}}}},"df":0,"docs":{}}},"df":0,"docs":{}}},"df":0,"docs":{}}}},"df":0,"docs":{}}},"l":{"df":0,"docs":{},"o":{"c":{"a":{"df":0,"docs":{},"t":{"df":0,"docs":{},"e":{"_":{"d":{"df":0,"docs":{},"e":{"df":0,"docs":{},"v":{"df":0,"docs":{},"i":{"c":{"df":0,"docs":{},"e":{"_":{"df":0,"docs":{},"p":{"a":{"df":0,"docs":{},"t":{"df":0,"docs":{},"h":{"df":1,"docs":{"19":{"tf":1.0}}}}},"df":0,"docs":{}}},"df":0,"docs":{}}},"df":0,"docs":{}}}}},"df":0,"docs":{},"h":{"a":{"df":0,"docs":{},"n":{"d":{"df":0,"docs":{},"l":{"df":1,"docs":{"19":{"tf":1.0}},"e":{"_":{"b":{"df":0,"docs":{},"u":{"df":0,"docs":{},"f":{"df":0,"docs":{},"f":{"df":1,"docs":{"19":{"tf":1.0}}}}}},"df":0,"docs":{}},"df":0,"docs":{}}}},"df":0,"docs":{}}},"df":0,"docs":{}}},"df":0,"docs":{}}}},"df":0,"docs":{}},"df":0,"docs":{}}},"o":{"df":0,"docs":{},"p":{"df":0,"docs":{},"e":{"df":0,"docs":{},"n":{"_":{"df":0,"docs":{},"p":{"df":0,"docs":{},"r":{"df":0,"docs":{},"o":{"df":0,"docs":{},"t":{"df":0,"docs":{},"o":{"c":{"df":0,"docs":{},"o":{"df":0,"docs":{},"l":{"_":{"df":0,"docs":{},"e":{"df":0,"docs":{},"x":{"c":{"df":0,"docs":{},"l":{"df":0,"docs":{},"u":{"df":0,"docs":{},"s":{"df":1,"docs":{"19":{"tf":1.4142135623730951}}}}}},"df":0,"docs":{}}}},"df":1,"docs":{"19":{"tf":1.0}}}}},"df":0,"docs":{}}}}}}},"df":0,"docs":{}}}}}},"df":0,"docs":{}},"df":0,"docs":{}}}},"df":0,"docs":{}}}}}},"x":{"6":{"4":{".":{"df":0,"docs":{},"e":{"df":0,"docs":{},"f":{"df":0,"docs":{},"i":{"df":2,"docs":{"15":{"tf":1.0},"35":{"tf":1.0}}}}}},"df":0,"docs":{}},"df":0,"docs":{}},"df":0,"docs":{}}}},"r":{"d":{"df":0,"docs":{},"e":{"df":0,"docs":{},"r":{"df":1,"docs":{"22":{"tf":2.23606797749979}}}}},"df":0,"docs":{}},"t":{"df":0,"docs":{},"h":{"df":4,"docs":{"21":{"tf":1.4142135623730951},"25":{"tf":1.0},"26":{"tf":1.0},"33":{"tf":1.0}}}}},"t":{".":{"df":0,"docs":{},"g":{"df":0,"docs":{},"e":{"df":0,"docs":{},"t":{"_":{"df":0,"docs":{},"h":{"a":{"df":0,"docs":{},"n":{"d":{"df":0,"docs":{},"l":{"df":0,"docs":{},"e":{"_":{"df":0,"docs":{},"f":{"df":0,"docs":{},"o":{"df":0,"docs":{},"r":{"_":{"df":0,"docs":{},"p":{"df":0,"docs":{},"r":{"df":0,"docs":{},"o":{"df":0,"docs":{},"t":{"df":0,"docs":{},"o":{"c":{"df":0,"docs":{},"o":{"df":0,"docs":{},"l":{":":{":":{"<":{"df":0,"docs":{},"g":{"df":0,"docs":{},"r":{"a":{"df":0,"docs":{},"p":{"df":0,"docs":{},"h":{"df":0,"docs":{},"i":{"c":{"df":0,"docs":{},"s":{"df":0,"docs":{},"o":{"df":0,"docs":{},"u":{"df":0,"docs":{},"t":{"df":0,"docs":{},"p":{"df":0,"docs":{},"u":{"df":0,"docs":{},"t":{"df":1,"docs":{"22":{"tf":1.0}}}}}}}}}},"df":0,"docs":{}}}}},"df":0,"docs":{}}},"r":{"df":0,"docs":{},"n":{"df":0,"docs":{},"g":{"df":1,"docs":{"22":{"tf":1.0}}}}}},"df":0,"docs":{}},"df":0,"docs":{}},"df":0,"docs":{}}}},"df":0,"docs":{}}}}}}},"df":0,"docs":{}}}}},"df":0,"docs":{}}}},"df":0,"docs":{}}},"df":0,"docs":{}}},"df":0,"docs":{}}}},"o":{"df":0,"docs":{},"p":{"df":0,"docs":{},"e":{"df":0,"docs":{},"n":{"_":{"df":0,"docs":{},"p":{"df":0,"docs":{},"r":{"df":0,"docs":{},"o":{"df":0,"docs":{},"t":{"df":0,"docs":{},"o":{"c":{"df":0,"docs":{},"o":{"df":0,"docs":{},"l":{"_":{"df":0,"docs":{},"e":{"df":0,"docs":{},"x":{"c":{"df":0,"docs":{},"l":{"df":0,"docs":{},"u":{"df":0,"docs":{},"s":{"df":0,"docs":{},"i":{"df":0,"docs":{},"v":{"df":0,"docs":{},"e":{":":{":":{"<":{"df":0,"docs":{},"g":{"df":0,"docs":{},"r":{"a":{"df":0,"docs":{},"p":{"df":0,"docs":{},"h":{"df":0,"docs":{},"i":{"c":{"df":0,"docs":{},"s":{"df":0,"docs":{},"o":{"df":0,"docs":{},"u":{"df":0,"docs":{},"t":{"df":0,"docs":{},"p":{"df":0,"docs":{},"u":{"df":0,"docs":{},"t":{">":{"(":{"df":0,"docs":{},"g":{"df":0,"docs":{},"o":{"df":0,"docs":{},"p":{"_":{"df":0,"docs":{},"h":{"a":{"df":0,"docs":{},"n":{"d":{"df":0,"docs":{},"l":{"df":1,"docs":{"22":{"tf":1.0}}}},"df":0,"docs":{}}},"df":0,"docs":{}}},"df":0,"docs":{}}}}},"df":0,"docs":{}},"df":0,"docs":{}}}}}}}}},"df":0,"docs":{}}}}},"df":0,"docs":{}}},"r":{"df":0,"docs":{},"n":{"df":0,"docs":{},"g":{">":{"(":{"df":0,"docs":{},"r":{"df":0,"docs":{},"n":{"df":0,"docs":{},"g":{"_":{"df":0,"docs":{},"h":{"a":{"df":0,"docs":{},"n":{"d":{"df":0,"docs":{},"l":{"df":1,"docs":{"22":{"tf":1.0}}}},"df":0,"docs":{}}},"df":0,"docs":{}}},"df":0,"docs":{}}}}},"df":0,"docs":{}},"df":0,"docs":{}}}}},"df":0,"docs":{}},"df":0,"docs":{}},"df":0,"docs":{}}}}}}}},"df":0,"docs":{}}}},"df":0,"docs":{}}}},"df":0,"docs":{}}}}}}},"df":0,"docs":{}}}}}},"df":1,"docs":{"22":{"tf":1.0}}},"u":{"df":0,"docs":{},"f":{")":{".":{"df":0,"docs":{},"e":{"df":0,"docs":{},"x":{"df":0,"docs":{},"p":{"df":0,"docs":{},"e":{"c":{"df":0,"docs":{},"t":{"(":{"\"":{"df":0,"docs":{},"g":{"df":0,"docs":{},"e":{"df":0,"docs":{},"t":{"_":{"df":0,"docs":{},"r":{"df":0,"docs":{},"n":{"df":0,"docs":{},"g":{"df":1,"docs":{"22":{"tf":1.0}}}}}},"df":0,"docs":{}}}}},"df":0,"docs":{}},"df":0,"docs":{}}},"df":0,"docs":{}}}}}},"df":0,"docs":{}},"df":1,"docs":{"22":{"tf":1.0}},"f":{"df":0,"docs":{},"e":{"df":0,"docs":{},"r":{".":{"b":{"df":0,"docs":{},"l":{"df":0,"docs":{},"i":{"df":0,"docs":{},"t":{"(":{"&":{"df":0,"docs":{},"m":{"df":0,"docs":{},"u":{"df":0,"docs":{},"t":{"df":1,"docs":{"22":{"tf":1.0}}}}}},"df":0,"docs":{}},"df":0,"docs":{}}}}},"df":0,"docs":{},"p":{"df":0,"docs":{},"i":{"df":0,"docs":{},"x":{"df":0,"docs":{},"e":{"df":0,"docs":{},"l":{"(":{"df":0,"docs":{},"p":{".":{"df":0,"docs":{},"x":{"df":1,"docs":{"22":{"tf":1.0}}}},"df":0,"docs":{}},"x":{"df":1,"docs":{"22":{"tf":1.0}}}},"df":0,"docs":{}}}}}}},":":{":":{"b":{"df":0,"docs":{},"l":{"df":0,"docs":{},"i":{"df":0,"docs":{},"t":{"df":1,"docs":{"22":{"tf":1.0}}}}}},"df":0,"docs":{},"n":{"df":0,"docs":{},"e":{"df":0,"docs":{},"w":{"(":{"df":0,"docs":{},"w":{"df":0,"docs":{},"i":{"d":{"df":0,"docs":{},"t":{"df":0,"docs":{},"h":{"df":1,"docs":{"22":{"tf":1.0}}}}},"df":0,"docs":{}}}},"df":0,"docs":{}}}}},"df":0,"docs":{}},"df":1,"docs":{"22":{"tf":4.358898943540674}}}}}},"i":{"df":0,"docs":{},"l":{"d":{"df":5,"docs":{"0":{"tf":1.0},"23":{"tf":2.0},"6":{"tf":1.7320508075688772},"7":{"tf":1.0},"8":{"tf":2.23606797749979}}},"df":0,"docs":{}}}},"y":{"df":0,"docs":{},"t":{"df":0,"docs":{},"e":{"df":2,"docs":{"27":{"tf":1.4142135623730951},"32":{"tf":1.0}}}}}},"c":{"1":{"2":{"a":{"7":{"3":{"2":{"8":{"df":2,"docs":{"15":{"tf":1.0},"35":{"tf":1.0}}},"df":0,"docs":{}},"df":0,"docs":{}},"df":0,"docs":{}},"df":0,"docs":{}},"df":0,"docs":{}},"df":0,"docs":{}},"a":{"df":0,"docs":{},"l":{"df":0,"docs":{},"l":{"df":6,"docs":{"21":{"tf":2.0},"22":{"tf":1.0},"25":{"tf":1.0},"26":{"tf":1.4142135623730951},"35":{"tf":1.0},"5":{"tf":1.0}}}},"n":{"'":{"df":0,"docs":{},"t":{"df":2,"docs":{"29":{"tf":1.0},"30":{"tf":1.0}}}},"df":0,"docs":{},"o":{"df":0,"docs":{},"n":{"df":1,"docs":{"24":{"tf":1.0}}}}},"p":{"df":0,"docs":{},"i":{"df":0,"docs":{},"t":{"df":1,"docs":{"15":{"tf":1.0}}}}},"r":{"df":0,"docs":{},"e":{"df":2,"docs":{"16":{"tf":1.0},"33":{"tf":1.0}}},"g":{"df":0,"docs":{},"o":{"/":{"c":{"df":0,"docs":{},"o":{"df":0,"docs":{},"n":{"df":0,"docs":{},"f":{"df":0,"docs":{},"i":{"df":0,"docs":{},"g":{".":{"df":0,"docs":{},"t":{"df":0,"docs":{},"o":{"df":0,"docs":{},"m":{"df":0,"docs":{},"l":{"df":1,"docs":{"23":{"tf":1.0}}}}}}},"df":0,"docs":{}}}}}}},"df":0,"docs":{}},"df":3,"docs":{"22":{"tf":1.0},"4":{"tf":1.4142135623730951},"8":{"tf":1.0}}}}},"s":{"df":0,"docs":{},"e":{"df":5,"docs":{"15":{"tf":1.0},"19":{"tf":1.4142135623730951},"20":{"tf":1.0},"21":{"tf":1.0},"33":{"tf":1.0}}}},"u":{"df":0,"docs":{},"s":{"df":1,"docs":{"33":{"tf":1.0}}}}},"d":{"df":1,"docs":{"4":{"tf":1.0}}},"df":1,"docs":{"23":{"tf":1.0}},"e":{"df":0,"docs":{},"n":{"df":0,"docs":{},"t":{"df":0,"docs":{},"e":{"df":0,"docs":{},"r":{"df":1,"docs":{"22":{"tf":1.0}}}}}}},"h":{"a":{"df":0,"docs":{},"n":{"df":0,"docs":{},"g":{"df":4,"docs":{"22":{"tf":1.0},"23":{"tf":1.0},"33":{"tf":1.0},"4":{"tf":1.0}}}},"o":{"df":1,"docs":{"22":{"tf":1.0}}},"p":{"df":0,"docs":{},"t":{"df":0,"docs":{},"e":{"df":0,"docs":{},"r":{"df":3,"docs":{"18":{"tf":1.0},"24":{"tf":1.0},"30":{"tf":1.0}}}}}}},"df":0,"docs":{},"o":{"df":0,"docs":{},"o":{"df":0,"docs":{},"s":{"df":1,"docs":{"22":{"tf":1.0}}}},"s":{"df":0,"docs":{},"e":{"df":0,"docs":{},"n":{"df":1,"docs":{"22":{"tf":1.0}}}}}}},"l":{"df":0,"docs":{},"e":{"a":{"df":0,"docs":{},"r":{"df":2,"docs":{"16":{"tf":1.0},"34":{"tf":1.0}}}},"df":0,"docs":{}},"o":{"df":0,"docs":{},"s":{"df":0,"docs":{},"e":{"df":1,"docs":{"19":{"tf":1.0}}}}}},"o":{"d":{"df":0,"docs":{},"e":{"df":3,"docs":{"11":{"tf":1.4142135623730951},"22":{"tf":1.4142135623730951},"5":{"tf":1.0}}}},"df":0,"docs":{},"l":{"df":0,"docs":{},"l":{"df":0,"docs":{},"e":{"c":{"df":0,"docs":{},"t":{"df":1,"docs":{"33":{"tf":1.0}}}},"df":0,"docs":{}}}},"m":{"b":{"df":0,"docs":{},"i":{"df":0,"docs":{},"n":{"df":1,"docs":{"21":{"tf":1.0}}}}},"df":0,"docs":{},"m":{"a":{"df":0,"docs":{},"n":{"d":{"df":2,"docs":{"16":{"tf":1.0},"8":{"tf":1.0}}},"df":0,"docs":{}}},"df":0,"docs":{},"o":{"df":0,"docs":{},"n":{"df":0,"docs":{},"l":{"df":0,"docs":{},"i":{"df":2,"docs":{"30":{"tf":1.0},"5":{"tf":1.0}}}}}}},"p":{"df":0,"docs":{},"i":{"df":0,"docs":{},"l":{"df":1,"docs":{"7":{"tf":1.0}}}},"l":{"df":0,"docs":{},"e":{"df":0,"docs":{},"t":{"df":1,"docs":{"5":{"tf":1.0}}},"x":{"df":1,"docs":{"22":{"tf":1.0}}}}},"u":{"df":0,"docs":{},"t":{"df":1,"docs":{"17":{"tf":1.0}}}}}},"n":{"c":{"df":0,"docs":{},"e":{"df":0,"docs":{},"p":{"df":0,"docs":{},"t":{"df":13,"docs":{"0":{"tf":1.0},"24":{"tf":2.0},"25":{"tf":1.0},"26":{"tf":1.0},"27":{"tf":1.0},"28":{"tf":1.0},"29":{"tf":1.0},"30":{"tf":1.0},"31":{"tf":1.0},"32":{"tf":1.0},"33":{"tf":1.0},"34":{"tf":1.0},"35":{"tf":1.0}}}}}},"d":{"df":0,"docs":{},"i":{"df":0,"docs":{},"t":{"df":1,"docs":{"28":{"tf":1.0}}}}},"df":0,"docs":{},"f":{"df":0,"docs":{},"i":{"df":0,"docs":{},"g":{"df":0,"docs":{},"u":{"df":0,"docs":{},"r":{"df":1,"docs":{"35":{"tf":1.0}}}}}},"o":{"df":0,"docs":{},"r":{"df":0,"docs":{},"m":{"df":1,"docs":{"15":{"tf":1.0}}}}}},"s":{"df":0,"docs":{},"i":{"df":0,"docs":{},"s":{"df":0,"docs":{},"t":{"df":2,"docs":{"28":{"tf":1.0},"32":{"tf":1.0}}}}},"o":{"df":0,"docs":{},"l":{"df":1,"docs":{"31":{"tf":1.0}}}},"u":{"df":0,"docs":{},"m":{"df":1,"docs":{"26":{"tf":1.0}}}}},"t":{"a":{"df":0,"docs":{},"i":{"df":0,"docs":{},"n":{"df":6,"docs":{"12":{"tf":1.0},"16":{"tf":1.0},"18":{"tf":1.0},"31":{"tf":1.0},"34":{"tf":1.4142135623730951},"35":{"tf":1.0}}}}},"df":0,"docs":{},"e":{"df":0,"docs":{},"n":{"df":0,"docs":{},"t":{"df":2,"docs":{"24":{"tf":1.0},"4":{"tf":1.0}}}}},"r":{"df":0,"docs":{},"i":{"b":{"df":0,"docs":{},"u":{"df":0,"docs":{},"t":{"df":1,"docs":{"30":{"tf":1.0}}}}},"df":0,"docs":{}}}},"v":{"df":0,"docs":{},"e":{"df":0,"docs":{},"n":{"df":0,"docs":{},"i":{"df":1,"docs":{"21":{"tf":1.0}}}},"r":{"df":0,"docs":{},"t":{"_":{"d":{"df":0,"docs":{},"e":{"df":0,"docs":{},"v":{"df":0,"docs":{},"i":{"c":{"df":0,"docs":{},"e":{"_":{"df":0,"docs":{},"p":{"a":{"df":0,"docs":{},"t":{"df":0,"docs":{},"h":{"_":{"df":0,"docs":{},"t":{"df":0,"docs":{},"o":{"_":{"df":0,"docs":{},"t":{"df":0,"docs":{},"e":{"df":0,"docs":{},"x":{"df":0,"docs":{},"t":{"df":2,"docs":{"20":{"tf":1.0},"21":{"tf":1.0}}}}}}},"df":0,"docs":{}}}},"df":0,"docs":{}}}},"df":0,"docs":{}}},"df":0,"docs":{}}},"df":0,"docs":{}}}}},"df":0,"docs":{}},"df":2,"docs":{"21":{"tf":1.0},"31":{"tf":1.0}}}}}}},"p":{"df":0,"docs":{},"i":{"df":5,"docs":{"11":{"tf":1.4142135623730951},"15":{"tf":1.0},"16":{"tf":1.0},"22":{"tf":1.4142135623730951},"34":{"tf":1.0}}}},"r":{"df":0,"docs":{},"e":{":":{":":{"df":0,"docs":{},"m":{"df":0,"docs":{},"e":{"df":0,"docs":{},"m":{"df":1,"docs":{"22":{"tf":1.0}}}}}},"df":0,"docs":{}},"df":3,"docs":{"22":{"tf":1.0},"28":{"tf":1.0},"5":{"tf":1.0}}}},"u":{"df":0,"docs":{},"p":{"df":0,"docs":{},"l":{"df":2,"docs":{"20":{"tf":1.0},"34":{"tf":1.0}}}}},"v":{"df":0,"docs":{},"e":{"df":0,"docs":{},"r":{"df":1,"docs":{"30":{"tf":1.0}}}}}},"p":{"df":3,"docs":{"11":{"tf":1.4142135623730951},"12":{"tf":1.0},"16":{"tf":1.0}}},"r":{"a":{"df":0,"docs":{},"t":{"df":0,"docs":{},"e":{"df":3,"docs":{"22":{"tf":1.4142135623730951},"36":{"tf":2.0},"5":{"tf":2.0}}}}},"df":0,"docs":{},"e":{"a":{"df":0,"docs":{},"t":{"df":10,"docs":{"1":{"tf":1.0},"12":{"tf":1.0},"13":{"tf":1.0},"15":{"tf":1.4142135623730951},"16":{"tf":1.7320508075688772},"2":{"tf":1.7320508075688772},"22":{"tf":1.7320508075688772},"3":{"tf":1.0},"4":{"tf":2.0},"5":{"tf":1.0}}}},"df":0,"docs":{}},"i":{"df":0,"docs":{},"t":{"df":0,"docs":{},"i":{"c":{"df":1,"docs":{"24":{"tf":1.0}}},"df":0,"docs":{}}}}},"u":{"df":0,"docs":{},"l":{"df":0,"docs":{},"m":{"df":0,"docs":{},"i":{"df":0,"docs":{},"n":{"df":1,"docs":{"25":{"tf":1.0}}}}}},"r":{"df":0,"docs":{},"r":{"df":0,"docs":{},"e":{"df":0,"docs":{},"n":{"df":0,"docs":{},"t":{"df":5,"docs":{"20":{"tf":1.0},"21":{"tf":1.0},"24":{"tf":1.0},"5":{"tf":1.0},"7":{"tf":1.0}}}}}}}},"y":{"c":{"df":0,"docs":{},"l":{"df":1,"docs":{"33":{"tf":1.0}}}},"df":0,"docs":{}}},"d":{"a":{"df":0,"docs":{},"t":{"a":{"df":5,"docs":{"16":{"tf":1.0},"21":{"tf":1.4142135623730951},"31":{"tf":1.0},"32":{"tf":1.0},"34":{"tf":1.0}}},"df":0,"docs":{}}},"df":0,"docs":{},"e":{"a":{"df":0,"docs":{},"l":{"df":1,"docs":{"33":{"tf":1.0}}}},"b":{"df":0,"docs":{},"i":{"a":{"df":0,"docs":{},"n":{"/":{"df":0,"docs":{},"u":{"b":{"df":0,"docs":{},"u":{"df":0,"docs":{},"n":{"df":0,"docs":{},"t":{"df":0,"docs":{},"u":{"df":1,"docs":{"10":{"tf":1.0}}}}}}},"df":0,"docs":{}}},"df":1,"docs":{"11":{"tf":1.0}}}},"df":0,"docs":{}}},"df":0,"docs":{},"f":{"a":{"df":0,"docs":{},"u":{"df":0,"docs":{},"l":{"df":0,"docs":{},"t":{"df":3,"docs":{"21":{"tf":1.0},"23":{"tf":1.0},"35":{"tf":1.0}}}}}},"df":0,"docs":{},"i":{"df":0,"docs":{},"n":{"df":4,"docs":{"22":{"tf":1.0},"30":{"tf":1.0},"34":{"tf":1.0},"5":{"tf":1.0}}}}},"l":{"df":0,"docs":{},"e":{"df":0,"docs":{},"t":{"df":1,"docs":{"33":{"tf":1.0}}}},"l":{"df":1,"docs":{"17":{"tf":1.0}}}},"p":{"df":0,"docs":{},"e":{"df":0,"docs":{},"n":{"d":{"df":6,"docs":{"10":{"tf":2.0},"11":{"tf":1.0},"15":{"tf":1.0},"17":{"tf":1.0},"3":{"tf":1.4142135623730951},"4":{"tf":1.0}}},"df":0,"docs":{}}}},"r":{"df":0,"docs":{},"i":{"df":0,"docs":{},"v":{"df":0,"docs":{},"e":{"(":{"c":{"df":0,"docs":{},"l":{"df":0,"docs":{},"o":{"df":0,"docs":{},"n":{"df":1,"docs":{"22":{"tf":1.0}}}}}},"df":0,"docs":{}},"df":0,"docs":{}}}}},"s":{"c":{"df":0,"docs":{},"r":{"df":0,"docs":{},"i":{"b":{"df":5,"docs":{"0":{"tf":1.0},"1":{"tf":1.0},"25":{"tf":1.0},"31":{"tf":1.0},"34":{"tf":1.0}}},"df":0,"docs":{}}}},"df":0,"docs":{},"t":{"df":1,"docs":{"22":{"tf":1.4142135623730951}},"r":{"df":0,"docs":{},"u":{"c":{"df":0,"docs":{},"t":{"df":1,"docs":{"16":{"tf":1.0}}}},"df":0,"docs":{}}}}},"t":{"a":{"df":0,"docs":{},"i":{"df":0,"docs":{},"l":{"df":8,"docs":{"10":{"tf":1.0},"11":{"tf":1.0},"15":{"tf":1.0},"20":{"tf":1.0},"27":{"tf":1.0},"30":{"tf":1.0},"31":{"tf":1.4142135623730951},"33":{"tf":1.0}}}}},"df":0,"docs":{}},"v":{"df":0,"docs":{},"i":{"c":{"df":4,"docs":{"19":{"tf":1.0},"29":{"tf":1.4142135623730951},"30":{"tf":1.0},"31":{"tf":3.1622776601683795}},"e":{"_":{"df":0,"docs":{},"p":{"a":{"df":0,"docs":{},"t":{"df":0,"docs":{},"h":{"_":{"df":0,"docs":{},"t":{"df":0,"docs":{},"o":{"_":{"df":0,"docs":{},"t":{"df":0,"docs":{},"e":{"df":0,"docs":{},"x":{"df":0,"docs":{},"t":{"_":{"df":0,"docs":{},"h":{"a":{"df":0,"docs":{},"n":{"d":{"df":0,"docs":{},"l":{"df":2,"docs":{"20":{"tf":1.4142135623730951},"21":{"tf":1.7320508075688772}}}},"df":0,"docs":{}}},"df":0,"docs":{}}},"df":2,"docs":{"20":{"tf":1.4142135623730951},"21":{"tf":1.4142135623730951}}}}}}},"df":0,"docs":{}}}},"df":0,"docs":{}}}},"df":0,"docs":{}}},"df":0,"docs":{},"p":{"a":{"df":0,"docs":{},"t":{"df":0,"docs":{},"h":{"df":0,"docs":{},"t":{"df":0,"docs":{},"o":{"df":0,"docs":{},"t":{"df":0,"docs":{},"e":{"df":0,"docs":{},"x":{"df":0,"docs":{},"t":{"df":2,"docs":{"20":{"tf":1.4142135623730951},"21":{"tf":1.7320508075688772}}}}}}}}}}},"df":0,"docs":{}}}},"df":0,"docs":{}}}},"i":{"df":0,"docs":{},"f":{"df":0,"docs":{},"f":{"df":0,"docs":{},"e":{"df":0,"docs":{},"r":{"df":5,"docs":{"20":{"tf":1.0},"21":{"tf":1.0},"32":{"tf":1.0},"35":{"tf":1.0},"5":{"tf":1.7320508075688772}}}}}},"m":{"df":1,"docs":{"22":{"tf":1.4142135623730951}}},"r":{"df":0,"docs":{},"e":{"c":{"df":0,"docs":{},"t":{"df":0,"docs":{},"l":{"df":0,"docs":{},"i":{"df":1,"docs":{"29":{"tf":1.0}}}},"o":{"df":0,"docs":{},"r":{"df":0,"docs":{},"i":{"df":6,"docs":{"11":{"tf":1.4142135623730951},"12":{"tf":1.0},"13":{"tf":1.0},"15":{"tf":1.4142135623730951},"16":{"tf":1.0},"4":{"tf":1.0}}}}}}},"df":0,"docs":{}}},"s":{"c":{"a":{"df":0,"docs":{},"r":{"d":{"df":1,"docs":{"21":{"tf":1.0}}},"df":0,"docs":{}}},"df":0,"docs":{}},"df":0,"docs":{},"k":{"df":5,"docs":{"16":{"tf":1.0},"27":{"tf":1.0},"29":{"tf":1.0},"31":{"tf":1.0},"34":{"tf":2.0}}},"p":{"df":0,"docs":{},"l":{"a":{"df":0,"docs":{},"y":{"df":0,"docs":{},"o":{"df":0,"docs":{},"n":{"df":0,"docs":{},"l":{"df":0,"docs":{},"i":{"df":1,"docs":{"20":{"tf":1.0}}},"y":{"(":{"df":0,"docs":{},"t":{"df":0,"docs":{},"r":{"df":0,"docs":{},"u":{"df":2,"docs":{"20":{"tf":1.0},"21":{"tf":1.0}}}}}},"df":0,"docs":{}}}}}}},"df":0,"docs":{}}},"t":{"df":0,"docs":{},"i":{"df":0,"docs":{},"n":{"c":{"df":0,"docs":{},"t":{"df":1,"docs":{"25":{"tf":1.0}}}},"df":0,"docs":{}}}}},"v":{"df":0,"docs":{},"e":{"df":0,"docs":{},"r":{"df":0,"docs":{},"s":{"df":1,"docs":{"30":{"tf":1.0}}}}}}},"n":{"df":0,"docs":{},"f":{"df":1,"docs":{"10":{"tf":1.0}}}},"o":{"c":{"df":0,"docs":{},"u":{"df":0,"docs":{},"m":{"df":0,"docs":{},"e":{"df":0,"docs":{},"n":{"df":0,"docs":{},"t":{"df":4,"docs":{"11":{"tf":1.0},"21":{"tf":1.0},"24":{"tf":1.0},"31":{"tf":1.0}}}}}}}},"df":1,"docs":{"5":{"tf":1.0}},"e":{"df":0,"docs":{},"s":{"df":0,"docs":{},"n":{"'":{"df":0,"docs":{},"t":{"df":1,"docs":{"15":{"tf":1.0}}}},"df":0,"docs":{}}}},"n":{"'":{"df":0,"docs":{},"t":{"df":2,"docs":{"32":{"tf":1.0},"7":{"tf":1.0}}}},"df":0,"docs":{}},"w":{"df":0,"docs":{},"n":{"df":1,"docs":{"17":{"tf":1.0}}}}},"r":{"a":{"df":0,"docs":{},"w":{"_":{"df":0,"docs":{},"s":{"df":0,"docs":{},"i":{"df":0,"docs":{},"e":{"df":0,"docs":{},"r":{"df":0,"docs":{},"p":{"df":0,"docs":{},"i":{"df":0,"docs":{},"n":{"df":0,"docs":{},"s":{"df":0,"docs":{},"k":{"df":0,"docs":{},"i":{"(":{"b":{"df":0,"docs":{},"t":{")":{".":{"df":0,"docs":{},"u":{"df":0,"docs":{},"n":{"df":0,"docs":{},"w":{"df":0,"docs":{},"r":{"a":{"df":0,"docs":{},"p":{"df":1,"docs":{"22":{"tf":1.0}}}},"df":0,"docs":{}}}}}},"df":0,"docs":{}},"df":1,"docs":{"22":{"tf":1.0}}}},"df":0,"docs":{}},"df":0,"docs":{}}}}}}}}}}}},"df":1,"docs":{"22":{"tf":3.0}}}},"df":0,"docs":{},"i":{"df":0,"docs":{},"v":{"df":0,"docs":{},"e":{"df":5,"docs":{"13":{"tf":1.7320508075688772},"14":{"tf":1.0},"15":{"tf":1.4142135623730951},"17":{"tf":1.0},"29":{"tf":1.0}},"r":{"df":3,"docs":{"23":{"tf":2.23606797749979},"25":{"tf":1.0},"28":{"tf":1.0}}}}}},"o":{"df":0,"docs":{},"p":{"df":1,"docs":{"19":{"tf":1.0}}}}},"u":{"df":0,"docs":{},"e":{"df":1,"docs":{"33":{"tf":1.0}}},"r":{"df":0,"docs":{},"e":{"df":4,"docs":{"25":{"tf":1.0},"26":{"tf":1.0},"30":{"tf":1.4142135623730951},"33":{"tf":1.0}}}}}},"df":0,"docs":{},"e":{"a":{"c":{"df":0,"docs":{},"h":{"df":6,"docs":{"21":{"tf":1.4142135623730951},"22":{"tf":1.4142135623730951},"32":{"tf":1.4142135623730951},"33":{"tf":1.0},"34":{"tf":1.0},"5":{"tf":1.0}}}},"df":0,"docs":{},"r":{"df":0,"docs":{},"l":{"df":0,"docs":{},"i":{"df":1,"docs":{"25":{"tf":1.0}}}}},"s":{"df":1,"docs":{"11":{"tf":1.0}},"i":{"df":0,"docs":{},"e":{"df":0,"docs":{},"s":{"df":0,"docs":{},"t":{"df":1,"docs":{"7":{"tf":1.0}}}}}}}},"d":{"df":0,"docs":{},"k":{"2":{"df":1,"docs":{"10":{"tf":1.0}}},"df":0,"docs":{}}},"df":0,"docs":{},"f":{"df":0,"docs":{},"f":{"df":0,"docs":{},"i":{"c":{"df":0,"docs":{},"i":{"df":1,"docs":{"22":{"tf":1.0}}}},"df":0,"docs":{}}},"i":{"/":{"b":{"df":0,"docs":{},"o":{"df":0,"docs":{},"o":{"df":0,"docs":{},"t":{"df":1,"docs":{"15":{"tf":1.4142135623730951}}}}}},"df":0,"docs":{}},"\\":{"b":{"df":0,"docs":{},"o":{"df":0,"docs":{},"o":{"df":0,"docs":{},"t":{"\\":{"b":{"df":0,"docs":{},"o":{"df":0,"docs":{},"o":{"df":0,"docs":{},"t":{"df":0,"docs":{},"x":{"6":{"4":{".":{"df":0,"docs":{},"e":{"df":0,"docs":{},"f":{"df":0,"docs":{},"i":{"df":1,"docs":{"20":{"tf":1.0}}}}}},"df":0,"docs":{}},"df":0,"docs":{}},"df":0,"docs":{}}}}}},"df":0,"docs":{}},"df":1,"docs":{"35":{"tf":1.0}}}}}},"df":0,"docs":{}},"_":{"b":{"df":0,"docs":{},"o":{"df":0,"docs":{},"o":{"df":0,"docs":{},"t":{"_":{"df":0,"docs":{},"s":{"df":0,"docs":{},"e":{"df":0,"docs":{},"r":{"df":0,"docs":{},"v":{"df":0,"docs":{},"i":{"c":{"df":1,"docs":{"26":{"tf":1.0}},"e":{"_":{"d":{"df":0,"docs":{},"r":{"df":0,"docs":{},"i":{"df":0,"docs":{},"v":{"df":1,"docs":{"23":{"tf":1.0}}}}}},"df":0,"docs":{}},"df":0,"docs":{}}},"df":0,"docs":{}}}}}}},"df":0,"docs":{}}}}},"df":0,"docs":{},"r":{"df":0,"docs":{},"u":{"df":0,"docs":{},"n":{"df":0,"docs":{},"t":{"df":0,"docs":{},"i":{"df":0,"docs":{},"m":{"df":0,"docs":{},"e":{"_":{"d":{"df":0,"docs":{},"r":{"df":0,"docs":{},"i":{"df":0,"docs":{},"v":{"df":1,"docs":{"23":{"tf":1.0}}}}}},"df":0,"docs":{},"s":{"df":0,"docs":{},"e":{"df":0,"docs":{},"r":{"df":0,"docs":{},"v":{"df":0,"docs":{},"i":{"c":{"df":1,"docs":{"26":{"tf":1.0}}},"df":0,"docs":{}}}}}}},"df":0,"docs":{}}}}}}}},"s":{"df":0,"docs":{},"y":{"df":0,"docs":{},"s":{"df":0,"docs":{},"t":{"df":0,"docs":{},"e":{"df":0,"docs":{},"m":{"_":{"df":0,"docs":{},"t":{"df":1,"docs":{"26":{"tf":1.0}}}},"df":0,"docs":{}}}}}}}},"df":3,"docs":{"15":{"tf":1.7320508075688772},"16":{"tf":1.0},"35":{"tf":1.0}}}},"m":{"b":{"df":0,"docs":{},"e":{"d":{"df":1,"docs":{"22":{"tf":1.0}}},"df":0,"docs":{}}},"df":0,"docs":{},"p":{"df":0,"docs":{},"t":{"df":0,"docs":{},"i":{"df":1,"docs":{"4":{"tf":1.0}}}}}},"n":{"a":{"b":{"df":0,"docs":{},"l":{"df":1,"docs":{"13":{"tf":1.0}}}},"df":0,"docs":{}},"c":{"df":0,"docs":{},"o":{"d":{"df":1,"docs":{"31":{"tf":1.0}}},"df":0,"docs":{}}},"d":{"df":2,"docs":{"25":{"tf":1.0},"34":{"tf":1.0}},"i":{"a":{"df":0,"docs":{},"n":{"df":1,"docs":{"27":{"tf":1.0}}}},"df":0,"docs":{}}},"df":0,"docs":{},"o":{"df":0,"docs":{},"u":{"df":0,"docs":{},"g":{"df":0,"docs":{},"h":{"df":1,"docs":{"5":{"tf":1.0}}}}}},"s":{"df":0,"docs":{},"u":{"df":0,"docs":{},"r":{"df":1,"docs":{"5":{"tf":1.0}}}}},"t":{"df":0,"docs":{},"e":{"df":0,"docs":{},"r":{"df":1,"docs":{"17":{"tf":1.0}}}},"r":{"df":0,"docs":{},"i":{"df":6,"docs":{"20":{"tf":1.0},"22":{"tf":1.0},"26":{"tf":1.0},"34":{"tf":2.0},"4":{"tf":1.0},"5":{"tf":1.4142135623730951}}}}}},"r":{"df":0,"docs":{},"r":{"df":0,"docs":{},"o":{"df":0,"docs":{},"r":{"df":2,"docs":{"21":{"tf":1.4142135623730951},"5":{"tf":1.0}}}}}},"s":{"df":0,"docs":{},"p":{"/":{"df":0,"docs":{},"e":{"df":0,"docs":{},"f":{"df":0,"docs":{},"i":{"/":{"b":{"df":0,"docs":{},"o":{"df":0,"docs":{},"o":{"df":0,"docs":{},"t":{"/":{"b":{"df":0,"docs":{},"o":{"df":0,"docs":{},"o":{"df":0,"docs":{},"t":{"df":0,"docs":{},"x":{"6":{"4":{".":{"df":0,"docs":{},"e":{"df":0,"docs":{},"f":{"df":0,"docs":{},"i":{"df":2,"docs":{"12":{"tf":1.0},"16":{"tf":1.0}}}}}},"df":0,"docs":{}},"df":0,"docs":{}},"df":0,"docs":{}}}}}},"df":0,"docs":{}},"df":2,"docs":{"12":{"tf":1.0},"16":{"tf":1.0}}}}}},"df":0,"docs":{}},"df":0,"docs":{}}}}},"df":4,"docs":{"13":{"tf":1.0},"15":{"tf":1.0},"16":{"tf":1.4142135623730951},"35":{"tf":1.0}}},"s":{"df":0,"docs":{},"e":{"df":0,"docs":{},"n":{"df":0,"docs":{},"t":{"df":0,"docs":{},"i":{"df":2,"docs":{"31":{"tf":1.0},"5":{"tf":1.0}}}}}}}},"v":{"df":0,"docs":{},"e":{"df":0,"docs":{},"n":{"df":1,"docs":{"33":{"tf":1.0}}},"r":{"df":0,"docs":{},"y":{"df":0,"docs":{},"t":{"df":0,"docs":{},"h":{"df":1,"docs":{"5":{"tf":1.0}}}}}}}},"x":{"a":{"c":{"df":0,"docs":{},"t":{"df":0,"docs":{},"l":{"df":0,"docs":{},"i":{"df":1,"docs":{"15":{"tf":1.0}}}}}},"df":0,"docs":{},"m":{"df":0,"docs":{},"p":{"df":0,"docs":{},"l":{"df":8,"docs":{"15":{"tf":1.0},"16":{"tf":1.4142135623730951},"17":{"tf":1.0},"20":{"tf":1.7320508075688772},"21":{"tf":1.4142135623730951},"22":{"tf":2.0},"23":{"tf":1.0},"30":{"tf":1.0}},"e":{".":{"df":0,"docs":{},"r":{"df":0,"docs":{},"s":{"@":{"0":{"5":{"8":{"df":1,"docs":{"20":{"tf":1.0}}},"df":0,"docs":{}},"df":0,"docs":{}},"df":0,"docs":{}},"df":0,"docs":{}}}},"df":0,"docs":{}}}}}},"c":{"df":0,"docs":{},"i":{"df":0,"docs":{},"t":{"df":1,"docs":{"5":{"tf":1.0}}}},"l":{"df":0,"docs":{},"u":{"df":0,"docs":{},"s":{"df":1,"docs":{"19":{"tf":1.0}}}}}},"df":0,"docs":{},"e":{"c":{"df":0,"docs":{},"u":{"df":0,"docs":{},"t":{"a":{"b":{"df":0,"docs":{},"l":{"df":0,"docs":{},"e":{".":{"df":0,"docs":{},"e":{"df":0,"docs":{},"f":{"df":0,"docs":{},"i":{"df":1,"docs":{"16":{"tf":1.0}}}}}},"df":0,"docs":{}}}},"df":0,"docs":{}},"df":8,"docs":{"11":{"tf":1.0},"12":{"tf":1.0},"16":{"tf":1.0},"20":{"tf":1.0},"26":{"tf":1.0},"29":{"tf":1.0},"5":{"tf":1.0},"8":{"tf":1.0}}}}},"df":0,"docs":{}},"i":{"df":0,"docs":{},"s":{"df":0,"docs":{},"t":{"df":1,"docs":{"35":{"tf":1.0}}}},"t":{"df":2,"docs":{"1":{"tf":1.0},"33":{"tf":1.0}}}},"p":{"df":0,"docs":{},"e":{"c":{"df":0,"docs":{},"t":{"(":{"\"":{"c":{"df":0,"docs":{},"o":{"df":0,"docs":{},"n":{"df":0,"docs":{},"v":{"df":0,"docs":{},"e":{"df":0,"docs":{},"r":{"df":0,"docs":{},"t":{"_":{"d":{"df":0,"docs":{},"e":{"df":0,"docs":{},"v":{"df":0,"docs":{},"i":{"c":{"df":0,"docs":{},"e":{"_":{"df":0,"docs":{},"p":{"a":{"df":0,"docs":{},"t":{"df":0,"docs":{},"h":{"_":{"df":0,"docs":{},"t":{"df":0,"docs":{},"o":{"_":{"df":0,"docs":{},"t":{"df":0,"docs":{},"e":{"df":0,"docs":{},"x":{"df":0,"docs":{},"t":{"df":2,"docs":{"20":{"tf":1.0},"21":{"tf":1.0}}}}}}},"df":0,"docs":{}}}},"df":0,"docs":{}}}},"df":0,"docs":{}}},"df":0,"docs":{}}},"df":0,"docs":{}}}}},"df":0,"docs":{}},"df":0,"docs":{}}}}}}}},"d":{"df":0,"docs":{},"e":{"df":0,"docs":{},"v":{"df":0,"docs":{},"i":{"c":{"df":0,"docs":{},"e":{"df":0,"docs":{},"p":{"a":{"df":0,"docs":{},"t":{"df":0,"docs":{},"h":{"df":0,"docs":{},"t":{"df":0,"docs":{},"o":{"df":0,"docs":{},"t":{"df":0,"docs":{},"e":{"df":0,"docs":{},"x":{"df":0,"docs":{},"t":{"df":2,"docs":{"20":{"tf":1.0},"21":{"tf":1.0}}}}}}}}}}},"df":0,"docs":{}}}},"df":0,"docs":{}}}}},"df":0,"docs":{}},"df":0,"docs":{}},"df":0,"docs":{}}},"df":0,"docs":{}},"o":{"df":0,"docs":{},"r":{"df":0,"docs":{},"t":{"df":1,"docs":{"5":{"tf":1.0}}}}}},"t":{"df":0,"docs":{},"e":{"df":0,"docs":{},"n":{"df":0,"docs":{},"s":{"df":2,"docs":{"26":{"tf":1.0},"28":{"tf":1.0}}}},"r":{"df":0,"docs":{},"n":{"df":1,"docs":{"22":{"tf":1.0}}}}}}}},"f":{"1":{"2":{"df":1,"docs":{"17":{"tf":1.0}}},"df":0,"docs":{}},"3":{"2":{"df":1,"docs":{"22":{"tf":3.1622776601683795}}},"df":0,"docs":{}},"8":{"1":{"df":0,"docs":{},"f":{"df":3,"docs":{"15":{"tf":1.0},"16":{"tf":1.0},"35":{"tf":1.0}}}},"df":0,"docs":{}},"9":{"df":1,"docs":{"17":{"tf":1.0}}},"a":{"df":0,"docs":{},"i":{"df":0,"docs":{},"l":{"df":3,"docs":{"20":{"tf":1.0},"21":{"tf":1.0},"22":{"tf":1.0}}},"r":{"df":0,"docs":{},"l":{"df":0,"docs":{},"i":{"df":2,"docs":{"26":{"tf":1.0},"32":{"tf":1.0}}}}}},"t":{"df":3,"docs":{"15":{"tf":2.0},"16":{"tf":1.0},"35":{"tf":1.0}}}},"df":0,"docs":{},"e":{"d":{"4":{"df":1,"docs":{"27":{"tf":1.0}}},"df":0,"docs":{},"o":{"df":0,"docs":{},"r":{"a":{"df":2,"docs":{"10":{"tf":1.0},"11":{"tf":1.0}}},"df":0,"docs":{}}}},"df":0,"docs":{},"w":{"df":3,"docs":{"13":{"tf":1.0},"26":{"tf":1.0},"4":{"tf":1.0}}}},"i":{"df":0,"docs":{},"e":{"df":0,"docs":{},"l":{"d":{"df":1,"docs":{"27":{"tf":1.0}}},"df":0,"docs":{}}},"g":{"df":0,"docs":{},"u":{"df":0,"docs":{},"r":{"df":1,"docs":{"33":{"tf":1.0}}}}},"l":{"df":0,"docs":{},"e":{"df":6,"docs":{"11":{"tf":2.8284271247461903},"15":{"tf":2.0},"20":{"tf":1.0},"31":{"tf":1.4142135623730951},"35":{"tf":2.449489742783178},"7":{"tf":1.0}}}},"n":{"a":{"df":0,"docs":{},"l":{"df":1,"docs":{"5":{"tf":1.0}}}},"d":{"df":2,"docs":{"19":{"tf":1.0},"21":{"tf":1.4142135623730951}}},"df":0,"docs":{}},"r":{"df":0,"docs":{},"m":{"df":0,"docs":{},"w":{"a":{"df":0,"docs":{},"r":{"df":2,"docs":{"10":{"tf":1.0},"11":{"tf":1.7320508075688772}}}},"df":0,"docs":{}}},"s":{"df":0,"docs":{},"t":{"df":5,"docs":{"19":{"tf":1.0},"20":{"tf":1.4142135623730951},"21":{"tf":1.7320508075688772},"27":{"tf":1.0},"5":{"tf":1.0}}}}}},"l":{"a":{"df":0,"docs":{},"g":{"df":2,"docs":{"23":{"tf":1.0},"33":{"tf":1.0}}}},"df":0,"docs":{},"e":{"df":0,"docs":{},"x":{"df":0,"docs":{},"i":{"b":{"df":0,"docs":{},"l":{"df":2,"docs":{"31":{"tf":1.0},"32":{"tf":1.0}}}},"df":0,"docs":{}}}}},"n":{"df":6,"docs":{"20":{"tf":1.4142135623730951},"21":{"tf":1.0},"22":{"tf":3.1622776601683795},"26":{"tf":1.0},"4":{"tf":1.0},"5":{"tf":1.0}}},"o":{"c":{"df":0,"docs":{},"u":{"df":1,"docs":{"0":{"tf":1.0}}}},"df":0,"docs":{},"l":{"df":0,"docs":{},"l":{"df":0,"docs":{},"o":{"df":0,"docs":{},"w":{"df":3,"docs":{"22":{"tf":1.0},"3":{"tf":1.0},"34":{"tf":1.0}}}}}},"r":{"df":0,"docs":{},"e":{"df":0,"docs":{},"v":{"df":1,"docs":{"22":{"tf":1.0}}}},"m":{"a":{"df":0,"docs":{},"t":{"=":{"df":0,"docs":{},"r":{"a":{"df":0,"docs":{},"w":{",":{"df":0,"docs":{},"f":{"df":0,"docs":{},"i":{"df":0,"docs":{},"l":{"df":0,"docs":{},"e":{"=":{"df":0,"docs":{},"f":{"a":{"df":0,"docs":{},"t":{":":{"df":0,"docs":{},"r":{"df":0,"docs":{},"w":{":":{"df":0,"docs":{},"e":{"df":0,"docs":{},"s":{"df":0,"docs":{},"p":{"df":1,"docs":{"13":{"tf":1.0}}}}}},"df":0,"docs":{}}}},"df":0,"docs":{}}},"df":0,"docs":{}}},"df":0,"docs":{}}}}}},"df":0,"docs":{}}},"df":0,"docs":{}}},"df":3,"docs":{"15":{"tf":1.0},"16":{"tf":1.0},"27":{"tf":1.4142135623730951}}}},"df":0,"docs":{}}}},"r":{"a":{"c":{"df":0,"docs":{},"t":{"a":{"df":0,"docs":{},"l":{"df":1,"docs":{"22":{"tf":1.0}}}},"df":0,"docs":{}}},"df":0,"docs":{},"m":{"df":0,"docs":{},"e":{"b":{"df":0,"docs":{},"u":{"df":0,"docs":{},"f":{"df":0,"docs":{},"f":{"df":1,"docs":{"22":{"tf":1.4142135623730951}}}}}},"df":1,"docs":{"22":{"tf":1.0}}}}},"df":0,"docs":{}},"u":{"df":0,"docs":{},"l":{"df":0,"docs":{},"l":{"df":2,"docs":{"22":{"tf":1.0},"33":{"tf":1.0}}}},"n":{"c":{"df":0,"docs":{},"t":{"df":0,"docs":{},"i":{"df":0,"docs":{},"o":{"df":0,"docs":{},"n":{"df":4,"docs":{"21":{"tf":1.4142135623730951},"25":{"tf":1.0},"30":{"tf":1.4142135623730951},"5":{"tf":2.0}}}}}}},"df":0,"docs":{}}}},"g":{"a":{"df":0,"docs":{},"m":{"df":0,"docs":{},"e":{"df":1,"docs":{"22":{"tf":1.0}}}},"r":{"b":{"a":{"df":0,"docs":{},"g":{"df":1,"docs":{"33":{"tf":1.0}}}},"df":0,"docs":{}},"df":0,"docs":{},"r":{"df":0,"docs":{},"e":{"df":0,"docs":{},"t":{"'":{"df":1,"docs":{"33":{"tf":1.0}}},"df":0,"docs":{}}}}}},"df":1,"docs":{"22":{"tf":1.4142135623730951}},"e":{"df":0,"docs":{},"n":{"df":0,"docs":{},"e":{"df":0,"docs":{},"r":{"df":3,"docs":{"0":{"tf":1.0},"15":{"tf":1.0},"22":{"tf":1.0}}}}},"t":{"_":{"df":0,"docs":{},"r":{"a":{"df":0,"docs":{},"n":{"d":{"df":0,"docs":{},"o":{"df":0,"docs":{},"m":{"_":{"df":0,"docs":{},"u":{"df":0,"docs":{},"s":{"df":0,"docs":{},"i":{"df":0,"docs":{},"z":{"df":0,"docs":{},"e":{"(":{"df":0,"docs":{},"r":{"df":0,"docs":{},"n":{"df":0,"docs":{},"g":{"df":1,"docs":{"22":{"tf":1.0}}}}}},"df":0,"docs":{}}}}}}},"df":0,"docs":{}}}},"df":0,"docs":{}}},"df":0,"docs":{}}},"df":1,"docs":{"34":{"tf":1.0}}}},"i":{"df":0,"docs":{},"v":{"df":0,"docs":{},"e":{"df":1,"docs":{"21":{"tf":1.0}}}}},"l":{"df":0,"docs":{},"o":{"b":{"a":{"df":0,"docs":{},"l":{"df":1,"docs":{"27":{"tf":1.0}}}},"df":1,"docs":{"5":{"tf":1.0}}},"df":0,"docs":{}}},"o":{"df":0,"docs":{},"e":{"df":1,"docs":{"25":{"tf":1.0}}},"p":{".":{"b":{"df":0,"docs":{},"l":{"df":0,"docs":{},"t":{"(":{"b":{"df":0,"docs":{},"l":{"df":0,"docs":{},"t":{"df":0,"docs":{},"o":{"df":0,"docs":{},"p":{":":{":":{"b":{"df":0,"docs":{},"u":{"df":0,"docs":{},"f":{"df":0,"docs":{},"f":{"df":0,"docs":{},"e":{"df":0,"docs":{},"r":{"df":0,"docs":{},"t":{"df":0,"docs":{},"o":{"df":0,"docs":{},"v":{"df":0,"docs":{},"i":{"d":{"df":0,"docs":{},"e":{"df":0,"docs":{},"o":{"df":1,"docs":{"22":{"tf":1.4142135623730951}}}}},"df":0,"docs":{}}}}}}}}}}},"df":0,"docs":{}},"df":0,"docs":{}},"df":0,"docs":{}}}}}},"df":0,"docs":{}},"df":0,"docs":{}}}},"c":{"df":0,"docs":{},"u":{"df":0,"docs":{},"r":{"df":0,"docs":{},"r":{"df":0,"docs":{},"e":{"df":0,"docs":{},"n":{"df":0,"docs":{},"t":{"_":{"df":0,"docs":{},"m":{"df":0,"docs":{},"o":{"d":{"df":0,"docs":{},"e":{"_":{"df":0,"docs":{},"i":{"df":0,"docs":{},"n":{"df":0,"docs":{},"f":{"df":0,"docs":{},"o":{"(":{")":{".":{"df":0,"docs":{},"r":{"df":0,"docs":{},"e":{"df":0,"docs":{},"s":{"df":0,"docs":{},"o":{"df":0,"docs":{},"l":{"df":0,"docs":{},"u":{"df":0,"docs":{},"t":{"df":1,"docs":{"22":{"tf":1.0}}}}}}}}}},"df":0,"docs":{}},"df":0,"docs":{}},"df":0,"docs":{}}}}}},"df":0,"docs":{}}},"df":0,"docs":{}}}},"df":0,"docs":{}}}}}}}},"df":0,"docs":{}},"_":{"df":0,"docs":{},"h":{"a":{"df":0,"docs":{},"n":{"d":{"df":0,"docs":{},"l":{"df":1,"docs":{"22":{"tf":1.0}}}},"df":0,"docs":{}}},"df":0,"docs":{}}},"df":1,"docs":{"22":{"tf":2.0}}}},"p":{"df":0,"docs":{},"t":{"df":4,"docs":{"15":{"tf":1.4142135623730951},"16":{"tf":1.0},"34":{"tf":2.449489742783178},"35":{"tf":1.0}}}},"r":{"a":{"d":{"df":0,"docs":{},"i":{"df":0,"docs":{},"e":{"df":0,"docs":{},"n":{"df":0,"docs":{},"t":{"df":1,"docs":{"22":{"tf":1.0}}}}}}},"df":0,"docs":{},"p":{"df":0,"docs":{},"h":{"df":0,"docs":{},"i":{"c":{"df":1,"docs":{"22":{"tf":2.23606797749979}},"s":{"df":0,"docs":{},"o":{"df":0,"docs":{},"u":{"df":0,"docs":{},"t":{"df":0,"docs":{},"p":{"df":0,"docs":{},"u":{"df":0,"docs":{},"t":{"df":1,"docs":{"22":{"tf":1.7320508075688772}}}}}}}}}},"df":0,"docs":{}}}}},"df":0,"docs":{},"e":{"df":0,"docs":{},"e":{"df":0,"docs":{},"n":{"df":1,"docs":{"22":{"tf":1.0}}}}},"o":{"df":0,"docs":{},"u":{"df":0,"docs":{},"p":{"df":1,"docs":{"27":{"tf":1.0}}}}}},"u":{"df":0,"docs":{},"i":{"d":{"df":5,"docs":{"15":{"tf":1.7320508075688772},"18":{"tf":1.0},"27":{"tf":3.3166247903554},"32":{"tf":1.4142135623730951},"34":{"tf":1.7320508075688772}}},"df":0,"docs":{}}}},"h":{"a":{"df":0,"docs":{},"l":{"df":0,"docs":{},"f":{"df":0,"docs":{},"w":{"a":{"df":0,"docs":{},"y":{"df":1,"docs":{"22":{"tf":1.0}}}},"df":0,"docs":{}}}},"n":{"d":{"df":0,"docs":{},"l":{"df":11,"docs":{"19":{"tf":3.1622776601683795},"20":{"tf":1.0},"21":{"tf":2.449489742783178},"22":{"tf":1.0},"26":{"tf":1.0},"28":{"tf":2.0},"29":{"tf":2.449489742783178},"30":{"tf":1.0},"31":{"tf":1.4142135623730951},"4":{"tf":1.0},"5":{"tf":1.7320508075688772}},"e":{"df":0,"docs":{},"r":{"df":1,"docs":{"5":{"tf":1.0}}}}}},"df":0,"docs":{}},"p":{"df":0,"docs":{},"p":{"df":0,"docs":{},"e":{"df":0,"docs":{},"n":{"df":1,"docs":{"32":{"tf":1.0}}}}}},"r":{"d":{"df":0,"docs":{},"w":{"a":{"df":0,"docs":{},"r":{"df":5,"docs":{"14":{"tf":2.0},"15":{"tf":1.0},"16":{"tf":1.0},"17":{"tf":1.0},"28":{"tf":1.0}}}},"df":0,"docs":{}}},"df":0,"docs":{}}},"df":0,"docs":{},"e":{"a":{"d":{"df":0,"docs":{},"e":{"df":0,"docs":{},"r":{"df":1,"docs":{"34":{"tf":1.4142135623730951}}}}},"df":0,"docs":{}},"df":0,"docs":{},"i":{"df":0,"docs":{},"g":{"df":0,"docs":{},"h":{"df":0,"docs":{},"t":{"df":1,"docs":{"22":{"tf":3.4641016151377544}}}}}},"l":{"df":0,"docs":{},"l":{"df":0,"docs":{},"o":{"df":4,"docs":{"1":{"tf":1.0},"13":{"tf":1.0},"21":{"tf":1.0},"5":{"tf":1.0}}}}},"r":{"df":0,"docs":{},"e":{"'":{"df":2,"docs":{"20":{"tf":1.0},"22":{"tf":1.0}}},"df":4,"docs":{"21":{"tf":1.0},"22":{"tf":1.0},"5":{"tf":1.4142135623730951},"7":{"tf":1.0}}}}},"o":{"df":0,"docs":{},"l":{"d":{"df":1,"docs":{"17":{"tf":1.0}}},"df":0,"docs":{}}},"p":{"df":1,"docs":{"17":{"tf":1.0}}},"u":{"df":0,"docs":{},"g":{"df":0,"docs":{},"e":{"df":1,"docs":{"24":{"tf":1.0}}}},"m":{"a":{"df":0,"docs":{},"n":{"df":1,"docs":{"31":{"tf":1.0}}}},"df":0,"docs":{}}}},"i":{"6":{"8":{"6":{"df":1,"docs":{"7":{"tf":1.0}}},"df":0,"docs":{}},"df":0,"docs":{}},"d":{"df":0,"docs":{},"e":{"df":0,"docs":{},"n":{"df":0,"docs":{},"t":{"df":0,"docs":{},"i":{"df":0,"docs":{},"f":{"df":0,"docs":{},"i":{"df":5,"docs":{"27":{"tf":1.7320508075688772},"31":{"tf":1.0},"32":{"tf":1.0},"34":{"tf":1.0},"35":{"tf":1.0}}}}}}}}},"df":0,"docs":{},"f":{"=":{"df":0,"docs":{},"p":{"df":0,"docs":{},"f":{"df":0,"docs":{},"l":{"a":{"df":0,"docs":{},"s":{"df":0,"docs":{},"h":{",":{"df":0,"docs":{},"f":{"df":0,"docs":{},"o":{"df":0,"docs":{},"r":{"df":0,"docs":{},"m":{"a":{"df":0,"docs":{},"t":{"=":{"df":0,"docs":{},"r":{"a":{"df":0,"docs":{},"w":{",":{"df":0,"docs":{},"r":{"df":0,"docs":{},"e":{"a":{"d":{"df":0,"docs":{},"o":{"df":0,"docs":{},"n":{"df":0,"docs":{},"l":{"df":0,"docs":{},"y":{"=":{"df":0,"docs":{},"o":{"df":0,"docs":{},"n":{",":{"df":0,"docs":{},"f":{"df":0,"docs":{},"i":{"df":0,"docs":{},"l":{"df":0,"docs":{},"e":{"=":{"df":0,"docs":{},"o":{"df":0,"docs":{},"v":{"df":0,"docs":{},"m":{"df":0,"docs":{},"f":{"_":{"c":{"df":0,"docs":{},"o":{"d":{"df":0,"docs":{},"e":{".":{"df":0,"docs":{},"f":{"d":{"df":1,"docs":{"13":{"tf":1.0}}},"df":0,"docs":{}}},"df":0,"docs":{}}},"df":0,"docs":{}}},"df":0,"docs":{},"v":{"a":{"df":0,"docs":{},"r":{"df":0,"docs":{},"s":{".":{"df":0,"docs":{},"f":{"d":{"df":1,"docs":{"13":{"tf":1.0}}},"df":0,"docs":{}}},"df":0,"docs":{}}}},"df":0,"docs":{}}},"df":0,"docs":{}}}}}},"df":0,"docs":{}}}}}},"df":0,"docs":{}}}},"df":0,"docs":{}}}}}},"df":0,"docs":{}},"df":0,"docs":{}}}},"df":0,"docs":{}}},"df":0,"docs":{}}},"df":0,"docs":{}}},"df":0,"docs":{}}}}}},"df":0,"docs":{}}}},"df":0,"docs":{}}}}},"df":0,"docs":{}},"m":{"a":{"df":0,"docs":{},"g":{"df":4,"docs":{"20":{"tf":1.0},"21":{"tf":1.0},"23":{"tf":1.0},"5":{"tf":1.4142135623730951}},"e":{"_":{"d":{"df":0,"docs":{},"e":{"df":0,"docs":{},"v":{"df":0,"docs":{},"i":{"c":{"df":0,"docs":{},"e":{"_":{"df":0,"docs":{},"p":{"a":{"df":0,"docs":{},"t":{"df":0,"docs":{},"h":{"_":{"df":0,"docs":{},"t":{"df":0,"docs":{},"e":{"df":0,"docs":{},"x":{"df":0,"docs":{},"t":{"df":2,"docs":{"20":{"tf":1.4142135623730951},"21":{"tf":1.4142135623730951}}}}}}},"df":2,"docs":{"20":{"tf":1.4142135623730951},"21":{"tf":1.4142135623730951}}}}},"df":0,"docs":{}}},"df":0,"docs":{}}},"df":0,"docs":{}}}}},"df":0,"docs":{},"h":{"a":{"df":0,"docs":{},"n":{"d":{"df":0,"docs":{},"l":{"df":1,"docs":{"21":{"tf":1.0}}}},"df":0,"docs":{}}},"df":0,"docs":{}}},"df":0,"docs":{}}}},"df":0,"docs":{},"i":{"df":0,"docs":{},"t":{"df":1,"docs":{"12":{"tf":1.0}}}},"p":{"df":0,"docs":{},"l":{"df":1,"docs":{"22":{"tf":1.7320508075688772}},"e":{"df":0,"docs":{},"m":{"df":0,"docs":{},"e":{"df":0,"docs":{},"n":{"df":0,"docs":{},"t":{"df":5,"docs":{"10":{"tf":1.0},"15":{"tf":1.7320508075688772},"22":{"tf":1.0},"33":{"tf":1.4142135623730951},"34":{"tf":1.4142135623730951}}}}}}}},"o":{"df":0,"docs":{},"r":{"df":0,"docs":{},"t":{"df":5,"docs":{"24":{"tf":1.0},"27":{"tf":1.0},"33":{"tf":1.0},"35":{"tf":1.0},"5":{"tf":1.0}}}}}}},"n":{"c":{"df":0,"docs":{},"l":{"df":0,"docs":{},"u":{"d":{"df":4,"docs":{"11":{"tf":1.0},"26":{"tf":1.0},"31":{"tf":1.0},"34":{"tf":1.0}}},"df":0,"docs":{}}}},"d":{"df":0,"docs":{},"i":{"c":{"df":2,"docs":{"34":{"tf":1.0},"5":{"tf":1.0}}},"df":0,"docs":{},"v":{"df":0,"docs":{},"i":{"d":{"df":0,"docs":{},"u":{"df":3,"docs":{"21":{"tf":1.0},"30":{"tf":1.0},"34":{"tf":1.0}}}},"df":0,"docs":{}}}}},"df":0,"docs":{},"f":{"df":0,"docs":{},"o":{"!":{"(":{"\"":{"df":0,"docs":{},"h":{"df":0,"docs":{},"e":{"df":0,"docs":{},"l":{"df":0,"docs":{},"l":{"df":0,"docs":{},"o":{"df":2,"docs":{"4":{"tf":1.0},"5":{"tf":1.0}}}}}}},"i":{"df":0,"docs":{},"m":{"a":{"df":0,"docs":{},"g":{"df":2,"docs":{"20":{"tf":1.0},"21":{"tf":1.0}}}},"df":0,"docs":{}}}},"df":0,"docs":{}},"df":0,"docs":{}},"df":2,"docs":{"13":{"tf":1.0},"20":{"tf":1.0}},"r":{"df":0,"docs":{},"m":{"df":3,"docs":{"20":{"tf":1.0},"24":{"tf":1.0},"31":{"tf":1.0}}}}}},"h":{"df":0,"docs":{},"e":{"df":0,"docs":{},"r":{"df":1,"docs":{"30":{"tf":1.0}}}}},"i":{"df":0,"docs":{},"t":{"df":0,"docs":{},"i":{"df":3,"docs":{"22":{"tf":1.0},"25":{"tf":1.4142135623730951},"5":{"tf":1.4142135623730951}}}}},"s":{"df":0,"docs":{},"e":{"df":0,"docs":{},"n":{"df":0,"docs":{},"s":{"df":0,"docs":{},"i":{"df":0,"docs":{},"t":{"df":1,"docs":{"15":{"tf":1.0}}}}}},"r":{"df":0,"docs":{},"t":{"df":1,"docs":{"17":{"tf":1.0}}}}},"i":{"d":{"df":1,"docs":{"5":{"tf":1.0}}},"df":0,"docs":{}},"t":{"a":{"df":0,"docs":{},"l":{"df":4,"docs":{"10":{"tf":2.23606797749979},"11":{"tf":1.0},"3":{"tf":1.7320508075688772},"7":{"tf":1.0}}}},"df":0,"docs":{},"r":{"df":0,"docs":{},"u":{"c":{"df":0,"docs":{},"t":{"df":1,"docs":{"3":{"tf":1.0}}}},"df":0,"docs":{}}}}},"t":{"df":0,"docs":{},"e":{"df":0,"docs":{},"l":{"df":1,"docs":{"35":{"tf":1.0}}},"n":{"d":{"df":1,"docs":{"5":{"tf":1.0}}},"df":0,"docs":{}},"r":{"a":{"c":{"df":0,"docs":{},"t":{"df":1,"docs":{"30":{"tf":1.4142135623730951}}}},"df":0,"docs":{}},"df":0,"docs":{},"f":{"a":{"c":{"df":3,"docs":{"26":{"tf":1.0},"28":{"tf":1.0},"30":{"tf":1.0}}},"df":0,"docs":{}},"df":0,"docs":{}}}},"r":{"df":0,"docs":{},"o":{"d":{"df":0,"docs":{},"u":{"c":{"df":0,"docs":{},"t":{"df":1,"docs":{"0":{"tf":1.7320508075688772}}}},"df":0,"docs":{}}},"df":0,"docs":{}}}}},"o":{"df":1,"docs":{"30":{"tf":1.0}}},"s":{"df":0,"docs":{},"n":{"'":{"df":0,"docs":{},"t":{"df":1,"docs":{"21":{"tf":1.0}}}},"df":0,"docs":{}}},"t":{"'":{"df":1,"docs":{"34":{"tf":1.4142135623730951}}},"a":{"df":0,"docs":{},"n":{"df":0,"docs":{},"i":{"df":0,"docs":{},"u":{"df":0,"docs":{},"m":{"df":1,"docs":{"35":{"tf":1.0}}}}}}},"df":0,"docs":{},"s":{"df":0,"docs":{},"e":{"df":0,"docs":{},"l":{"df":0,"docs":{},"f":{"df":1,"docs":{"10":{"tf":1.0}}}}}}}},"k":{"df":0,"docs":{},"e":{"df":0,"docs":{},"y":{"/":{"df":0,"docs":{},"v":{"a":{"df":0,"docs":{},"l":{"df":0,"docs":{},"u":{"df":1,"docs":{"32":{"tf":1.0}}}}},"df":0,"docs":{}}},"df":2,"docs":{"17":{"tf":1.7320508075688772},"32":{"tf":1.0}}}},"i":{"df":0,"docs":{},"n":{"d":{"df":1,"docs":{"31":{"tf":1.0}}},"df":0,"docs":{}}},"v":{"df":0,"docs":{},"m":{"df":2,"docs":{"10":{"tf":1.0},"13":{"tf":1.0}}}}},"l":{"a":{"df":0,"docs":{},"r":{"df":0,"docs":{},"g":{"df":2,"docs":{"30":{"tf":1.0},"34":{"tf":1.4142135623730951}}}},"u":{"df":0,"docs":{},"n":{"c":{"df":0,"docs":{},"h":{"df":2,"docs":{"13":{"tf":1.7320508075688772},"20":{"tf":1.0}}}},"df":0,"docs":{}}}},"df":0,"docs":{},"e":{"a":{"df":0,"docs":{},"r":{"df":0,"docs":{},"n":{"df":1,"docs":{"30":{"tf":1.0}}}}},"df":0,"docs":{},"n":{"df":0,"docs":{},"g":{"df":0,"docs":{},"t":{"df":0,"docs":{},"h":{"df":1,"docs":{"31":{"tf":1.0}}}}}},"s":{"df":0,"docs":{},"s":{"df":2,"docs":{"21":{"tf":1.0},"29":{"tf":1.0}}}},"t":{"'":{"df":2,"docs":{"21":{"tf":1.0},"5":{"tf":1.0}}},"df":0,"docs":{}},"v":{"df":0,"docs":{},"e":{"df":0,"docs":{},"l":{"df":1,"docs":{"26":{"tf":1.0}}}}}},"i":{"b":{"df":0,"docs":{},"r":{"a":{"df":0,"docs":{},"r":{"df":0,"docs":{},"i":{"df":1,"docs":{"5":{"tf":1.0}}}}},"df":0,"docs":{}}},"df":0,"docs":{},"m":{"df":0,"docs":{},"i":{"df":0,"docs":{},"t":{"df":3,"docs":{"25":{"tf":1.0},"26":{"tf":1.0},"33":{"tf":1.0}}}}},"n":{"df":0,"docs":{},"e":{"a":{"df":0,"docs":{},"r":{"df":1,"docs":{"22":{"tf":1.0}}}},"df":1,"docs":{"5":{"tf":1.4142135623730951}}},"k":{"df":2,"docs":{"23":{"tf":1.0},"24":{"tf":1.0}},"e":{"df":0,"docs":{},"r":{"df":1,"docs":{"23":{"tf":1.0}}}}},"u":{"df":0,"docs":{},"x":{"df":2,"docs":{"16":{"tf":1.4142135623730951},"25":{"tf":1.0}}}}},"t":{"df":0,"docs":{},"t":{"df":0,"docs":{},"l":{"df":2,"docs":{"27":{"tf":1.0},"5":{"tf":1.0}}}}}},"o":{"a":{"d":{"df":3,"docs":{"25":{"tf":1.4142135623730951},"26":{"tf":1.0},"29":{"tf":1.0}},"e":{"d":{"_":{"df":0,"docs":{},"i":{"df":0,"docs":{},"m":{"a":{"df":0,"docs":{},"g":{"df":2,"docs":{"20":{"tf":1.0},"21":{"tf":1.0}},"e":{".":{"df":0,"docs":{},"f":{"df":0,"docs":{},"i":{"df":0,"docs":{},"l":{"df":0,"docs":{},"e":{"_":{"df":0,"docs":{},"p":{"a":{"df":0,"docs":{},"t":{"df":0,"docs":{},"h":{"(":{")":{".":{"df":0,"docs":{},"e":{"df":0,"docs":{},"x":{"df":0,"docs":{},"p":{"df":0,"docs":{},"e":{"c":{"df":0,"docs":{},"t":{"(":{"\"":{"df":0,"docs":{},"f":{"df":0,"docs":{},"i":{"df":0,"docs":{},"l":{"df":2,"docs":{"20":{"tf":1.0},"21":{"tf":1.0}}}}}},"df":0,"docs":{}},"df":0,"docs":{}}},"df":0,"docs":{}}}}}},"df":0,"docs":{}},"df":0,"docs":{}},"df":0,"docs":{}}}},"df":0,"docs":{}}},"df":0,"docs":{}}}}}},"df":0,"docs":{}}}},"df":0,"docs":{}}}},"df":0,"docs":{},"i":{"df":0,"docs":{},"m":{"a":{"df":0,"docs":{},"g":{"df":2,"docs":{"20":{"tf":1.0},"21":{"tf":1.4142135623730951}}}},"df":0,"docs":{}}}},"df":0,"docs":{}}},"df":0,"docs":{}},"c":{"a":{"df":0,"docs":{},"t":{"df":1,"docs":{"11":{"tf":1.0}},"e":{"_":{"df":0,"docs":{},"h":{"a":{"df":0,"docs":{},"n":{"d":{"df":0,"docs":{},"l":{"df":0,"docs":{},"e":{"_":{"b":{"df":0,"docs":{},"u":{"df":0,"docs":{},"f":{"df":0,"docs":{},"f":{"df":2,"docs":{"19":{"tf":1.0},"21":{"tf":1.0}},"e":{"df":0,"docs":{},"r":{"(":{"df":0,"docs":{},"s":{"df":0,"docs":{},"e":{"a":{"df":0,"docs":{},"r":{"c":{"df":0,"docs":{},"h":{"df":0,"docs":{},"t":{"df":0,"docs":{},"y":{"df":0,"docs":{},"p":{"df":0,"docs":{},"e":{":":{":":{"b":{"df":0,"docs":{},"y":{"df":0,"docs":{},"p":{"df":0,"docs":{},"r":{"df":0,"docs":{},"o":{"df":0,"docs":{},"t":{"df":0,"docs":{},"o":{"c":{"df":0,"docs":{},"o":{"df":0,"docs":{},"l":{"(":{"&":{"d":{"df":0,"docs":{},"e":{"df":0,"docs":{},"v":{"df":0,"docs":{},"i":{"c":{"df":0,"docs":{},"e":{"df":0,"docs":{},"p":{"a":{"df":0,"docs":{},"t":{"df":0,"docs":{},"h":{"df":0,"docs":{},"t":{"df":0,"docs":{},"o":{"df":0,"docs":{},"t":{"df":0,"docs":{},"e":{"df":0,"docs":{},"x":{"df":0,"docs":{},"t":{":":{":":{"df":0,"docs":{},"g":{"df":0,"docs":{},"u":{"df":0,"docs":{},"i":{"d":{"df":2,"docs":{"20":{"tf":1.0},"21":{"tf":1.0}}},"df":0,"docs":{}}}}},"df":0,"docs":{}},"df":0,"docs":{}}}}}}}}}},"df":0,"docs":{}}}},"df":0,"docs":{}}}}},"df":0,"docs":{}},"df":0,"docs":{}},"df":0,"docs":{}}}},"df":0,"docs":{}}}}}}}},"df":0,"docs":{}},"df":0,"docs":{}},"df":0,"docs":{}}}}}}},"df":0,"docs":{}}},"df":0,"docs":{}}}},"df":0,"docs":{}}}}}}},"df":0,"docs":{}},"df":0,"docs":{}}}},"df":0,"docs":{}}},"df":0,"docs":{}}},"df":0,"docs":{}}}},"df":0,"docs":{}},"df":0,"docs":{},"g":{":":{":":{"df":0,"docs":{},"i":{"df":0,"docs":{},"n":{"df":0,"docs":{},"f":{"df":0,"docs":{},"o":{"df":3,"docs":{"20":{"tf":1.0},"4":{"tf":1.0},"5":{"tf":1.0}}}}}}},"df":0,"docs":{}},"df":4,"docs":{"13":{"tf":1.0},"21":{"tf":1.0},"4":{"tf":1.0},"5":{"tf":1.0}},"g":{"df":0,"docs":{},"e":{"df":0,"docs":{},"r":{"df":1,"docs":{"5":{"tf":1.0}}}}}},"n":{"df":0,"docs":{},"g":{"df":0,"docs":{},"e":{"df":0,"docs":{},"r":{"df":1,"docs":{"25":{"tf":1.0}}}}}},"o":{"df":0,"docs":{},"k":{"df":6,"docs":{"15":{"tf":1.0},"20":{"tf":1.0},"21":{"tf":1.7320508075688772},"27":{"tf":1.0},"31":{"tf":1.0},"5":{"tf":1.7320508075688772}}},"p":{"df":1,"docs":{"22":{"tf":1.4142135623730951}}}}}},"m":{"a":{"c":{"df":1,"docs":{"17":{"tf":1.0}},"h":{"df":0,"docs":{},"i":{"df":0,"docs":{},"n":{"df":3,"docs":{"10":{"tf":1.0},"17":{"tf":1.0},"33":{"tf":1.0}}}}},"r":{"df":0,"docs":{},"o":{"df":1,"docs":{"36":{"tf":1.0}}}}},"df":0,"docs":{},"i":{"df":0,"docs":{},"n":{"(":{"_":{"df":0,"docs":{},"h":{"a":{"df":0,"docs":{},"n":{"d":{"df":0,"docs":{},"l":{"df":1,"docs":{"22":{"tf":1.0}}}},"df":0,"docs":{}}},"df":0,"docs":{}},"i":{"df":0,"docs":{},"m":{"a":{"df":0,"docs":{},"g":{"df":0,"docs":{},"e":{"_":{"df":0,"docs":{},"h":{"a":{"df":0,"docs":{},"n":{"d":{"df":0,"docs":{},"l":{"df":2,"docs":{"4":{"tf":1.0},"5":{"tf":1.0}}}},"df":0,"docs":{}}},"df":0,"docs":{}}},"df":0,"docs":{}}}},"df":0,"docs":{}}}},"df":0,"docs":{},"h":{"a":{"df":0,"docs":{},"n":{"d":{"df":0,"docs":{},"l":{"df":1,"docs":{"26":{"tf":1.0}}}},"df":0,"docs":{}}},"df":0,"docs":{}},"i":{"df":0,"docs":{},"m":{"a":{"df":0,"docs":{},"g":{"df":0,"docs":{},"e":{"_":{"df":0,"docs":{},"h":{"a":{"df":0,"docs":{},"n":{"d":{"df":0,"docs":{},"l":{"df":1,"docs":{"20":{"tf":1.0}}}},"df":0,"docs":{}}},"df":0,"docs":{}}},"df":0,"docs":{}}}},"df":0,"docs":{}}}},"df":4,"docs":{"21":{"tf":1.4142135623730951},"25":{"tf":1.0},"26":{"tf":1.0},"5":{"tf":2.23606797749979}}}},"k":{"df":0,"docs":{},"e":{"df":2,"docs":{"28":{"tf":1.0},"5":{"tf":1.7320508075688772}}}},"n":{"df":0,"docs":{},"i":{"df":4,"docs":{"15":{"tf":1.0},"30":{"tf":1.4142135623730951},"31":{"tf":1.0},"5":{"tf":1.0}}}},"p":{"df":1,"docs":{"26":{"tf":1.0}}},"r":{"df":0,"docs":{},"k":{"df":1,"docs":{"15":{"tf":1.0}}}},"s":{"df":0,"docs":{},"t":{"df":0,"docs":{},"e":{"df":0,"docs":{},"r":{"df":1,"docs":{"34":{"tf":1.0}}}}}},"t":{"c":{"df":0,"docs":{},"h":{"df":1,"docs":{"34":{"tf":1.0}}}},"df":0,"docs":{},"t":{"df":0,"docs":{},"e":{"df":0,"docs":{},"r":{"df":1,"docs":{"15":{"tf":1.0}}}},"h":{"df":0,"docs":{},"e":{"df":0,"docs":{},"w":{"df":1,"docs":{"33":{"tf":1.0}}}}}}}},"b":{"df":0,"docs":{},"r":{"df":1,"docs":{"34":{"tf":1.7320508075688772}}}},"df":0,"docs":{},"e":{"a":{"df":0,"docs":{},"n":{"df":1,"docs":{"19":{"tf":1.0}}}},"c":{"df":0,"docs":{},"h":{"a":{"df":0,"docs":{},"n":{"df":1,"docs":{"28":{"tf":1.0}}}},"df":0,"docs":{}}},"df":0,"docs":{},"m":{":":{":":{"df":0,"docs":{},"s":{"df":0,"docs":{},"i":{"df":0,"docs":{},"z":{"df":0,"docs":{},"e":{"_":{"df":0,"docs":{},"o":{"df":0,"docs":{},"f":{":":{":":{"<":{"df":0,"docs":{},"u":{"df":0,"docs":{},"s":{"df":1,"docs":{"22":{"tf":1.0}}}}},"df":0,"docs":{}},"df":0,"docs":{}},"df":0,"docs":{}}}},"df":0,"docs":{}}}}}},"df":0,"docs":{}},"df":0,"docs":{},"o":{"df":0,"docs":{},"r":{"df":0,"docs":{},"i":{"df":3,"docs":{"26":{"tf":1.4142135623730951},"33":{"tf":1.7320508075688772},"5":{"tf":1.0}}}}}},"n":{"df":0,"docs":{},"u":{"df":1,"docs":{"17":{"tf":1.0}}}},"s":{"df":0,"docs":{},"s":{"a":{"df":0,"docs":{},"g":{"df":1,"docs":{"13":{"tf":1.0}}}},"df":0,"docs":{}}},"t":{"df":0,"docs":{},"h":{"df":0,"docs":{},"o":{"d":{"df":2,"docs":{"21":{"tf":1.4142135623730951},"22":{"tf":2.23606797749979}}},"df":0,"docs":{}}}}},"i":{"c":{"df":0,"docs":{},"e":{"df":1,"docs":{"31":{"tf":1.0}}}},"df":0,"docs":{},"n":{"df":0,"docs":{},"i":{"df":0,"docs":{},"m":{"df":1,"docs":{"4":{"tf":1.4142135623730951}}}}},"s":{"df":0,"docs":{},"i":{"df":0,"docs":{},"n":{"df":0,"docs":{},"t":{"df":0,"docs":{},"e":{"df":0,"docs":{},"r":{"df":0,"docs":{},"p":{"df":0,"docs":{},"r":{"df":0,"docs":{},"e":{"df":0,"docs":{},"t":{"df":1,"docs":{"32":{"tf":1.0}}}}}}}}}}},"s":{"df":2,"docs":{"20":{"tf":1.0},"21":{"tf":1.0}}}}},"k":{"d":{"df":0,"docs":{},"i":{"df":0,"docs":{},"r":{"df":2,"docs":{"12":{"tf":1.0},"16":{"tf":1.4142135623730951}}}}},"df":0,"docs":{},"f":{"df":0,"docs":{},"s":{".":{"df":0,"docs":{},"f":{"a":{"df":0,"docs":{},"t":{"df":1,"docs":{"16":{"tf":1.0}}}},"df":0,"docs":{}}},"df":0,"docs":{}}}},"o":{"d":{"df":0,"docs":{},"e":{"df":2,"docs":{"19":{"tf":1.0},"25":{"tf":1.7320508075688772}},"r":{"df":0,"docs":{},"n":{"df":1,"docs":{"34":{"tf":1.0}}}}},"u":{"df":0,"docs":{},"l":{"df":2,"docs":{"31":{"tf":1.0},"5":{"tf":1.0}}}}},"df":0,"docs":{},"r":{"df":0,"docs":{},"e":{"df":8,"docs":{"21":{"tf":1.0},"22":{"tf":1.0},"24":{"tf":1.0},"25":{"tf":1.0},"27":{"tf":1.0},"31":{"tf":1.0},"33":{"tf":1.0},"34":{"tf":1.0}}}},"s":{"df":0,"docs":{},"t":{"df":0,"docs":{},"l":{"df":0,"docs":{},"i":{"df":1,"docs":{"25":{"tf":1.0}}}}}},"u":{"df":0,"docs":{},"n":{"df":0,"docs":{},"t":{"df":2,"docs":{"15":{"tf":1.0},"16":{"tf":1.4142135623730951}}}}},"v":{"df":0,"docs":{},"e":{"df":1,"docs":{"22":{"tf":1.0}}}}},"u":{"c":{"df":0,"docs":{},"h":{"df":6,"docs":{"21":{"tf":1.0},"24":{"tf":1.0},"25":{"tf":1.0},"27":{"tf":1.0},"33":{"tf":1.0},"5":{"tf":1.0}}}},"df":0,"docs":{},"l":{"df":0,"docs":{},"t":{"df":0,"docs":{},"i":{"df":0,"docs":{},"p":{"df":0,"docs":{},"l":{"df":1,"docs":{"11":{"tf":1.0}}}}}}},"t":{"df":5,"docs":{"20":{"tf":1.0},"22":{"tf":3.1622776601683795},"26":{"tf":1.0},"4":{"tf":1.0},"5":{"tf":1.0}}}}},"n":{"a":{"df":0,"docs":{},"m":{"df":0,"docs":{},"e":{"df":3,"docs":{"15":{"tf":1.4142135623730951},"32":{"tf":1.4142135623730951},"35":{"tf":1.7320508075688772}},"s":{"df":0,"docs":{},"p":{"a":{"c":{"df":1,"docs":{"32":{"tf":1.0}}},"df":0,"docs":{}},"df":0,"docs":{}}}}}},"df":0,"docs":{},"e":{"a":{"df":0,"docs":{},"r":{"df":1,"docs":{"34":{"tf":1.0}},"l":{"df":0,"docs":{},"i":{"df":1,"docs":{"24":{"tf":1.0}}}}}},"c":{"df":0,"docs":{},"e":{"df":0,"docs":{},"s":{"df":0,"docs":{},"s":{"a":{"df":0,"docs":{},"r":{"df":0,"docs":{},"i":{"df":1,"docs":{"15":{"tf":1.0}}}}},"df":0,"docs":{}}}}},"df":0,"docs":{},"e":{"d":{"df":5,"docs":{"10":{"tf":1.0},"14":{"tf":1.0},"21":{"tf":1.0},"5":{"tf":1.7320508075688772},"7":{"tf":1.0}}},"df":0,"docs":{}},"w":{"(":{"df":0,"docs":{},"w":{"df":0,"docs":{},"i":{"d":{"df":0,"docs":{},"t":{"df":0,"docs":{},"h":{"df":1,"docs":{"22":{"tf":1.4142135623730951}}}}},"df":0,"docs":{}}},"x":{"df":1,"docs":{"22":{"tf":1.0}}}},"=":{"1":{":":{"1":{"df":0,"docs":{},"m":{":":{"1":{"0":{"df":0,"docs":{},"m":{"df":1,"docs":{"16":{"tf":1.0}}}},"df":0,"docs":{}},"df":0,"docs":{}},"df":0,"docs":{}}},"df":0,"docs":{}},"df":0,"docs":{}},"df":0,"docs":{}},"df":3,"docs":{"22":{"tf":1.7320508075688772},"26":{"tf":1.0},"4":{"tf":1.0}}},"x":{"df":0,"docs":{},"t":{"df":2,"docs":{"21":{"tf":1.0},"5":{"tf":1.4142135623730951}}}}},"o":{"_":{"df":0,"docs":{},"m":{"a":{"df":0,"docs":{},"i":{"df":0,"docs":{},"n":{"df":4,"docs":{"20":{"tf":1.0},"22":{"tf":1.0},"4":{"tf":1.0},"5":{"tf":1.4142135623730951}}}}},"df":0,"docs":{}},"s":{"df":0,"docs":{},"t":{"d":{"df":4,"docs":{"20":{"tf":1.0},"22":{"tf":1.0},"4":{"tf":1.0},"5":{"tf":1.4142135623730951}}},"df":0,"docs":{}}}},"df":0,"docs":{},"n":{"_":{"df":0,"docs":{},"v":{"df":0,"docs":{},"o":{"df":0,"docs":{},"l":{"a":{"df":0,"docs":{},"t":{"df":0,"docs":{},"i":{"df":0,"docs":{},"l":{"df":1,"docs":{"33":{"tf":1.0}}}}}},"df":0,"docs":{}}}}},"df":2,"docs":{"33":{"tf":1.7320508075688772},"34":{"tf":1.0}}},"r":{"df":0,"docs":{},"m":{"a":{"df":0,"docs":{},"l":{"df":1,"docs":{"33":{"tf":1.0}}}},"df":0,"docs":{}}},"t":{"df":0,"docs":{},"e":{"df":2,"docs":{"15":{"tf":1.4142135623730951},"31":{"tf":1.0}}},"h":{"df":1,"docs":{"5":{"tf":1.0}}}},"w":{"df":4,"docs":{"12":{"tf":1.0},"13":{"tf":1.0},"21":{"tf":1.0},"5":{"tf":1.0}}}},"u":{"df":0,"docs":{},"l":{"df":0,"docs":{},"l":{"df":1,"docs":{"32":{"tf":1.0}}}},"m":{"b":{"df":0,"docs":{},"e":{"df":0,"docs":{},"r":{"df":4,"docs":{"22":{"tf":1.0},"30":{"tf":1.0},"34":{"tf":1.0},"5":{"tf":1.0}}}}},"df":0,"docs":{},"e":{"df":0,"docs":{},"r":{"df":1,"docs":{"5":{"tf":1.0}}}}}}},"o":{"b":{"df":0,"docs":{},"t":{"a":{"df":0,"docs":{},"i":{"df":0,"docs":{},"n":{"df":1,"docs":{"19":{"tf":1.0}}}}},"df":0,"docs":{}}},"df":0,"docs":{},"k":{"df":2,"docs":{"20":{"tf":1.0},"21":{"tf":1.0}}},"n":{"c":{"df":5,"docs":{"17":{"tf":1.0},"19":{"tf":1.0},"25":{"tf":1.0},"26":{"tf":1.0},"33":{"tf":1.0}}},"df":6,"docs":{"11":{"tf":1.4142135623730951},"17":{"tf":1.4142135623730951},"21":{"tf":1.4142135623730951},"22":{"tf":1.0},"26":{"tf":1.0},"30":{"tf":1.0}}},"p":{"a":{"df":0,"docs":{},"q":{"df":0,"docs":{},"u":{"df":3,"docs":{"27":{"tf":1.0},"29":{"tf":1.0},"31":{"tf":1.0}}}}},"df":0,"docs":{},"e":{"df":0,"docs":{},"n":{"_":{"df":0,"docs":{},"p":{"df":0,"docs":{},"r":{"df":0,"docs":{},"o":{"df":0,"docs":{},"t":{"df":0,"docs":{},"o":{"c":{"df":0,"docs":{},"o":{"df":0,"docs":{},"l":{"_":{"df":0,"docs":{},"e":{"df":0,"docs":{},"x":{"c":{"df":0,"docs":{},"l":{"df":0,"docs":{},"u":{"df":0,"docs":{},"s":{"df":1,"docs":{"21":{"tf":1.4142135623730951}},"i":{"df":0,"docs":{},"v":{"df":0,"docs":{},"e":{":":{":":{"<":{"d":{"df":0,"docs":{},"e":{"df":0,"docs":{},"v":{"df":0,"docs":{},"i":{"c":{"df":0,"docs":{},"e":{"df":0,"docs":{},"p":{"a":{"df":0,"docs":{},"t":{"df":0,"docs":{},"h":{"df":0,"docs":{},"t":{"df":0,"docs":{},"o":{"df":0,"docs":{},"t":{"df":0,"docs":{},"e":{"df":0,"docs":{},"x":{"df":0,"docs":{},"t":{"df":2,"docs":{"20":{"tf":1.0},"21":{"tf":1.0}}}}}}}}}}},"df":0,"docs":{}}}},"df":0,"docs":{}}}}},"df":0,"docs":{},"l":{"df":0,"docs":{},"o":{"a":{"d":{"df":0,"docs":{},"e":{"d":{"df":0,"docs":{},"i":{"df":0,"docs":{},"m":{"a":{"df":0,"docs":{},"g":{"df":0,"docs":{},"e":{">":{"(":{"b":{"df":0,"docs":{},"o":{"df":0,"docs":{},"o":{"df":0,"docs":{},"t":{"_":{"df":0,"docs":{},"s":{"df":0,"docs":{},"e":{"df":0,"docs":{},"r":{"df":0,"docs":{},"v":{"df":0,"docs":{},"i":{"c":{"df":0,"docs":{},"e":{"df":0,"docs":{},"s":{".":{"df":0,"docs":{},"i":{"df":0,"docs":{},"m":{"a":{"df":0,"docs":{},"g":{"df":0,"docs":{},"e":{"_":{"df":0,"docs":{},"h":{"a":{"df":0,"docs":{},"n":{"d":{"df":0,"docs":{},"l":{"df":2,"docs":{"20":{"tf":1.0},"21":{"tf":1.0}}}},"df":0,"docs":{}}},"df":0,"docs":{}}},"df":0,"docs":{}}}},"df":0,"docs":{}}}},"df":0,"docs":{}}}},"df":0,"docs":{}}}}}}},"df":0,"docs":{}}}}},"df":0,"docs":{}},"df":0,"docs":{}},"df":0,"docs":{}}}},"df":0,"docs":{}}}},"df":0,"docs":{}}},"df":0,"docs":{}},"df":0,"docs":{}}}},"df":0,"docs":{}},"df":0,"docs":{}},"df":0,"docs":{}}}}}}}},"df":0,"docs":{}}}},"df":0,"docs":{}}}},"df":0,"docs":{}}}}}}},"df":5,"docs":{"19":{"tf":2.23606797749979},"20":{"tf":1.7320508075688772},"21":{"tf":2.0},"22":{"tf":1.4142135623730951},"29":{"tf":1.0}}},"r":{"df":5,"docs":{"10":{"tf":1.0},"11":{"tf":1.0},"16":{"tf":1.0},"25":{"tf":1.4142135623730951},"29":{"tf":1.0}}}},"t":{"df":0,"docs":{},"i":{"df":0,"docs":{},"o":{"df":0,"docs":{},"n":{"<":{"&":{"df":0,"docs":{},"m":{"df":0,"docs":{},"u":{"df":0,"docs":{},"t":{"df":1,"docs":{"22":{"tf":1.4142135623730951}}}}}},"df":0,"docs":{}},"df":3,"docs":{"17":{"tf":1.0},"24":{"tf":1.0},"26":{"tf":1.0}}}}}}},"r":{"d":{"df":0,"docs":{},"e":{"df":0,"docs":{},"r":{"df":2,"docs":{"27":{"tf":1.0},"7":{"tf":1.0}}}}},"df":0,"docs":{},"i":{"df":0,"docs":{},"g":{"df":0,"docs":{},"i":{"df":0,"docs":{},"n":{"df":1,"docs":{"26":{"tf":1.0}}}}}}},"s":{"df":1,"docs":{"15":{"tf":1.0}}},"u":{"df":0,"docs":{},"t":{"df":2,"docs":{"21":{"tf":1.0},"33":{"tf":1.0}},"p":{"df":0,"docs":{},"u":{"df":0,"docs":{},"t":{"df":3,"docs":{"21":{"tf":1.0},"22":{"tf":1.7320508075688772},"5":{"tf":1.4142135623730951}}}}},"s":{"df":0,"docs":{},"i":{"d":{"df":1,"docs":{"25":{"tf":1.0}}},"df":0,"docs":{}}}}},"v":{"df":0,"docs":{},"e":{"df":0,"docs":{},"r":{"df":2,"docs":{"27":{"tf":1.0},"34":{"tf":1.0}},"v":{"df":0,"docs":{},"i":{"df":0,"docs":{},"e":{"df":0,"docs":{},"w":{"df":1,"docs":{"19":{"tf":1.0}}}}}},"w":{"df":0,"docs":{},"r":{"df":0,"docs":{},"i":{"df":0,"docs":{},"t":{"df":1,"docs":{"32":{"tf":1.0}}}}}}}},"m":{"df":0,"docs":{},"f":{"df":2,"docs":{"10":{"tf":2.0},"11":{"tf":1.7320508075688772}}}}}},"p":{".":{"df":0,"docs":{},"i":{"df":1,"docs":{"22":{"tf":1.7320508075688772}}},"x":{"df":1,"docs":{"22":{"tf":1.4142135623730951}}}},"a":{"c":{"df":0,"docs":{},"k":{"a":{"df":0,"docs":{},"g":{"df":1,"docs":{"11":{"tf":1.4142135623730951}},"e":{"'":{"df":1,"docs":{"11":{"tf":1.0}}},"df":0,"docs":{}}}},"df":1,"docs":{"31":{"tf":1.0}}}},"d":{"df":1,"docs":{"22":{"tf":1.0}}},"df":0,"docs":{},"g":{"df":0,"docs":{},"e":{"df":1,"docs":{"24":{"tf":1.0}}}},"n":{"df":0,"docs":{},"i":{"c":{"df":1,"docs":{"5":{"tf":1.0}}},"df":0,"docs":{}}},"r":{"a":{"df":0,"docs":{},"m":{"df":0,"docs":{},"e":{"df":0,"docs":{},"t":{"df":1,"docs":{"21":{"tf":1.4142135623730951}}}}}},"df":0,"docs":{},"s":{"df":0,"docs":{},"e":{"a":{"b":{"df":0,"docs":{},"l":{"df":1,"docs":{"31":{"tf":1.0}}}},"df":0,"docs":{}},"df":0,"docs":{}}},"t":{"df":2,"docs":{"27":{"tf":1.0},"5":{"tf":1.0}},"i":{"c":{"df":0,"docs":{},"u":{"df":0,"docs":{},"l":{"a":{"df":0,"docs":{},"r":{"df":2,"docs":{"19":{"tf":1.0},"35":{"tf":1.0}}}},"df":0,"docs":{}}}},"df":0,"docs":{},"t":{"df":7,"docs":{"12":{"tf":1.7320508075688772},"15":{"tf":3.3166247903554},"16":{"tf":2.0},"27":{"tf":1.0},"31":{"tf":1.0},"34":{"tf":3.3166247903554},"35":{"tf":2.8284271247461903}}}}}},"s":{"df":0,"docs":{},"s":{"df":2,"docs":{"21":{"tf":1.0},"23":{"tf":1.0}}}},"t":{"df":0,"docs":{},"h":{"/":{"df":0,"docs":{},"t":{"df":0,"docs":{},"o":{"/":{"d":{"df":0,"docs":{},"i":{"df":0,"docs":{},"s":{"df":0,"docs":{},"k":{"_":{"df":0,"docs":{},"p":{"a":{"df":0,"docs":{},"r":{"df":0,"docs":{},"t":{"df":0,"docs":{},"i":{"df":0,"docs":{},"t":{"df":1,"docs":{"16":{"tf":1.4142135623730951}}}}}}},"df":0,"docs":{}}},"df":1,"docs":{"16":{"tf":1.0}}}}}},"df":0,"docs":{},"y":{"df":0,"docs":{},"o":{"df":0,"docs":{},"u":{"df":0,"docs":{},"r":{"df":1,"docs":{"16":{"tf":1.0}}}}}}},"df":0,"docs":{}}}},"df":6,"docs":{"15":{"tf":1.0},"19":{"tf":1.0},"20":{"tf":2.0},"21":{"tf":1.7320508075688772},"31":{"tf":3.4641016151377544},"35":{"tf":1.0}}}},"u":{"df":0,"docs":{},"s":{"df":3,"docs":{"1":{"tf":1.0},"21":{"tf":1.0},"5":{"tf":1.0}}}}},"df":2,"docs":{"12":{"tf":1.0},"22":{"tf":2.0}},"e":{"df":0,"docs":{},"r":{"df":0,"docs":{},"s":{"df":0,"docs":{},"i":{"df":0,"docs":{},"s":{"df":0,"docs":{},"t":{"df":1,"docs":{"33":{"tf":1.0}}}}}}}},"h":{"a":{"df":0,"docs":{},"s":{"df":0,"docs":{},"e":{"df":1,"docs":{"25":{"tf":1.4142135623730951}}}}},"df":0,"docs":{},"y":{"df":0,"docs":{},"s":{"df":0,"docs":{},"i":{"c":{"df":1,"docs":{"29":{"tf":1.0}}},"df":0,"docs":{}}}}},"i":{"df":0,"docs":{},"x":{"df":0,"docs":{},"e":{"df":0,"docs":{},"l":{"(":{"&":{"df":0,"docs":{},"m":{"df":0,"docs":{},"u":{"df":0,"docs":{},"t":{"df":1,"docs":{"22":{"tf":1.4142135623730951}}}}}},"df":0,"docs":{}},".":{"b":{"df":0,"docs":{},"l":{"df":0,"docs":{},"u":{"df":1,"docs":{"22":{"tf":1.4142135623730951}}}}},"df":0,"docs":{},"g":{"df":0,"docs":{},"r":{"df":0,"docs":{},"e":{"df":0,"docs":{},"e":{"df":0,"docs":{},"n":{"df":1,"docs":{"22":{"tf":1.4142135623730951}}}}}}},"r":{"df":1,"docs":{"22":{"tf":1.4142135623730951}}}},"df":1,"docs":{"22":{"tf":3.3166247903554}}}}}},"l":{"a":{"c":{"df":0,"docs":{},"e":{"df":3,"docs":{"21":{"tf":1.0},"27":{"tf":1.0},"30":{"tf":1.0}}}},"df":0,"docs":{},"t":{"df":0,"docs":{},"f":{"df":0,"docs":{},"o":{"df":0,"docs":{},"r":{"df":0,"docs":{},"m":{"df":1,"docs":{"25":{"tf":1.4142135623730951}}}}}}}},"df":0,"docs":{},"u":{"df":1,"docs":{"32":{"tf":1.0}}}},"o":{"df":0,"docs":{},"i":{"df":0,"docs":{},"n":{"df":0,"docs":{},"t":{":":{":":{"df":0,"docs":{},"n":{"df":0,"docs":{},"e":{"df":0,"docs":{},"w":{"(":{"b":{"df":0,"docs":{},"o":{"df":0,"docs":{},"r":{"d":{"df":1,"docs":{"22":{"tf":1.0}}},"df":0,"docs":{}}}},"df":0,"docs":{},"s":{"df":0,"docs":{},"i":{"df":0,"docs":{},"z":{"df":0,"docs":{},"e":{".":{"df":0,"docs":{},"x":{"df":1,"docs":{"22":{"tf":1.7320508075688772}}}},"df":0,"docs":{}}}}},"w":{"df":0,"docs":{},"i":{"d":{"df":0,"docs":{},"t":{"df":0,"docs":{},"h":{"df":1,"docs":{"22":{"tf":1.0}}}}},"df":0,"docs":{}}}},"df":0,"docs":{}}}}},"df":0,"docs":{}},"df":3,"docs":{"22":{"tf":2.0},"26":{"tf":1.0},"5":{"tf":1.0}},"e":{"df":0,"docs":{},"r":{"df":2,"docs":{"29":{"tf":1.0},"31":{"tf":1.0}}}}}}},"o":{"df":0,"docs":{},"r":{"df":1,"docs":{"33":{"tf":1.0}}}},"w":{"df":0,"docs":{},"e":{"df":0,"docs":{},"r":{"df":1,"docs":{"33":{"tf":1.0}}}}}},"r":{"a":{"c":{"df":0,"docs":{},"t":{"df":0,"docs":{},"i":{"c":{"df":1,"docs":{"18":{"tf":1.0}}},"df":0,"docs":{}}}},"df":0,"docs":{}},"df":0,"docs":{},"e":{"c":{"df":0,"docs":{},"i":{"df":0,"docs":{},"s":{"df":1,"docs":{"34":{"tf":1.0}}}}},"df":0,"docs":{},"p":{"a":{"df":0,"docs":{},"r":{"df":2,"docs":{"14":{"tf":1.0},"15":{"tf":1.7320508075688772}}}},"df":0,"docs":{}},"s":{"df":0,"docs":{},"s":{"df":1,"docs":{"17":{"tf":1.7320508075688772}}}},"v":{"df":0,"docs":{},"e":{"df":0,"docs":{},"n":{"df":0,"docs":{},"t":{"df":1,"docs":{"33":{"tf":1.0}}}}},"i":{"df":0,"docs":{},"o":{"df":0,"docs":{},"u":{"df":1,"docs":{"21":{"tf":1.0}}}}}}},"i":{"df":0,"docs":{},"m":{"a":{"df":0,"docs":{},"r":{"df":0,"docs":{},"i":{"df":1,"docs":{"34":{"tf":1.0}}}}},"df":0,"docs":{}},"n":{"df":0,"docs":{},"t":{"_":{"df":0,"docs":{},"i":{"df":0,"docs":{},"m":{"a":{"df":0,"docs":{},"g":{"df":0,"docs":{},"e":{"_":{"df":0,"docs":{},"p":{"a":{"df":0,"docs":{},"t":{"df":0,"docs":{},"h":{"(":{"b":{"df":0,"docs":{},"o":{"df":0,"docs":{},"o":{"df":0,"docs":{},"t":{"_":{"df":0,"docs":{},"s":{"df":0,"docs":{},"e":{"df":0,"docs":{},"r":{"df":0,"docs":{},"v":{"df":0,"docs":{},"i":{"c":{"df":2,"docs":{"20":{"tf":1.0},"21":{"tf":1.0}},"e":{"df":0,"docs":{},"s":{")":{".":{"df":0,"docs":{},"u":{"df":0,"docs":{},"n":{"df":0,"docs":{},"w":{"df":0,"docs":{},"r":{"a":{"df":0,"docs":{},"p":{"df":1,"docs":{"20":{"tf":1.0}}}},"df":0,"docs":{}}}}}},"df":0,"docs":{}},"df":0,"docs":{}}}},"df":0,"docs":{}}}}}}},"df":0,"docs":{}}}}},"df":0,"docs":{}},"df":1,"docs":{"21":{"tf":1.4142135623730951}}}}},"df":0,"docs":{}}},"df":0,"docs":{}}}},"df":0,"docs":{}}}},"df":2,"docs":{"1":{"tf":1.0},"20":{"tf":1.0}}}}},"o":{"c":{"df":0,"docs":{},"e":{"df":0,"docs":{},"s":{"df":0,"docs":{},"s":{"df":2,"docs":{"1":{"tf":1.0},"25":{"tf":1.0}}}}}},"d":{"df":0,"docs":{},"u":{"c":{"df":2,"docs":{"23":{"tf":1.0},"8":{"tf":1.0}}},"df":0,"docs":{}}},"df":0,"docs":{},"g":{"df":0,"docs":{},"r":{"a":{"df":0,"docs":{},"m":{"'":{"df":1,"docs":{"21":{"tf":1.0}}},"df":4,"docs":{"20":{"tf":2.449489742783178},"21":{"tf":1.0},"33":{"tf":1.0},"5":{"tf":1.4142135623730951}}}},"df":0,"docs":{}}},"j":{"df":0,"docs":{},"e":{"c":{"df":0,"docs":{},"t":{"df":1,"docs":{"11":{"tf":1.4142135623730951}}}},"df":0,"docs":{}}},"t":{"df":0,"docs":{},"o":{"c":{"df":0,"docs":{},"o":{"df":0,"docs":{},"l":{"'":{"df":1,"docs":{"22":{"tf":1.0}}},"df":9,"docs":{"19":{"tf":3.3166247903554},"20":{"tf":2.0},"21":{"tf":3.0},"22":{"tf":1.7320508075688772},"26":{"tf":1.0},"27":{"tf":1.0},"28":{"tf":2.0},"29":{"tf":1.4142135623730951},"30":{"tf":3.605551275463989}}}}},"df":0,"docs":{}}},"v":{"df":0,"docs":{},"i":{"d":{"df":8,"docs":{"10":{"tf":1.0},"11":{"tf":1.4142135623730951},"19":{"tf":1.0},"26":{"tf":2.0},"28":{"tf":1.0},"30":{"tf":1.4142135623730951},"32":{"tf":1.0},"5":{"tf":1.4142135623730951}}},"df":0,"docs":{}}}}},"u":{"df":0,"docs":{},"r":{"df":0,"docs":{},"p":{"df":0,"docs":{},"o":{"df":0,"docs":{},"s":{"df":1,"docs":{"34":{"tf":1.0}}}}}},"t":{"df":1,"docs":{"25":{"tf":1.0}}}}},"q":{"df":0,"docs":{},"e":{"df":0,"docs":{},"m":{"df":0,"docs":{},"u":{"df":3,"docs":{"0":{"tf":1.0},"10":{"tf":2.23606797749979},"13":{"tf":1.7320508075688772}}}}},"u":{"df":0,"docs":{},"i":{"c":{"df":0,"docs":{},"k":{"df":1,"docs":{"5":{"tf":1.0}}}},"df":0,"docs":{},"r":{"df":0,"docs":{},"k":{"df":1,"docs":{"33":{"tf":1.0}}}}}}},"r":{"a":{"df":0,"docs":{},"n":{"d":{"df":0,"docs":{},"o":{"df":0,"docs":{},"m":{"df":1,"docs":{"22":{"tf":1.7320508075688772}}}}},"df":0,"docs":{},"g":{"df":1,"docs":{"21":{"tf":1.0}}}},"w":{"df":1,"docs":{"36":{"tf":1.0}}}},"df":1,"docs":{"22":{"tf":1.4142135623730951}},"e":{"a":{"d":{"a":{"b":{"df":0,"docs":{},"l":{"df":1,"docs":{"31":{"tf":1.0}}}},"df":0,"docs":{}},"df":3,"docs":{"21":{"tf":1.0},"30":{"tf":1.0},"33":{"tf":1.0}}},"df":0,"docs":{},"l":{"df":1,"docs":{"14":{"tf":1.0}}}},"b":{"df":0,"docs":{},"o":{"df":0,"docs":{},"o":{"df":0,"docs":{},"t":{"df":1,"docs":{"17":{"tf":1.0}}}}}},"c":{"df":0,"docs":{},"o":{"df":0,"docs":{},"r":{"d":{"df":1,"docs":{"34":{"tf":1.0}}},"df":0,"docs":{}}}},"d":{"df":1,"docs":{"22":{"tf":1.0}},"u":{"df":0,"docs":{},"n":{"d":{"df":1,"docs":{"34":{"tf":1.0}}},"df":0,"docs":{}}}},"df":0,"docs":{},"f":{"df":0,"docs":{},"e":{"df":0,"docs":{},"r":{"df":3,"docs":{"11":{"tf":1.0},"21":{"tf":1.0},"36":{"tf":2.6457513110645907}}}}},"g":{"df":0,"docs":{},"u":{"df":0,"docs":{},"l":{"a":{"df":0,"docs":{},"r":{"df":1,"docs":{"21":{"tf":1.0}}}},"df":0,"docs":{}}}},"l":{"a":{"df":0,"docs":{},"t":{"df":2,"docs":{"24":{"tf":1.0},"33":{"tf":1.0}}}},"df":1,"docs":{"34":{"tf":1.0}},"e":{"df":0,"docs":{},"v":{"df":2,"docs":{"0":{"tf":1.0},"24":{"tf":1.0}}}}},"m":{"df":0,"docs":{},"o":{"df":0,"docs":{},"v":{"df":1,"docs":{"7":{"tf":1.0}}}}},"p":{"df":0,"docs":{},"l":{"a":{"c":{"df":1,"docs":{"4":{"tf":1.0}}},"df":0,"docs":{}},"df":0,"docs":{}},"o":{"df":0,"docs":{},"s":{"df":0,"docs":{},"i":{"df":0,"docs":{},"t":{"df":0,"docs":{},"o":{"df":0,"docs":{},"r":{"df":0,"docs":{},"i":{"df":2,"docs":{"22":{"tf":1.0},"7":{"tf":1.0}}}}}}}}},"r":{"df":0,"docs":{},"e":{"df":0,"docs":{},"s":{"df":4,"docs":{"27":{"tf":1.0},"29":{"tf":1.0},"33":{"tf":1.0},"5":{"tf":1.0}},"e":{"df":0,"docs":{},"n":{"df":0,"docs":{},"t":{"df":2,"docs":{"27":{"tf":1.7320508075688772},"31":{"tf":1.0}}}}}}}}},"q":{"df":0,"docs":{},"u":{"df":0,"docs":{},"i":{"df":0,"docs":{},"r":{"df":2,"docs":{"15":{"tf":1.4142135623730951},"5":{"tf":1.0}}}}}},"s":{"df":0,"docs":{},"e":{"df":0,"docs":{},"t":{"df":1,"docs":{"25":{"tf":1.0}}}},"o":{"df":0,"docs":{},"u":{"df":0,"docs":{},"r":{"c":{"df":3,"docs":{"29":{"tf":1.4142135623730951},"30":{"tf":1.0},"31":{"tf":1.0}}},"df":0,"docs":{}}}},"t":{"df":2,"docs":{"21":{"tf":1.0},"22":{"tf":1.0}}},"u":{"df":0,"docs":{},"l":{"df":0,"docs":{},"t":{"df":3,"docs":{"20":{"tf":1.4142135623730951},"21":{"tf":1.4142135623730951},"22":{"tf":1.7320508075688772}}}}}},"t":{"df":0,"docs":{},"u":{"df":0,"docs":{},"r":{"df":0,"docs":{},"n":{"df":5,"docs":{"19":{"tf":1.0},"21":{"tf":1.0},"25":{"tf":1.0},"26":{"tf":1.0},"5":{"tf":1.4142135623730951}}}}}}},"i":{"df":0,"docs":{},"s":{"c":{"df":1,"docs":{"35":{"tf":1.7320508075688772}}},"df":0,"docs":{}}},"n":{"df":0,"docs":{},"g":{".":{"df":0,"docs":{},"g":{"df":0,"docs":{},"e":{"df":0,"docs":{},"t":{"_":{"df":0,"docs":{},"r":{"df":0,"docs":{},"n":{"df":0,"docs":{},"g":{"(":{"df":0,"docs":{},"n":{"df":0,"docs":{},"o":{"df":0,"docs":{},"n":{"df":1,"docs":{"22":{"tf":1.0}}}}}},"df":0,"docs":{}}}}},"df":0,"docs":{}}}}},"_":{"df":0,"docs":{},"h":{"a":{"df":0,"docs":{},"n":{"d":{"df":0,"docs":{},"l":{"df":1,"docs":{"22":{"tf":1.0}}}},"df":0,"docs":{}}},"df":0,"docs":{}}},"df":1,"docs":{"22":{"tf":1.7320508075688772}}}},"o":{"df":0,"docs":{},"o":{"df":0,"docs":{},"t":{"df":1,"docs":{"7":{"tf":1.0}}}}},"s":{"df":7,"docs":{"0":{"tf":1.0},"21":{"tf":1.0},"22":{"tf":1.0},"24":{"tf":1.0},"25":{"tf":1.0},"27":{"tf":1.0},"30":{"tf":1.4142135623730951}}},"u":{"df":0,"docs":{},"n":{"df":16,"docs":{"1":{"tf":1.0},"10":{"tf":1.4142135623730951},"11":{"tf":1.0},"12":{"tf":1.0},"13":{"tf":1.0},"14":{"tf":2.0},"15":{"tf":1.0},"16":{"tf":1.4142135623730951},"17":{"tf":1.0},"20":{"tf":1.4142135623730951},"21":{"tf":1.0},"22":{"tf":1.4142135623730951},"25":{"tf":1.4142135623730951},"5":{"tf":1.0},"8":{"tf":1.0},"9":{"tf":1.7320508075688772}},"t":{"df":0,"docs":{},"i":{"df":0,"docs":{},"m":{"df":5,"docs":{"23":{"tf":1.0},"25":{"tf":2.0},"26":{"tf":1.0},"30":{"tf":1.0},"33":{"tf":1.0}},"e":{"_":{"a":{"c":{"c":{"df":0,"docs":{},"e":{"df":0,"docs":{},"s":{"df":0,"docs":{},"s":{"df":1,"docs":{"33":{"tf":1.0}}}}}},"df":0,"docs":{}},"df":0,"docs":{}},"df":0,"docs":{}},"df":0,"docs":{},"s":{"df":0,"docs":{},"e":{"df":0,"docs":{},"r":{"df":0,"docs":{},"v":{"df":0,"docs":{},"i":{"c":{"df":2,"docs":{"25":{"tf":1.4142135623730951},"26":{"tf":1.4142135623730951}}},"df":0,"docs":{}}}}}}}}}}},"s":{"df":0,"docs":{},"t":{"'":{"df":1,"docs":{"23":{"tf":1.0}}},"df":6,"docs":{"0":{"tf":1.4142135623730951},"1":{"tf":1.0},"3":{"tf":1.4142135623730951},"36":{"tf":1.0},"5":{"tf":1.7320508075688772},"7":{"tf":1.0}},"f":{"df":0,"docs":{},"l":{"a":{"df":0,"docs":{},"g":{"df":1,"docs":{"23":{"tf":1.4142135623730951}}}},"df":0,"docs":{}}},"u":{"df":0,"docs":{},"p":{"df":1,"docs":{"7":{"tf":1.0}}}}}}}},"s":{"a":{"df":0,"docs":{},"f":{"df":0,"docs":{},"e":{"df":0,"docs":{},"s":{"df":0,"docs":{},"t":{"df":1,"docs":{"19":{"tf":1.0}}}}}},"m":{"df":0,"docs":{},"e":{"df":4,"docs":{"19":{"tf":1.0},"27":{"tf":1.0},"31":{"tf":1.0},"32":{"tf":1.0}}}}},"c":{"df":0,"docs":{},"o":{"df":0,"docs":{},"p":{"df":0,"docs":{},"e":{"d":{"df":0,"docs":{},"p":{"df":0,"docs":{},"r":{"df":0,"docs":{},"o":{"df":0,"docs":{},"t":{"df":0,"docs":{},"o":{"c":{"df":0,"docs":{},"o":{"df":0,"docs":{},"l":{"df":1,"docs":{"19":{"tf":1.0}}}}},"df":0,"docs":{}}}}}}},"df":1,"docs":{"25":{"tf":1.0}}}}},"r":{"df":0,"docs":{},"e":{"df":0,"docs":{},"e":{"df":0,"docs":{},"n":{"df":1,"docs":{"22":{"tf":2.449489742783178}},"s":{"df":0,"docs":{},"h":{"df":0,"docs":{},"o":{"df":0,"docs":{},"t":{"df":1,"docs":{"22":{"tf":1.0}}}}}}}}}}},"df":1,"docs":{"22":{"tf":1.0}},"e":{"c":{"df":0,"docs":{},"o":{"df":0,"docs":{},"n":{"d":{"a":{"df":0,"docs":{},"r":{"df":0,"docs":{},"i":{"df":1,"docs":{"34":{"tf":1.0}}}}},"df":4,"docs":{"1":{"tf":1.0},"13":{"tf":1.0},"21":{"tf":1.0},"5":{"tf":1.0}}},"df":0,"docs":{}}}},"df":0,"docs":{},"e":{"df":6,"docs":{"13":{"tf":1.0},"15":{"tf":1.4142135623730951},"19":{"tf":1.0},"30":{"tf":1.0},"31":{"tf":1.0},"5":{"tf":1.0}}},"l":{"df":0,"docs":{},"e":{"c":{"df":0,"docs":{},"t":{"df":1,"docs":{"17":{"tf":1.0}}}},"df":0,"docs":{}},"f":{".":{"df":0,"docs":{},"h":{"df":0,"docs":{},"e":{"df":0,"docs":{},"i":{"df":0,"docs":{},"g":{"df":0,"docs":{},"h":{"df":0,"docs":{},"t":{"df":1,"docs":{"22":{"tf":1.4142135623730951}}}}}}}},"p":{"df":0,"docs":{},"i":{"df":0,"docs":{},"x":{"df":0,"docs":{},"e":{"df":0,"docs":{},"l":{"df":1,"docs":{"22":{"tf":1.4142135623730951}},"s":{".":{"df":0,"docs":{},"g":{"df":0,"docs":{},"e":{"df":0,"docs":{},"t":{"_":{"df":0,"docs":{},"m":{"df":0,"docs":{},"u":{"df":0,"docs":{},"t":{"(":{"df":0,"docs":{},"i":{"df":1,"docs":{"22":{"tf":1.4142135623730951}}}},"df":0,"docs":{}}}}},"df":0,"docs":{}}}}},"df":0,"docs":{}}}}}}},"w":{"df":0,"docs":{},"i":{"d":{"df":0,"docs":{},"t":{"df":0,"docs":{},"h":{"df":1,"docs":{"22":{"tf":2.0}}}}},"df":0,"docs":{}}}},"df":1,"docs":{"22":{"tf":2.449489742783178}}}},"p":{"a":{"df":0,"docs":{},"r":{"df":1,"docs":{"25":{"tf":1.0}}}},"df":0,"docs":{}},"r":{"df":0,"docs":{},"v":{"df":1,"docs":{"32":{"tf":1.0}},"i":{"c":{"df":9,"docs":{"23":{"tf":1.0},"24":{"tf":1.0},"25":{"tf":1.4142135623730951},"26":{"tf":2.23606797749979},"30":{"tf":1.0},"33":{"tf":1.4142135623730951},"36":{"tf":1.0},"4":{"tf":1.0},"5":{"tf":1.0}}},"df":0,"docs":{}}}},"t":{"df":12,"docs":{"15":{"tf":1.0},"16":{"tf":1.0},"20":{"tf":1.0},"21":{"tf":1.4142135623730951},"22":{"tf":1.0},"23":{"tf":1.0},"26":{"tf":1.0},"3":{"tf":1.0},"33":{"tf":2.0},"35":{"tf":1.0},"5":{"tf":1.0},"7":{"tf":1.0}}},"v":{"df":0,"docs":{},"e":{"df":0,"docs":{},"r":{"df":1,"docs":{"25":{"tf":1.0}}}}}},"g":{"d":{"df":0,"docs":{},"i":{"df":0,"docs":{},"s":{"df":0,"docs":{},"k":{"df":1,"docs":{"16":{"tf":1.0}}}}}},"df":0,"docs":{}},"h":{"df":0,"docs":{},"o":{"df":0,"docs":{},"r":{"df":0,"docs":{},"t":{"df":3,"docs":{"27":{"tf":1.0},"34":{"tf":1.0},"35":{"tf":1.0}},"l":{"df":0,"docs":{},"i":{"df":1,"docs":{"20":{"tf":1.0}}}}}},"w":{"df":1,"docs":{"22":{"tf":1.0}}}}},"i":{"df":0,"docs":{},"e":{"df":0,"docs":{},"r":{"df":0,"docs":{},"p":{"df":0,"docs":{},"i":{"df":0,"docs":{},"n":{"df":0,"docs":{},"s":{"df":0,"docs":{},"k":{"df":0,"docs":{},"i":{"df":1,"docs":{"22":{"tf":1.0}}}}}},"ń":{"df":0,"docs":{},"s":{"df":0,"docs":{},"k":{"df":0,"docs":{},"i":{"df":1,"docs":{"22":{"tf":1.0}}}}}}}}}},"m":{"df":0,"docs":{},"p":{"df":0,"docs":{},"l":{"df":3,"docs":{"1":{"tf":1.0},"22":{"tf":1.0},"5":{"tf":1.0}},"e":{"df":0,"docs":{},"r":{"df":1,"docs":{"5":{"tf":1.0}}}}}}},"n":{"df":0,"docs":{},"g":{"df":0,"docs":{},"l":{"df":1,"docs":{"22":{"tf":1.7320508075688772}}}}},"z":{"df":0,"docs":{},"e":{".":{"df":0,"docs":{},"i":{"df":1,"docs":{"22":{"tf":1.7320508075688772}}}},"df":2,"docs":{"22":{"tf":1.0},"33":{"tf":1.0}}}}},"l":{"df":0,"docs":{},"i":{"c":{"df":0,"docs":{},"e":{"df":1,"docs":{"19":{"tf":1.0}}}},"df":0,"docs":{}}},"o":{"df":0,"docs":{},"m":{"df":0,"docs":{},"e":{"df":0,"docs":{},"t":{"df":0,"docs":{},"h":{"df":2,"docs":{"20":{"tf":1.0},"29":{"tf":1.0}}},"i":{"df":0,"docs":{},"m":{"df":1,"docs":{"35":{"tf":1.0}}}}}}},"u":{"df":0,"docs":{},"r":{"c":{"df":1,"docs":{"24":{"tf":1.0}}},"df":0,"docs":{}}}},"p":{"a":{"c":{"df":0,"docs":{},"e":{"df":1,"docs":{"33":{"tf":1.0}}}},"df":0,"docs":{}},"df":0,"docs":{},"e":{"c":{"df":0,"docs":{},"i":{"a":{"df":0,"docs":{},"l":{"df":3,"docs":{"14":{"tf":1.0},"33":{"tf":1.0},"35":{"tf":1.0}}}},"df":0,"docs":{},"f":{"df":9,"docs":{"15":{"tf":1.4142135623730951},"21":{"tf":1.4142135623730951},"24":{"tf":1.4142135623730951},"25":{"tf":1.4142135623730951},"26":{"tf":1.7320508075688772},"27":{"tf":1.0},"30":{"tf":1.4142135623730951},"34":{"tf":1.0},"36":{"tf":1.0}},"i":{"df":1,"docs":{"7":{"tf":1.0}}}}}},"df":0,"docs":{}}},"r":{"c":{"/":{"df":0,"docs":{},"m":{"a":{"df":0,"docs":{},"i":{"df":0,"docs":{},"n":{".":{"df":0,"docs":{},"r":{"df":1,"docs":{"4":{"tf":1.0}},"s":{"@":{"0":{"1":{"1":{"df":1,"docs":{"13":{"tf":1.0}}},"df":0,"docs":{}},"df":0,"docs":{}},"df":0,"docs":{}},"df":0,"docs":{}}}},"df":0,"docs":{}}}},"df":0,"docs":{}}},"df":1,"docs":{"22":{"tf":1.4142135623730951}}},"df":0,"docs":{}},"t":{"a":{"df":0,"docs":{},"g":{"df":0,"docs":{},"e":{"df":4,"docs":{"25":{"tf":2.6457513110645907},"26":{"tf":1.4142135623730951},"30":{"tf":1.4142135623730951},"33":{"tf":1.0}}}},"l":{"df":0,"docs":{},"l":{"df":1,"docs":{"5":{"tf":1.0}}}},"n":{"d":{"a":{"df":0,"docs":{},"r":{"d":{"df":4,"docs":{"27":{"tf":1.0},"34":{"tf":1.0},"35":{"tf":1.0},"5":{"tf":1.7320508075688772}}},"df":0,"docs":{}}},"df":0,"docs":{}},"df":0,"docs":{}},"r":{"df":0,"docs":{},"t":{"/":{"df":0,"docs":{},"e":{"df":0,"docs":{},"n":{"d":{"df":1,"docs":{"34":{"tf":1.0}}},"df":0,"docs":{}}}},"df":4,"docs":{"16":{"tf":1.0},"21":{"tf":1.4142135623730951},"22":{"tf":1.0},"5":{"tf":1.0}}}},"t":{"df":0,"docs":{},"u":{"df":5,"docs":{"20":{"tf":1.0},"22":{"tf":1.0},"26":{"tf":1.0},"4":{"tf":1.0},"5":{"tf":1.4142135623730951}},"s":{":":{":":{"df":0,"docs":{},"s":{"df":0,"docs":{},"u":{"c":{"c":{"df":0,"docs":{},"e":{"df":0,"docs":{},"s":{"df":0,"docs":{},"s":{"df":4,"docs":{"20":{"tf":1.0},"22":{"tf":1.0},"4":{"tf":1.0},"5":{"tf":1.4142135623730951}}}}}},"df":0,"docs":{}},"df":0,"docs":{}}}},"df":0,"docs":{}},"df":0,"docs":{}}}}},"d":{"df":1,"docs":{"5":{"tf":1.0}}},"df":0,"docs":{},"e":{"df":0,"docs":{},"p":{"df":1,"docs":{"15":{"tf":1.4142135623730951}}}},"i":{"df":0,"docs":{},"l":{"df":0,"docs":{},"l":{"df":3,"docs":{"25":{"tf":1.0},"28":{"tf":1.0},"5":{"tf":1.0}}}}},"o":{"df":0,"docs":{},"r":{"a":{"df":0,"docs":{},"g":{"df":4,"docs":{"11":{"tf":1.0},"26":{"tf":1.0},"32":{"tf":1.0},"33":{"tf":1.4142135623730951}}}},"df":0,"docs":{},"e":{"df":5,"docs":{"19":{"tf":1.0},"22":{"tf":1.0},"31":{"tf":1.0},"32":{"tf":1.0},"33":{"tf":1.7320508075688772}}}}},"r":{"df":0,"docs":{},"i":{"c":{"df":0,"docs":{},"t":{"df":0,"docs":{},"l":{"df":0,"docs":{},"i":{"df":2,"docs":{"15":{"tf":1.4142135623730951},"5":{"tf":1.0}}}}}},"df":0,"docs":{},"n":{"df":0,"docs":{},"g":{"df":1,"docs":{"27":{"tf":1.4142135623730951}}}}},"u":{"c":{"df":0,"docs":{},"t":{"df":1,"docs":{"22":{"tf":1.7320508075688772}},"u":{"df":0,"docs":{},"r":{"df":5,"docs":{"12":{"tf":1.0},"15":{"tf":1.0},"26":{"tf":1.0},"31":{"tf":1.4142135623730951},"34":{"tf":1.0}}}}}},"df":0,"docs":{}}}},"u":{"b":{"df":0,"docs":{},"s":{"df":0,"docs":{},"y":{"df":0,"docs":{},"s":{"df":0,"docs":{},"t":{"df":0,"docs":{},"e":{"df":0,"docs":{},"m":{"df":1,"docs":{"23":{"tf":1.0}}}}}}}}},"c":{"c":{"df":0,"docs":{},"e":{"df":0,"docs":{},"s":{"df":0,"docs":{},"s":{"df":2,"docs":{"21":{"tf":1.0},"5":{"tf":1.0}},"f":{"df":0,"docs":{},"u":{"df":0,"docs":{},"l":{"df":0,"docs":{},"l":{"df":0,"docs":{},"i":{"df":1,"docs":{"5":{"tf":1.0}}}}}}}}}}},"df":0,"docs":{},"h":{"df":5,"docs":{"0":{"tf":1.0},"25":{"tf":1.0},"26":{"tf":1.0},"29":{"tf":1.0},"31":{"tf":1.0}}}},"d":{"df":0,"docs":{},"o":{"df":1,"docs":{"10":{"tf":1.4142135623730951}}}},"df":0,"docs":{},"m":{"df":0,"docs":{},"m":{"a":{"df":0,"docs":{},"r":{"df":1,"docs":{"24":{"tf":1.0}}}},"df":0,"docs":{}}},"p":{"df":0,"docs":{},"p":{"df":0,"docs":{},"o":{"df":0,"docs":{},"r":{"df":0,"docs":{},"t":{"df":4,"docs":{"19":{"tf":1.0},"21":{"tf":1.0},"34":{"tf":1.0},"7":{"tf":1.0}}}}}}}},"y":{"df":0,"docs":{},"s":{"df":0,"docs":{},"t":{"df":0,"docs":{},"e":{"df":0,"docs":{},"m":{"_":{"df":0,"docs":{},"t":{"a":{"b":{"df":0,"docs":{},"l":{"df":0,"docs":{},"e":{")":{".":{"df":0,"docs":{},"u":{"df":0,"docs":{},"n":{"df":0,"docs":{},"w":{"df":0,"docs":{},"r":{"a":{"df":0,"docs":{},"p":{"df":4,"docs":{"20":{"tf":1.0},"22":{"tf":1.0},"4":{"tf":1.0},"5":{"tf":1.0}}}},"df":0,"docs":{}}}}}},"df":0,"docs":{}},".":{"b":{"df":0,"docs":{},"o":{"df":0,"docs":{},"o":{"df":0,"docs":{},"t":{"_":{"df":0,"docs":{},"s":{"df":0,"docs":{},"e":{"df":0,"docs":{},"r":{"df":0,"docs":{},"v":{"df":0,"docs":{},"i":{"c":{"df":2,"docs":{"20":{"tf":1.0},"22":{"tf":1.0}},"e":{"df":0,"docs":{},"s":{"(":{")":{".":{"df":0,"docs":{},"s":{"df":0,"docs":{},"t":{"a":{"df":0,"docs":{},"l":{"df":0,"docs":{},"l":{"(":{"1":{"0":{"_":{"0":{"0":{"0":{"_":{"0":{"0":{"0":{"df":2,"docs":{"4":{"tf":1.0},"5":{"tf":1.0}}},"df":0,"docs":{}},"df":0,"docs":{}},"df":0,"docs":{}},"df":0,"docs":{}},"df":0,"docs":{}},"df":0,"docs":{}},"df":0,"docs":{}},"df":0,"docs":{}},"df":0,"docs":{}},"df":0,"docs":{}},"df":0,"docs":{}}}},"df":0,"docs":{}}}},"df":0,"docs":{}},"df":0,"docs":{}},"df":0,"docs":{}}}},"df":0,"docs":{}}}}}}},"df":0,"docs":{}}}}},"df":0,"docs":{}},"df":0,"docs":{}}}},"df":0,"docs":{}},"df":5,"docs":{"20":{"tf":1.0},"22":{"tf":1.0},"26":{"tf":1.0},"4":{"tf":1.0},"5":{"tf":1.0}}}},"df":13,"docs":{"10":{"tf":1.0},"11":{"tf":1.0},"12":{"tf":1.7320508075688772},"13":{"tf":1.0},"15":{"tf":1.4142135623730951},"16":{"tf":1.0},"20":{"tf":1.0},"25":{"tf":2.449489742783178},"26":{"tf":2.0},"31":{"tf":1.4142135623730951},"34":{"tf":1.0},"35":{"tf":2.8284271247461903},"5":{"tf":1.7320508075688772}},"t":{"a":{"b":{"df":0,"docs":{},"l":{"df":0,"docs":{},"e":{":":{":":{"b":{"df":0,"docs":{},"o":{"df":0,"docs":{},"o":{"df":0,"docs":{},"t":{"_":{"df":0,"docs":{},"s":{"df":0,"docs":{},"e":{"df":0,"docs":{},"r":{"df":0,"docs":{},"v":{"df":0,"docs":{},"i":{"c":{"df":1,"docs":{"26":{"tf":1.0}}},"df":0,"docs":{}}}}}}},"df":0,"docs":{}}}}},"df":0,"docs":{},"e":{"df":0,"docs":{},"x":{"df":0,"docs":{},"i":{"df":0,"docs":{},"t":{"_":{"b":{"df":0,"docs":{},"o":{"df":0,"docs":{},"o":{"df":0,"docs":{},"t":{"_":{"df":0,"docs":{},"s":{"df":0,"docs":{},"e":{"df":0,"docs":{},"r":{"df":0,"docs":{},"v":{"df":0,"docs":{},"i":{"c":{"df":2,"docs":{"25":{"tf":1.0},"26":{"tf":1.0}}},"df":0,"docs":{}}}}}}},"df":0,"docs":{}}}}},"df":0,"docs":{}},"df":0,"docs":{}}}}},"r":{"df":0,"docs":{},"u":{"df":0,"docs":{},"n":{"df":0,"docs":{},"t":{"df":0,"docs":{},"i":{"df":0,"docs":{},"m":{"df":0,"docs":{},"e":{"_":{"df":0,"docs":{},"s":{"df":0,"docs":{},"e":{"df":0,"docs":{},"r":{"df":0,"docs":{},"v":{"df":0,"docs":{},"i":{"c":{"df":1,"docs":{"26":{"tf":1.0}}},"df":0,"docs":{}}}}}}},"df":0,"docs":{}}}}}}}}},"df":0,"docs":{}},"<":{"b":{"df":0,"docs":{},"o":{"df":0,"docs":{},"o":{"df":0,"docs":{},"t":{"df":5,"docs":{"20":{"tf":1.0},"22":{"tf":1.0},"26":{"tf":1.0},"4":{"tf":1.0},"5":{"tf":1.0}}}}}},"df":0,"docs":{}},"df":0,"docs":{}}}},"df":0,"docs":{}},"df":1,"docs":{"26":{"tf":1.0}}}}}}}}},"t":{"a":{"b":{"df":0,"docs":{},"l":{"df":5,"docs":{"15":{"tf":1.0},"25":{"tf":1.7320508075688772},"26":{"tf":3.7416573867739413},"34":{"tf":1.4142135623730951},"5":{"tf":1.4142135623730951}}}},"df":0,"docs":{},"k":{"df":0,"docs":{},"e":{"df":2,"docs":{"21":{"tf":1.4142135623730951},"5":{"tf":1.0}}}},"n":{"df":0,"docs":{},"g":{"df":0,"docs":{},"i":{"b":{"df":0,"docs":{},"l":{"df":1,"docs":{"29":{"tf":1.0}}}},"df":0,"docs":{}}}},"r":{"df":0,"docs":{},"g":{"df":0,"docs":{},"e":{"df":0,"docs":{},"t":{"/":{"df":0,"docs":{},"x":{"8":{"6":{"_":{"6":{"4":{"df":2,"docs":{"12":{"tf":1.0},"8":{"tf":1.0}}},"df":0,"docs":{}},"df":0,"docs":{}},"df":0,"docs":{}},"df":0,"docs":{}},"df":0,"docs":{}}},"df":5,"docs":{"17":{"tf":1.0},"23":{"tf":1.0},"36":{"tf":1.0},"7":{"tf":1.7320508075688772},"8":{"tf":1.0}}}}}}},"df":0,"docs":{},"e":{"df":0,"docs":{},"n":{"df":1,"docs":{"21":{"tf":1.0}}},"r":{"df":0,"docs":{},"m":{"df":1,"docs":{"19":{"tf":1.0}},"i":{"df":0,"docs":{},"n":{"df":1,"docs":{"32":{"tf":1.0}}}}}},"x":{"df":0,"docs":{},"t":{"df":2,"docs":{"21":{"tf":1.0},"31":{"tf":1.0}}}}},"h":{"df":0,"docs":{},"i":{"df":0,"docs":{},"n":{"df":0,"docs":{},"g":{"df":4,"docs":{"20":{"tf":1.0},"21":{"tf":1.0},"31":{"tf":1.0},"5":{"tf":1.7320508075688772}}}}},"o":{"df":0,"docs":{},"u":{"df":0,"docs":{},"g":{"df":0,"docs":{},"h":{"df":1,"docs":{"21":{"tf":1.0}}}}}},"r":{"df":0,"docs":{},"e":{"df":0,"docs":{},"e":{"df":3,"docs":{"23":{"tf":1.0},"27":{"tf":1.0},"7":{"tf":1.0}}}},"o":{"df":0,"docs":{},"u":{"df":0,"docs":{},"g":{"df":0,"docs":{},"h":{"df":4,"docs":{"20":{"tf":1.0},"21":{"tf":1.0},"25":{"tf":1.0},"35":{"tf":1.0}}}}}}}},"i":{"df":0,"docs":{},"m":{"df":0,"docs":{},"e":{"df":5,"docs":{"17":{"tf":1.4142135623730951},"21":{"tf":1.4142135623730951},"22":{"tf":1.0},"26":{"tf":1.0},"5":{"tf":1.0}}}}},"o":{"df":0,"docs":{},"g":{"df":0,"docs":{},"e":{"df":0,"docs":{},"t":{"df":0,"docs":{},"h":{"df":2,"docs":{"21":{"tf":1.0},"28":{"tf":1.0}}}}}},"o":{"df":0,"docs":{},"l":{"c":{"df":0,"docs":{},"h":{"a":{"df":0,"docs":{},"i":{"df":0,"docs":{},"n":{".":{"df":0,"docs":{},"t":{"df":0,"docs":{},"o":{"df":0,"docs":{},"m":{"df":0,"docs":{},"l":{"df":1,"docs":{"7":{"tf":1.0}}}}}}},"df":1,"docs":{"7":{"tf":2.0}}}}},"df":0,"docs":{}}},"df":1,"docs":{"0":{"tf":1.0}}}},"p":{"df":2,"docs":{"26":{"tf":1.0},"5":{"tf":1.0}}}},"r":{"df":0,"docs":{},"e":{"a":{"df":0,"docs":{},"t":{"df":1,"docs":{"27":{"tf":1.0}}}},"df":0,"docs":{}},"i":{"a":{"df":0,"docs":{},"n":{"df":0,"docs":{},"g":{"df":0,"docs":{},"l":{"df":1,"docs":{"22":{"tf":2.0}},"e":{"'":{"df":1,"docs":{"22":{"tf":1.0}}},"[":{"df":0,"docs":{},"g":{"df":0,"docs":{},"e":{"df":0,"docs":{},"t":{"_":{"df":0,"docs":{},"r":{"a":{"df":0,"docs":{},"n":{"d":{"df":0,"docs":{},"o":{"df":0,"docs":{},"m":{"_":{"df":0,"docs":{},"u":{"df":0,"docs":{},"s":{"df":0,"docs":{},"i":{"df":0,"docs":{},"z":{"df":0,"docs":{},"e":{"(":{"&":{"df":0,"docs":{},"m":{"df":0,"docs":{},"u":{"df":0,"docs":{},"t":{"df":1,"docs":{"22":{"tf":1.0}}}}}},"df":0,"docs":{}},"df":0,"docs":{}}}}}}},"df":0,"docs":{}}}},"df":0,"docs":{}}},"df":0,"docs":{}}},"df":0,"docs":{}}}}},"df":0,"docs":{}}}}}},"c":{"df":0,"docs":{},"k":{"df":0,"docs":{},"i":{"df":1,"docs":{"33":{"tf":1.0}}}}},"df":2,"docs":{"34":{"tf":1.0},"35":{"tf":1.0}}}},"u":{"df":0,"docs":{},"r":{"df":0,"docs":{},"n":{"df":1,"docs":{"5":{"tf":1.0}}}},"t":{"df":0,"docs":{},"o":{"df":0,"docs":{},"r":{"df":0,"docs":{},"i":{"df":17,"docs":{"1":{"tf":2.0},"10":{"tf":1.0},"11":{"tf":1.0},"12":{"tf":1.0},"13":{"tf":1.0},"14":{"tf":1.0},"15":{"tf":1.0},"16":{"tf":1.0},"17":{"tf":1.0},"2":{"tf":1.0},"3":{"tf":1.0},"4":{"tf":1.0},"5":{"tf":1.0},"6":{"tf":1.0},"7":{"tf":1.0},"8":{"tf":1.0},"9":{"tf":1.0}}}}}}},"w":{"df":0,"docs":{},"o":{"df":3,"docs":{"10":{"tf":1.0},"11":{"tf":1.0},"5":{"tf":1.0}}}},"y":{"df":0,"docs":{},"p":{"df":0,"docs":{},"e":{"c":{"df":0,"docs":{},"o":{"d":{"df":0,"docs":{},"e":{"=":{"1":{":":{"c":{"1":{"2":{"a":{"7":{"3":{"2":{"8":{"df":1,"docs":{"16":{"tf":1.0}}},"df":0,"docs":{}},"df":0,"docs":{}},"df":0,"docs":{}},"df":0,"docs":{}},"df":0,"docs":{}},"df":0,"docs":{}},"df":0,"docs":{}},"df":0,"docs":{}},"df":0,"docs":{}},"df":0,"docs":{}},"df":0,"docs":{}}},"df":0,"docs":{}}},"df":10,"docs":{"15":{"tf":1.0},"16":{"tf":1.0},"21":{"tf":2.449489742783178},"22":{"tf":1.0},"23":{"tf":1.0},"27":{"tf":1.0},"33":{"tf":1.0},"34":{"tf":1.0},"35":{"tf":1.0},"5":{"tf":1.0}}},"i":{"c":{"df":1,"docs":{"25":{"tf":1.4142135623730951}}},"df":0,"docs":{}}}}},"u":{"8":{"df":1,"docs":{"22":{"tf":1.4142135623730951}}},"b":{"df":0,"docs":{},"u":{"df":0,"docs":{},"n":{"df":0,"docs":{},"t":{"df":0,"docs":{},"u":{"df":1,"docs":{"11":{"tf":1.0}}}}}}},"c":{"df":1,"docs":{"32":{"tf":1.0}}},"df":0,"docs":{},"e":{"df":0,"docs":{},"f":{"df":0,"docs":{},"i":{"'":{"df":1,"docs":{"35":{"tf":1.0}}},"/":{"d":{"df":0,"docs":{},"e":{"b":{"df":0,"docs":{},"u":{"df":0,"docs":{},"g":{"/":{"df":0,"docs":{},"m":{"df":0,"docs":{},"i":{"df":2,"docs":{"12":{"tf":1.0},"8":{"tf":1.0}}}}},"df":0,"docs":{}}}},"df":0,"docs":{}}},"df":0,"docs":{}},":":{":":{"df":0,"docs":{},"p":{"df":0,"docs":{},"r":{"df":0,"docs":{},"e":{"df":0,"docs":{},"l":{"df":0,"docs":{},"u":{"d":{"df":4,"docs":{"20":{"tf":1.0},"22":{"tf":1.0},"4":{"tf":1.0},"5":{"tf":1.4142135623730951}}},"df":0,"docs":{}}}},"o":{"df":0,"docs":{},"t":{"df":0,"docs":{},"o":{":":{":":{"c":{"df":0,"docs":{},"o":{"df":0,"docs":{},"n":{"df":0,"docs":{},"s":{"df":0,"docs":{},"o":{"df":0,"docs":{},"l":{"df":0,"docs":{},"e":{":":{":":{"df":0,"docs":{},"g":{"df":0,"docs":{},"o":{"df":0,"docs":{},"p":{":":{":":{"df":0,"docs":{},"{":{"b":{"df":0,"docs":{},"l":{"df":0,"docs":{},"t":{"df":0,"docs":{},"o":{"df":0,"docs":{},"p":{"df":1,"docs":{"22":{"tf":1.0}}}}}}},"df":0,"docs":{}}},"df":0,"docs":{}},"df":0,"docs":{}}}}},"df":0,"docs":{}},"df":0,"docs":{}}}}}}}},"d":{"df":0,"docs":{},"e":{"df":0,"docs":{},"v":{"df":0,"docs":{},"i":{"c":{"df":0,"docs":{},"e":{"_":{"df":0,"docs":{},"p":{"a":{"df":0,"docs":{},"t":{"df":0,"docs":{},"h":{":":{":":{"df":0,"docs":{},"t":{"df":0,"docs":{},"e":{"df":0,"docs":{},"x":{"df":0,"docs":{},"t":{"df":2,"docs":{"20":{"tf":1.0},"31":{"tf":1.0}}}}}}},"df":0,"docs":{}},"df":1,"docs":{"31":{"tf":1.0}}}}},"df":0,"docs":{}}},"df":0,"docs":{}}},"df":0,"docs":{}}}}},"df":0,"docs":{},"l":{"df":0,"docs":{},"o":{"a":{"d":{"df":0,"docs":{},"e":{"d":{"_":{"df":0,"docs":{},"i":{"df":0,"docs":{},"m":{"a":{"df":0,"docs":{},"g":{"df":0,"docs":{},"e":{":":{":":{"df":0,"docs":{},"l":{"df":0,"docs":{},"o":{"a":{"d":{"df":0,"docs":{},"e":{"d":{"df":0,"docs":{},"i":{"df":0,"docs":{},"m":{"a":{"df":0,"docs":{},"g":{"df":1,"docs":{"20":{"tf":1.0}}}},"df":0,"docs":{}}}},"df":0,"docs":{}}},"df":0,"docs":{}},"df":0,"docs":{}}}},"df":0,"docs":{}},"df":0,"docs":{}}}},"df":0,"docs":{}}}},"df":0,"docs":{}},"df":0,"docs":{}}},"df":0,"docs":{}},"df":0,"docs":{}}},"r":{"df":0,"docs":{},"n":{"df":0,"docs":{},"g":{":":{":":{"df":0,"docs":{},"r":{"df":0,"docs":{},"n":{"df":0,"docs":{},"g":{"df":1,"docs":{"22":{"tf":1.0}}}}}},"df":0,"docs":{}},"df":0,"docs":{}}}}},"df":0,"docs":{}},"df":0,"docs":{}}}}}},"r":{"df":0,"docs":{},"e":{"df":0,"docs":{},"s":{"df":0,"docs":{},"u":{"df":0,"docs":{},"l":{"df":0,"docs":{},"t":{"df":2,"docs":{"21":{"tf":1.0},"22":{"tf":1.0}}}}}}}},"s":{"df":0,"docs":{},"t":{"a":{"df":0,"docs":{},"t":{"df":0,"docs":{},"u":{"df":1,"docs":{"21":{"tf":1.0}}}}},"df":0,"docs":{}}},"t":{"a":{"b":{"df":0,"docs":{},"l":{"df":0,"docs":{},"e":{":":{":":{"b":{"df":0,"docs":{},"o":{"df":0,"docs":{},"o":{"df":0,"docs":{},"t":{":":{":":{"b":{"df":0,"docs":{},"o":{"df":0,"docs":{},"o":{"df":0,"docs":{},"t":{"df":0,"docs":{},"s":{"df":0,"docs":{},"e":{"df":0,"docs":{},"r":{"df":0,"docs":{},"v":{"df":0,"docs":{},"i":{"c":{"df":1,"docs":{"22":{"tf":1.0}}},"df":0,"docs":{}}}}}}}}}},"df":0,"docs":{},"s":{"df":0,"docs":{},"e":{"a":{"df":0,"docs":{},"r":{"c":{"df":0,"docs":{},"h":{"df":0,"docs":{},"t":{"df":0,"docs":{},"y":{"df":0,"docs":{},"p":{"df":1,"docs":{"20":{"tf":1.0}}}}}}},"df":0,"docs":{}}},"df":0,"docs":{}}}},"df":0,"docs":{}},"df":0,"docs":{}}}}},"df":0,"docs":{}},"df":0,"docs":{}},"df":0,"docs":{}}}},"df":0,"docs":{}},"df":0,"docs":{}},"{":{"df":0,"docs":{},"i":{"d":{"df":0,"docs":{},"e":{"df":0,"docs":{},"n":{"df":0,"docs":{},"t":{"df":0,"docs":{},"i":{"df":0,"docs":{},"f":{"df":0,"docs":{},"i":{"df":1,"docs":{"20":{"tf":1.0}}}}}}}}},"df":0,"docs":{}}}},"df":0,"docs":{}},"_":{"df":0,"docs":{},"s":{"df":0,"docs":{},"e":{"df":0,"docs":{},"r":{"df":0,"docs":{},"v":{"df":0,"docs":{},"i":{"c":{"df":1,"docs":{"5":{"tf":1.4142135623730951}},"e":{"df":0,"docs":{},"s":{":":{":":{"df":0,"docs":{},"i":{"df":0,"docs":{},"n":{"df":0,"docs":{},"i":{"df":0,"docs":{},"t":{"(":{"&":{"df":0,"docs":{},"m":{"df":0,"docs":{},"u":{"df":0,"docs":{},"t":{"df":4,"docs":{"20":{"tf":1.0},"22":{"tf":1.0},"4":{"tf":1.0},"5":{"tf":1.0}}}}}},"df":0,"docs":{}},"df":0,"docs":{}}}}}},"df":0,"docs":{}},"df":0,"docs":{}}}},"df":0,"docs":{}}}}}}},"df":25,"docs":{"0":{"tf":2.0},"1":{"tf":1.0},"10":{"tf":1.0},"12":{"tf":1.4142135623730951},"15":{"tf":2.0},"2":{"tf":1.7320508075688772},"21":{"tf":1.4142135623730951},"22":{"tf":1.0},"23":{"tf":1.4142135623730951},"24":{"tf":2.23606797749979},"25":{"tf":2.449489742783178},"26":{"tf":1.7320508075688772},"27":{"tf":1.4142135623730951},"28":{"tf":1.4142135623730951},"3":{"tf":1.0},"30":{"tf":2.0},"32":{"tf":1.0},"33":{"tf":1.4142135623730951},"34":{"tf":1.4142135623730951},"35":{"tf":1.4142135623730951},"36":{"tf":2.449489742783178},"4":{"tf":2.23606797749979},"5":{"tf":3.0},"7":{"tf":2.23606797749979},"8":{"tf":1.4142135623730951}}}}},"n":{"a":{"df":0,"docs":{},"u":{"df":0,"docs":{},"t":{"df":0,"docs":{},"h":{"df":0,"docs":{},"o":{"df":0,"docs":{},"r":{"df":1,"docs":{"33":{"tf":1.0}}}}}}}},"d":{"df":0,"docs":{},"e":{"df":0,"docs":{},"r":{"df":3,"docs":{"11":{"tf":1.0},"15":{"tf":1.0},"35":{"tf":1.0}},"s":{"df":0,"docs":{},"t":{"a":{"df":0,"docs":{},"n":{"d":{"df":1,"docs":{"24":{"tf":1.4142135623730951}}},"df":0,"docs":{}}},"df":0,"docs":{}}}}}},"df":0,"docs":{},"i":{"df":0,"docs":{},"q":{"df":0,"docs":{},"u":{"df":2,"docs":{"27":{"tf":1.0},"31":{"tf":1.0}}}}},"k":{"df":0,"docs":{},"n":{"df":0,"docs":{},"o":{"df":0,"docs":{},"w":{"df":0,"docs":{},"n":{"df":4,"docs":{"12":{"tf":1.0},"36":{"tf":1.0},"7":{"tf":1.7320508075688772},"8":{"tf":1.4142135623730951}}}}}}},"l":{"df":0,"docs":{},"i":{"df":0,"docs":{},"k":{"df":2,"docs":{"31":{"tf":1.0},"34":{"tf":1.0}}}}},"s":{"a":{"df":0,"docs":{},"f":{"df":1,"docs":{"19":{"tf":1.0}}}},"df":0,"docs":{}},"t":{"df":0,"docs":{},"i":{"df":0,"docs":{},"l":{"df":1,"docs":{"25":{"tf":1.0}}}}},"u":{"df":0,"docs":{},"s":{"df":1,"docs":{"22":{"tf":1.0}}}}},"p":{"df":4,"docs":{"21":{"tf":1.0},"3":{"tf":1.0},"5":{"tf":1.0},"7":{"tf":1.0}}},"s":{"b":{"df":3,"docs":{"14":{"tf":1.0},"17":{"tf":2.0},"29":{"tf":1.0}}},"df":17,"docs":{"0":{"tf":1.0},"13":{"tf":1.0},"15":{"tf":1.7320508075688772},"17":{"tf":1.4142135623730951},"19":{"tf":2.8284271247461903},"20":{"tf":2.6457513110645907},"21":{"tf":2.0},"22":{"tf":3.605551275463989},"26":{"tf":1.0},"27":{"tf":1.4142135623730951},"30":{"tf":1.4142135623730951},"31":{"tf":1.0},"33":{"tf":1.4142135623730951},"34":{"tf":1.4142135623730951},"4":{"tf":1.4142135623730951},"5":{"tf":2.449489742783178},"7":{"tf":1.0}},"i":{"df":0,"docs":{},"z":{"df":1,"docs":{"22":{"tf":3.872983346207417}},"e":{")":{".":{"df":0,"docs":{},"u":{"df":0,"docs":{},"n":{"df":0,"docs":{},"w":{"df":0,"docs":{},"r":{"a":{"df":0,"docs":{},"p":{"df":1,"docs":{"22":{"tf":1.0}}}},"df":0,"docs":{}}}}}},"df":0,"docs":{}},":":{":":{"df":0,"docs":{},"f":{"df":0,"docs":{},"r":{"df":0,"docs":{},"o":{"df":0,"docs":{},"m":{"_":{"df":0,"docs":{},"l":{"df":0,"docs":{},"e":{"_":{"b":{"df":0,"docs":{},"y":{"df":0,"docs":{},"t":{"df":0,"docs":{},"e":{"df":0,"docs":{},"s":{"(":{"b":{"df":0,"docs":{},"u":{"df":0,"docs":{},"f":{"df":1,"docs":{"22":{"tf":1.0}}}}},"df":0,"docs":{}},"df":0,"docs":{}}}}}},"df":0,"docs":{}},"df":0,"docs":{}}}},"df":0,"docs":{}}}}}},"df":0,"docs":{}},"df":0,"docs":{}}}},"r":{"/":{"df":0,"docs":{},"s":{"df":0,"docs":{},"h":{"a":{"df":0,"docs":{},"r":{"df":0,"docs":{},"e":{"/":{"df":0,"docs":{},"o":{"df":0,"docs":{},"v":{"df":0,"docs":{},"m":{"df":0,"docs":{},"f":{"/":{"df":0,"docs":{},"o":{"df":0,"docs":{},"v":{"df":0,"docs":{},"m":{"df":0,"docs":{},"f":{"_":{"c":{"df":0,"docs":{},"o":{"d":{"df":0,"docs":{},"e":{".":{"df":0,"docs":{},"f":{"d":{"df":1,"docs":{"11":{"tf":1.0}}},"df":0,"docs":{}}},"df":0,"docs":{}}},"df":0,"docs":{}}},"df":0,"docs":{},"v":{"a":{"df":0,"docs":{},"r":{"df":0,"docs":{},"s":{".":{"df":0,"docs":{},"f":{"d":{"df":1,"docs":{"11":{"tf":1.0}}},"df":0,"docs":{}}},"df":0,"docs":{}}}},"df":0,"docs":{}}},"df":0,"docs":{}}}}}},"df":1,"docs":{"11":{"tf":1.0}}}}}}},"df":0,"docs":{}}}},"df":0,"docs":{}}}},"df":0,"docs":{}}}},"v":{".":{"df":0,"docs":{},"i":{"df":1,"docs":{"22":{"tf":1.0}}},"x":{"df":1,"docs":{"22":{"tf":1.0}}}},"a":{"df":0,"docs":{},"l":{"df":0,"docs":{},"u":{"df":2,"docs":{"22":{"tf":1.0},"23":{"tf":1.0}}}},"r":{"df":1,"docs":{"11":{"tf":1.0}},"i":{"a":{"b":{"df":0,"docs":{},"l":{"df":7,"docs":{"11":{"tf":1.0},"26":{"tf":1.0},"27":{"tf":1.0},"31":{"tf":1.0},"32":{"tf":2.8284271247461903},"33":{"tf":3.0},"35":{"tf":1.0}}}},"df":0,"docs":{},"t":{"df":1,"docs":{"11":{"tf":1.0}}}},"df":2,"docs":{"10":{"tf":1.0},"15":{"tf":1.0}},"o":{"df":0,"docs":{},"u":{"df":2,"docs":{"30":{"tf":1.0},"35":{"tf":1.0}}}}}}},"df":2,"docs":{"22":{"tf":1.0},"35":{"tf":1.7320508075688772}},"e":{"c":{"!":{"[":{"b":{"df":0,"docs":{},"l":{"df":0,"docs":{},"t":{"df":0,"docs":{},"p":{"df":0,"docs":{},"i":{"df":0,"docs":{},"x":{"df":0,"docs":{},"e":{"df":0,"docs":{},"l":{":":{":":{"df":0,"docs":{},"n":{"df":0,"docs":{},"e":{"df":0,"docs":{},"w":{"(":{"0":{"df":1,"docs":{"22":{"tf":1.4142135623730951}}},"df":0,"docs":{}},"df":0,"docs":{}}}}},"df":0,"docs":{}},"df":0,"docs":{}}}}}}}}},"df":0,"docs":{}},"df":0,"docs":{}},"<":{"b":{"df":0,"docs":{},"l":{"df":0,"docs":{},"t":{"df":0,"docs":{},"p":{"df":0,"docs":{},"i":{"df":0,"docs":{},"x":{"df":0,"docs":{},"e":{"df":0,"docs":{},"l":{"df":1,"docs":{"22":{"tf":1.4142135623730951}}}}}}}}}},"df":0,"docs":{}},"df":1,"docs":{"22":{"tf":1.0}}},"df":0,"docs":{},"n":{"d":{"df":0,"docs":{},"o":{"df":0,"docs":{},"r":{"'":{"df":2,"docs":{"32":{"tf":1.0},"33":{"tf":1.0}}},"df":2,"docs":{"17":{"tf":1.0},"32":{"tf":1.7320508075688772}}}}},"df":0,"docs":{}},"r":{"df":0,"docs":{},"i":{"df":5,"docs":{"21":{"tf":1.0},"30":{"tf":1.4142135623730951},"31":{"tf":1.0},"33":{"tf":1.0},"34":{"tf":1.4142135623730951}}},"s":{"df":0,"docs":{},"i":{"df":0,"docs":{},"o":{"df":0,"docs":{},"n":{"df":1,"docs":{"35":{"tf":1.0}}}}}},"t":{"df":0,"docs":{},"e":{"df":0,"docs":{},"x":{"df":1,"docs":{"22":{"tf":1.0}}}},"i":{"c":{"df":1,"docs":{"22":{"tf":1.4142135623730951}}},"df":0,"docs":{}}}}},"i":{"a":{"df":1,"docs":{"33":{"tf":1.0}}},"df":0,"docs":{},"r":{"df":0,"docs":{},"t":{"df":0,"docs":{},"u":{"a":{"df":0,"docs":{},"l":{"df":2,"docs":{"10":{"tf":1.0},"26":{"tf":1.0}}}},"df":0,"docs":{}}}}},"m":{"df":5,"docs":{"10":{"tf":1.0},"11":{"tf":1.0},"12":{"tf":1.0},"13":{"tf":1.7320508075688772},"9":{"tf":1.7320508075688772}}},"o":{"df":0,"docs":{},"l":{"a":{"df":0,"docs":{},"t":{"df":0,"docs":{},"i":{"df":0,"docs":{},"l":{"df":1,"docs":{"33":{"tf":1.7320508075688772}}}}}},"df":0,"docs":{}}},"v":{"df":0,"docs":{},"f":{"a":{"df":0,"docs":{},"t":{"df":1,"docs":{"13":{"tf":1.0}}}},"df":0,"docs":{}}}},"w":{"a":{"df":0,"docs":{},"l":{"df":0,"docs":{},"k":{"df":1,"docs":{"20":{"tf":1.0}},"t":{"df":0,"docs":{},"h":{"df":0,"docs":{},"r":{"df":0,"docs":{},"o":{"df":0,"docs":{},"u":{"df":0,"docs":{},"g":{"df":0,"docs":{},"h":{"df":2,"docs":{"21":{"tf":1.4142135623730951},"5":{"tf":1.4142135623730951}}}}}}}}}}},"n":{"df":0,"docs":{},"t":{"df":1,"docs":{"21":{"tf":1.4142135623730951}}}},"r":{"df":0,"docs":{},"n":{"df":1,"docs":{"16":{"tf":1.0}}}},"y":{"df":2,"docs":{"19":{"tf":1.0},"7":{"tf":1.0}}}},"df":0,"docs":{},"e":{"'":{"df":0,"docs":{},"l":{"df":0,"docs":{},"l":{"df":2,"docs":{"11":{"tf":1.0},"20":{"tf":1.4142135623730951}}}}},"df":0,"docs":{},"l":{"c":{"df":0,"docs":{},"o":{"df":0,"docs":{},"m":{"df":2,"docs":{"0":{"tf":1.0},"30":{"tf":1.0}}}}},"df":0,"docs":{},"l":{"df":1,"docs":{"0":{"tf":1.0}}}}},"h":{"df":0,"docs":{},"o":{"df":0,"docs":{},"l":{"df":0,"docs":{},"e":{"df":2,"docs":{"20":{"tf":1.0},"24":{"tf":1.0}}}}}},"i":{"d":{"df":0,"docs":{},"e":{"df":3,"docs":{"21":{"tf":1.0},"26":{"tf":1.0},"28":{"tf":1.0}}},"t":{"df":0,"docs":{},"h":{"df":1,"docs":{"22":{"tf":2.8284271247461903}}}}},"df":0,"docs":{},"n":{"d":{"df":0,"docs":{},"o":{"df":0,"docs":{},"w":{"df":2,"docs":{"13":{"tf":1.0},"25":{"tf":1.0}}}}},"df":0,"docs":{}},"t":{"df":0,"docs":{},"h":{"df":0,"docs":{},"i":{"df":0,"docs":{},"n":{"df":1,"docs":{"35":{"tf":1.0}}}}}}},"o":{"df":0,"docs":{},"r":{"df":0,"docs":{},"l":{"d":{"df":5,"docs":{"1":{"tf":1.0},"13":{"tf":1.0},"21":{"tf":1.0},"4":{"tf":1.0},"5":{"tf":1.4142135623730951}}},"df":0,"docs":{}}}},"r":{"a":{"df":0,"docs":{},"p":{"df":1,"docs":{"30":{"tf":1.0}}}},"df":0,"docs":{},"i":{"df":0,"docs":{},"t":{"df":0,"docs":{},"e":{"df":3,"docs":{"26":{"tf":1.0},"30":{"tf":1.0},"33":{"tf":1.0}}},"t":{"df":0,"docs":{},"e":{"df":0,"docs":{},"n":{"df":1,"docs":{"33":{"tf":1.0}}}}}}}}},"x":{"8":{"6":{"_":{"6":{"4":{"df":6,"docs":{"1":{"tf":1.0},"13":{"tf":1.0},"15":{"tf":1.0},"35":{"tf":1.0},"7":{"tf":1.0},"8":{"tf":1.0}}},"df":0,"docs":{}},"df":0,"docs":{}},"df":1,"docs":{"8":{"tf":1.0}}},"df":0,"docs":{}},"df":1,"docs":{"22":{"tf":2.8284271247461903}},"t":{"a":{"df":0,"docs":{},"s":{"df":0,"docs":{},"k":{"df":1,"docs":{"22":{"tf":1.0}}}}},"df":0,"docs":{}}},"y":{")":{".":{"df":0,"docs":{},"u":{"df":0,"docs":{},"n":{"df":0,"docs":{},"w":{"df":0,"docs":{},"r":{"a":{"df":0,"docs":{},"p":{"df":1,"docs":{"22":{"tf":1.0}}}},"df":0,"docs":{}}}}}},"df":0,"docs":{}},"df":1,"docs":{"22":{"tf":2.6457513110645907}},"o":{"df":0,"docs":{},"u":{"'":{"df":0,"docs":{},"l":{"df":0,"docs":{},"l":{"df":1,"docs":{"14":{"tf":1.0}}}}},"df":0,"docs":{}}}}}},"title":{"root":{"a":{"df":0,"docs":{},"p":{"df":0,"docs":{},"p":{"df":0,"docs":{},"l":{"df":0,"docs":{},"i":{"c":{"df":3,"docs":{"2":{"tf":1.0},"4":{"tf":1.0},"8":{"tf":1.0}}},"df":0,"docs":{}}}}},"t":{"df":0,"docs":{},"t":{"df":0,"docs":{},"r":{"df":0,"docs":{},"i":{"b":{"df":0,"docs":{},"u":{"df":0,"docs":{},"t":{"df":1,"docs":{"33":{"tf":1.0}}}}},"df":0,"docs":{}}}}}},"b":{"df":0,"docs":{},"o":{"df":0,"docs":{},"o":{"df":0,"docs":{},"t":{"df":2,"docs":{"17":{"tf":1.0},"25":{"tf":1.0}}}}},"u":{"df":0,"docs":{},"i":{"df":0,"docs":{},"l":{"d":{"df":3,"docs":{"23":{"tf":1.0},"6":{"tf":1.0},"8":{"tf":1.0}}},"df":0,"docs":{}}}}},"c":{"df":0,"docs":{},"o":{"df":0,"docs":{},"n":{"c":{"df":0,"docs":{},"e":{"df":0,"docs":{},"p":{"df":0,"docs":{},"t":{"df":1,"docs":{"24":{"tf":1.0}}}}}},"df":0,"docs":{}}},"r":{"df":0,"docs":{},"e":{"a":{"df":0,"docs":{},"t":{"df":2,"docs":{"2":{"tf":1.0},"4":{"tf":1.0}}}},"df":0,"docs":{}}}},"d":{"df":0,"docs":{},"e":{"df":0,"docs":{},"p":{"df":0,"docs":{},"e":{"df":0,"docs":{},"n":{"d":{"df":2,"docs":{"10":{"tf":1.0},"3":{"tf":1.0}}},"df":0,"docs":{}}}},"v":{"df":0,"docs":{},"i":{"c":{"df":1,"docs":{"31":{"tf":1.0}}},"df":0,"docs":{}}}},"r":{"a":{"df":0,"docs":{},"w":{"df":1,"docs":{"22":{"tf":1.0}}}},"df":0,"docs":{},"i":{"df":0,"docs":{},"v":{"df":0,"docs":{},"e":{"df":0,"docs":{},"r":{"df":1,"docs":{"23":{"tf":1.0}}}}}}}},"df":0,"docs":{},"e":{"df":0,"docs":{},"x":{"a":{"df":0,"docs":{},"m":{"df":0,"docs":{},"p":{"df":0,"docs":{},"l":{"df":2,"docs":{"16":{"tf":1.0},"20":{"tf":1.0}}}}}},"df":0,"docs":{}}},"f":{"df":0,"docs":{},"i":{"df":0,"docs":{},"l":{"df":0,"docs":{},"e":{"df":1,"docs":{"11":{"tf":1.0}}}},"r":{"df":0,"docs":{},"m":{"df":0,"docs":{},"w":{"a":{"df":0,"docs":{},"r":{"df":1,"docs":{"11":{"tf":1.0}}}},"df":0,"docs":{}}}}}},"g":{"df":0,"docs":{},"p":{"df":0,"docs":{},"t":{"df":1,"docs":{"34":{"tf":1.0}}}},"u":{"df":0,"docs":{},"i":{"d":{"df":1,"docs":{"27":{"tf":1.0}}},"df":0,"docs":{}}}},"h":{"a":{"df":0,"docs":{},"n":{"d":{"df":0,"docs":{},"l":{"df":2,"docs":{"28":{"tf":1.0},"29":{"tf":1.0}}}},"df":0,"docs":{}},"r":{"d":{"df":0,"docs":{},"w":{"a":{"df":0,"docs":{},"r":{"df":1,"docs":{"14":{"tf":1.0}}}},"df":0,"docs":{}}},"df":0,"docs":{}}},"df":0,"docs":{}},"i":{"df":0,"docs":{},"n":{"df":0,"docs":{},"s":{"df":0,"docs":{},"t":{"a":{"df":0,"docs":{},"l":{"df":2,"docs":{"10":{"tf":1.0},"3":{"tf":1.0}}}},"df":0,"docs":{}}},"t":{"df":0,"docs":{},"r":{"df":0,"docs":{},"o":{"d":{"df":0,"docs":{},"u":{"c":{"df":0,"docs":{},"t":{"df":1,"docs":{"0":{"tf":1.0}}}},"df":0,"docs":{}}},"df":0,"docs":{}}}}}},"l":{"a":{"df":0,"docs":{},"u":{"df":0,"docs":{},"n":{"c":{"df":0,"docs":{},"h":{"df":1,"docs":{"13":{"tf":1.0}}}},"df":0,"docs":{}}}},"df":0,"docs":{},"i":{"df":0,"docs":{},"n":{"df":0,"docs":{},"u":{"df":0,"docs":{},"x":{"df":1,"docs":{"16":{"tf":1.0}}}}}}},"m":{"df":0,"docs":{},"i":{"df":0,"docs":{},"n":{"df":0,"docs":{},"i":{"df":0,"docs":{},"m":{"df":1,"docs":{"4":{"tf":1.0}}}}}}},"p":{"a":{"df":0,"docs":{},"r":{"df":0,"docs":{},"t":{"df":0,"docs":{},"i":{"df":0,"docs":{},"t":{"df":2,"docs":{"12":{"tf":1.0},"35":{"tf":1.0}}}}}},"t":{"df":0,"docs":{},"h":{"df":1,"docs":{"31":{"tf":1.0}}}}},"df":0,"docs":{},"r":{"df":0,"docs":{},"e":{"df":0,"docs":{},"p":{"a":{"df":0,"docs":{},"r":{"df":1,"docs":{"15":{"tf":1.0}}}},"df":0,"docs":{}}},"o":{"df":0,"docs":{},"t":{"df":0,"docs":{},"o":{"c":{"df":0,"docs":{},"o":{"df":0,"docs":{},"l":{"df":3,"docs":{"19":{"tf":1.0},"28":{"tf":1.0},"30":{"tf":1.0}}}}},"df":0,"docs":{}}}}}},"r":{"df":0,"docs":{},"e":{"df":0,"docs":{},"f":{"df":0,"docs":{},"e":{"df":0,"docs":{},"r":{"df":1,"docs":{"36":{"tf":1.0}}}}}},"u":{"df":0,"docs":{},"n":{"df":2,"docs":{"14":{"tf":1.0},"9":{"tf":1.0}}}}},"s":{"c":{"df":0,"docs":{},"r":{"df":0,"docs":{},"e":{"df":0,"docs":{},"e":{"df":0,"docs":{},"n":{"df":1,"docs":{"22":{"tf":1.0}}}}}}},"df":0,"docs":{},"t":{"a":{"df":0,"docs":{},"g":{"df":0,"docs":{},"e":{"df":1,"docs":{"25":{"tf":1.0}}}}},"df":0,"docs":{}},"y":{"df":0,"docs":{},"s":{"df":0,"docs":{},"t":{"df":0,"docs":{},"e":{"df":0,"docs":{},"m":{"df":2,"docs":{"12":{"tf":1.0},"35":{"tf":1.0}}}}}}}},"t":{"a":{"b":{"df":0,"docs":{},"l":{"df":1,"docs":{"26":{"tf":1.0}}}},"df":0,"docs":{}},"df":0,"docs":{},"o":{"df":0,"docs":{},"o":{"df":0,"docs":{},"l":{"c":{"df":0,"docs":{},"h":{"a":{"df":0,"docs":{},"i":{"df":0,"docs":{},"n":{"df":1,"docs":{"7":{"tf":1.0}}}}},"df":0,"docs":{}}},"df":0,"docs":{}}}},"u":{"df":0,"docs":{},"t":{"df":0,"docs":{},"o":{"df":0,"docs":{},"r":{"df":0,"docs":{},"i":{"df":1,"docs":{"1":{"tf":1.0}}}}}}}},"u":{"df":0,"docs":{},"e":{"df":0,"docs":{},"f":{"df":0,"docs":{},"i":{"df":1,"docs":{"2":{"tf":1.0}}}}},"s":{"b":{"df":1,"docs":{"17":{"tf":1.0}}},"df":1,"docs":{"19":{"tf":1.0}}}},"v":{"a":{"df":0,"docs":{},"r":{"df":0,"docs":{},"i":{"a":{"b":{"df":0,"docs":{},"l":{"df":1,"docs":{"32":{"tf":1.0}}}},"df":0,"docs":{}},"df":0,"docs":{}}}},"df":0,"docs":{},"m":{"df":2,"docs":{"13":{"tf":1.0},"9":{"tf":1.0}}}},"w":{"a":{"df":0,"docs":{},"l":{"df":0,"docs":{},"k":{"df":0,"docs":{},"t":{"df":0,"docs":{},"h":{"df":0,"docs":{},"r":{"df":0,"docs":{},"o":{"df":0,"docs":{},"u":{"df":0,"docs":{},"g":{"df":0,"docs":{},"h":{"df":2,"docs":{"21":{"tf":1.0},"5":{"tf":1.0}}}}}}}}}}}},"df":0,"docs":{}}}}},"lang":"English","pipeline":["trimmer","stopWordFilter","stemmer"],"ref":"id","version":"0.9.5"},"results_options":{"limit_results":30,"teaser_word_count":30},"search_options":{"bool":"OR","expand":true,"fields":{"body":{"boost":1},"breadcrumbs":{"boost":1},"title":{"boost":2}}}}); \ No newline at end of file diff --git a/HEAD/searchindex.json b/HEAD/searchindex.json new file mode 100644 index 000000000..5b5b3b70d --- /dev/null +++ b/HEAD/searchindex.json @@ -0,0 +1 @@ +{"doc_urls":["introduction.html#introduction","tutorial/introduction.html#tutorial","tutorial/app.html#creating-a-uefi-application","tutorial/app.html#install-dependencies","tutorial/app.html#create-a-minimal-application","tutorial/app.html#walkthrough","tutorial/building.html#building","tutorial/building.html#toolchain","tutorial/building.html#build-the-application","tutorial/vm.html#running-in-a-vm","tutorial/vm.html#install-dependencies","tutorial/vm.html#firmware-files","tutorial/vm.html#system-partition","tutorial/vm.html#launch-the-vm","tutorial/hardware.html#running-on-hardware","tutorial/hardware.html#preparation","tutorial/hardware.html#example-on-linux","tutorial/hardware.html#booting-the-usb","how_to/introduction.html#how-to","how_to/protocols.html#using-protocols","how_to/protocols.html#example","how_to/protocols.html#walkthrough","how_to/drawing.html#drawing-to-the-screen","how_to/building_drivers.html#building-drivers","concepts/introduction.html#concepts","concepts/boot_stages.html#boot-stages","concepts/tables.html#tables","concepts/guid.html#guid","concepts/handles_and_protocols.html#handles-and-protocols","concepts/handles_and_protocols.html#handles","concepts/handles_and_protocols.html#protocols","concepts/device_paths.html#device-paths","concepts/variables.html#variables","concepts/variables.html#attributes","concepts/gpt.html#gpt","concepts/gpt.html#system-partition","reference.html#reference"],"index":{"documentStore":{"docInfo":{"0":{"body":22,"breadcrumbs":2,"title":1},"1":{"body":18,"breadcrumbs":2,"title":1},"10":{"body":36,"breadcrumbs":5,"title":2},"11":{"body":53,"breadcrumbs":5,"title":2},"12":{"body":20,"breadcrumbs":5,"title":2},"13":{"body":33,"breadcrumbs":5,"title":2},"14":{"body":9,"breadcrumbs":5,"title":2},"15":{"body":103,"breadcrumbs":4,"title":1},"16":{"body":54,"breadcrumbs":5,"title":2},"17":{"body":38,"breadcrumbs":5,"title":2},"18":{"body":4,"breadcrumbs":0,"title":0},"19":{"body":64,"breadcrumbs":4,"title":2},"2":{"body":0,"breadcrumbs":7,"title":3},"20":{"body":112,"breadcrumbs":3,"title":1},"21":{"body":182,"breadcrumbs":3,"title":1},"22":{"body":438,"breadcrumbs":4,"title":2},"23":{"body":33,"breadcrumbs":4,"title":2},"24":{"body":33,"breadcrumbs":2,"title":1},"25":{"body":92,"breadcrumbs":5,"title":2},"26":{"body":103,"breadcrumbs":3,"title":1},"27":{"body":64,"breadcrumbs":3,"title":1},"28":{"body":21,"breadcrumbs":5,"title":2},"29":{"body":26,"breadcrumbs":4,"title":1},"3":{"body":7,"breadcrumbs":6,"title":2},"30":{"body":69,"breadcrumbs":4,"title":1},"31":{"body":70,"breadcrumbs":5,"title":2},"32":{"body":44,"breadcrumbs":3,"title":1},"33":{"body":109,"breadcrumbs":3,"title":1},"34":{"body":99,"breadcrumbs":3,"title":1},"35":{"body":94,"breadcrumbs":4,"title":2},"36":{"body":21,"breadcrumbs":2,"title":1},"4":{"body":44,"breadcrumbs":7,"title":3},"5":{"body":179,"breadcrumbs":5,"title":1},"6":{"body":0,"breadcrumbs":3,"title":1},"7":{"body":40,"breadcrumbs":3,"title":1},"8":{"body":19,"breadcrumbs":4,"title":2},"9":{"body":0,"breadcrumbs":5,"title":2}},"docs":{"0":{"body":"Welcome to the Rust UEFI Book. The focus of this book is how to use uefi-rs to build UEFI applications in Rust, but it also describes some general UEFI concepts, as well as relevant tools such as QEMU.","breadcrumbs":"Introduction » Introduction","id":"0","title":"Introduction"},"1":{"body":"This tutorial describes the process of creating and running a simple x86_64 UEFI application in Rust. The application will print \"Hello World\", pause for 10 seconds, then exit.","breadcrumbs":"Tutorial » Tutorial","id":"1","title":"Tutorial"},"10":{"body":"Two dependencies are needed: QEMU , which implements the virtual machine itself, and OVMF , which provides UEFI firmware that QEMU can run. The details of how to install QEMU and OVMF will vary depending on your operating system. Debian/Ubuntu: sudo apt-get install qemu ovmf Fedora: sudo dnf install qemu-kvm edk2-ovmf","breadcrumbs":"Tutorial » Running in a VM » Install dependencies","id":"10","title":"Install dependencies"},"11":{"body":"The OVMF package provides two firmware files, one for the executable code and one for variable storage. (The package may provide multiple variations of these files; refer to the package's documentation for details of the files it includes.) For ease of access we'll copy the OVMF code and vars files to the project directory. The location where OVMF is installed depends on your operating system; for Debian, Ubuntu and Fedora the files are under /usr/share/OVMF. Copy the files to your project directory: cp /usr/share/OVMF/OVMF_CODE.fd .\ncp /usr/share/OVMF/OVMF_VARS.fd .","breadcrumbs":"Tutorial » Running in a VM » Firmware files","id":"11","title":"Firmware files"},"12":{"body":"Now create a directory structure containing the executable to imitate a UEFI System Partition : mkdir -p esp/efi/boot\ncp target/x86_64-unknown-uefi/debug/my-uefi-app.efi esp/efi/boot/bootx64.efi","breadcrumbs":"Tutorial » Running in a VM » System partition","id":"12","title":"System partition"},"13":{"body":"Now we can launch QEMU, using VVFAT to access the esp directory created above. qemu-system-x86_64 -enable-kvm \\ -drive if=pflash,format=raw,readonly=on,file=OVMF_CODE.fd \\ -drive if=pflash,format=raw,readonly=on,file=OVMF_VARS.fd \\ -drive format=raw,file=fat:rw:esp A QEMU window should appear, and after a few seconds you should see the log message: [ INFO]: src/main.rs@011: Hello world!","breadcrumbs":"Tutorial » Running in a VM » Launch the VM","id":"13","title":"Launch the VM"},"14":{"body":"To run on real hardware you'll need a specially-prepared USB drive.","breadcrumbs":"Tutorial » Running on Hardware » Running on Hardware","id":"14","title":"Running on Hardware"},"15":{"body":"The general steps to prepare the drive are: Partition the drive using GPT . Create a partition. Set the partition type GUID to C12A7328-F81F-11D2-BA4B-00A0C93EC93B. That marks it as an EFI System partition. (On many UEFI implementations this is not strictly necessary, see note below.) Format the partition as FAT . Mount the partition. Create the directory path EFI/BOOT on the partition. (FAT is case insensitive, so capitalization doesn't matter.) Copy your EFI application to a file under EFI/BOOT. The file name is specific to the architecture. For example, on x86_64 the file name must be BOOTX64.EFI. See the boot files table for other architectures. The details of exactly how to do these steps will vary depending on your OS. Note that most UEFI implementations do not strictly require GPT partitioning or the EFI System partition GUID; they will look for any FAT partition with the appropriate directory structure. This is not required however; the UEFI Specification says \"UEFI implementations may allow the use of conforming FAT partitions which do not use the ESP GUID.\"","breadcrumbs":"Tutorial » Running on Hardware » Preparation","id":"15","title":"Preparation"},"16":{"body":"Warning: these operations are destructive! Do not run these commands on a disk if you care about the data it contains. # Create the GPT, create a 9MB partition starting at 1MB, and set the\n# partition type to EFI System.\nsgdisk \\ --clear \\ --new=1:1M:10M \\ --typecode=1:C12A7328-F81F-11D2-BA4B-00A0C93EC93B \\ /path/to/disk # Format the partition as FAT.\nmkfs.fat /path/to/disk_partition # Mount the partition.\nmkdir esp\nmount /path/to/disk_partition esp # Create the boot directory.\nmkdir esp/EFI/BOOT # Copy in the boot executable.\ncp /path/to/your-executable.efi esp/EFI/BOOT/BOOTX64.EFI","breadcrumbs":"Tutorial » Running on Hardware » Example on Linux","id":"16","title":"Example on Linux"},"17":{"body":"Insert the USB into the target computer. Reboot the machine, then press the one-time boot key. Which key to press depends on the vendor. For example, Dell uses F12, HP uses F9, and on Macs you hold down the Option key. Once the one-time boot menu appears, select your USB drive and press enter.","breadcrumbs":"Tutorial » Running on Hardware » Booting the USB","id":"17","title":"Booting the USB"},"18":{"body":"This chapter contains practical how-to guides.","breadcrumbs":"How-to » How-to","id":"18","title":"How-to"},"19":{"body":"The open a protocol, you must first get a handle, then open a protocol on that handle. See Handles and Protocols for an overview of what these terms mean. To get a handle you can use: BootServices::locate_handle_buffer : this can be used to get all available handles, or just the handles that support a particular protocol. BootServices::locate_handle : the same as locate_handle_buffer, but you provide the slice that stores the handles. BootServices::locate_device_path : find a handle by Device Path . Once you have obtained a handle, use BootServices::open_protocol_exclusive to open a protocol on that handle. This returns a ScopedProtocol , which automatically closes the protocol when dropped. Using BootServices::open_protocol_exclusive is the safest way to open a protocol, but in some cases a protocol cannot be opened in exclusive mode. The unsafe BootServices::open_protocol can be used in that case.","breadcrumbs":"How-to » Using Protocols » Using Protocols","id":"19","title":"Using Protocols"},"2":{"body":"","breadcrumbs":"Tutorial » Creating a UEFI Application » Creating a UEFI application","id":"2","title":"Creating a UEFI application"},"20":{"body":"For this example we'll look at a program that opens a couple different protocols. This program opens the LoadedImage protocol to get information about an executable (the currently-running program in this case). It also opens the DevicePathToText protocol to get the file system path that the program was launched from. We'll walk through the details of this program shortly, but first here's the whole thing: #![no_main]\n#![no_std] use log::info;\nuse uefi::prelude::*;\nuse uefi::proto::device_path::text::{ AllowShortcuts, DevicePathToText, DisplayOnly,\n};\nuse uefi::proto::loaded_image::LoadedImage;\nuse uefi::table::boot::SearchType;\nuse uefi::{Identify, Result}; #[entry]\nfn main(image_handle: Handle, mut system_table: SystemTable) -> Status { uefi_services::init(&mut system_table).unwrap(); let boot_services = system_table.boot_services(); print_image_path(boot_services).unwrap(); boot_services.stall(10_000_000); Status::SUCCESS\n} fn print_image_path(boot_services: &BootServices) -> Result { let loaded_image = boot_services .open_protocol_exclusive::(boot_services.image_handle())?; let device_path_to_text_handle = *boot_services .locate_handle_buffer(SearchType::ByProtocol(&DevicePathToText::GUID))? .first() .expect(\"DevicePathToText is missing\"); let device_path_to_text = boot_services .open_protocol_exclusive::( device_path_to_text_handle, )?; let image_device_path = loaded_image.file_path().expect(\"File path is not set\"); let image_device_path_text = device_path_to_text .convert_device_path_to_text( boot_services, image_device_path, DisplayOnly(true), AllowShortcuts(false), ) .expect(\"convert_device_path_to_text failed\"); info!(\"Image path: {}\", &*image_device_path_text); Ok(())\n} When the program is run it will print something like this: [ INFO]: example.rs@058: Image path: \\EFI\\BOOT\\BOOTX64.EFI","breadcrumbs":"How-to » Using Protocols » Example","id":"20","title":"Example"},"21":{"body":"The main function looks much like the \"Hello world!\" example . It sets up logging, calls print_image_path, and pauses for ten seconds to give you time to read the output. Let's look at print_image_path: fn print_image_path(boot_services: &BootServices) -> Result { The return type is a uefi::Result , which is a Result alias that combines uefi::Status with the error data. Both the success and error data types are () by default. The function starts by opening the LoadedImage protocol: let loaded_image = boot_services .open_protocol_exclusive::(boot_services.image_handle())?; The open_protocol_exclusive method takes a type parameter, which is the type of Protocol you want to open ( LoadedImage in this case). It also takes one regular argument of type Handle . For this example we want the handle of the currently-running image, which was passed in as the first argument to main. The handle is conveniently accessible through BootServices::image_handle , so we use that here. Next the program opens the DevicePathToText protocol: let device_path_to_text_handle = *boot_services .locate_handle_buffer(SearchType::ByProtocol(&DevicePathToText::GUID))? .first() .expect(\"DevicePathToText is missing\"); let device_path_to_text = boot_services .open_protocol_exclusive::( device_path_to_text_handle, )?; This protocol isn't available for the image_handle, so we start by using locate_handle_buffer to find all handles that support DevicePathToText. We only need one handle though, so we call first() and discard the rest. Then we call open_protocol_exclusive again. It looks more or less like the previous time, but with DevicePathToText as the type parameter and device_path_to_text_handle as the handle. Now that we have both protocols open, we can use them together to get the program's path and convert it to text: let image_device_path = loaded_image.file_path().expect(\"File path is not set\"); let image_device_path_text = device_path_to_text .convert_device_path_to_text( boot_services, image_device_path, DisplayOnly(true), AllowShortcuts(false), ) .expect(\"convert_device_path_to_text failed\"); info!(\"Image path: {}\", &*image_device_path_text); Ok(())\n} Since protocols do a wide range of different things, the methods available to call are very specific to each individual protocol. The best places to find out what each protocol can do are the uefi-rs reference documentation and the UEFI Specification .","breadcrumbs":"How-to » Using Protocols » Walkthrough","id":"21","title":"Walkthrough"},"22":{"body":"This example shows how to draw to the screen using the graphics output protocol . The code will a Sierpiński triangle using the \"chaos game\" method. screenshot The core abstraction used here is a linear buffer: struct Buffer { width: usize, height: usize, pixels: Vec,\n} impl Buffer { /// Create a new `Buffer`. fn new(width: usize, height: usize) -> Self { Buffer { width, height, pixels: vec![BltPixel::new(0, 0, 0); width * height], } } /// Get a single pixel. fn pixel(&mut self, x: usize, y: usize) -> Option<&mut BltPixel> { self.pixels.get_mut(y * self.width + x) } /// Blit the buffer to the framebuffer. fn blit(&self, gop: &mut GraphicsOutput) -> Result { gop.blt(BltOp::BufferToVideo { buffer: &self.pixels, src: BltRegion::Full, dest: (0, 0), dims: (self.width, self.height), }) }\n} This Buffer type stores a Vec of BltPixel s, which are BGRX 32-bit pixels (8 bites each for blue, green, and red, followed by 8 unused bits of padding). We use the pixel method to alter a single pixel at a time. This is often not an efficient method; for more complex graphics you could use a crate like embedded-graphics . The Buffer::blit method calls the graphics output protocol's blt method to copy the buffer to the screen. Most of the rest of the code is just implementing the algorithm for drawing the fractal. Here's the full example: #![no_main]\n#![no_std] extern crate alloc; use alloc::vec;\nuse alloc::vec::Vec;\nuse core::mem;\nuse uefi::prelude::*;\nuse uefi::proto::console::gop::{BltOp, BltPixel, BltRegion, GraphicsOutput};\nuse uefi::proto::rng::Rng;\nuse uefi::table::boot::BootServices;\nuse uefi::Result; #[derive(Clone, Copy)]\nstruct Point { x: f32, y: f32,\n} impl Point { fn new(x: f32, y: f32) -> Self { Self { x, y } }\n} struct Buffer { width: usize, height: usize, pixels: Vec,\n} impl Buffer { /// Create a new `Buffer`. fn new(width: usize, height: usize) -> Self { Buffer { width, height, pixels: vec![BltPixel::new(0, 0, 0); width * height], } } /// Get a single pixel. fn pixel(&mut self, x: usize, y: usize) -> Option<&mut BltPixel> { self.pixels.get_mut(y * self.width + x) } /// Blit the buffer to the framebuffer. fn blit(&self, gop: &mut GraphicsOutput) -> Result { gop.blt(BltOp::BufferToVideo { buffer: &self.pixels, src: BltRegion::Full, dest: (0, 0), dims: (self.width, self.height), }) }\n} /// Get a random `usize` value.\nfn get_random_usize(rng: &mut Rng) -> usize { let mut buf = [0; mem::size_of::()]; rng.get_rng(None, &mut buf).expect(\"get_rng failed\"); usize::from_le_bytes(buf)\n} fn draw_sierpinski(bt: &BootServices) -> Result { // Open graphics output protocol. let gop_handle = bt.get_handle_for_protocol::()?; let mut gop = bt.open_protocol_exclusive::(gop_handle)?; // Open random number generator protocol. let rng_handle = bt.get_handle_for_protocol::()?; let mut rng = bt.open_protocol_exclusive::(rng_handle)?; // Create a buffer to draw into. let (width, height) = gop.current_mode_info().resolution(); let mut buffer = Buffer::new(width, height); // Initialize the buffer with a simple gradient background. for y in 0..height { let r = ((y as f32) / ((height - 1) as f32)) * 255.0; for x in 0..width { let g = ((x as f32) / ((width - 1) as f32)) * 255.0; let pixel = buffer.pixel(x, y).unwrap(); pixel.red = r as u8; pixel.green = g as u8; pixel.blue = 255; } } let size = Point::new(width as f32, height as f32); // Define the vertices of a big triangle. let border = 20.0; let triangle = [ Point::new(size.x / 2.0, border), Point::new(border, size.y - border), Point::new(size.x - border, size.y - border), ]; // `p` is the point to draw. Start at the center of the triangle. let mut p = Point::new(size.x / 2.0, size.y / 2.0); // Loop forever, drawing the frame after each new point is changed. loop { // Choose one of the triangle's vertices at random. let v = triangle[get_random_usize(&mut rng) % 3]; // Move `p` halfway to the chosen vertex. p.x = (p.x + v.x) * 0.5; p.y = (p.y + v.y) * 0.5; // Set `p` to black. let pixel = buffer.pixel(p.x as usize, p.y as usize).unwrap(); pixel.red = 0; pixel.green = 100; pixel.blue = 0; // Draw the buffer to the screen. buffer.blit(&mut gop)?; }\n} #[entry]\nfn main(_handle: Handle, mut system_table: SystemTable) -> Status { uefi_services::init(&mut system_table).unwrap(); let bt = system_table.boot_services(); draw_sierpinski(bt).unwrap(); Status::SUCCESS\n} You can run this example from the uefi-rs repository with: cargo xtask run --example sierpinski","breadcrumbs":"How-to » Drawing to the Screen » Drawing to the Screen","id":"22","title":"Drawing to the Screen"},"23":{"body":"There are three types of UEFI images: Application Boot service driver Runtime driver By default , Rust's UEFI targets produce applications. This can be changed by passing a subsystem linker flag in rustflags and setting the value to efi_boot_service_driver or efi_runtime_driver. Example: # In .cargo/config.toml:\n[build]\nrustflags = [\"-C\", \"link-args=/subsystem:efi_runtime_driver\"]","breadcrumbs":"How-to » Building drivers » Building drivers","id":"23","title":"Building drivers"},"24":{"body":"The canonical source of information about UEFI is the UEFI specification . The specification is huge (currently nearly 2500 pages). Much of that content relates to optional services, understanding of which is not critical to understanding UEFI as a whole. This chapter summarizes some of the more important UEFI concepts and links to the relevant uefi-rs documentation.","breadcrumbs":"Concepts » Concepts","id":"24","title":"Concepts"},"25":{"body":"A UEFI system goes through several distinct phases during the boot process. Platform Initialization. This early-boot phase is mostly outside the scope of uefi-rs. It is described by the UEFI Platform Initialization Specification , which is separate from the main UEFI Specification. Boot Services. This is when UEFI drivers and applications are loaded. Both the BootServices and RuntimeServices tables are accessible. This stage typically culminates in running a bootloader that loads an operating system. The stage ends when SystemTable::exit_boot_services is called, putting the system in Runtime mode. Runtime. This stage is typically active when running an operating system such as Linux or Windows. UEFI functionality is much more limited in the Runtime mode. The BootServices table is no longer accessible, but the RuntimeServices table is still available. Once the system is in Runtime mode, it cannot return to the Boot Services stage until after a system reset.","breadcrumbs":"Concepts » Boot Stages » Boot Stages","id":"25","title":"Boot Stages"},"26":{"body":"UEFI has a few table structures. These tables are how you get access to UEFI services. SystemTable (EFI_SYSTEM_TABLE in the specification) is the top-level table that provides access to the other tables. BootServices (EFI_BOOT_SERVICES in the specification) provides access to a wide array of services such as memory allocation, executable loading, and optional extension interfaces called protocols. This table is only accessible while in the Boot Services stage. RuntimeServices (EFI_RUNTIME_SERVICES in the specification) provides access to a fairly limited set of services, including variable storage, system time, and virtual-memory mapping. This table is accessible during both the Boot Services and Runtime stages. When writing a UEFI application, you get access to the system table from one of the arguments to the main entry point: fn main(handle: Handle, mut system_table: SystemTable) -> Status; Then use SystemTable::boot_services and SystemTable::runtime_services to get access to the other tables. Once SystemTable::exit_boot_services is called, the original system table is consumed and a new system table is returned that only provides access to the RuntimeServices table.","breadcrumbs":"Concepts » Tables » Tables","id":"26","title":"Tables"},"27":{"body":"GUID is short for Globally Unique Identifier. A GUID is always 16 bytes, and has a standard string representation format that looks like this: 313b0d7c-fed4-4de7-99ed-2fe48874a410. The details of the GUID format aren't too important, but be aware that the actual byte representation is not in the same order as the string representation because the first three fields are little-endian. For the most part you can treat GUIDs as opaque identifiers. The UEFI specification uses GUIDs all over the place. GUIDs are used to identify protocols, disk partitions, variable groupings, and much more. In uefi-rs, GUIDs are represented by the Guid type.","breadcrumbs":"Concepts » GUID » GUID","id":"27","title":"GUID"},"28":{"body":"Handles and protocols are at the core of what makes UEFI extensible. Together they are the mechanism by which UEFI can adapt to a wide array of hardware and boot conditions, while still providing a consistent interface to drivers and applications.","breadcrumbs":"Concepts » Handles and Protocols » Handles and Protocols","id":"28","title":"Handles and Protocols"},"29":{"body":"Handles represent resources. A resource might be a physical device such as a disk drive or USB device, or something less tangible like a loaded executable. A Handle is an opaque pointer, so you can't do anything with it directly. To operate on a handle you have to open a protocol.","breadcrumbs":"Concepts » Handles and Protocols » Handles","id":"29","title":"Handles"},"3":{"body":"Follow the Rust installation instructions to set up Rust.","breadcrumbs":"Tutorial » Creating a UEFI Application » Install dependencies","id":"3","title":"Install dependencies"},"30":{"body":"Protocols are interfaces that provide functions to interact with a resource. For example, the BlockIO protocol provides functions to read and write to block IO devices. Protocols are only available during the Boot Services stage ; you can't access them during the Runtime stage. The UEFI Specification defines a very large number of protocols. Because protocols are inherently very diverse, the best place to learn about individual protocols is the UEFI Specification . There are many chapters covering various protocols. Not all of these protocols are wrapped by uefi-rs yet (contributions welcome!) but many of the most commonly useful ones are. See the Using Protocols how-to for details of the uefi-rs API for interacting with protocols.","breadcrumbs":"Concepts » Handles and Protocols » Protocols","id":"30","title":"Protocols"},"31":{"body":"A device path is a very flexible packed data structure for storing paths to many kinds of device. Note that these device paths are not the same thing as file system paths, although they can include file system paths. Like handles , device paths can be used to uniquely identify resources such as consoles, mice, disks, partitions, and more. Unlike handles , which are essentially opaque pointers, device paths are variable-length structures that contain parseable information. The uefi::proto::device_path module documentation describes the details of how device paths are encoded. Device paths can also be converted to and from human-readable text representations that look like this: PciRoot(0x0)/Pci(0x1F,0x2)/Sata(0x0,0xFFFF,0x0)/HD(1,MBR,0xBE1AFDFA,0x3F,0xFBFC1) See uefi::proto::device_path::text for details.","breadcrumbs":"Concepts » Device Paths » Device Paths","id":"31","title":"Device Paths"},"32":{"body":"UEFI provides fairly flexible key/value variable storage. Each variable is identified by a key consisting of a UCS-2 null-terminated name plus a vendor GUID . The vendor GUID serves as a namespace for variables so that different vendors don't accidentally overwrite or misinterpret another vendor's variable if they happen to have the same name. The data stored in each variable is an arbitrary byte array.","breadcrumbs":"Concepts » Variables » Variables","id":"32","title":"Variables"},"33":{"body":"Each variable has attributes (represented as bit flags) associated with it that affect how it is stored and how it can be accessed. If the BOOTSERVICE_ACCESS and RUNTIME_ACCESS bits are set, the variable can be accessed during both the Boot Services and Runtime stages . If only BOOTSERVICE_ACCESS is set then the variable can neither be read nor written to after exiting boot services. Another important attribute is the NON_VOLATILE bit. If this bit is not set, the variable will be stored in normal memory and will not persist across a power cycle. If this bit is set, the variable will be stored in special non-volatile memory. You should be careful about writing variables of this type, because the non-volatile storage can be very limited in size. There have been cases where a vendor's poor UEFI implementation caused the machine not too boot once the storage became too full. Even figuring out how much space is in use can be tricky due to deletion being implemented via garbage collection. Matthew Garret's article \"Dealing with UEFI non-volatile memory quirks\" has more details. Most of the other attributes relate to authenticated variables, which can be used to prevent changes to a variable by unauthorized programs.","breadcrumbs":"Concepts » Variables » Attributes","id":"33","title":"Attributes"},"34":{"body":"GPT is short for GUID Partition Table. It's a more modern alternative to MBR (master boot record) partition tables. Although it's defined in the UEFI specification, it often gets used on non-UEFI systems too. There are a couple big advantages of using GPT over MBR: It has a relatively clear and precise standard, unlike MBR where implementations often just try to match what other implementations do. It supports very large disks and very large numbers of partitions. A GPT disk contains a primary header near the beginning of the disk, followed by a partition entry array. The header and partition entry array have a secondary copy at the end of the disk for redundancy. The partition entry arrays contain structures that describe each partition, including a GUID to identify the individual partition, a partition type GUID to indicate the purpose of the partition, and start/end block addresses. In between the entry arrays is the actual partition data.","breadcrumbs":"Concepts » GPT » GPT","id":"34","title":"GPT"},"35":{"body":"The system partition is UEFI's version of a bootable partition. The system partition is sometimes called the ESP, or EFI System Partition. It is identified by a partition type of c12a7328-f81f-11d2-ba4b-00a0c93ec93b. The system partition always contains a FAT file system. There are various standardized paths that can exist within the file system, and of particular importance are the boot files. These are the files that UEFI will try to boot from by default (in the absence of a different boot configuration set through special UEFI variables ). Boot files are under \\EFI\\BOOT, and are named BOOT.efi, where is a short architecture name. Architecture File name Intel 32-bit BOOTIA32.EFI X86_64 BOOTX64.EFI Itanium BOOTIA64.EFI AArch32 BOOTARM.EFI AArch64 BOOTAA64.EFI RISC-V 32-bit BOOTRISCV32.EFI RISC-V 64-bit BOOTRISCV64.EFI RISC-V 128-bit BOOTRISCV128.EFI","breadcrumbs":"Concepts » GPT » System partition","id":"35","title":"System partition"},"36":{"body":"Rust *-unknown-uefi targets uefi crate reference uefi-macros crate reference uefi-raw crate reference uefi-services crate reference UEFI Specifications","breadcrumbs":"Reference » Reference","id":"36","title":"Reference"},"4":{"body":"Create an empty application and change to that directory: cargo new my-uefi-app\ncd my-uefi-app Add a few dependencies: cargo add log uefi uefi-services Replace the contents of src/main.rs with this: #![no_main]\n#![no_std] use log::info;\nuse uefi::prelude::*; #[entry]\nfn main(_image_handle: Handle, mut system_table: SystemTable) -> Status { uefi_services::init(&mut system_table).unwrap(); info!(\"Hello world!\"); system_table.boot_services().stall(10_000_000); Status::SUCCESS\n}","breadcrumbs":"Tutorial » Creating a UEFI Application » Create a minimal application","id":"4","title":"Create a minimal application"},"5":{"body":"Let's look a quick look at what each part of the program is doing, starting with the #![...] lines at the top: #![no_main]\n#![no_std] This is some boilerplate that all Rust UEFI applications will need. no_main is needed because the UEFI application entry point is different from the standard Rust main function. no_std is needed to turn off the std library; the core and alloc crates can still be used. Next up are some use lines. Nothing too exciting here; the uefi::prelude module is intended to be glob-imported, and exports a number of commonly-used types. use log::info;\nuse uefi::prelude::*; Now we get to the UEFI application main function, and here things look a little different from a standard Rust program. #[entry]\nfn main(_image_handle: Handle, mut system_table: SystemTable) -> Status { The main function in a Uefi application always takes two arguments, the image handle and the system table. The image handle represents the currently-running executable, and the system table provides access to many different UEFI services. The main function returns a Status , which is essentially a numeric error (or success) code defined by UEFI. The first thing we do inside of main is initialize uefi_services: uefi_services::init(&mut system_table).unwrap(); The uefi_services crate is not strictly required to make a UEFI application with the uefi crate, but it makes things much simpler by setting a simple memory allocator, initializing the logger, and providing a panic handler. Next we use the standard log crate to output \"Hello world!\". Then we call stall to make the system pause for 10 seconds. This just ensures you have enough time to see the output. info!(\"Hello world!\"); system_table.boot_services().stall(10_000_000); Finally we return Status::SUCCESS indicating that everything completed successfully: Status::SUCCESS\n}","breadcrumbs":"Tutorial » Creating a UEFI Application » Walkthrough","id":"5","title":"Walkthrough"},"6":{"body":"","breadcrumbs":"Tutorial » Building » Building","id":"6","title":"Building"},"7":{"body":"In order to compile for UEFI, an appropriate target must be installed. The easiest way to set this up is using a rustup toolchain file . In the root of your repository, add rust-toolchain.toml: [toolchain]\ntargets = [\"aarch64-unknown-uefi\", \"i686-unknown-uefi\", \"x86_64-unknown-uefi\"] Here we have specified all three of the currently-supported UEFI targets; you can remove some if you don't need them.","breadcrumbs":"Tutorial » Building » Toolchain","id":"7","title":"Toolchain"},"8":{"body":"Run this command to build the application: cargo build --target x86_64-unknown-uefi This will produce an x86-64 executable: target/x86_64-unknown-uefi/debug/my-uefi-app.efi.","breadcrumbs":"Tutorial » Building » Build the application","id":"8","title":"Build the application"},"9":{"body":"","breadcrumbs":"Tutorial » Running in a VM » Running in a VM","id":"9","title":"Running in a VM"}},"length":37,"save":true},"fields":["title","body","breadcrumbs"],"index":{"body":{"root":{"0":{".":{".":{"df":0,"docs":{},"h":{"df":0,"docs":{},"e":{"df":0,"docs":{},"i":{"df":0,"docs":{},"g":{"df":0,"docs":{},"h":{"df":0,"docs":{},"t":{"df":1,"docs":{"22":{"tf":1.0}}}}}}}},"w":{"df":0,"docs":{},"i":{"d":{"df":0,"docs":{},"t":{"df":0,"docs":{},"h":{"df":1,"docs":{"22":{"tf":1.0}}}}},"df":0,"docs":{}}}},"5":{"df":1,"docs":{"22":{"tf":1.4142135623730951}}},"df":0,"docs":{}},"0":{"a":{"0":{"c":{"9":{"3":{"df":0,"docs":{},"e":{"c":{"9":{"3":{"b":{"df":3,"docs":{"15":{"tf":1.0},"16":{"tf":1.0},"35":{"tf":1.0}}},"df":0,"docs":{}},"df":0,"docs":{}},"df":0,"docs":{}},"df":0,"docs":{}}},"df":0,"docs":{}},"df":0,"docs":{}},"df":0,"docs":{}},"df":0,"docs":{}},"df":0,"docs":{}},"df":1,"docs":{"22":{"tf":3.3166247903554}}},"1":{"0":{"0":{"df":1,"docs":{"22":{"tf":1.0}}},"df":2,"docs":{"1":{"tf":1.0},"5":{"tf":1.0}}},"1":{"d":{"2":{"df":3,"docs":{"15":{"tf":1.0},"16":{"tf":1.0},"35":{"tf":1.0}}},"df":0,"docs":{}},"df":0,"docs":{}},"2":{"8":{"df":1,"docs":{"35":{"tf":1.0}}},"df":0,"docs":{}},"6":{"df":1,"docs":{"27":{"tf":1.0}}},"df":1,"docs":{"22":{"tf":1.4142135623730951}},"m":{"b":{"df":1,"docs":{"16":{"tf":1.0}}},"df":0,"docs":{}}},"2":{".":{"0":{"df":1,"docs":{"22":{"tf":1.7320508075688772}}},"df":0,"docs":{}},"0":{".":{"0":{"df":1,"docs":{"22":{"tf":1.0}}},"df":0,"docs":{}},"df":0,"docs":{}},"5":{"0":{"0":{"df":1,"docs":{"24":{"tf":1.0}}},"df":0,"docs":{}},"5":{".":{"0":{"df":1,"docs":{"22":{"tf":1.4142135623730951}}},"df":0,"docs":{}},"df":1,"docs":{"22":{"tf":1.0}}},"df":0,"docs":{}},"df":1,"docs":{"32":{"tf":1.0}},"f":{"df":0,"docs":{},"e":{"4":{"8":{"8":{"7":{"4":{"a":{"4":{"1":{"0":{"df":1,"docs":{"27":{"tf":1.0}}},"df":0,"docs":{}},"df":0,"docs":{}},"df":0,"docs":{}},"df":0,"docs":{}},"df":0,"docs":{}},"df":0,"docs":{}},"df":0,"docs":{}},"df":0,"docs":{}},"df":0,"docs":{}}}},"3":{"1":{"3":{"b":{"0":{"d":{"7":{"c":{"df":1,"docs":{"27":{"tf":1.0}}},"df":0,"docs":{}},"df":0,"docs":{}},"df":0,"docs":{}},"df":0,"docs":{}},"df":0,"docs":{}},"df":0,"docs":{}},"2":{"df":2,"docs":{"22":{"tf":1.0},"35":{"tf":1.4142135623730951}}},"df":1,"docs":{"22":{"tf":1.0}}},"4":{"d":{"df":0,"docs":{},"e":{"7":{"df":1,"docs":{"27":{"tf":1.0}}},"df":0,"docs":{}}},"df":0,"docs":{}},"6":{"4":{"df":2,"docs":{"35":{"tf":1.0},"8":{"tf":1.0}}},"df":0,"docs":{}},"8":{"df":1,"docs":{"22":{"tf":1.4142135623730951}}},"9":{"9":{"df":0,"docs":{},"e":{"d":{"df":1,"docs":{"27":{"tf":1.0}}},"df":0,"docs":{}}},"df":0,"docs":{},"m":{"b":{"df":1,"docs":{"16":{"tf":1.0}}},"df":0,"docs":{}}},"a":{"a":{"df":0,"docs":{},"r":{"c":{"df":0,"docs":{},"h":{"3":{"2":{"df":1,"docs":{"35":{"tf":1.0}}},"df":0,"docs":{}},"6":{"4":{"df":2,"docs":{"35":{"tf":1.0},"7":{"tf":1.0}}},"df":0,"docs":{}},"df":0,"docs":{}}},"df":0,"docs":{}}},"b":{"df":0,"docs":{},"o":{"df":0,"docs":{},"v":{"df":1,"docs":{"13":{"tf":1.0}}}},"s":{"df":0,"docs":{},"e":{"df":0,"docs":{},"n":{"c":{"df":1,"docs":{"35":{"tf":1.0}}},"df":0,"docs":{}}},"t":{"df":0,"docs":{},"r":{"a":{"c":{"df":0,"docs":{},"t":{"df":1,"docs":{"22":{"tf":1.0}}}},"df":0,"docs":{}},"df":0,"docs":{}}}}},"c":{"c":{"df":0,"docs":{},"e":{"df":0,"docs":{},"s":{"df":0,"docs":{},"s":{"df":8,"docs":{"11":{"tf":1.0},"13":{"tf":1.0},"21":{"tf":1.0},"25":{"tf":1.4142135623730951},"26":{"tf":3.0},"30":{"tf":1.0},"33":{"tf":1.4142135623730951},"5":{"tf":1.0}}}}},"i":{"d":{"df":0,"docs":{},"e":{"df":0,"docs":{},"n":{"df":0,"docs":{},"t":{"df":1,"docs":{"32":{"tf":1.0}}}}}},"df":0,"docs":{}}},"df":0,"docs":{},"t":{"df":0,"docs":{},"i":{"df":0,"docs":{},"v":{"df":1,"docs":{"25":{"tf":1.0}}}},"u":{"a":{"df":0,"docs":{},"l":{"df":2,"docs":{"27":{"tf":1.0},"34":{"tf":1.0}}}},"df":0,"docs":{}}}},"d":{"a":{"df":0,"docs":{},"p":{"df":0,"docs":{},"t":{"df":1,"docs":{"28":{"tf":1.0}}}}},"d":{"df":2,"docs":{"4":{"tf":1.4142135623730951},"7":{"tf":1.0}},"r":{"df":0,"docs":{},"e":{"df":0,"docs":{},"s":{"df":0,"docs":{},"s":{"df":1,"docs":{"34":{"tf":1.0}}}}}}},"df":0,"docs":{},"v":{"a":{"df":0,"docs":{},"n":{"df":0,"docs":{},"t":{"a":{"df":0,"docs":{},"g":{"df":1,"docs":{"34":{"tf":1.0}}}},"df":0,"docs":{}}}},"df":0,"docs":{}}},"df":0,"docs":{},"f":{"df":0,"docs":{},"f":{"df":0,"docs":{},"e":{"c":{"df":0,"docs":{},"t":{"df":1,"docs":{"33":{"tf":1.0}}}},"df":0,"docs":{}}}},"g":{"a":{"df":0,"docs":{},"i":{"df":0,"docs":{},"n":{"df":1,"docs":{"21":{"tf":1.0}}}}},"df":0,"docs":{}},"l":{"df":0,"docs":{},"g":{"df":0,"docs":{},"o":{"df":0,"docs":{},"r":{"df":0,"docs":{},"i":{"df":0,"docs":{},"t":{"df":0,"docs":{},"h":{"df":0,"docs":{},"m":{"df":1,"docs":{"22":{"tf":1.0}}}}}}}}},"i":{"a":{"df":1,"docs":{"21":{"tf":1.0}}},"df":0,"docs":{}},"l":{"df":0,"docs":{},"o":{"c":{":":{":":{"df":0,"docs":{},"v":{"df":0,"docs":{},"e":{"c":{":":{":":{"df":0,"docs":{},"v":{"df":0,"docs":{},"e":{"c":{"df":1,"docs":{"22":{"tf":1.0}}},"df":0,"docs":{}}}},"df":0,"docs":{}},"df":1,"docs":{"22":{"tf":1.0}}},"df":0,"docs":{}}}},"df":0,"docs":{}},"df":3,"docs":{"22":{"tf":1.0},"26":{"tf":1.0},"5":{"tf":1.4142135623730951}}},"df":0,"docs":{},"w":{"df":1,"docs":{"15":{"tf":1.0}},"s":{"df":0,"docs":{},"h":{"df":0,"docs":{},"o":{"df":0,"docs":{},"r":{"df":0,"docs":{},"t":{"c":{"df":0,"docs":{},"u":{"df":0,"docs":{},"t":{"df":1,"docs":{"20":{"tf":1.0}},"s":{"(":{"df":0,"docs":{},"f":{"a":{"df":0,"docs":{},"l":{"df":0,"docs":{},"s":{"df":2,"docs":{"20":{"tf":1.0},"21":{"tf":1.0}}}}},"df":0,"docs":{}}},"df":0,"docs":{}}}}},"df":0,"docs":{}}}}}}}}},"t":{"df":0,"docs":{},"e":{"df":0,"docs":{},"r":{"df":1,"docs":{"22":{"tf":1.0}},"n":{"df":1,"docs":{"34":{"tf":1.0}}}}},"h":{"df":0,"docs":{},"o":{"df":0,"docs":{},"u":{"df":0,"docs":{},"g":{"df":0,"docs":{},"h":{"df":2,"docs":{"31":{"tf":1.0},"34":{"tf":1.0}}}}}}}},"w":{"a":{"df":0,"docs":{},"y":{"df":3,"docs":{"27":{"tf":1.0},"35":{"tf":1.0},"5":{"tf":1.0}}}},"df":0,"docs":{}}},"n":{"df":0,"docs":{},"o":{"df":0,"docs":{},"t":{"df":0,"docs":{},"h":{"df":2,"docs":{"32":{"tf":1.0},"33":{"tf":1.0}}}}},"y":{"df":0,"docs":{},"t":{"df":0,"docs":{},"h":{"df":1,"docs":{"29":{"tf":1.0}}}}}},"p":{"df":0,"docs":{},"i":{"df":1,"docs":{"30":{"tf":1.0}}},"p":{".":{"df":0,"docs":{},"e":{"df":0,"docs":{},"f":{"df":0,"docs":{},"i":{"df":2,"docs":{"12":{"tf":1.0},"8":{"tf":1.0}}}}}},"df":1,"docs":{"4":{"tf":1.4142135623730951}},"e":{"a":{"df":0,"docs":{},"r":{"df":2,"docs":{"13":{"tf":1.0},"17":{"tf":1.0}}}},"df":0,"docs":{}},"l":{"df":0,"docs":{},"i":{"c":{"df":11,"docs":{"0":{"tf":1.0},"1":{"tf":1.4142135623730951},"15":{"tf":1.0},"2":{"tf":1.0},"23":{"tf":1.4142135623730951},"25":{"tf":1.0},"26":{"tf":1.0},"28":{"tf":1.0},"4":{"tf":1.4142135623730951},"5":{"tf":2.23606797749979},"8":{"tf":1.4142135623730951}}},"df":0,"docs":{}}},"r":{"df":0,"docs":{},"o":{"df":0,"docs":{},"p":{"df":0,"docs":{},"r":{"df":0,"docs":{},"i":{"df":2,"docs":{"15":{"tf":1.0},"7":{"tf":1.0}}}}}}}},"t":{"df":1,"docs":{"10":{"tf":1.0}}}},"r":{"b":{"df":0,"docs":{},"i":{"df":0,"docs":{},"t":{"df":0,"docs":{},"r":{"a":{"df":0,"docs":{},"r":{"df":0,"docs":{},"i":{"df":1,"docs":{"32":{"tf":1.0}}}}},"df":0,"docs":{}}}}},"c":{"df":0,"docs":{},"h":{"df":1,"docs":{"35":{"tf":1.0}},"i":{"df":0,"docs":{},"t":{"df":0,"docs":{},"e":{"c":{"df":0,"docs":{},"t":{"df":0,"docs":{},"u":{"df":0,"docs":{},"r":{"df":2,"docs":{"15":{"tf":1.4142135623730951},"35":{"tf":1.4142135623730951}}}}}},"df":0,"docs":{}}}}}},"df":0,"docs":{},"e":{"df":0,"docs":{},"n":{"'":{"df":0,"docs":{},"t":{"df":1,"docs":{"27":{"tf":1.0}}}},"df":0,"docs":{}}},"g":{"df":0,"docs":{},"s":{"=":{"/":{"df":0,"docs":{},"s":{"df":0,"docs":{},"u":{"b":{"df":0,"docs":{},"s":{"df":0,"docs":{},"y":{"df":0,"docs":{},"s":{"df":0,"docs":{},"t":{"df":0,"docs":{},"e":{"df":0,"docs":{},"m":{":":{"df":0,"docs":{},"e":{"df":0,"docs":{},"f":{"df":0,"docs":{},"i":{"_":{"df":0,"docs":{},"r":{"df":0,"docs":{},"u":{"df":0,"docs":{},"n":{"df":0,"docs":{},"t":{"df":0,"docs":{},"i":{"df":0,"docs":{},"m":{"df":0,"docs":{},"e":{"_":{"d":{"df":0,"docs":{},"r":{"df":0,"docs":{},"i":{"df":0,"docs":{},"v":{"df":1,"docs":{"23":{"tf":1.0}}}}}},"df":0,"docs":{}},"df":0,"docs":{}}}}}}}}},"df":0,"docs":{}}}}},"df":0,"docs":{}}}}}}}},"df":0,"docs":{}}}},"df":0,"docs":{}},"df":0,"docs":{}},"u":{"df":0,"docs":{},"m":{"df":0,"docs":{},"e":{"df":0,"docs":{},"n":{"df":0,"docs":{},"t":{"df":3,"docs":{"21":{"tf":1.4142135623730951},"26":{"tf":1.0},"5":{"tf":1.0}}}}}}}},"r":{"a":{"df":0,"docs":{},"y":{"df":4,"docs":{"26":{"tf":1.0},"28":{"tf":1.0},"32":{"tf":1.0},"34":{"tf":2.0}}}},"df":0,"docs":{}},"t":{"df":0,"docs":{},"i":{"c":{"df":0,"docs":{},"l":{"df":1,"docs":{"33":{"tf":1.0}}}},"df":0,"docs":{}}}},"s":{"df":0,"docs":{},"s":{"df":0,"docs":{},"o":{"c":{"df":0,"docs":{},"i":{"df":1,"docs":{"33":{"tf":1.0}}}},"df":0,"docs":{}}}},"t":{"df":0,"docs":{},"t":{"df":0,"docs":{},"r":{"df":0,"docs":{},"i":{"b":{"df":0,"docs":{},"u":{"df":0,"docs":{},"t":{"df":1,"docs":{"33":{"tf":2.0}}}}},"df":0,"docs":{}}}}},"u":{"df":0,"docs":{},"t":{"df":0,"docs":{},"h":{"df":0,"docs":{},"e":{"df":0,"docs":{},"n":{"df":0,"docs":{},"t":{"df":1,"docs":{"33":{"tf":1.0}}}}}},"o":{"df":0,"docs":{},"m":{"a":{"df":0,"docs":{},"t":{"df":1,"docs":{"19":{"tf":1.0}}}},"df":0,"docs":{}}}}},"v":{"a":{"df":0,"docs":{},"i":{"df":0,"docs":{},"l":{"df":4,"docs":{"19":{"tf":1.0},"21":{"tf":1.4142135623730951},"25":{"tf":1.0},"30":{"tf":1.0}}}}},"df":0,"docs":{}},"w":{"a":{"df":0,"docs":{},"r":{"df":1,"docs":{"27":{"tf":1.0}}}},"df":0,"docs":{}}},"b":{"a":{"4":{"b":{"df":3,"docs":{"15":{"tf":1.0},"16":{"tf":1.0},"35":{"tf":1.0}}},"df":0,"docs":{}},"c":{"df":0,"docs":{},"k":{"df":0,"docs":{},"g":{"df":0,"docs":{},"r":{"df":0,"docs":{},"o":{"df":0,"docs":{},"u":{"df":0,"docs":{},"n":{"d":{"df":1,"docs":{"22":{"tf":1.0}}},"df":0,"docs":{}}}}}}}},"df":0,"docs":{}},"df":0,"docs":{},"e":{"c":{"a":{"df":0,"docs":{},"m":{"df":1,"docs":{"33":{"tf":1.0}}}},"df":0,"docs":{}},"df":1,"docs":{"33":{"tf":1.0}},"g":{"df":0,"docs":{},"i":{"df":0,"docs":{},"n":{"df":1,"docs":{"34":{"tf":1.0}}}}},"l":{"df":0,"docs":{},"o":{"df":0,"docs":{},"w":{"df":1,"docs":{"15":{"tf":1.0}}}}},"s":{"df":0,"docs":{},"t":{"df":2,"docs":{"21":{"tf":1.0},"30":{"tf":1.0}}}},"t":{"df":0,"docs":{},"w":{"df":0,"docs":{},"e":{"df":0,"docs":{},"e":{"df":0,"docs":{},"n":{"df":1,"docs":{"34":{"tf":1.0}}}}}}}},"g":{"df":0,"docs":{},"r":{"df":0,"docs":{},"x":{"df":1,"docs":{"22":{"tf":1.0}}}}},"i":{"df":0,"docs":{},"g":{"df":2,"docs":{"22":{"tf":1.0},"34":{"tf":1.0}}},"t":{"df":3,"docs":{"22":{"tf":1.4142135623730951},"33":{"tf":2.23606797749979},"35":{"tf":2.0}},"e":{"df":1,"docs":{"22":{"tf":1.0}}}}},"l":{"a":{"c":{"df":0,"docs":{},"k":{"df":1,"docs":{"22":{"tf":1.0}}}},"df":0,"docs":{}},"df":0,"docs":{},"i":{"df":0,"docs":{},"t":{"(":{"&":{"df":0,"docs":{},"s":{"df":0,"docs":{},"e":{"df":0,"docs":{},"l":{"df":0,"docs":{},"f":{"df":1,"docs":{"22":{"tf":1.4142135623730951}}}}}}},"df":0,"docs":{}},"df":1,"docs":{"22":{"tf":1.4142135623730951}}}},"o":{"c":{"df":0,"docs":{},"k":{"df":2,"docs":{"30":{"tf":1.0},"34":{"tf":1.0}},"i":{"df":0,"docs":{},"o":{"df":1,"docs":{"30":{"tf":1.0}}}}}},"df":0,"docs":{}},"t":{"df":1,"docs":{"22":{"tf":1.0}},"p":{"df":0,"docs":{},"i":{"df":0,"docs":{},"x":{"df":0,"docs":{},"e":{"df":0,"docs":{},"l":{"df":1,"docs":{"22":{"tf":2.0}}}}}}},"r":{"df":0,"docs":{},"e":{"df":0,"docs":{},"g":{"df":0,"docs":{},"i":{"df":0,"docs":{},"o":{"df":0,"docs":{},"n":{":":{":":{"df":0,"docs":{},"f":{"df":0,"docs":{},"u":{"df":0,"docs":{},"l":{"df":1,"docs":{"22":{"tf":1.4142135623730951}}}}}},"df":0,"docs":{}},"df":1,"docs":{"22":{"tf":1.0}}}}}}}}},"u":{"df":0,"docs":{},"e":{"df":1,"docs":{"22":{"tf":1.0}}}}},"o":{"df":0,"docs":{},"i":{"df":0,"docs":{},"l":{"df":0,"docs":{},"e":{"df":0,"docs":{},"r":{"df":0,"docs":{},"p":{"df":0,"docs":{},"l":{"df":1,"docs":{"5":{"tf":1.0}}}}}}}},"o":{"df":0,"docs":{},"k":{"df":1,"docs":{"0":{"tf":1.4142135623730951}}},"t":{"<":{"a":{"df":0,"docs":{},"r":{"c":{"df":0,"docs":{},"h":{">":{".":{"df":0,"docs":{},"e":{"df":0,"docs":{},"f":{"df":0,"docs":{},"i":{"df":1,"docs":{"35":{"tf":1.0}}}}}},"df":0,"docs":{}},"df":0,"docs":{}}},"df":0,"docs":{}}},"df":0,"docs":{}},"_":{"df":0,"docs":{},"s":{"df":0,"docs":{},"e":{"df":0,"docs":{},"r":{"df":0,"docs":{},"v":{"df":0,"docs":{},"i":{"c":{"df":2,"docs":{"20":{"tf":2.23606797749979},"21":{"tf":2.0}},"e":{"df":0,"docs":{},"s":{".":{"df":0,"docs":{},"s":{"df":0,"docs":{},"t":{"a":{"df":0,"docs":{},"l":{"df":0,"docs":{},"l":{"(":{"1":{"0":{"_":{"0":{"0":{"0":{"_":{"0":{"0":{"0":{"df":1,"docs":{"20":{"tf":1.0}}},"df":0,"docs":{}},"df":0,"docs":{}},"df":0,"docs":{}},"df":0,"docs":{}},"df":0,"docs":{}},"df":0,"docs":{}},"df":0,"docs":{}},"df":0,"docs":{}},"df":0,"docs":{}},"df":0,"docs":{}},"df":0,"docs":{}}}},"df":0,"docs":{}}}},"df":0,"docs":{}}}},"df":0,"docs":{}}}}}}},"a":{"a":{"6":{"4":{".":{"df":0,"docs":{},"e":{"df":0,"docs":{},"f":{"df":0,"docs":{},"i":{"df":1,"docs":{"35":{"tf":1.0}}}}}},"df":0,"docs":{}},"df":0,"docs":{}},"df":0,"docs":{}},"b":{"df":0,"docs":{},"l":{"df":1,"docs":{"35":{"tf":1.0}}}},"df":0,"docs":{},"r":{"df":0,"docs":{},"m":{".":{"df":0,"docs":{},"e":{"df":0,"docs":{},"f":{"df":0,"docs":{},"i":{"df":1,"docs":{"35":{"tf":1.0}}}}}},"df":0,"docs":{}}}},"df":11,"docs":{"15":{"tf":1.0},"16":{"tf":1.4142135623730951},"17":{"tf":1.7320508075688772},"23":{"tf":1.0},"25":{"tf":2.23606797749979},"26":{"tf":1.4142135623730951},"28":{"tf":1.0},"30":{"tf":1.0},"33":{"tf":1.7320508075688772},"34":{"tf":1.0},"35":{"tf":2.0}},"i":{"a":{"3":{"2":{".":{"df":0,"docs":{},"e":{"df":0,"docs":{},"f":{"df":0,"docs":{},"i":{"df":1,"docs":{"35":{"tf":1.0}}}}}},"df":0,"docs":{}},"df":0,"docs":{}},"6":{"4":{".":{"df":0,"docs":{},"e":{"df":0,"docs":{},"f":{"df":0,"docs":{},"i":{"df":1,"docs":{"35":{"tf":1.0}}}}}},"df":0,"docs":{}},"df":0,"docs":{}},"df":0,"docs":{}},"df":0,"docs":{}},"l":{"df":0,"docs":{},"o":{"a":{"d":{"df":1,"docs":{"25":{"tf":1.0}}},"df":0,"docs":{}},"df":0,"docs":{}}},"r":{"df":0,"docs":{},"i":{"df":0,"docs":{},"s":{"c":{"df":0,"docs":{},"v":{"1":{"2":{"8":{".":{"df":0,"docs":{},"e":{"df":0,"docs":{},"f":{"df":0,"docs":{},"i":{"df":1,"docs":{"35":{"tf":1.0}}}}}},"df":0,"docs":{}},"df":0,"docs":{}},"df":0,"docs":{}},"3":{"2":{".":{"df":0,"docs":{},"e":{"df":0,"docs":{},"f":{"df":0,"docs":{},"i":{"df":1,"docs":{"35":{"tf":1.0}}}}}},"df":0,"docs":{}},"df":0,"docs":{}},"6":{"4":{".":{"df":0,"docs":{},"e":{"df":0,"docs":{},"f":{"df":0,"docs":{},"i":{"df":1,"docs":{"35":{"tf":1.0}}}}}},"df":0,"docs":{}},"df":0,"docs":{}},"df":0,"docs":{}}},"df":0,"docs":{}}}},"s":{"df":0,"docs":{},"e":{"df":0,"docs":{},"r":{"df":0,"docs":{},"v":{"df":0,"docs":{},"i":{"c":{"df":5,"docs":{"20":{"tf":1.0},"21":{"tf":1.0},"22":{"tf":1.0},"25":{"tf":1.4142135623730951},"26":{"tf":1.0}},"e":{"_":{"a":{"c":{"c":{"df":0,"docs":{},"e":{"df":0,"docs":{},"s":{"df":0,"docs":{},"s":{"df":1,"docs":{"33":{"tf":1.4142135623730951}}}}}},"df":0,"docs":{}},"df":0,"docs":{}},"df":0,"docs":{}},"df":0,"docs":{},"s":{":":{":":{"df":0,"docs":{},"i":{"df":0,"docs":{},"m":{"a":{"df":0,"docs":{},"g":{"df":0,"docs":{},"e":{"_":{"df":0,"docs":{},"h":{"a":{"df":0,"docs":{},"n":{"d":{"df":0,"docs":{},"l":{"df":1,"docs":{"21":{"tf":1.0}}}},"df":0,"docs":{}}},"df":0,"docs":{}}},"df":0,"docs":{}}}},"df":0,"docs":{}}},"l":{"df":0,"docs":{},"o":{"c":{"a":{"df":0,"docs":{},"t":{"df":0,"docs":{},"e":{"_":{"d":{"df":0,"docs":{},"e":{"df":0,"docs":{},"v":{"df":0,"docs":{},"i":{"c":{"df":0,"docs":{},"e":{"_":{"df":0,"docs":{},"p":{"a":{"df":0,"docs":{},"t":{"df":0,"docs":{},"h":{"df":1,"docs":{"19":{"tf":1.0}}}}},"df":0,"docs":{}}},"df":0,"docs":{}}},"df":0,"docs":{}}}}},"df":0,"docs":{},"h":{"a":{"df":0,"docs":{},"n":{"d":{"df":0,"docs":{},"l":{"df":1,"docs":{"19":{"tf":1.0}},"e":{"_":{"b":{"df":0,"docs":{},"u":{"df":0,"docs":{},"f":{"df":0,"docs":{},"f":{"df":1,"docs":{"19":{"tf":1.0}}}}}},"df":0,"docs":{}},"df":0,"docs":{}}}},"df":0,"docs":{}}},"df":0,"docs":{}}},"df":0,"docs":{}}}},"df":0,"docs":{}},"df":0,"docs":{}}},"o":{"df":0,"docs":{},"p":{"df":0,"docs":{},"e":{"df":0,"docs":{},"n":{"_":{"df":0,"docs":{},"p":{"df":0,"docs":{},"r":{"df":0,"docs":{},"o":{"df":0,"docs":{},"t":{"df":0,"docs":{},"o":{"c":{"df":0,"docs":{},"o":{"df":0,"docs":{},"l":{"_":{"df":0,"docs":{},"e":{"df":0,"docs":{},"x":{"c":{"df":0,"docs":{},"l":{"df":0,"docs":{},"u":{"df":0,"docs":{},"s":{"df":1,"docs":{"19":{"tf":1.4142135623730951}}}}}},"df":0,"docs":{}}}},"df":1,"docs":{"19":{"tf":1.0}}}}},"df":0,"docs":{}}}}}}},"df":0,"docs":{}}}}}},"df":0,"docs":{}},"df":0,"docs":{}}}},"df":0,"docs":{}}}}}},"x":{"6":{"4":{".":{"df":0,"docs":{},"e":{"df":0,"docs":{},"f":{"df":0,"docs":{},"i":{"df":2,"docs":{"15":{"tf":1.0},"35":{"tf":1.0}}}}}},"df":0,"docs":{}},"df":0,"docs":{}},"df":0,"docs":{}}}},"r":{"d":{"df":0,"docs":{},"e":{"df":0,"docs":{},"r":{"df":1,"docs":{"22":{"tf":2.23606797749979}}}}},"df":0,"docs":{}},"t":{"df":0,"docs":{},"h":{"df":4,"docs":{"21":{"tf":1.4142135623730951},"25":{"tf":1.0},"26":{"tf":1.0},"33":{"tf":1.0}}}}},"t":{".":{"df":0,"docs":{},"g":{"df":0,"docs":{},"e":{"df":0,"docs":{},"t":{"_":{"df":0,"docs":{},"h":{"a":{"df":0,"docs":{},"n":{"d":{"df":0,"docs":{},"l":{"df":0,"docs":{},"e":{"_":{"df":0,"docs":{},"f":{"df":0,"docs":{},"o":{"df":0,"docs":{},"r":{"_":{"df":0,"docs":{},"p":{"df":0,"docs":{},"r":{"df":0,"docs":{},"o":{"df":0,"docs":{},"t":{"df":0,"docs":{},"o":{"c":{"df":0,"docs":{},"o":{"df":0,"docs":{},"l":{":":{":":{"<":{"df":0,"docs":{},"g":{"df":0,"docs":{},"r":{"a":{"df":0,"docs":{},"p":{"df":0,"docs":{},"h":{"df":0,"docs":{},"i":{"c":{"df":0,"docs":{},"s":{"df":0,"docs":{},"o":{"df":0,"docs":{},"u":{"df":0,"docs":{},"t":{"df":0,"docs":{},"p":{"df":0,"docs":{},"u":{"df":0,"docs":{},"t":{"df":1,"docs":{"22":{"tf":1.0}}}}}}}}}},"df":0,"docs":{}}}}},"df":0,"docs":{}}},"r":{"df":0,"docs":{},"n":{"df":0,"docs":{},"g":{"df":1,"docs":{"22":{"tf":1.0}}}}}},"df":0,"docs":{}},"df":0,"docs":{}},"df":0,"docs":{}}}},"df":0,"docs":{}}}}}}},"df":0,"docs":{}}}}},"df":0,"docs":{}}}},"df":0,"docs":{}}},"df":0,"docs":{}}},"df":0,"docs":{}}}},"o":{"df":0,"docs":{},"p":{"df":0,"docs":{},"e":{"df":0,"docs":{},"n":{"_":{"df":0,"docs":{},"p":{"df":0,"docs":{},"r":{"df":0,"docs":{},"o":{"df":0,"docs":{},"t":{"df":0,"docs":{},"o":{"c":{"df":0,"docs":{},"o":{"df":0,"docs":{},"l":{"_":{"df":0,"docs":{},"e":{"df":0,"docs":{},"x":{"c":{"df":0,"docs":{},"l":{"df":0,"docs":{},"u":{"df":0,"docs":{},"s":{"df":0,"docs":{},"i":{"df":0,"docs":{},"v":{"df":0,"docs":{},"e":{":":{":":{"<":{"df":0,"docs":{},"g":{"df":0,"docs":{},"r":{"a":{"df":0,"docs":{},"p":{"df":0,"docs":{},"h":{"df":0,"docs":{},"i":{"c":{"df":0,"docs":{},"s":{"df":0,"docs":{},"o":{"df":0,"docs":{},"u":{"df":0,"docs":{},"t":{"df":0,"docs":{},"p":{"df":0,"docs":{},"u":{"df":0,"docs":{},"t":{">":{"(":{"df":0,"docs":{},"g":{"df":0,"docs":{},"o":{"df":0,"docs":{},"p":{"_":{"df":0,"docs":{},"h":{"a":{"df":0,"docs":{},"n":{"d":{"df":0,"docs":{},"l":{"df":1,"docs":{"22":{"tf":1.0}}}},"df":0,"docs":{}}},"df":0,"docs":{}}},"df":0,"docs":{}}}}},"df":0,"docs":{}},"df":0,"docs":{}}}}}}}}},"df":0,"docs":{}}}}},"df":0,"docs":{}}},"r":{"df":0,"docs":{},"n":{"df":0,"docs":{},"g":{">":{"(":{"df":0,"docs":{},"r":{"df":0,"docs":{},"n":{"df":0,"docs":{},"g":{"_":{"df":0,"docs":{},"h":{"a":{"df":0,"docs":{},"n":{"d":{"df":0,"docs":{},"l":{"df":1,"docs":{"22":{"tf":1.0}}}},"df":0,"docs":{}}},"df":0,"docs":{}}},"df":0,"docs":{}}}}},"df":0,"docs":{}},"df":0,"docs":{}}}}},"df":0,"docs":{}},"df":0,"docs":{}},"df":0,"docs":{}}}}}}}},"df":0,"docs":{}}}},"df":0,"docs":{}}}},"df":0,"docs":{}}}}}}},"df":0,"docs":{}}}}}},"df":1,"docs":{"22":{"tf":1.0}}},"u":{"df":0,"docs":{},"f":{")":{".":{"df":0,"docs":{},"e":{"df":0,"docs":{},"x":{"df":0,"docs":{},"p":{"df":0,"docs":{},"e":{"c":{"df":0,"docs":{},"t":{"(":{"\"":{"df":0,"docs":{},"g":{"df":0,"docs":{},"e":{"df":0,"docs":{},"t":{"_":{"df":0,"docs":{},"r":{"df":0,"docs":{},"n":{"df":0,"docs":{},"g":{"df":1,"docs":{"22":{"tf":1.0}}}}}},"df":0,"docs":{}}}}},"df":0,"docs":{}},"df":0,"docs":{}}},"df":0,"docs":{}}}}}},"df":0,"docs":{}},"df":1,"docs":{"22":{"tf":1.0}},"f":{"df":0,"docs":{},"e":{"df":0,"docs":{},"r":{".":{"b":{"df":0,"docs":{},"l":{"df":0,"docs":{},"i":{"df":0,"docs":{},"t":{"(":{"&":{"df":0,"docs":{},"m":{"df":0,"docs":{},"u":{"df":0,"docs":{},"t":{"df":1,"docs":{"22":{"tf":1.0}}}}}},"df":0,"docs":{}},"df":0,"docs":{}}}}},"df":0,"docs":{},"p":{"df":0,"docs":{},"i":{"df":0,"docs":{},"x":{"df":0,"docs":{},"e":{"df":0,"docs":{},"l":{"(":{"df":0,"docs":{},"p":{".":{"df":0,"docs":{},"x":{"df":1,"docs":{"22":{"tf":1.0}}}},"df":0,"docs":{}},"x":{"df":1,"docs":{"22":{"tf":1.0}}}},"df":0,"docs":{}}}}}}},":":{":":{"b":{"df":0,"docs":{},"l":{"df":0,"docs":{},"i":{"df":0,"docs":{},"t":{"df":1,"docs":{"22":{"tf":1.0}}}}}},"df":0,"docs":{},"n":{"df":0,"docs":{},"e":{"df":0,"docs":{},"w":{"(":{"df":0,"docs":{},"w":{"df":0,"docs":{},"i":{"d":{"df":0,"docs":{},"t":{"df":0,"docs":{},"h":{"df":1,"docs":{"22":{"tf":1.0}}}}},"df":0,"docs":{}}}},"df":0,"docs":{}}}}},"df":0,"docs":{}},"df":1,"docs":{"22":{"tf":4.358898943540674}}}}}},"i":{"df":0,"docs":{},"l":{"d":{"df":4,"docs":{"0":{"tf":1.0},"23":{"tf":1.4142135623730951},"6":{"tf":1.0},"8":{"tf":1.7320508075688772}}},"df":0,"docs":{}}}},"y":{"df":0,"docs":{},"t":{"df":0,"docs":{},"e":{"df":2,"docs":{"27":{"tf":1.4142135623730951},"32":{"tf":1.0}}}}}},"c":{"1":{"2":{"a":{"7":{"3":{"2":{"8":{"df":2,"docs":{"15":{"tf":1.0},"35":{"tf":1.0}}},"df":0,"docs":{}},"df":0,"docs":{}},"df":0,"docs":{}},"df":0,"docs":{}},"df":0,"docs":{}},"df":0,"docs":{}},"a":{"df":0,"docs":{},"l":{"df":0,"docs":{},"l":{"df":6,"docs":{"21":{"tf":2.0},"22":{"tf":1.0},"25":{"tf":1.0},"26":{"tf":1.4142135623730951},"35":{"tf":1.0},"5":{"tf":1.0}}}},"n":{"'":{"df":0,"docs":{},"t":{"df":2,"docs":{"29":{"tf":1.0},"30":{"tf":1.0}}}},"df":0,"docs":{},"o":{"df":0,"docs":{},"n":{"df":1,"docs":{"24":{"tf":1.0}}}}},"p":{"df":0,"docs":{},"i":{"df":0,"docs":{},"t":{"df":1,"docs":{"15":{"tf":1.0}}}}},"r":{"df":0,"docs":{},"e":{"df":2,"docs":{"16":{"tf":1.0},"33":{"tf":1.0}}},"g":{"df":0,"docs":{},"o":{"/":{"c":{"df":0,"docs":{},"o":{"df":0,"docs":{},"n":{"df":0,"docs":{},"f":{"df":0,"docs":{},"i":{"df":0,"docs":{},"g":{".":{"df":0,"docs":{},"t":{"df":0,"docs":{},"o":{"df":0,"docs":{},"m":{"df":0,"docs":{},"l":{"df":1,"docs":{"23":{"tf":1.0}}}}}}},"df":0,"docs":{}}}}}}},"df":0,"docs":{}},"df":3,"docs":{"22":{"tf":1.0},"4":{"tf":1.4142135623730951},"8":{"tf":1.0}}}}},"s":{"df":0,"docs":{},"e":{"df":5,"docs":{"15":{"tf":1.0},"19":{"tf":1.4142135623730951},"20":{"tf":1.0},"21":{"tf":1.0},"33":{"tf":1.0}}}},"u":{"df":0,"docs":{},"s":{"df":1,"docs":{"33":{"tf":1.0}}}}},"d":{"df":1,"docs":{"4":{"tf":1.0}}},"df":1,"docs":{"23":{"tf":1.0}},"e":{"df":0,"docs":{},"n":{"df":0,"docs":{},"t":{"df":0,"docs":{},"e":{"df":0,"docs":{},"r":{"df":1,"docs":{"22":{"tf":1.0}}}}}}},"h":{"a":{"df":0,"docs":{},"n":{"df":0,"docs":{},"g":{"df":4,"docs":{"22":{"tf":1.0},"23":{"tf":1.0},"33":{"tf":1.0},"4":{"tf":1.0}}}},"o":{"df":1,"docs":{"22":{"tf":1.0}}},"p":{"df":0,"docs":{},"t":{"df":0,"docs":{},"e":{"df":0,"docs":{},"r":{"df":3,"docs":{"18":{"tf":1.0},"24":{"tf":1.0},"30":{"tf":1.0}}}}}}},"df":0,"docs":{},"o":{"df":0,"docs":{},"o":{"df":0,"docs":{},"s":{"df":1,"docs":{"22":{"tf":1.0}}}},"s":{"df":0,"docs":{},"e":{"df":0,"docs":{},"n":{"df":1,"docs":{"22":{"tf":1.0}}}}}}},"l":{"df":0,"docs":{},"e":{"a":{"df":0,"docs":{},"r":{"df":2,"docs":{"16":{"tf":1.0},"34":{"tf":1.0}}}},"df":0,"docs":{}},"o":{"df":0,"docs":{},"s":{"df":0,"docs":{},"e":{"df":1,"docs":{"19":{"tf":1.0}}}}}},"o":{"d":{"df":0,"docs":{},"e":{"df":3,"docs":{"11":{"tf":1.4142135623730951},"22":{"tf":1.4142135623730951},"5":{"tf":1.0}}}},"df":0,"docs":{},"l":{"df":0,"docs":{},"l":{"df":0,"docs":{},"e":{"c":{"df":0,"docs":{},"t":{"df":1,"docs":{"33":{"tf":1.0}}}},"df":0,"docs":{}}}},"m":{"b":{"df":0,"docs":{},"i":{"df":0,"docs":{},"n":{"df":1,"docs":{"21":{"tf":1.0}}}}},"df":0,"docs":{},"m":{"a":{"df":0,"docs":{},"n":{"d":{"df":2,"docs":{"16":{"tf":1.0},"8":{"tf":1.0}}},"df":0,"docs":{}}},"df":0,"docs":{},"o":{"df":0,"docs":{},"n":{"df":0,"docs":{},"l":{"df":0,"docs":{},"i":{"df":2,"docs":{"30":{"tf":1.0},"5":{"tf":1.0}}}}}}},"p":{"df":0,"docs":{},"i":{"df":0,"docs":{},"l":{"df":1,"docs":{"7":{"tf":1.0}}}},"l":{"df":0,"docs":{},"e":{"df":0,"docs":{},"t":{"df":1,"docs":{"5":{"tf":1.0}}},"x":{"df":1,"docs":{"22":{"tf":1.0}}}}},"u":{"df":0,"docs":{},"t":{"df":1,"docs":{"17":{"tf":1.0}}}}}},"n":{"c":{"df":0,"docs":{},"e":{"df":0,"docs":{},"p":{"df":0,"docs":{},"t":{"df":2,"docs":{"0":{"tf":1.0},"24":{"tf":1.4142135623730951}}}}}},"d":{"df":0,"docs":{},"i":{"df":0,"docs":{},"t":{"df":1,"docs":{"28":{"tf":1.0}}}}},"df":0,"docs":{},"f":{"df":0,"docs":{},"i":{"df":0,"docs":{},"g":{"df":0,"docs":{},"u":{"df":0,"docs":{},"r":{"df":1,"docs":{"35":{"tf":1.0}}}}}},"o":{"df":0,"docs":{},"r":{"df":0,"docs":{},"m":{"df":1,"docs":{"15":{"tf":1.0}}}}}},"s":{"df":0,"docs":{},"i":{"df":0,"docs":{},"s":{"df":0,"docs":{},"t":{"df":2,"docs":{"28":{"tf":1.0},"32":{"tf":1.0}}}}},"o":{"df":0,"docs":{},"l":{"df":1,"docs":{"31":{"tf":1.0}}}},"u":{"df":0,"docs":{},"m":{"df":1,"docs":{"26":{"tf":1.0}}}}},"t":{"a":{"df":0,"docs":{},"i":{"df":0,"docs":{},"n":{"df":6,"docs":{"12":{"tf":1.0},"16":{"tf":1.0},"18":{"tf":1.0},"31":{"tf":1.0},"34":{"tf":1.4142135623730951},"35":{"tf":1.0}}}}},"df":0,"docs":{},"e":{"df":0,"docs":{},"n":{"df":0,"docs":{},"t":{"df":2,"docs":{"24":{"tf":1.0},"4":{"tf":1.0}}}}},"r":{"df":0,"docs":{},"i":{"b":{"df":0,"docs":{},"u":{"df":0,"docs":{},"t":{"df":1,"docs":{"30":{"tf":1.0}}}}},"df":0,"docs":{}}}},"v":{"df":0,"docs":{},"e":{"df":0,"docs":{},"n":{"df":0,"docs":{},"i":{"df":1,"docs":{"21":{"tf":1.0}}}},"r":{"df":0,"docs":{},"t":{"_":{"d":{"df":0,"docs":{},"e":{"df":0,"docs":{},"v":{"df":0,"docs":{},"i":{"c":{"df":0,"docs":{},"e":{"_":{"df":0,"docs":{},"p":{"a":{"df":0,"docs":{},"t":{"df":0,"docs":{},"h":{"_":{"df":0,"docs":{},"t":{"df":0,"docs":{},"o":{"_":{"df":0,"docs":{},"t":{"df":0,"docs":{},"e":{"df":0,"docs":{},"x":{"df":0,"docs":{},"t":{"df":2,"docs":{"20":{"tf":1.0},"21":{"tf":1.0}}}}}}},"df":0,"docs":{}}}},"df":0,"docs":{}}}},"df":0,"docs":{}}},"df":0,"docs":{}}},"df":0,"docs":{}}}}},"df":0,"docs":{}},"df":2,"docs":{"21":{"tf":1.0},"31":{"tf":1.0}}}}}}},"p":{"df":0,"docs":{},"i":{"df":5,"docs":{"11":{"tf":1.4142135623730951},"15":{"tf":1.0},"16":{"tf":1.0},"22":{"tf":1.4142135623730951},"34":{"tf":1.0}}}},"r":{"df":0,"docs":{},"e":{":":{":":{"df":0,"docs":{},"m":{"df":0,"docs":{},"e":{"df":0,"docs":{},"m":{"df":1,"docs":{"22":{"tf":1.0}}}}}},"df":0,"docs":{}},"df":3,"docs":{"22":{"tf":1.0},"28":{"tf":1.0},"5":{"tf":1.0}}}},"u":{"df":0,"docs":{},"p":{"df":0,"docs":{},"l":{"df":2,"docs":{"20":{"tf":1.0},"34":{"tf":1.0}}}}},"v":{"df":0,"docs":{},"e":{"df":0,"docs":{},"r":{"df":1,"docs":{"30":{"tf":1.0}}}}}},"p":{"df":3,"docs":{"11":{"tf":1.4142135623730951},"12":{"tf":1.0},"16":{"tf":1.0}}},"r":{"a":{"df":0,"docs":{},"t":{"df":0,"docs":{},"e":{"df":3,"docs":{"22":{"tf":1.4142135623730951},"36":{"tf":2.0},"5":{"tf":2.0}}}}},"df":0,"docs":{},"e":{"a":{"df":0,"docs":{},"t":{"df":8,"docs":{"1":{"tf":1.0},"12":{"tf":1.0},"13":{"tf":1.0},"15":{"tf":1.4142135623730951},"16":{"tf":1.7320508075688772},"2":{"tf":1.0},"22":{"tf":1.7320508075688772},"4":{"tf":1.4142135623730951}}}},"df":0,"docs":{}},"i":{"df":0,"docs":{},"t":{"df":0,"docs":{},"i":{"c":{"df":1,"docs":{"24":{"tf":1.0}}},"df":0,"docs":{}}}}},"u":{"df":0,"docs":{},"l":{"df":0,"docs":{},"m":{"df":0,"docs":{},"i":{"df":0,"docs":{},"n":{"df":1,"docs":{"25":{"tf":1.0}}}}}},"r":{"df":0,"docs":{},"r":{"df":0,"docs":{},"e":{"df":0,"docs":{},"n":{"df":0,"docs":{},"t":{"df":5,"docs":{"20":{"tf":1.0},"21":{"tf":1.0},"24":{"tf":1.0},"5":{"tf":1.0},"7":{"tf":1.0}}}}}}}},"y":{"c":{"df":0,"docs":{},"l":{"df":1,"docs":{"33":{"tf":1.0}}}},"df":0,"docs":{}}},"d":{"a":{"df":0,"docs":{},"t":{"a":{"df":5,"docs":{"16":{"tf":1.0},"21":{"tf":1.4142135623730951},"31":{"tf":1.0},"32":{"tf":1.0},"34":{"tf":1.0}}},"df":0,"docs":{}}},"df":0,"docs":{},"e":{"a":{"df":0,"docs":{},"l":{"df":1,"docs":{"33":{"tf":1.0}}}},"b":{"df":0,"docs":{},"i":{"a":{"df":0,"docs":{},"n":{"/":{"df":0,"docs":{},"u":{"b":{"df":0,"docs":{},"u":{"df":0,"docs":{},"n":{"df":0,"docs":{},"t":{"df":0,"docs":{},"u":{"df":1,"docs":{"10":{"tf":1.0}}}}}}},"df":0,"docs":{}}},"df":1,"docs":{"11":{"tf":1.0}}}},"df":0,"docs":{}}},"df":0,"docs":{},"f":{"a":{"df":0,"docs":{},"u":{"df":0,"docs":{},"l":{"df":0,"docs":{},"t":{"df":3,"docs":{"21":{"tf":1.0},"23":{"tf":1.0},"35":{"tf":1.0}}}}}},"df":0,"docs":{},"i":{"df":0,"docs":{},"n":{"df":4,"docs":{"22":{"tf":1.0},"30":{"tf":1.0},"34":{"tf":1.0},"5":{"tf":1.0}}}}},"l":{"df":0,"docs":{},"e":{"df":0,"docs":{},"t":{"df":1,"docs":{"33":{"tf":1.0}}}},"l":{"df":1,"docs":{"17":{"tf":1.0}}}},"p":{"df":0,"docs":{},"e":{"df":0,"docs":{},"n":{"d":{"df":6,"docs":{"10":{"tf":1.7320508075688772},"11":{"tf":1.0},"15":{"tf":1.0},"17":{"tf":1.0},"3":{"tf":1.0},"4":{"tf":1.0}}},"df":0,"docs":{}}}},"r":{"df":0,"docs":{},"i":{"df":0,"docs":{},"v":{"df":0,"docs":{},"e":{"(":{"c":{"df":0,"docs":{},"l":{"df":0,"docs":{},"o":{"df":0,"docs":{},"n":{"df":1,"docs":{"22":{"tf":1.0}}}}}},"df":0,"docs":{}},"df":0,"docs":{}}}}},"s":{"c":{"df":0,"docs":{},"r":{"df":0,"docs":{},"i":{"b":{"df":5,"docs":{"0":{"tf":1.0},"1":{"tf":1.0},"25":{"tf":1.0},"31":{"tf":1.0},"34":{"tf":1.0}}},"df":0,"docs":{}}}},"df":0,"docs":{},"t":{"df":1,"docs":{"22":{"tf":1.4142135623730951}},"r":{"df":0,"docs":{},"u":{"c":{"df":0,"docs":{},"t":{"df":1,"docs":{"16":{"tf":1.0}}}},"df":0,"docs":{}}}}},"t":{"a":{"df":0,"docs":{},"i":{"df":0,"docs":{},"l":{"df":8,"docs":{"10":{"tf":1.0},"11":{"tf":1.0},"15":{"tf":1.0},"20":{"tf":1.0},"27":{"tf":1.0},"30":{"tf":1.0},"31":{"tf":1.4142135623730951},"33":{"tf":1.0}}}}},"df":0,"docs":{}},"v":{"df":0,"docs":{},"i":{"c":{"df":4,"docs":{"19":{"tf":1.0},"29":{"tf":1.4142135623730951},"30":{"tf":1.0},"31":{"tf":2.8284271247461903}},"e":{"_":{"df":0,"docs":{},"p":{"a":{"df":0,"docs":{},"t":{"df":0,"docs":{},"h":{"_":{"df":0,"docs":{},"t":{"df":0,"docs":{},"o":{"_":{"df":0,"docs":{},"t":{"df":0,"docs":{},"e":{"df":0,"docs":{},"x":{"df":0,"docs":{},"t":{"_":{"df":0,"docs":{},"h":{"a":{"df":0,"docs":{},"n":{"d":{"df":0,"docs":{},"l":{"df":2,"docs":{"20":{"tf":1.4142135623730951},"21":{"tf":1.7320508075688772}}}},"df":0,"docs":{}}},"df":0,"docs":{}}},"df":2,"docs":{"20":{"tf":1.4142135623730951},"21":{"tf":1.4142135623730951}}}}}}},"df":0,"docs":{}}}},"df":0,"docs":{}}}},"df":0,"docs":{}}},"df":0,"docs":{},"p":{"a":{"df":0,"docs":{},"t":{"df":0,"docs":{},"h":{"df":0,"docs":{},"t":{"df":0,"docs":{},"o":{"df":0,"docs":{},"t":{"df":0,"docs":{},"e":{"df":0,"docs":{},"x":{"df":0,"docs":{},"t":{"df":2,"docs":{"20":{"tf":1.4142135623730951},"21":{"tf":1.7320508075688772}}}}}}}}}}},"df":0,"docs":{}}}},"df":0,"docs":{}}}},"i":{"df":0,"docs":{},"f":{"df":0,"docs":{},"f":{"df":0,"docs":{},"e":{"df":0,"docs":{},"r":{"df":5,"docs":{"20":{"tf":1.0},"21":{"tf":1.0},"32":{"tf":1.0},"35":{"tf":1.0},"5":{"tf":1.7320508075688772}}}}}},"m":{"df":1,"docs":{"22":{"tf":1.4142135623730951}}},"r":{"df":0,"docs":{},"e":{"c":{"df":0,"docs":{},"t":{"df":0,"docs":{},"l":{"df":0,"docs":{},"i":{"df":1,"docs":{"29":{"tf":1.0}}}},"o":{"df":0,"docs":{},"r":{"df":0,"docs":{},"i":{"df":6,"docs":{"11":{"tf":1.4142135623730951},"12":{"tf":1.0},"13":{"tf":1.0},"15":{"tf":1.4142135623730951},"16":{"tf":1.0},"4":{"tf":1.0}}}}}}},"df":0,"docs":{}}},"s":{"c":{"a":{"df":0,"docs":{},"r":{"d":{"df":1,"docs":{"21":{"tf":1.0}}},"df":0,"docs":{}}},"df":0,"docs":{}},"df":0,"docs":{},"k":{"df":5,"docs":{"16":{"tf":1.0},"27":{"tf":1.0},"29":{"tf":1.0},"31":{"tf":1.0},"34":{"tf":2.0}}},"p":{"df":0,"docs":{},"l":{"a":{"df":0,"docs":{},"y":{"df":0,"docs":{},"o":{"df":0,"docs":{},"n":{"df":0,"docs":{},"l":{"df":0,"docs":{},"i":{"df":1,"docs":{"20":{"tf":1.0}}},"y":{"(":{"df":0,"docs":{},"t":{"df":0,"docs":{},"r":{"df":0,"docs":{},"u":{"df":2,"docs":{"20":{"tf":1.0},"21":{"tf":1.0}}}}}},"df":0,"docs":{}}}}}}},"df":0,"docs":{}}},"t":{"df":0,"docs":{},"i":{"df":0,"docs":{},"n":{"c":{"df":0,"docs":{},"t":{"df":1,"docs":{"25":{"tf":1.0}}}},"df":0,"docs":{}}}}},"v":{"df":0,"docs":{},"e":{"df":0,"docs":{},"r":{"df":0,"docs":{},"s":{"df":1,"docs":{"30":{"tf":1.0}}}}}}},"n":{"df":0,"docs":{},"f":{"df":1,"docs":{"10":{"tf":1.0}}}},"o":{"c":{"df":0,"docs":{},"u":{"df":0,"docs":{},"m":{"df":0,"docs":{},"e":{"df":0,"docs":{},"n":{"df":0,"docs":{},"t":{"df":4,"docs":{"11":{"tf":1.0},"21":{"tf":1.0},"24":{"tf":1.0},"31":{"tf":1.0}}}}}}}},"df":1,"docs":{"5":{"tf":1.0}},"e":{"df":0,"docs":{},"s":{"df":0,"docs":{},"n":{"'":{"df":0,"docs":{},"t":{"df":1,"docs":{"15":{"tf":1.0}}}},"df":0,"docs":{}}}},"n":{"'":{"df":0,"docs":{},"t":{"df":2,"docs":{"32":{"tf":1.0},"7":{"tf":1.0}}}},"df":0,"docs":{}},"w":{"df":0,"docs":{},"n":{"df":1,"docs":{"17":{"tf":1.0}}}}},"r":{"a":{"df":0,"docs":{},"w":{"_":{"df":0,"docs":{},"s":{"df":0,"docs":{},"i":{"df":0,"docs":{},"e":{"df":0,"docs":{},"r":{"df":0,"docs":{},"p":{"df":0,"docs":{},"i":{"df":0,"docs":{},"n":{"df":0,"docs":{},"s":{"df":0,"docs":{},"k":{"df":0,"docs":{},"i":{"(":{"b":{"df":0,"docs":{},"t":{")":{".":{"df":0,"docs":{},"u":{"df":0,"docs":{},"n":{"df":0,"docs":{},"w":{"df":0,"docs":{},"r":{"a":{"df":0,"docs":{},"p":{"df":1,"docs":{"22":{"tf":1.0}}}},"df":0,"docs":{}}}}}},"df":0,"docs":{}},"df":1,"docs":{"22":{"tf":1.0}}}},"df":0,"docs":{}},"df":0,"docs":{}}}}}}}}}}}},"df":1,"docs":{"22":{"tf":2.6457513110645907}}}},"df":0,"docs":{},"i":{"df":0,"docs":{},"v":{"df":0,"docs":{},"e":{"df":5,"docs":{"13":{"tf":1.7320508075688772},"14":{"tf":1.0},"15":{"tf":1.4142135623730951},"17":{"tf":1.0},"29":{"tf":1.0}},"r":{"df":3,"docs":{"23":{"tf":1.7320508075688772},"25":{"tf":1.0},"28":{"tf":1.0}}}}}},"o":{"df":0,"docs":{},"p":{"df":1,"docs":{"19":{"tf":1.0}}}}},"u":{"df":0,"docs":{},"e":{"df":1,"docs":{"33":{"tf":1.0}}},"r":{"df":0,"docs":{},"e":{"df":4,"docs":{"25":{"tf":1.0},"26":{"tf":1.0},"30":{"tf":1.4142135623730951},"33":{"tf":1.0}}}}}},"df":0,"docs":{},"e":{"a":{"c":{"df":0,"docs":{},"h":{"df":6,"docs":{"21":{"tf":1.4142135623730951},"22":{"tf":1.4142135623730951},"32":{"tf":1.4142135623730951},"33":{"tf":1.0},"34":{"tf":1.0},"5":{"tf":1.0}}}},"df":0,"docs":{},"r":{"df":0,"docs":{},"l":{"df":0,"docs":{},"i":{"df":1,"docs":{"25":{"tf":1.0}}}}},"s":{"df":1,"docs":{"11":{"tf":1.0}},"i":{"df":0,"docs":{},"e":{"df":0,"docs":{},"s":{"df":0,"docs":{},"t":{"df":1,"docs":{"7":{"tf":1.0}}}}}}}},"d":{"df":0,"docs":{},"k":{"2":{"df":1,"docs":{"10":{"tf":1.0}}},"df":0,"docs":{}}},"df":0,"docs":{},"f":{"df":0,"docs":{},"f":{"df":0,"docs":{},"i":{"c":{"df":0,"docs":{},"i":{"df":1,"docs":{"22":{"tf":1.0}}}},"df":0,"docs":{}}},"i":{"/":{"b":{"df":0,"docs":{},"o":{"df":0,"docs":{},"o":{"df":0,"docs":{},"t":{"df":1,"docs":{"15":{"tf":1.4142135623730951}}}}}},"df":0,"docs":{}},"\\":{"b":{"df":0,"docs":{},"o":{"df":0,"docs":{},"o":{"df":0,"docs":{},"t":{"\\":{"b":{"df":0,"docs":{},"o":{"df":0,"docs":{},"o":{"df":0,"docs":{},"t":{"df":0,"docs":{},"x":{"6":{"4":{".":{"df":0,"docs":{},"e":{"df":0,"docs":{},"f":{"df":0,"docs":{},"i":{"df":1,"docs":{"20":{"tf":1.0}}}}}},"df":0,"docs":{}},"df":0,"docs":{}},"df":0,"docs":{}}}}}},"df":0,"docs":{}},"df":1,"docs":{"35":{"tf":1.0}}}}}},"df":0,"docs":{}},"_":{"b":{"df":0,"docs":{},"o":{"df":0,"docs":{},"o":{"df":0,"docs":{},"t":{"_":{"df":0,"docs":{},"s":{"df":0,"docs":{},"e":{"df":0,"docs":{},"r":{"df":0,"docs":{},"v":{"df":0,"docs":{},"i":{"c":{"df":1,"docs":{"26":{"tf":1.0}},"e":{"_":{"d":{"df":0,"docs":{},"r":{"df":0,"docs":{},"i":{"df":0,"docs":{},"v":{"df":1,"docs":{"23":{"tf":1.0}}}}}},"df":0,"docs":{}},"df":0,"docs":{}}},"df":0,"docs":{}}}}}}},"df":0,"docs":{}}}}},"df":0,"docs":{},"r":{"df":0,"docs":{},"u":{"df":0,"docs":{},"n":{"df":0,"docs":{},"t":{"df":0,"docs":{},"i":{"df":0,"docs":{},"m":{"df":0,"docs":{},"e":{"_":{"d":{"df":0,"docs":{},"r":{"df":0,"docs":{},"i":{"df":0,"docs":{},"v":{"df":1,"docs":{"23":{"tf":1.0}}}}}},"df":0,"docs":{},"s":{"df":0,"docs":{},"e":{"df":0,"docs":{},"r":{"df":0,"docs":{},"v":{"df":0,"docs":{},"i":{"c":{"df":1,"docs":{"26":{"tf":1.0}}},"df":0,"docs":{}}}}}}},"df":0,"docs":{}}}}}}}},"s":{"df":0,"docs":{},"y":{"df":0,"docs":{},"s":{"df":0,"docs":{},"t":{"df":0,"docs":{},"e":{"df":0,"docs":{},"m":{"_":{"df":0,"docs":{},"t":{"df":1,"docs":{"26":{"tf":1.0}}}},"df":0,"docs":{}}}}}}}},"df":3,"docs":{"15":{"tf":1.7320508075688772},"16":{"tf":1.0},"35":{"tf":1.0}}}},"m":{"b":{"df":0,"docs":{},"e":{"d":{"df":1,"docs":{"22":{"tf":1.0}}},"df":0,"docs":{}}},"df":0,"docs":{},"p":{"df":0,"docs":{},"t":{"df":0,"docs":{},"i":{"df":1,"docs":{"4":{"tf":1.0}}}}}},"n":{"a":{"b":{"df":0,"docs":{},"l":{"df":1,"docs":{"13":{"tf":1.0}}}},"df":0,"docs":{}},"c":{"df":0,"docs":{},"o":{"d":{"df":1,"docs":{"31":{"tf":1.0}}},"df":0,"docs":{}}},"d":{"df":2,"docs":{"25":{"tf":1.0},"34":{"tf":1.0}},"i":{"a":{"df":0,"docs":{},"n":{"df":1,"docs":{"27":{"tf":1.0}}}},"df":0,"docs":{}}},"df":0,"docs":{},"o":{"df":0,"docs":{},"u":{"df":0,"docs":{},"g":{"df":0,"docs":{},"h":{"df":1,"docs":{"5":{"tf":1.0}}}}}},"s":{"df":0,"docs":{},"u":{"df":0,"docs":{},"r":{"df":1,"docs":{"5":{"tf":1.0}}}}},"t":{"df":0,"docs":{},"e":{"df":0,"docs":{},"r":{"df":1,"docs":{"17":{"tf":1.0}}}},"r":{"df":0,"docs":{},"i":{"df":6,"docs":{"20":{"tf":1.0},"22":{"tf":1.0},"26":{"tf":1.0},"34":{"tf":2.0},"4":{"tf":1.0},"5":{"tf":1.4142135623730951}}}}}},"r":{"df":0,"docs":{},"r":{"df":0,"docs":{},"o":{"df":0,"docs":{},"r":{"df":2,"docs":{"21":{"tf":1.4142135623730951},"5":{"tf":1.0}}}}}},"s":{"df":0,"docs":{},"p":{"/":{"df":0,"docs":{},"e":{"df":0,"docs":{},"f":{"df":0,"docs":{},"i":{"/":{"b":{"df":0,"docs":{},"o":{"df":0,"docs":{},"o":{"df":0,"docs":{},"t":{"/":{"b":{"df":0,"docs":{},"o":{"df":0,"docs":{},"o":{"df":0,"docs":{},"t":{"df":0,"docs":{},"x":{"6":{"4":{".":{"df":0,"docs":{},"e":{"df":0,"docs":{},"f":{"df":0,"docs":{},"i":{"df":2,"docs":{"12":{"tf":1.0},"16":{"tf":1.0}}}}}},"df":0,"docs":{}},"df":0,"docs":{}},"df":0,"docs":{}}}}}},"df":0,"docs":{}},"df":2,"docs":{"12":{"tf":1.0},"16":{"tf":1.0}}}}}},"df":0,"docs":{}},"df":0,"docs":{}}}}},"df":4,"docs":{"13":{"tf":1.0},"15":{"tf":1.0},"16":{"tf":1.4142135623730951},"35":{"tf":1.0}}},"s":{"df":0,"docs":{},"e":{"df":0,"docs":{},"n":{"df":0,"docs":{},"t":{"df":0,"docs":{},"i":{"df":2,"docs":{"31":{"tf":1.0},"5":{"tf":1.0}}}}}}}},"v":{"df":0,"docs":{},"e":{"df":0,"docs":{},"n":{"df":1,"docs":{"33":{"tf":1.0}}},"r":{"df":0,"docs":{},"y":{"df":0,"docs":{},"t":{"df":0,"docs":{},"h":{"df":1,"docs":{"5":{"tf":1.0}}}}}}}},"x":{"a":{"c":{"df":0,"docs":{},"t":{"df":0,"docs":{},"l":{"df":0,"docs":{},"i":{"df":1,"docs":{"15":{"tf":1.0}}}}}},"df":0,"docs":{},"m":{"df":0,"docs":{},"p":{"df":0,"docs":{},"l":{"df":8,"docs":{"15":{"tf":1.0},"16":{"tf":1.0},"17":{"tf":1.0},"20":{"tf":1.4142135623730951},"21":{"tf":1.4142135623730951},"22":{"tf":2.0},"23":{"tf":1.0},"30":{"tf":1.0}},"e":{".":{"df":0,"docs":{},"r":{"df":0,"docs":{},"s":{"@":{"0":{"5":{"8":{"df":1,"docs":{"20":{"tf":1.0}}},"df":0,"docs":{}},"df":0,"docs":{}},"df":0,"docs":{}},"df":0,"docs":{}}}},"df":0,"docs":{}}}}}},"c":{"df":0,"docs":{},"i":{"df":0,"docs":{},"t":{"df":1,"docs":{"5":{"tf":1.0}}}},"l":{"df":0,"docs":{},"u":{"df":0,"docs":{},"s":{"df":1,"docs":{"19":{"tf":1.0}}}}}},"df":0,"docs":{},"e":{"c":{"df":0,"docs":{},"u":{"df":0,"docs":{},"t":{"a":{"b":{"df":0,"docs":{},"l":{"df":0,"docs":{},"e":{".":{"df":0,"docs":{},"e":{"df":0,"docs":{},"f":{"df":0,"docs":{},"i":{"df":1,"docs":{"16":{"tf":1.0}}}}}},"df":0,"docs":{}}}},"df":0,"docs":{}},"df":8,"docs":{"11":{"tf":1.0},"12":{"tf":1.0},"16":{"tf":1.0},"20":{"tf":1.0},"26":{"tf":1.0},"29":{"tf":1.0},"5":{"tf":1.0},"8":{"tf":1.0}}}}},"df":0,"docs":{}},"i":{"df":0,"docs":{},"s":{"df":0,"docs":{},"t":{"df":1,"docs":{"35":{"tf":1.0}}}},"t":{"df":2,"docs":{"1":{"tf":1.0},"33":{"tf":1.0}}}},"p":{"df":0,"docs":{},"e":{"c":{"df":0,"docs":{},"t":{"(":{"\"":{"c":{"df":0,"docs":{},"o":{"df":0,"docs":{},"n":{"df":0,"docs":{},"v":{"df":0,"docs":{},"e":{"df":0,"docs":{},"r":{"df":0,"docs":{},"t":{"_":{"d":{"df":0,"docs":{},"e":{"df":0,"docs":{},"v":{"df":0,"docs":{},"i":{"c":{"df":0,"docs":{},"e":{"_":{"df":0,"docs":{},"p":{"a":{"df":0,"docs":{},"t":{"df":0,"docs":{},"h":{"_":{"df":0,"docs":{},"t":{"df":0,"docs":{},"o":{"_":{"df":0,"docs":{},"t":{"df":0,"docs":{},"e":{"df":0,"docs":{},"x":{"df":0,"docs":{},"t":{"df":2,"docs":{"20":{"tf":1.0},"21":{"tf":1.0}}}}}}},"df":0,"docs":{}}}},"df":0,"docs":{}}}},"df":0,"docs":{}}},"df":0,"docs":{}}},"df":0,"docs":{}}}}},"df":0,"docs":{}},"df":0,"docs":{}}}}}}}},"d":{"df":0,"docs":{},"e":{"df":0,"docs":{},"v":{"df":0,"docs":{},"i":{"c":{"df":0,"docs":{},"e":{"df":0,"docs":{},"p":{"a":{"df":0,"docs":{},"t":{"df":0,"docs":{},"h":{"df":0,"docs":{},"t":{"df":0,"docs":{},"o":{"df":0,"docs":{},"t":{"df":0,"docs":{},"e":{"df":0,"docs":{},"x":{"df":0,"docs":{},"t":{"df":2,"docs":{"20":{"tf":1.0},"21":{"tf":1.0}}}}}}}}}}},"df":0,"docs":{}}}},"df":0,"docs":{}}}}},"df":0,"docs":{}},"df":0,"docs":{}},"df":0,"docs":{}}},"df":0,"docs":{}},"o":{"df":0,"docs":{},"r":{"df":0,"docs":{},"t":{"df":1,"docs":{"5":{"tf":1.0}}}}}},"t":{"df":0,"docs":{},"e":{"df":0,"docs":{},"n":{"df":0,"docs":{},"s":{"df":2,"docs":{"26":{"tf":1.0},"28":{"tf":1.0}}}},"r":{"df":0,"docs":{},"n":{"df":1,"docs":{"22":{"tf":1.0}}}}}}}},"f":{"1":{"2":{"df":1,"docs":{"17":{"tf":1.0}}},"df":0,"docs":{}},"3":{"2":{"df":1,"docs":{"22":{"tf":3.1622776601683795}}},"df":0,"docs":{}},"8":{"1":{"df":0,"docs":{},"f":{"df":3,"docs":{"15":{"tf":1.0},"16":{"tf":1.0},"35":{"tf":1.0}}}},"df":0,"docs":{}},"9":{"df":1,"docs":{"17":{"tf":1.0}}},"a":{"df":0,"docs":{},"i":{"df":0,"docs":{},"l":{"df":3,"docs":{"20":{"tf":1.0},"21":{"tf":1.0},"22":{"tf":1.0}}},"r":{"df":0,"docs":{},"l":{"df":0,"docs":{},"i":{"df":2,"docs":{"26":{"tf":1.0},"32":{"tf":1.0}}}}}},"t":{"df":3,"docs":{"15":{"tf":2.0},"16":{"tf":1.0},"35":{"tf":1.0}}}},"df":0,"docs":{},"e":{"d":{"4":{"df":1,"docs":{"27":{"tf":1.0}}},"df":0,"docs":{},"o":{"df":0,"docs":{},"r":{"a":{"df":2,"docs":{"10":{"tf":1.0},"11":{"tf":1.0}}},"df":0,"docs":{}}}},"df":0,"docs":{},"w":{"df":3,"docs":{"13":{"tf":1.0},"26":{"tf":1.0},"4":{"tf":1.0}}}},"i":{"df":0,"docs":{},"e":{"df":0,"docs":{},"l":{"d":{"df":1,"docs":{"27":{"tf":1.0}}},"df":0,"docs":{}}},"g":{"df":0,"docs":{},"u":{"df":0,"docs":{},"r":{"df":1,"docs":{"33":{"tf":1.0}}}}},"l":{"df":0,"docs":{},"e":{"df":6,"docs":{"11":{"tf":2.6457513110645907},"15":{"tf":2.0},"20":{"tf":1.0},"31":{"tf":1.4142135623730951},"35":{"tf":2.449489742783178},"7":{"tf":1.0}}}},"n":{"a":{"df":0,"docs":{},"l":{"df":1,"docs":{"5":{"tf":1.0}}}},"d":{"df":2,"docs":{"19":{"tf":1.0},"21":{"tf":1.4142135623730951}}},"df":0,"docs":{}},"r":{"df":0,"docs":{},"m":{"df":0,"docs":{},"w":{"a":{"df":0,"docs":{},"r":{"df":2,"docs":{"10":{"tf":1.0},"11":{"tf":1.4142135623730951}}}},"df":0,"docs":{}}},"s":{"df":0,"docs":{},"t":{"df":5,"docs":{"19":{"tf":1.0},"20":{"tf":1.4142135623730951},"21":{"tf":1.7320508075688772},"27":{"tf":1.0},"5":{"tf":1.0}}}}}},"l":{"a":{"df":0,"docs":{},"g":{"df":2,"docs":{"23":{"tf":1.0},"33":{"tf":1.0}}}},"df":0,"docs":{},"e":{"df":0,"docs":{},"x":{"df":0,"docs":{},"i":{"b":{"df":0,"docs":{},"l":{"df":2,"docs":{"31":{"tf":1.0},"32":{"tf":1.0}}}},"df":0,"docs":{}}}}},"n":{"df":6,"docs":{"20":{"tf":1.4142135623730951},"21":{"tf":1.0},"22":{"tf":3.1622776601683795},"26":{"tf":1.0},"4":{"tf":1.0},"5":{"tf":1.0}}},"o":{"c":{"df":0,"docs":{},"u":{"df":1,"docs":{"0":{"tf":1.0}}}},"df":0,"docs":{},"l":{"df":0,"docs":{},"l":{"df":0,"docs":{},"o":{"df":0,"docs":{},"w":{"df":3,"docs":{"22":{"tf":1.0},"3":{"tf":1.0},"34":{"tf":1.0}}}}}},"r":{"df":0,"docs":{},"e":{"df":0,"docs":{},"v":{"df":1,"docs":{"22":{"tf":1.0}}}},"m":{"a":{"df":0,"docs":{},"t":{"=":{"df":0,"docs":{},"r":{"a":{"df":0,"docs":{},"w":{",":{"df":0,"docs":{},"f":{"df":0,"docs":{},"i":{"df":0,"docs":{},"l":{"df":0,"docs":{},"e":{"=":{"df":0,"docs":{},"f":{"a":{"df":0,"docs":{},"t":{":":{"df":0,"docs":{},"r":{"df":0,"docs":{},"w":{":":{"df":0,"docs":{},"e":{"df":0,"docs":{},"s":{"df":0,"docs":{},"p":{"df":1,"docs":{"13":{"tf":1.0}}}}}},"df":0,"docs":{}}}},"df":0,"docs":{}}},"df":0,"docs":{}}},"df":0,"docs":{}}}}}},"df":0,"docs":{}}},"df":0,"docs":{}}},"df":3,"docs":{"15":{"tf":1.0},"16":{"tf":1.0},"27":{"tf":1.4142135623730951}}}},"df":0,"docs":{}}}},"r":{"a":{"c":{"df":0,"docs":{},"t":{"a":{"df":0,"docs":{},"l":{"df":1,"docs":{"22":{"tf":1.0}}}},"df":0,"docs":{}}},"df":0,"docs":{},"m":{"df":0,"docs":{},"e":{"b":{"df":0,"docs":{},"u":{"df":0,"docs":{},"f":{"df":0,"docs":{},"f":{"df":1,"docs":{"22":{"tf":1.4142135623730951}}}}}},"df":1,"docs":{"22":{"tf":1.0}}}}},"df":0,"docs":{}},"u":{"df":0,"docs":{},"l":{"df":0,"docs":{},"l":{"df":2,"docs":{"22":{"tf":1.0},"33":{"tf":1.0}}}},"n":{"c":{"df":0,"docs":{},"t":{"df":0,"docs":{},"i":{"df":0,"docs":{},"o":{"df":0,"docs":{},"n":{"df":4,"docs":{"21":{"tf":1.4142135623730951},"25":{"tf":1.0},"30":{"tf":1.4142135623730951},"5":{"tf":2.0}}}}}}},"df":0,"docs":{}}}},"g":{"a":{"df":0,"docs":{},"m":{"df":0,"docs":{},"e":{"df":1,"docs":{"22":{"tf":1.0}}}},"r":{"b":{"a":{"df":0,"docs":{},"g":{"df":1,"docs":{"33":{"tf":1.0}}}},"df":0,"docs":{}},"df":0,"docs":{},"r":{"df":0,"docs":{},"e":{"df":0,"docs":{},"t":{"'":{"df":1,"docs":{"33":{"tf":1.0}}},"df":0,"docs":{}}}}}},"df":1,"docs":{"22":{"tf":1.4142135623730951}},"e":{"df":0,"docs":{},"n":{"df":0,"docs":{},"e":{"df":0,"docs":{},"r":{"df":3,"docs":{"0":{"tf":1.0},"15":{"tf":1.0},"22":{"tf":1.0}}}}},"t":{"_":{"df":0,"docs":{},"r":{"a":{"df":0,"docs":{},"n":{"d":{"df":0,"docs":{},"o":{"df":0,"docs":{},"m":{"_":{"df":0,"docs":{},"u":{"df":0,"docs":{},"s":{"df":0,"docs":{},"i":{"df":0,"docs":{},"z":{"df":0,"docs":{},"e":{"(":{"df":0,"docs":{},"r":{"df":0,"docs":{},"n":{"df":0,"docs":{},"g":{"df":1,"docs":{"22":{"tf":1.0}}}}}},"df":0,"docs":{}}}}}}},"df":0,"docs":{}}}},"df":0,"docs":{}}},"df":0,"docs":{}}},"df":1,"docs":{"34":{"tf":1.0}}}},"i":{"df":0,"docs":{},"v":{"df":0,"docs":{},"e":{"df":1,"docs":{"21":{"tf":1.0}}}}},"l":{"df":0,"docs":{},"o":{"b":{"a":{"df":0,"docs":{},"l":{"df":1,"docs":{"27":{"tf":1.0}}}},"df":1,"docs":{"5":{"tf":1.0}}},"df":0,"docs":{}}},"o":{"df":0,"docs":{},"e":{"df":1,"docs":{"25":{"tf":1.0}}},"p":{".":{"b":{"df":0,"docs":{},"l":{"df":0,"docs":{},"t":{"(":{"b":{"df":0,"docs":{},"l":{"df":0,"docs":{},"t":{"df":0,"docs":{},"o":{"df":0,"docs":{},"p":{":":{":":{"b":{"df":0,"docs":{},"u":{"df":0,"docs":{},"f":{"df":0,"docs":{},"f":{"df":0,"docs":{},"e":{"df":0,"docs":{},"r":{"df":0,"docs":{},"t":{"df":0,"docs":{},"o":{"df":0,"docs":{},"v":{"df":0,"docs":{},"i":{"d":{"df":0,"docs":{},"e":{"df":0,"docs":{},"o":{"df":1,"docs":{"22":{"tf":1.4142135623730951}}}}},"df":0,"docs":{}}}}}}}}}}},"df":0,"docs":{}},"df":0,"docs":{}},"df":0,"docs":{}}}}}},"df":0,"docs":{}},"df":0,"docs":{}}}},"c":{"df":0,"docs":{},"u":{"df":0,"docs":{},"r":{"df":0,"docs":{},"r":{"df":0,"docs":{},"e":{"df":0,"docs":{},"n":{"df":0,"docs":{},"t":{"_":{"df":0,"docs":{},"m":{"df":0,"docs":{},"o":{"d":{"df":0,"docs":{},"e":{"_":{"df":0,"docs":{},"i":{"df":0,"docs":{},"n":{"df":0,"docs":{},"f":{"df":0,"docs":{},"o":{"(":{")":{".":{"df":0,"docs":{},"r":{"df":0,"docs":{},"e":{"df":0,"docs":{},"s":{"df":0,"docs":{},"o":{"df":0,"docs":{},"l":{"df":0,"docs":{},"u":{"df":0,"docs":{},"t":{"df":1,"docs":{"22":{"tf":1.0}}}}}}}}}},"df":0,"docs":{}},"df":0,"docs":{}},"df":0,"docs":{}}}}}},"df":0,"docs":{}}},"df":0,"docs":{}}}},"df":0,"docs":{}}}}}}}},"df":0,"docs":{}},"_":{"df":0,"docs":{},"h":{"a":{"df":0,"docs":{},"n":{"d":{"df":0,"docs":{},"l":{"df":1,"docs":{"22":{"tf":1.0}}}},"df":0,"docs":{}}},"df":0,"docs":{}}},"df":1,"docs":{"22":{"tf":2.0}}}},"p":{"df":0,"docs":{},"t":{"df":3,"docs":{"15":{"tf":1.4142135623730951},"16":{"tf":1.0},"34":{"tf":2.0}}}},"r":{"a":{"d":{"df":0,"docs":{},"i":{"df":0,"docs":{},"e":{"df":0,"docs":{},"n":{"df":0,"docs":{},"t":{"df":1,"docs":{"22":{"tf":1.0}}}}}}},"df":0,"docs":{},"p":{"df":0,"docs":{},"h":{"df":0,"docs":{},"i":{"c":{"df":1,"docs":{"22":{"tf":2.23606797749979}},"s":{"df":0,"docs":{},"o":{"df":0,"docs":{},"u":{"df":0,"docs":{},"t":{"df":0,"docs":{},"p":{"df":0,"docs":{},"u":{"df":0,"docs":{},"t":{"df":1,"docs":{"22":{"tf":1.7320508075688772}}}}}}}}}},"df":0,"docs":{}}}}},"df":0,"docs":{},"e":{"df":0,"docs":{},"e":{"df":0,"docs":{},"n":{"df":1,"docs":{"22":{"tf":1.0}}}}},"o":{"df":0,"docs":{},"u":{"df":0,"docs":{},"p":{"df":1,"docs":{"27":{"tf":1.0}}}}}},"u":{"df":0,"docs":{},"i":{"d":{"df":5,"docs":{"15":{"tf":1.7320508075688772},"18":{"tf":1.0},"27":{"tf":3.0},"32":{"tf":1.4142135623730951},"34":{"tf":1.7320508075688772}}},"df":0,"docs":{}}}},"h":{"a":{"df":0,"docs":{},"l":{"df":0,"docs":{},"f":{"df":0,"docs":{},"w":{"a":{"df":0,"docs":{},"y":{"df":1,"docs":{"22":{"tf":1.0}}}},"df":0,"docs":{}}}},"n":{"d":{"df":0,"docs":{},"l":{"df":10,"docs":{"19":{"tf":3.1622776601683795},"20":{"tf":1.0},"21":{"tf":2.449489742783178},"22":{"tf":1.0},"26":{"tf":1.0},"28":{"tf":1.4142135623730951},"29":{"tf":2.0},"31":{"tf":1.4142135623730951},"4":{"tf":1.0},"5":{"tf":1.7320508075688772}},"e":{"df":0,"docs":{},"r":{"df":1,"docs":{"5":{"tf":1.0}}}}}},"df":0,"docs":{}},"p":{"df":0,"docs":{},"p":{"df":0,"docs":{},"e":{"df":0,"docs":{},"n":{"df":1,"docs":{"32":{"tf":1.0}}}}}},"r":{"d":{"df":0,"docs":{},"w":{"a":{"df":0,"docs":{},"r":{"df":2,"docs":{"14":{"tf":1.4142135623730951},"28":{"tf":1.0}}}},"df":0,"docs":{}}},"df":0,"docs":{}}},"df":0,"docs":{},"e":{"a":{"d":{"df":0,"docs":{},"e":{"df":0,"docs":{},"r":{"df":1,"docs":{"34":{"tf":1.4142135623730951}}}}},"df":0,"docs":{}},"df":0,"docs":{},"i":{"df":0,"docs":{},"g":{"df":0,"docs":{},"h":{"df":0,"docs":{},"t":{"df":1,"docs":{"22":{"tf":3.4641016151377544}}}}}},"l":{"df":0,"docs":{},"l":{"df":0,"docs":{},"o":{"df":4,"docs":{"1":{"tf":1.0},"13":{"tf":1.0},"21":{"tf":1.0},"5":{"tf":1.0}}}}},"r":{"df":0,"docs":{},"e":{"'":{"df":2,"docs":{"20":{"tf":1.0},"22":{"tf":1.0}}},"df":4,"docs":{"21":{"tf":1.0},"22":{"tf":1.0},"5":{"tf":1.4142135623730951},"7":{"tf":1.0}}}}},"o":{"df":0,"docs":{},"l":{"d":{"df":1,"docs":{"17":{"tf":1.0}}},"df":0,"docs":{}}},"p":{"df":1,"docs":{"17":{"tf":1.0}}},"u":{"df":0,"docs":{},"g":{"df":0,"docs":{},"e":{"df":1,"docs":{"24":{"tf":1.0}}}},"m":{"a":{"df":0,"docs":{},"n":{"df":1,"docs":{"31":{"tf":1.0}}}},"df":0,"docs":{}}}},"i":{"6":{"8":{"6":{"df":1,"docs":{"7":{"tf":1.0}}},"df":0,"docs":{}},"df":0,"docs":{}},"d":{"df":0,"docs":{},"e":{"df":0,"docs":{},"n":{"df":0,"docs":{},"t":{"df":0,"docs":{},"i":{"df":0,"docs":{},"f":{"df":0,"docs":{},"i":{"df":5,"docs":{"27":{"tf":1.7320508075688772},"31":{"tf":1.0},"32":{"tf":1.0},"34":{"tf":1.0},"35":{"tf":1.0}}}}}}}}},"df":0,"docs":{},"f":{"=":{"df":0,"docs":{},"p":{"df":0,"docs":{},"f":{"df":0,"docs":{},"l":{"a":{"df":0,"docs":{},"s":{"df":0,"docs":{},"h":{",":{"df":0,"docs":{},"f":{"df":0,"docs":{},"o":{"df":0,"docs":{},"r":{"df":0,"docs":{},"m":{"a":{"df":0,"docs":{},"t":{"=":{"df":0,"docs":{},"r":{"a":{"df":0,"docs":{},"w":{",":{"df":0,"docs":{},"r":{"df":0,"docs":{},"e":{"a":{"d":{"df":0,"docs":{},"o":{"df":0,"docs":{},"n":{"df":0,"docs":{},"l":{"df":0,"docs":{},"y":{"=":{"df":0,"docs":{},"o":{"df":0,"docs":{},"n":{",":{"df":0,"docs":{},"f":{"df":0,"docs":{},"i":{"df":0,"docs":{},"l":{"df":0,"docs":{},"e":{"=":{"df":0,"docs":{},"o":{"df":0,"docs":{},"v":{"df":0,"docs":{},"m":{"df":0,"docs":{},"f":{"_":{"c":{"df":0,"docs":{},"o":{"d":{"df":0,"docs":{},"e":{".":{"df":0,"docs":{},"f":{"d":{"df":1,"docs":{"13":{"tf":1.0}}},"df":0,"docs":{}}},"df":0,"docs":{}}},"df":0,"docs":{}}},"df":0,"docs":{},"v":{"a":{"df":0,"docs":{},"r":{"df":0,"docs":{},"s":{".":{"df":0,"docs":{},"f":{"d":{"df":1,"docs":{"13":{"tf":1.0}}},"df":0,"docs":{}}},"df":0,"docs":{}}}},"df":0,"docs":{}}},"df":0,"docs":{}}}}}},"df":0,"docs":{}}}}}},"df":0,"docs":{}}}},"df":0,"docs":{}}}}}},"df":0,"docs":{}},"df":0,"docs":{}}}},"df":0,"docs":{}}},"df":0,"docs":{}}},"df":0,"docs":{}}},"df":0,"docs":{}}}}}},"df":0,"docs":{}}}},"df":0,"docs":{}}}}},"df":0,"docs":{}},"m":{"a":{"df":0,"docs":{},"g":{"df":4,"docs":{"20":{"tf":1.0},"21":{"tf":1.0},"23":{"tf":1.0},"5":{"tf":1.4142135623730951}},"e":{"_":{"d":{"df":0,"docs":{},"e":{"df":0,"docs":{},"v":{"df":0,"docs":{},"i":{"c":{"df":0,"docs":{},"e":{"_":{"df":0,"docs":{},"p":{"a":{"df":0,"docs":{},"t":{"df":0,"docs":{},"h":{"_":{"df":0,"docs":{},"t":{"df":0,"docs":{},"e":{"df":0,"docs":{},"x":{"df":0,"docs":{},"t":{"df":2,"docs":{"20":{"tf":1.4142135623730951},"21":{"tf":1.4142135623730951}}}}}}},"df":2,"docs":{"20":{"tf":1.4142135623730951},"21":{"tf":1.4142135623730951}}}}},"df":0,"docs":{}}},"df":0,"docs":{}}},"df":0,"docs":{}}}}},"df":0,"docs":{},"h":{"a":{"df":0,"docs":{},"n":{"d":{"df":0,"docs":{},"l":{"df":1,"docs":{"21":{"tf":1.0}}}},"df":0,"docs":{}}},"df":0,"docs":{}}},"df":0,"docs":{}}}},"df":0,"docs":{},"i":{"df":0,"docs":{},"t":{"df":1,"docs":{"12":{"tf":1.0}}}},"p":{"df":0,"docs":{},"l":{"df":1,"docs":{"22":{"tf":1.7320508075688772}},"e":{"df":0,"docs":{},"m":{"df":0,"docs":{},"e":{"df":0,"docs":{},"n":{"df":0,"docs":{},"t":{"df":5,"docs":{"10":{"tf":1.0},"15":{"tf":1.7320508075688772},"22":{"tf":1.0},"33":{"tf":1.4142135623730951},"34":{"tf":1.4142135623730951}}}}}}}},"o":{"df":0,"docs":{},"r":{"df":0,"docs":{},"t":{"df":5,"docs":{"24":{"tf":1.0},"27":{"tf":1.0},"33":{"tf":1.0},"35":{"tf":1.0},"5":{"tf":1.0}}}}}}},"n":{"c":{"df":0,"docs":{},"l":{"df":0,"docs":{},"u":{"d":{"df":4,"docs":{"11":{"tf":1.0},"26":{"tf":1.0},"31":{"tf":1.0},"34":{"tf":1.0}}},"df":0,"docs":{}}}},"d":{"df":0,"docs":{},"i":{"c":{"df":2,"docs":{"34":{"tf":1.0},"5":{"tf":1.0}}},"df":0,"docs":{},"v":{"df":0,"docs":{},"i":{"d":{"df":0,"docs":{},"u":{"df":3,"docs":{"21":{"tf":1.0},"30":{"tf":1.0},"34":{"tf":1.0}}}},"df":0,"docs":{}}}}},"df":0,"docs":{},"f":{"df":0,"docs":{},"o":{"!":{"(":{"\"":{"df":0,"docs":{},"h":{"df":0,"docs":{},"e":{"df":0,"docs":{},"l":{"df":0,"docs":{},"l":{"df":0,"docs":{},"o":{"df":2,"docs":{"4":{"tf":1.0},"5":{"tf":1.0}}}}}}},"i":{"df":0,"docs":{},"m":{"a":{"df":0,"docs":{},"g":{"df":2,"docs":{"20":{"tf":1.0},"21":{"tf":1.0}}}},"df":0,"docs":{}}}},"df":0,"docs":{}},"df":0,"docs":{}},"df":2,"docs":{"13":{"tf":1.0},"20":{"tf":1.0}},"r":{"df":0,"docs":{},"m":{"df":3,"docs":{"20":{"tf":1.0},"24":{"tf":1.0},"31":{"tf":1.0}}}}}},"h":{"df":0,"docs":{},"e":{"df":0,"docs":{},"r":{"df":1,"docs":{"30":{"tf":1.0}}}}},"i":{"df":0,"docs":{},"t":{"df":0,"docs":{},"i":{"df":3,"docs":{"22":{"tf":1.0},"25":{"tf":1.4142135623730951},"5":{"tf":1.4142135623730951}}}}},"s":{"df":0,"docs":{},"e":{"df":0,"docs":{},"n":{"df":0,"docs":{},"s":{"df":0,"docs":{},"i":{"df":0,"docs":{},"t":{"df":1,"docs":{"15":{"tf":1.0}}}}}},"r":{"df":0,"docs":{},"t":{"df":1,"docs":{"17":{"tf":1.0}}}}},"i":{"d":{"df":1,"docs":{"5":{"tf":1.0}}},"df":0,"docs":{}},"t":{"a":{"df":0,"docs":{},"l":{"df":4,"docs":{"10":{"tf":2.0},"11":{"tf":1.0},"3":{"tf":1.4142135623730951},"7":{"tf":1.0}}}},"df":0,"docs":{},"r":{"df":0,"docs":{},"u":{"c":{"df":0,"docs":{},"t":{"df":1,"docs":{"3":{"tf":1.0}}}},"df":0,"docs":{}}}}},"t":{"df":0,"docs":{},"e":{"df":0,"docs":{},"l":{"df":1,"docs":{"35":{"tf":1.0}}},"n":{"d":{"df":1,"docs":{"5":{"tf":1.0}}},"df":0,"docs":{}},"r":{"a":{"c":{"df":0,"docs":{},"t":{"df":1,"docs":{"30":{"tf":1.4142135623730951}}}},"df":0,"docs":{}},"df":0,"docs":{},"f":{"a":{"c":{"df":3,"docs":{"26":{"tf":1.0},"28":{"tf":1.0},"30":{"tf":1.0}}},"df":0,"docs":{}},"df":0,"docs":{}}}},"r":{"df":0,"docs":{},"o":{"d":{"df":0,"docs":{},"u":{"c":{"df":0,"docs":{},"t":{"df":1,"docs":{"0":{"tf":1.0}}}},"df":0,"docs":{}}},"df":0,"docs":{}}}}},"o":{"df":1,"docs":{"30":{"tf":1.0}}},"s":{"df":0,"docs":{},"n":{"'":{"df":0,"docs":{},"t":{"df":1,"docs":{"21":{"tf":1.0}}}},"df":0,"docs":{}}},"t":{"'":{"df":1,"docs":{"34":{"tf":1.4142135623730951}}},"a":{"df":0,"docs":{},"n":{"df":0,"docs":{},"i":{"df":0,"docs":{},"u":{"df":0,"docs":{},"m":{"df":1,"docs":{"35":{"tf":1.0}}}}}}},"df":0,"docs":{},"s":{"df":0,"docs":{},"e":{"df":0,"docs":{},"l":{"df":0,"docs":{},"f":{"df":1,"docs":{"10":{"tf":1.0}}}}}}}},"k":{"df":0,"docs":{},"e":{"df":0,"docs":{},"y":{"/":{"df":0,"docs":{},"v":{"a":{"df":0,"docs":{},"l":{"df":0,"docs":{},"u":{"df":1,"docs":{"32":{"tf":1.0}}}}},"df":0,"docs":{}}},"df":2,"docs":{"17":{"tf":1.7320508075688772},"32":{"tf":1.0}}}},"i":{"df":0,"docs":{},"n":{"d":{"df":1,"docs":{"31":{"tf":1.0}}},"df":0,"docs":{}}},"v":{"df":0,"docs":{},"m":{"df":2,"docs":{"10":{"tf":1.0},"13":{"tf":1.0}}}}},"l":{"a":{"df":0,"docs":{},"r":{"df":0,"docs":{},"g":{"df":2,"docs":{"30":{"tf":1.0},"34":{"tf":1.4142135623730951}}}},"u":{"df":0,"docs":{},"n":{"c":{"df":0,"docs":{},"h":{"df":2,"docs":{"13":{"tf":1.4142135623730951},"20":{"tf":1.0}}}},"df":0,"docs":{}}}},"df":0,"docs":{},"e":{"a":{"df":0,"docs":{},"r":{"df":0,"docs":{},"n":{"df":1,"docs":{"30":{"tf":1.0}}}}},"df":0,"docs":{},"n":{"df":0,"docs":{},"g":{"df":0,"docs":{},"t":{"df":0,"docs":{},"h":{"df":1,"docs":{"31":{"tf":1.0}}}}}},"s":{"df":0,"docs":{},"s":{"df":2,"docs":{"21":{"tf":1.0},"29":{"tf":1.0}}}},"t":{"'":{"df":2,"docs":{"21":{"tf":1.0},"5":{"tf":1.0}}},"df":0,"docs":{}},"v":{"df":0,"docs":{},"e":{"df":0,"docs":{},"l":{"df":1,"docs":{"26":{"tf":1.0}}}}}},"i":{"b":{"df":0,"docs":{},"r":{"a":{"df":0,"docs":{},"r":{"df":0,"docs":{},"i":{"df":1,"docs":{"5":{"tf":1.0}}}}},"df":0,"docs":{}}},"df":0,"docs":{},"m":{"df":0,"docs":{},"i":{"df":0,"docs":{},"t":{"df":3,"docs":{"25":{"tf":1.0},"26":{"tf":1.0},"33":{"tf":1.0}}}}},"n":{"df":0,"docs":{},"e":{"a":{"df":0,"docs":{},"r":{"df":1,"docs":{"22":{"tf":1.0}}}},"df":1,"docs":{"5":{"tf":1.4142135623730951}}},"k":{"df":2,"docs":{"23":{"tf":1.0},"24":{"tf":1.0}},"e":{"df":0,"docs":{},"r":{"df":1,"docs":{"23":{"tf":1.0}}}}},"u":{"df":0,"docs":{},"x":{"df":2,"docs":{"16":{"tf":1.0},"25":{"tf":1.0}}}}},"t":{"df":0,"docs":{},"t":{"df":0,"docs":{},"l":{"df":2,"docs":{"27":{"tf":1.0},"5":{"tf":1.0}}}}}},"o":{"a":{"d":{"df":3,"docs":{"25":{"tf":1.4142135623730951},"26":{"tf":1.0},"29":{"tf":1.0}},"e":{"d":{"_":{"df":0,"docs":{},"i":{"df":0,"docs":{},"m":{"a":{"df":0,"docs":{},"g":{"df":2,"docs":{"20":{"tf":1.0},"21":{"tf":1.0}},"e":{".":{"df":0,"docs":{},"f":{"df":0,"docs":{},"i":{"df":0,"docs":{},"l":{"df":0,"docs":{},"e":{"_":{"df":0,"docs":{},"p":{"a":{"df":0,"docs":{},"t":{"df":0,"docs":{},"h":{"(":{")":{".":{"df":0,"docs":{},"e":{"df":0,"docs":{},"x":{"df":0,"docs":{},"p":{"df":0,"docs":{},"e":{"c":{"df":0,"docs":{},"t":{"(":{"\"":{"df":0,"docs":{},"f":{"df":0,"docs":{},"i":{"df":0,"docs":{},"l":{"df":2,"docs":{"20":{"tf":1.0},"21":{"tf":1.0}}}}}},"df":0,"docs":{}},"df":0,"docs":{}}},"df":0,"docs":{}}}}}},"df":0,"docs":{}},"df":0,"docs":{}},"df":0,"docs":{}}}},"df":0,"docs":{}}},"df":0,"docs":{}}}}}},"df":0,"docs":{}}}},"df":0,"docs":{}}}},"df":0,"docs":{},"i":{"df":0,"docs":{},"m":{"a":{"df":0,"docs":{},"g":{"df":2,"docs":{"20":{"tf":1.0},"21":{"tf":1.4142135623730951}}}},"df":0,"docs":{}}}},"df":0,"docs":{}}},"df":0,"docs":{}},"c":{"a":{"df":0,"docs":{},"t":{"df":1,"docs":{"11":{"tf":1.0}},"e":{"_":{"df":0,"docs":{},"h":{"a":{"df":0,"docs":{},"n":{"d":{"df":0,"docs":{},"l":{"df":0,"docs":{},"e":{"_":{"b":{"df":0,"docs":{},"u":{"df":0,"docs":{},"f":{"df":0,"docs":{},"f":{"df":2,"docs":{"19":{"tf":1.0},"21":{"tf":1.0}},"e":{"df":0,"docs":{},"r":{"(":{"df":0,"docs":{},"s":{"df":0,"docs":{},"e":{"a":{"df":0,"docs":{},"r":{"c":{"df":0,"docs":{},"h":{"df":0,"docs":{},"t":{"df":0,"docs":{},"y":{"df":0,"docs":{},"p":{"df":0,"docs":{},"e":{":":{":":{"b":{"df":0,"docs":{},"y":{"df":0,"docs":{},"p":{"df":0,"docs":{},"r":{"df":0,"docs":{},"o":{"df":0,"docs":{},"t":{"df":0,"docs":{},"o":{"c":{"df":0,"docs":{},"o":{"df":0,"docs":{},"l":{"(":{"&":{"d":{"df":0,"docs":{},"e":{"df":0,"docs":{},"v":{"df":0,"docs":{},"i":{"c":{"df":0,"docs":{},"e":{"df":0,"docs":{},"p":{"a":{"df":0,"docs":{},"t":{"df":0,"docs":{},"h":{"df":0,"docs":{},"t":{"df":0,"docs":{},"o":{"df":0,"docs":{},"t":{"df":0,"docs":{},"e":{"df":0,"docs":{},"x":{"df":0,"docs":{},"t":{":":{":":{"df":0,"docs":{},"g":{"df":0,"docs":{},"u":{"df":0,"docs":{},"i":{"d":{"df":2,"docs":{"20":{"tf":1.0},"21":{"tf":1.0}}},"df":0,"docs":{}}}}},"df":0,"docs":{}},"df":0,"docs":{}}}}}}}}}},"df":0,"docs":{}}}},"df":0,"docs":{}}}}},"df":0,"docs":{}},"df":0,"docs":{}},"df":0,"docs":{}}}},"df":0,"docs":{}}}}}}}},"df":0,"docs":{}},"df":0,"docs":{}},"df":0,"docs":{}}}}}}},"df":0,"docs":{}}},"df":0,"docs":{}}}},"df":0,"docs":{}}}}}}},"df":0,"docs":{}},"df":0,"docs":{}}}},"df":0,"docs":{}}},"df":0,"docs":{}}},"df":0,"docs":{}}}},"df":0,"docs":{}},"df":0,"docs":{},"g":{":":{":":{"df":0,"docs":{},"i":{"df":0,"docs":{},"n":{"df":0,"docs":{},"f":{"df":0,"docs":{},"o":{"df":3,"docs":{"20":{"tf":1.0},"4":{"tf":1.0},"5":{"tf":1.0}}}}}}},"df":0,"docs":{}},"df":4,"docs":{"13":{"tf":1.0},"21":{"tf":1.0},"4":{"tf":1.0},"5":{"tf":1.0}},"g":{"df":0,"docs":{},"e":{"df":0,"docs":{},"r":{"df":1,"docs":{"5":{"tf":1.0}}}}}},"n":{"df":0,"docs":{},"g":{"df":0,"docs":{},"e":{"df":0,"docs":{},"r":{"df":1,"docs":{"25":{"tf":1.0}}}}}},"o":{"df":0,"docs":{},"k":{"df":6,"docs":{"15":{"tf":1.0},"20":{"tf":1.0},"21":{"tf":1.7320508075688772},"27":{"tf":1.0},"31":{"tf":1.0},"5":{"tf":1.7320508075688772}}},"p":{"df":1,"docs":{"22":{"tf":1.4142135623730951}}}}}},"m":{"a":{"c":{"df":1,"docs":{"17":{"tf":1.0}},"h":{"df":0,"docs":{},"i":{"df":0,"docs":{},"n":{"df":3,"docs":{"10":{"tf":1.0},"17":{"tf":1.0},"33":{"tf":1.0}}}}},"r":{"df":0,"docs":{},"o":{"df":1,"docs":{"36":{"tf":1.0}}}}},"df":0,"docs":{},"i":{"df":0,"docs":{},"n":{"(":{"_":{"df":0,"docs":{},"h":{"a":{"df":0,"docs":{},"n":{"d":{"df":0,"docs":{},"l":{"df":1,"docs":{"22":{"tf":1.0}}}},"df":0,"docs":{}}},"df":0,"docs":{}},"i":{"df":0,"docs":{},"m":{"a":{"df":0,"docs":{},"g":{"df":0,"docs":{},"e":{"_":{"df":0,"docs":{},"h":{"a":{"df":0,"docs":{},"n":{"d":{"df":0,"docs":{},"l":{"df":2,"docs":{"4":{"tf":1.0},"5":{"tf":1.0}}}},"df":0,"docs":{}}},"df":0,"docs":{}}},"df":0,"docs":{}}}},"df":0,"docs":{}}}},"df":0,"docs":{},"h":{"a":{"df":0,"docs":{},"n":{"d":{"df":0,"docs":{},"l":{"df":1,"docs":{"26":{"tf":1.0}}}},"df":0,"docs":{}}},"df":0,"docs":{}},"i":{"df":0,"docs":{},"m":{"a":{"df":0,"docs":{},"g":{"df":0,"docs":{},"e":{"_":{"df":0,"docs":{},"h":{"a":{"df":0,"docs":{},"n":{"d":{"df":0,"docs":{},"l":{"df":1,"docs":{"20":{"tf":1.0}}}},"df":0,"docs":{}}},"df":0,"docs":{}}},"df":0,"docs":{}}}},"df":0,"docs":{}}}},"df":4,"docs":{"21":{"tf":1.4142135623730951},"25":{"tf":1.0},"26":{"tf":1.0},"5":{"tf":2.23606797749979}}}},"k":{"df":0,"docs":{},"e":{"df":2,"docs":{"28":{"tf":1.0},"5":{"tf":1.7320508075688772}}}},"n":{"df":0,"docs":{},"i":{"df":4,"docs":{"15":{"tf":1.0},"30":{"tf":1.4142135623730951},"31":{"tf":1.0},"5":{"tf":1.0}}}},"p":{"df":1,"docs":{"26":{"tf":1.0}}},"r":{"df":0,"docs":{},"k":{"df":1,"docs":{"15":{"tf":1.0}}}},"s":{"df":0,"docs":{},"t":{"df":0,"docs":{},"e":{"df":0,"docs":{},"r":{"df":1,"docs":{"34":{"tf":1.0}}}}}},"t":{"c":{"df":0,"docs":{},"h":{"df":1,"docs":{"34":{"tf":1.0}}}},"df":0,"docs":{},"t":{"df":0,"docs":{},"e":{"df":0,"docs":{},"r":{"df":1,"docs":{"15":{"tf":1.0}}}},"h":{"df":0,"docs":{},"e":{"df":0,"docs":{},"w":{"df":1,"docs":{"33":{"tf":1.0}}}}}}}},"b":{"df":0,"docs":{},"r":{"df":1,"docs":{"34":{"tf":1.7320508075688772}}}},"df":0,"docs":{},"e":{"a":{"df":0,"docs":{},"n":{"df":1,"docs":{"19":{"tf":1.0}}}},"c":{"df":0,"docs":{},"h":{"a":{"df":0,"docs":{},"n":{"df":1,"docs":{"28":{"tf":1.0}}}},"df":0,"docs":{}}},"df":0,"docs":{},"m":{":":{":":{"df":0,"docs":{},"s":{"df":0,"docs":{},"i":{"df":0,"docs":{},"z":{"df":0,"docs":{},"e":{"_":{"df":0,"docs":{},"o":{"df":0,"docs":{},"f":{":":{":":{"<":{"df":0,"docs":{},"u":{"df":0,"docs":{},"s":{"df":1,"docs":{"22":{"tf":1.0}}}}},"df":0,"docs":{}},"df":0,"docs":{}},"df":0,"docs":{}}}},"df":0,"docs":{}}}}}},"df":0,"docs":{}},"df":0,"docs":{},"o":{"df":0,"docs":{},"r":{"df":0,"docs":{},"i":{"df":3,"docs":{"26":{"tf":1.4142135623730951},"33":{"tf":1.7320508075688772},"5":{"tf":1.0}}}}}},"n":{"df":0,"docs":{},"u":{"df":1,"docs":{"17":{"tf":1.0}}}},"s":{"df":0,"docs":{},"s":{"a":{"df":0,"docs":{},"g":{"df":1,"docs":{"13":{"tf":1.0}}}},"df":0,"docs":{}}},"t":{"df":0,"docs":{},"h":{"df":0,"docs":{},"o":{"d":{"df":2,"docs":{"21":{"tf":1.4142135623730951},"22":{"tf":2.23606797749979}}},"df":0,"docs":{}}}}},"i":{"c":{"df":0,"docs":{},"e":{"df":1,"docs":{"31":{"tf":1.0}}}},"df":0,"docs":{},"n":{"df":0,"docs":{},"i":{"df":0,"docs":{},"m":{"df":1,"docs":{"4":{"tf":1.0}}}}},"s":{"df":0,"docs":{},"i":{"df":0,"docs":{},"n":{"df":0,"docs":{},"t":{"df":0,"docs":{},"e":{"df":0,"docs":{},"r":{"df":0,"docs":{},"p":{"df":0,"docs":{},"r":{"df":0,"docs":{},"e":{"df":0,"docs":{},"t":{"df":1,"docs":{"32":{"tf":1.0}}}}}}}}}}},"s":{"df":2,"docs":{"20":{"tf":1.0},"21":{"tf":1.0}}}}},"k":{"d":{"df":0,"docs":{},"i":{"df":0,"docs":{},"r":{"df":2,"docs":{"12":{"tf":1.0},"16":{"tf":1.4142135623730951}}}}},"df":0,"docs":{},"f":{"df":0,"docs":{},"s":{".":{"df":0,"docs":{},"f":{"a":{"df":0,"docs":{},"t":{"df":1,"docs":{"16":{"tf":1.0}}}},"df":0,"docs":{}}},"df":0,"docs":{}}}},"o":{"d":{"df":0,"docs":{},"e":{"df":2,"docs":{"19":{"tf":1.0},"25":{"tf":1.7320508075688772}},"r":{"df":0,"docs":{},"n":{"df":1,"docs":{"34":{"tf":1.0}}}}},"u":{"df":0,"docs":{},"l":{"df":2,"docs":{"31":{"tf":1.0},"5":{"tf":1.0}}}}},"df":0,"docs":{},"r":{"df":0,"docs":{},"e":{"df":8,"docs":{"21":{"tf":1.0},"22":{"tf":1.0},"24":{"tf":1.0},"25":{"tf":1.0},"27":{"tf":1.0},"31":{"tf":1.0},"33":{"tf":1.0},"34":{"tf":1.0}}}},"s":{"df":0,"docs":{},"t":{"df":0,"docs":{},"l":{"df":0,"docs":{},"i":{"df":1,"docs":{"25":{"tf":1.0}}}}}},"u":{"df":0,"docs":{},"n":{"df":0,"docs":{},"t":{"df":2,"docs":{"15":{"tf":1.0},"16":{"tf":1.4142135623730951}}}}},"v":{"df":0,"docs":{},"e":{"df":1,"docs":{"22":{"tf":1.0}}}}},"u":{"c":{"df":0,"docs":{},"h":{"df":6,"docs":{"21":{"tf":1.0},"24":{"tf":1.0},"25":{"tf":1.0},"27":{"tf":1.0},"33":{"tf":1.0},"5":{"tf":1.0}}}},"df":0,"docs":{},"l":{"df":0,"docs":{},"t":{"df":0,"docs":{},"i":{"df":0,"docs":{},"p":{"df":0,"docs":{},"l":{"df":1,"docs":{"11":{"tf":1.0}}}}}}},"t":{"df":5,"docs":{"20":{"tf":1.0},"22":{"tf":3.1622776601683795},"26":{"tf":1.0},"4":{"tf":1.0},"5":{"tf":1.0}}}}},"n":{"a":{"df":0,"docs":{},"m":{"df":0,"docs":{},"e":{"df":3,"docs":{"15":{"tf":1.4142135623730951},"32":{"tf":1.4142135623730951},"35":{"tf":1.7320508075688772}},"s":{"df":0,"docs":{},"p":{"a":{"c":{"df":1,"docs":{"32":{"tf":1.0}}},"df":0,"docs":{}},"df":0,"docs":{}}}}}},"df":0,"docs":{},"e":{"a":{"df":0,"docs":{},"r":{"df":1,"docs":{"34":{"tf":1.0}},"l":{"df":0,"docs":{},"i":{"df":1,"docs":{"24":{"tf":1.0}}}}}},"c":{"df":0,"docs":{},"e":{"df":0,"docs":{},"s":{"df":0,"docs":{},"s":{"a":{"df":0,"docs":{},"r":{"df":0,"docs":{},"i":{"df":1,"docs":{"15":{"tf":1.0}}}}},"df":0,"docs":{}}}}},"df":0,"docs":{},"e":{"d":{"df":5,"docs":{"10":{"tf":1.0},"14":{"tf":1.0},"21":{"tf":1.0},"5":{"tf":1.7320508075688772},"7":{"tf":1.0}}},"df":0,"docs":{}},"w":{"(":{"df":0,"docs":{},"w":{"df":0,"docs":{},"i":{"d":{"df":0,"docs":{},"t":{"df":0,"docs":{},"h":{"df":1,"docs":{"22":{"tf":1.4142135623730951}}}}},"df":0,"docs":{}}},"x":{"df":1,"docs":{"22":{"tf":1.0}}}},"=":{"1":{":":{"1":{"df":0,"docs":{},"m":{":":{"1":{"0":{"df":0,"docs":{},"m":{"df":1,"docs":{"16":{"tf":1.0}}}},"df":0,"docs":{}},"df":0,"docs":{}},"df":0,"docs":{}}},"df":0,"docs":{}},"df":0,"docs":{}},"df":0,"docs":{}},"df":3,"docs":{"22":{"tf":1.7320508075688772},"26":{"tf":1.0},"4":{"tf":1.0}}},"x":{"df":0,"docs":{},"t":{"df":2,"docs":{"21":{"tf":1.0},"5":{"tf":1.4142135623730951}}}}},"o":{"_":{"df":0,"docs":{},"m":{"a":{"df":0,"docs":{},"i":{"df":0,"docs":{},"n":{"df":4,"docs":{"20":{"tf":1.0},"22":{"tf":1.0},"4":{"tf":1.0},"5":{"tf":1.4142135623730951}}}}},"df":0,"docs":{}},"s":{"df":0,"docs":{},"t":{"d":{"df":4,"docs":{"20":{"tf":1.0},"22":{"tf":1.0},"4":{"tf":1.0},"5":{"tf":1.4142135623730951}}},"df":0,"docs":{}}}},"df":0,"docs":{},"n":{"_":{"df":0,"docs":{},"v":{"df":0,"docs":{},"o":{"df":0,"docs":{},"l":{"a":{"df":0,"docs":{},"t":{"df":0,"docs":{},"i":{"df":0,"docs":{},"l":{"df":1,"docs":{"33":{"tf":1.0}}}}}},"df":0,"docs":{}}}}},"df":2,"docs":{"33":{"tf":1.7320508075688772},"34":{"tf":1.0}}},"r":{"df":0,"docs":{},"m":{"a":{"df":0,"docs":{},"l":{"df":1,"docs":{"33":{"tf":1.0}}}},"df":0,"docs":{}}},"t":{"df":0,"docs":{},"e":{"df":2,"docs":{"15":{"tf":1.4142135623730951},"31":{"tf":1.0}}},"h":{"df":1,"docs":{"5":{"tf":1.0}}}},"w":{"df":4,"docs":{"12":{"tf":1.0},"13":{"tf":1.0},"21":{"tf":1.0},"5":{"tf":1.0}}}},"u":{"df":0,"docs":{},"l":{"df":0,"docs":{},"l":{"df":1,"docs":{"32":{"tf":1.0}}}},"m":{"b":{"df":0,"docs":{},"e":{"df":0,"docs":{},"r":{"df":4,"docs":{"22":{"tf":1.0},"30":{"tf":1.0},"34":{"tf":1.0},"5":{"tf":1.0}}}}},"df":0,"docs":{},"e":{"df":0,"docs":{},"r":{"df":1,"docs":{"5":{"tf":1.0}}}}}}},"o":{"b":{"df":0,"docs":{},"t":{"a":{"df":0,"docs":{},"i":{"df":0,"docs":{},"n":{"df":1,"docs":{"19":{"tf":1.0}}}}},"df":0,"docs":{}}},"df":0,"docs":{},"k":{"df":2,"docs":{"20":{"tf":1.0},"21":{"tf":1.0}}},"n":{"c":{"df":5,"docs":{"17":{"tf":1.0},"19":{"tf":1.0},"25":{"tf":1.0},"26":{"tf":1.0},"33":{"tf":1.0}}},"df":6,"docs":{"11":{"tf":1.4142135623730951},"17":{"tf":1.4142135623730951},"21":{"tf":1.4142135623730951},"22":{"tf":1.0},"26":{"tf":1.0},"30":{"tf":1.0}}},"p":{"a":{"df":0,"docs":{},"q":{"df":0,"docs":{},"u":{"df":3,"docs":{"27":{"tf":1.0},"29":{"tf":1.0},"31":{"tf":1.0}}}}},"df":0,"docs":{},"e":{"df":0,"docs":{},"n":{"_":{"df":0,"docs":{},"p":{"df":0,"docs":{},"r":{"df":0,"docs":{},"o":{"df":0,"docs":{},"t":{"df":0,"docs":{},"o":{"c":{"df":0,"docs":{},"o":{"df":0,"docs":{},"l":{"_":{"df":0,"docs":{},"e":{"df":0,"docs":{},"x":{"c":{"df":0,"docs":{},"l":{"df":0,"docs":{},"u":{"df":0,"docs":{},"s":{"df":1,"docs":{"21":{"tf":1.4142135623730951}},"i":{"df":0,"docs":{},"v":{"df":0,"docs":{},"e":{":":{":":{"<":{"d":{"df":0,"docs":{},"e":{"df":0,"docs":{},"v":{"df":0,"docs":{},"i":{"c":{"df":0,"docs":{},"e":{"df":0,"docs":{},"p":{"a":{"df":0,"docs":{},"t":{"df":0,"docs":{},"h":{"df":0,"docs":{},"t":{"df":0,"docs":{},"o":{"df":0,"docs":{},"t":{"df":0,"docs":{},"e":{"df":0,"docs":{},"x":{"df":0,"docs":{},"t":{"df":2,"docs":{"20":{"tf":1.0},"21":{"tf":1.0}}}}}}}}}}},"df":0,"docs":{}}}},"df":0,"docs":{}}}}},"df":0,"docs":{},"l":{"df":0,"docs":{},"o":{"a":{"d":{"df":0,"docs":{},"e":{"d":{"df":0,"docs":{},"i":{"df":0,"docs":{},"m":{"a":{"df":0,"docs":{},"g":{"df":0,"docs":{},"e":{">":{"(":{"b":{"df":0,"docs":{},"o":{"df":0,"docs":{},"o":{"df":0,"docs":{},"t":{"_":{"df":0,"docs":{},"s":{"df":0,"docs":{},"e":{"df":0,"docs":{},"r":{"df":0,"docs":{},"v":{"df":0,"docs":{},"i":{"c":{"df":0,"docs":{},"e":{"df":0,"docs":{},"s":{".":{"df":0,"docs":{},"i":{"df":0,"docs":{},"m":{"a":{"df":0,"docs":{},"g":{"df":0,"docs":{},"e":{"_":{"df":0,"docs":{},"h":{"a":{"df":0,"docs":{},"n":{"d":{"df":0,"docs":{},"l":{"df":2,"docs":{"20":{"tf":1.0},"21":{"tf":1.0}}}},"df":0,"docs":{}}},"df":0,"docs":{}}},"df":0,"docs":{}}}},"df":0,"docs":{}}}},"df":0,"docs":{}}}},"df":0,"docs":{}}}}}}},"df":0,"docs":{}}}}},"df":0,"docs":{}},"df":0,"docs":{}},"df":0,"docs":{}}}},"df":0,"docs":{}}}},"df":0,"docs":{}}},"df":0,"docs":{}},"df":0,"docs":{}}}},"df":0,"docs":{}},"df":0,"docs":{}},"df":0,"docs":{}}}}}}}},"df":0,"docs":{}}}},"df":0,"docs":{}}}},"df":0,"docs":{}}}}}}},"df":5,"docs":{"19":{"tf":2.23606797749979},"20":{"tf":1.7320508075688772},"21":{"tf":2.0},"22":{"tf":1.4142135623730951},"29":{"tf":1.0}}},"r":{"df":5,"docs":{"10":{"tf":1.0},"11":{"tf":1.0},"16":{"tf":1.0},"25":{"tf":1.4142135623730951},"29":{"tf":1.0}}}},"t":{"df":0,"docs":{},"i":{"df":0,"docs":{},"o":{"df":0,"docs":{},"n":{"<":{"&":{"df":0,"docs":{},"m":{"df":0,"docs":{},"u":{"df":0,"docs":{},"t":{"df":1,"docs":{"22":{"tf":1.4142135623730951}}}}}},"df":0,"docs":{}},"df":3,"docs":{"17":{"tf":1.0},"24":{"tf":1.0},"26":{"tf":1.0}}}}}}},"r":{"d":{"df":0,"docs":{},"e":{"df":0,"docs":{},"r":{"df":2,"docs":{"27":{"tf":1.0},"7":{"tf":1.0}}}}},"df":0,"docs":{},"i":{"df":0,"docs":{},"g":{"df":0,"docs":{},"i":{"df":0,"docs":{},"n":{"df":1,"docs":{"26":{"tf":1.0}}}}}}},"s":{"df":1,"docs":{"15":{"tf":1.0}}},"u":{"df":0,"docs":{},"t":{"df":2,"docs":{"21":{"tf":1.0},"33":{"tf":1.0}},"p":{"df":0,"docs":{},"u":{"df":0,"docs":{},"t":{"df":3,"docs":{"21":{"tf":1.0},"22":{"tf":1.7320508075688772},"5":{"tf":1.4142135623730951}}}}},"s":{"df":0,"docs":{},"i":{"d":{"df":1,"docs":{"25":{"tf":1.0}}},"df":0,"docs":{}}}}},"v":{"df":0,"docs":{},"e":{"df":0,"docs":{},"r":{"df":2,"docs":{"27":{"tf":1.0},"34":{"tf":1.0}},"v":{"df":0,"docs":{},"i":{"df":0,"docs":{},"e":{"df":0,"docs":{},"w":{"df":1,"docs":{"19":{"tf":1.0}}}}}},"w":{"df":0,"docs":{},"r":{"df":0,"docs":{},"i":{"df":0,"docs":{},"t":{"df":1,"docs":{"32":{"tf":1.0}}}}}}}},"m":{"df":0,"docs":{},"f":{"df":2,"docs":{"10":{"tf":2.0},"11":{"tf":1.7320508075688772}}}}}},"p":{".":{"df":0,"docs":{},"i":{"df":1,"docs":{"22":{"tf":1.7320508075688772}}},"x":{"df":1,"docs":{"22":{"tf":1.4142135623730951}}}},"a":{"c":{"df":0,"docs":{},"k":{"a":{"df":0,"docs":{},"g":{"df":1,"docs":{"11":{"tf":1.4142135623730951}},"e":{"'":{"df":1,"docs":{"11":{"tf":1.0}}},"df":0,"docs":{}}}},"df":1,"docs":{"31":{"tf":1.0}}}},"d":{"df":1,"docs":{"22":{"tf":1.0}}},"df":0,"docs":{},"g":{"df":0,"docs":{},"e":{"df":1,"docs":{"24":{"tf":1.0}}}},"n":{"df":0,"docs":{},"i":{"c":{"df":1,"docs":{"5":{"tf":1.0}}},"df":0,"docs":{}}},"r":{"a":{"df":0,"docs":{},"m":{"df":0,"docs":{},"e":{"df":0,"docs":{},"t":{"df":1,"docs":{"21":{"tf":1.4142135623730951}}}}}},"df":0,"docs":{},"s":{"df":0,"docs":{},"e":{"a":{"b":{"df":0,"docs":{},"l":{"df":1,"docs":{"31":{"tf":1.0}}}},"df":0,"docs":{}},"df":0,"docs":{}}},"t":{"df":2,"docs":{"27":{"tf":1.0},"5":{"tf":1.0}},"i":{"c":{"df":0,"docs":{},"u":{"df":0,"docs":{},"l":{"a":{"df":0,"docs":{},"r":{"df":2,"docs":{"19":{"tf":1.0},"35":{"tf":1.0}}}},"df":0,"docs":{}}}},"df":0,"docs":{},"t":{"df":7,"docs":{"12":{"tf":1.4142135623730951},"15":{"tf":3.3166247903554},"16":{"tf":2.0},"27":{"tf":1.0},"31":{"tf":1.0},"34":{"tf":3.3166247903554},"35":{"tf":2.6457513110645907}}}}}},"s":{"df":0,"docs":{},"s":{"df":2,"docs":{"21":{"tf":1.0},"23":{"tf":1.0}}}},"t":{"df":0,"docs":{},"h":{"/":{"df":0,"docs":{},"t":{"df":0,"docs":{},"o":{"/":{"d":{"df":0,"docs":{},"i":{"df":0,"docs":{},"s":{"df":0,"docs":{},"k":{"_":{"df":0,"docs":{},"p":{"a":{"df":0,"docs":{},"r":{"df":0,"docs":{},"t":{"df":0,"docs":{},"i":{"df":0,"docs":{},"t":{"df":1,"docs":{"16":{"tf":1.4142135623730951}}}}}}},"df":0,"docs":{}}},"df":1,"docs":{"16":{"tf":1.0}}}}}},"df":0,"docs":{},"y":{"df":0,"docs":{},"o":{"df":0,"docs":{},"u":{"df":0,"docs":{},"r":{"df":1,"docs":{"16":{"tf":1.0}}}}}}},"df":0,"docs":{}}}},"df":6,"docs":{"15":{"tf":1.0},"19":{"tf":1.0},"20":{"tf":2.0},"21":{"tf":1.7320508075688772},"31":{"tf":3.1622776601683795},"35":{"tf":1.0}}}},"u":{"df":0,"docs":{},"s":{"df":3,"docs":{"1":{"tf":1.0},"21":{"tf":1.0},"5":{"tf":1.0}}}}},"df":2,"docs":{"12":{"tf":1.0},"22":{"tf":2.0}},"e":{"df":0,"docs":{},"r":{"df":0,"docs":{},"s":{"df":0,"docs":{},"i":{"df":0,"docs":{},"s":{"df":0,"docs":{},"t":{"df":1,"docs":{"33":{"tf":1.0}}}}}}}},"h":{"a":{"df":0,"docs":{},"s":{"df":0,"docs":{},"e":{"df":1,"docs":{"25":{"tf":1.4142135623730951}}}}},"df":0,"docs":{},"y":{"df":0,"docs":{},"s":{"df":0,"docs":{},"i":{"c":{"df":1,"docs":{"29":{"tf":1.0}}},"df":0,"docs":{}}}}},"i":{"df":0,"docs":{},"x":{"df":0,"docs":{},"e":{"df":0,"docs":{},"l":{"(":{"&":{"df":0,"docs":{},"m":{"df":0,"docs":{},"u":{"df":0,"docs":{},"t":{"df":1,"docs":{"22":{"tf":1.4142135623730951}}}}}},"df":0,"docs":{}},".":{"b":{"df":0,"docs":{},"l":{"df":0,"docs":{},"u":{"df":1,"docs":{"22":{"tf":1.4142135623730951}}}}},"df":0,"docs":{},"g":{"df":0,"docs":{},"r":{"df":0,"docs":{},"e":{"df":0,"docs":{},"e":{"df":0,"docs":{},"n":{"df":1,"docs":{"22":{"tf":1.4142135623730951}}}}}}},"r":{"df":1,"docs":{"22":{"tf":1.4142135623730951}}}},"df":1,"docs":{"22":{"tf":3.3166247903554}}}}}},"l":{"a":{"c":{"df":0,"docs":{},"e":{"df":3,"docs":{"21":{"tf":1.0},"27":{"tf":1.0},"30":{"tf":1.0}}}},"df":0,"docs":{},"t":{"df":0,"docs":{},"f":{"df":0,"docs":{},"o":{"df":0,"docs":{},"r":{"df":0,"docs":{},"m":{"df":1,"docs":{"25":{"tf":1.4142135623730951}}}}}}}},"df":0,"docs":{},"u":{"df":1,"docs":{"32":{"tf":1.0}}}},"o":{"df":0,"docs":{},"i":{"df":0,"docs":{},"n":{"df":0,"docs":{},"t":{":":{":":{"df":0,"docs":{},"n":{"df":0,"docs":{},"e":{"df":0,"docs":{},"w":{"(":{"b":{"df":0,"docs":{},"o":{"df":0,"docs":{},"r":{"d":{"df":1,"docs":{"22":{"tf":1.0}}},"df":0,"docs":{}}}},"df":0,"docs":{},"s":{"df":0,"docs":{},"i":{"df":0,"docs":{},"z":{"df":0,"docs":{},"e":{".":{"df":0,"docs":{},"x":{"df":1,"docs":{"22":{"tf":1.7320508075688772}}}},"df":0,"docs":{}}}}},"w":{"df":0,"docs":{},"i":{"d":{"df":0,"docs":{},"t":{"df":0,"docs":{},"h":{"df":1,"docs":{"22":{"tf":1.0}}}}},"df":0,"docs":{}}}},"df":0,"docs":{}}}}},"df":0,"docs":{}},"df":3,"docs":{"22":{"tf":2.0},"26":{"tf":1.0},"5":{"tf":1.0}},"e":{"df":0,"docs":{},"r":{"df":2,"docs":{"29":{"tf":1.0},"31":{"tf":1.0}}}}}}},"o":{"df":0,"docs":{},"r":{"df":1,"docs":{"33":{"tf":1.0}}}},"w":{"df":0,"docs":{},"e":{"df":0,"docs":{},"r":{"df":1,"docs":{"33":{"tf":1.0}}}}}},"r":{"a":{"c":{"df":0,"docs":{},"t":{"df":0,"docs":{},"i":{"c":{"df":1,"docs":{"18":{"tf":1.0}}},"df":0,"docs":{}}}},"df":0,"docs":{}},"df":0,"docs":{},"e":{"c":{"df":0,"docs":{},"i":{"df":0,"docs":{},"s":{"df":1,"docs":{"34":{"tf":1.0}}}}},"df":0,"docs":{},"p":{"a":{"df":0,"docs":{},"r":{"df":2,"docs":{"14":{"tf":1.0},"15":{"tf":1.4142135623730951}}}},"df":0,"docs":{}},"s":{"df":0,"docs":{},"s":{"df":1,"docs":{"17":{"tf":1.7320508075688772}}}},"v":{"df":0,"docs":{},"e":{"df":0,"docs":{},"n":{"df":0,"docs":{},"t":{"df":1,"docs":{"33":{"tf":1.0}}}}},"i":{"df":0,"docs":{},"o":{"df":0,"docs":{},"u":{"df":1,"docs":{"21":{"tf":1.0}}}}}}},"i":{"df":0,"docs":{},"m":{"a":{"df":0,"docs":{},"r":{"df":0,"docs":{},"i":{"df":1,"docs":{"34":{"tf":1.0}}}}},"df":0,"docs":{}},"n":{"df":0,"docs":{},"t":{"_":{"df":0,"docs":{},"i":{"df":0,"docs":{},"m":{"a":{"df":0,"docs":{},"g":{"df":0,"docs":{},"e":{"_":{"df":0,"docs":{},"p":{"a":{"df":0,"docs":{},"t":{"df":0,"docs":{},"h":{"(":{"b":{"df":0,"docs":{},"o":{"df":0,"docs":{},"o":{"df":0,"docs":{},"t":{"_":{"df":0,"docs":{},"s":{"df":0,"docs":{},"e":{"df":0,"docs":{},"r":{"df":0,"docs":{},"v":{"df":0,"docs":{},"i":{"c":{"df":2,"docs":{"20":{"tf":1.0},"21":{"tf":1.0}},"e":{"df":0,"docs":{},"s":{")":{".":{"df":0,"docs":{},"u":{"df":0,"docs":{},"n":{"df":0,"docs":{},"w":{"df":0,"docs":{},"r":{"a":{"df":0,"docs":{},"p":{"df":1,"docs":{"20":{"tf":1.0}}}},"df":0,"docs":{}}}}}},"df":0,"docs":{}},"df":0,"docs":{}}}},"df":0,"docs":{}}}}}}},"df":0,"docs":{}}}}},"df":0,"docs":{}},"df":1,"docs":{"21":{"tf":1.4142135623730951}}}}},"df":0,"docs":{}}},"df":0,"docs":{}}}},"df":0,"docs":{}}}},"df":2,"docs":{"1":{"tf":1.0},"20":{"tf":1.0}}}}},"o":{"c":{"df":0,"docs":{},"e":{"df":0,"docs":{},"s":{"df":0,"docs":{},"s":{"df":2,"docs":{"1":{"tf":1.0},"25":{"tf":1.0}}}}}},"d":{"df":0,"docs":{},"u":{"c":{"df":2,"docs":{"23":{"tf":1.0},"8":{"tf":1.0}}},"df":0,"docs":{}}},"df":0,"docs":{},"g":{"df":0,"docs":{},"r":{"a":{"df":0,"docs":{},"m":{"'":{"df":1,"docs":{"21":{"tf":1.0}}},"df":4,"docs":{"20":{"tf":2.449489742783178},"21":{"tf":1.0},"33":{"tf":1.0},"5":{"tf":1.4142135623730951}}}},"df":0,"docs":{}}},"j":{"df":0,"docs":{},"e":{"c":{"df":0,"docs":{},"t":{"df":1,"docs":{"11":{"tf":1.4142135623730951}}}},"df":0,"docs":{}}},"t":{"df":0,"docs":{},"o":{"c":{"df":0,"docs":{},"o":{"df":0,"docs":{},"l":{"'":{"df":1,"docs":{"22":{"tf":1.0}}},"df":9,"docs":{"19":{"tf":3.0},"20":{"tf":1.7320508075688772},"21":{"tf":2.8284271247461903},"22":{"tf":1.7320508075688772},"26":{"tf":1.0},"27":{"tf":1.0},"28":{"tf":1.4142135623730951},"29":{"tf":1.0},"30":{"tf":3.3166247903554}}}}},"df":0,"docs":{}}},"v":{"df":0,"docs":{},"i":{"d":{"df":8,"docs":{"10":{"tf":1.0},"11":{"tf":1.4142135623730951},"19":{"tf":1.0},"26":{"tf":2.0},"28":{"tf":1.0},"30":{"tf":1.4142135623730951},"32":{"tf":1.0},"5":{"tf":1.4142135623730951}}},"df":0,"docs":{}}}}},"u":{"df":0,"docs":{},"r":{"df":0,"docs":{},"p":{"df":0,"docs":{},"o":{"df":0,"docs":{},"s":{"df":1,"docs":{"34":{"tf":1.0}}}}}},"t":{"df":1,"docs":{"25":{"tf":1.0}}}}},"q":{"df":0,"docs":{},"e":{"df":0,"docs":{},"m":{"df":0,"docs":{},"u":{"df":3,"docs":{"0":{"tf":1.0},"10":{"tf":2.23606797749979},"13":{"tf":1.7320508075688772}}}}},"u":{"df":0,"docs":{},"i":{"c":{"df":0,"docs":{},"k":{"df":1,"docs":{"5":{"tf":1.0}}}},"df":0,"docs":{},"r":{"df":0,"docs":{},"k":{"df":1,"docs":{"33":{"tf":1.0}}}}}}},"r":{"a":{"df":0,"docs":{},"n":{"d":{"df":0,"docs":{},"o":{"df":0,"docs":{},"m":{"df":1,"docs":{"22":{"tf":1.7320508075688772}}}}},"df":0,"docs":{},"g":{"df":1,"docs":{"21":{"tf":1.0}}}},"w":{"df":1,"docs":{"36":{"tf":1.0}}}},"df":1,"docs":{"22":{"tf":1.4142135623730951}},"e":{"a":{"d":{"a":{"b":{"df":0,"docs":{},"l":{"df":1,"docs":{"31":{"tf":1.0}}}},"df":0,"docs":{}},"df":3,"docs":{"21":{"tf":1.0},"30":{"tf":1.0},"33":{"tf":1.0}}},"df":0,"docs":{},"l":{"df":1,"docs":{"14":{"tf":1.0}}}},"b":{"df":0,"docs":{},"o":{"df":0,"docs":{},"o":{"df":0,"docs":{},"t":{"df":1,"docs":{"17":{"tf":1.0}}}}}},"c":{"df":0,"docs":{},"o":{"df":0,"docs":{},"r":{"d":{"df":1,"docs":{"34":{"tf":1.0}}},"df":0,"docs":{}}}},"d":{"df":1,"docs":{"22":{"tf":1.0}},"u":{"df":0,"docs":{},"n":{"d":{"df":1,"docs":{"34":{"tf":1.0}}},"df":0,"docs":{}}}},"df":0,"docs":{},"f":{"df":0,"docs":{},"e":{"df":0,"docs":{},"r":{"df":3,"docs":{"11":{"tf":1.0},"21":{"tf":1.0},"36":{"tf":2.23606797749979}}}}},"g":{"df":0,"docs":{},"u":{"df":0,"docs":{},"l":{"a":{"df":0,"docs":{},"r":{"df":1,"docs":{"21":{"tf":1.0}}}},"df":0,"docs":{}}}},"l":{"a":{"df":0,"docs":{},"t":{"df":2,"docs":{"24":{"tf":1.0},"33":{"tf":1.0}}}},"df":1,"docs":{"34":{"tf":1.0}},"e":{"df":0,"docs":{},"v":{"df":2,"docs":{"0":{"tf":1.0},"24":{"tf":1.0}}}}},"m":{"df":0,"docs":{},"o":{"df":0,"docs":{},"v":{"df":1,"docs":{"7":{"tf":1.0}}}}},"p":{"df":0,"docs":{},"l":{"a":{"c":{"df":1,"docs":{"4":{"tf":1.0}}},"df":0,"docs":{}},"df":0,"docs":{}},"o":{"df":0,"docs":{},"s":{"df":0,"docs":{},"i":{"df":0,"docs":{},"t":{"df":0,"docs":{},"o":{"df":0,"docs":{},"r":{"df":0,"docs":{},"i":{"df":2,"docs":{"22":{"tf":1.0},"7":{"tf":1.0}}}}}}}}},"r":{"df":0,"docs":{},"e":{"df":0,"docs":{},"s":{"df":4,"docs":{"27":{"tf":1.0},"29":{"tf":1.0},"33":{"tf":1.0},"5":{"tf":1.0}},"e":{"df":0,"docs":{},"n":{"df":0,"docs":{},"t":{"df":2,"docs":{"27":{"tf":1.7320508075688772},"31":{"tf":1.0}}}}}}}}},"q":{"df":0,"docs":{},"u":{"df":0,"docs":{},"i":{"df":0,"docs":{},"r":{"df":2,"docs":{"15":{"tf":1.4142135623730951},"5":{"tf":1.0}}}}}},"s":{"df":0,"docs":{},"e":{"df":0,"docs":{},"t":{"df":1,"docs":{"25":{"tf":1.0}}}},"o":{"df":0,"docs":{},"u":{"df":0,"docs":{},"r":{"c":{"df":3,"docs":{"29":{"tf":1.4142135623730951},"30":{"tf":1.0},"31":{"tf":1.0}}},"df":0,"docs":{}}}},"t":{"df":2,"docs":{"21":{"tf":1.0},"22":{"tf":1.0}}},"u":{"df":0,"docs":{},"l":{"df":0,"docs":{},"t":{"df":3,"docs":{"20":{"tf":1.4142135623730951},"21":{"tf":1.4142135623730951},"22":{"tf":1.7320508075688772}}}}}},"t":{"df":0,"docs":{},"u":{"df":0,"docs":{},"r":{"df":0,"docs":{},"n":{"df":5,"docs":{"19":{"tf":1.0},"21":{"tf":1.0},"25":{"tf":1.0},"26":{"tf":1.0},"5":{"tf":1.4142135623730951}}}}}}},"i":{"df":0,"docs":{},"s":{"c":{"df":1,"docs":{"35":{"tf":1.7320508075688772}}},"df":0,"docs":{}}},"n":{"df":0,"docs":{},"g":{".":{"df":0,"docs":{},"g":{"df":0,"docs":{},"e":{"df":0,"docs":{},"t":{"_":{"df":0,"docs":{},"r":{"df":0,"docs":{},"n":{"df":0,"docs":{},"g":{"(":{"df":0,"docs":{},"n":{"df":0,"docs":{},"o":{"df":0,"docs":{},"n":{"df":1,"docs":{"22":{"tf":1.0}}}}}},"df":0,"docs":{}}}}},"df":0,"docs":{}}}}},"_":{"df":0,"docs":{},"h":{"a":{"df":0,"docs":{},"n":{"d":{"df":0,"docs":{},"l":{"df":1,"docs":{"22":{"tf":1.0}}}},"df":0,"docs":{}}},"df":0,"docs":{}}},"df":1,"docs":{"22":{"tf":1.7320508075688772}}}},"o":{"df":0,"docs":{},"o":{"df":0,"docs":{},"t":{"df":1,"docs":{"7":{"tf":1.0}}}}},"s":{"df":7,"docs":{"0":{"tf":1.0},"21":{"tf":1.0},"22":{"tf":1.0},"24":{"tf":1.0},"25":{"tf":1.0},"27":{"tf":1.0},"30":{"tf":1.4142135623730951}}},"u":{"df":0,"docs":{},"n":{"df":11,"docs":{"1":{"tf":1.0},"10":{"tf":1.0},"14":{"tf":1.4142135623730951},"16":{"tf":1.0},"20":{"tf":1.4142135623730951},"21":{"tf":1.0},"22":{"tf":1.4142135623730951},"25":{"tf":1.4142135623730951},"5":{"tf":1.0},"8":{"tf":1.0},"9":{"tf":1.0}},"t":{"df":0,"docs":{},"i":{"df":0,"docs":{},"m":{"df":5,"docs":{"23":{"tf":1.0},"25":{"tf":2.0},"26":{"tf":1.0},"30":{"tf":1.0},"33":{"tf":1.0}},"e":{"_":{"a":{"c":{"c":{"df":0,"docs":{},"e":{"df":0,"docs":{},"s":{"df":0,"docs":{},"s":{"df":1,"docs":{"33":{"tf":1.0}}}}}},"df":0,"docs":{}},"df":0,"docs":{}},"df":0,"docs":{}},"df":0,"docs":{},"s":{"df":0,"docs":{},"e":{"df":0,"docs":{},"r":{"df":0,"docs":{},"v":{"df":0,"docs":{},"i":{"c":{"df":2,"docs":{"25":{"tf":1.4142135623730951},"26":{"tf":1.4142135623730951}}},"df":0,"docs":{}}}}}}}}}}},"s":{"df":0,"docs":{},"t":{"'":{"df":1,"docs":{"23":{"tf":1.0}}},"df":6,"docs":{"0":{"tf":1.4142135623730951},"1":{"tf":1.0},"3":{"tf":1.4142135623730951},"36":{"tf":1.0},"5":{"tf":1.7320508075688772},"7":{"tf":1.0}},"f":{"df":0,"docs":{},"l":{"a":{"df":0,"docs":{},"g":{"df":1,"docs":{"23":{"tf":1.4142135623730951}}}},"df":0,"docs":{}}},"u":{"df":0,"docs":{},"p":{"df":1,"docs":{"7":{"tf":1.0}}}}}}}},"s":{"a":{"df":0,"docs":{},"f":{"df":0,"docs":{},"e":{"df":0,"docs":{},"s":{"df":0,"docs":{},"t":{"df":1,"docs":{"19":{"tf":1.0}}}}}},"m":{"df":0,"docs":{},"e":{"df":4,"docs":{"19":{"tf":1.0},"27":{"tf":1.0},"31":{"tf":1.0},"32":{"tf":1.0}}}}},"c":{"df":0,"docs":{},"o":{"df":0,"docs":{},"p":{"df":0,"docs":{},"e":{"d":{"df":0,"docs":{},"p":{"df":0,"docs":{},"r":{"df":0,"docs":{},"o":{"df":0,"docs":{},"t":{"df":0,"docs":{},"o":{"c":{"df":0,"docs":{},"o":{"df":0,"docs":{},"l":{"df":1,"docs":{"19":{"tf":1.0}}}}},"df":0,"docs":{}}}}}}},"df":1,"docs":{"25":{"tf":1.0}}}}},"r":{"df":0,"docs":{},"e":{"df":0,"docs":{},"e":{"df":0,"docs":{},"n":{"df":1,"docs":{"22":{"tf":2.0}},"s":{"df":0,"docs":{},"h":{"df":0,"docs":{},"o":{"df":0,"docs":{},"t":{"df":1,"docs":{"22":{"tf":1.0}}}}}}}}}}},"df":1,"docs":{"22":{"tf":1.0}},"e":{"c":{"df":0,"docs":{},"o":{"df":0,"docs":{},"n":{"d":{"a":{"df":0,"docs":{},"r":{"df":0,"docs":{},"i":{"df":1,"docs":{"34":{"tf":1.0}}}}},"df":4,"docs":{"1":{"tf":1.0},"13":{"tf":1.0},"21":{"tf":1.0},"5":{"tf":1.0}}},"df":0,"docs":{}}}},"df":0,"docs":{},"e":{"df":6,"docs":{"13":{"tf":1.0},"15":{"tf":1.4142135623730951},"19":{"tf":1.0},"30":{"tf":1.0},"31":{"tf":1.0},"5":{"tf":1.0}}},"l":{"df":0,"docs":{},"e":{"c":{"df":0,"docs":{},"t":{"df":1,"docs":{"17":{"tf":1.0}}}},"df":0,"docs":{}},"f":{".":{"df":0,"docs":{},"h":{"df":0,"docs":{},"e":{"df":0,"docs":{},"i":{"df":0,"docs":{},"g":{"df":0,"docs":{},"h":{"df":0,"docs":{},"t":{"df":1,"docs":{"22":{"tf":1.4142135623730951}}}}}}}},"p":{"df":0,"docs":{},"i":{"df":0,"docs":{},"x":{"df":0,"docs":{},"e":{"df":0,"docs":{},"l":{"df":1,"docs":{"22":{"tf":1.4142135623730951}},"s":{".":{"df":0,"docs":{},"g":{"df":0,"docs":{},"e":{"df":0,"docs":{},"t":{"_":{"df":0,"docs":{},"m":{"df":0,"docs":{},"u":{"df":0,"docs":{},"t":{"(":{"df":0,"docs":{},"i":{"df":1,"docs":{"22":{"tf":1.4142135623730951}}}},"df":0,"docs":{}}}}},"df":0,"docs":{}}}}},"df":0,"docs":{}}}}}}},"w":{"df":0,"docs":{},"i":{"d":{"df":0,"docs":{},"t":{"df":0,"docs":{},"h":{"df":1,"docs":{"22":{"tf":2.0}}}}},"df":0,"docs":{}}}},"df":1,"docs":{"22":{"tf":2.449489742783178}}}},"p":{"a":{"df":0,"docs":{},"r":{"df":1,"docs":{"25":{"tf":1.0}}}},"df":0,"docs":{}},"r":{"df":0,"docs":{},"v":{"df":1,"docs":{"32":{"tf":1.0}},"i":{"c":{"df":9,"docs":{"23":{"tf":1.0},"24":{"tf":1.0},"25":{"tf":1.4142135623730951},"26":{"tf":2.23606797749979},"30":{"tf":1.0},"33":{"tf":1.4142135623730951},"36":{"tf":1.0},"4":{"tf":1.0},"5":{"tf":1.0}}},"df":0,"docs":{}}}},"t":{"df":12,"docs":{"15":{"tf":1.0},"16":{"tf":1.0},"20":{"tf":1.0},"21":{"tf":1.4142135623730951},"22":{"tf":1.0},"23":{"tf":1.0},"26":{"tf":1.0},"3":{"tf":1.0},"33":{"tf":2.0},"35":{"tf":1.0},"5":{"tf":1.0},"7":{"tf":1.0}}},"v":{"df":0,"docs":{},"e":{"df":0,"docs":{},"r":{"df":1,"docs":{"25":{"tf":1.0}}}}}},"g":{"d":{"df":0,"docs":{},"i":{"df":0,"docs":{},"s":{"df":0,"docs":{},"k":{"df":1,"docs":{"16":{"tf":1.0}}}}}},"df":0,"docs":{}},"h":{"df":0,"docs":{},"o":{"df":0,"docs":{},"r":{"df":0,"docs":{},"t":{"df":3,"docs":{"27":{"tf":1.0},"34":{"tf":1.0},"35":{"tf":1.0}},"l":{"df":0,"docs":{},"i":{"df":1,"docs":{"20":{"tf":1.0}}}}}},"w":{"df":1,"docs":{"22":{"tf":1.0}}}}},"i":{"df":0,"docs":{},"e":{"df":0,"docs":{},"r":{"df":0,"docs":{},"p":{"df":0,"docs":{},"i":{"df":0,"docs":{},"n":{"df":0,"docs":{},"s":{"df":0,"docs":{},"k":{"df":0,"docs":{},"i":{"df":1,"docs":{"22":{"tf":1.0}}}}}},"ń":{"df":0,"docs":{},"s":{"df":0,"docs":{},"k":{"df":0,"docs":{},"i":{"df":1,"docs":{"22":{"tf":1.0}}}}}}}}}},"m":{"df":0,"docs":{},"p":{"df":0,"docs":{},"l":{"df":3,"docs":{"1":{"tf":1.0},"22":{"tf":1.0},"5":{"tf":1.0}},"e":{"df":0,"docs":{},"r":{"df":1,"docs":{"5":{"tf":1.0}}}}}}},"n":{"df":0,"docs":{},"g":{"df":0,"docs":{},"l":{"df":1,"docs":{"22":{"tf":1.7320508075688772}}}}},"z":{"df":0,"docs":{},"e":{".":{"df":0,"docs":{},"i":{"df":1,"docs":{"22":{"tf":1.7320508075688772}}}},"df":2,"docs":{"22":{"tf":1.0},"33":{"tf":1.0}}}}},"l":{"df":0,"docs":{},"i":{"c":{"df":0,"docs":{},"e":{"df":1,"docs":{"19":{"tf":1.0}}}},"df":0,"docs":{}}},"o":{"df":0,"docs":{},"m":{"df":0,"docs":{},"e":{"df":0,"docs":{},"t":{"df":0,"docs":{},"h":{"df":2,"docs":{"20":{"tf":1.0},"29":{"tf":1.0}}},"i":{"df":0,"docs":{},"m":{"df":1,"docs":{"35":{"tf":1.0}}}}}}},"u":{"df":0,"docs":{},"r":{"c":{"df":1,"docs":{"24":{"tf":1.0}}},"df":0,"docs":{}}}},"p":{"a":{"c":{"df":0,"docs":{},"e":{"df":1,"docs":{"33":{"tf":1.0}}}},"df":0,"docs":{}},"df":0,"docs":{},"e":{"c":{"df":0,"docs":{},"i":{"a":{"df":0,"docs":{},"l":{"df":3,"docs":{"14":{"tf":1.0},"33":{"tf":1.0},"35":{"tf":1.0}}}},"df":0,"docs":{},"f":{"df":9,"docs":{"15":{"tf":1.4142135623730951},"21":{"tf":1.4142135623730951},"24":{"tf":1.4142135623730951},"25":{"tf":1.4142135623730951},"26":{"tf":1.7320508075688772},"27":{"tf":1.0},"30":{"tf":1.4142135623730951},"34":{"tf":1.0},"36":{"tf":1.0}},"i":{"df":1,"docs":{"7":{"tf":1.0}}}}}},"df":0,"docs":{}}},"r":{"c":{"/":{"df":0,"docs":{},"m":{"a":{"df":0,"docs":{},"i":{"df":0,"docs":{},"n":{".":{"df":0,"docs":{},"r":{"df":1,"docs":{"4":{"tf":1.0}},"s":{"@":{"0":{"1":{"1":{"df":1,"docs":{"13":{"tf":1.0}}},"df":0,"docs":{}},"df":0,"docs":{}},"df":0,"docs":{}},"df":0,"docs":{}}}},"df":0,"docs":{}}}},"df":0,"docs":{}}},"df":1,"docs":{"22":{"tf":1.4142135623730951}}},"df":0,"docs":{}},"t":{"a":{"df":0,"docs":{},"g":{"df":0,"docs":{},"e":{"df":4,"docs":{"25":{"tf":2.23606797749979},"26":{"tf":1.4142135623730951},"30":{"tf":1.4142135623730951},"33":{"tf":1.0}}}},"l":{"df":0,"docs":{},"l":{"df":1,"docs":{"5":{"tf":1.0}}}},"n":{"d":{"a":{"df":0,"docs":{},"r":{"d":{"df":4,"docs":{"27":{"tf":1.0},"34":{"tf":1.0},"35":{"tf":1.0},"5":{"tf":1.7320508075688772}}},"df":0,"docs":{}}},"df":0,"docs":{}},"df":0,"docs":{}},"r":{"df":0,"docs":{},"t":{"/":{"df":0,"docs":{},"e":{"df":0,"docs":{},"n":{"d":{"df":1,"docs":{"34":{"tf":1.0}}},"df":0,"docs":{}}}},"df":4,"docs":{"16":{"tf":1.0},"21":{"tf":1.4142135623730951},"22":{"tf":1.0},"5":{"tf":1.0}}}},"t":{"df":0,"docs":{},"u":{"df":5,"docs":{"20":{"tf":1.0},"22":{"tf":1.0},"26":{"tf":1.0},"4":{"tf":1.0},"5":{"tf":1.4142135623730951}},"s":{":":{":":{"df":0,"docs":{},"s":{"df":0,"docs":{},"u":{"c":{"c":{"df":0,"docs":{},"e":{"df":0,"docs":{},"s":{"df":0,"docs":{},"s":{"df":4,"docs":{"20":{"tf":1.0},"22":{"tf":1.0},"4":{"tf":1.0},"5":{"tf":1.4142135623730951}}}}}},"df":0,"docs":{}},"df":0,"docs":{}}}},"df":0,"docs":{}},"df":0,"docs":{}}}}},"d":{"df":1,"docs":{"5":{"tf":1.0}}},"df":0,"docs":{},"e":{"df":0,"docs":{},"p":{"df":1,"docs":{"15":{"tf":1.4142135623730951}}}},"i":{"df":0,"docs":{},"l":{"df":0,"docs":{},"l":{"df":3,"docs":{"25":{"tf":1.0},"28":{"tf":1.0},"5":{"tf":1.0}}}}},"o":{"df":0,"docs":{},"r":{"a":{"df":0,"docs":{},"g":{"df":4,"docs":{"11":{"tf":1.0},"26":{"tf":1.0},"32":{"tf":1.0},"33":{"tf":1.4142135623730951}}}},"df":0,"docs":{},"e":{"df":5,"docs":{"19":{"tf":1.0},"22":{"tf":1.0},"31":{"tf":1.0},"32":{"tf":1.0},"33":{"tf":1.7320508075688772}}}}},"r":{"df":0,"docs":{},"i":{"c":{"df":0,"docs":{},"t":{"df":0,"docs":{},"l":{"df":0,"docs":{},"i":{"df":2,"docs":{"15":{"tf":1.4142135623730951},"5":{"tf":1.0}}}}}},"df":0,"docs":{},"n":{"df":0,"docs":{},"g":{"df":1,"docs":{"27":{"tf":1.4142135623730951}}}}},"u":{"c":{"df":0,"docs":{},"t":{"df":1,"docs":{"22":{"tf":1.7320508075688772}},"u":{"df":0,"docs":{},"r":{"df":5,"docs":{"12":{"tf":1.0},"15":{"tf":1.0},"26":{"tf":1.0},"31":{"tf":1.4142135623730951},"34":{"tf":1.0}}}}}},"df":0,"docs":{}}}},"u":{"b":{"df":0,"docs":{},"s":{"df":0,"docs":{},"y":{"df":0,"docs":{},"s":{"df":0,"docs":{},"t":{"df":0,"docs":{},"e":{"df":0,"docs":{},"m":{"df":1,"docs":{"23":{"tf":1.0}}}}}}}}},"c":{"c":{"df":0,"docs":{},"e":{"df":0,"docs":{},"s":{"df":0,"docs":{},"s":{"df":2,"docs":{"21":{"tf":1.0},"5":{"tf":1.0}},"f":{"df":0,"docs":{},"u":{"df":0,"docs":{},"l":{"df":0,"docs":{},"l":{"df":0,"docs":{},"i":{"df":1,"docs":{"5":{"tf":1.0}}}}}}}}}}},"df":0,"docs":{},"h":{"df":5,"docs":{"0":{"tf":1.0},"25":{"tf":1.0},"26":{"tf":1.0},"29":{"tf":1.0},"31":{"tf":1.0}}}},"d":{"df":0,"docs":{},"o":{"df":1,"docs":{"10":{"tf":1.4142135623730951}}}},"df":0,"docs":{},"m":{"df":0,"docs":{},"m":{"a":{"df":0,"docs":{},"r":{"df":1,"docs":{"24":{"tf":1.0}}}},"df":0,"docs":{}}},"p":{"df":0,"docs":{},"p":{"df":0,"docs":{},"o":{"df":0,"docs":{},"r":{"df":0,"docs":{},"t":{"df":4,"docs":{"19":{"tf":1.0},"21":{"tf":1.0},"34":{"tf":1.0},"7":{"tf":1.0}}}}}}}},"y":{"df":0,"docs":{},"s":{"df":0,"docs":{},"t":{"df":0,"docs":{},"e":{"df":0,"docs":{},"m":{"_":{"df":0,"docs":{},"t":{"a":{"b":{"df":0,"docs":{},"l":{"df":0,"docs":{},"e":{")":{".":{"df":0,"docs":{},"u":{"df":0,"docs":{},"n":{"df":0,"docs":{},"w":{"df":0,"docs":{},"r":{"a":{"df":0,"docs":{},"p":{"df":4,"docs":{"20":{"tf":1.0},"22":{"tf":1.0},"4":{"tf":1.0},"5":{"tf":1.0}}}},"df":0,"docs":{}}}}}},"df":0,"docs":{}},".":{"b":{"df":0,"docs":{},"o":{"df":0,"docs":{},"o":{"df":0,"docs":{},"t":{"_":{"df":0,"docs":{},"s":{"df":0,"docs":{},"e":{"df":0,"docs":{},"r":{"df":0,"docs":{},"v":{"df":0,"docs":{},"i":{"c":{"df":2,"docs":{"20":{"tf":1.0},"22":{"tf":1.0}},"e":{"df":0,"docs":{},"s":{"(":{")":{".":{"df":0,"docs":{},"s":{"df":0,"docs":{},"t":{"a":{"df":0,"docs":{},"l":{"df":0,"docs":{},"l":{"(":{"1":{"0":{"_":{"0":{"0":{"0":{"_":{"0":{"0":{"0":{"df":2,"docs":{"4":{"tf":1.0},"5":{"tf":1.0}}},"df":0,"docs":{}},"df":0,"docs":{}},"df":0,"docs":{}},"df":0,"docs":{}},"df":0,"docs":{}},"df":0,"docs":{}},"df":0,"docs":{}},"df":0,"docs":{}},"df":0,"docs":{}},"df":0,"docs":{}},"df":0,"docs":{}}}},"df":0,"docs":{}}}},"df":0,"docs":{}},"df":0,"docs":{}},"df":0,"docs":{}}}},"df":0,"docs":{}}}}}}},"df":0,"docs":{}}}}},"df":0,"docs":{}},"df":0,"docs":{}}}},"df":0,"docs":{}},"df":5,"docs":{"20":{"tf":1.0},"22":{"tf":1.0},"26":{"tf":1.0},"4":{"tf":1.0},"5":{"tf":1.0}}}},"df":13,"docs":{"10":{"tf":1.0},"11":{"tf":1.0},"12":{"tf":1.4142135623730951},"13":{"tf":1.0},"15":{"tf":1.4142135623730951},"16":{"tf":1.0},"20":{"tf":1.0},"25":{"tf":2.449489742783178},"26":{"tf":2.0},"31":{"tf":1.4142135623730951},"34":{"tf":1.0},"35":{"tf":2.6457513110645907},"5":{"tf":1.7320508075688772}},"t":{"a":{"b":{"df":0,"docs":{},"l":{"df":0,"docs":{},"e":{":":{":":{"b":{"df":0,"docs":{},"o":{"df":0,"docs":{},"o":{"df":0,"docs":{},"t":{"_":{"df":0,"docs":{},"s":{"df":0,"docs":{},"e":{"df":0,"docs":{},"r":{"df":0,"docs":{},"v":{"df":0,"docs":{},"i":{"c":{"df":1,"docs":{"26":{"tf":1.0}}},"df":0,"docs":{}}}}}}},"df":0,"docs":{}}}}},"df":0,"docs":{},"e":{"df":0,"docs":{},"x":{"df":0,"docs":{},"i":{"df":0,"docs":{},"t":{"_":{"b":{"df":0,"docs":{},"o":{"df":0,"docs":{},"o":{"df":0,"docs":{},"t":{"_":{"df":0,"docs":{},"s":{"df":0,"docs":{},"e":{"df":0,"docs":{},"r":{"df":0,"docs":{},"v":{"df":0,"docs":{},"i":{"c":{"df":2,"docs":{"25":{"tf":1.0},"26":{"tf":1.0}}},"df":0,"docs":{}}}}}}},"df":0,"docs":{}}}}},"df":0,"docs":{}},"df":0,"docs":{}}}}},"r":{"df":0,"docs":{},"u":{"df":0,"docs":{},"n":{"df":0,"docs":{},"t":{"df":0,"docs":{},"i":{"df":0,"docs":{},"m":{"df":0,"docs":{},"e":{"_":{"df":0,"docs":{},"s":{"df":0,"docs":{},"e":{"df":0,"docs":{},"r":{"df":0,"docs":{},"v":{"df":0,"docs":{},"i":{"c":{"df":1,"docs":{"26":{"tf":1.0}}},"df":0,"docs":{}}}}}}},"df":0,"docs":{}}}}}}}}},"df":0,"docs":{}},"<":{"b":{"df":0,"docs":{},"o":{"df":0,"docs":{},"o":{"df":0,"docs":{},"t":{"df":5,"docs":{"20":{"tf":1.0},"22":{"tf":1.0},"26":{"tf":1.0},"4":{"tf":1.0},"5":{"tf":1.0}}}}}},"df":0,"docs":{}},"df":0,"docs":{}}}},"df":0,"docs":{}},"df":1,"docs":{"26":{"tf":1.0}}}}}}}}},"t":{"a":{"b":{"df":0,"docs":{},"l":{"df":5,"docs":{"15":{"tf":1.0},"25":{"tf":1.7320508075688772},"26":{"tf":3.4641016151377544},"34":{"tf":1.4142135623730951},"5":{"tf":1.4142135623730951}}}},"df":0,"docs":{},"k":{"df":0,"docs":{},"e":{"df":2,"docs":{"21":{"tf":1.4142135623730951},"5":{"tf":1.0}}}},"n":{"df":0,"docs":{},"g":{"df":0,"docs":{},"i":{"b":{"df":0,"docs":{},"l":{"df":1,"docs":{"29":{"tf":1.0}}}},"df":0,"docs":{}}}},"r":{"df":0,"docs":{},"g":{"df":0,"docs":{},"e":{"df":0,"docs":{},"t":{"/":{"df":0,"docs":{},"x":{"8":{"6":{"_":{"6":{"4":{"df":2,"docs":{"12":{"tf":1.0},"8":{"tf":1.0}}},"df":0,"docs":{}},"df":0,"docs":{}},"df":0,"docs":{}},"df":0,"docs":{}},"df":0,"docs":{}}},"df":5,"docs":{"17":{"tf":1.0},"23":{"tf":1.0},"36":{"tf":1.0},"7":{"tf":1.7320508075688772},"8":{"tf":1.0}}}}}}},"df":0,"docs":{},"e":{"df":0,"docs":{},"n":{"df":1,"docs":{"21":{"tf":1.0}}},"r":{"df":0,"docs":{},"m":{"df":1,"docs":{"19":{"tf":1.0}},"i":{"df":0,"docs":{},"n":{"df":1,"docs":{"32":{"tf":1.0}}}}}},"x":{"df":0,"docs":{},"t":{"df":2,"docs":{"21":{"tf":1.0},"31":{"tf":1.0}}}}},"h":{"df":0,"docs":{},"i":{"df":0,"docs":{},"n":{"df":0,"docs":{},"g":{"df":4,"docs":{"20":{"tf":1.0},"21":{"tf":1.0},"31":{"tf":1.0},"5":{"tf":1.7320508075688772}}}}},"o":{"df":0,"docs":{},"u":{"df":0,"docs":{},"g":{"df":0,"docs":{},"h":{"df":1,"docs":{"21":{"tf":1.0}}}}}},"r":{"df":0,"docs":{},"e":{"df":0,"docs":{},"e":{"df":3,"docs":{"23":{"tf":1.0},"27":{"tf":1.0},"7":{"tf":1.0}}}},"o":{"df":0,"docs":{},"u":{"df":0,"docs":{},"g":{"df":0,"docs":{},"h":{"df":4,"docs":{"20":{"tf":1.0},"21":{"tf":1.0},"25":{"tf":1.0},"35":{"tf":1.0}}}}}}}},"i":{"df":0,"docs":{},"m":{"df":0,"docs":{},"e":{"df":5,"docs":{"17":{"tf":1.4142135623730951},"21":{"tf":1.4142135623730951},"22":{"tf":1.0},"26":{"tf":1.0},"5":{"tf":1.0}}}}},"o":{"df":0,"docs":{},"g":{"df":0,"docs":{},"e":{"df":0,"docs":{},"t":{"df":0,"docs":{},"h":{"df":2,"docs":{"21":{"tf":1.0},"28":{"tf":1.0}}}}}},"o":{"df":0,"docs":{},"l":{"c":{"df":0,"docs":{},"h":{"a":{"df":0,"docs":{},"i":{"df":0,"docs":{},"n":{".":{"df":0,"docs":{},"t":{"df":0,"docs":{},"o":{"df":0,"docs":{},"m":{"df":0,"docs":{},"l":{"df":1,"docs":{"7":{"tf":1.0}}}}}}},"df":1,"docs":{"7":{"tf":1.7320508075688772}}}}},"df":0,"docs":{}}},"df":1,"docs":{"0":{"tf":1.0}}}},"p":{"df":2,"docs":{"26":{"tf":1.0},"5":{"tf":1.0}}}},"r":{"df":0,"docs":{},"e":{"a":{"df":0,"docs":{},"t":{"df":1,"docs":{"27":{"tf":1.0}}}},"df":0,"docs":{}},"i":{"a":{"df":0,"docs":{},"n":{"df":0,"docs":{},"g":{"df":0,"docs":{},"l":{"df":1,"docs":{"22":{"tf":2.0}},"e":{"'":{"df":1,"docs":{"22":{"tf":1.0}}},"[":{"df":0,"docs":{},"g":{"df":0,"docs":{},"e":{"df":0,"docs":{},"t":{"_":{"df":0,"docs":{},"r":{"a":{"df":0,"docs":{},"n":{"d":{"df":0,"docs":{},"o":{"df":0,"docs":{},"m":{"_":{"df":0,"docs":{},"u":{"df":0,"docs":{},"s":{"df":0,"docs":{},"i":{"df":0,"docs":{},"z":{"df":0,"docs":{},"e":{"(":{"&":{"df":0,"docs":{},"m":{"df":0,"docs":{},"u":{"df":0,"docs":{},"t":{"df":1,"docs":{"22":{"tf":1.0}}}}}},"df":0,"docs":{}},"df":0,"docs":{}}}}}}},"df":0,"docs":{}}}},"df":0,"docs":{}}},"df":0,"docs":{}}},"df":0,"docs":{}}}}},"df":0,"docs":{}}}}}},"c":{"df":0,"docs":{},"k":{"df":0,"docs":{},"i":{"df":1,"docs":{"33":{"tf":1.0}}}}},"df":2,"docs":{"34":{"tf":1.0},"35":{"tf":1.0}}}},"u":{"df":0,"docs":{},"r":{"df":0,"docs":{},"n":{"df":1,"docs":{"5":{"tf":1.0}}}},"t":{"df":0,"docs":{},"o":{"df":0,"docs":{},"r":{"df":0,"docs":{},"i":{"df":1,"docs":{"1":{"tf":1.4142135623730951}}}}}}},"w":{"df":0,"docs":{},"o":{"df":3,"docs":{"10":{"tf":1.0},"11":{"tf":1.0},"5":{"tf":1.0}}}},"y":{"df":0,"docs":{},"p":{"df":0,"docs":{},"e":{"c":{"df":0,"docs":{},"o":{"d":{"df":0,"docs":{},"e":{"=":{"1":{":":{"c":{"1":{"2":{"a":{"7":{"3":{"2":{"8":{"df":1,"docs":{"16":{"tf":1.0}}},"df":0,"docs":{}},"df":0,"docs":{}},"df":0,"docs":{}},"df":0,"docs":{}},"df":0,"docs":{}},"df":0,"docs":{}},"df":0,"docs":{}},"df":0,"docs":{}},"df":0,"docs":{}},"df":0,"docs":{}},"df":0,"docs":{}}},"df":0,"docs":{}}},"df":10,"docs":{"15":{"tf":1.0},"16":{"tf":1.0},"21":{"tf":2.449489742783178},"22":{"tf":1.0},"23":{"tf":1.0},"27":{"tf":1.0},"33":{"tf":1.0},"34":{"tf":1.0},"35":{"tf":1.0},"5":{"tf":1.0}}},"i":{"c":{"df":1,"docs":{"25":{"tf":1.4142135623730951}}},"df":0,"docs":{}}}}},"u":{"8":{"df":1,"docs":{"22":{"tf":1.4142135623730951}}},"b":{"df":0,"docs":{},"u":{"df":0,"docs":{},"n":{"df":0,"docs":{},"t":{"df":0,"docs":{},"u":{"df":1,"docs":{"11":{"tf":1.0}}}}}}},"c":{"df":1,"docs":{"32":{"tf":1.0}}},"df":0,"docs":{},"e":{"df":0,"docs":{},"f":{"df":0,"docs":{},"i":{"'":{"df":1,"docs":{"35":{"tf":1.0}}},"/":{"d":{"df":0,"docs":{},"e":{"b":{"df":0,"docs":{},"u":{"df":0,"docs":{},"g":{"/":{"df":0,"docs":{},"m":{"df":0,"docs":{},"i":{"df":2,"docs":{"12":{"tf":1.0},"8":{"tf":1.0}}}}},"df":0,"docs":{}}}},"df":0,"docs":{}}},"df":0,"docs":{}},":":{":":{"df":0,"docs":{},"p":{"df":0,"docs":{},"r":{"df":0,"docs":{},"e":{"df":0,"docs":{},"l":{"df":0,"docs":{},"u":{"d":{"df":4,"docs":{"20":{"tf":1.0},"22":{"tf":1.0},"4":{"tf":1.0},"5":{"tf":1.4142135623730951}}},"df":0,"docs":{}}}},"o":{"df":0,"docs":{},"t":{"df":0,"docs":{},"o":{":":{":":{"c":{"df":0,"docs":{},"o":{"df":0,"docs":{},"n":{"df":0,"docs":{},"s":{"df":0,"docs":{},"o":{"df":0,"docs":{},"l":{"df":0,"docs":{},"e":{":":{":":{"df":0,"docs":{},"g":{"df":0,"docs":{},"o":{"df":0,"docs":{},"p":{":":{":":{"df":0,"docs":{},"{":{"b":{"df":0,"docs":{},"l":{"df":0,"docs":{},"t":{"df":0,"docs":{},"o":{"df":0,"docs":{},"p":{"df":1,"docs":{"22":{"tf":1.0}}}}}}},"df":0,"docs":{}}},"df":0,"docs":{}},"df":0,"docs":{}}}}},"df":0,"docs":{}},"df":0,"docs":{}}}}}}}},"d":{"df":0,"docs":{},"e":{"df":0,"docs":{},"v":{"df":0,"docs":{},"i":{"c":{"df":0,"docs":{},"e":{"_":{"df":0,"docs":{},"p":{"a":{"df":0,"docs":{},"t":{"df":0,"docs":{},"h":{":":{":":{"df":0,"docs":{},"t":{"df":0,"docs":{},"e":{"df":0,"docs":{},"x":{"df":0,"docs":{},"t":{"df":2,"docs":{"20":{"tf":1.0},"31":{"tf":1.0}}}}}}},"df":0,"docs":{}},"df":1,"docs":{"31":{"tf":1.0}}}}},"df":0,"docs":{}}},"df":0,"docs":{}}},"df":0,"docs":{}}}}},"df":0,"docs":{},"l":{"df":0,"docs":{},"o":{"a":{"d":{"df":0,"docs":{},"e":{"d":{"_":{"df":0,"docs":{},"i":{"df":0,"docs":{},"m":{"a":{"df":0,"docs":{},"g":{"df":0,"docs":{},"e":{":":{":":{"df":0,"docs":{},"l":{"df":0,"docs":{},"o":{"a":{"d":{"df":0,"docs":{},"e":{"d":{"df":0,"docs":{},"i":{"df":0,"docs":{},"m":{"a":{"df":0,"docs":{},"g":{"df":1,"docs":{"20":{"tf":1.0}}}},"df":0,"docs":{}}}},"df":0,"docs":{}}},"df":0,"docs":{}},"df":0,"docs":{}}}},"df":0,"docs":{}},"df":0,"docs":{}}}},"df":0,"docs":{}}}},"df":0,"docs":{}},"df":0,"docs":{}}},"df":0,"docs":{}},"df":0,"docs":{}}},"r":{"df":0,"docs":{},"n":{"df":0,"docs":{},"g":{":":{":":{"df":0,"docs":{},"r":{"df":0,"docs":{},"n":{"df":0,"docs":{},"g":{"df":1,"docs":{"22":{"tf":1.0}}}}}},"df":0,"docs":{}},"df":0,"docs":{}}}}},"df":0,"docs":{}},"df":0,"docs":{}}}}}},"r":{"df":0,"docs":{},"e":{"df":0,"docs":{},"s":{"df":0,"docs":{},"u":{"df":0,"docs":{},"l":{"df":0,"docs":{},"t":{"df":2,"docs":{"21":{"tf":1.0},"22":{"tf":1.0}}}}}}}},"s":{"df":0,"docs":{},"t":{"a":{"df":0,"docs":{},"t":{"df":0,"docs":{},"u":{"df":1,"docs":{"21":{"tf":1.0}}}}},"df":0,"docs":{}}},"t":{"a":{"b":{"df":0,"docs":{},"l":{"df":0,"docs":{},"e":{":":{":":{"b":{"df":0,"docs":{},"o":{"df":0,"docs":{},"o":{"df":0,"docs":{},"t":{":":{":":{"b":{"df":0,"docs":{},"o":{"df":0,"docs":{},"o":{"df":0,"docs":{},"t":{"df":0,"docs":{},"s":{"df":0,"docs":{},"e":{"df":0,"docs":{},"r":{"df":0,"docs":{},"v":{"df":0,"docs":{},"i":{"c":{"df":1,"docs":{"22":{"tf":1.0}}},"df":0,"docs":{}}}}}}}}}},"df":0,"docs":{},"s":{"df":0,"docs":{},"e":{"a":{"df":0,"docs":{},"r":{"c":{"df":0,"docs":{},"h":{"df":0,"docs":{},"t":{"df":0,"docs":{},"y":{"df":0,"docs":{},"p":{"df":1,"docs":{"20":{"tf":1.0}}}}}}},"df":0,"docs":{}}},"df":0,"docs":{}}}},"df":0,"docs":{}},"df":0,"docs":{}}}}},"df":0,"docs":{}},"df":0,"docs":{}},"df":0,"docs":{}}}},"df":0,"docs":{}},"df":0,"docs":{}},"{":{"df":0,"docs":{},"i":{"d":{"df":0,"docs":{},"e":{"df":0,"docs":{},"n":{"df":0,"docs":{},"t":{"df":0,"docs":{},"i":{"df":0,"docs":{},"f":{"df":0,"docs":{},"i":{"df":1,"docs":{"20":{"tf":1.0}}}}}}}}},"df":0,"docs":{}}}},"df":0,"docs":{}},"_":{"df":0,"docs":{},"s":{"df":0,"docs":{},"e":{"df":0,"docs":{},"r":{"df":0,"docs":{},"v":{"df":0,"docs":{},"i":{"c":{"df":1,"docs":{"5":{"tf":1.4142135623730951}},"e":{"df":0,"docs":{},"s":{":":{":":{"df":0,"docs":{},"i":{"df":0,"docs":{},"n":{"df":0,"docs":{},"i":{"df":0,"docs":{},"t":{"(":{"&":{"df":0,"docs":{},"m":{"df":0,"docs":{},"u":{"df":0,"docs":{},"t":{"df":4,"docs":{"20":{"tf":1.0},"22":{"tf":1.0},"4":{"tf":1.0},"5":{"tf":1.0}}}}}},"df":0,"docs":{}},"df":0,"docs":{}}}}}},"df":0,"docs":{}},"df":0,"docs":{}}}},"df":0,"docs":{}}}}}}},"df":24,"docs":{"0":{"tf":2.0},"1":{"tf":1.0},"10":{"tf":1.0},"12":{"tf":1.4142135623730951},"15":{"tf":2.0},"2":{"tf":1.0},"21":{"tf":1.4142135623730951},"22":{"tf":1.0},"23":{"tf":1.4142135623730951},"24":{"tf":2.23606797749979},"25":{"tf":2.449489742783178},"26":{"tf":1.7320508075688772},"27":{"tf":1.4142135623730951},"28":{"tf":1.4142135623730951},"30":{"tf":2.0},"32":{"tf":1.0},"33":{"tf":1.4142135623730951},"34":{"tf":1.4142135623730951},"35":{"tf":1.4142135623730951},"36":{"tf":2.449489742783178},"4":{"tf":2.0},"5":{"tf":2.8284271247461903},"7":{"tf":2.23606797749979},"8":{"tf":1.4142135623730951}}}}},"n":{"a":{"df":0,"docs":{},"u":{"df":0,"docs":{},"t":{"df":0,"docs":{},"h":{"df":0,"docs":{},"o":{"df":0,"docs":{},"r":{"df":1,"docs":{"33":{"tf":1.0}}}}}}}},"d":{"df":0,"docs":{},"e":{"df":0,"docs":{},"r":{"df":3,"docs":{"11":{"tf":1.0},"15":{"tf":1.0},"35":{"tf":1.0}},"s":{"df":0,"docs":{},"t":{"a":{"df":0,"docs":{},"n":{"d":{"df":1,"docs":{"24":{"tf":1.4142135623730951}}},"df":0,"docs":{}}},"df":0,"docs":{}}}}}},"df":0,"docs":{},"i":{"df":0,"docs":{},"q":{"df":0,"docs":{},"u":{"df":2,"docs":{"27":{"tf":1.0},"31":{"tf":1.0}}}}},"k":{"df":0,"docs":{},"n":{"df":0,"docs":{},"o":{"df":0,"docs":{},"w":{"df":0,"docs":{},"n":{"df":4,"docs":{"12":{"tf":1.0},"36":{"tf":1.0},"7":{"tf":1.7320508075688772},"8":{"tf":1.4142135623730951}}}}}}},"l":{"df":0,"docs":{},"i":{"df":0,"docs":{},"k":{"df":2,"docs":{"31":{"tf":1.0},"34":{"tf":1.0}}}}},"s":{"a":{"df":0,"docs":{},"f":{"df":1,"docs":{"19":{"tf":1.0}}}},"df":0,"docs":{}},"t":{"df":0,"docs":{},"i":{"df":0,"docs":{},"l":{"df":1,"docs":{"25":{"tf":1.0}}}}},"u":{"df":0,"docs":{},"s":{"df":1,"docs":{"22":{"tf":1.0}}}}},"p":{"df":4,"docs":{"21":{"tf":1.0},"3":{"tf":1.0},"5":{"tf":1.0},"7":{"tf":1.0}}},"s":{"b":{"df":3,"docs":{"14":{"tf":1.0},"17":{"tf":1.7320508075688772},"29":{"tf":1.0}}},"df":17,"docs":{"0":{"tf":1.0},"13":{"tf":1.0},"15":{"tf":1.7320508075688772},"17":{"tf":1.4142135623730951},"19":{"tf":2.449489742783178},"20":{"tf":2.449489742783178},"21":{"tf":1.7320508075688772},"22":{"tf":3.605551275463989},"26":{"tf":1.0},"27":{"tf":1.4142135623730951},"30":{"tf":1.4142135623730951},"31":{"tf":1.0},"33":{"tf":1.4142135623730951},"34":{"tf":1.4142135623730951},"4":{"tf":1.4142135623730951},"5":{"tf":2.449489742783178},"7":{"tf":1.0}},"i":{"df":0,"docs":{},"z":{"df":1,"docs":{"22":{"tf":3.872983346207417}},"e":{")":{".":{"df":0,"docs":{},"u":{"df":0,"docs":{},"n":{"df":0,"docs":{},"w":{"df":0,"docs":{},"r":{"a":{"df":0,"docs":{},"p":{"df":1,"docs":{"22":{"tf":1.0}}}},"df":0,"docs":{}}}}}},"df":0,"docs":{}},":":{":":{"df":0,"docs":{},"f":{"df":0,"docs":{},"r":{"df":0,"docs":{},"o":{"df":0,"docs":{},"m":{"_":{"df":0,"docs":{},"l":{"df":0,"docs":{},"e":{"_":{"b":{"df":0,"docs":{},"y":{"df":0,"docs":{},"t":{"df":0,"docs":{},"e":{"df":0,"docs":{},"s":{"(":{"b":{"df":0,"docs":{},"u":{"df":0,"docs":{},"f":{"df":1,"docs":{"22":{"tf":1.0}}}}},"df":0,"docs":{}},"df":0,"docs":{}}}}}},"df":0,"docs":{}},"df":0,"docs":{}}}},"df":0,"docs":{}}}}}},"df":0,"docs":{}},"df":0,"docs":{}}}},"r":{"/":{"df":0,"docs":{},"s":{"df":0,"docs":{},"h":{"a":{"df":0,"docs":{},"r":{"df":0,"docs":{},"e":{"/":{"df":0,"docs":{},"o":{"df":0,"docs":{},"v":{"df":0,"docs":{},"m":{"df":0,"docs":{},"f":{"/":{"df":0,"docs":{},"o":{"df":0,"docs":{},"v":{"df":0,"docs":{},"m":{"df":0,"docs":{},"f":{"_":{"c":{"df":0,"docs":{},"o":{"d":{"df":0,"docs":{},"e":{".":{"df":0,"docs":{},"f":{"d":{"df":1,"docs":{"11":{"tf":1.0}}},"df":0,"docs":{}}},"df":0,"docs":{}}},"df":0,"docs":{}}},"df":0,"docs":{},"v":{"a":{"df":0,"docs":{},"r":{"df":0,"docs":{},"s":{".":{"df":0,"docs":{},"f":{"d":{"df":1,"docs":{"11":{"tf":1.0}}},"df":0,"docs":{}}},"df":0,"docs":{}}}},"df":0,"docs":{}}},"df":0,"docs":{}}}}}},"df":1,"docs":{"11":{"tf":1.0}}}}}}},"df":0,"docs":{}}}},"df":0,"docs":{}}}},"df":0,"docs":{}}}},"v":{".":{"df":0,"docs":{},"i":{"df":1,"docs":{"22":{"tf":1.0}}},"x":{"df":1,"docs":{"22":{"tf":1.0}}}},"a":{"df":0,"docs":{},"l":{"df":0,"docs":{},"u":{"df":2,"docs":{"22":{"tf":1.0},"23":{"tf":1.0}}}},"r":{"df":1,"docs":{"11":{"tf":1.0}},"i":{"a":{"b":{"df":0,"docs":{},"l":{"df":7,"docs":{"11":{"tf":1.0},"26":{"tf":1.0},"27":{"tf":1.0},"31":{"tf":1.0},"32":{"tf":2.449489742783178},"33":{"tf":2.8284271247461903},"35":{"tf":1.0}}}},"df":0,"docs":{},"t":{"df":1,"docs":{"11":{"tf":1.0}}}},"df":2,"docs":{"10":{"tf":1.0},"15":{"tf":1.0}},"o":{"df":0,"docs":{},"u":{"df":2,"docs":{"30":{"tf":1.0},"35":{"tf":1.0}}}}}}},"df":2,"docs":{"22":{"tf":1.0},"35":{"tf":1.7320508075688772}},"e":{"c":{"!":{"[":{"b":{"df":0,"docs":{},"l":{"df":0,"docs":{},"t":{"df":0,"docs":{},"p":{"df":0,"docs":{},"i":{"df":0,"docs":{},"x":{"df":0,"docs":{},"e":{"df":0,"docs":{},"l":{":":{":":{"df":0,"docs":{},"n":{"df":0,"docs":{},"e":{"df":0,"docs":{},"w":{"(":{"0":{"df":1,"docs":{"22":{"tf":1.4142135623730951}}},"df":0,"docs":{}},"df":0,"docs":{}}}}},"df":0,"docs":{}},"df":0,"docs":{}}}}}}}}},"df":0,"docs":{}},"df":0,"docs":{}},"<":{"b":{"df":0,"docs":{},"l":{"df":0,"docs":{},"t":{"df":0,"docs":{},"p":{"df":0,"docs":{},"i":{"df":0,"docs":{},"x":{"df":0,"docs":{},"e":{"df":0,"docs":{},"l":{"df":1,"docs":{"22":{"tf":1.4142135623730951}}}}}}}}}},"df":0,"docs":{}},"df":1,"docs":{"22":{"tf":1.0}}},"df":0,"docs":{},"n":{"d":{"df":0,"docs":{},"o":{"df":0,"docs":{},"r":{"'":{"df":2,"docs":{"32":{"tf":1.0},"33":{"tf":1.0}}},"df":2,"docs":{"17":{"tf":1.0},"32":{"tf":1.7320508075688772}}}}},"df":0,"docs":{}},"r":{"df":0,"docs":{},"i":{"df":5,"docs":{"21":{"tf":1.0},"30":{"tf":1.4142135623730951},"31":{"tf":1.0},"33":{"tf":1.0},"34":{"tf":1.4142135623730951}}},"s":{"df":0,"docs":{},"i":{"df":0,"docs":{},"o":{"df":0,"docs":{},"n":{"df":1,"docs":{"35":{"tf":1.0}}}}}},"t":{"df":0,"docs":{},"e":{"df":0,"docs":{},"x":{"df":1,"docs":{"22":{"tf":1.0}}}},"i":{"c":{"df":1,"docs":{"22":{"tf":1.4142135623730951}}},"df":0,"docs":{}}}}},"i":{"a":{"df":1,"docs":{"33":{"tf":1.0}}},"df":0,"docs":{},"r":{"df":0,"docs":{},"t":{"df":0,"docs":{},"u":{"a":{"df":0,"docs":{},"l":{"df":2,"docs":{"10":{"tf":1.0},"26":{"tf":1.0}}}},"df":0,"docs":{}}}}},"m":{"df":2,"docs":{"13":{"tf":1.0},"9":{"tf":1.0}}},"o":{"df":0,"docs":{},"l":{"a":{"df":0,"docs":{},"t":{"df":0,"docs":{},"i":{"df":0,"docs":{},"l":{"df":1,"docs":{"33":{"tf":1.7320508075688772}}}}}},"df":0,"docs":{}}},"v":{"df":0,"docs":{},"f":{"a":{"df":0,"docs":{},"t":{"df":1,"docs":{"13":{"tf":1.0}}}},"df":0,"docs":{}}}},"w":{"a":{"df":0,"docs":{},"l":{"df":0,"docs":{},"k":{"df":1,"docs":{"20":{"tf":1.0}},"t":{"df":0,"docs":{},"h":{"df":0,"docs":{},"r":{"df":0,"docs":{},"o":{"df":0,"docs":{},"u":{"df":0,"docs":{},"g":{"df":0,"docs":{},"h":{"df":2,"docs":{"21":{"tf":1.0},"5":{"tf":1.0}}}}}}}}}}},"n":{"df":0,"docs":{},"t":{"df":1,"docs":{"21":{"tf":1.4142135623730951}}}},"r":{"df":0,"docs":{},"n":{"df":1,"docs":{"16":{"tf":1.0}}}},"y":{"df":2,"docs":{"19":{"tf":1.0},"7":{"tf":1.0}}}},"df":0,"docs":{},"e":{"'":{"df":0,"docs":{},"l":{"df":0,"docs":{},"l":{"df":2,"docs":{"11":{"tf":1.0},"20":{"tf":1.4142135623730951}}}}},"df":0,"docs":{},"l":{"c":{"df":0,"docs":{},"o":{"df":0,"docs":{},"m":{"df":2,"docs":{"0":{"tf":1.0},"30":{"tf":1.0}}}}},"df":0,"docs":{},"l":{"df":1,"docs":{"0":{"tf":1.0}}}}},"h":{"df":0,"docs":{},"o":{"df":0,"docs":{},"l":{"df":0,"docs":{},"e":{"df":2,"docs":{"20":{"tf":1.0},"24":{"tf":1.0}}}}}},"i":{"d":{"df":0,"docs":{},"e":{"df":3,"docs":{"21":{"tf":1.0},"26":{"tf":1.0},"28":{"tf":1.0}}},"t":{"df":0,"docs":{},"h":{"df":1,"docs":{"22":{"tf":2.8284271247461903}}}}},"df":0,"docs":{},"n":{"d":{"df":0,"docs":{},"o":{"df":0,"docs":{},"w":{"df":2,"docs":{"13":{"tf":1.0},"25":{"tf":1.0}}}}},"df":0,"docs":{}},"t":{"df":0,"docs":{},"h":{"df":0,"docs":{},"i":{"df":0,"docs":{},"n":{"df":1,"docs":{"35":{"tf":1.0}}}}}}},"o":{"df":0,"docs":{},"r":{"df":0,"docs":{},"l":{"d":{"df":5,"docs":{"1":{"tf":1.0},"13":{"tf":1.0},"21":{"tf":1.0},"4":{"tf":1.0},"5":{"tf":1.4142135623730951}}},"df":0,"docs":{}}}},"r":{"a":{"df":0,"docs":{},"p":{"df":1,"docs":{"30":{"tf":1.0}}}},"df":0,"docs":{},"i":{"df":0,"docs":{},"t":{"df":0,"docs":{},"e":{"df":3,"docs":{"26":{"tf":1.0},"30":{"tf":1.0},"33":{"tf":1.0}}},"t":{"df":0,"docs":{},"e":{"df":0,"docs":{},"n":{"df":1,"docs":{"33":{"tf":1.0}}}}}}}}},"x":{"8":{"6":{"_":{"6":{"4":{"df":6,"docs":{"1":{"tf":1.0},"13":{"tf":1.0},"15":{"tf":1.0},"35":{"tf":1.0},"7":{"tf":1.0},"8":{"tf":1.0}}},"df":0,"docs":{}},"df":0,"docs":{}},"df":1,"docs":{"8":{"tf":1.0}}},"df":0,"docs":{}},"df":1,"docs":{"22":{"tf":2.8284271247461903}},"t":{"a":{"df":0,"docs":{},"s":{"df":0,"docs":{},"k":{"df":1,"docs":{"22":{"tf":1.0}}}}},"df":0,"docs":{}}},"y":{")":{".":{"df":0,"docs":{},"u":{"df":0,"docs":{},"n":{"df":0,"docs":{},"w":{"df":0,"docs":{},"r":{"a":{"df":0,"docs":{},"p":{"df":1,"docs":{"22":{"tf":1.0}}}},"df":0,"docs":{}}}}}},"df":0,"docs":{}},"df":1,"docs":{"22":{"tf":2.6457513110645907}},"o":{"df":0,"docs":{},"u":{"'":{"df":0,"docs":{},"l":{"df":0,"docs":{},"l":{"df":1,"docs":{"14":{"tf":1.0}}}}},"df":0,"docs":{}}}}}},"breadcrumbs":{"root":{"0":{".":{".":{"df":0,"docs":{},"h":{"df":0,"docs":{},"e":{"df":0,"docs":{},"i":{"df":0,"docs":{},"g":{"df":0,"docs":{},"h":{"df":0,"docs":{},"t":{"df":1,"docs":{"22":{"tf":1.0}}}}}}}},"w":{"df":0,"docs":{},"i":{"d":{"df":0,"docs":{},"t":{"df":0,"docs":{},"h":{"df":1,"docs":{"22":{"tf":1.0}}}}},"df":0,"docs":{}}}},"5":{"df":1,"docs":{"22":{"tf":1.4142135623730951}}},"df":0,"docs":{}},"0":{"a":{"0":{"c":{"9":{"3":{"df":0,"docs":{},"e":{"c":{"9":{"3":{"b":{"df":3,"docs":{"15":{"tf":1.0},"16":{"tf":1.0},"35":{"tf":1.0}}},"df":0,"docs":{}},"df":0,"docs":{}},"df":0,"docs":{}},"df":0,"docs":{}}},"df":0,"docs":{}},"df":0,"docs":{}},"df":0,"docs":{}},"df":0,"docs":{}},"df":0,"docs":{}},"df":1,"docs":{"22":{"tf":3.3166247903554}}},"1":{"0":{"0":{"df":1,"docs":{"22":{"tf":1.0}}},"df":2,"docs":{"1":{"tf":1.0},"5":{"tf":1.0}}},"1":{"d":{"2":{"df":3,"docs":{"15":{"tf":1.0},"16":{"tf":1.0},"35":{"tf":1.0}}},"df":0,"docs":{}},"df":0,"docs":{}},"2":{"8":{"df":1,"docs":{"35":{"tf":1.0}}},"df":0,"docs":{}},"6":{"df":1,"docs":{"27":{"tf":1.0}}},"df":1,"docs":{"22":{"tf":1.4142135623730951}},"m":{"b":{"df":1,"docs":{"16":{"tf":1.0}}},"df":0,"docs":{}}},"2":{".":{"0":{"df":1,"docs":{"22":{"tf":1.7320508075688772}}},"df":0,"docs":{}},"0":{".":{"0":{"df":1,"docs":{"22":{"tf":1.0}}},"df":0,"docs":{}},"df":0,"docs":{}},"5":{"0":{"0":{"df":1,"docs":{"24":{"tf":1.0}}},"df":0,"docs":{}},"5":{".":{"0":{"df":1,"docs":{"22":{"tf":1.4142135623730951}}},"df":0,"docs":{}},"df":1,"docs":{"22":{"tf":1.0}}},"df":0,"docs":{}},"df":1,"docs":{"32":{"tf":1.0}},"f":{"df":0,"docs":{},"e":{"4":{"8":{"8":{"7":{"4":{"a":{"4":{"1":{"0":{"df":1,"docs":{"27":{"tf":1.0}}},"df":0,"docs":{}},"df":0,"docs":{}},"df":0,"docs":{}},"df":0,"docs":{}},"df":0,"docs":{}},"df":0,"docs":{}},"df":0,"docs":{}},"df":0,"docs":{}},"df":0,"docs":{}}}},"3":{"1":{"3":{"b":{"0":{"d":{"7":{"c":{"df":1,"docs":{"27":{"tf":1.0}}},"df":0,"docs":{}},"df":0,"docs":{}},"df":0,"docs":{}},"df":0,"docs":{}},"df":0,"docs":{}},"df":0,"docs":{}},"2":{"df":2,"docs":{"22":{"tf":1.0},"35":{"tf":1.4142135623730951}}},"df":1,"docs":{"22":{"tf":1.0}}},"4":{"d":{"df":0,"docs":{},"e":{"7":{"df":1,"docs":{"27":{"tf":1.0}}},"df":0,"docs":{}}},"df":0,"docs":{}},"6":{"4":{"df":2,"docs":{"35":{"tf":1.0},"8":{"tf":1.0}}},"df":0,"docs":{}},"8":{"df":1,"docs":{"22":{"tf":1.4142135623730951}}},"9":{"9":{"df":0,"docs":{},"e":{"d":{"df":1,"docs":{"27":{"tf":1.0}}},"df":0,"docs":{}}},"df":0,"docs":{},"m":{"b":{"df":1,"docs":{"16":{"tf":1.0}}},"df":0,"docs":{}}},"a":{"a":{"df":0,"docs":{},"r":{"c":{"df":0,"docs":{},"h":{"3":{"2":{"df":1,"docs":{"35":{"tf":1.0}}},"df":0,"docs":{}},"6":{"4":{"df":2,"docs":{"35":{"tf":1.0},"7":{"tf":1.0}}},"df":0,"docs":{}},"df":0,"docs":{}}},"df":0,"docs":{}}},"b":{"df":0,"docs":{},"o":{"df":0,"docs":{},"v":{"df":1,"docs":{"13":{"tf":1.0}}}},"s":{"df":0,"docs":{},"e":{"df":0,"docs":{},"n":{"c":{"df":1,"docs":{"35":{"tf":1.0}}},"df":0,"docs":{}}},"t":{"df":0,"docs":{},"r":{"a":{"c":{"df":0,"docs":{},"t":{"df":1,"docs":{"22":{"tf":1.0}}}},"df":0,"docs":{}},"df":0,"docs":{}}}}},"c":{"c":{"df":0,"docs":{},"e":{"df":0,"docs":{},"s":{"df":0,"docs":{},"s":{"df":8,"docs":{"11":{"tf":1.0},"13":{"tf":1.0},"21":{"tf":1.0},"25":{"tf":1.4142135623730951},"26":{"tf":3.0},"30":{"tf":1.0},"33":{"tf":1.4142135623730951},"5":{"tf":1.0}}}}},"i":{"d":{"df":0,"docs":{},"e":{"df":0,"docs":{},"n":{"df":0,"docs":{},"t":{"df":1,"docs":{"32":{"tf":1.0}}}}}},"df":0,"docs":{}}},"df":0,"docs":{},"t":{"df":0,"docs":{},"i":{"df":0,"docs":{},"v":{"df":1,"docs":{"25":{"tf":1.0}}}},"u":{"a":{"df":0,"docs":{},"l":{"df":2,"docs":{"27":{"tf":1.0},"34":{"tf":1.0}}}},"df":0,"docs":{}}}},"d":{"a":{"df":0,"docs":{},"p":{"df":0,"docs":{},"t":{"df":1,"docs":{"28":{"tf":1.0}}}}},"d":{"df":2,"docs":{"4":{"tf":1.4142135623730951},"7":{"tf":1.0}},"r":{"df":0,"docs":{},"e":{"df":0,"docs":{},"s":{"df":0,"docs":{},"s":{"df":1,"docs":{"34":{"tf":1.0}}}}}}},"df":0,"docs":{},"v":{"a":{"df":0,"docs":{},"n":{"df":0,"docs":{},"t":{"a":{"df":0,"docs":{},"g":{"df":1,"docs":{"34":{"tf":1.0}}}},"df":0,"docs":{}}}},"df":0,"docs":{}}},"df":0,"docs":{},"f":{"df":0,"docs":{},"f":{"df":0,"docs":{},"e":{"c":{"df":0,"docs":{},"t":{"df":1,"docs":{"33":{"tf":1.0}}}},"df":0,"docs":{}}}},"g":{"a":{"df":0,"docs":{},"i":{"df":0,"docs":{},"n":{"df":1,"docs":{"21":{"tf":1.0}}}}},"df":0,"docs":{}},"l":{"df":0,"docs":{},"g":{"df":0,"docs":{},"o":{"df":0,"docs":{},"r":{"df":0,"docs":{},"i":{"df":0,"docs":{},"t":{"df":0,"docs":{},"h":{"df":0,"docs":{},"m":{"df":1,"docs":{"22":{"tf":1.0}}}}}}}}},"i":{"a":{"df":1,"docs":{"21":{"tf":1.0}}},"df":0,"docs":{}},"l":{"df":0,"docs":{},"o":{"c":{":":{":":{"df":0,"docs":{},"v":{"df":0,"docs":{},"e":{"c":{":":{":":{"df":0,"docs":{},"v":{"df":0,"docs":{},"e":{"c":{"df":1,"docs":{"22":{"tf":1.0}}},"df":0,"docs":{}}}},"df":0,"docs":{}},"df":1,"docs":{"22":{"tf":1.0}}},"df":0,"docs":{}}}},"df":0,"docs":{}},"df":3,"docs":{"22":{"tf":1.0},"26":{"tf":1.0},"5":{"tf":1.4142135623730951}}},"df":0,"docs":{},"w":{"df":1,"docs":{"15":{"tf":1.0}},"s":{"df":0,"docs":{},"h":{"df":0,"docs":{},"o":{"df":0,"docs":{},"r":{"df":0,"docs":{},"t":{"c":{"df":0,"docs":{},"u":{"df":0,"docs":{},"t":{"df":1,"docs":{"20":{"tf":1.0}},"s":{"(":{"df":0,"docs":{},"f":{"a":{"df":0,"docs":{},"l":{"df":0,"docs":{},"s":{"df":2,"docs":{"20":{"tf":1.0},"21":{"tf":1.0}}}}},"df":0,"docs":{}}},"df":0,"docs":{}}}}},"df":0,"docs":{}}}}}}}}},"t":{"df":0,"docs":{},"e":{"df":0,"docs":{},"r":{"df":1,"docs":{"22":{"tf":1.0}},"n":{"df":1,"docs":{"34":{"tf":1.0}}}}},"h":{"df":0,"docs":{},"o":{"df":0,"docs":{},"u":{"df":0,"docs":{},"g":{"df":0,"docs":{},"h":{"df":2,"docs":{"31":{"tf":1.0},"34":{"tf":1.0}}}}}}}},"w":{"a":{"df":0,"docs":{},"y":{"df":3,"docs":{"27":{"tf":1.0},"35":{"tf":1.0},"5":{"tf":1.0}}}},"df":0,"docs":{}}},"n":{"df":0,"docs":{},"o":{"df":0,"docs":{},"t":{"df":0,"docs":{},"h":{"df":2,"docs":{"32":{"tf":1.0},"33":{"tf":1.0}}}}},"y":{"df":0,"docs":{},"t":{"df":0,"docs":{},"h":{"df":1,"docs":{"29":{"tf":1.0}}}}}},"p":{"df":0,"docs":{},"i":{"df":1,"docs":{"30":{"tf":1.0}}},"p":{".":{"df":0,"docs":{},"e":{"df":0,"docs":{},"f":{"df":0,"docs":{},"i":{"df":2,"docs":{"12":{"tf":1.0},"8":{"tf":1.0}}}}}},"df":1,"docs":{"4":{"tf":1.4142135623730951}},"e":{"a":{"df":0,"docs":{},"r":{"df":2,"docs":{"13":{"tf":1.0},"17":{"tf":1.0}}}},"df":0,"docs":{}},"l":{"df":0,"docs":{},"i":{"c":{"df":12,"docs":{"0":{"tf":1.0},"1":{"tf":1.4142135623730951},"15":{"tf":1.0},"2":{"tf":1.7320508075688772},"23":{"tf":1.4142135623730951},"25":{"tf":1.0},"26":{"tf":1.0},"28":{"tf":1.0},"3":{"tf":1.0},"4":{"tf":2.0},"5":{"tf":2.449489742783178},"8":{"tf":1.7320508075688772}}},"df":0,"docs":{}}},"r":{"df":0,"docs":{},"o":{"df":0,"docs":{},"p":{"df":0,"docs":{},"r":{"df":0,"docs":{},"i":{"df":2,"docs":{"15":{"tf":1.0},"7":{"tf":1.0}}}}}}}},"t":{"df":1,"docs":{"10":{"tf":1.0}}}},"r":{"b":{"df":0,"docs":{},"i":{"df":0,"docs":{},"t":{"df":0,"docs":{},"r":{"a":{"df":0,"docs":{},"r":{"df":0,"docs":{},"i":{"df":1,"docs":{"32":{"tf":1.0}}}}},"df":0,"docs":{}}}}},"c":{"df":0,"docs":{},"h":{"df":1,"docs":{"35":{"tf":1.0}},"i":{"df":0,"docs":{},"t":{"df":0,"docs":{},"e":{"c":{"df":0,"docs":{},"t":{"df":0,"docs":{},"u":{"df":0,"docs":{},"r":{"df":2,"docs":{"15":{"tf":1.4142135623730951},"35":{"tf":1.4142135623730951}}}}}},"df":0,"docs":{}}}}}},"df":0,"docs":{},"e":{"df":0,"docs":{},"n":{"'":{"df":0,"docs":{},"t":{"df":1,"docs":{"27":{"tf":1.0}}}},"df":0,"docs":{}}},"g":{"df":0,"docs":{},"s":{"=":{"/":{"df":0,"docs":{},"s":{"df":0,"docs":{},"u":{"b":{"df":0,"docs":{},"s":{"df":0,"docs":{},"y":{"df":0,"docs":{},"s":{"df":0,"docs":{},"t":{"df":0,"docs":{},"e":{"df":0,"docs":{},"m":{":":{"df":0,"docs":{},"e":{"df":0,"docs":{},"f":{"df":0,"docs":{},"i":{"_":{"df":0,"docs":{},"r":{"df":0,"docs":{},"u":{"df":0,"docs":{},"n":{"df":0,"docs":{},"t":{"df":0,"docs":{},"i":{"df":0,"docs":{},"m":{"df":0,"docs":{},"e":{"_":{"d":{"df":0,"docs":{},"r":{"df":0,"docs":{},"i":{"df":0,"docs":{},"v":{"df":1,"docs":{"23":{"tf":1.0}}}}}},"df":0,"docs":{}},"df":0,"docs":{}}}}}}}}},"df":0,"docs":{}}}}},"df":0,"docs":{}}}}}}}},"df":0,"docs":{}}}},"df":0,"docs":{}},"df":0,"docs":{}},"u":{"df":0,"docs":{},"m":{"df":0,"docs":{},"e":{"df":0,"docs":{},"n":{"df":0,"docs":{},"t":{"df":3,"docs":{"21":{"tf":1.4142135623730951},"26":{"tf":1.0},"5":{"tf":1.0}}}}}}}},"r":{"a":{"df":0,"docs":{},"y":{"df":4,"docs":{"26":{"tf":1.0},"28":{"tf":1.0},"32":{"tf":1.0},"34":{"tf":2.0}}}},"df":0,"docs":{}},"t":{"df":0,"docs":{},"i":{"c":{"df":0,"docs":{},"l":{"df":1,"docs":{"33":{"tf":1.0}}}},"df":0,"docs":{}}}},"s":{"df":0,"docs":{},"s":{"df":0,"docs":{},"o":{"c":{"df":0,"docs":{},"i":{"df":1,"docs":{"33":{"tf":1.0}}}},"df":0,"docs":{}}}},"t":{"df":0,"docs":{},"t":{"df":0,"docs":{},"r":{"df":0,"docs":{},"i":{"b":{"df":0,"docs":{},"u":{"df":0,"docs":{},"t":{"df":1,"docs":{"33":{"tf":2.23606797749979}}}}},"df":0,"docs":{}}}}},"u":{"df":0,"docs":{},"t":{"df":0,"docs":{},"h":{"df":0,"docs":{},"e":{"df":0,"docs":{},"n":{"df":0,"docs":{},"t":{"df":1,"docs":{"33":{"tf":1.0}}}}}},"o":{"df":0,"docs":{},"m":{"a":{"df":0,"docs":{},"t":{"df":1,"docs":{"19":{"tf":1.0}}}},"df":0,"docs":{}}}}},"v":{"a":{"df":0,"docs":{},"i":{"df":0,"docs":{},"l":{"df":4,"docs":{"19":{"tf":1.0},"21":{"tf":1.4142135623730951},"25":{"tf":1.0},"30":{"tf":1.0}}}}},"df":0,"docs":{}},"w":{"a":{"df":0,"docs":{},"r":{"df":1,"docs":{"27":{"tf":1.0}}}},"df":0,"docs":{}}},"b":{"a":{"4":{"b":{"df":3,"docs":{"15":{"tf":1.0},"16":{"tf":1.0},"35":{"tf":1.0}}},"df":0,"docs":{}},"c":{"df":0,"docs":{},"k":{"df":0,"docs":{},"g":{"df":0,"docs":{},"r":{"df":0,"docs":{},"o":{"df":0,"docs":{},"u":{"df":0,"docs":{},"n":{"d":{"df":1,"docs":{"22":{"tf":1.0}}},"df":0,"docs":{}}}}}}}},"df":0,"docs":{}},"df":0,"docs":{},"e":{"c":{"a":{"df":0,"docs":{},"m":{"df":1,"docs":{"33":{"tf":1.0}}}},"df":0,"docs":{}},"df":1,"docs":{"33":{"tf":1.0}},"g":{"df":0,"docs":{},"i":{"df":0,"docs":{},"n":{"df":1,"docs":{"34":{"tf":1.0}}}}},"l":{"df":0,"docs":{},"o":{"df":0,"docs":{},"w":{"df":1,"docs":{"15":{"tf":1.0}}}}},"s":{"df":0,"docs":{},"t":{"df":2,"docs":{"21":{"tf":1.0},"30":{"tf":1.0}}}},"t":{"df":0,"docs":{},"w":{"df":0,"docs":{},"e":{"df":0,"docs":{},"e":{"df":0,"docs":{},"n":{"df":1,"docs":{"34":{"tf":1.0}}}}}}}},"g":{"df":0,"docs":{},"r":{"df":0,"docs":{},"x":{"df":1,"docs":{"22":{"tf":1.0}}}}},"i":{"df":0,"docs":{},"g":{"df":2,"docs":{"22":{"tf":1.0},"34":{"tf":1.0}}},"t":{"df":3,"docs":{"22":{"tf":1.4142135623730951},"33":{"tf":2.23606797749979},"35":{"tf":2.0}},"e":{"df":1,"docs":{"22":{"tf":1.0}}}}},"l":{"a":{"c":{"df":0,"docs":{},"k":{"df":1,"docs":{"22":{"tf":1.0}}}},"df":0,"docs":{}},"df":0,"docs":{},"i":{"df":0,"docs":{},"t":{"(":{"&":{"df":0,"docs":{},"s":{"df":0,"docs":{},"e":{"df":0,"docs":{},"l":{"df":0,"docs":{},"f":{"df":1,"docs":{"22":{"tf":1.4142135623730951}}}}}}},"df":0,"docs":{}},"df":1,"docs":{"22":{"tf":1.4142135623730951}}}},"o":{"c":{"df":0,"docs":{},"k":{"df":2,"docs":{"30":{"tf":1.0},"34":{"tf":1.0}},"i":{"df":0,"docs":{},"o":{"df":1,"docs":{"30":{"tf":1.0}}}}}},"df":0,"docs":{}},"t":{"df":1,"docs":{"22":{"tf":1.0}},"p":{"df":0,"docs":{},"i":{"df":0,"docs":{},"x":{"df":0,"docs":{},"e":{"df":0,"docs":{},"l":{"df":1,"docs":{"22":{"tf":2.0}}}}}}},"r":{"df":0,"docs":{},"e":{"df":0,"docs":{},"g":{"df":0,"docs":{},"i":{"df":0,"docs":{},"o":{"df":0,"docs":{},"n":{":":{":":{"df":0,"docs":{},"f":{"df":0,"docs":{},"u":{"df":0,"docs":{},"l":{"df":1,"docs":{"22":{"tf":1.4142135623730951}}}}}},"df":0,"docs":{}},"df":1,"docs":{"22":{"tf":1.0}}}}}}}}},"u":{"df":0,"docs":{},"e":{"df":1,"docs":{"22":{"tf":1.0}}}}},"o":{"df":0,"docs":{},"i":{"df":0,"docs":{},"l":{"df":0,"docs":{},"e":{"df":0,"docs":{},"r":{"df":0,"docs":{},"p":{"df":0,"docs":{},"l":{"df":1,"docs":{"5":{"tf":1.0}}}}}}}},"o":{"df":0,"docs":{},"k":{"df":1,"docs":{"0":{"tf":1.4142135623730951}}},"t":{"<":{"a":{"df":0,"docs":{},"r":{"c":{"df":0,"docs":{},"h":{">":{".":{"df":0,"docs":{},"e":{"df":0,"docs":{},"f":{"df":0,"docs":{},"i":{"df":1,"docs":{"35":{"tf":1.0}}}}}},"df":0,"docs":{}},"df":0,"docs":{}}},"df":0,"docs":{}}},"df":0,"docs":{}},"_":{"df":0,"docs":{},"s":{"df":0,"docs":{},"e":{"df":0,"docs":{},"r":{"df":0,"docs":{},"v":{"df":0,"docs":{},"i":{"c":{"df":2,"docs":{"20":{"tf":2.23606797749979},"21":{"tf":2.0}},"e":{"df":0,"docs":{},"s":{".":{"df":0,"docs":{},"s":{"df":0,"docs":{},"t":{"a":{"df":0,"docs":{},"l":{"df":0,"docs":{},"l":{"(":{"1":{"0":{"_":{"0":{"0":{"0":{"_":{"0":{"0":{"0":{"df":1,"docs":{"20":{"tf":1.0}}},"df":0,"docs":{}},"df":0,"docs":{}},"df":0,"docs":{}},"df":0,"docs":{}},"df":0,"docs":{}},"df":0,"docs":{}},"df":0,"docs":{}},"df":0,"docs":{}},"df":0,"docs":{}},"df":0,"docs":{}},"df":0,"docs":{}}}},"df":0,"docs":{}}}},"df":0,"docs":{}}}},"df":0,"docs":{}}}}}}},"a":{"a":{"6":{"4":{".":{"df":0,"docs":{},"e":{"df":0,"docs":{},"f":{"df":0,"docs":{},"i":{"df":1,"docs":{"35":{"tf":1.0}}}}}},"df":0,"docs":{}},"df":0,"docs":{}},"df":0,"docs":{}},"b":{"df":0,"docs":{},"l":{"df":1,"docs":{"35":{"tf":1.0}}}},"df":0,"docs":{},"r":{"df":0,"docs":{},"m":{".":{"df":0,"docs":{},"e":{"df":0,"docs":{},"f":{"df":0,"docs":{},"i":{"df":1,"docs":{"35":{"tf":1.0}}}}}},"df":0,"docs":{}}}},"df":11,"docs":{"15":{"tf":1.0},"16":{"tf":1.4142135623730951},"17":{"tf":2.0},"23":{"tf":1.0},"25":{"tf":2.6457513110645907},"26":{"tf":1.4142135623730951},"28":{"tf":1.0},"30":{"tf":1.0},"33":{"tf":1.7320508075688772},"34":{"tf":1.0},"35":{"tf":2.0}},"i":{"a":{"3":{"2":{".":{"df":0,"docs":{},"e":{"df":0,"docs":{},"f":{"df":0,"docs":{},"i":{"df":1,"docs":{"35":{"tf":1.0}}}}}},"df":0,"docs":{}},"df":0,"docs":{}},"6":{"4":{".":{"df":0,"docs":{},"e":{"df":0,"docs":{},"f":{"df":0,"docs":{},"i":{"df":1,"docs":{"35":{"tf":1.0}}}}}},"df":0,"docs":{}},"df":0,"docs":{}},"df":0,"docs":{}},"df":0,"docs":{}},"l":{"df":0,"docs":{},"o":{"a":{"d":{"df":1,"docs":{"25":{"tf":1.0}}},"df":0,"docs":{}},"df":0,"docs":{}}},"r":{"df":0,"docs":{},"i":{"df":0,"docs":{},"s":{"c":{"df":0,"docs":{},"v":{"1":{"2":{"8":{".":{"df":0,"docs":{},"e":{"df":0,"docs":{},"f":{"df":0,"docs":{},"i":{"df":1,"docs":{"35":{"tf":1.0}}}}}},"df":0,"docs":{}},"df":0,"docs":{}},"df":0,"docs":{}},"3":{"2":{".":{"df":0,"docs":{},"e":{"df":0,"docs":{},"f":{"df":0,"docs":{},"i":{"df":1,"docs":{"35":{"tf":1.0}}}}}},"df":0,"docs":{}},"df":0,"docs":{}},"6":{"4":{".":{"df":0,"docs":{},"e":{"df":0,"docs":{},"f":{"df":0,"docs":{},"i":{"df":1,"docs":{"35":{"tf":1.0}}}}}},"df":0,"docs":{}},"df":0,"docs":{}},"df":0,"docs":{}}},"df":0,"docs":{}}}},"s":{"df":0,"docs":{},"e":{"df":0,"docs":{},"r":{"df":0,"docs":{},"v":{"df":0,"docs":{},"i":{"c":{"df":5,"docs":{"20":{"tf":1.0},"21":{"tf":1.0},"22":{"tf":1.0},"25":{"tf":1.4142135623730951},"26":{"tf":1.0}},"e":{"_":{"a":{"c":{"c":{"df":0,"docs":{},"e":{"df":0,"docs":{},"s":{"df":0,"docs":{},"s":{"df":1,"docs":{"33":{"tf":1.4142135623730951}}}}}},"df":0,"docs":{}},"df":0,"docs":{}},"df":0,"docs":{}},"df":0,"docs":{},"s":{":":{":":{"df":0,"docs":{},"i":{"df":0,"docs":{},"m":{"a":{"df":0,"docs":{},"g":{"df":0,"docs":{},"e":{"_":{"df":0,"docs":{},"h":{"a":{"df":0,"docs":{},"n":{"d":{"df":0,"docs":{},"l":{"df":1,"docs":{"21":{"tf":1.0}}}},"df":0,"docs":{}}},"df":0,"docs":{}}},"df":0,"docs":{}}}},"df":0,"docs":{}}},"l":{"df":0,"docs":{},"o":{"c":{"a":{"df":0,"docs":{},"t":{"df":0,"docs":{},"e":{"_":{"d":{"df":0,"docs":{},"e":{"df":0,"docs":{},"v":{"df":0,"docs":{},"i":{"c":{"df":0,"docs":{},"e":{"_":{"df":0,"docs":{},"p":{"a":{"df":0,"docs":{},"t":{"df":0,"docs":{},"h":{"df":1,"docs":{"19":{"tf":1.0}}}}},"df":0,"docs":{}}},"df":0,"docs":{}}},"df":0,"docs":{}}}}},"df":0,"docs":{},"h":{"a":{"df":0,"docs":{},"n":{"d":{"df":0,"docs":{},"l":{"df":1,"docs":{"19":{"tf":1.0}},"e":{"_":{"b":{"df":0,"docs":{},"u":{"df":0,"docs":{},"f":{"df":0,"docs":{},"f":{"df":1,"docs":{"19":{"tf":1.0}}}}}},"df":0,"docs":{}},"df":0,"docs":{}}}},"df":0,"docs":{}}},"df":0,"docs":{}}},"df":0,"docs":{}}}},"df":0,"docs":{}},"df":0,"docs":{}}},"o":{"df":0,"docs":{},"p":{"df":0,"docs":{},"e":{"df":0,"docs":{},"n":{"_":{"df":0,"docs":{},"p":{"df":0,"docs":{},"r":{"df":0,"docs":{},"o":{"df":0,"docs":{},"t":{"df":0,"docs":{},"o":{"c":{"df":0,"docs":{},"o":{"df":0,"docs":{},"l":{"_":{"df":0,"docs":{},"e":{"df":0,"docs":{},"x":{"c":{"df":0,"docs":{},"l":{"df":0,"docs":{},"u":{"df":0,"docs":{},"s":{"df":1,"docs":{"19":{"tf":1.4142135623730951}}}}}},"df":0,"docs":{}}}},"df":1,"docs":{"19":{"tf":1.0}}}}},"df":0,"docs":{}}}}}}},"df":0,"docs":{}}}}}},"df":0,"docs":{}},"df":0,"docs":{}}}},"df":0,"docs":{}}}}}},"x":{"6":{"4":{".":{"df":0,"docs":{},"e":{"df":0,"docs":{},"f":{"df":0,"docs":{},"i":{"df":2,"docs":{"15":{"tf":1.0},"35":{"tf":1.0}}}}}},"df":0,"docs":{}},"df":0,"docs":{}},"df":0,"docs":{}}}},"r":{"d":{"df":0,"docs":{},"e":{"df":0,"docs":{},"r":{"df":1,"docs":{"22":{"tf":2.23606797749979}}}}},"df":0,"docs":{}},"t":{"df":0,"docs":{},"h":{"df":4,"docs":{"21":{"tf":1.4142135623730951},"25":{"tf":1.0},"26":{"tf":1.0},"33":{"tf":1.0}}}}},"t":{".":{"df":0,"docs":{},"g":{"df":0,"docs":{},"e":{"df":0,"docs":{},"t":{"_":{"df":0,"docs":{},"h":{"a":{"df":0,"docs":{},"n":{"d":{"df":0,"docs":{},"l":{"df":0,"docs":{},"e":{"_":{"df":0,"docs":{},"f":{"df":0,"docs":{},"o":{"df":0,"docs":{},"r":{"_":{"df":0,"docs":{},"p":{"df":0,"docs":{},"r":{"df":0,"docs":{},"o":{"df":0,"docs":{},"t":{"df":0,"docs":{},"o":{"c":{"df":0,"docs":{},"o":{"df":0,"docs":{},"l":{":":{":":{"<":{"df":0,"docs":{},"g":{"df":0,"docs":{},"r":{"a":{"df":0,"docs":{},"p":{"df":0,"docs":{},"h":{"df":0,"docs":{},"i":{"c":{"df":0,"docs":{},"s":{"df":0,"docs":{},"o":{"df":0,"docs":{},"u":{"df":0,"docs":{},"t":{"df":0,"docs":{},"p":{"df":0,"docs":{},"u":{"df":0,"docs":{},"t":{"df":1,"docs":{"22":{"tf":1.0}}}}}}}}}},"df":0,"docs":{}}}}},"df":0,"docs":{}}},"r":{"df":0,"docs":{},"n":{"df":0,"docs":{},"g":{"df":1,"docs":{"22":{"tf":1.0}}}}}},"df":0,"docs":{}},"df":0,"docs":{}},"df":0,"docs":{}}}},"df":0,"docs":{}}}}}}},"df":0,"docs":{}}}}},"df":0,"docs":{}}}},"df":0,"docs":{}}},"df":0,"docs":{}}},"df":0,"docs":{}}}},"o":{"df":0,"docs":{},"p":{"df":0,"docs":{},"e":{"df":0,"docs":{},"n":{"_":{"df":0,"docs":{},"p":{"df":0,"docs":{},"r":{"df":0,"docs":{},"o":{"df":0,"docs":{},"t":{"df":0,"docs":{},"o":{"c":{"df":0,"docs":{},"o":{"df":0,"docs":{},"l":{"_":{"df":0,"docs":{},"e":{"df":0,"docs":{},"x":{"c":{"df":0,"docs":{},"l":{"df":0,"docs":{},"u":{"df":0,"docs":{},"s":{"df":0,"docs":{},"i":{"df":0,"docs":{},"v":{"df":0,"docs":{},"e":{":":{":":{"<":{"df":0,"docs":{},"g":{"df":0,"docs":{},"r":{"a":{"df":0,"docs":{},"p":{"df":0,"docs":{},"h":{"df":0,"docs":{},"i":{"c":{"df":0,"docs":{},"s":{"df":0,"docs":{},"o":{"df":0,"docs":{},"u":{"df":0,"docs":{},"t":{"df":0,"docs":{},"p":{"df":0,"docs":{},"u":{"df":0,"docs":{},"t":{">":{"(":{"df":0,"docs":{},"g":{"df":0,"docs":{},"o":{"df":0,"docs":{},"p":{"_":{"df":0,"docs":{},"h":{"a":{"df":0,"docs":{},"n":{"d":{"df":0,"docs":{},"l":{"df":1,"docs":{"22":{"tf":1.0}}}},"df":0,"docs":{}}},"df":0,"docs":{}}},"df":0,"docs":{}}}}},"df":0,"docs":{}},"df":0,"docs":{}}}}}}}}},"df":0,"docs":{}}}}},"df":0,"docs":{}}},"r":{"df":0,"docs":{},"n":{"df":0,"docs":{},"g":{">":{"(":{"df":0,"docs":{},"r":{"df":0,"docs":{},"n":{"df":0,"docs":{},"g":{"_":{"df":0,"docs":{},"h":{"a":{"df":0,"docs":{},"n":{"d":{"df":0,"docs":{},"l":{"df":1,"docs":{"22":{"tf":1.0}}}},"df":0,"docs":{}}},"df":0,"docs":{}}},"df":0,"docs":{}}}}},"df":0,"docs":{}},"df":0,"docs":{}}}}},"df":0,"docs":{}},"df":0,"docs":{}},"df":0,"docs":{}}}}}}}},"df":0,"docs":{}}}},"df":0,"docs":{}}}},"df":0,"docs":{}}}}}}},"df":0,"docs":{}}}}}},"df":1,"docs":{"22":{"tf":1.0}}},"u":{"df":0,"docs":{},"f":{")":{".":{"df":0,"docs":{},"e":{"df":0,"docs":{},"x":{"df":0,"docs":{},"p":{"df":0,"docs":{},"e":{"c":{"df":0,"docs":{},"t":{"(":{"\"":{"df":0,"docs":{},"g":{"df":0,"docs":{},"e":{"df":0,"docs":{},"t":{"_":{"df":0,"docs":{},"r":{"df":0,"docs":{},"n":{"df":0,"docs":{},"g":{"df":1,"docs":{"22":{"tf":1.0}}}}}},"df":0,"docs":{}}}}},"df":0,"docs":{}},"df":0,"docs":{}}},"df":0,"docs":{}}}}}},"df":0,"docs":{}},"df":1,"docs":{"22":{"tf":1.0}},"f":{"df":0,"docs":{},"e":{"df":0,"docs":{},"r":{".":{"b":{"df":0,"docs":{},"l":{"df":0,"docs":{},"i":{"df":0,"docs":{},"t":{"(":{"&":{"df":0,"docs":{},"m":{"df":0,"docs":{},"u":{"df":0,"docs":{},"t":{"df":1,"docs":{"22":{"tf":1.0}}}}}},"df":0,"docs":{}},"df":0,"docs":{}}}}},"df":0,"docs":{},"p":{"df":0,"docs":{},"i":{"df":0,"docs":{},"x":{"df":0,"docs":{},"e":{"df":0,"docs":{},"l":{"(":{"df":0,"docs":{},"p":{".":{"df":0,"docs":{},"x":{"df":1,"docs":{"22":{"tf":1.0}}}},"df":0,"docs":{}},"x":{"df":1,"docs":{"22":{"tf":1.0}}}},"df":0,"docs":{}}}}}}},":":{":":{"b":{"df":0,"docs":{},"l":{"df":0,"docs":{},"i":{"df":0,"docs":{},"t":{"df":1,"docs":{"22":{"tf":1.0}}}}}},"df":0,"docs":{},"n":{"df":0,"docs":{},"e":{"df":0,"docs":{},"w":{"(":{"df":0,"docs":{},"w":{"df":0,"docs":{},"i":{"d":{"df":0,"docs":{},"t":{"df":0,"docs":{},"h":{"df":1,"docs":{"22":{"tf":1.0}}}}},"df":0,"docs":{}}}},"df":0,"docs":{}}}}},"df":0,"docs":{}},"df":1,"docs":{"22":{"tf":4.358898943540674}}}}}},"i":{"df":0,"docs":{},"l":{"d":{"df":5,"docs":{"0":{"tf":1.0},"23":{"tf":2.0},"6":{"tf":1.7320508075688772},"7":{"tf":1.0},"8":{"tf":2.23606797749979}}},"df":0,"docs":{}}}},"y":{"df":0,"docs":{},"t":{"df":0,"docs":{},"e":{"df":2,"docs":{"27":{"tf":1.4142135623730951},"32":{"tf":1.0}}}}}},"c":{"1":{"2":{"a":{"7":{"3":{"2":{"8":{"df":2,"docs":{"15":{"tf":1.0},"35":{"tf":1.0}}},"df":0,"docs":{}},"df":0,"docs":{}},"df":0,"docs":{}},"df":0,"docs":{}},"df":0,"docs":{}},"df":0,"docs":{}},"a":{"df":0,"docs":{},"l":{"df":0,"docs":{},"l":{"df":6,"docs":{"21":{"tf":2.0},"22":{"tf":1.0},"25":{"tf":1.0},"26":{"tf":1.4142135623730951},"35":{"tf":1.0},"5":{"tf":1.0}}}},"n":{"'":{"df":0,"docs":{},"t":{"df":2,"docs":{"29":{"tf":1.0},"30":{"tf":1.0}}}},"df":0,"docs":{},"o":{"df":0,"docs":{},"n":{"df":1,"docs":{"24":{"tf":1.0}}}}},"p":{"df":0,"docs":{},"i":{"df":0,"docs":{},"t":{"df":1,"docs":{"15":{"tf":1.0}}}}},"r":{"df":0,"docs":{},"e":{"df":2,"docs":{"16":{"tf":1.0},"33":{"tf":1.0}}},"g":{"df":0,"docs":{},"o":{"/":{"c":{"df":0,"docs":{},"o":{"df":0,"docs":{},"n":{"df":0,"docs":{},"f":{"df":0,"docs":{},"i":{"df":0,"docs":{},"g":{".":{"df":0,"docs":{},"t":{"df":0,"docs":{},"o":{"df":0,"docs":{},"m":{"df":0,"docs":{},"l":{"df":1,"docs":{"23":{"tf":1.0}}}}}}},"df":0,"docs":{}}}}}}},"df":0,"docs":{}},"df":3,"docs":{"22":{"tf":1.0},"4":{"tf":1.4142135623730951},"8":{"tf":1.0}}}}},"s":{"df":0,"docs":{},"e":{"df":5,"docs":{"15":{"tf":1.0},"19":{"tf":1.4142135623730951},"20":{"tf":1.0},"21":{"tf":1.0},"33":{"tf":1.0}}}},"u":{"df":0,"docs":{},"s":{"df":1,"docs":{"33":{"tf":1.0}}}}},"d":{"df":1,"docs":{"4":{"tf":1.0}}},"df":1,"docs":{"23":{"tf":1.0}},"e":{"df":0,"docs":{},"n":{"df":0,"docs":{},"t":{"df":0,"docs":{},"e":{"df":0,"docs":{},"r":{"df":1,"docs":{"22":{"tf":1.0}}}}}}},"h":{"a":{"df":0,"docs":{},"n":{"df":0,"docs":{},"g":{"df":4,"docs":{"22":{"tf":1.0},"23":{"tf":1.0},"33":{"tf":1.0},"4":{"tf":1.0}}}},"o":{"df":1,"docs":{"22":{"tf":1.0}}},"p":{"df":0,"docs":{},"t":{"df":0,"docs":{},"e":{"df":0,"docs":{},"r":{"df":3,"docs":{"18":{"tf":1.0},"24":{"tf":1.0},"30":{"tf":1.0}}}}}}},"df":0,"docs":{},"o":{"df":0,"docs":{},"o":{"df":0,"docs":{},"s":{"df":1,"docs":{"22":{"tf":1.0}}}},"s":{"df":0,"docs":{},"e":{"df":0,"docs":{},"n":{"df":1,"docs":{"22":{"tf":1.0}}}}}}},"l":{"df":0,"docs":{},"e":{"a":{"df":0,"docs":{},"r":{"df":2,"docs":{"16":{"tf":1.0},"34":{"tf":1.0}}}},"df":0,"docs":{}},"o":{"df":0,"docs":{},"s":{"df":0,"docs":{},"e":{"df":1,"docs":{"19":{"tf":1.0}}}}}},"o":{"d":{"df":0,"docs":{},"e":{"df":3,"docs":{"11":{"tf":1.4142135623730951},"22":{"tf":1.4142135623730951},"5":{"tf":1.0}}}},"df":0,"docs":{},"l":{"df":0,"docs":{},"l":{"df":0,"docs":{},"e":{"c":{"df":0,"docs":{},"t":{"df":1,"docs":{"33":{"tf":1.0}}}},"df":0,"docs":{}}}},"m":{"b":{"df":0,"docs":{},"i":{"df":0,"docs":{},"n":{"df":1,"docs":{"21":{"tf":1.0}}}}},"df":0,"docs":{},"m":{"a":{"df":0,"docs":{},"n":{"d":{"df":2,"docs":{"16":{"tf":1.0},"8":{"tf":1.0}}},"df":0,"docs":{}}},"df":0,"docs":{},"o":{"df":0,"docs":{},"n":{"df":0,"docs":{},"l":{"df":0,"docs":{},"i":{"df":2,"docs":{"30":{"tf":1.0},"5":{"tf":1.0}}}}}}},"p":{"df":0,"docs":{},"i":{"df":0,"docs":{},"l":{"df":1,"docs":{"7":{"tf":1.0}}}},"l":{"df":0,"docs":{},"e":{"df":0,"docs":{},"t":{"df":1,"docs":{"5":{"tf":1.0}}},"x":{"df":1,"docs":{"22":{"tf":1.0}}}}},"u":{"df":0,"docs":{},"t":{"df":1,"docs":{"17":{"tf":1.0}}}}}},"n":{"c":{"df":0,"docs":{},"e":{"df":0,"docs":{},"p":{"df":0,"docs":{},"t":{"df":13,"docs":{"0":{"tf":1.0},"24":{"tf":2.0},"25":{"tf":1.0},"26":{"tf":1.0},"27":{"tf":1.0},"28":{"tf":1.0},"29":{"tf":1.0},"30":{"tf":1.0},"31":{"tf":1.0},"32":{"tf":1.0},"33":{"tf":1.0},"34":{"tf":1.0},"35":{"tf":1.0}}}}}},"d":{"df":0,"docs":{},"i":{"df":0,"docs":{},"t":{"df":1,"docs":{"28":{"tf":1.0}}}}},"df":0,"docs":{},"f":{"df":0,"docs":{},"i":{"df":0,"docs":{},"g":{"df":0,"docs":{},"u":{"df":0,"docs":{},"r":{"df":1,"docs":{"35":{"tf":1.0}}}}}},"o":{"df":0,"docs":{},"r":{"df":0,"docs":{},"m":{"df":1,"docs":{"15":{"tf":1.0}}}}}},"s":{"df":0,"docs":{},"i":{"df":0,"docs":{},"s":{"df":0,"docs":{},"t":{"df":2,"docs":{"28":{"tf":1.0},"32":{"tf":1.0}}}}},"o":{"df":0,"docs":{},"l":{"df":1,"docs":{"31":{"tf":1.0}}}},"u":{"df":0,"docs":{},"m":{"df":1,"docs":{"26":{"tf":1.0}}}}},"t":{"a":{"df":0,"docs":{},"i":{"df":0,"docs":{},"n":{"df":6,"docs":{"12":{"tf":1.0},"16":{"tf":1.0},"18":{"tf":1.0},"31":{"tf":1.0},"34":{"tf":1.4142135623730951},"35":{"tf":1.0}}}}},"df":0,"docs":{},"e":{"df":0,"docs":{},"n":{"df":0,"docs":{},"t":{"df":2,"docs":{"24":{"tf":1.0},"4":{"tf":1.0}}}}},"r":{"df":0,"docs":{},"i":{"b":{"df":0,"docs":{},"u":{"df":0,"docs":{},"t":{"df":1,"docs":{"30":{"tf":1.0}}}}},"df":0,"docs":{}}}},"v":{"df":0,"docs":{},"e":{"df":0,"docs":{},"n":{"df":0,"docs":{},"i":{"df":1,"docs":{"21":{"tf":1.0}}}},"r":{"df":0,"docs":{},"t":{"_":{"d":{"df":0,"docs":{},"e":{"df":0,"docs":{},"v":{"df":0,"docs":{},"i":{"c":{"df":0,"docs":{},"e":{"_":{"df":0,"docs":{},"p":{"a":{"df":0,"docs":{},"t":{"df":0,"docs":{},"h":{"_":{"df":0,"docs":{},"t":{"df":0,"docs":{},"o":{"_":{"df":0,"docs":{},"t":{"df":0,"docs":{},"e":{"df":0,"docs":{},"x":{"df":0,"docs":{},"t":{"df":2,"docs":{"20":{"tf":1.0},"21":{"tf":1.0}}}}}}},"df":0,"docs":{}}}},"df":0,"docs":{}}}},"df":0,"docs":{}}},"df":0,"docs":{}}},"df":0,"docs":{}}}}},"df":0,"docs":{}},"df":2,"docs":{"21":{"tf":1.0},"31":{"tf":1.0}}}}}}},"p":{"df":0,"docs":{},"i":{"df":5,"docs":{"11":{"tf":1.4142135623730951},"15":{"tf":1.0},"16":{"tf":1.0},"22":{"tf":1.4142135623730951},"34":{"tf":1.0}}}},"r":{"df":0,"docs":{},"e":{":":{":":{"df":0,"docs":{},"m":{"df":0,"docs":{},"e":{"df":0,"docs":{},"m":{"df":1,"docs":{"22":{"tf":1.0}}}}}},"df":0,"docs":{}},"df":3,"docs":{"22":{"tf":1.0},"28":{"tf":1.0},"5":{"tf":1.0}}}},"u":{"df":0,"docs":{},"p":{"df":0,"docs":{},"l":{"df":2,"docs":{"20":{"tf":1.0},"34":{"tf":1.0}}}}},"v":{"df":0,"docs":{},"e":{"df":0,"docs":{},"r":{"df":1,"docs":{"30":{"tf":1.0}}}}}},"p":{"df":3,"docs":{"11":{"tf":1.4142135623730951},"12":{"tf":1.0},"16":{"tf":1.0}}},"r":{"a":{"df":0,"docs":{},"t":{"df":0,"docs":{},"e":{"df":3,"docs":{"22":{"tf":1.4142135623730951},"36":{"tf":2.0},"5":{"tf":2.0}}}}},"df":0,"docs":{},"e":{"a":{"df":0,"docs":{},"t":{"df":10,"docs":{"1":{"tf":1.0},"12":{"tf":1.0},"13":{"tf":1.0},"15":{"tf":1.4142135623730951},"16":{"tf":1.7320508075688772},"2":{"tf":1.7320508075688772},"22":{"tf":1.7320508075688772},"3":{"tf":1.0},"4":{"tf":2.0},"5":{"tf":1.0}}}},"df":0,"docs":{}},"i":{"df":0,"docs":{},"t":{"df":0,"docs":{},"i":{"c":{"df":1,"docs":{"24":{"tf":1.0}}},"df":0,"docs":{}}}}},"u":{"df":0,"docs":{},"l":{"df":0,"docs":{},"m":{"df":0,"docs":{},"i":{"df":0,"docs":{},"n":{"df":1,"docs":{"25":{"tf":1.0}}}}}},"r":{"df":0,"docs":{},"r":{"df":0,"docs":{},"e":{"df":0,"docs":{},"n":{"df":0,"docs":{},"t":{"df":5,"docs":{"20":{"tf":1.0},"21":{"tf":1.0},"24":{"tf":1.0},"5":{"tf":1.0},"7":{"tf":1.0}}}}}}}},"y":{"c":{"df":0,"docs":{},"l":{"df":1,"docs":{"33":{"tf":1.0}}}},"df":0,"docs":{}}},"d":{"a":{"df":0,"docs":{},"t":{"a":{"df":5,"docs":{"16":{"tf":1.0},"21":{"tf":1.4142135623730951},"31":{"tf":1.0},"32":{"tf":1.0},"34":{"tf":1.0}}},"df":0,"docs":{}}},"df":0,"docs":{},"e":{"a":{"df":0,"docs":{},"l":{"df":1,"docs":{"33":{"tf":1.0}}}},"b":{"df":0,"docs":{},"i":{"a":{"df":0,"docs":{},"n":{"/":{"df":0,"docs":{},"u":{"b":{"df":0,"docs":{},"u":{"df":0,"docs":{},"n":{"df":0,"docs":{},"t":{"df":0,"docs":{},"u":{"df":1,"docs":{"10":{"tf":1.0}}}}}}},"df":0,"docs":{}}},"df":1,"docs":{"11":{"tf":1.0}}}},"df":0,"docs":{}}},"df":0,"docs":{},"f":{"a":{"df":0,"docs":{},"u":{"df":0,"docs":{},"l":{"df":0,"docs":{},"t":{"df":3,"docs":{"21":{"tf":1.0},"23":{"tf":1.0},"35":{"tf":1.0}}}}}},"df":0,"docs":{},"i":{"df":0,"docs":{},"n":{"df":4,"docs":{"22":{"tf":1.0},"30":{"tf":1.0},"34":{"tf":1.0},"5":{"tf":1.0}}}}},"l":{"df":0,"docs":{},"e":{"df":0,"docs":{},"t":{"df":1,"docs":{"33":{"tf":1.0}}}},"l":{"df":1,"docs":{"17":{"tf":1.0}}}},"p":{"df":0,"docs":{},"e":{"df":0,"docs":{},"n":{"d":{"df":6,"docs":{"10":{"tf":2.0},"11":{"tf":1.0},"15":{"tf":1.0},"17":{"tf":1.0},"3":{"tf":1.4142135623730951},"4":{"tf":1.0}}},"df":0,"docs":{}}}},"r":{"df":0,"docs":{},"i":{"df":0,"docs":{},"v":{"df":0,"docs":{},"e":{"(":{"c":{"df":0,"docs":{},"l":{"df":0,"docs":{},"o":{"df":0,"docs":{},"n":{"df":1,"docs":{"22":{"tf":1.0}}}}}},"df":0,"docs":{}},"df":0,"docs":{}}}}},"s":{"c":{"df":0,"docs":{},"r":{"df":0,"docs":{},"i":{"b":{"df":5,"docs":{"0":{"tf":1.0},"1":{"tf":1.0},"25":{"tf":1.0},"31":{"tf":1.0},"34":{"tf":1.0}}},"df":0,"docs":{}}}},"df":0,"docs":{},"t":{"df":1,"docs":{"22":{"tf":1.4142135623730951}},"r":{"df":0,"docs":{},"u":{"c":{"df":0,"docs":{},"t":{"df":1,"docs":{"16":{"tf":1.0}}}},"df":0,"docs":{}}}}},"t":{"a":{"df":0,"docs":{},"i":{"df":0,"docs":{},"l":{"df":8,"docs":{"10":{"tf":1.0},"11":{"tf":1.0},"15":{"tf":1.0},"20":{"tf":1.0},"27":{"tf":1.0},"30":{"tf":1.0},"31":{"tf":1.4142135623730951},"33":{"tf":1.0}}}}},"df":0,"docs":{}},"v":{"df":0,"docs":{},"i":{"c":{"df":4,"docs":{"19":{"tf":1.0},"29":{"tf":1.4142135623730951},"30":{"tf":1.0},"31":{"tf":3.1622776601683795}},"e":{"_":{"df":0,"docs":{},"p":{"a":{"df":0,"docs":{},"t":{"df":0,"docs":{},"h":{"_":{"df":0,"docs":{},"t":{"df":0,"docs":{},"o":{"_":{"df":0,"docs":{},"t":{"df":0,"docs":{},"e":{"df":0,"docs":{},"x":{"df":0,"docs":{},"t":{"_":{"df":0,"docs":{},"h":{"a":{"df":0,"docs":{},"n":{"d":{"df":0,"docs":{},"l":{"df":2,"docs":{"20":{"tf":1.4142135623730951},"21":{"tf":1.7320508075688772}}}},"df":0,"docs":{}}},"df":0,"docs":{}}},"df":2,"docs":{"20":{"tf":1.4142135623730951},"21":{"tf":1.4142135623730951}}}}}}},"df":0,"docs":{}}}},"df":0,"docs":{}}}},"df":0,"docs":{}}},"df":0,"docs":{},"p":{"a":{"df":0,"docs":{},"t":{"df":0,"docs":{},"h":{"df":0,"docs":{},"t":{"df":0,"docs":{},"o":{"df":0,"docs":{},"t":{"df":0,"docs":{},"e":{"df":0,"docs":{},"x":{"df":0,"docs":{},"t":{"df":2,"docs":{"20":{"tf":1.4142135623730951},"21":{"tf":1.7320508075688772}}}}}}}}}}},"df":0,"docs":{}}}},"df":0,"docs":{}}}},"i":{"df":0,"docs":{},"f":{"df":0,"docs":{},"f":{"df":0,"docs":{},"e":{"df":0,"docs":{},"r":{"df":5,"docs":{"20":{"tf":1.0},"21":{"tf":1.0},"32":{"tf":1.0},"35":{"tf":1.0},"5":{"tf":1.7320508075688772}}}}}},"m":{"df":1,"docs":{"22":{"tf":1.4142135623730951}}},"r":{"df":0,"docs":{},"e":{"c":{"df":0,"docs":{},"t":{"df":0,"docs":{},"l":{"df":0,"docs":{},"i":{"df":1,"docs":{"29":{"tf":1.0}}}},"o":{"df":0,"docs":{},"r":{"df":0,"docs":{},"i":{"df":6,"docs":{"11":{"tf":1.4142135623730951},"12":{"tf":1.0},"13":{"tf":1.0},"15":{"tf":1.4142135623730951},"16":{"tf":1.0},"4":{"tf":1.0}}}}}}},"df":0,"docs":{}}},"s":{"c":{"a":{"df":0,"docs":{},"r":{"d":{"df":1,"docs":{"21":{"tf":1.0}}},"df":0,"docs":{}}},"df":0,"docs":{}},"df":0,"docs":{},"k":{"df":5,"docs":{"16":{"tf":1.0},"27":{"tf":1.0},"29":{"tf":1.0},"31":{"tf":1.0},"34":{"tf":2.0}}},"p":{"df":0,"docs":{},"l":{"a":{"df":0,"docs":{},"y":{"df":0,"docs":{},"o":{"df":0,"docs":{},"n":{"df":0,"docs":{},"l":{"df":0,"docs":{},"i":{"df":1,"docs":{"20":{"tf":1.0}}},"y":{"(":{"df":0,"docs":{},"t":{"df":0,"docs":{},"r":{"df":0,"docs":{},"u":{"df":2,"docs":{"20":{"tf":1.0},"21":{"tf":1.0}}}}}},"df":0,"docs":{}}}}}}},"df":0,"docs":{}}},"t":{"df":0,"docs":{},"i":{"df":0,"docs":{},"n":{"c":{"df":0,"docs":{},"t":{"df":1,"docs":{"25":{"tf":1.0}}}},"df":0,"docs":{}}}}},"v":{"df":0,"docs":{},"e":{"df":0,"docs":{},"r":{"df":0,"docs":{},"s":{"df":1,"docs":{"30":{"tf":1.0}}}}}}},"n":{"df":0,"docs":{},"f":{"df":1,"docs":{"10":{"tf":1.0}}}},"o":{"c":{"df":0,"docs":{},"u":{"df":0,"docs":{},"m":{"df":0,"docs":{},"e":{"df":0,"docs":{},"n":{"df":0,"docs":{},"t":{"df":4,"docs":{"11":{"tf":1.0},"21":{"tf":1.0},"24":{"tf":1.0},"31":{"tf":1.0}}}}}}}},"df":1,"docs":{"5":{"tf":1.0}},"e":{"df":0,"docs":{},"s":{"df":0,"docs":{},"n":{"'":{"df":0,"docs":{},"t":{"df":1,"docs":{"15":{"tf":1.0}}}},"df":0,"docs":{}}}},"n":{"'":{"df":0,"docs":{},"t":{"df":2,"docs":{"32":{"tf":1.0},"7":{"tf":1.0}}}},"df":0,"docs":{}},"w":{"df":0,"docs":{},"n":{"df":1,"docs":{"17":{"tf":1.0}}}}},"r":{"a":{"df":0,"docs":{},"w":{"_":{"df":0,"docs":{},"s":{"df":0,"docs":{},"i":{"df":0,"docs":{},"e":{"df":0,"docs":{},"r":{"df":0,"docs":{},"p":{"df":0,"docs":{},"i":{"df":0,"docs":{},"n":{"df":0,"docs":{},"s":{"df":0,"docs":{},"k":{"df":0,"docs":{},"i":{"(":{"b":{"df":0,"docs":{},"t":{")":{".":{"df":0,"docs":{},"u":{"df":0,"docs":{},"n":{"df":0,"docs":{},"w":{"df":0,"docs":{},"r":{"a":{"df":0,"docs":{},"p":{"df":1,"docs":{"22":{"tf":1.0}}}},"df":0,"docs":{}}}}}},"df":0,"docs":{}},"df":1,"docs":{"22":{"tf":1.0}}}},"df":0,"docs":{}},"df":0,"docs":{}}}}}}}}}}}},"df":1,"docs":{"22":{"tf":3.0}}}},"df":0,"docs":{},"i":{"df":0,"docs":{},"v":{"df":0,"docs":{},"e":{"df":5,"docs":{"13":{"tf":1.7320508075688772},"14":{"tf":1.0},"15":{"tf":1.4142135623730951},"17":{"tf":1.0},"29":{"tf":1.0}},"r":{"df":3,"docs":{"23":{"tf":2.23606797749979},"25":{"tf":1.0},"28":{"tf":1.0}}}}}},"o":{"df":0,"docs":{},"p":{"df":1,"docs":{"19":{"tf":1.0}}}}},"u":{"df":0,"docs":{},"e":{"df":1,"docs":{"33":{"tf":1.0}}},"r":{"df":0,"docs":{},"e":{"df":4,"docs":{"25":{"tf":1.0},"26":{"tf":1.0},"30":{"tf":1.4142135623730951},"33":{"tf":1.0}}}}}},"df":0,"docs":{},"e":{"a":{"c":{"df":0,"docs":{},"h":{"df":6,"docs":{"21":{"tf":1.4142135623730951},"22":{"tf":1.4142135623730951},"32":{"tf":1.4142135623730951},"33":{"tf":1.0},"34":{"tf":1.0},"5":{"tf":1.0}}}},"df":0,"docs":{},"r":{"df":0,"docs":{},"l":{"df":0,"docs":{},"i":{"df":1,"docs":{"25":{"tf":1.0}}}}},"s":{"df":1,"docs":{"11":{"tf":1.0}},"i":{"df":0,"docs":{},"e":{"df":0,"docs":{},"s":{"df":0,"docs":{},"t":{"df":1,"docs":{"7":{"tf":1.0}}}}}}}},"d":{"df":0,"docs":{},"k":{"2":{"df":1,"docs":{"10":{"tf":1.0}}},"df":0,"docs":{}}},"df":0,"docs":{},"f":{"df":0,"docs":{},"f":{"df":0,"docs":{},"i":{"c":{"df":0,"docs":{},"i":{"df":1,"docs":{"22":{"tf":1.0}}}},"df":0,"docs":{}}},"i":{"/":{"b":{"df":0,"docs":{},"o":{"df":0,"docs":{},"o":{"df":0,"docs":{},"t":{"df":1,"docs":{"15":{"tf":1.4142135623730951}}}}}},"df":0,"docs":{}},"\\":{"b":{"df":0,"docs":{},"o":{"df":0,"docs":{},"o":{"df":0,"docs":{},"t":{"\\":{"b":{"df":0,"docs":{},"o":{"df":0,"docs":{},"o":{"df":0,"docs":{},"t":{"df":0,"docs":{},"x":{"6":{"4":{".":{"df":0,"docs":{},"e":{"df":0,"docs":{},"f":{"df":0,"docs":{},"i":{"df":1,"docs":{"20":{"tf":1.0}}}}}},"df":0,"docs":{}},"df":0,"docs":{}},"df":0,"docs":{}}}}}},"df":0,"docs":{}},"df":1,"docs":{"35":{"tf":1.0}}}}}},"df":0,"docs":{}},"_":{"b":{"df":0,"docs":{},"o":{"df":0,"docs":{},"o":{"df":0,"docs":{},"t":{"_":{"df":0,"docs":{},"s":{"df":0,"docs":{},"e":{"df":0,"docs":{},"r":{"df":0,"docs":{},"v":{"df":0,"docs":{},"i":{"c":{"df":1,"docs":{"26":{"tf":1.0}},"e":{"_":{"d":{"df":0,"docs":{},"r":{"df":0,"docs":{},"i":{"df":0,"docs":{},"v":{"df":1,"docs":{"23":{"tf":1.0}}}}}},"df":0,"docs":{}},"df":0,"docs":{}}},"df":0,"docs":{}}}}}}},"df":0,"docs":{}}}}},"df":0,"docs":{},"r":{"df":0,"docs":{},"u":{"df":0,"docs":{},"n":{"df":0,"docs":{},"t":{"df":0,"docs":{},"i":{"df":0,"docs":{},"m":{"df":0,"docs":{},"e":{"_":{"d":{"df":0,"docs":{},"r":{"df":0,"docs":{},"i":{"df":0,"docs":{},"v":{"df":1,"docs":{"23":{"tf":1.0}}}}}},"df":0,"docs":{},"s":{"df":0,"docs":{},"e":{"df":0,"docs":{},"r":{"df":0,"docs":{},"v":{"df":0,"docs":{},"i":{"c":{"df":1,"docs":{"26":{"tf":1.0}}},"df":0,"docs":{}}}}}}},"df":0,"docs":{}}}}}}}},"s":{"df":0,"docs":{},"y":{"df":0,"docs":{},"s":{"df":0,"docs":{},"t":{"df":0,"docs":{},"e":{"df":0,"docs":{},"m":{"_":{"df":0,"docs":{},"t":{"df":1,"docs":{"26":{"tf":1.0}}}},"df":0,"docs":{}}}}}}}},"df":3,"docs":{"15":{"tf":1.7320508075688772},"16":{"tf":1.0},"35":{"tf":1.0}}}},"m":{"b":{"df":0,"docs":{},"e":{"d":{"df":1,"docs":{"22":{"tf":1.0}}},"df":0,"docs":{}}},"df":0,"docs":{},"p":{"df":0,"docs":{},"t":{"df":0,"docs":{},"i":{"df":1,"docs":{"4":{"tf":1.0}}}}}},"n":{"a":{"b":{"df":0,"docs":{},"l":{"df":1,"docs":{"13":{"tf":1.0}}}},"df":0,"docs":{}},"c":{"df":0,"docs":{},"o":{"d":{"df":1,"docs":{"31":{"tf":1.0}}},"df":0,"docs":{}}},"d":{"df":2,"docs":{"25":{"tf":1.0},"34":{"tf":1.0}},"i":{"a":{"df":0,"docs":{},"n":{"df":1,"docs":{"27":{"tf":1.0}}}},"df":0,"docs":{}}},"df":0,"docs":{},"o":{"df":0,"docs":{},"u":{"df":0,"docs":{},"g":{"df":0,"docs":{},"h":{"df":1,"docs":{"5":{"tf":1.0}}}}}},"s":{"df":0,"docs":{},"u":{"df":0,"docs":{},"r":{"df":1,"docs":{"5":{"tf":1.0}}}}},"t":{"df":0,"docs":{},"e":{"df":0,"docs":{},"r":{"df":1,"docs":{"17":{"tf":1.0}}}},"r":{"df":0,"docs":{},"i":{"df":6,"docs":{"20":{"tf":1.0},"22":{"tf":1.0},"26":{"tf":1.0},"34":{"tf":2.0},"4":{"tf":1.0},"5":{"tf":1.4142135623730951}}}}}},"r":{"df":0,"docs":{},"r":{"df":0,"docs":{},"o":{"df":0,"docs":{},"r":{"df":2,"docs":{"21":{"tf":1.4142135623730951},"5":{"tf":1.0}}}}}},"s":{"df":0,"docs":{},"p":{"/":{"df":0,"docs":{},"e":{"df":0,"docs":{},"f":{"df":0,"docs":{},"i":{"/":{"b":{"df":0,"docs":{},"o":{"df":0,"docs":{},"o":{"df":0,"docs":{},"t":{"/":{"b":{"df":0,"docs":{},"o":{"df":0,"docs":{},"o":{"df":0,"docs":{},"t":{"df":0,"docs":{},"x":{"6":{"4":{".":{"df":0,"docs":{},"e":{"df":0,"docs":{},"f":{"df":0,"docs":{},"i":{"df":2,"docs":{"12":{"tf":1.0},"16":{"tf":1.0}}}}}},"df":0,"docs":{}},"df":0,"docs":{}},"df":0,"docs":{}}}}}},"df":0,"docs":{}},"df":2,"docs":{"12":{"tf":1.0},"16":{"tf":1.0}}}}}},"df":0,"docs":{}},"df":0,"docs":{}}}}},"df":4,"docs":{"13":{"tf":1.0},"15":{"tf":1.0},"16":{"tf":1.4142135623730951},"35":{"tf":1.0}}},"s":{"df":0,"docs":{},"e":{"df":0,"docs":{},"n":{"df":0,"docs":{},"t":{"df":0,"docs":{},"i":{"df":2,"docs":{"31":{"tf":1.0},"5":{"tf":1.0}}}}}}}},"v":{"df":0,"docs":{},"e":{"df":0,"docs":{},"n":{"df":1,"docs":{"33":{"tf":1.0}}},"r":{"df":0,"docs":{},"y":{"df":0,"docs":{},"t":{"df":0,"docs":{},"h":{"df":1,"docs":{"5":{"tf":1.0}}}}}}}},"x":{"a":{"c":{"df":0,"docs":{},"t":{"df":0,"docs":{},"l":{"df":0,"docs":{},"i":{"df":1,"docs":{"15":{"tf":1.0}}}}}},"df":0,"docs":{},"m":{"df":0,"docs":{},"p":{"df":0,"docs":{},"l":{"df":8,"docs":{"15":{"tf":1.0},"16":{"tf":1.4142135623730951},"17":{"tf":1.0},"20":{"tf":1.7320508075688772},"21":{"tf":1.4142135623730951},"22":{"tf":2.0},"23":{"tf":1.0},"30":{"tf":1.0}},"e":{".":{"df":0,"docs":{},"r":{"df":0,"docs":{},"s":{"@":{"0":{"5":{"8":{"df":1,"docs":{"20":{"tf":1.0}}},"df":0,"docs":{}},"df":0,"docs":{}},"df":0,"docs":{}},"df":0,"docs":{}}}},"df":0,"docs":{}}}}}},"c":{"df":0,"docs":{},"i":{"df":0,"docs":{},"t":{"df":1,"docs":{"5":{"tf":1.0}}}},"l":{"df":0,"docs":{},"u":{"df":0,"docs":{},"s":{"df":1,"docs":{"19":{"tf":1.0}}}}}},"df":0,"docs":{},"e":{"c":{"df":0,"docs":{},"u":{"df":0,"docs":{},"t":{"a":{"b":{"df":0,"docs":{},"l":{"df":0,"docs":{},"e":{".":{"df":0,"docs":{},"e":{"df":0,"docs":{},"f":{"df":0,"docs":{},"i":{"df":1,"docs":{"16":{"tf":1.0}}}}}},"df":0,"docs":{}}}},"df":0,"docs":{}},"df":8,"docs":{"11":{"tf":1.0},"12":{"tf":1.0},"16":{"tf":1.0},"20":{"tf":1.0},"26":{"tf":1.0},"29":{"tf":1.0},"5":{"tf":1.0},"8":{"tf":1.0}}}}},"df":0,"docs":{}},"i":{"df":0,"docs":{},"s":{"df":0,"docs":{},"t":{"df":1,"docs":{"35":{"tf":1.0}}}},"t":{"df":2,"docs":{"1":{"tf":1.0},"33":{"tf":1.0}}}},"p":{"df":0,"docs":{},"e":{"c":{"df":0,"docs":{},"t":{"(":{"\"":{"c":{"df":0,"docs":{},"o":{"df":0,"docs":{},"n":{"df":0,"docs":{},"v":{"df":0,"docs":{},"e":{"df":0,"docs":{},"r":{"df":0,"docs":{},"t":{"_":{"d":{"df":0,"docs":{},"e":{"df":0,"docs":{},"v":{"df":0,"docs":{},"i":{"c":{"df":0,"docs":{},"e":{"_":{"df":0,"docs":{},"p":{"a":{"df":0,"docs":{},"t":{"df":0,"docs":{},"h":{"_":{"df":0,"docs":{},"t":{"df":0,"docs":{},"o":{"_":{"df":0,"docs":{},"t":{"df":0,"docs":{},"e":{"df":0,"docs":{},"x":{"df":0,"docs":{},"t":{"df":2,"docs":{"20":{"tf":1.0},"21":{"tf":1.0}}}}}}},"df":0,"docs":{}}}},"df":0,"docs":{}}}},"df":0,"docs":{}}},"df":0,"docs":{}}},"df":0,"docs":{}}}}},"df":0,"docs":{}},"df":0,"docs":{}}}}}}}},"d":{"df":0,"docs":{},"e":{"df":0,"docs":{},"v":{"df":0,"docs":{},"i":{"c":{"df":0,"docs":{},"e":{"df":0,"docs":{},"p":{"a":{"df":0,"docs":{},"t":{"df":0,"docs":{},"h":{"df":0,"docs":{},"t":{"df":0,"docs":{},"o":{"df":0,"docs":{},"t":{"df":0,"docs":{},"e":{"df":0,"docs":{},"x":{"df":0,"docs":{},"t":{"df":2,"docs":{"20":{"tf":1.0},"21":{"tf":1.0}}}}}}}}}}},"df":0,"docs":{}}}},"df":0,"docs":{}}}}},"df":0,"docs":{}},"df":0,"docs":{}},"df":0,"docs":{}}},"df":0,"docs":{}},"o":{"df":0,"docs":{},"r":{"df":0,"docs":{},"t":{"df":1,"docs":{"5":{"tf":1.0}}}}}},"t":{"df":0,"docs":{},"e":{"df":0,"docs":{},"n":{"df":0,"docs":{},"s":{"df":2,"docs":{"26":{"tf":1.0},"28":{"tf":1.0}}}},"r":{"df":0,"docs":{},"n":{"df":1,"docs":{"22":{"tf":1.0}}}}}}}},"f":{"1":{"2":{"df":1,"docs":{"17":{"tf":1.0}}},"df":0,"docs":{}},"3":{"2":{"df":1,"docs":{"22":{"tf":3.1622776601683795}}},"df":0,"docs":{}},"8":{"1":{"df":0,"docs":{},"f":{"df":3,"docs":{"15":{"tf":1.0},"16":{"tf":1.0},"35":{"tf":1.0}}}},"df":0,"docs":{}},"9":{"df":1,"docs":{"17":{"tf":1.0}}},"a":{"df":0,"docs":{},"i":{"df":0,"docs":{},"l":{"df":3,"docs":{"20":{"tf":1.0},"21":{"tf":1.0},"22":{"tf":1.0}}},"r":{"df":0,"docs":{},"l":{"df":0,"docs":{},"i":{"df":2,"docs":{"26":{"tf":1.0},"32":{"tf":1.0}}}}}},"t":{"df":3,"docs":{"15":{"tf":2.0},"16":{"tf":1.0},"35":{"tf":1.0}}}},"df":0,"docs":{},"e":{"d":{"4":{"df":1,"docs":{"27":{"tf":1.0}}},"df":0,"docs":{},"o":{"df":0,"docs":{},"r":{"a":{"df":2,"docs":{"10":{"tf":1.0},"11":{"tf":1.0}}},"df":0,"docs":{}}}},"df":0,"docs":{},"w":{"df":3,"docs":{"13":{"tf":1.0},"26":{"tf":1.0},"4":{"tf":1.0}}}},"i":{"df":0,"docs":{},"e":{"df":0,"docs":{},"l":{"d":{"df":1,"docs":{"27":{"tf":1.0}}},"df":0,"docs":{}}},"g":{"df":0,"docs":{},"u":{"df":0,"docs":{},"r":{"df":1,"docs":{"33":{"tf":1.0}}}}},"l":{"df":0,"docs":{},"e":{"df":6,"docs":{"11":{"tf":2.8284271247461903},"15":{"tf":2.0},"20":{"tf":1.0},"31":{"tf":1.4142135623730951},"35":{"tf":2.449489742783178},"7":{"tf":1.0}}}},"n":{"a":{"df":0,"docs":{},"l":{"df":1,"docs":{"5":{"tf":1.0}}}},"d":{"df":2,"docs":{"19":{"tf":1.0},"21":{"tf":1.4142135623730951}}},"df":0,"docs":{}},"r":{"df":0,"docs":{},"m":{"df":0,"docs":{},"w":{"a":{"df":0,"docs":{},"r":{"df":2,"docs":{"10":{"tf":1.0},"11":{"tf":1.7320508075688772}}}},"df":0,"docs":{}}},"s":{"df":0,"docs":{},"t":{"df":5,"docs":{"19":{"tf":1.0},"20":{"tf":1.4142135623730951},"21":{"tf":1.7320508075688772},"27":{"tf":1.0},"5":{"tf":1.0}}}}}},"l":{"a":{"df":0,"docs":{},"g":{"df":2,"docs":{"23":{"tf":1.0},"33":{"tf":1.0}}}},"df":0,"docs":{},"e":{"df":0,"docs":{},"x":{"df":0,"docs":{},"i":{"b":{"df":0,"docs":{},"l":{"df":2,"docs":{"31":{"tf":1.0},"32":{"tf":1.0}}}},"df":0,"docs":{}}}}},"n":{"df":6,"docs":{"20":{"tf":1.4142135623730951},"21":{"tf":1.0},"22":{"tf":3.1622776601683795},"26":{"tf":1.0},"4":{"tf":1.0},"5":{"tf":1.0}}},"o":{"c":{"df":0,"docs":{},"u":{"df":1,"docs":{"0":{"tf":1.0}}}},"df":0,"docs":{},"l":{"df":0,"docs":{},"l":{"df":0,"docs":{},"o":{"df":0,"docs":{},"w":{"df":3,"docs":{"22":{"tf":1.0},"3":{"tf":1.0},"34":{"tf":1.0}}}}}},"r":{"df":0,"docs":{},"e":{"df":0,"docs":{},"v":{"df":1,"docs":{"22":{"tf":1.0}}}},"m":{"a":{"df":0,"docs":{},"t":{"=":{"df":0,"docs":{},"r":{"a":{"df":0,"docs":{},"w":{",":{"df":0,"docs":{},"f":{"df":0,"docs":{},"i":{"df":0,"docs":{},"l":{"df":0,"docs":{},"e":{"=":{"df":0,"docs":{},"f":{"a":{"df":0,"docs":{},"t":{":":{"df":0,"docs":{},"r":{"df":0,"docs":{},"w":{":":{"df":0,"docs":{},"e":{"df":0,"docs":{},"s":{"df":0,"docs":{},"p":{"df":1,"docs":{"13":{"tf":1.0}}}}}},"df":0,"docs":{}}}},"df":0,"docs":{}}},"df":0,"docs":{}}},"df":0,"docs":{}}}}}},"df":0,"docs":{}}},"df":0,"docs":{}}},"df":3,"docs":{"15":{"tf":1.0},"16":{"tf":1.0},"27":{"tf":1.4142135623730951}}}},"df":0,"docs":{}}}},"r":{"a":{"c":{"df":0,"docs":{},"t":{"a":{"df":0,"docs":{},"l":{"df":1,"docs":{"22":{"tf":1.0}}}},"df":0,"docs":{}}},"df":0,"docs":{},"m":{"df":0,"docs":{},"e":{"b":{"df":0,"docs":{},"u":{"df":0,"docs":{},"f":{"df":0,"docs":{},"f":{"df":1,"docs":{"22":{"tf":1.4142135623730951}}}}}},"df":1,"docs":{"22":{"tf":1.0}}}}},"df":0,"docs":{}},"u":{"df":0,"docs":{},"l":{"df":0,"docs":{},"l":{"df":2,"docs":{"22":{"tf":1.0},"33":{"tf":1.0}}}},"n":{"c":{"df":0,"docs":{},"t":{"df":0,"docs":{},"i":{"df":0,"docs":{},"o":{"df":0,"docs":{},"n":{"df":4,"docs":{"21":{"tf":1.4142135623730951},"25":{"tf":1.0},"30":{"tf":1.4142135623730951},"5":{"tf":2.0}}}}}}},"df":0,"docs":{}}}},"g":{"a":{"df":0,"docs":{},"m":{"df":0,"docs":{},"e":{"df":1,"docs":{"22":{"tf":1.0}}}},"r":{"b":{"a":{"df":0,"docs":{},"g":{"df":1,"docs":{"33":{"tf":1.0}}}},"df":0,"docs":{}},"df":0,"docs":{},"r":{"df":0,"docs":{},"e":{"df":0,"docs":{},"t":{"'":{"df":1,"docs":{"33":{"tf":1.0}}},"df":0,"docs":{}}}}}},"df":1,"docs":{"22":{"tf":1.4142135623730951}},"e":{"df":0,"docs":{},"n":{"df":0,"docs":{},"e":{"df":0,"docs":{},"r":{"df":3,"docs":{"0":{"tf":1.0},"15":{"tf":1.0},"22":{"tf":1.0}}}}},"t":{"_":{"df":0,"docs":{},"r":{"a":{"df":0,"docs":{},"n":{"d":{"df":0,"docs":{},"o":{"df":0,"docs":{},"m":{"_":{"df":0,"docs":{},"u":{"df":0,"docs":{},"s":{"df":0,"docs":{},"i":{"df":0,"docs":{},"z":{"df":0,"docs":{},"e":{"(":{"df":0,"docs":{},"r":{"df":0,"docs":{},"n":{"df":0,"docs":{},"g":{"df":1,"docs":{"22":{"tf":1.0}}}}}},"df":0,"docs":{}}}}}}},"df":0,"docs":{}}}},"df":0,"docs":{}}},"df":0,"docs":{}}},"df":1,"docs":{"34":{"tf":1.0}}}},"i":{"df":0,"docs":{},"v":{"df":0,"docs":{},"e":{"df":1,"docs":{"21":{"tf":1.0}}}}},"l":{"df":0,"docs":{},"o":{"b":{"a":{"df":0,"docs":{},"l":{"df":1,"docs":{"27":{"tf":1.0}}}},"df":1,"docs":{"5":{"tf":1.0}}},"df":0,"docs":{}}},"o":{"df":0,"docs":{},"e":{"df":1,"docs":{"25":{"tf":1.0}}},"p":{".":{"b":{"df":0,"docs":{},"l":{"df":0,"docs":{},"t":{"(":{"b":{"df":0,"docs":{},"l":{"df":0,"docs":{},"t":{"df":0,"docs":{},"o":{"df":0,"docs":{},"p":{":":{":":{"b":{"df":0,"docs":{},"u":{"df":0,"docs":{},"f":{"df":0,"docs":{},"f":{"df":0,"docs":{},"e":{"df":0,"docs":{},"r":{"df":0,"docs":{},"t":{"df":0,"docs":{},"o":{"df":0,"docs":{},"v":{"df":0,"docs":{},"i":{"d":{"df":0,"docs":{},"e":{"df":0,"docs":{},"o":{"df":1,"docs":{"22":{"tf":1.4142135623730951}}}}},"df":0,"docs":{}}}}}}}}}}},"df":0,"docs":{}},"df":0,"docs":{}},"df":0,"docs":{}}}}}},"df":0,"docs":{}},"df":0,"docs":{}}}},"c":{"df":0,"docs":{},"u":{"df":0,"docs":{},"r":{"df":0,"docs":{},"r":{"df":0,"docs":{},"e":{"df":0,"docs":{},"n":{"df":0,"docs":{},"t":{"_":{"df":0,"docs":{},"m":{"df":0,"docs":{},"o":{"d":{"df":0,"docs":{},"e":{"_":{"df":0,"docs":{},"i":{"df":0,"docs":{},"n":{"df":0,"docs":{},"f":{"df":0,"docs":{},"o":{"(":{")":{".":{"df":0,"docs":{},"r":{"df":0,"docs":{},"e":{"df":0,"docs":{},"s":{"df":0,"docs":{},"o":{"df":0,"docs":{},"l":{"df":0,"docs":{},"u":{"df":0,"docs":{},"t":{"df":1,"docs":{"22":{"tf":1.0}}}}}}}}}},"df":0,"docs":{}},"df":0,"docs":{}},"df":0,"docs":{}}}}}},"df":0,"docs":{}}},"df":0,"docs":{}}}},"df":0,"docs":{}}}}}}}},"df":0,"docs":{}},"_":{"df":0,"docs":{},"h":{"a":{"df":0,"docs":{},"n":{"d":{"df":0,"docs":{},"l":{"df":1,"docs":{"22":{"tf":1.0}}}},"df":0,"docs":{}}},"df":0,"docs":{}}},"df":1,"docs":{"22":{"tf":2.0}}}},"p":{"df":0,"docs":{},"t":{"df":4,"docs":{"15":{"tf":1.4142135623730951},"16":{"tf":1.0},"34":{"tf":2.449489742783178},"35":{"tf":1.0}}}},"r":{"a":{"d":{"df":0,"docs":{},"i":{"df":0,"docs":{},"e":{"df":0,"docs":{},"n":{"df":0,"docs":{},"t":{"df":1,"docs":{"22":{"tf":1.0}}}}}}},"df":0,"docs":{},"p":{"df":0,"docs":{},"h":{"df":0,"docs":{},"i":{"c":{"df":1,"docs":{"22":{"tf":2.23606797749979}},"s":{"df":0,"docs":{},"o":{"df":0,"docs":{},"u":{"df":0,"docs":{},"t":{"df":0,"docs":{},"p":{"df":0,"docs":{},"u":{"df":0,"docs":{},"t":{"df":1,"docs":{"22":{"tf":1.7320508075688772}}}}}}}}}},"df":0,"docs":{}}}}},"df":0,"docs":{},"e":{"df":0,"docs":{},"e":{"df":0,"docs":{},"n":{"df":1,"docs":{"22":{"tf":1.0}}}}},"o":{"df":0,"docs":{},"u":{"df":0,"docs":{},"p":{"df":1,"docs":{"27":{"tf":1.0}}}}}},"u":{"df":0,"docs":{},"i":{"d":{"df":5,"docs":{"15":{"tf":1.7320508075688772},"18":{"tf":1.0},"27":{"tf":3.3166247903554},"32":{"tf":1.4142135623730951},"34":{"tf":1.7320508075688772}}},"df":0,"docs":{}}}},"h":{"a":{"df":0,"docs":{},"l":{"df":0,"docs":{},"f":{"df":0,"docs":{},"w":{"a":{"df":0,"docs":{},"y":{"df":1,"docs":{"22":{"tf":1.0}}}},"df":0,"docs":{}}}},"n":{"d":{"df":0,"docs":{},"l":{"df":11,"docs":{"19":{"tf":3.1622776601683795},"20":{"tf":1.0},"21":{"tf":2.449489742783178},"22":{"tf":1.0},"26":{"tf":1.0},"28":{"tf":2.0},"29":{"tf":2.449489742783178},"30":{"tf":1.0},"31":{"tf":1.4142135623730951},"4":{"tf":1.0},"5":{"tf":1.7320508075688772}},"e":{"df":0,"docs":{},"r":{"df":1,"docs":{"5":{"tf":1.0}}}}}},"df":0,"docs":{}},"p":{"df":0,"docs":{},"p":{"df":0,"docs":{},"e":{"df":0,"docs":{},"n":{"df":1,"docs":{"32":{"tf":1.0}}}}}},"r":{"d":{"df":0,"docs":{},"w":{"a":{"df":0,"docs":{},"r":{"df":5,"docs":{"14":{"tf":2.0},"15":{"tf":1.0},"16":{"tf":1.0},"17":{"tf":1.0},"28":{"tf":1.0}}}},"df":0,"docs":{}}},"df":0,"docs":{}}},"df":0,"docs":{},"e":{"a":{"d":{"df":0,"docs":{},"e":{"df":0,"docs":{},"r":{"df":1,"docs":{"34":{"tf":1.4142135623730951}}}}},"df":0,"docs":{}},"df":0,"docs":{},"i":{"df":0,"docs":{},"g":{"df":0,"docs":{},"h":{"df":0,"docs":{},"t":{"df":1,"docs":{"22":{"tf":3.4641016151377544}}}}}},"l":{"df":0,"docs":{},"l":{"df":0,"docs":{},"o":{"df":4,"docs":{"1":{"tf":1.0},"13":{"tf":1.0},"21":{"tf":1.0},"5":{"tf":1.0}}}}},"r":{"df":0,"docs":{},"e":{"'":{"df":2,"docs":{"20":{"tf":1.0},"22":{"tf":1.0}}},"df":4,"docs":{"21":{"tf":1.0},"22":{"tf":1.0},"5":{"tf":1.4142135623730951},"7":{"tf":1.0}}}}},"o":{"df":0,"docs":{},"l":{"d":{"df":1,"docs":{"17":{"tf":1.0}}},"df":0,"docs":{}}},"p":{"df":1,"docs":{"17":{"tf":1.0}}},"u":{"df":0,"docs":{},"g":{"df":0,"docs":{},"e":{"df":1,"docs":{"24":{"tf":1.0}}}},"m":{"a":{"df":0,"docs":{},"n":{"df":1,"docs":{"31":{"tf":1.0}}}},"df":0,"docs":{}}}},"i":{"6":{"8":{"6":{"df":1,"docs":{"7":{"tf":1.0}}},"df":0,"docs":{}},"df":0,"docs":{}},"d":{"df":0,"docs":{},"e":{"df":0,"docs":{},"n":{"df":0,"docs":{},"t":{"df":0,"docs":{},"i":{"df":0,"docs":{},"f":{"df":0,"docs":{},"i":{"df":5,"docs":{"27":{"tf":1.7320508075688772},"31":{"tf":1.0},"32":{"tf":1.0},"34":{"tf":1.0},"35":{"tf":1.0}}}}}}}}},"df":0,"docs":{},"f":{"=":{"df":0,"docs":{},"p":{"df":0,"docs":{},"f":{"df":0,"docs":{},"l":{"a":{"df":0,"docs":{},"s":{"df":0,"docs":{},"h":{",":{"df":0,"docs":{},"f":{"df":0,"docs":{},"o":{"df":0,"docs":{},"r":{"df":0,"docs":{},"m":{"a":{"df":0,"docs":{},"t":{"=":{"df":0,"docs":{},"r":{"a":{"df":0,"docs":{},"w":{",":{"df":0,"docs":{},"r":{"df":0,"docs":{},"e":{"a":{"d":{"df":0,"docs":{},"o":{"df":0,"docs":{},"n":{"df":0,"docs":{},"l":{"df":0,"docs":{},"y":{"=":{"df":0,"docs":{},"o":{"df":0,"docs":{},"n":{",":{"df":0,"docs":{},"f":{"df":0,"docs":{},"i":{"df":0,"docs":{},"l":{"df":0,"docs":{},"e":{"=":{"df":0,"docs":{},"o":{"df":0,"docs":{},"v":{"df":0,"docs":{},"m":{"df":0,"docs":{},"f":{"_":{"c":{"df":0,"docs":{},"o":{"d":{"df":0,"docs":{},"e":{".":{"df":0,"docs":{},"f":{"d":{"df":1,"docs":{"13":{"tf":1.0}}},"df":0,"docs":{}}},"df":0,"docs":{}}},"df":0,"docs":{}}},"df":0,"docs":{},"v":{"a":{"df":0,"docs":{},"r":{"df":0,"docs":{},"s":{".":{"df":0,"docs":{},"f":{"d":{"df":1,"docs":{"13":{"tf":1.0}}},"df":0,"docs":{}}},"df":0,"docs":{}}}},"df":0,"docs":{}}},"df":0,"docs":{}}}}}},"df":0,"docs":{}}}}}},"df":0,"docs":{}}}},"df":0,"docs":{}}}}}},"df":0,"docs":{}},"df":0,"docs":{}}}},"df":0,"docs":{}}},"df":0,"docs":{}}},"df":0,"docs":{}}},"df":0,"docs":{}}}}}},"df":0,"docs":{}}}},"df":0,"docs":{}}}}},"df":0,"docs":{}},"m":{"a":{"df":0,"docs":{},"g":{"df":4,"docs":{"20":{"tf":1.0},"21":{"tf":1.0},"23":{"tf":1.0},"5":{"tf":1.4142135623730951}},"e":{"_":{"d":{"df":0,"docs":{},"e":{"df":0,"docs":{},"v":{"df":0,"docs":{},"i":{"c":{"df":0,"docs":{},"e":{"_":{"df":0,"docs":{},"p":{"a":{"df":0,"docs":{},"t":{"df":0,"docs":{},"h":{"_":{"df":0,"docs":{},"t":{"df":0,"docs":{},"e":{"df":0,"docs":{},"x":{"df":0,"docs":{},"t":{"df":2,"docs":{"20":{"tf":1.4142135623730951},"21":{"tf":1.4142135623730951}}}}}}},"df":2,"docs":{"20":{"tf":1.4142135623730951},"21":{"tf":1.4142135623730951}}}}},"df":0,"docs":{}}},"df":0,"docs":{}}},"df":0,"docs":{}}}}},"df":0,"docs":{},"h":{"a":{"df":0,"docs":{},"n":{"d":{"df":0,"docs":{},"l":{"df":1,"docs":{"21":{"tf":1.0}}}},"df":0,"docs":{}}},"df":0,"docs":{}}},"df":0,"docs":{}}}},"df":0,"docs":{},"i":{"df":0,"docs":{},"t":{"df":1,"docs":{"12":{"tf":1.0}}}},"p":{"df":0,"docs":{},"l":{"df":1,"docs":{"22":{"tf":1.7320508075688772}},"e":{"df":0,"docs":{},"m":{"df":0,"docs":{},"e":{"df":0,"docs":{},"n":{"df":0,"docs":{},"t":{"df":5,"docs":{"10":{"tf":1.0},"15":{"tf":1.7320508075688772},"22":{"tf":1.0},"33":{"tf":1.4142135623730951},"34":{"tf":1.4142135623730951}}}}}}}},"o":{"df":0,"docs":{},"r":{"df":0,"docs":{},"t":{"df":5,"docs":{"24":{"tf":1.0},"27":{"tf":1.0},"33":{"tf":1.0},"35":{"tf":1.0},"5":{"tf":1.0}}}}}}},"n":{"c":{"df":0,"docs":{},"l":{"df":0,"docs":{},"u":{"d":{"df":4,"docs":{"11":{"tf":1.0},"26":{"tf":1.0},"31":{"tf":1.0},"34":{"tf":1.0}}},"df":0,"docs":{}}}},"d":{"df":0,"docs":{},"i":{"c":{"df":2,"docs":{"34":{"tf":1.0},"5":{"tf":1.0}}},"df":0,"docs":{},"v":{"df":0,"docs":{},"i":{"d":{"df":0,"docs":{},"u":{"df":3,"docs":{"21":{"tf":1.0},"30":{"tf":1.0},"34":{"tf":1.0}}}},"df":0,"docs":{}}}}},"df":0,"docs":{},"f":{"df":0,"docs":{},"o":{"!":{"(":{"\"":{"df":0,"docs":{},"h":{"df":0,"docs":{},"e":{"df":0,"docs":{},"l":{"df":0,"docs":{},"l":{"df":0,"docs":{},"o":{"df":2,"docs":{"4":{"tf":1.0},"5":{"tf":1.0}}}}}}},"i":{"df":0,"docs":{},"m":{"a":{"df":0,"docs":{},"g":{"df":2,"docs":{"20":{"tf":1.0},"21":{"tf":1.0}}}},"df":0,"docs":{}}}},"df":0,"docs":{}},"df":0,"docs":{}},"df":2,"docs":{"13":{"tf":1.0},"20":{"tf":1.0}},"r":{"df":0,"docs":{},"m":{"df":3,"docs":{"20":{"tf":1.0},"24":{"tf":1.0},"31":{"tf":1.0}}}}}},"h":{"df":0,"docs":{},"e":{"df":0,"docs":{},"r":{"df":1,"docs":{"30":{"tf":1.0}}}}},"i":{"df":0,"docs":{},"t":{"df":0,"docs":{},"i":{"df":3,"docs":{"22":{"tf":1.0},"25":{"tf":1.4142135623730951},"5":{"tf":1.4142135623730951}}}}},"s":{"df":0,"docs":{},"e":{"df":0,"docs":{},"n":{"df":0,"docs":{},"s":{"df":0,"docs":{},"i":{"df":0,"docs":{},"t":{"df":1,"docs":{"15":{"tf":1.0}}}}}},"r":{"df":0,"docs":{},"t":{"df":1,"docs":{"17":{"tf":1.0}}}}},"i":{"d":{"df":1,"docs":{"5":{"tf":1.0}}},"df":0,"docs":{}},"t":{"a":{"df":0,"docs":{},"l":{"df":4,"docs":{"10":{"tf":2.23606797749979},"11":{"tf":1.0},"3":{"tf":1.7320508075688772},"7":{"tf":1.0}}}},"df":0,"docs":{},"r":{"df":0,"docs":{},"u":{"c":{"df":0,"docs":{},"t":{"df":1,"docs":{"3":{"tf":1.0}}}},"df":0,"docs":{}}}}},"t":{"df":0,"docs":{},"e":{"df":0,"docs":{},"l":{"df":1,"docs":{"35":{"tf":1.0}}},"n":{"d":{"df":1,"docs":{"5":{"tf":1.0}}},"df":0,"docs":{}},"r":{"a":{"c":{"df":0,"docs":{},"t":{"df":1,"docs":{"30":{"tf":1.4142135623730951}}}},"df":0,"docs":{}},"df":0,"docs":{},"f":{"a":{"c":{"df":3,"docs":{"26":{"tf":1.0},"28":{"tf":1.0},"30":{"tf":1.0}}},"df":0,"docs":{}},"df":0,"docs":{}}}},"r":{"df":0,"docs":{},"o":{"d":{"df":0,"docs":{},"u":{"c":{"df":0,"docs":{},"t":{"df":1,"docs":{"0":{"tf":1.7320508075688772}}}},"df":0,"docs":{}}},"df":0,"docs":{}}}}},"o":{"df":1,"docs":{"30":{"tf":1.0}}},"s":{"df":0,"docs":{},"n":{"'":{"df":0,"docs":{},"t":{"df":1,"docs":{"21":{"tf":1.0}}}},"df":0,"docs":{}}},"t":{"'":{"df":1,"docs":{"34":{"tf":1.4142135623730951}}},"a":{"df":0,"docs":{},"n":{"df":0,"docs":{},"i":{"df":0,"docs":{},"u":{"df":0,"docs":{},"m":{"df":1,"docs":{"35":{"tf":1.0}}}}}}},"df":0,"docs":{},"s":{"df":0,"docs":{},"e":{"df":0,"docs":{},"l":{"df":0,"docs":{},"f":{"df":1,"docs":{"10":{"tf":1.0}}}}}}}},"k":{"df":0,"docs":{},"e":{"df":0,"docs":{},"y":{"/":{"df":0,"docs":{},"v":{"a":{"df":0,"docs":{},"l":{"df":0,"docs":{},"u":{"df":1,"docs":{"32":{"tf":1.0}}}}},"df":0,"docs":{}}},"df":2,"docs":{"17":{"tf":1.7320508075688772},"32":{"tf":1.0}}}},"i":{"df":0,"docs":{},"n":{"d":{"df":1,"docs":{"31":{"tf":1.0}}},"df":0,"docs":{}}},"v":{"df":0,"docs":{},"m":{"df":2,"docs":{"10":{"tf":1.0},"13":{"tf":1.0}}}}},"l":{"a":{"df":0,"docs":{},"r":{"df":0,"docs":{},"g":{"df":2,"docs":{"30":{"tf":1.0},"34":{"tf":1.4142135623730951}}}},"u":{"df":0,"docs":{},"n":{"c":{"df":0,"docs":{},"h":{"df":2,"docs":{"13":{"tf":1.7320508075688772},"20":{"tf":1.0}}}},"df":0,"docs":{}}}},"df":0,"docs":{},"e":{"a":{"df":0,"docs":{},"r":{"df":0,"docs":{},"n":{"df":1,"docs":{"30":{"tf":1.0}}}}},"df":0,"docs":{},"n":{"df":0,"docs":{},"g":{"df":0,"docs":{},"t":{"df":0,"docs":{},"h":{"df":1,"docs":{"31":{"tf":1.0}}}}}},"s":{"df":0,"docs":{},"s":{"df":2,"docs":{"21":{"tf":1.0},"29":{"tf":1.0}}}},"t":{"'":{"df":2,"docs":{"21":{"tf":1.0},"5":{"tf":1.0}}},"df":0,"docs":{}},"v":{"df":0,"docs":{},"e":{"df":0,"docs":{},"l":{"df":1,"docs":{"26":{"tf":1.0}}}}}},"i":{"b":{"df":0,"docs":{},"r":{"a":{"df":0,"docs":{},"r":{"df":0,"docs":{},"i":{"df":1,"docs":{"5":{"tf":1.0}}}}},"df":0,"docs":{}}},"df":0,"docs":{},"m":{"df":0,"docs":{},"i":{"df":0,"docs":{},"t":{"df":3,"docs":{"25":{"tf":1.0},"26":{"tf":1.0},"33":{"tf":1.0}}}}},"n":{"df":0,"docs":{},"e":{"a":{"df":0,"docs":{},"r":{"df":1,"docs":{"22":{"tf":1.0}}}},"df":1,"docs":{"5":{"tf":1.4142135623730951}}},"k":{"df":2,"docs":{"23":{"tf":1.0},"24":{"tf":1.0}},"e":{"df":0,"docs":{},"r":{"df":1,"docs":{"23":{"tf":1.0}}}}},"u":{"df":0,"docs":{},"x":{"df":2,"docs":{"16":{"tf":1.4142135623730951},"25":{"tf":1.0}}}}},"t":{"df":0,"docs":{},"t":{"df":0,"docs":{},"l":{"df":2,"docs":{"27":{"tf":1.0},"5":{"tf":1.0}}}}}},"o":{"a":{"d":{"df":3,"docs":{"25":{"tf":1.4142135623730951},"26":{"tf":1.0},"29":{"tf":1.0}},"e":{"d":{"_":{"df":0,"docs":{},"i":{"df":0,"docs":{},"m":{"a":{"df":0,"docs":{},"g":{"df":2,"docs":{"20":{"tf":1.0},"21":{"tf":1.0}},"e":{".":{"df":0,"docs":{},"f":{"df":0,"docs":{},"i":{"df":0,"docs":{},"l":{"df":0,"docs":{},"e":{"_":{"df":0,"docs":{},"p":{"a":{"df":0,"docs":{},"t":{"df":0,"docs":{},"h":{"(":{")":{".":{"df":0,"docs":{},"e":{"df":0,"docs":{},"x":{"df":0,"docs":{},"p":{"df":0,"docs":{},"e":{"c":{"df":0,"docs":{},"t":{"(":{"\"":{"df":0,"docs":{},"f":{"df":0,"docs":{},"i":{"df":0,"docs":{},"l":{"df":2,"docs":{"20":{"tf":1.0},"21":{"tf":1.0}}}}}},"df":0,"docs":{}},"df":0,"docs":{}}},"df":0,"docs":{}}}}}},"df":0,"docs":{}},"df":0,"docs":{}},"df":0,"docs":{}}}},"df":0,"docs":{}}},"df":0,"docs":{}}}}}},"df":0,"docs":{}}}},"df":0,"docs":{}}}},"df":0,"docs":{},"i":{"df":0,"docs":{},"m":{"a":{"df":0,"docs":{},"g":{"df":2,"docs":{"20":{"tf":1.0},"21":{"tf":1.4142135623730951}}}},"df":0,"docs":{}}}},"df":0,"docs":{}}},"df":0,"docs":{}},"c":{"a":{"df":0,"docs":{},"t":{"df":1,"docs":{"11":{"tf":1.0}},"e":{"_":{"df":0,"docs":{},"h":{"a":{"df":0,"docs":{},"n":{"d":{"df":0,"docs":{},"l":{"df":0,"docs":{},"e":{"_":{"b":{"df":0,"docs":{},"u":{"df":0,"docs":{},"f":{"df":0,"docs":{},"f":{"df":2,"docs":{"19":{"tf":1.0},"21":{"tf":1.0}},"e":{"df":0,"docs":{},"r":{"(":{"df":0,"docs":{},"s":{"df":0,"docs":{},"e":{"a":{"df":0,"docs":{},"r":{"c":{"df":0,"docs":{},"h":{"df":0,"docs":{},"t":{"df":0,"docs":{},"y":{"df":0,"docs":{},"p":{"df":0,"docs":{},"e":{":":{":":{"b":{"df":0,"docs":{},"y":{"df":0,"docs":{},"p":{"df":0,"docs":{},"r":{"df":0,"docs":{},"o":{"df":0,"docs":{},"t":{"df":0,"docs":{},"o":{"c":{"df":0,"docs":{},"o":{"df":0,"docs":{},"l":{"(":{"&":{"d":{"df":0,"docs":{},"e":{"df":0,"docs":{},"v":{"df":0,"docs":{},"i":{"c":{"df":0,"docs":{},"e":{"df":0,"docs":{},"p":{"a":{"df":0,"docs":{},"t":{"df":0,"docs":{},"h":{"df":0,"docs":{},"t":{"df":0,"docs":{},"o":{"df":0,"docs":{},"t":{"df":0,"docs":{},"e":{"df":0,"docs":{},"x":{"df":0,"docs":{},"t":{":":{":":{"df":0,"docs":{},"g":{"df":0,"docs":{},"u":{"df":0,"docs":{},"i":{"d":{"df":2,"docs":{"20":{"tf":1.0},"21":{"tf":1.0}}},"df":0,"docs":{}}}}},"df":0,"docs":{}},"df":0,"docs":{}}}}}}}}}},"df":0,"docs":{}}}},"df":0,"docs":{}}}}},"df":0,"docs":{}},"df":0,"docs":{}},"df":0,"docs":{}}}},"df":0,"docs":{}}}}}}}},"df":0,"docs":{}},"df":0,"docs":{}},"df":0,"docs":{}}}}}}},"df":0,"docs":{}}},"df":0,"docs":{}}}},"df":0,"docs":{}}}}}}},"df":0,"docs":{}},"df":0,"docs":{}}}},"df":0,"docs":{}}},"df":0,"docs":{}}},"df":0,"docs":{}}}},"df":0,"docs":{}},"df":0,"docs":{},"g":{":":{":":{"df":0,"docs":{},"i":{"df":0,"docs":{},"n":{"df":0,"docs":{},"f":{"df":0,"docs":{},"o":{"df":3,"docs":{"20":{"tf":1.0},"4":{"tf":1.0},"5":{"tf":1.0}}}}}}},"df":0,"docs":{}},"df":4,"docs":{"13":{"tf":1.0},"21":{"tf":1.0},"4":{"tf":1.0},"5":{"tf":1.0}},"g":{"df":0,"docs":{},"e":{"df":0,"docs":{},"r":{"df":1,"docs":{"5":{"tf":1.0}}}}}},"n":{"df":0,"docs":{},"g":{"df":0,"docs":{},"e":{"df":0,"docs":{},"r":{"df":1,"docs":{"25":{"tf":1.0}}}}}},"o":{"df":0,"docs":{},"k":{"df":6,"docs":{"15":{"tf":1.0},"20":{"tf":1.0},"21":{"tf":1.7320508075688772},"27":{"tf":1.0},"31":{"tf":1.0},"5":{"tf":1.7320508075688772}}},"p":{"df":1,"docs":{"22":{"tf":1.4142135623730951}}}}}},"m":{"a":{"c":{"df":1,"docs":{"17":{"tf":1.0}},"h":{"df":0,"docs":{},"i":{"df":0,"docs":{},"n":{"df":3,"docs":{"10":{"tf":1.0},"17":{"tf":1.0},"33":{"tf":1.0}}}}},"r":{"df":0,"docs":{},"o":{"df":1,"docs":{"36":{"tf":1.0}}}}},"df":0,"docs":{},"i":{"df":0,"docs":{},"n":{"(":{"_":{"df":0,"docs":{},"h":{"a":{"df":0,"docs":{},"n":{"d":{"df":0,"docs":{},"l":{"df":1,"docs":{"22":{"tf":1.0}}}},"df":0,"docs":{}}},"df":0,"docs":{}},"i":{"df":0,"docs":{},"m":{"a":{"df":0,"docs":{},"g":{"df":0,"docs":{},"e":{"_":{"df":0,"docs":{},"h":{"a":{"df":0,"docs":{},"n":{"d":{"df":0,"docs":{},"l":{"df":2,"docs":{"4":{"tf":1.0},"5":{"tf":1.0}}}},"df":0,"docs":{}}},"df":0,"docs":{}}},"df":0,"docs":{}}}},"df":0,"docs":{}}}},"df":0,"docs":{},"h":{"a":{"df":0,"docs":{},"n":{"d":{"df":0,"docs":{},"l":{"df":1,"docs":{"26":{"tf":1.0}}}},"df":0,"docs":{}}},"df":0,"docs":{}},"i":{"df":0,"docs":{},"m":{"a":{"df":0,"docs":{},"g":{"df":0,"docs":{},"e":{"_":{"df":0,"docs":{},"h":{"a":{"df":0,"docs":{},"n":{"d":{"df":0,"docs":{},"l":{"df":1,"docs":{"20":{"tf":1.0}}}},"df":0,"docs":{}}},"df":0,"docs":{}}},"df":0,"docs":{}}}},"df":0,"docs":{}}}},"df":4,"docs":{"21":{"tf":1.4142135623730951},"25":{"tf":1.0},"26":{"tf":1.0},"5":{"tf":2.23606797749979}}}},"k":{"df":0,"docs":{},"e":{"df":2,"docs":{"28":{"tf":1.0},"5":{"tf":1.7320508075688772}}}},"n":{"df":0,"docs":{},"i":{"df":4,"docs":{"15":{"tf":1.0},"30":{"tf":1.4142135623730951},"31":{"tf":1.0},"5":{"tf":1.0}}}},"p":{"df":1,"docs":{"26":{"tf":1.0}}},"r":{"df":0,"docs":{},"k":{"df":1,"docs":{"15":{"tf":1.0}}}},"s":{"df":0,"docs":{},"t":{"df":0,"docs":{},"e":{"df":0,"docs":{},"r":{"df":1,"docs":{"34":{"tf":1.0}}}}}},"t":{"c":{"df":0,"docs":{},"h":{"df":1,"docs":{"34":{"tf":1.0}}}},"df":0,"docs":{},"t":{"df":0,"docs":{},"e":{"df":0,"docs":{},"r":{"df":1,"docs":{"15":{"tf":1.0}}}},"h":{"df":0,"docs":{},"e":{"df":0,"docs":{},"w":{"df":1,"docs":{"33":{"tf":1.0}}}}}}}},"b":{"df":0,"docs":{},"r":{"df":1,"docs":{"34":{"tf":1.7320508075688772}}}},"df":0,"docs":{},"e":{"a":{"df":0,"docs":{},"n":{"df":1,"docs":{"19":{"tf":1.0}}}},"c":{"df":0,"docs":{},"h":{"a":{"df":0,"docs":{},"n":{"df":1,"docs":{"28":{"tf":1.0}}}},"df":0,"docs":{}}},"df":0,"docs":{},"m":{":":{":":{"df":0,"docs":{},"s":{"df":0,"docs":{},"i":{"df":0,"docs":{},"z":{"df":0,"docs":{},"e":{"_":{"df":0,"docs":{},"o":{"df":0,"docs":{},"f":{":":{":":{"<":{"df":0,"docs":{},"u":{"df":0,"docs":{},"s":{"df":1,"docs":{"22":{"tf":1.0}}}}},"df":0,"docs":{}},"df":0,"docs":{}},"df":0,"docs":{}}}},"df":0,"docs":{}}}}}},"df":0,"docs":{}},"df":0,"docs":{},"o":{"df":0,"docs":{},"r":{"df":0,"docs":{},"i":{"df":3,"docs":{"26":{"tf":1.4142135623730951},"33":{"tf":1.7320508075688772},"5":{"tf":1.0}}}}}},"n":{"df":0,"docs":{},"u":{"df":1,"docs":{"17":{"tf":1.0}}}},"s":{"df":0,"docs":{},"s":{"a":{"df":0,"docs":{},"g":{"df":1,"docs":{"13":{"tf":1.0}}}},"df":0,"docs":{}}},"t":{"df":0,"docs":{},"h":{"df":0,"docs":{},"o":{"d":{"df":2,"docs":{"21":{"tf":1.4142135623730951},"22":{"tf":2.23606797749979}}},"df":0,"docs":{}}}}},"i":{"c":{"df":0,"docs":{},"e":{"df":1,"docs":{"31":{"tf":1.0}}}},"df":0,"docs":{},"n":{"df":0,"docs":{},"i":{"df":0,"docs":{},"m":{"df":1,"docs":{"4":{"tf":1.4142135623730951}}}}},"s":{"df":0,"docs":{},"i":{"df":0,"docs":{},"n":{"df":0,"docs":{},"t":{"df":0,"docs":{},"e":{"df":0,"docs":{},"r":{"df":0,"docs":{},"p":{"df":0,"docs":{},"r":{"df":0,"docs":{},"e":{"df":0,"docs":{},"t":{"df":1,"docs":{"32":{"tf":1.0}}}}}}}}}}},"s":{"df":2,"docs":{"20":{"tf":1.0},"21":{"tf":1.0}}}}},"k":{"d":{"df":0,"docs":{},"i":{"df":0,"docs":{},"r":{"df":2,"docs":{"12":{"tf":1.0},"16":{"tf":1.4142135623730951}}}}},"df":0,"docs":{},"f":{"df":0,"docs":{},"s":{".":{"df":0,"docs":{},"f":{"a":{"df":0,"docs":{},"t":{"df":1,"docs":{"16":{"tf":1.0}}}},"df":0,"docs":{}}},"df":0,"docs":{}}}},"o":{"d":{"df":0,"docs":{},"e":{"df":2,"docs":{"19":{"tf":1.0},"25":{"tf":1.7320508075688772}},"r":{"df":0,"docs":{},"n":{"df":1,"docs":{"34":{"tf":1.0}}}}},"u":{"df":0,"docs":{},"l":{"df":2,"docs":{"31":{"tf":1.0},"5":{"tf":1.0}}}}},"df":0,"docs":{},"r":{"df":0,"docs":{},"e":{"df":8,"docs":{"21":{"tf":1.0},"22":{"tf":1.0},"24":{"tf":1.0},"25":{"tf":1.0},"27":{"tf":1.0},"31":{"tf":1.0},"33":{"tf":1.0},"34":{"tf":1.0}}}},"s":{"df":0,"docs":{},"t":{"df":0,"docs":{},"l":{"df":0,"docs":{},"i":{"df":1,"docs":{"25":{"tf":1.0}}}}}},"u":{"df":0,"docs":{},"n":{"df":0,"docs":{},"t":{"df":2,"docs":{"15":{"tf":1.0},"16":{"tf":1.4142135623730951}}}}},"v":{"df":0,"docs":{},"e":{"df":1,"docs":{"22":{"tf":1.0}}}}},"u":{"c":{"df":0,"docs":{},"h":{"df":6,"docs":{"21":{"tf":1.0},"24":{"tf":1.0},"25":{"tf":1.0},"27":{"tf":1.0},"33":{"tf":1.0},"5":{"tf":1.0}}}},"df":0,"docs":{},"l":{"df":0,"docs":{},"t":{"df":0,"docs":{},"i":{"df":0,"docs":{},"p":{"df":0,"docs":{},"l":{"df":1,"docs":{"11":{"tf":1.0}}}}}}},"t":{"df":5,"docs":{"20":{"tf":1.0},"22":{"tf":3.1622776601683795},"26":{"tf":1.0},"4":{"tf":1.0},"5":{"tf":1.0}}}}},"n":{"a":{"df":0,"docs":{},"m":{"df":0,"docs":{},"e":{"df":3,"docs":{"15":{"tf":1.4142135623730951},"32":{"tf":1.4142135623730951},"35":{"tf":1.7320508075688772}},"s":{"df":0,"docs":{},"p":{"a":{"c":{"df":1,"docs":{"32":{"tf":1.0}}},"df":0,"docs":{}},"df":0,"docs":{}}}}}},"df":0,"docs":{},"e":{"a":{"df":0,"docs":{},"r":{"df":1,"docs":{"34":{"tf":1.0}},"l":{"df":0,"docs":{},"i":{"df":1,"docs":{"24":{"tf":1.0}}}}}},"c":{"df":0,"docs":{},"e":{"df":0,"docs":{},"s":{"df":0,"docs":{},"s":{"a":{"df":0,"docs":{},"r":{"df":0,"docs":{},"i":{"df":1,"docs":{"15":{"tf":1.0}}}}},"df":0,"docs":{}}}}},"df":0,"docs":{},"e":{"d":{"df":5,"docs":{"10":{"tf":1.0},"14":{"tf":1.0},"21":{"tf":1.0},"5":{"tf":1.7320508075688772},"7":{"tf":1.0}}},"df":0,"docs":{}},"w":{"(":{"df":0,"docs":{},"w":{"df":0,"docs":{},"i":{"d":{"df":0,"docs":{},"t":{"df":0,"docs":{},"h":{"df":1,"docs":{"22":{"tf":1.4142135623730951}}}}},"df":0,"docs":{}}},"x":{"df":1,"docs":{"22":{"tf":1.0}}}},"=":{"1":{":":{"1":{"df":0,"docs":{},"m":{":":{"1":{"0":{"df":0,"docs":{},"m":{"df":1,"docs":{"16":{"tf":1.0}}}},"df":0,"docs":{}},"df":0,"docs":{}},"df":0,"docs":{}}},"df":0,"docs":{}},"df":0,"docs":{}},"df":0,"docs":{}},"df":3,"docs":{"22":{"tf":1.7320508075688772},"26":{"tf":1.0},"4":{"tf":1.0}}},"x":{"df":0,"docs":{},"t":{"df":2,"docs":{"21":{"tf":1.0},"5":{"tf":1.4142135623730951}}}}},"o":{"_":{"df":0,"docs":{},"m":{"a":{"df":0,"docs":{},"i":{"df":0,"docs":{},"n":{"df":4,"docs":{"20":{"tf":1.0},"22":{"tf":1.0},"4":{"tf":1.0},"5":{"tf":1.4142135623730951}}}}},"df":0,"docs":{}},"s":{"df":0,"docs":{},"t":{"d":{"df":4,"docs":{"20":{"tf":1.0},"22":{"tf":1.0},"4":{"tf":1.0},"5":{"tf":1.4142135623730951}}},"df":0,"docs":{}}}},"df":0,"docs":{},"n":{"_":{"df":0,"docs":{},"v":{"df":0,"docs":{},"o":{"df":0,"docs":{},"l":{"a":{"df":0,"docs":{},"t":{"df":0,"docs":{},"i":{"df":0,"docs":{},"l":{"df":1,"docs":{"33":{"tf":1.0}}}}}},"df":0,"docs":{}}}}},"df":2,"docs":{"33":{"tf":1.7320508075688772},"34":{"tf":1.0}}},"r":{"df":0,"docs":{},"m":{"a":{"df":0,"docs":{},"l":{"df":1,"docs":{"33":{"tf":1.0}}}},"df":0,"docs":{}}},"t":{"df":0,"docs":{},"e":{"df":2,"docs":{"15":{"tf":1.4142135623730951},"31":{"tf":1.0}}},"h":{"df":1,"docs":{"5":{"tf":1.0}}}},"w":{"df":4,"docs":{"12":{"tf":1.0},"13":{"tf":1.0},"21":{"tf":1.0},"5":{"tf":1.0}}}},"u":{"df":0,"docs":{},"l":{"df":0,"docs":{},"l":{"df":1,"docs":{"32":{"tf":1.0}}}},"m":{"b":{"df":0,"docs":{},"e":{"df":0,"docs":{},"r":{"df":4,"docs":{"22":{"tf":1.0},"30":{"tf":1.0},"34":{"tf":1.0},"5":{"tf":1.0}}}}},"df":0,"docs":{},"e":{"df":0,"docs":{},"r":{"df":1,"docs":{"5":{"tf":1.0}}}}}}},"o":{"b":{"df":0,"docs":{},"t":{"a":{"df":0,"docs":{},"i":{"df":0,"docs":{},"n":{"df":1,"docs":{"19":{"tf":1.0}}}}},"df":0,"docs":{}}},"df":0,"docs":{},"k":{"df":2,"docs":{"20":{"tf":1.0},"21":{"tf":1.0}}},"n":{"c":{"df":5,"docs":{"17":{"tf":1.0},"19":{"tf":1.0},"25":{"tf":1.0},"26":{"tf":1.0},"33":{"tf":1.0}}},"df":6,"docs":{"11":{"tf":1.4142135623730951},"17":{"tf":1.4142135623730951},"21":{"tf":1.4142135623730951},"22":{"tf":1.0},"26":{"tf":1.0},"30":{"tf":1.0}}},"p":{"a":{"df":0,"docs":{},"q":{"df":0,"docs":{},"u":{"df":3,"docs":{"27":{"tf":1.0},"29":{"tf":1.0},"31":{"tf":1.0}}}}},"df":0,"docs":{},"e":{"df":0,"docs":{},"n":{"_":{"df":0,"docs":{},"p":{"df":0,"docs":{},"r":{"df":0,"docs":{},"o":{"df":0,"docs":{},"t":{"df":0,"docs":{},"o":{"c":{"df":0,"docs":{},"o":{"df":0,"docs":{},"l":{"_":{"df":0,"docs":{},"e":{"df":0,"docs":{},"x":{"c":{"df":0,"docs":{},"l":{"df":0,"docs":{},"u":{"df":0,"docs":{},"s":{"df":1,"docs":{"21":{"tf":1.4142135623730951}},"i":{"df":0,"docs":{},"v":{"df":0,"docs":{},"e":{":":{":":{"<":{"d":{"df":0,"docs":{},"e":{"df":0,"docs":{},"v":{"df":0,"docs":{},"i":{"c":{"df":0,"docs":{},"e":{"df":0,"docs":{},"p":{"a":{"df":0,"docs":{},"t":{"df":0,"docs":{},"h":{"df":0,"docs":{},"t":{"df":0,"docs":{},"o":{"df":0,"docs":{},"t":{"df":0,"docs":{},"e":{"df":0,"docs":{},"x":{"df":0,"docs":{},"t":{"df":2,"docs":{"20":{"tf":1.0},"21":{"tf":1.0}}}}}}}}}}},"df":0,"docs":{}}}},"df":0,"docs":{}}}}},"df":0,"docs":{},"l":{"df":0,"docs":{},"o":{"a":{"d":{"df":0,"docs":{},"e":{"d":{"df":0,"docs":{},"i":{"df":0,"docs":{},"m":{"a":{"df":0,"docs":{},"g":{"df":0,"docs":{},"e":{">":{"(":{"b":{"df":0,"docs":{},"o":{"df":0,"docs":{},"o":{"df":0,"docs":{},"t":{"_":{"df":0,"docs":{},"s":{"df":0,"docs":{},"e":{"df":0,"docs":{},"r":{"df":0,"docs":{},"v":{"df":0,"docs":{},"i":{"c":{"df":0,"docs":{},"e":{"df":0,"docs":{},"s":{".":{"df":0,"docs":{},"i":{"df":0,"docs":{},"m":{"a":{"df":0,"docs":{},"g":{"df":0,"docs":{},"e":{"_":{"df":0,"docs":{},"h":{"a":{"df":0,"docs":{},"n":{"d":{"df":0,"docs":{},"l":{"df":2,"docs":{"20":{"tf":1.0},"21":{"tf":1.0}}}},"df":0,"docs":{}}},"df":0,"docs":{}}},"df":0,"docs":{}}}},"df":0,"docs":{}}}},"df":0,"docs":{}}}},"df":0,"docs":{}}}}}}},"df":0,"docs":{}}}}},"df":0,"docs":{}},"df":0,"docs":{}},"df":0,"docs":{}}}},"df":0,"docs":{}}}},"df":0,"docs":{}}},"df":0,"docs":{}},"df":0,"docs":{}}}},"df":0,"docs":{}},"df":0,"docs":{}},"df":0,"docs":{}}}}}}}},"df":0,"docs":{}}}},"df":0,"docs":{}}}},"df":0,"docs":{}}}}}}},"df":5,"docs":{"19":{"tf":2.23606797749979},"20":{"tf":1.7320508075688772},"21":{"tf":2.0},"22":{"tf":1.4142135623730951},"29":{"tf":1.0}}},"r":{"df":5,"docs":{"10":{"tf":1.0},"11":{"tf":1.0},"16":{"tf":1.0},"25":{"tf":1.4142135623730951},"29":{"tf":1.0}}}},"t":{"df":0,"docs":{},"i":{"df":0,"docs":{},"o":{"df":0,"docs":{},"n":{"<":{"&":{"df":0,"docs":{},"m":{"df":0,"docs":{},"u":{"df":0,"docs":{},"t":{"df":1,"docs":{"22":{"tf":1.4142135623730951}}}}}},"df":0,"docs":{}},"df":3,"docs":{"17":{"tf":1.0},"24":{"tf":1.0},"26":{"tf":1.0}}}}}}},"r":{"d":{"df":0,"docs":{},"e":{"df":0,"docs":{},"r":{"df":2,"docs":{"27":{"tf":1.0},"7":{"tf":1.0}}}}},"df":0,"docs":{},"i":{"df":0,"docs":{},"g":{"df":0,"docs":{},"i":{"df":0,"docs":{},"n":{"df":1,"docs":{"26":{"tf":1.0}}}}}}},"s":{"df":1,"docs":{"15":{"tf":1.0}}},"u":{"df":0,"docs":{},"t":{"df":2,"docs":{"21":{"tf":1.0},"33":{"tf":1.0}},"p":{"df":0,"docs":{},"u":{"df":0,"docs":{},"t":{"df":3,"docs":{"21":{"tf":1.0},"22":{"tf":1.7320508075688772},"5":{"tf":1.4142135623730951}}}}},"s":{"df":0,"docs":{},"i":{"d":{"df":1,"docs":{"25":{"tf":1.0}}},"df":0,"docs":{}}}}},"v":{"df":0,"docs":{},"e":{"df":0,"docs":{},"r":{"df":2,"docs":{"27":{"tf":1.0},"34":{"tf":1.0}},"v":{"df":0,"docs":{},"i":{"df":0,"docs":{},"e":{"df":0,"docs":{},"w":{"df":1,"docs":{"19":{"tf":1.0}}}}}},"w":{"df":0,"docs":{},"r":{"df":0,"docs":{},"i":{"df":0,"docs":{},"t":{"df":1,"docs":{"32":{"tf":1.0}}}}}}}},"m":{"df":0,"docs":{},"f":{"df":2,"docs":{"10":{"tf":2.0},"11":{"tf":1.7320508075688772}}}}}},"p":{".":{"df":0,"docs":{},"i":{"df":1,"docs":{"22":{"tf":1.7320508075688772}}},"x":{"df":1,"docs":{"22":{"tf":1.4142135623730951}}}},"a":{"c":{"df":0,"docs":{},"k":{"a":{"df":0,"docs":{},"g":{"df":1,"docs":{"11":{"tf":1.4142135623730951}},"e":{"'":{"df":1,"docs":{"11":{"tf":1.0}}},"df":0,"docs":{}}}},"df":1,"docs":{"31":{"tf":1.0}}}},"d":{"df":1,"docs":{"22":{"tf":1.0}}},"df":0,"docs":{},"g":{"df":0,"docs":{},"e":{"df":1,"docs":{"24":{"tf":1.0}}}},"n":{"df":0,"docs":{},"i":{"c":{"df":1,"docs":{"5":{"tf":1.0}}},"df":0,"docs":{}}},"r":{"a":{"df":0,"docs":{},"m":{"df":0,"docs":{},"e":{"df":0,"docs":{},"t":{"df":1,"docs":{"21":{"tf":1.4142135623730951}}}}}},"df":0,"docs":{},"s":{"df":0,"docs":{},"e":{"a":{"b":{"df":0,"docs":{},"l":{"df":1,"docs":{"31":{"tf":1.0}}}},"df":0,"docs":{}},"df":0,"docs":{}}},"t":{"df":2,"docs":{"27":{"tf":1.0},"5":{"tf":1.0}},"i":{"c":{"df":0,"docs":{},"u":{"df":0,"docs":{},"l":{"a":{"df":0,"docs":{},"r":{"df":2,"docs":{"19":{"tf":1.0},"35":{"tf":1.0}}}},"df":0,"docs":{}}}},"df":0,"docs":{},"t":{"df":7,"docs":{"12":{"tf":1.7320508075688772},"15":{"tf":3.3166247903554},"16":{"tf":2.0},"27":{"tf":1.0},"31":{"tf":1.0},"34":{"tf":3.3166247903554},"35":{"tf":2.8284271247461903}}}}}},"s":{"df":0,"docs":{},"s":{"df":2,"docs":{"21":{"tf":1.0},"23":{"tf":1.0}}}},"t":{"df":0,"docs":{},"h":{"/":{"df":0,"docs":{},"t":{"df":0,"docs":{},"o":{"/":{"d":{"df":0,"docs":{},"i":{"df":0,"docs":{},"s":{"df":0,"docs":{},"k":{"_":{"df":0,"docs":{},"p":{"a":{"df":0,"docs":{},"r":{"df":0,"docs":{},"t":{"df":0,"docs":{},"i":{"df":0,"docs":{},"t":{"df":1,"docs":{"16":{"tf":1.4142135623730951}}}}}}},"df":0,"docs":{}}},"df":1,"docs":{"16":{"tf":1.0}}}}}},"df":0,"docs":{},"y":{"df":0,"docs":{},"o":{"df":0,"docs":{},"u":{"df":0,"docs":{},"r":{"df":1,"docs":{"16":{"tf":1.0}}}}}}},"df":0,"docs":{}}}},"df":6,"docs":{"15":{"tf":1.0},"19":{"tf":1.0},"20":{"tf":2.0},"21":{"tf":1.7320508075688772},"31":{"tf":3.4641016151377544},"35":{"tf":1.0}}}},"u":{"df":0,"docs":{},"s":{"df":3,"docs":{"1":{"tf":1.0},"21":{"tf":1.0},"5":{"tf":1.0}}}}},"df":2,"docs":{"12":{"tf":1.0},"22":{"tf":2.0}},"e":{"df":0,"docs":{},"r":{"df":0,"docs":{},"s":{"df":0,"docs":{},"i":{"df":0,"docs":{},"s":{"df":0,"docs":{},"t":{"df":1,"docs":{"33":{"tf":1.0}}}}}}}},"h":{"a":{"df":0,"docs":{},"s":{"df":0,"docs":{},"e":{"df":1,"docs":{"25":{"tf":1.4142135623730951}}}}},"df":0,"docs":{},"y":{"df":0,"docs":{},"s":{"df":0,"docs":{},"i":{"c":{"df":1,"docs":{"29":{"tf":1.0}}},"df":0,"docs":{}}}}},"i":{"df":0,"docs":{},"x":{"df":0,"docs":{},"e":{"df":0,"docs":{},"l":{"(":{"&":{"df":0,"docs":{},"m":{"df":0,"docs":{},"u":{"df":0,"docs":{},"t":{"df":1,"docs":{"22":{"tf":1.4142135623730951}}}}}},"df":0,"docs":{}},".":{"b":{"df":0,"docs":{},"l":{"df":0,"docs":{},"u":{"df":1,"docs":{"22":{"tf":1.4142135623730951}}}}},"df":0,"docs":{},"g":{"df":0,"docs":{},"r":{"df":0,"docs":{},"e":{"df":0,"docs":{},"e":{"df":0,"docs":{},"n":{"df":1,"docs":{"22":{"tf":1.4142135623730951}}}}}}},"r":{"df":1,"docs":{"22":{"tf":1.4142135623730951}}}},"df":1,"docs":{"22":{"tf":3.3166247903554}}}}}},"l":{"a":{"c":{"df":0,"docs":{},"e":{"df":3,"docs":{"21":{"tf":1.0},"27":{"tf":1.0},"30":{"tf":1.0}}}},"df":0,"docs":{},"t":{"df":0,"docs":{},"f":{"df":0,"docs":{},"o":{"df":0,"docs":{},"r":{"df":0,"docs":{},"m":{"df":1,"docs":{"25":{"tf":1.4142135623730951}}}}}}}},"df":0,"docs":{},"u":{"df":1,"docs":{"32":{"tf":1.0}}}},"o":{"df":0,"docs":{},"i":{"df":0,"docs":{},"n":{"df":0,"docs":{},"t":{":":{":":{"df":0,"docs":{},"n":{"df":0,"docs":{},"e":{"df":0,"docs":{},"w":{"(":{"b":{"df":0,"docs":{},"o":{"df":0,"docs":{},"r":{"d":{"df":1,"docs":{"22":{"tf":1.0}}},"df":0,"docs":{}}}},"df":0,"docs":{},"s":{"df":0,"docs":{},"i":{"df":0,"docs":{},"z":{"df":0,"docs":{},"e":{".":{"df":0,"docs":{},"x":{"df":1,"docs":{"22":{"tf":1.7320508075688772}}}},"df":0,"docs":{}}}}},"w":{"df":0,"docs":{},"i":{"d":{"df":0,"docs":{},"t":{"df":0,"docs":{},"h":{"df":1,"docs":{"22":{"tf":1.0}}}}},"df":0,"docs":{}}}},"df":0,"docs":{}}}}},"df":0,"docs":{}},"df":3,"docs":{"22":{"tf":2.0},"26":{"tf":1.0},"5":{"tf":1.0}},"e":{"df":0,"docs":{},"r":{"df":2,"docs":{"29":{"tf":1.0},"31":{"tf":1.0}}}}}}},"o":{"df":0,"docs":{},"r":{"df":1,"docs":{"33":{"tf":1.0}}}},"w":{"df":0,"docs":{},"e":{"df":0,"docs":{},"r":{"df":1,"docs":{"33":{"tf":1.0}}}}}},"r":{"a":{"c":{"df":0,"docs":{},"t":{"df":0,"docs":{},"i":{"c":{"df":1,"docs":{"18":{"tf":1.0}}},"df":0,"docs":{}}}},"df":0,"docs":{}},"df":0,"docs":{},"e":{"c":{"df":0,"docs":{},"i":{"df":0,"docs":{},"s":{"df":1,"docs":{"34":{"tf":1.0}}}}},"df":0,"docs":{},"p":{"a":{"df":0,"docs":{},"r":{"df":2,"docs":{"14":{"tf":1.0},"15":{"tf":1.7320508075688772}}}},"df":0,"docs":{}},"s":{"df":0,"docs":{},"s":{"df":1,"docs":{"17":{"tf":1.7320508075688772}}}},"v":{"df":0,"docs":{},"e":{"df":0,"docs":{},"n":{"df":0,"docs":{},"t":{"df":1,"docs":{"33":{"tf":1.0}}}}},"i":{"df":0,"docs":{},"o":{"df":0,"docs":{},"u":{"df":1,"docs":{"21":{"tf":1.0}}}}}}},"i":{"df":0,"docs":{},"m":{"a":{"df":0,"docs":{},"r":{"df":0,"docs":{},"i":{"df":1,"docs":{"34":{"tf":1.0}}}}},"df":0,"docs":{}},"n":{"df":0,"docs":{},"t":{"_":{"df":0,"docs":{},"i":{"df":0,"docs":{},"m":{"a":{"df":0,"docs":{},"g":{"df":0,"docs":{},"e":{"_":{"df":0,"docs":{},"p":{"a":{"df":0,"docs":{},"t":{"df":0,"docs":{},"h":{"(":{"b":{"df":0,"docs":{},"o":{"df":0,"docs":{},"o":{"df":0,"docs":{},"t":{"_":{"df":0,"docs":{},"s":{"df":0,"docs":{},"e":{"df":0,"docs":{},"r":{"df":0,"docs":{},"v":{"df":0,"docs":{},"i":{"c":{"df":2,"docs":{"20":{"tf":1.0},"21":{"tf":1.0}},"e":{"df":0,"docs":{},"s":{")":{".":{"df":0,"docs":{},"u":{"df":0,"docs":{},"n":{"df":0,"docs":{},"w":{"df":0,"docs":{},"r":{"a":{"df":0,"docs":{},"p":{"df":1,"docs":{"20":{"tf":1.0}}}},"df":0,"docs":{}}}}}},"df":0,"docs":{}},"df":0,"docs":{}}}},"df":0,"docs":{}}}}}}},"df":0,"docs":{}}}}},"df":0,"docs":{}},"df":1,"docs":{"21":{"tf":1.4142135623730951}}}}},"df":0,"docs":{}}},"df":0,"docs":{}}}},"df":0,"docs":{}}}},"df":2,"docs":{"1":{"tf":1.0},"20":{"tf":1.0}}}}},"o":{"c":{"df":0,"docs":{},"e":{"df":0,"docs":{},"s":{"df":0,"docs":{},"s":{"df":2,"docs":{"1":{"tf":1.0},"25":{"tf":1.0}}}}}},"d":{"df":0,"docs":{},"u":{"c":{"df":2,"docs":{"23":{"tf":1.0},"8":{"tf":1.0}}},"df":0,"docs":{}}},"df":0,"docs":{},"g":{"df":0,"docs":{},"r":{"a":{"df":0,"docs":{},"m":{"'":{"df":1,"docs":{"21":{"tf":1.0}}},"df":4,"docs":{"20":{"tf":2.449489742783178},"21":{"tf":1.0},"33":{"tf":1.0},"5":{"tf":1.4142135623730951}}}},"df":0,"docs":{}}},"j":{"df":0,"docs":{},"e":{"c":{"df":0,"docs":{},"t":{"df":1,"docs":{"11":{"tf":1.4142135623730951}}}},"df":0,"docs":{}}},"t":{"df":0,"docs":{},"o":{"c":{"df":0,"docs":{},"o":{"df":0,"docs":{},"l":{"'":{"df":1,"docs":{"22":{"tf":1.0}}},"df":9,"docs":{"19":{"tf":3.3166247903554},"20":{"tf":2.0},"21":{"tf":3.0},"22":{"tf":1.7320508075688772},"26":{"tf":1.0},"27":{"tf":1.0},"28":{"tf":2.0},"29":{"tf":1.4142135623730951},"30":{"tf":3.605551275463989}}}}},"df":0,"docs":{}}},"v":{"df":0,"docs":{},"i":{"d":{"df":8,"docs":{"10":{"tf":1.0},"11":{"tf":1.4142135623730951},"19":{"tf":1.0},"26":{"tf":2.0},"28":{"tf":1.0},"30":{"tf":1.4142135623730951},"32":{"tf":1.0},"5":{"tf":1.4142135623730951}}},"df":0,"docs":{}}}}},"u":{"df":0,"docs":{},"r":{"df":0,"docs":{},"p":{"df":0,"docs":{},"o":{"df":0,"docs":{},"s":{"df":1,"docs":{"34":{"tf":1.0}}}}}},"t":{"df":1,"docs":{"25":{"tf":1.0}}}}},"q":{"df":0,"docs":{},"e":{"df":0,"docs":{},"m":{"df":0,"docs":{},"u":{"df":3,"docs":{"0":{"tf":1.0},"10":{"tf":2.23606797749979},"13":{"tf":1.7320508075688772}}}}},"u":{"df":0,"docs":{},"i":{"c":{"df":0,"docs":{},"k":{"df":1,"docs":{"5":{"tf":1.0}}}},"df":0,"docs":{},"r":{"df":0,"docs":{},"k":{"df":1,"docs":{"33":{"tf":1.0}}}}}}},"r":{"a":{"df":0,"docs":{},"n":{"d":{"df":0,"docs":{},"o":{"df":0,"docs":{},"m":{"df":1,"docs":{"22":{"tf":1.7320508075688772}}}}},"df":0,"docs":{},"g":{"df":1,"docs":{"21":{"tf":1.0}}}},"w":{"df":1,"docs":{"36":{"tf":1.0}}}},"df":1,"docs":{"22":{"tf":1.4142135623730951}},"e":{"a":{"d":{"a":{"b":{"df":0,"docs":{},"l":{"df":1,"docs":{"31":{"tf":1.0}}}},"df":0,"docs":{}},"df":3,"docs":{"21":{"tf":1.0},"30":{"tf":1.0},"33":{"tf":1.0}}},"df":0,"docs":{},"l":{"df":1,"docs":{"14":{"tf":1.0}}}},"b":{"df":0,"docs":{},"o":{"df":0,"docs":{},"o":{"df":0,"docs":{},"t":{"df":1,"docs":{"17":{"tf":1.0}}}}}},"c":{"df":0,"docs":{},"o":{"df":0,"docs":{},"r":{"d":{"df":1,"docs":{"34":{"tf":1.0}}},"df":0,"docs":{}}}},"d":{"df":1,"docs":{"22":{"tf":1.0}},"u":{"df":0,"docs":{},"n":{"d":{"df":1,"docs":{"34":{"tf":1.0}}},"df":0,"docs":{}}}},"df":0,"docs":{},"f":{"df":0,"docs":{},"e":{"df":0,"docs":{},"r":{"df":3,"docs":{"11":{"tf":1.0},"21":{"tf":1.0},"36":{"tf":2.6457513110645907}}}}},"g":{"df":0,"docs":{},"u":{"df":0,"docs":{},"l":{"a":{"df":0,"docs":{},"r":{"df":1,"docs":{"21":{"tf":1.0}}}},"df":0,"docs":{}}}},"l":{"a":{"df":0,"docs":{},"t":{"df":2,"docs":{"24":{"tf":1.0},"33":{"tf":1.0}}}},"df":1,"docs":{"34":{"tf":1.0}},"e":{"df":0,"docs":{},"v":{"df":2,"docs":{"0":{"tf":1.0},"24":{"tf":1.0}}}}},"m":{"df":0,"docs":{},"o":{"df":0,"docs":{},"v":{"df":1,"docs":{"7":{"tf":1.0}}}}},"p":{"df":0,"docs":{},"l":{"a":{"c":{"df":1,"docs":{"4":{"tf":1.0}}},"df":0,"docs":{}},"df":0,"docs":{}},"o":{"df":0,"docs":{},"s":{"df":0,"docs":{},"i":{"df":0,"docs":{},"t":{"df":0,"docs":{},"o":{"df":0,"docs":{},"r":{"df":0,"docs":{},"i":{"df":2,"docs":{"22":{"tf":1.0},"7":{"tf":1.0}}}}}}}}},"r":{"df":0,"docs":{},"e":{"df":0,"docs":{},"s":{"df":4,"docs":{"27":{"tf":1.0},"29":{"tf":1.0},"33":{"tf":1.0},"5":{"tf":1.0}},"e":{"df":0,"docs":{},"n":{"df":0,"docs":{},"t":{"df":2,"docs":{"27":{"tf":1.7320508075688772},"31":{"tf":1.0}}}}}}}}},"q":{"df":0,"docs":{},"u":{"df":0,"docs":{},"i":{"df":0,"docs":{},"r":{"df":2,"docs":{"15":{"tf":1.4142135623730951},"5":{"tf":1.0}}}}}},"s":{"df":0,"docs":{},"e":{"df":0,"docs":{},"t":{"df":1,"docs":{"25":{"tf":1.0}}}},"o":{"df":0,"docs":{},"u":{"df":0,"docs":{},"r":{"c":{"df":3,"docs":{"29":{"tf":1.4142135623730951},"30":{"tf":1.0},"31":{"tf":1.0}}},"df":0,"docs":{}}}},"t":{"df":2,"docs":{"21":{"tf":1.0},"22":{"tf":1.0}}},"u":{"df":0,"docs":{},"l":{"df":0,"docs":{},"t":{"df":3,"docs":{"20":{"tf":1.4142135623730951},"21":{"tf":1.4142135623730951},"22":{"tf":1.7320508075688772}}}}}},"t":{"df":0,"docs":{},"u":{"df":0,"docs":{},"r":{"df":0,"docs":{},"n":{"df":5,"docs":{"19":{"tf":1.0},"21":{"tf":1.0},"25":{"tf":1.0},"26":{"tf":1.0},"5":{"tf":1.4142135623730951}}}}}}},"i":{"df":0,"docs":{},"s":{"c":{"df":1,"docs":{"35":{"tf":1.7320508075688772}}},"df":0,"docs":{}}},"n":{"df":0,"docs":{},"g":{".":{"df":0,"docs":{},"g":{"df":0,"docs":{},"e":{"df":0,"docs":{},"t":{"_":{"df":0,"docs":{},"r":{"df":0,"docs":{},"n":{"df":0,"docs":{},"g":{"(":{"df":0,"docs":{},"n":{"df":0,"docs":{},"o":{"df":0,"docs":{},"n":{"df":1,"docs":{"22":{"tf":1.0}}}}}},"df":0,"docs":{}}}}},"df":0,"docs":{}}}}},"_":{"df":0,"docs":{},"h":{"a":{"df":0,"docs":{},"n":{"d":{"df":0,"docs":{},"l":{"df":1,"docs":{"22":{"tf":1.0}}}},"df":0,"docs":{}}},"df":0,"docs":{}}},"df":1,"docs":{"22":{"tf":1.7320508075688772}}}},"o":{"df":0,"docs":{},"o":{"df":0,"docs":{},"t":{"df":1,"docs":{"7":{"tf":1.0}}}}},"s":{"df":7,"docs":{"0":{"tf":1.0},"21":{"tf":1.0},"22":{"tf":1.0},"24":{"tf":1.0},"25":{"tf":1.0},"27":{"tf":1.0},"30":{"tf":1.4142135623730951}}},"u":{"df":0,"docs":{},"n":{"df":16,"docs":{"1":{"tf":1.0},"10":{"tf":1.4142135623730951},"11":{"tf":1.0},"12":{"tf":1.0},"13":{"tf":1.0},"14":{"tf":2.0},"15":{"tf":1.0},"16":{"tf":1.4142135623730951},"17":{"tf":1.0},"20":{"tf":1.4142135623730951},"21":{"tf":1.0},"22":{"tf":1.4142135623730951},"25":{"tf":1.4142135623730951},"5":{"tf":1.0},"8":{"tf":1.0},"9":{"tf":1.7320508075688772}},"t":{"df":0,"docs":{},"i":{"df":0,"docs":{},"m":{"df":5,"docs":{"23":{"tf":1.0},"25":{"tf":2.0},"26":{"tf":1.0},"30":{"tf":1.0},"33":{"tf":1.0}},"e":{"_":{"a":{"c":{"c":{"df":0,"docs":{},"e":{"df":0,"docs":{},"s":{"df":0,"docs":{},"s":{"df":1,"docs":{"33":{"tf":1.0}}}}}},"df":0,"docs":{}},"df":0,"docs":{}},"df":0,"docs":{}},"df":0,"docs":{},"s":{"df":0,"docs":{},"e":{"df":0,"docs":{},"r":{"df":0,"docs":{},"v":{"df":0,"docs":{},"i":{"c":{"df":2,"docs":{"25":{"tf":1.4142135623730951},"26":{"tf":1.4142135623730951}}},"df":0,"docs":{}}}}}}}}}}},"s":{"df":0,"docs":{},"t":{"'":{"df":1,"docs":{"23":{"tf":1.0}}},"df":6,"docs":{"0":{"tf":1.4142135623730951},"1":{"tf":1.0},"3":{"tf":1.4142135623730951},"36":{"tf":1.0},"5":{"tf":1.7320508075688772},"7":{"tf":1.0}},"f":{"df":0,"docs":{},"l":{"a":{"df":0,"docs":{},"g":{"df":1,"docs":{"23":{"tf":1.4142135623730951}}}},"df":0,"docs":{}}},"u":{"df":0,"docs":{},"p":{"df":1,"docs":{"7":{"tf":1.0}}}}}}}},"s":{"a":{"df":0,"docs":{},"f":{"df":0,"docs":{},"e":{"df":0,"docs":{},"s":{"df":0,"docs":{},"t":{"df":1,"docs":{"19":{"tf":1.0}}}}}},"m":{"df":0,"docs":{},"e":{"df":4,"docs":{"19":{"tf":1.0},"27":{"tf":1.0},"31":{"tf":1.0},"32":{"tf":1.0}}}}},"c":{"df":0,"docs":{},"o":{"df":0,"docs":{},"p":{"df":0,"docs":{},"e":{"d":{"df":0,"docs":{},"p":{"df":0,"docs":{},"r":{"df":0,"docs":{},"o":{"df":0,"docs":{},"t":{"df":0,"docs":{},"o":{"c":{"df":0,"docs":{},"o":{"df":0,"docs":{},"l":{"df":1,"docs":{"19":{"tf":1.0}}}}},"df":0,"docs":{}}}}}}},"df":1,"docs":{"25":{"tf":1.0}}}}},"r":{"df":0,"docs":{},"e":{"df":0,"docs":{},"e":{"df":0,"docs":{},"n":{"df":1,"docs":{"22":{"tf":2.449489742783178}},"s":{"df":0,"docs":{},"h":{"df":0,"docs":{},"o":{"df":0,"docs":{},"t":{"df":1,"docs":{"22":{"tf":1.0}}}}}}}}}}},"df":1,"docs":{"22":{"tf":1.0}},"e":{"c":{"df":0,"docs":{},"o":{"df":0,"docs":{},"n":{"d":{"a":{"df":0,"docs":{},"r":{"df":0,"docs":{},"i":{"df":1,"docs":{"34":{"tf":1.0}}}}},"df":4,"docs":{"1":{"tf":1.0},"13":{"tf":1.0},"21":{"tf":1.0},"5":{"tf":1.0}}},"df":0,"docs":{}}}},"df":0,"docs":{},"e":{"df":6,"docs":{"13":{"tf":1.0},"15":{"tf":1.4142135623730951},"19":{"tf":1.0},"30":{"tf":1.0},"31":{"tf":1.0},"5":{"tf":1.0}}},"l":{"df":0,"docs":{},"e":{"c":{"df":0,"docs":{},"t":{"df":1,"docs":{"17":{"tf":1.0}}}},"df":0,"docs":{}},"f":{".":{"df":0,"docs":{},"h":{"df":0,"docs":{},"e":{"df":0,"docs":{},"i":{"df":0,"docs":{},"g":{"df":0,"docs":{},"h":{"df":0,"docs":{},"t":{"df":1,"docs":{"22":{"tf":1.4142135623730951}}}}}}}},"p":{"df":0,"docs":{},"i":{"df":0,"docs":{},"x":{"df":0,"docs":{},"e":{"df":0,"docs":{},"l":{"df":1,"docs":{"22":{"tf":1.4142135623730951}},"s":{".":{"df":0,"docs":{},"g":{"df":0,"docs":{},"e":{"df":0,"docs":{},"t":{"_":{"df":0,"docs":{},"m":{"df":0,"docs":{},"u":{"df":0,"docs":{},"t":{"(":{"df":0,"docs":{},"i":{"df":1,"docs":{"22":{"tf":1.4142135623730951}}}},"df":0,"docs":{}}}}},"df":0,"docs":{}}}}},"df":0,"docs":{}}}}}}},"w":{"df":0,"docs":{},"i":{"d":{"df":0,"docs":{},"t":{"df":0,"docs":{},"h":{"df":1,"docs":{"22":{"tf":2.0}}}}},"df":0,"docs":{}}}},"df":1,"docs":{"22":{"tf":2.449489742783178}}}},"p":{"a":{"df":0,"docs":{},"r":{"df":1,"docs":{"25":{"tf":1.0}}}},"df":0,"docs":{}},"r":{"df":0,"docs":{},"v":{"df":1,"docs":{"32":{"tf":1.0}},"i":{"c":{"df":9,"docs":{"23":{"tf":1.0},"24":{"tf":1.0},"25":{"tf":1.4142135623730951},"26":{"tf":2.23606797749979},"30":{"tf":1.0},"33":{"tf":1.4142135623730951},"36":{"tf":1.0},"4":{"tf":1.0},"5":{"tf":1.0}}},"df":0,"docs":{}}}},"t":{"df":12,"docs":{"15":{"tf":1.0},"16":{"tf":1.0},"20":{"tf":1.0},"21":{"tf":1.4142135623730951},"22":{"tf":1.0},"23":{"tf":1.0},"26":{"tf":1.0},"3":{"tf":1.0},"33":{"tf":2.0},"35":{"tf":1.0},"5":{"tf":1.0},"7":{"tf":1.0}}},"v":{"df":0,"docs":{},"e":{"df":0,"docs":{},"r":{"df":1,"docs":{"25":{"tf":1.0}}}}}},"g":{"d":{"df":0,"docs":{},"i":{"df":0,"docs":{},"s":{"df":0,"docs":{},"k":{"df":1,"docs":{"16":{"tf":1.0}}}}}},"df":0,"docs":{}},"h":{"df":0,"docs":{},"o":{"df":0,"docs":{},"r":{"df":0,"docs":{},"t":{"df":3,"docs":{"27":{"tf":1.0},"34":{"tf":1.0},"35":{"tf":1.0}},"l":{"df":0,"docs":{},"i":{"df":1,"docs":{"20":{"tf":1.0}}}}}},"w":{"df":1,"docs":{"22":{"tf":1.0}}}}},"i":{"df":0,"docs":{},"e":{"df":0,"docs":{},"r":{"df":0,"docs":{},"p":{"df":0,"docs":{},"i":{"df":0,"docs":{},"n":{"df":0,"docs":{},"s":{"df":0,"docs":{},"k":{"df":0,"docs":{},"i":{"df":1,"docs":{"22":{"tf":1.0}}}}}},"ń":{"df":0,"docs":{},"s":{"df":0,"docs":{},"k":{"df":0,"docs":{},"i":{"df":1,"docs":{"22":{"tf":1.0}}}}}}}}}},"m":{"df":0,"docs":{},"p":{"df":0,"docs":{},"l":{"df":3,"docs":{"1":{"tf":1.0},"22":{"tf":1.0},"5":{"tf":1.0}},"e":{"df":0,"docs":{},"r":{"df":1,"docs":{"5":{"tf":1.0}}}}}}},"n":{"df":0,"docs":{},"g":{"df":0,"docs":{},"l":{"df":1,"docs":{"22":{"tf":1.7320508075688772}}}}},"z":{"df":0,"docs":{},"e":{".":{"df":0,"docs":{},"i":{"df":1,"docs":{"22":{"tf":1.7320508075688772}}}},"df":2,"docs":{"22":{"tf":1.0},"33":{"tf":1.0}}}}},"l":{"df":0,"docs":{},"i":{"c":{"df":0,"docs":{},"e":{"df":1,"docs":{"19":{"tf":1.0}}}},"df":0,"docs":{}}},"o":{"df":0,"docs":{},"m":{"df":0,"docs":{},"e":{"df":0,"docs":{},"t":{"df":0,"docs":{},"h":{"df":2,"docs":{"20":{"tf":1.0},"29":{"tf":1.0}}},"i":{"df":0,"docs":{},"m":{"df":1,"docs":{"35":{"tf":1.0}}}}}}},"u":{"df":0,"docs":{},"r":{"c":{"df":1,"docs":{"24":{"tf":1.0}}},"df":0,"docs":{}}}},"p":{"a":{"c":{"df":0,"docs":{},"e":{"df":1,"docs":{"33":{"tf":1.0}}}},"df":0,"docs":{}},"df":0,"docs":{},"e":{"c":{"df":0,"docs":{},"i":{"a":{"df":0,"docs":{},"l":{"df":3,"docs":{"14":{"tf":1.0},"33":{"tf":1.0},"35":{"tf":1.0}}}},"df":0,"docs":{},"f":{"df":9,"docs":{"15":{"tf":1.4142135623730951},"21":{"tf":1.4142135623730951},"24":{"tf":1.4142135623730951},"25":{"tf":1.4142135623730951},"26":{"tf":1.7320508075688772},"27":{"tf":1.0},"30":{"tf":1.4142135623730951},"34":{"tf":1.0},"36":{"tf":1.0}},"i":{"df":1,"docs":{"7":{"tf":1.0}}}}}},"df":0,"docs":{}}},"r":{"c":{"/":{"df":0,"docs":{},"m":{"a":{"df":0,"docs":{},"i":{"df":0,"docs":{},"n":{".":{"df":0,"docs":{},"r":{"df":1,"docs":{"4":{"tf":1.0}},"s":{"@":{"0":{"1":{"1":{"df":1,"docs":{"13":{"tf":1.0}}},"df":0,"docs":{}},"df":0,"docs":{}},"df":0,"docs":{}},"df":0,"docs":{}}}},"df":0,"docs":{}}}},"df":0,"docs":{}}},"df":1,"docs":{"22":{"tf":1.4142135623730951}}},"df":0,"docs":{}},"t":{"a":{"df":0,"docs":{},"g":{"df":0,"docs":{},"e":{"df":4,"docs":{"25":{"tf":2.6457513110645907},"26":{"tf":1.4142135623730951},"30":{"tf":1.4142135623730951},"33":{"tf":1.0}}}},"l":{"df":0,"docs":{},"l":{"df":1,"docs":{"5":{"tf":1.0}}}},"n":{"d":{"a":{"df":0,"docs":{},"r":{"d":{"df":4,"docs":{"27":{"tf":1.0},"34":{"tf":1.0},"35":{"tf":1.0},"5":{"tf":1.7320508075688772}}},"df":0,"docs":{}}},"df":0,"docs":{}},"df":0,"docs":{}},"r":{"df":0,"docs":{},"t":{"/":{"df":0,"docs":{},"e":{"df":0,"docs":{},"n":{"d":{"df":1,"docs":{"34":{"tf":1.0}}},"df":0,"docs":{}}}},"df":4,"docs":{"16":{"tf":1.0},"21":{"tf":1.4142135623730951},"22":{"tf":1.0},"5":{"tf":1.0}}}},"t":{"df":0,"docs":{},"u":{"df":5,"docs":{"20":{"tf":1.0},"22":{"tf":1.0},"26":{"tf":1.0},"4":{"tf":1.0},"5":{"tf":1.4142135623730951}},"s":{":":{":":{"df":0,"docs":{},"s":{"df":0,"docs":{},"u":{"c":{"c":{"df":0,"docs":{},"e":{"df":0,"docs":{},"s":{"df":0,"docs":{},"s":{"df":4,"docs":{"20":{"tf":1.0},"22":{"tf":1.0},"4":{"tf":1.0},"5":{"tf":1.4142135623730951}}}}}},"df":0,"docs":{}},"df":0,"docs":{}}}},"df":0,"docs":{}},"df":0,"docs":{}}}}},"d":{"df":1,"docs":{"5":{"tf":1.0}}},"df":0,"docs":{},"e":{"df":0,"docs":{},"p":{"df":1,"docs":{"15":{"tf":1.4142135623730951}}}},"i":{"df":0,"docs":{},"l":{"df":0,"docs":{},"l":{"df":3,"docs":{"25":{"tf":1.0},"28":{"tf":1.0},"5":{"tf":1.0}}}}},"o":{"df":0,"docs":{},"r":{"a":{"df":0,"docs":{},"g":{"df":4,"docs":{"11":{"tf":1.0},"26":{"tf":1.0},"32":{"tf":1.0},"33":{"tf":1.4142135623730951}}}},"df":0,"docs":{},"e":{"df":5,"docs":{"19":{"tf":1.0},"22":{"tf":1.0},"31":{"tf":1.0},"32":{"tf":1.0},"33":{"tf":1.7320508075688772}}}}},"r":{"df":0,"docs":{},"i":{"c":{"df":0,"docs":{},"t":{"df":0,"docs":{},"l":{"df":0,"docs":{},"i":{"df":2,"docs":{"15":{"tf":1.4142135623730951},"5":{"tf":1.0}}}}}},"df":0,"docs":{},"n":{"df":0,"docs":{},"g":{"df":1,"docs":{"27":{"tf":1.4142135623730951}}}}},"u":{"c":{"df":0,"docs":{},"t":{"df":1,"docs":{"22":{"tf":1.7320508075688772}},"u":{"df":0,"docs":{},"r":{"df":5,"docs":{"12":{"tf":1.0},"15":{"tf":1.0},"26":{"tf":1.0},"31":{"tf":1.4142135623730951},"34":{"tf":1.0}}}}}},"df":0,"docs":{}}}},"u":{"b":{"df":0,"docs":{},"s":{"df":0,"docs":{},"y":{"df":0,"docs":{},"s":{"df":0,"docs":{},"t":{"df":0,"docs":{},"e":{"df":0,"docs":{},"m":{"df":1,"docs":{"23":{"tf":1.0}}}}}}}}},"c":{"c":{"df":0,"docs":{},"e":{"df":0,"docs":{},"s":{"df":0,"docs":{},"s":{"df":2,"docs":{"21":{"tf":1.0},"5":{"tf":1.0}},"f":{"df":0,"docs":{},"u":{"df":0,"docs":{},"l":{"df":0,"docs":{},"l":{"df":0,"docs":{},"i":{"df":1,"docs":{"5":{"tf":1.0}}}}}}}}}}},"df":0,"docs":{},"h":{"df":5,"docs":{"0":{"tf":1.0},"25":{"tf":1.0},"26":{"tf":1.0},"29":{"tf":1.0},"31":{"tf":1.0}}}},"d":{"df":0,"docs":{},"o":{"df":1,"docs":{"10":{"tf":1.4142135623730951}}}},"df":0,"docs":{},"m":{"df":0,"docs":{},"m":{"a":{"df":0,"docs":{},"r":{"df":1,"docs":{"24":{"tf":1.0}}}},"df":0,"docs":{}}},"p":{"df":0,"docs":{},"p":{"df":0,"docs":{},"o":{"df":0,"docs":{},"r":{"df":0,"docs":{},"t":{"df":4,"docs":{"19":{"tf":1.0},"21":{"tf":1.0},"34":{"tf":1.0},"7":{"tf":1.0}}}}}}}},"y":{"df":0,"docs":{},"s":{"df":0,"docs":{},"t":{"df":0,"docs":{},"e":{"df":0,"docs":{},"m":{"_":{"df":0,"docs":{},"t":{"a":{"b":{"df":0,"docs":{},"l":{"df":0,"docs":{},"e":{")":{".":{"df":0,"docs":{},"u":{"df":0,"docs":{},"n":{"df":0,"docs":{},"w":{"df":0,"docs":{},"r":{"a":{"df":0,"docs":{},"p":{"df":4,"docs":{"20":{"tf":1.0},"22":{"tf":1.0},"4":{"tf":1.0},"5":{"tf":1.0}}}},"df":0,"docs":{}}}}}},"df":0,"docs":{}},".":{"b":{"df":0,"docs":{},"o":{"df":0,"docs":{},"o":{"df":0,"docs":{},"t":{"_":{"df":0,"docs":{},"s":{"df":0,"docs":{},"e":{"df":0,"docs":{},"r":{"df":0,"docs":{},"v":{"df":0,"docs":{},"i":{"c":{"df":2,"docs":{"20":{"tf":1.0},"22":{"tf":1.0}},"e":{"df":0,"docs":{},"s":{"(":{")":{".":{"df":0,"docs":{},"s":{"df":0,"docs":{},"t":{"a":{"df":0,"docs":{},"l":{"df":0,"docs":{},"l":{"(":{"1":{"0":{"_":{"0":{"0":{"0":{"_":{"0":{"0":{"0":{"df":2,"docs":{"4":{"tf":1.0},"5":{"tf":1.0}}},"df":0,"docs":{}},"df":0,"docs":{}},"df":0,"docs":{}},"df":0,"docs":{}},"df":0,"docs":{}},"df":0,"docs":{}},"df":0,"docs":{}},"df":0,"docs":{}},"df":0,"docs":{}},"df":0,"docs":{}},"df":0,"docs":{}}}},"df":0,"docs":{}}}},"df":0,"docs":{}},"df":0,"docs":{}},"df":0,"docs":{}}}},"df":0,"docs":{}}}}}}},"df":0,"docs":{}}}}},"df":0,"docs":{}},"df":0,"docs":{}}}},"df":0,"docs":{}},"df":5,"docs":{"20":{"tf":1.0},"22":{"tf":1.0},"26":{"tf":1.0},"4":{"tf":1.0},"5":{"tf":1.0}}}},"df":13,"docs":{"10":{"tf":1.0},"11":{"tf":1.0},"12":{"tf":1.7320508075688772},"13":{"tf":1.0},"15":{"tf":1.4142135623730951},"16":{"tf":1.0},"20":{"tf":1.0},"25":{"tf":2.449489742783178},"26":{"tf":2.0},"31":{"tf":1.4142135623730951},"34":{"tf":1.0},"35":{"tf":2.8284271247461903},"5":{"tf":1.7320508075688772}},"t":{"a":{"b":{"df":0,"docs":{},"l":{"df":0,"docs":{},"e":{":":{":":{"b":{"df":0,"docs":{},"o":{"df":0,"docs":{},"o":{"df":0,"docs":{},"t":{"_":{"df":0,"docs":{},"s":{"df":0,"docs":{},"e":{"df":0,"docs":{},"r":{"df":0,"docs":{},"v":{"df":0,"docs":{},"i":{"c":{"df":1,"docs":{"26":{"tf":1.0}}},"df":0,"docs":{}}}}}}},"df":0,"docs":{}}}}},"df":0,"docs":{},"e":{"df":0,"docs":{},"x":{"df":0,"docs":{},"i":{"df":0,"docs":{},"t":{"_":{"b":{"df":0,"docs":{},"o":{"df":0,"docs":{},"o":{"df":0,"docs":{},"t":{"_":{"df":0,"docs":{},"s":{"df":0,"docs":{},"e":{"df":0,"docs":{},"r":{"df":0,"docs":{},"v":{"df":0,"docs":{},"i":{"c":{"df":2,"docs":{"25":{"tf":1.0},"26":{"tf":1.0}}},"df":0,"docs":{}}}}}}},"df":0,"docs":{}}}}},"df":0,"docs":{}},"df":0,"docs":{}}}}},"r":{"df":0,"docs":{},"u":{"df":0,"docs":{},"n":{"df":0,"docs":{},"t":{"df":0,"docs":{},"i":{"df":0,"docs":{},"m":{"df":0,"docs":{},"e":{"_":{"df":0,"docs":{},"s":{"df":0,"docs":{},"e":{"df":0,"docs":{},"r":{"df":0,"docs":{},"v":{"df":0,"docs":{},"i":{"c":{"df":1,"docs":{"26":{"tf":1.0}}},"df":0,"docs":{}}}}}}},"df":0,"docs":{}}}}}}}}},"df":0,"docs":{}},"<":{"b":{"df":0,"docs":{},"o":{"df":0,"docs":{},"o":{"df":0,"docs":{},"t":{"df":5,"docs":{"20":{"tf":1.0},"22":{"tf":1.0},"26":{"tf":1.0},"4":{"tf":1.0},"5":{"tf":1.0}}}}}},"df":0,"docs":{}},"df":0,"docs":{}}}},"df":0,"docs":{}},"df":1,"docs":{"26":{"tf":1.0}}}}}}}}},"t":{"a":{"b":{"df":0,"docs":{},"l":{"df":5,"docs":{"15":{"tf":1.0},"25":{"tf":1.7320508075688772},"26":{"tf":3.7416573867739413},"34":{"tf":1.4142135623730951},"5":{"tf":1.4142135623730951}}}},"df":0,"docs":{},"k":{"df":0,"docs":{},"e":{"df":2,"docs":{"21":{"tf":1.4142135623730951},"5":{"tf":1.0}}}},"n":{"df":0,"docs":{},"g":{"df":0,"docs":{},"i":{"b":{"df":0,"docs":{},"l":{"df":1,"docs":{"29":{"tf":1.0}}}},"df":0,"docs":{}}}},"r":{"df":0,"docs":{},"g":{"df":0,"docs":{},"e":{"df":0,"docs":{},"t":{"/":{"df":0,"docs":{},"x":{"8":{"6":{"_":{"6":{"4":{"df":2,"docs":{"12":{"tf":1.0},"8":{"tf":1.0}}},"df":0,"docs":{}},"df":0,"docs":{}},"df":0,"docs":{}},"df":0,"docs":{}},"df":0,"docs":{}}},"df":5,"docs":{"17":{"tf":1.0},"23":{"tf":1.0},"36":{"tf":1.0},"7":{"tf":1.7320508075688772},"8":{"tf":1.0}}}}}}},"df":0,"docs":{},"e":{"df":0,"docs":{},"n":{"df":1,"docs":{"21":{"tf":1.0}}},"r":{"df":0,"docs":{},"m":{"df":1,"docs":{"19":{"tf":1.0}},"i":{"df":0,"docs":{},"n":{"df":1,"docs":{"32":{"tf":1.0}}}}}},"x":{"df":0,"docs":{},"t":{"df":2,"docs":{"21":{"tf":1.0},"31":{"tf":1.0}}}}},"h":{"df":0,"docs":{},"i":{"df":0,"docs":{},"n":{"df":0,"docs":{},"g":{"df":4,"docs":{"20":{"tf":1.0},"21":{"tf":1.0},"31":{"tf":1.0},"5":{"tf":1.7320508075688772}}}}},"o":{"df":0,"docs":{},"u":{"df":0,"docs":{},"g":{"df":0,"docs":{},"h":{"df":1,"docs":{"21":{"tf":1.0}}}}}},"r":{"df":0,"docs":{},"e":{"df":0,"docs":{},"e":{"df":3,"docs":{"23":{"tf":1.0},"27":{"tf":1.0},"7":{"tf":1.0}}}},"o":{"df":0,"docs":{},"u":{"df":0,"docs":{},"g":{"df":0,"docs":{},"h":{"df":4,"docs":{"20":{"tf":1.0},"21":{"tf":1.0},"25":{"tf":1.0},"35":{"tf":1.0}}}}}}}},"i":{"df":0,"docs":{},"m":{"df":0,"docs":{},"e":{"df":5,"docs":{"17":{"tf":1.4142135623730951},"21":{"tf":1.4142135623730951},"22":{"tf":1.0},"26":{"tf":1.0},"5":{"tf":1.0}}}}},"o":{"df":0,"docs":{},"g":{"df":0,"docs":{},"e":{"df":0,"docs":{},"t":{"df":0,"docs":{},"h":{"df":2,"docs":{"21":{"tf":1.0},"28":{"tf":1.0}}}}}},"o":{"df":0,"docs":{},"l":{"c":{"df":0,"docs":{},"h":{"a":{"df":0,"docs":{},"i":{"df":0,"docs":{},"n":{".":{"df":0,"docs":{},"t":{"df":0,"docs":{},"o":{"df":0,"docs":{},"m":{"df":0,"docs":{},"l":{"df":1,"docs":{"7":{"tf":1.0}}}}}}},"df":1,"docs":{"7":{"tf":2.0}}}}},"df":0,"docs":{}}},"df":1,"docs":{"0":{"tf":1.0}}}},"p":{"df":2,"docs":{"26":{"tf":1.0},"5":{"tf":1.0}}}},"r":{"df":0,"docs":{},"e":{"a":{"df":0,"docs":{},"t":{"df":1,"docs":{"27":{"tf":1.0}}}},"df":0,"docs":{}},"i":{"a":{"df":0,"docs":{},"n":{"df":0,"docs":{},"g":{"df":0,"docs":{},"l":{"df":1,"docs":{"22":{"tf":2.0}},"e":{"'":{"df":1,"docs":{"22":{"tf":1.0}}},"[":{"df":0,"docs":{},"g":{"df":0,"docs":{},"e":{"df":0,"docs":{},"t":{"_":{"df":0,"docs":{},"r":{"a":{"df":0,"docs":{},"n":{"d":{"df":0,"docs":{},"o":{"df":0,"docs":{},"m":{"_":{"df":0,"docs":{},"u":{"df":0,"docs":{},"s":{"df":0,"docs":{},"i":{"df":0,"docs":{},"z":{"df":0,"docs":{},"e":{"(":{"&":{"df":0,"docs":{},"m":{"df":0,"docs":{},"u":{"df":0,"docs":{},"t":{"df":1,"docs":{"22":{"tf":1.0}}}}}},"df":0,"docs":{}},"df":0,"docs":{}}}}}}},"df":0,"docs":{}}}},"df":0,"docs":{}}},"df":0,"docs":{}}},"df":0,"docs":{}}}}},"df":0,"docs":{}}}}}},"c":{"df":0,"docs":{},"k":{"df":0,"docs":{},"i":{"df":1,"docs":{"33":{"tf":1.0}}}}},"df":2,"docs":{"34":{"tf":1.0},"35":{"tf":1.0}}}},"u":{"df":0,"docs":{},"r":{"df":0,"docs":{},"n":{"df":1,"docs":{"5":{"tf":1.0}}}},"t":{"df":0,"docs":{},"o":{"df":0,"docs":{},"r":{"df":0,"docs":{},"i":{"df":17,"docs":{"1":{"tf":2.0},"10":{"tf":1.0},"11":{"tf":1.0},"12":{"tf":1.0},"13":{"tf":1.0},"14":{"tf":1.0},"15":{"tf":1.0},"16":{"tf":1.0},"17":{"tf":1.0},"2":{"tf":1.0},"3":{"tf":1.0},"4":{"tf":1.0},"5":{"tf":1.0},"6":{"tf":1.0},"7":{"tf":1.0},"8":{"tf":1.0},"9":{"tf":1.0}}}}}}},"w":{"df":0,"docs":{},"o":{"df":3,"docs":{"10":{"tf":1.0},"11":{"tf":1.0},"5":{"tf":1.0}}}},"y":{"df":0,"docs":{},"p":{"df":0,"docs":{},"e":{"c":{"df":0,"docs":{},"o":{"d":{"df":0,"docs":{},"e":{"=":{"1":{":":{"c":{"1":{"2":{"a":{"7":{"3":{"2":{"8":{"df":1,"docs":{"16":{"tf":1.0}}},"df":0,"docs":{}},"df":0,"docs":{}},"df":0,"docs":{}},"df":0,"docs":{}},"df":0,"docs":{}},"df":0,"docs":{}},"df":0,"docs":{}},"df":0,"docs":{}},"df":0,"docs":{}},"df":0,"docs":{}},"df":0,"docs":{}}},"df":0,"docs":{}}},"df":10,"docs":{"15":{"tf":1.0},"16":{"tf":1.0},"21":{"tf":2.449489742783178},"22":{"tf":1.0},"23":{"tf":1.0},"27":{"tf":1.0},"33":{"tf":1.0},"34":{"tf":1.0},"35":{"tf":1.0},"5":{"tf":1.0}}},"i":{"c":{"df":1,"docs":{"25":{"tf":1.4142135623730951}}},"df":0,"docs":{}}}}},"u":{"8":{"df":1,"docs":{"22":{"tf":1.4142135623730951}}},"b":{"df":0,"docs":{},"u":{"df":0,"docs":{},"n":{"df":0,"docs":{},"t":{"df":0,"docs":{},"u":{"df":1,"docs":{"11":{"tf":1.0}}}}}}},"c":{"df":1,"docs":{"32":{"tf":1.0}}},"df":0,"docs":{},"e":{"df":0,"docs":{},"f":{"df":0,"docs":{},"i":{"'":{"df":1,"docs":{"35":{"tf":1.0}}},"/":{"d":{"df":0,"docs":{},"e":{"b":{"df":0,"docs":{},"u":{"df":0,"docs":{},"g":{"/":{"df":0,"docs":{},"m":{"df":0,"docs":{},"i":{"df":2,"docs":{"12":{"tf":1.0},"8":{"tf":1.0}}}}},"df":0,"docs":{}}}},"df":0,"docs":{}}},"df":0,"docs":{}},":":{":":{"df":0,"docs":{},"p":{"df":0,"docs":{},"r":{"df":0,"docs":{},"e":{"df":0,"docs":{},"l":{"df":0,"docs":{},"u":{"d":{"df":4,"docs":{"20":{"tf":1.0},"22":{"tf":1.0},"4":{"tf":1.0},"5":{"tf":1.4142135623730951}}},"df":0,"docs":{}}}},"o":{"df":0,"docs":{},"t":{"df":0,"docs":{},"o":{":":{":":{"c":{"df":0,"docs":{},"o":{"df":0,"docs":{},"n":{"df":0,"docs":{},"s":{"df":0,"docs":{},"o":{"df":0,"docs":{},"l":{"df":0,"docs":{},"e":{":":{":":{"df":0,"docs":{},"g":{"df":0,"docs":{},"o":{"df":0,"docs":{},"p":{":":{":":{"df":0,"docs":{},"{":{"b":{"df":0,"docs":{},"l":{"df":0,"docs":{},"t":{"df":0,"docs":{},"o":{"df":0,"docs":{},"p":{"df":1,"docs":{"22":{"tf":1.0}}}}}}},"df":0,"docs":{}}},"df":0,"docs":{}},"df":0,"docs":{}}}}},"df":0,"docs":{}},"df":0,"docs":{}}}}}}}},"d":{"df":0,"docs":{},"e":{"df":0,"docs":{},"v":{"df":0,"docs":{},"i":{"c":{"df":0,"docs":{},"e":{"_":{"df":0,"docs":{},"p":{"a":{"df":0,"docs":{},"t":{"df":0,"docs":{},"h":{":":{":":{"df":0,"docs":{},"t":{"df":0,"docs":{},"e":{"df":0,"docs":{},"x":{"df":0,"docs":{},"t":{"df":2,"docs":{"20":{"tf":1.0},"31":{"tf":1.0}}}}}}},"df":0,"docs":{}},"df":1,"docs":{"31":{"tf":1.0}}}}},"df":0,"docs":{}}},"df":0,"docs":{}}},"df":0,"docs":{}}}}},"df":0,"docs":{},"l":{"df":0,"docs":{},"o":{"a":{"d":{"df":0,"docs":{},"e":{"d":{"_":{"df":0,"docs":{},"i":{"df":0,"docs":{},"m":{"a":{"df":0,"docs":{},"g":{"df":0,"docs":{},"e":{":":{":":{"df":0,"docs":{},"l":{"df":0,"docs":{},"o":{"a":{"d":{"df":0,"docs":{},"e":{"d":{"df":0,"docs":{},"i":{"df":0,"docs":{},"m":{"a":{"df":0,"docs":{},"g":{"df":1,"docs":{"20":{"tf":1.0}}}},"df":0,"docs":{}}}},"df":0,"docs":{}}},"df":0,"docs":{}},"df":0,"docs":{}}}},"df":0,"docs":{}},"df":0,"docs":{}}}},"df":0,"docs":{}}}},"df":0,"docs":{}},"df":0,"docs":{}}},"df":0,"docs":{}},"df":0,"docs":{}}},"r":{"df":0,"docs":{},"n":{"df":0,"docs":{},"g":{":":{":":{"df":0,"docs":{},"r":{"df":0,"docs":{},"n":{"df":0,"docs":{},"g":{"df":1,"docs":{"22":{"tf":1.0}}}}}},"df":0,"docs":{}},"df":0,"docs":{}}}}},"df":0,"docs":{}},"df":0,"docs":{}}}}}},"r":{"df":0,"docs":{},"e":{"df":0,"docs":{},"s":{"df":0,"docs":{},"u":{"df":0,"docs":{},"l":{"df":0,"docs":{},"t":{"df":2,"docs":{"21":{"tf":1.0},"22":{"tf":1.0}}}}}}}},"s":{"df":0,"docs":{},"t":{"a":{"df":0,"docs":{},"t":{"df":0,"docs":{},"u":{"df":1,"docs":{"21":{"tf":1.0}}}}},"df":0,"docs":{}}},"t":{"a":{"b":{"df":0,"docs":{},"l":{"df":0,"docs":{},"e":{":":{":":{"b":{"df":0,"docs":{},"o":{"df":0,"docs":{},"o":{"df":0,"docs":{},"t":{":":{":":{"b":{"df":0,"docs":{},"o":{"df":0,"docs":{},"o":{"df":0,"docs":{},"t":{"df":0,"docs":{},"s":{"df":0,"docs":{},"e":{"df":0,"docs":{},"r":{"df":0,"docs":{},"v":{"df":0,"docs":{},"i":{"c":{"df":1,"docs":{"22":{"tf":1.0}}},"df":0,"docs":{}}}}}}}}}},"df":0,"docs":{},"s":{"df":0,"docs":{},"e":{"a":{"df":0,"docs":{},"r":{"c":{"df":0,"docs":{},"h":{"df":0,"docs":{},"t":{"df":0,"docs":{},"y":{"df":0,"docs":{},"p":{"df":1,"docs":{"20":{"tf":1.0}}}}}}},"df":0,"docs":{}}},"df":0,"docs":{}}}},"df":0,"docs":{}},"df":0,"docs":{}}}}},"df":0,"docs":{}},"df":0,"docs":{}},"df":0,"docs":{}}}},"df":0,"docs":{}},"df":0,"docs":{}},"{":{"df":0,"docs":{},"i":{"d":{"df":0,"docs":{},"e":{"df":0,"docs":{},"n":{"df":0,"docs":{},"t":{"df":0,"docs":{},"i":{"df":0,"docs":{},"f":{"df":0,"docs":{},"i":{"df":1,"docs":{"20":{"tf":1.0}}}}}}}}},"df":0,"docs":{}}}},"df":0,"docs":{}},"_":{"df":0,"docs":{},"s":{"df":0,"docs":{},"e":{"df":0,"docs":{},"r":{"df":0,"docs":{},"v":{"df":0,"docs":{},"i":{"c":{"df":1,"docs":{"5":{"tf":1.4142135623730951}},"e":{"df":0,"docs":{},"s":{":":{":":{"df":0,"docs":{},"i":{"df":0,"docs":{},"n":{"df":0,"docs":{},"i":{"df":0,"docs":{},"t":{"(":{"&":{"df":0,"docs":{},"m":{"df":0,"docs":{},"u":{"df":0,"docs":{},"t":{"df":4,"docs":{"20":{"tf":1.0},"22":{"tf":1.0},"4":{"tf":1.0},"5":{"tf":1.0}}}}}},"df":0,"docs":{}},"df":0,"docs":{}}}}}},"df":0,"docs":{}},"df":0,"docs":{}}}},"df":0,"docs":{}}}}}}},"df":25,"docs":{"0":{"tf":2.0},"1":{"tf":1.0},"10":{"tf":1.0},"12":{"tf":1.4142135623730951},"15":{"tf":2.0},"2":{"tf":1.7320508075688772},"21":{"tf":1.4142135623730951},"22":{"tf":1.0},"23":{"tf":1.4142135623730951},"24":{"tf":2.23606797749979},"25":{"tf":2.449489742783178},"26":{"tf":1.7320508075688772},"27":{"tf":1.4142135623730951},"28":{"tf":1.4142135623730951},"3":{"tf":1.0},"30":{"tf":2.0},"32":{"tf":1.0},"33":{"tf":1.4142135623730951},"34":{"tf":1.4142135623730951},"35":{"tf":1.4142135623730951},"36":{"tf":2.449489742783178},"4":{"tf":2.23606797749979},"5":{"tf":3.0},"7":{"tf":2.23606797749979},"8":{"tf":1.4142135623730951}}}}},"n":{"a":{"df":0,"docs":{},"u":{"df":0,"docs":{},"t":{"df":0,"docs":{},"h":{"df":0,"docs":{},"o":{"df":0,"docs":{},"r":{"df":1,"docs":{"33":{"tf":1.0}}}}}}}},"d":{"df":0,"docs":{},"e":{"df":0,"docs":{},"r":{"df":3,"docs":{"11":{"tf":1.0},"15":{"tf":1.0},"35":{"tf":1.0}},"s":{"df":0,"docs":{},"t":{"a":{"df":0,"docs":{},"n":{"d":{"df":1,"docs":{"24":{"tf":1.4142135623730951}}},"df":0,"docs":{}}},"df":0,"docs":{}}}}}},"df":0,"docs":{},"i":{"df":0,"docs":{},"q":{"df":0,"docs":{},"u":{"df":2,"docs":{"27":{"tf":1.0},"31":{"tf":1.0}}}}},"k":{"df":0,"docs":{},"n":{"df":0,"docs":{},"o":{"df":0,"docs":{},"w":{"df":0,"docs":{},"n":{"df":4,"docs":{"12":{"tf":1.0},"36":{"tf":1.0},"7":{"tf":1.7320508075688772},"8":{"tf":1.4142135623730951}}}}}}},"l":{"df":0,"docs":{},"i":{"df":0,"docs":{},"k":{"df":2,"docs":{"31":{"tf":1.0},"34":{"tf":1.0}}}}},"s":{"a":{"df":0,"docs":{},"f":{"df":1,"docs":{"19":{"tf":1.0}}}},"df":0,"docs":{}},"t":{"df":0,"docs":{},"i":{"df":0,"docs":{},"l":{"df":1,"docs":{"25":{"tf":1.0}}}}},"u":{"df":0,"docs":{},"s":{"df":1,"docs":{"22":{"tf":1.0}}}}},"p":{"df":4,"docs":{"21":{"tf":1.0},"3":{"tf":1.0},"5":{"tf":1.0},"7":{"tf":1.0}}},"s":{"b":{"df":3,"docs":{"14":{"tf":1.0},"17":{"tf":2.0},"29":{"tf":1.0}}},"df":17,"docs":{"0":{"tf":1.0},"13":{"tf":1.0},"15":{"tf":1.7320508075688772},"17":{"tf":1.4142135623730951},"19":{"tf":2.8284271247461903},"20":{"tf":2.6457513110645907},"21":{"tf":2.0},"22":{"tf":3.605551275463989},"26":{"tf":1.0},"27":{"tf":1.4142135623730951},"30":{"tf":1.4142135623730951},"31":{"tf":1.0},"33":{"tf":1.4142135623730951},"34":{"tf":1.4142135623730951},"4":{"tf":1.4142135623730951},"5":{"tf":2.449489742783178},"7":{"tf":1.0}},"i":{"df":0,"docs":{},"z":{"df":1,"docs":{"22":{"tf":3.872983346207417}},"e":{")":{".":{"df":0,"docs":{},"u":{"df":0,"docs":{},"n":{"df":0,"docs":{},"w":{"df":0,"docs":{},"r":{"a":{"df":0,"docs":{},"p":{"df":1,"docs":{"22":{"tf":1.0}}}},"df":0,"docs":{}}}}}},"df":0,"docs":{}},":":{":":{"df":0,"docs":{},"f":{"df":0,"docs":{},"r":{"df":0,"docs":{},"o":{"df":0,"docs":{},"m":{"_":{"df":0,"docs":{},"l":{"df":0,"docs":{},"e":{"_":{"b":{"df":0,"docs":{},"y":{"df":0,"docs":{},"t":{"df":0,"docs":{},"e":{"df":0,"docs":{},"s":{"(":{"b":{"df":0,"docs":{},"u":{"df":0,"docs":{},"f":{"df":1,"docs":{"22":{"tf":1.0}}}}},"df":0,"docs":{}},"df":0,"docs":{}}}}}},"df":0,"docs":{}},"df":0,"docs":{}}}},"df":0,"docs":{}}}}}},"df":0,"docs":{}},"df":0,"docs":{}}}},"r":{"/":{"df":0,"docs":{},"s":{"df":0,"docs":{},"h":{"a":{"df":0,"docs":{},"r":{"df":0,"docs":{},"e":{"/":{"df":0,"docs":{},"o":{"df":0,"docs":{},"v":{"df":0,"docs":{},"m":{"df":0,"docs":{},"f":{"/":{"df":0,"docs":{},"o":{"df":0,"docs":{},"v":{"df":0,"docs":{},"m":{"df":0,"docs":{},"f":{"_":{"c":{"df":0,"docs":{},"o":{"d":{"df":0,"docs":{},"e":{".":{"df":0,"docs":{},"f":{"d":{"df":1,"docs":{"11":{"tf":1.0}}},"df":0,"docs":{}}},"df":0,"docs":{}}},"df":0,"docs":{}}},"df":0,"docs":{},"v":{"a":{"df":0,"docs":{},"r":{"df":0,"docs":{},"s":{".":{"df":0,"docs":{},"f":{"d":{"df":1,"docs":{"11":{"tf":1.0}}},"df":0,"docs":{}}},"df":0,"docs":{}}}},"df":0,"docs":{}}},"df":0,"docs":{}}}}}},"df":1,"docs":{"11":{"tf":1.0}}}}}}},"df":0,"docs":{}}}},"df":0,"docs":{}}}},"df":0,"docs":{}}}},"v":{".":{"df":0,"docs":{},"i":{"df":1,"docs":{"22":{"tf":1.0}}},"x":{"df":1,"docs":{"22":{"tf":1.0}}}},"a":{"df":0,"docs":{},"l":{"df":0,"docs":{},"u":{"df":2,"docs":{"22":{"tf":1.0},"23":{"tf":1.0}}}},"r":{"df":1,"docs":{"11":{"tf":1.0}},"i":{"a":{"b":{"df":0,"docs":{},"l":{"df":7,"docs":{"11":{"tf":1.0},"26":{"tf":1.0},"27":{"tf":1.0},"31":{"tf":1.0},"32":{"tf":2.8284271247461903},"33":{"tf":3.0},"35":{"tf":1.0}}}},"df":0,"docs":{},"t":{"df":1,"docs":{"11":{"tf":1.0}}}},"df":2,"docs":{"10":{"tf":1.0},"15":{"tf":1.0}},"o":{"df":0,"docs":{},"u":{"df":2,"docs":{"30":{"tf":1.0},"35":{"tf":1.0}}}}}}},"df":2,"docs":{"22":{"tf":1.0},"35":{"tf":1.7320508075688772}},"e":{"c":{"!":{"[":{"b":{"df":0,"docs":{},"l":{"df":0,"docs":{},"t":{"df":0,"docs":{},"p":{"df":0,"docs":{},"i":{"df":0,"docs":{},"x":{"df":0,"docs":{},"e":{"df":0,"docs":{},"l":{":":{":":{"df":0,"docs":{},"n":{"df":0,"docs":{},"e":{"df":0,"docs":{},"w":{"(":{"0":{"df":1,"docs":{"22":{"tf":1.4142135623730951}}},"df":0,"docs":{}},"df":0,"docs":{}}}}},"df":0,"docs":{}},"df":0,"docs":{}}}}}}}}},"df":0,"docs":{}},"df":0,"docs":{}},"<":{"b":{"df":0,"docs":{},"l":{"df":0,"docs":{},"t":{"df":0,"docs":{},"p":{"df":0,"docs":{},"i":{"df":0,"docs":{},"x":{"df":0,"docs":{},"e":{"df":0,"docs":{},"l":{"df":1,"docs":{"22":{"tf":1.4142135623730951}}}}}}}}}},"df":0,"docs":{}},"df":1,"docs":{"22":{"tf":1.0}}},"df":0,"docs":{},"n":{"d":{"df":0,"docs":{},"o":{"df":0,"docs":{},"r":{"'":{"df":2,"docs":{"32":{"tf":1.0},"33":{"tf":1.0}}},"df":2,"docs":{"17":{"tf":1.0},"32":{"tf":1.7320508075688772}}}}},"df":0,"docs":{}},"r":{"df":0,"docs":{},"i":{"df":5,"docs":{"21":{"tf":1.0},"30":{"tf":1.4142135623730951},"31":{"tf":1.0},"33":{"tf":1.0},"34":{"tf":1.4142135623730951}}},"s":{"df":0,"docs":{},"i":{"df":0,"docs":{},"o":{"df":0,"docs":{},"n":{"df":1,"docs":{"35":{"tf":1.0}}}}}},"t":{"df":0,"docs":{},"e":{"df":0,"docs":{},"x":{"df":1,"docs":{"22":{"tf":1.0}}}},"i":{"c":{"df":1,"docs":{"22":{"tf":1.4142135623730951}}},"df":0,"docs":{}}}}},"i":{"a":{"df":1,"docs":{"33":{"tf":1.0}}},"df":0,"docs":{},"r":{"df":0,"docs":{},"t":{"df":0,"docs":{},"u":{"a":{"df":0,"docs":{},"l":{"df":2,"docs":{"10":{"tf":1.0},"26":{"tf":1.0}}}},"df":0,"docs":{}}}}},"m":{"df":5,"docs":{"10":{"tf":1.0},"11":{"tf":1.0},"12":{"tf":1.0},"13":{"tf":1.7320508075688772},"9":{"tf":1.7320508075688772}}},"o":{"df":0,"docs":{},"l":{"a":{"df":0,"docs":{},"t":{"df":0,"docs":{},"i":{"df":0,"docs":{},"l":{"df":1,"docs":{"33":{"tf":1.7320508075688772}}}}}},"df":0,"docs":{}}},"v":{"df":0,"docs":{},"f":{"a":{"df":0,"docs":{},"t":{"df":1,"docs":{"13":{"tf":1.0}}}},"df":0,"docs":{}}}},"w":{"a":{"df":0,"docs":{},"l":{"df":0,"docs":{},"k":{"df":1,"docs":{"20":{"tf":1.0}},"t":{"df":0,"docs":{},"h":{"df":0,"docs":{},"r":{"df":0,"docs":{},"o":{"df":0,"docs":{},"u":{"df":0,"docs":{},"g":{"df":0,"docs":{},"h":{"df":2,"docs":{"21":{"tf":1.4142135623730951},"5":{"tf":1.4142135623730951}}}}}}}}}}},"n":{"df":0,"docs":{},"t":{"df":1,"docs":{"21":{"tf":1.4142135623730951}}}},"r":{"df":0,"docs":{},"n":{"df":1,"docs":{"16":{"tf":1.0}}}},"y":{"df":2,"docs":{"19":{"tf":1.0},"7":{"tf":1.0}}}},"df":0,"docs":{},"e":{"'":{"df":0,"docs":{},"l":{"df":0,"docs":{},"l":{"df":2,"docs":{"11":{"tf":1.0},"20":{"tf":1.4142135623730951}}}}},"df":0,"docs":{},"l":{"c":{"df":0,"docs":{},"o":{"df":0,"docs":{},"m":{"df":2,"docs":{"0":{"tf":1.0},"30":{"tf":1.0}}}}},"df":0,"docs":{},"l":{"df":1,"docs":{"0":{"tf":1.0}}}}},"h":{"df":0,"docs":{},"o":{"df":0,"docs":{},"l":{"df":0,"docs":{},"e":{"df":2,"docs":{"20":{"tf":1.0},"24":{"tf":1.0}}}}}},"i":{"d":{"df":0,"docs":{},"e":{"df":3,"docs":{"21":{"tf":1.0},"26":{"tf":1.0},"28":{"tf":1.0}}},"t":{"df":0,"docs":{},"h":{"df":1,"docs":{"22":{"tf":2.8284271247461903}}}}},"df":0,"docs":{},"n":{"d":{"df":0,"docs":{},"o":{"df":0,"docs":{},"w":{"df":2,"docs":{"13":{"tf":1.0},"25":{"tf":1.0}}}}},"df":0,"docs":{}},"t":{"df":0,"docs":{},"h":{"df":0,"docs":{},"i":{"df":0,"docs":{},"n":{"df":1,"docs":{"35":{"tf":1.0}}}}}}},"o":{"df":0,"docs":{},"r":{"df":0,"docs":{},"l":{"d":{"df":5,"docs":{"1":{"tf":1.0},"13":{"tf":1.0},"21":{"tf":1.0},"4":{"tf":1.0},"5":{"tf":1.4142135623730951}}},"df":0,"docs":{}}}},"r":{"a":{"df":0,"docs":{},"p":{"df":1,"docs":{"30":{"tf":1.0}}}},"df":0,"docs":{},"i":{"df":0,"docs":{},"t":{"df":0,"docs":{},"e":{"df":3,"docs":{"26":{"tf":1.0},"30":{"tf":1.0},"33":{"tf":1.0}}},"t":{"df":0,"docs":{},"e":{"df":0,"docs":{},"n":{"df":1,"docs":{"33":{"tf":1.0}}}}}}}}},"x":{"8":{"6":{"_":{"6":{"4":{"df":6,"docs":{"1":{"tf":1.0},"13":{"tf":1.0},"15":{"tf":1.0},"35":{"tf":1.0},"7":{"tf":1.0},"8":{"tf":1.0}}},"df":0,"docs":{}},"df":0,"docs":{}},"df":1,"docs":{"8":{"tf":1.0}}},"df":0,"docs":{}},"df":1,"docs":{"22":{"tf":2.8284271247461903}},"t":{"a":{"df":0,"docs":{},"s":{"df":0,"docs":{},"k":{"df":1,"docs":{"22":{"tf":1.0}}}}},"df":0,"docs":{}}},"y":{")":{".":{"df":0,"docs":{},"u":{"df":0,"docs":{},"n":{"df":0,"docs":{},"w":{"df":0,"docs":{},"r":{"a":{"df":0,"docs":{},"p":{"df":1,"docs":{"22":{"tf":1.0}}}},"df":0,"docs":{}}}}}},"df":0,"docs":{}},"df":1,"docs":{"22":{"tf":2.6457513110645907}},"o":{"df":0,"docs":{},"u":{"'":{"df":0,"docs":{},"l":{"df":0,"docs":{},"l":{"df":1,"docs":{"14":{"tf":1.0}}}}},"df":0,"docs":{}}}}}},"title":{"root":{"a":{"df":0,"docs":{},"p":{"df":0,"docs":{},"p":{"df":0,"docs":{},"l":{"df":0,"docs":{},"i":{"c":{"df":3,"docs":{"2":{"tf":1.0},"4":{"tf":1.0},"8":{"tf":1.0}}},"df":0,"docs":{}}}}},"t":{"df":0,"docs":{},"t":{"df":0,"docs":{},"r":{"df":0,"docs":{},"i":{"b":{"df":0,"docs":{},"u":{"df":0,"docs":{},"t":{"df":1,"docs":{"33":{"tf":1.0}}}}},"df":0,"docs":{}}}}}},"b":{"df":0,"docs":{},"o":{"df":0,"docs":{},"o":{"df":0,"docs":{},"t":{"df":2,"docs":{"17":{"tf":1.0},"25":{"tf":1.0}}}}},"u":{"df":0,"docs":{},"i":{"df":0,"docs":{},"l":{"d":{"df":3,"docs":{"23":{"tf":1.0},"6":{"tf":1.0},"8":{"tf":1.0}}},"df":0,"docs":{}}}}},"c":{"df":0,"docs":{},"o":{"df":0,"docs":{},"n":{"c":{"df":0,"docs":{},"e":{"df":0,"docs":{},"p":{"df":0,"docs":{},"t":{"df":1,"docs":{"24":{"tf":1.0}}}}}},"df":0,"docs":{}}},"r":{"df":0,"docs":{},"e":{"a":{"df":0,"docs":{},"t":{"df":2,"docs":{"2":{"tf":1.0},"4":{"tf":1.0}}}},"df":0,"docs":{}}}},"d":{"df":0,"docs":{},"e":{"df":0,"docs":{},"p":{"df":0,"docs":{},"e":{"df":0,"docs":{},"n":{"d":{"df":2,"docs":{"10":{"tf":1.0},"3":{"tf":1.0}}},"df":0,"docs":{}}}},"v":{"df":0,"docs":{},"i":{"c":{"df":1,"docs":{"31":{"tf":1.0}}},"df":0,"docs":{}}}},"r":{"a":{"df":0,"docs":{},"w":{"df":1,"docs":{"22":{"tf":1.0}}}},"df":0,"docs":{},"i":{"df":0,"docs":{},"v":{"df":0,"docs":{},"e":{"df":0,"docs":{},"r":{"df":1,"docs":{"23":{"tf":1.0}}}}}}}},"df":0,"docs":{},"e":{"df":0,"docs":{},"x":{"a":{"df":0,"docs":{},"m":{"df":0,"docs":{},"p":{"df":0,"docs":{},"l":{"df":2,"docs":{"16":{"tf":1.0},"20":{"tf":1.0}}}}}},"df":0,"docs":{}}},"f":{"df":0,"docs":{},"i":{"df":0,"docs":{},"l":{"df":0,"docs":{},"e":{"df":1,"docs":{"11":{"tf":1.0}}}},"r":{"df":0,"docs":{},"m":{"df":0,"docs":{},"w":{"a":{"df":0,"docs":{},"r":{"df":1,"docs":{"11":{"tf":1.0}}}},"df":0,"docs":{}}}}}},"g":{"df":0,"docs":{},"p":{"df":0,"docs":{},"t":{"df":1,"docs":{"34":{"tf":1.0}}}},"u":{"df":0,"docs":{},"i":{"d":{"df":1,"docs":{"27":{"tf":1.0}}},"df":0,"docs":{}}}},"h":{"a":{"df":0,"docs":{},"n":{"d":{"df":0,"docs":{},"l":{"df":2,"docs":{"28":{"tf":1.0},"29":{"tf":1.0}}}},"df":0,"docs":{}},"r":{"d":{"df":0,"docs":{},"w":{"a":{"df":0,"docs":{},"r":{"df":1,"docs":{"14":{"tf":1.0}}}},"df":0,"docs":{}}},"df":0,"docs":{}}},"df":0,"docs":{}},"i":{"df":0,"docs":{},"n":{"df":0,"docs":{},"s":{"df":0,"docs":{},"t":{"a":{"df":0,"docs":{},"l":{"df":2,"docs":{"10":{"tf":1.0},"3":{"tf":1.0}}}},"df":0,"docs":{}}},"t":{"df":0,"docs":{},"r":{"df":0,"docs":{},"o":{"d":{"df":0,"docs":{},"u":{"c":{"df":0,"docs":{},"t":{"df":1,"docs":{"0":{"tf":1.0}}}},"df":0,"docs":{}}},"df":0,"docs":{}}}}}},"l":{"a":{"df":0,"docs":{},"u":{"df":0,"docs":{},"n":{"c":{"df":0,"docs":{},"h":{"df":1,"docs":{"13":{"tf":1.0}}}},"df":0,"docs":{}}}},"df":0,"docs":{},"i":{"df":0,"docs":{},"n":{"df":0,"docs":{},"u":{"df":0,"docs":{},"x":{"df":1,"docs":{"16":{"tf":1.0}}}}}}},"m":{"df":0,"docs":{},"i":{"df":0,"docs":{},"n":{"df":0,"docs":{},"i":{"df":0,"docs":{},"m":{"df":1,"docs":{"4":{"tf":1.0}}}}}}},"p":{"a":{"df":0,"docs":{},"r":{"df":0,"docs":{},"t":{"df":0,"docs":{},"i":{"df":0,"docs":{},"t":{"df":2,"docs":{"12":{"tf":1.0},"35":{"tf":1.0}}}}}},"t":{"df":0,"docs":{},"h":{"df":1,"docs":{"31":{"tf":1.0}}}}},"df":0,"docs":{},"r":{"df":0,"docs":{},"e":{"df":0,"docs":{},"p":{"a":{"df":0,"docs":{},"r":{"df":1,"docs":{"15":{"tf":1.0}}}},"df":0,"docs":{}}},"o":{"df":0,"docs":{},"t":{"df":0,"docs":{},"o":{"c":{"df":0,"docs":{},"o":{"df":0,"docs":{},"l":{"df":3,"docs":{"19":{"tf":1.0},"28":{"tf":1.0},"30":{"tf":1.0}}}}},"df":0,"docs":{}}}}}},"r":{"df":0,"docs":{},"e":{"df":0,"docs":{},"f":{"df":0,"docs":{},"e":{"df":0,"docs":{},"r":{"df":1,"docs":{"36":{"tf":1.0}}}}}},"u":{"df":0,"docs":{},"n":{"df":2,"docs":{"14":{"tf":1.0},"9":{"tf":1.0}}}}},"s":{"c":{"df":0,"docs":{},"r":{"df":0,"docs":{},"e":{"df":0,"docs":{},"e":{"df":0,"docs":{},"n":{"df":1,"docs":{"22":{"tf":1.0}}}}}}},"df":0,"docs":{},"t":{"a":{"df":0,"docs":{},"g":{"df":0,"docs":{},"e":{"df":1,"docs":{"25":{"tf":1.0}}}}},"df":0,"docs":{}},"y":{"df":0,"docs":{},"s":{"df":0,"docs":{},"t":{"df":0,"docs":{},"e":{"df":0,"docs":{},"m":{"df":2,"docs":{"12":{"tf":1.0},"35":{"tf":1.0}}}}}}}},"t":{"a":{"b":{"df":0,"docs":{},"l":{"df":1,"docs":{"26":{"tf":1.0}}}},"df":0,"docs":{}},"df":0,"docs":{},"o":{"df":0,"docs":{},"o":{"df":0,"docs":{},"l":{"c":{"df":0,"docs":{},"h":{"a":{"df":0,"docs":{},"i":{"df":0,"docs":{},"n":{"df":1,"docs":{"7":{"tf":1.0}}}}},"df":0,"docs":{}}},"df":0,"docs":{}}}},"u":{"df":0,"docs":{},"t":{"df":0,"docs":{},"o":{"df":0,"docs":{},"r":{"df":0,"docs":{},"i":{"df":1,"docs":{"1":{"tf":1.0}}}}}}}},"u":{"df":0,"docs":{},"e":{"df":0,"docs":{},"f":{"df":0,"docs":{},"i":{"df":1,"docs":{"2":{"tf":1.0}}}}},"s":{"b":{"df":1,"docs":{"17":{"tf":1.0}}},"df":1,"docs":{"19":{"tf":1.0}}}},"v":{"a":{"df":0,"docs":{},"r":{"df":0,"docs":{},"i":{"a":{"b":{"df":0,"docs":{},"l":{"df":1,"docs":{"32":{"tf":1.0}}}},"df":0,"docs":{}},"df":0,"docs":{}}}},"df":0,"docs":{},"m":{"df":2,"docs":{"13":{"tf":1.0},"9":{"tf":1.0}}}},"w":{"a":{"df":0,"docs":{},"l":{"df":0,"docs":{},"k":{"df":0,"docs":{},"t":{"df":0,"docs":{},"h":{"df":0,"docs":{},"r":{"df":0,"docs":{},"o":{"df":0,"docs":{},"u":{"df":0,"docs":{},"g":{"df":0,"docs":{},"h":{"df":2,"docs":{"21":{"tf":1.0},"5":{"tf":1.0}}}}}}}}}}}},"df":0,"docs":{}}}}},"lang":"English","pipeline":["trimmer","stopWordFilter","stemmer"],"ref":"id","version":"0.9.5"},"results_options":{"limit_results":30,"teaser_word_count":30},"search_options":{"bool":"OR","expand":true,"fields":{"body":{"boost":1},"breadcrumbs":{"boost":1},"title":{"boost":2}}}} \ No newline at end of file diff --git a/HEAD/tomorrow-night.css b/HEAD/tomorrow-night.css new file mode 100644 index 000000000..5b4aca77c --- /dev/null +++ b/HEAD/tomorrow-night.css @@ -0,0 +1,102 @@ +/* Tomorrow Night Theme */ +/* http://jmblog.github.com/color-themes-for-google-code-highlightjs */ +/* Original theme - https://github.com/chriskempson/tomorrow-theme */ +/* http://jmblog.github.com/color-themes-for-google-code-highlightjs */ + +/* Tomorrow Comment */ +.hljs-comment { + color: #969896; +} + +/* Tomorrow Red */ +.hljs-variable, +.hljs-attribute, +.hljs-tag, +.hljs-regexp, +.ruby .hljs-constant, +.xml .hljs-tag .hljs-title, +.xml .hljs-pi, +.xml .hljs-doctype, +.html .hljs-doctype, +.css .hljs-id, +.css .hljs-class, +.css .hljs-pseudo { + color: #cc6666; +} + +/* Tomorrow Orange */ +.hljs-number, +.hljs-preprocessor, +.hljs-pragma, +.hljs-built_in, +.hljs-literal, +.hljs-params, +.hljs-constant { + color: #de935f; +} + +/* Tomorrow Yellow */ +.ruby .hljs-class .hljs-title, +.css .hljs-rule .hljs-attribute { + color: #f0c674; +} + +/* Tomorrow Green */ +.hljs-string, +.hljs-value, +.hljs-inheritance, +.hljs-header, +.hljs-name, +.ruby .hljs-symbol, +.xml .hljs-cdata { + color: #b5bd68; +} + +/* Tomorrow Aqua */ +.hljs-title, +.css .hljs-hexcolor { + color: #8abeb7; +} + +/* Tomorrow Blue */ +.hljs-function, +.python .hljs-decorator, +.python .hljs-title, +.ruby .hljs-function .hljs-title, +.ruby .hljs-title .hljs-keyword, +.perl .hljs-sub, +.javascript .hljs-title, +.coffeescript .hljs-title { + color: #81a2be; +} + +/* Tomorrow Purple */ +.hljs-keyword, +.javascript .hljs-function { + color: #b294bb; +} + +.hljs { + display: block; + overflow-x: auto; + background: #1d1f21; + color: #c5c8c6; +} + +.coffeescript .javascript, +.javascript .xml, +.tex .hljs-formula, +.xml .javascript, +.xml .vbscript, +.xml .css, +.xml .hljs-cdata { + opacity: 0.5; +} + +.hljs-addition { + color: #718c00; +} + +.hljs-deletion { + color: #c82829; +} diff --git a/HEAD/tutorial/app.html b/HEAD/tutorial/app.html new file mode 100644 index 000000000..180e2d2a8 --- /dev/null +++ b/HEAD/tutorial/app.html @@ -0,0 +1,262 @@ + + + + + + Creating a UEFI Application - Rust UEFI Book + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ +
+ + + + + + + +
+
+

Creating a UEFI application

+

Install dependencies

+

Follow the Rust installation instructions to set up Rust.

+

Create a minimal application

+

Create an empty application and change to that directory:

+
cargo new my-uefi-app
+cd my-uefi-app
+
+

Add a few dependencies:

+
cargo add log uefi uefi-services
+
+

Replace the contents of src/main.rs with this:

+
#![no_main]
+#![no_std]
+
+use log::info;
+use uefi::prelude::*;
+
+#[entry]
+fn main(_image_handle: Handle, mut system_table: SystemTable<Boot>) -> Status {
+    uefi_services::init(&mut system_table).unwrap();
+    info!("Hello world!");
+    system_table.boot_services().stall(10_000_000);
+    Status::SUCCESS
+}
+
+

Walkthrough

+

Let's look a quick look at what each part of the program is doing, +starting with the #![...] lines at the top:

+
#![allow(unused)]
+#![no_main]
+#![no_std]
+fn main() {
+}
+
+

This is some boilerplate that all Rust UEFI applications will +need. no_main is needed because the UEFI application entry point is +different from the standard Rust main function. no_std is needed to +turn off the std library; the core and alloc crates can still be +used.

+

Next up are some use lines. Nothing too exciting here; the +uefi::prelude module is intended to be glob-imported, and exports a +number of commonly-used types.

+
#![allow(unused)]
+fn main() {
+use log::info;
+use uefi::prelude::*;
+}
+
+

Now we get to the UEFI application main function, and here things look +a little different from a standard Rust program.

+
#[entry]
+fn main(_image_handle: Handle, mut system_table: SystemTable<Boot>) -> Status {
+
+

The main function in a Uefi application always takes two arguments, +the image handle and the system table. The image handle represents the +currently-running executable, and the system table provides access to +many different UEFI services. The main function returns a Status, +which is essentially a numeric error (or success) code defined by UEFI.

+

The first thing we do inside of main is initialize uefi_services:

+
#![allow(unused)]
+fn main() {
+    uefi_services::init(&mut system_table).unwrap();
+}
+
+

The uefi_services crate is not strictly required to make a UEFI +application with the uefi crate, but it makes things much simpler by +setting a simple memory allocator, initializing the logger, and +providing a panic handler.

+

Next we use the standard log crate to output "Hello world!". Then we +call stall to make the system pause for 10 seconds. This just ensures +you have enough time to see the output.

+
#![allow(unused)]
+fn main() {
+    info!("Hello world!");
+    system_table.boot_services().stall(10_000_000);
+}
+
+

Finally we return Status::SUCCESS indicating that everything completed +successfully:

+
#![allow(unused)]
+fn main() {
+    Status::SUCCESS
+}
+}
+
+ +
+ + +
+
+ + + +
+ + + + + + + + + + + + diff --git a/HEAD/tutorial/building.html b/HEAD/tutorial/building.html new file mode 100644 index 000000000..afbcfec76 --- /dev/null +++ b/HEAD/tutorial/building.html @@ -0,0 +1,192 @@ + + + + + + Building - Rust UEFI Book + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ +
+ + + + + + + +
+
+

Building

+

Toolchain

+

In order to compile for UEFI, an appropriate target must be installed. The +easiest way to set this up is using a rustup toolchain file. In the root of +your repository, add rust-toolchain.toml:

+
[toolchain]
+targets = ["aarch64-unknown-uefi", "i686-unknown-uefi", "x86_64-unknown-uefi"]
+
+

Here we have specified all three of the currently-supported UEFI targets; you +can remove some if you don't need them.

+

Build the application

+

Run this command to build the application:

+
cargo build --target x86_64-unknown-uefi
+
+

This will produce an x86-64 executable: +target/x86_64-unknown-uefi/debug/my-uefi-app.efi.

+ +
+ + +
+
+ + + +
+ + + + + + + + + + + + diff --git a/HEAD/tutorial/hardware.html b/HEAD/tutorial/hardware.html new file mode 100644 index 000000000..76e2b6a25 --- /dev/null +++ b/HEAD/tutorial/hardware.html @@ -0,0 +1,233 @@ + + + + + + Running on Hardware - Rust UEFI Book + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ +
+ + + + + + + +
+
+

Running on Hardware

+

To run on real hardware you'll need a specially-prepared USB drive.

+

Preparation

+

The general steps to prepare the drive are:

+
    +
  1. Partition the drive using GPT.
  2. +
  3. Create a partition.
  4. +
  5. Set the partition type GUID to +C12A7328-F81F-11D2-BA4B-00A0C93EC93B. That marks it as an EFI +System partition. (On many UEFI implementations this is not strictly +necessary, see note below.)
  6. +
  7. Format the partition as FAT.
  8. +
  9. Mount the partition.
  10. +
  11. Create the directory path EFI/BOOT on the partition. (FAT is case +insensitive, so capitalization doesn't matter.)
  12. +
  13. Copy your EFI application to a file under EFI/BOOT. The file name +is specific to the architecture. For example, on x86_64 the file name +must be BOOTX64.EFI. See the boot files table for other +architectures.
  14. +
+

The details of exactly how to do these steps will vary depending on your OS.

+

Note that most UEFI implementations do not strictly require GPT +partitioning or the EFI System partition GUID; they will look for any +FAT partition with the appropriate directory structure. This is not +required however; the UEFI Specification says "UEFI implementations may +allow the use of conforming FAT partitions which do not use the ESP +GUID."

+

Example on Linux

+

Warning: these operations are destructive! Do not run these commands +on a disk if you care about the data it contains.

+
# Create the GPT, create a 9MB partition starting at 1MB, and set the
+# partition type to EFI System.
+sgdisk \
+    --clear \
+    --new=1:1M:10M \
+    --typecode=1:C12A7328-F81F-11D2-BA4B-00A0C93EC93B \
+    /path/to/disk
+
+# Format the partition as FAT.
+mkfs.fat /path/to/disk_partition
+
+# Mount the partition.
+mkdir esp
+mount /path/to/disk_partition esp
+
+# Create the boot directory.
+mkdir esp/EFI/BOOT
+
+# Copy in the boot executable.
+cp /path/to/your-executable.efi esp/EFI/BOOT/BOOTX64.EFI
+
+

Booting the USB

+

Insert the USB into the target computer. Reboot the machine, then press +the one-time boot key. Which key to press depends on the vendor. For +example, Dell uses F12, HP uses F9, and on Macs you hold down the Option +key.

+

Once the one-time boot menu appears, select your USB drive and press enter.

+ +
+ + +
+
+ + + +
+ + + + + + + + + + + + diff --git a/HEAD/tutorial/introduction.html b/HEAD/tutorial/introduction.html new file mode 100644 index 000000000..47828d87a --- /dev/null +++ b/HEAD/tutorial/introduction.html @@ -0,0 +1,180 @@ + + + + + + Tutorial - Rust UEFI Book + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ +
+ + + + + + + +
+
+

Tutorial

+

This tutorial describes the process of creating and running a simple +x86_64 UEFI application in Rust. The application will print "Hello +World", pause for 10 seconds, then exit.

+ +
+ + +
+
+ + + +
+ + + + + + + + + + + + diff --git a/HEAD/tutorial/vm.html b/HEAD/tutorial/vm.html new file mode 100644 index 000000000..b18a71a21 --- /dev/null +++ b/HEAD/tutorial/vm.html @@ -0,0 +1,219 @@ + + + + + + Running in a VM - Rust UEFI Book + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ +
+ + + + + + + +
+
+

Running in a VM

+

Install dependencies

+

Two dependencies are needed: QEMU, which implements the virtual +machine itself, and OVMF, which provides UEFI firmware that QEMU can +run.

+

The details of how to install QEMU and OVMF will vary depending on your +operating system.

+

Debian/Ubuntu:

+
sudo apt-get install qemu ovmf
+
+

Fedora:

+
sudo dnf install qemu-kvm edk2-ovmf
+
+

Firmware files

+

The OVMF package provides two firmware files, one for the executable +code and one for variable storage. (The package may provide multiple +variations of these files; refer to the package's documentation for +details of the files it includes.)

+

For ease of access we'll copy the OVMF code and vars files to the +project directory. The location where OVMF is installed depends on your +operating system; for Debian, Ubuntu and Fedora the files are under +/usr/share/OVMF.

+

Copy the files to your project directory:

+
cp /usr/share/OVMF/OVMF_CODE.fd .
+cp /usr/share/OVMF/OVMF_VARS.fd .
+
+

System partition

+

Now create a directory structure containing the executable to imitate a +UEFI System Partition:

+
mkdir -p esp/efi/boot
+cp target/x86_64-unknown-uefi/debug/my-uefi-app.efi esp/efi/boot/bootx64.efi
+
+

Launch the VM

+

Now we can launch QEMU, using VVFAT to access the esp directory created above.

+
qemu-system-x86_64 -enable-kvm \
+    -drive if=pflash,format=raw,readonly=on,file=OVMF_CODE.fd \
+    -drive if=pflash,format=raw,readonly=on,file=OVMF_VARS.fd \
+    -drive format=raw,file=fat:rw:esp
+
+

A QEMU window should appear, and after a few seconds you should see the +log message:

+
[ INFO]:  src/main.rs@011: Hello world!
+
+ +
+ + +
+
+ + + +
+ + + + + + + + + + + + diff --git a/LICENSE b/LICENSE new file mode 100644 index 000000000..a612ad981 --- /dev/null +++ b/LICENSE @@ -0,0 +1,373 @@ +Mozilla Public License Version 2.0 +================================== + +1. Definitions +-------------- + +1.1. "Contributor" + means each individual or legal entity that creates, contributes to + the creation of, or owns Covered Software. + +1.2. "Contributor Version" + means the combination of the Contributions of others (if any) used + by a Contributor and that particular Contributor's Contribution. + +1.3. "Contribution" + means Covered Software of a particular Contributor. + +1.4. "Covered Software" + means Source Code Form to which the initial Contributor has attached + the notice in Exhibit A, the Executable Form of such Source Code + Form, and Modifications of such Source Code Form, in each case + including portions thereof. + +1.5. "Incompatible With Secondary Licenses" + means + + (a) that the initial Contributor has attached the notice described + in Exhibit B to the Covered Software; or + + (b) that the Covered Software was made available under the terms of + version 1.1 or earlier of the License, but not also under the + terms of a Secondary License. + +1.6. "Executable Form" + means any form of the work other than Source Code Form. + +1.7. "Larger Work" + means a work that combines Covered Software with other material, in + a separate file or files, that is not Covered Software. + +1.8. "License" + means this document. + +1.9. "Licensable" + means having the right to grant, to the maximum extent possible, + whether at the time of the initial grant or subsequently, any and + all of the rights conveyed by this License. + +1.10. "Modifications" + means any of the following: + + (a) any file in Source Code Form that results from an addition to, + deletion from, or modification of the contents of Covered + Software; or + + (b) any new file in Source Code Form that contains any Covered + Software. + +1.11. "Patent Claims" of a Contributor + means any patent claim(s), including without limitation, method, + process, and apparatus claims, in any patent Licensable by such + Contributor that would be infringed, but for the grant of the + License, by the making, using, selling, offering for sale, having + made, import, or transfer of either its Contributions or its + Contributor Version. + +1.12. "Secondary License" + means either the GNU General Public License, Version 2.0, the GNU + Lesser General Public License, Version 2.1, the GNU Affero General + Public License, Version 3.0, or any later versions of those + licenses. + +1.13. "Source Code Form" + means the form of the work preferred for making modifications. + +1.14. "You" (or "Your") + means an individual or a legal entity exercising rights under this + License. For legal entities, "You" includes any entity that + controls, is controlled by, or is under common control with You. For + purposes of this definition, "control" means (a) the power, direct + or indirect, to cause the direction or management of such entity, + whether by contract or otherwise, or (b) ownership of more than + fifty percent (50%) of the outstanding shares or beneficial + ownership of such entity. + +2. License Grants and Conditions +-------------------------------- + +2.1. Grants + +Each Contributor hereby grants You a world-wide, royalty-free, +non-exclusive license: + +(a) under intellectual property rights (other than patent or trademark) + Licensable by such Contributor to use, reproduce, make available, + modify, display, perform, distribute, and otherwise exploit its + Contributions, either on an unmodified basis, with Modifications, or + as part of a Larger Work; and + +(b) under Patent Claims of such Contributor to make, use, sell, offer + for sale, have made, import, and otherwise transfer either its + Contributions or its Contributor Version. + +2.2. Effective Date + +The licenses granted in Section 2.1 with respect to any Contribution +become effective for each Contribution on the date the Contributor first +distributes such Contribution. + +2.3. Limitations on Grant Scope + +The licenses granted in this Section 2 are the only rights granted under +this License. No additional rights or licenses will be implied from the +distribution or licensing of Covered Software under this License. +Notwithstanding Section 2.1(b) above, no patent license is granted by a +Contributor: + +(a) for any code that a Contributor has removed from Covered Software; + or + +(b) for infringements caused by: (i) Your and any other third party's + modifications of Covered Software, or (ii) the combination of its + Contributions with other software (except as part of its Contributor + Version); or + +(c) under Patent Claims infringed by Covered Software in the absence of + its Contributions. + +This License does not grant any rights in the trademarks, service marks, +or logos of any Contributor (except as may be necessary to comply with +the notice requirements in Section 3.4). + +2.4. Subsequent Licenses + +No Contributor makes additional grants as a result of Your choice to +distribute the Covered Software under a subsequent version of this +License (see Section 10.2) or under the terms of a Secondary License (if +permitted under the terms of Section 3.3). + +2.5. Representation + +Each Contributor represents that the Contributor believes its +Contributions are its original creation(s) or it has sufficient rights +to grant the rights to its Contributions conveyed by this License. + +2.6. Fair Use + +This License is not intended to limit any rights You have under +applicable copyright doctrines of fair use, fair dealing, or other +equivalents. + +2.7. Conditions + +Sections 3.1, 3.2, 3.3, and 3.4 are conditions of the licenses granted +in Section 2.1. + +3. Responsibilities +------------------- + +3.1. Distribution of Source Form + +All distribution of Covered Software in Source Code Form, including any +Modifications that You create or to which You contribute, must be under +the terms of this License. You must inform recipients that the Source +Code Form of the Covered Software is governed by the terms of this +License, and how they can obtain a copy of this License. You may not +attempt to alter or restrict the recipients' rights in the Source Code +Form. + +3.2. Distribution of Executable Form + +If You distribute Covered Software in Executable Form then: + +(a) such Covered Software must also be made available in Source Code + Form, as described in Section 3.1, and You must inform recipients of + the Executable Form how they can obtain a copy of such Source Code + Form by reasonable means in a timely manner, at a charge no more + than the cost of distribution to the recipient; and + +(b) You may distribute such Executable Form under the terms of this + License, or sublicense it under different terms, provided that the + license for the Executable Form does not attempt to limit or alter + the recipients' rights in the Source Code Form under this License. + +3.3. Distribution of a Larger Work + +You may create and distribute a Larger Work under terms of Your choice, +provided that You also comply with the requirements of this License for +the Covered Software. If the Larger Work is a combination of Covered +Software with a work governed by one or more Secondary Licenses, and the +Covered Software is not Incompatible With Secondary Licenses, this +License permits You to additionally distribute such Covered Software +under the terms of such Secondary License(s), so that the recipient of +the Larger Work may, at their option, further distribute the Covered +Software under the terms of either this License or such Secondary +License(s). + +3.4. Notices + +You may not remove or alter the substance of any license notices +(including copyright notices, patent notices, disclaimers of warranty, +or limitations of liability) contained within the Source Code Form of +the Covered Software, except that You may alter any license notices to +the extent required to remedy known factual inaccuracies. + +3.5. Application of Additional Terms + +You may choose to offer, and to charge a fee for, warranty, support, +indemnity or liability obligations to one or more recipients of Covered +Software. However, You may do so only on Your own behalf, and not on +behalf of any Contributor. You must make it absolutely clear that any +such warranty, support, indemnity, or liability obligation is offered by +You alone, and You hereby agree to indemnify every Contributor for any +liability incurred by such Contributor as a result of warranty, support, +indemnity or liability terms You offer. You may include additional +disclaimers of warranty and limitations of liability specific to any +jurisdiction. + +4. Inability to Comply Due to Statute or Regulation +--------------------------------------------------- + +If it is impossible for You to comply with any of the terms of this +License with respect to some or all of the Covered Software due to +statute, judicial order, or regulation then You must: (a) comply with +the terms of this License to the maximum extent possible; and (b) +describe the limitations and the code they affect. Such description must +be placed in a text file included with all distributions of the Covered +Software under this License. Except to the extent prohibited by statute +or regulation, such description must be sufficiently detailed for a +recipient of ordinary skill to be able to understand it. + +5. Termination +-------------- + +5.1. The rights granted under this License will terminate automatically +if You fail to comply with any of its terms. However, if You become +compliant, then the rights granted under this License from a particular +Contributor are reinstated (a) provisionally, unless and until such +Contributor explicitly and finally terminates Your grants, and (b) on an +ongoing basis, if such Contributor fails to notify You of the +non-compliance by some reasonable means prior to 60 days after You have +come back into compliance. Moreover, Your grants from a particular +Contributor are reinstated on an ongoing basis if such Contributor +notifies You of the non-compliance by some reasonable means, this is the +first time You have received notice of non-compliance with this License +from such Contributor, and You become compliant prior to 30 days after +Your receipt of the notice. + +5.2. If You initiate litigation against any entity by asserting a patent +infringement claim (excluding declaratory judgment actions, +counter-claims, and cross-claims) alleging that a Contributor Version +directly or indirectly infringes any patent, then the rights granted to +You by any and all Contributors for the Covered Software under Section +2.1 of this License shall terminate. + +5.3. In the event of termination under Sections 5.1 or 5.2 above, all +end user license agreements (excluding distributors and resellers) which +have been validly granted by You or Your distributors under this License +prior to termination shall survive termination. + +************************************************************************ +* * +* 6. Disclaimer of Warranty * +* ------------------------- * +* * +* Covered Software is provided under this License on an "as is" * +* basis, without warranty of any kind, either expressed, implied, or * +* statutory, including, without limitation, warranties that the * +* Covered Software is free of defects, merchantable, fit for a * +* particular purpose or non-infringing. The entire risk as to the * +* quality and performance of the Covered Software is with You. * +* Should any Covered Software prove defective in any respect, You * +* (not any Contributor) assume the cost of any necessary servicing, * +* repair, or correction. This disclaimer of warranty constitutes an * +* essential part of this License. No use of any Covered Software is * +* authorized under this License except under this disclaimer. * +* * +************************************************************************ + +************************************************************************ +* * +* 7. Limitation of Liability * +* -------------------------- * +* * +* Under no circumstances and under no legal theory, whether tort * +* (including negligence), contract, or otherwise, shall any * +* Contributor, or anyone who distributes Covered Software as * +* permitted above, be liable to You for any direct, indirect, * +* special, incidental, or consequential damages of any character * +* including, without limitation, damages for lost profits, loss of * +* goodwill, work stoppage, computer failure or malfunction, or any * +* and all other commercial damages or losses, even if such party * +* shall have been informed of the possibility of such damages. This * +* limitation of liability shall not apply to liability for death or * +* personal injury resulting from such party's negligence to the * +* extent applicable law prohibits such limitation. Some * +* jurisdictions do not allow the exclusion or limitation of * +* incidental or consequential damages, so this exclusion and * +* limitation may not apply to You. * +* * +************************************************************************ + +8. Litigation +------------- + +Any litigation relating to this License may be brought only in the +courts of a jurisdiction where the defendant maintains its principal +place of business and such litigation shall be governed by laws of that +jurisdiction, without reference to its conflict-of-law provisions. +Nothing in this Section shall prevent a party's ability to bring +cross-claims or counter-claims. + +9. Miscellaneous +---------------- + +This License represents the complete agreement concerning the subject +matter hereof. If any provision of this License is held to be +unenforceable, such provision shall be reformed only to the extent +necessary to make it enforceable. Any law or regulation which provides +that the language of a contract shall be construed against the drafter +shall not be used to construe this License against a Contributor. + +10. Versions of the License +--------------------------- + +10.1. New Versions + +Mozilla Foundation is the license steward. Except as provided in Section +10.3, no one other than the license steward has the right to modify or +publish new versions of this License. Each version will be given a +distinguishing version number. + +10.2. Effect of New Versions + +You may distribute the Covered Software under the terms of the version +of the License under which You originally received the Covered Software, +or under the terms of any subsequent version published by the license +steward. + +10.3. Modified Versions + +If you create software not governed by this License, and you want to +create a new license for such software, you may create and use a +modified version of this License if you rename the license and remove +any references to the name of the license steward (except to note that +such modified license differs from this License). + +10.4. Distributing Source Code Form that is Incompatible With Secondary +Licenses + +If You choose to distribute Source Code Form that is Incompatible With +Secondary Licenses under the terms of this version of the License, the +notice described in Exhibit B of this License must be attached. + +Exhibit A - Source Code Form License Notice +------------------------------------------- + + This Source Code Form is subject to the terms of the Mozilla Public + License, v. 2.0. If a copy of the MPL was not distributed with this + file, You can obtain one at http://mozilla.org/MPL/2.0/. + +If it is not possible or desirable to put the notice in a particular +file, then You may include the notice in a location (such as a LICENSE +file in a relevant directory) where a recipient would be likely to look +for such a notice. + +You may add additional accurate notices of copyright ownership. + +Exhibit B - "Incompatible With Secondary Licenses" Notice +--------------------------------------------------------- + + This Source Code Form is "Incompatible With Secondary Licenses", as + defined by the Mozilla Public License, v. 2.0. diff --git a/PUBLISHING.md b/PUBLISHING.md new file mode 100644 index 000000000..8a6d9e0cd --- /dev/null +++ b/PUBLISHING.md @@ -0,0 +1,74 @@ +# Publishing new versions of uefi-rs to Crates.io + +This guide documents the best practices for publishing new versions of +the crates in this repository to [crates.io](https://crates.io/). + +**It is mostly intended for maintainers of the uefi-rs project.** + +## Bumping the crate versions + +For ensuring compatibility within the crates ecosystem, +Cargo [recommends][cargo-semver] maintainers to follow the [semantic versioning][semver] guidelines. + +This means that before publishing the changes, we need to decide +which crates were modified and how should their version numbers be incremented. + +Incrementing the version number of a crate is as simple as editing +the corresponding `Cargo.toml` file and updating the `version = ...` line, +then commiting the change (preferrably on a new branch, so that all of the version bumps +can be combined in a single pull request). + +### Crate dependencies + +The dependency graph of the published crates in this repo is: + +- `uefi-services` depends on `uefi` (the root project) +- `uefi` depends on `uefi-macros` + +If there are breaking changes happening in the project, we should first publish +a new version of `uefi-macros`, then of `uefi`, then of `uefi-services` and so on. + +For example, if the signature of a widely-used macro from `uefi-macros` is changed, +a new major version of that crate will have to be published, then a new version of +`uefi` (major if the previous bump caused changes in the public API of this crate as well), +then possibly a new version of `uefi-services`. + +Furthermore, `uefi-macros` has the `uefi` crate as a `dev-dependency`, +and that will have to be updated in tandem with the major versions of the core crate. + +### Updating the dependent crates + +Remember that if a new major version of a crate gets released, when bumping the version +of it's dependents you will have to also change the dependency line for it. + +For example, if `uefi-macros` gets bumped from `1.1.0` to `2.0.0`, +you will also have to update the corresponding `Cargo.toml` of `uefi` to be: + +```toml +uefi-macros = "2.0.0" +``` + +The dependencies in `template/Cargo.toml` should also be updated to the new version. + +[cargo-semver]: https://doc.rust-lang.org/cargo/reference/semver.html +[semver]: https://semver.org/ + +## Publishing new versions of the crates + +This section is mostly a summary of the official [guide to publishing on crates.io][cargo-publishing-reference], +with a few remarks regarding the specific of this project. + +Start by following the steps in the guide. When running `cargo publish`, +you will have to use a custom `--target` flag to be able to build/verify the crates: + +``` +cargo publish --target x86_64-unknown-uefi +``` + +[cargo-publishing-reference]: https://doc.rust-lang.org/cargo/reference/publishing.html + +## Updating the changelog + +After bumping the crate versions, we should also update the [`CHANGELOG.md`](CHANGELOG.md) file +in order to move all of the unpublished changes to their respective version, and prepare it for +tracking further changes. diff --git a/README.md b/README.md new file mode 100644 index 000000000..cd1adb7ce --- /dev/null +++ b/README.md @@ -0,0 +1,116 @@ +# uefi-rs + +[![Crates.io](https://img.shields.io/crates/v/uefi)](https://crates.io/crates/uefi) +[![Docs.rs](https://docs.rs/uefi/badge.svg)](https://docs.rs/uefi) +![Stars](https://img.shields.io/github/stars/rust-osdev/uefi-rs) +![License](https://img.shields.io/github/license/rust-osdev/uefi-rs) +![Build status](https://github.com/rust-osdev/uefi-rs/workflows/Rust/badge.svg) + +## Description + +[UEFI] is the successor to the BIOS. It provides an early boot environment for +OS loaders, hypervisors and other low-level applications. While it started out +as x86-specific, it has been adopted on other platforms, such as ARM. + +This crate makes it easy to both: + - Write UEFI applications in Rust (for `i686`, `x86_64`, or `aarch64`) + - Call UEFI functions from an OS (usually built with a [custom target][rustc-custom]) + +The objective is to provide **safe** and **performant** wrappers for UEFI interfaces, +and allow developers to write idiomatic Rust code. + +Check out [the UEFI application template](template) for a quick start. + +[UEFI]: https://en.wikipedia.org/wiki/Unified_Extensible_Firmware_Interface +[rustc-custom]: https://doc.rust-lang.org/rustc/targets/custom.html + +![uefi-rs running in QEMU](https://imgur.com/SFPSVuO.png) + +## Project structure + +This project contains multiple sub-crates: + +- `uefi` (top directory): defines the standard UEFI tables / interfaces. + The objective is to stay unopionated and safely wrap most interfaces. + + Optional features: + - `alloc`: implements a global allocator using UEFI functions. + - This allows you to allocate objects on the heap. + - There's no guarantee of the efficiency of UEFI's allocator. + - `logger`: logging implementation for the standard [log] crate. + - Prints output to console. + - No buffering is done: this is not a high-performance logger. + - `exts`: extensions providing utility functions for common patterns. + - Requires the `alloc` crate (either enable the `alloc` optional feature or your own custom allocator). + +- `uefi-macros`: procedural macros that are used to derive some traits in `uefi`. + +- `uefi-services`: provides a panic handler, and initializes the `alloc` / `logger` features. + +- `uefi-test-runner`: a UEFI application that runs unit / integration tests. + +[log]: https://github.com/rust-lang-nursery/log + +## Documentation + +The docs for the latest published crate version can be found at +[docs.rs/uefi/](https://docs.rs/uefi/) + +This crate's documentation is fairly minimal, and you are encouraged to refer to +the [UEFI specification][spec] for detailed information. + +[spec]: http://www.uefi.org/specifications + +## Building and testing uefi-rs + +Use the `cargo xtask` command to build and test the crate. + +Available commands: +- `build`: build all the UEFI packages + - `--release`: build in release mode + - `--target {x86_64,ia32,aarch64}`: choose target UEFI arch +- `clippy`: run clippy on all the packages + - `--target {x86_64,ia32,aarch64}`: choose target UEFI arch + - `--warnings-as-errors`: treat warnings as errors +- `doc`: build the docs for the UEFI packages + - `--open`: open the docs in a browser + - `--warnings-as-errors`: treat warnings as errors +- `run`: build `uefi-test-runner` and run it in QEMU + - `--ci`: disable some tests that don't work in the CI + - `--disable-kvm`: disable hardware accelerated virtualization support in QEMU. + Especially useful if you want to run the tests under + [WSL](https://docs.microsoft.com/en-us/windows/wsl) on Windows. + - `--example `: run an example instead of the main binary. + - `--headless`: run QEMU without a GUI + - `--ovmf-code `: path of an OVMF code file + - `--ovmf-vars `: path of an OVMF vars file + - `--release`: build in release mode + - `--target {x86_64,ia32,aarch64}`: choose target UEFI arch +- `test`: run unit tests and doctests on the host + +The `uefi-test-runner` directory contains a sample UEFI app which exercises +most of the library's functionality. + +Check out the testing project's [`README.md`](uefi-test-runner/README.md) for +prerequisites for running the tests. + +## Building UEFI programs + +For instructions on how to create your own UEFI apps, see the [BUILDING.md](BUILDING.md) file. + +The uefi-rs crates currently require some [unstable features]. +The nightly MSRV is currently 2022-04-18. + +[unstable features]: https://github.com/rust-osdev/uefi-rs/issues/452 + +## Contributing + +We welcome issues and pull requests! For instructions on how to set up a development +environment and how to add new protocols, check out [CONTRIBUTING.md](CONTRIBUTING.md). + +## License + +The code in this repository is licensed under the Mozilla Public License 2. +This license allows you to use the crate in proprietary programs, but any modifications to the files must be open-sourced. + +The full text of the license is available in the [license file](LICENSE). diff --git a/book/README.md b/book/README.md new file mode 100644 index 000000000..0235b901d --- /dev/null +++ b/book/README.md @@ -0,0 +1,14 @@ +# UEFI Book + +To build the book locally, first install [mdBook]. + +Next, launch a server that will automatically update as changes are made +to the markdown sources: + +```console +mdbook serve book/ +``` + +Then open in a web browser. + +[mdBook]: https://rust-lang.github.io/mdBook/guide/installation.html diff --git a/book/book.toml b/book/book.toml new file mode 100644 index 000000000..370cad8ef --- /dev/null +++ b/book/book.toml @@ -0,0 +1,5 @@ +[book] +language = "en" +multilingual = false +src = "src" +title = "Rust UEFI Book" diff --git a/book/head_redirect.html b/book/head_redirect.html new file mode 100644 index 000000000..7c75cfd02 --- /dev/null +++ b/book/head_redirect.html @@ -0,0 +1,8 @@ + + + +Redirecting to latest documentation + + + +Redirecting to ./HEAD... diff --git a/book/src/SUMMARY.md b/book/src/SUMMARY.md new file mode 100644 index 000000000..be7eb70c6 --- /dev/null +++ b/book/src/SUMMARY.md @@ -0,0 +1,18 @@ +# Summary + +- [Introduction](introduction.md) +- [Tutorial](tutorial/introduction.md) + - [Creating a UEFI Application](tutorial/app.md) + - [Building](tutorial/building.md) + - [Running in a VM](tutorial/vm.md) +- [How-to](how_to/introduction.md) + - [Using Protocols](how_to/protocols.md) +- [Concepts](concepts/introduction.md) + - [Boot Stages](concepts/boot_stages.md) + - [Tables](concepts/tables.md) + - [GUID](concepts/guid.md) + - [Handles and Protocols](concepts/handles_and_protocols.md) + - [Device Paths](concepts/device_paths.md) + - [Variables](concepts/variables.md) + - [GPT](concepts/gpt.md) +- [Reference](reference.md) diff --git a/book/src/concepts/boot_stages.md b/book/src/concepts/boot_stages.md new file mode 100644 index 000000000..acb81db67 --- /dev/null +++ b/book/src/concepts/boot_stages.md @@ -0,0 +1,24 @@ +# Boot Stages + +A UEFI system goes through several distinct phases during the boot process. +1. **Platform Initialization.** This early-boot phase is mostly outside + the scope of `uefi-rs`. It is described by the [UEFI Platform + Initialization Specification], which is separate from the main UEFI + Specification. +2. **Boot Services.** This is when UEFI drivers and applications are + loaded. Both the [`BootServices`] and [`RuntimeServices`] tables are + accessible. This stage typically culminates in running a bootloader + that loads an operating system. The stage ends when + [`SystemTable::exit_boot_services`] is called, putting the system in + Runtime mode. +3. **Runtime.** This stage is typically active when running an operating + system such as Linux or Windows. UEFI functionality is much more + limited in the Runtime mode. The [`BootServices`] table is no longer + accessible, but the [`RuntimeServices`] table is still + available. Once the system is in Runtime mode, it cannot return to + the Boot Services stage until after a system reset. + +[UEFI Platform Initialization Specification]: https://uefi.org/specifications +[`BootServices`]: https://docs.rs/uefi/latest/uefi/table/boot/struct.BootServices.html +[`RuntimeServices`]: https://docs.rs/uefi/latest/uefi/table/runtime/struct.RuntimeServices.html +[`SystemTable::exit_boot_services`]: https://docs.rs/uefi/latest/uefi/table/struct.SystemTable.html#method.exit_boot_services diff --git a/book/src/concepts/device_paths.md b/book/src/concepts/device_paths.md new file mode 100644 index 000000000..268d9db0b --- /dev/null +++ b/book/src/concepts/device_paths.md @@ -0,0 +1,24 @@ +# Device Paths + +A device path is a very flexible packed data structure for storing paths +to many kinds of device. Note that these device paths are not the same +thing as file system paths, although they can include file system +paths. Like [handles], device paths can be used to uniquely identify +resources such as consoles, mice, disks, partitions, and more. Unlike +[handles], which are essentially opaque pointers, device paths are +variable-length structures that contain parseable information. + +The [`uefi::proto::device_path`] module documentation describes the +details of how device paths are encoded. + +Device paths can also be converted to and from human-readable text +representations that look like this: +```text +PciRoot(0x0)/Pci(0x1F,0x2)/Sata(0x0,0xFFFF,0x0)/HD(1,MBR,0xBE1AFDFA,0x3F,0xFBFC1) +``` + +See [`uefi::proto::device_path::text`] for details. + +[handles]: handles.md +[`uefi::proto::device_path`]: https://docs.rs/uefi/latest/uefi/proto/device_path/index.html +[`uefi::proto::device_path::text`]: https://docs.rs/uefi/latest/uefi/proto/device_path/text/index.html diff --git a/book/src/concepts/gpt.md b/book/src/concepts/gpt.md new file mode 100644 index 000000000..1beb889ca --- /dev/null +++ b/book/src/concepts/gpt.md @@ -0,0 +1,47 @@ +# GPT + +[GPT] is short for [GUID] Partition Table. It's a more modern +alternative to MBR (master boot record) partition tables. Although it's +defined in the UEFI specification, it often gets used on non-UEFI +systems too. There are a couple big advantages of using GPT over MBR: +- It has a relatively clear and precise standard, unlike MBR where + implementations often just try to match what other implementations do. +- It supports very large disks and very large numbers of partitions. + +A GPT disk contains a primary header near the beginning of the disk, +followed by a partition entry array. The header and partition entry +array have a secondary copy at the end of the disk for redundency. The +partition entry arrays contain structures that describe each partition, +including a GUID to identify the individual partition, a partition type +GUID to indicate the purpose of the partition, and start/end block +addresses. In between the entry arrays is the actual partition data. + +## System partition + +The system partition is UEFI's version of a bootable partition. The +system partition is sometimes called the ESP, or EFI System +Partition. It is identified by a partition type of +`c12a7328-f81f-11d2-ba4b-00a0c93ec93b`. The system partition always +contains a FAT file system. There are various standardized paths that +can exist within the file system, and of particular importance are the +boot files. These are the files that UEFI will try to boot from by +default (in the absence of a different boot configuration set through +special [UEFI variables]). + +Boot files are under `\EFI\BOOT`, and are named `BOOT.efi`, where +`` is a short architecture name. + +|Architecture |File name | +|--------------|----------------| +|Intel 32-bit |BOOTIA32.EFI | +|X86_64 |BOOTX64.EFI | +|Itanium |BOOTIA64.EFI | +|AArch32 |BOOTARM.EFI | +|AArch64 |BOOTAA64.EFI | +|RISC-V 32-bit |BOOTRISCV32.EFI | +|RISC-V 64-bit |BOOTRISCV64.EFI | +|RISC-V 128-bit|BOOTRISCV128.EFI| + +[GPT]: https://en.wikipedia.org/wiki/GUID_Partition_Table +[GUID]: guid.md +[UEFI variables]: variables.md diff --git a/book/src/concepts/guid.md b/book/src/concepts/guid.md new file mode 100644 index 000000000..e91f54cc4 --- /dev/null +++ b/book/src/concepts/guid.md @@ -0,0 +1,15 @@ +# GUID + +GUID is short for Globally Unique Identifier. A GUID is always 16 bytes, +and has a standard string representation format that looks like this: +`313b0d7c-fed4-4de7-99ed-2fe48874a410`. The details of the GUID format +aren't too important, but be aware that the actual byte representation +is not in the same order as the string representation because the first +three fields are little-endian. For the most part you can treat GUIDs as +opaque identifiers. + +The UEFI specification uses GUIDs all over the place. GUIDs are used to +identify protocols, disk partitions, variable groupings, and much +more. In `uefi-rs`, GUIDs are represented by the [`Guid`] type. + +[`Guid`]: https://docs.rs/uefi/latest/uefi/struct.Guid.html diff --git a/book/src/concepts/handles_and_protocols.md b/book/src/concepts/handles_and_protocols.md new file mode 100644 index 000000000..7e6c7d28d --- /dev/null +++ b/book/src/concepts/handles_and_protocols.md @@ -0,0 +1,40 @@ +# Handles and Protocols + +Handles and protocols are at the core of what makes UEFI +extensible. Together they are the mechanism by which UEFI can adapt to a +wide array of hardware and boot conditions, while still providing a +consistent interface to drivers and applications. + +### Handles + +Handles represent resources. A resource might be a physical device such +as a disk drive or USB device, or something less tangible like a loaded +executable. + +A [Handle] is an opaque pointer, so you can't do anything with it +directly. To operate on a handle you have to open a protocol. + +### Protocols + +Protocols are interfaces that provide functions to interact with a +resource. For example, the [BlockIO] protocol provides functions to read +and write to block IO devices. + +Protocols are only available during the Boot Services [stage]; you can't +access them during the Runtime stage. + +The UEFI Specification defines a very large number of protocols. Because +protocols are inherently very diverse, the best place to learn about +individual protocols is the [UEFI Specification]. There are many +chapters covering various protocols. Not all of these protocols are +wrapped by `uefi-rs` yet (contributions welcome!) but many of the most +commonly useful ones are. + +See the [Using Protocols] how-to for details of the `uefi-rs` API for +interacting with protocols. + +[UEFI Specification]: https://uefi.org/specifications +[stage]: boot_stages.md +[Handle]: https://docs.rs/uefi/latest/uefi/data_types/struct.Handle.html +[BlockIO]: https://docs.rs/uefi/latest/uefi/proto/media/block/struct.BlockIO.html +[Using Protocols]: ../how_to/protocols.md diff --git a/book/src/concepts/introduction.md b/book/src/concepts/introduction.md new file mode 100644 index 000000000..79ad8df6c --- /dev/null +++ b/book/src/concepts/introduction.md @@ -0,0 +1,10 @@ +# Concepts + +The canonical source of information about UEFI is the [UEFI specification]. +The specification is huge (currently nearly 2500 pages). Much of that +content relates to optional services, understanding of which is not +critical to understanding UEFI as a whole. This chapter summarizes some +of the more important UEFI concepts and links to the relevant `uefi-rs` +documentation. + +[UEFI specification]: https://uefi.org/specifications diff --git a/book/src/concepts/tables.md b/book/src/concepts/tables.md new file mode 100644 index 000000000..8e072c710 --- /dev/null +++ b/book/src/concepts/tables.md @@ -0,0 +1,37 @@ +# Tables + +UEFI has a few table structures. These tables are how you get access to +UEFI services. + +[`SystemTable`] (`EFI_SYSTEM_TABLE` in the specification) is the +top-level table that provides access to the other tables. + +[`BootServices`] (`EFI_BOOT_SERVICES` in the specification) provides +access to a wide array of services such as memory allocation, executable +loading, and optional extension interfaces called protocols. This table +is only accessible while in the Boot Services stage. + +[`RuntimeServices`] (`EFI_RUNTIME_SERVICES` in the specification) +provides access to a fairly limited set of services, including variable +storage, system time, and virtual-memory mapping. This table is +accessible during both the Boot Services and Runtime stages. + +When writing a UEFI application, you get access to the system table from +one of the arguments to the `main` entry point: + +```rust,ignore +fn main(handle: Handle, mut system_table: SystemTable) -> Status; +``` + +Then use [`SystemTable::boot_services`] and +[`SystemTable::runtime_services`] to get access to the other +tables. Once [`SystemTable::exit_boot_services`] is called, the original +system table is consumed and a new system table is returned that only +provides access to the [`RuntimeServices`] table. + +[`BootServices`]: https://docs.rs/uefi/latest/uefi/table/boot/struct.BootServices.html +[`RuntimeServices`]: https://docs.rs/uefi/latest/uefi/table/runtime/struct.RuntimeServices.html +[`SystemTable::boot_services`]: https://docs.rs/uefi/latest/uefi/table/struct.SystemTable.html#method.boot_services +[`SystemTable::exit_boot_services`]: https://docs.rs/uefi/latest/uefi/table/struct.SystemTable.html#method.exit_boot_services +[`SystemTable::runtime_services`]: https://docs.rs/uefi/latest/uefi/table/struct.SystemTable.html#method.runtime_services +[`SystemTable`]: https://docs.rs/uefi/latest/uefi/table/struct.SystemTable.html diff --git a/book/src/concepts/variables.md b/book/src/concepts/variables.md new file mode 100644 index 000000000..023b7e3df --- /dev/null +++ b/book/src/concepts/variables.md @@ -0,0 +1,39 @@ +# Variables + +UEFI provides fairly flexible key/value variable storage. + +Each variable is identified by a key consisting of a UCS-2 +null-terminated name plus a vendor [GUID]. The vendor GUID serves as a +namespace for variables so that different vendors don't accidentally +overwrite or misinterpret another vendor's variable if they happen to +have the same name. + +The data stored in each variable is an arbitrary byte array. + +## Attributes + +Each variable has attributes (represented as bit flags) associated with +it that affect how it is stored and how it can be accessed. + +If the `BOOTSERVICE_ACCESS` and `RUNTIME_ACCESS` bits are set, the +variable can be accessed during both the Boot Services and Runtime +[stages]. If only `BOOTSERVICE_ACCESS` is set then the variable can +neither be read nor written to after exiting boot services. + +Another important attribute is the `NON_VOLATILE` bit. If this bit is +_not_ set, the variable will be stored in normal memory and will not +persist across a power cycle. If this bit _is_ set, the variable will be +stored in special non-volatile memory. You should be careful about +writing variables of this type, because the non-volatile storage can be +very limited in size. There have been cases where a vendor's poor UEFI +implementation caused the machine not too boot once the storage became +too full. Even figuring out how much space is in use can be tricky due +to deletion being implemented via garbage collection. Matthew Garret's +article ["Dealing with UEFI non-volatile memory quirks"] has more details. + +Most of the other attributes relate to authenticated variables, which +can be used to prevent changes to a variable by unauthorized programs. + +[GUID]: guid.md +[stages]: boot_stages.md +["Dealing with UEFI non-volatile memory quirks"]: https://mjg59.dreamwidth.org/25091.html diff --git a/book/src/how_to/introduction.md b/book/src/how_to/introduction.md new file mode 100644 index 000000000..290e4e68d --- /dev/null +++ b/book/src/how_to/introduction.md @@ -0,0 +1,3 @@ +# How-to + +This chapter contains practical how-to guides. diff --git a/book/src/how_to/protocols.md b/book/src/how_to/protocols.md new file mode 100644 index 000000000..85d6dea28 --- /dev/null +++ b/book/src/how_to/protocols.md @@ -0,0 +1,122 @@ +# Using Protocols + +The open a protocol, you must first get a handle, then open a protocol +on that handle. See [Handles and Protocols] for an overview of what +these terms mean. + +To get a handle you can use: +* [`BootServices::locate_handle_buffer`]: this can be used to get _all_ + available handles, or just the handles that support a particular + protocol. +* [`BootServices::locate_handle`]: the same as `locate_handle_buffer`, + but you provide the slice that stores the handles. +* [`BootServices::locate_device_path`]: find a handle by [Device Path]. + +Once you have obtained a handle, use +[`BootServices::open_protocol_exclusive`] to open a protocol on that +handle. This returns a [`ScopedProtocol`], which automatically closes +the protocol when dropped. + +Using [`BootServices::open_protocol_exclusive`] is the safest way to +open a protocol, but in some cases a protocol cannot be opened in +exclusive mode. The `unsafe` [`BootServices::open_protocol`] can be used +in that case. + +## Example + +For this example we'll look at a program that opens a couple different +protocols. This program opens the [`LoadedImage`] protocol to get +information about an executable (the currently-running program in this +case). It also opens the [`DevicePathToText`] protocol to get the file +system path that the program was launched from. + +We'll walk through the details of this program shortly, but first here's +the whole thing: + +```rust +{{#include ../../../uefi-test-runner/examples/loaded_image.rs:all}} +``` + +When the program is run it will print something like this: + +```text +[ INFO]: example.rs@058: Image path: \EFI\BOOT\BOOTX64.EFI +``` + +## Walkthrough + +The `main` function looks much like the ["Hello world!" example]. It +sets up logging, calls `print_image_path`, and pauses for ten seconds to +give you time to read the output. Let's look at `print_image_path`: + +```rust +{{#include ../../../uefi-test-runner/examples/loaded_image.rs:print_image_path}} +``` + +The return type is a [`uefi::Result`], which is a `Result` alias that +combines [`uefi::Status`] with the error data. Both the success and +error data types are `()` by default. + +The function starts by opening the [`LoadedImage`] protocol: + +```rust +{{#include ../../../uefi-test-runner/examples/loaded_image.rs:loaded_image}} +``` + +The [`open_protocol_exclusive`] method takes a type parameter, which is +the type of [`Protocol`] you want to open ([`LoadedImage`] in this +case). It also takes one regular argument of type [`Handle`]. For this +example we want the handle of the currently-running image, which was +passed in as the first argument to `main`. The handle is conveniently +accessible through [`BootServices::image_handle`], so we use that here. + +Next the program opens the [`DevicePathToText`] protocol: + +```rust +{{#include ../../../uefi-test-runner/examples/loaded_image.rs:device_path}} +``` + +This protocol isn't available for the `image_handle`, so we start by +using [`locate_handle_buffer`] to find all handles that support +`DevicePathToText`. We only need one handle though, so we call `first()` +and discard the rest. Then we call [`open_protocol_exclusive`] again. It +looks more or less like the previous time, but with [`DevicePathToText`] +as the type parameter and `device_path_to_text_handle` as the handle. + +Now that we have both protocols open, we can use them together to get +the program's path and convert it to text: + +```rust +{{#include ../../../uefi-test-runner/examples/loaded_image.rs:text}} +``` + +Since protocols do a wide range of different things, the methods +available to call are very specific to each individual protocol. The +best places to find out what each protocol can do are the [uefi-rs +reference documentation] and the [UEFI Specification]. + +[Device Path]: ../concepts/device_paths.md +[Handles and Protocols]: ../concepts/handles_and_protocols.md +[UEFI Specification]: https://uefi.org/specifications +[`BootServices::image_handle`]: https://docs.rs/uefi/latest/uefi/table/boot/struct.BootServices.html#method.image_handle +[`BootServices::locate_device_path`]: https://docs.rs/uefi/latest/uefi/table/boot/struct.BootServices.html#method.locate_device_path +[`BootServices::locate_handle_buffer`]: https://docs.rs/uefi/latest/uefi/table/boot/struct.BootServices.html#method.locate_handle_buffer +[`BootServices::locate_handle`]: https://docs.rs/uefi/latest/uefi/table/boot/struct.BootServices.html#method.locate_handle +[`BootServices::open_protocol`]: https://docs.rs/uefi/latest/uefi/table/boot/struct.BootServices.html#method.open_protocol +[`BootServices::open_protocol_exclusive`]: https://docs.rs/uefi/latest/uefi/table/boot/struct.BootServices.html#method.open_protocol_exclusive +[`BootServices`]: https://docs.rs/uefi/latest/uefi/table/boot/struct.BootServices.html +[`DevicePathToText`]: https://docs.rs/uefi/latest/uefi/proto/device_path/text/struct.DevicePathToText.html +["Hello world!" example]: ../tutorial/app.html +[`Handle`]: https://docs.rs/uefi/latest/uefi/data_types/struct.Handle.html +[`LoadedImage`]: https://docs.rs/uefi/latest/uefi/proto/loaded_image/struct.LoadedImage.html +[`OpenProtocolAttributes::Exclusive`]: https://docs.rs/uefi/latest/uefi/table/boot/enum.OpenProtocolAttributes.html#variant.Exclusive +[`OpenProtocolAttributes`]: https://docs.rs/uefi/latest/uefi/table/boot/enum.OpenProtocolAttributes.html +[`OpenProtocolParams`]: https://docs.rs/uefi/latest/uefi/table/boot/struct.OpenProtocolParams.html +[`Protocol`]: https://docs.rs/uefi/latest/uefi/proto/trait.Protocol.html +[`ScopedProtocol`]: https://docs.rs/uefi/latest/uefi/table/boot/struct.ScopedProtocol.html +[`locate_handle_buffer`]: https://docs.rs/uefi/latest/uefi/table/boot/struct.BootServices.html#method.locate_handle_buffer +[`open_protocol`]: https://docs.rs/uefi/latest/uefi/table/boot/struct.BootServices.html#method.open_protocol +[`open_protocol_exclusive`]: https://docs.rs/uefi/latest/uefi/table/boot/struct.BootServices.html#method.open_protocol_exclusive +[uefi-rs reference documentation]: https://docs.rs/uefi/latest/uefi/proto/index.html +[`uefi::Result`]: https://docs.rs/uefi/latest/uefi/type.Result.html +[`uefi::Status`]: https://docs.rs/uefi/latest/uefi/struct.Status.html diff --git a/book/src/introduction.md b/book/src/introduction.md new file mode 100644 index 000000000..ad0bcb955 --- /dev/null +++ b/book/src/introduction.md @@ -0,0 +1,7 @@ +# Introduction + +Welcome to the Rust UEFI Book. The focus of this book is how to use +[`uefi-rs`] to build UEFI applications in Rust, but it also describes +some general UEFI concepts, as well as relevant tools such as QEMU. + +[`uefi-rs`]: https://github.com/rust-osdev/uefi-rs diff --git a/book/src/reference.md b/book/src/reference.md new file mode 100644 index 000000000..20afef162 --- /dev/null +++ b/book/src/reference.md @@ -0,0 +1,6 @@ +# Reference + +* [`uefi` crate reference](https://docs.rs/uefi) +* [`uefi-macros` crate reference](https://docs.rs/uefi-macros) +* [`uefi-services` crate reference](https://docs.rs/uefi-services) +* [UEFI Specifications](https://uefi.org/specifications) diff --git a/book/src/tutorial/app.md b/book/src/tutorial/app.md new file mode 100644 index 000000000..61711ec35 --- /dev/null +++ b/book/src/tutorial/app.md @@ -0,0 +1,99 @@ +# Creating a UEFI application + +## Install dependencies + +Follow the [Rust installation instructions] to set up Rust. + +## Create a minimal application + +Create an empty application and change to that directory: + +```sh +cargo new my-uefi-app +cd my-uefi-app +``` + +In `cargo.toml`, add a few dependencies: + +```toml +[dependencies] +log = "0.4" +uefi = "0.17" +uefi-services = "0.14" +``` + +Replace the contents of `src/main.rs` with this: + +```rust +{{#include ../../../uefi-test-runner/examples/hello_world.rs:all}} +``` + +## Walkthrough + +Let's look a quick look at what each part of the program is doing, +starting with the `#![...]` lines at the top: + +```rust +{{#include ../../../uefi-test-runner/examples/hello_world.rs:features}} +``` + +This is some boilerplate that all Rust UEFI applications will +need. `no_main` is needed because the UEFI application entry point is +different from the standard Rust `main` function. `no_std` is needed to +turn off the `std` library; the `core` and `alloc` crates can still be +used. And `feature(abi_efiapi)` is needed because UEFI applications have +a special calling convention that is not yet stabilized in the Rust +compiler. + +Next up are some `use` lines. Nothing too exciting here; the +`uefi::prelude` module is intended to be glob-imported, and exports a +number of commonly-used types. + +```rust +{{#include ../../../uefi-test-runner/examples/hello_world.rs:use}} +``` + +Now we get to the UEFI application `main` function, and here things look +a little different from a standard Rust program. + +```rust +{{#include ../../../uefi-test-runner/examples/hello_world.rs:entry}} +``` + +The `main` function in a Uefi application always takes two arguments, +the image handle and the system table. The image [handle] represents the +currently-running executable, and the system [table] provides access to +many different UEFI services. The `main` function returns a [`Status`], +which is essentially a numeric error (or success) code defined by UEFI. + +The first thing we do inside of `main` is initialize `uefi_services`: + +```rust +{{#include ../../../uefi-test-runner/examples/hello_world.rs:services}} +``` + +The `uefi_services` crate is not strictly required to make a UEFI +application with the `uefi` crate, but it makes things much simpler by +setting a simple memory allocator, initializing the logger, and +providing a panic handler. + +Next we use the standard `log` crate to output "Hello world!". Then we +call `stall` to make the system pause for 10 seconds. This just ensures +you have enough time to see the output. + +```rust +{{#include ../../../uefi-test-runner/examples/hello_world.rs:log}} +``` + +Finally we return `Status::SUCCESS` indicating that everything completed +successfully: + +```rust +{{#include ../../../uefi-test-runner/examples/hello_world.rs:return}} +``` + +[Rust installation instructions]: https://www.rust-lang.org/tools/install +[`Status`]: https://docs.rs/uefi/latest/uefi/struct.Status.html +[`log`]: https://crates.io/crates/log +[handle]: ../concepts/handles_and_protocols.md +[table]: ../concepts/tables.md diff --git a/book/src/tutorial/building.md b/book/src/tutorial/building.md new file mode 100644 index 000000000..8938a8ec5 --- /dev/null +++ b/book/src/tutorial/building.md @@ -0,0 +1,64 @@ +# Building + +## Nightly toolchain + +Rust's nightly toolchain is currently required because uefi-rs uses some +unstable features. The [`build-std`] feature we use to build the +standard libraries is also unstable. + +The easiest way to set this up is using a [rustup toolchain file]. In +the root of your repository, add `rust-toolchain.toml`: + +```toml +[toolchain] +channel = "nightly" +components = ["rust-src"] +``` + +Note that nightly releases can sometimes break, so you might opt to pin +to a specific release. For example, `channel = "nightly-2022-09-01"`. + +## Build the application + +Run this command to build the application: + +```sh +cargo build --target x86_64-unknown-uefi \ + -Zbuild-std=core,compiler_builtins,alloc \ + -Zbuild-std-features=compiler-builtins-mem +``` + +This will produce an x86-64 executable: +`target/x86_64-unknown-uefi/debug/my-uefi-app.efi`. + +## Simplifying the build command + +The above build command is verbose and not easy to remember. With a bit +of configuration we can simplify it a lot. + +Create a `.cargo` directory in the root of the project: + +```sh +mkdir .cargo +``` + +Create `.cargo/config.toml` with these contents: + +```toml +[build] +target = "x86_64-unknown-uefi" + +[unstable] +build-std = ["core", "compiler_builtins", "alloc"] +build-std-features = ["compiler-builtins-mem"] +``` + +Now you can build much more simply: + +```sh +cargo build +``` + +[`build-std`]: https://doc.rust-lang.org/nightly/cargo/reference/unstable.html#build-std +[`rust-toolchain.toml`]: https://rust-lang.github.io/rustup/overrides.html#the-toolchain-file +[rustup toolchain file]: https://rust-lang.github.io/rustup/concepts/toolchains.html diff --git a/book/src/tutorial/introduction.md b/book/src/tutorial/introduction.md new file mode 100644 index 000000000..b1a250a14 --- /dev/null +++ b/book/src/tutorial/introduction.md @@ -0,0 +1,5 @@ +# Tutorial + +This tutorial describes the process of creating and running a simple +x86_64 UEFI application in Rust. The application will print "Hello +World", pause for 10 seconds, then exit. diff --git a/book/src/tutorial/vm.md b/book/src/tutorial/vm.md new file mode 100644 index 000000000..f54a26018 --- /dev/null +++ b/book/src/tutorial/vm.md @@ -0,0 +1,70 @@ +# Running in a VM + +## Install dependencies + +Two dependencies are needed: [QEMU], which implements the virtual +machine itself, and [OVMF], which provides UEFI firmware that QEMU can +run. + +The details of how to install QEMU and OVMF will vary depending on your +operating system. + +Debian/Ubuntu: +```sh +sudo apt-get install qemu ovmf +``` + +Fedora: +```sh +sudo dnf install qemu-kvm edk2-ovmf +``` + +### Firmware files + +The OVMF package provides two firmware files, one for the executable +code and one for variable storage. (The package may provide multiple +variations of these files; refer to the package's documentation for +details of the files it includes.) + +For ease of access we'll copy the OVMF code and vars files to the +project directory. The location where OVMF is installed depends on your +operating system; for Debian, Ubuntu and Fedora the files are under +`/usr/share/OVMF`. + +Copy the files to your project directory: +```sh +cp /usr/share/OVMF/OVMF_CODE.fd . +cp /usr/share/OVMF/OVMF_VARS.fd . +``` + +## System partition + +Now create a directory structure containing the executable to imitate a +[UEFI System Partition]: + +```sh +mkdir -p esp/efi/boot +cp target/x86_64-unknown-uefi/debug/my-uefi-app.efi esp/efi/boot/bootx64.efi +``` + +## Launch the VM + +Now we can launch QEMU, using [VVFAT] to access the `esp` directory created above. + +```sh +qemu-system-x86_64 -enable-kvm \ + -drive if=pflash,format=raw,readonly=on,file=OVMF_CODE.fd \ + -drive if=pflash,format=raw,readonly=on,file=OVMF_VARS.fd \ + -drive format=raw,file=fat:rw:esp +``` + +A QEMU window should appear, and after a few seconds you should see the +log message: +```text +[ INFO]: src/main.rs@011: Hello world! +``` + +[QEMU]: https://www.qemu.org +[OVMF]: https://github.com/tianocore/tianocore.github.io/wiki/OVMF +[VVFAT]: https://en.m.wikibooks.org/wiki/QEMU/Devices/Storage#Virtual_FAT_filesystem_(VVFAT) +[UEFI System Partition]: ../concepts/gpt.md#system-partition diff --git a/index.html b/index.html new file mode 100644 index 000000000..7c75cfd02 --- /dev/null +++ b/index.html @@ -0,0 +1,8 @@ + + + +Redirecting to latest documentation + + + +Redirecting to ./HEAD... diff --git a/rust-toolchain.toml b/rust-toolchain.toml new file mode 100644 index 000000000..bb0480f10 --- /dev/null +++ b/rust-toolchain.toml @@ -0,0 +1,6 @@ +[toolchain] +channel = "nightly" + +# Install the `rust-src` component so that `-Zbuild-std` works. This in +# addition to the components included in the default profile. +components = ["rust-src"] diff --git a/src/alloc.rs b/src/alloc.rs new file mode 100644 index 000000000..8f19dd3d5 --- /dev/null +++ b/src/alloc.rs @@ -0,0 +1,94 @@ +//! This module implements Rust's global allocator interface using UEFI's memory allocation functions. +//! +//! Enabling the `alloc` optional feature in your app will allow you to use Rust's higher-level data structures, +//! like boxes, vectors, hash maps, linked lists and so on. +//! +//! # Usage +//! +//! Call the `init` function with a reference to the boot services table. +//! Failure to do so before calling a memory allocating function will panic. +//! +//! Call the `exit_boot_services` function before exiting UEFI boot services. +//! Failure to do so will turn subsequent allocation into undefined behaviour. + +use core::alloc::{GlobalAlloc, Layout}; +use core::ptr::{self, NonNull}; + +use crate::table::boot::{BootServices, MemoryType}; + +/// Reference to the boot services table, used to call the pool memory allocation functions. +/// +/// The inner pointer is only safe to dereference if UEFI boot services have not been +/// exited by the host application yet. +static mut BOOT_SERVICES: Option> = None; + +/// Initializes the allocator. +/// +/// # Safety +/// +/// This function is unsafe because you _must_ make sure that exit_boot_services +/// will be called when UEFI boot services will be exited. +pub unsafe fn init(boot_services: &BootServices) { + BOOT_SERVICES = NonNull::new(boot_services as *const _ as *mut _); +} + +/// Access the boot services +fn boot_services() -> NonNull { + unsafe { BOOT_SERVICES.expect("Boot services are unavailable or have been exited") } +} + +/// Notify the allocator library that boot services are not safe to call anymore +/// +/// You must arrange for this function to be called on exit from UEFI boot services +pub fn exit_boot_services() { + unsafe { + BOOT_SERVICES = None; + } +} + +/// Allocator which uses the UEFI pool allocation functions. +/// +/// Only valid for as long as the UEFI boot services are available. +pub struct Allocator; + +unsafe impl GlobalAlloc for Allocator { + unsafe fn alloc(&self, layout: Layout) -> *mut u8 { + let mem_ty = MemoryType::LOADER_DATA; + let size = layout.size(); + let align = layout.align(); + + if align > 8 { + // allocate more space for alignment + let ptr = if let Ok(ptr) = boot_services().as_ref().allocate_pool(mem_ty, size + align) + { + ptr + } else { + return ptr::null_mut(); + }; + // calculate align offset + let mut offset = ptr.align_offset(align); + if offset == 0 { + offset = align; + } + let return_ptr = ptr.add(offset); + // store allocated pointer before the struct + (return_ptr.cast::<*mut u8>()).sub(1).write(ptr); + return_ptr + } else { + boot_services() + .as_ref() + .allocate_pool(mem_ty, size) + .unwrap_or(ptr::null_mut()) + } + } + + unsafe fn dealloc(&self, mut ptr: *mut u8, layout: Layout) { + if layout.align() > 8 { + ptr = (ptr as *const *mut u8).sub(1).read(); + } + boot_services().as_ref().free_pool(ptr).unwrap(); + } +} + +#[global_allocator] +static ALLOCATOR: Allocator = Allocator; diff --git a/src/data_types/chars.rs b/src/data_types/chars.rs new file mode 100644 index 000000000..718c8a897 --- /dev/null +++ b/src/data_types/chars.rs @@ -0,0 +1,128 @@ +//! UEFI character handling +//! +//! UEFI uses both Latin-1 and UCS-2 character encoding, this module implements +//! support for the associated character types. + +use core::fmt; + +/// Character conversion error +#[derive(Clone, Copy, Debug)] +pub struct CharConversionError; + +/// A Latin-1 character +#[derive(Clone, Copy, Default, Eq, PartialEq, PartialOrd, Ord)] +#[repr(transparent)] +pub struct Char8(u8); + +impl TryFrom for Char8 { + type Error = CharConversionError; + + fn try_from(value: char) -> Result { + let code_point = value as u32; + if code_point <= 0xff { + Ok(Char8(code_point as u8)) + } else { + Err(CharConversionError) + } + } +} + +impl From for char { + fn from(char: Char8) -> char { + char.0 as char + } +} + +impl From for Char8 { + fn from(value: u8) -> Self { + Char8(value) + } +} + +impl From for u8 { + fn from(char: Char8) -> u8 { + char.0 + } +} + +impl fmt::Debug for Char8 { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + ::fmt(&From::from(self.0), f) + } +} + +impl fmt::Display for Char8 { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + ::fmt(&From::from(self.0), f) + } +} + +/// Latin-1 version of the NUL character +pub const NUL_8: Char8 = Char8(0); + +/// An UCS-2 code point +#[derive(Clone, Copy, Default, Eq, PartialEq, PartialOrd, Ord)] +#[repr(transparent)] +pub struct Char16(u16); + +impl TryFrom for Char16 { + type Error = CharConversionError; + + fn try_from(value: char) -> Result { + let code_point = value as u32; + if code_point <= 0xffff { + Ok(Char16(code_point as u16)) + } else { + Err(CharConversionError) + } + } +} + +impl From for char { + fn from(char: Char16) -> char { + u32::from(char.0).try_into().unwrap() + } +} + +impl TryFrom for Char16 { + type Error = CharConversionError; + + fn try_from(value: u16) -> Result { + // We leverage char's TryFrom impl for Unicode validity checking + let res: Result = u32::from(value).try_into(); + if let Ok(ch) = res { + ch.try_into() + } else { + Err(CharConversionError) + } + } +} + +impl From for u16 { + fn from(char: Char16) -> u16 { + char.0 as u16 + } +} + +impl fmt::Debug for Char16 { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + if let Ok(c) = u32::from(self.0).try_into() { + ::fmt(&c, f) + } else { + write!(f, "Char16({:?})", self.0) + } + } +} + +impl fmt::Display for Char16 { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + if let Ok(c) = u32::from(self.0).try_into() { + ::fmt(&c, f) + } else { + write!(f, "{}", core::char::REPLACEMENT_CHARACTER) + } + } +} + +/// UCS-2 version of the NUL character +pub const NUL_16: Char16 = Char16(0); diff --git a/src/data_types/enums.rs b/src/data_types/enums.rs new file mode 100644 index 000000000..47a2f1ed2 --- /dev/null +++ b/src/data_types/enums.rs @@ -0,0 +1,84 @@ +//! This module provides tooling that facilitates dealing with C-style enums +//! +//! C-style enums and Rust-style enums are quite different. There are things +//! which one allows, but not the other, and vice versa. In an FFI context, two +//! aspects of C-style enums are particularly bothersome to us: +//! +//! - They allow a caller to send back an unknown enum variant. In Rust, the +//! mere act of storing such a variant in a variable is undefined behavior. +//! - They have an implicit conversion to integers, which is often used as a +//! more portable alternative to C bitfields or as a way to count the amount +//! of variants of an enumerated type. Rust enums do not model this well. +//! +//! Therefore, in many cases, C enums are best modeled as newtypes of integers +//! featuring a large set of associated constants instead of as Rust enums. This +//! module provides facilities to simplify this kind of FFI. + +/// Interface a C-style enum as an integer newtype. +/// +/// This macro implements Debug for you, the way you would expect it to work on +/// Rust enums (printing the variant name instead of its integer value). It also +/// derives Clone, Copy, Eq and PartialEq, since that always makes sense for +/// C-style enums and is used by the implementation. If you want anything else +/// to be derived, you can ask for it by adding extra derives as shown in the +/// example below. +/// +/// One minor annoyance is that since variants will be translated into +/// associated constants in a separate impl block, you need to discriminate +/// which attributes should go on the type and which should go on the impl +/// block. The latter should go on the right-hand side of the arrow operator. +/// +/// Usage example: +/// ``` +/// use uefi::newtype_enum; +/// newtype_enum! { +/// #[derive(Ord, PartialOrd)] +/// pub enum UnixBool: i32 => #[allow(missing_docs)] { +/// FALSE = 0, +/// TRUE = 1, +/// /// Nobody expects the Unix inquisition! +/// FILE_NOT_FOUND = -1, +/// }} +/// ``` +#[macro_export] +macro_rules! newtype_enum { + ( + $(#[$type_attrs:meta])* + $visibility:vis enum $type:ident : $base_integer:ty => $(#[$impl_attrs:meta])* { + $( + $(#[$variant_attrs:meta])* + $variant:ident = $value:expr, + )* + } + ) => { + $(#[$type_attrs])* + #[repr(transparent)] + #[derive(Clone, Copy, Eq, PartialEq)] + $visibility struct $type(pub $base_integer); + + $(#[$impl_attrs])* + #[allow(unused)] + impl $type { + $( + $(#[$variant_attrs])* + pub const $variant: $type = $type($value); + )* + } + + impl core::fmt::Debug for $type { + fn fmt(&self, f: &mut core::fmt::Formatter) -> core::fmt::Result { + match *self { + // Display variants by their name, like Rust enums do + $( + $type::$variant => write!(f, stringify!($variant)), + )* + + // Display unknown variants in tuple struct format + $type(unknown) => { + write!(f, "{}({})", stringify!($type), unknown) + } + } + } + } + } +} diff --git a/src/data_types/guid.rs b/src/data_types/guid.rs new file mode 100644 index 000000000..445d6fee9 --- /dev/null +++ b/src/data_types/guid.rs @@ -0,0 +1,138 @@ +use core::fmt; + +/// A globally unique identifier +/// +/// GUIDs are used by UEFI to identify protocols and other objects. They are +/// mostly like variant 2 UUIDs as specified by RFC 4122, but differ from them +/// in that the first 3 fields are little endian instead of big endian. +/// +/// The `Display` formatter prints GUIDs in the canonical format defined by +/// RFC 4122, which is also used by UEFI. +#[derive(Debug, Default, Copy, Clone, Eq, Ord, PartialEq, PartialOrd)] +#[repr(C)] +pub struct Guid { + /// The low field of the timestamp. + a: u32, + /// The middle field of the timestamp. + b: u16, + /// The high field of the timestamp multiplexed with the version number. + c: u16, + /// Contains, in this order: + /// - The high field of the clock sequence multiplexed with the variant. + /// - The low field of the clock sequence. + /// - The spatially unique node identifier. + d: [u8; 8], +} + +impl Guid { + /// Creates a new GUID from its canonical representation + pub const fn from_values( + time_low: u32, + time_mid: u16, + time_high_and_version: u16, + clock_seq_and_variant: u16, + node: u64, + ) -> Self { + assert!(node.leading_zeros() >= 16, "node must be a 48-bit integer"); + // intentional shadowing + let node = node.to_be_bytes(); + + Guid { + a: time_low, + b: time_mid, + c: time_high_and_version, + d: [ + (clock_seq_and_variant / 0x100) as u8, + (clock_seq_and_variant % 0x100) as u8, + // first two elements of node are ignored, we only want the low 48 bits + node[2], + node[3], + node[4], + node[5], + node[6], + node[7], + ], + } + } +} + +impl fmt::Display for Guid { + fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result { + let d = { + let mut buf = [0u8; 2]; + buf[..].copy_from_slice(&self.d[0..2]); + u16::from_be_bytes(buf) + }; + + let e = { + let mut buf = [0u8; 8]; + // first two elements of node are ignored, we only want the low 48 bits + buf[2..].copy_from_slice(&self.d[2..8]); + u64::from_be_bytes(buf) + }; + + write!( + fmt, + "{:08x}-{:04x}-{:04x}-{:04x}-{:012x}", + self.a, self.b, self.c, d, e + ) + } +} + +/// Several entities in the UEFI specification can be referred to by their GUID, +/// this trait is a building block to interface them in uefi-rs. +/// +/// You should never need to use the `Identify` trait directly, but instead go +/// for more specific traits such as `Protocol` or `FileProtocolInfo`, which +/// indicate in which circumstances an `Identify`-tagged type should be used. +/// +/// # Safety +/// +/// Implementing `Identify` is unsafe because attaching an incorrect GUID to a +/// type can lead to type unsafety on both the Rust and UEFI side. +/// +/// You can derive `Identify` for a type using the `unsafe_guid` procedural +/// macro, which is exported by this module. This macro mostly works like a +/// custom derive, but also supports type aliases. It takes a GUID in canonical +/// textual format as an argument, and is used in the following way: +/// +/// ``` +/// use uefi::unsafe_guid; +/// #[unsafe_guid("12345678-9abc-def0-1234-56789abcdef0")] +/// struct Emptiness; +/// ``` +pub unsafe trait Identify { + /// Unique protocol identifier. + const GUID: Guid; +} + +pub use uefi_macros::unsafe_guid; + +#[cfg(test)] +mod tests { + use uefi::unsafe_guid; + extern crate alloc; + use super::*; + + #[test] + fn test_guid_display() { + assert_eq!( + alloc::format!( + "{}", + Guid::from_values(0x12345678, 0x9abc, 0xdef0, 0x1234, 0x56789abcdef0) + ), + "12345678-9abc-def0-1234-56789abcdef0" + ); + } + + #[test] + fn test_unsafe_guid() { + #[unsafe_guid("12345678-9abc-def0-1234-56789abcdef0")] + struct X; + + assert_eq!( + X::GUID, + Guid::from_values(0x12345678, 0x9abc, 0xdef0, 0x1234, 0x56789abcdef0) + ); + } +} diff --git a/src/data_types/mod.rs b/src/data_types/mod.rs new file mode 100644 index 000000000..f1f8adb45 --- /dev/null +++ b/src/data_types/mod.rs @@ -0,0 +1,183 @@ +//! Data type definitions +//! +//! This module defines the basic data types that are used throughout uefi-rs + +use core::{ffi::c_void, ptr::NonNull}; + +/// Opaque handle to an UEFI entity (protocol, image...), guaranteed to be non-null. +/// +/// If you need to have a nullable handle (for a custom UEFI FFI for example) use `Option`. +#[derive(Clone, Copy, Debug)] +#[repr(transparent)] +pub struct Handle(NonNull); + +impl Handle { + /// Creates a new [`Handle`] from a raw address. The address might + /// come from the Multiboot2 information structure or something similar. + /// + /// # Example + /// ```no_run + /// use core::ffi::c_void; + /// use uefi::Handle; + /// + /// let image_handle_addr = 0xdeadbeef as *mut c_void; + /// + /// let uefi_image_handle = unsafe { + /// Handle::from_ptr(image_handle_addr).expect("Pointer must not be null!") + /// }; + /// ``` + /// + /// # Safety + /// This function is unsafe because the caller must be sure that the pointer + /// is valid. Otherwise, further operations on the object might result in + /// undefined behaviour, even if the methods aren't marked as unsafe. + pub unsafe fn from_ptr(ptr: *mut c_void) -> Option { + // shorthand for "|ptr| Self(ptr)" + NonNull::new(ptr).map(Self) + } +} + +/// Handle to an event structure +#[repr(transparent)] +pub struct Event(*mut c_void); + +impl Event { + /// Clone this `Event` + /// + /// # Safety + /// When an event is closed by calling `BootServices::close_event`, that event and ALL references + /// to it are invalidated and the underlying memory is freed by firmware. The caller must ensure + /// that any clones of a closed `Event` are never used again. + #[must_use] + pub unsafe fn unsafe_clone(&self) -> Self { + Self(self.0) + } +} + +/// Trait for querying the alignment of a struct. +/// +/// For a statically-sized type the alignment can be retrieved with +/// [`core::mem::align_of`]. For a dynamically-sized type (DST), +/// [`core::mem::align_of_val`] provides the alignment given a reference. But in +/// some cases it's helpful to know the alignment of a DST prior to having a +/// value, meaning there's no reference to pass to `align_of_val`. For example, +/// when using an API that creates a value using a `[u8]` buffer, the alignment +/// of the buffer must be checked. The `Align` trait makes that possible by +/// allowing the appropriate alignment to be manually specified. +pub trait Align { + /// Required memory alignment for this type + fn alignment() -> usize; + + /// Calculate the offset from `val` necessary to make it aligned, + /// rounding up. For example, if `val` is 1 and the alignment is 8, + /// this will return 7. Returns 0 if `val == 0`. + fn offset_up_to_alignment(val: usize) -> usize { + assert!(Self::alignment() != 0); + let r = val % Self::alignment(); + if r == 0 { + 0 + } else { + Self::alignment() - r + } + } + + /// Round `val` up so that it is aligned. + fn round_up_to_alignment(val: usize) -> usize { + val + Self::offset_up_to_alignment(val) + } + + /// Get a subslice of `buf` where the address of the first element + /// is aligned. Returns `None` if no element of the buffer is + /// aligned. + fn align_buf(buf: &mut [u8]) -> Option<&mut [u8]> { + let addr = buf.as_ptr() as usize; + let offset = Self::offset_up_to_alignment(addr); + buf.get_mut(offset..) + } + + /// Assert that some storage is correctly aligned for this type + fn assert_aligned(storage: &mut [u8]) { + if !storage.is_empty() { + assert_eq!( + (storage.as_ptr() as usize) % Self::alignment(), + 0, + "The provided storage is not correctly aligned for this type" + ) + } + } +} + +/// Physical memory address. This is always a 64-bit value, regardless +/// of target platform. +pub type PhysicalAddress = u64; + +/// Virtual memory address. This is always a 64-bit value, regardless +/// of target platform. +pub type VirtualAddress = u64; + +mod guid; +pub use self::guid::Guid; +pub use self::guid::{unsafe_guid, Identify}; + +pub mod chars; +pub use self::chars::{Char16, Char8}; + +#[macro_use] +mod enums; + +mod strs; +pub use self::strs::{ + CStr16, CStr8, EqStrUntilNul, FromSliceWithNulError, FromStrWithBufError, UnalignedCStr16, + UnalignedCStr16Error, +}; + +#[cfg(feature = "exts")] +mod owned_strs; +#[cfg(feature = "exts")] +pub use self::owned_strs::{CString16, FromStrError}; + +#[cfg(test)] +mod tests { + use super::*; + + #[test] + fn test_alignment() { + struct X {} + + impl Align for X { + fn alignment() -> usize { + 4 + } + } + + assert_eq!(X::offset_up_to_alignment(0), 0); + assert_eq!(X::offset_up_to_alignment(1), 3); + assert_eq!(X::offset_up_to_alignment(2), 2); + assert_eq!(X::offset_up_to_alignment(3), 1); + assert_eq!(X::offset_up_to_alignment(4), 0); + assert_eq!(X::offset_up_to_alignment(5), 3); + assert_eq!(X::offset_up_to_alignment(6), 2); + assert_eq!(X::offset_up_to_alignment(7), 1); + assert_eq!(X::offset_up_to_alignment(8), 0); + + assert_eq!(X::round_up_to_alignment(0), 0); + assert_eq!(X::round_up_to_alignment(1), 4); + assert_eq!(X::round_up_to_alignment(2), 4); + assert_eq!(X::round_up_to_alignment(3), 4); + assert_eq!(X::round_up_to_alignment(4), 4); + assert_eq!(X::round_up_to_alignment(5), 8); + assert_eq!(X::round_up_to_alignment(6), 8); + assert_eq!(X::round_up_to_alignment(7), 8); + assert_eq!(X::round_up_to_alignment(8), 8); + + // Get an intentionally mis-aligned buffer. + let mut buffer = [0u8; 16]; + let mut buffer = &mut buffer[..]; + if (buffer.as_ptr() as usize) % X::alignment() == 0 { + buffer = &mut buffer[1..]; + } + + let buffer = X::align_buf(buffer).unwrap(); + X::assert_aligned(buffer); + } +} diff --git a/src/data_types/owned_strs.rs b/src/data_types/owned_strs.rs new file mode 100644 index 000000000..048fabf69 --- /dev/null +++ b/src/data_types/owned_strs.rs @@ -0,0 +1,189 @@ +use super::chars::{Char16, NUL_16}; +use super::strs::{CStr16, FromSliceWithNulError}; +use crate::alloc_api::vec::Vec; +use crate::data_types::strs::EqStrUntilNul; +use core::fmt; +use core::ops; + +/// Error returned by [`CString16::try_from::<&str>`]. +#[derive(Clone, Copy, Debug, Eq, PartialEq)] +pub enum FromStrError { + /// Character conversion error. + InvalidChar, + /// Nul character found in the input. + InteriorNul, +} + +/// An owned UCS-2 null-terminated string. +/// +/// For convenience, a [CString16] is comparable with `&str` and `String` from the standard library +/// through the trait [EqStrUntilNul]. +/// +/// # Examples +/// +/// Round-trip conversion from a [`&str`] to a `CString16` and back: +/// +/// ``` +/// use uefi::CString16; +/// +/// let s = CString16::try_from("abc").unwrap(); +/// assert_eq!(s.to_string(), "abc"); +/// ``` +#[derive(Clone, Debug, Default, Eq, PartialEq, Ord, PartialOrd)] +pub struct CString16(Vec); + +impl TryFrom<&str> for CString16 { + type Error = FromStrError; + + fn try_from(input: &str) -> Result { + // Initially allocate one Char16 for each byte of the input, plus + // one for the null byte. This should be a good guess for ASCII-ish + // input. + let mut output = Vec::with_capacity(input.len() + 1); + + // Convert to UTF-16, then convert to UCS-2. + for c in input.encode_utf16() { + let c = Char16::try_from(c).map_err(|_| FromStrError::InvalidChar)?; + + // Check for interior nul chars. + if c == NUL_16 { + return Err(FromStrError::InteriorNul); + } + + output.push(c); + } + + // Add trailing nul. + output.push(NUL_16); + + Ok(CString16(output)) + } +} + +impl TryFrom> for CString16 { + type Error = FromSliceWithNulError; + + fn try_from(input: Vec) -> Result { + // Try creating a CStr16 from the input. We throw away the + // result if successful, but it takes care of all the necessary + // validity checks (valid UCS-2, ends in null, contains no + // interior nulls). + CStr16::from_u16_with_nul(&input)?; + + // Convert the input vector from `u16` to `Char16`. + // + // Safety: `Char16` is a transparent struct wrapping `u16`, so + // the types are compatible. The pattern used here matches the + // example in the docs for `into_raw_parts`. + let (ptr, len, cap) = input.into_raw_parts(); + let rebuilt = unsafe { + let ptr = ptr.cast::(); + Vec::from_raw_parts(ptr, len, cap) + }; + + Ok(Self(rebuilt)) + } +} + +impl ops::Deref for CString16 { + type Target = CStr16; + + fn deref(&self) -> &CStr16 { + unsafe { &*(self.0.as_slice() as *const [Char16] as *const CStr16) } + } +} + +impl AsRef for CString16 { + fn as_ref(&self) -> &CStr16 { + self + } +} + +impl fmt::Display for CString16 { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + self.as_ref().fmt(f) + } +} + +impl PartialEq<&CStr16> for CString16 { + fn eq(&self, other: &&CStr16) -> bool { + PartialEq::eq(self.as_ref(), other) + } +} + +impl> EqStrUntilNul for CString16 { + fn eq_str_until_nul(&self, other: &StrType) -> bool { + let this = self.as_ref(); + this.eq_str_until_nul(other) + } +} + +#[cfg(test)] +mod tests { + use super::*; + use crate::alloc_api::string::String; + use crate::alloc_api::vec; + + #[test] + fn test_cstring16_from_str() { + assert_eq!( + CString16::try_from("x").unwrap(), + CString16(vec![Char16::try_from('x').unwrap(), NUL_16]) + ); + + assert_eq!(CString16::try_from("😀"), Err(FromStrError::InvalidChar)); + + assert_eq!(CString16::try_from("x\0"), Err(FromStrError::InteriorNul)); + } + + #[test] + fn test_cstring16_from_u16_vec() { + // Test that invalid inputs are caught. + assert_eq!( + CString16::try_from(vec![]), + Err(FromSliceWithNulError::NotNulTerminated) + ); + assert_eq!( + CString16::try_from(vec![b'a'.into(), 0, b'b'.into(), 0]), + Err(FromSliceWithNulError::InteriorNul(1)) + ); + assert_eq!( + CString16::try_from(vec![0xd800, 0]), + Err(FromSliceWithNulError::InvalidChar(0)) + ); + + // Test valid input. + assert_eq!( + CString16::try_from(vec![b'x'.into(), 0]).unwrap(), + CString16::try_from("x").unwrap() + ); + } + + /// Test `CString16 == &CStr16` and `&CStr16 == CString16`. + #[test] + fn test_cstring16_cstr16_eq() { + assert_eq!( + crate::prelude::cstr16!("abc"), + CString16::try_from("abc").unwrap() + ); + + assert_eq!( + CString16::try_from("abc").unwrap(), + crate::prelude::cstr16!("abc") + ); + } + + /// Tests the trait implementation of trait [EqStrUntilNul]. + #[test] + fn test_cstring16_eq_std_str() { + let input = CString16::try_from("test").unwrap(); + + // test various comparisons with different order (left, right) + assert!(input.eq_str_until_nul(&"test")); + assert!(input.eq_str_until_nul(&String::from("test"))); + + // now other direction + assert!(String::from("test").eq_str_until_nul(&input)); + assert!("test".eq_str_until_nul(&input)); + } +} diff --git a/src/data_types/strs.rs b/src/data_types/strs.rs new file mode 100644 index 000000000..888d0b97a --- /dev/null +++ b/src/data_types/strs.rs @@ -0,0 +1,640 @@ +use super::chars::{Char16, Char8, NUL_16, NUL_8}; +use core::fmt; +use core::iter::Iterator; +use core::marker::PhantomData; +use core::mem::MaybeUninit; +use core::result::Result; +use core::slice; +#[cfg(feature = "exts")] +use {super::CString16, crate::alloc_api::vec::Vec}; + +/// Errors which can occur during checked `[uN]` -> `CStrN` conversions +#[derive(Clone, Copy, Debug, Eq, PartialEq)] +pub enum FromSliceWithNulError { + /// An invalid character was encountered before the end of the slice + InvalidChar(usize), + + /// A null character was encountered before the end of the slice + InteriorNul(usize), + + /// The slice was not null-terminated + NotNulTerminated, +} + +/// Error returned by [`UnalignedCStr16::to_cstr16`]. +#[derive(Clone, Copy, Debug, Eq, PartialEq)] +pub enum UnalignedCStr16Error { + /// An invalid character was encountered. + InvalidChar(usize), + + /// A null character was encountered before the end of the data. + InteriorNul(usize), + + /// The data was not null-terminated. + NotNulTerminated, + + /// The buffer is not big enough to hold the entire string and + /// trailing null character. + BufferTooSmall, +} + +/// Error returned by [`CStr16::from_str_with_buf`]. +#[derive(Clone, Copy, Debug, Eq, PartialEq)] +pub enum FromStrWithBufError { + /// An invalid character was encountered before the end of the string + InvalidChar(usize), + + /// A null character was encountered in the string + InteriorNul(usize), + + /// The buffer is not big enough to hold the entire string and + /// trailing null character + BufferTooSmall, +} + +/// A null-terminated Latin-1 string. +/// +/// This type is largely inspired by [`core::ffi::CStr`] with the exception that all characters are +/// guaranteed to be 8 bit long. +/// +/// For convenience, a [`CStr8`] is comparable with [`core::str`] and +/// `alloc::string::String` from the standard library through the trait [`EqStrUntilNul`]. +#[repr(transparent)] +#[derive(Eq, PartialEq)] +pub struct CStr8([Char8]); + +impl CStr8 { + /// Takes a raw pointer to a null-terminated Latin-1 string and wraps it in a CStr8 reference. + /// + /// # Safety + /// + /// The function will start accessing memory from `ptr` until the first + /// null byte. It's the callers responsibility to ensure `ptr` points to + /// a valid null-terminated string in accessible memory. + pub unsafe fn from_ptr<'ptr>(ptr: *const Char8) -> &'ptr Self { + let mut len = 0; + while *ptr.add(len) != NUL_8 { + len += 1 + } + let ptr = ptr.cast::(); + Self::from_bytes_with_nul_unchecked(slice::from_raw_parts(ptr, len + 1)) + } + + /// Creates a CStr8 reference from bytes. + pub fn from_bytes_with_nul(chars: &[u8]) -> Result<&Self, FromSliceWithNulError> { + let nul_pos = chars.iter().position(|&c| c == 0); + if let Some(nul_pos) = nul_pos { + if nul_pos + 1 != chars.len() { + return Err(FromSliceWithNulError::InteriorNul(nul_pos)); + } + Ok(unsafe { Self::from_bytes_with_nul_unchecked(chars) }) + } else { + Err(FromSliceWithNulError::NotNulTerminated) + } + } + + /// Unsafely creates a CStr8 reference from bytes. + /// + /// # Safety + /// + /// It's the callers responsibility to ensure chars is a valid Latin-1 + /// null-terminated string, with no interior null bytes. + pub unsafe fn from_bytes_with_nul_unchecked(chars: &[u8]) -> &Self { + &*(chars as *const [u8] as *const Self) + } + + /// Returns the inner pointer to this CStr8. + pub fn as_ptr(&self) -> *const Char8 { + self.0.as_ptr() + } + + /// Converts this CStr8 to a slice of bytes without the terminating null byte. + pub fn to_bytes(&self) -> &[u8] { + let chars = self.to_bytes_with_nul(); + &chars[..chars.len() - 1] + } + + /// Converts this CStr8 to a slice of bytes containing the trailing null byte. + pub fn to_bytes_with_nul(&self) -> &[u8] { + unsafe { &*(&self.0 as *const [Char8] as *const [u8]) } + } +} + +impl fmt::Debug for CStr8 { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + write!(f, "CStr8({:?})", &self.0) + } +} + +impl fmt::Display for CStr8 { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + for c in self.0.iter() { + ::fmt(c, f)?; + } + Ok(()) + } +} + +impl> EqStrUntilNul for CStr8 { + fn eq_str_until_nul(&self, other: &StrType) -> bool { + let other = other.as_ref(); + + // TODO: CStr16 has .iter() implemented, CStr8 not yet + let any_not_equal = self + .0 + .iter() + .copied() + .map(char::from) + .zip(other.chars()) + // this only works as CStr8 is guaranteed to have a fixed character length + .take_while(|(l, r)| *l != '\0' && *r != '\0') + .any(|(l, r)| l != r); + + !any_not_equal + } +} + +/// An UCS-2 null-terminated string. +/// +/// This type is largely inspired by [`core::ffi::CStr`] with the exception that all characters are +/// guaranteed to be 16 bit long. +/// +/// For convenience, a [`CStr16`] is comparable with [`core::str`] and +/// `alloc::string::String` from the standard library through the trait [`EqStrUntilNul`]. +#[derive(Eq, PartialEq)] +#[repr(transparent)] +pub struct CStr16([Char16]); + +impl CStr16 { + /// Wraps a raw UEFI string with a safe C string wrapper + /// + /// # Safety + /// + /// The function will start accessing memory from `ptr` until the first + /// null byte. It's the callers responsibility to ensure `ptr` points to + /// a valid string, in accessible memory. + pub unsafe fn from_ptr<'ptr>(ptr: *const Char16) -> &'ptr Self { + let mut len = 0; + while *ptr.add(len) != NUL_16 { + len += 1 + } + let ptr = ptr.cast::(); + Self::from_u16_with_nul_unchecked(slice::from_raw_parts(ptr, len + 1)) + } + + /// Creates a C string wrapper from a u16 slice + /// + /// Since not every u16 value is a valid UCS-2 code point, this function + /// must do a bit more validity checking than CStr::from_bytes_with_nul + pub fn from_u16_with_nul(codes: &[u16]) -> Result<&Self, FromSliceWithNulError> { + for (pos, &code) in codes.iter().enumerate() { + match code.try_into() { + Ok(NUL_16) => { + if pos != codes.len() - 1 { + return Err(FromSliceWithNulError::InteriorNul(pos)); + } else { + return Ok(unsafe { Self::from_u16_with_nul_unchecked(codes) }); + } + } + Err(_) => { + return Err(FromSliceWithNulError::InvalidChar(pos)); + } + _ => {} + } + } + Err(FromSliceWithNulError::NotNulTerminated) + } + + /// Unsafely creates a C string wrapper from a u16 slice. + /// + /// # Safety + /// + /// It's the callers responsibility to ensure chars is a valid UCS-2 + /// null-terminated string, with no interior null bytes. + pub unsafe fn from_u16_with_nul_unchecked(codes: &[u16]) -> &Self { + &*(codes as *const [u16] as *const Self) + } + + /// Convert a [`&str`] to a `&CStr16`, backed by a buffer. + /// + /// The input string must contain only characters representable with + /// UCS-2, and must not contain any null characters (even at the end of + /// the input). + /// + /// The backing buffer must be big enough to hold the converted string as + /// well as a trailing null character. + /// + /// # Examples + /// + /// Convert the UTF-8 string "ABC" to a `&CStr16`: + /// + /// ``` + /// use uefi::CStr16; + /// + /// let mut buf = [0; 4]; + /// CStr16::from_str_with_buf("ABC", &mut buf).unwrap(); + /// ``` + pub fn from_str_with_buf<'a>( + input: &str, + buf: &'a mut [u16], + ) -> Result<&'a Self, FromStrWithBufError> { + let mut index = 0; + + // Convert to UTF-16. + for c in input.encode_utf16() { + *buf.get_mut(index) + .ok_or(FromStrWithBufError::BufferTooSmall)? = c; + index += 1; + } + + // Add trailing null character. + *buf.get_mut(index) + .ok_or(FromStrWithBufError::BufferTooSmall)? = 0; + + // Convert from u16 to Char16. This checks for invalid UCS-2 chars and + // interior nulls. The NotNulTerminated case is unreachable because we + // just added a trailing null character. + Self::from_u16_with_nul(&buf[..index + 1]).map_err(|err| match err { + FromSliceWithNulError::InvalidChar(p) => FromStrWithBufError::InvalidChar(p), + FromSliceWithNulError::InteriorNul(p) => FromStrWithBufError::InteriorNul(p), + FromSliceWithNulError::NotNulTerminated => unreachable!(), + }) + } + + /// Returns the inner pointer to this C string + pub fn as_ptr(&self) -> *const Char16 { + self.0.as_ptr() + } + + /// Get the underlying [`Char16`] slice, including the trailing null. + pub fn as_slice_with_nul(&self) -> &[Char16] { + &self.0 + } + + /// Converts this C string to a u16 slice + pub fn to_u16_slice(&self) -> &[u16] { + let chars = self.to_u16_slice_with_nul(); + &chars[..chars.len() - 1] + } + + /// Converts this C string to a u16 slice containing the trailing 0 char + pub fn to_u16_slice_with_nul(&self) -> &[u16] { + unsafe { &*(&self.0 as *const [Char16] as *const [u16]) } + } + + /// Returns an iterator over this C string + pub fn iter(&self) -> CStr16Iter { + CStr16Iter { + inner: self, + pos: 0, + } + } + + /// Get the number of bytes in the string (including the trailing null character). + pub fn num_bytes(&self) -> usize { + self.0.len() * 2 + } + + /// Writes each [`Char16`] as a [`char`] (4 bytes long in Rust language) into the buffer. + /// It is up the the implementer of [`core::fmt::Write`] to convert the char to a string + /// with proper encoding/charset. For example, in the case of [`alloc::string::String`] + /// all Rust chars (UTF-32) get converted to UTF-8. + /// + /// ## Example + /// + /// ```ignore + /// let firmware_vendor_c16_str: CStr16 = ...; + /// // crate "arrayvec" uses stack-allocated arrays for Strings => no heap allocations + /// let mut buf = arrayvec::ArrayString::<128>::new(); + /// firmware_vendor_c16_str.as_str_in_buf(&mut buf); + /// log::info!("as rust str: {}", buf.as_str()); + /// ``` + /// + /// [`alloc::string::String`]: https://doc.rust-lang.org/nightly/alloc/string/struct.String.html + pub fn as_str_in_buf(&self, buf: &mut dyn core::fmt::Write) -> core::fmt::Result { + for c16 in self.iter() { + buf.write_char(char::from(*c16))?; + } + Ok(()) + } +} + +impl> EqStrUntilNul for CStr16 { + fn eq_str_until_nul(&self, other: &StrType) -> bool { + let other = other.as_ref(); + + let any_not_equal = self + .iter() + .copied() + .map(char::from) + .zip(other.chars()) + // this only works as CStr16 is guaranteed to have a fixed character length + .take_while(|(l, r)| *l != '\0' && *r != '\0') + .any(|(l, r)| l != r); + + !any_not_equal + } +} + +/// An iterator over `CStr16`. +#[derive(Debug)] +pub struct CStr16Iter<'a> { + inner: &'a CStr16, + pos: usize, +} + +impl<'a> Iterator for CStr16Iter<'a> { + type Item = &'a Char16; + + fn next(&mut self) -> Option { + if self.pos >= self.inner.0.len() - 1 { + None + } else { + self.pos += 1; + self.inner.0.get(self.pos - 1) + } + } +} + +impl fmt::Debug for CStr16 { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + write!(f, "CStr16({:?})", &self.0) + } +} + +impl fmt::Display for CStr16 { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + for c in self.iter() { + ::fmt(c, f)?; + } + Ok(()) + } +} + +#[cfg(feature = "exts")] +impl PartialEq for &CStr16 { + fn eq(&self, other: &CString16) -> bool { + PartialEq::eq(*self, other.as_ref()) + } +} + +/// An unaligned UCS-2 null-terminated string. +/// +/// This wrapper type can be used with UEFI strings that are inside a +/// [`repr(packed)`] struct. Creating a reference to a packed field is +/// not allowed because it might not be properly aligned, so a +/// [`CStr16`] can't be directly constructed. `UnalignedCStr16` instead +/// takes a pointer to the unaligned field, which is allowed. The +/// resulting unaligned string cannot be used directly, but must be +/// converted to an aligned form first with [`to_cstr16`] or +/// [`to_cstring16`]. +/// +/// [`repr(packed)`]: https://doc.rust-lang.org/nomicon/other-reprs.html#reprpacked +/// [`to_cstr16`]: Self::to_cstr16 +/// [`to_cstring16`]: Self::to_cstring16 +#[derive(Debug)] +pub struct UnalignedCStr16<'a> { + data: *const u16, + len: usize, + _phantom_lifetime: PhantomData<&'a ()>, +} + +// While it's not unsafe to have an empty `UnalignedCStr16`, there's not +// much point either since the string wouldn't be valid without a null +// terminator. So skip adding an `is_empty` method. +#[allow(clippy::len_without_is_empty)] +impl<'a> UnalignedCStr16<'a> { + /// Create an `UnalignedCStr16` from a `*const u16` pointer. The + /// pointer must be valid but can be unaligned. The `len` parameter + /// is the number of `u16` characters in the string (not the number + /// of bytes), including the trailing null. + /// + /// The `_lifetime` parameter is used to make it easy to set an + /// appropriate lifetime for `'a`. The caller should pass in a + /// reference to something tied to the lifetime of `data`. (The + /// `data` parameter cannot itself be a reference because the + /// pointer is allowed to be unaligned.) + /// + /// # Safety + /// + /// The `data` pointer cannot be dangling, and must remain valid for + /// the lifetime of `'a`. There must be at least `len` `u16` + /// elements starting with the the first character pointed to by + /// `data`. These restrictions allow all other methods on + /// `UnalignedCStr16` to be safe. + pub unsafe fn new(_lifetime: &'a T, data: *const u16, len: usize) -> Self { + Self { + data, + len, + _phantom_lifetime: PhantomData, + } + } + + /// Number of `u16` elements in the string, including the trailing null. + pub fn len(&self) -> usize { + self.len + } + + /// Copy the data to an aligned buffer. Panics if the length of + /// `dst` is not exactly the same as `self.len()`. Otherwise the + /// function always succeeds, and initializes all elements of `dst`. + pub fn copy_to(&self, dst: &mut [MaybeUninit]) { + if dst.len() != self.len { + panic!("incorrect buffer length"); + } + + for (i, elem) in dst.iter_mut().enumerate() { + unsafe { elem.write(self.data.add(i).read_unaligned()) }; + } + } + + /// Convert to a [`CStr16`] using an aligned buffer for storage. The + /// lifetime of the output is tied to `buf`, not `self`. + pub fn to_cstr16<'buf>( + &self, + buf: &'buf mut [MaybeUninit], + ) -> Result<&'buf CStr16, UnalignedCStr16Error> { + // The input `buf` might be longer than needed, so get a + // subslice of the required length. + let buf = buf + .get_mut(..self.len()) + .ok_or(UnalignedCStr16Error::BufferTooSmall)?; + + self.copy_to(buf); + let buf = unsafe { + // Safety: `copy_buf` fully initializes the slice. + MaybeUninit::slice_assume_init_ref(buf) + }; + CStr16::from_u16_with_nul(buf).map_err(|e| match e { + FromSliceWithNulError::InvalidChar(v) => UnalignedCStr16Error::InvalidChar(v), + FromSliceWithNulError::InteriorNul(v) => UnalignedCStr16Error::InteriorNul(v), + FromSliceWithNulError::NotNulTerminated => UnalignedCStr16Error::NotNulTerminated, + }) + } + + /// Convert to a [`CString16`]. Requires the `exts` feature. + #[cfg(feature = "exts")] + pub fn to_cstring16(&self) -> Result { + let len = self.len(); + let mut v = Vec::with_capacity(len); + unsafe { + self.copy_to(v.spare_capacity_mut()); + v.set_len(len); + } + CString16::try_from(v) + } +} + +/// Trait that helps to compare Rust strings against CStr16 types. +/// A generic implementation of this trait enables us that we only have to +/// implement one direction (`left.eq_str_until_nul(&right)`) and we get +/// the other direction (`right.eq_str_until_nul(&left)`) for free. +pub trait EqStrUntilNul { + /// Checks if the provided Rust string `StrType` is equal to [Self] until the first null-byte + /// is found. An exception is the terminating null-byte of [Self] which is ignored. + /// + /// As soon as the first null byte in either `&self` or `other` is found, this method returns. + /// Note that Rust strings are allowed to contain null-bytes that do not terminate the string. + /// Although this is rather unusual, you can compare `"foo\0bar"` with an instance of [Self]. + /// In that case, only `foo"` is compared against [Self] (if [Self] is long enough). + fn eq_str_until_nul(&self, other: &StrType) -> bool; +} + +// magic implementation which transforms an existing `left.eq_str_until_nul(&right)` implementation +// into an additional working `right.eq_str_until_nul(&left)` implementation. +impl EqStrUntilNul for StrType +where + StrType: AsRef, + C16StrType: EqStrUntilNul + ?Sized, +{ + fn eq_str_until_nul(&self, other: &C16StrType) -> bool { + // reuse the existing implementation + other.eq_str_until_nul(self) + } +} + +#[cfg(test)] +mod tests { + use super::*; + use crate::alloc_api::string::String; + use uefi_macros::{cstr16, cstr8}; + + #[test] + fn test_cstr16_num_bytes() { + let s = CStr16::from_u16_with_nul(&[65, 66, 67, 0]).unwrap(); + assert_eq!(s.num_bytes(), 8); + } + + #[test] + fn test_cstr16_from_str_with_buf() { + let mut buf = [0; 4]; + + // OK: buf is exactly the right size. + let s = CStr16::from_str_with_buf("ABC", &mut buf).unwrap(); + assert_eq!(s.to_u16_slice_with_nul(), [65, 66, 67, 0]); + + // OK: buf is bigger than needed. + let s = CStr16::from_str_with_buf("A", &mut buf).unwrap(); + assert_eq!(s.to_u16_slice_with_nul(), [65, 0]); + + // Error: buf is too small. + assert_eq!( + CStr16::from_str_with_buf("ABCD", &mut buf).unwrap_err(), + FromStrWithBufError::BufferTooSmall + ); + + // Error: invalid character. + assert_eq!( + CStr16::from_str_with_buf("a😀", &mut buf).unwrap_err(), + FromStrWithBufError::InvalidChar(1), + ); + + // Error: interior null. + assert_eq!( + CStr16::from_str_with_buf("a\0b", &mut buf).unwrap_err(), + FromStrWithBufError::InteriorNul(1), + ); + } + + #[test] + fn test_cstr16_macro() { + // Just a sanity check to make sure it's spitting out the right characters + assert_eq!( + crate::prelude::cstr16!("ABC").to_u16_slice_with_nul(), + [65, 66, 67, 0] + ) + } + + #[test] + fn test_unaligned_cstr16() { + let mut buf = [0u16; 6]; + let us = unsafe { + let ptr = buf.as_mut_ptr() as *mut u8; + // Intentionally create an unaligned u16 pointer. This + // leaves room for five u16 characters. + let ptr = ptr.add(1) as *mut u16; + // Write out the "test" string. + ptr.add(0).write_unaligned(b't'.into()); + ptr.add(1).write_unaligned(b'e'.into()); + ptr.add(2).write_unaligned(b's'.into()); + ptr.add(3).write_unaligned(b't'.into()); + ptr.add(4).write_unaligned(b'\0'.into()); + + // Create the `UnalignedCStr16`. + UnalignedCStr16::new(&buf, ptr, 5) + }; + + // Test `to_cstr16()` with too small of a buffer. + let mut buf = [MaybeUninit::new(0); 4]; + assert_eq!( + us.to_cstr16(&mut buf).unwrap_err(), + UnalignedCStr16Error::BufferTooSmall + ); + // Test with a big enough buffer. + let mut buf = [MaybeUninit::new(0); 5]; + assert_eq!( + us.to_cstr16(&mut buf).unwrap(), + CString16::try_from("test").unwrap() + ); + + // Test `to_cstring16()`. + assert_eq!( + us.to_cstring16().unwrap(), + CString16::try_from("test").unwrap() + ); + } + + // Code generation helper for the compare tests of our CStrX types against "str" and "String" + // from the standard library. + #[allow(non_snake_case)] + macro_rules! test_compare_cstrX { + ($input:ident) => { + assert!($input.eq_str_until_nul(&"test")); + assert!($input.eq_str_until_nul(&String::from("test"))); + + // now other direction + assert!(String::from("test").eq_str_until_nul($input)); + assert!("test".eq_str_until_nul($input)); + + // some more tests + // this is fine: compare until the first null + assert!($input.eq_str_until_nul(&"te\0st")); + // this is fine + assert!($input.eq_str_until_nul(&"test\0")); + assert!(!$input.eq_str_until_nul(&"hello")); + }; + } + + #[test] + fn test_compare_cstr8() { + // test various comparisons with different order (left, right) + let input: &CStr8 = cstr8!("test"); + test_compare_cstrX!(input); + } + + #[test] + fn test_compare_cstr16() { + let input: &CStr16 = cstr16!("test"); + test_compare_cstrX!(input); + } +} diff --git a/src/lib.rs b/src/lib.rs new file mode 100644 index 000000000..510e63756 --- /dev/null +++ b/src/lib.rs @@ -0,0 +1,65 @@ +//! Rusty wrapper for the Unified Extensible Firmware Interface. +//! +//! # Crate organisation +//! +//! The top-level module contains some of the most used types, +//! such as the result and error types, or other common data structures +//! such as GUIDs and handles. +//! +//! ## Tables and protocols +//! +//! The `table` module contains definitions of the UEFI tables, +//! which are structures containing some basic functions and references to other tables. +//! Most importantly, the boot services table also provides a way to obtain **protocol** handles. +//! +//! The `proto` module contains the standard UEFI protocols, which are normally provided +//! by the various UEFI drivers and firmware layers. +//! +//! ## Adapting to local conditions +//! +//! Unlike system tables, which are present on *all* UEFI implementations, +//! protocols *may* or *may not* be present on a certain system. +//! +//! For example, a PC with no network card might not contain a network driver, +//! therefore all the network protocols will be unavailable. + +#![feature(abi_efiapi)] +#![feature(maybe_uninit_slice)] +#![feature(negative_impls)] +#![feature(ptr_metadata)] +#![cfg_attr(feature = "exts", feature(vec_into_raw_parts))] +#![cfg_attr(docsrs, feature(doc_auto_cfg))] +#![no_std] +// Enable some additional warnings and lints. +#![warn(clippy::ptr_as_ptr, missing_docs, unused)] +#![deny(clippy::all)] + +// `uefi-exts` requires access to memory allocation APIs. +#[cfg(feature = "exts")] +extern crate alloc as alloc_api; + +// allow referring to self as ::uefi for macros to work universally (from this crate and from others) +// see https://github.com/rust-lang/rust/issues/54647 +extern crate self as uefi; + +#[macro_use] +pub mod data_types; +#[cfg(feature = "exts")] +pub use self::data_types::CString16; +pub use self::data_types::{unsafe_guid, Identify}; +pub use self::data_types::{CStr16, CStr8, Char16, Char8, Event, Guid, Handle}; + +mod result; +pub use self::result::{Error, Result, ResultExt, Status}; + +pub mod table; + +pub mod proto; + +pub mod prelude; + +#[cfg(feature = "alloc")] +pub mod alloc; + +#[cfg(feature = "logger")] +pub mod logger; diff --git a/src/logger.rs b/src/logger.rs new file mode 100644 index 000000000..5b073652d --- /dev/null +++ b/src/logger.rs @@ -0,0 +1,168 @@ +//! This optional feature adds support for the `log` crate, providing +//! a custom logger implementation which writes to a UEFI text output protocol. +//! +//! The main export of this module is the `Logger` structure, +//! which implements the `log` crate's trait `Log`. +//! +//! # Implementation details +//! +//! The implementation is not the most efficient, since there is no buffering done, +//! and the messages have to be converted from UTF-8 to UEFI's UCS-2. +//! +//! The last part also means that some Unicode characters might not be +//! supported by the UEFI console. Don't expect emoji output support. + +use crate::proto::console::text::Output; + +use core::fmt::{self, Write}; +use core::ptr::NonNull; + +/// Logging implementation which writes to a UEFI output stream. +/// +/// If this logger is used as a global logger, you must disable it using the +/// `disable` method before exiting UEFI boot services in order to prevent +/// undefined behaviour from inadvertent logging. +pub struct Logger { + writer: Option>>, +} + +impl Logger { + /// Creates a new logger. + /// + /// You must arrange for the `disable` method to be called or for this logger + /// to be otherwise discarded before boot services are exited. + /// + /// # Safety + /// + /// Undefined behaviour may occur if this logger is still active after the + /// application has exited the boot services stage. + pub unsafe fn new(output: &mut Output) -> Self { + Logger { + writer: NonNull::new(output as *const _ as *mut _), + } + } + + /// Disable the logger + pub fn disable(&mut self) { + self.writer = None; + } +} + +impl log::Log for Logger { + fn enabled(&self, _metadata: &log::Metadata) -> bool { + self.writer.is_some() + } + + fn log(&self, record: &log::Record) { + if let Some(mut ptr) = self.writer { + let writer = unsafe { ptr.as_mut() }; + let result = DecoratedLog::write( + writer, + record.level(), + record.args(), + record.file().unwrap_or(""), + record.line().unwrap_or(0), + ); + + // Some UEFI implementations, such as the one used by VirtualBox, + // may intermittently drop out some text from SimpleTextOutput and + // report an EFI_DEVICE_ERROR. This will be reported here as an + // `fmt::Error`, and given how the `log` crate is designed, our main + // choices when that happens are to ignore the error or panic. + // + // Ignoring errors is bad, especially when they represent loss of + // precious early-boot system diagnosis data, so we panic by + // default. But if you experience this problem and want your UEFI + // application to keep running when it happens, you can disable the + // `panic-on-logger-errors` cargo feature. If you do so, logging errors + // will be ignored by `uefi-rs` instead. + // + if cfg!(feature = "panic-on-logger-errors") { + result.unwrap() + } + } + } + + fn flush(&self) { + // This simple logger does not buffer output. + } +} + +// The logger is not thread-safe, but the UEFI boot environment only uses one processor. +unsafe impl Sync for Logger {} +unsafe impl Send for Logger {} + +/// Writer wrapper which prints a log level in front of every line of text +/// +/// This is less easy than it sounds because... +/// +/// 1. The fmt::Arguments is a rather opaque type, the ~only thing you can do +/// with it is to hand it to an fmt::Write implementation. +/// 2. Without using memory allocation, the easy cop-out of writing everything +/// to a String then post-processing is not available. +/// +/// Therefore, we need to inject ourselves in the middle of the fmt::Write +/// machinery and intercept the strings that it sends to the Writer. +struct DecoratedLog<'writer, 'a, W: fmt::Write> { + writer: &'writer mut W, + log_level: log::Level, + at_line_start: bool, + file: &'a str, + line: u32, +} + +impl<'writer, 'a, W: fmt::Write> DecoratedLog<'writer, 'a, W> { + // Call this method to print a level-annotated log + fn write( + writer: &'writer mut W, + log_level: log::Level, + args: &fmt::Arguments, + file: &'a str, + line: u32, + ) -> fmt::Result { + let mut decorated_writer = Self { + writer, + log_level, + at_line_start: true, + file, + line, + }; + writeln!(decorated_writer, "{}", *args) + } +} + +impl<'writer, 'a, W: fmt::Write> fmt::Write for DecoratedLog<'writer, 'a, W> { + fn write_str(&mut self, s: &str) -> fmt::Result { + // Split the input string into lines + let mut lines = s.lines(); + + // The beginning of the input string may actually fall in the middle of + // a line of output. We only print the log level if it truly is at the + // beginning of a line of output. + let first = lines.next().unwrap_or(""); + if self.at_line_start { + write!( + self.writer, + "[{:>5}]: {:>12}@{:03}: ", + self.log_level, self.file, self.line + )?; + self.at_line_start = false; + } + write!(self.writer, "{}", first)?; + + // For the remainder of the line iterator (if any), we know that we are + // truly at the beginning of lines of output. + for line in lines { + write!(self.writer, "\n{}: {}", self.log_level, line)?; + } + + // If the string ends with a newline character, we must 1/propagate it + // to the output (it was swallowed by the iteration) and 2/prepare to + // write the log level of the beginning of the next line (if any). + if let Some('\n') = s.chars().next_back() { + writeln!(self.writer)?; + self.at_line_start = true; + } + Ok(()) + } +} diff --git a/src/prelude.rs b/src/prelude.rs new file mode 100644 index 000000000..3a5dac089 --- /dev/null +++ b/src/prelude.rs @@ -0,0 +1,13 @@ +//! This module is used to simplify importing the most common UEFI types. +//! +//! This includes the system table types, `Status` codes, etc. + +pub use crate::{Handle, ResultExt, Status}; + +// Import the basic table types. +pub use crate::table::boot::BootServices; +pub use crate::table::runtime::RuntimeServices; +pub use crate::table::{Boot, SystemTable}; + +// Import the macro for creating the custom entry point, as well as the cstr macros. +pub use uefi_macros::{cstr16, cstr8, entry}; diff --git a/src/proto/console/gop.rs b/src/proto/console/gop.rs new file mode 100644 index 000000000..e5e464abb --- /dev/null +++ b/src/proto/console/gop.rs @@ -0,0 +1,657 @@ +//! Graphics output protocol. +//! +//! The UEFI GOP is meant to replace existing [VGA][vga] hardware interfaces. +//! It can be used in the boot environment as well as at runtime, +//! until a high-performance driver is loaded by the OS. +//! +//! The GOP provides access to a hardware frame buffer and allows UEFI apps +//! to draw directly to the graphics output device. +//! +//! The advantage of the GOP over legacy VGA is that it allows multiple GPUs +//! to exist and be used on the system. There is a GOP implementation for every +//! unique GPU in the system which supports UEFI. +//! +//! This protocol _can_ be used after boot services are exited. +//! +//! [vga]: https://en.wikipedia.org/wiki/Video_Graphics_Array +//! +//! # Definitions +//! +//! All graphics operations use a coordinate system where the top-left of the screen +//! is mapped to the point (0, 0), and `y` increases going down. +//! +//! Rectangles are defined by their top-left corner, and their width and height. +//! +//! The stride is understood as the length in bytes of a scan line / row of a buffer. +//! In theory, a buffer with a width of 640 should have (640 * 4) bytes per row, +//! but in practice there might be some extra padding used for efficiency. +//! +//! Frame buffers represent the graphics card's image buffers, backing the displays. +//! +//! Blits (**bl**ock **t**ransfer) can do high-speed memory copy between +//! the frame buffer and itself, or to and from some other buffers. +//! +//! # Blitting +//! +//! On certain hardware, the frame buffer is in a opaque format, +//! or cannot be accessed by the CPU. In those cases, it is not possible +//! to draw directly to the frame buffer. You must draw to another buffer +//! with a known pixel format, and then submit a blit command to copy that buffer +//! into the back buffer. +//! +//! Blitting can also copy a rectangle from the frame buffer to +//! another rectangle in the frame buffer, or move data out of the frame buffer +//! into a CPU-visible buffer. It can also do very fast color fills. +//! +//! The source and destination rectangles must always be of the same size: +//! no stretching / squashing will be done. +//! +//! # Animations +//! +//! UEFI does not mention if double buffering is used, nor how often +//! the frame buffer gets sent to the screen, but it's safe to assume that +//! the graphics card will re-draw the buffer at around the monitor's refresh rate. +//! You will have to implement your own double buffering if you want to +//! avoid tearing with animations. + +use crate::proto::Protocol; +use crate::{unsafe_guid, Result, Status}; +use core::marker::PhantomData; +use core::mem; +use core::ptr; + +/// Provides access to the video hardware's frame buffer. +/// +/// The GOP can be used to set the properties of the frame buffer, +/// and also allows the app to access the in-memory buffer. +#[repr(C)] +#[unsafe_guid("9042a9de-23dc-4a38-96fb-7aded080516a")] +#[derive(Protocol)] +pub struct GraphicsOutput<'boot> { + query_mode: extern "efiapi" fn( + &GraphicsOutput, + mode: u32, + info_sz: &mut usize, + &mut *const ModeInfo, + ) -> Status, + set_mode: extern "efiapi" fn(&mut GraphicsOutput, mode: u32) -> Status, + // Clippy correctly complains that this is too complicated, but we can't change the spec. + blt: unsafe extern "efiapi" fn( + this: &mut GraphicsOutput, + buffer: *mut BltPixel, + op: u32, + source_x: usize, + source_y: usize, + dest_x: usize, + dest_y: usize, + width: usize, + height: usize, + stride: usize, + ) -> Status, + mode: &'boot ModeData<'boot>, +} + +impl<'boot> GraphicsOutput<'boot> { + /// Returns information for an available graphics mode that the graphics + /// device and the set of active video output devices supports. + pub fn query_mode(&self, index: u32) -> Result { + let mut info_sz = 0; + let mut info = ptr::null(); + + (self.query_mode)(self, index, &mut info_sz, &mut info).into_with_val(|| { + let info = unsafe { *info }; + Mode { + index, + info_sz, + info, + } + }) + } + + /// Returns information about all available graphics modes. + pub fn modes(&'_ self) -> impl ExactSizeIterator + '_ { + ModeIter { + gop: self, + current: 0, + max: self.mode.max_mode, + } + } + + /// Sets the video device into the specified mode, clearing visible portions + /// of the output display to black. + /// + /// This function will invalidate the current framebuffer. + pub fn set_mode(&mut self, mode: &Mode) -> Result { + (self.set_mode)(self, mode.index).into() + } + + /// Performs a blt (block transfer) operation on the frame buffer. + /// + /// Every operation requires different parameters. + pub fn blt(&mut self, op: BltOp) -> Result { + // Demultiplex the operation type. + unsafe { + match op { + BltOp::VideoFill { + color, + dest: (dest_x, dest_y), + dims: (width, height), + } => { + self.check_framebuffer_region((dest_x, dest_y), (width, height)); + (self.blt)( + self, + &color as *const _ as *mut _, + 0, + 0, + 0, + dest_x, + dest_y, + width, + height, + 0, + ) + .into() + } + BltOp::VideoToBltBuffer { + buffer, + src: (src_x, src_y), + dest: dest_region, + dims: (width, height), + } => { + self.check_framebuffer_region((src_x, src_y), (width, height)); + self.check_blt_buffer_region(dest_region, (width, height), buffer.len()); + match dest_region { + BltRegion::Full => (self.blt)( + self, + buffer.as_mut_ptr(), + 1, + src_x, + src_y, + 0, + 0, + width, + height, + 0, + ) + .into(), + BltRegion::SubRectangle { + coords: (dest_x, dest_y), + px_stride, + } => (self.blt)( + self, + buffer.as_mut_ptr(), + 1, + src_x, + src_y, + dest_x, + dest_y, + width, + height, + px_stride * core::mem::size_of::(), + ) + .into(), + } + } + BltOp::BufferToVideo { + buffer, + src: src_region, + dest: (dest_x, dest_y), + dims: (width, height), + } => { + self.check_blt_buffer_region(src_region, (width, height), buffer.len()); + self.check_framebuffer_region((dest_x, dest_y), (width, height)); + match src_region { + BltRegion::Full => (self.blt)( + self, + buffer.as_ptr() as *mut _, + 2, + 0, + 0, + dest_x, + dest_y, + width, + height, + 0, + ) + .into(), + BltRegion::SubRectangle { + coords: (src_x, src_y), + px_stride, + } => (self.blt)( + self, + buffer.as_ptr() as *mut _, + 2, + src_x, + src_y, + dest_x, + dest_y, + width, + height, + px_stride * core::mem::size_of::(), + ) + .into(), + } + } + BltOp::VideoToVideo { + src: (src_x, src_y), + dest: (dest_x, dest_y), + dims: (width, height), + } => { + self.check_framebuffer_region((src_x, src_y), (width, height)); + self.check_framebuffer_region((dest_x, dest_y), (width, height)); + (self.blt)( + self, + ptr::null_mut(), + 3, + src_x, + src_y, + dest_x, + dest_y, + width, + height, + 0, + ) + .into() + } + } + } + } + + /// Memory-safety check for accessing a region of the framebuffer + fn check_framebuffer_region(&self, coords: (usize, usize), dims: (usize, usize)) { + let (width, height) = self.current_mode_info().resolution(); + assert!( + coords.0.saturating_add(dims.0) <= width, + "Horizontal framebuffer coordinate out of bounds" + ); + assert!( + coords.1.saturating_add(dims.1) <= height, + "Vertical framebuffer coordinate out of bounds" + ); + } + + /// Memory-safety check for accessing a region of a user-provided buffer + fn check_blt_buffer_region(&self, region: BltRegion, dims: (usize, usize), buf_length: usize) { + match region { + BltRegion::Full => assert!( + dims.1.saturating_mul(dims.0) <= buf_length, + "BltBuffer access out of bounds" + ), + BltRegion::SubRectangle { + coords: (x, y), + px_stride, + } => { + assert!( + x.saturating_add(dims.0) <= px_stride, + "Horizontal BltBuffer coordinate out of bounds" + ); + assert!( + y.saturating_add(dims.1).saturating_mul(px_stride) <= buf_length, + "Vertical BltBuffer coordinate out of bounds" + ); + } + } + } + + /// Returns the frame buffer information for the current mode. + pub fn current_mode_info(&self) -> ModeInfo { + *self.mode.info + } + + /// Access the frame buffer directly + pub fn frame_buffer(&mut self) -> FrameBuffer { + assert!( + self.mode.info.format != PixelFormat::BltOnly, + "Cannot access the framebuffer in a Blt-only mode" + ); + let base = self.mode.fb_address as *mut u8; + let size = self.mode.fb_size; + + FrameBuffer { + base, + size, + _lifetime: PhantomData, + } + } +} + +#[repr(C)] +struct ModeData<'info> { + // Number of modes which the GOP supports. + max_mode: u32, + // Current mode. + mode: u32, + // Information about the current mode. + info: &'info ModeInfo, + // Size of the above structure. + info_sz: usize, + // Physical address of the frame buffer. + fb_address: u64, + // Size in bytes. Equal to (pixel size) * height * stride. + fb_size: usize, +} + +/// Represents the format of the pixels in a frame buffer. +#[derive(Debug, Copy, Clone, Eq, PartialEq)] +#[repr(u32)] +pub enum PixelFormat { + /// Each pixel is 32-bit long, with 24-bit RGB, and the last byte is reserved. + Rgb = 0, + /// Each pixel is 32-bit long, with 24-bit BGR, and the last byte is reserved. + Bgr, + /// Custom pixel format, check the associated bitmask. + Bitmask, + /// The graphics mode does not support drawing directly to the frame buffer. + /// + /// This means you will have to use the `blt` function which will + /// convert the graphics data to the device's internal pixel format. + BltOnly, + // SAFETY: UEFI also defines a PixelFormatMax variant, and states that all + // valid enum values are guaranteed to be smaller. Since that is the + // case, adding a new enum variant would be a breaking change, so it + // is safe to model this C enum as a Rust enum. +} + +/// Bitmask used to indicate which bits of a pixel represent a given color. +#[derive(Debug, Copy, Clone, Eq, PartialEq)] +#[repr(C)] +pub struct PixelBitmask { + /// The bits indicating the red channel. + pub red: u32, + /// The bits indicating the green channel. + pub green: u32, + /// The bits indicating the blue channel. + pub blue: u32, + /// The reserved bits, which are ignored by the video hardware. + pub reserved: u32, +} + +/// Represents a graphics mode compatible with a given graphics device. +pub struct Mode { + index: u32, + info_sz: usize, + info: ModeInfo, +} + +impl Mode { + /// The size of the info structure in bytes. + /// + /// Newer versions of the spec might add extra information, in a backwards compatible way. + pub fn info_size(&self) -> usize { + self.info_sz + } + + /// Returns a reference to the mode info structure. + pub fn info(&self) -> &ModeInfo { + &self.info + } +} + +/// Information about a graphics output mode. +#[derive(Debug, Copy, Clone)] +#[repr(C)] +pub struct ModeInfo { + // The only known version, associated with the current spec, is 0. + version: u32, + hor_res: u32, + ver_res: u32, + format: PixelFormat, + mask: PixelBitmask, + stride: u32, +} + +impl ModeInfo { + /// Returns the (horizontal, vertical) resolution. + /// + /// On desktop monitors, this usually means (width, height). + pub fn resolution(&self) -> (usize, usize) { + (self.hor_res as usize, self.ver_res as usize) + } + + /// Returns the format of the frame buffer. + pub fn pixel_format(&self) -> PixelFormat { + self.format + } + + /// Returns the bitmask of the custom pixel format, if available. + pub fn pixel_bitmask(&self) -> Option { + match self.format { + PixelFormat::Bitmask => Some(self.mask), + _ => None, + } + } + + /// Returns the number of pixels per scanline. + /// + /// Due to performance reasons, the stride might not be equal to the width, + /// instead the stride might be bigger for better alignment. + pub fn stride(&self) -> usize { + self.stride as usize + } +} + +/// Iterator for graphics modes. +struct ModeIter<'gop> { + gop: &'gop GraphicsOutput<'gop>, + current: u32, + max: u32, +} + +impl<'gop> Iterator for ModeIter<'gop> { + type Item = Mode; + + fn next(&mut self) -> Option { + let index = self.current; + if index < self.max { + let m = self.gop.query_mode(index); + self.current += 1; + + m.ok().or_else(|| self.next()) + } else { + None + } + } + + fn size_hint(&self) -> (usize, Option) { + let size = (self.max - self.current) as usize; + (size, Some(size)) + } +} + +impl ExactSizeIterator for ModeIter<'_> {} + +/// Format of pixel data used for blitting. +/// +/// This is a BGR 24-bit format with an 8-bit padding, to keep each pixel 32-bit in size. +#[allow(missing_docs)] +#[derive(Debug, Copy, Clone)] +#[repr(C)] +pub struct BltPixel { + pub blue: u8, + pub green: u8, + pub red: u8, + _reserved: u8, +} + +impl BltPixel { + /// Create a new pixel from RGB values. + pub fn new(red: u8, green: u8, blue: u8) -> Self { + Self { + red, + green, + blue, + _reserved: 0, + } + } +} + +impl From for BltPixel { + fn from(color: u32) -> Self { + Self { + blue: (color & 0x00_00_FF) as u8, + green: ((color & 0x00_FF_00) >> 8) as u8, + red: ((color & 0xFF_00_00) >> 16) as u8, + _reserved: 0, + } + } +} + +/// Region of the `BltBuffer` which we are operating on +/// +/// Some `Blt` operations can operate on either the full `BltBuffer` or a +/// sub-rectangle of it, but require the stride to be known in the latter case. +#[derive(Clone, Copy, Debug)] +pub enum BltRegion { + /// Operate on the full `BltBuffer` + Full, + + /// Operate on a sub-rectangle of the `BltBuffer` + SubRectangle { + /// Coordinate of the rectangle in the `BltBuffer` + coords: (usize, usize), + + /// Stride (length of each row of the `BltBuffer`) in **pixels** + px_stride: usize, + }, +} + +/// Blit operation to perform. +#[derive(Debug)] +pub enum BltOp<'buf> { + /// Fills a rectangle of video display with a pixel color. + VideoFill { + /// The color to fill with. + color: BltPixel, + /// The X / Y coordinates of the destination rectangle. + dest: (usize, usize), + /// The width / height of the rectangle. + dims: (usize, usize), + }, + /// Reads data from the video display to the buffer. + VideoToBltBuffer { + /// Buffer into which to copy data. + buffer: &'buf mut [BltPixel], + /// Coordinates of the source rectangle, in the frame buffer. + src: (usize, usize), + /// Location of the destination rectangle in the user-provided buffer + dest: BltRegion, + /// Width / height of the rectangles. + dims: (usize, usize), + }, + /// Write data from the buffer to the video rectangle. + /// Delta must be the stride (count of bytes in a row) of the buffer. + BufferToVideo { + /// Buffer from which to copy data. + buffer: &'buf [BltPixel], + /// Location of the source rectangle in the user-provided buffer. + src: BltRegion, + /// Coordinates of the destination rectangle, in the frame buffer. + dest: (usize, usize), + /// Width / height of the rectangles. + dims: (usize, usize), + }, + /// Copy from the source rectangle in video memory to + /// the destination rectangle, also in video memory. + VideoToVideo { + /// Coordinates of the source rectangle, in the frame buffer. + src: (usize, usize), + /// Coordinates of the destination rectangle, also in the frame buffer. + dest: (usize, usize), + /// Width / height of the rectangles. + dims: (usize, usize), + }, +} + +/// Direct access to a memory-mapped frame buffer +pub struct FrameBuffer<'gop> { + base: *mut u8, + size: usize, + _lifetime: PhantomData<&'gop mut u8>, +} + +impl<'gop> FrameBuffer<'gop> { + /// Access the raw framebuffer pointer + /// + /// To use this pointer safely and correctly, you must... + /// - Honor the pixel format and stride specified by the mode info + /// - Keep memory accesses in bound + /// - Use volatile reads and writes + /// - Make sure that the pointer does not outlive the FrameBuffer + pub fn as_mut_ptr(&mut self) -> *mut u8 { + self.base + } + + /// Query the framebuffer size in bytes + pub fn size(&self) -> usize { + self.size + } + + /// Modify the i-th byte of the frame buffer + /// + /// # Safety + /// + /// This operation is unsafe because... + /// - You must honor the pixel format and stride specified by the mode info + /// - There is no bound checking on memory accesses in release mode + #[inline] + pub unsafe fn write_byte(&mut self, index: usize, value: u8) { + debug_assert!(index < self.size, "Frame buffer accessed out of bounds"); + self.base.add(index).write_volatile(value) + } + + /// Read the i-th byte of the frame buffer + /// + /// # Safety + /// + /// This operation is unsafe because... + /// - You must honor the pixel format and stride specified by the mode info + /// - There is no bound checking on memory accesses in release mode + #[inline] + pub unsafe fn read_byte(&self, index: usize) -> u8 { + debug_assert!(index < self.size, "Frame buffer accessed out of bounds"); + self.base.add(index).read_volatile() + } + + /// Write a value in the frame buffer, starting at the i-th byte + /// + /// We only recommend using this method with [u8; N] arrays. Once Rust has + /// const generics, it will be deprecated and replaced with a write_bytes() + /// method that only accepts [u8; N] input. + /// + /// # Safety + /// + /// This operation is unsafe because... + /// - It is your reponsibility to make sure that the value type makes sense + /// - You must honor the pixel format and stride specified by the mode info + /// - There is no bound checking on memory accesses in release mode + #[inline] + pub unsafe fn write_value(&mut self, index: usize, value: T) { + debug_assert!( + index.saturating_add(mem::size_of::()) <= self.size, + "Frame buffer accessed out of bounds" + ); + let ptr = self.base.add(index).cast::(); + ptr.write_volatile(value) + } + + /// Read a value from the frame buffer, starting at the i-th byte + /// + /// We only recommend using this method with [u8; N] arrays. Once Rust has + /// const generics, it will be deprecated and replaced with a read_bytes() + /// method that only accepts [u8; N] input. + /// + /// # Safety + /// + /// This operation is unsafe because... + /// - It is your reponsibility to make sure that the value type makes sense + /// - You must honor the pixel format and stride specified by the mode info + /// - There is no bound checking on memory accesses in release mode + #[inline] + pub unsafe fn read_value(&self, index: usize) -> T { + debug_assert!( + index.saturating_add(mem::size_of::()) <= self.size, + "Frame buffer accessed out of bounds" + ); + (self.base.add(index) as *const T).read_volatile() + } +} diff --git a/src/proto/console/mod.rs b/src/proto/console/mod.rs new file mode 100644 index 000000000..636eb77b4 --- /dev/null +++ b/src/proto/console/mod.rs @@ -0,0 +1,9 @@ +//! Console support protocols. +//! +//! The console represents the various input and output methods +//! used by the user to interact with the early boot platform. + +pub mod gop; +pub mod pointer; +pub mod serial; +pub mod text; diff --git a/src/proto/console/pointer/mod.rs b/src/proto/console/pointer/mod.rs new file mode 100644 index 000000000..52750e7a0 --- /dev/null +++ b/src/proto/console/pointer/mod.rs @@ -0,0 +1,83 @@ +//! Pointer device access. + +use crate::proto::Protocol; +use crate::{unsafe_guid, Event, Result, Status}; +use core::mem::MaybeUninit; + +/// Provides information about a pointer device. +#[repr(C)] +#[unsafe_guid("31878c87-0b75-11d5-9a4f-0090273fc14d")] +#[derive(Protocol)] +pub struct Pointer<'boot> { + reset: extern "efiapi" fn(this: &mut Pointer, ext_verif: bool) -> Status, + get_state: extern "efiapi" fn(this: &Pointer, state: *mut PointerState) -> Status, + wait_for_input: Event, + mode: &'boot PointerMode, +} + +impl<'boot> Pointer<'boot> { + /// Resets the pointer device hardware. + /// + /// The `extended_verification` parameter is used to request that UEFI + /// performs an extended check and reset of the input device. + /// + /// # Errors + /// + /// - `DeviceError` if the device is malfunctioning and cannot be reset. + pub fn reset(&mut self, extended_verification: bool) -> Result { + (self.reset)(self, extended_verification).into() + } + + /// Retrieves the pointer device's current state, if a state change occured + /// since the last time this function was called. + /// + /// Use `wait_for_input_event()` with the `BootServices::wait_for_event()` + /// interface in order to wait for input from the pointer device. + /// + /// # Errors + /// - `DeviceError` if there was an issue with the pointer device. + pub fn read_state(&mut self) -> Result> { + let mut pointer_state = MaybeUninit::::uninit(); + + match (self.get_state)(self, pointer_state.as_mut_ptr()) { + Status::NOT_READY => Ok(None), + other => other.into_with_val(|| unsafe { Some(pointer_state.assume_init()) }), + } + } + + /// Event to be used with `BootServices::wait_for_event()` in order to wait + /// for input from the pointer device + pub fn wait_for_input_event(&self) -> &Event { + &self.wait_for_input + } + + /// Returns a reference to the pointer device information. + pub fn mode(&self) -> &PointerMode { + self.mode + } +} + +/// Information about this pointer device. +#[derive(Debug, Copy, Clone)] +#[repr(C)] +pub struct PointerMode { + /// The pointer device's resolution on the X/Y/Z axis in counts/mm. + /// If a value is 0, then the device does _not_ support that axis. + pub resolution: (u64, u64, u64), + /// Whether the devices has a left button / right button. + pub has_button: (bool, bool), +} + +/// The relative change in the pointer's state. +#[derive(Debug, Copy, Clone)] +#[repr(C)] +pub struct PointerState { + /// The relative movement on the X/Y/Z axis. + /// + /// If `PointerMode` indicates an axis is not supported, it must be ignored. + pub relative_movement: (i32, i32, i32), + /// Whether the left / right mouse button is currently pressed. + /// + /// If `PointerMode` indicates a button is not supported, it must be ignored. + pub button: (bool, bool), +} diff --git a/src/proto/console/serial.rs b/src/proto/console/serial.rs new file mode 100644 index 000000000..79044c572 --- /dev/null +++ b/src/proto/console/serial.rs @@ -0,0 +1,232 @@ +//! Abstraction over byte stream devices, also known as serial I/O devices. + +use core::fmt::Write; + +use crate::proto::Protocol; +use crate::{unsafe_guid, Result, Status}; +use bitflags::bitflags; + +/// Provides access to a serial I/O device. +/// +/// This can include standard UART devices, serial ports over a USB interface, +/// or any other character-based communication device. +/// +/// Since UEFI drivers are implemented through polling, if you fail to regularly +/// check for input/output, some data might be lost. +#[repr(C)] +#[unsafe_guid("bb25cf6f-f1d4-11d2-9a0c-0090273fc1fd")] +#[derive(Protocol)] +pub struct Serial<'boot> { + // Revision of this protocol, only 1.0 is currently defined. + // Future versions will be backwards compatible. + revision: u32, + reset: extern "efiapi" fn(&mut Serial) -> Status, + set_attributes: extern "efiapi" fn( + &Serial, + baud_rate: u64, + receive_fifo_depth: u32, + timeout: u32, + parity: Parity, + data_bits: u8, + stop_bits_type: StopBits, + ) -> Status, + set_control_bits: extern "efiapi" fn(&mut Serial, ControlBits) -> Status, + get_control_bits: extern "efiapi" fn(&Serial, &mut ControlBits) -> Status, + write: unsafe extern "efiapi" fn(&mut Serial, &mut usize, *const u8) -> Status, + read: unsafe extern "efiapi" fn(&mut Serial, &mut usize, *mut u8) -> Status, + io_mode: &'boot IoMode, +} + +impl<'boot> Serial<'boot> { + /// Reset the device. + pub fn reset(&mut self) -> Result { + (self.reset)(self).into() + } + + /// Returns the current I/O mode. + pub fn io_mode(&self) -> &IoMode { + self.io_mode + } + + /// Sets the device's new attributes. + /// + /// The given `IoMode` will become the device's new `IoMode`, + /// with some exceptions: + /// + /// - `control_mask` is ignored, since it's a read-only field; + /// + /// - values set to `0` / `Default` will be filled with the device's + /// default parameters + /// + /// - if either `baud_rate` or `receive_fifo_depth` is less than + /// the device's minimum, an error will be returned; + /// this value will be rounded down to the nearest value supported by the device; + pub fn set_attributes(&mut self, mode: &IoMode) -> Result { + (self.set_attributes)( + self, + mode.baud_rate, + mode.receive_fifo_depth, + mode.timeout, + mode.parity, + mode.data_bits as u8, + mode.stop_bits, + ) + .into() + } + + /// Retrieve the device's current control bits. + pub fn get_control_bits(&self) -> Result { + let mut bits = ControlBits::empty(); + (self.get_control_bits)(self, &mut bits).into_with_val(|| bits) + } + + /// Sets the device's new control bits. + /// + /// Not all bits can be modified with this function. A mask of the allowed + /// bits is stored in the [`ControlBits::SETTABLE`] constant. + pub fn set_control_bits(&mut self, bits: ControlBits) -> Result { + (self.set_control_bits)(self, bits).into() + } + + /// Reads data from this device. + /// + /// This operation will block until the buffer has been filled with data or + /// an error occurs. In the latter case, the error will indicate how many + /// bytes were actually read from the device. + pub fn read(&mut self, data: &mut [u8]) -> Result<(), usize> { + let mut buffer_size = data.len(); + unsafe { (self.read)(self, &mut buffer_size, data.as_mut_ptr()) }.into_with( + || debug_assert_eq!(buffer_size, data.len()), + |_| buffer_size, + ) + } + + /// Writes data to this device. + /// + /// This operation will block until the data has been fully written or an + /// error occurs. In the latter case, the error will indicate how many bytes + /// were actually written to the device. + pub fn write(&mut self, data: &[u8]) -> Result<(), usize> { + let mut buffer_size = data.len(); + unsafe { (self.write)(self, &mut buffer_size, data.as_ptr()) }.into_with( + || debug_assert_eq!(buffer_size, data.len()), + |_| buffer_size, + ) + } +} + +impl<'boot> Write for Serial<'boot> { + fn write_str(&mut self, s: &str) -> core::fmt::Result { + self.write(s.as_bytes()).map_err(|_| core::fmt::Error) + } +} + +/// Structure representing the device's current parameters. +/// +/// The default values for all UART-like devices is: +/// - 115,200 baud +/// - 1 byte receive FIFO +/// - 1'000'000 microsecond timeout +/// - no parity +/// - 8 data bits +/// - 1 stop bit +/// +/// The software is responsible for flow control. +#[derive(Debug, Copy, Clone)] +#[repr(C)] +pub struct IoMode { + /// Bitmask of the control bits that this device supports. + pub control_mask: ControlBits, + /// If applicable, the number of microseconds to wait before assuming an + /// operation timed out. + pub timeout: u32, + /// Device's baud rate, or 0 if unknown. + pub baud_rate: u64, + /// Size in character's of the device's buffer. + pub receive_fifo_depth: u32, + /// Number of data bits in each character. + pub data_bits: u32, + /// If applicable, the parity that is computed or checked for each character. + pub parity: Parity, + /// If applicable, the number of stop bits per character. + pub stop_bits: StopBits, +} + +bitflags! { + /// The control bits of a device. These are defined in the [RS-232] standard. + /// + /// [RS-232]: https://en.wikipedia.org/wiki/RS-232 + pub struct ControlBits: u32 { + /// Clear to send + const CLEAR_TO_SEND = 0x10; + /// Data set ready + const DATA_SET_READY = 0x20; + /// Indicates that a phone line is ringing + const RING_INDICATE = 0x40; + /// Indicates the connection is still connected + const CARRIER_DETECT = 0x80; + /// The input buffer is empty + const INPUT_BUFFER_EMPTY = 0x100; + /// The output buffer is empty + const OUTPUT_BUFFER_EMPTY = 0x200; + + /// Terminal is ready for communications + const DATA_TERMINAL_READY = 0x1; + /// Request the device to send data + const REQUEST_TO_SEND = 0x2; + /// Enable hardware loop-back + const HARDWARE_LOOPBACK_ENABLE = 0x1000; + /// Enable software loop-back + const SOFTWARE_LOOPBACK_ENABLE = 0x2000; + /// Allow the hardware to handle flow control + const HARDWARE_FLOW_CONTROL_ENABLE = 0x4000; + + /// Bitmask of the control bits that can be set. + /// + /// Up to date as of UEFI 2.7 / Serial protocol v1 + const SETTABLE = + ControlBits::DATA_TERMINAL_READY.bits + | ControlBits::REQUEST_TO_SEND.bits + | ControlBits::HARDWARE_LOOPBACK_ENABLE.bits + | ControlBits::SOFTWARE_LOOPBACK_ENABLE.bits + | ControlBits::HARDWARE_FLOW_CONTROL_ENABLE.bits; + } +} + +/// The parity of the device. +#[derive(Debug, Copy, Clone, Eq, PartialEq)] +#[repr(u32)] +pub enum Parity { + /// Device default + Default = 0, + /// No parity + None, + /// Even parity + Even, + /// Odd parity + Odd, + /// Mark parity + Mark, + /// Space parity + Space, + // SAFETY: The serial protocol is very old, and new parity modes are very + // unlikely to be added at this point in time. Therefore, modeling + // this C enum as a Rust enum seems safe. +} + +/// Number of stop bits per character. +#[derive(Debug, Copy, Clone, Eq, PartialEq)] +#[repr(u32)] +pub enum StopBits { + /// Device default + Default = 0, + /// 1 stop bit + One, + /// 1.5 stop bits + OneFive, + /// 2 stop bits + Two, + // SAFETY: The serial protocol is very old, and new stop bit modes are very + // unlikely to be added at this point in time. Therefore, modeling + // this C enum as a Rust enum seems safe. +} diff --git a/src/proto/console/text/input.rs b/src/proto/console/text/input.rs new file mode 100644 index 000000000..0009c39d6 --- /dev/null +++ b/src/proto/console/text/input.rs @@ -0,0 +1,144 @@ +use crate::proto::Protocol; +use crate::{unsafe_guid, Char16, Event, Result, Status}; +use core::mem::MaybeUninit; + +/// Interface for text-based input devices. +#[repr(C)] +#[unsafe_guid("387477c1-69c7-11d2-8e39-00a0c969723b")] +#[derive(Protocol)] +pub struct Input { + reset: extern "efiapi" fn(this: &mut Input, extended: bool) -> Status, + read_key_stroke: extern "efiapi" fn(this: &mut Input, key: *mut RawKey) -> Status, + wait_for_key: Event, +} + +impl Input { + /// Resets the input device hardware. + /// + /// The `extended_verification` parameter is used to request that UEFI + /// performs an extended check and reset of the input device. + /// + /// # Errors + /// + /// - `DeviceError` if the device is malfunctioning and cannot be reset. + pub fn reset(&mut self, extended_verification: bool) -> Result { + (self.reset)(self, extended_verification).into() + } + + /// Reads the next keystroke from the input device, if any. + /// + /// Use `wait_for_key_event()` with the `BootServices::wait_for_event()` + /// interface in order to wait for a key to be pressed. + /// + /// # Errors + /// + /// - `DeviceError` if there was an issue with the input device + pub fn read_key(&mut self) -> Result> { + let mut key = MaybeUninit::::uninit(); + + match (self.read_key_stroke)(self, key.as_mut_ptr()) { + Status::NOT_READY => Ok(None), + other => other.into_with_val(|| Some(unsafe { key.assume_init() }.into())), + } + } + + /// Event to be used with `BootServices::wait_for_event()` in order to wait + /// for a key to be available + pub fn wait_for_key_event(&self) -> &Event { + &self.wait_for_key + } +} + +/// A key read from the console (high-level version) +#[derive(Debug, Copy, Clone, Eq, PartialEq)] +pub enum Key { + /// The key is associated with a printable Unicode character + Printable(Char16), + + /// The key is special (arrow, function, multimedia...) + Special(ScanCode), +} + +impl From for Key { + fn from(k: RawKey) -> Key { + if k.scan_code == ScanCode::NULL { + Key::Printable(k.unicode_char) + } else { + Key::Special(k.scan_code) + } + } +} + +/// A key read from the console (UEFI version) +#[repr(C)] +pub struct RawKey { + /// The key's scan code. + /// or 0 if printable + pub scan_code: ScanCode, + /// Associated Unicode character, + /// or 0 if not printable. + pub unicode_char: Char16, +} + +newtype_enum! { +/// A keyboard scan code +/// +/// Codes 0x8000 -> 0xFFFF are reserved for future OEM extensibility, therefore +/// this C enum is _not_ safe to model as a Rust enum (where the compiler must +/// know about all variants at compile time). +pub enum ScanCode: u16 => #[allow(missing_docs)] { + /// Null scan code, indicates that the Unicode character should be used. + NULL = 0x00, + /// Move cursor up 1 row. + UP = 0x01, + /// Move cursor down 1 row. + DOWN = 0x02, + /// Move cursor right 1 column. + RIGHT = 0x03, + /// Move cursor left 1 column. + LEFT = 0x04, + HOME = 0x05, + END = 0x06, + INSERT = 0x07, + DELETE = 0x08, + PAGE_UP = 0x09, + PAGE_DOWN = 0x0A, + FUNCTION_1 = 0x0B, + FUNCTION_2 = 0x0C, + FUNCTION_3 = 0x0D, + FUNCTION_4 = 0x0E, + FUNCTION_5 = 0x0F, + FUNCTION_6 = 0x10, + FUNCTION_7 = 0x11, + FUNCTION_8 = 0x12, + FUNCTION_9 = 0x13, + FUNCTION_10 = 0x14, + FUNCTION_11 = 0x15, + FUNCTION_12 = 0x16, + ESCAPE = 0x17, + + FUNCTION_13 = 0x68, + FUNCTION_14 = 0x69, + FUNCTION_15 = 0x6A, + FUNCTION_16 = 0x6B, + FUNCTION_17 = 0x6C, + FUNCTION_18 = 0x6D, + FUNCTION_19 = 0x6E, + FUNCTION_20 = 0x6F, + FUNCTION_21 = 0x70, + FUNCTION_22 = 0x71, + FUNCTION_23 = 0x72, + FUNCTION_24 = 0x73, + + MUTE = 0x7F, + VOLUME_UP = 0x80, + VOLUME_DOWN = 0x81, + + BRIGHTNESS_UP = 0x100, + BRIGHTNESS_DOWN = 0x101, + SUSPEND = 0x102, + HIBERNATE = 0x103, + TOGGLE_DISPLAY = 0x104, + RECOVERY = 0x105, + EJECT = 0x106, +}} diff --git a/src/proto/console/text/mod.rs b/src/proto/console/text/mod.rs new file mode 100644 index 000000000..ebcd3fcec --- /dev/null +++ b/src/proto/console/text/mod.rs @@ -0,0 +1,7 @@ +//! Text I/O. + +mod input; +pub use self::input::{Input, Key, ScanCode}; + +mod output; +pub use self::output::{Color, Output, OutputMode}; diff --git a/src/proto/console/text/output.rs b/src/proto/console/text/output.rs new file mode 100644 index 000000000..5f298de78 --- /dev/null +++ b/src/proto/console/text/output.rs @@ -0,0 +1,348 @@ +use crate::proto::Protocol; +use crate::{unsafe_guid, CStr16, Char16, Result, ResultExt, Status}; +use core::fmt; +use core::fmt::{Debug, Formatter}; + +/// Interface for text-based output devices. +/// +/// It implements the fmt::Write trait, so you can use it to print text with +/// standard Rust constructs like the `write!()` and `writeln!()` macros. +/// +/// # Accessing `Output` protocol +/// +/// The standard output and standard error output protocols can be accessed +/// using [`SystemTable::stdout`] and [`SystemTable::stderr`], respectively. +/// +/// An `Output` protocol can also be accessed like any other UEFI protocol. +/// See the [`BootServices`] documentation for more details of how to open a +/// protocol. +/// +/// [`SystemTable::stdout`]: crate::table::SystemTable::stdout +/// [`SystemTable::stderr`]: crate::table::SystemTable::stderr +/// [`BootServices`]: crate::table::boot::BootServices#accessing-protocols +#[repr(C)] +#[unsafe_guid("387477c2-69c7-11d2-8e39-00a0c969723b")] +#[derive(Protocol)] +pub struct Output<'boot> { + reset: extern "efiapi" fn(this: &Output, extended: bool) -> Status, + output_string: unsafe extern "efiapi" fn(this: &Output, string: *const Char16) -> Status, + test_string: unsafe extern "efiapi" fn(this: &Output, string: *const Char16) -> Status, + query_mode: extern "efiapi" fn( + this: &Output, + mode: usize, + columns: &mut usize, + rows: &mut usize, + ) -> Status, + set_mode: extern "efiapi" fn(this: &mut Output, mode: usize) -> Status, + set_attribute: extern "efiapi" fn(this: &mut Output, attribute: usize) -> Status, + clear_screen: extern "efiapi" fn(this: &mut Output) -> Status, + set_cursor_position: extern "efiapi" fn(this: &mut Output, column: usize, row: usize) -> Status, + enable_cursor: extern "efiapi" fn(this: &mut Output, visible: bool) -> Status, + data: &'boot OutputData, +} + +impl<'boot> Output<'boot> { + /// Resets and clears the text output device hardware. + pub fn reset(&mut self, extended: bool) -> Result { + (self.reset)(self, extended).into() + } + + /// Clears the output screen. + /// + /// The background is set to the current background color. + /// The cursor is moved to (0, 0). + pub fn clear(&mut self) -> Result { + (self.clear_screen)(self).into() + } + + /// Writes a string to the output device. + pub fn output_string(&mut self, string: &CStr16) -> Result { + unsafe { (self.output_string)(self, string.as_ptr()) }.into() + } + + /// Writes a string to the output device. If the string contains + /// unknown characters that cannot be rendered they will be silently + /// skipped. + pub fn output_string_lossy(&mut self, string: &CStr16) -> Result { + self.output_string(string).handle_warning(|err| { + if err.status() == Status::WARN_UNKNOWN_GLYPH { + Ok(()) + } else { + Err(err) + } + }) + } + + /// Checks if a string contains only supported characters. + /// + /// UEFI applications are encouraged to try to print a string even if it contains + /// some unsupported characters. + pub fn test_string(&mut self, string: &CStr16) -> Result { + match unsafe { (self.test_string)(self, string.as_ptr()) } { + Status::UNSUPPORTED => Ok(false), + other => other.into_with_val(|| true), + } + } + + /// Returns an iterator of all supported text modes. + // TODO: Bring back impl Trait once the story around bounds improves + pub fn modes<'out>(&'out mut self) -> OutputModeIter<'out, 'boot> { + let max = self.data.max_mode as usize; + OutputModeIter { + output: self, + current: 0, + max, + } + } + + /// Returns the width (column count) and height (row count) of a text mode. + /// + /// Devices are required to support at least an 80x25 text mode and to + /// assign index 0 to it. If 80x50 is supported, then it will be mode 1, + /// otherwise querying for mode 1 will return the `Unsupported` error. + /// Modes 2+ will describe other text modes supported by the device. + /// + /// If you want to iterate over all text modes supported by the device, + /// consider using the iterator produced by `modes()` as a more ergonomic + /// alternative to this method. + fn query_mode(&self, index: usize) -> Result<(usize, usize)> { + let (mut columns, mut rows) = (0, 0); + (self.query_mode)(self, index, &mut columns, &mut rows).into_with_val(|| (columns, rows)) + } + + /// Returns the the current text mode. + pub fn current_mode(&self) -> Result> { + match self.data.mode { + -1 => Ok(None), + n if n >= 0 => { + let index = n as usize; + self.query_mode(index) + .map(|dims| Some(OutputMode { index, dims })) + } + _ => unreachable!(), + } + } + + /// Sets a mode as current. + pub fn set_mode(&mut self, mode: OutputMode) -> Result { + (self.set_mode)(self, mode.index).into() + } + + /// Returns whether the cursor is currently shown or not. + pub fn cursor_visible(&self) -> bool { + self.data.cursor_visible + } + + /// Make the cursor visible or invisible. + /// + /// The output device may not support this operation, in which case an + /// `Unsupported` error will be returned. + pub fn enable_cursor(&mut self, visible: bool) -> Result { + (self.enable_cursor)(self, visible).into() + } + + /// Returns the column and row of the cursor. + pub fn cursor_position(&self) -> (usize, usize) { + let column = self.data.cursor_column; + let row = self.data.cursor_row; + (column as usize, row as usize) + } + + /// Sets the cursor's position, relative to the top-left corner, which is (0, 0). + /// + /// This function will fail if the cursor's new position would exceed the screen's bounds. + pub fn set_cursor_position(&mut self, column: usize, row: usize) -> Result { + (self.set_cursor_position)(self, column, row).into() + } + + /// Sets the text and background colors for the console. + /// + /// Note that for the foreground color you can choose any color. + /// The background must be one of the first 8 colors. + pub fn set_color(&mut self, foreground: Color, background: Color) -> Result { + let fgc = foreground as usize; + let bgc = background as usize; + + assert!(bgc < 8, "An invalid background color was requested"); + + let attr = ((bgc & 0x7) << 4) | (fgc & 0xF); + (self.set_attribute)(self, attr).into() + } +} + +impl<'boot> fmt::Write for Output<'boot> { + fn write_str(&mut self, s: &str) -> fmt::Result { + // Allocate a small buffer on the stack. + const BUF_SIZE: usize = 128; + // Add 1 extra character for the null terminator. + let mut buf = [0u16; BUF_SIZE + 1]; + + let mut i = 0; + + // This closure writes the local buffer to the output and resets the buffer. + let mut flush_buffer = |buf: &mut [u16], i: &mut usize| { + buf[*i] = 0; + let codes = &buf[..=*i]; + *i = 0; + + let text = CStr16::from_u16_with_nul(codes).map_err(|_| fmt::Error)?; + + self.output_string(text).map_err(|_| fmt::Error) + }; + + // This closure converts a character to UCS-2 and adds it to the buffer, + // flushing it as necessary. + let mut add_char = |ch| { + // UEFI only supports UCS-2 characters, not UTF-16, + // so there are no multibyte characters. + buf[i] = ch; + i += 1; + + if i == BUF_SIZE { + flush_buffer(&mut buf, &mut i).map_err(|_| ucs2::Error::BufferOverflow) + } else { + Ok(()) + } + }; + + // This one converts Rust line feeds to UEFI line feeds beforehand + let add_ch = |ch| { + if ch == '\n' as u16 { + add_char('\r' as u16)?; + } + add_char(ch) + }; + + // Translate and write the input string, flushing the buffer when needed + ucs2::encode_with(s, add_ch).map_err(|_| fmt::Error)?; + + // Flush the remainder of the buffer + flush_buffer(&mut buf, &mut i) + } +} + +impl<'boot> Debug for Output<'boot> { + fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result { + f.debug_struct("Output") + .field("reset (fn ptr)", &(self.reset as *const u64)) + .field( + "output_string (fn ptr)", + &(self.output_string as *const u64), + ) + .field("test_string (fn ptr)", &(self.test_string as *const u64)) + .field("query_mode (fn ptr)", &(self.query_mode as *const u64)) + .field("set_mode (fn ptr)", &(self.set_mode as *const u64)) + .field( + "set_attribute (fn ptr)", + &(self.set_attribute as *const u64), + ) + .field("clear_screen (fn ptr)", &(self.clear_screen as *const u64)) + .field( + "set_cursor_position (fn ptr)", + &(self.set_cursor_position as *const u64), + ) + .field( + "enable_cursor (fn ptr)", + &(self.enable_cursor as *const u64), + ) + .field("data", &self.data) + .finish() + } +} + +/// The text mode (resolution) of the output device. +#[derive(Debug, Copy, Clone, Eq, PartialEq, Ord, PartialOrd)] +pub struct OutputMode { + index: usize, + dims: (usize, usize), +} + +impl OutputMode { + /// Returns the index of this mode. + #[inline] + pub fn index(&self) -> usize { + self.index + } + + /// Returns the width in columns. + #[inline] + pub fn columns(&self) -> usize { + self.dims.0 + } + + /// Returns the height in rows. + #[inline] + pub fn rows(&self) -> usize { + self.dims.1 + } +} + +/// An iterator of the text modes (possibly) supported by a device. +pub struct OutputModeIter<'out, 'boot: 'out> { + output: &'out mut Output<'boot>, + current: usize, + max: usize, +} + +impl<'out, 'boot> Iterator for OutputModeIter<'out, 'boot> { + type Item = OutputMode; + + fn next(&mut self) -> Option { + let index = self.current; + if index < self.max { + self.current += 1; + + if let Ok(dims) = self.output.query_mode(index) { + Some(OutputMode { index, dims }) + } else { + self.next() + } + } else { + None + } + } +} + +/// Additional data of the output device. +#[derive(Debug)] +#[repr(C)] +struct OutputData { + /// The number of modes supported by the device. + max_mode: i32, + /// The current output mode. + /// Negative index -1 is used to notify that no valid mode is configured + mode: i32, + /// The current character output attribute. + attribute: i32, + /// The cursor’s column. + cursor_column: i32, + /// The cursor’s row. + cursor_row: i32, + /// Whether the cursor is currently visible or not. + cursor_visible: bool, +} + +/// Colors for the UEFI console. +/// +/// All colors can be used as foreground colors. +/// The first 8 colors can also be used as background colors. +#[allow(missing_docs)] +#[derive(Debug, Copy, Clone)] +pub enum Color { + Black = 0, + Blue, + Green, + Cyan, + Red, + Magenta, + Brown, + LightGray, + DarkGray, + LightBlue, + LightGreen, + LightCyan, + LightRed, + LightMagenta, + Yellow, + White, +} diff --git a/src/proto/debug/context.rs b/src/proto/debug/context.rs new file mode 100644 index 000000000..188309e05 --- /dev/null +++ b/src/proto/debug/context.rs @@ -0,0 +1,644 @@ +// note from the spec: +// When the context record field is larger than the register being stored in it, the upper bits of the +// context record field are unused and ignored +/// Universal EFI_SYSTEM_CONTEXT defintion +/// This is passed to debug callbacks +#[repr(C)] +pub union SystemContext { + ebc: *mut SystemContextEBC, + riscv_32: *mut SystemContextRiscV32, + riscv_64: *mut SystemContextRiscV64, + riscv_128: *mut SystemContextRiscV128, + ia32: *mut SystemContextIA32, + x64: *mut SystemContextX64, + ipf: *mut SystemContextIPF, + arm: *mut SystemContextARM, + aarch64: *mut SystemContextAARCH64, +} + +/// System context for virtual EBC processors +#[repr(C)] +#[derive(Debug, Clone, Copy)] +pub struct SystemContextEBC { + r0: u64, + r1: u64, + r2: u64, + r3: u64, + r4: u64, + r5: u64, + r6: u64, + r7: u64, + flags: u64, + control_flags: u64, + ip: u64, +} + +#[repr(C)] +#[derive(Debug, Clone, Copy)] +pub struct SystemContextRiscV32 { + // Integer registers + zero: u32, + ra: u32, + sp: u32, + gp: u32, + tp: u32, + t0: u32, + t1: u32, + t2: u32, + s0fp: u32, + s1: u32, + a0: u32, + a1: u32, + a2: u32, + a3: u32, + a4: u32, + a5: u32, + a6: u32, + a7: u32, + s2: u32, + s3: u32, + s4: u32, + s5: u32, + s6: u32, + s7: u32, + s8: u32, + s9: u32, + s10: u32, + s11: u32, + t3: u32, + t4: u32, + t5: u32, + t6: u32, + // Float registers for F, D, and Q Standard Extensions + ft0: u128, + ft1: u128, + ft2: u128, + ft3: u128, + ft4: u128, + ft5: u128, + ft6: u128, + ft7: u128, + fs0: u128, + fs1: u128, + fa0: u128, + fa1: u128, + fa2: u128, + fa3: u128, + fa4: u128, + fa5: u128, + fa6: u128, + fa7: u128, + fs2: u128, + fs3: u128, + fs4: u128, + fs5: u128, + fs6: u128, + fs7: u128, + fs8: u128, + fs9: u128, + fs10: u128, + fs11: u128, + ft8: u128, + ft9: u128, + ft10: u128, + ft11: u128, +} + +#[repr(C)] +#[derive(Debug, Clone, Copy)] +pub struct SystemContextRiscV64 { + // Integer registers + zero: u64, + ra: u64, + sp: u64, + gp: u64, + tp: u64, + t0: u64, + t1: u64, + t2: u64, + s0fp: u64, + s1: u64, + a0: u64, + a1: u64, + a2: u64, + a3: u64, + a4: u64, + a5: u64, + a6: u64, + a7: u64, + s2: u64, + s3: u64, + s4: u64, + s5: u64, + s6: u64, + s7: u64, + s8: u64, + s9: u64, + s10: u64, + s11: u64, + t3: u64, + t4: u64, + t5: u64, + t6: u64, + // Floating registers for F, D, and Q Standard Extensions + ft0: u128, + ft1: u128, + ft2: u128, + ft3: u128, + ft4: u128, + ft5: u128, + ft6: u128, + ft7: u128, + fs0: u128, + fs1: u128, + fa0: u128, + fa1: u128, + fa2: u128, + fa3: u128, + fa4: u128, + fa5: u128, + fa6: u128, + fa7: u128, + fs2: u128, + fs3: u128, + fs4: u128, + fs5: u128, + fs6: u128, + fs7: u128, + fs8: u128, + fs9: u128, + fs10: u128, + fs11: u128, + ft8: u128, + ft9: u128, + ft10: u128, + ft11: u128, +} + +#[repr(C)] +#[derive(Debug, Clone, Copy)] +pub struct SystemContextRiscV128 { + // Integer registers + zero: u128, + ra: u128, + sp: u128, + gp: u128, + tp: u128, + t0: u128, + t1: u128, + t2: u128, + s0fp: u128, + s1: u128, + a0: u128, + a1: u128, + a2: u128, + a3: u128, + a4: u128, + a5: u128, + a6: u128, + a7: u128, + s2: u128, + s3: u128, + s4: u128, + s5: u128, + s6: u128, + s7: u128, + s8: u128, + s9: u128, + s10: u128, + s11: u128, + t3: u128, + t4: u128, + t5: u128, + t6: u128, + // Floating registers for F, D, and Q Standard Extensions + ft0: u128, + ft1: u128, + ft2: u128, + ft3: u128, + ft4: u128, + ft5: u128, + ft6: u128, + ft7: u128, + fs0: u128, + fs1: u128, + fa0: u128, + fa1: u128, + fa2: u128, + fa3: u128, + fa4: u128, + fa5: u128, + fa6: u128, + fa7: u128, + fs2: u128, + fs3: u128, + fs4: u128, + fs5: u128, + fs6: u128, + fs7: u128, + fs8: u128, + fs9: u128, + fs10: u128, + fs11: u128, + ft8: u128, + ft9: u128, + ft10: u128, + ft11: u128, +} + +/// System context for IA-32 processors (x86) +#[repr(C)] +#[derive(Debug, Clone, Copy)] +pub struct SystemContextIA32 { + exception_data: u32, // additional data pushed on the stack by some types of exceptions + fx_save_state: FxSaveStateIA32, + dr0: u32, + dr1: u32, + dr2: u32, + dr3: u32, + dr6: u32, + dr7: u32, + cr0: u32, + cr1: u32, // Noted as "Reserved" in the UEFI Specification + cr2: u32, + cr3: u32, + cr4: u32, + eflags: u32, + ldtr: u32, + tr: u32, + gdtr: [u32; 2], + idtr: [u32; 2], + eip: u32, + gs: u32, + fs: u32, + es: u32, + ds: u32, + cs: u32, + ss: u32, + edi: u32, + esi: u32, + ebp: u32, + esp: u32, + ebx: u32, + edx: u32, + ecx: u32, + eax: u32, +} + +/// FP / MMX / XMM registers for IA-32 +#[repr(C)] +#[derive(Debug, Clone, Copy)] +pub struct FxSaveStateIA32 { + fcw: u16, + fsw: u16, + ftw: u16, + opcode: u16, + eip: u32, + cs: u16, + reserved_1: u16, + data_offset: u32, + ds: u16, + reserved_2: [u8; 10], + st0mm0: [u8; 10], + reserved_3: [u8; 6], + st1mm1: [u8; 10], + reserved_4: [u8; 6], + st2mm2: [u8; 10], + reserved_5: [u8; 6], + st3mm3: [u8; 10], + reserved_6: [u8; 6], + st4mm4: [u8; 10], + reserved_7: [u8; 6], + st5mm5: [u8; 10], + reserved_8: [u8; 6], + st6mm6: [u8; 10], + reserved_9: [u8; 6], + st7mm7: [u8; 10], + reserved_10: [u8; 6], + xmm0: [u8; 16], + xmm1: [u8; 16], + xmm2: [u8; 16], + xmm3: [u8; 16], + xmm4: [u8; 16], + xmm5: [u8; 16], + xmm6: [u8; 16], + xmm7: [u8; 16], + reserved_11: [u8; 14 * 16], +} + +/// System context for x64 processors +#[repr(C)] +#[derive(Debug, Clone, Copy)] +pub struct SystemContextX64 { + exception_data: u64, // additional data pushed on the stack by some types of exceptions + fx_save_state: FxSaveStateX64, + dr0: u64, + dr1: u64, + dr2: u64, + dr3: u64, + dr6: u64, + dr7: u64, + cr0: u64, + cr1: u64, // Noted as "Reserved" in the UEFI Specification + cr2: u64, + cr3: u64, + cr4: u64, + cr8: u64, + rflags: u64, + ldtr: u64, + tr: u64, + gdtr: [u64; 2], + idtr: [u64; 2], + rip: u64, + gs: u64, + fs: u64, + es: u64, + ds: u64, + cs: u64, + ss: u64, + rdi: u64, + rsi: u64, + rbp: u64, + rsp: u64, + rbx: u64, + rdx: u64, + rcx: u64, + rax: u64, + r8: u64, + r9: u64, + r10: u64, + r11: u64, + r12: u64, + r13: u64, + r14: u64, + r15: u64, +} + +/// FP / MMX / XMM registers for X64 +#[repr(C)] +#[derive(Debug, Clone, Copy)] +pub struct FxSaveStateX64 { + fcw: u16, + fsw: u16, + ftw: u16, + opcode: u16, + rip: u64, + data_offset: u64, + reserved_1: [u8; 8], + st0mm0: [u8; 10], + reserved_2: [u8; 6], + st1mm1: [u8; 10], + reserved_3: [u8; 6], + st2mm2: [u8; 10], + reserved_4: [u8; 6], + st3mm3: [u8; 10], + reserved_5: [u8; 6], + st4mm4: [u8; 10], + reserved_6: [u8; 6], + st5mm5: [u8; 10], + reserved_7: [u8; 6], + st6mm6: [u8; 10], + reserved_8: [u8; 6], + st7mm7: [u8; 10], + reserved_9: [u8; 6], + xmm0: [u8; 16], + xmm1: [u8; 16], + xmm2: [u8; 16], + xmm3: [u8; 16], + xmm4: [u8; 16], + xmm5: [u8; 16], + xmm6: [u8; 16], + xmm7: [u8; 16], + reserved_11: [u8; 14 * 16], // spec goes right from `Reserved9` to `Reserved11` +} + +#[repr(C)] +#[derive(Debug, Clone, Copy)] +pub struct SystemContextIPF { + reserved: u64, + r1: u64, + r2: u64, + r3: u64, + r4: u64, + r5: u64, + r6: u64, + r7: u64, + r8: u64, + r9: u64, + r10: u64, + r11: u64, + r12: u64, + r13: u64, + r14: u64, + r15: u64, + r16: u64, + r17: u64, + r18: u64, + r19: u64, + r20: u64, + r21: u64, + r22: u64, + r23: u64, + r24: u64, + r25: u64, + r26: u64, + r27: u64, + r28: u64, + r29: u64, + r30: u64, + r31: u64, + f2: [u64; 2], + f3: [u64; 2], + f4: [u64; 2], + f5: [u64; 2], + f6: [u64; 2], + f7: [u64; 2], + f8: [u64; 2], + f9: [u64; 2], + f10: [u64; 2], + f11: [u64; 2], + f12: [u64; 2], + f13: [u64; 2], + f14: [u64; 2], + f15: [u64; 2], + f16: [u64; 2], + f17: [u64; 2], + f18: [u64; 2], + f19: [u64; 2], + f20: [u64; 2], + f21: [u64; 2], + f22: [u64; 2], + f23: [u64; 2], + f24: [u64; 2], + f25: [u64; 2], + f26: [u64; 2], + f27: [u64; 2], + f28: [u64; 2], + f29: [u64; 2], + f30: [u64; 2], + f31: [u64; 2], + pr: u64, + b0: u64, + b1: u64, + b2: u64, + b3: u64, + b4: u64, + b5: u64, + b6: u64, + b7: u64, + // application registers + ar_rsc: u64, + ar_bsp: u64, + ar_bspstore: u64, + ar_rnat: u64, + ar_fcr: u64, + ar_eflag: u64, + ar_csd: u64, + ar_ssd: u64, + ar_cflg: u64, + ar_fsr: u64, + ar_fir: u64, + ar_fdr: u64, + ar_ccv: u64, + ar_unat: u64, + ar_fpsr: u64, + ar_pfs: u64, + ar_lc: u64, + ar_ec: u64, + // control registers + cr_dcr: u64, + cr_itm: u64, + cr_iva: u64, + cr_pta: u64, + cr_ipsr: u64, + cr_isr: u64, + cr_iip: u64, + cr_ifa: u64, + cr_itir: u64, + cr_iipa: u64, + cr_ifs: u64, + cr_iim: u64, + cr_iha: u64, + // debug registers + dbr0: u64, + dbr1: u64, + dbr2: u64, + dbr3: u64, + dbr4: u64, + dbr5: u64, + dbr6: u64, + dbr7: u64, + ibr0: u64, + ibr1: u64, + ibr2: u64, + ibr3: u64, + ibr4: u64, + ibr5: u64, + ibr6: u64, + ibr7: u64, + // virtual Registers + int_nat: u64, // nat bits for r1-r31 +} + +/// System context for ARM processors +#[repr(C)] +#[derive(Debug, Clone, Copy)] +pub struct SystemContextARM { + r0: u32, + r1: u32, + r2: u32, + r3: u32, + r4: u32, + r5: u32, + r6: u32, + r7: u32, + r8: u32, + r9: u32, + r10: u32, + r11: u32, + r12: u32, + sp: u32, + lr: u32, + pc: u32, + cpsr: u32, + dfsr: u32, + dfar: u32, + ifsr: u32, +} + +/// System context for AARCH64 processors +#[repr(C)] +#[derive(Debug, Clone, Copy)] +pub struct SystemContextAARCH64 { + // General Purpose Registers + x0: u64, + x1: u64, + x2: u64, + x3: u64, + x4: u64, + x5: u64, + x6: u64, + x7: u64, + x8: u64, + x9: u64, + x10: u64, + x11: u64, + x12: u64, + x13: u64, + x14: u64, + x15: u64, + x16: u64, + x17: u64, + x18: u64, + x19: u64, + x20: u64, + x21: u64, + x22: u64, + x23: u64, + x24: u64, + x25: u64, + x26: u64, + x27: u64, + x28: u64, + fp: u64, // x29 - Frame Pointer + lr: u64, // x30 - Link Register + sp: u64, // x31 - Stack Pointer + // FP/SIMD Registers + v0: [u64; 2], + v1: [u64; 2], + v2: [u64; 2], + v3: [u64; 2], + v4: [u64; 2], + v5: [u64; 2], + v6: [u64; 2], + v7: [u64; 2], + v8: [u64; 2], + v9: [u64; 2], + v10: [u64; 2], + v11: [u64; 2], + v12: [u64; 2], + v13: [u64; 2], + v14: [u64; 2], + v15: [u64; 2], + v16: [u64; 2], + v17: [u64; 2], + v18: [u64; 2], + v19: [u64; 2], + v20: [u64; 2], + v21: [u64; 2], + v22: [u64; 2], + v23: [u64; 2], + v24: [u64; 2], + v25: [u64; 2], + v26: [u64; 2], + v27: [u64; 2], + v28: [u64; 2], + v29: [u64; 2], + v30: [u64; 2], + v31: [u64; 2], + elr: u64, // Exception Link Register + spsr: u64, // Saved Processor Status Register + fpsr: u64, // Floating Point Status Register + esr: u64, // Exception Syndrome Register + far: u64, // Fault Address Register +} diff --git a/src/proto/debug/exception.rs b/src/proto/debug/exception.rs new file mode 100644 index 000000000..4f25a6ea5 --- /dev/null +++ b/src/proto/debug/exception.rs @@ -0,0 +1,185 @@ +/// Represents supported CPU exceptions. +#[repr(C)] +pub struct ExceptionType(isize); + +impl ExceptionType { + /// Undefined Exception + pub const EXCEPT_EBC_UNDEFINED: ExceptionType = ExceptionType(0); + /// Divide-by-zero Error + pub const EXCEPT_EBC_DIVIDE_ERROR: ExceptionType = ExceptionType(1); + /// Debug Exception + pub const EXCEPT_EBC_DEBUG: ExceptionType = ExceptionType(2); + /// Breakpoint + pub const EXCEPT_EBC_BREAKPOINT: ExceptionType = ExceptionType(3); + /// Overflow + pub const EXCEPT_EBC_OVERFLOW: ExceptionType = ExceptionType(4); + /// Invalid Opcode + pub const EXCEPT_EBC_INVALID_OPCODE: ExceptionType = ExceptionType(5); + /// Stack-Segment Fault + pub const EXCEPT_EBC_STACK_FAULT: ExceptionType = ExceptionType(6); + /// Alignment Check + pub const EXCEPT_EBC_ALIGNMENT_CHECK: ExceptionType = ExceptionType(7); + /// Instruction Encoding Exception + pub const EXCEPT_EBC_INSTRUCTION_ENCODING: ExceptionType = ExceptionType(8); + /// Bad Breakpoint Exception + pub const EXCEPT_EBC_BAD_BREAK: ExceptionType = ExceptionType(9); + /// Single Step Exception + pub const EXCEPT_EBC_SINGLE_STEP: ExceptionType = ExceptionType(10); +} + +#[cfg(target_arch = "x86")] +impl ExceptionType { + /// Divide-by-zero Error + pub const EXCEPT_IA32_DIVIDE_ERROR: ExceptionType = ExceptionType(0); + /// Debug Exception + pub const EXCEPT_IA32_DEBUG: ExceptionType = ExceptionType(1); + /// Non-maskable Interrupt + pub const EXCEPT_IA32_NMI: ExceptionType = ExceptionType(2); + /// Breakpoint + pub const EXCEPT_IA32_BREAKPOINT: ExceptionType = ExceptionType(3); + /// Overflow + pub const EXCEPT_IA32_OVERFLOW: ExceptionType = ExceptionType(4); + /// Bound Range Exceeded + pub const EXCEPT_IA32_BOUND: ExceptionType = ExceptionType(5); + /// Invalid Opcode + pub const EXCEPT_IA32_INVALID_OPCODE: ExceptionType = ExceptionType(6); + /// Double Fault + pub const EXCEPT_IA32_DOUBLE_FAULT: ExceptionType = ExceptionType(8); + /// Invalid TSS + pub const EXCEPT_IA32_INVALID_TSS: ExceptionType = ExceptionType(10); + /// Segment Not Present + pub const EXCEPT_IA32_SEG_NOT_PRESENT: ExceptionType = ExceptionType(11); + /// Stack-Segment Fault + pub const EXCEPT_IA32_STACK_FAULT: ExceptionType = ExceptionType(12); + /// General Protection Fault + pub const EXCEPT_IA32_GP_FAULT: ExceptionType = ExceptionType(13); + /// Page Fault + pub const EXCEPT_IA32_PAGE_FAULT: ExceptionType = ExceptionType(14); + /// x87 Floating-Point Exception + pub const EXCEPT_IA32_FP_ERROR: ExceptionType = ExceptionType(16); + /// Alignment Check + pub const EXCEPT_IA32_ALIGNMENT_CHECK: ExceptionType = ExceptionType(17); + /// Machine Check + pub const EXCEPT_IA32_MACHINE_CHECK: ExceptionType = ExceptionType(18); + /// SIMD Floating-Point Exception + pub const EXCEPT_IA32_SIMD: ExceptionType = ExceptionType(19); +} + +#[cfg(target_arch = "x86_64")] +impl ExceptionType { + /// Divide-by-zero Error + pub const EXCEPT_X64_DIVIDE_ERROR: ExceptionType = ExceptionType(0); + /// Debug Exception + pub const EXCEPT_X64_DEBUG: ExceptionType = ExceptionType(1); + /// Non-maskable Interrupt + pub const EXCEPT_X64_NMI: ExceptionType = ExceptionType(2); + /// Breakpoint + pub const EXCEPT_X64_BREAKPOINT: ExceptionType = ExceptionType(3); + /// Overflow + pub const EXCEPT_X64_OVERFLOW: ExceptionType = ExceptionType(4); + /// Bound Range Exceeded + pub const EXCEPT_X64_BOUND: ExceptionType = ExceptionType(5); + /// Invalid Opcode + pub const EXCEPT_X64_INVALID_OPCODE: ExceptionType = ExceptionType(6); + /// Double Fault + pub const EXCEPT_X64_DOUBLE_FAULT: ExceptionType = ExceptionType(8); + /// Invalid TSS + pub const EXCEPT_X64_INVALID_TSS: ExceptionType = ExceptionType(10); + /// Segment Not Present + pub const EXCEPT_X64_SEG_NOT_PRESENT: ExceptionType = ExceptionType(11); + /// Stack-Segment Fault + pub const EXCEPT_X64_STACK_FAULT: ExceptionType = ExceptionType(12); + /// General Protection Fault + pub const EXCEPT_X64_GP_FAULT: ExceptionType = ExceptionType(13); + /// Page Fault + pub const EXCEPT_X64_PAGE_FAULT: ExceptionType = ExceptionType(14); + /// x87 Floating-Point Exception + pub const EXCEPT_X64_FP_ERROR: ExceptionType = ExceptionType(16); + /// Alignment Check + pub const EXCEPT_X64_ALIGNMENT_CHECK: ExceptionType = ExceptionType(17); + /// Machine Check + pub const EXCEPT_X64_MACHINE_CHECK: ExceptionType = ExceptionType(18); + /// SIMD Floating-Point Exception + pub const EXCEPT_X64_SIMD: ExceptionType = ExceptionType(19); +} + +#[cfg(target_arch = "arm")] +impl ExceptionType { + /// Processor reset + pub const EXCEPT_ARM_RESET: ExceptionType = ExceptionType(0); + /// Undefined instruction + pub const EXCEPT_ARM_UNDEFINED_INSTRUCTION: ExceptionType = ExceptionType(1); + /// Software Interrupt + pub const EXCEPT_ARM_SOFTWARE_INTERRUPT: ExceptionType = ExceptionType(2); + /// Prefetch aborted + pub const EXCEPT_ARM_PREFETCH_ABORT: ExceptionType = ExceptionType(3); + /// Data access memory abort + pub const EXCEPT_ARM_DATA_ABORT: ExceptionType = ExceptionType(4); + /// Reserved + pub const EXCEPT_ARM_RESERVED: ExceptionType = ExceptionType(5); + /// Normal interrupt + pub const EXCEPT_ARM_IRQ: ExceptionType = ExceptionType(6); + /// Fast interrupt + pub const EXCEPT_ARM_FIQ: ExceptionType = ExceptionType(7); + /// In the UEFI spec for "convenience", unsure if we'll need it. Set to `EXCEPT_ARM_FIQ` + pub const MAX_ARM_EXCEPTION: ExceptionType = ExceptionType::EXCEPT_ARM_FIQ; +} + +#[cfg(target_arch = "aarch64")] +impl ExceptionType { + /// Synchronous exception, such as attempting to execute an invalid instruction + pub const EXCEPT_AARCH64_SYNCHRONOUS_EXCEPTIONS: ExceptionType = ExceptionType(0); + /// Normal interrupt + pub const EXCEPT_AARCH64_IRQ: ExceptionType = ExceptionType(1); + /// Fast interrupt + pub const EXCEPT_AARCH64_FIQ: ExceptionType = ExceptionType(2); + /// System Error + pub const EXCEPT_AARCH64_SERROR: ExceptionType = ExceptionType(3); + /// In the UEFI spec for "convenience", unsure if we'll need it. Set to `EXCEPT_AARCH64_SERROR` + pub const MAX_AARCH64_EXCEPTION: ExceptionType = ExceptionType::EXCEPT_AARCH64_SERROR; +} + +#[cfg(target_arch = "riscv")] +impl ExceptionType { + /// Instruction misaligned + pub const EXCEPT_RISCV_INST_MISALIGNED: ExceptionType = ExceptionType(0); + /// Instruction access fault + pub const EXCEPT_RISCV_INST_ACCESS_FAULT: ExceptionType = ExceptionType(1); + /// Illegal instruction + pub const EXCEPT_RISCV_ILLEGAL_INST: ExceptionType = ExceptionType(2); + /// Breakpoint + pub const EXCEPT_RISCV_BREAKPOINT: ExceptionType = ExceptionType(3); + /// Load address misaligned + pub const EXCEPT_RISCV_LOAD_ADDRESS_MISALIGNED: ExceptionType = ExceptionType(4); + /// Load accept fault + pub const EXCEPT_RISCV_LOAD_ACCESS_FAULT: ExceptionType = ExceptionType(5); + /// Store AMO address misaligned + pub const EXCEPT_RISCV_STORE_AMO_ADDRESS_MISALIGNED: ExceptionType = ExceptionType(6); + /// Store AMO access fault + pub const EXCEPT_RISCV_STORE_AMO_ACCESS_FAULT: ExceptionType = ExceptionType(7); + /// ECALL from User mode + pub const EXCEPT_RISCV_ENV_CALL_FROM_UMODE: ExceptionType = ExceptionType(8); + /// ECALL from Supervisor mode + pub const EXCEPT_RISCV_ENV_CALL_FROM_SMODE: ExceptionType = ExceptionType(9); + /// ECALL from Machine mode + pub const EXCEPT_RISCV_ENV_CALL_FROM_MMODE: ExceptionType = ExceptionType(11); + /// Instruction page fault + pub const EXCEPT_RISCV_INST_PAGE_FAULT: ExceptionType = ExceptionType(12); + /// Load page fault + pub const EXCEPT_RISCV_LOAD_PAGE_FAULT: ExceptionType = ExceptionType(13); + /// Store AMO page fault + pub const EXCEPT_RISCV_STORE_AMO_PAGE_FAULT: ExceptionType = ExceptionType(15); + // RISC-V interrupt types + /// Supervisor software interrupt + pub const EXCEPT_RISCV_SUPERVISOR_SOFTWARE_INT: ExceptionType = ExceptionType(1); + /// Machine software interrupt + pub const EXCEPT_RISCV_MACHINE_SOFTWARE_INT: ExceptionType = ExceptionType(3); + /// Supervisor timer interrupt + pub const EXCEPT_RISCV_SUPERVISOR_TIMER_INT: ExceptionType = ExceptionType(5); + /// Machine timer interrupt + pub const EXCEPT_RISCV_MACHINE_TIMER_INT: ExceptionType = ExceptionType(7); + /// Supervisor external interrupt + pub const EXCEPT_RISCV_SUPERVISOR_EXTERNAL_INT: ExceptionType = ExceptionType(9); + /// Machine external interrupt + pub const EXCEPT_RISCV_MACHINE_EXTERNAL_INT: ExceptionType = ExceptionType(11); +} diff --git a/src/proto/debug/mod.rs b/src/proto/debug/mod.rs new file mode 100644 index 000000000..5f5d73846 --- /dev/null +++ b/src/proto/debug/mod.rs @@ -0,0 +1,172 @@ +//! Provides support for the UEFI debugging protocol. +//! +//! This protocol is designed to allow debuggers to query the state of the firmware, +//! as well as set up callbacks for various events. +//! +//! It also defines a Debugport protocol for debugging over serial devices. +//! +//! An example UEFI debugger is Intel's [UDK Debugger Tool][udk]. +//! +//! [udk]: https://firmware.intel.com/develop/intel-uefi-tools-and-utilities/intel-uefi-development-kit-debugger-tool + +use core::ffi::c_void; + +use crate::proto::Protocol; +use crate::{unsafe_guid, Result, Status}; + +// re-export for ease of use +pub use self::context::SystemContext; +pub use self::exception::ExceptionType; + +mod context; +mod exception; + +/// The debugging support protocol allows debuggers to connect to a UEFI machine. +/// It is expected that there will typically be two instances of the EFI Debug Support protocol in the system. +/// One associated with the native processor instruction set (IA-32, x64, ARM, RISC-V, or Itanium processor +/// family), and one for the EFI virtual machine that implements EFI byte code (EBC). +/// While multiple instances of the EFI Debug Support protocol are expected, there must never be more than +/// one for any given instruction set. +/// +/// NOTE: OVMF only implements this protocol interface for the virtual EBC processor +#[repr(C)] +#[unsafe_guid("2755590c-6f3c-42fa-9ea4-a3ba543cda25")] +#[derive(Protocol)] +pub struct DebugSupport { + isa: ProcessorArch, + get_maximum_processor_index: + extern "efiapi" fn(this: &mut DebugSupport, max_processor_index: &mut usize) -> Status, + register_periodic_callback: unsafe extern "efiapi" fn( + this: &mut DebugSupport, + processor_index: usize, + periodic_callback: Option, + ) -> Status, + register_exception_callback: unsafe extern "efiapi" fn( + this: &mut DebugSupport, + processor_index: usize, + exception_callback: Option, + exception_type: ExceptionType, + ) -> Status, + invalidate_instruction_cache: unsafe extern "efiapi" fn( + this: &mut DebugSupport, + processor_index: usize, + start: *mut c_void, + length: u64, + ) -> Status, +} + +impl DebugSupport { + /// Returns the processor architecture of the running CPU. + pub fn arch(&self) -> ProcessorArch { + self.isa + } + + /// Returns the maximum value that may be used for the processor_index parameter in + /// `register_periodic_callback()` and `register_exception_callback()`. + /// + /// Note: Applications built with EDK2 (such as OVMF) always return `0` as of 2021-09-15 + pub fn get_maximum_processor_index(&mut self) -> usize { + // initially set to a canary value for testing purposes + let mut max_processor_index: usize = usize::MAX; + + // per the UEFI spec, this call should only return EFI_SUCCESS + let _ = (self.get_maximum_processor_index)(self, &mut max_processor_index); + + max_processor_index + } + + /// Registers a function to be called back periodically in interrupt context. + /// Pass `None` for `callback` to deregister the currently registered function for + /// a specified `processor_index`. Will return `Status::INVALID_PARAMETER` if + /// `processor_index` exceeds the current maximum from `Self::get_maximum_processor_index`. + /// + /// Note: Applications built with EDK2 (such as OVMF) ignore the `processor_index` parameter + /// + /// # Safety + /// No portion of the debug agent that runs in interrupt context may make any + /// calls to EFI services or other protocol interfaces. + pub unsafe fn register_periodic_callback( + &mut self, + processor_index: usize, + callback: Option, + ) -> Result { + if processor_index > self.get_maximum_processor_index() { + return Err(Status::INVALID_PARAMETER.into()); + } + + // Safety: As we've validated the `processor_index`, this should always be safe + (self.register_periodic_callback)(self, processor_index, callback).into() + } + + /// Registers a function to be called when a given processor exception occurs. + /// Pass `None` for `callback` to deregister the currently registered function for a + /// given `exception_type` and `processor_index`. Will return `Status::INVALID_PARAMETER` + /// if `processor_index` exceeds the current maximum from `Self::get_maximum_processor_index`. + /// + /// Note: Applications built with EDK2 (such as OVMF) ignore the `processor_index` parameter + /// + /// # Safety + /// No portion of the debug agent that runs in interrupt context may make any + /// calls to EFI services or other protocol interfaces. + pub unsafe fn register_exception_callback( + &mut self, + processor_index: usize, + callback: Option, + exception_type: ExceptionType, + ) -> Result { + if processor_index > self.get_maximum_processor_index() { + return Err(Status::INVALID_PARAMETER.into()); + } + + // Safety: As we've validated the `processor_index`, this should always be safe + (self.register_exception_callback)(self, processor_index, callback, exception_type).into() + } + + /// Invalidates processor instruction cache for a memory range for a given `processor_index`. + /// + /// Note: Applications built with EDK2 (such as OVMF) ignore the `processor_index` parameter + /// + /// # Safety + /// `start` must be a c_void ptr to a valid memory address + pub unsafe fn invalidate_instruction_cache( + &mut self, + processor_index: usize, + start: *mut c_void, + length: u64, + ) -> Result { + if processor_index > self.get_maximum_processor_index() { + return Err(Status::INVALID_PARAMETER.into()); + } + + // per the UEFI spec, this call should only return EFI_SUCCESS + // Safety: As we've validated the `processor_index`, this should always be safe + (self.invalidate_instruction_cache)(self, processor_index, start, length).into() + } +} + +newtype_enum! { +/// The instruction set architecture of the running processor. +/// +/// UEFI can be and has been ported to new CPU architectures in the past, +/// therefore modeling this C enum as a Rust enum (where the compiler must know +/// about every variant in existence) would _not_ be safe. +pub enum ProcessorArch: u32 => { + /// 32-bit x86 PC + X86_32 = 0x014C, + /// 64-bit x86 PC + X86_64 = 0x8664, + /// Intel Itanium + ITANIUM = 0x200, + /// UEFI Interpreter bytecode + EBC = 0x0EBC, + /// ARM Thumb / Mixed + ARM = 0x01C2, + /// ARM 64-bit + AARCH_64 = 0xAA64, + /// RISC-V 32-bit + RISCV_32 = 0x5032, + /// RISC-V 64-bit + RISCV_64 = 0x5064, + /// RISC-V 128-bit + RISCV_128 = 0x5128, +}} diff --git a/src/proto/device_path/mod.rs b/src/proto/device_path/mod.rs new file mode 100644 index 000000000..660ce80d3 --- /dev/null +++ b/src/proto/device_path/mod.rs @@ -0,0 +1,869 @@ +//! Device Path protocol +//! +//! A UEFI device path is a very flexible structure for encoding a +//! programatic path such as a hard drive or console. +//! +//! A device path is made up of a packed list of variable-length nodes of +//! various types. The entire device path is terminated with an +//! [`END_ENTIRE`] node. A device path _may_ contain multiple device-path +//! instances separated by [`END_INSTANCE`] nodes, but typical paths contain +//! only a single instance (in which case no `END_INSTANCE` node is needed). +//! +//! Example of what a device path containing two instances (each comprised of +//! three nodes) might look like: +//! +//! ```text +//! ┌──────┬─────┬──────────────╥───────┬──────────┬────────────┠+//! │ ACPI │ PCI │ END_INSTANCE ║ CDROM │ FILEPATH │ END_ENTIRE │ +//! └──────┴─────┴──────────────╨───────┴──────────┴────────────┘ +//! ↑ ↑ ↑ +//! ├─── DevicePathInstance ────╨────── DevicePathInstance ─────┤ +//! │ │ +//! └─────────────────── Entire DevicePath ─────────────────────┘ +//! ``` +//! +//! # Types +//! +//! To represent device paths, this module provides several types: +//! +//! * [`DevicePath`] is the root type that represents a full device +//! path, containing one or more device path instance. It ends with an +//! [`END_ENTIRE`] node. It implements [`Protocol`] (corresponding to +//! `EFI_DEVICE_PATH_PROTOCOL`). +//! +//! * [`DevicePathInstance`] represents a single path instance within a +//! device path. It ends with either an [`END_INSTANCE`] or [`END_ENTIRE`] +//! node. +//! +//! * [`DevicePathNode`] represents a single node within a path. The +//! node's [`device_type`] and [`sub_type`] must be examined to +//! determine what type of data it contains. +//! +//! Specific node types have their own structures, but only a few are +//! currently implemented: +//! * [`AcpiDevicePath`] +//! * [`FilePathMediaDevicePath`] +//! * [`HardDriveMediaDevicePath`] +//! +//! * [`DevicePathHeader`] is a header present at the start of every +//! node. It describes the type of node as well as the node's size. +//! +//! * [`FfiDevicePath`] is an opaque type used whenever a device path +//! pointer is passed to or from external UEFI interfaces (i.e. where +//! the UEFI spec uses `const* EFI_DEVICE_PATH_PROTOCOL`, `*const +//! FfiDevicePath` should be used in the Rust definition). Many of the +//! other types in this module are DSTs, so pointers to the type are +//! "fat" and not suitable for FFI. +//! +//! All of these types use a packed layout and may appear on any byte +//! boundary. +//! +//! Note: the API provided by this module is currently mostly limited to +//! reading existing device paths rather than constructing new ones. +//! +//! [`END_ENTIRE`]: DeviceSubType::END_ENTIRE +//! [`END_INSTANCE`]: DeviceSubType::END_INSTANCE +//! [`device_type`]: DevicePathNode::device_type +//! [`sub_type`]: DevicePathNode::sub_type + +pub mod text; + +use crate::data_types::UnalignedCStr16; +use crate::proto::{Protocol, ProtocolPointer}; +use crate::{unsafe_guid, Guid}; +use core::ffi::c_void; +use core::marker::{PhantomData, PhantomPinned}; +use core::{mem, ptr}; + +/// Opaque type that should be used to represent a pointer to a +/// [`DevicePath`] or [`DevicePathNode`] in foreign function interfaces. This +/// type produces a thin pointer, unlike [`DevicePath`] and +/// [`DevicePathNode`]. +#[repr(C, packed)] +pub struct FfiDevicePath { + // This representation is recommended by the nomicon: + // https://doc.rust-lang.org/stable/nomicon/ffi.html#representing-opaque-structs + _data: [u8; 0], + _marker: PhantomData<(*mut u8, PhantomPinned)>, +} + +/// Header that appears at the start of every [`DevicePathNode`]. +#[derive(Clone, Copy, Debug, Eq, PartialEq)] +#[repr(C, packed)] +pub struct DevicePathHeader { + /// Type of device + pub device_type: DeviceType, + /// Sub type of device + pub sub_type: DeviceSubType, + /// Size (in bytes) of the [`DevicePathNode`], including this header. + pub length: u16, +} + +/// A single node within a [`DevicePath`]. +/// +/// Each node starts with a [`DevicePathHeader`]. The rest of the data +/// in the node depends on the type of node. +/// +/// See the [module-level documentation] for more details. +/// +/// [module-level documentation]: crate::proto::device_path +#[derive(Debug, Eq, PartialEq)] +#[repr(C, packed)] +pub struct DevicePathNode { + header: DevicePathHeader, + data: [u8], +} + +impl DevicePathNode { + /// Create a [`DevicePathNode`] reference from an opaque pointer. + /// + /// # Safety + /// + /// The input pointer must point to valid data. That data must + /// remain valid for the lifetime `'a`, and cannot be mutated during + /// that lifetime. + pub unsafe fn from_ffi_ptr<'a>(ptr: *const FfiDevicePath) -> &'a DevicePathNode { + let header = *ptr.cast::(); + + let data_len = usize::from(header.length) - mem::size_of::(); + &*ptr::from_raw_parts(ptr.cast(), data_len) + } + + /// Cast to a [`FfiDevicePath`] pointer. + pub fn as_ffi_ptr(&self) -> *const FfiDevicePath { + let ptr: *const Self = self; + ptr.cast::() + } + + /// Type of device + pub fn device_type(&self) -> DeviceType { + self.header.device_type + } + + /// Sub type of device + pub fn sub_type(&self) -> DeviceSubType { + self.header.sub_type + } + + /// Tuple of the node's type and subtype. + pub fn full_type(&self) -> (DeviceType, DeviceSubType) { + (self.header.device_type, self.header.sub_type) + } + + /// Size (in bytes) of the full [`DevicePathNode`], including the header. + pub fn length(&self) -> u16 { + self.header.length + } + + /// True if this node ends an entire [`DevicePath`]. + pub fn is_end_entire(&self) -> bool { + self.full_type() == (DeviceType::END, DeviceSubType::END_ENTIRE) + } + + /// Convert to a [`FilePathMediaDevicePath`]. Returns `None` if the + /// node is not of the appropriate type. + pub fn as_file_path_media_device_path(&self) -> Option<&FilePathMediaDevicePath> { + if self.full_type() == (DeviceType::MEDIA, DeviceSubType::MEDIA_FILE_PATH) { + // Get the length of the `path_name` field. + let path_name_size_in_bytes = usize::from(self.header.length) - 4; + assert!(path_name_size_in_bytes % mem::size_of::() == 0); + let path_name_len = path_name_size_in_bytes / mem::size_of::(); + + // Convert the `self` pointer to `FilePathMediaDevicePath`, + // which is a DST as it ends in a slice. + let p = self as *const Self; + let p: *const FilePathMediaDevicePath = ptr::from_raw_parts(p.cast(), path_name_len); + Some(unsafe { &*p }) + } else { + None + } + } + + /// Convert to a [`HardDriveMediaDevicePath`]. Returns `None` if the + /// node is not of the appropriate type. + pub fn as_hard_drive_media_device_path(&self) -> Option<&HardDriveMediaDevicePath> { + if self.full_type() == (DeviceType::MEDIA, DeviceSubType::MEDIA_HARD_DRIVE) { + assert!({ self.header.length } == HARD_DRIVE_MEDIA_DEVICE_PATH_LENGTH); + + let p = self as *const Self; + let p = p.cast::(); + Some(unsafe { &*p }) + } else { + None + } + } +} + +/// A single device path instance that ends with either an [`END_INSTANCE`] +/// or [`END_ENTIRE`] node. Use [`DevicePath::instance_iter`] to get the +/// path instances in a [`DevicePath`]. +/// +/// See the [module-level documentation] for more details. +/// +/// [`END_ENTIRE`]: DeviceSubType::END_ENTIRE +/// [`END_INSTANCE`]: DeviceSubType::END_INSTANCE +/// [module-level documentation]: crate::proto::device_path +#[repr(C, packed)] +#[derive(Debug, Eq, PartialEq)] +pub struct DevicePathInstance { + data: [u8], +} + +impl DevicePathInstance { + /// Get an iterator over the [`DevicePathNodes`] in this + /// instance. Iteration ends when any [`DeviceType::END`] node is + /// reached. + /// + /// [`DevicePathNodes`]: DevicePathNode + pub fn node_iter(&self) -> DevicePathNodeIterator { + DevicePathNodeIterator { + nodes: &self.data, + stop_condition: StopCondition::AnyEndNode, + } + } +} + +/// Device path protocol. +/// +/// A device path contains one or more device path instances made of up +/// variable-length nodes. It ends with an [`END_ENTIRE`] node. +/// +/// See the [module-level documentation] for more details. +/// +/// [module-level documentation]: crate::proto::device_path +/// [`END_ENTIRE`]: DeviceSubType::END_ENTIRE +#[repr(C, packed)] +#[unsafe_guid("09576e91-6d3f-11d2-8e39-00a0c969723b")] +#[derive(Debug, Eq, PartialEq, Protocol)] +pub struct DevicePath { + data: [u8], +} + +impl ProtocolPointer for DevicePath { + unsafe fn ptr_from_ffi(ptr: *const c_void) -> *const Self { + ptr::from_raw_parts(ptr.cast(), Self::size_in_bytes_from_ptr(ptr)) + } + + unsafe fn mut_ptr_from_ffi(ptr: *mut c_void) -> *mut Self { + ptr::from_raw_parts_mut(ptr.cast(), Self::size_in_bytes_from_ptr(ptr)) + } +} + +impl DevicePath { + /// Calculate the size in bytes of the entire `DevicePath` starting + /// at `ptr`. This adds up each node's length, including the + /// end-entire node. + unsafe fn size_in_bytes_from_ptr(ptr: *const c_void) -> usize { + let mut ptr = ptr.cast::(); + let mut total_size_in_bytes: usize = 0; + loop { + let node = DevicePathNode::from_ffi_ptr(ptr.cast::()); + let node_size_in_bytes = usize::from(node.length()); + total_size_in_bytes += node_size_in_bytes; + if node.is_end_entire() { + break; + } + ptr = ptr.add(node_size_in_bytes); + } + + total_size_in_bytes + } + + /// Create a [`DevicePath`] reference from an opaque pointer. + /// + /// # Safety + /// + /// The input pointer must point to valid data. That data must + /// remain valid for the lifetime `'a`, and cannot be mutated during + /// that lifetime. + pub unsafe fn from_ffi_ptr<'a>(ptr: *const FfiDevicePath) -> &'a DevicePath { + &*Self::ptr_from_ffi(ptr.cast::()) + } + + /// Cast to a [`FfiDevicePath`] pointer. + pub fn as_ffi_ptr(&self) -> *const FfiDevicePath { + let p = self as *const Self; + p.cast() + } + + /// Get an iterator over the [`DevicePathInstance`]s in this path. + pub fn instance_iter(&self) -> DevicePathInstanceIterator { + DevicePathInstanceIterator { + remaining_path: Some(self), + } + } + + /// Get an iterator over the [`DevicePathNode`]s starting at + /// `self`. Iteration ends when a path is reached where + /// [`is_end_entire`][DevicePathNode::is_end_entire] is true. That ending + /// path is not returned by the iterator. + pub fn node_iter(&self) -> DevicePathNodeIterator { + DevicePathNodeIterator { + nodes: &self.data, + stop_condition: StopCondition::EndEntireNode, + } + } +} + +/// Iterator over the [`DevicePathInstance`]s in a [`DevicePath`]. +/// +/// This struct is returned by [`DevicePath::instance_iter`]. +pub struct DevicePathInstanceIterator<'a> { + remaining_path: Option<&'a DevicePath>, +} + +impl<'a> Iterator for DevicePathInstanceIterator<'a> { + type Item = &'a DevicePathInstance; + + fn next(&mut self) -> Option { + let remaining_path = self.remaining_path?; + + let mut instance_size: usize = 0; + + // Find the end of the instance, which can be either kind of end + // node (end-instance or end-entire). Count the number of bytes + // up to and including that end node. + let node_iter = DevicePathNodeIterator { + nodes: &remaining_path.data, + stop_condition: StopCondition::NoMoreNodes, + }; + for node in node_iter { + instance_size += usize::from(node.length()); + if node.device_type() == DeviceType::END { + break; + } + } + + let (head, rest) = remaining_path.data.split_at(instance_size); + + if rest.is_empty() { + self.remaining_path = None; + } else { + self.remaining_path = unsafe { + Some(&*ptr::from_raw_parts( + rest.as_ptr().cast::<()>(), + rest.len(), + )) + }; + } + + unsafe { + Some(&*ptr::from_raw_parts( + head.as_ptr().cast::<()>(), + head.len(), + )) + } + } +} + +enum StopCondition { + AnyEndNode, + EndEntireNode, + NoMoreNodes, +} + +/// Iterator over [`DevicePathNode`]s. +/// +/// This struct is returned by [`DevicePath::node_iter`] and +/// [`DevicePathInstance::node_iter`]. +pub struct DevicePathNodeIterator<'a> { + nodes: &'a [u8], + stop_condition: StopCondition, +} + +impl<'a> Iterator for DevicePathNodeIterator<'a> { + type Item = &'a DevicePathNode; + + fn next(&mut self) -> Option { + if self.nodes.is_empty() { + return None; + } + + let node = + unsafe { DevicePathNode::from_ffi_ptr(self.nodes.as_ptr().cast::()) }; + + // Check if an early stop condition has been reached. + let stop = match self.stop_condition { + StopCondition::AnyEndNode => node.device_type() == DeviceType::END, + StopCondition::EndEntireNode => node.is_end_entire(), + StopCondition::NoMoreNodes => false, + }; + + if stop { + // Clear the remaining node data so that future calls to + // next() immediately return `None`. + self.nodes = &[]; + None + } else { + // Advance to next node. + let node_size = usize::from(node.length()); + self.nodes = &self.nodes[node_size..]; + Some(node) + } + } +} + +newtype_enum! { +/// Type identifier for a DevicePath +pub enum DeviceType: u8 => { + /// Hardware Device Path. + /// + /// This Device Path defines how a device is attached to the resource domain of a system, where resource domain is + /// simply the shared memory, memory mapped I/ O, and I/O space of the system. + HARDWARE = 0x01, + /// ACPI Device Path. + /// + /// This Device Path is used to describe devices whose enumeration is not described in an industry-standard fashion. + /// These devices must be described using ACPI AML in the ACPI namespace; this Device Path is a linkage to the ACPI + /// namespace. + ACPI = 0x02, + /// Messaging Device Path. + /// + /// This Device Path is used to describe the connection of devices outside the resource domain of the system. This + /// Device Path can describe physical messaging information such as a SCSI ID, or abstract information such as + /// networking protocol IP addresses. + MESSAGING = 0x03, + /// Media Device Path. + /// + /// This Device Path is used to describe the portion of a medium that is being abstracted by a boot service. + /// For example, a Media Device Path could define which partition on a hard drive was being used. + MEDIA = 0x04, + /// BIOS Boot Specification Device Path. + /// + /// This Device Path is used to point to boot legacy operating systems; it is based on the BIOS Boot Specification + /// Version 1.01. + BIOS_BOOT_SPEC = 0x05, + /// End of Hardware Device Path. + /// + /// Depending on the Sub-Type, this Device Path node is used to indicate the end of the Device Path instance or + /// Device Path structure. + END = 0x7F, +}} + +/// Sub-type identifier for a DevicePath +#[derive(Clone, Copy, Debug, Eq, PartialEq)] +pub struct DeviceSubType(pub u8); + +impl DeviceSubType { + /// PCI Device Path. + pub const HARDWARE_PCI: DeviceSubType = DeviceSubType(0x01); + /// PCCARD Device Path. + pub const HARDWARE_PCCARD: DeviceSubType = DeviceSubType(0x02); + /// Memory-mapped Device Path. + pub const HARDWARE_MEMORY_MAPPED: DeviceSubType = DeviceSubType(0x03); + /// Vendor-Defined Device Path. + pub const HARDWARE_VENDOR: DeviceSubType = DeviceSubType(0x04); + /// Controller Device Path. + pub const HARDWARE_CONTROLLER: DeviceSubType = DeviceSubType(0x05); + /// BMC Device Path. + pub const HARDWARE_BMC: DeviceSubType = DeviceSubType(0x06); + + /// ACPI Device Path. + pub const ACPI: DeviceSubType = DeviceSubType(0x01); + /// Expanded ACPI Device Path. + pub const ACPI_EXPANDED: DeviceSubType = DeviceSubType(0x02); + /// ACPI _ADR Device Path. + pub const ACPI_ADR: DeviceSubType = DeviceSubType(0x03); + /// NVDIMM Device Path. + pub const ACPI_NVDIMM: DeviceSubType = DeviceSubType(0x04); + + /// ATAPI Device Path. + pub const MESSAGING_ATAPI: DeviceSubType = DeviceSubType(0x01); + /// SCSI Device Path. + pub const MESSAGING_SCSI: DeviceSubType = DeviceSubType(0x02); + /// Fibre Channel Device Path. + pub const MESSAGING_FIBRE_CHANNEL: DeviceSubType = DeviceSubType(0x03); + /// 1394 Device Path. + pub const MESSAGING_1394: DeviceSubType = DeviceSubType(0x04); + /// USB Device Path. + pub const MESSAGING_USB: DeviceSubType = DeviceSubType(0x05); + /// I2O Device Path. + pub const MESSAGING_I2O: DeviceSubType = DeviceSubType(0x06); + /// Infiniband Device Path. + pub const MESSAGING_INFINIBAND: DeviceSubType = DeviceSubType(0x09); + /// Vendor-Defined Device Path. + pub const MESSAGING_VENDOR: DeviceSubType = DeviceSubType(0x0a); + /// MAC Address Device Path. + pub const MESSAGING_MAC_ADDRESS: DeviceSubType = DeviceSubType(0x0b); + /// IPV4 Device Path. + pub const MESSAGING_IPV4: DeviceSubType = DeviceSubType(0x0c); + /// IPV6 Device Path. + pub const MESSAGING_IPV6: DeviceSubType = DeviceSubType(0x0d); + /// UART Device Path. + pub const MESSAGING_UART: DeviceSubType = DeviceSubType(0x0e); + /// USB Class Device Path. + pub const MESSAGING_USB_CLASS: DeviceSubType = DeviceSubType(0x0f); + /// USB WWID Device Path. + pub const MESSAGING_USB_WWID: DeviceSubType = DeviceSubType(0x10); + /// Device Logical Unit. + pub const MESSAGING_DEVICE_LOGICAL_UNIT: DeviceSubType = DeviceSubType(0x11); + /// SATA Device Path. + pub const MESSAGING_SATA: DeviceSubType = DeviceSubType(0x12); + /// iSCSI Device Path node (base information). + pub const MESSAGING_ISCSI: DeviceSubType = DeviceSubType(0x13); + /// VLAN Device Path node. + pub const MESSAGING_VLAN: DeviceSubType = DeviceSubType(0x14); + /// Fibre Channel Ex Device Path. + pub const MESSAGING_FIBRE_CHANNEL_EX: DeviceSubType = DeviceSubType(0x15); + /// Serial Attached SCSI (SAS) Ex Device Path. + pub const MESSAGING_SCSI_SAS_EX: DeviceSubType = DeviceSubType(0x16); + /// NVM Express Namespace Device Path. + pub const MESSAGING_NVME_NAMESPACE: DeviceSubType = DeviceSubType(0x17); + /// Uniform Resource Identifiers (URI) Device Path. + pub const MESSAGING_URI: DeviceSubType = DeviceSubType(0x18); + /// UFS Device Path. + pub const MESSAGING_UFS: DeviceSubType = DeviceSubType(0x19); + /// SD (Secure Digital) Device Path. + pub const MESSAGING_SD: DeviceSubType = DeviceSubType(0x1a); + /// Bluetooth Device Path. + pub const MESSAGING_BLUETOOTH: DeviceSubType = DeviceSubType(0x1b); + /// Wi-Fi Device Path. + pub const MESSAGING_WIFI: DeviceSubType = DeviceSubType(0x1c); + /// eMMC (Embedded Multi-Media Card) Device Path. + pub const MESSAGING_EMMC: DeviceSubType = DeviceSubType(0x1d); + /// BluetoothLE Device Path. + pub const MESSAGING_BLUETOOTH_LE: DeviceSubType = DeviceSubType(0x1e); + /// DNS Device Path. + pub const MESSAGING_DNS: DeviceSubType = DeviceSubType(0x1f); + /// NVDIMM Namespace Device Path. + pub const MESSAGING_NVDIMM_NAMESPACE: DeviceSubType = DeviceSubType(0x20); + + /// Hard Drive Media Device Path. + pub const MEDIA_HARD_DRIVE: DeviceSubType = DeviceSubType(0x01); + /// CD-ROM Media Device Path. + pub const MEDIA_CD_ROM: DeviceSubType = DeviceSubType(0x02); + /// Vendor-Defined Media Device Path. + pub const MEDIA_VENDOR: DeviceSubType = DeviceSubType(0x03); + /// File Path Media Device Path. + pub const MEDIA_FILE_PATH: DeviceSubType = DeviceSubType(0x04); + /// Media Protocol Device Path. + pub const MEDIA_PROTOCOL: DeviceSubType = DeviceSubType(0x05); + /// PIWG Firmware File. + pub const MEDIA_PIWG_FIRMWARE_FILE: DeviceSubType = DeviceSubType(0x06); + /// PIWG Firmware Volume. + pub const MEDIA_PIWG_FIRMWARE_VOLUME: DeviceSubType = DeviceSubType(0x07); + /// Relative Offset Range. + pub const MEDIA_RELATIVE_OFFSET_RANGE: DeviceSubType = DeviceSubType(0x08); + /// RAM Disk Device Path. + pub const MEDIA_RAM_DISK: DeviceSubType = DeviceSubType(0x09); + + /// BIOS Boot Specification Device Path. + pub const BIOS_BOOT_SPECIFICATION: DeviceSubType = DeviceSubType(0x01); + + /// End this instance of a Device Path and start a new one. + pub const END_INSTANCE: DeviceSubType = DeviceSubType(0x01); + /// End entire Device Path. + pub const END_ENTIRE: DeviceSubType = DeviceSubType(0xff); +} + +/// ACPI Device Path +#[repr(C, packed)] +pub struct AcpiDevicePath { + header: DevicePathHeader, + + /// Device's PnP hardware ID stored in a numeric 32-bit compressed EISA-type ID. This value must match the + /// corresponding _HID in the ACPI name space. + pub hid: u32, + /// Unique ID that is required by ACPI if two devices have the same _HID. This value must also match the + /// corresponding _UID/_HID pair in the ACPI name space. Only the 32-bit numeric value type of _UID is supported; + /// thus strings must not be used for the _UID in the ACPI name space. + pub uid: u32, +} + +/// File Path Media Device Path. +#[repr(C, packed)] +pub struct FilePathMediaDevicePath { + header: DevicePathHeader, + path_name: [u16], +} + +impl FilePathMediaDevicePath { + /// Get the path. An [`UnalignedCStr16`] is returned since this is a + /// packed struct. + pub fn path_name(&self) -> UnalignedCStr16<'_> { + // Safety: creating this `UnalignedCStr16` is safe because the + // `path_name` pointer is valid (although potentially + // unaligned), and the lifetime of the output is tied to `self`, + // so there's no possibility of use-after-free. + unsafe { + // Use `addr_of` to avoid creating an unaligned reference. + let ptr: *const [u16] = ptr::addr_of!(self.path_name); + let (ptr, len): (*const (), usize) = ptr.to_raw_parts(); + UnalignedCStr16::new(self, ptr.cast::(), len) + } + } +} + +/// Hard Drive Media Device Path. +#[repr(C, packed)] +pub struct HardDriveMediaDevicePath { + header: DevicePathHeader, + partition_number: u32, + partition_start: u64, + partition_size: u64, + partition_signature: PartitionSignatureUnion, + partition_format: PartitionFormat, + signature_type: SignatureType, +} + +/// [`HardDriveMediaDevicePath`] is a fixed-length structure of 42 bytes. +const HARD_DRIVE_MEDIA_DEVICE_PATH_LENGTH: u16 = 42; + +impl HardDriveMediaDevicePath { + /// Returns the format of the partition (MBR, GPT, or unknown). + pub fn partition_format(&self) -> PartitionFormat { + self.partition_format + } + + /// Returns the 1-based index of the partition. + pub fn partition_number(&self) -> u32 { + self.partition_number + } + + /// Returns the partition size in logical blocks. + pub fn partition_size(&self) -> u64 { + self.partition_size + } + + /// Returns the starting LBA of the partition. + pub fn partition_start(&self) -> u64 { + self.partition_start + } + + /// Returns the MBR or GPT partition signature + pub fn partition_signature(&self) -> Option { + match self.signature_type { + SignatureType::MBR => { + let mbr_signature = unsafe { self.partition_signature.mbr_signature }; + Some(PartitionSignature::MBR(mbr_signature)) + } + SignatureType::GUID => { + let guid = unsafe { self.partition_signature.guid }; + Some(PartitionSignature::GUID(guid)) + } + _ => None, + } + } +} + +newtype_enum! { + /// Partition format. + pub enum PartitionFormat: u8 => { + /// MBR (PC-AT compatible Master Boot Record) format. + MBR = 0x01, + /// GPT (GUID Partition Table) format. + GPT = 0x02, + } +} + +/// Partition signature. +#[derive(Clone, Debug, Eq, PartialEq)] +pub enum PartitionSignature { + /// 32-bit MBR partition signature. + MBR(u32), + /// 128-bit GUID partition signature. + GUID(Guid), +} + +#[repr(C)] +union PartitionSignatureUnion { + mbr_signature: u32, + guid: Guid, +} + +newtype_enum! { + /// Signature type. + enum SignatureType: u8 => { + /// 32-bit MBR partition signature. + MBR = 0x01, + /// 128-bit GUID partition signature. + GUID = 0x02, + } +} + +#[cfg(test)] +mod tests { + use super::*; + use crate::CString16; + use alloc_api::vec::Vec; + + /// Create a node to `path` from raw data. + fn add_node(path: &mut Vec, device_type: u8, sub_type: u8, node_data: &[u8]) { + path.push(device_type); + path.push(sub_type); + path.extend( + u16::try_from(mem::size_of::() + node_data.len()) + .unwrap() + .to_le_bytes(), + ); + path.extend(node_data); + } + + /// Create a test device path list as raw bytes. + fn create_raw_device_path() -> Vec { + let mut raw_data = Vec::new(); + + // First path instance. + add_node(&mut raw_data, 0xa0, 0xb0, &[10, 11]); + add_node(&mut raw_data, 0xa1, 0xb1, &[20, 21, 22, 23]); + add_node( + &mut raw_data, + DeviceType::END.0, + DeviceSubType::END_INSTANCE.0, + &[], + ); + // Second path instance. + add_node(&mut raw_data, 0xa2, 0xb2, &[30, 31]); + add_node(&mut raw_data, 0xa3, 0xb3, &[40, 41, 42, 43]); + add_node( + &mut raw_data, + DeviceType::END.0, + DeviceSubType::END_ENTIRE.0, + &[], + ); + + raw_data + } + + /// Check that `node` has the expected content. + fn check_node(node: &DevicePathNode, device_type: u8, sub_type: u8, node_data: &[u8]) { + assert_eq!(node.device_type().0, device_type); + assert_eq!(node.sub_type().0, sub_type); + assert_eq!( + node.length(), + u16::try_from(mem::size_of::() + node_data.len()).unwrap() + ); + assert_eq!(&node.data, node_data); + } + + #[test] + fn test_device_path_nodes() { + let raw_data = create_raw_device_path(); + let dp = unsafe { DevicePath::from_ffi_ptr(raw_data.as_ptr().cast()) }; + + // Check that the size is the sum of the nodes' lengths. + assert_eq!(mem::size_of_val(dp), 6 + 8 + 4 + 6 + 8 + 4); + + // Check the list's node iter. + let nodes: Vec<_> = dp.node_iter().collect(); + check_node(nodes[0], 0xa0, 0xb0, &[10, 11]); + check_node(nodes[1], 0xa1, 0xb1, &[20, 21, 22, 23]); + check_node( + nodes[2], + DeviceType::END.0, + DeviceSubType::END_INSTANCE.0, + &[], + ); + check_node(nodes[3], 0xa2, 0xb2, &[30, 31]); + check_node(nodes[4], 0xa3, 0xb3, &[40, 41, 42, 43]); + // The end-entire node is not returned by the iterator. + assert_eq!(nodes.len(), 5); + } + + #[test] + fn test_device_path_instances() { + let raw_data = create_raw_device_path(); + let dp = unsafe { DevicePath::from_ffi_ptr(raw_data.as_ptr().cast()) }; + + // Check the list's instance iter. + let mut iter = dp.instance_iter(); + let mut instance = iter.next().unwrap(); + assert_eq!(mem::size_of_val(instance), 6 + 8 + 4); + + // Check the first instance's node iter. + let nodes: Vec<_> = instance.node_iter().collect(); + check_node(nodes[0], 0xa0, 0xb0, &[10, 11]); + check_node(nodes[1], 0xa1, 0xb1, &[20, 21, 22, 23]); + // The end node is not returned by the iterator. + assert_eq!(nodes.len(), 2); + + // Check second instance. + instance = iter.next().unwrap(); + assert_eq!(mem::size_of_val(instance), 6 + 8 + 4); + + let nodes: Vec<_> = instance.node_iter().collect(); + check_node(nodes[0], 0xa2, 0xb2, &[30, 31]); + check_node(nodes[1], 0xa3, 0xb3, &[40, 41, 42, 43]); + // The end node is not returned by the iterator. + assert_eq!(nodes.len(), 2); + + // Only two instances. + assert!(iter.next().is_none()); + } + + #[test] + fn test_file_path_media() { + // Manually create data for a `FilePathMediaDevicePath` node. + let raw_data: [u16; 7] = [ + // MEDIA | MEDIA_FILE_PATH + 0x0404, + // Length + 0x00_0e, + b't'.into(), + b'e'.into(), + b's'.into(), + b't'.into(), + // Trailing null. + 0, + ]; + + // Convert the raw data to a `DevicePath` node. + let dp = unsafe { DevicePathNode::from_ffi_ptr(raw_data.as_ptr().cast()) }; + assert_eq!(dp.length(), 14); + + // Check that the `file_name` is correct. + let fpm = dp.as_file_path_media_device_path().unwrap(); + assert_eq!( + fpm.path_name().to_cstring16().unwrap(), + CString16::try_from("test").unwrap() + ); + } + + #[test] + fn test_hard_drive_media_mbr() { + let mbr_partition_bytes: [u8; 42] = [ + 0x04, 0x01, 0x2a, 0x00, 0x01, 0x00, 0x00, 0x00, 0x3f, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0xc1, 0xbf, 0x0f, 0x00, 0x00, 0x00, 0x00, 0x00, 0xfa, 0xfd, 0x1a, 0xbe, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x01, + ]; + let dp = unsafe { DevicePathNode::from_ffi_ptr(mbr_partition_bytes.as_ptr().cast()) }; + assert_eq!(dp.length(), HARD_DRIVE_MEDIA_DEVICE_PATH_LENGTH); + + let hdm = dp.as_hard_drive_media_device_path().unwrap(); + assert_eq!(hdm.partition_format(), PartitionFormat::MBR); + assert_eq!(hdm.partition_number(), 1); + assert_eq!(hdm.partition_size(), 1032129); + assert_eq!(hdm.partition_start(), 63); + assert_eq!( + hdm.partition_signature(), + Some(PartitionSignature::MBR(0xBE1AFDFA)) + ); + } + + #[test] + fn test_hard_drive_media_gpt() { + let guid_partition_bytes: [u8; 42] = [ + 0x04, 0x01, 0x2a, 0x00, 0x01, 0x00, 0x00, 0x00, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x10, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0xa0, 0x39, 0xaa, 0x41, + 0x35, 0x3d, 0x84, 0x4f, 0xb1, 0x95, 0xae, 0x3a, 0x95, 0x0b, 0xfb, 0xad, 0x02, 0x02, + ]; + let dp = unsafe { DevicePathNode::from_ffi_ptr(guid_partition_bytes.as_ptr().cast()) }; + assert_eq!(dp.length(), HARD_DRIVE_MEDIA_DEVICE_PATH_LENGTH); + + let hdm = dp.as_hard_drive_media_device_path().unwrap(); + assert_eq!(hdm.partition_format(), PartitionFormat::GPT); + assert_eq!(hdm.partition_number(), 1); + assert_eq!(hdm.partition_size(), 200704); + assert_eq!(hdm.partition_start(), 128); + assert_eq!( + hdm.partition_signature(), + Some(PartitionSignature::GUID(Guid::from_values( + 0x41aa39a0, + 0x3d35, + 0x4f84, + 0xb195, + 0xae3a950bfbad + ))) + ); + } +} diff --git a/src/proto/device_path/text.rs b/src/proto/device_path/text.rs new file mode 100644 index 000000000..42c8408ca --- /dev/null +++ b/src/proto/device_path/text.rs @@ -0,0 +1,207 @@ +//! `DevicePathToText` and `DevicePathFromText` Protocol + +// Note on return types: the specification of the conversion functions +// is a little unusual in that they return a pointer rather than +// `EFI_STATUS`. A NULL pointer is used to indicate an error, and the +// spec says that will only happen if the input pointer is null (which +// can't happen here since we use references as input, not pointers), or +// if there is insufficient memory. So we treat any NULL output as an +// `OUT_OF_RESOURCES` error. + +use crate::{ + proto::device_path::{DevicePath, DevicePathNode, FfiDevicePath}, + proto::Protocol, + table::boot::BootServices, + unsafe_guid, CStr16, Char16, Result, Status, +}; +use core::ops::Deref; + +/// This struct is a wrapper of `display_only` parameter +/// used by Device Path to Text protocol. +/// +/// The `display_only` parameter controls whether the longer +/// (parseable) or shorter (display-only) form of the conversion +/// is used. If `display_only` is TRUE, then the shorter text +/// representation of the display node is used, where applicable. +/// If `display_only` is FALSE, then the longer text representation +/// of the display node is used. +#[derive(Clone, Copy)] +pub struct DisplayOnly(pub bool); + +/// This struct is a wrapper of `allow_shortcuts` parameter +/// used by Device Path to Text protocol. +/// +/// The `allow_shortcuts` is FALSE, then the shortcut forms of +/// text representation for a device node cannot be used. A +/// shortcut form is one which uses information other than the +/// type or subtype. If `allow_shortcuts is TRUE, then the +/// shortcut forms of text representation for a device node +/// can be used, where applicable. +#[derive(Clone, Copy)] +pub struct AllowShortcuts(pub bool); + +/// Wrapper for a string internally allocated from +/// UEFI boot services memory. +pub struct PoolString<'a> { + boot_services: &'a BootServices, + text: *const Char16, +} + +impl<'a> PoolString<'a> { + fn new(boot_services: &'a BootServices, text: *const Char16) -> Result { + if text.is_null() { + Err(Status::OUT_OF_RESOURCES.into()) + } else { + Ok(Self { + boot_services, + text, + }) + } + } +} + +impl<'a> Deref for PoolString<'a> { + type Target = CStr16; + + fn deref(&self) -> &Self::Target { + unsafe { CStr16::from_ptr(self.text) } + } +} + +impl Drop for PoolString<'_> { + fn drop(&mut self) { + let addr = self.text as *mut u8; + self.boot_services + .free_pool(addr) + .expect("Failed to free pool [{addr:#?}]"); + } +} + +/// Device Path to Text protocol. +/// +/// This protocol provides common utility functions for converting device +/// nodes and device paths to a text representation. +#[repr(C)] +#[unsafe_guid("8b843e20-8132-4852-90cc-551a4e4a7f1c")] +#[derive(Protocol)] +pub struct DevicePathToText { + convert_device_node_to_text: unsafe extern "efiapi" fn( + device_node: *const FfiDevicePath, + display_only: bool, + allow_shortcuts: bool, + ) -> *const Char16, + convert_device_path_to_text: unsafe extern "efiapi" fn( + device_path: *const FfiDevicePath, + display_only: bool, + allow_shortcuts: bool, + ) -> *const Char16, +} + +impl DevicePathToText { + /// Convert a device node to its text representation. + /// + /// Returns an [`OUT_OF_RESOURCES`] error if there is unsufficient + /// memory for the conversion. + /// + /// [`OUT_OF_RESOURCES`]: Status::OUT_OF_RESOURCES + pub fn convert_device_node_to_text<'boot>( + &self, + boot_services: &'boot BootServices, + device_node: &DevicePathNode, + display_only: DisplayOnly, + allow_shortcuts: AllowShortcuts, + ) -> Result> { + let text_device_node = unsafe { + (self.convert_device_node_to_text)( + device_node.as_ffi_ptr(), + display_only.0, + allow_shortcuts.0, + ) + }; + PoolString::new(boot_services, text_device_node) + } + + /// Convert a device path to its text representation. + /// + /// Returns an [`OUT_OF_RESOURCES`] error if there is unsufficient + /// memory for the conversion. + /// + /// [`OUT_OF_RESOURCES`]: Status::OUT_OF_RESOURCES + pub fn convert_device_path_to_text<'boot>( + &self, + boot_services: &'boot BootServices, + device_path: &DevicePath, + display_only: DisplayOnly, + allow_shortcuts: AllowShortcuts, + ) -> Result> { + let text_device_path = unsafe { + (self.convert_device_path_to_text)( + device_path.as_ffi_ptr(), + display_only.0, + allow_shortcuts.0, + ) + }; + PoolString::new(boot_services, text_device_path) + } +} + +/// Device Path from Text protocol. +/// +/// This protocol provides common utilities for converting text to +/// device paths and device nodes. +#[repr(C)] +#[unsafe_guid("05c99a21-c70f-4ad2-8a5f-35df3343f51e")] +#[derive(Protocol)] +pub struct DevicePathFromText { + convert_text_to_device_node: + unsafe extern "efiapi" fn(text_device_node: *const Char16) -> *const FfiDevicePath, + convert_text_to_device_path: + unsafe extern "efiapi" fn(text_device_path: *const Char16) -> *const FfiDevicePath, +} + +impl DevicePathFromText { + /// Convert text to the binary representation of a device node. + /// + /// `text_device_node` is the text representation of a device node. + /// Conversion starts with the first character and continues until + /// the first non-device node character. + /// + /// Returns an [`OUT_OF_RESOURCES`] error if there is unsufficient + /// memory for the conversion. + /// + /// [`OUT_OF_RESOURCES`]: Status::OUT_OF_RESOURCES + pub fn convert_text_to_device_node( + &self, + text_device_node: &CStr16, + ) -> Result<&DevicePathNode> { + unsafe { + let ptr = (self.convert_text_to_device_node)(text_device_node.as_ptr()); + if ptr.is_null() { + Err(Status::OUT_OF_RESOURCES.into()) + } else { + Ok(DevicePathNode::from_ffi_ptr(ptr)) + } + } + } + + /// Convert a text to its binary device path representation. + /// + /// `text_device_path` is the text representation of a device path. + /// Conversion starts with the first character and continues until + /// the first non-device path character. + /// + /// Returns an [`OUT_OF_RESOURCES`] error if there is unsufficient + /// memory for the conversion. + /// + /// [`OUT_OF_RESOURCES`]: Status::OUT_OF_RESOURCES + pub fn convert_text_to_device_path(&self, text_device_path: &CStr16) -> Result<&DevicePath> { + unsafe { + let ptr = (self.convert_text_to_device_path)(text_device_path.as_ptr()); + if ptr.is_null() { + Err(Status::OUT_OF_RESOURCES.into()) + } else { + Ok(DevicePath::from_ffi_ptr(ptr)) + } + } + } +} diff --git a/src/proto/loaded_image.rs b/src/proto/loaded_image.rs new file mode 100644 index 000000000..d90037b79 --- /dev/null +++ b/src/proto/loaded_image.rs @@ -0,0 +1,170 @@ +//! `LoadedImage` protocol. + +use crate::{ + data_types::FromSliceWithNulError, + proto::device_path::{DevicePath, FfiDevicePath}, + proto::Protocol, + table::boot::MemoryType, + unsafe_guid, CStr16, Handle, Status, +}; +use core::{ffi::c_void, mem, slice}; + +/// The LoadedImage protocol. This can be opened on any image handle using the `HandleProtocol` boot service. +#[repr(C)] +#[unsafe_guid("5b1b31a1-9562-11d2-8e3f-00a0c969723b")] +#[derive(Protocol)] +pub struct LoadedImage { + revision: u32, + parent_handle: Handle, + system_table: *const c_void, + + // Source location of the image + device_handle: Handle, + file_path: *const FfiDevicePath, + _reserved: *const c_void, + + // Image load options + load_options_size: u32, + load_options: *const u8, + + // Location where image was loaded + image_base: *const c_void, + image_size: u64, + image_code_type: MemoryType, + image_data_type: MemoryType, + /// This is a callback that a loaded image can use to do cleanup. It is called by the + /// `UnloadImage` boot service. + unload: extern "efiapi" fn(image_handle: Handle) -> Status, +} + +/// Errors that can be raised during parsing of the load options. +#[derive(Debug)] +pub enum LoadOptionsError { + /// Load options are not set. + NotSet, + + /// The start and/or length of the load options is not [`u16`]-aligned. + NotAligned, + + /// Not a valid null-terminated UCS-2 string. + InvalidString(FromSliceWithNulError), +} + +impl LoadedImage { + /// Returns a handle to the storage device on which the image is located. + pub fn device(&self) -> Handle { + self.device_handle + } + + /// Get a reference to the `file_path`. + /// + /// Return `None` if the pointer to the file path portion specific to + /// DeviceHandle that the EFI Image was loaded from is null. + pub fn file_path(&self) -> Option<&DevicePath> { + if self.file_path.is_null() { + None + } else { + unsafe { Some(DevicePath::from_ffi_ptr(self.file_path)) } + } + } + + /// Get the load options of the image as a [`&CStr16`]. + /// + /// Load options are typically used to pass command-line options as + /// a null-terminated UCS-2 string. This format is not required + /// though; use [`load_options_as_bytes`] to access the raw bytes. + /// + /// [`&CStr16`]: `CStr16` + /// [`load_options_as_bytes`]: `Self::load_options_as_bytes` + pub fn load_options_as_cstr16(&self) -> Result<&CStr16, LoadOptionsError> { + let load_options_size = usize::try_from(self.load_options_size).unwrap(); + + if self.load_options.is_null() { + Err(LoadOptionsError::NotSet) + } else if (load_options_size % mem::size_of::() != 0) + || (((self.load_options as usize) % mem::align_of::()) != 0) + { + Err(LoadOptionsError::NotAligned) + } else { + let s = unsafe { + slice::from_raw_parts( + self.load_options.cast::(), + load_options_size / mem::size_of::(), + ) + }; + CStr16::from_u16_with_nul(s).map_err(LoadOptionsError::InvalidString) + } + } + + /// Get the load options of the image as raw bytes. + /// + /// UEFI allows arbitrary binary data in load options, but typically + /// the data is a null-terminated UCS-2 string. Use + /// [`load_options_as_cstr16`] to more conveniently access the load + /// options as a string. + /// + /// Returns `None` if load options are not set. + /// + /// [`load_options_as_cstr16`]: `Self::load_options_as_cstr16` + pub fn load_options_as_bytes(&self) -> Option<&[u8]> { + if self.load_options.is_null() { + None + } else { + unsafe { + Some(slice::from_raw_parts( + self.load_options, + usize::try_from(self.load_options_size).unwrap(), + )) + } + } + } + + /// Set the image data address and size. + /// + /// This is useful in the following scenario: + /// 1. Secure boot is enabled, so images loaded with `LoadImage` must be + /// signed with an appropriate key known to the firmware. + /// 2. The bootloader has its own key embedded, and uses that key to + /// verify the next stage. This key is not known to the firmware, so + /// the next stage's image can't be loaded with `LoadImage`. + /// 3. Since image handles are created by `LoadImage`, which we can't + /// call, we have to make use of an existing image handle -- the one + /// passed into the bootloader's entry function. By modifying that + /// image handle (after appropriately verifying the signature of the + /// new data), we can repurpose the image handle for the next stage. + /// + /// See [shim] for an example of this scenario. + /// + /// # Safety + /// + /// This function takes `data` as a raw pointer because the data is not + /// owned by `LoadedImage`. The caller must ensure that the memory lives + /// long enough. + /// + /// [shim]: https://github.com/rhboot/shim/blob/4d64389c6c941d21548b06423b8131c872e3c3c7/pe.c#L1143 + pub unsafe fn set_image(&mut self, data: *const c_void, size: u64) { + self.image_base = data; + self.image_size = size; + } + + /// Set the load options for the image. This can be used prior to + /// calling `BootServices.start_image` to control the command line + /// passed to the image. + /// + /// `size` is in bytes. + /// + /// # Safety + /// + /// This function takes `options` as a raw pointer because the + /// load options data is not owned by `LoadedImage`. The caller + /// must ensure that the memory lives long enough. + pub unsafe fn set_load_options(&mut self, options: *const u8, size: u32) { + self.load_options = options; + self.load_options_size = size; + } + + /// Returns the base address and the size in bytes of the loaded image. + pub fn info(&self) -> (*const c_void, u64) { + (self.image_base, self.image_size) + } +} diff --git a/src/proto/media/block.rs b/src/proto/media/block.rs new file mode 100644 index 000000000..b95ba9807 --- /dev/null +++ b/src/proto/media/block.rs @@ -0,0 +1,191 @@ +//! Block I/O protocols. + +use crate::proto::Protocol; +use crate::{unsafe_guid, Result, Status}; + +/// The Block I/O protocol. +#[repr(C)] +#[unsafe_guid("964e5b21-6459-11d2-8e39-00a0c969723b")] +#[derive(Protocol)] +pub struct BlockIO { + revision: u64, + media: *const BlockIOMedia, + + reset: extern "efiapi" fn(this: &BlockIO, extended_verification: bool) -> Status, + read_blocks: extern "efiapi" fn( + this: &BlockIO, + media_id: u32, + lba: Lba, + buffer_size: usize, + buffer: *mut u8, + ) -> Status, + write_blocks: extern "efiapi" fn( + this: &BlockIO, + media_id: u32, + lba: Lba, + buffer_size: usize, + buffer: *const u8, + ) -> Status, + flush_blocks: extern "efiapi" fn(this: &BlockIO) -> Status, +} + +impl BlockIO { + /// Pointer for block IO media. + pub fn media(&self) -> &BlockIOMedia { + unsafe { &*self.media } + } + + /// Resets the block device hardware. + /// + /// # Arguments + /// * `extended_verification` Indicates that the driver may perform a more exhaustive verification operation of + /// the device during reset. + /// + /// # Errors + /// * `uefi::Status::DEVICE_ERROR` The block device is not functioning correctly and could not be reset. + pub fn reset(&mut self, extended_verification: bool) -> Result { + (self.reset)(self, extended_verification).into() + } + + /// Read the requested number of blocks from the device. + /// + /// # Arguments + /// * `media_id` - The media ID that the read request is for. + /// * `lba` - The starting logical block address to read from on the device. + /// * `buffer` - The target buffer of the read operation + /// + /// # Errors + /// * `uefi::Status::DEVICE_ERROR` The device reported an error while attempting to perform the read + /// operation. + /// * `uefi::Status::NO_MEDIA` There is no media in the device. + /// * `uefi::Status::MEDIA_CHANGED` The `media_id` is not for the current media. + /// * `uefi::Status::BAD_BUFFER_SIZE` The buffer size parameter is not a multiple of the intrinsic block size of + /// the device. + /// * `uefi::Status::INVALID_PARAMETER` The read request contains LBAs that are not valid, or the buffer is not on + /// proper alignment. + pub fn read_blocks(&self, media_id: u32, lba: Lba, buffer: &mut [u8]) -> Result { + let buffer_size = buffer.len(); + (self.read_blocks)(self, media_id, lba, buffer_size, buffer.as_mut_ptr()).into() + } + + /// Writes the requested number of blocks to the device. + /// + /// # Arguments + /// * `media_id` The media ID that the write request is for. + /// * `lba` The starting logical block address to be written. + /// * `buffer` Buffer to be written + /// + /// # Errors + /// * `uefi::Status::WRITE_PROTECTED` The device cannot be written to. + /// * `uefi::Status::NO_MEDIA` There is no media in the device. + /// * `uefi::Status::MEDIA_CHANGED` The `media_id` is not for the current media. + /// * `uefi::Status::DEVICE_ERROR` The device reported an error while attempting to perform the write + /// operation. + /// * `uefi::Status::BAD_BUFFER_SIZE` The buffer size parameter is not a multiple of the intrinsic block size + /// of the device. + /// * `uefi::Status::INVALID_PARAMETER` The write request contains LBAs that are not valid, or the buffer is not + /// on proper alignment. + pub fn write_blocks(&mut self, media_id: u32, lba: Lba, buffer: &[u8]) -> Result { + let buffer_size = buffer.len(); + (self.write_blocks)(self, media_id, lba, buffer_size, buffer.as_ptr()).into() + } + + /// Flushes all modified data to a physical block device. + /// + /// # Errors + /// * `uefi::Status::DEVICE_ERROR` The device reported an error while attempting to write data. + /// * `uefi::Status::NO_MEDIA` There is no media in the device. + pub fn flush_blocks(&mut self) -> Result { + (self.flush_blocks)(self).into() + } +} + +/// EFI LBA type +pub type Lba = u64; + +/// Media information structure +#[repr(C)] +#[derive(Debug)] +pub struct BlockIOMedia { + media_id: u32, + removable_media: bool, + media_present: bool, + logical_partition: bool, + read_only: bool, + write_caching: bool, + + block_size: u32, + io_align: u32, + last_block: Lba, + + // Revision 2 + lowest_aligned_lba: Lba, + logical_blocks_per_physical_block: u32, + + // Revision 3 + optimal_transfer_length_granularity: u32, +} + +impl BlockIOMedia { + /// The current media ID. + pub fn media_id(&self) -> u32 { + self.media_id + } + + /// True if the media is removable. + pub fn is_removable_media(&self) -> bool { + self.removable_media + } + + /// True if there is a media currently present in the device. + pub fn is_media_present(&self) -> bool { + self.media_present + } + + /// True if block IO was produced to abstract partition structure. + pub fn is_logical_partition(&self) -> bool { + self.logical_partition + } + + /// True if the media is marked read-only. + pub fn is_read_only(&self) -> bool { + self.read_only + } + + /// True if `writeBlocks` function writes data. + pub fn is_write_caching(&self) -> bool { + self.write_caching + } + + /// The intrinsic block size of the device. + /// + /// If the media changes, then this field is updated. Returns the number of bytes per logical block. + pub fn block_size(&self) -> u32 { + self.block_size + } + + /// Supplies the alignment requirement for any buffer used in a data transfer. + pub fn io_align(&self) -> u32 { + self.io_align + } + + /// The last LBA on the device. If the media changes, then this field is updated. + pub fn last_block(&self) -> Lba { + self.last_block + } + + /// Returns the first LBA that is aligned to a physical block boundary. + pub fn lowest_aligned_lba(&self) -> Lba { + self.lowest_aligned_lba + } + + /// Returns the number of logical blocks per physical block. + pub fn logical_blocks_per_physical_block(&self) -> u32 { + self.logical_blocks_per_physical_block + } + + /// Returns the optimal transfer length granularity as a number of logical blocks. + pub fn optimal_transfer_length_granularity(&self) -> u32 { + self.optimal_transfer_length_granularity + } +} diff --git a/src/proto/media/disk.rs b/src/proto/media/disk.rs new file mode 100644 index 000000000..9cf7926a7 --- /dev/null +++ b/src/proto/media/disk.rs @@ -0,0 +1,208 @@ +//! Disk I/O protocols. + +use crate::proto::Protocol; +use crate::{unsafe_guid, Event, Result, Status}; +use core::ptr::NonNull; + +/// The disk I/O protocol. +/// +/// This protocol is used to abstract the block accesses of the block I/O +/// protocol to a more general offset-length protocol. Firmware is +/// reponsible for adding this protocol to any block I/O interface that +/// appears in the system that does not already have a disk I/O protocol. +#[repr(C)] +#[unsafe_guid("ce345171-ba0b-11d2-8e4f-00a0c969723b")] +#[derive(Protocol)] +pub struct DiskIo { + revision: u64, + read_disk: extern "efiapi" fn( + this: &DiskIo, + media_id: u32, + offset: u64, + len: usize, + buffer: *mut u8, + ) -> Status, + write_disk: extern "efiapi" fn( + this: &mut DiskIo, + media_id: u32, + offset: u64, + len: usize, + buffer: *const u8, + ) -> Status, +} + +impl DiskIo { + /// Reads bytes from the disk device. + /// + /// # Arguments: + /// * `media_id` - ID of the medium to be read. + /// * `offset` - Starting byte offset on the logical block I/O device to read from. + /// * `buffer` - Pointer to a buffer to read into. + /// + /// # Errors: + /// * `uefi::status::INVALID_PARAMETER` The read request contains device addresses that + /// are not valid for the device. + /// * `uefi::status::DEVICE_ERROR` The device reported an error while performing + /// the read operation. + /// * `uefi::status::NO_MEDIA` There is no medium in the device. + /// * `uefi::status::MEDIA_CHANGED` `media_id` is not for the current medium. + pub fn read_disk(&self, media_id: u32, offset: u64, buffer: &mut [u8]) -> Result { + (self.read_disk)(self, media_id, offset, buffer.len(), buffer.as_mut_ptr()).into() + } + + /// Writes bytes to the disk device. + /// + /// # Arguments: + /// * `media_id` - ID of the medium to be written. + /// * `offset` - Starting byte offset on the logical block I/O device to write to. + /// * `buffer` - Pointer to a buffer to write from. + /// + /// # Errors: + /// * `uefi::status::INVALID_PARAMETER` The write request contains device addresses that + /// are not valid for the device. + /// * `uefi::status::DEVICE_ERROR` The device reported an error while performing + /// the write operation. + /// * `uefi::status::NO_MEDIA` There is no medium in the device. + /// * `uefi::status::MEDIA_CHANGED` `media_id` is not for the current medium. + /// * `uefi::status::WRITE_PROTECTED` The device cannot be written to. + pub fn write_disk(&mut self, media_id: u32, offset: u64, buffer: &[u8]) -> Result { + (self.write_disk)(self, media_id, offset, buffer.len(), buffer.as_ptr()).into() + } +} + +/// Asynchronous transaction token for disk I/O 2 operations. +#[repr(C)] +pub struct DiskIo2Token { + /// Event to be signalled when an asynchronous disk I/O operation completes. + pub event: Event, + /// Transaction status code. + pub transaction_status: Status, +} + +/// The disk I/O 2 protocol. +/// +/// This protocol provides an extension to the disk I/O protocol to enable +/// non-blocking / asynchronous byte-oriented disk operation. +#[repr(C)] +#[unsafe_guid("151c8eae-7f2c-472c-9e54-9828194f6a88")] +#[derive(Protocol)] +pub struct DiskIo2 { + revision: u64, + cancel: extern "efiapi" fn(this: &mut DiskIo2) -> Status, + read_disk_ex: extern "efiapi" fn( + this: &DiskIo2, + media_id: u32, + offset: u64, + token: Option>, + len: usize, + buffer: *mut u8, + ) -> Status, + write_disk_ex: extern "efiapi" fn( + this: &mut DiskIo2, + media_id: u32, + offset: u64, + token: Option>, + len: usize, + buffer: *const u8, + ) -> Status, + flush_disk_ex: + extern "efiapi" fn(this: &mut DiskIo2, token: Option>) -> Status, +} + +impl DiskIo2 { + /// Terminates outstanding asynchronous requests to the device. + /// + /// # Errors: + /// * `uefi::status::DEVICE_ERROR` The device reported an error while performing + /// the cancel operation. + pub fn cancel(&mut self) -> Result { + (self.cancel)(self).into() + } + + /// Reads bytes from the disk device. + /// + /// # Arguments: + /// * `media_id` - ID of the medium to be read from. + /// * `offset` - Starting byte offset on the logical block I/O device to read from. + /// * `token` - Transaction token for asynchronous read. + /// * `len` - Buffer size. + /// * `buffer` - Buffer to read into. + /// + /// # Safety + /// + /// Because of the asynchronous nature of the disk transaction, manual lifetime + /// tracking is required. + /// + /// # Errors: + /// * `uefi::status::INVALID_PARAMETER` The read request contains device addresses + /// that are not valid for the device. + /// * `uefi::status::OUT_OF_RESOURCES` The request could not be completed due to + /// a lack of resources. + /// * `uefi::status::MEDIA_CHANGED` `media_id` is not for the current medium. + /// * `uefi::status::NO_MEDIA` There is no medium in the device. + /// * `uefi::status::DEVICE_ERROR` The device reported an error while performing + /// the read operation. + pub unsafe fn read_disk_raw( + &self, + media_id: u32, + offset: u64, + token: Option>, + len: usize, + buffer: *mut u8, + ) -> Result { + (self.read_disk_ex)(self, media_id, offset, token, len, buffer).into() + } + + /// Writes bytes to the disk device. + /// + /// # Arguments: + /// * `media_id` - ID of the medium to write to. + /// * `offset` - Starting byte offset on the logical block I/O device to write to. + /// * `token` - Transaction token for asynchronous write. + /// * `len` - Buffer size. + /// * `buffer` - Buffer to write from. + /// + /// # Safety + /// + /// Because of the asynchronous nature of the disk transaction, manual lifetime + /// tracking is required. + /// + /// # Errors: + /// * `uefi::status::INVALID_PARAMETER` The write request contains device addresses + /// that are not valid for the device. + /// * `uefi::status::OUT_OF_RESOURCES` The request could not be completed due to + /// a lack of resources. + /// * `uefi::status::MEDIA_CHANGED` `media_id` is not for the current medium. + /// * `uefi::status::NO_MEDIA` There is no medium in the device. + /// * `uefi::status::DEVICE_ERROR` The device reported an error while performing + /// the write operation. + /// * `uefi::status::WRITE_PROTECTED` The device cannot be written to. + pub unsafe fn write_disk_raw( + &mut self, + media_id: u32, + offset: u64, + token: Option>, + len: usize, + buffer: *const u8, + ) -> Result { + (self.write_disk_ex)(self, media_id, offset, token, len, buffer).into() + } + + /// Flushes all modified data to the physical device. + /// + /// # Arguments: + /// * `token` - Transaction token for the asynchronous flush. + /// + /// # Errors: + /// * `uefi::status::OUT_OF_RESOURCES` The request could not be completed due to + /// a lack of resources. + /// * `uefi::status::MEDIA_CHANGED` The medium in the device has changed since + /// the last access. + /// * `uefi::status::NO_MEDIA` There is no medium in the device. + /// * `uefi::status::DEVICE_ERROR` The device reported an error while performing + /// the flush operation. + /// * `uefi::status::WRITE_PROTECTED` The device cannot be written to. + pub fn flush_disk(&mut self, token: Option>) -> Result { + (self.flush_disk_ex)(self, token).into() + } +} diff --git a/src/proto/media/file/dir.rs b/src/proto/media/file/dir.rs new file mode 100644 index 000000000..4f2a79d27 --- /dev/null +++ b/src/proto/media/file/dir.rs @@ -0,0 +1,78 @@ +use super::{File, FileHandle, FileInfo, FromUefi, RegularFile}; +use crate::data_types::Align; +use crate::Result; +use core::ffi::c_void; + +/// A `FileHandle` that is also a directory. +/// +/// Use `File::into_type` or `Directory::new` to create a `Directory`. In +/// addition to supporting the normal `File` operations, `Directory` +/// supports iterating over its contained files. +#[repr(transparent)] +pub struct Directory(RegularFile); + +impl Directory { + /// Coverts a `FileHandle` into a `Directory` without checking the file type. + /// # Safety + /// This function should only be called on files which ARE directories, + /// doing otherwise is unsafe. + pub unsafe fn new(handle: FileHandle) -> Self { + Self(RegularFile::new(handle)) + } + + /// Read the next directory entry + /// + /// Try to read the next directory entry into `buffer`. If the buffer is too small, report the + /// required buffer size as part of the error. If there are no more directory entries, return + /// an empty optional. + /// + /// The input buffer must be correctly aligned for a `FileInfo`. You can query the required + /// alignment through the `Align` trait (`::alignment()`). + /// + /// # Arguments + /// * `buffer` The target buffer of the read operation + /// + /// # Errors + /// * `uefi::Status::NO_MEDIA` The device has no media + /// * `uefi::Status::DEVICE_ERROR` The device reported an error, the file was deleted, + /// or the end of the file was reached before the `read()`. + /// * `uefi::Status::VOLUME_CORRUPTED` The filesystem structures are corrupted + /// * `uefi::Status::BUFFER_TOO_SMALL` The buffer is too small to hold a directory entry, + /// the required buffer size is provided into the error. + pub fn read_entry<'buf>( + &mut self, + buffer: &'buf mut [u8], + ) -> Result, Option> { + // Make sure that the storage is properly aligned + FileInfo::assert_aligned(buffer); + + // Read the directory entry into the aligned storage + self.0.read(buffer).map(|size| { + if size != 0 { + unsafe { Some(FileInfo::from_uefi(buffer.as_mut_ptr().cast::())) } + } else { + None + } + }) + } + + /// Start over the process of enumerating directory entries + pub fn reset_entry_readout(&mut self) -> Result { + self.0.set_position(0) + } +} + +impl File for Directory { + #[inline] + fn handle(&mut self) -> &mut FileHandle { + self.0.handle() + } + + fn is_regular_file(&self) -> Result { + Ok(false) + } + + fn is_directory(&self) -> Result { + Ok(true) + } +} diff --git a/src/proto/media/file/info.rs b/src/proto/media/file/info.rs new file mode 100644 index 000000000..2f96b1f72 --- /dev/null +++ b/src/proto/media/file/info.rs @@ -0,0 +1,491 @@ +use super::FileAttribute; +use crate::data_types::Align; +use crate::table::runtime::Time; +use crate::{unsafe_guid, CStr16, Char16, Identify}; +use core::ffi::c_void; +use core::{mem, ptr}; + +/// Common trait for data structures that can be used with +/// `File::set_info()` or `File::get_info()`. +/// +/// The long-winded name is needed because "FileInfo" is already taken by UEFI. +pub trait FileProtocolInfo: Align + Identify + FromUefi {} + +/// Trait for going from an UEFI-originated pointer to a Rust reference +/// +/// This is trivial for `Sized` types, but requires some work when operating on +/// dynamic-sized types like `NamedFileProtocolInfo`, as the second member of +/// the fat pointer must be reconstructed using hidden UEFI-provided metadata. +pub trait FromUefi { + /// Turn an UEFI-provided pointer-to-base into a (possibly fat) Rust reference + /// + /// # Safety + /// + /// This function can lead to undefined behavior if the given pointer is not + /// pointing to a valid object of the specified type. + unsafe fn from_uefi<'ptr>(ptr: *mut c_void) -> &'ptr mut Self; +} + +/// Internal trait for initializing one of the info types. +/// +/// This is used with `FileInfo`, `FileSystemInfo`, and +/// `FileSystemVolumeLabel`, all of which are dynamically-sized structs +/// that have zero or more header fields followed by a variable-length +/// [Char16] name. +trait InfoInternal: Align + ptr::Pointee { + /// Offset in bytes of the start of the name slice at the end of + /// the struct. + fn name_offset() -> usize; + + /// Get a mutable pointer to the name slice at the end of the + /// struct. + unsafe fn name_ptr(ptr: *mut u8) -> *mut Char16 { + let offset_of_str = Self::name_offset(); + ptr.add(offset_of_str).cast::() + } + + /// Create a new info type in user-provided storage. + /// + /// The structure will be created in-place within the provided + /// `storage` buffer. The alignment and size of the buffer is + /// checked, then the `init` function is called to fill in the + /// struct header (everything except for the name slice). The name + /// slice is then initialized, and at that point the struct is fully + /// initialized so it's safe to create a reference. + /// + /// # Safety + /// + /// The `init` function must initialize the entire struct except for + /// the name slice. + unsafe fn new_impl<'buf, F>( + storage: &'buf mut [u8], + name: &CStr16, + init: F, + ) -> Result<&'buf mut Self, FileInfoCreationError> + where + F: FnOnce(*mut Self, u64), + { + // Calculate the final size of the struct. + let name_length_ucs2 = name.as_slice_with_nul().len(); + let name_size = name_length_ucs2 * mem::size_of::(); + let info_size = Self::name_offset() + name_size; + let info_size = Self::round_up_to_alignment(info_size); + + // Make sure that the storage is properly aligned + let storage = Self::align_buf(storage) + .ok_or(FileInfoCreationError::InsufficientStorage(info_size))?; + Self::assert_aligned(storage); + + // Make sure that the storage is large enough for our needs + if storage.len() < info_size { + return Err(FileInfoCreationError::InsufficientStorage(info_size)); + } + + // Create a raw fat pointer using the `storage` as a base. + let info_ptr: *mut Self = + ptr::from_raw_parts_mut(storage.as_mut_ptr().cast::<()>(), name_length_ucs2); + + // Initialize the struct header. + init(info_ptr, info_size as u64); + + // Create a pointer to the part of info where the name is + // stored. Note that `info_ptr` is used rather than `storage` to + // comply with Stacked Borrows. + let info_name_ptr = Self::name_ptr(info_ptr.cast::()); + + // Initialize the name slice. + ptr::copy(name.as_ptr(), info_name_ptr, name_length_ucs2); + + // The struct is now valid and safe to dereference. + let info = &mut *info_ptr; + Ok(info) + } +} + +impl FromUefi for T +where + T: InfoInternal + ?Sized, +{ + unsafe fn from_uefi<'ptr>(ptr: *mut c_void) -> &'ptr mut Self { + let name_ptr = Self::name_ptr(ptr.cast::()); + let name = CStr16::from_ptr(name_ptr); + let name_len = name.as_slice_with_nul().len(); + &mut *ptr::from_raw_parts_mut(ptr.cast::<()>(), name_len) + } +} + +/// Errors that can occur when creating a `FileProtocolInfo` +#[derive(Clone, Copy, Debug, Eq, PartialEq)] +pub enum FileInfoCreationError { + /// The provided buffer was too small to hold the `FileInfo`. You need at + /// least the indicated buffer size (in bytes). Please remember that using + /// a misaligned buffer will cause a decrease of usable storage capacity. + InsufficientStorage(usize), +} + +/// Generic file information +/// +/// The following rules apply when using this struct with `set_info()`: +/// +/// - On directories, the file size is determined by the contents of the +/// directory and cannot be changed by setting `file_size`. This member is +/// ignored by `set_info()`. +/// - The `physical_size` is determined by the `file_size` and cannot be +/// changed. This member is ignored by `set_info()`. +/// - The `FileAttribute::DIRECTORY` bit cannot be changed. It must match the +/// file’s actual type. +/// - A value of zero in create_time, last_access, or modification_time causes +/// the fields to be ignored (and not updated). +/// - It is forbidden to change the name of a file to the name of another +/// existing file in the same directory. +/// - If a file is read-only, the only allowed change is to remove the read-only +/// attribute. Other changes must be carried out in a separate transaction. +#[derive(Debug, Eq, PartialEq)] +#[repr(C)] +#[unsafe_guid("09576e92-6d3f-11d2-8e39-00a0c969723b")] +pub struct FileInfo { + size: u64, + file_size: u64, + physical_size: u64, + create_time: Time, + last_access_time: Time, + modification_time: Time, + attribute: FileAttribute, + file_name: [Char16], +} + +impl FileInfo { + /// Create a `FileInfo` structure + /// + /// The structure will be created in-place within the provided storage + /// buffer. The buffer must be large enough to hold the data structure, + /// including a null-terminated UCS-2 `name` string. + /// + /// The buffer must be correctly aligned. You can query the required + /// alignment using the `alignment()` method of the `Align` trait that this + /// struct implements. + #[allow(clippy::too_many_arguments)] + pub fn new<'buf>( + storage: &'buf mut [u8], + file_size: u64, + physical_size: u64, + create_time: Time, + last_access_time: Time, + modification_time: Time, + attribute: FileAttribute, + file_name: &CStr16, + ) -> core::result::Result<&'buf mut Self, FileInfoCreationError> { + unsafe { + Self::new_impl(storage, file_name, |ptr, size| { + ptr::addr_of_mut!((*ptr).size).write(size); + ptr::addr_of_mut!((*ptr).file_size).write(file_size); + ptr::addr_of_mut!((*ptr).physical_size).write(physical_size); + ptr::addr_of_mut!((*ptr).create_time).write(create_time); + ptr::addr_of_mut!((*ptr).last_access_time).write(last_access_time); + ptr::addr_of_mut!((*ptr).modification_time).write(modification_time); + ptr::addr_of_mut!((*ptr).attribute).write(attribute); + }) + } + } + + /// File size (number of bytes stored in the file) + pub fn file_size(&self) -> u64 { + self.file_size + } + + /// Physical space consumed by the file on the file system volume + pub fn physical_size(&self) -> u64 { + self.physical_size + } + + /// Time when the file was created + pub fn create_time(&self) -> &Time { + &self.create_time + } + + /// Time when the file was last accessed + pub fn last_access_time(&self) -> &Time { + &self.last_access_time + } + + /// Time when the file's contents were last modified + pub fn modification_time(&self) -> &Time { + &self.modification_time + } + + /// Attribute bits for the file + pub fn attribute(&self) -> FileAttribute { + self.attribute + } + + /// Name of the file + pub fn file_name(&self) -> &CStr16 { + unsafe { CStr16::from_ptr(self.file_name.as_ptr()) } + } +} + +impl Align for FileInfo { + fn alignment() -> usize { + 8 + } +} + +impl InfoInternal for FileInfo { + fn name_offset() -> usize { + 80 + } +} + +impl FileProtocolInfo for FileInfo {} + +/// System volume information +/// +/// May only be obtained on the root directory's file handle. +/// +/// Please note that only the system volume's volume label may be set using +/// this information structure. Consider using `FileSystemVolumeLabel` instead. +#[derive(Debug, Eq, PartialEq)] +#[repr(C)] +#[unsafe_guid("09576e93-6d3f-11d2-8e39-00a0c969723b")] +pub struct FileSystemInfo { + size: u64, + read_only: bool, + volume_size: u64, + free_space: u64, + block_size: u32, + volume_label: [Char16], +} + +impl FileSystemInfo { + /// Create a `FileSystemInfo` structure + /// + /// The structure will be created in-place within the provided storage + /// buffer. The buffer must be large enough to hold the data structure, + /// including a null-terminated UCS-2 `name` string. + /// + /// The buffer must be correctly aligned. You can query the required + /// alignment using the `alignment()` method of the `Align` trait that this + /// struct implements. + pub fn new<'buf>( + storage: &'buf mut [u8], + read_only: bool, + volume_size: u64, + free_space: u64, + block_size: u32, + volume_label: &CStr16, + ) -> core::result::Result<&'buf mut Self, FileInfoCreationError> { + unsafe { + Self::new_impl(storage, volume_label, |ptr, size| { + ptr::addr_of_mut!((*ptr).size).write(size); + ptr::addr_of_mut!((*ptr).read_only).write(read_only); + ptr::addr_of_mut!((*ptr).volume_size).write(volume_size); + ptr::addr_of_mut!((*ptr).free_space).write(free_space); + ptr::addr_of_mut!((*ptr).block_size).write(block_size); + }) + } + } + + /// Truth that the volume only supports read access + pub fn read_only(&self) -> bool { + self.read_only + } + + /// Number of bytes managed by the file system + pub fn volume_size(&self) -> u64 { + self.volume_size + } + + /// Number of available bytes for use by the file system + pub fn free_space(&self) -> u64 { + self.free_space + } + + /// Nominal block size by which files are typically grown + pub fn block_size(&self) -> u32 { + self.block_size + } + + /// Volume label + pub fn volume_label(&self) -> &CStr16 { + unsafe { CStr16::from_ptr(self.volume_label.as_ptr()) } + } +} + +impl Align for FileSystemInfo { + fn alignment() -> usize { + 8 + } +} + +impl InfoInternal for FileSystemInfo { + fn name_offset() -> usize { + 36 + } +} + +impl FileProtocolInfo for FileSystemInfo {} + +/// System volume label +/// +/// May only be obtained on the root directory's file handle. +#[derive(Debug, Eq, PartialEq)] +#[repr(C)] +#[unsafe_guid("db47d7d3-fe81-11d3-9a35-0090273fc14d")] +pub struct FileSystemVolumeLabel { + volume_label: [Char16], +} + +impl FileSystemVolumeLabel { + /// Create a `FileSystemVolumeLabel` structure + /// + /// The structure will be created in-place within the provided storage + /// buffer. The buffer must be large enough to hold the data structure, + /// including a null-terminated UCS-2 `name` string. + /// + /// The buffer must be correctly aligned. You can query the required + /// alignment using the `alignment()` method of the `Align` trait that this + /// struct implements. + pub fn new<'buf>( + storage: &'buf mut [u8], + volume_label: &CStr16, + ) -> core::result::Result<&'buf mut Self, FileInfoCreationError> { + unsafe { Self::new_impl(storage, volume_label, |_ptr, _size| {}) } + } + + /// Volume label + pub fn volume_label(&self) -> &CStr16 { + unsafe { CStr16::from_ptr(self.volume_label.as_ptr()) } + } +} + +impl Align for FileSystemVolumeLabel { + fn alignment() -> usize { + 2 + } +} + +impl InfoInternal for FileSystemVolumeLabel { + fn name_offset() -> usize { + 0 + } +} + +impl FileProtocolInfo for FileSystemVolumeLabel {} + +#[cfg(test)] +mod tests { + use super::*; + use crate::alloc_api::vec; + use crate::table::runtime::TimeParams; + use crate::table::runtime::{Daylight, Time}; + use crate::CString16; + + fn validate_layout(info: &T, name: &[Char16]) { + // Check the hardcoded struct alignment. + assert_eq!(mem::align_of_val(info), T::alignment()); + // Check the hardcoded name slice offset. + assert_eq!( + unsafe { (name.as_ptr() as *const u8).offset_from(info as *const _ as *const u8) }, + T::name_offset() as isize + ); + } + + #[test] + fn test_file_info() { + let mut storage = vec![0; 128]; + + let file_size = 123; + let physical_size = 456; + let tp = TimeParams { + year: 1970, + month: 1, + day: 1, + hour: 0, + minute: 0, + second: 0, + nanosecond: 0, + time_zone: None, + daylight: Daylight::IN_DAYLIGHT, + }; + let create_time = Time::new(tp).unwrap(); + let last_access_time = Time::new(TimeParams { year: 1971, ..tp }).unwrap(); + let modification_time = Time::new(TimeParams { year: 1972, ..tp }).unwrap(); + let attribute = FileAttribute::READ_ONLY; + let name = CString16::try_from("test_name").unwrap(); + let info = FileInfo::new( + &mut storage, + file_size, + physical_size, + create_time, + last_access_time, + modification_time, + attribute, + &name, + ) + .unwrap(); + + validate_layout(info, &info.file_name); + + // Header size: 80 bytes + // + Name size (including trailing null): 20 bytes + // = 100 + // Round size up to match FileInfo alignment of 8: 104 + assert_eq!(info.size, 104); + assert_eq!(info.size, mem::size_of_val(info) as u64); + + assert_eq!(info.file_size(), file_size); + assert_eq!(info.physical_size(), physical_size); + assert_eq!(info.create_time(), &create_time); + assert_eq!(info.last_access_time(), &last_access_time); + assert_eq!(info.modification_time(), &modification_time); + assert_eq!(info.attribute(), attribute); + assert_eq!(info.file_name(), name); + } + + #[test] + fn test_file_system_info() { + let mut storage = vec![0; 128]; + + let read_only = true; + let volume_size = 123; + let free_space = 456; + let block_size = 789; + let name = CString16::try_from("test_name2").unwrap(); + let info = FileSystemInfo::new( + &mut storage, + read_only, + volume_size, + free_space, + block_size, + &name, + ) + .unwrap(); + + validate_layout(info, &info.volume_label); + + // Header size: 36 bytes + // + Name size (including trailing null): 22 bytes + // = 58 + // Round size up to match FileSystemInfo alignment of 8: 64 + assert_eq!(info.size, 64); + assert_eq!(info.size, mem::size_of_val(info) as u64); + + assert_eq!(info.read_only, read_only); + assert_eq!(info.volume_size, volume_size); + assert_eq!(info.free_space, free_space); + assert_eq!(info.block_size, block_size); + assert_eq!(info.volume_label(), name); + } + + #[test] + fn test_file_system_volume_label() { + let mut storage = vec![0; 128]; + + let name = CString16::try_from("test_name").unwrap(); + let info = FileSystemVolumeLabel::new(&mut storage, &name).unwrap(); + + validate_layout(info, &info.volume_label); + + assert_eq!(info.volume_label(), name); + } +} diff --git a/src/proto/media/file/mod.rs b/src/proto/media/file/mod.rs new file mode 100644 index 000000000..37dd1e9b3 --- /dev/null +++ b/src/proto/media/file/mod.rs @@ -0,0 +1,531 @@ +//! This module provides the `FileHandle` structure as well as the more specific `RegularFile` and +//! `Directory` structures. This module also provides the `File` trait for opening, querying, +//! creating, reading, and writing files. +//! +//! Usually a file system implementation will return a "root" directory, representing +//! `/` on that volume. With that directory, it is possible to enumerate and open +//! all the other files on that volume. + +mod dir; +mod info; +mod regular; + +use crate::{CStr16, Char16, Guid, Result, Status}; +use bitflags::bitflags; +use core::ffi::c_void; +use core::fmt::Debug; +use core::mem; +use core::ptr; +#[cfg(feature = "exts")] +use { + crate::ResultExt, + alloc_api::{alloc, alloc::Layout, boxed::Box}, + core::slice, +}; + +pub use self::info::{FileInfo, FileProtocolInfo, FileSystemInfo, FileSystemVolumeLabel, FromUefi}; +pub use self::{dir::Directory, regular::RegularFile}; + +/// Common interface to `FileHandle`, `RegularFile`, and `Directory`. +/// +/// `File` contains all functionality that is safe to perform on any type of +/// file handle. +pub trait File: Sized { + /// Access the underlying file handle. + #[doc(hidden)] + fn handle(&mut self) -> &mut FileHandle; + + /// Try to open a file relative to this file. + /// + /// # Arguments + /// * `filename` Path of file to open, relative to this file + /// * `open_mode` The mode to open the file with + /// * `attributes` Only valid when `FILE_MODE_CREATE` is used as a mode + /// + /// # Errors + /// * `uefi::Status::INVALID_PARAMETER` The filename exceeds the maximum length of 255 chars + /// * `uefi::Status::NOT_FOUND` Could not find file + /// * `uefi::Status::NO_MEDIA` The device has no media + /// * `uefi::Status::MEDIA_CHANGED` The device has a different medium in it + /// * `uefi::Status::DEVICE_ERROR` The device reported an error + /// * `uefi::Status::VOLUME_CORRUPTED` The filesystem structures are corrupted + /// * `uefi::Status::WRITE_PROTECTED` Write/Create attempted on readonly file + /// * `uefi::Status::ACCESS_DENIED` The service denied access to the file + /// * `uefi::Status::OUT_OF_RESOURCES` Not enough resources to open file + /// * `uefi::Status::VOLUME_FULL` The volume is full + fn open( + &mut self, + filename: &CStr16, + open_mode: FileMode, + attributes: FileAttribute, + ) -> Result { + let mut ptr = ptr::null_mut(); + + unsafe { + (self.imp().open)( + self.imp(), + &mut ptr, + filename.as_ptr(), + open_mode, + attributes, + ) + } + .into_with_val(|| unsafe { FileHandle::new(ptr) }) + } + + /// Close this file handle. Same as dropping this structure. + fn close(self) {} + + /// Closes and deletes this file + /// + /// # Warnings + /// * `uefi::Status::WARN_DELETE_FAILURE` The file was closed, but deletion failed + fn delete(mut self) -> Result { + let result = (self.imp().delete)(self.imp()).into(); + mem::forget(self); + result + } + + /// Queries some information about a file + /// + /// The information will be written into a user-provided buffer. + /// If the buffer is too small, the required buffer size will be returned as part of the error. + /// + /// The buffer must be aligned on an `::alignment()` boundary. + /// + /// # Arguments + /// * `buffer` Buffer that the information should be written into + /// + /// # Errors + /// * `uefi::Status::UNSUPPORTED` The file does not possess this information type + /// * `uefi::Status::NO_MEDIA` The device has no medium + /// * `uefi::Status::DEVICE_ERROR` The device reported an error + /// * `uefi::Status::VOLUME_CORRUPTED` The file system structures are corrupted + /// * `uefi::Status::BUFFER_TOO_SMALL` The buffer is too small for the requested + fn get_info<'buf, Info: FileProtocolInfo + ?Sized>( + &mut self, + buffer: &'buf mut [u8], + ) -> Result<&'buf mut Info, Option> { + let mut buffer_size = buffer.len(); + Info::assert_aligned(buffer); + unsafe { + (self.imp().get_info)( + self.imp(), + &Info::GUID, + &mut buffer_size, + buffer.as_mut_ptr(), + ) + } + .into_with( + || unsafe { Info::from_uefi(buffer.as_mut_ptr().cast::()) }, + |s| { + if s == Status::BUFFER_TOO_SMALL { + Some(buffer_size) + } else { + None + } + }, + ) + } + + /// Sets some information about a file + /// + /// There are various restrictions on the information that may be modified using this method. + /// The simplest one is that it is usually not possible to call it on read-only media. Further + /// restrictions specific to a given information type are described in the corresponding + /// `FileProtocolInfo` type documentation. + /// + /// # Arguments + /// * `info` Info that should be set for the file + /// + /// # Errors + /// * `uefi::Status::UNSUPPORTED` The file does not possess this information type + /// * `uefi::Status::NO_MEDIA` The device has no medium + /// * `uefi::Status::DEVICE_ERROR` The device reported an error + /// * `uefi::Status::VOLUME_CORRUPTED` The file system structures are corrupted + /// * `uefi::Status::WRITE_PROTECTED` Attempted to set information on a read-only media + /// * `uefi::Status::ACCESS_DENIED` Requested change is invalid for this information type + /// * `uefi::Status::VOLUME_FULL` Not enough space left on the volume to change the info + fn set_info(&mut self, info: &Info) -> Result { + let info_ptr = (info as *const Info).cast::(); + let info_size = mem::size_of_val(&info); + unsafe { (self.imp().set_info)(self.imp(), &Info::GUID, info_size, info_ptr).into() } + } + + /// Flushes all modified data associated with the file handle to the device + /// + /// # Errors + /// * `uefi::Status::NO_MEDIA` The device has no media + /// * `uefi::Status::DEVICE_ERROR` The device reported an error + /// * `uefi::Status::VOLUME_CORRUPTED` The filesystem structures are corrupted + /// * `uefi::Status::WRITE_PROTECTED` The file or medium is write protected + /// * `uefi::Status::ACCESS_DENIED` The file was opened read only + /// * `uefi::Status::VOLUME_FULL` The volume is full + fn flush(&mut self) -> Result { + (self.imp().flush)(self.imp()).into() + } + + #[cfg(feature = "exts")] + /// Get the dynamically allocated info for a file + fn get_boxed_info(&mut self) -> Result> { + // Initially try get_info with an empty array, this should always fail + // as all Info types at least need room for a null-terminator. + let size = match self + .get_info::(&mut []) + .expect_err("zero sized get_info unexpectedly succeeded") + .split() + { + (s, None) => return Err(s.into()), + (_, Some(size)) => size, + }; + + // We add trailing padding because the size of a rust structure must + // always be a multiple of alignment. + let layout = Layout::from_size_align(size, Info::alignment()) + .unwrap() + .pad_to_align(); + + // Allocate the buffer. + let data: *mut u8 = unsafe { + let data = alloc::alloc(layout); + if data.is_null() { + return Err(Status::OUT_OF_RESOURCES.into()); + } + data + }; + + // Get the file info using the allocated buffer for storage. + let info = { + let buffer = unsafe { slice::from_raw_parts_mut(data, layout.size()) }; + self.get_info::(buffer).discard_errdata() + }; + + // If an error occurred, deallocate the memory before returning. + let info = match info { + Ok(info) => info, + Err(err) => { + unsafe { alloc::dealloc(data, layout) }; + return Err(err); + } + }; + + // Wrap the file info in a box so that it will be deallocated on + // drop. This is valid because the memory was allocated with the + // global allocator. + unsafe { Ok(Box::from_raw(info)) } + } + + /// Returns if the underlying file is a regular file. + /// The result is an error if the underlying file was already closed or deleted. + /// + /// UEFI file system protocol only knows "regular files" and "directories". + fn is_regular_file(&self) -> Result; + + /// Returns if the underlying file is a directory. + /// The result is an error if the underlying file was already closed or deleted. + /// + /// UEFI file system protocol only knows "regular files" and "directories". + fn is_directory(&self) -> Result; +} + +// Internal File helper methods to access the funciton pointer table. +trait FileInternal: File { + fn imp(&mut self) -> &mut FileImpl { + unsafe { &mut *self.handle().0 } + } +} + +impl FileInternal for T {} + +/// An opaque handle to some contiguous block of data on a volume. +/// +/// A `FileHandle` is just a wrapper around a UEFI file handle. Under the hood, it can either be a +/// `RegularFile` or a `Directory`; use the `into_type()` or the unsafe +/// `{RegularFile, Directory}::new()` methods to perform the conversion. +/// +/// Dropping this structure will result in the file handle being closed. +#[repr(transparent)] +pub struct FileHandle(*mut FileImpl); + +impl FileHandle { + pub(super) unsafe fn new(ptr: *mut FileImpl) -> Self { + Self(ptr) + } + + /// Converts `File` into a more specific subtype based on if it is a + /// directory or not. Wrapper around [Self::is_regular_file]. + pub fn into_type(self) -> Result { + use FileType::*; + + self.is_regular_file().map(|is_file| { + if is_file { + unsafe { Regular(RegularFile::new(self)) } + } else { + unsafe { Dir(Directory::new(self)) } + } + }) + } + + /// If the handle represents a directory, convert it into a + /// [`Directory`]. Otherwise returns `None`. + pub fn into_directory(self) -> Option { + if let Ok(FileType::Dir(dir)) = self.into_type() { + Some(dir) + } else { + None + } + } + + /// If the handle represents a regular file, convert it into a + /// [`RegularFile`]. Otherwise returns `None`. + pub fn into_regular_file(self) -> Option { + if let Ok(FileType::Regular(regular)) = self.into_type() { + Some(regular) + } else { + None + } + } +} + +impl File for FileHandle { + #[inline] + fn handle(&mut self) -> &mut FileHandle { + self + } + + fn is_regular_file(&self) -> Result { + let this = unsafe { self.0.as_mut().unwrap() }; + + // - get_position fails with EFI_UNSUPPORTED on directories + // - result is an error if the underlying file was already closed or deleted. + let mut pos = 0; + match (this.get_position)(this, &mut pos) { + Status::SUCCESS => Ok(true), + Status::UNSUPPORTED => Ok(false), + s => Err(s.into()), + } + } + + fn is_directory(&self) -> Result { + self.is_regular_file().map(|b| !b) + } +} + +impl Drop for FileHandle { + fn drop(&mut self) { + let result: Result = (self.imp().close)(self.imp()).into(); + // The spec says this always succeeds. + result.expect("Failed to close file"); + } +} + +/// The function pointer table for the File protocol. +#[repr(C)] +pub(super) struct FileImpl { + revision: u64, + open: unsafe extern "efiapi" fn( + this: &mut FileImpl, + new_handle: &mut *mut FileImpl, + filename: *const Char16, + open_mode: FileMode, + attributes: FileAttribute, + ) -> Status, + close: extern "efiapi" fn(this: &mut FileImpl) -> Status, + delete: extern "efiapi" fn(this: &mut FileImpl) -> Status, + read: unsafe extern "efiapi" fn( + this: &mut FileImpl, + buffer_size: &mut usize, + buffer: *mut u8, + ) -> Status, + write: unsafe extern "efiapi" fn( + this: &mut FileImpl, + buffer_size: &mut usize, + buffer: *const u8, + ) -> Status, + get_position: extern "efiapi" fn(this: &mut FileImpl, position: &mut u64) -> Status, + set_position: extern "efiapi" fn(this: &mut FileImpl, position: u64) -> Status, + get_info: unsafe extern "efiapi" fn( + this: &mut FileImpl, + information_type: &Guid, + buffer_size: &mut usize, + buffer: *mut u8, + ) -> Status, + set_info: unsafe extern "efiapi" fn( + this: &mut FileImpl, + information_type: &Guid, + buffer_size: usize, + buffer: *const c_void, + ) -> Status, + flush: extern "efiapi" fn(this: &mut FileImpl) -> Status, +} + +/// Disambiguates the file type. Returned by `File::into_type()`. +pub enum FileType { + /// The file was a regular (data) file. + Regular(RegularFile), + /// The file was a directory. + Dir(Directory), +} + +/// Usage flags describing what is possible to do with the file. +/// +/// SAFETY: Using a repr(C) enum is safe here because this type is only sent to +/// the UEFI implementation, and never received from it. +#[derive(Debug, Copy, Clone, Eq, PartialEq)] +#[repr(u64)] +pub enum FileMode { + /// The file can be read from + Read = 1, + + /// The file can be read from and written to + ReadWrite = 2 | 1, + + /// The file can be read, written, and will be created if it does not exist + CreateReadWrite = (1 << 63) | 2 | 1, +} + +bitflags! { + /// Attributes describing the properties of a file on the file system. + #[repr(transparent)] + pub struct FileAttribute: u64 { + /// File can only be opened in [`FileMode::READ`] mode. + const READ_ONLY = 1; + /// Hidden file, not normally visible to the user. + const HIDDEN = 1 << 1; + /// System file, indicates this file is an internal operating system file. + const SYSTEM = 1 << 2; + /// This file is a directory. + const DIRECTORY = 1 << 4; + /// This file is compressed. + const ARCHIVE = 1 << 5; + /// Mask combining all the valid attributes. + const VALID_ATTR = 0x37; + } +} + +#[cfg(test)] +mod tests { + use super::*; + use crate::table::runtime::Time; + use crate::{CString16, Identify}; + use alloc_api::vec; + + // Test `get_boxed_info` by setting up a fake file, which is mostly + // just function pointers. Most of the functions can be empty, only + // get_info is actually implemented to return useful data. + #[test] + fn test_get_boxed_info() { + let mut file_impl = FileImpl { + revision: 0, + open: stub_open, + close: stub_close, + delete: stub_delete, + read: stub_read, + write: stub_write, + get_position: stub_get_position, + set_position: stub_set_position, + get_info: stub_get_info, + set_info: stub_set_info, + flush: stub_flush, + }; + let file_handle = FileHandle(&mut file_impl); + + let mut file = unsafe { RegularFile::new(file_handle) }; + let info = file.get_boxed_info::().unwrap(); + assert_eq!(info.file_size(), 123); + assert_eq!(info.file_name(), CString16::try_from("test_file").unwrap()); + } + + extern "efiapi" fn stub_get_info( + _this: &mut FileImpl, + information_type: &Guid, + buffer_size: &mut usize, + buffer: *mut u8, + ) -> Status { + assert_eq!(*information_type, FileInfo::GUID); + + // Use a temporary buffer to get some file info, then copy that + // data to the output buffer. + let mut tmp = vec![0; 128]; + let file_size = 123; + let physical_size = 456; + let time = Time::invalid(); + let info = FileInfo::new( + &mut tmp, + file_size, + physical_size, + time, + time, + time, + FileAttribute::empty(), + &CString16::try_from("test_file").unwrap(), + ) + .unwrap(); + let required_size = mem::size_of_val(info); + if *buffer_size < required_size { + *buffer_size = required_size; + Status::BUFFER_TOO_SMALL + } else { + unsafe { + ptr::copy_nonoverlapping((info as *const FileInfo).cast(), buffer, required_size); + } + *buffer_size = required_size; + Status::SUCCESS + } + } + + extern "efiapi" fn stub_open( + _this: &mut FileImpl, + _new_handle: &mut *mut FileImpl, + _filename: *const Char16, + _open_mode: FileMode, + _attributes: FileAttribute, + ) -> Status { + Status::UNSUPPORTED + } + + extern "efiapi" fn stub_close(_this: &mut FileImpl) -> Status { + Status::SUCCESS + } + + extern "efiapi" fn stub_delete(_this: &mut FileImpl) -> Status { + Status::UNSUPPORTED + } + + extern "efiapi" fn stub_read( + _this: &mut FileImpl, + _buffer_size: &mut usize, + _buffer: *mut u8, + ) -> Status { + Status::UNSUPPORTED + } + + extern "efiapi" fn stub_write( + _this: &mut FileImpl, + _buffer_size: &mut usize, + _buffer: *const u8, + ) -> Status { + Status::UNSUPPORTED + } + + extern "efiapi" fn stub_get_position(_this: &mut FileImpl, _position: &mut u64) -> Status { + Status::UNSUPPORTED + } + + extern "efiapi" fn stub_set_position(_this: &mut FileImpl, _position: u64) -> Status { + Status::UNSUPPORTED + } + + extern "efiapi" fn stub_set_info( + _this: &mut FileImpl, + _information_type: &Guid, + _buffer_size: usize, + _buffer: *const c_void, + ) -> Status { + Status::UNSUPPORTED + } + + extern "efiapi" fn stub_flush(_this: &mut FileImpl) -> Status { + Status::UNSUPPORTED + } +} diff --git a/src/proto/media/file/regular.rs b/src/proto/media/file/regular.rs new file mode 100644 index 000000000..819612ebf --- /dev/null +++ b/src/proto/media/file/regular.rs @@ -0,0 +1,115 @@ +use super::{File, FileHandle, FileInternal}; +use crate::{Result, Status}; + +/// A `FileHandle` that is also a regular (data) file. +/// +/// Use `FileHandle::into_type` or `RegularFile::new` to create a `RegularFile`. +/// In addition to supporting the normal `File` operations, `RegularFile` +/// supports direct reading and writing. +#[repr(transparent)] +pub struct RegularFile(FileHandle); + +impl RegularFile { + /// A special position used to seek to the end of a file with `set_position()`. + pub const END_OF_FILE: u64 = core::u64::MAX; + + /// Coverts a `FileHandle` into a `RegularFile` without checking the file kind. + /// # Safety + /// This function should only be called on handles which ARE NOT directories, + /// doing otherwise is unsafe. + pub unsafe fn new(handle: FileHandle) -> Self { + Self(handle) + } + + /// Read data from file + /// + /// Try to read as much as possible into `buffer`. Returns the number of bytes that were + /// actually read. + /// + /// # Arguments + /// * `buffer` The target buffer of the read operation + /// + /// # Errors + /// * `uefi::Status::NO_MEDIA` The device has no media + /// * `uefi::Status::DEVICE_ERROR` The device reported an error, the file was deleted, + /// or the end of the file was reached before the `read()`. + /// * `uefi::Status::VOLUME_CORRUPTED` The filesystem structures are corrupted + /// * `uefi::Status::BUFFER_TOO_SMALL` The buffer is too small to hold a directory entry, + /// and the required buffer size is provided as output. + pub fn read(&mut self, buffer: &mut [u8]) -> Result> { + let mut buffer_size = buffer.len(); + unsafe { (self.imp().read)(self.imp(), &mut buffer_size, buffer.as_mut_ptr()) }.into_with( + || buffer_size, + |s| { + if s == Status::BUFFER_TOO_SMALL { + Some(buffer_size) + } else { + None + } + }, + ) + } + + /// Write data to file + /// + /// Write `buffer` to file, increment the file pointer. + /// + /// If an error occurs, returns the number of bytes that were actually written. If no error + /// occured, the entire buffer is guaranteed to have been written successfully. + /// + /// # Arguments + /// * `buffer` Buffer to write to file + /// + /// # Errors + /// * `uefi::Status::NO_MEDIA` The device has no media + /// * `uefi::Status::DEVICE_ERROR` The device reported an error or the file was deleted. + /// * `uefi::Status::VOLUME_CORRUPTED` The filesystem structures are corrupted + /// * `uefi::Status::WRITE_PROTECTED` Attempt to write to readonly file + /// * `uefi::Status::ACCESS_DENIED` The file was opened read only. + /// * `uefi::Status::VOLUME_FULL` The volume is full + pub fn write(&mut self, buffer: &[u8]) -> Result<(), usize> { + let mut buffer_size = buffer.len(); + unsafe { (self.imp().write)(self.imp(), &mut buffer_size, buffer.as_ptr()) } + .into_with_err(|_| buffer_size) + } + + /// Get the file's current position + /// + /// # Errors + /// * `uefi::Status::DEVICE_ERROR` An attempt was made to get the position of a deleted file + pub fn get_position(&mut self) -> Result { + let mut pos = 0u64; + (self.imp().get_position)(self.imp(), &mut pos).into_with_val(|| pos) + } + + /// Sets the file's current position + /// + /// Set the position of this file handle to the absolute position specified by `position`. + /// + /// Seeking past the end of the file is allowed, it will trigger file growth on the next write. + /// Using a position of RegularFile::END_OF_FILE will seek to the end of the file. + /// + /// # Arguments + /// * `position` The new absolution position of the file handle + /// + /// # Errors + /// * `uefi::Status::DEVICE_ERROR` An attempt was made to set the position of a deleted file + pub fn set_position(&mut self, position: u64) -> Result { + (self.imp().set_position)(self.imp(), position).into() + } +} + +impl File for RegularFile { + #[inline] + fn handle(&mut self) -> &mut FileHandle { + &mut self.0 + } + + fn is_regular_file(&self) -> Result { + Ok(true) + } + + fn is_directory(&self) -> Result { + Ok(false) + } +} diff --git a/src/proto/media/fs.rs b/src/proto/media/fs.rs new file mode 100644 index 000000000..32df63da3 --- /dev/null +++ b/src/proto/media/fs.rs @@ -0,0 +1,47 @@ +//! File system support protocols. + +use super::file::{Directory, FileHandle, FileImpl}; +use crate::proto::Protocol; +use crate::{unsafe_guid, Result, Status}; +use core::ptr; + +/// Allows access to a FAT-12/16/32 file system. +/// +/// This interface is implemented by some storage devices +/// to allow file access to the contained file systems. +/// +/// # Accessing `SimpleFileSystem` protocol +/// +/// Use [`BootServices::get_image_file_system`] to retrieve the `SimpleFileSystem` +/// protocol associated with a given image handle. +/// +/// See the [`BootServices`] documentation for more details of how to open a protocol. +/// +/// [`BootServices::get_image_file_system`]: crate::table::boot::BootServices::get_image_file_system +/// [`BootServices`]: crate::table::boot::BootServices#accessing-protocols +#[repr(C)] +#[unsafe_guid("964e5b22-6459-11d2-8e39-00a0c969723b")] +#[derive(Protocol)] +pub struct SimpleFileSystem { + revision: u64, + open_volume: + extern "efiapi" fn(this: &mut SimpleFileSystem, root: &mut *mut FileImpl) -> Status, +} + +impl SimpleFileSystem { + /// Open the root directory on a volume. + /// + /// # Errors + /// * `uefi::Status::UNSUPPORTED` - The volume does not support the requested filesystem type + /// * `uefi::Status::NO_MEDIA` - The device has no media + /// * `uefi::Status::DEVICE_ERROR` - The device reported an error + /// * `uefi::Status::VOLUME_CORRUPTED` - The file system structures are corrupted + /// * `uefi::Status::ACCESS_DENIED` - The service denied access to the file + /// * `uefi::Status::OUT_OF_RESOURCES` - The volume was not opened + /// * `uefi::Status::MEDIA_CHANGED` - The device has a different medium in it + pub fn open_volume(&mut self) -> Result { + let mut ptr = ptr::null_mut(); + (self.open_volume)(self, &mut ptr) + .into_with_val(|| unsafe { Directory::new(FileHandle::new(ptr)) }) + } +} diff --git a/src/proto/media/mod.rs b/src/proto/media/mod.rs new file mode 100644 index 000000000..6750875a6 --- /dev/null +++ b/src/proto/media/mod.rs @@ -0,0 +1,12 @@ +//! Media access protocols. +//! +//! These protocols can be used to enumerate and access various media devices. +//! They provide both **high-level abstractions** such as **files and partitions**, +//! and **low-level access** such as an **block I/O** or **raw ATA** access protocol. + +pub mod file; + +pub mod block; +pub mod disk; +pub mod fs; +pub mod partition; diff --git a/src/proto/media/partition.rs b/src/proto/media/partition.rs new file mode 100644 index 000000000..9c88ea0c4 --- /dev/null +++ b/src/proto/media/partition.rs @@ -0,0 +1,251 @@ +//! Partition information protocol. + +use crate::proto::Protocol; +use crate::{unsafe_guid, Char16, Guid}; +use bitflags::bitflags; + +newtype_enum! { + /// MBR OS type. + /// + /// Only two values are defined in the UEFI specification, other + /// values are used by legacy operating systems. + pub enum MbrOsType: u8 => { + /// A fake partition covering the entire disk. + GPT_PROTECTIVE = 0xee, + + /// UEFI system partition. + UEFI_SYSTEM_PARTITION = 0xef, + } +} + +/// Legacy MBR Partition Record. +#[repr(C)] +#[repr(packed)] +#[derive(Clone, Copy, Debug)] +pub struct MbrPartitionRecord { + /// If 0x80, this is the bootable legacy partition. + pub boot_indicator: u8, + + /// Start of the partition in CHS address format. + pub starting_chs: [u8; 3], + + /// Type of partition. + pub os_type: MbrOsType, + + /// End of the partition in CHS address format. + pub ending_chs: [u8; 3], + + /// Starting LBA of the partition on the disk. + pub starting_lba: u32, + + /// Size of the partition in LBA units of logical blocks. + pub size_in_lba: u32, +} + +impl MbrPartitionRecord { + /// True if the partition is a bootable legacy partition. + pub fn is_bootable(&self) -> bool { + self.boot_indicator == 0x80 + } +} + +newtype_enum! { + /// GUID that defines the type of partition. Only three values are + /// defined in the UEFI specification, OS vendors define their own + /// Partition Type GUIDs. + pub enum GptPartitionType: Guid => { + /// Indicates a partition entry is unused. + UNUSED_ENTRY = Guid::from_values( + 0x00000000, + 0x0000, + 0x0000, + 0x0000, + 0x000000000000, + ), + + /// EFI System Partition. + EFI_SYSTEM_PARTITION = Guid::from_values( + 0xc12a7328, + 0xf81f, + 0x11d2, + 0xba4b, + 0x00a0c93ec93b, + ), + + /// Partition containing a legacy MBR. + LEGACY_MBR = Guid::from_values( + 0x024dee41, + 0x33e7, + 0x11d3, + 0x9d69, + 0x0008c781f39f, + ), + } +} + +bitflags! { + /// Attributes describing a GPT partition. + /// + /// * Bit 0: [`REQUIRED_PARTITION`][Self::REQUIRED_PARTITION] + /// * Bit 1: [`NO_BLOCK_IO_PROTOCOL`][Self::NO_BLOCK_IO_PROTOCOL] + /// * Bit 2: [`LEGACY_BIOS_BOOTABLE`][Self::LEGACY_BIOS_BOOTABLE] + /// * Bits `3..=47`: reserved for future use and must be zero. + /// * Bits `48..=63`: See + /// [`type_specific_bits`][Self::type_specific_bits] and + /// [`RESERVED_FOR_PARTITION_TYPE`][Self::RESERVED_FOR_PARTITION_TYPE]. + #[derive(Default)] + #[repr(transparent)] + pub struct GptPartitionAttributes: u64 { + /// Partition is required for the platform to function. + const REQUIRED_PARTITION = 1 << 0; + + /// No [`BlockIO`] protocol will be created for this partition. + /// + /// [`BlockIO`]: uefi::proto::media::block::BlockIO + const NO_BLOCK_IO_PROTOCOL = 1 << 1; + + /// Indicates that special software on a legacy BIOS system may + /// treat this partition as bootable. UEFI boot managers must + /// ignore the partition. + const LEGACY_BIOS_BOOTABLE = 1 << 2; + + /// Mask for bits `48..=63`. The meaning of these bits depends + /// on the partition type. + const RESERVED_FOR_PARTITION_TYPE = 0xffff_0000_0000_0000; + } +} + +impl GptPartitionAttributes { + /// Get bits `48..=63` as a [`u16`]. The meaning of these bits depends + /// on the partition's type (see [`GptPartitionEntry::partition_type_guid`]). + pub fn type_specific_bits(&self) -> u16 { + (self.bits >> 48) as u16 + } +} + +/// GPT/EFI Partition Entry. +#[repr(C)] +#[repr(packed)] +#[derive(Clone, Copy, Debug)] +pub struct GptPartitionEntry { + /// GUID that defines the type of this Partition. A value of zero + /// indicates that this partition entry is unused. + pub partition_type_guid: GptPartitionType, + + /// GUID that is unique for every partition entry. + pub unique_partition_guid: Guid, + + /// Starting LBA of the partition. + pub starting_lba: u64, + + /// Ending LBA of the partition. + pub ending_lba: u64, + + /// All attribute bits of the partition. + pub attributes: GptPartitionAttributes, + + /// Null-terminated string containing a human-readable name of the + /// partition. + pub partition_name: [Char16; 36], +} + +impl GptPartitionEntry { + /// Get the number of blocks in the partition. Returns `None` if the + /// end block is before the start block, or if the number doesn't + /// fit in a `u64`. + pub fn num_blocks(&self) -> Option { + self.ending_lba + .checked_sub(self.starting_lba)? + .checked_add(1) + } +} + +newtype_enum! { + /// Partition type. + pub enum PartitionType: u32 => { + /// Partition is not MBR or GPT. + OTHER = 0x00, + /// MBR partition. + MBR = 0x01, + /// GPT partition. + GPT = 0x02, + } +} + +#[repr(C)] +#[derive(Clone, Copy)] +union PartitionInfoRecord { + mbr: MbrPartitionRecord, + gpt: GptPartitionEntry, +} + +newtype_enum! { + /// Partition info protocol revision. + pub enum PartitionInfoRevision: u32 => { + /// Revision of EFI_PARTITION_INFO_PROTOCOL_REVISION. + PROTOCOL_REVISION = 0x0001000, + } +} + +/// Protocol for accessing partition information. +#[repr(C)] +#[repr(packed)] +#[unsafe_guid("8cf2f62c-bc9b-4821-808d-ec9ec421a1a0")] +#[derive(Clone, Copy, Protocol)] +pub struct PartitionInfo { + /// Revision of the partition info protocol. + pub revision: PartitionInfoRevision, + + /// Type of partition. + pub partition_type: PartitionType, + + system: u8, + reserved: [u8; 7], + record: PartitionInfoRecord, +} + +impl PartitionInfo { + /// True if the partition is an EFI system partition. + pub fn is_system(&self) -> bool { + self.system == 1 + } + + /// Get the MBR partition record. Returns None if the partition + /// type is not MBR. + pub fn mbr_partition_record(&self) -> Option<&MbrPartitionRecord> { + if { self.revision } != PartitionInfoRevision::PROTOCOL_REVISION { + return None; + } + + if { self.partition_type } == PartitionType::MBR { + Some(unsafe { &self.record.mbr }) + } else { + None + } + } + + /// Get the GPT partition entry. Returns None if the partition + /// type is not GPT. + pub fn gpt_partition_entry(&self) -> Option<&GptPartitionEntry> { + if { self.revision } != PartitionInfoRevision::PROTOCOL_REVISION { + return None; + } + + if { self.partition_type } == PartitionType::GPT { + Some(unsafe { &self.record.gpt }) + } else { + None + } + } +} + +#[cfg(test)] +mod tests { + use super::*; + + #[test] + fn test_partition_attributes() { + let attr = GptPartitionAttributes::from_bits(0xabcd_0000_0000_0007).unwrap(); + assert_eq!(attr.type_specific_bits(), 0xabcd); + } +} diff --git a/src/proto/mod.rs b/src/proto/mod.rs new file mode 100644 index 000000000..895647c37 --- /dev/null +++ b/src/proto/mod.rs @@ -0,0 +1,76 @@ +//! Protocol definitions. +//! +//! Protocols are sets of related functionality identified by a unique +//! ID. They can be implemented by a UEFI driver or occasionally by a +//! UEFI application. +//! +//! See the [`BootServices`] documentation for details of how to open a +//! protocol. +//! +//! [`BootServices`]: crate::table::boot::BootServices#accessing-protocols + +use crate::Identify; +use core::ffi::c_void; + +/// Common trait implemented by all standard UEFI protocols +/// +/// According to the UEFI's specification, protocols are `!Send` (they expect to +/// be run on the bootstrap processor) and `!Sync` (they are not thread-safe). +/// You can derive the `Protocol` trait, add these bounds and specify the +/// protocol's GUID using the following syntax: +/// +/// ``` +/// #![feature(negative_impls)] +/// use uefi::{proto::Protocol, unsafe_guid}; +/// #[unsafe_guid("12345678-9abc-def0-1234-56789abcdef0")] +/// #[derive(Protocol)] +/// struct DummyProtocol {} +/// ``` +pub trait Protocol: Identify {} + +/// Trait for creating a protocol pointer from a [`c_void`] pointer. +/// +/// There is a blanket implementation for all [`Sized`] protocols that +/// simply casts the pointer to the appropriate type. Protocols that +/// are not sized must provide a custom implementation. +pub trait ProtocolPointer: Protocol { + /// Create a const pointer to a [`Protocol`] from a [`c_void`] pointer. + /// + /// # Safety + /// + /// The input pointer must point to valid data. + unsafe fn ptr_from_ffi(ptr: *const c_void) -> *const Self; + + /// Create a mutable pointer to a [`Protocol`] from a [`c_void`] pointer. + /// + /// # Safety + /// + /// The input pointer must point to valid data. + unsafe fn mut_ptr_from_ffi(ptr: *mut c_void) -> *mut Self; +} + +impl

ProtocolPointer for P +where + P: Protocol, +{ + unsafe fn ptr_from_ffi(ptr: *const c_void) -> *const Self { + ptr.cast::() + } + + unsafe fn mut_ptr_from_ffi(ptr: *mut c_void) -> *mut Self { + ptr.cast::() + } +} + +pub use uefi_macros::Protocol; + +pub mod console; +pub mod debug; +pub mod device_path; +pub mod loaded_image; +pub mod media; +pub mod network; +pub mod pi; +pub mod rng; +pub mod security; +pub mod shim; diff --git a/src/proto/network/mod.rs b/src/proto/network/mod.rs new file mode 100644 index 000000000..66c3a4220 --- /dev/null +++ b/src/proto/network/mod.rs @@ -0,0 +1,36 @@ +//! Network access protocols. +//! +//! These protocols can be used to interact with network resources. + +pub mod pxe; + +/// Represents an IPv4/v6 address. +/// +/// Corresponds to the `EFI_IP_ADDRESS` type in the C API. +#[derive(Clone, Copy, PartialEq, Eq, Hash)] +#[repr(C, align(4))] +pub struct IpAddress(pub [u8; 16]); + +impl IpAddress { + /// Construct a new IPv4 address. + pub const fn new_v4(ip_addr: [u8; 4]) -> Self { + let mut buffer = [0; 16]; + buffer[0] = ip_addr[0]; + buffer[1] = ip_addr[1]; + buffer[2] = ip_addr[2]; + buffer[3] = ip_addr[3]; + Self(buffer) + } + + /// Construct a new IPv6 address. + pub const fn new_v6(ip_addr: [u8; 16]) -> Self { + Self(ip_addr) + } +} + +/// Represents a MAC (media access control) address. +/// +/// Corresponds to the `EFI_MAC_ADDRESS` type in the C API. +#[derive(Clone, Copy, PartialEq, Eq, Hash)] +#[repr(C)] +pub struct MacAddress(pub [u8; 32]); diff --git a/src/proto/network/pxe.rs b/src/proto/network/pxe.rs new file mode 100644 index 000000000..c8b850d3a --- /dev/null +++ b/src/proto/network/pxe.rs @@ -0,0 +1,1253 @@ +//! PXE Base Code protocol. + +use core::{ + ffi::c_void, + iter::from_fn, + ptr::{null, null_mut}, +}; + +use bitflags::bitflags; +use uefi_macros::{unsafe_guid, Protocol}; + +use crate::{CStr8, Char8, Result, Status}; + +use super::{IpAddress, MacAddress}; + +/// PXE Base Code protocol +#[repr(C)] +#[unsafe_guid("03c4e603-ac28-11d3-9a2d-0090273fc14d")] +#[derive(Protocol)] +#[allow(clippy::type_complexity)] +pub struct BaseCode { + revision: u64, + start: extern "efiapi" fn(this: &Self, use_ipv6: bool) -> Status, + stop: extern "efiapi" fn(this: &Self) -> Status, + dhcp: extern "efiapi" fn(this: &Self, sort_offers: bool) -> Status, + discover: extern "efiapi" fn( + this: &Self, + ty: BootstrapType, + layer: &mut u16, + use_bis: bool, + info: Option<*const DiscoverInfo<[Server; 0]>>, + ) -> Status, + mtftp: unsafe extern "efiapi" fn( + this: &Self, + operation: TftpOpcode, + buffer: *mut c_void, + overwrite: bool, + buffer_size: &mut u64, + block_size: Option<&usize>, + server_ip: &IpAddress, + filename: *const Char8, + info: Option<&MtftpInfo>, + dont_use_buffer: bool, + ) -> Status, + udp_write: unsafe extern "efiapi" fn( + this: &Self, + op_flags: UdpOpFlags, + dest_ip: &IpAddress, + dest_port: &u16, + gateway_ip: Option<&IpAddress>, + src_ip: Option<&IpAddress>, + src_port: Option<&mut u16>, + header_size: Option<&usize>, + header_ptr: *const c_void, + buffer_size: &usize, + buffer_ptr: *const c_void, + ) -> Status, + udp_read: unsafe extern "efiapi" fn( + this: &Self, + op_flags: UdpOpFlags, + dest_ip: Option<&mut IpAddress>, + dest_port: Option<&mut u16>, + src_ip: Option<&mut IpAddress>, + src_port: Option<&mut u16>, + header_size: Option<&usize>, + header_ptr: *mut c_void, + buffer_size: &mut usize, + buffer_ptr: *mut c_void, + ) -> Status, + set_ip_filter: extern "efiapi" fn(this: &Self, new_filter: &IpFilter) -> Status, + arp: extern "efiapi" fn( + this: &Self, + ip_addr: &IpAddress, + mac_addr: Option<&mut MacAddress>, + ) -> Status, + set_parameters: extern "efiapi" fn( + this: &Self, + new_auto_arp: Option<&bool>, + new_send_guid: Option<&bool>, + new_ttl: Option<&u8>, + new_tos: Option<&u8>, + new_make_callback: Option<&bool>, + ) -> Status, + set_station_ip: extern "efiapi" fn( + this: &Self, + new_station_ip: Option<&IpAddress>, + new_subnet_mask: Option<&IpAddress>, + ) -> Status, + set_packets: extern "efiapi" fn( + this: &Self, + new_dhcp_discover_valid: Option<&bool>, + new_dhcp_ack_received: Option<&bool>, + new_proxy_offer_received: Option<&bool>, + new_pxe_discover_valid: Option<&bool>, + new_pxe_reply_received: Option<&bool>, + new_pxe_bis_reply_received: Option<&bool>, + new_dhcp_discover: Option<&Packet>, + new_dhcp_ack: Option<&Packet>, + new_proxy_offer: Option<&Packet>, + new_pxe_discover: Option<&Packet>, + new_pxe_reply: Option<&Packet>, + new_pxe_bis_reply: Option<&Packet>, + ) -> Status, + mode: *const Mode, +} + +impl BaseCode { + /// Enables the use of the PXE Base Code Protocol functions. + pub fn start(&mut self, use_ipv6: bool) -> Result { + (self.start)(self, use_ipv6).into() + } + + /// Disables the use of the PXE Base Code Protocol functions. + pub fn stop(&mut self) -> Result { + (self.stop)(self).into() + } + + /// Attempts to complete a DHCPv4 D.O.R.A. (discover / offer / request / + /// acknowledge) or DHCPv6 S.A.R.R (solicit / advertise / request / reply) sequence. + pub fn dhcp(&mut self, sort_offers: bool) -> Result { + (self.dhcp)(self, sort_offers).into() + } + + /// Attempts to complete the PXE Boot Server and/or boot image discovery + /// sequence. + pub fn discover( + &mut self, + ty: BootstrapType, + layer: &mut u16, + use_bis: bool, + info: Option<&DiscoverInfo<[Server]>>, + ) -> Result { + (self.discover)( + self, + ty, + layer, + use_bis, + info.map(|info| (info as *const DiscoverInfo<[Server]>).cast()), + ) + .into() + } + + /// Returns the size of a file located on a TFTP server. + pub fn tftp_get_file_size(&mut self, server_ip: &IpAddress, filename: &CStr8) -> Result { + let mut buffer_size = 0; + + let status = unsafe { + (self.mtftp)( + self, + TftpOpcode::TftpGetFileSize, + null_mut(), + false, + &mut buffer_size, + None, + server_ip, + filename.as_ptr(), + None, + false, + ) + }; + Result::from(status)?; + + Ok(buffer_size) + } + + /// Reads a file located on a TFTP server. + pub fn tftp_read_file( + &mut self, + server_ip: &IpAddress, + filename: &CStr8, + buffer: Option<&mut [u8]>, + ) -> Result { + let (buffer_ptr, mut buffer_size, dont_use_buffer) = if let Some(buffer) = buffer { + let buffer_size = u64::try_from(buffer.len()).unwrap(); + ((&mut buffer[0] as *mut u8).cast(), buffer_size, false) + } else { + (null_mut(), 0, true) + }; + + let status = unsafe { + (self.mtftp)( + self, + TftpOpcode::TftpReadFile, + buffer_ptr, + false, + &mut buffer_size, + None, + server_ip, + filename.as_ptr(), + None, + dont_use_buffer, + ) + }; + Result::from(status)?; + + Ok(buffer_size) + } + + /// Writes to a file located on a TFTP server. + pub fn tftp_write_file( + &mut self, + server_ip: &IpAddress, + filename: &CStr8, + overwrite: bool, + buffer: &[u8], + ) -> Result { + let buffer_ptr = (&buffer[0] as *const u8 as *mut u8).cast(); + let mut buffer_size = u64::try_from(buffer.len()).expect("buffer length should fit in u64"); + + unsafe { + (self.mtftp)( + self, + TftpOpcode::TftpWriteFile, + buffer_ptr, + overwrite, + &mut buffer_size, + None, + server_ip, + filename.as_ptr(), + None, + false, + ) + } + .into() + } + + /// Reads a directory listing of a directory on a TFTP server. + pub fn tftp_read_dir<'a>( + &self, + server_ip: &IpAddress, + directory_name: &CStr8, + buffer: &'a mut [u8], + ) -> Result, ReadDirParseError>> + 'a> + { + let buffer_ptr = (&buffer[0] as *const u8 as *mut u8).cast(); + let mut buffer_size = u64::try_from(buffer.len()).expect("buffer length should fit in u64"); + + let status = unsafe { + (self.mtftp)( + self, + TftpOpcode::TftpReadDirectory, + buffer_ptr, + false, + &mut buffer_size, + None, + server_ip, + directory_name.as_ptr(), + None, + false, + ) + }; + Result::from(status)?; + + let buffer_size = usize::try_from(buffer_size).expect("buffer length should fit in usize"); + let buffer = &buffer[..buffer_size]; + + let mut iterator = buffer.split_inclusive(|b| *b == 0); + let mut parse_next = move || { + let filename = iterator.next().ok_or(ReadDirParseError)?; + if filename == [0] { + // This is the final entry. + return Ok(None); + } + let filename = CStr8::from_bytes_with_nul(filename).unwrap(); + + let information_string = iterator.next().ok_or(ReadDirParseError)?; + let (_null_terminator, information_string) = information_string.split_last().unwrap(); + let information_string = + core::str::from_utf8(information_string).map_err(|_| ReadDirParseError)?; + + let (size, rest) = information_string + .split_once(' ') + .ok_or(ReadDirParseError)?; + let (year, rest) = rest.split_once('-').ok_or(ReadDirParseError)?; + let (month, rest) = rest.split_once('-').ok_or(ReadDirParseError)?; + let (day, rest) = rest.split_once(' ').ok_or(ReadDirParseError)?; + let (hour, rest) = rest.split_once(':').ok_or(ReadDirParseError)?; + let (minute, second) = rest.split_once(':').ok_or(ReadDirParseError)?; + + let size = size.parse().map_err(|_| ReadDirParseError)?; + let year = year.parse().map_err(|_| ReadDirParseError)?; + let month = month.parse().map_err(|_| ReadDirParseError)?; + let day = day.parse().map_err(|_| ReadDirParseError)?; + let hour = hour.parse().map_err(|_| ReadDirParseError)?; + let minute = minute.parse().map_err(|_| ReadDirParseError)?; + let second = second.parse().map_err(|_| ReadDirParseError)?; + + Ok(Some(TftpFileInfo { + filename, + size, + year, + month, + day, + hour, + minute, + second, + })) + }; + Ok(from_fn(move || parse_next().transpose()).fuse()) + } + + /// Returns the size of a file located on a MTFTP server. + pub fn mtftp_get_file_size( + &mut self, + server_ip: &IpAddress, + filename: &CStr8, + info: &MtftpInfo, + ) -> Result { + let mut buffer_size = 0; + + let status = unsafe { + (self.mtftp)( + self, + TftpOpcode::MtftpGetFileSize, + null_mut(), + false, + &mut buffer_size, + None, + server_ip, + filename.as_ptr(), + Some(info), + false, + ) + }; + Result::from(status)?; + + Ok(buffer_size) + } + + /// Reads a file located on a MTFTP server. + pub fn mtftp_read_file( + &mut self, + server_ip: &IpAddress, + filename: &CStr8, + buffer: Option<&mut [u8]>, + info: &MtftpInfo, + ) -> Result { + let (buffer_ptr, mut buffer_size, dont_use_buffer) = if let Some(buffer) = buffer { + let buffer_size = u64::try_from(buffer.len()).unwrap(); + ((&mut buffer[0] as *mut u8).cast(), buffer_size, false) + } else { + (null_mut(), 0, true) + }; + + let status = unsafe { + (self.mtftp)( + self, + TftpOpcode::MtftpReadFile, + buffer_ptr, + false, + &mut buffer_size, + None, + server_ip, + filename.as_ptr(), + Some(info), + dont_use_buffer, + ) + }; + Result::from(status)?; + + Ok(buffer_size) + } + + /// Reads a directory listing of a directory on a MTFTP server. + pub fn mtftp_read_dir<'a>( + &self, + server_ip: &IpAddress, + buffer: &'a mut [u8], + info: &MtftpInfo, + ) -> Result, ReadDirParseError>> + 'a> + { + let buffer_ptr = (&buffer[0] as *const u8 as *mut u8).cast(); + let mut buffer_size = u64::try_from(buffer.len()).expect("buffer length should fit in u64"); + + let status = unsafe { + (self.mtftp)( + self, + TftpOpcode::MtftpReadDirectory, + buffer_ptr, + false, + &mut buffer_size, + None, + server_ip, + null_mut(), + Some(info), + false, + ) + }; + Result::from(status)?; + + let buffer_size = usize::try_from(buffer_size).expect("buffer length should fit in usize"); + let buffer = &buffer[..buffer_size]; + + let mut iterator = buffer.split_inclusive(|b| *b == 0); + let mut parse_next = move || { + let filename = iterator.next().ok_or(ReadDirParseError)?; + if filename == [0] { + // This is the final entry. + return Ok(None); + } + let filename = CStr8::from_bytes_with_nul(filename).unwrap(); + + let multicast_ip = iterator.next().ok_or(ReadDirParseError)?; + let (_null_terminator, multicast_ip) = multicast_ip.split_last().unwrap(); + let multicast_ip = core::str::from_utf8(multicast_ip).map_err(|_| ReadDirParseError)?; + let mut octets = multicast_ip.split('.'); + let mut buffer = [0; 4]; + for b in buffer.iter_mut() { + let octet = octets.next().ok_or(ReadDirParseError)?; + let octet = octet.parse().map_err(|_| ReadDirParseError)?; + *b = octet; + } + if octets.next().is_some() { + // The IP should have exact 4 octets, not more. + return Err(ReadDirParseError); + } + let ip_address = IpAddress::new_v4(buffer); + + let information_string = iterator.next().ok_or(ReadDirParseError)?; + let (_null_terminator, information_string) = information_string.split_last().unwrap(); + let information_string = + core::str::from_utf8(information_string).map_err(|_| ReadDirParseError)?; + + let (size, rest) = information_string + .split_once(' ') + .ok_or(ReadDirParseError)?; + let (year, rest) = rest.split_once('-').ok_or(ReadDirParseError)?; + let (month, rest) = rest.split_once('-').ok_or(ReadDirParseError)?; + let (day, rest) = rest.split_once(' ').ok_or(ReadDirParseError)?; + let (hour, rest) = rest.split_once(':').ok_or(ReadDirParseError)?; + let (minute, second) = rest.split_once(':').ok_or(ReadDirParseError)?; + + let size = size.parse().map_err(|_| ReadDirParseError)?; + let year = year.parse().map_err(|_| ReadDirParseError)?; + let month = month.parse().map_err(|_| ReadDirParseError)?; + let day = day.parse().map_err(|_| ReadDirParseError)?; + let hour = hour.parse().map_err(|_| ReadDirParseError)?; + let minute = minute.parse().map_err(|_| ReadDirParseError)?; + let second = second.parse().map_err(|_| ReadDirParseError)?; + + Ok(Some(MtftpFileInfo { + filename, + ip_address, + size, + year, + month, + day, + hour, + minute, + second, + })) + }; + Ok(from_fn(move || parse_next().transpose()).fuse()) + } + + /// Writes a UDP packet to the network interface. + #[allow(clippy::too_many_arguments)] + pub fn udp_write( + &mut self, + op_flags: UdpOpFlags, + dest_ip: &IpAddress, + dest_port: u16, + gateway_ip: Option<&IpAddress>, + src_ip: Option<&IpAddress>, + src_port: Option<&mut u16>, + header: Option<&[u8]>, + buffer: &[u8], + ) -> Result { + let header_size_tmp; + let (header_size, header_ptr) = if let Some(header) = header { + header_size_tmp = header.len(); + (Some(&header_size_tmp), (&header[0] as *const u8).cast()) + } else { + (None, null()) + }; + + unsafe { + (self.udp_write)( + self, + op_flags, + dest_ip, + &dest_port, + gateway_ip, + src_ip, + src_port, + header_size, + header_ptr, + &buffer.len(), + (&buffer[0] as *const u8).cast(), + ) + } + .into() + } + + /// Reads a UDP packet from the network interface. + #[allow(clippy::too_many_arguments)] + pub fn udp_read( + &mut self, + op_flags: UdpOpFlags, + dest_ip: Option<&mut IpAddress>, + dest_port: Option<&mut u16>, + src_ip: Option<&mut IpAddress>, + src_port: Option<&mut u16>, + header: Option<&mut [u8]>, + buffer: &mut [u8], + ) -> Result { + let header_size_tmp; + let (header_size, header_ptr) = if let Some(header) = header { + header_size_tmp = header.len(); + (Some(&header_size_tmp), (&mut header[0] as *mut u8).cast()) + } else { + (None, null_mut()) + }; + + let mut buffer_size = buffer.len(); + + let status = unsafe { + (self.udp_read)( + self, + op_flags, + dest_ip, + dest_port, + src_ip, + src_port, + header_size, + header_ptr, + &mut buffer_size, + (&mut buffer[0] as *mut u8).cast(), + ) + }; + Result::from(status)?; + + Ok(buffer_size) + } + + /// Updates the IP receive filters of a network device and enables software + /// filtering. + pub fn set_ip_filter(&mut self, new_filter: &IpFilter) -> Result { + (self.set_ip_filter)(self, new_filter).into() + } + + /// Uses the ARP protocol to resolve a MAC address. + pub fn arp(&mut self, ip_addr: &IpAddress, mac_addr: Option<&mut MacAddress>) -> Result { + (self.arp)(self, ip_addr, mac_addr).into() + } + + /// Updates the parameters that affect the operation of the PXE Base Code + /// Protocol. + pub fn set_parameters( + &mut self, + new_auto_arp: Option, + new_send_guid: Option, + new_ttl: Option, + new_tos: Option, + new_make_callback: Option, + ) -> Result { + (self.set_parameters)( + self, + new_auto_arp.as_ref(), + new_send_guid.as_ref(), + new_ttl.as_ref(), + new_tos.as_ref(), + new_make_callback.as_ref(), + ) + .into() + } + + /// Updates the station IP address and/or subnet mask values of a network + /// device. + pub fn set_station_ip( + &mut self, + new_station_ip: Option<&IpAddress>, + new_subnet_mask: Option<&IpAddress>, + ) -> Result { + (self.set_station_ip)(self, new_station_ip, new_subnet_mask).into() + } + + /// Updates the contents of the cached DHCP and Discover packets. + #[allow(clippy::too_many_arguments)] + pub fn set_packets( + &mut self, + new_dhcp_discover_valid: Option, + new_dhcp_ack_received: Option, + new_proxy_offer_received: Option, + new_pxe_discover_valid: Option, + new_pxe_reply_received: Option, + new_pxe_bis_reply_received: Option, + new_dhcp_discover: Option<&Packet>, + new_dhcp_ack: Option<&Packet>, + new_proxy_offer: Option<&Packet>, + new_pxe_discover: Option<&Packet>, + new_pxe_reply: Option<&Packet>, + new_pxe_bis_reply: Option<&Packet>, + ) -> Result { + (self.set_packets)( + self, + new_dhcp_discover_valid.as_ref(), + new_dhcp_ack_received.as_ref(), + new_proxy_offer_received.as_ref(), + new_pxe_discover_valid.as_ref(), + new_pxe_reply_received.as_ref(), + new_pxe_bis_reply_received.as_ref(), + new_dhcp_discover, + new_dhcp_ack, + new_proxy_offer, + new_pxe_discover, + new_pxe_reply, + new_pxe_bis_reply, + ) + .into() + } + + /// Returns a reference to the `Mode` struct. + pub fn mode(&self) -> &Mode { + unsafe { &*self.mode } + } +} + +/// A type of bootstrap to perform in [`BaseCode::discover`]. +/// +/// Corresponds to the `EFI_PXE_BASE_CODE_BOOT_` constants in the C API. +#[derive(Clone, Copy, PartialEq, Eq, Hash)] +#[repr(u16)] +#[allow(missing_docs)] +pub enum BootstrapType { + Bootstrap = 0, + MsWinntRis = 1, + IntelLcm = 2, + DosUndi = 3, + NecEsmpro = 4, + IbmWsoD = 5, + IbmLccm = 6, + CaUnicenterTng = 7, + HpOpenview = 8, + Altiris9 = 9, + Altiris10 = 10, + Altiris11 = 11, + // NOT_USED_12 = 12, + RedhatInstall = 13, + RedhatBoot = 14, + Rembo = 15, + Beoboot = 16, + // + // Values 17 through 32767 are reserved. + // Values 32768 through 65279 are for vendor use. + // Values 65280 through 65534 are reserved. + // + PxeTest = 65535, +} + +/// This struct contains optional parameters for [`BaseCode::discover`]. +/// +/// Corresponds to the `EFI_PXE_BASE_CODE_DISCOVER_INFO` type in the C API. +#[repr(C)] +pub struct DiscoverInfo { + use_m_cast: bool, + use_b_cast: bool, + use_u_cast: bool, + must_use_list: bool, + server_m_cast_ip: IpAddress, + ip_cnt: u16, + srv_list: T, +} + +impl DiscoverInfo<[Server; N]> { + /// Create a `DiscoverInfo`. + pub const fn new( + use_m_cast: bool, + use_b_cast: bool, + use_u_cast: bool, + must_use_list: bool, + server_m_cast_ip: IpAddress, + srv_list: [Server; N], + ) -> Self { + assert!(N <= u16::MAX as usize, "too many servers"); + let ip_cnt = N as u16; + Self { + use_m_cast, + use_b_cast, + use_u_cast, + must_use_list, + server_m_cast_ip, + ip_cnt, + srv_list, + } + } +} + +impl DiscoverInfo { + /// Returns whether discovery should use multicast. + pub fn use_m_cast(&self) -> bool { + self.use_m_cast + } + + /// Returns whether discovery should use broadcast. + pub fn use_b_cast(&self) -> bool { + self.use_b_cast + } + + /// Returns whether discovery should use unicast. + pub fn use_u_cast(&self) -> bool { + self.use_u_cast + } + + /// Returns whether discovery should only accept boot servers in the server + /// list (boot server verification). + pub fn must_use_list(&self) -> bool { + self.must_use_list + } + + /// Returns the address used in multicast discovery. + pub fn server_m_cast_ip(&self) -> &IpAddress { + &self.server_m_cast_ip + } + + /// Returns the amount of Boot Server. + pub fn ip_cnt(&self) -> u16 { + self.ip_cnt + } + + /// Returns the Boot Server list used for unicast discovery or boot server + /// verification. + pub fn srv_list(&self) -> &T { + &self.srv_list + } +} + +/// An entry in the Boot Server list +/// +/// Corresponds to the `EFI_PXE_BASE_CODE_SRVLIST` type in the C API. +#[repr(C)] +pub struct Server { + /// The type of Boot Server reply + pub ty: u16, + accept_any_response: bool, + _reserved: u8, + /// The IP address of the server + ip_addr: IpAddress, +} + +impl Server { + /// Construct a `Server` for a Boot Server reply type. If `ip_addr` is not + /// `None` only Boot Server replies with matching the IP address will be + /// accepted. + pub fn new(ty: u16, ip_addr: Option) -> Self { + Self { + ty, + accept_any_response: ip_addr.is_none(), + _reserved: 0, + ip_addr: ip_addr.unwrap_or(IpAddress([0; 16])), + } + } + + /// Returns a `None` if the any response should be accepted or the IP + /// address of a Boot Server whose responses should be accepted. + pub fn ip_addr(&self) -> Option<&IpAddress> { + if self.accept_any_response { + None + } else { + Some(&self.ip_addr) + } + } +} + +/// Corresponds to the `EFI_PXE_BASE_CODE_TFTP_OPCODE` type in the C API. +#[repr(C)] +enum TftpOpcode { + TftpGetFileSize = 1, + TftpReadFile, + TftpWriteFile, + TftpReadDirectory, + MtftpGetFileSize, + MtftpReadFile, + MtftpReadDirectory, +} + +/// MTFTP connection parameters +/// +/// Corresponds to the `EFI_PXE_BASE_CODE_MTFTP_INFO` type in the C API. +#[derive(Clone, Copy)] +#[repr(C)] +pub struct MtftpInfo { + /// File multicast IP address. This is the IP address to which the server + /// will send the requested file. + pub m_cast_ip: IpAddress, + /// Client multicast listening port. This is the UDP port to which the + /// server will send the requested file. + pub c_port: u16, + /// Server multicast listening port. This is the UDP port on which the + /// server listens for multicast open requests and data acks. + pub s_port: u16, + /// The number of seconds a client should listen for an active multicast + /// session before requesting a new multicast session. + pub listen_timeout: u16, + /// The number of seconds a client should wait for a packet from the server + /// before retransmitting the previous open request or data ack packet. + pub transmit_timeout: u16, +} + +// No corresponding type in the UEFI spec, it just uses UINT16. +bitflags! { + /// Flags for UDP read and write operations. + #[repr(transparent)] + pub struct UdpOpFlags: u16 { + /// Receive a packet sent from any IP address in UDP read operations. + const ANY_SRC_IP = 0x0001; + /// Receive a packet sent from any UDP port in UDP read operations. If + /// the source port is no specified in UDP write operations, the + /// source port will be automatically selected. + const ANY_SRC_PORT = 0x0002; + /// Receive a packet sent to any IP address in UDP read operations. + const ANY_DEST_IP = 0x0004; + /// Receive a packet sent to any UDP port in UDP read operations. + const ANY_DEST_PORT = 0x0008; + /// The software filter is used in UDP read operations. + const USE_FILTER = 0x0010; + /// If required, a UDP write operation may be broken up across multiple packets. + const MAY_FRAGMENT = 0x0020; + } +} + +/// IP receive filter settings +/// +/// Corresponds to the `EFI_PXE_BASE_CODE_IP_FILTER` type in the C API. +#[repr(C)] +pub struct IpFilter { + /// A set of filters. + pub filters: IpFilters, + ip_cnt: u8, + _reserved: u16, + ip_list: [IpAddress; 8], +} + +impl IpFilter { + /// Construct a new `IpFilter`. + /// + /// # Panics + /// + /// Panics if `ip_list` contains more than 8 entries. + pub fn new(filters: IpFilters, ip_list: &[IpAddress]) -> Self { + assert!(ip_list.len() <= 8); + + let ip_cnt = ip_list.len() as u8; + let mut buffer = [IpAddress([0; 16]); 8]; + buffer[..ip_list.len()].copy_from_slice(ip_list); + + Self { + filters, + ip_cnt, + _reserved: 0, + ip_list: buffer, + } + } + + /// A list of IP addresses other than the Station Ip that should be + /// enabled. Maybe be multicast or unicast. + pub fn ip_list(&self) -> &[IpAddress] { + &self.ip_list[..usize::from(self.ip_cnt)] + } +} + +bitflags! { + /// IP receive filters. + #[repr(transparent)] + pub struct IpFilters: u8 { + /// Enable the Station IP address. + const STATION_IP = 0x01; + /// Enable IPv4 broadcast addresses. + const BROADCAST = 0x02; + /// Enable all addresses. + const PROMISCUOUS = 0x04; + /// Enable all multicast addresses. + const PROMISCUOUS_MULTICAST = 0x08; + } +} + +/// A network packet. +/// +/// Corresponds to the `EFI_PXE_BASE_CODE_PACKET` type in the C API. +#[repr(C)] +pub union Packet { + raw: [u8; 1472], + dhcpv4: DhcpV4Packet, + dhcpv6: DhcpV6Packet, +} + +impl AsRef<[u8; 1472]> for Packet { + fn as_ref(&self) -> &[u8; 1472] { + unsafe { &self.raw } + } +} + +impl AsRef for Packet { + fn as_ref(&self) -> &DhcpV4Packet { + unsafe { &self.dhcpv4 } + } +} + +impl AsRef for Packet { + fn as_ref(&self) -> &DhcpV6Packet { + unsafe { &self.dhcpv6 } + } +} + +/// A Dhcpv4 Packet. +/// +/// Corresponds to the `EFI_PXE_BASE_CODE_DHCPV4_PACKET` type in the C API. +#[repr(C)] +#[derive(Clone, Copy)] +pub struct DhcpV4Packet { + /// Packet op code / message type. + pub bootp_opcode: u8, + /// Hardware address type. + pub bootp_hw_type: u8, + /// Hardware address length. + pub bootp_hw_addr_len: u8, + /// Client sets to zero, optionally used by gateways in cross-gateway booting. + pub bootp_gate_hops: u8, + bootp_ident: u32, + bootp_seconds: u16, + bootp_flags: u16, + /// Client IP address, filled in by client in bootrequest if known. + pub bootp_ci_addr: [u8; 4], + /// 'your' (client) IP address; filled by server if client doesn't know its own address (`bootp_ci_addr` was 0). + pub bootp_yi_addr: [u8; 4], + /// Server IP address, returned in bootreply by server. + pub bootp_si_addr: [u8; 4], + /// Gateway IP address, used in optional cross-gateway booting. + pub bootp_gi_addr: [u8; 4], + /// Client hardware address, filled in by client. + pub bootp_hw_addr: [u8; 16], + /// Optional server host name, null terminated string. + pub bootp_srv_name: [u8; 64], + /// Boot file name, null terminated string, 'generic' name or null in + /// bootrequest, fully qualified directory-path name in bootreply. + pub bootp_boot_file: [u8; 128], + dhcp_magik: u32, + /// Optional vendor-specific area, e.g. could be hardware type/serial on request, or 'capability' / remote file system handle on reply. This info may be set aside for use by a third phase bootstrap or kernel. + pub dhcp_options: [u8; 56], +} + +impl DhcpV4Packet { + /// The expected value for [`Self::dhcp_magik`]. + pub const DHCP_MAGIK: u32 = 0x63825363; + + /// Transaction ID, a random number, used to match this boot request with the responses it generates. + pub fn bootp_ident(&self) -> u32 { + u32::from_be(self.bootp_ident) + } + + /// Filled in by client, seconds elapsed since client started trying to boot. + pub fn bootp_seconds(&self) -> u16 { + u16::from_be(self.bootp_seconds) + } + + /// The flags. + pub fn bootp_flags(&self) -> DhcpV4Flags { + DhcpV4Flags::from_bits_truncate(u16::from_be(self.bootp_flags)) + } + + /// A magic cookie, should be [`Self::DHCP_MAGIK`]. + pub fn dhcp_magik(&self) -> u32 { + u32::from_be(self.dhcp_magik) + } +} + +bitflags! { + /// Represents the 'flags' field for a [`DhcpV4Packet`]. + pub struct DhcpV4Flags: u16 { + /// Should be set when the client cannot receive unicast IP datagrams + /// until its protocol software has been configured with an IP address. + const BROADCAST = 1; + } +} + +/// A Dhcpv6 Packet. +/// +/// Corresponds to the `EFI_PXE_BASE_CODE_DHCPV6_PACKET` type in the C API. +#[repr(C)] +#[derive(Clone, Copy)] +pub struct DhcpV6Packet { + /// The message type. + pub message_type: u8, + transaction_id: [u8; 3], + /// A byte array containing dhcp options. + pub dhcp_options: [u8; 1024], +} + +impl DhcpV6Packet { + /// The transaction id. + pub fn transaction_id(&self) -> u32 { + u32::from(self.transaction_id[0]) << 16 + | u32::from(self.transaction_id[1]) << 8 + | u32::from(self.transaction_id[2]) + } +} + +/// The data values in this structure are read-only and are updated by the +/// [`BaseCode`]. +/// +/// Corresponds to the `EFI_PXE_BASE_CODE_MODE` type in the C API. +#[repr(C)] +pub struct Mode { + /// `true` if this device has been started by calling [`BaseCode::start`]. + /// This field is set to `true` by [`BaseCode::start`] and to `false` by + /// the [`BaseCode::stop`] function. + pub started: bool, + /// `true` if the UNDI protocol supports IPv6 + pub ipv6_available: bool, + /// `true` if this PXE Base Code Protocol implementation supports IPv6. + pub ipv6_supported: bool, + /// `true` if this device is currently using IPv6. This field is set by + /// [`BaseCode::start`]. + pub using_ipv6: bool, + /// `true` if this PXE Base Code implementation supports Boot Integrity + /// Services (BIS). This field is set by [`BaseCode::start`]. + pub bis_supported: bool, + /// `true` if this device and the platform support Boot Integrity Services + /// (BIS). This field is set by [`BaseCode::start`]. + pub bis_detected: bool, + /// `true` for automatic ARP packet generation, `false` otherwise. This + /// field is initialized to `true` by [`BaseCode::start`] and can be + /// modified with [`BaseCode::set_parameters`]. + pub auto_arp: bool, + /// This field is used to change the Client Hardware Address (chaddr) field + /// in the DHCP and Discovery packets. Set to `true` to send the SystemGuid + /// (if one is available). Set to `false` to send the client NIC MAC + /// address. This field is initialized to `false` by [`BaseCode::start`] + /// and can be modified with [`BaseCode::set_parameters`]. + pub send_guid: bool, + /// This field is initialized to `false` by [`BaseCode::start`] and set to + /// `true` when [`BaseCode::dhcp`] completes successfully. When `true`, + /// [`Self::dhcp_discover`] is valid. This field can also be changed by + /// [`BaseCode::set_packets`]. + pub dhcp_discover_valid: bool, + /// This field is initialized to `false` by [`BaseCode::start`] and set to + /// `true` when [`BaseCode::dhcp`] completes successfully. When `true`, + /// [`Self::dhcp_ack`] is valid. This field can also be changed by + /// [`BaseCode::set_packets`]. + pub dhcp_ack_received: bool, + /// This field is initialized to `false` by [`BaseCode::start`] and set to + /// `true` when [`BaseCode::dhcp`] completes successfully and a proxy DHCP + /// offer packet was received. When `true`, [`Self::proxy_offer`] is valid. + /// This field can also be changed by [`BaseCode::set_packets`]. + pub proxy_offer_received: bool, + /// When `true`, [`Self::pxe_discover`] is valid. This field is set to + /// `false` by [`BaseCode::start`] and [`BaseCode::dhcp`], and can be set + /// to `true` or `false` by [`BaseCode::discover`] and + /// [`BaseCode::set_packets`]. + pub pxe_discover_valid: bool, + /// When `true`, [`Self::pxe_reply`] is valid. This field is set to `false` + /// by [`BaseCode::start`] and [`BaseCode::dhcp`], and can be set to `true` + /// or `false` by [`BaseCode::discover`] and [`BaseCode::set_packets`]. + pub pxe_reply_received: bool, + /// When `true`, [`Self::pxe_bis_reply`] is valid. This field is set to + /// `false` by [`BaseCode::start`] and [`BaseCode::dhcp`], and can be set + /// to `true` or `false` by the [`BaseCode::discover`] and + /// [`BaseCode::set_packets`]. + pub pxe_bis_reply_received: bool, + /// Indicates whether [`Self::icmp_error`] has been updated. This field is + /// reset to `false` by [`BaseCode::start`], [`BaseCode::dhcp`], + /// [`BaseCode::discover`],[`BaseCode::udp_read`], [`BaseCode::udp_write`], + /// [`BaseCode::arp`] and any of the TFTP/MTFTP operations. If an ICMP + /// error is received, this field will be set to `true` after + /// [`Self::icmp_error`] is updated. + pub icmp_error_received: bool, + /// Indicates whether [`Self::tftp_error`] has been updated. This field is + /// reset to `false` by [`BaseCode::start`] and any of the TFTP/MTFTP + /// operations. If a TFTP error is received, this field will be set to + /// `true` after [`Self::tftp_error`] is updated. + pub tftp_error_received: bool, + /// When `false`, callbacks will not be made. When `true`, make callbacks + /// to the PXE Base Code Callback Protocol. This field is reset to `false` + /// by [`BaseCode::start`] if the PXE Base Code Callback Protocol is not + /// available. It is reset to `true` by [`BaseCode::start`] if the PXE Base + /// Code Callback Protocol is available. + pub make_callbacks: bool, + /// The "time to live" field of the IP header. This field is initialized to + /// `16` by [`BaseCode::start`] and can be modified by + /// [`BaseCode::set_parameters`]. + pub ttl: u8, + /// The type of service field of the IP header. This field is initialized + /// to `0` by [`BaseCode::start`], and can be modified with + /// [`BaseCode::set_parameters`]. + pub tos: u8, + /// The device’s current IP address. This field is initialized to a zero + /// address by Start(). This field is set when [`BaseCode::dhcp`] completes + /// successfully. This field can also be set by + /// [`BaseCode::set_station_ip`]. This field must be set to a valid IP + /// address by either [`BaseCode::dhcp`] or [`BaseCode::set_station_ip`] + /// before [`BaseCode::discover`], [`BaseCode::udp_read`], + /// [`BaseCode::udp_write`], [`BaseCode::arp`] and any of the TFTP/MTFTP + /// operations are called. + pub station_ip: IpAddress, + /// The device's current subnet mask. This field is initialized to a zero + /// address by [`BaseCode::start`]. This field is set when + /// [`BaseCode::dhcp`] completes successfully. This field can also be set + /// by [`BaseCode::set_station_ip`]. This field must be set to a valid + /// subnet mask by either [`BaseCode::dhcp`] or + /// [`BaseCode::set_station_ip`] before [`BaseCode::discover`], + /// [`BaseCode::udp_read`], [`BaseCode::udp_write`], + /// [`BaseCode::arp`] or any of the TFTP/MTFTP operations are called. + pub subnet_mask: IpAddress, + /// Cached DHCP Discover packet. This field is zero-filled by the + /// [`BaseCode::start`] function, and is set when [`BaseCode::dhcp`] + /// completes successfully. The contents of this field can replaced by + /// [`BaseCode::set_packets`]. + pub dhcp_discover: Packet, + /// Cached DHCP Ack packet. This field is zero-filled by + /// [`BaseCode::start`], and is set when [`BaseCode::dhcp`] completes + /// successfully. The contents of this field can be replaced by + /// [`BaseCode::set_packets`]. + pub dhcp_ack: Packet, + /// Cached Proxy Offer packet. This field is zero-filled by + /// [`BaseCode::start`], and is set when [`BaseCode::dhcp`] completes + /// successfully. The contents of this field can be replaced by + /// [`BaseCode::set_packets`]. + pub proxy_offer: Packet, + /// Cached PXE Discover packet. This field is zero-filled by + /// [`BaseCode::start`], and is set when [`BaseCode::discover`] completes + /// successfully. The contents of this field can be replaced by + /// [`BaseCode::set_packets`]. + pub pxe_discover: Packet, + /// Cached PXE Reply packet. This field is zero-filled by + /// [`BaseCode::start`], and is set when [`BaseCode::discover`] completes + /// successfully. The contents of this field can be replaced by the + /// [`BaseCode::set_packets`] function. + pub pxe_reply: Packet, + /// Cached PXE BIS Reply packet. This field is zero-filled by + /// [`BaseCode::start`], and is set when [`BaseCode::discover`] completes + /// successfully. This field can be replaced by [`BaseCode::set_packets`]. + pub pxe_bis_reply: Packet, + /// The current IP receive filter settings. The receive filter is disabled + /// and the number of IP receive filters is set to zero by + /// [`BaseCode::start`], and is set by [`BaseCode::set_ip_filter`]. + pub ip_filter: IpFilter, + /// The number of valid entries in the ARP cache. This field is reset to + /// zero by [`BaseCode::start`]. + pub arp_cache_entries: u32, + /// Array of cached ARP entries. + pub arp_cache: [ArpEntry; 8], + /// The number of valid entries in the current route table. This field is + /// reset to zero by [`BaseCode::start`]. + pub route_table_entries: u32, + /// Array of route table entries. + pub route_table: [RouteEntry; 8], + /// ICMP error packet. This field is updated when an ICMP error is received + /// and is undefined until the first ICMP error is received. This field is + /// zero-filled by [`BaseCode::start`]. + pub icmp_error: IcmpError, + /// TFTP error packet. This field is updated when a TFTP error is received + /// and is undefined until the first TFTP error is received. This field is + /// zero-filled by the [`BaseCode::start`] function. + pub tftp_error: TftpError, +} + +/// An entry for the ARP cache found in [`Mode::arp_cache`] +/// +/// Corresponds to the `EFI_PXE_BASE_CODE_ARP_ENTRY` type in the C API. +#[repr(C)] +pub struct ArpEntry { + /// The IP address. + pub ip_addr: IpAddress, + /// The mac address of the device that is addressed by [`Self::ip_addr`]. + pub mac_addr: MacAddress, +} + +/// An entry for the route table found in [`Mode::route_table`] +/// +/// Corresponds to the `EFI_PXE_BASE_CODE_ROUTE_ENTRY` type in the C API. +#[repr(C)] +#[allow(missing_docs)] +pub struct RouteEntry { + pub ip_addr: IpAddress, + pub subnet_mask: IpAddress, + pub gw_addr: IpAddress, +} + +/// An ICMP error packet. +/// +/// Corresponds to the `EFI_PXE_BASE_CODE_ICMP_ERROR` type in the C API. +#[repr(C)] +#[allow(missing_docs)] +pub struct IcmpError { + pub ty: u8, + pub code: u8, + pub checksum: u16, + pub u: IcmpErrorUnion, + pub data: [u8; 494], +} + +/// Corresponds to the anonymous union inside +/// `EFI_PXE_BASE_CODE_ICMP_ERROR` in the C API. +#[repr(C)] +#[allow(missing_docs)] +pub union IcmpErrorUnion { + pub reserved: u32, + pub mtu: u32, + pub pointer: u32, + pub echo: IcmpErrorEcho, +} + +/// Corresponds to the `Echo` field in the anonymous union inside +/// `EFI_PXE_BASE_CODE_ICMP_ERROR` in the C API. +#[repr(C)] +#[derive(Clone, Copy)] +#[allow(missing_docs)] +pub struct IcmpErrorEcho { + pub identifier: u16, + pub sequence: u16, +} + +/// A TFTP error packet. +/// +/// Corresponds to the `EFI_PXE_BASE_CODE_TFTP_ERROR` type in the C API. +#[repr(C)] +#[allow(missing_docs)] +pub struct TftpError { + pub error_code: u8, + pub error_string: [u8; 127], +} + +/// Returned by [`BaseCode::tftp_read_dir`]. +#[allow(missing_docs)] +pub struct TftpFileInfo<'a> { + pub filename: &'a CStr8, + pub size: u64, + pub year: u16, + pub month: u8, + pub day: u8, + pub hour: u8, + pub minute: u8, + pub second: f32, +} + +/// Returned by [`BaseCode::mtftp_read_dir`]. +#[allow(missing_docs)] +pub struct MtftpFileInfo<'a> { + pub filename: &'a CStr8, + pub ip_address: IpAddress, + pub size: u64, + pub year: u16, + pub month: u8, + pub day: u8, + pub hour: u8, + pub minute: u8, + pub second: f32, +} + +/// Returned if a server sends a malformed response in +/// [`BaseCode::tftp_read_dir`] or [`BaseCode::mtftp_read_dir`]. +#[derive(Clone, Copy, Debug)] +pub struct ReadDirParseError; diff --git a/src/proto/pi/mod.rs b/src/proto/pi/mod.rs new file mode 100644 index 000000000..a45e55ba6 --- /dev/null +++ b/src/proto/pi/mod.rs @@ -0,0 +1,6 @@ +//! Platform Initialization protocols. +//! +//! Contains protocols defined in UEFI's +//! Platform Initialization (PI) Specification. + +pub mod mp; diff --git a/src/proto/pi/mp.rs b/src/proto/pi/mp.rs new file mode 100644 index 000000000..83b0ee677 --- /dev/null +++ b/src/proto/pi/mp.rs @@ -0,0 +1,235 @@ +//! Multi-processor management protocols. +//! +//! On any system with more than one logical processor we can categorize them as: +//! +//! * BSP — bootstrap processor, executes modules that are necessary for booting the system +//! * AP — application processor, any processor other than the bootstrap processor +//! +//! This module contains protocols that provide a generalized way of performing the following tasks on these logical processors: +//! +//! * retrieving information of multi-processor environment and MP-related status of specific processors +//! * dispatching user-provided function to APs +//! * maintaining MP-related processor status + +use crate::proto::Protocol; +use crate::{unsafe_guid, Result, Status}; +use bitflags::bitflags; +use core::ffi::c_void; +use core::ptr; +use core::time::Duration; + +/// Callback to be called on the AP. +pub type Procedure = extern "efiapi" fn(*mut c_void); + +bitflags! { + /// Flags indicating if the processor is BSP or AP, + /// if the processor is enabled or disabled, and if + /// the processor is healthy. + #[derive(Default)] + struct StatusFlag: u32 { + /// Processor is playing the role of BSP. + const PROCESSOR_AS_BSP_BIT = 1; + /// Processor is enabled. + const PROCESSOR_ENABLED_BIT = 1 << 1; + /// Processor is healthy. + const PROCESSOR_HEALTH_STATUS_BIT = 1 << 2; + } +} + +/// Information about number of logical processors on the platform. +#[derive(Default, Debug)] +pub struct ProcessorCount { + /// Total number of processors (including BSP). + pub total: usize, + /// Number of processors (including BSP) that are currently enabled. + pub enabled: usize, +} + +/// Information about processor on the platform. +#[repr(C)] +#[derive(Default, Debug)] +pub struct ProcessorInformation { + /// Unique processor ID determined by system hardware. + pub processor_id: u64, + /// Flags indicating BSP, enabled and healthy status. + status_flag: StatusFlag, + /// Physical location of the processor. + pub location: CpuPhysicalLocation, +} + +impl ProcessorInformation { + /// Returns `true` if the processor is playing the role of BSP. + pub fn is_bsp(&self) -> bool { + self.status_flag.contains(StatusFlag::PROCESSOR_AS_BSP_BIT) + } + + /// Returns `true` if the processor is enabled. + pub fn is_enabled(&self) -> bool { + self.status_flag.contains(StatusFlag::PROCESSOR_ENABLED_BIT) + } + + /// Returns `true` if the processor is healthy. + pub fn is_healthy(&self) -> bool { + self.status_flag + .contains(StatusFlag::PROCESSOR_HEALTH_STATUS_BIT) + } +} + +/// Information about physical location of the processor. +#[repr(C)] +#[derive(Default, Debug)] +pub struct CpuPhysicalLocation { + /// Zero-based physical package number that identifies + /// the cartridge of the processor. + pub package: u32, + /// Zero-based physical core number within package of the processor. + pub core: u32, + /// Zero-based logical thread number within core of the processor. + pub thread: u32, +} + +/// Protocol that provides services needed for multi-processor management. +#[repr(C)] +#[unsafe_guid("3fdda605-a76e-4f46-ad29-12f4531b3d08")] +#[derive(Protocol)] +pub struct MpServices { + get_number_of_processors: extern "efiapi" fn( + this: *const MpServices, + number_of_processors: *mut usize, + number_of_enabled_processors: *mut usize, + ) -> Status, + get_processor_info: extern "efiapi" fn( + this: *const MpServices, + processor_number: usize, + processor_info_buffer: *mut ProcessorInformation, + ) -> Status, + startup_all_aps: extern "efiapi" fn( + this: *const MpServices, + procedure: Procedure, + single_thread: bool, + wait_event: *mut c_void, + timeout_in_micro_seconds: usize, + procedure_argument: *mut c_void, + failed_cpu_list: *mut *mut usize, + ) -> Status, + startup_this_ap: extern "efiapi" fn( + this: *const MpServices, + procedure: Procedure, + processor_number: usize, + wait_event: *mut c_void, + timeout_in_micro_seconds: usize, + procedure_argument: *mut c_void, + finished: *mut bool, + ) -> Status, + switch_bsp: extern "efiapi" fn( + this: *const MpServices, + processor_number: usize, + enable_old_bsp: bool, + ) -> Status, + enable_disable_ap: extern "efiapi" fn( + this: *const MpServices, + processor_number: usize, + enable_ap: bool, + health_flag: *const u32, + ) -> Status, + who_am_i: extern "efiapi" fn(this: *const MpServices, processor_number: *mut usize) -> Status, +} + +impl MpServices { + /// Retrieves the number of logical processors and the number of enabled logical processors in the system. + pub fn get_number_of_processors(&self) -> Result { + let mut total: usize = 0; + let mut enabled: usize = 0; + (self.get_number_of_processors)(self, &mut total, &mut enabled) + .into_with_val(|| ProcessorCount { total, enabled }) + } + + /// Gets detailed information on the requested processor at the instant this call is made. + pub fn get_processor_info(&self, processor_number: usize) -> Result { + let mut pi: ProcessorInformation = Default::default(); + (self.get_processor_info)(self, processor_number, &mut pi).into_with_val(|| pi) + } + + /// Executes provided function on all APs in blocking mode. + pub fn startup_all_aps( + &self, + single_thread: bool, + procedure: Procedure, + procedure_argument: *mut c_void, + timeout: Option, + ) -> Result { + let timeout_arg = match timeout { + Some(timeout) => timeout.as_micros().try_into().unwrap(), + None => 0, + }; + + (self.startup_all_aps)( + self, + procedure, + single_thread, + ptr::null_mut(), + timeout_arg, + procedure_argument, + ptr::null_mut(), + ) + .into() + } + + /// Executes provided function on a specific AP in blocking mode. + pub fn startup_this_ap( + &self, + processor_number: usize, + procedure: Procedure, + procedure_argument: *mut c_void, + timeout: Option, + ) -> Result { + let timeout_arg = match timeout { + Some(timeout) => timeout.as_micros().try_into().unwrap(), + None => 0, + }; + + (self.startup_this_ap)( + self, + procedure, + processor_number, + ptr::null_mut(), + timeout_arg, + procedure_argument, + ptr::null_mut(), + ) + .into() + } + + /// Switches the requested AP to be the BSP from that point onward. + pub fn switch_bsp(&self, processor_number: usize, enable_old_bsp: bool) -> Result { + (self.switch_bsp)(self, processor_number, enable_old_bsp).into() + } + + /// Enables or disables an AP from this point onward. + /// + /// The `healthy` argument can be used to specify the new health status of the AP. + pub fn enable_disable_ap( + &self, + processor_number: usize, + enable_ap: bool, + healthy: Option, + ) -> Result { + let health_flag_raw: u32; + let health_flag_ptr = match healthy { + Some(healthy) => { + let mut sf = StatusFlag::empty(); + sf.set(StatusFlag::PROCESSOR_HEALTH_STATUS_BIT, healthy); + health_flag_raw = sf.bits(); + &health_flag_raw + } + None => ptr::null(), + }; + (self.enable_disable_ap)(self, processor_number, enable_ap, health_flag_ptr).into() + } + + /// Gets the handle number of the caller processor. + pub fn who_am_i(&self) -> Result { + let mut processor_number: usize = 0; + (self.who_am_i)(self, &mut processor_number).into_with_val(|| processor_number) + } +} diff --git a/src/proto/rng.rs b/src/proto/rng.rs new file mode 100644 index 000000000..420f9b1ea --- /dev/null +++ b/src/proto/rng.rs @@ -0,0 +1,132 @@ +//! `Rng` protocol. + +use crate::{data_types::Guid, proto::Protocol, unsafe_guid, Result, Status}; +use core::{mem, ptr}; + +newtype_enum! { + /// The algorithms listed are optional, not meant to be exhaustive + /// and may be augmented by vendors or other industry standards. + pub enum RngAlgorithmType: Guid => { + /// Indicates a empty algorithm, used to instantiate a buffer + /// for `get_info` + EMPTY_ALGORITHM = Guid::from_values( + 0x00000000, + 0x0000, + 0x0000, + 0x0000, + 0x000000000000, + ), + + /// The “raw†algorithm, when supported, is intended to provide + /// entropy directly from the source, without it going through + /// some deterministic random bit generator. + ALGORITHM_RAW = Guid::from_values( + 0xe43176d7, + 0xb6e8, + 0x4827, + 0xb784, + 0x7ffdc4b68561, + ), + + /// ALGORITHM_SP800_90_HASH_256 + ALGORITHM_SP800_90_HASH_256 = Guid::from_values( + 0xa7af67cb, + 0x603b, + 0x4d42, + 0xba21, + 0x70bfb6293f96, + ), + + /// ALGORITHM_SP800_90_HMAC_256 + ALGORITHM_SP800_90_HMAC_256 = Guid::from_values( + 0xc5149b43, + 0xae85, + 0x4f53, + 0x9982, + 0xb94335d3a9e7, + ), + + /// ALGORITHM_SP800_90_CTR_256 + ALGORITHM_SP800_90_CTR_256 = Guid::from_values( + 0x44f0de6e, + 0x4d8c, + 0x4045, + 0xa8c7, + 0x4dd168856b9e, + ), + + /// ALGORITHM_X9_31_3DES + ALGORITHM_X9_31_3DES = Guid::from_values( + 0x63c4785a, + 0xca34, + 0x4012, + 0xa3c8, + 0x0b6a324f5546, + ), + + /// ALGORITHM_X9_31_AES + ALGORITHM_X9_31_AES = Guid::from_values( + 0xacd03321, + 0x777e, + 0x4d3d, + 0xb1c8, + 0x20cfd88820c9, + ), + } +} + +/// Rng protocol +#[repr(C)] +#[unsafe_guid("3152bca5-eade-433d-862e-c01cdc291f44")] +#[derive(Protocol)] +pub struct Rng { + get_info: unsafe extern "efiapi" fn( + this: &Rng, + algorithm_list_size: *mut usize, + algorithm_list: *mut RngAlgorithmType, + ) -> Status, + get_rng: unsafe extern "efiapi" fn( + this: &Rng, + algorithm: *const RngAlgorithmType, + value_length: usize, + value: *mut u8, + ) -> Status, +} + +impl Rng { + /// Returns information about the random number generation implementation. + pub fn get_info<'buf>( + &mut self, + algorithm_list: &'buf mut [RngAlgorithmType], + ) -> Result<&'buf [RngAlgorithmType], Option> { + let mut algorithm_list_size = algorithm_list.len() * mem::size_of::(); + + unsafe { + (self.get_info)(self, &mut algorithm_list_size, algorithm_list.as_mut_ptr()).into_with( + || { + let len = algorithm_list_size / mem::size_of::(); + &algorithm_list[..len] + }, + |status| { + if status == Status::BUFFER_TOO_SMALL { + Some(algorithm_list_size) + } else { + None + } + }, + ) + } + } + + /// Returns the next set of random numbers + pub fn get_rng(&mut self, algorithm: Option, buffer: &mut [u8]) -> Result { + let buffer_length = buffer.len(); + + let algo = match algorithm.as_ref() { + None => ptr::null(), + Some(algo) => algo as *const RngAlgorithmType, + }; + + unsafe { (self.get_rng)(self, algo, buffer_length, buffer.as_mut_ptr()).into() } + } +} diff --git a/src/proto/security/memory_protection.rs b/src/proto/security/memory_protection.rs new file mode 100644 index 000000000..0f548fc6c --- /dev/null +++ b/src/proto/security/memory_protection.rs @@ -0,0 +1,110 @@ +use crate::data_types::PhysicalAddress; +use crate::proto::Protocol; +use crate::table::boot::MemoryAttribute; +use crate::{unsafe_guid, Result, Status}; +use core::ops::Range; + +/// Protocol for getting and setting memory protection attributes. +/// +/// This corresponds to the `EFI_MEMORY_ATTRIBUTE_PROTOCOL` [proposal]. +/// +/// [proposal]: https://bugzilla.tianocore.org/show_bug.cgi?id=3519 +#[repr(C)] +#[unsafe_guid("f4560cf6-40ec-4b4a-a192-bf1d57d0b189")] +#[derive(Protocol)] +pub struct MemoryProtection { + get_memory_attributes: unsafe extern "efiapi" fn( + this: *const Self, + base_address: PhysicalAddress, + length: u64, + attributes: *mut MemoryAttribute, + ) -> Status, + + set_memory_attributes: unsafe extern "efiapi" fn( + this: *const Self, + base_address: PhysicalAddress, + length: u64, + attributes: MemoryAttribute, + ) -> Status, + + clear_memory_attributes: unsafe extern "efiapi" fn( + this: *const Self, + base_address: PhysicalAddress, + length: u64, + attributes: MemoryAttribute, + ) -> Status, +} + +impl MemoryProtection { + /// Get the attributes of a memory region. + /// + /// The attribute mask this returns will only contain bits in the + /// set of [`READ_PROTECT`], [`EXECUTE_PROTECT`], and [`READ_ONLY`]. + /// + /// If the attributes are not consistent within the region, + /// [`Status::NO_MAPPING`] is returned. + /// + /// [`READ_PROTECT`]: MemoryAttribute::READ_PROTECT + /// [`EXECUTE_PROTECT`]: MemoryAttribute::EXECUTE_PROTECT + /// [`READ_ONLY`]: MemoryAttribute::READ_ONLY + pub fn get_memory_attributes( + &self, + byte_region: Range, + ) -> Result { + let mut attributes = MemoryAttribute::empty(); + let (base_address, length) = range_to_base_and_len(byte_region); + unsafe { + (self.get_memory_attributes)(self, base_address, length, &mut attributes) + .into_with_val(|| attributes) + } + } + + /// Set the attributes of a memory region. + /// + /// The valid attributes to set are [`READ_PROTECT`], + /// [`EXECUTE_PROTECT`], and [`READ_ONLY`]. + /// + /// [`READ_PROTECT`]: MemoryAttribute::READ_PROTECT + /// [`EXECUTE_PROTECT`]: MemoryAttribute::EXECUTE_PROTECT + /// [`READ_ONLY`]: MemoryAttribute::READ_ONLY + pub fn set_memory_attributes( + &self, + byte_region: Range, + attributes: MemoryAttribute, + ) -> Result { + let (base_address, length) = range_to_base_and_len(byte_region); + unsafe { (self.set_memory_attributes)(self, base_address, length, attributes).into() } + } + + /// Clear the attributes of a memory region. + /// + /// The valid attributes to clear are [`READ_PROTECT`], + /// [`EXECUTE_PROTECT`], and [`READ_ONLY`]. + /// + /// [`READ_PROTECT`]: MemoryAttribute::READ_PROTECT + /// [`EXECUTE_PROTECT`]: MemoryAttribute::EXECUTE_PROTECT + /// [`READ_ONLY`]: MemoryAttribute::READ_ONLY + pub fn clear_memory_attributes( + &self, + byte_region: Range, + attributes: MemoryAttribute, + ) -> Result { + let (base_address, length) = range_to_base_and_len(byte_region); + unsafe { (self.clear_memory_attributes)(self, base_address, length, attributes).into() } + } +} + +/// Convert a byte `Range` to `(base_address, length)`. +fn range_to_base_and_len(r: Range) -> (PhysicalAddress, PhysicalAddress) { + (r.start, r.end.checked_sub(r.start).unwrap()) +} + +#[cfg(test)] +mod tests { + use super::*; + + #[test] + fn test_range_conversion() { + assert_eq!(range_to_base_and_len(2..5), (2, 3)); + } +} diff --git a/src/proto/security/mod.rs b/src/proto/security/mod.rs new file mode 100644 index 000000000..f4ac1de18 --- /dev/null +++ b/src/proto/security/mod.rs @@ -0,0 +1,4 @@ +//! Protocols related to secure technologies. + +mod memory_protection; +pub use memory_protection::MemoryProtection; diff --git a/src/proto/shim/mod.rs b/src/proto/shim/mod.rs new file mode 100644 index 000000000..c2a52b604 --- /dev/null +++ b/src/proto/shim/mod.rs @@ -0,0 +1,121 @@ +//! Shim lock protocol. + +#![cfg(any( + target_arch = "i386", + target_arch = "x86_64", + target_arch = "arm", + target_arch = "aarch64" +))] + +use crate::proto::Protocol; +use crate::result::Error; +use crate::{unsafe_guid, Result, Status}; +use core::ffi::c_void; +use core::mem::MaybeUninit; + +// The `PE_COFF_LOADER_IMAGE_CONTEXT` type. None of our methods need to inspect +// the fields of this struct, we just need to make sure it is the right size. +#[repr(C)] +struct Context { + _image_address: u64, + _image_size: u64, + _entry_point: u64, + _size_of_headers: usize, + _image_type: u16, + _number_of_sections: u16, + _section_alignment: u32, + _first_section: *const c_void, + _reloc_dir: *const c_void, + _sec_dir: *const c_void, + _number_of_rva_and_sizes: u64, + _pe_hdr: *const c_void, +} + +const SHA1_DIGEST_SIZE: usize = 20; +const SHA256_DIGEST_SIZE: usize = 32; + +/// Authenticode hashes of some UEFI application +pub struct Hashes { + /// SHA256 Authenticode Digest + pub sha256: [u8; SHA256_DIGEST_SIZE], + /// SHA1 Authenticode Digest + pub sha1: [u8; SHA1_DIGEST_SIZE], +} + +// These macros set the correct calling convention for the Shim protocol methods. + +#[cfg(any(target_arch = "i386", target_arch = "x86_64"))] +macro_rules! shim_function { + (fn $args:tt -> $return_type:ty) => (extern "sysv64" fn $args -> $return_type) +} + +#[cfg(any(target_arch = "arm", target_arch = "aarch64"))] +macro_rules! shim_function { + (fn $args:tt -> $return_type:ty) => (extern "C" fn $args -> $return_type) +} + +/// The Shim lock protocol. +/// +/// This protocol is not part of the UEFI specification, but is +/// installed by the [Shim bootloader](https://github.com/rhboot/shim) +/// which is commonly used by Linux distributions to support UEFI +/// Secure Boot. Shim is built with an embedded certificate that is +/// used to validate another EFI application before running it. That +/// application may itself be a bootloader that needs to validate +/// another EFI application before running it, and the shim lock +/// protocol exists to support that. +#[repr(C)] +#[unsafe_guid("605dab50-e046-4300-abb6-3dd810dd8b23")] +#[derive(Protocol)] +pub struct ShimLock { + verify: shim_function! { fn(buffer: *const u8, size: u32) -> Status }, + hash: shim_function! { + fn( + buffer: *const u8, + size: u32, + context: *mut Context, + sha256: *mut [u8; SHA256_DIGEST_SIZE], + sha1: *mut [u8; SHA1_DIGEST_SIZE] + ) -> Status + }, + context: shim_function! { fn(buffer: *const u8, size: u32, context: *mut Context) -> Status }, +} + +impl ShimLock { + /// Verify that an EFI application is signed by the certificate + /// embedded in shim. + /// + /// The buffer's size must fit in a `u32`; if that condition is not + /// met then a `BAD_BUFFER_SIZE` error will be returned and the shim + /// lock protocol will not be called. + pub fn verify(&self, buffer: &[u8]) -> Result { + let size: u32 = buffer + .len() + .try_into() + .map_err(|_| Error::from(Status::BAD_BUFFER_SIZE))?; + (self.verify)(buffer.as_ptr(), size).into() + } + /// Compute the Authenticode Hash of the provided EFI application. + /// + /// The buffer's size must fit in a `u32`; if that condition is not + /// met then a `BAD_BUFFER_SIZE` error will be returned and the shim + /// lock protocol will not be called. + pub fn hash(&self, buffer: &[u8], hashes: &mut Hashes) -> Result { + let ptr: *const u8 = buffer.as_ptr(); + let size: u32 = buffer + .len() + .try_into() + .map_err(|_| Error::from(Status::BAD_BUFFER_SIZE))?; + + let mut context = MaybeUninit::::uninit(); + Result::from((self.context)(ptr, size, context.as_mut_ptr()))?; + (self.hash)( + ptr, + size, + context.as_mut_ptr(), + &mut hashes.sha256, + &mut hashes.sha1, + ) + .into() + } +} diff --git a/src/result/error.rs b/src/result/error.rs new file mode 100644 index 000000000..e04be70ac --- /dev/null +++ b/src/result/error.rs @@ -0,0 +1,40 @@ +use super::Status; +use core::fmt::Debug; + +/// Errors emitted from UEFI entry point must propagate erronerous UEFI statuses, +/// and may optionally propagate additional entry point-specific data. +#[derive(Debug, PartialEq, Eq)] +pub struct Error { + status: Status, + data: Data, +} + +impl Error { + /// Create an `Error`. + pub fn new(status: Status, data: Data) -> Self { + Self { status, data } + } + + /// Get error `Status`. + pub fn status(&self) -> Status { + self.status + } + + /// Get error data. + pub fn data(&self) -> &Data { + &self.data + } + + /// Split this error into its inner status and error data + pub fn split(self) -> (Status, Data) { + (self.status, self.data) + } +} + +// Errors without error data can be autogenerated from statuses + +impl From for Error<()> { + fn from(status: Status) -> Self { + Self { status, data: () } + } +} diff --git a/src/result/mod.rs b/src/result/mod.rs new file mode 100644 index 000000000..32b29d285 --- /dev/null +++ b/src/result/mod.rs @@ -0,0 +1,96 @@ +///! Facilities for dealing with UEFI operation results. +use core::fmt::Debug; + +/// The error type that we use, essentially a status code + optional additional data +mod error; +pub use self::error::Error; + +/// Definition of UEFI's standard status codes +mod status; +pub use self::status::Status; + +/// Return type of most UEFI functions. Both success and error payloads are optional. +/// +/// Almost all UEFI operations provide a status code as an output which +/// indicates either success, a warning, or an error. This type alias maps +/// [`Status::SUCCESS`] to the `Ok` variant (with optional `Output` data), and +/// maps both warning and error statuses to the `Err` variant (with optional +/// `ErrData`). +/// +/// Warnings are treated as errors by default because they generally indicate +/// an abnormal situation. +/// +/// Some convenience methods are provided by the [`ResultExt`] trait. +pub type Result = core::result::Result>; + +/// Extension trait which provides some convenience methods for [`Result`]. +pub trait ResultExt { + /// Extract the UEFI status from this result + fn status(&self) -> Status; + + /// Transform the ErrData value to () + fn discard_errdata(self) -> Result; + + /// Calls `op` if the result contains a warning, otherwise returns + /// the result unchanged. + /// + /// By default warning statuses are treated as errors (i.e. stored in the + /// `Err` variant) because they generally indicate an abnormal + /// situation. In rare cases though it may be helpful to handle a + /// warning. This method is similar to [`Result::or_else`], except that + /// `op` is called only when the status is a warning. + /// + /// # Example + /// + /// ``` + /// use uefi::{Result, ResultExt, Status}; + /// + /// # fn x() -> uefi::Result { + /// # let some_result = Result::from(Status::WARN_RESET_REQUIRED); + /// // Treat a specific warning as success, propagate others as errors. + /// some_result.handle_warning(|err| { + /// if err.status() == Status::WARN_RESET_REQUIRED { + /// Ok(()) + /// } else { + /// Err(err) + /// } + /// })?; + /// # Status::SUCCESS.into() + /// # } + /// ``` + fn handle_warning(self, op: O) -> Result + where + O: FnOnce(Error) -> Result; +} + +impl ResultExt for Result { + fn status(&self) -> Status { + match self { + Ok(_) => Status::SUCCESS, + Err(e) => e.status(), + } + } + + fn discard_errdata(self) -> Result { + match self { + Ok(o) => Ok(o), + Err(e) => Err(e.status().into()), + } + } + + fn handle_warning(self, op: O) -> Result + where + O: FnOnce(Error) -> Result, + { + match self { + Ok(output) => Ok(output), + Err(err) => { + if err.status().is_warning() { + op(err) + } else { + Err(err) + } + } + } + } +} diff --git a/src/result/status.rs b/src/result/status.rs new file mode 100644 index 000000000..53c0f8117 --- /dev/null +++ b/src/result/status.rs @@ -0,0 +1,217 @@ +use super::{Error, Result}; +use core::fmt::Debug; + +/// Bit indicating that an UEFI status code is an error +const ERROR_BIT: usize = 1 << (core::mem::size_of::() * 8 - 1); + +newtype_enum! { +/// UEFI uses status codes in order to report successes, errors, and warnings. +/// +/// Unfortunately, the spec allows and encourages implementation-specific +/// non-portable status codes. Therefore, these cannot be modeled as a Rust +/// enum, as injecting an unknown value in a Rust enum is undefined behaviour. +/// +/// For lack of a better option, we therefore model them as a newtype of usize. +#[must_use] +pub enum Status: usize => { + /// The operation completed successfully. + SUCCESS = 0, + + /// The string contained characters that could not be rendered and were skipped. + WARN_UNKNOWN_GLYPH = 1, + /// The handle was closed, but the file was not deleted. + WARN_DELETE_FAILURE = 2, + /// The handle was closed, but the data to the file was not flushed properly. + WARN_WRITE_FAILURE = 3, + /// The resulting buffer was too small, and the data was truncated. + WARN_BUFFER_TOO_SMALL = 4, + /// The data has not been updated within the timeframe set by local policy. + WARN_STALE_DATA = 5, + /// The resulting buffer contains UEFI-compliant file system. + WARN_FILE_SYSTEM = 6, + /// The operation will be processed across a system reset. + WARN_RESET_REQUIRED = 7, + + /// The image failed to load. + LOAD_ERROR = ERROR_BIT | 1, + /// A parameter was incorrect. + INVALID_PARAMETER = ERROR_BIT | 2, + /// The operation is not supported. + UNSUPPORTED = ERROR_BIT | 3, + /// The buffer was not the proper size for the request. + BAD_BUFFER_SIZE = ERROR_BIT | 4, + /// The buffer is not large enough to hold the requested data. + /// The required buffer size is returned in the appropriate parameter. + BUFFER_TOO_SMALL = ERROR_BIT | 5, + /// There is no data pending upon return. + NOT_READY = ERROR_BIT | 6, + /// The physical device reported an error while attempting the operation. + DEVICE_ERROR = ERROR_BIT | 7, + /// The device cannot be written to. + WRITE_PROTECTED = ERROR_BIT | 8, + /// A resource has run out. + OUT_OF_RESOURCES = ERROR_BIT | 9, + /// An inconstency was detected on the file system. + VOLUME_CORRUPTED = ERROR_BIT | 10, + /// There is no more space on the file system. + VOLUME_FULL = ERROR_BIT | 11, + /// The device does not contain any medium to perform the operation. + NO_MEDIA = ERROR_BIT | 12, + /// The medium in the device has changed since the last access. + MEDIA_CHANGED = ERROR_BIT | 13, + /// The item was not found. + NOT_FOUND = ERROR_BIT | 14, + /// Access was denied. + ACCESS_DENIED = ERROR_BIT | 15, + /// The server was not found or did not respond to the request. + NO_RESPONSE = ERROR_BIT | 16, + /// A mapping to a device does not exist. + NO_MAPPING = ERROR_BIT | 17, + /// The timeout time expired. + TIMEOUT = ERROR_BIT | 18, + /// The protocol has not been started. + NOT_STARTED = ERROR_BIT | 19, + /// The protocol has already been started. + ALREADY_STARTED = ERROR_BIT | 20, + /// The operation was aborted. + ABORTED = ERROR_BIT | 21, + /// An ICMP error occurred during the network operation. + ICMP_ERROR = ERROR_BIT | 22, + /// A TFTP error occurred during the network operation. + TFTP_ERROR = ERROR_BIT | 23, + /// A protocol error occurred during the network operation. + PROTOCOL_ERROR = ERROR_BIT | 24, + /// The function encountered an internal version that was + /// incompatible with a version requested by the caller. + INCOMPATIBLE_VERSION = ERROR_BIT | 25, + /// The function was not performed due to a security violation. + SECURITY_VIOLATION = ERROR_BIT | 26, + /// A CRC error was detected. + CRC_ERROR = ERROR_BIT | 27, + /// Beginning or end of media was reached + END_OF_MEDIA = ERROR_BIT | 28, + /// The end of the file was reached. + END_OF_FILE = ERROR_BIT | 31, + /// The language specified was invalid. + INVALID_LANGUAGE = ERROR_BIT | 32, + /// The security status of the data is unknown or compromised and + /// the data must be updated or replaced to restore a valid security status. + COMPROMISED_DATA = ERROR_BIT | 33, + /// There is an address conflict address allocation + IP_ADDRESS_CONFLICT = ERROR_BIT | 34, + /// A HTTP error occurred during the network operation. + HTTP_ERROR = ERROR_BIT | 35, +}} + +impl Status { + /// Returns true if status code indicates success. + #[inline] + pub fn is_success(self) -> bool { + self == Status::SUCCESS + } + + /// Returns true if status code indicates a warning. + #[inline] + pub fn is_warning(self) -> bool { + (self != Status::SUCCESS) && (self.0 & ERROR_BIT == 0) + } + + /// Returns true if the status code indicates an error. + #[inline] + pub fn is_error(self) -> bool { + self.0 & ERROR_BIT != 0 + } + + /// Converts this status code into a result with a given value. + #[inline] + pub fn into_with_val(self, val: impl FnOnce() -> T) -> Result { + if self.is_success() { + Ok(val()) + } else { + Err(self.into()) + } + } + + /// Converts this status code into a result with a given error payload + #[inline] + pub fn into_with_err( + self, + err: impl FnOnce(Status) -> ErrData, + ) -> Result<(), ErrData> { + if self.is_success() { + Ok(()) + } else { + Err(Error::new(self, err(self))) + } + } + + /// Convert this status code into a result with a given value and error payload + #[inline] + pub fn into_with( + self, + val: impl FnOnce() -> T, + err: impl FnOnce(Status) -> ErrData, + ) -> Result { + if self.is_success() { + Ok(val()) + } else { + Err(Error::new(self, err(self))) + } + } +} + +// An UEFI status is equivalent to a Result with no data or error payload +impl From for Result<(), ()> { + #[inline] + fn from(status: Status) -> Result<(), ()> { + status.into_with(|| (), |_| ()) + } +} + +#[cfg(test)] +mod tests { + use super::*; + + #[test] + fn test_status_to_result() { + assert!(Result::from(Status::SUCCESS).is_ok()); + assert!(Result::from(Status::WARN_DELETE_FAILURE).is_err()); + assert!(Result::from(Status::BUFFER_TOO_SMALL).is_err()); + + assert_eq!(Status::SUCCESS.into_with_val(|| 123).unwrap(), 123); + assert!(Status::WARN_DELETE_FAILURE.into_with_val(|| 123).is_err()); + assert!(Status::BUFFER_TOO_SMALL.into_with_val(|| 123).is_err()); + + assert!(Status::SUCCESS.into_with_err(|_| 123).is_ok()); + assert_eq!( + *Status::WARN_DELETE_FAILURE + .into_with_err(|_| 123) + .unwrap_err() + .data(), + 123 + ); + assert_eq!( + *Status::BUFFER_TOO_SMALL + .into_with_err(|_| 123) + .unwrap_err() + .data(), + 123 + ); + + assert_eq!(Status::SUCCESS.into_with(|| 123, |_| 456).unwrap(), 123); + assert_eq!( + *Status::WARN_DELETE_FAILURE + .into_with(|| 123, |_| 456) + .unwrap_err() + .data(), + 456 + ); + assert_eq!( + *Status::BUFFER_TOO_SMALL + .into_with(|| 123, |_| 456) + .unwrap_err() + .data(), + 456 + ); + } +} diff --git a/src/table/boot.rs b/src/table/boot.rs new file mode 100644 index 000000000..acfc1d41c --- /dev/null +++ b/src/table/boot.rs @@ -0,0 +1,1828 @@ +//! UEFI services available during boot. + +use super::{Header, Revision}; +use crate::data_types::{Align, PhysicalAddress, VirtualAddress}; +use crate::proto::device_path::{DevicePath, FfiDevicePath}; +#[cfg(feature = "exts")] +use crate::proto::{loaded_image::LoadedImage, media::fs::SimpleFileSystem}; +use crate::proto::{Protocol, ProtocolPointer}; +use crate::{Char16, Event, Guid, Handle, Result, Status}; +#[cfg(feature = "exts")] +use alloc_api::vec::Vec; +use bitflags::bitflags; +use core::cell::UnsafeCell; +use core::ffi::c_void; +use core::fmt::{Debug, Formatter}; +use core::mem::{self, MaybeUninit}; +use core::ops::{Deref, DerefMut}; +use core::ptr::NonNull; +use core::{ptr, slice}; + +// TODO: this similar to `SyncUnsafeCell`. Once that is stabilized we +// can use it instead. +struct GlobalImageHandle { + handle: UnsafeCell>, +} + +// Safety: reads and writes are managed via `set_image_handle` and +// `BootServices::image_handle`. +unsafe impl Sync for GlobalImageHandle {} + +static IMAGE_HANDLE: GlobalImageHandle = GlobalImageHandle { + handle: UnsafeCell::new(None), +}; + +/// Contains pointers to all of the boot services. +/// +/// # Accessing `BootServices` +/// +/// A reference to `BootServices` can only be accessed by calling [`SystemTable::boot_services`]. +/// +/// [`SystemTable::boot_services`]: crate::table::SystemTable::boot_services +/// +/// # Accessing protocols +/// +/// Protocols can be opened using several methods of `BootServices`. Most +/// commonly, [`open_protocol_exclusive`] should be used. This ensures that +/// nothing else can use the protocol until it is closed, and returns a +/// [`ScopedProtocol`] that takes care of closing the protocol when it is +/// dropped. +/// +/// Other methods for opening protocols: +/// +/// * [`open_protocol`] +/// * [`get_image_file_system`] +/// * [`handle_protocol`] +/// * [`locate_protocol`] +/// +/// For protocol definitions, see the [`proto`] module. +/// +/// [`proto`]: crate::proto +/// [`open_protocol_exclusive`]: BootServices::open_protocol_exclusive +/// [`open_protocol`]: BootServices::open_protocol +/// [`get_image_file_system`]: BootServices::get_image_file_system +/// [`locate_protocol`]: BootServices::locate_protocol +/// [`handle_protocol`]: BootServices::handle_protocol +/// +/// ## Use of [`UnsafeCell`] for protocol references +/// +/// Some protocols require mutable access to themselves. For example, +/// most of the methods of the [`Output`] protocol take `&mut self`, +/// because the internal function pointers specified by UEFI for that +/// protocol take a mutable `*This` pointer. We don't want to directly +/// return a mutable reference to a protocol though because the lifetime +/// of the protocol is tied to `BootServices`. (That lifetime improves +/// safety by ensuring protocols aren't accessed after exiting boot +/// services.) If methods like [`open_protocol`] protocol took a mutable +/// reference to `BootServices` and returned a mutable reference to a +/// protocol it would prevent all other access to `BootServices` until +/// the protocol reference was dropped. To work around this, the +/// protocol reference is wrapped in an [`UnsafeCell`]. Callers can then +/// get a mutable reference to the protocol if needed. +/// +/// [`Output`]: crate::proto::console::text::Output +/// [`open_protocol`]: BootServices::open_protocol +#[repr(C)] +pub struct BootServices { + header: Header, + + // Task Priority services + raise_tpl: unsafe extern "efiapi" fn(new_tpl: Tpl) -> Tpl, + restore_tpl: unsafe extern "efiapi" fn(old_tpl: Tpl), + + // Memory allocation functions + allocate_pages: extern "efiapi" fn( + alloc_ty: u32, + mem_ty: MemoryType, + count: usize, + addr: &mut PhysicalAddress, + ) -> Status, + free_pages: extern "efiapi" fn(addr: PhysicalAddress, pages: usize) -> Status, + get_memory_map: unsafe extern "efiapi" fn( + size: &mut usize, + map: *mut MemoryDescriptor, + key: &mut MemoryMapKey, + desc_size: &mut usize, + desc_version: &mut u32, + ) -> Status, + allocate_pool: + extern "efiapi" fn(pool_type: MemoryType, size: usize, buffer: &mut *mut u8) -> Status, + free_pool: extern "efiapi" fn(buffer: *mut u8) -> Status, + + // Event & timer functions + create_event: unsafe extern "efiapi" fn( + ty: EventType, + notify_tpl: Tpl, + notify_func: Option, + notify_ctx: Option>, + out_event: *mut Event, + ) -> Status, + set_timer: unsafe extern "efiapi" fn(event: Event, ty: u32, trigger_time: u64) -> Status, + wait_for_event: unsafe extern "efiapi" fn( + number_of_events: usize, + events: *mut Event, + out_index: *mut usize, + ) -> Status, + signal_event: extern "efiapi" fn(event: Event) -> Status, + close_event: unsafe extern "efiapi" fn(event: Event) -> Status, + check_event: unsafe extern "efiapi" fn(event: Event) -> Status, + + // Protocol handlers + install_protocol_interface: usize, + reinstall_protocol_interface: usize, + uninstall_protocol_interface: usize, + handle_protocol: + extern "efiapi" fn(handle: Handle, proto: &Guid, out_proto: &mut *mut c_void) -> Status, + _reserved: usize, + register_protocol_notify: usize, + locate_handle: unsafe extern "efiapi" fn( + search_ty: i32, + proto: *const Guid, + key: *mut c_void, + buf_sz: &mut usize, + buf: *mut MaybeUninit, + ) -> Status, + locate_device_path: unsafe extern "efiapi" fn( + proto: &Guid, + device_path: &mut *const FfiDevicePath, + out_handle: &mut MaybeUninit, + ) -> Status, + install_configuration_table: usize, + + // Image services + load_image: unsafe extern "efiapi" fn( + boot_policy: u8, + parent_image_handle: Handle, + device_path: *const FfiDevicePath, + source_buffer: *const u8, + source_size: usize, + image_handle: &mut MaybeUninit, + ) -> Status, + start_image: unsafe extern "efiapi" fn( + image_handle: Handle, + exit_data_size: *mut usize, + exit_data: &mut *mut Char16, + ) -> Status, + exit: extern "efiapi" fn( + image_handle: Handle, + exit_status: Status, + exit_data_size: usize, + exit_data: *mut Char16, + ) -> !, + unload_image: extern "efiapi" fn(image_handle: Handle) -> Status, + exit_boot_services: + unsafe extern "efiapi" fn(image_handle: Handle, map_key: MemoryMapKey) -> Status, + + // Misc services + get_next_monotonic_count: usize, + stall: extern "efiapi" fn(microseconds: usize) -> Status, + set_watchdog_timer: unsafe extern "efiapi" fn( + timeout: usize, + watchdog_code: u64, + data_size: usize, + watchdog_data: *const u16, + ) -> Status, + + // Driver support services + connect_controller: unsafe extern "efiapi" fn( + controller: Handle, + driver_image: Option, + remaining_device_path: *const FfiDevicePath, + recursive: bool, + ) -> Status, + disconnect_controller: unsafe extern "efiapi" fn( + controller: Handle, + driver_image: Option, + child: Option, + ) -> Status, + + // Protocol open / close services + open_protocol: extern "efiapi" fn( + handle: Handle, + protocol: &Guid, + interface: &mut *mut c_void, + agent_handle: Handle, + controller_handle: Option, + attributes: u32, + ) -> Status, + close_protocol: extern "efiapi" fn( + handle: Handle, + protocol: &Guid, + agent_handle: Handle, + controller_handle: Option, + ) -> Status, + open_protocol_information: usize, + + // Library services + protocols_per_handle: unsafe extern "efiapi" fn( + handle: Handle, + protocol_buffer: *mut *mut *const Guid, + protocol_buffer_count: *mut usize, + ) -> Status, + locate_handle_buffer: unsafe extern "efiapi" fn( + search_ty: i32, + proto: *const Guid, + key: *const c_void, + no_handles: &mut usize, + buf: &mut *mut Handle, + ) -> Status, + locate_protocol: extern "efiapi" fn( + proto: &Guid, + registration: *mut c_void, + out_proto: &mut *mut c_void, + ) -> Status, + install_multiple_protocol_interfaces: usize, + uninstall_multiple_protocol_interfaces: usize, + + // CRC services + calculate_crc32: usize, + + // Misc services + copy_mem: unsafe extern "efiapi" fn(dest: *mut u8, src: *const u8, len: usize), + set_mem: unsafe extern "efiapi" fn(buffer: *mut u8, len: usize, value: u8), + + // New event functions (UEFI 2.0 or newer) + create_event_ex: unsafe extern "efiapi" fn( + ty: EventType, + notify_tpl: Tpl, + notify_fn: Option, + notify_ctx: Option>, + event_group: Option>, + out_event: *mut Event, + ) -> Status, +} + +impl BootServices { + /// Get the [`Handle`] of the currently-executing image. + pub fn image_handle(&self) -> Handle { + // Safety: + // + // `IMAGE_HANDLE` is only set by `set_image_handle`, see that + // documentation for more details. + // + // Additionally, `image_handle` takes a `&self` which ensures it + // can only be called while boot services are active. (After + // exiting boot services, the image handle should not be + // considered valid.) + unsafe { + IMAGE_HANDLE + .handle + .get() + .read() + .expect("set_image_handle has not been called") + } + } + + /// Update the global image [`Handle`]. + /// + /// This is called automatically in the `main` entry point as part + /// of [`uefi_macros::entry`]. It should not be called at any other + /// point in time, unless the executable does not use + /// [`uefi_macros::entry`], in which case it should be called once + /// before calling other `BootServices` functions. + /// + /// # Safety + /// + /// This function should only be called as described above. The + /// safety guarantees of [`BootServices::open_protocol_exclusive`] + /// rely on the global image handle being correct. + pub unsafe fn set_image_handle(&self, image_handle: Handle) { + // As with `image_handle`, `&self` isn't actually used, but it + // enforces that this function is only called while boot + // services are active. + IMAGE_HANDLE.handle.get().write(Some(image_handle)); + } + + /// Raises a task's priority level and returns its previous level. + /// + /// The effect of calling `raise_tpl` with a `Tpl` that is below the current + /// one (which, sadly, cannot be queried) is undefined by the UEFI spec, + /// which also warns against remaining at high `Tpl`s for a long time. + /// + /// This function outputs an RAII guard that will automatically restore the + /// original `Tpl` when dropped. + /// + /// # Safety + /// + /// Raising a task's priority level can affect other running tasks and + /// critical processes run by UEFI. The highest priority level is the + /// most dangerous, since it disables interrupts. + pub unsafe fn raise_tpl(&self, tpl: Tpl) -> TplGuard<'_> { + TplGuard { + boot_services: self, + old_tpl: (self.raise_tpl)(tpl), + } + } + + /// Allocates memory pages from the system. + /// + /// UEFI OS loaders should allocate memory of the type `LoaderData`. An `u64` + /// is returned even on 32-bit platforms because some hardware configurations + /// like Intel PAE enable 64-bit physical addressing on a 32-bit processor. + pub fn allocate_pages( + &self, + ty: AllocateType, + mem_ty: MemoryType, + count: usize, + ) -> Result { + let (ty, mut addr) = match ty { + AllocateType::AnyPages => (0, 0), + AllocateType::MaxAddress(addr) => (1, addr), + AllocateType::Address(addr) => (2, addr), + }; + (self.allocate_pages)(ty, mem_ty, count, &mut addr).into_with_val(|| addr) + } + + /// Frees memory pages allocated by UEFI. + pub fn free_pages(&self, addr: PhysicalAddress, count: usize) -> Result { + (self.free_pages)(addr, count).into() + } + + /// Returns struct which contains the size of a single memory descriptor + /// as well as the size of the current memory map. + /// + /// Note that the size of the memory map can increase any time an allocation happens, + /// so when creating a buffer to put the memory map into, it's recommended to allocate a few extra + /// elements worth of space above the size of the current memory map. + pub fn memory_map_size(&self) -> MemoryMapSize { + let mut map_size = 0; + let mut map_key = MemoryMapKey(0); + let mut entry_size = 0; + let mut entry_version = 0; + + let status = unsafe { + (self.get_memory_map)( + &mut map_size, + ptr::null_mut(), + &mut map_key, + &mut entry_size, + &mut entry_version, + ) + }; + assert_eq!(status, Status::BUFFER_TOO_SMALL); + + MemoryMapSize { + entry_size, + map_size, + } + } + + /// Retrieves the current memory map. + /// + /// The allocated buffer should be big enough to contain the memory map, + /// and a way of estimating how big it should be is by calling `memory_map_size`. + /// + /// The buffer must be aligned like a `MemoryDescriptor`. + /// + /// The returned key is a unique identifier of the current configuration of memory. + /// Any allocations or such will change the memory map's key. + /// + /// If you want to store the resulting memory map without having to keep + /// the buffer around, you can use `.copied().collect()` on the iterator. + pub fn memory_map<'buf>( + &self, + buffer: &'buf mut [u8], + ) -> Result<( + MemoryMapKey, + impl ExactSizeIterator + Clone, + )> { + let mut map_size = buffer.len(); + MemoryDescriptor::assert_aligned(buffer); + let map_buffer = buffer.as_mut_ptr().cast::(); + let mut map_key = MemoryMapKey(0); + let mut entry_size = 0; + let mut entry_version = 0; + + assert_eq!( + (map_buffer as usize) % mem::align_of::(), + 0, + "Memory map buffers must be aligned like a MemoryDescriptor" + ); + + unsafe { + (self.get_memory_map)( + &mut map_size, + map_buffer, + &mut map_key, + &mut entry_size, + &mut entry_version, + ) + } + .into_with_val(move || { + let len = map_size / entry_size; + let iter = MemoryMapIter { + buffer, + entry_size, + index: 0, + len, + }; + (map_key, iter) + }) + } + + /// Allocates from a memory pool. The pointer will be 8-byte aligned. + pub fn allocate_pool(&self, mem_ty: MemoryType, size: usize) -> Result<*mut u8> { + let mut buffer = ptr::null_mut(); + (self.allocate_pool)(mem_ty, size, &mut buffer).into_with_val(|| buffer) + } + + /// Frees memory allocated from a pool. + pub fn free_pool(&self, addr: *mut u8) -> Result { + (self.free_pool)(addr).into() + } + + /// Creates an event + /// + /// This function creates a new event of the specified type and returns it. + /// + /// Events are created in a "waiting" state, and may switch to a "signaled" + /// state. If the event type has flag `NotifySignal` set, this will result in + /// a callback for the event being immediately enqueued at the `notify_tpl` + /// priority level. If the event type has flag `NotifyWait`, the notification + /// will be delivered next time `wait_for_event` or `check_event` is called. + /// In both cases, a `notify_fn` callback must be specified. + /// + /// # Safety + /// + /// This function is unsafe because callbacks must handle exit from boot + /// services correctly. + pub unsafe fn create_event( + &self, + event_ty: EventType, + notify_tpl: Tpl, + notify_fn: Option, + notify_ctx: Option>, + ) -> Result { + // Prepare storage for the output Event + let mut event = MaybeUninit::::uninit(); + + // Now we're ready to call UEFI + (self.create_event)( + event_ty, + notify_tpl, + notify_fn, + notify_ctx, + event.as_mut_ptr(), + ) + .into_with_val(|| event.assume_init()) + } + + /// Creates a new `Event` of type `event_type`. The event's notification function, context, + /// and task priority are specified by `notify_fn`, `notify_ctx`, and `notify_tpl`, respectively. + /// The `Event` will be added to the group of `Event`s identified by `event_group`. + /// + /// If no group is specified by `event_group`, this function behaves as if the same parameters + /// had been passed to `create_event()`. + /// + /// Event groups are collections of events identified by a shared `Guid` where, when one member + /// event is signaled, all other events are signaled and their individual notification actions + /// are taken. All events are guaranteed to be signaled before the first notification action is + /// taken. All notification functions will be executed in the order specified by their `Tpl`. + /// + /// A single event can only be part of a single event group. An event may be removed from an + /// event group by using `close_event()`. + /// + /// The `EventType` of an event uses the same values as `create_event()`, except that + /// `EventType::SIGNAL_EXIT_BOOT_SERVICES` and `EventType::SIGNAL_VIRTUAL_ADDRESS_CHANGE` + /// are not valid. + /// + /// If `event_type` has `EventType::NOTIFY_SIGNAL` or `EventType::NOTIFY_WAIT`, then `notify_fn` + /// mus be `Some` and `notify_tpl` must be a valid task priority level, otherwise these parameters + /// are ignored. + /// + /// More than one event of type `EventType::TIMER` may be part of a single event group. However, + /// there is no mechanism for determining which of the timers was signaled. + /// + /// This operation is only supported starting with UEFI 2.0; earlier + /// versions will fail with [`Status::UNSUPPORTED`]. + /// + /// # Safety + /// + /// The caller must ensure they are passing a valid `Guid` as `event_group`, if applicable. + pub unsafe fn create_event_ex( + &self, + event_type: EventType, + notify_tpl: Tpl, + notify_fn: Option, + notify_ctx: Option>, + event_group: Option>, + ) -> Result { + if self.header.revision < Revision::EFI_2_00 { + return Err(Status::UNSUPPORTED.into()); + } + + let mut event = MaybeUninit::::uninit(); + + (self.create_event_ex)( + event_type, + notify_tpl, + notify_fn, + notify_ctx, + event_group, + event.as_mut_ptr(), + ) + .into_with_val(|| event.assume_init()) + } + + /// Sets the trigger for `EventType::TIMER` event. + pub fn set_timer(&self, event: &Event, trigger_time: TimerTrigger) -> Result { + let (ty, time) = match trigger_time { + TimerTrigger::Cancel => (0, 0), + TimerTrigger::Periodic(hundreds_ns) => (1, hundreds_ns), + TimerTrigger::Relative(hundreds_ns) => (2, hundreds_ns), + }; + unsafe { (self.set_timer)(event.unsafe_clone(), ty, time) }.into() + } + + /// Stops execution until an event is signaled. + /// + /// This function must be called at priority level `Tpl::APPLICATION`. If an + /// attempt is made to call it at any other priority level, an `Unsupported` + /// error is returned. + /// + /// The input `Event` slice is repeatedly iterated from first to last until + /// an event is signaled or an error is detected. The following checks are + /// performed on each event: + /// + /// * If an event is of type `NotifySignal`, then an `InvalidParameter` + /// error is returned with the index of the eve,t that caused the failure. + /// * If an event is in the signaled state, the signaled state is cleared + /// and the index of the event that was signaled is returned. + /// * If an event is not in the signaled state but does have a notification + /// function, the notification function is queued at the event's + /// notification task priority level. If the execution of the event's + /// notification function causes the event to be signaled, then the + /// signaled state is cleared and the index of the event that was signaled + /// is returned. + /// + /// To wait for a specified time, a timer event must be included in the + /// Event slice. + /// + /// To check if an event is signaled without waiting, an already signaled + /// event can be used as the last event in the slice being checked, or the + /// check_event() interface may be used. + pub fn wait_for_event(&self, events: &mut [Event]) -> Result> { + let (number_of_events, events) = (events.len(), events.as_mut_ptr()); + let mut index = MaybeUninit::::uninit(); + unsafe { (self.wait_for_event)(number_of_events, events, index.as_mut_ptr()) }.into_with( + || unsafe { index.assume_init() }, + |s| { + if s == Status::INVALID_PARAMETER { + unsafe { Some(index.assume_init()) } + } else { + None + } + }, + ) + } + + /// Place 'event' in the signaled stated. If 'event' is already in the signaled state, + /// then nothing further occurs and `Status::SUCCESS` is returned. If `event` is of type + /// `EventType::NOTIFY_SIGNAL`, then the event's notification function is scheduled to + /// be invoked at the event's notification task priority level. + /// + /// This function may be invoked from any task priority level. + /// + /// If `event` is part of an event group, then all of the events in the event group are + /// also signaled and their notification functions are scheduled. + /// + /// When signaling an event group, it is possible to create an event in the group, signal + /// it, and then close the event to remove it from the group. + pub fn signal_event(&self, event: &Event) -> Result { + // Safety: cloning this event should be safe, as we're directly passing it to firmware + // and not keeping the clone around. + unsafe { (self.signal_event)(event.unsafe_clone()).into() } + } + + /// Removes `event` from any event group to which it belongs and closes it. If `event` was + /// registered with `register_protocol_notify()`, then the corresponding registration will + /// be removed. It is safe to call this function within the corresponding notify function. + /// + /// + /// Note: The UEFI Specification v2.9 states that this may only return `EFI_SUCCESS`, but, + /// at least for application based on EDK2 (such as OVMF), it may also return `EFI_INVALID_PARAMETER`. + pub fn close_event(&self, event: Event) -> Result { + unsafe { (self.close_event)(event).into() } + } + + /// Checks to see if an event is signaled, without blocking execution to wait for it. + /// + /// The returned value will be `true` if the event is in the signaled state, + /// otherwise `false` is returned. + pub fn check_event(&self, event: Event) -> Result { + let status = unsafe { (self.check_event)(event) }; + match status { + Status::SUCCESS => Ok(true), + Status::NOT_READY => Ok(false), + _ => Err(status.into()), + } + } + + /// Query a handle for a certain protocol. + /// + /// This function attempts to get the protocol implementation of a handle, + /// based on the protocol GUID. + /// + /// It is recommended that all new drivers and applications use + /// [`open_protocol_exclusive`] or [`open_protocol`] instead of `handle_protocol`. + /// + /// UEFI protocols are neither thread-safe nor reentrant, but the firmware + /// provides no mechanism to protect against concurrent usage. Such + /// protections must be implemented by user-level code, for example via a + /// global `HashSet`. + /// + /// # Safety + /// + /// This method is unsafe because the handle database is not + /// notified that the handle and protocol are in use; there is no + /// guarantee that they will remain valid for the duration of their + /// use. Use [`open_protocol_exclusive`] if possible, otherwise use + /// [`open_protocol`]. + /// + /// [`open_protocol`]: BootServices::open_protocol + /// [`open_protocol_exclusive`]: BootServices::open_protocol_exclusive + #[deprecated( + note = "it is recommended to use `open_protocol_exclusive` or `open_protocol` instead" + )] + pub unsafe fn handle_protocol( + &self, + handle: Handle, + ) -> Result<&UnsafeCell

> { + let mut ptr = ptr::null_mut(); + (self.handle_protocol)(handle, &P::GUID, &mut ptr).into_with_val(|| { + let ptr = P::mut_ptr_from_ffi(ptr) as *const UnsafeCell

; + &*ptr + }) + } + + /// Enumerates all handles installed on the system which match a certain query. + /// + /// You should first call this function with `None` for the output buffer, + /// in order to retrieve the length of the buffer you need to allocate. + /// + /// The next call will fill the buffer with the requested data. + pub fn locate_handle( + &self, + search_ty: SearchType, + output: Option<&mut [MaybeUninit]>, + ) -> Result { + let handle_size = mem::size_of::(); + + const NULL_BUFFER: *mut MaybeUninit = ptr::null_mut(); + + let (mut buffer_size, buffer) = match output { + Some(buffer) => (buffer.len() * handle_size, buffer.as_mut_ptr()), + None => (0, NULL_BUFFER), + }; + + // Obtain the needed data from the parameters. + let (ty, guid, key) = match search_ty { + SearchType::AllHandles => (0, ptr::null(), ptr::null_mut()), + SearchType::ByProtocol(guid) => (2, guid as *const _, ptr::null_mut()), + }; + + let status = unsafe { (self.locate_handle)(ty, guid, key, &mut buffer_size, buffer) }; + + // Must convert the returned size (in bytes) to length (number of elements). + let buffer_len = buffer_size / handle_size; + + match (buffer, status) { + (NULL_BUFFER, Status::BUFFER_TOO_SMALL) => Ok(buffer_len), + (_, other_status) => other_status.into_with_val(|| buffer_len), + } + } + + /// Locates the handle to a device on the device path that supports the specified protocol. + /// + /// The `device_path` is updated to point at the remaining part of the [`DevicePath`] after + /// the part that matched the protocol. For example, it can be used with a device path + /// that contains a file path to strip off the file system portion of the device path, + /// leaving the file path and handle to the file system driver needed to access the file. + /// + /// If the first node of `device_path` matches the + /// protocol, the `device_path` is advanced to the device path terminator node. If `device_path` + /// is a multi-instance device path, the function will operate on the first instance. + pub fn locate_device_path(&self, device_path: &mut &DevicePath) -> Result { + let mut handle = MaybeUninit::uninit(); + let mut device_path_ptr = device_path.as_ffi_ptr(); + unsafe { + (self.locate_device_path)(&P::GUID, &mut device_path_ptr, &mut handle).into_with_val( + || { + *device_path = DevicePath::from_ffi_ptr(device_path_ptr); + handle.assume_init() + }, + ) + } + } + + /// Find an arbitrary handle that supports a particular + /// [`Protocol`]. Returns [`NOT_FOUND`] if no handles support the + /// protocol. + /// + /// This method is a convenient wrapper around + /// [`BootServices::locate_handle_buffer`] for getting just one + /// handle. This is useful when you don't care which handle the + /// protocol is opened on. For example, [`DevicePathToText`] isn't + /// tied to a particular device, so only a single handle is expected + /// to exist. + /// + /// [`NOT_FOUND`]: Status::NOT_FOUND + /// [`DevicePathToText`]: uefi::proto::device_path::text::DevicePathToText + /// + /// # Example + /// + /// ``` + /// use uefi::proto::device_path::text::DevicePathToText; + /// use uefi::table::boot::{BootServices, OpenProtocolAttributes, OpenProtocolParams}; + /// use uefi::Handle; + /// # use uefi::Result; + /// + /// # fn get_fake_val() -> T { todo!() } + /// # fn test() -> Result { + /// # let boot_services: &BootServices = get_fake_val(); + /// # let image_handle: Handle = get_fake_val(); + /// let handle = boot_services.get_handle_for_protocol::()?; + /// let device_path_to_text = boot_services.open_protocol_exclusive::(handle)?; + /// # Ok(()) + /// # } + /// ``` + pub fn get_handle_for_protocol(&self) -> Result { + // Delegate to a non-generic function to potentially reduce code size. + self.get_handle_for_protocol_impl(&P::GUID) + } + + fn get_handle_for_protocol_impl(&self, guid: &Guid) -> Result { + self.locate_handle_buffer(SearchType::ByProtocol(guid))? + .handles() + .first() + .cloned() + .ok_or_else(|| Status::NOT_FOUND.into()) + } + + /// Load an EFI image into memory and return a [`Handle`] to the image. + /// + /// There are two ways to load the image: by copying raw image data + /// from a source buffer, or by loading the image via the + /// [`SimpleFileSystem`] protocol. See [`LoadImageSource`] for more + /// details of the `source` parameter. + /// + /// The `parent_image_handle` is used to initialize the + /// `parent_handle` field of the [`LoadedImage`] protocol for the + /// image. + /// + /// If the image is successfully loaded, a [`Handle`] supporting the + /// [`LoadedImage`] and `LoadedImageDevicePath` protocols is + /// returned. The image can be started with [`start_image`] or + /// unloaded with [`unload_image`]. + /// + /// [`start_image`]: BootServices::start_image + /// [`unload_image`]: BootServices::unload_image + pub fn load_image( + &self, + parent_image_handle: Handle, + source: LoadImageSource, + ) -> uefi::Result { + let boot_policy; + let device_path; + let source_buffer; + let source_size; + match source { + LoadImageSource::FromBuffer { buffer, file_path } => { + // Boot policy is ignored when loading from source buffer. + boot_policy = 0; + + device_path = file_path.map(|p| p.as_ffi_ptr()).unwrap_or(ptr::null()); + source_buffer = buffer.as_ptr(); + source_size = buffer.len(); + } + LoadImageSource::FromFilePath { + file_path, + from_boot_manager, + } => { + boot_policy = u8::from(from_boot_manager); + device_path = file_path.as_ffi_ptr(); + source_buffer = ptr::null(); + source_size = 0; + } + }; + + let mut image_handle = MaybeUninit::uninit(); + unsafe { + (self.load_image)( + boot_policy, + parent_image_handle, + device_path, + source_buffer, + source_size, + &mut image_handle, + ) + .into_with_val(|| image_handle.assume_init()) + } + } + + /// Unload an EFI image. + pub fn unload_image(&self, image_handle: Handle) -> Result { + (self.unload_image)(image_handle).into() + } + + /// Transfer control to a loaded image's entry point. + pub fn start_image(&self, image_handle: Handle) -> Result { + unsafe { + // TODO: implement returning exit data to the caller. + let mut exit_data_size: usize = 0; + let mut exit_data: *mut Char16 = ptr::null_mut(); + (self.start_image)(image_handle, &mut exit_data_size, &mut exit_data).into() + } + } + + /// Exits the UEFI application and returns control to the UEFI component + /// that started the UEFI application. + /// + /// # Safety + /// + /// This function is unsafe because it is up to the caller to ensure that + /// all resources allocated by the application is freed before invoking + /// exit and returning control to the UEFI component that started the UEFI + /// application. + pub unsafe fn exit( + &self, + image_handle: Handle, + exit_status: Status, + exit_data_size: usize, + exit_data: *mut Char16, + ) -> ! { + (self.exit)(image_handle, exit_status, exit_data_size, exit_data) + } + + /// Exits the UEFI boot services + /// + /// This unsafe method is meant to be an implementation detail of the safe + /// `SystemTable::exit_boot_services()` method, which is why it is not + /// public. + /// + /// Everything that is explained in the documentation of the high-level + /// `SystemTable` method is also true here, except that this function + /// is one-shot (no automatic retry) and does not prevent you from shooting + /// yourself in the foot by calling invalid boot services after a failure. + pub(super) unsafe fn exit_boot_services( + &self, + image: Handle, + mmap_key: MemoryMapKey, + ) -> Result { + (self.exit_boot_services)(image, mmap_key).into() + } + + /// Stalls the processor for an amount of time. + /// + /// The time is in microseconds. + pub fn stall(&self, time: usize) { + assert_eq!((self.stall)(time), Status::SUCCESS); + } + + /// Set the watchdog timer. + /// + /// UEFI will start a 5-minute countdown after an UEFI image is loaded. + /// The image must either successfully load an OS and call `ExitBootServices` + /// in that time, or disable the watchdog. + /// + /// Otherwise, the firmware will log the event using the provided numeric + /// code and data, then reset the system. + /// + /// This function allows you to change the watchdog timer's timeout to a + /// certain amount of seconds or to disable the watchdog entirely. It also + /// allows you to change what will be logged when the timer expires. + /// + /// The watchdog codes from 0 to 0xffff (65535) are reserved for internal + /// firmware use. Higher values can be used freely by applications. + /// + /// If provided, the watchdog data must be a null-terminated string + /// optionally followed by other binary data. + pub fn set_watchdog_timer( + &self, + timeout: usize, + watchdog_code: u64, + data: Option<&mut [u16]>, + ) -> Result { + assert!( + watchdog_code > 0xffff, + "Invalid use of a reserved firmware watchdog code" + ); + + let (data_len, data) = data + .map(|d| { + assert!( + d.contains(&0), + "Watchdog data must start with a null-terminated string" + ); + (d.len(), d.as_mut_ptr()) + }) + .unwrap_or((0, ptr::null_mut())); + + unsafe { (self.set_watchdog_timer)(timeout, watchdog_code, data_len, data) }.into() + } + + /// Connect one or more drivers to a controller. + /// + /// Usually one disconnects and then reconnects certain drivers + /// to make them rescan some state that changed, e.g. reconnecting + /// a `BlockIO` handle after your app changed the partitions somehow. + pub fn connect_controller( + &self, + controller: Handle, + driver_image: Option, + remaining_device_path: Option<&DevicePath>, + recursive: bool, + ) -> Result { + unsafe { + (self.connect_controller)( + controller, + driver_image, + remaining_device_path + .map(|dp| dp.as_ffi_ptr()) + .unwrap_or(ptr::null()), + recursive, + ) + } + .into_with_err(|_| ()) + } + + /// Disconnect one or more drivers from a controller. + /// + /// See [`connect_controller`][Self::connect_controller]. + pub fn disconnect_controller( + &self, + controller: Handle, + driver_image: Option, + child: Option, + ) -> Result { + unsafe { (self.disconnect_controller)(controller, driver_image, child) } + .into_with_err(|_| ()) + } + + /// Open a protocol interface for a handle. + /// + /// See also [`open_protocol_exclusive`], which provides a safe + /// subset of this functionality. + /// + /// This function attempts to get the protocol implementation of a + /// handle, based on the protocol GUID. It is an extended version of + /// [`handle_protocol`]. It is recommended that all + /// new drivers and applications use `open_protocol_exclusive` or + /// `open_protocol` instead of `handle_protocol`. + /// + /// See [`OpenProtocolParams`] and [`OpenProtocolAttributes`] for + /// details of the input parameters. + /// + /// If successful, a [`ScopedProtocol`] is returned that will + /// automatically close the protocol interface when dropped. + /// + /// UEFI protocols are neither thread-safe nor reentrant, but the firmware + /// provides no mechanism to protect against concurrent usage. Such + /// protections must be implemented by user-level code, for example via a + /// global `HashSet`. + /// + /// # Safety + /// + /// This function is unsafe because it can be used to open a + /// protocol in ways that don't get tracked by the UEFI + /// implementation. This could allow the protocol to be removed from + /// a handle, or for the handle to be deleted entirely, while a + /// reference to the protocol is still active. The caller is + /// responsible for ensuring that the handle and protocol remain + /// valid until the `ScopedProtocol` is dropped. + /// + /// [`handle_protocol`]: BootServices::handle_protocol + /// [`open_protocol_exclusive`]: BootServices::open_protocol_exclusive + pub unsafe fn open_protocol( + &self, + params: OpenProtocolParams, + attributes: OpenProtocolAttributes, + ) -> Result> { + let mut interface = ptr::null_mut(); + (self.open_protocol)( + params.handle, + &P::GUID, + &mut interface, + params.agent, + params.controller, + attributes as u32, + ) + .into_with_val(|| { + let interface = P::mut_ptr_from_ffi(interface) as *const UnsafeCell

; + + #[allow(deprecated)] + ScopedProtocol { + interface: &*interface, + open_params: params, + boot_services: self, + } + }) + } + + /// Open a protocol interface for a handle in exclusive mode. + /// + /// If successful, a [`ScopedProtocol`] is returned that will + /// automatically close the protocol interface when dropped. + /// + /// [`handle_protocol`]: BootServices::handle_protocol + pub fn open_protocol_exclusive( + &self, + handle: Handle, + ) -> Result> { + // Safety: opening in exclusive mode with the correct agent + // handle set ensures that the protocol cannot be modified or + // removed while it is open, so this usage is safe. + unsafe { + self.open_protocol::

( + OpenProtocolParams { + handle, + agent: self.image_handle(), + controller: None, + }, + OpenProtocolAttributes::Exclusive, + ) + } + } + + /// Test whether a handle supports a protocol. + pub fn test_protocol(&self, params: OpenProtocolParams) -> Result<()> { + const TEST_PROTOCOL: u32 = 0x04; + let mut interface = ptr::null_mut(); + (self.open_protocol)( + params.handle, + &P::GUID, + &mut interface, + params.agent, + params.controller, + TEST_PROTOCOL, + ) + .into_with_val(|| ()) + } + + /// Get the list of protocol interface [`Guids`][Guid] that are installed + /// on a [`Handle`]. + pub fn protocols_per_handle(&self, handle: Handle) -> Result { + let mut protocols = ptr::null_mut(); + let mut count = 0; + + let mut status = unsafe { (self.protocols_per_handle)(handle, &mut protocols, &mut count) }; + + if !status.is_error() { + // Ensure that protocols isn't null, and that none of the GUIDs + // returned are null. + if protocols.is_null() { + status = Status::OUT_OF_RESOURCES; + } else { + let protocols: &[*const Guid] = unsafe { slice::from_raw_parts(protocols, count) }; + if protocols.iter().any(|ptr| ptr.is_null()) { + status = Status::OUT_OF_RESOURCES; + } + } + } + + status.into_with_val(|| ProtocolsPerHandle { + boot_services: self, + protocols: protocols.cast::<&Guid>(), + count, + }) + } + + /// Returns an array of handles that support the requested protocol in a buffer allocated from + /// pool. + pub fn locate_handle_buffer(&self, search_ty: SearchType) -> Result { + let mut num_handles: usize = 0; + let mut buffer: *mut Handle = ptr::null_mut(); + + // Obtain the needed data from the parameters. + let (ty, guid, key) = match search_ty { + SearchType::AllHandles => (0, ptr::null(), ptr::null_mut()), + SearchType::ByProtocol(guid) => (2, guid as *const _, ptr::null_mut()), + }; + + unsafe { (self.locate_handle_buffer)(ty, guid, key, &mut num_handles, &mut buffer) } + .into_with_val(|| HandleBuffer { + boot_services: self, + count: num_handles, + buffer, + }) + } + + /// Returns a protocol implementation, if present on the system. + /// + /// The caveats of `BootServices::handle_protocol()` also apply here. + /// + /// # Safety + /// + /// This method is unsafe because the handle database is not + /// notified that the handle and protocol are in use; there is no + /// guarantee that they will remain valid for the duration of their + /// use. Use [`get_handle_for_protocol`] and either + /// [`open_protocol_exclusive`] or [`open_protocol`] instead. + /// + /// [`get_handle_for_protocol`]: BootServices::get_handle_for_protocol + /// [`open_protocol`]: BootServices::open_protocol + /// [`open_protocol_exclusive`]: BootServices::open_protocol_exclusive + #[deprecated( + note = "it is recommended to use `open_protocol_exclusive` or `open_protocol` instead" + )] + pub unsafe fn locate_protocol(&self) -> Result<&UnsafeCell

> { + let mut ptr = ptr::null_mut(); + (self.locate_protocol)(&P::GUID, ptr::null_mut(), &mut ptr).into_with_val(|| { + let ptr = P::mut_ptr_from_ffi(ptr) as *const UnsafeCell

; + &*ptr + }) + } + + /// Copies memory from source to destination. The buffers can overlap. + /// + /// # Safety + /// + /// This function is unsafe as it can be used to violate most safety + /// invariants of the Rust type system. + pub unsafe fn memmove(&self, dest: *mut u8, src: *const u8, size: usize) { + (self.copy_mem)(dest, src, size); + } + + /// Sets a buffer to a certain value. + /// + /// # Safety + /// + /// This function is unsafe as it can be used to violate most safety + /// invariants of the Rust type system. + pub unsafe fn set_mem(&self, buffer: *mut u8, size: usize, value: u8) { + (self.set_mem)(buffer, size, value); + } +} + +#[cfg(feature = "exts")] +impl BootServices { + /// Returns all the handles implementing a certain protocol. + pub fn find_handles(&self) -> Result> { + // Search by protocol. + let search_type = SearchType::from_proto::

(); + + // Determine how much we need to allocate. + let buffer_size = self.locate_handle(search_type, None)?; + + // Allocate a large enough buffer without pointless initialization. + let mut handles = Vec::with_capacity(buffer_size); + let buffer = handles.spare_capacity_mut(); + + // Perform the search. + let buffer_size = self.locate_handle(search_type, Some(buffer))?; + + // Mark the returned number of elements as initialized. + unsafe { + handles.set_len(buffer_size); + } + + // Emit output, with warnings + Ok(handles) + } + + /// Retrieves the `SimpleFileSystem` protocol associated with + /// the device the given image was loaded from. + /// + /// You can retrieve the SFS protocol associated with the boot partition + /// by passing the image handle received by the UEFI entry point to this function. + pub fn get_image_file_system( + &self, + image_handle: Handle, + ) -> Result> { + let loaded_image = self.open_protocol_exclusive::(image_handle)?; + + let device_path = self.open_protocol_exclusive::(loaded_image.device())?; + + let device_handle = self.locate_device_path::(&mut &*device_path)?; + + self.open_protocol_exclusive(device_handle) + } +} + +impl super::Table for BootServices { + const SIGNATURE: u64 = 0x5652_4553_544f_4f42; +} + +impl Debug for BootServices { + fn fmt(&self, f: &mut Formatter<'_>) -> core::fmt::Result { + f.debug_struct("BootServices") + .field("header", &self.header) + .field("raise_tpl (fn ptr)", &(self.raise_tpl as *const usize)) + .field("restore_tpl (fn ptr)", &(self.restore_tpl as *const usize)) + .field( + "allocate_pages (fn ptr)", + &(self.allocate_pages as *const usize), + ) + .field("free_pages (fn ptr)", &(self.free_pages as *const usize)) + .field( + "get_memory_map (fn ptr)", + &(self.get_memory_map as *const usize), + ) + .field( + "allocate_pool (fn ptr)", + &(self.allocate_pool as *const usize), + ) + .field("free_pool (fn ptr)", &(self.free_pool as *const usize)) + .field( + "create_event (fn ptr)", + &(self.create_event as *const usize), + ) + .field("set_timer (fn ptr)", &(self.set_timer as *const usize)) + .field( + "wait_for_event (fn ptr)", + &(self.wait_for_event as *const usize), + ) + .field("signal_event", &(self.signal_event as *const usize)) + .field("close_event", &(self.close_event as *const usize)) + .field("check_event", &(self.check_event as *const usize)) + .field( + "install_protocol_interface", + &(self.install_protocol_interface as *const usize), + ) + .field( + "reinstall_protocol_interface", + &(self.reinstall_protocol_interface as *const usize), + ) + .field( + "uninstall_protocol_interface", + &(self.uninstall_protocol_interface as *const usize), + ) + .field( + "handle_protocol (fn ptr)", + &(self.handle_protocol as *const usize), + ) + .field( + "register_protocol_notify", + &(self.register_protocol_notify as *const usize), + ) + .field( + "locate_handle (fn ptr)", + &(self.locate_handle as *const usize), + ) + .field( + "locate_device_path (fn ptr)", + &(self.locate_device_path as *const usize), + ) + .field( + "install_configuration_table", + &(self.install_configuration_table as *const usize), + ) + .field("load_image (fn ptr)", &(self.load_image as *const usize)) + .field("start_image (fn ptr)", &(self.start_image as *const usize)) + .field("exit", &(self.exit as *const usize)) + .field( + "unload_image (fn ptr)", + &(self.unload_image as *const usize), + ) + .field( + "exit_boot_services (fn ptr)", + &(self.exit_boot_services as *const usize), + ) + .field( + "get_next_monotonic_count", + &(self.get_next_monotonic_count as *const usize), + ) + .field("stall (fn ptr)", &(self.stall as *const usize)) + .field( + "set_watchdog_timer (fn ptr)", + &(self.set_watchdog_timer as *const usize), + ) + .field( + "connect_controller", + &(self.connect_controller as *const usize), + ) + .field( + "disconnect_controller", + &(self.disconnect_controller as *const usize), + ) + .field("open_protocol", &(self.open_protocol as *const usize)) + .field("close_protocol", &(self.close_protocol as *const usize)) + .field( + "open_protocol_information", + &(self.open_protocol_information as *const usize), + ) + .field( + "protocols_per_handle", + &(self.protocols_per_handle as *const usize), + ) + .field( + "locate_handle_buffer", + &(self.locate_handle_buffer as *const usize), + ) + .field( + "locate_protocol (fn ptr)", + &(self.locate_protocol as *const usize), + ) + .field( + "install_multiple_protocol_interfaces", + &(self.install_multiple_protocol_interfaces as *const usize), + ) + .field( + "uninstall_multiple_protocol_interfaces", + &(self.uninstall_multiple_protocol_interfaces as *const usize), + ) + .field("calculate_crc32", &(self.calculate_crc32 as *const usize)) + .field("copy_mem (fn ptr)", &(self.copy_mem as *const usize)) + .field("set_mem (fn ptr)", &(self.set_mem as *const usize)) + .field("create_event_ex", &(self.create_event_ex as *const usize)) + .finish() + } +} + +/// Used as a parameter of [`BootServices::load_image`] to provide the +/// image source. +pub enum LoadImageSource<'a> { + /// Load an image from a buffer. The data will copied from the + /// buffer, so the input reference doesn't need to remain valid + /// after the image is loaded. + FromBuffer { + /// Raw image data. + buffer: &'a [u8], + + /// If set, this path will be added as the file path of the + /// loaded image. This is not required to load the image, but + /// may be used by the image itself to load other resources + /// relative to the image's path. + file_path: Option<&'a DevicePath>, + }, + + /// Load an image via the [`SimpleFileSystem`] protocol. If there is + /// no instance of that protocol associated with the path then the + /// behavior depends on `from_boot_manager`. If `true`, attempt to + /// load via the `LoadFile` protocol. If `false`, attempt to load + /// via the `LoadFile2` protocol, then fall back to `LoadFile`. + FromFilePath { + /// Device path from which to load the image. + file_path: &'a DevicePath, + + /// Whether the request originates from the boot manager. + from_boot_manager: bool, + }, +} + +newtype_enum! { +/// Task priority level. +/// +/// Although the UEFI specification repeatedly states that only the variants +/// specified below should be used in application-provided input, as the other +/// are reserved for internal firmware use, it might still happen that the +/// firmware accidentally discloses one of these internal TPLs to us. +/// +/// Since feeding an unexpected variant to a Rust enum is UB, this means that +/// this C enum must be interfaced via the newtype pattern. +pub enum Tpl: usize => { + /// Normal task execution level. + APPLICATION = 4, + /// Async interrupt-style callbacks run at this TPL. + CALLBACK = 8, + /// Notifications are masked at this level. + /// + /// This is used in critical sections of code. + NOTIFY = 16, + /// Highest priority level. + /// + /// Even processor interrupts are disable at this level. + HIGH_LEVEL = 31, +}} + +/// RAII guard for task priority level changes +/// +/// Will automatically restore the former task priority level when dropped. +pub struct TplGuard<'boot> { + boot_services: &'boot BootServices, + old_tpl: Tpl, +} + +impl Drop for TplGuard<'_> { + fn drop(&mut self) { + unsafe { + (self.boot_services.restore_tpl)(self.old_tpl); + } + } +} + +// OpenProtocolAttributes is safe to model as a regular enum because it +// is only used as an input. The attributes are bitflags, but all valid +// combinations are listed in the spec and only ByDriver and Exclusive +// can actually be combined. +// +// Some values intentionally excluded: +// +// ByHandleProtocol (0x01) excluded because it is only intended to be +// used in an implementation of `HandleProtocol`. +// +// TestProtocol (0x04) excluded because it doesn't actually open the +// protocol, just tests if it's present on the handle. Since that +// changes the interface significantly, that's exposed as a separate +// method: `BootServices::test_protocol`. + +/// Attributes for [`BootServices::open_protocol`]. +#[repr(u32)] +pub enum OpenProtocolAttributes { + /// Used by drivers to get a protocol interface for a handle. The + /// driver will not be informed if the interface is uninstalled or + /// reinstalled. + GetProtocol = 0x02, + + /// Used by bus drivers to show that a protocol is being used by one + /// of the child controllers of the bus. + ByChildController = 0x08, + + /// Used by a driver to gain access to a protocol interface. When + /// this mode is used, the driver's `Stop` function will be called + /// if the protocol interface is reinstalled or uninstalled. Once a + /// protocol interface is opened with this attribute, no other + /// drivers will be allowed to open the same protocol interface with + /// the `ByDriver` attribute. + ByDriver = 0x10, + + /// Used by a driver to gain exclusive access to a protocol + /// interface. If any other drivers have the protocol interface + /// opened with an attribute of `ByDriver`, then an attempt will be + /// made to remove them with `DisconnectController`. + ByDriverExclusive = 0x30, + + /// Used by applications to gain exclusive access to a protocol + /// interface. If any drivers have the protocol opened with an + /// attribute of `ByDriver`, then an attempt will be made to remove + /// them by calling the driver's `Stop` function. + Exclusive = 0x20, +} + +/// Parameters passed to [`BootServices::open_protocol`]. +pub struct OpenProtocolParams { + /// The handle for the protocol to open. + pub handle: Handle, + + /// The handle of the calling agent. For drivers, this is the handle + /// containing the `EFI_DRIVER_BINDING_PROTOCOL` instance. For + /// applications, this is the image handle. + pub agent: Handle, + + /// For drivers, this is the controller handle that requires the + /// protocol interface. For applications this should be set to + /// `None`. + pub controller: Option, +} + +/// An open protocol interface. Automatically closes the protocol +/// interface on drop. +/// +/// See also the [`BootServices`] documentation for details of how to open a +/// protocol and why [`UnsafeCell`] is used. +pub struct ScopedProtocol<'a, P: Protocol + ?Sized> { + /// The protocol interface. + #[deprecated(since = "0.17.0", note = "use Deref and DerefMut instead")] + pub interface: &'a UnsafeCell

, + + open_params: OpenProtocolParams, + boot_services: &'a BootServices, +} + +impl<'a, P: Protocol + ?Sized> Drop for ScopedProtocol<'a, P> { + fn drop(&mut self) { + let status = (self.boot_services.close_protocol)( + self.open_params.handle, + &P::GUID, + self.open_params.agent, + self.open_params.controller, + ); + // All of the error cases for close_protocol boil down to + // calling it with a different set of parameters than what was + // passed to open_protocol. The public API prevents such errors, + // and the error can't be propagated out of drop anyway, so just + // assert success. + assert_eq!(status, Status::SUCCESS); + } +} + +impl<'a, P: Protocol + ?Sized> Deref for ScopedProtocol<'a, P> { + type Target = P; + + fn deref(&self) -> &Self::Target { + #[allow(deprecated)] + unsafe { + &*self.interface.get() + } + } +} + +impl<'a, P: Protocol + ?Sized> DerefMut for ScopedProtocol<'a, P> { + fn deref_mut(&mut self) -> &mut Self::Target { + #[allow(deprecated)] + unsafe { + &mut *self.interface.get() + } + } +} + +/// Type of allocation to perform. +#[derive(Debug, Copy, Clone)] +pub enum AllocateType { + /// Allocate any possible pages. + AnyPages, + /// Allocate pages at any address below the given address. + MaxAddress(PhysicalAddress), + /// Allocate pages at the specified address. + Address(PhysicalAddress), +} + +newtype_enum! { +/// The type of a memory range. +/// +/// UEFI allows firmwares and operating systems to introduce new memory types +/// in the 0x70000000..0xFFFFFFFF range. Therefore, we don't know the full set +/// of memory types at compile time, and it is _not_ safe to model this C enum +/// as a Rust enum. +pub enum MemoryType: u32 => { + /// This enum variant is not used. + RESERVED = 0, + /// The code portions of a loaded UEFI application. + LOADER_CODE = 1, + /// The data portions of a loaded UEFI applications, + /// as well as any memory allocated by it. + LOADER_DATA = 2, + /// Code of the boot drivers. + /// + /// Can be reused after OS is loaded. + BOOT_SERVICES_CODE = 3, + /// Memory used to store boot drivers' data. + /// + /// Can be reused after OS is loaded. + BOOT_SERVICES_DATA = 4, + /// Runtime drivers' code. + RUNTIME_SERVICES_CODE = 5, + /// Runtime services' code. + RUNTIME_SERVICES_DATA = 6, + /// Free usable memory. + CONVENTIONAL = 7, + /// Memory in which errors have been detected. + UNUSABLE = 8, + /// Memory that holds ACPI tables. + /// Can be reclaimed after they are parsed. + ACPI_RECLAIM = 9, + /// Firmware-reserved addresses. + ACPI_NON_VOLATILE = 10, + /// A region used for memory-mapped I/O. + MMIO = 11, + /// Address space used for memory-mapped port I/O. + MMIO_PORT_SPACE = 12, + /// Address space which is part of the processor. + PAL_CODE = 13, + /// Memory region which is usable and is also non-volatile. + PERSISTENT_MEMORY = 14, +}} + +impl MemoryType { + /// Construct a custom `MemoryType`. Values in the range `0x80000000..=0xffffffff` are free for use if you are + /// an OS loader. + pub const fn custom(value: u32) -> MemoryType { + assert!(value >= 0x80000000); + MemoryType(value) + } +} + +/// Memory descriptor version number +pub const MEMORY_DESCRIPTOR_VERSION: u32 = 1; + +/// A structure describing a region of memory. +#[derive(Debug, Copy, Clone)] +#[repr(C)] +pub struct MemoryDescriptor { + /// Type of memory occupying this range. + pub ty: MemoryType, + /// Skip 4 bytes as UEFI declares items in structs should be naturally aligned + padding: u32, + /// Starting physical address. + pub phys_start: PhysicalAddress, + /// Starting virtual address. + pub virt_start: VirtualAddress, + /// Number of 4 KiB pages contained in this range. + pub page_count: u64, + /// The capability attributes of this memory range. + pub att: MemoryAttribute, +} + +impl Default for MemoryDescriptor { + fn default() -> MemoryDescriptor { + MemoryDescriptor { + ty: MemoryType::RESERVED, + padding: 0, + phys_start: 0, + virt_start: 0, + page_count: 0, + att: MemoryAttribute::empty(), + } + } +} + +impl Align for MemoryDescriptor { + fn alignment() -> usize { + mem::align_of::() + } +} + +bitflags! { + /// Flags describing the capabilities of a memory range. + pub struct MemoryAttribute: u64 { + /// Supports marking as uncacheable. + const UNCACHEABLE = 0x1; + /// Supports write-combining. + const WRITE_COMBINE = 0x2; + /// Supports write-through. + const WRITE_THROUGH = 0x4; + /// Support write-back. + const WRITE_BACK = 0x8; + /// Supports marking as uncacheable, exported and + /// supports the "fetch and add" semaphore mechanism. + const UNCACHABLE_EXPORTED = 0x10; + /// Supports write-protection. + const WRITE_PROTECT = 0x1000; + /// Supports read-protection. + const READ_PROTECT = 0x2000; + /// Supports disabling code execution. + const EXECUTE_PROTECT = 0x4000; + /// Persistent memory. + const NON_VOLATILE = 0x8000; + /// This memory region is more reliable than other memory. + const MORE_RELIABLE = 0x10000; + /// This memory range can be set as read-only. + const READ_ONLY = 0x20000; + /// This memory must be mapped by the OS when a runtime service is called. + const RUNTIME = 0x8000_0000_0000_0000; + } +} + +/// A unique identifier of a memory map. +/// +/// If the memory map changes, this value is no longer valid. +#[derive(Debug, Copy, Clone, Eq, PartialEq)] +#[repr(C)] +pub struct MemoryMapKey(usize); + +/// A structure containing the size of a memory descriptor and the size of the memory map +pub struct MemoryMapSize { + /// Size of a single memory descriptor in bytes + pub entry_size: usize, + /// Size of the entire memory map in bytes + pub map_size: usize, +} + +/// An iterator of memory descriptors +#[derive(Debug, Clone)] +struct MemoryMapIter<'buf> { + buffer: &'buf [u8], + entry_size: usize, + index: usize, + len: usize, +} + +impl<'buf> Iterator for MemoryMapIter<'buf> { + type Item = &'buf MemoryDescriptor; + + fn size_hint(&self) -> (usize, Option) { + let sz = self.len - self.index; + + (sz, Some(sz)) + } + + fn next(&mut self) -> Option { + if self.index < self.len { + let ptr = self.buffer.as_ptr() as usize + self.entry_size * self.index; + + self.index += 1; + + let descriptor = unsafe { &*(ptr as *const MemoryDescriptor) }; + + Some(descriptor) + } else { + None + } + } +} + +impl ExactSizeIterator for MemoryMapIter<'_> {} + +/// The type of handle search to perform. +#[derive(Debug, Copy, Clone)] +pub enum SearchType<'guid> { + /// Return all handles present on the system. + AllHandles, + /// Returns all handles supporting a certain protocol, specified by its GUID. + /// + /// If the protocol implements the `Protocol` interface, + /// you can use the `from_proto` function to construct a new `SearchType`. + ByProtocol(&'guid Guid), + // TODO: add ByRegisterNotify once the corresponding function is implemented. +} + +impl<'guid> SearchType<'guid> { + /// Constructs a new search type for a specified protocol. + pub fn from_proto() -> Self { + SearchType::ByProtocol(&P::GUID) + } +} + +bitflags! { + /// Flags describing the type of an UEFI event and its attributes. + pub struct EventType: u32 { + /// The event is a timer event and may be passed to `BootServices::set_timer()` + /// Note that timers only function during boot services time. + const TIMER = 0x8000_0000; + + /// The event is allocated from runtime memory. + /// This must be done if the event is to be signaled after ExitBootServices. + const RUNTIME = 0x4000_0000; + + /// Calling wait_for_event or check_event will enqueue the notification + /// function if the event is not already in the signaled state. + /// Mutually exclusive with `NOTIFY_SIGNAL`. + const NOTIFY_WAIT = 0x0000_0100; + + /// The notification function will be enqueued when the event is signaled + /// Mutually exclusive with `NOTIFY_WAIT`. + const NOTIFY_SIGNAL = 0x0000_0200; + + /// The event will be signaled at ExitBootServices time. + /// This event type should not be combined with any other. + /// Its notification function must follow some special rules: + /// - Cannot use memory allocation services, directly or indirectly + /// - Cannot depend on timer events, since those will be deactivated + const SIGNAL_EXIT_BOOT_SERVICES = 0x0000_0201; + + /// The event will be notified when SetVirtualAddressMap is performed. + /// This event type should not be combined with any other. + const SIGNAL_VIRTUAL_ADDRESS_CHANGE = 0x6000_0202; + } +} + +/// Raw event notification function +type EventNotifyFn = unsafe extern "efiapi" fn(event: Event, context: Option>); + +/// Timer events manipulation +pub enum TimerTrigger { + /// Cancel event's timer + Cancel, + /// The event is to be signaled periodically. + /// Parameter is the period in 100ns units. + /// Delay of 0 will be signalled on every timer tick. + Periodic(u64), + /// The event is to be signaled once in 100ns units. + /// Parameter is the delay in 100ns units. + /// Delay of 0 will be signalled on next timer tick. + Relative(u64), +} + +/// Protocol interface [`Guids`][Guid] that are installed on a [`Handle`] as +/// returned by [`BootServices::protocols_per_handle`]. +pub struct ProtocolsPerHandle<'a> { + // The pointer returned by `protocols_per_handle` has to be free'd with + // `free_pool`, so keep a reference to boot services for that purpose. + boot_services: &'a BootServices, + + protocols: *mut &'a Guid, + count: usize, +} + +impl<'a> Drop for ProtocolsPerHandle<'a> { + fn drop(&mut self) { + // Ignore the result, we can't do anything about an error here. + let _ = self.boot_services.free_pool(self.protocols.cast::()); + } +} + +impl<'a> ProtocolsPerHandle<'a> { + /// Get the protocol interface [`Guids`][Guid] that are installed on the + /// [`Handle`]. + pub fn protocols<'b>(&'b self) -> &'b [&'a Guid] { + // convert raw pointer to slice here so that we can get + // appropriate lifetime of the slice. + unsafe { slice::from_raw_parts(self.protocols, self.count) } + } +} + +/// A buffer that contains an array of [`Handles`][Handle] that support the requested protocol. +/// Returned by [`BootServices::locate_handle_buffer`]. +pub struct HandleBuffer<'a> { + // The pointer returned by `locate_handle_buffer` has to be free'd with + // `free_pool`, so keep a reference to boot services for that purpose. + boot_services: &'a BootServices, + count: usize, + buffer: *mut Handle, +} + +impl<'a> Drop for HandleBuffer<'a> { + fn drop(&mut self) { + // Ignore the result, we can't do anything about an error here. + let _ = self.boot_services.free_pool(self.buffer.cast::()); + } +} + +impl<'a> HandleBuffer<'a> { + /// Get an array of [`Handles`][Handle] that support the requested protocol. + pub fn handles(&self) -> &[Handle] { + // convert raw pointer to slice here so that we can get + // appropriate lifetime of the slice. + unsafe { slice::from_raw_parts(self.buffer, self.count) } + } +} diff --git a/src/table/cfg.rs b/src/table/cfg.rs new file mode 100644 index 000000000..1c5aa106b --- /dev/null +++ b/src/table/cfg.rs @@ -0,0 +1,100 @@ +//! Configuration table utilities. +//! +//! The configuration table is an array of GUIDs and pointers to extra system tables. +//! +//! For example, it can be used to find the ACPI tables. +//! +//! This module contains the actual entries of the configuration table, +//! as well as GUIDs for many known vendor tables. + +use crate::Guid; +use bitflags::bitflags; +use core::ffi::c_void; + +/// Contains a set of GUID / pointer for a vendor-specific table. +/// +/// The UEFI standard guarantees each entry is unique. +#[derive(Debug)] +#[repr(C)] +pub struct ConfigTableEntry { + /// The GUID identifying this table. + pub guid: Guid, + /// The starting address of this table. + /// + /// Whether this is a physical or virtual address depends on the table. + pub address: *const c_void, +} +/// Entry pointing to the old ACPI 1 RSDP. +pub const ACPI_GUID: Guid = Guid::from_values(0xeb9d2d30, 0x2d88, 0x11d3, 0x9a16, 0x0090273fc14d); + +///Entry pointing to the ACPI 2 RSDP. +pub const ACPI2_GUID: Guid = Guid::from_values(0x8868e871, 0xe4f1, 0x11d3, 0xbc22, 0x0080c73c8881); + +/// Entry pointing to the SMBIOS 1.0 table. +pub const SMBIOS_GUID: Guid = Guid::from_values(0xeb9d2d31, 0x2d88, 0x11d3, 0x9a16, 0x0090273fc14d); + +/// Entry pointing to the SMBIOS 3.0 table. +pub const SMBIOS3_GUID: Guid = + Guid::from_values(0xf2fd1544, 0x9794, 0x4a2c, 0x992e, 0xe5bbcf20e394); + +/// GUID of the UEFI properties table. +/// +/// The properties table is used to provide additional info +/// about the UEFI implementation. +pub const PROPERTIES_TABLE_GUID: Guid = + Guid::from_values(0x880aaca3, 0x4adc, 0x4a04, 0x9079, 0xb747340825e5); + +/// This table contains additional information about the UEFI implementation. +#[repr(C)] +pub struct PropertiesTable { + /// Version of the UEFI properties table. + /// + /// The only valid version currently is 0x10_000. + pub version: u32, + /// Length in bytes of this table. + /// + /// The initial version's length is 16. + pub length: u32, + /// Memory protection attributes. + pub memory_protection: MemoryProtectionAttribute, +} + +bitflags! { + /// Flags describing memory protection. + pub struct MemoryProtectionAttribute: usize { + /// If this bit is set, then the UEFI implementation will mark pages + /// containing data as non-executable. + const NON_EXECUTABLE_DATA = 1; + } +} + +/// Hand-off Blocks are used to pass data from the early pre-UEFI environment to the UEFI drivers. +/// +/// Most OS loaders or applications should not mess with this. +pub const HAND_OFF_BLOCK_LIST_GUID: Guid = + Guid::from_values(0x7739f24c, 0x93d7, 0x11d4, 0x9a3a, 0x0090273fc14d); + +/// Table used in the early boot environment to record memory ranges. +pub const MEMORY_TYPE_INFORMATION_GUID: Guid = + Guid::from_values(0x4c19049f, 0x4137, 0x4dd3, 0x9c10, 0x8b97a83ffdfa); + +/// Used to identify Hand-off Blocks which store +/// status codes reported during the pre-UEFI environment. +pub const MEMORY_STATUS_CODE_RECORD_GUID: Guid = + Guid::from_values(0x60cc026, 0x4c0d, 0x4dda, 0x8f41, 0x595fef00a502); + +/// Table which provides Driver eXecution Environment services. +pub const DXE_SERVICES_GUID: Guid = + Guid::from_values(0x5ad34ba, 0x6f02, 0x4214, 0x952e, 0x4da0398e2bb9); + +/// LZMA-compressed filesystem. +pub const LZMA_COMPRESS_GUID: Guid = + Guid::from_values(0xee4e5898, 0x3914, 0x4259, 0x9d6e, 0xdc7bd79403cf); + +/// A custom compressed filesystem used by the Tiano UEFI implementation. +pub const TIANO_COMPRESS_GUID: Guid = + Guid::from_values(0xa31280ad, 0x481e, 0x41b6, 0x95e8, 0x127f4c984779); + +/// Pointer to the debug image info table. +pub const DEBUG_IMAGE_INFO_GUID: Guid = + Guid::from_values(0x49152e77, 0x1ada, 0x4764, 0xb7a2, 0x7afefed95e8b); diff --git a/src/table/header.rs b/src/table/header.rs new file mode 100644 index 000000000..af449fe4d --- /dev/null +++ b/src/table/header.rs @@ -0,0 +1,18 @@ +use super::Revision; + +/// All standard UEFI tables begin with a common header. +#[derive(Debug)] +#[repr(C)] +pub struct Header { + /// Unique identifier for this table. + pub signature: u64, + /// Revision of the spec this table conforms to. + pub revision: Revision, + /// The size in bytes of the entire table. + pub size: u32, + /// 32-bit CRC-32-Castagnoli of the entire table, + /// calculated with this field set to 0. + pub crc: u32, + /// Reserved field that must be set to 0. + _reserved: u32, +} diff --git a/src/table/mod.rs b/src/table/mod.rs new file mode 100644 index 000000000..81b5c0007 --- /dev/null +++ b/src/table/mod.rs @@ -0,0 +1,22 @@ +//! Standard UEFI tables. + +/// Common trait implemented by all standard UEFI tables. +pub trait Table { + /// A unique number assigned by the UEFI specification + /// to the standard tables. + const SIGNATURE: u64; +} + +mod header; +pub use self::header::Header; + +mod revision; +pub use self::revision::Revision; + +mod system; +pub use self::system::{Boot, Runtime, SystemTable}; + +pub mod boot; +pub mod runtime; + +pub mod cfg; diff --git a/src/table/revision.rs b/src/table/revision.rs new file mode 100644 index 000000000..c79810936 --- /dev/null +++ b/src/table/revision.rs @@ -0,0 +1,72 @@ +use core::fmt; + +/// A revision of the UEFI specification. +/// +/// The major revision number is incremented on major, API-incompatible changes. +/// +/// The minor revision number is incremented on minor changes, +/// it is stored as a two-digit binary-coded decimal. +#[derive(Copy, Clone, Eq, PartialEq, Ord, PartialOrd)] +pub struct Revision(u32); + +// Allow missing docs, there's nothing useful to document about these +// constants. +#[allow(missing_docs)] +impl Revision { + pub const EFI_1_02: Self = Self::new(1, 2); + pub const EFI_1_10: Self = Self::new(1, 10); + pub const EFI_2_00: Self = Self::new(2, 00); + pub const EFI_2_10: Self = Self::new(2, 10); + pub const EFI_2_20: Self = Self::new(2, 20); + pub const EFI_2_30: Self = Self::new(2, 30); + pub const EFI_2_31: Self = Self::new(2, 31); + pub const EFI_2_40: Self = Self::new(2, 40); + pub const EFI_2_50: Self = Self::new(2, 50); + pub const EFI_2_60: Self = Self::new(2, 60); + pub const EFI_2_70: Self = Self::new(2, 70); + pub const EFI_2_80: Self = Self::new(2, 80); + pub const EFI_2_90: Self = Self::new(2, 90); +} + +impl Revision { + /// Creates a new revision. + pub const fn new(major: u16, minor: u16) -> Self { + let major = major as u32; + let minor = minor as u32; + let value = (major << 16) | minor; + Revision(value) + } + + /// Returns the major revision. + pub const fn major(self) -> u16 { + (self.0 >> 16) as u16 + } + + /// Returns the minor revision. + pub const fn minor(self) -> u16 { + self.0 as u16 + } +} + +impl fmt::Debug for Revision { + /// Formats the revision in the `major.minor.patch` format. + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + let (major, minor) = (self.major(), self.minor()); + write!(f, "{}.{}.{}", major, minor / 10, minor % 10) + } +} + +#[cfg(test)] +mod tests { + use super::*; + + #[test] + fn test_revision() { + let rev = Revision::EFI_2_31; + assert_eq!(rev.major(), 2); + assert_eq!(rev.minor(), 31); + assert_eq!(rev.0, 0x0002_001f); + + assert!(Revision::EFI_1_10 < Revision::EFI_2_00); + } +} diff --git a/src/table/runtime.rs b/src/table/runtime.rs new file mode 100644 index 000000000..6aa9087bf --- /dev/null +++ b/src/table/runtime.rs @@ -0,0 +1,705 @@ +//! UEFI services available at runtime, even after the OS boots. + +use super::{Header, Revision}; +#[cfg(feature = "exts")] +use crate::data_types::FromSliceWithNulError; +use crate::result::Error; +use crate::table::boot::MemoryDescriptor; +use crate::{CStr16, Char16, Guid, Result, Status}; +#[cfg(feature = "exts")] +use alloc_api::{vec, vec::Vec}; +use bitflags::bitflags; +use core::fmt::{Debug, Formatter}; +#[cfg(feature = "exts")] +use core::mem; +use core::mem::MaybeUninit; +use core::{fmt, ptr}; +/// Contains pointers to all of the runtime services. +/// +/// This table, and the function pointers it contains are valid +/// even after the UEFI OS loader and OS have taken control of the platform. +/// +/// # Accessing `RuntimeServices` +/// +/// A reference to `RuntimeServices` can only be accessed by calling [`SystemTable::runtime_services`]. +/// +/// [`SystemTable::runtime_services`]: crate::table::SystemTable::runtime_services +#[repr(C)] +pub struct RuntimeServices { + header: Header, + get_time: + unsafe extern "efiapi" fn(time: *mut Time, capabilities: *mut TimeCapabilities) -> Status, + set_time: unsafe extern "efiapi" fn(time: &Time) -> Status, + // Skip some useless functions. + _pad: [usize; 2], + pub(crate) set_virtual_address_map: unsafe extern "efiapi" fn( + map_size: usize, + desc_size: usize, + desc_version: u32, + virtual_map: *mut MemoryDescriptor, + ) -> Status, + _pad2: usize, + get_variable: unsafe extern "efiapi" fn( + variable_name: *const Char16, + vendor_guid: *const Guid, + attributes: *mut VariableAttributes, + data_size: *mut usize, + data: *mut u8, + ) -> Status, + get_next_variable_name: unsafe extern "efiapi" fn( + variable_name_size: *mut usize, + variable_name: *mut u16, + vendor_guid: *mut Guid, + ) -> Status, + set_variable: unsafe extern "efiapi" fn( + variable_name: *const Char16, + vendor_guid: *const Guid, + attributes: VariableAttributes, + data_size: usize, + data: *const u8, + ) -> Status, + _pad3: usize, + reset: unsafe extern "efiapi" fn( + rt: ResetType, + + status: Status, + data_size: usize, + data: *const u8, + ) -> !, + + // UEFI 2.0 Capsule Services. + update_capsule: usize, + query_capsule_capabilities: usize, + + // Miscellaneous UEFI 2.0 Service. + query_variable_info: unsafe extern "efiapi" fn( + attributes: VariableAttributes, + maximum_variable_storage_size: *mut u64, + remaining_variable_storage_size: *mut u64, + maximum_variable_size: *mut u64, + ) -> Status, +} + +impl RuntimeServices { + /// Query the current time and date information + pub fn get_time(&self) -> Result