{
  "version": 3,
  "sources": ["../../../../src/workers/r2/bucket.worker.ts", "../../../../src/workers/r2/constants.ts", "../../../../src/workers/r2/errors.worker.ts", "../../../../src/workers/r2/r2Object.worker.ts", "../../../../src/workers/r2/schemas.worker.ts", "../../../../src/workers/r2/validator.worker.ts"],
  "sourcesContent": ["import assert from \"node:assert\";\nimport { Buffer } from \"node:buffer\";\nimport { createHash } from \"node:crypto\";\nimport {\n\tall,\n\tbase64Decode,\n\tbase64Encode,\n\tDeferredPromise,\n\tGET,\n\tget,\n\tmaybeApply,\n\tMiniflareDurableObject,\n\tPUT,\n\treadPrefix,\n\tWaitGroup,\n} from \"miniflare:shared\";\nimport { R2Headers, R2Limits } from \"./constants\";\nimport {\n\tBadUpload,\n\tEntityTooSmall,\n\tInternalError,\n\tInvalidMetadata,\n\tInvalidPart,\n\tNoSuchKey,\n\tNoSuchUpload,\n\tPreconditionFailed,\n} from \"./errors.worker\";\nimport { InternalR2Object, InternalR2ObjectBody } from \"./r2Object.worker\";\nimport {\n\tMultipartUploadState,\n\tR2BindingRequestSchema,\n\tSQL_SCHEMA,\n} from \"./schemas.worker\";\nimport { R2_HASH_ALGORITHMS, Validator } from \"./validator.worker\";\nimport type { EncodedMetadata, InternalR2Objects } from \"./r2Object.worker\";\nimport type {\n\tInternalR2CreateMultipartUploadOptions,\n\tInternalR2GetOptions,\n\tInternalR2ListOptions,\n\tInternalR2PutOptions,\n\tMultipartPartRow,\n\tMultipartUploadRow,\n\tObjectRow,\n\tR2Conditional,\n\tR2CreateMultipartUploadResponse,\n\tR2PublishedPart,\n\tR2UploadPartResponse,\n} from \"./schemas.worker\";\nimport type { DigestAlgorithm } from \"./validator.worker\";\nimport type {\n\tBlobId,\n\tInclusiveRange,\n\tMiniflareDurableObjectEnv,\n\tRouteHandler,\n\tTypedSql,\n} from \"miniflare:shared\";\n\n// This file implements Miniflare's R2 simulator, supporting both single and\n// multipart uploads.\n//\n// ===== Notes on Multipart Uploads =====\n//\n// Multipart uploads are created and later resumed. When creating a multipart\n// upload, Miniflare will store an upload record, containing passed HTTP and\n// custom metadata. This record serves as a marker for the upload, and is used\n// by other methods to check the upload exists.\n//\n// A new part record is stored for each uploaded part. Each part gets an\n// associated ETag, which must be used in conjunction with the part number when\n// completing an upload. If a part is uploaded with the same part number as an\n// existing part, it will override it.\n//\n// To complete a multipart upload, an array of part number and ETag objects is\n// required. Miniflare will add an object record as usual, but without a body.\n// The selected parts will have their records updated to point to the body.\n// This means Miniflare doesn't need to load all parts into memory, concatenate\n// them, and write them back out. An upload can also be aborted, in which case\n// all its parts will be deleted.\n//\n// Note that when completing or aborting an upload, the upload record is NOT\n// deleted. This is because uploads can be aborted more than once, and even\n// aborted after completion (although in this case, aborting is a no-op). We\n// need to be able to distinguish between a completed upload, an aborted upload\n// and an upload that never existed to handle this, and match R2's error\n// messages.\n//\n// If regular `R2Bucket#{put,delete}()` methods are called on completed\n// multipart objects, they will delete all parts in addition to the object\n// itself. `R2Bucket#{put,delete}()` will never delete parts for in-progress\n// uploads. `R2Bucket#{head,get,list}()` will never return data from in-progress\n// uploads.\n\nclass DigestingStream<\n\tAlgorithm extends DigestAlgorithm = DigestAlgorithm,\n> extends TransformStream<Uint8Array, Uint8Array> {\n\treadonly digests: Promise<Map<Algorithm, Buffer>>;\n\n\tconstructor(algorithms: Algorithm[]) {\n\t\tconst digests = new DeferredPromise<Map<Algorithm, Buffer>>();\n\t\tconst hashes = algorithms.map((alg) => {\n\t\t\tconst stream = new crypto.DigestStream(alg);\n\t\t\tconst writer = stream.getWriter();\n\t\t\treturn { stream, writer };\n\t\t});\n\t\tsuper({\n\t\t\tasync transform(chunk, controller) {\n\t\t\t\tfor (const hash of hashes) await hash.writer.write(chunk);\n\t\t\t\tcontroller.enqueue(chunk);\n\t\t\t},\n\t\t\tasync flush() {\n\t\t\t\tconst result = new Map<Algorithm, Buffer>();\n\t\t\t\tfor (let i = 0; i < hashes.length; i++) {\n\t\t\t\t\tawait hashes[i].writer.close();\n\t\t\t\t\tresult.set(algorithms[i], Buffer.from(await hashes[i].stream.digest));\n\t\t\t\t}\n\t\t\t\tdigests.resolve(result);\n\t\t\t},\n\t\t});\n\t\tthis.digests = digests;\n\t}\n}\n\nconst validate = new Validator();\nconst decoder = new TextDecoder();\n\nfunction generateVersion() {\n\treturn Buffer.from(crypto.getRandomValues(new Uint8Array(16))).toString(\n\t\t\"hex\"\n\t);\n}\nfunction generateId() {\n\treturn Buffer.from(crypto.getRandomValues(new Uint8Array(128))).toString(\n\t\t\"base64url\"\n\t);\n}\nfunction generateMultipartEtag(md5Hexes: string[]) {\n\t// https://stackoverflow.com/a/19896823\n\tconst hash = createHash(\"md5\");\n\tfor (const md5Hex of md5Hexes) hash.update(md5Hex, \"hex\");\n\treturn `${hash.digest(\"hex\")}-${md5Hexes.length}`;\n}\n\nfunction rangeOverlaps(a: InclusiveRange, b: InclusiveRange): boolean {\n\treturn a.start <= b.end && b.start <= a.end;\n}\n\nasync function decodeMetadata(req: Request<unknown, unknown>) {\n\tconst metadataSize = parseInt(\n\t\treq.headers.get(R2Headers.METADATA_SIZE) ?? \"NaN\"\n\t);\n\tif (Number.isNaN(metadataSize)) throw new InvalidMetadata();\n\n\tassert(req.body !== null);\n\tconst body = req.body as ReadableStream<Uint8Array>;\n\n\t// Read just metadata from body stream\n\tconst [metadataBuffer, value] = await readPrefix(body, metadataSize);\n\tconst metadataJson = decoder.decode(metadataBuffer);\n\tconst metadata = R2BindingRequestSchema.parse(JSON.parse(metadataJson));\n\n\treturn { metadata, metadataSize, value };\n}\nfunction decodeHeaderMetadata(req: Request<unknown, unknown>) {\n\tconst header = req.headers.get(R2Headers.REQUEST);\n\tif (header === null) throw new InvalidMetadata();\n\treturn R2BindingRequestSchema.parse(JSON.parse(header));\n}\n\nfunction encodeResult(\n\tresult: InternalR2Object | InternalR2ObjectBody | InternalR2Objects\n) {\n\tlet encoded: EncodedMetadata;\n\tif (result instanceof InternalR2Object) {\n\t\tencoded = result.encode();\n\t} else {\n\t\tencoded = InternalR2Object.encodeMultiple(result);\n\t}\n\n\treturn new Response(encoded.value, {\n\t\theaders: {\n\t\t\t[R2Headers.METADATA_SIZE]: `${encoded.metadataSize}`,\n\t\t\t\"Content-Type\": \"application/json\",\n\t\t\t\"Content-Length\": `${encoded.size}`,\n\t\t},\n\t});\n}\nfunction encodeJSONResult(result: unknown) {\n\tconst encoded = JSON.stringify(result);\n\treturn new Response(encoded, {\n\t\theaders: {\n\t\t\t[R2Headers.METADATA_SIZE]: `${Buffer.byteLength(encoded)}`,\n\t\t\t\"Content-Type\": \"application/json\",\n\t\t},\n\t});\n}\n\nfunction sqlStmts(db: TypedSql) {\n\tconst stmtGetPreviousByKey = db.stmt<\n\t\tPick<ObjectRow, \"key\">,\n\t\tPick<ObjectRow, \"blob_id\" | \"etag\" | \"uploaded\">\n\t>(\"SELECT blob_id, etag, uploaded FROM _mf_objects WHERE key = :key\");\n\t// Regular statements\n\tconst stmtGetByKey = db.stmt<Pick<ObjectRow, \"key\">, ObjectRow>(`\n    SELECT key, blob_id, version, size, etag, uploaded, checksums, http_metadata, custom_metadata\n    FROM _mf_objects WHERE key = :key\n  `);\n\tconst stmtPut = db.stmt<ObjectRow>(`\n    INSERT OR REPLACE INTO _mf_objects (key, blob_id, version, size, etag, uploaded, checksums, http_metadata, custom_metadata)\n    VALUES (:key, :blob_id, :version, :size, :etag, :uploaded, :checksums, :http_metadata, :custom_metadata)\n  `);\n\tconst stmtDelete = db.stmt<\n\t\tPick<ObjectRow, \"key\">,\n\t\tPick<ObjectRow, \"blob_id\">\n\t>(\"DELETE FROM _mf_objects WHERE key = :key RETURNING blob_id\");\n\n\tfunction stmtListWithoutDelimiter<ExtraColumns extends (keyof ObjectRow)[]>(\n\t\t...extraColumns: ExtraColumns\n\t) {\n\t\tconst columns: (keyof ObjectRow)[] = [\n\t\t\t\"key\",\n\t\t\t\"version\",\n\t\t\t\"size\",\n\t\t\t\"etag\",\n\t\t\t\"uploaded\",\n\t\t\t\"checksums\",\n\t\t\t...extraColumns,\n\t\t];\n\t\t// TODO: consider applying same `:start_after IS NULL` trick to KeyValueStore\n\t\treturn db.stmt<\n\t\t\t{ limit: number; prefix: string; start_after: string | null },\n\t\t\tOmit<ObjectRow, \"blob_id\"> & Pick<ObjectRow, ExtraColumns[number]>\n\t\t>(`\n      SELECT ${columns.join(\", \")}\n      FROM _mf_objects\n      WHERE substr(key, 1, length(:prefix)) = :prefix\n      AND (:start_after IS NULL OR key > :start_after)\n      ORDER BY key LIMIT :limit\n    `);\n\t}\n\n\t// Multipart upload statements\n\tconst stmtGetUploadState = db.stmt<\n\t\tPick<MultipartUploadRow, \"upload_id\" | \"key\">,\n\t\tPick<MultipartUploadRow, \"state\">\n\t>(\n\t\t// For checking current upload state\n\t\t\"SELECT state FROM _mf_multipart_uploads WHERE upload_id = :upload_id AND key = :key\"\n\t);\n\tconst stmtGetUploadMetadata = db.stmt<\n\t\tPick<MultipartUploadRow, \"upload_id\" | \"key\">,\n\t\tPick<MultipartUploadRow, \"http_metadata\" | \"custom_metadata\" | \"state\">\n\t>(\n\t\t// For checking current upload state, and getting metadata for completion\n\t\t\"SELECT http_metadata, custom_metadata, state FROM _mf_multipart_uploads WHERE upload_id = :upload_id AND key = :key\"\n\t);\n\tconst stmtUpdateUploadState = db.stmt<\n\t\tPick<MultipartUploadRow, \"upload_id\" | \"state\">\n\t>(\n\t\t// For completing/aborting uploads\n\t\t\"UPDATE _mf_multipart_uploads SET state = :state WHERE upload_id = :upload_id\"\n\t);\n\t// Multipart part statements\n\tconst stmtGetPreviousPartByNumber = db.stmt<\n\t\tPick<MultipartPartRow, \"upload_id\" | \"part_number\">,\n\t\tPick<MultipartPartRow, \"blob_id\">\n\t>(\n\t\t// For getting part number's previous blob ID to garbage collect\n\t\t\"SELECT blob_id FROM _mf_multipart_parts WHERE upload_id = :upload_id AND part_number = :part_number\"\n\t);\n\tconst stmtPutPart = db.stmt<Omit<MultipartPartRow, \"object_key\">>(\n\t\t// For recording metadata when uploading parts\n\t\t`INSERT OR REPLACE INTO _mf_multipart_parts (upload_id, part_number, blob_id, size, etag, checksum_md5)\n    VALUES (:upload_id, :part_number, :blob_id, :size, :etag, :checksum_md5)`\n\t);\n\tconst stmtLinkPart = db.stmt<\n\t\tPick<MultipartPartRow, \"upload_id\" | \"part_number\" | \"object_key\">\n\t>(\n\t\t// For linking parts with an object when completing uploads\n\t\t`UPDATE _mf_multipart_parts SET object_key = :object_key\n    WHERE upload_id = :upload_id AND part_number = :part_number`\n\t);\n\tconst stmtDeletePartsByUploadId = db.stmt<\n\t\tPick<MultipartPartRow, \"upload_id\">,\n\t\tPick<MultipartPartRow, \"blob_id\">\n\t>(\n\t\t// For deleting parts when aborting uploads\n\t\t\"DELETE FROM _mf_multipart_parts WHERE upload_id = :upload_id RETURNING blob_id\"\n\t);\n\tconst stmtDeleteUnlinkedPartsByUploadId = db.stmt<\n\t\tPick<MultipartPartRow, \"upload_id\">,\n\t\tPick<MultipartPartRow, \"blob_id\">\n\t>(\n\t\t// For deleting unused parts when completing uploads\n\t\t\"DELETE FROM _mf_multipart_parts WHERE upload_id = :upload_id AND object_key IS NULL RETURNING blob_id\"\n\t);\n\tconst stmtDeletePartsByKey = db.stmt<\n\t\tPick<MultipartPartRow, \"object_key\">,\n\t\tPick<MultipartPartRow, \"blob_id\">\n\t>(\n\t\t// For deleting dangling parts when overwriting an existing key\n\t\t\"DELETE FROM _mf_multipart_parts WHERE object_key = :object_key RETURNING blob_id\"\n\t);\n\tconst stmtListPartsByUploadId = db.stmt<\n\t\tPick<MultipartPartRow, \"upload_id\">,\n\t\tOmit<MultipartPartRow, \"blob_id\">\n\t>(\n\t\t// For getting part metadata when completing uploads\n\t\t`SELECT upload_id, part_number, blob_id, size, etag, checksum_md5, object_key\n    FROM _mf_multipart_parts WHERE upload_id = :upload_id`\n\t);\n\tconst stmtListPartsByKey = db.stmt<\n\t\tPick<MultipartPartRow, \"object_key\">,\n\t\tPick<MultipartPartRow, \"blob_id\" | \"size\">\n\t>(\n\t\t// For getting part metadata when getting values, size included for range\n\t\t// requests, so we only need to read blobs containing the required data\n\t\t\"SELECT blob_id, size FROM _mf_multipart_parts WHERE object_key = :object_key ORDER BY part_number\"\n\t);\n\n\treturn {\n\t\tgetByKey: stmtGetByKey,\n\t\tgetPartsByKey: db.txn((key: string) => {\n\t\t\tconst row = get(stmtGetByKey({ key }));\n\t\t\tif (row === undefined) return;\n\t\t\tif (row.blob_id === null) {\n\t\t\t\t// If this is a multipart object, also return the parts\n\t\t\t\tconst partsRows = all(stmtListPartsByKey({ object_key: key }));\n\t\t\t\treturn { row, parts: partsRows };\n\t\t\t} else {\n\t\t\t\t// Otherwise, just return the row\n\t\t\t\treturn { row };\n\t\t\t}\n\t\t}),\n\t\tput: db.txn((newRow: ObjectRow, onlyIf?: R2Conditional) => {\n\t\t\tconst key = newRow.key;\n\t\t\tconst row = get(stmtGetPreviousByKey({ key }));\n\t\t\tif (onlyIf !== undefined) validate.condition(row, onlyIf);\n\t\t\tstmtPut(newRow);\n\t\t\tconst maybeOldBlobId = row?.blob_id;\n\t\t\tif (maybeOldBlobId === undefined) {\n\t\t\t\treturn [];\n\t\t\t} else if (maybeOldBlobId === null) {\n\t\t\t\t// If blob_id is null, this was a multipart object, so delete all\n\t\t\t\t// multipart parts\n\t\t\t\tconst rows = all(stmtDeletePartsByKey({ object_key: key }));\n\t\t\t\treturn rows.map(({ blob_id }) => blob_id);\n\t\t\t} else {\n\t\t\t\treturn [maybeOldBlobId];\n\t\t\t}\n\t\t}),\n\t\tdeleteByKeys: db.txn((keys: string[]) => {\n\t\t\tconst oldBlobIds: string[] = [];\n\t\t\tfor (const key of keys) {\n\t\t\t\tconst row = get(stmtDelete({ key }));\n\t\t\t\tconst maybeOldBlobId = row?.blob_id;\n\t\t\t\tif (maybeOldBlobId === null) {\n\t\t\t\t\t// If blob_id is null, this was a multipart object, so delete all\n\t\t\t\t\t// multipart parts\n\t\t\t\t\tconst partRows = stmtDeletePartsByKey({ object_key: key });\n\t\t\t\t\tfor (const partRow of partRows) oldBlobIds.push(partRow.blob_id);\n\t\t\t\t} else if (maybeOldBlobId !== undefined) {\n\t\t\t\t\toldBlobIds.push(maybeOldBlobId);\n\t\t\t\t}\n\t\t\t}\n\t\t\treturn oldBlobIds;\n\t\t}),\n\n\t\tlistWithoutDelimiter: stmtListWithoutDelimiter(),\n\t\tlistHttpMetadataWithoutDelimiter: stmtListWithoutDelimiter(\"http_metadata\"),\n\t\tlistCustomMetadataWithoutDelimiter:\n\t\t\tstmtListWithoutDelimiter(\"custom_metadata\"),\n\t\tlistHttpCustomMetadataWithoutDelimiter: stmtListWithoutDelimiter(\n\t\t\t\"http_metadata\",\n\t\t\t\"custom_metadata\"\n\t\t),\n\t\tlistMetadata: db.stmt<\n\t\t\t{\n\t\t\t\tlimit: number;\n\t\t\t\tstart_after: string | null;\n\t\t\t\tprefix: string;\n\t\t\t\tdelimiter: string;\n\t\t\t},\n\t\t\tOmit<ObjectRow, \"key\" | \"blob_id\"> & {\n\t\t\t\tlast_key: string;\n\t\t\t\tdelimited_prefix_or_key: `dlp:${string}` | `key:${string}`;\n\t\t\t}\n\t\t>(`\n      SELECT\n        -- When grouping by a delimited prefix, this will give us the last key with that prefix.\n        --   NOTE: we'll use this for the next cursor. If we didn't return the last key, the next page may return the\n        --   same delimited prefix. Essentially, we're skipping over all keys with this group's delimited prefix.\n        -- When grouping by a key, this will just give us the key.\n        max(key) AS last_key,\n        iif(\n            -- Try get 1-indexed position \\`i\\` of :delimiter in rest of key after :prefix...\n                                                       instr(substr(key, length(:prefix) + 1), :delimiter),\n            -- ...if found, we have a delimited prefix of the :prefix followed by the rest of key up to and including the :delimiter\n            'dlp:' || substr(key, 1, length(:prefix) + instr(substr(key, length(:prefix) + 1), :delimiter) + length(:delimiter) - 1),\n            -- ...otherwise, we just have a regular key\n            'key:' || key\n        ) AS delimited_prefix_or_key,\n        -- NOTE: we'll ignore metadata for delimited prefix rows, so it doesn't matter which keys' we return\n        version, size, etag, uploaded, checksums, http_metadata, custom_metadata\n      FROM _mf_objects\n      WHERE substr(key, 1, length(:prefix)) = :prefix\n      AND (:start_after IS NULL OR key > :start_after)\n      GROUP BY delimited_prefix_or_key -- Group keys with same delimited prefix into a row, leaving others in their own rows\n      ORDER BY last_key LIMIT :limit;\n    `),\n\n\t\tcreateMultipartUpload: db.stmt<Omit<MultipartUploadRow, \"state\">>(`\n      INSERT INTO _mf_multipart_uploads (upload_id, key, http_metadata, custom_metadata)\n      VALUES (:upload_id, :key, :http_metadata, :custom_metadata)\n    `),\n\t\tputPart: db.txn(\n\t\t\t(key: string, newRow: Omit<MultipartPartRow, \"object_key\">) => {\n\t\t\t\t// 1. Check the upload exists and is in-progress\n\t\t\t\tconst uploadRow = get(\n\t\t\t\t\tstmtGetUploadState({\n\t\t\t\t\t\tkey,\n\t\t\t\t\t\tupload_id: newRow.upload_id,\n\t\t\t\t\t})\n\t\t\t\t);\n\t\t\t\tif (uploadRow?.state !== MultipartUploadState.IN_PROGRESS) {\n\t\t\t\t\tthrow new NoSuchUpload();\n\t\t\t\t}\n\n\t\t\t\t// 2. Check if we have an existing part with this number, then upsert\n\t\t\t\tconst partRow = get(\n\t\t\t\t\tstmtGetPreviousPartByNumber({\n\t\t\t\t\t\tupload_id: newRow.upload_id,\n\t\t\t\t\t\tpart_number: newRow.part_number,\n\t\t\t\t\t})\n\t\t\t\t);\n\t\t\t\tstmtPutPart(newRow);\n\t\t\t\treturn partRow?.blob_id;\n\t\t\t}\n\t\t),\n\t\tcompleteMultipartUpload: db.txn(\n\t\t\t(\n\t\t\t\tkey: string,\n\t\t\t\tupload_id: string,\n\t\t\t\tselectedParts: R2PublishedPart[],\n\t\t\t\tminPartSize: number\n\t\t\t) => {\n\t\t\t\t// 1. Check the upload exists and is in-progress\n\t\t\t\tconst uploadRow = get(stmtGetUploadMetadata({ key, upload_id }));\n\t\t\t\tif (uploadRow === undefined) {\n\t\t\t\t\tthrow new InternalError();\n\t\t\t\t} else if (uploadRow.state > MultipartUploadState.IN_PROGRESS) {\n\t\t\t\t\tthrow new NoSuchUpload();\n\t\t\t\t}\n\n\t\t\t\t// 2. Check all selected part numbers are unique\n\t\t\t\tconst partNumberSet = new Set<number>();\n\t\t\t\tfor (const { part } of selectedParts) {\n\t\t\t\t\tif (partNumberSet.has(part)) throw new InternalError();\n\t\t\t\t\tpartNumberSet.add(part);\n\t\t\t\t}\n\n\t\t\t\t// 3. Get metadata for all uploaded parts, checking all selected parts\n\t\t\t\t//    exist\n\t\t\t\tconst uploadedPartRows = stmtListPartsByUploadId({ upload_id });\n\t\t\t\tconst uploadedParts = new Map<\n\t\t\t\t\t/* part number */ number,\n\t\t\t\t\tOmit<MultipartPartRow, \"blob_id\">\n\t\t\t\t>();\n\t\t\t\tfor (const row of uploadedPartRows) {\n\t\t\t\t\tuploadedParts.set(row.part_number, row);\n\t\t\t\t}\n\t\t\t\tconst parts = selectedParts.map((selectedPart) => {\n\t\t\t\t\t// Try find matching uploaded part. If part couldn't be found, or\n\t\t\t\t\t// ETags don't match, throw.\n\t\t\t\t\tconst uploadedPart = uploadedParts.get(selectedPart.part);\n\t\t\t\t\t// (if an uploaded part couldn't be found with the selected part\n\t\t\t\t\t// number, `uploadedPart?.etag` will be `undefined`, which will never\n\t\t\t\t\t// match `selectedPart.etag`, as we've validated it's a string)\n\t\t\t\t\tif (uploadedPart?.etag !== selectedPart.etag) {\n\t\t\t\t\t\tthrow new InvalidPart();\n\t\t\t\t\t}\n\t\t\t\t\treturn uploadedPart;\n\t\t\t\t});\n\t\t\t\t// `parts` now contains a list of selected parts' metadata.\n\n\t\t\t\t// 4. Check all but last part meets minimum size requirements. First\n\t\t\t\t//    check this in argument order, throwing a friendly error...\n\t\t\t\tfor (const part of parts.slice(0, -1)) {\n\t\t\t\t\tif (part.size < minPartSize) {\n\t\t\t\t\t\tthrow new EntityTooSmall();\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\t//    ...then check again in ascending part number order, throwing an\n\t\t\t\t//    internal error. We won't know where the current last element ends\n\t\t\t\t//    up in the sort, so we just check all parts again.\n\t\t\t\t//\n\t\t\t\t//    Also check that all but the last parts are the same size...\n\t\t\t\tparts.sort((a, b) => a.part_number - b.part_number);\n\t\t\t\tlet partSize: number | undefined;\n\t\t\t\tfor (const part of parts.slice(0, -1)) {\n\t\t\t\t\t// noinspection JSUnusedAssignment\n\t\t\t\t\tpartSize ??= part.size;\n\t\t\t\t\tif (part.size < minPartSize || part.size !== partSize) {\n\t\t\t\t\t\tthrow new BadUpload();\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\t//    ...and the last part is not greater than all others\n\t\t\t\t//    (if part size is defined, we must have at least one part)\n\t\t\t\tif (partSize !== undefined && parts[parts.length - 1].size > partSize) {\n\t\t\t\t\tthrow new BadUpload();\n\t\t\t\t}\n\n\t\t\t\t// 5. Get existing upload if any, and delete previous multipart parts\n\t\t\t\tconst oldBlobIds: string[] = [];\n\t\t\t\tconst existingRow = get(stmtGetPreviousByKey({ key }));\n\t\t\t\tconst maybeOldBlobId = existingRow?.blob_id;\n\t\t\t\tif (maybeOldBlobId === null) {\n\t\t\t\t\t// If blob_id is null, this was a multipart object, so delete all\n\t\t\t\t\t// multipart parts\n\t\t\t\t\tconst partRows = stmtDeletePartsByKey({ object_key: key });\n\t\t\t\t\tfor (const partRow of partRows) oldBlobIds.push(partRow.blob_id);\n\t\t\t\t} else if (maybeOldBlobId !== undefined) {\n\t\t\t\t\toldBlobIds.push(maybeOldBlobId);\n\t\t\t\t}\n\n\t\t\t\t// 6. Write object to the database, and link parts with object\n\t\t\t\tconst totalSize = parts.reduce((acc, { size }) => acc + size, 0);\n\t\t\t\tconst etag = generateMultipartEtag(\n\t\t\t\t\tparts.map(({ checksum_md5 }) => checksum_md5)\n\t\t\t\t);\n\t\t\t\tconst newRow: ObjectRow = {\n\t\t\t\t\tkey,\n\t\t\t\t\tblob_id: null,\n\t\t\t\t\tversion: generateVersion(),\n\t\t\t\t\tsize: totalSize,\n\t\t\t\t\tetag,\n\t\t\t\t\tuploaded: Date.now(),\n\t\t\t\t\tchecksums: \"{}\",\n\t\t\t\t\thttp_metadata: uploadRow.http_metadata,\n\t\t\t\t\tcustom_metadata: uploadRow.custom_metadata,\n\t\t\t\t};\n\t\t\t\tstmtPut(newRow);\n\t\t\t\tfor (const part of parts) {\n\t\t\t\t\tstmtLinkPart({\n\t\t\t\t\t\tupload_id,\n\t\t\t\t\t\tpart_number: part.part_number,\n\t\t\t\t\t\tobject_key: key,\n\t\t\t\t\t});\n\t\t\t\t}\n\n\t\t\t\t// 7. Delete unlinked, unused parts\n\t\t\t\tconst partRows = stmtDeleteUnlinkedPartsByUploadId({ upload_id });\n\t\t\t\tfor (const partRow of partRows) oldBlobIds.push(partRow.blob_id);\n\n\t\t\t\t// 8. Mark the upload as completed\n\t\t\t\tstmtUpdateUploadState({\n\t\t\t\t\tupload_id,\n\t\t\t\t\tstate: MultipartUploadState.COMPLETED,\n\t\t\t\t});\n\n\t\t\t\treturn { newRow, oldBlobIds };\n\t\t\t}\n\t\t),\n\t\tabortMultipartUpload: db.txn((key: string, upload_id: string) => {\n\t\t\t// 1. Make sure this multipart upload exists, ignoring finalised states\n\t\t\tconst uploadRow = get(stmtGetUploadState({ key, upload_id }));\n\t\t\tif (uploadRow === undefined) {\n\t\t\t\tthrow new InternalError();\n\t\t\t} else if (uploadRow.state > MultipartUploadState.IN_PROGRESS) {\n\t\t\t\t// If this upload has already been finalised, return here. `abort()` can\n\t\t\t\t// be called multiple times, and on already `complete()`ed uploads. In\n\t\t\t\t// the later case, we really don't want to delete pointed-to parts.\n\t\t\t\treturn [];\n\t\t\t}\n\n\t\t\t// 2. Delete all parts in the upload\n\t\t\tconst partRows = all(stmtDeletePartsByUploadId({ upload_id }));\n\t\t\tconst oldBlobIds = partRows.map(({ blob_id }) => blob_id);\n\n\t\t\t// 3. Mark the uploaded as aborted\n\t\t\tstmtUpdateUploadState({\n\t\t\t\tupload_id,\n\t\t\t\tstate: MultipartUploadState.ABORTED,\n\t\t\t});\n\n\t\t\treturn oldBlobIds;\n\t\t}),\n\t};\n}\n\n// noinspection JSUnusedGlobalSymbols\nexport class R2BucketObject extends MiniflareDurableObject {\n\treadonly #stmts: ReturnType<typeof sqlStmts>;\n\n\t// Multipart uploads are stored as multiple blobs. Therefore, when reading a\n\t// multipart upload, we'll be reading multiple blobs. When an object is\n\t// deleted, all its blobs are deleted in the background.\n\t//\n\t// Normally for single part objects, this is fine, since we'd open a handle to\n\t// a single blob, which we'd have until we closed it, at which point the blob\n\t// may be deleted. With multipart, we don't want to open handles for all blobs\n\t// as we could hit open file descriptor limits. Similarly, we don't want to\n\t// read all blobs first, as we'd have to buffer them.\n\t//\n\t// Instead, we set up in-process locking on blobs needed for multipart reads.\n\t// When we start a multipart read, we acquire all the blobs we need, then\n\t// release them as we've streamed each part. Multiple multipart reads may be\n\t// in-progress at any given time, so we use a wait group.\n\t//\n\t// This assumes we only ever have a single Miniflare instance operating on a\n\t// blob store, which is always true for in-memory stores, and usually true for\n\t// on-disk ones. If we really wanted to do this properly, we could store the\n\t// bookkeeping for the wait group in SQLite, but then we'd have to implement\n\t// some inter-process signalling/subscription system.\n\treadonly #inUseBlobs = new Map<BlobId, WaitGroup>();\n\n\tconstructor(state: DurableObjectState, env: MiniflareDurableObjectEnv) {\n\t\tsuper(state, env);\n\t\tthis.db.exec(\"PRAGMA case_sensitive_like = TRUE\");\n\t\tthis.db.exec(SQL_SCHEMA);\n\t\tthis.#stmts = sqlStmts(this.db);\n\t}\n\n\t#acquireBlob(blobId: BlobId) {\n\t\tlet waitGroup = this.#inUseBlobs.get(blobId);\n\t\tif (waitGroup === undefined) {\n\t\t\twaitGroup = new WaitGroup();\n\t\t\tthis.#inUseBlobs.set(blobId, waitGroup);\n\t\t\twaitGroup.add();\n\t\t\t// Automatically remove the wait group once this blob is fully released\n\t\t\twaitGroup.wait().then(() => this.#inUseBlobs.delete(blobId));\n\t\t} else {\n\t\t\twaitGroup.add();\n\t\t}\n\t}\n\n\t#releaseBlob(blobId: BlobId) {\n\t\tthis.#inUseBlobs.get(blobId)?.done();\n\t}\n\n\t#backgroundDelete(blobId: BlobId) {\n\t\tthis.timers.queueMicrotask(async () => {\n\t\t\t// Wait for all multipart gets using this blob to complete\n\t\t\tawait this.#inUseBlobs.get(blobId)?.wait();\n\t\t\treturn this.blob.delete(blobId).catch((e) => {\n\t\t\t\tconsole.error(\"R2BucketObject##backgroundDelete():\", e);\n\t\t\t});\n\t\t});\n\t}\n\n\t#assembleMultipartValue(\n\t\tparts: Pick<MultipartPartRow, \"blob_id\" | \"size\">[],\n\t\tqueryRange: InclusiveRange\n\t): ReadableStream<Uint8Array> {\n\t\t// Find required parts (and the ranges within them) to satisfy the query\n\t\t// (doing this outside async IIFE to acquire all required parts before we\n\t\t// start streaming any)\n\t\tconst requiredParts: { blobId: BlobId; range: InclusiveRange }[] = [];\n\t\tlet start = 0;\n\t\tfor (const part of parts) {\n\t\t\tconst partRange: InclusiveRange = { start, end: start + part.size - 1 };\n\t\t\tif (rangeOverlaps(partRange, queryRange)) {\n\t\t\t\tconst range: InclusiveRange = {\n\t\t\t\t\tstart: Math.max(partRange.start, queryRange.start) - partRange.start,\n\t\t\t\t\tend: Math.min(partRange.end, queryRange.end) - partRange.start,\n\t\t\t\t};\n\t\t\t\tthis.#acquireBlob(part.blob_id);\n\t\t\t\trequiredParts.push({ blobId: part.blob_id, range });\n\t\t\t}\n\t\t\tstart = partRange.end + 1;\n\t\t}\n\n\t\t// Stream required parts, the `Promise`s returned from `pipeTo()` won't\n\t\t// resolve until a reader starts reading, so run this in the background as\n\t\t// an async IIFE.\n\t\t//\n\t\t// NOTE: we can't use `IdentityTransformStream` here as piping the readable\n\t\t// side of an `IdentityTransformStream` to the writable side of another\n\t\t// `IdentityTransformStream` is not supported:\n\t\t// https://github.com/cloudflare/workerd/blob/c6f439ca37c5fa34acc54a6df79214ae029ddf9f/src/workerd/api/streams/internal.c%2B%2B#L169\n\t\t// We'll be piping to an `IdentityTransformStream` when we encode the\n\t\t// metadata followed by this stream as the response body.\n\t\tconst identity = new TransformStream<Uint8Array, Uint8Array>();\n\t\t(async () => {\n\t\t\tlet i = 0;\n\t\t\ttry {\n\t\t\t\t// Sharing loop index with `finally` block to ensure all blobs released.\n\t\t\t\t// `i++` is only called at the *end* of a loop iteration, just after we\n\t\t\t\t// release a blob. If an iteration throws, `i` will remain the same, and\n\t\t\t\t// that blob (and the rest) will be released in the `finally`.\n\t\t\t\tfor (; i < requiredParts.length; i++) {\n\t\t\t\t\tconst { blobId, range } = requiredParts[i];\n\t\t\t\t\tconst value = await this.blob.get(blobId, range);\n\t\t\t\t\tconst msg = `Expected to find blob \"${blobId}\" for multipart value`;\n\t\t\t\t\tassert(value !== null, msg);\n\t\t\t\t\tawait value.pipeTo(identity.writable, { preventClose: true });\n\t\t\t\t\tthis.#releaseBlob(blobId);\n\t\t\t\t}\n\t\t\t\tawait identity.writable.close();\n\t\t\t} catch (e) {\n\t\t\t\tawait identity.writable.abort(e);\n\t\t\t} finally {\n\t\t\t\tfor (; i < requiredParts.length; i++) {\n\t\t\t\t\tthis.#releaseBlob(requiredParts[i].blobId);\n\t\t\t\t}\n\t\t\t}\n\t\t})();\n\t\treturn identity.readable;\n\t}\n\n\tasync #head(key: string): Promise<InternalR2Object> {\n\t\tvalidate.key(key);\n\n\t\tconst row = get(this.#stmts.getByKey({ key }));\n\t\tif (row === undefined) throw new NoSuchKey();\n\n\t\tconst range: R2Range = { offset: 0, length: row.size };\n\t\treturn new InternalR2Object(row, range);\n\t}\n\n\tasync #get(\n\t\tkey: string,\n\t\topts: InternalR2GetOptions\n\t): Promise<InternalR2ObjectBody | InternalR2Object> {\n\t\tvalidate.key(key);\n\n\t\t// Try to get this key, including multipart parts if it's multipart\n\t\tconst result = this.#stmts.getPartsByKey(key);\n\t\tif (result === undefined) throw new NoSuchKey();\n\t\tconst { row, parts } = result;\n\n\t\t// Validate pre-condition\n\t\tconst defaultR2Range: R2Range = { offset: 0, length: row.size };\n\t\ttry {\n\t\t\tvalidate.condition(row, opts.onlyIf);\n\t\t} catch (e) {\n\t\t\tif (e instanceof PreconditionFailed) {\n\t\t\t\te.attach(new InternalR2Object(row, defaultR2Range));\n\t\t\t}\n\t\t\tthrow e;\n\t\t}\n\n\t\t// Validate range, and convert to R2 range for return\n\t\tconst range = validate.range(opts, row.size);\n\t\tlet r2Range: R2Range;\n\t\tif (range === undefined) {\n\t\t\tr2Range = defaultR2Range;\n\t\t} else {\n\t\t\tconst start = range.start;\n\t\t\tconst end = Math.min(range.end, row.size);\n\t\t\tr2Range = { offset: start, length: end - start + 1 };\n\t\t}\n\n\t\tlet value: ReadableStream<Uint8Array> | null;\n\t\tif (row.blob_id === null) {\n\t\t\t// If this is a multipart object, we should've fetched multipart parts\n\t\t\tassert(parts !== undefined);\n\t\t\tconst defaultRange = { start: 0, end: row.size - 1 };\n\t\t\tvalue = this.#assembleMultipartValue(parts, range ?? defaultRange);\n\t\t} else {\n\t\t\t// Otherwise, just return a single part value\n\t\t\tvalue = await this.blob.get(row.blob_id, range);\n\t\t\tif (value === null) throw new NoSuchKey();\n\t\t}\n\n\t\treturn new InternalR2ObjectBody(row, value, r2Range);\n\t}\n\n\tasync #put(\n\t\tkey: string,\n\t\tvalue: ReadableStream<Uint8Array>,\n\t\tvalueSize: number,\n\t\topts: InternalR2PutOptions\n\t): Promise<InternalR2Object> {\n\t\t// Store value in the blob store, computing required digests as we go\n\t\t// (this means we don't have to buffer the entire stream to compute them)\n\t\tconst algorithms: DigestAlgorithm[] = [];\n\t\tfor (const { name, field } of R2_HASH_ALGORITHMS) {\n\t\t\t// Always compute MD5 digest\n\t\t\tif (field === \"md5\" || opts[field] !== undefined) algorithms.push(name);\n\t\t}\n\t\tconst digesting = new DigestingStream(algorithms);\n\t\tconst blobId = await this.blob.put(value.pipeThrough(digesting));\n\t\tconst digests = await digesting.digests;\n\t\tconst md5Digest = digests.get(\"MD5\");\n\t\tassert(md5Digest !== undefined);\n\t\tconst md5DigestHex = md5Digest.toString(\"hex\");\n\n\t\tconst checksums = validate\n\t\t\t.key(key)\n\t\t\t.size(valueSize)\n\t\t\t.metadataSize(opts.customMetadata)\n\t\t\t.hash(digests, opts);\n\t\tconst row: ObjectRow = {\n\t\t\tkey,\n\t\t\tblob_id: blobId,\n\t\t\tversion: generateVersion(),\n\t\t\tsize: valueSize,\n\t\t\tetag: md5DigestHex,\n\t\t\tuploaded: Date.now(),\n\t\t\tchecksums: JSON.stringify(checksums),\n\t\t\thttp_metadata: JSON.stringify(opts.httpMetadata ?? {}),\n\t\t\tcustom_metadata: JSON.stringify(opts.customMetadata ?? {}),\n\t\t};\n\t\tlet oldBlobIds: string[] | undefined;\n\t\ttry {\n\t\t\toldBlobIds = this.#stmts.put(row, opts.onlyIf);\n\t\t} catch (e) {\n\t\t\t// Probably precondition failed. In any case, the put transaction failed,\n\t\t\t// so we're not storing a reference to the blob ID\n\t\t\tthis.#backgroundDelete(blobId);\n\t\t\tthrow e;\n\t\t}\n\t\tif (oldBlobIds !== undefined) {\n\t\t\tfor (const blobId of oldBlobIds) this.#backgroundDelete(blobId);\n\t\t}\n\t\treturn new InternalR2Object(row);\n\t}\n\n\t#delete(keys: string | string[]) {\n\t\tif (!Array.isArray(keys)) keys = [keys];\n\t\tfor (const key of keys) validate.key(key);\n\t\tconst oldBlobIds = this.#stmts.deleteByKeys(keys);\n\t\tfor (const blobId of oldBlobIds) this.#backgroundDelete(blobId);\n\t}\n\n\t#listWithoutDelimiterQuery(excludeHttp: boolean, excludeCustom: boolean) {\n\t\tif (excludeHttp && excludeCustom) return this.#stmts.listWithoutDelimiter;\n\t\tif (excludeHttp) return this.#stmts.listCustomMetadataWithoutDelimiter;\n\t\tif (excludeCustom) return this.#stmts.listHttpMetadataWithoutDelimiter;\n\t\treturn this.#stmts.listHttpCustomMetadataWithoutDelimiter;\n\t}\n\n\tasync #list(opts: InternalR2ListOptions): Promise<InternalR2Objects> {\n\t\tconst prefix = opts.prefix ?? \"\";\n\n\t\tlet limit = opts.limit ?? R2Limits.MAX_LIST_KEYS;\n\t\tvalidate.limit(limit);\n\n\t\t// If metadata is requested, R2 may return fewer than `limit` results to\n\t\t// accommodate it. Simulate this by limiting the limit to 100.\n\t\t// See https://developers.cloudflare.com/r2/api/workers/workers-api-reference/#r2listoptions.\n\t\tconst include = opts.include ?? [];\n\t\tif (include.length > 0) limit = Math.min(limit, 100);\n\t\tconst excludeHttp = !include.includes(\"httpMetadata\");\n\t\tconst excludeCustom = !include.includes(\"customMetadata\");\n\t\tconst rowObject = (\n\t\t\trow: Omit<ObjectRow, \"blob_id\" | \"http_metadata\" | \"custom_metadata\"> & {\n\t\t\t\thttp_metadata?: string;\n\t\t\t\tcustom_metadata?: string;\n\t\t\t}\n\t\t) => {\n\t\t\tif (row.http_metadata === undefined || excludeHttp) {\n\t\t\t\trow.http_metadata = \"{}\";\n\t\t\t}\n\t\t\tif (row.custom_metadata === undefined || excludeCustom) {\n\t\t\t\trow.custom_metadata = \"{}\";\n\t\t\t}\n\t\t\treturn new InternalR2Object(row as Omit<ObjectRow, \"blob_id\">);\n\t\t};\n\n\t\t// If cursor set, and lexicographically after `startAfter`, use that for\n\t\t// `startAfter` instead\n\t\tlet startAfter = opts.startAfter;\n\t\tif (opts.cursor !== undefined) {\n\t\t\tconst cursorStartAfter = base64Decode(opts.cursor);\n\t\t\tif (startAfter === undefined || cursorStartAfter > startAfter) {\n\t\t\t\tstartAfter = cursorStartAfter;\n\t\t\t}\n\t\t}\n\n\t\tlet delimiter = opts.delimiter;\n\t\tif (delimiter === \"\") delimiter = undefined;\n\n\t\t// Run appropriate query depending on options\n\t\tconst params = {\n\t\t\tprefix,\n\t\t\tstart_after: startAfter ?? null,\n\t\t\t// Increase the queried limit by 1, if we return this many results, we\n\t\t\t// know there are more rows. We'll truncate to the original limit before\n\t\t\t// returning results.\n\t\t\tlimit: limit + 1,\n\t\t};\n\n\t\tlet objects: InternalR2Object[];\n\t\tconst delimitedPrefixes: string[] = [];\n\t\tlet nextCursorStartAfter: string | undefined;\n\n\t\tif (delimiter !== undefined) {\n\t\t\tconst rows = all(this.#stmts.listMetadata({ ...params, delimiter }));\n\n\t\t\t// If there are more results, we'll be returning a cursor\n\t\t\tconst hasMoreRows = rows.length === limit + 1;\n\t\t\trows.splice(limit, 1);\n\n\t\t\tobjects = [];\n\t\t\tfor (const row of rows) {\n\t\t\t\tif (row.delimited_prefix_or_key.startsWith(\"dlp:\")) {\n\t\t\t\t\tdelimitedPrefixes.push(row.delimited_prefix_or_key.substring(4));\n\t\t\t\t} else {\n\t\t\t\t\tobjects.push(rowObject({ ...row, key: row.last_key }));\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tif (hasMoreRows) nextCursorStartAfter = rows[limit - 1].last_key;\n\t\t} else {\n\t\t\t// If we don't have a delimiter, we can use a more efficient query\n\t\t\tconst query = this.#listWithoutDelimiterQuery(excludeHttp, excludeCustom);\n\t\t\tconst rows = all(query(params));\n\n\t\t\t// If there are more results, we'll be returning a cursor\n\t\t\tconst hasMoreRows = rows.length === limit + 1;\n\t\t\trows.splice(limit, 1);\n\n\t\t\tobjects = rows.map(rowObject);\n\n\t\t\tif (hasMoreRows) nextCursorStartAfter = rows[limit - 1].key;\n\t\t}\n\n\t\t// The cursor encodes a key to start after rather than the key to start at\n\t\t// to ensure keys added between `list()` calls are returned.\n\t\tconst nextCursor = maybeApply(base64Encode, nextCursorStartAfter);\n\n\t\treturn {\n\t\t\tobjects,\n\t\t\ttruncated: nextCursor !== undefined,\n\t\t\tcursor: nextCursor,\n\t\t\tdelimitedPrefixes,\n\t\t};\n\t}\n\n\tasync #createMultipartUpload(\n\t\tkey: string,\n\t\topts: InternalR2CreateMultipartUploadOptions\n\t): Promise<R2CreateMultipartUploadResponse> {\n\t\tvalidate.key(key);\n\n\t\tconst uploadId = generateId();\n\t\tthis.#stmts.createMultipartUpload({\n\t\t\tkey,\n\t\t\tupload_id: uploadId,\n\t\t\thttp_metadata: JSON.stringify(opts.httpMetadata ?? {}),\n\t\t\tcustom_metadata: JSON.stringify(opts.customMetadata ?? {}),\n\t\t});\n\t\treturn { uploadId };\n\t}\n\n\tasync #uploadPart(\n\t\tkey: string,\n\t\tuploadId: string,\n\t\tpartNumber: number,\n\t\tvalue: ReadableStream<Uint8Array>,\n\t\tvalueSize: number\n\t): Promise<R2UploadPartResponse> {\n\t\tvalidate.key(key);\n\n\t\t// Store value in the blob store, computing MD5 digest as we go\n\t\tconst digesting = new DigestingStream([\"MD5\"]);\n\t\tconst blobId = await this.blob.put(value.pipeThrough(digesting));\n\t\tconst digests = await digesting.digests;\n\t\tconst md5Digest = digests.get(\"MD5\");\n\t\tassert(md5Digest !== undefined);\n\n\t\t// Generate random ETag for this part\n\t\tconst etag = generateId();\n\n\t\t// Store the new part in the metadata store, removing the old blob\n\t\t// associated with this part number if any\n\t\tlet maybeOldBlobId: string | undefined;\n\t\ttry {\n\t\t\tmaybeOldBlobId = this.#stmts.putPart(key, {\n\t\t\t\tupload_id: uploadId,\n\t\t\t\tpart_number: partNumber,\n\t\t\t\tblob_id: blobId,\n\t\t\t\tsize: valueSize,\n\t\t\t\tetag,\n\t\t\t\tchecksum_md5: md5Digest.toString(\"hex\"),\n\t\t\t});\n\t\t} catch (e) {\n\t\t\t// Probably upload not found. In any case, the put transaction failed,\n\t\t\t// so we're not storing a reference to the blob ID\n\t\t\tthis.#backgroundDelete(blobId);\n\t\t\tthrow e;\n\t\t}\n\t\tif (maybeOldBlobId !== undefined) this.#backgroundDelete(maybeOldBlobId);\n\n\t\treturn { etag };\n\t}\n\n\tasync #completeMultipartUpload(\n\t\tkey: string,\n\t\tuploadId: string,\n\t\tparts: R2PublishedPart[]\n\t): Promise<InternalR2Object> {\n\t\tvalidate.key(key);\n\t\tconst minPartSize = this.beingTested\n\t\t\t? R2Limits.MIN_MULTIPART_PART_SIZE_TEST\n\t\t\t: R2Limits.MIN_MULTIPART_PART_SIZE;\n\t\tconst { newRow, oldBlobIds } = this.#stmts.completeMultipartUpload(\n\t\t\tkey,\n\t\t\tuploadId,\n\t\t\tparts,\n\t\t\tminPartSize\n\t\t);\n\t\tfor (const blobId of oldBlobIds) this.#backgroundDelete(blobId);\n\t\treturn new InternalR2Object(newRow);\n\t}\n\n\tasync #abortMultipartUpload(key: string, uploadId: string): Promise<void> {\n\t\tvalidate.key(key);\n\t\tconst oldBlobIds = this.#stmts.abortMultipartUpload(key, uploadId);\n\t\tfor (const blobId of oldBlobIds) this.#backgroundDelete(blobId);\n\t}\n\n\t@GET(\"/\")\n\tget: RouteHandler = async (req) => {\n\t\tconst metadata = decodeHeaderMetadata(req);\n\n\t\tlet result: InternalR2Object | InternalR2ObjectBody | InternalR2Objects;\n\t\tif (metadata.method === \"head\") {\n\t\t\tresult = await this.#head(metadata.object);\n\t\t} else if (metadata.method === \"get\") {\n\t\t\tresult = await this.#get(metadata.object, metadata);\n\t\t} else if (metadata.method === \"list\") {\n\t\t\tresult = await this.#list(metadata);\n\t\t} else {\n\t\t\tthrow new InternalError();\n\t\t}\n\n\t\treturn encodeResult(result);\n\t};\n\n\t@PUT(\"/\")\n\tput: RouteHandler = async (req) => {\n\t\tconst { metadata, metadataSize, value } = await decodeMetadata(req);\n\n\t\tif (metadata.method === \"delete\") {\n\t\t\tawait this.#delete(\n\t\t\t\t\"object\" in metadata ? metadata.object : metadata.objects\n\t\t\t);\n\t\t\treturn new Response();\n\t\t} else if (metadata.method === \"put\") {\n\t\t\tconst contentLength = parseInt(\n\t\t\t\treq.headers.get(\"Content-Length\") ?? \"NaN\"\n\t\t\t);\n\t\t\t// `workerd` requires a known value size for R2 put requests:\n\t\t\t// - https://github.com/cloudflare/workerd/blob/e3479895a2ace28e4fd5f1399cea4c92291966ab/src/workerd/api/r2-rpc.c%2B%2B#L154-L156\n\t\t\t// - https://github.com/cloudflare/workerd/blob/e3479895a2ace28e4fd5f1399cea4c92291966ab/src/workerd/api/r2-rpc.c%2B%2B#L188-L189\n\t\t\tassert(!isNaN(contentLength));\n\t\t\tconst valueSize = contentLength - metadataSize;\n\t\t\tconst result = await this.#put(\n\t\t\t\tmetadata.object,\n\t\t\t\tvalue,\n\t\t\t\tvalueSize,\n\t\t\t\tmetadata\n\t\t\t);\n\t\t\treturn encodeResult(result);\n\t\t} else if (metadata.method === \"createMultipartUpload\") {\n\t\t\tconst result = await this.#createMultipartUpload(\n\t\t\t\tmetadata.object,\n\t\t\t\tmetadata\n\t\t\t);\n\t\t\treturn encodeJSONResult(result);\n\t\t} else if (metadata.method === \"uploadPart\") {\n\t\t\tconst contentLength = parseInt(\n\t\t\t\treq.headers.get(\"Content-Length\") ?? \"NaN\"\n\t\t\t);\n\t\t\t// `workerd` requires a known value size for R2 put requests as above\n\t\t\tassert(!isNaN(contentLength));\n\t\t\tconst valueSize = contentLength - metadataSize;\n\t\t\tconst result = await this.#uploadPart(\n\t\t\t\tmetadata.object,\n\t\t\t\tmetadata.uploadId,\n\t\t\t\tmetadata.partNumber,\n\t\t\t\tvalue,\n\t\t\t\tvalueSize\n\t\t\t);\n\t\t\treturn encodeJSONResult(result);\n\t\t} else if (metadata.method === \"completeMultipartUpload\") {\n\t\t\tconst result = await this.#completeMultipartUpload(\n\t\t\t\tmetadata.object,\n\t\t\t\tmetadata.uploadId,\n\t\t\t\tmetadata.parts\n\t\t\t);\n\t\t\treturn encodeResult(result);\n\t\t} else if (metadata.method === \"abortMultipartUpload\") {\n\t\t\tawait this.#abortMultipartUpload(metadata.object, metadata.uploadId);\n\t\t\treturn new Response();\n\t\t} else {\n\t\t\tthrow new InternalError(); // Unknown method: should never be reached\n\t\t}\n\t};\n}\n", "export const R2Limits = {\n\tMAX_LIST_KEYS: 1_000,\n\tMAX_KEY_SIZE: 1024,\n\t// https://developers.cloudflare.com/r2/platform/limits/\n\tMAX_VALUE_SIZE: 5_368_709_120 - 5_242_880, // 5 GiB - 5 MiB\n\tMAX_METADATA_SIZE: 2048, // 2048 B\n\tMIN_MULTIPART_PART_SIZE: 5 * 1024 * 1024,\n\tMIN_MULTIPART_PART_SIZE_TEST: 50,\n} as const;\n\n/** AWS SigV4 credentials guarding a bucket on the local S3 endpoint */\nexport interface S3Credentials {\n\taccessKeyId: string;\n\tsecretAccessKey: string;\n}\n\nexport const R2S3Bindings = {\n\t/** JSON map of bucket id to `{ accessKeyId, secretAccessKey }` */\n\tJSON_CREDENTIALS: \"MINIFLARE_R2_S3_CREDENTIALS\",\n\t/** Prefix for per-bucket `R2Bucket` bindings (followed by the bucket id) */\n\tBUCKET_PREFIX: \"MINIFLARE_R2_S3_BUCKET_\",\n} as const;\n\nexport const R2Headers = {\n\tERROR: \"cf-r2-error\",\n\tREQUEST: \"cf-r2-request\",\n\tMETADATA_SIZE: \"cf-r2-metadata-size\",\n} as const;\n", "import { HttpError } from \"miniflare:shared\";\nimport { R2Headers } from \"./constants\";\nimport type { InternalR2Object } from \"./r2Object.worker\";\nimport type { Buffer } from \"node:buffer\";\n\nconst R2ErrorCode = {\n\tINTERNAL_ERROR: 10001,\n\tNO_SUCH_OBJECT_KEY: 10007,\n\tENTITY_TOO_LARGE: 100100,\n\tENTITY_TOO_SMALL: 10011,\n\tMETADATA_TOO_LARGE: 10012,\n\tINVALID_OBJECT_NAME: 10020,\n\tINVALID_MAX_KEYS: 10022,\n\tNO_SUCH_UPLOAD: 10024,\n\tINVALID_PART: 10025,\n\tINVALID_ARGUMENT: 10029,\n\tPRECONDITION_FAILED: 10031,\n\tBAD_DIGEST: 10037,\n\tINVALID_RANGE: 10039,\n\tBAD_UPLOAD: 10048,\n} as const;\n\nexport class R2Error extends HttpError {\n\tobject?: InternalR2Object;\n\n\tconstructor(\n\t\tcode: number,\n\t\tmessage: string,\n\t\treadonly v4Code: number\n\t) {\n\t\tsuper(code, message);\n\t}\n\n\ttoResponse() {\n\t\tif (this.object !== undefined) {\n\t\t\tconst { metadataSize, value } = this.object.encode();\n\t\t\treturn new Response(value, {\n\t\t\t\tstatus: this.code,\n\t\t\t\theaders: {\n\t\t\t\t\t[R2Headers.METADATA_SIZE]: `${metadataSize}`,\n\t\t\t\t\t\"Content-Type\": \"application/json\",\n\t\t\t\t\t[R2Headers.ERROR]: JSON.stringify({\n\t\t\t\t\t\tmessage: this.message,\n\t\t\t\t\t\tversion: 1,\n\t\t\t\t\t\t// Note the lowercase 'c', which the runtime expects\n\t\t\t\t\t\tv4code: this.v4Code,\n\t\t\t\t\t}),\n\t\t\t\t},\n\t\t\t});\n\t\t}\n\t\treturn new Response(null, {\n\t\t\tstatus: this.code,\n\t\t\theaders: {\n\t\t\t\t[R2Headers.ERROR]: JSON.stringify({\n\t\t\t\t\tmessage: this.message,\n\t\t\t\t\tversion: 1,\n\t\t\t\t\t// Note the lowercase 'c', which the runtime expects\n\t\t\t\t\tv4code: this.v4Code,\n\t\t\t\t}),\n\t\t\t},\n\t\t});\n\t}\n\n\tcontext(info: string) {\n\t\tthis.message += ` (${info})`;\n\t\treturn this;\n\t}\n\n\tattach(object: InternalR2Object) {\n\t\tthis.object = object;\n\t\treturn this;\n\t}\n}\n\nexport class InvalidMetadata extends R2Error {\n\tconstructor() {\n\t\tsuper(400, \"Metadata missing or invalid\", R2ErrorCode.INVALID_ARGUMENT);\n\t}\n}\n\nexport class InternalError extends R2Error {\n\tconstructor() {\n\t\tsuper(\n\t\t\t500,\n\t\t\t\"We encountered an internal error. Please try again.\",\n\t\t\tR2ErrorCode.INTERNAL_ERROR\n\t\t);\n\t}\n}\nexport class NoSuchKey extends R2Error {\n\tconstructor() {\n\t\tsuper(\n\t\t\t404,\n\t\t\t\"The specified key does not exist.\",\n\t\t\tR2ErrorCode.NO_SUCH_OBJECT_KEY\n\t\t);\n\t}\n}\n\nexport class EntityTooLarge extends R2Error {\n\tconstructor() {\n\t\tsuper(\n\t\t\t400,\n\t\t\t\"Your proposed upload exceeds the maximum allowed object size.\",\n\t\t\tR2ErrorCode.ENTITY_TOO_LARGE\n\t\t);\n\t}\n}\n\nexport class EntityTooSmall extends R2Error {\n\tconstructor() {\n\t\tsuper(\n\t\t\t400,\n\t\t\t\"Your proposed upload is smaller than the minimum allowed object size.\",\n\t\t\tR2ErrorCode.ENTITY_TOO_SMALL\n\t\t);\n\t}\n}\n\nexport class MetadataTooLarge extends R2Error {\n\tconstructor() {\n\t\tsuper(\n\t\t\t400,\n\t\t\t\"Your metadata headers exceed the maximum allowed metadata size.\",\n\t\t\tR2ErrorCode.METADATA_TOO_LARGE\n\t\t);\n\t}\n}\n\nexport class BadDigest extends R2Error {\n\tconstructor(\n\t\talgorithm: \"MD5\" | \"SHA-1\" | \"SHA-256\" | \"SHA-384\" | \"SHA-512\",\n\t\tprovided: Buffer,\n\t\tcalculated: Buffer\n\t) {\n\t\tsuper(\n\t\t\t400,\n\t\t\t[\n\t\t\t\t`The ${algorithm} checksum you specified did not match what we received.`,\n\t\t\t\t`You provided a ${algorithm} checksum with value: ${provided.toString(\n\t\t\t\t\t\"hex\"\n\t\t\t\t)}`,\n\t\t\t\t`Actual ${algorithm} was: ${calculated.toString(\"hex\")}`,\n\t\t\t].join(\"\\n\"),\n\t\t\tR2ErrorCode.BAD_DIGEST\n\t\t);\n\t}\n}\n\nexport class InvalidObjectName extends R2Error {\n\tconstructor() {\n\t\tsuper(\n\t\t\t400,\n\t\t\t\"The specified object name is not valid.\",\n\t\t\tR2ErrorCode.INVALID_OBJECT_NAME\n\t\t);\n\t}\n}\n\nexport class InvalidMaxKeys extends R2Error {\n\tconstructor() {\n\t\tsuper(\n\t\t\t400,\n\t\t\t\"MaxKeys params must be positive integer <= 1000.\",\n\t\t\tR2ErrorCode.INVALID_MAX_KEYS\n\t\t);\n\t}\n}\n\nexport class NoSuchUpload extends R2Error {\n\tconstructor() {\n\t\tsuper(\n\t\t\t400,\n\t\t\t\"The specified multipart upload does not exist.\",\n\t\t\tR2ErrorCode.NO_SUCH_UPLOAD\n\t\t);\n\t}\n}\n\nexport class InvalidPart extends R2Error {\n\tconstructor() {\n\t\tsuper(\n\t\t\t400,\n\t\t\t\"One or more of the specified parts could not be found.\",\n\t\t\tR2ErrorCode.INVALID_PART\n\t\t);\n\t}\n}\n\nexport class PreconditionFailed extends R2Error {\n\tconstructor() {\n\t\tsuper(\n\t\t\t412,\n\t\t\t\"At least one of the pre-conditions you specified did not hold.\",\n\t\t\tR2ErrorCode.PRECONDITION_FAILED\n\t\t);\n\t}\n}\n\nexport class InvalidRange extends R2Error {\n\tconstructor() {\n\t\tsuper(\n\t\t\t416,\n\t\t\t\"The requested range is not satisfiable\",\n\t\t\tR2ErrorCode.INVALID_RANGE\n\t\t);\n\t}\n}\n\nexport class BadUpload extends R2Error {\n\tconstructor() {\n\t\tsuper(\n\t\t\t500,\n\t\t\t\"There was a problem with the multipart upload.\",\n\t\t\tR2ErrorCode.BAD_UPLOAD\n\t\t);\n\t}\n}\n", "import { HEX_REGEXP } from \"miniflare:zod\";\nimport type {\n\tObjectRow,\n\tR2HeadResponse,\n\tR2HttpFields,\n\tR2Range,\n} from \"./schemas.worker\";\n\nexport interface EncodedMetadata {\n\tmetadataSize: number;\n\tvalue: ReadableStream<Uint8Array>;\n\tsize: number;\n}\n\nexport class InternalR2Object {\n\treadonly key: string;\n\treadonly version: string;\n\treadonly size: number;\n\treadonly etag: string;\n\treadonly uploaded: number;\n\treadonly httpMetadata: R2HttpFields;\n\treadonly customMetadata: Record<string, string>;\n\treadonly range?: R2Range;\n\treadonly checksums: R2StringChecksums;\n\n\tconstructor(row: Omit<ObjectRow, \"blob_id\">, range?: R2Range) {\n\t\tthis.key = row.key;\n\t\tthis.version = row.version;\n\t\tthis.size = row.size;\n\t\tthis.etag = row.etag;\n\t\tthis.uploaded = row.uploaded;\n\t\tthis.httpMetadata = JSON.parse(row.http_metadata);\n\t\tthis.customMetadata = JSON.parse(row.custom_metadata);\n\t\tthis.range = range;\n\n\t\t// For non-multipart uploads, we always need to store an MD5 hash in\n\t\t// `checksums`. To avoid data duplication, we just use `etag` for this.\n\t\tconst checksums: R2StringChecksums = JSON.parse(row.checksums);\n\t\tif (this.etag.length === 32 && HEX_REGEXP.test(this.etag)) {\n\t\t\tchecksums.md5 = row.etag;\n\t\t}\n\t\tthis.checksums = checksums;\n\t}\n\n\t// Format for return to the Workers Runtime\n\t#rawProperties(): R2HeadResponse {\n\t\treturn {\n\t\t\tname: this.key,\n\t\t\tversion: this.version,\n\t\t\tsize: this.size,\n\t\t\tetag: this.etag,\n\t\t\tuploaded: this.uploaded,\n\t\t\thttpFields: this.httpMetadata,\n\t\t\tcustomFields: Object.entries(this.customMetadata).map(([k, v]) => ({\n\t\t\t\tk,\n\t\t\t\tv,\n\t\t\t})),\n\t\t\trange: this.range,\n\t\t\tchecksums: {\n\t\t\t\t0: this.checksums.md5,\n\t\t\t\t1: this.checksums.sha1,\n\t\t\t\t2: this.checksums.sha256,\n\t\t\t\t3: this.checksums.sha384,\n\t\t\t\t4: this.checksums.sha512,\n\t\t\t},\n\t\t};\n\t}\n\n\tencode(): EncodedMetadata {\n\t\tconst json = JSON.stringify(this.#rawProperties());\n\t\tconst blob = new Blob([json]);\n\t\treturn { metadataSize: blob.size, value: blob.stream(), size: blob.size };\n\t}\n\n\tstatic encodeMultiple(objects: InternalR2Objects): EncodedMetadata {\n\t\tconst json = JSON.stringify({\n\t\t\t...objects,\n\t\t\tobjects: objects.objects.map((o) => o.#rawProperties()),\n\t\t});\n\t\tconst blob = new Blob([json]);\n\t\treturn { metadataSize: blob.size, value: blob.stream(), size: blob.size };\n\t}\n}\n\nexport class InternalR2ObjectBody extends InternalR2Object {\n\tconstructor(\n\t\tmetadata: Omit<ObjectRow, \"blob_id\">,\n\t\treadonly body: ReadableStream<Uint8Array>,\n\t\trange?: R2Range\n\t) {\n\t\tsuper(metadata, range);\n\t}\n\n\tencode(): EncodedMetadata {\n\t\tconst { metadataSize, value: metadata } = super.encode();\n\t\tconst size = this.range?.length ?? this.size;\n\t\tconst identity = new FixedLengthStream(size + metadataSize);\n\t\tvoid metadata\n\t\t\t.pipeTo(identity.writable, { preventClose: true })\n\t\t\t.then(() => this.body.pipeTo(identity.writable));\n\t\treturn {\n\t\t\tmetadataSize: metadataSize,\n\t\t\tvalue: identity.readable,\n\t\t\tsize,\n\t\t};\n\t}\n}\n\nexport interface InternalR2Objects {\n\t// An array of objects matching the list request.\n\tobjects: InternalR2Object[];\n\t// If true, indicates there are more results to be retrieved for the current\n\t// list request.\n\ttruncated: boolean;\n\t// A token that can be passed to future list calls to resume listing from that\n\t// point.\n\t// Only present if truncated is true.\n\tcursor?: string;\n\t// If a delimiter has been specified, contains all prefixes between the\n\t// specified prefix and the next occurrence of the delimiter. For example, if\n\t// no prefix is provided and the delimiter is \"/\", \"foo/bar/baz\" would return\n\t// \"foo\" as a delimited prefix. If \"foo/\" was passed as a prefix with the same\n\t// structure and delimiter, \"foo/bar\" would be returned as a delimited prefix.\n\tdelimitedPrefixes: string[];\n}\n", "import { Base64DataSchema, HexDataSchema, z } from \"miniflare:zod\";\nimport type { ValueOf } from \"miniflare:shared\";\n\nexport type ObjectRow = {\n\tkey: string;\n\tblob_id: string | null; // null if multipart\n\tversion: string;\n\tsize: number; // total size of object (all parts) in bytes\n\tetag: string; // hex MD5 hash if not multipart\n\tuploaded: number; // milliseconds since unix epoch\n\tchecksums: string; // JSON-serialised `R2StringChecksums` (workers-types)\n\thttp_metadata: string; // JSON-serialised `R2HTTPMetadata` (workers-types)\n\tcustom_metadata: string; // JSON-serialised user-defined metadata\n};\nexport const MultipartUploadState = {\n\tIN_PROGRESS: 0,\n\tCOMPLETED: 1,\n\tABORTED: 2,\n} as const;\nexport type MultipartUploadRow = {\n\tupload_id: string;\n\tkey: string;\n\thttp_metadata: string; // JSON-serialised `R2HTTPMetadata` (workers-types)\n\tcustom_metadata: string; // JSON-serialised user-defined metadata\n\tstate: ValueOf<typeof MultipartUploadState>;\n\t// NOTE: we need to keep completed/aborted uploads around for referential\n\t// integrity, and because error messages are different when attempting to\n\t// upload parts to them\n};\nexport type MultipartPartRow = {\n\tupload_id: string;\n\tpart_number: number;\n\tblob_id: string;\n\tsize: number; // NOTE: used to identify which parts to read for range requests\n\tetag: string; // NOTE: multipart part ETag's are not MD5 checksums\n\tchecksum_md5: string; // NOTE: used in construction of final object's ETag\n\tobject_key: string | null; // null if in-progress upload\n};\nexport const SQL_SCHEMA = `\nCREATE TABLE IF NOT EXISTS _mf_objects (\n    key TEXT PRIMARY KEY,\n    blob_id TEXT,\n    version TEXT NOT NULL,\n    size INTEGER NOT NULL,\n    etag TEXT NOT NULL,\n    uploaded INTEGER NOT NULL,\n    checksums TEXT NOT NULL,\n    http_metadata TEXT NOT NULL,\n    custom_metadata TEXT NOT NULL\n);\nCREATE TABLE IF NOT EXISTS _mf_multipart_uploads (\n    upload_id TEXT PRIMARY KEY,\n    key TEXT NOT NULL,\n    http_metadata TEXT NOT NULL,\n    custom_metadata TEXT NOT NULL,\n    state TINYINT DEFAULT 0 NOT NULL\n);\nCREATE TABLE IF NOT EXISTS _mf_multipart_parts (\n    upload_id TEXT NOT NULL REFERENCES _mf_multipart_uploads(upload_id),\n    part_number INTEGER NOT NULL,\n    blob_id TEXT NOT NULL,\n    size INTEGER NOT NULL,\n    etag TEXT NOT NULL,\n    checksum_md5 TEXT NOT NULL,\n    object_key TEXT REFERENCES _mf_objects(key) DEFERRABLE INITIALLY DEFERRED,\n    PRIMARY KEY (upload_id, part_number)\n);\n`;\n// NOTE: `object_key` foreign key constraint is deferred, meaning we can delete\n// the linked object row, *then* the multipart part rows in a transaction,\n// see https://www.sqlite.org/foreignkeys.html#fk_deferred for more details\n\n// https://github.com/cloudflare/workerd/blob/4290f9717bc94647d9c8afd29602cdac97fdff1b/src/workerd/api/r2-api.capnp\n\nexport const DateSchema = z.coerce\n\t.number()\n\t.transform((value) => new Date(value));\n\nexport const RecordSchema = z\n\t.object({\n\t\tk: z.string(),\n\t\tv: z.string(),\n\t})\n\t.array()\n\t.transform((entries) =>\n\t\tObject.fromEntries(entries.map(({ k, v }) => [k, v]))\n\t);\nexport type RawRecord = z.input<typeof RecordSchema>;\n\nexport const R2RangeSchema = z.object({\n\toffset: z.coerce.number().optional(),\n\tlength: z.coerce.number().optional(),\n\tsuffix: z.coerce.number().optional(),\n});\nexport type R2Range = z.infer<typeof R2RangeSchema>;\n\nexport const R2EtagSchema = z.discriminatedUnion(\"type\", [\n\tz.object({ type: z.literal(\"strong\"), value: z.string() }),\n\tz.object({ type: z.literal(\"weak\"), value: z.string() }),\n\tz.object({ type: z.literal(\"wildcard\") }),\n]);\nexport type R2Etag = z.infer<typeof R2EtagSchema>;\nexport const R2EtagMatchSchema = R2EtagSchema.array().min(1).optional();\n\n// For more information, refer to https://datatracker.ietf.org/doc/html/rfc7232\nexport const R2ConditionalSchema = z.object({\n\t// Performs the operation if the object's ETag matches the given string\n\tetagMatches: R2EtagMatchSchema, // \"If-Match\"\n\t// Performs the operation if the object's ETag does NOT match the given string\n\tetagDoesNotMatch: R2EtagMatchSchema, // \"If-None-Match\"\n\t// Performs the operation if the object was uploaded BEFORE the given date\n\tuploadedBefore: DateSchema.optional(), // \"If-Unmodified-Since\"\n\t// Performs the operation if the object was uploaded AFTER the given date\n\tuploadedAfter: DateSchema.optional(), // \"If-Modified-Since\"\n\t// Truncates dates to seconds before performing comparisons\n\tsecondsGranularity: z.boolean().optional(),\n});\nexport type R2Conditional = z.infer<typeof R2ConditionalSchema>;\n\nexport const R2ChecksumsSchema = z\n\t.object({\n\t\t0: HexDataSchema.optional(),\n\t\t1: HexDataSchema.optional(),\n\t\t2: HexDataSchema.optional(),\n\t\t3: HexDataSchema.optional(),\n\t\t4: HexDataSchema.optional(),\n\t})\n\t.transform((checksums) => ({\n\t\tmd5: checksums[\"0\"],\n\t\tsha1: checksums[\"1\"],\n\t\tsha256: checksums[\"2\"],\n\t\tsha384: checksums[\"3\"],\n\t\tsha512: checksums[\"4\"],\n\t}));\nexport type RawR2Checksums = z.input<typeof R2ChecksumsSchema>;\nexport type R2Checksums = z.infer<typeof R2ChecksumsSchema>;\n\nexport const R2PublishedPartSchema = z.object({\n\tetag: z.string(),\n\tpart: z.number(),\n});\nexport type R2PublishedPart = z.infer<typeof R2PublishedPartSchema>;\n\nexport const R2HttpFieldsSchema = z.object({\n\tcontentType: z.string().optional(),\n\tcontentLanguage: z.string().optional(),\n\tcontentDisposition: z.string().optional(),\n\tcontentEncoding: z.string().optional(),\n\tcacheControl: z.string().optional(),\n\tcacheExpiry: z.coerce.number().optional(),\n});\nexport type R2HttpFields = z.infer<typeof R2HttpFieldsSchema>;\n\nexport const R2HeadRequestSchema = z.object({\n\tmethod: z.literal(\"head\"),\n\tobject: z.string(),\n});\n\nexport const R2GetRequestSchema = z.object({\n\tmethod: z.literal(\"get\"),\n\tobject: z.string(),\n\t// Specifies that only a specific length (from an optional offset) or suffix\n\t// of bytes from the object should be returned. Refer to\n\t// https://developers.cloudflare.com/r2/runtime-apis/#ranged-reads.\n\trange: R2RangeSchema.optional(),\n\trangeHeader: z.string().optional(),\n\t// Specifies that the object should only be returned given satisfaction of\n\t// certain conditions in the R2Conditional. Refer to R2Conditional above.\n\tonlyIf: R2ConditionalSchema.optional(),\n});\n\nexport const R2PutRequestSchema = z\n\t.object({\n\t\tmethod: z.literal(\"put\"),\n\t\tobject: z.string(),\n\t\tcustomFields: RecordSchema.optional(), // (renamed in transform)\n\t\thttpFields: R2HttpFieldsSchema.optional(), // (renamed in transform)\n\t\tonlyIf: R2ConditionalSchema.optional(),\n\t\tmd5: Base64DataSchema.optional(), // (intentionally base64, not hex)\n\t\tsha1: HexDataSchema.optional(),\n\t\tsha256: HexDataSchema.optional(),\n\t\tsha384: HexDataSchema.optional(),\n\t\tsha512: HexDataSchema.optional(),\n\t})\n\t.transform((value) => ({\n\t\tmethod: value.method,\n\t\tobject: value.object,\n\t\tcustomMetadata: value.customFields,\n\t\thttpMetadata: value.httpFields,\n\t\tonlyIf: value.onlyIf,\n\t\tmd5: value.md5,\n\t\tsha1: value.sha1,\n\t\tsha256: value.sha256,\n\t\tsha384: value.sha384,\n\t\tsha512: value.sha512,\n\t}));\n\nexport const R2CreateMultipartUploadRequestSchema = z\n\t.object({\n\t\tmethod: z.literal(\"createMultipartUpload\"),\n\t\tobject: z.string(),\n\t\tcustomFields: RecordSchema.optional(), // (renamed in transform)\n\t\thttpFields: R2HttpFieldsSchema.optional(), // (renamed in transform)\n\t})\n\t.transform((value) => ({\n\t\tmethod: value.method,\n\t\tobject: value.object,\n\t\tcustomMetadata: value.customFields,\n\t\thttpMetadata: value.httpFields,\n\t}));\n\nexport const R2UploadPartRequestSchema = z.object({\n\tmethod: z.literal(\"uploadPart\"),\n\tobject: z.string(),\n\tuploadId: z.string(),\n\tpartNumber: z.number(),\n});\n\nexport const R2CompleteMultipartUploadRequestSchema = z.object({\n\tmethod: z.literal(\"completeMultipartUpload\"),\n\tobject: z.string(),\n\tuploadId: z.string(),\n\tparts: R2PublishedPartSchema.array(),\n});\n\nexport const R2AbortMultipartUploadRequestSchema = z.object({\n\tmethod: z.literal(\"abortMultipartUpload\"),\n\tobject: z.string(),\n\tuploadId: z.string(),\n});\n\nexport const R2ListRequestSchema = z.object({\n\tmethod: z.literal(\"list\"),\n\tlimit: z.number().optional(),\n\tprefix: z.string().optional(),\n\tcursor: z.string().optional(),\n\tdelimiter: z.string().optional(),\n\tstartAfter: z.string().optional(),\n\tinclude: z\n\t\t.union([z.literal(0), z.literal(1)])\n\t\t.transform((value) => (value === 0 ? \"httpMetadata\" : \"customMetadata\"))\n\t\t.array()\n\t\t.optional(),\n});\n\nexport const R2DeleteRequestSchema = z.intersection(\n\tz.object({ method: z.literal(\"delete\") }),\n\tz.union([\n\t\tz.object({ object: z.string() }),\n\t\tz.object({ objects: z.string().array() }),\n\t])\n);\n\n// Not using `z.discriminatedUnion()` here, as that doesn't work with\n// intersection/transformed types.\n// TODO(someday): switch to proposed `z.switch()`: https://github.com/colinhacks/zod/issues/2106\nexport const R2BindingRequestSchema = z.union([\n\tR2HeadRequestSchema,\n\tR2GetRequestSchema,\n\tR2PutRequestSchema,\n\tR2CreateMultipartUploadRequestSchema,\n\tR2UploadPartRequestSchema,\n\tR2CompleteMultipartUploadRequestSchema,\n\tR2AbortMultipartUploadRequestSchema,\n\tR2ListRequestSchema,\n\tR2DeleteRequestSchema,\n]);\n\nexport type OmitRequest<T> = Omit<T, \"method\" | \"object\">;\nexport type InternalR2GetOptions = OmitRequest<\n\tz.infer<typeof R2GetRequestSchema>\n>;\nexport type InternalR2PutOptions = OmitRequest<\n\tz.infer<typeof R2PutRequestSchema>\n>;\nexport type InternalR2ListOptions = OmitRequest<\n\tz.infer<typeof R2ListRequestSchema>\n>;\nexport type InternalR2CreateMultipartUploadOptions = OmitRequest<\n\tz.infer<typeof R2CreateMultipartUploadRequestSchema>\n>;\n\nexport interface R2ErrorResponse {\n\tversion: number;\n\tv4code: number;\n\tmessage: string;\n}\n\nexport interface R2HeadResponse {\n\tname: string;\n\tversion: string;\n\tsize: number;\n\tetag: string;\n\tuploaded: number;\n\t// Optional: https://github.com/cloudflare/workerd/blob/4290f9717bc94647d9c8afd29602cdac97fdff1b/src/workerd/api/r2-bucket.c%2B%2B#L81\n\thttpFields?: R2HttpFields;\n\t// Optional: https://github.com/cloudflare/workerd/blob/4290f9717bc94647d9c8afd29602cdac97fdff1b/src/workerd/api/r2-bucket.c%2B%2B#L113\n\tcustomFields?: RawRecord;\n\t// Optional: https://github.com/cloudflare/workerd/blob/4290f9717bc94647d9c8afd29602cdac97fdff1b/src/workerd/api/r2-bucket.c%2B%2B#L130\n\trange?: R2Range;\n\t// Optional: https://github.com/cloudflare/workerd/blob/4290f9717bc94647d9c8afd29602cdac97fdff1b/src/workerd/api/r2-bucket.c%2B%2B#L140\n\tchecksums?: RawR2Checksums;\n}\n\nexport type R2GetResponse = R2HeadResponse;\n\nexport type R2PutResponse = R2HeadResponse;\n\nexport interface R2CreateMultipartUploadResponse {\n\tuploadId: string;\n}\n\nexport interface R2UploadPartResponse {\n\tetag: string;\n}\n\nexport type R2CompleteMultipartUploadResponse = R2PutResponse;\n\n// eslint-disable-next-line @typescript-eslint/no-empty-object-type -- empty interface is intentional; represents an R2 response with no body fields\nexport interface R2AbortMultipartUploadResponse {}\n\nexport interface R2ListResponse {\n\tobjects: R2HeadResponse[];\n\ttruncated: boolean;\n\tcursor?: string;\n\tdelimitedPrefixes: string[];\n}\n\n// eslint-disable-next-line @typescript-eslint/no-empty-object-type -- Empty interface is intentional; represents an R2 response with no body fields\nexport interface R2DeleteResponse {}\n", "import assert from \"node:assert\";\nimport { Buffer } from \"node:buffer\";\nimport { parseRanges } from \"miniflare:shared\";\nimport { R2Limits } from \"./constants\";\nimport {\n\tBadDigest,\n\tEntityTooLarge,\n\tInvalidMaxKeys,\n\tInvalidObjectName,\n\tInvalidRange,\n\tMetadataTooLarge,\n\tPreconditionFailed,\n} from \"./errors.worker\";\nimport type { InternalR2Object } from \"./r2Object.worker\";\nimport type {\n\tInternalR2GetOptions,\n\tR2Conditional,\n\tR2Etag,\n} from \"./schemas.worker\";\nimport type { InclusiveRange } from \"miniflare:shared\";\n\nfunction identity(ms: number) {\n\treturn ms;\n}\nfunction truncateToSeconds(ms: number) {\n\treturn Math.floor(ms / 1000) * 1000;\n}\n\nfunction includesEtag(\n\tconditions: R2Etag[],\n\tetag: string,\n\tcomparison: \"strong\" | \"weak\"\n) {\n\t// Adapted from internal R2 gateway implementation.\n\tfor (const condition of conditions) {\n\t\tif (condition.type === \"wildcard\") return true;\n\t\tif (condition.value === etag) {\n\t\t\tif (condition.type === \"strong\" || comparison === \"weak\") return true;\n\t\t}\n\t}\n\treturn false;\n}\n\n// Returns `true` iff the condition passed\n/** @internal */\nexport function _testR2Conditional(\n\tcond: R2Conditional,\n\tmetadata?: Pick<InternalR2Object, \"etag\" | \"uploaded\">\n): boolean {\n\t// Adapted from internal R2 gateway implementation.\n\t// See also https://datatracker.ietf.org/doc/html/rfc7232#section-6.\n\n\tif (metadata === undefined) {\n\t\tconst ifMatch = cond.etagMatches === undefined;\n\t\tconst ifModifiedSince = cond.uploadedAfter === undefined;\n\t\treturn ifMatch && ifModifiedSince;\n\t}\n\n\tconst { etag, uploaded: lastModifiedRaw } = metadata;\n\tconst ifMatch =\n\t\tcond.etagMatches === undefined ||\n\t\tincludesEtag(cond.etagMatches, etag, \"strong\");\n\tconst ifNoneMatch =\n\t\tcond.etagDoesNotMatch === undefined ||\n\t\t!includesEtag(cond.etagDoesNotMatch, etag, \"weak\");\n\n\tconst maybeTruncate = cond.secondsGranularity ? truncateToSeconds : identity;\n\tconst lastModified = maybeTruncate(lastModifiedRaw);\n\tconst ifModifiedSince =\n\t\tcond.uploadedAfter === undefined ||\n\t\tmaybeTruncate(cond.uploadedAfter.getTime()) < lastModified ||\n\t\t(cond.etagDoesNotMatch !== undefined && ifNoneMatch);\n\tconst ifUnmodifiedSince =\n\t\tcond.uploadedBefore === undefined ||\n\t\tlastModified < maybeTruncate(cond.uploadedBefore.getTime()) ||\n\t\t(cond.etagMatches !== undefined && ifMatch);\n\n\treturn ifMatch && ifNoneMatch && ifModifiedSince && ifUnmodifiedSince;\n}\n\nexport const R2_HASH_ALGORITHMS = [\n\t{ name: \"MD5\", field: \"md5\" },\n\t{ name: \"SHA-1\", field: \"sha1\" },\n\t{ name: \"SHA-256\", field: \"sha256\" },\n\t{ name: \"SHA-384\", field: \"sha384\" },\n\t{ name: \"SHA-512\", field: \"sha512\" },\n] as const;\nexport type R2Hashes = Record<\n\t(typeof R2_HASH_ALGORITHMS)[number][\"field\"],\n\tBuffer | undefined\n>;\nexport type DigestAlgorithm = (typeof R2_HASH_ALGORITHMS)[number][\"name\"];\n\nfunction serialisedLength(x: string) {\n\t//  Adapted from internal R2 gateway implementation\n\tfor (let i = 0; i < x.length; i++) {\n\t\tif (x.charCodeAt(i) >= 256) return x.length * 2;\n\t}\n\treturn x.length;\n}\n\nexport class Validator {\n\thash(\n\t\tdigests: Map<DigestAlgorithm, Buffer>,\n\t\thashes: R2Hashes\n\t): R2StringChecksums {\n\t\tconst checksums: R2StringChecksums = {};\n\t\tfor (const { name, field } of R2_HASH_ALGORITHMS) {\n\t\t\tconst providedHash = hashes[field];\n\t\t\tif (providedHash !== undefined) {\n\t\t\t\tconst computedHash = digests.get(name);\n\t\t\t\t// Should've computed all required digests\n\t\t\t\tassert(computedHash !== undefined);\n\t\t\t\tif (!providedHash.equals(computedHash)) {\n\t\t\t\t\tthrow new BadDigest(name, providedHash, computedHash);\n\t\t\t\t}\n\t\t\t\t// Store computed hash to ensure consistent casing in returned checksums\n\t\t\t\t// from `R2Object`\n\t\t\t\tchecksums[field] = computedHash.toString(\"hex\");\n\t\t\t}\n\t\t}\n\t\treturn checksums;\n\t}\n\n\tcondition(\n\t\tmeta?: Pick<InternalR2Object, \"etag\" | \"uploaded\">,\n\t\tonlyIf?: R2Conditional\n\t): Validator {\n\t\tif (onlyIf !== undefined && !_testR2Conditional(onlyIf, meta)) {\n\t\t\tthrow new PreconditionFailed();\n\t\t}\n\t\treturn this;\n\t}\n\n\trange(\n\t\toptions: Pick<InternalR2GetOptions, \"rangeHeader\" | \"range\">,\n\t\tsize: number\n\t): InclusiveRange | undefined {\n\t\tif (options.rangeHeader !== undefined) {\n\t\t\tconst ranges = parseRanges(options.rangeHeader, size);\n\t\t\t// If the header contained a single range, use it. Otherwise, if the\n\t\t\t// header was invalid, or contained multiple ranges, just return the full\n\t\t\t// response (by returning undefined from this function).\n\t\t\tif (ranges?.length === 1) return ranges[0];\n\t\t} else if (options.range !== undefined) {\n\t\t\tlet { offset, length, suffix } = options.range;\n\t\t\t// Eliminate suffix if specified\n\t\t\tif (suffix !== undefined) {\n\t\t\t\tif (suffix <= 0) throw new InvalidRange();\n\t\t\t\tif (suffix > size) suffix = size;\n\t\t\t\toffset = size - suffix;\n\t\t\t\tlength = suffix;\n\t\t\t}\n\t\t\t// Validate offset and length\n\t\t\tif (offset === undefined) offset = 0;\n\t\t\tif (length === undefined) length = size - offset;\n\t\t\tif (offset < 0 || offset > size || length <= 0) throw new InvalidRange();\n\t\t\t// Clamp length to maximum\n\t\t\tif (offset + length > size) length = size - offset;\n\t\t\t// Convert to inclusive range\n\t\t\treturn { start: offset, end: offset + length - 1 };\n\t\t}\n\t}\n\n\tsize(size: number): Validator {\n\t\tif (size > R2Limits.MAX_VALUE_SIZE) {\n\t\t\tthrow new EntityTooLarge();\n\t\t}\n\t\treturn this;\n\t}\n\n\tmetadataSize(customMetadata?: Record<string, string>): Validator {\n\t\tif (customMetadata === undefined) return this;\n\t\tlet metadataLength = 0;\n\t\tfor (const [key, value] of Object.entries(customMetadata)) {\n\t\t\tmetadataLength += serialisedLength(key) + serialisedLength(value);\n\t\t}\n\t\tif (metadataLength > R2Limits.MAX_METADATA_SIZE) {\n\t\t\tthrow new MetadataTooLarge();\n\t\t}\n\t\treturn this;\n\t}\n\n\tkey(key: string): Validator {\n\t\tconst keyLength = Buffer.byteLength(key);\n\t\tif (keyLength > R2Limits.MAX_KEY_SIZE) {\n\t\t\tthrow new InvalidObjectName();\n\t\t}\n\t\treturn this;\n\t}\n\n\tlimit(limit?: number): Validator {\n\t\tif (limit !== undefined && (limit < 1 || limit > R2Limits.MAX_LIST_KEYS)) {\n\t\t\tthrow new InvalidMaxKeys();\n\t\t}\n\t\treturn this;\n\t}\n}\n"],
  "mappings": ";;;;;;;;;AAAA,OAAOA,aAAY;AACnB,SAAS,UAAAC,eAAc;AACvB,SAAS,kBAAkB;AAC3B;AAAA,EACC;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,OACM;;;ACfA,IAAM,WAAW;AAAA,EACvB,eAAe;AAAA,EACf,cAAc;AAAA;AAAA,EAEd,gBAAgB;AAAA;AAAA,EAChB,mBAAmB;AAAA;AAAA,EACnB,yBAAyB;AAAA,EACzB,8BAA8B;AAC/B;AAeO,IAAM,YAAY;AAAA,EACxB,OAAO;AAAA,EACP,SAAS;AAAA,EACT,eAAe;AAChB;;;AC3BA,SAAS,iBAAiB;AAK1B,IAAM,cAAc;AAAA,EACnB,gBAAgB;AAAA,EAChB,oBAAoB;AAAA,EACpB,kBAAkB;AAAA,EAClB,kBAAkB;AAAA,EAClB,oBAAoB;AAAA,EACpB,qBAAqB;AAAA,EACrB,kBAAkB;AAAA,EAClB,gBAAgB;AAAA,EAChB,cAAc;AAAA,EACd,kBAAkB;AAAA,EAClB,qBAAqB;AAAA,EACrB,YAAY;AAAA,EACZ,eAAe;AAAA,EACf,YAAY;AACb,GAEa,UAAN,cAAsB,UAAU;AAAA,EAGtC,YACC,MACA,SACS,QACR;AACD,UAAM,MAAM,OAAO;AAFV;AAAA,EAGV;AAAA,EAHU;AAAA,EALV;AAAA,EAUA,aAAa;AACZ,QAAI,KAAK,WAAW,QAAW;AAC9B,UAAM,EAAE,cAAc,MAAM,IAAI,KAAK,OAAO,OAAO;AACnD,aAAO,IAAI,SAAS,OAAO;AAAA,QAC1B,QAAQ,KAAK;AAAA,QACb,SAAS;AAAA,UACR,CAAC,UAAU,aAAa,GAAG,GAAG,YAAY;AAAA,UAC1C,gBAAgB;AAAA,UAChB,CAAC,UAAU,KAAK,GAAG,KAAK,UAAU;AAAA,YACjC,SAAS,KAAK;AAAA,YACd,SAAS;AAAA;AAAA,YAET,QAAQ,KAAK;AAAA,UACd,CAAC;AAAA,QACF;AAAA,MACD,CAAC;AAAA,IACF;AACA,WAAO,IAAI,SAAS,MAAM;AAAA,MACzB,QAAQ,KAAK;AAAA,MACb,SAAS;AAAA,QACR,CAAC,UAAU,KAAK,GAAG,KAAK,UAAU;AAAA,UACjC,SAAS,KAAK;AAAA,UACd,SAAS;AAAA;AAAA,UAET,QAAQ,KAAK;AAAA,QACd,CAAC;AAAA,MACF;AAAA,IACD,CAAC;AAAA,EACF;AAAA,EAEA,QAAQ,MAAc;AACrB,gBAAK,WAAW,KAAK,IAAI,KAClB;AAAA,EACR;AAAA,EAEA,OAAO,QAA0B;AAChC,gBAAK,SAAS,QACP;AAAA,EACR;AACD,GAEa,kBAAN,cAA8B,QAAQ;AAAA,EAC5C,cAAc;AACb,UAAM,KAAK,+BAA+B,YAAY,gBAAgB;AAAA,EACvE;AACD,GAEa,gBAAN,cAA4B,QAAQ;AAAA,EAC1C,cAAc;AACb;AAAA,MACC;AAAA,MACA;AAAA,MACA,YAAY;AAAA,IACb;AAAA,EACD;AACD,GACa,YAAN,cAAwB,QAAQ;AAAA,EACtC,cAAc;AACb;AAAA,MACC;AAAA,MACA;AAAA,MACA,YAAY;AAAA,IACb;AAAA,EACD;AACD,GAEa,iBAAN,cAA6B,QAAQ;AAAA,EAC3C,cAAc;AACb;AAAA,MACC;AAAA,MACA;AAAA,MACA,YAAY;AAAA,IACb;AAAA,EACD;AACD,GAEa,iBAAN,cAA6B,QAAQ;AAAA,EAC3C,cAAc;AACb;AAAA,MACC;AAAA,MACA;AAAA,MACA,YAAY;AAAA,IACb;AAAA,EACD;AACD,GAEa,mBAAN,cAA+B,QAAQ;AAAA,EAC7C,cAAc;AACb;AAAA,MACC;AAAA,MACA;AAAA,MACA,YAAY;AAAA,IACb;AAAA,EACD;AACD,GAEa,YAAN,cAAwB,QAAQ;AAAA,EACtC,YACC,WACA,UACA,YACC;AACD;AAAA,MACC;AAAA,MACA;AAAA,QACC,OAAO,SAAS;AAAA,QAChB,kBAAkB,SAAS,yBAAyB,SAAS;AAAA,UAC5D;AAAA,QACD,CAAC;AAAA,QACD,UAAU,SAAS,SAAS,WAAW,SAAS,KAAK,CAAC;AAAA,MACvD,EAAE,KAAK;AAAA,CAAI;AAAA,MACX,YAAY;AAAA,IACb;AAAA,EACD;AACD,GAEa,oBAAN,cAAgC,QAAQ;AAAA,EAC9C,cAAc;AACb;AAAA,MACC;AAAA,MACA;AAAA,MACA,YAAY;AAAA,IACb;AAAA,EACD;AACD,GAEa,iBAAN,cAA6B,QAAQ;AAAA,EAC3C,cAAc;AACb;AAAA,MACC;AAAA,MACA;AAAA,MACA,YAAY;AAAA,IACb;AAAA,EACD;AACD,GAEa,eAAN,cAA2B,QAAQ;AAAA,EACzC,cAAc;AACb;AAAA,MACC;AAAA,MACA;AAAA,MACA,YAAY;AAAA,IACb;AAAA,EACD;AACD,GAEa,cAAN,cAA0B,QAAQ;AAAA,EACxC,cAAc;AACb;AAAA,MACC;AAAA,MACA;AAAA,MACA,YAAY;AAAA,IACb;AAAA,EACD;AACD,GAEa,qBAAN,cAAiC,QAAQ;AAAA,EAC/C,cAAc;AACb;AAAA,MACC;AAAA,MACA;AAAA,MACA,YAAY;AAAA,IACb;AAAA,EACD;AACD,GAEa,eAAN,cAA2B,QAAQ;AAAA,EACzC,cAAc;AACb;AAAA,MACC;AAAA,MACA;AAAA,MACA,YAAY;AAAA,IACb;AAAA,EACD;AACD,GAEa,YAAN,cAAwB,QAAQ;AAAA,EACtC,cAAc;AACb;AAAA,MACC;AAAA,MACA;AAAA,MACA,YAAY;AAAA,IACb;AAAA,EACD;AACD;;;ACzNA,SAAS,kBAAkB;AAcpB,IAAM,mBAAN,MAAuB;AAAA,EACpB;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EAET,YAAY,KAAiC,OAAiB;AAC7D,SAAK,MAAM,IAAI,KACf,KAAK,UAAU,IAAI,SACnB,KAAK,OAAO,IAAI,MAChB,KAAK,OAAO,IAAI,MAChB,KAAK,WAAW,IAAI,UACpB,KAAK,eAAe,KAAK,MAAM,IAAI,aAAa,GAChD,KAAK,iBAAiB,KAAK,MAAM,IAAI,eAAe,GACpD,KAAK,QAAQ;AAIb,QAAM,YAA+B,KAAK,MAAM,IAAI,SAAS;AAC7D,IAAI,KAAK,KAAK,WAAW,MAAM,WAAW,KAAK,KAAK,IAAI,MACvD,UAAU,MAAM,IAAI,OAErB,KAAK,YAAY;AAAA,EAClB;AAAA;AAAA,EAGA,iBAAiC;AAChC,WAAO;AAAA,MACN,MAAM,KAAK;AAAA,MACX,SAAS,KAAK;AAAA,MACd,MAAM,KAAK;AAAA,MACX,MAAM,KAAK;AAAA,MACX,UAAU,KAAK;AAAA,MACf,YAAY,KAAK;AAAA,MACjB,cAAc,OAAO,QAAQ,KAAK,cAAc,EAAE,IAAI,CAAC,CAAC,GAAG,CAAC,OAAO;AAAA,QAClE;AAAA,QACA;AAAA,MACD,EAAE;AAAA,MACF,OAAO,KAAK;AAAA,MACZ,WAAW;AAAA,QACV,GAAG,KAAK,UAAU;AAAA,QAClB,GAAG,KAAK,UAAU;AAAA,QAClB,GAAG,KAAK,UAAU;AAAA,QAClB,GAAG,KAAK,UAAU;AAAA,QAClB,GAAG,KAAK,UAAU;AAAA,MACnB;AAAA,IACD;AAAA,EACD;AAAA,EAEA,SAA0B;AACzB,QAAM,OAAO,KAAK,UAAU,KAAK,eAAe,CAAC,GAC3C,OAAO,IAAI,KAAK,CAAC,IAAI,CAAC;AAC5B,WAAO,EAAE,cAAc,KAAK,MAAM,OAAO,KAAK,OAAO,GAAG,MAAM,KAAK,KAAK;AAAA,EACzE;AAAA,EAEA,OAAO,eAAe,SAA6C;AAClE,QAAM,OAAO,KAAK,UAAU;AAAA,MAC3B,GAAG;AAAA,MACH,SAAS,QAAQ,QAAQ,IAAI,CAAC,MAAM,EAAE,eAAe,CAAC;AAAA,IACvD,CAAC,GACK,OAAO,IAAI,KAAK,CAAC,IAAI,CAAC;AAC5B,WAAO,EAAE,cAAc,KAAK,MAAM,OAAO,KAAK,OAAO,GAAG,MAAM,KAAK,KAAK;AAAA,EACzE;AACD,GAEa,uBAAN,cAAmC,iBAAiB;AAAA,EAC1D,YACC,UACS,MACT,OACC;AACD,UAAM,UAAU,KAAK;AAHZ;AAAA,EAIV;AAAA,EAJU;AAAA,EAMV,SAA0B;AACzB,QAAM,EAAE,cAAc,OAAO,SAAS,IAAI,MAAM,OAAO,GACjD,OAAO,KAAK,OAAO,UAAU,KAAK,MAClCC,YAAW,IAAI,kBAAkB,OAAO,YAAY;AAC1D,WAAK,SACH,OAAOA,UAAS,UAAU,EAAE,cAAc,GAAK,CAAC,EAChD,KAAK,MAAM,KAAK,KAAK,OAAOA,UAAS,QAAQ,CAAC,GACzC;AAAA,MACN;AAAA,MACA,OAAOA,UAAS;AAAA,MAChB;AAAA,IACD;AAAA,EACD;AACD;;;AC1GA,SAAS,kBAAkB,eAAe,SAAS;AAc5C,IAAM,uBAAuB;AAAA,EACnC,aAAa;AAAA,EACb,WAAW;AAAA,EACX,SAAS;AACV,GAoBa,aAAa;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,GAoCb,aAAa,EAAE,OAC1B,OAAO,EACP,UAAU,CAAC,UAAU,IAAI,KAAK,KAAK,CAAC,GAEzB,eAAe,EAC1B,OAAO;AAAA,EACP,GAAG,EAAE,OAAO;AAAA,EACZ,GAAG,EAAE,OAAO;AACb,CAAC,EACA,MAAM,EACN;AAAA,EAAU,CAAC,YACX,OAAO,YAAY,QAAQ,IAAI,CAAC,EAAE,GAAG,EAAE,MAAM,CAAC,GAAG,CAAC,CAAC,CAAC;AACrD,GAGY,gBAAgB,EAAE,OAAO;AAAA,EACrC,QAAQ,EAAE,OAAO,OAAO,EAAE,SAAS;AAAA,EACnC,QAAQ,EAAE,OAAO,OAAO,EAAE,SAAS;AAAA,EACnC,QAAQ,EAAE,OAAO,OAAO,EAAE,SAAS;AACpC,CAAC,GAGY,eAAe,EAAE,mBAAmB,QAAQ;AAAA,EACxD,EAAE,OAAO,EAAE,MAAM,EAAE,QAAQ,QAAQ,GAAG,OAAO,EAAE,OAAO,EAAE,CAAC;AAAA,EACzD,EAAE,OAAO,EAAE,MAAM,EAAE,QAAQ,MAAM,GAAG,OAAO,EAAE,OAAO,EAAE,CAAC;AAAA,EACvD,EAAE,OAAO,EAAE,MAAM,EAAE,QAAQ,UAAU,EAAE,CAAC;AACzC,CAAC,GAEY,oBAAoB,aAAa,MAAM,EAAE,IAAI,CAAC,EAAE,SAAS,GAGzD,sBAAsB,EAAE,OAAO;AAAA;AAAA,EAE3C,aAAa;AAAA;AAAA;AAAA,EAEb,kBAAkB;AAAA;AAAA;AAAA,EAElB,gBAAgB,WAAW,SAAS;AAAA;AAAA;AAAA,EAEpC,eAAe,WAAW,SAAS;AAAA;AAAA;AAAA,EAEnC,oBAAoB,EAAE,QAAQ,EAAE,SAAS;AAC1C,CAAC,GAGY,oBAAoB,EAC/B,OAAO;AAAA,EACP,GAAG,cAAc,SAAS;AAAA,EAC1B,GAAG,cAAc,SAAS;AAAA,EAC1B,GAAG,cAAc,SAAS;AAAA,EAC1B,GAAG,cAAc,SAAS;AAAA,EAC1B,GAAG,cAAc,SAAS;AAC3B,CAAC,EACA,UAAU,CAAC,eAAe;AAAA,EAC1B,KAAK,UAAU,CAAG;AAAA,EAClB,MAAM,UAAU,CAAG;AAAA,EACnB,QAAQ,UAAU,CAAG;AAAA,EACrB,QAAQ,UAAU,CAAG;AAAA,EACrB,QAAQ,UAAU,CAAG;AACtB,EAAE,GAIU,wBAAwB,EAAE,OAAO;AAAA,EAC7C,MAAM,EAAE,OAAO;AAAA,EACf,MAAM,EAAE,OAAO;AAChB,CAAC,GAGY,qBAAqB,EAAE,OAAO;AAAA,EAC1C,aAAa,EAAE,OAAO,EAAE,SAAS;AAAA,EACjC,iBAAiB,EAAE,OAAO,EAAE,SAAS;AAAA,EACrC,oBAAoB,EAAE,OAAO,EAAE,SAAS;AAAA,EACxC,iBAAiB,EAAE,OAAO,EAAE,SAAS;AAAA,EACrC,cAAc,EAAE,OAAO,EAAE,SAAS;AAAA,EAClC,aAAa,EAAE,OAAO,OAAO,EAAE,SAAS;AACzC,CAAC,GAGY,sBAAsB,EAAE,OAAO;AAAA,EAC3C,QAAQ,EAAE,QAAQ,MAAM;AAAA,EACxB,QAAQ,EAAE,OAAO;AAClB,CAAC,GAEY,qBAAqB,EAAE,OAAO;AAAA,EAC1C,QAAQ,EAAE,QAAQ,KAAK;AAAA,EACvB,QAAQ,EAAE,OAAO;AAAA;AAAA;AAAA;AAAA,EAIjB,OAAO,cAAc,SAAS;AAAA,EAC9B,aAAa,EAAE,OAAO,EAAE,SAAS;AAAA;AAAA;AAAA,EAGjC,QAAQ,oBAAoB,SAAS;AACtC,CAAC,GAEY,qBAAqB,EAChC,OAAO;AAAA,EACP,QAAQ,EAAE,QAAQ,KAAK;AAAA,EACvB,QAAQ,EAAE,OAAO;AAAA,EACjB,cAAc,aAAa,SAAS;AAAA;AAAA,EACpC,YAAY,mBAAmB,SAAS;AAAA;AAAA,EACxC,QAAQ,oBAAoB,SAAS;AAAA,EACrC,KAAK,iBAAiB,SAAS;AAAA;AAAA,EAC/B,MAAM,cAAc,SAAS;AAAA,EAC7B,QAAQ,cAAc,SAAS;AAAA,EAC/B,QAAQ,cAAc,SAAS;AAAA,EAC/B,QAAQ,cAAc,SAAS;AAChC,CAAC,EACA,UAAU,CAAC,WAAW;AAAA,EACtB,QAAQ,MAAM;AAAA,EACd,QAAQ,MAAM;AAAA,EACd,gBAAgB,MAAM;AAAA,EACtB,cAAc,MAAM;AAAA,EACpB,QAAQ,MAAM;AAAA,EACd,KAAK,MAAM;AAAA,EACX,MAAM,MAAM;AAAA,EACZ,QAAQ,MAAM;AAAA,EACd,QAAQ,MAAM;AAAA,EACd,QAAQ,MAAM;AACf,EAAE,GAEU,uCAAuC,EAClD,OAAO;AAAA,EACP,QAAQ,EAAE,QAAQ,uBAAuB;AAAA,EACzC,QAAQ,EAAE,OAAO;AAAA,EACjB,cAAc,aAAa,SAAS;AAAA;AAAA,EACpC,YAAY,mBAAmB,SAAS;AAAA;AACzC,CAAC,EACA,UAAU,CAAC,WAAW;AAAA,EACtB,QAAQ,MAAM;AAAA,EACd,QAAQ,MAAM;AAAA,EACd,gBAAgB,MAAM;AAAA,EACtB,cAAc,MAAM;AACrB,EAAE,GAEU,4BAA4B,EAAE,OAAO;AAAA,EACjD,QAAQ,EAAE,QAAQ,YAAY;AAAA,EAC9B,QAAQ,EAAE,OAAO;AAAA,EACjB,UAAU,EAAE,OAAO;AAAA,EACnB,YAAY,EAAE,OAAO;AACtB,CAAC,GAEY,yCAAyC,EAAE,OAAO;AAAA,EAC9D,QAAQ,EAAE,QAAQ,yBAAyB;AAAA,EAC3C,QAAQ,EAAE,OAAO;AAAA,EACjB,UAAU,EAAE,OAAO;AAAA,EACnB,OAAO,sBAAsB,MAAM;AACpC,CAAC,GAEY,sCAAsC,EAAE,OAAO;AAAA,EAC3D,QAAQ,EAAE,QAAQ,sBAAsB;AAAA,EACxC,QAAQ,EAAE,OAAO;AAAA,EACjB,UAAU,EAAE,OAAO;AACpB,CAAC,GAEY,sBAAsB,EAAE,OAAO;AAAA,EAC3C,QAAQ,EAAE,QAAQ,MAAM;AAAA,EACxB,OAAO,EAAE,OAAO,EAAE,SAAS;AAAA,EAC3B,QAAQ,EAAE,OAAO,EAAE,SAAS;AAAA,EAC5B,QAAQ,EAAE,OAAO,EAAE,SAAS;AAAA,EAC5B,WAAW,EAAE,OAAO,EAAE,SAAS;AAAA,EAC/B,YAAY,EAAE,OAAO,EAAE,SAAS;AAAA,EAChC,SAAS,EACP,MAAM,CAAC,EAAE,QAAQ,CAAC,GAAG,EAAE,QAAQ,CAAC,CAAC,CAAC,EAClC,UAAU,CAAC,UAAW,UAAU,IAAI,iBAAiB,gBAAiB,EACtE,MAAM,EACN,SAAS;AACZ,CAAC,GAEY,wBAAwB,EAAE;AAAA,EACtC,EAAE,OAAO,EAAE,QAAQ,EAAE,QAAQ,QAAQ,EAAE,CAAC;AAAA,EACxC,EAAE,MAAM;AAAA,IACP,EAAE,OAAO,EAAE,QAAQ,EAAE,OAAO,EAAE,CAAC;AAAA,IAC/B,EAAE,OAAO,EAAE,SAAS,EAAE,OAAO,EAAE,MAAM,EAAE,CAAC;AAAA,EACzC,CAAC;AACF,GAKa,yBAAyB,EAAE,MAAM;AAAA,EAC7C;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AACD,CAAC;;;AC1QD,OAAO,YAAY;AACnB,SAAS,UAAAC,eAAc;AACvB,SAAS,mBAAmB;AAmB5B,SAAS,SAAS,IAAY;AAC7B,SAAO;AACR;AACA,SAAS,kBAAkB,IAAY;AACtC,SAAO,KAAK,MAAM,KAAK,GAAI,IAAI;AAChC;AAEA,SAAS,aACR,YACA,MACA,YACC;AAED,WAAW,aAAa;AAEvB,QADI,UAAU,SAAS,cACnB,UAAU,UAAU,SACnB,UAAU,SAAS,YAAY,eAAe;AAAQ,aAAO;AAGnE,SAAO;AACR;AAIO,SAAS,mBACf,MACA,UACU;AAIV,MAAI,aAAa,QAAW;AAC3B,QAAMC,WAAU,KAAK,gBAAgB,QAC/BC,mBAAkB,KAAK,kBAAkB;AAC/C,WAAOD,YAAWC;AAAA,EACnB;AAEA,MAAM,EAAE,MAAM,UAAU,gBAAgB,IAAI,UACtC,UACL,KAAK,gBAAgB,UACrB,aAAa,KAAK,aAAa,MAAM,QAAQ,GACxC,cACL,KAAK,qBAAqB,UAC1B,CAAC,aAAa,KAAK,kBAAkB,MAAM,MAAM,GAE5C,gBAAgB,KAAK,qBAAqB,oBAAoB,UAC9D,eAAe,cAAc,eAAe,GAC5C,kBACL,KAAK,kBAAkB,UACvB,cAAc,KAAK,cAAc,QAAQ,CAAC,IAAI,gBAC7C,KAAK,qBAAqB,UAAa,aACnC,oBACL,KAAK,mBAAmB,UACxB,eAAe,cAAc,KAAK,eAAe,QAAQ,CAAC,KACzD,KAAK,gBAAgB,UAAa;AAEpC,SAAO,WAAW,eAAe,mBAAmB;AACrD;AAEO,IAAM,qBAAqB;AAAA,EACjC,EAAE,MAAM,OAAO,OAAO,MAAM;AAAA,EAC5B,EAAE,MAAM,SAAS,OAAO,OAAO;AAAA,EAC/B,EAAE,MAAM,WAAW,OAAO,SAAS;AAAA,EACnC,EAAE,MAAM,WAAW,OAAO,SAAS;AAAA,EACnC,EAAE,MAAM,WAAW,OAAO,SAAS;AACpC;AAOA,SAAS,iBAAiB,GAAW;AAEpC,WAAS,IAAI,GAAG,IAAI,EAAE,QAAQ;AAC7B,QAAI,EAAE,WAAW,CAAC,KAAK,IAAK,QAAO,EAAE,SAAS;AAE/C,SAAO,EAAE;AACV;AAEO,IAAM,YAAN,MAAgB;AAAA,EACtB,KACC,SACA,QACoB;AACpB,QAAM,YAA+B,CAAC;AACtC,aAAW,EAAE,MAAM,MAAM,KAAK,oBAAoB;AACjD,UAAM,eAAe,OAAO,KAAK;AACjC,UAAI,iBAAiB,QAAW;AAC/B,YAAM,eAAe,QAAQ,IAAI,IAAI;AAGrC,YADA,OAAO,iBAAiB,MAAS,GAC7B,CAAC,aAAa,OAAO,YAAY;AACpC,gBAAM,IAAI,UAAU,MAAM,cAAc,YAAY;AAIrD,kBAAU,KAAK,IAAI,aAAa,SAAS,KAAK;AAAA,MAC/C;AAAA,IACD;AACA,WAAO;AAAA,EACR;AAAA,EAEA,UACC,MACA,QACY;AACZ,QAAI,WAAW,UAAa,CAAC,mBAAmB,QAAQ,IAAI;AAC3D,YAAM,IAAI,mBAAmB;AAE9B,WAAO;AAAA,EACR;AAAA,EAEA,MACC,SACA,MAC6B;AAC7B,QAAI,QAAQ,gBAAgB,QAAW;AACtC,UAAM,SAAS,YAAY,QAAQ,aAAa,IAAI;AAIpD,UAAI,QAAQ,WAAW,EAAG,QAAO,OAAO,CAAC;AAAA,IAC1C,WAAW,QAAQ,UAAU,QAAW;AACvC,UAAI,EAAE,QAAQ,QAAQ,OAAO,IAAI,QAAQ;AAEzC,UAAI,WAAW,QAAW;AACzB,YAAI,UAAU,EAAG,OAAM,IAAI,aAAa;AACxC,QAAI,SAAS,SAAM,SAAS,OAC5B,SAAS,OAAO,QAChB,SAAS;AAAA,MACV;AAIA,UAFI,WAAW,WAAW,SAAS,IAC/B,WAAW,WAAW,SAAS,OAAO,SACtC,SAAS,KAAK,SAAS,QAAQ,UAAU,EAAG,OAAM,IAAI,aAAa;AAEvE,aAAI,SAAS,SAAS,SAAM,SAAS,OAAO,SAErC,EAAE,OAAO,QAAQ,KAAK,SAAS,SAAS,EAAE;AAAA,IAClD;AAAA,EACD;AAAA,EAEA,KAAK,MAAyB;AAC7B,QAAI,OAAO,SAAS;AACnB,YAAM,IAAI,eAAe;AAE1B,WAAO;AAAA,EACR;AAAA,EAEA,aAAa,gBAAoD;AAChE,QAAI,mBAAmB,OAAW,QAAO;AACzC,QAAI,iBAAiB;AACrB,aAAW,CAAC,KAAK,KAAK,KAAK,OAAO,QAAQ,cAAc;AACvD,wBAAkB,iBAAiB,GAAG,IAAI,iBAAiB,KAAK;AAEjE,QAAI,iBAAiB,SAAS;AAC7B,YAAM,IAAI,iBAAiB;AAE5B,WAAO;AAAA,EACR;AAAA,EAEA,IAAI,KAAwB;AAE3B,QADkBC,QAAO,WAAW,GAAG,IACvB,SAAS;AACxB,YAAM,IAAI,kBAAkB;AAE7B,WAAO;AAAA,EACR;AAAA,EAEA,MAAM,OAA2B;AAChC,QAAI,UAAU,WAAc,QAAQ,KAAK,QAAQ,SAAS;AACzD,YAAM,IAAI,eAAe;AAE1B,WAAO;AAAA,EACR;AACD;;;ALzGA,IAAM,kBAAN,cAEU,gBAAwC;AAAA,EACxC;AAAA,EAET,YAAY,YAAyB;AACpC,QAAM,UAAU,IAAI,gBAAwC,GACtD,SAAS,WAAW,IAAI,CAAC,QAAQ;AACtC,UAAM,SAAS,IAAI,OAAO,aAAa,GAAG,GACpC,SAAS,OAAO,UAAU;AAChC,aAAO,EAAE,QAAQ,OAAO;AAAA,IACzB,CAAC;AACD,UAAM;AAAA,MACL,MAAM,UAAU,OAAO,YAAY;AAClC,iBAAW,QAAQ,OAAQ,OAAM,KAAK,OAAO,MAAM,KAAK;AACxD,mBAAW,QAAQ,KAAK;AAAA,MACzB;AAAA,MACA,MAAM,QAAQ;AACb,YAAM,SAAS,oBAAI,IAAuB;AAC1C,iBAAS,IAAI,GAAG,IAAI,OAAO,QAAQ;AAClC,gBAAM,OAAO,CAAC,EAAE,OAAO,MAAM,GAC7B,OAAO,IAAI,WAAW,CAAC,GAAGC,QAAO,KAAK,MAAM,OAAO,CAAC,EAAE,OAAO,MAAM,CAAC;AAErE,gBAAQ,QAAQ,MAAM;AAAA,MACvB;AAAA,IACD,CAAC,GACD,KAAK,UAAU;AAAA,EAChB;AACD,GAEM,WAAW,IAAI,UAAU,GACzB,UAAU,IAAI,YAAY;AAEhC,SAAS,kBAAkB;AAC1B,SAAOA,QAAO,KAAK,OAAO,gBAAgB,IAAI,WAAW,EAAE,CAAC,CAAC,EAAE;AAAA,IAC9D;AAAA,EACD;AACD;AACA,SAAS,aAAa;AACrB,SAAOA,QAAO,KAAK,OAAO,gBAAgB,IAAI,WAAW,GAAG,CAAC,CAAC,EAAE;AAAA,IAC/D;AAAA,EACD;AACD;AACA,SAAS,sBAAsB,UAAoB;AAElD,MAAM,OAAO,WAAW,KAAK;AAC7B,WAAW,UAAU,SAAU,MAAK,OAAO,QAAQ,KAAK;AACxD,SAAO,GAAG,KAAK,OAAO,KAAK,CAAC,IAAI,SAAS,MAAM;AAChD;AAEA,SAAS,cAAc,GAAmB,GAA4B;AACrE,SAAO,EAAE,SAAS,EAAE,OAAO,EAAE,SAAS,EAAE;AACzC;AAEA,eAAe,eAAe,KAAgC;AAC7D,MAAM,eAAe;AAAA,IACpB,IAAI,QAAQ,IAAI,UAAU,aAAa,KAAK;AAAA,EAC7C;AACA,MAAI,OAAO,MAAM,YAAY,EAAG,OAAM,IAAI,gBAAgB;AAE1D,EAAAC,QAAO,IAAI,SAAS,IAAI;AACxB,MAAM,OAAO,IAAI,MAGX,CAAC,gBAAgB,KAAK,IAAI,MAAM,WAAW,MAAM,YAAY,GAC7D,eAAe,QAAQ,OAAO,cAAc;AAGlD,SAAO,EAAE,UAFQ,uBAAuB,MAAM,KAAK,MAAM,YAAY,CAAC,GAEnD,cAAc,MAAM;AACxC;AACA,SAAS,qBAAqB,KAAgC;AAC7D,MAAM,SAAS,IAAI,QAAQ,IAAI,UAAU,OAAO;AAChD,MAAI,WAAW,KAAM,OAAM,IAAI,gBAAgB;AAC/C,SAAO,uBAAuB,MAAM,KAAK,MAAM,MAAM,CAAC;AACvD;AAEA,SAAS,aACR,QACC;AACD,MAAI;AACJ,SAAI,kBAAkB,mBACrB,UAAU,OAAO,OAAO,IAExB,UAAU,iBAAiB,eAAe,MAAM,GAG1C,IAAI,SAAS,QAAQ,OAAO;AAAA,IAClC,SAAS;AAAA,MACR,CAAC,UAAU,aAAa,GAAG,GAAG,QAAQ,YAAY;AAAA,MAClD,gBAAgB;AAAA,MAChB,kBAAkB,GAAG,QAAQ,IAAI;AAAA,IAClC;AAAA,EACD,CAAC;AACF;AACA,SAAS,iBAAiB,QAAiB;AAC1C,MAAM,UAAU,KAAK,UAAU,MAAM;AACrC,SAAO,IAAI,SAAS,SAAS;AAAA,IAC5B,SAAS;AAAA,MACR,CAAC,UAAU,aAAa,GAAG,GAAGD,QAAO,WAAW,OAAO,CAAC;AAAA,MACxD,gBAAgB;AAAA,IACjB;AAAA,EACD,CAAC;AACF;AAEA,SAAS,SAAS,IAAc;AAC/B,MAAM,uBAAuB,GAAG,KAG9B,kEAAkE,GAE9D,eAAe,GAAG,KAAwC;AAAA;AAAA;AAAA,GAG9D,GACI,UAAU,GAAG,KAAgB;AAAA;AAAA;AAAA,GAGjC,GACI,aAAa,GAAG,KAGpB,4DAA4D;AAE9D,WAAS,4BACL,cACF;AACD,QAAM,UAA+B;AAAA,MACpC;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA,GAAG;AAAA,IACJ;AAEA,WAAO,GAAG,KAGR;AAAA,eACW,QAAQ,KAAK,IAAI,CAAC;AAAA;AAAA;AAAA;AAAA;AAAA,KAK5B;AAAA,EACJ;AAGA,MAAM,qBAAqB,GAAG;AAAA;AAAA,IAK7B;AAAA,EACD,GACM,wBAAwB,GAAG;AAAA;AAAA,IAKhC;AAAA,EACD,GACM,wBAAwB,GAAG;AAAA;AAAA,IAIhC;AAAA,EACD,GAEM,8BAA8B,GAAG;AAAA;AAAA,IAKtC;AAAA,EACD,GACM,cAAc,GAAG;AAAA;AAAA,IAEtB;AAAA;AAAA,EAED,GACM,eAAe,GAAG;AAAA;AAAA,IAIvB;AAAA;AAAA,EAED,GACM,4BAA4B,GAAG;AAAA;AAAA,IAKpC;AAAA,EACD,GACM,oCAAoC,GAAG;AAAA;AAAA,IAK5C;AAAA,EACD,GACM,uBAAuB,GAAG;AAAA;AAAA,IAK/B;AAAA,EACD,GACM,0BAA0B,GAAG;AAAA;AAAA,IAKlC;AAAA;AAAA,EAED,GACM,qBAAqB,GAAG;AAAA;AAAA;AAAA,IAM7B;AAAA,EACD;AAEA,SAAO;AAAA,IACN,UAAU;AAAA,IACV,eAAe,GAAG,IAAI,CAAC,QAAgB;AACtC,UAAM,MAAM,IAAI,aAAa,EAAE,IAAI,CAAC,CAAC;AACrC,UAAI,QAAQ;AACZ,YAAI,IAAI,YAAY,MAAM;AAEzB,cAAM,YAAY,IAAI,mBAAmB,EAAE,YAAY,IAAI,CAAC,CAAC;AAC7D,iBAAO,EAAE,KAAK,OAAO,UAAU;AAAA,QAChC;AAEC,iBAAO,EAAE,IAAI;AAAA,IAEf,CAAC;AAAA,IACD,KAAK,GAAG,IAAI,CAAC,QAAmB,WAA2B;AAC1D,UAAM,MAAM,OAAO,KACb,MAAM,IAAI,qBAAqB,EAAE,IAAI,CAAC,CAAC;AAC7C,MAAI,WAAW,UAAW,SAAS,UAAU,KAAK,MAAM,GACxD,QAAQ,MAAM;AACd,UAAM,iBAAiB,KAAK;AAC5B,aAAI,mBAAmB,SACf,CAAC,IACE,mBAAmB,OAGhB,IAAI,qBAAqB,EAAE,YAAY,IAAI,CAAC,CAAC,EAC9C,IAAI,CAAC,EAAE,QAAQ,MAAM,OAAO,IAEjC,CAAC,cAAc;AAAA,IAExB,CAAC;AAAA,IACD,cAAc,GAAG,IAAI,CAAC,SAAmB;AACxC,UAAM,aAAuB,CAAC;AAC9B,eAAW,OAAO,MAAM;AAEvB,YAAM,iBADM,IAAI,WAAW,EAAE,IAAI,CAAC,CAAC,GACP;AAC5B,YAAI,mBAAmB,MAAM;AAG5B,cAAM,WAAW,qBAAqB,EAAE,YAAY,IAAI,CAAC;AACzD,mBAAW,WAAW,SAAU,YAAW,KAAK,QAAQ,OAAO;AAAA,QAChE,MAAO,CAAI,mBAAmB,UAC7B,WAAW,KAAK,cAAc;AAAA,MAEhC;AACA,aAAO;AAAA,IACR,CAAC;AAAA,IAED,sBAAsB,yBAAyB;AAAA,IAC/C,kCAAkC,yBAAyB,eAAe;AAAA,IAC1E,oCACC,yBAAyB,iBAAiB;AAAA,IAC3C,wCAAwC;AAAA,MACvC;AAAA,MACA;AAAA,IACD;AAAA,IACA,cAAc,GAAG,KAWf;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,KAsBC;AAAA,IAEH,uBAAuB,GAAG,KAAwC;AAAA;AAAA;AAAA,KAG/D;AAAA,IACH,SAAS,GAAG;AAAA,MACX,CAAC,KAAa,WAAiD;AAQ9D,YANkB;AAAA,UACjB,mBAAmB;AAAA,YAClB;AAAA,YACA,WAAW,OAAO;AAAA,UACnB,CAAC;AAAA,QACF,GACe,UAAU,qBAAqB;AAC7C,gBAAM,IAAI,aAAa;AAIxB,YAAM,UAAU;AAAA,UACf,4BAA4B;AAAA,YAC3B,WAAW,OAAO;AAAA,YAClB,aAAa,OAAO;AAAA,UACrB,CAAC;AAAA,QACF;AACA,2BAAY,MAAM,GACX,SAAS;AAAA,MACjB;AAAA,IACD;AAAA,IACA,yBAAyB,GAAG;AAAA,MAC3B,CACC,KACA,WACA,eACA,gBACI;AAEJ,YAAM,YAAY,IAAI,sBAAsB,EAAE,KAAK,UAAU,CAAC,CAAC;AAC/D,YAAI,cAAc;AACjB,gBAAM,IAAI,cAAc;AAClB,YAAI,UAAU,QAAQ,qBAAqB;AACjD,gBAAM,IAAI,aAAa;AAIxB,YAAM,gBAAgB,oBAAI,IAAY;AACtC,iBAAW,EAAE,KAAK,KAAK,eAAe;AACrC,cAAI,cAAc,IAAI,IAAI,EAAG,OAAM,IAAI,cAAc;AACrD,wBAAc,IAAI,IAAI;AAAA,QACvB;AAIA,YAAM,mBAAmB,wBAAwB,EAAE,UAAU,CAAC,GACxD,gBAAgB,oBAAI,IAGxB;AACF,iBAAW,OAAO;AACjB,wBAAc,IAAI,IAAI,aAAa,GAAG;AAEvC,YAAM,QAAQ,cAAc,IAAI,CAAC,iBAAiB;AAGjD,cAAM,eAAe,cAAc,IAAI,aAAa,IAAI;AAIxD,cAAI,cAAc,SAAS,aAAa;AACvC,kBAAM,IAAI,YAAY;AAEvB,iBAAO;AAAA,QACR,CAAC;AAKD,iBAAW,QAAQ,MAAM,MAAM,GAAG,EAAE;AACnC,cAAI,KAAK,OAAO;AACf,kBAAM,IAAI,eAAe;AAQ3B,cAAM,KAAK,CAAC,GAAG,MAAM,EAAE,cAAc,EAAE,WAAW;AAClD,YAAI;AACJ,iBAAW,QAAQ,MAAM,MAAM,GAAG,EAAE;AAGnC,cADA,aAAa,KAAK,MACd,KAAK,OAAO,eAAe,KAAK,SAAS;AAC5C,kBAAM,IAAI,UAAU;AAKtB,YAAI,aAAa,UAAa,MAAM,MAAM,SAAS,CAAC,EAAE,OAAO;AAC5D,gBAAM,IAAI,UAAU;AAIrB,YAAM,aAAuB,CAAC,GAExB,iBADc,IAAI,qBAAqB,EAAE,IAAI,CAAC,CAAC,GACjB;AACpC,YAAI,mBAAmB,MAAM;AAG5B,cAAME,YAAW,qBAAqB,EAAE,YAAY,IAAI,CAAC;AACzD,mBAAW,WAAWA,UAAU,YAAW,KAAK,QAAQ,OAAO;AAAA,QAChE,MAAO,CAAI,mBAAmB,UAC7B,WAAW,KAAK,cAAc;AAI/B,YAAM,YAAY,MAAM,OAAO,CAAC,KAAK,EAAE,KAAK,MAAM,MAAM,MAAM,CAAC,GACzD,OAAO;AAAA,UACZ,MAAM,IAAI,CAAC,EAAE,aAAa,MAAM,YAAY;AAAA,QAC7C,GACM,SAAoB;AAAA,UACzB;AAAA,UACA,SAAS;AAAA,UACT,SAAS,gBAAgB;AAAA,UACzB,MAAM;AAAA,UACN;AAAA,UACA,UAAU,KAAK,IAAI;AAAA,UACnB,WAAW;AAAA,UACX,eAAe,UAAU;AAAA,UACzB,iBAAiB,UAAU;AAAA,QAC5B;AACA,gBAAQ,MAAM;AACd,iBAAW,QAAQ;AAClB,uBAAa;AAAA,YACZ;AAAA,YACA,aAAa,KAAK;AAAA,YAClB,YAAY;AAAA,UACb,CAAC;AAIF,YAAM,WAAW,kCAAkC,EAAE,UAAU,CAAC;AAChE,iBAAW,WAAW,SAAU,YAAW,KAAK,QAAQ,OAAO;AAG/D,qCAAsB;AAAA,UACrB;AAAA,UACA,OAAO,qBAAqB;AAAA,QAC7B,CAAC,GAEM,EAAE,QAAQ,WAAW;AAAA,MAC7B;AAAA,IACD;AAAA,IACA,sBAAsB,GAAG,IAAI,CAAC,KAAa,cAAsB;AAEhE,UAAM,YAAY,IAAI,mBAAmB,EAAE,KAAK,UAAU,CAAC,CAAC;AAC5D,UAAI,cAAc;AACjB,cAAM,IAAI,cAAc;AAClB,UAAI,UAAU,QAAQ,qBAAqB;AAIjD,eAAO,CAAC;AAKT,UAAM,aADW,IAAI,0BAA0B,EAAE,UAAU,CAAC,CAAC,EACjC,IAAI,CAAC,EAAE,QAAQ,MAAM,OAAO;AAGxD,mCAAsB;AAAA,QACrB;AAAA,QACA,OAAO,qBAAqB;AAAA,MAC7B,CAAC,GAEM;AAAA,IACR,CAAC;AAAA,EACF;AACD;AAGO,IAAM,iBAAN,cAA6B,uBAAuB;AAAA,EACjD;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAsBA,cAAc,oBAAI,IAAuB;AAAA,EAElD,YAAY,OAA2B,KAAgC;AACtE,UAAM,OAAO,GAAG,GAChB,KAAK,GAAG,KAAK,mCAAmC,GAChD,KAAK,GAAG,KAAK,UAAU,GACvB,KAAK,SAAS,SAAS,KAAK,EAAE;AAAA,EAC/B;AAAA,EAEA,aAAa,QAAgB;AAC5B,QAAI,YAAY,KAAK,YAAY,IAAI,MAAM;AAC3C,IAAI,cAAc,UACjB,YAAY,IAAI,UAAU,GAC1B,KAAK,YAAY,IAAI,QAAQ,SAAS,GACtC,UAAU,IAAI,GAEd,UAAU,KAAK,EAAE,KAAK,MAAM,KAAK,YAAY,OAAO,MAAM,CAAC,KAE3D,UAAU,IAAI;AAAA,EAEhB;AAAA,EAEA,aAAa,QAAgB;AAC5B,SAAK,YAAY,IAAI,MAAM,GAAG,KAAK;AAAA,EACpC;AAAA,EAEA,kBAAkB,QAAgB;AACjC,SAAK,OAAO,eAAe,aAE1B,MAAM,KAAK,YAAY,IAAI,MAAM,GAAG,KAAK,GAClC,KAAK,KAAK,OAAO,MAAM,EAAE,MAAM,CAAC,MAAM;AAC5C,cAAQ,MAAM,uCAAuC,CAAC;AAAA,IACvD,CAAC,EACD;AAAA,EACF;AAAA,EAEA,wBACC,OACA,YAC6B;AAI7B,QAAM,gBAA6D,CAAC,GAChE,QAAQ;AACZ,aAAW,QAAQ,OAAO;AACzB,UAAM,YAA4B,EAAE,OAAO,KAAK,QAAQ,KAAK,OAAO,EAAE;AACtE,UAAI,cAAc,WAAW,UAAU,GAAG;AACzC,YAAM,QAAwB;AAAA,UAC7B,OAAO,KAAK,IAAI,UAAU,OAAO,WAAW,KAAK,IAAI,UAAU;AAAA,UAC/D,KAAK,KAAK,IAAI,UAAU,KAAK,WAAW,GAAG,IAAI,UAAU;AAAA,QAC1D;AACA,aAAK,aAAa,KAAK,OAAO,GAC9B,cAAc,KAAK,EAAE,QAAQ,KAAK,SAAS,MAAM,CAAC;AAAA,MACnD;AACA,cAAQ,UAAU,MAAM;AAAA,IACzB;AAYA,QAAMC,YAAW,IAAI,gBAAwC;AAC7D,YAAC,YAAY;AACZ,UAAI,IAAI;AACR,UAAI;AAKH,eAAO,IAAI,cAAc,QAAQ,KAAK;AACrC,cAAM,EAAE,QAAQ,MAAM,IAAI,cAAc,CAAC,GACnC,QAAQ,MAAM,KAAK,KAAK,IAAI,QAAQ,KAAK,GACzC,MAAM,0BAA0B,MAAM;AAC5C,UAAAF,QAAO,UAAU,MAAM,GAAG,GAC1B,MAAM,MAAM,OAAOE,UAAS,UAAU,EAAE,cAAc,GAAK,CAAC,GAC5D,KAAK,aAAa,MAAM;AAAA,QACzB;AACA,cAAMA,UAAS,SAAS,MAAM;AAAA,MAC/B,SAAS,GAAG;AACX,cAAMA,UAAS,SAAS,MAAM,CAAC;AAAA,MAChC,UAAE;AACD,eAAO,IAAI,cAAc,QAAQ;AAChC,eAAK,aAAa,cAAc,CAAC,EAAE,MAAM;AAAA,MAE3C;AAAA,IACD,GAAG,GACIA,UAAS;AAAA,EACjB;AAAA,EAEA,MAAM,MAAM,KAAwC;AACnD,aAAS,IAAI,GAAG;AAEhB,QAAM,MAAM,IAAI,KAAK,OAAO,SAAS,EAAE,IAAI,CAAC,CAAC;AAC7C,QAAI,QAAQ,OAAW,OAAM,IAAI,UAAU;AAE3C,QAAM,QAAiB,EAAE,QAAQ,GAAG,QAAQ,IAAI,KAAK;AACrD,WAAO,IAAI,iBAAiB,KAAK,KAAK;AAAA,EACvC;AAAA,EAEA,MAAM,KACL,KACA,MACmD;AACnD,aAAS,IAAI,GAAG;AAGhB,QAAM,SAAS,KAAK,OAAO,cAAc,GAAG;AAC5C,QAAI,WAAW,OAAW,OAAM,IAAI,UAAU;AAC9C,QAAM,EAAE,KAAK,MAAM,IAAI,QAGjB,iBAA0B,EAAE,QAAQ,GAAG,QAAQ,IAAI,KAAK;AAC9D,QAAI;AACH,eAAS,UAAU,KAAK,KAAK,MAAM;AAAA,IACpC,SAAS,GAAG;AACX,YAAI,aAAa,sBAChB,EAAE,OAAO,IAAI,iBAAiB,KAAK,cAAc,CAAC,GAE7C;AAAA,IACP;AAGA,QAAM,QAAQ,SAAS,MAAM,MAAM,IAAI,IAAI,GACvC;AACJ,QAAI,UAAU;AACb,gBAAU;AAAA,SACJ;AACN,UAAM,QAAQ,MAAM,OACd,MAAM,KAAK,IAAI,MAAM,KAAK,IAAI,IAAI;AACxC,gBAAU,EAAE,QAAQ,OAAO,QAAQ,MAAM,QAAQ,EAAE;AAAA,IACpD;AAEA,QAAI;AACJ,QAAI,IAAI,YAAY,MAAM;AAEzB,MAAAF,QAAO,UAAU,MAAS;AAC1B,UAAM,eAAe,EAAE,OAAO,GAAG,KAAK,IAAI,OAAO,EAAE;AACnD,cAAQ,KAAK,wBAAwB,OAAO,SAAS,YAAY;AAAA,IAClE,WAEC,QAAQ,MAAM,KAAK,KAAK,IAAI,IAAI,SAAS,KAAK,GAC1C,UAAU,KAAM,OAAM,IAAI,UAAU;AAGzC,WAAO,IAAI,qBAAqB,KAAK,OAAO,OAAO;AAAA,EACpD;AAAA,EAEA,MAAM,KACL,KACA,OACA,WACA,MAC4B;AAG5B,QAAM,aAAgC,CAAC;AACvC,aAAW,EAAE,MAAM,MAAM,KAAK;AAE7B,OAAI,UAAU,SAAS,KAAK,KAAK,MAAM,WAAW,WAAW,KAAK,IAAI;AAEvE,QAAM,YAAY,IAAI,gBAAgB,UAAU,GAC1C,SAAS,MAAM,KAAK,KAAK,IAAI,MAAM,YAAY,SAAS,CAAC,GACzD,UAAU,MAAM,UAAU,SAC1B,YAAY,QAAQ,IAAI,KAAK;AACnC,IAAAA,QAAO,cAAc,MAAS;AAC9B,QAAM,eAAe,UAAU,SAAS,KAAK,GAEvC,YAAY,SAChB,IAAI,GAAG,EACP,KAAK,SAAS,EACd,aAAa,KAAK,cAAc,EAChC,KAAK,SAAS,IAAI,GACd,MAAiB;AAAA,MACtB;AAAA,MACA,SAAS;AAAA,MACT,SAAS,gBAAgB;AAAA,MACzB,MAAM;AAAA,MACN,MAAM;AAAA,MACN,UAAU,KAAK,IAAI;AAAA,MACnB,WAAW,KAAK,UAAU,SAAS;AAAA,MACnC,eAAe,KAAK,UAAU,KAAK,gBAAgB,CAAC,CAAC;AAAA,MACrD,iBAAiB,KAAK,UAAU,KAAK,kBAAkB,CAAC,CAAC;AAAA,IAC1D,GACI;AACJ,QAAI;AACH,mBAAa,KAAK,OAAO,IAAI,KAAK,KAAK,MAAM;AAAA,IAC9C,SAAS,GAAG;AAGX,iBAAK,kBAAkB,MAAM,GACvB;AAAA,IACP;AACA,QAAI,eAAe;AAClB,eAAWG,WAAU,WAAY,MAAK,kBAAkBA,OAAM;AAE/D,WAAO,IAAI,iBAAiB,GAAG;AAAA,EAChC;AAAA,EAEA,QAAQ,MAAyB;AAChC,IAAK,MAAM,QAAQ,IAAI,MAAG,OAAO,CAAC,IAAI;AACtC,aAAW,OAAO,KAAM,UAAS,IAAI,GAAG;AACxC,QAAM,aAAa,KAAK,OAAO,aAAa,IAAI;AAChD,aAAW,UAAU,WAAY,MAAK,kBAAkB,MAAM;AAAA,EAC/D;AAAA,EAEA,2BAA2B,aAAsB,eAAwB;AACxE,WAAI,eAAe,gBAAsB,KAAK,OAAO,uBACjD,cAAoB,KAAK,OAAO,qCAChC,gBAAsB,KAAK,OAAO,mCAC/B,KAAK,OAAO;AAAA,EACpB;AAAA,EAEA,MAAM,MAAM,MAAyD;AACpE,QAAM,SAAS,KAAK,UAAU,IAE1B,QAAQ,KAAK,SAAS,SAAS;AACnC,aAAS,MAAM,KAAK;AAKpB,QAAM,UAAU,KAAK,WAAW,CAAC;AACjC,IAAI,QAAQ,SAAS,MAAG,QAAQ,KAAK,IAAI,OAAO,GAAG;AACnD,QAAM,cAAc,CAAC,QAAQ,SAAS,cAAc,GAC9C,gBAAgB,CAAC,QAAQ,SAAS,gBAAgB,GAClD,YAAY,CACjB,UAKI,IAAI,kBAAkB,UAAa,iBACtC,IAAI,gBAAgB,QAEjB,IAAI,oBAAoB,UAAa,mBACxC,IAAI,kBAAkB,OAEhB,IAAI,iBAAiB,GAAiC,IAK1D,aAAa,KAAK;AACtB,QAAI,KAAK,WAAW,QAAW;AAC9B,UAAM,mBAAmB,aAAa,KAAK,MAAM;AACjD,OAAI,eAAe,UAAa,mBAAmB,gBAClD,aAAa;AAAA,IAEf;AAEA,QAAI,YAAY,KAAK;AACrB,IAAI,cAAc,OAAI,YAAY;AAGlC,QAAM,SAAS;AAAA,MACd;AAAA,MACA,aAAa,cAAc;AAAA;AAAA;AAAA;AAAA,MAI3B,OAAO,QAAQ;AAAA,IAChB,GAEI,SACE,oBAA8B,CAAC,GACjC;AAEJ,QAAI,cAAc,QAAW;AAC5B,UAAM,OAAO,IAAI,KAAK,OAAO,aAAa,EAAE,GAAG,QAAQ,UAAU,CAAC,CAAC,GAG7D,cAAc,KAAK,WAAW,QAAQ;AAC5C,WAAK,OAAO,OAAO,CAAC,GAEpB,UAAU,CAAC;AACX,eAAW,OAAO;AACjB,QAAI,IAAI,wBAAwB,WAAW,MAAM,IAChD,kBAAkB,KAAK,IAAI,wBAAwB,UAAU,CAAC,CAAC,IAE/D,QAAQ,KAAK,UAAU,EAAE,GAAG,KAAK,KAAK,IAAI,SAAS,CAAC,CAAC;AAIvD,MAAI,gBAAa,uBAAuB,KAAK,QAAQ,CAAC,EAAE;AAAA,IACzD,OAAO;AAEN,UAAM,QAAQ,KAAK,2BAA2B,aAAa,aAAa,GAClE,OAAO,IAAI,MAAM,MAAM,CAAC,GAGxB,cAAc,KAAK,WAAW,QAAQ;AAC5C,WAAK,OAAO,OAAO,CAAC,GAEpB,UAAU,KAAK,IAAI,SAAS,GAExB,gBAAa,uBAAuB,KAAK,QAAQ,CAAC,EAAE;AAAA,IACzD;AAIA,QAAM,aAAa,WAAW,cAAc,oBAAoB;AAEhE,WAAO;AAAA,MACN;AAAA,MACA,WAAW,eAAe;AAAA,MAC1B,QAAQ;AAAA,MACR;AAAA,IACD;AAAA,EACD;AAAA,EAEA,MAAM,uBACL,KACA,MAC2C;AAC3C,aAAS,IAAI,GAAG;AAEhB,QAAM,WAAW,WAAW;AAC5B,gBAAK,OAAO,sBAAsB;AAAA,MACjC;AAAA,MACA,WAAW;AAAA,MACX,eAAe,KAAK,UAAU,KAAK,gBAAgB,CAAC,CAAC;AAAA,MACrD,iBAAiB,KAAK,UAAU,KAAK,kBAAkB,CAAC,CAAC;AAAA,IAC1D,CAAC,GACM,EAAE,SAAS;AAAA,EACnB;AAAA,EAEA,MAAM,YACL,KACA,UACA,YACA,OACA,WACgC;AAChC,aAAS,IAAI,GAAG;AAGhB,QAAM,YAAY,IAAI,gBAAgB,CAAC,KAAK,CAAC,GACvC,SAAS,MAAM,KAAK,KAAK,IAAI,MAAM,YAAY,SAAS,CAAC,GAEzD,aADU,MAAM,UAAU,SACN,IAAI,KAAK;AACnC,IAAAH,QAAO,cAAc,MAAS;AAG9B,QAAM,OAAO,WAAW,GAIpB;AACJ,QAAI;AACH,uBAAiB,KAAK,OAAO,QAAQ,KAAK;AAAA,QACzC,WAAW;AAAA,QACX,aAAa;AAAA,QACb,SAAS;AAAA,QACT,MAAM;AAAA,QACN;AAAA,QACA,cAAc,UAAU,SAAS,KAAK;AAAA,MACvC,CAAC;AAAA,IACF,SAAS,GAAG;AAGX,iBAAK,kBAAkB,MAAM,GACvB;AAAA,IACP;AACA,WAAI,mBAAmB,UAAW,KAAK,kBAAkB,cAAc,GAEhE,EAAE,KAAK;AAAA,EACf;AAAA,EAEA,MAAM,yBACL,KACA,UACA,OAC4B;AAC5B,aAAS,IAAI,GAAG;AAChB,QAAM,cAAc,KAAK,cACtB,SAAS,+BACT,SAAS,yBACN,EAAE,QAAQ,WAAW,IAAI,KAAK,OAAO;AAAA,MAC1C;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,IACD;AACA,aAAW,UAAU,WAAY,MAAK,kBAAkB,MAAM;AAC9D,WAAO,IAAI,iBAAiB,MAAM;AAAA,EACnC;AAAA,EAEA,MAAM,sBAAsB,KAAa,UAAiC;AACzE,aAAS,IAAI,GAAG;AAChB,QAAM,aAAa,KAAK,OAAO,qBAAqB,KAAK,QAAQ;AACjE,aAAW,UAAU,WAAY,MAAK,kBAAkB,MAAM;AAAA,EAC/D;AAAA,EAGA,MAAoB,OAAO,QAAQ;AAClC,QAAM,WAAW,qBAAqB,GAAG,GAErC;AACJ,QAAI,SAAS,WAAW;AACvB,eAAS,MAAM,KAAK,MAAM,SAAS,MAAM;AAAA,aAC/B,SAAS,WAAW;AAC9B,eAAS,MAAM,KAAK,KAAK,SAAS,QAAQ,QAAQ;AAAA,aACxC,SAAS,WAAW;AAC9B,eAAS,MAAM,KAAK,MAAM,QAAQ;AAAA;AAElC,YAAM,IAAI,cAAc;AAGzB,WAAO,aAAa,MAAM;AAAA,EAC3B;AAAA,EAGA,MAAoB,OAAO,QAAQ;AAClC,QAAM,EAAE,UAAU,cAAc,MAAM,IAAI,MAAM,eAAe,GAAG;AAElE,QAAI,SAAS,WAAW;AACvB,mBAAM,KAAK;AAAA,QACV,YAAY,WAAW,SAAS,SAAS,SAAS;AAAA,MACnD,GACO,IAAI,SAAS;AACd,QAAI,SAAS,WAAW,OAAO;AACrC,UAAM,gBAAgB;AAAA,QACrB,IAAI,QAAQ,IAAI,gBAAgB,KAAK;AAAA,MACtC;AAIA,MAAAA,QAAO,CAAC,MAAM,aAAa,CAAC;AAC5B,UAAM,YAAY,gBAAgB,cAC5B,SAAS,MAAM,KAAK;AAAA,QACzB,SAAS;AAAA,QACT;AAAA,QACA;AAAA,QACA;AAAA,MACD;AACA,aAAO,aAAa,MAAM;AAAA,IAC3B,WAAW,SAAS,WAAW,yBAAyB;AACvD,UAAM,SAAS,MAAM,KAAK;AAAA,QACzB,SAAS;AAAA,QACT;AAAA,MACD;AACA,aAAO,iBAAiB,MAAM;AAAA,IAC/B,WAAW,SAAS,WAAW,cAAc;AAC5C,UAAM,gBAAgB;AAAA,QACrB,IAAI,QAAQ,IAAI,gBAAgB,KAAK;AAAA,MACtC;AAEA,MAAAA,QAAO,CAAC,MAAM,aAAa,CAAC;AAC5B,UAAM,YAAY,gBAAgB,cAC5B,SAAS,MAAM,KAAK;AAAA,QACzB,SAAS;AAAA,QACT,SAAS;AAAA,QACT,SAAS;AAAA,QACT;AAAA,QACA;AAAA,MACD;AACA,aAAO,iBAAiB,MAAM;AAAA,IAC/B,WAAW,SAAS,WAAW,2BAA2B;AACzD,UAAM,SAAS,MAAM,KAAK;AAAA,QACzB,SAAS;AAAA,QACT,SAAS;AAAA,QACT,SAAS;AAAA,MACV;AACA,aAAO,aAAa,MAAM;AAAA,IAC3B,OAAO;AAAA,UAAI,SAAS,WAAW;AAC9B,qBAAM,KAAK,sBAAsB,SAAS,QAAQ,SAAS,QAAQ,GAC5D,IAAI,SAAS;AAEpB,YAAM,IAAI,cAAc;AAAA;AAAA,EAE1B;AACD;AA7EC;AAAA,EADC,IAAI,GAAG;AAAA,GAvaI,eAwaZ,sBAkBA;AAAA,EADC,IAAI,GAAG;AAAA,GAzbI,eA0bZ;",
  "names": ["assert", "Buffer", "identity", "Buffer", "ifMatch", "ifModifiedSince", "Buffer", "Buffer", "assert", "partRows", "identity", "blobId"]
}
