diff --git a/.cargo/config.toml b/.cargo/config.toml new file mode 100644 index 000000000..ddff4407b --- /dev/null +++ b/.cargo/config.toml @@ -0,0 +1,2 @@ +[build] +rustflags = ["-C", "target-cpu=native"] diff --git a/Cargo.lock b/Cargo.lock index 8eba872c0..a41a95eee 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -134,15 +134,6 @@ dependencies = [ "windows-sys 0.61.2", ] -[[package]] -name = "arbitrary" -version = "1.4.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c3d036a3c4ab069c7b410a2ce876bd74808d2d0888a82667669f8e783a898bf1" -dependencies = [ - "derive_arbitrary", -] - [[package]] name = "arrayvec" version = "0.7.6" @@ -471,14 +462,11 @@ dependencies = [ "brk_server", "clap", "color-eyre", - "importmap", - "minreq", "serde", "tokio", "toml", "tracing", "vecdb", - "zip", ] [[package]] @@ -748,6 +736,8 @@ dependencies = [ "brk_traversable", "brk_types", "derive_more", + "importmap", + "include_dir", "jiff", "quick_cache", "schemars", @@ -1249,17 +1239,6 @@ dependencies = [ "powerfmt", ] -[[package]] -name = "derive_arbitrary" -version = "1.4.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1e567bd82dcff979e4b03460c307b3cdc9e96fde3d73bed1496d2bc75d9dd62a" -dependencies = [ - "proc-macro2", - "quote", - "syn", -] - [[package]] name = "derive_more" version = "2.1.1" @@ -1450,7 +1429,6 @@ checksum = "b375d6465b98090a5f25b1c7703f3859783755aa9a80433b36e0379a3ec2f369" dependencies = [ "crc32fast", "miniz_oxide", - "zlib-rs", ] [[package]] @@ -1954,9 +1932,9 @@ dependencies = [ [[package]] name = "importmap" -version = "0.1.3" +version = "0.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a45c4c5e8b4d0a6aed90f3a14125bd3af3bca73d49d44e8f8b764311903b5213" +checksum = "f650142f4c83e122ae10a49dbaa88593dc4b20158124409856adbae847775938" dependencies = [ "rapidhash", "serde", @@ -1964,6 +1942,25 @@ dependencies = [ "walkdir", ] +[[package]] +name = "include_dir" +version = "0.7.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "923d117408f1e49d914f1a379a309cffe4f18c05cf4e3d12e613a15fc81bd0dd" +dependencies = [ + "include_dir_macros", +] + +[[package]] +name = "include_dir_macros" +version = "0.7.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7cab85a7ed0bd5f0e76d93846e0147172bed2e2d3f859bcc33a8d9699cad1a75" +dependencies = [ + "proc-macro2", + "quote", +] + [[package]] name = "indenter" version = "0.3.4" @@ -2644,9 +2641,9 @@ dependencies = [ [[package]] name = "quickmatch" -version = "0.1.8" +version = "0.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2da298bd4f885924ca16faab70af76893797eb0164dfa4e86a14ffd983b8cb14" +checksum = "e6f3930eacf56a69f668e37113288d810cc83a7af7afde8d7bf81d73148a5db7" dependencies = [ "rustc-hash", ] @@ -2745,9 +2742,9 @@ dependencies = [ [[package]] name = "rawdb" -version = "0.5.9" +version = "0.5.10" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "eb8999fc8f80521c13091f98e1a24bde2448b29c0637f008dc470ed84d58f703" +checksum = "12f4f316acfc1844da8b3c84163aabd98f155df82d3b57ce4075dda550e1752d" dependencies = [ "libc", "log", @@ -3689,9 +3686,9 @@ checksum = "8f54a172d0620933a27a4360d3db3e2ae0dd6cceae9730751a036bbf182c4b23" [[package]] name = "vecdb" -version = "0.5.9" +version = "0.5.10" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1a31985bee527adda1601eab9c72de0a567be83a08e80e646b79afb77ab14970" +checksum = "28d56bd525ca319c5772dcc91b40caa6947dfb6c56b63c4a9b2268ee24254c05" dependencies = [ "ctrlc", "log", @@ -3710,9 +3707,9 @@ dependencies = [ [[package]] name = "vecdb_derive" -version = "0.5.9" +version = "0.5.10" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "61716cbeb322dcc9838cea11b533cea278f9592b2ef2ce520595849833cfee1c" +checksum = "17c227a593e7a08c3d00babaa81aec624052d2c6a16ba127fb8f491f273c9751" dependencies = [ "quote", "syn", @@ -4206,44 +4203,12 @@ dependencies = [ "syn", ] -[[package]] -name = "zip" -version = "7.0.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bdd8a47718a4ee5fe78e07667cd36f3de80e7c2bfe727c7074245ffc7303c037" -dependencies = [ - "arbitrary", - "crc32fast", - "flate2", - "indexmap", - "memchr", - "zopfli", -] - -[[package]] -name = "zlib-rs" -version = "0.5.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "40990edd51aae2c2b6907af74ffb635029d5788228222c4bb811e9351c0caad3" - [[package]] name = "zmij" version = "1.0.14" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "bd8f3f50b848df28f887acb68e41201b5aea6bc8a8dacc00fb40635ff9a72fea" -[[package]] -name = "zopfli" -version = "0.8.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f05cd8797d63865425ff89b5c4a48804f35ba0ce8d125800027ad6017d2b5249" -dependencies = [ - "bumpalo", - "crc32fast", - "log", - "simd-adler32", -] - [[package]] name = "zstd" version = "0.13.3" diff --git a/Cargo.toml b/Cargo.toml index 8a3efc534..24dfcd122 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -79,7 +79,7 @@ serde_json = { version = "1.0.149", features = ["float_roundtrip", "preserve_ord smallvec = "1.15.1" tokio = { version = "1.49.0", features = ["rt-multi-thread"] } tracing = { version = "0.1", default-features = false, features = ["std"] } -vecdb = { version = "0.5.9", features = ["derive", "serde_json", "pco", "schemars"] } +vecdb = { version = "0.5.10", features = ["derive", "serde_json", "pco", "schemars"] } # vecdb = { path = "../anydb/crates/vecdb", features = ["derive", "serde_json", "pco", "schemars"] } [workspace.metadata.release] diff --git a/crates/brk/Cargo.toml b/crates/brk/Cargo.toml index 1fab87bdd..3569c0224 100644 --- a/crates/brk/Cargo.toml +++ b/crates/brk/Cargo.toml @@ -6,12 +6,11 @@ homepage.workspace = true repository.workspace = true edition.workspace = true version.workspace = true -build = "build.rs" [features] full = [ "bencher", - "binder", + "bindgen", "client", "computer", "error", @@ -31,7 +30,7 @@ full = [ "types", ] bencher = ["brk_bencher"] -binder = ["brk_bindgen"] +bindgen = ["brk_bindgen"] client = ["brk_client"] computer = ["brk_computer"] error = ["brk_error"] diff --git a/crates/brk/README.md b/crates/brk/README.md index f91f4fe73..0818e68de 100644 --- a/crates/brk/README.md +++ b/crates/brk/README.md @@ -61,7 +61,3 @@ Feature flags match crate names without the `brk_` prefix. Use `full` to enable | [brk_error](https://docs.rs/brk_error) | Error types | | [brk_logger](https://docs.rs/brk_logger) | Logging infrastructure | | [brk_bencher](https://docs.rs/brk_bencher) | Benchmarking utilities | - -## License - -MIT diff --git a/crates/brk/build.rs b/crates/brk/build.rs deleted file mode 100644 index a4055a31e..000000000 --- a/crates/brk/build.rs +++ /dev/null @@ -1,8 +0,0 @@ -fn main() { - let profile = std::env::var("PROFILE").unwrap_or_default(); - - if profile == "release" { - println!("cargo:rustc-flag=-C"); - println!("cargo:rustc-flag=target-cpu=native"); - } -} diff --git a/crates/brk/src/lib.rs b/crates/brk/src/lib.rs index 5a37a7ae2..f212b329e 100644 --- a/crates/brk/src/lib.rs +++ b/crates/brk/src/lib.rs @@ -4,9 +4,9 @@ #[doc(inline)] pub use brk_bencher as bencher; -#[cfg(feature = "binder")] +#[cfg(feature = "bindgen")] #[doc(inline)] -pub use brk_bindgen as binder; +pub use brk_bindgen as bindgen; #[cfg(feature = "client")] #[doc(inline)] diff --git a/crates/brk_bencher/Cargo.toml b/crates/brk_bencher/Cargo.toml index 04eba1b8b..b94c38a79 100644 --- a/crates/brk_bencher/Cargo.toml +++ b/crates/brk_bencher/Cargo.toml @@ -6,7 +6,6 @@ edition.workspace = true license.workspace = true homepage.workspace = true repository.workspace = true -build = "build.rs" [dependencies] brk_error = { workspace = true } diff --git a/crates/brk_bencher/build.rs b/crates/brk_bencher/build.rs deleted file mode 100644 index a4055a31e..000000000 --- a/crates/brk_bencher/build.rs +++ /dev/null @@ -1,8 +0,0 @@ -fn main() { - let profile = std::env::var("PROFILE").unwrap_or_default(); - - if profile == "release" { - println!("cargo:rustc-flag=-C"); - println!("cargo:rustc-flag=target-cpu=native"); - } -} diff --git a/crates/brk_bencher_visualizer/Cargo.toml b/crates/brk_bencher_visualizer/Cargo.toml index 877a5e515..199695dab 100644 --- a/crates/brk_bencher_visualizer/Cargo.toml +++ b/crates/brk_bencher_visualizer/Cargo.toml @@ -7,7 +7,6 @@ license.workspace = true homepage.workspace = true repository.workspace = true publish = false -build = "build.rs" [dependencies] plotters = "0.3.7" diff --git a/crates/brk_bencher_visualizer/build.rs b/crates/brk_bencher_visualizer/build.rs deleted file mode 100644 index a4055a31e..000000000 --- a/crates/brk_bencher_visualizer/build.rs +++ /dev/null @@ -1,8 +0,0 @@ -fn main() { - let profile = std::env::var("PROFILE").unwrap_or_default(); - - if profile == "release" { - println!("cargo:rustc-flag=-C"); - println!("cargo:rustc-flag=target-cpu=native"); - } -} diff --git a/crates/brk_bindgen/Cargo.toml b/crates/brk_bindgen/Cargo.toml index 6fee2c2bf..dec77bf70 100644 --- a/crates/brk_bindgen/Cargo.toml +++ b/crates/brk_bindgen/Cargo.toml @@ -6,7 +6,6 @@ edition.workspace = true license.workspace = true homepage.workspace = true repository.workspace = true -build = "build.rs" [dependencies] brk_cohort = { workspace = true } diff --git a/crates/brk_bindgen/build.rs b/crates/brk_bindgen/build.rs deleted file mode 100644 index a4055a31e..000000000 --- a/crates/brk_bindgen/build.rs +++ /dev/null @@ -1,8 +0,0 @@ -fn main() { - let profile = std::env::var("PROFILE").unwrap_or_default(); - - if profile == "release" { - println!("cargo:rustc-flag=-C"); - println!("cargo:rustc-flag=target-cpu=native"); - } -} diff --git a/crates/brk_bindgen/src/generators/javascript/client.rs b/crates/brk_bindgen/src/generators/javascript/client.rs index 0b6e2cb12..5333ba362 100644 --- a/crates/brk_bindgen/src/generators/javascript/client.rs +++ b/crates/brk_bindgen/src/generators/javascript/client.rs @@ -110,7 +110,7 @@ class BrkError extends Error {{ * @typedef {{Object}} MetricPattern * @property {{string}} name - The metric name * @property {{Readonly>>>}} by - Index endpoints as lazy getters. Access via .by.dateindex or .by['dateindex'] - * @property {{() => Index[]}} indexes - Get the list of available indexes + * @property {{() => readonly Index[]}} indexes - Get the list of available indexes * @property {{(index: Index) => MetricEndpointBuilder|undefined}} get - Get an endpoint for a specific index */ @@ -333,14 +333,14 @@ pub fn generate_index_accessors(output: &mut String, patterns: &[IndexSetPattern // Generate index array constants (e.g., _i1 = ["dateindex", "height"]) for (i, pattern) in patterns.iter().enumerate() { - write!(output, "const _i{} = [", i + 1).unwrap(); + write!(output, "const _i{} = /** @type {{const}} */ ([", i + 1).unwrap(); for (j, index) in pattern.indexes.iter().enumerate() { if j > 0 { write!(output, ", ").unwrap(); } write!(output, "\"{}\"", index.serialize_long()).unwrap(); } - writeln!(output, "];").unwrap(); + writeln!(output, "]);").unwrap(); } writeln!(output).unwrap(); @@ -352,11 +352,10 @@ pub fn generate_index_accessors(output: &mut String, patterns: &[IndexSetPattern * @template T * @param {{BrkClientBase}} client * @param {{string}} name - The metric vec name - * @param {{readonly string[]}} indexes - The supported indexes - * @returns {{MetricPattern}} + * @param {{readonly Index[]}} indexes - The supported indexes */ function _mp(client, name, indexes) {{ - const by = {{}}; + const by = /** @type {{any}} */ ({{}}); for (const idx of indexes) {{ Object.defineProperty(by, idx, {{ get() {{ return _endpoint(client, name, idx); }}, @@ -368,6 +367,7 @@ function _mp(client, name, indexes) {{ name, by, indexes() {{ return indexes; }}, + /** @param {{Index}} index */ get(index) {{ return indexes.includes(index) ? _endpoint(client, name, index) : undefined; }} }}; }} @@ -392,7 +392,7 @@ function _mp(client, name, indexes) {{ writeln!( output, - "/** @template T @typedef {{{{ name: string, by: {}, indexes: () => Index[], get: (index: Index) => MetricEndpointBuilder|undefined }}}} {} */", + "/** @template T @typedef {{{{ name: string, by: {}, indexes: () => readonly Index[], get: (index: Index) => MetricEndpointBuilder|undefined }}}} {} */", by_type, pattern.name ) .unwrap(); diff --git a/crates/brk_bindgen/src/openapi.rs b/crates/brk_bindgen/src/openapi.rs index d6b76713e..c0874e80d 100644 --- a/crates/brk_bindgen/src/openapi.rs +++ b/crates/brk_bindgen/src/openapi.rs @@ -2,7 +2,10 @@ use std::{collections::BTreeMap, io}; use crate::ref_to_type_name; use oas3::Spec; -use oas3::spec::{ObjectOrReference, ObjectSchema, Operation, ParameterIn, PathItem, Schema, SchemaType, SchemaTypeSet}; +use oas3::spec::{ + ObjectOrReference, ObjectSchema, Operation, ParameterIn, PathItem, Schema, SchemaType, + SchemaTypeSet, +}; use serde_json::Value; /// Type schema extracted from OpenAPI components @@ -156,7 +159,7 @@ pub fn extract_endpoints(spec: &Spec) -> Vec { for (path, path_item) in paths { for (method, operation) in get_operations(path_item) { - if let Some(endpoint) = extract_endpoint(path, &method, operation) { + if let Some(endpoint) = extract_endpoint(path, method, operation) { endpoints.push(endpoint); } } @@ -218,11 +221,7 @@ fn extract_path_parameters(path: &str, operation: &Operation) -> Vec // Extract parameter names from the path in order (e.g., "/api/metric/{metric}/{index}" -> ["metric", "index"]) let path_order: Vec<&str> = path .split('/') - .filter_map(|segment| { - segment - .strip_prefix('{') - .and_then(|s| s.strip_suffix('}')) - }) + .filter_map(|segment| segment.strip_prefix('{').and_then(|s| s.strip_suffix('}'))) .collect(); // Get all path parameters from the operation diff --git a/crates/brk_cli/Cargo.toml b/crates/brk_cli/Cargo.toml index 1df37b08b..34f4372bc 100644 --- a/crates/brk_cli/Cargo.toml +++ b/crates/brk_cli/Cargo.toml @@ -6,7 +6,6 @@ edition.workspace = true license.workspace = true homepage.workspace = true repository.workspace = true -build = "build.rs" [dependencies] brk_alloc = { workspace = true } @@ -23,15 +22,11 @@ brk_rpc = { workspace = true } brk_server = { workspace = true } clap = { version = "4.5.54", features = ["derive", "string"] } color-eyre = { workspace = true } -importmap = "0.1.3" -# importmap = { path = "../../../importmap" } tracing = { workspace = true } -minreq = { workspace = true } serde = { workspace = true } tokio = { workspace = true } toml = "0.9.11" vecdb = { workspace = true } -zip = { version = "7.0.0", default-features = false, features = ["deflate"] } [[bin]] name = "brk" diff --git a/crates/brk_cli/README.md b/crates/brk_cli/README.md index fe24c3081..14b61d0bd 100644 --- a/crates/brk_cli/README.md +++ b/crates/brk_cli/README.md @@ -21,6 +21,30 @@ Run a full BRK instance: index the blockchain, compute metrics, serve the API, a cargo install --locked brk_cli ``` +For pre-release versions (alpha, beta, rc), specify the version explicitly: + +```bash +# Find the latest version +cargo search brk_cli + +# Install a specific version +cargo install --locked brk_cli --version "VERSION" +``` + +See [crates.io/crates/brk_cli/versions](https://crates.io/crates/brk_cli/versions) for all available versions. + +For better performance, build with native CPU optimizations: + +```bash +RUSTFLAGS="-C target-cpu=native" cargo install --locked brk_cli +``` + +## Requirements + +- Bitcoin Core with accessible `blk*.dat` files +- ~400 GB disk space +- 12+ GB RAM recommended + ## Usage ```bash @@ -45,11 +69,7 @@ brk --help ## Performance -| Machine | Time | Disk | Peak Disk | Memory | Peak Memory | -|---------|------|------|-----------|--------|-------------| -| MBP M3 Pro (36GB, internal SSD) | 5.2h | 341 GB | 415 GB | 6.4 GB | 12 GB | - -Full benchmark data: [`https://github.com/bitcoinresearchkit/benches/tree/main/brk`](/benches/brk) +See [brk_computer](https://docs.rs/brk_computer) for full pipeline benchmarks. ## Built On diff --git a/crates/brk_cli/build.rs b/crates/brk_cli/build.rs deleted file mode 100644 index a4055a31e..000000000 --- a/crates/brk_cli/build.rs +++ /dev/null @@ -1,8 +0,0 @@ -fn main() { - let profile = std::env::var("PROFILE").unwrap_or_default(); - - if profile == "release" { - println!("cargo:rustc-flag=-C"); - println!("cargo:rustc-flag=target-cpu=native"); - } -} diff --git a/crates/brk_cli/src/config.rs b/crates/brk_cli/src/config.rs index 8d534e0c8..5f8be6109 100644 --- a/crates/brk_cli/src/config.rs +++ b/crates/brk_cli/src/config.rs @@ -9,9 +9,8 @@ use brk_rpc::{Auth, Client}; use clap::Parser; use serde::{Deserialize, Deserializer, Serialize}; -use crate::{default_brk_path, dot_brk_path, website::Website}; +use crate::{default_brk_path, dot_brk_path, fix_user_path, website::Website}; -const DOWNLOADS: &str = "downloads"; #[derive(Parser, Debug, Default, PartialEq, Eq, PartialOrd, Ord, Deserialize, Serialize)] #[command(version, about)] @@ -234,58 +233,36 @@ Finally, you can run the program with '-h' for help." self.bitcoindir .as_ref() .map_or_else(Client::default_bitcoin_path, |s| { - Self::fix_user_path(s.as_ref()) + fix_user_path(s.as_ref()) }) } pub fn blocksdir(&self) -> PathBuf { self.blocksdir.as_ref().map_or_else( || self.bitcoindir().join("blocks"), - |blocksdir| Self::fix_user_path(blocksdir.as_str()), + |blocksdir| fix_user_path(blocksdir.as_str()), ) } pub fn brkdir(&self) -> PathBuf { self.brkdir .as_ref() - .map_or_else(default_brk_path, |s| Self::fix_user_path(s.as_ref())) + .map_or_else(default_brk_path, |s| fix_user_path(s.as_ref())) } pub fn harsdir(&self) -> PathBuf { self.brkdir().join("hars") } - pub fn downloads_dir(&self) -> PathBuf { - dot_brk_path().join(DOWNLOADS) - } - fn path_cookiefile(&self) -> PathBuf { self.rpccookiefile.as_ref().map_or_else( || self.bitcoindir().join(".cookie"), - |p| Self::fix_user_path(p.as_str()), + |p| fix_user_path(p.as_str()), ) } - fn fix_user_path(path: &str) -> PathBuf { - let fix = move |pattern: &str| { - if path.starts_with(pattern) { - let path = &path - .replace(&format!("{pattern}/"), "") - .replace(pattern, ""); - - let home = std::env::var("HOME").unwrap(); - - Some(Path::new(&home).join(path)) - } else { - None - } - }; - - fix("~").unwrap_or_else(|| fix("$HOME").unwrap_or_else(|| PathBuf::from(&path))) - } - pub fn website(&self) -> Website { - self.website.unwrap_or(Website::Bitview) + self.website.clone().unwrap_or_default() } pub fn fetch(&self) -> bool { diff --git a/crates/brk_cli/src/main.rs b/crates/brk_cli/src/main.rs index 0a501866f..babe81892 100644 --- a/crates/brk_cli/src/main.rs +++ b/crates/brk_cli/src/main.rs @@ -2,7 +2,6 @@ use std::{ fs, - io::Cursor, path::PathBuf, thread::{self, sleep}, time::Duration, @@ -16,8 +15,7 @@ use brk_iterator::Blocks; use brk_mempool::Mempool; use brk_query::AsyncQuery; use brk_reader::Reader; -use brk_server::{Server, VERSION}; -use importmap::ImportMap; +use brk_server::{Server, WebsiteSource}; use tracing::info; use vecdb::Exit; @@ -25,7 +23,7 @@ mod config; mod paths; mod website; -use crate::{config::Config, paths::*}; +use crate::{config::Config, paths::*, website::Website}; pub fn main() -> color_eyre::Result<()> { // Can't increase main thread's stack size, thus we need to use another thread @@ -80,89 +78,22 @@ pub fn run() -> color_eyre::Result<()> { let query = AsyncQuery::build(&reader, &indexer, &computer, Some(mempool)); - let website = config.website(); - - let downloads_path = config.downloads_dir(); let data_path = config.brkdir(); - let future = async move { - // Try to find local dev directories - check cwd and parent directories - let find_dev_dirs = || -> Option<(PathBuf, PathBuf)> { - let mut dir = std::env::current_dir().ok()?; - loop { - let websites = dir.join("websites"); - let modules = dir.join("modules"); - if websites.exists() && modules.exists() { - return Some((websites, modules)); - } - // Stop at workspace root (crates/ indicates we're there) - if dir.join("crates").exists() { - return None; - } - dir = dir.parent()?.to_path_buf(); - } - }; - - let dev_dirs = find_dev_dirs(); - let is_dev = dev_dirs.is_some(); - - let bundle_path = if website.is_some() { - let websites_path = if let Some((websites, _modules)) = dev_dirs { - websites - } else { - let downloaded_brk_path = downloads_path.join(format!("brk-{VERSION}")); - let downloaded_websites_path = downloaded_brk_path.join("websites"); - - if !fs::exists(&downloaded_websites_path)? { - info!("Downloading source from Github..."); - - let url = format!( - "https://github.com/bitcoinresearchkit/brk/archive/refs/tags/v{VERSION}.zip", - ); - - let response = minreq::get(url).with_timeout(60).send()?; - let bytes = response.as_bytes(); - let cursor = Cursor::new(bytes); - - let mut zip = zip::ZipArchive::new(cursor).unwrap(); - - zip.extract(downloads_path).unwrap(); - } - - downloaded_websites_path - }; - - Some(websites_path.join(website.to_folder_name())) - } else { - None - }; - - // Generate import map for cache busting (disabled in dev mode) - if let Some(ref path) = bundle_path { - let map = if is_dev { - ImportMap::empty() - } else { - match ImportMap::scan(path, "") { - Ok(map) => map, - Err(e) => { - tracing::error!("Failed to generate importmap: {e}"); - ImportMap::empty() - } - } - }; - - let html_path = path.join("index.html"); - if let Ok(html) = fs::read_to_string(&html_path) - && let Some(updated) = map.update_html(&html) - { - let _ = fs::write(&html_path, updated); - if !is_dev { - info!("Updated importmap in index.html"); - } + let website_source = match config.website() { + Website::Enabled(false) => WebsiteSource::Disabled, + Website::Path(p) => WebsiteSource::Filesystem(p), + Website::Enabled(true) => { + // Prefer local filesystem if available, otherwise use embedded + match find_local_website_dir() { + Some(path) => WebsiteSource::Filesystem(path), + None => WebsiteSource::Embedded, } } + }; - let server = Server::new(&query, data_path, bundle_path); + let future = async move { + let server = Server::new(&query, data_path, website_source); tokio::spawn(async move { server.serve(true).await.unwrap(); @@ -201,3 +132,12 @@ pub fn run() -> color_eyre::Result<()> { } } } + +/// Path to website directory relative to this crate (only valid at dev machine) +const DEV_WEBSITE_DIR: &str = concat!(env!("CARGO_MANIFEST_DIR"), "/../../website"); + +/// Returns local website path if it exists (dev mode) +fn find_local_website_dir() -> Option { + let path = PathBuf::from(DEV_WEBSITE_DIR); + path.exists().then_some(path) +} diff --git a/crates/brk_cli/src/paths.rs b/crates/brk_cli/src/paths.rs index 20b968e0b..4f476ac25 100644 --- a/crates/brk_cli/src/paths.rs +++ b/crates/brk_cli/src/paths.rs @@ -12,3 +12,12 @@ pub fn dot_brk_log_path() -> PathBuf { pub fn default_brk_path() -> PathBuf { dot_brk_path() } + +pub fn fix_user_path(path: &str) -> PathBuf { + if let Some(rest) = path.strip_prefix("~/").or(path.strip_prefix("$HOME/")) + && let Ok(home) = std::env::var("HOME") + { + return PathBuf::from(home).join(rest); + } + PathBuf::from(path) +} diff --git a/crates/brk_cli/src/website.rs b/crates/brk_cli/src/website.rs index d526ae6f5..c93b12039 100644 --- a/crates/brk_cli/src/website.rs +++ b/crates/brk_cli/src/website.rs @@ -1,28 +1,35 @@ -use clap::ValueEnum; +use std::{path::PathBuf, str::FromStr}; + use serde::{Deserialize, Serialize}; -#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Deserialize, Serialize, ValueEnum)] -#[serde(rename_all = "lowercase")] +use crate::paths::fix_user_path; + +/// Website configuration: +/// - `true` or omitted: serve embedded website +/// - `false`: disable website serving +/// - `"/path/to/website"`: serve custom website from path +#[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Deserialize, Serialize)] +#[serde(untagged)] pub enum Website { - None, - Bitview, - Custom, + Enabled(bool), + Path(PathBuf), } -impl Website { - pub fn is_none(&self) -> bool { - self == &Self::None - } - - pub fn is_some(&self) -> bool { - !self.is_none() - } - - pub fn to_folder_name(self) -> &'static str { - match self { - Self::Custom => "custom", - Self::Bitview => "bitview", - Self::None => unreachable!(), - } +impl Default for Website { + fn default() -> Self { + Self::Enabled(true) + } +} + + +impl FromStr for Website { + type Err = std::convert::Infallible; + + fn from_str(s: &str) -> Result { + Ok(match s.to_lowercase().as_str() { + "true" | "1" | "yes" | "on" => Self::Enabled(true), + "false" | "0" | "no" | "off" => Self::Enabled(false), + _ => Self::Path(fix_user_path(s)), + }) } } diff --git a/crates/brk_client/Cargo.toml b/crates/brk_client/Cargo.toml index bb38d7158..0f7e36aa7 100644 --- a/crates/brk_client/Cargo.toml +++ b/crates/brk_client/Cargo.toml @@ -6,7 +6,6 @@ edition.workspace = true license.workspace = true homepage.workspace = true repository.workspace = true -build = "build.rs" keywords = ["bitcoin", "blockchain", "analytics", "on-chain"] categories = ["api-bindings", "cryptography::cryptocurrencies"] diff --git a/crates/brk_client/README.md b/crates/brk_client/README.md index b6fd460ca..71b8ed3d3 100644 --- a/crates/brk_client/README.md +++ b/crates/brk_client/README.md @@ -17,7 +17,7 @@ brk_client = "0.1" use brk_client::{BrkClient, Index}; fn main() -> brk_client::Result<()> { - let client = BrkClient::new("http://localhost:3000"); + let client = BrkClient::new("http://localhost:3110"); // Blockchain data (mempool.space compatible) let block = client.get_block_by_height(800000)?; @@ -47,11 +47,7 @@ fn main() -> brk_client::Result<()> { use brk_client::{BrkClient, BrkClientOptions}; let client = BrkClient::with_options(BrkClientOptions { - base_url: "http://localhost:3000".to_string(), + base_url: "http://localhost:3110".to_string(), timeout_secs: 60, }); ``` - -## License - -MIT diff --git a/crates/brk_client/build.rs b/crates/brk_client/build.rs deleted file mode 100644 index a4055a31e..000000000 --- a/crates/brk_client/build.rs +++ /dev/null @@ -1,8 +0,0 @@ -fn main() { - let profile = std::env::var("PROFILE").unwrap_or_default(); - - if profile == "release" { - println!("cargo:rustc-flag=-C"); - println!("cargo:rustc-flag=target-cpu=native"); - } -} diff --git a/crates/brk_client/src/lib.rs b/crates/brk_client/src/lib.rs index 66d2b63bb..e9958ebeb 100644 --- a/crates/brk_client/src/lib.rs +++ b/crates/brk_client/src/lib.rs @@ -1585,6 +1585,40 @@ impl BitcoinPattern { } } +/// Pattern struct for repeated tree structure. +pub struct ClassAveragePricePattern { + pub _2015: MetricPattern4, + pub _2016: MetricPattern4, + pub _2017: MetricPattern4, + pub _2018: MetricPattern4, + pub _2019: MetricPattern4, + pub _2020: MetricPattern4, + pub _2021: MetricPattern4, + pub _2022: MetricPattern4, + pub _2023: MetricPattern4, + pub _2024: MetricPattern4, + pub _2025: MetricPattern4, +} + +impl ClassAveragePricePattern { + /// Create a new pattern node with accumulated metric name. + pub fn new(client: Arc, acc: String) -> Self { + Self { + _2015: MetricPattern4::new(client.clone(), _m(&acc, "2015_average_price")), + _2016: MetricPattern4::new(client.clone(), _m(&acc, "2016_average_price")), + _2017: MetricPattern4::new(client.clone(), _m(&acc, "2017_average_price")), + _2018: MetricPattern4::new(client.clone(), _m(&acc, "2018_average_price")), + _2019: MetricPattern4::new(client.clone(), _m(&acc, "2019_average_price")), + _2020: MetricPattern4::new(client.clone(), _m(&acc, "2020_average_price")), + _2021: MetricPattern4::new(client.clone(), _m(&acc, "2021_average_price")), + _2022: MetricPattern4::new(client.clone(), _m(&acc, "2022_average_price")), + _2023: MetricPattern4::new(client.clone(), _m(&acc, "2023_average_price")), + _2024: MetricPattern4::new(client.clone(), _m(&acc, "2024_average_price")), + _2025: MetricPattern4::new(client.clone(), _m(&acc, "2025_average_price")), + } + } +} + /// Pattern struct for repeated tree structure. pub struct DollarsPattern { pub average: MetricPattern2, @@ -1620,35 +1654,33 @@ impl DollarsPattern { } /// Pattern struct for repeated tree structure. -pub struct ClassAveragePricePattern { - pub _2015: MetricPattern4, - pub _2016: MetricPattern4, - pub _2017: MetricPattern4, - pub _2018: MetricPattern4, - pub _2019: MetricPattern4, - pub _2020: MetricPattern4, - pub _2021: MetricPattern4, - pub _2022: MetricPattern4, - pub _2023: MetricPattern4, - pub _2024: MetricPattern4, - pub _2025: MetricPattern4, +pub struct RelativePattern2 { + pub neg_unrealized_loss_rel_to_own_market_cap: MetricPattern1, + pub neg_unrealized_loss_rel_to_own_total_unrealized_pnl: MetricPattern1, + pub net_unrealized_pnl_rel_to_own_market_cap: MetricPattern1, + pub net_unrealized_pnl_rel_to_own_total_unrealized_pnl: MetricPattern1, + pub supply_in_loss_rel_to_own_supply: MetricPattern1, + pub supply_in_profit_rel_to_own_supply: MetricPattern1, + pub unrealized_loss_rel_to_own_market_cap: MetricPattern1, + pub unrealized_loss_rel_to_own_total_unrealized_pnl: MetricPattern1, + pub unrealized_profit_rel_to_own_market_cap: MetricPattern1, + pub unrealized_profit_rel_to_own_total_unrealized_pnl: MetricPattern1, } -impl ClassAveragePricePattern { +impl RelativePattern2 { /// Create a new pattern node with accumulated metric name. pub fn new(client: Arc, acc: String) -> Self { Self { - _2015: MetricPattern4::new(client.clone(), _m(&acc, "2015_returns")), - _2016: MetricPattern4::new(client.clone(), _m(&acc, "2016_returns")), - _2017: MetricPattern4::new(client.clone(), _m(&acc, "2017_returns")), - _2018: MetricPattern4::new(client.clone(), _m(&acc, "2018_returns")), - _2019: MetricPattern4::new(client.clone(), _m(&acc, "2019_returns")), - _2020: MetricPattern4::new(client.clone(), _m(&acc, "2020_returns")), - _2021: MetricPattern4::new(client.clone(), _m(&acc, "2021_returns")), - _2022: MetricPattern4::new(client.clone(), _m(&acc, "2022_returns")), - _2023: MetricPattern4::new(client.clone(), _m(&acc, "2023_returns")), - _2024: MetricPattern4::new(client.clone(), _m(&acc, "2024_returns")), - _2025: MetricPattern4::new(client.clone(), _m(&acc, "2025_returns")), + neg_unrealized_loss_rel_to_own_market_cap: MetricPattern1::new(client.clone(), _m(&acc, "neg_unrealized_loss_rel_to_own_market_cap")), + neg_unrealized_loss_rel_to_own_total_unrealized_pnl: MetricPattern1::new(client.clone(), _m(&acc, "neg_unrealized_loss_rel_to_own_total_unrealized_pnl")), + net_unrealized_pnl_rel_to_own_market_cap: MetricPattern1::new(client.clone(), _m(&acc, "net_unrealized_pnl_rel_to_own_market_cap")), + net_unrealized_pnl_rel_to_own_total_unrealized_pnl: MetricPattern1::new(client.clone(), _m(&acc, "net_unrealized_pnl_rel_to_own_total_unrealized_pnl")), + supply_in_loss_rel_to_own_supply: MetricPattern1::new(client.clone(), _m(&acc, "supply_in_loss_rel_to_own_supply")), + supply_in_profit_rel_to_own_supply: MetricPattern1::new(client.clone(), _m(&acc, "supply_in_profit_rel_to_own_supply")), + unrealized_loss_rel_to_own_market_cap: MetricPattern1::new(client.clone(), _m(&acc, "unrealized_loss_rel_to_own_market_cap")), + unrealized_loss_rel_to_own_total_unrealized_pnl: MetricPattern1::new(client.clone(), _m(&acc, "unrealized_loss_rel_to_own_total_unrealized_pnl")), + unrealized_profit_rel_to_own_market_cap: MetricPattern1::new(client.clone(), _m(&acc, "unrealized_profit_rel_to_own_market_cap")), + unrealized_profit_rel_to_own_total_unrealized_pnl: MetricPattern1::new(client.clone(), _m(&acc, "unrealized_profit_rel_to_own_total_unrealized_pnl")), } } } @@ -1685,38 +1717,6 @@ impl RelativePattern { } } -/// Pattern struct for repeated tree structure. -pub struct RelativePattern2 { - pub neg_unrealized_loss_rel_to_own_market_cap: MetricPattern1, - pub neg_unrealized_loss_rel_to_own_total_unrealized_pnl: MetricPattern1, - pub net_unrealized_pnl_rel_to_own_market_cap: MetricPattern1, - pub net_unrealized_pnl_rel_to_own_total_unrealized_pnl: MetricPattern1, - pub supply_in_loss_rel_to_own_supply: MetricPattern1, - pub supply_in_profit_rel_to_own_supply: MetricPattern1, - pub unrealized_loss_rel_to_own_market_cap: MetricPattern1, - pub unrealized_loss_rel_to_own_total_unrealized_pnl: MetricPattern1, - pub unrealized_profit_rel_to_own_market_cap: MetricPattern1, - pub unrealized_profit_rel_to_own_total_unrealized_pnl: MetricPattern1, -} - -impl RelativePattern2 { - /// Create a new pattern node with accumulated metric name. - pub fn new(client: Arc, acc: String) -> Self { - Self { - neg_unrealized_loss_rel_to_own_market_cap: MetricPattern1::new(client.clone(), _m(&acc, "neg_unrealized_loss_rel_to_own_market_cap")), - neg_unrealized_loss_rel_to_own_total_unrealized_pnl: MetricPattern1::new(client.clone(), _m(&acc, "neg_unrealized_loss_rel_to_own_total_unrealized_pnl")), - net_unrealized_pnl_rel_to_own_market_cap: MetricPattern1::new(client.clone(), _m(&acc, "net_unrealized_pnl_rel_to_own_market_cap")), - net_unrealized_pnl_rel_to_own_total_unrealized_pnl: MetricPattern1::new(client.clone(), _m(&acc, "net_unrealized_pnl_rel_to_own_total_unrealized_pnl")), - supply_in_loss_rel_to_own_supply: MetricPattern1::new(client.clone(), _m(&acc, "supply_in_loss_rel_to_own_supply")), - supply_in_profit_rel_to_own_supply: MetricPattern1::new(client.clone(), _m(&acc, "supply_in_profit_rel_to_own_supply")), - unrealized_loss_rel_to_own_market_cap: MetricPattern1::new(client.clone(), _m(&acc, "unrealized_loss_rel_to_own_market_cap")), - unrealized_loss_rel_to_own_total_unrealized_pnl: MetricPattern1::new(client.clone(), _m(&acc, "unrealized_loss_rel_to_own_total_unrealized_pnl")), - unrealized_profit_rel_to_own_market_cap: MetricPattern1::new(client.clone(), _m(&acc, "unrealized_profit_rel_to_own_market_cap")), - unrealized_profit_rel_to_own_total_unrealized_pnl: MetricPattern1::new(client.clone(), _m(&acc, "unrealized_profit_rel_to_own_total_unrealized_pnl")), - } - } -} - /// Pattern struct for repeated tree structure. pub struct CountPattern2 { pub average: MetricPattern1, @@ -1779,36 +1779,6 @@ impl AddrCountPattern { } } -/// Pattern struct for repeated tree structure. -pub struct FeeRatePattern { - pub average: MetricPattern1, - pub max: MetricPattern1, - pub median: MetricPattern11, - pub min: MetricPattern1, - pub pct10: MetricPattern11, - pub pct25: MetricPattern11, - pub pct75: MetricPattern11, - pub pct90: MetricPattern11, - pub txindex: MetricPattern27, -} - -impl FeeRatePattern { - /// Create a new pattern node with accumulated metric name. - pub fn new(client: Arc, acc: String) -> Self { - Self { - average: MetricPattern1::new(client.clone(), _m(&acc, "average")), - max: MetricPattern1::new(client.clone(), _m(&acc, "max")), - median: MetricPattern11::new(client.clone(), _m(&acc, "median")), - min: MetricPattern1::new(client.clone(), _m(&acc, "min")), - pct10: MetricPattern11::new(client.clone(), _m(&acc, "pct10")), - pct25: MetricPattern11::new(client.clone(), _m(&acc, "pct25")), - pct75: MetricPattern11::new(client.clone(), _m(&acc, "pct75")), - pct90: MetricPattern11::new(client.clone(), _m(&acc, "pct90")), - txindex: MetricPattern27::new(client.clone(), acc.clone()), - } - } -} - /// Pattern struct for repeated tree structure. pub struct FullnessPattern { pub average: MetricPattern2, @@ -1839,6 +1809,36 @@ impl FullnessPattern { } } +/// Pattern struct for repeated tree structure. +pub struct FeeRatePattern { + pub average: MetricPattern1, + pub max: MetricPattern1, + pub median: MetricPattern11, + pub min: MetricPattern1, + pub pct10: MetricPattern11, + pub pct25: MetricPattern11, + pub pct75: MetricPattern11, + pub pct90: MetricPattern11, + pub txindex: MetricPattern27, +} + +impl FeeRatePattern { + /// Create a new pattern node with accumulated metric name. + pub fn new(client: Arc, acc: String) -> Self { + Self { + average: MetricPattern1::new(client.clone(), _m(&acc, "average")), + max: MetricPattern1::new(client.clone(), _m(&acc, "max")), + median: MetricPattern11::new(client.clone(), _m(&acc, "median")), + min: MetricPattern1::new(client.clone(), _m(&acc, "min")), + pct10: MetricPattern11::new(client.clone(), _m(&acc, "pct10")), + pct25: MetricPattern11::new(client.clone(), _m(&acc, "pct25")), + pct75: MetricPattern11::new(client.clone(), _m(&acc, "pct75")), + pct90: MetricPattern11::new(client.clone(), _m(&acc, "pct90")), + txindex: MetricPattern27::new(client.clone(), acc.clone()), + } + } +} + /// Pattern struct for repeated tree structure. pub struct _0satsPattern { pub activity: ActivityPattern2, @@ -1868,79 +1868,27 @@ impl _0satsPattern { } /// Pattern struct for repeated tree structure. -pub struct _100btcPattern { - pub activity: ActivityPattern2, - pub cost_basis: CostBasisPattern, - pub outputs: OutputsPattern, - pub realized: RealizedPattern, - pub relative: RelativePattern, - pub supply: SupplyPattern2, - pub unrealized: UnrealizedPattern, +pub struct PeriodCagrPattern { + pub _10y: MetricPattern4, + pub _2y: MetricPattern4, + pub _3y: MetricPattern4, + pub _4y: MetricPattern4, + pub _5y: MetricPattern4, + pub _6y: MetricPattern4, + pub _8y: MetricPattern4, } -impl _100btcPattern { +impl PeriodCagrPattern { /// Create a new pattern node with accumulated metric name. pub fn new(client: Arc, acc: String) -> Self { Self { - activity: ActivityPattern2::new(client.clone(), acc.clone()), - cost_basis: CostBasisPattern::new(client.clone(), acc.clone()), - outputs: OutputsPattern::new(client.clone(), _m(&acc, "utxo_count")), - realized: RealizedPattern::new(client.clone(), acc.clone()), - relative: RelativePattern::new(client.clone(), acc.clone()), - supply: SupplyPattern2::new(client.clone(), _m(&acc, "supply")), - unrealized: UnrealizedPattern::new(client.clone(), acc.clone()), - } - } -} - -/// Pattern struct for repeated tree structure. -pub struct _10yTo12yPattern { - pub activity: ActivityPattern2, - pub cost_basis: CostBasisPattern2, - pub outputs: OutputsPattern, - pub realized: RealizedPattern2, - pub relative: RelativePattern2, - pub supply: SupplyPattern2, - pub unrealized: UnrealizedPattern, -} - -impl _10yTo12yPattern { - /// Create a new pattern node with accumulated metric name. - pub fn new(client: Arc, acc: String) -> Self { - Self { - activity: ActivityPattern2::new(client.clone(), acc.clone()), - cost_basis: CostBasisPattern2::new(client.clone(), acc.clone()), - outputs: OutputsPattern::new(client.clone(), _m(&acc, "utxo_count")), - realized: RealizedPattern2::new(client.clone(), acc.clone()), - relative: RelativePattern2::new(client.clone(), acc.clone()), - supply: SupplyPattern2::new(client.clone(), _m(&acc, "supply")), - unrealized: UnrealizedPattern::new(client.clone(), acc.clone()), - } - } -} - -/// Pattern struct for repeated tree structure. -pub struct _10yPattern { - pub activity: ActivityPattern2, - pub cost_basis: CostBasisPattern, - pub outputs: OutputsPattern, - pub realized: RealizedPattern4, - pub relative: RelativePattern, - pub supply: SupplyPattern2, - pub unrealized: UnrealizedPattern, -} - -impl _10yPattern { - /// Create a new pattern node with accumulated metric name. - pub fn new(client: Arc, acc: String) -> Self { - Self { - activity: ActivityPattern2::new(client.clone(), acc.clone()), - cost_basis: CostBasisPattern::new(client.clone(), acc.clone()), - outputs: OutputsPattern::new(client.clone(), _m(&acc, "utxo_count")), - realized: RealizedPattern4::new(client.clone(), acc.clone()), - relative: RelativePattern::new(client.clone(), acc.clone()), - supply: SupplyPattern2::new(client.clone(), _m(&acc, "supply")), - unrealized: UnrealizedPattern::new(client.clone(), acc.clone()), + _10y: MetricPattern4::new(client.clone(), _p("10y", &acc)), + _2y: MetricPattern4::new(client.clone(), _p("2y", &acc)), + _3y: MetricPattern4::new(client.clone(), _p("3y", &acc)), + _4y: MetricPattern4::new(client.clone(), _p("4y", &acc)), + _5y: MetricPattern4::new(client.clone(), _p("5y", &acc)), + _6y: MetricPattern4::new(client.clone(), _p("6y", &acc)), + _8y: MetricPattern4::new(client.clone(), _p("8y", &acc)), } } } @@ -1998,27 +1946,79 @@ impl _0satsPattern2 { } /// Pattern struct for repeated tree structure. -pub struct PeriodCagrPattern { - pub _10y: MetricPattern4, - pub _2y: MetricPattern4, - pub _3y: MetricPattern4, - pub _4y: MetricPattern4, - pub _5y: MetricPattern4, - pub _6y: MetricPattern4, - pub _8y: MetricPattern4, +pub struct _100btcPattern { + pub activity: ActivityPattern2, + pub cost_basis: CostBasisPattern, + pub outputs: OutputsPattern, + pub realized: RealizedPattern, + pub relative: RelativePattern, + pub supply: SupplyPattern2, + pub unrealized: UnrealizedPattern, } -impl PeriodCagrPattern { +impl _100btcPattern { /// Create a new pattern node with accumulated metric name. pub fn new(client: Arc, acc: String) -> Self { Self { - _10y: MetricPattern4::new(client.clone(), _p("10y", &acc)), - _2y: MetricPattern4::new(client.clone(), _p("2y", &acc)), - _3y: MetricPattern4::new(client.clone(), _p("3y", &acc)), - _4y: MetricPattern4::new(client.clone(), _p("4y", &acc)), - _5y: MetricPattern4::new(client.clone(), _p("5y", &acc)), - _6y: MetricPattern4::new(client.clone(), _p("6y", &acc)), - _8y: MetricPattern4::new(client.clone(), _p("8y", &acc)), + activity: ActivityPattern2::new(client.clone(), acc.clone()), + cost_basis: CostBasisPattern::new(client.clone(), acc.clone()), + outputs: OutputsPattern::new(client.clone(), _m(&acc, "utxo_count")), + realized: RealizedPattern::new(client.clone(), acc.clone()), + relative: RelativePattern::new(client.clone(), acc.clone()), + supply: SupplyPattern2::new(client.clone(), _m(&acc, "supply")), + unrealized: UnrealizedPattern::new(client.clone(), acc.clone()), + } + } +} + +/// Pattern struct for repeated tree structure. +pub struct _10yPattern { + pub activity: ActivityPattern2, + pub cost_basis: CostBasisPattern, + pub outputs: OutputsPattern, + pub realized: RealizedPattern4, + pub relative: RelativePattern, + pub supply: SupplyPattern2, + pub unrealized: UnrealizedPattern, +} + +impl _10yPattern { + /// Create a new pattern node with accumulated metric name. + pub fn new(client: Arc, acc: String) -> Self { + Self { + activity: ActivityPattern2::new(client.clone(), acc.clone()), + cost_basis: CostBasisPattern::new(client.clone(), acc.clone()), + outputs: OutputsPattern::new(client.clone(), _m(&acc, "utxo_count")), + realized: RealizedPattern4::new(client.clone(), acc.clone()), + relative: RelativePattern::new(client.clone(), acc.clone()), + supply: SupplyPattern2::new(client.clone(), _m(&acc, "supply")), + unrealized: UnrealizedPattern::new(client.clone(), acc.clone()), + } + } +} + +/// Pattern struct for repeated tree structure. +pub struct _10yTo12yPattern { + pub activity: ActivityPattern2, + pub cost_basis: CostBasisPattern2, + pub outputs: OutputsPattern, + pub realized: RealizedPattern2, + pub relative: RelativePattern2, + pub supply: SupplyPattern2, + pub unrealized: UnrealizedPattern, +} + +impl _10yTo12yPattern { + /// Create a new pattern node with accumulated metric name. + pub fn new(client: Arc, acc: String) -> Self { + Self { + activity: ActivityPattern2::new(client.clone(), acc.clone()), + cost_basis: CostBasisPattern2::new(client.clone(), acc.clone()), + outputs: OutputsPattern::new(client.clone(), _m(&acc, "utxo_count")), + realized: RealizedPattern2::new(client.clone(), acc.clone()), + relative: RelativePattern2::new(client.clone(), acc.clone()), + supply: SupplyPattern2::new(client.clone(), _m(&acc, "supply")), + unrealized: UnrealizedPattern::new(client.clone(), acc.clone()), } } } @@ -2066,91 +2066,19 @@ impl SplitPattern2 { } /// Pattern struct for repeated tree structure. -pub struct CostBasisPattern2 { - pub max: MetricPattern1, - pub min: MetricPattern1, - pub percentiles: PercentilesPattern, +pub struct ActiveSupplyPattern { + pub bitcoin: MetricPattern1, + pub dollars: MetricPattern1, + pub sats: MetricPattern1, } -impl CostBasisPattern2 { +impl ActiveSupplyPattern { /// Create a new pattern node with accumulated metric name. pub fn new(client: Arc, acc: String) -> Self { Self { - max: MetricPattern1::new(client.clone(), _m(&acc, "max_cost_basis")), - min: MetricPattern1::new(client.clone(), _m(&acc, "min_cost_basis")), - percentiles: PercentilesPattern::new(client.clone(), _m(&acc, "cost_basis")), - } - } -} - -/// Pattern struct for repeated tree structure. -pub struct SegwitAdoptionPattern { - pub base: MetricPattern11, - pub cumulative: MetricPattern2, - pub sum: MetricPattern2, -} - -impl SegwitAdoptionPattern { - /// Create a new pattern node with accumulated metric name. - pub fn new(client: Arc, acc: String) -> Self { - Self { - base: MetricPattern11::new(client.clone(), acc.clone()), - cumulative: MetricPattern2::new(client.clone(), _m(&acc, "cumulative")), - sum: MetricPattern2::new(client.clone(), _m(&acc, "sum")), - } - } -} - -/// Pattern struct for repeated tree structure. -pub struct UnclaimedRewardsPattern { - pub bitcoin: BitcoinPattern2, - pub dollars: BlockCountPattern, - pub sats: BlockCountPattern, -} - -impl UnclaimedRewardsPattern { - /// Create a new pattern node with accumulated metric name. - pub fn new(client: Arc, acc: String) -> Self { - Self { - bitcoin: BitcoinPattern2::new(client.clone(), _m(&acc, "btc")), - dollars: BlockCountPattern::new(client.clone(), _m(&acc, "usd")), - sats: BlockCountPattern::new(client.clone(), acc.clone()), - } - } -} - -/// Pattern struct for repeated tree structure. -pub struct CoinbasePattern { - pub bitcoin: BitcoinPattern, - pub dollars: DollarsPattern, - pub sats: DollarsPattern, -} - -impl CoinbasePattern { - /// Create a new pattern node with accumulated metric name. - pub fn new(client: Arc, acc: String) -> Self { - Self { - bitcoin: BitcoinPattern::new(client.clone(), _m(&acc, "btc")), - dollars: DollarsPattern::new(client.clone(), _m(&acc, "usd")), - sats: DollarsPattern::new(client.clone(), acc.clone()), - } - } -} - -/// Pattern struct for repeated tree structure. -pub struct _2015Pattern { - pub bitcoin: MetricPattern4, - pub dollars: MetricPattern4, - pub sats: MetricPattern4, -} - -impl _2015Pattern { - /// Create a new pattern node with accumulated metric name. - pub fn new(client: Arc, acc: String) -> Self { - Self { - bitcoin: MetricPattern4::new(client.clone(), _m(&acc, "btc")), - dollars: MetricPattern4::new(client.clone(), _m(&acc, "usd")), - sats: MetricPattern4::new(client.clone(), acc.clone()), + bitcoin: MetricPattern1::new(client.clone(), _m(&acc, "btc")), + dollars: MetricPattern1::new(client.clone(), _m(&acc, "usd")), + sats: MetricPattern1::new(client.clone(), acc.clone()), } } } @@ -2174,35 +2102,107 @@ impl CoinbasePattern2 { } /// Pattern struct for repeated tree structure. -pub struct ActiveSupplyPattern { - pub bitcoin: MetricPattern1, - pub dollars: MetricPattern1, - pub sats: MetricPattern1, +pub struct _2015Pattern { + pub bitcoin: MetricPattern4, + pub dollars: MetricPattern4, + pub sats: MetricPattern4, } -impl ActiveSupplyPattern { +impl _2015Pattern { /// Create a new pattern node with accumulated metric name. pub fn new(client: Arc, acc: String) -> Self { Self { - bitcoin: MetricPattern1::new(client.clone(), _m(&acc, "btc")), - dollars: MetricPattern1::new(client.clone(), _m(&acc, "usd")), - sats: MetricPattern1::new(client.clone(), acc.clone()), + bitcoin: MetricPattern4::new(client.clone(), _m(&acc, "btc")), + dollars: MetricPattern4::new(client.clone(), _m(&acc, "usd")), + sats: MetricPattern4::new(client.clone(), acc.clone()), } } } /// Pattern struct for repeated tree structure. -pub struct _1dReturns1mSdPattern { - pub sd: MetricPattern4, - pub sma: MetricPattern4, +pub struct CoinbasePattern { + pub bitcoin: BitcoinPattern, + pub dollars: DollarsPattern, + pub sats: DollarsPattern, } -impl _1dReturns1mSdPattern { +impl CoinbasePattern { /// Create a new pattern node with accumulated metric name. pub fn new(client: Arc, acc: String) -> Self { Self { - sd: MetricPattern4::new(client.clone(), _m(&acc, "sd")), - sma: MetricPattern4::new(client.clone(), _m(&acc, "sma")), + bitcoin: BitcoinPattern::new(client.clone(), _m(&acc, "btc")), + dollars: DollarsPattern::new(client.clone(), _m(&acc, "usd")), + sats: DollarsPattern::new(client.clone(), acc.clone()), + } + } +} + +/// Pattern struct for repeated tree structure. +pub struct UnclaimedRewardsPattern { + pub bitcoin: BitcoinPattern2, + pub dollars: BlockCountPattern, + pub sats: BlockCountPattern, +} + +impl UnclaimedRewardsPattern { + /// Create a new pattern node with accumulated metric name. + pub fn new(client: Arc, acc: String) -> Self { + Self { + bitcoin: BitcoinPattern2::new(client.clone(), _m(&acc, "btc")), + dollars: BlockCountPattern::new(client.clone(), _m(&acc, "usd")), + sats: BlockCountPattern::new(client.clone(), acc.clone()), + } + } +} + +/// Pattern struct for repeated tree structure. +pub struct SegwitAdoptionPattern { + pub base: MetricPattern11, + pub cumulative: MetricPattern2, + pub sum: MetricPattern2, +} + +impl SegwitAdoptionPattern { + /// Create a new pattern node with accumulated metric name. + pub fn new(client: Arc, acc: String) -> Self { + Self { + base: MetricPattern11::new(client.clone(), acc.clone()), + cumulative: MetricPattern2::new(client.clone(), _m(&acc, "cumulative")), + sum: MetricPattern2::new(client.clone(), _m(&acc, "sum")), + } + } +} + +/// Pattern struct for repeated tree structure. +pub struct CostBasisPattern2 { + pub max: MetricPattern1, + pub min: MetricPattern1, + pub percentiles: PercentilesPattern, +} + +impl CostBasisPattern2 { + /// Create a new pattern node with accumulated metric name. + pub fn new(client: Arc, acc: String) -> Self { + Self { + max: MetricPattern1::new(client.clone(), _m(&acc, "max_cost_basis")), + min: MetricPattern1::new(client.clone(), _m(&acc, "min_cost_basis")), + percentiles: PercentilesPattern::new(client.clone(), _m(&acc, "cost_basis")), + } + } +} + +/// Pattern struct for repeated tree structure. +pub struct CostBasisPattern { + pub max: MetricPattern1, + pub min: MetricPattern1, +} + +impl CostBasisPattern { + /// Create a new pattern node with accumulated metric name. + pub fn new(client: Arc, acc: String) -> Self { + Self { + max: MetricPattern1::new(client.clone(), _m(&acc, "max_cost_basis")), + min: MetricPattern1::new(client.clone(), _m(&acc, "min_cost_basis")), } } } @@ -2240,49 +2240,17 @@ impl RelativePattern4 { } /// Pattern struct for repeated tree structure. -pub struct CostBasisPattern { - pub max: MetricPattern1, - pub min: MetricPattern1, +pub struct _1dReturns1mSdPattern { + pub sd: MetricPattern4, + pub sma: MetricPattern4, } -impl CostBasisPattern { +impl _1dReturns1mSdPattern { /// Create a new pattern node with accumulated metric name. pub fn new(client: Arc, acc: String) -> Self { Self { - max: MetricPattern1::new(client.clone(), _m(&acc, "max_cost_basis")), - min: MetricPattern1::new(client.clone(), _m(&acc, "min_cost_basis")), - } - } -} - -/// Pattern struct for repeated tree structure. -pub struct SatsPattern { - pub ohlc: MetricPattern1, - pub split: SplitPattern2, -} - -impl SatsPattern { - /// Create a new pattern node with accumulated metric name. - pub fn new(client: Arc, acc: String) -> Self { - Self { - ohlc: MetricPattern1::new(client.clone(), _m(&acc, "ohlc")), - split: SplitPattern2::new(client.clone(), acc.clone()), - } - } -} - -/// Pattern struct for repeated tree structure. -pub struct BitcoinPattern2 { - pub cumulative: MetricPattern2, - pub sum: MetricPattern1, -} - -impl BitcoinPattern2 { - /// Create a new pattern node with accumulated metric name. - pub fn new(client: Arc, acc: String) -> Self { - Self { - cumulative: MetricPattern2::new(client.clone(), _m(&acc, "cumulative")), - sum: MetricPattern1::new(client.clone(), acc.clone()), + sd: MetricPattern4::new(client.clone(), _m(&acc, "sd")), + sma: MetricPattern4::new(client.clone(), _m(&acc, "sma")), } } } @@ -2303,6 +2271,38 @@ impl BlockCountPattern { } } +/// Pattern struct for repeated tree structure. +pub struct SatsPattern { + pub ohlc: MetricPattern1, + pub split: SplitPattern2, +} + +impl SatsPattern { + /// Create a new pattern node with accumulated metric name. + pub fn new(client: Arc, acc: String) -> Self { + Self { + ohlc: MetricPattern1::new(client.clone(), _m(&acc, "ohlc_sats")), + split: SplitPattern2::new(client.clone(), _m(&acc, "sats")), + } + } +} + +/// Pattern struct for repeated tree structure. +pub struct BitcoinPattern2 { + pub cumulative: MetricPattern2, + pub sum: MetricPattern1, +} + +impl BitcoinPattern2 { + /// Create a new pattern node with accumulated metric name. + pub fn new(client: Arc, acc: String) -> Self { + Self { + cumulative: MetricPattern2::new(client.clone(), _m(&acc, "cumulative")), + sum: MetricPattern1::new(client.clone(), acc.clone()), + } + } +} + /// Pattern struct for repeated tree structure. pub struct OutputsPattern { pub utxo_count: MetricPattern1, @@ -9300,8 +9300,8 @@ impl MetricsTree_Market_Ath { /// Metrics tree node. pub struct MetricsTree_Market_Dca { - pub class_average_price: MetricsTree_Market_Dca_ClassAveragePrice, - pub class_returns: ClassAveragePricePattern, + pub class_average_price: ClassAveragePricePattern, + pub class_returns: MetricsTree_Market_Dca_ClassReturns, pub class_stack: MetricsTree_Market_Dca_ClassStack, pub period_average_price: PeriodAveragePricePattern, pub period_cagr: PeriodCagrPattern, @@ -9313,8 +9313,8 @@ pub struct MetricsTree_Market_Dca { impl MetricsTree_Market_Dca { pub fn new(client: Arc, base_path: String) -> Self { Self { - class_average_price: MetricsTree_Market_Dca_ClassAveragePrice::new(client.clone(), format!("{base_path}_class_average_price")), - class_returns: ClassAveragePricePattern::new(client.clone(), "dca_class".to_string()), + class_average_price: ClassAveragePricePattern::new(client.clone(), "dca_class".to_string()), + class_returns: MetricsTree_Market_Dca_ClassReturns::new(client.clone(), format!("{base_path}_class_returns")), class_stack: MetricsTree_Market_Dca_ClassStack::new(client.clone(), format!("{base_path}_class_stack")), period_average_price: PeriodAveragePricePattern::new(client.clone(), "dca_average_price".to_string()), period_cagr: PeriodCagrPattern::new(client.clone(), "dca_cagr".to_string()), @@ -9326,34 +9326,34 @@ impl MetricsTree_Market_Dca { } /// Metrics tree node. -pub struct MetricsTree_Market_Dca_ClassAveragePrice { - pub _2015: MetricPattern4, - pub _2016: MetricPattern4, - pub _2017: MetricPattern4, - pub _2018: MetricPattern4, - pub _2019: MetricPattern4, - pub _2020: MetricPattern4, - pub _2021: MetricPattern4, - pub _2022: MetricPattern4, - pub _2023: MetricPattern4, - pub _2024: MetricPattern4, - pub _2025: MetricPattern4, +pub struct MetricsTree_Market_Dca_ClassReturns { + pub _2015: MetricPattern4, + pub _2016: MetricPattern4, + pub _2017: MetricPattern4, + pub _2018: MetricPattern4, + pub _2019: MetricPattern4, + pub _2020: MetricPattern4, + pub _2021: MetricPattern4, + pub _2022: MetricPattern4, + pub _2023: MetricPattern4, + pub _2024: MetricPattern4, + pub _2025: MetricPattern4, } -impl MetricsTree_Market_Dca_ClassAveragePrice { +impl MetricsTree_Market_Dca_ClassReturns { pub fn new(client: Arc, base_path: String) -> Self { Self { - _2015: MetricPattern4::new(client.clone(), "dca_class_2015_average_price".to_string()), - _2016: MetricPattern4::new(client.clone(), "dca_class_2016_average_price".to_string()), - _2017: MetricPattern4::new(client.clone(), "dca_class_2017_average_price".to_string()), - _2018: MetricPattern4::new(client.clone(), "dca_class_2018_average_price".to_string()), - _2019: MetricPattern4::new(client.clone(), "dca_class_2019_average_price".to_string()), - _2020: MetricPattern4::new(client.clone(), "dca_class_2020_average_price".to_string()), - _2021: MetricPattern4::new(client.clone(), "dca_class_2021_average_price".to_string()), - _2022: MetricPattern4::new(client.clone(), "dca_class_2022_average_price".to_string()), - _2023: MetricPattern4::new(client.clone(), "dca_class_2023_average_price".to_string()), - _2024: MetricPattern4::new(client.clone(), "dca_class_2024_average_price".to_string()), - _2025: MetricPattern4::new(client.clone(), "dca_class_2025_average_price".to_string()), + _2015: MetricPattern4::new(client.clone(), "dca_class_2015_returns".to_string()), + _2016: MetricPattern4::new(client.clone(), "dca_class_2016_returns".to_string()), + _2017: MetricPattern4::new(client.clone(), "dca_class_2017_returns".to_string()), + _2018: MetricPattern4::new(client.clone(), "dca_class_2018_returns".to_string()), + _2019: MetricPattern4::new(client.clone(), "dca_class_2019_returns".to_string()), + _2020: MetricPattern4::new(client.clone(), "dca_class_2020_returns".to_string()), + _2021: MetricPattern4::new(client.clone(), "dca_class_2021_returns".to_string()), + _2022: MetricPattern4::new(client.clone(), "dca_class_2022_returns".to_string()), + _2023: MetricPattern4::new(client.clone(), "dca_class_2023_returns".to_string()), + _2024: MetricPattern4::new(client.clone(), "dca_class_2024_returns".to_string()), + _2025: MetricPattern4::new(client.clone(), "dca_class_2025_returns".to_string()), } } } @@ -11757,7 +11757,7 @@ impl MetricsTree_Price_Oracle { Self { ohlc_cents: MetricPattern6::new(client.clone(), "oracle_ohlc_cents".to_string()), ohlc_dollars: MetricPattern6::new(client.clone(), "oracle_ohlc".to_string()), - price_cents: MetricPattern11::new(client.clone(), "orange_price_cents".to_string()), + price_cents: MetricPattern11::new(client.clone(), "oracle_price_cents".to_string()), tx_count: MetricPattern6::new(client.clone(), "oracle_tx_count".to_string()), } } diff --git a/crates/brk_cohort/Cargo.toml b/crates/brk_cohort/Cargo.toml index 9ccd74961..ca5568103 100644 --- a/crates/brk_cohort/Cargo.toml +++ b/crates/brk_cohort/Cargo.toml @@ -6,7 +6,6 @@ edition.workspace = true license.workspace = true homepage.workspace = true repository.workspace = true -build = "build.rs" [dependencies] brk_error = { workspace = true } diff --git a/crates/brk_cohort/README.md b/crates/brk_cohort/README.md index 596e4e086..f8e1e34d6 100644 --- a/crates/brk_cohort/README.md +++ b/crates/brk_cohort/README.md @@ -4,13 +4,13 @@ UTXO and address cohort filtering for on-chain analytics. ## What It Enables -Slice the UTXO set and address population by age, amount, output type, halving epoch, or holder classification (STH/LTH). Build complex cohorts by combining filters for metrics like "realized cap of 1+ BTC UTXOs older than 155 days." +Slice the UTXO set and address population by age, amount, output type, halving epoch, or holder classification (STH/LTH). Build complex cohorts by combining filters for metrics like "realized cap of 1+ BTC UTXOs older than 150 days." ## Key Features -- **Age-based**: `TimeFilter::GreaterOrEqual(155)`, `TimeFilter::Range(30..90)`, `TimeFilter::LowerThan(7)` +- **Age-based**: `TimeFilter::GreaterOrEqual(hours)`, `TimeFilter::Range(hours..hours)`, `TimeFilter::LowerThan(hours)` - **Amount-based**: `AmountFilter::GreaterOrEqual(Sats::_1BTC)`, `AmountFilter::Range(Sats::_100K..Sats::_1M)` -- **Term classification**: `Term::Sth` (short-term holders, <155 days), `Term::Lth` (long-term holders) +- **Term classification**: `Term::Sth` (short-term holders, <150 days), `Term::Lth` (long-term holders) - **Epoch filters**: Group by halving epoch - **Type filters**: Segment by output type (P2PKH, P2TR, etc.) - **Context-aware naming**: Automatic prefix generation (`utxos_`, `addrs_`) based on cohort context @@ -25,6 +25,7 @@ pub enum Filter { Time(TimeFilter), // Age-based Amount(AmountFilter), // Value-based Epoch(HalvingEpoch), // Halving epoch + Year(Year), // Calendar year Type(OutputType), // P2PKH, P2TR, etc. } ``` @@ -32,15 +33,16 @@ pub enum Filter { ## Core API ```rust,ignore -let filter = Filter::Time(TimeFilter::GreaterOrEqual(155)); +// TimeFilter values are in hours (e.g., 3600 hours = 150 days) +let filter = Filter::Time(TimeFilter::GreaterOrEqual(3600)); // Check membership -filter.contains_time(200); // true +filter.contains_time(4000); // true (4000 hours > 3600 hours) filter.contains_amount(sats); // Generate metric names (via CohortContext) let ctx = CohortContext::Utxo; -ctx.full_name(&filter, "min_age_155d"); // "utxos_min_age_155d" +ctx.full_name(&filter, "min_age_150d"); // "utxos_min_age_150d" ``` ## Built On diff --git a/crates/brk_cohort/build.rs b/crates/brk_cohort/build.rs deleted file mode 100644 index a4055a31e..000000000 --- a/crates/brk_cohort/build.rs +++ /dev/null @@ -1,8 +0,0 @@ -fn main() { - let profile = std::env::var("PROFILE").unwrap_or_default(); - - if profile == "release" { - println!("cargo:rustc-flag=-C"); - println!("cargo:rustc-flag=target-cpu=native"); - } -} diff --git a/crates/brk_computer/Cargo.toml b/crates/brk_computer/Cargo.toml index 899af6b81..83a43dbaf 100644 --- a/crates/brk_computer/Cargo.toml +++ b/crates/brk_computer/Cargo.toml @@ -6,7 +6,6 @@ edition.workspace = true license.workspace = true homepage.workspace = true repository.workspace = true -build = "build.rs" [dependencies] bitcoin = { workspace = true } diff --git a/crates/brk_computer/README.md b/crates/brk_computer/README.md index ad8b1c3d1..157a85ff2 100644 --- a/crates/brk_computer/README.md +++ b/crates/brk_computer/README.md @@ -19,14 +19,14 @@ Compute 1000+ on-chain metrics from indexed blockchain data: supply breakdowns, ## Core API ```rust,ignore -let mut computer = Computer::forced_import(&outputs_path, &indexer, fetcher)?; +let mut computer = Computer::forced_import(&outputs_path, &indexer, Some(fetcher))?; // Compute all metrics for new blocks computer.compute(&indexer, starting_indexes, &reader, &exit)?; -// Access computed data -let supply = computer.distribution.utxo_cohorts.all.metrics.supply.height_to_supply.get(height)?; -let realized_cap = computer.distribution.utxo_cohorts.all.metrics.realized.height_to_realized_cap.get(height)?; +// Access computed data via traversable vecs +let supply = computer.distribution.utxo_cohorts.all.metrics.supply.total.sats.height; +let realized_cap = computer.distribution.utxo_cohorts.all.metrics.realized.unwrap().realized_cap.height; ``` ## Metric Categories @@ -45,9 +45,9 @@ let realized_cap = computer.distribution.utxo_cohorts.all.metrics.realized.heigh ## Cohort System UTXO and address cohorts support filtering by: -- **Age**: STH (<150d), LTH (≥150d), age bands (1d, 1w, 1m, 3m, 6m, 1y, 2y, ...) +- **Age**: STH (<150d), LTH (≥150d), 21 age bands (<1h, 1h-1d, 1d-1w, 1w-1m, 1m-2m, ..., 6m-1y, 1y-2y, ..., 12y-15y, 15y+) - **Amount**: 0-0.001 BTC, 0.001-0.01, ..., 10k+ BTC -- **Type**: P2PKH, P2SH, P2WPKH, P2WSH, P2TR +- **Type**: P2PK, P2PKH, P2MS, P2SH, P2WPKH, P2WSH, P2TR, P2A - **Epoch**: By halving epoch ## Performance @@ -58,9 +58,10 @@ Full pipeline benchmarks (indexer + computer): | Machine | Time | Disk | Peak Disk | Memory | Peak Memory | |---------|------|------|-----------|--------|-------------| -| MBP M3 Pro (36GB, internal SSD) | 5.2h | 341 GB | 415 GB | 6.4 GB | 12 GB | +| MBP M3 Pro (36GB, internal SSD) | 4.4h | 345 GB | 348 GB | 3.3 GB | 11 GB | +| Mac Mini M4 (16GB, external SSD) | 7h | 344 GB | 346 GB | 4 GB | 10 GB | -Full benchmark data: [`https://github.com/bitcoinresearchkit/benches/tree/main/brk`](/benches/brk) +Full benchmark data: [bitcoinresearchkit/benches](https://github.com/bitcoinresearchkit/benches/tree/main/brk) ## Recommended: mimalloc v3 diff --git a/crates/brk_computer/build.rs b/crates/brk_computer/build.rs deleted file mode 100644 index a4055a31e..000000000 --- a/crates/brk_computer/build.rs +++ /dev/null @@ -1,8 +0,0 @@ -fn main() { - let profile = std::env::var("PROFILE").unwrap_or_default(); - - if profile == "release" { - println!("cargo:rustc-flag=-C"); - println!("cargo:rustc-flag=target-cpu=native"); - } -} diff --git a/crates/brk_computer/src/price/oracle/compute.rs b/crates/brk_computer/src/price/oracle/compute.rs index 1cb19e2c8..1be3ce6ab 100644 --- a/crates/brk_computer/src/price/oracle/compute.rs +++ b/crates/brk_computer/src/price/oracle/compute.rs @@ -187,12 +187,14 @@ impl Vecs { continue; } - // Check witness size (SegWit era only, activated Aug 2017) + // Check witness size per input (SegWit era only, activated Aug 2017) // Pre-SegWit transactions have no witness data + // Python checks each input's witness ≤ 500 bytes; we approximate with average if cached_year >= 2017 { let base_size: StoredU32 = txindex_to_base_size_iter.get_at_unwrap(txindex); let total_size: StoredU32 = txindex_to_total_size_iter.get_at_unwrap(txindex); - if *total_size - *base_size > 500 { + let witness_size = *total_size - *base_size; + if witness_size / *input_count as u32 > 500 { continue; } } @@ -379,10 +381,9 @@ impl Vecs { } }; - self.ohlc_cents - .truncate_push_at(dateindex.to_usize(), ohlc)?; + self.ohlc_cents.truncate_push(dateindex, ohlc)?; self.tx_count - .truncate_push_at(dateindex.to_usize(), StoredU32::from(tx_count))?; + .truncate_push(dateindex, StoredU32::from(tx_count))?; } // Write daily data diff --git a/crates/brk_computer/src/price/oracle/config.rs b/crates/brk_computer/src/price/oracle/config.rs index 87a6f9d9b..e195b09d6 100644 --- a/crates/brk_computer/src/price/oracle/config.rs +++ b/crates/brk_computer/src/price/oracle/config.rs @@ -48,11 +48,12 @@ impl OracleConfig { blocks_per_window: 144, // ~1 day min_tx_count: 1000, }, - // 2017+: Modern era ($1,000 - $1,000,000+) + // 2017+: Modern era ($10,000 - $500,000) + // Matches Python's slide range of -141 to 201 _ => Self { - min_price_cents: 100_000, // $1,000 - max_price_cents: 100_000_000, // $1,000,000 - blocks_per_window: 144, // ~1 day + min_price_cents: 1_000_000, // $10,000 (gives max_slide = 200) + max_price_cents: 50_000_000, // $500,000 (gives min_slide ≈ -140) + blocks_per_window: 144, // ~1 day min_tx_count: 2000, }, } @@ -90,9 +91,10 @@ mod tests { #[test] fn test_config_for_year() { + // 2017+ config matches Python: $10,000 to $500,000 let c2020 = OracleConfig::for_year(2020); - assert_eq!(c2020.min_price_cents, 100_000); - assert_eq!(c2020.max_price_cents, 100_000_000); + assert_eq!(c2020.min_price_cents, 1_000_000); + assert_eq!(c2020.max_price_cents, 50_000_000); let c2015 = OracleConfig::for_year(2015); assert_eq!(c2015.min_price_cents, 10_000); @@ -101,13 +103,13 @@ mod tests { #[test] fn test_slide_range() { - // 2024 config: $1,000 to $1,000,000 + // 2024 config: $10,000 to $500,000 (matches Python's -141 to 201) let config = OracleConfig::for_year(2024); let (min, max) = config.slide_range(); - // $1,000,000 = 10^8 cents → slide = (7-8)*200 = -200 - // $1,000 = 10^5 cents → slide = (7-5)*200 = 400 - assert_eq!(min, -200); - assert_eq!(max, 400); + // $500,000 = 5*10^7 cents → slide = (7-7.699)*200 ≈ -140 + // $10,000 = 10^6 cents → slide = (7-6)*200 = 200 + assert!((-141..=-139).contains(&min)); // ~-140 + assert_eq!(max, 200); // 2015 config: $100 to $20,000 let config = OracleConfig::for_year(2015); diff --git a/crates/brk_computer/src/price/oracle/histogram.rs b/crates/brk_computer/src/price/oracle/histogram.rs index 18b7bc831..88afae1fe 100644 --- a/crates/brk_computer/src/price/oracle/histogram.rs +++ b/crates/brk_computer/src/price/oracle/histogram.rs @@ -11,10 +11,12 @@ pub const MAX_LOG_BTC: f64 = 2.0; // 10^2 BTC = 100 BTC pub const NUM_DECADES: usize = 8; // -6 to +2 pub const TOTAL_BINS: usize = NUM_DECADES * BINS_PER_DECADE; // 1600 bins -/// Minimum output value to consider (10,000 sats = 0.0001 BTC) -pub const MIN_OUTPUT_SATS: Sats = Sats::_10K; -/// Maximum output value to consider (10 BTC) -pub const MAX_OUTPUT_SATS: Sats = Sats::_10BTC; +/// Minimum output value to consider (~1,000 sats = 0.00001 BTC) +/// Matches Python: zeros bins 0-200 which is 10^-5 BTC +pub const MIN_OUTPUT_SATS: Sats = Sats::_1K; +/// Maximum output value to consider (100 BTC) +/// Matches Python: zeros bins 1601+ which is ~10^2 BTC +pub const MAX_OUTPUT_SATS: Sats = Sats::_100BTC; /// Round BTC bin indices that should be smoothed to avoid false positives /// These are bins where round BTC amounts would naturally cluster diff --git a/crates/brk_computer/src/price/oracle/import.rs b/crates/brk_computer/src/price/oracle/import.rs index e6c8004f6..1df260d89 100644 --- a/crates/brk_computer/src/price/oracle/import.rs +++ b/crates/brk_computer/src/price/oracle/import.rs @@ -5,8 +5,11 @@ use vecdb::{BytesVec, Database, ImportableVec, IterableCloneableVec, LazyVecFrom use super::Vecs; impl Vecs { - pub fn forced_import(db: &Database, version: Version) -> Result { - let price_cents = PcoVec::forced_import(db, "orange_price_cents", version)?; + pub fn forced_import(db: &Database, parent_version: Version) -> Result { + // v2: Fixed spike stencil positions and Gaussian center to match Python's empirical data + let version = parent_version + Version::TWO; + + let price_cents = PcoVec::forced_import(db, "oracle_price_cents", version)?; let ohlc_cents = BytesVec::forced_import(db, "oracle_ohlc_cents", version)?; let tx_count = PcoVec::forced_import(db, "oracle_tx_count", version)?; diff --git a/crates/brk_computer/src/price/oracle/stencil.rs b/crates/brk_computer/src/price/oracle/stencil.rs index e8fb63d41..efa5bd150 100644 --- a/crates/brk_computer/src/price/oracle/stencil.rs +++ b/crates/brk_computer/src/price/oracle/stencil.rs @@ -12,68 +12,66 @@ use super::histogram::{BINS_PER_DECADE, Histogram, TOTAL_BINS}; /// Number of parallel chunks for stencil sliding const PARALLEL_CHUNKS: i32 = 4; -/// USD spike stencil entries: (bin offset from $100 center, weight) +/// USD spike stencil entries: (bin offset from center_bin, weight) /// These represent the expected frequency of round USD amounts in transactions -/// Offset formula: log10(USD/100) * 200 bins/decade -/// Companion spikes at ±2 bins from main spike (Rust 200 bins/decade ≈ Python's ±1 at 180 bins/decade) -/// Matches Python's 29 entries from utxo_oracle.py lines 1013-1041 +/// Positions derived from Python's empirical data (utxo_oracle.py lines 1013-1041) +/// Offset = python_stencil_index - 402 (since Python stencil starts at bin 199, center is 601) const SPIKE_STENCIL: &[(i32, f64)] = &[ - // $1 (single) - (-400, 0.00130), - // $5 (single) - (-260, 0.00168), - // $10 (main + companion) - (-200, 0.00347), - (-198, 0.00199), - // $15 (single) - (-165, 0.00191), - // $20 (main + companion) - (-140, 0.00334), - (-138, 0.00259), - // $30 (main + companion) - (-105, 0.00258), - (-103, 0.00273), - // $50 (main + 2 companions) + // $1 (single) - Python index 40 + (-362, 0.00130), + // $5 (single) - Python index 141 + (-261, 0.00168), + // $10 (main + companion) - Python indices 201-202 + (-201, 0.00347), + (-200, 0.00199), + // $15 (single) - Python index 236 + (-166, 0.00191), + // $20 (main + companion) - Python indices 261-262 + (-141, 0.00334), + (-140, 0.00259), + // $30 (main + companion) - Python indices 296-297 + (-106, 0.00258), + (-105, 0.00273), + // $50 (main + 2 companions) - Python indices 340-342 (-62, 0.00308), - (-60, 0.00561), - (-58, 0.00309), - // $100 (main + 3 companions) - center + (-61, 0.00561), + (-60, 0.00309), + // $100 (main + 3 companions) - Python indices 400-403 (-2, 0.00292), - (0, 0.00617), - (2, 0.00442), - (4, 0.00263), - // $150 (single) - (35, 0.00286), - // $200 (main + companion) - (60, 0.00410), - (62, 0.00335), - // $300 (main + companion) - (95, 0.00252), - (97, 0.00278), - // $500 (single) - (140, 0.00379), - // $1000 (main + companion) - (200, 0.00369), - (202, 0.00239), - // $1500 (single) - (235, 0.00128), - // $2000 (main + companion) - (260, 0.00165), - (262, 0.00140), - // $5000 (single) - (340, 0.00115), - // $10000 (single) - (400, 0.00083), + (-1, 0.00617), + (0, 0.00442), + (1, 0.00263), + // $150 (single) - Python index 436 + (34, 0.00286), + // $200 (main + companion) - Python indices 461-462 + (59, 0.00410), + (60, 0.00335), + // $300 (main + companion) - Python indices 496-497 + (94, 0.00252), + (95, 0.00278), + // $500 (single) - Python index 541 + (139, 0.00379), + // $1000 (main + companion) - Python indices 601-602 + (199, 0.00369), + (200, 0.00239), + // $1500 (single) - Python index 636 + (234, 0.00128), + // $2000 (main + companion) - Python indices 661-662 + (259, 0.00165), + (260, 0.00140), + // $5000 (single) - Python index 741 + (339, 0.00115), + // $10000 (single) - Python index 801 + (399, 0.00083), ]; /// Width of the smooth stencil in bins (Gaussian sigma) -/// Python uses std_dev=201 with 803 bins. Our histogram has 1600 bins (2x), -/// so we use 201 * (1600/803) ≈ 400 bins sigma equivalent -const SMOOTH_WIDTH: f64 = 400.0; +/// Both Python and Rust use 200 bins per decade, so sigma is the same +const SMOOTH_WIDTH: f64 = 201.0; /// Linear term coefficient for smooth stencil (per Python: 0.0000005 * x) -/// Scaled for our larger histogram: 0.0000005 * (803/1600) ≈ 0.00000025 -const SMOOTH_LINEAR_COEF: f64 = 0.00000025; +/// NOT scaled - the linear term uses window position (0-802), same as Python +const SMOOTH_LINEAR_COEF: f64 = 0.0000005; /// Weight given to smooth stencil vs spike stencil const SMOOTH_WEIGHT: f64 = 0.65; @@ -84,6 +82,12 @@ const SPIKE_WEIGHT: f64 = 1.0; /// This avoids computing exp() billions of times const SMOOTH_RANGE: usize = 800; +/// Gaussian center bin offset from spike center +/// Python's Gaussian has mean=411 in 803-element stencil +/// Stencil starts at bin 199, so Gaussian centers at bin 199+411=610 +/// Spike center is at bin 601, so Gaussian is offset by +9 bins +const GAUSSIAN_CENTER_OFFSET: i32 = 9; + /// Lazily initialized Gaussian weight lookup table fn gaussian_weights() -> &'static [f64; SMOOTH_RANGE + 1] { use std::sync::OnceLock; @@ -110,16 +114,6 @@ fn gaussian_weights() -> &'static [f64; SMOOTH_RANGE + 1] { pub fn find_best_price(histogram: &Histogram, min_slide: i32, max_slide: i32) -> Option { let bins = histogram.bins(); - // Pre-compute the linear term sum (constant for all slide positions) - // linear_sum = Σ bins[i] * SMOOTH_LINEAR_COEF * i - let linear_sum: f64 = bins - .iter() - .copied() - .enumerate() - .filter(|(_, v)| *v > 0.0) - .map(|(i, v)| v * SMOOTH_LINEAR_COEF * i as f64) - .sum(); - // Collect non-zero bins: Vec for Gaussian (needs iteration), HashMap for spike (needs lookup) let non_zero_bins: Vec<(usize, f64)> = bins .iter() @@ -147,7 +141,7 @@ pub fn find_best_price(histogram: &Histogram, min_slide: i32, max_slide: i32) -> let mut local_total = 0.0; for slide in chunk_start..=chunk_end { - let score = compute_score_fast(&non_zero_bins, &bin_map, linear_sum, slide); + let score = compute_score_fast(&non_zero_bins, &bin_map, slide); local_total += score; if score > local_best_score { local_best_score = score; @@ -170,8 +164,8 @@ pub fn find_best_price(histogram: &Histogram, min_slide: i32, max_slide: i32) -> ); // Compute neighbor scores for sub-bin interpolation (matches Python behavior) - let neighbor_up_score = compute_score_fast(&non_zero_bins, &bin_map, linear_sum, best_position + 1); - let neighbor_down_score = compute_score_fast(&non_zero_bins, &bin_map, linear_sum, best_position - 1); + let neighbor_up_score = compute_score_fast(&non_zero_bins, &bin_map, best_position + 1); + let neighbor_down_score = compute_score_fast(&non_zero_bins, &bin_map, best_position - 1); // Find best neighbor let (best_neighbor_offset, neighbor_score) = if neighbor_up_score > neighbor_down_score { @@ -204,7 +198,6 @@ pub fn find_best_price(histogram: &Histogram, min_slide: i32, max_slide: i32) -> fn compute_score_fast( non_zero_bins: &[(usize, f64)], bin_map: &FxHashMap, - linear_sum: f64, slide: i32, ) -> f64 { let spike_score = compute_spike_score_hash(bin_map, slide); @@ -212,17 +205,40 @@ fn compute_score_fast( // Python: smooth weight only applied for slide < 150 if slide < 150 { let gaussian_score = compute_gaussian_score_sparse(non_zero_bins, slide); + let linear_score = compute_linear_score_sparse(non_zero_bins, slide); // Combine Gaussian and linear parts of smooth score - let smooth_score = 0.0015 * gaussian_score + linear_sum; + let smooth_score = 0.0015 * gaussian_score + linear_score; SMOOTH_WEIGHT * smooth_score + SPIKE_WEIGHT * spike_score } else { SPIKE_WEIGHT * spike_score } } +/// Compute the linear part of the smooth stencil (per-slide, matches Python) +/// Python: sum(shifted_curve[n] * 0.0000005 * n) where n is window position (0-802) +fn compute_linear_score_sparse(non_zero_bins: &[(usize, f64)], slide: i32) -> f64 { + // Window starts at left_p001 + slide = (center_bin - 402) + slide = 199 + slide + // Python: left_p001 = center_p001 - int((803+1)/2) = 601 - 402 = 199 + let window_start = 199 + slide; + let window_end = window_start + 803; // 803 elements like Python's stencil + let mut score = 0.0; + + for &(i, bin_value) in non_zero_bins { + let bin_idx = i as i32; + if bin_idx >= window_start && bin_idx < window_end { + let window_pos = bin_idx - window_start; + score += bin_value * SMOOTH_LINEAR_COEF * window_pos as f64; + } + } + + score +} + /// Compute just the Gaussian part of the smooth stencil (sparse iteration) +/// Note: Gaussian center is offset from spike center by GAUSSIAN_CENTER_OFFSET fn compute_gaussian_score_sparse(non_zero_bins: &[(usize, f64)], slide: i32) -> f64 { - let center = center_bin() as i32 + slide; + // Python's Gaussian is centered at bin 610 (not 601), so we add the offset + let center = center_bin() as i32 + GAUSSIAN_CENTER_OFFSET + slide; let weights = gaussian_weights(); let mut score = 0.0; diff --git a/crates/brk_error/Cargo.toml b/crates/brk_error/Cargo.toml index 6f81c04ea..efab1fe21 100644 --- a/crates/brk_error/Cargo.toml +++ b/crates/brk_error/Cargo.toml @@ -6,7 +6,6 @@ edition.workspace = true license.workspace = true homepage.workspace = true repository.workspace = true -build = "build.rs" [dependencies] bitcoin = { workspace = true } diff --git a/crates/brk_error/build.rs b/crates/brk_error/build.rs deleted file mode 100644 index a4055a31e..000000000 --- a/crates/brk_error/build.rs +++ /dev/null @@ -1,8 +0,0 @@ -fn main() { - let profile = std::env::var("PROFILE").unwrap_or_default(); - - if profile == "release" { - println!("cargo:rustc-flag=-C"); - println!("cargo:rustc-flag=target-cpu=native"); - } -} diff --git a/crates/brk_fetcher/Cargo.toml b/crates/brk_fetcher/Cargo.toml index c165e8658..51e03ca19 100644 --- a/crates/brk_fetcher/Cargo.toml +++ b/crates/brk_fetcher/Cargo.toml @@ -6,7 +6,6 @@ edition.workspace = true license.workspace = true homepage.workspace = true repository.workspace = true -build = "build.rs" [dependencies] brk_error = { workspace = true } diff --git a/crates/brk_fetcher/build.rs b/crates/brk_fetcher/build.rs deleted file mode 100644 index a4055a31e..000000000 --- a/crates/brk_fetcher/build.rs +++ /dev/null @@ -1,8 +0,0 @@ -fn main() { - let profile = std::env::var("PROFILE").unwrap_or_default(); - - if profile == "release" { - println!("cargo:rustc-flag=-C"); - println!("cargo:rustc-flag=target-cpu=native"); - } -} diff --git a/crates/brk_indexer/Cargo.toml b/crates/brk_indexer/Cargo.toml index bafe34f95..e9d93415a 100644 --- a/crates/brk_indexer/Cargo.toml +++ b/crates/brk_indexer/Cargo.toml @@ -6,7 +6,6 @@ edition.workspace = true license.workspace = true homepage.workspace = true repository.workspace = true -build = "build.rs" [dependencies] bitcoin = { workspace = true } diff --git a/crates/brk_indexer/README.md b/crates/brk_indexer/README.md index 65cfc9b3f..c18de4a36 100644 --- a/crates/brk_indexer/README.md +++ b/crates/brk_indexer/README.md @@ -24,23 +24,24 @@ let mut indexer = Indexer::forced_import(&outputs_dir)?; let starting_indexes = indexer.index(&blocks, &client, &exit)?; // Access indexed data -let height = indexer.stores.txidprefix_to_txindex.get(&txid_prefix)?; -let blockhash = indexer.vecs.block.height_to_blockhash.get(height)?; +let txindex = indexer.stores.txidprefix_to_txindex.get(&txid_prefix)?; +let blockhash = indexer.vecs.blocks.blockhash.get(height)?; ``` ## Data Structures **Vecs** (append-only vectors): -- Block: `height_to_blockhash`, `height_to_timestamp`, `height_to_difficulty` -- Transaction: `txindex_to_txid`, `txindex_to_height`, `txindex_to_base_size` -- Input/Output: `txinindex_to_outpoint`, `txoutindex_to_value`, `txoutindex_to_outputtype` -- Address: Per-type `typeindex_to_addressbytes` +- `blocks`: `blockhash`, `timestamp`, `difficulty`, `total_size`, `weight` +- `transactions`: `txid`, `first_txinindex`, `first_txoutindex` +- `inputs`: `outpoint`, `txindex` +- `outputs`: `value`, `outputtype`, `typeindex`, `txindex` +- `addresses`: Per-type `p2pkhbytes`, `p2shbytes`, `p2wpkhbytes`, etc. **Stores** (key-value lookups): - `txidprefix_to_txindex` - TXID lookup via 10-byte prefix - `blockhashprefix_to_height` - Block lookup via 4-byte prefix -- `addresshash_to_addressindex` - Address lookup per type -- `addressindex_to_unspent_outpoints` - Live UTXO set per address +- `addresstype_to_addresshash_to_addressindex` - Address lookup per type +- `addresstype_to_addressindex_and_unspentoutpoint` - Live UTXO set per address ## Processing Pipeline @@ -55,10 +56,10 @@ let blockhash = indexer.vecs.block.height_to_blockhash.get(height)?; | Machine | Time | Disk | Peak Disk | Memory | Peak Memory | |---------|------|------|-----------|--------|-------------| -| MBP M3 Pro (36GB, internal SSD) | 3.1h | 233 GB | 307 GB | 5.5 GB | 11 GB | +| MBP M3 Pro (36GB, internal SSD) | 3h | 247 GB | 314 GB | 5.2 GB | 11 GB | | Mac Mini M4 (16GB, external SSD) | 4.9h | 233 GB | 303 GB | 5.4 GB | 11 GB | -Full benchmark data: [`https://github.com/bitcoinresearchkit/benches/tree/main/brk_indexer`](/benches/brk_indexer) +Full benchmark data: [bitcoinresearchkit/benches](https://github.com/bitcoinresearchkit/benches/tree/main/brk_indexer) ## Recommended: mimalloc v3 @@ -66,6 +67,7 @@ Use [mimalloc v3](https://crates.io/crates/mimalloc) as the global allocator to ## Built On +- `vecdb` for append-only vectors - `brk_cohort` for address type handling - `brk_iterator` for block iteration - `brk_store` for key-value storage diff --git a/crates/brk_indexer/build.rs b/crates/brk_indexer/build.rs deleted file mode 100644 index a4055a31e..000000000 --- a/crates/brk_indexer/build.rs +++ /dev/null @@ -1,8 +0,0 @@ -fn main() { - let profile = std::env::var("PROFILE").unwrap_or_default(); - - if profile == "release" { - println!("cargo:rustc-flag=-C"); - println!("cargo:rustc-flag=target-cpu=native"); - } -} diff --git a/crates/brk_iterator/Cargo.toml b/crates/brk_iterator/Cargo.toml index 45bb62dc4..a7fb1e2f5 100644 --- a/crates/brk_iterator/Cargo.toml +++ b/crates/brk_iterator/Cargo.toml @@ -6,7 +6,6 @@ edition.workspace = true license.workspace = true homepage.workspace = true repository.workspace = true -build = "build.rs" [dependencies] brk_error = { workspace = true } diff --git a/crates/brk_iterator/build.rs b/crates/brk_iterator/build.rs deleted file mode 100644 index a4055a31e..000000000 --- a/crates/brk_iterator/build.rs +++ /dev/null @@ -1,8 +0,0 @@ -fn main() { - let profile = std::env::var("PROFILE").unwrap_or_default(); - - if profile == "release" { - println!("cargo:rustc-flag=-C"); - println!("cargo:rustc-flag=target-cpu=native"); - } -} diff --git a/crates/brk_logger/Cargo.toml b/crates/brk_logger/Cargo.toml index 2b4fc4805..c7ec1a3c7 100644 --- a/crates/brk_logger/Cargo.toml +++ b/crates/brk_logger/Cargo.toml @@ -6,7 +6,6 @@ edition.workspace = true license.workspace = true homepage.workspace = true repository.workspace = true -build = "build.rs" [dependencies] jiff = { workspace = true } diff --git a/crates/brk_logger/build.rs b/crates/brk_logger/build.rs deleted file mode 100644 index a4055a31e..000000000 --- a/crates/brk_logger/build.rs +++ /dev/null @@ -1,8 +0,0 @@ -fn main() { - let profile = std::env::var("PROFILE").unwrap_or_default(); - - if profile == "release" { - println!("cargo:rustc-flag=-C"); - println!("cargo:rustc-flag=target-cpu=native"); - } -} diff --git a/crates/brk_mcp/Cargo.toml b/crates/brk_mcp/Cargo.toml index f76bf1cf5..c632fc349 100644 --- a/crates/brk_mcp/Cargo.toml +++ b/crates/brk_mcp/Cargo.toml @@ -6,7 +6,6 @@ edition.workspace = true license.workspace = true homepage.workspace = true repository.workspace = true -build = "build.rs" [dependencies] axum = { workspace = true } diff --git a/crates/brk_mcp/build.rs b/crates/brk_mcp/build.rs deleted file mode 100644 index a4055a31e..000000000 --- a/crates/brk_mcp/build.rs +++ /dev/null @@ -1,8 +0,0 @@ -fn main() { - let profile = std::env::var("PROFILE").unwrap_or_default(); - - if profile == "release" { - println!("cargo:rustc-flag=-C"); - println!("cargo:rustc-flag=target-cpu=native"); - } -} diff --git a/crates/brk_mempool/Cargo.toml b/crates/brk_mempool/Cargo.toml index de3f8eda2..78734718c 100644 --- a/crates/brk_mempool/Cargo.toml +++ b/crates/brk_mempool/Cargo.toml @@ -6,7 +6,6 @@ edition.workspace = true license.workspace = true homepage.workspace = true repository.workspace = true -build = "build.rs" [dependencies] brk_error = { workspace = true } diff --git a/crates/brk_mempool/README.md b/crates/brk_mempool/README.md index abb07ea33..932dd46a5 100644 --- a/crates/brk_mempool/README.md +++ b/crates/brk_mempool/README.md @@ -36,10 +36,10 @@ let tracker = mempool.get_addresses(); Returns `RecommendedFees` with sat/vB rates for different confirmation targets: -- `fastest_fee` - Next block -- `half_hour_fee` - ~3 blocks -- `hour_fee` - ~6 blocks -- `economy_fee` - ~144 blocks +- `fastest_fee` - Next block (index 0) +- `half_hour_fee` - ~3 blocks (index 2) +- `hour_fee` - ~6 blocks (index 5) +- `economy_fee` - ~8 blocks (index 7, last projected block) - `minimum_fee` - Relay minimum ## Block Projection @@ -48,7 +48,7 @@ Builds projected blocks by: 1. Constructing transaction dependency graph 2. Calculating effective fee rates (including ancestors) 3. Selecting transactions greedily by ancestor-aware fee rate -4. Partitioning into ~4MB virtual blocks +4. Partitioning into 1MB vsize blocks ## Built On diff --git a/crates/brk_mempool/build.rs b/crates/brk_mempool/build.rs deleted file mode 100644 index a4055a31e..000000000 --- a/crates/brk_mempool/build.rs +++ /dev/null @@ -1,8 +0,0 @@ -fn main() { - let profile = std::env::var("PROFILE").unwrap_or_default(); - - if profile == "release" { - println!("cargo:rustc-flag=-C"); - println!("cargo:rustc-flag=target-cpu=native"); - } -} diff --git a/crates/brk_query/Cargo.toml b/crates/brk_query/Cargo.toml index ddb06010c..76ca8ff76 100644 --- a/crates/brk_query/Cargo.toml +++ b/crates/brk_query/Cargo.toml @@ -6,7 +6,6 @@ edition.workspace = true version.workspace = true homepage.workspace = true repository.workspace = true -build = "build.rs" [features] tokio = ["dep:tokio"] @@ -24,6 +23,6 @@ brk_types = { workspace = true } derive_more = { workspace = true } jiff = { workspace = true } # quickmatch = { path = "../../../quickmatch" } -quickmatch = "0.1.8" +quickmatch = "0.2.0" tokio = { workspace = true, optional = true } vecdb = { workspace = true } diff --git a/crates/brk_query/README.md b/crates/brk_query/README.md index 7e4940d6e..529ebed1b 100644 --- a/crates/brk_query/README.md +++ b/crates/brk_query/README.md @@ -25,20 +25,19 @@ let height = query.height(); // Metric queries let data = query.search_and_format(MetricSelection { - vecids: vec!["supply".into()], + metrics: vec!["supply".into()], index: Index::Height, - range: DataRange::Last(100), - ..Default::default() + range: DataRangeFormat::default(), })?; // Block queries -let info = query.block_info(Height::new(840_000))?; +let info = query.block_by_height(Height::new(840_000))?; // Transaction queries -let tx = query.transaction(&txid)?; +let tx = query.transaction(txid.into())?; // Address queries -let stats = query.address_stats(&address)?; +let stats = query.address(address)?; ``` ## Query Types @@ -46,11 +45,11 @@ let stats = query.address_stats(&address)?; | Domain | Methods | |--------|---------| | Metrics | `metrics`, `search_and_format`, `metric_to_indexes` | -| Blocks | `block_info`, `block_txs`, `block_status`, `block_timestamp` | -| Transactions | `transaction`, `tx_status`, `tx_merkle_proof` | -| Addresses | `address_stats`, `address_txs`, `address_utxos` | -| Mining | `difficulty_adjustments`, `hashrate`, `pools`, `epochs` | -| Mempool | `mempool_info`, `mempool_fees`, `mempool_projected_blocks` | +| Blocks | `block`, `block_by_height`, `blocks`, `block_txs`, `block_status`, `block_by_timestamp` | +| Transactions | `transaction`, `transaction_status`, `transaction_hex`, `outspend`, `outspends` | +| Addresses | `address`, `address_txids`, `address_utxos` | +| Mining | `difficulty_adjustments`, `hashrate`, `mining_pools`, `reward_stats` | +| Mempool | `mempool_info`, `recommended_fees`, `mempool_blocks` | ## Async Usage @@ -58,7 +57,7 @@ let stats = query.address_stats(&address)?; let async_query = AsyncQuery::build(&reader, &indexer, &computer, mempool); // Run blocking queries in thread pool -let result = async_query.run(|q| q.block_info(height)).await; +let result = async_query.run(|q| q.block_by_height(height)).await; // Access inner Query let height = async_query.inner().height(); diff --git a/crates/brk_query/build.rs b/crates/brk_query/build.rs deleted file mode 100644 index a4055a31e..000000000 --- a/crates/brk_query/build.rs +++ /dev/null @@ -1,8 +0,0 @@ -fn main() { - let profile = std::env::var("PROFILE").unwrap_or_default(); - - if profile == "release" { - println!("cargo:rustc-flag=-C"); - println!("cargo:rustc-flag=target-cpu=native"); - } -} diff --git a/crates/brk_reader/Cargo.toml b/crates/brk_reader/Cargo.toml index 881e258ca..5f56bcde2 100644 --- a/crates/brk_reader/Cargo.toml +++ b/crates/brk_reader/Cargo.toml @@ -8,7 +8,6 @@ edition.workspace = true license.workspace = true homepage.workspace = true repository.workspace = true -build = "build.rs" [dependencies] bitcoin = { workspace = true } diff --git a/crates/brk_reader/build.rs b/crates/brk_reader/build.rs deleted file mode 100644 index a4055a31e..000000000 --- a/crates/brk_reader/build.rs +++ /dev/null @@ -1,8 +0,0 @@ -fn main() { - let profile = std::env::var("PROFILE").unwrap_or_default(); - - if profile == "release" { - println!("cargo:rustc-flag=-C"); - println!("cargo:rustc-flag=target-cpu=native"); - } -} diff --git a/crates/brk_rpc/Cargo.toml b/crates/brk_rpc/Cargo.toml index bbbe28f4d..b2c6df973 100644 --- a/crates/brk_rpc/Cargo.toml +++ b/crates/brk_rpc/Cargo.toml @@ -6,7 +6,6 @@ edition.workspace = true license.workspace = true homepage.workspace = true repository.workspace = true -build = "build.rs" [dependencies] bitcoin = { workspace = true } diff --git a/crates/brk_rpc/build.rs b/crates/brk_rpc/build.rs deleted file mode 100644 index a4055a31e..000000000 --- a/crates/brk_rpc/build.rs +++ /dev/null @@ -1,8 +0,0 @@ -fn main() { - let profile = std::env::var("PROFILE").unwrap_or_default(); - - if profile == "release" { - println!("cargo:rustc-flag=-C"); - println!("cargo:rustc-flag=target-cpu=native"); - } -} diff --git a/crates/brk_server/Cargo.toml b/crates/brk_server/Cargo.toml index a14d69e63..6f2113315 100644 --- a/crates/brk_server/Cargo.toml +++ b/crates/brk_server/Cargo.toml @@ -24,6 +24,7 @@ brk_rpc = { workspace = true } brk_types = { workspace = true } brk_traversable = { workspace = true } derive_more = { workspace = true } +include_dir = "0.7" vecdb = { workspace = true } jiff = { workspace = true } quick_cache = "0.6.18" @@ -34,5 +35,12 @@ tokio = { workspace = true } tracing = { workspace = true } tower-http = { version = "0.6.8", features = ["compression-full", "trace"] } +[build-dependencies] +# importmap = { path = "../../../importmap" } +importmap = "0.2" + [dev-dependencies] brk_mempool = { workspace = true } + +[package.metadata.cargo-machete] +ignored = ["importmap"] diff --git a/crates/brk_server/README.md b/crates/brk_server/README.md index be660d096..9d143fb51 100644 --- a/crates/brk_server/README.md +++ b/crates/brk_server/README.md @@ -8,7 +8,7 @@ Serve BRK data via REST API with OpenAPI documentation, response caching, MCP en ## Key Features -- **OpenAPI spec**: Auto-generated documentation at `/api/openapi.json` +- **OpenAPI spec**: Auto-generated documentation at `/api.json` (interactive docs at `/api`) - **Response caching**: LRU cache with 5000 entries for repeated queries - **Compression**: Brotli, gzip, deflate, zstd support - **Static files**: Optional web interface hosting @@ -17,7 +17,8 @@ Serve BRK data via REST API with OpenAPI documentation, response caching, MCP en ## Core API ```rust,ignore -let server = Server::new(&async_query, Some(files_path)); +let server = Server::new(&async_query, data_path, WebsiteSource::Filesystem(files_path)); +// Or WebsiteSource::Embedded, or WebsiteSource::Disabled server.serve(true).await?; // true enables MCP endpoint ``` @@ -25,17 +26,18 @@ server.serve(true).await?; // true enables MCP endpoint | Path | Description | |------|-------------| -| `/api/blocks/{height}` | Block info, transactions, status | -| `/api/txs/{txid}` | Transaction details, status, merkle proof | -| `/api/addresses/{addr}` | Address stats, transactions, UTXOs | +| `/api/block-height/{height}` | Block by height | +| `/api/block/{hash}` | Block info, transactions, status | +| `/api/tx/{txid}` | Transaction details, status, hex | +| `/api/address/{addr}` | Address stats, transactions, UTXOs | | `/api/metrics` | Metric catalog and data queries | -| `/api/mining/*` | Hashrate, difficulty, pools, epochs | +| `/api/v1/mining/*` | Hashrate, difficulty, pools, rewards | | `/api/mempool/*` | Fee estimates, projected blocks | | `/mcp` | MCP endpoint (if enabled) | ## Caching -Uses ETag-based caching with stale-while-revalidate semantics: +Uses ETag-based caching with must-revalidate semantics: - Height-indexed data: Cache until height changes - Date-indexed data: Cache with longer TTL - Mempool data: Short TTL, frequent updates diff --git a/crates/brk_server/build.rs b/crates/brk_server/build.rs index a4055a31e..4dac4fecf 100644 --- a/crates/brk_server/build.rs +++ b/crates/brk_server/build.rs @@ -1,8 +1,22 @@ -fn main() { - let profile = std::env::var("PROFILE").unwrap_or_default(); +use std::{env, path::Path}; - if profile == "release" { - println!("cargo:rustc-flag=-C"); - println!("cargo:rustc-flag=target-cpu=native"); +fn main() { + let is_dev = env::var("PROFILE").is_ok_and(|p| p == "debug"); + + // Generate importmap for website (updates index.html in place) + let manifest_dir = env::var("CARGO_MANIFEST_DIR").unwrap(); + let website_path = Path::new(&manifest_dir).join("../../website"); + + println!("cargo:rerun-if-changed=../../website"); + + if website_path.exists() { + // Skip importmap hashing in dev mode (files change often) + let map = if is_dev { + importmap::ImportMap::empty() + } else { + importmap::ImportMap::scan(&website_path, "").unwrap_or_else(|_| importmap::ImportMap::empty()) + }; + + let _ = map.update_html_file(&website_path.join("index.html")); } } diff --git a/crates/brk_server/examples/server.rs b/crates/brk_server/examples/server.rs index d0b7ae9ec..653b95c9f 100644 --- a/crates/brk_server/examples/server.rs +++ b/crates/brk_server/examples/server.rs @@ -8,7 +8,7 @@ use brk_mempool::Mempool; use brk_query::AsyncQuery; use brk_reader::Reader; use brk_rpc::{Auth, Client}; -use brk_server::Server; +use brk_server::{Server, WebsiteSource}; use tracing::info; use vecdb::Exit; @@ -54,7 +54,7 @@ fn run() -> Result<()> { // Option 1: block_on to run and properly propagate errors runtime.block_on(async move { - let server = Server::new(&query, outputs_dir, None); + let server = Server::new(&query, outputs_dir, WebsiteSource::Disabled); let handle = tokio::spawn(async move { server.serve(true).await }); diff --git a/crates/brk_server/src/files/file.rs b/crates/brk_server/src/files/file.rs index bd9a9b0ff..dde1107fb 100644 --- a/crates/brk_server/src/files/file.rs +++ b/crates/brk_server/src/files/file.rs @@ -10,121 +10,63 @@ use axum::{ http::{HeaderMap, StatusCode}, response::{IntoResponse, Response}, }; -use brk_error::{Error, Result}; +use brk_error::Result; use quick_cache::sync::GuardResult; use tracing::{error, info}; -use crate::{AppState, HeaderMapExtended, ModifiedState, ResponseExtended}; +use crate::{ + AppState, EMBEDDED_WEBSITE, HeaderMapExtended, ModifiedState, ResponseExtended, WebsiteSource, +}; pub async fn file_handler( headers: HeaderMap, State(state): State, path: extract::Path, ) -> Response { - any_handler(headers, state, Some(path)) + any_handler(headers, state, Some(path.0)) } pub async fn index_handler(headers: HeaderMap, State(state): State) -> Response { any_handler(headers, state, None) } -fn any_handler( - headers: HeaderMap, - state: AppState, - path: Option>, -) -> Response { - let files_path = state.files_path.as_ref().unwrap(); - - if let Some(path) = path.as_ref() { - // Sanitize path components to prevent traversal attacks - let sanitized: String = path - .0 - .split('/') - .filter(|component| !component.is_empty() && *component != "." && *component != "..") - .collect::>() - .join("/"); - - let mut path = files_path.join(&sanitized); - - // Canonicalize and verify the path stays within the project root - // (allows symlinks to modules/ which is outside the website directory) - if let Ok(canonical) = path.canonicalize() - && let Ok(canonical_base) = files_path.canonicalize() - { - // Allow paths within files_path OR within project root (2 levels up) - let project_root = canonical_base.parent().and_then(|p| p.parent()); - let allowed = canonical.starts_with(&canonical_base) - || project_root.is_some_and(|root| canonical.starts_with(root)); - if !allowed { - let mut response: Response = - (StatusCode::FORBIDDEN, "Access denied".to_string()).into_response(); - response.headers_mut().insert_cors(); - return response; - } - } - - // Strip hash from import-mapped URLs (e.g., foo.abc12345.js -> foo.js) - if !path.exists() - && let Some(unhashed) = strip_importmap_hash(&path) - && unhashed.exists() - { - path = unhashed; - } - - if !path.exists() || path.is_dir() { - if path.extension().is_some() { - let mut response: Response = ( - StatusCode::INTERNAL_SERVER_ERROR, - "File doesn't exist".to_string(), - ) - .into_response(); - - response.headers_mut().insert_cors(); - - return response; - } else { - path = files_path.join("index.html"); - } - } - - path_to_response(&headers, &state, &path) - } else { - path_to_response(&headers, &state, &files_path.join("index.html")) - } -} - -fn path_to_response(headers: &HeaderMap, state: &AppState, path: &Path) -> Response { - match path_to_response_(headers, state, path) { - Ok(response) => response, - Err(error) => { - let mut response = - (StatusCode::INTERNAL_SERVER_ERROR, error.to_string()).into_response(); - - response.headers_mut().insert_cors(); - - response +fn any_handler(headers: HeaderMap, state: AppState, path: Option) -> Response { + match &state.website { + WebsiteSource::Disabled => unreachable!("routes not added when disabled"), + WebsiteSource::Embedded => embedded_handler(&state, path), + WebsiteSource::Filesystem(files_path) => { + filesystem_handler(headers, &state, files_path, path) } } } -fn path_to_response_(headers: &HeaderMap, state: &AppState, path: &Path) -> Result { - let (modified, date) = headers.check_if_modified_since(path)?; - if !cfg!(debug_assertions) && modified == ModifiedState::NotModifiedSince { - return Ok(Response::new_not_modified()); - } +/// Sanitize path to prevent traversal attacks +fn sanitize_path(path: &str) -> String { + path.split('/') + .filter(|c| !c.is_empty() && *c != "." && *c != "..") + .collect::>() + .join("/") +} - let serialized_path = path.to_str().unwrap(); +/// Check if path requires revalidation (HTML files, service worker) +fn must_revalidate(path: &Path) -> bool { + path.extension().is_some_and(|ext| ext == "html") + || path + .to_str() + .is_some_and(|p| p.ends_with("service-worker.js")) +} - let must_revalidate = path - .extension() - .is_some_and(|extension| extension == "html") - || serialized_path.ends_with("service-worker.js"); +/// Build response with proper headers and caching +fn build_response(state: &AppState, path: &Path, content: Vec, cache_key: &str) -> Response { + let must_revalidate = must_revalidate(path); + // Use cache for non-HTML files in release mode let guard_res = if !cfg!(debug_assertions) && !must_revalidate { - Some(state.cache.get_value_or_guard( - &path.to_str().unwrap().to_owned(), - Some(Duration::from_millis(50)), - )) + Some( + state + .cache + .get_value_or_guard(&cache_key.to_owned(), Some(Duration::from_millis(50))), + ) } else { None }; @@ -132,19 +74,10 @@ fn path_to_response_(headers: &HeaderMap, state: &AppState, path: &Path) -> Resu let mut response = if let Some(GuardResult::Value(v)) = guard_res { Response::new(Body::from(v)) } else { - let content = fs::read(path).unwrap_or_else(|error| { - error!("{error}"); - let path = path.to_str().unwrap(); - info!("Can't read file {path}"); - panic!("") - }); - if let Some(GuardResult::Guard(g)) = guard_res { - g.insert(content.clone().into()) - .map_err(|_| Error::QuickCacheError)?; + let _ = g.insert(content.clone().into()); } - - Response::new(content.into()) + Response::new(Body::from(content)) }; let headers = response.headers_mut(); @@ -157,7 +90,129 @@ fn path_to_response_(headers: &HeaderMap, state: &AppState, path: &Path) -> Resu headers.insert_cache_control_immutable(); } - headers.insert_last_modified(date); + response +} + +fn embedded_handler(state: &AppState, path: Option) -> Response { + let path = path.unwrap_or_else(|| "index.html".to_string()); + let sanitized = sanitize_path(&path); + + // Try to get file, with importmap hash stripping and SPA fallback + let file = EMBEDDED_WEBSITE + .get_file(&sanitized) + .or_else(|| { + strip_importmap_hash(Path::new(&sanitized)) + .and_then(|unhashed| EMBEDDED_WEBSITE.get_file(unhashed.to_str()?)) + }) + .or_else(|| { + // If no extension, serve index.html (SPA routing) + if Path::new(&sanitized).extension().is_none() { + EMBEDDED_WEBSITE.get_file("index.html") + } else { + None + } + }); + + let Some(file) = file else { + let mut response: Response = + (StatusCode::NOT_FOUND, "File not found".to_string()).into_response(); + response.headers_mut().insert_cors(); + return response; + }; + + build_response( + state, + Path::new(file.path()), + file.contents().to_vec(), + &file.path().to_string_lossy(), + ) +} + +fn filesystem_handler( + headers: HeaderMap, + state: &AppState, + files_path: &Path, + path: Option, +) -> Response { + let path = if let Some(path) = path { + let sanitized = sanitize_path(&path); + let mut path = files_path.join(&sanitized); + + // Canonicalize and verify the path stays within the project root + // (allows symlinks to modules/ which is outside the website directory) + if let Ok(canonical) = path.canonicalize() + && let Ok(canonical_base) = files_path.canonicalize() + { + let project_root = canonical_base.parent().and_then(|p| p.parent()); + let allowed = canonical.starts_with(&canonical_base) + || project_root.is_some_and(|root| canonical.starts_with(root)); + if !allowed { + let mut response: Response = + (StatusCode::FORBIDDEN, "Access denied".to_string()).into_response(); + response.headers_mut().insert_cors(); + return response; + } + } + + // Strip hash from import-mapped URLs + if !path.exists() + && let Some(unhashed) = strip_importmap_hash(&path) + && unhashed.exists() + { + path = unhashed; + } + + // SPA fallback + if !path.exists() || path.is_dir() { + if path.extension().is_some() { + let mut response: Response = ( + StatusCode::INTERNAL_SERVER_ERROR, + "File doesn't exist".to_string(), + ) + .into_response(); + response.headers_mut().insert_cors(); + return response; + } else { + path = files_path.join("index.html"); + } + } + + path + } else { + files_path.join("index.html") + }; + + path_to_response(&headers, state, &path) +} + +fn path_to_response(headers: &HeaderMap, state: &AppState, path: &Path) -> Response { + match path_to_response_(headers, state, path) { + Ok(response) => response, + Err(error) => { + let mut response = + (StatusCode::INTERNAL_SERVER_ERROR, error.to_string()).into_response(); + response.headers_mut().insert_cors(); + response + } + } +} + +fn path_to_response_(headers: &HeaderMap, state: &AppState, path: &Path) -> Result { + let (modified, date) = headers.check_if_modified_since(path)?; + if !cfg!(debug_assertions) && modified == ModifiedState::NotModifiedSince { + return Ok(Response::new_not_modified()); + } + + let content = fs::read(path).unwrap_or_else(|error| { + error!("{error}"); + let path = path.to_str().unwrap(); + info!("Can't read file {path}"); + panic!("") + }); + + let cache_key = path.to_str().unwrap(); + let mut response = build_response(state, path, content, cache_key); + response.headers_mut().insert_last_modified(date); Ok(response) } diff --git a/crates/brk_server/src/files/mod.rs b/crates/brk_server/src/files/mod.rs index 56b3f217d..70ec24206 100644 --- a/crates/brk_server/src/files/mod.rs +++ b/crates/brk_server/src/files/mod.rs @@ -1,21 +1,19 @@ -use std::path::PathBuf; - use aide::axum::ApiRouter; use axum::{response::Redirect, routing::get}; -use super::AppState; +use super::{AppState, WebsiteSource}; mod file; use file::{file_handler, index_handler}; pub trait FilesRoutes { - fn add_files_routes(self, path: Option<&PathBuf>) -> Self; + fn add_files_routes(self, website: &WebsiteSource) -> Self; } impl FilesRoutes for ApiRouter { - fn add_files_routes(self, path: Option<&PathBuf>) -> Self { - if path.is_some() { + fn add_files_routes(self, website: &WebsiteSource) -> Self { + if website.is_enabled() { self.route("/{*path}", get(file_handler)) .route("/", get(index_handler)) } else { diff --git a/crates/brk_server/src/lib.rs b/crates/brk_server/src/lib.rs index 4aacae5e7..0b5be5b74 100644 --- a/crates/brk_server/src/lib.rs +++ b/crates/brk_server/src/lib.rs @@ -15,11 +15,29 @@ use axum::{ use brk_error::Result; use brk_mcp::route::mcp_router; use brk_query::AsyncQuery; +use include_dir::{include_dir, Dir}; use quick_cache::sync::Cache; use tokio::net::TcpListener; use tower_http::{compression::CompressionLayer, trace::TraceLayer}; use tracing::{error, info}; +/// Embedded website assets +pub static EMBEDDED_WEBSITE: Dir = include_dir!("$CARGO_MANIFEST_DIR/../../website"); + +/// Source for serving the website +#[derive(Debug, Clone)] +pub enum WebsiteSource { + Disabled, + Embedded, + Filesystem(PathBuf), +} + +impl WebsiteSource { + pub fn is_enabled(&self) -> bool { + !matches!(self, Self::Disabled) + } +} + mod api; pub mod cache; mod extended; @@ -37,12 +55,12 @@ pub const VERSION: &str = env!("CARGO_PKG_VERSION"); pub struct Server(AppState); impl Server { - pub fn new(query: &AsyncQuery, data_path: PathBuf, files_path: Option) -> Self { + pub fn new(query: &AsyncQuery, data_path: PathBuf, website: WebsiteSource) -> Self { Self(AppState { client: query.client().clone(), query: query.clone(), data_path, - files_path, + website, cache: Arc::new(Cache::new(5_000)), started_at: jiff::Timestamp::now(), started_instant: Instant::now(), @@ -87,7 +105,7 @@ impl Server { let vecs = state.query.inner().vecs(); let router = ApiRouter::new() .add_api_routes() - .add_files_routes(state.files_path.as_ref()) + .add_files_routes(&state.website) .route( "/discord", get(Redirect::temporary("https://discord.gg/WACpShCB7M")), diff --git a/crates/brk_server/src/state.rs b/crates/brk_server/src/state.rs index 0d6699b00..889abad48 100644 --- a/crates/brk_server/src/state.rs +++ b/crates/brk_server/src/state.rs @@ -13,7 +13,7 @@ use quick_cache::sync::Cache; use serde::Serialize; use crate::{ - CacheParams, CacheStrategy, + CacheParams, CacheStrategy, WebsiteSource, extended::{ResponseExtended, ResultExtended}, }; @@ -22,7 +22,7 @@ pub struct AppState { #[deref] pub query: AsyncQuery, pub data_path: PathBuf, - pub files_path: Option, + pub website: WebsiteSource, pub cache: Arc>, pub client: Client, pub started_at: Timestamp, diff --git a/crates/brk_store/Cargo.toml b/crates/brk_store/Cargo.toml index 3552fc635..a67b570e1 100644 --- a/crates/brk_store/Cargo.toml +++ b/crates/brk_store/Cargo.toml @@ -8,7 +8,6 @@ edition.workspace = true license.workspace = true homepage.workspace = true repository.workspace = true -build = "build.rs" [dependencies] brk_error = { workspace = true } diff --git a/crates/brk_store/README.md b/crates/brk_store/README.md index bcb071dc2..a6498eac8 100644 --- a/crates/brk_store/README.md +++ b/crates/brk_store/README.md @@ -19,7 +19,7 @@ Persist and query Bitcoin index data (address→outputs, txid→height, etc.) wi ```rust,ignore let store: Store = Store::import( &db, &path, "txid_to_height", - Version::new(1), Mode::default(), Kind::Random + Version::new(1), Mode::Any, Kind::Random )?; store.insert(txid, height); diff --git a/crates/brk_store/build.rs b/crates/brk_store/build.rs deleted file mode 100644 index a4055a31e..000000000 --- a/crates/brk_store/build.rs +++ /dev/null @@ -1,8 +0,0 @@ -fn main() { - let profile = std::env::var("PROFILE").unwrap_or_default(); - - if profile == "release" { - println!("cargo:rustc-flag=-C"); - println!("cargo:rustc-flag=target-cpu=native"); - } -} diff --git a/crates/brk_traversable/Cargo.toml b/crates/brk_traversable/Cargo.toml index 1b2b88bac..690b46139 100644 --- a/crates/brk_traversable/Cargo.toml +++ b/crates/brk_traversable/Cargo.toml @@ -6,7 +6,6 @@ edition.workspace = true license.workspace = true homepage.workspace = true repository.workspace = true -build = "build.rs" [features] derive = ["brk_traversable_derive"] diff --git a/crates/brk_traversable/build.rs b/crates/brk_traversable/build.rs deleted file mode 100644 index a4055a31e..000000000 --- a/crates/brk_traversable/build.rs +++ /dev/null @@ -1,8 +0,0 @@ -fn main() { - let profile = std::env::var("PROFILE").unwrap_or_default(); - - if profile == "release" { - println!("cargo:rustc-flag=-C"); - println!("cargo:rustc-flag=target-cpu=native"); - } -} diff --git a/crates/brk_traversable_derive/Cargo.toml b/crates/brk_traversable_derive/Cargo.toml index 0007c8c8c..792e35b04 100644 --- a/crates/brk_traversable_derive/Cargo.toml +++ b/crates/brk_traversable_derive/Cargo.toml @@ -6,7 +6,6 @@ edition.workspace = true license.workspace = true homepage.workspace = true repository.workspace = true -build = "build.rs" [lib] proc-macro = true diff --git a/crates/brk_traversable_derive/build.rs b/crates/brk_traversable_derive/build.rs deleted file mode 100644 index a4055a31e..000000000 --- a/crates/brk_traversable_derive/build.rs +++ /dev/null @@ -1,8 +0,0 @@ -fn main() { - let profile = std::env::var("PROFILE").unwrap_or_default(); - - if profile == "release" { - println!("cargo:rustc-flag=-C"); - println!("cargo:rustc-flag=target-cpu=native"); - } -} diff --git a/crates/brk_types/Cargo.toml b/crates/brk_types/Cargo.toml index 5ba6b9396..bc6ca071a 100644 --- a/crates/brk_types/Cargo.toml +++ b/crates/brk_types/Cargo.toml @@ -6,7 +6,6 @@ edition.workspace = true license.workspace = true homepage.workspace = true repository.workspace = true -build = "build.rs" [dependencies] bitcoin = { workspace = true } diff --git a/crates/brk_types/README.md b/crates/brk_types/README.md index 8ceba77e3..68cf7a083 100644 --- a/crates/brk_types/README.md +++ b/crates/brk_types/README.md @@ -9,8 +9,8 @@ Work with Bitcoin primitives (heights, satoshis, addresses, transactions) throug ## Key Features - **Bitcoin primitives**: `Height`, `Sats`, `Txid`, `BlockHash`, `Outpoint` with full arithmetic and conversion support -- **Address types**: All output types (P2PKH, P2SH, P2WPKH, P2WSH, P2TR, P2PK, P2A, OP_RETURN) with address index variants -- **Time indexes**: `DateIndex`, `WeekIndex`, `MonthIndex`, `QuarterIndex`, `YearIndex`, `DecadeIndex` with cross-index conversion +- **Address types**: All output types (P2PK33, P2PK65, P2PKH, P2MS, P2SH, P2WPKH, P2WSH, P2TR, P2A, OP_RETURN) with address index variants +- **Time indexes**: `DateIndex`, `WeekIndex`, `MonthIndex`, `QuarterIndex`, `SemesterIndex`, `YearIndex`, `DecadeIndex` with cross-index conversion - **Protocol types**: `DifficultyEpoch`, `HalvingEpoch`, `TxVersion`, `RawLocktime` - **Financial types**: `Dollars`, `Cents`, `OHLC` (Open/High/Low/Close) - **Serialization**: Serde + JSON Schema generation via schemars diff --git a/crates/brk_types/build.rs b/crates/brk_types/build.rs deleted file mode 100644 index a4055a31e..000000000 --- a/crates/brk_types/build.rs +++ /dev/null @@ -1,8 +0,0 @@ -fn main() { - let profile = std::env::var("PROFILE").unwrap_or_default(); - - if profile == "release" { - println!("cargo:rustc-flag=-C"); - println!("cargo:rustc-flag=target-cpu=native"); - } -} diff --git a/docs/HOSTING.md b/docs/HOSTING.md index a77455ea7..468ff3df2 100644 --- a/docs/HOSTING.md +++ b/docs/HOSTING.md @@ -2,19 +2,7 @@ ## Self-Hosting -BRK is designed to be self-hosted. Install and run with: - -```bash -cargo install --locked brk_cli -brk --bitcoindir ~/.bitcoin --brkdir ~/.brk -``` - -Requirements: -- Bitcoin Core with accessible `blk*.dat` files -- ~400 GB disk space -- 12+ GB RAM recommended - -See the [CLI documentation](https://docs.rs/brk_cli) for configuration options. +BRK is designed to be self-hosted. See the [brk_cli documentation](https://docs.rs/brk_cli) for installation, requirements, and configuration options. ## Professional Hosting diff --git a/docs/README.md b/docs/README.md index 2312f288a..722e8e167 100644 --- a/docs/README.md +++ b/docs/README.md @@ -35,7 +35,7 @@ BRK parses, indexes, and analyzes Bitcoin blockchain data. It combines on-chain **Use the Public API** — Access data without running infrastructure. Client libraries available for [JavaScript](https://www.npmjs.com/package/brk-client), [Python](https://pypi.org/project/brk-client/), and [Rust](https://crates.io/crates/brk_client). See the [API reference](https://bitcoinresearchkit.org/api) for endpoints. -**Self-Host** — Run your own instance with Bitcoin Core. Install via `cargo install --locked brk_cli` or use [Docker](https://github.com/bitcoinresearchkit/brk/tree/main/docker). Requires ~400 GB disk and 12+ GB RAM. See the [hosting guide](./HOSTING.md). +**Self-Host** — Run your own instance with Bitcoin Core. Install via [`brk_cli`](https://docs.rs/brk_cli) or use [Docker](https://github.com/bitcoinresearchkit/brk/tree/main/docker). See the [hosting guide](./HOSTING.md). **Use as a Library** — Build custom tools with the Rust crates. Use individual components or the [umbrella crate](https://docs.rs/brk). See [architecture](./ARCHITECTURE.md) for how they fit together. diff --git a/modules/brk-client/index.js b/modules/brk-client/index.js index b87b9e347..73e775be8 100644 --- a/modules/brk-client/index.js +++ b/modules/brk-client/index.js @@ -889,7 +889,7 @@ class BrkError extends Error { * @typedef {Object} MetricPattern * @property {string} name - The metric name * @property {Readonly>>>} by - Index endpoints as lazy getters. Access via .by.dateindex or .by['dateindex'] - * @property {() => Index[]} indexes - Get the list of available indexes + * @property {() => readonly Index[]} indexes - Get the list of available indexes * @property {(index: Index) => MetricEndpointBuilder|undefined} get - Get an endpoint for a specific index */ @@ -1103,7 +1103,7 @@ const _p = (prefix, acc) => (acc ? `${prefix}_${acc}` : prefix); // Index group constants and factory -const _i1 = [ +const _i1 = /** @type {const} */ ([ "dateindex", "decadeindex", "difficultyepoch", @@ -1113,8 +1113,8 @@ const _i1 = [ "semesterindex", "weekindex", "yearindex", -]; -const _i2 = [ +]); +const _i2 = /** @type {const} */ ([ "dateindex", "decadeindex", "difficultyepoch", @@ -1123,8 +1123,8 @@ const _i2 = [ "semesterindex", "weekindex", "yearindex", -]; -const _i3 = [ +]); +const _i3 = /** @type {const} */ ([ "dateindex", "decadeindex", "height", @@ -1133,8 +1133,8 @@ const _i3 = [ "semesterindex", "weekindex", "yearindex", -]; -const _i4 = [ +]); +const _i4 = /** @type {const} */ ([ "dateindex", "decadeindex", "monthindex", @@ -1142,46 +1142,45 @@ const _i4 = [ "semesterindex", "weekindex", "yearindex", -]; -const _i5 = ["dateindex", "height"]; -const _i6 = ["dateindex"]; -const _i7 = ["decadeindex"]; -const _i8 = ["difficultyepoch"]; -const _i9 = ["emptyoutputindex"]; -const _i10 = ["halvingepoch"]; -const _i11 = ["height"]; -const _i12 = ["txinindex"]; -const _i13 = ["monthindex"]; -const _i14 = ["opreturnindex"]; -const _i15 = ["txoutindex"]; -const _i16 = ["p2aaddressindex"]; -const _i17 = ["p2msoutputindex"]; -const _i18 = ["p2pk33addressindex"]; -const _i19 = ["p2pk65addressindex"]; -const _i20 = ["p2pkhaddressindex"]; -const _i21 = ["p2shaddressindex"]; -const _i22 = ["p2traddressindex"]; -const _i23 = ["p2wpkhaddressindex"]; -const _i24 = ["p2wshaddressindex"]; -const _i25 = ["quarterindex"]; -const _i26 = ["semesterindex"]; -const _i27 = ["txindex"]; -const _i28 = ["unknownoutputindex"]; -const _i29 = ["weekindex"]; -const _i30 = ["yearindex"]; -const _i31 = ["loadedaddressindex"]; -const _i32 = ["emptyaddressindex"]; +]); +const _i5 = /** @type {const} */ (["dateindex", "height"]); +const _i6 = /** @type {const} */ (["dateindex"]); +const _i7 = /** @type {const} */ (["decadeindex"]); +const _i8 = /** @type {const} */ (["difficultyepoch"]); +const _i9 = /** @type {const} */ (["emptyoutputindex"]); +const _i10 = /** @type {const} */ (["halvingepoch"]); +const _i11 = /** @type {const} */ (["height"]); +const _i12 = /** @type {const} */ (["txinindex"]); +const _i13 = /** @type {const} */ (["monthindex"]); +const _i14 = /** @type {const} */ (["opreturnindex"]); +const _i15 = /** @type {const} */ (["txoutindex"]); +const _i16 = /** @type {const} */ (["p2aaddressindex"]); +const _i17 = /** @type {const} */ (["p2msoutputindex"]); +const _i18 = /** @type {const} */ (["p2pk33addressindex"]); +const _i19 = /** @type {const} */ (["p2pk65addressindex"]); +const _i20 = /** @type {const} */ (["p2pkhaddressindex"]); +const _i21 = /** @type {const} */ (["p2shaddressindex"]); +const _i22 = /** @type {const} */ (["p2traddressindex"]); +const _i23 = /** @type {const} */ (["p2wpkhaddressindex"]); +const _i24 = /** @type {const} */ (["p2wshaddressindex"]); +const _i25 = /** @type {const} */ (["quarterindex"]); +const _i26 = /** @type {const} */ (["semesterindex"]); +const _i27 = /** @type {const} */ (["txindex"]); +const _i28 = /** @type {const} */ (["unknownoutputindex"]); +const _i29 = /** @type {const} */ (["weekindex"]); +const _i30 = /** @type {const} */ (["yearindex"]); +const _i31 = /** @type {const} */ (["loadedaddressindex"]); +const _i32 = /** @type {const} */ (["emptyaddressindex"]); /** * Generic metric pattern factory. * @template T * @param {BrkClientBase} client * @param {string} name - The metric vec name - * @param {readonly string[]} indexes - The supported indexes - * @returns {MetricPattern} + * @param {readonly Index[]} indexes - The supported indexes */ function _mp(client, name, indexes) { - const by = {}; + const by = /** @type {any} */ ({}); for (const idx of indexes) { Object.defineProperty(by, idx, { get() { @@ -1197,6 +1196,7 @@ function _mp(client, name, indexes) { indexes() { return indexes; }, + /** @param {Index} index */ get(index) { return indexes.includes(index) ? _endpoint(client, name, index) @@ -1205,162 +1205,162 @@ function _mp(client, name, indexes) { }; } -/** @template T @typedef {{ name: string, by: { readonly dateindex: MetricEndpointBuilder, readonly decadeindex: MetricEndpointBuilder, readonly difficultyepoch: MetricEndpointBuilder, readonly height: MetricEndpointBuilder, readonly monthindex: MetricEndpointBuilder, readonly quarterindex: MetricEndpointBuilder, readonly semesterindex: MetricEndpointBuilder, readonly weekindex: MetricEndpointBuilder, readonly yearindex: MetricEndpointBuilder }, indexes: () => Index[], get: (index: Index) => MetricEndpointBuilder|undefined }} MetricPattern1 */ +/** @template T @typedef {{ name: string, by: { readonly dateindex: MetricEndpointBuilder, readonly decadeindex: MetricEndpointBuilder, readonly difficultyepoch: MetricEndpointBuilder, readonly height: MetricEndpointBuilder, readonly monthindex: MetricEndpointBuilder, readonly quarterindex: MetricEndpointBuilder, readonly semesterindex: MetricEndpointBuilder, readonly weekindex: MetricEndpointBuilder, readonly yearindex: MetricEndpointBuilder }, indexes: () => readonly Index[], get: (index: Index) => MetricEndpointBuilder|undefined }} MetricPattern1 */ /** @template T @param {BrkClientBase} client @param {string} name @returns {MetricPattern1} */ function createMetricPattern1(client, name) { return _mp(client, name, _i1); } -/** @template T @typedef {{ name: string, by: { readonly dateindex: MetricEndpointBuilder, readonly decadeindex: MetricEndpointBuilder, readonly difficultyepoch: MetricEndpointBuilder, readonly monthindex: MetricEndpointBuilder, readonly quarterindex: MetricEndpointBuilder, readonly semesterindex: MetricEndpointBuilder, readonly weekindex: MetricEndpointBuilder, readonly yearindex: MetricEndpointBuilder }, indexes: () => Index[], get: (index: Index) => MetricEndpointBuilder|undefined }} MetricPattern2 */ +/** @template T @typedef {{ name: string, by: { readonly dateindex: MetricEndpointBuilder, readonly decadeindex: MetricEndpointBuilder, readonly difficultyepoch: MetricEndpointBuilder, readonly monthindex: MetricEndpointBuilder, readonly quarterindex: MetricEndpointBuilder, readonly semesterindex: MetricEndpointBuilder, readonly weekindex: MetricEndpointBuilder, readonly yearindex: MetricEndpointBuilder }, indexes: () => readonly Index[], get: (index: Index) => MetricEndpointBuilder|undefined }} MetricPattern2 */ /** @template T @param {BrkClientBase} client @param {string} name @returns {MetricPattern2} */ function createMetricPattern2(client, name) { return _mp(client, name, _i2); } -/** @template T @typedef {{ name: string, by: { readonly dateindex: MetricEndpointBuilder, readonly decadeindex: MetricEndpointBuilder, readonly height: MetricEndpointBuilder, readonly monthindex: MetricEndpointBuilder, readonly quarterindex: MetricEndpointBuilder, readonly semesterindex: MetricEndpointBuilder, readonly weekindex: MetricEndpointBuilder, readonly yearindex: MetricEndpointBuilder }, indexes: () => Index[], get: (index: Index) => MetricEndpointBuilder|undefined }} MetricPattern3 */ +/** @template T @typedef {{ name: string, by: { readonly dateindex: MetricEndpointBuilder, readonly decadeindex: MetricEndpointBuilder, readonly height: MetricEndpointBuilder, readonly monthindex: MetricEndpointBuilder, readonly quarterindex: MetricEndpointBuilder, readonly semesterindex: MetricEndpointBuilder, readonly weekindex: MetricEndpointBuilder, readonly yearindex: MetricEndpointBuilder }, indexes: () => readonly Index[], get: (index: Index) => MetricEndpointBuilder|undefined }} MetricPattern3 */ /** @template T @param {BrkClientBase} client @param {string} name @returns {MetricPattern3} */ function createMetricPattern3(client, name) { return _mp(client, name, _i3); } -/** @template T @typedef {{ name: string, by: { readonly dateindex: MetricEndpointBuilder, readonly decadeindex: MetricEndpointBuilder, readonly monthindex: MetricEndpointBuilder, readonly quarterindex: MetricEndpointBuilder, readonly semesterindex: MetricEndpointBuilder, readonly weekindex: MetricEndpointBuilder, readonly yearindex: MetricEndpointBuilder }, indexes: () => Index[], get: (index: Index) => MetricEndpointBuilder|undefined }} MetricPattern4 */ +/** @template T @typedef {{ name: string, by: { readonly dateindex: MetricEndpointBuilder, readonly decadeindex: MetricEndpointBuilder, readonly monthindex: MetricEndpointBuilder, readonly quarterindex: MetricEndpointBuilder, readonly semesterindex: MetricEndpointBuilder, readonly weekindex: MetricEndpointBuilder, readonly yearindex: MetricEndpointBuilder }, indexes: () => readonly Index[], get: (index: Index) => MetricEndpointBuilder|undefined }} MetricPattern4 */ /** @template T @param {BrkClientBase} client @param {string} name @returns {MetricPattern4} */ function createMetricPattern4(client, name) { return _mp(client, name, _i4); } -/** @template T @typedef {{ name: string, by: { readonly dateindex: MetricEndpointBuilder, readonly height: MetricEndpointBuilder }, indexes: () => Index[], get: (index: Index) => MetricEndpointBuilder|undefined }} MetricPattern5 */ +/** @template T @typedef {{ name: string, by: { readonly dateindex: MetricEndpointBuilder, readonly height: MetricEndpointBuilder }, indexes: () => readonly Index[], get: (index: Index) => MetricEndpointBuilder|undefined }} MetricPattern5 */ /** @template T @param {BrkClientBase} client @param {string} name @returns {MetricPattern5} */ function createMetricPattern5(client, name) { return _mp(client, name, _i5); } -/** @template T @typedef {{ name: string, by: { readonly dateindex: MetricEndpointBuilder }, indexes: () => Index[], get: (index: Index) => MetricEndpointBuilder|undefined }} MetricPattern6 */ +/** @template T @typedef {{ name: string, by: { readonly dateindex: MetricEndpointBuilder }, indexes: () => readonly Index[], get: (index: Index) => MetricEndpointBuilder|undefined }} MetricPattern6 */ /** @template T @param {BrkClientBase} client @param {string} name @returns {MetricPattern6} */ function createMetricPattern6(client, name) { return _mp(client, name, _i6); } -/** @template T @typedef {{ name: string, by: { readonly decadeindex: MetricEndpointBuilder }, indexes: () => Index[], get: (index: Index) => MetricEndpointBuilder|undefined }} MetricPattern7 */ +/** @template T @typedef {{ name: string, by: { readonly decadeindex: MetricEndpointBuilder }, indexes: () => readonly Index[], get: (index: Index) => MetricEndpointBuilder|undefined }} MetricPattern7 */ /** @template T @param {BrkClientBase} client @param {string} name @returns {MetricPattern7} */ function createMetricPattern7(client, name) { return _mp(client, name, _i7); } -/** @template T @typedef {{ name: string, by: { readonly difficultyepoch: MetricEndpointBuilder }, indexes: () => Index[], get: (index: Index) => MetricEndpointBuilder|undefined }} MetricPattern8 */ +/** @template T @typedef {{ name: string, by: { readonly difficultyepoch: MetricEndpointBuilder }, indexes: () => readonly Index[], get: (index: Index) => MetricEndpointBuilder|undefined }} MetricPattern8 */ /** @template T @param {BrkClientBase} client @param {string} name @returns {MetricPattern8} */ function createMetricPattern8(client, name) { return _mp(client, name, _i8); } -/** @template T @typedef {{ name: string, by: { readonly emptyoutputindex: MetricEndpointBuilder }, indexes: () => Index[], get: (index: Index) => MetricEndpointBuilder|undefined }} MetricPattern9 */ +/** @template T @typedef {{ name: string, by: { readonly emptyoutputindex: MetricEndpointBuilder }, indexes: () => readonly Index[], get: (index: Index) => MetricEndpointBuilder|undefined }} MetricPattern9 */ /** @template T @param {BrkClientBase} client @param {string} name @returns {MetricPattern9} */ function createMetricPattern9(client, name) { return _mp(client, name, _i9); } -/** @template T @typedef {{ name: string, by: { readonly halvingepoch: MetricEndpointBuilder }, indexes: () => Index[], get: (index: Index) => MetricEndpointBuilder|undefined }} MetricPattern10 */ +/** @template T @typedef {{ name: string, by: { readonly halvingepoch: MetricEndpointBuilder }, indexes: () => readonly Index[], get: (index: Index) => MetricEndpointBuilder|undefined }} MetricPattern10 */ /** @template T @param {BrkClientBase} client @param {string} name @returns {MetricPattern10} */ function createMetricPattern10(client, name) { return _mp(client, name, _i10); } -/** @template T @typedef {{ name: string, by: { readonly height: MetricEndpointBuilder }, indexes: () => Index[], get: (index: Index) => MetricEndpointBuilder|undefined }} MetricPattern11 */ +/** @template T @typedef {{ name: string, by: { readonly height: MetricEndpointBuilder }, indexes: () => readonly Index[], get: (index: Index) => MetricEndpointBuilder|undefined }} MetricPattern11 */ /** @template T @param {BrkClientBase} client @param {string} name @returns {MetricPattern11} */ function createMetricPattern11(client, name) { return _mp(client, name, _i11); } -/** @template T @typedef {{ name: string, by: { readonly txinindex: MetricEndpointBuilder }, indexes: () => Index[], get: (index: Index) => MetricEndpointBuilder|undefined }} MetricPattern12 */ +/** @template T @typedef {{ name: string, by: { readonly txinindex: MetricEndpointBuilder }, indexes: () => readonly Index[], get: (index: Index) => MetricEndpointBuilder|undefined }} MetricPattern12 */ /** @template T @param {BrkClientBase} client @param {string} name @returns {MetricPattern12} */ function createMetricPattern12(client, name) { return _mp(client, name, _i12); } -/** @template T @typedef {{ name: string, by: { readonly monthindex: MetricEndpointBuilder }, indexes: () => Index[], get: (index: Index) => MetricEndpointBuilder|undefined }} MetricPattern13 */ +/** @template T @typedef {{ name: string, by: { readonly monthindex: MetricEndpointBuilder }, indexes: () => readonly Index[], get: (index: Index) => MetricEndpointBuilder|undefined }} MetricPattern13 */ /** @template T @param {BrkClientBase} client @param {string} name @returns {MetricPattern13} */ function createMetricPattern13(client, name) { return _mp(client, name, _i13); } -/** @template T @typedef {{ name: string, by: { readonly opreturnindex: MetricEndpointBuilder }, indexes: () => Index[], get: (index: Index) => MetricEndpointBuilder|undefined }} MetricPattern14 */ +/** @template T @typedef {{ name: string, by: { readonly opreturnindex: MetricEndpointBuilder }, indexes: () => readonly Index[], get: (index: Index) => MetricEndpointBuilder|undefined }} MetricPattern14 */ /** @template T @param {BrkClientBase} client @param {string} name @returns {MetricPattern14} */ function createMetricPattern14(client, name) { return _mp(client, name, _i14); } -/** @template T @typedef {{ name: string, by: { readonly txoutindex: MetricEndpointBuilder }, indexes: () => Index[], get: (index: Index) => MetricEndpointBuilder|undefined }} MetricPattern15 */ +/** @template T @typedef {{ name: string, by: { readonly txoutindex: MetricEndpointBuilder }, indexes: () => readonly Index[], get: (index: Index) => MetricEndpointBuilder|undefined }} MetricPattern15 */ /** @template T @param {BrkClientBase} client @param {string} name @returns {MetricPattern15} */ function createMetricPattern15(client, name) { return _mp(client, name, _i15); } -/** @template T @typedef {{ name: string, by: { readonly p2aaddressindex: MetricEndpointBuilder }, indexes: () => Index[], get: (index: Index) => MetricEndpointBuilder|undefined }} MetricPattern16 */ +/** @template T @typedef {{ name: string, by: { readonly p2aaddressindex: MetricEndpointBuilder }, indexes: () => readonly Index[], get: (index: Index) => MetricEndpointBuilder|undefined }} MetricPattern16 */ /** @template T @param {BrkClientBase} client @param {string} name @returns {MetricPattern16} */ function createMetricPattern16(client, name) { return _mp(client, name, _i16); } -/** @template T @typedef {{ name: string, by: { readonly p2msoutputindex: MetricEndpointBuilder }, indexes: () => Index[], get: (index: Index) => MetricEndpointBuilder|undefined }} MetricPattern17 */ +/** @template T @typedef {{ name: string, by: { readonly p2msoutputindex: MetricEndpointBuilder }, indexes: () => readonly Index[], get: (index: Index) => MetricEndpointBuilder|undefined }} MetricPattern17 */ /** @template T @param {BrkClientBase} client @param {string} name @returns {MetricPattern17} */ function createMetricPattern17(client, name) { return _mp(client, name, _i17); } -/** @template T @typedef {{ name: string, by: { readonly p2pk33addressindex: MetricEndpointBuilder }, indexes: () => Index[], get: (index: Index) => MetricEndpointBuilder|undefined }} MetricPattern18 */ +/** @template T @typedef {{ name: string, by: { readonly p2pk33addressindex: MetricEndpointBuilder }, indexes: () => readonly Index[], get: (index: Index) => MetricEndpointBuilder|undefined }} MetricPattern18 */ /** @template T @param {BrkClientBase} client @param {string} name @returns {MetricPattern18} */ function createMetricPattern18(client, name) { return _mp(client, name, _i18); } -/** @template T @typedef {{ name: string, by: { readonly p2pk65addressindex: MetricEndpointBuilder }, indexes: () => Index[], get: (index: Index) => MetricEndpointBuilder|undefined }} MetricPattern19 */ +/** @template T @typedef {{ name: string, by: { readonly p2pk65addressindex: MetricEndpointBuilder }, indexes: () => readonly Index[], get: (index: Index) => MetricEndpointBuilder|undefined }} MetricPattern19 */ /** @template T @param {BrkClientBase} client @param {string} name @returns {MetricPattern19} */ function createMetricPattern19(client, name) { return _mp(client, name, _i19); } -/** @template T @typedef {{ name: string, by: { readonly p2pkhaddressindex: MetricEndpointBuilder }, indexes: () => Index[], get: (index: Index) => MetricEndpointBuilder|undefined }} MetricPattern20 */ +/** @template T @typedef {{ name: string, by: { readonly p2pkhaddressindex: MetricEndpointBuilder }, indexes: () => readonly Index[], get: (index: Index) => MetricEndpointBuilder|undefined }} MetricPattern20 */ /** @template T @param {BrkClientBase} client @param {string} name @returns {MetricPattern20} */ function createMetricPattern20(client, name) { return _mp(client, name, _i20); } -/** @template T @typedef {{ name: string, by: { readonly p2shaddressindex: MetricEndpointBuilder }, indexes: () => Index[], get: (index: Index) => MetricEndpointBuilder|undefined }} MetricPattern21 */ +/** @template T @typedef {{ name: string, by: { readonly p2shaddressindex: MetricEndpointBuilder }, indexes: () => readonly Index[], get: (index: Index) => MetricEndpointBuilder|undefined }} MetricPattern21 */ /** @template T @param {BrkClientBase} client @param {string} name @returns {MetricPattern21} */ function createMetricPattern21(client, name) { return _mp(client, name, _i21); } -/** @template T @typedef {{ name: string, by: { readonly p2traddressindex: MetricEndpointBuilder }, indexes: () => Index[], get: (index: Index) => MetricEndpointBuilder|undefined }} MetricPattern22 */ +/** @template T @typedef {{ name: string, by: { readonly p2traddressindex: MetricEndpointBuilder }, indexes: () => readonly Index[], get: (index: Index) => MetricEndpointBuilder|undefined }} MetricPattern22 */ /** @template T @param {BrkClientBase} client @param {string} name @returns {MetricPattern22} */ function createMetricPattern22(client, name) { return _mp(client, name, _i22); } -/** @template T @typedef {{ name: string, by: { readonly p2wpkhaddressindex: MetricEndpointBuilder }, indexes: () => Index[], get: (index: Index) => MetricEndpointBuilder|undefined }} MetricPattern23 */ +/** @template T @typedef {{ name: string, by: { readonly p2wpkhaddressindex: MetricEndpointBuilder }, indexes: () => readonly Index[], get: (index: Index) => MetricEndpointBuilder|undefined }} MetricPattern23 */ /** @template T @param {BrkClientBase} client @param {string} name @returns {MetricPattern23} */ function createMetricPattern23(client, name) { return _mp(client, name, _i23); } -/** @template T @typedef {{ name: string, by: { readonly p2wshaddressindex: MetricEndpointBuilder }, indexes: () => Index[], get: (index: Index) => MetricEndpointBuilder|undefined }} MetricPattern24 */ +/** @template T @typedef {{ name: string, by: { readonly p2wshaddressindex: MetricEndpointBuilder }, indexes: () => readonly Index[], get: (index: Index) => MetricEndpointBuilder|undefined }} MetricPattern24 */ /** @template T @param {BrkClientBase} client @param {string} name @returns {MetricPattern24} */ function createMetricPattern24(client, name) { return _mp(client, name, _i24); } -/** @template T @typedef {{ name: string, by: { readonly quarterindex: MetricEndpointBuilder }, indexes: () => Index[], get: (index: Index) => MetricEndpointBuilder|undefined }} MetricPattern25 */ +/** @template T @typedef {{ name: string, by: { readonly quarterindex: MetricEndpointBuilder }, indexes: () => readonly Index[], get: (index: Index) => MetricEndpointBuilder|undefined }} MetricPattern25 */ /** @template T @param {BrkClientBase} client @param {string} name @returns {MetricPattern25} */ function createMetricPattern25(client, name) { return _mp(client, name, _i25); } -/** @template T @typedef {{ name: string, by: { readonly semesterindex: MetricEndpointBuilder }, indexes: () => Index[], get: (index: Index) => MetricEndpointBuilder|undefined }} MetricPattern26 */ +/** @template T @typedef {{ name: string, by: { readonly semesterindex: MetricEndpointBuilder }, indexes: () => readonly Index[], get: (index: Index) => MetricEndpointBuilder|undefined }} MetricPattern26 */ /** @template T @param {BrkClientBase} client @param {string} name @returns {MetricPattern26} */ function createMetricPattern26(client, name) { return _mp(client, name, _i26); } -/** @template T @typedef {{ name: string, by: { readonly txindex: MetricEndpointBuilder }, indexes: () => Index[], get: (index: Index) => MetricEndpointBuilder|undefined }} MetricPattern27 */ +/** @template T @typedef {{ name: string, by: { readonly txindex: MetricEndpointBuilder }, indexes: () => readonly Index[], get: (index: Index) => MetricEndpointBuilder|undefined }} MetricPattern27 */ /** @template T @param {BrkClientBase} client @param {string} name @returns {MetricPattern27} */ function createMetricPattern27(client, name) { return _mp(client, name, _i27); } -/** @template T @typedef {{ name: string, by: { readonly unknownoutputindex: MetricEndpointBuilder }, indexes: () => Index[], get: (index: Index) => MetricEndpointBuilder|undefined }} MetricPattern28 */ +/** @template T @typedef {{ name: string, by: { readonly unknownoutputindex: MetricEndpointBuilder }, indexes: () => readonly Index[], get: (index: Index) => MetricEndpointBuilder|undefined }} MetricPattern28 */ /** @template T @param {BrkClientBase} client @param {string} name @returns {MetricPattern28} */ function createMetricPattern28(client, name) { return _mp(client, name, _i28); } -/** @template T @typedef {{ name: string, by: { readonly weekindex: MetricEndpointBuilder }, indexes: () => Index[], get: (index: Index) => MetricEndpointBuilder|undefined }} MetricPattern29 */ +/** @template T @typedef {{ name: string, by: { readonly weekindex: MetricEndpointBuilder }, indexes: () => readonly Index[], get: (index: Index) => MetricEndpointBuilder|undefined }} MetricPattern29 */ /** @template T @param {BrkClientBase} client @param {string} name @returns {MetricPattern29} */ function createMetricPattern29(client, name) { return _mp(client, name, _i29); } -/** @template T @typedef {{ name: string, by: { readonly yearindex: MetricEndpointBuilder }, indexes: () => Index[], get: (index: Index) => MetricEndpointBuilder|undefined }} MetricPattern30 */ +/** @template T @typedef {{ name: string, by: { readonly yearindex: MetricEndpointBuilder }, indexes: () => readonly Index[], get: (index: Index) => MetricEndpointBuilder|undefined }} MetricPattern30 */ /** @template T @param {BrkClientBase} client @param {string} name @returns {MetricPattern30} */ function createMetricPattern30(client, name) { return _mp(client, name, _i30); } -/** @template T @typedef {{ name: string, by: { readonly loadedaddressindex: MetricEndpointBuilder }, indexes: () => Index[], get: (index: Index) => MetricEndpointBuilder|undefined }} MetricPattern31 */ +/** @template T @typedef {{ name: string, by: { readonly loadedaddressindex: MetricEndpointBuilder }, indexes: () => readonly Index[], get: (index: Index) => MetricEndpointBuilder|undefined }} MetricPattern31 */ /** @template T @param {BrkClientBase} client @param {string} name @returns {MetricPattern31} */ function createMetricPattern31(client, name) { return _mp(client, name, _i31); } -/** @template T @typedef {{ name: string, by: { readonly emptyaddressindex: MetricEndpointBuilder }, indexes: () => Index[], get: (index: Index) => MetricEndpointBuilder|undefined }} MetricPattern32 */ +/** @template T @typedef {{ name: string, by: { readonly emptyaddressindex: MetricEndpointBuilder }, indexes: () => readonly Index[], get: (index: Index) => MetricEndpointBuilder|undefined }} MetricPattern32 */ /** @template T @param {BrkClientBase} client @param {string} name @returns {MetricPattern32} */ function createMetricPattern32(client, name) { return _mp(client, name, _i32); @@ -2397,6 +2397,45 @@ function createBitcoinPattern(client, acc) { }; } +/** + * @template T + * @typedef {Object} ClassAveragePricePattern + * @property {MetricPattern4} _2015 + * @property {MetricPattern4} _2016 + * @property {MetricPattern4} _2017 + * @property {MetricPattern4} _2018 + * @property {MetricPattern4} _2019 + * @property {MetricPattern4} _2020 + * @property {MetricPattern4} _2021 + * @property {MetricPattern4} _2022 + * @property {MetricPattern4} _2023 + * @property {MetricPattern4} _2024 + * @property {MetricPattern4} _2025 + */ + +/** + * Create a ClassAveragePricePattern pattern node + * @template T + * @param {BrkClientBase} client + * @param {string} acc - Accumulated metric name + * @returns {ClassAveragePricePattern} + */ +function createClassAveragePricePattern(client, acc) { + return { + _2015: createMetricPattern4(client, _m(acc, "2015_average_price")), + _2016: createMetricPattern4(client, _m(acc, "2016_average_price")), + _2017: createMetricPattern4(client, _m(acc, "2017_average_price")), + _2018: createMetricPattern4(client, _m(acc, "2018_average_price")), + _2019: createMetricPattern4(client, _m(acc, "2019_average_price")), + _2020: createMetricPattern4(client, _m(acc, "2020_average_price")), + _2021: createMetricPattern4(client, _m(acc, "2021_average_price")), + _2022: createMetricPattern4(client, _m(acc, "2022_average_price")), + _2023: createMetricPattern4(client, _m(acc, "2023_average_price")), + _2024: createMetricPattern4(client, _m(acc, "2024_average_price")), + _2025: createMetricPattern4(client, _m(acc, "2025_average_price")), + }; +} + /** * @template T * @typedef {Object} DollarsPattern @@ -2436,107 +2475,6 @@ function createDollarsPattern(client, acc) { }; } -/** - * @template T - * @typedef {Object} ClassAveragePricePattern - * @property {MetricPattern4} _2015 - * @property {MetricPattern4} _2016 - * @property {MetricPattern4} _2017 - * @property {MetricPattern4} _2018 - * @property {MetricPattern4} _2019 - * @property {MetricPattern4} _2020 - * @property {MetricPattern4} _2021 - * @property {MetricPattern4} _2022 - * @property {MetricPattern4} _2023 - * @property {MetricPattern4} _2024 - * @property {MetricPattern4} _2025 - */ - -/** - * Create a ClassAveragePricePattern pattern node - * @template T - * @param {BrkClientBase} client - * @param {string} acc - Accumulated metric name - * @returns {ClassAveragePricePattern} - */ -function createClassAveragePricePattern(client, acc) { - return { - _2015: createMetricPattern4(client, _m(acc, "2015_returns")), - _2016: createMetricPattern4(client, _m(acc, "2016_returns")), - _2017: createMetricPattern4(client, _m(acc, "2017_returns")), - _2018: createMetricPattern4(client, _m(acc, "2018_returns")), - _2019: createMetricPattern4(client, _m(acc, "2019_returns")), - _2020: createMetricPattern4(client, _m(acc, "2020_returns")), - _2021: createMetricPattern4(client, _m(acc, "2021_returns")), - _2022: createMetricPattern4(client, _m(acc, "2022_returns")), - _2023: createMetricPattern4(client, _m(acc, "2023_returns")), - _2024: createMetricPattern4(client, _m(acc, "2024_returns")), - _2025: createMetricPattern4(client, _m(acc, "2025_returns")), - }; -} - -/** - * @typedef {Object} RelativePattern - * @property {MetricPattern1} negUnrealizedLossRelToMarketCap - * @property {MetricPattern1} netUnrealizedPnlRelToMarketCap - * @property {MetricPattern1} nupl - * @property {MetricPattern1} supplyInLossRelToCirculatingSupply - * @property {MetricPattern1} supplyInLossRelToOwnSupply - * @property {MetricPattern1} supplyInProfitRelToCirculatingSupply - * @property {MetricPattern1} supplyInProfitRelToOwnSupply - * @property {MetricPattern4} supplyRelToCirculatingSupply - * @property {MetricPattern1} unrealizedLossRelToMarketCap - * @property {MetricPattern1} unrealizedProfitRelToMarketCap - */ - -/** - * Create a RelativePattern pattern node - * @param {BrkClientBase} client - * @param {string} acc - Accumulated metric name - * @returns {RelativePattern} - */ -function createRelativePattern(client, acc) { - return { - negUnrealizedLossRelToMarketCap: createMetricPattern1( - client, - _m(acc, "neg_unrealized_loss_rel_to_market_cap"), - ), - netUnrealizedPnlRelToMarketCap: createMetricPattern1( - client, - _m(acc, "net_unrealized_pnl_rel_to_market_cap"), - ), - nupl: createMetricPattern1(client, _m(acc, "nupl")), - supplyInLossRelToCirculatingSupply: createMetricPattern1( - client, - _m(acc, "supply_in_loss_rel_to_circulating_supply"), - ), - supplyInLossRelToOwnSupply: createMetricPattern1( - client, - _m(acc, "supply_in_loss_rel_to_own_supply"), - ), - supplyInProfitRelToCirculatingSupply: createMetricPattern1( - client, - _m(acc, "supply_in_profit_rel_to_circulating_supply"), - ), - supplyInProfitRelToOwnSupply: createMetricPattern1( - client, - _m(acc, "supply_in_profit_rel_to_own_supply"), - ), - supplyRelToCirculatingSupply: createMetricPattern4( - client, - _m(acc, "supply_rel_to_circulating_supply"), - ), - unrealizedLossRelToMarketCap: createMetricPattern1( - client, - _m(acc, "unrealized_loss_rel_to_market_cap"), - ), - unrealizedProfitRelToMarketCap: createMetricPattern1( - client, - _m(acc, "unrealized_profit_rel_to_market_cap"), - ), - }; -} - /** * @typedef {Object} RelativePattern2 * @property {MetricPattern1} negUnrealizedLossRelToOwnMarketCap @@ -2602,6 +2540,68 @@ function createRelativePattern2(client, acc) { }; } +/** + * @typedef {Object} RelativePattern + * @property {MetricPattern1} negUnrealizedLossRelToMarketCap + * @property {MetricPattern1} netUnrealizedPnlRelToMarketCap + * @property {MetricPattern1} nupl + * @property {MetricPattern1} supplyInLossRelToCirculatingSupply + * @property {MetricPattern1} supplyInLossRelToOwnSupply + * @property {MetricPattern1} supplyInProfitRelToCirculatingSupply + * @property {MetricPattern1} supplyInProfitRelToOwnSupply + * @property {MetricPattern4} supplyRelToCirculatingSupply + * @property {MetricPattern1} unrealizedLossRelToMarketCap + * @property {MetricPattern1} unrealizedProfitRelToMarketCap + */ + +/** + * Create a RelativePattern pattern node + * @param {BrkClientBase} client + * @param {string} acc - Accumulated metric name + * @returns {RelativePattern} + */ +function createRelativePattern(client, acc) { + return { + negUnrealizedLossRelToMarketCap: createMetricPattern1( + client, + _m(acc, "neg_unrealized_loss_rel_to_market_cap"), + ), + netUnrealizedPnlRelToMarketCap: createMetricPattern1( + client, + _m(acc, "net_unrealized_pnl_rel_to_market_cap"), + ), + nupl: createMetricPattern1(client, _m(acc, "nupl")), + supplyInLossRelToCirculatingSupply: createMetricPattern1( + client, + _m(acc, "supply_in_loss_rel_to_circulating_supply"), + ), + supplyInLossRelToOwnSupply: createMetricPattern1( + client, + _m(acc, "supply_in_loss_rel_to_own_supply"), + ), + supplyInProfitRelToCirculatingSupply: createMetricPattern1( + client, + _m(acc, "supply_in_profit_rel_to_circulating_supply"), + ), + supplyInProfitRelToOwnSupply: createMetricPattern1( + client, + _m(acc, "supply_in_profit_rel_to_own_supply"), + ), + supplyRelToCirculatingSupply: createMetricPattern4( + client, + _m(acc, "supply_rel_to_circulating_supply"), + ), + unrealizedLossRelToMarketCap: createMetricPattern1( + client, + _m(acc, "unrealized_loss_rel_to_market_cap"), + ), + unrealizedProfitRelToMarketCap: createMetricPattern1( + client, + _m(acc, "unrealized_profit_rel_to_market_cap"), + ), + }; +} + /** * @template T * @typedef {Object} CountPattern2 @@ -2672,41 +2672,6 @@ function createAddrCountPattern(client, acc) { }; } -/** - * @template T - * @typedef {Object} FeeRatePattern - * @property {MetricPattern1} average - * @property {MetricPattern1} max - * @property {MetricPattern11} median - * @property {MetricPattern1} min - * @property {MetricPattern11} pct10 - * @property {MetricPattern11} pct25 - * @property {MetricPattern11} pct75 - * @property {MetricPattern11} pct90 - * @property {MetricPattern27} txindex - */ - -/** - * Create a FeeRatePattern pattern node - * @template T - * @param {BrkClientBase} client - * @param {string} acc - Accumulated metric name - * @returns {FeeRatePattern} - */ -function createFeeRatePattern(client, acc) { - return { - average: createMetricPattern1(client, _m(acc, "average")), - max: createMetricPattern1(client, _m(acc, "max")), - median: createMetricPattern11(client, _m(acc, "median")), - min: createMetricPattern1(client, _m(acc, "min")), - pct10: createMetricPattern11(client, _m(acc, "pct10")), - pct25: createMetricPattern11(client, _m(acc, "pct25")), - pct75: createMetricPattern11(client, _m(acc, "pct75")), - pct90: createMetricPattern11(client, _m(acc, "pct90")), - txindex: createMetricPattern27(client, acc), - }; -} - /** * @template T * @typedef {Object} FullnessPattern @@ -2742,6 +2707,41 @@ function createFullnessPattern(client, acc) { }; } +/** + * @template T + * @typedef {Object} FeeRatePattern + * @property {MetricPattern1} average + * @property {MetricPattern1} max + * @property {MetricPattern11} median + * @property {MetricPattern1} min + * @property {MetricPattern11} pct10 + * @property {MetricPattern11} pct25 + * @property {MetricPattern11} pct75 + * @property {MetricPattern11} pct90 + * @property {MetricPattern27} txindex + */ + +/** + * Create a FeeRatePattern pattern node + * @template T + * @param {BrkClientBase} client + * @param {string} acc - Accumulated metric name + * @returns {FeeRatePattern} + */ +function createFeeRatePattern(client, acc) { + return { + average: createMetricPattern1(client, _m(acc, "average")), + max: createMetricPattern1(client, _m(acc, "max")), + median: createMetricPattern11(client, _m(acc, "median")), + min: createMetricPattern1(client, _m(acc, "min")), + pct10: createMetricPattern11(client, _m(acc, "pct10")), + pct25: createMetricPattern11(client, _m(acc, "pct25")), + pct75: createMetricPattern11(client, _m(acc, "pct75")), + pct90: createMetricPattern11(client, _m(acc, "pct90")), + txindex: createMetricPattern27(client, acc), + }; +} + /** * @typedef {Object} _0satsPattern * @property {ActivityPattern2} activity @@ -2774,89 +2774,31 @@ function create_0satsPattern(client, acc) { } /** - * @typedef {Object} _100btcPattern - * @property {ActivityPattern2} activity - * @property {CostBasisPattern} costBasis - * @property {OutputsPattern} outputs - * @property {RealizedPattern} realized - * @property {RelativePattern} relative - * @property {SupplyPattern2} supply - * @property {UnrealizedPattern} unrealized + * @typedef {Object} PeriodCagrPattern + * @property {MetricPattern4} _10y + * @property {MetricPattern4} _2y + * @property {MetricPattern4} _3y + * @property {MetricPattern4} _4y + * @property {MetricPattern4} _5y + * @property {MetricPattern4} _6y + * @property {MetricPattern4} _8y */ /** - * Create a _100btcPattern pattern node + * Create a PeriodCagrPattern pattern node * @param {BrkClientBase} client * @param {string} acc - Accumulated metric name - * @returns {_100btcPattern} + * @returns {PeriodCagrPattern} */ -function create_100btcPattern(client, acc) { +function createPeriodCagrPattern(client, acc) { return { - activity: createActivityPattern2(client, acc), - costBasis: createCostBasisPattern(client, acc), - outputs: createOutputsPattern(client, _m(acc, "utxo_count")), - realized: createRealizedPattern(client, acc), - relative: createRelativePattern(client, acc), - supply: createSupplyPattern2(client, _m(acc, "supply")), - unrealized: createUnrealizedPattern(client, acc), - }; -} - -/** - * @typedef {Object} _10yTo12yPattern - * @property {ActivityPattern2} activity - * @property {CostBasisPattern2} costBasis - * @property {OutputsPattern} outputs - * @property {RealizedPattern2} realized - * @property {RelativePattern2} relative - * @property {SupplyPattern2} supply - * @property {UnrealizedPattern} unrealized - */ - -/** - * Create a _10yTo12yPattern pattern node - * @param {BrkClientBase} client - * @param {string} acc - Accumulated metric name - * @returns {_10yTo12yPattern} - */ -function create_10yTo12yPattern(client, acc) { - return { - activity: createActivityPattern2(client, acc), - costBasis: createCostBasisPattern2(client, acc), - outputs: createOutputsPattern(client, _m(acc, "utxo_count")), - realized: createRealizedPattern2(client, acc), - relative: createRelativePattern2(client, acc), - supply: createSupplyPattern2(client, _m(acc, "supply")), - unrealized: createUnrealizedPattern(client, acc), - }; -} - -/** - * @typedef {Object} _10yPattern - * @property {ActivityPattern2} activity - * @property {CostBasisPattern} costBasis - * @property {OutputsPattern} outputs - * @property {RealizedPattern4} realized - * @property {RelativePattern} relative - * @property {SupplyPattern2} supply - * @property {UnrealizedPattern} unrealized - */ - -/** - * Create a _10yPattern pattern node - * @param {BrkClientBase} client - * @param {string} acc - Accumulated metric name - * @returns {_10yPattern} - */ -function create_10yPattern(client, acc) { - return { - activity: createActivityPattern2(client, acc), - costBasis: createCostBasisPattern(client, acc), - outputs: createOutputsPattern(client, _m(acc, "utxo_count")), - realized: createRealizedPattern4(client, acc), - relative: createRelativePattern(client, acc), - supply: createSupplyPattern2(client, _m(acc, "supply")), - unrealized: createUnrealizedPattern(client, acc), + _10y: createMetricPattern4(client, _p("10y", acc)), + _2y: createMetricPattern4(client, _p("2y", acc)), + _3y: createMetricPattern4(client, _p("3y", acc)), + _4y: createMetricPattern4(client, _p("4y", acc)), + _5y: createMetricPattern4(client, _p("5y", acc)), + _6y: createMetricPattern4(client, _p("6y", acc)), + _8y: createMetricPattern4(client, _p("8y", acc)), }; } @@ -2934,31 +2876,89 @@ function create_0satsPattern2(client, acc) { } /** - * @typedef {Object} PeriodCagrPattern - * @property {MetricPattern4} _10y - * @property {MetricPattern4} _2y - * @property {MetricPattern4} _3y - * @property {MetricPattern4} _4y - * @property {MetricPattern4} _5y - * @property {MetricPattern4} _6y - * @property {MetricPattern4} _8y + * @typedef {Object} _100btcPattern + * @property {ActivityPattern2} activity + * @property {CostBasisPattern} costBasis + * @property {OutputsPattern} outputs + * @property {RealizedPattern} realized + * @property {RelativePattern} relative + * @property {SupplyPattern2} supply + * @property {UnrealizedPattern} unrealized */ /** - * Create a PeriodCagrPattern pattern node + * Create a _100btcPattern pattern node * @param {BrkClientBase} client * @param {string} acc - Accumulated metric name - * @returns {PeriodCagrPattern} + * @returns {_100btcPattern} */ -function createPeriodCagrPattern(client, acc) { +function create_100btcPattern(client, acc) { return { - _10y: createMetricPattern4(client, _p("10y", acc)), - _2y: createMetricPattern4(client, _p("2y", acc)), - _3y: createMetricPattern4(client, _p("3y", acc)), - _4y: createMetricPattern4(client, _p("4y", acc)), - _5y: createMetricPattern4(client, _p("5y", acc)), - _6y: createMetricPattern4(client, _p("6y", acc)), - _8y: createMetricPattern4(client, _p("8y", acc)), + activity: createActivityPattern2(client, acc), + costBasis: createCostBasisPattern(client, acc), + outputs: createOutputsPattern(client, _m(acc, "utxo_count")), + realized: createRealizedPattern(client, acc), + relative: createRelativePattern(client, acc), + supply: createSupplyPattern2(client, _m(acc, "supply")), + unrealized: createUnrealizedPattern(client, acc), + }; +} + +/** + * @typedef {Object} _10yPattern + * @property {ActivityPattern2} activity + * @property {CostBasisPattern} costBasis + * @property {OutputsPattern} outputs + * @property {RealizedPattern4} realized + * @property {RelativePattern} relative + * @property {SupplyPattern2} supply + * @property {UnrealizedPattern} unrealized + */ + +/** + * Create a _10yPattern pattern node + * @param {BrkClientBase} client + * @param {string} acc - Accumulated metric name + * @returns {_10yPattern} + */ +function create_10yPattern(client, acc) { + return { + activity: createActivityPattern2(client, acc), + costBasis: createCostBasisPattern(client, acc), + outputs: createOutputsPattern(client, _m(acc, "utxo_count")), + realized: createRealizedPattern4(client, acc), + relative: createRelativePattern(client, acc), + supply: createSupplyPattern2(client, _m(acc, "supply")), + unrealized: createUnrealizedPattern(client, acc), + }; +} + +/** + * @typedef {Object} _10yTo12yPattern + * @property {ActivityPattern2} activity + * @property {CostBasisPattern2} costBasis + * @property {OutputsPattern} outputs + * @property {RealizedPattern2} realized + * @property {RelativePattern2} relative + * @property {SupplyPattern2} supply + * @property {UnrealizedPattern} unrealized + */ + +/** + * Create a _10yTo12yPattern pattern node + * @param {BrkClientBase} client + * @param {string} acc - Accumulated metric name + * @returns {_10yTo12yPattern} + */ +function create_10yTo12yPattern(client, acc) { + return { + activity: createActivityPattern2(client, acc), + costBasis: createCostBasisPattern2(client, acc), + outputs: createOutputsPattern(client, _m(acc, "utxo_count")), + realized: createRealizedPattern2(client, acc), + relative: createRelativePattern2(client, acc), + supply: createSupplyPattern2(client, _m(acc, "supply")), + unrealized: createUnrealizedPattern(client, acc), }; } @@ -3025,107 +3025,23 @@ function createSplitPattern2(client, acc) { } /** - * @typedef {Object} CostBasisPattern2 - * @property {MetricPattern1} max - * @property {MetricPattern1} min - * @property {PercentilesPattern} percentiles + * @typedef {Object} ActiveSupplyPattern + * @property {MetricPattern1} bitcoin + * @property {MetricPattern1} dollars + * @property {MetricPattern1} sats */ /** - * Create a CostBasisPattern2 pattern node + * Create a ActiveSupplyPattern pattern node * @param {BrkClientBase} client * @param {string} acc - Accumulated metric name - * @returns {CostBasisPattern2} + * @returns {ActiveSupplyPattern} */ -function createCostBasisPattern2(client, acc) { +function createActiveSupplyPattern(client, acc) { return { - max: createMetricPattern1(client, _m(acc, "max_cost_basis")), - min: createMetricPattern1(client, _m(acc, "min_cost_basis")), - percentiles: createPercentilesPattern(client, _m(acc, "cost_basis")), - }; -} - -/** - * @typedef {Object} SegwitAdoptionPattern - * @property {MetricPattern11} base - * @property {MetricPattern2} cumulative - * @property {MetricPattern2} sum - */ - -/** - * Create a SegwitAdoptionPattern pattern node - * @param {BrkClientBase} client - * @param {string} acc - Accumulated metric name - * @returns {SegwitAdoptionPattern} - */ -function createSegwitAdoptionPattern(client, acc) { - return { - base: createMetricPattern11(client, acc), - cumulative: createMetricPattern2(client, _m(acc, "cumulative")), - sum: createMetricPattern2(client, _m(acc, "sum")), - }; -} - -/** - * @typedef {Object} UnclaimedRewardsPattern - * @property {BitcoinPattern2} bitcoin - * @property {BlockCountPattern} dollars - * @property {BlockCountPattern} sats - */ - -/** - * Create a UnclaimedRewardsPattern pattern node - * @param {BrkClientBase} client - * @param {string} acc - Accumulated metric name - * @returns {UnclaimedRewardsPattern} - */ -function createUnclaimedRewardsPattern(client, acc) { - return { - bitcoin: createBitcoinPattern2(client, _m(acc, "btc")), - dollars: createBlockCountPattern(client, _m(acc, "usd")), - sats: createBlockCountPattern(client, acc), - }; -} - -/** - * @typedef {Object} CoinbasePattern - * @property {BitcoinPattern} bitcoin - * @property {DollarsPattern} dollars - * @property {DollarsPattern} sats - */ - -/** - * Create a CoinbasePattern pattern node - * @param {BrkClientBase} client - * @param {string} acc - Accumulated metric name - * @returns {CoinbasePattern} - */ -function createCoinbasePattern(client, acc) { - return { - bitcoin: createBitcoinPattern(client, _m(acc, "btc")), - dollars: createDollarsPattern(client, _m(acc, "usd")), - sats: createDollarsPattern(client, acc), - }; -} - -/** - * @typedef {Object} _2015Pattern - * @property {MetricPattern4} bitcoin - * @property {MetricPattern4} dollars - * @property {MetricPattern4} sats - */ - -/** - * Create a _2015Pattern pattern node - * @param {BrkClientBase} client - * @param {string} acc - Accumulated metric name - * @returns {_2015Pattern} - */ -function create_2015Pattern(client, acc) { - return { - bitcoin: createMetricPattern4(client, _m(acc, "btc")), - dollars: createMetricPattern4(client, _m(acc, "usd")), - sats: createMetricPattern4(client, acc), + bitcoin: createMetricPattern1(client, _m(acc, "btc")), + dollars: createMetricPattern1(client, _m(acc, "usd")), + sats: createMetricPattern1(client, acc), }; } @@ -3151,42 +3067,126 @@ function createCoinbasePattern2(client, acc) { } /** - * @typedef {Object} ActiveSupplyPattern - * @property {MetricPattern1} bitcoin - * @property {MetricPattern1} dollars - * @property {MetricPattern1} sats + * @typedef {Object} _2015Pattern + * @property {MetricPattern4} bitcoin + * @property {MetricPattern4} dollars + * @property {MetricPattern4} sats */ /** - * Create a ActiveSupplyPattern pattern node + * Create a _2015Pattern pattern node * @param {BrkClientBase} client * @param {string} acc - Accumulated metric name - * @returns {ActiveSupplyPattern} + * @returns {_2015Pattern} */ -function createActiveSupplyPattern(client, acc) { +function create_2015Pattern(client, acc) { return { - bitcoin: createMetricPattern1(client, _m(acc, "btc")), - dollars: createMetricPattern1(client, _m(acc, "usd")), - sats: createMetricPattern1(client, acc), + bitcoin: createMetricPattern4(client, _m(acc, "btc")), + dollars: createMetricPattern4(client, _m(acc, "usd")), + sats: createMetricPattern4(client, acc), }; } /** - * @typedef {Object} _1dReturns1mSdPattern - * @property {MetricPattern4} sd - * @property {MetricPattern4} sma + * @typedef {Object} CoinbasePattern + * @property {BitcoinPattern} bitcoin + * @property {DollarsPattern} dollars + * @property {DollarsPattern} sats */ /** - * Create a _1dReturns1mSdPattern pattern node + * Create a CoinbasePattern pattern node * @param {BrkClientBase} client * @param {string} acc - Accumulated metric name - * @returns {_1dReturns1mSdPattern} + * @returns {CoinbasePattern} */ -function create_1dReturns1mSdPattern(client, acc) { +function createCoinbasePattern(client, acc) { return { - sd: createMetricPattern4(client, _m(acc, "sd")), - sma: createMetricPattern4(client, _m(acc, "sma")), + bitcoin: createBitcoinPattern(client, _m(acc, "btc")), + dollars: createDollarsPattern(client, _m(acc, "usd")), + sats: createDollarsPattern(client, acc), + }; +} + +/** + * @typedef {Object} UnclaimedRewardsPattern + * @property {BitcoinPattern2} bitcoin + * @property {BlockCountPattern} dollars + * @property {BlockCountPattern} sats + */ + +/** + * Create a UnclaimedRewardsPattern pattern node + * @param {BrkClientBase} client + * @param {string} acc - Accumulated metric name + * @returns {UnclaimedRewardsPattern} + */ +function createUnclaimedRewardsPattern(client, acc) { + return { + bitcoin: createBitcoinPattern2(client, _m(acc, "btc")), + dollars: createBlockCountPattern(client, _m(acc, "usd")), + sats: createBlockCountPattern(client, acc), + }; +} + +/** + * @typedef {Object} SegwitAdoptionPattern + * @property {MetricPattern11} base + * @property {MetricPattern2} cumulative + * @property {MetricPattern2} sum + */ + +/** + * Create a SegwitAdoptionPattern pattern node + * @param {BrkClientBase} client + * @param {string} acc - Accumulated metric name + * @returns {SegwitAdoptionPattern} + */ +function createSegwitAdoptionPattern(client, acc) { + return { + base: createMetricPattern11(client, acc), + cumulative: createMetricPattern2(client, _m(acc, "cumulative")), + sum: createMetricPattern2(client, _m(acc, "sum")), + }; +} + +/** + * @typedef {Object} CostBasisPattern2 + * @property {MetricPattern1} max + * @property {MetricPattern1} min + * @property {PercentilesPattern} percentiles + */ + +/** + * Create a CostBasisPattern2 pattern node + * @param {BrkClientBase} client + * @param {string} acc - Accumulated metric name + * @returns {CostBasisPattern2} + */ +function createCostBasisPattern2(client, acc) { + return { + max: createMetricPattern1(client, _m(acc, "max_cost_basis")), + min: createMetricPattern1(client, _m(acc, "min_cost_basis")), + percentiles: createPercentilesPattern(client, _m(acc, "cost_basis")), + }; +} + +/** + * @typedef {Object} CostBasisPattern + * @property {MetricPattern1} max + * @property {MetricPattern1} min + */ + +/** + * Create a CostBasisPattern pattern node + * @param {BrkClientBase} client + * @param {string} acc - Accumulated metric name + * @returns {CostBasisPattern} + */ +function createCostBasisPattern(client, acc) { + return { + max: createMetricPattern1(client, _m(acc, "max_cost_basis")), + min: createMetricPattern1(client, _m(acc, "min_cost_basis")), }; } @@ -3235,63 +3235,21 @@ function createRelativePattern4(client, acc) { } /** - * @typedef {Object} CostBasisPattern - * @property {MetricPattern1} max - * @property {MetricPattern1} min + * @typedef {Object} _1dReturns1mSdPattern + * @property {MetricPattern4} sd + * @property {MetricPattern4} sma */ /** - * Create a CostBasisPattern pattern node + * Create a _1dReturns1mSdPattern pattern node * @param {BrkClientBase} client * @param {string} acc - Accumulated metric name - * @returns {CostBasisPattern} + * @returns {_1dReturns1mSdPattern} */ -function createCostBasisPattern(client, acc) { +function create_1dReturns1mSdPattern(client, acc) { return { - max: createMetricPattern1(client, _m(acc, "max_cost_basis")), - min: createMetricPattern1(client, _m(acc, "min_cost_basis")), - }; -} - -/** - * @template T - * @typedef {Object} SatsPattern - * @property {MetricPattern1} ohlc - * @property {SplitPattern2} split - */ - -/** - * Create a SatsPattern pattern node - * @template T - * @param {BrkClientBase} client - * @param {string} acc - Accumulated metric name - * @returns {SatsPattern} - */ -function createSatsPattern(client, acc) { - return { - ohlc: createMetricPattern1(client, _m(acc, "ohlc")), - split: createSplitPattern2(client, acc), - }; -} - -/** - * @template T - * @typedef {Object} BitcoinPattern2 - * @property {MetricPattern2} cumulative - * @property {MetricPattern1} sum - */ - -/** - * Create a BitcoinPattern2 pattern node - * @template T - * @param {BrkClientBase} client - * @param {string} acc - Accumulated metric name - * @returns {BitcoinPattern2} - */ -function createBitcoinPattern2(client, acc) { - return { - cumulative: createMetricPattern2(client, _m(acc, "cumulative")), - sum: createMetricPattern1(client, acc), + sd: createMetricPattern4(client, _m(acc, "sd")), + sma: createMetricPattern4(client, _m(acc, "sma")), }; } @@ -3316,6 +3274,48 @@ function createBlockCountPattern(client, acc) { }; } +/** + * @template T + * @typedef {Object} SatsPattern + * @property {MetricPattern1} ohlc + * @property {SplitPattern2} split + */ + +/** + * Create a SatsPattern pattern node + * @template T + * @param {BrkClientBase} client + * @param {string} acc - Accumulated metric name + * @returns {SatsPattern} + */ +function createSatsPattern(client, acc) { + return { + ohlc: createMetricPattern1(client, _m(acc, "ohlc_sats")), + split: createSplitPattern2(client, _m(acc, "sats")), + }; +} + +/** + * @template T + * @typedef {Object} BitcoinPattern2 + * @property {MetricPattern2} cumulative + * @property {MetricPattern1} sum + */ + +/** + * Create a BitcoinPattern2 pattern node + * @template T + * @param {BrkClientBase} client + * @param {string} acc - Accumulated metric name + * @returns {BitcoinPattern2} + */ +function createBitcoinPattern2(client, acc) { + return { + cumulative: createMetricPattern2(client, _m(acc, "cumulative")), + sum: createMetricPattern1(client, acc), + }; +} + /** * @typedef {Object} OutputsPattern * @property {MetricPattern1} utxoCount @@ -6421,8 +6421,8 @@ function createRealizedPriceExtraPattern(client, acc) { /** * @typedef {Object} MetricsTree_Market_Dca - * @property {MetricsTree_Market_Dca_ClassAveragePrice} classAveragePrice - * @property {ClassAveragePricePattern} classReturns + * @property {ClassAveragePricePattern} classAveragePrice + * @property {MetricsTree_Market_Dca_ClassReturns} classReturns * @property {MetricsTree_Market_Dca_ClassStack} classStack * @property {PeriodAveragePricePattern} periodAveragePrice * @property {PeriodCagrPattern} periodCagr @@ -6432,18 +6432,18 @@ function createRealizedPriceExtraPattern(client, acc) { */ /** - * @typedef {Object} MetricsTree_Market_Dca_ClassAveragePrice - * @property {MetricPattern4} _2015 - * @property {MetricPattern4} _2016 - * @property {MetricPattern4} _2017 - * @property {MetricPattern4} _2018 - * @property {MetricPattern4} _2019 - * @property {MetricPattern4} _2020 - * @property {MetricPattern4} _2021 - * @property {MetricPattern4} _2022 - * @property {MetricPattern4} _2023 - * @property {MetricPattern4} _2024 - * @property {MetricPattern4} _2025 + * @typedef {Object} MetricsTree_Market_Dca_ClassReturns + * @property {MetricPattern4} _2015 + * @property {MetricPattern4} _2016 + * @property {MetricPattern4} _2017 + * @property {MetricPattern4} _2018 + * @property {MetricPattern4} _2019 + * @property {MetricPattern4} _2020 + * @property {MetricPattern4} _2021 + * @property {MetricPattern4} _2022 + * @property {MetricPattern4} _2023 + * @property {MetricPattern4} _2024 + * @property {MetricPattern4} _2025 */ /** @@ -12842,20 +12842,20 @@ class BrkClient extends BrkClientBase { ), }, dca: { - classAveragePrice: { - _2015: createMetricPattern4(this, "dca_class_2015_average_price"), - _2016: createMetricPattern4(this, "dca_class_2016_average_price"), - _2017: createMetricPattern4(this, "dca_class_2017_average_price"), - _2018: createMetricPattern4(this, "dca_class_2018_average_price"), - _2019: createMetricPattern4(this, "dca_class_2019_average_price"), - _2020: createMetricPattern4(this, "dca_class_2020_average_price"), - _2021: createMetricPattern4(this, "dca_class_2021_average_price"), - _2022: createMetricPattern4(this, "dca_class_2022_average_price"), - _2023: createMetricPattern4(this, "dca_class_2023_average_price"), - _2024: createMetricPattern4(this, "dca_class_2024_average_price"), - _2025: createMetricPattern4(this, "dca_class_2025_average_price"), + classAveragePrice: createClassAveragePricePattern(this, "dca_class"), + classReturns: { + _2015: createMetricPattern4(this, "dca_class_2015_returns"), + _2016: createMetricPattern4(this, "dca_class_2016_returns"), + _2017: createMetricPattern4(this, "dca_class_2017_returns"), + _2018: createMetricPattern4(this, "dca_class_2018_returns"), + _2019: createMetricPattern4(this, "dca_class_2019_returns"), + _2020: createMetricPattern4(this, "dca_class_2020_returns"), + _2021: createMetricPattern4(this, "dca_class_2021_returns"), + _2022: createMetricPattern4(this, "dca_class_2022_returns"), + _2023: createMetricPattern4(this, "dca_class_2023_returns"), + _2024: createMetricPattern4(this, "dca_class_2024_returns"), + _2025: createMetricPattern4(this, "dca_class_2025_returns"), }, - classReturns: createClassAveragePricePattern(this, "dca_class"), classStack: { _2015: create_2015Pattern(this, "dca_class_2015_stack"), _2016: create_2015Pattern(this, "dca_class_2016_stack"), @@ -14639,7 +14639,7 @@ class BrkClient extends BrkClientBase { oracle: { ohlcCents: createMetricPattern6(this, "oracle_ohlc_cents"), ohlcDollars: createMetricPattern6(this, "oracle_ohlc"), - priceCents: createMetricPattern11(this, "orange_price_cents"), + priceCents: createMetricPattern11(this, "oracle_price_cents"), txCount: createMetricPattern6(this, "oracle_tx_count"), }, sats: { diff --git a/modules/lean-qr/2.6.1/index.mjs b/modules/lean-qr/2.6.1/index.mjs deleted file mode 100644 index 163dd46b9..000000000 --- a/modules/lean-qr/2.6.1/index.mjs +++ /dev/null @@ -1,2 +0,0 @@ -// @ts-nocheck -const t=[.2,3/8,5/9,2/3],o=(o,e)=>r=>{const n=4*o+r-4,s="*-04-39?2$%%$%%'$%''%'''%')(%'))%(++'(++'(+.'+-.',/3',33)-/5)-43).36)058*18<+37<+4:<,4:E,5C/8@F/:EH/8?s:1,c=e/f|0,i=e%f,l=f-i,a=n>8?c*t[r]+(o>5)&-2:s,_=c-a;return{t:l*_+i*_+i,o:[[l,_],[i,_+1]],i:a}},e={min:0,L:0,M:1,Q:2,H:3,max:3},r=t=>new Uint8Array(t),n=t=>{const o=new Error(`lean-qr error ${t}`);throw o.code=t,o},s=t=>"0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ $%*+-./:".indexOf(t),f=t=>t.charCodeAt(0),c=(...t)=>(o,e)=>t.forEach(t=>t(o,e)),i=t=>o=>{o.eci!==t&&(o.push(7,4),o.push(t,8),o.eci=t)},l=t=>(o,e)=>{o.push(4,4),o.push(t.length,8+8*(e>9)),t.forEach(t=>o.push(t,8))},a=(t,o,e,r,n=(t,o)=>e(t.length,o),s=(r?o=>c(i(r),t(o)):t))=>(s.test=o,s.l=e,s.est=n,s.eci=r&&[r],s),_=a(t=>(o,e)=>{o.push(1,4),o.push(t.length,10+2*(e>26)+2*(e>9));let r=0;for(;r/[0-9]/.test(t),(t,o)=>14+2*(o>26)+2*(o>9)+10*t/3),u=a(t=>(o,e)=>{o.push(2,4),o.push(t.length,9+2*(e>26)+2*(e>9));let r=0;for(;rs(t)>=0,(t,o)=>13+2*(o>26)+2*(o>9)+5.5*t),d=a(t=>l([...t].map(f)),t=>f(t)<128,(t,o)=>12+8*(o>9)+8*t);d._=!0,d.u=!0;const p=a(d,t=>f(t)<256,d.l,3);p._=!0;const m=new TextEncoder,h=a(t=>l(m.encode(t)),()=>1,0,26,(t,o)=>12+8*(o>9)+8*m.encode(t).length);h._=!0;let w=()=>{const t=new Map,o=new TextDecoder("sjis"),e=r(2);for(let r=0;r<7973;++r)e[0]=r/192+129+64*(r>5951),e[1]=r%192+64,t.set(o.decode(e),r);return t.delete("\ufffd"),w=()=>t,t};const y=a(t=>(o,e)=>{o.push(8,4),o.push(t.length,8+2*(e>26)+2*(e>9));for(const e of t)o.push(w().get(e),13)},t=>w().has(t),(t,o)=>12+2*(o>26)+2*(o>9)+13*t);y._=!0;const g=[_,u,d,p,y,h],b={auto:(t,{modes:o=g}={})=>(e,r)=>{const s=o.map((o,e)=>{const n=new Map,s=(t,o)=>(n.has(t)||n.set(t,o(t,r)),n.get(t));return{m:o,h:1<s(e-t,o.l):(e,r)=>s(t.slice(e,r),o.est)}});let f=[{v:0}],c=0,i=0,l=-1;for(const o of[...t,""]){let t=0;if(o)for(const e of s)e.m.test(o)&&(t|=e.h);if(!o||t!==l){if(-1!==l){const t=new Set(f.map(t=>t.D)),o=[];for(const{m:e,C:r,S:n,h:a}of s)if(l&a){const s=n(c,i);for(const l of e.eci??t)if(!e.u||!l){let t;for(const o of f)if(o.D===l||e.eci){const f=o.m===e&&o.D===l,a=f?o.V:o,_=e._&&f?o.v+s-r:a.v+12*(a.D!==l)+(f?n(f?o.$:c,i):s);(!t||_o.vt(e,r))},multi:c,eci:i,bytes:l,numeric:_,alphaNumeric:u,ascii:d,iso8859_1:p,shift_jis:y,utf8:h},C=()=>({F:r(2956),I:0,push(t,o){for(let e=o,r=8-(7&this.I);e>0;e-=r,r=8)this.F[this.I>>3]|=t<>e,this.I+=e({size:t,K:e,get:(o,r)=>o>=0&&o1&(t^o),(t,o)=>1&o,t=>t%3,(t,o)=>(t+o)%3,(t,o)=>1&(t/3^o>>1),(t,o)=>(t&o&1)+t*o%3,(t,o)=>(t&o)+t*o%3&1,(t,o)=>(t^o)+t*o%3&1],E=r(511);for(let t=0,o=1;t<255;o=2*o^285*(o>127))E[E[o+255]=t++]=o;const M=t=>E[t%255],S=t=>E[t+255],v=(t,o)=>{const e=r(t.length+o.length-1);for(let r=0;r{const e=r(t.length+o.length-1);e.set(t,0);for(let r=0;r{const e=[[],[]];let n=0,s=0;for(const[r,f]of o.o)for(let c=0;c{let r=t<<=e;for(let t=134217728;t>>=1;)r&t&&(r^=o*(t>>e));return r|t},A=({size:t,K:o},e)=>{const r=(e,r,n,s)=>{for(;n-- >0;e+=t)o.fill(s,e,e+r)},n=(o,e,n)=>{for(let s=0;s++<3;n-=2)r(e*t+o-(n>>1)*(t+1),n,n,2|s)},s=2*((t-13)/(1+(e/7|0))/2+.75|0);if(e>1)for(let o=t-7;o>8;o-=s){for(let t=o;t>8;t-=s)n(o,t,5);o6)for(let r=$(e,7973,12),n=1;n<7;++n)for(let e=12;e-- >9;r>>=1)o[n*t-e]=2|1&r;r(7,2,9,2),r(t-8,8,9,2);for(let e=0;e{const e=[];for(let r=t-2,n=t,s=-1;r>=0;r-=2){for(5===r&&(r=4);n+=s,-1!==n&&n!==t;){const s=n*t+r;o[s+1]||e.push(s+1),o[s]||e.push(s)}s*=-1}return e},H=({K:t},o,e)=>o.forEach((o,r)=>t[o]=e[r>>3]>>(7&~r)&1),I=({size:t,K:o},e,r,n)=>{for(let r=0;r>=1)o[(e-(e<7))*t+8]=1&s,o[9*t-e]=1&s;for(let e=8;--e,s;s>>=1)o[8*t+e-(e<7)]=1&s,o[(t-e)*t+8]=1&s},K=({size:t,K:o},e=0,r=0)=>{for(let n=0;n>1|2098176)&(3047517^a-1),2049&i&&(e+=40),a!==f&&(l=0),f=a,e+=5===++l?3:l>5}if(n)for(let r=t+n,s=5*o[n-1]^o[n];r{r>3);if(8*f(e).t=e;--t){const o=f(t);if(8*o.t{const n=x(e.size,e.K);return I(n,o,c??r,t),n.s=K(n),n}).reduce((t,o)=>o.s(o,e)=>P(o,{modes:[...g,...t],...e});export{e as correction,P as generate,b as mode}; diff --git a/modules/lean-qr/2.6.1/index.d.ts b/modules/lean-qr/2.7.1/index.d.ts similarity index 100% rename from modules/lean-qr/2.6.1/index.d.ts rename to modules/lean-qr/2.7.1/index.d.ts diff --git a/modules/lean-qr/2.7.1/index.mjs b/modules/lean-qr/2.7.1/index.mjs new file mode 100644 index 000000000..f8625849e --- /dev/null +++ b/modules/lean-qr/2.7.1/index.mjs @@ -0,0 +1,2 @@ +// @ts-nocheck +const t = [.2, 3 / 8, 5 / 9, 2 / 3], o = (o, e) => r => { const n = 4 * o + r - 4, s = "*-04-39?2$%%$%%'$%''%'''%')(%'))%(++'(++'(+.'+-.',/3',33)-/5)-43).36)058*18<+37<+4:<,4:E,5C/8@F/:EH/ 8 ? s : 1, c = e / f | 0, i = e % f, l = f - i, a = n > 8 ? c * t[r] + (o > 5) & -2 : s, _ = c - a; return { t: l * _ + i * _ + i, o: [[l, _], [i, _ + 1]], i: a } }, e = { min: 0, L: 0, M: 1, Q: 2, H: 3, max: 3 }, r = t => new Uint8Array(t), n = t => { const o = new Error(`lean-qr error ${t}`); throw o.code = t, o }, s = t => "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ $%*+-./:".indexOf(t), f = t => t.charCodeAt(0), c = (...t) => (o, e) => t.forEach(t => t(o, e)), i = t => o => { o.eci !== t && (o.push(7, 4), t < 128 ? o.push(t, 8) : t < 16384 ? o.push(32768 | t, 16) : o.push(12582912 | t, 24), o.eci = t) }, l = t => (o, e) => { o.push(4, 4), o.push(t.length, 8 + 8 * (e > 9)), t.forEach(t => o.push(t, 8)) }, a = (t, o, e, r, n = (t, o) => e(t.length, o), s = (r ? o => c(i(r), t(o)) : t)) => (s.test = o, s.l = e, s.est = n, s.eci = r && [r], s), _ = a(t => (o, e) => { o.push(1, 4), o.push(t.length, 10 + 2 * (e > 26) + 2 * (e > 9)); let r = 0; for (; r < t.length - 2; r += 3)o.push(+t.slice(r, r + 3), 10); r < t.length - 1 ? o.push(+t.slice(r), 7) : r < t.length && o.push(+t[r], 4) }, t => /[0-9]/.test(t), (t, o) => 14 + 2 * (o > 26) + 2 * (o > 9) + 10 * t / 3), u = a(t => (o, e) => { o.push(2, 4), o.push(t.length, 9 + 2 * (e > 26) + 2 * (e > 9)); let r = 0; for (; r < t.length - 1; r += 2)o.push(45 * s(t[r]) + s(t[r + 1]), 11); r < t.length && o.push(s(t[r]), 6) }, t => s(t) >= 0, (t, o) => 13 + 2 * (o > 26) + 2 * (o > 9) + 5.5 * t), d = a(t => l([...t].map(f)), t => f(t) < 128, (t, o) => 12 + 8 * (o > 9) + 8 * t); d._ = !0, d.u = !0; const p = a(d, t => f(t) < 256, d.l, 3); p._ = !0; const m = new TextEncoder, h = a(t => l(m.encode(t)), () => 1, 0, 26, (t, o) => 12 + 8 * (o > 9) + 8 * m.encode(t).length); h._ = !0; let w = () => { const t = new Map, o = new TextDecoder("sjis"), e = r(2); for (let r = 0; r < 7973; ++r)e[0] = r / 192 + 129 + 64 * (r > 5951), e[1] = r % 192 + 64, t.set(o.decode(e), r); return t.delete("\ufffd"), w = () => t, t }; const y = a(t => (o, e) => { o.push(8, 4), o.push(t.length, 8 + 2 * (e > 26) + 2 * (e > 9)); for (const e of t) o.push(w().get(e), 13) }, t => w().has(t), (t, o) => 12 + 2 * (o > 26) + 2 * (o > 9) + 13 * t); y._ = !0; const g = [_, u, d, p, y, h], b = { auto: (t, { modes: o = g } = {}) => (e, r) => { const s = o.map((o, e) => { const n = new Map, s = (t, o) => (n.has(t) || n.set(t, o(t, r)), n.get(t)); return { m: o, h: 1 << e, C: o.est("", r), S: o.l ? (t, e) => s(e - t, o.l) : (e, r) => s(t.slice(e, r), o.est) } }); let f = [{ v: 0 }], c = 0, i = 0, l = -1; for (const o of [...t, ""]) { let t = 0; if (o) for (const e of s) e.m.test(o) && (t |= e.h); if (!o || t !== l) { if (-1 !== l) { const t = new Set(f.map(t => t.D)), o = []; for (const { m: e, C: r, S: n, h: a } of s) if (l & a) { const s = n(c, i); for (const l of e.eci ?? t) if (!e.u || !l) { let t; for (const o of f) if (o.D === l || e.eci) { const f = o.m === e && o.D === l, a = f ? o.V : o, _ = e._ && f ? o.v + s - r : a.v + 12 * (a.D !== l) + (f ? n(f ? o.$ : c, i) : s); (!t || _ < t.v) && (t = { $: f ? o.$ : c, V: a, m: e, D: l, A: i, v: _ }) } t && o.push(t) } } f = o } l = t, c = i } i += o.length } f.length || n(5); const a = []; for (let o = f.reduce((t, o) => o.v < t.v ? o : t); o.m; o = o.V)a.push(o.m(t.slice(o.$, o.A))); a.reverse().forEach(t => t(e, r)) }, multi: c, eci: i, bytes: l, numeric: _, alphaNumeric: u, ascii: d, iso8859_1: p, shift_jis: y, utf8: h }, C = () => ({ F: r(2956), I: 0, push(t, o) { for (let e = o, r = 8 - (7 & this.I); e > 0; e -= r, r = 8)this.F[this.I >> 3] |= t << r >> e, this.I += e < r ? e : r } }), x = (t, o = t * t, e = r(o)) => ({ size: t, K: e, get: (o, r) => o >= 0 && o < t && !!(1 & e[r * t + o]), toString({ on: o = "##", off: e = " ", lf: r = "\n", pad: n = 4, padX: s = n, padY: f = n } = {}) { let c = ""; for (let n = -f; n < t + f; ++n){ for (let r = -s; r < t + s; ++r)c += this.get(r, n) ? o : e; c += r } return c }, toImageData(o, { on: e = [0, 0, 0], off: r = [0, 0, 0, 0], pad: n = 4, padX: s = n, padY: f = n } = {}) { const c = t + 2 * s, i = t + 2 * f, l = o.createImageData(c, i), a = new Uint32Array(l.data.buffer); l.data.set([...e, 255]); const _ = a[0]; l.data.set([...r, 255]); const u = a[0]; for (let t = 0; t < i; ++t)for (let o = 0; o < c; ++o)a[t * c + o] = this.get(o - s, t - f) ? _ : u; return l }, toCanvas(t, o) { const e = t.getContext("2d"), r = this.toImageData(e, o); t.width = r.width, t.height = r.height, e.putImageData(r, 0, 0) }, toDataURL({ type: t = "image/png", scale: o = 1, ...e } = {}) { const r = document.createElement("canvas"), n = r.getContext("2d"), s = this.toImageData(n, e); return r.width = s.width * o, r.height = s.height * o, n.putImageData(s, 0, 0), n.imageSmoothingEnabled = !1, n.globalCompositeOperation = "copy", n.drawImage(r, 0, 0, s.width, s.height, 0, 0, r.width, r.height), r.toDataURL(t, 1) } }), z = [(t, o) => 1 & (t ^ o), (t, o) => 1 & o, t => t % 3, (t, o) => (t + o) % 3, (t, o) => 1 & (t / 3 ^ o >> 1), (t, o) => (t & o & 1) + t * o % 3, (t, o) => (t & o) + t * o % 3 & 1, (t, o) => (t ^ o) + t * o % 3 & 1], E = r(511); for (let t = 0, o = 1; t < 255; o = 2 * o ^ 285 * (o > 127))E[E[o + 255] = t++] = o; const M = t => E[t % 255], S = t => E[t + 255], v = (t, o) => { const e = r(t.length + o.length - 1); for (let r = 0; r < t.length; ++r)for (let n = 0; n < o.length; ++n)e[r + n] ^= M(t[r] + o[n]); return e.map(S) }, D = (t, o) => { const e = r(t.length + o.length - 1); e.set(t, 0); for (let r = 0; r < t.length; ++r)if (e[r]) { const t = S(e[r]); for (let n = 0; n < o.length; ++n)e[r + n] ^= M(o[n] + t) } return e.slice(t.length) }, L = [[0], [0, 0]]; for (let t = 1; t < 30; ++t)L.push(v(L[t], [0, t])); const V = (t, o) => { const e = [[], []]; let n = 0, s = 0; for (const [r, f] of o.o) for (let c = 0; c < r; ++c, n += f){ const r = t.slice(n, n + f); e[0].push(r), e[1].push(D(r, L[o.i])), s += f + o.i } const f = r(s); s = 0; for (const t of e) for (let o, e = 0; s !== o; ++e){ o = s; for (const o of t) e < o.length && (f[s++] = o[e]) } return f }, $ = (t, o, e) => { let r = t <<= e; for (let t = 134217728; t >>= 1;)r & t && (r ^= o * (t >> e)); return r | t }, A = ({ size: t, K: o }, e) => { const r = (e, r, n, s) => { for (; n-- > 0; e += t)o.fill(s, e, e + r) }, n = (o, e, n) => { for (let s = 0; s++ < 3; n -= 2)r(e * t + o - (n >> 1) * (t + 1), n, n, 2 | s) }, s = 2 * ((t - 13) / (1 + (e / 7 | 0)) / 2 + .75 | 0); if (e > 1) for (let o = t - 7; o > 8; o -= s){ for (let t = o; t > 8; t -= s)n(o, t, 5); o < t - 7 && n(o, 6, 5) } if (e > 6) for (let r = $(e, 7973, 12), n = 1; n < 7; ++n)for (let e = 12; e-- > 9; r >>= 1)o[n * t - e] = 2 | 1 & r; r(7, 2, 9, 2), r(t - 8, 8, 9, 2); for (let e = 0; e < t; ++e)o[6 * t + e] = 3 ^ 1 & e; n(3, 3, 7), n(t - 4, 3, 7); for (let e = 0; e < t; ++e)for (let r = e; r < t; ++r)o[r * t + e] = o[e * t + r]; o[(t - 8) * t + 8] = 3 }, F = ({ size: t, K: o }) => { const e = []; for (let r = t - 2, n = t, s = -1; r >= 0; r -= 2){ for (5 === r && (r = 4); n += s, -1 !== n && n !== t;){ const s = n * t + r; o[s + 1] || e.push(s + 1), o[s] || e.push(s) } s *= -1 } return e }, H = ({ K: t }, o, e) => o.forEach((o, r) => t[o] = e[r >> 3] >> (7 & ~r) & 1), I = ({ size: t, K: o }, e, r, n) => { for (let r = 0; r < t; ++r)for (let n = 0; n < t; ++n){ const s = r * t + n; o[s] ^= !(e(n, r) || 2 & o[s]) } let s = 21522 ^ $((1 ^ n) << 3 | r, 1335, 10); for (let e = 0; e++ < 8; s >>= 1)o[(e - (e < 7)) * t + 8] = 1 & s, o[9 * t - e] = 1 & s; for (let e = 8; --e, s; s >>= 1)o[8 * t + e - (e < 7)] = 1 & s, o[(t - e) * t + 8] = 1 & s }, K = ({ size: t, K: o }, e = 0, r = 0) => { for (let n = 0; n < t; ++n){ for (let s = 0; s < 2; ++s)for (let f, c = 0, i = 0, l = 0; c < t; ++c){ const a = 1 & o[s ? n * t + c : c * t + n]; r += a, i = (i >> 1 | 2098176) & (3047517 ^ a - 1), 2049 & i && (e += 40), a !== f && (l = 0), f = a, e += 5 === ++l ? 3 : l > 5 } if (n) for (let r = t + n, s = 5 * o[n - 1] ^ o[n]; r < t * t; r += t){ const t = 5 * o[r - 1] ^ o[r]; e += 3 * !(1 & (s | t) | 4 & (s ^ t)), s = t } } return e + 10 * (10 * Math.abs(r / (t * t) - 1) | 0) }, N = [], P = (t = n(1), { minCorrectionLevel: e = 0, maxCorrectionLevel: r = 3, minVersion: s = 1, maxVersion: f = 40, mask: c, trailer: i = 60433, ...l } = {}) => { r < e && n(3), f < s && n(2), "string" == typeof t && (t = b.auto(t, l)); for (let n = s, l = 0; n <= f; ++n){ let s = N[n]; s || (N[n] = s = x(4 * n + 17), A(s, n), s.p = F(s)); const f = o(n, s.p.length >> 3); if (8 * f(e).t < l) continue; const a = C(); t(a, n), l = a.I; for (let t = r; t >= e; --t){ const o = f(t); if (8 * o.t < l) continue; for (a.I = l + 11 & -8; a.I < 8 * o.t;)a.push(i, 16); const e = x(s.size, s.K); return H(e, s.p, V(a.F, o)), (z[c ?? -1] ? [z[c]] : z).map((o, r) => { const n = x(e.size, e.K); return I(n, o, c ?? r, t), n.s = K(n), n }).reduce((t, o) => o.s < t.s ? o : t) } } n(4) }; P.with = (...t) => (o, e) => P(o, { modes: [...g, ...t], ...e }); export { e as correction, P as generate, b as mode }; diff --git a/modules/lightweight-charts/5.0.9/dist/lightweight-charts.standalone.production.mjs b/modules/lightweight-charts/5.0.9/dist/lightweight-charts.standalone.production.mjs deleted file mode 100644 index 5b856fec9..000000000 --- a/modules/lightweight-charts/5.0.9/dist/lightweight-charts.standalone.production.mjs +++ /dev/null @@ -1,8 +0,0 @@ -// @ts-nocheck -/*! - * @license - * TradingView Lightweight Charts™ v5.0.9 - * Copyright (c) 2025 TradingView, Inc. - * Licensed under Apache License 2.0 https://www.apache.org/licenses/LICENSE-2.0 - */ -const t={title:"",visible:!0,lastValueVisible:!0,priceLineVisible:!0,priceLineSource:0,priceLineWidth:1,priceLineColor:"",priceLineStyle:2,baseLineVisible:!0,baseLineWidth:1,baseLineColor:"#B2B5BE",baseLineStyle:0,priceFormat:{type:"price",precision:2,minMove:.01}};var i,s;function n(t,i){const s={0:[],1:[t.lineWidth,t.lineWidth],2:[2*t.lineWidth,2*t.lineWidth],3:[6*t.lineWidth,6*t.lineWidth],4:[t.lineWidth,4*t.lineWidth]}[i];t.setLineDash(s)}function e(t,i,s,n){t.beginPath();const e=t.lineWidth%2?.5:0;t.moveTo(s,i+e),t.lineTo(n,i+e),t.stroke()}function r(t,i){if(!t)throw new Error("Assertion failed"+(i?": "+i:""))}function h(t){if(void 0===t)throw new Error("Value is undefined");return t}function a(t){if(null===t)throw new Error("Value is null");return t}function l(t){return a(h(t))}!function(t){t[t.Simple=0]="Simple",t[t.WithSteps=1]="WithSteps",t[t.Curved=2]="Curved"}(i||(i={})),function(t){t[t.Solid=0]="Solid",t[t.Dotted=1]="Dotted",t[t.Dashed=2]="Dashed",t[t.LargeDashed=3]="LargeDashed",t[t.SparseDotted=4]="SparseDotted"}(s||(s={}));class o{constructor(){this.t=[]}i(t,i,s){const n={h:t,l:i,o:!0===s};this.t.push(n)}_(t){const i=this.t.findIndex((i=>t===i.h));i>-1&&this.t.splice(i,1)}u(t){this.t=this.t.filter((i=>i.l!==t))}p(t,i,s){const n=[...this.t];this.t=this.t.filter((t=>!t.o)),n.forEach((n=>n.h(t,i,s)))}v(){return this.t.length>0}m(){this.t=[]}}function _(t,...i){for(const s of i)for(const i in s)void 0!==s[i]&&Object.prototype.hasOwnProperty.call(s,i)&&!["__proto__","constructor","prototype"].includes(i)&&("object"!=typeof s[i]||void 0===t[i]||Array.isArray(s[i])?t[i]=s[i]:_(t[i],s[i]));return t}function u(t){return"number"==typeof t&&isFinite(t)}function c(t){return"number"==typeof t&&t%1==0}function d(t){return"string"==typeof t}function f(t){return"boolean"==typeof t}function p(t){const i=t;if(!i||"object"!=typeof i)return i;let s,n,e;for(n in s=Array.isArray(i)?[]:{},i)i.hasOwnProperty(n)&&(e=i[n],s[n]=e&&"object"==typeof e?p(e):e);return s}function v(t){return null!==t}function m(t){return null===t?void 0:t}const w="-apple-system, BlinkMacSystemFont, 'Trebuchet MS', Roboto, Ubuntu, sans-serif";function g(t,i,s){return void 0===i&&(i=w),`${s=void 0!==s?`${s} `:""}${t}px ${i}`}class M{constructor(t){this.M={S:1,C:5,P:NaN,k:"",T:"",R:"",D:"",V:0,B:0,I:0,A:0,O:0},this.L=t}N(){const t=this.M,i=this.F(),s=this.W();return t.P===i&&t.T===s||(t.P=i,t.T=s,t.k=g(i,s),t.A=2.5/12*i,t.V=t.A,t.B=i/12*t.C,t.I=i/12*t.C,t.O=0),t.R=this.H(),t.D=this.U(),this.M}H(){return this.L.N().layout.textColor}U(){return this.L.$()}F(){return this.L.N().layout.fontSize}W(){return this.L.N().layout.fontFamily}}function b(t){return t<0?0:t>255?255:Math.round(t)||0}function x(t){return.199*t[0]+.687*t[1]+.114*t[2]}class S{constructor(t,i){this.j=new Map,this.q=t,i&&(this.j=i)}Y(t,i){if("transparent"===t)return t;const s=this.K(t),n=s[3];return`rgba(${s[0]}, ${s[1]}, ${s[2]}, ${i*n})`}X(t){const i=this.K(t);return{Z:`rgb(${i[0]}, ${i[1]}, ${i[2]})`,G:x(i)>160?"black":"white"}}J(t){return x(this.K(t))}tt(t,i,s){const[n,e,r,h]=this.K(t),[a,l,o,_]=this.K(i),u=[b(n+s*(a-n)),b(e+s*(l-e)),b(r+s*(o-r)),(c=h+s*(_-h),c<=0||c>1?Math.min(Math.max(c,0),1):Math.round(1e4*c)/1e4)];var c;return`rgba(${u[0]}, ${u[1]}, ${u[2]}, ${u[3]})`}K(t){const i=this.j.get(t);if(i)return i;const s=function(t){const i=document.createElement("div");i.style.display="none",document.body.appendChild(i),i.style.color=t;const s=window.getComputedStyle(i).color;return document.body.removeChild(i),s}(t),n=s.match(/^rgba?\s*\((\d+),\s*(\d+),\s*(\d+)(?:,\s*(\d*\.?\d+))?\)$/);if(!n){if(this.q.length)for(const i of this.q){const s=i(t);if(s)return this.j.set(t,s),s}throw new Error(`Failed to parse color: ${t}`)}const e=[parseInt(n[1],10),parseInt(n[2],10),parseInt(n[3],10),n[4]?parseFloat(n[4]):1];return this.j.set(t,e),e}}class C{constructor(){this.it=[]}st(t){this.it=t}nt(t,i,s){this.it.forEach((n=>{n.nt(t,i,s)}))}}class y{nt(t,i,s){t.useBitmapCoordinateSpace((t=>this.et(t,i,s)))}}class P extends y{constructor(){super(...arguments),this.rt=null}ht(t){this.rt=t}et({context:t,horizontalPixelRatio:i,verticalPixelRatio:s}){if(null===this.rt||null===this.rt.lt)return;const n=this.rt.lt,e=this.rt,r=Math.max(1,Math.floor(i))%2/2,h=h=>{t.beginPath();for(let a=n.to-1;a>=n.from;--a){const n=e.ot[a],l=Math.round(n._t*i)+r,o=n.ut*s,_=h*s+r;t.moveTo(l,o),t.arc(l,o,_,0,2*Math.PI)}t.fill()};e.ct>0&&(t.fillStyle=e.dt,h(e.ft+e.ct)),t.fillStyle=e.vt,h(e.ft)}}function k(){return{ot:[{_t:0,ut:0,wt:0,gt:0}],vt:"",dt:"",ft:0,ct:0,lt:null}}const T={from:0,to:1};class R{constructor(t,i,s){this.Mt=new C,this.bt=[],this.xt=[],this.St=!0,this.L=t,this.Ct=i,this.yt=s,this.Mt.st(this.bt)}Pt(t){this.kt(),this.St=!0}Tt(){return this.St&&(this.Rt(),this.St=!1),this.Mt}kt(){const t=this.yt.Dt();t.length!==this.bt.length&&(this.xt=t.map(k),this.bt=this.xt.map((t=>{const i=new P;return i.ht(t),i})),this.Mt.st(this.bt))}Rt(){const t=2===this.Ct.N().mode||!this.Ct.Et(),i=this.yt.Vt(),s=this.Ct.Bt(),n=this.L.It();this.kt(),i.forEach(((i,e)=>{const r=this.xt[e],h=i.At(s),a=i.zt();!t&&null!==h&&i.Et()&&null!==a?(r.vt=h.Ot,r.ft=h.ft,r.ct=h.Lt,r.ot[0].gt=h.gt,r.ot[0].ut=i.Ft().Nt(h.gt,a.Wt),r.dt=h.Ht??this.L.Ut(r.ot[0].ut/i.Ft().$t()),r.ot[0].wt=s,r.ot[0]._t=n.jt(s),r.lt=T):r.lt=null}))}}class D extends y{constructor(t){super(),this.qt=t}et({context:t,bitmapSize:i,horizontalPixelRatio:s,verticalPixelRatio:r}){if(null===this.qt)return;const h=this.qt.Yt.Et,a=this.qt.Kt.Et;if(!h&&!a)return;const l=Math.round(this.qt._t*s),o=Math.round(this.qt.ut*r);t.lineCap="butt",h&&l>=0&&(t.lineWidth=Math.floor(this.qt.Yt.ct*s),t.strokeStyle=this.qt.Yt.R,t.fillStyle=this.qt.Yt.R,n(t,this.qt.Yt.Xt),function(t,i,s,n){t.beginPath();const e=t.lineWidth%2?.5:0;t.moveTo(i+e,s),t.lineTo(i+e,n),t.stroke()}(t,l,0,i.height)),a&&o>=0&&(t.lineWidth=Math.floor(this.qt.Kt.ct*r),t.strokeStyle=this.qt.Kt.R,t.fillStyle=this.qt.Kt.R,n(t,this.qt.Kt.Xt),e(t,o,0,i.width))}}class E{constructor(t,i){this.St=!0,this.Zt={Yt:{ct:1,Xt:0,R:"",Et:!1},Kt:{ct:1,Xt:0,R:"",Et:!1},_t:0,ut:0},this.Gt=new D(this.Zt),this.Jt=t,this.yt=i}Pt(){this.St=!0}Tt(t){return this.St&&(this.Rt(),this.St=!1),this.Gt}Rt(){const t=this.Jt.Et(),i=this.yt.Qt().N().crosshair,s=this.Zt;if(2===i.mode)return s.Kt.Et=!1,void(s.Yt.Et=!1);s.Kt.Et=t&&this.Jt.ti(this.yt),s.Yt.Et=t&&this.Jt.ii(),s.Kt.ct=i.horzLine.width,s.Kt.Xt=i.horzLine.style,s.Kt.R=i.horzLine.color,s.Yt.ct=i.vertLine.width,s.Yt.Xt=i.vertLine.style,s.Yt.R=i.vertLine.color,s._t=this.Jt.si(),s.ut=this.Jt.ni()}}function V(t,i,s,n,e,r){t.fillRect(i+r,s,n-2*r,r),t.fillRect(i+r,s+e-r,n-2*r,r),t.fillRect(i,s,r,e),t.fillRect(i+n-r,s,r,e)}function B(t,i,s,n,e,r){t.save(),t.globalCompositeOperation="copy",t.fillStyle=r,t.fillRect(i,s,n,e),t.restore()}function I(t,i,s,n,e,r){t.beginPath(),t.roundRect?t.roundRect(i,s,n,e,r):(t.lineTo(i+n-r[1],s),0!==r[1]&&t.arcTo(i+n,s,i+n,s+r[1],r[1]),t.lineTo(i+n,s+e-r[2]),0!==r[2]&&t.arcTo(i+n,s+e,i+n-r[2],s+e,r[2]),t.lineTo(i+r[3],s+e),0!==r[3]&&t.arcTo(i,s+e,i,s+e-r[3],r[3]),t.lineTo(i,s+r[0]),0!==r[0]&&t.arcTo(i,s,i+r[0],s,r[0]))}function A(t,i,s,n,e,r,h=0,a=[0,0,0,0],l=""){if(t.save(),!h||!l||l===r)return I(t,i,s,n,e,a),t.fillStyle=r,t.fill(),void t.restore();const o=h/2;var _;I(t,i+o,s+o,n-h,e-h,(_=-o,a.map((t=>0===t?t:t+_)))),"transparent"!==r&&(t.fillStyle=r,t.fill()),"transparent"!==l&&(t.lineWidth=h,t.strokeStyle=l,t.closePath(),t.stroke()),t.restore()}function z(t,i,s,n,e,r,h){t.save(),t.globalCompositeOperation="copy";const a=t.createLinearGradient(0,0,0,e);a.addColorStop(0,r),a.addColorStop(1,h),t.fillStyle=a,t.fillRect(i,s,n,e),t.restore()}class O{constructor(t,i){this.ht(t,i)}ht(t,i){this.qt=t,this.ei=i}$t(t,i){return this.qt.Et?t.P+t.A+t.V:0}nt(t,i,s,n){if(!this.qt.Et||0===this.qt.ri.length)return;const e=this.qt.R,r=this.ei.Z,h=t.useBitmapCoordinateSpace((t=>{const h=t.context;h.font=i.k;const a=this.hi(t,i,s,n),l=a.ai;return a.li?A(h,l.oi,l._i,l.ui,l.ci,r,l.di,[l.ft,0,0,l.ft],r):A(h,l.fi,l._i,l.ui,l.ci,r,l.di,[0,l.ft,l.ft,0],r),this.qt.pi&&(h.fillStyle=e,h.fillRect(l.fi,l.mi,l.wi-l.fi,l.gi)),this.qt.Mi&&(h.fillStyle=i.D,h.fillRect(a.li?l.bi-l.di:0,l._i,l.di,l.xi-l._i)),a}));t.useMediaCoordinateSpace((({context:t})=>{const s=h.Si;t.font=i.k,t.textAlign=h.li?"right":"left",t.textBaseline="middle",t.fillStyle=e,t.fillText(this.qt.ri,s.Ci,(s._i+s.xi)/2+s.yi)}))}hi(t,i,s,n){const{context:e,bitmapSize:r,mediaSize:h,horizontalPixelRatio:a,verticalPixelRatio:l}=t,o=this.qt.pi||!this.qt.Pi?i.C:0,_=this.qt.ki?i.S:0,u=i.A+this.ei.Ti,c=i.V+this.ei.Ri,d=i.B,f=i.I,p=this.qt.ri,v=i.P,m=s.Di(e,p),w=Math.ceil(s.Ei(e,p)),g=v+u+c,M=i.S+d+f+w+o,b=Math.max(1,Math.floor(l));let x=Math.round(g*l);x%2!=b%2&&(x+=1);const S=_>0?Math.max(1,Math.floor(_*a)):0,C=Math.round(M*a),y=Math.round(o*a),P=this.ei.Vi??this.ei.Bi,k=Math.round(P*l)-Math.floor(.5*l),T=Math.floor(k+b/2-x/2),R=T+x,D="right"===n,E=D?h.width-_:_,V=D?r.width-S:S;let B,I,A;return D?(B=V-C,I=V-y,A=E-o-d-_):(B=V+C,I=V+y,A=E+o+d),{li:D,ai:{_i:T,mi:k,xi:R,ui:C,ci:x,ft:2*a,di:S,oi:B,fi:V,wi:I,gi:b,bi:r.width},Si:{_i:T/l,xi:R/l,Ci:A,yi:m}}}}class L{constructor(t){this.Ii={Bi:0,Z:"#000",Ri:0,Ti:0},this.Ai={ri:"",Et:!1,pi:!0,Pi:!1,Ht:"",R:"#FFF",Mi:!1,ki:!1},this.zi={ri:"",Et:!1,pi:!1,Pi:!0,Ht:"",R:"#FFF",Mi:!0,ki:!0},this.St=!0,this.Oi=new(t||O)(this.Ai,this.Ii),this.Li=new(t||O)(this.zi,this.Ii)}ri(){return this.Ni(),this.Ai.ri}Bi(){return this.Ni(),this.Ii.Bi}Pt(){this.St=!0}$t(t,i=!1){return Math.max(this.Oi.$t(t,i),this.Li.$t(t,i))}Fi(){return this.Ii.Vi||0}Wi(t){this.Ii.Vi=t}Hi(){return this.Ni(),this.Ai.Et||this.zi.Et}Ui(){return this.Ni(),this.Ai.Et}Tt(t){return this.Ni(),this.Ai.pi=this.Ai.pi&&t.N().ticksVisible,this.zi.pi=this.zi.pi&&t.N().ticksVisible,this.Oi.ht(this.Ai,this.Ii),this.Li.ht(this.zi,this.Ii),this.Oi}$i(){return this.Ni(),this.Oi.ht(this.Ai,this.Ii),this.Li.ht(this.zi,this.Ii),this.Li}Ni(){this.St&&(this.Ai.pi=!0,this.zi.pi=!1,this.ji(this.Ai,this.zi,this.Ii))}}class N extends L{constructor(t,i,s){super(),this.Jt=t,this.qi=i,this.Yi=s}ji(t,i,s){if(t.Et=!1,2===this.Jt.N().mode)return;const n=this.Jt.N().horzLine;if(!n.labelVisible)return;const e=this.qi.zt();if(!this.Jt.Et()||this.qi.Ki()||null===e)return;const r=this.qi.Xi().X(n.labelBackgroundColor);s.Z=r.Z,t.R=r.G;const h=2/12*this.qi.P();s.Ti=h,s.Ri=h;const a=this.Yi(this.qi);s.Bi=a.Bi,t.ri=this.qi.Zi(a.gt,e),t.Et=!0}}const F=/[1-9]/g;class W{constructor(){this.qt=null}ht(t){this.qt=t}nt(t,i){if(null===this.qt||!1===this.qt.Et||0===this.qt.ri.length)return;const s=t.useMediaCoordinateSpace((({context:t})=>(t.font=i.k,Math.round(i.Gi.Ei(t,a(this.qt).ri,F)))));if(s<=0)return;const n=i.Ji,e=s+2*n,r=e/2,h=this.qt.Qi;let l=this.qt.Bi,o=Math.floor(l-r)+.5;o<0?(l+=Math.abs(0-o),o=Math.floor(l-r)+.5):o+e>h&&(l-=Math.abs(h-(o+e)),o=Math.floor(l-r)+.5);const _=o+e,u=Math.ceil(0+i.S+i.C+i.A+i.P+i.V);t.useBitmapCoordinateSpace((({context:t,horizontalPixelRatio:s,verticalPixelRatio:n})=>{const e=a(this.qt);t.fillStyle=e.Z;const r=Math.round(o*s),h=Math.round(0*n),l=Math.round(_*s),c=Math.round(u*n),d=Math.round(2*s);if(t.beginPath(),t.moveTo(r,h),t.lineTo(r,c-d),t.arcTo(r,c,r+d,c,d),t.lineTo(l-d,c),t.arcTo(l,c,l,c-d,d),t.lineTo(l,h),t.fill(),e.pi){const r=Math.round(e.Bi*s),a=h,l=Math.round((a+i.C)*n);t.fillStyle=e.R;const o=Math.max(1,Math.floor(s)),_=Math.floor(.5*s);t.fillRect(r-_,a,o,l-a)}})),t.useMediaCoordinateSpace((({context:t})=>{const s=a(this.qt),e=0+i.S+i.C+i.A+i.P/2;t.font=i.k,t.textAlign="left",t.textBaseline="middle",t.fillStyle=s.R;const r=i.Gi.Di(t,"Apr0");t.translate(o+n,e+r),t.fillText(s.ri,0,0)}))}}class H{constructor(t,i,s){this.St=!0,this.Gt=new W,this.Zt={Et:!1,Z:"#4c525e",R:"white",ri:"",Qi:0,Bi:NaN,pi:!0},this.Ct=t,this.ts=i,this.Yi=s}Pt(){this.St=!0}Tt(){return this.St&&(this.Rt(),this.St=!1),this.Gt.ht(this.Zt),this.Gt}Rt(){const t=this.Zt;if(t.Et=!1,2===this.Ct.N().mode)return;const i=this.Ct.N().vertLine;if(!i.labelVisible)return;const s=this.ts.It();if(s.Ki())return;t.Qi=s.Qi();const n=this.Yi();if(null===n)return;t.Bi=n.Bi;const e=s.ss(this.Ct.Bt());t.ri=s.ns(a(e)),t.Et=!0;const r=this.ts.Xi().X(i.labelBackgroundColor);t.Z=r.Z,t.R=r.G,t.pi=s.N().ticksVisible}}class U{constructor(){this.es=null,this.rs=0}hs(){return this.rs}ls(t){this.rs=t}Ft(){return this.es}_s(t){this.es=t}us(t){return[]}cs(){return[]}Et(){return!0}}var $;!function(t){t[t.Normal=0]="Normal",t[t.Magnet=1]="Magnet",t[t.Hidden=2]="Hidden",t[t.MagnetOHLC=3]="MagnetOHLC"}($||($={}));class j extends U{constructor(t,i){super(),this.yt=null,this.ds=NaN,this.fs=0,this.ps=!1,this.vs=new Map,this.ws=!1,this.gs=new WeakMap,this.Ms=new WeakMap,this.bs=NaN,this.xs=NaN,this.Ss=NaN,this.Cs=NaN,this.ts=t,this.ys=i;this.Ps=((t,i)=>s=>{const n=i(),e=t();if(s===a(this.yt).ks())return{gt:e,Bi:n};{const t=a(s.zt());return{gt:s.Ts(n,t),Bi:n}}})((()=>this.ds),(()=>this.xs));const s=((t,i)=>()=>{const s=this.ts.It().Rs(t()),n=i();return s&&Number.isFinite(n)?{wt:s,Bi:n}:null})((()=>this.fs),(()=>this.si()));this.Ds=new H(this,t,s)}N(){return this.ys}Es(t,i){this.Ss=t,this.Cs=i}Vs(){this.Ss=NaN,this.Cs=NaN}Bs(){return this.Ss}Is(){return this.Cs}As(t,i,s){this.ws||(this.ws=!0),this.ps=!0,this.zs(t,i,s)}Bt(){return this.fs}si(){return this.bs}ni(){return this.xs}Et(){return this.ps}Os(){this.ps=!1,this.Ls(),this.ds=NaN,this.bs=NaN,this.xs=NaN,this.yt=null,this.Vs(),this.Ns()}Fs(t){let i=this.gs.get(t);i||(i=new E(this,t),this.gs.set(t,i));let s=this.Ms.get(t);return s||(s=new R(this.ts,this,t),this.Ms.set(t,s)),[i,s]}ti(t){return t===this.yt&&this.ys.horzLine.visible}ii(){return this.ys.vertLine.visible}Ws(t,i){this.ps&&this.yt===t||this.vs.clear();const s=[];return this.yt===t&&s.push(this.Hs(this.vs,i,this.Ps)),s}cs(){return this.ps?[this.Ds]:[]}Us(){return this.yt}Ns(){this.ts.$s().forEach((t=>{this.gs.get(t)?.Pt(),this.Ms.get(t)?.Pt()})),this.vs.forEach((t=>t.Pt())),this.Ds.Pt()}js(t){return t&&!t.ks().Ki()?t.ks():null}zs(t,i,s){this.qs(t,i,s)&&this.Ns()}qs(t,i,s){const n=this.bs,e=this.xs,r=this.ds,h=this.fs,a=this.yt,l=this.js(s);this.fs=t,this.bs=isNaN(t)?NaN:this.ts.It().jt(t),this.yt=s;const o=null!==l?l.zt():null;return null!==l&&null!==o?(this.ds=i,this.xs=l.Nt(i,o)):(this.ds=NaN,this.xs=NaN),n!==this.bs||e!==this.xs||h!==this.fs||r!==this.ds||a!==this.yt}Ls(){const t=this.ts.Ys().map((t=>t.Xs().Ks())).filter(v),i=0===t.length?null:Math.max(...t);this.fs=null!==i?i:NaN}Hs(t,i,s){let n=t.get(i);return void 0===n&&(n=new N(this,i,s),t.set(i,n)),n}}function q(t){return"left"===t||"right"===t}class Y{constructor(t){this.Zs=new Map,this.Gs=[],this.Js=t}Qs(t,i){const s=function(t,i){return void 0===t?i:{tn:Math.max(t.tn,i.tn),sn:t.sn||i.sn}}(this.Zs.get(t),i);this.Zs.set(t,s)}nn(){return this.Js}en(t){const i=this.Zs.get(t);return void 0===i?{tn:this.Js}:{tn:Math.max(this.Js,i.tn),sn:i.sn}}rn(){this.hn(),this.Gs=[{an:0}]}ln(t){this.hn(),this.Gs=[{an:1,Wt:t}]}_n(t){this.un(),this.Gs.push({an:5,Wt:t})}hn(){this.un(),this.Gs.push({an:6})}cn(){this.hn(),this.Gs=[{an:4}]}dn(t){this.hn(),this.Gs.push({an:2,Wt:t})}fn(t){this.hn(),this.Gs.push({an:3,Wt:t})}pn(){return this.Gs}vn(t){for(const i of t.Gs)this.mn(i);this.Js=Math.max(this.Js,t.Js),t.Zs.forEach(((t,i)=>{this.Qs(i,t)}))}static wn(){return new Y(2)}static gn(){return new Y(3)}mn(t){switch(t.an){case 0:this.rn();break;case 1:this.ln(t.Wt);break;case 2:this.dn(t.Wt);break;case 3:this.fn(t.Wt);break;case 4:this.cn();break;case 5:this._n(t.Wt);break;case 6:this.un()}}un(){const t=this.Gs.findIndex((t=>5===t.an));-1!==t&&this.Gs.splice(t,1)}}class K{formatTickmarks(t){return t.map((t=>this.format(t)))}}const X=".";function Z(t,i){if(!u(t))return"n/a";if(!c(i))throw new TypeError("invalid length");if(i<0||i>16)throw new TypeError("invalid length");if(0===i)return t.toString();return("0000000000000000"+t.toString()).slice(-i)}class G extends K{constructor(t,i){if(super(),i||(i=1),u(t)&&c(t)||(t=100),t<0)throw new TypeError("invalid base");this.qi=t,this.Mn=i,this.bn()}format(t){const i=t<0?"−":"";return t=Math.abs(t),i+this.xn(t)}bn(){if(this.Sn=0,this.qi>0&&this.Mn>0){let t=this.qi;for(;t>1;)t/=10,this.Sn++}}xn(t){const i=this.qi/this.Mn;let s=Math.floor(t),n="";const e=void 0!==this.Sn?this.Sn:NaN;if(i>1){let r=+(Math.round(t*i)-s*i).toFixed(this.Sn);r>=i&&(r-=i,s+=1),n=X+Z(+r.toFixed(this.Sn)*this.Mn,e)}else s=Math.round(s*i)/i,e>0&&(n=X+Z(0,e));return s.toFixed(0)+n}}class J extends G{constructor(t=100){super(t)}format(t){return`${super.format(t)}%`}}class Q extends K{constructor(t){super(),this.Cn=t}format(t){let i="";return t<0&&(i="-",t=-t),t<995?i+this.yn(t):t<999995?i+this.yn(t/1e3)+"K":t<999999995?(t=1e3*Math.round(t/1e3),i+this.yn(t/1e6)+"M"):(t=1e6*Math.round(t/1e6),i+this.yn(t/1e9)+"B")}yn(t){let i;const s=Math.pow(10,this.Cn);return i=(t=Math.round(t*s)/s)>=1e-15&&t<1?t.toFixed(this.Cn).replace(/\.?0+$/,""):String(t),i.replace(/(\.[1-9]*)0+$/,((t,i)=>i))}}const tt=/[2-9]/g;class it{constructor(t=50){this.Pn=0,this.kn=1,this.Tn=1,this.Rn={},this.Dn=new Map,this.En=t}Vn(){this.Pn=0,this.Dn.clear(),this.kn=1,this.Tn=1,this.Rn={}}Ei(t,i,s){return this.Bn(t,i,s).width}Di(t,i,s){const n=this.Bn(t,i,s);return((n.actualBoundingBoxAscent||0)-(n.actualBoundingBoxDescent||0))/2}Bn(t,i,s){const n=s||tt,e=String(i).replace(n,"0");if(this.Dn.has(e))return h(this.Dn.get(e)).In;if(this.Pn===this.En){const t=this.Rn[this.Tn];delete this.Rn[this.Tn],this.Dn.delete(t),this.Tn++,this.Pn--}t.save(),t.textBaseline="middle";const r=t.measureText(e);return t.restore(),0===r.width&&i.length||(this.Dn.set(e,{In:r,An:this.kn}),this.Rn[this.kn]=e,this.Pn++,this.kn++),r}}class st{constructor(t){this.zn=null,this.M=null,this.On="right",this.Ln=t}Nn(t,i,s){this.zn=t,this.M=i,this.On=s}nt(t){null!==this.M&&null!==this.zn&&this.zn.nt(t,this.M,this.Ln,this.On)}}class nt{constructor(t,i,s){this.Fn=t,this.Ln=new it(50),this.Wn=i,this.L=s,this.F=-1,this.Gt=new st(this.Ln)}Tt(){const t=this.L.Hn(this.Wn);if(null===t)return null;const i=t.Un(this.Wn)?t.$n():this.Wn.Ft();if(null===i)return null;const s=t.jn(i);if("overlay"===s)return null;const n=this.L.qn();return n.P!==this.F&&(this.F=n.P,this.Ln.Vn()),this.Gt.Nn(this.Fn.$i(),n,s),this.Gt}}class et extends y{constructor(){super(...arguments),this.qt=null}ht(t){this.qt=t}Yn(t,i){if(!this.qt?.Et)return null;const{ut:s,ct:n,Kn:e}=this.qt;return i>=s-n-7&&i<=s+n+7?{Xn:this.qt,Kn:e}:null}et({context:t,bitmapSize:i,horizontalPixelRatio:s,verticalPixelRatio:r}){if(null===this.qt)return;if(!1===this.qt.Et)return;const h=Math.round(this.qt.ut*r);h<0||h>i.height||(t.lineCap="butt",t.strokeStyle=this.qt.R,t.lineWidth=Math.floor(this.qt.ct*s),n(t,this.qt.Xt),e(t,h,0,i.width))}}class rt{constructor(t){this.Zn={ut:0,R:"rgba(0, 0, 0, 0)",ct:1,Xt:0,Et:!1},this.Gn=new et,this.St=!0,this.Jn=t,this.Qn=t.Qt(),this.Gn.ht(this.Zn)}Pt(){this.St=!0}Tt(){return this.Jn.Et()?(this.St&&(this.te(),this.St=!1),this.Gn):null}}class ht extends rt{constructor(t){super(t)}te(){this.Zn.Et=!1;const t=this.Jn.Ft(),i=t.ie().ie;if(2!==i&&3!==i)return;const s=this.Jn.N();if(!s.baseLineVisible||!this.Jn.Et())return;const n=this.Jn.zt();null!==n&&(this.Zn.Et=!0,this.Zn.ut=t.Nt(n.Wt,n.Wt),this.Zn.R=s.baseLineColor,this.Zn.ct=s.baseLineWidth,this.Zn.Xt=s.baseLineStyle)}}class at extends y{constructor(){super(...arguments),this.qt=null}ht(t){this.qt=t}se(){return this.qt}et({context:t,horizontalPixelRatio:i,verticalPixelRatio:s}){const n=this.qt;if(null===n)return;const e=Math.max(1,Math.floor(i)),r=e%2/2,h=Math.round(n.ne.x*i)+r,a=n.ne.y*s;t.fillStyle=n.ee,t.beginPath();const l=Math.max(2,1.5*n.re)*i;t.arc(h,a,l,0,2*Math.PI,!1),t.fill(),t.fillStyle=n.he,t.beginPath(),t.arc(h,a,n.ft*i,0,2*Math.PI,!1),t.fill(),t.lineWidth=e,t.strokeStyle=n.ae,t.beginPath(),t.arc(h,a,n.ft*i+e/2,0,2*Math.PI,!1),t.stroke()}}const lt=[{le:0,oe:.25,_e:4,ue:10,ce:.25,de:0,fe:.4,pe:.8},{le:.25,oe:.525,_e:10,ue:14,ce:0,de:0,fe:.8,pe:0},{le:.525,oe:1,_e:14,ue:14,ce:0,de:0,fe:0,pe:0}];class ot{constructor(t){this.Gt=new at,this.St=!0,this.ve=!0,this.me=performance.now(),this.we=this.me-1,this.ge=t}Me(){this.we=this.me-1,this.Pt()}be(){if(this.Pt(),2===this.ge.N().lastPriceAnimation){const t=performance.now(),i=this.we-t;if(i>0)return void(i<650&&(this.we+=2600));this.me=t,this.we=t+2600}}Pt(){this.St=!0}xe(){this.ve=!0}Et(){return 0!==this.ge.N().lastPriceAnimation}Se(){switch(this.ge.N().lastPriceAnimation){case 0:return!1;case 1:return!0;case 2:return performance.now()<=this.we}}Tt(){return this.St?(this.Rt(),this.St=!1,this.ve=!1):this.ve&&(this.Ce(),this.ve=!1),this.Gt}Rt(){this.Gt.ht(null);const t=this.ge.Qt().It(),i=t.ye(),s=this.ge.zt();if(null===i||null===s)return;const n=this.ge.Pe(!0);if(n.ke||!i.Te(n.Re))return;const e={x:t.jt(n.Re),y:this.ge.Ft().Nt(n.gt,s.Wt)},r=n.R,h=this.ge.N().lineWidth,a=this.De(this.Ee(),r);this.Gt.ht({ee:r,re:h,he:a.he,ae:a.ae,ft:a.ft,ne:e})}Ce(){const t=this.Gt.se();if(null!==t){const i=this.De(this.Ee(),t.ee);t.he=i.he,t.ae=i.ae,t.ft=i.ft}}Ee(){return this.Se()?performance.now()-this.me:2599}Ve(t,i,s,n){const e=s+(n-s)*i;return this.ge.Qt().Xi().Y(t,e)}De(t,i){const s=t%2600/2600;let n;for(const t of lt)if(s>=t.le&&s<=t.oe){n=t;break}r(void 0!==n,"Last price animation internal logic error");const e=(s-n.le)/(n.oe-n.le);return{he:this.Ve(i,e,n.ce,n.de),ae:this.Ve(i,e,n.fe,n.pe),ft:(h=e,a=n._e,l=n.ue,a+(l-a)*h)};var h,a,l}}class _t extends rt{constructor(t){super(t)}te(){const t=this.Zn;t.Et=!1;const i=this.Jn.N();if(!i.priceLineVisible||!this.Jn.Et())return;const s=this.Jn.Pe(0===i.priceLineSource);s.ke||(t.Et=!0,t.ut=s.Bi,t.R=this.Jn.Be(s.R),t.ct=i.priceLineWidth,t.Xt=i.priceLineStyle)}}class ut extends L{constructor(t){super(),this.Jt=t}ji(t,i,s){t.Et=!1,i.Et=!1;const n=this.Jt;if(!n.Et())return;const e=n.N(),r=e.lastValueVisible,h=""!==n.Ie(),a=0===e.seriesLastValueMode,l=n.Pe(!1);if(l.ke)return;r&&(t.ri=this.Ae(l,r,a),t.Et=0!==t.ri.length),(h||a)&&(i.ri=this.ze(l,r,h,a),i.Et=i.ri.length>0);const o=n.Be(l.R),_=this.Jt.Qt().Xi().X(o);s.Z=_.Z,s.Bi=l.Bi,i.Ht=n.Qt().Ut(l.Bi/n.Ft().$t()),t.Ht=o,t.R=_.G,i.R=_.G}ze(t,i,s,n){let e="";const r=this.Jt.Ie();return s&&0!==r.length&&(e+=`${r} `),i&&n&&(e+=this.Jt.Ft().Oe()?t.Le:t.Ne),e.trim()}Ae(t,i,s){return i?s?this.Jt.Ft().Oe()?t.Ne:t.Le:t.ri:""}}function ct(t,i,s,n){const e=Number.isFinite(i),r=Number.isFinite(s);return e&&r?t(i,s):e||r?e?i:s:n}class dt{constructor(t,i){this.Fe=t,this.We=i}He(t){return null!==t&&(this.Fe===t.Fe&&this.We===t.We)}Ue(){return new dt(this.Fe,this.We)}$e(){return this.Fe}je(){return this.We}qe(){return this.We-this.Fe}Ki(){return this.We===this.Fe||Number.isNaN(this.We)||Number.isNaN(this.Fe)}vn(t){return null===t?this:new dt(ct(Math.min,this.$e(),t.$e(),-1/0),ct(Math.max,this.je(),t.je(),1/0))}Ye(t){if(!u(t))return;if(0===this.We-this.Fe)return;const i=.5*(this.We+this.Fe);let s=this.We-i,n=this.Fe-i;s*=t,n*=t,this.We=i+s,this.Fe=i+n}Ke(t){u(t)&&(this.We+=t,this.Fe+=t)}Xe(){return{minValue:this.Fe,maxValue:this.We}}static Ze(t){return null===t?null:new dt(t.minValue,t.maxValue)}}class ft{constructor(t,i){this.Ge=t,this.Je=i||null}Qe(){return this.Ge}tr(){return this.Je}Xe(){return{priceRange:null===this.Ge?null:this.Ge.Xe(),margins:this.Je||void 0}}static Ze(t){return null===t?null:new ft(dt.Ze(t.priceRange),t.margins)}}class pt extends rt{constructor(t,i){super(t),this.ir=i}te(){const t=this.Zn;t.Et=!1;const i=this.ir.N();if(!this.Jn.Et()||!i.lineVisible)return;const s=this.ir.sr();null!==s&&(t.Et=!0,t.ut=s,t.R=i.color,t.ct=i.lineWidth,t.Xt=i.lineStyle,t.Kn=this.ir.N().id)}}class vt extends L{constructor(t,i){super(),this.ge=t,this.ir=i}ji(t,i,s){t.Et=!1,i.Et=!1;const n=this.ir.N(),e=n.axisLabelVisible,r=""!==n.title,h=this.ge;if(!e||!h.Et())return;const a=this.ir.sr();if(null===a)return;r&&(i.ri=n.title,i.Et=!0),i.Ht=h.Qt().Ut(a/h.Ft().$t()),t.ri=this.nr(n.price),t.Et=!0;const l=this.ge.Qt().Xi().X(n.axisLabelColor||n.color);s.Z=l.Z;const o=n.axisLabelTextColor||l.G;t.R=o,i.R=o,s.Bi=a}nr(t){const i=this.ge.zt();return null===i?"":this.ge.Ft().Zi(t,i.Wt)}}class mt{constructor(t,i){this.ge=t,this.ys=i,this.er=new pt(t,this),this.Fn=new vt(t,this),this.rr=new nt(this.Fn,t,t.Qt())}hr(t){_(this.ys,t),this.Pt(),this.ge.Qt().ar()}N(){return this.ys}lr(){return this.er}_r(){return this.rr}ur(){return this.Fn}Pt(){this.er.Pt(),this.Fn.Pt()}sr(){const t=this.ge,i=t.Ft();if(t.Qt().It().Ki()||i.Ki())return null;const s=t.zt();return null===s?null:i.Nt(this.ys.price,s.Wt)}}class wt extends U{constructor(t){super(),this.ts=t}Qt(){return this.ts}}const gt={Bar:(t,i,s,n)=>{const e=i.upColor,r=i.downColor,h=a(t(s,n)),o=l(h.Wt[0])<=l(h.Wt[3]);return{cr:h.R??(o?e:r)}},Candlestick:(t,i,s,n)=>{const e=i.upColor,r=i.downColor,h=i.borderUpColor,o=i.borderDownColor,_=i.wickUpColor,u=i.wickDownColor,c=a(t(s,n)),d=l(c.Wt[0])<=l(c.Wt[3]);return{cr:c.R??(d?e:r),dr:c.Ht??(d?h:o),pr:c.vr??(d?_:u)}},Custom:(t,i,s,n)=>({cr:a(t(s,n)).R??i.color}),Area:(t,i,s,n)=>{const e=a(t(s,n));return{cr:e.vt??i.lineColor,vt:e.vt??i.lineColor,mr:e.mr??i.topColor,wr:e.wr??i.bottomColor}},Baseline:(t,i,s,n)=>{const e=a(t(s,n));return{cr:e.Wt[3]>=i.baseValue.price?i.topLineColor:i.bottomLineColor,gr:e.gr??i.topLineColor,Mr:e.Mr??i.bottomLineColor,br:e.br??i.topFillColor1,Sr:e.Sr??i.topFillColor2,Cr:e.Cr??i.bottomFillColor1,yr:e.yr??i.bottomFillColor2}},Line:(t,i,s,n)=>{const e=a(t(s,n));return{cr:e.R??i.color,vt:e.R??i.color}},Histogram:(t,i,s,n)=>({cr:a(t(s,n)).R??i.color})};class Mt{constructor(t){this.Pr=(t,i)=>void 0!==i?i.Wt:this.ge.Xs().kr(t),this.ge=t,this.Tr=gt[t.Rr()]}Dr(t,i){return this.Tr(this.Pr,this.ge.N(),t,i)}}function bt(t,i,s,n,e=0,r=i.length){let h=r-e;for(;0>1,a=e+r;n(i[a],s)===t?(e=a+1,h-=r+1):h=r}return e}const xt=bt.bind(null,!0),St=bt.bind(null,!1);var Ct;!function(t){t[t.NearestLeft=-1]="NearestLeft",t[t.None=0]="None",t[t.NearestRight=1]="NearestRight"}(Ct||(Ct={}));const yt=30;class Pt{constructor(){this.Er=[],this.Vr=new Map,this.Br=new Map,this.Ir=[]}Ar(){return this.zr()>0?this.Er[this.Er.length-1]:null}Or(){return this.zr()>0?this.Lr(0):null}Ks(){return this.zr()>0?this.Lr(this.Er.length-1):null}zr(){return this.Er.length}Ki(){return 0===this.zr()}Te(t){return null!==this.Nr(t,0)}kr(t){return this.Fr(t)}Fr(t,i=0){const s=this.Nr(t,i);return null===s?null:{...this.Wr(s),Re:this.Lr(s)}}Hr(){return this.Er}Ur(t,i,s){if(this.Ki())return null;let n=null;for(const e of s){n=kt(n,this.$r(t,i,e))}return n}ht(t){this.Br.clear(),this.Vr.clear(),this.Er=t,this.Ir=t.map((t=>t.Re))}jr(){return this.Ir}Lr(t){return this.Er[t].Re}Wr(t){return this.Er[t]}Nr(t,i){const s=this.qr(t);if(null===s&&0!==i)switch(i){case-1:return this.Yr(t);case 1:return this.Kr(t);default:throw new TypeError("Unknown search mode")}return s}Yr(t){let i=this.Xr(t);return i>0&&(i-=1),i!==this.Er.length&&this.Lr(i)t.Ret.Re>i))}Gr(t,i,s){let n=null;for(let e=t;en.Qr&&(n.Qr=t)))}return n}$r(t,i,s){if(this.Ki())return null;let n=null;const e=a(this.Or()),r=a(this.Ks()),h=Math.max(t,e),l=Math.min(i,r),o=Math.ceil(h/yt)*yt,_=Math.max(o,Math.floor(l/yt)*yt);{const t=this.Xr(h),e=this.Zr(Math.min(l,o,i));n=kt(n,this.Gr(t,e,s))}let u=this.Vr.get(s);void 0===u&&(u=new Map,this.Vr.set(s,u));for(let t=Math.max(o+1,h);t<_;t+=yt){const i=Math.floor(t/yt);let e=u.get(i);if(void 0===e){const t=this.Xr(i*yt),n=this.Zr((i+1)*yt-1);e=this.Gr(t,n,s),u.set(i,e)}n=kt(n,e)}{const t=this.Xr(_),i=this.Zr(l);n=kt(n,this.Gr(t,i,s))}return n}}function kt(t,i){if(null===t)return i;if(null===i)return t;return{Jr:Math.min(t.Jr,i.Jr),Qr:Math.max(t.Qr,i.Qr)}}const Tt={setLineStyle:n};class Rt{constructor(t){this.th=t}nt(t,i,s){this.th.draw(t,Tt)}ih(t,i,s){this.th.drawBackground?.(t,Tt)}}class Dt{constructor(t){this.Dn=null,this.sh=t}Tt(){const t=this.sh.renderer();if(null===t)return null;if(this.Dn?.nh===t)return this.Dn.eh;const i=new Rt(t);return this.Dn={nh:t,eh:i},i}rh(){return this.sh.zOrder?.()??"normal"}}class Et{constructor(t){this.hh=null,this.ah=t}oh(){return this.ah}Ns(){this.ah.updateAllViews?.()}Fs(){const t=this.ah.paneViews?.()??[];if(this.hh?.nh===t)return this.hh.eh;const i=t.map((t=>new Dt(t)));return this.hh={nh:t,eh:i},i}Yn(t,i){return this.ah.hitTest?.(t,i)??null}}let Vt=class extends Et{us(){return[]}};class Bt{constructor(t){this.th=t}nt(t,i,s){this.th.draw(t,Tt)}ih(t,i,s){this.th.drawBackground?.(t,Tt)}}class It{constructor(t){this.Dn=null,this.sh=t}Tt(){const t=this.sh.renderer();if(null===t)return null;if(this.Dn?.nh===t)return this.Dn.eh;const i=new Bt(t);return this.Dn={nh:t,eh:i},i}rh(){return this.sh.zOrder?.()??"normal"}}function At(t){return{ri:t.text(),Bi:t.coordinate(),Vi:t.fixedCoordinate?.(),R:t.textColor(),Z:t.backColor(),Et:t.visible?.()??!0,pi:t.tickVisible?.()??!0}}class zt{constructor(t,i){this.Gt=new W,this._h=t,this.uh=i}Tt(){return this.Gt.ht({Qi:this.uh.Qi(),...At(this._h)}),this.Gt}}class Ot extends L{constructor(t,i){super(),this._h=t,this.qi=i}ji(t,i,s){const n=At(this._h);s.Z=n.Z,t.R=n.R;const e=2/12*this.qi.P();s.Ti=e,s.Ri=e,s.Bi=n.Bi,s.Vi=n.Vi,t.ri=n.ri,t.Et=n.Et,t.pi=n.pi}}class Lt extends Et{constructor(t,i){super(t),this.dh=null,this.fh=null,this.ph=null,this.mh=null,this.ge=i}cs(){const t=this.ah.timeAxisViews?.()??[];if(this.dh?.nh===t)return this.dh.eh;const i=this.ge.Qt().It(),s=t.map((t=>new zt(t,i)));return this.dh={nh:t,eh:s},s}Ws(){const t=this.ah.priceAxisViews?.()??[];if(this.fh?.nh===t)return this.fh.eh;const i=this.ge.Ft(),s=t.map((t=>new Ot(t,i)));return this.fh={nh:t,eh:s},s}wh(){const t=this.ah.priceAxisPaneViews?.()??[];if(this.ph?.nh===t)return this.ph.eh;const i=t.map((t=>new It(t)));return this.ph={nh:t,eh:i},i}gh(){const t=this.ah.timeAxisPaneViews?.()??[];if(this.mh?.nh===t)return this.mh.eh;const i=t.map((t=>new It(t)));return this.mh={nh:t,eh:i},i}Mh(t,i){return this.ah.autoscaleInfo?.(t,i)??null}}function Nt(t,i,s,n){t.forEach((t=>{i(t).forEach((t=>{t.rh()===s&&n.push(t)}))}))}function Ft(t){return t.Fs()}function Wt(t){return t.wh()}function Ht(t){return t.gh()}const Ut=["Area","Line","Baseline"];class $t extends wt{constructor(t,i,s,n,e){super(t),this.qt=new Pt,this.er=new _t(this),this.bh=[],this.xh=new ht(this),this.Sh=null,this.Ch=null,this.yh=null,this.Ph=[],this.ys=s,this.kh=i;const r=new ut(this);this.vs=[r],this.rr=new nt(r,this,t),Ut.includes(this.kh)&&(this.Sh=new ot(this)),this.Th(),this.sh=n(this,this.Qt(),e)}m(){null!==this.yh&&clearTimeout(this.yh)}Be(t){return this.ys.priceLineColor||t}Pe(t){const i={ke:!0},s=this.Ft();if(this.Qt().It().Ki()||s.Ki()||this.qt.Ki())return i;const n=this.Qt().It().ye(),e=this.zt();if(null===n||null===e)return i;let r,h;if(t){const t=this.qt.Ar();if(null===t)return i;r=t,h=t.Re}else{const t=this.qt.Fr(n.bi(),-1);if(null===t)return i;if(r=this.qt.kr(t.Re),null===r)return i;h=t.Re}const a=r.Wt[3],l=this.Rh().Dr(h,{Wt:r}),o=s.Nt(a,e.Wt);return{ke:!1,gt:a,ri:s.Zi(a,e.Wt),Le:s.Dh(a),Ne:s.Eh(a,e.Wt),R:l.cr,Bi:o,Re:h}}Rh(){return null!==this.Ch||(this.Ch=new Mt(this)),this.Ch}N(){return this.ys}hr(t){const i=t.priceScaleId;void 0!==i&&i!==this.ys.priceScaleId&&this.Qt().Vh(this,i),_(this.ys,t),void 0!==t.priceFormat&&(this.Th(),this.Qt().Bh()),this.Qt().Ih(this),this.Qt().Ah(),this.sh.Pt("options")}ht(t,i){this.qt.ht(t),this.sh.Pt("data"),null!==this.Sh&&(i&&i.zh?this.Sh.be():0===t.length&&this.Sh.Me());const s=this.Qt().Hn(this);this.Qt().Oh(s),this.Qt().Ih(this),this.Qt().Ah(),this.Qt().ar()}Lh(t){const i=new mt(this,t);return this.bh.push(i),this.Qt().Ih(this),i}Nh(t){const i=this.bh.indexOf(t);-1!==i&&this.bh.splice(i,1),this.Qt().Ih(this)}Fh(){return this.bh}Rr(){return this.kh}zt(){const t=this.Wh();return null===t?null:{Wt:t.Wt[3],Hh:t.wt}}Wh(){const t=this.Qt().It().ye();if(null===t)return null;const i=t.Uh();return this.qt.Fr(i,1)}Xs(){return this.qt}$h(t){const i=this.qt.kr(t);return null===i?null:"Bar"===this.kh||"Candlestick"===this.kh||"Custom"===this.kh?{jh:i.Wt[0],qh:i.Wt[1],Yh:i.Wt[2],Kh:i.Wt[3]}:i.Wt[3]}Xh(t){const i=[];Nt(this.Ph,Ft,"top",i);const s=this.Sh;return null!==s&&s.Et()?(null===this.yh&&s.Se()&&(this.yh=setTimeout((()=>{this.yh=null,this.Qt().Zh()}),0)),s.xe(),i.unshift(s),i):i}Fs(){const t=[];this.Gh()||t.push(this.xh),t.push(this.sh,this.er);const i=this.bh.map((t=>t.lr()));return t.push(...i),Nt(this.Ph,Ft,"normal",t),t}Jh(){return this.Qh(Ft,"bottom")}ta(t){return this.Qh(Wt,t)}ia(t){return this.Qh(Ht,t)}sa(t,i){return this.Ph.map((s=>s.Yn(t,i))).filter((t=>null!==t))}us(){return[this.rr,...this.bh.map((t=>t._r()))]}Ws(t,i){if(i!==this.es&&!this.Gh())return[];const s=[...this.vs];for(const t of this.bh)s.push(t.ur());return this.Ph.forEach((t=>{s.push(...t.Ws())})),s}cs(){const t=[];return this.Ph.forEach((i=>{t.push(...i.cs())})),t}Mh(t,i){if(void 0!==this.ys.autoscaleInfoProvider){const s=this.ys.autoscaleInfoProvider((()=>{const s=this.na(t,i);return null===s?null:s.Xe()}));return ft.Ze(s)}return this.na(t,i)}nh(){const t=this.ys.priceFormat;return t.base??1/t.minMove}ea(){return this.ra}Ns(){this.sh.Pt();for(const t of this.vs)t.Pt();for(const t of this.bh)t.Pt();this.er.Pt(),this.xh.Pt(),this.Sh?.Pt(),this.Ph.forEach((t=>t.Ns()))}Ft(){return a(super.Ft())}At(t){if(!(("Line"===this.kh||"Area"===this.kh||"Baseline"===this.kh)&&this.ys.crosshairMarkerVisible))return null;const i=this.qt.kr(t);if(null===i)return null;return{gt:i.Wt[3],ft:this.ha(),Ht:this.aa(),Lt:this.la(),Ot:this.oa(t)}}Ie(){return this.ys.title}Et(){return this.ys.visible}_a(t){this.Ph.push(new Lt(t,this))}ua(t){this.Ph=this.Ph.filter((i=>i.oh()!==t))}ca(){if("Custom"===this.kh)return t=>this.sh.da(t)}fa(){if("Custom"===this.kh)return t=>this.sh.pa(t)}va(){return this.qt.jr()}Gh(){return!q(this.Ft().ma())}na(t,i){if(!c(t)||!c(i)||this.qt.Ki())return null;const s="Line"===this.kh||"Area"===this.kh||"Baseline"===this.kh||"Histogram"===this.kh?[3]:[2,1],n=this.qt.Ur(t,i,s);let e=null!==n?new dt(n.Jr,n.Qr):null,r=null;if("Histogram"===this.Rr()){const t=this.ys.base,i=new dt(t,t);e=null!==e?e.vn(i):i}return this.Ph.forEach((s=>{const n=s.Mh(t,i);if(n?.priceRange){const t=new dt(n.priceRange.minValue,n.priceRange.maxValue);e=null!==e?e.vn(t):t}n?.margins&&(r=n.margins)})),new ft(e,r)}ha(){switch(this.kh){case"Line":case"Area":case"Baseline":return this.ys.crosshairMarkerRadius}return 0}aa(){switch(this.kh){case"Line":case"Area":case"Baseline":{const t=this.ys.crosshairMarkerBorderColor;if(0!==t.length)return t}}return null}la(){switch(this.kh){case"Line":case"Area":case"Baseline":return this.ys.crosshairMarkerBorderWidth}return 0}oa(t){switch(this.kh){case"Line":case"Area":case"Baseline":{const t=this.ys.crosshairMarkerBackgroundColor;if(0!==t.length)return t}}return this.Rh().Dr(t).cr}Th(){switch(this.ys.priceFormat.type){case"custom":{const t=this.ys.priceFormat.formatter;this.ra={format:t,formatTickmarks:this.ys.priceFormat.tickmarksFormatter??(i=>i.map(t))};break}case"volume":this.ra=new Q(this.ys.priceFormat.precision);break;case"percent":this.ra=new J(this.ys.priceFormat.precision);break;default:{const t=Math.pow(10,this.ys.priceFormat.precision);this.ra=new G(t,this.ys.priceFormat.minMove*t)}}null!==this.es&&this.es.wa()}Qh(t,i){const s=[];return Nt(this.Ph,t,i,s),s}}const jt=[3],qt=[0,1,2,3];class Yt{constructor(t){this.ys=t}ga(t,i,s){let n=t;if(0===this.ys.mode)return n;const e=s.ks(),r=e.zt();if(null===r)return n;const h=e.Nt(t,r),a=s.Ma().filter((t=>t instanceof $t)).reduce(((t,n)=>{if(s.Un(n)||!n.Et())return t;const e=n.Ft(),r=n.Xs();if(e.Ki()||!r.Te(i))return t;const h=r.kr(i);if(null===h)return t;const a=l(n.zt()),o=3===this.ys.mode?qt:jt;return t.concat(o.map((t=>e.Nt(h.Wt[t],a.Wt))))}),[]);if(0===a.length)return n;a.sort(((t,i)=>Math.abs(t-h)-Math.abs(i-h)));const o=a[0];return n=e.Ts(o,r),n}}function Kt(t,i,s){return Math.min(Math.max(t,i),s)}function Xt(t,i,s){return i-t<=s}function Zt(t){const i=Math.ceil(t);return i%2==0?i-1:i}class Gt extends y{constructor(){super(...arguments),this.qt=null}ht(t){this.qt=t}et({context:t,bitmapSize:i,horizontalPixelRatio:s,verticalPixelRatio:e}){if(null===this.qt)return;const r=Math.max(1,Math.floor(s));t.lineWidth=r,function(t,i){t.save(),t.lineWidth%2&&t.translate(.5,.5),i(),t.restore()}(t,(()=>{const h=a(this.qt);if(h.ba){t.strokeStyle=h.xa,n(t,h.Sa),t.beginPath();for(const n of h.Ca){const e=Math.round(n.ya*s);t.moveTo(e,-r),t.lineTo(e,i.height+r)}t.stroke()}if(h.Pa){t.strokeStyle=h.ka,n(t,h.Ta),t.beginPath();for(const s of h.Ra){const n=Math.round(s.ya*e);t.moveTo(-r,n),t.lineTo(i.width+r,n)}t.stroke()}}))}}class Jt{constructor(t){this.Gt=new Gt,this.St=!0,this.yt=t}Pt(){this.St=!0}Tt(){if(this.St){const t=this.yt.Qt().N().grid,i={Pa:t.horzLines.visible,ba:t.vertLines.visible,ka:t.horzLines.color,xa:t.vertLines.color,Ta:t.horzLines.style,Sa:t.vertLines.style,Ra:this.yt.ks().Da(),Ca:(this.yt.Qt().It().Da()||[]).map((t=>({ya:t.coord})))};this.Gt.ht(i),this.St=!1}return this.Gt}}class Qt{constructor(t){this.sh=new Jt(t)}lr(){return this.sh}}const ti={Ea:4,Va:1e-4};function ii(t,i){const s=100*(t-i)/i;return i<0?-s:s}function si(t,i){const s=ii(t.$e(),i),n=ii(t.je(),i);return new dt(s,n)}function ni(t,i){const s=100*(t-i)/i+100;return i<0?-s:s}function ei(t,i){const s=ni(t.$e(),i),n=ni(t.je(),i);return new dt(s,n)}function ri(t,i){const s=Math.abs(t);if(s<1e-15)return 0;const n=Math.log10(s+i.Va)+i.Ea;return t<0?-n:n}function hi(t,i){const s=Math.abs(t);if(s<1e-15)return 0;const n=Math.pow(10,s-i.Ea)-i.Va;return t<0?-n:n}function ai(t,i){if(null===t)return null;const s=ri(t.$e(),i),n=ri(t.je(),i);return new dt(s,n)}function li(t,i){if(null===t)return null;const s=hi(t.$e(),i),n=hi(t.je(),i);return new dt(s,n)}function oi(t){if(null===t)return ti;const i=Math.abs(t.je()-t.$e());if(i>=1||i<1e-15)return ti;const s=Math.ceil(Math.abs(Math.log10(i))),n=ti.Ea+s;return{Ea:n,Va:1/Math.pow(10,n)}}class _i{constructor(t,i){if(this.Ba=t,this.Ia=i,function(t){if(t<0)return!1;if(t>1e18)return!0;for(let i=t;i>1;i/=10)if(i%10!=0)return!1;return!0}(this.Ba))this.Aa=[2,2.5,2];else{this.Aa=[];for(let t=this.Ba;1!==t;){if(t%2==0)this.Aa.push(2),t/=2;else{if(t%5!=0)throw new Error("unexpected base");this.Aa.push(2,2.5),t/=5}if(this.Aa.length>100)throw new Error("something wrong with base")}}}za(t,i,s){const n=0===this.Ba?0:1/this.Ba;let e=Math.pow(10,Math.max(0,Math.ceil(Math.log10(t-i)))),r=0,h=this.Ia[0];for(;;){const t=Xt(e,n,1e-14)&&e>n+1e-14,i=Xt(e,s*h,1e-14),a=Xt(e,1,1e-14);if(!(t&&i&&a))break;e/=h,h=this.Ia[++r%this.Ia.length]}if(e<=n+1e-14&&(e=n),e=Math.max(1,e),this.Aa.length>0&&(a=e,l=1,o=1e-14,Math.abs(a-l)n+1e-14;)e/=h,h=this.Aa[++r%this.Aa.length];var a,l,o;return e}}class ui{constructor(t,i,s,n){this.Oa=[],this.qi=t,this.Ba=i,this.La=s,this.Na=n}za(t,i){if(tt.Ka)),c=this.qi.Xa(u);for(let t=0;t=n?1:-1;let _=null,u=0;for(let c=s-l;c>n;c-=i){const s=this.Na(c,t,!0);null!==_&&Math.abs(s-_)r||(u0&&h[0].ya-a.ya0&&l.ya-h[h.length-1].yaa(t.hs())-a(i.hs())))}var di;!function(t){t[t.Normal=0]="Normal",t[t.Logarithmic=1]="Logarithmic",t[t.Percentage=2]="Percentage",t[t.IndexedTo100=3]="IndexedTo100"}(di||(di={}));const fi=new J,pi=new G(100,1);class vi{constructor(t,i,s,n,e){this.il=0,this.sl=null,this.Ge=null,this.nl=null,this.el={rl:!1,hl:null},this.al=!1,this.ll=0,this.ol=0,this._l=new o,this.ul=new o,this.cl=[],this.dl=null,this.fl=null,this.pl=null,this.vl=null,this.ml=null,this.ra=pi,this.wl=oi(null),this.gl=t,this.ys=i,this.Ml=s,this.bl=n,this.xl=e,this.Sl=new ui(this,100,this.Cl.bind(this),this.yl.bind(this))}ma(){return this.gl}N(){return this.ys}hr(t){if(_(this.ys,t),this.wa(),void 0!==t.mode&&this.Pl({ie:t.mode}),void 0!==t.scaleMargins){const i=h(t.scaleMargins.top),s=h(t.scaleMargins.bottom);if(i<0||i>1)throw new Error(`Invalid top margin - expect value between 0 and 1, given=${i}`);if(s<0||s>1)throw new Error(`Invalid bottom margin - expect value between 0 and 1, given=${s}`);if(i+s>1)throw new Error(`Invalid margins - sum of margins must be less than 1, given=${i+s}`);this.kl(),this.pl=null}}Tl(){return this.ys.autoScale}Rl(){return this.al}Ja(){return 1===this.ys.mode}Oe(){return 2===this.ys.mode}Dl(){return 3===this.ys.mode}tl(){return this.wl}ie(){return{sn:this.ys.autoScale,El:this.ys.invertScale,ie:this.ys.mode}}Pl(t){const i=this.ie();let s=null;void 0!==t.sn&&(this.ys.autoScale=t.sn),void 0!==t.ie&&(this.ys.mode=t.ie,2!==t.ie&&3!==t.ie||(this.ys.autoScale=!0),this.el.rl=!1),1===i.ie&&t.ie!==i.ie&&(!function(t,i){if(null===t)return!1;const s=hi(t.$e(),i),n=hi(t.je(),i);return isFinite(s)&&isFinite(n)}(this.Ge,this.wl)?this.ys.autoScale=!0:(s=li(this.Ge,this.wl),null!==s&&this.Vl(s))),1===t.ie&&t.ie!==i.ie&&(s=ai(this.Ge,this.wl),null!==s&&this.Vl(s));const n=i.ie!==this.ys.mode;n&&(2===i.ie||this.Oe())&&this.wa(),n&&(3===i.ie||this.Dl())&&this.wa(),void 0!==t.El&&i.El!==t.El&&(this.ys.invertScale=t.El,this.Bl()),this.ul.p(i,this.ie())}Il(){return this.ul}P(){return this.Ml.fontSize}$t(){return this.il}Al(t){this.il!==t&&(this.il=t,this.kl(),this.pl=null)}zl(){if(this.sl)return this.sl;const t=this.$t()-this.Ol()-this.Ll();return this.sl=t,t}Qe(){return this.Nl(),this.Ge}Vl(t,i){const s=this.Ge;(i||null===s&&null!==t||null!==s&&!s.He(t))&&(this.pl=null,this.Ge=t)}Fl(t){this.Vl(t),this.Wl(null!==t)}Ki(){return this.Nl(),0===this.il||!this.Ge||this.Ge.Ki()}Hl(t){return this.El()?t:this.$t()-1-t}Nt(t,i){return this.Oe()?t=ii(t,i):this.Dl()&&(t=ni(t,i)),this.yl(t,i)}Ul(t,i,s){this.Nl();const n=this.Ll(),e=a(this.Qe()),r=e.$e(),h=e.je(),l=this.zl()-1,o=this.El(),_=l/(h-r),u=void 0===s?0:s.from,c=void 0===s?t.length:s.to,d=this.$l();for(let s=u;st.Ns()))}$a(){return this.ys.ensureEdgeTickMarksVisible&&this.Tl()}qa(){return this.P()/2}wa(){this.pl=null;let t=1/0;this.dl=null;for(const i of this.cl)i.hs()ri(t,this.wl):null}vo(t,i,s){return void 0===i?(void 0===s&&(s=this.ea()),s.format(t)):i(t)}mo(t,i,s){return void 0===i?(void 0===s&&(s=this.ea()),s.formatTickmarks(t)):i(t)}nr(t,i){return this.vo(t,this.bl.priceFormatter,i)}uo(t,i){const s=this.bl.priceFormatter;return this.mo(t,this.bl.tickmarksPriceFormatter??(s?t=>t.map(s):void 0),i)}oo(t,i){return this.vo(t,this.bl.percentageFormatter,i)}_o(t,i){const s=this.bl.percentageFormatter;return this.mo(t,this.bl.tickmarksPercentageFormatter??(s?t=>t.map(s):void 0),i)}}function mi(t){return t instanceof $t}class wi{constructor(t,i){this.cl=[],this.wo=new Map,this.il=0,this.Mo=0,this.bo=1,this.fl=null,this.xo=!1,this.So=new o,this.Ph=[],this.uh=t,this.ts=i,this.Co=new Qt(this);const s=i.N();this.yo=this.Po("left",s.leftPriceScale),this.ko=this.Po("right",s.rightPriceScale),this.yo.Il().i(this.To.bind(this,this.yo),this),this.ko.Il().i(this.To.bind(this,this.ko),this),this.Ro(s)}Ro(t){if(t.leftPriceScale&&this.yo.hr(t.leftPriceScale),t.rightPriceScale&&this.ko.hr(t.rightPriceScale),t.localization&&(this.yo.wa(),this.ko.wa()),t.overlayPriceScales){const i=Array.from(this.wo.values());for(const s of i){const i=a(s[0].Ft());i.hr(t.overlayPriceScales),t.localization&&i.wa()}}}Do(t){switch(t){case"left":return this.yo;case"right":return this.ko}return this.wo.has(t)?h(this.wo.get(t))[0].Ft():null}m(){this.Qt().Eo().u(this),this.yo.Il().u(this),this.ko.Il().u(this),this.cl.forEach((t=>{t.m&&t.m()})),this.Ph=this.Ph.filter((t=>{const i=t.oh();return i.detached&&i.detached(),!1})),this.So.p()}Vo(){return this.bo}Bo(t){this.bo=t}Qt(){return this.ts}Qi(){return this.Mo}$t(){return this.il}Io(t){this.Mo=t,this.Ao()}Al(t){this.il=t,this.yo.Al(t),this.ko.Al(t),this.cl.forEach((i=>{if(this.Un(i)){const s=i.Ft();null!==s&&s.Al(t)}})),this.Ao()}zo(t){this.xo=t}Oo(){return this.xo}Lo(){return this.cl.filter(mi)}Ma(){return this.cl}Un(t){const i=t.Ft();return null===i||this.yo!==i&&this.ko!==i}Gl(t,i,s){this.No(t,i,s?t.hs():this.cl.length)}Ql(t,i){const s=this.cl.indexOf(t);r(-1!==s,"removeDataSource: invalid data source"),this.cl.splice(s,1),i||this.cl.forEach(((t,i)=>t.ls(i)));const n=a(t.Ft()).ma();if(this.wo.has(n)){const i=h(this.wo.get(n)),s=i.indexOf(t);-1!==s&&(i.splice(s,1),0===i.length&&this.wo.delete(n))}const e=t.Ft();e&&e.Ma().indexOf(t)>=0&&(e.Ql(t),this.Fo(e)),this.fl=null}jn(t){return t===this.yo?"left":t===this.ko?"right":"overlay"}Wo(){return this.yo}Ho(){return this.ko}Uo(t,i){t.no(i)}$o(t,i){t.eo(i),this.Ao()}jo(t){t.ro()}qo(t,i){t.ho(i)}Yo(t,i){t.ao(i),this.Ao()}Ko(t){t.lo()}Ao(){this.cl.forEach((t=>{t.Ns()}))}ks(){let t=null;return this.ts.N().rightPriceScale.visible&&0!==this.ko.Ma().length?t=this.ko:this.ts.N().leftPriceScale.visible&&0!==this.yo.Ma().length?t=this.yo:0!==this.cl.length&&(t=this.cl[0].Ft()),null===t&&(t=this.ko),t}$n(){let t=null;return this.ts.N().rightPriceScale.visible?t=this.ko:this.ts.N().leftPriceScale.visible&&(t=this.yo),t}Fo(t){null!==t&&t.Tl()&&this.Xo(t)}Zo(t){const i=this.uh.ye();t.Pl({sn:!0}),null!==i&&t.do(i),this.Ao()}Go(){this.Xo(this.yo),this.Xo(this.ko)}Jo(){this.Fo(this.yo),this.Fo(this.ko),this.cl.forEach((t=>{this.Un(t)&&this.Fo(t.Ft())})),this.Ao(),this.ts.ar()}Dt(){return null===this.fl&&(this.fl=ci(this.cl)),this.fl}Qo(t,i){i=Kt(i,0,this.cl.length-1);const s=this.cl.indexOf(t);r(-1!==s,"setSeriesOrder: invalid data source"),this.cl.splice(s,1),this.cl.splice(i,0,t),this.cl.forEach(((t,i)=>t.ls(i))),this.fl=null;for(const t of[this.yo,this.ko])t.Jl(),t.wa();this.ts.ar()}Vt(){return this.Dt().filter(mi)}t_(){return this.So}i_(){return this.Co}_a(t){this.Ph.push(new Vt(t))}ua(t){this.Ph=this.Ph.filter((i=>i.oh()!==t)),t.detached&&t.detached(),this.ts.ar()}s_(){return this.Ph}sa(t,i){return this.Ph.map((s=>s.Yn(t,i))).filter((t=>null!==t))}Xo(t){const i=t.co();if(i&&i.length>0&&!this.uh.Ki()){const i=this.uh.ye();null!==i&&t.do(i)}t.Ns()}No(t,i,s){let n=this.Do(i);if(null===n&&(n=this.Po(i,this.ts.N().overlayPriceScales)),this.cl.splice(s,0,t),!q(i)){const s=this.wo.get(i)||[];s.push(t),this.wo.set(i,s)}t.ls(s),n.Gl(t),t._s(n),this.Fo(n),this.fl=null}To(t,i,s){i.ie!==s.ie&&this.Xo(t)}Po(t,i){const s={visible:!0,autoScale:!0,...p(i)},n=new vi(t,s,this.ts.N().layout,this.ts.N().localization,this.ts.Xi());return n.Al(this.$t()),n}}function gi(t){return{n_:t.n_,e_:{Kn:t.r_.externalId},h_:t.r_.cursorStyle}}function Mi(t,i,s,n){for(const e of t){const t=e.Tt(n);if(null!==t&&t.Yn){const n=t.Yn(i,s);if(null!==n)return{a_:e,e_:n}}}return null}function bi(t){return void 0!==t.Fs}function xi(t,i,s){const n=[t,...t.Dt()],e=function(t,i,s){let n,e;for(const a of t){const t=a.sa?.(i,s)??[];for(const i of t)r=i.zOrder,h=n?.zOrder,(!h||"top"===r&&"top"!==h||"normal"===r&&"bottom"===h)&&(n=i,e=a)}var r,h;return n&&e?{r_:n,n_:e}:null}(n,i,s);if("top"===e?.r_.zOrder)return gi(e);for(const r of n){if(e&&e.n_===r&&"bottom"!==e.r_.zOrder&&!e.r_.isBackground)return gi(e);if(bi(r)){const n=Mi(r.Fs(t),i,s,t);if(null!==n)return{n_:r,a_:n.a_,e_:n.e_}}if(e&&e.n_===r&&"bottom"!==e.r_.zOrder&&e.r_.isBackground)return gi(e)}return e?.r_?gi(e):null}class Si{constructor(t,i,s=50){this.Pn=0,this.kn=1,this.Tn=1,this.Dn=new Map,this.Rn=new Map,this.l_=t,this.o_=i,this.En=s}__(t){const i=t.time,s=this.o_.cacheKey(i),n=this.Dn.get(s);if(void 0!==n)return n.u_;if(this.Pn===this.En){const t=this.Rn.get(this.Tn);this.Rn.delete(this.Tn),this.Dn.delete(h(t)),this.Tn++,this.Pn--}const e=this.l_(t);return this.Dn.set(s,{u_:e,An:this.kn}),this.Rn.set(this.kn,s),this.Pn++,this.kn++,e}}class Ci{constructor(t,i){r(t<=i,"right should be >= left"),this.c_=t,this.d_=i}Uh(){return this.c_}bi(){return this.d_}f_(){return this.d_-this.c_+1}Te(t){return this.c_<=t&&t<=this.d_}He(t){return this.c_===t.Uh()&&this.d_===t.bi()}}function yi(t,i){return null===t||null===i?t===i:t.He(i)}class Pi{constructor(){this.p_=new Map,this.Dn=null,this.v_=!1}m_(t){this.v_=t,this.Dn=null}w_(t,i){this.g_(i),this.Dn=null;for(let s=i;s{t<=s[0].index?i.push(n):s.splice(xt(s,t,(i=>i.index!i||s.has(t.index);for(const i of Array.from(this.p_.keys()).sort(((t,i)=>i-t))){if(!this.p_.get(i))continue;const s=n;n=[];const r=s.length;let a=0;const l=h(this.p_.get(i)),o=l.length;let _=1/0,u=-1/0;for(let i=0;i=t&&o-u>=t&&e(h))n.push(h),u=o;else if(this.v_)return s}for(;ai.weight?t:i}class Ri{constructor(t,i,s,n){this.Mo=0,this.R_=null,this.D_=[],this.ml=null,this.vl=null,this.E_=new Pi,this.V_=new Map,this.B_=ki.T_(),this.I_=!0,this.A_=new o,this.z_=new o,this.O_=new o,this.L_=null,this.N_=null,this.F_=new Map,this.W_=-1,this.H_=[],this.ys=i,this.bl=s,this.U_=i.rightOffset,this.j_=i.barSpacing,this.ts=t,this.q_(i),this.o_=n,this.Y_(),this.E_.m_(i.uniformDistribution),this.K_()}N(){return this.ys}X_(t){_(this.bl,t),this.Z_(),this.Y_()}hr(t,i){_(this.ys,t),this.ys.fixLeftEdge&&this.G_(),this.ys.fixRightEdge&&this.J_(),void 0!==t.barSpacing&&this.ts.dn(t.barSpacing),void 0!==t.rightOffset&&this.ts.fn(t.rightOffset),this.q_(t),void 0===t.minBarSpacing&&void 0===t.maxBarSpacing||this.ts.dn(t.barSpacing??this.j_),void 0!==t.ignoreWhitespaceIndices&&t.ignoreWhitespaceIndices!==this.ys.ignoreWhitespaceIndices&&this.K_(),this.Z_(),this.Y_(),this.O_.p()}Rs(t){return this.D_[t]?.time??null}ss(t){return this.D_[t]??null}Q_(t,i){if(this.D_.length<1)return null;if(this.o_.key(t)>this.o_.key(this.D_[this.D_.length-1].time))return i?this.D_.length-1:null;const s=xt(this.D_,this.o_.key(t),((t,i)=>this.o_.key(t.time)0}ye(){return this.iu(),this.B_.P_()}su(){return this.iu(),this.B_.k_()}nu(){const t=this.ye();if(null===t)return null;const i={from:t.Uh(),to:t.bi()};return this.eu(i)}eu(t){const i=Math.round(t.from),s=Math.round(t.to),n=a(this.ru()),e=a(this.hu());return{from:a(this.ss(Math.max(n,i))),to:a(this.ss(Math.min(e,s)))}}au(t){return{from:a(this.Q_(t.from,!0)),to:a(this.Q_(t.to,!0))}}Qi(){return this.Mo}Io(t){if(!isFinite(t)||t<=0)return;if(this.Mo===t)return;const i=this.su(),s=this.Mo;if(this.Mo=t,this.I_=!0,this.ys.lockVisibleTimeRangeOnResize&&0!==s){const i=this.j_*t/s;this.j_=i}if(this.ys.fixLeftEdge&&null!==i&&i.Uh()<=0){const i=s-t;this.U_-=Math.round(i/this.j_)+1,this.I_=!0}this.lu(),this.ou()}jt(t){if(this.Ki()||!c(t))return 0;const i=this._u()+this.U_-t;return this.Mo-(i+.5)*this.j_-1}uu(t,i){const s=this._u(),n=void 0===i?0:i.from,e=void 0===i?t.length:i.to;for(let i=n;ii/2&&!_?s.needAlignCoordinate=!1:s.needAlignCoordinate=u&&t.index<=l||c&&t.index>=o,d++}return this.H_.length=d,this.N_=this.H_,this.H_}xu(){let t;this.I_=!0,this.dn(this.ys.barSpacing),t=void 0!==this.ys.rightOffsetPixels?this.ys.rightOffsetPixels/this.mu():this.ys.rightOffset,this.fn(t)}Su(t){this.I_=!0,this.R_=t,this.ou(),this.G_()}Cu(t,i){const s=this.du(t),n=this.mu(),e=n+i*(n/10);this.dn(e),this.ys.rightBarStaysOnScroll||this.fn(this.gu()+(s-this.du(t)))}no(t){this.ml&&this.lo(),null===this.vl&&null===this.L_&&(this.Ki()||(this.vl=t,this.yu()))}eo(t){if(null===this.L_)return;const i=Kt(this.Mo-t,0,this.Mo),s=Kt(this.Mo-a(this.vl),0,this.Mo);0!==i&&0!==s&&this.dn(this.L_.mu*i/s)}ro(){null!==this.vl&&(this.vl=null,this.Pu())}ho(t){null===this.ml&&null===this.L_&&(this.Ki()||(this.ml=t,this.yu()))}ao(t){if(null===this.ml)return;const i=(this.ml-t)/this.mu();this.U_=a(this.L_).gu+i,this.I_=!0,this.ou()}lo(){null!==this.ml&&(this.ml=null,this.Pu())}ku(){this.Tu(this.ys.rightOffset)}Tu(t,i=400){if(!isFinite(t))throw new RangeError("offset is required and must be finite number");if(!isFinite(i)||i<=0)throw new RangeError("animationDuration (optional) must be finite positive number");const s=this.U_,n=performance.now();this.ts._n({Ru:t=>(t-n)/i>=1,Du:e=>{const r=(e-n)/i;return r>=1?t:s+(t-s)*r}})}Pt(t,i){this.I_=!0,this.D_=t,this.E_.w_(t,i),this.ou()}Eu(){return this.A_}Vu(){return this.z_}Bu(){return this.O_}_u(){return this.R_||0}Iu(t,i){const s=t.f_(),n=i&&this.ys.rightOffsetPixels||0;this.wu((this.Mo-n)/s),this.U_=t.bi()-this._u(),i&&(this.U_=n?n/this.mu():this.ys.rightOffset),this.ou(),this.I_=!0,this.ts.vu(),this.ts.ar()}Au(){const t=this.ru(),i=this.hu();null!==t&&null!==i&&this.Iu(new Ci(t,i),!0)}zu(t){const i=new Ci(t.from,t.to);this.Iu(i)}ns(t){return void 0!==this.bl.timeFormatter?this.bl.timeFormatter(t.originalTime):this.o_.formatHorzItem(t.time)}K_(){if(!this.ys.ignoreWhitespaceIndices)return;this.F_.clear();const t=this.ts.Ys();for(const i of t)for(const t of i.va())this.F_.set(t,!0);this.W_++}Mu(){const t=this.ts.N().handleScroll,i=this.ts.N().handleScale;return!(t.horzTouchDrag||t.mouseWheel||t.pressedMouseMove||t.vertTouchDrag||i.axisDoubleClickReset.time||i.axisPressedMouseMove.time||i.mouseWheel||i.pinch)}ru(){return 0===this.D_.length?null:0}hu(){return 0===this.D_.length?null:this.D_.length-1}Ou(t){return(this.Mo-1-t)/this.j_}du(t){const i=this.Ou(t),s=this._u()+this.U_-i;return Math.round(1e6*s)/1e6}wu(t){const i=this.j_;this.j_=t,this.lu(),i!==this.j_&&(this.I_=!0,this.Lu())}iu(){if(!this.I_)return;if(this.I_=!1,this.Ki())return void this.Nu(ki.T_());const t=this._u(),i=this.Mo/this.j_,s=this.U_+t,n=new Ci(s-i+1,s);this.Nu(new ki(n))}lu(){const t=Kt(this.j_,this.Fu(),this.Wu());this.j_!==t&&(this.j_=t,this.I_=!0)}Wu(){return this.ys.maxBarSpacing>0?this.ys.maxBarSpacing:.5*this.Mo}Fu(){return this.ys.fixLeftEdge&&this.ys.fixRightEdge&&0!==this.D_.length?this.Mo/this.D_.length:this.ys.minBarSpacing}ou(){const t=this.Hu();null!==t&&this.U_i&&(this.U_=i,this.I_=!0)}Hu(){const t=this.ru(),i=this.R_;if(null===t||null===i)return null;return t-i-1+(this.ys.fixLeftEdge?this.Mo/this.j_:Math.min(2,this.D_.length))}Uu(){return this.ys.fixRightEdge?0:this.Mo/this.j_-Math.min(2,this.D_.length)}yu(){this.L_={mu:this.mu(),gu:this.gu()}}Pu(){this.L_=null}bu(t){let i=this.V_.get(t.weight);return void 0===i&&(i=new Si((t=>this.$u(t)),this.o_),this.V_.set(t.weight,i)),i.__(t)}$u(t){return this.o_.formatTickmark(t,this.bl)}Nu(t){const i=this.B_;this.B_=t,yi(i.P_(),this.B_.P_())||this.A_.p(),yi(i.k_(),this.B_.k_())||this.z_.p(),this.Lu()}Lu(){this.N_=null}Z_(){this.Lu(),this.V_.clear()}Y_(){this.o_.updateFormatter(this.bl)}G_(){if(!this.ys.fixLeftEdge)return;const t=this.ru();if(null===t)return;const i=this.ye();if(null===i)return;const s=i.Uh()-t;if(s<0){const t=this.U_-s-1;this.fn(t)}this.lu()}J_(){this.ou(),this.lu()}fu(t){return!this.ys.ignoreWhitespaceIndices||(this.F_.get(t)||!1)}pu(t){const i=function*(t){const i=Math.round(t),s=is)break}return t}q_(t){if(void 0!==t.rightOffsetPixels){const i=t.rightOffsetPixels/(t.barSpacing||this.j_);this.ts.fn(i)}}}var Di,Ei,Vi,Bi,Ii;!function(t){t[t.OnTouchEnd=0]="OnTouchEnd",t[t.OnNextTap=1]="OnNextTap"}(Di||(Di={}));class Ai{constructor(t,i,s){this.ju=[],this.qu=[],this.Mo=0,this.Yu=null,this.Ku=new o,this.Xu=new o,this.Zu=null,this.Gu=t,this.ys=i,this.o_=s,this.xl=new S(this.ys.layout.colorParsers),this.Ju=new M(this),this.uh=new Ri(this,i.timeScale,this.ys.localization,s),this.Ct=new j(this,i.crosshair),this.Qu=new Yt(i.crosshair),i.addDefaultPane&&(this.tc(0),this.ju[0].Bo(2)),this.sc=this.nc(0),this.ec=this.nc(1)}Bh(){this.rc(Y.gn())}ar(){this.rc(Y.wn())}Zh(){this.rc(new Y(1))}Ih(t){const i=this.hc(t);this.rc(i)}ac(){return this.Yu}lc(t){if(this.Yu?.n_===t?.n_&&this.Yu?.e_?.Kn===t?.e_?.Kn)return;const i=this.Yu;this.Yu=t,null!==i&&this.Ih(i.n_),null!==t&&t.n_!==i?.n_&&this.Ih(t.n_)}N(){return this.ys}hr(t){_(this.ys,t),this.ju.forEach((i=>i.Ro(t))),void 0!==t.timeScale&&this.uh.hr(t.timeScale),void 0!==t.localization&&this.uh.X_(t.localization),(t.leftPriceScale||t.rightPriceScale)&&this.Ku.p(),this.sc=this.nc(0),this.ec=this.nc(1),this.Bh()}oc(t,i,s=0){const n=this.ju[s];if(void 0===n)return;if("left"===t)return _(this.ys,{leftPriceScale:i}),n.Ro({leftPriceScale:i}),this.Ku.p(),void this.Bh();if("right"===t)return _(this.ys,{rightPriceScale:i}),n.Ro({rightPriceScale:i}),this.Ku.p(),void this.Bh();const e=this._c(t,s);null!==e&&(e.Ft.hr(i),this.Ku.p())}_c(t,i){const s=this.ju[i];if(void 0===s)return null;const n=s.Do(t);return null!==n?{Us:s,Ft:n}:null}It(){return this.uh}$s(){return this.ju}uc(){return this.Ct}cc(){return this.Xu}dc(t,i){t.Al(i),this.vu()}Io(t){this.Mo=t,this.uh.Io(this.Mo),this.ju.forEach((i=>i.Io(t))),this.vu()}fc(t){1!==this.ju.length&&(r(t>=0&&t=0&&tt+i.Vo()),0),e=this.ju.reduce(((t,i)=>t+i.$t()),0),h=e-30*(this.ju.length-1);i=Math.min(h,Math.max(30,i));const a=n/e,l=s.$t();s.Bo(i*a);let o=i-l,_=this.ju.length-1;for(const t of this.ju)if(t!==s){const i=Math.min(h,Math.max(30,t.$t()-o/_));o-=t.$t()-i,_-=1;const s=i*a;t.Bo(s)}this.Bh()}mc(t,i){r(t>=0&&t=0&&i=0&&t=0&&ithis.o_.key(e),l=null!==t&&t>r&&!a,o=this.uh.N().allowShiftVisibleRangeOnWhitespaceReplacement,_=i&&(!(void 0===s)||o)&&this.uh.N().shiftVisibleRangeOnNewBar;if(l&&!_){const i=t-r;this.uh.fn(this.uh.gu()-i)}}this.uh.Su(t)}Oh(t){null!==t&&t.Jo()}Hn(t){if(function(t){return t instanceof wi}(t))return t;const i=this.ju.find((i=>i.Dt().includes(t)));return void 0===i?null:i}vu(){this.ju.forEach((t=>t.Jo())),this.Ah()}m(){this.ju.forEach((t=>t.m())),this.ju.length=0,this.ys.localization.priceFormatter=void 0,this.ys.localization.percentageFormatter=void 0,this.ys.localization.timeFormatter=void 0}Vc(){return this.Ju}qn(){return this.Ju.N()}Eo(){return this.Ku}Bc(t,i){const s=this.tc(i);this.Ic(t,s),this.qu.push(t),1===this.qu.length?this.Bh():this.ar()}Ac(t){const i=this.Hn(t),s=this.qu.indexOf(t);r(-1!==s,"Series not found");const n=a(i);this.qu.splice(s,1),n.Ql(t),t.m&&t.m(),this.uh.K_(),this.zc(n)}Vh(t,i){const s=a(this.Hn(t));s.Ql(t,!0),s.Gl(t,i,!0)}Au(){const t=Y.wn();t.rn(),this.rc(t)}Oc(t){const i=Y.wn();i.ln(t),this.rc(i)}cn(){const t=Y.wn();t.cn(),this.rc(t)}dn(t){const i=Y.wn();i.dn(t),this.rc(i)}fn(t){const i=Y.wn();i.fn(t),this.rc(i)}_n(t){const i=Y.wn();i._n(t),this.rc(i)}hn(){const t=Y.wn();t.hn(),this.rc(t)}Lc(){return this.ys.rightPriceScale.visible?"right":"left"}Nc(t,i){r(i>=0,"Index should be greater or equal to 0");if(i===this.Fc(t))return;const s=a(this.Hn(t));s.Ql(t);const n=this.tc(i);this.Ic(t,n),0===s.Ma().length&&this.zc(s),this.Bh()}Wc(){return this.ec}$(){return this.sc}Ut(t){const i=this.ec,s=this.sc;if(i===s)return i;if(t=Math.max(0,Math.min(100,Math.round(100*t))),null===this.Zu||this.Zu.mr!==s||this.Zu.wr!==i)this.Zu={mr:s,wr:i,Hc:new Map};else{const i=this.Zu.Hc.get(t);if(void 0!==i)return i}const n=this.xl.tt(s,i,t/100);return this.Zu.Hc.set(t,n),n}Uc(t){return this.ju.indexOf(t)}Xi(){return this.xl}$c(){return this.jc()}jc(t){const i=new wi(this.uh,this);this.ju.push(i);const s=t??this.ju.length-1,n=Y.gn();return n.Qs(s,{tn:0,sn:!0}),this.rc(n),i}tc(t){return r(t>=0,"Index should be greater or equal to 0"),(t=Math.min(this.ju.length,t))i.Lo().includes(t)))}gc(t,i){const s=new Y(i);if(null!==t){const n=this.ju.indexOf(t);s.Qs(n,{tn:i})}return s}hc(t,i){return void 0===i&&(i=2),this.gc(this.Hn(t),i)}rc(t){this.Gu&&this.Gu(t),this.ju.forEach((t=>t.i_().lr().Pt()))}Ic(t,i){const s=t.N().priceScaleId,n=void 0!==s?s:this.Lc();i.Gl(t,n),q(n)||t.hr(t.N())}nc(t){const i=this.ys.layout;return"gradient"===i.background.type?0===t?i.background.topColor:i.background.bottomColor:i.background.color}zc(t){!t.Oo()&&0===t.Ma().length&&this.ju.length>1&&this.ju.splice(this.Uc(t),1)}}function zi(t){if(t>=1)return 0;let i=0;for(;i<8;i++){const s=Math.round(t);if(Math.abs(s-t)<1e-8)return i;t*=10}return i}function Oi(t){return!u(t)&&!d(t)}function Li(t){return u(t)}!function(t){t[t.Disabled=0]="Disabled",t[t.Continuous=1]="Continuous",t[t.OnDataUpdate=2]="OnDataUpdate"}(Ei||(Ei={})),function(t){t[t.LastBar=0]="LastBar",t[t.LastVisible=1]="LastVisible"}(Vi||(Vi={})),function(t){t.Solid="solid",t.VerticalGradient="gradient"}(Bi||(Bi={})),function(t){t[t.Year=0]="Year",t[t.Month=1]="Month",t[t.DayOfMonth=2]="DayOfMonth",t[t.Time=3]="Time",t[t.TimeWithSeconds=4]="TimeWithSeconds"}(Ii||(Ii={}));const Ni=t=>t.getUTCFullYear();function Fi(t,i,s){return i.replace(/yyyy/g,(t=>Z(Ni(t),4))(t)).replace(/yy/g,(t=>Z(Ni(t)%100,2))(t)).replace(/MMMM/g,((t,i)=>new Date(t.getUTCFullYear(),t.getUTCMonth(),1).toLocaleString(i,{month:"long"}))(t,s)).replace(/MMM/g,((t,i)=>new Date(t.getUTCFullYear(),t.getUTCMonth(),1).toLocaleString(i,{month:"short"}))(t,s)).replace(/MM/g,(t=>Z((t=>t.getUTCMonth()+1)(t),2))(t)).replace(/dd/g,(t=>Z((t=>t.getUTCDate())(t),2))(t))}class Wi{constructor(t="yyyy-MM-dd",i="default"){this.qc=t,this.Yc=i}__(t){return Fi(t,this.qc,this.Yc)}}class Hi{constructor(t){this.Kc=t||"%h:%m:%s"}__(t){return this.Kc.replace("%h",Z(t.getUTCHours(),2)).replace("%m",Z(t.getUTCMinutes(),2)).replace("%s",Z(t.getUTCSeconds(),2))}}const Ui={Xc:"yyyy-MM-dd",Zc:"%h:%m:%s",Gc:" ",Jc:"default"};class $i{constructor(t={}){const i={...Ui,...t};this.Qc=new Wi(i.Xc,i.Jc),this.td=new Hi(i.Zc),this.sd=i.Gc}__(t){return`${this.Qc.__(t)}${this.sd}${this.td.__(t)}`}}function ji(t){return 60*t*60*1e3}function qi(t){return 60*t*1e3}const Yi=[{nd:(Ki=1,1e3*Ki),ed:10},{nd:qi(1),ed:20},{nd:qi(5),ed:21},{nd:qi(30),ed:22},{nd:ji(1),ed:30},{nd:ji(3),ed:31},{nd:ji(6),ed:32},{nd:ji(12),ed:33}];var Ki;function Xi(t,i){if(t.getUTCFullYear()!==i.getUTCFullYear())return 70;if(t.getUTCMonth()!==i.getUTCMonth())return 60;if(t.getUTCDate()!==i.getUTCDate())return 50;for(let s=Yi.length-1;s>=0;--s)if(Math.floor(i.getTime()/Yi[s].nd)!==Math.floor(t.getTime()/Yi[s].nd))return Yi[s].ed;return 0}function Zi(t){let i=t;if(d(t)&&(i=Ji(t)),!Oi(i))throw new Error("time must be of type BusinessDay");const s=new Date(Date.UTC(i.year,i.month-1,i.day,0,0,0,0));return{rd:Math.round(s.getTime()/1e3),hd:i}}function Gi(t){if(!Li(t))throw new Error("time must be of type isUTCTimestamp");return{rd:t}}function Ji(t){const i=new Date(t);if(isNaN(i.getTime()))throw new Error(`Invalid date string=${t}, expected format=yyyy-mm-dd`);return{day:i.getUTCDate(),month:i.getUTCMonth()+1,year:i.getUTCFullYear()}}function Qi(t){d(t.time)&&(t.time=Ji(t.time))}class ts{options(){return this.ys}setOptions(t){this.ys=t,this.updateFormatter(t.localization)}preprocessData(t){Array.isArray(t)?function(t){t.forEach(Qi)}(t):Qi(t)}createConverterToInternalObj(t){return a(function(t){return 0===t.length?null:Oi(t[0].time)||d(t[0].time)?Zi:Gi}(t))}key(t){return"object"==typeof t&&"rd"in t?t.rd:this.key(this.convertHorzItemToInternal(t))}cacheKey(t){const i=t;return void 0===i.hd?new Date(1e3*i.rd).getTime():new Date(Date.UTC(i.hd.year,i.hd.month-1,i.hd.day)).getTime()}convertHorzItemToInternal(t){return Li(i=t)?Gi(i):Oi(i)?Zi(i):Zi(Ji(i));var i}updateFormatter(t){if(!this.ys)return;const i=t.dateFormat;this.ys.timeScale.timeVisible?this.ad=new $i({Xc:i,Zc:this.ys.timeScale.secondsVisible?"%h:%m:%s":"%h:%m",Gc:" ",Jc:t.locale}):this.ad=new Wi(i,t.locale)}formatHorzItem(t){const i=t;return this.ad.__(new Date(1e3*i.rd))}formatTickmark(t,i){const s=function(t,i,s){switch(t){case 0:case 10:return i?s?4:3:2;case 20:case 21:case 22:case 30:case 31:case 32:case 33:return i?3:2;case 50:return 2;case 60:return 1;case 70:return 0}}(t.weight,this.ys.timeScale.timeVisible,this.ys.timeScale.secondsVisible),n=this.ys.timeScale;if(void 0!==n.tickMarkFormatter){const e=n.tickMarkFormatter(t.originalTime,s,i.locale);if(null!==e)return e}return function(t,i,s){const n={};switch(i){case 0:n.year="numeric";break;case 1:n.month="short";break;case 2:n.day="numeric";break;case 3:n.hour12=!1,n.hour="2-digit",n.minute="2-digit";break;case 4:n.hour12=!1,n.hour="2-digit",n.minute="2-digit",n.second="2-digit"}const e=void 0===t.hd?new Date(1e3*t.rd):new Date(Date.UTC(t.hd.year,t.hd.month-1,t.hd.day));return new Date(e.getUTCFullYear(),e.getUTCMonth(),e.getUTCDate(),e.getUTCHours(),e.getUTCMinutes(),e.getUTCSeconds(),e.getUTCMilliseconds()).toLocaleString(s,n)}(t.time,s,i.locale)}maxTickMarkWeight(t){let i=t.reduce(Ti,t[0]).weight;return i>30&&i<50&&(i=30),i}fillWeightsForPoints(t,i){!function(t,i=0){if(0===t.length)return;let s=0===i?null:t[i-1].time.rd,n=null!==s?new Date(1e3*s):null,e=0;for(let r=i;r1){const i=Math.ceil(e/(t.length-1)),s=new Date(1e3*(t[0].time.rd-i));t[0].timeWeight=Xi(new Date(1e3*t[0].time.rd),s)}}(t,i)}static ld(t){return _({localization:{dateFormat:"dd MMM 'yy"}},t??{})}}function is(t){var i=t.width,s=t.height;if(i<0)throw new Error("Negative width is not allowed for Size");if(s<0)throw new Error("Negative height is not allowed for Size");return{width:i,height:s}}function ss(t,i){return t.width===i.width&&t.height===i.height}var ns=function(){function t(t){var i=this;this._resolutionListener=function(){return i._onResolutionChanged()},this._resolutionMediaQueryList=null,this._observers=[],this._window=t,this._installResolutionListener()}return t.prototype.dispose=function(){this._uninstallResolutionListener(),this._window=null},Object.defineProperty(t.prototype,"value",{get:function(){return this._window.devicePixelRatio},enumerable:!1,configurable:!0}),t.prototype.subscribe=function(t){var i=this,s={next:t};return this._observers.push(s),{unsubscribe:function(){i._observers=i._observers.filter((function(t){return t!==s}))}}},t.prototype._installResolutionListener=function(){if(null!==this._resolutionMediaQueryList)throw new Error("Resolution listener is already installed");var t=this._window.devicePixelRatio;this._resolutionMediaQueryList=this._window.matchMedia("all and (resolution: ".concat(t,"dppx)")),this._resolutionMediaQueryList.addListener(this._resolutionListener)},t.prototype._uninstallResolutionListener=function(){null!==this._resolutionMediaQueryList&&(this._resolutionMediaQueryList.removeListener(this._resolutionListener),this._resolutionMediaQueryList=null)},t.prototype._reinstallResolutionListener=function(){this._uninstallResolutionListener(),this._installResolutionListener()},t.prototype._onResolutionChanged=function(){var t=this;this._observers.forEach((function(i){return i.next(t._window.devicePixelRatio)})),this._reinstallResolutionListener()},t}();var es=function(){function t(t,i,s){var n;this._canvasElement=null,this._bitmapSizeChangedListeners=[],this._suggestedBitmapSize=null,this._suggestedBitmapSizeChangedListeners=[],this._devicePixelRatioObservable=null,this._canvasElementResizeObserver=null,this._canvasElement=t,this._canvasElementClientSize=is({width:this._canvasElement.clientWidth,height:this._canvasElement.clientHeight}),this._transformBitmapSize=null!=i?i:function(t){return t},this._allowResizeObserver=null===(n=null==s?void 0:s.allowResizeObserver)||void 0===n||n,this._chooseAndInitObserver()}return t.prototype.dispose=function(){var t,i;if(null===this._canvasElement)throw new Error("Object is disposed");null===(t=this._canvasElementResizeObserver)||void 0===t||t.disconnect(),this._canvasElementResizeObserver=null,null===(i=this._devicePixelRatioObservable)||void 0===i||i.dispose(),this._devicePixelRatioObservable=null,this._suggestedBitmapSizeChangedListeners.length=0,this._bitmapSizeChangedListeners.length=0,this._canvasElement=null},Object.defineProperty(t.prototype,"canvasElement",{get:function(){if(null===this._canvasElement)throw new Error("Object is disposed");return this._canvasElement},enumerable:!1,configurable:!0}),Object.defineProperty(t.prototype,"canvasElementClientSize",{get:function(){return this._canvasElementClientSize},enumerable:!1,configurable:!0}),Object.defineProperty(t.prototype,"bitmapSize",{get:function(){return is({width:this.canvasElement.width,height:this.canvasElement.height})},enumerable:!1,configurable:!0}),t.prototype.resizeCanvasElement=function(t){this._canvasElementClientSize=is(t),this.canvasElement.style.width="".concat(this._canvasElementClientSize.width,"px"),this.canvasElement.style.height="".concat(this._canvasElementClientSize.height,"px"),this._invalidateBitmapSize()},t.prototype.subscribeBitmapSizeChanged=function(t){this._bitmapSizeChangedListeners.push(t)},t.prototype.unsubscribeBitmapSizeChanged=function(t){this._bitmapSizeChangedListeners=this._bitmapSizeChangedListeners.filter((function(i){return i!==t}))},Object.defineProperty(t.prototype,"suggestedBitmapSize",{get:function(){return this._suggestedBitmapSize},enumerable:!1,configurable:!0}),t.prototype.subscribeSuggestedBitmapSizeChanged=function(t){this._suggestedBitmapSizeChangedListeners.push(t)},t.prototype.unsubscribeSuggestedBitmapSizeChanged=function(t){this._suggestedBitmapSizeChangedListeners=this._suggestedBitmapSizeChangedListeners.filter((function(i){return i!==t}))},t.prototype.applySuggestedBitmapSize=function(){if(null!==this._suggestedBitmapSize){var t=this._suggestedBitmapSize;this._suggestedBitmapSize=null,this._resizeBitmap(t),this._emitSuggestedBitmapSizeChanged(t,this._suggestedBitmapSize)}},t.prototype._resizeBitmap=function(t){var i=this.bitmapSize;ss(i,t)||(this.canvasElement.width=t.width,this.canvasElement.height=t.height,this._emitBitmapSizeChanged(i,t))},t.prototype._emitBitmapSizeChanged=function(t,i){var s=this;this._bitmapSizeChangedListeners.forEach((function(n){return n.call(s,t,i)}))},t.prototype._suggestNewBitmapSize=function(t){var i=this._suggestedBitmapSize,s=is(this._transformBitmapSize(t,this._canvasElementClientSize)),n=ss(this.bitmapSize,s)?null:s;null===i&&null===n||null!==i&&null!==n&&ss(i,n)||(this._suggestedBitmapSize=n,this._emitSuggestedBitmapSizeChanged(i,n))},t.prototype._emitSuggestedBitmapSizeChanged=function(t,i){var s=this;this._suggestedBitmapSizeChangedListeners.forEach((function(n){return n.call(s,t,i)}))},t.prototype._chooseAndInitObserver=function(){var t=this;this._allowResizeObserver?new Promise((function(t){var i=new ResizeObserver((function(s){t(s.every((function(t){return"devicePixelContentBoxSize"in t}))),i.disconnect()}));i.observe(document.body,{box:"device-pixel-content-box"})})).catch((function(){return!1})).then((function(i){return i?t._initResizeObserver():t._initDevicePixelRatioObservable()})):this._initDevicePixelRatioObservable()},t.prototype._initDevicePixelRatioObservable=function(){var t=this;if(null!==this._canvasElement){var i=rs(this._canvasElement);if(null===i)throw new Error("No window is associated with the canvas");this._devicePixelRatioObservable=function(t){return new ns(t)}(i),this._devicePixelRatioObservable.subscribe((function(){return t._invalidateBitmapSize()})),this._invalidateBitmapSize()}},t.prototype._invalidateBitmapSize=function(){var t,i;if(null!==this._canvasElement){var s=rs(this._canvasElement);if(null!==s){var n=null!==(i=null===(t=this._devicePixelRatioObservable)||void 0===t?void 0:t.value)&&void 0!==i?i:s.devicePixelRatio,e=this._canvasElement.getClientRects(),r=void 0!==e[0]?function(t,i){return is({width:Math.round(t.left*i+t.width*i)-Math.round(t.left*i),height:Math.round(t.top*i+t.height*i)-Math.round(t.top*i)})}(e[0],n):is({width:this._canvasElementClientSize.width*n,height:this._canvasElementClientSize.height*n});this._suggestNewBitmapSize(r)}}},t.prototype._initResizeObserver=function(){var t=this;null!==this._canvasElement&&(this._canvasElementResizeObserver=new ResizeObserver((function(i){var s=i.find((function(i){return i.target===t._canvasElement}));if(s&&s.devicePixelContentBoxSize&&s.devicePixelContentBoxSize[0]){var n=s.devicePixelContentBoxSize[0],e=is({width:n.inlineSize,height:n.blockSize});t._suggestNewBitmapSize(e)}})),this._canvasElementResizeObserver.observe(this._canvasElement,{box:"device-pixel-content-box"}))},t}();function rs(t){return t.ownerDocument.defaultView}var hs=function(){function t(t,i,s){if(0===i.width||0===i.height)throw new TypeError("Rendering target could only be created on a media with positive width and height");if(this._mediaSize=i,0===s.width||0===s.height)throw new TypeError("Rendering target could only be created using a bitmap with positive integer width and height");this._bitmapSize=s,this._context=t}return t.prototype.useMediaCoordinateSpace=function(t){try{return this._context.save(),this._context.setTransform(1,0,0,1,0,0),this._context.scale(this._horizontalPixelRatio,this._verticalPixelRatio),t({context:this._context,mediaSize:this._mediaSize})}finally{this._context.restore()}},t.prototype.useBitmapCoordinateSpace=function(t){try{return this._context.save(),this._context.setTransform(1,0,0,1,0,0),t({context:this._context,mediaSize:this._mediaSize,bitmapSize:this._bitmapSize,horizontalPixelRatio:this._horizontalPixelRatio,verticalPixelRatio:this._verticalPixelRatio})}finally{this._context.restore()}},Object.defineProperty(t.prototype,"_horizontalPixelRatio",{get:function(){return this._bitmapSize.width/this._mediaSize.width},enumerable:!1,configurable:!0}),Object.defineProperty(t.prototype,"_verticalPixelRatio",{get:function(){return this._bitmapSize.height/this._mediaSize.height},enumerable:!1,configurable:!0}),t}();function as(t,i){var s=t.canvasElementClientSize;if(0===s.width||0===s.height)return null;var n=t.bitmapSize;if(0===n.width||0===n.height)return null;var e=t.canvasElement.getContext("2d",i);return null===e?null:new hs(e,s,n)}const ls="undefined"!=typeof window;function os(){return!!ls&&window.navigator.userAgent.toLowerCase().indexOf("firefox")>-1}function _s(){return!!ls&&/iPhone|iPad|iPod/.test(window.navigator.platform)}function us(t){return t+t%2}function cs(t){ls&&void 0!==window.chrome&&t.addEventListener("mousedown",(t=>{if(1===t.button)return t.preventDefault(),!1}))}class ds{constructor(t,i,s){this.od=0,this._d=null,this.ud={_t:Number.NEGATIVE_INFINITY,ut:Number.POSITIVE_INFINITY},this.dd=0,this.fd=null,this.pd={_t:Number.NEGATIVE_INFINITY,ut:Number.POSITIVE_INFINITY},this.vd=null,this.md=!1,this.wd=null,this.gd=null,this.Md=!1,this.bd=!1,this.xd=!1,this.Sd=null,this.Cd=null,this.yd=null,this.Pd=null,this.kd=null,this.Td=null,this.Rd=null,this.Dd=0,this.Ed=!1,this.Vd=!1,this.Bd=!1,this.Id=0,this.Ad=null,this.zd=!_s(),this.Od=t=>{this.Ld(t)},this.Nd=t=>{if(this.Fd(t)){const i=this.Wd(t);if(++this.dd,this.fd&&this.dd>1){const{Hd:s}=this.Ud(vs(t),this.pd);s<30&&!this.xd&&this.$d(i,this.qd.jd),this.Yd()}}else{const i=this.Wd(t);if(++this.od,this._d&&this.od>1){const{Hd:s}=this.Ud(vs(t),this.ud);s<5&&!this.bd&&this.Kd(i,this.qd.Xd),this.Zd()}}},this.Gd=t,this.qd=i,this.ys=s,this.Jd()}m(){null!==this.Sd&&(this.Sd(),this.Sd=null),null!==this.Cd&&(this.Cd(),this.Cd=null),null!==this.Pd&&(this.Pd(),this.Pd=null),null!==this.kd&&(this.kd(),this.kd=null),null!==this.Td&&(this.Td(),this.Td=null),null!==this.yd&&(this.yd(),this.yd=null),this.Qd(),this.Zd()}tf(t){this.Pd&&this.Pd();const i=this.if.bind(this);if(this.Pd=()=>{this.Gd.removeEventListener("mousemove",i)},this.Gd.addEventListener("mousemove",i),this.Fd(t))return;const s=this.Wd(t);this.Kd(s,this.qd.sf),this.zd=!0}Zd(){null!==this._d&&clearTimeout(this._d),this.od=0,this._d=null,this.ud={_t:Number.NEGATIVE_INFINITY,ut:Number.POSITIVE_INFINITY}}Yd(){null!==this.fd&&clearTimeout(this.fd),this.dd=0,this.fd=null,this.pd={_t:Number.NEGATIVE_INFINITY,ut:Number.POSITIVE_INFINITY}}if(t){if(this.Bd||null!==this.gd)return;if(this.Fd(t))return;const i=this.Wd(t);this.Kd(i,this.qd.nf),this.zd=!0}ef(t){const i=ws(t.changedTouches,a(this.Ad));if(null===i)return;if(this.Id=ms(t),null!==this.Rd)return;if(this.Vd)return;this.Ed=!0;const s=this.Ud(vs(i),a(this.gd)),{rf:n,hf:e,Hd:r}=s;if(this.Md||!(r<5)){if(!this.Md){const t=.5*n,i=e>=t&&!this.ys.af(),s=t>e&&!this.ys.lf();i||s||(this.Vd=!0),this.Md=!0,this.xd=!0,this.Qd(),this.Yd()}if(!this.Vd){const s=this.Wd(t,i);this.$d(s,this.qd._f),ps(t)}}}uf(t){if(0!==t.button)return;const i=this.Ud(vs(t),a(this.wd)),{Hd:s}=i;if(s>=5&&(this.bd=!0,this.Zd()),this.bd){const i=this.Wd(t);this.Kd(i,this.qd.cf)}}Ud(t,i){const s=Math.abs(i._t-t._t),n=Math.abs(i.ut-t.ut);return{rf:s,hf:n,Hd:s+n}}df(t){let i=ws(t.changedTouches,a(this.Ad));if(null===i&&0===t.touches.length&&(i=t.changedTouches[0]),null===i)return;this.Ad=null,this.Id=ms(t),this.Qd(),this.gd=null,this.Td&&(this.Td(),this.Td=null);const s=this.Wd(t,i);if(this.$d(s,this.qd.ff),++this.dd,this.fd&&this.dd>1){const{Hd:t}=this.Ud(vs(i),this.pd);t<30&&!this.xd&&this.$d(s,this.qd.jd),this.Yd()}else this.xd||(this.$d(s,this.qd.pf),this.qd.pf&&ps(t));0===this.dd&&ps(t),0===t.touches.length&&this.md&&(this.md=!1,ps(t))}Ld(t){if(0!==t.button)return;const i=this.Wd(t);if(this.wd=null,this.Bd=!1,this.kd&&(this.kd(),this.kd=null),os()){this.Gd.ownerDocument.documentElement.removeEventListener("mouseleave",this.Od)}if(!this.Fd(t))if(this.Kd(i,this.qd.vf),++this.od,this._d&&this.od>1){const{Hd:s}=this.Ud(vs(t),this.ud);s<5&&!this.bd&&this.Kd(i,this.qd.Xd),this.Zd()}else this.bd||this.Kd(i,this.qd.mf)}Qd(){null!==this.vd&&(clearTimeout(this.vd),this.vd=null)}wf(t){if(null!==this.Ad)return;const i=t.changedTouches[0];this.Ad=i.identifier,this.Id=ms(t);const s=this.Gd.ownerDocument.documentElement;this.xd=!1,this.Md=!1,this.Vd=!1,this.gd=vs(i),this.Td&&(this.Td(),this.Td=null);{const i=this.ef.bind(this),n=this.df.bind(this);this.Td=()=>{s.removeEventListener("touchmove",i),s.removeEventListener("touchend",n)},s.addEventListener("touchmove",i,{passive:!1}),s.addEventListener("touchend",n,{passive:!1}),this.Qd(),this.vd=setTimeout(this.gf.bind(this,t),240)}const n=this.Wd(t,i);this.$d(n,this.qd.Mf),this.fd||(this.dd=0,this.fd=setTimeout(this.Yd.bind(this),500),this.pd=vs(i))}bf(t){if(0!==t.button)return;const i=this.Gd.ownerDocument.documentElement;os()&&i.addEventListener("mouseleave",this.Od),this.bd=!1,this.wd=vs(t),this.kd&&(this.kd(),this.kd=null);{const t=this.uf.bind(this),s=this.Ld.bind(this);this.kd=()=>{i.removeEventListener("mousemove",t),i.removeEventListener("mouseup",s)},i.addEventListener("mousemove",t),i.addEventListener("mouseup",s)}if(this.Bd=!0,this.Fd(t))return;const s=this.Wd(t);this.Kd(s,this.qd.xf),this._d||(this.od=0,this._d=setTimeout(this.Zd.bind(this),500),this.ud=vs(t))}Jd(){this.Gd.addEventListener("mouseenter",this.tf.bind(this)),this.Gd.addEventListener("touchcancel",this.Qd.bind(this));{const t=this.Gd.ownerDocument,i=t=>{this.qd.Sf&&(t.composed&&this.Gd.contains(t.composedPath()[0])||t.target&&this.Gd.contains(t.target)||this.qd.Sf())};this.Cd=()=>{t.removeEventListener("touchstart",i)},this.Sd=()=>{t.removeEventListener("mousedown",i)},t.addEventListener("mousedown",i),t.addEventListener("touchstart",i,{passive:!0})}_s()&&(this.yd=()=>{this.Gd.removeEventListener("dblclick",this.Nd)},this.Gd.addEventListener("dblclick",this.Nd)),this.Gd.addEventListener("mouseleave",this.Cf.bind(this)),this.Gd.addEventListener("touchstart",this.wf.bind(this),{passive:!0}),cs(this.Gd),this.Gd.addEventListener("mousedown",this.bf.bind(this)),this.yf(),this.Gd.addEventListener("touchmove",(()=>{}),{passive:!1})}yf(){void 0===this.qd.Pf&&void 0===this.qd.kf&&void 0===this.qd.Tf||(this.Gd.addEventListener("touchstart",(t=>this.Rf(t.touches)),{passive:!0}),this.Gd.addEventListener("touchmove",(t=>{if(2===t.touches.length&&null!==this.Rd&&void 0!==this.qd.kf){const i=fs(t.touches[0],t.touches[1])/this.Dd;this.qd.kf(this.Rd,i),ps(t)}}),{passive:!1}),this.Gd.addEventListener("touchend",(t=>{this.Rf(t.touches)})))}Rf(t){1===t.length&&(this.Ed=!1),2!==t.length||this.Ed||this.md?this.Df():this.Ef(t)}Ef(t){const i=this.Gd.getBoundingClientRect()||{left:0,top:0};this.Rd={_t:(t[0].clientX-i.left+(t[1].clientX-i.left))/2,ut:(t[0].clientY-i.top+(t[1].clientY-i.top))/2},this.Dd=fs(t[0],t[1]),void 0!==this.qd.Pf&&this.qd.Pf(),this.Qd()}Df(){null!==this.Rd&&(this.Rd=null,void 0!==this.qd.Tf&&this.qd.Tf())}Cf(t){if(this.Pd&&this.Pd(),this.Fd(t))return;if(!this.zd)return;const i=this.Wd(t);this.Kd(i,this.qd.Vf),this.zd=!_s()}gf(t){const i=ws(t.touches,a(this.Ad));if(null===i)return;const s=this.Wd(t,i);this.$d(s,this.qd.Bf),this.xd=!0,this.md=!0}Fd(t){return t.sourceCapabilities&&void 0!==t.sourceCapabilities.firesTouchEvents?t.sourceCapabilities.firesTouchEvents:ms(t){"touchstart"!==t.type&&ps(t)}}}}function fs(t,i){const s=t.clientX-i.clientX,n=t.clientY-i.clientY;return Math.sqrt(s*s+n*n)}function ps(t){t.cancelable&&t.preventDefault()}function vs(t){return{_t:t.pageX,ut:t.pageY}}function ms(t){return t.timeStamp||performance.now()}function ws(t,i){for(let s=0;s!1,lf:()=>!0}),this.Lf={ip:s,tp:t}}Kf(){this.Yf.style.background=this.Hf.N().layout.panes.separatorColor}sp(t){null!==this.Lf&&(this.Lf.ip.style.backgroundColor=this.Hf.N().layout.panes.separatorHoverColor)}np(t){null!==this.Lf&&null===this.Wf&&(this.Lf.ip.style.backgroundColor="")}ep(t){if(null===this.Lf)return;const i=this.Uf.ap().Vo()+this.jf.ap().Vo(),s=i/(this.Uf.Gf().height+this.jf.Gf().height),n=30*s;i<=2*n||(this.Wf={lp:t.pageY,op:this.Uf.ap().Vo(),_p:i-n,up:i,cp:s,dp:n},this.Lf.tp.style.display="block")}rp(t){const i=this.Wf;if(null===i)return;const s=(t.pageY-i.lp)*i.cp,n=Kt(i.op+s,i.dp,i._p);this.Uf.ap().Bo(n),this.jf.ap().Bo(i.up-n),this.Hf.Qt().Bh()}hp(t){null!==this.Wf&&null!==this.Lf&&(this.Wf=null,this.Lf.tp.style.display="none")}}function Ms(t,i){return t.fp-i.fp}function bs(t,i,s){const n=(t.fp-i.fp)/(t.wt-i.wt);return Math.sign(n)*Math.min(Math.abs(n),s)}class xs{constructor(t,i,s,n){this.pp=null,this.vp=null,this.mp=null,this.wp=null,this.gp=null,this.Mp=0,this.bp=0,this.xp=t,this.Sp=i,this.Cp=s,this.Mn=n}yp(t,i){if(null!==this.pp){if(this.pp.wt===i)return void(this.pp.fp=t);if(Math.abs(this.pp.fp-t)50)return;let s=0;const n=bs(this.pp,this.vp,this.Sp),e=Ms(this.pp,this.vp),r=[n],h=[e];if(s+=e,null!==this.mp){const t=bs(this.vp,this.mp,this.Sp);if(Math.sign(t)===Math.sign(n)){const i=Ms(this.vp,this.mp);if(r.push(t),h.push(i),s+=i,null!==this.wp){const t=bs(this.mp,this.wp,this.Sp);if(Math.sign(t)===Math.sign(n)){const i=Ms(this.mp,this.wp);r.push(t),h.push(i),s+=i}}}}let a=0;for(let t=0;t160?"dark":"light"}Ap(){return this.Ep.N().layout.attributionLogo}Op(){const t=new URL(location.href);return t.hostname?"&utm_source="+t.hostname+t.pathname:""}Vp(){this.Ip()&&(this.Bp(),this.ps=this.Ap(),this.ps&&(this.Rp=this.zp(),this.Tp=document.createElement("style"),this.Tp.innerText="a#tv-attr-logo{--fill:#131722;--stroke:#fff;position:absolute;left:10px;bottom:10px;height:19px;width:35px;margin:0;padding:0;border:0;z-index:3;}a#tv-attr-logo[data-dark]{--fill:#D1D4DC;--stroke:#131722;}",this.kp=document.createElement("a"),this.kp.href=`https://www.tradingview.com/?utm_medium=lwc-link&utm_campaign=lwc-chart${this.Op()}`,this.kp.title="Charting by TradingView",this.kp.id="tv-attr-logo",this.kp.target="_blank",this.kp.innerHTML='',this.kp.toggleAttribute("data-dark","dark"===this.Rp),this.Dp.appendChild(this.Tp),this.Dp.appendChild(this.kp)))}}function Cs(t,i){const s=a(t.ownerDocument).createElement("canvas");t.appendChild(s);const n=new es(s,(e={options:{allowResizeObserver:!0},transform:(t,i)=>({width:Math.max(t.width,i.width),height:Math.max(t.height,i.height)})}).transform,e.options);var e;return n.resizeCanvasElement(i),n}function ys(t){t.width=1,t.height=1,t.getContext("2d")?.clearRect(0,0,1,1)}function Ps(t,i,s,n){t.ih&&t.ih(i,s,n)}function ks(t,i,s,n){t.nt(i,s,n)}function Ts(t,i,s,n){const e=t(s,n);for(const t of e){const s=t.Tt(n);null!==s&&i(s)}}function Rs(t,i){return s=>{if(!function(t){return void 0!==t.Ft}(s))return[];return(s.Ft()?.ma()??"")!==i?[]:s.ta?.(t)??[]}}function Ds(t,i,s,n){if(!t.length)return;let e=0;const r=t[0].$t(n,!0);let h=1===i?s/2-(t[0].Fi()-r/2):t[0].Fi()-r/2-s/2;h=Math.max(0,h);for(let r=1;ru-o:_s)&&h>0){const n=1===i?-1-r:r-s,a=Math.min(n,h);for(let s=e;s{this.Up||this.yt.jp().Qt().ar()},this.qp=()=>{this.Up||this.yt.jp().Qt().ar()},this.yt=t,this.ys=i,this.Ml=i.layout,this.Ju=s,this.Yp="left"===n,this.Kp=Rs("normal",n),this.Xp=Rs("top",n),this.Zp=Rs("bottom",n),this.Yf=document.createElement("div"),this.Yf.style.height="100%",this.Yf.style.overflow="hidden",this.Yf.style.width="25px",this.Yf.style.left="0",this.Yf.style.position="relative",this.Gp=Cs(this.Yf,is({width:16,height:16})),this.Gp.subscribeSuggestedBitmapSizeChanged(this.$p);const e=this.Gp.canvasElement;e.style.position="absolute",e.style.zIndex="1",e.style.left="0",e.style.top="0",this.Jp=Cs(this.Yf,is({width:16,height:16})),this.Jp.subscribeSuggestedBitmapSizeChanged(this.qp);const r=this.Jp.canvasElement;r.style.position="absolute",r.style.zIndex="2",r.style.left="0",r.style.top="0";const h={xf:this.ep.bind(this),Mf:this.ep.bind(this),cf:this.rp.bind(this),_f:this.rp.bind(this),Sf:this.Qp.bind(this),vf:this.hp.bind(this),ff:this.hp.bind(this),Xd:this.tv.bind(this),jd:this.tv.bind(this),sf:this.iv.bind(this),Vf:this.np.bind(this)};this.Nf=new ds(this.Jp.canvasElement,h,{af:()=>!this.ys.handleScroll.vertTouchDrag,lf:()=>!0})}m(){this.Nf.m(),this.Jp.unsubscribeSuggestedBitmapSizeChanged(this.qp),ys(this.Jp.canvasElement),this.Jp.dispose(),this.Gp.unsubscribeSuggestedBitmapSizeChanged(this.$p),ys(this.Gp.canvasElement),this.Gp.dispose(),null!==this.qi&&this.qi.so().u(this),this.qi=null}Zf(){return this.Yf}P(){return this.Ml.fontSize}sv(){const t=this.Ju.N();return this.Wp!==t.k&&(this.Fp.Vn(),this.Wp=t.k),t}nv(){if(null===this.qi)return 0;let t=0;const i=this.sv(),s=a(this.Gp.canvasElement.getContext("2d",{colorSpace:this.yt.jp().N().layout.colorSpace}));s.save();const n=this.qi.Da();s.font=this.ev(),n.length>0&&(t=Math.max(this.Fp.Ei(s,n[0].Za),this.Fp.Ei(s,n[n.length-1].Za)));const e=this.rv();for(let i=e.length;i--;){const n=this.Fp.Ei(s,e[i].ri());n>t&&(t=n)}const r=this.qi.zt();if(null!==r&&null!==this.Lp&&(2!==(h=this.ys.crosshair).mode&&h.horzLine.visible&&h.horzLine.labelVisible)){const i=this.qi.Ts(1,r),n=this.qi.Ts(this.Lp.height-2,r);t=Math.max(t,this.Fp.Ei(s,this.qi.Zi(Math.floor(Math.min(i,n))+.11111111111111,r)),this.Fp.Ei(s,this.qi.Zi(Math.ceil(Math.max(i,n))-.11111111111111,r)))}var h;s.restore();const l=t||34;return us(Math.ceil(i.S+i.C+i.B+i.I+5+l))}hv(t){null!==this.Lp&&ss(this.Lp,t)||(this.Lp=t,this.Up=!0,this.Gp.resizeCanvasElement(t),this.Jp.resizeCanvasElement(t),this.Up=!1,this.Yf.style.width=`${t.width}px`,this.Yf.style.height=`${t.height}px`)}av(){return a(this.Lp).width}_s(t){this.qi!==t&&(null!==this.qi&&this.qi.so().u(this),this.qi=t,t.so().i(this._l.bind(this),this))}Ft(){return this.qi}Vn(){const t=this.yt.ap();this.yt.jp().Qt().Zo(t,a(this.Ft()))}lv(t){if(null===this.Lp)return;const i={colorSpace:this.yt.jp().N().layout.colorSpace};if(1!==t){this.ov(),this.Gp.applySuggestedBitmapSize();const t=as(this.Gp,i);null!==t&&(t.useBitmapCoordinateSpace((t=>{this._v(t),this.uv(t)})),this.yt.cv(t,this.Zp),this.dv(t),this.yt.cv(t,this.Kp),this.fv(t))}this.Jp.applySuggestedBitmapSize();const s=as(this.Jp,i);null!==s&&(s.useBitmapCoordinateSpace((({context:t,bitmapSize:i})=>{t.clearRect(0,0,i.width,i.height)})),this.pv(s),this.yt.cv(s,this.Xp))}Jf(){return this.Gp.bitmapSize}Qf(t,i,s,n){const e=this.Jf();if(e.width>0&&e.height>0&&(t.drawImage(this.Gp.canvasElement,i,s),n)){const n=this.Jp.canvasElement;t.drawImage(n,i,s)}}Pt(){this.qi?.Da()}ep(t){if(null===this.qi||this.qi.Ki()||!this.ys.handleScale.axisPressedMouseMove.price)return;const i=this.yt.jp().Qt(),s=this.yt.ap();this.Np=!0,i.Uo(s,this.qi,t.localY)}rp(t){if(null===this.qi||!this.ys.handleScale.axisPressedMouseMove.price)return;const i=this.yt.jp().Qt(),s=this.yt.ap(),n=this.qi;i.$o(s,n,t.localY)}Qp(){if(null===this.qi||!this.ys.handleScale.axisPressedMouseMove.price)return;const t=this.yt.jp().Qt(),i=this.yt.ap(),s=this.qi;this.Np&&(this.Np=!1,t.jo(i,s))}hp(t){if(null===this.qi||!this.ys.handleScale.axisPressedMouseMove.price)return;const i=this.yt.jp().Qt(),s=this.yt.ap();this.Np=!1,i.jo(s,this.qi)}tv(t){this.ys.handleScale.axisDoubleClickReset.price&&this.Vn()}iv(t){if(null===this.qi)return;!this.yt.jp().Qt().N().handleScale.axisPressedMouseMove.price||this.qi.Oe()||this.qi.Dl()||this.vv(1)}np(t){this.vv(0)}rv(){const t=[],i=null===this.qi?void 0:this.qi;return(s=>{for(let n=0;n{t.fillStyle=s.borderColor;const a=Math.max(1,Math.floor(h)),l=Math.floor(.5*h),o=Math.round(n.C*r);t.beginPath();for(const s of i)t.rect(Math.floor(e*r),Math.round(s.ya*h)-l,o,a);t.fill()})),t.useMediaCoordinateSpace((({context:t})=>{t.font=this.ev(),t.fillStyle=s.textColor??this.Ml.textColor,t.textAlign=this.Yp?"right":"left",t.textBaseline="middle";const r=this.Yp?Math.round(e-n.B):Math.round(e+n.C+n.B),h=i.map((i=>this.Fp.Di(t,i.Za)));for(let s=i.length;s--;){const n=i[s];t.fillText(n.Za,r,n.ya+h[s])}}))}ov(){if(null===this.Lp||null===this.qi)return;let t=this.Lp.height/2;const i=[],s=this.qi.Dt().slice(),n=this.yt.ap(),e=this.sv();this.qi===n.$n()&&this.yt.ap().Dt().forEach((t=>{n.Un(t)&&s.push(t)}));const r=this.qi.Ma()[0],h=this.qi;s.forEach((s=>{const e=s.Ws(n,h);e.forEach((t=>{t.Wi(null),t.Hi()&&i.push(t)})),r===s&&e.length>0&&(t=e[0].Bi())})),i.forEach((t=>t.Wi(t.Bi())));this.qi.N().alignLabels&&this.mv(i,e,t)}mv(t,i,s){if(null===this.Lp)return;const n=t.filter((t=>t.Bi()<=s)),e=t.filter((t=>t.Bi()>s));n.sort(((t,i)=>i.Bi()-t.Bi())),n.length&&e.length&&e.push(n[0]),e.sort(((t,i)=>t.Bi()-i.Bi()));for(const s of t){const t=Math.floor(s.$t(i)/2),n=s.Bi();n>-t&&nthis.Lp.height-t&&n{if(i.Ui()){i.Tt(a(this.qi)).nt(t,s,this.Fp,n)}}))}pv(t){if(null===this.Lp||null===this.qi)return;const i=this.yt.jp().Qt(),s=[],n=this.yt.ap(),e=i.uc().Ws(n,this.qi);e.length&&s.push(e);const r=this.sv(),h=this.Yp?"right":"left";s.forEach((i=>{i.forEach((i=>{i.Tt(a(this.qi)).nt(t,r,this.Fp,h)}))}))}vv(t){this.Yf.style.cursor=1===t?"ns-resize":"default"}_l(){const t=this.nv();this.Hp{this.Up||null===this.Ev||this.ts().ar()},this.qp=()=>{this.Up||null===this.Ev||this.ts().ar()},this.Ep=t,this.Ev=i,this.Ev.t_().i(this.Vv.bind(this),this,!0),this.Bv=document.createElement("td"),this.Bv.style.padding="0",this.Bv.style.position="relative";const s=document.createElement("div");s.style.width="100%",s.style.height="100%",s.style.position="relative",s.style.overflow="hidden",this.Iv=document.createElement("td"),this.Iv.style.padding="0",this.Av=document.createElement("td"),this.Av.style.padding="0",this.Bv.appendChild(s),this.Gp=Cs(s,is({width:16,height:16})),this.Gp.subscribeSuggestedBitmapSizeChanged(this.$p);const n=this.Gp.canvasElement;n.style.position="absolute",n.style.zIndex="1",n.style.left="0",n.style.top="0",this.Jp=Cs(s,is({width:16,height:16})),this.Jp.subscribeSuggestedBitmapSizeChanged(this.qp);const e=this.Jp.canvasElement;e.style.position="absolute",e.style.zIndex="2",e.style.left="0",e.style.top="0",this.qf=document.createElement("tr"),this.qf.appendChild(this.Iv),this.qf.appendChild(this.Bv),this.qf.appendChild(this.Av),this.zv(),this.Nf=new ds(this.Jp.canvasElement,this,{af:()=>null===this.kv&&!this.Ep.N().handleScroll.vertTouchDrag,lf:()=>null===this.kv&&!this.Ep.N().handleScroll.horzTouchDrag})}m(){null!==this.wv&&this.wv.m(),null!==this.gv&&this.gv.m(),this.Mv=null,this.Jp.unsubscribeSuggestedBitmapSizeChanged(this.qp),ys(this.Jp.canvasElement),this.Jp.dispose(),this.Gp.unsubscribeSuggestedBitmapSizeChanged(this.$p),ys(this.Gp.canvasElement),this.Gp.dispose(),null!==this.Ev&&(this.Ev.t_().u(this),this.Ev.m()),this.Nf.m()}ap(){return a(this.Ev)}Ov(t){null!==this.Ev&&this.Ev.t_().u(this),this.Ev=t,null!==this.Ev&&this.Ev.t_().i(zs.prototype.Vv.bind(this),this,!0),this.zv(),this.Ep.$f().indexOf(this)===this.Ep.$f().length-1?(this.Mv=this.Mv??new Ss(this.Bv,this.Ep),this.Mv.Pt()):(this.Mv?.Bp(),this.Mv=null)}jp(){return this.Ep}Zf(){return this.qf}zv(){if(null!==this.Ev&&(this.Lv(),0!==this.ts().Ys().length)){if(null!==this.wv){const t=this.Ev.Wo();this.wv._s(a(t))}if(null!==this.gv){const t=this.Ev.Ho();this.gv._s(a(t))}}}Nv(){null!==this.wv&&this.wv.Pt(),null!==this.gv&&this.gv.Pt()}Vo(){return null!==this.Ev?this.Ev.Vo():0}Bo(t){this.Ev&&this.Ev.Bo(t)}sf(t){if(!this.Ev)return;this.Fv();const i=t.localX,s=t.localY;this.Wv(i,s,t)}xf(t){this.Fv(),this.Hv(),this.Wv(t.localX,t.localY,t)}nf(t){if(!this.Ev)return;this.Fv();const i=t.localX,s=t.localY;this.Wv(i,s,t)}mf(t){null!==this.Ev&&(this.Fv(),this.Uv(t))}Xd(t){null!==this.Ev&&this.$v(this.Cv,t)}jd(t){this.Xd(t)}cf(t){this.Fv(),this.jv(t),this.Wv(t.localX,t.localY,t)}vf(t){null!==this.Ev&&(this.Fv(),this.Pv=!1,this.qv(t))}pf(t){null!==this.Ev&&this.Uv(t)}Bf(t){if(this.Pv=!0,null===this.kv){const i={x:t.localX,y:t.localY};this.Yv(i,i,t)}}Vf(t){null!==this.Ev&&(this.Fv(),this.Ev.Qt().lc(null),this.Kv())}Xv(){return this.Sv}Zv(){return this.Cv}Pf(){this.yv=1,this.ts().hn()}kf(t,i){if(!this.Ep.N().handleScale.pinch)return;const s=5*(i-this.yv);this.yv=i,this.ts().bc(t._t,s)}Mf(t){this.Pv=!1,this.Tv=null!==this.kv,this.Hv();const i=this.ts().uc();null!==this.kv&&i.Et()&&(this.Rv={x:i.si(),y:i.ni()},this.kv={x:t.localX,y:t.localY})}_f(t){if(null===this.Ev)return;const i=t.localX,s=t.localY;if(null===this.kv)this.jv(t);else{this.Tv=!1;const n=a(this.Rv),e=n.x+(i-this.kv.x),r=n.y+(s-this.kv.y);this.Wv(e,r,t)}}ff(t){0===this.jp().N().trackingMode.exitMode&&(this.Tv=!0),this.Gv(),this.qv(t)}Yn(t,i){const s=this.Ev;return null===s?null:xi(s,t,i)}Jv(t,i){a("left"===i?this.wv:this.gv).hv(is({width:t,height:this.Lp.height}))}Gf(){return this.Lp}hv(t){ss(this.Lp,t)||(this.Lp=t,this.Up=!0,this.Gp.resizeCanvasElement(t),this.Jp.resizeCanvasElement(t),this.Up=!1,this.Bv.style.width=t.width+"px",this.Bv.style.height=t.height+"px")}Qv(){const t=a(this.Ev);t.Fo(t.Wo()),t.Fo(t.Ho());for(const i of t.Ma())if(t.Un(i)){const s=i.Ft();null!==s&&t.Fo(s),i.Ns()}for(const i of t.s_())i.Ns()}Jf(){return this.Gp.bitmapSize}Qf(t,i,s,n){const e=this.Jf();if(e.width>0&&e.height>0&&(t.drawImage(this.Gp.canvasElement,i,s),n)){const n=this.Jp.canvasElement;null!==t&&t.drawImage(n,i,s)}}lv(t){if(0===t)return;if(null===this.Ev)return;t>1&&this.Qv(),null!==this.wv&&this.wv.lv(t),null!==this.gv&&this.gv.lv(t);const i={colorSpace:this.Ep.N().layout.colorSpace};if(1!==t){this.Gp.applySuggestedBitmapSize();const t=as(this.Gp,i);null!==t&&(t.useBitmapCoordinateSpace((t=>{this._v(t)})),this.Ev&&(this.tm(t,Vs),this.im(t),this.tm(t,Bs),this.tm(t,Is)))}this.Jp.applySuggestedBitmapSize();const s=as(this.Jp,i);null!==s&&(s.useBitmapCoordinateSpace((({context:t,bitmapSize:i})=>{t.clearRect(0,0,i.width,i.height)})),this.sm(s),this.tm(s,As),this.tm(s,Is))}nm(){return this.wv}rm(){return this.gv}cv(t,i){this.tm(t,i)}Vv(){null!==this.Ev&&this.Ev.t_().u(this),this.Ev=null}Uv(t){this.$v(this.Sv,t)}$v(t,i){const s=i.localX,n=i.localY;t.v()&&t.p(this.ts().It().cu(s),{x:s,y:n},i)}_v({context:t,bitmapSize:i}){const{width:s,height:n}=i,e=this.ts(),r=e.$(),h=e.Wc();r===h?B(t,0,0,s,n,h):z(t,0,0,s,n,r,h)}im(t){const i=a(this.Ev),s=i.i_().lr().Tt(i);null!==s&&s.nt(t,!1)}sm(t){this.hm(t,Bs,ks,this.ts().uc())}tm(t,i){const s=a(this.Ev),n=s.Dt(),e=s.s_();for(const s of e)this.hm(t,i,Ps,s);for(const s of n)this.hm(t,i,Ps,s);for(const s of e)this.hm(t,i,ks,s);for(const s of n)this.hm(t,i,ks,s)}hm(t,i,s,n){const e=a(this.Ev),r=e.Qt().ac(),h=null!==r&&r.n_===n,l=null!==r&&h&&void 0!==r.e_?r.e_.Xn:void 0;Ts(i,(i=>s(i,t,h,l)),n,e)}Lv(){if(null===this.Ev)return;const t=this.Ep,i=this.Ev.Wo().N().visible,s=this.Ev.Ho().N().visible;i||null===this.wv||(this.Iv.removeChild(this.wv.Zf()),this.wv.m(),this.wv=null),s||null===this.gv||(this.Av.removeChild(this.gv.Zf()),this.gv.m(),this.gv=null);const n=t.Qt().Vc();i&&null===this.wv&&(this.wv=new Es(this,t.N(),n,"left"),this.Iv.appendChild(this.wv.Zf())),s&&null===this.gv&&(this.gv=new Es(this,t.N(),n,"right"),this.Av.appendChild(this.gv.Zf()))}am(t){return t.If&&this.Pv||null!==this.kv}lm(t){return Math.max(0,Math.min(t,this.Lp.width-1))}om(t){return Math.max(0,Math.min(t,this.Lp.height-1))}Wv(t,i,s){this.ts().Tc(this.lm(t),this.om(i),s,a(this.Ev))}Kv(){this.ts().Dc()}Gv(){this.Tv&&(this.kv=null,this.Kv())}Yv(t,i,s){this.kv=t,this.Tv=!1,this.Wv(i.x,i.y,s);const n=this.ts().uc();this.Rv={x:n.si(),y:n.ni()}}ts(){return this.Ep.Qt()}qv(t){if(!this.xv)return;const i=this.ts(),s=this.ap();if(i.Ko(s,s.ks()),this.bv=null,this.xv=!1,i.yc(),null!==this.Dv){const t=performance.now(),s=i.It();this.Dv.le(s.gu(),t),this.Dv.Ru(t)||i._n(this.Dv)}}Fv(){this.kv=null}Hv(){if(!this.Ev)return;if(this.ts().hn(),document.activeElement!==document.body&&document.activeElement!==document.documentElement)a(document.activeElement).blur();else{const t=document.getSelection();null!==t&&t.removeAllRanges()}!this.Ev.ks().Ki()&&this.ts().It().Ki()}jv(t){if(null===this.Ev)return;const i=this.ts(),s=i.It();if(s.Ki())return;const n=this.Ep.N(),e=n.handleScroll,r=n.kineticScroll;if((!e.pressedMouseMove||t.If)&&(!e.horzTouchDrag&&!e.vertTouchDrag||!t.If))return;const h=this.Ev.ks(),a=performance.now();if(null!==this.bv||this.am(t)||(this.bv={x:t.clientX,y:t.clientY,rd:a,_m:t.localX,um:t.localY}),null!==this.bv&&!this.xv&&(this.bv.x!==t.clientX||this.bv.y!==t.clientY)){if(t.If&&r.touch||!t.If&&r.mouse){const t=s.mu();this.Dv=new xs(.2/t,7/t,.997,15/t),this.Dv.yp(s.gu(),this.bv.rd)}else this.Dv=null;h.Ki()||i.qo(this.Ev,h,t.localY),i.Sc(t.localX),this.xv=!0}this.xv&&(h.Ki()||i.Yo(this.Ev,h,t.localY),i.Cc(t.localX),null!==this.Dv&&this.Dv.yp(s.gu(),a))}}class Os{constructor(t,i,s,n,e){this.St=!0,this.Lp=is({width:0,height:0}),this.$p=()=>this.lv(3),this.Yp="left"===t,this.Ju=s.Vc,this.ys=i,this.dm=n,this.fm=e,this.Yf=document.createElement("div"),this.Yf.style.width="25px",this.Yf.style.height="100%",this.Yf.style.overflow="hidden",this.Gp=Cs(this.Yf,is({width:16,height:16})),this.Gp.subscribeSuggestedBitmapSizeChanged(this.$p)}m(){this.Gp.unsubscribeSuggestedBitmapSizeChanged(this.$p),ys(this.Gp.canvasElement),this.Gp.dispose()}Zf(){return this.Yf}Gf(){return this.Lp}hv(t){ss(this.Lp,t)||(this.Lp=t,this.Gp.resizeCanvasElement(t),this.Yf.style.width=`${t.width}px`,this.Yf.style.height=`${t.height}px`,this.St=!0)}lv(t){if(t<3&&!this.St)return;if(0===this.Lp.width||0===this.Lp.height)return;this.St=!1,this.Gp.applySuggestedBitmapSize();const i=as(this.Gp,{colorSpace:this.ys.layout.colorSpace});null!==i&&i.useBitmapCoordinateSpace((t=>{this._v(t),this.uv(t)}))}Jf(){return this.Gp.bitmapSize}Qf(t,i,s){const n=this.Jf();n.width>0&&n.height>0&&t.drawImage(this.Gp.canvasElement,i,s)}uv({context:t,bitmapSize:i,horizontalPixelRatio:s,verticalPixelRatio:n}){if(!this.dm())return;t.fillStyle=this.ys.timeScale.borderColor;const e=Math.floor(this.Ju.N().S*s),r=Math.floor(this.Ju.N().S*n),h=this.Yp?i.width-e:0;t.fillRect(h,0,e,r)}_v({context:t,bitmapSize:i}){B(t,0,0,i.width,i.height,this.fm())}}function Ls(t){return i=>i.ia?.(t)??[]}const Ns=Ls("normal"),Fs=Ls("top"),Ws=Ls("bottom");class Hs{constructor(t,i){this.pm=null,this.vm=null,this.M=null,this.wm=!1,this.Lp=is({width:0,height:0}),this.gm=new o,this.Fp=new it(5),this.Up=!1,this.$p=()=>{this.Up||this.Ep.Qt().ar()},this.qp=()=>{this.Up||this.Ep.Qt().ar()},this.Ep=t,this.o_=i,this.ys=t.N().layout,this.kp=document.createElement("tr"),this.Mm=document.createElement("td"),this.Mm.style.padding="0",this.bm=document.createElement("td"),this.bm.style.padding="0",this.Yf=document.createElement("td"),this.Yf.style.height="25px",this.Yf.style.padding="0",this.xm=document.createElement("div"),this.xm.style.width="100%",this.xm.style.height="100%",this.xm.style.position="relative",this.xm.style.overflow="hidden",this.Yf.appendChild(this.xm),this.Gp=Cs(this.xm,is({width:16,height:16})),this.Gp.subscribeSuggestedBitmapSizeChanged(this.$p);const s=this.Gp.canvasElement;s.style.position="absolute",s.style.zIndex="1",s.style.left="0",s.style.top="0",this.Jp=Cs(this.xm,is({width:16,height:16})),this.Jp.subscribeSuggestedBitmapSizeChanged(this.qp);const n=this.Jp.canvasElement;n.style.position="absolute",n.style.zIndex="2",n.style.left="0",n.style.top="0",this.kp.appendChild(this.Mm),this.kp.appendChild(this.Yf),this.kp.appendChild(this.bm),this.Sm(),this.Ep.Qt().Eo().i(this.Sm.bind(this),this),this.Nf=new ds(this.Jp.canvasElement,this,{af:()=>!0,lf:()=>!this.Ep.N().handleScroll.horzTouchDrag})}m(){this.Nf.m(),null!==this.pm&&this.pm.m(),null!==this.vm&&this.vm.m(),this.Jp.unsubscribeSuggestedBitmapSizeChanged(this.qp),ys(this.Jp.canvasElement),this.Jp.dispose(),this.Gp.unsubscribeSuggestedBitmapSizeChanged(this.$p),ys(this.Gp.canvasElement),this.Gp.dispose()}Zf(){return this.kp}Cm(){return this.pm}ym(){return this.vm}xf(t){if(this.wm)return;this.wm=!0;const i=this.Ep.Qt();!i.It().Ki()&&this.Ep.N().handleScale.axisPressedMouseMove.time&&i.Mc(t.localX)}Mf(t){this.xf(t)}Sf(){const t=this.Ep.Qt();!t.It().Ki()&&this.wm&&(this.wm=!1,this.Ep.N().handleScale.axisPressedMouseMove.time&&t.kc())}cf(t){const i=this.Ep.Qt();!i.It().Ki()&&this.Ep.N().handleScale.axisPressedMouseMove.time&&i.Pc(t.localX)}_f(t){this.cf(t)}vf(){this.wm=!1;const t=this.Ep.Qt();t.It().Ki()&&!this.Ep.N().handleScale.axisPressedMouseMove.time||t.kc()}ff(){this.vf()}Xd(){this.Ep.N().handleScale.axisDoubleClickReset.time&&this.Ep.Qt().cn()}jd(){this.Xd()}sf(){this.Ep.Qt().N().handleScale.axisPressedMouseMove.time&&this.vv(1)}Vf(){this.vv(0)}Gf(){return this.Lp}Pm(){return this.gm}km(t,i,s){ss(this.Lp,t)||(this.Lp=t,this.Up=!0,this.Gp.resizeCanvasElement(t),this.Jp.resizeCanvasElement(t),this.Up=!1,this.Yf.style.width=`${t.width}px`,this.Yf.style.height=`${t.height}px`,this.gm.p(t)),null!==this.pm&&this.pm.hv(is({width:i,height:t.height})),null!==this.vm&&this.vm.hv(is({width:s,height:t.height}))}Tm(){const t=this.Rm();return Math.ceil(t.S+t.C+t.P+t.A+t.V+t.Dm)}Pt(){this.Ep.Qt().It().Da()}Jf(){return this.Gp.bitmapSize}Qf(t,i,s,n){const e=this.Jf();if(e.width>0&&e.height>0&&(t.drawImage(this.Gp.canvasElement,i,s),n)){const n=this.Jp.canvasElement;t.drawImage(n,i,s)}}lv(t){if(0===t)return;const i={colorSpace:this.ys.colorSpace};if(1!==t){this.Gp.applySuggestedBitmapSize();const s=as(this.Gp,i);null!==s&&(s.useBitmapCoordinateSpace((t=>{this._v(t),this.uv(t),this.Em(s,Ws)})),this.dv(s),this.Em(s,Ns)),null!==this.pm&&this.pm.lv(t),null!==this.vm&&this.vm.lv(t)}this.Jp.applySuggestedBitmapSize();const s=as(this.Jp,i);null!==s&&(s.useBitmapCoordinateSpace((({context:t,bitmapSize:i})=>{t.clearRect(0,0,i.width,i.height)})),this.Vm([...this.Ep.Qt().Ys(),this.Ep.Qt().uc()],s),this.Em(s,Fs))}Em(t,i){const s=this.Ep.Qt().Ys();for(const n of s)Ts(i,(i=>Ps(i,t,!1,void 0)),n,void 0);for(const n of s)Ts(i,(i=>ks(i,t,!1,void 0)),n,void 0)}_v({context:t,bitmapSize:i}){B(t,0,0,i.width,i.height,this.Ep.Qt().Wc())}uv({context:t,bitmapSize:i,verticalPixelRatio:s}){if(this.Ep.N().timeScale.borderVisible){t.fillStyle=this.Bm();const n=Math.max(1,Math.floor(this.Rm().S*s));t.fillRect(0,0,i.width,n)}}dv(t){const i=this.Ep.Qt().It(),s=i.Da();if(!s||0===s.length)return;const n=this.o_.maxTickMarkWeight(s),e=this.Rm(),r=i.N();r.borderVisible&&r.ticksVisible&&t.useBitmapCoordinateSpace((({context:t,horizontalPixelRatio:i,verticalPixelRatio:n})=>{t.strokeStyle=this.Bm(),t.fillStyle=this.Bm();const r=Math.max(1,Math.floor(i)),h=Math.floor(.5*i);t.beginPath();const a=Math.round(e.C*n);for(let n=s.length;n--;){const e=Math.round(s[n].coord*i);t.rect(e-h,0,r,a)}t.fill()})),t.useMediaCoordinateSpace((({context:t})=>{const i=e.S+e.C+e.A+e.P/2;t.textAlign="center",t.textBaseline="middle",t.fillStyle=this.H(),t.font=this.ev();for(const e of s)if(e.weight=n){const s=e.needAlignCoordinate?this.Im(t,e.coord,e.label):e.coord;t.fillText(e.label,s,i)}}))}Im(t,i,s){const n=this.Fp.Ei(t,s),e=n/2,r=Math.floor(i-e)+.5;return r<0?i+=Math.abs(0-r):r+n>this.Lp.width&&(i-=Math.abs(this.Lp.width-(r+n))),i}Vm(t,i){const s=this.Rm();for(const n of t)for(const t of n.cs())t.Tt().nt(i,s)}Bm(){return this.Ep.N().timeScale.borderColor}H(){return this.ys.textColor}F(){return this.ys.fontSize}ev(){return g(this.F(),this.ys.fontFamily)}Am(){return g(this.F(),this.ys.fontFamily,"bold")}Rm(){null===this.M&&(this.M={S:1,O:NaN,A:NaN,V:NaN,Ji:NaN,C:5,P:NaN,k:"",Gi:new it,Dm:0});const t=this.M,i=this.ev();if(t.k!==i){const s=this.F();t.P=s,t.k=i,t.A=3*s/12,t.V=3*s/12,t.Ji=9*s/12,t.O=0,t.Dm=4*s/12,t.Gi.Vn()}return this.M}vv(t){this.Yf.style.cursor=1===t?"ew-resize":"default"}Sm(){const t=this.Ep.Qt(),i=t.N();i.leftPriceScale.visible||null===this.pm||(this.Mm.removeChild(this.pm.Zf()),this.pm.m(),this.pm=null),i.rightPriceScale.visible||null===this.vm||(this.bm.removeChild(this.vm.Zf()),this.vm.m(),this.vm=null);const s={Vc:this.Ep.Qt().Vc()},n=()=>i.leftPriceScale.borderVisible&&t.It().N().borderVisible,e=()=>t.Wc();i.leftPriceScale.visible&&null===this.pm&&(this.pm=new Os("left",i,s,n,e),this.Mm.appendChild(this.pm.Zf())),i.rightPriceScale.visible&&null===this.vm&&(this.vm=new Os("right",i,s,n,e),this.bm.appendChild(this.vm.Zf()))}}const Us=!!ls&&!!navigator.userAgentData&&navigator.userAgentData.brands.some((t=>t.brand.includes("Chromium")))&&!!ls&&(navigator?.userAgentData?.platform?"Windows"===navigator.userAgentData.platform:navigator.userAgent.toLowerCase().indexOf("win")>=0);class $s{constructor(t,i,s){var n;this.zm=[],this.Om=[],this.Lm=0,this.il=0,this.Mo=0,this.Nm=0,this.Fm=0,this.Wm=null,this.Hm=!1,this.Sv=new o,this.Cv=new o,this.Xu=new o,this.Um=null,this.$m=null,this.Dp=t,this.ys=i,this.o_=s,this.kp=document.createElement("div"),this.kp.classList.add("tv-lightweight-charts"),this.kp.style.overflow="hidden",this.kp.style.direction="ltr",this.kp.style.width="100%",this.kp.style.height="100%",(n=this.kp).style.userSelect="none",n.style.webkitUserSelect="none",n.style.msUserSelect="none",n.style.MozUserSelect="none",n.style.webkitTapHighlightColor="transparent",this.jm=document.createElement("table"),this.jm.setAttribute("cellspacing","0"),this.kp.appendChild(this.jm),this.qm=this.Ym.bind(this),js(this.ys)&&this.Km(!0),this.ts=new Ai(this.Gu.bind(this),this.ys,s),this.Qt().cc().i(this.Xm.bind(this),this),this.Zm=new Hs(this,this.o_),this.jm.appendChild(this.Zm.Zf());const e=i.autoSize&&this.Gm();let r=this.ys.width,h=this.ys.height;if(e||0===r||0===h){const i=t.getBoundingClientRect();r=r||i.width,h=h||i.height}this.Jm(r,h),this.Qm(),t.appendChild(this.kp),this.tw(),this.ts.It().Bu().i(this.ts.Bh.bind(this.ts),this),this.ts.Eo().i(this.ts.Bh.bind(this.ts),this)}Qt(){return this.ts}N(){return this.ys}$f(){return this.zm}iw(){return this.Zm}m(){this.Km(!1),0!==this.Lm&&window.cancelAnimationFrame(this.Lm),this.ts.cc().u(this),this.ts.It().Bu().u(this),this.ts.Eo().u(this),this.ts.m();for(const t of this.zm)this.jm.removeChild(t.Zf()),t.Xv().u(this),t.Zv().u(this),t.m();this.zm=[];for(const t of this.Om)this.sw(t);this.Om=[],a(this.Zm).m(),null!==this.kp.parentElement&&this.kp.parentElement.removeChild(this.kp),this.Xu.m(),this.Sv.m(),this.Cv.m(),this.nw()}Jm(t,i,s=!1){if(this.il===i&&this.Mo===t)return;const n=function(t){const i=Math.floor(t.width),s=Math.floor(t.height);return is({width:i-i%2,height:s-s%2})}(is({width:t,height:i}));this.il=n.height,this.Mo=n.width;const e=this.il+"px",r=this.Mo+"px";a(this.kp).style.height=e,a(this.kp).style.width=r,this.jm.style.height=e,this.jm.style.width=r,s?this.ew(Y.gn(),performance.now()):this.ts.Bh()}lv(t){void 0===t&&(t=Y.gn());for(let i=0;i{t.Pt()}))}hw(t){(void 0!==t.autoSize||!this.Um||void 0===t.width&&void 0===t.height)&&(t.autoSize&&!this.Um&&this.Gm(),!1===t.autoSize&&null!==this.Um&&this.nw(),t.autoSize||void 0===t.width&&void 0===t.height||this.Jm(t.width||this.Mo,t.height||this.il))}lw(t,i){let s=0,n=0;const e=this.zm[0],r=(s,n)=>{let e=0;for(let r=0;r{a("left"===i?this.Zm.Cm():this.Zm.ym()).Qf(a(t),s,n)};if(this.ys.timeScale.visible){const s=this.Zm.Jf();if(null!==t){let r=0;this._w()&&(h("left",r,n),r=a(e.nm()).Jf().width),this.Zm.Qf(t,r,n,i),r+=s.width,this.uw()&&h("right",r,n)}n+=s.height}return is({width:s,height:n})}mw(){let t=0,i=0,s=0;for(const n of this.zm)this._w()&&(i=Math.max(i,a(n.nm()).nv(),this.ys.leftPriceScale.minimumWidth)),this.uw()&&(s=Math.max(s,a(n.rm()).nv(),this.ys.rightPriceScale.minimumWidth)),t+=n.Vo();i=us(i),s=us(s);const n=this.Mo,e=this.il,r=Math.max(n-i-s,0),h=1*this.Om.length,l=this.ys.timeScale.visible;let o=l?Math.max(this.Zm.Tm(),this.ys.timeScale.minimumHeight):0;var _;o=(_=o)+_%2;const u=h+o,c=e{t.Nv()})),3===this.Wm?.nn()&&(this.Wm.vn(t),this.gw(),this.Mw(this.Wm),this.bw(this.Wm,i),t=this.Wm,this.Wm=null)),this.lv(t)}bw(t,i){for(const s of t.pn())this.mn(s,i)}Mw(t){const i=this.ts.$s();for(let s=0;s{if(this.Hm=!1,this.Lm=0,null!==this.Wm){const i=this.Wm;this.Wm=null,this.ew(i,t);for(const s of i.pn())if(5===s.an&&!s.Wt.Ru(t)){this.Qt()._n(s.Wt);break}}})))}gw(){this.Qm()}sw(t){this.jm.removeChild(t.Zf()),t.m()}Qm(){const t=this.ts.$s(),i=t.length,s=this.zm.length;for(let t=i;t0){const t=new gs(this,n-1,n);this.Om.push(t),this.jm.insertBefore(t.Zf(),this.Zm.Zf())}this.jm.insertBefore(i.Zf(),this.Zm.Zf())}for(let s=0;s{const s=i.Xs().Fr(t);null!==s&&e.set(i,s)}))}let r;if(null!==t){const i=this.ts.It().ss(t)?.originalTime;void 0!==i&&(r=i)}const h=this.Qt().ac(),a=null!==h&&h.n_ instanceof $t?h.n_:void 0,l=null!==h&&void 0!==h.e_?h.e_.Kn:void 0,o=this.yw(n);return{Pw:r,Re:t??void 0,kw:i??void 0,Tw:-1!==o?o:void 0,Rw:a,Dw:e,Ew:l,Vw:s??void 0}}yw(t){let i=-1;if(t)i=this.zm.indexOf(t);else{const t=this.Qt().uc().Us();null!==t&&(i=this.Qt().$s().indexOf(t))}return i}xw(t,i,s,n){this.Sv.p((()=>this.Cw(i,s,n,t)))}Sw(t,i,s,n){this.Cv.p((()=>this.Cw(i,s,n,t)))}Xm(t,i,s){this.dw(this.Qt().ac()?.h_??null),this.Xu.p((()=>this.Cw(t,i,s)))}tw(){const t=this.ys.timeScale.visible?"":"none";this.Zm.Zf().style.display=t}_w(){return this.zm[0].ap().Wo().N().visible}uw(){return this.zm[0].ap().Ho().N().visible}Gm(){return"ResizeObserver"in window&&(this.Um=new ResizeObserver((t=>{const i=t[t.length-1];i&&this.Jm(i.contentRect.width,i.contentRect.height)})),this.Um.observe(this.Dp,{box:"border-box"}),!0)}nw(){null!==this.Um&&this.Um.disconnect(),this.Um=null}}function js(t){return Boolean(t.handleScroll.mouseWheel||t.handleScale.mouseWheel)}function qs(t){return void 0===t.open&&void 0===t.value}function Ys(t){return function(t){return void 0!==t.open}(t)||function(t){return void 0!==t.value}(t)}function Ks(t,i,s,n){const e=s.value,r={Re:i,wt:t,Wt:[e,e,e,e],Pw:n};return void 0!==s.color&&(r.R=s.color),r}function Xs(t,i,s,n){const e=s.value,r={Re:i,wt:t,Wt:[e,e,e,e],Pw:n};return void 0!==s.lineColor&&(r.vt=s.lineColor),void 0!==s.topColor&&(r.mr=s.topColor),void 0!==s.bottomColor&&(r.wr=s.bottomColor),r}function Zs(t,i,s,n){const e=s.value,r={Re:i,wt:t,Wt:[e,e,e,e],Pw:n};return void 0!==s.topLineColor&&(r.gr=s.topLineColor),void 0!==s.bottomLineColor&&(r.Mr=s.bottomLineColor),void 0!==s.topFillColor1&&(r.br=s.topFillColor1),void 0!==s.topFillColor2&&(r.Sr=s.topFillColor2),void 0!==s.bottomFillColor1&&(r.Cr=s.bottomFillColor1),void 0!==s.bottomFillColor2&&(r.yr=s.bottomFillColor2),r}function Gs(t,i,s,n){const e={Re:i,wt:t,Wt:[s.open,s.high,s.low,s.close],Pw:n};return void 0!==s.color&&(e.R=s.color),e}function Js(t,i,s,n){const e={Re:i,wt:t,Wt:[s.open,s.high,s.low,s.close],Pw:n};return void 0!==s.color&&(e.R=s.color),void 0!==s.borderColor&&(e.Ht=s.borderColor),void 0!==s.wickColor&&(e.vr=s.wickColor),e}function Qs(t,i,s,n,e){const r=h(e)(s),a=Math.max(...r),l=Math.min(...r),o=r[r.length-1],_=[o,a,l,o],{time:u,color:c,...d}=s;return{Re:i,wt:t,Wt:_,Pw:n,se:d,R:c}}function tn(t){return void 0!==t.Wt}function sn(t,i){return void 0!==i.customValues&&(t.Bw=i.customValues),t}function nn(t){return(i,s,n,e,r,h)=>function(t,i){return i?i(t):qs(t)}(n,h)?sn({wt:i,Re:s,Pw:e},n):sn(t(i,s,n,e,r),n)}function en(t){return{Candlestick:nn(Js),Bar:nn(Gs),Area:nn(Xs),Baseline:nn(Zs),Histogram:nn(Ks),Line:nn(Ks),Custom:nn(Qs)}[t]}function rn(t){return{Re:0,Iw:new Map,Hh:t}}function hn(t,i){if(void 0!==t&&0!==t.length)return{Aw:i.key(t[0].wt),zw:i.key(t[t.length-1].wt)}}function an(t){let i;return t.forEach((t=>{void 0===i&&(i=t.Pw)})),h(i)}class ln{constructor(t){this.Ow=new Map,this.Lw=new Map,this.Nw=new Map,this.Fw=[],this.o_=t}m(){this.Ow.clear(),this.Lw.clear(),this.Nw.clear(),this.Fw=[]}Ww(t,i){let s=0!==this.Ow.size,n=!1;const e=this.Lw.get(t);if(void 0!==e)if(1===this.Lw.size)s=!1,n=!0,this.Ow.clear();else for(const i of this.Fw)i.pointData.Iw.delete(t)&&(n=!0);let r=[];if(0!==i.length){const s=i.map((t=>t.time)),e=this.o_.createConverterToInternalObj(i),h=en(t.Rr()),a=t.ca(),l=t.fa();r=i.map(((i,r)=>{const o=e(i.time),_=this.o_.key(o);let u=this.Ow.get(_);void 0===u&&(u=rn(o),this.Ow.set(_,u),n=!0);const c=h(o,u.Re,i,s[r],a,l);return u.Iw.set(t,c),c}))}s&&this.Hw(),this.Uw(t,r);let h=-1;if(n){const t=[];this.Ow.forEach((i=>{t.push({timeWeight:0,time:i.Hh,pointData:i,originalTime:an(i.Iw)})})),t.sort(((t,i)=>this.o_.key(t.time)-this.o_.key(i.time))),h=this.$w(t)}return this.jw(t,h,function(t,i,s){const n=hn(t,s),e=hn(i,s);if(void 0!==n&&void 0!==e)return{qw:!1,zh:n.zw>=e.zw&&n.Aw>=e.Aw}}(this.Lw.get(t),e,this.o_))}Ac(t){return this.Ww(t,[])}Yw(t,i,s){const n=i;!function(t){void 0===t.Pw&&(t.Pw=t.time)}(n),this.o_.preprocessData(i);const e=this.o_.createConverterToInternalObj([i])(i.time),r=this.Nw.get(t);if(!s&&void 0!==r&&this.o_.key(e)this.o_.key(t.time)this.o_.key(n.wt)?tn(i)&&s.push(i):tn(i)?s[s.length-1]=i:s.splice(-1,1),this.Nw.set(t,i.wt)}Kw(t,i,s){const n=this.Lw.get(t);if(void 0===n)return;const e=xt(n,s,((t,i)=>t.Re{0!==i.length&&(t=Math.max(t,i[i.length-1].Re))})),t}jw(t,i,s){const n=this.Gw();if(-1!==i)this.Lw.forEach(((i,e)=>{n.Lo.set(e,{se:i,Qw:e===t?s:void 0})})),this.Lw.has(t)||n.Lo.set(t,{se:[],Qw:s}),n.It.tg=this.Fw,n.It.ig=i;else{const i=this.Lw.get(t);n.Lo.set(t,{se:i||[],Qw:s})}return n}Gw(){return{Lo:new Map,It:{_u:this.Jw()}}}}function on(t,i){t.Re=i,t.Iw.forEach((t=>{t.Re=i}))}function _n(t,i){return t.wt0&&r=n&&(a=r-1),h>0&&h({...t,...this.Jn.Rh().Dr(t.wt)})))}ug(){this.hg=null}lg(){this.ng&&(this.cg(),this.ng=!1),this.eg&&(this._g(),this.eg=!1),this.sg&&(this.dg(),this.sg=!1)}dg(){const t=this.Jn.Ft(),i=this.Qn.It();if(this.ug(),i.Ki()||t.Ki())return;const s=i.ye();if(null===s)return;if(0===this.Jn.Xs().zr())return;const n=this.Jn.zt();null!==n&&(this.hg=cn(this.rg,s,this.ag),this.fg(t,i,n.Wt),this.pg())}}class fn{constructor(t,i){this.vg=t,this.qi=i}nt(t,i,s){this.vg.draw(t,this.qi,i,s)}}class pn extends dn{constructor(t,i,s){super(t,i,!1),this.sh=s,this.og=new fn(this.sh.renderer(),(i=>{const s=t.zt();return null===s?null:t.Ft().Nt(i,s.Wt)}))}da(t){return this.sh.priceValueBuilder(t)}pa(t){return this.sh.isWhitespace(t)}cg(){const t=this.Jn.Rh();this.rg=this.Jn.Xs().Hr().map((i=>({wt:i.Re,_t:NaN,...t.Dr(i.Re),mg:i.se})))}fg(t,i){i.uu(this.rg,m(this.hg))}pg(){this.sh.update({bars:this.rg.map(vn),barSpacing:this.Qn.It().mu(),visibleRange:this.hg},this.Jn.N())}}function vn(t){return{x:t._t,time:t.wt,originalData:t.mg,barColor:t.cr}}const mn={color:"#2196f3"},wn=(t,i,s)=>{const n=l(s);return new pn(t,i,n)};function gn(t){const i={value:t.Wt[3],time:t.Pw};return void 0!==t.Bw&&(i.customValues=t.Bw),i}function Mn(t){const i=gn(t);return void 0!==t.R&&(i.color=t.R),i}function bn(t){const i=gn(t);return void 0!==t.vt&&(i.lineColor=t.vt),void 0!==t.mr&&(i.topColor=t.mr),void 0!==t.wr&&(i.bottomColor=t.wr),i}function xn(t){const i=gn(t);return void 0!==t.gr&&(i.topLineColor=t.gr),void 0!==t.Mr&&(i.bottomLineColor=t.Mr),void 0!==t.br&&(i.topFillColor1=t.br),void 0!==t.Sr&&(i.topFillColor2=t.Sr),void 0!==t.Cr&&(i.bottomFillColor1=t.Cr),void 0!==t.yr&&(i.bottomFillColor2=t.yr),i}function Sn(t){const i={open:t.Wt[0],high:t.Wt[1],low:t.Wt[2],close:t.Wt[3],time:t.Pw};return void 0!==t.Bw&&(i.customValues=t.Bw),i}function Cn(t){const i=Sn(t);return void 0!==t.R&&(i.color=t.R),i}function yn(t){const i=Sn(t),{R:s,Ht:n,vr:e}=t;return void 0!==s&&(i.color=s),void 0!==n&&(i.borderColor=n),void 0!==e&&(i.wickColor=e),i}function Pn(t){return{Area:bn,Line:Mn,Baseline:xn,Histogram:Mn,Bar:Cn,Candlestick:yn,Custom:kn}[t]}function kn(t){const i=t.Pw;return{...t.se,time:i}}const Tn={vertLine:{color:"#9598A1",width:1,style:3,visible:!0,labelVisible:!0,labelBackgroundColor:"#131722"},horzLine:{color:"#9598A1",width:1,style:3,visible:!0,labelVisible:!0,labelBackgroundColor:"#131722"},mode:1},Rn={vertLines:{color:"#D6DCDE",style:0,visible:!0},horzLines:{color:"#D6DCDE",style:0,visible:!0}},Dn={background:{type:"solid",color:"#FFFFFF"},textColor:"#191919",fontSize:12,fontFamily:w,panes:{enableResize:!0,separatorColor:"#E0E3EB",separatorHoverColor:"rgba(178, 181, 189, 0.2)"},attributionLogo:!0,colorSpace:"srgb",colorParsers:[]},En={autoScale:!0,mode:0,invertScale:!1,alignLabels:!0,borderVisible:!0,borderColor:"#2B2B43",entireTextOnly:!1,visible:!1,ticksVisible:!1,scaleMargins:{bottom:.1,top:.2},minimumWidth:0,ensureEdgeTickMarksVisible:!1},Vn={rightOffset:0,barSpacing:6,minBarSpacing:.5,maxBarSpacing:0,fixLeftEdge:!1,fixRightEdge:!1,lockVisibleTimeRangeOnResize:!1,rightBarStaysOnScroll:!1,borderVisible:!0,borderColor:"#2B2B43",visible:!0,timeVisible:!1,secondsVisible:!0,shiftVisibleRangeOnNewBar:!0,allowShiftVisibleRangeOnWhitespaceReplacement:!1,ticksVisible:!1,uniformDistribution:!1,minimumHeight:0,allowBoldLabels:!0,ignoreWhitespaceIndices:!1};function Bn(){return{addDefaultPane:!0,width:0,height:0,autoSize:!1,layout:Dn,crosshair:Tn,grid:Rn,overlayPriceScales:{...En},leftPriceScale:{...En,visible:!1},rightPriceScale:{...En,visible:!0},timeScale:Vn,localization:{locale:ls?navigator.language:"",dateFormat:"dd MMM 'yy"},handleScroll:{mouseWheel:!0,pressedMouseMove:!0,horzTouchDrag:!0,vertTouchDrag:!0},handleScale:{axisPressedMouseMove:{time:!0,price:!0},axisDoubleClickReset:{time:!0,price:!0},mouseWheel:!0,pinch:!0},kineticScroll:{mouse:!1,touch:!0},trackingMode:{exitMode:1}}}class In{constructor(t,i,s){this.Hf=t,this.wg=i,this.gg=s??0}applyOptions(t){this.Hf.Qt().oc(this.wg,t,this.gg)}options(){return this.qi().N()}width(){return q(this.wg)?this.Hf.ow(this.wg):0}setVisibleRange(t){this.setAutoScale(!1),this.qi().Fl(new dt(t.from,t.to))}getVisibleRange(){let t,i,s=this.qi().Qe();if(null===s)return null;if(this.qi().Ja()){const n=this.qi().fo(),e=zi(n);s=li(s,this.qi().tl()),t=Number((Math.round(s.$e()/n)*n).toFixed(e)),i=Number((Math.round(s.je()/n)*n).toFixed(e))}else t=s.$e(),i=s.je();return{from:t,to:i}}setAutoScale(t){this.applyOptions({autoScale:t})}qi(){return a(this.Hf.Qt()._c(this.wg,this.gg)).Ft}}class An{constructor(t,i,s,n){this.Hf=t,this.yt=s,this.Mg=i,this.bg=n}getHeight(){return this.yt.$t()}setHeight(t){const i=this.Hf.Qt(),s=i.Uc(this.yt);i.vc(s,t)}getStretchFactor(){return this.yt.Vo()}setStretchFactor(t){this.yt.Bo(t),this.Hf.Qt().Bh()}paneIndex(){return this.Hf.Qt().Uc(this.yt)}moveTo(t){const i=this.paneIndex();i!==t&&(r(t>=0&&tthis.Mg(t)))??[]}getHTMLElement(){const t=this.Hf.$f();return t&&0!==t.length&&t[this.paneIndex()]?t[this.paneIndex()].Zf():null}attachPrimitive(t){this.yt._a(t),t.attached&&t.attached({chart:this.bg,requestUpdate:()=>this.yt.Qt().Bh()})}detachPrimitive(t){this.yt.ua(t)}priceScale(t){if(null===this.yt.Do(t))throw new Error(`Cannot find price scale with id: ${t}`);return new In(this.Hf,t,this.paneIndex())}setPreserveEmptyPane(t){this.yt.zo(t)}preserveEmptyPane(){return this.yt.Oo()}addCustomSeries(t,i={},s=0){return this.bg.addCustomSeries(t,i,s)}addSeries(t,i={}){return this.bg.addSeries(t,i,this.paneIndex())}}const zn={color:"#FF0000",price:0,lineStyle:2,lineWidth:1,lineVisible:!0,axisLabelVisible:!0,title:"",axisLabelColor:"",axisLabelTextColor:""};class On{constructor(t){this.ir=t}applyOptions(t){this.ir.hr(t)}options(){return this.ir.N()}xg(){return this.ir}}class Ln{constructor(t,i,s,n,e,r){this.Sg=new o,this.Jn=t,this.Cg=i,this.yg=s,this.o_=e,this.bg=n,this.Pg=r}m(){this.Sg.m()}priceFormatter(){return this.Jn.ea()}priceToCoordinate(t){const i=this.Jn.zt();return null===i?null:this.Jn.Ft().Nt(t,i.Wt)}coordinateToPrice(t){const i=this.Jn.zt();return null===i?null:this.Jn.Ft().Ts(t,i.Wt)}barsInLogicalRange(t){if(null===t)return null;const i=new ki(new Ci(t.from,t.to)).P_(),s=this.Jn.Xs();if(s.Ki())return null;const n=s.Fr(i.Uh(),1),e=s.Fr(i.bi(),-1),r=a(s.Or()),h=a(s.Ks());if(null!==n&&null!==e&&n.Re>e.Re)return{barsBefore:t.from-r,barsAfter:h-t.to};const l={barsBefore:null===n||n.Re===r?t.from-r:n.Re-r,barsAfter:null===e||e.Re===h?h-t.to:h-e.Re};return null!==n&&null!==e&&(l.from=n.Pw,l.to=e.Pw),l}setData(t){this.o_,this.Jn.Rr(),this.Cg.kg(this.Jn,t),this.Tg("full")}update(t,i=!1){this.Jn.Rr(),this.Cg.Rg(this.Jn,t,i),this.Tg("update")}pop(t=1){const i=this.Cg.Dg(this.Jn,t);0!==i.length&&this.Tg("update");const s=Pn(this.seriesType());return i.map((t=>s(t)))}dataByIndex(t,i){const s=this.Jn.Xs().Fr(t,i);if(null===s)return null;return Pn(this.seriesType())(s)}data(){const t=Pn(this.seriesType());return this.Jn.Xs().Hr().map((i=>t(i)))}subscribeDataChanged(t){this.Sg.i(t)}unsubscribeDataChanged(t){this.Sg._(t)}applyOptions(t){this.Jn.hr(t)}options(){return p(this.Jn.N())}priceScale(){return this.yg.priceScale(this.Jn.Ft().ma(),this.getPane().paneIndex())}createPriceLine(t){const i=_(p(zn),t),s=this.Jn.Lh(i);return new On(s)}removePriceLine(t){this.Jn.Nh(t.xg())}priceLines(){return this.Jn.Fh().map((t=>new On(t)))}seriesType(){return this.Jn.Rr()}lastValueData(t){const i=this.Jn.Pe(t);return i.ke?{noData:!0}:{noData:!1,price:i.gt,color:i.R}}attachPrimitive(t){this.Jn._a(t),t.attached&&t.attached({chart:this.bg,series:this,requestUpdate:()=>this.Jn.Qt().Bh(),horzScaleBehavior:this.o_})}detachPrimitive(t){this.Jn.ua(t),t.detached&&t.detached(),this.Jn.Qt().Bh()}getPane(){const t=this.Jn,i=a(this.Jn.Qt().Hn(t));return this.Pg(i)}moveToPane(t){this.Jn.Qt().Nc(this.Jn,t)}seriesOrder(){const t=this.Jn.Qt().Hn(this.Jn);return null===t?-1:t.Lo().indexOf(this.Jn)}setSeriesOrder(t){const i=this.Jn.Qt().Hn(this.Jn);null!==i&&i.Qo(this.Jn,t)}Tg(t){this.Sg.v()&&this.Sg.p(t)}}class Nn{constructor(t,i,s){this.Eg=new o,this.z_=new o,this.gm=new o,this.ts=t,this.uh=t.It(),this.Zm=i,this.uh.Eu().i(this.Vg.bind(this)),this.uh.Vu().i(this.Bg.bind(this)),this.Zm.Pm().i(this.Ig.bind(this)),this.o_=s}m(){this.uh.Eu().u(this),this.uh.Vu().u(this),this.Zm.Pm().u(this),this.Eg.m(),this.z_.m(),this.gm.m()}scrollPosition(){return this.uh.gu()}scrollToPosition(t,i){i?this.uh.Tu(t,1e3):this.ts.fn(t)}scrollToRealTime(){this.uh.ku()}getVisibleRange(){const t=this.uh.nu();return null===t?null:{from:t.from.originalTime,to:t.to.originalTime}}setVisibleRange(t){const i={from:this.o_.convertHorzItemToInternal(t.from),to:this.o_.convertHorzItemToInternal(t.to)},s=this.uh.au(i);this.ts.Oc(s)}getVisibleLogicalRange(){const t=this.uh.su();return null===t?null:{from:t.Uh(),to:t.bi()}}setVisibleLogicalRange(t){r(t.from<=t.to,"The from index cannot be after the to index."),this.ts.Oc(t)}resetTimeScale(){this.ts.cn()}fitContent(){this.ts.Au()}logicalToCoordinate(t){const i=this.ts.It();return i.Ki()?null:i.jt(t)}coordinateToLogical(t){return this.uh.Ki()?null:this.uh.cu(t)}timeToIndex(t,i){const s=this.o_.convertHorzItemToInternal(t);return this.uh.Q_(s,i)}timeToCoordinate(t){const i=this.timeToIndex(t,!1);return null===i?null:this.uh.jt(i)}coordinateToTime(t){const i=this.ts.It(),s=i.cu(t),n=i.ss(s);return null===n?null:n.originalTime}width(){return this.Zm.Gf().width}height(){return this.Zm.Gf().height}subscribeVisibleTimeRangeChange(t){this.Eg.i(t)}unsubscribeVisibleTimeRangeChange(t){this.Eg._(t)}subscribeVisibleLogicalRangeChange(t){this.z_.i(t)}unsubscribeVisibleLogicalRangeChange(t){this.z_._(t)}subscribeSizeChange(t){this.gm.i(t)}unsubscribeSizeChange(t){this.gm._(t)}applyOptions(t){this.uh.hr(t)}options(){return{...p(this.uh.N()),barSpacing:this.uh.mu()}}Vg(){this.Eg.v()&&this.Eg.p(this.getVisibleRange())}Bg(){this.z_.v()&&this.z_.p(this.getVisibleLogicalRange())}Ig(t){this.gm.p(t.width,t.height)}}function Fn(t){return function(t){if(f(t.handleScale)){const i=t.handleScale;t.handleScale={axisDoubleClickReset:{time:i,price:i},axisPressedMouseMove:{time:i,price:i},mouseWheel:i,pinch:i}}else if(void 0!==t.handleScale){const{axisPressedMouseMove:i,axisDoubleClickReset:s}=t.handleScale;f(i)&&(t.handleScale.axisPressedMouseMove={time:i,price:i}),f(s)&&(t.handleScale.axisDoubleClickReset={time:s,price:s})}const i=t.handleScroll;f(i)&&(t.handleScroll={horzTouchDrag:i,vertTouchDrag:i,mouseWheel:i,pressedMouseMove:i})}(t),t}class Wn{constructor(t,i,s){this.Ag=new Map,this.zg=new Map,this.Og=new o,this.Lg=new o,this.Ng=new o,this.ju=new WeakMap,this.Fg=new ln(i);const n=void 0===s?p(Bn()):_(p(Bn()),Fn(s));this.Wg=i,this.Hf=new $s(t,n,i),this.Hf.Xv().i((t=>{this.Og.v()&&this.Og.p(this.Hg(t()))}),this),this.Hf.Zv().i((t=>{this.Lg.v()&&this.Lg.p(this.Hg(t()))}),this),this.Hf.cc().i((t=>{this.Ng.v()&&this.Ng.p(this.Hg(t()))}),this);const e=this.Hf.Qt();this.Ug=new Nn(e,this.Hf.iw(),this.Wg)}remove(){this.Hf.Xv().u(this),this.Hf.Zv().u(this),this.Hf.cc().u(this),this.Ug.m(),this.Hf.m(),this.Ag.clear(),this.zg.clear(),this.Og.m(),this.Lg.m(),this.Ng.m(),this.Fg.m()}resize(t,i,s){this.autoSizeActive()||this.Hf.Jm(t,i,s)}addCustomSeries(t,i={},s=0){const n=(t=>({type:"Custom",isBuiltIn:!1,defaultOptions:{...mn,...t.defaultOptions()},$g:wn,jg:t}))(l(t));return this.qg(n,i,s)}addSeries(t,i={},s=0){return this.qg(t,i,s)}removeSeries(t){const i=h(this.Ag.get(t)),s=this.Fg.Ac(i);this.Hf.Qt().Ac(i),this.Yg(s),this.Ag.delete(t),this.zg.delete(i)}kg(t,i){this.Yg(this.Fg.Ww(t,i))}Rg(t,i,s){this.Yg(this.Fg.Yw(t,i,s))}Dg(t,i){const[s,n]=this.Fg.Zw(t,i);return 0!==s.length&&this.Yg(n),s}subscribeClick(t){this.Og.i(t)}unsubscribeClick(t){this.Og._(t)}subscribeCrosshairMove(t){this.Ng.i(t)}unsubscribeCrosshairMove(t){this.Ng._(t)}subscribeDblClick(t){this.Lg.i(t)}unsubscribeDblClick(t){this.Lg._(t)}priceScale(t,i=0){return new In(this.Hf,t,i)}timeScale(){return this.Ug}applyOptions(t){this.Hf.hr(Fn(t))}options(){return this.Hf.N()}takeScreenshot(t=!1,i=!1){let s,n;try{i||(s=this.Hf.Qt().N().crosshair.mode,this.Hf.hr({crosshair:{mode:2}})),n=this.Hf.aw(t)}finally{i||void 0===s||this.Hf.Qt().hr({crosshair:{mode:s}})}return n}addPane(t=!1){const i=this.Hf.Qt().$c();return i.zo(t),this.Kg(i)}removePane(t){this.Hf.Qt().fc(t)}swapPanes(t,i){this.Hf.Qt().mc(t,i)}autoSizeActive(){return this.Hf.cw()}chartElement(){return this.Hf.ip()}panes(){return this.Hf.Qt().$s().map((t=>this.Kg(t)))}paneSize(t=0){const i=this.Hf.pw(t);return{height:i.height,width:i.width}}setCrosshairPosition(t,i,s){const n=this.Ag.get(s);if(void 0===n)return;const e=this.Hf.Qt().Hn(n);null!==e&&this.Hf.Qt().Rc(t,i,e)}clearCrosshairPosition(){this.Hf.Qt().Dc(!0)}horzBehaviour(){return this.Wg}qg(i,s={},n=0){r(void 0!==i.$g),function(t){if(void 0===t||"custom"===t.type)return;const i=t;void 0!==i.minMove&&void 0===i.precision&&(i.precision=zi(i.minMove))}(s.priceFormat),"Candlestick"===i.type&&function(t){void 0!==t.borderColor&&(t.borderUpColor=t.borderColor,t.borderDownColor=t.borderColor),void 0!==t.wickColor&&(t.wickUpColor=t.wickColor,t.wickDownColor=t.wickColor)}(s);const e=_(p(t),p(i.defaultOptions),s),h=i.$g,a=new $t(this.Hf.Qt(),i.type,e,h,i.jg);this.Hf.Qt().Bc(a,n);const l=new Ln(a,this,this,this,this.Wg,(t=>this.Kg(t)));return this.Ag.set(l,a),this.zg.set(a,l),l}Yg(t){const i=this.Hf.Qt();i.Ec(t.It._u,t.It.tg,t.It.ig),t.Lo.forEach(((t,i)=>i.ht(t.se,t.Qw))),i.It().K_(),i.vu()}Xg(t){return h(this.zg.get(t))}Hg(t){const i=new Map;t.Dw.forEach(((t,s)=>{const n=s.Rr(),e=Pn(n)(t);if("Custom"!==n)r(Ys(e));else{const t=s.fa();r(!t||!1===t(e))}i.set(this.Xg(s),e)}));const s=void 0!==t.Rw&&this.zg.has(t.Rw)?this.Xg(t.Rw):void 0;return{time:t.Pw,logical:t.Re,point:t.kw,paneIndex:t.Tw,hoveredSeries:s,hoveredObjectId:t.Ew,seriesData:i,sourceEvent:t.Vw}}Kg(t){let i=this.ju.get(t);return i||(i=new An(this.Hf,(t=>this.Xg(t)),t,this),this.ju.set(t,i)),i}}function Hn(t){if(d(t)){const i=document.getElementById(t);return r(null!==i,`Cannot find element in DOM with id=${t}`),i}return t}function Un(t,i,s){const n=Hn(t),e=new Wn(n,i,s);return i.setOptions(e.options()),e}function $n(t,i){return Un(t,new ts,ts.ld(i))}function jn(){return ts}class qn extends dn{constructor(t,i){super(t,i,!0)}fg(t,i,s){i.uu(this.rg,m(this.hg)),t.Ul(this.rg,s,m(this.hg))}Zg(t,i){return{wt:t,gt:i,_t:NaN,ut:NaN}}cg(){const t=this.Jn.Rh();this.rg=this.Jn.Xs().Hr().map((i=>{const s=i.Wt[3];return this.Gg(i.Re,s,t)}))}}function Yn(t,i,s,n,e,r,h){if(0===i.length||n.from>=i.length||n.to<=0)return;const{context:a,horizontalPixelRatio:l,verticalPixelRatio:o}=t,_=i[n.from];let u=r(t,_),c=_;if(n.to-n.from<2){const i=e/2;a.beginPath();const s={_t:_._t-i,ut:_.ut},n={_t:_._t+i,ut:_.ut};a.moveTo(s._t*l,s.ut*o),a.lineTo(n._t*l,n.ut*o),h(t,u,s,n)}else{const e=(i,s)=>{h(t,u,c,s),a.beginPath(),u=i,c=s};let d=c;a.beginPath(),a.moveTo(_._t*l,_.ut*o);for(let h=n.from+1;h=n.from;--s){const n=i[s];if(n){const i=e(t,n);i!==l&&(a.beginPath(),null!==l&&a.fill(),a.fillStyle=i,l=i);const s=Math.round(n._t*r)+o,u=n.ut*h;a.moveTo(s,u),a.arc(s,u,_,0,2*Math.PI)}}a.fill()}(t,i,l,s,_)}}class te extends Qn{iM(t,i){return i.vt}}class ie extends qn{constructor(){super(...arguments),this.og=new te}Gg(t,i,s){return{...this.Zg(t,i),...s.Dr(t)}}pg(){const t=this.Jn.N(),i={ot:this.rg,Xt:t.lineStyle,Qg:t.lineVisible?t.lineType:void 0,ct:t.lineWidth,tM:t.pointMarkersVisible?t.pointMarkersRadius||t.lineWidth/2+2:void 0,lt:this.hg,Jg:this.Qn.It().mu()};this.og.ht(i)}}const se={type:"Line",isBuiltIn:!0,defaultOptions:{color:"#2196f3",lineStyle:0,lineWidth:3,lineType:0,lineVisible:!0,crosshairMarkerVisible:!0,crosshairMarkerRadius:4,crosshairMarkerBorderColor:"",crosshairMarkerBorderWidth:2,crosshairMarkerBackgroundColor:"",lastPriceAnimation:0,pointMarkersVisible:!1},$g:(t,i)=>new ie(t,i)};function ne(t,i){return t.weight>i.weight?t:i}class ee{constructor(){this.sM=new o,this.nM=function(t){let i=!1;return function(...s){i||(i=!0,queueMicrotask((()=>{t(...s),i=!1})))}}((()=>this.sM.p(this.eM))),this.eM=0}rM(){return this.sM}m(){this.sM.m()}options(){return this.ys}setOptions(t){this.ys=t}preprocessData(t){}updateFormatter(t){this.ys&&(this.ys.localization=t)}createConverterToInternalObj(t){return this.nM(),t=>(t>this.eM&&(this.eM=t),t)}key(t){return t}cacheKey(t){return t}convertHorzItemToInternal(t){return t}formatHorzItem(t){return this.hM(t)}formatTickmark(t){return this.hM(t.time)}maxTickMarkWeight(t){return t.reduce(ne,t[0]).weight}fillWeightsForPoints(t,i){for(let n=i;nt.toFixed(3)+"%"}},he={lastValueVisible:!1,priceLineVisible:!1};class ae extends Wn{constructor(t,i){const s=_(re,i||{}),n=new ee;super(t,n,s),n.setOptions(this.options()),this._initWhitespaceSeries()}addSeries(t,i={},s=0){if(t.isBuiltIn&&!1===["Area","Line"].includes(t.type))throw new Error("Yield curve only support Area and Line series");const n={...he,...i};return super.addSeries(t,n,s)}_initWhitespaceSeries(){const t=this.horzBehaviour(),i=this.addSeries(se);let s;function n(n){const e=function(t,i){return{le:Math.max(0,t.startTimeRange),oe:Math.max(0,t.minimumTimeRange,i||0),aM:Math.max(1,t.baseResolution)}}(t.options().yieldCurve,n),r=(({le:t,oe:i,aM:s})=>`${t}~${i}~${s}`)(e);r!==s&&(s=r,i.setData(function({le:t,oe:i,aM:s}){return Array.from({length:Math.floor((i-t)/s)+1},((i,n)=>({time:t+n*s})))}(e)))}n(0),t.rM().i(n)}}function le(t,i){const s=Hn(t);return new ae(s,i)}function oe(t,i){return t.weight>i.weight?t:i}class _e{options(){return this.ys}setOptions(t){this.ys=t}preprocessData(t){}updateFormatter(t){this.ys&&(this.ys.localization=t)}createConverterToInternalObj(t){return t=>t}key(t){return t}cacheKey(t){return t}convertHorzItemToInternal(t){return t}formatHorzItem(t){return t.toFixed(this.Cn())}formatTickmark(t,i){return t.time.toFixed(this.Cn())}maxTickMarkWeight(t){return t.reduce(oe,t[0]).weight}fillWeightsForPoints(t,i){for(let n=i;n0?s:1,u=l*_,c=o===t.bitmapSize.height?o:o*_,d=(a??0)*_,f=t.context.createLinearGradient(0,u,0,c);if(f.addColorStop(0,n),null!=a){const t=Kt((d-u)/(c-u),0,1);f.addColorStop(t,e),f.addColorStop(t,r)}f.addColorStop(1,h),this.gM=f,this.cM=i}return this.gM}}class pe extends de{constructor(){super(...arguments),this.MM=new fe}_M(t,i){const s=this.rt;return this.MM.uM(t,{dM:i.br,fM:i.Sr,pM:i.Cr,vM:i.yr,lM:s.lM,mM:s.mM??0,wM:s.wM??t.bitmapSize.height})}}class ve extends Qn{constructor(){super(...arguments),this.bM=new fe}iM(t,i){const s=this.rt;return this.bM.uM(t,{dM:i.gr,fM:i.gr,pM:i.Mr,vM:i.Mr,lM:s.lM,mM:s.mM??0,wM:s.wM??t.bitmapSize.height})}}class me extends qn{constructor(t,i){super(t,i),this.og=new C,this.xM=new pe,this.SM=new ve,this.og.st([this.xM,this.SM])}Gg(t,i,s){return{...this.Zg(t,i),...s.Dr(t)}}pg(){const t=this.Jn.zt();if(null===t)return;const i=this.Jn.N(),s=this.Jn.Ft().Nt(i.baseValue.price,t.Wt),n=this.Qn.It().mu();if(null===this.hg||0===this.rg.length)return;let e,r;if(i.relativeGradient){e=this.rg[this.hg.from].ut,r=this.rg[this.hg.from].ut;for(let t=this.hg.from;tr&&(r=i.ut)}}this.xM.ht({ot:this.rg,ct:i.lineWidth,Xt:i.lineStyle,Qg:i.lineType,lM:s,mM:e,wM:r,oM:!1,lt:this.hg,Jg:n}),this.SM.ht({ot:this.rg,ct:i.lineWidth,Xt:i.lineStyle,Qg:i.lineVisible?i.lineType:void 0,tM:i.pointMarkersVisible?i.pointMarkersRadius||i.lineWidth/2+2:void 0,lM:s,mM:e,wM:r,lt:this.hg,Jg:n})}}const we={type:"Baseline",isBuiltIn:!0,defaultOptions:{baseValue:{type:"price",price:0},relativeGradient:!1,topFillColor1:"rgba(38, 166, 154, 0.28)",topFillColor2:"rgba(38, 166, 154, 0.05)",topLineColor:"rgba(38, 166, 154, 1)",bottomFillColor1:"rgba(239, 83, 80, 0.05)",bottomFillColor2:"rgba(239, 83, 80, 0.28)",bottomLineColor:"rgba(239, 83, 80, 1)",lineWidth:3,lineStyle:0,lineType:0,lineVisible:!0,crosshairMarkerVisible:!0,crosshairMarkerRadius:4,crosshairMarkerBorderColor:"",crosshairMarkerBorderWidth:2,crosshairMarkerBackgroundColor:"",lastPriceAnimation:0,pointMarkersVisible:!1},$g:(t,i)=>new me(t,i)};class ge extends de{constructor(){super(...arguments),this.MM=new fe}_M(t,i){return this.MM.uM(t,{dM:i.mr,fM:"",pM:"",vM:i.wr,mM:this.rt?.mM??0,wM:t.bitmapSize.height})}}class Me extends qn{constructor(t,i){super(t,i),this.og=new C,this.CM=new ge,this.yM=new te,this.og.st([this.CM,this.yM])}Gg(t,i,s){return{...this.Zg(t,i),...s.Dr(t)}}pg(){const t=this.Jn.N();if(null===this.hg||0===this.rg.length)return;let i;if(t.relativeGradient){i=this.rg[this.hg.from].ut;for(let t=this.hg.from;tnew Me(t,i)};class xe extends y{constructor(){super(...arguments),this.qt=null,this.PM=0,this.kM=0}ht(t){this.qt=t}et({context:t,horizontalPixelRatio:i,verticalPixelRatio:s}){if(null===this.qt||0===this.qt.Xs.length||null===this.qt.lt)return;if(this.PM=this.TM(i),this.PM>=2){Math.max(1,Math.floor(i))%2!=this.PM%2&&this.PM--}this.kM=this.qt.RM?Math.min(this.PM,Math.floor(i)):this.PM;let n=null;const e=this.kM<=this.PM&&this.qt.mu>=Math.floor(1.5*i);for(let r=this.qt.lt.from;rf+v-1&&(e=f+v-1,n=e-_+1),t.fillRect(i,n,o-i,e-n+1)}const i=l+m;let n=Math.max(f,Math.round(h.Xl*s)-a),e=n+_-1;e>f+v-1&&(e=f+v-1,n=e-_+1),t.fillRect(u+1,n,i-u,e-n+1)}}}TM(t){const i=Math.floor(t);return Math.max(i,Math.floor(function(t,i){return Math.floor(.3*t*i)}(a(this.qt).mu,t)))}}class Se extends dn{constructor(t,i){super(t,i,!1)}fg(t,i,s){i.uu(this.rg,m(this.hg)),t.jl(this.rg,s,m(this.hg))}EM(t,i,s){return{wt:t,jh:i.Wt[0],qh:i.Wt[1],Yh:i.Wt[2],Kh:i.Wt[3],_t:NaN,ql:NaN,Yl:NaN,Kl:NaN,Xl:NaN}}cg(){const t=this.Jn.Rh();this.rg=this.Jn.Xs().Hr().map((i=>this.Gg(i.Re,i,t)))}}class Ce extends Se{constructor(){super(...arguments),this.og=new xe}Gg(t,i,s){return{...this.EM(t,i,s),...s.Dr(t)}}pg(){const t=this.Jn.N();this.og.ht({Xs:this.rg,mu:this.Qn.It().mu(),DM:t.openVisible,RM:t.thinBars,lt:this.hg})}}const ye={type:"Bar",isBuiltIn:!0,defaultOptions:{upColor:"#26a69a",downColor:"#ef5350",openVisible:!0,thinBars:!0},$g:(t,i)=>new Ce(t,i)};class Pe extends y{constructor(){super(...arguments),this.qt=null,this.PM=0}ht(t){this.qt=t}et(t){if(null===this.qt||0===this.qt.Xs.length||null===this.qt.lt)return;const{horizontalPixelRatio:i}=t;if(this.PM=function(t,i){if(t>=2.5&&t<=4)return Math.floor(3*i);const s=1-.2*Math.atan(Math.max(4,t)-4)/(.5*Math.PI),n=Math.floor(t*s*i),e=Math.floor(t*i),r=Math.min(n,e);return Math.max(Math.floor(i),r)}(this.qt.mu,i),this.PM>=2){Math.floor(i)%2!=this.PM%2&&this.PM--}const s=this.qt.Xs;this.qt.VM&&this.BM(t,s,this.qt.lt),this.qt.Mi&&this.uv(t,s,this.qt.lt);const n=this.IM(i);(!this.qt.Mi||this.PM>2*n)&&this.AM(t,s,this.qt.lt)}BM(t,i,s){if(null===this.qt)return;const{context:n,horizontalPixelRatio:e,verticalPixelRatio:r}=t;let h="",a=Math.min(Math.floor(e),Math.floor(this.qt.mu*e));a=Math.max(Math.floor(e),Math.min(a,this.PM));const l=Math.floor(.5*a);let o=null;for(let t=s.from;t2*a)V(n,o,u,_-o+1,c-u+1,a);else{const t=_-o+1;n.fillRect(o,u,t,c-u+1)}l=_}}AM(t,i,s){if(null===this.qt)return;const{context:n,horizontalPixelRatio:e,verticalPixelRatio:r}=t;let h="";const a=this.IM(e);for(let t=s.from;to||n.fillRect(_,l,u-_+1,o-l+1)}}}class ke extends Se{constructor(){super(...arguments),this.og=new Pe}Gg(t,i,s){return{...this.EM(t,i,s),...s.Dr(t)}}pg(){const t=this.Jn.N();this.og.ht({Xs:this.rg,mu:this.Qn.It().mu(),VM:t.wickVisible,Mi:t.borderVisible,lt:this.hg})}}const Te={type:"Candlestick",isBuiltIn:!0,defaultOptions:{upColor:"#26a69a",downColor:"#ef5350",wickVisible:!0,borderVisible:!0,borderColor:"#378658",borderUpColor:"#26a69a",borderDownColor:"#ef5350",wickColor:"#737375",wickUpColor:"#26a69a",wickDownColor:"#ef5350"},$g:(t,i)=>new ke(t,i)};class Re extends y{constructor(){super(...arguments),this.qt=null,this.zM=[]}ht(t){this.qt=t,this.zM=[]}et({context:t,horizontalPixelRatio:i,verticalPixelRatio:s}){if(null===this.qt||0===this.qt.ot.length||null===this.qt.lt)return;this.zM.length||this.OM(i);const n=Math.max(1,Math.floor(s)),e=Math.round(this.qt.LM*s)-Math.floor(n/2),r=e+n;for(let i=this.qt.lt.from;in.ne?n.bi=s.Uh-i-1:s.Uh=n.bi+i+1))}let n=Math.ceil(this.qt.mu*t);for(let t=this.qt.lt.from;t0&&n<4)for(let t=this.qt.lt.from;tn&&(i.NM>i.ne?i.bi-=1:i.Uh+=1)}}}class De extends qn{constructor(){super(...arguments),this.og=new Re}Gg(t,i,s){return{...this.Zg(t,i),...s.Dr(t)}}pg(){const t={ot:this.rg,mu:this.Qn.It().mu(),lt:this.hg,LM:this.Jn.Ft().Nt(this.Jn.N().base,a(this.Jn.zt()).Wt)};this.og.ht(t)}}const Ee={type:"Histogram",isBuiltIn:!0,defaultOptions:{color:"#26a69a",base:0},$g:(t,i)=>new De(t,i)};class Ve{constructor(t,i){this.yt=t,this.FM=i,this.WM()}detach(){this.yt.detachPrimitive(this.FM)}getPane(){return this.yt}applyOptions(t){this.FM.hr?.(t)}WM(){this.yt.attachPrimitive(this.FM)}}const Be={visible:!0,horzAlign:"center",vertAlign:"center",lines:[]},Ie={color:"rgba(0, 0, 0, 0.5)",fontSize:48,fontFamily:w,fontStyle:"",text:""};class Ae{constructor(t){this.HM=new Map,this.qt=t}draw(t){t.useMediaCoordinateSpace((t=>{if(!this.qt.visible)return;const{context:i,mediaSize:s}=t;let n=0;for(const t of this.qt.lines){if(0===t.text.length)continue;i.font=t.k;const e=this.UM(i,t.text);e>s.width?t.Cu=s.width/e:t.Cu=1,n+=t.lineHeight*t.Cu}let e=0;switch(this.qt.vertAlign){case"top":e=0;break;case"center":e=Math.max((s.height-n)/2,0);break;case"bottom":e=Math.max(s.height-n,0)}for(const t of this.qt.lines){i.save(),i.fillStyle=t.color;let n=0;switch(this.qt.horzAlign){case"left":i.textAlign="left",n=t.lineHeight/2;break;case"center":i.textAlign="center",n=s.width/2;break;case"right":i.textAlign="right",n=s.width-1-t.lineHeight/2}i.translate(n,e),i.textBaseline="top",i.font=t.k,i.scale(t.Cu,t.Cu),i.fillText(t.text,0,t.$M),i.restore(),e+=t.lineHeight*t.Cu}}))}UM(t,i){const s=this.jM(t.font);let n=s.get(i);return void 0===n&&(n=t.measureText(i).width,s.set(i,n)),n}jM(t){let i=this.HM.get(t);return void 0===i&&(i=new Map,this.HM.set(t,i)),i}}class ze{constructor(t){this.ys=Le(t)}Pt(t){this.ys=Le(t)}renderer(){return new Ae(this.ys)}}function Oe(t){return{...t,k:g(t.fontSize,t.fontFamily,t.fontStyle),lineHeight:t.lineHeight||1.2*t.fontSize,$M:0,Cu:0}}function Le(t){return{...t,lines:t.lines.map(Oe)}}function Ne(t){return{...Ie,...t}}function Fe(t){return{...Be,...t,lines:t.lines?.map(Ne)??[]}}class We{constructor(t){this.ys=Fe(t),this.qM=[new ze(this.ys)]}updateAllViews(){this.qM.forEach((t=>t.Pt(this.ys)))}paneViews(){return this.qM}attached({requestUpdate:t}){this.YM=t}detached(){this.YM=void 0}hr(t){this.ys=Fe({...this.ys,...t}),this.YM&&this.YM()}}function He(t,i){return new Ve(t,new We(i))}const Ue={alpha:1,padding:0};class $e{constructor(t){this.qt=t}draw(t){t.useMediaCoordinateSpace((t=>{const i=t.context,s=this.KM(this.qt,t.mediaSize);s&&this.qt.XM&&(i.globalAlpha=this.qt.alpha??1,i.drawImage(this.qt.XM,s._t,s.ut,s.Qi,s.$t))}))}KM(t,i){const{maxHeight:s,maxWidth:n,ZM:e,GM:r,padding:h}=t,a=Math.round(i.width/2),l=Math.round(i.height/2),o=h??0;let _=i.width-2*o,u=i.height-2*o;s&&(u=Math.min(u,s)),n&&(_=Math.min(_,n));const c=_/r,d=u/e,f=Math.min(c,d),p=r*f,v=e*f;return{_t:a-.5*p,ut:l-.5*v,$t:v,Qi:p}}}class je{constructor(t){this.JM=null,this.QM=0,this.tb=0,this.ys=t,this.M=qe(this.ys,this.JM,this.QM,this.tb)}ib(t){void 0!==t.sb&&(this.QM=t.sb),void 0!==t.nb&&(this.tb=t.nb),void 0!==t.eb&&(this.JM=t.eb),this.Pt()}rb(t){this.ys=t,this.Pt()}zOrder(){return"bottom"}Pt(){this.M=qe(this.ys,this.JM,this.QM,this.tb)}renderer(){return new $e(this.M)}}function qe(t,i,s,n){return{...t,XM:i,GM:s,ZM:n}}function Ye(t){return{...Ue,...t}}class Ke{constructor(t,i){this.hb=null,this.ab=t,this.ys=Ye(i),this.qM=[new je(this.ys)]}updateAllViews(){this.qM.forEach((t=>t.Pt()))}paneViews(){return this.qM}attached(t){const{requestUpdate:i}=t;this.lb=i,this.hb=new Image,this.hb.onload=()=>{const t=this.hb?.naturalHeight??1,i=this.hb?.naturalWidth??1;this.qM.forEach((s=>s.ib({nb:t,sb:i,eb:this.hb}))),this.lb&&this.lb()},this.hb.src=this.ab}detached(){this.lb=void 0,this.hb=null}hr(t){this.ys=Ye({...this.ys,...t}),this.ob(),this.YM&&this.YM()}YM(){this.lb&&this.lb()}ob(){this.qM.forEach((t=>t.rb(this.ys)))}}function Xe(t,i,s){return new Ve(t,new Ke(i,s))}class Ze{constructor(t,i){this.Jn=t,this.ah=i,this.WM()}detach(){this.Jn.detachPrimitive(this.ah)}getSeries(){return this.Jn}applyOptions(t){this.ah&&this.ah.hr&&this.ah.hr(t)}WM(){this.Jn.attachPrimitive(this.ah)}}const Ge={autoScale:!0,zOrder:"normal"};function Je(t,i){return Zt(Math.min(Math.max(t,12),30)*i)}function Qe(t,i){switch(t){case"arrowDown":case"arrowUp":return Je(i,1);case"circle":return Je(i,.8);case"square":return Je(i,.7)}}function tr(t){return function(t){const i=Math.ceil(t);return i%2!=0?i-1:i}(Je(t,1))}function ir(t){return Math.max(Je(t,.1),3)}function sr(t,i,s){return i?t:s?Math.ceil(t/2):0}function nr(t,i,s,n){const e=(Qe("arrowUp",n)-1)/2*s._b,r=(Zt(n/2)-1)/2*s._b;i.beginPath(),t?(i.moveTo(s._t-e,s.ut),i.lineTo(s._t,s.ut-e),i.lineTo(s._t+e,s.ut),i.lineTo(s._t+r,s.ut),i.lineTo(s._t+r,s.ut+e),i.lineTo(s._t-r,s.ut+e),i.lineTo(s._t-r,s.ut)):(i.moveTo(s._t-e,s.ut),i.lineTo(s._t,s.ut+e),i.lineTo(s._t+e,s.ut),i.lineTo(s._t+r,s.ut),i.lineTo(s._t+r,s.ut-e),i.lineTo(s._t-r,s.ut-e),i.lineTo(s._t-r,s.ut)),i.fill()}function er(t,i,s,n,e,r){const h=(Qe("arrowUp",n)-1)/2,a=(Zt(n/2)-1)/2;if(e>=i-a-2&&e<=i+a+2&&r>=(t?s:s-h)-2&&r<=(t?s+h:s)+2)return!0;return(()=>{if(ei+h+3||r<(t?s-h-3:s)||r>(t?s:s+h+3))return!1;const n=Math.abs(e-i);return Math.abs(r-s)+3>=n/2})()}class rr{constructor(){this.qt=null,this.Ln=new it,this.F=-1,this.W="",this.Wp="",this.ub="normal"}ht(t){this.qt=t}Nn(t,i,s){this.F===t&&this.W===i||(this.F=t,this.W=i,this.Wp=g(t,i),this.Ln.Vn()),this.ub=s}Yn(t,i){if(null===this.qt||null===this.qt.lt)return null;for(let s=this.qt.lt.from;s{this.et(t)}))}drawBackground(t){"aboveSeries"===this.ub&&t.useBitmapCoordinateSpace((t=>{this.et(t)}))}et({context:t,horizontalPixelRatio:i,verticalPixelRatio:s}){if(null!==this.qt&&null!==this.qt.lt){t.textBaseline="middle",t.font=this.Wp;for(let n=this.qt.lt.from;n=t&&e<=t+s&&r>=i-h&&r<=i+h}(t.ri._t,t.ri.ut,t.ri.Qi,t.ri.$t,i,s))||function(t,i,s){if(0===t.zr)return!1;switch(t.fb){case"arrowDown":return er(!0,t._t,t.ut,t.zr,i,s);case"arrowUp":return er(!1,t._t,t.ut,t.zr,i,s);case"circle":return function(t,i,s,n,e){const r=2+Qe("circle",s)/2,h=t-n,a=i-e;return Math.sqrt(h*h+a*a)<=r}(t._t,t.ut,t.zr,i,s);case"square":return function(t,i,s,n,e){const r=Qe("square",s),h=(r-1)/2,a=t-h,l=i-h;return n>=a&&n<=a+r&&e>=l&&e<=l+r}(t._t,t.ut,t.zr,i,s)}}(t,i,s)}function lr(t){return"atPriceTop"===t||"atPriceBottom"===t||"atPriceMiddle"===t}function or(t,i,s,n,e,r,h,l){const o=function(t,i,s){if(lr(i.position)&&void 0!==i.price)return i.price;if("value"in(n=t)&&"number"==typeof n.value)return t.value;var n;if(function(t){return"open"in t&&"high"in t&&"low"in t&&"close"in t}(t)){if("inBar"===i.position)return t.close;if("aboveBar"===i.position)return s?t.low:t.high;if("belowBar"===i.position)return s?t.high:t.low}}(s,i,h.priceScale().options().invertScale);if(void 0===o)return;const _=lr(i.position),c=l.timeScale(),d=u(i.size)?Math.max(i.size,0):1,f=tr(c.options().barSpacing)*d,p=f/2;t.zr=f;switch(i.position){case"inBar":case"atPriceMiddle":return t.ut=a(h.priceToCoordinate(o)),void(void 0!==t.ri&&(t.ri.ut=t.ut+p+r+.6*e));case"aboveBar":case"atPriceTop":{const i=_?0:n.pb;return t.ut=a(h.priceToCoordinate(o))-p-i,void 0!==t.ri&&(t.ri.ut=t.ut-p-.6*e,n.pb+=1.2*e),void(_||(n.pb+=f+r))}case"belowBar":case"atPriceBottom":{const i=_?0:n.mb;return t.ut=a(h.priceToCoordinate(o))+p+i,void 0!==t.ri&&(t.ri.ut=t.ut+p+r+.6*e,n.mb+=1.2*e),void(_||(n.mb+=f+r))}}}class _r{constructor(t,i,s){this.wb=[],this.St=!0,this.gb=!0,this.Gt=new rr,this.ge=t,this.Ep=i,this.qt={ot:[],lt:null},this.ys=s}renderer(){if(!this.ge.options().visible)return null;this.St&&this.Mb();const t=this.Ep.options().layout;return this.Gt.Nn(t.fontSize,t.fontFamily,this.ys.zOrder),this.Gt.ht(this.qt),this.Gt}bb(t){this.wb=t,this.Pt("data")}Pt(t){this.St=!0,"data"===t&&(this.gb=!0)}xb(t){this.St=!0,this.ys=t}zOrder(){return"aboveSeries"===this.ys.zOrder?"top":this.ys.zOrder}Mb(){const t=this.Ep.timeScale(),i=this.wb;this.gb&&(this.qt.ot=i.map((t=>({wt:t.time,_t:0,ut:0,zr:0,fb:t.shape,R:t.color,Kn:t.id,Sb:t.Sb,ri:void 0}))),this.gb=!1);const s=this.Ep.options().layout;this.qt.lt=null;const n=t.getVisibleLogicalRange();if(null===n)return;const e=new Ci(Math.floor(n.from),Math.ceil(n.to));if(null===this.ge.data()[0])return;if(0===this.qt.ot.length)return;let r=NaN;const h=ir(t.options().barSpacing),l={pb:h,mb:h};this.qt.lt=cn(this.qt.ot,e,!0);for(let n=this.qt.lt.from;n0&&(o.ri={cb:e.text,_t:0,ut:0,Qi:0,$t:0});const _=this.ge.dataByIndex(e.time,0);null!==_&&or(o,e,_,l,s.fontSize,h,this.ge,this.Ep)}this.St=!1}}function ur(t){return{...Ge,...t}}class cr{constructor(t){this.sh=null,this.wb=[],this.Cb=[],this.yb=null,this.ge=null,this.Ep=null,this.Pb=!0,this.kb=null,this.Tb=null,this.Rb=null,this.Db=!0,this.ys=ur(t)}attached(t){this.Eb(),this.Ep=t.chart,this.ge=t.series,this.sh=new _r(this.ge,a(this.Ep),this.ys),this.lb=t.requestUpdate,this.ge.subscribeDataChanged((t=>this.Tg(t))),this.Db=!0,this.YM()}YM(){this.lb&&this.lb()}detached(){this.ge&&this.yb&&this.ge.unsubscribeDataChanged(this.yb),this.Ep=null,this.ge=null,this.sh=null,this.yb=null}bb(t){this.Db=!0,this.wb=t,this.Eb(),this.Pb=!0,this.Tb=null,this.YM()}Vb(){return this.wb}paneViews(){return this.sh?[this.sh]:[]}updateAllViews(){this.Bb()}hitTest(t,i){return this.sh?this.sh.renderer()?.Yn(t,i)??null:null}autoscaleInfo(t,i){if(this.ys.autoScale&&this.sh){const t=this.Ib();if(t)return{priceRange:null,margins:t}}return null}hr(t){this.ys=ur({...this.ys,...t}),this.YM&&this.YM()}Ib(){const t=a(this.Ep).timeScale().options().barSpacing;if(this.Pb||t!==this.Rb){if(this.Rb=t,this.wb.length>0){const i=ir(t),s=1.5*tr(t)+2*i,n=this.Ab();this.kb={above:sr(s,n.aboveBar,n.inBar),below:sr(s,n.belowBar,n.inBar)}}else this.kb=null;this.Pb=!1}return this.kb}Ab(){return null===this.Tb&&(this.Tb=this.wb.reduce(((t,i)=>(t[i.position]||(t[i.position]=!0),t)),{inBar:!1,aboveBar:!1,belowBar:!1,atPriceTop:!1,atPriceBottom:!1,atPriceMiddle:!1})),this.Tb}Eb(){if(!this.Db||!this.Ep||!this.ge)return;const t=this.Ep.timeScale(),i=this.ge?.data();if(null==t.getVisibleLogicalRange()||!this.ge||0===i.length)return void(this.Cb=[]);const s=t.timeToIndex(a(i[0].time),!0);this.Cb=this.wb.map(((i,n)=>{const e=t.timeToIndex(i.time,!0),r=e{this.wb.delete(i),this.Nb()}),s),e={...t,Fb:n,Wb:Date.now()+s};this.wb.set(i,e)}else this.wb.set(i,{...t,Fb:void 0,Wb:void 0});this.Nb()}Lb(t){const i=this.wb.get(t);i&&void 0!==i.Fb&&window.clearTimeout(i.Fb),this.wb.delete(t),this.Nb()}Hb(){for(const[t]of this.wb)this.Lb(t)}Ub(){const t=Date.now(),i=[];for(const[s,n]of this.wb)!n.Wb||n.Wb>t?i.push({time:n.time,sign:n.sign,value:n.value}):this.Lb(s);return i}$b(t){this.zb=t}Nb(){this.zb&&this.zb()}}const vr={positiveColor:"#22AB94",negativeColor:"#F7525F",updateVisibilityDuration:5e3};class mr{constructor(t,i,s,n){this.qt=t,this.jb=i,this.qb=s,this.Yb=n}draw(t){t.useBitmapCoordinateSpace((t=>{const i=t.context,s=Math.max(1,Math.floor(t.horizontalPixelRatio))%2/2,n=4*t.verticalPixelRatio+s;this.qt.forEach((e=>{const r=Math.round(e._t*t.horizontalPixelRatio)+s;i.beginPath();const h=this.Kb(e.Xb);i.fillStyle=h,i.arc(r,e.ut*t.verticalPixelRatio,n,0,2*Math.PI,!1),i.fill(),e.Xb&&(i.strokeStyle=h,i.lineWidth=Math.floor(2*t.horizontalPixelRatio),i.beginPath(),i.moveTo((e._t-4.7)*t.horizontalPixelRatio+s,(e.ut-7*e.Xb)*t.verticalPixelRatio),i.lineTo(e._t*t.horizontalPixelRatio+s,(e.ut-7*e.Xb-7*e.Xb*.5)*t.verticalPixelRatio),i.lineTo((e._t+4.7)*t.horizontalPixelRatio+s,(e.ut-7*e.Xb)*t.verticalPixelRatio),i.stroke())}))}))}Kb(t){return 0===t?this.jb:t>0?this.Yb:this.qb}}class wr{constructor(t,i,s){this.qt=[],this.ge=t,this.uh=i,this.ys=s}Pt(t){this.qt=t.map((t=>{const i=this.ge.priceToCoordinate(t.value);if(null===i)return null;return{_t:a(this.uh.timeToCoordinate(t.time)),ut:i,Xb:t.sign}})).filter(v)}renderer(){const t=function(t,i){return function(t,i){return"Area"===i}(0,i)?t.lineColor:t.color}(this.ge.options(),this.ge.seriesType());return new mr(this.qt,t,this.ys.negativeColor,this.ys.positiveColor)}}function gr(t,i){return"Line"===i||"Area"===i}class Mr{constructor(t){this.Ep=void 0,this.ge=void 0,this.qM=[],this.o_=null,this.Zb=new Map,this.Gb=new pr((()=>this.YM())),this.ys={...vr,...t}}hr(t){this.ys={...this.ys,...t},this.YM()}bb(t){this.Gb.Hb();const i=this.o_;i&&t.forEach((t=>{this.Gb.Ob(t,i.key(t.time))}))}Vb(){return this.Gb.Ub()}YM(){this.lb?.()}attached(t){const{chart:i,series:s,requestUpdate:n,horzScaleBehavior:e}=t;this.Ep=i,this.ge=s,this.o_=e;const r=this.ge.seriesType();if("Area"!==r&&"Line"!==r)throw new Error("UpDownMarkersPrimitive is only supported for Area and Line series types");this.qM=[new wr(this.ge,this.Ep.timeScale(),this.ys)],this.lb=n,this.YM()}detached(){this.Ep=void 0,this.ge=void 0,this.lb=void 0}jp(){return h(this.Ep)}Lo(){return h(this.ge)}updateAllViews(){this.qM.forEach((t=>t.Pt(this.Vb())))}paneViews(){return this.qM}ht(t){if(!this.ge)throw new Error("Primitive not attached to series");const i=this.ge.seriesType();this.Zb.clear();const s=this.o_;s&&t.forEach((t=>{Ys(t)&&gr(0,i)&&this.Zb.set(s.key(t.time),t.value)})),h(this.ge).setData(t)}Pt(t,i){if(!this.ge||!this.o_)throw new Error("Primitive not attached to series");const s=this.ge.seriesType(),n=this.o_.key(t.time);if(qs(t)&&this.Zb.delete(n),Ys(t)&&gr(0,s)){const i=this.Zb.get(n);i&&this.Gb.Ob({time:t.time,value:t.value,sign:br(t.value,i)},n,this.ys.updateVisibilityDuration)}h(this.ge).update(t,i)}Jb(){this.Gb.Hb()}}function br(t,i){return t===i?0:t-i>0?1:-1}class xr extends Ze{setData(t){return this.ah.ht(t)}update(t,i){return this.ah.Pt(t,i)}markers(){return this.ah.Vb()}setMarkers(t){return this.ah.bb(t)}clearMarkers(){return this.ah.Jb()}}function Sr(t,i={}){return new xr(t,new Mr(i))}const Cr={...t,color:"#2196f3"};function yr(){return"5.0.9"}export{be as AreaSeries,ye as BarSeries,we as BaselineSeries,Te as CandlestickSeries,Bi as ColorType,$ as CrosshairMode,Ee as HistogramSeries,Ei as LastPriceAnimationMode,se as LineSeries,s as LineStyle,i as LineType,Ct as MismatchDirection,Vi as PriceLineSource,di as PriceScaleMode,Ii as TickMarkType,Di as TrackingModeExitMode,$n as createChart,Un as createChartEx,Xe as createImageWatermark,ue as createOptionsChart,fr as createSeriesMarkers,He as createTextWatermark,Sr as createUpDownMarkers,le as createYieldCurveChart,Cr as customSeriesDefaultOptions,jn as defaultHorzScaleBehavior,Oi as isBusinessDay,Li as isUTCTimestamp,yr as version}; diff --git a/modules/lightweight-charts/5.0.9/dist/typings.d.ts b/modules/lightweight-charts/5.0.9/dist/typings.d.ts deleted file mode 100644 index a77c8077d..000000000 --- a/modules/lightweight-charts/5.0.9/dist/typings.d.ts +++ /dev/null @@ -1,5000 +0,0 @@ -// Generated by dts-bundle-generator v9.5.1 - -type CanvasRenderingTarget2D = any; - -declare const areaSeries: SeriesDefinition<"Area">; -declare const barSeries: SeriesDefinition<"Bar">; -declare const baselineSeries: SeriesDefinition<"Baseline">; -declare const candlestickSeries: SeriesDefinition<"Candlestick">; -declare const histogramSeries: SeriesDefinition<"Histogram">; -declare const lineSeries: SeriesDefinition<"Line">; -export declare const customSeriesDefaultOptions: CustomSeriesOptions; -/** - * Enumeration representing the sign of a marker. - */ -export declare const enum MarkerSign { - /** Represents a negative change (-1) */ - Negative = -1, - /** Represents no change (0) */ - Neutral = 0, - /** Represents a positive change (1) */ - Positive = 1, -} -/** - * Represents a type of color. - */ -export declare enum ColorType { - /** Solid color */ - Solid = "solid", - /** Vertical gradient color */ - VerticalGradient = "gradient", -} -/** - * Represents the crosshair mode. - */ -export declare enum CrosshairMode { - /** - * This mode allows crosshair to move freely on the chart. - */ - Normal = 0, - /** - * This mode sticks crosshair's horizontal line to the price value of a single-value series or to the close price of OHLC-based series. - */ - Magnet = 1, - /** - * This mode disables rendering of the crosshair. - */ - Hidden = 2, - /** - * This mode sticks crosshair's horizontal line to the price value of a single-value series or to the open/high/low/close price of OHLC-based series. - */ - MagnetOHLC = 3, -} -/** - * Represents the type of the last price animation for series such as area or line. - */ -export declare enum LastPriceAnimationMode { - /** - * Animation is always disabled - */ - Disabled = 0, - /** - * Animation is always enabled. - */ - Continuous = 1, - /** - * Animation is active after new data. - */ - OnDataUpdate = 2, -} -/** - * Represents the possible line styles. - */ -export declare enum LineStyle { - /** - * A solid line. - */ - Solid = 0, - /** - * A dotted line. - */ - Dotted = 1, - /** - * A dashed line. - */ - Dashed = 2, - /** - * A dashed line with bigger dashes. - */ - LargeDashed = 3, - /** - * A dotted line with more space between dots. - */ - SparseDotted = 4, -} -/** - * Represents the possible line types. - */ -export declare enum LineType { - /** - * A line. - */ - Simple = 0, - /** - * A stepped line. - */ - WithSteps = 1, - /** - * A curved line. - */ - Curved = 2, -} -/** - * Search direction if no data found at provided index - */ -export declare enum MismatchDirection { - /** - * Search the nearest left item - */ - NearestLeft = -1, - /** - * Do not search - */ - None = 0, - /** - * Search the nearest right item - */ - NearestRight = 1, -} -/** - * Represents the source of data to be used for the horizontal price line. - */ -export declare enum PriceLineSource { - /** - * Use the last bar data. - */ - LastBar = 0, - /** - * Use the last visible data of the chart viewport. - */ - LastVisible = 1, -} -/** - * Represents the price scale mode. - */ -export declare enum PriceScaleMode { - /** - * Price scale shows prices. Price range changes linearly. - */ - Normal = 0, - /** - * Price scale shows prices. Price range changes logarithmically. - */ - Logarithmic = 1, - /** - * Price scale shows percentage values according the first visible value of the price scale. - * The first visible value is 0% in this mode. - */ - Percentage = 2, - /** - * The same as percentage mode, but the first value is moved to 100. - */ - IndexedTo100 = 3, -} -/** - * Represents the type of a tick mark on the time axis. - */ -export declare enum TickMarkType { - /** - * The start of the year (e.g. it's the first tick mark in a year). - */ - Year = 0, - /** - * The start of the month (e.g. it's the first tick mark in a month). - */ - Month = 1, - /** - * A day of the month. - */ - DayOfMonth = 2, - /** - * A time without seconds. - */ - Time = 3, - /** - * A time with seconds. - */ - TimeWithSeconds = 4, -} -/** - * Determine how to exit the tracking mode. - * - * By default, mobile users will long press to deactivate the scroll and have the ability to check values and dates. - * Another press is required to activate the scroll, be able to move left/right, zoom, etc. - */ -export declare enum TrackingModeExitMode { - /** - * Tracking Mode will be deactivated on touch end event. - */ - OnTouchEnd = 0, - /** - * Tracking Mode will be deactivated on the next tap event. - */ - OnNextTap = 1, -} -/** - * This function is the simplified main entry point of the Lightweight Charting Library with time points for the horizontal scale. - * - * @param container - ID of HTML element or element itself - * @param options - Any subset of options to be applied at start. - * @returns An interface to the created chart - */ -export declare function createChart( - container: string | HTMLElement, - options?: DeepPartial, -): IChartApi; -/** - * This function is the main entry point of the Lightweight Charting Library. If you are using time values - * for the horizontal scale then it is recommended that you rather use the {@link createChart} function. - * - * @template HorzScaleItem - type of points on the horizontal scale - * @template THorzScaleBehavior - type of horizontal axis strategy that encapsulate all the specific behaviors of the horizontal scale type - * - * @param container - ID of HTML element or element itself - * @param horzScaleBehavior - Horizontal scale behavior - * @param options - Any subset of options to be applied at start. - * @returns An interface to the created chart - */ -export declare function createChartEx< - HorzScaleItem, - THorzScaleBehavior extends IHorzScaleBehavior, ->( - container: string | HTMLElement, - horzScaleBehavior: THorzScaleBehavior, - options?: DeepPartial>, -): IChartApiBase; -/** - * Creates an image watermark. - * - * @param pane - Target pane. - * @param imageUrl - Image URL. - * @param options - Watermark options. - * - * @returns Image watermark wrapper. - * - * @example - * ```js - * import { createImageWatermark } from 'lightweight-charts'; - * - * const firstPane = chart.panes()[0]; - * const imageWatermark = createImageWatermark(firstPane, '/images/my-image.png', { - * alpha: 0.5, - * padding: 20, - * }); - * // to change options - * imageWatermark.applyOptions({ padding: 10 }); - * // to remove watermark from the pane - * imageWatermark.detach(); - * ``` - */ -export declare function createImageWatermark( - pane: IPaneApi, - imageUrl: string, - options: DeepPartial, -): IImageWatermarkPluginApi; -/** - * Creates an 'options' chart with price values on the horizontal scale. - * - * This function is used to create a specialized chart type where the horizontal scale - * represents price values instead of time. It's particularly useful for visualizing - * option chains, price distributions, or any data where price is the primary x-axis metric. - * - * @param container - The DOM element or its id where the chart will be rendered. - * @param options - Optional configuration options for the price chart. - * @returns An instance of IChartApiBase configured for price-based horizontal scaling. - */ -export declare function createOptionsChart( - container: string | HTMLElement, - options?: DeepPartial, -): IChartApiBase; -/** - * A function to create a series markers primitive. - * - * @param series - The series to which the primitive will be attached. - * - * @param markers - An array of markers to be displayed on the series. - * - * @param options - Options for the series markers plugin. - * - * @example - * ```js - * import { createSeriesMarkers } from 'lightweight-charts'; - * - * const seriesMarkers = createSeriesMarkers( - * series, - * [ - * { - * color: 'green', - * position: 'inBar', - * shape: 'arrowDown', - * time: 1556880900, - * }, - * ] - * ); - * // and then you can modify the markers - * // set it to empty array to remove all markers - * seriesMarkers.setMarkers([]); - * - * // `seriesMarkers.markers()` returns current markers - * ``` - */ -export declare function createSeriesMarkers( - series: ISeriesApi, - markers?: SeriesMarker[], - options?: DeepPartial, -): ISeriesMarkersPluginApi; -/** - * Creates an image watermark. - * - * @param pane - Target pane. - * @param options - Watermark options. - * - * @returns Image watermark wrapper. - * - * @example - * ```js - * import { createTextWatermark } from 'lightweight-charts'; - * - * const firstPane = chart.panes()[0]; - * const textWatermark = createTextWatermark(firstPane, { - * horzAlign: 'center', - * vertAlign: 'center', - * lines: [ - * { - * text: 'Hello', - * color: 'rgba(255,0,0,0.5)', - * fontSize: 100, - * fontStyle: 'bold', - * }, - * { - * text: 'This is a text watermark', - * color: 'rgba(0,0,255,0.5)', - * fontSize: 50, - * fontStyle: 'italic', - * fontFamily: 'monospace', - * }, - * ], - * }); - * // to change options - * textWatermark.applyOptions({ horzAlign: 'left' }); - * // to remove watermark from the pane - * textWatermark.detach(); - * ``` - */ -export declare function createTextWatermark( - pane: IPaneApi, - options: DeepPartial, -): ITextWatermarkPluginApi; -/** - * Creates and attaches the Series Up Down Markers Plugin. - * - * @param series - Series to which attach the Up Down Markers Plugin - * @param options - options for the Up Down Markers Plugin - * - * @returns Api for Series Up Down Marker Plugin. {@link ISeriesUpDownMarkerPluginApi} - * - * @example - * ```js - * import { createUpDownMarkers, createChart, LineSeries } from 'lightweight-charts'; - * - * const chart = createChart('container'); - * const lineSeries = chart.addSeries(LineSeries); - * const upDownMarkers = createUpDownMarkers(lineSeries, { - * positiveColor: '#22AB94', - * negativeColor: '#F7525F', - * updateVisibilityDuration: 5000, - * }); - * // to add some data - * upDownMarkers.setData( - * [ - * { time: '2020-02-02', value: 12.34 }, - * //... more line series data - * ] - * ); - * // ... Update some values - * upDownMarkers.update({ time: '2020-02-02', value: 13.54 }, true); - * // to remove plugin from the series - * upDownMarkers.detach(); - * ``` - */ -export declare function createUpDownMarkers( - series: ISeriesApi, - options?: Partial, -): ISeriesUpDownMarkerPluginApi; -/** - * Creates a yield curve chart with the specified options. - * - * A yield curve chart differs from the default chart type - * in the following ways: - * - Horizontal scale is linearly spaced, and defined in monthly - * time duration units - * - Whitespace is ignored for the crosshair and grid lines - * - * @param container - ID of HTML element or element itself - * @param options - The yield chart options. - * @returns An interface to the created chart - */ -export declare function createYieldCurveChart( - container: string | HTMLElement, - options?: DeepPartial, -): IYieldCurveChartApi; -/** - * Provides the default implementation of the horizontal scale (time-based) that can be used as a base for extending the horizontal scale with custom behavior. - * This allows for the introduction of custom functionality without re-implementing the entire {@link IHorzScaleBehavior}<{@link Time}> interface. - * - * For further details, refer to the {@link createChartEx} chart constructor method. - * - * @returns An uninitialized class implementing the {@link IHorzScaleBehavior}<{@link Time}> interface - */ -export declare function defaultHorzScaleBehavior(): new () => IHorzScaleBehavior