From 3e0b95784a3a683094bed6f9f5c65c63bfa51525 Mon Sep 17 00:00:00 2001 From: Ben Burwell Date: Wed, 1 Nov 2023 09:59:52 -0400 Subject: [PATCH] Add initial implementation --- .github/workflows/cargo_test.yml | 23 ++ .gitignore | 2 + Cargo.toml | 19 + LICENSE.txt | 26 ++ README.md | 25 +- egm.zip.sha256 | 1 + flake.lock | 59 +++ flake.nix | 24 ++ generate.py | 73 ++++ generate_geoid.sh | 36 ++ src/geoid.rs | 667 +++++++++++++++++++++++++++++++ src/lib.rs | 247 ++++++++++++ 12 files changed, 1201 insertions(+), 1 deletion(-) create mode 100644 .github/workflows/cargo_test.yml create mode 100644 Cargo.toml create mode 100644 LICENSE.txt create mode 100644 egm.zip.sha256 create mode 100644 flake.lock create mode 100644 flake.nix create mode 100644 generate.py create mode 100755 generate_geoid.sh create mode 100644 src/geoid.rs create mode 100644 src/lib.rs diff --git a/.github/workflows/cargo_test.yml b/.github/workflows/cargo_test.yml new file mode 100644 index 0000000..0630ca3 --- /dev/null +++ b/.github/workflows/cargo_test.yml @@ -0,0 +1,23 @@ +name: Cargo Build & Test + +on: + push: + pull_request: + +env: + CARGO_TERM_COLOR: always + +jobs: + build_and_test: + name: Rust project - latest + runs-on: ubuntu-latest + strategy: + matrix: + toolchain: + - stable + - beta + steps: + - uses: actions/checkout@v3 + - run: rustup update ${{ matrix.toolchain }} && rustup default ${{ matrix.toolchain }} + - run: cargo build --verbose + - run: cargo test --verbose diff --git a/.gitignore b/.gitignore index 2f7896d..d9bad7b 100644 --- a/.gitignore +++ b/.gitignore @@ -1 +1,3 @@ target/ +Cargo.lock +egm.zip diff --git a/Cargo.toml b/Cargo.toml new file mode 100644 index 0000000..391dc80 --- /dev/null +++ b/Cargo.toml @@ -0,0 +1,19 @@ +[package] +name = "egm2008" +version = "0.1.0" +edition = "2021" +authors = ["FlightAware", "Ben Burwell "] +description = "Earth Gravitational Model (EGM2008)" +keywords = ["egm", "geoid", "gis"] +license = "BSD-3-Clause" +homepage = "https://github.com/flightaware/egm2008" +repository = "https://github.com/flightaware/egm2008" +categories = ["science::geo"] +readme = "README.md" +include = [ + "src/*.rs", + "Cargo.toml" +] + +[dependencies] +thiserror = "1.0.50" diff --git a/LICENSE.txt b/LICENSE.txt new file mode 100644 index 0000000..2998c94 --- /dev/null +++ b/LICENSE.txt @@ -0,0 +1,26 @@ +Copyright 2023 FlightAware + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are met: + +1. Redistributions of source code must retain the above copyright notice, this +list of conditions and the following disclaimer. + +2. Redistributions in binary form must reproduce the above copyright notice, +this list of conditions and the following disclaimer in the documentation +and/or other materials provided with the distribution. + +3. Neither the name of the copyright holder nor the names of its contributors +may be used to endorse or promote products derived from this software without +specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND +ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE +FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR +SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER +CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, +OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. diff --git a/README.md b/README.md index 520cf7d..0a9a079 100644 --- a/README.md +++ b/README.md @@ -1 +1,24 @@ -# Earth Gravitational Model +# Earth Gravitational Model (EGM2008) + +The coordinate system used by GPS is [WGS 84](https://en.wikipedia.org/wiki/World_Geodetic_System#WGS_84), which expresses altitudes as a "height above ellipsoid". +Because this ellipsoid is a mathematical simplification, the height given by GPS does not necessarily reflect the height above the actual ground beneath. + +The [Earth Gravitational Models](https://en.wikipedia.org/wiki/Earth_Gravitational_Model) published by the National Geospatial Intelligence Agency are a way to approximate how high an altitude given in WGS 84 coordinates truly is above the ground. + +This library includes data derived from [EGM 2008](https://earth-info.nga.mil/index.php?dir=wgs84&action=wgs84) along with an interpolation function. Together, these allow for an approximate offset to be obtained for arbitrary points on the globe. + +The `geoid.rs` file containing terrain data is [generated using the Fortran program](./tools/README.md) provided by NGA. + +## Updating `geoid.rs` + +The `src/geoid.rs` file is generated by a Python script (`generate.py`) that +runs NGA's Fortran interpolation program. In order to run the script, you'll +need to download the EGM model data from the NGA's website. + +You will also need to install `gfortran`. There are a few ways to do this: +- On macOS, through [Homebrew](https://brew.sh) with `brew install gfortran`. +- Use the included [Nix](https://nix.dev) dev shell with `nix develop`. + +For convenience, you can run `generate_geoid.sh` which will download and verify +the model data from NGA, compile the interpolation program, and update +`src/geoid.rs`. diff --git a/egm.zip.sha256 b/egm.zip.sha256 new file mode 100644 index 0000000..38e639f --- /dev/null +++ b/egm.zip.sha256 @@ -0,0 +1 @@ +0f65f16e6fd3f89a6b8022d7a89375d0c29fb275a551927175669bb610904cd0 egm.zip diff --git a/flake.lock b/flake.lock new file mode 100644 index 0000000..1bbe398 --- /dev/null +++ b/flake.lock @@ -0,0 +1,59 @@ +{ + "nodes": { + "flake-utils": { + "inputs": { + "systems": "systems" + }, + "locked": { + "lastModified": 1694529238, + "narHash": "sha256-zsNZZGTGnMOf9YpHKJqMSsa0dXbfmxeoJ7xHlrt+xmY=", + "owner": "numtide", + "repo": "flake-utils", + "rev": "ff7b65b44d01cf9ba6a71320833626af21126384", + "type": "github" + }, + "original": { + "owner": "numtide", + "repo": "flake-utils", + "type": "github" + } + }, + "nixpkgs": { + "locked": { + "lastModified": 1698553279, + "narHash": "sha256-T/9P8yBSLcqo/v+FTOBK+0rjzjPMctVymZydbvR/Fak=", + "owner": "NixOS", + "repo": "nixpkgs", + "rev": "90e85bc7c1a6fc0760a94ace129d3a1c61c3d035", + "type": "github" + }, + "original": { + "id": "nixpkgs", + "type": "indirect" + } + }, + "root": { + "inputs": { + "flake-utils": "flake-utils", + "nixpkgs": "nixpkgs" + } + }, + "systems": { + "locked": { + "lastModified": 1681028828, + "narHash": "sha256-Vy1rq5AaRuLzOxct8nz4T6wlgyUR7zLU309k9mBC768=", + "owner": "nix-systems", + "repo": "default", + "rev": "da67096a3b9bf56a91d16901293e51ba5b49a27e", + "type": "github" + }, + "original": { + "owner": "nix-systems", + "repo": "default", + "type": "github" + } + } + }, + "root": "root", + "version": 7 +} diff --git a/flake.nix b/flake.nix new file mode 100644 index 0000000..35d91dc --- /dev/null +++ b/flake.nix @@ -0,0 +1,24 @@ +{ + inputs = { + nixpkgs.url = "nixpkgs"; + flake-utils.url = "github:numtide/flake-utils"; + }; + + outputs = { self, nixpkgs, flake-utils, ... }: + flake-utils.lib.eachDefaultSystem (system: + let + pkgs = nixpkgs.legacyPackages.${system}; + in { + devShells = { + default = pkgs.mkShell { + nativeBuildInputs = with pkgs; [ + rustc + cargo + rustfmt + gfortran + python3 + ]; + }; + }; + }); +} diff --git a/generate.py b/generate.py new file mode 100644 index 0000000..786c57a --- /dev/null +++ b/generate.py @@ -0,0 +1,73 @@ +#!/usr/bin/env python3 + +import sys +import os +import re +import math +from contextlib import closing + +scale = 3.0 +splitter = re.compile(r'\s+') + +if math.fmod(360.0, scale) != 0: + raise RuntimeError('non-exact scale') +if math.fmod(180.0, scale) != 0: + raise RuntimeError('non-exact scale') + +bandsize = int(360.0 / scale + 1) +bandcount = int(180.0 / scale + 1) +tablesize = bandsize * bandcount +table = [None] * tablesize + +print('{} degree grid, {} table entries'.format(scale, tablesize), file=sys.stderr) +print('Generating INPUT.DAT', file=sys.stderr) +with closing(open('INPUT.DAT', 'w')) as f: + for lat in range(bandcount): + for lon in range(bandsize): + print(lat * scale - 90.0, lon * scale - 180.0, file=f) + +print('Generating OUTPUT.DAT', file=sys.stderr) +os.system('./interpolate') + +with closing(open('OUTPUT.DAT', 'r')) as f: + for line in f: + line = line.strip() + lat, lon, geoid = splitter.split(line.rstrip('\r\n')) + lat, lon, geoid = float(lat), float(lon), float(geoid) + + lat_i = int((lat + 90) / scale) + lon_i = int((lon + 180) / scale) + index = (lat_i * bandsize) + lon_i + table[index] = geoid + +for i in range(tablesize): + if table[i] is None: + raise RuntimeError('missing values at index {}'.format(i)) + +print('Generating geoid.rs', file=sys.stderr) +with closing(open('geoid.rs', 'w')) as f: + prog = ''' +// Generated by generate.py, DO NOT EDIT! + +/// Grid size in degrees. +pub(crate) const SCALE: f32 = {scale}; + +/// How many entries each band has. +pub(crate) const BAND_SIZE: usize = {bandsize}; + +/// How many bands there are in total. +pub(crate) const BAND_COUNT: usize = {bandcount}; + +/// An array of geoid undulation data with BAND_SIZE * BAND_COUNT entries. +/// +/// Data is expressed in meters. +#[allow(clippy::approx_constant)] +pub(crate) const DATA: &[f32] = &{table}; +'''.format(scale=scale, + bandsize=bandsize, + bandcount=bandcount, + table=table) + print(prog, file=f) + +print('Formatting geoid.rs', file=sys.stderr) +os.system('rustfmt geoid.rs') diff --git a/generate_geoid.sh b/generate_geoid.sh new file mode 100755 index 0000000..a04969b --- /dev/null +++ b/generate_geoid.sh @@ -0,0 +1,36 @@ +#!/bin/sh + +project_dir=$(pwd) + +if [ ! -f egm.zip ]; then + echo "===> Downloading egm.zip from earth-info.nga.mil..." + curl -o egm.zip 'https://earth-info.nga.mil/php/download.php?file=egm-08interpolation' +else + echo "===> Using existing egm.zip" +fi + +echo "===> Verifying downloaded archive..." +if ! shasum -a 256 -c egm.zip.sha256; then + echo " Bailing due to bad checksum!" + exit 1 +fi + +build_dir=$(mktemp -d) +echo "===> Unzipping egm.zip into $build_dir..." +unzip egm.zip -d "$build_dir" + +echo "===> Installing generate.py..." +cp generate.py "$build_dir/generate.py" + +echo "===> Entering $build_dir..." +cd "$build_dir" || exit 1 + +echo "===> Compiling Fortran interpolater..." +gfortran -o interpolate interp_2p5min.f + +echo "===> Generating geoid.rs..." +python3 generate.py +mv geoid.rs "$project_dir/src/geoid.rs" + +echo "===> Cleaning up $build_dir..." +rm -rf "$build_dir" diff --git a/src/geoid.rs b/src/geoid.rs new file mode 100644 index 0000000..0fd2912 --- /dev/null +++ b/src/geoid.rs @@ -0,0 +1,667 @@ +// Generated by generate.py, DO NOT EDIT! + +/// Grid size in degrees. +pub(crate) const SCALE: f32 = 3.0; + +/// How many entries each band has. +pub(crate) const BAND_SIZE: usize = 121; + +/// How many bands there are in total. +pub(crate) const BAND_COUNT: usize = 61; + +/// An array of geoid undulation data with BAND_SIZE * BAND_COUNT entries. +/// +/// Data is expressed in meters. +#[allow(clippy::approx_constant)] +pub(crate) const DATA: &[f32] = &[ + -30.15, -30.15, -30.15, -30.15, -30.15, -30.15, -30.15, -30.15, -30.15, -30.15, -30.15, -30.15, + -30.15, -30.15, -30.15, -30.15, -30.15, -30.15, -30.15, -30.15, -30.15, -30.15, -30.15, -30.15, + -30.15, -30.15, -30.15, -30.15, -30.15, -30.15, -30.15, -30.15, -30.15, -30.15, -30.15, -30.15, + -30.15, -30.15, -30.15, -30.15, -30.15, -30.15, -30.15, -30.15, -30.15, -30.15, -30.15, -30.15, + -30.15, -30.15, -30.15, -30.15, -30.15, -30.15, -30.15, -30.15, -30.15, -30.15, -30.15, -30.15, + -30.15, -30.15, -30.15, -30.15, -30.15, -30.15, -30.15, -30.15, -30.15, -30.15, -30.15, -30.15, + -30.15, -30.15, -30.15, -30.15, -30.15, -30.15, -30.15, -30.15, -30.15, -30.15, -30.15, -30.15, + -30.15, -30.15, -30.15, -30.15, -30.15, -30.15, -30.15, -30.15, -30.15, -30.15, -30.15, -30.15, + -30.15, -30.15, -30.15, -30.15, -30.15, -30.15, -30.15, -30.15, -30.15, -30.15, -30.15, -30.15, + -30.15, -30.15, -30.15, -30.15, -30.15, -30.15, -30.15, -30.15, -30.15, -30.15, -30.15, -30.15, + -30.15, -30.551, -30.283, -30.082, -29.94, -29.872, -29.905, -30.025, -30.085, -30.067, + -30.028, -29.919, -29.83, -29.706, -29.549, -29.39, -29.226, -29.103, -29.017, -28.944, + -28.874, -28.798, -28.696, -28.578, -28.449, -28.318, -28.185, -28.085, -28.005, -27.917, + -27.791, -27.604, -27.315, -26.897, -26.338, -25.686, -25.023, -24.397, -23.879, -23.56, + -23.526, -23.779, -24.283, -24.975, -25.783, -26.593, -27.293, -27.8, -28.074, -28.106, + -27.929, -27.595, -27.15, -26.647, -26.129, -25.616, -25.121, -24.641, -24.154, -23.657, + -23.142, -22.616, -22.071, -21.514, -20.955, -20.41, -19.892, -19.406, -18.97, -18.594, + -18.292, -18.063, -17.904, -17.809, -17.755, -17.726, -17.708, -17.684, -17.671, -17.692, + -17.774, -17.943, -18.225, -18.634, -19.17, -19.824, -20.573, -21.394, -22.26, -23.146, + -24.043, -24.93, -25.794, -26.635, -27.449, -28.251, -29.034, -29.796, -30.529, -31.23, + -31.888, -32.475, -32.976, -33.368, -33.633, -33.768, -33.786, -33.703, -33.539, -33.329, + -33.103, -32.882, -32.682, -32.504, -32.334, -32.155, -31.952, -31.712, -31.432, -31.136, + -30.828, -30.551, -42.49, -42.991, -43.267, -43.459, -43.671, -43.887, -44.022, -43.986, + -43.741, -43.35, -42.923, -42.549, -42.236, -41.923, -41.517, -40.965, -40.251, -39.389, + -38.374, -37.278, -36.132, -34.991, -33.913, -32.846, -31.738, -30.656, -29.675, -28.889, + -28.323, -28.001, -27.794, -27.656, -27.477, -27.202, -26.879, -26.585, -26.424, -26.504, + -26.71, -26.911, -26.844, -26.228, -25.077, -23.293, -21.387, -19.678, -18.282, -17.208, + -16.378, -15.787, -15.457, -15.353, -15.498, -15.581, -15.435, -15.043, -14.543, -14.159, + -13.905, -13.73, -13.57, -13.383, -13.287, -13.42, -13.764, -14.073, -13.964, -13.086, -11.408, + -9.319, -7.43, -6.324, -6.29, -7.148, -8.327, -9.234, -9.461, -8.974, -8.029, -7.032, -6.325, + -6.073, -6.307, -6.948, -7.925, -9.155, -10.533, -11.907, -13.142, -14.231, -15.257, -16.364, + -17.638, -19.065, -20.542, -21.997, -23.453, -25.013, -26.758, -28.637, -30.489, -32.09, + -33.325, -34.239, -35.01, -35.853, -36.824, -37.817, -38.593, -38.945, -38.823, -38.317, + -37.695, -37.298, -37.063, -37.562, -38.863, -39.307, -40.679, -41.669, -42.49, -50.15, + -50.747, -51.122, -51.216, -51.167, -51.087, -50.954, -50.72, -50.427, -50.106, -49.676, + -49.042, -48.23, -47.343, -46.358, -45.184, -43.825, -42.501, -41.33, -40.151, -38.783, -37.37, + -36.191, -35.166, -33.889, -32.156, -30.167, -28.26, -26.534, -25.245, -24.59, -24.617, -25.06, + -25.821, -26.454, -26.71, -26.386, -25.569, -24.763, -24.506, -24.776, -24.897, -24.186, + -22.691, -21.098, -20.038, -19.497, -19.065, -18.452, -17.748, -17.046, -16.414, -15.609, + -14.419, -12.964, -11.714, -11.128, -11.038, -10.501, -8.82, -6.439, -4.631, -3.953, -3.792, + -3.12, -1.589, 0.213, 1.616, 2.461, 3.069, 3.624, 4.037, 4.141, 3.926, 3.506, 3.028, 2.734, + 2.826, 3.296, 3.834, 4.084, 3.987, 3.82, 3.903, 4.117, 3.915, 3.031, 1.648, 0.203, -1.438, + -3.801, -6.932, -10.087, -12.7, -15.226, -18.424, -22.173, -25.569, -28.159, -30.444, -33.164, + -36.172, -38.701, -40.437, -41.865, -43.558, -45.512, -47.36, -48.818, -49.705, -49.738, + -48.926, -47.924, -47.419, -47.615, -48.341, -48.953, -49.215, -49.324, -49.606, -50.15, + -56.337, -57.303, -57.105, -56.96, -57.336, -56.903, -56.474, -55.374, -54.844, -54.487, + -53.474, -52.102, -50.603, -48.579, -46.054, -43.902, -42.538, -41.25, -39.716, -38.355, + -36.996, -35.289, -33.955, -33.61, -33.034, -31.289, -29.658, -29.059, -27.763, -24.534, + -21.356, -20.329, -20.443, -20.888, -20.853, -20.482, -20.037, -19.744, -19.614, -19.689, + -19.931, -19.838, -18.801, -17.011, -15.435, -14.752, -14.659, -13.989, -12.802, -11.573, + -10.528, -9.215, -7.91, -7.204, -6.625, -5.494, -4.184, -3.52, -3.565, -3.464, -2.654, -1.303, + 0.221, 1.922, 3.445, 4.214, 4.452, 4.954, 5.868, 6.839, 7.848, 8.962, 9.853, 10.093, 9.579, + 8.725, 8.246, 8.271, 8.073, 7.22, 6.488, 6.836, 7.835, 7.693, 5.809, 3.691, 2.704, 2.656, + 2.599, 1.432, -1.344, -5.054, -8.635, -12.382, -16.247, -18.593, -19.437, -21.457, -25.984, + -31.18, -35.392, -38.73, -41.148, -42.633, -44.501, -47.704, -51.163, -53.616, -55.273, + -56.504, -56.72, -55.403, -53.255, -51.807, -51.444, -51.696, -52.592, -53.33, -53.886, + -54.782, -56.337, -61.554, -61.992, -63.242, -62.6, -63.14, -63.443, -63.365, -62.593, -61.428, + -60.544, -60.087, -57.948, -53.46, -52.164, -48.591, -45.468, -43.165, -41.264, -39.544, + -37.899, -35.858, -33.651, -31.811, -30.757, -30.021, -28.857, -27.133, -25.11, -23.386, + -21.869, -19.811, -17.634, -16.12, -14.841, -13.146, -10.956, -7.716, -4.921, -5.409, -8.087, + -9.985, -10.3, -8.982, -6.944, -5.988, -4.644, -2.801, -0.885, 0.656, 0.167, -1.032, -1.391, + 0.263, 1.604, 1.082, 2.232, 6.103, 8.905, 9.77, 10.909, 11.738, 11.397, 11.515, 12.068, 12.095, + 12.781, 14.087, 14.913, 16.223, 17.932, 17.831, 16.843, 17.418, 18.308, 17.985, 17.21, 16.654, + 16.516, 16.197, 14.615, 12.672, 10.976, 8.717, 6.613, 6.477, 8.068, 8.527, 7.252, 6.303, 5.18, + 2.17, -1.624, -4.851, -7.38, -9.824, -13.535, -19.374, -27.247, -34.032, -36.981, -38.33, + -39.386, -39.267, -41.087, -46.249, -49.621, -49.345, -50.553, -54.211, -56.926, -57.535, + -57.394, -58.571, -60.126, -59.209, -58.346, -56.894, -57.866, -58.537, -59.391, -61.554, + -62.161, -62.311, -65.615, -65.195, -65.036, -64.255, -63.288, -62.532, -61.808, -61.039, + -60.262, -59.329, -57.501, -55.286, -52.883, -50.509, -47.197, -45.378, -43.156, -40.607, + -36.736, -33.586, -32.075, -30.295, -27.914, -26.481, -24.237, -22.181, -21.252, -19.707, + -18.416, -16.919, -14.358, -11.738, -9.221, -6.324, -3.577, -2.187, 1.295, 3.15, 0.402, 0.409, + 2.083, 1.144, 0.509, -1.252, -2.641, -2.854, -3.288, -3.263, -3.113, -1.683, -0.902, 0.139, + 3.381, 10.064, 9.798, 7.381, 8.547, 9.639, 11.672, 16.271, 17.297, 17.581, 19.075, 18.774, + 16.499, 15.947, 18.211, 17.934, 16.993, 21.303, 24.971, 25.049, 24.653, 23.962, 24.508, 24.72, + 23.332, 23.165, 22.338, 19.821, 16.567, 12.302, 11.169, 13.794, 15.366, 14.599, 12.442, 9.338, + 6.014, 3.796, 1.231, -2.877, -10.303, -19.459, -26.821, -28.477, -26.368, -26.862, -29.226, + -32.778, -36.311, -39.102, -40.037, -41.5, -47.434, -50.846, -50.578, -53.827, -56.79, -58.506, + -58.538, -56.935, -57.479, -55.684, -53.423, -56.128, -58.228, -61.034, -62.161, -61.565, + -62.731, -63.433, -61.784, -60.348, -59.298, -58.694, -57.856, -57.484, -56.261, -55.367, + -53.889, -52.56, -50.952, -49.047, -46.675, -44.317, -41.418, -39.329, -37.628, -36.481, + -34.889, -33.648, -32.231, -30.691, -29.057, -27.642, -25.894, -25.204, -21.316, -16.781, + -15.192, -13.047, -9.089, -5.079, -1.275, 2.58, 5.629, 9.63, 8.532, 6.406, 7.989, 3.569, 3.452, + 4.143, 3.652, 4.108, 4.459, 4.481, 3.507, 3.091, 3.381, 3.662, 4.027, 4.687, 5.174, 5.952, + 7.434, 9.616, 9.005, 9.68, 10.475, 13.457, 14.333, 16.226, 16.445, 15.529, 16.35, 16.94, + 17.741, 21.255, 23.22, 22.027, 21.684, 25.242, 29.145, 28.733, 31.335, 34.281, 33.159, 31.265, + 28.31, 26.331, 22.337, 17.737, 15.633, 16.866, 17.138, 14.623, 12.51, 11.252, 10.063, 4.867, + -5.897, -8.049, -11.569, -17.552, -18.729, -21.634, -23.194, -26.273, -28.844, -32.611, + -38.478, -37.906, -39.581, -42.384, -40.618, -44.789, -49.491, -53.835, -55.188, -53.316, + -54.291, -54.423, -56.512, -56.744, -57.059, -58.82, -60.085, -61.565, -55.192, -53.521, + -53.511, -53.025, -52.589, -52.195, -51.454, -51.034, -50.035, -49.371, -48.318, -46.734, + -45.094, -43.484, -43.315, -42.304, -40.927, -38.353, -36.233, -34.65, -33.327, -32.128, + -30.821, -28.811, -26.986, -25.784, -24.662, -23.25, -20.942, -19.224, -16.053, -13.927, + -11.594, -8.512, -5.353, -1.744, 2.719, 9.173, 13.29, 16.787, 14.43, 15.025, 14.525, 11.077, + 11.409, 12.6, 12.178, 11.798, 10.93, 10.345, 9.577, 8.786, 8.577, 7.921, 7.143, 7.618, 7.934, + 8.291, 9.447, 10.727, 12.859, 14.709, 15.204, 16.072, 18.572, 18.033, 17.04, 17.798, 17.713, + 18.354, 19.958, 22.486, 23.614, 24.097, 25.807, 27.878, 30.98, 32.204, 33.624, 32.505, 29.132, + 25.89, 24.822, 23.904, 21.742, 18.619, 15.322, 15.978, 14.843, 11.974, 7.659, 2.403, -0.91, + -2.259, -3.576, -8.72, -13.968, -17.184, -20.452, -23.792, -26.106, -28.977, -31.522, -35.347, + -37.017, -39.63, -41.923, -42.463, -44.58, -45.183, -44.696, -48.661, -46.665, -47.144, + -47.672, -48.836, -50.7, -52.331, -54.206, -54.597, -55.192, -49.627, -48.961, -48.334, + -46.873, -45.641, -44.325, -43.429, -42.52, -41.44, -40.488, -39.568, -39.028, -38.093, -37.73, + -37.17, -36.406, -35.272, -33.909, -32.538, -30.842, -29.392, -27.929, -26.973, -25.855, + -24.657, -23.089, -21.703, -20.017, -17.951, -15.719, -13.442, -11.675, -9.594, -6.111, -2.579, + 1.856, 5.197, 9.275, 13.706, 15.805, 20.452, 23.34, 23.124, 20.429, 19.348, 18.95, 18.389, + 18.767, 17.726, 17.252, 16.636, 15.951, 14.508, 13.324, 11.964, 11.147, 10.81, 11.468, 11.568, + 11.993, 13.499, 15.087, 17.497, 19.232, 21.313, 22.226, 22.51, 22.344, 22.615, 23.485, 24.614, + 25.039, 27.833, 29.691, 31.113, 30.937, 30.537, 29.546, 29.655, 30.763, 30.398, 29.43, 27.486, + 26.149, 24.808, 23.62, 20.894, 17.634, 15.787, 11.632, 7.156, 3.495, -0.842, -4.285, -8.803, + -11.528, -14.303, -19.431, -22.71, -25.341, -28.82, -31.752, -33.5, -36.153, -38.534, -40.295, + -40.846, -40.991, -39.907, -39.51, -38.971, -37.457, -37.963, -38.207, -40.077, -42.189, + -43.405, -45.502, -47.954, -49.706, -49.627, -45.977, -45.392, -44.409, -43.228, -42.141, + -40.564, -38.74, -36.575, -34.771, -32.993, -32.047, -31.313, -30.919, -30.227, -29.656, + -28.756, -27.415, -26.384, -25.502, -24.163, -23.501, -22.64, -22.799, -22.243, -21.384, + -19.692, -18.417, -16.229, -14.134, -12.639, -11.232, -8.844, -6.6, -4.305, -1.19, 2.472, + 6.551, 11.777, 16.141, 18.135, 20.163, 20.254, 21.135, 20.281, 18.083, 15.56, 19.852, 21.437, + 21.658, 23.34, 23.844, 17.544, 13.419, 19.969, 21.145, 19.231, 17.802, 16.539, 16.149, 15.791, + 15.175, 15.727, 17.04, 19.328, 22.097, 23.655, 25.236, 25.69, 25.937, 28.246, 29.141, 30.344, + 32.147, 33.523, 34.683, 34.672, 33.636, 32.983, 33.09, 32.634, 32.789, 31.373, 30.901, 30.003, + 27.659, 27.27, 26.418, 25.105, 20.845, 12.533, 8.934, 5.147, 1.797, -2.111, -5.201, -7.775, + -11.132, -14.79, -18.485, -21.818, -24.67, -26.886, -28.899, -31.007, -32.401, -32.829, + -33.027, -32.813, -31.564, -30.669, -29.559, -29.299, -30.475, -32.331, -36.776, -39.716, + -42.814, -45.208, -46.472, -46.902, -45.977, -40.308, -39.574, -39.302, -37.818, -36.441, + -34.33, -32.459, -30.393, -28.917, -27.042, -25.959, -24.719, -24.386, -24.253, -22.405, + -21.63, -20.837, -20.013, -19.117, -18.227, -18.322, -16.703, -16.68, -16.388, -15.645, + -15.115, -13.286, -12.255, -11.222, -9.962, -8.414, -6.644, -3.89, -0.932, 1.649, 4.523, 7.274, + 7.962, 13.181, 16.252, 19.037, 19.503, 18.454, 18.476, 19.313, 18.963, 18.23, 19.538, 20.858, + 22.11, 23.283, 21.052, 8.903, 19.714, 20.073, 21.08, 21.362, 22.855, 24.161, 23.559, 22.912, + 22.516, 20.574, 20.042, 20.92, 23.562, 26.783, 28.055, 29.527, 29.887, 32.376, 34.281, 36.498, + 38.76, 39.233, 39.619, 39.002, 37.523, 36.513, 35.966, 35.166, 34.506, 35.198, 34.718, 33.645, + 31.006, 28.768, 23.555, 18.18, 15.705, 12.623, 9.099, 5.168, 0.652, -2.652, -6.468, -9.931, + -13.636, -17.097, -19.955, -22.339, -24.348, -26.058, -26.852, -27.179, -27.08, -26.873, + -25.979, -24.352, -23.402, -23.818, -24.701, -26.334, -27.124, -30.621, -34.67, -37.266, + -38.968, -39.738, -39.705, -40.308, -31.098, -31.641, -31.114, -30.21, -28.919, -27.624, + -26.423, -24.904, -23.392, -22.639, -22.0, -20.881, -19.88, -18.836, -17.655, -17.097, -18.15, + -17.116, -14.786, -13.252, -11.759, -11.566, -12.14, -12.276, -12.429, -12.009, -11.716, + -9.598, -8.972, -8.335, -5.748, -4.256, -1.872, 1.731, 4.642, 4.709, 11.899, 11.876, 11.897, + 8.882, 10.563, 8.418, 8.581, 12.188, 11.963, 13.389, 15.131, 17.386, 16.96, 13.208, 14.001, + 13.637, 19.708, 20.825, 21.654, 22.801, 24.099, 25.765, 27.16, 27.903, 27.488, 27.927, 28.247, + 26.213, 27.923, 28.985, 31.887, 34.573, 36.428, 34.259, 35.502, 38.135, 41.258, 45.416, 47.365, + 45.634, 45.188, 44.006, 41.397, 39.536, 37.807, 35.467, 34.563, 34.725, 35.44, 35.232, 30.365, + 23.657, 20.814, 17.215, 13.338, 9.455, 5.762, 1.41, -1.914, -5.868, -9.688, -13.321, -17.014, + -19.522, -21.5, -23.045, -24.226, -23.864, -23.451, -23.058, -22.235, -20.521, -19.147, + -20.284, -20.553, -20.835, -21.991, -17.922, -22.608, -22.556, -22.482, -24.422, -29.026, + -30.344, -31.098, -20.573, -21.145, -22.6, -21.078, -21.239, -21.048, -20.051, -20.135, + -19.605, -18.876, -17.725, -17.205, -17.556, -18.706, -18.323, -18.315, -17.64, -15.508, + -13.438, -11.499, -10.285, -9.902, -10.325, -10.759, -10.776, -10.904, -10.164, -8.11, -7.374, + -6.466, -4.24, -1.846, 0.682, 3.564, 5.295, 13.789, 12.407, 10.113, 10.879, 13.37, 13.391, + 12.3, 9.716, 6.12, 5.926, 6.276, 8.082, 6.672, 7.883, 10.035, 12.549, 15.342, 17.284, 19.701, + 22.109, 24.579, 26.19, 26.841, 28.232, 27.315, 26.401, 25.182, 25.306, 25.756, 27.09, 31.275, + 32.971, 34.513, 35.741, 37.094, 37.933, 39.712, 42.247, 45.709, 46.897, 46.696, 45.197, 44.149, + 43.082, 40.87, 38.495, 36.957, 36.857, 35.052, 37.85, 35.869, 30.228, 26.785, 22.182, 17.728, + 13.249, 9.296, 4.771, 0.249, -3.887, -7.978, -11.747, -14.972, -17.861, -20.218, -21.907, + -23.102, -23.724, -22.317, -21.262, -20.15, -18.801, -18.549, -17.564, -18.376, -18.242, + -17.588, -17.764, -15.715, -10.899, -14.267, -11.768, -13.154, -14.522, -19.209, -20.573, + -4.699, -11.742, -13.217, -13.806, -14.047, -14.071, -13.851, -14.343, -13.411, -13.101, + -13.704, -14.835, -15.762, -16.695, -17.252, -16.716, -15.284, -14.103, -12.177, -11.474, + -10.2, -9.567, -9.319, -9.528, -9.737, -9.347, -8.681, -7.277, -6.303, -4.082, -0.71, 0.11, + 2.527, 4.969, 7.313, 14.785, 16.733, 15.743, 11.576, 10.937, 10.042, 5.566, 1.236, -1.526, + -2.814, -2.199, -1.21, -0.314, 1.508, 4.474, 8.63, 12.568, 16.381, 20.088, 23.289, 25.556, + 27.873, 27.843, 25.592, 23.896, 23.281, 22.497, 23.808, 25.347, 26.201, 29.099, 30.686, 32.537, + 33.343, 34.208, 38.838, 42.63, 43.395, 43.094, 43.751, 44.198, 44.917, 44.986, 44.031, 41.873, + 38.618, 36.672, 38.898, 40.042, 35.48, 31.176, 27.959, 24.452, 20.182, 15.937, 11.388, 6.754, + 2.378, -2.35, -7.058, -11.509, -15.465, -19.03, -21.71, -23.43, -24.314, -24.801, -24.376, + -23.279, -21.536, -19.526, -17.451, -17.465, -16.202, -14.791, -14.179, -14.675, -14.264, + -12.565, -8.867, -8.555, -3.846, -5.662, -4.978, -5.333, -4.699, 3.379, 2.692, -1.137, -5.061, + -7.623, -8.49, -8.058, -7.345, -8.342, -9.389, -11.229, -12.349, -13.703, -14.771, -15.258, + -15.03, -14.35, -13.666, -12.339, -11.578, -10.766, -10.553, -9.837, -9.609, -9.089, -8.289, + -7.153, -6.007, -4.008, -2.912, -0.881, 1.343, 4.02, 6.021, 10.537, 13.232, 19.875, 17.637, + 13.013, 11.112, 9.081, 2.183, -0.119, -2.61, -3.67, -3.667, -4.957, -4.555, -2.876, 1.348, + 6.879, 11.915, 16.575, 20.887, 23.993, 26.732, 26.043, 25.395, 24.667, 22.355, 20.987, 21.832, + 22.766, 25.879, 26.838, 28.345, 31.21, 32.669, 33.362, 33.259, 34.428, 39.196, 46.515, 46.34, + 45.506, 45.881, 45.042, 45.015, 43.196, 40.397, 35.747, 32.239, 31.69, 31.116, 29.5, 26.507, + 23.919, 20.364, 16.494, 12.141, 7.738, 2.833, -2.372, -8.049, -12.765, -17.193, -21.236, + -24.381, -26.673, -27.421, -27.309, -27.332, -26.329, -25.074, -22.814, -20.263, -17.541, + -16.66, -15.016, -12.913, -11.441, -10.336, -8.634, -7.358, -4.272, -3.028, 7.361, 7.493, + 4.913, 5.126, 3.379, 15.427, 12.877, 8.668, 4.497, 0.732, -0.655, -1.479, -2.495, -3.93, -5.64, + -7.836, -10.468, -11.541, -12.801, -13.463, -13.714, -13.665, -13.184, -12.274, -11.838, + -12.12, -11.658, -10.657, -9.997, -9.685, -8.758, -8.067, -7.225, -4.899, -2.596, -0.864, + 1.658, 3.988, 7.073, 10.442, 11.939, 21.193, 21.467, 15.258, 12.26, 11.938, 6.224, 0.372, + -1.976, -2.884, -5.188, -7.354, -6.182, -3.14, 0.677, 6.389, 11.505, 16.059, 20.302, 23.509, + 24.856, 24.398, 23.84, 22.432, 20.283, 24.183, 19.692, 21.827, 25.126, 27.148, 28.899, 29.63, + 30.819, 34.26, 35.086, 33.181, 34.278, 38.579, 42.15, 44.285, 43.883, 43.1, 42.221, 39.08, + 35.282, 31.857, 29.282, 28.292, 27.061, 23.895, 21.65, 19.326, 16.015, 12.022, 7.605, 2.605, + -3.024, -8.858, -14.519, -19.463, -23.5, -27.339, -30.05, -31.249, -31.236, -31.11, -30.316, + -28.71, -26.971, -23.961, -20.74, -17.543, -15.269, -11.514, -0.798, -6.693, -4.609, -2.291, + -0.352, 2.231, 5.655, 10.133, 14.209, 11.901, 11.336, 15.427, 21.563, 19.483, 13.172, 10.123, + 9.294, 5.812, 3.553, 2.706, 0.38, -2.954, -6.574, -8.407, -10.072, -11.027, -11.911, -12.243, + -12.597, -12.359, -12.123, -12.321, -12.744, -12.25, -11.343, -10.21, -9.894, -8.87, -7.459, + -6.304, -3.877, -2.196, -1.139, 0.025, 2.129, 5.681, 9.425, 9.195, 20.196, 20.027, 16.145, + 14.414, 12.09, 12.341, 3.692, -1.599, -4.193, -5.944, -7.102, -6.161, -3.615, 0.721, 6.513, + 11.468, 15.813, 19.067, 22.012, 23.197, 22.812, 22.067, 20.255, 17.723, 17.015, 19.134, 20.6, + 23.073, 25.905, 27.021, 27.283, 29.026, 30.169, 33.691, 32.195, 32.318, 32.229, 34.246, 38.587, + 40.661, 42.163, 39.829, 34.8, 29.979, 26.902, 25.604, 24.867, 22.805, 19.081, 16.161, 15.324, + 9.657, 5.136, 0.252, -4.912, -10.484, -16.147, -21.588, -26.369, -30.075, -32.753, -34.181, + -35.312, -35.292, -34.41, -32.967, -31.005, -28.543, -25.347, -21.495, -15.907, -10.143, + -0.653, 2.066, -0.603, 3.158, 5.379, 6.946, 9.476, 15.397, 21.218, 21.641, 22.999, 20.332, + 21.563, 23.348, 24.199, 20.88, 16.515, 13.75, 9.673, 6.124, 3.252, -0.088, -2.439, -4.249, + -6.74, -8.467, -9.367, -10.217, -11.52, -11.209, -11.487, -11.329, -11.332, -12.102, -12.089, + -10.719, -9.888, -9.44, -7.953, -7.322, -5.227, -4.253, -2.892, -2.466, -1.022, 2.195, 6.194, + 9.878, 11.348, 21.017, 25.453, 19.334, 18.12, 16.999, 15.266, 9.465, 1.464, -4.342, -5.88, + -7.042, -6.641, -4.041, 0.755, 5.56, 10.602, 14.639, 17.778, 20.148, 19.683, 18.72, 17.972, + 17.17, 17.322, 17.114, 18.745, 21.125, 23.666, 25.4, 25.946, 28.872, 31.583, 27.11, 27.65, + 27.528, 29.883, 27.074, 27.286, 29.597, 34.677, 34.075, 34.397, 32.631, 26.759, 23.774, 23.805, + 21.584, 17.988, 14.6, 11.573, 9.449, 4.152, -1.643, -6.779, -12.153, -17.699, -23.48, -28.341, + -32.399, -36.97, -39.23, -39.765, -40.003, -37.518, -38.495, -36.333, -33.46, -30.171, -25.905, + -18.351, -4.596, 1.302, 6.369, 12.019, 15.917, 10.788, 14.085, 14.77, 18.836, 24.472, 26.587, + 29.497, 35.881, 34.28, 23.348, 42.327, 23.755, 27.239, 20.425, 16.04, 11.322, 7.743, 4.666, + 1.398, -0.486, -2.917, -4.432, -7.994, -9.535, -10.484, -11.43, -11.876, -11.635, -10.902, + -11.093, -10.795, -10.776, -10.083, -9.533, -8.624, -7.383, -6.445, -5.717, -4.69, -2.863, + -1.367, 0.004, 2.651, 5.907, 8.906, 13.367, 15.119, 23.933, 25.533, 20.221, 16.87, 16.853, + 13.271, 8.329, -2.682, -6.051, -7.436, -6.88, -3.026, 1.244, 4.392, 7.515, 10.982, 13.822, + 15.873, 17.312, 16.268, 15.709, 16.516, 19.755, 19.778, 21.046, 22.09, 23.668, 25.611, 27.45, + 31.241, 34.048, 29.479, 29.76, 25.098, 25.687, 26.129, 20.673, 23.421, 30.347, 25.463, 24.022, + 23.967, 23.075, 20.051, 17.953, 15.56, 12.994, 9.289, 6.375, 2.652, -2.686, -8.012, -12.179, + -18.916, -24.492, -29.186, -33.285, -37.971, -40.816, -40.444, -37.71, -35.777, -26.987, + -28.006, -26.259, -21.978, -20.441, -14.388, -6.425, 2.694, 8.533, 11.392, 18.93, 26.312, + 20.29, 24.169, 23.656, 28.766, 30.629, 33.848, 37.513, 40.042, 41.59, 42.327, 47.718, 26.436, + 30.6, 24.698, 18.703, 13.809, 8.776, 4.33, 1.418, -0.647, -1.355, -4.508, -6.797, -8.162, + -9.912, -11.864, -13.062, -12.67, -11.535, -10.789, -10.335, -9.642, -8.852, -8.027, -7.185, + -6.247, -5.237, -4.052, -2.907, -0.794, 1.004, 1.782, 3.561, 6.743, 10.359, 14.895, 14.76, + 32.146, 23.94, 22.513, 18.102, 14.284, 10.169, 4.7, 0.776, -7.2, -8.956, -7.019, -1.371, 0.789, + 3.469, 4.684, 6.978, 9.535, 11.994, 14.082, 15.172, 15.145, 16.104, 18.672, 21.645, 25.474, + 23.656, 25.719, 26.663, 31.822, 33.577, 32.565, 32.687, 33.374, 30.945, 21.408, 19.585, 13.445, + 14.987, 19.449, 16.686, 13.943, 15.12, 14.171, 15.049, 11.713, 10.079, 7.452, 3.855, 0.259, + -5.026, -10.642, -15.805, -20.031, -25.117, -30.137, -33.396, -36.433, -37.845, -39.404, + -39.804, -38.403, -32.921, -24.331, -22.222, -20.618, -18.166, -16.535, -5.693, 0.704, 7.947, + 15.107, 20.617, 26.181, 31.89, 34.421, 29.521, 33.815, 36.191, 36.08, 42.736, 44.877, 45.223, + 45.355, 47.718, 48.179, 44.534, 33.574, 28.652, 19.239, 13.419, 8.805, 5.498, 1.649, -0.673, + -2.205, -4.07, -5.026, -8.773, -11.616, -13.102, -13.104, -12.085, -11.181, -9.708, -8.401, + -7.376, -6.453, -5.16, -4.746, -3.864, -2.516, -2.048, -0.919, 0.554, 1.68, 3.423, 5.158, + 7.888, 11.808, 16.261, 13.891, 40.433, 37.145, 24.029, 20.436, 15.145, 6.067, 6.504, 1.34, + -7.888, -9.948, -8.921, -6.595, -3.191, -1.566, 0.415, 3.285, 6.073, 8.848, 11.819, 13.744, + 14.723, 16.041, 18.286, 20.702, 24.189, 24.832, 25.474, 26.623, 32.015, 31.167, 29.36, 28.573, + 28.945, 28.333, 18.417, 13.043, 6.304, 7.634, 9.418, 8.123, 4.413, 4.347, 5.065, 3.961, 5.67, + 4.943, 1.124, -2.276, -7.795, -13.981, -19.278, -24.349, -27.423, -33.583, -37.471, -39.785, + -39.671, -38.86, -37.788, -37.793, -34.392, -22.829, -17.41, -15.146, -12.272, -10.186, -5.221, + 0.236, 7.115, 13.944, 20.011, 26.623, 33.986, 38.251, 42.648, 37.125, 40.348, 43.664, 42.978, + 47.908, 50.208, 50.162, 48.273, 48.179, 50.543, 51.066, 31.775, 28.042, 19.772, 14.199, 10.97, + 6.958, 3.373, 0.152, -3.32, -5.523, -8.321, -9.946, -11.476, -12.475, -12.116, -10.833, + -10.108, -8.595, -6.672, -5.069, -4.403, -4.23, -3.861, -3.177, -2.593, -1.461, -0.514, 0.486, + 1.57, 2.84, 4.619, 7.623, 10.785, 15.791, 17.404, 34.598, 41.795, 24.303, 20.006, 12.629, + 2.188, 0.005, -3.346, -5.055, -8.46, -10.438, -8.53, -6.66, -5.799, -4.656, -1.578, 1.525, + 5.603, 9.369, 12.178, 13.088, 14.276, 16.482, 19.189, 22.433, 27.246, 23.119, 25.466, 30.718, + 29.608, 25.774, 22.417, 16.897, 15.747, 9.56, 6.208, 3.014, 1.61, 7.635, 2.669, -1.857, -0.627, + -0.792, -1.663, -1.841, -3.496, -6.176, -11.344, -17.027, -23.25, -28.525, -32.937, -34.911, + -40.419, -42.96, -44.141, -43.886, -40.703, -36.111, -32.259, -30.178, -18.852, -11.572, + -4.796, -3.671, 0.178, 3.878, 7.265, 17.222, 26.22, 32.5, 35.012, 45.555, 49.338, 48.065, + 46.069, 46.89, 50.711, 50.138, 55.539, 53.304, 53.866, 51.282, 50.543, 50.179, 52.659, 35.511, + 28.396, 20.431, 14.203, 11.833, 8.862, 4.881, 1.097, -2.084, -5.374, -7.799, -9.464, -10.417, + -11.38, -11.837, -11.496, -10.064, -7.684, -5.5, -3.778, -2.821, -2.565, -2.75, -2.958, -3.249, + -3.257, -2.633, -1.376, -0.536, 1.021, 3.183, 8.108, 10.672, 15.835, 19.759, 38.635, 42.333, + 22.847, 21.062, 13.212, -0.9, -6.997, -7.075, -4.006, -7.072, -10.977, -8.339, -6.233, -5.978, + -6.165, -4.934, -1.546, 2.657, 7.246, 11.959, 12.697, 13.498, 15.067, 16.87, 19.173, 22.469, + 22.686, 24.769, 27.592, 28.634, 20.803, 16.553, 13.606, 7.642, 3.835, -4.457, -5.888, -5.84, + -2.724, -1.483, -9.131, -7.973, -9.639, -7.584, -8.674, -10.908, -14.636, -21.601, -27.69, + -33.465, -38.488, -42.087, -42.348, -46.021, -47.554, -46.401, -47.229, -42.064, -35.351, + -31.342, -26.859, -17.921, -7.768, 0.768, 7.426, 11.44, 17.504, 23.953, 31.032, 36.225, 43.507, + 46.774, 54.118, 55.379, 55.618, 53.56, 56.892, 56.945, 61.769, 56.587, 63.697, 61.781, 53.248, + 50.179, 50.458, 49.169, 46.883, 29.583, 21.071, 14.187, 11.569, 7.848, 5.759, 3.046, 3.198, + -2.681, -5.428, -6.669, -8.919, -10.786, -11.005, -10.464, -9.365, -7.362, -5.314, -3.444, + -2.179, -1.931, -2.578, -3.34, -4.366, -5.119, -5.054, -4.381, -3.194, -1.665, 0.963, 5.585, + 12.142, 17.085, 17.645, 44.583, 43.397, 21.725, 19.353, 11.001, -1.192, -6.306, -11.807, + -10.704, -9.498, -7.416, -3.884, -6.77, -5.548, -7.168, -6.082, -1.348, 3.437, 7.229, 10.528, + 12.496, 12.655, 13.723, 15.547, 15.763, 17.173, 17.595, 22.39, 24.17, 20.005, 14.197, 10.321, + 4.116, 3.313, -2.349, -9.867, -13.169, -13.787, -9.545, -5.086, -15.177, -15.696, -16.882, + -16.688, -18.267, -20.399, -26.067, -33.305, -39.595, -43.598, -48.525, -52.808, -51.852, + -52.365, -50.73, -49.378, -44.994, -41.402, -34.04, -27.344, -19.38, -11.676, -4.819, 8.553, + 17.473, 23.858, 28.898, 33.252, 39.24, 45.448, 49.794, 56.83, 59.5, 60.31, 59.567, 60.185, + 58.909, 57.882, 59.857, 57.503, 66.077, 62.842, 56.827, 50.458, 49.296, 44.99, 38.431, 28.787, + 19.852, 13.755, 10.572, 8.285, 6.314, 4.672, 1.504, -0.09, -3.226, -5.682, -9.107, -10.049, + -9.767, -9.412, -8.653, -7.774, -6.447, -4.765, -3.418, -3.131, -3.406, -4.79, -6.248, -6.721, + -6.547, -6.593, -5.495, -4.182, -1.485, 4.319, 11.871, 29.963, 42.858, 47.135, 23.226, 22.667, + 16.947, 3.096, -3.643, -7.517, -14.418, -12.107, -11.409, -7.607, -11.68, -8.023, -6.95, + -7.059, -5.165, -1.356, 2.974, 7.325, 9.85, 11.726, 12.927, 13.396, 13.483, 13.494, 13.905, + 15.112, 20.524, 22.402, 16.584, 10.062, 5.124, 1.595, -7.372, -11.403, -13.746, -19.367, + -21.31, -25.128, -17.497, -19.211, -22.387, -23.038, -22.692, -28.987, -31.661, -38.092, + -46.285, -51.941, -55.107, -58.116, -61.234, -56.418, -57.0, -53.717, -48.064, -41.76, -34.11, + -28.336, -18.214, -12.058, -2.617, 3.445, 15.726, 27.973, 35.053, 36.831, 42.869, 48.631, + 53.026, 56.303, 64.044, 63.429, 63.793, 61.912, 63.463, 62.953, 61.003, 59.356, 64.852, 64.086, + 59.459, 54.582, 49.296, 42.085, 34.751, 30.293, 24.761, 18.479, 14.778, 14.633, 9.494, 6.838, + 4.326, 2.645, -0.043, -3.426, -4.78, -5.312, -7.503, -8.541, -9.131, -9.381, -9.126, -8.671, + -7.697, -6.198, -5.575, -5.886, -7.426, -9.19, -9.704, -9.448, -8.988, -7.816, -5.335, -2.052, + 3.594, 9.754, 34.781, 32.747, 29.291, 28.367, 20.188, 10.194, 0.352, -8.245, -14.546, -15.964, + -15.684, -13.476, -11.676, -12.285, -9.405, -8.918, -7.548, -4.801, -0.265, 4.976, 8.608, + 10.463, 11.097, 12.387, 12.296, 11.31, 11.245, 12.272, 14.818, 17.265, 22.597, 15.2, 7.296, + 1.317, -2.859, -8.418, -14.008, -19.465, -22.839, -27.048, -27.154, -24.884, -28.398, -29.841, + -31.669, -36.065, -39.312, -43.524, -50.345, -58.076, -64.339, -68.065, -68.383, -67.346, + -66.982, -62.502, -55.668, -43.688, -35.369, -23.373, -13.66, -6.395, 3.35, 7.7, 14.772, + 23.246, 34.648, 41.119, 46.16, 54.415, 58.984, 62.477, 64.028, 68.805, 67.24, 65.636, 66.119, + 67.509, 64.072, 61.39, 55.397, 61.138, 57.761, 52.453, 46.739, 42.085, 31.836, 27.206, 24.349, + 21.494, 17.593, 15.304, 12.992, 9.659, 8.213, 7.535, 5.449, 2.328, 0.261, -0.562, -2.462, + -5.37, -8.422, -10.137, -11.292, -11.447, -12.469, -11.738, -10.459, -9.241, -9.09, -10.117, + -11.974, -12.419, -12.377, -11.827, -9.878, -6.665, -1.969, -2.178, 22.836, 17.112, 24.91, + 25.107, 17.267, 11.775, 2.672, -7.134, -14.722, -16.514, -20.36, -18.906, -14.328, -11.165, + -6.958, -10.91, -9.471, -7.121, -3.454, 2.265, 7.898, 11.74, 14.003, 14.051, 14.188, 14.144, + 11.72, 9.427, 9.455, 10.314, 12.888, 14.301, 6.742, 1.022, -5.128, -8.221, -13.583, -11.331, + -21.239, -25.609, -33.32, -34.939, -37.507, -33.444, -35.368, -38.094, -39.948, -49.024, + -55.735, -62.396, -68.232, -76.099, -79.572, -77.915, -75.39, -70.018, -64.473, -54.105, + -42.323, -29.222, -16.536, -9.079, -2.062, 11.968, 23.88, 35.933, 41.071, 32.511, 41.181, + 40.867, 56.201, 63.963, 67.47, 71.714, 74.082, 76.752, 76.524, 73.568, 70.371, 64.311, 54.175, + 57.048, 52.779, 45.38, 40.781, 36.21, 31.836, 26.169, 21.227, 19.204, 17.728, 16.903, 16.077, + 15.338, 12.331, 12.036, 10.611, 8.803, 5.968, 4.39, 1.626, -1.091, -4.959, -7.901, -10.181, + -12.496, -14.346, -15.063, -15.354, -14.802, -13.213, -12.593, -12.765, -13.537, -13.53, + -13.721, -12.733, -10.314, -6.233, -0.994, 9.775, 18.218, 12.674, 22.807, 21.458, 11.398, + 0.515, -6.429, -12.731, -20.546, -19.676, -24.332, -24.263, -18.473, -10.183, -4.949, -7.925, + -6.843, -4.631, -0.743, 4.114, 10.209, 14.05, 17.517, 17.268, 16.338, 16.772, 16.029, 10.86, + 8.034, 7.426, 10.513, 5.436, 0.241, -7.469, -14.395, -15.313, -14.156, -17.424, -19.732, + -28.095, -37.511, -39.955, -41.151, -40.216, -41.399, -44.393, -51.107, -58.629, -65.821, + -72.113, -75.648, -87.213, -89.038, -88.431, -83.964, -74.443, -62.989, -50.591, -37.228, + -21.4, -12.357, 7.423, 21.241, 29.111, 36.978, 44.208, 49.879, 51.56, 54.183, 53.02, 44.337, + 66.552, 69.732, 74.077, 83.381, 73.022, 80.946, 56.987, 64.489, 60.105, 56.152, 49.44, 44.175, + 38.768, 34.149, 31.145, 26.169, 23.261, 19.967, 18.19, 18.085, 16.428, 15.737, 15.001, 14.577, + 14.497, 13.928, 12.175, 9.192, 5.911, 2.644, -1.144, -5.232, -8.36, -11.504, -14.939, -17.022, + -18.639, -19.388, -18.685, -17.278, -16.221, -15.389, -14.701, -13.899, -13.053, -11.386, + -8.182, -4.207, 1.64, 4.181, 13.283, 16.509, 19.709, 13.68, 5.382, -5.131, -11.993, -15.356, + -19.934, -22.596, -26.152, -27.527, -20.148, -10.708, -10.083, -6.373, -3.676, -0.626, 2.375, + 6.551, 11.367, 16.588, 19.536, 19.436, 18.453, 17.729, 18.286, 15.737, 11.543, 7.543, 4.385, + 1.725, -10.254, -15.168, -19.923, -15.929, -8.784, -17.931, -18.729, -24.723, -37.497, -43.211, + -45.919, -44.839, -46.018, -51.229, -58.215, -66.24, -72.866, -80.051, -88.8, -94.787, -97.272, + -95.672, -88.768, -76.906, -62.875, -47.696, -31.195, -22.618, 5.187, 15.64, 24.214, 34.077, + 43.775, 52.595, 62.337, 57.041, 61.207, 59.997, 63.917, 69.398, 74.939, 76.927, 78.593, 79.821, + 77.031, 66.655, 62.768, 56.19, 49.881, 43.551, 39.586, 34.189, 29.703, 26.282, 23.261, 21.281, + 18.956, 17.272, 15.398, 14.959, 14.698, 15.971, 16.832, 16.833, 14.565, 12.914, 10.178, 6.324, + 2.255, -2.276, -6.763, -10.42, -14.315, -18.138, -21.137, -22.984, -23.879, -22.634, -20.902, + -19.07, -17.383, -15.614, -13.366, -11.167, -8.787, -4.059, -1.509, 2.868, 8.397, 27.692, + 18.993, 18.759, 11.044, 1.145, -5.829, -13.356, -22.364, -24.977, -23.961, -26.866, -23.28, + -23.264, -16.703, -10.509, -3.773, 2.45, 7.805, 10.116, 11.057, 13.225, 18.963, 19.276, 19.706, + 19.514, 17.893, 17.225, 17.132, 16.711, 12.141, 9.109, -1.272, -11.493, -18.198, -20.86, + -14.527, -10.781, -14.875, -14.399, -23.357, -33.294, -43.575, -49.142, -49.086, -50.697, + -55.483, -62.594, -70.744, -77.374, -86.473, -95.003, -100.417, -102.55, -101.565, -92.77, + -79.041, -63.286, -46.871, -29.698, -12.419, 1.655, 14.454, 25.242, 36.737, 48.974, 54.123, + 59.827, 54.631, 45.998, 73.789, 71.983, 72.74, 69.986, 72.516, 70.653, 66.155, 62.403, 58.168, + 58.656, 51.796, 44.886, 40.652, 36.349, 31.181, 26.953, 23.399, 21.281, 18.929, 17.082, 15.971, + 14.168, 13.852, 15.165, 16.419, 17.902, 16.164, 13.72, 10.529, 7.776, 4.028, -0.144, -4.97, + -9.95, -14.387, -18.356, -22.126, -25.361, -27.476, -27.803, -26.414, -24.441, -21.77, -18.626, + -15.732, -12.459, -8.965, -5.412, -2.157, 1.069, 5.761, 11.743, 16.023, 22.263, 11.584, 3.455, + -6.699, -9.112, -18.231, -24.893, -30.331, -31.124, -28.985, -28.787, -22.803, -15.239, -6.746, + 1.057, 6.472, 9.114, 11.528, 13.449, 15.546, 17.58, 20.477, 21.164, 19.646, 18.399, 16.799, + 15.211, 17.744, 15.191, 11.641, 4.066, -4.898, -13.539, -12.451, -12.009, -10.833, -13.373, + -16.89, -21.593, -29.182, -34.638, -46.928, -51.547, -52.459, -56.845, -63.184, -70.618, + -78.907, -90.016, -97.365, -101.038, -103.361, -103.551, -94.961, -80.324, -60.397, -48.794, + -31.766, -12.898, -1.141, 9.729, 21.027, 31.967, 45.487, 55.894, 57.125, 64.739, 66.642, + 66.882, 74.255, 70.708, 68.792, 68.213, 65.616, 63.677, 57.479, 54.441, 54.374, 49.542, 43.074, + 37.757, 32.03, 28.679, 24.801, 20.717, 18.929, 15.896, 15.79, 13.288, 11.891, 13.174, 14.225, + 16.609, 16.116, 13.489, 10.829, 7.27, 3.737, 0.111, -4.673, -9.812, -14.614, -18.805, -22.886, + -26.61, -29.839, -31.779, -32.125, -30.683, -27.72, -23.764, -19.761, -15.069, -10.846, -7.45, + -4.042, -0.566, 4.299, 8.913, 12.936, 11.967, 18.43, 5.749, -6.357, -9.299, -16.349, -23.961, + -28.032, -31.706, -35.651, -37.515, -32.107, -24.151, -16.198, -6.81, 2.178, 6.766, 10.051, + 13.537, 17.285, 18.305, 20.949, 24.586, 30.476, 29.237, 27.364, 25.462, 18.106, 18.395, 21.363, + 17.613, 10.762, 1.768, -5.933, -6.614, -10.32, -10.728, -12.965, -13.473, -14.11, -25.141, + -30.944, -39.524, -52.177, -53.988, -55.258, -60.082, -70.265, -81.622, -91.376, -97.202, + -100.756, -104.592, -97.739, -95.037, -79.289, -59.93, -53.81, -33.735, -18.892, -7.729, 1.061, + 14.046, 24.368, 35.038, 52.595, 60.237, 65.372, 62.108, 67.725, 67.252, 65.829, 65.817, 64.611, + 62.839, 60.431, 56.644, 52.498, 49.74, 45.015, 38.549, 32.618, 28.997, 24.922, 22.767, 18.584, + 15.896, 13.688, 12.07, 10.136, 11.443, 12.539, 13.723, 13.047, 11.392, 8.867, 6.226, 3.052, + 0.108, -3.729, -8.563, -13.708, -18.984, -24.69, -28.908, -32.993, -36.054, -37.229, -36.623, + -34.289, -30.14, -25.036, -19.881, -14.765, -10.255, -5.91, -2.041, 1.627, 5.991, 10.643, + 9.668, 11.43, -3.127, -11.45, -11.74, -17.937, -32.805, -33.359, -40.119, -41.553, -43.051, + -39.158, -32.274, -23.077, -14.146, -7.76, -2.521, 2.866, 8.468, 13.386, 19.589, 20.876, + 29.093, 29.87, 35.08, 29.316, 27.298, 24.53, 25.167, 22.776, 22.599, 17.881, 11.644, 3.944, + -1.178, -1.749, -5.454, -8.184, -9.338, -7.091, -7.767, -15.0, -22.003, -28.846, -41.159, + -51.844, -50.837, -57.944, -70.226, -80.428, -89.692, -95.524, -99.261, -97.329, -95.138, + -92.087, -78.335, -62.179, -60.332, -39.101, -24.996, -17.065, -6.303, 6.312, 17.866, 30.874, + 42.077, 54.688, 61.035, 69.577, 62.219, 61.195, 62.384, 59.571, 61.111, 55.031, 54.468, 55.671, + 46.122, 43.011, 38.35, 34.645, 29.192, 28.34, 27.005, 20.739, 17.888, 13.688, 11.046, 11.364, + 10.493, 10.606, 11.874, 12.051, 9.798, 7.794, 4.935, 1.807, -1.261, -3.941, -7.324, -11.688, + -17.297, -22.859, -28.446, -33.793, -38.104, -40.999, -42.245, -40.913, -37.627, -32.761, + -26.9, -20.319, -14.018, -9.156, -5.919, -1.884, -2.028, -0.518, 7.265, 2.523, -3.84, -16.027, + -15.743, -23.842, -31.73, -37.681, -49.112, -47.85, -44.812, -43.157, -38.043, -28.747, -21.96, + -16.895, -10.7, -3.713, 3.315, 10.061, 14.903, 18.163, 21.67, 29.424, 33.029, 32.131, 29.461, + 26.985, 24.69, 22.759, 21.263, 21.784, 17.591, 12.894, 8.449, 5.139, 3.73, 0.174, -0.484, + -3.59, -5.102, -3.457, -9.647, -16.952, -23.294, -30.252, -40.308, -46.465, -56.756, -66.501, + -76.091, -84.932, -89.821, -90.858, -91.745, -96.354, -88.79, -78.672, -64.163, -61.593, + -45.92, -32.153, -23.43, -13.344, 1.403, 8.736, 22.425, 36.506, 48.645, 55.484, 46.828, 55.526, + 53.925, 55.294, 56.186, 47.262, 38.178, 46.553, 44.637, 39.983, 35.72, 32.517, 30.012, 30.235, + 23.469, 20.423, 17.282, 14.295, 11.046, 8.619, 9.047, 8.341, 11.148, 10.382, 9.693, 7.311, + 4.665, 1.978, -2.126, -4.171, -7.399, -11.758, -14.869, -20.013, -26.083, -32.421, -37.488, + -41.252, -44.338, -44.817, -43.55, -39.409, -33.807, -28.544, -20.921, -14.833, -9.864, -9.279, + -4.933, 2.378, 4.996, 1.309, -2.988, -9.837, -18.027, -23.772, -31.683, -37.67, -39.512, + -55.776, -49.198, -46.809, -40.968, -32.754, -25.715, -21.117, -14.581, -7.64, 0.031, 8.057, + 15.663, 24.892, 21.682, 27.885, 31.06, 29.698, 29.752, 28.254, 28.353, 22.605, 22.239, 20.232, + 20.725, 17.516, 13.577, 10.587, 9.28, 9.707, 6.923, 3.91, 0.496, -0.875, 0.599, -7.361, -8.854, + -14.981, -24.185, -31.635, -39.76, -53.085, -60.745, -69.813, -79.131, -83.816, -83.381, + -86.547, -87.923, -84.415, -75.933, -64.035, -61.964, -46.816, -36.039, -28.978, -20.596, + -5.505, 1.583, 13.699, 26.806, 41.428, 41.618, 45.562, 47.621, 48.555, 50.312, 51.966, 52.301, + 54.91, 37.393, 43.993, 38.303, 31.378, 29.335, 25.093, 22.658, 17.868, 15.466, 12.826, 11.38, + 8.619, 5.911, 6.38, 8.815, 8.739, 9.187, 7.598, 6.573, 6.973, 3.576, -1.614, -5.882, -9.464, + -14.742, -19.988, -24.71, -29.927, -35.571, -39.729, -43.081, -45.725, -46.507, -44.821, + -40.768, -34.987, -29.755, -22.713, -13.862, -6.41, -10.801, -10.595, -6.707, -10.987, -11.956, + -12.589, -15.729, -23.854, -31.826, -41.523, -41.7, -43.098, -57.791, -46.847, -41.602, + -37.413, -29.842, -22.538, -17.54, -11.271, -3.28, 6.482, 14.666, 19.872, 24.753, 26.793, + 26.623, 32.967, 30.139, 27.789, 27.12, 27.462, 28.415, 25.617, 23.379, 26.998, 21.545, 17.631, + 13.519, 11.569, 12.077, 10.731, 7.132, 5.918, 3.554, -0.382, -2.654, -9.243, -22.452, -28.518, + -32.535, -35.331, -47.252, -53.88, -62.046, -68.84, -70.815, -74.337, -74.636, -74.004, + -71.401, -70.963, -63.121, -58.889, -46.671, -38.752, -32.242, -25.101, -17.034, -6.598, 4.849, + 18.117, 30.048, 32.157, 39.649, 41.587, 42.403, 44.721, 48.559, 50.179, 51.385, 37.034, 40.96, + 35.955, 30.581, 25.007, 21.511, 18.227, 15.953, 14.372, 9.626, 7.249, 5.911, 2.597, 2.021, + 5.111, 7.764, 9.166, 9.362, 8.182, 6.166, 9.47, -2.691, -7.9, -12.28, -17.363, -21.993, + -26.615, -32.065, -36.367, -40.945, -44.403, -46.922, -47.294, -45.814, -41.615, -35.853, + -30.406, -21.39, -12.597, -9.362, -18.931, -20.312, -13.719, -11.095, -20.041, -22.694, -22.61, + -33.999, -44.882, -50.871, -51.979, -50.639, -48.729, -44.116, -40.473, -34.023, -25.685, + -16.366, -11.737, -6.116, 1.021, 10.676, 17.562, 18.905, 22.337, 24.074, 27.664, 35.127, 35.57, + 31.005, 27.706, 27.153, 30.335, 32.081, 28.658, 28.191, 24.08, 22.193, 28.41, 14.432, 13.532, + 13.186, 9.877, 9.318, 7.886, 3.368, 4.05, -7.916, -24.091, -33.133, -35.694, -34.133, -39.962, + -47.557, -55.367, -56.402, -60.372, -62.984, -63.483, -64.403, -61.884, -61.636, -56.252, + -51.34, -46.828, -39.961, -34.253, -28.062, -22.234, -10.861, -0.385, 12.319, 18.389, 25.621, + 32.498, 36.026, 38.119, 40.869, 45.996, 48.38, 47.608, 29.231, 36.267, 32.101, 25.732, 19.456, + 16.182, 12.099, 9.307, 6.276, 4.651, 5.699, 2.597, -1.951, 0.069, 1.949, 4.333, 7.267, 8.901, + 5.344, 3.767, 2.484, -4.453, -10.043, -14.097, -18.476, -22.488, -27.434, -32.454, -36.7, + -41.215, -44.313, -46.787, -47.036, -44.893, -41.373, -35.206, -30.364, -19.465, -15.706, + -17.836, -27.776, -28.273, -27.653, -22.769, -25.233, -26.17, -26.581, -39.822, -47.585, + -51.921, -51.304, -52.44, -50.035, -45.571, -38.571, -30.49, -21.214, -11.185, -4.91, 0.287, + 5.377, 11.594, 17.273, 19.628, 22.935, 26.532, 31.012, 37.593, 37.754, 33.379, 30.109, 26.774, + 29.46, 32.289, 36.906, 34.179, 27.123, 25.108, 27.275, 20.134, 14.579, 15.529, 12.667, 11.026, + 8.367, 8.76, 5.618, -0.978, -18.031, -30.434, -32.967, -26.852, -37.753, -44.999, -45.753, + -48.447, -50.688, -54.075, -56.542, -59.609, -58.338, -55.475, -54.541, -51.009, -47.422, + -40.293, -34.679, -30.48, -25.847, -16.213, -5.642, 6.274, 17.719, 17.594, 27.825, 32.691, + 37.279, 38.145, 43.974, 47.631, 28.221, 35.708, 33.53, 25.374, 20.108, 16.599, 10.459, 5.11, + 3.072, -0.04, -1.064, -1.804, -1.951, -4.105, -0.819, -2.924, -0.298, 2.627, 2.635, 0.442, + -1.916, -5.919, -9.448, -12.662, -16.052, -19.457, -24.358, -28.922, -33.146, -37.647, -41.667, + -44.523, -45.742, -45.186, -43.232, -37.298, -35.542, -27.028, -22.255, -20.322, -25.279, + -27.878, -28.779, -27.054, -26.978, -24.904, -27.056, -33.553, -43.71, -49.913, -51.497, + -48.336, -49.272, -47.536, -42.66, -35.181, -26.189, -15.151, -3.695, 3.398, 8.585, 13.814, + 18.249, 22.832, 25.681, 25.541, 29.734, 34.569, 32.414, 39.14, 38.528, 33.792, 32.426, 25.555, + 26.389, 29.981, 29.12, 29.472, 27.974, 29.024, 22.987, 18.113, 14.149, 13.409, 14.955, 13.082, + 12.897, 8.63, -2.42, -15.516, -27.143, -25.242, -27.857, -23.534, -30.163, -34.048, -43.821, + -44.765, -47.329, -57.392, -65.908, -67.031, -51.223, -43.063, -51.225, -49.063, -39.314, + -33.486, -31.829, -27.834, -19.585, -10.536, 1.11, 12.176, 20.968, 29.772, 25.871, 33.265, + 36.842, 41.537, 42.062, 32.947, 32.066, 25.318, 18.394, 13.341, 8.406, 4.192, 0.238, -2.789, + -5.522, -6.036, -4.65, -4.105, -7.199, -7.678, -5.066, -5.308, -5.679, -5.73, -6.996, -9.477, + -11.953, -13.124, -15.88, -18.355, -22.717, -26.699, -30.391, -34.317, -37.745, -41.253, + -42.74, -43.239, -42.463, -40.189, -36.436, -31.672, -25.422, -23.889, -24.026, -23.553, + -28.588, -28.283, -27.438, -27.984, -28.795, -29.979, -38.942, -45.845, -51.4, -50.545, + -45.649, -42.167, -40.635, -36.298, -29.985, -20.75, -9.999, 1.496, 11.476, 18.318, 23.505, + 27.595, 30.224, 30.368, 29.899, 33.304, 36.003, 39.758, 41.913, 48.302, 47.682, 41.631, 34.404, + 29.55, 26.824, 26.77, 30.73, 29.679, 28.428, 24.396, 22.428, 17.987, 16.055, 17.813, 18.847, + 12.938, 5.012, -3.917, -15.356, -12.937, -7.509, -6.924, -15.271, -24.389, -28.787, -32.794, + -48.548, -47.092, -48.164, -28.99, -26.628, -30.676, -33.749, -35.087, -35.263, -35.76, + -32.239, -41.82, -33.354, -21.873, -15.07, -3.382, 7.855, 17.282, 25.354, 30.686, 26.905, + 35.637, 39.297, 34.268, 29.943, 25.591, 19.402, 13.833, 9.057, 4.31, -0.156, -3.635, -6.322, + -6.858, -6.359, -6.888, -7.199, -9.421, -10.397, -10.573, -11.029, -11.118, -10.866, -11.688, + -13.41, -14.967, -15.981, -19.589, -23.491, -26.842, -29.382, -32.417, -35.938, -38.869, + -40.616, -41.371, -41.011, -38.304, -33.452, -32.965, -29.028, -23.46, -22.41, -24.842, + -30.072, -26.494, -27.076, -27.952, -30.108, -28.412, -32.532, -38.894, -47.627, -50.619, + -47.351, -42.153, -37.487, -34.588, -30.583, -24.653, -15.465, -4.58, 6.6, 17.412, 27.793, + 33.377, 37.144, 39.111, 37.971, 35.454, 36.4, 45.266, 42.678, 42.373, 45.627, 52.601, 51.611, + 44.937, 39.068, 30.057, 31.18, 32.933, 30.127, 27.419, 28.106, 14.56, 6.967, 11.418, 15.479, + 23.269, 18.759, 8.533, -3.707, -2.29, 2.948, -3.772, -10.507, -14.309, -19.847, -22.92, + -27.044, -48.093, -41.711, -19.738, -27.587, -30.495, -33.814, -36.643, -38.772, -40.71, + -36.61, -34.88, -37.611, -33.407, -25.665, -18.042, -6.091, 4.789, 15.476, 23.567, 30.691, + 30.87, 34.338, 37.198, 33.521, 27.364, 22.617, 15.672, 10.284, 5.639, 3.271, -4.034, -8.158, + -8.832, -10.21, -9.228, -9.503, -9.421, -11.161, -11.544, -12.847, -13.521, -13.714, -12.987, + -14.132, -15.25, -16.668, -19.448, -21.569, -24.757, -28.685, -32.032, -35.017, -37.335, + -39.148, -40.039, -40.276, -37.68, -34.189, -29.259, -26.677, -23.247, -21.362, -18.85, + -26.707, -28.443, -29.57, -28.991, -29.058, -29.698, -31.603, -33.867, -35.515, -39.156, + -44.614, -43.285, -39.379, -35.45, -30.319, -25.855, -18.249, -9.082, 0.269, 10.854, 21.856, + 31.543, 40.984, 46.777, 48.304, 48.622, 46.832, 42.904, 42.869, 49.462, 46.969, 44.974, 41.981, + 48.355, 47.931, 46.493, 43.727, 42.178, 39.598, 37.881, 28.589, 14.337, 27.437, 24.1, 14.315, + 26.95, 25.822, 22.216, 16.021, 11.022, 11.639, 6.772, -3.193, -11.8, -17.82, -28.253, -28.939, + -36.975, -29.131, -29.863, -25.943, -32.321, -35.131, -39.283, -42.024, -43.797, -44.931, + -42.978, -42.991, -40.179, -34.358, -25.252, -16.286, -6.717, 4.364, 13.166, 21.978, 29.283, + 30.164, 34.926, 42.775, 31.441, 22.232, 20.967, 14.284, 8.301, 3.614, 0.571, -4.899, -8.221, + -9.622, -11.348, -10.848, -10.562, -11.161, -12.66, -12.439, -12.47, -11.633, -11.428, -11.455, + -13.032, -13.587, -15.985, -18.205, -21.341, -23.942, -28.066, -31.756, -34.356, -35.751, + -36.987, -36.889, -36.104, -29.395, -23.797, -22.54, -20.67, -18.032, -15.749, -15.502, + -23.879, -26.482, -31.24, -33.16, -31.904, -33.379, -34.387, -34.037, -34.114, -36.257, + -39.015, -37.74, -36.212, -31.899, -26.83, -22.019, -13.447, -3.57, 5.116, 13.894, 23.797, + 33.38, 42.559, 51.947, 57.448, 58.358, 54.954, 50.713, 49.484, 49.52, 48.596, 54.256, 54.285, + 53.505, 49.71, 47.468, 44.264, 45.942, 43.017, 42.886, 29.415, 27.809, 39.703, 39.177, 38.899, + 36.632, 34.575, 30.727, 26.654, 20.753, 10.686, -18.416, -20.515, -21.56, -29.468, -34.286, + -38.042, -34.211, -30.575, -36.268, -50.44, -52.141, -59.616, -63.094, -54.794, -55.972, + -50.069, -47.206, -50.853, -44.965, -36.513, -25.207, -14.367, -7.771, 1.464, 12.659, 20.673, + 23.14, 26.163, 30.28, 34.473, 41.349, 15.5, 21.671, 15.938, 9.327, 3.889, -1.039, -4.407, + -8.359, -10.946, -13.379, -11.712, -12.336, -12.66, -11.119, -10.741, -9.845, -8.541, -8.41, + -8.434, -9.791, -10.362, -12.428, -14.732, -17.515, -21.132, -24.049, -26.605, -29.441, + -31.117, -31.569, -30.638, -30.002, -23.261, -20.241, -17.552, -14.888, -13.681, -14.56, + -14.225, -19.256, -23.599, -27.77, -31.891, -33.37, -34.384, -35.325, -35.476, -32.415, + -30.671, -29.977, -28.063, -25.038, -25.948, -24.025, -16.442, -7.772, 3.809, 12.153, 20.455, + 28.935, 38.482, 46.171, 53.468, 60.357, 61.612, 59.903, 57.599, 54.359, 51.315, 50.94, 55.855, + 56.89, 54.876, 50.592, 49.939, 45.434, 50.195, 48.463, 45.921, 38.764, 44.902, 44.486, 40.142, + 30.284, 29.468, 24.742, 18.153, 19.582, 15.487, -1.344, -12.84, -13.867, -22.806, -27.943, + -33.141, -39.174, -43.24, -36.16, -36.833, -37.461, -44.848, -58.059, -62.111, -62.386, + -63.674, -57.528, -56.112, -52.328, -45.403, -35.744, -26.179, -15.742, -6.075, 2.062, 9.7, + 19.78, 26.06, 23.118, 26.222, 29.126, 32.978, 14.824, 10.26, 17.36, 13.293, 7.08, 1.879, + -2.445, -5.859, -8.994, -11.483, -10.536, -11.783, -11.119, -6.338, -5.488, -4.115, -3.688, + -2.729, -2.673, -3.257, -4.875, -7.31, -9.941, -13.104, -15.79, -18.843, -22.31, -25.501, + -27.38, -27.761, -26.416, -27.464, -22.222, -19.292, -15.268, -12.277, -8.062, -10.721, + -14.405, -19.541, -23.766, -26.192, -27.669, -33.583, -37.663, -36.463, -37.111, -35.065, + -31.872, -28.379, -25.667, -22.66, -19.314, -15.153, -6.765, 3.63, 14.119, 21.417, 27.979, + 34.319, 41.538, 49.004, 55.159, 61.501, 64.773, 64.493, 61.96, 58.536, 57.733, 54.012, 47.976, + 44.993, 45.952, 46.767, 52.657, 53.231, 41.398, 42.658, 45.374, 45.845, 43.917, 38.108, 32.0, + 30.628, 25.357, 17.122, 12.234, 11.712, 0.844, -7.142, -11.922, -17.839, -23.609, -29.048, + -33.346, -37.82, -40.747, -43.878, -47.409, -49.16, -45.624, -59.071, -66.659, -58.261, + -55.448, -52.755, -49.139, -47.773, -43.443, -37.164, -28.8, -17.588, -8.017, 0.054, 6.531, + 13.868, 20.886, 23.741, 28.328, 25.548, 29.251, 27.781, 26.695, 13.366, 3.177, 11.586, 6.67, + 1.727, -3.29, -7.141, -9.367, -8.595, -7.061, -6.338, -0.86, 0.693, 1.962, 3.767, 4.213, 4.401, + 3.739, 2.251, -0.117, -2.563, -5.092, -8.524, -12.238, -15.949, -19.131, -21.24, -21.572, + -21.89, -22.808, -19.984, -17.968, -16.561, -14.872, -14.443, -15.928, -17.163, -18.238, + -23.479, -27.102, -30.559, -32.661, -36.92, -37.184, -37.27, -37.402, -33.108, -29.549, -26.53, + -20.717, -17.871, -13.97, -1.221, 7.943, 16.41, 27.376, 35.017, 37.573, 43.892, 50.597, 56.077, + 61.827, 65.517, 63.934, 62.715, 60.8, 57.453, 54.267, 51.877, 52.462, 49.76, 47.26, 45.943, + 48.179, 48.67, 45.341, 46.501, 43.414, 40.881, 37.973, 33.515, 29.901, 24.126, 20.026, 14.395, + 7.245, -2.845, -11.626, -15.143, -18.943, -20.888, -23.648, -30.765, -32.435, -35.837, -40.529, + -42.879, -42.573, -45.775, -50.701, -50.154, -44.437, -48.636, -46.569, -44.03, -43.66, + -41.051, -34.08, -27.95, -20.653, -12.435, -1.365, 5.518, 11.623, 16.743, 19.433, 22.029, + 25.577, 21.705, 22.354, 19.815, 20.215, 24.162, 2.548, 10.367, 6.416, 2.118, -3.845, -3.073, + -2.555, -1.38, -0.86, -8.515, -8.22, -10.331, -5.09, 5.37, 9.854, 10.609, 9.689, 7.264, 5.293, + 2.623, 0.086, -3.109, -7.511, -11.399, -14.26, -15.735, -15.816, -13.179, -13.028, -15.588, + -13.696, -16.897, -18.906, -19.873, -20.599, -22.949, -28.54, -31.019, -33.758, -36.643, + -39.795, -41.298, -41.242, -40.731, -35.792, -31.809, -23.644, -19.768, -16.301, -10.125, + -1.747, 11.275, 20.014, 24.928, 33.593, 40.756, 47.789, 53.26, 58.091, 62.162, 62.939, 63.118, + 62.526, 58.81, 58.889, 58.518, 58.007, 54.715, 51.025, 45.476, 44.607, 45.496, 47.89, 45.581, + 42.544, 39.302, 35.917, 29.167, 29.666, 24.627, 20.398, 14.209, 11.324, 7.264, 2.886, -6.783, + -11.893, -15.376, -18.235, -18.134, -24.528, -26.756, -29.59, -33.192, -37.56, -40.368, + -42.807, -40.001, -39.356, -40.411, -42.422, -42.516, -39.125, -37.749, -36.779, -33.967, + -27.164, -21.32, -13.66, -5.07, 2.598, 8.596, 12.001, 17.437, 20.59, 20.33, 19.946, 18.655, + 17.531, 18.988, 21.445, 24.716, 6.711, 7.509, 7.893, 5.501, 2.767, -3.524, -10.037, -8.515, + 5.855, 3.004, 5.033, 8.464, 12.683, 17.569, 8.608, 8.265, 9.524, 11.11, 10.584, 6.829, 2.916, + -1.113, -4.062, -7.775, -7.778, -8.899, -11.139, -13.34, -13.363, -16.524, -20.081, -23.239, + -24.918, -25.994, -30.131, -32.032, -36.801, -39.524, -42.59, -45.583, -45.112, -44.437, + -42.296, -37.209, -31.129, -24.535, -19.946, -16.165, -8.718, 1.863, 13.66, 21.066, 29.78, + 37.779, 44.513, 51.349, 58.085, 60.297, 60.778, 61.144, 60.681, 60.212, 61.07, 58.295, 59.35, + 58.394, 56.755, 52.902, 45.913, 41.743, 40.077, 39.691, 38.955, 35.097, 30.249, 28.746, 26.952, + 24.249, 19.688, 16.676, 14.854, 10.44, 8.085, 6.006, 2.827, -0.235, -5.121, -10.382, -11.367, + -17.983, -23.302, -26.936, -29.541, -34.09, -37.728, -38.726, -39.17, -40.235, -37.134, -39.35, + -36.684, -37.201, -38.667, -34.274, -32.29, -26.874, -20.737, -15.078, -8.566, -2.449, 3.817, + 7.83, 12.967, 17.213, 16.769, 17.123, 16.703, 16.714, 18.803, 19.635, 22.369, 24.393, 3.967, + 4.947, 2.342, 3.849, 2.697, 2.411, 5.855, 1.982, 2.651, 5.677, 11.27, 12.671, 14.414, 15.248, + 14.308, 11.602, 14.401, 11.039, 7.914, 7.431, 3.963, 0.12, 1.878, 0.054, -2.356, -5.538, + -10.247, -14.691, -19.26, -22.028, -25.895, -29.397, -30.94, -33.567, -37.731, -41.67, -45.949, + -47.344, -48.114, -47.696, -44.64, -41.879, -36.353, -30.576, -26.304, -16.166, -9.872, -0.932, + 8.101, 15.856, 23.813, 31.836, 39.645, 45.554, 50.942, 57.562, 62.239, 61.885, 61.348, 61.134, + 61.813, 60.0, 60.449, 55.435, 57.925, 56.153, 52.224, 46.853, 43.848, 41.687, 39.488, 37.394, + 32.465, 26.367, 22.692, 20.98, 20.348, 17.836, 16.791, 13.42, 12.924, 9.293, 8.631, 6.673, + 2.365, -3.252, -4.709, -6.755, -14.485, -19.235, -23.576, -27.612, -29.582, -32.912, -34.041, + -35.523, -36.926, -38.277, -39.099, -40.573, -40.437, -36.48, -34.724, -32.898, -23.864, + -21.352, -14.032, -9.539, -5.126, 1.545, 8.565, 11.53, 12.739, 15.436, 13.921, 15.426, 17.702, + 17.899, 16.367, 19.029, 20.631, 17.758, 10.495, 8.012, 5.309, 2.124, 1.108, 1.982, 0.932, 4.94, + 7.784, 9.311, 10.893, 11.677, 13.02, 14.199, 14.918, 13.166, 14.39, 12.393, 11.366, 10.808, + 11.558, 7.197, 2.626, -1.787, -4.994, -12.337, -16.094, -20.372, -26.008, -30.222, -32.668, + -35.85, -40.077, -42.836, -46.528, -49.243, -46.777, -46.856, -43.806, -42.207, -37.23, + -29.547, -24.963, -21.312, -12.99, -1.099, 5.028, 11.985, 19.417, 27.011, 32.515, 41.301, + 47.882, 49.963, 54.273, 59.755, 63.896, 64.148, 62.999, 60.763, 60.023, 59.745, 57.547, 55.443, + 55.202, 53.126, 47.879, 45.109, 44.79, 42.396, 35.956, 29.568, 23.214, 19.113, 19.119, 15.562, + 15.862, 15.738, 13.608, 11.741, 11.203, 10.258, 7.149, 5.11, 1.814, -2.338, -3.888, -11.423, + -16.173, -19.72, -23.734, -26.253, -28.528, -30.717, -31.133, -32.199, -33.661, -31.055, + -34.261, -34.034, -33.034, -30.689, -29.562, -27.669, -27.857, -20.659, -16.626, -9.338, + -3.864, -1.142, 3.364, 4.909, 9.891, 12.131, 13.913, 14.773, 16.412, 17.126, 14.771, 13.89, + 14.818, 12.989, 9.381, 4.037, -1.04, -0.749, 0.932, 4.849, 4.676, 5.772, 6.643, 7.102, 7.821, + 10.478, 10.255, 11.505, 13.378, 15.317, 16.671, 16.478, 12.755, 10.053, 6.662, 3.917, 1.865, + -2.742, -10.443, -15.593, -21.381, -26.568, -29.297, -32.494, -35.977, -40.472, -43.952, + -44.848, -44.716, -43.732, -41.778, -40.126, -37.37, -32.866, -28.944, -23.052, -12.522, + -5.617, 2.392, 10.925, 16.388, 22.618, 30.022, 41.101, 49.528, 46.55, 50.196, 52.682, 56.115, + 60.767, 64.085, 65.653, 64.569, 62.839, 60.742, 61.543, 59.597, 55.327, 51.525, 48.989, 46.49, + 45.08, 43.265, 37.366, 31.742, 25.367, 18.425, 18.197, 18.375, 17.358, 15.021, 14.013, 12.851, + 11.836, 9.748, 9.288, 4.142, 1.382, -1.348, -2.499, -9.8, -11.293, -15.058, -19.14, -21.388, + -22.962, -23.97, -24.303, -25.397, -26.115, -26.179, -28.64, -29.582, -28.99, -28.95, -27.892, + -24.755, -22.991, -22.464, -18.435, -14.575, -12.593, -11.01, -7.349, -4.171, 4.843, 8.605, + 9.42, 10.811, 11.764, 11.563, 12.985, 13.461, 11.801, 11.937, 9.791, 9.302, 7.888, 6.004, + 4.849, 4.58, 3.918, 3.518, 3.776, 4.151, 5.14, 6.245, 7.578, 8.114, 9.719, 9.42, 9.323, 8.531, + 8.612, 6.339, 4.042, -2.201, -6.052, -8.388, -13.147, -17.002, -18.388, -21.12, -25.038, + -30.176, -34.161, -36.942, -38.644, -37.717, -35.992, -35.502, -34.014, -33.462, -32.054, + -28.692, -24.321, -18.555, -11.252, -0.679, 8.215, 17.783, 21.933, 28.386, 33.269, 38.97, + 45.708, 47.882, 49.494, 52.939, 57.532, 59.913, 61.442, 63.976, 65.13, 66.087, 64.574, 62.088, + 57.822, 53.667, 52.001, 50.437, 46.173, 43.328, 40.469, 37.117, 33.371, 30.243, 25.432, 20.381, + 18.226, 17.723, 17.607, 16.105, 14.695, 12.036, 10.841, 6.241, 4.019, 0.976, -1.272, -4.478, + -4.583, -7.499, -12.14, -15.61, -17.545, -17.231, -19.093, -18.791, -20.562, -21.893, -22.528, + -22.27, -22.194, -21.798, -20.275, -17.875, -15.922, -15.01, -15.592, -14.791, -14.722, + -11.645, -3.841, -3.832, -0.205, 2.784, 5.554, 5.945, 9.159, 4.73, 6.834, 7.4, 8.355, 9.846, + 10.27, 9.86, 8.355, 5.797, 5.417, 4.58, 3.228, 2.088, 0.997, 1.194, 1.336, 0.985, 3.482, 3.721, + 2.67, 3.093, 3.453, 5.823, 7.414, 4.229, -1.907, -5.456, -5.626, -7.441, -8.748, -7.956, + -11.576, -16.73, -20.091, -23.169, -29.868, -31.514, -31.09, -31.707, -31.318, -29.222, + -27.834, -27.752, -24.062, -23.384, -20.934, -14.972, -6.487, 0.524, 3.511, 15.271, 21.13, + 26.55, 23.743, 25.178, 33.349, 39.151, 43.334, 47.635, 52.512, 54.059, 58.199, 60.517, 59.42, + 60.044, 60.925, 60.316, 58.592, 56.61, 51.977, 50.77, 48.496, 46.918, 44.623, 41.611, 38.739, + 37.417, 32.21, 30.203, 26.802, 23.999, 20.572, 18.03, 15.029, 12.181, 9.782, 7.716, 4.969, + 2.984, 0.583, -1.452, -3.686, -5.312, -7.283, -9.607, -11.71, -12.318, -13.23, -13.953, -14.82, + -14.355, -15.187, -13.77, -13.754, -15.262, -16.226, -14.851, -13.281, -12.384, -11.8, -10.881, + -9.648, -12.192, -13.139, -4.494, -4.72, -2.891, -0.666, 0.347, 1.325, 2.622, 3.84, 3.615, + 4.061, 4.39, 5.34, 6.285, 5.429, 4.52, 5.034, 4.838, 3.228, 2.713, 2.029, 1.002, 0.918, 0.865, + 0.555, 1.202, 0.654, -1.662, -2.763, -6.746, -7.968, -7.975, -7.656, -7.405, -7.086, -5.104, + -7.304, -10.376, -9.852, -11.819, -13.77, -16.731, -19.08, -21.372, -22.073, -22.378, -18.905, + -17.742, -16.561, -15.853, -12.549, -10.373, -8.398, -2.627, 2.778, 7.156, 11.743, 14.679, + 19.216, 24.827, 25.439, 28.913, 34.254, 36.693, 38.438, 40.517, 44.062, 48.08, 49.569, 52.258, + 53.61, 53.602, 54.766, 55.423, 54.79, 53.658, 53.558, 53.051, 52.422, 50.64, 49.091, 45.833, + 43.11, 41.274, 40.162, 34.553, 29.423, 24.503, 21.019, 18.525, 15.964, 14.096, 10.991, 8.46, + 6.555, 4.36, 2.752, 3.171, -1.364, -3.054, -6.003, -6.962, -7.557, -8.168, -7.904, -9.142, + -10.419, -11.307, -12.559, -12.731, -13.503, -13.05, -12.275, -14.079, -11.991, -9.7, -9.962, + -9.611, -8.937, -8.837, -6.944, -7.157, -6.919, -6.036, -4.226, -2.624, -1.603, -0.379, 0.464, + 1.305, 1.537, 1.375, 1.556, 1.963, 2.371, 2.914, 2.602, 2.563, 3.609, 2.713, 1.283, 1.578, + 2.819, 3.914, 1.84, 0.456, -1.017, -1.566, -3.874, -3.402, -4.166, -4.863, -5.869, -7.212, + -8.539, -9.251, -7.178, -3.281, -8.166, -11.428, -11.851, -11.706, -11.398, -12.535, -13.643, + -13.55, -12.125, -9.775, -7.787, -6.507, -3.65, -0.829, 2.597, 5.536, 6.36, 13.81, 17.463, + 19.64, 19.32, 17.187, 19.56, 22.168, 26.812, 30.95, 32.998, 35.413, 36.454, 37.954, 40.203, + 42.349, 44.62, 45.615, 47.11, 45.853, 45.499, 47.048, 47.36, 46.084, 45.757, 45.013, 43.401, + 44.336, 44.227, 42.151, 39.899, 39.727, 34.585, 29.987, 27.13, 23.319, 20.571, 18.601, 15.784, + 12.987, 10.115, 8.338, 6.411, 4.329, 3.139, 4.719, 2.947, -0.375, -2.697, -4.113, -5.548, + -6.695, -7.106, -6.92, -6.829, -6.894, -7.66, -8.077, -8.926, -9.216, -8.711, -9.05, -7.492, + -6.066, -6.061, -5.96, -5.309, -4.733, -3.967, -3.167, -2.155, -1.576, 0.453, 1.152, 0.933, + 1.514, 1.184, 1.434, 1.175, 1.532, 1.55, 1.787, 1.816, 1.644, 1.479, 1.41, 1.283, 2.57, 3.074, + 2.496, 2.355, 3.871, 3.104, 1.114, 0.309, -0.091, -1.42, -2.077, -2.658, -3.86, -4.704, -5.513, + -5.998, -5.88, -4.628, -3.062, -2.329, -3.08, -2.526, -2.646, -3.231, -4.18, -3.806, -3.999, + -3.887, -1.757, -1.763, -1.223, 2.169, 6.586, 10.616, 11.117, 8.98, 12.709, 17.586, 21.009, + 24.071, 26.63, 28.459, 29.811, 30.466, 30.977, 32.596, 33.701, 34.701, 36.671, 38.698, 38.934, + 36.011, 32.861, 29.636, 31.228, 30.974, 33.904, 36.69, 38.747, 38.649, 38.597, 39.046, 39.863, + 38.794, 36.868, 32.664, 31.287, 29.235, 26.806, 23.577, 20.715, 18.674, 17.032, 14.954, 12.844, + 11.259, 9.383, 7.858, 6.729, 5.568, 4.033, 2.807, 1.003, -0.814, -1.647, -1.407, -1.606, + -3.079, -4.387, -4.894, -4.502, -4.017, -3.485, -2.912, -2.244, -1.201, -0.856, -1.013, -1.511, + -2.224, -1.712, -0.687, -1.177, -1.138, 0.223, 1.059, 1.219, 1.4, 2.018, 2.86, 3.562, 3.583, + 3.678, 3.479, 3.085, 2.938, 3.046, 2.994, 2.162, 1.947, 2.57, 3.667, 3.684, 2.976, 2.846, + 2.784, 2.597, 2.269, 1.848, 1.432, 1.067, 1.133, 1.315, 1.435, 1.309, 1.626, 1.807, 1.592, + 1.131, 0.781, 0.899, 1.535, 2.287, 3.47, 5.394, 6.823, 7.331, 6.884, 7.261, 8.549, 10.003, + 9.765, 10.255, 11.953, 13.874, 15.079, 17.492, 17.718, 14.454, 10.433, 13.232, 16.648, 19.811, + 22.373, 24.645, 26.965, 29.414, 32.01, 34.284, 34.651, 34.297, 34.958, 34.365, 32.279, 31.863, + 31.634, 31.512, 31.554, 32.782, 34.105, 33.12, 34.25, 34.583, 33.251, 32.33, 31.608, 31.266, + 30.367, 28.591, 27.53, 26.795, 25.353, 24.118, 22.683, 20.71, 19.485, 18.45, 17.229, 15.4, + 13.994, 12.832, 11.236, 10.454, 8.396, 7.147, 6.321, 6.506, 6.219, 5.816, 4.696, 3.868, 4.312, + 4.194, 5.265, 5.739, 6.628, 4.682, 2.711, 1.978, 2.344, 3.041, 2.705, 2.718, 2.854, 2.016, + 1.278, 0.838, 1.659, 2.158, 1.901, 1.412, 1.304, 1.271, 1.256, 1.221, 1.138, 1.547, 2.22, + 2.457, 2.695, 3.186, 3.667, 7.659, 7.847, 7.794, 7.572, 8.188, 7.908, 8.102, 8.388, 8.296, + 8.099, 8.202, 8.216, 8.572, 8.694, 8.557, 8.582, 8.731, 9.008, 9.223, 9.552, 9.857, 10.458, + 10.956, 11.611, 12.209, 12.67, 13.018, 13.433, 13.658, 14.362, 14.884, 15.319, 15.808, 16.351, + 17.594, 18.575, 19.36, 19.883, 20.245, 20.646, 21.393, 22.81, 24.086, 24.855, 25.221, 25.619, + 25.489, 25.082, 25.463, 26.162, 26.704, 27.131, 26.551, 25.908, 26.34, 26.959, 27.2, 27.78, + 28.514, 28.484, 27.966, 28.027, 27.845, 27.248, 26.423, 25.635, 24.809, 23.936, 23.162, 22.544, + 21.752, 21.023, 20.156, 19.439, 18.506, 17.724, 16.858, 16.027, 15.171, 14.575, 14.232, 13.943, + 13.797, 13.506, 12.915, 12.289, 11.66, 11.024, 10.462, 10.017, 9.616, 9.448, 9.28, 9.271, + 9.331, 9.132, 8.161, 7.328, 7.545, 7.871, 7.552, 6.887, 6.376, 5.92, 5.651, 5.527, 5.32, 5.692, + 6.574, 7.032, 6.257, 6.345, 5.802, 5.638, 5.623, 6.03, 6.279, 6.569, 6.726, 7.212, 7.659, + 10.718, 10.683, 10.636, 10.6, 10.568, 10.618, 10.79, 11.061, 11.339, 11.678, 11.897, 12.047, + 12.326, 12.877, 13.263, 13.338, 13.469, 13.738, 14.003, 14.129, 14.437, 14.86, 15.292, 15.433, + 15.474, 15.708, 16.135, 16.529, 16.723, 16.724, 16.913, 17.171, 17.274, 17.476, 17.676, 17.911, + 18.024, 18.076, 18.51, 19.264, 19.771, 19.941, 19.85, 19.647, 19.579, 19.196, 19.284, 19.717, + 19.9, 19.788, 19.679, 19.576, 19.567, 19.625, 19.735, 19.875, 20.012, 20.171, 20.298, 20.395, + 20.441, 20.573, 20.624, 20.61, 20.545, 20.557, 20.555, 20.485, 20.617, 21.003, 20.857, 20.727, + 20.59, 20.287, 20.136, 19.621, 18.74, 17.889, 17.311, 16.946, 16.856, 16.596, 16.426, 16.616, + 16.278, 16.109, 15.527, 14.755, 14.234, 13.914, 13.768, 13.566, 13.087, 12.467, 11.919, 11.544, + 11.169, 10.812, 10.544, 10.238, 9.919, 9.555, 9.29, 9.108, 9.26, 9.473, 9.27, 9.531, 10.411, + 10.985, 10.762, 10.181, 9.288, 8.766, 8.992, 9.734, 10.205, 10.524, 10.64, 10.709, 10.718, + 14.899, 14.899, 14.899, 14.899, 14.899, 14.899, 14.899, 14.899, 14.899, 14.899, 14.899, 14.899, + 14.899, 14.899, 14.899, 14.899, 14.899, 14.899, 14.899, 14.899, 14.899, 14.899, 14.899, 14.899, + 14.899, 14.899, 14.899, 14.899, 14.899, 14.899, 14.899, 14.899, 14.899, 14.899, 14.899, 14.899, + 14.899, 14.899, 14.899, 14.899, 14.899, 14.899, 14.899, 14.899, 14.899, 14.899, 14.899, 14.899, + 14.899, 14.899, 14.899, 14.899, 14.899, 14.899, 14.899, 14.899, 14.899, 14.899, 14.899, 14.899, + 14.899, 14.899, 14.899, 14.899, 14.899, 14.899, 14.899, 14.899, 14.899, 14.899, 14.899, 14.899, + 14.899, 14.899, 14.899, 14.899, 14.899, 14.899, 14.899, 14.899, 14.899, 14.899, 14.899, 14.899, + 14.899, 14.899, 14.899, 14.899, 14.899, 14.899, 14.899, 14.899, 14.899, 14.899, 14.899, 14.899, + 14.899, 14.899, 14.899, 14.899, 14.899, 14.899, 14.899, 14.899, 14.899, 14.899, 14.899, 14.899, + 14.899, 14.899, 14.899, 14.899, 14.899, 14.899, 14.899, 14.899, 14.899, 14.899, 14.899, 14.899, + 14.899, +]; diff --git a/src/lib.rs b/src/lib.rs new file mode 100644 index 0000000..ef30822 --- /dev/null +++ b/src/lib.rs @@ -0,0 +1,247 @@ +use crate::geoid::{BAND_COUNT, BAND_SIZE, DATA}; +use thiserror::Error; + +mod geoid; + +/// Errors indicate what went wrong calculating the geoid height. +#[derive(Error, Debug, PartialEq)] +pub enum Error { + /// The supplied latitude was not in the expected range. + #[error("latitude out of range")] + LatitudeOutOfRange, + /// The supplied longitude was not in the expected range. + #[error("longitude out of range")] + LongitudeOutOfRange, +} + +/// Get the geoid height at the specified point on the globe. +/// +/// The latitude must be in the range [-90, 90] inclusive, and the longitude must be in the range +/// [-180, 180] inclusive, otherwise an error will be returned. +/// +/// The result is represented in meters above or below the WGS 84 ellipsoid. +/// +/// # Examples +/// +/// ``` +/// # fn main() -> Result<(), egm2008::Error> { +/// let difference = egm2008::geoid_height(0.0, 0.0)?; +/// let message = format!("ground level is about {difference} meters above the WGS 84 ellipsoid"); +/// assert_eq!(message, "ground level is about 17.225 meters above the WGS 84 ellipsoid"); +/// Ok(()) +/// } +/// ``` +pub fn geoid_height(latitude: f32, longitude: f32) -> Result { + let latitude = Latitude::new(latitude)?; + let longitude = Longitude::new(longitude)?; + + let (band_low, band_high) = latitude.bounding_bands(); + let (offset_low, offset_high) = longitude.bounding_offsets(); + + // Look up the offsets at each of the four corners of the bounding box. + let h00 = lookup_height(band_low, offset_low); + let h01 = lookup_height(band_low, offset_high); + let h10 = lookup_height(band_high, offset_low); + let h11 = lookup_height(band_high, offset_high); + + // Interpolate a height for the actual lat/lon inside the bounding box. + let latitude_scalar = latitude.interpolation_scalar(); + let longitude_scalar = longitude.interpolation_scalar(); + let latitude_lo = interpolate(h00, h10, latitude_scalar); + let latitude_hi = interpolate(h01, h11, latitude_scalar); + Ok(interpolate(latitude_lo, latitude_hi, longitude_scalar)) +} + +/// Latitude holds an f32 representing a WGS-84 latitude in degrees. +struct Latitude(f32); + +impl Latitude { + /// Create a new Latitude from the given f32, returning `Error::LatitudeOutOfRange` if the + /// provided value is not between -90 and 90. + fn new(latitude: f32) -> Result { + match latitude { + latitude if (-90.0..=90.0).contains(&latitude) => Ok(Self(latitude)), + _ => Err(Error::LatitudeOutOfRange), + } + } + + /// Return a translated and scaled version of the latitude for easier calculation of bands. + /// + /// The value is translated from the [-90, 90] range to the [0, 180] range, and then scaled down + /// to the [0, 180/SCALE] range. + fn translate_and_scale(&self) -> f32 { + (self.0 + 90.0) / geoid::SCALE + } + + /// Get a lower and upper band that contains this latitude. + fn bounding_bands(&self) -> (usize, usize) { + let lat = self.translate_and_scale(); + let low = lat.floor() as usize; + let high = (low + 1).clamp(0, BAND_COUNT - 1); + (low, high) + } + + /// Figure out the proportion of the distance between the lower and upper bounds. + fn interpolation_scalar(&self) -> f32 { + let lat = self.translate_and_scale(); + let (lo, hi) = self.bounding_bands(); + let (lo, hi) = (lo as f32, hi as f32); + if lo == hi { + return 0.0; + } + (lat - lo) / (hi - lo) + } +} + +/// Latitude holds an f32 representing a WGS-84 longitude in degrees. +struct Longitude(f32); + +impl Longitude { + /// Create a new Longitude from the given f32, returning `Error::Longitude` if the + /// provided value is not between -180 and 180. + fn new(longitude: f32) -> Result { + match longitude { + longitude if (-180.0..=180.0).contains(&longitude) => Ok(Self(longitude)), + _ => Err(Error::LongitudeOutOfRange), + } + } + + /// Return a translated and scaled version of the longitude for easier calculation of offsets. + /// + /// The value is translated from the [-180, 180] range to the [0, 360] range, and then scaled + /// down to the [0, 360/SCALE] range. + fn translate_and_scale(&self) -> f32 { + (self.0 + 180.0) / geoid::SCALE + } + + /// Get a lower and upper offset that contains this longitude. + fn bounding_offsets(&self) -> (usize, usize) { + let lon = self.translate_and_scale(); + let low = lon.floor() as usize; + let high = (low + 1).clamp(0, BAND_SIZE - 1); + (low, high) + } + + /// Figure out the proportion of the distance between the lower and upper offsets. + fn interpolation_scalar(&self) -> f32 { + let lon = self.translate_and_scale(); + let (lo, hi) = self.bounding_offsets(); + let (lo, hi) = (lo as f32, hi as f32); + if lo == hi { + return 0.0; + } + (lon - lo) / (hi - lo) + } +} + +/// Look up the height for the specified band/offset. +/// +/// # Safety +/// +/// This could panic if an invalid band/offset are specified. However, this can never happen due to +/// the validation we perform when constructing [`Latitude`] and [`Longitude`] and how we use the +/// scale factor generated by the Python script. +fn lookup_height(band: usize, offset: usize) -> f32 { + DATA[band * BAND_SIZE + offset] +} + +/// Given known values at `a` and `b`, construct a new value for a point that is `proportion` of the +/// way from `a` to `b`. +/// +/// For example, if we know that F(5) = 1 and F(10) = 2, we can approximate that F(6), a value 20% +/// of the way between 5 and 10, will be 1.2 (a value 20% of the way between 1 and 2). +fn interpolate(a: f32, b: f32, proportion: f32) -> f32 { + a + ((b - a) * proportion) +} + +#[cfg(test)] +mod tests { + use crate::{geoid_height, interpolate, Error}; + + #[test] + fn test_interpolate() { + assert_eq!(interpolate(0.0, 100.0, 0.5), 50.0); + assert_eq!(interpolate(100.0, 0.0, 0.5), 50.0); + assert_eq!(interpolate(0.0, 0.0, 0.5), 0.0); + assert_eq!(interpolate(5.0, 10.0, 0.2), 6.0); + } + + #[test] + fn fuzz_inputs() { + let mut latitude = -90.0; + while latitude <= 90.0 { + let mut longitude = -180.0; + while longitude <= 180.0 { + assert!( + geoid_height(latitude, longitude).is_ok(), + "geoid_height({}, {}) caused a crash", + latitude, + longitude + ); + longitude += 0.09; + } + latitude += 0.11; + } + } + + #[test] + fn test_one_invalid_input() { + let tests = [ + (-91.0, 0.0, Error::LatitudeOutOfRange), + (91.0, 0.0, Error::LatitudeOutOfRange), + (0.0, -181.0, Error::LongitudeOutOfRange), + (0.0, 181.0, Error::LongitudeOutOfRange), + ]; + for (lat, lon, expected) in tests { + let result = geoid_height(lat, lon); + assert!( + result.is_err(), + "Expected an error computing height for ({}, {})", + lat, + lon + ); + if let Err(actual) = result { + assert_eq!(expected, actual, "Got a different error than expected"); + } + } + } + + #[test] + fn test_two_invalid_inputs() { + assert!(geoid_height(-95.0, -200.0).is_err()); + } + + #[test] + fn validate_known_points() { + let tests = [ + (-90.0, -180.0, -30.15), + (-90.0, 0.0, -30.15), + (-90.0, 180.0, -30.15), + (0.0, -180.0, 21.281), + (0.0, 0.0, 17.225), + (0.0, 180.0, 21.281), + (90.0, -180.0, 14.899), + (90.0, 0.0, 14.899), + (90.0, 180.0, 14.899), + (-81.0, -135.0, -45.184), + (72.0, 141.0, -1.603), + (-87.0, 49.5, -17.6775), + ]; + for (lat, lon, expected) in tests { + let result = geoid_height(lat, lon); + assert!( + result.is_ok(), + "could not calculate geoid height at ({}, {})", + lat, + lon + ); + if let Ok(actual) = result { + assert_eq!( + actual, expected, + "got unexpected height at ({}, {})", + lat, lon + ); + } + } + } +}