diff --git a/Cargo.lock b/Cargo.lock index a0941d972f..f2650c16b4 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -209,9 +209,9 @@ checksum = "c08606f8c3cbf4ce6ec8e28fb0014a2c086708fe954eaa885384a6165172e7e8" [[package]] name = "aws-lc-rs" -version = "1.16.2" +version = "1.16.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a054912289d18629dc78375ba2c3726a3afe3ff71b4edba9dedfca0e3446d1fc" +checksum = "d9a7b350e3bb1767102698302bc37256cbd48422809984b98d292c40e2579aa9" dependencies = [ "aws-lc-sys", "zeroize", @@ -219,9 +219,9 @@ dependencies = [ [[package]] name = "aws-lc-sys" -version = "0.39.0" +version = "0.37.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1fa7e52a4c5c547c741610a2c6f123f3881e409b714cd27e6798ef020c514f0a" +checksum = "b092fe214090261288111db7a2b2c2118e5a7f30dc2569f1732c4069a6840549" dependencies = [ "cc", "cmake", @@ -354,7 +354,7 @@ version = "0.6.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "cdeb9d870516001442e364c5220d3574d2da8dc765554b4a617230d33fa58ef5" dependencies = [ - "objc2 0.6.4", + "objc2 0.6.3", ] [[package]] @@ -421,9 +421,9 @@ checksum = "8f1fe948ff07f4bd06c30984e69f5b4899c516a3ef74f34df92a2df2ab535495" [[package]] name = "bytes" -version = "1.11.1" +version = "1.10.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1e748733b7cbc798e1434b6ac524f0c1ff2ab456fe201501e6497c8417a4fc33" +checksum = "d71b6127be86fdcfddb610f7182ac57211d4b18a3e9c82eb2d17662f2227ad6a" [[package]] name = "bzip2" @@ -582,7 +582,7 @@ dependencies = [ "clap", "libc", "libloading 0.9.0", - "objc2 0.6.4", + "objc2 0.6.3", "objc2-foundation 0.3.2", "objc2-io-surface", "objc2-metal 0.3.2", @@ -1120,9 +1120,9 @@ checksum = "be1e0bca6c3637f992fc1cc7cbc52a78c1ef6db076dbf1059c4323d6a2048376" [[package]] name = "deranged" -version = "0.5.8" +version = "0.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7cd812cc2bc1d69d4764bd80df88b4317eaef9e773c75226407d9bc0876b211c" +checksum = "9c9e6a11ca8224451684bc0d7d5a7adbf8f2fd6887261a1cfc3c0432f9d4068e" dependencies = [ "powerfmt", ] @@ -1213,7 +1213,7 @@ dependencies = [ "bitflags 2.11.0", "block2 0.6.2", "libc", - "objc2 0.6.4", + "objc2 0.6.3", ] [[package]] @@ -1994,6 +1994,8 @@ version = "0.1.0" dependencies = [ "chrono", "clap", + "document-container", + "document-format", "fern", "futures", "graph-craft", @@ -2142,7 +2144,7 @@ dependencies = [ "interprocess", "lzma-rust2", "muda", - "objc2 0.6.4", + "objc2 0.6.3", "objc2-app-kit 0.3.2", "objc2-foundation 0.3.2", "open", @@ -3282,7 +3284,7 @@ dependencies = [ "crossbeam-channel", "dpi", "keyboard-types", - "objc2 0.6.4", + "objc2 0.6.3", "objc2-app-kit 0.3.2", "objc2-core-foundation", "objc2-foundation 0.3.2", @@ -3451,9 +3453,9 @@ dependencies = [ [[package]] name = "num-conv" -version = "0.2.0" +version = "0.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cf97ec579c3c42f953ef76dbf8d55ac91fb219dde70e49aa4a6b7d74e9919050" +checksum = "51d515d32fb182ee37cda2ccdcb92950d6a3c2893aa280e540671c2cd0f3b1d9" [[package]] name = "num-derive" @@ -3525,9 +3527,9 @@ dependencies = [ [[package]] name = "objc2" -version = "0.6.4" +version = "0.6.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3a12a8ed07aefc768292f076dc3ac8c48f3781c8f2d5851dd3d98950e8c5a89f" +checksum = "b7c2599ce0ec54857b29ce62166b0ed9b4f6f1a70ccc9a71165b6154caca8c05" dependencies = [ "objc2-encode", ] @@ -3556,7 +3558,7 @@ checksum = "d49e936b501e5c5bf01fda3a9452ff86dc3ea98ad5f283e1455153142d97518c" dependencies = [ "bitflags 2.11.0", "block2 0.6.2", - "objc2 0.6.4", + "objc2 0.6.3", "objc2-core-foundation", "objc2-foundation 0.3.2", ] @@ -3582,7 +3584,7 @@ dependencies = [ "bitflags 2.11.0", "block2 0.6.2", "dispatch2", - "objc2 0.6.4", + "objc2 0.6.3", ] [[package]] @@ -3646,7 +3648,7 @@ dependencies = [ "bitflags 2.11.0", "block2 0.6.2", "libc", - "objc2 0.6.4", + "objc2 0.6.3", "objc2-core-foundation", ] @@ -3658,7 +3660,7 @@ checksum = "180788110936d59bab6bd83b6060ffdfffb3b922ba1396b312ae795e1de9d81d" dependencies = [ "bitflags 2.11.0", "libc", - "objc2 0.6.4", + "objc2 0.6.3", "objc2-core-foundation", "objc2-foundation 0.3.2", ] @@ -3684,7 +3686,7 @@ dependencies = [ "bitflags 2.11.0", "block2 0.6.2", "dispatch2", - "objc2 0.6.4", + "objc2 0.6.3", "objc2-core-foundation", "objc2-foundation 0.3.2", "objc2-io-surface", @@ -3710,7 +3712,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "96c1358452b371bf9f104e21ec536d37a650eb10f7ee379fff67d2e08d537f1f" dependencies = [ "bitflags 2.11.0", - "objc2 0.6.4", + "objc2 0.6.3", "objc2-core-foundation", "objc2-foundation 0.3.2", "objc2-metal 0.3.2", @@ -3723,7 +3725,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d87d638e33c06f577498cbcc50491496a3ed4246998a7fbba7ccb98b1e7eab22" dependencies = [ "bitflags 2.11.0", - "objc2 0.6.4", + "objc2 0.6.3", "objc2-core-foundation", "objc2-foundation 0.3.2", ] @@ -4500,7 +4502,7 @@ version = "1.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "40d213455a5f1dc59214213c7330e074ddf8114c9a42411eb890c767357ce135" dependencies = [ - "objc2 0.6.4", + "objc2 0.6.3", "objc2-core-foundation", "objc2-foundation 0.3.2", "objc2-quartz-core 0.3.2", @@ -4699,7 +4701,7 @@ dependencies = [ "js-sys", "libc", "log", - "objc2 0.6.4", + "objc2 0.6.3", "objc2-app-kit 0.3.2", "objc2-core-foundation", "objc2-foundation 0.3.2", @@ -4843,9 +4845,9 @@ dependencies = [ [[package]] name = "rustls" -version = "0.23.37" +version = "0.23.31" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "758025cb5fccfd3bc2fd74708fd4682be41d99e5dff73c377c0646c6012c73a4" +checksum = "c0ebcbd2f03de0fc1122ad9bb24b127a5a6cd51d72604a3f3c50ac459762b6cc" dependencies = [ "aws-lc-rs", "log", @@ -4917,9 +4919,9 @@ checksum = "f87165f0995f63a9fbeea62b64d10b4d9d8e78ec6d7d51fb2125fda7bb36788f" [[package]] name = "rustls-webpki" -version = "0.103.10" +version = "0.103.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "df33b2b81ac578cabaf06b89b0631153a3f416b0a886e8a7a1707fb51abbd1ef" +checksum = "0a17884ae0c1b773f1ccd2bd4a8c72f16da897310a98b0e84bf349ad5ead92fc" dependencies = [ "aws-lc-rs", "ring", @@ -5702,30 +5704,30 @@ dependencies = [ [[package]] name = "time" -version = "0.3.47" +version = "0.3.41" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "743bd48c283afc0388f9b8827b976905fb217ad9e647fae3a379a9283c4def2c" +checksum = "8a7619e19bc266e0f9c5e6686659d394bc57973859340060a69221e57dbc0c40" dependencies = [ "deranged", "itoa", "num-conv", "powerfmt", - "serde_core", + "serde", "time-core", "time-macros", ] [[package]] name = "time-core" -version = "0.1.8" +version = "0.1.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7694e1cfe791f8d31026952abf09c69ca6f6fa4e1a1229e18988f06a04a12dca" +checksum = "c9e9a38711f559d9e3ce1cdb06dd7c5b8ea546bc90052da6d06bb76da74bb07c" [[package]] name = "time-macros" -version = "0.2.27" +version = "0.2.22" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2e70e4c5a0e0a8a4823ad65dfe1a6930e4f4d756dcd9dd7939022b5e8c501215" +checksum = "3526739392ec93fd8b359c8e98514cb3e8e021beb4e5f597b00a0221f8ed8a49" dependencies = [ "num-conv", "time-core", @@ -6784,7 +6786,7 @@ dependencies = [ "log", "naga", "ndk-sys", - "objc2 0.6.4", + "objc2 0.6.3", "objc2-core-foundation", "objc2-foundation 0.3.2", "objc2-metal 0.3.2", @@ -7390,7 +7392,7 @@ dependencies = [ "block2 0.6.2", "dispatch2", "dpi", - "objc2 0.6.4", + "objc2 0.6.3", "objc2-app-kit 0.3.2", "objc2-core-foundation", "objc2-core-graphics", @@ -7409,7 +7411,7 @@ version = "0.30.12" source = "git+https://github.com/rust-windowing/winit.git#bd6fef1d80ba063cbe91e150b3fb343927cdc72b" dependencies = [ "memmap2 0.9.10", - "objc2 0.6.4", + "objc2 0.6.3", "objc2-core-foundation", "smol_str", "tracing", @@ -7457,7 +7459,7 @@ dependencies = [ "block2 0.6.2", "dispatch2", "dpi", - "objc2 0.6.4", + "objc2 0.6.3", "objc2-core-foundation", "objc2-foundation 0.3.2", "objc2-ui-kit", diff --git a/Cargo.toml b/Cargo.toml index de58ceffcc..6f1c3af456 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -7,8 +7,8 @@ members = [ "desktop/platform/linux", "desktop/platform/mac", "desktop/platform/win", - "document/container", "document/graph-storage", + "document/container", "document/document-format", "editor", "frontend/wrapper", @@ -106,6 +106,7 @@ rustc-hash = "2.0" bytemuck = { version = "1.13", features = ["derive", "min_const_generics"] } serde = { version = "1.0", features = ["derive", "rc"] } serde_json = "1.0" +rmp-serde = "1.3" serde_bytes = "0.11" serde-wasm-bindgen = "0.6" reqwest = { version = "0.13", features = ["blocking", "json"] } @@ -172,7 +173,6 @@ color = "0.3" # Linebender ecosystem (END) rand = { version = "0.9", default-features = false, features = ["std_rng"] } rand_chacha = "0.9" -rmp-serde = "1.3" glam = { version = "0.32.1", default-features = false, features = [ "nostd-libm", "scalar-math", diff --git a/editor/src/node_graph_executor/runtime.rs b/editor/src/node_graph_executor/runtime.rs index 6faf330a37..d799b3817d 100644 --- a/editor/src/node_graph_executor/runtime.rs +++ b/editor/src/node_graph_executor/runtime.rs @@ -348,7 +348,7 @@ impl NodeRuntime { async fn update_network(&mut self, graph: NodeNetwork) -> Result { let mut scoped_network = wrap_network_in_scope(graph, self.editor_api.clone()); - if let Err(e) = self.preprocessor.preprocess(&mut scoped_network, &self.resources) { + if let Err(e) = self.preprocessor.preprocess(&mut scoped_network, &|resource_id| self.resources.hash(&resource_id)) { return Err((ResolvedDocumentNodeTypesDelta::default(), e.to_string())); } diff --git a/node-graph/graph-craft/src/lib.rs b/node-graph/graph-craft/src/lib.rs index 787b6789aa..de33be0e45 100644 --- a/node-graph/graph-craft/src/lib.rs +++ b/node-graph/graph-craft/src/lib.rs @@ -7,6 +7,7 @@ pub use core_types::{ProtoNodeIdentifier, Type, TypeDescriptor, concrete, descri pub mod application_io; pub mod document; +pub use document::{DocumentNode, NodeNetwork}; pub mod graphene_compiler; pub mod proto; #[cfg(feature = "loading")] diff --git a/node-graph/graphene-cli/Cargo.toml b/node-graph/graphene-cli/Cargo.toml index 05e3b78705..5a7b82b9c3 100644 --- a/node-graph/graphene-cli/Cargo.toml +++ b/node-graph/graphene-cli/Cargo.toml @@ -17,6 +17,8 @@ graphene-std = { workspace = true } interpreted-executor = { workspace = true } graph-craft = { workspace = true, features = ["loading"] } preprocessor = { workspace = true } +document-format = { workspace = true, features = ["zip", "xz"] } +document-container = { workspace = true, features = ["zip", "xz"] } # Workspace dependencies log = { workspace = true } diff --git a/node-graph/graphene-cli/src/main.rs b/node-graph/graphene-cli/src/main.rs index 7c876c5d6a..673b0c3aa2 100644 --- a/node-graph/graphene-cli/src/main.rs +++ b/node-graph/graphene-cli/src/main.rs @@ -1,6 +1,9 @@ mod export; use clap::{Args, Parser, Subcommand}; +use document_container::AnyContainer; +use document_container::backends::memory::MemoryBackend; +use document_format::{GddV1, GddV1Layout}; use fern::colors::{Color, ColoredLevelConfig}; use futures::executor::block_on; use graph_craft::application_io::EditorPreferences; @@ -84,6 +87,11 @@ enum Command { duration: Option, }, ListNodeIdentifiers, + + /// Extract embedded legacy .graphite file from the new .gdd file + ExtractLegacyDoc { + document: PathBuf, + }, } #[derive(Debug, Args)] @@ -104,6 +112,7 @@ async fn main() -> Result<(), Box> { let document_path = match app.command { Command::Compile { ref document, .. } => document, Command::Export { ref document, .. } => document, + Command::ExtractLegacyDoc { ref document } => document, Command::ListNodeIdentifiers => { let mut nodes: Vec<_> = graphene_std::registry::NODE_METADATA.lock().unwrap().keys().cloned().collect(); nodes.sort_by_key(|x| x.as_str().to_string()); @@ -114,10 +123,51 @@ async fn main() -> Result<(), Box> { } }; - let document_string = std::fs::read_to_string(document_path).expect("Failed to read document"); + // Load the document by extension: `.gdd` opens the new archive format, anything else is treated as a + // legacy `.graphite` document. The legacy path has no `Gdd`, so resources fall back to the default registry. + let is_gdd = document_path.extension().is_some_and(|extension| extension.eq_ignore_ascii_case("gdd")); + + let gdd = if is_gdd { + let archive = std::fs::read(document_path).map_err(|error| format!("Failed to read document {}: {error}", document_path.display()))?; + let container = AnyContainer::Memory(MemoryBackend::new()); + let gdd = document_format::Gdd::open_from_archive(archive.as_ref(), container, GddV1Layout) + .await + .map_err(|error| format!("Failed to open document: {error}"))?; + Some(gdd) + } else { + None + }; + + if let Command::ExtractLegacyDoc { ref document } = app.command { + let Some(gdd) = &gdd else { return Err("ExtractLegacyDoc requires a .gdd document".into()) }; + let Some(legacy_doc) = gdd.read_legacy_document().await else { + return Err("gdd file did not contain a legacy .graphite document".into()); + }; + let mut new_path = document.clone(); + new_path.set_extension("graphite"); + std::fs::write(&new_path, legacy_doc).map_err(|error| format!("Failed to write .graphite file: {error}"))?; + eprintln!("Saved file to {}", new_path.to_string_lossy()); + return Ok(()); + } + + // Build the runtime network: from the `.gdd` registry, or by loading a legacy `.graphite` document. + let node_network = match &gdd { + Some(gdd) => { + let declarations = gdd.declarations(gdd).await; + let (node_network, _metadata) = gdd.registry().to_runtime_with_metadata(&declarations)?; + node_network + } + None => { + let document_string = std::fs::read_to_string(document_path).map_err(|error| format!("Failed to read document {}: {error}", document_path.display()))?; + load_network(&document_string) + } + }; log::info!("Creating GPU context"); - let application_io = block_on(PlatformApplicationIo::new()); + let mut application_io = PlatformApplicationIo::new().await; + if let Some(gdd) = &gdd { + application_io.inject_resource_proxy(Box::new(gdd.resource_proxy())); + } // Convert application_io to Arc first let application_io_arc = Arc::new(application_io); @@ -137,8 +187,7 @@ async fn main() -> Result<(), Box> { node_graph_message_sender: Box::new(UpdateLogger {}), editor_preferences: Box::new(preferences), }); - - let proto_graph = compile_graph(document_string, editor_api)?; + let proto_graph = compile_graph(node_network, editor_api, gdd.as_ref())?; match app.command { Command::Compile { print_proto, .. } => { @@ -218,37 +267,22 @@ fn init_logging(log_level: u8) { .unwrap(); } -// Migrations are done in the editor which is unfortunately not available here. -// TODO: remove this and share migrations between the editor and the CLI. -fn fix_nodes(network: &mut NodeNetwork) { - for node in network.nodes.values_mut() { - match &mut node.implementation { - // Recursively fix - DocumentNodeImplementation::Network(network) => fix_nodes(network), - // This replicates the migration from the editor linked: - // https://github.com/GraphiteEditor/Graphite/blob/d68f91ccca69e90e6d2df78d544d36cd1aaf348e/editor/src/messages/portfolio/portfolio_message_handler.rs#L535 - // Since the CLI doesn't have the document node definitions, a less robust method of just patching the inputs is used. - DocumentNodeImplementation::ProtoNode(proto_node_identifier) - if (proto_node_identifier.as_str().starts_with("graphene_core::ConstructLayerNode") || proto_node_identifier.as_str().starts_with("graphene_core::AddArtboardNode")) - && node.inputs.len() < 3 => - { - node.inputs.push(NodeInput::Reflection(DocumentNodeMetadata::DocumentNodePath)); - } - _ => {} - } - } -} -fn compile_graph(document_string: String, editor_api: Arc) -> Result> { - let mut network = load_network(&document_string); - fix_nodes(&mut network); +fn compile_graph(network: NodeNetwork, editor_api: Arc, gdd: Option<&GddV1>) -> Result> { + let preprocessor = preprocessor::Preprocessor::new(); - let mut wrapped_network = wrap_network_in_scope(network, editor_api); + let mut network = wrap_network_in_scope(network, editor_api); - let preprocessor = preprocessor::Preprocessor::new(); - preprocessor.preprocess(&mut wrapped_network, &ResourceRegistry::default()).expect("Failed to expand network"); // TODO: actually load the resources from the document + // A `.gdd` resolves resource hashes from its registry; a legacy `.graphite` has no resource store, so it + // preprocesses against an empty registry (matching the pre-`.gdd` CLI behavior). + match gdd { + Some(gdd) => preprocessor + .preprocess(&mut network, &|resource_id| gdd.registry().resources.get(&resource_id).and_then(|r| r.hash)) + .expect("Failed to expand network"), + None => { preprocessor.preprocess(&mut network, &|_| None) }.expect("Failed to expand network"), + } let compiler = Compiler {}; - compiler.compile_single(wrapped_network).map_err(|x| x.into()) + compiler.compile_single(network).map_err(|x| x.into()) } fn create_executor(proto_network: ProtoNetwork) -> Result> { diff --git a/node-graph/interpreted-executor/benches/benchmark_util.rs b/node-graph/interpreted-executor/benches/benchmark_util.rs index 08099719cf..54449ff13e 100644 --- a/node-graph/interpreted-executor/benches/benchmark_util.rs +++ b/node-graph/interpreted-executor/benches/benchmark_util.rs @@ -4,7 +4,6 @@ use futures::executor::block_on; use graph_craft::proto::ProtoNetwork; use graph_craft::util::{DEMO_ART, compile, load_from_name}; use graphene_std::application_io::EditorApi; -use graphene_std::application_io::resource::ResourceRegistry; use interpreted_executor::dynamic_executor::DynamicExecutor; use interpreted_executor::util::wrap_network_in_scope; @@ -13,7 +12,7 @@ pub fn setup_network(name: &str) -> (DynamicExecutor, ProtoNetwork) { let editor_api = std::sync::Arc::new(EditorApi::default()); let mut network = wrap_network_in_scope(network, editor_api); let preprocessor = preprocessor::Preprocessor::new(); - preprocessor.preprocess(&mut network, &ResourceRegistry::default()).unwrap(); + preprocessor.preprocess(&mut network, &|_| None).unwrap(); let proto_network = compile(network); let executor = block_on(DynamicExecutor::new(proto_network.clone())).unwrap(); (executor, proto_network) diff --git a/node-graph/preprocessor/src/lib.rs b/node-graph/preprocessor/src/lib.rs index 4017629ae3..4e543a7b7a 100644 --- a/node-graph/preprocessor/src/lib.rs +++ b/node-graph/preprocessor/src/lib.rs @@ -2,11 +2,12 @@ extern crate log; use graph_craft::Type; -use graph_craft::application_io::resource::{ResourceId, ResourceRegistry}; +use graph_craft::application_io::resource::ResourceId; use graph_craft::document::value::*; use graph_craft::document::*; use graph_craft::proto::RegistryValueSource; use graph_craft::{ProtoNodeIdentifier, concrete}; +use graphene_std::platform_application_io::ResourceHash; use graphene_std::registry::*; use graphene_std::*; use std::collections::{HashMap, HashSet}; @@ -19,9 +20,9 @@ pub struct Preprocessor { } impl Preprocessor { - pub fn preprocess(&self, network: &mut NodeNetwork, resources: &ResourceRegistry) -> Result<(), PreprocessorError> { + pub fn preprocess(&self, network: &mut NodeNetwork, resolve_resource: &dyn Fn(ResourceId) -> Option) -> Result<(), PreprocessorError> { self.insert_inject_scopes(network); - self.replace_resource_inputs(network, resources)?; + self.replace_resource_inputs(network, resolve_resource)?; self.expand_network(network); Ok(()) } @@ -41,13 +42,13 @@ impl Preprocessor { } /// Replace every `TaggedValue::Resource(hash)` input with a reference to a freshly inserted `resource` proto node. - fn replace_resource_inputs(&self, network: &mut NodeNetwork, resources: &ResourceRegistry) -> Result<(), PreprocessorError> { + fn replace_resource_inputs(&self, network: &mut NodeNetwork, resolve_resource: &dyn Fn(ResourceId) -> Option) -> Result<(), PreprocessorError> { let mut hash_to_node_id: HashMap = HashMap::new(); let mut new_resource_nodes: Vec<(NodeId, DocumentNode)> = Vec::new(); for node in network.nodes.values_mut() { if let DocumentNodeImplementation::Network(nested) = &mut node.implementation { - self.replace_resource_inputs(nested, resources)?; + self.replace_resource_inputs(nested, resolve_resource)?; continue; } @@ -59,7 +60,7 @@ impl Preprocessor { let NodeInput::Value { tagged_value, .. } = input else { continue }; let TaggedValue::Resource(resource_id) = **tagged_value else { continue }; - let Some(hash) = resources.hash(&resource_id) else { + let Some(hash) = resolve_resource(resource_id) else { return Err(PreprocessorError::ResourceNotFound(resource_id)); };