UNPKG

@halospv3/hce.shared-config

Version:

Automate commit message quality, changelogs, and CI/CD releases. Its `main` entry point is a Semantic Release config. Functions and classes are exposed for customization. An ESLint config, a Commitlint config, and addl. resources for .NET projects are als

1 lines 25.5 kB
{"version":3,"file":"helpers.mjs","names":["path","MSBPP"],"sources":["../../src/dotnet/helpers.ts"],"sourcesContent":["import { type, type Type } from 'arktype';\n// eslint-disable-next-line unicorn/import-style\nimport * as path from 'node:path';\nimport { cwd } from 'node:process';\nimport { MSBuildProject } from './MSBuildProject.ts';\nimport { MSBuildProjectProperties as MSBPP } from './MSBuildProjectProperties.ts';\nimport { NugetRegistryInfo } from './NugetRegistryInfo.ts';\nimport type { Default } from 'arktype/internal/attributes.ts';\n\nconst ourDefaultPubDirectory = path.join('.', 'publish') as `.${'/' | '\\\\'}publish`;\n\n/**\n * Build a prepareCmd string from .NET projects.\\\n * This will include a `dotnet publish` for each project's RID and TFM permutation,\\\n * `dotnet pack` for each project with output paths separated by NuGet Source and PackageId,\\\n * and `dotnet nuget sign` for each nupkg output directory.\n * @todo parse Solution files to publish all projects with default Publish parameters (as evaluated by MSBuild).\n * @param projectsToPublish An array of relative or full file paths of `.csproj`\n * projects -OR- an array of {@link MSBuildProject} objects.\n * The project paths will be passed to `dotnet publish` commands.\n * @param projectsToPackAndPush\n * Relative and/or full file paths of projects to pass to `dotnet pack`. If\n * string[], only the default NuGet Source will be used. If GitHub, GitLab,\n * etc. are also desired, pass {@link NugetRegistryInfo}[]\n * @param dotnetNugetSignOpts A {@link DotnetNugetSignOptions} object. The value\n * of the `--output` argument will be set to {@link ourDefaultPubDir} if `undefined`.\n * @returns A single string of CLI commands joined by ' && '\n */\n// eslint-disable-next-line unicorn/name-replacements\nexport async function configurePrepareCmd(\n projectsToPublish: string[] | MSBuildProject[],\n projectsToPackAndPush?: string[] | NugetRegistryInfo[],\n // eslint-disable-next-line unicorn/name-replacements\n dotnetNugetSignOpts?: typeof DotnetNugetSignOptions.inferIn,\n): Promise<string> {\n const evaluatedProjects: MSBuildProject[] = projectsToPublish.filter(p => p instanceof MSBuildProject);\n\n if (projectsToPackAndPush) {\n for (const project of projectsToPackAndPush) {\n if (project instanceof NugetRegistryInfo)\n evaluatedProjects.push(project.project);\n }\n }\n\n const dotnetPublishCommand: string = await formatDotnetPublish(projectsToPublish);\n const dotnetPackCommand: string | undefined = await formatDotnetPack(projectsToPackAndPush ?? []);\n const dotnetNugetSignCommand: string | undefined = formatDotnetNugetSign(dotnetNugetSignOpts);\n\n return [\n dotnetPublishCommand,\n dotnetPackCommand,\n dotnetNugetSignCommand,\n // remove no-op commands\n ]\n .filter(v => v !== undefined)\n .join(' && ');\n\n /**\n * Create a string of CLI commands to run `dotnet publish` or the Publish\n * MSBuild target for one or more projects.\n * @async\n * @param projectsToPublish An array of one or more projects, either\n * pre-evaluated (see {@link MSBuildProject.Evaluate}) or as full file paths.\\\n * NOTE: Although `dotnet publish` allows directory or Solution file (.sln,\n * .slnx) paths, this function expects projects' full or relative file\n * paths.\n * @returns A Promise of a string. This string contains one or more `dotnet publish`\n * commands conjoined by \" && \". It may also include one or more\n * `dotnet msbuild ${...} -restore -t:PublishAll -p:Configuration=Release` commands.\n */\n async function formatDotnetPublish(\n projectsToPublish: string[] | MSBuildProject[],\n ): Promise<string> {\n /* Fun Fact: You can define a property and get the evaluated value in the same command!\n ```pwsh\n dotnet msbuild .\\src\\HXE.csproj -property:RuntimeIdentifiers=\"\"\"place;holder\"\"\" -getProperty:RuntimeIdentifiers\n place;holder\n ```\n enclosing with \"\"\" is required in pwsh to prevent the semicolon from breaking the string.\n */\n if (!Array.isArray(projectsToPublish) || projectsToPublish.length === 0) {\n throw new Error(\n `Type of projectsToPublish (${typeof projectsToPublish}) is not allowed. Expected a string[] or MSBuildProject[] where length > 0.`,\n );\n }\n\n // each may have TargetFramework OR TargetFrameworks (plural)\n const evaluatedPublishProjects: MSBuildProject[] = await Promise.all(\n projectsToPublish.map(async (proj): Promise<MSBuildProject> => {\n if (proj instanceof MSBuildProject)\n return proj;\n\n // filter for projects whose full paths match the full path of the given string\n const filteredProjects = evaluatedProjects.filter(p =>\n p.Properties.MSBuildProjectFullPath === MSBPP.GetFullPath(proj),\n );\n\n // if no pre-existing MSBuildProject found,\n // evaluate a new one and push it\n if (filteredProjects.length === 0) {\n const _proj = await MSBuildProject.Evaluate({\n FullName: proj,\n GetProperty: MSBuildProject.MatrixProperties,\n GetItem: [],\n GetTargetResult: [],\n Property: {},\n Targets: ['Restore'],\n });\n evaluatedProjects.push(_proj);\n return _proj;\n }\n\n /**\n * Finds and returns the subjectively \"best\" project in {@link filteredProjects}\n * @returns the subjective \"best\" project in {@link filteredProjects}\n */\n function getBest() {\n let best: MSBuildProject | undefined;\n if (filteredProjects.length > 0 && (best = filteredProjects[0]) instanceof MSBuildProject)\n return best;\n throw new Error('No MSBuildProjects could be found!');\n }\n\n /*\n todo: improve filtering to select \"optimal\" instance.\n Which properties are most-needed?\n For now, we just pray the project has a well-defined publish flow e.g.\n @halospv3/hce.shared-config/dotnet/PublishAll.targets\n */\n return getBest();\n }),\n );\n\n /**\n * Returns an array of one or more `dotnet` arguments.\n * @param proj An {@link MSBuildProject} to be published for one or more\n * runtime-framework combinations.\n * @returns If {@link proj} imports {@link ../../dotnet/PublishAll.targets}...\n * ```\n * [`${proj.Properties.MSBuildProjectFullPath} -restore -t:PublishAll -p:Configuration=Release`]\n * ```\n * Else, an array of `dotnet publish` arguments permutations e.g.\n * ```\n * [\n * 'myProj.csproj --runtime win7-x86 --framework net6.0',\n * 'myProj.csproj --runtime win7-x64 --framework net6.0'\n * ]\n * ```\n * @example\n * const publishCmdArray = [];\n * const permutations = getPublishArgsPermutations(msbuildProject);\n * for (const permutation of permutations) {\n * if (permutation[0] === 'PublishAll') {\n * // 'dotnet msbuild full/path/to/myProj.csproj t:PublishAll'\n * publishCmdArray.push(`dotnet msbuild ${permutation[1]}`)\n * }\n * else {\n * publishCmdArray.push(`dotnet publish ${permutation}`)\n * }\n * }\n * // return array as success-chained CLI commands.\n * return publishCmdArray.join(' && ');\n */\n function getPublishArgumentsPermutations(proj: MSBuildProject):\n ([`\"${typeof proj.Properties.MSBuildProjectFullPath}\" -restore -t:PublishAll -p:Configuration=Release`])\n | ([`\"${typeof proj.Properties.MSBuildProjectFullPath}\"`])\n | (`\"${typeof proj.Properties.MSBuildProjectFullPath}\" --runtime ${string} --framework ${string}`)[]\n | (`\"${typeof proj.Properties.MSBuildProjectFullPath}\" --runtime ${string}`)[]\n | (`\"${typeof proj.Properties.MSBuildProjectFullPath}\" --framework ${string}`)[] {\n /**\n * If the project imports PublishAll to publish for each TFM-RID\n * permutation, return the appropriate command line.\n */\n if (proj.Targets.includes('PublishAll'))\n return [`\"${proj.Properties.MSBuildProjectFullPath}\" -restore -t:PublishAll -p:Configuration=Release`];\n\n // #region formatFrameworksAndRuntimes\n const tfmRidPermutations: `--runtime ${string} --framework ${string}`[]\n | `--runtime ${string}`[]\n | `--framework ${string}`[]\n = []; // forEach, run dotnet [proj.Properties.MSBuildProjectFullPath,...v]\n const RIDs: string[] = proj.Properties.RuntimeIdentifiers.split(';').filter(v => v !== '');\n const TFMs: string[] = proj.Properties.TargetFrameworks.split(';').filter(v => v !== '');\n\n if (TFMs.length === 0 && RIDs.length === 0)\n return [`\"${proj.Properties.MSBuildProjectFullPath}\"`] as [`\"${string}\"`];\n\n if (RIDs.length > 0) {\n if (TFMs.length > 0) {\n for (const RID of RIDs) {\n for (const TFM of TFMs) {\n (tfmRidPermutations as `--runtime ${string} --framework ${string}`[]).push(\n `--runtime ${RID} --framework ${TFM}`,\n );\n }\n }\n }\n else {\n // assume singular TFM. No need to specify it.\n for (const RID of RIDs) {\n (tfmRidPermutations as `--runtime ${string}`[]).push(\n `--runtime ${RID}`,\n );\n }\n }\n }\n else if (TFMs.length > 0) {\n for (const TFM of TFMs) {\n (tfmRidPermutations as `--framework ${string}`[]).push(`--framework ${TFM}`);\n }\n }\n\n /** prepend each set of args with the project's path */\n return tfmRidPermutations.map(permArguments =>\n `\"${proj.Properties.MSBuildProjectFullPath}\" ${permArguments}`,\n ) as `\"${typeof proj.Properties.MSBuildProjectFullPath}\" --runtime ${string} --framework ${string}`[]\n | `\"${typeof proj.Properties.MSBuildProjectFullPath}\" --runtime ${string}`[]\n | `\"${typeof proj.Properties.MSBuildProjectFullPath}\" --framework ${string}`[];\n // #endregion formatFrameworksAndRuntimes\n }\n\n const publishCmds: (`dotnet publish \"${string}\"` | `dotnet publish \"${string}\" ${string}` | `dotnet msbuild \"${string}\" -restore -t:PublishAll -p:Configuration=Release`)[] = [];\n /** convert {@link evaluatedPublishProjects} to sets of space-separated CLI args. */\n const argumentsSets = evaluatedPublishProjects.map(\n proj => getPublishArgumentsPermutations(proj),\n );\n for (const arguments_ of argumentsSets) {\n if (typeof arguments_ === 'string')\n throw new Error(`\\`args\\` should not be a string!`);\n for (const permutation of arguments_) {\n if (typeof permutation === 'string' && permutation.length === 1)\n throw new Error('Something has gone terribly wrong. A `dotnet publish` argument set was split to single characters!');\n if (/\".+\" -restore -t:PublishAll -p:Configuration=Release/.test(permutation))\n publishCmds.push(`dotnet msbuild ${permutation as `\"${string}\" -restore -t:PublishAll -p:Configuration=Release`}`);\n else\n publishCmds.push(`dotnet publish ${permutation}`);\n }\n }\n\n // For each argSet, create a new exec command. Then, join all commands with ' && ' so they are executed serially, synchronously.\n // e.g. `dotnet publish project.csproj --runtime win7-x86 --framework net6.0 && dotnet publish project.csproj --runtime win-x64 --framework net8.0\n return publishCmds.join(' && ');\n }\n\n /**\n * @param projectsToPackAndPush a string[] or {@link NugetRegistryInfo}[].\n * If a string[], the string must be the platform-dependent (not file://),\n * full path(s) to one or more projects with the .NET \"Pack\" MSBuild target.\n * See {@link https://learn.microsoft.com/en-us/dotnet/core/tools/dotnet-pack}\n * for command line usage.\n * @returns one or more command line strings joined with ' && '.\n * Each command line comprises the `dotnet pack` command, a project file path,\n * and a hardcoded output path (`--output ${cwd()}/publish`)\n */\n async function formatDotnetPack(\n projectsToPackAndPush: string[] | NugetRegistryInfo[],\n ): Promise<string | undefined> {\n if (projectsToPackAndPush.length === 0)\n return undefined;\n const nriArray = await Promise.all(\n projectsToPackAndPush.map(async (proj) => {\n if (proj instanceof NugetRegistryInfo)\n return proj;\n\n const msbpArray: MSBuildProject[] = await Promise.all(await MSBuildProject.PackableProjectsToMSBuildProjects([proj]));\n if (msbpArray.length === 0 || msbpArray[0] === undefined) {\n throw new Error('This should be impossible!');\n }\n const msbp: MSBuildProject = msbpArray[0];\n\n evaluatedProjects.push(msbp);\n\n return new NugetRegistryInfo({ project: msbp });\n }),\n );\n\n return nriArray\n .map((nri: NugetRegistryInfo): string =>\n nri.GetPackCommand(NugetRegistryInfo.PackPackagesOptionsType.from({})),\n ).join(' && ');\n }\n}\n\n/**\n * Prepare the CLI command to push NuGet packages. This should added to the `publishCmd` option of `@semantic-release/exec`\n *\n * Ensure your verifyConditionsCmd is set to prevent releases failing due to bad tokens or packages!\n * See {@link NugetRegistryInfo#PackDummyPackage}, {@link NugetRegistryInfo#GetPushDummyCommand}\n * @param registryInfos an array of {@link NugetRegistryInfo} (or derived classes) instances.\n * @param packageOutputPath Default: `${cwd()}/publish`.\\\n * The directory at which dotnet outputs the given projects' packages. Passed to\n * `dotnet pack` via the `--output` argument.\n * @returns a string of `dotnet pack` and `dotnet push` commands, joined by ' && '.\n */\nexport function configureDotnetNugetPush(\n registryInfos: NugetRegistryInfo[],\n // Explicit type required by JSR\n // eslint-disable-next-line @typescript-eslint/no-inferrable-types\n packageOutputPath: string = `${cwd()}/publish`,\n): string {\n if (registryInfos.some(registry => registry.source.trim() === ''))\n throw new Error('The URL for one of the provided NuGet registries was empty or whitespace.');\n\n const packCmds = registryInfos.map(\n (nri): string =>\n nri.GetPackCommand(\n { output: packageOutputPath },\n true,\n true,\n ),\n );\n\n const pushCmds = registryInfos.map(nri => nri.GetPushCommand({ root: packageOutputPath }, true, true));\n\n return [...packCmds, ...pushCmds].join(' && ');\n}\n\n/**\n * You should try {@link ../../dotnet/SignAfterPack.targets}!.\n * @param opts A {@link DotnetNugetSignOptions} object to be deconstructed and\n * passed to `dotnet nuget sign` as args.\n * @returns `dotnet nuget sign {...}`\n */\nfunction formatDotnetNugetSign(\n // eslint-disable-next-line unicorn/name-replacements\n opts: typeof DotnetNugetSignOptions.inferIn | undefined,\n): string | undefined {\n if (opts === undefined)\n return undefined;\n\n const validOptions = DotnetNugetSignOptions.from(opts);\n const arguments_: ['--timestamper', typeof validOptions.timestamper, '-o', string, ...string[]] = [\n '--timestamper', validOptions.timestamper,\n '-o', validOptions.output ?? ourDefaultPubDirectory,\n ];\n if (validOptions.certificatePassword)\n arguments_.push('---certificate-password', validOptions.certificatePassword);\n if (validOptions.hashAlgorithm)\n arguments_.push('--hash-algorithm', validOptions.hashAlgorithm);\n if (validOptions.overwrite)\n arguments_.push('--overwrite');\n if (validOptions.timestampHashAlgorithm)\n arguments_.push('--timestamp-hash-algorithm', validOptions.timestampHashAlgorithm);\n if (validOptions.verbosity)\n arguments_.push('-v', validOptions.verbosity);\n\n if ('certificatePath' in validOptions)\n arguments_.push('--certificate-path', validOptions.certificatePath);\n else if ('certificateStoreName' in validOptions) {\n SetSubjectNameOrFingerprint();\n arguments_.push('--certificate-store-name', validOptions.certificateStoreName);\n }\n else if ('certificateStoreLocation' in validOptions) {\n SetSubjectNameOrFingerprint();\n arguments_.push('--certificate-store-location', validOptions.certificateStoreLocation);\n }\n else throw new Error('No code signing certificate was specified!');\n\n return `dotnet nuget sign ${arguments_.join(' ')} `;\n\n // eslint-disable-next-line jsdoc/require-jsdoc\n function SetSubjectNameOrFingerprint() {\n if ('certificateSubjectName' in validOptions)\n arguments_.push('--certificate-subject-name', validOptions.certificateSubjectName);\n\n else if ('certificateFingerprint' in validOptions)\n arguments_.push('--certificate-fingerprint', validOptions.certificateFingerprint);\n else throw new Error('If certificateStoreName or certificateStoreLocation is set, either certificateSubjectName or certificateFingerprint must also be set!');\n }\n}\n\nconst DotnetNugetSignOptions: Type<\n {\n timestamper: Default<string, 'https://rfc3161.ai.moda/'>;\n certificatePassword?: string | undefined;\n hashAlgorithm?: string | undefined;\n output?: string | undefined;\n overwrite?: true | undefined;\n timestampHashAlgorithm?: string | undefined;\n verbosity?: 'q' | 'quiet' | 'm' | 'minimal' | 'n' | 'normal' | 'd' | 'detailed' | 'diag' | 'diagnostic';\n } & ({\n certificatePath: string;\n certificateSubjectName: string;\n } | {\n certificatePath: string;\n certificateFingerprint: string;\n } | {\n certificateStoreName: string;\n certificateSubjectName: string;\n } | {\n certificateStoreName: string;\n certificateFingerprint: string;\n } | {\n certificateStoreLocation: string;\n certificateSubjectName: string;\n } | {\n certificateStoreLocation: string;\n certificateFingerprint: string;\n })> = type({\n /**\n * Password for the certificate, if needed. This option can be used to specify\n * the password for the certificate. The command will throw an error message\n * if certificate is password protected but password is not provided as input.\n */\n 'certificatePassword?': 'string',\n /**\n * Hash algorithm to be used to sign the package. Defaults to SHA256.\n */\n 'hashAlgorithm?': 'string | \"SHA256\"',\n /**\n * Directory where the signed package(s) should be saved. By default the\n * original package is overwritten by the signed package.\n */\n 'output?': 'string',\n /**\n * Switch to indicate if the current signature should be overwritten. By\n * default the command will fail if the package already has a signature.\n */\n 'overwrite?': 'true',\n /**\n * URL to an RFC 3161 timestamping server.\n */\n timestamper: 'string = \"https://rfc3161.ai.moda/\"',\n /**\n * Hash algorithm to be used to sign the package. Defaults to SHA256.\n */\n 'timestampHashAlgorithm?': 'string | \"SHA256\"',\n /**\n * Set the verbosity level of the command. Allowed values are q[uiet],\n * m[inimal], n[ormal], d[etailed], and diag[nostic].\n */\n 'verbosity?': '\"q\"|\"quiet\"|\"m\"|\"minimal\"|\"n\"|\"normal\"|\"d\"|\"detailed\"|\"diag\"|\"diagnostic\"',\n}).and(\n type({\n /**\n * File path to the certificate to be used while signing the package.\n */\n certificatePath: 'string',\n }).or(\n type({\n /**\n * Name of the X.509 certificate store to use to search for the\n * certificate. Defaults to \"My\", the X.509 certificate store for personal\n * certificates.\n *\n * This option should be used when specifying the certificate via\n * --certificate-subject-name or --certificate-fingerprint options.\n */\n certificateStoreName: 'string',\n }).or({\n /**\n * Name of the X.509 certificate store use to search for the\n * certificate. Defaults to \"CurrentUser\", the X.509 certificate store\n * used by the current user.\n *\n * This option should be used when specifying the certificate via\n * --certificate-subject-name or --certificate-fingerprint options.\n */\n certificateStoreLocation: 'string',\n }),\n ).and(\n type({\n /**\n * Subject name of the certificate used to search a local certificate\n * store for the certificate. The search is a case-insensitive string\n * comparison using the supplied value, which will find all certificates\n * with the subject name containing that string, regardless of other\n * subject values. The certificate store can be specified by\n * --certificate-store-name and --certificate-store-location options.\n */\n certificateSubjectName: 'string',\n }).or({\n /**\n * SHA-256, SHA-384 or SHA-512 fingerprint of the certificate used to\n * search a local certificate store for the certificate. The certificate\n * store can be specified by --certificate-store-name and\n * --certificate-store-location options.\n */\n certificateFingerprint: 'string',\n }),\n ),\n);\n"],"mappings":";;;;;;;AASA,MAAM,yBAAyBA,OAAK,KAAK,KAAK,SAAS;;;;;;;;;;;;;;;;;;AAoBvD,eAAsB,oBACpB,mBACA,uBAEA,qBACiB;CACjB,MAAM,oBAAsC,kBAAkB,QAAO,MAAK,aAAa,cAAc;CAErG,IAAI,uBACG;OAAA,MAAM,WAAW,uBACpB,IAAI,mBAAmB,mBACrB,kBAAkB,KAAK,QAAQ,OAAO;CAAA;CAQ5C,OAAO;EACL,MALyC,oBAAoB,iBAAiB;EAM9E,MALkD,iBAAiB,yBAAyB,CAAC,CAAC;EAC7C,sBAAsB,mBAKlD;CAEvB,CAAC,CACE,QAAO,MAAK,MAAM,KAAA,CAAS,CAAC,CAC5B,KAAK,MAAM;;;;;;;;;;;;;;CAed,eAAe,oBACb,mBACiB;EAQjB,IAAI,CAAC,MAAM,QAAQ,iBAAiB,KAAK,kBAAkB,WAAW,GACpE,MAAM,IAAI,MACR,8BAA8B,OAAO,kBAAkB,4EACzD;EAIF,MAAM,2BAA6C,MAAM,QAAQ,IAC/D,kBAAkB,IAAI,OAAO,SAAkC;GAC7D,IAAI,gBAAgB,gBAClB,OAAO;GAGT,MAAM,mBAAmB,kBAAkB,QAAO,MAChD,EAAE,WAAW,2BAA2BC,yBAAM,YAAY,IAAI,CAChE;GAIA,IAAI,iBAAiB,WAAW,GAAG;IACjC,MAAM,QAAQ,MAAM,eAAe,SAAS;KAC1C,UAAU;KACV,aAAa,eAAe;KAC5B,SAAS,CAAC;KACV,iBAAiB,CAAC;KAClB,UAAU,CAAC;KACX,SAAS,CAAC,SAAS;IACrB,CAAC;IACD,kBAAkB,KAAK,KAAK;IAC5B,OAAO;GACT;;;;;GAMA,SAAS,UAAU;IACjB,IAAI;IACJ,IAAI,iBAAiB,SAAS,MAAM,OAAO,iBAAiB,eAAe,gBACzE,OAAO;IACT,MAAM,IAAI,MAAM,oCAAoC;GACtD;GAQA,OAAO,QAAQ;EACjB,CAAC,CACH;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;EAgCA,SAAS,gCAAgC,MAK0C;;;;;GAKjF,IAAI,KAAK,QAAQ,SAAS,YAAY,GACpC,OAAO,CAAC,IAAI,KAAK,WAAW,uBAAuB,kDAAkD;GAGvG,MAAM,qBAGA,CAAC;GACP,MAAM,OAAiB,KAAK,WAAW,mBAAmB,MAAM,GAAG,CAAC,CAAC,QAAO,MAAK,MAAM,EAAE;GACzF,MAAM,OAAiB,KAAK,WAAW,iBAAiB,MAAM,GAAG,CAAC,CAAC,QAAO,MAAK,MAAM,EAAE;GAEvF,IAAI,KAAK,WAAW,KAAK,KAAK,WAAW,GACvC,OAAO,CAAC,IAAI,KAAK,WAAW,uBAAuB,EAAE;GAEvD,IAAI,KAAK,SAAS,GAChB,IAAI,KAAK,SAAS,GAChB,KAAK,MAAM,OAAO,MAChB,KAAK,MAAM,OAAO,MAChB,mBAAsE,KACpE,aAAa,IAAI,eAAe,KAClC;QAMJ,KAAK,MAAM,OAAO,MAChB,mBAAgD,KAC9C,aAAa,KACf;QAID,IAAI,KAAK,SAAS,GACrB,KAAK,MAAM,OAAO,MAChB,mBAAkD,KAAK,eAAe,KAAK;;GAK/E,OAAO,mBAAmB,KAAI,kBAC5B,IAAI,KAAK,WAAW,uBAAuB,IAAI,eACjD;EAIF;EAEA,MAAM,cAAwK,CAAC;;EAE/K,MAAM,gBAAgB,yBAAyB,KAC7C,SAAQ,gCAAgC,IAAI,CAC9C;EACA,KAAK,MAAM,cAAc,eAAe;GACtC,IAAI,OAAO,eAAe,UACxB,MAAM,IAAI,MAAM,kCAAkC;GACpD,KAAK,MAAM,eAAe,YAAY;IACpC,IAAI,OAAO,gBAAgB,YAAY,YAAY,WAAW,GAC5D,MAAM,IAAI,MAAM,oGAAoG;IACtH,IAAI,uDAAuD,KAAK,WAAW,GACzE,YAAY,KAAK,kBAAkB,aAA8E;SAEjH,YAAY,KAAK,kBAAkB,aAAa;GACpD;EACF;EAIA,OAAO,YAAY,KAAK,MAAM;CAChC;;;;;;;;;;;CAYA,eAAe,iBACb,uBAC6B;EAC7B,IAAI,sBAAsB,WAAW,GACnC,OAAO,KAAA;EAkBT,QAAO,MAjBgB,QAAQ,IAC7B,sBAAsB,IAAI,OAAO,SAAS;GACxC,IAAI,gBAAgB,mBAClB,OAAO;GAET,MAAM,YAA8B,MAAM,QAAQ,IAAI,MAAM,eAAe,kCAAkC,CAAC,IAAI,CAAC,CAAC;GACpH,IAAI,UAAU,WAAW,KAAK,UAAU,OAAO,KAAA,GAC7C,MAAM,IAAI,MAAM,4BAA4B;GAE9C,MAAM,OAAuB,UAAU;GAEvC,kBAAkB,KAAK,IAAI;GAE3B,OAAO,IAAI,kBAAkB,EAAE,SAAS,KAAK,CAAC;EAChD,CAAC,CACH,EAAA,CAGG,KAAK,QACJ,IAAI,eAAe,kBAAkB,wBAAwB,KAAK,CAAC,CAAC,CAAC,CACvE,CAAC,CAAC,KAAK,MAAM;CACjB;AACF;;;;;;;;;;;;AAaA,SAAgB,yBACd,eAGA,oBAA4B,GAAG,IAAI,EAAE,WAC7B;CACR,IAAI,cAAc,MAAK,aAAY,SAAS,OAAO,KAAK,MAAM,EAAE,GAC9D,MAAM,IAAI,MAAM,2EAA2E;CAE7F,MAAM,WAAW,cAAc,KAC5B,QACC,IAAI,eACF,EAAE,QAAQ,kBAAkB,GAC5B,MACA,IACF,CACJ;CAEA,MAAM,WAAW,cAAc,KAAI,QAAO,IAAI,eAAe,EAAE,MAAM,kBAAkB,GAAG,MAAM,IAAI,CAAC;CAErG,OAAO,CAAC,GAAG,UAAU,GAAG,QAAQ,CAAC,CAAC,KAAK,MAAM;AAC/C;;;;;;;AAQA,SAAS,sBAEP,MACoB;CACpB,IAAI,SAAS,KAAA,GACX,OAAO,KAAA;CAET,MAAM,eAAe,uBAAuB,KAAK,IAAI;CACrD,MAAM,aAA4F;EAChG;EAAiB,aAAa;EAC9B;EAAM,aAAa,UAAU;CAC/B;CACA,IAAI,aAAa,qBACf,WAAW,KAAK,2BAA2B,aAAa,mBAAmB;CAC7E,IAAI,aAAa,eACf,WAAW,KAAK,oBAAoB,aAAa,aAAa;CAChE,IAAI,aAAa,WACf,WAAW,KAAK,aAAa;CAC/B,IAAI,aAAa,wBACf,WAAW,KAAK,8BAA8B,aAAa,sBAAsB;CACnF,IAAI,aAAa,WACf,WAAW,KAAK,MAAM,aAAa,SAAS;CAE9C,IAAI,qBAAqB,cACvB,WAAW,KAAK,sBAAsB,aAAa,eAAe;MAC/D,IAAI,0BAA0B,cAAc;EAC/C,4BAA4B;EAC5B,WAAW,KAAK,4BAA4B,aAAa,oBAAoB;CAC/E,OACK,IAAI,8BAA8B,cAAc;EACnD,4BAA4B;EAC5B,WAAW,KAAK,gCAAgC,aAAa,wBAAwB;CACvF,OACK,MAAM,IAAI,MAAM,4CAA4C;CAEjE,OAAO,qBAAqB,WAAW,KAAK,GAAG,EAAE;CAGjD,SAAS,8BAA8B;EACrC,IAAI,4BAA4B,cAC9B,WAAW,KAAK,8BAA8B,aAAa,sBAAsB;OAE9E,IAAI,4BAA4B,cACnC,WAAW,KAAK,6BAA6B,aAAa,sBAAsB;OAC7E,MAAM,IAAI,MAAM,uIAAuI;CAC9J;AACF;AAEA,MAAM,yBA2BE,KAAK;;;;;;CAMX,wBAAwB;;;;CAIxB,kBAAkB;;;;;CAKlB,WAAW;;;;;CAKX,cAAc;;;;CAId,aAAa;;;;CAIb,2BAA2B;;;;;CAK3B,cAAc;AAChB,CAAC,CAAC,CAAC,IACD,KAAK;;;;AAIH,iBAAiB,SACnB,CAAC,CAAC,CAAC,GACD,KAAK;;;;;;;;;AASH,sBAAsB,SACxB,CAAC,CAAC,CAAC,GAAG;;;;;;;;;AASJ,0BAA0B,SAC5B,CAAC,CACH,CAAC,CAAC,IACA,KAAK;;;;;;;;;AASH,wBAAwB,SAC1B,CAAC,CAAC,CAAC,GAAG;;;;;;;AAOJ,wBAAwB,SAC1B,CAAC,CACH,CACF"}