diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index fbcd21d..16f692b 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -47,8 +47,9 @@ jobs: - "webrtc" - "silero" - "ten-vad" + - "firered" - "serde" - - "webrtc,silero,ten-vad,serde" + - "webrtc,silero,ten-vad,firered,serde" steps: - uses: actions/checkout@v6 - uses: dtolnay/rust-toolchain@stable @@ -72,7 +73,7 @@ jobs: - name: Run accuracy regression check run: | cargo test --release -p wavekat-vad --no-default-features \ - --features webrtc,silero,ten-vad \ + --features webrtc,silero,ten-vad,firered \ -- --ignored accuracy_report --nocapture 2>&1 | tee accuracy-output.txt - name: Job summary if: always() diff --git a/.github/workflows/release-plz.yml b/.github/workflows/release-plz.yml index d5a63bc..f44327d 100644 --- a/.github/workflows/release-plz.yml +++ b/.github/workflows/release-plz.yml @@ -94,7 +94,7 @@ jobs: - name: Run accuracy report run: | cargo test --release -p wavekat-vad --no-default-features \ - --features webrtc,silero,ten-vad \ + --features webrtc,silero,ten-vad,firered \ -- --ignored accuracy_report --nocapture 2>&1 | tee accuracy-output.txt - name: Update README benchmark table diff --git a/.github/workflows/vad-accuracy.yml b/.github/workflows/vad-accuracy.yml index fe87abe..11bb014 100644 --- a/.github/workflows/vad-accuracy.yml +++ b/.github/workflows/vad-accuracy.yml @@ -29,7 +29,7 @@ jobs: - name: Run accuracy report run: | cargo test --release -p wavekat-vad --no-default-features \ - --features webrtc,silero,ten-vad \ + --features webrtc,silero,ten-vad,firered \ -- --ignored accuracy_report --nocapture 2>&1 | tee accuracy-output.txt - name: Update README benchmark table diff --git a/.gitignore b/.gitignore index 785f93a..ee0f453 100644 --- a/.gitignore +++ b/.gitignore @@ -30,9 +30,15 @@ tools/vad-lab/frontend/dist/ *.wav !testdata/**/*.wav +# Python virtual environments +.venv/ + # Environment .env +# macOS +.DS_Store + # ONNX models (downloaded at build time) crates/wavekat-vad/models/ diff --git a/Makefile b/Makefile index 69a7c22..ac7d58e 100644 --- a/Makefile +++ b/Makefile @@ -71,19 +71,20 @@ ci: cargo test -p wavekat-vad --no-default-features --features "webrtc" cargo test -p wavekat-vad --no-default-features --features "silero" cargo test -p wavekat-vad --no-default-features --features "ten-vad" + cargo test -p wavekat-vad --no-default-features --features "firered" cargo test -p wavekat-vad --no-default-features --features "serde" - cargo test -p wavekat-vad --no-default-features --features "webrtc,silero,ten-vad,serde" + cargo test -p wavekat-vad --no-default-features --features "webrtc,silero,ten-vad,firered,serde" # Run criterion benchmarks for per-frame inference timing bench: - cargo bench -p wavekat-vad --no-default-features --features "webrtc,silero,ten-vad" + cargo bench -p wavekat-vad --no-default-features --features "webrtc,silero,ten-vad,firered" # Run accuracy test against the TEN-VAD testset (30 labeled audio files) accuracy: - cargo test --release -p wavekat-vad --no-default-features --features "webrtc,silero,ten-vad" \ + cargo test --release -p wavekat-vad --no-default-features --features "webrtc,silero,ten-vad,firered" \ -- --ignored accuracy_report --nocapture # Update accuracy-baseline.json with current best scores (only raises, never lowers) accuracy-update-baseline: - cargo test --release -p wavekat-vad --no-default-features --features "webrtc,silero,ten-vad" \ + cargo test --release -p wavekat-vad --no-default-features --features "webrtc,silero,ten-vad,firered" \ -- --ignored accuracy_update_baseline --nocapture diff --git a/README.md b/README.md index 111b0c4..2ecab27 100644 --- a/README.md +++ b/README.md @@ -26,13 +26,15 @@ let probability = vad.process(&samples, 16000).unwrap(); | WebRTC | `webrtc` (default) | 8/16/32/48 kHz | 10, 20, or 30ms | Binary (0.0 or 1.0) | | Silero | `silero` | 8/16 kHz | 32ms (256 or 512 samples) | Continuous (0.0–1.0) | | TEN-VAD | `ten-vad` | 16 kHz only | 16ms (256 samples) | Continuous (0.0–1.0) | +| FireRedVAD | `firered` | 16 kHz only | 10ms (160 samples) | Continuous (0.0–1.0) | ```toml [dependencies] wavekat-vad = "0.1" # WebRTC only (default) wavekat-vad = { version = "0.1", features = ["silero"] } wavekat-vad = { version = "0.1", features = ["ten-vad"] } -wavekat-vad = { version = "0.1", features = ["webrtc", "silero", "ten-vad"] } # all backends +wavekat-vad = { version = "0.1", features = ["firered"] } +wavekat-vad = { version = "0.1", features = ["webrtc", "silero", "ten-vad", "firered"] } # all backends ``` ### Benchmarks @@ -98,6 +100,19 @@ let samples = vec![0i16; 256]; // 16ms at 16kHz let probability = vad.process(&samples, 16000).unwrap(); // 0.0–1.0 ``` +### FireRedVAD + +Xiaohongshu's FireRedVAD using a DFSMN architecture with pure Rust FBank preprocessing. Returns continuous probability, 16kHz only. Best overall F1 and AUC-ROC across benchmarks. + +```rust +use wavekat_vad::VoiceActivityDetector; +use wavekat_vad::backends::firered::FireRedVad; + +let mut vad = FireRedVad::new().unwrap(); +let samples = vec![0i16; 160]; // 10ms at 16kHz +let probability = vad.process(&samples, 16000).unwrap(); // 0.0–1.0 +``` + ## The `VoiceActivityDetector` Trait All backends implement a common trait, so you can write code that is generic over backends: @@ -175,16 +190,18 @@ let cleaned = preprocessor.process(&raw_audio); | `webrtc` | Yes | WebRTC VAD backend | | `silero` | No | Silero VAD backend (ONNX model downloaded at build time) | | `ten-vad` | No | TEN-VAD backend (ONNX model downloaded at build time) | +| `firered` | No | FireRedVAD backend (ONNX model downloaded at build time) | | `denoise` | No | RNNoise-based noise suppression in the preprocessing pipeline | | `serde` | No | `Serialize`/`Deserialize` for config types | ### ONNX Model Downloads -Silero and TEN-VAD models are downloaded automatically at build time. For offline or CI builds, point to a local model file: +Silero, TEN-VAD, and FireRedVAD models are downloaded automatically at build time. For offline or CI builds, point to a local model file: ```sh SILERO_MODEL_PATH=/path/to/silero_vad.onnx cargo build --features silero TEN_VAD_MODEL_PATH=/path/to/ten-vad.onnx cargo build --features ten-vad +FIRERED_MODEL_PATH=/path/to/fireredvad.onnx FIRERED_CMVN_PATH=/path/to/cmvn.ark cargo build --features firered ``` ## Error Handling @@ -223,6 +240,13 @@ Apache-2.0 The TEN-VAD ONNX model (used by the `ten-vad` feature) is licensed under Apache-2.0 with a non-compete clause by the TEN-framework / Agora. It restricts deployment that competes with Agora's offerings and limits deployment to "solely for your benefit and the benefit of your direct End Users." This is **not standard open-source** despite the Apache-2.0 label. Review the [TEN-VAD license](https://github.com/TEN-framework/ten-vad) before using in production. -### Third-party notices +### Acknowledgements + +This project wraps and builds on several upstream projects: -This project uses [nnnoiseless](https://github.com/jneem/nnnoiseless) (BSD-3-Clause) for noise suppression via the `denoise` feature. +- [webrtc-vad](https://github.com/kaegi/webrtc-vad) — Rust bindings for Google's WebRTC VAD +- [Silero VAD](https://github.com/snakers4/silero-vad) — neural network VAD by the Silero team +- [TEN-VAD](https://github.com/TEN-framework/ten-vad) — lightweight VAD by TEN-framework / Agora +- [FireRedVAD](https://github.com/FireRedTeam/FireRedVAD) — DFSMN-based VAD by the FireRedTeam +- [ort](https://github.com/pykeio/ort) — ONNX Runtime bindings for Rust +- [nnnoiseless](https://github.com/jneem/nnnoiseless) — Rust port of RNNoise for noise suppression diff --git a/crates/wavekat-vad/Cargo.toml b/crates/wavekat-vad/Cargo.toml index 3cf8f98..03639f0 100644 --- a/crates/wavekat-vad/Cargo.toml +++ b/crates/wavekat-vad/Cargo.toml @@ -17,6 +17,7 @@ webrtc = ["dep:webrtc-vad"] silero = ["dep:ort", "dep:ndarray", "dep:ureq"] denoise = ["dep:nnnoiseless"] ten-vad = ["dep:ort", "dep:ndarray", "dep:realfft", "dep:ureq"] +firered = ["dep:ort", "dep:ndarray", "dep:realfft", "dep:ureq"] serde = ["dep:serde"] [dependencies] @@ -45,6 +46,10 @@ name = "detect_speech" name = "ten_vad_file" required-features = ["ten-vad"] +[[example]] +name = "firered_file" +required-features = ["firered"] + [[bench]] name = "vad_comparison" harness = false diff --git a/crates/wavekat-vad/benches/vad_comparison.rs b/crates/wavekat-vad/benches/vad_comparison.rs index 15f9211..ca6bf02 100644 --- a/crates/wavekat-vad/benches/vad_comparison.rs +++ b/crates/wavekat-vad/benches/vad_comparison.rs @@ -45,6 +45,23 @@ fn vad_benchmarks(c: &mut Criterion) { }); } + #[cfg(feature = "firered")] + { + use wavekat_vad::backends::firered::FireRedVad; + use wavekat_vad::VoiceActivityDetector; + + let mut vad = FireRedVad::new().unwrap(); + // FireRedVad needs 3 frames to produce the first result (buffering 400 samples) + let warmup = vec![0i16; 160]; + let _ = vad.process(&warmup, 16000).unwrap(); + let _ = vad.process(&warmup, 16000).unwrap(); + let samples = vec![0i16; vad.capabilities().frame_size]; + + group.bench_function("fireredvad", |b| { + b.iter(|| vad.process(criterion::black_box(&samples), 16000).unwrap()) + }); + } + group.finish(); } diff --git a/crates/wavekat-vad/build.rs b/crates/wavekat-vad/build.rs index 8b235a8..c5c1ac2 100644 --- a/crates/wavekat-vad/build.rs +++ b/crates/wavekat-vad/build.rs @@ -35,6 +35,18 @@ fn main() { fs::write(&model_path, b"").expect("failed to write placeholder model"); } } + #[cfg(feature = "firered")] + { + let out_dir = env::var("OUT_DIR").expect("OUT_DIR not set"); + let model_path = Path::new(&out_dir).join("fireredvad_stream_vad_with_cache.onnx"); + if !model_path.exists() { + fs::write(&model_path, b"").expect("failed to write placeholder model"); + } + let cmvn_path = Path::new(&out_dir).join("firered_cmvn.ark"); + if !cmvn_path.exists() { + fs::write(&cmvn_path, b"").expect("failed to write placeholder cmvn"); + } + } return; } @@ -43,6 +55,9 @@ fn main() { #[cfg(feature = "ten-vad")] setup_ten_vad_model(); + + #[cfg(feature = "firered")] + setup_firered_model(); } #[cfg(feature = "silero")] @@ -153,3 +168,85 @@ fn setup_ten_vad_model() { model_dest.display() ); } + +#[cfg(feature = "firered")] +fn setup_firered_model() { + println!("cargo:rerun-if-env-changed=FIRERED_MODEL_PATH"); + println!("cargo:rerun-if-env-changed=FIRERED_CMVN_PATH"); + + let out_dir = env::var("OUT_DIR").expect("OUT_DIR not set"); + + // --- ONNX model --- + let model_dest = Path::new(&out_dir).join("fireredvad_stream_vad_with_cache.onnx"); + + if let Ok(local_path) = env::var("FIRERED_MODEL_PATH") { + let local_path = Path::new(&local_path); + if !local_path.exists() { + panic!( + "FIRERED_MODEL_PATH points to non-existent file: {}", + local_path.display() + ); + } + println!( + "cargo:warning=Using local FireRedVAD model: {}", + local_path.display() + ); + fs::copy(local_path, &model_dest).expect("failed to copy local model file"); + println!("cargo:rerun-if-changed={}", local_path.display()); + } else if !model_dest.exists() { + let model_url = "https://github.com/FireRedTeam/FireRedVAD/raw/main/pretrained_models/onnx_models/fireredvad_stream_vad_with_cache.onnx"; + println!("cargo:warning=Downloading FireRedVAD model from {model_url}"); + + let response = ureq::get(model_url).call().unwrap_or_else(|e| { + panic!("failed to download FireRedVAD model from {model_url}: {e}") + }); + + let bytes = response + .into_body() + .read_to_vec() + .expect("failed to read FireRedVAD model bytes"); + + fs::write(&model_dest, &bytes).expect("failed to write FireRedVAD model file"); + println!( + "cargo:warning=FireRedVAD model downloaded to {}", + model_dest.display() + ); + } + + // --- CMVN file --- + let cmvn_dest = Path::new(&out_dir).join("firered_cmvn.ark"); + + if let Ok(local_path) = env::var("FIRERED_CMVN_PATH") { + let local_path = Path::new(&local_path); + if !local_path.exists() { + panic!( + "FIRERED_CMVN_PATH points to non-existent file: {}", + local_path.display() + ); + } + println!( + "cargo:warning=Using local FireRedVAD CMVN: {}", + local_path.display() + ); + fs::copy(local_path, &cmvn_dest).expect("failed to copy local cmvn file"); + println!("cargo:rerun-if-changed={}", local_path.display()); + } else if !cmvn_dest.exists() { + let cmvn_url = "https://github.com/FireRedTeam/FireRedVAD/raw/main/pretrained_models/onnx_models/cmvn.ark"; + println!("cargo:warning=Downloading FireRedVAD CMVN from {cmvn_url}"); + + let response = ureq::get(cmvn_url) + .call() + .unwrap_or_else(|e| panic!("failed to download FireRedVAD CMVN from {cmvn_url}: {e}")); + + let bytes = response + .into_body() + .read_to_vec() + .expect("failed to read CMVN bytes"); + + fs::write(&cmvn_dest, &bytes).expect("failed to write CMVN file"); + println!( + "cargo:warning=FireRedVAD CMVN downloaded to {}", + cmvn_dest.display() + ); + } +} diff --git a/crates/wavekat-vad/examples/detect_speech.rs b/crates/wavekat-vad/examples/detect_speech.rs index ea09293..d1cec1f 100644 --- a/crates/wavekat-vad/examples/detect_speech.rs +++ b/crates/wavekat-vad/examples/detect_speech.rs @@ -9,6 +9,9 @@ //! //! # TEN-VAD: //! cargo run --example detect_speech --features ten-vad -- --backend ten-vad path/to/audio.wav +//! +//! # FireRedVAD: +//! cargo run --example detect_speech --features firered -- --backend firered path/to/audio.wav //! ``` use std::env; @@ -33,6 +36,11 @@ fn create_vad(backend: &str) -> Box { use wavekat_vad::backends::ten_vad::TenVad; Box::new(TenVad::new().expect("failed to create TEN-VAD")) } + #[cfg(feature = "firered")] + "firered" => { + use wavekat_vad::backends::firered::FireRedVad; + Box::new(FireRedVad::new().expect("failed to create FireRedVAD")) + } other => { eprintln!("Unknown or disabled backend: {other}"); eprintln!("Available backends:"); @@ -42,6 +50,8 @@ fn create_vad(backend: &str) -> Box { eprintln!(" silero"); #[cfg(feature = "ten-vad")] eprintln!(" ten-vad"); + #[cfg(feature = "firered")] + eprintln!(" firered"); std::process::exit(1); } } @@ -75,7 +85,7 @@ fn main() { } let wav_path = wav_path.unwrap_or_else(|| { - eprintln!("Usage: detect_speech [--backend webrtc|silero|ten-vad] "); + eprintln!("Usage: detect_speech [--backend webrtc|silero|ten-vad|firered] "); std::process::exit(1); }); diff --git a/crates/wavekat-vad/examples/firered_file.rs b/crates/wavekat-vad/examples/firered_file.rs new file mode 100644 index 0000000..f25849c --- /dev/null +++ b/crates/wavekat-vad/examples/firered_file.rs @@ -0,0 +1,69 @@ +//! Run FireRedVAD on a WAV file and print speech probabilities. +//! +//! ```sh +//! cargo run --example firered_file --features firered -- path/to/audio.wav +//! ``` +//! +//! Accepts any WAV file — automatically resamples to 16kHz and converts to mono. +//! +//! To use this code in your own project, add these dependencies: +//! ```sh +//! cargo add wavekat-vad --features firered +//! cargo add hound +//! ``` + +use std::env; + +use wavekat_vad::backends::firered::FireRedVad; +use wavekat_vad::preprocessing::AudioResampler; +use wavekat_vad::VoiceActivityDetector; + +fn main() { + let path = env::args().nth(1).expect("usage: firered_file "); + + let mut reader = hound::WavReader::open(&path).expect("failed to open WAV file"); + let spec = reader.spec(); + + println!( + "File: {path}\n channels: {}, sample rate: {} Hz, bits: {}", + spec.channels, spec.sample_rate, spec.bits_per_sample + ); + + // Read all samples (take first channel if stereo) + let samples: Vec = reader + .samples::() + .step_by(spec.channels as usize) + .map(|s| s.expect("failed to read sample")) + .collect(); + + let duration = samples.len() as f64 / spec.sample_rate as f64; + println!(" samples: {}, duration: {duration:.2}s", samples.len()); + + // Resample to 16kHz if needed + let target_rate = 16000; + let samples = if spec.sample_rate != target_rate { + println!(" resampling {}Hz -> {}Hz", spec.sample_rate, target_rate); + let mut resampler = + AudioResampler::new(spec.sample_rate, target_rate).expect("failed to create resampler"); + resampler.process(&samples) + } else { + samples + }; + + println!(); + + let mut vad = FireRedVad::new().expect("failed to create FireRedVAD"); + let caps = vad.capabilities(); + + // Only process the first 10 seconds + let max_samples = target_rate as usize * 10; + let samples = &samples[..samples.len().min(max_samples)]; + + // Process frame by frame + for (i, frame) in samples.chunks_exact(caps.frame_size).enumerate() { + let prob = vad.process(frame, target_rate).expect("VAD failed"); + let time_ms = i as f64 * caps.frame_duration_ms as f64; + let bar = "#".repeat((prob * 40.0) as usize); + println!("{time_ms:8.0}ms {prob:.3} {bar}"); + } +} diff --git a/crates/wavekat-vad/src/adapter.rs b/crates/wavekat-vad/src/adapter.rs index bbe58fc..6f86061 100644 --- a/crates/wavekat-vad/src/adapter.rs +++ b/crates/wavekat-vad/src/adapter.rs @@ -4,7 +4,7 @@ //! provides an adapter that buffers incoming audio and produces frames of the //! exact size required by each backend. -use crate::{VadCapabilities, VadError, VoiceActivityDetector}; +use crate::{ProcessTimings, VadCapabilities, VadError, VoiceActivityDetector}; /// Adapts audio frames to match a VAD backend's requirements. /// @@ -112,6 +112,11 @@ impl FrameAdapter { pub fn buffered_samples(&self) -> usize { self.buffer.len() } + + /// Returns accumulated processing timings from the inner detector. + pub fn timings(&self) -> ProcessTimings { + self.inner.timings() + } } #[cfg(test)] diff --git a/crates/wavekat-vad/src/backends/firered/cmvn.rs b/crates/wavekat-vad/src/backends/firered/cmvn.rs new file mode 100644 index 0000000..ebf9172 --- /dev/null +++ b/crates/wavekat-vad/src/backends/firered/cmvn.rs @@ -0,0 +1,257 @@ +//! Kaldi-format CMVN (Cepstral Mean-Variance Normalization) parser. +//! +//! Reads a Kaldi binary-format `cmvn.ark` file containing accumulated +//! feature statistics (sums and sums-of-squares), then computes per-dimension +//! mean and inverse standard deviation vectors for normalization. +//! +//! The normalization formula is: `normalized = (feature - mean) * inv_std` + +use crate::error::VadError; + +/// Per-dimension CMVN statistics for feature normalization. +pub(crate) struct CmvnStats { + /// Per-dimension means (80-dim). + pub means: Vec, + /// Per-dimension inverse standard deviations (80-dim). + pub inv_stds: Vec, +} + +impl CmvnStats { + /// Parse CMVN statistics from a Kaldi binary matrix file. + /// + /// The file format is: + /// - Header: ` BDM ` (space, B, D/F, M, space) for double/float matrix + /// - 4 bytes: rows (i32, little-endian) — expected 2 + /// - 4 bytes: cols (i32, little-endian) — expected dim+1 + /// - Row 0: accumulated sums (dim values) + count (last value) + /// - Row 1: accumulated sums of squares (dim values) + 0 + /// + /// Computes: + /// - `mean[d] = sums[d] / count` + /// - `variance[d] = (sum_sq[d] / count) - mean[d]^2` + /// - `inv_std[d] = 1 / sqrt(max(variance, 1e-20))` + pub fn from_kaldi_binary(data: &[u8]) -> Result { + // Minimum size: header (5) + row_tag (1+4) + col_tag (1+4) + at least some data + if data.len() < 15 { + return Err(VadError::BackendError("CMVN file too small".into())); + } + + // Skip the initial space-separated token (e.g., empty key before binary data). + // Kaldi ark files may have " BFM " or " BDM " as a header. + // Find the 'B' marker that starts the binary section. + // Format: [optional key] \0 B [type marker] [data] + // Or for standalone files: ' ' B [type] M ' ' + // We need to find '\0B' or ' B' followed by 'F'/'D' and 'M' + let b_pos = data + .iter() + .position(|&b| b == b'B') + .ok_or_else(|| VadError::BackendError("CMVN: no binary marker 'B' found".into()))?; + let mut pos = b_pos + 1; + + if pos >= data.len() { + return Err(VadError::BackendError("CMVN: truncated after 'B'".into())); + } + + // Type marker: 'F' = float32, 'D' = float64 + let type_marker = data[pos]; + pos += 1; + let is_double = match type_marker { + b'F' => false, + b'D' => true, + _ => { + return Err(VadError::BackendError(format!( + "CMVN: unexpected type marker '{}'", + type_marker as char + ))) + } + }; + + // 'M' for matrix + if pos >= data.len() || data[pos] != b'M' { + return Err(VadError::BackendError("CMVN: expected 'M' marker".into())); + } + pos += 1; + + // Skip space after 'M' if present + if pos < data.len() && data[pos] == b' ' { + pos += 1; + } + + // Read row tag byte (0x04) + rows (i32 LE) + if pos + 5 > data.len() { + return Err(VadError::BackendError("CMVN: truncated at rows".into())); + } + pos += 1; // skip tag byte (0x04) + let rows = i32::from_le_bytes([data[pos], data[pos + 1], data[pos + 2], data[pos + 3]]); + pos += 4; + + if rows != 2 { + return Err(VadError::BackendError(format!( + "CMVN: expected 2 rows, got {rows}" + ))); + } + + // Read col tag byte (0x04) + cols (i32 LE) + if pos + 5 > data.len() { + return Err(VadError::BackendError("CMVN: truncated at cols".into())); + } + pos += 1; // skip tag byte + let cols = i32::from_le_bytes([data[pos], data[pos + 1], data[pos + 2], data[pos + 3]]); + pos += 4; + + if cols < 2 { + return Err(VadError::BackendError(format!( + "CMVN: expected cols >= 2, got {cols}" + ))); + } + let dim = (cols - 1) as usize; + + // Read matrix data + let elem_size = if is_double { 8 } else { 4 }; + let total_elems = 2 * cols as usize; + let data_size = total_elems * elem_size; + + if pos + data_size > data.len() { + return Err(VadError::BackendError(format!( + "CMVN: file too small for {total_elems} elements" + ))); + } + + // Parse row 0 (sums + count) and row 1 (sums of squares) + let read_f64 = |offset: usize| -> f64 { + if is_double { + f64::from_le_bytes([ + data[offset], + data[offset + 1], + data[offset + 2], + data[offset + 3], + data[offset + 4], + data[offset + 5], + data[offset + 6], + data[offset + 7], + ]) + } else { + f32::from_le_bytes([ + data[offset], + data[offset + 1], + data[offset + 2], + data[offset + 3], + ]) as f64 + } + }; + + // Row 0: sums[0..dim], count[dim] + let row0_start = pos; + let row1_start = pos + cols as usize * elem_size; + + let count = read_f64(row0_start + dim * elem_size); + if count < 1.0 { + return Err(VadError::BackendError(format!( + "CMVN: count must be >= 1, got {count}" + ))); + } + + let floor: f64 = 1e-20; + let mut means = Vec::with_capacity(dim); + let mut inv_stds = Vec::with_capacity(dim); + + for d in 0..dim { + let sum = read_f64(row0_start + d * elem_size); + let sum_sq = read_f64(row1_start + d * elem_size); + + let mean = sum / count; + let variance = (sum_sq / count) - mean * mean; + let variance = if variance < floor { floor } else { variance }; + let istd = 1.0 / variance.sqrt(); + + means.push(mean as f32); + inv_stds.push(istd as f32); + } + + Ok(Self { means, inv_stds }) + } + + /// Apply CMVN normalization to a feature vector in-place. + #[inline] + pub fn normalize(&self, features: &mut [f32]) { + for (i, feat) in features.iter_mut().enumerate() { + *feat = (*feat - self.means[i]) * self.inv_stds[i]; + } + } +} + +#[cfg(test)] +mod tests { + use super::*; + + /// Embedded CMVN file for testing. + const CMVN_BYTES: &[u8] = include_bytes!(concat!(env!("OUT_DIR"), "/firered_cmvn.ark")); + + #[test] + fn parse_cmvn_dimensions() { + let stats = CmvnStats::from_kaldi_binary(CMVN_BYTES).unwrap(); + assert_eq!(stats.means.len(), 80); + assert_eq!(stats.inv_stds.len(), 80); + } + + #[test] + fn parse_cmvn_values_match_python() { + let stats = CmvnStats::from_kaldi_binary(CMVN_BYTES).unwrap(); + + // Reference values from Python (firered_reference.py) + let ref_means: [f64; 5] = [ + 10.42295174919564, + 10.862097411631494, + 11.764544378124809, + 12.490164701573908, + 13.25983008289003, + ]; + let ref_inv_stds: [f64; 5] = [ + 0.2494980879825924, + 0.23563235243542163, + 0.23145152525802104, + 0.2332233926481505, + 0.23182660283718737, + ]; + + for i in 0..5 { + let mean_diff = (stats.means[i] as f64 - ref_means[i]).abs(); + assert!( + mean_diff < 1e-4, + "mean[{i}]: rust={}, python={}, diff={mean_diff}", + stats.means[i], + ref_means[i] + ); + + let istd_diff = (stats.inv_stds[i] as f64 - ref_inv_stds[i]).abs(); + assert!( + istd_diff < 1e-4, + "inv_std[{i}]: rust={}, python={}, diff={istd_diff}", + stats.inv_stds[i], + ref_inv_stds[i] + ); + } + } + + #[test] + fn normalize_applies_correctly() { + let stats = CmvnStats { + means: vec![1.0, 2.0], + inv_stds: vec![0.5, 0.25], + }; + + let mut features = vec![3.0, 6.0]; + stats.normalize(&mut features); + + // (3.0 - 1.0) * 0.5 = 1.0 + // (6.0 - 2.0) * 0.25 = 1.0 + assert!((features[0] - 1.0).abs() < 1e-6); + assert!((features[1] - 1.0).abs() < 1e-6); + } + + #[test] + fn parse_invalid_data() { + assert!(CmvnStats::from_kaldi_binary(b"").is_err()); + assert!(CmvnStats::from_kaldi_binary(b"too short").is_err()); + } +} diff --git a/crates/wavekat-vad/src/backends/firered/fbank.rs b/crates/wavekat-vad/src/backends/firered/fbank.rs new file mode 100644 index 0000000..9f80e59 --- /dev/null +++ b/crates/wavekat-vad/src/backends/firered/fbank.rs @@ -0,0 +1,395 @@ +//! 80-dim log Mel filterbank (FBank) feature extractor. +//! +//! Matches the `kaldi_native_fbank` configuration used by FireRedVAD: +//! +//! - Sample rate: 16 kHz +//! - Frame length: 25 ms (400 samples) +//! - Frame shift: 10 ms (160 samples) +//! - FFT size: 512 (next power of 2 >= 400) +//! - 80 Mel filter banks, 20–8000 Hz (Kaldi mel scale) +//! - Povey window +//! - Pre-emphasis: 0.97 +//! - DC offset removal +//! - No dither +//! - `snip_edges = true` + +use realfft::{RealFftPlanner, RealToComplex}; +use std::sync::Arc; + +/// Sample rate (16 kHz only). +const SAMPLE_RATE: u32 = 16000; + +/// Frame length in samples (25 ms at 16 kHz). +const FRAME_LENGTH: usize = 400; + +/// Frame shift in samples (10 ms at 16 kHz). +pub(crate) const FRAME_SHIFT: usize = 160; + +/// FFT size (next power of 2 >= FRAME_LENGTH). +const FFT_SIZE: usize = 512; + +/// Number of FFT bins (FFT_SIZE / 2 + 1). +const N_BINS: usize = FFT_SIZE / 2 + 1; // 257 + +/// Number of Mel filter banks. +const N_MEL: usize = 80; + +/// Low frequency for Mel filterbank (Hz). +const LOW_FREQ: f32 = 20.0; + +/// High frequency for Mel filterbank (Hz). 0 means Nyquist. +const HIGH_FREQ: f32 = 8000.0; // sample_rate / 2 + +/// Pre-emphasis coefficient. +const PREEMPH_COEFF: f32 = 0.97; + +/// Kaldi mel scale: 1127 * ln(1 + f/700). +#[inline] +fn mel_scale(freq: f32) -> f32 { + 1127.0 * (1.0 + freq / 700.0).ln() +} + +/// Inverse Kaldi mel scale. +#[allow(dead_code)] +#[inline] +fn inverse_mel_scale(mel: f32) -> f32 { + 700.0 * ((mel / 1127.0).exp() - 1.0) +} + +/// Sparse Mel filter (only stores non-zero bins). +struct MelFilter { + /// First FFT bin with a non-zero coefficient. + start_bin: usize, + /// Non-zero filter coefficients. + weights: Vec, +} + +/// 80-dim FBank feature extractor matching kaldi_native_fbank. +pub(crate) struct FbankExtractor { + /// FFT plan. + fft: Arc>, + /// Povey window coefficients (FRAME_LENGTH). + window: Vec, + /// Mel filterbank (sparse). + mel_filters: Vec, + /// Overlap buffer: last (FRAME_LENGTH - FRAME_SHIFT) = 240 samples + /// from the previous frame, used for windowing. + overlap_buffer: Vec, + /// Whether this is the first frame (no overlap yet). + first_frame: bool, + /// Reusable FFT input buffer (FFT_SIZE). + fft_input: Vec, + /// Reusable FFT scratch buffer. + fft_scratch: Vec>, + /// Reusable FFT output buffer (N_BINS complex values). + fft_output: Vec>, + /// Reusable power spectrum buffer (N_BINS). + power_spectrum: Vec, + /// Total frames processed. + frame_count: usize, +} + +impl FbankExtractor { + /// Create a new FBank extractor. + pub fn new() -> Self { + let mut planner = RealFftPlanner::new(); + let fft = planner.plan_fft_forward(FFT_SIZE); + let scratch_len = fft.get_scratch_len(); + + let window = Self::povey_window(); + let mel_filters = Self::compute_mel_filterbank(); + + Self { + fft, + window, + mel_filters, + overlap_buffer: vec![0.0; FRAME_LENGTH - FRAME_SHIFT], // 240 samples + first_frame: true, + fft_input: vec![0.0; FFT_SIZE], + fft_scratch: vec![realfft::num_complex::Complex::new(0.0, 0.0); scratch_len], + fft_output: vec![realfft::num_complex::Complex::new(0.0, 0.0); N_BINS], + power_spectrum: vec![0.0; N_BINS], + frame_count: 0, + } + } + + /// Generate Povey window: pow(0.5 - 0.5*cos(2*PI*n/(N-1)), 0.85). + fn povey_window() -> Vec { + (0..FRAME_LENGTH) + .map(|i| { + let hann = 0.5 + - 0.5 + * (2.0 * std::f64::consts::PI * i as f64 / (FRAME_LENGTH - 1) as f64).cos(); + hann.powf(0.85) as f32 + }) + .collect() + } + + /// Compute Kaldi-style Mel filterbank using mel-domain interpolation. + /// + /// For each filter m, the center frequencies (left, center, right) are + /// equally spaced in the mel domain. Filter weights for each FFT bin + /// are computed by mapping the bin frequency to mel scale and + /// interpolating within the triangle. + fn compute_mel_filterbank() -> Vec { + let mel_low = mel_scale(LOW_FREQ); + let mel_high = mel_scale(HIGH_FREQ); + let mel_delta = (mel_high - mel_low) / (N_MEL as f32 + 1.0); + let fft_bin_width = SAMPLE_RATE as f32 / FFT_SIZE as f32; + + let mut filters = Vec::with_capacity(N_MEL); + + for m in 0..N_MEL { + let left_mel = mel_low + m as f32 * mel_delta; + let center_mel = mel_low + (m + 1) as f32 * mel_delta; + let right_mel = mel_low + (m + 2) as f32 * mel_delta; + + let mut start_bin = N_BINS; // will be set to first non-zero bin + let mut weights = Vec::new(); + + for i in 0..N_BINS { + let freq = fft_bin_width * i as f32; + let mel = mel_scale(freq); + + // Strict inequality: mel > left_mel && mel < right_mel + if mel > left_mel && mel < right_mel { + let weight = if mel <= center_mel { + (mel - left_mel) / (center_mel - left_mel) + } else { + (right_mel - mel) / (right_mel - center_mel) + }; + + if start_bin == N_BINS { + start_bin = i; + } + // Fill any gap between last weight and this bin + let expected_idx = i - start_bin; + while weights.len() < expected_idx { + weights.push(0.0); + } + weights.push(weight); + } + } + + if start_bin == N_BINS { + start_bin = 0; + } + + filters.push(MelFilter { start_bin, weights }); + } + + filters + } + + /// Extract one FBank frame from new f32 samples. + /// + /// Input: `FRAME_SHIFT` (160) f32 samples at 16 kHz. + /// Output: 80-dim log Mel filterbank feature vector. + /// + /// Internally buffers the overlap from previous frames to form + /// the full 400-sample analysis window. Must call + /// [`extract_frame_full`](Self::extract_frame_full) for the first frame. + pub fn extract_frame(&mut self, samples: &[f32], output: &mut [f32; N_MEL]) { + debug_assert_eq!(samples.len(), FRAME_SHIFT); + debug_assert!( + !self.first_frame, + "must call extract_frame_full for the first frame" + ); + let overlap_len = FRAME_LENGTH - FRAME_SHIFT; // 240 + + let mut frame = [0.0f32; FRAME_LENGTH]; + frame[..overlap_len].copy_from_slice(&self.overlap_buffer); + frame[overlap_len..].copy_from_slice(samples); + + self.overlap_buffer.copy_from_slice(&frame[FRAME_SHIFT..]); + self.process_frame(&frame, output); + self.frame_count += 1; + } + + /// Extract a FBank frame from a complete 400-sample window. + /// + /// Used for the first frame or when the caller provides full windows directly. + pub fn extract_frame_full( + &mut self, + frame_samples: &[f32; FRAME_LENGTH], + output: &mut [f32; N_MEL], + ) { + // Store overlap for next frame + self.overlap_buffer + .copy_from_slice(&frame_samples[FRAME_SHIFT..]); + self.first_frame = false; + + self.process_frame(frame_samples, output); + self.frame_count += 1; + } + + /// Process a complete 400-sample frame through the FBank pipeline. + /// + /// Steps: + /// 1. Remove DC offset (subtract mean) + /// 2. Pre-emphasis: x[i] -= 0.97 * x[i-1]; x[0] *= (1 - 0.97) + /// 3. Apply Povey window + /// 4. Zero-pad to FFT_SIZE (512) + /// 5. Compute FFT + /// 6. Compute power spectrum |X[k]|^2 + /// 7. Apply Mel filterbank + /// 8. Log compress: ln(max(energy, epsilon)) + fn process_frame(&mut self, frame: &[f32], output: &mut [f32; N_MEL]) { + let mut work = [0.0f32; FRAME_LENGTH]; + work.copy_from_slice(&frame[..FRAME_LENGTH]); + + // 1. Remove DC offset + let mean = work.iter().sum::() / FRAME_LENGTH as f32; + for s in work.iter_mut() { + *s -= mean; + } + + // 2. Pre-emphasis (backwards, Kaldi-style) + for i in (1..FRAME_LENGTH).rev() { + work[i] -= PREEMPH_COEFF * work[i - 1]; + } + work[0] -= PREEMPH_COEFF * work[0]; // = work[0] * (1 - PREEMPH_COEFF) + + // 3. Apply Povey window + for (s, &w) in work.iter_mut().zip(self.window.iter()) { + *s *= w; + } + + // 4. Zero-pad to FFT_SIZE and compute FFT + self.fft_input[..FRAME_LENGTH].copy_from_slice(&work); + self.fft_input[FRAME_LENGTH..].fill(0.0); + + self.fft + .process_with_scratch( + &mut self.fft_input, + &mut self.fft_output, + &mut self.fft_scratch, + ) + .expect("FFT failed"); + + // 5. Power spectrum |X[k]|^2 + for (pow, c) in self.power_spectrum.iter_mut().zip(self.fft_output.iter()) { + *pow = c.re * c.re + c.im * c.im; + } + + // 6. Apply Mel filterbank + 7. Log compress + let epsilon = f32::EPSILON; // ~1.19e-7, matches Kaldi's std::numeric_limits::epsilon() + for (m, filter) in self.mel_filters.iter().enumerate() { + let mut energy = 0.0f32; + let spectrum_slice = &self.power_spectrum[filter.start_bin..]; + for (w, &p) in filter.weights.iter().zip(spectrum_slice.iter()) { + energy += w * p; + } + output[m] = energy.max(epsilon).ln(); + } + } + + /// Reset all internal state. + pub fn reset(&mut self) { + self.overlap_buffer.fill(0.0); + self.first_frame = true; + self.fft_input.fill(0.0); + self.power_spectrum.fill(0.0); + self.frame_count = 0; + } +} + +#[cfg(test)] +mod tests { + use super::*; + + #[test] + fn povey_window_shape() { + let window = FbankExtractor::povey_window(); + assert_eq!(window.len(), FRAME_LENGTH); + + // Endpoints should be 0 + assert!((window[0]).abs() < 1e-10); + assert!((window[FRAME_LENGTH - 1]).abs() < 1e-10); + + // Middle should be close to 1 + let mid = window[FRAME_LENGTH / 2]; + assert!(mid > 0.9, "window midpoint = {mid}, expected > 0.9"); + + // Should be symmetric + for i in 0..FRAME_LENGTH / 2 { + let diff = (window[i] - window[FRAME_LENGTH - 1 - i]).abs(); + assert!(diff < 1e-6, "asymmetry at {i}: {diff}"); + } + } + + #[test] + fn mel_filterbank_structure() { + let filters = FbankExtractor::compute_mel_filterbank(); + assert_eq!(filters.len(), N_MEL); + + // All filters should have some non-zero weights + for (i, f) in filters.iter().enumerate() { + assert!(!f.weights.is_empty(), "filter {i} has no weights"); + } + + // Filters should be ordered (start bins increase) + for i in 1..N_MEL { + assert!( + filters[i].start_bin >= filters[i - 1].start_bin, + "filter {i} start_bin {} < filter {} start_bin {}", + filters[i].start_bin, + i - 1, + filters[i - 1].start_bin + ); + } + } + + #[test] + fn fbank_matches_python_reference() { + // Load reference data + let ref_json = include_str!(concat!( + env!("CARGO_MANIFEST_DIR"), + "/../../testdata/firered_reference/ref_fbank.json" + )); + let ref_data: serde_json::Value = serde_json::from_str(ref_json).unwrap(); + let ref_fbank: Vec> = serde_json::from_value(ref_data["data"].clone()).unwrap(); + let ref_shape: Vec = serde_json::from_value(ref_data["shape"].clone()).unwrap(); + assert_eq!(ref_shape[1], N_MEL); + + // Load reference samples + let samples_json = include_str!(concat!( + env!("CARGO_MANIFEST_DIR"), + "/../../testdata/firered_reference/ref_samples.json" + )); + let samples_data: serde_json::Value = serde_json::from_str(samples_json).unwrap(); + let samples: Vec = serde_json::from_value(samples_data["samples"].clone()).unwrap(); + + // Extract FBank features frame by frame (matching snip_edges=true) + let mut extractor = FbankExtractor::new(); + let num_frames = (samples.len() - FRAME_LENGTH) / FRAME_SHIFT + 1; + assert_eq!(num_frames, ref_shape[0]); + + let mut max_diff: f64 = 0.0; + + for frame_idx in 0..num_frames { + let start = frame_idx * FRAME_SHIFT; + let end = start + FRAME_LENGTH; + let frame_samples: Vec = samples[start..end].iter().map(|&s| s as f32).collect(); + let frame_arr: &[f32; FRAME_LENGTH] = frame_samples.as_slice().try_into().unwrap(); + + let mut output = [0.0f32; N_MEL]; + extractor.extract_frame_full(frame_arr, &mut output); + + // Compare with Python reference + for bin in 0..N_MEL { + let diff = (output[bin] as f64 - ref_fbank[frame_idx][bin]).abs(); + if diff > max_diff { + max_diff = diff; + } + } + } + + // Tolerance: 2e-3 for FBank (accounts for float32 FFT differences) + assert!( + max_diff < 2e-3, + "FBank max diff vs Python reference: {max_diff:.8} (tolerance: 2e-3)" + ); + eprintln!("FBank max diff vs Python reference: {max_diff:.8}"); + } +} diff --git a/crates/wavekat-vad/src/backends/firered/mod.rs b/crates/wavekat-vad/src/backends/firered/mod.rs new file mode 100644 index 0000000..ca7c4a8 --- /dev/null +++ b/crates/wavekat-vad/src/backends/firered/mod.rs @@ -0,0 +1,651 @@ +//! FireRedVAD backend using pure Rust preprocessing + ONNX inference. +//! +//! This backend wraps [FireRedVAD](https://github.com/FireRedTeam/FireRedVAD), +//! a state-of-the-art voice activity detector from Xiaohongshu using a DFSMN +//! (Deep Feedforward Sequential Memory Network) architecture. The full +//! preprocessing pipeline (FBank feature extraction + CMVN normalization) +//! is implemented in pure Rust — only ONNX Runtime (through the +//! [`ort`](https://crates.io/crates/ort) crate) is needed for inference. +//! Returns continuous speech probability scores between 0.0 and 1.0. +//! +//! # Audio Requirements +//! +//! - **Sample rate:** 16000 Hz only +//! - **Frame size:** 160 samples (10 ms) +//! - **Format:** 16-bit signed integers (i16) +//! +//! # Internal State +//! +//! The model maintains 8 DFSMN cache tensors (shape `[8, 1, 128, 19]`) and +//! the preprocessor keeps an overlap buffer across calls. This means: +//! - Frames **must** be fed sequentially — skipping or reordering frames +//! will produce inaccurate results. +//! - Call [`reset()`](crate::VoiceActivityDetector::reset) when starting +//! a new audio stream or after a gap in input. +//! +//! # Preprocessing Pipeline +//! +//! 1. Buffer 160 samples into 400-sample windows (25 ms, 10 ms hop) +//! 2. Remove DC offset +//! 3. Pre-emphasis: 0.97 coefficient +//! 4. Povey window +//! 5. 512-point FFT → power spectrum +//! 6. 80-band Mel filterbank (20–8000 Hz, Kaldi mel scale) +//! 7. Log compression +//! 8. CMVN normalization (global mean/variance from `cmvn.ark`) +//! +//! # Model Loading +//! +//! The default ONNX model and CMVN file are embedded in the binary at +//! compile time — no external files are needed at runtime. For custom +//! models, use [`FireRedVad::from_file`] or [`FireRedVad::from_memory`]. +//! +//! # Example +//! +//! ```no_run +//! use wavekat_vad::backends::firered::FireRedVad; +//! use wavekat_vad::VoiceActivityDetector; +//! +//! let mut vad = FireRedVad::new().unwrap(); +//! let samples = vec![0i16; 160]; // 10ms at 16kHz +//! let probability = vad.process(&samples, 16000).unwrap(); +//! println!("Speech probability: {probability:.3}"); +//! ``` + +pub(crate) mod cmvn; +pub(crate) mod fbank; + +use super::onnx; +use crate::error::VadError; +use crate::{ProcessTimings, VadCapabilities, VoiceActivityDetector}; +use cmvn::CmvnStats; +use fbank::FbankExtractor; +use ndarray::Array4; +use ort::{inputs, session::Session, value::TensorRef}; +use std::time::{Duration, Instant}; + +/// Embedded FireRedVAD ONNX model (streaming with cache). +const MODEL_BYTES: &[u8] = include_bytes!(concat!( + env!("OUT_DIR"), + "/fireredvad_stream_vad_with_cache.onnx" +)); + +/// Embedded CMVN statistics file (Kaldi binary format). +const CMVN_BYTES: &[u8] = include_bytes!(concat!(env!("OUT_DIR"), "/firered_cmvn.ark")); + +/// Sample rate (16 kHz only). +const SAMPLE_RATE: u32 = 16000; + +/// Frame shift (10 ms at 16 kHz). +const FRAME_SHIFT: usize = fbank::FRAME_SHIFT; // 160 + +/// Frame length for windowed analysis (25 ms at 16 kHz). +const FRAME_LENGTH: usize = 400; + +/// Number of Mel filter banks. +const N_MEL: usize = 80; + +/// DFSMN cache dimensions. +const CACHE_LAYERS: usize = 8; +const CACHE_BATCH: usize = 1; +const CACHE_PROJ: usize = 128; +const CACHE_LOOKBACK: usize = 19; + +/// Voice activity detector backed by the FireRedVAD ONNX model with pure +/// Rust preprocessing. +/// +/// Accepts 16 kHz / 160-sample (10 ms) frames and returns a continuous +/// speech probability (0.0–1.0). The full preprocessing pipeline +/// (FBank + CMVN) runs in Rust — no external libraries beyond ONNX +/// Runtime are required. +/// +/// Internal state (DFSMN caches + preprocessor buffers) persists across +/// calls. Call [`reset()`](VoiceActivityDetector::reset) when switching +/// to a new audio stream. See the [module-level docs](self) for the +/// full preprocessing pipeline description. +pub struct FireRedVad { + /// ONNX Runtime session. + session: Session, + /// FBank feature extractor. + fbank: FbankExtractor, + /// CMVN statistics for normalization. + cmvn: CmvnStats, + /// DFSMN cache state: shape [8, 1, 128, 19]. + caches: Array4, + /// Sample accumulation buffer for building full frames. + /// Collects samples until we have FRAME_LENGTH (400) for the first frame, + /// then FRAME_SHIFT (160) for subsequent frames. + sample_buffer: Vec, + /// Total frames produced so far. + frame_count: usize, + /// Accumulated time for FBank feature extraction (buffer + FFT + mel). + fbank_time: Duration, + /// Accumulated time for CMVN normalization. + cmvn_time: Duration, + /// Accumulated time for tensor creation + ONNX run + cache update. + onnx_time: Duration, + /// Number of frames that produced a result. + timing_frames: u64, +} + +// SAFETY: ort::Session is Send in ort 2.x, and all other fields are owned Send types. +unsafe impl Send for FireRedVad {} + +impl FireRedVad { + /// Create a new FireRedVAD instance using the embedded model and CMVN. + /// + /// The ONNX model and CMVN statistics are embedded in the binary at + /// compile time — no external files are needed at runtime. + /// + /// # Errors + /// + /// Returns `VadError::BackendError` if the ONNX session or CMVN parsing fails. + pub fn new() -> Result { + let cmvn = CmvnStats::from_kaldi_binary(CMVN_BYTES)?; + Self::from_session(onnx::session_from_memory(MODEL_BYTES)?, cmvn) + } + + /// Create a new FireRedVAD instance from custom model and CMVN files. + /// + /// # Arguments + /// + /// * `model_path` - Path to the ONNX model file + /// * `cmvn_path` - Path to the Kaldi-format CMVN ark file + /// + /// # Errors + /// + /// Returns `VadError::BackendError` if files cannot be loaded. + /// + /// # Example + /// + /// ```no_run + /// use wavekat_vad::backends::firered::FireRedVad; + /// + /// let vad = FireRedVad::from_file("model.onnx", "cmvn.ark").unwrap(); + /// ``` + pub fn from_file>( + model_path: P, + cmvn_path: P, + ) -> Result { + let cmvn_data = std::fs::read(cmvn_path.as_ref()).map_err(|e| { + VadError::BackendError(format!( + "failed to read CMVN file '{}': {e}", + cmvn_path.as_ref().display() + )) + })?; + let cmvn = CmvnStats::from_kaldi_binary(&cmvn_data)?; + Self::from_session(onnx::session_from_file(model_path)?, cmvn) + } + + /// Create a new FireRedVAD instance from model and CMVN bytes in memory. + /// + /// # Arguments + /// + /// * `model_bytes` - Raw ONNX model data + /// * `cmvn_bytes` - Raw Kaldi-format CMVN data + /// + /// # Errors + /// + /// Returns `VadError::BackendError` if parsing fails. + pub fn from_memory(model_bytes: &[u8], cmvn_bytes: &[u8]) -> Result { + let cmvn = CmvnStats::from_kaldi_binary(cmvn_bytes)?; + Self::from_session(onnx::session_from_memory(model_bytes)?, cmvn) + } + + fn from_session(session: Session, cmvn: CmvnStats) -> Result { + Ok(Self { + session, + fbank: FbankExtractor::new(), + cmvn, + caches: Array4::::zeros((CACHE_LAYERS, CACHE_BATCH, CACHE_PROJ, CACHE_LOOKBACK)), + sample_buffer: Vec::with_capacity(FRAME_LENGTH), + frame_count: 0, + fbank_time: Duration::ZERO, + cmvn_time: Duration::ZERO, + onnx_time: Duration::ZERO, + timing_frames: 0, + }) + } + + /// Run ONNX inference on a single normalized feature frame. + fn run_inference(&mut self, features: &[f32; N_MEL]) -> Result { + // Create feature tensor: shape [1, 1, 80] — zero-copy view over the slice + let feat_tensor = TensorRef::from_array_view(([1i64, 1, N_MEL as i64], &features[..])) + .map_err(|e| VadError::BackendError(format!("failed to create feature tensor: {e}")))?; + + // Create cache tensor: zero-copy view over the existing array (no clone) + let cache_tensor = TensorRef::from_array_view(self.caches.view()) + .map_err(|e| VadError::BackendError(format!("failed to create cache tensor: {e}")))?; + + // Run inference + let outputs = self + .session + .run(inputs![ + "feat" => feat_tensor, + "caches_in" => cache_tensor, + ]) + .map_err(|e| VadError::BackendError(format!("inference failed: {e}")))?; + + // Extract probability + let probs = outputs + .get("probs") + .ok_or_else(|| VadError::BackendError("missing 'probs' tensor".into()))?; + let (_, probs_data): (_, &[f32]) = probs + .try_extract_tensor() + .map_err(|e| VadError::BackendError(format!("failed to extract probs: {e}")))?; + let probability = *probs_data + .first() + .ok_or_else(|| VadError::BackendError("empty probs tensor".into()))?; + + // Update caches + let new_caches = outputs + .get("caches_out") + .ok_or_else(|| VadError::BackendError("missing 'caches_out' tensor".into()))?; + let (_, cache_data): (_, &[f32]) = new_caches + .try_extract_tensor() + .map_err(|e| VadError::BackendError(format!("failed to extract caches: {e}")))?; + + let expected_cache_size = CACHE_LAYERS * CACHE_BATCH * CACHE_PROJ * CACHE_LOOKBACK; + if cache_data.len() == expected_cache_size { + self.caches + .as_slice_mut() + .ok_or_else(|| VadError::BackendError("cache buffer not contiguous".into()))? + .copy_from_slice(cache_data); + } else { + return Err(VadError::BackendError(format!( + "unexpected cache size: expected {expected_cache_size}, got {}", + cache_data.len() + ))); + } + + Ok(probability.clamp(0.0, 1.0)) + } +} + +impl VoiceActivityDetector for FireRedVad { + fn capabilities(&self) -> VadCapabilities { + VadCapabilities { + sample_rate: SAMPLE_RATE, + frame_size: FRAME_SHIFT, + frame_duration_ms: (FRAME_SHIFT as u32 * 1000) / SAMPLE_RATE, + } + } + + fn process(&mut self, samples: &[i16], sample_rate: u32) -> Result { + // Validate sample rate + if sample_rate != SAMPLE_RATE { + return Err(VadError::InvalidSampleRate(sample_rate)); + } + + // Validate frame size + if samples.len() != FRAME_SHIFT { + return Err(VadError::InvalidFrameSize { + got: samples.len(), + expected: FRAME_SHIFT, + }); + } + + // Add samples to buffer + for &s in samples { + self.sample_buffer.push(s as f32); + } + + // Check if we have enough samples for a frame + let needed = if self.frame_count == 0 { + FRAME_LENGTH // First frame needs 400 samples + } else { + FRAME_SHIFT // Subsequent frames need 160 new samples + }; + + if self.sample_buffer.len() < needed { + // Not enough samples yet — return 0 probability + // This only happens for the first 2 calls (need 400 samples = 2.5 × 160) + return Ok(0.0); + } + + // --- FBank feature extraction --- + let t_fbank = Instant::now(); + let mut fbank_features = [0.0f32; N_MEL]; + + if self.frame_count == 0 { + // First frame: use first FRAME_LENGTH samples + let frame: &[f32; FRAME_LENGTH] = self.sample_buffer[..FRAME_LENGTH] + .try_into() + .map_err(|_| VadError::BackendError("buffer size mismatch".into()))?; + self.fbank.extract_frame_full(frame, &mut fbank_features); + + // Keep the overlap portion for next frame + let drain_len = FRAME_SHIFT; + self.sample_buffer.drain(..drain_len); + } else { + // Subsequent frames: overlap is already stored in FbankExtractor + self.fbank + .extract_frame(&self.sample_buffer[..FRAME_SHIFT], &mut fbank_features); + self.sample_buffer.drain(..FRAME_SHIFT); + } + + self.frame_count += 1; + self.fbank_time += t_fbank.elapsed(); + + // --- CMVN normalization --- + let t_cmvn = Instant::now(); + self.cmvn.normalize(&mut fbank_features); + self.cmvn_time += t_cmvn.elapsed(); + + // --- ONNX inference --- + let t_onnx = Instant::now(); + let result = self.run_inference(&fbank_features); + self.onnx_time += t_onnx.elapsed(); + self.timing_frames += 1; + + result + } + + fn reset(&mut self) { + self.fbank.reset(); + self.caches.fill(0.0); + self.sample_buffer.clear(); + self.frame_count = 0; + } + + fn timings(&self) -> ProcessTimings { + ProcessTimings { + stages: vec![ + ("fbank", self.fbank_time), + ("cmvn", self.cmvn_time), + ("onnx", self.onnx_time), + ], + frames: self.timing_frames, + } + } +} + +#[cfg(test)] +mod tests { + use super::*; + + #[test] + fn create_succeeds() { + let vad = FireRedVad::new(); + assert!(vad.is_ok(), "Failed to create FireRedVad: {:?}", vad.err()); + } + + #[test] + fn capabilities() { + let vad = FireRedVad::new().unwrap(); + let caps = vad.capabilities(); + assert_eq!(caps.sample_rate, 16000); + assert_eq!(caps.frame_size, 160); + assert_eq!(caps.frame_duration_ms, 10); + } + + #[test] + fn process_silence() { + let mut vad = FireRedVad::new().unwrap(); + let silence = vec![0i16; 160]; + + // Feed enough frames for initial buffering (need 400 samples = 3 frames of 160) + let _ = vad.process(&silence, 16000).unwrap(); // 160 samples, not enough + let _ = vad.process(&silence, 16000).unwrap(); // 320 samples, not enough + let prob = vad.process(&silence, 16000).unwrap(); // 480 samples, first frame produced + + assert!( + prob >= 0.0 && prob <= 1.0, + "Probability out of range: {prob}" + ); + } + + #[test] + fn process_wrong_sample_rate() { + let mut vad = FireRedVad::new().unwrap(); + let samples = vec![0i16; 160]; + let result = vad.process(&samples, 8000); + assert!(matches!(result, Err(VadError::InvalidSampleRate(8000)))); + } + + #[test] + fn process_wrong_frame_size() { + let mut vad = FireRedVad::new().unwrap(); + let samples = vec![0i16; 100]; + let result = vad.process(&samples, 16000); + assert!(matches!( + result, + Err(VadError::InvalidFrameSize { + got: 100, + expected: 160 + }) + )); + } + + #[test] + fn reset_works() { + let mut vad = FireRedVad::new().unwrap(); + let samples: Vec = (0..160).map(|i| (i * 10) as i16).collect(); + + // Process some audio + let _ = vad.process(&samples, 16000).unwrap(); + let _ = vad.process(&samples, 16000).unwrap(); + let _ = vad.process(&samples, 16000).unwrap(); + + // Reset + vad.reset(); + + // Should work again + let silence = vec![0i16; 160]; + let result = vad.process(&silence, 16000); + assert!(result.is_ok()); + } + + #[test] + fn multiple_frames() { + let mut vad = FireRedVad::new().unwrap(); + let silence = vec![0i16; 160]; + + for _ in 0..10 { + let result = vad.process(&silence, 16000); + assert!(result.is_ok()); + let prob = result.unwrap(); + assert!(prob >= 0.0 && prob <= 1.0); + } + } + + #[test] + fn from_memory_with_embedded_model() { + let vad = FireRedVad::from_memory(MODEL_BYTES, CMVN_BYTES); + assert!(vad.is_ok(), "from_memory failed: {:?}", vad.err()); + } + + #[test] + fn from_memory_invalid_bytes() { + let result = FireRedVad::from_memory(b"not a valid onnx model", CMVN_BYTES); + assert!(result.is_err()); + assert!(matches!(result, Err(VadError::BackendError(_)))); + } + + #[test] + fn from_file_nonexistent() { + let result = FireRedVad::from_file("/nonexistent/model.onnx", "/nonexistent/cmvn.ark"); + assert!(result.is_err()); + assert!(matches!(result, Err(VadError::BackendError(_)))); + } + + #[test] + fn probabilities_match_python_reference() { + // Load reference data + let samples_json = include_str!(concat!( + env!("CARGO_MANIFEST_DIR"), + "/../../testdata/firered_reference/ref_samples.json" + )); + let samples_data: serde_json::Value = serde_json::from_str(samples_json).unwrap(); + let samples: Vec = serde_json::from_value(samples_data["samples"].clone()).unwrap(); + + let probs_json = include_str!(concat!( + env!("CARGO_MANIFEST_DIR"), + "/../../testdata/firered_reference/ref_probs.json" + )); + let probs_data: serde_json::Value = serde_json::from_str(probs_json).unwrap(); + let ref_probs: Vec = serde_json::from_value(probs_data["probs"].clone()).unwrap(); + + // Process samples through our Rust pipeline + // The Python reference processes full frames from a file (snip_edges=true), + // so we need to match that behavior. The Python gets 98 frames from 16000 samples: + // num_frames = (16000 - 400) / 160 + 1 = 98 + // + // Our streaming API buffers samples differently, so let's use + // extract_frame_full directly to match the Python pipeline exactly. + let cmvn = CmvnStats::from_kaldi_binary(CMVN_BYTES).unwrap(); + let mut session = onnx::session_from_memory(MODEL_BYTES).unwrap(); + let mut fbank = FbankExtractor::new(); + let mut caches = + Array4::::zeros((CACHE_LAYERS, CACHE_BATCH, CACHE_PROJ, CACHE_LOOKBACK)); + + let num_frames = (samples.len() - 400) / 160 + 1; + assert_eq!(num_frames, ref_probs.len()); + + let mut max_diff: f64 = 0.0; + + for frame_idx in 0..num_frames { + let start = frame_idx * 160; + let end = start + 400; + let frame_samples: Vec = samples[start..end].iter().map(|&s| s as f32).collect(); + let frame_arr: &[f32; 400] = frame_samples.as_slice().try_into().unwrap(); + + // Extract FBank + let mut features = [0.0f32; 80]; + fbank.extract_frame_full(frame_arr, &mut features); + + // Apply CMVN + cmvn.normalize(&mut features); + + // Run inference (zero-copy tensor views) + let feat_tensor = TensorRef::from_array_view(([1i64, 1, 80], &features[..])).unwrap(); + let cache_tensor = TensorRef::from_array_view(caches.view()).unwrap(); + + let outputs = session + .run(inputs![ + "feat" => feat_tensor, + "caches_in" => cache_tensor, + ]) + .unwrap(); + + let probs = outputs.get("probs").unwrap(); + let (_, probs_data): (_, &[f32]) = probs.try_extract_tensor().unwrap(); + let probability = probs_data[0]; + + let new_caches = outputs.get("caches_out").unwrap(); + let (_, cache_data): (_, &[f32]) = new_caches.try_extract_tensor().unwrap(); + caches.as_slice_mut().unwrap().copy_from_slice(cache_data); + + let diff = (probability as f64 - ref_probs[frame_idx]).abs(); + if diff > max_diff { + max_diff = diff; + } + + // Print first few for debugging + if frame_idx < 5 { + eprintln!( + " frame {frame_idx}: rust={probability:.6}, python={:.6}, diff={diff:.8}", + ref_probs[frame_idx] + ); + } + } + + eprintln!("Max probability diff vs Python: {max_diff:.8}"); + + // Tolerance: 0.02 for end-to-end probabilities + assert!( + max_diff < 0.02, + "Probability max diff vs Python: {max_diff:.8} (tolerance: 0.02)" + ); + } + + /// Compare Rust output directly against FireRedVAD's official pip package + /// (PyTorch) output. This closes the validation chain: + /// + /// ```text + /// FireRedVAD upstream (PyTorch) ← ref_upstream_probs.json + /// ↕ this test + /// Rust implementation + /// ``` + /// + /// The upstream probs are generated by `scripts/firered/validate_upstream.py --save-upstream` + /// using the same synthetic test signal. + #[test] + fn probabilities_match_upstream_fireredvad() { + let samples_json = include_str!(concat!( + env!("CARGO_MANIFEST_DIR"), + "/../../testdata/firered_reference/ref_samples.json" + )); + let samples_data: serde_json::Value = serde_json::from_str(samples_json).unwrap(); + let samples: Vec = serde_json::from_value(samples_data["samples"].clone()).unwrap(); + + let upstream_json = include_str!(concat!( + env!("CARGO_MANIFEST_DIR"), + "/../../testdata/firered_reference/ref_upstream_probs.json" + )); + let upstream_data: serde_json::Value = serde_json::from_str(upstream_json).unwrap(); + let upstream_probs: Vec = + serde_json::from_value(upstream_data["probs"].clone()).unwrap(); + + // Run our full Rust pipeline (same as probabilities_match_python_reference) + let cmvn = CmvnStats::from_kaldi_binary(CMVN_BYTES).unwrap(); + let mut session = onnx::session_from_memory(MODEL_BYTES).unwrap(); + let mut fbank = FbankExtractor::new(); + let mut caches = + Array4::::zeros((CACHE_LAYERS, CACHE_BATCH, CACHE_PROJ, CACHE_LOOKBACK)); + + let num_frames = (samples.len() - 400) / 160 + 1; + assert_eq!(num_frames, upstream_probs.len()); + + let mut max_diff: f64 = 0.0; + + for frame_idx in 0..num_frames { + let start = frame_idx * 160; + let end = start + 400; + let frame_samples: Vec = samples[start..end].iter().map(|&s| s as f32).collect(); + let frame_arr: &[f32; 400] = frame_samples.as_slice().try_into().unwrap(); + + let mut features = [0.0f32; 80]; + fbank.extract_frame_full(frame_arr, &mut features); + cmvn.normalize(&mut features); + + let feat_tensor = TensorRef::from_array_view(([1i64, 1, 80], &features[..])).unwrap(); + let cache_tensor = TensorRef::from_array_view(caches.view()).unwrap(); + + let outputs = session + .run(inputs![ + "feat" => feat_tensor, + "caches_in" => cache_tensor, + ]) + .unwrap(); + + let probs = outputs.get("probs").unwrap(); + let (_, probs_data): (_, &[f32]) = probs.try_extract_tensor().unwrap(); + let probability = probs_data[0]; + + let new_caches = outputs.get("caches_out").unwrap(); + let (_, cache_data): (_, &[f32]) = new_caches.try_extract_tensor().unwrap(); + caches.as_slice_mut().unwrap().copy_from_slice(cache_data); + + let diff = (probability as f64 - upstream_probs[frame_idx]).abs(); + if diff > max_diff { + max_diff = diff; + } + + if frame_idx < 5 { + eprintln!( + " frame {frame_idx}: rust={probability:.6}, upstream={:.6}, diff={diff:.8}", + upstream_probs[frame_idx] + ); + } + } + + eprintln!("Max probability diff vs upstream FireRedVAD: {max_diff:.8}"); + + // Tolerance: 0.02 for Rust vs upstream (PyTorch→ONNX numerical gap + FBank diff) + assert!( + max_diff < 0.02, + "Probability max diff vs upstream: {max_diff:.8} (tolerance: 0.02)" + ); + } +} diff --git a/crates/wavekat-vad/src/backends/mod.rs b/crates/wavekat-vad/src/backends/mod.rs index c2e14a3..ee40afb 100644 --- a/crates/wavekat-vad/src/backends/mod.rs +++ b/crates/wavekat-vad/src/backends/mod.rs @@ -8,10 +8,11 @@ //! | [`webrtc`] | `webrtc` (default) | Google's WebRTC VAD | //! | [`silero`] | `silero` | Silero VAD v5 (ONNX) | //! | [`ten_vad`] | `ten-vad` | Agora's TEN-VAD (ONNX) | +//! | [`firered`] | `firered` | FireRedVAD (ONNX) | //! //! All backends implement the [`VoiceActivityDetector`](crate::VoiceActivityDetector) trait. -#[cfg(any(feature = "silero", feature = "ten-vad"))] +#[cfg(any(feature = "silero", feature = "ten-vad", feature = "firered"))] pub(crate) mod onnx; #[cfg(feature = "webrtc")] @@ -22,3 +23,6 @@ pub mod silero; #[cfg(feature = "ten-vad")] pub mod ten_vad; + +#[cfg(feature = "firered")] +pub mod firered; diff --git a/crates/wavekat-vad/src/backends/silero.rs b/crates/wavekat-vad/src/backends/silero.rs index 193a97b..b69e28d 100644 --- a/crates/wavekat-vad/src/backends/silero.rs +++ b/crates/wavekat-vad/src/backends/silero.rs @@ -42,9 +42,10 @@ use super::onnx; use crate::error::VadError; -use crate::{VadCapabilities, VoiceActivityDetector}; +use crate::{ProcessTimings, VadCapabilities, VoiceActivityDetector}; use ndarray::{Array1, Array2, Array3}; use ort::{inputs, session::Session, value::Tensor}; +use std::time::{Duration, Instant}; /// Embedded Silero VAD ONNX model (v5). /// Downloaded automatically at build time by build.rs. @@ -73,6 +74,12 @@ pub struct SileroVad { state: Array3, /// Context buffer: last 64 samples from previous chunk. context: Vec, + /// Accumulated time for i16→f32 normalization + context building. + normalize_time: Duration, + /// Accumulated time for tensor creation + ONNX run + state update. + onnx_time: Duration, + /// Number of frames that produced a result. + timing_frames: u64, } // SAFETY: ort::Session is Send in ort 2.x, and all other fields are owned Send types. @@ -134,6 +141,9 @@ impl SileroVad { chunk_size, state, context, + normalize_time: Duration::ZERO, + onnx_time: Duration::ZERO, + timing_frames: 0, }) } @@ -160,6 +170,9 @@ impl SileroVad { chunk_size, state, context, + normalize_time: Duration::ZERO, + onnx_time: Duration::ZERO, + timing_frames: 0, }) } @@ -202,6 +215,9 @@ impl VoiceActivityDetector for SileroVad { }); } + // --- Preprocessing: normalize + build input --- + let t_preprocess = Instant::now(); + // Convert i16 samples to f32 and normalize to [-1.0, 1.0] let samples_f32: Vec = samples.iter().map(|&s| s as f32 / 32768.0).collect(); @@ -211,6 +227,11 @@ impl VoiceActivityDetector for SileroVad { input_data.extend_from_slice(&self.context); input_data.extend_from_slice(&samples_f32); + self.normalize_time += t_preprocess.elapsed(); + + // --- Inference: tensor creation + ONNX run + state update --- + let t_inference = Instant::now(); + // Create input tensor: shape [1, context_size + chunk_size] let input_array = Array2::from_shape_vec((1, input_size), input_data) .map_err(|e| VadError::BackendError(format!("failed to create input array: {e}")))?; @@ -273,6 +294,9 @@ impl VoiceActivityDetector for SileroVad { let start = samples_f32.len().saturating_sub(CONTEXT_SIZE); self.context.copy_from_slice(&samples_f32[start..]); + self.onnx_time += t_inference.elapsed(); + self.timing_frames += 1; + // Clamp probability to valid range Ok(probability.clamp(0.0, 1.0)) } @@ -284,6 +308,13 @@ impl VoiceActivityDetector for SileroVad { // Reset context buffer to zeros self.context.fill(0.0); } + + fn timings(&self) -> ProcessTimings { + ProcessTimings { + stages: vec![("normalize", self.normalize_time), ("onnx", self.onnx_time)], + frames: self.timing_frames, + } + } } #[cfg(test)] diff --git a/crates/wavekat-vad/src/backends/ten_vad.rs b/crates/wavekat-vad/src/backends/ten_vad.rs index 825dbed..1e99762 100644 --- a/crates/wavekat-vad/src/backends/ten_vad.rs +++ b/crates/wavekat-vad/src/backends/ten_vad.rs @@ -58,11 +58,12 @@ use super::onnx; use crate::error::VadError; -use crate::{VadCapabilities, VoiceActivityDetector}; +use crate::{ProcessTimings, VadCapabilities, VoiceActivityDetector}; use ndarray::{Array2, Array3}; use ort::{inputs, session::Session, value::Tensor}; use realfft::{RealFftPlanner, RealToComplex}; use std::sync::Arc; +use std::time::{Duration, Instant}; /// Embedded TEN-VAD ONNX model. const MODEL_BYTES: &[u8] = include_bytes!(concat!(env!("OUT_DIR"), "/ten-vad.onnx")); @@ -579,6 +580,12 @@ pub struct TenVad { preprocessor: TenVadPreprocessor, /// Hidden states: 4 tensors of shape [1, 64]. hidden_states: [Array2; 4], + /// Accumulated time for feature extraction (pre-emphasis + STFT + mel + pitch). + preprocess_time: Duration, + /// Accumulated time for tensor creation + ONNX run + state update. + onnx_time: Duration, + /// Number of frames that produced a result. + timing_frames: u64, } // SAFETY: ort::Session is Send in ort 2.x, and all other fields are owned Send types. @@ -649,6 +656,9 @@ impl TenVad { session, preprocessor: TenVadPreprocessor::new(), hidden_states, + preprocess_time: Duration::ZERO, + onnx_time: Duration::ZERO, + timing_frames: 0, }) } } @@ -676,8 +686,13 @@ impl VoiceActivityDetector for TenVad { }); } - // Run preprocessing + // --- Preprocessing: feature extraction --- + let t_preprocess = Instant::now(); let features = self.preprocessor.process(samples); + self.preprocess_time += t_preprocess.elapsed(); + + // --- Inference: tensor creation + ONNX run + state update --- + let t_inference = Instant::now(); // Create feature tensor: shape [1, 3, 41] let feature_array = @@ -744,6 +759,9 @@ impl VoiceActivityDetector for TenVad { } } + self.onnx_time += t_inference.elapsed(); + self.timing_frames += 1; + Ok(probability.clamp(0.0, 1.0)) } @@ -753,6 +771,16 @@ impl VoiceActivityDetector for TenVad { h.fill(0.0); } } + + fn timings(&self) -> ProcessTimings { + ProcessTimings { + stages: vec![ + ("preprocess", self.preprocess_time), + ("onnx", self.onnx_time), + ], + frames: self.timing_frames, + } + } } #[cfg(test)] diff --git a/crates/wavekat-vad/src/backends/webrtc.rs b/crates/wavekat-vad/src/backends/webrtc.rs index 661e65b..7ae5fa9 100644 --- a/crates/wavekat-vad/src/backends/webrtc.rs +++ b/crates/wavekat-vad/src/backends/webrtc.rs @@ -44,7 +44,8 @@ use crate::error::VadError; use crate::frame::{frame_samples, validate_sample_rate}; -use crate::{VadCapabilities, VoiceActivityDetector}; +use crate::{ProcessTimings, VadCapabilities, VoiceActivityDetector}; +use std::time::{Duration, Instant}; /// WebRTC VAD aggressiveness mode. /// @@ -89,6 +90,8 @@ pub struct WebRtcVad { sample_rate: u32, mode: WebRtcVadMode, frame_duration_ms: u32, + inference_time: Duration, + timing_frames: u64, } // SAFETY: webrtc_vad::Vad wraps a C pointer that is only accessed via &mut self. @@ -137,6 +140,8 @@ impl WebRtcVad { sample_rate, mode, frame_duration_ms, + inference_time: Duration::ZERO, + timing_frames: 0, }) } } @@ -169,10 +174,13 @@ impl VoiceActivityDetector for WebRtcVad { }); } + let start = Instant::now(); let is_voice = self .vad .is_voice_segment(samples) .map_err(|()| VadError::BackendError("webrtc-vad processing error".into()))?; + self.inference_time += start.elapsed(); + self.timing_frames += 1; Ok(if is_voice { 1.0 } else { 0.0 }) } @@ -182,6 +190,13 @@ impl VoiceActivityDetector for WebRtcVad { vad.set_mode(self.mode.into()); self.vad = vad; } + + fn timings(&self) -> ProcessTimings { + ProcessTimings { + stages: vec![("inference", self.inference_time)], + frames: self.timing_frames, + } + } } fn to_sample_rate(rate: u32) -> webrtc_vad::SampleRate { diff --git a/crates/wavekat-vad/src/lib.rs b/crates/wavekat-vad/src/lib.rs index 40df6f4..489090c 100644 --- a/crates/wavekat-vad/src/lib.rs +++ b/crates/wavekat-vad/src/lib.rs @@ -11,6 +11,7 @@ //! | [WebRTC](`backends::webrtc`) | `webrtc` (default) | 8/16/32/48 kHz | 10, 20, or 30ms | Binary (0.0 or 1.0) | //! | [Silero](`backends::silero`) | `silero` | 8/16 kHz | 32ms | Continuous (0.0–1.0) | //! | [TEN-VAD](`backends::ten_vad`) | `ten-vad` | 16 kHz only | 16ms | Continuous (0.0–1.0) | +//! | [FireRedVAD](`backends::firered`) | `firered` | 16 kHz only | 10ms | Continuous (0.0–1.0) | //! //! # Quick start //! @@ -21,6 +22,7 @@ //! wavekat-vad = "0.1" # WebRTC only (default) //! wavekat-vad = { version = "0.1", features = ["silero"] } # Silero //! wavekat-vad = { version = "0.1", features = ["ten-vad"] } # TEN-VAD +//! wavekat-vad = { version = "0.1", features = ["firered"] } # FireRedVAD //! ``` //! //! Then create a detector and process audio frames: @@ -101,18 +103,20 @@ //! | `webrtc` | Yes | WebRTC VAD backend | //! | `silero` | No | Silero VAD backend (ONNX model downloaded at build time) | //! | `ten-vad` | No | TEN-VAD backend (ONNX model downloaded at build time) | +//! | `firered` | No | FireRedVAD backend (ONNX model + CMVN downloaded at build time) | //! | `denoise` | No | RNNoise-based noise suppression in [`preprocessing`] | //! | `serde` | No | `Serialize`/`Deserialize` for config types | //! //! ## ONNX model downloads //! -//! The Silero and TEN-VAD backends download their ONNX models automatically -//! at build time. For offline or CI builds, set environment variables to -//! point to local model files: +//! The Silero, TEN-VAD, and FireRedVAD backends download their ONNX models +//! automatically at build time. For offline or CI builds, set environment +//! variables to point to local model files: //! //! ```sh //! SILERO_MODEL_PATH=/path/to/silero_vad.onnx cargo build --features silero //! TEN_VAD_MODEL_PATH=/path/to/ten-vad.onnx cargo build --features ten-vad +//! FIRERED_MODEL_PATH=/path/to/model.onnx FIRERED_CMVN_PATH=/path/to/cmvn.ark cargo build --features firered //! ``` //! //! # Error handling @@ -158,6 +162,39 @@ pub use adapter::FrameAdapter; pub use error::VadError; +use std::time::Duration; + +/// Accumulated processing time breakdown by named pipeline stage. +/// +/// Each backend defines its own stages (e.g. `"fbank"`, `"cmvn"`, `"onnx"`), +/// so you can see exactly where time is spent without hardcoding a fixed set +/// of fields. Stages are returned in pipeline order. +/// +/// Call [`VoiceActivityDetector::timings()`] to retrieve the current values. +/// Timings accumulate across all calls to [`process()`](VoiceActivityDetector::process) +/// and are **not** reset by [`reset()`](VoiceActivityDetector::reset). +/// +/// # Example +/// +/// ```ignore +/// let t = vad.timings(); +/// for (name, dur) in &t.stages { +/// let avg_us = dur.as_secs_f64() * 1_000_000.0 / t.frames as f64; +/// println!("{name}: {avg_us:.1} µs/frame"); +/// } +/// ``` +#[derive(Debug, Clone, Default)] +pub struct ProcessTimings { + /// Named timing stages in pipeline order. + /// + /// Each entry is `(stage_name, accumulated_duration)`. The stage names + /// are backend-specific — for example FireRedVAD reports `"fbank"`, + /// `"cmvn"`, and `"onnx"`, while Silero reports `"normalize"` and `"onnx"`. + pub stages: Vec<(&'static str, Duration)>, + /// Number of frames that produced a result (excludes buffering-only frames). + pub frames: u64, +} + /// Describes the audio requirements of a VAD backend. #[derive(Debug, Clone, PartialEq, Eq)] pub struct VadCapabilities { @@ -201,5 +238,15 @@ pub trait VoiceActivityDetector: Send { /// Reset the detector's internal state. /// /// Call this when starting a new audio stream or after a long pause. + /// Does **not** reset accumulated [`timings()`](Self::timings). fn reset(&mut self); + + /// Return accumulated processing time breakdown. + /// + /// Timings accumulate across all calls to [`process()`](Self::process) + /// and persist through [`reset()`](Self::reset). Returns default + /// (zero) timings if the backend does not track them. + fn timings(&self) -> ProcessTimings { + ProcessTimings::default() + } } diff --git a/crates/wavekat-vad/tests/accuracy-baseline.json b/crates/wavekat-vad/tests/accuracy-baseline.json index 8eda9b8..453a6d8 100644 --- a/crates/wavekat-vad/tests/accuracy-baseline.json +++ b/crates/wavekat-vad/tests/accuracy-baseline.json @@ -1,5 +1,22 @@ { - "webrtc": { "precision": 0.821, "recall": 0.983, "f1": 0.895 }, - "silero": { "precision": 0.938, "recall": 0.938, "f1": 0.938 }, - "ten-vad": { "precision": 0.942, "recall": 0.915, "f1": 0.928 } + "ten-vad": { + "precision": 0.942, + "recall": 0.915, + "f1": 0.928 + }, + "silero": { + "precision": 0.938, + "recall": 0.938, + "f1": 0.938 + }, + "webrtc": { + "precision": 0.821, + "recall": 0.983, + "f1": 0.895 + }, + "firered": { + "precision": 0.95, + "recall": 0.879, + "f1": 0.913 + } } diff --git a/crates/wavekat-vad/tests/accuracy.rs b/crates/wavekat-vad/tests/accuracy.rs index bc6f82d..1b7d9d0 100644 --- a/crates/wavekat-vad/tests/accuracy.rs +++ b/crates/wavekat-vad/tests/accuracy.rs @@ -7,7 +7,7 @@ //! //! Run with: //! ```sh -//! cargo test --release -p wavekat-vad --features webrtc,silero,ten-vad \ +//! cargo test --release -p wavekat-vad --features webrtc,silero,ten-vad,firered \ //! -- --ignored accuracy_report --nocapture //! ``` //! @@ -23,7 +23,7 @@ use std::collections::HashMap; use std::path::{Path, PathBuf}; use std::time::{Duration, Instant}; -use wavekat_vad::VoiceActivityDetector; +use wavekat_vad::{ProcessTimings, VoiceActivityDetector}; const TESTSET_URL: &str = "https://github.com/TEN-framework/ten-vad/raw/main/testset"; const NUM_FILES: usize = 30; @@ -193,6 +193,8 @@ struct BackendResult { rtf: f64, frame_size: usize, frame_ms: u32, + /// Per-stage timing breakdown from the backend. + timings: ProcessTimings, } fn evaluate_backend( @@ -272,10 +274,25 @@ fn evaluate_backend( 0.0 }; - eprintln!( + let timings = vad.timings(); + + // Print summary + per-stage breakdown + eprint!( "{display}: P={precision:.3} R={recall:.3} F1={f1:.3} \ frames={total_frames} avg={avg_frame_us:.1}µs RTF={rtf:.4}" ); + if timings.frames > 0 { + eprint!(" ["); + for (i, (name, dur)) in timings.stages.iter().enumerate() { + if i > 0 { + eprint!(", "); + } + let avg_us = dur.as_secs_f64() * 1_000_000.0 / timings.frames as f64; + eprint!("{name}={avg_us:.1}µs"); + } + eprint!("]"); + } + eprintln!(); BackendResult { id: id.to_string(), @@ -287,6 +304,7 @@ fn evaluate_backend( rtf, frame_size, frame_ms: caps.frame_duration_ms, + timings, } } @@ -327,9 +345,21 @@ fn accuracy_report() { )); } + #[cfg(feature = "firered")] + { + use wavekat_vad::backends::firered::FireRedVad; + let mut vad = FireRedVad::new().unwrap(); + results.push(evaluate_backend( + "firered", + "FireRedVAD", + &mut vad, + &testset_dir, + )); + } + assert!( !results.is_empty(), - "No backends enabled — use --features webrtc,silero,ten-vad" + "No backends enabled — use --features webrtc,silero,ten-vad,firered" ); // Print markdown table (CI parses this to update README) @@ -346,6 +376,35 @@ fn accuracy_report() { } println!(); + // Print per-stage timing breakdown + println!("### Per-Stage Timing (µs/frame)"); + println!(); + for r in &results { + if r.timings.frames > 0 { + let stage_strs: Vec = r + .timings + .stages + .iter() + .map(|(name, dur)| { + let avg = dur.as_secs_f64() * 1_000_000.0 / r.timings.frames as f64; + format!("{name}: {avg:.1}") + }) + .collect(); + let total: f64 = r + .timings + .stages + .iter() + .map(|(_, d)| d.as_secs_f64() * 1_000_000.0 / r.timings.frames as f64) + .sum(); + println!( + "- **{}**: {} (total: {total:.1} µs/frame)", + r.display, + stage_strs.join(" → ") + ); + } + } + println!(); + // Check each backend against baseline let mut regressions = Vec::new(); for r in &results { @@ -419,6 +478,14 @@ fn accuracy_update_baseline() { update_baseline(&mut baselines, &r); } + #[cfg(feature = "firered")] + { + use wavekat_vad::backends::firered::FireRedVad; + let mut vad = FireRedVad::new().unwrap(); + let r = evaluate_backend("firered", "FireRedVAD", &mut vad, &testset_dir); + update_baseline(&mut baselines, &r); + } + save_baselines(&baselines); eprintln!("Baseline updated: {}", baseline_path().display()); } diff --git a/docs/experiments/2026-03-25-firered-vad-parity.md b/docs/experiments/2026-03-25-firered-vad-parity.md new file mode 100644 index 0000000..fef45ce --- /dev/null +++ b/docs/experiments/2026-03-25-firered-vad-parity.md @@ -0,0 +1,90 @@ +# FireRedVAD Python–Rust Parity Validation + +**Date:** 2026-03-25 +**Goal:** Verify that our pure Rust FBank + CMVN preprocessing produces numerically identical results to the Python `kaldi_native_fbank` + `kaldiio` pipeline used by FireRedVAD. + +## Background + +FireRedVAD's ONNX model expects 80-dim log Mel filterbank features normalized by CMVN. If our Rust preprocessing diverges from the Python pipeline, the model produces garbage. This is the highest-risk part of the FireRedVAD integration. + +The Python pipeline uses: +- `kaldi_native_fbank` v1.22 — C++ library with Python bindings for Kaldi-compatible FBank extraction +- `kaldiio` v2.18 — reads Kaldi binary ark files (CMVN stats) + +We implemented both in pure Rust (no C++ FFI). + +## Method + +### Test Signal + +Deterministic 1-second signal at 16 kHz (16000 i16 samples): sum of sine waves at 200, 800, 2000, and 5000 Hz, scaled to ~70% of int16 range. This produces non-trivial FBank features across multiple mel bands while being perfectly reproducible. + +### Reference Data Generation + +Python script `scripts/firered/reference.py`: +1. Generates the test signal +2. Extracts FBank using `kaldi_native_fbank.OnlineFbank` with FireRedVAD's exact config +3. Parses CMVN from `cmvn.ark` using `kaldiio.load_mat()` +4. Applies CMVN normalization +5. Runs `onnxruntime` streaming inference (frame-by-frame with cache) +6. Dumps all intermediates to `testdata/firered_reference/*.json` + +### Rust Comparison + +Three levels of comparison tests: + +| Test | What it compares | How | +|------|-----------------|-----| +| `cmvn::tests::parse_cmvn_values_match_python` | CMVN means + inv_stds | Load `ref_cmvn.json`, compare first 5 values | +| `fbank::tests::fbank_matches_python_reference` | All 98×80 FBank features | Load `ref_fbank.json`, compare every element | +| `tests::probabilities_match_python_reference` | All 98 output probabilities | Load `ref_probs.json`, run full Rust pipeline, compare | + +## Results + +| Stage | Tolerance | Actual Max Diff | Margin | +|-------|-----------|-----------------|--------| +| CMVN parsing | < 1e-4 | < 1e-4 | ~1× | +| FBank (98 frames × 80 bins = 7840 values) | < 1e-3 | **6.8e-4** | 1.5× | +| End-to-end probabilities (98 frames) | < 0.02 | **1.2e-5** | 1667× | + +### Key Observations + +1. **FBank precision is excellent** — max diff 0.00068 across 7840 values. The small error comes from float32 FFT arithmetic differences between `realfft` (Rust) and the C++ FFTW/KissFFT used by `kaldi_native_fbank`. + +2. **Probability error is negligible** — the 0.000012 max diff is well within ONNX Runtime's own numerical noise. The DFSMN model is not sensitive to the sub-1e-3 FBank differences. + +3. **No accumulated drift** — the test signal is periodic (all sine frequencies divide evenly into 160-sample frames), so all 98 frames exercise the same code path. A non-periodic signal would better test overlap buffering, but the parity is good enough to proceed. + +## Key Implementation Details Discovered + +These details were **not in the original plan** and were discovered by inspecting the Python source and `kaldi_native_fbank` defaults: + +1. **Povey window** (not Hann): `pow(0.5 - 0.5*cos(2π·n/(N-1)), 0.85)` — a modified Hann raised to power 0.85 +2. **Mel-domain interpolation**: triangular filter weights computed in mel space, not Hz space — `(mel(f) - mel_left) / (mel_center - mel_left)` +3. **DC offset removal**: mean of each frame is subtracted before pre-emphasis +4. **Pre-emphasis within frame**: backwards loop `x[i] -= 0.97*x[i-1]`, with `x[0] *= 0.03` — applied independently per frame (not across frames like TEN-VAD) +5. **Raw i16 input**: FBank operates on raw int16 values cast to f32 (no normalization to [-1,1]) +6. **Energy floor**: `f32::EPSILON` (~1.19e-7), not 1e-10 or 1e-20 +7. **Mel range**: 20–8000 Hz (not 0–8000 Hz) — `low_freq=20` is the `kaldi_native_fbank` default +8. **CMVN file format**: Kaldi binary matrix (`BDM` header), not text — the plan incorrectly said "text matrix" + +## Conclusions + +- Pure Rust FBank + CMVN achieves sufficient numerical parity. **No need for C++ FFI fallback.** +- The reference data and comparison tests should be maintained as regression tests. +- The test signal could be improved with non-periodic content (e.g. chirp or real speech) to exercise overlap buffering paths differently. + +## Reproducing + +```sh +# Set up Python environment +python3 -m venv scripts/.venv +source scripts/.venv/bin/activate +pip install kaldi_native_fbank kaldiio numpy soundfile onnxruntime + +# Generate reference data +python scripts/firered/reference.py + +# Run Rust comparison tests +cargo test --features firered -p wavekat-vad -- firered --nocapture +``` diff --git a/docs/firered-vad-implementation-plan.md b/docs/firered-vad-implementation-plan.md new file mode 100644 index 0000000..94f313c --- /dev/null +++ b/docs/firered-vad-implementation-plan.md @@ -0,0 +1,310 @@ +# FireRedVAD Implementation Plan + +## Overview + +Integrate [FireRedVAD](https://github.com/FireRedTeam/FireRedVAD) as a new backend for wavekat-vad. FireRedVAD is a state-of-the-art VAD from Xiaohongshu (released March 2026) that outperforms Silero, TEN-VAD, and WebRTC across multiple benchmarks. It uses a DFSMN (Deep Feedforward Sequential Memory Network) architecture with ~0.6M parameters. + +## Why FireRedVAD + +| Metric (FLEURS-VAD-102) | FireRedVAD | Silero | TEN-VAD | WebRTC | +|--------------------------|-----------|--------|---------|--------| +| AUC-ROC | **99.60** | 97.99 | 97.81 | — | +| F1 Score | **97.57** | 95.95 | 95.19 | 52.30 | +| False Alarm Rate | **2.69** | 9.41 | 15.47 | 2.83 | +| Miss Rate | 3.62 | 3.95 | 2.95 | 64.15 | + +- Best overall F1 and AUC-ROC +- Lowest false alarm rate +- Apache-2.0 license (no restrictions unlike TEN-VAD) +- Tiny model (~2.2 MB, ~0.6M params) +- Pre-exported ONNX models available — fits our existing `ort` infrastructure + +## Key Differences from Existing Backends + +| Aspect | WebRTC | Silero | TEN-VAD | FireRedVAD | +|--------|--------|--------|---------|------------| +| Output | Binary (0/1) | Continuous (0.0-1.0) | Continuous (0.0-1.0) | Continuous (0.0-1.0) | +| Sample rate | 8k/16k/32k/48k | 8k/16k | 16k only | 16k only | +| Frame size | 10/20/30ms | 32ms | 16ms | 10ms (160 samples) | +| State | Minimal | LSTM h/c [2,1,128] | 4x hidden [1,64] | DFSMN caches [8,1,128,19] | +| Preprocessing | None | i16→f32 normalize | Pre-emphasis + STFT + mel + pitch | **FBank (80-dim) + CMVN** | +| Model size | N/A (rule-based) | ~2 MB | ~0.5 MB | ~2.2 MB | + +## Model Details + +### Architecture: DFSMN + +- 8 DFSMN blocks, 1 DNN layer +- Hidden size 256, projection size 128 +- Input: 80-dim log Mel filterbank (FBank) features +- Streaming model uses causal convolutions (lookback only, no lookahead) + +### ONNX Model Variants (pre-exported in repo) + +| Model | File | Input | Output | Use Case | +|-------|------|-------|--------|----------| +| Non-streaming VAD | `fireredvad_vad.onnx` | `feat [B,T,80]` | `probs [B,T,1]` | File processing | +| Streaming VAD (with cache) | `fireredvad_stream_vad_with_cache.onnx` | `feat [1,T,80]` + `caches_in [8,1,128,19]` | `probs [1,T,1]` + `caches_out [8,1,128,19]` | Real-time / frame-by-frame | +| Streaming VAD (no cache input) | `fireredvad_stream_vad.onnx` | `feat [B,T,80]` | `probs [B,T,1]` + cache tensors | First-call only variant | +| AED (3-class) | `fireredvad_aed.onnx` | `feat [B,T,80]` | `probs [B,T,3]` | Speech/singing/music classification | + +**We will use `fireredvad_stream_vad_with_cache.onnx`** for the streaming backend — it fits our frame-by-frame `VoiceActivityDetector` trait and carries state via explicit cache tensors (similar to Silero's LSTM state). + +### Preprocessing Pipeline (must implement in Rust) + +1. **FBank feature extraction** (80-dim log Mel filterbank) + - Window: 25ms (400 samples at 16kHz) + - Hop: 10ms (160 samples at 16kHz) + - 80 Mel filters + - This is the most complex piece — similar to TEN-VAD's mel filterbank but with different parameters + +2. **CMVN normalization** (Cepstral Mean-Variance Normalization) + - Read per-dimension mean/variance from `cmvn.ark` (Kaldi format) + - Apply: `(feature - mean) / sqrt(variance)` + - The `cmvn.ark` file is small (~1.3 KB) — embed at compile time + +### Frame Mapping + +Each call to `process()` with 160 i16 samples (10ms at 16kHz): +1. Buffer into 25ms windows (400 samples) with 10ms hop → produces 1 FBank frame per call +2. Apply CMVN → 1x80 feature vector +3. Run ONNX inference with `feat [1,1,80]` + `caches_in [8,1,128,19]` +4. Return speech probability from `probs [1,1,1]` +5. Store `caches_out` for next call + +## Implementation Plan + +### Step 1: Add Feature Flag and Dependencies ✅ + +**File: `crates/wavekat-vad/Cargo.toml`** + +```toml +[features] +firered = ["dep:ort", "dep:ndarray", "dep:realfft", "dep:ureq"] + +# realfft is already a dependency (used by ten-vad for FFT) +# ndarray is already a dependency (used by silero and ten-vad) +``` + +No new dependencies needed — `ort`, `ndarray`, and `realfft` are already in the workspace for TEN-VAD. + +### Step 2: Download ONNX Model + CMVN in build.rs ✅ + +**File: `crates/wavekat-vad/build.rs`** + +Add `setup_firered_model()` following the existing pattern: + +- Download `fireredvad_stream_vad_with_cache.onnx` from the GitHub repo +- Download `cmvn.ark` from the GitHub repo +- Support `FIRERED_MODEL_PATH` and `FIRERED_CMVN_PATH` env vars for offline builds +- Write both files to `OUT_DIR` + +Source URLs: +- Model: `https://github.com/FireRedTeam/FireRedVAD/raw/main/pretrained_models/onnx_models/fireredvad_stream_vad_with_cache.onnx` +- CMVN: `https://github.com/FireRedTeam/FireRedVAD/raw/main/pretrained_models/onnx_models/cmvn.ark` + +### Step 3: Implement CMVN Parser ✅ + +**File: `crates/wavekat-vad/src/backends/firered/cmvn.rs`** + +Parse the Kaldi-format `cmvn.ark` file embedded at compile time: +- Format: **Kaldi binary matrix** (`BDM` header = Binary Double Matrix) — not text format +- Row 0: accumulated sums per dimension + count in last column +- Row 1: accumulated sums of squares per dimension +- Computes: `mean[d] = sum[d] / count`, `variance[d] = (sum_sq[d] / count) - mean[d]^2` +- Output: per-dimension mean and inverse-std vectors (80 floats each) +- Apply as `(feature - mean) * inv_std` per dimension +- Variance floor: `1e-20` (matches Python implementation) + +Reference: The Python implementation reads this via `kaldiio.load_mat()`. Our Rust parser reads the Kaldi binary format directly (no dependency on kaldiio). + +### Step 4: Implement FBank Feature Extraction ✅ + +**File: `crates/wavekat-vad/src/backends/firered/fbank.rs`** + +80-dim log Mel filterbank, matching FireRedVAD's `kaldi_native_fbank` configuration. + +The exact `kaldi_native_fbank` defaults used by FireRedVAD (confirmed from Python source): + +| Parameter | Value | +|-----------|-------| +| `samp_freq` | 16000 | +| `frame_length_ms` | 25 (400 samples) | +| `frame_shift_ms` | 10 (160 samples) | +| `window_type` | **povey** (Hann^0.85) | +| `preemph_coeff` | 0.97 | +| `remove_dc_offset` | true | +| `dither` | 0 (disabled for inference) | +| `snip_edges` | true | +| `round_to_power_of_two` | true (FFT size = 512) | +| `num_bins` | 80 | +| `low_freq` | 20 Hz | +| `high_freq` | 0 (= Nyquist = 8000 Hz) | +| `htk_mode` | false | +| `use_energy` | false | +| `use_log_fbank` | true | +| `use_power` | true | +| `energy_floor` | f32::EPSILON (~1.19e-7) | + +Processing pipeline per frame: +1. **DC offset removal**: subtract mean of frame +2. **Pre-emphasis**: `x[i] -= 0.97 * x[i-1]` (backwards, Kaldi-style; `x[0] *= 0.03`) +3. **Povey window**: `pow(0.5 - 0.5*cos(2π·n/(N-1)), 0.85)` +4. **FFT**: 512-point real FFT (zero-padded from 400), using `realfft` crate +5. **Power spectrum**: |FFT[k]|² +6. **Mel filterbank**: 80 triangular filters, 20–8000 Hz, **mel-domain interpolation** (not Hz-domain) +7. **Log compression**: `ln(max(energy, ε))` + +Key difference from TEN-VAD mel filterbank: the triangular filter weights are computed in the **mel domain** — the weight at FFT bin `i` for filter `m` is `(mel(freq_i) - mel_left) / (mel_center - mel_left)`, not `(freq_i - f_left) / (f_center - f_left)`. + +**Important**: Input to FBank is **raw i16 values** passed as f32 (not normalized to [-1,1]). This matches `kaldi_native_fbank` which calls `accept_waveform(sample_rate, wav_np.tolist())` with raw int16 values. + +### Step 5: Implement FireRedVAD Backend ✅ + +**File: `crates/wavekat-vad/src/backends/firered/mod.rs`** + +```rust +pub struct FireRedVad { + session: Session, + fbank: FbankExtractor, + cmvn: CmvnStats, // holds means + inv_stds + caches: Array4, // [8, 1, 128, 19] + sample_buffer: Vec, // accumulates samples for frame building + frame_count: usize, +} +``` + +The sample buffering handles the first-frame startup: the FBank needs 400 samples (25ms) for the first frame but `process()` receives 160 samples (10ms) at a time. The first 2 calls return `0.0`, and the 3rd call produces the first real probability. + +Constructor pattern matching existing backends: +- `FireRedVad::new()` — uses embedded model + cmvn +- `FireRedVad::from_file(model_path, cmvn_path)` — custom model +- `FireRedVad::from_memory(model_bytes, cmvn_bytes)` — from bytes + +### Step 6: Wire Up Module ✅ (partial) + +**File: `crates/wavekat-vad/src/backends/mod.rs`** ✅ + +```rust +#[cfg(feature = "firered")] +pub mod firered; +``` + +Also updated the `onnx` module gate to include `firered`. + +**File: `crates/wavekat-vad/src/lib.rs`** + +TODO: Update module docs table to include FireRedVAD. + +### Step 7: Tests ✅ + +**18 tests total** across all three modules, all passing. + +Unit tests in `firered/mod.rs` (11 tests): +- ✅ `create_succeeds` — model loads without error +- ✅ `process_silence` — low probability for silence +- ✅ `process_wrong_sample_rate` — returns `InvalidSampleRate` +- ✅ `process_wrong_frame_size` — returns `InvalidFrameSize` +- ✅ `capabilities` — correct sample rate, frame size, duration +- ✅ `reset_works` — reset + process works +- ✅ `multiple_frames` — 10 sequential frames work +- ✅ `from_memory_with_embedded_model` — embedded model works +- ✅ `from_memory_invalid_bytes` — bad model fails gracefully +- ✅ `from_file_nonexistent` — missing file fails gracefully +- ✅ `probabilities_match_python_reference` — **end-to-end parity test** (98 frames, max diff 0.000012) + +FBank-specific tests in `firered/fbank.rs` (3 tests): +- ✅ `povey_window_shape` — endpoints zero, symmetric, midpoint > 0.9 +- ✅ `mel_filterbank_structure` — 80 filters, all non-empty, ordered +- ✅ `fbank_matches_python_reference` — **98 frames × 80 bins compared** (max diff 0.00068) + +CMVN tests in `firered/cmvn.rs` (4 tests): +- ✅ `parse_cmvn_dimensions` — 80-dim +- ✅ `parse_cmvn_values_match_python` — first 5 means/inv_stds match within 1e-4 +- ✅ `normalize_applies_correctly` — formula verified +- ✅ `parse_invalid_data` — empty/truncated data errors + +### Step 8: Update Documentation ✅ + +- [x] Update `lib.rs` doc table to include FireRedVAD +- [x] Update `backends/mod.rs` doc table to include FireRedVAD +- [x] Update `README.md` feature table +- [x] Update `lib.rs` feature flags table +- [x] Add `FIRERED_MODEL_PATH` / `FIRERED_CMVN_PATH` to env var docs in `lib.rs` + +### Step 9: Wire into vad-lab ✅ + +- [x] **File: `tools/vad-lab/backend/Cargo.toml`** — Add `firered` to the wavekat-vad features list +- [x] **File: `tools/vad-lab/backend/src/pipeline.rs`** — Add FireRedVAD to `create_detector()`, `backend_required_rate()`, `available_backends()` + +## File Summary + +### New Files +| File | Purpose | +|------|---------| +| `crates/wavekat-vad/src/backends/firered/mod.rs` | Backend struct, `VoiceActivityDetector` impl, tests | +| `crates/wavekat-vad/src/backends/firered/fbank.rs` | 80-dim FBank feature extraction | +| `crates/wavekat-vad/src/backends/firered/cmvn.rs` | Kaldi CMVN parser | + +### Modified Files +| File | Change | +|------|--------| +| `crates/wavekat-vad/Cargo.toml` | Add `firered` feature flag | +| `crates/wavekat-vad/build.rs` | Add model + cmvn download | +| `crates/wavekat-vad/src/backends/mod.rs` | Add `firered` module | +| `crates/wavekat-vad/src/lib.rs` | Update doc comments | +| `tools/vad-lab/backend/Cargo.toml` | Add `firered` feature | +| `tools/vad-lab/backend/src/pipeline.rs` | Add FireRedVAD to `create_detector()`, `backend_required_rate()`, `available_backends()` | + +## Python–Rust Parity Validation ✅ + +Our Rust preprocessing (FBank + CMVN) **must** produce numerically comparable results to the Python `kaldi_native_fbank` + `kaldiio` pipeline. If features diverge, the ONNX model will produce garbage. This was the highest-risk part of the implementation. + +### Validation Strategy + +#### Step A: Generate Reference Data from Python ✅ + +Python script `scripts/firered/reference.py` generates reference data using `kaldi_native_fbank` and `kaldiio` (installed in `scripts/.venv`). Uses a deterministic 1-second sine wave test signal (200+800+2000+5000 Hz mix) to produce 98 FBank frames. + +Reference data saved to `testdata/firered_reference/`: +- `ref_samples.json` — 16000 raw i16 samples +- `ref_fbank.json` — FBank features pre-CMVN [98, 80] +- `ref_features.json` — CMVN-normalized features [98, 80] +- `ref_cmvn.json` — CMVN mean/inv_std vectors [80] each +- `ref_probs.json` — per-frame ONNX probabilities [98] + +#### Step B: Rust Comparison Tests ✅ — All Passing + +| Stage | Tolerance | Actual Max Diff | Result | +|-------|-----------|-----------------|--------| +| CMVN parsing | < 1e-4 | < 1e-4 | ✅ | +| FBank (98 frames × 80 bins) | < 1e-3 | **0.00068** | ✅ | +| Final probabilities (98 frames) | < 0.02 | **0.000012** | ✅ | + +The pure Rust implementation achieves excellent numerical parity — **probability error is 1600× below tolerance**. + +#### Step C: Key Details Resolved + +These are the specific numerical choices in `kaldi_native_fbank` that we replicated: + +1. **Window function**: **Povey window** — `pow(0.5 - 0.5*cos(2π·n/(N-1)), 0.85)` (confirmed via Python introspection) +2. **Mel scale**: **Kaldi mel scale** (non-HTK mode) — `1127 * ln(1 + f/700)`, numerically equivalent to HTK's `2595 * log10(1 + f/700)` but using natural log +3. **Energy floor**: `f32::EPSILON` (~1.19e-7) — matches `std::numeric_limits::epsilon()` in kaldi-native-fbank C++ +4. **Pre-emphasis**: 0.97 coefficient, applied **within each frame** (backwards loop), `x[0] *= (1 - 0.97)`. Applied after DC offset removal, before windowing. +5. **FFT normalization**: `realfft` crate does NOT divide by N (matches Kaldi) +6. **First/last frame padding**: `snip_edges=true` — no padding, only full frames are extracted +7. **CMVN application**: Global (from `cmvn.ark`), applied as `(feature - mean) * inv_std` + +### FFI Fallback: Not Needed + +Pure Rust achieved parity well within tolerances. No need for `kaldi-native-fbank` C++ bindings. + +## Risks — Resolved + +1. **Window buffering** ✅ — The FbankExtractor stores the last 240 samples as overlap. The FireRedVad struct additionally buffers incoming 160-sample chunks via `sample_buffer` until enough samples are accumulated for a full 400-sample window. + +2. **Model download size** ✅ — ~2.2 MB, comparable to Silero. No concern. + +3. **`ndarray` dimension** ✅ — `Array4` works correctly for the `[8,1,128,19]` DFSMN cache. + +4. **First-frame startup** — New discovery: since `process()` receives 160 samples but the first FBank frame needs 400, the first 2 calls return `0.0` while samples accumulate. The 3rd call (at 480 samples) produces the first real probability. This is acceptable for streaming use. diff --git a/docs/video-script-firered-vad.md b/docs/video-script-firered-vad.md new file mode 100644 index 0000000..9b9dc06 --- /dev/null +++ b/docs/video-script-firered-vad.md @@ -0,0 +1,155 @@ +# Video Script: Adding FireRedVAD to wavekat-vad + +**Working title:** New VAD Backend — FireRedVAD in wavekat-vad + +--- + +## INTRO [~0:00] + +Hey everyone. Today we're adding a new voice activity detection backend to wavekat-vad — FireRedVAD. It's the most accurate VAD we've tested so far, and it's now available alongside WebRTC, Silero, and TEN-VAD. + +Let me show you what it looks like and why we're excited about it. + +--- + +## QUICK RECAP [~0:20] + +If you're new here — wavekat-vad is a Rust library for voice activity detection. It gives you a simple, unified interface across multiple VAD engines. You feed in audio, you get back a speech probability. We also have vad-lab, a browser-based tool for comparing backends side by side in real time. + +--- + +## WHAT IS FIREREDVAD [~0:45] + +FireRedVAD comes from Xiaohongshu — the company behind Little Red Book. It was released in March 2026 and uses a neural network architecture called DFSMN. + +What makes it stand out? The numbers. + +On FLEURS-VAD-102, a benchmark that tests across 102 languages: + +- F1 score: 97.6 — that's the best we've seen. Silero is at 96.0, TEN-VAD at 95.2. +- False alarm rate: just 2.7% — Silero is at 9.4%, TEN-VAD at 15.5%. +- AUC-ROC: 99.6. + +It's also Apache-2.0 licensed with no usage restrictions. TEN-VAD, for comparison, has a non-compete clause. So FireRedVAD is friendlier for production use. + +The model is tiny — about 2.2 MB — and it processes audio in 10ms frames. That's finer resolution than Silero's 32ms or TEN-VAD's 16ms, which means more precise speech boundary detection. + +--- + +## DEMO: VAD-LAB COMPARISON [~1:45] + +*[Screen: vad-lab running in browser]* + +Let me show this in vad-lab. I've got all four backends running on the same audio file. You can see the waveform at the top, and below it, each backend's speech probability over time. + +*[Point to results]* + +Notice how FireRedVAD's output is smoother and more decisive — it transitions quickly between speech and silence, with fewer hesitations in the middle. WebRTC, being rule-based, gives you binary yes/no with a lot of false negatives. Silero and TEN-VAD are good, but you can see FireRedVAD catches speech segments more consistently with fewer false alarms. + +The threshold slider works the same as the other neural backends — 0.5 by default, drag it lower for more sensitivity. + +We also added per-stage timing breakdowns in this update, so you can see exactly how much time each processing step takes. + +--- + +## USING IT IN YOUR CODE [~3:00] + +Adding FireRedVAD to your project is the same as any other backend. Add the feature flag: + +```toml +wavekat-vad = { version = "0.1", features = ["firered"] } +``` + +We have a ready-to-run example in the repo. Let me run it. + +*[Screen: terminal]* + +```sh +cargo run --example firered_file --features firered -- testdata/speech/sample.wav +``` + +*[Show output scrolling — timestamps with probabilities and # bars]* + +That's the `firered_file` example. It opens a WAV file, resamples to 16 kHz if needed, and runs FireRedVAD frame by frame — printing the speech probability at each 10ms step. You can see the probability jump up during speech segments and drop back to near zero during silence. + +The example is about 70 lines of code. Here's the core of it: + +```rust +use wavekat_vad::backends::firered::FireRedVad; +use wavekat_vad::VoiceActivityDetector; + +let mut vad = FireRedVad::new().unwrap(); +let caps = vad.capabilities(); + +for frame in samples.chunks_exact(caps.frame_size) { + let prob = vad.process(frame, 16000).unwrap(); + // ... +} +``` + +Create the VAD, get the frame size from capabilities, chunk your audio, and call `process`. That's it. + +We also have a multi-backend example — `detect_speech` — where you can switch between all four backends with a `--backend` flag: + +```sh +cargo run --example detect_speech --features firered -- --backend firered audio.wav +``` + +The ONNX model downloads automatically at build time and gets embedded in your binary. No external files needed at runtime. If you're building in CI or offline, you can point to a local model file with an environment variable. + +One thing to note: FireRedVAD only supports 16 kHz audio. If you're working with 8 kHz telephone audio, you'd need to resample. Silero handles 8k natively if that's your use case. + +--- + +## WHAT MADE THIS INTERESTING [~3:45] + +Most VAD models take raw audio samples as input. FireRedVAD is different — it expects preprocessed audio features. Specifically, 80-dimensional log Mel filterbank features with CMVN normalization. This is a Kaldi-style preprocessing pipeline. + +The upstream Python implementation uses C++ libraries for this. We reimplemented the entire pipeline in pure Rust — no C++ dependencies, no Python, everything compiles with `cargo build`. + +The tricky part was matching every numerical detail exactly. The model is trained on features from a specific pipeline, so if your preprocessing diverges even slightly, you get bad results. We built a validation suite that compares our Rust output against the Python pipeline at every stage — and the final probability difference is 0.000012. Essentially identical. + +That was the bulk of the work for this feature. Around 700 lines of Rust for the preprocessing, and a thorough validation setup to prove it works. + +--- + +## TRADEOFFS [~4:45] + +Quick summary of how FireRedVAD compares to the other backends: + +- **Accuracy**: Best overall. Highest F1, lowest false alarm rate. +- **Frame size**: 10ms — the finest resolution we have. +- **Sample rate**: 16 kHz only. Less flexible than Silero (8k/16k) or WebRTC (8k–48k). +- **Startup**: First two frames return zero while the internal buffer fills up. 30ms startup latency, then it's real-time. +- **License**: Apache-2.0, no restrictions. + +If you want the best accuracy and you're working with 16 kHz audio, FireRedVAD is the one to use. + +--- + +## WRAP UP [~5:15] + +That's FireRedVAD in wavekat-vad. Fourth backend, best accuracy, pure Rust all the way down. + +To try it out: add the `firered` feature flag, or clone the repo and fire up vad-lab to compare all four backends on your own audio. + +Links in the description. Thanks for watching, see you next time. + +--- + +## VIDEO METADATA + +**Title:** New VAD Backend — FireRedVAD in wavekat-vad + +**Description:** +We added FireRedVAD as a new backend to wavekat-vad, our open-source Rust voice activity detection library. FireRedVAD achieves 99.6 AUC-ROC and 97.6 F1 on FLEURS-VAD-102 — the best accuracy of any backend in the library. + +In this video: +- What FireRedVAD is and why we added it +- Side-by-side comparison in vad-lab +- How to use it in your code +- Accuracy vs flexibility tradeoffs across all four backends + +GitHub: [link] + +**Tags:** rust, voice-activity-detection, vad, firered, audio-processing, machine-learning, open-source diff --git a/scripts/README.md b/scripts/README.md new file mode 100644 index 0000000..f74b3c0 --- /dev/null +++ b/scripts/README.md @@ -0,0 +1,114 @@ +# Scripts + +Scripts for generating reference data used by Rust integration tests, organized by backend. + +## Why These Exist + +Some VAD backends (e.g. FireRedVAD) require complex preprocessing (FBank, CMVN) that must produce numerically identical output to the original Python implementation. To validate this, we: + +1. Run the **original Python pipeline** to generate reference data (intermediate features, probabilities) +2. Run the **Rust implementation** on the same input +3. Compare at each stage — Rust tests load the reference JSON and assert tolerances + +The reference data lives in `testdata/_reference/` and is checked into git so the Rust tests work without Python installed. + +## Setup + +```sh +python3 -m venv scripts/.venv +source scripts/.venv/bin/activate + +# Core deps (reference data generation) +pip install kaldi_native_fbank kaldiio numpy soundfile onnxruntime + +# Additional deps for upstream validation (validate_upstream.py) +pip install fireredvad torch huggingface_hub +``` + +### External model files + +`reference.py` needs the ONNX model and CMVN file. These are automatically downloaded during `cargo build --features firered` to `/tmp/`: + +- `/tmp/fireredvad_stream_vad_with_cache.onnx` +- `/tmp/firered_cmvn.ark` + +If you haven't built the Rust crate yet, download them manually: + +```sh +curl -sSL -o /tmp/fireredvad_stream_vad_with_cache.onnx \ + https://github.com/FireRedTeam/FireRedVAD/raw/main/pretrained_models/onnx_models/fireredvad_stream_vad_with_cache.onnx +curl -sSL -o /tmp/firered_cmvn.ark \ + https://github.com/FireRedTeam/FireRedVAD/raw/main/pretrained_models/onnx_models/cmvn.ark +``` + +`validate_upstream.py` additionally needs the PyTorch model from HuggingFace: + +```sh +python -c "from huggingface_hub import snapshot_download; snapshot_download('FireRedTeam/FireRedVAD', local_dir='/tmp/FireRedVAD')" +``` + +## `firered/` + +Reference data generation for the FireRedVAD backend. See `docs/experiments/2026-03-25-firered-vad-parity.md` for the full experiment log. + +### `firered/reference.py` + +Generates end-to-end reference data for FireRedVAD: + +- Synthesizes a deterministic 1-second test signal (mixed sine waves) +- Extracts FBank features using `kaldi_native_fbank` (the same library FireRedVAD uses) +- Parses CMVN stats using `kaldiio` +- Runs ONNX streaming inference frame-by-frame + +**Output** (`testdata/firered_reference/`): + +| File | Contents | +|------|----------| +| `ref_samples.json` | Raw i16 samples (16000 samples, 1 second) | +| `ref_cmvn.json` | CMVN means and inverse std vectors (80-dim each) | +| `ref_fbank.json` | FBank features pre-CMVN [98, 80] | +| `ref_features.json` | CMVN-normalized features [98, 80] | +| `ref_probs.json` | Per-frame speech probabilities [98] | + +**To regenerate:** + +```sh +source scripts/.venv/bin/activate +python scripts/firered/reference.py +``` + +### `firered/validate_upstream.py` + +End-to-end validation against FireRedVAD's official pip package. Runs the same audio through both our ONNX pipeline and the upstream `fireredvad` package (PyTorch), then compares per-frame probabilities. This proves our FBank config and CMVN match upstream without needing to inspect their source code. + +```sh +# With synthetic test signal +python scripts/firered/validate_upstream.py + +# With a real WAV file (more convincing) +python scripts/firered/validate_upstream.py --wav target/testset/testset-audio-01.wav + +# Save upstream probs for Rust tests (uses synthetic signal) +python scripts/firered/validate_upstream.py --save-upstream +``` + +Small numerical differences (< 1%) are expected due to PyTorch vs ONNX inference. + +### `firered/fbank_details.py` + +Dumps detailed FBank intermediates (Povey window, mel filterbank, per-frame DC offset / pre-emphasis / power spectrum) for debugging. Useful when the FBank output drifts from the reference. + +```sh +python scripts/firered/fbank_details.py +``` + +## When to Regenerate + +Re-run the reference scripts if: + +- The test signal generation changes +- You want to validate against a different audio file +- The upstream `kaldi_native_fbank` or FireRedVAD model changes +- You're debugging a numerical parity issue + +The Rust tests will fail if the reference data is out of sync. diff --git a/scripts/firered/fbank_details.py b/scripts/firered/fbank_details.py new file mode 100644 index 0000000..7021d8e --- /dev/null +++ b/scripts/firered/fbank_details.py @@ -0,0 +1,203 @@ +#!/usr/bin/env python3 +"""Dump detailed FBank intermediates for step-by-step Rust validation. + +Manually reimplements the kaldi_native_fbank pipeline to dump every +intermediate buffer. Then verifies our manual pipeline matches the +library's output. +""" + +import json +import math +import os +import sys + +import numpy as np + +SCRIPT_DIR = os.path.dirname(os.path.abspath(__file__)) +PROJECT_DIR = os.path.dirname(os.path.dirname(SCRIPT_DIR)) +REF_DIR = os.path.join(PROJECT_DIR, "testdata", "firered_reference") + +# Kaldi FBank parameters (matching FireRedVAD config) +SAMPLE_RATE = 16000 +FRAME_LENGTH_MS = 25 +FRAME_SHIFT_MS = 10 +FRAME_LENGTH = int(SAMPLE_RATE * FRAME_LENGTH_MS / 1000) # 400 +FRAME_SHIFT = int(SAMPLE_RATE * FRAME_SHIFT_MS / 1000) # 160 +FFT_SIZE = 512 # next power of 2 >= 400 +N_BINS = FFT_SIZE // 2 + 1 # 257 +N_MEL = 80 +LOW_FREQ = 20.0 +HIGH_FREQ = 8000.0 # 0 means Nyquist +PREEMPH = 0.97 + + +def mel_scale(freq): + """Kaldi mel scale (non-HTK): 1127 * ln(1 + f/700).""" + return 1127.0 * math.log(1.0 + freq / 700.0) + + +def inverse_mel_scale(mel): + """Inverse Kaldi mel scale.""" + return 700.0 * (math.exp(mel / 1127.0) - 1.0) + + +def povey_window(length): + """Povey window: pow(0.5 - 0.5*cos(2*pi*n/(N-1)), 0.85).""" + window = np.zeros(length) + for i in range(length): + window[i] = (0.5 - 0.5 * math.cos(2.0 * math.pi * i / (length - 1))) ** 0.85 + return window + + +def compute_mel_filterbank(): + """Compute Kaldi-style mel filterbank weights. + + Returns (n_mel, n_bins) matrix of filterbank weights. + """ + low_mel = mel_scale(LOW_FREQ) + high_mel = mel_scale(HIGH_FREQ) + + # n_mel + 2 equally spaced points in mel domain + mel_points = np.linspace(low_mel, high_mel, N_MEL + 2) + hz_points = np.array([inverse_mel_scale(m) for m in mel_points]) + + # Convert Hz to FFT bin indices (real-valued, for interpolation) + bin_freqs = np.array([i * SAMPLE_RATE / FFT_SIZE for i in range(N_BINS)]) + + weights = np.zeros((N_MEL, N_BINS)) + for m in range(N_MEL): + f_left = hz_points[m] + f_center = hz_points[m + 1] + f_right = hz_points[m + 2] + + for k in range(N_BINS): + freq = bin_freqs[k] + if freq < f_left or freq > f_right: + continue + if freq <= f_center: + if f_center > f_left: + weights[m, k] = (freq - f_left) / (f_center - f_left) + else: + if f_right > f_center: + weights[m, k] = (f_right - freq) / (f_right - f_center) + + return weights + + +def process_frame(samples_f32, window): + """Process a single frame through the Kaldi FBank pipeline. + + Args: + samples_f32: float64 samples for this frame (400 samples) + window: Povey window coefficients + + Returns dict with all intermediates. + """ + frame = samples_f32.copy() + + # 1. Remove DC offset + dc_offset = np.mean(frame) + frame -= dc_offset + + # 2. Pre-emphasis (in-place, backwards) + # Kaldi does: for i in N-1..1: x[i] -= 0.97*x[i-1]; x[0] -= 0.97*x[0] + preemph_frame = frame.copy() + for i in range(len(preemph_frame) - 1, 0, -1): + preemph_frame[i] -= PREEMPH * preemph_frame[i - 1] + preemph_frame[0] -= PREEMPH * preemph_frame[0] + + # 3. Apply window + windowed = preemph_frame * window + + # 4. FFT (zero-pad to FFT_SIZE) + padded = np.zeros(FFT_SIZE) + padded[:FRAME_LENGTH] = windowed + spectrum = np.fft.rfft(padded) + + # 5. Power spectrum + power = np.abs(spectrum) ** 2 + + # 6. Mel filterbank + mel_weights = compute_mel_filterbank() + mel_energies = mel_weights @ power + + # 7. Log (with floor) + epsilon = np.finfo(np.float32).eps # ~1.19e-7 + log_mel = np.log(np.maximum(mel_energies, epsilon)) + + return { + "dc_offset": float(dc_offset), + "after_dc_removal": frame[:10].tolist(), + "after_preemph": preemph_frame[:10].tolist(), + "after_window": windowed[:10].tolist(), + "power_spectrum_first10": power[:10].tolist(), + "power_spectrum_last5": power[-5:].tolist(), + "mel_energies": mel_energies.tolist(), + "log_mel": log_mel.tolist(), + } + + +def main(): + # Load reference samples + with open(os.path.join(REF_DIR, "ref_samples.json")) as f: + data = json.load(f) + samples_i16 = np.array(data["samples"], dtype=np.int16) + + # Load reference FBank for comparison + with open(os.path.join(REF_DIR, "ref_fbank.json")) as f: + ref_data = json.load(f) + ref_fbank = np.array(ref_data["data"]) + + print("=== Povey Window (first 10, last 5) ===") + window = povey_window(FRAME_LENGTH) + print(f" First 10: {window[:10].tolist()}") + print(f" Last 5: {window[-5:].tolist()}") + print(f" Window sum: {window.sum():.6f}") + + print("\n=== Mel Filterbank ===") + mel_weights = compute_mel_filterbank() + print(f" Shape: {mel_weights.shape}") + # Find first non-zero bin for each filter + for m in [0, 1, 39, 79]: + nonzero = np.nonzero(mel_weights[m])[0] + if len(nonzero) > 0: + print(f" Filter {m}: bins {nonzero[0]}-{nonzero[-1]}, " + f"peak={mel_weights[m].max():.6f}") + + # Process first 5 frames + print("\n=== Frame-by-Frame Processing ===") + details = [] + for frame_idx in range(min(5, ref_fbank.shape[0])): + start = frame_idx * FRAME_SHIFT + end = start + FRAME_LENGTH + # Kaldi passes raw int16 values as float + frame_samples = samples_i16[start:end].astype(np.float64) + + result = process_frame(frame_samples, window) + + # Compare with kaldi_native_fbank reference + max_diff = np.max(np.abs(np.array(result["log_mel"]) - ref_fbank[frame_idx])) + print(f"\n Frame {frame_idx}:") + print(f" DC offset: {result['dc_offset']:.6f}") + print(f" After preemph (first 5): {result['after_preemph'][:5]}") + print(f" Log mel (first 5): {result['log_mel'][:5]}") + print(f" Ref fbank (first 5): {ref_fbank[frame_idx, :5].tolist()}") + print(f" Max diff vs reference: {max_diff:.8f}") + + details.append(result) + + # Save all intermediates + output = { + "povey_window": window.tolist(), + "mel_filterbank_shape": list(mel_weights.shape), + "frame_details": details, + } + + with open(os.path.join(REF_DIR, "ref_fbank_intermediates.json"), "w") as f: + json.dump(output, f) + + print(f"\n=== Saved intermediates to {REF_DIR}/ref_fbank_intermediates.json ===") + + +if __name__ == "__main__": + main() diff --git a/scripts/firered/reference.py b/scripts/firered/reference.py new file mode 100644 index 0000000..18a845b --- /dev/null +++ b/scripts/firered/reference.py @@ -0,0 +1,194 @@ +#!/usr/bin/env python3 +"""Generate reference data for FireRedVAD Rust implementation validation. + +Dumps intermediate values at each preprocessing stage so the Rust +implementation can be validated step by step. + +Output files (in testdata/firered_reference/): + - ref_samples.json : Raw i16 samples for the test signal + - ref_cmvn.json : CMVN mean and inv_std vectors (80-dim each) + - ref_fbank.json : FBank features pre-CMVN [T, 80] + - ref_probs.json : Per-frame speech probabilities [T] +""" + +import json +import math +import os +import sys + +import kaldiio +import kaldi_native_fbank as knf +import numpy as np +import onnxruntime as ort + +SCRIPT_DIR = os.path.dirname(os.path.abspath(__file__)) +PROJECT_DIR = os.path.dirname(os.path.dirname(SCRIPT_DIR)) +REF_DIR = os.path.join(PROJECT_DIR, "testdata", "firered_reference") +CMVN_PATH = "/tmp/firered_cmvn.ark" +MODEL_PATH = "/tmp/fireredvad_stream_vad_with_cache.onnx" + + +def generate_test_signal(): + """Generate a deterministic test signal: 1 second of mixed sine waves at 16kHz. + + Uses multiple frequencies to produce non-trivial FBank features. + Returns int16 samples. + """ + sample_rate = 16000 + duration = 1.0 # 1 second = 100 frames of 10ms + t = np.arange(int(sample_rate * duration)) / sample_rate + + # Mix of frequencies: 200Hz, 800Hz, 2000Hz, 5000Hz + signal = ( + 0.3 * np.sin(2 * np.pi * 200 * t) + + 0.25 * np.sin(2 * np.pi * 800 * t) + + 0.2 * np.sin(2 * np.pi * 2000 * t) + + 0.15 * np.sin(2 * np.pi * 5000 * t) + ) + + # Scale to int16 range (use ~70% of range to avoid clipping) + signal = signal / np.max(np.abs(signal)) * 0.7 * 32767 + samples_i16 = signal.astype(np.int16) + return samples_i16 + + +def parse_cmvn(cmvn_path): + """Parse CMVN ark file and return (dim, means, inv_stds).""" + stats = kaldiio.load_mat(cmvn_path) + assert stats.shape[0] == 2, f"Expected 2 rows, got {stats.shape[0]}" + dim = stats.shape[-1] - 1 + count = stats[0, dim] + assert count >= 1 + + floor = 1e-20 + means = [] + inverse_std_variances = [] + for d in range(dim): + mean = stats[0, d] / count + means.append(float(mean)) + variance = (stats[1, d] / count) - mean * mean + if variance < floor: + variance = floor + istd = 1.0 / math.sqrt(variance) + inverse_std_variances.append(float(istd)) + + return dim, np.array(means), np.array(inverse_std_variances) + + +def extract_fbank(samples_i16, sample_rate=16000): + """Extract 80-dim FBank features using kaldi_native_fbank. + + Matches FireRedVAD's exact configuration. + """ + opts = knf.FbankOptions() + opts.frame_opts.samp_freq = sample_rate + opts.frame_opts.frame_length_ms = 25 + opts.frame_opts.frame_shift_ms = 10 + opts.frame_opts.dither = 0 + opts.frame_opts.snip_edges = True + opts.mel_opts.num_bins = 80 + opts.mel_opts.debug_mel = False + + fbank = knf.OnlineFbank(opts) + fbank.accept_waveform(sample_rate, samples_i16.tolist()) + + frames = [] + for i in range(fbank.num_frames_ready): + frames.append(fbank.get_frame(i)) + + if len(frames) == 0: + return np.zeros((0, 80)) + return np.vstack(frames) + + +def apply_cmvn(features, means, inv_stds): + """Apply CMVN normalization.""" + return (features - means) * inv_stds + + +def run_onnx_streaming(features, model_path): + """Run streaming ONNX inference frame by frame, returning per-frame probs.""" + session = ort.InferenceSession(model_path) + + # Print input/output info + print("ONNX Model Inputs:") + for inp in session.get_inputs(): + print(f" {inp.name}: shape={inp.shape}, type={inp.type}") + print("ONNX Model Outputs:") + for out in session.get_outputs(): + print(f" {out.name}: shape={out.shape}, type={out.type}") + + # Initialize caches: [8, 1, 128, 19] + caches = np.zeros((8, 1, 128, 19), dtype=np.float32) + probs = [] + + for t in range(features.shape[0]): + feat_frame = features[t:t+1, :].reshape(1, 1, 80).astype(np.float32) + + outputs = session.run( + None, + { + "feat": feat_frame, + "caches_in": caches, + }, + ) + + prob = outputs[0] # probs [1, 1, 1] + caches = outputs[1] # caches_out [8, 1, 128, 19] + + probs.append(float(prob.flatten()[0])) + + return probs + + +def main(): + os.makedirs(REF_DIR, exist_ok=True) + + print("=== Step 0: Generate test signal ===") + samples = generate_test_signal() + print(f" Samples: {len(samples)} ({len(samples)/16000:.3f}s)") + print(f" Range: [{samples.min()}, {samples.max()}]") + print(f" First 10: {samples[:10].tolist()}") + + with open(os.path.join(REF_DIR, "ref_samples.json"), "w") as f: + json.dump({"samples": samples.tolist(), "sample_rate": 16000}, f) + + print("\n=== Step 1: Parse CMVN ===") + dim, means, inv_stds = parse_cmvn(CMVN_PATH) + print(f" Dimension: {dim}") + print(f" Means (first 5): {means[:5].tolist()}") + print(f" InvStds (first 5): {inv_stds[:5].tolist()}") + + with open(os.path.join(REF_DIR, "ref_cmvn.json"), "w") as f: + json.dump({"dim": dim, "means": means.tolist(), "inv_stds": inv_stds.tolist()}, f) + + print("\n=== Step 2: Extract FBank features ===") + fbank = extract_fbank(samples) + print(f" Shape: {fbank.shape}") + print(f" Frame 0 (first 5 bins): {fbank[0, :5].tolist()}") + print(f" Frame 0 (last 5 bins): {fbank[0, -5:].tolist()}") + print(f" Min: {fbank.min():.6f}, Max: {fbank.max():.6f}") + + with open(os.path.join(REF_DIR, "ref_fbank.json"), "w") as f: + json.dump({"shape": list(fbank.shape), "data": fbank.tolist()}, f) + + print("\n=== Step 3: Apply CMVN ===") + features = apply_cmvn(fbank, means, inv_stds) + print(f" Shape: {features.shape}") + print(f" Frame 0 (first 5): {features[0, :5].tolist()}") + print(f" Min: {features.min():.6f}, Max: {features.max():.6f}") + + print("\n=== Step 4: Run ONNX streaming inference ===") + probs = run_onnx_streaming(features, MODEL_PATH) + print(f" Num frames: {len(probs)}") + print(f" First 10 probs: {probs[:10]}") + print(f" Min: {min(probs):.6f}, Max: {max(probs):.6f}") + + with open(os.path.join(REF_DIR, "ref_probs.json"), "w") as f: + json.dump({"probs": probs}, f) + + print("\n=== Done! Reference data saved to", REF_DIR, "===") + + +if __name__ == "__main__": + main() diff --git a/scripts/firered/validate_upstream.py b/scripts/firered/validate_upstream.py new file mode 100644 index 0000000..1c9b9ea --- /dev/null +++ b/scripts/firered/validate_upstream.py @@ -0,0 +1,276 @@ +#!/usr/bin/env python3 +"""Validate our reference pipeline against FireRedVAD's official pip package. + +Runs the same audio through both pipelines and compares per-frame probabilities +end-to-end. If they match, our FBank config, CMVN parsing, and ONNX inference +are correct by definition — no need to inspect upstream internals. + +Requirements: + pip install fireredvad torch soundfile numpy kaldi_native_fbank kaldiio onnxruntime + +Usage: + # With synthetic test signal (default) + python scripts/firered/validate_upstream.py + + # With a real WAV file + python scripts/firered/validate_upstream.py --wav path/to/audio.wav +""" + +import json +import math +import os +import tempfile + +import kaldiio +import kaldi_native_fbank as knf +import numpy as np +import onnxruntime as ort +import soundfile as sf + +SCRIPT_DIR = os.path.dirname(os.path.abspath(__file__)) +PROJECT_DIR = os.path.dirname(os.path.dirname(SCRIPT_DIR)) + +ONNX_MODEL_PATH = "/tmp/fireredvad_stream_vad_with_cache.onnx" +CMVN_PATH = "/tmp/firered_cmvn.ark" + + +# --------------------------------------------------------------------------- +# Our pipeline (same logic as reference.py, but on arbitrary audio) +# --------------------------------------------------------------------------- + + +def parse_cmvn(cmvn_path): + """Parse CMVN ark file and return (means, inv_stds).""" + stats = kaldiio.load_mat(cmvn_path) + dim = stats.shape[-1] - 1 + count = stats[0, dim] + floor = 1e-20 + means = [] + inv_stds = [] + for d in range(dim): + mean = stats[0, d] / count + means.append(float(mean)) + variance = (stats[1, d] / count) - mean * mean + if variance < floor: + variance = floor + inv_stds.append(float(1.0 / math.sqrt(variance))) + return np.array(means), np.array(inv_stds) + + +def extract_fbank(samples_i16, sample_rate=16000): + """Extract 80-dim FBank features using kaldi_native_fbank.""" + opts = knf.FbankOptions() + opts.frame_opts.samp_freq = sample_rate + opts.frame_opts.frame_length_ms = 25 + opts.frame_opts.frame_shift_ms = 10 + opts.frame_opts.dither = 0 + opts.frame_opts.snip_edges = True + opts.mel_opts.num_bins = 80 + opts.mel_opts.debug_mel = False + + fbank = knf.OnlineFbank(opts) + fbank.accept_waveform(sample_rate, samples_i16.tolist()) + + frames = [] + for i in range(fbank.num_frames_ready): + frames.append(fbank.get_frame(i)) + + if len(frames) == 0: + return np.zeros((0, 80)) + return np.vstack(frames) + + +def run_our_pipeline(samples_i16): + """Run our ONNX pipeline on raw i16 samples. Returns per-frame probs.""" + means, inv_stds = parse_cmvn(CMVN_PATH) + fbank = extract_fbank(samples_i16) + features = (fbank - means) * inv_stds + + session = ort.InferenceSession(ONNX_MODEL_PATH) + caches = np.zeros((8, 1, 128, 19), dtype=np.float32) + probs = [] + + for t in range(features.shape[0]): + feat_frame = features[t : t + 1, :].reshape(1, 1, 80).astype(np.float32) + outputs = session.run( + None, {"feat": feat_frame, "caches_in": caches} + ) + probs.append(float(outputs[0].flatten()[0])) + caches = outputs[1] + + return probs + + +# --------------------------------------------------------------------------- +# Upstream pipeline (fireredvad pip package) +# --------------------------------------------------------------------------- + + +def run_upstream(wav_path, model_dir): + """Run FireRedVAD's official pip package on the WAV file.""" + from fireredvad import FireRedStreamVad, FireRedStreamVadConfig + + config = FireRedStreamVadConfig(use_gpu=False) + vad = FireRedStreamVad.from_pretrained(model_dir, config=config) + frame_results, _ = vad.detect_full(wav_path) + return [r.raw_prob for r in frame_results] + + +# --------------------------------------------------------------------------- +# Test signal generation +# --------------------------------------------------------------------------- + + +def generate_test_signal(): + """Same deterministic test signal as reference.py.""" + sample_rate = 16000 + duration = 1.0 + t = np.arange(int(sample_rate * duration)) / sample_rate + signal = ( + 0.3 * np.sin(2 * np.pi * 200 * t) + + 0.25 * np.sin(2 * np.pi * 800 * t) + + 0.2 * np.sin(2 * np.pi * 2000 * t) + + 0.15 * np.sin(2 * np.pi * 5000 * t) + ) + signal = signal / np.max(np.abs(signal)) * 0.7 * 32767 + return signal.astype(np.int16) + + +# --------------------------------------------------------------------------- +# Main +# --------------------------------------------------------------------------- + + +def compare_probs(upstream_probs, our_probs, tolerance=0.01): + """Compare two probability lists and print results.""" + min_len = min(len(upstream_probs), len(our_probs)) + if len(upstream_probs) != len(our_probs): + print( + f" WARNING: frame count differs: upstream={len(upstream_probs)}, ours={len(our_probs)}" + ) + print(f" Comparing first {min_len} frames") + + upstream_arr = np.array(upstream_probs[:min_len]) + our_arr = np.array(our_probs[:min_len]) + diffs = np.abs(upstream_arr - our_arr) + + max_diff = diffs.max() + mean_diff = diffs.mean() + max_diff_idx = diffs.argmax() + + print(f" Max diff: {max_diff:.8f} (frame {max_diff_idx})") + print(f" Mean diff: {mean_diff:.8f}") + + if max_diff < tolerance: + print(f"\n PASS: max diff {max_diff:.8f} < tolerance {tolerance}") + else: + print(f"\n FAIL: max diff {max_diff:.8f} >= tolerance {tolerance}") + worst_indices = np.argsort(diffs)[-5:][::-1] + print("\n Worst frames:") + for idx in worst_indices: + print( + f" frame {idx}: upstream={upstream_arr[idx]:.8f}, " + f"ours={our_arr[idx]:.8f}, diff={diffs[idx]:.8f}" + ) + + return max_diff < tolerance + + +def main(): + import argparse + + parser = argparse.ArgumentParser( + description="Validate our ONNX pipeline against FireRedVAD upstream (PyTorch)." + ) + parser.add_argument( + "--wav", + default=None, + help="Path to a WAV file (16kHz mono). If omitted, uses a synthetic test signal.", + ) + parser.add_argument( + "--model-dir", + default="/tmp/FireRedVAD/Stream-VAD", + help="Path to Stream-VAD model directory (contains model.pth.tar + cmvn.ark).", + ) + parser.add_argument( + "--save-upstream", + action="store_true", + help="Save upstream probabilities to testdata/firered_reference/ref_upstream_probs.json", + ) + args = parser.parse_args() + + print("=== Validating our pipeline against FireRedVAD upstream ===\n") + + # Check prerequisites + model_pth = os.path.join(args.model_dir, "model.pth.tar") + if not os.path.exists(model_pth): + print(f"ERROR: {model_pth} not found.") + print("Download models first:") + print(" pip install huggingface_hub") + print( + ' python -c "from huggingface_hub import snapshot_download; ' + "snapshot_download('FireRedTeam/FireRedVAD', local_dir='/tmp/FireRedVAD')\"" + ) + return + + if not os.path.exists(ONNX_MODEL_PATH): + print(f"ERROR: {ONNX_MODEL_PATH} not found.") + print("The ONNX model is downloaded during `cargo build --features firered`.") + return + + # Prepare audio + cleanup_wav = False + if args.wav: + wav_path = args.wav + data, sr = sf.read(wav_path, dtype="int16") + samples_i16 = data + duration = len(data) / sr + print(f"Input: {wav_path} ({duration:.2f}s, {sr} Hz, {len(data)} samples)") + else: + samples_i16 = generate_test_signal() + wav_path = os.path.join(tempfile.gettempdir(), "firered_validate_test.wav") + sf.write(wav_path, samples_i16, 16000, subtype="PCM_16") + cleanup_wav = True + print(f"Input: synthetic test signal (1.00s, 16000 Hz, {len(samples_i16)} samples)") + + # Run upstream (PyTorch) + print("\n--- Upstream (fireredvad pip, PyTorch) ---") + try: + upstream_probs = run_upstream(wav_path, args.model_dir) + except ImportError: + print("ERROR: fireredvad not installed. Run: pip install fireredvad torch") + return + print(f" Frames: {len(upstream_probs)}") + print(f" First 5: {[f'{p:.6f}' for p in upstream_probs[:5]]}") + print(f" Range: [{min(upstream_probs):.6f}, {max(upstream_probs):.6f}]") + + # Run our pipeline (ONNX) + print("\n--- Our pipeline (kaldi_native_fbank + ONNX) ---") + our_probs = run_our_pipeline(samples_i16) + print(f" Frames: {len(our_probs)}") + print(f" First 5: {[f'{p:.6f}' for p in our_probs[:5]]}") + print(f" Range: [{min(our_probs):.6f}, {max(our_probs):.6f}]") + + # Compare + print("\n--- Comparison ---") + passed = compare_probs(upstream_probs, our_probs) + + if passed: + print(" Our pipeline matches FireRedVAD upstream end-to-end.") + + # Save upstream probs for Rust tests (only with default synthetic signal) + if args.save_upstream and not args.wav: + ref_dir = os.path.join(PROJECT_DIR, "testdata", "firered_reference") + out_path = os.path.join(ref_dir, "ref_upstream_probs.json") + with open(out_path, "w") as f: + json.dump({"probs": upstream_probs}, f) + print(f"\n Upstream probs saved to {out_path}") + elif args.save_upstream and args.wav: + print("\n WARNING: --save-upstream only works with the default synthetic signal") + + if cleanup_wav: + os.remove(wav_path) + + +if __name__ == "__main__": + main() diff --git a/testdata/firered_reference/README.md b/testdata/firered_reference/README.md new file mode 100644 index 0000000..db4f043 --- /dev/null +++ b/testdata/firered_reference/README.md @@ -0,0 +1,24 @@ +# FireRedVAD Reference Data + +Ground truth data generated by the Python `kaldi_native_fbank` + `kaldiio` pipeline, used by Rust tests to validate numerical parity of our pure Rust FBank + CMVN implementation. + +## Files + +| File | Used by | Contents | +|------|---------|----------| +| `ref_samples.json` | `fbank.rs`, `mod.rs` | 16000 raw i16 samples (1s deterministic sine wave test signal) | +| `ref_fbank.json` | `fbank.rs` | FBank features pre-CMVN, shape [98, 80] | +| `ref_probs.json` | `mod.rs` | Per-frame ONNX speech probabilities, shape [98] | +| `ref_upstream_probs.json` | `mod.rs` | Per-frame probabilities from upstream FireRedVAD pip package (PyTorch), shape [98] | +| `ref_cmvn.json` | — | CMVN mean/inv_std vectors (80-dim each), used as hardcoded values in `cmvn.rs` tests | + +## Regenerating + +```sh +source scripts/.venv/bin/activate # see scripts/README.md for setup +python scripts/firered/reference.py +``` + +## Details + +See `docs/experiments/2026-03-25-firered-vad-parity.md` for the full experiment log. diff --git a/testdata/firered_reference/ref_cmvn.json b/testdata/firered_reference/ref_cmvn.json new file mode 100644 index 0000000..1bb688a --- /dev/null +++ b/testdata/firered_reference/ref_cmvn.json @@ -0,0 +1 @@ +{"dim": 80, "means": [10.42295174919564, 10.862097411631494, 11.764544378124809, 12.490164701573908, 13.25983008289003, 13.89594383242307, 14.364940238918987, 14.593948347480778, 14.749723601612253, 14.668315348346496, 14.730796723156509, 14.775052459167833, 14.9890519821556, 15.178004932637085, 15.253520314586988, 15.328637048782031, 15.334018588850057, 15.288641702136166, 15.4276616890477, 15.246266155846598, 15.092573799088989, 15.290421940704482, 15.07575008669762, 15.186772872540853, 15.088673242416798, 15.170797396442111, 15.070178088017926, 15.150795340269006, 15.108532832116397, 15.115345080167454, 15.141279987705998, 15.131832359605129, 15.145195868641611, 15.19151892676777, 15.235478667211774, 15.306369752614641, 15.373021476906201, 15.416394625766584, 15.459857436373436, 15.39143273165164, 15.46357624247469, 15.399661212735632, 15.462907917820873, 15.441629120393843, 15.484969525295984, 15.552401775001249, 15.638091925650645, 15.705489346158819, 15.767008852632651, 15.855123781367105, 15.867269782501769, 15.891537408746947, 15.9231448295521, 15.978382613315533, 16.014801667676718, 16.048674939996204, 16.082029914992358, 16.09680075379873, 16.093736693349236, 16.07247919506059, 16.075509664672943, 16.02227087563821, 15.976762101902347, 15.89786454765505, 15.812741644368487, 15.711205109067762, 15.604198886052728, 15.553519438005933, 15.51025275187747, 15.460023817226517, 15.4156843628003, 15.37602764551613, 15.328348980305998, 15.295370796331634, 15.185470194591382, 15.017044975516262, 14.905080029850632, 14.623806569017782, 14.138093813776406, 13.313870348004635], "inv_stds": [0.2494980879825924, 0.23563235243542163, 0.23145152525802104, 0.2332233926481505, 0.23182660283718737, 0.22853356937894798, 0.2243486976577694, 0.21898920450844725, 0.21832438092730974, 0.22082592767700662, 0.2229673556813116, 0.22288416257259386, 0.22234810686081127, 0.22100642502031184, 0.21994202276343874, 0.22005444019015313, 0.22070092118977014, 0.22150809748461409, 0.22236667273698002, 0.22305291750035372, 0.22335341587062665, 0.22438905727453648, 0.22547701626910854, 0.2269007560258811, 0.22823023223045188, 0.22931472070164832, 0.23046728075908798, 0.23083553439603108, 0.23143382733873202, 0.2322065940520882, 0.2325798897870885, 0.2336197007969686, 0.23437240620327746, 0.23508252486137127, 0.23578078965798868, 0.235892002292441, 0.2360209777141303, 0.23663799549538955, 0.2374987640063862, 0.2379845180109627, 0.23899377757763487, 0.239748152899516, 0.24030835895648858, 0.2409769361661754, 0.24143248909906587, 0.24135465696291541, 0.24079937967447773, 0.24047405396120294, 0.23995525139180407, 0.23952287673801784, 0.2394808893818449, 0.2393650908183211, 0.23929339134427347, 0.23902199338028696, 0.23857873289710127, 0.23814701563685442, 0.23804621120577427, 0.23824193788738984, 0.2386009552212688, 0.23915406501238878, 0.23922540730102645, 0.2393830803524144, 0.2397336021407156, 0.2396056154523928, 0.24028502694537057, 0.2406181323375118, 0.2406792985927079, 0.24096201908324874, 0.24043605546026958, 0.24021526735270676, 0.23972514279402155, 0.23871998076352863, 0.2374413126648784, 0.23619509194955604, 0.23337281484306663, 0.2268023271445609, 0.2257750261856693, 0.22503847248255957, 0.2263113742246566, 0.2289949344716713]} \ No newline at end of file diff --git a/testdata/firered_reference/ref_fbank.json b/testdata/firered_reference/ref_fbank.json new file mode 100644 index 0000000..ef2d949 --- /dev/null +++ b/testdata/firered_reference/ref_fbank.json @@ -0,0 +1 @@ +{"shape": [98, 80], "data": [[11.957717895507812, 13.076170921325684, 13.540555953979492, 12.3357515335083, 19.54880142211914, 21.13422966003418, 22.153228759765625, 22.045536041259766, 19.850162506103516, 15.962414741516113, 12.538640975952148, 12.135064125061035, 11.775374412536621, 10.733291625976562, 10.073046684265137, 10.343765258789062, 10.145851135253906, 10.090106010437012, 13.432523727416992, 14.701224327087402, 14.390131950378418, 20.754722595214844, 23.930192947387695, 24.82101821899414, 23.2471923828125, 16.2166748046875, 15.633496284484863, 13.430355072021484, 11.82071590423584, 11.436760902404785, 9.276786804199219, 9.31650161743164, 8.556788444519043, 7.594658851623535, 8.436553001403809, 9.816822052001953, 9.853339195251465, 11.87073802947998, 12.51904010772705, 14.666692733764648, 17.830902099609375, 24.481689453125, 26.432226181030273, 24.109989166259766, 17.1800594329834, 14.377769470214844, 12.212200164794922, 10.967619895935059, 10.121705055236816, 9.109648704528809, 8.166550636291504, 7.561773300170898, 7.073575973510742, 6.609354019165039, 6.891024589538574, 5.786100387573242, 5.787997722625732, 6.950540065765381, 6.740077018737793, 7.3592305183410645, 8.051239967346191, 8.956376075744629, 10.082350730895996, 11.581804275512695, 13.963129043579102, 20.408432006835938, 27.32776641845703, 26.256542205810547, 15.449851989746094, 12.521167755126953, 10.454995155334473, 9.057662963867188, 8.047090530395508, 7.676164150238037, 7.133976459503174, 6.480343818664551, 5.611476421356201, 4.659528732299805, 4.80872106552124, 6.6143975257873535], [11.957717895507812, 13.076170921325684, 13.540555953979492, 12.3357515335083, 19.54880142211914, 21.13422966003418, 22.153228759765625, 22.045536041259766, 19.850162506103516, 15.962414741516113, 12.538640975952148, 12.135064125061035, 11.775374412536621, 10.733291625976562, 10.073046684265137, 10.343765258789062, 10.145851135253906, 10.090106010437012, 13.432523727416992, 14.701224327087402, 14.390131950378418, 20.754722595214844, 23.930192947387695, 24.82101821899414, 23.2471923828125, 16.2166748046875, 15.633496284484863, 13.430355072021484, 11.82071590423584, 11.436760902404785, 9.276786804199219, 9.31650161743164, 8.556788444519043, 7.594658851623535, 8.436553001403809, 9.816822052001953, 9.853339195251465, 11.87073802947998, 12.51904010772705, 14.666692733764648, 17.830902099609375, 24.481689453125, 26.432226181030273, 24.109989166259766, 17.1800594329834, 14.377769470214844, 12.212200164794922, 10.967619895935059, 10.121705055236816, 9.109648704528809, 8.166550636291504, 7.561773300170898, 7.073575973510742, 6.609354019165039, 6.891024589538574, 5.786100387573242, 5.787997722625732, 6.950540065765381, 6.740077018737793, 7.3592305183410645, 8.051239967346191, 8.956376075744629, 10.082350730895996, 11.581804275512695, 13.963129043579102, 20.408432006835938, 27.32776641845703, 26.256542205810547, 15.449851989746094, 12.521167755126953, 10.454995155334473, 9.057662963867188, 8.047090530395508, 7.676164150238037, 7.133976459503174, 6.480343818664551, 5.611476421356201, 4.659528732299805, 4.80872106552124, 6.6143975257873535], [11.957717895507812, 13.076170921325684, 13.540555953979492, 12.3357515335083, 19.54880142211914, 21.13422966003418, 22.153228759765625, 22.045536041259766, 19.850162506103516, 15.962414741516113, 12.538640975952148, 12.135064125061035, 11.775374412536621, 10.733291625976562, 10.073046684265137, 10.343765258789062, 10.145851135253906, 10.090106010437012, 13.432523727416992, 14.701224327087402, 14.390131950378418, 20.754722595214844, 23.930192947387695, 24.82101821899414, 23.2471923828125, 16.2166748046875, 15.633496284484863, 13.430355072021484, 11.82071590423584, 11.436760902404785, 9.276786804199219, 9.31650161743164, 8.556788444519043, 7.594658851623535, 8.436553001403809, 9.816822052001953, 9.853339195251465, 11.87073802947998, 12.51904010772705, 14.666692733764648, 17.830902099609375, 24.481689453125, 26.432226181030273, 24.109989166259766, 17.1800594329834, 14.377769470214844, 12.212200164794922, 10.967619895935059, 10.121705055236816, 9.109648704528809, 8.166550636291504, 7.561773300170898, 7.073575973510742, 6.609354019165039, 6.891024589538574, 5.786100387573242, 5.787997722625732, 6.950540065765381, 6.740077018737793, 7.3592305183410645, 8.051239967346191, 8.956376075744629, 10.082350730895996, 11.581804275512695, 13.963129043579102, 20.408432006835938, 27.32776641845703, 26.256542205810547, 15.449851989746094, 12.521167755126953, 10.454995155334473, 9.057662963867188, 8.047090530395508, 7.676164150238037, 7.133976459503174, 6.480343818664551, 5.611476421356201, 4.659528732299805, 4.80872106552124, 6.6143975257873535], [11.957717895507812, 13.076170921325684, 13.540555953979492, 12.3357515335083, 19.54880142211914, 21.13422966003418, 22.153228759765625, 22.045536041259766, 19.850162506103516, 15.962414741516113, 12.538640975952148, 12.135064125061035, 11.775374412536621, 10.733291625976562, 10.073046684265137, 10.343765258789062, 10.145851135253906, 10.090106010437012, 13.432523727416992, 14.701224327087402, 14.390131950378418, 20.754722595214844, 23.930192947387695, 24.82101821899414, 23.2471923828125, 16.2166748046875, 15.633496284484863, 13.430355072021484, 11.82071590423584, 11.436760902404785, 9.276786804199219, 9.31650161743164, 8.556788444519043, 7.594658851623535, 8.436553001403809, 9.816822052001953, 9.853339195251465, 11.87073802947998, 12.51904010772705, 14.666692733764648, 17.830902099609375, 24.481689453125, 26.432226181030273, 24.109989166259766, 17.1800594329834, 14.377769470214844, 12.212200164794922, 10.967619895935059, 10.121705055236816, 9.109648704528809, 8.166550636291504, 7.561773300170898, 7.073575973510742, 6.609354019165039, 6.891024589538574, 5.786100387573242, 5.787997722625732, 6.950540065765381, 6.740077018737793, 7.3592305183410645, 8.051239967346191, 8.956376075744629, 10.082350730895996, 11.581804275512695, 13.963129043579102, 20.408432006835938, 27.32776641845703, 26.256542205810547, 15.449851989746094, 12.521167755126953, 10.454995155334473, 9.057662963867188, 8.047090530395508, 7.676164150238037, 7.133976459503174, 6.480343818664551, 5.611476421356201, 4.659528732299805, 4.80872106552124, 6.6143975257873535], [11.957717895507812, 13.076170921325684, 13.540555953979492, 12.3357515335083, 19.54880142211914, 21.13422966003418, 22.153228759765625, 22.045536041259766, 19.850162506103516, 15.962414741516113, 12.538640975952148, 12.135064125061035, 11.775374412536621, 10.733291625976562, 10.073046684265137, 10.343765258789062, 10.145851135253906, 10.090106010437012, 13.432523727416992, 14.701224327087402, 14.390131950378418, 20.754722595214844, 23.930192947387695, 24.82101821899414, 23.2471923828125, 16.2166748046875, 15.633496284484863, 13.430355072021484, 11.82071590423584, 11.436760902404785, 9.276786804199219, 9.31650161743164, 8.556788444519043, 7.594658851623535, 8.436553001403809, 9.816822052001953, 9.853339195251465, 11.87073802947998, 12.51904010772705, 14.666692733764648, 17.830902099609375, 24.481689453125, 26.432226181030273, 24.109989166259766, 17.1800594329834, 14.377769470214844, 12.212200164794922, 10.967619895935059, 10.121705055236816, 9.109648704528809, 8.166550636291504, 7.561773300170898, 7.073575973510742, 6.609354019165039, 6.891024589538574, 5.786100387573242, 5.787997722625732, 6.950540065765381, 6.740077018737793, 7.3592305183410645, 8.051239967346191, 8.956376075744629, 10.082350730895996, 11.581804275512695, 13.963129043579102, 20.408432006835938, 27.32776641845703, 26.256542205810547, 15.449851989746094, 12.521167755126953, 10.454995155334473, 9.057662963867188, 8.047090530395508, 7.676164150238037, 7.133976459503174, 6.480343818664551, 5.611476421356201, 4.659528732299805, 4.80872106552124, 6.6143975257873535], [11.957717895507812, 13.076170921325684, 13.540555953979492, 12.3357515335083, 19.54880142211914, 21.13422966003418, 22.153228759765625, 22.045536041259766, 19.850162506103516, 15.962414741516113, 12.538640975952148, 12.135064125061035, 11.775374412536621, 10.733291625976562, 10.073046684265137, 10.343765258789062, 10.145851135253906, 10.090106010437012, 13.432523727416992, 14.701224327087402, 14.390131950378418, 20.754722595214844, 23.930192947387695, 24.82101821899414, 23.2471923828125, 16.2166748046875, 15.633496284484863, 13.430355072021484, 11.82071590423584, 11.436760902404785, 9.276786804199219, 9.31650161743164, 8.556788444519043, 7.594658851623535, 8.436553001403809, 9.816822052001953, 9.853339195251465, 11.87073802947998, 12.51904010772705, 14.666692733764648, 17.830902099609375, 24.481689453125, 26.432226181030273, 24.109989166259766, 17.1800594329834, 14.377769470214844, 12.212200164794922, 10.967619895935059, 10.121705055236816, 9.109648704528809, 8.166550636291504, 7.561773300170898, 7.073575973510742, 6.609354019165039, 6.891024589538574, 5.786100387573242, 5.787997722625732, 6.950540065765381, 6.740077018737793, 7.3592305183410645, 8.051239967346191, 8.956376075744629, 10.082350730895996, 11.581804275512695, 13.963129043579102, 20.408432006835938, 27.32776641845703, 26.256542205810547, 15.449851989746094, 12.521167755126953, 10.454995155334473, 9.057662963867188, 8.047090530395508, 7.676164150238037, 7.133976459503174, 6.480343818664551, 5.611476421356201, 4.659528732299805, 4.80872106552124, 6.6143975257873535], [11.957717895507812, 13.076170921325684, 13.540555953979492, 12.3357515335083, 19.54880142211914, 21.13422966003418, 22.153228759765625, 22.045536041259766, 19.850162506103516, 15.962414741516113, 12.538640975952148, 12.135064125061035, 11.775374412536621, 10.733291625976562, 10.073046684265137, 10.343765258789062, 10.145851135253906, 10.090106010437012, 13.432523727416992, 14.701224327087402, 14.390131950378418, 20.754722595214844, 23.930192947387695, 24.82101821899414, 23.2471923828125, 16.2166748046875, 15.633496284484863, 13.430355072021484, 11.82071590423584, 11.436760902404785, 9.276786804199219, 9.31650161743164, 8.556788444519043, 7.594658851623535, 8.436553001403809, 9.816822052001953, 9.853339195251465, 11.87073802947998, 12.51904010772705, 14.666692733764648, 17.830902099609375, 24.481689453125, 26.432226181030273, 24.109989166259766, 17.1800594329834, 14.377769470214844, 12.212200164794922, 10.967619895935059, 10.121705055236816, 9.109648704528809, 8.166550636291504, 7.561773300170898, 7.073575973510742, 6.609354019165039, 6.891024589538574, 5.786100387573242, 5.787997722625732, 6.950540065765381, 6.740077018737793, 7.3592305183410645, 8.051239967346191, 8.956376075744629, 10.082350730895996, 11.581804275512695, 13.963129043579102, 20.408432006835938, 27.32776641845703, 26.256542205810547, 15.449851989746094, 12.521167755126953, 10.454995155334473, 9.057662963867188, 8.047090530395508, 7.676164150238037, 7.133976459503174, 6.480343818664551, 5.611476421356201, 4.659528732299805, 4.80872106552124, 6.6143975257873535], [11.957717895507812, 13.076170921325684, 13.540555953979492, 12.3357515335083, 19.54880142211914, 21.13422966003418, 22.153228759765625, 22.045536041259766, 19.850162506103516, 15.962414741516113, 12.538640975952148, 12.135064125061035, 11.775374412536621, 10.733291625976562, 10.073046684265137, 10.343765258789062, 10.145851135253906, 10.090106010437012, 13.432523727416992, 14.701224327087402, 14.390131950378418, 20.754722595214844, 23.930192947387695, 24.82101821899414, 23.2471923828125, 16.2166748046875, 15.633496284484863, 13.430355072021484, 11.82071590423584, 11.436760902404785, 9.276786804199219, 9.31650161743164, 8.556788444519043, 7.594658851623535, 8.436553001403809, 9.816822052001953, 9.853339195251465, 11.87073802947998, 12.51904010772705, 14.666692733764648, 17.830902099609375, 24.481689453125, 26.432226181030273, 24.109989166259766, 17.1800594329834, 14.377769470214844, 12.212200164794922, 10.967619895935059, 10.121705055236816, 9.109648704528809, 8.166550636291504, 7.561773300170898, 7.073575973510742, 6.609354019165039, 6.891024589538574, 5.786100387573242, 5.787997722625732, 6.950540065765381, 6.740077018737793, 7.3592305183410645, 8.051239967346191, 8.956376075744629, 10.082350730895996, 11.581804275512695, 13.963129043579102, 20.408432006835938, 27.32776641845703, 26.256542205810547, 15.449851989746094, 12.521167755126953, 10.454995155334473, 9.057662963867188, 8.047090530395508, 7.676164150238037, 7.133976459503174, 6.480343818664551, 5.611476421356201, 4.659528732299805, 4.80872106552124, 6.6143975257873535], [11.957717895507812, 13.076170921325684, 13.540555953979492, 12.3357515335083, 19.54880142211914, 21.13422966003418, 22.153228759765625, 22.045536041259766, 19.850162506103516, 15.962414741516113, 12.538640975952148, 12.135064125061035, 11.775374412536621, 10.733291625976562, 10.073046684265137, 10.343765258789062, 10.145851135253906, 10.090106010437012, 13.432523727416992, 14.701224327087402, 14.390131950378418, 20.754722595214844, 23.930192947387695, 24.82101821899414, 23.2471923828125, 16.2166748046875, 15.633496284484863, 13.430355072021484, 11.82071590423584, 11.436760902404785, 9.276786804199219, 9.31650161743164, 8.556788444519043, 7.594658851623535, 8.436553001403809, 9.816822052001953, 9.853339195251465, 11.87073802947998, 12.51904010772705, 14.666692733764648, 17.830902099609375, 24.481689453125, 26.432226181030273, 24.109989166259766, 17.1800594329834, 14.377769470214844, 12.212200164794922, 10.967619895935059, 10.121705055236816, 9.109648704528809, 8.166550636291504, 7.561773300170898, 7.073575973510742, 6.609354019165039, 6.891024589538574, 5.786100387573242, 5.787997722625732, 6.950540065765381, 6.740077018737793, 7.3592305183410645, 8.051239967346191, 8.956376075744629, 10.082350730895996, 11.581804275512695, 13.963129043579102, 20.408432006835938, 27.32776641845703, 26.256542205810547, 15.449851989746094, 12.521167755126953, 10.454995155334473, 9.057662963867188, 8.047090530395508, 7.676164150238037, 7.133976459503174, 6.480343818664551, 5.611476421356201, 4.659528732299805, 4.80872106552124, 6.6143975257873535], [11.957717895507812, 13.076170921325684, 13.540555953979492, 12.3357515335083, 19.54880142211914, 21.13422966003418, 22.153228759765625, 22.045536041259766, 19.850162506103516, 15.962414741516113, 12.538640975952148, 12.135064125061035, 11.775374412536621, 10.733291625976562, 10.073046684265137, 10.343765258789062, 10.145851135253906, 10.090106010437012, 13.432523727416992, 14.701224327087402, 14.390131950378418, 20.754722595214844, 23.930192947387695, 24.82101821899414, 23.2471923828125, 16.2166748046875, 15.633496284484863, 13.430355072021484, 11.82071590423584, 11.436760902404785, 9.276786804199219, 9.31650161743164, 8.556788444519043, 7.594658851623535, 8.436553001403809, 9.816822052001953, 9.853339195251465, 11.87073802947998, 12.51904010772705, 14.666692733764648, 17.830902099609375, 24.481689453125, 26.432226181030273, 24.109989166259766, 17.1800594329834, 14.377769470214844, 12.212200164794922, 10.967619895935059, 10.121705055236816, 9.109648704528809, 8.166550636291504, 7.561773300170898, 7.073575973510742, 6.609354019165039, 6.891024589538574, 5.786100387573242, 5.787997722625732, 6.950540065765381, 6.740077018737793, 7.3592305183410645, 8.051239967346191, 8.956376075744629, 10.082350730895996, 11.581804275512695, 13.963129043579102, 20.408432006835938, 27.32776641845703, 26.256542205810547, 15.449851989746094, 12.521167755126953, 10.454995155334473, 9.057662963867188, 8.047090530395508, 7.676164150238037, 7.133976459503174, 6.480343818664551, 5.611476421356201, 4.659528732299805, 4.80872106552124, 6.6143975257873535], [11.957717895507812, 13.076170921325684, 13.540555953979492, 12.3357515335083, 19.54880142211914, 21.13422966003418, 22.153228759765625, 22.045536041259766, 19.850162506103516, 15.962414741516113, 12.538640975952148, 12.135064125061035, 11.775374412536621, 10.733291625976562, 10.073046684265137, 10.343765258789062, 10.145851135253906, 10.090106010437012, 13.432523727416992, 14.701224327087402, 14.390131950378418, 20.754722595214844, 23.930192947387695, 24.82101821899414, 23.2471923828125, 16.2166748046875, 15.633496284484863, 13.430355072021484, 11.82071590423584, 11.436760902404785, 9.276786804199219, 9.31650161743164, 8.556788444519043, 7.594658851623535, 8.436553001403809, 9.816822052001953, 9.853339195251465, 11.87073802947998, 12.51904010772705, 14.666692733764648, 17.830902099609375, 24.481689453125, 26.432226181030273, 24.109989166259766, 17.1800594329834, 14.377769470214844, 12.212200164794922, 10.967619895935059, 10.121705055236816, 9.109648704528809, 8.166550636291504, 7.561773300170898, 7.073575973510742, 6.609354019165039, 6.891024589538574, 5.786100387573242, 5.787997722625732, 6.950540065765381, 6.740077018737793, 7.3592305183410645, 8.051239967346191, 8.956376075744629, 10.082350730895996, 11.581804275512695, 13.963129043579102, 20.408432006835938, 27.32776641845703, 26.256542205810547, 15.449851989746094, 12.521167755126953, 10.454995155334473, 9.057662963867188, 8.047090530395508, 7.676164150238037, 7.133976459503174, 6.480343818664551, 5.611476421356201, 4.659528732299805, 4.80872106552124, 6.6143975257873535], [11.957717895507812, 13.076170921325684, 13.540555953979492, 12.3357515335083, 19.54880142211914, 21.13422966003418, 22.153228759765625, 22.045536041259766, 19.850162506103516, 15.962414741516113, 12.538640975952148, 12.135064125061035, 11.775374412536621, 10.733291625976562, 10.073046684265137, 10.343765258789062, 10.145851135253906, 10.090106010437012, 13.432523727416992, 14.701224327087402, 14.390131950378418, 20.754722595214844, 23.930192947387695, 24.82101821899414, 23.2471923828125, 16.2166748046875, 15.633496284484863, 13.430355072021484, 11.82071590423584, 11.436760902404785, 9.276786804199219, 9.31650161743164, 8.556788444519043, 7.594658851623535, 8.436553001403809, 9.816822052001953, 9.853339195251465, 11.87073802947998, 12.51904010772705, 14.666692733764648, 17.830902099609375, 24.481689453125, 26.432226181030273, 24.109989166259766, 17.1800594329834, 14.377769470214844, 12.212200164794922, 10.967619895935059, 10.121705055236816, 9.109648704528809, 8.166550636291504, 7.561773300170898, 7.073575973510742, 6.609354019165039, 6.891024589538574, 5.786100387573242, 5.787997722625732, 6.950540065765381, 6.740077018737793, 7.3592305183410645, 8.051239967346191, 8.956376075744629, 10.082350730895996, 11.581804275512695, 13.963129043579102, 20.408432006835938, 27.32776641845703, 26.256542205810547, 15.449851989746094, 12.521167755126953, 10.454995155334473, 9.057662963867188, 8.047090530395508, 7.676164150238037, 7.133976459503174, 6.480343818664551, 5.611476421356201, 4.659528732299805, 4.80872106552124, 6.6143975257873535], [11.957717895507812, 13.076170921325684, 13.540555953979492, 12.3357515335083, 19.54880142211914, 21.13422966003418, 22.153228759765625, 22.045536041259766, 19.850162506103516, 15.962414741516113, 12.538640975952148, 12.135064125061035, 11.775374412536621, 10.733291625976562, 10.073046684265137, 10.343765258789062, 10.145851135253906, 10.090106010437012, 13.432523727416992, 14.701224327087402, 14.390131950378418, 20.754722595214844, 23.930192947387695, 24.82101821899414, 23.2471923828125, 16.2166748046875, 15.633496284484863, 13.430355072021484, 11.82071590423584, 11.436760902404785, 9.276786804199219, 9.31650161743164, 8.556788444519043, 7.594658851623535, 8.436553001403809, 9.816822052001953, 9.853339195251465, 11.87073802947998, 12.51904010772705, 14.666692733764648, 17.830902099609375, 24.481689453125, 26.432226181030273, 24.109989166259766, 17.1800594329834, 14.377769470214844, 12.212200164794922, 10.967619895935059, 10.121705055236816, 9.109648704528809, 8.166550636291504, 7.561773300170898, 7.073575973510742, 6.609354019165039, 6.891024589538574, 5.786100387573242, 5.787997722625732, 6.950540065765381, 6.740077018737793, 7.3592305183410645, 8.051239967346191, 8.956376075744629, 10.082350730895996, 11.581804275512695, 13.963129043579102, 20.408432006835938, 27.32776641845703, 26.256542205810547, 15.449851989746094, 12.521167755126953, 10.454995155334473, 9.057662963867188, 8.047090530395508, 7.676164150238037, 7.133976459503174, 6.480343818664551, 5.611476421356201, 4.659528732299805, 4.80872106552124, 6.6143975257873535], [11.957717895507812, 13.076170921325684, 13.540555953979492, 12.3357515335083, 19.54880142211914, 21.13422966003418, 22.153228759765625, 22.045536041259766, 19.850162506103516, 15.962414741516113, 12.538640975952148, 12.135064125061035, 11.775374412536621, 10.733291625976562, 10.073046684265137, 10.343765258789062, 10.145851135253906, 10.090106010437012, 13.432523727416992, 14.701224327087402, 14.390131950378418, 20.754722595214844, 23.930192947387695, 24.82101821899414, 23.2471923828125, 16.2166748046875, 15.633496284484863, 13.430355072021484, 11.82071590423584, 11.436760902404785, 9.276786804199219, 9.31650161743164, 8.556788444519043, 7.594658851623535, 8.436553001403809, 9.816822052001953, 9.853339195251465, 11.87073802947998, 12.51904010772705, 14.666692733764648, 17.830902099609375, 24.481689453125, 26.432226181030273, 24.109989166259766, 17.1800594329834, 14.377769470214844, 12.212200164794922, 10.967619895935059, 10.121705055236816, 9.109648704528809, 8.166550636291504, 7.561773300170898, 7.073575973510742, 6.609354019165039, 6.891024589538574, 5.786100387573242, 5.787997722625732, 6.950540065765381, 6.740077018737793, 7.3592305183410645, 8.051239967346191, 8.956376075744629, 10.082350730895996, 11.581804275512695, 13.963129043579102, 20.408432006835938, 27.32776641845703, 26.256542205810547, 15.449851989746094, 12.521167755126953, 10.454995155334473, 9.057662963867188, 8.047090530395508, 7.676164150238037, 7.133976459503174, 6.480343818664551, 5.611476421356201, 4.659528732299805, 4.80872106552124, 6.6143975257873535], [11.957717895507812, 13.076170921325684, 13.540555953979492, 12.3357515335083, 19.54880142211914, 21.13422966003418, 22.153228759765625, 22.045536041259766, 19.850162506103516, 15.962414741516113, 12.538640975952148, 12.135064125061035, 11.775374412536621, 10.733291625976562, 10.073046684265137, 10.343765258789062, 10.145851135253906, 10.090106010437012, 13.432523727416992, 14.701224327087402, 14.390131950378418, 20.754722595214844, 23.930192947387695, 24.82101821899414, 23.2471923828125, 16.2166748046875, 15.633496284484863, 13.430355072021484, 11.82071590423584, 11.436760902404785, 9.276786804199219, 9.31650161743164, 8.556788444519043, 7.594658851623535, 8.436553001403809, 9.816822052001953, 9.853339195251465, 11.87073802947998, 12.51904010772705, 14.666692733764648, 17.830902099609375, 24.481689453125, 26.432226181030273, 24.109989166259766, 17.1800594329834, 14.377769470214844, 12.212200164794922, 10.967619895935059, 10.121705055236816, 9.109648704528809, 8.166550636291504, 7.561773300170898, 7.073575973510742, 6.609354019165039, 6.891024589538574, 5.786100387573242, 5.787997722625732, 6.950540065765381, 6.740077018737793, 7.3592305183410645, 8.051239967346191, 8.956376075744629, 10.082350730895996, 11.581804275512695, 13.963129043579102, 20.408432006835938, 27.32776641845703, 26.256542205810547, 15.449851989746094, 12.521167755126953, 10.454995155334473, 9.057662963867188, 8.047090530395508, 7.676164150238037, 7.133976459503174, 6.480343818664551, 5.611476421356201, 4.659528732299805, 4.80872106552124, 6.6143975257873535], [11.957717895507812, 13.076170921325684, 13.540555953979492, 12.3357515335083, 19.54880142211914, 21.13422966003418, 22.153228759765625, 22.045536041259766, 19.850162506103516, 15.962414741516113, 12.538640975952148, 12.135064125061035, 11.775374412536621, 10.733291625976562, 10.073046684265137, 10.343765258789062, 10.145851135253906, 10.090106010437012, 13.432523727416992, 14.701224327087402, 14.390131950378418, 20.754722595214844, 23.930192947387695, 24.82101821899414, 23.2471923828125, 16.2166748046875, 15.633496284484863, 13.430355072021484, 11.82071590423584, 11.436760902404785, 9.276786804199219, 9.31650161743164, 8.556788444519043, 7.594658851623535, 8.436553001403809, 9.816822052001953, 9.853339195251465, 11.87073802947998, 12.51904010772705, 14.666692733764648, 17.830902099609375, 24.481689453125, 26.432226181030273, 24.109989166259766, 17.1800594329834, 14.377769470214844, 12.212200164794922, 10.967619895935059, 10.121705055236816, 9.109648704528809, 8.166550636291504, 7.561773300170898, 7.073575973510742, 6.609354019165039, 6.891024589538574, 5.786100387573242, 5.787997722625732, 6.950540065765381, 6.740077018737793, 7.3592305183410645, 8.051239967346191, 8.956376075744629, 10.082350730895996, 11.581804275512695, 13.963129043579102, 20.408432006835938, 27.32776641845703, 26.256542205810547, 15.449851989746094, 12.521167755126953, 10.454995155334473, 9.057662963867188, 8.047090530395508, 7.676164150238037, 7.133976459503174, 6.480343818664551, 5.611476421356201, 4.659528732299805, 4.80872106552124, 6.6143975257873535], [11.957717895507812, 13.076170921325684, 13.540555953979492, 12.3357515335083, 19.54880142211914, 21.13422966003418, 22.153228759765625, 22.045536041259766, 19.850162506103516, 15.962414741516113, 12.538640975952148, 12.135064125061035, 11.775374412536621, 10.733291625976562, 10.073046684265137, 10.343765258789062, 10.145851135253906, 10.090106010437012, 13.432523727416992, 14.701224327087402, 14.390131950378418, 20.754722595214844, 23.930192947387695, 24.82101821899414, 23.2471923828125, 16.2166748046875, 15.633496284484863, 13.430355072021484, 11.82071590423584, 11.436760902404785, 9.276786804199219, 9.31650161743164, 8.556788444519043, 7.594658851623535, 8.436553001403809, 9.816822052001953, 9.853339195251465, 11.87073802947998, 12.51904010772705, 14.666692733764648, 17.830902099609375, 24.481689453125, 26.432226181030273, 24.109989166259766, 17.1800594329834, 14.377769470214844, 12.212200164794922, 10.967619895935059, 10.121705055236816, 9.109648704528809, 8.166550636291504, 7.561773300170898, 7.073575973510742, 6.609354019165039, 6.891024589538574, 5.786100387573242, 5.787997722625732, 6.950540065765381, 6.740077018737793, 7.3592305183410645, 8.051239967346191, 8.956376075744629, 10.082350730895996, 11.581804275512695, 13.963129043579102, 20.408432006835938, 27.32776641845703, 26.256542205810547, 15.449851989746094, 12.521167755126953, 10.454995155334473, 9.057662963867188, 8.047090530395508, 7.676164150238037, 7.133976459503174, 6.480343818664551, 5.611476421356201, 4.659528732299805, 4.80872106552124, 6.6143975257873535], [11.957717895507812, 13.076170921325684, 13.540555953979492, 12.3357515335083, 19.54880142211914, 21.13422966003418, 22.153228759765625, 22.045536041259766, 19.850162506103516, 15.962414741516113, 12.538640975952148, 12.135064125061035, 11.775374412536621, 10.733291625976562, 10.073046684265137, 10.343765258789062, 10.145851135253906, 10.090106010437012, 13.432523727416992, 14.701224327087402, 14.390131950378418, 20.754722595214844, 23.930192947387695, 24.82101821899414, 23.2471923828125, 16.2166748046875, 15.633496284484863, 13.430355072021484, 11.82071590423584, 11.436760902404785, 9.276786804199219, 9.31650161743164, 8.556788444519043, 7.594658851623535, 8.436553001403809, 9.816822052001953, 9.853339195251465, 11.87073802947998, 12.51904010772705, 14.666692733764648, 17.830902099609375, 24.481689453125, 26.432226181030273, 24.109989166259766, 17.1800594329834, 14.377769470214844, 12.212200164794922, 10.967619895935059, 10.121705055236816, 9.109648704528809, 8.166550636291504, 7.561773300170898, 7.073575973510742, 6.609354019165039, 6.891024589538574, 5.786100387573242, 5.787997722625732, 6.950540065765381, 6.740077018737793, 7.3592305183410645, 8.051239967346191, 8.956376075744629, 10.082350730895996, 11.581804275512695, 13.963129043579102, 20.408432006835938, 27.32776641845703, 26.256542205810547, 15.449851989746094, 12.521167755126953, 10.454995155334473, 9.057662963867188, 8.047090530395508, 7.676164150238037, 7.133976459503174, 6.480343818664551, 5.611476421356201, 4.659528732299805, 4.80872106552124, 6.6143975257873535], [11.957717895507812, 13.076170921325684, 13.540555953979492, 12.3357515335083, 19.54880142211914, 21.13422966003418, 22.153228759765625, 22.045536041259766, 19.850162506103516, 15.962414741516113, 12.538640975952148, 12.135064125061035, 11.775374412536621, 10.733291625976562, 10.073046684265137, 10.343765258789062, 10.145851135253906, 10.090106010437012, 13.432523727416992, 14.701224327087402, 14.390131950378418, 20.754722595214844, 23.930192947387695, 24.82101821899414, 23.2471923828125, 16.2166748046875, 15.633496284484863, 13.430355072021484, 11.82071590423584, 11.436760902404785, 9.276786804199219, 9.31650161743164, 8.556788444519043, 7.594658851623535, 8.436553001403809, 9.816822052001953, 9.853339195251465, 11.87073802947998, 12.51904010772705, 14.666692733764648, 17.830902099609375, 24.481689453125, 26.432226181030273, 24.109989166259766, 17.1800594329834, 14.377769470214844, 12.212200164794922, 10.967619895935059, 10.121705055236816, 9.109648704528809, 8.166550636291504, 7.561773300170898, 7.073575973510742, 6.609354019165039, 6.891024589538574, 5.786100387573242, 5.787997722625732, 6.950540065765381, 6.740077018737793, 7.3592305183410645, 8.051239967346191, 8.956376075744629, 10.082350730895996, 11.581804275512695, 13.963129043579102, 20.408432006835938, 27.32776641845703, 26.256542205810547, 15.449851989746094, 12.521167755126953, 10.454995155334473, 9.057662963867188, 8.047090530395508, 7.676164150238037, 7.133976459503174, 6.480343818664551, 5.611476421356201, 4.659528732299805, 4.80872106552124, 6.6143975257873535], [11.957717895507812, 13.076170921325684, 13.540555953979492, 12.3357515335083, 19.54880142211914, 21.13422966003418, 22.153228759765625, 22.045536041259766, 19.850162506103516, 15.962414741516113, 12.538640975952148, 12.135064125061035, 11.775374412536621, 10.733291625976562, 10.073046684265137, 10.343765258789062, 10.145851135253906, 10.090106010437012, 13.432523727416992, 14.701224327087402, 14.390131950378418, 20.754722595214844, 23.930192947387695, 24.82101821899414, 23.2471923828125, 16.2166748046875, 15.633496284484863, 13.430355072021484, 11.82071590423584, 11.436760902404785, 9.276786804199219, 9.31650161743164, 8.556788444519043, 7.594658851623535, 8.436553001403809, 9.816822052001953, 9.853339195251465, 11.87073802947998, 12.51904010772705, 14.666692733764648, 17.830902099609375, 24.481689453125, 26.432226181030273, 24.109989166259766, 17.1800594329834, 14.377769470214844, 12.212200164794922, 10.967619895935059, 10.121705055236816, 9.109648704528809, 8.166550636291504, 7.561773300170898, 7.073575973510742, 6.609354019165039, 6.891024589538574, 5.786100387573242, 5.787997722625732, 6.950540065765381, 6.740077018737793, 7.3592305183410645, 8.051239967346191, 8.956376075744629, 10.082350730895996, 11.581804275512695, 13.963129043579102, 20.408432006835938, 27.32776641845703, 26.256542205810547, 15.449851989746094, 12.521167755126953, 10.454995155334473, 9.057662963867188, 8.047090530395508, 7.676164150238037, 7.133976459503174, 6.480343818664551, 5.611476421356201, 4.659528732299805, 4.80872106552124, 6.6143975257873535], [11.957717895507812, 13.076170921325684, 13.540555953979492, 12.3357515335083, 19.54880142211914, 21.13422966003418, 22.153228759765625, 22.045536041259766, 19.850162506103516, 15.962414741516113, 12.538640975952148, 12.135064125061035, 11.775374412536621, 10.733291625976562, 10.073046684265137, 10.343765258789062, 10.145851135253906, 10.090106010437012, 13.432523727416992, 14.701224327087402, 14.390131950378418, 20.754722595214844, 23.930192947387695, 24.82101821899414, 23.2471923828125, 16.2166748046875, 15.633496284484863, 13.430355072021484, 11.82071590423584, 11.436760902404785, 9.276786804199219, 9.31650161743164, 8.556788444519043, 7.594658851623535, 8.436553001403809, 9.816822052001953, 9.853339195251465, 11.87073802947998, 12.51904010772705, 14.666692733764648, 17.830902099609375, 24.481689453125, 26.432226181030273, 24.109989166259766, 17.1800594329834, 14.377769470214844, 12.212200164794922, 10.967619895935059, 10.121705055236816, 9.109648704528809, 8.166550636291504, 7.561773300170898, 7.073575973510742, 6.609354019165039, 6.891024589538574, 5.786100387573242, 5.787997722625732, 6.950540065765381, 6.740077018737793, 7.3592305183410645, 8.051239967346191, 8.956376075744629, 10.082350730895996, 11.581804275512695, 13.963129043579102, 20.408432006835938, 27.32776641845703, 26.256542205810547, 15.449851989746094, 12.521167755126953, 10.454995155334473, 9.057662963867188, 8.047090530395508, 7.676164150238037, 7.133976459503174, 6.480343818664551, 5.611476421356201, 4.659528732299805, 4.80872106552124, 6.6143975257873535], [11.957717895507812, 13.076170921325684, 13.540555953979492, 12.3357515335083, 19.54880142211914, 21.13422966003418, 22.153228759765625, 22.045536041259766, 19.850162506103516, 15.962414741516113, 12.538640975952148, 12.135064125061035, 11.775374412536621, 10.733291625976562, 10.073046684265137, 10.343765258789062, 10.145851135253906, 10.090106010437012, 13.432523727416992, 14.701224327087402, 14.390131950378418, 20.754722595214844, 23.930192947387695, 24.82101821899414, 23.2471923828125, 16.2166748046875, 15.633496284484863, 13.430355072021484, 11.82071590423584, 11.436760902404785, 9.276786804199219, 9.31650161743164, 8.556788444519043, 7.594658851623535, 8.436553001403809, 9.816822052001953, 9.853339195251465, 11.87073802947998, 12.51904010772705, 14.666692733764648, 17.830902099609375, 24.481689453125, 26.432226181030273, 24.109989166259766, 17.1800594329834, 14.377769470214844, 12.212200164794922, 10.967619895935059, 10.121705055236816, 9.109648704528809, 8.166550636291504, 7.561773300170898, 7.073575973510742, 6.609354019165039, 6.891024589538574, 5.786100387573242, 5.787997722625732, 6.950540065765381, 6.740077018737793, 7.3592305183410645, 8.051239967346191, 8.956376075744629, 10.082350730895996, 11.581804275512695, 13.963129043579102, 20.408432006835938, 27.32776641845703, 26.256542205810547, 15.449851989746094, 12.521167755126953, 10.454995155334473, 9.057662963867188, 8.047090530395508, 7.676164150238037, 7.133976459503174, 6.480343818664551, 5.611476421356201, 4.659528732299805, 4.80872106552124, 6.6143975257873535], [11.957717895507812, 13.076170921325684, 13.540555953979492, 12.3357515335083, 19.54880142211914, 21.13422966003418, 22.153228759765625, 22.045536041259766, 19.850162506103516, 15.962414741516113, 12.538640975952148, 12.135064125061035, 11.775374412536621, 10.733291625976562, 10.073046684265137, 10.343765258789062, 10.145851135253906, 10.090106010437012, 13.432523727416992, 14.701224327087402, 14.390131950378418, 20.754722595214844, 23.930192947387695, 24.82101821899414, 23.2471923828125, 16.2166748046875, 15.633496284484863, 13.430355072021484, 11.82071590423584, 11.436760902404785, 9.276786804199219, 9.31650161743164, 8.556788444519043, 7.594658851623535, 8.436553001403809, 9.816822052001953, 9.853339195251465, 11.87073802947998, 12.51904010772705, 14.666692733764648, 17.830902099609375, 24.481689453125, 26.432226181030273, 24.109989166259766, 17.1800594329834, 14.377769470214844, 12.212200164794922, 10.967619895935059, 10.121705055236816, 9.109648704528809, 8.166550636291504, 7.561773300170898, 7.073575973510742, 6.609354019165039, 6.891024589538574, 5.786100387573242, 5.787997722625732, 6.950540065765381, 6.740077018737793, 7.3592305183410645, 8.051239967346191, 8.956376075744629, 10.082350730895996, 11.581804275512695, 13.963129043579102, 20.408432006835938, 27.32776641845703, 26.256542205810547, 15.449851989746094, 12.521167755126953, 10.454995155334473, 9.057662963867188, 8.047090530395508, 7.676164150238037, 7.133976459503174, 6.480343818664551, 5.611476421356201, 4.659528732299805, 4.80872106552124, 6.6143975257873535], [11.957717895507812, 13.076170921325684, 13.540555953979492, 12.3357515335083, 19.54880142211914, 21.13422966003418, 22.153228759765625, 22.045536041259766, 19.850162506103516, 15.962414741516113, 12.538640975952148, 12.135064125061035, 11.775374412536621, 10.733291625976562, 10.073046684265137, 10.343765258789062, 10.145851135253906, 10.090106010437012, 13.432523727416992, 14.701224327087402, 14.390131950378418, 20.754722595214844, 23.930192947387695, 24.82101821899414, 23.2471923828125, 16.2166748046875, 15.633496284484863, 13.430355072021484, 11.82071590423584, 11.436760902404785, 9.276786804199219, 9.31650161743164, 8.556788444519043, 7.594658851623535, 8.436553001403809, 9.816822052001953, 9.853339195251465, 11.87073802947998, 12.51904010772705, 14.666692733764648, 17.830902099609375, 24.481689453125, 26.432226181030273, 24.109989166259766, 17.1800594329834, 14.377769470214844, 12.212200164794922, 10.967619895935059, 10.121705055236816, 9.109648704528809, 8.166550636291504, 7.561773300170898, 7.073575973510742, 6.609354019165039, 6.891024589538574, 5.786100387573242, 5.787997722625732, 6.950540065765381, 6.740077018737793, 7.3592305183410645, 8.051239967346191, 8.956376075744629, 10.082350730895996, 11.581804275512695, 13.963129043579102, 20.408432006835938, 27.32776641845703, 26.256542205810547, 15.449851989746094, 12.521167755126953, 10.454995155334473, 9.057662963867188, 8.047090530395508, 7.676164150238037, 7.133976459503174, 6.480343818664551, 5.611476421356201, 4.659528732299805, 4.80872106552124, 6.6143975257873535], [11.957717895507812, 13.076170921325684, 13.540555953979492, 12.3357515335083, 19.54880142211914, 21.13422966003418, 22.153228759765625, 22.045536041259766, 19.850162506103516, 15.962414741516113, 12.538640975952148, 12.135064125061035, 11.775374412536621, 10.733291625976562, 10.073046684265137, 10.343765258789062, 10.145851135253906, 10.090106010437012, 13.432523727416992, 14.701224327087402, 14.390131950378418, 20.754722595214844, 23.930192947387695, 24.82101821899414, 23.2471923828125, 16.2166748046875, 15.633496284484863, 13.430355072021484, 11.82071590423584, 11.436760902404785, 9.276786804199219, 9.31650161743164, 8.556788444519043, 7.594658851623535, 8.436553001403809, 9.816822052001953, 9.853339195251465, 11.87073802947998, 12.51904010772705, 14.666692733764648, 17.830902099609375, 24.481689453125, 26.432226181030273, 24.109989166259766, 17.1800594329834, 14.377769470214844, 12.212200164794922, 10.967619895935059, 10.121705055236816, 9.109648704528809, 8.166550636291504, 7.561773300170898, 7.073575973510742, 6.609354019165039, 6.891024589538574, 5.786100387573242, 5.787997722625732, 6.950540065765381, 6.740077018737793, 7.3592305183410645, 8.051239967346191, 8.956376075744629, 10.082350730895996, 11.581804275512695, 13.963129043579102, 20.408432006835938, 27.32776641845703, 26.256542205810547, 15.449851989746094, 12.521167755126953, 10.454995155334473, 9.057662963867188, 8.047090530395508, 7.676164150238037, 7.133976459503174, 6.480343818664551, 5.611476421356201, 4.659528732299805, 4.80872106552124, 6.6143975257873535], [11.957717895507812, 13.076170921325684, 13.540555953979492, 12.3357515335083, 19.54880142211914, 21.13422966003418, 22.153228759765625, 22.045536041259766, 19.850162506103516, 15.962414741516113, 12.538640975952148, 12.135064125061035, 11.775374412536621, 10.733291625976562, 10.073046684265137, 10.343765258789062, 10.145851135253906, 10.090106010437012, 13.432523727416992, 14.701224327087402, 14.390131950378418, 20.754722595214844, 23.930192947387695, 24.82101821899414, 23.2471923828125, 16.2166748046875, 15.633496284484863, 13.430355072021484, 11.82071590423584, 11.436760902404785, 9.276786804199219, 9.31650161743164, 8.556788444519043, 7.594658851623535, 8.436553001403809, 9.816822052001953, 9.853339195251465, 11.87073802947998, 12.51904010772705, 14.666692733764648, 17.830902099609375, 24.481689453125, 26.432226181030273, 24.109989166259766, 17.1800594329834, 14.377769470214844, 12.212200164794922, 10.967619895935059, 10.121705055236816, 9.109648704528809, 8.166550636291504, 7.561773300170898, 7.073575973510742, 6.609354019165039, 6.891024589538574, 5.786100387573242, 5.787997722625732, 6.950540065765381, 6.740077018737793, 7.3592305183410645, 8.051239967346191, 8.956376075744629, 10.082350730895996, 11.581804275512695, 13.963129043579102, 20.408432006835938, 27.32776641845703, 26.256542205810547, 15.449851989746094, 12.521167755126953, 10.454995155334473, 9.057662963867188, 8.047090530395508, 7.676164150238037, 7.133976459503174, 6.480343818664551, 5.611476421356201, 4.659528732299805, 4.80872106552124, 6.6143975257873535], [11.957717895507812, 13.076170921325684, 13.540555953979492, 12.3357515335083, 19.54880142211914, 21.13422966003418, 22.153228759765625, 22.045536041259766, 19.850162506103516, 15.962414741516113, 12.538640975952148, 12.135064125061035, 11.775374412536621, 10.733291625976562, 10.073046684265137, 10.343765258789062, 10.145851135253906, 10.090106010437012, 13.432523727416992, 14.701224327087402, 14.390131950378418, 20.754722595214844, 23.930192947387695, 24.82101821899414, 23.2471923828125, 16.2166748046875, 15.633496284484863, 13.430355072021484, 11.82071590423584, 11.436760902404785, 9.276786804199219, 9.31650161743164, 8.556788444519043, 7.594658851623535, 8.436553001403809, 9.816822052001953, 9.853339195251465, 11.87073802947998, 12.51904010772705, 14.666692733764648, 17.830902099609375, 24.481689453125, 26.432226181030273, 24.109989166259766, 17.1800594329834, 14.377769470214844, 12.212200164794922, 10.967619895935059, 10.121705055236816, 9.109648704528809, 8.166550636291504, 7.561773300170898, 7.073575973510742, 6.609354019165039, 6.891024589538574, 5.786100387573242, 5.787997722625732, 6.950540065765381, 6.740077018737793, 7.3592305183410645, 8.051239967346191, 8.956376075744629, 10.082350730895996, 11.581804275512695, 13.963129043579102, 20.408432006835938, 27.32776641845703, 26.256542205810547, 15.449851989746094, 12.521167755126953, 10.454995155334473, 9.057662963867188, 8.047090530395508, 7.676164150238037, 7.133976459503174, 6.480343818664551, 5.611476421356201, 4.659528732299805, 4.80872106552124, 6.6143975257873535], [11.957717895507812, 13.076170921325684, 13.540555953979492, 12.3357515335083, 19.54880142211914, 21.13422966003418, 22.153228759765625, 22.045536041259766, 19.850162506103516, 15.962414741516113, 12.538640975952148, 12.135064125061035, 11.775374412536621, 10.733291625976562, 10.073046684265137, 10.343765258789062, 10.145851135253906, 10.090106010437012, 13.432523727416992, 14.701224327087402, 14.390131950378418, 20.754722595214844, 23.930192947387695, 24.82101821899414, 23.2471923828125, 16.2166748046875, 15.633496284484863, 13.430355072021484, 11.82071590423584, 11.436760902404785, 9.276786804199219, 9.31650161743164, 8.556788444519043, 7.594658851623535, 8.436553001403809, 9.816822052001953, 9.853339195251465, 11.87073802947998, 12.51904010772705, 14.666692733764648, 17.830902099609375, 24.481689453125, 26.432226181030273, 24.109989166259766, 17.1800594329834, 14.377769470214844, 12.212200164794922, 10.967619895935059, 10.121705055236816, 9.109648704528809, 8.166550636291504, 7.561773300170898, 7.073575973510742, 6.609354019165039, 6.891024589538574, 5.786100387573242, 5.787997722625732, 6.950540065765381, 6.740077018737793, 7.3592305183410645, 8.051239967346191, 8.956376075744629, 10.082350730895996, 11.581804275512695, 13.963129043579102, 20.408432006835938, 27.32776641845703, 26.256542205810547, 15.449851989746094, 12.521167755126953, 10.454995155334473, 9.057662963867188, 8.047090530395508, 7.676164150238037, 7.133976459503174, 6.480343818664551, 5.611476421356201, 4.659528732299805, 4.80872106552124, 6.6143975257873535], [11.957717895507812, 13.076170921325684, 13.540555953979492, 12.3357515335083, 19.54880142211914, 21.13422966003418, 22.153228759765625, 22.045536041259766, 19.850162506103516, 15.962414741516113, 12.538640975952148, 12.135064125061035, 11.775374412536621, 10.733291625976562, 10.073046684265137, 10.343765258789062, 10.145851135253906, 10.090106010437012, 13.432523727416992, 14.701224327087402, 14.390131950378418, 20.754722595214844, 23.930192947387695, 24.82101821899414, 23.2471923828125, 16.2166748046875, 15.633496284484863, 13.430355072021484, 11.82071590423584, 11.436760902404785, 9.276786804199219, 9.31650161743164, 8.556788444519043, 7.594658851623535, 8.436553001403809, 9.816822052001953, 9.853339195251465, 11.87073802947998, 12.51904010772705, 14.666692733764648, 17.830902099609375, 24.481689453125, 26.432226181030273, 24.109989166259766, 17.1800594329834, 14.377769470214844, 12.212200164794922, 10.967619895935059, 10.121705055236816, 9.109648704528809, 8.166550636291504, 7.561773300170898, 7.073575973510742, 6.609354019165039, 6.891024589538574, 5.786100387573242, 5.787997722625732, 6.950540065765381, 6.740077018737793, 7.3592305183410645, 8.051239967346191, 8.956376075744629, 10.082350730895996, 11.581804275512695, 13.963129043579102, 20.408432006835938, 27.32776641845703, 26.256542205810547, 15.449851989746094, 12.521167755126953, 10.454995155334473, 9.057662963867188, 8.047090530395508, 7.676164150238037, 7.133976459503174, 6.480343818664551, 5.611476421356201, 4.659528732299805, 4.80872106552124, 6.6143975257873535], [11.957717895507812, 13.076170921325684, 13.540555953979492, 12.3357515335083, 19.54880142211914, 21.13422966003418, 22.153228759765625, 22.045536041259766, 19.850162506103516, 15.962414741516113, 12.538640975952148, 12.135064125061035, 11.775374412536621, 10.733291625976562, 10.073046684265137, 10.343765258789062, 10.145851135253906, 10.090106010437012, 13.432523727416992, 14.701224327087402, 14.390131950378418, 20.754722595214844, 23.930192947387695, 24.82101821899414, 23.2471923828125, 16.2166748046875, 15.633496284484863, 13.430355072021484, 11.82071590423584, 11.436760902404785, 9.276786804199219, 9.31650161743164, 8.556788444519043, 7.594658851623535, 8.436553001403809, 9.816822052001953, 9.853339195251465, 11.87073802947998, 12.51904010772705, 14.666692733764648, 17.830902099609375, 24.481689453125, 26.432226181030273, 24.109989166259766, 17.1800594329834, 14.377769470214844, 12.212200164794922, 10.967619895935059, 10.121705055236816, 9.109648704528809, 8.166550636291504, 7.561773300170898, 7.073575973510742, 6.609354019165039, 6.891024589538574, 5.786100387573242, 5.787997722625732, 6.950540065765381, 6.740077018737793, 7.3592305183410645, 8.051239967346191, 8.956376075744629, 10.082350730895996, 11.581804275512695, 13.963129043579102, 20.408432006835938, 27.32776641845703, 26.256542205810547, 15.449851989746094, 12.521167755126953, 10.454995155334473, 9.057662963867188, 8.047090530395508, 7.676164150238037, 7.133976459503174, 6.480343818664551, 5.611476421356201, 4.659528732299805, 4.80872106552124, 6.6143975257873535], [11.957717895507812, 13.076170921325684, 13.540555953979492, 12.3357515335083, 19.54880142211914, 21.13422966003418, 22.153228759765625, 22.045536041259766, 19.850162506103516, 15.962414741516113, 12.538640975952148, 12.135064125061035, 11.775374412536621, 10.733291625976562, 10.073046684265137, 10.343765258789062, 10.145851135253906, 10.090106010437012, 13.432523727416992, 14.701224327087402, 14.390131950378418, 20.754722595214844, 23.930192947387695, 24.82101821899414, 23.2471923828125, 16.2166748046875, 15.633496284484863, 13.430355072021484, 11.82071590423584, 11.436760902404785, 9.276786804199219, 9.31650161743164, 8.556788444519043, 7.594658851623535, 8.436553001403809, 9.816822052001953, 9.853339195251465, 11.87073802947998, 12.51904010772705, 14.666692733764648, 17.830902099609375, 24.481689453125, 26.432226181030273, 24.109989166259766, 17.1800594329834, 14.377769470214844, 12.212200164794922, 10.967619895935059, 10.121705055236816, 9.109648704528809, 8.166550636291504, 7.561773300170898, 7.073575973510742, 6.609354019165039, 6.891024589538574, 5.786100387573242, 5.787997722625732, 6.950540065765381, 6.740077018737793, 7.3592305183410645, 8.051239967346191, 8.956376075744629, 10.082350730895996, 11.581804275512695, 13.963129043579102, 20.408432006835938, 27.32776641845703, 26.256542205810547, 15.449851989746094, 12.521167755126953, 10.454995155334473, 9.057662963867188, 8.047090530395508, 7.676164150238037, 7.133976459503174, 6.480343818664551, 5.611476421356201, 4.659528732299805, 4.80872106552124, 6.6143975257873535], [11.957717895507812, 13.076170921325684, 13.540555953979492, 12.3357515335083, 19.54880142211914, 21.13422966003418, 22.153228759765625, 22.045536041259766, 19.850162506103516, 15.962414741516113, 12.538640975952148, 12.135064125061035, 11.775374412536621, 10.733291625976562, 10.073046684265137, 10.343765258789062, 10.145851135253906, 10.090106010437012, 13.432523727416992, 14.701224327087402, 14.390131950378418, 20.754722595214844, 23.930192947387695, 24.82101821899414, 23.2471923828125, 16.2166748046875, 15.633496284484863, 13.430355072021484, 11.82071590423584, 11.436760902404785, 9.276786804199219, 9.31650161743164, 8.556788444519043, 7.594658851623535, 8.436553001403809, 9.816822052001953, 9.853339195251465, 11.87073802947998, 12.51904010772705, 14.666692733764648, 17.830902099609375, 24.481689453125, 26.432226181030273, 24.109989166259766, 17.1800594329834, 14.377769470214844, 12.212200164794922, 10.967619895935059, 10.121705055236816, 9.109648704528809, 8.166550636291504, 7.561773300170898, 7.073575973510742, 6.609354019165039, 6.891024589538574, 5.786100387573242, 5.787997722625732, 6.950540065765381, 6.740077018737793, 7.3592305183410645, 8.051239967346191, 8.956376075744629, 10.082350730895996, 11.581804275512695, 13.963129043579102, 20.408432006835938, 27.32776641845703, 26.256542205810547, 15.449851989746094, 12.521167755126953, 10.454995155334473, 9.057662963867188, 8.047090530395508, 7.676164150238037, 7.133976459503174, 6.480343818664551, 5.611476421356201, 4.659528732299805, 4.80872106552124, 6.6143975257873535], [11.957717895507812, 13.076170921325684, 13.540555953979492, 12.3357515335083, 19.54880142211914, 21.13422966003418, 22.153228759765625, 22.045536041259766, 19.850162506103516, 15.962414741516113, 12.538640975952148, 12.135064125061035, 11.775374412536621, 10.733291625976562, 10.073046684265137, 10.343765258789062, 10.145851135253906, 10.090106010437012, 13.432523727416992, 14.701224327087402, 14.390131950378418, 20.754722595214844, 23.930192947387695, 24.82101821899414, 23.2471923828125, 16.2166748046875, 15.633496284484863, 13.430355072021484, 11.82071590423584, 11.436760902404785, 9.276786804199219, 9.31650161743164, 8.556788444519043, 7.594658851623535, 8.436553001403809, 9.816822052001953, 9.853339195251465, 11.87073802947998, 12.51904010772705, 14.666692733764648, 17.830902099609375, 24.481689453125, 26.432226181030273, 24.109989166259766, 17.1800594329834, 14.377769470214844, 12.212200164794922, 10.967619895935059, 10.121705055236816, 9.109648704528809, 8.166550636291504, 7.561773300170898, 7.073575973510742, 6.609354019165039, 6.891024589538574, 5.786100387573242, 5.787997722625732, 6.950540065765381, 6.740077018737793, 7.3592305183410645, 8.051239967346191, 8.956376075744629, 10.082350730895996, 11.581804275512695, 13.963129043579102, 20.408432006835938, 27.32776641845703, 26.256542205810547, 15.449851989746094, 12.521167755126953, 10.454995155334473, 9.057662963867188, 8.047090530395508, 7.676164150238037, 7.133976459503174, 6.480343818664551, 5.611476421356201, 4.659528732299805, 4.80872106552124, 6.6143975257873535], [11.957717895507812, 13.076170921325684, 13.540555953979492, 12.3357515335083, 19.54880142211914, 21.13422966003418, 22.153228759765625, 22.045536041259766, 19.850162506103516, 15.962414741516113, 12.538640975952148, 12.135064125061035, 11.775374412536621, 10.733291625976562, 10.073046684265137, 10.343765258789062, 10.145851135253906, 10.090106010437012, 13.432523727416992, 14.701224327087402, 14.390131950378418, 20.754722595214844, 23.930192947387695, 24.82101821899414, 23.2471923828125, 16.2166748046875, 15.633496284484863, 13.430355072021484, 11.82071590423584, 11.436760902404785, 9.276786804199219, 9.31650161743164, 8.556788444519043, 7.594658851623535, 8.436553001403809, 9.816822052001953, 9.853339195251465, 11.87073802947998, 12.51904010772705, 14.666692733764648, 17.830902099609375, 24.481689453125, 26.432226181030273, 24.109989166259766, 17.1800594329834, 14.377769470214844, 12.212200164794922, 10.967619895935059, 10.121705055236816, 9.109648704528809, 8.166550636291504, 7.561773300170898, 7.073575973510742, 6.609354019165039, 6.891024589538574, 5.786100387573242, 5.787997722625732, 6.950540065765381, 6.740077018737793, 7.3592305183410645, 8.051239967346191, 8.956376075744629, 10.082350730895996, 11.581804275512695, 13.963129043579102, 20.408432006835938, 27.32776641845703, 26.256542205810547, 15.449851989746094, 12.521167755126953, 10.454995155334473, 9.057662963867188, 8.047090530395508, 7.676164150238037, 7.133976459503174, 6.480343818664551, 5.611476421356201, 4.659528732299805, 4.80872106552124, 6.6143975257873535], [11.957717895507812, 13.076170921325684, 13.540555953979492, 12.3357515335083, 19.54880142211914, 21.13422966003418, 22.153228759765625, 22.045536041259766, 19.850162506103516, 15.962414741516113, 12.538640975952148, 12.135064125061035, 11.775374412536621, 10.733291625976562, 10.073046684265137, 10.343765258789062, 10.145851135253906, 10.090106010437012, 13.432523727416992, 14.701224327087402, 14.390131950378418, 20.754722595214844, 23.930192947387695, 24.82101821899414, 23.2471923828125, 16.2166748046875, 15.633496284484863, 13.430355072021484, 11.82071590423584, 11.436760902404785, 9.276786804199219, 9.31650161743164, 8.556788444519043, 7.594658851623535, 8.436553001403809, 9.816822052001953, 9.853339195251465, 11.87073802947998, 12.51904010772705, 14.666692733764648, 17.830902099609375, 24.481689453125, 26.432226181030273, 24.109989166259766, 17.1800594329834, 14.377769470214844, 12.212200164794922, 10.967619895935059, 10.121705055236816, 9.109648704528809, 8.166550636291504, 7.561773300170898, 7.073575973510742, 6.609354019165039, 6.891024589538574, 5.786100387573242, 5.787997722625732, 6.950540065765381, 6.740077018737793, 7.3592305183410645, 8.051239967346191, 8.956376075744629, 10.082350730895996, 11.581804275512695, 13.963129043579102, 20.408432006835938, 27.32776641845703, 26.256542205810547, 15.449851989746094, 12.521167755126953, 10.454995155334473, 9.057662963867188, 8.047090530395508, 7.676164150238037, 7.133976459503174, 6.480343818664551, 5.611476421356201, 4.659528732299805, 4.80872106552124, 6.6143975257873535], [11.957717895507812, 13.076170921325684, 13.540555953979492, 12.3357515335083, 19.54880142211914, 21.13422966003418, 22.153228759765625, 22.045536041259766, 19.850162506103516, 15.962414741516113, 12.538640975952148, 12.135064125061035, 11.775374412536621, 10.733291625976562, 10.073046684265137, 10.343765258789062, 10.145851135253906, 10.090106010437012, 13.432523727416992, 14.701224327087402, 14.390131950378418, 20.754722595214844, 23.930192947387695, 24.82101821899414, 23.2471923828125, 16.2166748046875, 15.633496284484863, 13.430355072021484, 11.82071590423584, 11.436760902404785, 9.276786804199219, 9.31650161743164, 8.556788444519043, 7.594658851623535, 8.436553001403809, 9.816822052001953, 9.853339195251465, 11.87073802947998, 12.51904010772705, 14.666692733764648, 17.830902099609375, 24.481689453125, 26.432226181030273, 24.109989166259766, 17.1800594329834, 14.377769470214844, 12.212200164794922, 10.967619895935059, 10.121705055236816, 9.109648704528809, 8.166550636291504, 7.561773300170898, 7.073575973510742, 6.609354019165039, 6.891024589538574, 5.786100387573242, 5.787997722625732, 6.950540065765381, 6.740077018737793, 7.3592305183410645, 8.051239967346191, 8.956376075744629, 10.082350730895996, 11.581804275512695, 13.963129043579102, 20.408432006835938, 27.32776641845703, 26.256542205810547, 15.449851989746094, 12.521167755126953, 10.454995155334473, 9.057662963867188, 8.047090530395508, 7.676164150238037, 7.133976459503174, 6.480343818664551, 5.611476421356201, 4.659528732299805, 4.80872106552124, 6.6143975257873535], [11.957717895507812, 13.076170921325684, 13.540555953979492, 12.3357515335083, 19.54880142211914, 21.13422966003418, 22.153228759765625, 22.045536041259766, 19.850162506103516, 15.962414741516113, 12.538640975952148, 12.135064125061035, 11.775374412536621, 10.733291625976562, 10.073046684265137, 10.343765258789062, 10.145851135253906, 10.090106010437012, 13.432523727416992, 14.701224327087402, 14.390131950378418, 20.754722595214844, 23.930192947387695, 24.82101821899414, 23.2471923828125, 16.2166748046875, 15.633496284484863, 13.430355072021484, 11.82071590423584, 11.436760902404785, 9.276786804199219, 9.31650161743164, 8.556788444519043, 7.594658851623535, 8.436553001403809, 9.816822052001953, 9.853339195251465, 11.87073802947998, 12.51904010772705, 14.666692733764648, 17.830902099609375, 24.481689453125, 26.432226181030273, 24.109989166259766, 17.1800594329834, 14.377769470214844, 12.212200164794922, 10.967619895935059, 10.121705055236816, 9.109648704528809, 8.166550636291504, 7.561773300170898, 7.073575973510742, 6.609354019165039, 6.891024589538574, 5.786100387573242, 5.787997722625732, 6.950540065765381, 6.740077018737793, 7.3592305183410645, 8.051239967346191, 8.956376075744629, 10.082350730895996, 11.581804275512695, 13.963129043579102, 20.408432006835938, 27.32776641845703, 26.256542205810547, 15.449851989746094, 12.521167755126953, 10.454995155334473, 9.057662963867188, 8.047090530395508, 7.676164150238037, 7.133976459503174, 6.480343818664551, 5.611476421356201, 4.659528732299805, 4.80872106552124, 6.6143975257873535], [11.957717895507812, 13.076170921325684, 13.540555953979492, 12.3357515335083, 19.54880142211914, 21.13422966003418, 22.153228759765625, 22.045536041259766, 19.850162506103516, 15.962414741516113, 12.538640975952148, 12.135064125061035, 11.775374412536621, 10.733291625976562, 10.073046684265137, 10.343765258789062, 10.145851135253906, 10.090106010437012, 13.432523727416992, 14.701224327087402, 14.390131950378418, 20.754722595214844, 23.930192947387695, 24.82101821899414, 23.2471923828125, 16.2166748046875, 15.633496284484863, 13.430355072021484, 11.82071590423584, 11.436760902404785, 9.276786804199219, 9.31650161743164, 8.556788444519043, 7.594658851623535, 8.436553001403809, 9.816822052001953, 9.853339195251465, 11.87073802947998, 12.51904010772705, 14.666692733764648, 17.830902099609375, 24.481689453125, 26.432226181030273, 24.109989166259766, 17.1800594329834, 14.377769470214844, 12.212200164794922, 10.967619895935059, 10.121705055236816, 9.109648704528809, 8.166550636291504, 7.561773300170898, 7.073575973510742, 6.609354019165039, 6.891024589538574, 5.786100387573242, 5.787997722625732, 6.950540065765381, 6.740077018737793, 7.3592305183410645, 8.051239967346191, 8.956376075744629, 10.082350730895996, 11.581804275512695, 13.963129043579102, 20.408432006835938, 27.32776641845703, 26.256542205810547, 15.449851989746094, 12.521167755126953, 10.454995155334473, 9.057662963867188, 8.047090530395508, 7.676164150238037, 7.133976459503174, 6.480343818664551, 5.611476421356201, 4.659528732299805, 4.80872106552124, 6.6143975257873535], [11.957717895507812, 13.076170921325684, 13.540555953979492, 12.3357515335083, 19.54880142211914, 21.13422966003418, 22.153228759765625, 22.045536041259766, 19.850162506103516, 15.962414741516113, 12.538640975952148, 12.135064125061035, 11.775374412536621, 10.733291625976562, 10.073046684265137, 10.343765258789062, 10.145851135253906, 10.090106010437012, 13.432523727416992, 14.701224327087402, 14.390131950378418, 20.754722595214844, 23.930192947387695, 24.82101821899414, 23.2471923828125, 16.2166748046875, 15.633496284484863, 13.430355072021484, 11.82071590423584, 11.436760902404785, 9.276786804199219, 9.31650161743164, 8.556788444519043, 7.594658851623535, 8.436553001403809, 9.816822052001953, 9.853339195251465, 11.87073802947998, 12.51904010772705, 14.666692733764648, 17.830902099609375, 24.481689453125, 26.432226181030273, 24.109989166259766, 17.1800594329834, 14.377769470214844, 12.212200164794922, 10.967619895935059, 10.121705055236816, 9.109648704528809, 8.166550636291504, 7.561773300170898, 7.073575973510742, 6.609354019165039, 6.891024589538574, 5.786100387573242, 5.787997722625732, 6.950540065765381, 6.740077018737793, 7.3592305183410645, 8.051239967346191, 8.956376075744629, 10.082350730895996, 11.581804275512695, 13.963129043579102, 20.408432006835938, 27.32776641845703, 26.256542205810547, 15.449851989746094, 12.521167755126953, 10.454995155334473, 9.057662963867188, 8.047090530395508, 7.676164150238037, 7.133976459503174, 6.480343818664551, 5.611476421356201, 4.659528732299805, 4.80872106552124, 6.6143975257873535], [11.957717895507812, 13.076170921325684, 13.540555953979492, 12.3357515335083, 19.54880142211914, 21.13422966003418, 22.153228759765625, 22.045536041259766, 19.850162506103516, 15.962414741516113, 12.538640975952148, 12.135064125061035, 11.775374412536621, 10.733291625976562, 10.073046684265137, 10.343765258789062, 10.145851135253906, 10.090106010437012, 13.432523727416992, 14.701224327087402, 14.390131950378418, 20.754722595214844, 23.930192947387695, 24.82101821899414, 23.2471923828125, 16.2166748046875, 15.633496284484863, 13.430355072021484, 11.82071590423584, 11.436760902404785, 9.276786804199219, 9.31650161743164, 8.556788444519043, 7.594658851623535, 8.436553001403809, 9.816822052001953, 9.853339195251465, 11.87073802947998, 12.51904010772705, 14.666692733764648, 17.830902099609375, 24.481689453125, 26.432226181030273, 24.109989166259766, 17.1800594329834, 14.377769470214844, 12.212200164794922, 10.967619895935059, 10.121705055236816, 9.109648704528809, 8.166550636291504, 7.561773300170898, 7.073575973510742, 6.609354019165039, 6.891024589538574, 5.786100387573242, 5.787997722625732, 6.950540065765381, 6.740077018737793, 7.3592305183410645, 8.051239967346191, 8.956376075744629, 10.082350730895996, 11.581804275512695, 13.963129043579102, 20.408432006835938, 27.32776641845703, 26.256542205810547, 15.449851989746094, 12.521167755126953, 10.454995155334473, 9.057662963867188, 8.047090530395508, 7.676164150238037, 7.133976459503174, 6.480343818664551, 5.611476421356201, 4.659528732299805, 4.80872106552124, 6.6143975257873535], [11.957717895507812, 13.076170921325684, 13.540555953979492, 12.3357515335083, 19.54880142211914, 21.13422966003418, 22.153228759765625, 22.045536041259766, 19.850162506103516, 15.962414741516113, 12.538640975952148, 12.135064125061035, 11.775374412536621, 10.733291625976562, 10.073046684265137, 10.343765258789062, 10.145851135253906, 10.090106010437012, 13.432523727416992, 14.701224327087402, 14.390131950378418, 20.754722595214844, 23.930192947387695, 24.82101821899414, 23.2471923828125, 16.2166748046875, 15.633496284484863, 13.430355072021484, 11.82071590423584, 11.436760902404785, 9.276786804199219, 9.31650161743164, 8.556788444519043, 7.594658851623535, 8.436553001403809, 9.816822052001953, 9.853339195251465, 11.87073802947998, 12.51904010772705, 14.666692733764648, 17.830902099609375, 24.481689453125, 26.432226181030273, 24.109989166259766, 17.1800594329834, 14.377769470214844, 12.212200164794922, 10.967619895935059, 10.121705055236816, 9.109648704528809, 8.166550636291504, 7.561773300170898, 7.073575973510742, 6.609354019165039, 6.891024589538574, 5.786100387573242, 5.787997722625732, 6.950540065765381, 6.740077018737793, 7.3592305183410645, 8.051239967346191, 8.956376075744629, 10.082350730895996, 11.581804275512695, 13.963129043579102, 20.408432006835938, 27.32776641845703, 26.256542205810547, 15.449851989746094, 12.521167755126953, 10.454995155334473, 9.057662963867188, 8.047090530395508, 7.676164150238037, 7.133976459503174, 6.480343818664551, 5.611476421356201, 4.659528732299805, 4.80872106552124, 6.6143975257873535], [11.957717895507812, 13.076170921325684, 13.540555953979492, 12.3357515335083, 19.54880142211914, 21.13422966003418, 22.153228759765625, 22.045536041259766, 19.850162506103516, 15.962414741516113, 12.538640975952148, 12.135064125061035, 11.775374412536621, 10.733291625976562, 10.073046684265137, 10.343765258789062, 10.145851135253906, 10.090106010437012, 13.432523727416992, 14.701224327087402, 14.390131950378418, 20.754722595214844, 23.930192947387695, 24.82101821899414, 23.2471923828125, 16.2166748046875, 15.633496284484863, 13.430355072021484, 11.82071590423584, 11.436760902404785, 9.276786804199219, 9.31650161743164, 8.556788444519043, 7.594658851623535, 8.436553001403809, 9.816822052001953, 9.853339195251465, 11.87073802947998, 12.51904010772705, 14.666692733764648, 17.830902099609375, 24.481689453125, 26.432226181030273, 24.109989166259766, 17.1800594329834, 14.377769470214844, 12.212200164794922, 10.967619895935059, 10.121705055236816, 9.109648704528809, 8.166550636291504, 7.561773300170898, 7.073575973510742, 6.609354019165039, 6.891024589538574, 5.786100387573242, 5.787997722625732, 6.950540065765381, 6.740077018737793, 7.3592305183410645, 8.051239967346191, 8.956376075744629, 10.082350730895996, 11.581804275512695, 13.963129043579102, 20.408432006835938, 27.32776641845703, 26.256542205810547, 15.449851989746094, 12.521167755126953, 10.454995155334473, 9.057662963867188, 8.047090530395508, 7.676164150238037, 7.133976459503174, 6.480343818664551, 5.611476421356201, 4.659528732299805, 4.80872106552124, 6.6143975257873535], [11.957717895507812, 13.076170921325684, 13.540555953979492, 12.3357515335083, 19.54880142211914, 21.13422966003418, 22.153228759765625, 22.045536041259766, 19.850162506103516, 15.962414741516113, 12.538640975952148, 12.135064125061035, 11.775374412536621, 10.733291625976562, 10.073046684265137, 10.343765258789062, 10.145851135253906, 10.090106010437012, 13.432523727416992, 14.701224327087402, 14.390131950378418, 20.754722595214844, 23.930192947387695, 24.82101821899414, 23.2471923828125, 16.2166748046875, 15.633496284484863, 13.430355072021484, 11.82071590423584, 11.436760902404785, 9.276786804199219, 9.31650161743164, 8.556788444519043, 7.594658851623535, 8.436553001403809, 9.816822052001953, 9.853339195251465, 11.87073802947998, 12.51904010772705, 14.666692733764648, 17.830902099609375, 24.481689453125, 26.432226181030273, 24.109989166259766, 17.1800594329834, 14.377769470214844, 12.212200164794922, 10.967619895935059, 10.121705055236816, 9.109648704528809, 8.166550636291504, 7.561773300170898, 7.073575973510742, 6.609354019165039, 6.891024589538574, 5.786100387573242, 5.787997722625732, 6.950540065765381, 6.740077018737793, 7.3592305183410645, 8.051239967346191, 8.956376075744629, 10.082350730895996, 11.581804275512695, 13.963129043579102, 20.408432006835938, 27.32776641845703, 26.256542205810547, 15.449851989746094, 12.521167755126953, 10.454995155334473, 9.057662963867188, 8.047090530395508, 7.676164150238037, 7.133976459503174, 6.480343818664551, 5.611476421356201, 4.659528732299805, 4.80872106552124, 6.6143975257873535], [11.957717895507812, 13.076170921325684, 13.540555953979492, 12.3357515335083, 19.54880142211914, 21.13422966003418, 22.153228759765625, 22.045536041259766, 19.850162506103516, 15.962414741516113, 12.538640975952148, 12.135064125061035, 11.775374412536621, 10.733291625976562, 10.073046684265137, 10.343765258789062, 10.145851135253906, 10.090106010437012, 13.432523727416992, 14.701224327087402, 14.390131950378418, 20.754722595214844, 23.930192947387695, 24.82101821899414, 23.2471923828125, 16.2166748046875, 15.633496284484863, 13.430355072021484, 11.82071590423584, 11.436760902404785, 9.276786804199219, 9.31650161743164, 8.556788444519043, 7.594658851623535, 8.436553001403809, 9.816822052001953, 9.853339195251465, 11.87073802947998, 12.51904010772705, 14.666692733764648, 17.830902099609375, 24.481689453125, 26.432226181030273, 24.109989166259766, 17.1800594329834, 14.377769470214844, 12.212200164794922, 10.967619895935059, 10.121705055236816, 9.109648704528809, 8.166550636291504, 7.561773300170898, 7.073575973510742, 6.609354019165039, 6.891024589538574, 5.786100387573242, 5.787997722625732, 6.950540065765381, 6.740077018737793, 7.3592305183410645, 8.051239967346191, 8.956376075744629, 10.082350730895996, 11.581804275512695, 13.963129043579102, 20.408432006835938, 27.32776641845703, 26.256542205810547, 15.449851989746094, 12.521167755126953, 10.454995155334473, 9.057662963867188, 8.047090530395508, 7.676164150238037, 7.133976459503174, 6.480343818664551, 5.611476421356201, 4.659528732299805, 4.80872106552124, 6.6143975257873535], [11.957717895507812, 13.076170921325684, 13.540555953979492, 12.3357515335083, 19.54880142211914, 21.13422966003418, 22.153228759765625, 22.045536041259766, 19.850162506103516, 15.962414741516113, 12.538640975952148, 12.135064125061035, 11.775374412536621, 10.733291625976562, 10.073046684265137, 10.343765258789062, 10.145851135253906, 10.090106010437012, 13.432523727416992, 14.701224327087402, 14.390131950378418, 20.754722595214844, 23.930192947387695, 24.82101821899414, 23.2471923828125, 16.2166748046875, 15.633496284484863, 13.430355072021484, 11.82071590423584, 11.436760902404785, 9.276786804199219, 9.31650161743164, 8.556788444519043, 7.594658851623535, 8.436553001403809, 9.816822052001953, 9.853339195251465, 11.87073802947998, 12.51904010772705, 14.666692733764648, 17.830902099609375, 24.481689453125, 26.432226181030273, 24.109989166259766, 17.1800594329834, 14.377769470214844, 12.212200164794922, 10.967619895935059, 10.121705055236816, 9.109648704528809, 8.166550636291504, 7.561773300170898, 7.073575973510742, 6.609354019165039, 6.891024589538574, 5.786100387573242, 5.787997722625732, 6.950540065765381, 6.740077018737793, 7.3592305183410645, 8.051239967346191, 8.956376075744629, 10.082350730895996, 11.581804275512695, 13.963129043579102, 20.408432006835938, 27.32776641845703, 26.256542205810547, 15.449851989746094, 12.521167755126953, 10.454995155334473, 9.057662963867188, 8.047090530395508, 7.676164150238037, 7.133976459503174, 6.480343818664551, 5.611476421356201, 4.659528732299805, 4.80872106552124, 6.6143975257873535], [11.957717895507812, 13.076170921325684, 13.540555953979492, 12.3357515335083, 19.54880142211914, 21.13422966003418, 22.153228759765625, 22.045536041259766, 19.850162506103516, 15.962414741516113, 12.538640975952148, 12.135064125061035, 11.775374412536621, 10.733291625976562, 10.073046684265137, 10.343765258789062, 10.145851135253906, 10.090106010437012, 13.432523727416992, 14.701224327087402, 14.390131950378418, 20.754722595214844, 23.930192947387695, 24.82101821899414, 23.2471923828125, 16.2166748046875, 15.633496284484863, 13.430355072021484, 11.82071590423584, 11.436760902404785, 9.276786804199219, 9.31650161743164, 8.556788444519043, 7.594658851623535, 8.436553001403809, 9.816822052001953, 9.853339195251465, 11.87073802947998, 12.51904010772705, 14.666692733764648, 17.830902099609375, 24.481689453125, 26.432226181030273, 24.109989166259766, 17.1800594329834, 14.377769470214844, 12.212200164794922, 10.967619895935059, 10.121705055236816, 9.109648704528809, 8.166550636291504, 7.561773300170898, 7.073575973510742, 6.609354019165039, 6.891024589538574, 5.786100387573242, 5.787997722625732, 6.950540065765381, 6.740077018737793, 7.3592305183410645, 8.051239967346191, 8.956376075744629, 10.082350730895996, 11.581804275512695, 13.963129043579102, 20.408432006835938, 27.32776641845703, 26.256542205810547, 15.449851989746094, 12.521167755126953, 10.454995155334473, 9.057662963867188, 8.047090530395508, 7.676164150238037, 7.133976459503174, 6.480343818664551, 5.611476421356201, 4.659528732299805, 4.80872106552124, 6.6143975257873535], [11.957717895507812, 13.076170921325684, 13.540555953979492, 12.3357515335083, 19.54880142211914, 21.13422966003418, 22.153228759765625, 22.045536041259766, 19.850162506103516, 15.962414741516113, 12.538640975952148, 12.135064125061035, 11.775374412536621, 10.733291625976562, 10.073046684265137, 10.343765258789062, 10.145851135253906, 10.090106010437012, 13.432523727416992, 14.701224327087402, 14.390131950378418, 20.754722595214844, 23.930192947387695, 24.82101821899414, 23.2471923828125, 16.2166748046875, 15.633496284484863, 13.430355072021484, 11.82071590423584, 11.436760902404785, 9.276786804199219, 9.31650161743164, 8.556788444519043, 7.594658851623535, 8.436553001403809, 9.816822052001953, 9.853339195251465, 11.87073802947998, 12.51904010772705, 14.666692733764648, 17.830902099609375, 24.481689453125, 26.432226181030273, 24.109989166259766, 17.1800594329834, 14.377769470214844, 12.212200164794922, 10.967619895935059, 10.121705055236816, 9.109648704528809, 8.166550636291504, 7.561773300170898, 7.073575973510742, 6.609354019165039, 6.891024589538574, 5.786100387573242, 5.787997722625732, 6.950540065765381, 6.740077018737793, 7.3592305183410645, 8.051239967346191, 8.956376075744629, 10.082350730895996, 11.581804275512695, 13.963129043579102, 20.408432006835938, 27.32776641845703, 26.256542205810547, 15.449851989746094, 12.521167755126953, 10.454995155334473, 9.057662963867188, 8.047090530395508, 7.676164150238037, 7.133976459503174, 6.480343818664551, 5.611476421356201, 4.659528732299805, 4.80872106552124, 6.6143975257873535], [11.957717895507812, 13.076170921325684, 13.540555953979492, 12.3357515335083, 19.54880142211914, 21.13422966003418, 22.153228759765625, 22.045536041259766, 19.850162506103516, 15.962414741516113, 12.538640975952148, 12.135064125061035, 11.775374412536621, 10.733291625976562, 10.073046684265137, 10.343765258789062, 10.145851135253906, 10.090106010437012, 13.432523727416992, 14.701224327087402, 14.390131950378418, 20.754722595214844, 23.930192947387695, 24.82101821899414, 23.2471923828125, 16.2166748046875, 15.633496284484863, 13.430355072021484, 11.82071590423584, 11.436760902404785, 9.276786804199219, 9.31650161743164, 8.556788444519043, 7.594658851623535, 8.436553001403809, 9.816822052001953, 9.853339195251465, 11.87073802947998, 12.51904010772705, 14.666692733764648, 17.830902099609375, 24.481689453125, 26.432226181030273, 24.109989166259766, 17.1800594329834, 14.377769470214844, 12.212200164794922, 10.967619895935059, 10.121705055236816, 9.109648704528809, 8.166550636291504, 7.561773300170898, 7.073575973510742, 6.609354019165039, 6.891024589538574, 5.786100387573242, 5.787997722625732, 6.950540065765381, 6.740077018737793, 7.3592305183410645, 8.051239967346191, 8.956376075744629, 10.082350730895996, 11.581804275512695, 13.963129043579102, 20.408432006835938, 27.32776641845703, 26.256542205810547, 15.449851989746094, 12.521167755126953, 10.454995155334473, 9.057662963867188, 8.047090530395508, 7.676164150238037, 7.133976459503174, 6.480343818664551, 5.611476421356201, 4.659528732299805, 4.80872106552124, 6.6143975257873535], [11.957717895507812, 13.076170921325684, 13.540555953979492, 12.3357515335083, 19.54880142211914, 21.13422966003418, 22.153228759765625, 22.045536041259766, 19.850162506103516, 15.962414741516113, 12.538640975952148, 12.135064125061035, 11.775374412536621, 10.733291625976562, 10.073046684265137, 10.343765258789062, 10.145851135253906, 10.090106010437012, 13.432523727416992, 14.701224327087402, 14.390131950378418, 20.754722595214844, 23.930192947387695, 24.82101821899414, 23.2471923828125, 16.2166748046875, 15.633496284484863, 13.430355072021484, 11.82071590423584, 11.436760902404785, 9.276786804199219, 9.31650161743164, 8.556788444519043, 7.594658851623535, 8.436553001403809, 9.816822052001953, 9.853339195251465, 11.87073802947998, 12.51904010772705, 14.666692733764648, 17.830902099609375, 24.481689453125, 26.432226181030273, 24.109989166259766, 17.1800594329834, 14.377769470214844, 12.212200164794922, 10.967619895935059, 10.121705055236816, 9.109648704528809, 8.166550636291504, 7.561773300170898, 7.073575973510742, 6.609354019165039, 6.891024589538574, 5.786100387573242, 5.787997722625732, 6.950540065765381, 6.740077018737793, 7.3592305183410645, 8.051239967346191, 8.956376075744629, 10.082350730895996, 11.581804275512695, 13.963129043579102, 20.408432006835938, 27.32776641845703, 26.256542205810547, 15.449851989746094, 12.521167755126953, 10.454995155334473, 9.057662963867188, 8.047090530395508, 7.676164150238037, 7.133976459503174, 6.480343818664551, 5.611476421356201, 4.659528732299805, 4.80872106552124, 6.6143975257873535], [11.957717895507812, 13.076170921325684, 13.540555953979492, 12.3357515335083, 19.54880142211914, 21.13422966003418, 22.153228759765625, 22.045536041259766, 19.850162506103516, 15.962414741516113, 12.538640975952148, 12.135064125061035, 11.775374412536621, 10.733291625976562, 10.073046684265137, 10.343765258789062, 10.145851135253906, 10.090106010437012, 13.432523727416992, 14.701224327087402, 14.390131950378418, 20.754722595214844, 23.930192947387695, 24.82101821899414, 23.2471923828125, 16.2166748046875, 15.633496284484863, 13.430355072021484, 11.82071590423584, 11.436760902404785, 9.276786804199219, 9.31650161743164, 8.556788444519043, 7.594658851623535, 8.436553001403809, 9.816822052001953, 9.853339195251465, 11.87073802947998, 12.51904010772705, 14.666692733764648, 17.830902099609375, 24.481689453125, 26.432226181030273, 24.109989166259766, 17.1800594329834, 14.377769470214844, 12.212200164794922, 10.967619895935059, 10.121705055236816, 9.109648704528809, 8.166550636291504, 7.561773300170898, 7.073575973510742, 6.609354019165039, 6.891024589538574, 5.786100387573242, 5.787997722625732, 6.950540065765381, 6.740077018737793, 7.3592305183410645, 8.051239967346191, 8.956376075744629, 10.082350730895996, 11.581804275512695, 13.963129043579102, 20.408432006835938, 27.32776641845703, 26.256542205810547, 15.449851989746094, 12.521167755126953, 10.454995155334473, 9.057662963867188, 8.047090530395508, 7.676164150238037, 7.133976459503174, 6.480343818664551, 5.611476421356201, 4.659528732299805, 4.80872106552124, 6.6143975257873535], [11.957717895507812, 13.076170921325684, 13.540555953979492, 12.3357515335083, 19.54880142211914, 21.13422966003418, 22.153228759765625, 22.045536041259766, 19.850162506103516, 15.962414741516113, 12.538640975952148, 12.135064125061035, 11.775374412536621, 10.733291625976562, 10.073046684265137, 10.343765258789062, 10.145851135253906, 10.090106010437012, 13.432523727416992, 14.701224327087402, 14.390131950378418, 20.754722595214844, 23.930192947387695, 24.82101821899414, 23.2471923828125, 16.2166748046875, 15.633496284484863, 13.430355072021484, 11.82071590423584, 11.436760902404785, 9.276786804199219, 9.31650161743164, 8.556788444519043, 7.594658851623535, 8.436553001403809, 9.816822052001953, 9.853339195251465, 11.87073802947998, 12.51904010772705, 14.666692733764648, 17.830902099609375, 24.481689453125, 26.432226181030273, 24.109989166259766, 17.1800594329834, 14.377769470214844, 12.212200164794922, 10.967619895935059, 10.121705055236816, 9.109648704528809, 8.166550636291504, 7.561773300170898, 7.073575973510742, 6.609354019165039, 6.891024589538574, 5.786100387573242, 5.787997722625732, 6.950540065765381, 6.740077018737793, 7.3592305183410645, 8.051239967346191, 8.956376075744629, 10.082350730895996, 11.581804275512695, 13.963129043579102, 20.408432006835938, 27.32776641845703, 26.256542205810547, 15.449851989746094, 12.521167755126953, 10.454995155334473, 9.057662963867188, 8.047090530395508, 7.676164150238037, 7.133976459503174, 6.480343818664551, 5.611476421356201, 4.659528732299805, 4.80872106552124, 6.6143975257873535], [11.957717895507812, 13.076170921325684, 13.540555953979492, 12.3357515335083, 19.54880142211914, 21.13422966003418, 22.153228759765625, 22.045536041259766, 19.850162506103516, 15.962414741516113, 12.538640975952148, 12.135064125061035, 11.775374412536621, 10.733291625976562, 10.073046684265137, 10.343765258789062, 10.145851135253906, 10.090106010437012, 13.432523727416992, 14.701224327087402, 14.390131950378418, 20.754722595214844, 23.930192947387695, 24.82101821899414, 23.2471923828125, 16.2166748046875, 15.633496284484863, 13.430355072021484, 11.82071590423584, 11.436760902404785, 9.276786804199219, 9.31650161743164, 8.556788444519043, 7.594658851623535, 8.436553001403809, 9.816822052001953, 9.853339195251465, 11.87073802947998, 12.51904010772705, 14.666692733764648, 17.830902099609375, 24.481689453125, 26.432226181030273, 24.109989166259766, 17.1800594329834, 14.377769470214844, 12.212200164794922, 10.967619895935059, 10.121705055236816, 9.109648704528809, 8.166550636291504, 7.561773300170898, 7.073575973510742, 6.609354019165039, 6.891024589538574, 5.786100387573242, 5.787997722625732, 6.950540065765381, 6.740077018737793, 7.3592305183410645, 8.051239967346191, 8.956376075744629, 10.082350730895996, 11.581804275512695, 13.963129043579102, 20.408432006835938, 27.32776641845703, 26.256542205810547, 15.449851989746094, 12.521167755126953, 10.454995155334473, 9.057662963867188, 8.047090530395508, 7.676164150238037, 7.133976459503174, 6.480343818664551, 5.611476421356201, 4.659528732299805, 4.80872106552124, 6.6143975257873535], [11.957717895507812, 13.076170921325684, 13.540555953979492, 12.3357515335083, 19.54880142211914, 21.13422966003418, 22.153228759765625, 22.045536041259766, 19.850162506103516, 15.962414741516113, 12.538640975952148, 12.135064125061035, 11.775374412536621, 10.733291625976562, 10.073046684265137, 10.343765258789062, 10.145851135253906, 10.090106010437012, 13.432523727416992, 14.701224327087402, 14.390131950378418, 20.754722595214844, 23.930192947387695, 24.82101821899414, 23.2471923828125, 16.2166748046875, 15.633496284484863, 13.430355072021484, 11.82071590423584, 11.436760902404785, 9.276786804199219, 9.31650161743164, 8.556788444519043, 7.594658851623535, 8.436553001403809, 9.816822052001953, 9.853339195251465, 11.87073802947998, 12.51904010772705, 14.666692733764648, 17.830902099609375, 24.481689453125, 26.432226181030273, 24.109989166259766, 17.1800594329834, 14.377769470214844, 12.212200164794922, 10.967619895935059, 10.121705055236816, 9.109648704528809, 8.166550636291504, 7.561773300170898, 7.073575973510742, 6.609354019165039, 6.891024589538574, 5.786100387573242, 5.787997722625732, 6.950540065765381, 6.740077018737793, 7.3592305183410645, 8.051239967346191, 8.956376075744629, 10.082350730895996, 11.581804275512695, 13.963129043579102, 20.408432006835938, 27.32776641845703, 26.256542205810547, 15.449851989746094, 12.521167755126953, 10.454995155334473, 9.057662963867188, 8.047090530395508, 7.676164150238037, 7.133976459503174, 6.480343818664551, 5.611476421356201, 4.659528732299805, 4.80872106552124, 6.6143975257873535], [11.957717895507812, 13.076170921325684, 13.540555953979492, 12.3357515335083, 19.54880142211914, 21.13422966003418, 22.153228759765625, 22.045536041259766, 19.850162506103516, 15.962414741516113, 12.538640975952148, 12.135064125061035, 11.775374412536621, 10.733291625976562, 10.073046684265137, 10.343765258789062, 10.145851135253906, 10.090106010437012, 13.432523727416992, 14.701224327087402, 14.390131950378418, 20.754722595214844, 23.930192947387695, 24.82101821899414, 23.2471923828125, 16.2166748046875, 15.633496284484863, 13.430355072021484, 11.82071590423584, 11.436760902404785, 9.276786804199219, 9.31650161743164, 8.556788444519043, 7.594658851623535, 8.436553001403809, 9.816822052001953, 9.853339195251465, 11.87073802947998, 12.51904010772705, 14.666692733764648, 17.830902099609375, 24.481689453125, 26.432226181030273, 24.109989166259766, 17.1800594329834, 14.377769470214844, 12.212200164794922, 10.967619895935059, 10.121705055236816, 9.109648704528809, 8.166550636291504, 7.561773300170898, 7.073575973510742, 6.609354019165039, 6.891024589538574, 5.786100387573242, 5.787997722625732, 6.950540065765381, 6.740077018737793, 7.3592305183410645, 8.051239967346191, 8.956376075744629, 10.082350730895996, 11.581804275512695, 13.963129043579102, 20.408432006835938, 27.32776641845703, 26.256542205810547, 15.449851989746094, 12.521167755126953, 10.454995155334473, 9.057662963867188, 8.047090530395508, 7.676164150238037, 7.133976459503174, 6.480343818664551, 5.611476421356201, 4.659528732299805, 4.80872106552124, 6.6143975257873535], [11.957717895507812, 13.076170921325684, 13.540555953979492, 12.3357515335083, 19.54880142211914, 21.13422966003418, 22.153228759765625, 22.045536041259766, 19.850162506103516, 15.962414741516113, 12.538640975952148, 12.135064125061035, 11.775374412536621, 10.733291625976562, 10.073046684265137, 10.343765258789062, 10.145851135253906, 10.090106010437012, 13.432523727416992, 14.701224327087402, 14.390131950378418, 20.754722595214844, 23.930192947387695, 24.82101821899414, 23.2471923828125, 16.2166748046875, 15.633496284484863, 13.430355072021484, 11.82071590423584, 11.436760902404785, 9.276786804199219, 9.31650161743164, 8.556788444519043, 7.594658851623535, 8.436553001403809, 9.816822052001953, 9.853339195251465, 11.87073802947998, 12.51904010772705, 14.666692733764648, 17.830902099609375, 24.481689453125, 26.432226181030273, 24.109989166259766, 17.1800594329834, 14.377769470214844, 12.212200164794922, 10.967619895935059, 10.121705055236816, 9.109648704528809, 8.166550636291504, 7.561773300170898, 7.073575973510742, 6.609354019165039, 6.891024589538574, 5.786100387573242, 5.787997722625732, 6.950540065765381, 6.740077018737793, 7.3592305183410645, 8.051239967346191, 8.956376075744629, 10.082350730895996, 11.581804275512695, 13.963129043579102, 20.408432006835938, 27.32776641845703, 26.256542205810547, 15.449851989746094, 12.521167755126953, 10.454995155334473, 9.057662963867188, 8.047090530395508, 7.676164150238037, 7.133976459503174, 6.480343818664551, 5.611476421356201, 4.659528732299805, 4.80872106552124, 6.6143975257873535], [11.957717895507812, 13.076170921325684, 13.540555953979492, 12.3357515335083, 19.54880142211914, 21.13422966003418, 22.153228759765625, 22.045536041259766, 19.850162506103516, 15.962414741516113, 12.538640975952148, 12.135064125061035, 11.775374412536621, 10.733291625976562, 10.073046684265137, 10.343765258789062, 10.145851135253906, 10.090106010437012, 13.432523727416992, 14.701224327087402, 14.390131950378418, 20.754722595214844, 23.930192947387695, 24.82101821899414, 23.2471923828125, 16.2166748046875, 15.633496284484863, 13.430355072021484, 11.82071590423584, 11.436760902404785, 9.276786804199219, 9.31650161743164, 8.556788444519043, 7.594658851623535, 8.436553001403809, 9.816822052001953, 9.853339195251465, 11.87073802947998, 12.51904010772705, 14.666692733764648, 17.830902099609375, 24.481689453125, 26.432226181030273, 24.109989166259766, 17.1800594329834, 14.377769470214844, 12.212200164794922, 10.967619895935059, 10.121705055236816, 9.109648704528809, 8.166550636291504, 7.561773300170898, 7.073575973510742, 6.609354019165039, 6.891024589538574, 5.786100387573242, 5.787997722625732, 6.950540065765381, 6.740077018737793, 7.3592305183410645, 8.051239967346191, 8.956376075744629, 10.082350730895996, 11.581804275512695, 13.963129043579102, 20.408432006835938, 27.32776641845703, 26.256542205810547, 15.449851989746094, 12.521167755126953, 10.454995155334473, 9.057662963867188, 8.047090530395508, 7.676164150238037, 7.133976459503174, 6.480343818664551, 5.611476421356201, 4.659528732299805, 4.80872106552124, 6.6143975257873535], [11.957717895507812, 13.076170921325684, 13.540555953979492, 12.3357515335083, 19.54880142211914, 21.13422966003418, 22.153228759765625, 22.045536041259766, 19.850162506103516, 15.962414741516113, 12.538640975952148, 12.135064125061035, 11.775374412536621, 10.733291625976562, 10.073046684265137, 10.343765258789062, 10.145851135253906, 10.090106010437012, 13.432523727416992, 14.701224327087402, 14.390131950378418, 20.754722595214844, 23.930192947387695, 24.82101821899414, 23.2471923828125, 16.2166748046875, 15.633496284484863, 13.430355072021484, 11.82071590423584, 11.436760902404785, 9.276786804199219, 9.31650161743164, 8.556788444519043, 7.594658851623535, 8.436553001403809, 9.816822052001953, 9.853339195251465, 11.87073802947998, 12.51904010772705, 14.666692733764648, 17.830902099609375, 24.481689453125, 26.432226181030273, 24.109989166259766, 17.1800594329834, 14.377769470214844, 12.212200164794922, 10.967619895935059, 10.121705055236816, 9.109648704528809, 8.166550636291504, 7.561773300170898, 7.073575973510742, 6.609354019165039, 6.891024589538574, 5.786100387573242, 5.787997722625732, 6.950540065765381, 6.740077018737793, 7.3592305183410645, 8.051239967346191, 8.956376075744629, 10.082350730895996, 11.581804275512695, 13.963129043579102, 20.408432006835938, 27.32776641845703, 26.256542205810547, 15.449851989746094, 12.521167755126953, 10.454995155334473, 9.057662963867188, 8.047090530395508, 7.676164150238037, 7.133976459503174, 6.480343818664551, 5.611476421356201, 4.659528732299805, 4.80872106552124, 6.6143975257873535], [11.957717895507812, 13.076170921325684, 13.540555953979492, 12.3357515335083, 19.54880142211914, 21.13422966003418, 22.153228759765625, 22.045536041259766, 19.850162506103516, 15.962414741516113, 12.538640975952148, 12.135064125061035, 11.775374412536621, 10.733291625976562, 10.073046684265137, 10.343765258789062, 10.145851135253906, 10.090106010437012, 13.432523727416992, 14.701224327087402, 14.390131950378418, 20.754722595214844, 23.930192947387695, 24.82101821899414, 23.2471923828125, 16.2166748046875, 15.633496284484863, 13.430355072021484, 11.82071590423584, 11.436760902404785, 9.276786804199219, 9.31650161743164, 8.556788444519043, 7.594658851623535, 8.436553001403809, 9.816822052001953, 9.853339195251465, 11.87073802947998, 12.51904010772705, 14.666692733764648, 17.830902099609375, 24.481689453125, 26.432226181030273, 24.109989166259766, 17.1800594329834, 14.377769470214844, 12.212200164794922, 10.967619895935059, 10.121705055236816, 9.109648704528809, 8.166550636291504, 7.561773300170898, 7.073575973510742, 6.609354019165039, 6.891024589538574, 5.786100387573242, 5.787997722625732, 6.950540065765381, 6.740077018737793, 7.3592305183410645, 8.051239967346191, 8.956376075744629, 10.082350730895996, 11.581804275512695, 13.963129043579102, 20.408432006835938, 27.32776641845703, 26.256542205810547, 15.449851989746094, 12.521167755126953, 10.454995155334473, 9.057662963867188, 8.047090530395508, 7.676164150238037, 7.133976459503174, 6.480343818664551, 5.611476421356201, 4.659528732299805, 4.80872106552124, 6.6143975257873535], [11.957717895507812, 13.076170921325684, 13.540555953979492, 12.3357515335083, 19.54880142211914, 21.13422966003418, 22.153228759765625, 22.045536041259766, 19.850162506103516, 15.962414741516113, 12.538640975952148, 12.135064125061035, 11.775374412536621, 10.733291625976562, 10.073046684265137, 10.343765258789062, 10.145851135253906, 10.090106010437012, 13.432523727416992, 14.701224327087402, 14.390131950378418, 20.754722595214844, 23.930192947387695, 24.82101821899414, 23.2471923828125, 16.2166748046875, 15.633496284484863, 13.430355072021484, 11.82071590423584, 11.436760902404785, 9.276786804199219, 9.31650161743164, 8.556788444519043, 7.594658851623535, 8.436553001403809, 9.816822052001953, 9.853339195251465, 11.87073802947998, 12.51904010772705, 14.666692733764648, 17.830902099609375, 24.481689453125, 26.432226181030273, 24.109989166259766, 17.1800594329834, 14.377769470214844, 12.212200164794922, 10.967619895935059, 10.121705055236816, 9.109648704528809, 8.166550636291504, 7.561773300170898, 7.073575973510742, 6.609354019165039, 6.891024589538574, 5.786100387573242, 5.787997722625732, 6.950540065765381, 6.740077018737793, 7.3592305183410645, 8.051239967346191, 8.956376075744629, 10.082350730895996, 11.581804275512695, 13.963129043579102, 20.408432006835938, 27.32776641845703, 26.256542205810547, 15.449851989746094, 12.521167755126953, 10.454995155334473, 9.057662963867188, 8.047090530395508, 7.676164150238037, 7.133976459503174, 6.480343818664551, 5.611476421356201, 4.659528732299805, 4.80872106552124, 6.6143975257873535], [11.957717895507812, 13.076170921325684, 13.540555953979492, 12.3357515335083, 19.54880142211914, 21.13422966003418, 22.153228759765625, 22.045536041259766, 19.850162506103516, 15.962414741516113, 12.538640975952148, 12.135064125061035, 11.775374412536621, 10.733291625976562, 10.073046684265137, 10.343765258789062, 10.145851135253906, 10.090106010437012, 13.432523727416992, 14.701224327087402, 14.390131950378418, 20.754722595214844, 23.930192947387695, 24.82101821899414, 23.2471923828125, 16.2166748046875, 15.633496284484863, 13.430355072021484, 11.82071590423584, 11.436760902404785, 9.276786804199219, 9.31650161743164, 8.556788444519043, 7.594658851623535, 8.436553001403809, 9.816822052001953, 9.853339195251465, 11.87073802947998, 12.51904010772705, 14.666692733764648, 17.830902099609375, 24.481689453125, 26.432226181030273, 24.109989166259766, 17.1800594329834, 14.377769470214844, 12.212200164794922, 10.967619895935059, 10.121705055236816, 9.109648704528809, 8.166550636291504, 7.561773300170898, 7.073575973510742, 6.609354019165039, 6.891024589538574, 5.786100387573242, 5.787997722625732, 6.950540065765381, 6.740077018737793, 7.3592305183410645, 8.051239967346191, 8.956376075744629, 10.082350730895996, 11.581804275512695, 13.963129043579102, 20.408432006835938, 27.32776641845703, 26.256542205810547, 15.449851989746094, 12.521167755126953, 10.454995155334473, 9.057662963867188, 8.047090530395508, 7.676164150238037, 7.133976459503174, 6.480343818664551, 5.611476421356201, 4.659528732299805, 4.80872106552124, 6.6143975257873535], [11.957717895507812, 13.076170921325684, 13.540555953979492, 12.3357515335083, 19.54880142211914, 21.13422966003418, 22.153228759765625, 22.045536041259766, 19.850162506103516, 15.962414741516113, 12.538640975952148, 12.135064125061035, 11.775374412536621, 10.733291625976562, 10.073046684265137, 10.343765258789062, 10.145851135253906, 10.090106010437012, 13.432523727416992, 14.701224327087402, 14.390131950378418, 20.754722595214844, 23.930192947387695, 24.82101821899414, 23.2471923828125, 16.2166748046875, 15.633496284484863, 13.430355072021484, 11.82071590423584, 11.436760902404785, 9.276786804199219, 9.31650161743164, 8.556788444519043, 7.594658851623535, 8.436553001403809, 9.816822052001953, 9.853339195251465, 11.87073802947998, 12.51904010772705, 14.666692733764648, 17.830902099609375, 24.481689453125, 26.432226181030273, 24.109989166259766, 17.1800594329834, 14.377769470214844, 12.212200164794922, 10.967619895935059, 10.121705055236816, 9.109648704528809, 8.166550636291504, 7.561773300170898, 7.073575973510742, 6.609354019165039, 6.891024589538574, 5.786100387573242, 5.787997722625732, 6.950540065765381, 6.740077018737793, 7.3592305183410645, 8.051239967346191, 8.956376075744629, 10.082350730895996, 11.581804275512695, 13.963129043579102, 20.408432006835938, 27.32776641845703, 26.256542205810547, 15.449851989746094, 12.521167755126953, 10.454995155334473, 9.057662963867188, 8.047090530395508, 7.676164150238037, 7.133976459503174, 6.480343818664551, 5.611476421356201, 4.659528732299805, 4.80872106552124, 6.6143975257873535], [11.957717895507812, 13.076170921325684, 13.540555953979492, 12.3357515335083, 19.54880142211914, 21.13422966003418, 22.153228759765625, 22.045536041259766, 19.850162506103516, 15.962414741516113, 12.538640975952148, 12.135064125061035, 11.775374412536621, 10.733291625976562, 10.073046684265137, 10.343765258789062, 10.145851135253906, 10.090106010437012, 13.432523727416992, 14.701224327087402, 14.390131950378418, 20.754722595214844, 23.930192947387695, 24.82101821899414, 23.2471923828125, 16.2166748046875, 15.633496284484863, 13.430355072021484, 11.82071590423584, 11.436760902404785, 9.276786804199219, 9.31650161743164, 8.556788444519043, 7.594658851623535, 8.436553001403809, 9.816822052001953, 9.853339195251465, 11.87073802947998, 12.51904010772705, 14.666692733764648, 17.830902099609375, 24.481689453125, 26.432226181030273, 24.109989166259766, 17.1800594329834, 14.377769470214844, 12.212200164794922, 10.967619895935059, 10.121705055236816, 9.109648704528809, 8.166550636291504, 7.561773300170898, 7.073575973510742, 6.609354019165039, 6.891024589538574, 5.786100387573242, 5.787997722625732, 6.950540065765381, 6.740077018737793, 7.3592305183410645, 8.051239967346191, 8.956376075744629, 10.082350730895996, 11.581804275512695, 13.963129043579102, 20.408432006835938, 27.32776641845703, 26.256542205810547, 15.449851989746094, 12.521167755126953, 10.454995155334473, 9.057662963867188, 8.047090530395508, 7.676164150238037, 7.133976459503174, 6.480343818664551, 5.611476421356201, 4.659528732299805, 4.80872106552124, 6.6143975257873535], [11.957717895507812, 13.076170921325684, 13.540555953979492, 12.3357515335083, 19.54880142211914, 21.13422966003418, 22.153228759765625, 22.045536041259766, 19.850162506103516, 15.962414741516113, 12.538640975952148, 12.135064125061035, 11.775374412536621, 10.733291625976562, 10.073046684265137, 10.343765258789062, 10.145851135253906, 10.090106010437012, 13.432523727416992, 14.701224327087402, 14.390131950378418, 20.754722595214844, 23.930192947387695, 24.82101821899414, 23.2471923828125, 16.2166748046875, 15.633496284484863, 13.430355072021484, 11.82071590423584, 11.436760902404785, 9.276786804199219, 9.31650161743164, 8.556788444519043, 7.594658851623535, 8.436553001403809, 9.816822052001953, 9.853339195251465, 11.87073802947998, 12.51904010772705, 14.666692733764648, 17.830902099609375, 24.481689453125, 26.432226181030273, 24.109989166259766, 17.1800594329834, 14.377769470214844, 12.212200164794922, 10.967619895935059, 10.121705055236816, 9.109648704528809, 8.166550636291504, 7.561773300170898, 7.073575973510742, 6.609354019165039, 6.891024589538574, 5.786100387573242, 5.787997722625732, 6.950540065765381, 6.740077018737793, 7.3592305183410645, 8.051239967346191, 8.956376075744629, 10.082350730895996, 11.581804275512695, 13.963129043579102, 20.408432006835938, 27.32776641845703, 26.256542205810547, 15.449851989746094, 12.521167755126953, 10.454995155334473, 9.057662963867188, 8.047090530395508, 7.676164150238037, 7.133976459503174, 6.480343818664551, 5.611476421356201, 4.659528732299805, 4.80872106552124, 6.6143975257873535], [11.957717895507812, 13.076170921325684, 13.540555953979492, 12.3357515335083, 19.54880142211914, 21.13422966003418, 22.153228759765625, 22.045536041259766, 19.850162506103516, 15.962414741516113, 12.538640975952148, 12.135064125061035, 11.775374412536621, 10.733291625976562, 10.073046684265137, 10.343765258789062, 10.145851135253906, 10.090106010437012, 13.432523727416992, 14.701224327087402, 14.390131950378418, 20.754722595214844, 23.930192947387695, 24.82101821899414, 23.2471923828125, 16.2166748046875, 15.633496284484863, 13.430355072021484, 11.82071590423584, 11.436760902404785, 9.276786804199219, 9.31650161743164, 8.556788444519043, 7.594658851623535, 8.436553001403809, 9.816822052001953, 9.853339195251465, 11.87073802947998, 12.51904010772705, 14.666692733764648, 17.830902099609375, 24.481689453125, 26.432226181030273, 24.109989166259766, 17.1800594329834, 14.377769470214844, 12.212200164794922, 10.967619895935059, 10.121705055236816, 9.109648704528809, 8.166550636291504, 7.561773300170898, 7.073575973510742, 6.609354019165039, 6.891024589538574, 5.786100387573242, 5.787997722625732, 6.950540065765381, 6.740077018737793, 7.3592305183410645, 8.051239967346191, 8.956376075744629, 10.082350730895996, 11.581804275512695, 13.963129043579102, 20.408432006835938, 27.32776641845703, 26.256542205810547, 15.449851989746094, 12.521167755126953, 10.454995155334473, 9.057662963867188, 8.047090530395508, 7.676164150238037, 7.133976459503174, 6.480343818664551, 5.611476421356201, 4.659528732299805, 4.80872106552124, 6.6143975257873535], [11.957717895507812, 13.076170921325684, 13.540555953979492, 12.3357515335083, 19.54880142211914, 21.13422966003418, 22.153228759765625, 22.045536041259766, 19.850162506103516, 15.962414741516113, 12.538640975952148, 12.135064125061035, 11.775374412536621, 10.733291625976562, 10.073046684265137, 10.343765258789062, 10.145851135253906, 10.090106010437012, 13.432523727416992, 14.701224327087402, 14.390131950378418, 20.754722595214844, 23.930192947387695, 24.82101821899414, 23.2471923828125, 16.2166748046875, 15.633496284484863, 13.430355072021484, 11.82071590423584, 11.436760902404785, 9.276786804199219, 9.31650161743164, 8.556788444519043, 7.594658851623535, 8.436553001403809, 9.816822052001953, 9.853339195251465, 11.87073802947998, 12.51904010772705, 14.666692733764648, 17.830902099609375, 24.481689453125, 26.432226181030273, 24.109989166259766, 17.1800594329834, 14.377769470214844, 12.212200164794922, 10.967619895935059, 10.121705055236816, 9.109648704528809, 8.166550636291504, 7.561773300170898, 7.073575973510742, 6.609354019165039, 6.891024589538574, 5.786100387573242, 5.787997722625732, 6.950540065765381, 6.740077018737793, 7.3592305183410645, 8.051239967346191, 8.956376075744629, 10.082350730895996, 11.581804275512695, 13.963129043579102, 20.408432006835938, 27.32776641845703, 26.256542205810547, 15.449851989746094, 12.521167755126953, 10.454995155334473, 9.057662963867188, 8.047090530395508, 7.676164150238037, 7.133976459503174, 6.480343818664551, 5.611476421356201, 4.659528732299805, 4.80872106552124, 6.6143975257873535], [11.957717895507812, 13.076170921325684, 13.540555953979492, 12.3357515335083, 19.54880142211914, 21.13422966003418, 22.153228759765625, 22.045536041259766, 19.850162506103516, 15.962414741516113, 12.538640975952148, 12.135064125061035, 11.775374412536621, 10.733291625976562, 10.073046684265137, 10.343765258789062, 10.145851135253906, 10.090106010437012, 13.432523727416992, 14.701224327087402, 14.390131950378418, 20.754722595214844, 23.930192947387695, 24.82101821899414, 23.2471923828125, 16.2166748046875, 15.633496284484863, 13.430355072021484, 11.82071590423584, 11.436760902404785, 9.276786804199219, 9.31650161743164, 8.556788444519043, 7.594658851623535, 8.436553001403809, 9.816822052001953, 9.853339195251465, 11.87073802947998, 12.51904010772705, 14.666692733764648, 17.830902099609375, 24.481689453125, 26.432226181030273, 24.109989166259766, 17.1800594329834, 14.377769470214844, 12.212200164794922, 10.967619895935059, 10.121705055236816, 9.109648704528809, 8.166550636291504, 7.561773300170898, 7.073575973510742, 6.609354019165039, 6.891024589538574, 5.786100387573242, 5.787997722625732, 6.950540065765381, 6.740077018737793, 7.3592305183410645, 8.051239967346191, 8.956376075744629, 10.082350730895996, 11.581804275512695, 13.963129043579102, 20.408432006835938, 27.32776641845703, 26.256542205810547, 15.449851989746094, 12.521167755126953, 10.454995155334473, 9.057662963867188, 8.047090530395508, 7.676164150238037, 7.133976459503174, 6.480343818664551, 5.611476421356201, 4.659528732299805, 4.80872106552124, 6.6143975257873535], [11.957717895507812, 13.076170921325684, 13.540555953979492, 12.3357515335083, 19.54880142211914, 21.13422966003418, 22.153228759765625, 22.045536041259766, 19.850162506103516, 15.962414741516113, 12.538640975952148, 12.135064125061035, 11.775374412536621, 10.733291625976562, 10.073046684265137, 10.343765258789062, 10.145851135253906, 10.090106010437012, 13.432523727416992, 14.701224327087402, 14.390131950378418, 20.754722595214844, 23.930192947387695, 24.82101821899414, 23.2471923828125, 16.2166748046875, 15.633496284484863, 13.430355072021484, 11.82071590423584, 11.436760902404785, 9.276786804199219, 9.31650161743164, 8.556788444519043, 7.594658851623535, 8.436553001403809, 9.816822052001953, 9.853339195251465, 11.87073802947998, 12.51904010772705, 14.666692733764648, 17.830902099609375, 24.481689453125, 26.432226181030273, 24.109989166259766, 17.1800594329834, 14.377769470214844, 12.212200164794922, 10.967619895935059, 10.121705055236816, 9.109648704528809, 8.166550636291504, 7.561773300170898, 7.073575973510742, 6.609354019165039, 6.891024589538574, 5.786100387573242, 5.787997722625732, 6.950540065765381, 6.740077018737793, 7.3592305183410645, 8.051239967346191, 8.956376075744629, 10.082350730895996, 11.581804275512695, 13.963129043579102, 20.408432006835938, 27.32776641845703, 26.256542205810547, 15.449851989746094, 12.521167755126953, 10.454995155334473, 9.057662963867188, 8.047090530395508, 7.676164150238037, 7.133976459503174, 6.480343818664551, 5.611476421356201, 4.659528732299805, 4.80872106552124, 6.6143975257873535], [11.957717895507812, 13.076170921325684, 13.540555953979492, 12.3357515335083, 19.54880142211914, 21.13422966003418, 22.153228759765625, 22.045536041259766, 19.850162506103516, 15.962414741516113, 12.538640975952148, 12.135064125061035, 11.775374412536621, 10.733291625976562, 10.073046684265137, 10.343765258789062, 10.145851135253906, 10.090106010437012, 13.432523727416992, 14.701224327087402, 14.390131950378418, 20.754722595214844, 23.930192947387695, 24.82101821899414, 23.2471923828125, 16.2166748046875, 15.633496284484863, 13.430355072021484, 11.82071590423584, 11.436760902404785, 9.276786804199219, 9.31650161743164, 8.556788444519043, 7.594658851623535, 8.436553001403809, 9.816822052001953, 9.853339195251465, 11.87073802947998, 12.51904010772705, 14.666692733764648, 17.830902099609375, 24.481689453125, 26.432226181030273, 24.109989166259766, 17.1800594329834, 14.377769470214844, 12.212200164794922, 10.967619895935059, 10.121705055236816, 9.109648704528809, 8.166550636291504, 7.561773300170898, 7.073575973510742, 6.609354019165039, 6.891024589538574, 5.786100387573242, 5.787997722625732, 6.950540065765381, 6.740077018737793, 7.3592305183410645, 8.051239967346191, 8.956376075744629, 10.082350730895996, 11.581804275512695, 13.963129043579102, 20.408432006835938, 27.32776641845703, 26.256542205810547, 15.449851989746094, 12.521167755126953, 10.454995155334473, 9.057662963867188, 8.047090530395508, 7.676164150238037, 7.133976459503174, 6.480343818664551, 5.611476421356201, 4.659528732299805, 4.80872106552124, 6.6143975257873535], [11.957717895507812, 13.076170921325684, 13.540555953979492, 12.3357515335083, 19.54880142211914, 21.13422966003418, 22.153228759765625, 22.045536041259766, 19.850162506103516, 15.962414741516113, 12.538640975952148, 12.135064125061035, 11.775374412536621, 10.733291625976562, 10.073046684265137, 10.343765258789062, 10.145851135253906, 10.090106010437012, 13.432523727416992, 14.701224327087402, 14.390131950378418, 20.754722595214844, 23.930192947387695, 24.82101821899414, 23.2471923828125, 16.2166748046875, 15.633496284484863, 13.430355072021484, 11.82071590423584, 11.436760902404785, 9.276786804199219, 9.31650161743164, 8.556788444519043, 7.594658851623535, 8.436553001403809, 9.816822052001953, 9.853339195251465, 11.87073802947998, 12.51904010772705, 14.666692733764648, 17.830902099609375, 24.481689453125, 26.432226181030273, 24.109989166259766, 17.1800594329834, 14.377769470214844, 12.212200164794922, 10.967619895935059, 10.121705055236816, 9.109648704528809, 8.166550636291504, 7.561773300170898, 7.073575973510742, 6.609354019165039, 6.891024589538574, 5.786100387573242, 5.787997722625732, 6.950540065765381, 6.740077018737793, 7.3592305183410645, 8.051239967346191, 8.956376075744629, 10.082350730895996, 11.581804275512695, 13.963129043579102, 20.408432006835938, 27.32776641845703, 26.256542205810547, 15.449851989746094, 12.521167755126953, 10.454995155334473, 9.057662963867188, 8.047090530395508, 7.676164150238037, 7.133976459503174, 6.480343818664551, 5.611476421356201, 4.659528732299805, 4.80872106552124, 6.6143975257873535], [11.957717895507812, 13.076170921325684, 13.540555953979492, 12.3357515335083, 19.54880142211914, 21.13422966003418, 22.153228759765625, 22.045536041259766, 19.850162506103516, 15.962414741516113, 12.538640975952148, 12.135064125061035, 11.775374412536621, 10.733291625976562, 10.073046684265137, 10.343765258789062, 10.145851135253906, 10.090106010437012, 13.432523727416992, 14.701224327087402, 14.390131950378418, 20.754722595214844, 23.930192947387695, 24.82101821899414, 23.2471923828125, 16.2166748046875, 15.633496284484863, 13.430355072021484, 11.82071590423584, 11.436760902404785, 9.276786804199219, 9.31650161743164, 8.556788444519043, 7.594658851623535, 8.436553001403809, 9.816822052001953, 9.853339195251465, 11.87073802947998, 12.51904010772705, 14.666692733764648, 17.830902099609375, 24.481689453125, 26.432226181030273, 24.109989166259766, 17.1800594329834, 14.377769470214844, 12.212200164794922, 10.967619895935059, 10.121705055236816, 9.109648704528809, 8.166550636291504, 7.561773300170898, 7.073575973510742, 6.609354019165039, 6.891024589538574, 5.786100387573242, 5.787997722625732, 6.950540065765381, 6.740077018737793, 7.3592305183410645, 8.051239967346191, 8.956376075744629, 10.082350730895996, 11.581804275512695, 13.963129043579102, 20.408432006835938, 27.32776641845703, 26.256542205810547, 15.449851989746094, 12.521167755126953, 10.454995155334473, 9.057662963867188, 8.047090530395508, 7.676164150238037, 7.133976459503174, 6.480343818664551, 5.611476421356201, 4.659528732299805, 4.80872106552124, 6.6143975257873535], [11.957717895507812, 13.076170921325684, 13.540555953979492, 12.3357515335083, 19.54880142211914, 21.13422966003418, 22.153228759765625, 22.045536041259766, 19.850162506103516, 15.962414741516113, 12.538640975952148, 12.135064125061035, 11.775374412536621, 10.733291625976562, 10.073046684265137, 10.343765258789062, 10.145851135253906, 10.090106010437012, 13.432523727416992, 14.701224327087402, 14.390131950378418, 20.754722595214844, 23.930192947387695, 24.82101821899414, 23.2471923828125, 16.2166748046875, 15.633496284484863, 13.430355072021484, 11.82071590423584, 11.436760902404785, 9.276786804199219, 9.31650161743164, 8.556788444519043, 7.594658851623535, 8.436553001403809, 9.816822052001953, 9.853339195251465, 11.87073802947998, 12.51904010772705, 14.666692733764648, 17.830902099609375, 24.481689453125, 26.432226181030273, 24.109989166259766, 17.1800594329834, 14.377769470214844, 12.212200164794922, 10.967619895935059, 10.121705055236816, 9.109648704528809, 8.166550636291504, 7.561773300170898, 7.073575973510742, 6.609354019165039, 6.891024589538574, 5.786100387573242, 5.787997722625732, 6.950540065765381, 6.740077018737793, 7.3592305183410645, 8.051239967346191, 8.956376075744629, 10.082350730895996, 11.581804275512695, 13.963129043579102, 20.408432006835938, 27.32776641845703, 26.256542205810547, 15.449851989746094, 12.521167755126953, 10.454995155334473, 9.057662963867188, 8.047090530395508, 7.676164150238037, 7.133976459503174, 6.480343818664551, 5.611476421356201, 4.659528732299805, 4.80872106552124, 6.6143975257873535], [11.957717895507812, 13.076170921325684, 13.540555953979492, 12.3357515335083, 19.54880142211914, 21.13422966003418, 22.153228759765625, 22.045536041259766, 19.850162506103516, 15.962414741516113, 12.538640975952148, 12.135064125061035, 11.775374412536621, 10.733291625976562, 10.073046684265137, 10.343765258789062, 10.145851135253906, 10.090106010437012, 13.432523727416992, 14.701224327087402, 14.390131950378418, 20.754722595214844, 23.930192947387695, 24.82101821899414, 23.2471923828125, 16.2166748046875, 15.633496284484863, 13.430355072021484, 11.82071590423584, 11.436760902404785, 9.276786804199219, 9.31650161743164, 8.556788444519043, 7.594658851623535, 8.436553001403809, 9.816822052001953, 9.853339195251465, 11.87073802947998, 12.51904010772705, 14.666692733764648, 17.830902099609375, 24.481689453125, 26.432226181030273, 24.109989166259766, 17.1800594329834, 14.377769470214844, 12.212200164794922, 10.967619895935059, 10.121705055236816, 9.109648704528809, 8.166550636291504, 7.561773300170898, 7.073575973510742, 6.609354019165039, 6.891024589538574, 5.786100387573242, 5.787997722625732, 6.950540065765381, 6.740077018737793, 7.3592305183410645, 8.051239967346191, 8.956376075744629, 10.082350730895996, 11.581804275512695, 13.963129043579102, 20.408432006835938, 27.32776641845703, 26.256542205810547, 15.449851989746094, 12.521167755126953, 10.454995155334473, 9.057662963867188, 8.047090530395508, 7.676164150238037, 7.133976459503174, 6.480343818664551, 5.611476421356201, 4.659528732299805, 4.80872106552124, 6.6143975257873535], [11.957717895507812, 13.076170921325684, 13.540555953979492, 12.3357515335083, 19.54880142211914, 21.13422966003418, 22.153228759765625, 22.045536041259766, 19.850162506103516, 15.962414741516113, 12.538640975952148, 12.135064125061035, 11.775374412536621, 10.733291625976562, 10.073046684265137, 10.343765258789062, 10.145851135253906, 10.090106010437012, 13.432523727416992, 14.701224327087402, 14.390131950378418, 20.754722595214844, 23.930192947387695, 24.82101821899414, 23.2471923828125, 16.2166748046875, 15.633496284484863, 13.430355072021484, 11.82071590423584, 11.436760902404785, 9.276786804199219, 9.31650161743164, 8.556788444519043, 7.594658851623535, 8.436553001403809, 9.816822052001953, 9.853339195251465, 11.87073802947998, 12.51904010772705, 14.666692733764648, 17.830902099609375, 24.481689453125, 26.432226181030273, 24.109989166259766, 17.1800594329834, 14.377769470214844, 12.212200164794922, 10.967619895935059, 10.121705055236816, 9.109648704528809, 8.166550636291504, 7.561773300170898, 7.073575973510742, 6.609354019165039, 6.891024589538574, 5.786100387573242, 5.787997722625732, 6.950540065765381, 6.740077018737793, 7.3592305183410645, 8.051239967346191, 8.956376075744629, 10.082350730895996, 11.581804275512695, 13.963129043579102, 20.408432006835938, 27.32776641845703, 26.256542205810547, 15.449851989746094, 12.521167755126953, 10.454995155334473, 9.057662963867188, 8.047090530395508, 7.676164150238037, 7.133976459503174, 6.480343818664551, 5.611476421356201, 4.659528732299805, 4.80872106552124, 6.6143975257873535], [11.957717895507812, 13.076170921325684, 13.540555953979492, 12.3357515335083, 19.54880142211914, 21.13422966003418, 22.153228759765625, 22.045536041259766, 19.850162506103516, 15.962414741516113, 12.538640975952148, 12.135064125061035, 11.775374412536621, 10.733291625976562, 10.073046684265137, 10.343765258789062, 10.145851135253906, 10.090106010437012, 13.432523727416992, 14.701224327087402, 14.390131950378418, 20.754722595214844, 23.930192947387695, 24.82101821899414, 23.2471923828125, 16.2166748046875, 15.633496284484863, 13.430355072021484, 11.82071590423584, 11.436760902404785, 9.276786804199219, 9.31650161743164, 8.556788444519043, 7.594658851623535, 8.436553001403809, 9.816822052001953, 9.853339195251465, 11.87073802947998, 12.51904010772705, 14.666692733764648, 17.830902099609375, 24.481689453125, 26.432226181030273, 24.109989166259766, 17.1800594329834, 14.377769470214844, 12.212200164794922, 10.967619895935059, 10.121705055236816, 9.109648704528809, 8.166550636291504, 7.561773300170898, 7.073575973510742, 6.609354019165039, 6.891024589538574, 5.786100387573242, 5.787997722625732, 6.950540065765381, 6.740077018737793, 7.3592305183410645, 8.051239967346191, 8.956376075744629, 10.082350730895996, 11.581804275512695, 13.963129043579102, 20.408432006835938, 27.32776641845703, 26.256542205810547, 15.449851989746094, 12.521167755126953, 10.454995155334473, 9.057662963867188, 8.047090530395508, 7.676164150238037, 7.133976459503174, 6.480343818664551, 5.611476421356201, 4.659528732299805, 4.80872106552124, 6.6143975257873535], [11.957717895507812, 13.076170921325684, 13.540555953979492, 12.3357515335083, 19.54880142211914, 21.13422966003418, 22.153228759765625, 22.045536041259766, 19.850162506103516, 15.962414741516113, 12.538640975952148, 12.135064125061035, 11.775374412536621, 10.733291625976562, 10.073046684265137, 10.343765258789062, 10.145851135253906, 10.090106010437012, 13.432523727416992, 14.701224327087402, 14.390131950378418, 20.754722595214844, 23.930192947387695, 24.82101821899414, 23.2471923828125, 16.2166748046875, 15.633496284484863, 13.430355072021484, 11.82071590423584, 11.436760902404785, 9.276786804199219, 9.31650161743164, 8.556788444519043, 7.594658851623535, 8.436553001403809, 9.816822052001953, 9.853339195251465, 11.87073802947998, 12.51904010772705, 14.666692733764648, 17.830902099609375, 24.481689453125, 26.432226181030273, 24.109989166259766, 17.1800594329834, 14.377769470214844, 12.212200164794922, 10.967619895935059, 10.121705055236816, 9.109648704528809, 8.166550636291504, 7.561773300170898, 7.073575973510742, 6.609354019165039, 6.891024589538574, 5.786100387573242, 5.787997722625732, 6.950540065765381, 6.740077018737793, 7.3592305183410645, 8.051239967346191, 8.956376075744629, 10.082350730895996, 11.581804275512695, 13.963129043579102, 20.408432006835938, 27.32776641845703, 26.256542205810547, 15.449851989746094, 12.521167755126953, 10.454995155334473, 9.057662963867188, 8.047090530395508, 7.676164150238037, 7.133976459503174, 6.480343818664551, 5.611476421356201, 4.659528732299805, 4.80872106552124, 6.6143975257873535], [11.957717895507812, 13.076170921325684, 13.540555953979492, 12.3357515335083, 19.54880142211914, 21.13422966003418, 22.153228759765625, 22.045536041259766, 19.850162506103516, 15.962414741516113, 12.538640975952148, 12.135064125061035, 11.775374412536621, 10.733291625976562, 10.073046684265137, 10.343765258789062, 10.145851135253906, 10.090106010437012, 13.432523727416992, 14.701224327087402, 14.390131950378418, 20.754722595214844, 23.930192947387695, 24.82101821899414, 23.2471923828125, 16.2166748046875, 15.633496284484863, 13.430355072021484, 11.82071590423584, 11.436760902404785, 9.276786804199219, 9.31650161743164, 8.556788444519043, 7.594658851623535, 8.436553001403809, 9.816822052001953, 9.853339195251465, 11.87073802947998, 12.51904010772705, 14.666692733764648, 17.830902099609375, 24.481689453125, 26.432226181030273, 24.109989166259766, 17.1800594329834, 14.377769470214844, 12.212200164794922, 10.967619895935059, 10.121705055236816, 9.109648704528809, 8.166550636291504, 7.561773300170898, 7.073575973510742, 6.609354019165039, 6.891024589538574, 5.786100387573242, 5.787997722625732, 6.950540065765381, 6.740077018737793, 7.3592305183410645, 8.051239967346191, 8.956376075744629, 10.082350730895996, 11.581804275512695, 13.963129043579102, 20.408432006835938, 27.32776641845703, 26.256542205810547, 15.449851989746094, 12.521167755126953, 10.454995155334473, 9.057662963867188, 8.047090530395508, 7.676164150238037, 7.133976459503174, 6.480343818664551, 5.611476421356201, 4.659528732299805, 4.80872106552124, 6.6143975257873535], [11.957717895507812, 13.076170921325684, 13.540555953979492, 12.3357515335083, 19.54880142211914, 21.13422966003418, 22.153228759765625, 22.045536041259766, 19.850162506103516, 15.962414741516113, 12.538640975952148, 12.135064125061035, 11.775374412536621, 10.733291625976562, 10.073046684265137, 10.343765258789062, 10.145851135253906, 10.090106010437012, 13.432523727416992, 14.701224327087402, 14.390131950378418, 20.754722595214844, 23.930192947387695, 24.82101821899414, 23.2471923828125, 16.2166748046875, 15.633496284484863, 13.430355072021484, 11.82071590423584, 11.436760902404785, 9.276786804199219, 9.31650161743164, 8.556788444519043, 7.594658851623535, 8.436553001403809, 9.816822052001953, 9.853339195251465, 11.87073802947998, 12.51904010772705, 14.666692733764648, 17.830902099609375, 24.481689453125, 26.432226181030273, 24.109989166259766, 17.1800594329834, 14.377769470214844, 12.212200164794922, 10.967619895935059, 10.121705055236816, 9.109648704528809, 8.166550636291504, 7.561773300170898, 7.073575973510742, 6.609354019165039, 6.891024589538574, 5.786100387573242, 5.787997722625732, 6.950540065765381, 6.740077018737793, 7.3592305183410645, 8.051239967346191, 8.956376075744629, 10.082350730895996, 11.581804275512695, 13.963129043579102, 20.408432006835938, 27.32776641845703, 26.256542205810547, 15.449851989746094, 12.521167755126953, 10.454995155334473, 9.057662963867188, 8.047090530395508, 7.676164150238037, 7.133976459503174, 6.480343818664551, 5.611476421356201, 4.659528732299805, 4.80872106552124, 6.6143975257873535], [11.957717895507812, 13.076170921325684, 13.540555953979492, 12.3357515335083, 19.54880142211914, 21.13422966003418, 22.153228759765625, 22.045536041259766, 19.850162506103516, 15.962414741516113, 12.538640975952148, 12.135064125061035, 11.775374412536621, 10.733291625976562, 10.073046684265137, 10.343765258789062, 10.145851135253906, 10.090106010437012, 13.432523727416992, 14.701224327087402, 14.390131950378418, 20.754722595214844, 23.930192947387695, 24.82101821899414, 23.2471923828125, 16.2166748046875, 15.633496284484863, 13.430355072021484, 11.82071590423584, 11.436760902404785, 9.276786804199219, 9.31650161743164, 8.556788444519043, 7.594658851623535, 8.436553001403809, 9.816822052001953, 9.853339195251465, 11.87073802947998, 12.51904010772705, 14.666692733764648, 17.830902099609375, 24.481689453125, 26.432226181030273, 24.109989166259766, 17.1800594329834, 14.377769470214844, 12.212200164794922, 10.967619895935059, 10.121705055236816, 9.109648704528809, 8.166550636291504, 7.561773300170898, 7.073575973510742, 6.609354019165039, 6.891024589538574, 5.786100387573242, 5.787997722625732, 6.950540065765381, 6.740077018737793, 7.3592305183410645, 8.051239967346191, 8.956376075744629, 10.082350730895996, 11.581804275512695, 13.963129043579102, 20.408432006835938, 27.32776641845703, 26.256542205810547, 15.449851989746094, 12.521167755126953, 10.454995155334473, 9.057662963867188, 8.047090530395508, 7.676164150238037, 7.133976459503174, 6.480343818664551, 5.611476421356201, 4.659528732299805, 4.80872106552124, 6.6143975257873535], [11.957717895507812, 13.076170921325684, 13.540555953979492, 12.3357515335083, 19.54880142211914, 21.13422966003418, 22.153228759765625, 22.045536041259766, 19.850162506103516, 15.962414741516113, 12.538640975952148, 12.135064125061035, 11.775374412536621, 10.733291625976562, 10.073046684265137, 10.343765258789062, 10.145851135253906, 10.090106010437012, 13.432523727416992, 14.701224327087402, 14.390131950378418, 20.754722595214844, 23.930192947387695, 24.82101821899414, 23.2471923828125, 16.2166748046875, 15.633496284484863, 13.430355072021484, 11.82071590423584, 11.436760902404785, 9.276786804199219, 9.31650161743164, 8.556788444519043, 7.594658851623535, 8.436553001403809, 9.816822052001953, 9.853339195251465, 11.87073802947998, 12.51904010772705, 14.666692733764648, 17.830902099609375, 24.481689453125, 26.432226181030273, 24.109989166259766, 17.1800594329834, 14.377769470214844, 12.212200164794922, 10.967619895935059, 10.121705055236816, 9.109648704528809, 8.166550636291504, 7.561773300170898, 7.073575973510742, 6.609354019165039, 6.891024589538574, 5.786100387573242, 5.787997722625732, 6.950540065765381, 6.740077018737793, 7.3592305183410645, 8.051239967346191, 8.956376075744629, 10.082350730895996, 11.581804275512695, 13.963129043579102, 20.408432006835938, 27.32776641845703, 26.256542205810547, 15.449851989746094, 12.521167755126953, 10.454995155334473, 9.057662963867188, 8.047090530395508, 7.676164150238037, 7.133976459503174, 6.480343818664551, 5.611476421356201, 4.659528732299805, 4.80872106552124, 6.6143975257873535], [11.957717895507812, 13.076170921325684, 13.540555953979492, 12.3357515335083, 19.54880142211914, 21.13422966003418, 22.153228759765625, 22.045536041259766, 19.850162506103516, 15.962414741516113, 12.538640975952148, 12.135064125061035, 11.775374412536621, 10.733291625976562, 10.073046684265137, 10.343765258789062, 10.145851135253906, 10.090106010437012, 13.432523727416992, 14.701224327087402, 14.390131950378418, 20.754722595214844, 23.930192947387695, 24.82101821899414, 23.2471923828125, 16.2166748046875, 15.633496284484863, 13.430355072021484, 11.82071590423584, 11.436760902404785, 9.276786804199219, 9.31650161743164, 8.556788444519043, 7.594658851623535, 8.436553001403809, 9.816822052001953, 9.853339195251465, 11.87073802947998, 12.51904010772705, 14.666692733764648, 17.830902099609375, 24.481689453125, 26.432226181030273, 24.109989166259766, 17.1800594329834, 14.377769470214844, 12.212200164794922, 10.967619895935059, 10.121705055236816, 9.109648704528809, 8.166550636291504, 7.561773300170898, 7.073575973510742, 6.609354019165039, 6.891024589538574, 5.786100387573242, 5.787997722625732, 6.950540065765381, 6.740077018737793, 7.3592305183410645, 8.051239967346191, 8.956376075744629, 10.082350730895996, 11.581804275512695, 13.963129043579102, 20.408432006835938, 27.32776641845703, 26.256542205810547, 15.449851989746094, 12.521167755126953, 10.454995155334473, 9.057662963867188, 8.047090530395508, 7.676164150238037, 7.133976459503174, 6.480343818664551, 5.611476421356201, 4.659528732299805, 4.80872106552124, 6.6143975257873535], [11.957717895507812, 13.076170921325684, 13.540555953979492, 12.3357515335083, 19.54880142211914, 21.13422966003418, 22.153228759765625, 22.045536041259766, 19.850162506103516, 15.962414741516113, 12.538640975952148, 12.135064125061035, 11.775374412536621, 10.733291625976562, 10.073046684265137, 10.343765258789062, 10.145851135253906, 10.090106010437012, 13.432523727416992, 14.701224327087402, 14.390131950378418, 20.754722595214844, 23.930192947387695, 24.82101821899414, 23.2471923828125, 16.2166748046875, 15.633496284484863, 13.430355072021484, 11.82071590423584, 11.436760902404785, 9.276786804199219, 9.31650161743164, 8.556788444519043, 7.594658851623535, 8.436553001403809, 9.816822052001953, 9.853339195251465, 11.87073802947998, 12.51904010772705, 14.666692733764648, 17.830902099609375, 24.481689453125, 26.432226181030273, 24.109989166259766, 17.1800594329834, 14.377769470214844, 12.212200164794922, 10.967619895935059, 10.121705055236816, 9.109648704528809, 8.166550636291504, 7.561773300170898, 7.073575973510742, 6.609354019165039, 6.891024589538574, 5.786100387573242, 5.787997722625732, 6.950540065765381, 6.740077018737793, 7.3592305183410645, 8.051239967346191, 8.956376075744629, 10.082350730895996, 11.581804275512695, 13.963129043579102, 20.408432006835938, 27.32776641845703, 26.256542205810547, 15.449851989746094, 12.521167755126953, 10.454995155334473, 9.057662963867188, 8.047090530395508, 7.676164150238037, 7.133976459503174, 6.480343818664551, 5.611476421356201, 4.659528732299805, 4.80872106552124, 6.6143975257873535], [11.957717895507812, 13.076170921325684, 13.540555953979492, 12.3357515335083, 19.54880142211914, 21.13422966003418, 22.153228759765625, 22.045536041259766, 19.850162506103516, 15.962414741516113, 12.538640975952148, 12.135064125061035, 11.775374412536621, 10.733291625976562, 10.073046684265137, 10.343765258789062, 10.145851135253906, 10.090106010437012, 13.432523727416992, 14.701224327087402, 14.390131950378418, 20.754722595214844, 23.930192947387695, 24.82101821899414, 23.2471923828125, 16.2166748046875, 15.633496284484863, 13.430355072021484, 11.82071590423584, 11.436760902404785, 9.276786804199219, 9.31650161743164, 8.556788444519043, 7.594658851623535, 8.436553001403809, 9.816822052001953, 9.853339195251465, 11.87073802947998, 12.51904010772705, 14.666692733764648, 17.830902099609375, 24.481689453125, 26.432226181030273, 24.109989166259766, 17.1800594329834, 14.377769470214844, 12.212200164794922, 10.967619895935059, 10.121705055236816, 9.109648704528809, 8.166550636291504, 7.561773300170898, 7.073575973510742, 6.609354019165039, 6.891024589538574, 5.786100387573242, 5.787997722625732, 6.950540065765381, 6.740077018737793, 7.3592305183410645, 8.051239967346191, 8.956376075744629, 10.082350730895996, 11.581804275512695, 13.963129043579102, 20.408432006835938, 27.32776641845703, 26.256542205810547, 15.449851989746094, 12.521167755126953, 10.454995155334473, 9.057662963867188, 8.047090530395508, 7.676164150238037, 7.133976459503174, 6.480343818664551, 5.611476421356201, 4.659528732299805, 4.80872106552124, 6.6143975257873535], [11.957717895507812, 13.076170921325684, 13.540555953979492, 12.3357515335083, 19.54880142211914, 21.13422966003418, 22.153228759765625, 22.045536041259766, 19.850162506103516, 15.962414741516113, 12.538640975952148, 12.135064125061035, 11.775374412536621, 10.733291625976562, 10.073046684265137, 10.343765258789062, 10.145851135253906, 10.090106010437012, 13.432523727416992, 14.701224327087402, 14.390131950378418, 20.754722595214844, 23.930192947387695, 24.82101821899414, 23.2471923828125, 16.2166748046875, 15.633496284484863, 13.430355072021484, 11.82071590423584, 11.436760902404785, 9.276786804199219, 9.31650161743164, 8.556788444519043, 7.594658851623535, 8.436553001403809, 9.816822052001953, 9.853339195251465, 11.87073802947998, 12.51904010772705, 14.666692733764648, 17.830902099609375, 24.481689453125, 26.432226181030273, 24.109989166259766, 17.1800594329834, 14.377769470214844, 12.212200164794922, 10.967619895935059, 10.121705055236816, 9.109648704528809, 8.166550636291504, 7.561773300170898, 7.073575973510742, 6.609354019165039, 6.891024589538574, 5.786100387573242, 5.787997722625732, 6.950540065765381, 6.740077018737793, 7.3592305183410645, 8.051239967346191, 8.956376075744629, 10.082350730895996, 11.581804275512695, 13.963129043579102, 20.408432006835938, 27.32776641845703, 26.256542205810547, 15.449851989746094, 12.521167755126953, 10.454995155334473, 9.057662963867188, 8.047090530395508, 7.676164150238037, 7.133976459503174, 6.480343818664551, 5.611476421356201, 4.659528732299805, 4.80872106552124, 6.6143975257873535], [11.957717895507812, 13.076170921325684, 13.540555953979492, 12.3357515335083, 19.54880142211914, 21.13422966003418, 22.153228759765625, 22.045536041259766, 19.850162506103516, 15.962414741516113, 12.538640975952148, 12.135064125061035, 11.775374412536621, 10.733291625976562, 10.073046684265137, 10.343765258789062, 10.145851135253906, 10.090106010437012, 13.432523727416992, 14.701224327087402, 14.390131950378418, 20.754722595214844, 23.930192947387695, 24.82101821899414, 23.2471923828125, 16.2166748046875, 15.633496284484863, 13.430355072021484, 11.82071590423584, 11.436760902404785, 9.276786804199219, 9.31650161743164, 8.556788444519043, 7.594658851623535, 8.436553001403809, 9.816822052001953, 9.853339195251465, 11.87073802947998, 12.51904010772705, 14.666692733764648, 17.830902099609375, 24.481689453125, 26.432226181030273, 24.109989166259766, 17.1800594329834, 14.377769470214844, 12.212200164794922, 10.967619895935059, 10.121705055236816, 9.109648704528809, 8.166550636291504, 7.561773300170898, 7.073575973510742, 6.609354019165039, 6.891024589538574, 5.786100387573242, 5.787997722625732, 6.950540065765381, 6.740077018737793, 7.3592305183410645, 8.051239967346191, 8.956376075744629, 10.082350730895996, 11.581804275512695, 13.963129043579102, 20.408432006835938, 27.32776641845703, 26.256542205810547, 15.449851989746094, 12.521167755126953, 10.454995155334473, 9.057662963867188, 8.047090530395508, 7.676164150238037, 7.133976459503174, 6.480343818664551, 5.611476421356201, 4.659528732299805, 4.80872106552124, 6.6143975257873535], [11.957717895507812, 13.076170921325684, 13.540555953979492, 12.3357515335083, 19.54880142211914, 21.13422966003418, 22.153228759765625, 22.045536041259766, 19.850162506103516, 15.962414741516113, 12.538640975952148, 12.135064125061035, 11.775374412536621, 10.733291625976562, 10.073046684265137, 10.343765258789062, 10.145851135253906, 10.090106010437012, 13.432523727416992, 14.701224327087402, 14.390131950378418, 20.754722595214844, 23.930192947387695, 24.82101821899414, 23.2471923828125, 16.2166748046875, 15.633496284484863, 13.430355072021484, 11.82071590423584, 11.436760902404785, 9.276786804199219, 9.31650161743164, 8.556788444519043, 7.594658851623535, 8.436553001403809, 9.816822052001953, 9.853339195251465, 11.87073802947998, 12.51904010772705, 14.666692733764648, 17.830902099609375, 24.481689453125, 26.432226181030273, 24.109989166259766, 17.1800594329834, 14.377769470214844, 12.212200164794922, 10.967619895935059, 10.121705055236816, 9.109648704528809, 8.166550636291504, 7.561773300170898, 7.073575973510742, 6.609354019165039, 6.891024589538574, 5.786100387573242, 5.787997722625732, 6.950540065765381, 6.740077018737793, 7.3592305183410645, 8.051239967346191, 8.956376075744629, 10.082350730895996, 11.581804275512695, 13.963129043579102, 20.408432006835938, 27.32776641845703, 26.256542205810547, 15.449851989746094, 12.521167755126953, 10.454995155334473, 9.057662963867188, 8.047090530395508, 7.676164150238037, 7.133976459503174, 6.480343818664551, 5.611476421356201, 4.659528732299805, 4.80872106552124, 6.6143975257873535], [11.957717895507812, 13.076170921325684, 13.540555953979492, 12.3357515335083, 19.54880142211914, 21.13422966003418, 22.153228759765625, 22.045536041259766, 19.850162506103516, 15.962414741516113, 12.538640975952148, 12.135064125061035, 11.775374412536621, 10.733291625976562, 10.073046684265137, 10.343765258789062, 10.145851135253906, 10.090106010437012, 13.432523727416992, 14.701224327087402, 14.390131950378418, 20.754722595214844, 23.930192947387695, 24.82101821899414, 23.2471923828125, 16.2166748046875, 15.633496284484863, 13.430355072021484, 11.82071590423584, 11.436760902404785, 9.276786804199219, 9.31650161743164, 8.556788444519043, 7.594658851623535, 8.436553001403809, 9.816822052001953, 9.853339195251465, 11.87073802947998, 12.51904010772705, 14.666692733764648, 17.830902099609375, 24.481689453125, 26.432226181030273, 24.109989166259766, 17.1800594329834, 14.377769470214844, 12.212200164794922, 10.967619895935059, 10.121705055236816, 9.109648704528809, 8.166550636291504, 7.561773300170898, 7.073575973510742, 6.609354019165039, 6.891024589538574, 5.786100387573242, 5.787997722625732, 6.950540065765381, 6.740077018737793, 7.3592305183410645, 8.051239967346191, 8.956376075744629, 10.082350730895996, 11.581804275512695, 13.963129043579102, 20.408432006835938, 27.32776641845703, 26.256542205810547, 15.449851989746094, 12.521167755126953, 10.454995155334473, 9.057662963867188, 8.047090530395508, 7.676164150238037, 7.133976459503174, 6.480343818664551, 5.611476421356201, 4.659528732299805, 4.80872106552124, 6.6143975257873535], [11.957717895507812, 13.076170921325684, 13.540555953979492, 12.3357515335083, 19.54880142211914, 21.13422966003418, 22.153228759765625, 22.045536041259766, 19.850162506103516, 15.962414741516113, 12.538640975952148, 12.135064125061035, 11.775374412536621, 10.733291625976562, 10.073046684265137, 10.343765258789062, 10.145851135253906, 10.090106010437012, 13.432523727416992, 14.701224327087402, 14.390131950378418, 20.754722595214844, 23.930192947387695, 24.82101821899414, 23.2471923828125, 16.2166748046875, 15.633496284484863, 13.430355072021484, 11.82071590423584, 11.436760902404785, 9.276786804199219, 9.31650161743164, 8.556788444519043, 7.594658851623535, 8.436553001403809, 9.816822052001953, 9.853339195251465, 11.87073802947998, 12.51904010772705, 14.666692733764648, 17.830902099609375, 24.481689453125, 26.432226181030273, 24.109989166259766, 17.1800594329834, 14.377769470214844, 12.212200164794922, 10.967619895935059, 10.121705055236816, 9.109648704528809, 8.166550636291504, 7.561773300170898, 7.073575973510742, 6.609354019165039, 6.891024589538574, 5.786100387573242, 5.787997722625732, 6.950540065765381, 6.740077018737793, 7.3592305183410645, 8.051239967346191, 8.956376075744629, 10.082350730895996, 11.581804275512695, 13.963129043579102, 20.408432006835938, 27.32776641845703, 26.256542205810547, 15.449851989746094, 12.521167755126953, 10.454995155334473, 9.057662963867188, 8.047090530395508, 7.676164150238037, 7.133976459503174, 6.480343818664551, 5.611476421356201, 4.659528732299805, 4.80872106552124, 6.6143975257873535], [11.957717895507812, 13.076170921325684, 13.540555953979492, 12.3357515335083, 19.54880142211914, 21.13422966003418, 22.153228759765625, 22.045536041259766, 19.850162506103516, 15.962414741516113, 12.538640975952148, 12.135064125061035, 11.775374412536621, 10.733291625976562, 10.073046684265137, 10.343765258789062, 10.145851135253906, 10.090106010437012, 13.432523727416992, 14.701224327087402, 14.390131950378418, 20.754722595214844, 23.930192947387695, 24.82101821899414, 23.2471923828125, 16.2166748046875, 15.633496284484863, 13.430355072021484, 11.82071590423584, 11.436760902404785, 9.276786804199219, 9.31650161743164, 8.556788444519043, 7.594658851623535, 8.436553001403809, 9.816822052001953, 9.853339195251465, 11.87073802947998, 12.51904010772705, 14.666692733764648, 17.830902099609375, 24.481689453125, 26.432226181030273, 24.109989166259766, 17.1800594329834, 14.377769470214844, 12.212200164794922, 10.967619895935059, 10.121705055236816, 9.109648704528809, 8.166550636291504, 7.561773300170898, 7.073575973510742, 6.609354019165039, 6.891024589538574, 5.786100387573242, 5.787997722625732, 6.950540065765381, 6.740077018737793, 7.3592305183410645, 8.051239967346191, 8.956376075744629, 10.082350730895996, 11.581804275512695, 13.963129043579102, 20.408432006835938, 27.32776641845703, 26.256542205810547, 15.449851989746094, 12.521167755126953, 10.454995155334473, 9.057662963867188, 8.047090530395508, 7.676164150238037, 7.133976459503174, 6.480343818664551, 5.611476421356201, 4.659528732299805, 4.80872106552124, 6.6143975257873535], [11.957717895507812, 13.076170921325684, 13.540555953979492, 12.3357515335083, 19.54880142211914, 21.13422966003418, 22.153228759765625, 22.045536041259766, 19.850162506103516, 15.962414741516113, 12.538640975952148, 12.135064125061035, 11.775374412536621, 10.733291625976562, 10.073046684265137, 10.343765258789062, 10.145851135253906, 10.090106010437012, 13.432523727416992, 14.701224327087402, 14.390131950378418, 20.754722595214844, 23.930192947387695, 24.82101821899414, 23.2471923828125, 16.2166748046875, 15.633496284484863, 13.430355072021484, 11.82071590423584, 11.436760902404785, 9.276786804199219, 9.31650161743164, 8.556788444519043, 7.594658851623535, 8.436553001403809, 9.816822052001953, 9.853339195251465, 11.87073802947998, 12.51904010772705, 14.666692733764648, 17.830902099609375, 24.481689453125, 26.432226181030273, 24.109989166259766, 17.1800594329834, 14.377769470214844, 12.212200164794922, 10.967619895935059, 10.121705055236816, 9.109648704528809, 8.166550636291504, 7.561773300170898, 7.073575973510742, 6.609354019165039, 6.891024589538574, 5.786100387573242, 5.787997722625732, 6.950540065765381, 6.740077018737793, 7.3592305183410645, 8.051239967346191, 8.956376075744629, 10.082350730895996, 11.581804275512695, 13.963129043579102, 20.408432006835938, 27.32776641845703, 26.256542205810547, 15.449851989746094, 12.521167755126953, 10.454995155334473, 9.057662963867188, 8.047090530395508, 7.676164150238037, 7.133976459503174, 6.480343818664551, 5.611476421356201, 4.659528732299805, 4.80872106552124, 6.6143975257873535], [11.957717895507812, 13.076170921325684, 13.540555953979492, 12.3357515335083, 19.54880142211914, 21.13422966003418, 22.153228759765625, 22.045536041259766, 19.850162506103516, 15.962414741516113, 12.538640975952148, 12.135064125061035, 11.775374412536621, 10.733291625976562, 10.073046684265137, 10.343765258789062, 10.145851135253906, 10.090106010437012, 13.432523727416992, 14.701224327087402, 14.390131950378418, 20.754722595214844, 23.930192947387695, 24.82101821899414, 23.2471923828125, 16.2166748046875, 15.633496284484863, 13.430355072021484, 11.82071590423584, 11.436760902404785, 9.276786804199219, 9.31650161743164, 8.556788444519043, 7.594658851623535, 8.436553001403809, 9.816822052001953, 9.853339195251465, 11.87073802947998, 12.51904010772705, 14.666692733764648, 17.830902099609375, 24.481689453125, 26.432226181030273, 24.109989166259766, 17.1800594329834, 14.377769470214844, 12.212200164794922, 10.967619895935059, 10.121705055236816, 9.109648704528809, 8.166550636291504, 7.561773300170898, 7.073575973510742, 6.609354019165039, 6.891024589538574, 5.786100387573242, 5.787997722625732, 6.950540065765381, 6.740077018737793, 7.3592305183410645, 8.051239967346191, 8.956376075744629, 10.082350730895996, 11.581804275512695, 13.963129043579102, 20.408432006835938, 27.32776641845703, 26.256542205810547, 15.449851989746094, 12.521167755126953, 10.454995155334473, 9.057662963867188, 8.047090530395508, 7.676164150238037, 7.133976459503174, 6.480343818664551, 5.611476421356201, 4.659528732299805, 4.80872106552124, 6.6143975257873535], [11.957717895507812, 13.076170921325684, 13.540555953979492, 12.3357515335083, 19.54880142211914, 21.13422966003418, 22.153228759765625, 22.045536041259766, 19.850162506103516, 15.962414741516113, 12.538640975952148, 12.135064125061035, 11.775374412536621, 10.733291625976562, 10.073046684265137, 10.343765258789062, 10.145851135253906, 10.090106010437012, 13.432523727416992, 14.701224327087402, 14.390131950378418, 20.754722595214844, 23.930192947387695, 24.82101821899414, 23.2471923828125, 16.2166748046875, 15.633496284484863, 13.430355072021484, 11.82071590423584, 11.436760902404785, 9.276786804199219, 9.31650161743164, 8.556788444519043, 7.594658851623535, 8.436553001403809, 9.816822052001953, 9.853339195251465, 11.87073802947998, 12.51904010772705, 14.666692733764648, 17.830902099609375, 24.481689453125, 26.432226181030273, 24.109989166259766, 17.1800594329834, 14.377769470214844, 12.212200164794922, 10.967619895935059, 10.121705055236816, 9.109648704528809, 8.166550636291504, 7.561773300170898, 7.073575973510742, 6.609354019165039, 6.891024589538574, 5.786100387573242, 5.787997722625732, 6.950540065765381, 6.740077018737793, 7.3592305183410645, 8.051239967346191, 8.956376075744629, 10.082350730895996, 11.581804275512695, 13.963129043579102, 20.408432006835938, 27.32776641845703, 26.256542205810547, 15.449851989746094, 12.521167755126953, 10.454995155334473, 9.057662963867188, 8.047090530395508, 7.676164150238037, 7.133976459503174, 6.480343818664551, 5.611476421356201, 4.659528732299805, 4.80872106552124, 6.6143975257873535], [11.957717895507812, 13.076170921325684, 13.540555953979492, 12.3357515335083, 19.54880142211914, 21.13422966003418, 22.153228759765625, 22.045536041259766, 19.850162506103516, 15.962414741516113, 12.538640975952148, 12.135064125061035, 11.775374412536621, 10.733291625976562, 10.073046684265137, 10.343765258789062, 10.145851135253906, 10.090106010437012, 13.432523727416992, 14.701224327087402, 14.390131950378418, 20.754722595214844, 23.930192947387695, 24.82101821899414, 23.2471923828125, 16.2166748046875, 15.633496284484863, 13.430355072021484, 11.82071590423584, 11.436760902404785, 9.276786804199219, 9.31650161743164, 8.556788444519043, 7.594658851623535, 8.436553001403809, 9.816822052001953, 9.853339195251465, 11.87073802947998, 12.51904010772705, 14.666692733764648, 17.830902099609375, 24.481689453125, 26.432226181030273, 24.109989166259766, 17.1800594329834, 14.377769470214844, 12.212200164794922, 10.967619895935059, 10.121705055236816, 9.109648704528809, 8.166550636291504, 7.561773300170898, 7.073575973510742, 6.609354019165039, 6.891024589538574, 5.786100387573242, 5.787997722625732, 6.950540065765381, 6.740077018737793, 7.3592305183410645, 8.051239967346191, 8.956376075744629, 10.082350730895996, 11.581804275512695, 13.963129043579102, 20.408432006835938, 27.32776641845703, 26.256542205810547, 15.449851989746094, 12.521167755126953, 10.454995155334473, 9.057662963867188, 8.047090530395508, 7.676164150238037, 7.133976459503174, 6.480343818664551, 5.611476421356201, 4.659528732299805, 4.80872106552124, 6.6143975257873535], [11.957717895507812, 13.076170921325684, 13.540555953979492, 12.3357515335083, 19.54880142211914, 21.13422966003418, 22.153228759765625, 22.045536041259766, 19.850162506103516, 15.962414741516113, 12.538640975952148, 12.135064125061035, 11.775374412536621, 10.733291625976562, 10.073046684265137, 10.343765258789062, 10.145851135253906, 10.090106010437012, 13.432523727416992, 14.701224327087402, 14.390131950378418, 20.754722595214844, 23.930192947387695, 24.82101821899414, 23.2471923828125, 16.2166748046875, 15.633496284484863, 13.430355072021484, 11.82071590423584, 11.436760902404785, 9.276786804199219, 9.31650161743164, 8.556788444519043, 7.594658851623535, 8.436553001403809, 9.816822052001953, 9.853339195251465, 11.87073802947998, 12.51904010772705, 14.666692733764648, 17.830902099609375, 24.481689453125, 26.432226181030273, 24.109989166259766, 17.1800594329834, 14.377769470214844, 12.212200164794922, 10.967619895935059, 10.121705055236816, 9.109648704528809, 8.166550636291504, 7.561773300170898, 7.073575973510742, 6.609354019165039, 6.891024589538574, 5.786100387573242, 5.787997722625732, 6.950540065765381, 6.740077018737793, 7.3592305183410645, 8.051239967346191, 8.956376075744629, 10.082350730895996, 11.581804275512695, 13.963129043579102, 20.408432006835938, 27.32776641845703, 26.256542205810547, 15.449851989746094, 12.521167755126953, 10.454995155334473, 9.057662963867188, 8.047090530395508, 7.676164150238037, 7.133976459503174, 6.480343818664551, 5.611476421356201, 4.659528732299805, 4.80872106552124, 6.6143975257873535], [11.957717895507812, 13.076170921325684, 13.540555953979492, 12.3357515335083, 19.54880142211914, 21.13422966003418, 22.153228759765625, 22.045536041259766, 19.850162506103516, 15.962414741516113, 12.538640975952148, 12.135064125061035, 11.775374412536621, 10.733291625976562, 10.073046684265137, 10.343765258789062, 10.145851135253906, 10.090106010437012, 13.432523727416992, 14.701224327087402, 14.390131950378418, 20.754722595214844, 23.930192947387695, 24.82101821899414, 23.2471923828125, 16.2166748046875, 15.633496284484863, 13.430355072021484, 11.82071590423584, 11.436760902404785, 9.276786804199219, 9.31650161743164, 8.556788444519043, 7.594658851623535, 8.436553001403809, 9.816822052001953, 9.853339195251465, 11.87073802947998, 12.51904010772705, 14.666692733764648, 17.830902099609375, 24.481689453125, 26.432226181030273, 24.109989166259766, 17.1800594329834, 14.377769470214844, 12.212200164794922, 10.967619895935059, 10.121705055236816, 9.109648704528809, 8.166550636291504, 7.561773300170898, 7.073575973510742, 6.609354019165039, 6.891024589538574, 5.786100387573242, 5.787997722625732, 6.950540065765381, 6.740077018737793, 7.3592305183410645, 8.051239967346191, 8.956376075744629, 10.082350730895996, 11.581804275512695, 13.963129043579102, 20.408432006835938, 27.32776641845703, 26.256542205810547, 15.449851989746094, 12.521167755126953, 10.454995155334473, 9.057662963867188, 8.047090530395508, 7.676164150238037, 7.133976459503174, 6.480343818664551, 5.611476421356201, 4.659528732299805, 4.80872106552124, 6.6143975257873535], [11.957717895507812, 13.076170921325684, 13.540555953979492, 12.3357515335083, 19.54880142211914, 21.13422966003418, 22.153228759765625, 22.045536041259766, 19.850162506103516, 15.962414741516113, 12.538640975952148, 12.135064125061035, 11.775374412536621, 10.733291625976562, 10.073046684265137, 10.343765258789062, 10.145851135253906, 10.090106010437012, 13.432523727416992, 14.701224327087402, 14.390131950378418, 20.754722595214844, 23.930192947387695, 24.82101821899414, 23.2471923828125, 16.2166748046875, 15.633496284484863, 13.430355072021484, 11.82071590423584, 11.436760902404785, 9.276786804199219, 9.31650161743164, 8.556788444519043, 7.594658851623535, 8.436553001403809, 9.816822052001953, 9.853339195251465, 11.87073802947998, 12.51904010772705, 14.666692733764648, 17.830902099609375, 24.481689453125, 26.432226181030273, 24.109989166259766, 17.1800594329834, 14.377769470214844, 12.212200164794922, 10.967619895935059, 10.121705055236816, 9.109648704528809, 8.166550636291504, 7.561773300170898, 7.073575973510742, 6.609354019165039, 6.891024589538574, 5.786100387573242, 5.787997722625732, 6.950540065765381, 6.740077018737793, 7.3592305183410645, 8.051239967346191, 8.956376075744629, 10.082350730895996, 11.581804275512695, 13.963129043579102, 20.408432006835938, 27.32776641845703, 26.256542205810547, 15.449851989746094, 12.521167755126953, 10.454995155334473, 9.057662963867188, 8.047090530395508, 7.676164150238037, 7.133976459503174, 6.480343818664551, 5.611476421356201, 4.659528732299805, 4.80872106552124, 6.6143975257873535], [11.957717895507812, 13.076170921325684, 13.540555953979492, 12.3357515335083, 19.54880142211914, 21.13422966003418, 22.153228759765625, 22.045536041259766, 19.850162506103516, 15.962414741516113, 12.538640975952148, 12.135064125061035, 11.775374412536621, 10.733291625976562, 10.073046684265137, 10.343765258789062, 10.145851135253906, 10.090106010437012, 13.432523727416992, 14.701224327087402, 14.390131950378418, 20.754722595214844, 23.930192947387695, 24.82101821899414, 23.2471923828125, 16.2166748046875, 15.633496284484863, 13.430355072021484, 11.82071590423584, 11.436760902404785, 9.276786804199219, 9.31650161743164, 8.556788444519043, 7.594658851623535, 8.436553001403809, 9.816822052001953, 9.853339195251465, 11.87073802947998, 12.51904010772705, 14.666692733764648, 17.830902099609375, 24.481689453125, 26.432226181030273, 24.109989166259766, 17.1800594329834, 14.377769470214844, 12.212200164794922, 10.967619895935059, 10.121705055236816, 9.109648704528809, 8.166550636291504, 7.561773300170898, 7.073575973510742, 6.609354019165039, 6.891024589538574, 5.786100387573242, 5.787997722625732, 6.950540065765381, 6.740077018737793, 7.3592305183410645, 8.051239967346191, 8.956376075744629, 10.082350730895996, 11.581804275512695, 13.963129043579102, 20.408432006835938, 27.32776641845703, 26.256542205810547, 15.449851989746094, 12.521167755126953, 10.454995155334473, 9.057662963867188, 8.047090530395508, 7.676164150238037, 7.133976459503174, 6.480343818664551, 5.611476421356201, 4.659528732299805, 4.80872106552124, 6.6143975257873535], [11.957717895507812, 13.076170921325684, 13.540555953979492, 12.3357515335083, 19.54880142211914, 21.13422966003418, 22.153228759765625, 22.045536041259766, 19.850162506103516, 15.962414741516113, 12.538640975952148, 12.135064125061035, 11.775374412536621, 10.733291625976562, 10.073046684265137, 10.343765258789062, 10.145851135253906, 10.090106010437012, 13.432523727416992, 14.701224327087402, 14.390131950378418, 20.754722595214844, 23.930192947387695, 24.82101821899414, 23.2471923828125, 16.2166748046875, 15.633496284484863, 13.430355072021484, 11.82071590423584, 11.436760902404785, 9.276786804199219, 9.31650161743164, 8.556788444519043, 7.594658851623535, 8.436553001403809, 9.816822052001953, 9.853339195251465, 11.87073802947998, 12.51904010772705, 14.666692733764648, 17.830902099609375, 24.481689453125, 26.432226181030273, 24.109989166259766, 17.1800594329834, 14.377769470214844, 12.212200164794922, 10.967619895935059, 10.121705055236816, 9.109648704528809, 8.166550636291504, 7.561773300170898, 7.073575973510742, 6.609354019165039, 6.891024589538574, 5.786100387573242, 5.787997722625732, 6.950540065765381, 6.740077018737793, 7.3592305183410645, 8.051239967346191, 8.956376075744629, 10.082350730895996, 11.581804275512695, 13.963129043579102, 20.408432006835938, 27.32776641845703, 26.256542205810547, 15.449851989746094, 12.521167755126953, 10.454995155334473, 9.057662963867188, 8.047090530395508, 7.676164150238037, 7.133976459503174, 6.480343818664551, 5.611476421356201, 4.659528732299805, 4.80872106552124, 6.6143975257873535], [11.957717895507812, 13.076170921325684, 13.540555953979492, 12.3357515335083, 19.54880142211914, 21.13422966003418, 22.153228759765625, 22.045536041259766, 19.850162506103516, 15.962414741516113, 12.538640975952148, 12.135064125061035, 11.775374412536621, 10.733291625976562, 10.073046684265137, 10.343765258789062, 10.145851135253906, 10.090106010437012, 13.432523727416992, 14.701224327087402, 14.390131950378418, 20.754722595214844, 23.930192947387695, 24.82101821899414, 23.2471923828125, 16.2166748046875, 15.633496284484863, 13.430355072021484, 11.82071590423584, 11.436760902404785, 9.276786804199219, 9.31650161743164, 8.556788444519043, 7.594658851623535, 8.436553001403809, 9.816822052001953, 9.853339195251465, 11.87073802947998, 12.51904010772705, 14.666692733764648, 17.830902099609375, 24.481689453125, 26.432226181030273, 24.109989166259766, 17.1800594329834, 14.377769470214844, 12.212200164794922, 10.967619895935059, 10.121705055236816, 9.109648704528809, 8.166550636291504, 7.561773300170898, 7.073575973510742, 6.609354019165039, 6.891024589538574, 5.786100387573242, 5.787997722625732, 6.950540065765381, 6.740077018737793, 7.3592305183410645, 8.051239967346191, 8.956376075744629, 10.082350730895996, 11.581804275512695, 13.963129043579102, 20.408432006835938, 27.32776641845703, 26.256542205810547, 15.449851989746094, 12.521167755126953, 10.454995155334473, 9.057662963867188, 8.047090530395508, 7.676164150238037, 7.133976459503174, 6.480343818664551, 5.611476421356201, 4.659528732299805, 4.80872106552124, 6.6143975257873535]]} \ No newline at end of file diff --git a/testdata/firered_reference/ref_probs.json b/testdata/firered_reference/ref_probs.json new file mode 100644 index 0000000..1eaaf53 --- /dev/null +++ b/testdata/firered_reference/ref_probs.json @@ -0,0 +1 @@ +{"probs": [0.04676017165184021, 0.055218636989593506, 0.05121740698814392, 0.059388935565948486, 0.09061706066131592, 0.11598056554794312, 0.12477180361747742, 0.11045300960540771, 0.08661586046218872, 0.07074344158172607, 0.06713229417800903, 0.06406882405281067, 0.055654823780059814, 0.044833481311798096, 0.04214540123939514, 0.03858298063278198, 0.044511377811431885, 0.0455666184425354, 0.04858344793319702, 0.041245996952056885, 0.046636492013931274, 0.04452899098396301, 0.04498150944709778, 0.040284931659698486, 0.03365519642829895, 0.02793976664543152, 0.024532616138458252, 0.022923529148101807, 0.020948290824890137, 0.01894959807395935, 0.016977578401565552, 0.012940704822540283, 0.011039584875106812, 0.00936010479927063, 0.007842659950256348, 0.00709882378578186, 0.006302326917648315, 0.005769133567810059, 0.004631698131561279, 0.006275981664657593, 0.005852162837982178, 0.005577713251113892, 0.00585213303565979, 0.005906879901885986, 0.005759537220001221, 0.005704998970031738, 0.006005138158798218, 0.0063790082931518555, 0.006620943546295166, 0.006661355495452881, 0.006799519062042236, 0.006615668535232544, 0.006243199110031128, 0.005958825349807739, 0.005885452032089233, 0.0055484771728515625, 0.005479991436004639, 0.004785418510437012, 0.005066365003585815, 0.005213439464569092, 0.005936563014984131, 0.006165564060211182, 0.0060637593269348145, 0.005734533071517944, 0.005036383867263794, 0.004215538501739502, 0.004152417182922363, 0.0039643049240112305, 0.004028350114822388, 0.0038444101810455322, 0.003906518220901489, 0.0041106343269348145, 0.004172563552856445, 0.004038870334625244, 0.00374448299407959, 0.0034519731998443604, 0.002969026565551758, 0.003168255090713501, 0.0028406083583831787, 0.0026157796382904053, 0.002449721097946167, 0.0023322105407714844, 0.00227200984954834, 0.002247542142868042, 0.002199023962020874, 0.0021591484546661377, 0.002126336097717285, 0.0021274685859680176, 0.0021434426307678223, 0.0021381378173828125, 0.002115190029144287, 0.002035677433013916, 0.0019636452198028564, 0.0017410516738891602, 0.0015181005001068115, 0.0013241171836853027, 0.0013412237167358398, 0.0012754499912261963]} \ No newline at end of file diff --git a/testdata/firered_reference/ref_samples.json b/testdata/firered_reference/ref_samples.json new file mode 100644 index 0000000..34c77bd --- /dev/null +++ b/testdata/firered_reference/ref_samples.json @@ -0,0 +1 @@ +{"samples": [0, 10767, 8138, 10075, 13586, 4693, 1919, 10071, 9141, 7774, 14653, 9888, -1533, -861, -1820, -7149, 1344, 10447, 6879, 8648, 12724, 5019, 3879, 13887, 14791, 14987, 22936, 18574, 6776, 6259, 3342, -4592, 831, 6631, -215, -1447, 139, -9361, -11483, -1599, 0, 1599, 11483, 9361, -139, 1447, 215, -6631, -831, 4592, -3342, -6259, -6776, -18574, -22936, -14987, -14791, -13887, -3879, -5019, -12724, -8648, -6879, -10447, -1344, 7149, 1820, 861, 1533, -9888, -14653, -7774, -9141, -10071, -1919, -4693, -13586, -10075, -8138, -10767, 0, 10767, 8138, 10075, 13586, 4693, 1919, 10071, 9141, 7774, 14653, 9888, -1533, -861, -1820, -7149, 1344, 10447, 6879, 8648, 12724, 5019, 3879, 13887, 14791, 14987, 22936, 18574, 6776, 6259, 3342, -4592, 831, 6631, -215, -1447, 139, -9361, -11483, -1599, 0, 1599, 11483, 9361, -139, 1447, 215, -6631, -831, 4592, -3342, -6259, -6776, -18574, -22936, -14987, -14791, -13887, -3879, -5019, -12724, -8648, -6879, -10447, -1344, 7149, 1820, 861, 1533, -9888, -14653, -7774, -9141, -10071, -1919, -4693, -13586, -10075, -8138, -10767, 0, 10767, 8138, 10075, 13586, 4693, 1919, 10071, 9141, 7774, 14653, 9888, -1533, -861, -1820, -7149, 1344, 10447, 6879, 8648, 12724, 5019, 3879, 13887, 14791, 14987, 22936, 18574, 6776, 6259, 3342, -4592, 831, 6631, -215, -1447, 139, -9361, -11483, -1599, 0, 1599, 11483, 9361, -139, 1447, 215, -6631, -831, 4592, -3342, -6259, -6776, -18574, -22936, -14987, -14791, -13887, -3879, -5019, -12724, -8648, -6879, -10447, -1344, 7149, 1820, 861, 1533, -9888, -14653, -7774, -9141, -10071, -1919, -4693, -13586, -10075, -8138, -10767, 0, 10767, 8138, 10075, 13586, 4693, 1919, 10071, 9141, 7774, 14653, 9888, -1533, -861, -1820, -7149, 1344, 10447, 6879, 8648, 12724, 5019, 3879, 13887, 14791, 14987, 22936, 18574, 6776, 6259, 3342, -4592, 831, 6631, -215, -1447, 139, -9361, -11483, -1599, 0, 1599, 11483, 9361, -139, 1447, 215, -6631, -831, 4592, -3342, -6259, -6776, -18574, -22936, -14987, -14791, -13887, -3879, -5019, -12724, -8648, -6879, -10447, -1344, 7149, 1820, 861, 1533, -9888, -14653, -7774, -9141, -10071, -1919, -4693, -13586, -10075, -8138, -10767, 0, 10767, 8138, 10075, 13586, 4693, 1919, 10071, 9141, 7774, 14653, 9888, -1533, -861, -1820, -7149, 1344, 10447, 6879, 8648, 12724, 5019, 3879, 13887, 14791, 14987, 22936, 18574, 6776, 6259, 3342, -4592, 831, 6631, -215, -1447, 139, -9361, -11483, -1599, 0, 1599, 11483, 9361, -139, 1447, 215, -6631, -831, 4592, -3342, -6259, -6776, -18574, -22936, -14987, -14791, -13887, -3879, -5019, -12724, -8648, -6879, -10447, -1344, 7149, 1820, 861, 1533, -9888, -14653, -7774, -9141, -10071, -1919, -4693, -13586, -10075, -8138, -10767, 0, 10767, 8138, 10075, 13586, 4693, 1919, 10071, 9141, 7774, 14653, 9888, -1533, -861, -1820, -7149, 1344, 10447, 6879, 8648, 12724, 5019, 3879, 13887, 14791, 14987, 22936, 18574, 6776, 6259, 3342, -4592, 831, 6631, -215, -1447, 139, -9361, -11483, -1599, 0, 1599, 11483, 9361, -139, 1447, 215, -6631, -831, 4592, -3342, -6259, -6776, -18574, -22936, -14987, -14791, -13887, -3879, -5019, -12724, -8648, -6879, -10447, -1344, 7149, 1820, 861, 1533, -9888, -14653, -7774, -9141, -10071, -1919, -4693, -13586, -10075, -8138, -10767, 0, 10767, 8138, 10075, 13586, 4693, 1919, 10071, 9141, 7774, 14653, 9888, -1533, -861, -1820, -7149, 1344, 10447, 6879, 8648, 12724, 5019, 3879, 13887, 14791, 14987, 22936, 18574, 6776, 6259, 3342, -4592, 831, 6631, -215, -1447, 139, -9361, -11483, -1599, 0, 1599, 11483, 9361, -139, 1447, 215, -6631, -831, 4592, -3342, -6259, -6776, -18574, -22936, -14987, -14791, -13887, -3879, -5019, -12724, -8648, -6879, -10447, -1344, 7149, 1820, 861, 1533, -9888, -14653, -7774, -9141, -10071, -1919, -4693, -13586, -10075, -8138, -10767, 0, 10767, 8138, 10075, 13586, 4693, 1919, 10071, 9141, 7774, 14653, 9888, -1533, -861, -1820, -7149, 1344, 10447, 6879, 8648, 12724, 5019, 3879, 13887, 14791, 14987, 22936, 18574, 6776, 6259, 3342, -4592, 831, 6631, -215, -1447, 139, -9361, -11483, -1599, 0, 1599, 11483, 9361, -139, 1447, 215, -6631, -831, 4592, -3342, -6259, -6776, -18574, -22936, -14987, -14791, -13887, -3879, -5019, -12724, -8648, -6879, -10447, -1344, 7149, 1820, 861, 1533, -9888, -14653, -7774, -9141, -10071, -1919, -4693, -13586, -10075, -8138, -10767, 0, 10767, 8138, 10075, 13586, 4693, 1919, 10071, 9141, 7774, 14653, 9888, -1533, -861, -1820, -7149, 1344, 10447, 6879, 8648, 12724, 5019, 3879, 13887, 14791, 14987, 22936, 18574, 6776, 6259, 3342, -4592, 831, 6631, -215, -1447, 139, -9361, -11483, -1599, 0, 1599, 11483, 9361, -139, 1447, 215, -6631, -831, 4592, -3342, -6259, -6776, -18574, -22936, -14987, -14791, -13887, -3879, -5019, -12724, -8648, -6879, -10447, -1344, 7149, 1820, 861, 1533, -9888, -14653, -7774, -9141, -10071, -1919, -4693, -13586, -10075, -8138, -10767, 0, 10767, 8138, 10075, 13586, 4693, 1919, 10071, 9141, 7774, 14653, 9888, -1533, -861, -1820, -7149, 1344, 10447, 6879, 8648, 12724, 5019, 3879, 13887, 14791, 14987, 22936, 18574, 6776, 6259, 3342, -4592, 831, 6631, -215, -1447, 139, -9361, -11483, -1599, 0, 1599, 11483, 9361, -139, 1447, 215, -6631, -831, 4592, -3342, -6259, -6776, -18574, -22936, -14987, -14791, -13887, -3879, -5019, -12724, -8648, -6879, -10447, -1344, 7149, 1820, 861, 1533, -9888, -14653, -7774, -9141, -10071, -1919, -4693, -13586, -10075, -8138, -10767, 0, 10767, 8138, 10075, 13586, 4693, 1919, 10071, 9141, 7774, 14653, 9888, -1533, -861, -1820, -7149, 1344, 10447, 6879, 8648, 12724, 5019, 3879, 13887, 14791, 14987, 22936, 18574, 6776, 6259, 3342, -4592, 831, 6631, -215, -1447, 139, -9361, -11483, -1599, 0, 1599, 11483, 9361, -139, 1447, 215, -6631, -831, 4592, -3342, -6259, -6776, -18574, -22936, -14987, -14791, -13887, -3879, -5019, -12724, -8648, -6879, -10447, -1344, 7149, 1820, 861, 1533, -9888, -14653, -7774, -9141, -10071, -1919, -4693, -13586, -10075, -8138, -10767, 0, 10767, 8138, 10075, 13586, 4693, 1919, 10071, 9141, 7774, 14653, 9888, -1533, -861, -1820, -7149, 1344, 10447, 6879, 8648, 12724, 5019, 3879, 13887, 14791, 14987, 22936, 18574, 6776, 6259, 3342, -4592, 831, 6631, -215, -1447, 139, -9361, -11483, -1599, 0, 1599, 11483, 9361, -139, 1447, 215, -6631, -831, 4592, -3342, -6259, -6776, -18574, -22936, -14987, -14791, -13887, -3879, -5019, -12724, -8648, -6879, -10447, -1344, 7149, 1820, 861, 1533, -9888, -14653, -7774, -9141, -10071, -1919, -4693, -13586, -10075, -8138, -10767, 0, 10767, 8138, 10075, 13586, 4693, 1919, 10071, 9141, 7774, 14653, 9888, -1533, -861, -1820, -7149, 1344, 10447, 6879, 8648, 12724, 5019, 3879, 13887, 14791, 14987, 22936, 18574, 6776, 6259, 3342, -4592, 831, 6631, -215, -1447, 139, -9361, -11483, -1599, 0, 1599, 11483, 9361, -139, 1447, 215, -6631, -831, 4592, -3342, -6259, -6776, -18574, -22936, -14987, -14791, -13887, -3879, -5019, -12724, -8648, -6879, -10447, -1344, 7149, 1820, 861, 1533, -9888, -14653, -7774, -9141, -10071, -1919, -4693, -13586, -10075, -8138, -10767, 0, 10767, 8138, 10075, 13586, 4693, 1919, 10071, 9141, 7774, 14653, 9888, -1533, -861, -1820, -7149, 1344, 10447, 6879, 8648, 12724, 5019, 3879, 13887, 14791, 14987, 22936, 18574, 6776, 6259, 3342, -4592, 831, 6631, -215, -1447, 139, -9361, -11483, -1599, 0, 1599, 11483, 9361, -139, 1447, 215, -6631, -831, 4592, -3342, -6259, -6776, -18574, -22936, -14987, -14791, -13887, -3879, -5019, -12724, -8648, -6879, -10447, -1344, 7149, 1820, 861, 1533, -9888, -14653, -7774, -9141, -10071, -1919, -4693, -13586, -10075, -8138, -10767, 0, 10767, 8138, 10075, 13586, 4693, 1919, 10071, 9141, 7774, 14653, 9888, -1533, -861, -1820, -7149, 1344, 10447, 6879, 8648, 12724, 5019, 3879, 13887, 14791, 14987, 22936, 18574, 6776, 6259, 3342, -4592, 831, 6631, -215, -1447, 139, -9361, -11483, -1599, 0, 1599, 11483, 9361, -139, 1447, 215, -6631, -831, 4592, -3342, -6259, -6776, -18574, -22936, -14987, -14791, -13887, -3879, -5019, -12724, -8648, -6879, -10447, -1344, 7149, 1820, 861, 1533, -9888, -14653, -7774, -9141, -10071, -1919, -4693, -13586, -10075, -8138, -10767, 0, 10767, 8138, 10075, 13586, 4693, 1919, 10071, 9141, 7774, 14653, 9888, -1533, -861, -1820, -7149, 1344, 10447, 6879, 8648, 12724, 5019, 3879, 13887, 14791, 14987, 22936, 18574, 6776, 6259, 3342, -4592, 831, 6631, -215, -1447, 139, -9361, -11483, -1599, 0, 1599, 11483, 9361, -139, 1447, 215, -6631, -831, 4592, -3342, -6259, -6776, -18574, -22936, -14987, -14791, -13887, -3879, -5019, -12724, -8648, -6879, -10447, -1344, 7149, 1820, 861, 1533, -9888, -14653, -7774, -9141, -10071, -1919, -4693, -13586, -10075, -8138, -10767, 0, 10767, 8138, 10075, 13586, 4693, 1919, 10071, 9141, 7774, 14653, 9888, -1533, -861, -1820, -7149, 1344, 10447, 6879, 8648, 12724, 5019, 3879, 13887, 14791, 14987, 22936, 18574, 6776, 6259, 3342, -4592, 831, 6631, -215, -1447, 139, -9361, -11483, -1599, 0, 1599, 11483, 9361, -139, 1447, 215, -6631, -831, 4592, -3342, -6259, -6776, -18574, -22936, -14987, -14791, -13887, -3879, -5019, -12724, -8648, -6879, -10447, -1344, 7149, 1820, 861, 1533, -9888, -14653, -7774, -9141, -10071, -1919, -4693, -13586, -10075, -8138, -10767, 0, 10767, 8138, 10075, 13586, 4693, 1919, 10071, 9141, 7774, 14653, 9888, -1533, -861, -1820, -7149, 1344, 10447, 6879, 8648, 12724, 5019, 3879, 13887, 14791, 14987, 22936, 18574, 6776, 6259, 3342, -4592, 831, 6631, -215, -1447, 139, -9361, -11483, -1599, 0, 1599, 11483, 9361, -139, 1447, 215, -6631, -831, 4592, -3342, -6259, -6776, -18574, -22936, -14987, -14791, -13887, -3879, -5019, -12724, -8648, -6879, -10447, -1344, 7149, 1820, 861, 1533, -9888, -14653, -7774, -9141, -10071, -1919, -4693, -13586, -10075, -8138, -10767, 0, 10767, 8138, 10075, 13586, 4693, 1919, 10071, 9141, 7774, 14653, 9888, -1533, -861, -1820, -7149, 1344, 10447, 6879, 8648, 12724, 5019, 3879, 13887, 14791, 14987, 22936, 18574, 6776, 6259, 3342, -4592, 831, 6631, -215, -1447, 139, -9361, -11483, -1599, 0, 1599, 11483, 9361, -139, 1447, 215, -6631, -831, 4592, -3342, -6259, -6776, -18574, -22936, -14987, -14791, -13887, -3879, -5019, -12724, -8648, -6879, -10447, -1344, 7149, 1820, 861, 1533, -9888, -14653, -7774, -9141, -10071, -1919, -4693, -13586, -10075, -8138, -10767, 0, 10767, 8138, 10075, 13586, 4693, 1919, 10071, 9141, 7774, 14653, 9888, -1533, -861, -1820, -7149, 1344, 10447, 6879, 8648, 12724, 5019, 3879, 13887, 14791, 14987, 22936, 18574, 6776, 6259, 3342, -4592, 831, 6631, -215, -1447, 139, -9361, -11483, -1599, 0, 1599, 11483, 9361, -139, 1447, 215, -6631, -831, 4592, -3342, -6259, -6776, -18574, -22936, -14987, -14791, -13887, -3879, -5019, -12724, -8648, -6879, -10447, -1344, 7149, 1820, 861, 1533, -9888, -14653, -7774, -9141, -10071, -1919, -4693, -13586, -10075, -8138, -10767, 0, 10767, 8138, 10075, 13586, 4693, 1919, 10071, 9141, 7774, 14653, 9888, -1533, -861, -1820, -7149, 1344, 10447, 6879, 8648, 12724, 5019, 3879, 13887, 14791, 14987, 22936, 18574, 6776, 6259, 3342, -4592, 831, 6631, -215, -1447, 139, -9361, -11483, -1599, 0, 1599, 11483, 9361, -139, 1447, 215, -6631, -831, 4592, -3342, -6259, -6776, -18574, -22936, -14987, -14791, -13887, -3879, -5019, -12724, -8648, -6879, -10447, -1344, 7149, 1820, 861, 1533, -9888, -14653, -7774, -9141, -10071, -1919, -4693, -13586, -10075, -8138, -10767, 0, 10767, 8138, 10075, 13586, 4693, 1919, 10071, 9141, 7774, 14653, 9888, -1533, -861, -1820, -7149, 1344, 10447, 6879, 8648, 12724, 5019, 3879, 13887, 14791, 14987, 22936, 18574, 6776, 6259, 3342, -4592, 831, 6631, -215, -1447, 139, -9361, -11483, -1599, 0, 1599, 11483, 9361, -139, 1447, 215, -6631, -831, 4592, -3342, -6259, -6776, -18574, -22936, -14987, -14791, -13887, -3879, -5019, -12724, -8648, -6879, -10447, -1344, 7149, 1820, 861, 1533, -9888, -14653, -7774, -9141, -10071, -1919, -4693, -13586, -10075, -8138, -10767, 0, 10767, 8138, 10075, 13586, 4693, 1919, 10071, 9141, 7774, 14653, 9888, -1533, -861, -1820, -7149, 1344, 10447, 6879, 8648, 12724, 5019, 3879, 13887, 14791, 14987, 22936, 18574, 6776, 6259, 3342, -4592, 831, 6631, -215, -1447, 139, -9361, -11483, -1599, 0, 1599, 11483, 9361, -139, 1447, 215, -6631, -831, 4592, -3342, -6259, -6776, -18574, -22936, -14987, -14791, -13887, -3879, -5019, -12724, -8648, -6879, -10447, -1344, 7149, 1820, 861, 1533, -9888, -14653, -7774, -9141, -10071, -1919, -4693, -13586, -10075, -8138, -10767, 0, 10767, 8138, 10075, 13586, 4693, 1919, 10071, 9141, 7774, 14653, 9888, -1533, -861, -1820, -7149, 1344, 10447, 6879, 8648, 12724, 5019, 3879, 13887, 14791, 14987, 22936, 18574, 6776, 6259, 3342, -4592, 831, 6631, -215, -1447, 139, -9361, -11483, -1599, 0, 1599, 11483, 9361, -139, 1447, 215, -6631, -831, 4592, -3342, -6259, -6776, -18574, -22936, -14987, -14791, -13887, -3879, -5019, -12724, -8648, -6879, -10447, -1344, 7149, 1820, 861, 1533, -9888, -14653, -7774, -9141, -10071, -1919, -4693, -13586, -10075, -8138, -10767, 0, 10767, 8138, 10075, 13586, 4693, 1919, 10071, 9141, 7774, 14653, 9888, -1533, -861, -1820, -7149, 1344, 10447, 6879, 8648, 12724, 5019, 3879, 13887, 14791, 14987, 22936, 18574, 6776, 6259, 3342, -4592, 831, 6631, -215, -1447, 139, -9361, -11483, -1599, 0, 1599, 11483, 9361, -139, 1447, 215, -6631, -831, 4592, -3342, -6259, -6776, -18574, -22936, -14987, -14791, -13887, -3879, -5019, -12724, -8648, -6879, -10447, -1344, 7149, 1820, 861, 1533, -9888, -14653, -7774, -9141, -10071, -1919, -4693, -13586, -10075, -8138, -10767, 0, 10767, 8138, 10075, 13586, 4693, 1919, 10071, 9141, 7774, 14653, 9888, -1533, -861, -1820, -7149, 1344, 10447, 6879, 8648, 12724, 5019, 3879, 13887, 14791, 14987, 22936, 18574, 6776, 6259, 3342, -4592, 831, 6631, -215, -1447, 139, -9361, -11483, -1599, 0, 1599, 11483, 9361, -139, 1447, 215, -6631, -831, 4592, -3342, -6259, -6776, -18574, -22936, -14987, -14791, -13887, -3879, -5019, -12724, -8648, -6879, -10447, -1344, 7149, 1820, 861, 1533, -9888, -14653, -7774, -9141, -10071, -1919, -4693, -13586, -10075, -8138, -10767, 0, 10767, 8138, 10075, 13586, 4693, 1919, 10071, 9141, 7774, 14653, 9888, -1533, -861, -1820, -7149, 1344, 10447, 6879, 8648, 12724, 5019, 3879, 13887, 14791, 14987, 22936, 18574, 6776, 6259, 3342, -4592, 831, 6631, -215, -1447, 139, -9361, -11483, -1599, 0, 1599, 11483, 9361, -139, 1447, 215, -6631, -831, 4592, -3342, -6259, -6776, -18574, -22936, -14987, -14791, -13887, -3879, -5019, -12724, -8648, -6879, -10447, -1344, 7149, 1820, 861, 1533, -9888, -14653, -7774, -9141, -10071, -1919, -4693, -13586, -10075, -8138, -10767, 0, 10767, 8138, 10075, 13586, 4693, 1919, 10071, 9141, 7774, 14653, 9888, -1533, -861, -1820, -7149, 1344, 10447, 6879, 8648, 12724, 5019, 3879, 13887, 14791, 14987, 22936, 18574, 6776, 6259, 3342, -4592, 831, 6631, -215, -1447, 139, -9361, -11483, -1599, 0, 1599, 11483, 9361, -139, 1447, 215, -6631, -831, 4592, -3342, -6259, -6776, -18574, -22936, -14987, -14791, -13887, -3879, -5019, -12724, -8648, -6879, -10447, -1344, 7149, 1820, 861, 1533, -9888, -14653, -7774, -9141, -10071, -1919, -4693, -13586, -10075, -8138, -10767, 0, 10767, 8138, 10075, 13586, 4693, 1919, 10071, 9141, 7774, 14653, 9888, -1533, -861, -1820, -7149, 1344, 10447, 6879, 8648, 12724, 5019, 3879, 13887, 14791, 14987, 22936, 18574, 6776, 6259, 3342, -4592, 831, 6631, -215, -1447, 139, -9361, -11483, -1599, 0, 1599, 11483, 9361, -139, 1447, 215, -6631, -831, 4592, -3342, -6259, -6776, -18574, -22936, -14987, -14791, -13887, -3879, -5019, -12724, -8648, -6879, -10447, -1344, 7149, 1820, 861, 1533, -9888, -14653, -7774, -9141, -10071, -1919, -4693, -13586, -10075, -8138, -10767, 0, 10767, 8138, 10075, 13586, 4693, 1919, 10071, 9141, 7774, 14653, 9888, -1533, -861, -1820, -7149, 1344, 10447, 6879, 8648, 12724, 5019, 3879, 13887, 14791, 14987, 22936, 18574, 6776, 6259, 3342, -4592, 831, 6631, -215, -1447, 139, -9361, -11483, -1599, 0, 1599, 11483, 9361, -139, 1447, 215, -6631, -831, 4592, -3342, -6259, -6776, -18574, -22936, -14987, -14791, -13887, -3879, -5019, -12724, -8648, -6879, -10447, -1344, 7149, 1820, 861, 1533, -9888, -14653, -7774, -9141, -10071, -1919, -4693, -13586, -10075, -8138, -10767, 0, 10767, 8138, 10075, 13586, 4693, 1919, 10071, 9141, 7774, 14653, 9888, -1533, -861, -1820, -7149, 1344, 10447, 6879, 8648, 12724, 5019, 3879, 13887, 14791, 14987, 22936, 18574, 6776, 6259, 3342, -4592, 831, 6631, -215, -1447, 139, -9361, -11483, -1599, 0, 1599, 11483, 9361, -139, 1447, 215, -6631, -831, 4592, -3342, -6259, -6776, -18574, -22936, -14987, -14791, -13887, -3879, -5019, -12724, -8648, -6879, -10447, -1344, 7149, 1820, 861, 1533, -9888, -14653, -7774, -9141, -10071, -1919, -4693, -13586, -10075, -8138, -10767, 0, 10767, 8138, 10075, 13586, 4693, 1919, 10071, 9141, 7774, 14653, 9888, -1533, -861, -1820, -7149, 1344, 10447, 6879, 8648, 12724, 5019, 3879, 13887, 14791, 14987, 22936, 18574, 6776, 6259, 3342, -4592, 831, 6631, -215, -1447, 139, -9361, -11483, -1599, 0, 1599, 11483, 9361, -139, 1447, 215, -6631, -831, 4592, -3342, -6259, -6776, -18574, -22936, -14987, -14791, -13887, -3879, -5019, -12724, -8648, -6879, -10447, -1344, 7149, 1820, 861, 1533, -9888, -14653, -7774, -9141, -10071, -1919, -4693, -13586, -10075, -8138, -10767, 0, 10767, 8138, 10075, 13586, 4693, 1919, 10071, 9141, 7774, 14653, 9888, -1533, -861, -1820, -7149, 1344, 10447, 6879, 8648, 12724, 5019, 3879, 13887, 14791, 14987, 22936, 18574, 6776, 6259, 3342, -4592, 831, 6631, -215, -1447, 139, -9361, -11483, -1599, 0, 1599, 11483, 9361, -139, 1447, 215, -6631, -831, 4592, -3342, -6259, -6776, -18574, -22936, -14987, -14791, -13887, -3879, -5019, -12724, -8648, -6879, -10447, -1344, 7149, 1820, 861, 1533, -9888, -14653, -7774, -9141, -10071, -1919, -4693, -13586, -10075, -8138, -10767, 0, 10767, 8138, 10075, 13586, 4693, 1919, 10071, 9141, 7774, 14653, 9888, -1533, -861, -1820, -7149, 1344, 10447, 6879, 8648, 12724, 5019, 3879, 13887, 14791, 14987, 22936, 18574, 6776, 6259, 3342, -4592, 831, 6631, -215, -1447, 139, -9361, -11483, -1599, 0, 1599, 11483, 9361, -139, 1447, 215, -6631, -831, 4592, -3342, -6259, -6776, -18574, -22936, -14987, -14791, -13887, -3879, -5019, -12724, -8648, -6879, -10447, -1344, 7149, 1820, 861, 1533, -9888, -14653, -7774, -9141, -10071, -1919, -4693, -13586, -10075, -8138, -10767, 0, 10767, 8138, 10075, 13586, 4693, 1919, 10071, 9141, 7774, 14653, 9888, -1533, -861, -1820, -7149, 1344, 10447, 6879, 8648, 12724, 5019, 3879, 13887, 14791, 14987, 22936, 18574, 6776, 6259, 3342, -4592, 831, 6631, -215, -1447, 139, -9361, -11483, -1599, 0, 1599, 11483, 9361, -139, 1447, 215, -6631, -831, 4592, -3342, -6259, -6776, -18574, -22936, -14987, -14791, -13887, -3879, -5019, -12724, -8648, -6879, -10447, -1344, 7149, 1820, 861, 1533, -9888, -14653, -7774, -9141, -10071, -1919, -4693, -13586, -10075, -8138, -10767, 0, 10767, 8138, 10075, 13586, 4693, 1919, 10071, 9141, 7774, 14653, 9888, -1533, -861, -1820, -7149, 1344, 10447, 6879, 8648, 12724, 5019, 3879, 13887, 14791, 14987, 22936, 18574, 6776, 6259, 3342, -4592, 831, 6631, -215, -1447, 139, -9361, -11483, -1599, 0, 1599, 11483, 9361, -139, 1447, 215, -6631, -831, 4592, -3342, -6259, -6776, -18574, -22936, -14987, -14791, -13887, -3879, -5019, -12724, -8648, -6879, -10447, -1344, 7149, 1820, 861, 1533, -9888, -14653, -7774, -9141, -10071, -1919, -4693, -13586, -10075, -8138, -10767, 0, 10767, 8138, 10075, 13586, 4693, 1919, 10071, 9141, 7774, 14653, 9888, -1533, -861, -1820, -7149, 1344, 10447, 6879, 8648, 12724, 5019, 3879, 13887, 14791, 14987, 22936, 18574, 6776, 6259, 3342, -4592, 831, 6631, -215, -1447, 139, -9361, -11483, -1599, 0, 1599, 11483, 9361, -139, 1447, 215, -6631, -831, 4592, -3342, -6259, -6776, -18574, -22936, -14987, -14791, -13887, -3879, -5019, -12724, -8648, -6879, -10447, -1344, 7149, 1820, 861, 1533, -9888, -14653, -7774, -9141, -10071, -1919, -4693, -13586, -10075, -8138, -10767, 0, 10767, 8138, 10075, 13586, 4693, 1919, 10071, 9141, 7774, 14653, 9888, -1533, -861, -1820, -7149, 1344, 10447, 6879, 8648, 12724, 5019, 3879, 13887, 14791, 14987, 22936, 18574, 6776, 6259, 3342, -4592, 831, 6631, -215, -1447, 139, -9361, -11483, -1599, 0, 1599, 11483, 9361, -139, 1447, 215, -6631, -831, 4592, -3342, -6259, -6776, -18574, -22936, -14987, -14791, -13887, -3879, -5019, -12724, -8648, -6879, -10447, -1344, 7149, 1820, 861, 1533, -9888, -14653, -7774, -9141, -10071, -1919, -4693, -13586, -10075, -8138, -10767, 0, 10767, 8138, 10075, 13586, 4693, 1919, 10071, 9141, 7774, 14653, 9888, -1533, -861, -1820, -7149, 1344, 10447, 6879, 8648, 12724, 5019, 3879, 13887, 14791, 14987, 22936, 18574, 6776, 6259, 3342, -4592, 831, 6631, -215, -1447, 139, -9361, -11483, -1599, 0, 1599, 11483, 9361, -139, 1447, 215, -6631, -831, 4592, -3342, -6259, -6776, -18574, -22936, -14987, -14791, -13887, -3879, -5019, -12724, -8648, -6879, -10447, -1344, 7149, 1820, 861, 1533, -9888, -14653, -7774, -9141, -10071, -1919, -4693, -13586, -10075, -8138, -10767, 0, 10767, 8138, 10075, 13586, 4693, 1919, 10071, 9141, 7774, 14653, 9888, -1533, -861, -1820, -7149, 1344, 10447, 6879, 8648, 12724, 5019, 3879, 13887, 14791, 14987, 22936, 18574, 6776, 6259, 3342, -4592, 831, 6631, -215, -1447, 139, -9361, -11483, -1599, 0, 1599, 11483, 9361, -139, 1447, 215, -6631, -831, 4592, -3342, -6259, -6776, -18574, -22936, -14987, -14791, -13887, -3879, -5019, -12724, -8648, -6879, -10447, -1344, 7149, 1820, 861, 1533, -9888, -14653, -7774, -9141, -10071, -1919, -4693, -13586, -10075, -8138, -10767, 0, 10767, 8138, 10075, 13586, 4693, 1919, 10071, 9141, 7774, 14653, 9888, -1533, -861, -1820, -7149, 1344, 10447, 6879, 8648, 12724, 5019, 3879, 13887, 14791, 14987, 22936, 18574, 6776, 6259, 3342, -4592, 831, 6631, -215, -1447, 139, -9361, -11483, -1599, 0, 1599, 11483, 9361, -139, 1447, 215, -6631, -831, 4592, -3342, -6259, -6776, -18574, -22936, -14987, -14791, -13887, -3879, -5019, -12724, -8648, -6879, -10447, -1344, 7149, 1820, 861, 1533, -9888, -14653, -7774, -9141, -10071, -1919, -4693, -13586, -10075, -8138, -10767, 0, 10767, 8138, 10075, 13586, 4693, 1919, 10071, 9141, 7774, 14653, 9888, -1533, -861, -1820, -7149, 1344, 10447, 6879, 8648, 12724, 5019, 3879, 13887, 14791, 14987, 22936, 18574, 6776, 6259, 3342, -4592, 831, 6631, -215, -1447, 139, -9361, -11483, -1599, 0, 1599, 11483, 9361, -139, 1447, 215, -6631, -831, 4592, -3342, -6259, -6776, -18574, -22936, -14987, -14791, -13887, -3879, -5019, -12724, -8648, -6879, -10447, -1344, 7149, 1820, 861, 1533, -9888, -14653, -7774, -9141, -10071, -1919, -4693, -13586, -10075, -8138, -10767, 0, 10767, 8138, 10075, 13586, 4693, 1919, 10071, 9141, 7774, 14653, 9888, -1533, -861, -1820, -7149, 1344, 10447, 6879, 8648, 12724, 5019, 3879, 13887, 14791, 14987, 22936, 18574, 6776, 6259, 3342, -4592, 831, 6631, -215, -1447, 139, -9361, -11483, -1599, 0, 1599, 11483, 9361, -139, 1447, 215, -6631, -831, 4592, -3342, -6259, -6776, -18574, -22936, -14987, -14791, -13887, -3879, -5019, -12724, -8648, -6879, -10447, -1344, 7149, 1820, 861, 1533, -9888, -14653, -7774, -9141, -10071, -1919, -4693, -13586, -10075, -8138, -10767, 0, 10767, 8138, 10075, 13586, 4693, 1919, 10071, 9141, 7774, 14653, 9888, -1533, -861, -1820, -7149, 1344, 10447, 6879, 8648, 12724, 5019, 3879, 13887, 14791, 14987, 22936, 18574, 6776, 6259, 3342, -4592, 831, 6631, -215, -1447, 139, -9361, -11483, -1599, 0, 1599, 11483, 9361, -139, 1447, 215, -6631, -831, 4592, -3342, -6259, -6776, -18574, -22936, -14987, -14791, -13887, -3879, -5019, -12724, -8648, -6879, -10447, -1344, 7149, 1820, 861, 1533, -9888, -14653, -7774, -9141, -10071, -1919, -4693, -13586, -10075, -8138, -10767, 0, 10767, 8138, 10075, 13586, 4693, 1919, 10071, 9141, 7774, 14653, 9888, -1533, -861, -1820, -7149, 1344, 10447, 6879, 8648, 12724, 5019, 3879, 13887, 14791, 14987, 22936, 18574, 6776, 6259, 3342, -4592, 831, 6631, -215, -1447, 139, -9361, -11483, -1599, 0, 1599, 11483, 9361, -139, 1447, 215, -6631, -831, 4592, -3342, -6259, -6776, -18574, -22936, -14987, -14791, -13887, -3879, -5019, -12724, -8648, -6879, -10447, -1344, 7149, 1820, 861, 1533, -9888, -14653, -7774, -9141, -10071, -1919, -4693, -13586, -10075, -8138, -10767, 0, 10767, 8138, 10075, 13586, 4693, 1919, 10071, 9141, 7774, 14653, 9888, -1533, -861, -1820, -7149, 1344, 10447, 6879, 8648, 12724, 5019, 3879, 13887, 14791, 14987, 22936, 18574, 6776, 6259, 3342, -4592, 831, 6631, -215, -1447, 139, -9361, -11483, -1599, 0, 1599, 11483, 9361, -139, 1447, 215, -6631, -831, 4592, -3342, -6259, -6776, -18574, -22936, -14987, -14791, -13887, -3879, -5019, -12724, -8648, -6879, -10447, -1344, 7149, 1820, 861, 1533, -9888, -14653, -7774, -9141, -10071, -1919, -4693, -13586, -10075, -8138, -10767, 0, 10767, 8138, 10075, 13586, 4693, 1919, 10071, 9141, 7774, 14653, 9888, -1533, -861, -1820, -7149, 1344, 10447, 6879, 8648, 12724, 5019, 3879, 13887, 14791, 14987, 22936, 18574, 6776, 6259, 3342, -4592, 831, 6631, -215, -1447, 139, -9361, -11483, -1599, 0, 1599, 11483, 9361, -139, 1447, 215, -6631, -831, 4592, -3342, -6259, -6776, -18574, -22936, -14987, -14791, -13887, -3879, -5019, -12724, -8648, -6879, -10447, -1344, 7149, 1820, 861, 1533, -9888, -14653, -7774, -9141, -10071, -1919, -4693, -13586, -10075, -8138, -10767, 0, 10767, 8138, 10075, 13586, 4693, 1919, 10071, 9141, 7774, 14653, 9888, -1533, -861, -1820, -7149, 1344, 10447, 6879, 8648, 12724, 5019, 3879, 13887, 14791, 14987, 22936, 18574, 6776, 6259, 3342, -4592, 831, 6631, -215, -1447, 139, -9361, -11483, -1599, 0, 1599, 11483, 9361, -139, 1447, 215, -6631, -831, 4592, -3342, -6259, -6776, -18574, -22936, -14987, -14791, -13887, -3879, -5019, -12724, -8648, -6879, -10447, -1344, 7149, 1820, 861, 1533, -9888, -14653, -7774, -9141, -10071, -1919, -4693, -13586, -10075, -8138, -10767, 0, 10767, 8138, 10075, 13586, 4693, 1919, 10071, 9141, 7774, 14653, 9888, -1533, -861, -1820, -7149, 1344, 10447, 6879, 8648, 12724, 5019, 3879, 13887, 14791, 14987, 22936, 18574, 6776, 6259, 3342, -4592, 831, 6631, -215, -1447, 139, -9361, -11483, -1599, 0, 1599, 11483, 9361, -139, 1447, 215, -6631, -831, 4592, -3342, -6259, -6776, -18574, -22936, -14987, -14791, -13887, -3879, -5019, -12724, -8648, -6879, -10447, -1344, 7149, 1820, 861, 1533, -9888, -14653, -7774, -9141, -10071, -1919, -4693, -13586, -10075, -8138, -10767, 0, 10767, 8138, 10075, 13586, 4693, 1919, 10071, 9141, 7774, 14653, 9888, -1533, -861, -1820, -7149, 1344, 10447, 6879, 8648, 12724, 5019, 3879, 13887, 14791, 14987, 22936, 18574, 6776, 6259, 3342, -4592, 831, 6631, -215, -1447, 139, -9361, -11483, -1599, 0, 1599, 11483, 9361, -139, 1447, 215, -6631, -831, 4592, -3342, -6259, -6776, -18574, -22936, -14987, -14791, -13887, -3879, -5019, -12724, -8648, -6879, -10447, -1344, 7149, 1820, 861, 1533, -9888, -14653, -7774, -9141, -10071, -1919, -4693, -13586, -10075, -8138, -10767, 0, 10767, 8138, 10075, 13586, 4693, 1919, 10071, 9141, 7774, 14653, 9888, -1533, -861, -1820, -7149, 1344, 10447, 6879, 8648, 12724, 5019, 3879, 13887, 14791, 14987, 22936, 18574, 6776, 6259, 3342, -4592, 831, 6631, -215, -1447, 139, -9361, -11483, -1599, 0, 1599, 11483, 9361, -139, 1447, 215, -6631, -831, 4592, -3342, -6259, -6776, -18574, -22936, -14987, -14791, -13887, -3879, -5019, -12724, -8648, -6879, -10447, -1344, 7149, 1820, 861, 1533, -9888, -14653, -7774, -9141, -10071, -1919, -4693, -13586, -10075, -8138, -10767, 0, 10767, 8138, 10075, 13586, 4693, 1919, 10071, 9141, 7774, 14653, 9888, -1533, -861, -1820, -7149, 1344, 10447, 6879, 8648, 12724, 5019, 3879, 13887, 14791, 14987, 22936, 18574, 6776, 6259, 3342, -4592, 831, 6631, -215, -1447, 139, -9361, -11483, -1599, 0, 1599, 11483, 9361, -139, 1447, 215, -6631, -831, 4592, -3342, -6259, -6776, -18574, -22936, -14987, -14791, -13887, -3879, -5019, -12724, -8648, -6879, -10447, -1344, 7149, 1820, 861, 1533, -9888, -14653, -7774, -9141, -10071, -1919, -4693, -13586, -10075, -8138, -10767, 0, 10767, 8138, 10075, 13586, 4693, 1919, 10071, 9141, 7774, 14653, 9888, -1533, -861, -1820, -7149, 1344, 10447, 6879, 8648, 12724, 5019, 3879, 13887, 14791, 14987, 22936, 18574, 6776, 6259, 3342, -4592, 831, 6631, -215, -1447, 139, -9361, -11483, -1599, 0, 1599, 11483, 9361, -139, 1447, 215, -6631, -831, 4592, -3342, -6259, -6776, -18574, -22936, -14987, -14791, -13887, -3879, -5019, -12724, -8648, -6879, -10447, -1344, 7149, 1820, 861, 1533, -9888, -14653, -7774, -9141, -10071, -1919, -4693, -13586, -10075, -8138, -10767, 0, 10767, 8138, 10075, 13586, 4693, 1919, 10071, 9141, 7774, 14653, 9888, -1533, -861, -1820, -7149, 1344, 10447, 6879, 8648, 12724, 5019, 3879, 13887, 14791, 14987, 22936, 18574, 6776, 6259, 3342, -4592, 831, 6631, -215, -1447, 139, -9361, -11483, -1599, 0, 1599, 11483, 9361, -139, 1447, 215, -6631, -831, 4592, -3342, -6259, -6776, -18574, -22936, -14987, -14791, -13887, -3879, -5019, -12724, -8648, -6879, -10447, -1344, 7149, 1820, 861, 1533, -9888, -14653, -7774, -9141, -10071, -1919, -4693, -13586, -10075, -8138, -10767, 0, 10767, 8138, 10075, 13586, 4693, 1919, 10071, 9141, 7774, 14653, 9888, -1533, -861, -1820, -7149, 1344, 10447, 6879, 8648, 12724, 5019, 3879, 13887, 14791, 14987, 22936, 18574, 6776, 6259, 3342, -4592, 831, 6631, -215, -1447, 139, -9361, -11483, -1599, 0, 1599, 11483, 9361, -139, 1447, 215, -6631, -831, 4592, -3342, -6259, -6776, -18574, -22936, -14987, -14791, -13887, -3879, -5019, -12724, -8648, -6879, -10447, -1344, 7149, 1820, 861, 1533, -9888, -14653, -7774, -9141, -10071, -1919, -4693, -13586, -10075, -8138, -10767, 0, 10767, 8138, 10075, 13586, 4693, 1919, 10071, 9141, 7774, 14653, 9888, -1533, -861, -1820, -7149, 1344, 10447, 6879, 8648, 12724, 5019, 3879, 13887, 14791, 14987, 22936, 18574, 6776, 6259, 3342, -4592, 831, 6631, -215, -1447, 139, -9361, -11483, -1599, 0, 1599, 11483, 9361, -139, 1447, 215, -6631, -831, 4592, -3342, -6259, -6776, -18574, -22936, -14987, -14791, -13887, -3879, -5019, -12724, -8648, -6879, -10447, -1344, 7149, 1820, 861, 1533, -9888, -14653, -7774, -9141, -10071, -1919, -4693, -13586, -10075, -8138, -10767, 0, 10767, 8138, 10075, 13586, 4693, 1919, 10071, 9141, 7774, 14653, 9888, -1533, -861, -1820, -7149, 1344, 10447, 6879, 8648, 12724, 5019, 3879, 13887, 14791, 14987, 22936, 18574, 6776, 6259, 3342, -4592, 831, 6631, -215, -1447, 139, -9361, -11483, -1599, 0, 1599, 11483, 9361, -139, 1447, 215, -6631, -831, 4592, -3342, -6259, -6776, -18574, -22936, -14987, -14791, -13887, -3879, -5019, -12724, -8648, -6879, -10447, -1344, 7149, 1820, 861, 1533, -9888, -14653, -7774, -9141, -10071, -1919, -4693, -13586, -10075, -8138, -10767, 0, 10767, 8138, 10075, 13586, 4693, 1919, 10071, 9141, 7774, 14653, 9888, -1533, -861, -1820, -7149, 1344, 10447, 6879, 8648, 12724, 5019, 3879, 13887, 14791, 14987, 22936, 18574, 6776, 6259, 3342, -4592, 831, 6631, -215, -1447, 139, -9361, -11483, -1599, 0, 1599, 11483, 9361, -139, 1447, 215, -6631, -831, 4592, -3342, -6259, -6776, -18574, -22936, -14987, -14791, -13887, -3879, -5019, -12724, -8648, -6879, -10447, -1344, 7149, 1820, 861, 1533, -9888, -14653, -7774, -9141, -10071, -1919, -4693, -13586, -10075, -8138, -10767, 0, 10767, 8138, 10075, 13586, 4693, 1919, 10071, 9141, 7774, 14653, 9888, -1533, -861, -1820, -7149, 1344, 10447, 6879, 8648, 12724, 5019, 3879, 13887, 14791, 14987, 22936, 18574, 6776, 6259, 3342, -4592, 831, 6631, -215, -1447, 139, -9361, -11483, -1599, 0, 1599, 11483, 9361, -139, 1447, 215, -6631, -831, 4592, -3342, -6259, -6776, -18574, -22936, -14987, -14791, -13887, -3879, -5019, -12724, -8648, -6879, -10447, -1344, 7149, 1820, 861, 1533, -9888, -14653, -7774, -9141, -10071, -1919, -4693, -13586, -10075, -8138, -10767, 0, 10767, 8138, 10075, 13586, 4693, 1919, 10071, 9141, 7774, 14653, 9888, -1533, -861, -1820, -7149, 1344, 10447, 6879, 8648, 12724, 5019, 3879, 13887, 14791, 14987, 22936, 18574, 6776, 6259, 3342, -4592, 831, 6631, -215, -1447, 139, -9361, -11483, -1599, 0, 1599, 11483, 9361, -139, 1447, 215, -6631, -831, 4592, -3342, -6259, -6776, -18574, -22936, -14987, -14791, -13887, -3879, -5019, -12724, -8648, -6879, -10447, -1344, 7149, 1820, 861, 1533, -9888, -14653, -7774, -9141, -10071, -1919, -4693, -13586, -10075, -8138, -10767, 0, 10767, 8138, 10075, 13586, 4693, 1919, 10071, 9141, 7774, 14653, 9888, -1533, -861, -1820, -7149, 1344, 10447, 6879, 8648, 12724, 5019, 3879, 13887, 14791, 14987, 22936, 18574, 6776, 6259, 3342, -4592, 831, 6631, -215, -1447, 139, -9361, -11483, -1599, 0, 1599, 11483, 9361, -139, 1447, 215, -6631, -831, 4592, -3342, -6259, -6776, -18574, -22936, -14987, -14791, -13887, -3879, -5019, -12724, -8648, -6879, -10447, -1344, 7149, 1820, 861, 1533, -9888, -14653, -7774, -9141, -10071, -1919, -4693, -13586, -10075, -8138, -10767, 0, 10767, 8138, 10075, 13586, 4693, 1919, 10071, 9141, 7774, 14653, 9888, -1533, -861, -1820, -7149, 1344, 10447, 6879, 8648, 12724, 5019, 3879, 13887, 14791, 14987, 22936, 18574, 6776, 6259, 3342, -4592, 831, 6631, -215, -1447, 139, -9361, -11483, -1599, 0, 1599, 11483, 9361, -139, 1447, 215, -6631, -831, 4592, -3342, -6259, -6776, -18574, -22936, -14987, -14791, -13887, -3879, -5019, -12724, -8648, -6879, -10447, -1344, 7149, 1820, 861, 1533, -9888, -14653, -7774, -9141, -10071, -1919, -4693, -13586, -10075, -8138, -10767, 0, 10767, 8138, 10075, 13586, 4693, 1919, 10071, 9141, 7774, 14653, 9888, -1533, -861, -1820, -7149, 1344, 10447, 6879, 8648, 12724, 5019, 3879, 13887, 14791, 14987, 22936, 18574, 6776, 6259, 3342, -4592, 831, 6631, -215, -1447, 139, -9361, -11483, -1599, 0, 1599, 11483, 9361, -139, 1447, 215, -6631, -831, 4592, -3342, -6259, -6776, -18574, -22936, -14987, -14791, -13887, -3879, -5019, -12724, -8648, -6879, -10447, -1344, 7149, 1820, 861, 1533, -9888, -14653, -7774, -9141, -10071, -1919, -4693, -13586, -10075, -8138, -10767, 0, 10767, 8138, 10075, 13586, 4693, 1919, 10071, 9141, 7774, 14653, 9888, -1533, -861, -1820, -7149, 1344, 10447, 6879, 8648, 12724, 5019, 3879, 13887, 14791, 14987, 22936, 18574, 6776, 6259, 3342, -4592, 831, 6631, -215, -1447, 139, -9361, -11483, -1599, 0, 1599, 11483, 9361, -139, 1447, 215, -6631, -831, 4592, -3342, -6259, -6776, -18574, -22936, -14987, -14791, -13887, -3879, -5019, -12724, -8648, -6879, -10447, -1344, 7149, 1820, 861, 1533, -9888, -14653, -7774, -9141, -10071, -1919, -4693, -13586, -10075, -8138, -10767, 0, 10767, 8138, 10075, 13586, 4693, 1919, 10071, 9141, 7774, 14653, 9888, -1533, -861, -1820, -7149, 1344, 10447, 6879, 8648, 12724, 5019, 3879, 13887, 14791, 14987, 22936, 18574, 6776, 6259, 3342, -4592, 831, 6631, -215, -1447, 139, -9361, -11483, -1599, 0, 1599, 11483, 9361, -139, 1447, 215, -6631, -831, 4592, -3342, -6259, -6776, -18574, -22936, -14987, -14791, -13887, -3879, -5019, -12724, -8648, -6879, -10447, -1344, 7149, 1820, 861, 1533, -9888, -14653, -7774, -9141, -10071, -1919, -4693, -13586, -10075, -8138, -10767, 0, 10767, 8138, 10075, 13586, 4693, 1919, 10071, 9141, 7774, 14653, 9888, -1533, -861, -1820, -7149, 1344, 10447, 6879, 8648, 12724, 5019, 3879, 13887, 14791, 14987, 22936, 18574, 6776, 6259, 3342, -4592, 831, 6631, -215, -1447, 139, -9361, -11483, -1599, 0, 1599, 11483, 9361, -139, 1447, 215, -6631, -831, 4592, -3342, -6259, -6776, -18574, -22936, -14987, -14791, -13887, -3879, -5019, -12724, -8648, -6879, -10447, -1344, 7149, 1820, 861, 1533, -9888, -14653, -7774, -9141, -10071, -1919, -4693, -13586, -10075, -8138, -10767, 0, 10767, 8138, 10075, 13586, 4693, 1919, 10071, 9141, 7774, 14653, 9888, -1533, -861, -1820, -7149, 1344, 10447, 6879, 8648, 12724, 5019, 3879, 13887, 14791, 14987, 22936, 18574, 6776, 6259, 3342, -4592, 831, 6631, -215, -1447, 139, -9361, -11483, -1599, 0, 1599, 11483, 9361, -139, 1447, 215, -6631, -831, 4592, -3342, -6259, -6776, -18574, -22936, -14987, -14791, -13887, -3879, -5019, -12724, -8648, -6879, -10447, -1344, 7149, 1820, 861, 1533, -9888, -14653, -7774, -9141, -10071, -1919, -4693, -13586, -10075, -8138, -10767, 0, 10767, 8138, 10075, 13586, 4693, 1919, 10071, 9141, 7774, 14653, 9888, -1533, -861, -1820, -7149, 1344, 10447, 6879, 8648, 12724, 5019, 3879, 13887, 14791, 14987, 22936, 18574, 6776, 6259, 3342, -4592, 831, 6631, -215, -1447, 139, -9361, -11483, -1599, 0, 1599, 11483, 9361, -139, 1447, 215, -6631, -831, 4592, -3342, -6259, -6776, -18574, -22936, -14987, -14791, -13887, -3879, -5019, -12724, -8648, -6879, -10447, -1344, 7149, 1820, 861, 1533, -9888, -14653, -7774, -9141, -10071, -1919, -4693, -13586, -10075, -8138, -10767, 0, 10767, 8138, 10075, 13586, 4693, 1919, 10071, 9141, 7774, 14653, 9888, -1533, -861, -1820, -7149, 1344, 10447, 6879, 8648, 12724, 5019, 3879, 13887, 14791, 14987, 22936, 18574, 6776, 6259, 3342, -4592, 831, 6631, -215, -1447, 139, -9361, -11483, -1599, 0, 1599, 11483, 9361, -139, 1447, 215, -6631, -831, 4592, -3342, -6259, -6776, -18574, -22936, -14987, -14791, -13887, -3879, -5019, -12724, -8648, -6879, -10447, -1344, 7149, 1820, 861, 1533, -9888, -14653, -7774, -9141, -10071, -1919, -4693, -13586, -10075, -8138, -10767, 0, 10767, 8138, 10075, 13586, 4693, 1919, 10071, 9141, 7774, 14653, 9888, -1533, -861, -1820, -7149, 1344, 10447, 6879, 8648, 12724, 5019, 3879, 13887, 14791, 14987, 22936, 18574, 6776, 6259, 3342, -4592, 831, 6631, -215, -1447, 139, -9361, -11483, -1599, 0, 1599, 11483, 9361, -139, 1447, 215, -6631, -831, 4592, -3342, -6259, -6776, -18574, -22936, -14987, -14791, -13887, -3879, -5019, -12724, -8648, -6879, -10447, -1344, 7149, 1820, 861, 1533, -9888, -14653, -7774, -9141, -10071, -1919, -4693, -13586, -10075, -8138, -10767, 0, 10767, 8138, 10075, 13586, 4693, 1919, 10071, 9141, 7774, 14653, 9888, -1533, -861, -1820, -7149, 1344, 10447, 6879, 8648, 12724, 5019, 3879, 13887, 14791, 14987, 22936, 18574, 6776, 6259, 3342, -4592, 831, 6631, -215, -1447, 139, -9361, -11483, -1599, 0, 1599, 11483, 9361, -139, 1447, 215, -6631, -831, 4592, -3342, -6259, -6776, -18574, -22936, -14987, -14791, -13887, -3879, -5019, -12724, -8648, -6879, -10447, -1344, 7149, 1820, 861, 1533, -9888, -14653, -7774, -9141, -10071, -1919, -4693, -13586, -10075, -8138, -10767, 0, 10767, 8138, 10075, 13586, 4693, 1919, 10071, 9141, 7774, 14653, 9888, -1533, -861, -1820, -7149, 1344, 10447, 6879, 8648, 12724, 5019, 3879, 13887, 14791, 14987, 22936, 18574, 6776, 6259, 3342, -4592, 831, 6631, -215, -1447, 139, -9361, -11483, -1599, 0, 1599, 11483, 9361, -139, 1447, 215, -6631, -831, 4592, -3342, -6259, -6776, -18574, -22936, -14987, -14791, -13887, -3879, -5019, -12724, -8648, -6879, -10447, -1344, 7149, 1820, 861, 1533, -9888, -14653, -7774, -9141, -10071, -1919, -4693, -13586, -10075, -8138, -10767, 0, 10767, 8138, 10075, 13586, 4693, 1919, 10071, 9141, 7774, 14653, 9888, -1533, -861, -1820, -7149, 1344, 10447, 6879, 8648, 12724, 5019, 3879, 13887, 14791, 14987, 22936, 18574, 6776, 6259, 3342, -4592, 831, 6631, -215, -1447, 139, -9361, -11483, -1599, 0, 1599, 11483, 9361, -139, 1447, 215, -6631, -831, 4592, -3342, -6259, -6776, -18574, -22936, -14987, -14791, -13887, -3879, -5019, -12724, -8648, -6879, -10447, -1344, 7149, 1820, 861, 1533, -9888, -14653, -7774, -9141, -10071, -1919, -4693, -13586, -10075, -8138, -10767, 0, 10767, 8138, 10075, 13586, 4693, 1919, 10071, 9141, 7774, 14653, 9888, -1533, -861, -1820, -7149, 1344, 10447, 6879, 8648, 12724, 5019, 3879, 13887, 14791, 14987, 22936, 18574, 6776, 6259, 3342, -4592, 831, 6631, -215, -1447, 139, -9361, -11483, -1599, 0, 1599, 11483, 9361, -139, 1447, 215, -6631, -831, 4592, -3342, -6259, -6776, -18574, -22936, -14987, -14791, -13887, -3879, -5019, -12724, -8648, -6879, -10447, -1344, 7149, 1820, 861, 1533, -9888, -14653, -7774, -9141, -10071, -1919, -4693, -13586, -10075, -8138, -10767, 0, 10767, 8138, 10075, 13586, 4693, 1919, 10071, 9141, 7774, 14653, 9888, -1533, -861, -1820, -7149, 1344, 10447, 6879, 8648, 12724, 5019, 3879, 13887, 14791, 14987, 22936, 18574, 6776, 6259, 3342, -4592, 831, 6631, -215, -1447, 139, -9361, -11483, -1599, 0, 1599, 11483, 9361, -139, 1447, 215, -6631, -831, 4592, -3342, -6259, -6776, -18574, -22936, -14987, -14791, -13887, -3879, -5019, -12724, -8648, -6879, -10447, -1344, 7149, 1820, 861, 1533, -9888, -14653, -7774, -9141, -10071, -1919, -4693, -13586, -10075, -8138, -10767, 0, 10767, 8138, 10075, 13586, 4693, 1919, 10071, 9141, 7774, 14653, 9888, -1533, -861, -1820, -7149, 1344, 10447, 6879, 8648, 12724, 5019, 3879, 13887, 14791, 14987, 22936, 18574, 6776, 6259, 3342, -4592, 831, 6631, -215, -1447, 139, -9361, -11483, -1599, 0, 1599, 11483, 9361, -139, 1447, 215, -6631, -831, 4592, -3342, -6259, -6776, -18574, -22936, -14987, -14791, -13887, -3879, -5019, -12724, -8648, -6879, -10447, -1344, 7149, 1820, 861, 1533, -9888, -14653, -7774, -9141, -10071, -1919, -4693, -13586, -10075, -8138, -10767, 0, 10767, 8138, 10075, 13586, 4693, 1919, 10071, 9141, 7774, 14653, 9888, -1533, -861, -1820, -7149, 1344, 10447, 6879, 8648, 12724, 5019, 3879, 13887, 14791, 14987, 22936, 18574, 6776, 6259, 3342, -4592, 831, 6631, -215, -1447, 139, -9361, -11483, -1599, 0, 1599, 11483, 9361, -139, 1447, 215, -6631, -831, 4592, -3342, -6259, -6776, -18574, -22936, -14987, -14791, -13887, -3879, -5019, -12724, -8648, -6879, -10447, -1344, 7149, 1820, 861, 1533, -9888, -14653, -7774, -9141, -10071, -1919, -4693, -13586, -10075, -8138, -10767, 0, 10767, 8138, 10075, 13586, 4693, 1919, 10071, 9141, 7774, 14653, 9888, -1533, -861, -1820, -7149, 1344, 10447, 6879, 8648, 12724, 5019, 3879, 13887, 14791, 14987, 22936, 18574, 6776, 6259, 3342, -4592, 831, 6631, -215, -1447, 139, -9361, -11483, -1599, 0, 1599, 11483, 9361, -139, 1447, 215, -6631, -831, 4592, -3342, -6259, -6776, -18574, -22936, -14987, -14791, -13887, -3879, -5019, -12724, -8648, -6879, -10447, -1344, 7149, 1820, 861, 1533, -9888, -14653, -7774, -9141, -10071, -1919, -4693, -13586, -10075, -8138, -10767, 0, 10767, 8138, 10075, 13586, 4693, 1919, 10071, 9141, 7774, 14653, 9888, -1533, -861, -1820, -7149, 1344, 10447, 6879, 8648, 12724, 5019, 3879, 13887, 14791, 14987, 22936, 18574, 6776, 6259, 3342, -4592, 831, 6631, -215, -1447, 139, -9361, -11483, -1599, 0, 1599, 11483, 9361, -139, 1447, 215, -6631, -831, 4592, -3342, -6259, -6776, -18574, -22936, -14987, -14791, -13887, -3879, -5019, -12724, -8648, -6879, -10447, -1344, 7149, 1820, 861, 1533, -9888, -14653, -7774, -9141, -10071, -1919, -4693, -13586, -10075, -8138, -10767, 0, 10767, 8138, 10075, 13586, 4693, 1919, 10071, 9141, 7774, 14653, 9888, -1533, -861, -1820, -7149, 1344, 10447, 6879, 8648, 12724, 5019, 3879, 13887, 14791, 14987, 22936, 18574, 6776, 6259, 3342, -4592, 831, 6631, -215, -1447, 139, -9361, -11483, -1599, 0, 1599, 11483, 9361, -139, 1447, 215, -6631, -831, 4592, -3342, -6259, -6776, -18574, -22936, -14987, -14791, -13887, -3879, -5019, -12724, -8648, -6879, -10447, -1344, 7149, 1820, 861, 1533, -9888, -14653, -7774, -9141, -10071, -1919, -4693, -13586, -10075, -8138, -10767, 0, 10767, 8138, 10075, 13586, 4693, 1919, 10071, 9141, 7774, 14653, 9888, -1533, -861, -1820, -7149, 1344, 10447, 6879, 8648, 12724, 5019, 3879, 13887, 14791, 14987, 22936, 18574, 6776, 6259, 3342, -4592, 831, 6631, -215, -1447, 139, -9361, -11483, -1599, 0, 1599, 11483, 9361, -139, 1447, 215, -6631, -831, 4592, -3342, -6259, -6776, -18574, -22936, -14987, -14791, -13887, -3879, -5019, -12724, -8648, -6879, -10447, -1344, 7149, 1820, 861, 1533, -9888, -14653, -7774, -9141, -10071, -1919, -4693, -13586, -10075, -8138, -10767, 0, 10767, 8138, 10075, 13586, 4693, 1919, 10071, 9141, 7774, 14653, 9888, -1533, -861, -1820, -7149, 1344, 10447, 6879, 8648, 12724, 5019, 3879, 13887, 14791, 14987, 22936, 18574, 6776, 6259, 3342, -4592, 831, 6631, -215, -1447, 139, -9361, -11483, -1599, 0, 1599, 11483, 9361, -139, 1447, 215, -6631, -831, 4592, -3342, -6259, -6776, -18574, -22936, -14987, -14791, -13887, -3879, -5019, -12724, -8648, -6879, -10447, -1344, 7149, 1820, 861, 1533, -9888, -14653, -7774, -9141, -10071, -1919, -4693, -13586, -10075, -8138, -10767, 0, 10767, 8138, 10075, 13586, 4693, 1919, 10071, 9141, 7774, 14653, 9888, -1533, -861, -1820, -7149, 1344, 10447, 6879, 8648, 12724, 5019, 3879, 13887, 14791, 14987, 22936, 18574, 6776, 6259, 3342, -4592, 831, 6631, -215, -1447, 139, -9361, -11483, -1599, 0, 1599, 11483, 9361, -139, 1447, 215, -6631, -831, 4592, -3342, -6259, -6776, -18574, -22936, -14987, -14791, -13887, -3879, -5019, -12724, -8648, -6879, -10447, -1344, 7149, 1820, 861, 1533, -9888, -14653, -7774, -9141, -10071, -1919, -4693, -13586, -10075, -8138, -10767, 0, 10767, 8138, 10075, 13586, 4693, 1919, 10071, 9141, 7774, 14653, 9888, -1533, -861, -1820, -7149, 1344, 10447, 6879, 8648, 12724, 5019, 3879, 13887, 14791, 14987, 22936, 18574, 6776, 6259, 3342, -4592, 831, 6631, -215, -1447, 139, -9361, -11483, -1599, 0, 1599, 11483, 9361, -139, 1447, 215, -6631, -831, 4592, -3342, -6259, -6776, -18574, -22936, -14987, -14791, -13887, -3879, -5019, -12724, -8648, -6879, -10447, -1344, 7149, 1820, 861, 1533, -9888, -14653, -7774, -9141, -10071, -1919, -4693, -13586, -10075, -8138, -10767, 0, 10767, 8138, 10075, 13586, 4693, 1919, 10071, 9141, 7774, 14653, 9888, -1533, -861, -1820, -7149, 1344, 10447, 6879, 8648, 12724, 5019, 3879, 13887, 14791, 14987, 22936, 18574, 6776, 6259, 3342, -4592, 831, 6631, -215, -1447, 139, -9361, -11483, -1599, 0, 1599, 11483, 9361, -139, 1447, 215, -6631, -831, 4592, -3342, -6259, -6776, -18574, -22936, -14987, -14791, -13887, -3879, -5019, -12724, -8648, -6879, -10447, -1344, 7149, 1820, 861, 1533, -9888, -14653, -7774, -9141, -10071, -1919, -4693, -13586, -10075, -8138, -10767, 0, 10767, 8138, 10075, 13586, 4693, 1919, 10071, 9141, 7774, 14653, 9888, -1533, -861, -1820, -7149, 1344, 10447, 6879, 8648, 12724, 5019, 3879, 13887, 14791, 14987, 22936, 18574, 6776, 6259, 3342, -4592, 831, 6631, -215, -1447, 139, -9361, -11483, -1599, 0, 1599, 11483, 9361, -139, 1447, 215, -6631, -831, 4592, -3342, -6259, -6776, -18574, -22936, -14987, -14791, -13887, -3879, -5019, -12724, -8648, -6879, -10447, -1344, 7149, 1820, 861, 1533, -9888, -14653, -7774, -9141, -10071, -1919, -4693, -13586, -10075, -8138, -10767, 0, 10767, 8138, 10075, 13586, 4693, 1919, 10071, 9141, 7774, 14653, 9888, -1533, -861, -1820, -7149, 1344, 10447, 6879, 8648, 12724, 5019, 3879, 13887, 14791, 14987, 22936, 18574, 6776, 6259, 3342, -4592, 831, 6631, -215, -1447, 139, -9361, -11483, -1599, 0, 1599, 11483, 9361, -139, 1447, 215, -6631, -831, 4592, -3342, -6259, -6776, -18574, -22936, -14987, -14791, -13887, -3879, -5019, -12724, -8648, -6879, -10447, -1344, 7149, 1820, 861, 1533, -9888, -14653, -7774, -9141, -10071, -1919, -4693, -13586, -10075, -8138, -10767, 0, 10767, 8138, 10075, 13586, 4693, 1919, 10071, 9141, 7774, 14653, 9888, -1533, -861, -1820, -7149, 1344, 10447, 6879, 8648, 12724, 5019, 3879, 13887, 14791, 14987, 22936, 18574, 6776, 6259, 3342, -4592, 831, 6631, -215, -1447, 139, -9361, -11483, -1599, 0, 1599, 11483, 9361, -139, 1447, 215, -6631, -831, 4592, -3342, -6259, -6776, -18574, -22936, -14987, -14791, -13887, -3879, -5019, -12724, -8648, -6879, -10447, -1344, 7149, 1820, 861, 1533, -9888, -14653, -7774, -9141, -10071, -1919, -4693, -13586, -10075, -8138, -10767, 0, 10767, 8138, 10075, 13586, 4693, 1919, 10071, 9141, 7774, 14653, 9888, -1533, -861, -1820, -7149, 1344, 10447, 6879, 8648, 12724, 5019, 3879, 13887, 14791, 14987, 22936, 18574, 6776, 6259, 3342, -4592, 831, 6631, -215, -1447, 139, -9361, -11483, -1599, 0, 1599, 11483, 9361, -139, 1447, 215, -6631, -831, 4592, -3342, -6259, -6776, -18574, -22936, -14987, -14791, -13887, -3879, -5019, -12724, -8648, -6879, -10447, -1344, 7149, 1820, 861, 1533, -9888, -14653, -7774, -9141, -10071, -1919, -4693, -13586, -10075, -8138, -10767, 0, 10767, 8138, 10075, 13586, 4693, 1919, 10071, 9141, 7774, 14653, 9888, -1533, -861, -1820, -7149, 1344, 10447, 6879, 8648, 12724, 5019, 3879, 13887, 14791, 14987, 22936, 18574, 6776, 6259, 3342, -4592, 831, 6631, -215, -1447, 139, -9361, -11483, -1599, 0, 1599, 11483, 9361, -139, 1447, 215, -6631, -831, 4592, -3342, -6259, -6776, -18574, -22936, -14987, -14791, -13887, -3879, -5019, -12724, -8648, -6879, -10447, -1344, 7149, 1820, 861, 1533, -9888, -14653, -7774, -9141, -10071, -1919, -4693, -13586, -10075, -8138, -10767, 0, 10767, 8138, 10075, 13586, 4693, 1919, 10071, 9141, 7774, 14653, 9888, -1533, -861, -1820, -7149, 1344, 10447, 6879, 8648, 12724, 5019, 3879, 13887, 14791, 14987, 22936, 18574, 6776, 6259, 3342, -4592, 831, 6631, -215, -1447, 139, -9361, -11483, -1599, 0, 1599, 11483, 9361, -139, 1447, 215, -6631, -831, 4592, -3342, -6259, -6776, -18574, -22936, -14987, -14791, -13887, -3879, -5019, -12724, -8648, -6879, -10447, -1344, 7149, 1820, 861, 1533, -9888, -14653, -7774, -9141, -10071, -1919, -4693, -13586, -10075, -8138, -10767, 0, 10767, 8138, 10075, 13586, 4693, 1919, 10071, 9141, 7774, 14653, 9888, -1533, -861, -1820, -7149, 1344, 10447, 6879, 8648, 12724, 5019, 3879, 13887, 14791, 14987, 22936, 18574, 6776, 6259, 3342, -4592, 831, 6631, -215, -1447, 139, -9361, -11483, -1599, 0, 1599, 11483, 9361, -139, 1447, 215, -6631, -831, 4592, -3342, -6259, -6776, -18574, -22936, -14987, -14791, -13887, -3879, -5019, -12724, -8648, -6879, -10447, -1344, 7149, 1820, 861, 1533, -9888, -14653, -7774, -9141, -10071, -1919, -4693, -13586, -10075, -8138, -10767, 0, 10767, 8138, 10075, 13586, 4693, 1919, 10071, 9141, 7774, 14653, 9888, -1533, -861, -1820, -7149, 1344, 10447, 6879, 8648, 12724, 5019, 3879, 13887, 14791, 14987, 22936, 18574, 6776, 6259, 3342, -4592, 831, 6631, -215, -1447, 139, -9361, -11483, -1599, 0, 1599, 11483, 9361, -139, 1447, 215, -6631, -831, 4592, -3342, -6259, -6776, -18574, -22936, -14987, -14791, -13887, -3879, -5019, -12724, -8648, -6879, -10447, -1344, 7149, 1820, 861, 1533, -9888, -14653, -7774, -9141, -10071, -1919, -4693, -13586, -10075, -8138, -10767, 0, 10767, 8138, 10075, 13586, 4693, 1919, 10071, 9141, 7774, 14653, 9888, -1533, -861, -1820, -7149, 1344, 10447, 6879, 8648, 12724, 5019, 3879, 13887, 14791, 14987, 22936, 18574, 6776, 6259, 3342, -4592, 831, 6631, -215, -1447, 139, -9361, -11483, -1599, 0, 1599, 11483, 9361, -139, 1447, 215, -6631, -831, 4592, -3342, -6259, -6776, -18574, -22936, -14987, -14791, -13887, -3879, -5019, -12724, -8648, -6879, -10447, -1344, 7149, 1820, 861, 1533, -9888, -14653, -7774, -9141, -10071, -1919, -4693, -13586, -10075, -8138, -10767, 0, 10767, 8138, 10075, 13586, 4693, 1919, 10071, 9141, 7774, 14653, 9888, -1533, -861, -1820, -7149, 1344, 10447, 6879, 8648, 12724, 5019, 3879, 13887, 14791, 14987, 22936, 18574, 6776, 6259, 3342, -4592, 831, 6631, -215, -1447, 139, -9361, -11483, -1599, 0, 1599, 11483, 9361, -139, 1447, 215, -6631, -831, 4592, -3342, -6259, -6776, -18574, -22936, -14987, -14791, -13887, -3879, -5019, -12724, -8648, -6879, -10447, -1344, 7149, 1820, 861, 1533, -9888, -14653, -7774, -9141, -10071, -1919, -4693, -13586, -10075, -8138, -10767, 0, 10767, 8138, 10075, 13586, 4693, 1919, 10071, 9141, 7774, 14653, 9888, -1533, -861, -1820, -7149, 1344, 10447, 6879, 8648, 12724, 5019, 3879, 13887, 14791, 14987, 22936, 18574, 6776, 6259, 3342, -4592, 831, 6631, -215, -1447, 139, -9361, -11483, -1599, 0, 1599, 11483, 9361, -139, 1447, 215, -6631, -831, 4592, -3342, -6259, -6776, -18574, -22936, -14987, -14791, -13887, -3879, -5019, -12724, -8648, -6879, -10447, -1344, 7149, 1820, 861, 1533, -9888, -14653, -7774, -9141, -10071, -1919, -4693, -13586, -10075, -8138, -10767, 0, 10767, 8138, 10075, 13586, 4693, 1919, 10071, 9141, 7774, 14653, 9888, -1533, -861, -1820, -7149, 1344, 10447, 6879, 8648, 12724, 5019, 3879, 13887, 14791, 14987, 22936, 18574, 6776, 6259, 3342, -4592, 831, 6631, -215, -1447, 139, -9361, -11483, -1599, 0, 1599, 11483, 9361, -139, 1447, 215, -6631, -831, 4592, -3342, -6259, -6776, -18574, -22936, -14987, -14791, -13887, -3879, -5019, -12724, -8648, -6879, -10447, -1344, 7149, 1820, 861, 1533, -9888, -14653, -7774, -9141, -10071, -1919, -4693, -13586, -10075, -8138, -10767, 0, 10767, 8138, 10075, 13586, 4693, 1919, 10071, 9141, 7774, 14653, 9888, -1533, -861, -1820, -7149, 1344, 10447, 6879, 8648, 12724, 5019, 3879, 13887, 14791, 14987, 22936, 18574, 6776, 6259, 3342, -4592, 831, 6631, -215, -1447, 139, -9361, -11483, -1599, 0, 1599, 11483, 9361, -139, 1447, 215, -6631, -831, 4592, -3342, -6259, -6776, -18574, -22936, -14987, -14791, -13887, -3879, -5019, -12724, -8648, -6879, -10447, -1344, 7149, 1820, 861, 1533, -9888, -14653, -7774, -9141, -10071, -1919, -4693, -13586, -10075, -8138, -10767, 0, 10767, 8138, 10075, 13586, 4693, 1919, 10071, 9141, 7774, 14653, 9888, -1533, -861, -1820, -7149, 1344, 10447, 6879, 8648, 12724, 5019, 3879, 13887, 14791, 14987, 22936, 18574, 6776, 6259, 3342, -4592, 831, 6631, -215, -1447, 139, -9361, -11483, -1599, 0, 1599, 11483, 9361, -139, 1447, 215, -6631, -831, 4592, -3342, -6259, -6776, -18574, -22936, -14987, -14791, -13887, -3879, -5019, -12724, -8648, -6879, -10447, -1344, 7149, 1820, 861, 1533, -9888, -14653, -7774, -9141, -10071, -1919, -4693, -13586, -10075, -8138, -10767, 0, 10767, 8138, 10075, 13586, 4693, 1919, 10071, 9141, 7774, 14653, 9888, -1533, -861, -1820, -7149, 1344, 10447, 6879, 8648, 12724, 5019, 3879, 13887, 14791, 14987, 22936, 18574, 6776, 6259, 3342, -4592, 831, 6631, -215, -1447, 139, -9361, -11483, -1599, 0, 1599, 11483, 9361, -139, 1447, 215, -6631, -831, 4592, -3342, -6259, -6776, -18574, -22936, -14987, -14791, -13887, -3879, -5019, -12724, -8648, -6879, -10447, -1344, 7149, 1820, 861, 1533, -9888, -14653, -7774, -9141, -10071, -1919, -4693, -13586, -10075, -8138, -10767, 0, 10767, 8138, 10075, 13586, 4693, 1919, 10071, 9141, 7774, 14653, 9888, -1533, -861, -1820, -7149, 1344, 10447, 6879, 8648, 12724, 5019, 3879, 13887, 14791, 14987, 22936, 18574, 6776, 6259, 3342, -4592, 831, 6631, -215, -1447, 139, -9361, -11483, -1599, 0, 1599, 11483, 9361, -139, 1447, 215, -6631, -831, 4592, -3342, -6259, -6776, -18574, -22936, -14987, -14791, -13887, -3879, -5019, -12724, -8648, -6879, -10447, -1344, 7149, 1820, 861, 1533, -9888, -14653, -7774, -9141, -10071, -1919, -4693, -13586, -10075, -8138, -10767, 0, 10767, 8138, 10075, 13586, 4693, 1919, 10071, 9141, 7774, 14653, 9888, -1533, -861, -1820, -7149, 1344, 10447, 6879, 8648, 12724, 5019, 3879, 13887, 14791, 14987, 22936, 18574, 6776, 6259, 3342, -4592, 831, 6631, -215, -1447, 139, -9361, -11483, -1599, 0, 1599, 11483, 9361, -139, 1447, 215, -6631, -831, 4592, -3342, -6259, -6776, -18574, -22936, -14987, -14791, -13887, -3879, -5019, -12724, -8648, -6879, -10447, -1344, 7149, 1820, 861, 1533, -9888, -14653, -7774, -9141, -10071, -1919, -4693, -13586, -10075, -8138, -10767, 0, 10767, 8138, 10075, 13586, 4693, 1919, 10071, 9141, 7774, 14653, 9888, -1533, -861, -1820, -7149, 1344, 10447, 6879, 8648, 12724, 5019, 3879, 13887, 14791, 14987, 22936, 18574, 6776, 6259, 3342, -4592, 831, 6631, -215, -1447, 139, -9361, -11483, -1599, 0, 1599, 11483, 9361, -139, 1447, 215, -6631, -831, 4592, -3342, -6259, -6776, -18574, -22936, -14987, -14791, -13887, -3879, -5019, -12724, -8648, -6879, -10447, -1344, 7149, 1820, 861, 1533, -9888, -14653, -7774, -9141, -10071, -1919, -4693, -13586, -10075, -8138, -10767, 0, 10767, 8138, 10075, 13586, 4693, 1919, 10071, 9141, 7774, 14653, 9888, -1533, -861, -1820, -7149, 1344, 10447, 6879, 8648, 12724, 5019, 3879, 13887, 14791, 14987, 22936, 18574, 6776, 6259, 3342, -4592, 831, 6631, -215, -1447, 139, -9361, -11483, -1599, 0, 1599, 11483, 9361, -139, 1447, 215, -6631, -831, 4592, -3342, -6259, -6776, -18574, -22936, -14987, -14791, -13887, -3879, -5019, -12724, -8648, -6879, -10447, -1344, 7149, 1820, 861, 1533, -9888, -14653, -7774, -9141, -10071, -1919, -4693, -13586, -10075, -8138, -10767, 0, 10767, 8138, 10075, 13586, 4693, 1919, 10071, 9141, 7774, 14653, 9888, -1533, -861, -1820, -7149, 1344, 10447, 6879, 8648, 12724, 5019, 3879, 13887, 14791, 14987, 22936, 18574, 6776, 6259, 3342, -4592, 831, 6631, -215, -1447, 139, -9361, -11483, -1599, 0, 1599, 11483, 9361, -139, 1447, 215, -6631, -831, 4592, -3342, -6259, -6776, -18574, -22936, -14987, -14791, -13887, -3879, -5019, -12724, -8648, -6879, -10447, -1344, 7149, 1820, 861, 1533, -9888, -14653, -7774, -9141, -10071, -1919, -4693, -13586, -10075, -8138, -10767, 0, 10767, 8138, 10075, 13586, 4693, 1919, 10071, 9141, 7774, 14653, 9888, -1533, -861, -1820, -7149, 1344, 10447, 6879, 8648, 12724, 5019, 3879, 13887, 14791, 14987, 22936, 18574, 6776, 6259, 3342, -4592, 831, 6631, -215, -1447, 139, -9361, -11483, -1599, 0, 1599, 11483, 9361, -139, 1447, 215, -6631, -831, 4592, -3342, -6259, -6776, -18574, -22936, -14987, -14791, -13887, -3879, -5019, -12724, -8648, -6879, -10447, -1344, 7149, 1820, 861, 1533, -9888, -14653, -7774, -9141, -10071, -1919, -4693, -13586, -10075, -8138, -10767, 0, 10767, 8138, 10075, 13586, 4693, 1919, 10071, 9141, 7774, 14653, 9888, -1533, -861, -1820, -7149, 1344, 10447, 6879, 8648, 12724, 5019, 3879, 13887, 14791, 14987, 22936, 18574, 6776, 6259, 3342, -4592, 831, 6631, -215, -1447, 139, -9361, -11483, -1599, 0, 1599, 11483, 9361, -139, 1447, 215, -6631, -831, 4592, -3342, -6259, -6776, -18574, -22936, -14987, -14791, -13887, -3879, -5019, -12724, -8648, -6879, -10447, -1344, 7149, 1820, 861, 1533, -9888, -14653, -7774, -9141, -10071, -1919, -4693, -13586, -10075, -8138, -10767, 0, 10767, 8138, 10075, 13586, 4693, 1919, 10071, 9141, 7774, 14653, 9888, -1533, -861, -1820, -7149, 1344, 10447, 6879, 8648, 12724, 5019, 3879, 13887, 14791, 14987, 22936, 18574, 6776, 6259, 3342, -4592, 831, 6631, -215, -1447, 139, -9361, -11483, -1599, 0, 1599, 11483, 9361, -139, 1447, 215, -6631, -831, 4592, -3342, -6259, -6776, -18574, -22936, -14987, -14791, -13887, -3879, -5019, -12724, -8648, -6879, -10447, -1344, 7149, 1820, 861, 1533, -9888, -14653, -7774, -9141, -10071, -1919, -4693, -13586, -10075, -8138, -10767, 0, 10767, 8138, 10075, 13586, 4693, 1919, 10071, 9141, 7774, 14653, 9888, -1533, -861, -1820, -7149, 1344, 10447, 6879, 8648, 12724, 5019, 3879, 13887, 14791, 14987, 22936, 18574, 6776, 6259, 3342, -4592, 831, 6631, -215, -1447, 139, -9361, -11483, -1599, 0, 1599, 11483, 9361, -139, 1447, 215, -6631, -831, 4592, -3342, -6259, -6776, -18574, -22936, -14987, -14791, -13887, -3879, -5019, -12724, -8648, -6879, -10447, -1344, 7149, 1820, 861, 1533, -9888, -14653, -7774, -9141, -10071, -1919, -4693, -13586, -10075, -8138, -10767, 0, 10767, 8138, 10075, 13586, 4693, 1919, 10071, 9141, 7774, 14653, 9888, -1533, -861, -1820, -7149, 1344, 10447, 6879, 8648, 12724, 5019, 3879, 13887, 14791, 14987, 22936, 18574, 6776, 6259, 3342, -4592, 831, 6631, -215, -1447, 139, -9361, -11483, -1599, 0, 1599, 11483, 9361, -139, 1447, 215, -6631, -831, 4592, -3342, -6259, -6776, -18574, -22936, -14987, -14791, -13887, -3879, -5019, -12724, -8648, -6879, -10447, -1344, 7149, 1820, 861, 1533, -9888, -14653, -7774, -9141, -10071, -1919, -4693, -13586, -10075, -8138, -10767, 0, 10767, 8138, 10075, 13586, 4693, 1919, 10071, 9141, 7774, 14653, 9888, -1533, -861, -1820, -7149, 1344, 10447, 6879, 8648, 12724, 5019, 3879, 13887, 14791, 14987, 22936, 18574, 6776, 6259, 3342, -4592, 831, 6631, -215, -1447, 139, -9361, -11483, -1599, 0, 1599, 11483, 9361, -139, 1447, 215, -6631, -831, 4592, -3342, -6259, -6776, -18574, -22936, -14987, -14791, -13887, -3879, -5019, -12724, -8648, -6879, -10447, -1344, 7149, 1820, 861, 1533, -9888, -14653, -7774, -9141, -10071, -1919, -4693, -13586, -10075, -8138, -10767, 0, 10767, 8138, 10075, 13586, 4693, 1919, 10071, 9141, 7774, 14653, 9888, -1533, -861, -1820, -7149, 1344, 10447, 6879, 8648, 12724, 5019, 3879, 13887, 14791, 14987, 22936, 18574, 6776, 6259, 3342, -4592, 831, 6631, -215, -1447, 139, -9361, -11483, -1599, 0, 1599, 11483, 9361, -139, 1447, 215, -6631, -831, 4592, -3342, -6259, -6776, -18574, -22936, -14987, -14791, -13887, -3879, -5019, -12724, -8648, -6879, -10447, -1344, 7149, 1820, 861, 1533, -9888, -14653, -7774, -9141, -10071, -1919, -4693, -13586, -10075, -8138, -10767, 0, 10767, 8138, 10075, 13586, 4693, 1919, 10071, 9141, 7774, 14653, 9888, -1533, -861, -1820, -7149, 1344, 10447, 6879, 8648, 12724, 5019, 3879, 13887, 14791, 14987, 22936, 18574, 6776, 6259, 3342, -4592, 831, 6631, -215, -1447, 139, -9361, -11483, -1599, 0, 1599, 11483, 9361, -139, 1447, 215, -6631, -831, 4592, -3342, -6259, -6776, -18574, -22936, -14987, -14791, -13887, -3879, -5019, -12724, -8648, -6879, -10447, -1344, 7149, 1820, 861, 1533, -9888, -14653, -7774, -9141, -10071, -1919, -4693, -13586, -10075, -8138, -10767, 0, 10767, 8138, 10075, 13586, 4693, 1919, 10071, 9141, 7774, 14653, 9888, -1533, -861, -1820, -7149, 1344, 10447, 6879, 8648, 12724, 5019, 3879, 13887, 14791, 14987, 22936, 18574, 6776, 6259, 3342, -4592, 831, 6631, -215, -1447, 139, -9361, -11483, -1599, 0, 1599, 11483, 9361, -139, 1447, 215, -6631, -831, 4592, -3342, -6259, -6776, -18574, -22936, -14987, -14791, -13887, -3879, -5019, -12724, -8648, -6879, -10447, -1344, 7149, 1820, 861, 1533, -9888, -14653, -7774, -9141, -10071, -1919, -4693, -13586, -10075, -8138, -10767, 0, 10767, 8138, 10075, 13586, 4693, 1919, 10071, 9141, 7774, 14653, 9888, -1533, -861, -1820, -7149, 1344, 10447, 6879, 8648, 12724, 5019, 3879, 13887, 14791, 14987, 22936, 18574, 6776, 6259, 3342, -4592, 831, 6631, -215, -1447, 139, -9361, -11483, -1599, 0, 1599, 11483, 9361, -139, 1447, 215, -6631, -831, 4592, -3342, -6259, -6776, -18574, -22936, -14987, -14791, -13887, -3879, -5019, -12724, -8648, -6879, -10447, -1344, 7149, 1820, 861, 1533, -9888, -14653, -7774, -9141, -10071, -1919, -4693, -13586, -10075, -8138, -10767, 0, 10767, 8138, 10075, 13586, 4693, 1919, 10071, 9141, 7774, 14653, 9888, -1533, -861, -1820, -7149, 1344, 10447, 6879, 8648, 12724, 5019, 3879, 13887, 14791, 14987, 22936, 18574, 6776, 6259, 3342, -4592, 831, 6631, -215, -1447, 139, -9361, -11483, -1599, 0, 1599, 11483, 9361, -139, 1447, 215, -6631, -831, 4592, -3342, -6259, -6776, -18574, -22936, -14987, -14791, -13887, -3879, -5019, -12724, -8648, -6879, -10447, -1344, 7149, 1820, 861, 1533, -9888, -14653, -7774, -9141, -10071, -1919, -4693, -13586, -10075, -8138, -10767, 0, 10767, 8138, 10075, 13586, 4693, 1919, 10071, 9141, 7774, 14653, 9888, -1533, -861, -1820, -7149, 1344, 10447, 6879, 8648, 12724, 5019, 3879, 13887, 14791, 14987, 22936, 18574, 6776, 6259, 3342, -4592, 831, 6631, -215, -1447, 139, -9361, -11483, -1599, 0, 1599, 11483, 9361, -139, 1447, 215, -6631, -831, 4592, -3342, -6259, -6776, -18574, -22936, -14987, -14791, -13887, -3879, -5019, -12724, -8648, -6879, -10447, -1344, 7149, 1820, 861, 1533, -9888, -14653, -7774, -9141, -10071, -1919, -4693, -13586, -10075, -8138, -10767, 0, 10767, 8138, 10075, 13586, 4693, 1919, 10071, 9141, 7774, 14653, 9888, -1533, -861, -1820, -7149, 1344, 10447, 6879, 8648, 12724, 5019, 3879, 13887, 14791, 14987, 22936, 18574, 6776, 6259, 3342, -4592, 831, 6631, -215, -1447, 139, -9361, -11483, -1599, 0, 1599, 11483, 9361, -139, 1447, 215, -6631, -831, 4592, -3342, -6259, -6776, -18574, -22936, -14987, -14791, -13887, -3879, -5019, -12724, -8648, -6879, -10447, -1344, 7149, 1820, 861, 1533, -9888, -14653, -7774, -9141, -10071, -1919, -4693, -13586, -10075, -8138, -10767, 0, 10767, 8138, 10075, 13586, 4693, 1919, 10071, 9141, 7774, 14653, 9888, -1533, -861, -1820, -7149, 1344, 10447, 6879, 8648, 12724, 5019, 3879, 13887, 14791, 14987, 22936, 18574, 6776, 6259, 3342, -4592, 831, 6631, -215, -1447, 139, -9361, -11483, -1599, 0, 1599, 11483, 9361, -139, 1447, 215, -6631, -831, 4592, -3342, -6259, -6776, -18574, -22936, -14987, -14791, -13887, -3879, -5019, -12724, -8648, -6879, -10447, -1344, 7149, 1820, 861, 1533, -9888, -14653, -7774, -9141, -10071, -1919, -4693, -13586, -10075, -8138, -10767, 0, 10767, 8138, 10075, 13586, 4693, 1919, 10071, 9141, 7774, 14653, 9888, -1533, -861, -1820, -7149, 1344, 10447, 6879, 8648, 12724, 5019, 3879, 13887, 14791, 14987, 22936, 18574, 6776, 6259, 3342, -4592, 831, 6631, -215, -1447, 139, -9361, -11483, -1599, 0, 1599, 11483, 9361, -139, 1447, 215, -6631, -831, 4592, -3342, -6259, -6776, -18574, -22936, -14987, -14791, -13887, -3879, -5019, -12724, -8648, -6879, -10447, -1344, 7149, 1820, 861, 1533, -9888, -14653, -7774, -9141, -10071, -1919, -4693, -13586, -10075, -8138, -10767, 0, 10767, 8138, 10075, 13586, 4693, 1919, 10071, 9141, 7774, 14653, 9888, -1533, -861, -1820, -7149, 1344, 10447, 6879, 8648, 12724, 5019, 3879, 13887, 14791, 14987, 22936, 18574, 6776, 6259, 3342, -4592, 831, 6631, -215, -1447, 139, -9361, -11483, -1599, 0, 1599, 11483, 9361, -139, 1447, 215, -6631, -831, 4592, -3342, -6259, -6776, -18574, -22936, -14987, -14791, -13887, -3879, -5019, -12724, -8648, -6879, -10447, -1344, 7149, 1820, 861, 1533, -9888, -14653, -7774, -9141, -10071, -1919, -4693, -13586, -10075, -8138, -10767, 0, 10767, 8138, 10075, 13586, 4693, 1919, 10071, 9141, 7774, 14653, 9888, -1533, -861, -1820, -7149, 1344, 10447, 6879, 8648, 12724, 5019, 3879, 13887, 14791, 14987, 22936, 18574, 6776, 6259, 3342, -4592, 831, 6631, -215, -1447, 139, -9361, -11483, -1599, 0, 1599, 11483, 9361, -139, 1447, 215, -6631, -831, 4592, -3342, -6259, -6776, -18574, -22936, -14987, -14791, -13887, -3879, -5019, -12724, -8648, -6879, -10447, -1344, 7149, 1820, 861, 1533, -9888, -14653, -7774, -9141, -10071, -1919, -4693, -13586, -10075, -8138, -10767, 0, 10767, 8138, 10075, 13586, 4693, 1919, 10071, 9141, 7774, 14653, 9888, -1533, -861, -1820, -7149, 1344, 10447, 6879, 8648, 12724, 5019, 3879, 13887, 14791, 14987, 22936, 18574, 6776, 6259, 3342, -4592, 831, 6631, -215, -1447, 139, -9361, -11483, -1599, 0, 1599, 11483, 9361, -139, 1447, 215, -6631, -831, 4592, -3342, -6259, -6776, -18574, -22936, -14987, -14791, -13887, -3879, -5019, -12724, -8648, -6879, -10447, -1344, 7149, 1820, 861, 1533, -9888, -14653, -7774, -9141, -10071, -1919, -4693, -13586, -10075, -8138, -10767, 0, 10767, 8138, 10075, 13586, 4693, 1919, 10071, 9141, 7774, 14653, 9888, -1533, -861, -1820, -7149, 1344, 10447, 6879, 8648, 12724, 5019, 3879, 13887, 14791, 14987, 22936, 18574, 6776, 6259, 3342, -4592, 831, 6631, -215, -1447, 139, -9361, -11483, -1599, 0, 1599, 11483, 9361, -139, 1447, 215, -6631, -831, 4592, -3342, -6259, -6776, -18574, -22936, -14987, -14791, -13887, -3879, -5019, -12724, -8648, -6879, -10447, -1344, 7149, 1820, 861, 1533, -9888, -14653, -7774, -9141, -10071, -1919, -4693, -13586, -10075, -8138, -10767, 0, 10767, 8138, 10075, 13586, 4693, 1919, 10071, 9141, 7774, 14653, 9888, -1533, -861, -1820, -7149, 1344, 10447, 6879, 8648, 12724, 5019, 3879, 13887, 14791, 14987, 22936, 18574, 6776, 6259, 3342, -4592, 831, 6631, -215, -1447, 139, -9361, -11483, -1599, 0, 1599, 11483, 9361, -139, 1447, 215, -6631, -831, 4592, -3342, -6259, -6776, -18574, -22936, -14987, -14791, -13887, -3879, -5019, -12724, -8648, -6879, -10447, -1344, 7149, 1820, 861, 1533, -9888, -14653, -7774, -9141, -10071, -1919, -4693, -13586, -10075, -8138, -10767, 0, 10767, 8138, 10075, 13586, 4693, 1919, 10071, 9141, 7774, 14653, 9888, -1533, -861, -1820, -7149, 1344, 10447, 6879, 8648, 12724, 5019, 3879, 13887, 14791, 14987, 22936, 18574, 6776, 6259, 3342, -4592, 831, 6631, -215, -1447, 139, -9361, -11483, -1599, 0, 1599, 11483, 9361, -139, 1447, 215, -6631, -831, 4592, -3342, -6259, -6776, -18574, -22936, -14987, -14791, -13887, -3879, -5019, -12724, -8648, -6879, -10447, -1344, 7149, 1820, 861, 1533, -9888, -14653, -7774, -9141, -10071, -1919, -4693, -13586, -10075, -8138, -10767, 0, 10767, 8138, 10075, 13586, 4693, 1919, 10071, 9141, 7774, 14653, 9888, -1533, -861, -1820, -7149, 1344, 10447, 6879, 8648, 12724, 5019, 3879, 13887, 14791, 14987, 22936, 18574, 6776, 6259, 3342, -4592, 831, 6631, -215, -1447, 139, -9361, -11483, -1599, 0, 1599, 11483, 9361, -139, 1447, 215, -6631, -831, 4592, -3342, -6259, -6776, -18574, -22936, -14987, -14791, -13887, -3879, -5019, -12724, -8648, -6879, -10447, -1344, 7149, 1820, 861, 1533, -9888, -14653, -7774, -9141, -10071, -1919, -4693, -13586, -10075, -8138, -10767, 0, 10767, 8138, 10075, 13586, 4693, 1919, 10071, 9141, 7774, 14653, 9888, -1533, -861, -1820, -7149, 1344, 10447, 6879, 8648, 12724, 5019, 3879, 13887, 14791, 14987, 22936, 18574, 6776, 6259, 3342, -4592, 831, 6631, -215, -1447, 139, -9361, -11483, -1599, 0, 1599, 11483, 9361, -139, 1447, 215, -6631, -831, 4592, -3342, -6259, -6776, -18574, -22936, -14987, -14791, -13887, -3879, -5019, -12724, -8648, -6879, -10447, -1344, 7149, 1820, 861, 1533, -9888, -14653, -7774, -9141, -10071, -1919, -4693, -13586, -10075, -8138, -10767, 0, 10767, 8138, 10075, 13586, 4693, 1919, 10071, 9141, 7774, 14653, 9888, -1533, -861, -1820, -7149, 1344, 10447, 6879, 8648, 12724, 5019, 3879, 13887, 14791, 14987, 22936, 18574, 6776, 6259, 3342, -4592, 831, 6631, -215, -1447, 139, -9361, -11483, -1599, 0, 1599, 11483, 9361, -139, 1447, 215, -6631, -831, 4592, -3342, -6259, -6776, -18574, -22936, -14987, -14791, -13887, -3879, -5019, -12724, -8648, -6879, -10447, -1344, 7149, 1820, 861, 1533, -9888, -14653, -7774, -9141, -10071, -1919, -4693, -13586, -10075, -8138, -10767, 0, 10767, 8138, 10075, 13586, 4693, 1919, 10071, 9141, 7774, 14653, 9888, -1533, -861, -1820, -7149, 1344, 10447, 6879, 8648, 12724, 5019, 3879, 13887, 14791, 14987, 22936, 18574, 6776, 6259, 3342, -4592, 831, 6631, -215, -1447, 139, -9361, -11483, -1599, 0, 1599, 11483, 9361, -139, 1447, 215, -6631, -831, 4592, -3342, -6259, -6776, -18574, -22936, -14987, -14791, -13887, -3879, -5019, -12724, -8648, -6879, -10447, -1344, 7149, 1820, 861, 1533, -9888, -14653, -7774, -9141, -10071, -1919, -4693, -13586, -10075, -8138, -10767, 0, 10767, 8138, 10075, 13586, 4693, 1919, 10071, 9141, 7774, 14653, 9888, -1533, -861, -1820, -7149, 1344, 10447, 6879, 8648, 12724, 5019, 3879, 13887, 14791, 14987, 22936, 18574, 6776, 6259, 3342, -4592, 831, 6631, -215, -1447, 139, -9361, -11483, -1599, 0, 1599, 11483, 9361, -139, 1447, 215, -6631, -831, 4592, -3342, -6259, -6776, -18574, -22936, -14987, -14791, -13887, -3879, -5019, -12724, -8648, -6879, -10447, -1344, 7149, 1820, 861, 1533, -9888, -14653, -7774, -9141, -10071, -1919, -4693, -13586, -10075, -8138, -10767, 0, 10767, 8138, 10075, 13586, 4693, 1919, 10071, 9141, 7774, 14653, 9888, -1533, -861, -1820, -7149, 1344, 10447, 6879, 8648, 12724, 5019, 3879, 13887, 14791, 14987, 22936, 18574, 6776, 6259, 3342, -4592, 831, 6631, -215, -1447, 139, -9361, -11483, -1599, 0, 1599, 11483, 9361, -139, 1447, 215, -6631, -831, 4592, -3342, -6259, -6776, -18574, -22936, -14987, -14791, -13887, -3879, -5019, -12724, -8648, -6879, -10447, -1344, 7149, 1820, 861, 1533, -9888, -14653, -7774, -9141, -10071, -1919, -4693, -13586, -10075, -8138, -10767, 0, 10767, 8138, 10075, 13586, 4693, 1919, 10071, 9141, 7774, 14653, 9888, -1533, -861, -1820, -7149, 1344, 10447, 6879, 8648, 12724, 5019, 3879, 13887, 14791, 14987, 22936, 18574, 6776, 6259, 3342, -4592, 831, 6631, -215, -1447, 139, -9361, -11483, -1599, 0, 1599, 11483, 9361, -139, 1447, 215, -6631, -831, 4592, -3342, -6259, -6776, -18574, -22936, -14987, -14791, -13887, -3879, -5019, -12724, -8648, -6879, -10447, -1344, 7149, 1820, 861, 1533, -9888, -14653, -7774, -9141, -10071, -1919, -4693, -13586, -10075, -8138, -10767, 0, 10767, 8138, 10075, 13586, 4693, 1919, 10071, 9141, 7774, 14653, 9888, -1533, -861, -1820, -7149, 1344, 10447, 6879, 8648, 12724, 5019, 3879, 13887, 14791, 14987, 22936, 18574, 6776, 6259, 3342, -4592, 831, 6631, -215, -1447, 139, -9361, -11483, -1599, 0, 1599, 11483, 9361, -139, 1447, 215, -6631, -831, 4592, -3342, -6259, -6776, -18574, -22936, -14987, -14791, -13887, -3879, -5019, -12724, -8648, -6879, -10447, -1344, 7149, 1820, 861, 1533, -9888, -14653, -7774, -9141, -10071, -1919, -4693, -13586, -10075, -8138, -10767, 0, 10767, 8138, 10075, 13586, 4693, 1919, 10071, 9141, 7774, 14653, 9888, -1533, -861, -1820, -7149, 1344, 10447, 6879, 8648, 12724, 5019, 3879, 13887, 14791, 14987, 22936, 18574, 6776, 6259, 3342, -4592, 831, 6631, -215, -1447, 139, -9361, -11483, -1599, 0, 1599, 11483, 9361, -139, 1447, 215, -6631, -831, 4592, -3342, -6259, -6776, -18574, -22936, -14987, -14791, -13887, -3879, -5019, -12724, -8648, -6879, -10447, -1344, 7149, 1820, 861, 1533, -9888, -14653, -7774, -9141, -10071, -1919, -4693, -13586, -10075, -8138, -10767, 0, 10767, 8138, 10075, 13586, 4693, 1919, 10071, 9141, 7774, 14653, 9888, -1533, -861, -1820, -7149, 1344, 10447, 6879, 8648, 12724, 5019, 3879, 13887, 14791, 14987, 22936, 18574, 6776, 6259, 3342, -4592, 831, 6631, -215, -1447, 139, -9361, -11483, -1599, 0, 1599, 11483, 9361, -139, 1447, 215, -6631, -831, 4592, -3342, -6259, -6776, -18574, -22936, -14987, -14791, -13887, -3879, -5019, -12724, -8648, -6879, -10447, -1344, 7149, 1820, 861, 1533, -9888, -14653, -7774, -9141, -10071, -1919, -4693, -13586, -10075, -8138, -10767, 0, 10767, 8138, 10075, 13586, 4693, 1919, 10071, 9141, 7774, 14653, 9888, -1533, -861, -1820, -7149, 1344, 10447, 6879, 8648, 12724, 5019, 3879, 13887, 14791, 14987, 22936, 18574, 6776, 6259, 3342, -4592, 831, 6631, -215, -1447, 139, -9361, -11483, -1599, 0, 1599, 11483, 9361, -139, 1447, 215, -6631, -831, 4592, -3342, -6259, -6776, -18574, -22936, -14987, -14791, -13887, -3879, -5019, -12724, -8648, -6879, -10447, -1344, 7149, 1820, 861, 1533, -9888, -14653, -7774, -9141, -10071, -1919, -4693, -13586, -10075, -8138, -10767, 0, 10767, 8138, 10075, 13586, 4693, 1919, 10071, 9141, 7774, 14653, 9888, -1533, -861, -1820, -7149, 1344, 10447, 6879, 8648, 12724, 5019, 3879, 13887, 14791, 14987, 22936, 18574, 6776, 6259, 3342, -4592, 831, 6631, -215, -1447, 139, -9361, -11483, -1599, 0, 1599, 11483, 9361, -139, 1447, 215, -6631, -831, 4592, -3342, -6259, -6776, -18574, -22936, -14987, -14791, -13887, -3879, -5019, -12724, -8648, -6879, -10447, -1344, 7149, 1820, 861, 1533, -9888, -14653, -7774, -9141, -10071, -1919, -4693, -13586, -10075, -8138, -10767, 0, 10767, 8138, 10075, 13586, 4693, 1919, 10071, 9141, 7774, 14653, 9888, -1533, -861, -1820, -7149, 1344, 10447, 6879, 8648, 12724, 5019, 3879, 13887, 14791, 14987, 22936, 18574, 6776, 6259, 3342, -4592, 831, 6631, -215, -1447, 139, -9361, -11483, -1599, 0, 1599, 11483, 9361, -139, 1447, 215, -6631, -831, 4592, -3342, -6259, -6776, -18574, -22936, -14987, -14791, -13887, -3879, -5019, -12724, -8648, -6879, -10447, -1344, 7149, 1820, 861, 1533, -9888, -14653, -7774, -9141, -10071, -1919, -4693, -13586, -10075, -8138, -10767, 0, 10767, 8138, 10075, 13586, 4693, 1919, 10071, 9141, 7774, 14653, 9888, -1533, -861, -1820, -7149, 1344, 10447, 6879, 8648, 12724, 5019, 3879, 13887, 14791, 14987, 22936, 18574, 6776, 6259, 3342, -4592, 831, 6631, -215, -1447, 139, -9361, -11483, -1599, 0, 1599, 11483, 9361, -139, 1447, 215, -6631, -831, 4592, -3342, -6259, -6776, -18574, -22936, -14987, -14791, -13887, -3879, -5019, -12724, -8648, -6879, -10447, -1344, 7149, 1820, 861, 1533, -9888, -14653, -7774, -9141, -10071, -1919, -4693, -13586, -10075, -8138, -10767, 0, 10767, 8138, 10075, 13586, 4693, 1919, 10071, 9141, 7774, 14653, 9888, -1533, -861, -1820, -7149, 1344, 10447, 6879, 8648, 12724, 5019, 3879, 13887, 14791, 14987, 22936, 18574, 6776, 6259, 3342, -4592, 831, 6631, -215, -1447, 139, -9361, -11483, -1599, 0, 1599, 11483, 9361, -139, 1447, 215, -6631, -831, 4592, -3342, -6259, -6776, -18574, -22936, -14987, -14791, -13887, -3879, -5019, -12724, -8648, -6879, -10447, -1344, 7149, 1820, 861, 1533, -9888, -14653, -7774, -9141, -10071, -1919, -4693, -13586, -10075, -8138, -10767, 0, 10767, 8138, 10075, 13586, 4693, 1919, 10071, 9141, 7774, 14653, 9888, -1533, -861, -1820, -7149, 1344, 10447, 6879, 8648, 12724, 5019, 3879, 13887, 14791, 14987, 22936, 18574, 6776, 6259, 3342, -4592, 831, 6631, -215, -1447, 139, -9361, -11483, -1599, 0, 1599, 11483, 9361, -139, 1447, 215, -6631, -831, 4592, -3342, -6259, -6776, -18574, -22936, -14987, -14791, -13887, -3879, -5019, -12724, -8648, -6879, -10447, -1344, 7149, 1820, 861, 1533, -9888, -14653, -7774, -9141, -10071, -1919, -4693, -13586, -10075, -8138, -10767, 0, 10767, 8138, 10075, 13586, 4693, 1919, 10071, 9141, 7774, 14653, 9888, -1533, -861, -1820, -7149, 1344, 10447, 6879, 8648, 12724, 5019, 3879, 13887, 14791, 14987, 22936, 18574, 6776, 6259, 3342, -4592, 831, 6631, -215, -1447, 139, -9361, -11483, -1599, 0, 1599, 11483, 9361, -139, 1447, 215, -6631, -831, 4592, -3342, -6259, -6776, -18574, -22936, -14987, -14791, -13887, -3879, -5019, -12724, -8648, -6879, -10447, -1344, 7149, 1820, 861, 1533, -9888, -14653, -7774, -9141, -10071, -1919, -4693, -13586, -10075, -8138, -10767, 0, 10767, 8138, 10075, 13586, 4693, 1919, 10071, 9141, 7774, 14653, 9888, -1533, -861, -1820, -7149, 1344, 10447, 6879, 8648, 12724, 5019, 3879, 13887, 14791, 14987, 22936, 18574, 6776, 6259, 3342, -4592, 831, 6631, -215, -1447, 139, -9361, -11483, -1599, 0, 1599, 11483, 9361, -139, 1447, 215, -6631, -831, 4592, -3342, -6259, -6776, -18574, -22936, -14987, -14791, -13887, -3879, -5019, -12724, -8648, -6879, -10447, -1344, 7149, 1820, 861, 1533, -9888, -14653, -7774, -9141, -10071, -1919, -4693, -13586, -10075, -8138, -10767, 0, 10767, 8138, 10075, 13586, 4693, 1919, 10071, 9141, 7774, 14653, 9888, -1533, -861, -1820, -7149, 1344, 10447, 6879, 8648, 12724, 5019, 3879, 13887, 14791, 14987, 22936, 18574, 6776, 6259, 3342, -4592, 831, 6631, -215, -1447, 139, -9361, -11483, -1599, 0, 1599, 11483, 9361, -139, 1447, 215, -6631, -831, 4592, -3342, -6259, -6776, -18574, -22936, -14987, -14791, -13887, -3879, -5019, -12724, -8648, -6879, -10447, -1344, 7149, 1820, 861, 1533, -9888, -14653, -7774, -9141, -10071, -1919, -4693, -13586, -10075, -8138, -10767, 0, 10767, 8138, 10075, 13586, 4693, 1919, 10071, 9141, 7774, 14653, 9888, -1533, -861, -1820, -7149, 1344, 10447, 6879, 8648, 12724, 5019, 3879, 13887, 14791, 14987, 22936, 18574, 6776, 6259, 3342, -4592, 831, 6631, -215, -1447, 139, -9361, -11483, -1599, 0, 1599, 11483, 9361, -139, 1447, 215, -6631, -831, 4592, -3342, -6259, -6776, -18574, -22936, -14987, -14791, -13887, -3879, -5019, -12724, -8648, -6879, -10447, -1344, 7149, 1820, 861, 1533, -9888, -14653, -7774, -9141, -10071, -1919, -4693, -13586, -10075, -8138, -10767, 0, 10767, 8138, 10075, 13586, 4693, 1919, 10071, 9141, 7774, 14653, 9888, -1533, -861, -1820, -7149, 1344, 10447, 6879, 8648, 12724, 5019, 3879, 13887, 14791, 14987, 22936, 18574, 6776, 6259, 3342, -4592, 831, 6631, -215, -1447, 139, -9361, -11483, -1599, 0, 1599, 11483, 9361, -139, 1447, 215, -6631, -831, 4592, -3342, -6259, -6776, -18574, -22936, -14987, -14791, -13887, -3879, -5019, -12724, -8648, -6879, -10447, -1344, 7149, 1820, 861, 1533, -9888, -14653, -7774, -9141, -10071, -1919, -4693, -13586, -10075, -8138, -10767, 0, 10767, 8138, 10075, 13586, 4693, 1919, 10071, 9141, 7774, 14653, 9888, -1533, -861, -1820, -7149, 1344, 10447, 6879, 8648, 12724, 5019, 3879, 13887, 14791, 14987, 22936, 18574, 6776, 6259, 3342, -4592, 831, 6631, -215, -1447, 139, -9361, -11483, -1599, 0, 1599, 11483, 9361, -139, 1447, 215, -6631, -831, 4592, -3342, -6259, -6776, -18574, -22936, -14987, -14791, -13887, -3879, -5019, -12724, -8648, -6879, -10447, -1344, 7149, 1820, 861, 1533, -9888, -14653, -7774, -9141, -10071, -1919, -4693, -13586, -10075, -8138, -10767, 0, 10767, 8138, 10075, 13586, 4693, 1919, 10071, 9141, 7774, 14653, 9888, -1533, -861, -1820, -7149, 1344, 10447, 6879, 8648, 12724, 5019, 3879, 13887, 14791, 14987, 22936, 18574, 6776, 6259, 3342, -4592, 831, 6631, -215, -1447, 139, -9361, -11483, -1599, 0, 1599, 11483, 9361, -139, 1447, 215, -6631, -831, 4592, -3342, -6259, -6776, -18574, -22936, -14987, -14791, -13887, -3879, -5019, -12724, -8648, -6879, -10447, -1344, 7149, 1820, 861, 1533, -9888, -14653, -7774, -9141, -10071, -1919, -4693, -13586, -10075, -8138, -10767, 0, 10767, 8138, 10075, 13586, 4693, 1919, 10071, 9141, 7774, 14653, 9888, -1533, -861, -1820, -7149, 1344, 10447, 6879, 8648, 12724, 5019, 3879, 13887, 14791, 14987, 22936, 18574, 6776, 6259, 3342, -4592, 831, 6631, -215, -1447, 139, -9361, -11483, -1599, 0, 1599, 11483, 9361, -139, 1447, 215, -6631, -831, 4592, -3342, -6259, -6776, -18574, -22936, -14987, -14791, -13887, -3879, -5019, -12724, -8648, -6879, -10447, -1344, 7149, 1820, 861, 1533, -9888, -14653, -7774, -9141, -10071, -1919, -4693, -13586, -10075, -8138, -10767, 0, 10767, 8138, 10075, 13586, 4693, 1919, 10071, 9141, 7774, 14653, 9888, -1533, -861, -1820, -7149, 1344, 10447, 6879, 8648, 12724, 5019, 3879, 13887, 14791, 14987, 22936, 18574, 6776, 6259, 3342, -4592, 831, 6631, -215, -1447, 139, -9361, -11483, -1599, 0, 1599, 11483, 9361, -139, 1447, 215, -6631, -831, 4592, -3342, -6259, -6776, -18574, -22936, -14987, -14791, -13887, -3879, -5019, -12724, -8648, -6879, -10447, -1344, 7149, 1820, 861, 1533, -9888, -14653, -7774, -9141, -10071, -1919, -4693, -13586, -10075, -8138, -10767, 0, 10767, 8138, 10075, 13586, 4693, 1919, 10071, 9141, 7774, 14653, 9888, -1533, -861, -1820, -7149, 1344, 10447, 6879, 8648, 12724, 5019, 3879, 13887, 14791, 14987, 22936, 18574, 6776, 6259, 3342, -4592, 831, 6631, -215, -1447, 139, -9361, -11483, -1599, 0, 1599, 11483, 9361, -139, 1447, 215, -6631, -831, 4592, -3342, -6259, -6776, -18574, -22936, -14987, -14791, -13887, -3879, -5019, -12724, -8648, -6879, -10447, -1344, 7149, 1820, 861, 1533, -9888, -14653, -7774, -9141, -10071, -1919, -4693, -13586, -10075, -8138, -10767, 0, 10767, 8138, 10075, 13586, 4693, 1919, 10071, 9141, 7774, 14653, 9888, -1533, -861, -1820, -7149, 1344, 10447, 6879, 8648, 12724, 5019, 3879, 13887, 14791, 14987, 22936, 18574, 6776, 6259, 3342, -4592, 831, 6631, -215, -1447, 139, -9361, -11483, -1599, 0, 1599, 11483, 9361, -139, 1447, 215, -6631, -831, 4592, -3342, -6259, -6776, -18574, -22936, -14987, -14791, -13887, -3879, -5019, -12724, -8648, -6879, -10447, -1344, 7149, 1820, 861, 1533, -9888, -14653, -7774, -9141, -10071, -1919, -4693, -13586, -10075, -8138, -10767, 0, 10767, 8138, 10075, 13586, 4693, 1919, 10071, 9141, 7774, 14653, 9888, -1533, -861, -1820, -7149, 1344, 10447, 6879, 8648, 12724, 5019, 3879, 13887, 14791, 14987, 22936, 18574, 6776, 6259, 3342, -4592, 831, 6631, -215, -1447, 139, -9361, -11483, -1599, 0, 1599, 11483, 9361, -139, 1447, 215, -6631, -831, 4592, -3342, -6259, -6776, -18574, -22936, -14987, -14791, -13887, -3879, -5019, -12724, -8648, -6879, -10447, -1344, 7149, 1820, 861, 1533, -9888, -14653, -7774, -9141, -10071, -1919, -4693, -13586, -10075, -8138, -10767, 0, 10767, 8138, 10075, 13586, 4693, 1919, 10071, 9141, 7774, 14653, 9888, -1533, -861, -1820, -7149, 1344, 10447, 6879, 8648, 12724, 5019, 3879, 13887, 14791, 14987, 22936, 18574, 6776, 6259, 3342, -4592, 831, 6631, -215, -1447, 139, -9361, -11483, -1599, 0, 1599, 11483, 9361, -139, 1447, 215, -6631, -831, 4592, -3342, -6259, -6776, -18574, -22936, -14987, -14791, -13887, -3879, -5019, -12724, -8648, -6879, -10447, -1344, 7149, 1820, 861, 1533, -9888, -14653, -7774, -9141, -10071, -1919, -4693, -13586, -10075, -8138, -10767, 0, 10767, 8138, 10075, 13586, 4693, 1919, 10071, 9141, 7774, 14653, 9888, -1533, -861, -1820, -7149, 1344, 10447, 6879, 8648, 12724, 5019, 3879, 13887, 14791, 14987, 22936, 18574, 6776, 6259, 3342, -4592, 831, 6631, -215, -1447, 139, -9361, -11483, -1599, 0, 1599, 11483, 9361, -139, 1447, 215, -6631, -831, 4592, -3342, -6259, -6776, -18574, -22936, -14987, -14791, -13887, -3879, -5019, -12724, -8648, -6879, -10447, -1344, 7149, 1820, 861, 1533, -9888, -14653, -7774, -9141, -10071, -1919, -4693, -13586, -10075, -8138, -10767, 0, 10767, 8138, 10075, 13586, 4693, 1919, 10071, 9141, 7774, 14653, 9888, -1533, -861, -1820, -7149, 1344, 10447, 6879, 8648, 12724, 5019, 3879, 13887, 14791, 14987, 22936, 18574, 6776, 6259, 3342, -4592, 831, 6631, -215, -1447, 139, -9361, -11483, -1599, 0, 1599, 11483, 9361, -139, 1447, 215, -6631, -831, 4592, -3342, -6259, -6776, -18574, -22936, -14987, -14791, -13887, -3879, -5019, -12724, -8648, -6879, -10447, -1344, 7149, 1820, 861, 1533, -9888, -14653, -7774, -9141, -10071, -1919, -4693, -13586, -10075, -8138, -10767, 0, 10767, 8138, 10075, 13586, 4693, 1919, 10071, 9141, 7774, 14653, 9888, -1533, -861, -1820, -7149, 1344, 10447, 6879, 8648, 12724, 5019, 3879, 13887, 14791, 14987, 22936, 18574, 6776, 6259, 3342, -4592, 831, 6631, -215, -1447, 139, -9361, -11483, -1599, 0, 1599, 11483, 9361, -139, 1447, 215, -6631, -831, 4592, -3342, -6259, -6776, -18574, -22936, -14987, -14791, -13887, -3879, -5019, -12724, -8648, -6879, -10447, -1344, 7149, 1820, 861, 1533, -9888, -14653, -7774, -9141, -10071, -1919, -4693, -13586, -10075, -8138, -10767, 0, 10767, 8138, 10075, 13586, 4693, 1919, 10071, 9141, 7774, 14653, 9888, -1533, -861, -1820, -7149, 1344, 10447, 6879, 8648, 12724, 5019, 3879, 13887, 14791, 14987, 22936, 18574, 6776, 6259, 3342, -4592, 831, 6631, -215, -1447, 139, -9361, -11483, -1599, 0, 1599, 11483, 9361, -139, 1447, 215, -6631, -831, 4592, -3342, -6259, -6776, -18574, -22936, -14987, -14791, -13887, -3879, -5019, -12724, -8648, -6879, -10447, -1344, 7149, 1820, 861, 1533, -9888, -14653, -7774, -9141, -10071, -1919, -4693, -13586, -10075, -8138, -10767, 0, 10767, 8138, 10075, 13586, 4693, 1919, 10071, 9141, 7774, 14653, 9888, -1533, -861, -1820, -7149, 1344, 10447, 6879, 8648, 12724, 5019, 3879, 13887, 14791, 14987, 22936, 18574, 6776, 6259, 3342, -4592, 831, 6631, -215, -1447, 139, -9361, -11483, -1599, 0, 1599, 11483, 9361, -139, 1447, 215, -6631, -831, 4592, -3342, -6259, -6776, -18574, -22936, -14987, -14791, -13887, -3879, -5019, -12724, -8648, -6879, -10447, -1344, 7149, 1820, 861, 1533, -9888, -14653, -7774, -9141, -10071, -1919, -4693, -13586, -10075, -8138, -10767, 0, 10767, 8138, 10075, 13586, 4693, 1919, 10071, 9141, 7774, 14653, 9888, -1533, -861, -1820, -7149, 1344, 10447, 6879, 8648, 12724, 5019, 3879, 13887, 14791, 14987, 22936, 18574, 6776, 6259, 3342, -4592, 831, 6631, -215, -1447, 139, -9361, -11483, -1599, 0, 1599, 11483, 9361, -139, 1447, 215, -6631, -831, 4592, -3342, -6259, -6776, -18574, -22936, -14987, -14791, -13887, -3879, -5019, -12724, -8648, -6879, -10447, -1344, 7149, 1820, 861, 1533, -9888, -14653, -7774, -9141, -10071, -1919, -4693, -13586, -10075, -8138, -10767, 0, 10767, 8138, 10075, 13586, 4693, 1919, 10071, 9141, 7774, 14653, 9888, -1533, -861, -1820, -7149, 1344, 10447, 6879, 8648, 12724, 5019, 3879, 13887, 14791, 14987, 22936, 18574, 6776, 6259, 3342, -4592, 831, 6631, -215, -1447, 139, -9361, -11483, -1599, 0, 1599, 11483, 9361, -139, 1447, 215, -6631, -831, 4592, -3342, -6259, -6776, -18574, -22936, -14987, -14791, -13887, -3879, -5019, -12724, -8648, -6879, -10447, -1344, 7149, 1820, 861, 1533, -9888, -14653, -7774, -9141, -10071, -1919, -4693, -13586, -10075, -8138, -10767, 0, 10767, 8138, 10075, 13586, 4693, 1919, 10071, 9141, 7774, 14653, 9888, -1533, -861, -1820, -7149, 1344, 10447, 6879, 8648, 12724, 5019, 3879, 13887, 14791, 14987, 22936, 18574, 6776, 6259, 3342, -4592, 831, 6631, -215, -1447, 139, -9361, -11483, -1599, 0, 1599, 11483, 9361, -139, 1447, 215, -6631, -831, 4592, -3342, -6259, -6776, -18574, -22936, -14987, -14791, -13887, -3879, -5019, -12724, -8648, -6879, -10447, -1344, 7149, 1820, 861, 1533, -9888, -14653, -7774, -9141, -10071, -1919, -4693, -13586, -10075, -8138, -10767, 0, 10767, 8138, 10075, 13586, 4693, 1919, 10071, 9141, 7774, 14653, 9888, -1533, -861, -1820, -7149, 1344, 10447, 6879, 8648, 12724, 5019, 3879, 13887, 14791, 14987, 22936, 18574, 6776, 6259, 3342, -4592, 831, 6631, -215, -1447, 139, -9361, -11483, -1599, 0, 1599, 11483, 9361, -139, 1447, 215, -6631, -831, 4592, -3342, -6259, -6776, -18574, -22936, -14987, -14791, -13887, -3879, -5019, -12724, -8648, -6879, -10447, -1344, 7149, 1820, 861, 1533, -9888, -14653, -7774, -9141, -10071, -1919, -4693, -13586, -10075, -8138, -10767, 0, 10767, 8138, 10075, 13586, 4693, 1919, 10071, 9141, 7774, 14653, 9888, -1533, -861, -1820, -7149, 1344, 10447, 6879, 8648, 12724, 5019, 3879, 13887, 14791, 14987, 22936, 18574, 6776, 6259, 3342, -4592, 831, 6631, -215, -1447, 139, -9361, -11483, -1599, 0, 1599, 11483, 9361, -139, 1447, 215, -6631, -831, 4592, -3342, -6259, -6776, -18574, -22936, -14987, -14791, -13887, -3879, -5019, -12724, -8648, -6879, -10447, -1344, 7149, 1820, 861, 1533, -9888, -14653, -7774, -9141, -10071, -1919, -4693, -13586, -10075, -8138, -10767, 0, 10767, 8138, 10075, 13586, 4693, 1919, 10071, 9141, 7774, 14653, 9888, -1533, -861, -1820, -7149, 1344, 10447, 6879, 8648, 12724, 5019, 3879, 13887, 14791, 14987, 22936, 18574, 6776, 6259, 3342, -4592, 831, 6631, -215, -1447, 139, -9361, -11483, -1599, 0, 1599, 11483, 9361, -139, 1447, 215, -6631, -831, 4592, -3342, -6259, -6776, -18574, -22936, -14987, -14791, -13887, -3879, -5019, -12724, -8648, -6879, -10447, -1344, 7149, 1820, 861, 1533, -9888, -14653, -7774, -9141, -10071, -1919, -4693, -13586, -10075, -8138, -10767, 0, 10767, 8138, 10075, 13586, 4693, 1919, 10071, 9141, 7774, 14653, 9888, -1533, -861, -1820, -7149, 1344, 10447, 6879, 8648, 12724, 5019, 3879, 13887, 14791, 14987, 22936, 18574, 6776, 6259, 3342, -4592, 831, 6631, -215, -1447, 139, -9361, -11483, -1599, 0, 1599, 11483, 9361, -139, 1447, 215, -6631, -831, 4592, -3342, -6259, -6776, -18574, -22936, -14987, -14791, -13887, -3879, -5019, -12724, -8648, -6879, -10447, -1344, 7149, 1820, 861, 1533, -9888, -14653, -7774, -9141, -10071, -1919, -4693, -13586, -10075, -8138, -10767, 0, 10767, 8138, 10075, 13586, 4693, 1919, 10071, 9141, 7774, 14653, 9888, -1533, -861, -1820, -7149, 1344, 10447, 6879, 8648, 12724, 5019, 3879, 13887, 14791, 14987, 22936, 18574, 6776, 6259, 3342, -4592, 831, 6631, -215, -1447, 139, -9361, -11483, -1599, 0, 1599, 11483, 9361, -139, 1447, 215, -6631, -831, 4592, -3342, -6259, -6776, -18574, -22936, -14987, -14791, -13887, -3879, -5019, -12724, -8648, -6879, -10447, -1344, 7149, 1820, 861, 1533, -9888, -14653, -7774, -9141, -10071, -1919, -4693, -13586, -10075, -8138, -10767, 0, 10767, 8138, 10075, 13586, 4693, 1919, 10071, 9141, 7774, 14653, 9888, -1533, -861, -1820, -7149, 1344, 10447, 6879, 8648, 12724, 5019, 3879, 13887, 14791, 14987, 22936, 18574, 6776, 6259, 3342, -4592, 831, 6631, -215, -1447, 139, -9361, -11483, -1599, 0, 1599, 11483, 9361, -139, 1447, 215, -6631, -831, 4592, -3342, -6259, -6776, -18574, -22936, -14987, -14791, -13887, -3879, -5019, -12724, -8648, -6879, -10447, -1344, 7149, 1820, 861, 1533, -9888, -14653, -7774, -9141, -10071, -1919, -4693, -13586, -10075, -8138, -10767, 0, 10767, 8138, 10075, 13586, 4693, 1919, 10071, 9141, 7774, 14653, 9888, -1533, -861, -1820, -7149, 1344, 10447, 6879, 8648, 12724, 5019, 3879, 13887, 14791, 14987, 22936, 18574, 6776, 6259, 3342, -4592, 831, 6631, -215, -1447, 139, -9361, -11483, -1599, 0, 1599, 11483, 9361, -139, 1447, 215, -6631, -831, 4592, -3342, -6259, -6776, -18574, -22936, -14987, -14791, -13887, -3879, -5019, -12724, -8648, -6879, -10447, -1344, 7149, 1820, 861, 1533, -9888, -14653, -7774, -9141, -10071, -1919, -4693, -13586, -10075, -8138, -10767, 0, 10767, 8138, 10075, 13586, 4693, 1919, 10071, 9141, 7774, 14653, 9888, -1533, -861, -1820, -7149, 1344, 10447, 6879, 8648, 12724, 5019, 3879, 13887, 14791, 14987, 22936, 18574, 6776, 6259, 3342, -4592, 831, 6631, -215, -1447, 139, -9361, -11483, -1599, 0, 1599, 11483, 9361, -139, 1447, 215, -6631, -831, 4592, -3342, -6259, -6776, -18574, -22936, -14987, -14791, -13887, -3879, -5019, -12724, -8648, -6879, -10447, -1344, 7149, 1820, 861, 1533, -9888, -14653, -7774, -9141, -10071, -1919, -4693, -13586, -10075, -8138, -10767, 0, 10767, 8138, 10075, 13586, 4693, 1919, 10071, 9141, 7774, 14653, 9888, -1533, -861, -1820, -7149, 1344, 10447, 6879, 8648, 12724, 5019, 3879, 13887, 14791, 14987, 22936, 18574, 6776, 6259, 3342, -4592, 831, 6631, -215, -1447, 139, -9361, -11483, -1599, 0, 1599, 11483, 9361, -139, 1447, 215, -6631, -831, 4592, -3342, -6259, -6776, -18574, -22936, -14987, -14791, -13887, -3879, -5019, -12724, -8648, -6879, -10447, -1344, 7149, 1820, 861, 1533, -9888, -14653, -7774, -9141, -10071, -1919, -4693, -13586, -10075, -8138, -10767, 0, 10767, 8138, 10075, 13586, 4693, 1919, 10071, 9141, 7774, 14653, 9888, -1533, -861, -1820, -7149, 1344, 10447, 6879, 8648, 12724, 5019, 3879, 13887, 14791, 14987, 22936, 18574, 6776, 6259, 3342, -4592, 831, 6631, -215, -1447, 139, -9361, -11483, -1599, 0, 1599, 11483, 9361, -139, 1447, 215, -6631, -831, 4592, -3342, -6259, -6776, -18574, -22936, -14987, -14791, -13887, -3879, -5019, -12724, -8648, -6879, -10447, -1344, 7149, 1820, 861, 1533, -9888, -14653, -7774, -9141, -10071, -1919, -4693, -13586, -10075, -8138, -10767, 0, 10767, 8138, 10075, 13586, 4693, 1919, 10071, 9141, 7774, 14653, 9888, -1533, -861, -1820, -7149, 1344, 10447, 6879, 8648, 12724, 5019, 3879, 13887, 14791, 14987, 22936, 18574, 6776, 6259, 3342, -4592, 831, 6631, -215, -1447, 139, -9361, -11483, -1599, 0, 1599, 11483, 9361, -139, 1447, 215, -6631, -831, 4592, -3342, -6259, -6776, -18574, -22936, -14987, -14791, -13887, -3879, -5019, -12724, -8648, -6879, -10447, -1344, 7149, 1820, 861, 1533, -9888, -14653, -7774, -9141, -10071, -1919, -4693, -13586, -10075, -8138, -10767, 0, 10767, 8138, 10075, 13586, 4693, 1919, 10071, 9141, 7774, 14653, 9888, -1533, -861, -1820, -7149, 1344, 10447, 6879, 8648, 12724, 5019, 3879, 13887, 14791, 14987, 22936, 18574, 6776, 6259, 3342, -4592, 831, 6631, -215, -1447, 139, -9361, -11483, -1599, 0, 1599, 11483, 9361, -139, 1447, 215, -6631, -831, 4592, -3342, -6259, -6776, -18574, -22936, -14987, -14791, -13887, -3879, -5019, -12724, -8648, -6879, -10447, -1344, 7149, 1820, 861, 1533, -9888, -14653, -7774, -9141, -10071, -1919, -4693, -13586, -10075, -8138, -10767, 0, 10767, 8138, 10075, 13586, 4693, 1919, 10071, 9141, 7774, 14653, 9888, -1533, -861, -1820, -7149, 1344, 10447, 6879, 8648, 12724, 5019, 3879, 13887, 14791, 14987, 22936, 18574, 6776, 6259, 3342, -4592, 831, 6631, -215, -1447, 139, -9361, -11483, -1599, 0, 1599, 11483, 9361, -139, 1447, 215, -6631, -831, 4592, -3342, -6259, -6776, -18574, -22936, -14987, -14791, -13887, -3879, -5019, -12724, -8648, -6879, -10447, -1344, 7149, 1820, 861, 1533, -9888, -14653, -7774, -9141, -10071, -1919, -4693, -13586, -10075, -8138, -10767, 0, 10767, 8138, 10075, 13586, 4693, 1919, 10071, 9141, 7774, 14653, 9888, -1533, -861, -1820, -7149, 1344, 10447, 6879, 8648, 12724, 5019, 3879, 13887, 14791, 14987, 22936, 18574, 6776, 6259, 3342, -4592, 831, 6631, -215, -1447, 139, -9361, -11483, -1599, 0, 1599, 11483, 9361, -139, 1447, 215, -6631, -831, 4592, -3342, -6259, -6776, -18574, -22936, -14987, -14791, -13887, -3879, -5019, -12724, -8648, -6879, -10447, -1344, 7149, 1820, 861, 1533, -9888, -14653, -7774, -9141, -10071, -1919, -4693, -13586, -10075, -8138, -10767, 0, 10767, 8138, 10075, 13586, 4693, 1919, 10071, 9141, 7774, 14653, 9888, -1533, -861, -1820, -7149, 1344, 10447, 6879, 8648, 12724, 5019, 3879, 13887, 14791, 14987, 22936, 18574, 6776, 6259, 3342, -4592, 831, 6631, -215, -1447, 139, -9361, -11483, -1599, 0, 1599, 11483, 9361, -139, 1447, 215, -6631, -831, 4592, -3342, -6259, -6776, -18574, -22936, -14987, -14791, -13887, -3879, -5019, -12724, -8648, -6879, -10447, -1344, 7149, 1820, 861, 1533, -9888, -14653, -7774, -9141, -10071, -1919, -4693, -13586, -10075, -8138, -10767, 0, 10767, 8138, 10075, 13586, 4693, 1919, 10071, 9141, 7774, 14653, 9888, -1533, -861, -1820, -7149, 1344, 10447, 6879, 8648, 12724, 5019, 3879, 13887, 14791, 14987, 22936, 18574, 6776, 6259, 3342, -4592, 831, 6631, -215, -1447, 139, -9361, -11483, -1599, 0, 1599, 11483, 9361, -139, 1447, 215, -6631, -831, 4592, -3342, -6259, -6776, -18574, -22936, -14987, -14791, -13887, -3879, -5019, -12724, -8648, -6879, -10447, -1344, 7149, 1820, 861, 1533, -9888, -14653, -7774, -9141, -10071, -1919, -4693, -13586, -10075, -8138, -10767, 0, 10767, 8138, 10075, 13586, 4693, 1919, 10071, 9141, 7774, 14653, 9888, -1533, -861, -1820, -7149, 1344, 10447, 6879, 8648, 12724, 5019, 3879, 13887, 14791, 14987, 22936, 18574, 6776, 6259, 3342, -4592, 831, 6631, -215, -1447, 139, -9361, -11483, -1599, 0, 1599, 11483, 9361, -139, 1447, 215, -6631, -831, 4592, -3342, -6259, -6776, -18574, -22936, -14987, -14791, -13887, -3879, -5019, -12724, -8648, -6879, -10447, -1344, 7149, 1820, 861, 1533, -9888, -14653, -7774, -9141, -10071, -1919, -4693, -13586, -10075, -8138, -10767, 0, 10767, 8138, 10075, 13586, 4693, 1919, 10071, 9141, 7774, 14653, 9888, -1533, -861, -1820, -7149, 1344, 10447, 6879, 8648, 12724, 5019, 3879, 13887, 14791, 14987, 22936, 18574, 6776, 6259, 3342, -4592, 831, 6631, -215, -1447, 139, -9361, -11483, -1599, 0, 1599, 11483, 9361, -139, 1447, 215, -6631, -831, 4592, -3342, -6259, -6776, -18574, -22936, -14987, -14791, -13887, -3879, -5019, -12724, -8648, -6879, -10447, -1344, 7149, 1820, 861, 1533, -9888, -14653, -7774, -9141, -10071, -1919, -4693, -13586, -10075, -8138, -10767, 0, 10767, 8138, 10075, 13586, 4693, 1919, 10071, 9141, 7774, 14653, 9888, -1533, -861, -1820, -7149, 1344, 10447, 6879, 8648, 12724, 5019, 3879, 13887, 14791, 14987, 22936, 18574, 6776, 6259, 3342, -4592, 831, 6631, -215, -1447, 139, -9361, -11483, -1599, 0, 1599, 11483, 9361, -139, 1447, 215, -6631, -831, 4592, -3342, -6259, -6776, -18574, -22936, -14987, -14791, -13887, -3879, -5019, -12724, -8648, -6879, -10447, -1344, 7149, 1820, 861, 1533, -9888, -14653, -7774, -9141, -10071, -1919, -4693, -13586, -10075, -8138, -10767, 0, 10767, 8138, 10075, 13586, 4693, 1919, 10071, 9141, 7774, 14653, 9888, -1533, -861, -1820, -7149, 1344, 10447, 6879, 8648, 12724, 5019, 3879, 13887, 14791, 14987, 22936, 18574, 6776, 6259, 3342, -4592, 831, 6631, -215, -1447, 139, -9361, -11483, -1599, 0, 1599, 11483, 9361, -139, 1447, 215, -6631, -831, 4592, -3342, -6259, -6776, -18574, -22936, -14987, -14791, -13887, -3879, -5019, -12724, -8648, -6879, -10447, -1344, 7149, 1820, 861, 1533, -9888, -14653, -7774, -9141, -10071, -1919, -4693, -13586, -10075, -8138, -10767, 0, 10767, 8138, 10075, 13586, 4693, 1919, 10071, 9141, 7774, 14653, 9888, -1533, -861, -1820, -7149, 1344, 10447, 6879, 8648, 12724, 5019, 3879, 13887, 14791, 14987, 22936, 18574, 6776, 6259, 3342, -4592, 831, 6631, -215, -1447, 139, -9361, -11483, -1599, 0, 1599, 11483, 9361, -139, 1447, 215, -6631, -831, 4592, -3342, -6259, -6776, -18574, -22936, -14987, -14791, -13887, -3879, -5019, -12724, -8648, -6879, -10447, -1344, 7149, 1820, 861, 1533, -9888, -14653, -7774, -9141, -10071, -1919, -4693, -13586, -10075, -8138, -10767, 0, 10767, 8138, 10075, 13586, 4693, 1919, 10071, 9141, 7774, 14653, 9888, -1533, -861, -1820, -7149, 1344, 10447, 6879, 8648, 12724, 5019, 3879, 13887, 14791, 14987, 22936, 18574, 6776, 6259, 3342, -4592, 831, 6631, -215, -1447, 139, -9361, -11483, -1599, 0, 1599, 11483, 9361, -139, 1447, 215, -6631, -831, 4592, -3342, -6259, -6776, -18574, -22936, -14987, -14791, -13887, -3879, -5019, -12724, -8648, -6879, -10447, -1344, 7149, 1820, 861, 1533, -9888, -14653, -7774, -9141, -10071, -1919, -4693, -13586, -10075, -8138, -10767, 0, 10767, 8138, 10075, 13586, 4693, 1919, 10071, 9141, 7774, 14653, 9888, -1533, -861, -1820, -7149, 1344, 10447, 6879, 8648, 12724, 5019, 3879, 13887, 14791, 14987, 22936, 18574, 6776, 6259, 3342, -4592, 831, 6631, -215, -1447, 139, -9361, -11483, -1599, 0, 1599, 11483, 9361, -139, 1447, 215, -6631, -831, 4592, -3342, -6259, -6776, -18574, -22936, -14987, -14791, -13887, -3879, -5019, -12724, -8648, -6879, -10447, -1344, 7149, 1820, 861, 1533, -9888, -14653, -7774, -9141, -10071, -1919, -4693, -13586, -10075, -8138, -10767, 0, 10767, 8138, 10075, 13586, 4693, 1919, 10071, 9141, 7774, 14653, 9888, -1533, -861, -1820, -7149, 1344, 10447, 6879, 8648, 12724, 5019, 3879, 13887, 14791, 14987, 22936, 18574, 6776, 6259, 3342, -4592, 831, 6631, -215, -1447, 139, -9361, -11483, -1599, 0, 1599, 11483, 9361, -139, 1447, 215, -6631, -831, 4592, -3342, -6259, -6776, -18574, -22936, -14987, -14791, -13887, -3879, -5019, -12724, -8648, -6879, -10447, -1344, 7149, 1820, 861, 1533, -9888, -14653, -7774, -9141, -10071, -1919, -4693, -13586, -10075, -8138, -10767, 0, 10767, 8138, 10075, 13586, 4693, 1919, 10071, 9141, 7774, 14653, 9888, -1533, -861, -1820, -7149, 1344, 10447, 6879, 8648, 12724, 5019, 3879, 13887, 14791, 14987, 22936, 18574, 6776, 6259, 3342, -4592, 831, 6631, -215, -1447, 139, -9361, -11483, -1599, 0, 1599, 11483, 9361, -139, 1447, 215, -6631, -831, 4592, -3342, -6259, -6776, -18574, -22936, -14987, -14791, -13887, -3879, -5019, -12724, -8648, -6879, -10447, -1344, 7149, 1820, 861, 1533, -9888, -14653, -7774, -9141, -10071, -1919, -4693, -13586, -10075, -8138, -10767, 0, 10767, 8138, 10075, 13586, 4693, 1919, 10071, 9141, 7774, 14653, 9888, -1533, -861, -1820, -7149, 1344, 10447, 6879, 8648, 12724, 5019, 3879, 13887, 14791, 14987, 22936, 18574, 6776, 6259, 3342, -4592, 831, 6631, -215, -1447, 139, -9361, -11483, -1599, 0, 1599, 11483, 9361, -139, 1447, 215, -6631, -831, 4592, -3342, -6259, -6776, -18574, -22936, -14987, -14791, -13887, -3879, -5019, -12724, -8648, -6879, -10447, -1344, 7149, 1820, 861, 1533, -9888, -14653, -7774, -9141, -10071, -1919, -4693, -13586, -10075, -8138, -10767, 0, 10767, 8138, 10075, 13586, 4693, 1919, 10071, 9141, 7774, 14653, 9888, -1533, -861, -1820, -7149, 1344, 10447, 6879, 8648, 12724, 5019, 3879, 13887, 14791, 14987, 22936, 18574, 6776, 6259, 3342, -4592, 831, 6631, -215, -1447, 139, -9361, -11483, -1599, 0, 1599, 11483, 9361, -139, 1447, 215, -6631, -831, 4592, -3342, -6259, -6776, -18574, -22936, -14987, -14791, -13887, -3879, -5019, -12724, -8648, -6879, -10447, -1344, 7149, 1820, 861, 1533, -9888, -14653, -7774, -9141, -10071, -1919, -4693, -13586, -10075, -8138, -10767, 0, 10767, 8138, 10075, 13586, 4693, 1919, 10071, 9141, 7774, 14653, 9888, -1533, -861, -1820, -7149, 1344, 10447, 6879, 8648, 12724, 5019, 3879, 13887, 14791, 14987, 22936, 18574, 6776, 6259, 3342, -4592, 831, 6631, -215, -1447, 139, -9361, -11483, -1599, 0, 1599, 11483, 9361, -139, 1447, 215, -6631, -831, 4592, -3342, -6259, -6776, -18574, -22936, -14987, -14791, -13887, -3879, -5019, -12724, -8648, -6879, -10447, -1344, 7149, 1820, 861, 1533, -9888, -14653, -7774, -9141, -10071, -1919, -4693, -13586, -10075, -8138, -10767, 0, 10767, 8138, 10075, 13586, 4693, 1919, 10071, 9141, 7774, 14653, 9888, -1533, -861, -1820, -7149, 1344, 10447, 6879, 8648, 12724, 5019, 3879, 13887, 14791, 14987, 22936, 18574, 6776, 6259, 3342, -4592, 831, 6631, -215, -1447, 139, -9361, -11483, -1599, 0, 1599, 11483, 9361, -139, 1447, 215, -6631, -831, 4592, -3342, -6259, -6776, -18574, -22936, -14987, -14791, -13887, -3879, -5019, -12724, -8648, -6879, -10447, -1344, 7149, 1820, 861, 1533, -9888, -14653, -7774, -9141, -10071, -1919, -4693, -13586, -10075, -8138, -10767, 0, 10767, 8138, 10075, 13586, 4693, 1919, 10071, 9141, 7774, 14653, 9888, -1533, -861, -1820, -7149, 1344, 10447, 6879, 8648, 12724, 5019, 3879, 13887, 14791, 14987, 22936, 18574, 6776, 6259, 3342, -4592, 831, 6631, -215, -1447, 139, -9361, -11483, -1599, 0, 1599, 11483, 9361, -139, 1447, 215, -6631, -831, 4592, -3342, -6259, -6776, -18574, -22936, -14987, -14791, -13887, -3879, -5019, -12724, -8648, -6879, -10447, -1344, 7149, 1820, 861, 1533, -9888, -14653, -7774, -9141, -10071, -1919, -4693, -13586, -10075, -8138, -10767, 0, 10767, 8138, 10075, 13586, 4693, 1919, 10071, 9141, 7774, 14653, 9888, -1533, -861, -1820, -7149, 1344, 10447, 6879, 8648, 12724, 5019, 3879, 13887, 14791, 14987, 22936, 18574, 6776, 6259, 3342, -4592, 831, 6631, -215, -1447, 139, -9361, -11483, -1599, 0, 1599, 11483, 9361, -139, 1447, 215, -6631, -831, 4592, -3342, -6259, -6776, -18574, -22936, -14987, -14791, -13887, -3879, -5019, -12724, -8648, -6879, -10447, -1344, 7149, 1820, 861, 1533, -9888, -14653, -7774, -9141, -10071, -1919, -4693, -13586, -10075, -8138, -10767, 0, 10767, 8138, 10075, 13586, 4693, 1919, 10071, 9141, 7774, 14653, 9888, -1533, -861, -1820, -7149, 1344, 10447, 6879, 8648, 12724, 5019, 3879, 13887, 14791, 14987, 22936, 18574, 6776, 6259, 3342, -4592, 831, 6631, -215, -1447, 139, -9361, -11483, -1599, 0, 1599, 11483, 9361, -139, 1447, 215, -6631, -831, 4592, -3342, -6259, -6776, -18574, -22936, -14987, -14791, -13887, -3879, -5019, -12724, -8648, -6879, -10447, -1344, 7149, 1820, 861, 1533, -9888, -14653, -7774, -9141, -10071, -1919, -4693, -13586, -10075, -8138, -10767, 0, 10767, 8138, 10075, 13586, 4693, 1919, 10071, 9141, 7774, 14653, 9888, -1533, -861, -1820, -7149, 1344, 10447, 6879, 8648, 12724, 5019, 3879, 13887, 14791, 14987, 22936, 18574, 6776, 6259, 3342, -4592, 831, 6631, -215, -1447, 139, -9361, -11483, -1599, 0, 1599, 11483, 9361, -139, 1447, 215, -6631, -831, 4592, -3342, -6259, -6776, -18574, -22936, -14987, -14791, -13887, -3879, -5019, -12724, -8648, -6879, -10447, -1344, 7149, 1820, 861, 1533, -9888, -14653, -7774, -9141, -10071, -1919, -4693, -13586, -10075, -8138, -10767, 0, 10767, 8138, 10075, 13586, 4693, 1919, 10071, 9141, 7774, 14653, 9888, -1533, -861, -1820, -7149, 1344, 10447, 6879, 8648, 12724, 5019, 3879, 13887, 14791, 14987, 22936, 18574, 6776, 6259, 3342, -4592, 831, 6631, -215, -1447, 139, -9361, -11483, -1599, 0, 1599, 11483, 9361, -139, 1447, 215, -6631, -831, 4592, -3342, -6259, -6776, -18574, -22936, -14987, -14791, -13887, -3879, -5019, -12724, -8648, -6879, -10447, -1344, 7149, 1820, 861, 1533, -9888, -14653, -7774, -9141, -10071, -1919, -4693, -13586, -10075, -8138, -10767, 0, 10767, 8138, 10075, 13586, 4693, 1919, 10071, 9141, 7774, 14653, 9888, -1533, -861, -1820, -7149, 1344, 10447, 6879, 8648, 12724, 5019, 3879, 13887, 14791, 14987, 22936, 18574, 6776, 6259, 3342, -4592, 831, 6631, -215, -1447, 139, -9361, -11483, -1599, 0, 1599, 11483, 9361, -139, 1447, 215, -6631, -831, 4592, -3342, -6259, -6776, -18574, -22936, -14987, -14791, -13887, -3879, -5019, -12724, -8648, -6879, -10447, -1344, 7149, 1820, 861, 1533, -9888, -14653, -7774, -9141, -10071, -1919, -4693, -13586, -10075, -8138, -10767, 0, 10767, 8138, 10075, 13586, 4693, 1919, 10071, 9141, 7774, 14653, 9888, -1533, -861, -1820, -7149, 1344, 10447, 6879, 8648, 12724, 5019, 3879, 13887, 14791, 14987, 22936, 18574, 6776, 6259, 3342, -4592, 831, 6631, -215, -1447, 139, -9361, -11483, -1599, 0, 1599, 11483, 9361, -139, 1447, 215, -6631, -831, 4592, -3342, -6259, -6776, -18574, -22936, -14987, -14791, -13887, -3879, -5019, -12724, -8648, -6879, -10447, -1344, 7149, 1820, 861, 1533, -9888, -14653, -7774, -9141, -10071, -1919, -4693, -13586, -10075, -8138, -10767, 0, 10767, 8138, 10075, 13586, 4693, 1919, 10071, 9141, 7774, 14653, 9888, -1533, -861, -1820, -7149, 1344, 10447, 6879, 8648, 12724, 5019, 3879, 13887, 14791, 14987, 22936, 18574, 6776, 6259, 3342, -4592, 831, 6631, -215, -1447, 139, -9361, -11483, -1599, 0, 1599, 11483, 9361, -139, 1447, 215, -6631, -831, 4592, -3342, -6259, -6776, -18574, -22936, -14987, -14791, -13887, -3879, -5019, -12724, -8648, -6879, -10447, -1344, 7149, 1820, 861, 1533, -9888, -14653, -7774, -9141, -10071, -1919, -4693, -13586, -10075, -8138, -10767], "sample_rate": 16000} \ No newline at end of file diff --git a/testdata/firered_reference/ref_upstream_probs.json b/testdata/firered_reference/ref_upstream_probs.json new file mode 100644 index 0000000..76bc85a --- /dev/null +++ b/testdata/firered_reference/ref_upstream_probs.json @@ -0,0 +1 @@ +{"probs": [0.047, 0.055, 0.051, 0.059, 0.091, 0.116, 0.125, 0.11, 0.087, 0.071, 0.067, 0.064, 0.056, 0.045, 0.042, 0.039, 0.045, 0.046, 0.049, 0.041, 0.047, 0.045, 0.045, 0.04, 0.034, 0.028, 0.025, 0.023, 0.021, 0.019, 0.017, 0.013, 0.011, 0.009, 0.008, 0.007, 0.006, 0.006, 0.005, 0.006, 0.006, 0.006, 0.006, 0.006, 0.006, 0.006, 0.006, 0.006, 0.007, 0.007, 0.007, 0.007, 0.006, 0.006, 0.006, 0.006, 0.005, 0.005, 0.005, 0.005, 0.006, 0.006, 0.006, 0.006, 0.005, 0.004, 0.004, 0.004, 0.004, 0.004, 0.004, 0.004, 0.004, 0.004, 0.004, 0.003, 0.003, 0.003, 0.003, 0.003, 0.002, 0.002, 0.002, 0.002, 0.002, 0.002, 0.002, 0.002, 0.002, 0.002, 0.002, 0.002, 0.002, 0.002, 0.002, 0.001, 0.001, 0.001]} \ No newline at end of file diff --git a/tools/vad-lab/backend/Cargo.toml b/tools/vad-lab/backend/Cargo.toml index 48a2532..e66da56 100644 --- a/tools/vad-lab/backend/Cargo.toml +++ b/tools/vad-lab/backend/Cargo.toml @@ -4,7 +4,7 @@ version = "0.1.0" edition = "2021" [dependencies] -wavekat-vad = { path = "../../../crates/wavekat-vad", features = ["webrtc", "silero", "denoise", "ten-vad", "serde"] } +wavekat-vad = { path = "../../../crates/wavekat-vad", features = ["webrtc", "silero", "denoise", "ten-vad", "firered", "serde"] } axum = { version = "0.8", features = ["ws", "multipart"] } tokio = { workspace = true } tower-http = { version = "0.6", features = ["cors", "fs"] } diff --git a/tools/vad-lab/backend/src/pipeline.rs b/tools/vad-lab/backend/src/pipeline.rs index a795ba3..c598ecc 100644 --- a/tools/vad-lab/backend/src/pipeline.rs +++ b/tools/vad-lab/backend/src/pipeline.rs @@ -5,7 +5,16 @@ use std::collections::HashMap; use std::time::Instant; use tokio::sync::{broadcast, mpsc}; use wavekat_vad::preprocessing::Preprocessor; -use wavekat_vad::{FrameAdapter, VoiceActivityDetector}; +use wavekat_vad::{FrameAdapter, ProcessTimings, VoiceActivityDetector}; + +/// Per-stage timing entry (name + microseconds). +#[derive(Debug, Clone, Serialize)] +pub struct StageTiming { + /// Stage name (e.g. "fbank", "onnx"). + pub name: String, + /// Time in microseconds for this frame. + pub us: f64, +} /// A VAD result from the pipeline. #[derive(Debug, Clone, Serialize)] @@ -18,6 +27,8 @@ pub struct PipelineResult { pub probability: f32, /// Inference time in microseconds for this frame. pub inference_us: f64, + /// Per-stage timing breakdown in pipeline order. + pub stage_times: Vec, /// Frame duration in milliseconds (from backend capabilities). pub frame_duration_ms: u32, /// Preprocessed audio samples (for visualization). @@ -25,6 +36,34 @@ pub struct PipelineResult { pub preprocessed_samples: Vec, } +/// Compute per-frame stage timing deltas between two snapshots. +fn stage_deltas( + before: &ProcessTimings, + after: &ProcessTimings, + num_frames: usize, +) -> Vec { + if num_frames == 0 { + return Vec::new(); + } + after + .stages + .iter() + .map(|(name, dur_after)| { + let dur_before = before + .stages + .iter() + .find(|(n, _)| n == name) + .map(|(_, d)| *d) + .unwrap_or(std::time::Duration::ZERO); + let delta_us = (dur_after.as_secs_f64() - dur_before.as_secs_f64()) * 1_000_000.0; + StageTiming { + name: name.to_string(), + us: delta_us / num_frames as f64, + } + }) + .collect() +} + /// Run the VAD pipeline: fan out audio frames to multiple VAD configs. /// /// Each config gets its own task with its own broadcast receiver, so all @@ -90,6 +129,7 @@ pub fn run_pipeline( let preprocessed_samples = preprocessor.process(&samples); // Run VAD on preprocessed audio (adapter handles frame buffering) + let timings_before = adapter.timings(); let start = Instant::now(); match adapter.process_all(&preprocessed_samples, effective_rate) { Ok(probabilities) => { @@ -100,12 +140,15 @@ pub fn run_pipeline( } else { elapsed_us / probabilities.len() as f64 }; + let per_frame_stages = + stage_deltas(&timings_before, &adapter.timings(), probabilities.len()); for probability in probabilities { let result = PipelineResult { config_id: config_id.clone(), timestamp_ms: frame.timestamp_ms, probability, inference_us: per_frame_us, + stage_times: per_frame_stages.clone(), frame_duration_ms, preprocessed_samples: preprocessed_samples.clone(), }; @@ -136,8 +179,8 @@ pub fn run_pipeline( /// Returns `None` when the backend accepts the given `input_rate` as-is. fn backend_required_rate(backend: &str, input_rate: u32) -> Option { match backend { - // TEN-VAD only supports 16 kHz - "ten-vad" if input_rate != 16000 => Some(16000), + // TEN-VAD and FireRedVAD only support 16 kHz + "ten-vad" | "firered-vad" if input_rate != 16000 => Some(16000), _ => None, } } @@ -177,14 +220,9 @@ fn create_detector( .params .get("mode") .and_then(|v| v.as_str()) - .unwrap_or("0 - quality"); - - // Strip "N - " prefix if present (e.g. "2 - aggressive" -> "aggressive") - let mode_key = mode_str - .split_once(" - ") - .map_or(mode_str, |(_, name)| name); + .unwrap_or("quality"); - let mode = match mode_key { + let mode = match mode_str { "quality" => WebRtcVadMode::Quality, "low_bitrate" => WebRtcVadMode::LowBitrate, "aggressive" => WebRtcVadMode::Aggressive, @@ -209,6 +247,12 @@ fn create_detector( let vad = TenVad::new().map_err(|e| format!("failed to create TEN VAD: {e}"))?; Ok(Box::new(vad)) } + "firered-vad" => { + use wavekat_vad::backends::firered::FireRedVad; + + let vad = FireRedVad::new().map_err(|e| format!("failed to create FireRedVAD: {e}"))?; + Ok(Box::new(vad)) + } other => Err(format!("unknown backend: {other}")), } } @@ -223,12 +267,24 @@ pub fn available_backends() -> HashMap> { name: "mode".to_string(), description: "Aggressiveness mode".to_string(), param_type: ParamType::Select(vec![ - "0 - quality".to_string(), - "1 - low_bitrate".to_string(), - "2 - aggressive".to_string(), - "3 - very_aggressive".to_string(), + SelectOption { + value: "quality".into(), + label: "0 - Quality".into(), + }, + SelectOption { + value: "low_bitrate".into(), + label: "1 - Low Bitrate".into(), + }, + SelectOption { + value: "aggressive".into(), + label: "2 - Aggressive".into(), + }, + SelectOption { + value: "very_aggressive".into(), + label: "3 - Very Aggressive".into(), + }, ]), - default: serde_json::json!("0 - quality"), + default: serde_json::json!("quality"), }], ); @@ -241,7 +297,9 @@ pub fn available_backends() -> HashMap> { backends.insert("silero-vad".to_string(), vec![threshold_param.clone()]); - backends.insert("ten-vad".to_string(), vec![threshold_param]); + backends.insert("ten-vad".to_string(), vec![threshold_param.clone()]); + + backends.insert("firered-vad".to_string(), vec![threshold_param]); backends } @@ -261,7 +319,16 @@ pub fn preprocessing_params() -> Vec { ParamInfo { name: "denoise".to_string(), description: "RNNoise noise suppression".to_string(), - param_type: ParamType::Select(vec!["off".to_string(), "on".to_string()]), + param_type: ParamType::Select(vec![ + SelectOption { + value: "off".into(), + label: "Off".into(), + }, + SelectOption { + value: "on".into(), + label: "On".into(), + }, + ]), default: serde_json::json!("off"), }, ParamInfo { @@ -289,12 +356,19 @@ pub struct ParamInfo { pub default: serde_json::Value, } +/// A select option with a machine value and a human-readable label. +#[derive(Debug, Clone, Serialize)] +pub struct SelectOption { + pub value: String, + pub label: String, +} + /// Type of a configurable parameter. #[derive(Debug, Clone, Serialize)] #[serde(tag = "type", content = "options")] pub enum ParamType { /// Select from a list of options. - Select(Vec), + Select(Vec), /// Float value with min/max range. #[allow(dead_code)] Float { min: f64, max: f64 }, diff --git a/tools/vad-lab/backend/src/ws.rs b/tools/vad-lab/backend/src/ws.rs index 884c89a..539c0c1 100644 --- a/tools/vad-lab/backend/src/ws.rs +++ b/tools/vad-lab/backend/src/ws.rs @@ -84,6 +84,8 @@ pub enum ServerMessage { probability: f32, /// Inference time in microseconds for this frame. inference_us: f64, + /// Per-stage timing breakdown (e.g. fbank, cmvn, onnx). + stage_times: Vec, /// Frame duration in milliseconds (from backend capabilities). frame_duration_ms: u32, }, @@ -242,6 +244,7 @@ pub async fn handle_ws(socket: WebSocket) { timestamp_ms: result.timestamp_ms, probability: result.probability, inference_us: result.inference_us, + stage_times: result.stage_times.clone(), frame_duration_ms: result.frame_duration_ms, }; if msg_tx_vad.send(vad_msg).await.is_err() { @@ -426,6 +429,7 @@ pub async fn handle_ws(socket: WebSocket) { timestamp_ms: result.timestamp_ms, probability: result.probability, inference_us: result.inference_us, + stage_times: result.stage_times.clone(), frame_duration_ms: result.frame_duration_ms, }; if msg_tx_vad.send(vad_msg).await.is_err() { diff --git a/tools/vad-lab/frontend/src/App.tsx b/tools/vad-lab/frontend/src/App.tsx index ba220bf..3dd6518 100644 --- a/tools/vad-lab/frontend/src/App.tsx +++ b/tools/vad-lab/frontend/src/App.tsx @@ -92,7 +92,7 @@ function createDefaultConfigs(): VadConfig[] { id: "config-1", label: "WebRTC VAD", backend: "webrtc-vad", - params: { mode: "0 - quality" }, + params: { mode: "very_aggressive" }, preprocessing: {}, }, { @@ -109,6 +109,13 @@ function createDefaultConfigs(): VadConfig[] { params: { threshold: 0.5 }, preprocessing: {}, }, + { + id: "config-4", + label: "FireRed VAD", + backend: "firered-vad", + params: { threshold: 0.5 }, + preprocessing: {}, + }, ]; } @@ -150,7 +157,7 @@ function App() { >({}); // Cumulative inference timing per config for RTF computation const [vadTiming, setVadTiming] = useState< - Record + Record; frameDurationMs: number }> >({}); const [totalDurationMs, setTotalDurationMs] = useState(0); const [sampleRate, setSampleRate] = useState(null); @@ -244,7 +251,7 @@ function App() { configsLoadedRef.current = true; setConfigs(createDefaultConfigs()); } else { - // Backfill missing param defaults for saved configs (e.g. new params added) + // Backfill missing params and fix stale Select values in saved configs setConfigs((prev) => prev.map((c) => { const backendParams = msg.backends[c.backend]; @@ -255,6 +262,13 @@ function App() { if (!(p.name in params)) { params[p.name] = p.default; changed = true; + } else if (p.param_type.type === "Select") { + // Reset to default if saved value doesn't match any valid option + const valid = p.param_type.options.map((o) => o.value); + if (!valid.includes(String(params[p.name]))) { + params[p.name] = p.default; + changed = true; + } } } return changed ? { ...c, params } : c; @@ -298,12 +312,18 @@ function App() { ], })); setVadTiming((prev) => { - const existing = prev[msg.config_id] ?? { totalInferenceUs: 0, totalAudioMs: 0 }; + const existing = prev[msg.config_id] ?? { totalInferenceUs: 0, totalAudioMs: 0, stageTotals: {}, frameDurationMs: 0 }; + const stageTotals = { ...existing.stageTotals }; + for (const st of msg.stage_times ?? []) { + stageTotals[st.name] = (stageTotals[st.name] ?? 0) + st.us; + } return { ...prev, [msg.config_id]: { totalInferenceUs: existing.totalInferenceUs + msg.inference_us, totalAudioMs: existing.totalAudioMs + msg.frame_duration_ms, + stageTotals, + frameDurationMs: msg.frame_duration_ms, }, }; }); @@ -734,6 +754,13 @@ function App() { const rtf = timing && timing.totalAudioMs > 0 ? (timing.totalInferenceUs / 1000) / timing.totalAudioMs : null; + const numResults = (vadResults[config.id] ?? []).length; + const stageAvgs = timing && numResults > 0 + ? Object.entries(timing.stageTotals).map(([name, totalUs]) => ({ + name, + us: totalUs / numResults, + })) + : undefined; return ( {param.param_type.options.map((opt) => ( - - {opt} + + {opt.label} ))} diff --git a/tools/vad-lab/frontend/src/components/VadTimeline.tsx b/tools/vad-lab/frontend/src/components/VadTimeline.tsx index a77ecc5..151019d 100644 --- a/tools/vad-lab/frontend/src/components/VadTimeline.tsx +++ b/tools/vad-lab/frontend/src/components/VadTimeline.tsx @@ -1,4 +1,6 @@ import { useRef, useEffect, useCallback } from "react"; +import { Info } from "lucide-react"; +import { Tooltip, TooltipTrigger, TooltipContent } from "@/components/ui/tooltip"; import { type Viewport, pixelToTime, timeToPixel } from "@/lib/viewport"; interface VadConfig { @@ -18,6 +20,10 @@ interface VadTimelineProps { results: Array<{ timestamp_ms: number; probability: number }>; /** Real-Time Factor (processing_time / audio_duration). Lower is better. */ rtf?: number | null; + /** Per-stage average timing breakdown in µs/frame. */ + stageAvgs?: Array<{ name: string; us: number }>; + /** Frame duration in milliseconds (from backend capabilities). */ + frameDurationMs?: number; totalDurationMs: number; viewport: Viewport; width?: number; @@ -39,11 +45,7 @@ function formatConfigSummary(config: VadConfig): string { // Add key backend params for (const [key, value] of Object.entries(config.params)) { if (value != null && value !== "") { - // For mode params, just show the first part (e.g., "0 - quality" -> "mode:0") - const displayValue = typeof value === "string" && value.includes(" - ") - ? value.split(" - ")[0] - : String(value); - parts.push(`${key}:${displayValue}`); + parts.push(`${key}:${String(value)}`); } } @@ -63,6 +65,8 @@ export function VadTimeline({ config, results, rtf, + stageAvgs, + frameDurationMs, totalDurationMs, viewport, width = 800, @@ -269,21 +273,64 @@ export function VadTimeline({ }, [results, width, height, color, config, hoverTimeMs, playheadMs, totalDurationMs, effectiveViewport]); return ( -
+
- {label} - {config && ( - - {formatConfigSummary(config)} - - )} +
+ {label} + {config && ( + + {formatConfigSummary(config)} + + )} +
{rtf != null && ( - - RTF {rtf.toFixed(4)} - +
+
+ RTF {rtf.toFixed(4)} + {stageAvgs && stageAvgs.length > 0 && ( + ({stageAvgs.map((s) => + `${s.name}: ${s.us < 10 ? s.us.toFixed(1) : Math.round(s.us)}µs` + ).join(" → ")}) + )} +
+ {frameDurationMs != null && frameDurationMs > 0 && stageAvgs && stageAvgs.length > 0 && (() => { + const totalUs = stageAvgs.reduce((sum, s) => sum + s.us, 0); + const frameDurationUs = frameDurationMs * 1000; + return ( + + + + + +
RTF = processing time / audio duration
+ + + + + + + {stageAvgs.map((s) => ( + + + + + ))} + + + + + +
frame{frameDurationMs}ms ({frameDurationUs.toLocaleString()}µs)
{s.name}{s.us < 10 ? s.us.toFixed(1) : Math.round(s.us)}µs
total{Math.round(totalUs)}µs / {frameDurationUs.toLocaleString()}µs ≈ {(totalUs / frameDurationUs).toFixed(4)}
+
Lower is better. RTF < 1 = faster than real-time.
+
+
+ ); + })()} +
)}
+ ) +} + +function Tooltip({ ...props }: TooltipPrimitive.Root.Props) { + return +} + +function TooltipTrigger({ ...props }: TooltipPrimitive.Trigger.Props) { + return +} + +function TooltipContent({ + className, + side = "top", + sideOffset = 4, + align = "center", + alignOffset = 0, + children, + ...props +}: TooltipPrimitive.Popup.Props & + Pick< + TooltipPrimitive.Positioner.Props, + "align" | "alignOffset" | "side" | "sideOffset" + >) { + return ( + + + + {children} + + + + + ) +} + +export { Tooltip, TooltipTrigger, TooltipContent, TooltipProvider } diff --git a/tools/vad-lab/frontend/src/lib/websocket.ts b/tools/vad-lab/frontend/src/lib/websocket.ts index e00d58e..85838de 100644 --- a/tools/vad-lab/frontend/src/lib/websocket.ts +++ b/tools/vad-lab/frontend/src/lib/websocket.ts @@ -20,7 +20,7 @@ export interface VadConfig { export interface ParamInfo { name: string; description: string; - param_type: { type: "Select"; options: string[] } | { type: "Float"; options: { min: number; max: number } } | { type: "Int"; options: { min: number; max: number } }; + param_type: { type: "Select"; options: { value: string; label: string }[] } | { type: "Float"; options: { min: number; max: number } } | { type: "Int"; options: { min: number; max: number } }; default: unknown; } @@ -33,7 +33,7 @@ export type ServerMessage = | { type: "spectrum"; timestamp_ms: number; magnitudes: number[] } | { type: "preprocessed_audio"; config_id: string; timestamp_ms: number; samples: number[] } | { type: "preprocessed_spectrum"; config_id: string; timestamp_ms: number; magnitudes: number[] } - | { type: "vad"; config_id: string; timestamp_ms: number; probability: number; inference_us: number; frame_duration_ms: number } + | { type: "vad"; config_id: string; timestamp_ms: number; probability: number; inference_us: number; stage_times: Array<{ name: string; us: number }>; frame_duration_ms: number } | { type: "done" } | { type: "error"; message: string }; diff --git a/tools/vad-lab/frontend/src/main.tsx b/tools/vad-lab/frontend/src/main.tsx index bef5202..2e4b659 100644 --- a/tools/vad-lab/frontend/src/main.tsx +++ b/tools/vad-lab/frontend/src/main.tsx @@ -1,10 +1,13 @@ import { StrictMode } from 'react' import { createRoot } from 'react-dom/client' +import { TooltipProvider } from '@/components/ui/tooltip' import './index.css' import App from './App.tsx' createRoot(document.getElementById('root')!).render( - + + + , )