From b1990a3b63ab0a05133e5450c1d847dc8c591b25 Mon Sep 17 00:00:00 2001 From: tmathern <60901087+tmathern@users.noreply.github.com> Date: Thu, 6 Feb 2025 14:02:47 -0800 Subject: [PATCH 01/35] feat: c2patool to read cawg data (#904) * ci: Add debug statements * Omit additional paddings * feat: Omit more padding tags * ci: add explanation * ci: Catch result strings before they get returned * ci: sdk catch result string before returning them * ci: look into parsing stuff * ci: WIP for cawg display * ci: Replace signature with hash * ci: Replace signature with hash * ci: Clean up leftover debug code * ci: Parse cawg data in cli, introduce tokio * ci: WIP * ci: WIP * ci: Up some deps * ci: WIP * ci: WIP * feat: Add methods to reader to decorate the json * ci: Got the cleaned content signature * ci: Some clean up * ci: Some clean up * ci: WIP * feat: cawg parsing hack * feat: move display * feat: Refactor * feat: Refactor * feat: Refactor * ci: Tmp check all other tests * ci: Tmp check all other tests * Debug * fix: fix mistake of returning too early * fix: Remove debug file * fix: Remove debug file * fix: Change error handling --- Cargo.lock | 2 + Makefile | 2 + .../ica_signature_verifier.rs | 2 +- .../src/claim_aggregation/w3c_vc/did_web.rs | 2 +- .../claim_aggregation/w3c_vc/serialization.rs | 2 - cli/Cargo.toml | 2 + cli/src/main.rs | 155 +++++++++++++++++- cli/tests/fixtures/C_with_CAWG_data.jpg | Bin 0 -> 141901 bytes sdk/Cargo.toml | 2 +- sdk/src/error.rs | 3 + sdk/src/hashed_uri.rs | 6 +- sdk/src/manifest_store.rs | 6 + sdk/src/reader.rs | 14 +- 13 files changed, 184 insertions(+), 14 deletions(-) create mode 100644 cli/tests/fixtures/C_with_CAWG_data.jpg diff --git a/Cargo.lock b/Cargo.lock index f8fcd7b73..a87cd69ec 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -857,6 +857,7 @@ dependencies = [ "atree", "c2pa", "c2pa-crypto", + "cawg-identity", "clap", "env_logger", "glob", @@ -871,6 +872,7 @@ dependencies = [ "serde_derive", "serde_json", "tempfile", + "tokio", "treeline", "url", ] diff --git a/Makefile b/Makefile index e3f8b0a81..9b54d8294 100644 --- a/Makefile +++ b/Makefile @@ -31,6 +31,8 @@ test-wasm: test-wasm-web: cd sdk && wasm-pack test --chrome --headless -- --features="serialize_thumbnails" +test-no-wasm: check-format check-docs clippy test-local + # Full local validation, build and test all features including wasm # Run this before pushing a PR to pre-validate test: check-format check-docs clippy test-local test-wasm-web diff --git a/cawg_identity/src/claim_aggregation/ica_signature_verifier.rs b/cawg_identity/src/claim_aggregation/ica_signature_verifier.rs index 7b4fc2ff0..d9a5c341f 100644 --- a/cawg_identity/src/claim_aggregation/ica_signature_verifier.rs +++ b/cawg_identity/src/claim_aggregation/ica_signature_verifier.rs @@ -153,7 +153,7 @@ impl SignatureVerifier for IcaSignatureVerifier { )); }; - dbg!(&jwk_prop); + // dbg!(&jwk_prop); // OMG SO HACKY! let Ok(jwk_json) = serde_json::to_string_pretty(jwk_prop) else { diff --git a/cawg_identity/src/claim_aggregation/w3c_vc/did_web.rs b/cawg_identity/src/claim_aggregation/w3c_vc/did_web.rs index 4dbe6ac71..68c9d5702 100644 --- a/cawg_identity/src/claim_aggregation/w3c_vc/did_web.rs +++ b/cawg_identity/src/claim_aggregation/w3c_vc/did_web.rs @@ -68,7 +68,7 @@ pub(crate) async fn resolve(did: &Did<'_>) -> Result { let method_specific_id = did.method_specific_id(); - dbg!(method_specific_id); + //dbg!(method_specific_id); let url = to_url(method_specific_id)?; // TODO: https://w3c-ccg.github.io/did-method-web/#in-transit-security diff --git a/cawg_identity/src/claim_aggregation/w3c_vc/serialization.rs b/cawg_identity/src/claim_aggregation/w3c_vc/serialization.rs index 2ea80288d..21fe2a5dd 100644 --- a/cawg_identity/src/claim_aggregation/w3c_vc/serialization.rs +++ b/cawg_identity/src/claim_aggregation/w3c_vc/serialization.rs @@ -57,8 +57,6 @@ pub(crate) mod one_or_many { where M: de::MapAccess<'de>, { - eprintln!("Yo!"); - let one = Deserialize::deserialize(de::value::MapAccessDeserializer::new(map))?; Ok(nev!(one)) diff --git a/cli/Cargo.toml b/cli/Cargo.toml index 7e8945b13..5ec25b479 100644 --- a/cli/Cargo.toml +++ b/cli/Cargo.toml @@ -22,6 +22,7 @@ unexpected_cfgs = { level = "warn", check-cfg = ['cfg(test)'] } [dependencies] anyhow = "1.0" atree = "0.5.2" +cawg-identity = { path = "../cawg_identity"} c2pa = { path = "../sdk", version = "0.45.1", features = [ "fetch_remote_manifests", "file_io", @@ -37,6 +38,7 @@ serde = { version = "1.0", features = ["derive"] } serde_derive = "1.0" serde_json = "1.0" tempfile = "3.3" +tokio = { version = "1.42", features = ["full"] } treeline = "0.1.0" pem = "3.0.3" openssl = { version = "0.10.61", features = ["vendored"] } diff --git a/cli/src/main.rs b/cli/src/main.rs index 1c3d56203..671472fc0 100644 --- a/cli/src/main.rs +++ b/cli/src/main.rs @@ -27,10 +27,13 @@ use std::{ use anyhow::{anyhow, bail, Context, Result}; use c2pa::{Builder, ClaimGeneratorInfo, Error, Ingredient, ManifestDefinition, Reader, Signer}; +use cawg_identity::{claim_aggregation::IcaSignatureVerifier, IdentityAssertion}; use clap::{Parser, Subcommand}; use log::debug; use serde::Deserialize; +use serde_json::{Map, Value}; use signer::SignConfig; +use tokio::runtime::Runtime; use url::Url; use crate::{ @@ -424,6 +427,144 @@ fn verify_fragmented(init_pattern: &Path, frag_pattern: &Path) -> Result String { + let mut reader_content = match reader.json_value_map() { + Ok(mapped_json) => mapped_json, + Err(_) => { + println!("Could not parse manifest store JSON content"); + return String::new(); + } + }; + + let json_content = match reader_content.get_mut("manifests") { + Some(json) => json, + None => { + println!("No JSON to parse in manifest store (key: manifests)"); + return String::new(); + } + }; + + // Update manifests with CAWG details + if let Value::Object(map) = json_content { + // Iterate over the key-value pairs + for (key, value) in &mut *map { + // Get additional CAWG details + let current_manifest: &c2pa::Manifest = reader.get_manifest(key).unwrap(); + + // Replace the signature content of the assertion with parsed details by CAWG + let assertions = value.get_mut("assertions").unwrap(); + let assertions_array = assertions.as_array_mut().unwrap(); + for assertion in assertions_array { + let label = assertion.get("label").unwrap().to_string(); + + // for CAWG assertions, further parse the signature + if label.contains("cawg.identity") { + let parsed_cawg_json_string = + match get_cawg_details_for_manifest(current_manifest, tokio_runtime) { + Some(parsed_cawg_json_string) => parsed_cawg_json_string, + None => { + println!("Could not parse CAWG details for manifest"); + continue; + } + }; + + let assertion_data: &mut serde_json::Value = assertion.get_mut("data").unwrap(); + assertion_data["signature"] = + serde_json::from_str(&parsed_cawg_json_string).unwrap(); + } + } + } + } else { + println!("Could not parse manifest store JSON content"); + } + + match serde_json::to_string_pretty(&reader_content) { + Ok(decorated_result) => decorated_result, + Err(err) => { + println!( + "Could not parse manifest store JSON content with additional CAWG details: {:?}", + err + ); + String::new() + } + } +} + +/// Parse additional CAWG details from the manifest store to update displayed results. +/// As CAWG mostly async, this will block on network requests for checks using a tokio runtime. +fn get_cawg_details_for_manifest( + manifest: &c2pa::Manifest, + tokio_runtime: &Runtime, +) -> Option { + let ia_iter = IdentityAssertion::from_manifest(manifest); + + // TODO: Determine what should happen when multiple identities are reported (currently only 1 is supported) + let mut parsed_cawg_json = String::new(); + + ia_iter.for_each(|ia| { + let identity_assertion = match ia { + Ok(ia) => ia, + Err(err) => { + println!("Could not parse identity assertion: {:?}", err); + return; + } + }; + + let isv = IcaSignatureVerifier {}; + let ica_validated = tokio_runtime.block_on(identity_assertion.validate(manifest, &isv)); + let ica = match ica_validated { + Ok(ica) => ica, + Err(err) => { + println!("Could not validate identity assertion: {:?}", err); + return; + } + }; + + parsed_cawg_json = serde_json::to_string(&ica).unwrap(); + }); + + // Get the JSON as mutable, so we can further parse and format + let maybe_map = serde_json::from_str(parsed_cawg_json.as_str()); + let mut map: Map = match maybe_map { + Ok(map) => map, + Err(err) => { + println!("Could not parse CAWG details for manifest: {:?}", err); + return None; + } + }; + + // Get the credentials subject information... + let credentials_subject = map.get_mut("credentialSubject"); + let credentials_subject = match credentials_subject { + Some(credentials_subject) => credentials_subject, + None => { + println!("Could not find credentialSubject in CAWG details for manifest"); + return None; + } + }; + let credentials_subject_as_obj = credentials_subject.as_object_mut(); + let credential_subject_details = match credentials_subject_as_obj { + Some(credentials_subject) => credentials_subject, + None => { + println!("Could not parse credential subject as object in CAWG details for manifest"); + return None; + } + }; + // As per design CAWG has some repetition between assertion an signature (c2paAsset field) + // so we remove the c2paAsset field from the credential subject details too + credential_subject_details.remove("c2paAsset"); + + // return the for-display json-formatted string + let serialized_content = serde_json::to_string(&map); + match serialized_content { + Ok(serialized_content) => Some(serialized_content), + Err(err) => { + println!("Could not parse CAWG details for manifest: {:?}", err); + None + } + } +} + fn main() -> Result<()> { let args = CliArgs::parse(); @@ -464,6 +605,9 @@ fn main() -> Result<()> { // configure the SDK configure_sdk(&args).context("Could not configure c2pa-rs")?; + // configure tokio runtime for blocking operations + let tokio_runtime: Runtime = Runtime::new()?; + // Remove manifest needs to also remove XMP provenance // if args.remove_manifest { // match args.output { @@ -674,10 +818,9 @@ fn main() -> Result<()> { Ingredient::from_file(&args.path).map_err(special_errs)? ) } else if args.detailed { - println!( - "{:#?}", - Reader::from_file(&args.path).map_err(special_errs)? - ) + println!("## TMN-Debug ~ cli#main ~ Here we read the detailed edition"); + let reader = Reader::from_file(&args.path).map_err(special_errs)?; + println!("{:#?}", reader) } else if let Some(Commands::Fragment { fragments_glob: Some(fg), }) = &args.command @@ -689,7 +832,9 @@ fn main() -> Result<()> { println!("{} Init manifests validated", stores.len()); } } else { - println!("{}", Reader::from_file(&args.path).map_err(special_errs)?) + let reader: Reader = Reader::from_file(&args.path).map_err(special_errs)?; + let stringified_decorated_json = decorate_json_display(reader, &tokio_runtime); + println!("{}", stringified_decorated_json); } Ok(()) diff --git a/cli/tests/fixtures/C_with_CAWG_data.jpg b/cli/tests/fixtures/C_with_CAWG_data.jpg new file mode 100644 index 0000000000000000000000000000000000000000..4088d990003954524f36f69553fa25a1afacc9dd GIT binary patch literal 141901 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 String { self.manifest_store.to_string() } + /// Get the manifest store as a serde serialized JSON value map. + pub fn json_value_map(&self) -> Result> { + let reader_as_json = self.json(); + let reader_as_json_str = reader_as_json.as_str(); + let mapped_json = serde_json::from_str(reader_as_json_str); + match mapped_json { + Ok(mapped_json) => Ok(mapped_json), + Err(err) => Err(crate::Error::JsonSerializationError(err.to_string())), + } + } + /// Get the [`ValidationStatus`] array of the manifest store if it exists. /// Call this method to check for validation errors. /// From 35217309c2c5a1c80d6b5e59029599345df6c6ff Mon Sep 17 00:00:00 2001 From: Tania Mathern Date: Thu, 6 Feb 2025 14:05:46 -0800 Subject: [PATCH 02/35] ci: Refactor --- sdk/src/reader.rs | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/sdk/src/reader.rs b/sdk/src/reader.rs index 612874b8a..cdaa3215d 100644 --- a/sdk/src/reader.rs +++ b/sdk/src/reader.rs @@ -249,10 +249,7 @@ impl Reader { /// Get the manifest store as a serde serialized JSON value map. pub fn json_value_map(&self) -> Result> { - let reader_as_json = self.json(); - let reader_as_json_str = reader_as_json.as_str(); - let mapped_json = serde_json::from_str(reader_as_json_str); - match mapped_json { + match serde_json::from_str(self.json().as_str()) { Ok(mapped_json) => Ok(mapped_json), Err(err) => Err(crate::Error::JsonSerializationError(err.to_string())), } From 9af655d8c8509f937fef0e8f0cd5c23eb9020581 Mon Sep 17 00:00:00 2001 From: Tania Mathern Date: Thu, 6 Feb 2025 14:13:24 -0800 Subject: [PATCH 03/35] ci: Refactor --- cawg_identity/src/claim_aggregation/w3c_vc/did_web.rs | 2 +- cli/src/main.rs | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/cawg_identity/src/claim_aggregation/w3c_vc/did_web.rs b/cawg_identity/src/claim_aggregation/w3c_vc/did_web.rs index 68c9d5702..010d37bfd 100644 --- a/cawg_identity/src/claim_aggregation/w3c_vc/did_web.rs +++ b/cawg_identity/src/claim_aggregation/w3c_vc/did_web.rs @@ -68,7 +68,7 @@ pub(crate) async fn resolve(did: &Did<'_>) -> Result { let method_specific_id = did.method_specific_id(); - //dbg!(method_specific_id); + // dbg!(method_specific_id); let url = to_url(method_specific_id)?; // TODO: https://w3c-ccg.github.io/did-method-web/#in-transit-security diff --git a/cli/src/main.rs b/cli/src/main.rs index 671472fc0..96f126cf7 100644 --- a/cli/src/main.rs +++ b/cli/src/main.rs @@ -534,8 +534,8 @@ fn get_cawg_details_for_manifest( }; // Get the credentials subject information... - let credentials_subject = map.get_mut("credentialSubject"); - let credentials_subject = match credentials_subject { + let credentials_subject_maybe = map.get_mut("credentialSubject"); + let credentials_subject = match credentials_subject_maybe { Some(credentials_subject) => credentials_subject, None => { println!("Could not find credentialSubject in CAWG details for manifest"); From 7ed719c5d809aca40ffcbf2a55befb0008e7997f Mon Sep 17 00:00:00 2001 From: Tania Mathern Date: Thu, 6 Feb 2025 14:33:04 -0800 Subject: [PATCH 04/35] ci: Refactor --- cli/src/main.rs | 69 +++++++++++++++++++++++++++++++++++++------------ 1 file changed, 53 insertions(+), 16 deletions(-) diff --git a/cli/src/main.rs b/cli/src/main.rs index 96f126cf7..bda214425 100644 --- a/cli/src/main.rs +++ b/cli/src/main.rs @@ -459,18 +459,39 @@ fn decorate_json_display(reader: Reader, tokio_runtime: &Runtime) -> String { // for CAWG assertions, further parse the signature if label.contains("cawg.identity") { - let parsed_cawg_json_string = - match get_cawg_details_for_manifest(current_manifest, tokio_runtime) { - Some(parsed_cawg_json_string) => parsed_cawg_json_string, - None => { - println!("Could not parse CAWG details for manifest"); - continue; - } - }; + let parsed_cawg_json_string = match get_cawg_details_for_manifest( + current_manifest, + tokio_runtime, + ) { + Some(parsed_cawg_json_string) => parsed_cawg_json_string, + None => { + println!("Could not parse CAWG details for manifest (leaving original raw data unformatted)"); + continue; + } + }; let assertion_data: &mut serde_json::Value = assertion.get_mut("data").unwrap(); - assertion_data["signature"] = - serde_json::from_str(&parsed_cawg_json_string).unwrap(); + // update signature with parsed content + + let parsed_signature = match serde_json::from_str(&parsed_cawg_json_string) { + Ok(parsed_signature) => parsed_signature, + Err(err) => { + println!("Could not parse CAWG signature details: {:?}", err); + continue; + } + }; + assertion_data["signature"] = parsed_signature; + + // we don't need to show the padding fields either + let assertion_data_map = match assertion_data.as_object_mut() { + Some(assertion_data_map) => assertion_data_map, + None => { + println!("Could not parse assertion data as object"); + continue; + } + }; + assertion_data_map.remove("pad1"); + assertion_data_map.remove("pad2"); } } } @@ -505,7 +526,7 @@ fn get_cawg_details_for_manifest( let identity_assertion = match ia { Ok(ia) => ia, Err(err) => { - println!("Could not parse identity assertion: {:?}", err); + println!("Could not parse CAWG identity assertion: {:?}", err); return; } }; @@ -515,20 +536,36 @@ fn get_cawg_details_for_manifest( let ica = match ica_validated { Ok(ica) => ica, Err(err) => { - println!("Could not validate identity assertion: {:?}", err); + println!("Could not validate CAWG identity assertion: {:?}", err); return; } }; - parsed_cawg_json = serde_json::to_string(&ica).unwrap(); + parsed_cawg_json = match serde_json::to_string(&ica) { + Ok(parsed_cawg_json) => parsed_cawg_json, + Err(err) => { + println!( + "Could not parse CAWG identity claims aggregation details for manifest: {:?}", + err + ); + return; + } + }; }); - // Get the JSON as mutable, so we can further parse and format + if parsed_cawg_json.is_empty() { + return None; + } + + // Get the JSON as mutable, so we can further parse and format CAWG data let maybe_map = serde_json::from_str(parsed_cawg_json.as_str()); let mut map: Map = match maybe_map { Ok(map) => map, Err(err) => { - println!("Could not parse CAWG details for manifest: {:?}", err); + println!( + "Could not parse convert CAWG identity claims details to JSON string map: {:?}", + err + ); return None; } }; @@ -538,7 +575,7 @@ fn get_cawg_details_for_manifest( let credentials_subject = match credentials_subject_maybe { Some(credentials_subject) => credentials_subject, None => { - println!("Could not find credentialSubject in CAWG details for manifest"); + println!("Could not find credential subject in CAWG details for manifest"); return None; } }; From a18e1f9bca97579b919f80fef8cfc897ec20f118 Mon Sep 17 00:00:00 2001 From: Tania Mathern Date: Thu, 6 Feb 2025 14:52:26 -0800 Subject: [PATCH 05/35] ci: Refactor and rerun tests --- cli/src/main.rs | 67 +++++++++++++++++++++++++++++++++++-------------- 1 file changed, 48 insertions(+), 19 deletions(-) diff --git a/cli/src/main.rs b/cli/src/main.rs index bda214425..e4254945b 100644 --- a/cli/src/main.rs +++ b/cli/src/main.rs @@ -427,6 +427,7 @@ fn verify_fragmented(init_pattern: &Path, frag_pattern: &Path) -> Result String { let mut reader_content = match reader.json_value_map() { Ok(mapped_json) => mapped_json, @@ -436,7 +437,7 @@ fn decorate_json_display(reader: Reader, tokio_runtime: &Runtime) -> String { } }; - let json_content = match reader_content.get_mut("manifests") { + let manifests_json_content = match reader_content.get_mut("manifests") { Some(json) => json, None => { println!("No JSON to parse in manifest store (key: manifests)"); @@ -444,18 +445,57 @@ fn decorate_json_display(reader: Reader, tokio_runtime: &Runtime) -> String { } }; - // Update manifests with CAWG details + // Update assertion with more details, eg. for CAWG + decorate_json_assertions(reader, manifests_json_content, tokio_runtime); + + match serde_json::to_string_pretty(&reader_content) { + Ok(decorated_result) => decorated_result, + Err(err) => { + println!( + "Could not decorate displayed JSON with additional details: {:?}", + err + ); + String::new() + } + } +} + +// Update/decorate the displayed JSON assertions for a more human-readable JSON output. +fn decorate_json_assertions(reader: Reader, json_content: &mut Value, tokio_runtime: &Runtime) -> Result<(), Error>{ if let Value::Object(map) = json_content { // Iterate over the key-value pairs for (key, value) in &mut *map { // Get additional CAWG details - let current_manifest: &c2pa::Manifest = reader.get_manifest(key).unwrap(); + let current_manifest = reader.get_manifest(key); + let current_manifest = match current_manifest { + Some(current_manifest) => current_manifest, + None => { + return Err(crate::Error::JsonSerializationError("Could not get current manifest".to_string())); + } + }; + + // Get the assertions as array from the JSON + let assertions = match value.get_mut("assertions") { + Some(assertions) => assertions, + None => { + return Err(crate::Error::JsonSerializationError("Could not parse JSON assertions as object".to_string())); + } + }; + let assertions_array = match assertions.as_array_mut() { + Some(assertions_array) => assertions_array, + None => { + return Err(crate::Error::JsonSerializationError("Could not parse JSON assertions as array".to_string())); + } + }; - // Replace the signature content of the assertion with parsed details by CAWG - let assertions = value.get_mut("assertions").unwrap(); - let assertions_array = assertions.as_array_mut().unwrap(); + // Loop over the assertions to process those of interest for assertion in assertions_array { - let label = assertion.get("label").unwrap().to_string(); + let label = match assertion.get("label") { + Some(label) => label.to_string(), + None => { + return Err(crate::Error::JsonSerializationError("Could not parse assertion label".to_string())); + } + }; // for CAWG assertions, further parse the signature if label.contains("cawg.identity") { @@ -495,20 +535,9 @@ fn decorate_json_display(reader: Reader, tokio_runtime: &Runtime) -> String { } } } - } else { - println!("Could not parse manifest store JSON content"); } - match serde_json::to_string_pretty(&reader_content) { - Ok(decorated_result) => decorated_result, - Err(err) => { - println!( - "Could not parse manifest store JSON content with additional CAWG details: {:?}", - err - ); - String::new() - } - } + Ok(()) } /// Parse additional CAWG details from the manifest store to update displayed results. From cb389d56fe183880bb7dcc09cd2890effb1c95f3 Mon Sep 17 00:00:00 2001 From: Tania Mathern Date: Thu, 6 Feb 2025 14:54:16 -0800 Subject: [PATCH 06/35] ci: Refactor --- cli/src/main.rs | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/cli/src/main.rs b/cli/src/main.rs index e4254945b..a64ac420f 100644 --- a/cli/src/main.rs +++ b/cli/src/main.rs @@ -446,7 +446,12 @@ fn decorate_json_display(reader: Reader, tokio_runtime: &Runtime) -> String { }; // Update assertion with more details, eg. for CAWG - decorate_json_assertions(reader, manifests_json_content, tokio_runtime); + match decorate_json_assertions(reader, manifests_json_content, tokio_runtime) { + Ok(_) => (), + Err(err) => { + println!("Could not decorate JSON assertions for display: {:?}", err); + } + }; match serde_json::to_string_pretty(&reader_content) { Ok(decorated_result) => decorated_result, From e1b268efcc6232ef5bc3ed3940cbfcda2dfc22f0 Mon Sep 17 00:00:00 2001 From: Tania Mathern Date: Thu, 6 Feb 2025 15:06:35 -0800 Subject: [PATCH 07/35] ci: Solidify error handling --- cli/src/main.rs | 111 +++++++++++++++++++++++++++++++----------------- 1 file changed, 71 insertions(+), 40 deletions(-) diff --git a/cli/src/main.rs b/cli/src/main.rs index a64ac420f..2b5271940 100644 --- a/cli/src/main.rs +++ b/cli/src/main.rs @@ -427,7 +427,7 @@ fn verify_fragmented(init_pattern: &Path, frag_pattern: &Path) -> Result String { let mut reader_content = match reader.json_value_map() { Ok(mapped_json) => mapped_json, @@ -465,8 +465,12 @@ fn decorate_json_display(reader: Reader, tokio_runtime: &Runtime) -> String { } } -// Update/decorate the displayed JSON assertions for a more human-readable JSON output. -fn decorate_json_assertions(reader: Reader, json_content: &mut Value, tokio_runtime: &Runtime) -> Result<(), Error>{ +/// Update/decorate the displayed JSON assertions for a more human-readable JSON output. +fn decorate_json_assertions( + reader: Reader, + json_content: &mut Value, + tokio_runtime: &Runtime, +) -> Result<(), Error> { if let Value::Object(map) = json_content { // Iterate over the key-value pairs for (key, value) in &mut *map { @@ -475,7 +479,9 @@ fn decorate_json_assertions(reader: Reader, json_content: &mut Value, tokio_runt let current_manifest = match current_manifest { Some(current_manifest) => current_manifest, None => { - return Err(crate::Error::JsonSerializationError("Could not get current manifest".to_string())); + return Err(crate::Error::JsonSerializationError( + "Could not get current manifest".to_string(), + )); } }; @@ -483,13 +489,17 @@ fn decorate_json_assertions(reader: Reader, json_content: &mut Value, tokio_runt let assertions = match value.get_mut("assertions") { Some(assertions) => assertions, None => { - return Err(crate::Error::JsonSerializationError("Could not parse JSON assertions as object".to_string())); + return Err(crate::Error::JsonSerializationError( + "Could not parse JSON assertions as object".to_string(), + )); } }; let assertions_array = match assertions.as_array_mut() { Some(assertions_array) => assertions_array, None => { - return Err(crate::Error::JsonSerializationError("Could not parse JSON assertions as array".to_string())); + return Err(crate::Error::JsonSerializationError( + "Could not parse JSON assertions as array".to_string(), + )); } }; @@ -498,45 +508,15 @@ fn decorate_json_assertions(reader: Reader, json_content: &mut Value, tokio_runt let label = match assertion.get("label") { Some(label) => label.to_string(), None => { - return Err(crate::Error::JsonSerializationError("Could not parse assertion label".to_string())); + return Err(crate::Error::JsonSerializationError( + "Could not parse assertion label".to_string(), + )); } }; // for CAWG assertions, further parse the signature if label.contains("cawg.identity") { - let parsed_cawg_json_string = match get_cawg_details_for_manifest( - current_manifest, - tokio_runtime, - ) { - Some(parsed_cawg_json_string) => parsed_cawg_json_string, - None => { - println!("Could not parse CAWG details for manifest (leaving original raw data unformatted)"); - continue; - } - }; - - let assertion_data: &mut serde_json::Value = assertion.get_mut("data").unwrap(); - // update signature with parsed content - - let parsed_signature = match serde_json::from_str(&parsed_cawg_json_string) { - Ok(parsed_signature) => parsed_signature, - Err(err) => { - println!("Could not parse CAWG signature details: {:?}", err); - continue; - } - }; - assertion_data["signature"] = parsed_signature; - - // we don't need to show the padding fields either - let assertion_data_map = match assertion_data.as_object_mut() { - Some(assertion_data_map) => assertion_data_map, - None => { - println!("Could not parse assertion data as object"); - continue; - } - }; - assertion_data_map.remove("pad1"); - assertion_data_map.remove("pad2"); + decorate_json_cawg_assertions(current_manifest, assertion, tokio_runtime)?; } } } @@ -545,6 +525,57 @@ fn decorate_json_assertions(reader: Reader, json_content: &mut Value, tokio_runt Ok(()) } +/// Update/decorate the displayed CAWG assertion for a more human-readable JSON output. +fn decorate_json_cawg_assertions( + holding_manifest: &c2pa::Manifest, + assertion: &mut Value, + tokio_runtime: &Runtime, +) -> Result<(), Error> { + let parsed_cawg_json_string = + match get_cawg_details_for_manifest(holding_manifest, tokio_runtime) { + Some(parsed_cawg_json_string) => parsed_cawg_json_string, + None => { + println!( + "Could not parse CAWG details for manifest (leaving original raw data unformatted)" + ); + return Ok(()); + } + }; + + // Let's look at the assertion data + let assertion_data = match assertion.get_mut("data") { + Some(assertion_data) => assertion_data, + None => { + return Err(crate::Error::JsonSerializationError( + "Could not parse CAWG assertion data".to_string(), + )); + } + }; + + // Update signature with parsed content + let parsed_signature = match serde_json::from_str(&parsed_cawg_json_string) { + Ok(parsed_signature) => parsed_signature, + Err(err) => { + return Err(crate::Error::JsonSerializationError(err.to_string())); + } + }; + assertion_data["signature"] = parsed_signature; + + // We don't need to show the padding fields either + let assertion_data_map = match assertion_data.as_object_mut() { + Some(assertion_data_map) => assertion_data_map, + None => { + return Err(crate::Error::JsonSerializationError( + "Could not parse CAWG assertion data as object".to_string(), + )); + } + }; + assertion_data_map.remove("pad1"); + assertion_data_map.remove("pad2"); + + Ok(()) +} + /// Parse additional CAWG details from the manifest store to update displayed results. /// As CAWG mostly async, this will block on network requests for checks using a tokio runtime. fn get_cawg_details_for_manifest( From cc6e7bd2d7ccca84743b8fbb744b3c34f066b0d9 Mon Sep 17 00:00:00 2001 From: Tania Mathern Date: Thu, 6 Feb 2025 15:14:07 -0800 Subject: [PATCH 08/35] ci: Add test --- cli/tests/integration.rs | 30 ++++++++++++++++++++++++++++++ 1 file changed, 30 insertions(+) diff --git a/cli/tests/integration.rs b/cli/tests/integration.rs index 04fd18f52..77ba0ad9e 100644 --- a/cli/tests/integration.rs +++ b/cli/tests/integration.rs @@ -36,6 +36,7 @@ fn temp_path(name: &str) -> PathBuf { create_dir_all(&path).ok(); path.join(name) } + #[test] fn tool_not_found() -> Result<(), Box> { let mut cmd = Command::cargo_bin("c2patool")?; @@ -43,6 +44,7 @@ fn tool_not_found() -> Result<(), Box> { cmd.assert().failure().stderr(str::contains("os error")); Ok(()) } + #[test] fn tool_not_found_info() -> Result<(), Box> { let mut cmd = Command::cargo_bin("c2patool")?; @@ -52,6 +54,7 @@ fn tool_not_found_info() -> Result<(), Box> { .stderr(str::contains("file not found")); Ok(()) } + #[test] fn tool_jpeg_no_report() -> Result<(), Box> { let mut cmd = Command::cargo_bin("c2patool")?; @@ -93,6 +96,7 @@ fn tool_embed_jpeg_report() -> Result<(), Box> { .stdout(str::contains("My Title")); Ok(()) } + #[test] fn tool_fs_output_report() -> Result<(), Box> { let path = temp_path("output_dir"); @@ -120,6 +124,7 @@ fn tool_fs_output_report() -> Result<(), Box> { ); Ok(()) } + #[test] fn tool_fs_output_report_supports_detailed_flag() -> Result<(), Box> { let path = temp_path("./output_detailed"); @@ -144,6 +149,7 @@ fn tool_fs_output_report_supports_detailed_flag() -> Result<(), Box> .is_some()); Ok(()) } + #[test] fn tool_fs_output_fails_when_output_exists() -> Result<(), Box> { let path = temp_path("./output_conflict"); @@ -160,6 +166,7 @@ fn tool_fs_output_fails_when_output_exists() -> Result<(), Box> { )); Ok(()) } + #[test] // c2patool tests/fixtures/C.jpg -fo target/tmp/manifest_test fn tool_test_manifest_folder() -> Result<(), Box> { @@ -180,6 +187,7 @@ fn tool_test_manifest_folder() -> Result<(), Box> { assert!(json.contains("make_test_images")); Ok(()) } + #[test] // c2patool tests/fixtures/C.jpg -ifo target/tmp/ingredient_test fn tool_test_ingredient_folder() -> Result<(), Box> { @@ -199,6 +207,7 @@ fn tool_test_ingredient_folder() -> Result<(), Box> { assert!(json.contains("manifest_data")); Ok(()) } + #[test] // c2patool tests/fixtures/C.jpg -ifo target/tmp/ingredient_json // c2patool tests/fixtures/earth_apollo17.jpg -m sample/test.json -p target/tmp/ingredient_json/ingredient.json -fo target/tmp/out_2.jpg @@ -230,6 +239,7 @@ fn tool_test_manifest_ingredient_json() -> Result<(), Box .stdout(str::contains("My Title")); Ok(()) } + #[test] // c2patool tests/fixtures/earth_apollo17.jpg -m tests/fixtures/ingredient_test.json -fo target/tmp/ingredients.jpg fn tool_embed_jpeg_with_ingredients_report() -> Result<(), Box> { @@ -248,6 +258,7 @@ fn tool_embed_jpeg_with_ingredients_report() -> Result<(), Box> { .stdout(str::contains("earth_apollo17.jpg")); Ok(()) } + #[test] fn tool_extensions_do_not_match() -> Result<(), Box> { let path = temp_path("./foo.png"); @@ -262,6 +273,7 @@ fn tool_extensions_do_not_match() -> Result<(), Box> { .stderr(str::contains("Output type must match source type")); Ok(()) } + #[test] fn tool_similar_extensions_match() -> Result<(), Box> { let path = temp_path("./similar.JpEg"); @@ -277,6 +289,7 @@ fn tool_similar_extensions_match() -> Result<(), Box> { .stdout(str::contains("similar.")); Ok(()) } + #[test] fn tool_fail_if_thumbnail_missing() -> Result<(), Box> { Command::cargo_bin("c2patool")? @@ -534,3 +547,20 @@ fn tool_tree() -> Result<(), Box> { .stdout(str::contains("Assertion:c2pa.actions")); Ok(()) } + +#[test] +// c2patool C_with_CAWG_data.jpg +fn tool_read_image_with_cawg_data() -> Result<(), Box> { + Command::cargo_bin("c2patool")? + .arg(fixture_path("C_with_CAWG_data.jpg")) + .assert() + .success() + .stdout(str::contains("cawg.identity")) + .stdout(str::contains("credentialSubject")) + .stdout(str::contains("verifiedIdentities")) + .stdout(str::contains("credentialSchema")) + .stdout(str::contains("cawg.social_media")) + .stdout(str::contains("VerifiableCredential")) + .stdout(str::contains("IdentityClaimsAggregationCredential")); + Ok(()) +} From 8a2ead23261ef5281237bbf6cb14f0d501feb1eb Mon Sep 17 00:00:00 2001 From: Tania Mathern Date: Thu, 6 Feb 2025 15:31:41 -0800 Subject: [PATCH 09/35] ci: Prepare for detailed view --- cli/src/main.rs | 3 +- sdk/src/reader.rs | 11 + tmp.json | 9952 +++++++++++++++++++++++++++++++++++++++++++++ tmp2.json | 125 + 4 files changed, 10089 insertions(+), 2 deletions(-) create mode 100644 tmp.json create mode 100644 tmp2.json diff --git a/cli/src/main.rs b/cli/src/main.rs index 2b5271940..feef1b0ad 100644 --- a/cli/src/main.rs +++ b/cli/src/main.rs @@ -920,9 +920,8 @@ fn main() -> Result<()> { Ingredient::from_file(&args.path).map_err(special_errs)? ) } else if args.detailed { - println!("## TMN-Debug ~ cli#main ~ Here we read the detailed edition"); let reader = Reader::from_file(&args.path).map_err(special_errs)?; - println!("{:#?}", reader) + println!("{:#?}", reader); } else if let Some(Commands::Fragment { fragments_glob: Some(fg), }) = &args.command diff --git a/sdk/src/reader.rs b/sdk/src/reader.rs index cdaa3215d..2f0370745 100644 --- a/sdk/src/reader.rs +++ b/sdk/src/reader.rs @@ -255,6 +255,17 @@ impl Reader { } } + // Get the full report as json + pub fn json_report(&self) -> Result { + let report = ManifestStoreReport::from_store(self.manifest_store.store()); + let mut report = match report { + Ok(report) => report, + Err(err) => return Err(crate::Error::JsonSerializationError(err.to_string())), + }; + report.validation_results = self.manifest_store.validation_results().cloned(); + Ok(report.to_string()) + } + /// Get the [`ValidationStatus`] array of the manifest store if it exists. /// Call this method to check for validation errors. /// diff --git a/tmp.json b/tmp.json new file mode 100644 index 000000000..965027b9e --- /dev/null +++ b/tmp.json @@ -0,0 +1,9952 @@ +{ + "active_manifest": "urn:uuid:edf0ad6d-e625-49d3-aebc-721f7d9be57b", + "manifests": { + "urn:uuid:edf0ad6d-e625-49d3-aebc-721f7d9be57b": { + "claim": { + "claim_generator": "adobetest/0.1", + "claim_generator_info": [ + { + "name": "AdobeTest", + "version": "0.1", + "org.cai.c2pa_rs": "0.45.1" + } + ], + "signature": "self#jumbf=/c2pa/urn:uuid:edf0ad6d-e625-49d3-aebc-721f7d9be57b/c2pa.signature", + "assertions": [ + { + "url": "self#jumbf=c2pa.assertions/c2pa.thumbnail.claim.jpeg", + "hash": "164tGhVisijlAiurtNX2EOGKlWPZfPgDxLkZSruemmY=" + }, + { + "url": "self#jumbf=c2pa.assertions/c2pa.actions", + "hash": "j/gQDlHexRYJJzZVQio01DkBQkONh66Dfx6Z0QBoivk=" + }, + { + "url": "self#jumbf=c2pa.assertions/cawg.identity", + "hash": "zVKyUh2sVcTum+9u+vRKc25Ex1t6J7WCA6f/VrzXxQo=" + }, + { + "url": "self#jumbf=c2pa.assertions/c2pa.hash.data", + "hash": "Rz9LLCKr1F+1/6xoZUqJxGC//+CzQ8QxORzGRv0Z9EQ=" + } + ], + "dc:format": "image/jpeg", + "instanceID": "xmp:iid:e9c6522c-a3e4-4959-940c-da2694a148f6", + "alg": "sha256" + }, + "assertion_store": { + "cawg.identity": { + "signer_payload": { + "referenced_assertions": [ + { + "url": "self#jumbf=c2pa.assertions/c2pa.hash.data", + "hash": "Rz9LLCKr1F+1/6xoZUqJxGC//+CzQ8QxORzGRv0Z9EQ=" + } + ], + "sig_type": "cawg.identity_claims_aggregation" + }, + "signature": [ + 210, + 132, + 88, + 105, + 164, + 1, + 39, + 16, + 118, + 97, + 112, + 112, + 108, + 105, + 99, + 97, + 116, + 105, + 111, + 110, + 47, + 118, + 99, + 45, + 108, + 100, + 43, + 99, + 111, + 115, + 101, + 3, + 110, + 97, + 112, + 112, + 108, + 105, + 99, + 97, + 116, + 105, + 111, + 110, + 47, + 118, + 99, + 4, + 88, + 59, + 100, + 105, + 100, + 58, + 119, + 101, + 98, + 58, + 99, + 111, + 110, + 110, + 101, + 99, + 116, + 101, + 100, + 45, + 105, + 100, + 101, + 110, + 116, + 105, + 116, + 105, + 101, + 115, + 46, + 105, + 100, + 101, + 110, + 116, + 105, + 116, + 121, + 45, + 115, + 116, + 97, + 103, + 101, + 46, + 97, + 100, + 111, + 98, + 101, + 46, + 99, + 111, + 109, + 35, + 107, + 101, + 121, + 45, + 48, + 160, + 89, + 3, + 193, + 123, + 34, + 64, + 99, + 111, + 110, + 116, + 101, + 120, + 116, + 34, + 58, + 91, + 34, + 104, + 116, + 116, + 112, + 115, + 58, + 47, + 47, + 119, + 119, + 119, + 46, + 119, + 51, + 46, + 111, + 114, + 103, + 47, + 110, + 115, + 47, + 99, + 114, + 101, + 100, + 101, + 110, + 116, + 105, + 97, + 108, + 115, + 47, + 118, + 50, + 34, + 44, + 34, + 104, + 116, + 116, + 112, + 115, + 58, + 47, + 47, + 99, + 114, + 101, + 97, + 116, + 111, + 114, + 45, + 97, + 115, + 115, + 101, + 114, + 116, + 105, + 111, + 110, + 115, + 46, + 103, + 105, + 116, + 104, + 117, + 98, + 46, + 105, + 111, + 47, + 116, + 98, + 100, + 47, + 116, + 98, + 100, + 34, + 93, + 44, + 34, + 116, + 121, + 112, + 101, + 34, + 58, + 91, + 34, + 86, + 101, + 114, + 105, + 102, + 105, + 97, + 98, + 108, + 101, + 67, + 114, + 101, + 100, + 101, + 110, + 116, + 105, + 97, + 108, + 34, + 44, + 34, + 73, + 100, + 101, + 110, + 116, + 105, + 116, + 121, + 67, + 108, + 97, + 105, + 109, + 115, + 65, + 103, + 103, + 114, + 101, + 103, + 97, + 116, + 105, + 111, + 110, + 67, + 114, + 101, + 100, + 101, + 110, + 116, + 105, + 97, + 108, + 34, + 93, + 44, + 34, + 105, + 115, + 115, + 117, + 101, + 114, + 34, + 58, + 34, + 100, + 105, + 100, + 58, + 119, + 101, + 98, + 58, + 99, + 111, + 110, + 110, + 101, + 99, + 116, + 101, + 100, + 45, + 105, + 100, + 101, + 110, + 116, + 105, + 116, + 105, + 101, + 115, + 46, + 105, + 100, + 101, + 110, + 116, + 105, + 116, + 121, + 45, + 115, + 116, + 97, + 103, + 101, + 46, + 97, + 100, + 111, + 98, + 101, + 46, + 99, + 111, + 109, + 34, + 44, + 34, + 118, + 97, + 108, + 105, + 100, + 70, + 114, + 111, + 109, + 34, + 58, + 34, + 50, + 48, + 50, + 53, + 45, + 48, + 49, + 45, + 51, + 49, + 84, + 50, + 50, + 58, + 49, + 53, + 58, + 53, + 55, + 90, + 34, + 44, + 34, + 99, + 114, + 101, + 100, + 101, + 110, + 116, + 105, + 97, + 108, + 83, + 117, + 98, + 106, + 101, + 99, + 116, + 34, + 58, + 123, + 34, + 105, + 100, + 34, + 58, + 34, + 100, + 105, + 100, + 58, + 119, + 101, + 98, + 58, + 99, + 111, + 110, + 110, + 101, + 99, + 116, + 101, + 100, + 45, + 105, + 100, + 101, + 110, + 116, + 105, + 116, + 105, + 101, + 115, + 46, + 105, + 100, + 101, + 110, + 116, + 105, + 116, + 121, + 45, + 115, + 116, + 97, + 103, + 101, + 46, + 97, + 100, + 111, + 98, + 101, + 46, + 99, + 111, + 109, + 58, + 117, + 115, + 101, + 114, + 58, + 102, + 56, + 99, + 102, + 98, + 102, + 102, + 54, + 99, + 56, + 98, + 50, + 49, + 53, + 48, + 97, + 54, + 51, + 101, + 56, + 54, + 99, + 50, + 99, + 102, + 53, + 102, + 102, + 48, + 97, + 97, + 98, + 48, + 54, + 50, + 49, + 101, + 100, + 53, + 100, + 51, + 102, + 49, + 49, + 55, + 102, + 100, + 54, + 101, + 97, + 57, + 99, + 101, + 101, + 56, + 54, + 51, + 99, + 48, + 101, + 101, + 51, + 55, + 99, + 102, + 34, + 44, + 34, + 118, + 101, + 114, + 105, + 102, + 105, + 101, + 100, + 73, + 100, + 101, + 110, + 116, + 105, + 116, + 105, + 101, + 115, + 34, + 58, + 91, + 123, + 34, + 116, + 121, + 112, + 101, + 34, + 58, + 34, + 99, + 97, + 119, + 103, + 46, + 115, + 111, + 99, + 105, + 97, + 108, + 95, + 109, + 101, + 100, + 105, + 97, + 34, + 44, + 34, + 117, + 115, + 101, + 114, + 110, + 97, + 109, + 101, + 34, + 58, + 34, + 102, + 105, + 114, + 115, + 116, + 108, + 97, + 115, + 116, + 53, + 53, + 53, + 34, + 44, + 34, + 117, + 114, + 105, + 34, + 58, + 34, + 104, + 116, + 116, + 112, + 115, + 58, + 47, + 47, + 110, + 101, + 116, + 46, + 115, + 50, + 115, + 116, + 97, + 103, + 101, + 104, + 97, + 110, + 99, + 101, + 46, + 99, + 111, + 109, + 47, + 102, + 105, + 114, + 115, + 116, + 108, + 97, + 115, + 116, + 53, + 53, + 53, + 34, + 44, + 34, + 112, + 114, + 111, + 118, + 105, + 100, + 101, + 114, + 34, + 58, + 123, + 34, + 105, + 100, + 34, + 58, + 34, + 104, + 116, + 116, + 112, + 115, + 58, + 47, + 47, + 98, + 101, + 104, + 97, + 110, + 99, + 101, + 46, + 110, + 101, + 116, + 34, + 44, + 34, + 110, + 97, + 109, + 101, + 34, + 58, + 34, + 98, + 101, + 104, + 97, + 110, + 99, + 101, + 34, + 125, + 44, + 34, + 118, + 101, + 114, + 105, + 102, + 105, + 101, + 100, + 65, + 116, + 34, + 58, + 34, + 50, + 48, + 50, + 53, + 45, + 48, + 49, + 45, + 49, + 48, + 84, + 49, + 57, + 58, + 53, + 51, + 58, + 53, + 57, + 90, + 34, + 125, + 93, + 44, + 34, + 99, + 50, + 112, + 97, + 65, + 115, + 115, + 101, + 116, + 34, + 58, + 123, + 34, + 114, + 101, + 102, + 101, + 114, + 101, + 110, + 99, + 101, + 100, + 95, + 97, + 115, + 115, + 101, + 114, + 116, + 105, + 111, + 110, + 115, + 34, + 58, + 91, + 123, + 34, + 117, + 114, + 108, + 34, + 58, + 34, + 115, + 101, + 108, + 102, + 35, + 106, + 117, + 109, + 98, + 102, + 61, + 99, + 50, + 112, + 97, + 46, + 97, + 115, + 115, + 101, + 114, + 116, + 105, + 111, + 110, + 115, + 47, + 99, + 50, + 112, + 97, + 46, + 104, + 97, + 115, + 104, + 46, + 100, + 97, + 116, + 97, + 34, + 44, + 34, + 104, + 97, + 115, + 104, + 34, + 58, + 34, + 82, + 122, + 57, + 76, + 76, + 67, + 75, + 114, + 49, + 70, + 43, + 49, + 47, + 54, + 120, + 111, + 90, + 85, + 113, + 74, + 120, + 71, + 67, + 47, + 47, + 43, + 67, + 122, + 81, + 56, + 81, + 120, + 79, + 82, + 122, + 71, + 82, + 118, + 48, + 90, + 57, + 69, + 81, + 61, + 34, + 44, + 34, + 97, + 108, + 103, + 34, + 58, + 34, + 115, + 104, + 97, + 50, + 53, + 54, + 34, + 125, + 93, + 44, + 34, + 115, + 105, + 103, + 95, + 116, + 121, + 112, + 101, + 34, + 58, + 34, + 99, + 97, + 119, + 103, + 46, + 105, + 100, + 101, + 110, + 116, + 105, + 116, + 121, + 95, + 99, + 108, + 97, + 105, + 109, + 115, + 95, + 97, + 103, + 103, + 114, + 101, + 103, + 97, + 116, + 105, + 111, + 110, + 34, + 125, + 125, + 44, + 34, + 99, + 114, + 101, + 100, + 101, + 110, + 116, + 105, + 97, + 108, + 83, + 99, + 104, + 101, + 109, + 97, + 34, + 58, + 91, + 123, + 34, + 105, + 100, + 34, + 58, + 34, + 104, + 116, + 116, + 112, + 115, + 58, + 47, + 47, + 99, + 97, + 119, + 103, + 46, + 105, + 111, + 47, + 115, + 99, + 104, + 101, + 109, + 97, + 115, + 47, + 118, + 49, + 47, + 99, + 114, + 101, + 97, + 116, + 111, + 114, + 45, + 105, + 100, + 101, + 110, + 116, + 105, + 116, + 121, + 45, + 97, + 115, + 115, + 101, + 114, + 116, + 105, + 111, + 110, + 46, + 106, + 115, + 111, + 110, + 34, + 44, + 34, + 116, + 121, + 112, + 101, + 34, + 58, + 34, + 74, + 83, + 79, + 78, + 83, + 99, + 104, + 101, + 109, + 97, + 34, + 125, + 93, + 125, + 88, + 64, + 139, + 119, + 109, + 84, + 122, + 57, + 216, + 105, + 44, + 196, + 96, + 149, + 50, + 54, + 98, + 231, + 93, + 118, + 97, + 89, + 26, + 162, + 7, + 50, + 214, + 139, + 221, + 76, + 29, + 133, + 171, + 172, + 11, + 201, + 103, + 4, + 253, + 149, + 143, + 255, + 61, + 222, + 109, + 72, + 83, + 109, + 50, + 255, + 136, + 129, + 99, + 181, + 119, + 215, + 150, + 16, + 184, + 106, + 252, + 177, + 237, + 117, + 24, + 7 + ], + "pad1": [ + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0 + ], + "pad2": [ + 0, + 0, + 0, + 0, + 0, + 0, + 0 + ] + }, + "c2pa.thumbnail.claim.jpeg": " len = 31608", + "c2pa.hash.data": { + "exclusions": [ + { + "start": 20, + "length": 55267 + } + ], + "name": "jumbf manifest", + "alg": "sha256", + "hash": "gWZNEOMHQNiULfA/tO5HD2awOwYMA3tnfUPApIr9csk=", + "pad": "" + }, + "c2pa.actions": { + "actions": [ + { + "action": "c2pa.edited" + } + ] + } + }, + "signature": { + "alg": "ps256", + "issuer": "Adobe Inc.", + "time": "2025-01-31T22:15:57+00:00" + } + } + }, + "validation_results": { + "activeManifest": { + "success": [ + { + "code": "claimSignature.validated", + "url": "self#jumbf=/c2pa/urn:uuid:edf0ad6d-e625-49d3-aebc-721f7d9be57b/c2pa.signature", + "explanation": "claim signature valid" + }, + { + "code": "assertion.hashedURI.match", + "url": "self#jumbf=/c2pa/urn:uuid:edf0ad6d-e625-49d3-aebc-721f7d9be57b/c2pa.assertions/c2pa.thumbnail.claim.jpeg", + "explanation": "hashed uri matched: self#jumbf=c2pa.assertions/c2pa.thumbnail.claim.jpeg" + }, + { + "code": "assertion.hashedURI.match", + "url": "self#jumbf=/c2pa/urn:uuid:edf0ad6d-e625-49d3-aebc-721f7d9be57b/c2pa.assertions/c2pa.actions", + "explanation": "hashed uri matched: self#jumbf=c2pa.assertions/c2pa.actions" + }, + { + "code": "assertion.hashedURI.match", + "url": "self#jumbf=/c2pa/urn:uuid:edf0ad6d-e625-49d3-aebc-721f7d9be57b/c2pa.assertions/cawg.identity", + "explanation": "hashed uri matched: self#jumbf=c2pa.assertions/cawg.identity" + }, + { + "code": "assertion.hashedURI.match", + "url": "self#jumbf=/c2pa/urn:uuid:edf0ad6d-e625-49d3-aebc-721f7d9be57b/c2pa.assertions/c2pa.hash.data", + "explanation": "hashed uri matched: self#jumbf=c2pa.assertions/c2pa.hash.data" + }, + { + "code": "assertion.dataHash.match", + "url": "self#jumbf=/c2pa/urn:uuid:edf0ad6d-e625-49d3-aebc-721f7d9be57b/c2pa.assertions/c2pa.hash.data", + "explanation": "data hash valid" + } + ], + "informational": [], + "failure": [] + } + } +} diff --git a/tmp2.json b/tmp2.json new file mode 100644 index 000000000..32922b970 --- /dev/null +++ b/tmp2.json @@ -0,0 +1,125 @@ +{ + "active_manifest": "urn:uuid:edf0ad6d-e625-49d3-aebc-721f7d9be57b", + "manifests": { + "urn:uuid:edf0ad6d-e625-49d3-aebc-721f7d9be57b": { + "claim_generator": "adobetest/0.1", + "claim_generator_info": [ + { + "name": "AdobeTest", + "version": "0.1", + "org.cai.c2pa_rs": "0.45.1" + } + ], + "format": "image/jpeg", + "instance_id": "xmp:iid:e9c6522c-a3e4-4959-940c-da2694a148f6", + "thumbnail": { + "format": "image/jpeg", + "identifier": "self#jumbf=/c2pa/urn:uuid:edf0ad6d-e625-49d3-aebc-721f7d9be57b/c2pa.assertions/c2pa.thumbnail.claim.jpeg" + }, + "ingredients": [], + "assertions": [ + { + "label": "c2pa.actions", + "data": { + "actions": [ + { + "action": "c2pa.edited" + } + ] + } + }, + { + "label": "cawg.identity", + "data": { + "signer_payload": { + "referenced_assertions": [ + { + "url": "self#jumbf=c2pa.assertions/c2pa.hash.data", + "hash": "Rz9LLCKr1F+1/6xoZUqJxGC//+CzQ8QxORzGRv0Z9EQ=" + } + ], + "sig_type": "cawg.identity_claims_aggregation" + }, + "signature": { + "@context": [ + "https://www.w3.org/ns/credentials/v2", + "https://creator-assertions.github.io/tbd/tbd" + ], + "type": [ + "VerifiableCredential", + "IdentityClaimsAggregationCredential" + ], + "credentialSubject": { + "verifiedIdentities": [ + { + "type": "cawg.social_media", + "username": "firstlast555", + "uri": "https://net.s2stagehance.com/firstlast555", + "verifiedAt": "2025-01-10T19:53:59Z", + "provider": { + "id": "https://behance.net", + "name": "behance" + } + } + ] + }, + "issuer": "did:web:connected-identities.identity-stage.adobe.com", + "validFrom": "2025-01-31T22:15:57Z", + "credentialSchema": [ + { + "id": "https://cawg.io/schemas/v1/creator-identity-assertion.json", + "type": "JSONSchema" + } + ] + } + } + } + ], + "signature_info": { + "alg": "Ps256", + "issuer": "Adobe Inc.", + "cert_serial_number": "28285008935659793949362901115676279692", + "time": "2025-01-31T22:15:57+00:00" + }, + "label": "urn:uuid:edf0ad6d-e625-49d3-aebc-721f7d9be57b" + } + }, + "validation_results": { + "activeManifest": { + "success": [ + { + "code": "claimSignature.validated", + "url": "self#jumbf=/c2pa/urn:uuid:edf0ad6d-e625-49d3-aebc-721f7d9be57b/c2pa.signature", + "explanation": "claim signature valid" + }, + { + "code": "assertion.hashedURI.match", + "url": "self#jumbf=/c2pa/urn:uuid:edf0ad6d-e625-49d3-aebc-721f7d9be57b/c2pa.assertions/c2pa.thumbnail.claim.jpeg", + "explanation": "hashed uri matched: self#jumbf=c2pa.assertions/c2pa.thumbnail.claim.jpeg" + }, + { + "code": "assertion.hashedURI.match", + "url": "self#jumbf=/c2pa/urn:uuid:edf0ad6d-e625-49d3-aebc-721f7d9be57b/c2pa.assertions/c2pa.actions", + "explanation": "hashed uri matched: self#jumbf=c2pa.assertions/c2pa.actions" + }, + { + "code": "assertion.hashedURI.match", + "url": "self#jumbf=/c2pa/urn:uuid:edf0ad6d-e625-49d3-aebc-721f7d9be57b/c2pa.assertions/cawg.identity", + "explanation": "hashed uri matched: self#jumbf=c2pa.assertions/cawg.identity" + }, + { + "code": "assertion.hashedURI.match", + "url": "self#jumbf=/c2pa/urn:uuid:edf0ad6d-e625-49d3-aebc-721f7d9be57b/c2pa.assertions/c2pa.hash.data", + "explanation": "hashed uri matched: self#jumbf=c2pa.assertions/c2pa.hash.data" + }, + { + "code": "assertion.dataHash.match", + "url": "self#jumbf=/c2pa/urn:uuid:edf0ad6d-e625-49d3-aebc-721f7d9be57b/c2pa.assertions/c2pa.hash.data", + "explanation": "data hash valid" + } + ], + "informational": [], + "failure": [] + } + } +} From dd70c83134c3e9c2c37113963f03728a6e88b7ee Mon Sep 17 00:00:00 2001 From: Tania Mathern Date: Thu, 6 Feb 2025 15:40:07 -0800 Subject: [PATCH 10/35] ci: Retrigger --- cli/src/main.rs | 1 - 1 file changed, 1 deletion(-) diff --git a/cli/src/main.rs b/cli/src/main.rs index feef1b0ad..192a76129 100644 --- a/cli/src/main.rs +++ b/cli/src/main.rs @@ -452,7 +452,6 @@ fn decorate_json_display(reader: Reader, tokio_runtime: &Runtime) -> String { println!("Could not decorate JSON assertions for display: {:?}", err); } }; - match serde_json::to_string_pretty(&reader_content) { Ok(decorated_result) => decorated_result, Err(err) => { From a77004ed322f75c85ce9ddea36d39591413d54d8 Mon Sep 17 00:00:00 2001 From: Tania Mathern Date: Thu, 6 Feb 2025 15:41:47 -0800 Subject: [PATCH 11/35] ci: Remove debug files --- tmp.json | 9952 ----------------------------------------------------- tmp2.json | 125 - 2 files changed, 10077 deletions(-) delete mode 100644 tmp.json delete mode 100644 tmp2.json diff --git a/tmp.json b/tmp.json deleted file mode 100644 index 965027b9e..000000000 --- a/tmp.json +++ /dev/null @@ -1,9952 +0,0 @@ -{ - "active_manifest": "urn:uuid:edf0ad6d-e625-49d3-aebc-721f7d9be57b", - "manifests": { - "urn:uuid:edf0ad6d-e625-49d3-aebc-721f7d9be57b": { - "claim": { - "claim_generator": "adobetest/0.1", - "claim_generator_info": [ - { - "name": "AdobeTest", - "version": "0.1", - "org.cai.c2pa_rs": "0.45.1" - } - ], - "signature": "self#jumbf=/c2pa/urn:uuid:edf0ad6d-e625-49d3-aebc-721f7d9be57b/c2pa.signature", - "assertions": [ - { - "url": "self#jumbf=c2pa.assertions/c2pa.thumbnail.claim.jpeg", - "hash": "164tGhVisijlAiurtNX2EOGKlWPZfPgDxLkZSruemmY=" - }, - { - "url": "self#jumbf=c2pa.assertions/c2pa.actions", - "hash": "j/gQDlHexRYJJzZVQio01DkBQkONh66Dfx6Z0QBoivk=" - }, - { - "url": "self#jumbf=c2pa.assertions/cawg.identity", - "hash": "zVKyUh2sVcTum+9u+vRKc25Ex1t6J7WCA6f/VrzXxQo=" - }, - { - "url": "self#jumbf=c2pa.assertions/c2pa.hash.data", - "hash": "Rz9LLCKr1F+1/6xoZUqJxGC//+CzQ8QxORzGRv0Z9EQ=" - } - ], - "dc:format": "image/jpeg", - "instanceID": "xmp:iid:e9c6522c-a3e4-4959-940c-da2694a148f6", - "alg": "sha256" - }, - "assertion_store": { - "cawg.identity": { - "signer_payload": { - "referenced_assertions": [ - { - "url": "self#jumbf=c2pa.assertions/c2pa.hash.data", - "hash": "Rz9LLCKr1F+1/6xoZUqJxGC//+CzQ8QxORzGRv0Z9EQ=" - } - ], - "sig_type": "cawg.identity_claims_aggregation" - }, - "signature": [ - 210, - 132, - 88, - 105, - 164, - 1, - 39, - 16, - 118, - 97, - 112, - 112, - 108, - 105, - 99, - 97, - 116, - 105, - 111, - 110, - 47, - 118, - 99, - 45, - 108, - 100, - 43, - 99, - 111, - 115, - 101, - 3, - 110, - 97, - 112, - 112, - 108, - 105, - 99, - 97, - 116, - 105, - 111, - 110, - 47, - 118, - 99, - 4, - 88, - 59, - 100, - 105, - 100, - 58, - 119, - 101, - 98, - 58, - 99, - 111, - 110, - 110, - 101, - 99, - 116, - 101, - 100, - 45, - 105, - 100, - 101, - 110, - 116, - 105, - 116, - 105, - 101, - 115, - 46, - 105, - 100, - 101, - 110, - 116, - 105, - 116, - 121, - 45, - 115, - 116, - 97, - 103, - 101, - 46, - 97, - 100, - 111, - 98, - 101, - 46, - 99, - 111, - 109, - 35, - 107, - 101, - 121, - 45, - 48, - 160, - 89, - 3, - 193, - 123, - 34, - 64, - 99, - 111, - 110, - 116, - 101, - 120, - 116, - 34, - 58, - 91, - 34, - 104, - 116, - 116, - 112, - 115, - 58, - 47, - 47, - 119, - 119, - 119, - 46, - 119, - 51, - 46, - 111, - 114, - 103, - 47, - 110, - 115, - 47, - 99, - 114, - 101, - 100, - 101, - 110, - 116, - 105, - 97, - 108, - 115, - 47, - 118, - 50, - 34, - 44, - 34, - 104, - 116, - 116, - 112, - 115, - 58, - 47, - 47, - 99, - 114, - 101, - 97, - 116, - 111, - 114, - 45, - 97, - 115, - 115, - 101, - 114, - 116, - 105, - 111, - 110, - 115, - 46, - 103, - 105, - 116, - 104, - 117, - 98, - 46, - 105, - 111, - 47, - 116, - 98, - 100, - 47, - 116, - 98, - 100, - 34, - 93, - 44, - 34, - 116, - 121, - 112, - 101, - 34, - 58, - 91, - 34, - 86, - 101, - 114, - 105, - 102, - 105, - 97, - 98, - 108, - 101, - 67, - 114, - 101, - 100, - 101, - 110, - 116, - 105, - 97, - 108, - 34, - 44, - 34, - 73, - 100, - 101, - 110, - 116, - 105, - 116, - 121, - 67, - 108, - 97, - 105, - 109, - 115, - 65, - 103, - 103, - 114, - 101, - 103, - 97, - 116, - 105, - 111, - 110, - 67, - 114, - 101, - 100, - 101, - 110, - 116, - 105, - 97, - 108, - 34, - 93, - 44, - 34, - 105, - 115, - 115, - 117, - 101, - 114, - 34, - 58, - 34, - 100, - 105, - 100, - 58, - 119, - 101, - 98, - 58, - 99, - 111, - 110, - 110, - 101, - 99, - 116, - 101, - 100, - 45, - 105, - 100, - 101, - 110, - 116, - 105, - 116, - 105, - 101, - 115, - 46, - 105, - 100, - 101, - 110, - 116, - 105, - 116, - 121, - 45, - 115, - 116, - 97, - 103, - 101, - 46, - 97, - 100, - 111, - 98, - 101, - 46, - 99, - 111, - 109, - 34, - 44, - 34, - 118, - 97, - 108, - 105, - 100, - 70, - 114, - 111, - 109, - 34, - 58, - 34, - 50, - 48, - 50, - 53, - 45, - 48, - 49, - 45, - 51, - 49, - 84, - 50, - 50, - 58, - 49, - 53, - 58, - 53, - 55, - 90, - 34, - 44, - 34, - 99, - 114, - 101, - 100, - 101, - 110, - 116, - 105, - 97, - 108, - 83, - 117, - 98, - 106, - 101, - 99, - 116, - 34, - 58, - 123, - 34, - 105, - 100, - 34, - 58, - 34, - 100, - 105, - 100, - 58, - 119, - 101, - 98, - 58, - 99, - 111, - 110, - 110, - 101, - 99, - 116, - 101, - 100, - 45, - 105, - 100, - 101, - 110, - 116, - 105, - 116, - 105, - 101, - 115, - 46, - 105, - 100, - 101, - 110, - 116, - 105, - 116, - 121, - 45, - 115, - 116, - 97, - 103, - 101, - 46, - 97, - 100, - 111, - 98, - 101, - 46, - 99, - 111, - 109, - 58, - 117, - 115, - 101, - 114, - 58, - 102, - 56, - 99, - 102, - 98, - 102, - 102, - 54, - 99, - 56, - 98, - 50, - 49, - 53, - 48, - 97, - 54, - 51, - 101, - 56, - 54, - 99, - 50, - 99, - 102, - 53, - 102, - 102, - 48, - 97, - 97, - 98, - 48, - 54, - 50, - 49, - 101, - 100, - 53, - 100, - 51, - 102, - 49, - 49, - 55, - 102, - 100, - 54, - 101, - 97, - 57, - 99, - 101, - 101, - 56, - 54, - 51, - 99, - 48, - 101, - 101, - 51, - 55, - 99, - 102, - 34, - 44, - 34, - 118, - 101, - 114, - 105, - 102, - 105, - 101, - 100, - 73, - 100, - 101, - 110, - 116, - 105, - 116, - 105, - 101, - 115, - 34, - 58, - 91, - 123, - 34, - 116, - 121, - 112, - 101, - 34, - 58, - 34, - 99, - 97, - 119, - 103, - 46, - 115, - 111, - 99, - 105, - 97, - 108, - 95, - 109, - 101, - 100, - 105, - 97, - 34, - 44, - 34, - 117, - 115, - 101, - 114, - 110, - 97, - 109, - 101, - 34, - 58, - 34, - 102, - 105, - 114, - 115, - 116, - 108, - 97, - 115, - 116, - 53, - 53, - 53, - 34, - 44, - 34, - 117, - 114, - 105, - 34, - 58, - 34, - 104, - 116, - 116, - 112, - 115, - 58, - 47, - 47, - 110, - 101, - 116, - 46, - 115, - 50, - 115, - 116, - 97, - 103, - 101, - 104, - 97, - 110, - 99, - 101, - 46, - 99, - 111, - 109, - 47, - 102, - 105, - 114, - 115, - 116, - 108, - 97, - 115, - 116, - 53, - 53, - 53, - 34, - 44, - 34, - 112, - 114, - 111, - 118, - 105, - 100, - 101, - 114, - 34, - 58, - 123, - 34, - 105, - 100, - 34, - 58, - 34, - 104, - 116, - 116, - 112, - 115, - 58, - 47, - 47, - 98, - 101, - 104, - 97, - 110, - 99, - 101, - 46, - 110, - 101, - 116, - 34, - 44, - 34, - 110, - 97, - 109, - 101, - 34, - 58, - 34, - 98, - 101, - 104, - 97, - 110, - 99, - 101, - 34, - 125, - 44, - 34, - 118, - 101, - 114, - 105, - 102, - 105, - 101, - 100, - 65, - 116, - 34, - 58, - 34, - 50, - 48, - 50, - 53, - 45, - 48, - 49, - 45, - 49, - 48, - 84, - 49, - 57, - 58, - 53, - 51, - 58, - 53, - 57, - 90, - 34, - 125, - 93, - 44, - 34, - 99, - 50, - 112, - 97, - 65, - 115, - 115, - 101, - 116, - 34, - 58, - 123, - 34, - 114, - 101, - 102, - 101, - 114, - 101, - 110, - 99, - 101, - 100, - 95, - 97, - 115, - 115, - 101, - 114, - 116, - 105, - 111, - 110, - 115, - 34, - 58, - 91, - 123, - 34, - 117, - 114, - 108, - 34, - 58, - 34, - 115, - 101, - 108, - 102, - 35, - 106, - 117, - 109, - 98, - 102, - 61, - 99, - 50, - 112, - 97, - 46, - 97, - 115, - 115, - 101, - 114, - 116, - 105, - 111, - 110, - 115, - 47, - 99, - 50, - 112, - 97, - 46, - 104, - 97, - 115, - 104, - 46, - 100, - 97, - 116, - 97, - 34, - 44, - 34, - 104, - 97, - 115, - 104, - 34, - 58, - 34, - 82, - 122, - 57, - 76, - 76, - 67, - 75, - 114, - 49, - 70, - 43, - 49, - 47, - 54, - 120, - 111, - 90, - 85, - 113, - 74, - 120, - 71, - 67, - 47, - 47, - 43, - 67, - 122, - 81, - 56, - 81, - 120, - 79, - 82, - 122, - 71, - 82, - 118, - 48, - 90, - 57, - 69, - 81, - 61, - 34, - 44, - 34, - 97, - 108, - 103, - 34, - 58, - 34, - 115, - 104, - 97, - 50, - 53, - 54, - 34, - 125, - 93, - 44, - 34, - 115, - 105, - 103, - 95, - 116, - 121, - 112, - 101, - 34, - 58, - 34, - 99, - 97, - 119, - 103, - 46, - 105, - 100, - 101, - 110, - 116, - 105, - 116, - 121, - 95, - 99, - 108, - 97, - 105, - 109, - 115, - 95, - 97, - 103, - 103, - 114, - 101, - 103, - 97, - 116, - 105, - 111, - 110, - 34, - 125, - 125, - 44, - 34, - 99, - 114, - 101, - 100, - 101, - 110, - 116, - 105, - 97, - 108, - 83, - 99, - 104, - 101, - 109, - 97, - 34, - 58, - 91, - 123, - 34, - 105, - 100, - 34, - 58, - 34, - 104, - 116, - 116, - 112, - 115, - 58, - 47, - 47, - 99, - 97, - 119, - 103, - 46, - 105, - 111, - 47, - 115, - 99, - 104, - 101, - 109, - 97, - 115, - 47, - 118, - 49, - 47, - 99, - 114, - 101, - 97, - 116, - 111, - 114, - 45, - 105, - 100, - 101, - 110, - 116, - 105, - 116, - 121, - 45, - 97, - 115, - 115, - 101, - 114, - 116, - 105, - 111, - 110, - 46, - 106, - 115, - 111, - 110, - 34, - 44, - 34, - 116, - 121, - 112, - 101, - 34, - 58, - 34, - 74, - 83, - 79, - 78, - 83, - 99, - 104, - 101, - 109, - 97, - 34, - 125, - 93, - 125, - 88, - 64, - 139, - 119, - 109, - 84, - 122, - 57, - 216, - 105, - 44, - 196, - 96, - 149, - 50, - 54, - 98, - 231, - 93, - 118, - 97, - 89, - 26, - 162, - 7, - 50, - 214, - 139, - 221, - 76, - 29, - 133, - 171, - 172, - 11, - 201, - 103, - 4, - 253, - 149, - 143, - 255, - 61, - 222, - 109, - 72, - 83, - 109, - 50, - 255, - 136, - 129, - 99, - 181, - 119, - 215, - 150, - 16, - 184, - 106, - 252, - 177, - 237, - 117, - 24, - 7 - ], - "pad1": [ - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0 - ], - "pad2": [ - 0, - 0, - 0, - 0, - 0, - 0, - 0 - ] - }, - "c2pa.thumbnail.claim.jpeg": " len = 31608", - "c2pa.hash.data": { - "exclusions": [ - { - "start": 20, - "length": 55267 - } - ], - "name": "jumbf manifest", - "alg": "sha256", - "hash": "gWZNEOMHQNiULfA/tO5HD2awOwYMA3tnfUPApIr9csk=", - "pad": "" - }, - "c2pa.actions": { - "actions": [ - { - "action": "c2pa.edited" - } - ] - } - }, - "signature": { - "alg": "ps256", - "issuer": "Adobe Inc.", - "time": "2025-01-31T22:15:57+00:00" - } - } - }, - "validation_results": { - "activeManifest": { - "success": [ - { - "code": "claimSignature.validated", - "url": "self#jumbf=/c2pa/urn:uuid:edf0ad6d-e625-49d3-aebc-721f7d9be57b/c2pa.signature", - "explanation": "claim signature valid" - }, - { - "code": "assertion.hashedURI.match", - "url": "self#jumbf=/c2pa/urn:uuid:edf0ad6d-e625-49d3-aebc-721f7d9be57b/c2pa.assertions/c2pa.thumbnail.claim.jpeg", - "explanation": "hashed uri matched: self#jumbf=c2pa.assertions/c2pa.thumbnail.claim.jpeg" - }, - { - "code": "assertion.hashedURI.match", - "url": "self#jumbf=/c2pa/urn:uuid:edf0ad6d-e625-49d3-aebc-721f7d9be57b/c2pa.assertions/c2pa.actions", - "explanation": "hashed uri matched: self#jumbf=c2pa.assertions/c2pa.actions" - }, - { - "code": "assertion.hashedURI.match", - "url": "self#jumbf=/c2pa/urn:uuid:edf0ad6d-e625-49d3-aebc-721f7d9be57b/c2pa.assertions/cawg.identity", - "explanation": "hashed uri matched: self#jumbf=c2pa.assertions/cawg.identity" - }, - { - "code": "assertion.hashedURI.match", - "url": "self#jumbf=/c2pa/urn:uuid:edf0ad6d-e625-49d3-aebc-721f7d9be57b/c2pa.assertions/c2pa.hash.data", - "explanation": "hashed uri matched: self#jumbf=c2pa.assertions/c2pa.hash.data" - }, - { - "code": "assertion.dataHash.match", - "url": "self#jumbf=/c2pa/urn:uuid:edf0ad6d-e625-49d3-aebc-721f7d9be57b/c2pa.assertions/c2pa.hash.data", - "explanation": "data hash valid" - } - ], - "informational": [], - "failure": [] - } - } -} diff --git a/tmp2.json b/tmp2.json deleted file mode 100644 index 32922b970..000000000 --- a/tmp2.json +++ /dev/null @@ -1,125 +0,0 @@ -{ - "active_manifest": "urn:uuid:edf0ad6d-e625-49d3-aebc-721f7d9be57b", - "manifests": { - "urn:uuid:edf0ad6d-e625-49d3-aebc-721f7d9be57b": { - "claim_generator": "adobetest/0.1", - "claim_generator_info": [ - { - "name": "AdobeTest", - "version": "0.1", - "org.cai.c2pa_rs": "0.45.1" - } - ], - "format": "image/jpeg", - "instance_id": "xmp:iid:e9c6522c-a3e4-4959-940c-da2694a148f6", - "thumbnail": { - "format": "image/jpeg", - "identifier": "self#jumbf=/c2pa/urn:uuid:edf0ad6d-e625-49d3-aebc-721f7d9be57b/c2pa.assertions/c2pa.thumbnail.claim.jpeg" - }, - "ingredients": [], - "assertions": [ - { - "label": "c2pa.actions", - "data": { - "actions": [ - { - "action": "c2pa.edited" - } - ] - } - }, - { - "label": "cawg.identity", - "data": { - "signer_payload": { - "referenced_assertions": [ - { - "url": "self#jumbf=c2pa.assertions/c2pa.hash.data", - "hash": "Rz9LLCKr1F+1/6xoZUqJxGC//+CzQ8QxORzGRv0Z9EQ=" - } - ], - "sig_type": "cawg.identity_claims_aggregation" - }, - "signature": { - "@context": [ - "https://www.w3.org/ns/credentials/v2", - "https://creator-assertions.github.io/tbd/tbd" - ], - "type": [ - "VerifiableCredential", - "IdentityClaimsAggregationCredential" - ], - "credentialSubject": { - "verifiedIdentities": [ - { - "type": "cawg.social_media", - "username": "firstlast555", - "uri": "https://net.s2stagehance.com/firstlast555", - "verifiedAt": "2025-01-10T19:53:59Z", - "provider": { - "id": "https://behance.net", - "name": "behance" - } - } - ] - }, - "issuer": "did:web:connected-identities.identity-stage.adobe.com", - "validFrom": "2025-01-31T22:15:57Z", - "credentialSchema": [ - { - "id": "https://cawg.io/schemas/v1/creator-identity-assertion.json", - "type": "JSONSchema" - } - ] - } - } - } - ], - "signature_info": { - "alg": "Ps256", - "issuer": "Adobe Inc.", - "cert_serial_number": "28285008935659793949362901115676279692", - "time": "2025-01-31T22:15:57+00:00" - }, - "label": "urn:uuid:edf0ad6d-e625-49d3-aebc-721f7d9be57b" - } - }, - "validation_results": { - "activeManifest": { - "success": [ - { - "code": "claimSignature.validated", - "url": "self#jumbf=/c2pa/urn:uuid:edf0ad6d-e625-49d3-aebc-721f7d9be57b/c2pa.signature", - "explanation": "claim signature valid" - }, - { - "code": "assertion.hashedURI.match", - "url": "self#jumbf=/c2pa/urn:uuid:edf0ad6d-e625-49d3-aebc-721f7d9be57b/c2pa.assertions/c2pa.thumbnail.claim.jpeg", - "explanation": "hashed uri matched: self#jumbf=c2pa.assertions/c2pa.thumbnail.claim.jpeg" - }, - { - "code": "assertion.hashedURI.match", - "url": "self#jumbf=/c2pa/urn:uuid:edf0ad6d-e625-49d3-aebc-721f7d9be57b/c2pa.assertions/c2pa.actions", - "explanation": "hashed uri matched: self#jumbf=c2pa.assertions/c2pa.actions" - }, - { - "code": "assertion.hashedURI.match", - "url": "self#jumbf=/c2pa/urn:uuid:edf0ad6d-e625-49d3-aebc-721f7d9be57b/c2pa.assertions/cawg.identity", - "explanation": "hashed uri matched: self#jumbf=c2pa.assertions/cawg.identity" - }, - { - "code": "assertion.hashedURI.match", - "url": "self#jumbf=/c2pa/urn:uuid:edf0ad6d-e625-49d3-aebc-721f7d9be57b/c2pa.assertions/c2pa.hash.data", - "explanation": "hashed uri matched: self#jumbf=c2pa.assertions/c2pa.hash.data" - }, - { - "code": "assertion.dataHash.match", - "url": "self#jumbf=/c2pa/urn:uuid:edf0ad6d-e625-49d3-aebc-721f7d9be57b/c2pa.assertions/c2pa.hash.data", - "explanation": "data hash valid" - } - ], - "informational": [], - "failure": [] - } - } -} From 13875f4aa1dc7eebf3c9fb3bb842f620a8b9055f Mon Sep 17 00:00:00 2001 From: Tania Mathern Date: Thu, 6 Feb 2025 16:30:21 -0800 Subject: [PATCH 12/35] ci: Review comment 1 --- cawg_identity/src/claim_aggregation/ica_signature_verifier.rs | 2 -- cawg_identity/src/claim_aggregation/w3c_vc/did_web.rs | 2 -- sdk/Cargo.toml | 2 +- 3 files changed, 1 insertion(+), 5 deletions(-) diff --git a/cawg_identity/src/claim_aggregation/ica_signature_verifier.rs b/cawg_identity/src/claim_aggregation/ica_signature_verifier.rs index d9a5c341f..6da3df3d8 100644 --- a/cawg_identity/src/claim_aggregation/ica_signature_verifier.rs +++ b/cawg_identity/src/claim_aggregation/ica_signature_verifier.rs @@ -153,8 +153,6 @@ impl SignatureVerifier for IcaSignatureVerifier { )); }; - // dbg!(&jwk_prop); - // OMG SO HACKY! let Ok(jwk_json) = serde_json::to_string_pretty(jwk_prop) else { return Err(ValidationError::SignatureError( diff --git a/cawg_identity/src/claim_aggregation/w3c_vc/did_web.rs b/cawg_identity/src/claim_aggregation/w3c_vc/did_web.rs index 010d37bfd..6f0e57375 100644 --- a/cawg_identity/src/claim_aggregation/w3c_vc/did_web.rs +++ b/cawg_identity/src/claim_aggregation/w3c_vc/did_web.rs @@ -68,8 +68,6 @@ pub(crate) async fn resolve(did: &Did<'_>) -> Result { let method_specific_id = did.method_specific_id(); - // dbg!(method_specific_id); - let url = to_url(method_specific_id)?; // TODO: https://w3c-ccg.github.io/did-method-web/#in-transit-security diff --git a/sdk/Cargo.toml b/sdk/Cargo.toml index 60a5a35e5..b9cb17479 100644 --- a/sdk/Cargo.toml +++ b/sdk/Cargo.toml @@ -115,7 +115,7 @@ serde_bytes = "0.11.5" serde_cbor = "0.11.1" serde_derive = "1.0.197" serde_json = { version = "1.0.117", features = ["preserve_order"] } -serde_with = { version = "3.12.0" } +serde_with = "3.12.0" serde-transcode = "1.1.1" sha1 = "0.10.6" sha2 = "0.10.6" From 3b450880654b04ec317b1f7747f804b32e20ed77 Mon Sep 17 00:00:00 2001 From: Tania Mathern Date: Thu, 6 Feb 2025 16:31:53 -0800 Subject: [PATCH 13/35] ci: Review comment 2 --- cli/Cargo.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cli/Cargo.toml b/cli/Cargo.toml index cdcbaf221..41331644c 100644 --- a/cli/Cargo.toml +++ b/cli/Cargo.toml @@ -22,7 +22,7 @@ unexpected_cfgs = { level = "warn", check-cfg = ['cfg(test)'] } [dependencies] anyhow = "1.0" atree = "0.5.2" -cawg-identity = { path = "../cawg_identity"} +cawg-identity = { path = "../cawg_identity", version = "0.6.0" } c2pa = { path = "../sdk", version = "0.45.2", features = [ "fetch_remote_manifests", "file_io", From 49adfd217cddfbed41cef22edb4cdd76030251d8 Mon Sep 17 00:00:00 2001 From: Tania Mathern Date: Thu, 6 Feb 2025 16:38:11 -0800 Subject: [PATCH 14/35] ci: Retrigger checks --- sdk/src/reader.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sdk/src/reader.rs b/sdk/src/reader.rs index 2f0370745..1afb75437 100644 --- a/sdk/src/reader.rs +++ b/sdk/src/reader.rs @@ -255,7 +255,7 @@ impl Reader { } } - // Get the full report as json + // Get the full report as json. pub fn json_report(&self) -> Result { let report = ManifestStoreReport::from_store(self.manifest_store.store()); let mut report = match report { From 151e312ce509dfe275c3fca9ca208ab2c18381fa Mon Sep 17 00:00:00 2001 From: Tania Mathern Date: Thu, 6 Feb 2025 16:43:02 -0800 Subject: [PATCH 15/35] ci: Retrigger checks --- sdk/src/reader.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sdk/src/reader.rs b/sdk/src/reader.rs index 1afb75437..973f0d519 100644 --- a/sdk/src/reader.rs +++ b/sdk/src/reader.rs @@ -255,7 +255,7 @@ impl Reader { } } - // Get the full report as json. + // Get a full reader (manifest and manifest store) report as a JSON string. pub fn json_report(&self) -> Result { let report = ManifestStoreReport::from_store(self.manifest_store.store()); let mut report = match report { From 153be9807c6bd9bb9cd80d6f25a73a44157b9113 Mon Sep 17 00:00:00 2001 From: Tania Mathern Date: Fri, 7 Feb 2025 09:16:18 -0800 Subject: [PATCH 16/35] ci: Cargo lock too --- Cargo.lock | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Cargo.lock b/Cargo.lock index 68892d86c..94440b905 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -850,7 +850,7 @@ version = "0.5.0" [[package]] name = "c2patool" -version = "0.13.1" +version = "0.13.2" dependencies = [ "anyhow", "assert_cmd", From c32ec31ea926198cbb527167515342558c6626d5 Mon Sep 17 00:00:00 2001 From: Tania Mathern Date: Fri, 7 Feb 2025 10:00:03 -0800 Subject: [PATCH 17/35] Errors go to stdout --- cli/src/main.rs | 27 +++++++++++++-------------- 1 file changed, 13 insertions(+), 14 deletions(-) diff --git a/cli/src/main.rs b/cli/src/main.rs index 192a76129..0f2f0b876 100644 --- a/cli/src/main.rs +++ b/cli/src/main.rs @@ -432,7 +432,7 @@ fn decorate_json_display(reader: Reader, tokio_runtime: &Runtime) -> String { let mut reader_content = match reader.json_value_map() { Ok(mapped_json) => mapped_json, Err(_) => { - println!("Could not parse manifest store JSON content"); + eprintln!("Could not parse manifest store JSON content"); return String::new(); } }; @@ -440,7 +440,7 @@ fn decorate_json_display(reader: Reader, tokio_runtime: &Runtime) -> String { let manifests_json_content = match reader_content.get_mut("manifests") { Some(json) => json, None => { - println!("No JSON to parse in manifest store (key: manifests)"); + eprintln!("No JSON to parse in manifest store (key: manifests)"); return String::new(); } }; @@ -449,13 +449,13 @@ fn decorate_json_display(reader: Reader, tokio_runtime: &Runtime) -> String { match decorate_json_assertions(reader, manifests_json_content, tokio_runtime) { Ok(_) => (), Err(err) => { - println!("Could not decorate JSON assertions for display: {:?}", err); + eprintln!("Could not decorate JSON assertions for display: {:?}", err); } }; match serde_json::to_string_pretty(&reader_content) { Ok(decorated_result) => decorated_result, Err(err) => { - println!( + eprintln!( "Could not decorate displayed JSON with additional details: {:?}", err ); @@ -534,9 +534,8 @@ fn decorate_json_cawg_assertions( match get_cawg_details_for_manifest(holding_manifest, tokio_runtime) { Some(parsed_cawg_json_string) => parsed_cawg_json_string, None => { - println!( - "Could not parse CAWG details for manifest (leaving original raw data unformatted)" - ); + // Could not parse CAWG details for manifest (leaving original raw data unformatted). + // Not a fatal failure, so leaving raw data unformatted. return Ok(()); } }; @@ -590,7 +589,7 @@ fn get_cawg_details_for_manifest( let identity_assertion = match ia { Ok(ia) => ia, Err(err) => { - println!("Could not parse CAWG identity assertion: {:?}", err); + eprintln!("Could not parse CAWG identity assertion: {:?}", err); return; } }; @@ -600,7 +599,7 @@ fn get_cawg_details_for_manifest( let ica = match ica_validated { Ok(ica) => ica, Err(err) => { - println!("Could not validate CAWG identity assertion: {:?}", err); + eprintln!("Could not validate CAWG identity assertion: {:?}", err); return; } }; @@ -608,7 +607,7 @@ fn get_cawg_details_for_manifest( parsed_cawg_json = match serde_json::to_string(&ica) { Ok(parsed_cawg_json) => parsed_cawg_json, Err(err) => { - println!( + eprintln!( "Could not parse CAWG identity claims aggregation details for manifest: {:?}", err ); @@ -626,7 +625,7 @@ fn get_cawg_details_for_manifest( let mut map: Map = match maybe_map { Ok(map) => map, Err(err) => { - println!( + eprintln!( "Could not parse convert CAWG identity claims details to JSON string map: {:?}", err ); @@ -639,7 +638,7 @@ fn get_cawg_details_for_manifest( let credentials_subject = match credentials_subject_maybe { Some(credentials_subject) => credentials_subject, None => { - println!("Could not find credential subject in CAWG details for manifest"); + eprintln!("Could not find credential subject in CAWG details for manifest"); return None; } }; @@ -647,7 +646,7 @@ fn get_cawg_details_for_manifest( let credential_subject_details = match credentials_subject_as_obj { Some(credentials_subject) => credentials_subject, None => { - println!("Could not parse credential subject as object in CAWG details for manifest"); + eprintln!("Could not parse credential subject as object in CAWG details for manifest"); return None; } }; @@ -660,7 +659,7 @@ fn get_cawg_details_for_manifest( match serialized_content { Ok(serialized_content) => Some(serialized_content), Err(err) => { - println!("Could not parse CAWG details for manifest: {:?}", err); + eprintln!("Could not parse CAWG details for manifest: {:?}", err); None } } From aba8668c0939d31cf8ca27a1797f6fc322414247 Mon Sep 17 00:00:00 2001 From: tmathern <60901087+tmathern@users.noreply.github.com> Date: Fri, 7 Feb 2025 10:00:34 -0800 Subject: [PATCH 18/35] feat: c2patool to read cawg data with `--detailed` flag too (#909) feat: c2patool to read cawg data with `--detailed` flag too (#909) --- cli/src/main.rs | 127 +++++++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 125 insertions(+), 2 deletions(-) diff --git a/cli/src/main.rs b/cli/src/main.rs index 0f2f0b876..d07a6cd86 100644 --- a/cli/src/main.rs +++ b/cli/src/main.rs @@ -427,6 +427,120 @@ fn verify_fragmented(init_pattern: &Path, frag_pattern: &Path) -> Result String { + let mut report_json_map: Map = match serde_json::from_str(&extracted_report) { + Ok(report_json_map) => report_json_map, + Err(err) => { + println!("Could not parse extracted JSON report: {:?}", err); + return String::new(); + } + }; + + let manifests = match report_json_map.get_mut("manifests") { + Some(manifests) => manifests, + None => { + println!("No parsable JSON in manifest store (key: manifests)"); + return String::new(); + } + }; + + match decorate_cawg_assertion_from_detailed_report(reader, manifests, tokio_runtime) { + Ok(_) => (), + Err(err) => { + println!("Could not decorate detailed JSON for display: {:?}", err); + } + }; + + match serde_json::to_string_pretty(&report_json_map) { + Ok(decorated_result) => decorated_result, + Err(err) => { + println!( + "Could not decorate displayed detailed JSON with additional details: {:?}", + err + ); + String::new() + } + } +} + +/// Update/decorate the displayed JSON assertions for a more human-readable JSON output. +fn decorate_cawg_assertion_from_detailed_report( + reader: Reader, + json_content: &mut Value, + tokio_runtime: &Runtime, +) -> Result<(), Error> { + if let Value::Object(map) = json_content { + // Iterate over the key-value pairs + for (key, value) in &mut *map { + // Get additional CAWG details + + // Get the assertions as array from the JSON + let assertions = match value.get_mut("assertion_store") { + Some(assertions) => assertions, + None => { + return Err(crate::Error::JsonSerializationError( + "Could not parse JSON assertion store as object".to_string(), + )); + } + }; + + let cawg_assertion = match assertions.get_mut("cawg.identity") { + Some(cawg_assertion) => cawg_assertion, + None => { + return Err(crate::Error::JsonSerializationError( + "Could not parse CAWG identity details from assertion store".to_string(), + )); + } + }; + + let holding_manifest = match reader.get_manifest(key) { + Some(holding_manifest) => holding_manifest, + None => { + return Err(crate::Error::JsonSerializationError( + "Could not recover manifest holding CAWG data".to_string(), + )); + } + }; + + let parsed_cawg_json_string = + match get_cawg_details_for_manifest(holding_manifest, tokio_runtime) { + Some(parsed_cawg_json_string) => parsed_cawg_json_string, + None => { + // Not a show-stopper: + // Could not parse CAWG details for manifest, + // so leaving original raw data unformatted. + return Ok(()); + } + }; + + cawg_assertion["signature"] = match serde_json::from_str(&parsed_cawg_json_string) { + Ok(decoded_cawg_assertion) => decoded_cawg_assertion, + Err(err) => { + return Err(crate::Error::JsonSerializationError(err.to_string())); + } + }; + + let cawg_assertion = match cawg_assertion.as_object_mut() { + Some(cawg_assertion) => cawg_assertion, + None => { + return Err(crate::Error::JsonSerializationError( + "Could not parse CAWG assertion data as object to decorate for display" + .to_string(), + )); + } + }; + cawg_assertion.remove("pad1"); + cawg_assertion.remove("pad2"); + } + } + + Ok(()) +} + /// Update/decorate the displayed JSON string for a more human-readable JSON output. fn decorate_json_display(reader: Reader, tokio_runtime: &Runtime) -> String { let mut reader_content = match reader.json_value_map() { @@ -445,7 +559,7 @@ fn decorate_json_display(reader: Reader, tokio_runtime: &Runtime) -> String { } }; - // Update assertion with more details, eg. for CAWG + // Update assertion with more details (eg. for CAWG) match decorate_json_assertions(reader, manifests_json_content, tokio_runtime) { Ok(_) => (), Err(err) => { @@ -919,7 +1033,16 @@ fn main() -> Result<()> { ) } else if args.detailed { let reader = Reader::from_file(&args.path).map_err(special_errs)?; - println!("{:#?}", reader); + + let json_report = reader.json_report(); + let extracted_json_report = match json_report { + Ok(extracted_json_report) => extracted_json_report, + Err(err) => format!("Could not parse JSON report: {:?}", err), + }; + + let decorated_details_manifest = + decorate_json_detailled_display(reader, extracted_json_report, &tokio_runtime); + println!("{}", decorated_details_manifest); } else if let Some(Commands::Fragment { fragments_glob: Some(fg), }) = &args.command From 85201a7fcb7104adb86a81e700bde68e2f4dddcb Mon Sep 17 00:00:00 2001 From: Tania Mathern Date: Fri, 7 Feb 2025 10:17:56 -0800 Subject: [PATCH 19/35] feat: Move cawg parsing for c2patool into own file --- cli/src/cawg_parser.rs | 370 +++++++++++++++++++++++++++++++++++++++++ cli/src/main.rs | 358 +-------------------------------------- 2 files changed, 373 insertions(+), 355 deletions(-) create mode 100644 cli/src/cawg_parser.rs diff --git a/cli/src/cawg_parser.rs b/cli/src/cawg_parser.rs new file mode 100644 index 000000000..23dab8233 --- /dev/null +++ b/cli/src/cawg_parser.rs @@ -0,0 +1,370 @@ +// Copyright 2022 Adobe. All rights reserved. +// This file is licensed to you under the Apache License, +// Version 2.0 (http://www.apache.org/licenses/LICENSE-2.0) +// or the MIT license (http://opensource.org/licenses/MIT), +// at your option. +// Unless required by applicable law or agreed to in writing, +// this software is distributed on an "AS IS" BASIS, WITHOUT +// WARRANTIES OR REPRESENTATIONS OF ANY KIND, either express or +// implied. See the LICENSE-MIT and LICENSE-APACHE files for the +// specific language governing permissions and limitations under +// each license. + +use c2pa::{Error, Reader}; +use cawg_identity::{claim_aggregation::IcaSignatureVerifier, IdentityAssertion}; +use serde_json::{Map, Value}; +use tokio::runtime::Runtime; + +/// Update/decorate the displayed JSON assertions for a more human-readable JSON output. +fn decorate_cawg_assertion_from_detailed_report( + reader: Reader, + json_content: &mut Value, + tokio_runtime: &Runtime, +) -> Result<(), Error> { + if let Value::Object(map) = json_content { + // Iterate over the key-value pairs + for (key, value) in &mut *map { + // Get additional CAWG details + + // Get the assertions as array from the JSON + let assertions = match value.get_mut("assertion_store") { + Some(assertions) => assertions, + None => { + return Err(crate::Error::JsonSerializationError( + "Could not parse JSON assertion store as object".to_string(), + )); + } + }; + + let cawg_assertion = match assertions.get_mut("cawg.identity") { + Some(cawg_assertion) => cawg_assertion, + None => { + return Err(crate::Error::JsonSerializationError( + "Could not parse CAWG identity details from assertion store".to_string(), + )); + } + }; + + let holding_manifest = match reader.get_manifest(key) { + Some(holding_manifest) => holding_manifest, + None => { + return Err(crate::Error::JsonSerializationError( + "Could not recover manifest holding CAWG data".to_string(), + )); + } + }; + + let parsed_cawg_json_string = + match get_cawg_details_for_manifest(holding_manifest, tokio_runtime) { + Some(parsed_cawg_json_string) => parsed_cawg_json_string, + None => { + // Not a show-stopper: + // Could not parse CAWG details for manifest, + // so leaving original raw data unformatted. + return Ok(()); + } + }; + + cawg_assertion["signature"] = match serde_json::from_str(&parsed_cawg_json_string) { + Ok(decoded_cawg_assertion) => decoded_cawg_assertion, + Err(err) => { + return Err(crate::Error::JsonSerializationError(err.to_string())); + } + }; + + let cawg_assertion = match cawg_assertion.as_object_mut() { + Some(cawg_assertion) => cawg_assertion, + None => { + return Err(crate::Error::JsonSerializationError( + "Could not parse CAWG assertion data as object to decorate for display" + .to_string(), + )); + } + }; + cawg_assertion.remove("pad1"); + cawg_assertion.remove("pad2"); + } + } + + Ok(()) +} + +/// Update/decorate the displayed JSON assertions for a more human-readable JSON output. +fn decorate_json_assertions( + reader: Reader, + json_content: &mut Value, + tokio_runtime: &Runtime, +) -> Result<(), Error> { + if let Value::Object(map) = json_content { + // Iterate over the key-value pairs + for (key, value) in &mut *map { + // Get additional CAWG details + let current_manifest = reader.get_manifest(key); + let current_manifest = match current_manifest { + Some(current_manifest) => current_manifest, + None => { + return Err(crate::Error::JsonSerializationError( + "Could not get current manifest".to_string(), + )); + } + }; + + // Get the assertions as array from the JSON + let assertions = match value.get_mut("assertions") { + Some(assertions) => assertions, + None => { + return Err(crate::Error::JsonSerializationError( + "Could not parse JSON assertions as object".to_string(), + )); + } + }; + let assertions_array = match assertions.as_array_mut() { + Some(assertions_array) => assertions_array, + None => { + return Err(crate::Error::JsonSerializationError( + "Could not parse JSON assertions as array".to_string(), + )); + } + }; + + // Loop over the assertions to process those of interest + for assertion in assertions_array { + let label = match assertion.get("label") { + Some(label) => label.to_string(), + None => { + return Err(crate::Error::JsonSerializationError( + "Could not parse assertion label".to_string(), + )); + } + }; + + // for CAWG assertions, further parse the signature + if label.contains("cawg.identity") { + decorate_json_cawg_assertions(current_manifest, assertion, tokio_runtime)?; + } + } + } + } + + Ok(()) +} + +/// Update/decorate the displayed CAWG assertion for a more human-readable JSON output. +fn decorate_json_cawg_assertions( + holding_manifest: &c2pa::Manifest, + assertion: &mut Value, + tokio_runtime: &Runtime, +) -> Result<(), Error> { + let parsed_cawg_json_string = + match get_cawg_details_for_manifest(holding_manifest, tokio_runtime) { + Some(parsed_cawg_json_string) => parsed_cawg_json_string, + None => { + // Could not parse CAWG details for manifest (leaving original raw data unformatted). + // Not a fatal failure, so leaving raw data unformatted. + return Ok(()); + } + }; + + // Let's look at the assertion data + let assertion_data = match assertion.get_mut("data") { + Some(assertion_data) => assertion_data, + None => { + return Err(crate::Error::JsonSerializationError( + "Could not parse CAWG assertion data".to_string(), + )); + } + }; + + // Update signature with parsed content + let parsed_signature = match serde_json::from_str(&parsed_cawg_json_string) { + Ok(parsed_signature) => parsed_signature, + Err(err) => { + return Err(crate::Error::JsonSerializationError(err.to_string())); + } + }; + assertion_data["signature"] = parsed_signature; + + // We don't need to show the padding fields either + let assertion_data_map = match assertion_data.as_object_mut() { + Some(assertion_data_map) => assertion_data_map, + None => { + return Err(crate::Error::JsonSerializationError( + "Could not parse CAWG assertion data as object".to_string(), + )); + } + }; + assertion_data_map.remove("pad1"); + assertion_data_map.remove("pad2"); + + Ok(()) +} + +/// Parse additional CAWG details from the manifest store to update displayed results. +/// As CAWG mostly async, this will block on network requests for checks using a tokio runtime. +fn get_cawg_details_for_manifest( + manifest: &c2pa::Manifest, + tokio_runtime: &Runtime, +) -> Option { + let ia_iter = IdentityAssertion::from_manifest(manifest); + + // TODO: Determine what should happen when multiple identities are reported (currently only 1 is supported) + let mut parsed_cawg_json = String::new(); + + ia_iter.for_each(|ia| { + let identity_assertion = match ia { + Ok(ia) => ia, + Err(err) => { + eprintln!("Could not parse CAWG identity assertion: {:?}", err); + return; + } + }; + + let isv = IcaSignatureVerifier {}; + let ica_validated = tokio_runtime.block_on(identity_assertion.validate(manifest, &isv)); + let ica = match ica_validated { + Ok(ica) => ica, + Err(err) => { + eprintln!("Could not validate CAWG identity assertion: {:?}", err); + return; + } + }; + + parsed_cawg_json = match serde_json::to_string(&ica) { + Ok(parsed_cawg_json) => parsed_cawg_json, + Err(err) => { + eprintln!( + "Could not parse CAWG identity claims aggregation details for manifest: {:?}", + err + ); + return; + } + }; + }); + + if parsed_cawg_json.is_empty() { + return None; + } + + // Get the JSON as mutable, so we can further parse and format CAWG data + let maybe_map = serde_json::from_str(parsed_cawg_json.as_str()); + let mut map: Map = match maybe_map { + Ok(map) => map, + Err(err) => { + eprintln!( + "Could not parse convert CAWG identity claims details to JSON string map: {:?}", + err + ); + return None; + } + }; + + // Get the credentials subject information... + let credentials_subject_maybe = map.get_mut("credentialSubject"); + let credentials_subject = match credentials_subject_maybe { + Some(credentials_subject) => credentials_subject, + None => { + eprintln!("Could not find credential subject in CAWG details for manifest"); + return None; + } + }; + let credentials_subject_as_obj = credentials_subject.as_object_mut(); + let credential_subject_details = match credentials_subject_as_obj { + Some(credentials_subject) => credentials_subject, + None => { + eprintln!("Could not parse credential subject as object in CAWG details for manifest"); + return None; + } + }; + // As per design CAWG has some repetition between assertion an signature (c2paAsset field) + // so we remove the c2paAsset field from the credential subject details too + credential_subject_details.remove("c2paAsset"); + + // return the for-display json-formatted string + let serialized_content = serde_json::to_string(&map); + match serialized_content { + Ok(serialized_content) => Some(serialized_content), + Err(err) => { + eprintln!("Could not parse CAWG details for manifest: {:?}", err); + None + } + } +} + +/// Update/decorate the detailed displayed JSON string for a more human-readable JSON output. +pub(crate) fn decorate_json_detailed_display( + reader: Reader, + extracted_report: String, + tokio_runtime: &Runtime, +) -> String { + let mut report_json_map: Map = match serde_json::from_str(&extracted_report) { + Ok(report_json_map) => report_json_map, + Err(err) => { + eprintln!("Could not parse extracted JSON report: {:?}", err); + return String::new(); + } + }; + + let manifests = match report_json_map.get_mut("manifests") { + Some(manifests) => manifests, + None => { + eprintln!("No parsable JSON in manifest store (key: manifests)"); + return String::new(); + } + }; + + match decorate_cawg_assertion_from_detailed_report(reader, manifests, tokio_runtime) { + Ok(_) => (), + Err(err) => { + eprintln!("Could not decorate detailed JSON for display: {:?}", err); + return String::new(); + } + }; + + match serde_json::to_string_pretty(&report_json_map) { + Ok(decorated_result) => decorated_result, + Err(err) => { + eprintln!( + "Could not decorate displayed detailed JSON with additional details: {:?}", + err + ); + String::new() + } + } +} + +/// Update/decorate the displayed JSON string for a more human-readable JSON output. +pub(crate) fn decorate_json_display(reader: Reader, tokio_runtime: &Runtime) -> String { + let mut reader_content = match reader.json_value_map() { + Ok(mapped_json) => mapped_json, + Err(_) => { + eprintln!("Could not parse manifest store JSON content"); + return String::new(); + } + }; + + let manifests_json_content = match reader_content.get_mut("manifests") { + Some(json) => json, + None => { + eprintln!("No JSON to parse in manifest store (key: manifests)"); + return String::new(); + } + }; + + // Update assertion with more details (eg. for CAWG) + match decorate_json_assertions(reader, manifests_json_content, tokio_runtime) { + Ok(_) => (), + Err(err) => { + eprintln!("Could not decorate JSON assertions for display: {:?}", err); + } + }; + match serde_json::to_string_pretty(&reader_content) { + Ok(decorated_result) => decorated_result, + Err(err) => { + eprintln!( + "Could not decorate displayed JSON with additional details: {:?}", + err + ); + String::new() + } + } +} diff --git a/cli/src/main.rs b/cli/src/main.rs index d07a6cd86..c5ee8ffa6 100644 --- a/cli/src/main.rs +++ b/cli/src/main.rs @@ -27,17 +27,16 @@ use std::{ use anyhow::{anyhow, bail, Context, Result}; use c2pa::{Builder, ClaimGeneratorInfo, Error, Ingredient, ManifestDefinition, Reader, Signer}; -use cawg_identity::{claim_aggregation::IcaSignatureVerifier, IdentityAssertion}; use clap::{Parser, Subcommand}; use log::debug; use serde::Deserialize; -use serde_json::{Map, Value}; use signer::SignConfig; use tokio::runtime::Runtime; use url::Url; use crate::{ callback_signer::{CallbackSigner, CallbackSignerConfig, ExternalProcessRunner}, + cawg_parser::{decorate_json_detailed_display, decorate_json_display}, info::info, }; @@ -45,6 +44,7 @@ mod info; mod tree; mod callback_signer; +mod cawg_parser; mod signer; /// Tool for displaying and creating C2PA manifests. @@ -427,358 +427,6 @@ fn verify_fragmented(init_pattern: &Path, frag_pattern: &Path) -> Result String { - let mut report_json_map: Map = match serde_json::from_str(&extracted_report) { - Ok(report_json_map) => report_json_map, - Err(err) => { - println!("Could not parse extracted JSON report: {:?}", err); - return String::new(); - } - }; - - let manifests = match report_json_map.get_mut("manifests") { - Some(manifests) => manifests, - None => { - println!("No parsable JSON in manifest store (key: manifests)"); - return String::new(); - } - }; - - match decorate_cawg_assertion_from_detailed_report(reader, manifests, tokio_runtime) { - Ok(_) => (), - Err(err) => { - println!("Could not decorate detailed JSON for display: {:?}", err); - } - }; - - match serde_json::to_string_pretty(&report_json_map) { - Ok(decorated_result) => decorated_result, - Err(err) => { - println!( - "Could not decorate displayed detailed JSON with additional details: {:?}", - err - ); - String::new() - } - } -} - -/// Update/decorate the displayed JSON assertions for a more human-readable JSON output. -fn decorate_cawg_assertion_from_detailed_report( - reader: Reader, - json_content: &mut Value, - tokio_runtime: &Runtime, -) -> Result<(), Error> { - if let Value::Object(map) = json_content { - // Iterate over the key-value pairs - for (key, value) in &mut *map { - // Get additional CAWG details - - // Get the assertions as array from the JSON - let assertions = match value.get_mut("assertion_store") { - Some(assertions) => assertions, - None => { - return Err(crate::Error::JsonSerializationError( - "Could not parse JSON assertion store as object".to_string(), - )); - } - }; - - let cawg_assertion = match assertions.get_mut("cawg.identity") { - Some(cawg_assertion) => cawg_assertion, - None => { - return Err(crate::Error::JsonSerializationError( - "Could not parse CAWG identity details from assertion store".to_string(), - )); - } - }; - - let holding_manifest = match reader.get_manifest(key) { - Some(holding_manifest) => holding_manifest, - None => { - return Err(crate::Error::JsonSerializationError( - "Could not recover manifest holding CAWG data".to_string(), - )); - } - }; - - let parsed_cawg_json_string = - match get_cawg_details_for_manifest(holding_manifest, tokio_runtime) { - Some(parsed_cawg_json_string) => parsed_cawg_json_string, - None => { - // Not a show-stopper: - // Could not parse CAWG details for manifest, - // so leaving original raw data unformatted. - return Ok(()); - } - }; - - cawg_assertion["signature"] = match serde_json::from_str(&parsed_cawg_json_string) { - Ok(decoded_cawg_assertion) => decoded_cawg_assertion, - Err(err) => { - return Err(crate::Error::JsonSerializationError(err.to_string())); - } - }; - - let cawg_assertion = match cawg_assertion.as_object_mut() { - Some(cawg_assertion) => cawg_assertion, - None => { - return Err(crate::Error::JsonSerializationError( - "Could not parse CAWG assertion data as object to decorate for display" - .to_string(), - )); - } - }; - cawg_assertion.remove("pad1"); - cawg_assertion.remove("pad2"); - } - } - - Ok(()) -} - -/// Update/decorate the displayed JSON string for a more human-readable JSON output. -fn decorate_json_display(reader: Reader, tokio_runtime: &Runtime) -> String { - let mut reader_content = match reader.json_value_map() { - Ok(mapped_json) => mapped_json, - Err(_) => { - eprintln!("Could not parse manifest store JSON content"); - return String::new(); - } - }; - - let manifests_json_content = match reader_content.get_mut("manifests") { - Some(json) => json, - None => { - eprintln!("No JSON to parse in manifest store (key: manifests)"); - return String::new(); - } - }; - - // Update assertion with more details (eg. for CAWG) - match decorate_json_assertions(reader, manifests_json_content, tokio_runtime) { - Ok(_) => (), - Err(err) => { - eprintln!("Could not decorate JSON assertions for display: {:?}", err); - } - }; - match serde_json::to_string_pretty(&reader_content) { - Ok(decorated_result) => decorated_result, - Err(err) => { - eprintln!( - "Could not decorate displayed JSON with additional details: {:?}", - err - ); - String::new() - } - } -} - -/// Update/decorate the displayed JSON assertions for a more human-readable JSON output. -fn decorate_json_assertions( - reader: Reader, - json_content: &mut Value, - tokio_runtime: &Runtime, -) -> Result<(), Error> { - if let Value::Object(map) = json_content { - // Iterate over the key-value pairs - for (key, value) in &mut *map { - // Get additional CAWG details - let current_manifest = reader.get_manifest(key); - let current_manifest = match current_manifest { - Some(current_manifest) => current_manifest, - None => { - return Err(crate::Error::JsonSerializationError( - "Could not get current manifest".to_string(), - )); - } - }; - - // Get the assertions as array from the JSON - let assertions = match value.get_mut("assertions") { - Some(assertions) => assertions, - None => { - return Err(crate::Error::JsonSerializationError( - "Could not parse JSON assertions as object".to_string(), - )); - } - }; - let assertions_array = match assertions.as_array_mut() { - Some(assertions_array) => assertions_array, - None => { - return Err(crate::Error::JsonSerializationError( - "Could not parse JSON assertions as array".to_string(), - )); - } - }; - - // Loop over the assertions to process those of interest - for assertion in assertions_array { - let label = match assertion.get("label") { - Some(label) => label.to_string(), - None => { - return Err(crate::Error::JsonSerializationError( - "Could not parse assertion label".to_string(), - )); - } - }; - - // for CAWG assertions, further parse the signature - if label.contains("cawg.identity") { - decorate_json_cawg_assertions(current_manifest, assertion, tokio_runtime)?; - } - } - } - } - - Ok(()) -} - -/// Update/decorate the displayed CAWG assertion for a more human-readable JSON output. -fn decorate_json_cawg_assertions( - holding_manifest: &c2pa::Manifest, - assertion: &mut Value, - tokio_runtime: &Runtime, -) -> Result<(), Error> { - let parsed_cawg_json_string = - match get_cawg_details_for_manifest(holding_manifest, tokio_runtime) { - Some(parsed_cawg_json_string) => parsed_cawg_json_string, - None => { - // Could not parse CAWG details for manifest (leaving original raw data unformatted). - // Not a fatal failure, so leaving raw data unformatted. - return Ok(()); - } - }; - - // Let's look at the assertion data - let assertion_data = match assertion.get_mut("data") { - Some(assertion_data) => assertion_data, - None => { - return Err(crate::Error::JsonSerializationError( - "Could not parse CAWG assertion data".to_string(), - )); - } - }; - - // Update signature with parsed content - let parsed_signature = match serde_json::from_str(&parsed_cawg_json_string) { - Ok(parsed_signature) => parsed_signature, - Err(err) => { - return Err(crate::Error::JsonSerializationError(err.to_string())); - } - }; - assertion_data["signature"] = parsed_signature; - - // We don't need to show the padding fields either - let assertion_data_map = match assertion_data.as_object_mut() { - Some(assertion_data_map) => assertion_data_map, - None => { - return Err(crate::Error::JsonSerializationError( - "Could not parse CAWG assertion data as object".to_string(), - )); - } - }; - assertion_data_map.remove("pad1"); - assertion_data_map.remove("pad2"); - - Ok(()) -} - -/// Parse additional CAWG details from the manifest store to update displayed results. -/// As CAWG mostly async, this will block on network requests for checks using a tokio runtime. -fn get_cawg_details_for_manifest( - manifest: &c2pa::Manifest, - tokio_runtime: &Runtime, -) -> Option { - let ia_iter = IdentityAssertion::from_manifest(manifest); - - // TODO: Determine what should happen when multiple identities are reported (currently only 1 is supported) - let mut parsed_cawg_json = String::new(); - - ia_iter.for_each(|ia| { - let identity_assertion = match ia { - Ok(ia) => ia, - Err(err) => { - eprintln!("Could not parse CAWG identity assertion: {:?}", err); - return; - } - }; - - let isv = IcaSignatureVerifier {}; - let ica_validated = tokio_runtime.block_on(identity_assertion.validate(manifest, &isv)); - let ica = match ica_validated { - Ok(ica) => ica, - Err(err) => { - eprintln!("Could not validate CAWG identity assertion: {:?}", err); - return; - } - }; - - parsed_cawg_json = match serde_json::to_string(&ica) { - Ok(parsed_cawg_json) => parsed_cawg_json, - Err(err) => { - eprintln!( - "Could not parse CAWG identity claims aggregation details for manifest: {:?}", - err - ); - return; - } - }; - }); - - if parsed_cawg_json.is_empty() { - return None; - } - - // Get the JSON as mutable, so we can further parse and format CAWG data - let maybe_map = serde_json::from_str(parsed_cawg_json.as_str()); - let mut map: Map = match maybe_map { - Ok(map) => map, - Err(err) => { - eprintln!( - "Could not parse convert CAWG identity claims details to JSON string map: {:?}", - err - ); - return None; - } - }; - - // Get the credentials subject information... - let credentials_subject_maybe = map.get_mut("credentialSubject"); - let credentials_subject = match credentials_subject_maybe { - Some(credentials_subject) => credentials_subject, - None => { - eprintln!("Could not find credential subject in CAWG details for manifest"); - return None; - } - }; - let credentials_subject_as_obj = credentials_subject.as_object_mut(); - let credential_subject_details = match credentials_subject_as_obj { - Some(credentials_subject) => credentials_subject, - None => { - eprintln!("Could not parse credential subject as object in CAWG details for manifest"); - return None; - } - }; - // As per design CAWG has some repetition between assertion an signature (c2paAsset field) - // so we remove the c2paAsset field from the credential subject details too - credential_subject_details.remove("c2paAsset"); - - // return the for-display json-formatted string - let serialized_content = serde_json::to_string(&map); - match serialized_content { - Ok(serialized_content) => Some(serialized_content), - Err(err) => { - eprintln!("Could not parse CAWG details for manifest: {:?}", err); - None - } - } -} - fn main() -> Result<()> { let args = CliArgs::parse(); @@ -1041,7 +689,7 @@ fn main() -> Result<()> { }; let decorated_details_manifest = - decorate_json_detailled_display(reader, extracted_json_report, &tokio_runtime); + decorate_json_detailed_display(reader, extracted_json_report, &tokio_runtime); println!("{}", decorated_details_manifest); } else if let Some(Commands::Fragment { fragments_glob: Some(fg), From 077a2850963cf248fd8cd9143490d225363e9f7d Mon Sep 17 00:00:00 2001 From: Tania Mathern Date: Fri, 7 Feb 2025 10:44:47 -0800 Subject: [PATCH 20/35] fix: Overhaul of error handling --- cli/src/cawg_parser.rs | 39 ++++++++++++++++++++++++--------------- cli/src/main.rs | 19 +++++++++---------- 2 files changed, 33 insertions(+), 25 deletions(-) diff --git a/cli/src/cawg_parser.rs b/cli/src/cawg_parser.rs index 23dab8233..dcbd43f2e 100644 --- a/cli/src/cawg_parser.rs +++ b/cli/src/cawg_parser.rs @@ -17,7 +17,7 @@ use tokio::runtime::Runtime; /// Update/decorate the displayed JSON assertions for a more human-readable JSON output. fn decorate_cawg_assertion_from_detailed_report( - reader: Reader, + reader: &Reader, json_content: &mut Value, tokio_runtime: &Runtime, ) -> Result<(), Error> { @@ -91,7 +91,7 @@ fn decorate_cawg_assertion_from_detailed_report( /// Update/decorate the displayed JSON assertions for a more human-readable JSON output. fn decorate_json_assertions( - reader: Reader, + reader: &Reader, json_content: &mut Value, tokio_runtime: &Runtime, ) -> Result<(), Error> { @@ -292,48 +292,57 @@ fn get_cawg_details_for_manifest( /// Update/decorate the detailed displayed JSON string for a more human-readable JSON output. pub(crate) fn decorate_json_detailed_display( - reader: Reader, - extracted_report: String, + reader: &Reader, tokio_runtime: &Runtime, -) -> String { +) -> Result { + let json_report = reader.json_report(); + let extracted_report = match json_report { + Ok(extracted_json_report) => extracted_json_report, + Err(err) => { + let message = format!("Could not parse JSON report: {:?}", err); + return Err(crate::Error::JsonSerializationError(message)); + } + }; + let mut report_json_map: Map = match serde_json::from_str(&extracted_report) { Ok(report_json_map) => report_json_map, Err(err) => { - eprintln!("Could not parse extracted JSON report: {:?}", err); - return String::new(); + let message = format!("Could not parse extracted JSON detailed report: {:?}", err); + return Err(crate::Error::JsonSerializationError(message)); } }; let manifests = match report_json_map.get_mut("manifests") { Some(manifests) => manifests, None => { - eprintln!("No parsable JSON in manifest store (key: manifests)"); - return String::new(); + return Err(crate::Error::JsonSerializationError( + "No parsable JSON in manifest store (key: manifests)".to_string(), + )); } }; match decorate_cawg_assertion_from_detailed_report(reader, manifests, tokio_runtime) { Ok(_) => (), Err(err) => { - eprintln!("Could not decorate detailed JSON for display: {:?}", err); - return String::new(); + let message = format!("Could not decorate detailed JSON for display: {:?}", err); + return Err(crate::Error::JsonSerializationError(message)); } }; match serde_json::to_string_pretty(&report_json_map) { - Ok(decorated_result) => decorated_result, + Ok(decorated_result) => Ok(decorated_result), Err(err) => { - eprintln!( + let message = format!( "Could not decorate displayed detailed JSON with additional details: {:?}", err ); - String::new() + return Err(crate::Error::JsonSerializationError(message)); } } } /// Update/decorate the displayed JSON string for a more human-readable JSON output. -pub(crate) fn decorate_json_display(reader: Reader, tokio_runtime: &Runtime) -> String { +pub(crate) fn decorate_json_display(reader: &Reader, tokio_runtime: &Runtime) -> String { let mut reader_content = match reader.json_value_map() { Ok(mapped_json) => mapped_json, Err(_) => { diff --git a/cli/src/main.rs b/cli/src/main.rs index c5ee8ffa6..3c83d3b70 100644 --- a/cli/src/main.rs +++ b/cli/src/main.rs @@ -681,16 +681,14 @@ fn main() -> Result<()> { ) } else if args.detailed { let reader = Reader::from_file(&args.path).map_err(special_errs)?; - - let json_report = reader.json_report(); - let extracted_json_report = match json_report { - Ok(extracted_json_report) => extracted_json_report, - Err(err) => format!("Could not parse JSON report: {:?}", err), + let decorated_details_manifest = decorate_json_detailed_display(&reader, &tokio_runtime); + match decorated_details_manifest { + Ok(decorated_details_manifest) => println!("{}", decorated_details_manifest), + Err(_) => { + // fall back to raw display of data (unparsed CAWG) + println!("{:#?}", reader) + } }; - - let decorated_details_manifest = - decorate_json_detailed_display(reader, extracted_json_report, &tokio_runtime); - println!("{}", decorated_details_manifest); } else if let Some(Commands::Fragment { fragments_glob: Some(fg), }) = &args.command @@ -703,7 +701,8 @@ fn main() -> Result<()> { } } else { let reader: Reader = Reader::from_file(&args.path).map_err(special_errs)?; - let stringified_decorated_json = decorate_json_display(reader, &tokio_runtime); + + let stringified_decorated_json = decorate_json_display(&reader, &tokio_runtime); println!("{}", stringified_decorated_json); } From b9c5c7af024333f7000e1074e7fbc70a813045e6 Mon Sep 17 00:00:00 2001 From: Tania Mathern Date: Fri, 7 Feb 2025 10:51:13 -0800 Subject: [PATCH 21/35] fix: Update error handling for non detailed view too --- cli/src/cawg_parser.rs | 27 ++++++++++++++++++--------- cli/src/main.rs | 12 ++++++++---- 2 files changed, 26 insertions(+), 13 deletions(-) diff --git a/cli/src/cawg_parser.rs b/cli/src/cawg_parser.rs index dcbd43f2e..6edadc4c1 100644 --- a/cli/src/cawg_parser.rs +++ b/cli/src/cawg_parser.rs @@ -342,20 +342,25 @@ pub(crate) fn decorate_json_detailed_display( } /// Update/decorate the displayed JSON string for a more human-readable JSON output. -pub(crate) fn decorate_json_display(reader: &Reader, tokio_runtime: &Runtime) -> String { +pub(crate) fn decorate_json_display( + reader: &Reader, + tokio_runtime: &Runtime, +) -> Result { let mut reader_content = match reader.json_value_map() { Ok(mapped_json) => mapped_json, Err(_) => { - eprintln!("Could not parse manifest store JSON content"); - return String::new(); + return Err(crate::Error::JsonSerializationError( + "Could not parse manifest store JSON content".to_string(), + )); } }; let manifests_json_content = match reader_content.get_mut("manifests") { Some(json) => json, None => { - eprintln!("No JSON to parse in manifest store (key: manifests)"); - return String::new(); + return Err(crate::Error::JsonSerializationError( + "No JSON to parse in manifest store (key: manifests)".to_string(), + )); } }; @@ -363,17 +368,21 @@ pub(crate) fn decorate_json_display(reader: &Reader, tokio_runtime: &Runtime) -> match decorate_json_assertions(reader, manifests_json_content, tokio_runtime) { Ok(_) => (), Err(err) => { - eprintln!("Could not decorate JSON assertions for display: {:?}", err); + let message = format!( + "Could not decorate displayed JSON with additional details: {:?}", + err + ); + return Err(crate::Error::JsonSerializationError(message)); } }; match serde_json::to_string_pretty(&reader_content) { - Ok(decorated_result) => decorated_result, + Ok(decorated_result) => Ok(decorated_result), Err(err) => { - eprintln!( + let message = format!( "Could not decorate displayed JSON with additional details: {:?}", err ); - String::new() + return Err(crate::Error::JsonSerializationError(message)); } } } diff --git a/cli/src/main.rs b/cli/src/main.rs index 3c83d3b70..adce3b7e3 100644 --- a/cli/src/main.rs +++ b/cli/src/main.rs @@ -685,7 +685,7 @@ fn main() -> Result<()> { match decorated_details_manifest { Ok(decorated_details_manifest) => println!("{}", decorated_details_manifest), Err(_) => { - // fall back to raw display of data (unparsed CAWG) + // fall back to raw debug display of data (unparsed CAWG) println!("{:#?}", reader) } }; @@ -701,9 +701,13 @@ fn main() -> Result<()> { } } else { let reader: Reader = Reader::from_file(&args.path).map_err(special_errs)?; - - let stringified_decorated_json = decorate_json_display(&reader, &tokio_runtime); - println!("{}", stringified_decorated_json); + match decorate_json_display(&reader, &tokio_runtime) { + Ok(stringified_decorated_json) => println!("{}", stringified_decorated_json), + Err(_) => { + // fall back to raw display of data (unparsed CAWG) + println!("{:?}", reader) + } + }; } Ok(()) From 5cffc27c3a28b8107a09e984296a85a41b979fc0 Mon Sep 17 00:00:00 2001 From: Tania Mathern Date: Fri, 7 Feb 2025 10:52:23 -0800 Subject: [PATCH 22/35] fix: Format --- cli/src/cawg_parser.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/cli/src/cawg_parser.rs b/cli/src/cawg_parser.rs index 6edadc4c1..60a8c80cd 100644 --- a/cli/src/cawg_parser.rs +++ b/cli/src/cawg_parser.rs @@ -336,7 +336,7 @@ pub(crate) fn decorate_json_detailed_display( "Could not decorate displayed detailed JSON with additional details: {:?}", err ); - return Err(crate::Error::JsonSerializationError(message)); + Err(crate::Error::JsonSerializationError(message)) } } } @@ -382,7 +382,7 @@ pub(crate) fn decorate_json_display( "Could not decorate displayed JSON with additional details: {:?}", err ); - return Err(crate::Error::JsonSerializationError(message)); + Err(crate::Error::JsonSerializationError(message)) } } } From ea923201eaa1abb28141ae3a5d76f2154ecb4b89 Mon Sep 17 00:00:00 2001 From: Tania Mathern Date: Fri, 7 Feb 2025 10:54:26 -0800 Subject: [PATCH 23/35] ci: Clarify comment --- cli/src/main.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/cli/src/main.rs b/cli/src/main.rs index adce3b7e3..2b4e109ae 100644 --- a/cli/src/main.rs +++ b/cli/src/main.rs @@ -685,7 +685,7 @@ fn main() -> Result<()> { match decorated_details_manifest { Ok(decorated_details_manifest) => println!("{}", decorated_details_manifest), Err(_) => { - // fall back to raw debug display of data (unparsed CAWG) + // non-fatal: fall back to raw debug display of data (unparsed CAWG) println!("{:#?}", reader) } }; @@ -704,7 +704,7 @@ fn main() -> Result<()> { match decorate_json_display(&reader, &tokio_runtime) { Ok(stringified_decorated_json) => println!("{}", stringified_decorated_json), Err(_) => { - // fall back to raw display of data (unparsed CAWG) + // non-fatal: fall back to raw display of data (unparsed CAWG) println!("{:?}", reader) } }; From b8ad8355c21d1c9bf8875f692083c29fed7fc5df Mon Sep 17 00:00:00 2001 From: Tania Mathern Date: Fri, 7 Feb 2025 11:03:34 -0800 Subject: [PATCH 24/35] fix: Refactor --- cli/src/cawg_parser.rs | 4 +++- sdk/src/reader.rs | 26 ++++++++++++++++++-------- 2 files changed, 21 insertions(+), 9 deletions(-) diff --git a/cli/src/cawg_parser.rs b/cli/src/cawg_parser.rs index 60a8c80cd..755a372f0 100644 --- a/cli/src/cawg_parser.rs +++ b/cli/src/cawg_parser.rs @@ -10,6 +10,8 @@ // specific language governing permissions and limitations under // each license. +use std::convert::TryInto; + use c2pa::{Error, Reader}; use cawg_identity::{claim_aggregation::IcaSignatureVerifier, IdentityAssertion}; use serde_json::{Map, Value}; @@ -346,7 +348,7 @@ pub(crate) fn decorate_json_display( reader: &Reader, tokio_runtime: &Runtime, ) -> Result { - let mut reader_content = match reader.json_value_map() { + let mut reader_content: serde_json::Map = match reader.try_into() { Ok(mapped_json) => mapped_json, Err(_) => { return Err(crate::Error::JsonSerializationError( diff --git a/sdk/src/reader.rs b/sdk/src/reader.rs index 973f0d519..5ce414c6d 100644 --- a/sdk/src/reader.rs +++ b/sdk/src/reader.rs @@ -247,14 +247,6 @@ impl Reader { self.manifest_store.to_string() } - /// Get the manifest store as a serde serialized JSON value map. - pub fn json_value_map(&self) -> Result> { - match serde_json::from_str(self.json().as_str()) { - Ok(mapped_json) => Ok(mapped_json), - Err(err) => Err(crate::Error::JsonSerializationError(err.to_string())), - } - } - // Get a full reader (manifest and manifest store) report as a JSON string. pub fn json_report(&self) -> Result { let report = ManifestStoreReport::from_store(self.manifest_store.store()); @@ -450,6 +442,24 @@ impl Default for Reader { } } +impl TryInto> for Reader { + type Error = crate::Error; + + /// Get the manifest store as a serde serialized JSON value map. + fn try_into(self) -> Result> { + serde_json::from_str(self.json().as_str()).map_err(crate::Error::JsonError) + } +} + +impl TryInto> for &Reader { + type Error = crate::Error; + + /// Get the manifest store as a serde serialized JSON value map. + fn try_into(self) -> Result> { + serde_json::from_str(self.json().as_str()).map_err(crate::Error::JsonError) + } +} + /// Prints the JSON of the manifest data. impl std::fmt::Display for Reader { fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { From 346f040b2243e35d0cae85680eff8d71010f18fb Mon Sep 17 00:00:00 2001 From: Tania Mathern Date: Fri, 7 Feb 2025 11:08:07 -0800 Subject: [PATCH 25/35] ci: Format --- cli/src/{cawg_parser.rs => display_decorator.rs} | 4 ++++ cli/src/main.rs | 8 ++++---- sdk/src/reader.rs | 1 - 3 files changed, 8 insertions(+), 5 deletions(-) rename cli/src/{cawg_parser.rs => display_decorator.rs} (99%) diff --git a/cli/src/cawg_parser.rs b/cli/src/display_decorator.rs similarity index 99% rename from cli/src/cawg_parser.rs rename to cli/src/display_decorator.rs index 755a372f0..92149453d 100644 --- a/cli/src/cawg_parser.rs +++ b/cli/src/display_decorator.rs @@ -323,6 +323,7 @@ pub(crate) fn decorate_json_detailed_display( } }; + // Update assertion with more details (eg. for CAWG) match decorate_cawg_assertion_from_detailed_report(reader, manifests, tokio_runtime) { Ok(_) => (), Err(err) => { @@ -331,6 +332,7 @@ pub(crate) fn decorate_json_detailed_display( } }; + // return decorated detailed JSON to display match serde_json::to_string_pretty(&report_json_map) { Ok(decorated_result) => Ok(decorated_result), Err(err) => { @@ -377,6 +379,8 @@ pub(crate) fn decorate_json_display( return Err(crate::Error::JsonSerializationError(message)); } }; + + // return decorated JSON to display match serde_json::to_string_pretty(&reader_content) { Ok(decorated_result) => Ok(decorated_result), Err(err) => { diff --git a/cli/src/main.rs b/cli/src/main.rs index 2b4e109ae..50957e582 100644 --- a/cli/src/main.rs +++ b/cli/src/main.rs @@ -36,7 +36,7 @@ use url::Url; use crate::{ callback_signer::{CallbackSigner, CallbackSignerConfig, ExternalProcessRunner}, - cawg_parser::{decorate_json_detailed_display, decorate_json_display}, + display_decorator::{decorate_json_detailed_display, decorate_json_display}, info::info, }; @@ -44,7 +44,7 @@ mod info; mod tree; mod callback_signer; -mod cawg_parser; +mod display_decorator; mod signer; /// Tool for displaying and creating C2PA manifests. @@ -685,7 +685,7 @@ fn main() -> Result<()> { match decorated_details_manifest { Ok(decorated_details_manifest) => println!("{}", decorated_details_manifest), Err(_) => { - // non-fatal: fall back to raw debug display of data (unparsed CAWG) + // non-fatal: fall back to raw debug display of data (eg. unparsed CAWG) println!("{:#?}", reader) } }; @@ -704,7 +704,7 @@ fn main() -> Result<()> { match decorate_json_display(&reader, &tokio_runtime) { Ok(stringified_decorated_json) => println!("{}", stringified_decorated_json), Err(_) => { - // non-fatal: fall back to raw display of data (unparsed CAWG) + // non-fatal: fall back to raw display of data (eg. unparsed CAWG) println!("{:?}", reader) } }; diff --git a/sdk/src/reader.rs b/sdk/src/reader.rs index 5ce414c6d..d33d46e27 100644 --- a/sdk/src/reader.rs +++ b/sdk/src/reader.rs @@ -23,7 +23,6 @@ use c2pa_status_tracker::DetailedStatusTracker; #[cfg(feature = "json_schema")] use schemars::JsonSchema; use serde::{Deserialize, Serialize}; -use serde_json::{Map, Value}; #[cfg(feature = "file_io")] use crate::error::Error; From dc48058bf1bcd707420f88443ed67ae35a8375b7 Mon Sep 17 00:00:00 2001 From: Tania Mathern Date: Fri, 7 Feb 2025 11:26:27 -0800 Subject: [PATCH 26/35] fix: Add test --- cli/tests/integration.rs | 19 +++++++++++++++++++ 1 file changed, 19 insertions(+) diff --git a/cli/tests/integration.rs b/cli/tests/integration.rs index 77ba0ad9e..4eabe8aa7 100644 --- a/cli/tests/integration.rs +++ b/cli/tests/integration.rs @@ -564,3 +564,22 @@ fn tool_read_image_with_cawg_data() -> Result<(), Box> { .stdout(str::contains("IdentityClaimsAggregationCredential")); Ok(()) } + +#[test] +// c2patool --detailed C_with_CAWG_data.jpg +fn tool_read_image_with_details_with_cawg_data() -> Result<(), Box> { + Command::cargo_bin("c2patool")? + .arg(fixture_path("C_with_CAWG_data.jpg")) + .arg("--detailed") + .assert() + .success() + .stdout(str::contains("assertion_store")) + .stdout(str::contains("cawg.identity")) + .stdout(str::contains("credentialSubject")) + .stdout(str::contains("verifiedIdentities")) + .stdout(str::contains("credentialSchema")) + .stdout(str::contains("cawg.social_media")) + .stdout(str::contains("VerifiableCredential")) + .stdout(str::contains("IdentityClaimsAggregationCredential")); + Ok(()) +} From 2a7d66de0316ed27d12fa5b9838d67bfb0cbed79 Mon Sep 17 00:00:00 2001 From: Tania Mathern Date: Fri, 7 Feb 2025 11:28:28 -0800 Subject: [PATCH 27/35] fix: Add test --- cli/src/display_decorator.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cli/src/display_decorator.rs b/cli/src/display_decorator.rs index 92149453d..d87d06f08 100644 --- a/cli/src/display_decorator.rs +++ b/cli/src/display_decorator.rs @@ -1,4 +1,4 @@ -// Copyright 2022 Adobe. All rights reserved. +// Copyright 2025 Adobe. All rights reserved. // This file is licensed to you under the Apache License, // Version 2.0 (http://www.apache.org/licenses/LICENSE-2.0) // or the MIT license (http://opensource.org/licenses/MIT), From 7d2418add9e92c9c855e24911a8a1fc58d59211c Mon Sep 17 00:00:00 2001 From: Tania Mathern Date: Fri, 7 Feb 2025 11:41:21 -0800 Subject: [PATCH 28/35] ci: Some more refactor --- cli/src/decorators/cawg_decorator.rs | 231 +++++++++++++++++++++++++++ cli/src/decorators/mod.rs | 13 ++ cli/src/display_decorator.rs | 218 +------------------------ cli/src/main.rs | 1 + 4 files changed, 248 insertions(+), 215 deletions(-) create mode 100644 cli/src/decorators/cawg_decorator.rs create mode 100644 cli/src/decorators/mod.rs diff --git a/cli/src/decorators/cawg_decorator.rs b/cli/src/decorators/cawg_decorator.rs new file mode 100644 index 000000000..ded342c9e --- /dev/null +++ b/cli/src/decorators/cawg_decorator.rs @@ -0,0 +1,231 @@ +// Copyright 2025 Adobe. All rights reserved. +// This file is licensed to you under the Apache License, +// Version 2.0 (http://www.apache.org/licenses/LICENSE-2.0) +// or the MIT license (http://opensource.org/licenses/MIT), +// at your option. +// Unless required by applicable law or agreed to in writing, +// this software is distributed on an "AS IS" BASIS, WITHOUT +// WARRANTIES OR REPRESENTATIONS OF ANY KIND, either express or +// implied. See the LICENSE-MIT and LICENSE-APACHE files for the +// specific language governing permissions and limitations under +// each license. + +use c2pa::{Error, Reader}; +use cawg_identity::{claim_aggregation::IcaSignatureVerifier, IdentityAssertion}; +use serde_json::{Map, Value}; +use tokio::runtime::Runtime; + +/// Update/decorate the displayed JSON assertions for a more human-readable JSON output. +pub(crate) fn decorate_cawg_assertion_from_detailed_report( + reader: &Reader, + json_content: &mut Value, + tokio_runtime: &Runtime, +) -> Result<(), Error> { + if let Value::Object(map) = json_content { + // Iterate over the key-value pairs + for (key, value) in &mut *map { + // Get additional CAWG details + + // Get the assertions as array from the JSON + let assertions = match value.get_mut("assertion_store") { + Some(assertions) => assertions, + None => { + return Err(crate::Error::JsonSerializationError( + "Could not parse JSON assertion store as object".to_string(), + )); + } + }; + + let cawg_assertion = match assertions.get_mut("cawg.identity") { + Some(cawg_assertion) => cawg_assertion, + None => { + return Err(crate::Error::JsonSerializationError( + "Could not parse CAWG identity details from assertion store".to_string(), + )); + } + }; + + let holding_manifest = match reader.get_manifest(key) { + Some(holding_manifest) => holding_manifest, + None => { + return Err(crate::Error::JsonSerializationError( + "Could not recover manifest holding CAWG data".to_string(), + )); + } + }; + + let parsed_cawg_json_string = + match get_cawg_details_for_manifest(holding_manifest, tokio_runtime) { + Some(parsed_cawg_json_string) => parsed_cawg_json_string, + None => { + // Not a show-stopper: + // Could not parse CAWG details for manifest, + // so leaving original raw data unformatted. + return Ok(()); + } + }; + + cawg_assertion["signature"] = match serde_json::from_str(&parsed_cawg_json_string) { + Ok(decoded_cawg_assertion) => decoded_cawg_assertion, + Err(err) => { + return Err(crate::Error::JsonSerializationError(err.to_string())); + } + }; + + let cawg_assertion = match cawg_assertion.as_object_mut() { + Some(cawg_assertion) => cawg_assertion, + None => { + return Err(crate::Error::JsonSerializationError( + "Could not parse CAWG assertion data as object to decorate for display" + .to_string(), + )); + } + }; + cawg_assertion.remove("pad1"); + cawg_assertion.remove("pad2"); + } + } + + Ok(()) +} + +/// Update/decorate the displayed CAWG assertion for a more human-readable JSON output. +pub(crate) fn decorate_json_cawg_assertions( + holding_manifest: &c2pa::Manifest, + assertion: &mut Value, + tokio_runtime: &Runtime, +) -> Result<(), Error> { + let parsed_cawg_json_string = + match get_cawg_details_for_manifest(holding_manifest, tokio_runtime) { + Some(parsed_cawg_json_string) => parsed_cawg_json_string, + None => { + // Could not parse CAWG details for manifest (leaving original raw data unformatted). + // Not a fatal failure, so leaving raw data unformatted. + return Ok(()); + } + }; + + // Let's look at the assertion data + let assertion_data = match assertion.get_mut("data") { + Some(assertion_data) => assertion_data, + None => { + return Err(crate::Error::JsonSerializationError( + "Could not parse CAWG assertion data".to_string(), + )); + } + }; + + // Update signature with parsed content + let parsed_signature = match serde_json::from_str(&parsed_cawg_json_string) { + Ok(parsed_signature) => parsed_signature, + Err(err) => { + return Err(crate::Error::JsonSerializationError(err.to_string())); + } + }; + assertion_data["signature"] = parsed_signature; + + // We don't need to show the padding fields either + let assertion_data_map = match assertion_data.as_object_mut() { + Some(assertion_data_map) => assertion_data_map, + None => { + return Err(crate::Error::JsonSerializationError( + "Could not parse CAWG assertion data as object".to_string(), + )); + } + }; + assertion_data_map.remove("pad1"); + assertion_data_map.remove("pad2"); + + Ok(()) +} + +/// Parse additional CAWG details from the manifest store to update displayed results. +/// As CAWG mostly async, this will block on network requests for checks using a tokio runtime. +fn get_cawg_details_for_manifest( + manifest: &c2pa::Manifest, + tokio_runtime: &Runtime, +) -> Option { + let ia_iter = IdentityAssertion::from_manifest(manifest); + + // TODO: Determine what should happen when multiple identities are reported (currently only 1 is supported) + let mut parsed_cawg_json = String::new(); + + ia_iter.for_each(|ia| { + let identity_assertion = match ia { + Ok(ia) => ia, + Err(err) => { + eprintln!("Could not parse CAWG identity assertion: {:?}", err); + return; + } + }; + + let isv = IcaSignatureVerifier {}; + let ica_validated = tokio_runtime.block_on(identity_assertion.validate(manifest, &isv)); + let ica = match ica_validated { + Ok(ica) => ica, + Err(err) => { + eprintln!("Could not validate CAWG identity assertion: {:?}", err); + return; + } + }; + + parsed_cawg_json = match serde_json::to_string(&ica) { + Ok(parsed_cawg_json) => parsed_cawg_json, + Err(err) => { + eprintln!( + "Could not parse CAWG identity claims aggregation details for manifest: {:?}", + err + ); + return; + } + }; + }); + + if parsed_cawg_json.is_empty() { + return None; + } + + // Get the JSON as mutable, so we can further parse and format CAWG data + let maybe_map = serde_json::from_str(parsed_cawg_json.as_str()); + let mut map: Map = match maybe_map { + Ok(map) => map, + Err(err) => { + eprintln!( + "Could not parse convert CAWG identity claims details to JSON string map: {:?}", + err + ); + return None; + } + }; + + // Get the credentials subject information... + let credentials_subject_maybe = map.get_mut("credentialSubject"); + let credentials_subject = match credentials_subject_maybe { + Some(credentials_subject) => credentials_subject, + None => { + eprintln!("Could not find credential subject in CAWG details for manifest"); + return None; + } + }; + let credentials_subject_as_obj = credentials_subject.as_object_mut(); + let credential_subject_details = match credentials_subject_as_obj { + Some(credentials_subject) => credentials_subject, + None => { + eprintln!("Could not parse credential subject as object in CAWG details for manifest"); + return None; + } + }; + // As per design CAWG has some repetition between assertion an signature (c2paAsset field) + // so we remove the c2paAsset field from the credential subject details too + credential_subject_details.remove("c2paAsset"); + + // return the for-display json-formatted string + let serialized_content = serde_json::to_string(&map); + match serialized_content { + Ok(serialized_content) => Some(serialized_content), + Err(err) => { + eprintln!("Could not parse CAWG details for manifest: {:?}", err); + None + } + } +} diff --git a/cli/src/decorators/mod.rs b/cli/src/decorators/mod.rs new file mode 100644 index 000000000..4e1d1963f --- /dev/null +++ b/cli/src/decorators/mod.rs @@ -0,0 +1,13 @@ +// Copyright 2025 Adobe. All rights reserved. +// This file is licensed to you under the Apache License, +// Version 2.0 (http://www.apache.org/licenses/LICENSE-2.0) +// or the MIT license (http://opensource.org/licenses/MIT), +// at your option. +// Unless required by applicable law or agreed to in writing, +// this software is distributed on an "AS IS" BASIS, WITHOUT +// WARRANTIES OR REPRESENTATIONS OF ANY KIND, either express or +// implied. See the LICENSE-MIT and LICENSE-APACHE files for the +// specific language governing permissions and limitations under +// each license. + +pub mod cawg_decorator; diff --git a/cli/src/display_decorator.rs b/cli/src/display_decorator.rs index d87d06f08..09e9be8e2 100644 --- a/cli/src/display_decorator.rs +++ b/cli/src/display_decorator.rs @@ -13,83 +13,12 @@ use std::convert::TryInto; use c2pa::{Error, Reader}; -use cawg_identity::{claim_aggregation::IcaSignatureVerifier, IdentityAssertion}; use serde_json::{Map, Value}; use tokio::runtime::Runtime; -/// Update/decorate the displayed JSON assertions for a more human-readable JSON output. -fn decorate_cawg_assertion_from_detailed_report( - reader: &Reader, - json_content: &mut Value, - tokio_runtime: &Runtime, -) -> Result<(), Error> { - if let Value::Object(map) = json_content { - // Iterate over the key-value pairs - for (key, value) in &mut *map { - // Get additional CAWG details - - // Get the assertions as array from the JSON - let assertions = match value.get_mut("assertion_store") { - Some(assertions) => assertions, - None => { - return Err(crate::Error::JsonSerializationError( - "Could not parse JSON assertion store as object".to_string(), - )); - } - }; - - let cawg_assertion = match assertions.get_mut("cawg.identity") { - Some(cawg_assertion) => cawg_assertion, - None => { - return Err(crate::Error::JsonSerializationError( - "Could not parse CAWG identity details from assertion store".to_string(), - )); - } - }; - - let holding_manifest = match reader.get_manifest(key) { - Some(holding_manifest) => holding_manifest, - None => { - return Err(crate::Error::JsonSerializationError( - "Could not recover manifest holding CAWG data".to_string(), - )); - } - }; - - let parsed_cawg_json_string = - match get_cawg_details_for_manifest(holding_manifest, tokio_runtime) { - Some(parsed_cawg_json_string) => parsed_cawg_json_string, - None => { - // Not a show-stopper: - // Could not parse CAWG details for manifest, - // so leaving original raw data unformatted. - return Ok(()); - } - }; - - cawg_assertion["signature"] = match serde_json::from_str(&parsed_cawg_json_string) { - Ok(decoded_cawg_assertion) => decoded_cawg_assertion, - Err(err) => { - return Err(crate::Error::JsonSerializationError(err.to_string())); - } - }; - - let cawg_assertion = match cawg_assertion.as_object_mut() { - Some(cawg_assertion) => cawg_assertion, - None => { - return Err(crate::Error::JsonSerializationError( - "Could not parse CAWG assertion data as object to decorate for display" - .to_string(), - )); - } - }; - cawg_assertion.remove("pad1"); - cawg_assertion.remove("pad2"); - } - } - - Ok(()) -} +use crate::decorators::cawg_decorator::{ + decorate_cawg_assertion_from_detailed_report, decorate_json_cawg_assertions, +}; /// Update/decorate the displayed JSON assertions for a more human-readable JSON output. fn decorate_json_assertions( @@ -151,147 +80,6 @@ fn decorate_json_assertions( Ok(()) } -/// Update/decorate the displayed CAWG assertion for a more human-readable JSON output. -fn decorate_json_cawg_assertions( - holding_manifest: &c2pa::Manifest, - assertion: &mut Value, - tokio_runtime: &Runtime, -) -> Result<(), Error> { - let parsed_cawg_json_string = - match get_cawg_details_for_manifest(holding_manifest, tokio_runtime) { - Some(parsed_cawg_json_string) => parsed_cawg_json_string, - None => { - // Could not parse CAWG details for manifest (leaving original raw data unformatted). - // Not a fatal failure, so leaving raw data unformatted. - return Ok(()); - } - }; - - // Let's look at the assertion data - let assertion_data = match assertion.get_mut("data") { - Some(assertion_data) => assertion_data, - None => { - return Err(crate::Error::JsonSerializationError( - "Could not parse CAWG assertion data".to_string(), - )); - } - }; - - // Update signature with parsed content - let parsed_signature = match serde_json::from_str(&parsed_cawg_json_string) { - Ok(parsed_signature) => parsed_signature, - Err(err) => { - return Err(crate::Error::JsonSerializationError(err.to_string())); - } - }; - assertion_data["signature"] = parsed_signature; - - // We don't need to show the padding fields either - let assertion_data_map = match assertion_data.as_object_mut() { - Some(assertion_data_map) => assertion_data_map, - None => { - return Err(crate::Error::JsonSerializationError( - "Could not parse CAWG assertion data as object".to_string(), - )); - } - }; - assertion_data_map.remove("pad1"); - assertion_data_map.remove("pad2"); - - Ok(()) -} - -/// Parse additional CAWG details from the manifest store to update displayed results. -/// As CAWG mostly async, this will block on network requests for checks using a tokio runtime. -fn get_cawg_details_for_manifest( - manifest: &c2pa::Manifest, - tokio_runtime: &Runtime, -) -> Option { - let ia_iter = IdentityAssertion::from_manifest(manifest); - - // TODO: Determine what should happen when multiple identities are reported (currently only 1 is supported) - let mut parsed_cawg_json = String::new(); - - ia_iter.for_each(|ia| { - let identity_assertion = match ia { - Ok(ia) => ia, - Err(err) => { - eprintln!("Could not parse CAWG identity assertion: {:?}", err); - return; - } - }; - - let isv = IcaSignatureVerifier {}; - let ica_validated = tokio_runtime.block_on(identity_assertion.validate(manifest, &isv)); - let ica = match ica_validated { - Ok(ica) => ica, - Err(err) => { - eprintln!("Could not validate CAWG identity assertion: {:?}", err); - return; - } - }; - - parsed_cawg_json = match serde_json::to_string(&ica) { - Ok(parsed_cawg_json) => parsed_cawg_json, - Err(err) => { - eprintln!( - "Could not parse CAWG identity claims aggregation details for manifest: {:?}", - err - ); - return; - } - }; - }); - - if parsed_cawg_json.is_empty() { - return None; - } - - // Get the JSON as mutable, so we can further parse and format CAWG data - let maybe_map = serde_json::from_str(parsed_cawg_json.as_str()); - let mut map: Map = match maybe_map { - Ok(map) => map, - Err(err) => { - eprintln!( - "Could not parse convert CAWG identity claims details to JSON string map: {:?}", - err - ); - return None; - } - }; - - // Get the credentials subject information... - let credentials_subject_maybe = map.get_mut("credentialSubject"); - let credentials_subject = match credentials_subject_maybe { - Some(credentials_subject) => credentials_subject, - None => { - eprintln!("Could not find credential subject in CAWG details for manifest"); - return None; - } - }; - let credentials_subject_as_obj = credentials_subject.as_object_mut(); - let credential_subject_details = match credentials_subject_as_obj { - Some(credentials_subject) => credentials_subject, - None => { - eprintln!("Could not parse credential subject as object in CAWG details for manifest"); - return None; - } - }; - // As per design CAWG has some repetition between assertion an signature (c2paAsset field) - // so we remove the c2paAsset field from the credential subject details too - credential_subject_details.remove("c2paAsset"); - - // return the for-display json-formatted string - let serialized_content = serde_json::to_string(&map); - match serialized_content { - Ok(serialized_content) => Some(serialized_content), - Err(err) => { - eprintln!("Could not parse CAWG details for manifest: {:?}", err); - None - } - } -} - /// Update/decorate the detailed displayed JSON string for a more human-readable JSON output. pub(crate) fn decorate_json_detailed_display( reader: &Reader, diff --git a/cli/src/main.rs b/cli/src/main.rs index 50957e582..ac194915a 100644 --- a/cli/src/main.rs +++ b/cli/src/main.rs @@ -44,6 +44,7 @@ mod info; mod tree; mod callback_signer; +mod decorators; mod display_decorator; mod signer; From 1c262b2292bd0452d7466ee09db49086af061a5d Mon Sep 17 00:00:00 2001 From: Tania Mathern Date: Fri, 7 Feb 2025 11:45:09 -0800 Subject: [PATCH 29/35] fix: Clarify comments --- cli/src/display_decorator.rs | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/cli/src/display_decorator.rs b/cli/src/display_decorator.rs index 09e9be8e2..9d5271fb9 100644 --- a/cli/src/display_decorator.rs +++ b/cli/src/display_decorator.rs @@ -16,10 +16,14 @@ use c2pa::{Error, Reader}; use serde_json::{Map, Value}; use tokio::runtime::Runtime; +// the decorators we know about an plan to use use crate::decorators::cawg_decorator::{ decorate_cawg_assertion_from_detailed_report, decorate_json_cawg_assertions, }; +// Display decorators for JSON output/display +// We do not mutate any Reader here, only make JSON output "nicer"" + /// Update/decorate the displayed JSON assertions for a more human-readable JSON output. fn decorate_json_assertions( reader: &Reader, @@ -69,7 +73,7 @@ fn decorate_json_assertions( } }; - // for CAWG assertions, further parse the signature + // here we decorate something: for CAWG assertions, further parse the signature if label.contains("cawg.identity") { decorate_json_cawg_assertions(current_manifest, assertion, tokio_runtime)?; } @@ -111,7 +115,7 @@ pub(crate) fn decorate_json_detailed_display( } }; - // Update assertion with more details (eg. for CAWG) + // Here we decorate something: Update assertion with more details (eg. for CAWG) match decorate_cawg_assertion_from_detailed_report(reader, manifests, tokio_runtime) { Ok(_) => (), Err(err) => { From 772570a4e97525d4d7ac8c3b02ec7fec9854ee4b Mon Sep 17 00:00:00 2001 From: Tania Mathern Date: Fri, 7 Feb 2025 11:47:27 -0800 Subject: [PATCH 30/35] ci: Refactor --- cli/src/display_decorator.rs | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/cli/src/display_decorator.rs b/cli/src/display_decorator.rs index 9d5271fb9..ddce6b981 100644 --- a/cli/src/display_decorator.rs +++ b/cli/src/display_decorator.rs @@ -22,7 +22,8 @@ use crate::decorators::cawg_decorator::{ }; // Display decorators for JSON output/display -// We do not mutate any Reader here, only make JSON output "nicer"" +// We do not mutate any Reader here, only make JSON output "nicer", +// by doing some additional parsing or clean-ups. /// Update/decorate the displayed JSON assertions for a more human-readable JSON output. fn decorate_json_assertions( From 18f1a0d9b3c396f5035f94754690940507cefe4b Mon Sep 17 00:00:00 2001 From: Tania Mathern Date: Fri, 7 Feb 2025 11:48:10 -0800 Subject: [PATCH 31/35] ci: Refactor --- cli/src/display_decorator.rs | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/cli/src/display_decorator.rs b/cli/src/display_decorator.rs index ddce6b981..055882d7c 100644 --- a/cli/src/display_decorator.rs +++ b/cli/src/display_decorator.rs @@ -32,9 +32,8 @@ fn decorate_json_assertions( tokio_runtime: &Runtime, ) -> Result<(), Error> { if let Value::Object(map) = json_content { - // Iterate over the key-value pairs for (key, value) in &mut *map { - // Get additional CAWG details + // extract manifest we're looking at let current_manifest = reader.get_manifest(key); let current_manifest = match current_manifest { Some(current_manifest) => current_manifest, From 7b740808c3732381808e5a6c35dd662727db4e6d Mon Sep 17 00:00:00 2001 From: Tania Mathern Date: Fri, 7 Feb 2025 12:51:47 -0800 Subject: [PATCH 32/35] fix: No need to process stuff we don't use --- sdk/src/manifest_store.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/sdk/src/manifest_store.rs b/sdk/src/manifest_store.rs index d3a5f6c9e..3bf7586cf 100644 --- a/sdk/src/manifest_store.rs +++ b/sdk/src/manifest_store.rs @@ -594,8 +594,8 @@ impl std::fmt::Display for ManifestStore { // Reason of padding, see note at: // https://c2pa.org/specifications/specifications/2.1/specs/C2PA_Specification.html#_going_back_and_filling_in json = omit_tag(json, "pad"); - json = omit_tag(json, "pad1"); - json = omit_tag(json, "pad2"); + // json = omit_tag(json, "pad1"); + // json = omit_tag(json, "pad2"); f.write_str(&json) } From 9a12f0fd694bbac6d09e401459c9ef4b46b578ce Mon Sep 17 00:00:00 2001 From: Tania Mathern Date: Fri, 7 Feb 2025 12:52:04 -0800 Subject: [PATCH 33/35] fix: Remove debug code --- sdk/src/manifest_store.rs | 2 -- 1 file changed, 2 deletions(-) diff --git a/sdk/src/manifest_store.rs b/sdk/src/manifest_store.rs index 3bf7586cf..a0119145e 100644 --- a/sdk/src/manifest_store.rs +++ b/sdk/src/manifest_store.rs @@ -594,8 +594,6 @@ impl std::fmt::Display for ManifestStore { // Reason of padding, see note at: // https://c2pa.org/specifications/specifications/2.1/specs/C2PA_Specification.html#_going_back_and_filling_in json = omit_tag(json, "pad"); - // json = omit_tag(json, "pad1"); - // json = omit_tag(json, "pad2"); f.write_str(&json) } From 2b7e13d8579ef0bfa809a84e3c5db8c118735504 Mon Sep 17 00:00:00 2001 From: Tania Mathern Date: Fri, 7 Feb 2025 13:08:17 -0800 Subject: [PATCH 34/35] fix: Remove some more stuff --- cli/src/display_decorator.rs | 9 +-------- sdk/src/reader.rs | 11 ----------- 2 files changed, 1 insertion(+), 19 deletions(-) diff --git a/cli/src/display_decorator.rs b/cli/src/display_decorator.rs index 055882d7c..9f2119ebf 100644 --- a/cli/src/display_decorator.rs +++ b/cli/src/display_decorator.rs @@ -89,14 +89,7 @@ pub(crate) fn decorate_json_detailed_display( reader: &Reader, tokio_runtime: &Runtime, ) -> Result { - let json_report = reader.json_report(); - let extracted_report = match json_report { - Ok(extracted_json_report) => extracted_json_report, - Err(err) => { - let message = format!("Could not parse JSON report: {:?}", err); - return Err(crate::Error::JsonSerializationError(message)); - } - }; + let extracted_report = format!("{:#?}", reader); let mut report_json_map: Map = match serde_json::from_str(&extracted_report) { Ok(report_json_map) => report_json_map, diff --git a/sdk/src/reader.rs b/sdk/src/reader.rs index d33d46e27..d91ee3413 100644 --- a/sdk/src/reader.rs +++ b/sdk/src/reader.rs @@ -246,17 +246,6 @@ impl Reader { self.manifest_store.to_string() } - // Get a full reader (manifest and manifest store) report as a JSON string. - pub fn json_report(&self) -> Result { - let report = ManifestStoreReport::from_store(self.manifest_store.store()); - let mut report = match report { - Ok(report) => report, - Err(err) => return Err(crate::Error::JsonSerializationError(err.to_string())), - }; - report.validation_results = self.manifest_store.validation_results().cloned(); - Ok(report.to_string()) - } - /// Get the [`ValidationStatus`] array of the manifest store if it exists. /// Call this method to check for validation errors. /// From fdd1906db8dc1a606a224cb97953c9ca907a68e1 Mon Sep 17 00:00:00 2001 From: Tania Mathern Date: Fri, 7 Feb 2025 14:33:50 -0800 Subject: [PATCH 35/35] ci: Undo new error --- cli/src/decorators/cawg_decorator.rs | 35 ++++++++++----------- cli/src/display_decorator.rs | 46 +++++++++++++--------------- sdk/src/error.rs | 3 -- 3 files changed, 38 insertions(+), 46 deletions(-) diff --git a/cli/src/decorators/cawg_decorator.rs b/cli/src/decorators/cawg_decorator.rs index ded342c9e..f6ed6ebca 100644 --- a/cli/src/decorators/cawg_decorator.rs +++ b/cli/src/decorators/cawg_decorator.rs @@ -10,7 +10,7 @@ // specific language governing permissions and limitations under // each license. -use c2pa::{Error, Reader}; +use c2pa::Reader; use cawg_identity::{claim_aggregation::IcaSignatureVerifier, IdentityAssertion}; use serde_json::{Map, Value}; use tokio::runtime::Runtime; @@ -20,7 +20,7 @@ pub(crate) fn decorate_cawg_assertion_from_detailed_report( reader: &Reader, json_content: &mut Value, tokio_runtime: &Runtime, -) -> Result<(), Error> { +) -> Result<(), anyhow::Error> { if let Value::Object(map) = json_content { // Iterate over the key-value pairs for (key, value) in &mut *map { @@ -30,8 +30,8 @@ pub(crate) fn decorate_cawg_assertion_from_detailed_report( let assertions = match value.get_mut("assertion_store") { Some(assertions) => assertions, None => { - return Err(crate::Error::JsonSerializationError( - "Could not parse JSON assertion store as object".to_string(), + return Err(anyhow::Error::msg( + "Could not parse JSON assertions as object", )); } }; @@ -39,8 +39,8 @@ pub(crate) fn decorate_cawg_assertion_from_detailed_report( let cawg_assertion = match assertions.get_mut("cawg.identity") { Some(cawg_assertion) => cawg_assertion, None => { - return Err(crate::Error::JsonSerializationError( - "Could not parse CAWG identity details from assertion store".to_string(), + return Err(anyhow::Error::msg( + "Could not parse CAWG identity details from assertion store", )); } }; @@ -48,8 +48,8 @@ pub(crate) fn decorate_cawg_assertion_from_detailed_report( let holding_manifest = match reader.get_manifest(key) { Some(holding_manifest) => holding_manifest, None => { - return Err(crate::Error::JsonSerializationError( - "Could not recover manifest holding CAWG data".to_string(), + return Err(anyhow::Error::msg( + "Could not recover manifest holding CAWG data", )); } }; @@ -68,16 +68,15 @@ pub(crate) fn decorate_cawg_assertion_from_detailed_report( cawg_assertion["signature"] = match serde_json::from_str(&parsed_cawg_json_string) { Ok(decoded_cawg_assertion) => decoded_cawg_assertion, Err(err) => { - return Err(crate::Error::JsonSerializationError(err.to_string())); + return Err(anyhow::Error::msg(err.to_string())); } }; let cawg_assertion = match cawg_assertion.as_object_mut() { Some(cawg_assertion) => cawg_assertion, None => { - return Err(crate::Error::JsonSerializationError( - "Could not parse CAWG assertion data as object to decorate for display" - .to_string(), + return Err(anyhow::Error::msg( + "Could not parse CAWG assertion data as object to decorate for display", )); } }; @@ -94,7 +93,7 @@ pub(crate) fn decorate_json_cawg_assertions( holding_manifest: &c2pa::Manifest, assertion: &mut Value, tokio_runtime: &Runtime, -) -> Result<(), Error> { +) -> Result<(), anyhow::Error> { let parsed_cawg_json_string = match get_cawg_details_for_manifest(holding_manifest, tokio_runtime) { Some(parsed_cawg_json_string) => parsed_cawg_json_string, @@ -109,9 +108,7 @@ pub(crate) fn decorate_json_cawg_assertions( let assertion_data = match assertion.get_mut("data") { Some(assertion_data) => assertion_data, None => { - return Err(crate::Error::JsonSerializationError( - "Could not parse CAWG assertion data".to_string(), - )); + return Err(anyhow::Error::msg("Could not parse CAWG assertion data")); } }; @@ -119,7 +116,7 @@ pub(crate) fn decorate_json_cawg_assertions( let parsed_signature = match serde_json::from_str(&parsed_cawg_json_string) { Ok(parsed_signature) => parsed_signature, Err(err) => { - return Err(crate::Error::JsonSerializationError(err.to_string())); + return Err(anyhow::Error::msg(err.to_string())); } }; assertion_data["signature"] = parsed_signature; @@ -128,8 +125,8 @@ pub(crate) fn decorate_json_cawg_assertions( let assertion_data_map = match assertion_data.as_object_mut() { Some(assertion_data_map) => assertion_data_map, None => { - return Err(crate::Error::JsonSerializationError( - "Could not parse CAWG assertion data as object".to_string(), + return Err(anyhow::Error::msg( + "Could not parse CAWG assertion data as object", )); } }; diff --git a/cli/src/display_decorator.rs b/cli/src/display_decorator.rs index 9f2119ebf..01898f70b 100644 --- a/cli/src/display_decorator.rs +++ b/cli/src/display_decorator.rs @@ -12,7 +12,7 @@ use std::convert::TryInto; -use c2pa::{Error, Reader}; +use c2pa::Reader; use serde_json::{Map, Value}; use tokio::runtime::Runtime; @@ -30,7 +30,7 @@ fn decorate_json_assertions( reader: &Reader, json_content: &mut Value, tokio_runtime: &Runtime, -) -> Result<(), Error> { +) -> Result<(), anyhow::Error> { if let Value::Object(map) = json_content { for (key, value) in &mut *map { // extract manifest we're looking at @@ -38,8 +38,8 @@ fn decorate_json_assertions( let current_manifest = match current_manifest { Some(current_manifest) => current_manifest, None => { - return Err(crate::Error::JsonSerializationError( - "Could not get current manifest".to_string(), + return Err(anyhow::Error::msg( + "Could not recover manifest for assertion decoration", )); } }; @@ -48,16 +48,16 @@ fn decorate_json_assertions( let assertions = match value.get_mut("assertions") { Some(assertions) => assertions, None => { - return Err(crate::Error::JsonSerializationError( - "Could not parse JSON assertions as object".to_string(), + return Err(anyhow::Error::msg( + "Could not parse JSON assertions as object", )); } }; let assertions_array = match assertions.as_array_mut() { Some(assertions_array) => assertions_array, None => { - return Err(crate::Error::JsonSerializationError( - "Could not parse JSON assertions as array".to_string(), + return Err(anyhow::Error::msg( + "Could not parse JSON assertions as array", )); } }; @@ -67,9 +67,7 @@ fn decorate_json_assertions( let label = match assertion.get("label") { Some(label) => label.to_string(), None => { - return Err(crate::Error::JsonSerializationError( - "Could not parse assertion label".to_string(), - )); + return Err(anyhow::Error::msg("Could not parse assertion label")); } }; @@ -88,22 +86,22 @@ fn decorate_json_assertions( pub(crate) fn decorate_json_detailed_display( reader: &Reader, tokio_runtime: &Runtime, -) -> Result { +) -> Result { let extracted_report = format!("{:#?}", reader); let mut report_json_map: Map = match serde_json::from_str(&extracted_report) { Ok(report_json_map) => report_json_map, Err(err) => { let message = format!("Could not parse extracted JSON detailed report: {:?}", err); - return Err(crate::Error::JsonSerializationError(message)); + return Err(anyhow::Error::msg(message)); } }; let manifests = match report_json_map.get_mut("manifests") { Some(manifests) => manifests, None => { - return Err(crate::Error::JsonSerializationError( - "No parsable JSON in manifest store (key: manifests)".to_string(), + return Err(anyhow::Error::msg( + "No parsable JSON in manifest store (key: manifests)", )); } }; @@ -113,7 +111,7 @@ pub(crate) fn decorate_json_detailed_display( Ok(_) => (), Err(err) => { let message = format!("Could not decorate detailed JSON for display: {:?}", err); - return Err(crate::Error::JsonSerializationError(message)); + return Err(anyhow::Error::msg(message)); } }; @@ -125,7 +123,7 @@ pub(crate) fn decorate_json_detailed_display( "Could not decorate displayed detailed JSON with additional details: {:?}", err ); - Err(crate::Error::JsonSerializationError(message)) + Err(anyhow::Error::msg(message)) } } } @@ -134,12 +132,12 @@ pub(crate) fn decorate_json_detailed_display( pub(crate) fn decorate_json_display( reader: &Reader, tokio_runtime: &Runtime, -) -> Result { +) -> Result { let mut reader_content: serde_json::Map = match reader.try_into() { Ok(mapped_json) => mapped_json, Err(_) => { - return Err(crate::Error::JsonSerializationError( - "Could not parse manifest store JSON content".to_string(), + return Err(anyhow::Error::msg( + "Could not parse manifest store JSON content", )); } }; @@ -147,8 +145,8 @@ pub(crate) fn decorate_json_display( let manifests_json_content = match reader_content.get_mut("manifests") { Some(json) => json, None => { - return Err(crate::Error::JsonSerializationError( - "No JSON to parse in manifest store (key: manifests)".to_string(), + return Err(anyhow::Error::msg( + "No JSON to parse in manifest store (key: manifests)", )); } }; @@ -161,7 +159,7 @@ pub(crate) fn decorate_json_display( "Could not decorate displayed JSON with additional details: {:?}", err ); - return Err(crate::Error::JsonSerializationError(message)); + return Err(anyhow::Error::msg(message)); } }; @@ -173,7 +171,7 @@ pub(crate) fn decorate_json_display( "Could not decorate displayed JSON with additional details: {:?}", err ); - Err(crate::Error::JsonSerializationError(message)) + Err(anyhow::Error::msg(message)) } } } diff --git a/sdk/src/error.rs b/sdk/src/error.rs index 0757bbc53..0dc95dfa4 100644 --- a/sdk/src/error.rs +++ b/sdk/src/error.rs @@ -252,9 +252,6 @@ pub enum Error { #[error("The Verifiable Content structure is not valid")] VerifiableCredentialInvalid, - #[error("error while serializing to JSON: {0}")] - JsonSerializationError(String), - /// Could not parse ECDSA signature. (Only appears when using WASM web crypto.) #[error("could not parse ECDSA signature")] InvalidEcdsaSignature,