{"version":3,"file":"credentialSelection.mjs","names":[],"sources":["../../../../src/modules/dif-presentation-exchange/utils/credentialSelection.ts"],"sourcesContent":["import {\n  type IPresentationDefinition,\n  type PEX,\n  type SelectResults,\n  Status,\n  type SubmissionRequirementMatch,\n} from '@animo-id/pex'\nimport type {\n  SubmissionRequirementMatchFrom,\n  SubmissionRequirementMatchInputDescriptor,\n} from '@animo-id/pex/dist/main/lib/evaluation/core'\nimport { SubmissionRequirementMatchType } from '@animo-id/pex/dist/main/lib/evaluation/core/index.js'\nimport { JSONPath } from '@astronautlabs/jsonpath'\nimport { decodeSdJwtSync, getClaimsSync } from '@sd-jwt/decode'\nimport type { InputDescriptorV1, InputDescriptorV2, SubmissionRequirement } from '@sphereon/pex-models'\nimport { Rules } from '@sphereon/pex-models'\nimport type { AgentContext } from 'packages/core/src/agent'\nimport { Hasher } from '../../../crypto'\nimport { CredoError } from '../../../error'\nimport type { JsonObject } from '../../../types'\nimport { MdocRecord } from '../../mdoc'\nimport { MdocDeviceResponse } from '../../mdoc/MdocDeviceResponse'\nimport { SdJwtVcRecord } from '../../sd-jwt-vc'\nimport { ClaimFormat, W3cCredentialRecord } from '../../vc'\nimport { DifPresentationExchangeError } from '../DifPresentationExchangeError'\nimport type {\n  DifPexCredentialsForRequest,\n  DifPexCredentialsForRequestRequirement,\n  DifPexCredentialsForRequestSubmissionEntry,\n  SubmissionEntryCredential,\n} from '../models'\nimport { getSphereonOriginalVerifiableCredential } from './transform'\n\nexport async function getCredentialsForRequest(\n  agentContext: AgentContext,\n  // PEX instance with hasher defined\n  pex: PEX,\n  presentationDefinition: IPresentationDefinition,\n  credentialRecords: Array<W3cCredentialRecord | SdJwtVcRecord | MdocRecord>\n): Promise<DifPexCredentialsForRequest> {\n  const encodedCredentials = credentialRecords.map(getSphereonOriginalVerifiableCredential)\n  const selectResultsRaw = pex.selectFrom(presentationDefinition, encodedCredentials)\n\n  const selectResults: CredentialRecordSelectResults = {\n    ...selectResultsRaw,\n    matches: selectResultsRaw.matches ?? [],\n    // Map the encoded credential to their respective credential record\n    verifiableCredential:\n      selectResultsRaw.verifiableCredential?.map((selectedEncoded, index): SubmissionEntryCredential => {\n        const credentialRecordIndex = selectResultsRaw.vcIndexes?.[index]\n        if (credentialRecordIndex === undefined || credentialRecordIndex === -1) {\n          throw new DifPresentationExchangeError('Unable to find credential in credential records.')\n        }\n        const credentialRecord = credentialRecords[credentialRecordIndex]\n        if (credentialRecord instanceof SdJwtVcRecord) {\n          // selectedEncoded always string when SdJwtVcRecord\n          // Get the decoded payload from the the selected credential, this already has SD applied\n          const { jwt, disclosures } = decodeSdJwtSync(selectedEncoded as string, Hasher.hash)\n          const prettyClaims = getClaimsSync(jwt.payload, disclosures, Hasher.hash)\n\n          return {\n            claimFormat: ClaimFormat.SdJwtDc,\n            credentialRecord,\n            disclosedPayload: prettyClaims as JsonObject,\n          }\n        }\n        if (credentialRecord instanceof MdocRecord) {\n          return {\n            claimFormat: ClaimFormat.MsoMdoc,\n            credentialRecord,\n            disclosedPayload: {},\n          }\n        }\n        if (credentialRecord instanceof W3cCredentialRecord) {\n          return {\n            claimFormat: credentialRecord.firstCredential.claimFormat,\n            credentialRecord,\n          }\n        }\n        throw new CredoError('Unrecognized credential record type')\n      }) ?? [],\n  }\n\n  const presentationSubmission: DifPexCredentialsForRequest = {\n    requirements: [],\n    areRequirementsSatisfied: false,\n    name: presentationDefinition.name,\n    purpose: presentationDefinition.purpose,\n  }\n\n  // If there's no submission requirements, ALL input descriptors MUST be satisfied\n  if (!presentationDefinition.submission_requirements || presentationDefinition.submission_requirements.length === 0) {\n    presentationSubmission.requirements = getSubmissionRequirementsForAllInputDescriptors(\n      presentationDefinition.input_descriptors,\n      selectResults\n    )\n  } else {\n    presentationSubmission.requirements = getSubmissionRequirements(presentationDefinition, selectResults)\n  }\n\n  const allEntries = presentationSubmission.requirements.flatMap((requirement) => requirement.submissionEntry)\n\n  const inputDescriptorsForMdocCredential = new Map<SubmissionEntryCredential, Set<string>>()\n  for (const entry of allEntries)\n    for (const verifiableCredential of entry.verifiableCredentials) {\n      if (verifiableCredential.claimFormat !== ClaimFormat.MsoMdoc) continue\n\n      const set = inputDescriptorsForMdocCredential.get(verifiableCredential) ?? new Set()\n      set.add(entry.inputDescriptorId)\n      inputDescriptorsForMdocCredential.set(verifiableCredential, set)\n    }\n\n  // NOTE: it might be better to apply disclosure per credential/match (as that's also how mdoc does this)\n  // however this doesn't work very well in wallets, as you usually won't show the same credential twice with\n  // different disclosed attributes\n  // Apply limit disclosure for all mdocs\n  for (const [verifiableCredential, inputDescriptorIds] of inputDescriptorsForMdocCredential.entries()) {\n    if (verifiableCredential.claimFormat !== ClaimFormat.MsoMdoc) continue\n\n    const inputDescriptorsForCredential = presentationDefinition.input_descriptors.filter(({ id }) =>\n      inputDescriptorIds.has(id)\n    )\n\n    const mdoc = verifiableCredential.credentialRecord.firstCredential\n    verifiableCredential.disclosedPayload = await MdocDeviceResponse.limitDisclosureToInputDescriptor(agentContext, {\n      inputDescriptor: {\n        id: mdoc.docType,\n        format: {\n          mso_mdoc: {\n            alg: [],\n          },\n        },\n        constraints: {\n          limit_disclosure: 'required',\n          fields: inputDescriptorsForCredential.flatMap((i) => i.constraints?.fields ?? []),\n        },\n      },\n      mdoc,\n    })\n  }\n\n  // There may be no requirements if we filter out all optional ones. To not makes things too complicated, we see it as an error\n  // for now if a request is made that has no required requirements (but only e.g. min: 0, which means we don't need to disclose anything)\n  // I see this more as the fault of the presentation definition, as it should have at least some requirements.\n  if (presentationSubmission.requirements.length === 0) {\n    throw new DifPresentationExchangeError(\n      'Presentation Definition does not require any credentials. Optional credentials are not included in the presentation submission.'\n    )\n  }\n\n  if (selectResults.areRequiredCredentialsPresent === Status.ERROR) {\n    return presentationSubmission\n  }\n\n  return {\n    ...presentationSubmission,\n\n    // If all requirements are satisfied, the presentation submission is satisfied\n    areRequirementsSatisfied: presentationSubmission.requirements.every(\n      (requirement) => requirement.isRequirementSatisfied\n    ),\n  }\n}\n\nfunction getSubmissionRequirements(\n  presentationDefinition: IPresentationDefinition,\n  selectResults: CredentialRecordSelectResults\n): Array<DifPexCredentialsForRequestRequirement> {\n  const submissionRequirements: Array<DifPexCredentialsForRequestRequirement> = []\n\n  const matches = selectResults.matches as SubmissionRequirementMatchFrom[]\n  if (!matches.every((match) => match.type === SubmissionRequirementMatchType.SubmissionRequirement && match.from)) {\n    throw new DifPresentationExchangeError(\n      `Expected all matches to be of type '${SubmissionRequirementMatchType.SubmissionRequirement}' with 'from' key.`\n    )\n  }\n\n  // There are submission requirements, so we need to select the input_descriptors\n  // based on the submission requirements\n  presentationDefinition.submission_requirements?.forEach((submissionRequirement, submissionRequirementIndex) => {\n    // Check: if the submissionRequirement uses `from_nested`, as we don't support this yet\n    if (submissionRequirement.from_nested) {\n      throw new DifPresentationExchangeError(\n        \"Presentation definition contains requirement using 'from_nested', which is not supported yet.\"\n      )\n    }\n\n    // Check if there's a 'from'. If not the structure is not as we expect it\n    if (!submissionRequirement.from) {\n      throw new DifPresentationExchangeError(\"Missing 'from' in submission requirement match\")\n    }\n\n    const match = matches.find((match) => match.id === submissionRequirementIndex)\n    if (!match) {\n      throw new Error(`Unable to find a match for submission requirement with index '${submissionRequirementIndex}'`)\n    }\n\n    if (submissionRequirement.rule === Rules.All) {\n      const selectedSubmission = getSubmissionRequirementRuleAll(\n        submissionRequirement,\n        presentationDefinition,\n        selectResults.verifiableCredential,\n        match\n      )\n      submissionRequirements.push(selectedSubmission)\n    } else {\n      const selectedSubmission = getSubmissionRequirementRulePick(\n        submissionRequirement,\n        presentationDefinition,\n        selectResults.verifiableCredential,\n        match\n      )\n\n      submissionRequirements.push(selectedSubmission)\n    }\n  })\n\n  // Submission may have requirement that doesn't require a credential to be submitted (e.g. min: 0)\n  // We use minimization strategy, and thus only disclose the minimum amount of information\n  const requirementsWithCredentials = submissionRequirements.filter((requirement) => requirement.needsCount > 0)\n\n  return requirementsWithCredentials\n}\n\nfunction getSubmissionRequirementsForAllInputDescriptors(\n  inputDescriptors: Array<InputDescriptorV1> | Array<InputDescriptorV2>,\n  selectResults: CredentialRecordSelectResults\n): Array<DifPexCredentialsForRequestRequirement> {\n  const submissionRequirements: Array<DifPexCredentialsForRequestRequirement> = []\n\n  const matches = selectResults.matches as SubmissionRequirementMatchInputDescriptor[]\n  if (!matches.every((match) => match.type === SubmissionRequirementMatchType.InputDescriptor)) {\n    throw new DifPresentationExchangeError(\n      `Expected all matches to be of type '${SubmissionRequirementMatchType.InputDescriptor}' when.`\n    )\n  }\n\n  for (const inputDescriptor of inputDescriptors) {\n    const submission = getSubmissionForInputDescriptor(inputDescriptor, selectResults.verifiableCredential, matches)\n    submissionRequirements.push({\n      rule: Rules.Pick,\n      needsCount: 1, // Every input descriptor is a distinct requirement, so the count is always 1,\n      submissionEntry: [submission],\n      isRequirementSatisfied: submission.verifiableCredentials.length >= 1,\n    })\n  }\n\n  return submissionRequirements\n}\n\nfunction getSubmissionRequirementRuleAll(\n  submissionRequirement: SubmissionRequirement,\n  presentationDefinition: IPresentationDefinition,\n  verifiableCredentials: SubmissionEntryCredential[],\n  match: SubmissionRequirementMatchFrom\n) {\n  // Check if there's a 'from'. If not the structure is not as we expect it\n  if (!submissionRequirement.from)\n    throw new DifPresentationExchangeError(\"Missing 'from' in submission requirement match.\")\n\n  const selectedSubmission: DifPexCredentialsForRequestRequirement = {\n    rule: Rules.All,\n    needsCount: 0,\n    name: submissionRequirement.name,\n    purpose: submissionRequirement.purpose,\n    submissionEntry: [],\n    isRequirementSatisfied: false,\n  }\n\n  for (const inputDescriptor of presentationDefinition.input_descriptors) {\n    // We only want to get the submission if the input descriptor belongs to the group\n    if (!inputDescriptor.group?.includes(match.from)) continue\n\n    const submission = getSubmissionForInputDescriptor(inputDescriptor, verifiableCredentials, match.input_descriptors)\n\n    // Rule ALL, so for every input descriptor that matches in this group, we need to add it\n    selectedSubmission.needsCount += 1\n    selectedSubmission.submissionEntry.push(submission)\n  }\n\n  return {\n    ...selectedSubmission,\n\n    // If all submissions have a credential, the requirement is satisfied\n    isRequirementSatisfied: selectedSubmission.submissionEntry.every(\n      (submission) => submission.verifiableCredentials.length >= 1\n    ),\n  }\n}\n\nfunction getSubmissionRequirementRulePick(\n  submissionRequirement: SubmissionRequirement,\n  presentationDefinition: IPresentationDefinition,\n  verifiableCredentials: SubmissionEntryCredential[],\n  match: SubmissionRequirementMatchFrom\n) {\n  // Check if there's a 'from'. If not the structure is not as we expect it\n  if (!submissionRequirement.from) {\n    throw new DifPresentationExchangeError(\"Missing 'from' in submission requirement match.\")\n  }\n\n  const selectedSubmission: DifPexCredentialsForRequestRequirement = {\n    rule: Rules.Pick,\n    needsCount: submissionRequirement.count ?? submissionRequirement.min ?? 1,\n    name: submissionRequirement.name,\n    purpose: submissionRequirement.purpose,\n    // If there's no count, min, or max we assume one credential is required for submission\n    // however, the exact behavior is not specified in the spec\n    submissionEntry: [],\n    isRequirementSatisfied: false,\n  }\n\n  const satisfiedSubmissions: Array<DifPexCredentialsForRequestSubmissionEntry> = []\n  const unsatisfiedSubmissions: Array<DifPexCredentialsForRequestSubmissionEntry> = []\n\n  for (const inputDescriptor of presentationDefinition.input_descriptors) {\n    // We only want to get the submission if the input descriptor belongs to the group\n    if (!inputDescriptor.group?.includes(match.from)) continue\n\n    const submission = getSubmissionForInputDescriptor(inputDescriptor, verifiableCredentials, match.input_descriptors)\n\n    if (submission.verifiableCredentials.length >= 1) {\n      satisfiedSubmissions.push(submission)\n    } else {\n      unsatisfiedSubmissions.push(submission)\n    }\n\n    // If we have found enough credentials to satisfy the requirement, we could stop\n    // but the user may not want the first x that match, so we continue and return all matches\n    // if (satisfiedSubmissions.length === selectedSubmission.needsCount) break\n  }\n\n  return {\n    ...selectedSubmission,\n\n    // If there are enough satisfied submissions, the requirement is satisfied\n    isRequirementSatisfied: satisfiedSubmissions.length >= selectedSubmission.needsCount,\n\n    // if the requirement is satisfied, we only need to return the satisfied submissions\n    // however if the requirement is not satisfied, we include all entries so the wallet could\n    // render which credentials are missing.\n    submissionEntry:\n      satisfiedSubmissions.length >= selectedSubmission.needsCount\n        ? satisfiedSubmissions\n        : [...satisfiedSubmissions, ...unsatisfiedSubmissions],\n  }\n}\n\nfunction getSubmissionForInputDescriptor(\n  inputDescriptor: InputDescriptorV1 | InputDescriptorV2,\n  verifiableCredentials: SubmissionEntryCredential[],\n  matches: SubmissionRequirementMatchInputDescriptor[]\n): DifPexCredentialsForRequestSubmissionEntry {\n  const matchesForInputDescriptor = matches.filter((m) => m.id === inputDescriptor.id)\n\n  const submissionEntry: DifPexCredentialsForRequestSubmissionEntry = {\n    inputDescriptorId: inputDescriptor.id,\n    name: inputDescriptor.name,\n    purpose: inputDescriptor.purpose,\n    verifiableCredentials: matchesForInputDescriptor.flatMap((matchForInputDescriptor) =>\n      extractCredentialsFromInputDescriptorMatch(matchForInputDescriptor, verifiableCredentials)\n    ),\n  }\n\n  // return early if no matches.\n  if (!matchesForInputDescriptor?.length) return submissionEntry\n\n  return submissionEntry\n}\n\nfunction extractCredentialsFromInputDescriptorMatch(\n  match: SubmissionRequirementMatchInputDescriptor,\n  availableCredentials: SubmissionEntryCredential[]\n) {\n  const verifiableCredentials: SubmissionEntryCredential[] = []\n\n  for (const vcPath of match.vc_path) {\n    const [verifiableCredential] = JSONPath.query(\n      { verifiableCredential: availableCredentials },\n      vcPath\n    ) as SubmissionEntryCredential[]\n    verifiableCredentials.push(verifiableCredential)\n  }\n\n  return verifiableCredentials\n}\n\n/**\n * Custom SelectResults that includes the Credo records instead of the encoded verifiable credential\n */\ntype CredentialRecordSelectResults = Omit<SelectResults, 'verifiableCredential'> & {\n  verifiableCredential: SubmissionEntryCredential[]\n  matches: SubmissionRequirementMatch[]\n}\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;AAiCA,eAAsB,yBACpB,cAEA,KACA,wBACA,mBACsC;CACtC,MAAM,qBAAqB,kBAAkB,IAAI,wCAAwC;CACzF,MAAM,mBAAmB,IAAI,WAAW,wBAAwB,mBAAmB;CAEnF,MAAM,gBAA+C;EACnD,GAAG;EACH,SAAS,iBAAiB,WAAW,EAAE;EAEvC,sBACE,iBAAiB,sBAAsB,KAAK,iBAAiB,UAAqC;GAChG,MAAM,wBAAwB,iBAAiB,YAAY;AAC3D,OAAI,0BAA0B,UAAa,0BAA0B,GACnE,OAAM,IAAI,6BAA6B,mDAAmD;GAE5F,MAAM,mBAAmB,kBAAkB;AAC3C,OAAI,4BAA4B,eAAe;IAG7C,MAAM,EAAE,KAAK,gBAAgB,gBAAgB,iBAA2B,OAAO,KAAK;IACpF,MAAM,eAAe,cAAc,IAAI,SAAS,aAAa,OAAO,KAAK;AAEzE,WAAO;KACL,aAAa,YAAY;KACzB;KACA,kBAAkB;KACnB;;AAEH,OAAI,4BAA4B,WAC9B,QAAO;IACL,aAAa,YAAY;IACzB;IACA,kBAAkB,EAAE;IACrB;AAEH,OAAI,4BAA4B,oBAC9B,QAAO;IACL,aAAa,iBAAiB,gBAAgB;IAC9C;IACD;AAEH,SAAM,IAAI,WAAW,sCAAsC;IAC3D,IAAI,EAAE;EACX;CAED,MAAM,yBAAsD;EAC1D,cAAc,EAAE;EAChB,0BAA0B;EAC1B,MAAM,uBAAuB;EAC7B,SAAS,uBAAuB;EACjC;AAGD,KAAI,CAAC,uBAAuB,2BAA2B,uBAAuB,wBAAwB,WAAW,EAC/G,wBAAuB,eAAe,gDACpC,uBAAuB,mBACvB,cACD;KAED,wBAAuB,eAAe,0BAA0B,wBAAwB,cAAc;CAGxG,MAAM,aAAa,uBAAuB,aAAa,SAAS,gBAAgB,YAAY,gBAAgB;CAE5G,MAAM,oDAAoC,IAAI,KAA6C;AAC3F,MAAK,MAAM,SAAS,WAClB,MAAK,MAAM,wBAAwB,MAAM,uBAAuB;AAC9D,MAAI,qBAAqB,gBAAgB,YAAY,QAAS;EAE9D,MAAM,MAAM,kCAAkC,IAAI,qBAAqB,oBAAI,IAAI,KAAK;AACpF,MAAI,IAAI,MAAM,kBAAkB;AAChC,oCAAkC,IAAI,sBAAsB,IAAI;;AAOpE,MAAK,MAAM,CAAC,sBAAsB,uBAAuB,kCAAkC,SAAS,EAAE;AACpG,MAAI,qBAAqB,gBAAgB,YAAY,QAAS;EAE9D,MAAM,gCAAgC,uBAAuB,kBAAkB,QAAQ,EAAE,SACvF,mBAAmB,IAAI,GAAG,CAC3B;EAED,MAAM,OAAO,qBAAqB,iBAAiB;AACnD,uBAAqB,mBAAmB,MAAM,mBAAmB,iCAAiC,cAAc;GAC9G,iBAAiB;IACf,IAAI,KAAK;IACT,QAAQ,EACN,UAAU,EACR,KAAK,EAAE,EACR,EACF;IACD,aAAa;KACX,kBAAkB;KAClB,QAAQ,8BAA8B,SAAS,MAAM,EAAE,aAAa,UAAU,EAAE,CAAC;KAClF;IACF;GACD;GACD,CAAC;;AAMJ,KAAI,uBAAuB,aAAa,WAAW,EACjD,OAAM,IAAI,6BACR,kIACD;AAGH,KAAI,cAAc,kCAAkC,OAAO,MACzD,QAAO;AAGT,QAAO;EACL,GAAG;EAGH,0BAA0B,uBAAuB,aAAa,OAC3D,gBAAgB,YAAY,uBAC9B;EACF;;AAGH,SAAS,0BACP,wBACA,eAC+C;CAC/C,MAAM,yBAAwE,EAAE;CAEhF,MAAM,UAAU,cAAc;AAC9B,KAAI,CAAC,QAAQ,OAAO,UAAU,MAAM,SAAS,+BAA+B,yBAAyB,MAAM,KAAK,CAC9G,OAAM,IAAI,6BACR,uCAAuC,+BAA+B,sBAAsB,oBAC7F;AAKH,wBAAuB,yBAAyB,SAAS,uBAAuB,+BAA+B;AAE7G,MAAI,sBAAsB,YACxB,OAAM,IAAI,6BACR,gGACD;AAIH,MAAI,CAAC,sBAAsB,KACzB,OAAM,IAAI,6BAA6B,iDAAiD;EAG1F,MAAM,QAAQ,QAAQ,MAAM,UAAU,MAAM,OAAO,2BAA2B;AAC9E,MAAI,CAAC,MACH,OAAM,IAAI,MAAM,iEAAiE,2BAA2B,GAAG;AAGjH,MAAI,sBAAsB,SAAS,MAAM,KAAK;GAC5C,MAAM,qBAAqB,gCACzB,uBACA,wBACA,cAAc,sBACd,MACD;AACD,0BAAuB,KAAK,mBAAmB;SAC1C;GACL,MAAM,qBAAqB,iCACzB,uBACA,wBACA,cAAc,sBACd,MACD;AAED,0BAAuB,KAAK,mBAAmB;;GAEjD;AAMF,QAFoC,uBAAuB,QAAQ,gBAAgB,YAAY,aAAa,EAAE;;AAKhH,SAAS,gDACP,kBACA,eAC+C;CAC/C,MAAM,yBAAwE,EAAE;CAEhF,MAAM,UAAU,cAAc;AAC9B,KAAI,CAAC,QAAQ,OAAO,UAAU,MAAM,SAAS,+BAA+B,gBAAgB,CAC1F,OAAM,IAAI,6BACR,uCAAuC,+BAA+B,gBAAgB,SACvF;AAGH,MAAK,MAAM,mBAAmB,kBAAkB;EAC9C,MAAM,aAAa,gCAAgC,iBAAiB,cAAc,sBAAsB,QAAQ;AAChH,yBAAuB,KAAK;GAC1B,MAAM,MAAM;GACZ,YAAY;GACZ,iBAAiB,CAAC,WAAW;GAC7B,wBAAwB,WAAW,sBAAsB,UAAU;GACpE,CAAC;;AAGJ,QAAO;;AAGT,SAAS,gCACP,uBACA,wBACA,uBACA,OACA;AAEA,KAAI,CAAC,sBAAsB,KACzB,OAAM,IAAI,6BAA6B,kDAAkD;CAE3F,MAAM,qBAA6D;EACjE,MAAM,MAAM;EACZ,YAAY;EACZ,MAAM,sBAAsB;EAC5B,SAAS,sBAAsB;EAC/B,iBAAiB,EAAE;EACnB,wBAAwB;EACzB;AAED,MAAK,MAAM,mBAAmB,uBAAuB,mBAAmB;AAEtE,MAAI,CAAC,gBAAgB,OAAO,SAAS,MAAM,KAAK,CAAE;EAElD,MAAM,aAAa,gCAAgC,iBAAiB,uBAAuB,MAAM,kBAAkB;AAGnH,qBAAmB,cAAc;AACjC,qBAAmB,gBAAgB,KAAK,WAAW;;AAGrD,QAAO;EACL,GAAG;EAGH,wBAAwB,mBAAmB,gBAAgB,OACxD,eAAe,WAAW,sBAAsB,UAAU,EAC5D;EACF;;AAGH,SAAS,iCACP,uBACA,wBACA,uBACA,OACA;AAEA,KAAI,CAAC,sBAAsB,KACzB,OAAM,IAAI,6BAA6B,kDAAkD;CAG3F,MAAM,qBAA6D;EACjE,MAAM,MAAM;EACZ,YAAY,sBAAsB,SAAS,sBAAsB,OAAO;EACxE,MAAM,sBAAsB;EAC5B,SAAS,sBAAsB;EAG/B,iBAAiB,EAAE;EACnB,wBAAwB;EACzB;CAED,MAAM,uBAA0E,EAAE;CAClF,MAAM,yBAA4E,EAAE;AAEpF,MAAK,MAAM,mBAAmB,uBAAuB,mBAAmB;AAEtE,MAAI,CAAC,gBAAgB,OAAO,SAAS,MAAM,KAAK,CAAE;EAElD,MAAM,aAAa,gCAAgC,iBAAiB,uBAAuB,MAAM,kBAAkB;AAEnH,MAAI,WAAW,sBAAsB,UAAU,EAC7C,sBAAqB,KAAK,WAAW;MAErC,wBAAuB,KAAK,WAAW;;AAQ3C,QAAO;EACL,GAAG;EAGH,wBAAwB,qBAAqB,UAAU,mBAAmB;EAK1E,iBACE,qBAAqB,UAAU,mBAAmB,aAC9C,uBACA,CAAC,GAAG,sBAAsB,GAAG,uBAAuB;EAC3D;;AAGH,SAAS,gCACP,iBACA,uBACA,SAC4C;CAC5C,MAAM,4BAA4B,QAAQ,QAAQ,MAAM,EAAE,OAAO,gBAAgB,GAAG;CAEpF,MAAM,kBAA8D;EAClE,mBAAmB,gBAAgB;EACnC,MAAM,gBAAgB;EACtB,SAAS,gBAAgB;EACzB,uBAAuB,0BAA0B,SAAS,4BACxD,2CAA2C,yBAAyB,sBAAsB,CAC3F;EACF;AAGD,KAAI,CAAC,2BAA2B,OAAQ,QAAO;AAE/C,QAAO;;AAGT,SAAS,2CACP,OACA,sBACA;CACA,MAAM,wBAAqD,EAAE;AAE7D,MAAK,MAAM,UAAU,MAAM,SAAS;EAClC,MAAM,CAAC,wBAAwB,SAAS,MACtC,EAAE,sBAAsB,sBAAsB,EAC9C,OACD;AACD,wBAAsB,KAAK,qBAAqB;;AAGlD,QAAO"}