-
Notifications
You must be signed in to change notification settings - Fork 4
feat/new compiler #33
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: main
Are you sure you want to change the base?
Conversation
…dregex-in-sdk-and-relayerutils Rutefig/reg 473 fix testdecomposedregex in sdk and relayerutils
WalkthroughRefactors circuit input generation into Circom and Noir modules, introduces an internal regex subsystem with wasm bindings, removes monolithic Changes
Sequence Diagram(s)sequenceDiagram
autonumber
participant User
participant Browser
participant NoirProver as NoirProver (browser)
participant CircomProver as CircomProver (browser)
participant SDK as zk-email SDK / Relayer
participant Worker as Prover Worker
participant Snarkjs as snarkjs
User->>Browser: Click "Prove"
Browser->>NoirProver: setupNoirProver(container)
Browser->>CircomProver: setupCircomProver(container)
NoirProver->>SDK: init WASM, fetch blueprint, parse EML
CircomProver->>SDK: init WASM, fetch blueprint, parse EML
SDK-->>NoirProver: decomposed regexes / circuit inputs
SDK-->>CircomProver: decomposed regexes / circuit inputs
CircomProver->>Worker: post inputs (wasm/zkey URLs + inputs)
Worker->>Worker: download chunks, uncompress, concatenate
Worker->>Snarkjs: groth16.fullProve(inputs, wasm, zkey)
Snarkjs-->>Worker: proof + public signals
Worker-->>CircomProver: proof & signals
NoirProver->>NoirProver: run Noir backend → proof
NoirProver-->>Browser: proof & parsed public outputs
CircomProver-->>Browser: proof & parsed public outputs
sequenceDiagram
autonumber
participant App
participant RegexMod as src/regex
participant Extract as extract.rs
participant NFAG as NFAGraph (optional)
App->>RegexMod: extract_substr_idxes(input, config, nfa?, reveal_private)
alt NFAGraph provided
Extract->>Extract: compose_pattern_for_nfa(nfa)
else
Extract->>Extract: compose_pattern_standalone(config)
end
Extract->>Extract: compile & match
alt match
Extract-->>App: return indices/substrings
else
Extract-->>App: return NoMatch/Error
end
Estimated code review effort🎯 4 (Complex) | ⏱️ ~60 minutes Areas to focus during review:
Possibly related PRs
Suggested reviewers
Pre-merge checks and finishing touches❌ Failed checks (1 inconclusive)
✅ Passed checks (2 passed)
✨ Finishing touches
🧪 Generate unit tests (beta)
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Actionable comments posted: 20
Caution
Some comments are outside the diff and can’t be posted inline due to platform limitations.
⚠️ Outside diff range comments (1)
src/parse_email.rs (1)
323-343: Critical: Functional bug from incomplete padding removal. The cleaned_body is padded to original_len but index_map is not.The issue goes beyond documentation. At
src/circuit/utils.rs:29,find_selector_in_clean_contentindexes intoposition_mapusing indices from the cleaned content. Sincecleaned_bodyis padded with zeros to match the original length butindex_mapis not, any selector match found in the padded region will attempt to access an out-of-bounds index inposition_map. This affectsget_adjusted_selector(called atsrc/circuit/mod.rs:164).The fix requires either:
- Not padding
cleaned_bodyto original length (only padindex_mapwithusize::MAXas documented), or- Padding
index_mapto matchcleaned_body.len()withusize::MAXentriesRecommend option 1: Remove the
.resize(original_len, 0)call and adjust callers that depend on the padded length.
🧹 Nitpick comments (6)
Cargo.toml (1)
16-16: Consider using semantic versions instead of git revisions.The
zk-regex-compilerdependency is pinned to a specific git revision (35014c2bff69115bb92be2dc2c9b006fa69a6649). While this ensures reproducible builds, it makes it harder to track updates and security patches. Consider requesting the upstream maintainers to publish versioned releases, or document why this specific revision is required.src/regex/padding.rs (2)
1-22: Consider adding test coverage for truncation behavior.The documentation clearly warns about silent truncation, which is good. However, the test suite doesn't verify this truncation behavior. Consider adding a test case to ensure callers are aware of this critical behavior.
Add a test case like:
#[test] fn test_pad_string_truncates_silently() { let input = "hello_world"; // 11 bytes let padded = pad_string(input, 5); assert_eq!(padded.len(), 5); assert_eq!(&padded[..], b"hello"); }
24-36: Document truncation behavior for consistency.Similar to
pad_string, this function will silently truncate ifdataexceedstarget_len. Consider documenting this behavior for consistency./// Pads a byte slice to the specified size with zero bytes /// /// # Arguments /// * `data` - The bytes to pad /// * `target_len` - The target length in bytes /// /// # Returns /// A vector of bytes padded to target_len with zeros +/// +/// # Behavior +/// - If the input data is shorter than `target_len`, it will be padded with zeros +/// - If the input data is exactly `target_len` bytes, it will be returned as-is +/// - If the input data exceeds `target_len`, it will be silently truncatedbrowser_test/src/prover-server.ts (1)
15-15: Consider parameterizing the blueprint ID.The blueprint ID is hardcoded, making the script less flexible. Consider accepting it as a command-line argument or environment variable.
const blueprintId = process.env.BLUEPRINT_ID || "8241f8bd-9fe7-443d-a09d-0150dcc7e85e";browser_test/src/noirProver.ts (1)
97-109: Handle required external inputs or surface them to the user.
addMaxLengthToExternalInputs([], blueprint.props.externalInputs)throws if the blueprint expects any external inputs, so proving simply fails with “You must provide the external input…”. Either gather values from the UI before calling this helper or defer wiring them until the user supplies them. At minimum, guard this path so the demo doesn’t explode on blueprints that require external data.src/circuit/noir/utils.rs (1)
319-350: Clarify the padding detection heuristic.The heuristic approach uses multiple fallback strategies, which is pragmatic. However, line 327's comment states "Check if everything after 0x80 is zeros or length encoding" but the code
all(|&b| b != 0x80)actually checks that there's no additional 0x80 byte in the remaining data. This is a reasonable heuristic but may have edge cases where legitimate data contains 0x80 bytes.Consider clarifying the comment:
- // Check if everything after 0x80 is zeros or length encoding + // Check if there's no other 0x80 byte in the remaining data (to avoid false positives) let after_padding = &data[padding_start + 1..];You may also want to add tests to verify this function handles edge cases correctly, especially when the data contains legitimate 0x80 bytes before the padding.
📜 Review details
Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro
⛔ Files ignored due to path filters (4)
Cargo.lockis excluded by!**/*.lockbrowser_test/bun.lockis excluded by!**/*.lockbrowser_test/public/vite.svgis excluded by!**/*.svgyarn.lockis excluded by!**/yarn.lock,!**/*.lock
📒 Files selected for processing (35)
.gitignore(1 hunks)Cargo.toml(2 hunks)browser_test/.gitignore(1 hunks)browser_test/index.html(1 hunks)browser_test/package.json(1 hunks)browser_test/public/amazon.eml(1 hunks)browser_test/public/github.eml(1 hunks)browser_test/public/residency.eml(1 hunks)browser_test/public/x.eml(1 hunks)browser_test/src/circomProver.ts(1 hunks)browser_test/src/localProverWorker.js(1 hunks)browser_test/src/main.ts(1 hunks)browser_test/src/noirProver.ts(1 hunks)browser_test/src/prover-server.ts(1 hunks)browser_test/src/style.css(1 hunks)browser_test/tsconfig.json(1 hunks)browser_test/vite.config.js(1 hunks)package.json(1 hunks)src/circuit.rs(0 hunks)src/circuit/circom.rs(1 hunks)src/circuit/mod.rs(1 hunks)src/circuit/noir/mod.rs(1 hunks)src/circuit/noir/structs.rs(1 hunks)src/circuit/noir/utils.rs(1 hunks)src/circuit/utils.rs(1 hunks)src/cryptos.rs(9 hunks)src/lib.rs(2 hunks)src/parse_email.rs(5 hunks)src/regex/extract.rs(1 hunks)src/regex/mod.rs(1 hunks)src/regex/padding.rs(1 hunks)src/regex/patterns.rs(1 hunks)src/regex/types.rs(1 hunks)src/regex/wasm.rs(1 hunks)src/wasm.rs(10 hunks)
💤 Files with no reviewable changes (1)
- src/circuit.rs
🧰 Additional context used
🧬 Code graph analysis (14)
src/lib.rs (3)
src/regex/patterns.rs (8)
extract_body_hash_idxes(106-108)extract_email_addr_idxes(81-83)extract_email_domain_idxes(86-88)extract_from_addr_idxes(91-93)extract_message_id_idxes(116-118)extract_subject_all_idxes(101-103)extract_timestamp_idxes(111-113)extract_to_addr_idxes(96-98)src/regex/extract.rs (2)
extract_substr(374-386)extract_substr_idxes(188-201)src/regex/padding.rs (2)
pad_bytes(32-36)pad_string(18-22)
browser_test/vite.config.js (1)
build.js (1)
path(2-2)
browser_test/src/noirProver.ts (1)
src/wasm.rs (2)
parseEmail(51-77)generateNoirCircuitInputsWithRegexesAndExternalInputs(605-652)
browser_test/src/main.ts (2)
browser_test/src/noirProver.ts (1)
setupNoirProver(5-163)browser_test/src/circomProver.ts (1)
setupCircomProver(22-209)
src/circuit/mod.rs (4)
src/cryptos.rs (5)
generate_partial_sha(494-564)sha256_pad(426-462)new(59-61)new(260-262)new(335-343)src/parse_email.rs (1)
remove_quoted_printable_soft_breaks(323-344)src/converters.rs (1)
to_circom_bigint_bytes(254-256)src/circuit/utils.rs (1)
get_adjusted_selector(66-87)
src/parse_email.rs (2)
src/regex/patterns.rs (8)
extract_body_hash_idxes(106-108)extract_email_addr_idxes(81-83)extract_email_domain_idxes(86-88)extract_from_addr_idxes(91-93)extract_message_id_idxes(116-118)extract_subject_all_idxes(101-103)extract_timestamp_idxes(111-113)extract_to_addr_idxes(96-98)src/regex/extract.rs (1)
extract_substr_idxes(188-201)
src/regex/patterns.rs (1)
src/regex/extract.rs (2)
extract_substr(374-386)extract_substr_idxes(188-201)
browser_test/src/prover-server.ts (1)
src/wasm.rs (1)
generateCircuitInputsWithDecomposedRegexesAndExternalInputs(168-222)
src/regex/wasm.rs (3)
src/regex/extract.rs (2)
extract_substr(374-386)extract_substr_idxes(188-201)src/regex/padding.rs (1)
pad_string(18-22)src/regex/patterns.rs (7)
extract_email_addr_idxes(81-83)extract_from_addr_idxes(91-93)extract_to_addr_idxes(96-98)extract_subject_all_idxes(101-103)extract_body_hash_idxes(106-108)extract_timestamp_idxes(111-113)extract_message_id_idxes(116-118)
src/circuit/circom.rs (5)
src/converters.rs (4)
field_to_hex(76-79)hex_to_u256(302-308)string_to_circom_bigint_bytes(463-483)vec_u8_to_bigint(265-269)src/parse_email.rs (3)
find_index_in_body(359-371)remove_quoted_printable_soft_breaks(323-344)new_from_raw_email(49-75)src/circuit/noir/utils.rs (1)
trim_sha256_padding(319-350)src/circuit/mod.rs (2)
generate_circuit_inputs(134-196)new(98-113)src/cryptos.rs (5)
from(273-275)new(59-61)new(260-262)new(335-343)from_email_addr(111-128)
src/circuit/noir/mod.rs (5)
src/parse_email.rs (2)
remove_quoted_printable_soft_breaks(323-344)new_from_raw_email(49-75)src/converters.rs (2)
string_to_circom_bigint_bytes(463-483)vec_u8_to_bigint(265-269)src/circuit/circom.rs (2)
compute_signal_length(577-579)clone(122-139)src/circuit/mod.rs (2)
generate_circuit_inputs(134-196)new(98-113)src/circuit/noir/utils.rs (6)
bn_to_limb_str_array(101-134)bn_to_redc_limb_str_array(161-164)get_header_sequence(195-228)u8_to_u32(304-317)get_address_header_sequence(248-290)trim_sha256_padding(319-350)
src/cryptos.rs (2)
src/regex/padding.rs (1)
pad_string(18-22)src/converters.rs (2)
hex_to_field(20-67)field_to_hex(76-79)
browser_test/src/circomProver.ts (1)
src/wasm.rs (2)
parseEmail(51-77)generateCircuitInputsWithDecomposedRegexesAndExternalInputs(168-222)
src/wasm.rs (2)
src/circuit/noir/mod.rs (2)
generate_noir_circuit_input(26-176)generate_noir_circuit_inputs_with_regexes_and_external_inputs(178-342)src/regex/wasm.rs (3)
extractSubstrIdxes(15-47)from_value(22-22)from_value(58-58)
🪛 ast-grep (0.39.6)
browser_test/src/main.ts
[warning] 4-18: Direct modification of innerHTML or outerHTML properties detected. Modifying these properties with unsanitized user input can lead to XSS vulnerabilities. Use safe alternatives or sanitize content first.
Context: document.querySelector("#app")!.innerHTML = `
ZK Email SDK Browser Test
(dom-content-modification)
[warning] 4-18: Direct HTML content assignment detected. Modifying innerHTML, outerHTML, or using document.write with unsanitized content can lead to XSS vulnerabilities. Use secure alternatives like textContent or sanitize HTML with libraries like DOMPurify.
Context: document.querySelector("#app")!.innerHTML = `
ZK Email SDK Browser Test
(unsafe-html-content-assignment)
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (1)
- GitHub Check: build-test
🔇 Additional comments (23)
package.json (1)
13-13: LGTM! Version bump to pre-release.The version update to
0.4.66-8follows semantic versioning with a pre-release suffix, which is appropriate for development builds..gitignore (1)
11-12: LGTM! Appropriate ignore entries for development artifacts.Adding
.claudeandthoughts/to version control exclusions prevents personal notes and AI-generated artifacts from being committed.browser_test/.gitignore (1)
1-24: LGTM! Comprehensive ignore patterns for browser test project.The ignore patterns appropriately cover logs, build artifacts, dependencies, and IDE-specific files, following standard Node.js/Vite project conventions.
Cargo.toml (1)
19-25: LGTM! Well-chosen dependencies added.The new dependencies are appropriate:
thiserrorfor ergonomic error handlingfancy-regexfor advanced regex featuresnum-traitsfor numeric trait abstractionsAll are well-maintained, widely-used crates in the Rust ecosystem.
browser_test/package.json (1)
18-32: No changes required—duplication is intentional.The two snarkjs packages serve distinct purposes:
snarkjs@^0.7.5is used inprover-server.tsfor standard Groth16 functionality, while@zk-email/snarkjs@^0.0.1is used inlocalProverWorker.jsfor ZK-Email's specialized chunked zkey support. They are imported in different files and do not conflict; this is a valid and intentional complementary dependency structure.browser_test/tsconfig.json (1)
1-23: LGTM!The TypeScript configuration is well-structured with appropriate compiler options for a browser-based Vite project. Strict mode and linting rules are properly enabled.
browser_test/src/style.css (1)
1-96: LGTM!The stylesheet provides clean, modern styling with proper light/dark theme support and responsive design. The layout and typography choices are appropriate for a browser testing UI.
browser_test/src/main.ts (1)
21-22: LGTM!The prover initialization is straightforward and correct. The non-null assertions are safe here since the DOM elements were just created in the previous statement.
src/parse_email.rs (2)
6-10: LGTM!The import refactoring correctly replaces the external
zk_regex_apisdependency with the new internalcrate::regexmodule, aligning with the PR's goal to internalize regex extraction functionality.
209-214: LGTM!All call sites correctly updated to match the new signature of
extract_substr_idxes, which now accepts an optionalNFAGraphparameter. PassingNonemaintains the existing behavior while supporting the new NFAGraph-based extraction path.Also applies to: 227-232, 266-279, 290-290
src/regex/padding.rs (1)
38-59: LGTM!The test coverage validates the padding behavior correctly. The suggestion to add truncation tests is optional.
browser_test/vite.config.js (1)
1-80: LGTM!The Vite configuration properly sets up Node.js polyfills required for running ZK proving operations in the browser. The extensive alias mappings and polyfill plugins are standard and necessary for this use case.
browser_test/src/prover-server.ts (2)
29-51: LGTM!Blueprint fetching and email validation include proper error handling with clear logging.
53-121: LGTM!Circuit input generation includes proper validation for missing regex graphs and haystack lengths. The Map-to-object conversion is handled correctly.
src/regex/mod.rs (1)
1-32: LGTM!The module structure is clean and well-documented. The hybrid extraction approach (with/without NFAGraph) is clearly explained, and the re-exports provide a convenient public API surface.
src/circuit/noir/mod.rs (3)
208-231: LGTM - Clean external input handling.The code properly handles missing external input values with
unwrap_or("")and applies appropriate padding to match the required signal length.
270-339: LGTM - Comprehensive regex result handling.The code properly validates that capture group data is complete (IDs, starts, and indices) and returns clear errors when required fields are missing. The rejection of Circom inputs in this Noir-specific function is appropriate.
344-361: LGTM - Clean helper functions.The JSON conversion helpers provide a clean interface for backward compatibility and interoperability with JSON-based systems.
src/circuit/noir/utils.rs (1)
195-228: LGTM - Proper error handling for header sequence extraction.The function correctly uses
Resultfor error handling and provides clear error messages for edge cases like empty field names and missing fields.src/circuit/circom.rs (4)
20-56: LGTM - Well-structured data types.The structs are well-documented and use appropriate serde attributes for optional field handling.
58-162: LGTM - Robust serialization infrastructure.The
SerializableRegexPartabstraction with bidirectionalFromimplementations and custom serde module enables clean JSON round-tripping. The customDebugimplementation that hides the large regex graph JSON is a nice touch for debugging.
415-454: LGTM - Proper haystack extraction logic.The code correctly handles both header and body locations, applies appropriate cleaning based on
remove_soft_line_breaks, and trims SHA256 padding before regex processing.
577-579: LGTM - Clean utility function.The
compute_signal_lengthfunction correctly computes the ceiling division by 31.
| Delivered-To: [email protected] | ||
| Received: by 2002:a05:6520:4d11:b0:298:de86:b196 with SMTP id cy17csp1851324lkb; | ||
| Thu, 15 Aug 2024 18:01:48 -0700 (PDT) | ||
| X-Forwarded-Encrypted: i=3; AJvYcCWCx1Cb3kEOBBorrIS5l2e6GCzKJxzBxybTlA6eTJnE+qGUWcW3x0U2DbMEuuE94csCWxFvt47ftW92zpoSTnvWP+8Mc1JAPw== | ||
| X-Google-Smtp-Source: AGHT+IFy7itmDPuDlSHhbsl0mXcp4WaIqPBhoxgtMIUJ4rixUL/hmu7Y7lNb/3SE/waaKnYbynS7 | ||
| X-Received: by 2002:a05:6000:a8b:b0:36b:8f94:e206 with SMTP id ffacd0b85a97d-37194315781mr855253f8f.5.1723770107871; | ||
| Thu, 15 Aug 2024 18:01:47 -0700 (PDT) | ||
| ARC-Seal: i=2; a=rsa-sha256; t=1723770107; cv=pass; | ||
| d=google.com; s=arc-20240605; | ||
| b=L4ifZud+phJJXmpjp/GJ3cSjA1D4Uhl604pR5GCQDZy4O/9FpFTTyQrlajv20a3CLA | ||
| LDohZyTwGvxXuUGOp4AnE3lb/GAeb9AQ3dfKQ5NRnBbbC5j01ow9/3hi/CQUG3K3uRxG | ||
| pCJKwe65M0PZryicz8+ZB1It0JoWHN9b9rWhTUesMV60vRLKHa76jBdrS3n5ykx6u+Hg | ||
| nDR/S+g3/qmdmopzKC4T5rKleVpLdBmBBfnpURBhyrbzR4YRAYrxHh6/Xmfxm2CXnP1G | ||
| BngzD5RfJcQJVBe2Hl7hTsPXNgDIW8Ng+G1w1sU12uUFdLUNMFL3Hmp0YXx52NGCsAxM | ||
| HjSg== | ||
| ARC-Message-Signature: i=2; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=arc-20240605; | ||
| h=feedback-id:bounces-to:mime-version:subject:message-id:to:from:date | ||
| :dkim-signature:dkim-signature; | ||
| bh=a+iNAUuMllM38rUYf1E0PCsZMSzHqdP5Rs6lXnKmcp4=; | ||
| fh=aslmXTwzSzJ1CMviWDZT1UuXOGBFyKTE9qzq5T44VcQ=; | ||
| b=Obl6fTQjJwbp1Z313OnnWM2NPRbOCUSY9p+6WdIDaWpqRQ0scS/tkVJPHyocDMPOFy | ||
| JxFpFA85L6u+XEVp249LYKd2p7z9z+uQaSW/sp0CrL5NPWk/jQcY37eLzlz9UDRVY0OR | ||
| Z8CxOzIiBJtsYGgMN594/rlliZQMEv7+EE7/bp4p0rEMweLeWmS73aT5JjmYvS6D0DrH | ||
| /shB9jMo5zS6qUNR8v8REiTJzcnN+yJ6iZ35c8Bg1rOu94hgJmnWNFLiiC47FEn5bzo9 | ||
| VvuVRFPJh/F8c3pEHTWLfNfjjzzZZA4PvQJS8YJ0isrIoCzeuqJMV0dOs2U8mc+H39Y5 | ||
| IGFg==; | ||
| dara=google.com | ||
| ARC-Authentication-Results: i=2; mx.google.com; | ||
| dkim=pass [email protected] header.s=yg4mwqurec7fkhzutopddd3ytuaqrvuz header.b="sk0yWvc/"; | ||
| dkim=pass [email protected] header.s=ug7nbtf4gccmlpwj322ax3p6ow6yfsug header.b=lUY1ph+6; | ||
| arc=pass (i=1 dkim=pass dkdomain=amazon.com dkim=pass dkdomain=amazonses.com); | ||
| spf=pass (google.com: domain of [email protected] designates 18.9.21.22 as permitted sender) smtp.mailfrom=[email protected]; | ||
| dmarc=pass (p=QUARANTINE sp=QUARANTINE dis=NONE) header.from=amazon.com | ||
| Return-Path: <[email protected]> | ||
| Received: from exchange-forwarding-2.mit.edu (exchange-forwarding-2.mit.edu. [18.9.21.22]) | ||
| by mx.google.com with ESMTPS id 5b1f17b1804b1-429ded70f98si27296005e9.143.2024.08.15.18.01.47 | ||
| for <[email protected]> | ||
| (version=TLS1_2 cipher=ECDHE-ECDSA-AES128-GCM-SHA256 bits=128/128); | ||
| Thu, 15 Aug 2024 18:01:47 -0700 (PDT) | ||
| Received-SPF: pass (google.com: domain of [email protected] designates 18.9.21.22 as permitted sender) client-ip=18.9.21.22; | ||
| Authentication-Results: mx.google.com; | ||
| dkim=pass [email protected] header.s=yg4mwqurec7fkhzutopddd3ytuaqrvuz header.b="sk0yWvc/"; | ||
| dkim=pass [email protected] header.s=ug7nbtf4gccmlpwj322ax3p6ow6yfsug header.b=lUY1ph+6; | ||
| arc=pass (i=1 dkim=pass dkdomain=amazon.com dkim=pass dkdomain=amazonses.com); | ||
| spf=pass (google.com: domain of [email protected] designates 18.9.21.22 as permitted sender) smtp.mailfrom=[email protected]; | ||
| dmarc=pass (p=QUARANTINE sp=QUARANTINE dis=NONE) header.from=amazon.com | ||
| Received: from mailhub-dmz-4.mit.edu (MAILHUB-DMZ-4.MIT.EDU [18.7.62.38]) | ||
| by exchange-forwarding-2.mit.edu (8.14.7/8.12.4) with ESMTP id 47G11hAQ014612 | ||
| for <[email protected]>; Thu, 15 Aug 2024 21:01:45 -0400 | ||
| Authentication-Results: mit.edu; dmarc=pass (p=quarantine dis=none) header.from=amazon.com | ||
| Authentication-Results: mit.edu; arc=none smtp.remote-ip=18.7.62.38 | ||
| ARC-Seal: i=1; a=rsa-sha256; d=mit.edu; s=arc; t=1723770105; cv=none; b=I3uoniJRBjPCLIEB3xP3hVBkvc+i2uRrt/Qa98Z9Pew6S0B9YMYkhfyoEzqG9SAM9Me5KO0YAvZMbfMtIqtaDh99KBS+iv77kBhEsx5OqUpzb3Wl2zIM+VbewBxhPFUae85UUUYlc3FcomH+e3BYp3s0M+3tU+UeXxMu+BbkcdomHRwIHAPNE4122eo78KPjc0cWQSrX/fL+/v0Z8PY7f99hN5Rqmv15JNhgWDpyrQ7S8UZ2YwzEzN6T8pRH7VhxZDNnwP6JRhylWcaeVEOZt9/x8YaVXBxAxmzz/+mt0J19JRLghzrzbLeUJyiR2M2uqzhH2koHQFf4r5N4/zmXBA== | ||
| ARC-Message-Signature: i=1; a=rsa-sha256; d=mit.edu; s=arc; t=1723770105; | ||
| c=relaxed/relaxed; bh=a+iNAUuMllM38rUYf1E0PCsZMSzHqdP5Rs6lXnKmcp4=; | ||
| h=Date:From:Message-ID:Subject:MIME-Version:Content-Type; b=qB8UXISZyqJo1Cu2Oca57DPK/fwTk63YJ3gOT3iewE5H9ZuhwLDffJOtj+5oTIpeuPsDtEJPfxMP6K3466KjPIhHycLkjJqM1qKZM5XGjcXE2YaWVdeZvFLtPdXAbuxBc98x0GuqXpWkQUuXuDHsOMpGxeIoD0x395i4XQF6JOKCJhqf6airXGRVQ0TvLgOc1sKAsUCiy8LVFxTZIFc959rHxSCd6KN+xomr+QVCELUtwwujGEz/0d2Py7Sf6GmvpDi1Csg8B9VeLWX+vyJ08XheWzGKu7lLRZvJ9KXOTnGskQCwTXs5Melz/84G8ewhiOrHEz4sUW5fx1ksFKJmlw== | ||
| ARC-Authentication-Results: i=1; mit.edu; dkim=pass (1024-bit key; unprotected) header.d=amazon.com [email protected] header.a=rsa-sha256 header.s=yg4mwqurec7fkhzutopddd3ytuaqrvuz header.b=sk0yWvc/; dkim=pass (1024-bit key; unprotected) header.d=amazonses.com [email protected] header.a=rsa-sha256 header.s=ug7nbtf4gccmlpwj322ax3p6ow6yfsug header.b=lUY1ph+6 | ||
| Authentication-Results: mit.edu; | ||
| dkim=pass (1024-bit key; unprotected) header.d=amazon.com [email protected] header.a=rsa-sha256 header.s=yg4mwqurec7fkhzutopddd3ytuaqrvuz header.b=sk0yWvc/; | ||
| dkim=pass (1024-bit key; unprotected) header.d=amazonses.com [email protected] header.a=rsa-sha256 header.s=ug7nbtf4gccmlpwj322ax3p6ow6yfsug header.b=lUY1ph+6 | ||
| Received: from mailhub-dmz-4.mit.edu (mailhub-dmz-4.mit.edu [127.0.0.1]) | ||
| by mailhub-dmz-4.mit.edu (8.14.7/8.9.2) with ESMTP id 47G11hGU006354 | ||
| for <[email protected]>; Thu, 15 Aug 2024 21:01:43 -0400 | ||
| Received: (from mdefang@localhost) | ||
| by mailhub-dmz-4.mit.edu (8.14.7/8.13.8/Submit) id 47G11di4006343 | ||
| for [email protected]; Thu, 15 Aug 2024 21:01:39 -0400 | ||
| Received: from BYAPR05CU005.outbound.protection.outlook.com (mail-westusazlp17010006.outbound.protection.outlook.com [40.93.1.6]) | ||
| by MAILHUB-DMZ-4.MIT.EDU (envelope-sender <20240816010133af409d4398414b769006b814f360p0na-C1MH0WGB67NIL9@bounces.amazon.com>) (MIMEDefang) with ESMTP id 47G11bAg006339 | ||
| for <[email protected]>; Thu, 15 Aug 2024 21:01:39 -0400 | ||
| Received: from SA9PR11CA0015.namprd11.prod.outlook.com (2603:10b6:806:6e::20) | ||
| by SA0PR01MB6188.prod.exchangelabs.com (2603:10b6:806:da::21) with Microsoft | ||
| SMTP Server (version=TLS1_2, cipher=TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384) id | ||
| 15.20.7875.18; Fri, 16 Aug 2024 01:01:34 +0000 | ||
| Received: from SA2PEPF00003F61.namprd04.prod.outlook.com | ||
| (2603:10b6:806:6e:cafe::b0) by SA9PR11CA0015.outlook.office365.com | ||
| (2603:10b6:806:6e::20) with Microsoft SMTP Server (version=TLS1_2, | ||
| cipher=TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384) id 15.20.7828.33 via Frontend | ||
| Transport; Fri, 16 Aug 2024 01:01:34 +0000 | ||
| Authentication-Results: spf=pass (sender IP is 54.240.13.78) | ||
| smtp.mailfrom=bounces.amazon.com; dkim=pass (signature was verified) | ||
| header.d=amazon.com;dmarc=pass action=none | ||
| header.from=amazon.com;compauth=pass reason=100 | ||
| Received-SPF: Pass (protection.outlook.com: domain of bounces.amazon.com | ||
| designates 54.240.13.78 as permitted sender) receiver=protection.outlook.com; | ||
| client-ip=54.240.13.78; helo=a13-78.smtp-out.amazonses.com; pr=C | ||
| Received: from a13-78.smtp-out.amazonses.com (54.240.13.78) by | ||
| SA2PEPF00003F61.mail.protection.outlook.com (10.167.248.36) with Microsoft | ||
| SMTP Server (version=TLS1_3, cipher=TLS_AES_256_GCM_SHA384) id 15.20.7849.8 | ||
| via Frontend Transport; Fri, 16 Aug 2024 01:01:34 +0000 | ||
| DKIM-Signature: v=1; a=rsa-sha256; q=dns/txt; c=relaxed/simple; | ||
| s=yg4mwqurec7fkhzutopddd3ytuaqrvuz; d=amazon.com; t=1723770094; | ||
| h=Date:From:To:Message-ID:Subject:MIME-Version:Content-Type; | ||
| bh=fHIH8oc4fnqEfBc2yA88CwZjgGRwbXrwhe87j4ItCcQ=; | ||
| b=sk0yWvc/xR48M8krmQkjZbwkeIFlDIHr96+9q2KY0UxYchD4Usu4LurSXTq0YF/8 | ||
| oXyRB0j9ocgDkpl6ASsyHrQJUn/Vy1nqvmJOAFRTV9v4NJyCquwME/hanRWmyDV8AJC | ||
| SpsrDeISMzFsQMvX3/BZ09/wAO+XPKNPx3iYrwfg= | ||
| DKIM-Signature: v=1; a=rsa-sha256; q=dns/txt; c=relaxed/simple; | ||
| s=ug7nbtf4gccmlpwj322ax3p6ow6yfsug; d=amazonses.com; t=1723770094; | ||
| h=Date:From:To:Message-ID:Subject:MIME-Version:Content-Type:Feedback-ID; | ||
| bh=fHIH8oc4fnqEfBc2yA88CwZjgGRwbXrwhe87j4ItCcQ=; | ||
| b=lUY1ph+6Hec4F2znvRMGzsMh87R1d8Zm/OiEqyOJdcoaC7SxQgTyiCqlG09+4OH6 | ||
| fH1GNOI1pZmXZ3eBxbRLf0r9wpTn+VpX7PkwvW6qZK4bDuEXGWcD7BOCL49qiDYgQ5E | ||
| WYWaB24Gp9ZuGr+aB8mX1q7X0tkjSQPh+SPwdWGA= | ||
| Date: Fri, 16 Aug 2024 01:01:34 +0000 | ||
| From: "Amazon.com" <[email protected]> | ||
| To: [email protected] | ||
| Message-ID: <0100019158b441de-d0733a8e-e37c-4906-9fc0-59a546ba46cc-000000@email.amazonses.com> | ||
| Subject: Delivered: Your Amazon.com order #111-3061760-5513056 | ||
| MIME-Version: 1.0 | ||
| Content-Type: multipart/alternative; | ||
| boundary="----=_Part_533333_1464710557.1723770094034" | ||
| X-AMAZON-MAIL-RELAY-TYPE: notification | ||
| Bounces-to: 20240816010133af409d4398414b769006b814f360p0na-C1MH0WGB67NIL9@bounces.amazon.com | ||
| X-AMAZON-METADATA: CA=C1MH0WGB67NIL9-CU=A2WSYR24L0Q7DI | ||
| X-Original-MessageID: <urn.rtn.msg.20240816010133af409d4398414b769006b814f360p0na@1723770094035.> | ||
| Feedback-ID: 917195550::1.us-east-1.ZHcGJK6s+x+i9lRHKog4RW3tECwWIf1xzTYCZyUaiec=:AmazonSES | ||
| X-SES-Outgoing: 2024.08.16-54.240.13.78 | ||
| X-EOPAttributedMessage: 0 | ||
| X-EOPTenantAttributedMessage: 64afd9ba-0ecf-4acf-bc36-935f6235ba8b:0 | ||
| X-MS-PublicTrafficType: Email | ||
| X-MS-TrafficTypeDiagnostic: SA2PEPF00003F61:EE_|SA0PR01MB6188:EE_ | ||
| X-MS-Office365-Filtering-Correlation-Id: 8b39e185-a9d4-4bc2-4904-08dcbd8ef988 | ||
| X-MS-Exchange-AtpMessageProperties: SA|SL | ||
| X-MIT-ForwardedCount: 1 | ||
| X-Microsoft-Antispam: | ||
| BCL:0;ARA:13230040|1032899013|12012899012|3092899012|6062899009|5062899012|5082899009|3072899012|32142699015|2092899012|69100299015|4092899012|13102899012|13012899012; | ||
| X-Microsoft-Antispam-Message-Info: | ||
| =?utf-8?B?dDA1dE50U1hkbFJkQVd3dzF0dzZoSk53clFKYU1JTmFkY2pWQ3FvZ2poQWpM?= | ||
| =?utf-8?B?NHZNR2pkWFpDQTc4dFYzUWRQTWdwSlZNRFBLdmMwZ1NoYXd6K21sQ25VTjha?= | ||
| =?utf-8?B?Y3hvdStXM0V6WDFZc1JxaGxKYXEyZnRvOFlhREN2LzZuVzVHS09CNjBQUDA3?= | ||
| =?utf-8?B?eTgrekxSUllJWm9lMVBiV1FSME1HMHhZUkdKZkNIWG92ZzdUZ09pNDYzRGVi?= | ||
| =?utf-8?B?L001VmVhbkhJWWR4L3p5NjRLNnM3Qlc1bitEWkh5dkx2VlVGNG5NRnJGa3Yz?= | ||
| =?utf-8?B?YklZVnhVaVFkM1VjR3BBZnIvU3Q3dXQ0SndNZmMyMnNNSThtN2FnUzNyNFVh?= | ||
| =?utf-8?B?SS9VZFJ2RVdrS2RjV2pNeG1iTUYvaXFJaXdaUWJSanJ4dEJqMUcyNGo5c0wz?= | ||
| =?utf-8?B?YnVLUUM4NHNsOVpkekFqSTlHbWpqQjdWWVBBeDMxL0VLdGRiekNiL3UxZlds?= | ||
| =?utf-8?B?cGZnakJmUzJQTHdHaXp0QVkrVnpVNGFXN2ZTRW4wMEtiblR6ODUvcUxoWG5H?= | ||
| =?utf-8?B?WTVoei9kbS9yVTBJOWk1RnVzL2cvL3JadEVtNUNFVktORnlJL1FMM2dWRFVv?= | ||
| =?utf-8?B?WGdydlFDRjRaMHRBZHVpTnVrMjBpZnplcHE0MGpISHErczJRYVRrMS9Lb1BQ?= | ||
| =?utf-8?B?eWFZU1ZiVzZhbDhScFNpb0czOUU3dkNVWXdTOXQ1M3BFNmw2eDNLNjU1UnRW?= | ||
| =?utf-8?B?ZDZLZDY0b1FVWkxoeVlqTSswbmwrc09tMzdjSk1FSEZ4d3R6dWRtT1NNRnc0?= | ||
| =?utf-8?B?VUp2Y01KN3pEbHJKUXYxdTRDak5zaE1QMDh1akg4NGxOUmNodTVydVErL2J4?= | ||
| =?utf-8?B?RksvdTlROFgyUjlDbzlkZXBMYjFhUC8wcDJHR0FIYVFuZmhadmEvUjhJcC9I?= | ||
| =?utf-8?B?UERhR3VxTEFBVzBaV01weDhLWjlUZVZseVN0cytlYmtTcnNQMTFDdGsyd2sr?= | ||
| =?utf-8?B?Zk9GaXFiWmE3d2lWREc0Q3NqOXRNTlE3K29DdHJuK1NsdFB2NldVbTQ5M0Ri?= | ||
| =?utf-8?B?L1ZHTWtSTlNYZmhVbVc5WUtITVlITHJ2aWo4dmY4ZG5FTGZSNUh6a0dEdTR4?= | ||
| =?utf-8?B?TDVuS2RmT1p3bElKSFc1Z3JPSVlYM0J5YXVyOUJGKzNCbERLK3dydlk0TnV1?= | ||
| =?utf-8?B?dHJlTU1HQktidEF5ajkvd29yUEtSSmt2SDMvejY5dU9XYzZzTUhKczdGTU9j?= | ||
| =?utf-8?B?QnZQSlBVT3RtcDF5NkxEeThNaGFrRG1pdlFhWUVSSXZmYnRkTEpsenJuQy91?= | ||
| =?utf-8?B?ZnRBQ21abC9NV2pscUFZQ1JGTStOUFZSOWZNdEIzcWYvTStiQ01OUE1hazVh?= | ||
| =?utf-8?B?enN6b25qbDN5OTZmVS9sUDBXQTVXWDhoNjFxS1o1S0FjYmVxQUFneFh6QkJJ?= | ||
| =?utf-8?B?K1dVUW1nTW5PbGF2MlNiNi9rRjhvbUMxWDNXZnBvQXhDZ0FWNFRjSi93RG9I?= | ||
| =?utf-8?B?SVdIc01aSVhqMEhnRmxQdlA4MmVBYWtQdXFFcGxZTnZ4Tk5hZVdsTnRoNDlk?= | ||
| =?utf-8?B?MWthWVUxZTArYUtOSUN5MVpxWjdQbmRpSHJ6VFJUYUt1VEV0WmdsWFRtNWIv?= | ||
| =?utf-8?B?T3ZXaTVtWGM2bzJlMkN5Z0pmRGoxQ2I0MjBYUGt6WkUzSkhwZHplMjVYY1Fn?= | ||
| =?utf-8?B?RG04bTBEQXJ1NmlMVi9rN3R2NDdvSTZ0RGVrNE42dGtSNVdWZXpjaUNFaGgx?= | ||
| =?utf-8?B?V2Jja3h1WXZVaktNdm1sSjBxTVVqTGdoMTlMbTVSVjVlbk9IR3NtVlFPRzhP?= | ||
| =?utf-8?B?TWhZMkluZGllNzJqRFhKNG1sMnBpLy9nTnc0WVdzbE1DNHNzbVZFTTlvRTc2?= | ||
| =?utf-8?B?Vi8vcVdSbmRUaDJNclY0a2QxM2NTNmljR01JNHF0SjBQUklkeEllYU1wNERl?= | ||
| =?utf-8?B?ekdJVlNpa09iWkZlbEJqMXR6b1dWWHE1aWpZK3JpaXlROFJtSDRFZHZjRHp3?= | ||
| =?utf-8?B?R29COXZpN2I3ajljaGlRRjkyZDIyenA4R0dIb2xBZkFLY1FJMU1kR3J3SG1U?= | ||
| =?utf-8?B?QmNMQnYzRnNqVHdQYmtlbzdES0xtRkExZE84d3FxelRYV3gyUjBySmZjdUM3?= | ||
| =?utf-8?B?QzNWVzZUKzdaL3hVb0ZvLzZ2MFFmcEM0VHNjaVZWUjE0MDlZR3dIQnc1bkIx?= | ||
| =?utf-8?B?N2VOUlZoSnF2RGYyZzgyWWZEeXJHSHlDakNIUFJhZmU1d1VXMlBUYzZTVFcw?= | ||
| =?utf-8?B?Uk5aMit5Q3ZCNzg2eFEwNTJBT3VIZlFuYlVhRnozZGoyajNhc2dVemo0SXNN?= | ||
| =?utf-8?B?RVp2RHQ1SHcvOG5ZWC93QnpQbFMycWYzUzErM0VMeGxmUnIzcnB0OThVS1VZ?= | ||
| =?utf-8?B?bk9kNk1PNS9kSFpmU2ZxUXRhWVJkTzN5ZWFqOVN1c2lDZVhaN0VjZW56cGE4?= | ||
| =?utf-8?B?eUVlNUtWTXNMVWZxVHFydzVEVDNIUjRmc3ltWVMxU3BXUFBlSnZTeEZ5SHZJ?= | ||
| =?utf-8?B?UUVHTTA4RVR3NjFYOWlGbVp1eU1FN0NDL2F6RzROanEzMEMyQzhhd3I4enh0?= | ||
| =?utf-8?Q?y43yNOONjO+?= | ||
| X-Forefront-Antispam-Report: | ||
| CIP:54.240.13.78;CTRY:US;LANG:en;SCL:1;SRV:;IPV:NLI;SFV:NSPM;H:a13-78.smtp-out.amazonses.com;PTR:a13-78.smtp-out.amazonses.com;CAT:NONE;SFS:(13230040)(1032899013)(12012899012)(3092899012)(6062899009)(5062899012)(5082899009)(3072899012)(32142699015)(2092899012)(69100299015)(4092899012)(13102899012)(13012899012);DIR:INB; | ||
| X-MS-Exchange-AntiSpam-ExternalHop-MessageData-ChunkCount: 1 | ||
| X-MS-Exchange-AntiSpam-ExternalHop-MessageData-0: | ||
| z1rzeYVa+P7w3Uut5PZY4XFxKFVPPMoRlChKSBEkqD70if+MiDWrj2kOzicowSH5/Ryv/yUxMBE5phZvD5onyE/TRH0DlXbWQHsVZq/ckPMOoPW60O70g7+Xp+ugQamDxA9jkDTgheWYPKDqTWmDgIAXrXe+gvQMpon+9pX4OvOUeIvap679lvHzOG7B3yR46+gn1J40mD9blXsZKSE+iDvWuc36A1bTZ8LPrpO4aWQP8UvqI8U+EebELungZppda6de5Si6ilLMSkckWRbqY/9LP9t+EUw6v9vh0GA2ExA/9TLvC/O9ARvbd4Yi2ZETUNj2awhkwVCrChWM05WWbbLXT1MqMzR1ErJxnDGIcs0jQ32ITjTNdC0zR4icAc72+gVhXdW8hdP5smLE1aD2h2zTGBo9nBHRterNuL1H1Cidl0rIjL3AA+5bgi01KTZNIatilr5DG9prwfrHNNkM2w/FT95g8nslWM2nEwu02YnP+XJEHHrxFXPPhJJHuGnqOI/dRGZ3YqEeO8VJMeC/dEqdsQMkVp8WR4TSd/rUgt46esSmEVXuMxpxaAMvcltPbFp9IFrfSz7JUCmxmgNAw6uGmPyiX1mFIA3PpRPODOpe2y/Bo/kJZul19eejoX2i | ||
| X-OriginatorOrg: mitprod.onmicrosoft.com | ||
| X-MS-Exchange-CrossTenant-OriginalArrivalTime: 16 Aug 2024 01:01:34.7825 | ||
| (UTC) | ||
| X-MS-Exchange-CrossTenant-Network-Message-Id: 8b39e185-a9d4-4bc2-4904-08dcbd8ef988 | ||
| X-MS-Exchange-CrossTenant-Id: 64afd9ba-0ecf-4acf-bc36-935f6235ba8b | ||
| X-MS-Exchange-CrossTenant-AuthSource: | ||
| SA2PEPF00003F61.namprd04.prod.outlook.com | ||
| X-MS-Exchange-CrossTenant-AuthAs: Anonymous | ||
| X-MS-Exchange-CrossTenant-FromEntityHeader: Internet | ||
| X-MS-Exchange-Transport-CrossTenantHeadersStamped: SA0PR01MB6188 | ||
| X-MS-Exchange-CrossPremises-OriginalClientIPAddress: 54.240.13.78 | ||
| X-MS-Exchange-CrossPremises-TransportTrafficType: Email | ||
| X-MS-Exchange-CrossPremises-AuthSource: | ||
| SA2PEPF00003F61.namprd04.prod.outlook.com | ||
| X-MS-Exchange-CrossPremises-AuthAs: Anonymous | ||
| X-MS-Exchange-CrossPremises-Antispam-ScanContext: | ||
| DIR:Incoming;SFV:NSPM;SKIP:0; | ||
| X-MS-Exchange-CrossPremises-SCL: 1 | ||
| X-MS-Exchange-CrossPremises-Processed-By-Journaling: Journal Agent | ||
| X-OrganizationHeadersPreserved: SA0PR01MB6188.prod.exchangelabs.com | ||
|
|
||
| ------=_Part_533333_1464710557.1723770094034 | ||
| Content-Type: text/plain; charset=utf-8 | ||
| Content-Transfer-Encoding: quoted-printable | ||
| =20 | ||
| Hi Aayush, | ||
| Your package has been delivered to reception. | ||
| How was your delivery? | ||
| It was great https://www.amazon.com/progress-tracker/package?_encoding=3DUT= | ||
| F8&itemId=3D&orderId=3D111-3061760-5513056&packageIndex=3D0&shipmentId=3D30= | ||
| 0612189807301&ingress=3Demail&intent=3Dfeedback_happy&ref_=3Dpdc_f_h | ||
| Not so great https://www.amazon.com/progress-tracker/package?_encoding=3DUT= | ||
| F8&itemId=3D&orderId=3D111-3061760-5513056&packageIndex=3D0&shipmentId=3D30= | ||
| 0612189807301&ingress=3Demail&intent=3Dfeedback_unhappy&ref_=3Dpdc_f_s | ||
| Track package | ||
| https://www.amazon.com/gp/your-account/ship-track?ie=3DUTF8&itemId=3D&order= | ||
| Id=3D111-3061760-5513056&packageIndex=3D0&shipmentId=3DGhsHRNhnG&ref_=3Dpdc= | ||
| _pt_track | ||
| Order # 111-3061760-5513056 | ||
| Return or replace items in [Your Orders](https://www.amazon.com/your-orders= | ||
| /orders?ref_=3Dpdc_yo). | ||
| =C2=A92024 Amazon.com, Inc. or its affiliates. Amazon and all related marks= | ||
| are trademarks of Amazon.com, Inc. or its affiliates, Amazon.com, Inc. 410= | ||
| Terry Avenue N., Seattle, WA 98109. | ||
| Amazon.com | ||
| ------=_Part_533333_1464710557.1723770094034 | ||
| Content-Type: text/html; charset=utf-8 | ||
| Content-Transfer-Encoding: quoted-printable | ||
|
|
||
| <!doctype html><html lang=3D"en" dir=3D"auto" xmlns=3D"http://www.w3.org/19= | ||
| 99/xhtml" xmlns:v=3D"urn:schemas-microsoft-com:vml" xmlns:o=3D"urn:schemas-= | ||
| microsoft-com:office:office"><head><title></title><!--[if !mso]><!--><meta = | ||
| http-equiv=3D"X-UA-Compatible" content=3D"IE=3Dedge"><!--<![endif]--><meta = | ||
| http-equiv=3D"Content-Type" content=3D"text/html; charset=3DUTF-8"><meta na= | ||
| me=3D"viewport" content=3D"width=3Ddevice-width,initial-scale=3D1"><style t= | ||
| ype=3D"text/css">#outlook a{padding:0}body{margin:0;padding:0;-webkit-text-= | ||
| size-adjust:100%;-ms-text-size-adjust:100%}table,td{border-collapse:collaps= | ||
| e;mso-table-lspace:0pt;mso-table-rspace:0pt}img{border:0;height:auto;line-h= | ||
| eight:100%;outline:0;text-decoration:none;-ms-interpolation-mode:bicubic}p{= | ||
| display:block;margin:13px 0}</style><!--[if mso]> | ||
| <noscript> | ||
| <xml> | ||
| <o:OfficeDocumentSettings> | ||
| <o:AllowPNG/> | ||
| <o:PixelsPerInch>96</o:PixelsPerInch> | ||
| </o:OfficeDocumentSettings> | ||
| </xml> | ||
| </noscript> | ||
| <![endif]--><!--[if lte mso 11]> | ||
| <style type=3D"text/css">.mj-outlook-group-fix{width:100%!important}</s= | ||
| tyle> | ||
| <![endif]--><style type=3D"text/css">@media only screen and (min-width:= | ||
| 600px){.mj-column-per-100{width:100%!important;max-width:100%}.mj-column-pe= | ||
| r-50{width:50%!important;max-width:50%}.mj-column-per-33{width:33%!importan= | ||
| t;max-width:33%}.mj-column-per-67{width:67%!important;max-width:67%}}</styl= | ||
| e><style media=3D"screen and (min-width:600px)">.moz-text-html .mj-column-p= | ||
| er-100 { width:100% !important; max-width: 100%; } | ||
| .moz-text-html .mj-column-per-50 { width:50% !important; max-width: 50%; } | ||
| .moz-text-html .mj-column-per-33 { width:33% !important; max-width: 33%; } | ||
| .moz-text-html .mj-column-per-67 { width:67% !important; max-width: 67%; }<= | ||
| /style><style type=3D"text/css">.rio-card-70 p+p{margin-top:1.2em}@media (p= | ||
| refers-color-scheme:dark){.rio-header-64,.rio-header-64 *{color:#fff!import= | ||
| ant}}@media (prefers-color-scheme:dark){.rio-header-65,.rio-header-65 *{col= | ||
| or:#fff!important}}@media (prefers-color-scheme:dark){.rio-text-121{color:#= | ||
| fff}}@media (prefers-color-scheme:dark){.rio-text-122{color:#fff}}@media (p= | ||
| refers-color-scheme:dark){.rio-text-123{color:#fff}}@media (prefers-color-s= | ||
| cheme:dark){.rio-text-124{color:#fff}}@media (prefers-color-scheme:dark){.r= | ||
| io-text-125{color:#fff}}@media (prefers-color-scheme:dark){.rio-text-126{co= | ||
| lor:#fff}}@media only screen and (min-width:600px){.rio-asin-image-1NSmq2Ns= | ||
| zkzYrLmYYAndnK .productImageTd{height:165px!important}.rio-asin-image-1NSmq= | ||
| 2NszkzYrLmYYAndnK .productImage{max-height:165px!important;max-width:165px!= | ||
| important}}@media (prefers-color-scheme:dark){.rio-text-127{color:#fff}}@me= | ||
| dia (prefers-color-scheme:dark){.rio-text-128{color:#fff}}.rio-card-72 p+p{= | ||
| margin-top:1.2em}@media (prefers-color-scheme:dark){.rio-header-66,.rio-hea= | ||
| der-66 *{color:#fff!important}}@media (prefers-color-scheme:dark){.rio-head= | ||
| er-67,.rio-header-67 *{color:#fff!important}}@media (prefers-color-scheme:d= | ||
| ark){.rio-text-129{color:#fff}}@media (prefers-color-scheme:dark){.rio-card= | ||
| ,.rio-card>table{background-color:#181a1a!important}}[data-ogsc] .rio-card,= | ||
| [data-ogsc] .rio-card>table{background-color:#181a1a!important}.rio-header = | ||
| strong{color:#067d62}@media (prefers-color-scheme:dark){.rio-header a{color= | ||
| :#6ed6e6!important}.rio-header strong{color:#13bd96!important}}[data-ogsc] = | ||
| .rio-header,[data-ogsc] .rio-header *{color:#fff!important}[data-ogsc] .rio= | ||
| -header a{color:#6ed6e6!important}[data-ogsc] .rio-header strong{color:#13b= | ||
| d96!important}@media only screen and (max-width:599px){table.mj-full-width-= | ||
| mobile{width:100%!important}td.mj-full-width-mobile{width:auto!important}}.= | ||
| rio-text strong{color:#067d62}.rio-text img{width:100%;height:auto}@media (= | ||
| prefers-color-scheme:dark){.rio-text *{color:#fff!important}.rio-text a,.ri= | ||
| o-text a>*{color:#6ed6e6!important}.rio-text strong{color:#13bd96!important= | ||
| }}[data-ogsc] .rio-text *{color:#fff!important}[data-ogsc] .rio-text a,[dat= | ||
| a-ogsc] .rio-text a>*{color:#6ed6e6!important}[data-ogsc] .rio-text strong{= | ||
| color:#13bd96!important}@media (prefers-color-scheme:dark){.rio-button-seco= | ||
| ndary *{color:#0f1111!important;background:#fefefe!important;background-col= | ||
| or:linear-gradient(#fefefe,#fefefe)!important}}[data-ogsc] .rio-button-seco= | ||
| ndary *{color:#0f1111!important;background:#fefefe!important;background-col= | ||
| or:linear-gradient(#fefefe,#fefefe)!important}.rio-asin-image .productImage= | ||
| {mix-blend-mode:multiply}u+.body .rio-asin-image .productImage{mix-blend-mo= | ||
| de:initial!important}@media (prefers-color-scheme:dark){.rio-asin-image .pr= | ||
| oductImageTd{background-image:linear-gradient(#fff,#fff)!important}.rio-asi= | ||
| n-image .productImage{mix-blend-mode:initial!important}}[data-ogsc] .rio-as= | ||
| in-image .productImageTd{background-image:linear-gradient(#fff,#fff)!import= | ||
| ant}[data-ogsc] .rio-asin-image .productImage{mix-blend-mode:initial!import= | ||
| ant}@media only screen and (min-width:600px){u+.body .rio-asin-image .produ= | ||
| ctImage{mix-blend-mode:multiply!important}}.footerCard li,.footerCard p{col= | ||
| or:inherit}.footerCard p+p{margin-top:1.2em}@media (prefers-color-scheme:da= | ||
| rk){.footerCard div{background-color:#303333!important}.footerLink div{colo= | ||
| r:#6ed6e6!important}.footerText div{color:#c8cccc!important}.lightFooterImg= | ||
| {display:none!important}.darkFooterImg{display:block!important}}[data-ogsb]= | ||
| .footerCard div{background-color:#303333!important}[data-ogsc] .footerLink= | ||
| div{color:#6ed6e6!important}[data-ogsc] .footerText div{color:#c8cccc!impo= | ||
| rtant}[data-ogsc] .lightFooterImg{display:none!important}[data-ogsc] .darkF= | ||
| ooterImg{display:block!important}</style><style type=3D"text/css">@font-fac= | ||
| e{font-family:Ember;font-weight:700;src:local("Ember"),url(https://m.media-= | ||
| amazon.com/images/G/01/outbound/AmazonEmber_Bd._CB1515450239_.WOFF) format(= | ||
| "woff");mso-generic-font-family:swiss;mso-font-alt:"Arial"}@font-face{font-= | ||
| family:Ember;font-weight:600;src:local("Ember"),url(https://m.media-amazon.= | ||
| com/images/G/01/outbound/AmazonEmber_Bd._CB1515450239_.WOFF) format("woff")= | ||
| ;mso-generic-font-family:swiss;mso-font-alt:"Arial"}@font-face{font-family:= | ||
| Ember;font-weight:500;src:local("Ember"),url(https://m.media-amazon.com/ima= | ||
| ges/G/01/outbound/AmazonEmber_Md._CB1515450239_.WOFF) format("woff");mso-ge= | ||
| neric-font-family:swiss;mso-font-alt:"Arial"}@font-face{font-family:Ember;f= | ||
| ont-weight:400;font-style:normal;src:local("Ember"),url(https://m.media-ama= | ||
| zon.com/images/G/01/outbound/AmazonEmber_Rg._CB1515450239_.WOFF) format("wo= | ||
| ff");mso-generic-font-family:swiss;mso-font-alt:"Arial"}@font-face{font-fam= | ||
| ily:Ember;font-weight:200;src:local("Ember"),url(https://m.media-amazon.com= | ||
| /images/G/01/outbound/AmazonEmber_Lt._CB1515450239_.WOFF) format("woff");ms= | ||
| o-generic-font-family:swiss;mso-font-alt:"Arial"}@font-face{font-family:"Am= | ||
| azon Ember";font-weight:700;src:local("Amazon Ember"),url(https://m.media-a= | ||
| mazon.com/images/G/01/outbound/AmazonEmber_Bd._CB1515450239_.WOFF) format("= | ||
| woff");mso-generic-font-family:swiss;mso-font-alt:"Arial"}@font-face{font-f= | ||
| amily:"Amazon Ember";font-weight:600;src:local("Amazon Ember"),url(https://= | ||
| m.media-amazon.com/images/G/01/outbound/AmazonEmber_Bd._CB1515450239_.WOFF)= | ||
| format("woff");mso-generic-font-family:swiss;mso-font-alt:"Arial"}@font-fa= | ||
| ce{font-family:"Amazon Ember";font-weight:500;src:local("Amazon Ember"),url= | ||
| (https://m.media-amazon.com/images/G/01/outbound/AmazonEmber_Md._CB15154502= | ||
| 39_.WOFF) format("woff");mso-generic-font-family:swiss;mso-font-alt:"Arial"= | ||
| }@font-face{font-family:"Amazon Ember";font-style:normal;font-weight:400;sr= | ||
| c:local("Amazon Ember"),url(https://m.media-amazon.com/images/G/01/outbound= | ||
| /AmazonEmber_Rg._CB1515450239_.WOFF) format("woff");mso-generic-font-family= | ||
| :swiss;mso-font-alt:"Arial"}@font-face{font-family:"Amazon Ember";font-weig= | ||
| ht:200;src:local("Amazon Ember"),url(https://m.media-amazon.com/images/G/01= | ||
| /outbound/AmazonEmber_Lt._CB1515450239_.WOFF) format("woff");mso-generic-fo= | ||
| nt-family:swiss;mso-font-alt:"Arial"}*{font-family:Ember,'Amazon Ember',Ari= | ||
| al,sans-serif;border-spacing:0;margin:0;padding:0}[data-ogsc] :root{--body-= | ||
| bg:#181A1A;--body-color:#ffffff}.rootContent{background:#d5d9d9!important}.= | ||
| fonts,.sans,h1,h2,h3,h4,h5,li,p,table,td,th{color:#0f1111}a{color:#007185;t= | ||
| ext-decoration:none}@media screen and (max-width:599px){.mobile-only{displa= | ||
| y:initial!important}.desktop-only{display:none!important;mso-hide:all!impor= | ||
| tant}}@media screen and (min-width:600px){.mobile-only{display:none!importa= | ||
| nt;mso-hide:all!important}}@media (prefers-color-scheme:light){:root{--body= | ||
| -bg:#ffffff;--body-color:#000000}}@media (prefers-color-scheme:dark){:root{= | ||
| --body-bg:#181A1A;--body-color:#ffffff}body{background-color:#181a1a!import= | ||
| ant}.fonts,.sans,h1,h2,h3,h4,h5,li,p,table,td,th{color:#fff}a{color:#6ed6e6= | ||
| }.rootContent,.rootContent>table{background:#181a1a!important}}[data-ogsc] = | ||
| .fonts,[data-ogsc] .sans,[data-ogsc] h1,[data-ogsc] h2,[data-ogsc] h3,[data= | ||
| -ogsc] h4,[data-ogsc] h5,[data-ogsc] li,[data-ogsc] p{color:#fff}[data-ogsc= | ||
| ] a{color:#6ed6e6}[data-ogsc] .rootContent,[data-ogsc] .rootContent>table{b= | ||
| ackground:#181a1a!important}body{background-color:var(--body-bg)!important;= | ||
| color:var(--body-color)!important;margin:0!important;padding:0}body>img{pos= | ||
| ition:absolute}table{border-spacing:0}h3,h4,h5,p,table th{font-weight:400;m= | ||
| argin:0;padding:0}td{padding:0}img{border:0}a,span,td{word-break:break-word= | ||
| !important}ol,ul{margin-left:32px!important}.button{background-color:#ffd81= | ||
| 4;color:#0f1111!important;border-radius:24px;padding:1px 16px;display:inlin= | ||
| e-block;box-shadow:1px 2px 4px rgba(153,153,153,.2);font-size:13px;line-hei= | ||
| ght:29px;white-space:nowrap;text-decoration:none;margin-top:4px}.box-shadow= | ||
| a{box-shadow:1px 2px 4px rgba(153,153,153,.2)}a,body,table,td{-ms-text-siz= | ||
| e-adjust:100%;-webkit-text-size-adjust:100%}.appleBody a,.appleFooter a{col= | ||
| or:#007185!important;text-decoration:none}a[x-apple-data-detectors]{color:#= | ||
| 007185!important;font-family:inherit!important;font-size:inherit!important;= | ||
| font-weight:inherit!important;line-height:inherit!important}u+#body a{color= | ||
| :#007185!important;font-family:inherit!important;font-size:inherit!importan= | ||
| t;font-weight:inherit!important;line-height:inherit!important}#MessageViewB= | ||
| ody a{color:#007185!important;font-family:inherit!important;font-size:inher= | ||
| it!important;font-weight:inherit!important;line-height:inherit!important}</= | ||
| style><meta content=3D"text/html; charset=3DUTF-8" http-equiv=3D"Content-Ty= | ||
| pe"><meta content=3D"telephone=3Dno" name=3D"format-detection"><meta conten= | ||
| t=3D"width=3Ddevice-width,initial-scale=3D1;user-scalable=3Dno;" name=3D"vi= | ||
| ewport"><meta content=3D"IE=3D9; IE=3D8; IE=3D7; IE=3DEDGE" http-equiv=3D"X= | ||
| -UA-Compatible"><meta name=3D"x-apple-disable-message-reformatting"><meta c= | ||
| ontent=3D"light dark" name=3D"color-scheme"><meta content=3D"light dark" na= | ||
| me=3D"supported-color-schemes"><!-- | ||
| =20 | ||
| =20 | ||
| =20 | ||
| --><style type=3D"text/css">.productListPrice{color:#565959}.= | ||
| productDiscount{color:#cc0c39}.productPrice{color:#0f1111}@media (prefers-c= | ||
| olor-scheme:dark){.productListPrice{color:#fff!important}.productDiscount{c= | ||
| olor:#ff8c8c!important}.productPrice{color:#fff!important}}[data-ogsc] .pro= | ||
| ductListPrice{color:#fff!important}[data-ogsc] .productDiscount{color:#ff8c= | ||
| 8c!important}[data-ogsc] .productPrice{color:#fff!important}</style><style = | ||
| type=3D"text/css">.dealBadge{background-color:#cc0c39;color:#fff}.dealText{= | ||
| color:#cc0c39}@media (prefers-color-scheme:dark){.dealBadge{background-colo= | ||
| r:#ff8c8c!important;color:#000!important}.dealText{color:#ff8c8c!important}= | ||
| }[data-ogsc] .dealBadge{background-color:#ff8c8c!important;color:#000!impor= | ||
| tant}[data-ogsc] .dealText{color:#ff8c8c!important}</style><style type=3D"t= | ||
| ext/css">#amazonLogo6ifDMeVChiamBC39CTSZBx.full{max-width:100%!important;pa= | ||
| dding-left:0!important;padding-right:0!important;width:100%!important}#amaz= | ||
| onLogo6ifDMeVChiamBC39CTSZBx.zeroBorder{border:0;border-collapse:collapse;b= | ||
| order-spacing:0}#amazonLogo6ifDMeVChiamBC39CTSZBx .full{max-width:100%!impo= | ||
| rtant;padding-left:0!important;padding-right:0!important;width:100%!importa= | ||
| nt}#amazonLogo6ifDMeVChiamBC39CTSZBx .zeroBorder{border:0;border-collapse:c= | ||
| ollapse;border-spacing:0}#amazonLogo6ifDMeVChiamBC39CTSZBx .light-img{backg= | ||
| round-color:#fff;background-image:linear-gradient(#fff,#fff)}@media (prefer= | ||
| s-color-scheme:light){#amazonLogo6ifDMeVChiamBC39CTSZBx .light-img{display:= | ||
| block!important}#amazonLogo6ifDMeVChiamBC39CTSZBx .dark-img{display:none!im= | ||
| portant}}@media (prefers-color-scheme:dark){#amazonLogo6ifDMeVChiamBC39CTSZ= | ||
| Bx .content{background-color:#181a1a!important}#amazonLogo6ifDMeVChiamBC39C= | ||
| TSZBx .light-img{display:none!important}#amazonLogo6ifDMeVChiamBC39CTSZBx .= | ||
| dark-img{display:block!important}}[data-ogsc] #amazonLogo6ifDMeVChiamBC39CT= | ||
| SZBx .content{background-color:#181a1a!important}[data-ogsc] #amazonLogo6if= | ||
| DMeVChiamBC39CTSZBx .light-img{display:none!important}[data-ogsc] #amazonLo= | ||
| go6ifDMeVChiamBC39CTSZBx .dark-img{display:block!important}</style><!--[if = | ||
| gte mso 9]> | ||
| <xml> | ||
| <o:OfficeDocumentSettings> | ||
| <o:AllowPNG /> | ||
| <o:PixelsPerInch>96</o:PixelsPerInch> | ||
| </o:OfficeDocumentSettings> | ||
| </xml> | ||
| <style> | ||
| body, h1, h2, h3, h4, table, th, td, p, li, a, .sans, .fonts { | ||
| font-family: Helvetica, Arial, sans-serif !important; | ||
| } | ||
| [data-ogsc] .rootContent, [data-ogsc] .rootContent > table{ | ||
| background: #181A1A !important; | ||
| } | ||
| </style> | ||
| <![endif]--></head><body class=3D"body" style=3D"word-spacing:normal;">= | ||
| <img width=3D"1" height=3D"1" src=3D"https://www.amazon.com/gp/r.html?C=3D1= | ||
| Z6HAGN0Q74SS&K=3D1PCIPA854472X&M=3Durn:rtn:msg:20240816010133af409d4398414b= | ||
| 769006b814f360p0na&R=3DE5DJPKCG5QDU&T=3DO&U=3Dhttps%3A%2F%2Fimages-na.ssl-i= | ||
| mages-amazon.com%2Fimages%2FG%2F01%2Fnav%2Ftransp.gif&H=3DF2PRANDPDWFKMJP01= | ||
| PAQRSV6UISA&ref_=3Dpe_108877690_917195550_opens" /><div style=3D"display:no= | ||
| ne;font-size:1px;color:#ffffff;line-height:1px;max-height:0px;max-width:0px= | ||
| ;opacity:0;overflow:hidden;">Delivered: Your Amazon.com order #111-3061760-= | ||
| 5513056͏ ‌   ­͏ ‌   ­= | ||
| ͏ ‌   ­͏ ‌   ­͏ = | ||
| ‌   ­͏ ‌   ­͏ ‌ = | ||
|   ­͏ ‌   ­͏ ‌ = | ||
|   ­͏ ‌   ­͏ ‌  = | ||
| ­͏ ‌   ­͏ ‌   ­&= | ||
| #847; ‌   ­͏ ‌   ­͏ &= | ||
| zwnj;   ­͏ ‌   ­͏ ‌ &= | ||
| nbsp;   ­͏ ‌   ­͏ ‌ &= | ||
| #8199; ­͏ ‌   ­͏ ‌   = | ||
| ­͏ ‌   ­͏ ‌   ­&#= | ||
| 847; ‌   ­͏ ‌   ­͏ &z= | ||
| wnj;   ­͏ ‌   ­͏ ‌ &n= | ||
| bsp;   ­͏ ‌   ­͏ ‌ &#= | ||
| 8199; ­͏ ‌   ­͏ ‌   &= | ||
| shy;͏ ‌   ­͏ ‌   ­= | ||
| 47; ‌   ­͏ ‌   ­͏ &zw= | ||
| nj;   ­͏ ‌   ­͏ ‌ &nb= | ||
| sp;   ­͏ ‌   ­͏ ‌ = | ||
| 199; ­͏ ‌   ­͏ ‌   &s= | ||
| hy;͏ ‌   ­͏ ‌   ­T= | ||
| 7; ‌   ­͏ ‌   ­͏ &zwn= | ||
| j;   ­͏ ‌   ­͏ ‌ &nbs= | ||
| p;   ­͏ ‌   ­͏ ‌ Q= | ||
| 99; ­͏ ‌   ­͏ ‌   &sh= | ||
| y;͏ ‌   ­͏ ‌   ­͏= | ||
| ; ‌   ­͏ ‌   ­͏ &zwnj= | ||
| ;   ­͏ ‌   ­͏ ‌  = | ||
| ;   ­͏ ‌   ­͏ ‌ ̳= | ||
| 9; ­͏ ‌   ­͏ ‌   ­= | ||
| ;͏ ‌   ­͏ ‌   ­͏= | ||
| ‌   ­͏ ‌   ­͏ ‌= | ||
|   ­͏ ‌   ­͏ ‌ = | ||
|   ­͏ ‌   ­͏ ‌  = | ||
| ; ­͏ ‌   ­͏ ‌   ­= | ||
| ͏ ‌   ­͏ ‌   ­͏ = | ||
| ‌   ­͏ ‌   ­͏ ‌ = | ||
|   ­͏ ‌   ­͏ ‌ = | ||
|   ­͏ ‌   ­͏ ‌  = | ||
| ­͏ ‌   ­͏ ‌   ­&= | ||
| #847; ‌   ­͏ ‌   ­͏ &= | ||
| zwnj;   ­͏ ‌   ­͏ ‌ &= | ||
| nbsp;   ­͏ ‌   ­͏ ‌ &= | ||
| #8199; ­͏ ‌   ­͏ ‌   = | ||
| ­͏ ‌   ­͏ ‌   ­&#= | ||
| 847; ‌   ­͏ ‌   ­͏ &z= | ||
| wnj;   ­͏ ‌   ­͏ ‌ &n= | ||
| bsp;   ­͏ ‌   ­͏ ‌ &#= | ||
| 8199; ­͏ ‌   ­͏ ‌   &= | ||
| shy;͏ ‌   ­͏ ‌   ­= | ||
| 47; ‌   ­͏ ‌   ­͏ &zw= | ||
| nj;   ­͏ ‌   ­͏ ‌ &nb= | ||
| sp;   ­͏ ‌   ­͏ ‌ = | ||
| 199; ­͏ ‌   ­͏ ‌   &s= | ||
| hy;͏ ‌   ­͏ ‌   ­T= | ||
| 7; ‌   ­͏ ‌   ­͏ &zwn= | ||
| j;   ­͏ ‌   ­͏ ‌ &nbs= | ||
| p;   ­͏ ‌   ­͏ ‌ Q= | ||
| 99; ­͏ ‌   ­͏ ‌   &sh= | ||
| y;͏ ‌   ­͏ ‌   ­͏= | ||
| ; ‌   ­͏ ‌   ­͏ &zwnj= | ||
| ;   ­͏ ‌   ­͏ ‌  = | ||
| ;   ­͏ ‌   ­͏ ‌ ̳= | ||
| 9; ­͏ ‌   ­͏ ‌   ­= | ||
| ;͏ ‌   ­͏ ‌   ­͏= | ||
| ‌   ­͏ ‌   ­͏ ‌= | ||
|   ­͏ ‌   ­͏ ‌ = | ||
|   ­͏ ‌   ­͏ ‌  = | ||
| ; ­</div><div class=3D"body" lang=3D"en" dir=3D"auto"><!--[if mso | IE]= | ||
| ><table align=3D"center" border=3D"0" cellpadding=3D"0" cellspacing=3D"0" c= | ||
| lass=3D"rootContent-outlook" role=3D"presentation" style=3D"width:600px;" w= | ||
| idth=3D"600" bgcolor=3D"#D5D9D9" ><tr><td style=3D"line-height:0px;font-siz= | ||
| e:0px;mso-line-height-rule:exactly;"><![endif]--><div class=3D"rootContent"= | ||
| style=3D"background:#D5D9D9;background-color:#D5D9D9;margin:0px auto;max-w= | ||
| idth:600px;"><table align=3D"center" border=3D"0" cellpadding=3D"0" cellspa= | ||
| cing=3D"0" role=3D"presentation" style=3D"background:#D5D9D9;background-col= | ||
| or:#D5D9D9;width:100%;"><tbody><tr><td style=3D"direction:ltr;font-size:0px= | ||
| ;padding:0px 0px 4px 0px;text-align:left;"><!--[if mso | IE]><table role=3D= | ||
| "presentation" border=3D"0" cellpadding=3D"0" cellspacing=3D"0"><![endif]--= | ||
| > <!-- PRIME LOGO --><!-- ALEXA LOGO --><!-- AMAZON BUSINESS LOGO --><!-- A= | ||
| ll European Union marketplaces need to use dma compliant logo --> <tab= | ||
| le id=3D"amazonLogo6ifDMeVChiamBC39CTSZBx" class=3D"full zeroBorder" style= | ||
| =3D"width: 100%;" role=3D"presentation"><tbody><tr><td class=3D"content" st= | ||
| yle=3D"padding:0; text-align:left; background-color: #FFFFFF"><!--[if gte m= | ||
| so 9]><table width=3D"600"><tr><td><![endif]--><a href=3D"https://www.amazo= | ||
| n.com/gp/r.html?C=3D1Z6HAGN0Q74SS&K=3D1PCIPA854472X&M=3Durn:rtn:msg:2024081= | ||
| 6010133af409d4398414b769006b814f360p0na&R=3D9WJYLFG12W1E&T=3DC&U=3Dhttps%3A= | ||
| %2F%2Fwww.amazon.com%3Fref_%3Dpe_108877690_917195550_LG0001IMG&H=3DJGWECUYR= | ||
| AY0HTEB3KEJCZQPE9H4A&ref_=3Dpe_108877690_917195550_LG0001IMG" target=3D"_bl= | ||
| ank"><img class=3D"light-img" height=3D"58" role=3D"presentation" src=3D"ht= | ||
| tps://m.media-amazon.com/images/G/01/outbound/OutboundTemplates/Amazon_logo= | ||
| _US._BG255,255,255_.png" style=3D" display:block;background-color: #ffffff;= | ||
| width:auto; height:58px; max-height:58px; max-width:100%; border:0; float:l= | ||
| eft;" alt=3D""> <!--[if !mso]><! --><img class=3D"dark-img" height=3D"58" r= | ||
| ole=3D"presentation" src=3D"https://m.media-amazon.com/images/G/01/outbound= | ||
| /OutboundTemplates/Amazon_logo_whiterev_US.png" style=3D"display:none; widt= | ||
| h:auto; height:58px; max-height:58px; max-width:100%; border:0; float:left;= | ||
| " alt=3D""><!--<![endif]--> </a><!--[if gte mso 9]></td></tr></table><![end= | ||
| if]--></td></tr></tbody></table><!--[if mso | IE]></table><![endif]--></td>= | ||
| </tr></tbody></table></div><!--[if mso | IE]></td></tr></table><![endif]-->= | ||
| <!--[if mso | IE]><table align=3D"center" border=3D"0" cellpadding=3D"0" ce= | ||
| llspacing=3D"0" class=3D"rootContent-outlook" role=3D"presentation" style= | ||
| =3D"width:600px;" width=3D"600" bgcolor=3D"#D5D9D9" ><tr><td style=3D"line-= | ||
| height:0px;font-size:0px;mso-line-height-rule:exactly;"><![endif]--><div cl= | ||
| ass=3D"rootContent" style=3D"background:#D5D9D9;background-color:#D5D9D9;ma= | ||
| rgin:0px auto;max-width:600px;"><table align=3D"center" border=3D"0" cellpa= | ||
| dding=3D"0" cellspacing=3D"0" role=3D"presentation" style=3D"background:#D5= | ||
| D9D9;background-color:#D5D9D9;width:100%;"><tbody><tr><td style=3D"directio= | ||
| n:ltr;font-size:0px;padding:4px 8px 4px 8px;text-align:left;"><!--[if mso |= | ||
| IE]><table role=3D"presentation" border=3D"0" cellpadding=3D"0" cellspacin= | ||
| g=3D"0"><![endif]--> <!--[if mso | IE]><tr><td align=3D"left" class= | ||
| =3D"sonar-informational-outlook sonar-informational-v1-outlook" width=3D"60= | ||
| 0px" ><table align=3D"center" border=3D"0" cellpadding=3D"0" cellspacing=3D= | ||
| "0" class=3D"rio-card-outlook rio-card-70-outlook" role=3D"presentation" st= | ||
| yle=3D"width:584px;" width=3D"584" bgcolor=3D"#ffffff" ><tr><td style=3D"li= | ||
| ne-height:0px;font-size:0px;mso-line-height-rule:exactly;"><![endif]--><div= | ||
| class=3D"rio-card rio-card-70" style=3D"background:#ffffff;background-colo= | ||
| r:#ffffff;margin:0px auto;border-radius:4px;max-width:584px;"><table align= | ||
| =3D"center" border=3D"0" cellpadding=3D"0" cellspacing=3D"0" role=3D"presen= | ||
| tation" style=3D"background:#ffffff;background-color:#ffffff;width:100%;bor= | ||
| der-radius:4px;"><tbody><tr><td style=3D"direction:ltr;font-size:0px;paddin= | ||
| g:12px 8px 12px 8px;text-align:left;"><!--[if mso | IE]><table role=3D"pres= | ||
| entation" border=3D"0" cellpadding=3D"0" cellspacing=3D"0"><tr><td align=3D= | ||
| "left" class=3D"" width=3D"584px" ><table align=3D"center" border=3D"0" cel= | ||
| lpadding=3D"0" cellspacing=3D"0" class=3D"" role=3D"presentation" style=3D"= | ||
| width:568px;" width=3D"568" ><tr><td style=3D"line-height:0px;font-size:0px= | ||
| ;mso-line-height-rule:exactly;"><![endif]--><div style=3D"margin:0px auto;m= | ||
| ax-width:568px;"><table align=3D"center" border=3D"0" cellpadding=3D"0" cel= | ||
| lspacing=3D"0" role=3D"presentation" style=3D"width:100%;"><tbody><tr><td s= | ||
| tyle=3D"direction:ltr;font-size:0px;padding:0;text-align:left;"><!--[if mso= | ||
| | IE]><table role=3D"presentation" border=3D"0" cellpadding=3D"0" cellspac= | ||
| ing=3D"0"><tr><td align=3D"left" class=3D"" style=3D"vertical-align:top;wid= | ||
| th:568px;" ><![endif]--><div class=3D"mj-column-per-100 mj-outlook-group-fi= | ||
| x" style=3D"font-size:0px;text-align:left;direction:ltr;display:inline-bloc= | ||
| k;vertical-align:top;width:100%;"><table border=3D"0" cellpadding=3D"0" cel= | ||
| lspacing=3D"0" role=3D"presentation" width=3D"100%"><tbody><tr><td style=3D= | ||
| "vertical-align:top;padding:0;"><table border=3D"0" cellpadding=3D"0" cells= | ||
| pacing=3D"0" role=3D"presentation" width=3D"100%"><tbody> <tr><td align=3D"= | ||
| left" style=3D"font-size:0px;padding:0;word-break:break-word;"><div style= | ||
| =3D"font-family:Ember,'Amazon Ember',Arial,sans-serif;font-size:15px;line-h= | ||
| eight:1;text-align:left;color:#000000;"><h2 style=3D"margin:0;padding:0;fon= | ||
| t-family:Ember,'Amazon Ember',Arial,sans-serif;font-weight:700;font-size:22= | ||
| px;line-height:28px;color:#0F1111;" class=3D"rio-header rio-header-64">Hi A= | ||
| ayush,</h2></div></td></tr></tbody></table></td></tr></tbody></table></div>= | ||
| <!--[if mso | IE]></td></tr></table><![endif]--></td></tr></tbody></table><= | ||
| /div><!--[if mso | IE]></td></tr></table></td></tr><tr><td align=3D"left" c= | ||
| lass=3D"" width=3D"584px" ><![endif]--> <!--[if mso | IE]><table align= | ||
| =3D"center" border=3D"0" cellpadding=3D"0" cellspacing=3D"0" class=3D"" rol= | ||
| e=3D"presentation" style=3D"width:568px;" width=3D"568" ><tr><td style=3D"l= | ||
| ine-height:0px;font-size:0px;mso-line-height-rule:exactly;"><![endif]--><di= | ||
| v style=3D"margin:0px auto;max-width:568px;"><table align=3D"center" border= | ||
| =3D"0" cellpadding=3D"0" cellspacing=3D"0" role=3D"presentation" style=3D"w= | ||
| idth:100%;"><tbody><tr><td style=3D"direction:ltr;font-size:0px;padding:0;t= | ||
| ext-align:left;"><!--[if mso | IE]><table role=3D"presentation" border=3D"0= | ||
| " cellpadding=3D"0" cellspacing=3D"0"><tr><td align=3D"left" class=3D"" sty= | ||
| le=3D"vertical-align:top;width:568px;" ><![endif]--><div class=3D"mj-column= | ||
| -per-100 mj-outlook-group-fix" style=3D"font-size:0px;text-align:left;direc= | ||
| tion:ltr;display:inline-block;vertical-align:top;width:100%;"><table border= | ||
| =3D"0" cellpadding=3D"0" cellspacing=3D"0" role=3D"presentation" width=3D"1= | ||
| 00%"><tbody><tr><td style=3D"vertical-align:top;padding:0;"><table border= | ||
| =3D"0" cellpadding=3D"0" cellspacing=3D"0" role=3D"presentation" width=3D"1= | ||
| 00%"><tbody><tr><td align=3D"left" style=3D"font-size:0px;padding:0;word-br= | ||
| eak:break-word;"><div style=3D"font-family:Ember,'Amazon Ember',Arial,sans-= | ||
| serif;font-size:15px;font-weight:400;line-height:20px;text-align:left;color= | ||
| :#0F1111;"><span class=3D"rio-text rio-text-121">Your package has been deli= | ||
| vered to reception.</span></div></td></tr></tbody></table></td></tr></tbody= | ||
| ></table></div><!--[if mso | IE]></td></tr></table><![endif]--></td></tr></= | ||
| tbody></table></div><!--[if mso | IE]></td></tr></table><![endif]--> = | ||
| <!--[if mso | IE]></td></tr></table><![endif]--></td></tr></tbody></table>= | ||
| </div><!--[if mso | IE]></td></tr></table></td></tr><![endif]--> <!--[if m= | ||
| so | IE]></table><![endif]--></td></tr></tbody></table></div><!--[if mso | = | ||
| IE]></td></tr></table><![endif]--><!--[if mso | IE]><table align=3D"center"= | ||
| border=3D"0" cellpadding=3D"0" cellspacing=3D"0" class=3D"rootContent-outl= | ||
| ook" role=3D"presentation" style=3D"width:600px;" width=3D"600" bgcolor=3D"= | ||
| #D5D9D9" ><tr><td style=3D"line-height:0px;font-size:0px;mso-line-height-ru= | ||
| le:exactly;"><![endif]--><div class=3D"rootContent" style=3D"background:#D5= | ||
| D9D9;background-color:#D5D9D9;margin:0px auto;max-width:600px;"><table alig= | ||
| n=3D"center" border=3D"0" cellpadding=3D"0" cellspacing=3D"0" role=3D"prese= | ||
| ntation" style=3D"background:#D5D9D9;background-color:#D5D9D9;width:100%;">= | ||
| <tbody><tr><td style=3D"direction:ltr;font-size:0px;padding:4px 8px 4px 8px= | ||
| ;text-align:left;"><!--[if mso | IE]><table role=3D"presentation" border=3D= | ||
| "0" cellpadding=3D"0" cellspacing=3D"0"><![endif]--> <!--[if mso | IE]><tr>= | ||
| <td align=3D"left" class=3D"rex-order-card-outlook rex-order-card-v1-outloo= | ||
| k" width=3D"600px" ><table align=3D"center" border=3D"0" cellpadding=3D"0" = | ||
| cellspacing=3D"0" class=3D"rio-card-outlook rio-card-71-outlook" role=3D"pr= | ||
| esentation" style=3D"width:584px;" width=3D"584" bgcolor=3D"#ffffff" ><tr><= | ||
| td style=3D"line-height:0px;font-size:0px;mso-line-height-rule:exactly;"><!= | ||
| [endif]--><div class=3D"rio-card rio-card-71" style=3D"background:#ffffff;b= | ||
| ackground-color:#ffffff;margin:0px auto;border-radius:4px;max-width:584px;"= | ||
| ><table align=3D"center" border=3D"0" cellpadding=3D"0" cellspacing=3D"0" r= | ||
| ole=3D"presentation" style=3D"background:#ffffff;background-color:#ffffff;w= | ||
| idth:100%;border-radius:4px;"><tbody><tr><td style=3D"direction:ltr;font-si= | ||
| ze:0px;padding:12px 8px 16px 8px;text-align:left;"><!--[if mso | IE]><table= | ||
| role=3D"presentation" border=3D"0" cellpadding=3D"0" cellspacing=3D"0"><![= | ||
| endif]--> <!--[if mso | IE]><tr><td align=3D"left" class=3D"" width= | ||
| =3D"584px" ><table align=3D"center" border=3D"0" cellpadding=3D"0" cellspac= | ||
| ing=3D"0" class=3D"" role=3D"presentation" style=3D"width:568px;" width=3D"= | ||
| 568" ><tr><td style=3D"line-height:0px;font-size:0px;mso-line-height-rule:e= | ||
| xactly;"><![endif]--><div style=3D"margin:0px auto;max-width:568px;"><table= | ||
| align=3D"center" border=3D"0" cellpadding=3D"0" cellspacing=3D"0" role=3D"= | ||
| presentation" style=3D"width:100%;"><tbody><tr><td style=3D"direction:ltr;f= | ||
| ont-size:0px;padding:0;text-align:left;"><!--[if mso | IE]><table role=3D"p= | ||
| resentation" border=3D"0" cellpadding=3D"0" cellspacing=3D"0"><tr><td align= | ||
| =3D"left" class=3D"" style=3D"vertical-align:middle;width:568px;" ><![endif= | ||
| ]--><div class=3D"mj-column-per-100 mj-outlook-group-fix" style=3D"font-siz= | ||
| e:0px;text-align:left;direction:ltr;display:inline-block;vertical-align:mid= | ||
| dle;width:100%;"><table border=3D"0" cellpadding=3D"0" cellspacing=3D"0" ro= | ||
| le=3D"presentation" width=3D"100%"><tbody><tr><td style=3D"vertical-align:m= | ||
| iddle;padding:0;"><table border=3D"0" cellpadding=3D"0" cellspacing=3D"0" r= | ||
| ole=3D"presentation" width=3D"100%"><tbody><tr><td align=3D"left" style=3D"= | ||
| font-size:0px;padding:0;word-break:break-word;"><div style=3D"font-family:E= | ||
| mber,'Amazon Ember',Arial,sans-serif;font-size:18px;font-weight:700;line-he= | ||
| ight:22px;text-align:left;color:#0F1111;"><span class=3D"rio-text rio-text-= | ||
| 122">How was your delivery?</span></div></td></tr><tr><td align=3D"left" cl= | ||
| ass=3D"rio-spacer" style=3D"font-size:0px;padding:0;word-break:break-word;"= | ||
| ><div style=3D"height:12px;line-height:12px;"> </div></td></tr></tbod= | ||
| y></table></td></tr></tbody></table></div><!--[if mso | IE]></td></tr></tab= | ||
| le><![endif]--></td></tr></tbody></table></div><!--[if mso | IE]></td></tr>= | ||
| </table><table align=3D"center" border=3D"0" cellpadding=3D"0" cellspacing= | ||
| =3D"0" class=3D"" role=3D"presentation" style=3D"width:568px;" width=3D"568= | ||
| " ><tr><td style=3D"line-height:0px;font-size:0px;mso-line-height-rule:exac= | ||
| tly;"><![endif]--><div style=3D"margin:0px auto;max-width:568px;"><table al= | ||
| ign=3D"center" border=3D"0" cellpadding=3D"0" cellspacing=3D"0" role=3D"pre= | ||
| sentation" style=3D"width:100%;"><tbody><tr><td style=3D"direction:ltr;font= | ||
| -size:0px;padding:0;text-align:left;"><!--[if mso | IE]><table role=3D"pres= | ||
| entation" border=3D"0" cellpadding=3D"0" cellspacing=3D"0"><tr><td align=3D= | ||
| "left" class=3D"" style=3D"width:568px;" ><![endif]--><div class=3D"mj-colu= | ||
| mn-per-100 mj-outlook-group-fix" style=3D"font-size:0;line-height:0;text-al= | ||
| ign:left;display:inline-block;width:100%;direction:ltr;"><!--[if mso | IE]>= | ||
| <table border=3D"0" cellpadding=3D"0" cellspacing=3D"0" role=3D"presentatio= | ||
| n" ><tr><td style=3D"align:left;vertical-align:middle;width:284px;" ><![end= | ||
| if]--><div class=3D"mj-column-per-50 mj-outlook-group-fix" style=3D"font-si= | ||
| ze:0px;text-align:left;direction:ltr;display:inline-block;vertical-align:mi= | ||
| ddle;width:50%;"><table border=3D"0" cellpadding=3D"0" cellspacing=3D"0" ro= | ||
| le=3D"presentation" width=3D"100%"><tbody><tr><td style=3D"vertical-align:m= | ||
| iddle;padding:0;padding-right:4px;padding-left:0;"><table border=3D"0" cell= | ||
| padding=3D"0" cellspacing=3D"0" role=3D"presentation" width=3D"100%"><tbody= | ||
| ><tr><td align=3D"left" style=3D"font-size:0px;padding:0;word-break:break-w= | ||
| ord;"><!--[if mso | IE]><table align=3D"center" border=3D"0" cellpadding=3D= | ||
| "0" cellspacing=3D"0" class=3D"" role=3D"presentation" style=3D"width:280px= | ||
| ;" width=3D"280" ><tr><td style=3D"line-height:0px;font-size:0px;mso-line-h= | ||
| eight-rule:exactly;"><![endif]--><div style=3D"margin:0px auto;max-width:28= | ||
| 0px;"><table align=3D"center" border=3D"0" cellpadding=3D"0" cellspacing=3D= | ||
| "0" role=3D"presentation" style=3D"width:100%;"><tbody><tr><td style=3D"dir= | ||
| ection:ltr;font-size:0px;padding:0;text-align:left;"><!--[if mso | IE]><tab= | ||
| le role=3D"presentation" border=3D"0" cellpadding=3D"0" cellspacing=3D"0"><= | ||
| tr><td align=3D"left" class=3D"" style=3D"vertical-align:top;width:280px;" = | ||
| ><![endif]--><div class=3D"mj-column-per-100 mj-outlook-group-fix" style=3D= | ||
| "font-size:0px;text-align:left;direction:ltr;display:inline-block;vertical-= | ||
| align:top;width:100%;"><table border=3D"0" cellpadding=3D"0" cellspacing=3D= | ||
| "0" role=3D"presentation" width=3D"100%"><tbody><tr><td style=3D"background= | ||
| -color:#F0F2F2;border-radius:4px;vertical-align:top;padding:0;"><table bord= | ||
| er=3D"0" cellpadding=3D"0" cellspacing=3D"0" role=3D"presentation" width=3D= | ||
| "100%"><tbody><tr><td align=3D"left" style=3D"font-size:0px;padding:0;word-= | ||
| break:break-word;"><div style=3D"font-family:Ember,'Amazon Ember',Arial,san= | ||
| s-serif;font-size:13px;font-weight:400;line-height:18px;text-align:center;c= | ||
| olor:#0F1111;"><span class=3D"rio-text rio-text-123"><a href=3D"https://www= | ||
| .amazon.com/gp/r.html?C=3D1Z6HAGN0Q74SS&K=3D1PCIPA854472X&M=3Durn:rtn:msg:2= | ||
| 0240816010133af409d4398414b769006b814f360p0na&R=3DSIRM1R078GGM&T=3DC&U=3Dht= | ||
| tps%3A%2F%2Fwww.amazon.com%2Fprogress-tracker%2Fpackage%3F_encoding%3DUTF8%= | ||
| 26itemId%3D%26orderId%3D111-3061760-5513056%26packageIndex%3D0%26shipmentId= | ||
| %3D300612189807301%26ingress%3Demail%26intent%3Dfeedback_happy%26ref_%3Dpe_= | ||
| 108877690_917195550_pdc_f_h&H=3DC5X8OQYHSNU4HZWASVBUOHCGVGGA&ref_=3Dpe_1088= | ||
| 77690_917195550_pdc_f_h" target=3D"_blank" style=3D"mso-margin-top-alt: 16p= | ||
| x;"><img href=3D"https://www.amazon.com/progress-tracker/package?_encoding= | ||
| =3DUTF8&itemId=3D&orderId=3D111-3061760-5513056&packageIndex=3D= | ||
| 0&shipmentId=3D300612189807301&ingress=3Demail&intent=3Dfeedbac= | ||
| k_happy&ref_=3Dpdc_f_h" src=3D"https://m.media-amazon.com/images/G/01/T= | ||
| xNotifications/Rio/thumbs_up.png" alt=3D"It was great" width=3D"24" height= | ||
| =3D"24" style=3D"margin: auto; padding: 8px; mso-padding-alt: 0; display: b= | ||
| lock; width: 24px"><p style=3D"padding-bottom: 8px; margin: 0; mso-margin-b= | ||
| ottom-alt: 8px">It was great</p></a></span></div></td></tr></tbody></table>= | ||
| </td></tr></tbody></table></div><!--[if mso | IE]></td></tr></table><![endi= | ||
| f]--></td></tr></tbody></table></div><!--[if mso | IE]></td></tr></table><!= | ||
| [endif]--></td></tr></tbody></table></td></tr></tbody></table></div><!--[if= | ||
| mso | IE]></td><td style=3D"align:left;vertical-align:middle;width:284px;"= | ||
| ><![endif]--><div class=3D"mj-column-per-50 mj-outlook-group-fix" style=3D= | ||
| "font-size:0px;text-align:left;direction:ltr;display:inline-block;vertical-= | ||
| align:middle;width:50%;"><table border=3D"0" cellpadding=3D"0" cellspacing= | ||
| =3D"0" role=3D"presentation" width=3D"100%"><tbody><tr><td style=3D"vertica= | ||
| l-align:middle;padding:0;padding-right:0;padding-left:4px;"><table border= | ||
| =3D"0" cellpadding=3D"0" cellspacing=3D"0" role=3D"presentation" width=3D"1= | ||
| 00%"><tbody><tr><td align=3D"left" style=3D"font-size:0px;padding:0;word-br= | ||
| eak:break-word;"><!--[if mso | IE]><table align=3D"center" border=3D"0" cel= | ||
| lpadding=3D"0" cellspacing=3D"0" class=3D"" role=3D"presentation" style=3D"= | ||
| width:280px;" width=3D"280" ><tr><td style=3D"line-height:0px;font-size:0px= | ||
| ;mso-line-height-rule:exactly;"><![endif]--><div style=3D"margin:0px auto;m= | ||
| ax-width:280px;"><table align=3D"center" border=3D"0" cellpadding=3D"0" cel= | ||
| lspacing=3D"0" role=3D"presentation" style=3D"width:100%;"><tbody><tr><td s= | ||
| tyle=3D"direction:ltr;font-size:0px;padding:0;text-align:left;"><!--[if mso= | ||
| | IE]><table role=3D"presentation" border=3D"0" cellpadding=3D"0" cellspac= | ||
| ing=3D"0"><tr><td align=3D"left" class=3D"" style=3D"vertical-align:top;wid= | ||
| th:280px;" ><![endif]--><div class=3D"mj-column-per-100 mj-outlook-group-fi= | ||
| x" style=3D"font-size:0px;text-align:left;direction:ltr;display:inline-bloc= | ||
| k;vertical-align:top;width:100%;"><table border=3D"0" cellpadding=3D"0" cel= | ||
| lspacing=3D"0" role=3D"presentation" width=3D"100%"><tbody><tr><td style=3D= | ||
| "background-color:#F0F2F2;border-radius:4px;vertical-align:top;padding:0;">= | ||
| <table border=3D"0" cellpadding=3D"0" cellspacing=3D"0" role=3D"presentatio= | ||
| n" width=3D"100%"><tbody><tr><td align=3D"left" style=3D"font-size:0px;padd= | ||
| ing:0;word-break:break-word;"><div style=3D"font-family:Ember,'Amazon Ember= | ||
| ',Arial,sans-serif;font-size:13px;font-weight:400;line-height:18px;text-ali= | ||
| gn:center;color:#0F1111;"><span class=3D"rio-text rio-text-124"><a href=3D"= | ||
| https://www.amazon.com/gp/r.html?C=3D1Z6HAGN0Q74SS&K=3D1PCIPA854472X&M=3Dur= | ||
| n:rtn:msg:20240816010133af409d4398414b769006b814f360p0na&R=3DMJGP66VISZXC&T= | ||
| =3DC&U=3Dhttps%3A%2F%2Fwww.amazon.com%2Fprogress-tracker%2Fpackage%3F_encod= | ||
| ing%3DUTF8%26itemId%3D%26orderId%3D111-3061760-5513056%26packageIndex%3D0%2= | ||
| 6shipmentId%3D300612189807301%26ingress%3Demail%26intent%3Dfeedback_unhappy= | ||
| %26ref_%3Dpe_108877690_917195550_pdc_f_s&H=3DGWG8R3TO7P0CBBABRRGLVRPQV9YA&r= | ||
| ef_=3Dpe_108877690_917195550_pdc_f_s" target=3D"_blank" style=3D"mso-margin= | ||
| -top-alt: 16px;"><img href=3D"https://www.amazon.com/progress-tracker/packa= | ||
| ge?_encoding=3DUTF8&itemId=3D&orderId=3D111-3061760-5513056&pac= | ||
| kageIndex=3D0&shipmentId=3D300612189807301&ingress=3Demail&inte= | ||
| nt=3Dfeedback_unhappy&ref_=3Dpdc_f_s" src=3D"https://m.media-amazon.com= | ||
| /images/G/01/TxNotifications/Rio/thumbs_down.png" alt=3D"Not so great" widt= | ||
| h=3D"24" height=3D"24" style=3D"margin: auto; padding: 8px; mso-padding-alt= | ||
| : 0; display: block; width: 24px"><p style=3D"padding-bottom: 8px; margin: = | ||
| 0; mso-margin-bottom-alt: 8px">Not so great</p></a></span></div></td></tr><= | ||
| /tbody></table></td></tr></tbody></table></div><!--[if mso | IE]></td></tr>= | ||
| </table><![endif]--></td></tr></tbody></table></div><!--[if mso | IE]></td>= | ||
| </tr></table><![endif]--></td></tr></tbody></table></td></tr></tbody></tabl= | ||
| e></div><!--[if mso | IE]></td></tr></table><![endif]--></div><!--[if mso |= | ||
| IE]></td></tr></table><![endif]--></td></tr></tbody></table></div><!--[if = | ||
| mso | IE]></td></tr></table></td></tr><![endif]--> <!--[if mso | IE]><tr><t= | ||
| d align=3D"left" class=3D"rio-spacer-outlook" width=3D"584px" ><![endif]-->= | ||
| <div style=3D"height:20px;line-height:20px;"> </div><!--[if mso | IE]= | ||
| ></td></tr><![endif]--> <!--[if mso | IE]><tr><td align=3D"left" class=3D""= | ||
| width=3D"584px" ><table align=3D"center" border=3D"0" cellpadding=3D"0" ce= | ||
| llspacing=3D"0" class=3D"" role=3D"presentation" style=3D"width:568px;" wid= | ||
| th=3D"568" ><tr><td style=3D"line-height:0px;font-size:0px;mso-line-height-= | ||
| rule:exactly;"><![endif]--><div style=3D"margin:0px auto;max-width:568px;">= | ||
| <table align=3D"center" border=3D"0" cellpadding=3D"0" cellspacing=3D"0" ro= | ||
| le=3D"presentation" style=3D"width:100%;"><tbody><tr><td style=3D"direction= | ||
| :ltr;font-size:0px;padding:0;text-align:left;"><!--[if mso | IE]><table rol= | ||
| e=3D"presentation" border=3D"0" cellpadding=3D"0" cellspacing=3D"0"><tr><td= | ||
| align=3D"left" class=3D"" style=3D"vertical-align:top;width:568px;" ><![en= | ||
| dif]--><div class=3D"mj-column-per-100 mj-outlook-group-fix" style=3D"font-= | ||
| size:0px;text-align:left;direction:ltr;display:inline-block;vertical-align:= | ||
| top;width:100%;"><table border=3D"0" cellpadding=3D"0" cellspacing=3D"0" ro= | ||
| le=3D"presentation" width=3D"100%"><tbody><tr><td style=3D"vertical-align:t= | ||
| op;padding:0;"><table border=3D"0" cellpadding=3D"0" cellspacing=3D"0" role= | ||
| =3D"presentation" width=3D"100%"><tbody><tr><td align=3D"left" style=3D"fon= | ||
| t-size:0px;padding:0;word-break:break-word;"><div style=3D"font-family:Embe= | ||
| r,'Amazon Ember',Arial,sans-serif;font-size:15px;font-weight:400;line-heigh= | ||
| t:21px;text-align:left;color:#565959;"><span class=3D"rio-text rio-text-125= | ||
| ">Order #</span></div></td></tr><tr><td align=3D"left" style=3D"font-size:0= | ||
| px;padding:0;word-break:break-word;"><div style=3D"font-family:Ember,'Amazo= | ||
| n Ember',Arial,sans-serif;font-size:15px;font-weight:700;line-height:21px;t= | ||
| ext-align:left;color:#0F1111;"><span class=3D"rio-text rio-text-126">111-30= | ||
| 61760-5513056</span></div></td></tr></tbody></table></td></tr></tbody></tab= | ||
| le></div><!--[if mso | IE]></td></tr></table><![endif]--></td></tr></tbody>= | ||
| </table></div><!--[if mso | IE]></td></tr></table></td></tr><tr><td align= | ||
| =3D"left" class=3D"" width=3D"584px" ><table align=3D"center" border=3D"0" = | ||
| cellpadding=3D"0" cellspacing=3D"0" class=3D"" role=3D"presentation" style= | ||
| =3D"width:568px;" width=3D"568" ><tr><td style=3D"line-height:0px;font-size= | ||
| :0px;mso-line-height-rule:exactly;"><![endif]--><div style=3D"margin:0px au= | ||
| to;max-width:568px;"><table align=3D"center" border=3D"0" cellpadding=3D"0"= | ||
| cellspacing=3D"0" role=3D"presentation" style=3D"width:100%;"><tbody><tr><= | ||
| td style=3D"direction:ltr;font-size:0px;padding:0;text-align:left;"><!--[if= | ||
| mso | IE]><table role=3D"presentation" border=3D"0" cellpadding=3D"0" cell= | ||
| spacing=3D"0"><tr><td align=3D"left" class=3D"" style=3D"width:568px;" ><![= | ||
| endif]--><div class=3D"mj-column-per-100 mj-outlook-group-fix" style=3D"fon= | ||
| t-size:0;line-height:0;text-align:left;display:inline-block;width:100%;dire= | ||
| ction:ltr;"><!--[if mso | IE]><table border=3D"0" cellpadding=3D"0" cellspa= | ||
| cing=3D"0" role=3D"presentation" ><tr><td style=3D"align:left;vertical-alig= | ||
| n:top;width:284px;" ><![endif]--><div class=3D"mj-column-per-50 mj-outlook-= | ||
| group-fix" style=3D"font-size:0px;text-align:left;direction:ltr;display:inl= | ||
| ine-block;vertical-align:top;width:50%;"><table border=3D"0" cellpadding=3D= | ||
| "0" cellspacing=3D"0" role=3D"presentation" width=3D"100%"><tbody><tr><td s= | ||
| tyle=3D"vertical-align:top;padding:0;"><table border=3D"0" cellpadding=3D"0= | ||
| " cellspacing=3D"0" role=3D"presentation" width=3D"100%"><tbody> <tr><td = | ||
| align=3D"left" class=3D"rio-spacer" style=3D"font-size:0px;padding:0;word-b= | ||
| reak:break-word;"><div style=3D"height:20px;line-height:20px;"> </div= | ||
| ></td></tr><tr><td align=3D"left" style=3D"font-size:0px;padding:0;word-bre= | ||
| ak:break-word;"><!--[if gte mso 9]><style type=3D"text/css">.rio-button-cta= | ||
| -primary{background-color:#ffd814!important;border:1px solid #fcd200!import= | ||
| ant;padding:6px 16px!important;text-align:center;border-collapse:collapse!i= | ||
| mportant}.rio-button-primary{border:none!important}</style><![endif]--><tab= | ||
| le cellpadding=3D"0" cellspacing=3D"0" border=3D"0" role=3D"presentation"><= | ||
| tr><td class=3D"rio-button-cta-primary" style=3D"text-align: center"><a tar= | ||
| get=3D"_blank" aria-describedby=3D"Track package" class=3D"rio-button-prima= | ||
| ry" href=3D"https://www.amazon.com/gp/r.html?C=3D1Z6HAGN0Q74SS&K=3D1PCIPA85= | ||
| 4472X&M=3Durn:rtn:msg:20240816010133af409d4398414b769006b814f360p0na&R=3DBU= | ||
| 2DG84QM77R&T=3DC&U=3Dhttps%3A%2F%2Fwww.amazon.com%2Fgp%2Fyour-account%2Fshi= | ||
| p-track%3Fie%3DUTF8%26itemId%3D%26orderId%3D111-3061760-5513056%26packageIn= | ||
| dex%3D0%26shipmentId%3DGhsHRNhnG%26ref_%3Dpe_108877690_917195550_pdc_pt_tra= | ||
| ck&H=3DKVPMEEQKDCKNEZFWYBLC3E75A84A&ref_=3Dpe_108877690_917195550_pdc_pt_tr= | ||
| ack" style=3D"background-color: #FFD814; border: 1px solid #FCD200; color: = | ||
| #0f1111; text-decoration: none; border-radius: 24px;padding: 6px 16px;displ= | ||
| ay: inline-block;box-shadow: 1px 2px 4px rgba(153, 153, 153, 0.2);font-size= | ||
| : 13px;line-height: 18px;white-space: nowrap;"><span style=3D"text-decorati= | ||
| on: none">Track package</span></a></td></tr></table></td></tr></tbody></tab= | ||
| le></td></tr></tbody></table></div><!--[if mso | IE]></td><td style=3D"alig= | ||
| n:left;width:284px;" ><![endif]--><div class=3D"mj-column-per-50 mj-outlook= | ||
| -group-fix" style=3D"font-size:0;line-height:0;text-align:left;display:inli= | ||
| ne-block;width:100%;direction:ltr;"><!--[if mso | IE]><table border=3D"0" c= | ||
| ellpadding=3D"0" cellspacing=3D"0" role=3D"presentation" ><tr></tr></table>= | ||
| <![endif]--></div><!--[if mso | IE]></td></tr></table><![endif]--></div><!-= | ||
| -[if mso | IE]></td></tr></table><![endif]--></td></tr></tbody></table></di= | ||
| v><!--[if mso | IE]></td></tr></table></td></tr><![endif]--> <!--[if mso | = | ||
| IE]></table><![endif]--></td></tr></tbody></table></div><!--[if mso | IE]><= | ||
| /td></tr></table></td></tr><![endif]--> <!--[if mso | IE]></table><![endif]= | ||
| --></td></tr></tbody></table></div><!--[if mso | IE]></td></tr></table><![e= | ||
| ndif]--><!--[if mso | IE]><table align=3D"center" border=3D"0" cellpadding= | ||
| =3D"0" cellspacing=3D"0" class=3D"rootContent-outlook" role=3D"presentation= | ||
| " style=3D"width:600px;" width=3D"600" bgcolor=3D"#D5D9D9" ><tr><td style= | ||
| =3D"line-height:0px;font-size:0px;mso-line-height-rule:exactly;"><![endif]-= | ||
| -><div class=3D"rootContent" style=3D"background:#D5D9D9;background-color:#= | ||
| D5D9D9;margin:0px auto;max-width:600px;"><table align=3D"center" border=3D"= | ||
| 0" cellpadding=3D"0" cellspacing=3D"0" role=3D"presentation" style=3D"backg= | ||
| round:#D5D9D9;background-color:#D5D9D9;width:100%;"><tbody><tr><td style=3D= | ||
| "direction:ltr;font-size:0px;padding:4px 8px 4px 8px;text-align:left;"><!--= | ||
| [if mso | IE]><table role=3D"presentation" border=3D"0" cellpadding=3D"0" c= | ||
| ellspacing=3D"0"><![endif]--> <!--[if mso | IE]><tr><td align=3D"left= | ||
| " class=3D"sonar-informational-outlook sonar-informational-v1-outlook" widt= | ||
| h=3D"600px" ><table align=3D"center" border=3D"0" cellpadding=3D"0" cellspa= | ||
| cing=3D"0" class=3D"rio-card-outlook rio-card-72-outlook" role=3D"presentat= | ||
| ion" style=3D"width:584px;" width=3D"584" bgcolor=3D"#ffffff" ><tr><td styl= | ||
| e=3D"line-height:0px;font-size:0px;mso-line-height-rule:exactly;"><![endif]= | ||
| --><div class=3D"rio-card rio-card-72" style=3D"background:#ffffff;backgrou= | ||
| nd-color:#ffffff;margin:0px auto;border-radius:4px;max-width:584px;"><table= | ||
| align=3D"center" border=3D"0" cellpadding=3D"0" cellspacing=3D"0" role=3D"= | ||
| presentation" style=3D"background:#ffffff;background-color:#ffffff;width:10= | ||
| 0%;border-radius:4px;"><tbody><tr><td style=3D"direction:ltr;font-size:0px;= | ||
| padding:12px 8px 12px 8px;text-align:left;"><!--[if mso | IE]><table role= | ||
| =3D"presentation" border=3D"0" cellpadding=3D"0" cellspacing=3D"0"><tr><td = | ||
| align=3D"left" class=3D"" width=3D"584px" ><table align=3D"center" border= | ||
| =3D"0" cellpadding=3D"0" cellspacing=3D"0" class=3D"" role=3D"presentation"= | ||
| style=3D"width:568px;" width=3D"568" ><tr><td style=3D"line-height:0px;fon= | ||
| t-size:0px;mso-line-height-rule:exactly;"><![endif]--><div style=3D"margin:= | ||
| 0px auto;max-width:568px;"><table align=3D"center" border=3D"0" cellpadding= | ||
| =3D"0" cellspacing=3D"0" role=3D"presentation" style=3D"width:100%;"><tbody= | ||
| ><tr><td style=3D"direction:ltr;font-size:0px;padding:0;text-align:left;"><= | ||
| !--[if mso | IE]><table role=3D"presentation" border=3D"0" cellpadding=3D"0= | ||
| " cellspacing=3D"0"><tr><td align=3D"left" class=3D"" style=3D"vertical-ali= | ||
| gn:top;width:568px;" ><![endif]--><div class=3D"mj-column-per-100 mj-outloo= | ||
| k-group-fix" style=3D"font-size:0px;text-align:left;direction:ltr;display:i= | ||
| nline-block;vertical-align:top;width:100%;"><table border=3D"0" cellpadding= | ||
| =3D"0" cellspacing=3D"0" role=3D"presentation" width=3D"100%"><tbody><tr><t= | ||
| d style=3D"vertical-align:top;padding:0;"><table border=3D"0" cellpadding= | ||
| =3D"0" cellspacing=3D"0" role=3D"presentation" width=3D"100%"><tbody> </tbo= | ||
| dy></table></td></tr></tbody></table></div><!--[if mso | IE]></td></tr></ta= | ||
| ble><![endif]--></td></tr></tbody></table></div><!--[if mso | IE]></td></tr= | ||
| ></table></td></tr><tr><td align=3D"left" class=3D"" width=3D"584px" ><![en= | ||
| dif]--> <!--[if mso | IE]><table align=3D"center" border=3D"0" cellpad= | ||
| ding=3D"0" cellspacing=3D"0" class=3D"" role=3D"presentation" style=3D"widt= | ||
| h:568px;" width=3D"568" ><tr><td style=3D"line-height:0px;font-size:0px;mso= | ||
| -line-height-rule:exactly;"><![endif]--><div style=3D"margin:0px auto;max-w= | ||
| idth:568px;"><table align=3D"center" border=3D"0" cellpadding=3D"0" cellspa= | ||
| cing=3D"0" role=3D"presentation" style=3D"width:100%;"><tbody><tr><td style= | ||
| =3D"direction:ltr;font-size:0px;padding:0;text-align:left;"><!--[if mso | I= | ||
| E]><table role=3D"presentation" border=3D"0" cellpadding=3D"0" cellspacing= | ||
| =3D"0"><tr><td align=3D"left" class=3D"" style=3D"vertical-align:top;width:= | ||
| 568px;" ><![endif]--><div class=3D"mj-column-per-100 mj-outlook-group-fix" = | ||
| style=3D"font-size:0px;text-align:left;direction:ltr;display:inline-block;v= | ||
| ertical-align:top;width:100%;"><table border=3D"0" cellpadding=3D"0" cellsp= | ||
| acing=3D"0" role=3D"presentation" width=3D"100%"><tbody><tr><td style=3D"ve= | ||
| rtical-align:top;padding:0;"><table border=3D"0" cellpadding=3D"0" cellspac= | ||
| ing=3D"0" role=3D"presentation" width=3D"100%"><tbody><tr><td align=3D"left= | ||
| " style=3D"font-size:0px;padding:0;word-break:break-word;"><div style=3D"fo= | ||
| nt-family:Ember,'Amazon Ember',Arial,sans-serif;font-size:15px;font-weight:= | ||
| 400;line-height:20px;text-align:left;color:#0F1111;"><span class=3D"rio-tex= | ||
| t rio-text-129">Return or replace items in=20 | ||
| <a href=3D"https://www.amazon.com/gp/r.html?C=3D1Z6HAGN0Q74SS&K=3D1PCIPA854= | ||
| 472X&M=3Durn:rtn:msg:20240816010133af409d4398414b769006b814f360p0na&R=3D2U7= | ||
| FVGB1HZ63S&T=3DC&U=3Dhttps%3A%2F%2Fwww.amazon.com%2Fyour-orders%2Forders%3F= | ||
| ref_%3Dpe_108877690_917195550_pdc_yo&H=3DMRR6NURCHGXV0VKPAM2B9LRNHGKA&ref_= | ||
| =3Dpe_108877690_917195550_pdc_yo" rel=3D"nofollow">Your Orders</a>.</span><= | ||
| /div></td></tr></tbody></table></td></tr></tbody></table></div><!--[if mso = | ||
| | IE]></td></tr></table><![endif]--></td></tr></tbody></table></div><!--[if= | ||
| mso | IE]></td></tr></table><![endif]--> <!--[if mso | IE]></td></t= | ||
| r></table><![endif]--></td></tr></tbody></table></div><!--[if mso | IE]></t= | ||
| d></tr></table></td></tr><![endif]--> <!--[if mso | IE]></table><![endif]-= | ||
| -></td></tr></tbody></table></div><!--[if mso | IE]></td></tr></table><![en= | ||
| dif]--><!--[if mso | IE]><table align=3D"center" border=3D"0" cellpadding= | ||
| =3D"0" cellspacing=3D"0" class=3D"rootContent-outlook" role=3D"presentation= | ||
| " style=3D"width:600px;" width=3D"600" bgcolor=3D"#D5D9D9" ><tr><td style= | ||
| =3D"line-height:0px;font-size:0px;mso-line-height-rule:exactly;"><![endif]-= | ||
| -><div class=3D"rootContent" style=3D"background:#D5D9D9;background-color:#= | ||
| D5D9D9;margin:0px auto;max-width:600px;"><table align=3D"center" border=3D"= | ||
| 0" cellpadding=3D"0" cellspacing=3D"0" role=3D"presentation" style=3D"backg= | ||
| round:#D5D9D9;background-color:#D5D9D9;width:100%;"><tbody><tr><td style=3D= | ||
| "direction:ltr;font-size:0px;padding:4px 0px 0px 0px;text-align:left;"><!--= | ||
| [if mso | IE]><table role=3D"presentation" border=3D"0" cellpadding=3D"0" c= | ||
| ellspacing=3D"0"><![endif]--> <!--[if mso | IE]><tr><td align=3D"left" clas= | ||
| s=3D"sonar-footer-outlook sonar-footer-v1-outlook" width=3D"600px" ><table = | ||
| align=3D"center" border=3D"0" cellpadding=3D"0" cellspacing=3D"0" class=3D"= | ||
| footerCard-outlook" role=3D"presentation" style=3D"width:600px;" width=3D"6= | ||
| 00" bgcolor=3D"#F0F2F2" ><tr><td style=3D"line-height:0px;font-size:0px;mso= | ||
| -line-height-rule:exactly;"><![endif]--><div class=3D"footerCard" style=3D"= | ||
| background:#F0F2F2;background-color:#F0F2F2;margin:0px auto;max-width:600px= | ||
| ;"><table align=3D"center" border=3D"0" cellpadding=3D"0" cellspacing=3D"0"= | ||
| role=3D"presentation" style=3D"background:#F0F2F2;background-color:#F0F2F2= | ||
| ;width:100%;"><tbody><tr><td style=3D"direction:ltr;font-size:0px;padding:0= | ||
| ;text-align:left;"><!--[if mso | IE]><table role=3D"presentation" border=3D= | ||
| "0" cellpadding=3D"0" cellspacing=3D"0"><tr><td align=3D"left" class=3D"foo= | ||
| terText-outlook" width=3D"600px" ><table align=3D"center" border=3D"0" cell= | ||
| padding=3D"0" cellspacing=3D"0" class=3D"footerText-outlook" role=3D"presen= | ||
| tation" style=3D"width:600px;" width=3D"600" ><tr><td style=3D"line-height:= | ||
| 0px;font-size:0px;mso-line-height-rule:exactly;"><![endif]--><div class=3D"= | ||
| footerText" style=3D"margin:0px auto;max-width:600px;"><table align=3D"cent= | ||
| er" border=3D"0" cellpadding=3D"0" cellspacing=3D"0" role=3D"presentation" = | ||
| style=3D"width:100%;"><tbody><tr><td style=3D"direction:ltr;font-size:0px;p= | ||
| adding:20px 16px 0;text-align:left;"><!--[if mso | IE]><table role=3D"prese= | ||
| ntation" border=3D"0" cellpadding=3D"0" cellspacing=3D"0"><tr><td align=3D"= | ||
| left" class=3D"" style=3D"vertical-align:top;width:568px;" ><![endif]--><di= | ||
| v class=3D"mj-column-per-100 mj-outlook-group-fix" style=3D"font-size:0px;t= | ||
| ext-align:left;direction:ltr;display:inline-block;vertical-align:top;width:= | ||
| 100%;"><table border=3D"0" cellpadding=3D"0" cellspacing=3D"0" role=3D"pres= | ||
| entation" width=3D"100%"><tbody><tr><td style=3D"vertical-align:top;padding= | ||
| :0;"><table border=3D"0" cellpadding=3D"0" cellspacing=3D"0" role=3D"presen= | ||
| tation" width=3D"100%"><tbody><tr><td align=3D"left" style=3D"font-size:0px= | ||
| ;padding:0;word-break:break-word;"><div style=3D"font-family:Ember,'Amazon = | ||
| Ember',Arial,sans-serif;font-size:14px;font-weight:400;line-height:20px;tex= | ||
| t-align:left;color:#494D4D;">=C2=A92024 Amazon.com, Inc. or its affiliates.= | ||
| Amazon and all related marks are trademarks of Amazon.com, Inc. or its aff= | ||
| iliates, Amazon.com, Inc. 410 Terry Avenue N., Seattle, WA 98109.</div></td= | ||
| ></tr></tbody></table></td></tr></tbody></table></div><!--[if mso | IE]></t= | ||
| d></tr></table><![endif]--></td></tr></tbody></table></div><!--[if mso | IE= | ||
| ]></td></tr></table></td></tr><![endif]--> <!--[if mso | IE]><tr><td align= | ||
| =3D"left" class=3D"" width=3D"600px" ><table align=3D"center" border=3D"0" = | ||
| cellpadding=3D"0" cellspacing=3D"0" class=3D"" role=3D"presentation" style= | ||
| =3D"width:600px;" width=3D"600" ><tr><td style=3D"line-height:0px;font-size= | ||
| :0px;mso-line-height-rule:exactly;"><![endif]--><div style=3D"margin:0px au= | ||
| to;max-width:600px;"><table align=3D"center" border=3D"0" cellpadding=3D"0"= | ||
| cellspacing=3D"0" role=3D"presentation" style=3D"width:100%;"><tbody><tr><= | ||
| td style=3D"direction:ltr;font-size:0px;padding:14px 16px 4px 0;text-align:= | ||
| left;"><!--[if mso | IE]><table role=3D"presentation" border=3D"0" cellpadd= | ||
| ing=3D"0" cellspacing=3D"0"><tr><td align=3D"left" class=3D"" style=3D"vert= | ||
| ical-align:top;width:584px;" ><![endif]--><div class=3D"mj-column-per-100 m= | ||
| j-outlook-group-fix" style=3D"font-size:0px;text-align:left;direction:ltr;d= | ||
| isplay:inline-block;vertical-align:top;width:100%;"><table border=3D"0" cel= | ||
| lpadding=3D"0" cellspacing=3D"0" role=3D"presentation" width=3D"100%"><tbod= | ||
| y><tr><td style=3D"vertical-align:top;padding:0;"><table border=3D"0" cellp= | ||
| adding=3D"0" cellspacing=3D"0" role=3D"presentation" width=3D"100%"><tbody>= | ||
| <table class=3D"lightFooterImg" style=3D"height:43px;width:86px;"><tr><td><= | ||
| img src=3D"https://m.media-amazon.com/images/G/01/outbound/OutboundTemplate= | ||
| s/Smile_Logo_Light._BG240,242,242_.png" alt=3D"Amazon.com" height=3D"43" wi= | ||
| dth=3D"86" align=3D"left"></td></tr></table><!--[if !mso]><!--><table class= | ||
| =3D"darkFooterImg" style=3D"height:43px;width:86px;display:none;"><tr><td><= | ||
| img src=3D"https://m.media-amazon.com/images/G/01/outbound/OutboundTemplate= | ||
| s/Smile_Logo_Dark.png" alt=3D"Amazon.com" height=3D"43" width=3D"86" align= | ||
| =3D"left"></td></tr></table><!--<![endif]--></tbody></table></td></tr></tbo= | ||
| dy></table></div><!--[if mso | IE]></td></tr></table><![endif]--></td></tr>= | ||
| </tbody></table></div><!--[if mso | IE]></td></tr></table></td></tr></table= | ||
| ><![endif]--></td></tr></tbody></table></div><!--[if mso | IE]></td></tr></= | ||
| table></td></tr><![endif]--> <!--[if mso | IE]></table><![endif]--></td></t= | ||
| r></tbody></table></div><!--[if mso | IE]></td></tr></table><![endif]--></d= | ||
| iv><img width=3D"1" height=3D"1" src=3D"https://www.amazon.com/gp/r.html?C= | ||
| =3D1Z6HAGN0Q74SS&K=3D1PCIPA854472X&M=3Durn:rtn:msg:20240816010133af409d4398= | ||
| 414b769006b814f360p0na&R=3D1RGIUEL0NLUB0&T=3DE&U=3Dhttps%3A%2F%2Fimages-na.= | ||
| ssl-images-amazon.com%2Fimages%2FG%2F01%2Fnav%2Ftransp.gif&H=3DHTTPRSBYHYPR= | ||
| XR0HOLWRVI18LHCA&ref_=3Dpe_108877690_917195550_open" /></body></html> | ||
| ------=_Part_533333_1464710557.1723770094034-- |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Privacy concern: Real email addresses and order information in version control.
This email fixture contains real personal information:
- Email addresses:
[email protected],[email protected] - Real Amazon order number:
111-3061760-5513056 - Recipient name: Aayush
- Delivery address details (referenced in tracking)
Committing real customer data and order information to public repositories violates privacy best practices and potentially terms of service. The email also contains complete SMTP routing information that could be used for reconnaissance.
Recommendation: Replace with synthetic test data that preserves the email structure but removes real identifiers.
🤖 Prompt for AI Agents
In browser_test/public/amazon.eml lines 1-1000, the fixture contains real PII
(email addresses [email protected], [email protected]), a real Amazon order
number (111-3061760-5513056), recipient name, and SMTP routing metadata; replace
all real identifiers with synthetic placeholders while preserving the original
email structure and formatting (e.g., replace addresses with
[email protected] and [email protected], replace order numbers with a
fake pattern like 000-0000000-0000000, redact recipient name to "Test User", and
scrub or anonymize SMTP headers/routing details) so tests still exercise
parsing/rendering but no real customer data remains in the repo.
| Delivered-To: [email protected] | ||
| Received: by 2002:a05:7108:5e85:b0:47f:4051:d657 with SMTP id ev5csp1218074gdb; | ||
| Fri, 22 Aug 2025 23:59:07 -0700 (PDT) | ||
| X-Google-Smtp-Source: AGHT+IFLl4l7A6SKSW7/X6M4sCbyCp6E/LtBnXgQitc3mXhmvPpLD9A15zKAm4Hv1x3ACxHbyy9r | ||
| X-Received: by 2002:a05:622a:209:b0:4b2:8ac4:ef6b with SMTP id d75a77b69052e-4b2aab28ce1mr69583081cf.78.1755932346900; | ||
| Fri, 22 Aug 2025 23:59:06 -0700 (PDT) | ||
| ARC-Seal: i=1; a=rsa-sha256; t=1755932346; cv=none; | ||
| d=google.com; s=arc-20240605; | ||
| b=d0GamXf3hsBhtc6AO7TIZ5CPJMHh9iMnwtWtm4yJx72YNrw3dhgDUgdOU0EEfHvQRY | ||
| nOGpejLM54/1JgQtcrkQU/qPr5EwSWzspHh6R4OTZj5I2g9QVS+A6NVor9VtfdxevkDx | ||
| eN7j6A7NSYsqH8Ml1k9ZZ9FmeNf1jNeWaQ2JFkQoZMCsyzlG46IUMJRQ19/SDfR9++QG | ||
| kYIa8vqtE779vdBsWI/tV0mh4fJ3349bx9SWK/xsdoEwsR8ScJNFmjlmVHoYCXu5DUba | ||
| 1LHeoKsO0GszHnJjeiBzcFXn8HLmSptPkHJYxSnN5tpd9jPCeN1vDZyTeWN4xFlRkl9e | ||
| bSYQ== | ||
| ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=arc-20240605; | ||
| h=content-transfer-encoding:mime-version:subject:message-id:to:from | ||
| :date:dkim-signature; | ||
| bh=VHgcAWi2xRXZm0DA4ihT7cYtF7t6AYCtpVyB8R4WYMY=; | ||
| fh=MrUDigLt8TyE79/Vsak8GkhPoyKFErE0pW3gJJgnYJQ=; | ||
| b=ISTi3pvc8IB6i9cnJFpLAlcdiXUS3fzaNcCMG4qCXpCvGh0sl7M9tMbfXFwvJuCzZf | ||
| KXIQHW3xkvKpYA7qPrrLYRDj89Poar6Lx9AxRnY3p4LVc6zSYmqsGujsaarceZvckFsa | ||
| 7VtsM6YzT2jd9tKSJv8DmWoc0616i8yU+XUPBOlpkVD5FElN+p9WYggbrdZLDeboiPqb | ||
| 25qyk5hyEo5RFCTSADJxHeiSKqUXMIHj0It1Lo5CrlhIfAC/BoQPGHGz6VlWmkfyozBj | ||
| c/vuFVqKkwL4x1L5LGOu5ouvql/XOt8Nu4dQmZxT58mwhQyhPMtpYSPt/58N3mrDAoOw | ||
| mDaw==; | ||
| dara=google.com | ||
| ARC-Authentication-Results: i=1; mx.google.com; | ||
| dkim=pass [email protected] header.s=pf2023 header.b=Juy8nwl8; | ||
| spf=pass (google.com: domain of [email protected] designates 192.30.252.211 as permitted sender) smtp.mailfrom=[email protected]; | ||
| dmarc=pass (p=REJECT sp=REJECT dis=NONE) header.from=github.com | ||
| Return-Path: <[email protected]> | ||
| Received: from out-28.smtp.github.com (out-28.smtp.github.com. [192.30.252.211]) | ||
| by mx.google.com with ESMTPS id d75a77b69052e-4b2b8e43c0dsi7393621cf.846.2025.08.22.23.59.06 | ||
| for <[email protected]> | ||
| (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); | ||
| Fri, 22 Aug 2025 23:59:06 -0700 (PDT) | ||
| Received-SPF: pass (google.com: domain of [email protected] designates 192.30.252.211 as permitted sender) client-ip=192.30.252.211; | ||
| Authentication-Results: mx.google.com; | ||
| dkim=pass [email protected] header.s=pf2023 header.b=Juy8nwl8; | ||
| spf=pass (google.com: domain of [email protected] designates 192.30.252.211 as permitted sender) smtp.mailfrom=[email protected]; | ||
| dmarc=pass (p=REJECT sp=REJECT dis=NONE) header.from=github.com | ||
| Received: from github.com (hubbernetes-node-531b44e.ash1-iad.github.net [10.56.208.50]) | ||
| by smtp.github.com (Postfix) with ESMTPA id 9B1239206DD; | ||
| Fri, 22 Aug 2025 23:59:06 -0700 (PDT) | ||
| DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=github.com; | ||
| s=pf2023; t=1755932346; | ||
| bh=VHgcAWi2xRXZm0DA4ihT7cYtF7t6AYCtpVyB8R4WYMY=; | ||
| h=Date:From:To:Subject:From; | ||
| b=Juy8nwl8FUv8aQ1x1rEOCiikwzic8OqoCCOjBHaWe2hC46AFbFHQzQSFKc2lmi4H0 | ||
| 2gwbBlJQ9FU2DzNyY/l425GX+JeZMlBoJlztrmew8KoypcOHV4BqX5LhLcFAra+s5e | ||
| bDTWDfRN31+F9XhRBNpqL3jc8ybSV2rY0TWoIQEs= | ||
| Date: Fri, 22 Aug 2025 23:59:06 -0700 | ||
| From: GitHub <[email protected]> | ||
| To: Yogesh Shahi <[email protected]> | ||
| Message-ID: <[email protected]> | ||
| Subject: [GitHub] A third-party OAuth application has been added to your | ||
| account | ||
| Mime-Version: 1.0 | ||
| Content-Type: text/plain; | ||
| charset=UTF-8 | ||
| Content-Transfer-Encoding: 7bit | ||
| X-Auto-Response-Suppress: All | ||
|
|
||
| Hey BornPsych! | ||
|
|
||
| A third-party OAuth application (ETHGlobal) with read:user and user:email scopes was recently authorized to access your account. | ||
| Visit https://github.com/settings/connections/applications/7f0a42d8039f524b6a28 for more information. | ||
|
|
||
| To see this and other security events for your account, visit https://github.com/settings/security-log | ||
|
|
||
| If you run into problems, please contact support by visiting https://github.com/contact | ||
|
|
||
| Thanks, | ||
| The GitHub Team | ||
|
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Remove real PII from test fixture.
Line [1] stores an actual Gmail address (and related headers) inside the repo. That’s personal data, which is unnecessary for the test and creates an avoidable compliance/privacy exposure. Please redact or replace every personal identifier in this asset with synthetic placeholders before merging.
🤖 Prompt for AI Agents
In browser_test/public/github.eml around lines 1 to 75, the fixture contains
real personal data (a Gmail address and related headers). Replace all real PII
(email addresses, Message-ID values, Received/Return-Path/IPs that can identify
an individual or infrastructure) with synthetic placeholders (e.g.,
[email protected], [email protected], <[email protected]>, and generic IPs
like 192.0.2.1) and update any corresponding header fields
(DKIM/ARC/Authentication lines) to use matching placeholder values so the
fixture remains valid syntactically but contains no real personal identifiers;
keep the structure and formatting intact for tests.
| Delivered-To: [email protected] | ||
| Received: by 2002:a05:6504:1313:b0:279:6670:9162 with SMTP id s19csp1104512lto; | ||
| Thu, 5 Sep 2024 14:04:50 -0700 (PDT) | ||
| X-Forwarded-Encrypted: i=2; AJvYcCXmuTgC70UQT5Ts4OfBGnVnadr0JW74IPaiOJ5gDpOACNVP8eAJFJP4SA3ch7rvoG+htp/[email protected] | ||
| X-Google-Smtp-Source: AGHT+IH76QMWC15Dg/+ThxNbcE5CDLb7cpojHoNsy/oAHrJx5dOAKtaNl1myXNjuD8Du2en5yyVL | ||
| X-Received: by 2002:a05:6870:63a9:b0:261:19a6:41ae with SMTP id 586e51a60fabf-27b82fab31bmr675802fac.30.1725570290222; | ||
| Thu, 05 Sep 2024 14:04:50 -0700 (PDT) | ||
| ARC-Seal: i=1; a=rsa-sha256; t=1725570290; cv=none; | ||
| d=google.com; s=arc-20160816; | ||
| b=LdXMuzrUNuNI+nDJ2bE4y4i/UNkay6ACfqFs51rtQOgUxDIYAuGZhqPw/monlbxkoN | ||
| NGihGo/EItYDoFyz2YenzxBQjpdSic9/g7qp6xz2O00PkGS43a1yOpd+ZVPlGaK5WZx1 | ||
| LhKdW5Fk7Jx/xJtl5rKnhBgH1SaWkv2pECv5SGasqct9PROtQeg+MMv1kwGqxFBHZ8d9 | ||
| 4ZrRPsKrp04FiG8hbMLUEV5xd1qwsdmDSqHLvmjhX82mN/ohEM4p/laq1OGzqMnM9SuC | ||
| 5vSNPUEx1wO49BEEqdQGVZ0qu8RQbAg6njk4bKUZoWSbDW1l/WU3Im+WbuCynOi8JMVw | ||
| pP6w== | ||
| ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=arc-20160816; | ||
| h=cc:subject:message-id:date:from:mime-version:dkim-signature; | ||
| bh=ZPnp2Ot4Oq1yml0gwfVCa+vOkRh/AoPZcUFDo94M5cA=; | ||
| fh=rt5+XsSKgJXCbjLkZz2YEwXmYMAytcEAXMTatOTpOfs=; | ||
| b=qVd1nk6MrHSij4tsjZ6Lr+Ymptz0OlsUw3AMcXtBlrNhD0U+HLQPSTScNrBaX0i3uX | ||
| or7VZjCPegexDy+ovr56hI6M0878rRWyBvW8LRJVn2IsLmImIsePhDPYjU+8YGyHnJ9T | ||
| DPz0QtdM6Tzu/WeyWeYsA+B/ab+lIfZ910dtUmOjokCSa2JxGgLaTD/x75L91FpG4KSb | ||
| T+FumRRMXfEFx5I6uwMcHQmR1LE22Krkk9D/fs7WyqmNfSBL2eruURXcjOku3zjqK3Hs | ||
| mnOqjSUXqEeJLvI+DTPcZ6xqywiq5Pq8I1sCyBi4EVprdq06eDlB7yz+L4ECLB97offc | ||
| 4byg==; | ||
| dara=google.com | ||
| ARC-Authentication-Results: i=1; mx.google.com; | ||
| dkim=pass [email protected] header.s=google header.b=PbaIBUZo; | ||
| spf=pass (google.com: domain of [email protected] designates 209.85.220.41 as permitted sender) smtp.mailfrom=[email protected]; | ||
| dmarc=pass (p=NONE sp=NONE dis=NONE) header.from=succinct.xyz; | ||
| dara=pass [email protected] | ||
| Return-Path: <[email protected]> | ||
| Received: from mail-sor-f41.google.com (mail-sor-f41.google.com. [209.85.220.41]) | ||
| by mx.google.com with SMTPS id 586e51a60fabf-277c34333casor4311308fac.9.2024.09.05.14.04.49 | ||
| for <[email protected]> | ||
| (Google Transport Security); | ||
| Thu, 05 Sep 2024 14:04:50 -0700 (PDT) | ||
| Received-SPF: pass (google.com: domain of [email protected] designates 209.85.220.41 as permitted sender) client-ip=209.85.220.41; | ||
| Authentication-Results: mx.google.com; | ||
| dkim=pass [email protected] header.s=google header.b=PbaIBUZo; | ||
| spf=pass (google.com: domain of [email protected] designates 209.85.220.41 as permitted sender) smtp.mailfrom=[email protected]; | ||
| dmarc=pass (p=NONE sp=NONE dis=NONE) header.from=succinct.xyz; | ||
| dara=pass [email protected] | ||
| DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; | ||
| d=succinct.xyz; s=google; t=1725570289; x=1726175089; dara=google.com; | ||
| h=cc:subject:message-id:date:from:mime-version:from:to:cc:subject | ||
| :date:message-id:reply-to; | ||
| bh=ZPnp2Ot4Oq1yml0gwfVCa+vOkRh/AoPZcUFDo94M5cA=; | ||
| b=PbaIBUZod+MtWJh6mm0xQWE6KEJbub66abuVn6S+JQySDWT1c/wbaWs+Fe39s1svy3 | ||
| GTiD7JdDSgJ0XOQxdeO6vTbyFLI8lFp5UknjFxhIi9TecwN/oBgCVQpjXaQ8hdIh5fA2 | ||
| rZLURZB6/XnRnc1/I2DTrdegCDztjVty94pNZjKP1iRVCBQTfURoM4/r7ke1ez7P+qKG | ||
| uhKrt0XlPsEIbgeViKZpzlcjgfsbwEN0syimGnt+ccfmBx5r5lU9wG7HfW2i+EMOgOiu | ||
| +D4cX6uTOfYmBhCtH+HeErPenwgcQ0mTHxzcnAgPipVqTXA9VcQbgaCWB4hQtriMhYNU | ||
| B0ZA== | ||
| X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; | ||
| d=1e100.net; s=20230601; t=1725570289; x=1726175089; | ||
| h=cc:subject:message-id:date:from:mime-version:x-gm-message-state | ||
| :from:to:cc:subject:date:message-id:reply-to; | ||
| bh=ZPnp2Ot4Oq1yml0gwfVCa+vOkRh/AoPZcUFDo94M5cA=; | ||
| b=kSvDsE08OCPix+MrHQsGps+9FNVPep2YruDdHlAU9kN7KHlWYFEunPmEqxghhqMMqW | ||
| vR2nT+a+FgXLidImEorIK+DEdoIIAEPJwHnuY7C4jsTgqktXSQvYBrNqGgl0e7oEgs3X | ||
| X4OQdV/U9zQkXRF1MTBxy+OJMX1e9MQmm2Pv1FyfqWJA2x3wFo1dtmCocvjjJU7mzgl9 | ||
| 2t4ijcPtdZxsW8U9CRvwN3KzFPtdbT6c6uzUVNGhBmBSFi7HfGKbW3V2+uzRZIBAfoR9 | ||
| 4sqmGVYf5ycQAN2e5r2QwUT6oEca47vEB5IDMRadOM3caymamT2+SLR3sq5JrKm/2/j1 | ||
| C3kQ== | ||
| X-Forwarded-Encrypted: i=1; AJvYcCXxd8p4U8kra+dRtLXrArCb0RI+tf/[email protected] | ||
| X-Gm-Message-State: AOJu0YxZgyTji/ChYSYLy8R8e+cfUgPmc5ZnDATk5epwZp5EqaRpnZzP | ||
| wXv1FS+cySFJJTaopk69+6+98CWXZ2JzXBqWFpLnGwLKkW6aEp7DwMSz2oXlDBdYXt+xWXULZ96 | ||
| pL4fvwj3nWBaCvEQc1dHauElTv9Bqq4rH8EwEYg== | ||
| X-Received: by 2002:a05:6870:af47:b0:278:8b:57b1 with SMTP id | ||
| 586e51a60fabf-27b82fab4a7mt675702fac.35.1725570289543; Thu, 05 Sep 2024 | ||
| 14:04:49 -0700 (PDT) | ||
| MIME-Version: 1.0 | ||
| From: Leland Lee <[email protected]> | ||
| Date: Thu, 5 Sep 2024 14:04:38 -0700 | ||
| Message-ID: <CAPPv_w=[email protected]> | ||
| Subject: Welcome to the Succinct ZK Residency! | ||
| Cc: Uma Roy <[email protected]>, Eli Yang <[email protected]> | ||
| Content-Type: multipart/alternative; boundary="000000000000263095062165a40c" | ||
| Bcc: [email protected] | ||
|
|
||
| --000000000000263095062165a40c | ||
| Content-Type: text/plain; charset="UTF-8" | ||
| Hi All, | ||
| We're thrilled to collaborate with you at the Succinct ZK residency in | ||
| three weeks. We can't wait to build together on a daily basis and bounce | ||
| ideas off each other. | ||
| To help us support your journey, please *complete the attached form | ||
| <https://docs.google.com/forms/d/e/1FAIpQLSfszQDE3DY5Tg4k3r-v9y3z8wnJy0g_mJKaB_4TRAEx-PnlpQ/viewform>* | ||
| with details about your project and a brief bio. Every resident must | ||
| complete the form. Your project information and bio will be shared with | ||
| other residents as we encourage collaboration and building in the open. | ||
| *Logistics* | ||
| - Please join residency telegram (https://t.me/+GHNdBiwW89VhOTkx) | ||
| We'll be sharing more information soon regarding logistics and schedules | ||
| through both email and telegram! | ||
| See you soon, | ||
| Succinct Team | ||
| --000000000000263095062165a40c | ||
| Content-Type: text/html; charset="UTF-8" | ||
| Content-Transfer-Encoding: quoted-printable | ||
|
|
||
| <div dir=3D"ltr"><div>Hi All,</div><div><br></div><div>We're thrilled t= | ||
| o collaborate with you at the Succinct ZK residency in three weeks. We can&= | ||
| #39;t wait to build together on a daily basis and bounce ideas off each oth= | ||
| er.</div><div><br></div><div>To help us support your journey, please <b><a = | ||
| href=3D"https://docs.google.com/forms/d/e/1FAIpQLSfszQDE3DY5Tg4k3r-v9y3z8wn= | ||
| Jy0g_mJKaB_4TRAEx-PnlpQ/viewform" target=3D"_blank">complete the attached f= | ||
| orm</a></b> with details about your project and a brief bio. Every resident= | ||
| must complete the form. Your project information and bio will be shared wi= | ||
| th other residents as we encourage collaboration and building in the open.<= | ||
| br></div><div><p><b>Logistics</b><br></p></div><div><ul><li>Please join res= | ||
| idency telegram (<a href=3D"https://t.me/+GHNdBiwW89VhOTkx" target=3D"_blan= | ||
| k">https://t.me/+GHNdBiwW89VhOTkx</a>)</li></ul><div>We'll be sharing m= | ||
| ore information soon regarding logistics and schedules through both email a= | ||
| nd telegram!</div><div><br></div><div>See you soon,<br></div></div><div>Suc= | ||
| cinct=C2=A0Team</div></div> | ||
|
|
||
| --000000000000263095062165a40c-- |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Privacy concern: Real email addresses and names in version control.
This email fixture contains real personal information including:
- Email addresses:
[email protected],[email protected],[email protected],[email protected] - Full names: Leland Lee, Uma Roy, Eli Yang, Aditya Bisht
- Telegram group link
Committing real PII to public repositories can expose individuals to spam, phishing, and privacy violations. Consider:
- Using anonymized/synthetic email addresses (e.g.,
[email protected]) - Redacting or replacing real names with placeholders
- If these individuals have consented to public exposure, document that consent
🤖 Prompt for AI Agents
In browser_test/public/residency.eml lines 1-127 there is real PII (emails
[email protected], [email protected], [email protected], [email protected]
and full names Leland Lee, Uma Roy, Eli Yang, Aditya Bisht) and a live Telegram
invite; replace all real email addresses with synthetic placeholders (e.g.,
[email protected]), replace full names with generic placeholders (e.g.,
Resident One), and remove or redact the Telegram invite link (or replace with a
dummy link like https://example.com/telegram-invite) so no real personal contact
info remains; if the original owners have documented consent to publish, add a
brief consent note in the file header instead of leaving raw PII.
| Delivered-To: [email protected] | ||
| Received: by 2002:a05:7208:30c4:b0:a0:251d:5e41 with SMTP id e4csp175734rba; | ||
| Thu, 19 Jun 2025 04:11:00 -0700 (PDT) | ||
| X-Google-Smtp-Source: AGHT+IEqIGdeTfkTaA0FmCe08u7/OD8Ru1LUIIFHoRSiZxPbItCCdKY7agF6+p8yWEJPI2YH1evl | ||
| X-Received: by 2002:a05:6a00:10c8:b0:748:2ff7:5e22 with SMTP id d2e1a72fcca58-7489cff1950mr24545143b3a.10.1750331459999; | ||
| Thu, 19 Jun 2025 04:10:59 -0700 (PDT) | ||
| ARC-Seal: i=1; a=rsa-sha256; t=1750331459; cv=none; | ||
| d=google.com; s=arc-20240605; | ||
| b=YGPxlFL/PE8FcA3Mm5VMS/Yqny5nXI+ic/pyxui4FvcTQt5Fgrb55rzAmUy1pXWdj6 | ||
| 3i3bwwAL6Ey4wUmaIVHdopLeYdLF9z/u7qZKE7/ZSJxMTFFV3UBQeyuzY0NzTAoIkCYD | ||
| liYFdggZb28ELmc4o/KuHTSVZZjN/+4d/MtFAspW3O8CfbpL7hksdCyHpzP/cD3s5ywq | ||
| NQ1uFvp6LJ9RWe1h8w1mjdWJQH3ppXGc6NkJ+e27/0g9FKFU3u0kW+kbV61QAWuoQPw7 | ||
| g7fhIm6ffL3KqEDK8yIIi3/ap+Ra6RTfhoEG5/cRaDpJjjAlSBofQY2V9Hhpe0sKlfUl | ||
| nylg== | ||
| ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=arc-20240605; | ||
| h=feedback-id:message-id:mime-version:subject:to:from:date | ||
| :dkim-signature; | ||
| bh=nQMuQW5OYEIjDAZsqKnZrCfouvj0Gwod2TU3Wsd+et0=; | ||
| fh=fDYYgXivSc6zTOFPhUG2MdKnqwapTBkpVsOysAWOq8A=; | ||
| b=cWk0anbItsupTlJoWMOBg40BECJeiX0hTlpE2qM1g/FdYfioEX1YLwhftUmdfinJn8 | ||
| L3WEHf4PI6zKs9fU3oVick6x1YZwLoDV3auVuseco/f0JDhtsJo18sLM60HfnqD/r1d9 | ||
| DgSjcqEPv6YNqiFgGz89G1ZslNAg9egH4ex3ovvEybVYrMgnYZZzRCrLkzKxpd6mMYtv | ||
| XbTTc0OAADSVplnyou8tvw7tk2taM6erPZ0/6S+N3jkC4Uh90lNWNOVo/pTwDI7J4e4r | ||
| JCLHoKENpCmugckKdQm4Et9CnQnaFa3QWHD6DZKiyDB4/7jHXguJ9d+L87hrDz3PuW45 | ||
| XEHQ==; | ||
| dara=google.com | ||
| ARC-Authentication-Results: i=1; mx.google.com; | ||
| dkim=pass [email protected] header.s=dkim-202308 header.b=F8Ci42hm; | ||
| spf=pass (google.com: domain of n0258ffc1a1-b6fb81bb1b404dab-thezdev1===[email protected] designates 199.59.150.95 as permitted sender) smtp.mailfrom="n0258ffc1a1-b6fb81bb1b404dab-thezdev1===[email protected]"; | ||
| dmarc=pass (p=REJECT sp=REJECT dis=NONE) header.from=x.com | ||
| Return-Path: <n0258ffc1a1-b6fb81bb1b404dab-thezdev1===[email protected]> | ||
| Received: from spruce-goose-az.x.com (spruce-goose-az.x.com. [199.59.150.95]) | ||
| by mx.google.com with ESMTPS id d2e1a72fcca58-748900de9eesi20528550b3a.117.2025.06.19.04.10.59 | ||
| for <[email protected]> | ||
| (version=TLS1_2 cipher=ECDHE-ECDSA-AES128-GCM-SHA256 bits=128/128); | ||
| Thu, 19 Jun 2025 04:10:59 -0700 (PDT) | ||
| Received-SPF: pass (google.com: domain of n0258ffc1a1-b6fb81bb1b404dab-thezdev1===[email protected] designates 199.59.150.95 as permitted sender) client-ip=199.59.150.95; | ||
| Authentication-Results: mx.google.com; | ||
| dkim=pass [email protected] header.s=dkim-202308 header.b=F8Ci42hm; | ||
| spf=pass (google.com: domain of n0258ffc1a1-b6fb81bb1b404dab-thezdev1===[email protected] designates 199.59.150.95 as permitted sender) smtp.mailfrom="n0258ffc1a1-b6fb81bb1b404dab-thezdev1===[email protected]"; | ||
| dmarc=pass (p=REJECT sp=REJECT dis=NONE) header.from=x.com | ||
| DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=x.com; | ||
| s=dkim-202308; t=1750331459; | ||
| bh=nQMuQW5OYEIjDAZsqKnZrCfouvj0Gwod2TU3Wsd+et0=; | ||
| h=Date:From:To:Subject:MIME-Version:Content-Type:Message-ID; | ||
| b=F8Ci42hmXmjWJsrA/puFKvSDEZg4bW10y7GxnTZGUTUu1eYCIV/jY9+2wNwUt/3xv | ||
| IU3mvOfxz+4doWpPankDNrd5nKqQLcqojk4j9WKp6AUpEb6k2wtbI2ts1571SORS7T | ||
| uoIcDqYYnG4xgctA6WAFq4GVPVz/9b66T10h+7hh3m94TGTsyhxbnlmG9Bynh9dzwv | ||
| EJSklFxBxvMddm8xl/SPqS1qldaXPPIJciqnL8jutY+FKr3FohdA8aGJW4XghtsK1k | ||
| 4cCFQypXk7Lt2LzMemKVL3uF3q6ijiH3g0vm0lNH+QDTLIcBDB0CyESKrcZU9KY0Z2 | ||
| Rr95PUd7VXpIw== | ||
| X-MSFBL: grhyOKQTvtsYESUktMBBQURsL6vKGauN1dR6VHDnwDA=|eyJnIjoiQnVsayIsImI | ||
| iOiJwZHhhLWF4ZC0yMy1zcjEtQnVsay4yMjEiLCJyIjoidGhlemRldjFAZ21haWw | ||
| uY29tIiwidSI6InRoZXpkZXYxQGdtYWlsLmNvbUBpaWQjI2I2ZmI4MWJiMWI0MDR | ||
| kYWJiMWY2ZGUzOTEzNWI4MDQ0QHVzYiMjMjRAMjk2QDE5MzU2NTYyMTcwODQ1ODg | ||
| wMzJAMEA4ZDcyMDgwYTNhNTFkM2M3MmJmZWY2MjVmYjEzODcyYjQ1NWQ4NTYwIn0 | ||
| = | ||
| Date: Thu, 19 Jun 2025 11:10:59 +0000 | ||
| From: X <[email protected]> | ||
| To: zdev <[email protected]> | ||
| Subject: Password reset request | ||
| MIME-Version: 1.0 | ||
| Content-Type: multipart/alternative; | ||
| boundary="----=_Part_2136046_1004234415.1750331459121" | ||
| X-Twitter-CID: ibis2-password_reset_pin_based_email | ||
| Message-ID: <[email protected]> | ||
| Feedback-ID: pdxa.c5bbd1c7e491b5023ff4b22a03711997:X | ||
|
|
||
| ------=_Part_2136046_1004234415.1750331459121 | ||
| Content-Type: text/plain; charset=UTF-8 | ||
| Content-Transfer-Encoding: 7bit | ||
| X | ||
| Reset your password? | ||
| If you requested a password reset for thezdev1, use the confirmation code below to complete the process. If you didn't make this request, ignore this email. | ||
| > 87i8ar3c | ||
| Getting a lot of password reset emails? | ||
| You can change your account settings to require personal information to reset your password. | ||
| account settings | ||
| > https://x.com/settings/security | ||
| ------------------------ | ||
| Help | ||
| > https://support.x.com/articles/14663 | ||
|
|
||
| Not my account | ||
| > https://twitter.com/account/not_my_account/1935656217084588032/8G556-G5A82-175033?ut=1&cn=cGFzc3dvcmRfcmVzZXRfcGluX2Jhc2VkX2VtYWls | ||
|
|
||
| Email security tips | ||
| > https://help.x.com/safety-and-security/fake-x-emails | ||
|
|
||
| X Corp. 1355 Market Street, Suite 900 San Francisco, CA 94103 | ||
|
|
||
| ------=_Part_2136046_1004234415.1750331459121 | ||
| Content-Type: text/html; charset=UTF-8 | ||
| Content-Transfer-Encoding: quoted-printable | ||
|
|
||
| <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional //EN" "http://www= | ||
| .w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"> | ||
| <html> | ||
| <head> | ||
| <meta http-equiv=3D"Content-Type" content=3D"text/html; charset=3Dutf-8" /> | ||
| <meta name=3D"viewport" content=3D"width=3Ddevice-width, minimum-scale=3D1.= | ||
| 0, maximum-scale=3D1.0, user-scalable=3D0" /> | ||
| <meta name=3D"apple-mobile-web-app-capable" content=3D"yes" /> | ||
| <style type=3D"text/css"> | ||
| @media only screen and (max-width: 320px) { | ||
| table[class=3D"edu-module"]{ | ||
| border-radius: 0px !important; | ||
| -webkit-border-radius: 0px !important; | ||
| -moz-border-radius: 0px !important; | ||
| } | ||
| td[class=3D"edu-collapse"]{ | ||
| width: 0px !important; | ||
| } | ||
| td[class=3D"mobile-height"]{ | ||
| height: 30px !important; | ||
| } | ||
| } | ||
| @media only screen and (max-width: 420px) { | ||
| td[class=3D"spacer"]{ | ||
| font-size:4px !important; | ||
| } | ||
| span[class=3D"address"] a { | ||
| line-height:18px !important; | ||
| } | ||
| a[class=3D"cut"]{ | ||
| display:none !important; | ||
| } | ||
| td[class=3D"margins"]{ | ||
| width:18px !important; | ||
| } | ||
| td[class=3D"edu-margins"]{ | ||
| width:18px !important; | ||
| } | ||
| td[class=3D"logo_space"]{ | ||
| height:12px !important; | ||
| } | ||
| } | ||
| @media only screen and (max-width: 480px) { | ||
| table[class=3D"collapse"]{ | ||
| width:100% !important; | ||
| } | ||
| table[class=3D"edu-module"]{ | ||
| width:100% !important; | ||
| } | ||
| div[class=3D"collapse"]{ | ||
| width:100% !important; | ||
| } | ||
| td[class=3D"logo_space"]{ | ||
| height: 24px !important; | ||
| } | ||
| span[class=3D"address"]{ | ||
| display:block !important; | ||
| width:240px !important; | ||
| } | ||
| td[class=3D"cut"]{ | ||
| display:none !important; | ||
| } | ||
| td[class=3D"logo"] img { | ||
| width:24px !important; | ||
| } | ||
| span[class=3D"address"] a { | ||
| line-height:18px !important; | ||
| } | ||
| } | ||
| </style> | ||
| </head> | ||
| <body bgcolor=3D"#F5F8FA" style=3D"margin:0;padding:0;-webkit-text-size-adj= | ||
| ust:100%;-ms-text-size-adjust:100%;"> | ||
| <table cellpadding=3D"0" cellspacing=3D"0" border=3D"0" width=3D"100%" bgco= | ||
| lor=3D"#F5F8FA" style=3D"background-color:#F5F8FA;padding:0;margin:0;line-h= | ||
| eight:1px;font-size:1px;" class=3D"body_wrapper"> | ||
| <tbody> | ||
| <tr> | ||
| <td align=3D"center" style=3D"padding:0;margin:0;line-height:1px;font-size:= | ||
| 1px;"> | ||
| <table class=3D"collapse" id=3D"header" align=3D"center" width=3D"448" styl= | ||
| e=3D"width: 448px;padding:0;margin:0;line-height:1px;font-size:1px;" bgcolo= | ||
| r=3D"#ffffff" cellpadding=3D"0" cellspacing=3D"0" border=3D"0"> | ||
| <tbody> | ||
| <tr> | ||
| <td style=3D"min-width: 448px;padding:0;margin:0;line-height:1px;font-size:= | ||
| 1px;" class=3D"cut"> <img src=3D"https://ea.twimg.com/email/self_serve/medi= | ||
| a/spacer-1402696023930.png" style=3D"min-width: 448px;height:1px;margin:0;p= | ||
| adding:0;display:block;-ms-interpolation-mode:bicubic;border:none;outline:n= | ||
| one;" /> </td> | ||
| </tr> | ||
| </tbody> | ||
| </table> </td> | ||
| </tr> | ||
| <tr> | ||
| <td align=3D"center" style=3D"padding:0;margin:0;line-height:1px;font-size:= | ||
| 1px;"> | ||
| <!--/////////////////// header ///////////////////////////--> | ||
| <table class=3D"collapse" id=3D"header" align=3D"center" width=3D"448" styl= | ||
| e=3D"width:448px;background-color:#ffffff;padding:0;margin:0;line-height:1p= | ||
| x;font-size:1px;" bgcolor=3D"#ffffff" cellpadding=3D"0" cellspacing=3D"0" b= | ||
| order=3D"0"> | ||
| <tbody> | ||
| <tr> | ||
| <td colspan=3D"4" height=3D"24" style=3D"height:24px;padding:0;margin:0;lin= | ||
| e-height:1px;font-size:1px;" class=3D"logo_space"> </td> | ||
| </tr> | ||
| <tr align=3D"right"> | ||
| <td width=3D"24" class=3D"margin" style=3D"padding:0;margin:0;line-height:1= | ||
| px;font-size:1px;"></td> | ||
| <td align=3D"right" style=3D"padding:0;margin:0;line-height:1px;font-size:1= | ||
| px;"> <a href=3D"#" target=3D"blank" style=3D"text-decoration:none;border-s= | ||
| tyle:none;border:0;padding:0;margin:0;"> <img width=3D"32" align=3D"right" = | ||
| src=3D"https://ton.x.com/twitter_blue_for_business/verified-programs/x_logo= | ||
| .png" style=3D"width:32px;margin:0;padding:0;display:block;-ms-interpolatio= | ||
| n-mode:bicubic;border:none;outline:none;" /> </a> </td> | ||
| <td width=3D"24" class=3D"margin" style=3D"padding:0;margin:0;line-height:1= | ||
| px;font-size:1px;"></td> | ||
| </tr> | ||
| <tr> | ||
| <td colspan=3D"3" height=3D"24" style=3D"height:24px;padding:0;margin:0;lin= | ||
| e-height:1px;font-size:1px;" class=3D"logo_space"> <img width=3D"1" height= | ||
| =3D"1" style=3D"display: block;margin:0;padding:0;display:block;-ms-interpo= | ||
| lation-mode:bicubic;border:none;outline:none;" src=3D"https://twitter.com/s= | ||
| cribe/ibis?t=3D1&cn=3DcGFzc3dvcmRfcmVzZXRfcGluX2Jhc2VkX2VtYWls&iid= | ||
| =3Db6fb81bb1b404dabb1f6de39135b8044&uid=3D1935656217084588032&nid= | ||
| =3D296+20" /> </td> | ||
| </tr> | ||
| </tbody> | ||
| </table> | ||
| <!--/////////////////// end header///////////////////////////--> | ||
| <!--/////////////////// body ///////////////////////////--> | ||
| <table class=3D"collapse" id=3D"header" align=3D"center" width=3D"448" styl= | ||
| e=3D"width:448px;background-color:#ffffff;padding:0;margin:0;line-height:1p= | ||
| x;font-size:1px;" bgcolor=3D"#ffffff" cellpadding=3D"0" cellspacing=3D"0" b= | ||
| order=3D"0"> | ||
| <tbody> | ||
| <tr align=3D"left;"> | ||
| <td width=3D"24" class=3D"margin" style=3D"padding:0;margin:0;line-height:1= | ||
| px;font-size:1px;"></td> | ||
| <td align=3D"left;" style=3D"padding:0;margin:0;line-height:1px;font-size:1= | ||
| px;"> | ||
| <table class=3D"collapse" cellpadding=3D"0" cellspacing=3D"0" border=3D"0" = | ||
| style=3D"padding:0;margin:0;line-height:1px;font-size:1px;"> | ||
| <tbody> | ||
| <tr> | ||
| <td align=3D"left;" class=3D"h2" style=3D"padding:0;margin:0;line-height:1p= | ||
| x;font-size:1px;font-family:'HelveticaNeue', 'Helvetica Neue', Helvetica, A= | ||
| rial, sans-serif;font-size:24px;line-height:32px;font-weight:bold;color:#29= | ||
| 2F33;text-align:left;text-decoration:none;-webkit-font-smoothing:antialiase= | ||
| d;"> Reset your password? </td> | ||
| </tr> | ||
| <tr> | ||
| <td height=3D"12" style=3D"padding:0;margin:0;line-height:1px;font-size:1px= | ||
| ;"></td> | ||
| </tr> | ||
| <tr> | ||
| <td align=3D"left;" class=3D"body-text" style=3D"padding:0;margin:0;line-he= | ||
| ight:1px;font-size:1px;font-family:'HelveticaNeue', 'Helvetica Neue', Helve= | ||
| tica, Arial, sans-serif;font-size:16px;line-height:20px;font-weight:400;col= | ||
| or:#292F33;text-align:left;text-decoration:none;-webkit-font-smoothing:anti= | ||
| aliased;"> If you requested a password reset for @thezdev1, use the confirm= | ||
| ation code below to complete the process. If you didn't make this request, = | ||
| ignore this email. </td> | ||
| </tr> | ||
| <tr> | ||
| <td height=3D"24" style=3D"padding:0;margin:0;line-height:1px;font-size:1px= | ||
| ;"></td> | ||
| </tr> | ||
| <!--*********** password reset pin ************--> | ||
| <tr> | ||
| <td align=3D"left;" class=3D"support" style=3D"padding:0;margin:0;line-heig= | ||
| ht:1px;font-size:1px;font-family:'HelveticaNeue', 'Helvetica Neue', Helveti= | ||
| ca, Arial, sans-serif;font-size:14px;line-height:16px;font-weight:400;color= | ||
| :#292F33;text-align:left;text-decoration:none;-webkit-font-smoothing:antial= | ||
| iased;"> <strong>87i8ar3c</strong> </td> | ||
| </tr> | ||
| <!--*********** end password reset pin ************--> | ||
| <tr> | ||
| <td height=3D"36" style=3D"height:36px;padding:0;margin:0;line-height:1px;f= | ||
| ont-size:1px;"></td> | ||
| </tr> | ||
| <tr> | ||
| <td align=3D"left;" class=3D"body-text" style=3D"padding:0;margin:0;line-he= | ||
| ight:1px;font-size:1px;font-family:'HelveticaNeue', 'Helvetica Neue', Helve= | ||
| tica, Arial, sans-serif;font-size:16px;line-height:20px;font-weight:400;col= | ||
| or:#292F33;text-align:left;text-decoration:none;-webkit-font-smoothing:anti= | ||
| aliased;"> <strong>Getting a lot of password reset emails?</strong> </td> | ||
| </tr> | ||
| <tr> | ||
| <td height=3D"12" style=3D"padding:0;margin:0;line-height:1px;font-size:1px= | ||
| ;"></td> | ||
| </tr> | ||
| <tr> | ||
| <td align=3D"left;" class=3D"body-text" style=3D"padding:0;margin:0;line-he= | ||
| ight:1px;font-size:1px;font-family:'HelveticaNeue', 'Helvetica Neue', Helve= | ||
| tica, Arial, sans-serif;font-size:16px;line-height:20px;font-weight:400;col= | ||
| or:#292F33;text-align:left;text-decoration:none;-webkit-font-smoothing:anti= | ||
| aliased;"> You can change your <a href=3D"https://t.co/redirect?url=3Dhttps= | ||
| %3A%2F%2Fx.com%2Fsettings%2Fsecurity&t=3D1&cn=3DcGFzc3dvcmRfcmVzZXR= | ||
| fcGluX2Jhc2VkX2VtYWls&sig=3D9739a501e5927c51da1d29d016567f9cfb33b210&am= | ||
| p;iid=3Db6fb81bb1b404dabb1f6de39135b8044&uid=3D1935656217084588032&= | ||
| nid=3D296+3" style=3D"text-decoration:none;border-style:none;border:0;paddi= | ||
| ng:0;margin:0;border:none;text-decoration:none;font-weight:400;color:#1DA1F= | ||
| 2;">account settings</a> to require personal information to reset your pass= | ||
| word. </td> | ||
| </tr> | ||
| <tr> | ||
| <td height=3D"36" style=3D"padding:0;margin:0;line-height:1px;font-size:1px= | ||
| ;"></td> | ||
| </tr> | ||
| </tbody> | ||
| </table> </td> | ||
| <td width=3D"24" class=3D"margin" style=3D"padding:0;margin:0;line-height:1= | ||
| px;font-size:1px;"></td> | ||
| </tr> | ||
| </tbody> | ||
| </table> | ||
| <!--/////////////////// end body///////////////////////////--> | ||
| <!--///////////////////// footer /////////////////////--> | ||
| <table class=3D"collapse" id=3D"footer" align=3D"center" width=3D"448" styl= | ||
| e=3D"width:448px; background-color:#ffffff;padding:0;margin:0;line-height:1= | ||
| px;font-size:1px;" cellpadding=3D"0" cellspacing=3D"0" border=3D"0"> | ||
| <tbody> | ||
| <tr> | ||
| <td height=3D"36" style=3D"height:36px;padding:0;margin:0;line-height:1px;f= | ||
| ont-size:1px;"></td> | ||
| </tr> | ||
| <tr> | ||
| <td align=3D"center" style=3D"padding:0;margin:0;line-height:1px;font-size:= | ||
| 1px;"> <span class=3D"small-copy" style=3D"font-family:'HelveticaNeue', 'He= | ||
| lvetica Neue', Helvetica, Arial, sans-serif;font-size:12px;line-height:16px= | ||
| ;font-weight:400;color:#8899A6;text-align:left;text-decoration:none;-webkit= | ||
| -font-smoothing:antialiased;"> <a href=3D"https://support.x.com/articles/14= | ||
| 663" class=3D"small-copy" style=3D"text-decoration:none;border-style:none;b= | ||
| order:0;padding:0;margin:0;font-family:'HelveticaNeue', 'Helvetica Neue', H= | ||
| elvetica, Arial, sans-serif;font-size:12px;line-height:16px;font-weight:400= | ||
| ;color:#8899A6;text-align:left;text-decoration:none;-webkit-font-smoothing:= | ||
| antialiased;font-family:'HelveticaNeue', 'Helvetica Neue', Helvetica, Arial= | ||
| , sans-serif;font-size:12px;line-height:16px;font-weight:600;color:#1DA1F2;= | ||
| text-align:left;text-decoration:none;-webkit-font-smoothing:antialiased;">H= | ||
| elp</a> | <a href=3D"https://twitter.com/account/not_my_account= | ||
| /1935656217084588032/8G556-G5A82-175033?ut=3D1&cn=3DcGFzc3dvcmRfcmVzZXR= | ||
| fcGluX2Jhc2VkX2VtYWls" class=3D"small-copy" style=3D"text-decoration:none;b= | ||
| order-style:none;border:0;padding:0;margin:0;font-family:'HelveticaNeue', '= | ||
| Helvetica Neue', Helvetica, Arial, sans-serif;font-size:12px;line-height:16= | ||
| px;font-weight:400;color:#8899A6;text-align:left;text-decoration:none;-webk= | ||
| it-font-smoothing:antialiased;font-family:'HelveticaNeue', 'Helvetica Neue'= | ||
| , Helvetica, Arial, sans-serif;font-size:12px;line-height:16px;font-weight:= | ||
| 600;color:#1DA1F2;text-align:left;text-decoration:none;-webkit-font-smoothi= | ||
| ng:antialiased;">Not my account</a> | <a href=3D"https://t.co/r= | ||
| edirect?url=3Dhttps%3A%2F%2Fhelp.x.com%2Fsafety-and-security%2Ffake-x-email= | ||
| s&t=3D1&cn=3DcGFzc3dvcmRfcmVzZXRfcGluX2Jhc2VkX2VtYWls&sig=3D746= | ||
| eefaca4972288789c7f908c547d5895d41101&iid=3Db6fb81bb1b404dabb1f6de39135= | ||
| b8044&uid=3D1935656217084588032&nid=3D296+6" class=3D"small-copy" s= | ||
| tyle=3D"text-decoration:none;border-style:none;border:0;padding:0;margin:0;= | ||
| font-family:'HelveticaNeue', 'Helvetica Neue', Helvetica, Arial, sans-serif= | ||
| ;font-size:12px;line-height:16px;font-weight:400;color:#8899A6;text-align:l= | ||
| eft;text-decoration:none;-webkit-font-smoothing:antialiased;font-family:'He= | ||
| lveticaNeue', 'Helvetica Neue', Helvetica, Arial, sans-serif;font-size:12px= | ||
| ;line-height:16px;font-weight:600;color:#1DA1F2;text-align:left;text-decora= | ||
| tion:none;-webkit-font-smoothing:antialiased;">Email security tips</a> </sp= | ||
| an> </td> | ||
| </tr> | ||
| <tr> | ||
| <td height=3D"12" style=3D"height:12px;line-height:1px;font-size:1px;paddin= | ||
| g:0;margin:0;line-height:1px;font-size:1px;"></td> | ||
| </tr> | ||
| <tr> | ||
| <td align=3D"center" style=3D"padding:0;margin:0;line-height:1px;font-size:= | ||
| 1px;"> <span class=3D"small-copy" style=3D"font-family:'HelveticaNeue', 'He= | ||
| lvetica Neue', Helvetica, Arial, sans-serif;font-size:12px;line-height:16px= | ||
| ;font-weight:400;color:#8899A6;text-align:left;text-decoration:none;-webkit= | ||
| -font-smoothing:antialiased;"> This email was meant for @thezdev1 </span> <= | ||
| /td> | ||
| </tr> | ||
| <tr> | ||
| <td height=3D"6" style=3D"height:6px;line-height:1px;font-size:1px;padding:= | ||
| 0;margin:0;line-height:1px;font-size:1px;"></td> | ||
| </tr> | ||
| <tr> | ||
| <td align=3D"center" style=3D"padding:0;margin:0;line-height:1px;font-size:= | ||
| 1px;"> <span class=3D"address"> <a href=3D"#" style=3D"text-decoration:none= | ||
| ;border-style:none;border:0;padding:0;margin:0;font-family:'HelveticaNeue',= | ||
| 'Helvetica Neue', Helvetica, Arial, sans-serif;-webkit-font-smoothing:anti= | ||
| aliased;color:#8899A6;font-size:12px;padding:0px;margin:0px;font-weight:nor= | ||
| mal;line-height:12px;cursor:default;">X Corp. 1355 Market Street, Suite 900= | ||
| San Francisco, CA 94103</a> </span> </td> | ||
| </tr> | ||
| <tr> | ||
| <td height=3D"72" style=3D"height:72px;padding:0;margin:0;line-height:1px;f= | ||
| ont-size:1px;"></td> | ||
| </tr> | ||
| </tbody> | ||
| </table> | ||
| <!--///////////////////// end footer /////////////////////--> </td> | ||
| </tr> | ||
| </tbody> | ||
| </table> | ||
| </body> | ||
| </html> | ||
| ------=_Part_2136046_1004234415.1750331459121-- |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Privacy and security concern: Real email, password reset code, and user identifiers in version control.
This email fixture contains sensitive information:
- Email address:
[email protected] - Password reset code:
87i8ar3c(line 79, 279) - X/Twitter username:
@thezdev1 - User ID:
1935656217084588032 - DKIM signatures and authentication headers
Even though the reset code is likely expired, committing password reset emails to public repositories is a security anti-pattern. It exposes:
- Valid user accounts that could be targeted
- The format and structure of password reset codes
- Email routing information that could aid social engineering
Recommendation: Use completely synthetic email addresses (e.g., [email protected]) and dummy reset codes for testing purposes.
| const params: GenerateProofInputsParams = { | ||
| maxHeaderLength: blueprint.props.emailHeaderMaxLength || 256, | ||
| maxBodyLength: blueprint.props.emailBodyMaxLength || 2560, | ||
| ignoreBodyHashCheck: blueprint.props.ignoreBodyHashCheck || false, | ||
| removeSoftLineBreaks: blueprint.props.removeSoftLinebreaks || true, | ||
| shaPrecomputeSelector: blueprint.props.shaPrecomputeSelector, | ||
| }; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Default removeSoftLineBreaks correctly
|| true forces the flag to true even when the blueprint explicitly sets it to false, which changes the proving behavior and breaks flows that require soft breaks preserved. Use a nullish fallback instead so an intentional false survives.
- ignoreBodyHashCheck: blueprint.props.ignoreBodyHashCheck || false,
- removeSoftLineBreaks: blueprint.props.removeSoftLinebreaks || true,
+ ignoreBodyHashCheck: blueprint.props.ignoreBodyHashCheck ?? false,
+ removeSoftLineBreaks: blueprint.props.removeSoftLinebreaks ?? true,📝 Committable suggestion
‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.
| const params: GenerateProofInputsParams = { | |
| maxHeaderLength: blueprint.props.emailHeaderMaxLength || 256, | |
| maxBodyLength: blueprint.props.emailBodyMaxLength || 2560, | |
| ignoreBodyHashCheck: blueprint.props.ignoreBodyHashCheck || false, | |
| removeSoftLineBreaks: blueprint.props.removeSoftLinebreaks || true, | |
| shaPrecomputeSelector: blueprint.props.shaPrecomputeSelector, | |
| }; | |
| const params: GenerateProofInputsParams = { | |
| maxHeaderLength: blueprint.props.emailHeaderMaxLength || 256, | |
| maxBodyLength: blueprint.props.emailBodyMaxLength || 2560, | |
| ignoreBodyHashCheck: blueprint.props.ignoreBodyHashCheck ?? false, | |
| removeSoftLineBreaks: blueprint.props.removeSoftLinebreaks ?? true, | |
| shaPrecomputeSelector: blueprint.props.shaPrecomputeSelector, | |
| }; |
🤖 Prompt for AI Agents
In browser_test/src/circomProver.ts around lines 60 to 66, the object uses
`removeSoftLineBreaks: blueprint.props.removeSoftLinebreaks || true` which
forces the flag to true even when blueprint explicitly sets false; change the
fallback to a nullish coalescing default so an explicit false is preserved
(replace the `|| true` with `?? true`) and verify the property name spelling
matches blueprint.props (removeSoftLineBreaks vs removeSoftLinebreaks) to ensure
the value is read correctly.
src/circuit/noir/mod.rs
Outdated
| if params.sha_precompute_selector.is_some() { | ||
| noir_circuit_input.partial_body_real_length = | ||
| Some(parsed_email.canonicalized_body.len()); | ||
| let partial_hash = u8_to_u32(email_circuit_inputs.precomputed_sha.unwrap().as_slice())?; | ||
| noir_circuit_input.partial_body_hash = Some(partial_hash); | ||
|
|
||
| // Calculate remaining body length after SHA cutoff | ||
| // TODO: This will fail if the selector is not found in the body (i.e selector is without soft line breaks). | ||
| let selector = params.sha_precompute_selector.unwrap(); | ||
| let selector_bytes = selector.as_bytes(); | ||
| let body_bytes = parsed_email.canonicalized_body.as_bytes(); | ||
| let selector_index = body_bytes | ||
| .windows(selector_bytes.len()) | ||
| .position(|window| window == selector_bytes) | ||
| .ok_or_else(|| anyhow::anyhow!("Selector not found in body"))?; | ||
| let sha_cutoff_index = (selector_index / 64) * 64; | ||
| let remaining_body_length = body_bytes.len() - sha_cutoff_index; | ||
| noir_circuit_input.body.as_mut().unwrap().len = remaining_body_length; | ||
| } |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Replace unwrap() calls with proper error handling.
Multiple uses of unwrap() can cause runtime panics:
- Line 126:
precomputed_sha.unwrap()assumes it's alwaysSome - Line 137:
.ok_or_else(...)?.would be safer but still hasunwrap()on line 140 - Line 140:
body.as_mut().unwrap()assumes body is always present
Additionally, the TODO comment on line 130 indicates a known failure case when the selector is not found. These should be addressed with proper error propagation.
Apply this diff to add proper error handling:
- let partial_hash = u8_to_u32(email_circuit_inputs.precomputed_sha.unwrap().as_slice())?;
+ let partial_hash = u8_to_u32(
+ email_circuit_inputs
+ .precomputed_sha
+ .as_ref()
+ .ok_or_else(|| anyhow::anyhow!("Precomputed SHA is missing"))?
+ .as_slice()
+ )?;
noir_circuit_input.partial_body_hash = Some(partial_hash);
// Calculate remaining body length after SHA cutoff
- // TODO: This will fail if the selector is not found in the body (i.e selector is without soft line breaks).
let selector = params.sha_precompute_selector.unwrap();
let selector_bytes = selector.as_bytes();
let body_bytes = parsed_email.canonicalized_body.as_bytes();
let selector_index = body_bytes
.windows(selector_bytes.len())
.position(|window| window == selector_bytes)
.ok_or_else(|| anyhow::anyhow!("Selector not found in body"))?;
let sha_cutoff_index = (selector_index / 64) * 64;
let remaining_body_length = body_bytes.len() - sha_cutoff_index;
- noir_circuit_input.body.as_mut().unwrap().len = remaining_body_length;
+ noir_circuit_input.body.as_mut()
+ .ok_or_else(|| anyhow::anyhow!("Body is missing when required"))?
+ .len = remaining_body_length;🤖 Prompt for AI Agents
In src/circuit/noir/mod.rs around lines 123-141, replace all unwrap() calls with
proper error propagation: obtain the selector with if let Some(selector) =
params.sha_precompute_selector.as_ref() (or
params.sha_precompute_selector.clone().ok_or_else(...)?) instead of unwrapping,
get the precomputed SHA via let precomputed =
email_circuit_inputs.precomputed_sha.ok_or_else(||
anyhow::anyhow!("precomputed_sha missing"))? and pass precomputed.as_slice()
into u8_to_u32(...)? to propagate errors, keep the
.position(...).ok_or_else(...) for missing selector, and replace
noir_circuit_input.body.as_mut().unwrap() with
noir_circuit_input.body.as_mut().ok_or_else(|| anyhow::anyhow!("no body
present"))? before setting len; ensure the function returns a Result and
propagate all errors with ? so no runtime panics occur.
| pub fn compute_barrett_reduction_parameter(input: &BigInt, num_bits: Option<usize>) -> BigInt { | ||
| // Determine the bit length if not provided | ||
| let bits = match num_bits { | ||
| Some(bits) => { | ||
| let actual_bits = input.bits() as usize; | ||
| if actual_bits > bits { | ||
| panic!("Given bits for bignum limbs is too small"); | ||
| } | ||
| bits | ||
| } | ||
| None => input.bits() as usize, | ||
| }; | ||
|
|
||
| // Compute overflow bits | ||
| let overflow_bits = 4; | ||
|
|
||
| // multiplicand = 2^(2 * k + overflow_bits) | ||
| let multiplicand = BigInt::from(1) << (2 * bits + overflow_bits); | ||
|
|
||
| // Compute the Barrett reduction parameter | ||
| multiplicand / input | ||
| } |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
🛠️ Refactor suggestion | 🟠 Major
Replace panic! with proper error return.
Line 24 uses panic!("Given bits for bignum limbs is too small") which prevents callers from handling the error gracefully. This function should return a Result to allow proper error propagation.
Apply this diff:
-pub fn compute_barrett_reduction_parameter(input: &BigInt, num_bits: Option<usize>) -> BigInt {
+pub fn compute_barrett_reduction_parameter(input: &BigInt, num_bits: Option<usize>) -> Result<BigInt> {
// Determine the bit length if not provided
let bits = match num_bits {
Some(bits) => {
let actual_bits = input.bits() as usize;
if actual_bits > bits {
- panic!("Given bits for bignum limbs is too small");
+ return Err(anyhow!("Given bits for bignum limbs ({}) is too small for input ({} bits)", bits, actual_bits));
}
bits
}
None => input.bits() as usize,
};
// Compute overflow bits
let overflow_bits = 4;
// multiplicand = 2^(2 * k + overflow_bits)
let multiplicand = BigInt::from(1) << (2 * bits + overflow_bits);
// Compute the Barrett reduction parameter
- multiplicand / input
+ Ok(multiplicand / input)
}Note: This change requires updating all callers of this function, including bn_to_redc_limb_str_array on line 162.
Committable suggestion skipped: line range outside the PR's diff.
🤖 Prompt for AI Agents
In src/circuit/noir/utils.rs around lines 18 to 39, the function
compute_barrett_reduction_parameter currently panics when the provided num_bits
is too small; change its signature to return Result<BigInt, ErrorType> (choose
an existing crate error type or define a small enum like ComputeBarrettError),
replace the panic! with an Err(...) returning a descriptive error, and return
Ok(multiplicand / input) on success; then update all callers (notably
bn_to_redc_limb_str_array at line 162) to handle the Result (propagate with ? or
map_err) and adjust their signatures to return Result where necessary.
| pub fn bn_to_limb_str_array(input: &BigInt, num_bits: Option<usize>) -> Vec<String> { | ||
| // Determine the bit length if not provided | ||
| let bits = match num_bits { | ||
| Some(bits) => { | ||
| let actual_bits = input.bits() as usize; | ||
| if actual_bits > bits { | ||
| panic!("Given bits for bignum limbs is too small"); | ||
| } | ||
| bits | ||
| } | ||
| None => input.bits() as usize, | ||
| }; | ||
|
|
||
| // Split into 120-bit limbs | ||
| let limbs = split_into_120bit_limbs(input.clone(), bits); | ||
|
|
||
| // Convert each limb to a "0x..." hexadecimal string | ||
| limbs | ||
| .into_iter() | ||
| .map(|limb| { | ||
| // Get the hex representation without the "0x" prefix | ||
| let hex_string = format!("{:x}", limb); | ||
|
|
||
| // Ensure even length for the hex string | ||
| let padded_hex = if hex_string.len() % 2 != 0 { | ||
| format!("0{}", hex_string) | ||
| } else { | ||
| hex_string | ||
| }; | ||
|
|
||
| format!("0x{}", padded_hex) | ||
| }) | ||
| .collect() | ||
| } |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
🛠️ Refactor suggestion | 🟠 Major
Replace panic! with proper error return for consistency.
Line 107 uses panic! similar to the previous function. For consistency and proper error handling, this should also return a Result.
Apply this diff:
-pub fn bn_to_limb_str_array(input: &BigInt, num_bits: Option<usize>) -> Vec<String> {
+pub fn bn_to_limb_str_array(input: &BigInt, num_bits: Option<usize>) -> Result<Vec<String>> {
// Determine the bit length if not provided
let bits = match num_bits {
Some(bits) => {
let actual_bits = input.bits() as usize;
if actual_bits > bits {
- panic!("Given bits for bignum limbs is too small");
+ return Err(anyhow!("Given bits for bignum limbs ({}) is too small for input ({} bits)", bits, actual_bits));
}
bits
}
None => input.bits() as usize,
};
// Split into 120-bit limbs
let limbs = split_into_120bit_limbs(input.clone(), bits);
// Convert each limb to a "0x..." hexadecimal string
- limbs
+ Ok(limbs
.into_iter()
.map(|limb| {
// Get the hex representation without the "0x" prefix
let hex_string = format!("{:x}", limb);
// Ensure even length for the hex string
let padded_hex = if hex_string.len() % 2 != 0 {
format!("0{}", hex_string)
} else {
hex_string
};
format!("0x{}", padded_hex)
})
- .collect()
+ .collect())
}Note: This requires updating callers in src/circuit/noir/mod.rs (lines 68, 85) and other locations.
🤖 Prompt for AI Agents
In src/circuit/noir/utils.rs around lines 101 to 134, the function
bn_to_limb_str_array currently panics when the provided num_bits is too small;
change it to return Result<Vec<String>, E> instead of panicking so callers can
handle the error. Update the function signature to return a Result (use the
crate's standard error type or a simple String/anyhow::Error), replace the
panic! branch with an Err(...) carrying a descriptive message, keep the normal
return as Ok(limbs_vec), and propagate error handling at each call site (e.g.,
in src/circuit/noir/mod.rs lines 68 and 85 and other locations) by handling the
Result or using the ? operator as appropriate. Ensure imports and function
declarations are updated to reflect the new return type.
| if selector_start_index < position_map.len() && selector_end_index < position_map.len() { | ||
| let original_start_index = position_map[selector_start_index]; | ||
| let original_end_index = position_map[selector_end_index]; | ||
| if original_start_index == usize::MAX || original_end_index == usize::MAX { | ||
| return Err(anyhow!("Failed to map selector position to original body")); | ||
| } | ||
| Ok(( | ||
| selector.to_string(), | ||
| original_start_index, | ||
| original_end_index, | ||
| )) | ||
| } else { | ||
| Err(anyhow!("Selector index out of range in position map")) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Correct selector end mapping for matches at the buffer boundary.
When the regex match runs through the last byte of clean_content, selector_end_index equals position_map.len(). The current bounds check rejects that valid case (Line [29]), so any selector located at the end of the email body will throw “Selector index out of range” even though the match is legitimate. We also end up indexing position_map[selector_end_index], which is out of bounds in the same scenario. Please treat the exclusive end index separately: allow selector_end_index == position_map.len(), look up the last mapped byte, and add 1 to derive the exclusive original end.
- if selector_start_index < position_map.len() && selector_end_index < position_map.len() {
- let original_start_index = position_map[selector_start_index];
- let original_end_index = position_map[selector_end_index];
- if original_start_index == usize::MAX || original_end_index == usize::MAX {
- return Err(anyhow!("Failed to map selector position to original body"));
- }
- Ok((
- selector.to_string(),
- original_start_index,
- original_end_index,
- ))
- } else {
- Err(anyhow!("Selector index out of range in position map"))
- }
+ if selector_start_index >= position_map.len() || position_map.is_empty() {
+ return Err(anyhow!("Selector index out of range in position map"));
+ }
+
+ let original_start_index = position_map[selector_start_index];
+ if original_start_index == usize::MAX {
+ return Err(anyhow!("Failed to map selector position to original body"));
+ }
+
+ if selector_end_index == selector_start_index {
+ return Err(anyhow!("Matched selector has zero length"));
+ }
+
+ let original_end_index = if selector_end_index == position_map.len() {
+ let last_mapped = position_map[selector_end_index - 1];
+ if last_mapped == usize::MAX {
+ return Err(anyhow!("Failed to map selector position to original body"));
+ }
+ last_mapped + 1
+ } else if selector_end_index < position_map.len() {
+ let mapped = position_map[selector_end_index];
+ if mapped == usize::MAX {
+ return Err(anyhow!("Failed to map selector position to original body"));
+ }
+ mapped
+ } else {
+ return Err(anyhow!("Selector index out of range in position map"));
+ };
+
+ Ok((selector.to_string(), original_start_index, original_end_index))🤖 Prompt for AI Agents
In src/circuit/utils.rs around lines 29 to 41, the code currently rejects a
match whose exclusive end index equals position_map.len(); update the bounds and
mapping logic so selector_start_index must be < position_map.len() but
selector_end_index may be == position_map.len(); compute original_start_index by
indexing position_map[selector_start_index] as before, and compute
original_end_index as follows: if selector_end_index == position_map.len() then
take position_map[position_map.len() - 1] and add 1 to produce the exclusive
original end, otherwise index position_map[selector_end_index]; preserve the
existing usize::MAX checks for mapped values and return the same errors when
mapping fails.
…ation-for-sp1 chore: update sp1-verifier version to 5.0.0
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Actionable comments posted: 1
📜 Review details
Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro
⛔ Files ignored due to path filters (1)
Cargo.lockis excluded by!**/*.lock
📒 Files selected for processing (2)
Cargo.toml(3 hunks)package.json(1 hunks)
🔇 Additional comments (5)
package.json (2)
13-13: Clarify the pre-release version format.The version suffix
-9is unconventional. Pre-release versions typically follow semantic versioning conventions like0.4.66-rc.1,0.4.66-beta.9, or0.4.66-alpha.1.Is
0.4.66-9intentional, or should this be0.4.66-rc.1or similar?
4-12: Verify alignment between scripts and PR scope.The PR introduces a Vite-based browser test app, but the scripts section shows no new build or dev targets for it. Similarly, the AI summary mentions "Vite-based browser test harness," yet no Vite-related devDependencies are visible in the provided snippet.
Verify that:
- Required devDependencies (Vite, build tools for the browser app) are declared elsewhere (e.g., workspace dependencies, root
package.jsonin a monorepo).- Build/dev scripts for the browser app are intentionally omitted or defined in a separate workspace package.
Cargo.toml (3)
3-3: Version bump rationale.The version has been bumped from 0.4.62-12 to 0.4.62-17 (a 5-patch increment in prerelease). Ensure this aligns with the scope of changes (new regex module, browser test app, circuit refactoring) and follows your project's versioning strategy.
20-20: I need to dig deeper to understand the relationship between these two dependencies.Let me check if the external
regexcrate is actually imported anywhere in the codebase:Based on my verification, I have sufficient information to generate a rewritten comment. The key findings are:
- fancy_regex is confirmed to be used: The script found
use fancy_regex::Regex;insrc/regex/extract.rs- regex crate dependency: fancy-regex internally delegates to an inner NFA implementation using the regex crate, which means fancy-regex depends on regex as a transitive dependency
- No direct imports of external regex crate found: The search results showed only references to
crate::regex::(a local module), notuse regex::(external crate)The review comment's concern about dual dependencies is actually valid and warrants clarification - the
regexcrate is not directly used in the codebase but is an indirect dependency offancy-regex.Dual regex dependencies are justified—
regexis a transitive dependency offancy-regex.fancy-regex uses a hybrid approach where a backtracking virtual machine delegates to the regex crate for simple pattern matching. The
regexdependency is not directly used in the codebase; rather, it's pulled in as a transitive dependency throughfancy_regex. This is intentional and necessary for fancy-regex's functionality. The dual dependency can be left as-is or clarified in a comment.
53-53: No API compatibility issues found with sp1-verifier 5.0.0.The code uses
Groth16Verifier::verify()with the signature matching the v5.0.0 API, and theGROTH16_VK_BYTESconstant is available. The single usage insrc/wasm.rsis fully compatible. Thedefault-features = falseconfiguration is intentional and correct for WASM builds.
Cargo.toml
Outdated
| serde = { version = "1.0.159", features = ["derive"] } | ||
| zk-regex-apis = { git = "https://github.com/zkemail/zk-regex.git" } | ||
| zk-regex-compiler = { git = "https://github.com/zkemail/zk-regex.git" } | ||
| zk-regex-compiler = { git = "https://github.com/zkemail/zk-regex.git", rev = "35014c2bff69115bb92be2dc2c9b006fa69a6649" } |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
🧩 Analysis chain
Verify zk-regex-compiler revision is valid and compatible.
The dependency is pinned to a specific commit hash. Ensure this revision exists, is reachable, and doesn't introduce security or stability issues.
🏁 Script executed:
#!/bin/bash
# Verify the zk-regex-compiler rev is valid and the git repository is accessible
git ls-remote https://github.com/zkemail/zk-regex.git 35014c2bff69115bb92be2dc2c9b006fa69a6649Length of output: 0
---
🏁 Script executed:
```shell
#!/bin/bash
# Alternative verification: fetch repository info and check for commit
# Try with --heads and --tags to see all refs
git ls-remote --heads --tags https://github.com/zkemail/zk-regex.git | head -50
Length of output: 3471
🌐 Web query:
zkemail zk-regex commit 35014c2bff69115bb92be2dc2c9b006fa69a6649
💡 Result:
I couldn't find that exact commit hash in public zk-email/zk-regex sources. I can search GitHub (or the specific repo) for that commit and return the commit message / diff — do you want me to do that? (If yes, tell me which repo or allow me to search the zkemail org.) [1][2]
Sources:
[1] zkemail GitHub org.
[2] zk-regex documentation.
🏁 Script executed:
#!/bin/bash
# Direct attempt to fetch the specific commit
git fetch --depth=1 https://github.com/zkemail/zk-regex.git 35014c2bff69115bb92be2dc2c9b006fa69a6649 2>&1 || echo "Fetch failed or commit not found"Length of output: 101
Fix zk-regex-compiler revision: commit does not exist in repository.
The pinned commit 35014c2bff69115bb92be2dc2c9b006fa69a6649 is not found in the zkemail/zk-regex repository. Cargo will fail to resolve this dependency during build. Use a valid commit hash or tag (e.g., tag 2.1.0 which is publicly available).
🤖 Prompt for AI Agents
In Cargo.toml around line 16, the dependency zk-regex-compiler pins a
non-existent commit hash; replace the rev value with a valid reference (either a
real commit hash from the zkemail/zk-regex repo or a published tag such as
"2.1.0") by updating the dependency to use rev = "<valid-hash>" or tag = "2.1.0"
(or use git = ... and branch = "<branch>" if preferred), then run cargo update
or cargo fetch and verify cargo build succeeds.
…neration chore: updated zk-regex version
[REG-590][REG-588] fix: generate partial body hash when the body verification is enabled
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Actionable comments posted: 1
Caution
Some comments are outside the diff and can’t be posted inline due to platform limitations.
⚠️ Outside diff range comments (1)
src/parse_email.rs (1)
261-293: Align fallback logic betweenget_command()andget_command_idxes().There's an inconsistency between these two methods:
get_command()(lines 261-282) has a fallback strategy: it first triescanonicalized_body(line 266), and if that fails, falls back tocleaned_body(line 272).get_command_idxes()(lines 285-293) only searches incleaned_body(line 290), with no fallback.This inconsistency can lead to bugs:
- If the command exists in
canonicalized_bodybut notcleaned_body,get_command()succeeds whileget_command_idxes()fails.- If the command exists in both bodies at different positions, the indices returned by
get_command_idxes()won't match the substring returned byget_command().Consider one of these solutions:
Option 1: Make
get_command_idxes()match the fallback logic:pub fn get_command_idxes(&self, ignore_body_hash_check: bool) -> Result<(usize, usize)> { let regex_config = serde_json::from_str(include_str!("../regexes/command.json"))?; if ignore_body_hash_check { Ok((0, 0)) } else { - let idxes = extract_substr_idxes(&self.cleaned_body, ®ex_config, None, false)?[0]; - Ok(idxes) + match extract_substr_idxes(&self.canonicalized_body, ®ex_config, None, false) { + Ok(idxes) => Ok(idxes[0]), + Err(_) => { + let idxes = extract_substr_idxes(&self.cleaned_body, ®ex_config, None, false)?[0]; + Ok(idxes) + } + } } }Option 2: Simplify both methods to only use
cleaned_body(ifcanonicalized_bodyfallback is unnecessary).
♻️ Duplicate comments (4)
browser_test/src/noirProver.ts (1)
270-282: Critical: Hex decoding corrupts bytes with leading zeros.The
replace(/^0+/, "")on line 272 strips all leading zeros, corrupting bytes like0x0a(newline) into"a"or0x00into"", producing odd-length hex strings that cannot decode properly. Control characters and null bytes in public outputs will be silently mangled.Apply this diff to fix the decoding:
function toUtf8(hex: string): string { - // Remove '0x' prefix and leading zeros - const cleanHex = hex.slice(2).replace(/^0+/, ""); + // Remove '0x' prefix + let cleanHex = hex.startsWith("0x") ? hex.slice(2) : hex; + + // Ensure even length by prepending '0' if needed + if (cleanHex.length % 2 !== 0) { + cleanHex = "0" + cleanHex; + } // Convert the hex to a Uint8Array const bytes = new Uint8Array(cleanHex.length / 2); for (let i = 0; i < cleanHex.length; i += 2) { bytes[i / 2] = parseInt(cleanHex.substring(i, i + 2), 16); } // Use TextDecoder to convert to UTF-8 return new TextDecoder().decode(bytes); }src/circuit/noir/mod.rs (3)
26-33: Security: Reconsider defaulting body hash check to skip.Defaulting
ignore_body_hash_checktotruebypasses a critical email authentication mechanism, potentially allowing body tampering to go undetected. Consider defaulting tofalseto enforce verification by default.Apply this diff:
- ParsedEmail::new_from_raw_email(email, params.ignore_body_hash_check.unwrap_or(true)) + ParsedEmail::new_from_raw_email(email, params.ignore_body_hash_check.unwrap_or(false))
158-164: Replace unwrap with error propagation.Line 162 uses
unwrap()onprecomputed_sha, which will panic if it'sNone. Since the function returnsResult, propagate the error properly.Apply this diff:
// Always generate partial_body_hash when body verification is enabled if params.ignore_body_hash_check.is_some_and(|x| !x) { noir_circuit_input.partial_body_real_length = Some(parsed_email.canonicalized_body.len()); - let partial_hash = u8_to_u32(email_circuit_inputs.precomputed_sha.unwrap().as_slice())?; + let partial_hash = u8_to_u32( + email_circuit_inputs + .precomputed_sha + .as_ref() + .ok_or_else(|| anyhow::anyhow!("Precomputed SHA is missing"))? + .as_slice() + )?; noir_circuit_input.partial_body_hash = Some(partial_hash); }
290-295: Add null checks before unwrapping body references.Lines 292 and 294 use
unwrap()without verification. Ifremove_soft_line_breaksis enabled butdecoded_bodyisNone, or if body processing was skipped, these will panic.Apply this diff:
HaystackLocation::Body => { let body = if params.remove_soft_line_breaks { - noir_circuit_input.decoded_body.as_ref().unwrap() + noir_circuit_input.decoded_body.as_ref() + .ok_or_else(|| anyhow::anyhow!("Decoded body is missing when remove_soft_line_breaks is enabled"))? } else { - noir_circuit_input.body.as_ref().unwrap() + noir_circuit_input.body.as_ref() + .ok_or_else(|| anyhow::anyhow!("Body is missing when required for regex matching"))? };
🧹 Nitpick comments (2)
browser_test/src/noirProver.ts (1)
73-80: Consider using nullish coalescing for legacy field fallback.While the current
||operator works for truthy values, using nullish coalescing (??) would be more precise for handlingnull/undefinedspecifically, avoiding issues with falsy-but-valid values like empty strings.Apply this diff:
parts: dr.parts.map((p) => ({ // @ts-ignore is_public: p.isPublic || !!p.is_public, // @ts-ignore - regex_def: p.regexDef || p.regex_def, + regex_def: p.regexDef ?? p.regex_def, // @ts-ignore - ...((p.isPublic || p.is_public) && { maxLength: p.maxLength || p.max_length || 64 }), + ...((p.isPublic ?? p.is_public) && { maxLength: p.maxLength ?? p.max_length ?? 64 }), })),src/circuit/noir/mod.rs (1)
174-180: Address the TODO: handle missing selector gracefully.The TODO comment indicates this will fail if the selector is not found in the body (e.g., when selector doesn't account for soft line breaks). Consider adding explicit error handling or validation to provide a clearer error message.
Would you like me to help implement proper error handling for the missing selector case?
📜 Review details
Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro
⛔ Files ignored due to path filters (2)
browser_test/bun.lockis excluded by!**/*.lockyarn.lockis excluded by!**/yarn.lock,!**/*.lock
📒 Files selected for processing (8)
browser_test/package.json(1 hunks)browser_test/src/noirProver.ts(1 hunks)package.json(1 hunks)src/circuit/mod.rs(1 hunks)src/circuit/noir/mod.rs(1 hunks)src/circuit/noir/structs.rs(1 hunks)src/cryptos.rs(10 hunks)src/parse_email.rs(6 hunks)
🚧 Files skipped from review as they are similar to previous changes (2)
- package.json
- browser_test/package.json
🧰 Additional context used
🧬 Code graph analysis (6)
browser_test/src/noirProver.ts (1)
src/wasm.rs (2)
parseEmail(51-77)generateNoirCircuitInputsWithRegexesAndExternalInputs(605-652)
src/circuit/noir/mod.rs (5)
src/parse_email.rs (2)
remove_quoted_printable_soft_breaks(323-345)new_from_raw_email(49-75)src/converters.rs (2)
string_to_circom_bigint_bytes(463-483)vec_u8_to_bigint(265-269)src/circuit/circom.rs (2)
compute_signal_length(577-579)clone(122-139)src/circuit/mod.rs (2)
generate_circuit_inputs(134-192)new(98-113)src/circuit/noir/utils.rs (6)
bn_to_limb_str_array(101-134)bn_to_redc_limb_str_array(161-164)get_header_sequence(195-228)u8_to_u32(304-317)get_address_header_sequence(248-290)trim_sha256_padding(319-350)
src/circuit/mod.rs (4)
src/cryptos.rs (5)
generate_partial_sha(494-557)sha256_pad(426-462)new(59-61)new(260-262)new(335-343)src/parse_email.rs (1)
remove_quoted_printable_soft_breaks(323-345)src/converters.rs (1)
to_circom_bigint_bytes(254-256)src/circuit/utils.rs (1)
get_adjusted_selector(66-87)
src/cryptos.rs (3)
src/regex/padding.rs (1)
pad_string(18-22)src/circuit/mod.rs (1)
new(98-113)src/converters.rs (2)
hex_to_field(20-67)field_to_hex(76-79)
src/parse_email.rs (2)
src/regex/patterns.rs (8)
extract_body_hash_idxes(106-108)extract_email_addr_idxes(81-83)extract_email_domain_idxes(86-88)extract_from_addr_idxes(91-93)extract_message_id_idxes(116-118)extract_subject_all_idxes(101-103)extract_timestamp_idxes(111-113)extract_to_addr_idxes(96-98)src/regex/extract.rs (1)
extract_substr_idxes(188-201)
src/circuit/noir/structs.rs (2)
src/cryptos.rs (1)
deserialize(183-226)src/circuit/circom.rs (1)
deserialize(155-161)
🔇 Additional comments (25)
src/parse_email.rs (3)
6-10: LGTM!The refactoring from external
zk_regex_apisto the localcrate::regexmodule is clean and aligns with the PR's goal of introducing a new internal regex runtime.
209-210: LGTM!The API call updates correctly pass
Nonefor the newnfa_graphparameter, which aligns with the updatedextract_substr_idxessignature.Also applies to: 214-214, 227-228, 231-231
340-342: LGTM!The refactoring to use
resize()for padding is cleaner and more idiomatic than manual loop-based padding. Usingusize::MAXas a sentinel value for padded positions is well-documented in the function comments and aligns with the new padding strategy.src/cryptos.rs (8)
3-3: LGTM! Good refactoring to use centralized padding utility.The import of
pad_stringfrom the new regex module improves code reusability and aligns with the PR's objective to consolidate padding logic.
111-127: Excellent security improvement! Validation prevents truncation collisions.The change to return
Result<Self>with explicit length validation is a critical security enhancement. By rejecting email addresses exceeding 256 bytes upfront, this prevents scenarios where different email addresses could produce identical padded representations due to silent truncation.The error handling is clear and the documentation properly explains the security rationale.
505-505: Good improvement! Error propagation instead of panicking.Replacing
.unwrap()with?operator for bothRegex::new()andString::from_utf8()provides better error handling by propagating errors to the caller rather than panicking at runtime.Also applies to: 515-515
800-816: LGTM! Proper error propagation throughout the function.The function signature change to return
Result<String>is consistent with the updatedPaddedEmailAddr::from_email_addrsignature. All error propagation using?operator is correct, and the function now properly handles errors from:
- Email address validation
- Hex-to-field conversions
- Account salt generation
Note: This is a breaking change to the public API.
833-833: Minor style improvement.Using
.or_else()for Option chaining is slightly more idiomatic than.unwrap_or_else()in this context, though both work correctly here.
601-697: Excellent test coverage for the new validation logic!The test suite comprehensively covers:
- Valid email address padding and verification
- Boundary condition (exactly 256 bytes - should pass)
- Over-limit rejection (257 bytes - should fail)
- Collision prevention security scenarios
- Long but valid emails under the limit
- Integration with
calculate_account_saltfor both success and error pathsThe tests are well-structured with clear assertions and descriptive error messages.
38-38: DKIM API endpoint is operational and returns valid data.The new endpoint
https://archive.zk.email/api/key/domainsuccessfully returns DKIM key records in the expected JSON format with proper structure (domain, selector, firstSeenAt, lastSeenAt, value fields). The change is verified as live and compatible.
532-532: Verify circuit-level SHA padding handling with circuit implementation team.The comment update at line 549 asserts that "the circuit handles SHA padding", allowing the remaining body to be padded to
max_remaining_body_lengthwith zeros rather than requiring it to be a multiple of 64 bytes. However, the verification script did not locate the circuit's actual SHA padding implementation (e.g.,partial_sha256_var_end) or corresponding tests that validate this behavior with variable-length inputs.Action required: Confirm with the circuit development team that the circuit implementation correctly handles variable-length remaining body inputs (i.e., not strictly multiples of 64) before this change is merged. The codebase reference alone is insufficient to verify this assumption.
src/circuit/mod.rs (3)
1-17: LGTM! Clean module organization.The module structure and imports are well-organized, with appropriate re-exports for public APIs.
19-75: LGTM! Well-designed data structures.The separation between public API structs (CircuitParams, CircuitOptions) and internal implementation structs (CircuitInput) provides good encapsulation. Serde annotations are correctly applied for JSON serialization.
77-114: LGTM! Secure defaults applied.The constructor correctly applies sensible defaults, including defaulting
ignore_body_hash_checktofalseto enforce body hash verification by default.browser_test/src/noirProver.ts (4)
1-15: LGTM! Clean SDK initialization.The imports and SDK configuration are well-structured, with helpful commented alternatives for different environments.
85-147: LGTM! Robust circuit execution flow.The Noir circuit execution is well-structured with appropriate error handling and data transformations (Map to object conversion for circuit inputs).
167-178: LGTM! Clean email fetching with error handling.The function properly handles fetch errors and returns the email content as text.
180-198: LGTM! Proper validation of required external inputs.The function correctly ensures all required external inputs are provided and augments them with maxLength constraints.
src/circuit/noir/structs.rs (3)
4-11: LGTM! Clean custom deserializer.The empty string to None deserializer is correctly implemented using
filter, providing clean handling of empty optional strings.
13-62: LGTM! Well-designed data structures.The struct definitions are clean and appropriate for Noir circuit inputs, with good use of
Optionfor conditional fields and the custom deserializer forsha_precompute_selectorto handle empty strings elegantly.
64-77: LGTM! Complete type definitions.The
HaystackLocationenum andRegexInputstruct provide clear, type-safe interfaces for regex processing in Noir circuits.src/circuit/noir/mod.rs (4)
1-24: LGTM! Clean module organization.Module structure, imports, and the
MODULUS_BITSconstant are well-organized.
35-105: LGTM! Clean circuit input construction.The conversion of parsed email data into circuit parameters and the initialization of
NoirCircuitInputsare well-structured.
223-277: LGTM! Clean integration of external inputs.The function properly constructs circuit parameters and processes external inputs with appropriate padding and serialization.
306-443: LGTM! Robust regex processing and test coverage.The regex input processing correctly handles capture groups with proper error checks, and the test module provides good coverage of the circuit input generation flow.
| let result = generate_partial_sha( | ||
| body_for_sha, | ||
| body_original_len, | ||
| adjusted_selector, | ||
| params.max_body_length, | ||
| ); | ||
|
|
||
| // Use match to handle the result and convert any error into an anyhow::Error | ||
| let (precomputed_sha, body_remaining_padded, body_remaining_length) = match result { | ||
| Ok((sha, remaining, len)) => (sha, remaining, len), | ||
| Err(e) => panic!("Failed to generate partial SHA: {:?}", e), | ||
| }; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Replace panic with error propagation.
The function panics on generate_partial_sha failure, but it already returns Result<CircuitInput>. Convert the error and propagate it using ? instead of panicking.
Apply this diff:
- // Use match to handle the result and convert any error into an anyhow::Error
- let (precomputed_sha, body_remaining_padded, body_remaining_length) = match result {
- Ok((sha, remaining, len)) => (sha, remaining, len),
- Err(e) => panic!("Failed to generate partial SHA: {:?}", e),
- };
+ // Convert the error into an anyhow::Error and propagate it
+ let (precomputed_sha, body_remaining_padded, body_remaining_length) = result
+ .map_err(|e| anyhow::anyhow!("Failed to generate partial SHA: {:?}", e))?;🤖 Prompt for AI Agents
In src/circuit/mod.rs around lines 172 to 183, the code currently panics on a
failed generate_partial_sha call; replace the match/panic with direct error
propagation. Call generate_partial_sha(...) and use the ? operator to propagate
the error (if needed, map the error into anyhow::Error with .map_err(|e|
anyhow::anyhow!(...)) before applying ?), then destructure the returned tuple
into (precomputed_sha, body_remaining_padded, body_remaining_length).
Support both legacy and new circuit input formats by:
- Adding optional fields (max_match_length, max_haystack_length, regex_graph_json) with aliases for old field names
- Implementing legacy path that generates {name}RegexIdx format for old circuits
- Using NFAGraph-based generation only when regex_graph_json is present
- Adding helper methods to detect circuit version and calculate defaults
- Fixing typo: removeSoftLinesBreaks -> removeSoftLineBreaks in tests
This ensures circuits compiled before the new compiler integration continue to work while supporting the new format.
Rutefig/fix proof gen old circuits
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Actionable comments posted: 0
♻️ Duplicate comments (2)
src/circuit/circom.rs (2)
630-637: Useu64(noti64) forcapture_group_start_indicesJSON numbersHere
capture_group_start_indiceselements are cast toi64while related fields (capture_group_ids,capture_group_starts) useu64, and indices are inherently non‑negative. This inconsistency is unnecessary and can be surprising when comparing Circom vs Noir outputs.Align this with the other fields by casting to
u64:- .map(|s| serde_json::Value::Number((*s as i64).into())) + .map(|s| serde_json::Value::Number((*s as u64).into()))
283-324: Silent fallback to index0can hide parsing failures for code/timestamp/command
code_idx,timestamp_idx, andcommand_idxall mapErr(_)to0, and the body-search fallback also forces0whenpadded_cleaned_bodyisNone. This silently suppresses errors and makes it impossible to distinguish “not found / failed to parse” from “found at position 0”, which can mis-wire circuit behavior.Consider instead:
- Propagating the errors (
?) if these indices are required, or- Using
Option<usize>inEmailCircuitInputand encoding the optionality explicitly at the circuit boundary, or- If
0is truly a safe sentinel, document that invariant clearly and ensure the circuits never treat index 0 as a valid match location.
🧹 Nitpick comments (4)
src/lib.rs (1)
9-10: Consider whetherregexneeds to be a public moduleYou’re already re-exporting the curated regex surface at the crate root; if external consumers don’t need to reach into
regex::*internals, you could make thismod regex;instead and keep the internal layout private. If consumers do rely on submodules, the currentpubis fine.src/circuit/circom.rs (3)
41-49:EmailCircuitParams.remove_soft_line_breaksis currently unusedThe
remove_soft_line_breaksflag is exposed onEmailCircuitParamsbut never read anywhere in this module, so toggling it has no effect. Either wire it into the email input generation (e.g., how the body is cleaned/padded) or drop the field to avoid a misleading public API.
569-581: DeadDecomposedRegexConfigconstruction in NFAGraph pathIn the NFAGraph branch you build and populate
decomposed_regex_config, but never actually use it; onlygen_circuit_inputswithNFAGraphis called afterward. This is dead code that adds confusion and may trigger unused-variable warnings.You can safely remove
decomposed_regex_config(and theVecDequedependency if unused elsewhere), or, if it’s intended for a future shared Circom/Noir path, add a brief comment to mark it as intentionally unused for now.
703-706:compute_signal_lengthis correct but lacks tests and can be simplifiedThe formula for
compute_signal_lengthmatches the intended “ceil(max_length / 31)”, but there’s a TODO and no tests here. Edge cases likemax_length = 0or exact multiples of 31 are easy to regress.Consider both (a) adding a small unit test table (e.g., 0, 1, 30, 31, 32) and (b) simplifying the implementation to
((max_length + 30) / 31)for readability. I can sketch the tests if helpful.Also applies to: 708-708
📜 Review details
Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro
⛔ Files ignored due to path filters (1)
Cargo.lockis excluded by!**/*.lock
📒 Files selected for processing (5)
Cargo.toml(3 hunks)package.json(1 hunks)src/circuit/circom.rs(1 hunks)src/lib.rs(2 hunks)ts_tests/circuit_input.test.ts(3 hunks)
🚧 Files skipped from review as they are similar to previous changes (1)
- package.json
🧰 Additional context used
🧬 Code graph analysis (2)
src/lib.rs (3)
src/regex/patterns.rs (8)
extract_body_hash_idxes(106-108)extract_email_addr_idxes(81-83)extract_email_domain_idxes(86-88)extract_from_addr_idxes(91-93)extract_message_id_idxes(116-118)extract_subject_all_idxes(101-103)extract_timestamp_idxes(111-113)extract_to_addr_idxes(96-98)src/regex/extract.rs (2)
extract_substr(374-386)extract_substr_idxes(188-201)src/regex/padding.rs (2)
pad_bytes(32-36)pad_string(18-22)
src/circuit/circom.rs (6)
src/converters.rs (4)
field_to_hex(76-79)hex_to_u256(302-308)string_to_circom_bigint_bytes(463-483)vec_u8_to_bigint(265-269)src/parse_email.rs (3)
find_index_in_body(360-372)remove_quoted_printable_soft_breaks(323-345)new_from_raw_email(49-75)src/circuit/noir/utils.rs (1)
trim_sha256_padding(319-350)src/circuit/mod.rs (2)
generate_circuit_inputs(134-192)new(98-113)src/cryptos.rs (5)
from(273-275)new(59-61)new(260-262)new(335-343)from_email_addr(111-128)src/regex/extract.rs (1)
extract_substr_idxes(188-201)
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (1)
- GitHub Check: build-test
🔇 Additional comments (5)
ts_tests/circuit_input.test.ts (1)
34-34: LGTM! Typo fix applied consistently.The property name correction from
removeSoftLinesBreakstoremoveSoftLineBreaks(removing the extra 's') is applied consistently across all three test cases. This aligns with the updated WASM API mentioned in the PR objectives.Also applies to: 79-79, 153-153
src/lib.rs (2)
11-11: WASM cfg gate forwasmmodule looks goodThe
#[cfg(target_arch = "wasm32")]around thewasmmodule keeps the native build surface clean while exposing the WASM helpers only where relevant; no issues here.
23-30: <!-- [scratchpad_start]
[task verify_re_export_impact 2/3]
[observations]
- Found lib.rs content showing re-export block at lines 24-30 (matches review snippet)
- Searched for
extract_across entire codebase - found extensive usage of:
- extract_body_hash_idxes, extract_email_addr_idxes, extract_email_domain_idxes
- extract_from_addr_idxes, extract_message_id_idxes, extract_subject_all_idxes
- extract_substr, extract_substr_idxes, extract_timestamp_idxes, extract_to_addr_idxes
- pad_bytes, pad_string in multiple files
- No results for
extract_substrs(plural) - onlyextract_substr(singular) exists- All re-exported items are actively used in src/parse_email.rs, src/regex/patterns.rs, src/regex/wasm.rs, src/circuit/circom.rs
- Functions defined in src/regex/patterns.rs (wrapper functions around extract_substr_idxes) and src/regex/extract.rs (core implementations)
[analysis]
- The original review suggested looking for removed helpers like
extract_substrs- No evidence of
extract_substrsexisting - appears never to have existed in codebase- All currently re-exported items are actively used and defined in the regex module
- Singular vs plural: code uses
extract_substr(singular) throughout, not plural variant[pending]
- Need to verify regex/mod.rs actually exports all these items
- Need to ensure all types are properly exported (DecomposedRegexConfig, ExtractionError, etc.)
- Check if re-export is complete or if any items are missing
[actions]
- Check src/regex/mod.rs to see what it actually exports
- Cross-reference all re-exported items with what's available in regex module
- Verify no breakage from the re-export set
#!/bin/bash # Check the regex module's mod.rs to see what it exports cat src/regex/mod.rs#!/bin/bash # Check if extract.rs and patterns.rs properly export their functions grep -n "^pub fn\|^pub struct\|^pub enum" src/regex/extract.rs src/regex/patterns.rs src/regex/types.rs#!/bin/bash # Verify all re-exported items from lib.rs actually exist in regex module # Check each function/type exists rg -n "pub fn extract_body_hash_idxes|pub fn extract_email_addr_idxes|pub fn extract_email_domain_idxes|pub fn extract_from_addr_idxes|pub fn extract_message_id_idxes|pub fn extract_subject_all_idxes|pub fn extract_substr|pub fn extract_substr_idxes|pub fn extract_timestamp_idxes|pub fn extract_to_addr_idxes|pub fn pad_bytes|pub fn pad_string" src/regex/Cargo.toml (2)
53-53: Let me search more specifically for any breaking changes documentation between versions:Let me search for the GitHub release notes more specifically:
Based on my verification, v5.0.0 was released as a fix for a Plonky3 library issue affecting SP1 zkVM security, specifically a FRI size check vulnerability. However, I found that:
No direct code usage detected: The codebase declares
sp1-verifieras a dependency but contains no direct Rust code imports or usages of it.Security fix, not breaking changes: The release notes indicate this was primarily a security fix rather than breaking API changes.
Incomplete verification: Without visible code usage of
sp1-verifieror documented API breaking changes, I cannot definitively confirm whether the upgrade required code modifications.Verify that the sp1-verifier 5.0.0 upgrade compiles successfully and that all tests pass. Confirm the dependency works as intended with the current codebase.
16-16: zk-regex-compiler revision is valid and reachable.The commit hash
a2ce67ff8ae667bc7846cf8920d7d866f2f02d4chas been verified as valid and accessible in the zkemail/zk-regex repository. The sp1-verifier upgrade from 4.0.0 to 5.0.0 shows no breaking changes in the public API based on the v5.0.0 release notes.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Actionable comments posted: 1
♻️ Duplicate comments (2)
src/circuit/circom.rs (2)
237-330: Silent 0 defaults for indices still risk hiding extraction failures
code_idx,timestamp_idx, andcommand_idxdefault to0on any extraction error (Lines 290–307) and are later overwritten withfind_index_in_bodyresults whenprecomputed_shais present (Lines 315–329). This keeps the previous behavior but still makes it hard to distinguish “not found / error” from a genuine index at 0.Consider one of:
- Propagating the errors instead of mapping
Err(_) => 0, or- Changing these fields to
Option<usize>inEmailCircuitInputand usingNoneon extraction failure, or- At minimum, documenting clearly that
0is a sentinel for “missing” and never a valid match position in your circuits.Example (propagate errors):
- let mut code_idx = match parsed_email.get_invitation_code_idxes( + let mut code_idx = parsed_email + .get_invitation_code_idxes( params .as_ref() .map_or(false, |p| p.ignore_body_hash_check.unwrap_or(false)), - ) { - Ok(indexes) => indexes.0, - Err(_) => 0, - }; - let timestamp_idx = match parsed_email.get_timestamp_idxes() { - Ok(indexes) => indexes.0, - Err(_) => 0, - }; - let mut command_idx = - match parsed_email.get_command_idxes(circuit_input_params.ignore_body_hash_check) { - Ok(indexes) => indexes.0, - Err(_) => 0, - }; + )? + .0; + let timestamp_idx = parsed_email.get_timestamp_idxes()?.0; + let mut command_idx = + parsed_email.get_command_idxes(circuit_input_params.ignore_body_hash_check)?.0;This issue was already raised in a previous review and still applies.
618-656: Useu64consistently for capture group indices instead ofi64All other Circom capture-group-related arrays here (
capture_group_ids,capture_group_starts) are serialized asu64, and the Noir side usesu64forcapture_group_start_indicesas well. This one cast toi64is inconsistent and can be confusing:.map(|s| serde_json::Value::Number((*s as i64).into()))Switching to
u64keeps all index-like fields non-negative and aligned:- .map(|s| serde_json::Value::Number((*s as i64).into())) + .map(|s| serde_json::Value::Number((*s as u64).into()))This was identified in an earlier review and still applies.
🧹 Nitpick comments (4)
package.json (1)
13-13: Clarify the pre-release version format.The version "0.4.66-15" uses a non-standard pre-release suffix. Semantic versioning typically expects formats like
0.4.66-alpha.15,0.4.66-beta.15, or0.4.66-rc.15to convey meaning.Please clarify what "-15" represents (e.g., build number, draft iteration) and consider adopting a standard pre-release identifier for clarity.
src/regex/types.rs (1)
30-71: Clarify behavior whenmax_bytes_per_partlength doesn’t matchparts
LegacyDecomposedRegexConfig::to_new_configsilently defaults to256whenmax_bytes_per_partisNoneor too short, which can surprise callers if they miscount parts.Consider either asserting or documenting this behavior explicitly, e.g.:
impl LegacyDecomposedRegexConfig { /// Convert old config to new config with optional max_bytes per part pub fn to_new_config(&self, max_bytes_per_part: Option<Vec<usize>>) -> DecomposedRegexConfig { + if let Some(ref v) = max_bytes_per_part { + debug_assert!( + v.len() >= self.parts.len(), + "max_bytes_per_part shorter than parts; missing entries default to 256", + ); + } let parts = self .parts .iter() .enumerate() .map(|(i, part)| { let max_bytes = max_bytes_per_part.as_ref().and_then(|v| v.get(i).copied()); part.to_new_part(max_bytes) }) .collect();This keeps runtime behavior but makes the implicit default less surprising.
src/circuit/circom.rs (2)
675-691: Minor readability tweak for external input value handlingThe call to
string_to_circom_bigint_bytesadds an extra reference:string_to_circom_bigint_bytes(&external_input.value.as_deref().unwrap_or(""))?;Since
as_deref().unwrap_or("")already yields&str, you can simplify to:- let mut value = - string_to_circom_bigint_bytes(&external_input.value.as_deref().unwrap_or(""))?; + let mut value = + string_to_circom_bigint_bytes(external_input.value.as_deref().unwrap_or(""))?;No functional change, just slightly clearer.
719-723:compute_signal_lengthlogic is correct; consider adding testsThe calculation
max_length / 31 + (if max_length % 31 != 0 { 1 } else { 0 })correctly computes the number of 31-byte limbs, including themax_length == 0case. Given the TODO, adding small table-driven tests (e.g., 0, 1, 31, 32, 62, 63) would lock this in.
📜 Review details
Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro
📒 Files selected for processing (5)
package.json(1 hunks)src/circuit/circom.rs(1 hunks)src/circuit/mod.rs(1 hunks)src/cryptos.rs(9 hunks)src/regex/types.rs(1 hunks)
🚧 Files skipped from review as they are similar to previous changes (1)
- src/circuit/mod.rs
🧰 Additional context used
🧬 Code graph analysis (2)
src/circuit/circom.rs (5)
src/circuit/mod.rs (3)
generate_circuit_inputs_old(194-256)generate_circuit_inputs(134-192)new(98-113)src/converters.rs (4)
field_to_hex(76-79)hex_to_u256(302-308)string_to_circom_bigint_bytes(463-483)vec_u8_to_bigint(265-269)src/parse_email.rs (3)
find_index_in_body(360-372)remove_quoted_printable_soft_breaks(323-345)new_from_raw_email(49-75)src/circuit/noir/utils.rs (1)
trim_sha256_padding(319-350)src/regex/extract.rs (1)
extract_substr_idxes(188-201)
src/cryptos.rs (2)
src/regex/padding.rs (1)
pad_string(18-22)src/converters.rs (2)
hex_to_field(20-67)field_to_hex(76-79)
🔇 Additional comments (14)
package.json (1)
4-12: Verify npm scripts cover new browser_test app.The PR introduces a browser_test Vite app. The current build scripts (
wasm:build,wasm:postbuild,build) appear focused on Rust WASM compilation. Confirm that:
- The browser_test app has its own separate build/dev scripts (e.g., in a nested
package.json), or- New npm scripts are needed to support browser_test development/build.
src/cryptos.rs (8)
3-3: LGTM!The new import for
pad_stringfrom the regex module is correctly used in the refactoredfrom_email_addrmethod (line 123) and aligns with the PR's goal of consolidating padding utilities.
111-128: LGTM! Excellent security improvement.The addition of length validation before padding prevents potential collision attacks where different email addresses exceeding 256 bytes could produce identical padded representations. The error handling is clear and the documentation thoroughly explains the security rationale.
559-630: LGTM! Good backward compatibility approach.The addition of
generate_partial_sha_oldmaintains support for the older Circom compiler that requires external padding. The 64-byte alignment check (lines 615-620) is correctly preserved for this compatibility path, while the new implementation delegates padding to the circuit.
674-770: LGTM! Excellent test coverage.The new tests comprehensively validate the email address length validation and padding behavior:
- Valid inputs and boundary cases (lines 674-702)
- Error handling for overflow (lines 704-718)
- Security properties preventing collisions (lines 720-730)
- Integration with
calculate_account_salt(lines 746-770)The tests are well-structured and provide strong confidence in the new validation logic.
872-890: LGTM! Proper error propagation implemented.The function signature change to return
Result<String>correctly propagates errors from:
PaddedEmailAddr::from_email_addr(line 875)hex_to_fieldconversions (lines 879, 881)AccountSalt::new(line 886)This provides better error visibility to callers and aligns with Rust best practices.
903-906: LGTM! Good robustness improvement.Adding a fallback to try the lowercase "from" header improves compatibility with email systems that may use different header casing. The
or_elsepattern ensures no behavioral change when the standard "From" header is present.
38-38: New DKIM API endpoint verified and functional.The endpoint change from
/api/keyto/api/key/domainhas been confirmed. The new endpoint returns HTTP 200 with a valid JSON array format where each element contains the required "value" field with DKIM records. The existing parsing logic at lines 1038-1041 (which uses.as_array()?.iter().filter_map(|record| record.get("value"))) correctly handles this response format. Query parameters remain unchanged. No breaking changes detected.
494-557: Verify circuit handling of non-64-byte-aligned SHA padding with test evidence.The Consensys Diligence audit of zkemail.nr (December 2024) identified that there are no tests for partial_sha256_var_end when the message size is not a multiple of block size (64 bytes). This directly validates your concern about removing the 64-byte alignment check in
generate_partial_sha.The code shifts SHA padding responsibility from Rust (
generate_partial_sha_oldchecked alignment explicitly) to the circuit'spartial_sha256_var_end, but this function is designed to hash additional parts of the message or complete the entire hash. Critical gap: no evidence in the current codebase that non-aligned inputs are tested or that recent audit findings have been addressed.Before merging, verify:
- Tests exist covering remaining bodies with lengths not divisible by 64
- The circuit implementation has been updated to handle the documented audit gaps
- Hash output matches standard implementations for all edge cases
src/regex/types.rs (1)
6-28: Error type and result alias are well-structuredThe
ExtractionErrorvariants and theExtractionResult<T>alias give clear, future-proof error reporting for regex extraction; no changes needed here.src/circuit/circom.rs (4)
61-220: Serde wrappers and legacy RegexPart handling look correctThe
SerializableRegexPart,RegexPartInput, andregex_parts_serdemodule cleanly support both new enum-based parts and legacy configs while preserving JSON compatibility. The customDecomposedRegexDebug/Cloneimplementations are also sound.
371-390: Claim circuit input generation is straightforward and correct
generate_claim_inputcleanly usesPaddedEmailAddr::from_email_addrand propagates validation via?, and the serialized shape ofClaimCircuitInputis simple and consistent.
397-451: Legacy regex circuit input generation matches old format
generate_legacy_circuit_inputscorrectly reconstructs{name}RegexIdxand{name}RegexIdxNfields fromextract_substr_idxes, preserving the legacy shape for old Circom circuits. No changes needed here.
581-604: NFAGraph path construction andregex_graph_jsonhandling look correctThe NFAGraph-based path correctly guards with
has_nfa_graph(), so the.unwrap()onregex_graph_jsonis safe, and the use ofget_max_haystack_length/max_match_lengthcleanly wires through togen_circuit_inputs.
| let email_circuit_inputs; | ||
| if decomposed_regexes[0].has_nfa_graph() { | ||
| email_circuit_inputs = generate_circuit_inputs(circuit_input_params.clone())?; | ||
| } else { | ||
| // TODO: remove all this temperory code for supporting old one | ||
| email_circuit_inputs = generate_circuit_inputs_old(circuit_input_params.clone())?; | ||
| } |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Potential panic when decomposed_regexes is empty
generate_circuit_inputs_with_decomposed_regexes_and_external_inputs indexes decomposed_regexes[0] to decide between generate_circuit_inputs and generate_circuit_inputs_old. If the caller passes an empty vector (e.g., only external inputs), this will panic.
Using .first() avoids this and lets you define a safe default (e.g., new compiler by default):
- let email_circuit_inputs;
- if decomposed_regexes[0].has_nfa_graph() {
- email_circuit_inputs = generate_circuit_inputs(circuit_input_params.clone())?;
- } else {
- // TODO: remove all this temperory code for supporting old one
- email_circuit_inputs = generate_circuit_inputs_old(circuit_input_params.clone())?;
- }
+ let email_circuit_inputs = if decomposed_regexes
+ .first()
+ .map(|r| r.has_nfa_graph())
+ .unwrap_or(true)
+ {
+ generate_circuit_inputs(circuit_input_params.clone())?
+ } else {
+ // TODO: remove all this temporary code for supporting old one
+ generate_circuit_inputs_old(circuit_input_params.clone())?
+ };This keeps behavior for non-empty inputs while making the empty case safe.
🤖 Prompt for AI Agents
In src/circuit/circom.rs around lines 503 to 509, the code unsafely indexes
decomposed_regexes[0] and can panic when the vector is empty; change the logic
to use decomposed_regexes.first() (or pattern-match) and, if Some(first) call
first.has_nfa_graph() to choose between generate_circuit_inputs and
generate_circuit_inputs_old, otherwise treat the empty case as the safe default
(use generate_circuit_inputs) so the function no longer panics on empty input.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Actionable comments posted: 0
🧹 Nitpick comments (2)
src/cryptos.rs (2)
559-559: Minor: Grammatical issue in comment.The comment reads "Just supported for older circom compiler" but should be "Only supported for older circom compiler" or "Supported only for older circom compiler" for better clarity.
Apply this diff:
-// TODO : Just supported for older circom compiler, since it's circuit doesn't had the padding inside, we padded them externally +// TODO: Only supported for older circom compiler, since its circuit doesn't have padding inside, so we pad externally
920-929: Consider adding a clarifying comment for the.last()usage.The use of
.captures_iter(from_domain).last()cleverly handles cases where the From header might contain multiple@symbols (e.g., in display names like"Contact @ Company <[email protected]>"). A brief comment explaining this would improve code clarity.// Extract domain from From header let from_domain = from_headers[0].as_str(); let from_re = Regex::new(r"@([^>\s]+)").unwrap(); + // Use .last() to get the domain from the actual email address, not from any @ in the display name let from_domain = from_re .captures_iter(from_domain) .last()
📜 Review details
Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro
📒 Files selected for processing (2)
package.json(1 hunks)src/cryptos.rs(10 hunks)
🧰 Additional context used
🧬 Code graph analysis (1)
src/cryptos.rs (2)
src/regex/padding.rs (1)
pad_string(18-22)src/converters.rs (2)
hex_to_field(20-67)field_to_hex(76-79)
🔇 Additional comments (8)
package.json (1)
13-13: Verify the version format is appropriate for npm publishing.The version
0.4.66-16uses a non-standard format for npm (typically semantic versioning or standard pre-release identifiers like0.4.66-alpha.16or0.4.66-rc.16are preferred). Given that this package has public npm publish scripts, confirm that this format is intentional and won't cause issues when published to the registry.src/cryptos.rs (7)
111-128: LGTM! Excellent security improvement.The email length validation prevents collision attacks where different email addresses exceeding 256 bytes could produce identical padded representations. The error handling is clear and comprehensive.
494-557: LGTM! Well-structured partial SHA generation.The function properly handles regex compilation errors, UTF-8 conversion errors, and validates the remaining body length. The padding logic is correct, and the comment at line 549 helpfully explains why 64-byte alignment checking is unnecessary (circuit handles it).
873-890: LGTM! Proper error propagation throughout.The function correctly propagates errors from
PaddedEmailAddr::from_email_addr,hex_to_field, andAccountSalt::newusing the?operator. The Result return type is appropriate for these validation steps.
903-906: LGTM! Good defensive handling of header case variations.The fallback to lowercase "from" header improves robustness across different mail servers that may use different header capitalization.
674-744: LGTM! Comprehensive test coverage for email validation.The tests thoroughly cover valid cases, boundary conditions (exactly 256 bytes), error cases (exceeding max length), and security concerns (collision prevention). Well-structured test suite.
746-770: LGTM! Good test coverage for account salt calculation.The tests verify both successful salt calculation with valid inputs and proper error propagation when the email exceeds maximum length. The use of a properly formatted 32-byte hex account code is appropriate.
38-38: Add integration test for the DKIM API endpoint in CI.The
fetch_public_keysfunction depends onhttps://archive.zk.email/api/key/domainfor DKIM verification, but the existing test skips in CI environments. Either add an integration test with a mock endpoint/fixture, or document the runtime requirement and expected response schema.
Note
Introduce a new regex runtime and split circuit code into circom/noir modules, update WASM/SDK integration, and add a browser proving app with stricter email validation and DKIM endpoint update.
regexmodule (extraction, padding, patterns, WASM) usingzk_regex_compiler; remove old inline regex logic and types.circomandnoirmodules; add Noir input generation and limb/REDc utilities; consolidate helpers.PaddedEmailAddr(returns Result); update DKIM key endpoint; improve padding/sha utilities.browser_test(Vite setup, worker, provers for Noir/Circom, assets) for in-browser proving.Written by Cursor Bugbot for commit bcf50a2. This will update automatically on new commits. Configure here.
Summary by CodeRabbit
New Features
Bug Fixes
Chores
✏️ Tip: You can customize this high-level summary in your review settings.